summaryrefslogtreecommitdiff
path: root/include/linux/llc.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/llc.h')
0 files changed, 0 insertions, 0 deletions
nux-arm.git/log/sound'>logtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig6
-rw-r--r--sound/Makefile2
-rw-r--r--sound/ac97/bus.c48
-rw-r--r--sound/ac97_bus.c16
-rw-r--r--sound/aoa/aoa-gpio.h1
-rw-r--r--sound/aoa/aoa.h1
-rw-r--r--sound/aoa/codecs/Makefile6
-rw-r--r--sound/aoa/codecs/onyx.c111
-rw-r--r--sound/aoa/codecs/onyx.h1
-rw-r--r--sound/aoa/codecs/tas.c121
-rw-r--r--sound/aoa/codecs/toonie.c2
-rw-r--r--sound/aoa/core/Makefile2
-rw-r--r--sound/aoa/core/alsa.c8
-rw-r--r--sound/aoa/core/gpio-feature.c20
-rw-r--r--sound/aoa/core/gpio-pmf.c26
-rw-r--r--sound/aoa/fabrics/Makefile2
-rw-r--r--sound/aoa/fabrics/layout.c19
-rw-r--r--sound/aoa/soundbus/Makefile2
-rw-r--r--sound/aoa/soundbus/core.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/Makefile2
-rw-r--r--sound/aoa/soundbus/i2sbus/control.c1
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c15
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h1
-rw-r--r--sound/aoa/soundbus/i2sbus/interface.h2
-rw-r--r--sound/aoa/soundbus/i2sbus/pcm.c216
-rw-r--r--sound/aoa/soundbus/soundbus.h2
-rw-r--r--sound/arm/Makefile4
-rw-r--r--sound/arm/aaci.c205
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c14
-rw-r--r--sound/arm/pxa2xx-ac97.c9
-rw-r--r--sound/arm/pxa2xx-pcm-lib.c12
-rw-r--r--sound/atmel/Makefile2
-rw-r--r--sound/atmel/ac97c.c41
-rw-r--r--sound/core/.kunitconfig5
-rw-r--r--sound/core/Kconfig53
-rw-r--r--sound/core/Makefile22
-rw-r--r--sound/core/compress_offload.c646
-rw-r--r--sound/core/control.c598
-rw-r--r--sound/core/control_compat.c144
-rw-r--r--sound/core/control_led.c199
-rw-r--r--sound/core/device.c23
-rw-r--r--sound/core/hrtimer.c32
-rw-r--r--sound/core/hwdep.c120
-rw-r--r--sound/core/info.c112
-rw-r--r--sound/core/info_oss.c10
-rw-r--r--sound/core/init.c296
-rw-r--r--sound/core/jack.c82
-rw-r--r--sound/core/memalloc.c214
-rw-r--r--sound/core/memalloc_local.h16
-rw-r--r--sound/core/memory.c75
-rw-r--r--sound/core/misc.c96
-rw-r--r--sound/core/oss/Makefile2
-rw-r--r--sound/core/oss/mixer_oss.c302
-rw-r--r--sound/core/oss/pcm_oss.c81
-rw-r--r--sound/core/oss/pcm_plugin.h5
-rw-r--r--sound/core/oss/rate.c2
-rw-r--r--sound/core/pcm.c142
-rw-r--r--sound/core/pcm_compat.c121
-rw-r--r--sound/core/pcm_dmaengine.c62
-rw-r--r--sound/core/pcm_drm_eld.c461
-rw-r--r--sound/core/pcm_lib.c194
-rw-r--r--sound/core/pcm_memory.c126
-rw-r--r--sound/core/pcm_misc.c52
-rw-r--r--sound/core/pcm_native.c702
-rw-r--r--sound/core/pcm_timer.c3
-rw-r--r--sound/core/pcm_trace.h2
-rw-r--r--sound/core/rawmidi.c497
-rw-r--r--sound/core/rawmidi_compat.c8
-rw-r--r--sound/core/seq/Kconfig13
-rw-r--r--sound/core/seq/Makefile15
-rw-r--r--sound/core/seq/oss/Makefile2
-rw-r--r--sound/core/seq/oss/seq_oss.c24
-rw-r--r--sound/core/seq/oss/seq_oss_device.h16
-rw-r--r--sound/core/seq/oss/seq_oss_event.c8
-rw-r--r--sound/core/seq/oss/seq_oss_init.c27
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c112
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c10
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c207
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c5
-rw-r--r--sound/core/seq/seq_clientmgr.c1308
-rw-r--r--sound/core/seq/seq_clientmgr.h44
-rw-r--r--sound/core/seq/seq_compat.c15
-rw-r--r--sound/core/seq/seq_dummy.c29
-rw-r--r--sound/core/seq/seq_fifo.c67
-rw-r--r--sound/core/seq/seq_fifo.h1
-rw-r--r--sound/core/seq/seq_memory.c131
-rw-r--r--sound/core/seq/seq_memory.h19
-rw-r--r--sound/core/seq/seq_midi.c56
-rw-r--r--sound/core/seq/seq_midi_event.c14
-rw-r--r--sound/core/seq/seq_ports.c180
-rw-r--r--sound/core/seq/seq_ports.h17
-rw-r--r--sound/core/seq/seq_prioq.c194
-rw-r--r--sound/core/seq/seq_queue.c172
-rw-r--r--sound/core/seq/seq_queue.h4
-rw-r--r--sound/core/seq/seq_system.c39
-rw-r--r--sound/core/seq/seq_system.h35
-rw-r--r--sound/core/seq/seq_timer.c181
-rw-r--r--sound/core/seq/seq_timer.h6
-rw-r--r--sound/core/seq/seq_ump_client.c539
-rw-r--r--sound/core/seq/seq_ump_convert.c1305
-rw-r--r--sound/core/seq/seq_ump_convert.h23
-rw-r--r--sound/core/seq/seq_virmidi.c52
-rw-r--r--sound/core/seq_device.c8
-rw-r--r--sound/core/sound.c30
-rw-r--r--sound/core/sound_kunit.c324
-rw-r--r--sound/core/sound_oss.c17
-rw-r--r--sound/core/timer.c787
-rw-r--r--sound/core/timer_compat.c7
-rw-r--r--sound/core/ump.c1394
-rw-r--r--sound/core/ump_convert.c528
-rw-r--r--sound/core/vmaster.c55
-rw-r--r--sound/drivers/Kconfig20
-rw-r--r--sound/drivers/Makefile18
-rw-r--r--sound/drivers/aloop.c385
-rw-r--r--sound/drivers/dummy.c82
-rw-r--r--sound/drivers/mpu401/Makefile4
-rw-r--r--sound/drivers/mpu401/mpu401.c20
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c76
-rw-r--r--sound/drivers/mtpav.c90
-rw-r--r--sound/drivers/mts64.c87
-rw-r--r--sound/drivers/opl3/Makefile2
-rw-r--r--sound/drivers/opl3/opl3_lib.c58
-rw-r--r--sound/drivers/opl3/opl3_midi.c148
-rw-r--r--sound/drivers/opl3/opl3_oss.c12
-rw-r--r--sound/drivers/opl3/opl3_seq.c27
-rw-r--r--sound/drivers/opl3/opl3_synth.c4
-rw-r--r--sound/drivers/opl4/Makefile4
-rw-r--r--sound/drivers/opl4/opl4_lib.c20
-rw-r--r--sound/drivers/opl4/opl4_mixer.c8
-rw-r--r--sound/drivers/opl4/opl4_proc.c10
-rw-r--r--sound/drivers/opl4/opl4_seq.c30
-rw-r--r--sound/drivers/opl4/opl4_synth.c81
-rw-r--r--sound/drivers/opl4/yrw801.c2
-rw-r--r--sound/drivers/pcmtest.c780
-rw-r--r--sound/drivers/pcsp/Makefile2
-rw-r--r--sound/drivers/pcsp/pcsp.c37
-rw-r--r--sound/drivers/pcsp/pcsp_lib.c40
-rw-r--r--sound/drivers/pcsp/pcsp_mixer.c4
-rw-r--r--sound/drivers/portman2x4.c40
-rw-r--r--sound/drivers/serial-generic.c24
-rw-r--r--sound/drivers/serial-u16550.c99
-rw-r--r--sound/drivers/virmidi.c14
-rw-r--r--sound/drivers/vx/Makefile2
-rw-r--r--sound/drivers/vx/vx_core.c85
-rw-r--r--sound/drivers/vx/vx_hwdep.c4
-rw-r--r--sound/drivers/vx/vx_mixer.c59
-rw-r--r--sound/drivers/vx/vx_pcm.c28
-rw-r--r--sound/drivers/vx/vx_uer.c20
-rw-r--r--sound/firewire/Kconfig2
-rw-r--r--sound/firewire/Makefile4
-rw-r--r--sound/firewire/amdtp-stream.c114
-rw-r--r--sound/firewire/amdtp-stream.h7
-rw-r--r--sound/firewire/bebob/Makefile2
-rw-r--r--sound/firewire/bebob/bebob.c44
-rw-r--r--sound/firewire/bebob/bebob_hwdep.c39
-rw-r--r--sound/firewire/bebob/bebob_maudio.c42
-rw-r--r--sound/firewire/bebob/bebob_midi.c40
-rw-r--r--sound/firewire/bebob/bebob_pcm.c71
-rw-r--r--sound/firewire/bebob/bebob_stream.c21
-rw-r--r--sound/firewire/cmp.c84
-rw-r--r--sound/firewire/cmp.h1
-rw-r--r--sound/firewire/dice/Makefile4
-rw-r--r--sound/firewire/dice/dice-extension.c4
-rw-r--r--sound/firewire/dice/dice-hwdep.c39
-rw-r--r--sound/firewire/dice/dice-midi.c42
-rw-r--r--sound/firewire/dice/dice-pcm.c96
-rw-r--r--sound/firewire/dice/dice-stream.c21
-rw-r--r--sound/firewire/dice/dice-teac.c43
-rw-r--r--sound/firewire/dice/dice-transaction.c7
-rw-r--r--sound/firewire/dice/dice-weiss.c104
-rw-r--r--sound/firewire/dice/dice.c91
-rw-r--r--sound/firewire/dice/dice.h2
-rw-r--r--sound/firewire/digi00x/Makefile2
-rw-r--r--sound/firewire/digi00x/digi00x-hwdep.c39
-rw-r--r--sound/firewire/digi00x/digi00x-midi.c48
-rw-r--r--sound/firewire/digi00x/digi00x-pcm.c78
-rw-r--r--sound/firewire/digi00x/digi00x-stream.c21
-rw-r--r--sound/firewire/digi00x/digi00x-transaction.c8
-rw-r--r--sound/firewire/digi00x/digi00x.c11
-rw-r--r--sound/firewire/fcp.c19
-rw-r--r--sound/firewire/fireface/Makefile2
-rw-r--r--sound/firewire/fireface/ff-hwdep.c39
-rw-r--r--sound/firewire/fireface/ff-midi.c14
-rw-r--r--sound/firewire/fireface/ff-pcm.c93
-rw-r--r--sound/firewire/fireface/ff-protocol-former.c4
-rw-r--r--sound/firewire/fireface/ff-stream.c21
-rw-r--r--sound/firewire/fireface/ff-transaction.c4
-rw-r--r--sound/firewire/fireface/ff.c10
-rw-r--r--sound/firewire/fireworks/Makefile2
-rw-r--r--sound/firewire/fireworks/fireworks.c59
-rw-r--r--sound/firewire/fireworks/fireworks_command.c16
-rw-r--r--sound/firewire/fireworks/fireworks_hwdep.c43
-rw-r--r--sound/firewire/fireworks/fireworks_midi.c43
-rw-r--r--sound/firewire/fireworks/fireworks_pcm.c70
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c21
-rw-r--r--sound/firewire/fireworks/fireworks_transaction.c39
-rw-r--r--sound/firewire/isight.c31
-rw-r--r--sound/firewire/iso-resources.c66
-rw-r--r--sound/firewire/lib.c2
-rw-r--r--sound/firewire/motu/Makefile2
-rw-r--r--sound/firewire/motu/motu-command-dsp-message-parser.c9
-rw-r--r--sound/firewire/motu/motu-hwdep.c39
-rw-r--r--sound/firewire/motu/motu-midi.c42
-rw-r--r--sound/firewire/motu/motu-pcm.c95
-rw-r--r--sound/firewire/motu/motu-protocol-v3.c9
-rw-r--r--sound/firewire/motu/motu-register-dsp-message-parser.c18
-rw-r--r--sound/firewire/motu/motu-stream.c21
-rw-r--r--sound/firewire/motu/motu-transaction.c7
-rw-r--r--sound/firewire/motu/motu.c10
-rw-r--r--sound/firewire/motu/motu.h1
-rw-r--r--sound/firewire/oxfw/Makefile2
-rw-r--r--sound/firewire/oxfw/oxfw-hwdep.c39
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c68
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c95
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c121
-rw-r--r--sound/firewire/oxfw/oxfw.c33
-rw-r--r--sound/firewire/oxfw/oxfw.h7
-rw-r--r--sound/firewire/tascam/Makefile2
-rw-r--r--sound/firewire/tascam/amdtp-tascam.c17
-rw-r--r--sound/firewire/tascam/tascam-hwdep.c39
-rw-r--r--sound/firewire/tascam/tascam-midi.c22
-rw-r--r--sound/firewire/tascam/tascam-pcm.c76
-rw-r--r--sound/firewire/tascam/tascam-stream.c42
-rw-r--r--sound/firewire/tascam/tascam.c11
-rw-r--r--sound/hda/Kconfig68
-rw-r--r--sound/hda/Makefile28
-rw-r--r--sound/hda/codecs/Kconfig137
-rw-r--r--sound/hda/codecs/Makefile34
-rw-r--r--sound/hda/codecs/analog.c (renamed from sound/pci/hda/patch_analog.c)236
-rw-r--r--sound/hda/codecs/ca0110.c (renamed from sound/pci/hda/patch_ca0110.c)37
-rw-r--r--sound/hda/codecs/ca0132.c (renamed from sound/pci/hda/patch_ca0132.c)496
-rw-r--r--sound/hda/codecs/ca0132_regs.h (renamed from sound/pci/hda/ca0132_regs.h)2
-rw-r--r--sound/hda/codecs/cirrus/Kconfig44
-rw-r--r--sound/hda/codecs/cirrus/Makefile10
-rw-r--r--sound/hda/codecs/cirrus/cs420x.c (renamed from sound/pci/hda/patch_cirrus.c)539
-rw-r--r--sound/hda/codecs/cirrus/cs421x.c590
-rw-r--r--sound/hda/codecs/cirrus/cs8409-tables.c (renamed from sound/pci/hda/patch_cs8409-tables.c)22
-rw-r--r--sound/hda/codecs/cirrus/cs8409.c (renamed from sound/pci/hda/patch_cs8409.c)119
-rw-r--r--sound/hda/codecs/cirrus/cs8409.h (renamed from sound/pci/hda/patch_cs8409.h)14
-rw-r--r--sound/hda/codecs/cm9825.c312
-rw-r--r--sound/hda/codecs/cmedia.c106
-rw-r--r--sound/hda/codecs/conexant.c (renamed from sound/pci/hda/patch_conexant.c)291
-rw-r--r--sound/hda/codecs/generic.c (renamed from sound/pci/hda/hda_generic.c)214
-rw-r--r--sound/hda/codecs/generic.h (renamed from sound/pci/hda/hda_generic.h)9
-rw-r--r--sound/hda/codecs/hdmi/Kconfig88
-rw-r--r--sound/hda/codecs/hdmi/Makefile18
-rw-r--r--sound/hda/codecs/hdmi/atihdmi.c615
-rw-r--r--sound/hda/codecs/hdmi/eld.c230
-rw-r--r--sound/hda/codecs/hdmi/hdmi.c2363
-rw-r--r--sound/hda/codecs/hdmi/hdmi_local.h302
-rw-r--r--sound/hda/codecs/hdmi/intelhdmi.c812
-rw-r--r--sound/hda/codecs/hdmi/nvhdmi-mcp.c383
-rw-r--r--sound/hda/codecs/hdmi/nvhdmi.c240
-rw-r--r--sound/hda/codecs/hdmi/simplehdmi.c251
-rw-r--r--sound/hda/codecs/hdmi/tegrahdmi.c318
-rw-r--r--sound/hda/codecs/helpers/hp_x360.c (renamed from sound/pci/hda/hp_x360_helper.c)0
-rw-r--r--sound/hda/codecs/helpers/ideapad_hotkey_led.c36
-rw-r--r--sound/hda/codecs/helpers/ideapad_s740.c (renamed from sound/pci/hda/ideapad_s740_helper.c)0
-rw-r--r--sound/hda/codecs/helpers/thinkpad.c (renamed from sound/pci/hda/thinkpad_helper.c)0
-rw-r--r--sound/hda/codecs/realtek/Kconfig104
-rw-r--r--sound/hda/codecs/realtek/Makefile26
-rw-r--r--sound/hda/codecs/realtek/alc260.c290
-rw-r--r--sound/hda/codecs/realtek/alc262.c213
-rw-r--r--sound/hda/codecs/realtek/alc268.c189
-rw-r--r--sound/hda/codecs/realtek/alc269.c (renamed from sound/pci/hda/patch_realtek.c)7950
-rw-r--r--sound/hda/codecs/realtek/alc662.c1116
-rw-r--r--sound/hda/codecs/realtek/alc680.c67
-rw-r--r--sound/hda/codecs/realtek/alc861.c163
-rw-r--r--sound/hda/codecs/realtek/alc861vd.c137
-rw-r--r--sound/hda/codecs/realtek/alc880.c509
-rw-r--r--sound/hda/codecs/realtek/alc882.c861
-rw-r--r--sound/hda/codecs/realtek/realtek.c2271
-rw-r--r--sound/hda/codecs/realtek/realtek.h319
-rw-r--r--sound/hda/codecs/senarytech.c249
-rw-r--r--sound/hda/codecs/si3054.c (renamed from sound/pci/hda/patch_si3054.c)53
-rw-r--r--sound/hda/codecs/side-codecs/Kconfig143
-rw-r--r--sound/hda/codecs/side-codecs/Makefile28
-rw-r--r--sound/hda/codecs/side-codecs/cirrus_scodec.c73
-rw-r--r--sound/hda/codecs/side-codecs/cirrus_scodec.h13
-rw-r--r--sound/hda/codecs/side-codecs/cirrus_scodec_test.c332
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.c (renamed from sound/pci/hda/cs35l41_hda.c)1471
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.h (renamed from sound/pci/hda/cs35l41_hda.h)29
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c (renamed from sound/pci/hda/cs35l41_hda_i2c.c)8
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda_property.c582
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda_property.h18
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda_spi.c (renamed from sound/pci/hda/cs35l41_hda_spi.c)5
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.c1286
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.h56
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c85
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda_spi.c88
-rw-r--r--sound/hda/codecs/side-codecs/hda_component.c209
-rw-r--r--sound/hda/codecs/side-codecs/hda_component.h102
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda.c416
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda.h90
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_i2c.c834
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_spi.c956
-rw-r--r--sound/hda/codecs/sigmatel.c (renamed from sound/pci/hda/patch_sigmatel.c)432
-rw-r--r--sound/hda/codecs/via.c (renamed from sound/pci/hda/patch_via.c)453
-rw-r--r--sound/hda/common/Kconfig97
-rw-r--r--sound/hda/common/Makefile13
-rw-r--r--sound/hda/common/auto_parser.c (renamed from sound/pci/hda/hda_auto_parser.c)89
-rw-r--r--sound/hda/common/beep.c (renamed from sound/pci/hda/hda_beep.c)16
-rw-r--r--sound/hda/common/bind.c (renamed from sound/pci/hda/hda_bind.c)37
-rw-r--r--sound/hda/common/codec.c (renamed from sound/pci/hda/hda_codec.c)364
-rw-r--r--sound/hda/common/controller.c (renamed from sound/pci/hda/hda_controller.c)172
-rw-r--r--sound/hda/common/controller_trace.h (renamed from sound/pci/hda/hda_controller_trace.h)2
-rw-r--r--sound/hda/common/hda_auto_parser.h (renamed from sound/pci/hda/hda_auto_parser.h)3
-rw-r--r--sound/hda/common/hda_beep.h (renamed from sound/pci/hda/hda_beep.h)1
-rw-r--r--sound/hda/common/hda_controller.h (renamed from sound/pci/hda/hda_controller.h)1
-rw-r--r--sound/hda/common/hda_jack.h (renamed from sound/pci/hda/hda_jack.h)0
-rw-r--r--sound/hda/common/hda_local.h (renamed from sound/pci/hda/hda_local.h)92
-rw-r--r--sound/hda/common/hwdep.c (renamed from sound/pci/hda/hda_hwdep.c)6
-rw-r--r--sound/hda/common/jack.c (renamed from sound/pci/hda/hda_jack.c)0
-rw-r--r--sound/hda/common/proc.c (renamed from sound/pci/hda/hda_proc.c)13
-rw-r--r--sound/hda/common/sysfs.c (renamed from sound/pci/hda/hda_sysfs.c)116
-rw-r--r--sound/hda/controllers/Kconfig42
-rw-r--r--sound/hda/controllers/Makefile13
-rw-r--r--sound/hda/controllers/acpi.c325
-rw-r--r--sound/hda/controllers/intel.c (renamed from sound/pci/hda/hda_intel.c)698
-rw-r--r--sound/hda/controllers/intel.h (renamed from sound/pci/hda/hda_intel.h)1
-rw-r--r--sound/hda/controllers/intel_trace.h (renamed from sound/pci/hda/hda_intel_trace.h)4
-rw-r--r--sound/hda/controllers/tegra.c (renamed from sound/pci/hda/hda_tegra.c)76
-rw-r--r--sound/hda/core/Kconfig51
-rw-r--r--sound/hda/core/Makefile22
-rw-r--r--sound/hda/core/array.c (renamed from sound/hda/array.c)0
-rw-r--r--sound/hda/core/bus.c (renamed from sound/hda/hdac_bus.c)8
-rw-r--r--sound/hda/core/component.c (renamed from sound/hda/hdac_component.c)13
-rw-r--r--sound/hda/core/controller.c (renamed from sound/hda/hdac_controller.c)174
-rw-r--r--sound/hda/core/device.c (renamed from sound/hda/hdac_device.c)194
-rw-r--r--sound/hda/core/ext/Makefile (renamed from sound/hda/ext/Makefile)2
-rw-r--r--sound/hda/core/ext/bus.c (renamed from sound/hda/ext/hdac_ext_bus.c)0
-rw-r--r--sound/hda/core/ext/controller.c (renamed from sound/hda/ext/hdac_ext_controller.c)25
-rw-r--r--sound/hda/core/ext/stream.c (renamed from sound/hda/ext/hdac_ext_stream.c)81
-rw-r--r--sound/hda/core/hda_bus_type.c (renamed from sound/hda/hda_bus_type.c)10
-rw-r--r--sound/hda/core/hdmi_chmap.c (renamed from sound/hda/hdmi_chmap.c)18
-rw-r--r--sound/hda/core/i915.c (renamed from sound/hda/hdac_i915.c)75
-rw-r--r--sound/hda/core/intel-dsp-config.c (renamed from sound/hda/intel-dsp-config.c)364
-rw-r--r--sound/hda/core/intel-nhlt.c (renamed from sound/hda/intel-nhlt.c)76
-rw-r--r--sound/hda/core/intel-sdw-acpi.c (renamed from sound/hda/intel-sdw-acpi.c)65
-rw-r--r--sound/hda/core/local.h (renamed from sound/hda/local.h)21
-rw-r--r--sound/hda/core/regmap.c (renamed from sound/hda/hdac_regmap.c)47
-rw-r--r--sound/hda/core/stream.c (renamed from sound/hda/hdac_stream.c)165
-rw-r--r--sound/hda/core/sysfs.c (renamed from sound/hda/hdac_sysfs.c)14
-rw-r--r--sound/hda/core/trace.c (renamed from sound/hda/trace.c)0
-rw-r--r--sound/hda/core/trace.h (renamed from sound/hda/trace.h)6
-rw-r--r--sound/i2c/Makefile6
-rw-r--r--sound/i2c/cs8427.c39
-rw-r--r--sound/i2c/other/Makefile10
-rw-r--r--sound/i2c/other/ak4113.c56
-rw-r--r--sound/i2c/other/ak4114.c51
-rw-r--r--sound/i2c/other/ak4117.c57
-rw-r--r--sound/i2c/other/ak4xxx-adda.c2
-rw-r--r--sound/i2c/other/pt2258.c14
-rw-r--r--sound/i2c/tea6330t.c3
-rw-r--r--sound/isa/Kconfig1
-rw-r--r--sound/isa/Makefile18
-rw-r--r--sound/isa/ad1816a/Makefile2
-rw-r--r--sound/isa/ad1816a/ad1816a.c20
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c139
-rw-r--r--sound/isa/ad1848/Makefile2
-rw-r--r--sound/isa/ad1848/ad1848.c12
-rw-r--r--sound/isa/adlib.c4
-rw-r--r--sound/isa/als100.c24
-rw-r--r--sound/isa/azt2320.c18
-rw-r--r--sound/isa/cmi8328.c62
-rw-r--r--sound/isa/cmi8330.c59
-rw-r--r--sound/isa/cs423x/Makefile4
-rw-r--r--sound/isa/cs423x/cs4231.c12
-rw-r--r--sound/isa/cs423x/cs4236.c47
-rw-r--r--sound/isa/cs423x/cs4236_lib.c189
-rw-r--r--sound/isa/es1688/Makefile4
-rw-r--r--sound/isa/es1688/es1688.c8
-rw-r--r--sound/isa/es1688/es1688_lib.c335
-rw-r--r--sound/isa/es18xx.c147
-rw-r--r--sound/isa/galaxy/Makefile4
-rw-r--r--sound/isa/galaxy/galaxy.c4
-rw-r--r--sound/isa/gus/Makefile12
-rw-r--r--sound/isa/gus/gus_dma.c129
-rw-r--r--sound/isa/gus/gus_dram.c8
-rw-r--r--sound/isa/gus/gus_io.c219
-rw-r--r--sound/isa/gus/gus_irq.c7
-rw-r--r--sound/isa/gus/gus_main.c124
-rw-r--r--sound/isa/gus/gus_mem.c35
-rw-r--r--sound/isa/gus/gus_mixer.c14
-rw-r--r--sound/isa/gus/gus_pcm.c231
-rw-r--r--sound/isa/gus/gus_reset.c93
-rw-r--r--sound/isa/gus/gus_timer.c20
-rw-r--r--sound/isa/gus/gus_uart.c47
-rw-r--r--sound/isa/gus/gus_volume.c7
-rw-r--r--sound/isa/gus/gusclassic.c4
-rw-r--r--sound/isa/gus/gusextreme.c33
-rw-r--r--sound/isa/gus/gusmax.c32
-rw-r--r--sound/isa/gus/interwave.c128
-rw-r--r--sound/isa/msnd/Makefile6
-rw-r--r--sound/isa/msnd/msnd.c77
-rw-r--r--sound/isa/msnd/msnd.h4
-rw-r--r--sound/isa/msnd/msnd_midi.c167
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c222
-rw-r--r--sound/isa/msnd/msnd_pinnacle_mixer.c10
-rw-r--r--sound/isa/opl3sa2.c95
-rw-r--r--sound/isa/opti9xx/Makefile8
-rw-r--r--sound/isa/opti9xx/miro.c196
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c119
-rw-r--r--sound/isa/sb/Makefile18
-rw-r--r--sound/isa/sb/emu8000.c116
-rw-r--r--sound/isa/sb/emu8000_patch.c14
-rw-r--r--sound/isa/sb/emu8000_pcm.c126
-rw-r--r--sound/isa/sb/emu8000_synth.c2
-rw-r--r--sound/isa/sb/jazz16.c54
-rw-r--r--sound/isa/sb/sb16.c58
-rw-r--r--sound/isa/sb/sb16_csp.c272
-rw-r--r--sound/isa/sb/sb16_main.c143
-rw-r--r--sound/isa/sb/sb8.c17
-rw-r--r--sound/isa/sb/sb8_main.c170
-rw-r--r--sound/isa/sb/sb8_midi.c130
-rw-r--r--sound/isa/sb/sb_common.c44
-rw-r--r--sound/isa/sb/sb_mixer.c70
-rw-r--r--sound/isa/sc6000.c197
-rw-r--r--sound/isa/sscape.c290
-rw-r--r--sound/isa/wavefront/Makefile2
-rw-r--r--sound/isa/wavefront/wavefront.c77
-rw-r--r--sound/isa/wavefront/wavefront_fx.c42
-rw-r--r--sound/isa/wavefront/wavefront_midi.c154
-rw-r--r--sound/isa/wavefront/wavefront_synth.c216
-rw-r--r--sound/isa/wss/Makefile2
-rw-r--r--sound/isa/wss/wss_lib.c469
-rw-r--r--sound/mips/Makefile4
-rw-r--r--sound/mips/hal2.c8
-rw-r--r--sound/mips/sgio2audio.c33
-rw-r--r--sound/mips/snd-n64.c26
-rw-r--r--sound/oss/dmasound/dmasound_atari.c2
-rw-r--r--sound/oss/dmasound/dmasound_core.c4
-rw-r--r--sound/oss/dmasound/dmasound_paula.c14
-rw-r--r--sound/parisc/Makefile2
-rw-r--r--sound/parisc/harmony.c111
-rw-r--r--sound/pci/Kconfig47
-rw-r--r--sound/pci/Makefile49
-rw-r--r--sound/pci/ac97/ac97_codec.c65
-rw-r--r--sound/pci/ac97/ac97_local.h2
-rw-r--r--sound/pci/ac97/ac97_patch.c46
-rw-r--r--sound/pci/ac97/ac97_pcm.c50
-rw-r--r--sound/pci/ac97/ac97_proc.c20
-rw-r--r--sound/pci/ad1889.c33
-rw-r--r--sound/pci/ak4531_codec.c20
-rw-r--r--sound/pci/ali5451/Makefile2
-rw-r--r--sound/pci/ali5451/ali5451.c138
-rw-r--r--sound/pci/als300.c36
-rw-r--r--sound/pci/als4000.c83
-rw-r--r--sound/pci/asihpi/Makefile2
-rw-r--r--sound/pci/asihpi/asihpi.c142
-rw-r--r--sound/pci/asihpi/hpi.h16
-rw-r--r--sound/pci/asihpi/hpi6000.c2
-rw-r--r--sound/pci/asihpi/hpi_internal.h5
-rw-r--r--sound/pci/asihpi/hpidebug.h9
-rw-r--r--sound/pci/asihpi/hpimsgx.c2
-rw-r--r--sound/pci/asihpi/hpioctl.c2
-rw-r--r--sound/pci/atiixp.c98
-rw-r--r--sound/pci/atiixp_modem.c73
-rw-r--r--sound/pci/au88x0/Makefile6
-rw-r--r--sound/pci/au88x0/au88x0.c21
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c10
-rw-r--r--sound/pci/au88x0/au88x0_core.c10
-rw-r--r--sound/pci/au88x0/au88x0_eq.c2
-rw-r--r--sound/pci/au88x0/au88x0_mixer.c2
-rw-r--r--sound/pci/aw2/Makefile2
-rw-r--r--sound/pci/aw2/aw2-alsa.c43
-rw-r--r--sound/pci/aw2/aw2-saa7146.h5
-rw-r--r--sound/pci/azt3328.c182
-rw-r--r--sound/pci/bt87x.c39
-rw-r--r--sound/pci/ca0106/Makefile2
-rw-r--r--sound/pci/ca0106/ca0106_main.c41
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c34
-rw-r--r--sound/pci/ca0106/ca0106_proc.c28
-rw-r--r--sound/pci/ca0106/ca_midi.c173
-rw-r--r--sound/pci/cmipci.c277
-rw-r--r--sound/pci/cs4281.c88
-rw-r--r--sound/pci/cs46xx/cs46xx.c4
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c231
-rw-r--r--sound/pci/cs46xx/dsp_spos.c78
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c70
-rw-r--r--sound/pci/cs5530.c11
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c20
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c14
-rw-r--r--sound/pci/ctxfi/Makefile2
-rw-r--r--sound/pci/ctxfi/ctamixer.c77
-rw-r--r--sound/pci/ctxfi/ctamixer.h8
-rw-r--r--sound/pci/ctxfi/ctatc.c148
-rw-r--r--sound/pci/ctxfi/ctatc.h8
-rw-r--r--sound/pci/ctxfi/ctdaio.c117
-rw-r--r--sound/pci/ctxfi/ctdaio.h7
-rw-r--r--sound/pci/ctxfi/cthardware.h4
-rw-r--r--sound/pci/ctxfi/cthw20k1.c42
-rw-r--r--sound/pci/ctxfi/cthw20k2.c81
-rw-r--r--sound/pci/ctxfi/ctmixer.c75
-rw-r--r--sound/pci/ctxfi/ctsrc.c111
-rw-r--r--sound/pci/ctxfi/ctsrc.h8
-rw-r--r--sound/pci/ctxfi/cttimer.c69
-rw-r--r--sound/pci/ctxfi/ctvmem.c16
-rw-r--r--sound/pci/ctxfi/xfi.c4
-rw-r--r--sound/pci/echoaudio/Makefile28
-rw-r--r--sound/pci/echoaudio/echoaudio.c170
-rw-r--r--sound/pci/echoaudio/echoaudio.h2
-rw-r--r--sound/pci/echoaudio/echoaudio_3g.c7
-rw-r--r--sound/pci/echoaudio/gina24_dsp.c3
-rw-r--r--sound/pci/echoaudio/layla24_dsp.c6
-rw-r--r--sound/pci/echoaudio/midi.c45
-rw-r--r--sound/pci/echoaudio/mona_dsp.c3
-rw-r--r--sound/pci/emu10k1/Makefile6
-rw-r--r--sound/pci/emu10k1/emu10k1.c27
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c260
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c711
-rw-r--r--sound/pci/emu10k1/emu10k1_patch.c210
-rw-r--r--sound/pci/emu10k1/emu10k1_synth.c14
-rw-r--r--sound/pci/emu10k1/emu10k1x.c238
-rw-r--r--sound/pci/emu10k1/emufx.c966
-rw-r--r--sound/pci/emu10k1/emumixer.c1691
-rw-r--r--sound/pci/emu10k1/emumpu401.c183
-rw-r--r--sound/pci/emu10k1/emupcm.c1100
-rw-r--r--sound/pci/emu10k1/emuproc.c560
-rw-r--r--sound/pci/emu10k1/io.c491
-rw-r--r--sound/pci/emu10k1/irq.c49
-rw-r--r--sound/pci/emu10k1/memory.c95
-rw-r--r--sound/pci/emu10k1/p16v.c27
-rw-r--r--sound/pci/emu10k1/p16v.h56
-rw-r--r--sound/pci/emu10k1/p17v.h1
-rw-r--r--sound/pci/emu10k1/timer.c36
-rw-r--r--sound/pci/emu10k1/tina2.h1
-rw-r--r--sound/pci/emu10k1/voice.c156
-rw-r--r--sound/pci/ens1370.c343
-rw-r--r--sound/pci/es1938.c79
-rw-r--r--sound/pci/es1968.c214
-rw-r--r--sound/pci/fm801.c90
-rw-r--r--sound/pci/hda/Kconfig321
-rw-r--r--sound/pci/hda/Makefile64
-rw-r--r--sound/pci/hda/hda_component.h19
-rw-r--r--sound/pci/hda/hda_cs_dsp_ctl.c252
-rw-r--r--sound/pci/hda/hda_cs_dsp_ctl.h39
-rw-r--r--sound/pci/hda/hda_eld.c771
-rw-r--r--sound/pci/hda/patch_cmedia.c127
-rw-r--r--sound/pci/hda/patch_hdmi.c4656
-rw-r--r--sound/pci/ice1712/Makefile6
-rw-r--r--sound/pci/ice1712/aureon.c34
-rw-r--r--sound/pci/ice1712/delta.c83
-rw-r--r--sound/pci/ice1712/ews.c53
-rw-r--r--sound/pci/ice1712/hoontech.c24
-rw-r--r--sound/pci/ice1712/ice1712.c214
-rw-r--r--sound/pci/ice1712/ice1724.c346
-rw-r--r--sound/pci/ice1712/juli.c28
-rw-r--r--sound/pci/ice1712/maya44.c18
-rw-r--r--sound/pci/ice1712/phase.c6
-rw-r--r--sound/pci/ice1712/pontis.c70
-rw-r--r--sound/pci/ice1712/prodigy192.c20
-rw-r--r--sound/pci/ice1712/prodigy_hifi.c56
-rw-r--r--sound/pci/ice1712/psc724.c19
-rw-r--r--sound/pci/ice1712/quartet.c27
-rw-r--r--sound/pci/ice1712/wm8776.c6
-rw-r--r--sound/pci/ice1712/wtm.c6
-rw-r--r--sound/pci/intel8x0.c208
-rw-r--r--sound/pci/intel8x0m.c34
-rw-r--r--sound/pci/korg1212/Makefile2
-rw-r--r--sound/pci/korg1212/korg1212.c341
-rw-r--r--sound/pci/lola/lola.c24
-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/lola/lola_pcm.c36
-rw-r--r--sound/pci/lx6464es/Makefile2
-rw-r--r--sound/pci/lx6464es/lx6464es.c55
-rw-r--r--sound/pci/lx6464es/lx_core.c119
-rw-r--r--sound/pci/lx6464es/lx_core.h3
-rw-r--r--sound/pci/maestro3.c77
-rw-r--r--sound/pci/mixart/Makefile2
-rw-r--r--sound/pci/mixart/mixart.c62
-rw-r--r--sound/pci/mixart/mixart_core.c71
-rw-r--r--sound/pci/mixart/mixart_core.h77
-rw-r--r--sound/pci/mixart/mixart_mixer.c46
-rw-r--r--sound/pci/nm256/Makefile2
-rw-r--r--sound/pci/nm256/nm256.c92
-rw-r--r--sound/pci/oxygen/Makefile8
-rw-r--r--sound/pci/oxygen/oxygen.c16
-rw-r--r--sound/pci/oxygen/oxygen.h2
-rw-r--r--sound/pci/oxygen/oxygen_lib.c147
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c68
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c175
-rw-r--r--sound/pci/oxygen/se6x.c4
-rw-r--r--sound/pci/oxygen/virtuoso.c4
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c6
-rw-r--r--sound/pci/oxygen/xonar_dg_mixer.c33
-rw-r--r--sound/pci/oxygen/xonar_lib.c3
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c21
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c31
-rw-r--r--sound/pci/pcxhr/Makefile2
-rw-r--r--sound/pci/pcxhr/pcxhr.c39
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c15
-rw-r--r--sound/pci/pcxhr/pcxhr_mix22.c25
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c58
-rw-r--r--sound/pci/riptide/Makefile2
-rw-r--r--sound/pci/riptide/riptide.c228
-rw-r--r--sound/pci/rme32.c211
-rw-r--r--sound/pci/rme96.c308
-rw-r--r--sound/pci/rme9652/Makefile6
-rw-r--r--sound/pci/rme9652/hdsp.c403
-rw-r--r--sound/pci/rme9652/hdspm.c369
-rw-r--r--sound/pci/rme9652/rme9652.c264
-rw-r--r--sound/pci/sis7019.c64
-rw-r--r--sound/pci/sonicvibes.c131
-rw-r--r--sound/pci/trident/Makefile2
-rw-r--r--sound/pci/trident/trident.c6
-rw-r--r--sound/pci/trident/trident.h5
-rw-r--r--sound/pci/trident/trident_main.c344
-rw-r--r--sound/pci/trident/trident_memory.c29
-rw-r--r--sound/pci/via82xx.c123
-rw-r--r--sound/pci/via82xx_modem.c21
-rw-r--r--sound/pci/vx222/Makefile2
-rw-r--r--sound/pci/vx222/vx222.c11
-rw-r--r--sound/pci/vx222/vx222_ops.c12
-rw-r--r--sound/pci/ymfpci/Makefile2
-rw-r--r--sound/pci/ymfpci/ymfpci.c12
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c264
-rw-r--r--sound/pcmcia/Kconfig1
-rw-r--r--sound/pcmcia/pdaudiocf/Makefile2
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c23
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_core.c39
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_irq.c3
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c27
-rw-r--r--sound/pcmcia/vx/Makefile2
-rw-r--r--sound/pcmcia/vx/vxp_mixer.c9
-rw-r--r--sound/pcmcia/vx/vxp_ops.c16
-rw-r--r--sound/pcmcia/vx/vxpocket.c29
-rw-r--r--sound/ppc/Makefile2
-rw-r--r--sound/ppc/awacs.c31
-rw-r--r--sound/ppc/beep.c17
-rw-r--r--sound/ppc/burgundy.c13
-rw-r--r--sound/ppc/daca.c4
-rw-r--r--sound/ppc/keywest.c18
-rw-r--r--sound/ppc/pmac.c142
-rw-r--r--sound/ppc/powermac.c12
-rw-r--r--sound/ppc/snd_ps3.c29
-rw-r--r--sound/ppc/tumbler.c21
-rw-r--r--sound/sh/Kconfig2
-rw-r--r--sound/sh/Makefile4
-rw-r--r--sound/sh/aica.c48
-rw-r--r--sound/sh/sh_dac_audio.c47
-rw-r--r--sound/soc/Kconfig46
-rw-r--r--sound/soc/Makefile31
-rw-r--r--sound/soc/adi/Kconfig9
-rw-r--r--sound/soc/adi/Makefile4
-rw-r--r--sound/soc/adi/axi-i2s.c8
-rw-r--r--sound/soc/adi/axi-spdif.c4
-rw-r--r--sound/soc/amd/Kconfig52
-rw-r--r--sound/soc/amd/Makefile14
-rw-r--r--sound/soc/amd/acp-config.c178
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c99
-rw-r--r--sound/soc/amd/acp-es8336.c16
-rw-r--r--sound/soc/amd/acp-pcm-dma.c4
-rw-r--r--sound/soc/amd/acp-rt5645.c34
-rw-r--r--sound/soc/amd/acp/Kconfig108
-rw-r--r--sound/soc/amd/acp/Makefile36
-rw-r--r--sound/soc/amd/acp/acp-i2s.c376
-rw-r--r--sound/soc/amd/acp/acp-legacy-common.c647
-rw-r--r--sound/soc/amd/acp/acp-legacy-mach.c139
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c752
-rw-r--r--sound/soc/amd/acp/acp-mach.h77
-rw-r--r--sound/soc/amd/acp/acp-pci.c257
-rw-r--r--sound/soc/amd/acp/acp-pdm.c76
-rw-r--r--sound/soc/amd/acp/acp-platform.c253
-rw-r--r--sound/soc/amd/acp/acp-rembrandt.c313
-rw-r--r--sound/soc/amd/acp/acp-renoir.c258
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c565
-rw-r--r--sound/soc/amd/acp/acp-sdw-mach-common.c98
-rw-r--r--sound/soc/amd/acp/acp-sdw-sof-mach.c461
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c68
-rw-r--r--sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c456
-rw-r--r--sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.h12
-rw-r--r--sound/soc/amd/acp/acp63.c298
-rw-r--r--sound/soc/amd/acp/acp70.c228
-rw-r--r--sound/soc/amd/acp/acp_common.h20
-rw-r--r--sound/soc/amd/acp/amd-acp63-acpi-match.c144
-rw-r--r--sound/soc/amd/acp/amd-acp70-acpi-match.c329
-rw-r--r--sound/soc/amd/acp/amd-acpi-mach.c93
-rw-r--r--sound/soc/amd/acp/amd-sdw-acpi.c62
-rw-r--r--sound/soc/amd/acp/amd.h289
-rw-r--r--sound/soc/amd/acp/chip_offset_byte.h98
-rw-r--r--sound/soc/amd/acp/soc_amd_sdw_common.h62
-rw-r--r--sound/soc/amd/acp3x-rt5682-max9836.c43
-rw-r--r--sound/soc/amd/mach-config.h8
-rw-r--r--sound/soc/amd/ps/Makefile10
-rw-r--r--sound/soc/amd/ps/acp63.h378
-rw-r--r--sound/soc/amd/ps/pci-ps.c683
-rw-r--r--sound/soc/amd/ps/ps-common.c493
-rw-r--r--sound/soc/amd/ps/ps-mach.c3
-rw-r--r--sound/soc/amd/ps/ps-pdm-dma.c35
-rw-r--r--sound/soc/amd/ps/ps-sdw-dma.c804
-rw-r--r--sound/soc/amd/raven/Makefile6
-rw-r--r--sound/soc/amd/raven/acp3x-i2s.c5
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c11
-rw-r--r--sound/soc/amd/renoir/Makefile6
-rw-r--r--sound/soc/amd/renoir/acp3x-pdm-dma.c5
-rw-r--r--sound/soc/amd/renoir/acp3x-rn.c1
-rw-r--r--sound/soc/amd/rpl/Makefile2
-rw-r--r--sound/soc/amd/rpl/rpl-pci-acp6x.c10
-rw-r--r--sound/soc/amd/vangogh/Makefile8
-rw-r--r--sound/soc/amd/vangogh/acp5x-i2s.c5
-rw-r--r--sound/soc/amd/vangogh/acp5x-mach.c158
-rw-r--r--sound/soc/amd/vangogh/acp5x-pcm-dma.c23
-rw-r--r--sound/soc/amd/vangogh/pci-acp5x.c22
-rw-r--r--sound/soc/amd/yc/Makefile6
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c362
-rw-r--r--sound/soc/amd/yc/acp6x-pdm-dma.c17
-rw-r--r--sound/soc/amd/yc/pci-acp6x.c10
-rw-r--r--sound/soc/apple/Kconfig5
-rw-r--r--sound/soc/apple/Makefile2
-rw-r--r--sound/soc/apple/mca.c56
-rw-r--r--sound/soc/atmel/Kconfig11
-rw-r--r--sound/soc/atmel/Makefile30
-rw-r--r--sound/soc/atmel/atmel-classd.c20
-rw-r--r--sound/soc/atmel/atmel-i2s.c25
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c8
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c4
-rw-r--r--sound/soc/atmel/atmel-pdmic.c18
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c5
-rw-r--r--sound/soc/atmel/atmel_wm8904.c7
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c72
-rw-r--r--sound/soc/atmel/mchp-pdmc.c130
-rw-r--r--sound/soc/atmel/mchp-spdifrx.c26
-rw-r--r--sound/soc/atmel/mchp-spdiftx.c24
-rw-r--r--sound/soc/atmel/mikroe-proto.c10
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c6
-rw-r--r--sound/soc/atmel/sam9x5_wm8731.c4
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c51
-rw-r--r--sound/soc/au1x/Kconfig4
-rw-r--r--sound/soc/au1x/Makefile16
-rw-r--r--sound/soc/au1x/ac97c.c12
-rw-r--r--sound/soc/au1x/db1200.c5
-rw-r--r--sound/soc/au1x/dbdma2.c6
-rw-r--r--sound/soc/au1x/dma.c6
-rw-r--r--sound/soc/au1x/i2sc.c19
-rw-r--r--sound/soc/au1x/psc-ac97.c23
-rw-r--r--sound/soc/au1x/psc-i2s.c19
-rw-r--r--sound/soc/bcm/Kconfig4
-rw-r--r--sound/soc/bcm/Makefile6
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c26
-rw-r--r--sound/soc/bcm/bcm63xx-i2s-whistler.c18
-rw-r--r--sound/soc/bcm/bcm63xx-pcm-whistler.c34
-rw-r--r--sound/soc/bcm/cygnus-pcm.c26
-rw-r--r--sound/soc/bcm/cygnus-ssp.c4
-rw-r--r--sound/soc/bcm/cygnus-ssp.h2
-rw-r--r--sound/soc/cirrus/Kconfig12
-rw-r--r--sound/soc/cirrus/Makefile8
-rw-r--r--sound/soc/cirrus/edb93xx.c117
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c23
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c19
-rw-r--r--sound/soc/codecs/88pm860x-codec.c19
-rw-r--r--sound/soc/codecs/Kconfig545
-rw-r--r--sound/soc/codecs/Makefile872
-rw-r--r--sound/soc/codecs/ab8500-codec.c19
-rw-r--r--sound/soc/codecs/ac97.c10
-rw-r--r--sound/soc/codecs/ad1836.c4
-rw-r--r--sound/soc/codecs/ad193x-i2c.c3
-rw-r--r--sound/soc/codecs/ad193x.c4
-rw-r--r--sound/soc/codecs/ad1980.c2
-rw-r--r--sound/soc/codecs/adau1372-i2c.c3
-rw-r--r--sound/soc/codecs/adau1372-spi.c1
-rw-r--r--sound/soc/codecs/adau1372.c10
-rw-r--r--sound/soc/codecs/adau1372.h1
-rw-r--r--sound/soc/codecs/adau1373.c206
-rw-r--r--sound/soc/codecs/adau1701.c17
-rw-r--r--sound/soc/codecs/adau1761-i2c.c5
-rw-r--r--sound/soc/codecs/adau1761.c11
-rw-r--r--sound/soc/codecs/adau1781-i2c.c5
-rw-r--r--sound/soc/codecs/adau1781.c4
-rw-r--r--sound/soc/codecs/adau17x1.c18
-rw-r--r--sound/soc/codecs/adau1977-i2c.c5
-rw-r--r--sound/soc/codecs/adau1977-spi.c1
-rw-r--r--sound/soc/codecs/adau1977.c9
-rw-r--r--sound/soc/codecs/adau7118-i2c.c4
-rw-r--r--sound/soc/codecs/adau7118.c19
-rw-r--r--sound/soc/codecs/adav803.c2
-rw-r--r--sound/soc/codecs/adav80x.c14
-rw-r--r--sound/soc/codecs/ak4104.c2
-rw-r--r--sound/soc/codecs/ak4118.c5
-rw-r--r--sound/soc/codecs/ak4375.c13
-rw-r--r--sound/soc/codecs/ak4458.c41
-rw-r--r--sound/soc/codecs/ak4535.c2
-rw-r--r--sound/soc/codecs/ak4613.c19
-rw-r--r--sound/soc/codecs/ak4619.c912
-rw-r--r--sound/soc/codecs/ak4641.c9
-rw-r--r--sound/soc/codecs/ak4642.c30
-rw-r--r--sound/soc/codecs/ak4671.c2
-rw-r--r--sound/soc/codecs/ak5386.c31
-rw-r--r--sound/soc/codecs/ak5558.c13
-rw-r--r--sound/soc/codecs/alc5623.c12
-rw-r--r--sound/soc/codecs/alc5632.c6
-rw-r--r--sound/soc/codecs/arizona-jack.c27
-rw-r--r--sound/soc/codecs/arizona.c60
-rw-r--r--sound/soc/codecs/audio-iio-aux.c314
-rw-r--r--sound/soc/codecs/aw87390.c461
-rw-r--r--sound/soc/codecs/aw87390.h85
-rw-r--r--sound/soc/codecs/aw88081.c1317
-rw-r--r--sound/soc/codecs/aw88081.h329
-rw-r--r--sound/soc/codecs/aw88166.c1815
-rw-r--r--sound/soc/codecs/aw88166.h529
-rw-r--r--sound/soc/codecs/aw88261.c1282
-rw-r--r--sound/soc/codecs/aw88261.h459
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c51
-rw-r--r--sound/soc/codecs/aw88395/aw88395.h2
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.c97
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.h36
-rw-r--r--sound/soc/codecs/aw88395/aw88395_lib.c172
-rw-r--r--sound/soc/codecs/aw88399.c2173
-rw-r--r--sound/soc/codecs/aw88399.h629
-rw-r--r--sound/soc/codecs/bd28623.c6
-rw-r--r--sound/soc/codecs/chv3-codec.c1
-rw-r--r--sound/soc/codecs/cpcap.c223
-rw-r--r--sound/soc/codecs/cros_ec_codec.c43
-rw-r--r--sound/soc/codecs/cs-amp-lib-test.c2451
-rw-r--r--sound/soc/codecs/cs-amp-lib.c737
-rw-r--r--sound/soc/codecs/cs35l32.c16
-rw-r--r--sound/soc/codecs/cs35l33.c26
-rw-r--r--sound/soc/codecs/cs35l34.c45
-rw-r--r--sound/soc/codecs/cs35l35.c9
-rw-r--r--sound/soc/codecs/cs35l36.c54
-rw-r--r--sound/soc/codecs/cs35l41-i2c.c21
-rw-r--r--sound/soc/codecs/cs35l41-lib.c192
-rw-r--r--sound/soc/codecs/cs35l41-spi.c14
-rw-r--r--sound/soc/codecs/cs35l41.c247
-rw-r--r--sound/soc/codecs/cs35l41.h1
-rw-r--r--sound/soc/codecs/cs35l45-i2c.c6
-rw-r--r--sound/soc/codecs/cs35l45-spi.c4
-rw-r--r--sound/soc/codecs/cs35l45-tables.c17
-rw-r--r--sound/soc/codecs/cs35l45.c256
-rw-r--r--sound/soc/codecs/cs35l45.h38
-rw-r--r--sound/soc/codecs/cs35l56-i2c.c50
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c250
-rw-r--r--sound/soc/codecs/cs35l56-shared.c1450
-rw-r--r--sound/soc/codecs/cs35l56-spi.c32
-rw-r--r--sound/soc/codecs/cs35l56.c1319
-rw-r--r--sound/soc/codecs/cs35l56.h28
-rw-r--r--sound/soc/codecs/cs40l50-codec.c307
-rw-r--r--sound/soc/codecs/cs4234.c19
-rw-r--r--sound/soc/codecs/cs4265.c8
-rw-r--r--sound/soc/codecs/cs4270.c12
-rw-r--r--sound/soc/codecs/cs4271-i2c.c2
-rw-r--r--sound/soc/codecs/cs4271.c99
-rw-r--r--sound/soc/codecs/cs42l42-i2c.c10
-rw-r--r--sound/soc/codecs/cs42l42-sdw.c51
-rw-r--r--sound/soc/codecs/cs42l42.c64
-rw-r--r--sound/soc/codecs/cs42l42.h3
-rw-r--r--sound/soc/codecs/cs42l43-jack.c962
-rw-r--r--sound/soc/codecs/cs42l43-sdw.c71
-rw-r--r--sound/soc/codecs/cs42l43.c2476
-rw-r--r--sound/soc/codecs/cs42l43.h146
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c14
-rw-r--r--sound/soc/codecs/cs42l51.c30
-rw-r--r--sound/soc/codecs/cs42l51.h1
-rw-r--r--sound/soc/codecs/cs42l52.c125
-rw-r--r--sound/soc/codecs/cs42l56.c103
-rw-r--r--sound/soc/codecs/cs42l73.c79
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c8
-rw-r--r--sound/soc/codecs/cs42l84.c1111
-rw-r--r--sound/soc/codecs/cs42l84.h210
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c18
-rw-r--r--sound/soc/codecs/cs42xx8.c18
-rw-r--r--sound/soc/codecs/cs43130.c479
-rw-r--r--sound/soc/codecs/cs43130.h141
-rw-r--r--sound/soc/codecs/cs4341.c4
-rw-r--r--sound/soc/codecs/cs4349.c14
-rw-r--r--sound/soc/codecs/cs47l15.c23
-rw-r--r--sound/soc/codecs/cs47l24.c20
-rw-r--r--sound/soc/codecs/cs47l35.c21
-rw-r--r--sound/soc/codecs/cs47l85.c21
-rw-r--r--sound/soc/codecs/cs47l90.c21
-rw-r--r--sound/soc/codecs/cs47l92.c23
-rw-r--r--sound/soc/codecs/cs48l32-tables.c538
-rw-r--r--sound/soc/codecs/cs48l32.c4076
-rw-r--r--sound/soc/codecs/cs48l32.h403
-rw-r--r--sound/soc/codecs/cs530x-i2c.c88
-rw-r--r--sound/soc/codecs/cs530x-spi.c92
-rw-r--r--sound/soc/codecs/cs530x.c1343
-rw-r--r--sound/soc/codecs/cs530x.h253
-rw-r--r--sound/soc/codecs/cs53l30.c49
-rw-r--r--sound/soc/codecs/cx20442.c9
-rw-r--r--sound/soc/codecs/cx2072x.c38
-rw-r--r--sound/soc/codecs/da7210.c10
-rw-r--r--sound/soc/codecs/da7213.c320
-rw-r--r--sound/soc/codecs/da7213.h66
-rw-r--r--sound/soc/codecs/da7218.c56
-rw-r--r--sound/soc/codecs/da7218.h2
-rw-r--r--sound/soc/codecs/da7219-aad.c46
-rw-r--r--sound/soc/codecs/da7219.c112
-rw-r--r--sound/soc/codecs/da732x.c13
-rw-r--r--sound/soc/codecs/da9055.c13
-rw-r--r--sound/soc/codecs/dmic.c27
-rw-r--r--sound/soc/codecs/es7134.c2
-rw-r--r--sound/soc/codecs/es8311.c974
-rw-r--r--sound/soc/codecs/es8311.h162
-rw-r--r--sound/soc/codecs/es8316.c75
-rw-r--r--sound/soc/codecs/es8316.h3
-rw-r--r--sound/soc/codecs/es8323.c791
-rw-r--r--sound/soc/codecs/es8323.h78
-rw-r--r--sound/soc/codecs/es8326.c930
-rw-r--r--sound/soc/codecs/es8326.h36
-rw-r--r--sound/soc/codecs/es8328-i2c.c4
-rw-r--r--sound/soc/codecs/es8328.c35
-rw-r--r--sound/soc/codecs/es8375.c794
-rw-r--r--sound/soc/codecs/es8375.h123
-rw-r--r--sound/soc/codecs/es8389.c962
-rw-r--r--sound/soc/codecs/es8389.h140
-rw-r--r--sound/soc/codecs/es83xx-dsm-common.c89
-rw-r--r--sound/soc/codecs/es83xx-dsm-common.h393
-rw-r--r--sound/soc/codecs/framer-codec.c413
-rw-r--r--sound/soc/codecs/fs-amp-lib.c265
-rw-r--r--sound/soc/codecs/fs-amp-lib.h150
-rw-r--r--sound/soc/codecs/fs210x.c1586
-rw-r--r--sound/soc/codecs/fs210x.h75
-rw-r--r--sound/soc/codecs/gtm601.c2
-rw-r--r--sound/soc/codecs/hda-dai.c9
-rw-r--r--sound/soc/codecs/hda.c45
-rw-r--r--sound/soc/codecs/hda.h2
-rw-r--r--sound/soc/codecs/hdac_hda.c131
-rw-r--r--sound/soc/codecs/hdac_hda.h1
-rw-r--r--sound/soc/codecs/hdac_hdmi.c393
-rw-r--r--sound/soc/codecs/hdac_hdmi.h10
-rw-r--r--sound/soc/codecs/hdmi-codec.c360
-rw-r--r--sound/soc/codecs/idt821034.c39
-rw-r--r--sound/soc/codecs/inno_rk3036.c2
-rw-r--r--sound/soc/codecs/isabelle.c2
-rw-r--r--sound/soc/codecs/jz4740.c5
-rw-r--r--sound/soc/codecs/jz4760.c41
-rw-r--r--sound/soc/codecs/jz4770.c50
-rw-r--r--sound/soc/codecs/l3.c132
-rw-r--r--sound/soc/codecs/lm4857.c2
-rw-r--r--sound/soc/codecs/lm49453.c5
-rw-r--r--sound/soc/codecs/lochnagar-sc.c4
-rw-r--r--sound/soc/codecs/lpass-macro-common.c25
-rw-r--r--sound/soc/codecs/lpass-macro-common.h57
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c787
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c751
-rw-r--r--sound/soc/codecs/lpass-va-macro.c174
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c946
-rw-r--r--sound/soc/codecs/madera.c79
-rw-r--r--sound/soc/codecs/max9759.c8
-rw-r--r--sound/soc/codecs/max9768.c60
-rw-r--r--sound/soc/codecs/max98088.c116
-rw-r--r--sound/soc/codecs/max98090.c148
-rw-r--r--sound/soc/codecs/max98090.h3
-rw-r--r--sound/soc/codecs/max98095.c31
-rw-r--r--sound/soc/codecs/max98357a.c1
-rw-r--r--sound/soc/codecs/max98363.c65
-rw-r--r--sound/soc/codecs/max98371.c2
-rw-r--r--sound/soc/codecs/max98373-i2c.c27
-rw-r--r--sound/soc/codecs/max98373-sdw.c63
-rw-r--r--sound/soc/codecs/max98373.c38
-rw-r--r--sound/soc/codecs/max98373.h2
-rw-r--r--sound/soc/codecs/max98388.c12
-rw-r--r--sound/soc/codecs/max98390.c33
-rw-r--r--sound/soc/codecs/max98396.c22
-rw-r--r--sound/soc/codecs/max9850.c5
-rw-r--r--sound/soc/codecs/max98504.c8
-rw-r--r--sound/soc/codecs/max98520.c14
-rw-r--r--sound/soc/codecs/max9860.c6
-rw-r--r--sound/soc/codecs/max9867.c25
-rw-r--r--sound/soc/codecs/max9877.c2
-rw-r--r--sound/soc/codecs/max98925.c4
-rw-r--r--sound/soc/codecs/max98926.c5
-rw-r--r--sound/soc/codecs/max98927.c369
-rw-r--r--sound/soc/codecs/ml26124.c5
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c56
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c8
-rw-r--r--sound/soc/codecs/mt6351.c2
-rw-r--r--sound/soc/codecs/mt6357.c1855
-rw-r--r--sound/soc/codecs/mt6357.h660
-rw-r--r--sound/soc/codecs/mt6358.c165
-rw-r--r--sound/soc/codecs/mt6358.h4
-rw-r--r--sound/soc/codecs/mt6359-accdet.c4
-rw-r--r--sound/soc/codecs/mt6359-accdet.h9
-rw-r--r--sound/soc/codecs/mt6359.c29
-rw-r--r--sound/soc/codecs/mt6660.c14
-rw-r--r--sound/soc/codecs/nau8325.c899
-rw-r--r--sound/soc/codecs/nau8325.h391
-rw-r--r--sound/soc/codecs/nau8540.c173
-rw-r--r--sound/soc/codecs/nau8540.h28
-rw-r--r--sound/soc/codecs/nau8810.c26
-rw-r--r--sound/soc/codecs/nau8821.c264
-rw-r--r--sound/soc/codecs/nau8821.h31
-rw-r--r--sound/soc/codecs/nau8822.c109
-rw-r--r--sound/soc/codecs/nau8822.h2
-rw-r--r--sound/soc/codecs/nau8824.c69
-rw-r--r--sound/soc/codecs/nau8824.h1
-rw-r--r--sound/soc/codecs/nau8825.c117
-rw-r--r--sound/soc/codecs/ntp8835.c480
-rw-r--r--sound/soc/codecs/ntp8918.c396
-rw-r--r--sound/soc/codecs/ntpfw.c137
-rw-r--r--sound/soc/codecs/ntpfw.h23
-rw-r--r--sound/soc/codecs/pcm1681.c9
-rw-r--r--sound/soc/codecs/pcm1754.c185
-rw-r--r--sound/soc/codecs/pcm1789-i2c.c2
-rw-r--r--sound/soc/codecs/pcm179x-i2c.c2
-rw-r--r--sound/soc/codecs/pcm186x-i2c.c3
-rw-r--r--sound/soc/codecs/pcm186x.c10
-rw-r--r--sound/soc/codecs/pcm3008.c61
-rw-r--r--sound/soc/codecs/pcm3008.h19
-rw-r--r--sound/soc/codecs/pcm3060-i2c.c4
-rw-r--r--sound/soc/codecs/pcm3060-spi.c4
-rw-r--r--sound/soc/codecs/pcm3060.c4
-rw-r--r--sound/soc/codecs/pcm3060.h2
-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.c21
-rw-r--r--sound/soc/codecs/pcm5102a.c2
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c8
-rw-r--r--sound/soc/codecs/pcm512x-spi.c4
-rw-r--r--sound/soc/codecs/pcm512x.c68
-rw-r--r--sound/soc/codecs/pcm6240.c2167
-rw-r--r--sound/soc/codecs/pcm6240.h247
-rw-r--r--sound/soc/codecs/peb2466.c43
-rw-r--r--sound/soc/codecs/pm4125-sdw.c495
-rw-r--r--sound/soc/codecs/pm4125.c1761
-rw-r--r--sound/soc/codecs/pm4125.h293
-rw-r--r--sound/soc/codecs/rk3308_codec.c975
-rw-r--r--sound/soc/codecs/rk3308_codec.h579
-rw-r--r--sound/soc/codecs/rk817_codec.c7
-rw-r--r--sound/soc/codecs/rt-sdw-common.c238
-rw-r--r--sound/soc/codecs/rt-sdw-common.h66
-rw-r--r--sound/soc/codecs/rt1011.c50
-rw-r--r--sound/soc/codecs/rt1015.c43
-rw-r--r--sound/soc/codecs/rt1015p.c1
-rw-r--r--sound/soc/codecs/rt1016.c13
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c822
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.h183
-rw-r--r--sound/soc/codecs/rt1019.c11
-rw-r--r--sound/soc/codecs/rt1305.c20
-rw-r--r--sound/soc/codecs/rt1308-sdw.c79
-rw-r--r--sound/soc/codecs/rt1308.c14
-rw-r--r--sound/soc/codecs/rt1316-sdw.c76
-rw-r--r--sound/soc/codecs/rt1318-sdw.c63
-rw-r--r--sound/soc/codecs/rt1318.c1353
-rw-r--r--sound/soc/codecs/rt1318.h342
-rw-r--r--sound/soc/codecs/rt1320-sdw.c1823
-rw-r--r--sound/soc/codecs/rt1320-sdw.h113
-rw-r--r--sound/soc/codecs/rt274.c21
-rw-r--r--sound/soc/codecs/rt286.c23
-rw-r--r--sound/soc/codecs/rt298.c23
-rw-r--r--sound/soc/codecs/rt5514-spi.c11
-rw-r--r--sound/soc/codecs/rt5514.c37
-rw-r--r--sound/soc/codecs/rt5616.c22
-rw-r--r--sound/soc/codecs/rt5631.c20
-rw-r--r--sound/soc/codecs/rt5640.c197
-rw-r--r--sound/soc/codecs/rt5640.h8
-rw-r--r--sound/soc/codecs/rt5645.c319
-rw-r--r--sound/soc/codecs/rt5645.h9
-rw-r--r--sound/soc/codecs/rt5651.c31
-rw-r--r--sound/soc/codecs/rt5659.c32
-rw-r--r--sound/soc/codecs/rt5660.c39
-rw-r--r--sound/soc/codecs/rt5663.c39
-rw-r--r--sound/soc/codecs/rt5665.c157
-rw-r--r--sound/soc/codecs/rt5665.h3
-rw-r--r--sound/soc/codecs/rt5668.c79
-rw-r--r--sound/soc/codecs/rt5668.h3
-rw-r--r--sound/soc/codecs/rt5670.c63
-rw-r--r--sound/soc/codecs/rt5677-spi.c11
-rw-r--r--sound/soc/codecs/rt5677.c141
-rw-r--r--sound/soc/codecs/rt5677.h92
-rw-r--r--sound/soc/codecs/rt5682-i2c.c43
-rw-r--r--sound/soc/codecs/rt5682-sdw.c98
-rw-r--r--sound/soc/codecs/rt5682.c85
-rw-r--r--sound/soc/codecs/rt5682.h6
-rw-r--r--sound/soc/codecs/rt5682s.c103
-rw-r--r--sound/soc/codecs/rt5682s.h9
-rw-r--r--sound/soc/codecs/rt700-sdw.c20
-rw-r--r--sound/soc/codecs/rt700.c94
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c36
-rw-r--r--sound/soc/codecs/rt711-sdca.c149
-rw-r--r--sound/soc/codecs/rt711-sdca.h1
-rw-r--r--sound/soc/codecs/rt711-sdw.c35
-rw-r--r--sound/soc/codecs/rt711.c93
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c104
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c68
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.h95
-rw-r--r--sound/soc/codecs/rt712-sdca.c826
-rw-r--r--sound/soc/codecs/rt712-sdca.h52
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c20
-rw-r--r--sound/soc/codecs/rt715-sdca.c117
-rw-r--r--sound/soc/codecs/rt715-sdw.c66
-rw-r--r--sound/soc/codecs/rt715.c164
-rw-r--r--sound/soc/codecs/rt715.h10
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c548
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.h150
-rw-r--r--sound/soc/codecs/rt721-sdca.c1561
-rw-r--r--sound/soc/codecs/rt721-sdca.h274
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c202
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.h100
-rw-r--r--sound/soc/codecs/rt722-sdca.c494
-rw-r--r--sound/soc/codecs/rt722-sdca.h19
-rw-r--r--sound/soc/codecs/rt9120.c8
-rw-r--r--sound/soc/codecs/rt9123.c500
-rw-r--r--sound/soc/codecs/rt9123p.c171
-rw-r--r--sound/soc/codecs/rtq9124.c543
-rw-r--r--sound/soc/codecs/rtq9128.c789
-rw-r--r--sound/soc/codecs/sdw-mockup.c1
-rw-r--r--sound/soc/codecs/sgtl5000.c16
-rw-r--r--sound/soc/codecs/sigmadsp-i2c.c2
-rw-r--r--sound/soc/codecs/sigmadsp.c33
-rw-r--r--sound/soc/codecs/simple-mux.c97
-rw-r--r--sound/soc/codecs/sma1303.c35
-rw-r--r--sound/soc/codecs/sma1307.c2044
-rw-r--r--sound/soc/codecs/sma1307.h444
-rw-r--r--sound/soc/codecs/spdif_receiver.c5
-rw-r--r--sound/soc/codecs/spdif_transmitter.c5
-rw-r--r--sound/soc/codecs/src4xxx-i2c.c2
-rw-r--r--sound/soc/codecs/src4xxx.c4
-rw-r--r--sound/soc/codecs/ssm2518.c5
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c5
-rw-r--r--sound/soc/codecs/ssm2602.c4
-rw-r--r--sound/soc/codecs/ssm3515.c2
-rw-r--r--sound/soc/codecs/ssm4567.c5
-rw-r--r--sound/soc/codecs/sta32x.c27
-rw-r--r--sound/soc/codecs/sta350.c17
-rw-r--r--sound/soc/codecs/sta529.c7
-rw-r--r--sound/soc/codecs/stac9766.c2
-rw-r--r--sound/soc/codecs/sti-sas.c23
-rw-r--r--sound/soc/codecs/tas2552.c29
-rw-r--r--sound/soc/codecs/tas2562.c25
-rw-r--r--sound/soc/codecs/tas2764-quirks.h180
-rw-r--r--sound/soc/codecs/tas2764.c264
-rw-r--r--sound/soc/codecs/tas2764.h18
-rw-r--r--sound/soc/codecs/tas2770.c214
-rw-r--r--sound/soc/codecs/tas2770.h6
-rw-r--r--sound/soc/codecs/tas2780.c9
-rw-r--r--sound/soc/codecs/tas2781-comlib-i2c.c371
-rw-r--r--sound/soc/codecs/tas2781-comlib.c221
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c2618
-rw-r--r--sound/soc/codecs/tas2781-i2c.c2132
-rw-r--r--sound/soc/codecs/tas2783-sdw.c1347
-rw-r--r--sound/soc/codecs/tas2783.h110
-rw-r--r--sound/soc/codecs/tas5086.c38
-rw-r--r--sound/soc/codecs/tas571x.c143
-rw-r--r--sound/soc/codecs/tas571x.h34
-rw-r--r--sound/soc/codecs/tas5720.c14
-rw-r--r--sound/soc/codecs/tas5805m.c11
-rw-r--r--sound/soc/codecs/tas6424.c8
-rw-r--r--sound/soc/codecs/tda7419.c3
-rw-r--r--sound/soc/codecs/tfa9879.c2
-rw-r--r--sound/soc/codecs/tfa989x.c2
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c135
-rw-r--r--sound/soc/codecs/tlv320adcx140.c7
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c2
-rw-r--r--sound/soc/codecs/tlv320aic23.c4
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c129
-rw-r--r--sound/soc/codecs/tlv320aic32x4-clk.c45
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c19
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c19
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c88
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h8
-rw-r--r--sound/soc/codecs/tlv320aic3x-i2c.c3
-rw-r--r--sound/soc/codecs/tlv320aic3x-spi.c1
-rw-r--r--sound/soc/codecs/tlv320aic3x.c49
-rw-r--r--sound/soc/codecs/tlv320dac33.c84
-rw-r--r--sound/soc/codecs/tpa6130a2.c58
-rw-r--r--sound/soc/codecs/ts3a227e.c9
-rw-r--r--sound/soc/codecs/tscs42xx.c10
-rw-r--r--sound/soc/codecs/tscs454.c13
-rw-r--r--sound/soc/codecs/twl4030.c107
-rw-r--r--sound/soc/codecs/twl6040.c15
-rw-r--r--sound/soc/codecs/uda1334.c6
-rw-r--r--sound/soc/codecs/uda1342.c347
-rw-r--r--sound/soc/codecs/uda1342.h78
-rw-r--r--sound/soc/codecs/uda134x.c587
-rw-r--r--sound/soc/codecs/uda134x.h33
-rw-r--r--sound/soc/codecs/uda1380.c11
-rw-r--r--sound/soc/codecs/wcd-clsh-v2.c8
-rw-r--r--sound/soc/codecs/wcd-clsh-v2.h1
-rw-r--r--sound/soc/codecs/wcd-common.c144
-rw-r--r--sound/soc/codecs/wcd-common.h46
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c160
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.h9
-rw-r--r--sound/soc/codecs/wcd9335.c228
-rw-r--r--sound/soc/codecs/wcd934x.c253
-rw-r--r--sound/soc/codecs/wcd937x-sdw.c1115
-rw-r--r--sound/soc/codecs/wcd937x.c2987
-rw-r--r--sound/soc/codecs/wcd937x.h618
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c121
-rw-r--r--sound/soc/codecs/wcd938x.c473
-rw-r--r--sound/soc/codecs/wcd938x.h38
-rw-r--r--sound/soc/codecs/wcd939x-sdw.c1477
-rw-r--r--sound/soc/codecs/wcd939x.c3623
-rw-r--r--sound/soc/codecs/wcd939x.h947
-rw-r--r--sound/soc/codecs/wl1273.c500
-rw-r--r--sound/soc/codecs/wl1273.h16
-rw-r--r--sound/soc/codecs/wm0010.c73
-rw-r--r--sound/soc/codecs/wm1250-ev1.c121
-rw-r--r--sound/soc/codecs/wm2000.c10
-rw-r--r--sound/soc/codecs/wm2200.c98
-rw-r--r--sound/soc/codecs/wm5100.c138
-rw-r--r--sound/soc/codecs/wm5102.c22
-rw-r--r--sound/soc/codecs/wm5110.c44
-rw-r--r--sound/soc/codecs/wm8350.c11
-rw-r--r--sound/soc/codecs/wm8400.c18
-rw-r--r--sound/soc/codecs/wm8510.c13
-rw-r--r--sound/soc/codecs/wm8523.c13
-rw-r--r--sound/soc/codecs/wm8524.c59
-rw-r--r--sound/soc/codecs/wm8580.c42
-rw-r--r--sound/soc/codecs/wm8711.c13
-rw-r--r--sound/soc/codecs/wm8728.c11
-rw-r--r--sound/soc/codecs/wm8731-i2c.c4
-rw-r--r--sound/soc/codecs/wm8731-spi.c2
-rw-r--r--sound/soc/codecs/wm8731.c11
-rw-r--r--sound/soc/codecs/wm8737.c16
-rw-r--r--sound/soc/codecs/wm8741.c8
-rw-r--r--sound/soc/codecs/wm8750.c15
-rw-r--r--sound/soc/codecs/wm8753.c25
-rw-r--r--sound/soc/codecs/wm8770.c11
-rw-r--r--sound/soc/codecs/wm8776.c11
-rw-r--r--sound/soc/codecs/wm8782.c63
-rw-r--r--sound/soc/codecs/wm8804-i2c.c4
-rw-r--r--sound/soc/codecs/wm8804-spi.c2
-rw-r--r--sound/soc/codecs/wm8804.c18
-rw-r--r--sound/soc/codecs/wm8900.c24
-rw-r--r--sound/soc/codecs/wm8903.c32
-rw-r--r--sound/soc/codecs/wm8904.c360
-rw-r--r--sound/soc/codecs/wm8940.c23
-rw-r--r--sound/soc/codecs/wm8955.c18
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c34
-rw-r--r--sound/soc/codecs/wm8960.c93
-rw-r--r--sound/soc/codecs/wm8960.h4
-rw-r--r--sound/soc/codecs/wm8961.c13
-rw-r--r--sound/soc/codecs/wm8962.c111
-rw-r--r--sound/soc/codecs/wm8971.c11
-rw-r--r--sound/soc/codecs/wm8974.c23
-rw-r--r--sound/soc/codecs/wm8978.c17
-rw-r--r--sound/soc/codecs/wm8983.c15
-rw-r--r--sound/soc/codecs/wm8985.c19
-rw-r--r--sound/soc/codecs/wm8988.c11
-rw-r--r--sound/soc/codecs/wm8990.c15
-rw-r--r--sound/soc/codecs/wm8991.c13
-rw-r--r--sound/soc/codecs/wm8993.c37
-rw-r--r--sound/soc/codecs/wm8994.c72
-rw-r--r--sound/soc/codecs/wm8994.h12
-rw-r--r--sound/soc/codecs/wm8995.c17
-rw-r--r--sound/soc/codecs/wm8996.c107
-rw-r--r--sound/soc/codecs/wm8997.c6
-rw-r--r--sound/soc/codecs/wm8998.c10
-rw-r--r--sound/soc/codecs/wm9081.c19
-rw-r--r--sound/soc/codecs/wm9090.c11
-rw-r--r--sound/soc/codecs/wm9705.c2
-rw-r--r--sound/soc/codecs/wm9712.c19
-rw-r--r--sound/soc/codecs/wm9713.c27
-rw-r--r--sound/soc/codecs/wm_adsp.c281
-rw-r--r--sound/soc/codecs/wm_adsp.h12
-rw-r--r--sound/soc/codecs/wm_hubs.c13
-rw-r--r--sound/soc/codecs/wsa881x.c85
-rw-r--r--sound/soc/codecs/wsa883x.c375
-rw-r--r--sound/soc/codecs/wsa884x.c2181
-rw-r--r--sound/soc/codecs/zl38060.c10
-rw-r--r--sound/soc/dwc/Kconfig3
-rw-r--r--sound/soc/dwc/dwc-i2s.c454
-rw-r--r--sound/soc/dwc/dwc-pcm.c12
-rw-r--r--sound/soc/dwc/local.h31
-rw-r--r--sound/soc/fsl/Kconfig39
-rw-r--r--sound/soc/fsl/Makefile58
-rw-r--r--sound/soc/fsl/efika-audio-fabric.c4
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c14
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c501
-rw-r--r--sound/soc/fsl/fsl_asrc.c202
-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_dma.c23
-rw-r--r--sound/soc/fsl/fsl_asrc_m2m.c729
-rw-r--r--sound/soc/fsl/fsl_aud2htx.c31
-rw-r--r--sound/soc/fsl/fsl_aud2htx.h3
-rw-r--r--sound/soc/fsl/fsl_audmix.c46
-rw-r--r--sound/soc/fsl/fsl_dma.c4
-rw-r--r--sound/soc/fsl/fsl_easrc.c297
-rw-r--r--sound/soc/fsl/fsl_easrc.h4
-rw-r--r--sound/soc/fsl/fsl_esai.c35
-rw-r--r--sound/soc/fsl/fsl_micfil.c513
-rw-r--r--sound/soc/fsl/fsl_micfil.h71
-rw-r--r--sound/soc/fsl/fsl_mqs.c135
-rw-r--r--sound/soc/fsl/fsl_qmc_audio.c601
-rw-r--r--sound/soc/fsl/fsl_rpmsg.c110
-rw-r--r--sound/soc/fsl/fsl_rpmsg.h2
-rw-r--r--sound/soc/fsl/fsl_sai.c377
-rw-r--r--sound/soc/fsl/fsl_sai.h16
-rw-r--r--sound/soc/fsl/fsl_spdif.c82
-rw-r--r--sound/soc/fsl/fsl_spdif.h6
-rw-r--r--sound/soc/fsl/fsl_ssi.c31
-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.c743
-rw-r--r--sound/soc/fsl/fsl_xcvr.h109
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c22
-rw-r--r--sound/soc/fsl/imx-audmix.c126
-rw-r--r--sound/soc/fsl/imx-audmux.c13
-rw-r--r--sound/soc/fsl/imx-card.c173
-rw-r--r--sound/soc/fsl/imx-es8328.c43
-rw-r--r--sound/soc/fsl/imx-hdmi.c19
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c1
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c4
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c83
-rw-r--r--sound/soc/fsl/imx-rpmsg.c105
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c4
-rw-r--r--sound/soc/fsl/imx-spdif.c103
-rw-r--r--sound/soc/fsl/lpc3xxx-i2s.c372
-rw-r--r--sound/soc/fsl/lpc3xxx-i2s.h80
-rw-r--r--sound/soc/fsl/lpc3xxx-pcm.c72
-rw-r--r--sound/soc/fsl/mpc5200_dma.c25
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c7
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c11
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c451
-rw-r--r--sound/soc/fsl/p1022_ds.c10
-rw-r--r--sound/soc/fsl/p1022_rdk.c43
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c5
-rw-r--r--sound/soc/generic/Kconfig4
-rw-r--r--sound/soc/generic/Makefile12
-rw-r--r--sound/soc/generic/audio-graph-card.c444
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample.c35
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample.dtsi393
-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.c778
-rw-r--r--sound/soc/generic/simple-card-utils.c596
-rw-r--r--sound/soc/generic/simple-card.c427
-rw-r--r--sound/soc/generic/test-component.c37
-rw-r--r--sound/soc/google/Kconfig3
-rw-r--r--sound/soc/google/chv3-i2s.c23
-rw-r--r--sound/soc/hisilicon/Kconfig4
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c3
-rw-r--r--sound/soc/img/Kconfig14
-rw-r--r--sound/soc/img/img-i2s-in.c29
-rw-r--r--sound/soc/img/img-i2s-out.c29
-rw-r--r--sound/soc/img/img-parallel-out.c21
-rw-r--r--sound/soc/img/img-spdif-in.c23
-rw-r--r--sound/soc/img/img-spdif-out.c24
-rw-r--r--sound/soc/img/pistachio-internal-dac.c10
-rw-r--r--sound/soc/intel/Kconfig133
-rw-r--r--sound/soc/intel/Makefile1
-rw-r--r--sound/soc/intel/atom/Makefile2
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c15
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-compress.c12
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c16
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform.h2
-rw-r--r--sound/soc/intel/atom/sst/Makefile6
-rw-r--r--sound/soc/intel/atom/sst/sst.c16
-rw-r--r--sound/soc/intel/atom/sst/sst.h13
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c69
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c33
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c3
-rw-r--r--sound/soc/intel/atom/sst/sst_pci.c63
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c34
-rw-r--r--sound/soc/intel/atom/sst/sst_stream.c13
-rw-r--r--sound/soc/intel/avs/Makefile13
-rw-r--r--sound/soc/intel/avs/apl.c86
-rw-r--r--sound/soc/intel/avs/avs.h198
-rw-r--r--sound/soc/intel/avs/board_selection.c469
-rw-r--r--sound/soc/intel/avs/boards/Kconfig60
-rw-r--r--sound/soc/intel/avs/boards/Makefile38
-rw-r--r--sound/soc/intel/avs/boards/da7219.c113
-rw-r--r--sound/soc/intel/avs/boards/dmic.c105
-rw-r--r--sound/soc/intel/avs/boards/es8336.c331
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c67
-rw-r--r--sound/soc/intel/avs/boards/i2s_test.c139
-rw-r--r--sound/soc/intel/avs/boards/max98357a.c55
-rw-r--r--sound/soc/intel/avs/boards/max98373.c57
-rw-r--r--sound/soc/intel/avs/boards/max98927.c59
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c73
-rw-r--r--sound/soc/intel/avs/boards/pcm3168a.c155
-rw-r--r--sound/soc/intel/avs/boards/probe.c67
-rw-r--r--sound/soc/intel/avs/boards/rt274.c73
-rw-r--r--sound/soc/intel/avs/boards/rt286.c73
-rw-r--r--sound/soc/intel/avs/boards/rt298.c74
-rw-r--r--sound/soc/intel/avs/boards/rt5514.c197
-rw-r--r--sound/soc/intel/avs/boards/rt5640.c271
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c268
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c129
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c64
-rw-r--r--sound/soc/intel/avs/cldma.c46
-rw-r--r--sound/soc/intel/avs/cldma.h7
-rw-r--r--sound/soc/intel/avs/cnl.c92
-rw-r--r--sound/soc/intel/avs/control.c209
-rw-r--r--sound/soc/intel/avs/control.h14
-rw-r--r--sound/soc/intel/avs/core.c414
-rw-r--r--sound/soc/intel/avs/debug.h91
-rw-r--r--sound/soc/intel/avs/debugfs.c34
-rw-r--r--sound/soc/intel/avs/dsp.c11
-rw-r--r--sound/soc/intel/avs/icl.c203
-rw-r--r--sound/soc/intel/avs/ipc.c177
-rw-r--r--sound/soc/intel/avs/lnl.c28
-rw-r--r--sound/soc/intel/avs/loader.c118
-rw-r--r--sound/soc/intel/avs/messages.c286
-rw-r--r--sound/soc/intel/avs/messages.h176
-rw-r--r--sound/soc/intel/avs/mtl.c201
-rw-r--r--sound/soc/intel/avs/path.c811
-rw-r--r--sound/soc/intel/avs/path.h27
-rw-r--r--sound/soc/intel/avs/pcm.c718
-rw-r--r--sound/soc/intel/avs/pcm.h16
-rw-r--r--sound/soc/intel/avs/probes.c74
-rw-r--r--sound/soc/intel/avs/ptl.c99
-rw-r--r--sound/soc/intel/avs/registers.h112
-rw-r--r--sound/soc/intel/avs/skl.c98
-rw-r--r--sound/soc/intel/avs/sysfs.c35
-rw-r--r--sound/soc/intel/avs/tgl.c87
-rw-r--r--sound/soc/intel/avs/topology.c604
-rw-r--r--sound/soc/intel/avs/topology.h49
-rw-r--r--sound/soc/intel/avs/trace.c2
-rw-r--r--sound/soc/intel/avs/trace.h42
-rw-r--r--sound/soc/intel/avs/utils.c10
-rw-r--r--sound/soc/intel/avs/utils.h77
-rw-r--r--sound/soc/intel/boards/Kconfig270
-rw-r--r--sound/soc/intel/boards/Makefile98
-rw-r--r--sound/soc/intel/boards/bdw-rt5650.c12
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c23
-rw-r--r--sound/soc/intel/boards/bdw_rt286.c26
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c881
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c668
-rw-r--r--sound/soc/intel/boards/bytcht_cx2072x.c26
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c25
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c121
-rw-r--r--sound/soc/intel/boards/bytcht_nocodec.c10
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c199
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c67
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c266
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c21
-rw-r--r--sound/soc/intel/boards/cht_bsw_nau8824.c14
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c53
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c42
-rw-r--r--sound/soc/intel/boards/cml_rt1011_rt5682.c609
-rw-r--r--sound/soc/intel/boards/ehl_rt5660.c29
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c691
-rw-r--r--sound/soc/intel/boards/hda_dsp_common.c19
-rw-r--r--sound/soc/intel/boards/hsw_rt5640.c16
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c680
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c1164
-rw-r--r--sound/soc/intel/boards/kbl_rt5660.c566
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c1071
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c868
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.c168
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.h66
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c273
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c703
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c751
-rw-r--r--sound/soc/intel/boards/skl_rt286.c567
-rw-r--r--sound/soc/intel/boards/sof_board_helpers.c785
-rw-r--r--sound/soc/intel/boards/sof_board_helpers.h173
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.c11
-rw-r--r--sound/soc/intel/boards/sof_cirrus_common.h9
-rw-r--r--sound/soc/intel/boards/sof_cs42l42.c600
-rw-r--r--sound/soc/intel/boards/sof_da7219.c490
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c472
-rw-r--r--sound/soc/intel/boards/sof_es8336.c84
-rw-r--r--sound/soc/intel/boards/sof_hdmi_common.h24
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.c420
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.h37
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c583
-rw-r--r--sound/soc/intel/boards/sof_nuvoton_common.c74
-rw-r--r--sound/soc/intel/boards/sof_nuvoton_common.h22
-rw-r--r--sound/soc/intel/boards/sof_pcm512x.c35
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.c364
-rw-r--r--sound/soc/intel/boards/sof_realtek_common.h40
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c1251
-rw-r--r--sound/soc/intel/boards/sof_sdw.c2265
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h168
-rw-r--r--sound/soc/intel/boards/sof_sdw_hdmi.c40
-rw-r--r--sound/soc/intel/boards/sof_sdw_maxim.c167
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt712_sdca.c102
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715.c36
-rw-r--r--sound/soc/intel/boards/sof_sdw_rt715_sdca.c36
-rw-r--r--sound/soc/intel/boards/sof_ssp_amp.c496
-rw-r--r--sound/soc/intel/boards/sof_wm8804.c14
-rw-r--r--sound/soc/intel/catpt/Makefile2
-rw-r--r--sound/soc/intel/catpt/core.h2
-rw-r--r--sound/soc/intel/catpt/device.c42
-rw-r--r--sound/soc/intel/catpt/dsp.c8
-rw-r--r--sound/soc/intel/catpt/ipc.c2
-rw-r--r--sound/soc/intel/catpt/loader.c20
-rw-r--r--sound/soc/intel/catpt/messages.c2
-rw-r--r--sound/soc/intel/catpt/messages.h2
-rw-r--r--sound/soc/intel/catpt/pcm.c82
-rw-r--r--sound/soc/intel/catpt/registers.h2
-rw-r--r--sound/soc/intel/catpt/sysfs.c5
-rw-r--r--sound/soc/intel/catpt/trace.h2
-rw-r--r--sound/soc/intel/common/Makefile15
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c280
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c534
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cht-match.c42
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cml-match.c12
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cnl-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ehl-match.c1
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-glk-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hda-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c8
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-jsl-match.c32
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-kbl-match.c11
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c731
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c967
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-nvl-match.c90
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ptl-match.c773
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-rpl-match.c182
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c42
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h14
-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-skl-match.c5
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ssp-common.c168
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c341
-rw-r--r--sound/soc/intel/common/soc-intel-quirks.h2
-rw-r--r--sound/soc/intel/common/sof-function-topology-lib.c140
-rw-r--r--sound/soc/intel/common/sof-function-topology-lib.h15
-rw-r--r--sound/soc/intel/common/sst-dsp-priv.h101
-rw-r--r--sound/soc/intel/common/sst-dsp.c250
-rw-r--r--sound/soc/intel/common/sst-dsp.h61
-rw-r--r--sound/soc/intel/common/sst-ipc.c294
-rw-r--r--sound/soc/intel/common/sst-ipc.h86
-rw-r--r--sound/soc/intel/keembay/Makefile2
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c24
-rw-r--r--sound/soc/intel/skylake/Makefile15
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c629
-rw-r--r--sound/soc/intel/skylake/cnl-sst-dsp.c266
-rw-r--r--sound/soc/intel/skylake/cnl-sst-dsp.h103
-rw-r--r--sound/soc/intel/skylake/cnl-sst.c508
-rw-r--r--sound/soc/intel/skylake/skl-debug.c248
-rw-r--r--sound/soc/intel/skylake/skl-i2s.h87
-rw-r--r--sound/soc/intel/skylake/skl-messages.c1419
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c269
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c1505
-rw-r--r--sound/soc/intel/skylake/skl-ssp-clk.c428
-rw-r--r--sound/soc/intel/skylake/skl-ssp-clk.h108
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c373
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.h243
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c462
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h256
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c1069
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h169
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c424
-rw-r--r--sound/soc/intel/skylake/skl-sst.c599
-rw-r--r--sound/soc/intel/skylake/skl-topology.c3774
-rw-r--r--sound/soc/intel/skylake/skl-topology.h524
-rw-r--r--sound/soc/intel/skylake/skl.c1205
-rw-r--r--sound/soc/intel/skylake/skl.h207
-rw-r--r--sound/soc/jz4740/Kconfig4
-rw-r--r--sound/soc/jz4740/Makefile2
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c3
-rw-r--r--sound/soc/kirkwood/Kconfig3
-rw-r--r--sound/soc/kirkwood/Makefile4
-rw-r--r--sound/soc/kirkwood/armada-370-db.c10
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c7
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c2
-rw-r--r--sound/soc/loongson/Kconfig44
-rw-r--r--sound/soc/loongson/Makefile13
-rw-r--r--sound/soc/loongson/loongson1_ac97.c398
-rw-r--r--sound/soc/loongson/loongson_card.c166
-rw-r--r--sound/soc/loongson/loongson_dma.c31
-rw-r--r--sound/soc/loongson/loongson_i2s.c139
-rw-r--r--sound/soc/loongson/loongson_i2s.h26
-rw-r--r--sound/soc/loongson/loongson_i2s_pci.c65
-rw-r--r--sound/soc/loongson/loongson_i2s_plat.c185
-rw-r--r--sound/soc/mediatek/Kconfig103
-rw-r--r--sound/soc/mediatek/Makefile3
-rw-r--r--sound/soc/mediatek/common/Makefile4
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c42
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.h2
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.c35
-rw-r--r--sound/soc/mediatek/common/mtk-base-afe.h1
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c53
-rw-r--r--sound/soc/mediatek/common/mtk-dai-adda-common.c70
-rw-r--r--sound/soc/mediatek/common/mtk-dai-adda-common.h45
-rw-r--r--sound/soc/mediatek/common/mtk-dsp-sof-common.c123
-rw-r--r--sound/soc/mediatek/common/mtk-dsp-sof-common.h7
-rw-r--r--sound/soc/mediatek/common/mtk-soc-card.h8
-rw-r--r--sound/soc/mediatek/common/mtk-soundcard-driver.c245
-rw-r--r--sound/soc/mediatek/common/mtk-soundcard-driver.h42
-rw-r--r--sound/soc/mediatek/mt2701/Makefile2
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c14
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-cs42448.c104
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c14
-rw-r--r--sound/soc/mediatek/mt6797/Makefile2
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c28
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-adda.c85
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-mt6351.c24
-rw-r--r--sound/soc/mediatek/mt7986/Makefile9
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-afe-common.h49
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-afe-pcm.c609
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-dai-etdm.c426
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-reg.h196
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-wm8960.c175
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c78
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c17
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c37
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c45
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c49
-rw-r--r--sound/soc/mediatek/mt8183/Makefile2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-pcm.c653
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c97
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-adda.c94
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-dai-i2s.c15
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c113
-rw-r--r--sound/soc/mediatek/mt8186/Makefile5
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-clk.c57
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-clk.h2
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-gpio.c1
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-pcm.c55
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-dai-adda.c100
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c2
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-dai-i2s.c8
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-dai-src.c4
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-dai-tdm.c6
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-misc-control.c12
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366-common.c4
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c1183
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366.c (renamed from sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c)740
-rw-r--r--sound/soc/mediatek/mt8188/Makefile3
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-clk.c15
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-clk.h9
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-common.h1
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-pcm.c94
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-audsys-clk.c51
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-audsys-clk.h1
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h4
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-dai-adda.c94
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-dai-dmic.c683
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-dai-etdm.c12
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-dai-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-mt6359.c626
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-reg.h17
-rw-r--r--sound/soc/mediatek/mt8189/Makefile18
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-afe-clk.c750
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-afe-clk.h76
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-afe-common.h240
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-afe-pcm.c2615
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-dai-adda.c1228
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-dai-i2s.c1463
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-dai-pcm.c332
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-dai-tdm.c672
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-interconnection.h97
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-nau8825.c1178
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-reg.h10773
-rw-r--r--sound/soc/mediatek/mt8192/Makefile2
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-gpio.c1
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-pcm.c152
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-adda.c106
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-i2s.c8
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-dai-tdm.c4
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c400
-rw-r--r--sound/soc/mediatek/mt8195/Makefile2
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-clk.c5
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-clk.h1
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-pcm.c93
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-audsys-clk.c47
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-audsys-clk.h1
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-dai-adda.c98
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-dai-etdm.c59
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-dai-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359.c670
-rw-r--r--sound/soc/mediatek/mt8365/Makefile15
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-clk.c420
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-clk.h32
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-common.h448
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-pcm.c2271
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-adda.c311
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-dmic.c310
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-i2s.c845
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-pcm.c293
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-mt6357.c346
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-reg.h993
-rw-r--r--sound/soc/meson/Kconfig3
-rw-r--r--sound/soc/meson/Makefile50
-rw-r--r--sound/soc/meson/aiu-acodec-ctrl.c10
-rw-r--r--sound/soc/meson/aiu-codec-ctrl.c10
-rw-r--r--sound/soc/meson/aiu-encoder-i2s.c9
-rw-r--r--sound/soc/meson/aiu-fifo-i2s.c5
-rw-r--r--sound/soc/meson/aiu-fifo-spdif.c5
-rw-r--r--sound/soc/meson/aiu-fifo.c4
-rw-r--r--sound/soc/meson/aiu-fifo.h4
-rw-r--r--sound/soc/meson/aiu.c27
-rw-r--r--sound/soc/meson/aiu.h1
-rw-r--r--sound/soc/meson/axg-card.c39
-rw-r--r--sound/soc/meson/axg-fifo.c52
-rw-r--r--sound/soc/meson/axg-fifo.h14
-rw-r--r--sound/soc/meson/axg-frddr.c17
-rw-r--r--sound/soc/meson/axg-pdm.c18
-rw-r--r--sound/soc/meson/axg-spdifin.c59
-rw-r--r--sound/soc/meson/axg-spdifout.c4
-rw-r--r--sound/soc/meson/axg-tdm-formatter.c82
-rw-r--r--sound/soc/meson/axg-tdm-interface.c100
-rw-r--r--sound/soc/meson/axg-tdm.h7
-rw-r--r--sound/soc/meson/axg-toddr.c34
-rw-r--r--sound/soc/meson/g12a-toacodec.c15
-rw-r--r--sound/soc/meson/g12a-tohdmitx.c24
-rw-r--r--sound/soc/meson/gx-card.c8
-rw-r--r--sound/soc/meson/meson-card-utils.c52
-rw-r--r--sound/soc/meson/meson-card.h5
-rw-r--r--sound/soc/meson/meson-codec-glue.c2
-rw-r--r--sound/soc/meson/t9015.c28
-rw-r--r--sound/soc/mxs/Kconfig2
-rw-r--r--sound/soc/mxs/Makefile6
-rw-r--r--sound/soc/mxs/mxs-pcm.c1
-rw-r--r--sound/soc/mxs/mxs-saif.c124
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c11
-rw-r--r--sound/soc/pxa/Kconfig12
-rw-r--r--sound/soc/pxa/Makefile12
-rw-r--r--sound/soc/pxa/mmp-sspa.c4
-rw-r--r--sound/soc/pxa/pxa-ssp.c14
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c8
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c21
-rw-r--r--sound/soc/pxa/spitz.c19
-rw-r--r--sound/soc/qcom/Kconfig33
-rw-r--r--sound/soc/qcom/Makefile40
-rw-r--r--sound/soc/qcom/apq8016_sbc.c52
-rw-r--r--sound/soc/qcom/apq8096.c12
-rw-r--r--sound/soc/qcom/common.c79
-rw-r--r--sound/soc/qcom/common.h3
-rw-r--r--sound/soc/qcom/lpass-apq8016.c14
-rw-r--r--sound/soc/qcom/lpass-cdc-dma.c24
-rw-r--r--sound/soc/qcom/lpass-cpu.c97
-rw-r--r--sound/soc/qcom/lpass-hdmi.c4
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c7
-rw-r--r--sound/soc/qcom/lpass-platform.c131
-rw-r--r--sound/soc/qcom/lpass-sc7180.c21
-rw-r--r--sound/soc/qcom/lpass-sc7280.c16
-rw-r--r--sound/soc/qcom/lpass.h13
-rw-r--r--sound/soc/qcom/qdsp6/Makefile5
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.c474
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.h88
-rw-r--r--sound/soc/qcom/qdsp6/q6adm.c179
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-clocks.c1
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c165
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c250
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.h38
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-dai.c519
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-lpass-dais.c61
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c157
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.h12
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c184
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c206
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.h22
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-common.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c9
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c26
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h1
-rw-r--r--sound/soc/qcom/qdsp6/q6prm-clocks.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.c27
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c26
-rw-r--r--sound/soc/qcom/qdsp6/q6usb.c422
-rw-r--r--sound/soc/qcom/qdsp6/topology.c102
-rw-r--r--sound/soc/qcom/sc7180.c277
-rw-r--r--sound/soc/qcom/sc7280.c170
-rw-r--r--sound/soc/qcom/sc8280xp.c94
-rw-r--r--sound/soc/qcom/sdm845.c135
-rw-r--r--sound/soc/qcom/sdw.c210
-rw-r--r--sound/soc/qcom/sdw.h8
-rw-r--r--sound/soc/qcom/sm8250.c97
-rw-r--r--sound/soc/qcom/storm.c6
-rw-r--r--sound/soc/qcom/usb_offload_utils.c56
-rw-r--r--sound/soc/qcom/usb_offload_utils.h30
-rw-r--r--sound/soc/qcom/x1e80100.c210
-rw-r--r--sound/soc/renesas/Kconfig (renamed from sound/soc/sh/Kconfig)12
-rw-r--r--sound/soc/renesas/Makefile (renamed from sound/soc/sh/Makefile)16
-rw-r--r--sound/soc/renesas/dma-sh7760.c (renamed from sound/soc/sh/dma-sh7760.c)34
-rw-r--r--sound/soc/renesas/fsi.c (renamed from sound/soc/sh/fsi.c)51
-rw-r--r--sound/soc/renesas/hac.c (renamed from sound/soc/sh/hac.c)2
-rw-r--r--sound/soc/renesas/migor.c (renamed from sound/soc/sh/migor.c)12
-rw-r--r--sound/soc/renesas/rcar/Makefile6
-rw-r--r--sound/soc/renesas/rcar/adg.c (renamed from sound/soc/sh/rcar/adg.c)139
-rw-r--r--sound/soc/renesas/rcar/cmd.c (renamed from sound/soc/sh/rcar/cmd.c)6
-rw-r--r--sound/soc/renesas/rcar/core.c (renamed from sound/soc/sh/rcar/core.c)278
-rw-r--r--sound/soc/renesas/rcar/ctu.c (renamed from sound/soc/sh/rcar/ctu.c)14
-rw-r--r--sound/soc/renesas/rcar/debugfs.c (renamed from sound/soc/sh/rcar/debugfs.c)0
-rw-r--r--sound/soc/renesas/rcar/dma.c (renamed from sound/soc/sh/rcar/dma.c)85
-rw-r--r--sound/soc/renesas/rcar/dvc.c (renamed from sound/soc/sh/rcar/dvc.c)14
-rw-r--r--sound/soc/renesas/rcar/gen.c495
-rw-r--r--sound/soc/renesas/rcar/mix.c (renamed from sound/soc/sh/rcar/mix.c)14
-rw-r--r--sound/soc/renesas/rcar/msiof.c629
-rw-r--r--sound/soc/renesas/rcar/rsnd.h (renamed from sound/soc/sh/rcar/rsnd.h)43
-rw-r--r--sound/soc/renesas/rcar/src.c (renamed from sound/soc/sh/rcar/src.c)158
-rw-r--r--sound/soc/renesas/rcar/ssi.c (renamed from sound/soc/sh/rcar/ssi.c)62
-rw-r--r--sound/soc/renesas/rcar/ssiu.c (renamed from sound/soc/sh/rcar/ssiu.c)12
-rw-r--r--sound/soc/renesas/rz-ssi.c (renamed from sound/soc/sh/rz-ssi.c)509
-rw-r--r--sound/soc/renesas/sh7760-ac97.c (renamed from sound/soc/sh/sh7760-ac97.c)0
-rw-r--r--sound/soc/renesas/siu.h (renamed from sound/soc/sh/siu.h)0
-rw-r--r--sound/soc/renesas/siu_dai.c (renamed from sound/soc/sh/siu_dai.c)2
-rw-r--r--sound/soc/renesas/siu_pcm.c (renamed from sound/soc/sh/siu_pcm.c)0
-rw-r--r--sound/soc/renesas/ssi.c (renamed from sound/soc/sh/ssi.c)0
-rw-r--r--sound/soc/rockchip/Kconfig31
-rw-r--r--sound/soc/rockchip/Makefile18
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c57
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c47
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c20
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.c473
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.h4
-rw-r--r--sound/soc/rockchip/rockchip_max98090.c22
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c21
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c36
-rw-r--r--sound/soc/rockchip/rockchip_sai.c1529
-rw-r--r--sound/soc/rockchip/rockchip_sai.h251
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c14
-rw-r--r--sound/soc/samsung/Kconfig8
-rw-r--r--sound/soc/samsung/Makefile38
-rw-r--r--sound/soc/samsung/aries_wm8994.c37
-rw-r--r--sound/soc/samsung/arndale.c18
-rw-r--r--sound/soc/samsung/bells.c45
-rw-r--r--sound/soc/samsung/i2s.c32
-rw-r--r--sound/soc/samsung/littlemill.c58
-rw-r--r--sound/soc/samsung/lowland.c22
-rw-r--r--sound/soc/samsung/midas_wm1811.c390
-rw-r--r--sound/soc/samsung/odroid.c58
-rw-r--r--sound/soc/samsung/pcm.c28
-rw-r--r--sound/soc/samsung/smdk_spdif.c4
-rw-r--r--sound/soc/samsung/smdk_wm8994.c66
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c8
-rw-r--r--sound/soc/samsung/snow.c9
-rw-r--r--sound/soc/samsung/spdif.c16
-rw-r--r--sound/soc/samsung/speyside.c91
-rw-r--r--sound/soc/samsung/tm2_wm5110.c48
-rw-r--r--sound/soc/samsung/tobermory.c19
-rw-r--r--sound/soc/sdca/Kconfig59
-rw-r--r--sound/soc/sdca/Makefile15
-rw-r--r--sound/soc/sdca/sdca_asoc.c1559
-rw-r--r--sound/soc/sdca/sdca_class.c304
-rw-r--r--sound/soc/sdca/sdca_class.h37
-rw-r--r--sound/soc/sdca/sdca_class_function.c460
-rw-r--r--sound/soc/sdca/sdca_device.c108
-rw-r--r--sound/soc/sdca/sdca_fdl.c504
-rw-r--r--sound/soc/sdca/sdca_function_device.c117
-rw-r--r--sound/soc/sdca/sdca_function_device.h15
-rw-r--r--sound/soc/sdca/sdca_functions.c2282
-rw-r--r--sound/soc/sdca/sdca_hid.c168
-rw-r--r--sound/soc/sdca/sdca_interrupts.c612
-rw-r--r--sound/soc/sdca/sdca_regmap.c373
-rw-r--r--sound/soc/sdca/sdca_ump.c262
-rw-r--r--sound/soc/sdw_utils/Kconfig6
-rw-r--r--sound/soc/sdw_utils/Makefile12
-rw-r--r--sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c156
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs42l42.c (renamed from sound/soc/intel/boards/sof_sdw_cs42l42.c)67
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs42l43.c174
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs42l45.c80
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs_amp.c125
-rw-r--r--sound/soc/sdw_utils/soc_sdw_dmic.c (renamed from sound/soc/intel/boards/sof_sdw_dmic.c)15
-rw-r--r--sound/soc/sdw_utils/soc_sdw_maxim.c139
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt5682.c (renamed from sound/soc/intel/boards/sof_sdw_rt5682.c)60
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt700.c (renamed from sound/soc/intel/boards/sof_sdw_rt700.c)62
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt711.c (renamed from sound/soc/intel/boards/sof_sdw_rt711.c)71
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_amp.c (renamed from sound/soc/intel/boards/sof_sdw_rt_amp.c)138
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h (renamed from sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h)6
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_dmic.c45
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c84
-rw-r--r--sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c (renamed from sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c)121
-rw-r--r--sound/soc/sdw_utils/soc_sdw_ti_amp.c93
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c1612
-rw-r--r--sound/soc/sh/rcar/Makefile3
-rw-r--r--sound/soc/sh/rcar/gen.c562
-rw-r--r--sound/soc/soc-ac97.c17
-rw-r--r--sound/soc/soc-acpi.c75
-rw-r--r--sound/soc/soc-card-test.c129
-rw-r--r--sound/soc/soc-card.c29
-rw-r--r--sound/soc/soc-component.c124
-rw-r--r--sound/soc/soc-compress.c73
-rw-r--r--sound/soc/soc-core.c942
-rw-r--r--sound/soc/soc-dai.c230
-rw-r--r--sound/soc/soc-dapm.c1504
-rw-r--r--sound/soc/soc-devres.c44
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c44
-rw-r--r--sound/soc/soc-jack.c27
-rw-r--r--sound/soc/soc-link.c42
-rw-r--r--sound/soc/soc-ops-test.c548
-rw-r--r--sound/soc/soc-ops.c801
-rw-r--r--sound/soc/soc-pcm.c979
-rw-r--r--sound/soc/soc-topology-test.c147
-rw-r--r--sound/soc/soc-topology.c967
-rw-r--r--sound/soc/soc-usb.c322
-rw-r--r--sound/soc/soc-utils.c104
-rw-r--r--sound/soc/sof/Kconfig15
-rw-r--r--sound/soc/sof/Makefile39
-rw-r--r--sound/soc/sof/amd/Kconfig64
-rw-r--r--sound/soc/sof/amd/Makefile19
-rw-r--r--sound/soc/sof/amd/acp-common.c82
-rw-r--r--sound/soc/sof/amd/acp-dsp-offset.h55
-rw-r--r--sound/soc/sof/amd/acp-ipc.c73
-rw-r--r--sound/soc/sof/amd/acp-loader.c161
-rw-r--r--sound/soc/sof/amd/acp-pcm.c10
-rw-r--r--sound/soc/sof/amd/acp-probes.c147
-rw-r--r--sound/soc/sof/amd/acp-stream.c6
-rw-r--r--sound/soc/sof/amd/acp-trace.c4
-rw-r--r--sound/soc/sof/amd/acp.c608
-rw-r--r--sound/soc/sof/amd/acp.h123
-rw-r--r--sound/soc/sof/amd/acp63.c142
-rw-r--r--sound/soc/sof/amd/acp70.c142
-rw-r--r--sound/soc/sof/amd/pci-acp63.c115
-rw-r--r--sound/soc/sof/amd/pci-acp70.c121
-rw-r--r--sound/soc/sof/amd/pci-rmb.c22
-rw-r--r--sound/soc/sof/amd/pci-rn.c23
-rw-r--r--sound/soc/sof/amd/pci-vangogh.c101
-rw-r--r--sound/soc/sof/amd/rembrandt.c6
-rw-r--r--sound/soc/sof/amd/renoir.c6
-rw-r--r--sound/soc/sof/amd/vangogh.c177
-rw-r--r--sound/soc/sof/compress.c2
-rw-r--r--sound/soc/sof/control.c3
-rw-r--r--sound/soc/sof/core.c421
-rw-r--r--sound/soc/sof/debug.c69
-rw-r--r--sound/soc/sof/fw-file-profile.c345
-rw-r--r--sound/soc/sof/imx/Kconfig18
-rw-r--r--sound/soc/sof/imx/Makefile10
-rw-r--r--sound/soc/sof/imx/imx-common.c409
-rw-r--r--sound/soc/sof/imx/imx-common.h158
-rw-r--r--sound/soc/sof/imx/imx8.c788
-rw-r--r--sound/soc/sof/imx/imx8m.c508
-rw-r--r--sound/soc/sof/imx/imx8ulp.c515
-rw-r--r--sound/soc/sof/imx/imx9.c117
-rw-r--r--sound/soc/sof/intel/Kconfig95
-rw-r--r--sound/soc/sof/intel/Makefile42
-rw-r--r--sound/soc/sof/intel/apl.c12
-rw-r--r--sound/soc/sof/intel/atom.c41
-rw-r--r--sound/soc/sof/intel/atom.h2
-rw-r--r--sound/soc/sof/intel/bdw.c41
-rw-r--r--sound/soc/sof/intel/byt.c53
-rw-r--r--sound/soc/sof/intel/cnl.c29
-rw-r--r--sound/soc/sof/intel/ext_manifest.h2
-rw-r--r--sound/soc/sof/intel/hda-bus.c9
-rw-r--r--sound/soc/sof/intel/hda-codec.c73
-rw-r--r--sound/soc/sof/intel/hda-common-ops.c11
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c30
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c225
-rw-r--r--sound/soc/sof/intel/hda-dai.c430
-rw-r--r--sound/soc/sof/intel/hda-dsp.c539
-rw-r--r--sound/soc/sof/intel/hda-ipc.c119
-rw-r--r--sound/soc/sof/intel/hda-ipc.h2
-rw-r--r--sound/soc/sof/intel/hda-loader-skl.c2
-rw-r--r--sound/soc/sof/intel/hda-loader.c244
-rw-r--r--sound/soc/sof/intel/hda-mlink.c257
-rw-r--r--sound/soc/sof/intel/hda-pcm.c75
-rw-r--r--sound/soc/sof/intel/hda-probes.c8
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c445
-rw-r--r--sound/soc/sof/intel/hda-stream.c253
-rw-r--r--sound/soc/sof/intel/hda-trace.c5
-rw-r--r--sound/soc/sof/intel/hda.c1448
-rw-r--r--sound/soc/sof/intel/hda.h111
-rw-r--r--sound/soc/sof/intel/icl.c14
-rw-r--r--sound/soc/sof/intel/lnl.c190
-rw-r--r--sound/soc/sof/intel/lnl.h21
-rw-r--r--sound/soc/sof/intel/mtl.c230
-rw-r--r--sound/soc/sof/intel/mtl.h67
-rw-r--r--sound/soc/sof/intel/nvl.c55
-rw-r--r--sound/soc/sof/intel/nvl.h14
-rw-r--r--sound/soc/sof/intel/pci-apl.c54
-rw-r--r--sound/soc/sof/intel/pci-cnl.c79
-rw-r--r--sound/soc/sof/intel/pci-icl.c59
-rw-r--r--sound/soc/sof/intel/pci-lnl.c84
-rw-r--r--sound/soc/sof/intel/pci-mtl.c95
-rw-r--r--sound/soc/sof/intel/pci-nvl.c82
-rw-r--r--sound/soc/sof/intel/pci-ptl.c113
-rw-r--r--sound/soc/sof/intel/pci-skl.c36
-rw-r--r--sound/soc/sof/intel/pci-tgl.c202
-rw-r--r--sound/soc/sof/intel/pci-tng.c27
-rw-r--r--sound/soc/sof/intel/ptl.c158
-rw-r--r--sound/soc/sof/intel/ptl.h19
-rw-r--r--sound/soc/sof/intel/shim.h12
-rw-r--r--sound/soc/sof/intel/skl.c11
-rw-r--r--sound/soc/sof/intel/telemetry.c96
-rw-r--r--sound/soc/sof/intel/telemetry.h35
-rw-r--r--sound/soc/sof/intel/tgl.c44
-rw-r--r--sound/soc/sof/intel/tracepoints.c5
-rw-r--r--sound/soc/sof/iomem-utils.c4
-rw-r--r--sound/soc/sof/ipc.c8
-rw-r--r--sound/soc/sof/ipc3-control.c2
-rw-r--r--sound/soc/sof/ipc3-dtrace.c20
-rw-r--r--sound/soc/sof/ipc3-loader.c7
-rw-r--r--sound/soc/sof/ipc3-pcm.c75
-rw-r--r--sound/soc/sof/ipc3-priv.h8
-rw-r--r--sound/soc/sof/ipc3-topology.c223
-rw-r--r--sound/soc/sof/ipc3.c64
-rw-r--r--sound/soc/sof/ipc4-control.c387
-rw-r--r--sound/soc/sof/ipc4-fw-reg.h2
-rw-r--r--sound/soc/sof/ipc4-loader.c207
-rw-r--r--sound/soc/sof/ipc4-mtrace.c47
-rw-r--r--sound/soc/sof/ipc4-pcm.c733
-rw-r--r--sound/soc/sof/ipc4-priv.h41
-rw-r--r--sound/soc/sof/ipc4-telemetry.c95
-rw-r--r--sound/soc/sof/ipc4-telemetry.h73
-rw-r--r--sound/soc/sof/ipc4-topology.c1568
-rw-r--r--sound/soc/sof/ipc4-topology.h113
-rw-r--r--sound/soc/sof/ipc4.c264
-rw-r--r--sound/soc/sof/loader.c2
-rw-r--r--sound/soc/sof/mediatek/adsp_helper.h4
-rw-r--r--sound/soc/sof/mediatek/mt8186/Makefile2
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c208
-rw-r--r--sound/soc/sof/mediatek/mt8195/Makefile2
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195-clk.c3
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.c201
-rw-r--r--sound/soc/sof/mediatek/mtk-adsp-common.c131
-rw-r--r--sound/soc/sof/mediatek/mtk-adsp-common.h10
-rw-r--r--sound/soc/sof/nocodec.c13
-rw-r--r--sound/soc/sof/ops.c2
-rw-r--r--sound/soc/sof/ops.h65
-rw-r--r--sound/soc/sof/pcm.c305
-rw-r--r--sound/soc/sof/pm.c14
-rw-r--r--sound/soc/sof/sof-acpi-dev.c40
-rw-r--r--sound/soc/sof/sof-acpi-dev.h4
-rw-r--r--sound/soc/sof/sof-audio.c282
-rw-r--r--sound/soc/sof/sof-audio.h63
-rw-r--r--sound/soc/sof/sof-client-ipc-flood-test.c63
-rw-r--r--sound/soc/sof/sof-client-ipc-kernel-injector.c7
-rw-r--r--sound/soc/sof/sof-client-ipc-msg-injector.c11
-rw-r--r--sound/soc/sof/sof-client-probes-ipc3.c27
-rw-r--r--sound/soc/sof/sof-client-probes-ipc4.c144
-rw-r--r--sound/soc/sof/sof-client-probes.c97
-rw-r--r--sound/soc/sof/sof-client-probes.h13
-rw-r--r--sound/soc/sof/sof-client.c179
-rw-r--r--sound/soc/sof/sof-client.h8
-rw-r--r--sound/soc/sof/sof-of-dev.c40
-rw-r--r--sound/soc/sof/sof-of-dev.h2
-rw-r--r--sound/soc/sof/sof-pci-dev.c159
-rw-r--r--sound/soc/sof/sof-pci-dev.h2
-rw-r--r--sound/soc/sof/sof-priv.h85
-rw-r--r--sound/soc/sof/sof-utils.c5
-rw-r--r--sound/soc/sof/sof-utils.h2
-rw-r--r--sound/soc/sof/stream-ipc.c10
-rw-r--r--sound/soc/sof/topology.c235
-rw-r--r--sound/soc/sof/trace.c2
-rw-r--r--sound/soc/sof/xtensa/Makefile2
-rw-r--r--sound/soc/sof/xtensa/core.c17
-rw-r--r--sound/soc/spacemit/Kconfig15
-rw-r--r--sound/soc/spacemit/Makefile5
-rw-r--r--sound/soc/spacemit/k1_i2s.c461
-rw-r--r--sound/soc/spear/Kconfig4
-rw-r--r--sound/soc/spear/Makefile6
-rw-r--r--sound/soc/sprd/Kconfig4
-rw-r--r--sound/soc/sprd/Makefile2
-rw-r--r--sound/soc/sprd/sprd-mcdt.c2
-rw-r--r--sound/soc/sprd/sprd-pcm-compress.c16
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c4
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.h4
-rw-r--r--sound/soc/starfive/Kconfig17
-rw-r--r--sound/soc/starfive/Makefile1
-rw-r--r--sound/soc/starfive/jh7110_pwmdac.c528
-rw-r--r--sound/soc/starfive/jh7110_tdm.c34
-rw-r--r--sound/soc/sti/Kconfig2
-rw-r--r--sound/soc/sti/Makefile2
-rw-r--r--sound/soc/sti/sti_uniperif.c15
-rw-r--r--sound/soc/sti/uniperif.h1
-rw-r--r--sound/soc/sti/uniperif_player.c1
-rw-r--r--sound/soc/sti/uniperif_reader.c1
-rw-r--r--sound/soc/stm/Kconfig2
-rw-r--r--sound/soc/stm/Makefile8
-rw-r--r--sound/soc/stm/stm32_adfsdm.c32
-rw-r--r--sound/soc/stm/stm32_i2s.c242
-rw-r--r--sound/soc/stm/stm32_sai.c78
-rw-r--r--sound/soc/stm/stm32_sai.h6
-rw-r--r--sound/soc/stm/stm32_sai_sub.c275
-rw-r--r--sound/soc/stm/stm32_spdifrx.c20
-rw-r--r--sound/soc/sunxi/Kconfig2
-rw-r--r--sound/soc/sunxi/sun4i-codec.c811
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c198
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c74
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c76
-rw-r--r--sound/soc/sunxi/sun50i-dmic.c50
-rw-r--r--sound/soc/sunxi/sun8i-codec-analog.c15
-rw-r--r--sound/soc/sunxi/sun8i-codec.c355
-rw-r--r--sound/soc/tegra/Kconfig7
-rw-r--r--sound/soc/tegra/Makefile46
-rw-r--r--sound/soc/tegra/tegra186_asrc.c60
-rw-r--r--sound/soc/tegra/tegra186_asrc.h12
-rw-r--r--sound/soc/tegra/tegra186_dspk.c51
-rw-r--r--sound/soc/tegra/tegra20_ac97.c70
-rw-r--r--sound/soc/tegra/tegra20_ac97.h4
-rw-r--r--sound/soc/tegra/tegra20_i2s.c17
-rw-r--r--sound/soc/tegra/tegra20_spdif.c17
-rw-r--r--sound/soc/tegra/tegra210_admaif.c299
-rw-r--r--sound/soc/tegra/tegra210_admaif.h87
-rw-r--r--sound/soc/tegra/tegra210_adx.c294
-rw-r--r--sound/soc/tegra/tegra210_adx.h36
-rw-r--r--sound/soc/tegra/tegra210_ahub.c889
-rw-r--r--sound/soc/tegra/tegra210_ahub.h52
-rw-r--r--sound/soc/tegra/tegra210_amx.c306
-rw-r--r--sound/soc/tegra/tegra210_amx.h34
-rw-r--r--sound/soc/tegra/tegra210_dmic.c48
-rw-r--r--sound/soc/tegra/tegra210_i2s.c379
-rw-r--r--sound/soc/tegra/tegra210_i2s.h60
-rw-r--r--sound/soc/tegra/tegra210_mbdrc.c24
-rw-r--r--sound/soc/tegra/tegra210_mixer.c31
-rw-r--r--sound/soc/tegra/tegra210_mvc.c39
-rw-r--r--sound/soc/tegra/tegra210_ope.c31
-rw-r--r--sound/soc/tegra/tegra210_peq.c9
-rw-r--r--sound/soc/tegra/tegra210_sfc.c70
-rw-r--r--sound/soc/tegra/tegra210_sfc.h4
-rw-r--r--sound/soc/tegra/tegra30_ahub.c15
-rw-r--r--sound/soc/tegra/tegra30_i2s.c18
-rw-r--r--sound/soc/tegra/tegra_asoc_machine.c46
-rw-r--r--sound/soc/tegra/tegra_audio_graph_card.c68
-rw-r--r--sound/soc/tegra/tegra_cif.h30
-rw-r--r--sound/soc/tegra/tegra_isomgr_bw.c130
-rw-r--r--sound/soc/tegra/tegra_isomgr_bw.h31
-rw-r--r--sound/soc/tegra/tegra_pcm.c19
-rw-r--r--sound/soc/tegra/tegra_wm8903.c9
-rw-r--r--sound/soc/ti/Kconfig7
-rw-r--r--sound/soc/ti/Makefile36
-rw-r--r--sound/soc/ti/ams-delta.c26
-rw-r--r--sound/soc/ti/davinci-evm.c43
-rw-r--r--sound/soc/ti/davinci-i2s.c300
-rw-r--r--sound/soc/ti/davinci-mcasp.c65
-rw-r--r--sound/soc/ti/j721e-evm.c27
-rw-r--r--sound/soc/ti/n810.c51
-rw-r--r--sound/soc/ti/omap-abe-twl6040.c12
-rw-r--r--sound/soc/ti/omap-dmic.c28
-rw-r--r--sound/soc/ti/omap-hdmi.c27
-rw-r--r--sound/soc/ti/omap-mcbsp-st.c2
-rw-r--r--sound/soc/ti/omap-mcbsp.c58
-rw-r--r--sound/soc/ti/omap-mcpdm.c29
-rw-r--r--sound/soc/ti/omap-twl4030.c30
-rw-r--r--sound/soc/ti/omap3pandora.c109
-rw-r--r--sound/soc/ti/osk5912.c7
-rw-r--r--sound/soc/ti/rx51.c56
-rw-r--r--sound/soc/uniphier/Kconfig14
-rw-r--r--sound/soc/uniphier/Makefile8
-rw-r--r--sound/soc/uniphier/aio-compress.c24
-rw-r--r--sound/soc/uniphier/aio-core.c25
-rw-r--r--sound/soc/uniphier/aio-cpu.c177
-rw-r--r--sound/soc/uniphier/aio-dma.c14
-rw-r--r--sound/soc/uniphier/aio-ld11.c64
-rw-r--r--sound/soc/uniphier/aio-pxs2.c57
-rw-r--r--sound/soc/uniphier/aio.h12
-rw-r--r--sound/soc/uniphier/evea.c16
-rw-r--r--sound/soc/ux500/Kconfig2
-rw-r--r--sound/soc/ux500/Makefile6
-rw-r--r--sound/soc/ux500/mop500.c2
-rw-r--r--sound/soc/ux500/mop500_ab8500.c20
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c11
-rw-r--r--sound/soc/ux500/ux500_pcm.c4
-rw-r--r--sound/soc/xilinx/Kconfig4
-rw-r--r--sound/soc/xilinx/Makefile6
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c4
-rw-r--r--sound/soc/xilinx/xlnx_i2s.c1
-rw-r--r--sound/soc/xilinx/xlnx_spdif.c38
-rw-r--r--sound/soc/xtensa/Kconfig4
-rw-r--r--sound/soc/xtensa/Makefile2
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c12
-rw-r--r--sound/sound_core.c23
-rw-r--r--sound/sparc/Makefile6
-rw-r--r--sound/sparc/amd7930.c134
-rw-r--r--sound/sparc/cs4231.c321
-rw-r--r--sound/sparc/dbri.c247
-rw-r--r--sound/spi/Makefile2
-rw-r--r--sound/spi/at73c213.c118
-rw-r--r--sound/synth/Makefile2
-rw-r--r--sound/synth/emux/Makefile2
-rw-r--r--sound/synth/emux/emux.c10
-rw-r--r--sound/synth/emux/emux_effect.c29
-rw-r--r--sound/synth/emux/emux_hwdep.c11
-rw-r--r--sound/synth/emux/emux_oss.c14
-rw-r--r--sound/synth/emux/emux_proc.c7
-rw-r--r--sound/synth/emux/emux_seq.c34
-rw-r--r--sound/synth/emux/emux_synth.c71
-rw-r--r--sound/synth/emux/soundfont.c249
-rw-r--r--sound/synth/util_mem.c17
-rw-r--r--sound/usb/6fire/Makefile2
-rw-r--r--sound/usb/6fire/chip.c54
-rw-r--r--sound/usb/6fire/midi.c23
-rw-r--r--sound/usb/6fire/pcm.c85
-rw-r--r--sound/usb/Kconfig38
-rw-r--r--sound/usb/Makefile10
-rw-r--r--sound/usb/bcd2000/bcd2000.c20
-rw-r--r--sound/usb/caiaq/audio.c64
-rw-r--r--sound/usb/caiaq/audio.h1
-rw-r--r--sound/usb/caiaq/device.c21
-rw-r--r--sound/usb/caiaq/device.h2
-rw-r--r--sound/usb/caiaq/input.c12
-rw-r--r--sound/usb/caiaq/input.h1
-rw-r--r--sound/usb/card.c245
-rw-r--r--sound/usb/card.h17
-rw-r--r--sound/usb/clock.c120
-rw-r--r--sound/usb/endpoint.c194
-rw-r--r--sound/usb/endpoint.h1
-rw-r--r--sound/usb/fcp.c1127
-rw-r--r--sound/usb/fcp.h7
-rw-r--r--sound/usb/format.c84
-rw-r--r--sound/usb/helper.c35
-rw-r--r--sound/usb/helper.h10
-rw-r--r--sound/usb/hiface/Makefile2
-rw-r--r--sound/usb/hiface/chip.c11
-rw-r--r--sound/usb/hiface/pcm.c60
-rw-r--r--sound/usb/implicit.c1
-rw-r--r--sound/usb/line6/capture.c8
-rw-r--r--sound/usb/line6/capture.h2
-rw-r--r--sound/usb/line6/driver.c50
-rw-r--r--sound/usb/line6/driver.h2
-rw-r--r--sound/usb/line6/midi.c16
-rw-r--r--sound/usb/line6/midi.h2
-rw-r--r--sound/usb/line6/midibuf.c2
-rw-r--r--sound/usb/line6/midibuf.h2
-rw-r--r--sound/usb/line6/pcm.c89
-rw-r--r--sound/usb/line6/pcm.h2
-rw-r--r--sound/usb/line6/playback.c2
-rw-r--r--sound/usb/line6/playback.h2
-rw-r--r--sound/usb/line6/pod.c2
-rw-r--r--sound/usb/line6/podhd.c18
-rw-r--r--sound/usb/line6/toneport.c6
-rw-r--r--sound/usb/line6/variax.c2
-rw-r--r--sound/usb/media.c10
-rw-r--r--sound/usb/midi.c268
-rw-r--r--sound/usb/midi.h5
-rw-r--r--sound/usb/midi2.c1233
-rw-r--r--sound/usb/midi2.h33
-rw-r--r--sound/usb/misc/Makefile2
-rw-r--r--sound/usb/misc/ua101.c262
-rw-r--r--sound/usb/mixer.c259
-rw-r--r--sound/usb/mixer.h1
-rw-r--r--sound/usb/mixer_maps.c36
-rw-r--r--sound/usb/mixer_quirks.c1890
-rw-r--r--sound/usb/mixer_s1810c.c318
-rw-r--r--sound/usb/mixer_scarlett.c35
-rw-r--r--sound/usb/mixer_scarlett2.c9434
-rw-r--r--sound/usb/mixer_scarlett2.h7
-rw-r--r--sound/usb/mixer_scarlett_gen2.c4197
-rw-r--r--sound/usb/mixer_scarlett_gen2.h7
-rw-r--r--sound/usb/mixer_us16x08.c37
-rw-r--r--sound/usb/pcm.c388
-rw-r--r--sound/usb/pcm.h11
-rw-r--r--sound/usb/power.c3
-rw-r--r--sound/usb/power.h1
-rw-r--r--sound/usb/proc.c5
-rw-r--r--sound/usb/qcom/Makefile4
-rw-r--r--sound/usb/qcom/mixer_usb_offload.c155
-rw-r--r--sound/usb/qcom/mixer_usb_offload.h11
-rw-r--r--sound/usb/qcom/qc_audio_offload.c1993
-rw-r--r--sound/usb/qcom/usb_audio_qmi_v01.c863
-rw-r--r--sound/usb/qcom/usb_audio_qmi_v01.h164
-rw-r--r--sound/usb/quirks-table.h2614
-rw-r--r--sound/usb/quirks.c537
-rw-r--r--sound/usb/quirks.h11
-rw-r--r--sound/usb/stream.c80
-rw-r--r--sound/usb/usbaudio.h124
-rw-r--r--sound/usb/usx2y/Makefile6
-rw-r--r--sound/usb/usx2y/us122l.c118
-rw-r--r--sound/usb/usx2y/us122l.h2
-rw-r--r--sound/usb/usx2y/us144mkii.c620
-rw-r--r--sound/usb/usx2y/us144mkii.h367
-rw-r--r--sound/usb/usx2y/us144mkii_capture.c319
-rw-r--r--sound/usb/usx2y/us144mkii_controls.c444
-rw-r--r--sound/usb/usx2y/us144mkii_midi.c403
-rw-r--r--sound/usb/usx2y/us144mkii_pcm.c370
-rw-r--r--sound/usb/usx2y/us144mkii_pcm.h165
-rw-r--r--sound/usb/usx2y/us144mkii_playback.c456
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c27
-rw-r--r--sound/usb/usx2y/usb_stream.c95
-rw-r--r--sound/usb/usx2y/usb_stream.h1
-rw-r--r--sound/usb/usx2y/usbusx2y.c22
-rw-r--r--sound/usb/usx2y/usbusx2y.h28
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c119
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c87
-rw-r--r--sound/usb/validate.c23
-rw-r--r--sound/virtio/Makefile3
-rw-r--r--sound/virtio/virtio_card.c55
-rw-r--r--sound/virtio/virtio_card.h22
-rw-r--r--sound/virtio/virtio_ctl_msg.c25
-rw-r--r--sound/virtio/virtio_kctl.c477
-rw-r--r--sound/virtio/virtio_pcm.c35
-rw-r--r--sound/virtio/virtio_pcm.h9
-rw-r--r--sound/virtio/virtio_pcm_msg.c98
-rw-r--r--sound/virtio/virtio_pcm_ops.c135
-rw-r--r--sound/x86/Makefile2
-rw-r--r--sound/x86/intel_hdmi_audio.c132
-rw-r--r--sound/xen/Makefile2
-rw-r--r--sound/xen/xen_snd_front.c82
-rw-r--r--sound/xen/xen_snd_front_alsa.c69
-rw-r--r--sound/xen/xen_snd_front_cfg.c2
-rw-r--r--sound/xen/xen_snd_front_evtchnl.c33
2263 files changed, 272239 insertions, 113628 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index 0ddfb717b81d..8b40205394fe 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SOUND
tristate "Sound card support"
- depends on HAS_IOMEM
+ depends on HAS_IOMEM || INDIRECT_IOMEM
help
If you have a sound card in your computer, i.e. if it can say more
than an occasional beep, say Y.
@@ -39,8 +39,6 @@ config SOUND_OSS_CORE_PRECLAIM
source "sound/oss/dmasound/Kconfig"
-if !UML
-
menuconfig SND
tristate "Advanced Linux Sound Architecture"
help
@@ -103,8 +101,6 @@ source "sound/virtio/Kconfig"
endif # SND
-endif # !UML
-
endif # SOUND
config AC97_BUS
diff --git a/sound/Makefile b/sound/Makefile
index 04ef04b1168f..5942311a4232 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -17,4 +17,4 @@ ifeq ($(CONFIG_SND),y)
obj-y += last.o
endif
-soundcore-objs := sound_core.o
+soundcore-y := sound_core.o
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
index 6067c04ce4c0..f4254703d29f 100644
--- a/sound/ac97/bus.c
+++ b/sound/ac97/bus.c
@@ -15,6 +15,7 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <sound/ac97_codec.h>
#include <sound/ac97/codec.h>
#include <sound/ac97/controller.h>
#include <sound/ac97/regs.h>
@@ -28,8 +29,6 @@ static DEFINE_MUTEX(ac97_controllers_mutex);
static DEFINE_IDR(ac97_adapter_idr);
static LIST_HEAD(ac97_controllers);
-static struct bus_type ac97_bus_type;
-
static inline struct ac97_controller*
to_ac97_controller(struct device *ac97_adapter)
{
@@ -181,7 +180,7 @@ static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)
/**
* snd_ac97_codec_driver_register - register an AC97 codec driver
- * @dev: AC97 driver codec to register
+ * @drv: AC97 driver codec to register
*
* Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital
* controller.
@@ -197,7 +196,7 @@ EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_register);
/**
* snd_ac97_codec_driver_unregister - unregister an AC97 codec driver
- * @dev: AC97 codec driver to unregister
+ * @drv: AC97 codec driver to unregister
*
* Unregister a previously registered ac97 codec driver.
*/
@@ -242,10 +241,9 @@ static ssize_t cold_reset_store(struct device *dev,
{
struct ac97_controller *ac97_ctrl;
- mutex_lock(&ac97_controllers_mutex);
+ guard(mutex)(&ac97_controllers_mutex);
ac97_ctrl = to_ac97_controller(dev);
ac97_ctrl->ops->reset(ac97_ctrl);
- mutex_unlock(&ac97_controllers_mutex);
return len;
}
static DEVICE_ATTR_WO(cold_reset);
@@ -259,10 +257,9 @@ static ssize_t warm_reset_store(struct device *dev,
if (!dev)
return -ENODEV;
- mutex_lock(&ac97_controllers_mutex);
+ guard(mutex)(&ac97_controllers_mutex);
ac97_ctrl = to_ac97_controller(dev);
ac97_ctrl->ops->warm_reset(ac97_ctrl);
- mutex_unlock(&ac97_controllers_mutex);
return len;
}
static DEVICE_ATTR_WO(warm_reset);
@@ -285,10 +282,10 @@ static const struct attribute_group *ac97_adapter_groups[] = {
static void ac97_del_adapter(struct ac97_controller *ac97_ctrl)
{
- mutex_lock(&ac97_controllers_mutex);
- ac97_ctrl_codecs_unregister(ac97_ctrl);
- list_del(&ac97_ctrl->controllers);
- mutex_unlock(&ac97_controllers_mutex);
+ scoped_guard(mutex, &ac97_controllers_mutex) {
+ ac97_ctrl_codecs_unregister(ac97_ctrl);
+ list_del(&ac97_ctrl->controllers);
+ }
device_unregister(&ac97_ctrl->adap);
}
@@ -312,7 +309,7 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
{
int ret;
- mutex_lock(&ac97_controllers_mutex);
+ guard(mutex)(&ac97_controllers_mutex);
ret = idr_alloc(&ac97_adapter_idr, ac97_ctrl, 0, 0, GFP_KERNEL);
ac97_ctrl->nr = ret;
if (ret >= 0) {
@@ -323,13 +320,11 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
if (ret)
put_device(&ac97_ctrl->adap);
}
- if (!ret)
+ if (!ret) {
list_add(&ac97_ctrl->controllers, &ac97_controllers);
- mutex_unlock(&ac97_controllers_mutex);
-
- if (!ret)
dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",
dev_name(ac97_ctrl->parent));
+ }
return ret;
}
@@ -339,6 +334,7 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
* @dev: the device providing the ac97 DC function
* @slots_available: mask of the ac97 codecs that can be scanned and probed
* bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3
+ * @codecs_pdata: codec platform data
*
* Register a digital controller which can control up to 4 ac97 codecs. This is
* the controller side of the AC97 AC-link, while the slave side are the codecs.
@@ -387,7 +383,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 +414,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 +422,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)
@@ -462,7 +453,7 @@ static ssize_t vendor_id_show(struct device *dev,
return sysfs_emit(buf, "%08x", codec->vendor_id);
}
-DEVICE_ATTR_RO(vendor_id);
+static DEVICE_ATTR_RO(vendor_id);
static struct attribute *ac97_dev_attrs[] = {
&dev_attr_vendor_id.attr,
@@ -470,10 +461,10 @@ static struct attribute *ac97_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(ac97_dev);
-static int ac97_bus_match(struct device *dev, struct device_driver *drv)
+static int ac97_bus_match(struct device *dev, const struct device_driver *drv)
{
struct ac97_codec_device *adev = to_ac97_device(dev);
- struct ac97_codec_driver *adrv = to_ac97_driver(drv);
+ const struct ac97_codec_driver *adrv = to_ac97_driver(drv);
const struct ac97_id *id = adrv->id_table;
int i = 0;
@@ -531,11 +522,11 @@ static void ac97_bus_remove(struct device *dev)
pm_runtime_disable(dev);
}
-static struct bus_type ac97_bus_type = {
+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,
};
@@ -552,5 +543,6 @@ static void __exit ac97_bus_exit(void)
}
module_exit(ac97_bus_exit);
+MODULE_DESCRIPTION("AC97 bus interface");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c
index c7aee8c42c55..8a44297964f5 100644
--- a/sound/ac97_bus.c
+++ b/sound/ac97_bus.c
@@ -46,11 +46,14 @@ static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,
* @id_mask: Mask that is applied to the device ID before comparing to @id
*
* This function resets the AC'97 device. If @try_warm is true the function
- * first performs a warm reset. If the warm reset is successful the function
- * returns 1. Otherwise or if @try_warm is false the function issues cold reset
- * followed by a warm reset. If this is successful the function returns 0,
- * otherwise a negative error code. If @id is 0 any valid device ID will be
- * accepted, otherwise only the ID that matches @id and @id_mask is accepted.
+ * first performs a warm reset. If @try_warm is false the function issues
+ * cold reset followed by a warm reset. If @id is 0 any valid device ID
+ * will be accepted, otherwise only the ID that matches @id and @id_mask
+ * is accepted.
+ * Returns:
+ * * %1 - if warm reset is successful
+ * * %0 - if cold reset and warm reset is successful
+ * * %-ENODEV - if @id and @id_mask not matching
*/
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
unsigned int id_mask)
@@ -75,7 +78,7 @@ int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
}
EXPORT_SYMBOL_GPL(snd_ac97_reset);
-struct bus_type ac97_bus_type = {
+const struct bus_type ac97_bus_type = {
.name = "ac97",
};
@@ -95,4 +98,5 @@ module_exit(ac97_bus_exit);
EXPORT_SYMBOL(ac97_bus_type);
+MODULE_DESCRIPTION("Legacy AC97 bus interface");
MODULE_LICENSE("GPL");
diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h
index 54f9a78fa08e..77ae75d7594c 100644
--- a/sound/aoa/aoa-gpio.h
+++ b/sound/aoa/aoa-gpio.h
@@ -9,7 +9,6 @@
#define __AOA_GPIO_H
#include <linux/workqueue.h>
#include <linux/mutex.h>
-#include <asm/prom.h>
typedef void (*notify_func_t)(void *data);
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h
index 3d2d03ff6337..badff9f7cd54 100644
--- a/sound/aoa/aoa.h
+++ b/sound/aoa/aoa.h
@@ -7,7 +7,6 @@
#ifndef __AOA_H
#define __AOA_H
-#include <asm/prom.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/asound.h>
diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile
index 95f4c3849d55..8feedc771bd9 100644
--- a/sound/aoa/codecs/Makefile
+++ b/sound/aoa/codecs/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
-snd-aoa-codec-onyx-objs := onyx.o
-snd-aoa-codec-tas-objs := tas.o
-snd-aoa-codec-toonie-objs := toonie.o
+snd-aoa-codec-onyx-y := onyx.o
+snd-aoa-codec-tas-y := tas.o
+snd-aoa-codec-toonie-y := toonie.o
obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o
obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 4c75381f5ab8..4cf959017c9d 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -30,6 +30,7 @@
*/
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
MODULE_LICENSE("GPL");
@@ -121,10 +122,9 @@ static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
s8 l, r;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
@@ -145,15 +145,13 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)
return -EINVAL;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
- r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
- mutex_unlock(&onyx->mutex);
+ r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1])
return 0;
- }
onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
ucontrol->value.integer.value[0]
@@ -161,7 +159,6 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
ucontrol->value.integer.value[1]
- VOLUME_RANGE_SHIFT);
- mutex_unlock(&onyx->mutex);
return 1;
}
@@ -197,9 +194,8 @@ static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 ig;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] =
(ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
@@ -216,14 +212,13 @@ static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||
ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)
return -EINVAL;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
n = v;
n &= ~ONYX_ADC_PGA_GAIN_MASK;
n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
& ONYX_ADC_PGA_GAIN_MASK;
onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
- mutex_unlock(&onyx->mutex);
return n != v;
}
@@ -251,9 +246,8 @@ static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
s8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
- mutex_unlock(&onyx->mutex);
ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
@@ -264,13 +258,12 @@ static void onyx_set_capture_source(struct onyx *onyx, int mic)
{
s8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
v &= ~ONYX_ADC_INPUT_MIC;
if (mic)
v |= ONYX_ADC_INPUT_MIC;
onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
- mutex_unlock(&onyx->mutex);
}
static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
@@ -311,9 +304,8 @@ static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 c;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
@@ -328,9 +320,9 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
u8 v = 0, c = 0;
int err = -EBUSY;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (onyx->analog_locked)
- goto out_unlock;
+ return -EBUSY;
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
c = v;
@@ -341,9 +333,6 @@ static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
c |= ONYX_MUTE_RIGHT;
err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
return !err ? (v != c) : err;
}
@@ -372,9 +361,8 @@ static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,
u8 address = (pv >> 8) & 0xff;
u8 mask = pv & 0xff;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, address, &c);
- mutex_unlock(&onyx->mutex);
ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
@@ -393,11 +381,10 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
u8 address = (pv >> 8) & 0xff;
u8 mask = pv & 0xff;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (spdiflock && onyx->spdif_locked) {
/* even if alsamixer doesn't care.. */
- err = -EBUSY;
- goto out_unlock;
+ return -EBUSY;
}
onyx_read_register(onyx, address, &v);
c = v;
@@ -406,9 +393,6 @@ static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
c |= mask;
err = onyx_write_register(onyx, address, c);
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
return !err ? (v != c) : err;
}
@@ -489,7 +473,7 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
ucontrol->value.iec958.status[0] = v & 0x3e;
@@ -501,7 +485,6 @@ static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
ucontrol->value.iec958.status[4] = v & 0x0f;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -512,7 +495,7 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
struct onyx *onyx = snd_kcontrol_chip(kcontrol);
u8 v;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
@@ -527,7 +510,6 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
- mutex_unlock(&onyx->mutex);
return 1;
}
@@ -672,14 +654,13 @@ static int onyx_usable(struct codec_info_item *cii,
struct onyx *onyx = cii->codec_data;
int spdif_enabled, analog_enabled;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
analog_enabled =
(v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
!= (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
- mutex_unlock(&onyx->mutex);
switch (ti->tag) {
case 0: return 1;
@@ -695,9 +676,8 @@ static int onyx_prepare(struct codec_info_item *cii,
{
u8 v;
struct onyx *onyx = cii->codec_data;
- int err = -EBUSY;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
@@ -706,10 +686,9 @@ static int onyx_prepare(struct codec_info_item *cii,
if (onyx_write_register(onyx,
ONYX_REG_DAC_CONTROL,
v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
- goto out_unlock;
+ return -EBUSY;
onyx->analog_locked = 1;
- err = 0;
- goto out_unlock;
+ return 0;
}
#endif
switch (substream->runtime->rate) {
@@ -719,8 +698,7 @@ static int onyx_prepare(struct codec_info_item *cii,
/* these rates are ok for all outputs */
/* FIXME: program spdif channel control bits here so that
* userspace doesn't have to if it only plays pcm! */
- err = 0;
- goto out_unlock;
+ return 0;
default:
/* got some rate that the digital output can't do,
* so disable and lock it */
@@ -728,16 +706,12 @@ static int onyx_prepare(struct codec_info_item *cii,
if (onyx_write_register(onyx,
ONYX_REG_DIG_INFO4,
v & ~ONYX_SPDIF_ENABLE))
- goto out_unlock;
+ return -EBUSY;
onyx->spdif_locked = 1;
- err = 0;
- goto out_unlock;
+ return 0;
}
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return -EBUSY;
}
static int onyx_open(struct codec_info_item *cii,
@@ -745,9 +719,8 @@ static int onyx_open(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx->open_count++;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -757,11 +730,10 @@ static int onyx_close(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
onyx->open_count--;
if (!onyx->open_count)
onyx->spdif_locked = onyx->analog_locked = 0;
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -771,7 +743,7 @@ static int onyx_switch_clock(struct codec_info_item *cii,
{
struct onyx *onyx = cii->codec_data;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
/* this *MUST* be more elaborate later... */
switch (what) {
case CLOCK_SWITCH_PREPARE_SLAVE:
@@ -783,7 +755,6 @@ static int onyx_switch_clock(struct codec_info_item *cii,
default: /* silence warning */
break;
}
- mutex_unlock(&onyx->mutex);
return 0;
}
@@ -794,27 +765,21 @@ static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)
{
struct onyx *onyx = cii->codec_data;
u8 v;
- int err = -ENXIO;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
- goto out_unlock;
+ return -ENXIO;
onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
/* Apple does a sleep here but the datasheet says to do it on resume */
- err = 0;
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return 0;
}
static int onyx_resume(struct codec_info_item *cii)
{
struct onyx *onyx = cii->codec_data;
u8 v;
- int err = -ENXIO;
- mutex_lock(&onyx->mutex);
+ guard(mutex)(&onyx->mutex);
/* reset codec */
onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
@@ -826,17 +791,13 @@ static int onyx_resume(struct codec_info_item *cii)
/* take codec out of suspend (if it still is after reset) */
if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
- goto out_unlock;
+ return -ENXIO;
onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
/* FIXME: should divide by sample rate, but 8k is the lowest we go */
msleep(2205000/8000);
/* reset all values */
onyx_register_init(onyx);
- err = 0;
- out_unlock:
- mutex_unlock(&onyx->mutex);
-
- return err;
+ return 0;
}
#endif /* CONFIG_PM */
@@ -1012,7 +973,7 @@ static int onyx_i2c_probe(struct i2c_client *client)
goto fail;
}
- strscpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN);
+ strscpy(onyx->codec.name, "onyx");
onyx->codec.owner = THIS_MODULE;
onyx->codec.init = onyx_init_codec;
onyx->codec.exit = onyx_exit_codec;
@@ -1039,7 +1000,7 @@ static void onyx_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id onyx_i2c_id[] = {
- { "MAC,pcm3052", 0 },
+ { "MAC,pcm3052" },
{ }
};
MODULE_DEVICE_TABLE(i2c,onyx_i2c_id);
@@ -1048,7 +1009,7 @@ static struct i2c_driver onyx_driver = {
.driver = {
.name = "aoa_codec_onyx",
},
- .probe_new = onyx_i2c_probe,
+ .probe = onyx_i2c_probe,
.remove = onyx_i2c_remove,
.id_table = onyx_i2c_id,
};
diff --git a/sound/aoa/codecs/onyx.h b/sound/aoa/codecs/onyx.h
index 6c31b7373b78..bbdca841fe90 100644
--- a/sound/aoa/codecs/onyx.h
+++ b/sound/aoa/codecs/onyx.h
@@ -8,7 +8,6 @@
#define __SND_AOA_CODEC_ONYX_H
#include <linux/i2c.h>
#include <asm/pmac_low_i2c.h>
-#include <asm/prom.h>
/* PCM3052 register definitions */
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index f906e9aaddcf..7085e0b93e29 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -60,10 +60,10 @@
*/
#include <linux/i2c.h>
#include <asm/pmac_low_i2c.h>
-#include <asm/prom.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/slab.h>
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
@@ -235,10 +235,9 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->cached_volume_l;
ucontrol->value.integer.value[1] = tas->cached_volume_r;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -254,18 +253,15 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[1] > 177)
return -EINVAL;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->cached_volume_l == ucontrol->value.integer.value[0]
- && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->cached_volume_r == ucontrol->value.integer.value[1])
return 0;
- }
tas->cached_volume_l = ucontrol->value.integer.value[0];
tas->cached_volume_r = ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_volume(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -285,10 +281,9 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = !tas->mute_l;
ucontrol->value.integer.value[1] = !tas->mute_r;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -297,18 +292,15 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->mute_l == !ucontrol->value.integer.value[0]
- && tas->mute_r == !ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->mute_r == !ucontrol->value.integer.value[1])
return 0;
- }
tas->mute_l = !ucontrol->value.integer.value[0];
tas->mute_r = !ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_volume(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -337,10 +329,9 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
struct tas *tas = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->mixer_l[idx];
ucontrol->value.integer.value[1] = tas->mixer_r[idx];
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -351,19 +342,16 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
struct tas *tas = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
- && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
- mutex_unlock(&tas->mtx);
+ && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
return 0;
- }
tas->mixer_l[idx] = ucontrol->value.integer.value[0];
tas->mixer_r[idx] = ucontrol->value.integer.value[1];
if (tas->hw_enabled)
tas_set_mixer(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -396,9 +384,8 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->drc_range;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -411,16 +398,13 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] > TAS3004_DRC_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->drc_range == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->drc_range == ucontrol->value.integer.value[0])
return 0;
- }
tas->drc_range = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas3004_set_drc(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -440,9 +424,8 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->drc_enabled;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -451,16 +434,13 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
- if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->drc_enabled == ucontrol->value.integer.value[0])
return 0;
- }
tas->drc_enabled = !!ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas3004_set_drc(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -486,9 +466,8 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -500,7 +479,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] > 1)
return -EINVAL;
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
oldacr = tas->acr;
/*
@@ -512,13 +491,10 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0])
tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL |
TAS_ACR_B_MON_SEL_RIGHT;
- if (oldacr == tas->acr) {
- mutex_unlock(&tas->mtx);
+ if (oldacr == tas->acr)
return 0;
- }
if (tas->hw_enabled)
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -557,9 +533,8 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->treble;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -571,16 +546,13 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN ||
ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->treble == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->treble == ucontrol->value.integer.value[0])
return 0;
- }
tas->treble = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas_set_treble(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -608,9 +580,8 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol,
{
struct tas *tas = snd_kcontrol_chip(kcontrol);
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
ucontrol->value.integer.value[0] = tas->bass;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -622,16 +593,13 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN ||
ucontrol->value.integer.value[0] > TAS3004_BASS_MAX)
return -EINVAL;
- mutex_lock(&tas->mtx);
- if (tas->bass == ucontrol->value.integer.value[0]) {
- mutex_unlock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
+ if (tas->bass == ucontrol->value.integer.value[0])
return 0;
- }
tas->bass = ucontrol->value.integer.value[0];
if (tas->hw_enabled)
tas_set_bass(tas);
- mutex_unlock(&tas->mtx);
return 1;
}
@@ -722,13 +690,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
break;
case CLOCK_SWITCH_SLAVE:
/* Clocks are back, re-init the codec */
- mutex_lock(&tas->mtx);
- tas_reset_init(tas);
- tas_set_volume(tas);
- tas_set_mixer(tas);
- tas->hw_enabled = 1;
- tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
- mutex_unlock(&tas->mtx);
+ scoped_guard(mutex, &tas->mtx) {
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ tas->hw_enabled = 1;
+ tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+ }
break;
default:
/* doesn't happen as of now */
@@ -743,23 +711,21 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock
* our i2c device is suspended, and then take note of that! */
static int tas_suspend(struct tas *tas)
{
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
tas->hw_enabled = 0;
tas->acr |= TAS_ACR_ANALOG_PDOWN;
tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
- mutex_unlock(&tas->mtx);
return 0;
}
static int tas_resume(struct tas *tas)
{
/* reset codec */
- mutex_lock(&tas->mtx);
+ guard(mutex)(&tas->mtx);
tas_reset_init(tas);
tas_set_volume(tas);
tas_set_mixer(tas);
tas->hw_enabled = 1;
- mutex_unlock(&tas->mtx);
return 0;
}
@@ -802,14 +768,13 @@ static int tas_init_codec(struct aoa_codec *codec)
return -EINVAL;
}
- mutex_lock(&tas->mtx);
- if (tas_reset_init(tas)) {
- printk(KERN_ERR PFX "tas failed to initialise\n");
- mutex_unlock(&tas->mtx);
- return -ENXIO;
+ scoped_guard(mutex, &tas->mtx) {
+ if (tas_reset_init(tas)) {
+ printk(KERN_ERR PFX "tas failed to initialise\n");
+ return -ENXIO;
+ }
+ tas->hw_enabled = 1;
}
- tas->hw_enabled = 1;
- mutex_unlock(&tas->mtx);
if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
aoa_get_card(),
@@ -892,7 +857,7 @@ static int tas_i2c_probe(struct i2c_client *client)
/* seems that half is a saner default */
tas->drc_range = TAS3004_DRC_MAX / 2;
- strscpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN);
+ strscpy(tas->codec.name, "tas");
tas->codec.owner = THIS_MODULE;
tas->codec.init = tas_init_codec;
tas->codec.exit = tas_exit_codec;
@@ -927,7 +892,7 @@ static void tas_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id tas_i2c_id[] = {
- { "MAC,tas3004", 0 },
+ { "MAC,tas3004" },
{ }
};
MODULE_DEVICE_TABLE(i2c,tas_i2c_id);
@@ -936,7 +901,7 @@ static struct i2c_driver tas_driver = {
.driver = {
.name = "aoa_codec_tas",
},
- .probe_new = tas_i2c_probe,
+ .probe = tas_i2c_probe,
.remove = tas_i2c_remove,
.id_table = tas_i2c_id,
};
diff --git a/sound/aoa/codecs/toonie.c b/sound/aoa/codecs/toonie.c
index 0da5af129492..b59967c49e0a 100644
--- a/sound/aoa/codecs/toonie.c
+++ b/sound/aoa/codecs/toonie.c
@@ -126,7 +126,7 @@ static int __init toonie_init(void)
if (!toonie)
return -ENOMEM;
- strscpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name));
+ strscpy(toonie->codec.name, "toonie");
toonie->codec.owner = THIS_MODULE;
toonie->codec.init = toonie_init_codec;
toonie->codec.exit = toonie_exit_codec;
diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile
index 056d69683b1e..f586c340fe12 100644
--- a/sound/aoa/core/Makefile
+++ b/sound/aoa/core/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SND_AOA) += snd-aoa.o
-snd-aoa-objs := core.o \
+snd-aoa-y := core.o \
alsa.o \
gpio-pmf.o \
gpio-feature.o
diff --git a/sound/aoa/core/alsa.c b/sound/aoa/core/alsa.c
index 7fce8581ddbd..aad7dfe089c7 100644
--- a/sound/aoa/core/alsa.c
+++ b/sound/aoa/core/alsa.c
@@ -28,10 +28,10 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
return err;
aoa_card = alsa_card->private_data;
aoa_card->alsa_card = alsa_card;
- strscpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
- strscpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
- strscpy(alsa_card->longname, name, sizeof(alsa_card->longname));
- strscpy(alsa_card->mixername, name, sizeof(alsa_card->mixername));
+ strscpy(alsa_card->driver, "AppleOnbdAudio");
+ strscpy(alsa_card->shortname, name);
+ strscpy(alsa_card->longname, name);
+ strscpy(alsa_card->mixername, name);
err = snd_card_register(aoa_card->alsa_card);
if (err < 0) {
printk(KERN_ERR "snd-aoa: couldn't register alsa card\n");
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index 39bb409b27f6..19ed0e6907da 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -212,10 +212,9 @@ static void ftr_handle_notify(struct work_struct *work)
struct gpio_notification *notif =
container_of(work, struct gpio_notification, work.work);
- mutex_lock(&notif->mutex);
+ guard(mutex)(&notif->mutex);
if (notif->notify)
notif->notify(notif->data);
- mutex_unlock(&notif->mutex);
}
static void gpio_enable_dual_edge(int gpio)
@@ -341,19 +340,17 @@ static int ftr_set_notify(struct gpio_runtime *rt,
if (!irq)
return -ENODEV;
- mutex_lock(&notif->mutex);
+ guard(mutex)(&notif->mutex);
old = notif->notify;
- if (!old && !notify) {
- err = 0;
- goto out_unlock;
- }
+ if (!old && !notify)
+ return 0;
if (old && notify) {
if (old == notify && notif->data == data)
err = 0;
- goto out_unlock;
+ return err;
}
if (old && !notify)
@@ -362,16 +359,13 @@ static int ftr_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
if (err)
- goto out_unlock;
+ return err;
}
notif->notify = notify;
notif->data = data;
- err = 0;
- out_unlock:
- mutex_unlock(&notif->mutex);
- return err;
+ return 0;
}
static int ftr_get_detect(struct gpio_runtime *rt,
diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c
index 37866039d1ea..e76bde25e41a 100644
--- a/sound/aoa/core/gpio-pmf.c
+++ b/sound/aoa/core/gpio-pmf.c
@@ -74,10 +74,9 @@ static void pmf_handle_notify(struct work_struct *work)
struct gpio_notification *notif =
container_of(work, struct gpio_notification, work.work);
- mutex_lock(&notif->mutex);
+ guard(mutex)(&notif->mutex);
if (notif->notify)
notif->notify(notif->data);
- mutex_unlock(&notif->mutex);
}
static void pmf_gpio_init(struct gpio_runtime *rt)
@@ -154,19 +153,17 @@ static int pmf_set_notify(struct gpio_runtime *rt,
return -EINVAL;
}
- mutex_lock(&notif->mutex);
+ guard(mutex)(&notif->mutex);
old = notif->notify;
- if (!old && !notify) {
- err = 0;
- goto out_unlock;
- }
+ if (!old && !notify)
+ return 0;
if (old && notify) {
if (old == notify && notif->data == data)
err = 0;
- goto out_unlock;
+ return err;
}
if (old && !notify) {
@@ -178,10 +175,8 @@ static int pmf_set_notify(struct gpio_runtime *rt,
if (!old && notify) {
irq_client = kzalloc(sizeof(struct pmf_irq_client),
GFP_KERNEL);
- if (!irq_client) {
- err = -ENOMEM;
- goto out_unlock;
- }
+ if (!irq_client)
+ return -ENOMEM;
irq_client->data = notif;
irq_client->handler = pmf_handle_notify_irq;
irq_client->owner = THIS_MODULE;
@@ -192,17 +187,14 @@ static int pmf_set_notify(struct gpio_runtime *rt,
printk(KERN_ERR "snd-aoa: gpio layer failed to"
" register %s irq (%d)\n", name, err);
kfree(irq_client);
- goto out_unlock;
+ return err;
}
notif->gpio_private = irq_client;
}
notif->notify = notify;
notif->data = data;
- err = 0;
- out_unlock:
- mutex_unlock(&notif->mutex);
- return err;
+ return 0;
}
static int pmf_get_detect(struct gpio_runtime *rt,
diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile
index 3f1d55f3f1fc..2c3bee6cfa2c 100644
--- a/sound/aoa/fabrics/Makefile
+++ b/sound/aoa/fabrics/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-aoa-fabric-layout-objs += layout.o
+snd-aoa-fabric-layout-y += layout.o
obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index 850dc8c53e9b..bb2a0ef3004b 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -7,9 +7,10 @@
* This fabric module looks for sound codecs based on the
* layout-id or device-id property in the device tree.
*/
-#include <asm/prom.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include "../aoa.h"
#include "../soundbus/soundbus.h"
@@ -948,8 +949,7 @@ static void layout_attached_codec(struct aoa_codec *codec)
ldev->gpio.methods->set_lineout(codec->gpio, 1);
ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
- strscpy(ctl->id.name,
- "Headphone Switch", sizeof(ctl->id.name));
+ strscpy(ctl->id.name, "Headphone Switch");
ldev->lineout_ctrl = ctl;
aoa_snd_ctl_add(ctl);
ldev->have_lineout_detect =
@@ -963,15 +963,13 @@ static void layout_attached_codec(struct aoa_codec *codec)
ldev);
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name,
- "Headphone Detect Autoswitch",
- sizeof(ctl->id.name));
+ "Headphone Detect Autoswitch");
aoa_snd_ctl_add(ctl);
ctl = snd_ctl_new1(&lineout_detected,
ldev);
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name,
- "Headphone Detected",
- sizeof(ctl->id.name));
+ "Headphone Detected");
ldev->lineout_detected_ctrl = ctl;
aoa_snd_ctl_add(ctl);
}
@@ -1125,7 +1123,6 @@ static void aoa_fabric_layout_remove(struct soundbus_dev *sdev)
sdev->pcmname = NULL;
}
-#ifdef CONFIG_PM_SLEEP
static int aoa_fabric_layout_suspend(struct device *dev)
{
struct layout_dev *ldev = dev_get_drvdata(dev);
@@ -1146,11 +1143,9 @@ static int aoa_fabric_layout_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops,
aoa_fabric_layout_suspend, aoa_fabric_layout_resume);
-#endif
-
static struct soundbus_driver aoa_soundbus_driver = {
.name = "snd_aoa_soundbus_drv",
.owner = THIS_MODULE,
@@ -1158,9 +1153,7 @@ static struct soundbus_driver aoa_soundbus_driver = {
.remove = aoa_fabric_layout_remove,
.driver = {
.owner = THIS_MODULE,
-#ifdef CONFIG_PM_SLEEP
.pm = &aoa_fabric_layout_pm_ops,
-#endif
}
};
diff --git a/sound/aoa/soundbus/Makefile b/sound/aoa/soundbus/Makefile
index e0b61cf5518e..a10b102daf81 100644
--- a/sound/aoa/soundbus/Makefile
+++ b/sound/aoa/soundbus/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SND_AOA_SOUNDBUS) += snd-aoa-soundbus.o
-snd-aoa-soundbus-objs := core.o sysfs.o
+snd-aoa-soundbus-y := core.o sysfs.o
obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += i2sbus/
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 39fb8fe4e6ab..2a295f610594 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -6,6 +6,8 @@
*/
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include "soundbus.h"
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
@@ -125,7 +127,7 @@ static void soundbus_device_shutdown(struct device *dev)
/* soundbus_dev_attrs is declared in sysfs.c */
ATTRIBUTE_GROUPS(soundbus_dev);
-static struct bus_type soundbus_bus_type = {
+static const struct bus_type soundbus_bus_type = {
.name = "aoa-soundbus",
.probe = soundbus_probe,
.uevent = soundbus_uevent,
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile
index 1b38c87fef09..1ddaa0e17d67 100644
--- a/sound/aoa/soundbus/i2sbus/Makefile
+++ b/sound/aoa/soundbus/i2sbus/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o
-snd-aoa-i2sbus-objs := core.o pcm.o control.o
+snd-aoa-i2sbus-y := core.o pcm.o control.o
diff --git a/sound/aoa/soundbus/i2sbus/control.c b/sound/aoa/soundbus/i2sbus/control.c
index 7d3abb8b2416..a003ef06de63 100644
--- a/sound/aoa/soundbus/i2sbus/control.c
+++ b/sound/aoa/soundbus/i2sbus/control.c
@@ -10,7 +10,6 @@
#include <linux/slab.h>
#include <linux/io.h>
-#include <asm/prom.h>
#include <asm/macio.h>
#include <asm/pmac_feature.h>
#include <asm/pmac_pfunc.h>
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 51ed2f34b276..f4d43c854bbd 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -10,6 +10,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -92,14 +93,12 @@ static irqreturn_t i2sbus_bus_intr(int irq, void *devid)
struct i2sbus_dev *dev = devid;
u32 intreg;
- spin_lock(&dev->low_lock);
+ guard(spinlock)(&dev->low_lock);
intreg = in_le32(&dev->intfregs->intr_ctl);
/* acknowledge interrupt reasons */
out_le32(&dev->intfregs->intr_ctl, intreg);
- spin_unlock(&dev->low_lock);
-
return IRQ_HANDLED;
}
@@ -157,7 +156,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
struct device_node *child, *sound = NULL;
struct resource *r;
int i, layout = 0, rlen, ok = force;
- char node_name[6];
+ char node_name[8];
static const char *rnames[] = { "i2sbus: %pOFn (control)",
"i2sbus: %pOFn (tx)",
"i2sbus: %pOFn (rx)" };
@@ -334,7 +333,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
{
- struct device_node *np = NULL;
+ struct device_node *np;
int got = 0, err;
struct i2sbus_control *control = NULL;
@@ -346,7 +345,7 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
return -ENODEV;
}
- while ((np = of_get_next_child(dev->ofdev.dev.of_node, np))) {
+ for_each_child_of_node(dev->ofdev.dev.of_node, np) {
if (of_device_is_compatible(np, "i2sbus") ||
of_device_is_compatible(np, "i2s-modem")) {
got += i2sbus_add_dev(dev, control, np);
@@ -364,15 +363,13 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
return 0;
}
-static int i2sbus_remove(struct macio_dev* dev)
+static void i2sbus_remove(struct macio_dev *dev)
{
struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
struct i2sbus_dev *i2sdev, *tmp;
list_for_each_entry_safe(i2sdev, tmp, &control->list, item)
soundbus_remove_one(&i2sdev->sound);
-
- return 0;
}
#ifdef CONFIG_PM
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index e86fdbb3b4c5..7a3cae0d6c26 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -13,7 +13,6 @@
#include <sound/pcm.h>
-#include <asm/prom.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
diff --git a/sound/aoa/soundbus/i2sbus/interface.h b/sound/aoa/soundbus/i2sbus/interface.h
index 16fa88822d2b..a136274266ea 100644
--- a/sound/aoa/soundbus/i2sbus/interface.h
+++ b/sound/aoa/soundbus/i2sbus/interface.h
@@ -34,7 +34,7 @@ struct i2s_interface_regs {
__le32 peak_level_in1; /* 0x90 */
PAD(12);
/* total size: 0x100 bytes */
-} __attribute__((__packed__));
+} __packed;
/* interrupt register is just a bitfield with
* interrupt enable and pending bits */
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index a9e502a6cdeb..4c480ad2c05d 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -79,11 +79,10 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
u64 formats = 0;
unsigned int rates = 0;
struct transfer_info v;
- int result = 0;
int bus_factor = 0, sysclock_factor = 0;
int found_this;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, &other);
@@ -92,8 +91,7 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
if (pi->active) {
/* alsa messed up */
- result = -EBUSY;
- goto out_unlock;
+ return -EBUSY;
}
/* we now need to assign the hw */
@@ -117,10 +115,8 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
ti++;
}
}
- if (!masks_inited || !bus_factor || !sysclock_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
+ if (!masks_inited || !bus_factor || !sysclock_factor)
+ return -ENODEV;
/* bus dependent stuff */
hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
@@ -194,15 +190,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
hw->periods_max = MAX_DBDMA_COMMANDS;
err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0) {
- result = err;
- goto out_unlock;
- }
+ if (err < 0)
+ return err;
list_for_each_entry(cii, &sdev->codec_list, list) {
if (cii->codec->open) {
err = cii->codec->open(cii, pi->substream);
if (err) {
- result = err;
/* unwind */
found_this = 0;
list_for_each_entry_reverse(rev,
@@ -214,14 +207,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
if (rev == cii)
found_this = 1;
}
- goto out_unlock;
+ return err;
}
}
}
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
+ return 0;
}
#undef CHECK_RATE
@@ -232,7 +223,7 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
struct pcm_info *pi;
int err = 0, tmp;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, NULL);
@@ -246,7 +237,6 @@ static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
pi->substream = NULL;
pi->active = 0;
- mutex_unlock(&i2sdev->lock);
return err;
}
@@ -255,24 +245,24 @@ static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
{
unsigned long flags;
DECLARE_COMPLETION_ONSTACK(done);
- long timeout;
+ unsigned long time_left;
spin_lock_irqsave(&i2sdev->low_lock, flags);
if (pi->dbdma_ring.stopping) {
pi->stop_completion = &done;
spin_unlock_irqrestore(&i2sdev->low_lock, flags);
- timeout = wait_for_completion_timeout(&done, HZ);
+ time_left = wait_for_completion_timeout(&done, HZ);
spin_lock_irqsave(&i2sdev->low_lock, flags);
pi->stop_completion = NULL;
- if (timeout == 0) {
+ if (time_left == 0) {
/* timeout expired, stop dbdma forcefully */
printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
/* make sure RUN, PAUSE and S0 bits are cleared */
out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
pi->dbdma_ring.stopping = 0;
- timeout = 10;
+ time_left = 10;
while (in_le32(&pi->dbdma->status) & ACTIVE) {
- if (--timeout <= 0)
+ if (--time_left <= 0)
break;
udelay(1);
}
@@ -330,33 +320,26 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
int input_16bit;
struct pcm_info *pi, *other;
int cnt;
- int result = 0;
unsigned int cmd, stopaddr;
- mutex_lock(&i2sdev->lock);
+ guard(mutex)(&i2sdev->lock);
get_pcm_info(i2sdev, in, &pi, &other);
- if (pi->dbdma_ring.running) {
- result = -EBUSY;
- goto out_unlock;
- }
+ if (pi->dbdma_ring.running)
+ return -EBUSY;
if (pi->dbdma_ring.stopping)
i2sbus_wait_for_stop(i2sdev, pi);
- if (!pi->substream || !pi->substream->runtime) {
- result = -EINVAL;
- goto out_unlock;
- }
+ if (!pi->substream || !pi->substream->runtime)
+ return -EINVAL;
runtime = pi->substream->runtime;
pi->active = 1;
if (other->active &&
((i2sdev->format != runtime->format)
- || (i2sdev->rate != runtime->rate))) {
- result = -EINVAL;
- goto out_unlock;
- }
+ || (i2sdev->rate != runtime->rate)))
+ return -EINVAL;
i2sdev->format = runtime->format;
i2sdev->rate = runtime->rate;
@@ -412,10 +395,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
bi.bus_factor = cii->codec->bus_factor;
break;
}
- if (!bi.bus_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
+ if (!bi.bus_factor)
+ return -ENODEV;
input_16bit = 1;
break;
case SNDRV_PCM_FORMAT_S32_BE:
@@ -426,8 +407,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
input_16bit = 0;
break;
default:
- result = -EINVAL;
- goto out_unlock;
+ return -EINVAL;
}
/* we assume all sysclocks are the same! */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
@@ -438,10 +418,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (clock_and_divisors(bi.sysclock_factor,
bi.bus_factor,
runtime->rate,
- &sfr) < 0) {
- result = -EINVAL;
- goto out_unlock;
- }
+ &sfr) < 0)
+ return -EINVAL;
switch (bi.bus_factor) {
case 32:
sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
@@ -457,10 +435,8 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
int err = 0;
if (cii->codec->prepare)
err = cii->codec->prepare(cii, &bi, pi->substream);
- if (err) {
- result = err;
- goto out_unlock;
- }
+ if (err)
+ return err;
}
/* codecs are fine with it, so set our clocks */
if (input_16bit)
@@ -476,7 +452,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
/* not locking these is fine since we touch them only in this function */
if (in_le32(&i2sdev->intfregs->serial_format) == sfr
&& in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
- goto out_unlock;
+ return 0;
/* let's notify the codecs about clocks going away.
* For now we only do mastering on the i2s cell... */
@@ -514,9 +490,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
if (cii->codec->switch_clock)
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
+ return 0;
}
#ifdef CONFIG_PM
@@ -531,20 +505,16 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
{
struct codec_info_item *cii;
struct pcm_info *pi;
- int result = 0;
- unsigned long flags;
- spin_lock_irqsave(&i2sdev->low_lock, flags);
+ guard(spinlock_irqsave)(&i2sdev->low_lock);
get_pcm_info(i2sdev, in, &pi, NULL);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
- if (pi->dbdma_ring.running) {
- result = -EALREADY;
- goto out_unlock;
- }
+ if (pi->dbdma_ring.running)
+ return -EALREADY;
list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
if (cii->codec->start)
cii->codec->start(cii, pi->substream);
@@ -558,7 +528,7 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
udelay(10);
if (in_le32(&pi->dbdma->status) & ACTIVE) {
pi->dbdma_ring.stopping = 0;
- goto out_unlock; /* keep running */
+ return 0; /* keep running */
}
}
}
@@ -584,10 +554,8 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- if (!pi->dbdma_ring.running) {
- result = -EALREADY;
- goto out_unlock;
- }
+ if (!pi->dbdma_ring.running)
+ return -EALREADY;
pi->dbdma_ring.running = 0;
/* Set the S0 bit to make the DMA branch to the stop cmd */
@@ -599,13 +567,10 @@ static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
cii->codec->stop(cii, pi->substream);
break;
default:
- result = -EINVAL;
- goto out_unlock;
+ return -EINVAL;
}
- out_unlock:
- spin_unlock_irqrestore(&i2sdev->low_lock, flags);
- return result;
+ return 0;
}
static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
@@ -632,70 +597,67 @@ static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
int dma_stopped = 0;
struct snd_pcm_runtime *runtime;
- spin_lock(&i2sdev->low_lock);
- get_pcm_info(i2sdev, in, &pi, NULL);
- if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
- goto out_unlock;
+ scoped_guard(spinlock, &i2sdev->low_lock) {
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
+ return;
+
+ i = pi->current_period;
+ runtime = pi->substream->runtime;
+ while (pi->dbdma_ring.cmds[i].xfer_status) {
+ if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
+ /*
+ * BT is the branch taken bit. If it took a branch
+ * it is because we set the S0 bit to make it
+ * branch to the stop command.
+ */
+ dma_stopped = 1;
+ pi->dbdma_ring.cmds[i].xfer_status = 0;
+
+ if (++i >= runtime->periods) {
+ i = 0;
+ pi->frame_count += runtime->buffer_size;
+ }
+ pi->current_period = i;
- i = pi->current_period;
- runtime = pi->substream->runtime;
- while (pi->dbdma_ring.cmds[i].xfer_status) {
- if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
/*
- * BT is the branch taken bit. If it took a branch
- * it is because we set the S0 bit to make it
- * branch to the stop command.
+ * Check the frame count. The DMA tends to get a bit
+ * ahead of the frame counter, which confuses the core.
*/
- dma_stopped = 1;
- pi->dbdma_ring.cmds[i].xfer_status = 0;
-
- if (++i >= runtime->periods) {
- i = 0;
- pi->frame_count += runtime->buffer_size;
+ fc = in_le32(&i2sdev->intfregs->frame_count);
+ nframes = i * runtime->period_size;
+ if (fc < pi->frame_count + nframes)
+ pi->frame_count = fc - nframes;
}
- pi->current_period = i;
-
- /*
- * Check the frame count. The DMA tends to get a bit
- * ahead of the frame counter, which confuses the core.
- */
- fc = in_le32(&i2sdev->intfregs->frame_count);
- nframes = i * runtime->period_size;
- if (fc < pi->frame_count + nframes)
- pi->frame_count = fc - nframes;
- }
- if (dma_stopped) {
- timeout = 1000;
- for (;;) {
- status = in_le32(&pi->dbdma->status);
- if (!(status & ACTIVE) && (!in || (status & 0x80)))
- break;
- if (--timeout <= 0) {
- printk(KERN_ERR "i2sbus: timed out "
- "waiting for DMA to stop!\n");
- break;
+ if (dma_stopped) {
+ timeout = 1000;
+ for (;;) {
+ status = in_le32(&pi->dbdma->status);
+ if (!(status & ACTIVE) && (!in || (status & 0x80)))
+ break;
+ if (--timeout <= 0) {
+ printk(KERN_ERR
+ "i2sbus: timed out waiting for DMA to stop!\n");
+ break;
+ }
+ udelay(1);
}
- udelay(1);
- }
- /* Turn off DMA controller, clear S0 bit */
- out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
+ /* Turn off DMA controller, clear S0 bit */
+ out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
- pi->dbdma_ring.stopping = 0;
- if (pi->stop_completion)
- complete(pi->stop_completion);
+ pi->dbdma_ring.stopping = 0;
+ if (pi->stop_completion)
+ complete(pi->stop_completion);
+ }
+
+ if (!pi->dbdma_ring.running)
+ return;
}
- if (!pi->dbdma_ring.running)
- goto out_unlock;
- spin_unlock(&i2sdev->low_lock);
/* may call _trigger again, hence needs to be unlocked */
snd_pcm_period_elapsed(pi->substream);
- return;
-
- out_unlock:
- spin_unlock(&i2sdev->low_lock);
}
irqreturn_t i2sbus_tx_intr(int irq, void *devid)
@@ -972,7 +934,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
&i2sbus_playback_ops);
- dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev.parent =
+ dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev->parent =
&dev->ofdev.dev;
i2sdev->out.created = 1;
}
@@ -989,7 +951,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
&i2sbus_record_ops);
- dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev.parent =
+ dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev->parent =
&dev->ofdev.dev;
i2sdev->in.created = 1;
}
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h
index db40f9d042b4..877cbad93f12 100644
--- a/sound/aoa/soundbus/soundbus.h
+++ b/sound/aoa/soundbus/soundbus.h
@@ -7,7 +7,7 @@
#ifndef __SOUNDBUS_H
#define __SOUNDBUS_H
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <linux/list.h>
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 34c769489877..899edb4bb278 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -4,11 +4,11 @@
#
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
-snd-aaci-objs := aaci.o
+snd-aaci-y := aaci.o
obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o
snd-pxa2xx-lib-y := pxa2xx-pcm-lib.o
snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
-snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
+snd-pxa2xx-ac97-y := pxa2xx-ac97.o
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 0817ad21af74..5548ed8e6b1c 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -73,7 +73,7 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
if (ac97->num >= 4)
return;
- mutex_lock(&aaci->ac97_sem);
+ guard(mutex)(&aaci->ac97_sem);
aaci_ac97_select_codec(aaci, ac97);
@@ -97,8 +97,6 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
if (v & (SLFR_1TXB|SLFR_2TXB))
dev_err(&aaci->dev->dev,
"timeout waiting for write to complete\n");
-
- mutex_unlock(&aaci->ac97_sem);
}
/*
@@ -113,7 +111,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
if (ac97->num >= 4)
return ~0;
- mutex_lock(&aaci->ac97_sem);
+ guard(mutex)(&aaci->ac97_sem);
aaci_ac97_select_codec(aaci, ac97);
@@ -134,8 +132,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
if (v & SLFR_1TXB) {
dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
- v = ~0;
- goto out;
+ return ~0;
}
/* Now wait for the response frame */
@@ -151,8 +148,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
if (v != (SLFR_1RXV|SLFR_2RXV)) {
dev_err(&aaci->dev->dev, "timeout on RX valid\n");
- v = ~0;
- goto out;
+ return ~0;
}
do {
@@ -171,8 +167,6 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
v = ~0;
}
} while (retries);
- out:
- mutex_unlock(&aaci->ac97_sem);
return v;
}
@@ -216,45 +210,43 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
return;
}
- spin_lock(&aacirun->lock);
-
- ptr = aacirun->ptr;
- do {
- unsigned int len = aacirun->fifo_bytes;
- u32 val;
-
- if (aacirun->bytes <= 0) {
- aacirun->bytes += aacirun->period;
- period_elapsed = true;
- }
- if (!(aacirun->cr & CR_EN))
- break;
-
- val = readl(aacirun->base + AACI_SR);
- if (!(val & SR_RXHF))
- break;
- if (!(val & SR_RXFF))
- len >>= 1;
-
- aacirun->bytes -= len;
-
- /* reading 16 bytes at a time */
- for( ; len > 0; len -= 16) {
- asm(
- "ldmia %1, {r0, r1, r2, r3}\n\t"
- "stmia %0!, {r0, r1, r2, r3}"
- : "+r" (ptr)
- : "r" (aacirun->fifo)
- : "r0", "r1", "r2", "r3", "cc");
-
- if (ptr >= aacirun->end)
- ptr = aacirun->start;
- }
- } while(1);
-
- aacirun->ptr = ptr;
-
- spin_unlock(&aacirun->lock);
+ scoped_guard(spinlock, &aacirun->lock) {
+ ptr = aacirun->ptr;
+ do {
+ unsigned int len = aacirun->fifo_bytes;
+ u32 val;
+
+ if (aacirun->bytes <= 0) {
+ aacirun->bytes += aacirun->period;
+ period_elapsed = true;
+ }
+ if (!(aacirun->cr & CR_EN))
+ break;
+
+ val = readl(aacirun->base + AACI_SR);
+ if (!(val & SR_RXHF))
+ break;
+ if (!(val & SR_RXFF))
+ len >>= 1;
+
+ aacirun->bytes -= len;
+
+ /* reading 16 bytes at a time */
+ for( ; len > 0; len -= 16) {
+ asm(
+ "ldmia %1, {r0, r1, r2, r3}\n\t"
+ "stmia %0!, {r0, r1, r2, r3}"
+ : "+r" (ptr)
+ : "r" (aacirun->fifo)
+ : "r0", "r1", "r2", "r3", "cc");
+
+ if (ptr >= aacirun->end)
+ ptr = aacirun->start;
+ }
+ } while(1);
+
+ aacirun->ptr = ptr;
+ }
if (period_elapsed)
snd_pcm_period_elapsed(aacirun->substream);
@@ -276,45 +268,43 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
return;
}
- spin_lock(&aacirun->lock);
-
- ptr = aacirun->ptr;
- do {
- unsigned int len = aacirun->fifo_bytes;
- u32 val;
-
- if (aacirun->bytes <= 0) {
- aacirun->bytes += aacirun->period;
- period_elapsed = true;
- }
- if (!(aacirun->cr & CR_EN))
- break;
-
- val = readl(aacirun->base + AACI_SR);
- if (!(val & SR_TXHE))
- break;
- if (!(val & SR_TXFE))
- len >>= 1;
-
- aacirun->bytes -= len;
-
- /* writing 16 bytes at a time */
- for ( ; len > 0; len -= 16) {
- asm(
- "ldmia %0!, {r0, r1, r2, r3}\n\t"
- "stmia %1, {r0, r1, r2, r3}"
- : "+r" (ptr)
- : "r" (aacirun->fifo)
- : "r0", "r1", "r2", "r3", "cc");
-
- if (ptr >= aacirun->end)
- ptr = aacirun->start;
- }
- } while (1);
-
- aacirun->ptr = ptr;
-
- spin_unlock(&aacirun->lock);
+ scoped_guard(spinlock, &aacirun->lock) {
+ ptr = aacirun->ptr;
+ do {
+ unsigned int len = aacirun->fifo_bytes;
+ u32 val;
+
+ if (aacirun->bytes <= 0) {
+ aacirun->bytes += aacirun->period;
+ period_elapsed = true;
+ }
+ if (!(aacirun->cr & CR_EN))
+ break;
+
+ val = readl(aacirun->base + AACI_SR);
+ if (!(val & SR_TXHE))
+ break;
+ if (!(val & SR_TXFE))
+ len >>= 1;
+
+ aacirun->bytes -= len;
+
+ /* writing 16 bytes at a time */
+ for ( ; len > 0; len -= 16) {
+ asm(
+ "ldmia %0!, {r0, r1, r2, r3}\n\t"
+ "stmia %1, {r0, r1, r2, r3}"
+ : "+r" (ptr)
+ : "r" (aacirun->fifo)
+ : "r0", "r1", "r2", "r3", "cc");
+
+ if (ptr >= aacirun->end)
+ ptr = aacirun->start;
+ }
+ } while (1);
+
+ aacirun->ptr = ptr;
+ }
if (period_elapsed)
snd_pcm_period_elapsed(aacirun->substream);
@@ -437,14 +427,13 @@ static int aaci_pcm_open(struct snd_pcm_substream *substream)
*/
runtime->hw.fifo_size = aaci->fifo_depth * 2;
- mutex_lock(&aaci->irq_lock);
+ guard(mutex)(&aaci->irq_lock);
if (!aaci->users++) {
ret = request_irq(aaci->dev->irq[0], aaci_irq,
IRQF_SHARED, DRIVER_NAME, aaci);
if (ret != 0)
aaci->users--;
}
- mutex_unlock(&aaci->irq_lock);
return ret;
}
@@ -462,10 +451,9 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream)
aacirun->substream = NULL;
- mutex_lock(&aaci->irq_lock);
+ guard(mutex)(&aaci->irq_lock);
if (!--aaci->users)
free_irq(aaci->dev->irq[0], aaci);
- mutex_unlock(&aaci->irq_lock);
return 0;
}
@@ -585,10 +573,8 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun)
static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct aaci_runtime *aacirun = substream->runtime->private_data;
- unsigned long flags;
- int ret = 0;
- spin_lock_irqsave(&aacirun->lock, flags);
+ guard(spinlock_irqsave)(&aacirun->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -614,12 +600,10 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm
break;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
- spin_unlock_irqrestore(&aacirun->lock, flags);
-
- return ret;
+ return 0;
}
static const struct snd_pcm_ops aaci_playback_ops = {
@@ -669,10 +653,8 @@ static void aaci_pcm_capture_start(struct aaci_runtime *aacirun)
static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct aaci_runtime *aacirun = substream->runtime->private_data;
- unsigned long flags;
- int ret = 0;
- spin_lock_irqsave(&aacirun->lock, flags);
+ guard(spinlock_irqsave)(&aacirun->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -698,12 +680,10 @@ static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd
break;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
- spin_unlock_irqrestore(&aacirun->lock, flags);
-
- return ret;
+ return 0;
}
static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream)
@@ -737,10 +717,8 @@ static const struct snd_pcm_ops aaci_capture_ops = {
/*
* Power Management.
*/
-#ifdef CONFIG_PM
static int aaci_do_suspend(struct snd_card *card)
{
- struct aaci *aaci = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
return 0;
}
@@ -763,12 +741,7 @@ static int aaci_resume(struct device *dev)
return card ? aaci_do_resume(card) : 0;
}
-static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
-#define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
-#else
-#define AACI_DEV_PM_OPS NULL
-#endif
-
+static DEFINE_SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
static const struct ac97_pcm ac97_defs[] = {
[0] = { /* Front PCM */
@@ -1068,7 +1041,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,
@@ -1081,7 +1054,7 @@ MODULE_DEVICE_TABLE(amba, aaci_ids);
static struct amba_driver aaci_driver = {
.drv = {
.name = DRIVER_NAME,
- .pm = AACI_DEV_PM_OPS,
+ .pm = &aaci_dev_pm_ops,
},
.probe = aaci_probe,
.remove = aaci_remove,
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index 2ca33fd5a575..64510318091f 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -33,8 +33,6 @@ static struct clk *ac97conf_clk;
static int reset_gpio;
static void __iomem *ac97_reg_base;
-extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
-
/*
* Beware PXA27x bugs:
*
@@ -53,7 +51,7 @@ int pxa2xx_ac97_read(int slot, unsigned short reg)
if (slot > 0)
return -ENODEV;
- mutex_lock(&car_mutex);
+ guard(mutex)(&car_mutex);
/* set up primary or secondary codec space */
if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
@@ -69,13 +67,12 @@ int pxa2xx_ac97_read(int slot, unsigned short reg)
gsr_bits = 0;
val = (readl(reg_addr) & 0xffff);
if (reg == AC97_GPIO_STATUS)
- goto out;
+ return val;
if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 &&
!((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) {
printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
__func__, reg, readl(ac97_reg_base + GSR) | gsr_bits);
- val = -ETIMEDOUT;
- goto out;
+ return -ETIMEDOUT;
}
/* valid data now */
@@ -84,8 +81,6 @@ int pxa2xx_ac97_read(int slot, unsigned short reg)
val = (readl(reg_addr) & 0xffff);
/* but we've just started another cycle... */
wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1);
-
-out: mutex_unlock(&car_mutex);
return val;
}
EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
@@ -95,7 +90,7 @@ int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val)
u32 __iomem *reg_addr;
int ret = 0;
- mutex_lock(&car_mutex);
+ guard(mutex)(&car_mutex);
/* set up primary or secondary codec space */
if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
@@ -116,7 +111,6 @@ int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val)
ret = -EIO;
}
- mutex_unlock(&car_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 2d83ad91f968..77b11616a7ee 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -111,8 +111,6 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
}
-#ifdef CONFIG_PM_SLEEP
-
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
{
pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
@@ -164,8 +162,7 @@ static int pxa2xx_ac97_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
.open = pxa2xx_ac97_pcm_open,
@@ -274,12 +271,10 @@ static void pxa2xx_ac97_remove(struct platform_device *dev)
static struct platform_driver pxa2xx_ac97_driver = {
.probe = pxa2xx_ac97_probe,
- .remove_new = pxa2xx_ac97_remove,
+ .remove = pxa2xx_ac97_remove,
.driver = {
.name = "pxa2xx-ac97",
-#ifdef CONFIG_PM_SLEEP
.pm = &pxa2xx_ac97_pm_ops,
-#endif
},
};
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
index 0a48805e513a..571e9d909cdf 100644
--- a/sound/arm/pxa2xx-pcm-lib.c
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -33,12 +33,12 @@ int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_dmaengine_dai_dma_data *dma_params;
struct dma_slave_config config;
int ret;
- dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_params = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if (!dma_params)
return 0;
@@ -47,7 +47,7 @@ int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
snd_dmaengine_pcm_set_config_from_dai_data(substream,
- snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream),
+ snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream),
&config);
ret = dmaengine_slave_config(chan, &config);
@@ -79,14 +79,14 @@ EXPORT_SYMBOL(pxa2xx_pcm_prepare);
int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dmaengine_dai_dma_data *dma_params;
int ret;
runtime->hw = pxa2xx_pcm_hardware;
- dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_params = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if (!dma_params)
return 0;
@@ -111,7 +111,7 @@ int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
return ret;
return snd_dmaengine_pcm_open(
- substream, dma_request_slave_channel(asoc_rtd_to_cpu(rtd, 0)->dev,
+ substream, dma_request_slave_channel(snd_soc_rtd_to_cpu(rtd, 0)->dev,
dma_params->chan_name));
}
EXPORT_SYMBOL(pxa2xx_pcm_open);
diff --git a/sound/atmel/Makefile b/sound/atmel/Makefile
index 57bc6f65be19..a8917d1854c7 100644
--- a/sound/atmel/Makefile
+++ b/sound/atmel/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-atmel-ac97c-objs := ac97c.o
+snd-atmel-ac97c-y := ac97c.o
obj-$(CONFIG_SND_ATMEL_AC97C) += snd-atmel-ac97c.o
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index c8912b8a1dc5..df0a049192de 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -12,13 +12,13 @@
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/string.h>
#include <linux/types.h>
#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/initval.h>
@@ -88,7 +88,7 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- mutex_lock(&opened_mutex);
+ guard(mutex)(&opened_mutex);
chip->opened++;
runtime->hw = atmel_ac97c_hw;
if (chip->cur_rate) {
@@ -97,7 +97,6 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
}
if (chip->cur_format)
runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
- mutex_unlock(&opened_mutex);
chip->playback_substream = substream;
return 0;
}
@@ -107,7 +106,7 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- mutex_lock(&opened_mutex);
+ guard(mutex)(&opened_mutex);
chip->opened++;
runtime->hw = atmel_ac97c_hw;
if (chip->cur_rate) {
@@ -116,7 +115,6 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
}
if (chip->cur_format)
runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
- mutex_unlock(&opened_mutex);
chip->capture_substream = substream;
return 0;
}
@@ -125,13 +123,12 @@ static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- mutex_lock(&opened_mutex);
+ guard(mutex)(&opened_mutex);
chip->opened--;
if (!chip->opened) {
chip->cur_rate = 0;
chip->cur_format = 0;
}
- mutex_unlock(&opened_mutex);
chip->playback_substream = NULL;
@@ -142,13 +139,12 @@ static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- mutex_lock(&opened_mutex);
+ guard(mutex)(&opened_mutex);
chip->opened--;
if (!chip->opened) {
chip->cur_rate = 0;
chip->cur_format = 0;
}
- mutex_unlock(&opened_mutex);
chip->capture_substream = NULL;
@@ -161,10 +157,9 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
/* Set restrictions to params. */
- mutex_lock(&opened_mutex);
+ guard(mutex)(&opened_mutex);
chip->cur_rate = params_rate(hw_params);
chip->cur_format = params_format(hw_params);
- mutex_unlock(&opened_mutex);
return 0;
}
@@ -175,10 +170,9 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
/* Set restrictions to params. */
- mutex_lock(&opened_mutex);
+ guard(mutex)(&opened_mutex);
chip->cur_rate = params_rate(hw_params);
chip->cur_format = params_format(hw_params);
- mutex_unlock(&opened_mutex);
return 0;
}
@@ -590,7 +584,7 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
return 0;
@@ -749,9 +743,9 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
spin_lock_init(&chip->lock);
- strcpy(card->driver, "Atmel AC97C");
- strcpy(card->shortname, "Atmel AC97C");
- sprintf(card->longname, "Atmel AC97 controller");
+ strscpy(card->driver, "Atmel AC97C");
+ strscpy(card->shortname, "Atmel AC97C");
+ strscpy(card->longname, "Atmel AC97 controller");
chip->card = card;
chip->pclk = pclk;
@@ -818,7 +812,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);
@@ -837,11 +830,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)
{
@@ -862,10 +851,10 @@ static void atmel_ac97c_remove(struct platform_device *pdev)
static struct platform_driver atmel_ac97c_driver = {
.probe = atmel_ac97c_probe,
- .remove_new = atmel_ac97c_remove,
+ .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/.kunitconfig b/sound/core/.kunitconfig
new file mode 100644
index 000000000000..440f974ba0b7
--- /dev/null
+++ b/sound/core/.kunitconfig
@@ -0,0 +1,5 @@
+CONFIG_KUNIT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_PCM=y
+CONFIG_SND_CORE_TEST=y
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 12990d9a4dff..48db44fa56fe 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -26,9 +26,42 @@ config SND_RAWMIDI
tristate
select SND_SEQ_DEVICE if SND_SEQUENCER != n
+config SND_UMP
+ tristate
+ select SND_RAWMIDI
+
+config SND_UMP_LEGACY_RAWMIDI
+ bool "Legacy raw MIDI support for UMP streams"
+ depends on SND_UMP
+ help
+ This option enables the legacy raw MIDI support for UMP streams.
+ When this option is set, an additional rawmidi device for the
+ legacy MIDI 1.0 byte streams is created for each UMP Endpoint.
+ The device contains 16 substreams corresponding to UMP groups.
+
+config SND_CORE_TEST
+ tristate "Sound core KUnit test"
+ depends on KUNIT
+ select SND_PCM
+ default KUNIT_ALL_TESTS
+ help
+ This options enables the sound core functions KUnit test.
+
+ KUnit tests run during boot and output the results to the debug
+ log in TAP format (https://testanything.org/). Only useful for
+ kernel devs running KUnit test harness and are not for inclusion
+ into a production build.
+
+ For more information on KUnit and unit tests in general, refer
+ to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+
config SND_COMPRESS_OFFLOAD
tristate
+config SND_COMPRESS_ACCEL
+ bool
+
config SND_JACK
bool
@@ -145,15 +178,6 @@ config SND_VERBOSE_PROCFS
useful information to developers when a problem occurs). On the
other side, it makes the ALSA subsystem larger.
-config SND_VERBOSE_PRINTK
- bool "Verbose printk"
- help
- Say Y here to enable verbose log messages. These messages
- will help to identify source file and position containing
- printed messages.
-
- You don't need this unless you're debugging ALSA.
-
config SND_CTL_FAST_LOOKUP
bool "Fast lookup of control elements" if EXPERT
default y
@@ -221,6 +245,16 @@ config SND_JACK_INJECTION_DEBUG
Say Y if you are debugging via jack injection interface.
If unsure select "N".
+config SND_UTIMER
+ bool "Enable support for userspace-controlled virtual timers"
+ depends on SND_TIMER
+ help
+ Say Y to enable the support of userspace-controlled timers. These
+ timers are purely virtual, and they are supposed to be triggered
+ from userspace. They could be quite useful when synchronizing the
+ sound timing with userspace applications (for instance, when sending
+ data through snd-aloop).
+
config SND_VMASTER
bool
@@ -232,6 +266,5 @@ config SND_CTL_LED
tristate
select NEW_LEDS if SND_CTL_LED
select LEDS_TRIGGERS if SND_CTL_LED
- select LEDS_TRIGGER_AUDIO if SND_CTL_LED
source "sound/core/seq/Kconfig"
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 2762f03d9b7b..31a0623cc89d 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -24,17 +24,18 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
CFLAGS_pcm_lib.o := -I$(src)
CFLAGS_pcm_native.o := -I$(src)
-snd-pcm-dmaengine-objs := pcm_dmaengine.o
+snd-pcm-dmaengine-y := pcm_dmaengine.o
-snd-ctl-led-objs := control_led.o
-snd-rawmidi-objs := rawmidi.o
-snd-timer-objs := timer.o
-snd-hrtimer-objs := hrtimer.o
-snd-rtctimer-objs := rtctimer.o
-snd-hwdep-objs := hwdep.o
-snd-seq-device-objs := seq_device.o
+snd-ctl-led-y := control_led.o
+snd-rawmidi-y := rawmidi.o
+snd-ump-y := ump.o
+snd-ump-$(CONFIG_SND_UMP_LEGACY_RAWMIDI) += ump_convert.o
+snd-timer-y := timer.o
+snd-hrtimer-y := hrtimer.o
+snd-hwdep-y := hwdep.o
+snd-seq-device-y := seq_device.o
-snd-compress-objs := compress_offload.o
+snd-compress-y := compress_offload.o
obj-$(CONFIG_SND) += snd.o
obj-$(CONFIG_SND_CTL_LED) += snd-ctl-led.o
@@ -45,6 +46,9 @@ obj-$(CONFIG_SND_PCM) += snd-pcm.o
obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o
obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
+obj-$(CONFIG_SND_UMP) += snd-ump.o
+
+obj-$(CONFIG_SND_CORE_TEST) += sound_kunit.o
obj-$(CONFIG_SND_OSSEMUL) += oss/
obj-$(CONFIG_SND_SEQUENCER) += seq/
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 243acad89fd3..da514fef45bc 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -24,6 +24,7 @@
#include <linux/types.h>
#include <linux/uio.h>
#include <linux/uaccess.h>
+#include <linux/dma-buf.h>
#include <linux/module.h>
#include <linux/compat.h>
#include <sound/core.h>
@@ -54,6 +55,12 @@ struct snd_compr_file {
static void error_delayed_work(struct work_struct *work);
+#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
+static void snd_compr_task_free_all(struct snd_compr_stream *stream);
+#else
+static inline void snd_compr_task_free_all(struct snd_compr_stream *stream) { }
+#endif
+
/*
* a note on stream states used:
* we use following states in the compressed core
@@ -85,6 +92,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
dirn = SND_COMPRESS_PLAYBACK;
else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
dirn = SND_COMPRESS_CAPTURE;
+ else if ((f->f_flags & O_ACCMODE) == O_RDWR)
+ dirn = SND_COMPRESS_ACCEL;
else
return -EINVAL;
@@ -125,11 +134,13 @@ static int snd_compr_open(struct inode *inode, struct file *f)
}
runtime->state = SNDRV_PCM_STATE_OPEN;
init_waitqueue_head(&runtime->sleep);
+#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
+ INIT_LIST_HEAD(&runtime->tasks);
+#endif
data->stream.runtime = runtime;
f->private_data = (void *)data;
- mutex_lock(&compr->lock);
- ret = compr->ops->open(&data->stream);
- mutex_unlock(&compr->lock);
+ scoped_guard(mutex, &compr->lock)
+ ret = compr->ops->open(&data->stream);
if (ret) {
kfree(runtime);
kfree(data);
@@ -155,6 +166,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
break;
}
+ snd_compr_task_free_all(&data->stream);
+
data->stream.ops->free(&data->stream);
if (!data->stream.runtime->dma_buffer_p)
kfree(data->stream.runtime->buffer);
@@ -163,14 +176,25 @@ static int snd_compr_free(struct inode *inode, struct file *f)
return 0;
}
+static void
+snd_compr_tstamp32_from_64(struct snd_compr_tstamp *tstamp32,
+ const struct snd_compr_tstamp64 *tstamp64)
+{
+ tstamp32->byte_offset = tstamp64->byte_offset;
+ tstamp32->copied_total = (u32)tstamp64->copied_total;
+ tstamp32->pcm_frames = (u32)tstamp64->pcm_frames;
+ tstamp32->pcm_io_frames = (u32)tstamp64->pcm_io_frames;
+ tstamp32->sampling_rate = tstamp64->sampling_rate;
+}
+
static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
if (!stream->ops->pointer)
return -ENOTSUPP;
stream->ops->pointer(stream, tstamp);
- pr_debug("dsp consumed till %d total %d bytes\n",
- tstamp->byte_offset, tstamp->copied_total);
+ pr_debug("dsp consumed till %u total %llu bytes\n", tstamp->byte_offset,
+ tstamp->copied_total);
if (stream->direction == SND_COMPRESS_PLAYBACK)
stream->runtime->total_bytes_transferred = tstamp->copied_total;
else
@@ -179,7 +203,7 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
}
static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
- struct snd_compr_avail *avail)
+ struct snd_compr_avail64 *avail)
{
memset(avail, 0, sizeof(*avail));
snd_compr_update_tstamp(stream, &avail->tstamp);
@@ -191,9 +215,9 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
pr_debug("detected init and someone forgot to do a write\n");
return stream->runtime->buffer_size;
}
- pr_debug("app wrote %lld, DSP consumed %lld\n",
- stream->runtime->total_bytes_available,
- stream->runtime->total_bytes_transferred);
+ pr_debug("app wrote %llu, DSP consumed %llu\n",
+ stream->runtime->total_bytes_available,
+ stream->runtime->total_bytes_transferred);
if (stream->runtime->total_bytes_available ==
stream->runtime->total_bytes_transferred) {
if (stream->direction == SND_COMPRESS_PLAYBACK) {
@@ -210,25 +234,43 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
if (stream->direction == SND_COMPRESS_PLAYBACK)
avail->avail = stream->runtime->buffer_size - avail->avail;
- pr_debug("ret avail as %lld\n", avail->avail);
+ pr_debug("ret avail as %zu\n", (size_t)avail->avail);
return avail->avail;
}
static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
{
- struct snd_compr_avail avail;
+ struct snd_compr_avail64 avail;
return snd_compr_calc_avail(stream, &avail);
}
-static int
-snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
+static void snd_compr_avail32_from_64(struct snd_compr_avail *avail32,
+ const struct snd_compr_avail64 *avail64)
{
- struct snd_compr_avail ioctl_avail;
+ avail32->avail = avail64->avail;
+ snd_compr_tstamp32_from_64(&avail32->tstamp, &avail64->tstamp);
+}
+
+static int snd_compr_ioctl_avail(struct snd_compr_stream *stream,
+ unsigned long arg, bool is_32bit)
+{
+ struct snd_compr_avail64 ioctl_avail64;
+ struct snd_compr_avail ioctl_avail32;
size_t avail;
+ const void *copy_from = &ioctl_avail64;
+ size_t copy_size = sizeof(ioctl_avail64);
- avail = snd_compr_calc_avail(stream, &ioctl_avail);
- ioctl_avail.avail = avail;
+ if (stream->direction == SND_COMPRESS_ACCEL)
+ return -EBADFD;
+
+ avail = snd_compr_calc_avail(stream, &ioctl_avail64);
+ ioctl_avail64.avail = avail;
+ if (is_32bit) {
+ snd_compr_avail32_from_64(&ioctl_avail32, &ioctl_avail64);
+ copy_from = &ioctl_avail32;
+ copy_size = sizeof(ioctl_avail32);
+ }
switch (stream->runtime->state) {
case SNDRV_PCM_STATE_OPEN:
@@ -239,8 +281,7 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
break;
}
- if (copy_to_user((__u64 __user *)arg,
- &ioctl_avail, sizeof(ioctl_avail)))
+ if (copy_to_user((__u64 __user *)arg, copy_from, copy_size))
return -EFAULT;
return 0;
}
@@ -258,8 +299,7 @@ static int snd_compr_write_data(struct snd_compr_stream *stream,
(app_pointer * runtime->buffer_size);
dstn = runtime->buffer + app_pointer;
- pr_debug("copying %ld at %lld\n",
- (unsigned long)count, app_pointer);
+ pr_debug("copying %lu at %llu\n", (unsigned long)count, app_pointer);
if (count < runtime->buffer_size - app_pointer) {
if (copy_from_user(dstn, buf, count))
return -EFAULT;
@@ -288,20 +328,21 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
return -EFAULT;
stream = &data->stream;
- mutex_lock(&stream->device->lock);
- /* write is allowed when stream is running or has been steup */
+ if (stream->direction == SND_COMPRESS_ACCEL)
+ return -EBADFD;
+ guard(mutex)(&stream->device->lock);
+ /* write is allowed when stream is running or has been setup */
switch (stream->runtime->state) {
case SNDRV_PCM_STATE_SETUP:
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_RUNNING:
break;
default:
- mutex_unlock(&stream->device->lock);
return -EBADFD;
}
avail = snd_compr_get_avail(stream);
- pr_debug("avail returned %ld\n", (unsigned long)avail);
+ pr_debug("avail returned %lu\n", (unsigned long)avail);
/* calculate how much we can write to buffer */
if (avail > count)
avail = count;
@@ -322,7 +363,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf,
pr_debug("stream prepared, Houston we are good to go\n");
}
- mutex_unlock(&stream->device->lock);
return retval;
}
@@ -339,7 +379,9 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
return -EFAULT;
stream = &data->stream;
- mutex_lock(&stream->device->lock);
+ if (stream->direction == SND_COMPRESS_ACCEL)
+ return -EBADFD;
+ guard(mutex)(&stream->device->lock);
/* read is allowed when stream is running, paused, draining and setup
* (yes setup is state which we transition to after stop, so if user
@@ -350,30 +392,24 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_SUSPENDED:
case SNDRV_PCM_STATE_DISCONNECTED:
- retval = -EBADFD;
- goto out;
+ return -EBADFD;
case SNDRV_PCM_STATE_XRUN:
- retval = -EPIPE;
- goto out;
+ return -EPIPE;
}
avail = snd_compr_get_avail(stream);
- pr_debug("avail returned %ld\n", (unsigned long)avail);
+ pr_debug("avail returned %lu\n", (unsigned long)avail);
/* calculate how much we can read from buffer */
if (avail > count)
avail = count;
- if (stream->ops->copy) {
+ if (stream->ops->copy)
retval = stream->ops->copy(stream, buf, avail);
- } else {
- retval = -ENXIO;
- goto out;
- }
+ else
+ return -ENXIO;
if (retval > 0)
stream->runtime->total_bytes_transferred += retval;
-out:
- mutex_unlock(&stream->device->lock);
return retval;
}
@@ -394,6 +430,7 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
{
struct snd_compr_file *data = f->private_data;
struct snd_compr_stream *stream;
+ struct snd_compr_runtime *runtime;
size_t avail;
__poll_t retval = 0;
@@ -401,43 +438,55 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait)
return EPOLLERR;
stream = &data->stream;
+ runtime = stream->runtime;
- mutex_lock(&stream->device->lock);
+ guard(mutex)(&stream->device->lock);
- switch (stream->runtime->state) {
+ switch (runtime->state) {
case SNDRV_PCM_STATE_OPEN:
case SNDRV_PCM_STATE_XRUN:
- retval = snd_compr_get_poll(stream) | EPOLLERR;
- goto out;
+ return snd_compr_get_poll(stream) | EPOLLERR;
default:
break;
}
- poll_wait(f, &stream->runtime->sleep, wait);
+ poll_wait(f, &runtime->sleep, wait);
+
+#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
+ if (stream->direction == SND_COMPRESS_ACCEL) {
+ struct snd_compr_task_runtime *task;
+ if (runtime->fragments > runtime->active_tasks)
+ retval |= EPOLLOUT | EPOLLWRNORM;
+ task = list_first_entry_or_null(&runtime->tasks,
+ struct snd_compr_task_runtime,
+ list);
+ if (task && task->state == SND_COMPRESS_TASK_STATE_FINISHED)
+ retval |= EPOLLIN | EPOLLRDNORM;
+ return retval;
+ }
+#endif
avail = snd_compr_get_avail(stream);
- pr_debug("avail is %ld\n", (unsigned long)avail);
+ pr_debug("avail is %lu\n", (unsigned long)avail);
/* check if we have at least one fragment to fill */
- switch (stream->runtime->state) {
+ switch (runtime->state) {
case SNDRV_PCM_STATE_DRAINING:
/* stream has been woken up after drain is complete
* draining done so set stream state to stopped
*/
retval = snd_compr_get_poll(stream);
- stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ runtime->state = SNDRV_PCM_STATE_SETUP;
break;
case SNDRV_PCM_STATE_RUNNING:
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_PAUSED:
- if (avail >= stream->runtime->fragment_size)
+ if (avail >= runtime->fragment_size)
retval = snd_compr_get_poll(stream);
break;
default:
- retval = snd_compr_get_poll(stream) | EPOLLERR;
- break;
+ return snd_compr_get_poll(stream) | EPOLLERR;
}
-out:
- mutex_unlock(&stream->device->lock);
+
return retval;
}
@@ -465,7 +514,7 @@ static int
snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
{
int retval;
- struct snd_compr_codec_caps *caps;
+ struct snd_compr_codec_caps *caps __free(kfree) = NULL;
if (!stream->ops->get_codec_caps)
return -ENXIO;
@@ -476,12 +525,9 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
retval = stream->ops->get_codec_caps(stream, caps);
if (retval)
- goto out;
+ return retval;
if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
- retval = -EFAULT;
-
-out:
- kfree(caps);
+ return -EFAULT;
return retval;
}
#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
@@ -536,6 +582,9 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
unsigned int buffer_size;
void *buffer = NULL;
+ if (stream->direction == SND_COMPRESS_ACCEL)
+ goto params;
+
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
if (stream->ops->copy) {
buffer = NULL;
@@ -546,7 +595,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
if (stream->runtime->dma_buffer_p) {
if (buffer_size > stream->runtime->dma_buffer_p->bytes)
- dev_err(&stream->device->dev,
+ dev_err(stream->device->dev,
"Not enough DMA buffer");
else
buffer = stream->runtime->dma_buffer_p->area;
@@ -558,18 +607,30 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
if (!buffer)
return -ENOMEM;
}
- stream->runtime->fragment_size = params->buffer.fragment_size;
- stream->runtime->fragments = params->buffer.fragments;
+
stream->runtime->buffer = buffer;
stream->runtime->buffer_size = buffer_size;
+params:
+ stream->runtime->fragment_size = params->buffer.fragment_size;
+ stream->runtime->fragments = params->buffer.fragments;
return 0;
}
-static int snd_compress_check_input(struct snd_compr_params *params)
+static int
+snd_compress_check_input(struct snd_compr_stream *stream, struct snd_compr_params *params)
{
+ u32 max_fragments;
+
/* first let's check the buffer parameter's */
- if (params->buffer.fragment_size == 0 ||
- params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||
+ if (params->buffer.fragment_size == 0)
+ return -EINVAL;
+
+ if (stream->direction == SND_COMPRESS_ACCEL)
+ max_fragments = 64; /* safe value */
+ else
+ max_fragments = U32_MAX / params->buffer.fragment_size;
+
+ if (params->buffer.fragments > max_fragments ||
params->buffer.fragments == 0)
return -EINVAL;
@@ -586,10 +647,10 @@ static int snd_compress_check_input(struct snd_compr_params *params)
static int
snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
{
- struct snd_compr_params *params;
+ struct snd_compr_params *params __free(kfree) = NULL;
int retval;
- if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+ if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
/*
* we should allow parameter change only when stream has been
* opened not in other cases
@@ -598,19 +659,20 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
if (IS_ERR(params))
return PTR_ERR(params);
- retval = snd_compress_check_input(params);
+ retval = snd_compress_check_input(stream, params);
if (retval)
- goto out;
+ return retval;
retval = snd_compr_allocate_buffer(stream, params);
- if (retval) {
- retval = -ENOMEM;
- goto out;
- }
+ if (retval)
+ return -ENOMEM;
retval = stream->ops->set_params(stream, params);
if (retval)
- goto out;
+ return retval;
+
+ if (stream->next_track)
+ return retval;
stream->metadata_set = false;
stream->next_track = false;
@@ -619,15 +681,13 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
} else {
return -EPERM;
}
-out:
- kfree(params);
return retval;
}
static int
snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
{
- struct snd_codec *params;
+ struct snd_codec *params __free(kfree) = NULL;
int retval;
if (!stream->ops->get_params)
@@ -638,12 +698,9 @@ snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
return -ENOMEM;
retval = stream->ops->get_params(stream, params);
if (retval)
- goto out;
+ return retval;
if (copy_to_user((char __user *)arg, params, sizeof(*params)))
- retval = -EFAULT;
-
-out:
- kfree(params);
+ return -EFAULT;
return retval;
}
@@ -690,16 +747,26 @@ snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
return retval;
}
-static inline int
-snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
+static inline int snd_compr_tstamp(struct snd_compr_stream *stream,
+ unsigned long arg, bool is_32bit)
{
- struct snd_compr_tstamp tstamp = {0};
+ struct snd_compr_tstamp64 tstamp64 = { 0 };
+ struct snd_compr_tstamp tstamp32 = { 0 };
+ const void *copy_from = &tstamp64;
+ size_t copy_size = sizeof(tstamp64);
int ret;
- ret = snd_compr_update_tstamp(stream, &tstamp);
- if (ret == 0)
- ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
- &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
+ ret = snd_compr_update_tstamp(stream, &tstamp64);
+ if (ret == 0) {
+ if (is_32bit) {
+ snd_compr_tstamp32_from_64(&tstamp32, &tstamp64);
+ copy_from = &tstamp32;
+ copy_size = sizeof(tstamp32);
+ }
+ ret = copy_to_user((void __user *)arg, copy_from, copy_size) ?
+ -EFAULT :
+ 0;
+ }
return ret;
}
@@ -802,12 +869,10 @@ static void error_delayed_work(struct work_struct *work)
stream = container_of(work, struct snd_compr_stream, error_work.work);
- mutex_lock(&stream->device->lock);
+ guard(mutex)(&stream->device->lock);
stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
wake_up(&stream->runtime->sleep);
-
- mutex_unlock(&stream->device->lock);
}
/**
@@ -960,74 +1025,348 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
return snd_compress_wait_for_drain(stream);
}
+#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
+
+static struct snd_compr_task_runtime *
+snd_compr_find_task(struct snd_compr_stream *stream, __u64 seqno)
+{
+ struct snd_compr_task_runtime *task;
+
+ list_for_each_entry(task, &stream->runtime->tasks, list) {
+ if (task->seqno == seqno)
+ return task;
+ }
+ return NULL;
+}
+
+static void snd_compr_task_free(struct snd_compr_task_runtime *task)
+{
+ if (task->output)
+ dma_buf_put(task->output);
+ if (task->input)
+ dma_buf_put(task->input);
+ kfree(task);
+}
+
+static u64 snd_compr_seqno_next(struct snd_compr_stream *stream)
+{
+ u64 seqno = ++stream->runtime->task_seqno;
+ if (seqno == 0)
+ seqno = ++stream->runtime->task_seqno;
+ return seqno;
+}
+
+static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_task *utask)
+{
+ struct snd_compr_task_runtime *task;
+ int retval, fd_i, fd_o;
+
+ if (stream->runtime->total_tasks >= stream->runtime->fragments)
+ return -EBUSY;
+ if (utask->origin_seqno != 0 || utask->input_size != 0)
+ return -EINVAL;
+ task = kzalloc(sizeof(*task), GFP_KERNEL);
+ if (task == NULL)
+ return -ENOMEM;
+ task->seqno = utask->seqno = snd_compr_seqno_next(stream);
+ task->input_size = utask->input_size;
+ retval = stream->ops->task_create(stream, task);
+ if (retval < 0)
+ goto cleanup;
+ /* similar functionality as in dma_buf_fd(), but ensure that both
+ file descriptors are allocated before fd_install() */
+ if (!task->input || !task->input->file || !task->output || !task->output->file) {
+ retval = -EINVAL;
+ goto cleanup;
+ }
+ fd_i = get_unused_fd_flags(O_WRONLY|O_CLOEXEC);
+ if (fd_i < 0)
+ goto cleanup;
+ fd_o = get_unused_fd_flags(O_RDONLY|O_CLOEXEC);
+ if (fd_o < 0) {
+ put_unused_fd(fd_i);
+ goto cleanup;
+ }
+ /* keep dmabuf reference until freed with task free ioctl */
+ get_dma_buf(task->input);
+ get_dma_buf(task->output);
+ fd_install(fd_i, task->input->file);
+ fd_install(fd_o, task->output->file);
+ utask->input_fd = fd_i;
+ utask->output_fd = fd_o;
+ list_add_tail(&task->list, &stream->runtime->tasks);
+ stream->runtime->total_tasks++;
+ return 0;
+cleanup:
+ snd_compr_task_free(task);
+ return retval;
+}
+
+static int snd_compr_task_create(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_task *task __free(kfree) = NULL;
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+ task = memdup_user((void __user *)arg, sizeof(*task));
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ retval = snd_compr_task_new(stream, task);
+ if (retval >= 0)
+ if (copy_to_user((void __user *)arg, task, sizeof(*task)))
+ retval = -EFAULT;
+ return retval;
+}
+
+static int snd_compr_task_start_prepare(struct snd_compr_task_runtime *task,
+ struct snd_compr_task *utask)
+{
+ if (task == NULL)
+ return -EINVAL;
+ if (task->state >= SND_COMPRESS_TASK_STATE_FINISHED)
+ return -EBUSY;
+ if (utask->input_size > task->input->size)
+ return -EINVAL;
+ task->flags = utask->flags;
+ task->input_size = utask->input_size;
+ task->state = SND_COMPRESS_TASK_STATE_IDLE;
+ return 0;
+}
+
+static int snd_compr_task_start(struct snd_compr_stream *stream, struct snd_compr_task *utask)
+{
+ struct snd_compr_task_runtime *task;
+ int retval;
+
+ if (utask->origin_seqno > 0) {
+ task = snd_compr_find_task(stream, utask->origin_seqno);
+ retval = snd_compr_task_start_prepare(task, utask);
+ if (retval < 0)
+ return retval;
+ task->seqno = utask->seqno = snd_compr_seqno_next(stream);
+ utask->origin_seqno = 0;
+ list_move_tail(&task->list, &stream->runtime->tasks);
+ } else {
+ task = snd_compr_find_task(stream, utask->seqno);
+ if (task && task->state != SND_COMPRESS_TASK_STATE_IDLE)
+ return -EBUSY;
+ retval = snd_compr_task_start_prepare(task, utask);
+ if (retval < 0)
+ return retval;
+ }
+ retval = stream->ops->task_start(stream, task);
+ if (retval >= 0) {
+ task->state = SND_COMPRESS_TASK_STATE_ACTIVE;
+ stream->runtime->active_tasks++;
+ }
+ return retval;
+}
+
+static int snd_compr_task_start_ioctl(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_task *task __free(kfree) = NULL;
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+ task = memdup_user((void __user *)arg, sizeof(*task));
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ retval = snd_compr_task_start(stream, task);
+ if (retval >= 0)
+ if (copy_to_user((void __user *)arg, task, sizeof(*task)))
+ retval = -EFAULT;
+ return retval;
+}
+
+static void snd_compr_task_stop_one(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ if (task->state != SND_COMPRESS_TASK_STATE_ACTIVE)
+ return;
+ stream->ops->task_stop(stream, task);
+ if (!snd_BUG_ON(stream->runtime->active_tasks == 0))
+ stream->runtime->active_tasks--;
+ list_move_tail(&task->list, &stream->runtime->tasks);
+ task->state = SND_COMPRESS_TASK_STATE_IDLE;
+}
+
+static void snd_compr_task_free_one(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ snd_compr_task_stop_one(stream, task);
+ stream->ops->task_free(stream, task);
+ list_del(&task->list);
+ snd_compr_task_free(task);
+ stream->runtime->total_tasks--;
+}
+
+static void snd_compr_task_free_all(struct snd_compr_stream *stream)
+{
+ struct snd_compr_task_runtime *task, *temp;
+
+ list_for_each_entry_safe_reverse(task, temp, &stream->runtime->tasks, list)
+ snd_compr_task_free_one(stream, task);
+}
+
+typedef void (*snd_compr_seq_func_t)(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task);
+
+static int snd_compr_task_seq(struct snd_compr_stream *stream, unsigned long arg,
+ snd_compr_seq_func_t fcn)
+{
+ struct snd_compr_task_runtime *task, *temp;
+ __u64 seqno;
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+ retval = copy_from_user(&seqno, (__u64 __user *)arg, sizeof(seqno));
+ if (retval)
+ return -EFAULT;
+ retval = 0;
+ if (seqno == 0) {
+ list_for_each_entry_safe_reverse(task, temp, &stream->runtime->tasks, list)
+ fcn(stream, task);
+ } else {
+ task = snd_compr_find_task(stream, seqno);
+ if (task == NULL) {
+ retval = -EINVAL;
+ } else {
+ fcn(stream, task);
+ }
+ }
+ return retval;
+}
+
+static int snd_compr_task_status(struct snd_compr_stream *stream,
+ struct snd_compr_task_status *status)
+{
+ struct snd_compr_task_runtime *task;
+
+ task = snd_compr_find_task(stream, status->seqno);
+ if (task == NULL)
+ return -EINVAL;
+ status->input_size = task->input_size;
+ status->output_size = task->output_size;
+ status->state = task->state;
+ return 0;
+}
+
+static int snd_compr_task_status_ioctl(struct snd_compr_stream *stream, unsigned long arg)
+{
+ struct snd_compr_task_status *status __free(kfree) = NULL;
+ int retval;
+
+ if (stream->runtime->state != SNDRV_PCM_STATE_SETUP)
+ return -EPERM;
+ status = memdup_user((void __user *)arg, sizeof(*status));
+ if (IS_ERR(status))
+ return PTR_ERR(status);
+ retval = snd_compr_task_status(stream, status);
+ if (retval >= 0)
+ if (copy_to_user((void __user *)arg, status, sizeof(*status)))
+ retval = -EFAULT;
+ return retval;
+}
+
+/**
+ * snd_compr_task_finished: Notify that the task was finished
+ * @stream: pointer to stream
+ * @task: runtime task structure
+ *
+ * Set the finished task state and notify waiters.
+ */
+void snd_compr_task_finished(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ guard(mutex)(&stream->device->lock);
+ if (!snd_BUG_ON(stream->runtime->active_tasks == 0))
+ stream->runtime->active_tasks--;
+ task->state = SND_COMPRESS_TASK_STATE_FINISHED;
+ wake_up(&stream->runtime->sleep);
+}
+EXPORT_SYMBOL_GPL(snd_compr_task_finished);
+
+MODULE_IMPORT_NS("DMA_BUF");
+#endif /* CONFIG_SND_COMPRESS_ACCEL */
+
static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
struct snd_compr_file *data = f->private_data;
struct snd_compr_stream *stream;
- int retval = -ENOTTY;
if (snd_BUG_ON(!data))
return -EFAULT;
stream = &data->stream;
- mutex_lock(&stream->device->lock);
- switch (_IOC_NR(cmd)) {
- case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
- retval = put_user(SNDRV_COMPRESS_VERSION,
+ guard(mutex)(&stream->device->lock);
+ switch (cmd) {
+ case SNDRV_COMPRESS_IOCTL_VERSION:
+ return put_user(SNDRV_COMPRESS_VERSION,
(int __user *)arg) ? -EFAULT : 0;
- break;
- case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
- retval = snd_compr_get_caps(stream, arg);
- break;
+ case SNDRV_COMPRESS_GET_CAPS:
+ return snd_compr_get_caps(stream, arg);
#ifndef COMPR_CODEC_CAPS_OVERFLOW
- case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
- retval = snd_compr_get_codec_caps(stream, arg);
- break;
+ case SNDRV_COMPRESS_GET_CODEC_CAPS:
+ return snd_compr_get_codec_caps(stream, arg);
#endif
- case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
- retval = snd_compr_set_params(stream, arg);
- break;
- case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
- retval = snd_compr_get_params(stream, arg);
- break;
- case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
- retval = snd_compr_set_metadata(stream, arg);
- break;
- case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
- retval = snd_compr_get_metadata(stream, arg);
- break;
- case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
- retval = snd_compr_tstamp(stream, arg);
- break;
- case _IOC_NR(SNDRV_COMPRESS_AVAIL):
- retval = snd_compr_ioctl_avail(stream, arg);
- break;
- case _IOC_NR(SNDRV_COMPRESS_PAUSE):
- retval = snd_compr_pause(stream);
- break;
- case _IOC_NR(SNDRV_COMPRESS_RESUME):
- retval = snd_compr_resume(stream);
- break;
- case _IOC_NR(SNDRV_COMPRESS_START):
- retval = snd_compr_start(stream);
- break;
- case _IOC_NR(SNDRV_COMPRESS_STOP):
- retval = snd_compr_stop(stream);
- break;
- case _IOC_NR(SNDRV_COMPRESS_DRAIN):
- retval = snd_compr_drain(stream);
- break;
- case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
- retval = snd_compr_partial_drain(stream);
- break;
- case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
- retval = snd_compr_next_track(stream);
- break;
+ case SNDRV_COMPRESS_SET_PARAMS:
+ return snd_compr_set_params(stream, arg);
+ case SNDRV_COMPRESS_GET_PARAMS:
+ return snd_compr_get_params(stream, arg);
+ case SNDRV_COMPRESS_SET_METADATA:
+ return snd_compr_set_metadata(stream, arg);
+ case SNDRV_COMPRESS_GET_METADATA:
+ return snd_compr_get_metadata(stream, arg);
+ }
+ if (stream->direction == SND_COMPRESS_ACCEL) {
+#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
+ switch (cmd) {
+ case SNDRV_COMPRESS_TASK_CREATE:
+ return snd_compr_task_create(stream, arg);
+ case SNDRV_COMPRESS_TASK_FREE:
+ return snd_compr_task_seq(stream, arg, snd_compr_task_free_one);
+ case SNDRV_COMPRESS_TASK_START:
+ return snd_compr_task_start_ioctl(stream, arg);
+ case SNDRV_COMPRESS_TASK_STOP:
+ return snd_compr_task_seq(stream, arg, snd_compr_task_stop_one);
+ case SNDRV_COMPRESS_TASK_STATUS:
+ return snd_compr_task_status_ioctl(stream, arg);
+ }
+#endif
+ return -ENOTTY;
}
- mutex_unlock(&stream->device->lock);
- return retval;
+
+ switch (cmd) {
+ case SNDRV_COMPRESS_TSTAMP:
+ return snd_compr_tstamp(stream, arg, true);
+ case SNDRV_COMPRESS_TSTAMP64:
+ return snd_compr_tstamp(stream, arg, false);
+ case SNDRV_COMPRESS_AVAIL:
+ return snd_compr_ioctl_avail(stream, arg, true);
+ case SNDRV_COMPRESS_AVAIL64:
+ return snd_compr_ioctl_avail(stream, arg, false);
+ case SNDRV_COMPRESS_PAUSE:
+ return snd_compr_pause(stream);
+ case SNDRV_COMPRESS_RESUME:
+ return snd_compr_resume(stream);
+ case SNDRV_COMPRESS_START:
+ return snd_compr_start(stream);
+ case SNDRV_COMPRESS_STOP:
+ return snd_compr_stop(stream);
+ case SNDRV_COMPRESS_DRAIN:
+ return snd_compr_drain(stream);
+ case SNDRV_COMPRESS_PARTIAL_DRAIN:
+ return snd_compr_partial_drain(stream);
+ case SNDRV_COMPRESS_NEXT_TRACK:
+ return snd_compr_next_track(stream);
+ }
+
+ return -ENOTTY;
}
/* support of 32bit userspace on 64bit platforms */
@@ -1067,7 +1406,7 @@ static int snd_compress_dev_register(struct snd_device *device)
/* register compressed device */
ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS,
compr->card, compr->device,
- &snd_compr_file_ops, compr, &compr->dev);
+ &snd_compr_file_ops, compr, compr->dev);
if (ret < 0) {
pr_err("snd_register_device failed %d\n", ret);
return ret;
@@ -1081,7 +1420,7 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
struct snd_compr *compr;
compr = device->device_data;
- snd_unregister_device(&compr->dev);
+ snd_unregister_device(compr->dev);
return 0;
}
@@ -1155,7 +1494,7 @@ static int snd_compress_dev_free(struct snd_device *device)
compr = device->device_data;
snd_compress_proc_done(compr);
- put_device(&compr->dev);
+ put_device(compr->dev);
return 0;
}
@@ -1179,6 +1518,11 @@ int snd_compress_new(struct snd_card *card, int device,
};
int ret;
+#if !IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL)
+ if (snd_BUG_ON(dirn == SND_COMPRESS_ACCEL))
+ return -EINVAL;
+#endif
+
compr->card = card;
compr->device = device;
compr->direction = dirn;
@@ -1186,12 +1530,16 @@ int snd_compress_new(struct snd_card *card, int device,
snd_compress_set_id(compr, id);
- snd_device_initialize(&compr->dev, card);
- dev_set_name(&compr->dev, "comprC%iD%i", card->number, device);
+ ret = snd_device_alloc(&compr->dev, card);
+ if (ret)
+ return ret;
+ dev_set_name(compr->dev, "comprC%iD%i", card->number, device);
ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
if (ret == 0)
snd_compress_proc_init(compr);
+ else
+ put_device(compr->dev);
return ret;
}
diff --git a/sound/core/control.c b/sound/core/control.c
index 82aa1af1d1d8..9c3fd5113a61 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -39,9 +39,11 @@ static LIST_HEAD(snd_control_compat_ioctls);
#endif
static struct snd_ctl_layer_ops *snd_ctl_layer;
+static int snd_ctl_remove_locked(struct snd_card *card,
+ struct snd_kcontrol *kcontrol);
+
static int snd_ctl_open(struct inode *inode, struct file *file)
{
- unsigned long flags;
struct snd_card *card;
struct snd_ctl_file *ctl;
int i, err;
@@ -77,9 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
ctl->preferred_subdevice[i] = -1;
ctl->pid = get_pid(task_pid(current));
file->private_data = ctl;
- write_lock_irqsave(&card->ctl_files_rwlock, flags);
- list_add_tail(&ctl->list, &card->ctl_files);
- write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+ scoped_guard(write_lock_irqsave, &card->controls_rwlock)
+ list_add_tail(&ctl->list, &card->ctl_files);
snd_card_unref(card);
return 0;
@@ -95,21 +96,18 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
{
- unsigned long flags;
struct snd_kctl_event *cread;
- spin_lock_irqsave(&ctl->read_lock, flags);
+ guard(spinlock_irqsave)(&ctl->read_lock);
while (!list_empty(&ctl->events)) {
cread = snd_kctl_event(ctl->events.next);
list_del(&cread->list);
kfree(cread);
}
- spin_unlock_irqrestore(&ctl->read_lock, flags);
}
static int snd_ctl_release(struct inode *inode, struct file *file)
{
- unsigned long flags;
struct snd_card *card;
struct snd_ctl_file *ctl;
struct snd_kcontrol *control;
@@ -118,15 +116,17 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
ctl = file->private_data;
file->private_data = NULL;
card = ctl->card;
- write_lock_irqsave(&card->ctl_files_rwlock, flags);
- list_del(&ctl->list);
- write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
- down_write(&card->controls_rwsem);
- list_for_each_entry(control, &card->controls, list)
- for (idx = 0; idx < control->count; idx++)
- if (control->vd[idx].owner == ctl)
- control->vd[idx].owner = NULL;
- up_write(&card->controls_rwsem);
+
+ scoped_guard(write_lock_irqsave, &card->controls_rwlock)
+ list_del(&ctl->list);
+
+ scoped_guard(rwsem_write, &card->controls_rwsem) {
+ list_for_each_entry(control, &card->controls, list)
+ for (idx = 0; idx < control->count; idx++)
+ if (control->vd[idx].owner == ctl)
+ control->vd[idx].owner = NULL;
+ }
+
snd_fasync_free(ctl->fasync);
snd_ctl_empty_read_queue(ctl);
put_pid(ctl->pid);
@@ -149,7 +149,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{
- unsigned long flags;
struct snd_ctl_file *ctl;
struct snd_kctl_event *ev;
@@ -157,34 +156,34 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
return;
if (card->shutdown)
return;
- read_lock_irqsave(&card->ctl_files_rwlock, flags);
+
+ guard(read_lock_irqsave)(&card->controls_rwlock);
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
card->mixer_oss_change_count++;
#endif
list_for_each_entry(ctl, &card->ctl_files, list) {
if (!ctl->subscribed)
continue;
- spin_lock(&ctl->read_lock);
- list_for_each_entry(ev, &ctl->events, list) {
- if (ev->id.numid == id->numid) {
- ev->mask |= mask;
- goto _found;
+ scoped_guard(spinlock, &ctl->read_lock) {
+ list_for_each_entry(ev, &ctl->events, list) {
+ if (ev->id.numid == id->numid) {
+ ev->mask |= mask;
+ goto _found;
+ }
}
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (ev) {
+ ev->id = *id;
+ ev->mask = mask;
+ list_add_tail(&ev->list, &ctl->events);
+ } else {
+ dev_err(card->dev, "No memory available to allocate event\n");
+ }
+_found:
+ wake_up(&ctl->change_sleep);
}
- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
- if (ev) {
- ev->id = *id;
- ev->mask = mask;
- list_add_tail(&ev->list, &ctl->events);
- } else {
- dev_err(card->dev, "No memory available to allocate event\n");
- }
- _found:
- wake_up(&ctl->change_sleep);
- spin_unlock(&ctl->read_lock);
snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN);
}
- read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
}
EXPORT_SYMBOL(snd_ctl_notify);
@@ -207,10 +206,9 @@ void snd_ctl_notify_one(struct snd_card *card, unsigned int mask,
id.index += ioff;
id.numid += ioff;
snd_ctl_notify(card, mask, &id);
- down_read(&snd_ctl_layer_rwsem);
+ guard(rwsem_read)(&snd_ctl_layer_rwsem);
for (lops = snd_ctl_layer; lops; lops = lops->next)
lops->lnotify(card, mask, kctl, ioff);
- up_read(&snd_ctl_layer_rwsem);
}
EXPORT_SYMBOL(snd_ctl_notify_one);
@@ -239,11 +237,11 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
if (!*kctl)
return -ENOMEM;
+ (*kctl)->count = count;
for (idx = 0; idx < count; idx++) {
(*kctl)->vd[idx].access = access;
(*kctl)->vd[idx].owner = file;
}
- (*kctl)->count = count;
return 0;
}
@@ -466,6 +464,8 @@ static int __snd_ctl_add_replace(struct snd_card *card,
struct snd_kcontrol *old;
int err;
+ lockdep_assert_held_write(&card->controls_rwsem);
+
id = kcontrol->id;
if (id.index > UINT_MAX - kcontrol->count)
return -EINVAL;
@@ -483,7 +483,7 @@ static int __snd_ctl_add_replace(struct snd_card *card,
return -EBUSY;
}
- err = snd_ctl_remove(card, old);
+ err = snd_ctl_remove_locked(card, old);
if (err < 0)
return err;
}
@@ -491,10 +491,12 @@ static int __snd_ctl_add_replace(struct snd_card *card,
if (snd_ctl_find_hole(card, kcontrol->count) < 0)
return -ENOMEM;
- list_add_tail(&kcontrol->list, &card->controls);
- card->controls_count += kcontrol->count;
- kcontrol->id.numid = card->last_numid + 1;
- card->last_numid += kcontrol->count;
+ scoped_guard(write_lock_irq, &card->controls_rwlock) {
+ list_add_tail(&kcontrol->list, &card->controls);
+ card->controls_count += kcontrol->count;
+ kcontrol->id.numid = card->last_numid + 1;
+ card->last_numid += kcontrol->count;
+ }
add_hash_entries(card, kcontrol);
@@ -515,9 +517,9 @@ static int snd_ctl_add_replace(struct snd_card *card,
if (snd_BUG_ON(!card || !kcontrol->info))
goto error;
- down_write(&card->controls_rwsem);
- err = __snd_ctl_add_replace(card, kcontrol, mode);
- up_write(&card->controls_rwsem);
+ scoped_guard(rwsem_write, &card->controls_rwsem)
+ err = __snd_ctl_add_replace(card, kcontrol, mode);
+
if (err < 0)
goto error;
return 0;
@@ -575,34 +577,50 @@ static int __snd_ctl_remove(struct snd_card *card,
{
unsigned int idx;
+ lockdep_assert_held_write(&card->controls_rwsem);
+
if (snd_BUG_ON(!card || !kcontrol))
return -EINVAL;
- list_del(&kcontrol->list);
if (remove_hash)
remove_hash_entries(card, kcontrol);
- card->controls_count -= kcontrol->count;
+ scoped_guard(write_lock_irq, &card->controls_rwlock) {
+ list_del(&kcontrol->list);
+ card->controls_count -= kcontrol->count;
+ }
+
for (idx = 0; idx < kcontrol->count; idx++)
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx);
snd_ctl_free_one(kcontrol);
return 0;
}
+static inline int snd_ctl_remove_locked(struct snd_card *card,
+ struct snd_kcontrol *kcontrol)
+{
+ return __snd_ctl_remove(card, kcontrol, true);
+}
+
/**
* snd_ctl_remove - remove the control from the card and release it
* @card: the card instance
* @kcontrol: the control instance to remove
*
* Removes the control from the card and then releases the instance.
- * You don't need to call snd_ctl_free_one(). You must be in
- * the write lock - down_write(&card->controls_rwsem).
+ * You don't need to call snd_ctl_free_one().
+ * Passing NULL to @kcontrol argument is allowed as noop.
*
* Return: 0 if successful, or a negative error code on failure.
+ *
+ * Note that this function takes card->controls_rwsem lock internally.
*/
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
- return __snd_ctl_remove(card, kcontrol, true);
+ if (!kcontrol)
+ return 0;
+ guard(rwsem_write)(&card->controls_rwsem);
+ return snd_ctl_remove_locked(card, kcontrol);
}
EXPORT_SYMBOL(snd_ctl_remove);
@@ -619,17 +637,12 @@ EXPORT_SYMBOL(snd_ctl_remove);
int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
{
struct snd_kcontrol *kctl;
- int ret;
- down_write(&card->controls_rwsem);
+ guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, id);
- if (kctl == NULL) {
- up_write(&card->controls_rwsem);
+ if (kctl == NULL)
return -ENOENT;
- }
- ret = snd_ctl_remove(card, kctl);
- up_write(&card->controls_rwsem);
- return ret;
+ return snd_ctl_remove_locked(card, kctl);
}
EXPORT_SYMBOL(snd_ctl_remove_id);
@@ -648,27 +661,18 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
{
struct snd_card *card = file->card;
struct snd_kcontrol *kctl;
- int idx, ret;
+ int idx;
- down_write(&card->controls_rwsem);
+ guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, id);
- if (kctl == NULL) {
- ret = -ENOENT;
- goto error;
- }
- if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
- ret = -EINVAL;
- goto error;
- }
+ if (kctl == NULL)
+ return -ENOENT;
+ if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER))
+ return -EINVAL;
for (idx = 0; idx < kctl->count; idx++)
- if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
- ret = -EBUSY;
- goto error;
- }
- ret = snd_ctl_remove(card, kctl);
-error:
- up_write(&card->controls_rwsem);
- return ret;
+ if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file)
+ return -EBUSY;
+ return snd_ctl_remove_locked(card, kctl);
}
/**
@@ -730,25 +734,30 @@ EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
* Finds the control with the old id from the card, and replaces the
* id with the new one.
*
+ * The function tries to keep the already assigned numid while replacing
+ * the rest.
+ *
+ * Note that this function should be used only in the card initialization
+ * phase. Calling after the card instantiation may cause issues with
+ * user-space expecting persistent numids.
+ *
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
struct snd_ctl_elem_id *dst_id)
{
struct snd_kcontrol *kctl;
+ int saved_numid;
- down_write(&card->controls_rwsem);
+ guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, src_id);
- if (kctl == NULL) {
- up_write(&card->controls_rwsem);
+ if (kctl == NULL)
return -ENOENT;
- }
+ saved_numid = kctl->id.numid;
remove_hash_entries(card, kctl);
kctl->id = *dst_id;
- kctl->id.numid = card->last_numid + 1;
- card->last_numid += kctl->count;
+ kctl->id.numid = saved_numid;
add_hash_entries(card, kctl);
- up_write(&card->controls_rwsem);
return 0;
}
EXPORT_SYMBOL(snd_ctl_rename_id);
@@ -761,11 +770,12 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
*
* Renames the specified control on the card to the new name.
*
- * Make sure to take the control write lock - down_write(&card->controls_rwsem).
+ * Note that this function takes card->controls_rwsem lock internally.
*/
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
const char *name)
{
+ guard(rwsem_write)(&card->controls_rwsem);
remove_hash_entries(card, kctl);
if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0)
@@ -782,6 +792,7 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
{
struct snd_kcontrol *kctl;
+ guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
return kctl;
@@ -797,16 +808,16 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
*
* Finds the control instance with the given number-id from the card.
*
- * The caller must down card->controls_rwsem before calling this function
- * (if the race condition can happen).
- *
* Return: The pointer of the instance if found, or %NULL if not.
*
+ * Note that this function takes card->controls_rwlock lock internally.
*/
-struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
+struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
+ unsigned int numid)
{
if (snd_BUG_ON(!card || !numid))
return NULL;
+
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
return xa_load(&card->ctl_numids, numid);
#else
@@ -822,19 +833,18 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
*
* Finds the control instance with the given id from the card.
*
- * The caller must down card->controls_rwsem before calling this function
- * (if the race condition can happen).
- *
* Return: The pointer of the instance if found, or %NULL if not.
*
+ * Note that this function takes card->controls_rwlock lock internally.
*/
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
- struct snd_ctl_elem_id *id)
+ const struct snd_ctl_elem_id *id)
{
struct snd_kcontrol *kctl;
if (snd_BUG_ON(!card || !id))
return NULL;
+
if (id->numid != 0)
return snd_ctl_find_numid(card, id->numid);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
@@ -845,6 +855,7 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
return NULL; /* we can rely on only hash table */
#endif
/* no matching in hash table - try all as the last resort */
+ guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->controls, list)
if (elem_id_matches(kctl, id))
return kctl;
@@ -856,25 +867,22 @@ EXPORT_SYMBOL(snd_ctl_find_id);
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
unsigned int cmd, void __user *arg)
{
- struct snd_ctl_card_info *info;
+ struct snd_ctl_card_info *info __free(kfree) = NULL;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (! info)
return -ENOMEM;
- down_read(&snd_ioctl_rwsem);
- info->card = card->number;
- strscpy(info->id, card->id, sizeof(info->id));
- strscpy(info->driver, card->driver, sizeof(info->driver));
- strscpy(info->name, card->shortname, sizeof(info->name));
- strscpy(info->longname, card->longname, sizeof(info->longname));
- strscpy(info->mixername, card->mixername, sizeof(info->mixername));
- strscpy(info->components, card->components, sizeof(info->components));
- up_read(&snd_ioctl_rwsem);
- if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
- kfree(info);
+ scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+ info->card = card->number;
+ strscpy(info->id, card->id, sizeof(info->id));
+ strscpy(info->driver, card->driver, sizeof(info->driver));
+ strscpy(info->name, card->shortname, sizeof(info->name));
+ strscpy(info->longname, card->longname, sizeof(info->longname));
+ strscpy(info->mixername, card->mixername, sizeof(info->mixername));
+ strscpy(info->components, card->components, sizeof(info->components));
+ }
+ if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
return -EFAULT;
- }
- kfree(info);
return 0;
}
@@ -884,37 +892,31 @@ static int snd_ctl_elem_list(struct snd_card *card,
struct snd_kcontrol *kctl;
struct snd_ctl_elem_id id;
unsigned int offset, space, jidx;
- int err = 0;
offset = list->offset;
space = list->space;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
list->count = card->controls_count;
list->used = 0;
- if (space > 0) {
- list_for_each_entry(kctl, &card->controls, list) {
- if (offset >= kctl->count) {
- offset -= kctl->count;
- continue;
- }
- for (jidx = offset; jidx < kctl->count; jidx++) {
- snd_ctl_build_ioff(&id, kctl, jidx);
- if (copy_to_user(list->pids + list->used, &id,
- sizeof(id))) {
- err = -EFAULT;
- goto out;
- }
- list->used++;
- if (!--space)
- goto out;
- }
- offset = 0;
+ if (!space)
+ return 0;
+ list_for_each_entry(kctl, &card->controls, list) {
+ if (offset >= kctl->count) {
+ offset -= kctl->count;
+ continue;
+ }
+ for (jidx = offset; jidx < kctl->count; jidx++) {
+ snd_ctl_build_ioff(&id, kctl, jidx);
+ if (copy_to_user(list->pids + list->used, &id, sizeof(id)))
+ return -EFAULT;
+ list->used++;
+ if (!--space)
+ return 0;
}
+ offset = 0;
}
- out:
- up_read(&card->controls_rwsem);
- return err;
+ return 0;
}
static int snd_ctl_elem_list_user(struct snd_card *card,
@@ -1132,10 +1134,7 @@ static int __snd_ctl_elem_info(struct snd_card *card,
#ifdef CONFIG_SND_DEBUG
info->access = 0;
#endif
- result = snd_power_ref_and_wait(card);
- if (!result)
- result = kctl->info(kctl, info);
- snd_power_unref(card);
+ result = kctl->info(kctl, info);
if (result >= 0) {
snd_BUG_ON(info->access);
index_offset = snd_ctl_get_ioff(kctl, &info->id);
@@ -1162,27 +1161,28 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
{
struct snd_card *card = ctl->card;
struct snd_kcontrol *kctl;
- int result;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &info->id);
- if (kctl == NULL)
- result = -ENOENT;
- else
- result = __snd_ctl_elem_info(card, kctl, info, ctl);
- up_read(&card->controls_rwsem);
- return result;
+ if (!kctl)
+ return -ENOENT;
+ return __snd_ctl_elem_info(card, kctl, info, ctl);
}
static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info __user *_info)
{
+ struct snd_card *card = ctl->card;
struct snd_ctl_elem_info info;
int result;
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
+ result = snd_power_ref_and_wait(card);
+ if (result)
+ return result;
result = snd_ctl_elem_info(ctl, &info);
+ snd_power_unref(card);
if (result < 0)
return result;
/* drop internal access flags */
@@ -1203,19 +1203,15 @@ static int snd_ctl_elem_read(struct snd_card *card,
const u32 pattern = 0xdeadbeef;
int ret;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
- if (kctl == NULL) {
- ret = -ENOENT;
- goto unlock;
- }
+ if (!kctl)
+ return -ENOENT;
index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset];
- if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
- ret = -EPERM;
- goto unlock;
- }
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || !kctl->get)
+ return -EPERM;
snd_ctl_build_ioff(&control->id, kctl, index_offset);
@@ -1225,17 +1221,14 @@ static int snd_ctl_elem_read(struct snd_card *card,
info.id = control->id;
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
if (ret < 0)
- goto unlock;
+ return ret;
#endif
if (!snd_ctl_skip_validation(&info))
fill_remaining_elem_value(control, &info, pattern);
- ret = snd_power_ref_and_wait(card);
- if (!ret)
- ret = kctl->get(kctl, control);
- snd_power_unref(card);
+ ret = kctl->get(kctl, control);
if (ret < 0)
- goto unlock;
+ return ret;
if (!snd_ctl_skip_validation(&info) &&
sanity_check_elem_value(card, control, &info, pattern) < 0) {
dev_err(card->dev,
@@ -1243,32 +1236,31 @@ static int snd_ctl_elem_read(struct snd_card *card,
control->id.iface, control->id.device,
control->id.subdevice, control->id.name,
control->id.index);
- ret = -EINVAL;
- goto unlock;
+ return -EINVAL;
}
-unlock:
- up_read(&card->controls_rwsem);
- return ret;
+ return 0;
}
static int snd_ctl_elem_read_user(struct snd_card *card,
struct snd_ctl_elem_value __user *_control)
{
- struct snd_ctl_elem_value *control;
+ struct snd_ctl_elem_value *control __free(kfree) = NULL;
int result;
control = memdup_user(_control, sizeof(*control));
if (IS_ERR(control))
return PTR_ERR(control);
+ result = snd_power_ref_and_wait(card);
+ if (result)
+ return result;
result = snd_ctl_elem_read(card, control);
+ snd_power_unref(card);
if (result < 0)
- goto error;
+ return result;
if (copy_to_user(_control, control, sizeof(*control)))
- result = -EFAULT;
- error:
- kfree(control);
+ return -EFAULT;
return result;
}
@@ -1278,7 +1270,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
- int result;
+ int result = 0;
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
@@ -1296,9 +1288,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
}
snd_ctl_build_ioff(&control->id, kctl, index_offset);
- result = snd_power_ref_and_wait(card);
/* validate input values */
- if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) {
+ if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION)) {
struct snd_ctl_elem_info info;
memset(&info, 0, sizeof(info));
@@ -1310,7 +1301,6 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
}
if (!result)
result = kctl->put(kctl, control);
- snd_power_unref(card);
if (result < 0) {
up_write(&card->controls_rwsem);
return result;
@@ -1330,7 +1320,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
struct snd_ctl_elem_value __user *_control)
{
- struct snd_ctl_elem_value *control;
+ struct snd_ctl_elem_value *control __free(kfree) = NULL;
struct snd_card *card;
int result;
@@ -1339,14 +1329,16 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
return PTR_ERR(control);
card = file->card;
+ result = snd_power_ref_and_wait(card);
+ if (result < 0)
+ return result;
result = snd_ctl_elem_write(card, file, control);
+ snd_power_unref(card);
if (result < 0)
- goto error;
+ return result;
if (copy_to_user(_control, control, sizeof(*control)))
- result = -EFAULT;
- error:
- kfree(control);
+ return -EFAULT;
return result;
}
@@ -1357,25 +1349,18 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
struct snd_ctl_elem_id id;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
- int result;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
- down_write(&card->controls_rwsem);
+ guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &id);
- if (kctl == NULL) {
- result = -ENOENT;
- } else {
- vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
- if (vd->owner != NULL)
- result = -EBUSY;
- else {
- vd->owner = file;
- result = 0;
- }
- }
- up_write(&card->controls_rwsem);
- return result;
+ if (!kctl)
+ return -ENOENT;
+ vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+ if (vd->owner)
+ return -EBUSY;
+ vd->owner = file;
+ return 0;
}
static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
@@ -1385,27 +1370,20 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
struct snd_ctl_elem_id id;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
- int result;
if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
- down_write(&card->controls_rwsem);
+ guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &id);
- if (kctl == NULL) {
- result = -ENOENT;
- } else {
- vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
- if (vd->owner == NULL)
- result = -EINVAL;
- else if (vd->owner != file)
- result = -EPERM;
- else {
- vd->owner = NULL;
- result = 0;
- }
- }
- up_write(&card->controls_rwsem);
- return result;
+ if (!kctl)
+ return -ENOENT;
+ vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+ if (!vd->owner)
+ return -EINVAL;
+ if (vd->owner != file)
+ return -EPERM;
+ vd->owner = NULL;
+ return 0;
}
struct user_element {
@@ -1427,7 +1405,7 @@ static bool check_user_elem_overflow(struct snd_card *card, ssize_t add)
static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct user_element *ue = kcontrol->private_data;
+ struct user_element *ue = snd_kcontrol_chip(kcontrol);
unsigned int offset;
offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
@@ -1440,7 +1418,7 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct user_element *ue = kcontrol->private_data;
+ struct user_element *ue = snd_kcontrol_chip(kcontrol);
const char *names;
unsigned int item;
unsigned int offset;
@@ -1457,7 +1435,7 @@ static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
names = ue->priv_data;
for (; item > 0; --item)
names += strlen(names) + 1;
- strcpy(uinfo->value.enumerated.name, names);
+ strscpy(uinfo->value.enumerated.name, names);
return 0;
}
@@ -1465,7 +1443,7 @@ static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct user_element *ue = kcontrol->private_data;
+ struct user_element *ue = snd_kcontrol_chip(kcontrol);
unsigned int size = ue->elem_data_size;
char *src = ue->elem_data +
snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
@@ -1477,12 +1455,16 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- int change;
- struct user_element *ue = kcontrol->private_data;
+ int err, change;
+ struct user_element *ue = snd_kcontrol_chip(kcontrol);
unsigned int size = ue->elem_data_size;
char *dst = ue->elem_data +
snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
+ err = sanity_check_input_values(ue->card, ucontrol, &ue->info, false);
+ if (err < 0)
+ return err;
+
change = memcmp(&ucontrol->value, dst, size) != 0;
if (change)
memcpy(dst, &ucontrol->value, size);
@@ -1493,12 +1475,14 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
unsigned int size)
{
- struct user_element *ue = kctl->private_data;
+ struct user_element *ue = snd_kcontrol_chip(kctl);
unsigned int *container;
unsigned int mask = 0;
int i;
int change;
+ lockdep_assert_held_write(&ue->card->controls_rwsem);
+
if (size > 1024 * 128) /* sane value */
return -EINVAL;
@@ -1544,7 +1528,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
unsigned int size)
{
- struct user_element *ue = kctl->private_data;
+ struct user_element *ue = snd_kcontrol_chip(kctl);
if (ue->tlv_data_size == 0 || ue->tlv_data == NULL)
return -ENXIO;
@@ -1575,6 +1559,8 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue)
unsigned int i;
const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
+ lockdep_assert_held_write(&ue->card->controls_rwsem);
+
buf_len = ue->info.value.enumerated.names_length;
if (buf_len > 64 * 1024)
return -EINVAL;
@@ -1612,7 +1598,7 @@ static size_t compute_user_elem_size(size_t size, unsigned int count)
static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
{
- struct user_element *ue = kcontrol->private_data;
+ struct user_element *ue = snd_kcontrol_chip(kcontrol);
// decrement the allocation size.
ue->card->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count);
@@ -1655,6 +1641,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
count = info->owner;
if (count == 0)
count = 1;
+ if (count > MAX_CONTROL_COUNT)
+ return -EINVAL;
/* Arrange access permissions if needed. */
access = info->access;
@@ -1683,11 +1671,9 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
private_size = value_sizes[info->type] * info->count;
alloc_size = compute_user_elem_size(private_size, count);
- down_write(&card->controls_rwsem);
- if (check_user_elem_overflow(card, alloc_size)) {
- err = -ENOMEM;
- goto unlock;
- }
+ guard(rwsem_write)(&card->controls_rwsem);
+ if (check_user_elem_overflow(card, alloc_size))
+ return -ENOMEM;
/*
* Keep memory object for this userspace control. After passing this
@@ -1697,13 +1683,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
*/
err = snd_ctl_new(&kctl, count, access, file);
if (err < 0)
- goto unlock;
+ return err;
memcpy(&kctl->id, &info->id, sizeof(kctl->id));
ue = kzalloc(alloc_size, GFP_KERNEL);
if (!ue) {
kfree(kctl);
- err = -ENOMEM;
- goto unlock;
+ return -ENOMEM;
}
kctl->private_data = ue;
kctl->private_free = snd_ctl_elem_user_free;
@@ -1721,7 +1706,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
err = snd_ctl_elem_init_enum_names(ue);
if (err < 0) {
snd_ctl_free_one(kctl);
- goto unlock;
+ return err;
}
}
@@ -1741,7 +1726,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
if (err < 0) {
snd_ctl_free_one(kctl);
- goto unlock;
+ return err;
}
offset = snd_ctl_get_ioff(kctl, &info->id);
snd_ctl_build_ioff(&info->id, kctl, offset);
@@ -1752,9 +1737,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
* applications because the field originally means PID of a process
* which locks the element.
*/
- unlock:
- up_write(&card->controls_rwsem);
- return err;
+ return 0;
}
static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
@@ -1821,7 +1804,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
{SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
};
struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
- int i, ret;
+ int i;
/* Check support of the request for this element. */
for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
@@ -1839,11 +1822,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
vd->owner != NULL && vd->owner != file)
return -EPERM;
- ret = snd_power_ref_and_wait(file->card);
- if (!ret)
- ret = kctl->tlv.c(kctl, op_flag, size, buf);
- snd_power_unref(file->card);
- return ret;
+ return kctl->tlv.c(kctl, op_flag, size, buf);
}
static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
@@ -1879,6 +1858,8 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
struct snd_ctl_elem_id id;
struct snd_kcontrol_volatile *vd;
+ lockdep_assert_held(&file->card->controls_rwsem);
+
if (copy_from_user(&header, buf, sizeof(header)))
return -EFAULT;
@@ -1954,34 +1935,41 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
return snd_ctl_subscribe_events(ctl, ip);
case SNDRV_CTL_IOCTL_TLV_READ:
- down_read(&ctl->card->controls_rwsem);
- err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
- up_read(&ctl->card->controls_rwsem);
+ err = snd_power_ref_and_wait(card);
+ if (err < 0)
+ return err;
+ scoped_guard(rwsem_read, &card->controls_rwsem)
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
+ snd_power_unref(card);
return err;
case SNDRV_CTL_IOCTL_TLV_WRITE:
- down_write(&ctl->card->controls_rwsem);
- err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
- up_write(&ctl->card->controls_rwsem);
+ err = snd_power_ref_and_wait(card);
+ if (err < 0)
+ return err;
+ scoped_guard(rwsem_write, &card->controls_rwsem)
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
+ snd_power_unref(card);
return err;
case SNDRV_CTL_IOCTL_TLV_COMMAND:
- down_write(&ctl->card->controls_rwsem);
- err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
- up_write(&ctl->card->controls_rwsem);
+ err = snd_power_ref_and_wait(card);
+ if (err < 0)
+ return err;
+ scoped_guard(rwsem_write, &card->controls_rwsem)
+ err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
+ snd_power_unref(card);
return err;
case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
}
- down_read(&snd_ioctl_rwsem);
+
+ guard(rwsem_read)(&snd_ioctl_rwsem);
list_for_each_entry(p, &snd_control_ioctls, list) {
err = p->fioctl(card, ctl, cmd, arg);
- if (err != -ENOIOCTLCMD) {
- up_read(&snd_ioctl_rwsem);
+ if (err != -ENOIOCTLCMD)
return err;
- }
}
- up_read(&snd_ioctl_rwsem);
dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
@@ -2073,9 +2061,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
if (pn == NULL)
return -ENOMEM;
pn->fioctl = fcn;
- down_write(&snd_ioctl_rwsem);
+ guard(rwsem_write)(&snd_ioctl_rwsem);
list_add_tail(&pn->list, lists);
- up_write(&snd_ioctl_rwsem);
return 0;
}
@@ -2118,16 +2105,14 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
if (snd_BUG_ON(!fcn))
return -EINVAL;
- down_write(&snd_ioctl_rwsem);
+ guard(rwsem_write)(&snd_ioctl_rwsem);
list_for_each_entry(p, lists, list) {
if (p->fioctl == fcn) {
list_del(&p->list);
- up_write(&snd_ioctl_rwsem);
kfree(p);
return 0;
}
}
- up_write(&snd_ioctl_rwsem);
snd_BUG();
return -EINVAL;
}
@@ -2174,9 +2159,8 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
{
struct snd_ctl_file *kctl;
int subdevice = -1;
- unsigned long flags;
- read_lock_irqsave(&card->ctl_files_rwlock, flags);
+ guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == task_pid(current)) {
subdevice = kctl->preferred_subdevice[type];
@@ -2184,7 +2168,6 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
break;
}
}
- read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
return subdevice;
}
EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
@@ -2214,13 +2197,11 @@ int snd_ctl_request_layer(const char *module_name)
if (module_name == NULL)
return 0;
- down_read(&snd_ctl_layer_rwsem);
- for (lops = snd_ctl_layer; lops; lops = lops->next)
- if (strcmp(lops->module_name, module_name) == 0)
- break;
- up_read(&snd_ctl_layer_rwsem);
- if (lops)
- return 0;
+ scoped_guard(rwsem_read, &snd_ctl_layer_rwsem) {
+ for (lops = snd_ctl_layer; lops; lops = lops->next)
+ if (strcmp(lops->module_name, module_name) == 0)
+ return 0;
+ }
return request_module(module_name);
}
EXPORT_SYMBOL_GPL(snd_ctl_request_layer);
@@ -2237,16 +2218,15 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
struct snd_card *card;
int card_number;
- down_write(&snd_ctl_layer_rwsem);
- lops->next = snd_ctl_layer;
- snd_ctl_layer = lops;
- up_write(&snd_ctl_layer_rwsem);
+ scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) {
+ lops->next = snd_ctl_layer;
+ snd_ctl_layer = lops;
+ }
for (card_number = 0; card_number < SNDRV_CARDS; card_number++) {
card = snd_card_ref(card_number);
if (card) {
- down_read(&card->controls_rwsem);
- lops->lregister(card);
- up_read(&card->controls_rwsem);
+ scoped_guard(rwsem_read, &card->controls_rwsem)
+ lops->lregister(card);
snd_card_unref(card);
}
}
@@ -2265,7 +2245,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
{
struct snd_ctl_layer_ops *lops2, *prev_lops2;
- down_write(&snd_ctl_layer_rwsem);
+ guard(rwsem_write)(&snd_ctl_layer_rwsem);
for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) {
if (lops2 == lops) {
if (!prev_lops2)
@@ -2276,7 +2256,6 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
}
prev_lops2 = lops2;
}
- up_write(&snd_ctl_layer_rwsem);
}
EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
@@ -2290,32 +2269,35 @@ static const struct file_operations snd_ctl_f_ops =
.read = snd_ctl_read,
.open = snd_ctl_open,
.release = snd_ctl_release,
- .llseek = no_llseek,
.poll = snd_ctl_poll,
.unlocked_ioctl = snd_ctl_ioctl,
.compat_ioctl = snd_ctl_ioctl_compat,
.fasync = snd_ctl_fasync,
};
+/* call lops under rwsems; called from snd_ctl_dev_*() below() */
+#define call_snd_ctl_lops(_card, _op) \
+ do { \
+ struct snd_ctl_layer_ops *lops; \
+ guard(rwsem_read)(&(_card)->controls_rwsem); \
+ guard(rwsem_read)(&snd_ctl_layer_rwsem); \
+ for (lops = snd_ctl_layer; lops; lops = lops->next) \
+ lops->_op(_card); \
+ } while (0)
+
/*
* registration of the control device
*/
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data;
- struct snd_ctl_layer_ops *lops;
int err;
err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
- &snd_ctl_f_ops, card, &card->ctl_dev);
+ &snd_ctl_f_ops, card, card->ctl_dev);
if (err < 0)
return err;
- down_read(&card->controls_rwsem);
- down_read(&snd_ctl_layer_rwsem);
- for (lops = snd_ctl_layer; lops; lops = lops->next)
- lops->lregister(card);
- up_read(&snd_ctl_layer_rwsem);
- up_read(&card->controls_rwsem);
+ call_snd_ctl_lops(card, lregister);
return 0;
}
@@ -2326,24 +2308,16 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct snd_ctl_file *ctl;
- struct snd_ctl_layer_ops *lops;
- unsigned long flags;
- read_lock_irqsave(&card->ctl_files_rwlock, flags);
- list_for_each_entry(ctl, &card->ctl_files, list) {
- wake_up(&ctl->change_sleep);
- snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
+ scoped_guard(read_lock_irqsave, &card->controls_rwlock) {
+ list_for_each_entry(ctl, &card->ctl_files, list) {
+ wake_up(&ctl->change_sleep);
+ snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
+ }
}
- read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
- down_read(&card->controls_rwsem);
- down_read(&snd_ctl_layer_rwsem);
- for (lops = snd_ctl_layer; lops; lops = lops->next)
- lops->ldisconnect(card);
- up_read(&snd_ctl_layer_rwsem);
- up_read(&card->controls_rwsem);
-
- return snd_unregister_device(&card->ctl_dev);
+ call_snd_ctl_lops(card, ldisconnect);
+ return snd_unregister_device(card->ctl_dev);
}
/*
@@ -2354,18 +2328,18 @@ static int snd_ctl_dev_free(struct snd_device *device)
struct snd_card *card = device->device_data;
struct snd_kcontrol *control;
- down_write(&card->controls_rwsem);
- while (!list_empty(&card->controls)) {
- control = snd_kcontrol(card->controls.next);
- __snd_ctl_remove(card, control, false);
- }
+ scoped_guard(rwsem_write, &card->controls_rwsem) {
+ while (!list_empty(&card->controls)) {
+ control = snd_kcontrol(card->controls.next);
+ __snd_ctl_remove(card, control, false);
+ }
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
- xa_destroy(&card->ctl_numids);
- xa_destroy(&card->ctl_hash);
+ xa_destroy(&card->ctl_numids);
+ xa_destroy(&card->ctl_hash);
#endif
- up_write(&card->controls_rwsem);
- put_device(&card->ctl_dev);
+ }
+ put_device(card->ctl_dev);
return 0;
}
@@ -2387,12 +2361,14 @@ int snd_ctl_create(struct snd_card *card)
if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS))
return -ENXIO;
- snd_device_initialize(&card->ctl_dev, card);
- dev_set_name(&card->ctl_dev, "controlC%d", card->number);
+ err = snd_device_alloc(&card->ctl_dev, card);
+ if (err < 0)
+ return err;
+ dev_set_name(card->ctl_dev, "controlC%d", card->number);
err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
if (err < 0)
- put_device(&card->ctl_dev);
+ put_device(card->ctl_dev);
return err;
}
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index d8a86d1a99d6..6459809ed364 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -74,66 +74,66 @@ struct snd_ctl_elem_info32 {
unsigned char reserved[128];
} value;
unsigned char reserved[64];
-} __attribute__((packed));
+} __packed;
static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info32 __user *data32)
{
- struct snd_ctl_elem_info *data;
+ struct snd_card *card = ctl->card;
+ struct snd_ctl_elem_info *data __free(kfree) = NULL;
int err;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (! data)
return -ENOMEM;
- err = -EFAULT;
/* copy id */
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
- goto error;
+ return -EFAULT;
/* we need to copy the item index.
* hope this doesn't break anything..
*/
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
- goto error;
+ return -EFAULT;
+ err = snd_power_ref_and_wait(card);
+ if (err < 0)
+ return err;
err = snd_ctl_elem_info(ctl, data);
+ snd_power_unref(card);
if (err < 0)
- goto error;
+ return err;
/* restore info to 32bit */
- err = -EFAULT;
/* id, type, access, count */
if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
- goto error;
+ return -EFAULT;
if (put_user(data->owner, &data32->owner))
- goto error;
+ return -EFAULT;
switch (data->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
if (put_user(data->value.integer.min, &data32->value.integer.min) ||
put_user(data->value.integer.max, &data32->value.integer.max) ||
put_user(data->value.integer.step, &data32->value.integer.step))
- goto error;
+ return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
if (copy_to_user(&data32->value.integer64,
&data->value.integer64,
sizeof(data->value.integer64)))
- goto error;
+ return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
if (copy_to_user(&data32->value.enumerated,
&data->value.enumerated,
sizeof(data->value.enumerated)))
- goto error;
+ return -EFAULT;
break;
default:
break;
}
- err = 0;
- error:
- kfree(data);
- return err;
+ return 0;
}
/* read / write */
@@ -169,35 +169,26 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
int *countp)
{
struct snd_kcontrol *kctl;
- struct snd_ctl_elem_info *info;
+ struct snd_ctl_elem_info *info __free(kfree) = NULL;
int err;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, id);
- if (! kctl) {
- up_read(&card->controls_rwsem);
+ if (!kctl)
return -ENOENT;
- }
info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (info == NULL) {
- up_read(&card->controls_rwsem);
+ if (info == NULL)
return -ENOMEM;
- }
info->id = *id;
- err = snd_power_ref_and_wait(card);
- if (!err)
- err = kctl->info(kctl, info);
- snd_power_unref(card);
- up_read(&card->controls_rwsem);
+ err = kctl->info(kctl, info);
if (err >= 0) {
err = info->type;
*countp = info->count;
}
- kfree(info);
return err;
}
-static int get_elem_size(int type, int count)
+static int get_elem_size(snd_ctl_elem_type_t type, int count)
{
switch (type) {
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
@@ -234,8 +225,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
if (type < 0)
return type;
- if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -244,7 +235,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
data->value.integer.value[i] = val;
}
} else {
- size = get_elem_size(type, count);
+ size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
if (size < 0) {
dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
@@ -267,8 +258,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
struct snd_ctl_elem_value32 __user *data32 = userdata;
int i, size;
- if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -277,7 +268,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
return -EFAULT;
}
} else {
- size = get_elem_size(type, count);
+ size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
if (copy_to_user(valuep, data->value.bytes.data, size))
return -EFAULT;
}
@@ -286,10 +277,10 @@ static int copy_ctl_value_to_user(void __user *userdata,
return 0;
}
-static int ctl_elem_read_user(struct snd_card *card,
- void __user *userdata, void __user *valuep)
+static int __ctl_elem_read_user(struct snd_card *card,
+ void __user *userdata, void __user *valuep)
{
- struct snd_ctl_elem_value *data;
+ struct snd_ctl_elem_value *data __free(kfree) = NULL;
int err, type, count;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -299,21 +290,31 @@ static int ctl_elem_read_user(struct snd_card *card,
err = copy_ctl_value_from_user(card, data, userdata, valuep,
&type, &count);
if (err < 0)
- goto error;
+ return err;
err = snd_ctl_elem_read(card, data);
if (err < 0)
- goto error;
- err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
- error:
- kfree(data);
+ return err;
+ return copy_ctl_value_to_user(userdata, valuep, data, type, count);
+}
+
+static int ctl_elem_read_user(struct snd_card *card,
+ void __user *userdata, void __user *valuep)
+{
+ int err;
+
+ err = snd_power_ref_and_wait(card);
+ if (err < 0)
+ return err;
+ err = __ctl_elem_read_user(card, userdata, valuep);
+ snd_power_unref(card);
return err;
}
-static int ctl_elem_write_user(struct snd_ctl_file *file,
- void __user *userdata, void __user *valuep)
+static int __ctl_elem_write_user(struct snd_ctl_file *file,
+ void __user *userdata, void __user *valuep)
{
- struct snd_ctl_elem_value *data;
+ struct snd_ctl_elem_value *data __free(kfree) = NULL;
struct snd_card *card = file->card;
int err, type, count;
@@ -324,14 +325,25 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
err = copy_ctl_value_from_user(card, data, userdata, valuep,
&type, &count);
if (err < 0)
- goto error;
+ return err;
err = snd_ctl_elem_write(card, file, data);
if (err < 0)
- goto error;
- err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
- error:
- kfree(data);
+ return err;
+ return copy_ctl_value_to_user(userdata, valuep, data, type, count);
+}
+
+static int ctl_elem_write_user(struct snd_ctl_file *file,
+ void __user *userdata, void __user *valuep)
+{
+ struct snd_card *card = file->card;
+ int err;
+
+ err = snd_power_ref_and_wait(card);
+ if (err < 0)
+ return err;
+ err = __ctl_elem_write_user(file, userdata, valuep);
+ snd_power_unref(card);
return err;
}
@@ -366,49 +378,44 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
struct snd_ctl_elem_info32 __user *data32,
int replace)
{
- struct snd_ctl_elem_info *data;
- int err;
+ struct snd_ctl_elem_info *data __free(kfree) = NULL;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (! data)
return -ENOMEM;
- err = -EFAULT;
/* id, type, access, count */ \
if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
- goto error;
+ return -EFAULT;
if (get_user(data->owner, &data32->owner))
- goto error;
+ return -EFAULT;
switch (data->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
if (get_user(data->value.integer.min, &data32->value.integer.min) ||
get_user(data->value.integer.max, &data32->value.integer.max) ||
get_user(data->value.integer.step, &data32->value.integer.step))
- goto error;
+ return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
if (copy_from_user(&data->value.integer64,
&data32->value.integer64,
sizeof(data->value.integer64)))
- goto error;
+ return -EFAULT;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
if (copy_from_user(&data->value.enumerated,
&data32->value.enumerated,
sizeof(data->value.enumerated)))
- goto error;
+ return -EFAULT;
data->value.enumerated.names_ptr =
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
break;
default:
break;
}
- err = snd_ctl_elem_add(file, data, replace);
- error:
- kfree(data);
- return err;
+ return snd_ctl_elem_add(file, data, replace);
}
enum {
@@ -468,16 +475,13 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
#endif /* CONFIG_X86_X32_ABI */
}
- down_read(&snd_ioctl_rwsem);
+ guard(rwsem_read)(&snd_ioctl_rwsem);
list_for_each_entry(p, &snd_control_compat_ioctls, list) {
if (p->fioctl) {
err = p->fioctl(ctl->card, ctl, cmd, arg);
- if (err != -ENOIOCTLCMD) {
- up_read(&snd_ioctl_rwsem);
+ if (err != -ENOIOCTLCMD)
return err;
- }
}
}
- up_read(&snd_ioctl_rwsem);
return -ENOIOCTLCMD;
}
diff --git a/sound/core/control_led.c b/sound/core/control_led.c
index 3cadd40100f3..e33dfcf863cf 100644
--- a/sound/core/control_led.c
+++ b/sound/core/control_led.c
@@ -53,6 +53,7 @@ struct snd_ctl_led_ctl {
static DEFINE_MUTEX(snd_ctl_led_mutex);
static bool snd_ctl_led_card_valid[SNDRV_CARDS];
+static struct led_trigger *snd_ctl_ledtrig_audio[NUM_AUDIO_LEDS];
static struct snd_ctl_led snd_ctl_leds[MAX_LED] = {
{
.name = "speaker",
@@ -147,37 +148,38 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access,
return;
route = -1;
found = false;
- mutex_lock(&snd_ctl_led_mutex);
- /* the card may not be registered (active) at this point */
- if (card && !snd_ctl_led_card_valid[card->number]) {
- mutex_unlock(&snd_ctl_led_mutex);
- return;
- }
- list_for_each_entry(lctl, &led->controls, list) {
- if (lctl->kctl == kctl && lctl->index_offset == ioff)
- found = true;
- UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
- }
- if (!found && kctl && card) {
- lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
- if (lctl) {
- lctl->card = card;
- lctl->access = access;
- lctl->kctl = kctl;
- lctl->index_offset = ioff;
- list_add(&lctl->list, &led->controls);
+ scoped_guard(mutex, &snd_ctl_led_mutex) {
+ /* the card may not be registered (active) at this point */
+ if (card && !snd_ctl_led_card_valid[card->number])
+ return;
+ list_for_each_entry(lctl, &led->controls, list) {
+ if (lctl->kctl == kctl && lctl->index_offset == ioff)
+ found = true;
UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
}
+ if (!found && kctl && card) {
+ lctl = kzalloc(sizeof(*lctl), GFP_KERNEL);
+ if (lctl) {
+ lctl->card = card;
+ lctl->access = access;
+ lctl->kctl = kctl;
+ lctl->index_offset = ioff;
+ list_add(&lctl->list, &led->controls);
+ UPDATE_ROUTE(route, snd_ctl_led_get(lctl));
+ }
+ }
}
- mutex_unlock(&snd_ctl_led_mutex);
switch (led->mode) {
case MODE_OFF: route = 1; break;
case MODE_ON: route = 0; break;
case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break;
case MODE_FOLLOW_MUTE: /* noop */ break;
}
- if (route >= 0)
- ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON);
+ if (route >= 0) {
+ struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type];
+
+ led_trigger_event(trig, route ? LED_OFF : LED_ON);
+ }
}
static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff)
@@ -201,14 +203,13 @@ static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int i
struct snd_ctl_led_ctl *lctl;
unsigned int ret = 0;
- mutex_lock(&snd_ctl_led_mutex);
+ guard(mutex)(&snd_ctl_led_mutex);
lctl = snd_ctl_led_find(kctl, ioff);
if (lctl && (access == 0 || access != lctl->access)) {
ret = lctl->access;
list_del(&lctl->list);
kfree(lctl);
}
- mutex_unlock(&snd_ctl_led_mutex);
return ret;
}
@@ -239,44 +240,36 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask,
}
}
+DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T))
+
static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
unsigned int group, bool set)
{
- struct snd_card *card;
+ struct snd_card *card __free(snd_card_unref) = NULL;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
unsigned int ioff, access, new_access;
- int err = 0;
card = snd_card_ref(card_number);
- if (card) {
- down_write(&card->controls_rwsem);
- kctl = snd_ctl_find_id(card, id);
- if (kctl) {
- ioff = snd_ctl_get_ioff(kctl, id);
- vd = &kctl->vd[ioff];
- access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
- if (access != 0 && access != group_to_access(group)) {
- err = -EXDEV;
- goto unlock;
- }
- new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
- if (set)
- new_access |= group_to_access(group);
- if (new_access != vd->access) {
- vd->access = new_access;
- snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
- }
- } else {
- err = -ENOENT;
- }
-unlock:
- up_write(&card->controls_rwsem);
- snd_card_unref(card);
- } else {
- err = -ENXIO;
+ if (!card)
+ return -ENXIO;
+ guard(rwsem_write)(&card->controls_rwsem);
+ kctl = snd_ctl_find_id(card, id);
+ if (!kctl)
+ return -ENOENT;
+ ioff = snd_ctl_get_ioff(kctl, id);
+ vd = &kctl->vd[ioff];
+ access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK;
+ if (access != 0 && access != group_to_access(group))
+ return -EXDEV;
+ new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK;
+ if (set)
+ new_access |= group_to_access(group);
+ if (new_access != vd->access) {
+ vd->access = new_access;
+ snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff);
}
- return err;
+ return 0;
}
static void snd_ctl_led_refresh(void)
@@ -296,25 +289,22 @@ static void snd_ctl_led_ctl_destroy(struct snd_ctl_led_ctl *lctl)
static void snd_ctl_led_clean(struct snd_card *card)
{
unsigned int group;
+ struct snd_ctl_led_ctl *lctl, *_lctl;
struct snd_ctl_led *led;
- struct snd_ctl_led_ctl *lctl;
for (group = 0; group < MAX_LED; group++) {
led = &snd_ctl_leds[group];
-repeat:
- list_for_each_entry(lctl, &led->controls, list)
- if (!card || lctl->card == card) {
+ list_for_each_entry_safe(lctl, _lctl, &led->controls, list)
+ if (!card || lctl->card == card)
snd_ctl_led_ctl_destroy(lctl);
- goto repeat;
- }
}
}
static int snd_ctl_led_reset(int card_number, unsigned int group)
{
- struct snd_card *card;
+ struct snd_card *card __free(snd_card_unref) = NULL;
+ struct snd_ctl_led_ctl *lctl, *_lctl;
struct snd_ctl_led *led;
- struct snd_ctl_led_ctl *lctl;
struct snd_kcontrol_volatile *vd;
bool change = false;
@@ -322,26 +312,20 @@ static int snd_ctl_led_reset(int card_number, unsigned int group)
if (!card)
return -ENXIO;
- mutex_lock(&snd_ctl_led_mutex);
- if (!snd_ctl_led_card_valid[card_number]) {
- mutex_unlock(&snd_ctl_led_mutex);
- snd_card_unref(card);
- return -ENXIO;
+ scoped_guard(mutex, &snd_ctl_led_mutex) {
+ if (!snd_ctl_led_card_valid[card_number])
+ return -ENXIO;
+ led = &snd_ctl_leds[group];
+ list_for_each_entry_safe(lctl, _lctl, &led->controls, list)
+ if (lctl->card == card) {
+ vd = &lctl->kctl->vd[lctl->index_offset];
+ vd->access &= ~group_to_access(group);
+ snd_ctl_led_ctl_destroy(lctl);
+ change = true;
+ }
}
- led = &snd_ctl_leds[group];
-repeat:
- list_for_each_entry(lctl, &led->controls, list)
- if (lctl->card == card) {
- vd = &lctl->kctl->vd[lctl->index_offset];
- vd->access &= ~group_to_access(group);
- snd_ctl_led_ctl_destroy(lctl);
- change = true;
- goto repeat;
- }
- mutex_unlock(&snd_ctl_led_mutex);
if (change)
snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0);
- snd_card_unref(card);
return 0;
}
@@ -353,9 +337,8 @@ static void snd_ctl_led_register(struct snd_card *card)
if (snd_BUG_ON(card->number < 0 ||
card->number >= ARRAY_SIZE(snd_ctl_led_card_valid)))
return;
- mutex_lock(&snd_ctl_led_mutex);
- snd_ctl_led_card_valid[card->number] = true;
- mutex_unlock(&snd_ctl_led_mutex);
+ scoped_guard(mutex, &snd_ctl_led_mutex)
+ snd_ctl_led_card_valid[card->number] = true;
/* the register callback is already called with held card->controls_rwsem */
list_for_each_entry(kctl, &card->controls, list)
for (ioff = 0; ioff < kctl->count; ioff++)
@@ -367,10 +350,10 @@ static void snd_ctl_led_register(struct snd_card *card)
static void snd_ctl_led_disconnect(struct snd_card *card)
{
snd_ctl_led_sysfs_remove(card);
- mutex_lock(&snd_ctl_led_mutex);
- snd_ctl_led_card_valid[card->number] = false;
- snd_ctl_led_clean(card);
- mutex_unlock(&snd_ctl_led_mutex);
+ scoped_guard(mutex, &snd_ctl_led_mutex) {
+ snd_ctl_led_card_valid[card->number] = false;
+ snd_ctl_led_clean(card);
+ }
snd_ctl_led_refresh();
}
@@ -430,9 +413,8 @@ static ssize_t mode_store(struct device *dev,
else
return count;
- mutex_lock(&snd_ctl_led_mutex);
- led->mode = mode;
- mutex_unlock(&snd_ctl_led_mutex);
+ scoped_guard(mutex, &snd_ctl_led_mutex)
+ led->mode = mode;
snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0);
return count;
@@ -442,8 +424,9 @@ static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
+ struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type];
- return sysfs_emit(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
+ return sysfs_emit(buf, "%u\n", led_trigger_get_brightness(trig));
}
static DEVICE_ATTR_RW(mode);
@@ -615,15 +598,15 @@ static ssize_t list_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
- struct snd_card *card;
+ struct snd_card *card __free(snd_card_unref) = NULL;
struct snd_ctl_led_ctl *lctl;
size_t l = 0;
card = snd_card_ref(led_card->number);
if (!card)
return -ENXIO;
- down_read(&card->controls_rwsem);
- mutex_lock(&snd_ctl_led_mutex);
+ guard(rwsem_read)(&card->controls_rwsem);
+ guard(mutex)(&snd_ctl_led_mutex);
if (snd_ctl_led_card_valid[led_card->number]) {
list_for_each_entry(lctl, &led_card->led->controls, list) {
if (lctl->card != card)
@@ -634,9 +617,6 @@ static ssize_t list_show(struct device *dev,
lctl->kctl->id.numid + lctl->index_offset);
}
}
- mutex_unlock(&snd_ctl_led_mutex);
- up_read(&card->controls_rwsem);
- snd_card_unref(card);
return l;
}
@@ -688,16 +668,22 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card)
goto cerr;
led->cards[card->number] = led_card;
snprintf(link_name, sizeof(link_name), "led-%s", led->name);
- WARN(sysfs_create_link(&card->ctl_dev.kobj, &led_card->dev.kobj, link_name),
- "can't create symlink to controlC%i device\n", card->number);
- WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"),
- "can't create symlink to card%i\n", card->number);
+ if (sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj,
+ link_name))
+ dev_err(card->dev,
+ "%s: can't create symlink to controlC%i device\n",
+ __func__, card->number);
+ if (sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj,
+ "card"))
+ dev_err(card->dev,
+ "%s: can't create symlink to card%i\n",
+ __func__, card->number);
continue;
cerr:
put_device(&led_card->dev);
cerr2:
- printk(KERN_ERR "snd_ctl_led: unable to add card%d", card->number);
+ dev_err(card->dev, "snd_ctl_led: unable to add card%d", card->number);
}
}
@@ -714,7 +700,7 @@ static void snd_ctl_led_sysfs_remove(struct snd_card *card)
if (!led_card)
continue;
snprintf(link_name, sizeof(link_name), "led-%s", led->name);
- sysfs_remove_link(&card->ctl_dev.kobj, link_name);
+ sysfs_remove_link(&card->ctl_dev->kobj, link_name);
sysfs_remove_link(&led_card->dev.kobj, "card");
device_unregister(&led_card->dev);
led->cards[card->number] = NULL;
@@ -736,8 +722,11 @@ static int __init snd_ctl_led_init(void)
struct snd_ctl_led *led;
unsigned int group;
+ led_trigger_register_simple("audio-mute", &snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]);
+ led_trigger_register_simple("audio-micmute", &snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]);
+
device_initialize(&snd_ctl_led_dev);
- snd_ctl_led_dev.class = sound_class;
+ snd_ctl_led_dev.class = &sound_class;
snd_ctl_led_dev.release = snd_ctl_led_dev_release;
dev_set_name(&snd_ctl_led_dev, "ctl-led");
if (device_add(&snd_ctl_led_dev)) {
@@ -788,7 +777,13 @@ static void __exit snd_ctl_led_exit(void)
}
device_unregister(&snd_ctl_led_dev);
snd_ctl_led_clean(NULL);
+
+ led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]);
+ led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]);
}
module_init(snd_ctl_led_init)
module_exit(snd_ctl_led_exit)
+
+MODULE_ALIAS("ledtrig:audio-mute");
+MODULE_ALIAS("ledtrig:audio-micmute");
diff --git a/sound/core/device.c b/sound/core/device.c
index b57d80a17052..cdc5af526739 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -237,26 +237,3 @@ void snd_device_free_all(struct snd_card *card)
list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
__snd_device_free(dev);
}
-
-/**
- * snd_device_get_state - Get the current state of the given device
- * @card: the card instance
- * @device_data: the data pointer to release
- *
- * Returns the current state of the given device object. For the valid
- * device, either @SNDRV_DEV_BUILD, @SNDRV_DEV_REGISTERED or
- * @SNDRV_DEV_DISCONNECTED is returned.
- * Or for a non-existing device, -1 is returned as an error.
- *
- * Return: the current state, or -1 if not found
- */
-int snd_device_get_state(struct snd_card *card, void *device_data)
-{
- struct snd_device *dev;
-
- dev = look_for_dev(card, device_data);
- if (dev)
- return dev->state;
- return -1;
-}
-EXPORT_SYMBOL_GPL(snd_device_get_state);
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index e97ff8cccb64..2d5f4d47071f 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/hrtimer.h>
@@ -35,29 +36,27 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
unsigned long ticks;
enum hrtimer_restart ret = HRTIMER_NORESTART;
- spin_lock(&t->lock);
- if (!t->running)
- goto out; /* fast path */
- stime->in_callback = true;
- ticks = t->sticks;
- spin_unlock(&t->lock);
+ scoped_guard(spinlock, &t->lock) {
+ if (!t->running)
+ return HRTIMER_NORESTART; /* fast path */
+ stime->in_callback = true;
+ ticks = t->sticks;
+ }
/* calculate the drift */
- delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
+ delta = ktime_sub(hrtimer_cb_get_time(hrt), hrtimer_get_expires(hrt));
if (delta > 0)
ticks += ktime_divns(delta, ticks * resolution);
snd_timer_interrupt(stime->timer, ticks);
- spin_lock(&t->lock);
+ guard(spinlock)(&t->lock);
if (t->running) {
hrtimer_add_expires_ns(hrt, t->sticks * resolution);
ret = HRTIMER_RESTART;
}
stime->in_callback = false;
- out:
- spin_unlock(&t->lock);
return ret;
}
@@ -68,9 +67,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;
}
@@ -80,10 +78,10 @@ static int snd_hrtimer_close(struct snd_timer *t)
struct snd_hrtimer *stime = t->private_data;
if (stime) {
- spin_lock_irq(&t->lock);
- t->running = 0; /* just to be sure */
- stime->in_callback = 1; /* skip start/stop */
- spin_unlock_irq(&t->lock);
+ scoped_guard(spinlock_irq, &t->lock) {
+ t->running = 0; /* just to be sure */
+ stime->in_callback = 1; /* skip start/stop */
+ }
hrtimer_cancel(&stime->hrt);
kfree(stime);
@@ -141,7 +139,7 @@ static int __init snd_hrtimer_init(void)
return err;
timer->module = THIS_MODULE;
- strcpy(timer->name, "HR timer");
+ strscpy(timer->name, "HR timer");
timer->hw = hrtimer_hw;
timer->hw.resolution = resolution;
timer->hw.ticks = NANO_SEC / resolution;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index e95fa275c289..09200df2932c 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -149,12 +149,12 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
struct snd_hwdep *hw = file->private_data;
struct module *mod = hw->card->module;
- mutex_lock(&hw->open_mutex);
- if (hw->ops.release)
- err = hw->ops.release(hw, file);
- if (hw->used > 0)
- hw->used--;
- mutex_unlock(&hw->open_mutex);
+ scoped_guard(mutex, &hw->open_mutex) {
+ if (hw->ops.release)
+ err = hw->ops.release(hw, file);
+ if (hw->used > 0)
+ hw->used--;
+ }
wake_up(&hw->open_wait);
snd_card_file_remove(hw->card, file);
@@ -272,23 +272,23 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
if (get_user(device, (int __user *)arg))
return -EFAULT;
- mutex_lock(&register_mutex);
-
- if (device < 0)
- device = 0;
- else if (device < SNDRV_MINOR_HWDEPS)
- device++;
- else
- device = SNDRV_MINOR_HWDEPS;
-
- while (device < SNDRV_MINOR_HWDEPS) {
- if (snd_hwdep_search(card, device))
- break;
- device++;
+
+ scoped_guard(mutex, &register_mutex) {
+ if (device < 0)
+ device = 0;
+ else if (device < SNDRV_MINOR_HWDEPS)
+ device++;
+ else
+ device = SNDRV_MINOR_HWDEPS;
+
+ while (device < SNDRV_MINOR_HWDEPS) {
+ if (snd_hwdep_search(card, device))
+ break;
+ device++;
+ }
+ if (device >= SNDRV_MINOR_HWDEPS)
+ device = -1;
}
- if (device >= SNDRV_MINOR_HWDEPS)
- device = -1;
- mutex_unlock(&register_mutex);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
@@ -296,19 +296,18 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
case SNDRV_CTL_IOCTL_HWDEP_INFO:
{
struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
- int device, err;
+ int device;
struct snd_hwdep *hwdep;
if (get_user(device, &info->device))
return -EFAULT;
- mutex_lock(&register_mutex);
- hwdep = snd_hwdep_search(card, device);
- if (hwdep)
- err = snd_hwdep_info(hwdep, info);
- else
- err = -ENXIO;
- mutex_unlock(&register_mutex);
- return err;
+ scoped_guard(mutex, &register_mutex) {
+ hwdep = snd_hwdep_search(card, device);
+ if (!hwdep)
+ return -ENXIO;
+ return snd_hwdep_info(hwdep, info);
+ }
+ break;
}
}
return -ENOIOCTLCMD;
@@ -338,9 +337,14 @@ static const struct file_operations snd_hwdep_f_ops =
.mmap = snd_hwdep_mmap,
};
-static void release_hwdep_device(struct device *dev)
+static void snd_hwdep_free(struct snd_hwdep *hwdep)
{
- kfree(container_of(dev, struct snd_hwdep, dev));
+ if (!hwdep)
+ return;
+ if (hwdep->private_free)
+ hwdep->private_free(hwdep);
+ put_device(hwdep->dev);
+ kfree(hwdep);
}
/**
@@ -382,16 +386,20 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
if (id)
strscpy(hwdep->id, id, sizeof(hwdep->id));
- snd_device_initialize(&hwdep->dev, card);
- hwdep->dev.release = release_hwdep_device;
- dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device);
+ err = snd_device_alloc(&hwdep->dev, card);
+ if (err < 0) {
+ snd_hwdep_free(hwdep);
+ return err;
+ }
+
+ dev_set_name(hwdep->dev, "hwC%iD%i", card->number, device);
#ifdef CONFIG_SND_OSSEMUL
hwdep->oss_type = -1;
#endif
err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops);
if (err < 0) {
- put_device(&hwdep->dev);
+ snd_hwdep_free(hwdep);
return err;
}
@@ -403,12 +411,7 @@ EXPORT_SYMBOL(snd_hwdep_new);
static int snd_hwdep_dev_free(struct snd_device *device)
{
- struct snd_hwdep *hwdep = device->device_data;
- if (!hwdep)
- return 0;
- if (hwdep->private_free)
- hwdep->private_free(hwdep);
- put_device(&hwdep->dev);
+ snd_hwdep_free(device->device_data);
return 0;
}
@@ -418,19 +421,16 @@ static int snd_hwdep_dev_register(struct snd_device *device)
struct snd_card *card = hwdep->card;
int err;
- mutex_lock(&register_mutex);
- if (snd_hwdep_search(card, hwdep->device)) {
- mutex_unlock(&register_mutex);
+ guard(mutex)(&register_mutex);
+ if (snd_hwdep_search(card, hwdep->device))
return -EBUSY;
- }
list_add_tail(&hwdep->list, &snd_hwdep_devices);
err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
hwdep->card, hwdep->device,
- &snd_hwdep_f_ops, hwdep, &hwdep->dev);
+ &snd_hwdep_f_ops, hwdep, hwdep->dev);
if (err < 0) {
- dev_err(&hwdep->dev, "unable to register\n");
+ dev_err(hwdep->dev, "unable to register\n");
list_del(&hwdep->list);
- mutex_unlock(&register_mutex);
return err;
}
@@ -439,18 +439,17 @@ static int snd_hwdep_dev_register(struct snd_device *device)
if (hwdep->oss_type >= 0) {
if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM &&
hwdep->device)
- dev_warn(&hwdep->dev,
+ dev_warn(hwdep->dev,
"only hwdep device 0 can be registered as OSS direct FM device!\n");
else if (snd_register_oss_device(hwdep->oss_type,
card, hwdep->device,
&snd_hwdep_f_ops, hwdep) < 0)
- dev_warn(&hwdep->dev,
+ dev_warn(hwdep->dev,
"unable to register OSS compatibility device\n");
else
hwdep->ossreg = 1;
}
#endif
- mutex_unlock(&register_mutex);
return 0;
}
@@ -460,21 +459,17 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
if (snd_BUG_ON(!hwdep))
return -ENXIO;
- mutex_lock(&register_mutex);
- if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
- mutex_unlock(&register_mutex);
+ guard(mutex)(&register_mutex);
+ if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep)
return -EINVAL;
- }
- mutex_lock(&hwdep->open_mutex);
+ guard(mutex)(&hwdep->open_mutex);
wake_up(&hwdep->open_wait);
#ifdef CONFIG_SND_OSSEMUL
if (hwdep->ossreg)
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif
- snd_unregister_device(&hwdep->dev);
+ snd_unregister_device(hwdep->dev);
list_del_init(&hwdep->list);
- mutex_unlock(&hwdep->open_mutex);
- mutex_unlock(&register_mutex);
return 0;
}
@@ -488,11 +483,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry,
{
struct snd_hwdep *hwdep;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
list_for_each_entry(hwdep, &snd_hwdep_devices, list)
snd_iprintf(buffer, "%02i-%02i: %s\n",
hwdep->card->number, hwdep->device, hwdep->name);
- mutex_unlock(&register_mutex);
}
static struct snd_info_entry *snd_hwdep_proc_entry;
diff --git a/sound/core/info.c b/sound/core/info.c
index 0b2f04dcb589..1f5b8a3d9e3b 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -56,7 +56,7 @@ struct snd_info_private_data {
};
static int snd_info_version_init(void);
-static void snd_info_disconnect(struct snd_info_entry *entry);
+static void snd_info_clear_entries(struct snd_info_entry *entry);
/*
@@ -105,17 +105,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{
struct snd_info_private_data *data;
struct snd_info_entry *entry;
- loff_t ret = -EINVAL, size;
+ loff_t size;
data = file->private_data;
entry = data->entry;
- mutex_lock(&entry->access);
- if (entry->c.ops->llseek) {
- ret = entry->c.ops->llseek(entry,
- data->file_private_data,
- file, offset, orig);
- goto out;
- }
+ guard(mutex)(&entry->access);
+ if (entry->c.ops->llseek)
+ return entry->c.ops->llseek(entry,
+ data->file_private_data,
+ file, offset, orig);
size = entry->size;
switch (orig) {
@@ -126,21 +124,18 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
break;
case SEEK_END:
if (!size)
- goto out;
+ return -EINVAL;
offset += size;
break;
default:
- goto out;
+ return -EINVAL;
}
if (offset < 0)
- goto out;
+ return -EINVAL;
if (size && offset > size)
offset = size;
file->f_pos = offset;
- ret = offset;
- out:
- mutex_unlock(&entry->access);
- return ret;
+ return offset;
}
static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
@@ -238,10 +233,10 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
struct snd_info_private_data *data;
int mode, err;
- mutex_lock(&info_mutex);
+ guard(mutex)(&info_mutex);
err = alloc_info_private(entry, &data);
if (err < 0)
- goto unlock;
+ return err;
mode = file->f_flags & O_ACCMODE;
if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
@@ -257,14 +252,11 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
}
file->private_data = data;
- mutex_unlock(&info_mutex);
return 0;
error:
kfree(data);
module_put(entry->module);
- unlock:
- mutex_unlock(&info_mutex);
return err;
}
@@ -306,7 +298,6 @@ static ssize_t snd_info_text_entry_write(struct file *file,
struct snd_info_buffer *buf;
loff_t pos;
size_t next;
- int err = 0;
if (!entry->c.text.write)
return -EIO;
@@ -317,34 +308,24 @@ static ssize_t snd_info_text_entry_write(struct file *file,
/* don't handle too large text inputs */
if (next > 16 * 1024)
return -EIO;
- mutex_lock(&entry->access);
+ guard(mutex)(&entry->access);
buf = data->wbuffer;
if (!buf) {
data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
- if (!buf) {
- err = -ENOMEM;
- goto error;
- }
+ if (!buf)
+ return -ENOMEM;
}
if (next > buf->len) {
char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
- if (!nbuf) {
- err = -ENOMEM;
- goto error;
- }
+ if (!nbuf)
+ return -ENOMEM;
kvfree(buf->buffer);
buf->buffer = nbuf;
buf->len = PAGE_ALIGN(next);
}
- if (copy_from_user(buf->buffer + pos, buffer, count)) {
- err = -EFAULT;
- goto error;
- }
+ if (copy_from_user(buf->buffer + pos, buffer, count))
+ return -EFAULT;
buf->size = next;
- error:
- mutex_unlock(&entry->access);
- if (err < 0)
- return err;
*offset = next;
return count;
}
@@ -369,10 +350,10 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
struct snd_info_private_data *data;
int err;
- mutex_lock(&info_mutex);
+ guard(mutex)(&info_mutex);
err = alloc_info_private(entry, &data);
if (err < 0)
- goto unlock;
+ return err;
data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
if (!data->rbuffer) {
@@ -386,15 +367,12 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file)
err = single_open(file, snd_info_seq_show, data);
if (err < 0)
goto error;
- mutex_unlock(&info_mutex);
return 0;
error:
kfree(data->rbuffer);
kfree(data);
module_put(entry->module);
- unlock:
- mutex_unlock(&info_mutex);
return err;
}
@@ -549,7 +527,7 @@ int snd_info_card_register(struct snd_card *card)
*/
void snd_info_card_id_change(struct snd_card *card)
{
- mutex_lock(&info_mutex);
+ guard(mutex)(&info_mutex);
if (card->proc_root_link) {
proc_remove(card->proc_root_link);
card->proc_root_link = NULL;
@@ -558,7 +536,6 @@ void snd_info_card_id_change(struct snd_card *card)
card->proc_root_link = proc_symlink(card->id,
snd_proc_root->p,
card->proc_root->name);
- mutex_unlock(&info_mutex);
}
/*
@@ -569,12 +546,16 @@ void snd_info_card_disconnect(struct snd_card *card)
{
if (!card)
return;
- mutex_lock(&info_mutex);
+
proc_remove(card->proc_root_link);
- card->proc_root_link = NULL;
if (card->proc_root)
- snd_info_disconnect(card->proc_root);
- mutex_unlock(&info_mutex);
+ proc_remove(card->proc_root->p);
+
+ guard(mutex)(&info_mutex);
+ if (card->proc_root)
+ snd_info_clear_entries(card->proc_root);
+ card->proc_root_link = NULL;
+ card->proc_root = NULL;
}
/*
@@ -698,9 +679,8 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent,
entry->parent = parent;
entry->module = module;
if (parent) {
- mutex_lock(&parent->access);
+ guard(mutex)(&parent->access);
list_add_tail(&entry->list, &parent->children);
- mutex_unlock(&parent->access);
}
return entry;
}
@@ -745,15 +725,14 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
}
EXPORT_SYMBOL(snd_info_create_card_entry);
-static void snd_info_disconnect(struct snd_info_entry *entry)
+static void snd_info_clear_entries(struct snd_info_entry *entry)
{
struct snd_info_entry *p;
if (!entry->p)
return;
list_for_each_entry(p, &entry->children, list)
- snd_info_disconnect(p);
- proc_remove(entry->p);
+ snd_info_clear_entries(p);
entry->p = NULL;
}
@@ -770,9 +749,9 @@ void snd_info_free_entry(struct snd_info_entry * entry)
if (!entry)
return;
if (entry->p) {
- mutex_lock(&info_mutex);
- snd_info_disconnect(entry);
- mutex_unlock(&info_mutex);
+ proc_remove(entry->p);
+ guard(mutex)(&info_mutex);
+ snd_info_clear_entries(entry);
}
/* free all children at first */
@@ -781,9 +760,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
p = entry->parent;
if (p) {
- mutex_lock(&p->access);
+ guard(mutex)(&p->access);
list_del(&entry->list);
- mutex_unlock(&p->access);
}
kfree(entry->name);
if (entry->private_free)
@@ -799,15 +777,13 @@ static int __snd_info_register(struct snd_info_entry *entry)
if (snd_BUG_ON(!entry))
return -ENXIO;
root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
- mutex_lock(&info_mutex);
+ guard(mutex)(&info_mutex);
if (entry->p || !root)
- goto unlock;
+ return 0;
if (S_ISDIR(entry->mode)) {
p = proc_mkdir_mode(entry->name, entry->mode, root);
- if (!p) {
- mutex_unlock(&info_mutex);
+ if (!p)
return -ENOMEM;
- }
} else {
const struct proc_ops *ops;
if (entry->content == SNDRV_INFO_CONTENT_DATA)
@@ -816,15 +792,11 @@ static int __snd_info_register(struct snd_info_entry *entry)
ops = &snd_info_text_entry_ops;
p = proc_create_data(entry->name, entry->mode, root,
ops, entry);
- if (!p) {
- mutex_unlock(&info_mutex);
+ if (!p)
return -ENOMEM;
- }
proc_set_size(p, entry->size);
}
entry->p = p;
- unlock:
- mutex_unlock(&info_mutex);
return 0;
}
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index ebc714b2f46b..0dbbb8005570 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -29,20 +29,17 @@ int snd_oss_info_register(int dev, int num, char *string)
return -ENXIO;
if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS))
return -ENXIO;
- mutex_lock(&strings);
+ guard(mutex)(&strings);
if (string == NULL) {
x = snd_sndstat_strings[num][dev];
kfree(x);
x = NULL;
} else {
x = kstrdup(string, GFP_KERNEL);
- if (x == NULL) {
- mutex_unlock(&strings);
+ if (x == NULL)
return -ENOMEM;
- }
}
snd_sndstat_strings[num][dev] = x;
- mutex_unlock(&strings);
return 0;
}
EXPORT_SYMBOL(snd_oss_info_register);
@@ -53,7 +50,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
char *str;
snd_iprintf(buf, "\n%s:", id);
- mutex_lock(&strings);
+ guard(mutex)(&strings);
for (idx = 0; idx < SNDRV_CARDS; idx++) {
str = snd_sndstat_strings[idx][dev];
if (str) {
@@ -64,7 +61,6 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
snd_iprintf(buf, "%i: %s\n", idx, str);
}
}
- mutex_unlock(&strings);
if (ok < 0)
snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
return ok;
diff --git a/sound/core/init.c b/sound/core/init.c
index df0c22480375..c372b3228785 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
static int module_slot_match(struct module *module, int idx)
{
int match = 1;
-#ifdef MODULE
+#ifdef CONFIG_MODULES
const char *s1, *s2;
if (!module || !*module->name || !slots[idx])
@@ -77,7 +77,7 @@ static int module_slot_match(struct module *module, int idx)
if (!c1)
break;
}
-#endif /* MODULE */
+#endif /* CONFIG_MODULES */
return match;
}
@@ -111,28 +111,36 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
return mask; /* unchanged */
}
-/* the default release callback set in snd_device_initialize() below;
- * this is just NOP for now, as almost all jobs are already done in
- * dev_free callback of snd_device chain instead.
- */
-static void default_release(struct device *dev)
+/* the default release callback set in snd_device_alloc() */
+static void default_release_alloc(struct device *dev)
{
+ kfree(dev);
}
/**
- * snd_device_initialize - Initialize struct device for sound devices
- * @dev: device to initialize
+ * snd_device_alloc - Allocate and initialize struct device for sound devices
+ * @dev_p: pointer to store the allocated device
* @card: card to assign, optional
+ *
+ * For releasing the allocated device, call put_device().
*/
-void snd_device_initialize(struct device *dev, struct snd_card *card)
+int snd_device_alloc(struct device **dev_p, struct snd_card *card)
{
+ struct device *dev;
+
+ *dev_p = NULL;
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
device_initialize(dev);
if (card)
dev->parent = &card->card_dev;
- dev->class = sound_class;
- dev->release = default_release;
+ dev->class = &sound_class;
+ dev->release = default_release_alloc;
+ *dev_p = dev;
+ return 0;
}
-EXPORT_SYMBOL_GPL(snd_device_initialize);
+EXPORT_SYMBOL_GPL(snd_device_alloc);
static int snd_card_init(struct snd_card *card, struct device *parent,
int idx, const char *xid, struct module *module,
@@ -270,48 +278,44 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
size_t extra_size)
{
int err;
-#ifdef CONFIG_SND_DEBUG
- char name[8];
-#endif
if (extra_size > 0)
card->private_data = (char *)card + sizeof(struct snd_card);
if (xid)
strscpy(card->id, xid, sizeof(card->id));
err = 0;
- mutex_lock(&snd_card_mutex);
- if (idx < 0) /* first check the matching module-name slot */
- idx = get_slot_from_bitmask(idx, module_slot_match, module);
- if (idx < 0) /* if not matched, assign an empty slot */
- idx = get_slot_from_bitmask(idx, check_empty_slot, module);
- if (idx < 0)
- err = -ENODEV;
- else if (idx < snd_ecards_limit) {
- if (test_bit(idx, snd_cards_lock))
- err = -EBUSY; /* invalid */
- } else if (idx >= SNDRV_CARDS)
- err = -ENODEV;
+ scoped_guard(mutex, &snd_card_mutex) {
+ if (idx < 0) /* first check the matching module-name slot */
+ idx = get_slot_from_bitmask(idx, module_slot_match, module);
+ if (idx < 0) /* if not matched, assign an empty slot */
+ idx = get_slot_from_bitmask(idx, check_empty_slot, module);
+ if (idx < 0)
+ err = -ENODEV;
+ else if (idx < snd_ecards_limit) {
+ if (test_bit(idx, snd_cards_lock))
+ err = -EBUSY; /* invalid */
+ } else if (idx >= SNDRV_CARDS)
+ err = -ENODEV;
+ if (!err) {
+ set_bit(idx, snd_cards_lock); /* lock it */
+ if (idx >= snd_ecards_limit)
+ snd_ecards_limit = idx + 1; /* increase the limit */
+ }
+ }
if (err < 0) {
- mutex_unlock(&snd_card_mutex);
dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
- idx, snd_ecards_limit - 1, err);
+ idx, snd_ecards_limit - 1, err);
if (!card->managed)
kfree(card); /* manually free here, as no destructor called */
return err;
}
- set_bit(idx, snd_cards_lock); /* lock it */
- if (idx >= snd_ecards_limit)
- snd_ecards_limit = idx + 1; /* increase the limit */
- mutex_unlock(&snd_card_mutex);
card->dev = parent;
card->number = idx;
-#ifdef MODULE
- WARN_ON(!module);
+ WARN_ON(IS_MODULE(CONFIG_SND) && !module);
card->module = module;
-#endif
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
- rwlock_init(&card->ctl_files_rwlock);
+ rwlock_init(&card->controls_rwlock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
@@ -331,7 +335,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
- card->card_dev.class = sound_class;
+ card->card_dev.class = &sound_class;
card->card_dev.release = release_card_device;
card->card_dev.groups = card->dev_groups;
card->dev_groups[0] = &card_dev_attr_group;
@@ -356,8 +360,8 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
}
#ifdef CONFIG_SND_DEBUG
- sprintf(name, "card%d", idx);
- card->debugfs_root = debugfs_create_dir(name, sound_debugfs_root);
+ card->debugfs_root = debugfs_create_dir(dev_name(&card->card_dev),
+ sound_debugfs_root);
#endif
return 0;
@@ -381,11 +385,10 @@ struct snd_card *snd_card_ref(int idx)
{
struct snd_card *card;
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card)
get_device(&card->card_dev);
- mutex_unlock(&snd_card_mutex);
return card;
}
EXPORT_SYMBOL_GPL(snd_card_ref);
@@ -393,12 +396,8 @@ EXPORT_SYMBOL_GPL(snd_card_ref);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
{
- int locked;
-
- mutex_lock(&snd_card_mutex);
- locked = test_bit(card, snd_cards_lock);
- mutex_unlock(&snd_card_mutex);
- return locked;
+ guard(mutex)(&snd_card_mutex);
+ return test_bit(card, snd_cards_lock);
}
static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
@@ -422,15 +421,15 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
{
struct snd_monitor_file *df = NULL, *_df;
- spin_lock(&shutdown_lock);
- list_for_each_entry(_df, &shutdown_files, shutdown_list) {
- if (_df->file == file) {
- df = _df;
- list_del_init(&df->shutdown_list);
- break;
+ scoped_guard(spinlock, &shutdown_lock) {
+ list_for_each_entry(_df, &shutdown_files, shutdown_list) {
+ if (_df->file == file) {
+ df = _df;
+ list_del_init(&df->shutdown_list);
+ break;
+ }
}
}
- spin_unlock(&shutdown_lock);
if (likely(df)) {
if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync)
@@ -496,27 +495,32 @@ void snd_card_disconnect(struct snd_card *card)
if (!card)
return;
- spin_lock(&card->files_lock);
- if (card->shutdown) {
- spin_unlock(&card->files_lock);
- return;
- }
- card->shutdown = 1;
+ scoped_guard(spinlock, &card->files_lock) {
+ if (card->shutdown)
+ return;
+ card->shutdown = 1;
- /* replace file->f_op with special dummy operations */
- list_for_each_entry(mfile, &card->files_list, list) {
- /* it's critical part, use endless loop */
- /* we have no room to fail */
- mfile->disconnected_f_op = mfile->file->f_op;
+ /* replace file->f_op with special dummy operations */
+ list_for_each_entry(mfile, &card->files_list, list) {
+ /* it's critical part, use endless loop */
+ /* we have no room to fail */
+ mfile->disconnected_f_op = mfile->file->f_op;
- spin_lock(&shutdown_lock);
- list_add(&mfile->shutdown_list, &shutdown_files);
- spin_unlock(&shutdown_lock);
+ scoped_guard(spinlock, &shutdown_lock)
+ list_add(&mfile->shutdown_list, &shutdown_files);
- mfile->file->f_op = &snd_shutdown_f_ops;
- fops_get(mfile->file->f_op);
+ mfile->file->f_op = &snd_shutdown_f_ops;
+ fops_get(mfile->file->f_op);
+ }
}
- spin_unlock(&card->files_lock);
+
+#ifdef CONFIG_PM
+ /* wake up sleepers here before other callbacks for avoiding potential
+ * deadlocks with other locks (e.g. in kctls);
+ * then this notifies the shutdown and sleepers would abort immediately
+ */
+ wake_up_all(&card->power_sleep);
+#endif
/* notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
@@ -533,21 +537,23 @@ void snd_card_disconnect(struct snd_card *card)
synchronize_irq(card->sync_irq);
snd_info_card_disconnect(card);
+#ifdef CONFIG_SND_DEBUG
+ debugfs_remove(card->debugfs_root);
+ card->debugfs_root = NULL;
+#endif
+
if (card->registered) {
device_del(&card->card_dev);
card->registered = false;
}
/* disable fops (user space) operations for ALSA API */
- mutex_lock(&snd_card_mutex);
- snd_cards[card->number] = NULL;
- clear_bit(card->number, snd_cards_lock);
- mutex_unlock(&snd_card_mutex);
+ scoped_guard(mutex, &snd_card_mutex) {
+ snd_cards[card->number] = NULL;
+ clear_bit(card->number, snd_cards_lock);
+ }
-#ifdef CONFIG_PM
- wake_up(&card->power_sleep);
snd_power_sync_ref(card);
-#endif
}
EXPORT_SYMBOL(snd_card_disconnect);
@@ -564,11 +570,10 @@ void snd_card_disconnect_sync(struct snd_card *card)
{
snd_card_disconnect(card);
- spin_lock_irq(&card->files_lock);
+ guard(spinlock_irq)(&card->files_lock);
wait_event_lock_irq(card->remove_sleep,
list_empty(&card->files_list),
card->files_lock);
- spin_unlock_irq(&card->files_lock);
}
EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
@@ -586,10 +591,6 @@ static int snd_card_do_free(struct snd_card *card)
dev_warn(card->dev, "unable to free card info\n");
/* Not fatal error */
}
-#ifdef CONFIG_SND_DEBUG
- debugfs_remove(card->debugfs_root);
- card->debugfs_root = NULL;
-#endif
if (card->release_completion)
complete(card->release_completion);
if (!card->managed)
@@ -653,13 +654,19 @@ void snd_card_free(struct snd_card *card)
}
EXPORT_SYMBOL(snd_card_free);
+/* check, if the character is in the valid ASCII range */
+static inline bool safe_ascii_char(char c)
+{
+ return isascii(c) && isalnum(c);
+}
+
/* retrieve the last word of shortname or longname */
static const char *retrieve_id_from_card_name(const char *name)
{
const char *spos = name;
while (*name) {
- if (isspace(*name) && isalnum(name[1]))
+ if (isspace(*name) && safe_ascii_char(name[1]))
spos = name + 1;
name++;
}
@@ -686,12 +693,12 @@ static void copy_valid_id_string(struct snd_card *card, const char *src,
{
char *id = card->id;
- while (*nid && !isalnum(*nid))
+ while (*nid && !safe_ascii_char(*nid))
nid++;
if (isdigit(*nid))
*id++ = isalpha(*src) ? *src : 'D';
while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) {
- if (isalnum(*nid))
+ if (safe_ascii_char(*nid))
*id++ = *nid;
nid++;
}
@@ -716,27 +723,25 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
* ("card" conflicts with proc directories)
*/
if (!*id || !strncmp(id, "card", 4)) {
- strcpy(id, "Default");
+ strscpy(card->id, "Default");
is_default = true;
}
len = strlen(id);
for (loops = 0; loops < SNDRV_CARDS; loops++) {
- char *spos;
char sfxstr[5]; /* "_012" */
- int sfxlen;
+ int sfxlen, slen;
if (card_id_ok(card, id))
return; /* OK */
/* Add _XYZ suffix */
- sprintf(sfxstr, "_%X", loops + 1);
- sfxlen = strlen(sfxstr);
+ sfxlen = scnprintf(sfxstr, sizeof(sfxstr), "_%X", loops + 1);
if (len + sfxlen >= sizeof(card->id))
- spos = id + sizeof(card->id) - sfxlen - 1;
+ slen = sizeof(card->id) - sfxlen - 1;
else
- spos = id + len;
- strcpy(spos, sfxstr);
+ slen = len;
+ strscpy(id + slen, sfxstr, sizeof(card->id) - slen);
}
/* fallback to the default id */
if (!is_default) {
@@ -762,9 +767,8 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
/* check if user specified own card->id */
if (card->id[0] != '\0')
return;
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
snd_card_set_id_no_lock(card, nid, nid);
- mutex_unlock(&snd_card_mutex);
}
EXPORT_SYMBOL(snd_card_set_id);
@@ -787,19 +791,16 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr,
for (idx = 0; idx < copy; idx++) {
c = buf[idx];
- if (!isalnum(c) && c != '_' && c != '-')
+ if (!safe_ascii_char(c) && c != '_' && c != '-')
return -EINVAL;
}
memcpy(buf1, buf, copy);
buf1[copy] = '\0';
- mutex_lock(&snd_card_mutex);
- if (!card_id_ok(NULL, buf1)) {
- mutex_unlock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
+ if (!card_id_ok(NULL, buf1))
return -EEXIST;
- }
- strcpy(card->id, buf1);
+ strscpy(card->id, buf1);
snd_info_card_id_change(card);
- mutex_unlock(&snd_card_mutex);
return count;
}
@@ -892,26 +893,27 @@ int snd_card_register(struct snd_card *card)
err = snd_device_register_all(card);
if (err < 0)
return err;
- mutex_lock(&snd_card_mutex);
- if (snd_cards[card->number]) {
- /* already registered */
- mutex_unlock(&snd_card_mutex);
- return snd_info_card_register(card); /* register pending info */
- }
- if (*card->id) {
- /* make a unique id name from the given string */
- char tmpid[sizeof(card->id)];
- memcpy(tmpid, card->id, sizeof(card->id));
- snd_card_set_id_no_lock(card, tmpid, tmpid);
- } else {
- /* create an id from either shortname or longname */
- const char *src;
- src = *card->shortname ? card->shortname : card->longname;
- snd_card_set_id_no_lock(card, src,
- retrieve_id_from_card_name(src));
+ scoped_guard(mutex, &snd_card_mutex) {
+ if (snd_cards[card->number]) {
+ /* already registered */
+ return snd_info_card_register(card); /* register pending info */
+ }
+ if (*card->id) {
+ /* make a unique id name from the given string */
+ char tmpid[sizeof(card->id)];
+
+ memcpy(tmpid, card->id, sizeof(card->id));
+ snd_card_set_id_no_lock(card, tmpid, tmpid);
+ } else {
+ /* create an id from either shortname or longname */
+ const char *src;
+
+ src = *card->shortname ? card->shortname : card->longname;
+ snd_card_set_id_no_lock(card, src,
+ retrieve_id_from_card_name(src));
+ }
+ snd_cards[card->number] = card;
}
- snd_cards[card->number] = card;
- mutex_unlock(&snd_card_mutex);
err = snd_info_card_register(card);
if (err < 0)
return err;
@@ -932,7 +934,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card) {
count++;
@@ -944,7 +946,6 @@ static void snd_card_info_read(struct snd_info_entry *entry,
snd_iprintf(buffer, " %s\n",
card->longname);
}
- mutex_unlock(&snd_card_mutex);
}
if (!count)
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -957,13 +958,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
struct snd_card *card;
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
- mutex_unlock(&snd_card_mutex);
}
if (!count) {
snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -972,7 +972,7 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
#endif
-#ifdef MODULE
+#ifdef CONFIG_MODULES
static void snd_card_module_info_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@@ -980,12 +980,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
struct snd_card *card;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
- mutex_lock(&snd_card_mutex);
+ guard(mutex)(&snd_card_mutex);
card = snd_cards[idx];
if (card)
snd_iprintf(buffer, "%2i %s\n",
idx, card->module->name);
- mutex_unlock(&snd_card_mutex);
}
}
#endif
@@ -1001,7 +1000,7 @@ int __init snd_card_info_init(void)
if (snd_info_register(entry) < 0)
return -ENOMEM; /* freed in error path */
-#ifdef MODULE
+#ifdef CONFIG_MODULES
entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
if (!entry)
return -ENOMEM;
@@ -1067,15 +1066,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
mfile->file = file;
mfile->disconnected_f_op = NULL;
INIT_LIST_HEAD(&mfile->shutdown_list);
- spin_lock(&card->files_lock);
+ guard(spinlock)(&card->files_lock);
if (card->shutdown) {
- spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
list_add(&mfile->list, &card->files_list);
get_device(&card->card_dev);
- spin_unlock(&card->files_lock);
return 0;
}
EXPORT_SYMBOL(snd_card_file_add);
@@ -1097,22 +1094,21 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile, *found = NULL;
- spin_lock(&card->files_lock);
- list_for_each_entry(mfile, &card->files_list, list) {
- if (mfile->file == file) {
- list_del(&mfile->list);
- spin_lock(&shutdown_lock);
- list_del(&mfile->shutdown_list);
- spin_unlock(&shutdown_lock);
- if (mfile->disconnected_f_op)
- fops_put(mfile->disconnected_f_op);
- found = mfile;
- break;
+ scoped_guard(spinlock, &card->files_lock) {
+ list_for_each_entry(mfile, &card->files_list, list) {
+ if (mfile->file == file) {
+ list_del(&mfile->list);
+ scoped_guard(spinlock, &shutdown_lock)
+ list_del(&mfile->shutdown_list);
+ if (mfile->disconnected_f_op)
+ fops_put(mfile->disconnected_f_op);
+ found = mfile;
+ break;
+ }
}
+ if (list_empty(&card->files_list))
+ wake_up_all(&card->remove_sleep);
}
- if (list_empty(&card->files_list))
- wake_up_all(&card->remove_sleep);
- spin_unlock(&card->files_lock);
if (!found) {
dev_err(card->dev, "card file remove problem (%p)\n", file);
return -ENOENT;
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 88493cc31914..93e357a23f17 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -34,19 +34,22 @@ static const int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
SW_JACK_PHYSICAL_INSERT,
SW_VIDEOOUT_INSERT,
SW_LINEIN_INSERT,
+ SW_USB_INSERT,
};
#endif /* CONFIG_SND_JACK_INPUT_DEV */
+static void snd_jack_remove_debugfs(struct snd_jack *jack);
+
static int snd_jack_dev_disconnect(struct snd_device *device)
{
-#ifdef CONFIG_SND_JACK_INPUT_DEV
struct snd_jack *jack = device->device_data;
- mutex_lock(&jack->input_dev_lock);
- if (!jack->input_dev) {
- mutex_unlock(&jack->input_dev_lock);
+ snd_jack_remove_debugfs(jack);
+
+#ifdef CONFIG_SND_JACK_INPUT_DEV
+ guard(mutex)(&jack->input_dev_lock);
+ if (!jack->input_dev)
return 0;
- }
/* If the input device is registered with the input subsystem
* then we need to use a different deallocator. */
@@ -55,7 +58,6 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
else
input_free_device(jack->input_dev);
jack->input_dev = NULL;
- mutex_unlock(&jack->input_dev_lock);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
return 0;
}
@@ -66,12 +68,10 @@ static int snd_jack_dev_free(struct snd_device *device)
struct snd_card *card = device->card;
struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl;
- down_write(&card->controls_rwsem);
list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) {
list_del_init(&jack_kctl->list);
snd_ctl_remove(card, jack_kctl->kctl);
}
- up_write(&card->controls_rwsem);
if (jack->private_free)
jack->private_free(jack);
@@ -94,11 +94,9 @@ static int snd_jack_dev_register(struct snd_device *device)
snprintf(jack->name, sizeof(jack->name), "%s %s",
card->shortname, jack->id);
- mutex_lock(&jack->input_dev_lock);
- if (!jack->input_dev) {
- mutex_unlock(&jack->input_dev_lock);
+ guard(mutex)(&jack->input_dev_lock);
+ if (!jack->input_dev)
return 0;
- }
jack->input_dev->name = jack->name;
@@ -123,7 +121,6 @@ static int snd_jack_dev_register(struct snd_device *device)
if (err == 0)
jack->registered = 1;
- mutex_unlock(&jack->input_dev_lock);
return err;
}
#endif /* CONFIG_SND_JACK_INPUT_DEV */
@@ -245,8 +242,9 @@ static ssize_t jack_kctl_id_read(struct file *file,
static const char * const jack_events_name[] = {
"HEADPHONE(0x0001)", "MICROPHONE(0x0002)", "LINEOUT(0x0004)",
"MECHANICAL(0x0008)", "VIDEOOUT(0x0010)", "LINEIN(0x0020)",
- "", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)", "BTN_3(0x0800)",
- "BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)", "",
+ "USB(0x0040)", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)",
+ "BTN_3(0x0800)", "BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)",
+ "",
};
/* the recommended buffer size is 256 */
@@ -389,10 +387,14 @@ static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
return 0;
}
-static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl)
+static void snd_jack_remove_debugfs(struct snd_jack *jack)
{
- debugfs_remove(jack_kctl->jack_debugfs_root);
- jack_kctl->jack_debugfs_root = NULL;
+ struct snd_jack_kctl *jack_kctl;
+
+ list_for_each_entry(jack_kctl, &jack->kctl_list, list) {
+ debugfs_remove(jack_kctl->jack_debugfs_root);
+ jack_kctl->jack_debugfs_root = NULL;
+ }
}
#else /* CONFIG_SND_JACK_INJECTION_DEBUG */
static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
@@ -401,7 +403,7 @@ static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
return 0;
}
-static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl)
+static void snd_jack_remove_debugfs(struct snd_jack *jack)
{
}
#endif /* CONFIG_SND_JACK_INJECTION_DEBUG */
@@ -412,7 +414,6 @@ static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
jack_kctl = kctl->private_data;
if (jack_kctl) {
- snd_jack_debugfs_clear_inject_node(jack_kctl);
list_del(&jack_kctl->list);
kfree(jack_kctl);
}
@@ -505,8 +506,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
.dev_free = snd_jack_dev_free,
#ifdef CONFIG_SND_JACK_INPUT_DEV
.dev_register = snd_jack_dev_register,
- .dev_disconnect = snd_jack_dev_disconnect,
#endif /* CONFIG_SND_JACK_INPUT_DEV */
+ .dev_disconnect = snd_jack_dev_disconnect,
};
if (initial_kctl) {
@@ -576,30 +577,6 @@ EXPORT_SYMBOL(snd_jack_new);
#ifdef CONFIG_SND_JACK_INPUT_DEV
/**
- * snd_jack_set_parent - Set the parent device for a jack
- *
- * @jack: The jack to configure
- * @parent: The device to set as parent for the jack.
- *
- * Set the parent for the jack devices in the device tree. This
- * function is only valid prior to registration of the jack. If no
- * parent is configured then the parent device will be the sound card.
- */
-void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
-{
- WARN_ON(jack->registered);
- mutex_lock(&jack->input_dev_lock);
- if (!jack->input_dev) {
- mutex_unlock(&jack->input_dev_lock);
- return;
- }
-
- jack->input_dev->dev.parent = parent;
- mutex_unlock(&jack->input_dev_lock);
-}
-EXPORT_SYMBOL(snd_jack_set_parent);
-
-/**
* snd_jack_set_key - Set a key mapping on a jack
*
* @jack: The jack to configure
@@ -654,6 +631,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
struct snd_jack_kctl *jack_kctl;
unsigned int mask_bits = 0;
#ifdef CONFIG_SND_JACK_INPUT_DEV
+ struct input_dev *idev;
int i;
#endif
@@ -670,17 +648,15 @@ void snd_jack_report(struct snd_jack *jack, int status)
status & jack_kctl->mask_bits);
#ifdef CONFIG_SND_JACK_INPUT_DEV
- mutex_lock(&jack->input_dev_lock);
- if (!jack->input_dev) {
- mutex_unlock(&jack->input_dev_lock);
+ idev = input_get_device(jack->input_dev);
+ if (!idev)
return;
- }
for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits);
if (jack->type & testbit)
- input_report_key(jack->input_dev, jack->key[i],
+ input_report_key(idev, jack->key[i],
status & testbit);
}
@@ -688,13 +664,13 @@ void snd_jack_report(struct snd_jack *jack, int status)
int testbit = ((1 << i) & ~mask_bits);
if (jack->type & testbit)
- input_report_switch(jack->input_dev,
+ input_report_switch(idev,
jack_switch_types[i],
status & testbit);
}
- input_sync(jack->input_dev);
- mutex_unlock(&jack->input_dev_lock);
+ input_sync(idev);
+ input_put_device(idev);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
}
EXPORT_SYMBOL(snd_jack_report);
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index f901504b5afc..b3853583d2ae 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -17,7 +17,17 @@
#include <asm/set_memory.h>
#endif
#include <sound/memalloc.h>
-#include "memalloc_local.h"
+
+struct snd_malloc_ops {
+ void *(*alloc)(struct snd_dma_buffer *dmab, size_t size);
+ void (*free)(struct snd_dma_buffer *dmab);
+ dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset);
+ struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset);
+ unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab,
+ unsigned int ofs, unsigned int size);
+ int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area);
+ void (*sync)(struct snd_dma_buffer *dmab, enum snd_dma_sync_mode mode);
+};
#define DEFAULT_GFP \
(GFP_KERNEL | \
@@ -26,10 +36,6 @@
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab);
-#ifdef CONFIG_SND_DMA_SGBUF
-static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size);
-#endif
-
static void *__snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
@@ -490,15 +496,26 @@ static const struct snd_malloc_ops snd_dma_dev_ops = {
/*
* Write-combined pages
*/
-/* x86-specific allocations */
#ifdef CONFIG_SND_DMA_SGBUF
+/* x86-specific allocations */
static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
{
- return do_alloc_pages(dmab->dev.dev, size, &dmab->addr, true);
+ void *p = do_alloc_pages(dmab->dev.dev, size, &dmab->addr, true);
+
+ if (!p)
+ return NULL;
+ dmab->addr = dma_map_single(dmab->dev.dev, p, size, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dmab->dev.dev, dmab->addr)) {
+ do_free_pages(dmab->area, size, true);
+ return NULL;
+ }
+ return p;
}
static void snd_dma_wc_free(struct snd_dma_buffer *dmab)
{
+ dma_unmap_single(dmab->dev.dev, dmab->addr, dmab->bytes,
+ DMA_BIDIRECTIONAL);
do_free_pages(dmab->area, dmab->bytes, true);
}
@@ -506,7 +523,8 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
- return snd_dma_continuous_mmap(dmab, area);
+ return dma_mmap_coherent(dmab->dev.dev, area,
+ dmab->area, dmab->addr, dmab->bytes);
}
#else
static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
@@ -525,7 +543,7 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab,
return dma_mmap_wc(dmab->dev.dev, area,
dmab->area, dmab->addr, dmab->bytes);
}
-#endif /* CONFIG_SND_DMA_SGBUF */
+#endif
static const struct snd_malloc_ops snd_dma_wc_ops = {
.alloc = snd_dma_wc_alloc,
@@ -541,16 +559,8 @@ static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
struct sg_table *sgt;
void *p;
-#ifdef CONFIG_SND_DMA_SGBUF
- if (cpu_feature_enabled(X86_FEATURE_XENPV))
- return snd_dma_sg_fallback_alloc(dmab, size);
-#endif
sgt = dma_alloc_noncontiguous(dmab->dev.dev, size, dmab->dev.dir,
DEFAULT_GFP, 0);
-#ifdef CONFIG_SND_DMA_SGBUF
- if (!sgt && !get_dma_ops(dmab->dev.dev))
- return snd_dma_sg_fallback_alloc(dmab, size);
-#endif
if (!sgt)
return NULL;
@@ -667,125 +677,64 @@ static const struct snd_malloc_ops snd_dma_noncontig_ops = {
.get_chunk_size = snd_dma_noncontig_get_chunk_size,
};
-/* x86-specific SG-buffer with WC pages */
#ifdef CONFIG_SND_DMA_SGBUF
-#define sg_wc_address(it) ((unsigned long)page_address(sg_page_iter_page(it)))
-
-static void *snd_dma_sg_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
-{
- void *p = snd_dma_noncontig_alloc(dmab, size);
- struct sg_table *sgt = dmab->private_data;
- struct sg_page_iter iter;
-
- if (!p)
- return NULL;
- if (dmab->dev.type != SNDRV_DMA_TYPE_DEV_WC_SG)
- return p;
- for_each_sgtable_page(sgt, &iter, 0)
- set_memory_wc(sg_wc_address(&iter), 1);
- return p;
-}
-
-static void snd_dma_sg_wc_free(struct snd_dma_buffer *dmab)
-{
- struct sg_table *sgt = dmab->private_data;
- struct sg_page_iter iter;
-
- for_each_sgtable_page(sgt, &iter, 0)
- set_memory_wb(sg_wc_address(&iter), 1);
- snd_dma_noncontig_free(dmab);
-}
-
-static int snd_dma_sg_wc_mmap(struct snd_dma_buffer *dmab,
- struct vm_area_struct *area)
-{
- area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
- return dma_mmap_noncontiguous(dmab->dev.dev, area,
- dmab->bytes, dmab->private_data);
-}
-
-static const struct snd_malloc_ops snd_dma_sg_wc_ops = {
- .alloc = snd_dma_sg_wc_alloc,
- .free = snd_dma_sg_wc_free,
- .mmap = snd_dma_sg_wc_mmap,
- .sync = snd_dma_noncontig_sync,
- .get_addr = snd_dma_noncontig_get_addr,
- .get_page = snd_dma_noncontig_get_page,
- .get_chunk_size = snd_dma_noncontig_get_chunk_size,
-};
-
/* Fallback SG-buffer allocations for x86 */
struct snd_dma_sg_fallback {
- bool use_dma_alloc_coherent;
+ struct sg_table sgt; /* used by get_addr - must be the first item */
size_t count;
struct page **pages;
- /* DMA address array; the first page contains #pages in ~PAGE_MASK */
- dma_addr_t *addrs;
+ unsigned int *npages;
};
static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab,
struct snd_dma_sg_fallback *sgbuf)
{
+ bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG;
size_t i, size;
- if (sgbuf->pages && sgbuf->addrs) {
+ if (sgbuf->pages && sgbuf->npages) {
i = 0;
while (i < sgbuf->count) {
- if (!sgbuf->pages[i] || !sgbuf->addrs[i])
- break;
- size = sgbuf->addrs[i] & ~PAGE_MASK;
- if (WARN_ON(!size))
+ size = sgbuf->npages[i];
+ if (!size)
break;
- if (sgbuf->use_dma_alloc_coherent)
- dma_free_coherent(dmab->dev.dev, size << PAGE_SHIFT,
- page_address(sgbuf->pages[i]),
- sgbuf->addrs[i] & PAGE_MASK);
- else
- do_free_pages(page_address(sgbuf->pages[i]),
- size << PAGE_SHIFT, false);
+ do_free_pages(page_address(sgbuf->pages[i]),
+ size << PAGE_SHIFT, wc);
i += size;
}
}
kvfree(sgbuf->pages);
- kvfree(sgbuf->addrs);
+ kvfree(sgbuf->npages);
kfree(sgbuf);
}
+/* fallback manual S/G buffer allocations */
static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
{
+ bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG;
struct snd_dma_sg_fallback *sgbuf;
struct page **pagep, *curp;
- size_t chunk, npages;
- dma_addr_t *addrp;
+ size_t chunk;
dma_addr_t addr;
+ unsigned int idx, npages;
void *p;
- /* correct the type */
- if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG)
- dmab->dev.type = SNDRV_DMA_TYPE_DEV_SG_FALLBACK;
- else if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
- dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
-
sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (!sgbuf)
return NULL;
- sgbuf->use_dma_alloc_coherent = cpu_feature_enabled(X86_FEATURE_XENPV);
size = PAGE_ALIGN(size);
sgbuf->count = size >> PAGE_SHIFT;
sgbuf->pages = kvcalloc(sgbuf->count, sizeof(*sgbuf->pages), GFP_KERNEL);
- sgbuf->addrs = kvcalloc(sgbuf->count, sizeof(*sgbuf->addrs), GFP_KERNEL);
- if (!sgbuf->pages || !sgbuf->addrs)
+ sgbuf->npages = kvcalloc(sgbuf->count, sizeof(*sgbuf->npages), GFP_KERNEL);
+ if (!sgbuf->pages || !sgbuf->npages)
goto error;
pagep = sgbuf->pages;
- addrp = sgbuf->addrs;
- chunk = (PAGE_SIZE - 1) << PAGE_SHIFT; /* to fit in low bits in addrs */
+ chunk = size;
+ idx = 0;
while (size > 0) {
chunk = min(size, chunk);
- if (sgbuf->use_dma_alloc_coherent)
- p = dma_alloc_coherent(dmab->dev.dev, chunk, &addr, DEFAULT_GFP);
- else
- p = do_alloc_pages(dmab->dev.dev, chunk, &addr, false);
+ p = do_alloc_pages(dmab->dev.dev, chunk, &addr, wc);
if (!p) {
if (chunk <= PAGE_SIZE)
goto error;
@@ -797,27 +746,33 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
size -= chunk;
/* fill pages */
npages = chunk >> PAGE_SHIFT;
- *addrp = npages; /* store in lower bits */
+ sgbuf->npages[idx] = npages;
+ idx += npages;
curp = virt_to_page(p);
- while (npages--) {
+ while (npages--)
*pagep++ = curp++;
- *addrp++ |= addr;
- addr += PAGE_SIZE;
- }
}
- p = vmap(sgbuf->pages, sgbuf->count, VM_MAP, PAGE_KERNEL);
- if (!p)
+ if (sg_alloc_table_from_pages(&sgbuf->sgt, sgbuf->pages, sgbuf->count,
+ 0, sgbuf->count << PAGE_SHIFT, GFP_KERNEL))
goto error;
- if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
- set_pages_array_wc(sgbuf->pages, sgbuf->count);
+ if (dma_map_sgtable(dmab->dev.dev, &sgbuf->sgt, DMA_BIDIRECTIONAL, 0))
+ goto error_dma_map;
+
+ p = vmap(sgbuf->pages, sgbuf->count, VM_MAP, PAGE_KERNEL);
+ if (!p)
+ goto error_vmap;
dmab->private_data = sgbuf;
/* store the first page address for convenience */
- dmab->addr = sgbuf->addrs[0] & PAGE_MASK;
+ dmab->addr = snd_sgbuf_get_addr(dmab, 0);
return p;
+ error_vmap:
+ dma_unmap_sgtable(dmab->dev.dev, &sgbuf->sgt, DMA_BIDIRECTIONAL, 0);
+ error_dma_map:
+ sg_free_table(&sgbuf->sgt);
error:
__snd_dma_sg_fallback_free(dmab, sgbuf);
return NULL;
@@ -827,36 +782,46 @@ static void snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab)
{
struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
- if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
- set_pages_array_wb(sgbuf->pages, sgbuf->count);
vunmap(dmab->area);
+ dma_unmap_sgtable(dmab->dev.dev, &sgbuf->sgt, DMA_BIDIRECTIONAL, 0);
+ sg_free_table(&sgbuf->sgt);
__snd_dma_sg_fallback_free(dmab, dmab->private_data);
}
-static dma_addr_t snd_dma_sg_fallback_get_addr(struct snd_dma_buffer *dmab,
- size_t offset)
-{
- struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
- size_t index = offset >> PAGE_SHIFT;
-
- return (sgbuf->addrs[index] & PAGE_MASK) | (offset & ~PAGE_MASK);
-}
-
static int snd_dma_sg_fallback_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
- if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
+ if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return vm_map_pages(area, sgbuf->pages, sgbuf->count);
}
-static const struct snd_malloc_ops snd_dma_sg_fallback_ops = {
- .alloc = snd_dma_sg_fallback_alloc,
+static void *snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size)
+{
+ int type = dmab->dev.type;
+ void *p;
+
+ /* try the standard DMA API allocation at first */
+ if (type == SNDRV_DMA_TYPE_DEV_WC_SG)
+ dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC;
+ else
+ dmab->dev.type = SNDRV_DMA_TYPE_DEV;
+ p = __snd_dma_alloc_pages(dmab, size);
+ if (p)
+ return p;
+
+ dmab->dev.type = type; /* restore the type */
+ return snd_dma_sg_fallback_alloc(dmab, size);
+}
+
+static const struct snd_malloc_ops snd_dma_sg_ops = {
+ .alloc = snd_dma_sg_alloc,
.free = snd_dma_sg_fallback_free,
.mmap = snd_dma_sg_fallback_mmap,
- .get_addr = snd_dma_sg_fallback_get_addr,
+ /* reuse noncontig helper */
+ .get_addr = snd_dma_noncontig_get_addr,
/* reuse vmalloc helpers */
.get_page = snd_dma_vmalloc_get_page,
.get_chunk_size = snd_dma_vmalloc_get_chunk_size,
@@ -927,15 +892,12 @@ static const struct snd_malloc_ops *snd_dma_ops[] = {
[SNDRV_DMA_TYPE_NONCONTIG] = &snd_dma_noncontig_ops,
[SNDRV_DMA_TYPE_NONCOHERENT] = &snd_dma_noncoherent_ops,
#ifdef CONFIG_SND_DMA_SGBUF
- [SNDRV_DMA_TYPE_DEV_WC_SG] = &snd_dma_sg_wc_ops,
+ [SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops,
+ [SNDRV_DMA_TYPE_DEV_WC_SG] = &snd_dma_sg_ops,
#endif
#ifdef CONFIG_GENERIC_ALLOCATOR
[SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops,
#endif /* CONFIG_GENERIC_ALLOCATOR */
-#ifdef CONFIG_SND_DMA_SGBUF
- [SNDRV_DMA_TYPE_DEV_SG_FALLBACK] = &snd_dma_sg_fallback_ops,
- [SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK] = &snd_dma_sg_fallback_ops,
-#endif
#endif /* CONFIG_HAS_DMA */
};
diff --git a/sound/core/memalloc_local.h b/sound/core/memalloc_local.h
deleted file mode 100644
index 8b19f3a68a4b..000000000000
--- a/sound/core/memalloc_local.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#ifndef __MEMALLOC_LOCAL_H
-#define __MEMALLOC_LOCAL_H
-
-struct snd_malloc_ops {
- void *(*alloc)(struct snd_dma_buffer *dmab, size_t size);
- void (*free)(struct snd_dma_buffer *dmab);
- dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset);
- struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset);
- unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab,
- unsigned int ofs, unsigned int size);
- int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area);
- void (*sync)(struct snd_dma_buffer *dmab, enum snd_dma_sync_mode mode);
-};
-
-#endif /* __MEMALLOC_LOCAL_H */
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 5d894dc32f7d..d683442b4c97 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -9,6 +9,7 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <sound/core.h>
+#include <sound/pcm.h>
/**
* copy_to_user_fromio - copy data from mmio-space to user-space
@@ -22,25 +23,50 @@
*/
int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
{
+ struct iov_iter iter;
+
+ if (import_ubuf(ITER_DEST, dst, count, &iter))
+ return -EFAULT;
+ 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
+ * @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: number of bytes to be copied
+ */
+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_user(dst, (const void __force*)src, count) ? -EFAULT : 0;
+ 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_user(dst, buf, c))
- return -EFAULT;
+ if (copy_to_iter(buf, c, dst) != c)
+ return res;
count -= c;
- dst += c;
src += c;
+ res += c;
}
- return 0;
+ return res;
#endif
}
-EXPORT_SYMBOL(copy_to_user_fromio);
+EXPORT_SYMBOL(copy_to_iter_fromio);
/**
* copy_from_user_toio - copy data from user-space to mmio-space
@@ -54,22 +80,47 @@ EXPORT_SYMBOL(copy_to_user_fromio);
*/
int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
{
+ struct iov_iter iter;
+
+ if (import_ubuf(ITER_SOURCE, (void __user *)src, count, &iter))
+ return -EFAULT;
+ 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
+ * @count: the data size to copy in bytes
+ * @src: the source iov_iter
+ *
+ * Copies the data from iov_iter to mmio-space.
+ *
+ * Return: number of bytes to be copied
+ */
+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_user((void __force *)dst, src, count) ? -EFAULT : 0;
+ 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_user(buf, src, c))
- return -EFAULT;
+ if (copy_from_iter(buf, c, src) != c)
+ return res;
memcpy_toio(dst, buf, c);
count -= c;
dst += c;
- src += c;
+ res += c;
}
- return 0;
+ return res;
#endif
}
-EXPORT_SYMBOL(copy_from_user_toio);
+EXPORT_SYMBOL(copy_from_iter_toio);
diff --git a/sound/core/misc.c b/sound/core/misc.c
index d32a19976a2b..88d9e1f9a6e9 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -13,20 +13,6 @@
#include <linux/fs.h>
#include <sound/core.h>
-#ifdef CONFIG_SND_DEBUG
-
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-#define DEFAULT_DEBUG_LEVEL 2
-#else
-#define DEFAULT_DEBUG_LEVEL 1
-#endif
-
-static int debug = DEFAULT_DEBUG_LEVEL;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level (0 = disable)");
-
-#endif /* CONFIG_SND_DEBUG */
-
void release_and_free_resource(struct resource *res)
{
if (res) {
@@ -36,63 +22,6 @@ void release_and_free_resource(struct resource *res)
}
EXPORT_SYMBOL(release_and_free_resource);
-#ifdef CONFIG_SND_VERBOSE_PRINTK
-/* strip the leading path if the given path is absolute */
-static const char *sanity_file_name(const char *path)
-{
- if (*path == '/')
- return strrchr(path, '/') + 1;
- else
- return path;
-}
-#endif
-
-#if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK)
-void __snd_printk(unsigned int level, const char *path, int line,
- const char *format, ...)
-{
- va_list args;
-#ifdef CONFIG_SND_VERBOSE_PRINTK
- int kern_level;
- struct va_format vaf;
- char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
- bool level_found = false;
-#endif
-
-#ifdef CONFIG_SND_DEBUG
- if (debug < level)
- return;
-#endif
-
- va_start(args, format);
-#ifdef CONFIG_SND_VERBOSE_PRINTK
- vaf.fmt = format;
- vaf.va = &args;
-
- while ((kern_level = printk_get_level(vaf.fmt)) != 0) {
- const char *end_of_header = printk_skip_level(vaf.fmt);
-
- /* Ignore KERN_CONT. We print filename:line for each piece. */
- if (kern_level >= '0' && kern_level <= '7') {
- memcpy(verbose_fmt, vaf.fmt, end_of_header - vaf.fmt);
- level_found = true;
- }
-
- vaf.fmt = end_of_header;
- }
-
- if (!level_found && level)
- memcpy(verbose_fmt, KERN_DEBUG, sizeof(KERN_DEBUG) - 1);
-
- printk(verbose_fmt, sanity_file_name(path), line, &vaf);
-#else
- vprintk(format, args);
-#endif
- va_end(args);
-}
-EXPORT_SYMBOL_GPL(__snd_printk);
-#endif
-
#ifdef CONFIG_PCI
#include <linux/pci.h>
/**
@@ -198,35 +127,30 @@ int snd_fasync_helper(int fd, struct file *file, int on,
INIT_LIST_HEAD(&fasync->list);
}
- spin_lock_irq(&snd_fasync_lock);
- if (*fasyncp) {
- kfree(fasync);
- fasync = *fasyncp;
- } else {
- if (!fasync) {
- spin_unlock_irq(&snd_fasync_lock);
- return 0;
+ scoped_guard(spinlock_irq, &snd_fasync_lock) {
+ if (*fasyncp) {
+ kfree(fasync);
+ fasync = *fasyncp;
+ } else {
+ if (!fasync)
+ return 0;
+ *fasyncp = fasync;
}
- *fasyncp = fasync;
+ fasync->on = on;
}
- fasync->on = on;
- spin_unlock_irq(&snd_fasync_lock);
return fasync_helper(fd, file, on, &fasync->fasync);
}
EXPORT_SYMBOL_GPL(snd_fasync_helper);
void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll)
{
- unsigned long flags;
-
if (!fasync || !fasync->on)
return;
- spin_lock_irqsave(&snd_fasync_lock, flags);
+ guard(spinlock_irqsave)(&snd_fasync_lock);
fasync->signal = signal;
fasync->poll = poll;
list_move(&fasync->list, &snd_fasync_list);
schedule_work(&snd_fasync_work);
- spin_unlock_irqrestore(&snd_fasync_lock, flags);
}
EXPORT_SYMBOL_GPL(snd_kill_fasync);
diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile
index ae25edcc3b42..d5f48ae6ba96 100644
--- a/sound/core/oss/Makefile
+++ b/sound/core/oss/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
-snd-mixer-oss-objs := mixer_oss.o
+snd-mixer-oss-y := mixer_oss.o
snd-pcm-oss-y := pcm_oss.o
snd-pcm-oss-$(CONFIG_SND_PCM_OSS_PLUGINS) += pcm_plugin.o \
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 9620115cfdc0..e839a4bb93f8 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -130,13 +130,12 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume || pslot->put_recsrc)
result |= 1 << chn;
}
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -148,13 +147,12 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
if (pslot->put_volume && pslot->stereo)
result |= 1 << chn;
}
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -165,7 +163,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
result = mixer->mask_recsrc;
} else {
@@ -177,7 +175,6 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
result |= 1 << chn;
}
}
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -188,12 +185,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
if (mixer == NULL)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
unsigned int index;
result = mixer->get_recsrc(fmixer, &index);
if (result < 0)
- goto unlock;
+ return result;
result = 1 << index;
} else {
struct snd_mixer_oss_slot *pslot;
@@ -209,8 +206,6 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
}
}
mixer->oss_recsrc = result;
- unlock:
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -224,7 +219,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
if (mixer == NULL)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
if (recsrc & ~mixer->oss_recsrc)
recsrc &= ~mixer->oss_recsrc;
@@ -250,7 +245,6 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
}
}
}
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -262,7 +256,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
if (mixer == NULL || slot > 30)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
left = pslot->volume[0];
right = pslot->volume[1];
@@ -270,21 +264,15 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
result = pslot->get_volume(fmixer, pslot, &left, &right);
if (!pslot->stereo)
right = left;
- if (snd_BUG_ON(left < 0 || left > 100)) {
- result = -EIO;
- goto unlock;
- }
- if (snd_BUG_ON(right < 0 || right > 100)) {
- result = -EIO;
- goto unlock;
- }
+ if (snd_BUG_ON(left < 0 || left > 100))
+ return -EIO;
+ if (snd_BUG_ON(right < 0 || right > 100))
+ return -EIO;
if (result >= 0) {
pslot->volume[0] = left;
pslot->volume[1] = right;
result = (left & 0xff) | ((right & 0xff) << 8);
}
- unlock:
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -297,7 +285,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (mixer == NULL || slot > 30)
return -EIO;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
pslot = &mixer->slots[slot];
if (left > 100)
left = 100;
@@ -308,12 +296,10 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
if (pslot->put_volume)
result = pslot->put_volume(fmixer, pslot, left, right);
if (result < 0)
- goto unlock;
+ return result;
pslot->volume[0] = left;
pslot->volume[1] = right;
result = (left & 0xff) | ((right & 0xff) << 8);
- unlock:
- mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -426,7 +412,6 @@ static const struct file_operations snd_mixer_oss_f_ops =
.owner = THIS_MODULE,
.open = snd_mixer_oss_open,
.release = snd_mixer_oss_release,
- .llseek = no_llseek,
.unlocked_ioctl = snd_mixer_oss_ioctl,
.compat_ioctl = snd_mixer_oss_ioctl_compat,
};
@@ -532,37 +517,31 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
unsigned int numid,
int *left, int *right)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid(card, numid);
- if (!kctl) {
- up_read(&card->controls_rwsem);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (kctl->get(kctl, uctl))
- goto __unalloc;
+ return;
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
- goto __unalloc;
+ return;
*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
if (uinfo->count > 1)
*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
@@ -571,27 +550,25 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
int *left, int *right,
int route)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid(card, numid);
- if (!kctl) {
- up_read(&card->controls_rwsem);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (kctl->get(kctl, uctl))
- goto __unalloc;
+ return;
if (!uctl->value.integer.value[0]) {
*left = 0;
if (uinfo->count == 1)
@@ -599,10 +576,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
}
if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
*right = 0;
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
@@ -636,41 +609,35 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
unsigned int numid,
int left, int right)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
int res;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid(card, numid);
- if (!kctl) {
- up_read(&card->controls_rwsem);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
- goto __unalloc;
+ return;
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
if (uinfo->count > 1)
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
res = kctl->put(kctl, uctl);
if (res < 0)
- goto __unalloc;
+ return;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
@@ -679,26 +646,24 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
int left, int right,
int route)
{
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
struct snd_kcontrol *kctl;
struct snd_card *card = fmixer->card;
int res;
if (numid == ID_UNKNOWN)
return;
- down_read(&card->controls_rwsem);
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid(card, numid);
- if (!kctl) {
- up_read(&card->controls_rwsem);
+ if (!kctl)
return;
- }
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL)
- goto __unalloc;
+ return;
if (kctl->info(kctl, uinfo))
- goto __unalloc;
+ return;
if (uinfo->count > 1) {
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
@@ -711,13 +676,9 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
}
res = kctl->put(kctl, uctl);
if (res < 0)
- goto __unalloc;
+ return;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- __unalloc:
- up_read(&card->controls_rwsem);
- kfree(uctl);
- kfree(uinfo);
}
static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
@@ -822,28 +783,24 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *pslot;
struct slot *slot;
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err, idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
- if (uinfo == NULL || uctl == NULL) {
- err = -ENOMEM;
- goto __free_only;
- }
- down_read(&card->controls_rwsem);
+ if (uinfo == NULL || uctl == NULL)
+ return -ENOMEM;
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
- if (! kctl) {
- err = -ENOENT;
- goto __unlock;
- }
+ if (!kctl)
+ return -ENOENT;
err = kctl->info(kctl, uinfo);
if (err < 0)
- goto __unlock;
+ return err;
err = kctl->get(kctl, uctl);
if (err < 0)
- goto __unlock;
+ return err;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
@@ -858,13 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
break;
}
}
- err = 0;
- __unlock:
- up_read(&card->controls_rwsem);
- __free_only:
- kfree(uctl);
- kfree(uinfo);
- return err;
+ return 0;
}
static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
@@ -874,26 +825,22 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *pslot;
struct slot *slot = NULL;
- struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err;
unsigned int idx;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
- if (uinfo == NULL || uctl == NULL) {
- err = -ENOMEM;
- goto __free_only;
- }
- down_read(&card->controls_rwsem);
+ if (uinfo == NULL || uctl == NULL)
+ return -ENOMEM;
+ guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
- if (! kctl) {
- err = -ENOENT;
- goto __unlock;
- }
+ if (!kctl)
+ return -ENOENT;
err = kctl->info(kctl, uinfo);
if (err < 0)
- goto __unlock;
+ return err;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
@@ -907,20 +854,14 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
break;
slot = NULL;
}
- if (! slot)
- goto __unlock;
+ if (!slot)
+ return 0;
for (idx = 0; idx < uinfo->count; idx++)
uctl->value.enumerated.item[idx] = slot->capture_item;
err = kctl->put(kctl, uctl);
if (err > 0)
snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
- err = 0;
- __unlock:
- up_read(&card->controls_rwsem);
- __free_only:
- kfree(uctl);
- kfree(uinfo);
- return err;
+ return 0;
}
struct snd_mixer_oss_assign_table {
@@ -931,34 +872,26 @@ struct snd_mixer_oss_assign_table {
static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
{
- struct snd_ctl_elem_info *info;
+ struct snd_ctl_elem_info *info __free(kfree) = NULL;
struct snd_kcontrol *kcontrol;
struct snd_card *card = mixer->card;
int err;
- down_read(&card->controls_rwsem);
- kcontrol = snd_mixer_oss_test_id(mixer, name, index);
- if (kcontrol == NULL) {
- up_read(&card->controls_rwsem);
- return 0;
- }
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (! info) {
- up_read(&card->controls_rwsem);
- return -ENOMEM;
- }
- err = kcontrol->info(kcontrol, info);
- if (err < 0) {
- up_read(&card->controls_rwsem);
- kfree(info);
- return err;
+ scoped_guard(rwsem_read, &card->controls_rwsem) {
+ kcontrol = snd_mixer_oss_test_id(mixer, name, index);
+ if (kcontrol == NULL)
+ return 0;
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ err = kcontrol->info(kcontrol, info);
+ if (err < 0)
+ return err;
+ slot->numid[item] = kcontrol->id.numid;
}
- slot->numid[item] = kcontrol->id.numid;
- up_read(&card->controls_rwsem);
if (info->count > slot->channels)
slot->channels = info->count;
slot->present |= 1 << item;
- kfree(info);
return 0;
}
@@ -967,8 +900,8 @@ static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
struct slot *p = chn->private_data;
if (p) {
if (p->allocated && p->assigned) {
- kfree_const(p->assigned->name);
- kfree_const(p->assigned);
+ kfree(p->assigned->name);
+ kfree(p->assigned);
}
kfree(p);
}
@@ -1058,7 +991,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
struct slot *pslot;
struct snd_kcontrol *kctl;
struct snd_mixer_oss_slot *rslot;
- char str[64];
+ const char *str;
/* check if already assigned */
if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
@@ -1068,49 +1001,39 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
return 0;
- down_read(&mixer->card->controls_rwsem);
+ guard(rwsem_read)(&mixer->card->controls_rwsem);
kctl = NULL;
if (!ptr->index)
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
if (kctl) {
- struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
- if (! uinfo) {
- up_read(&mixer->card->controls_rwsem);
+ if (!uinfo)
return -ENOMEM;
- }
- if (kctl->info(kctl, uinfo)) {
- up_read(&mixer->card->controls_rwsem);
- kfree(uinfo);
+ if (kctl->info(kctl, uinfo))
return 0;
- }
- strcpy(str, ptr->name);
+ str = ptr->name;
if (!strcmp(str, "Master"))
- strcpy(str, "Mix");
- if (!strcmp(str, "Master Mono"))
- strcpy(str, "Mix Mono");
+ str = "Mix";
+ else if (!strcmp(str, "Master Mono"))
+ str = "Mix Mono";
slot.capture_item = 0;
if (!strcmp(uinfo->value.enumerated.name, str)) {
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
} else {
for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
uinfo->value.enumerated.item = slot.capture_item;
- if (kctl->info(kctl, uinfo)) {
- up_read(&mixer->card->controls_rwsem);
- kfree(uinfo);
+ if (kctl->info(kctl, uinfo))
return 0;
- }
if (!strcmp(uinfo->value.enumerated.name, str)) {
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
break;
}
}
}
- kfree(uinfo);
}
- up_read(&mixer->card->controls_rwsem);
if (slot.present != 0) {
pslot = kmalloc(sizeof(slot), GFP_KERNEL);
if (! pslot)
@@ -1183,7 +1106,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
struct snd_mixer_oss *mixer = entry->private_data;
int i;
- mutex_lock(&mixer->reg_mutex);
+ guard(mutex)(&mixer->reg_mutex);
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
struct slot *p;
@@ -1198,7 +1121,6 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
else
snd_iprintf(buffer, "\"\" 0\n");
}
- mutex_unlock(&mixer->reg_mutex);
}
static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@@ -1225,9 +1147,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
cptr = snd_info_get_str(str, cptr, sizeof(str));
if (! *str) {
/* remove the entry */
- mutex_lock(&mixer->reg_mutex);
- mixer_slot_clear(&mixer->slots[ch]);
- mutex_unlock(&mixer->reg_mutex);
+ scoped_guard(mutex, &mixer->reg_mutex)
+ mixer_slot_clear(&mixer->slots[ch]);
continue;
}
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
@@ -1236,28 +1157,27 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
continue;
}
- mutex_lock(&mixer->reg_mutex);
- slot = (struct slot *)mixer->slots[ch].private_data;
- if (slot && slot->assigned &&
- slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
- /* not changed */
- goto __unlock;
- tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
- if (!tbl)
- goto __unlock;
- tbl->oss_id = ch;
- tbl->name = kstrdup(str, GFP_KERNEL);
- if (! tbl->name) {
- kfree(tbl);
- goto __unlock;
- }
- tbl->index = idx;
- if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
- kfree(tbl->name);
- kfree(tbl);
+ scoped_guard(mutex, &mixer->reg_mutex) {
+ slot = (struct slot *)mixer->slots[ch].private_data;
+ if (slot && slot->assigned &&
+ slot->assigned->index == idx && !strcmp(slot->assigned->name, str))
+ /* not changed */
+ break;
+ tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
+ if (!tbl)
+ break;
+ tbl->oss_id = ch;
+ tbl->name = kstrdup(str, GFP_KERNEL);
+ if (!tbl->name) {
+ kfree(tbl);
+ break;
+ }
+ tbl->index = idx;
+ if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
+ kfree(tbl->name);
+ kfree(tbl);
+ }
}
- __unlock:
- mutex_unlock(&mixer->reg_mutex);
}
}
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 728c211142d1..a82dd155e1d3 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -377,7 +377,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
snd_pcm_hw_param_t var, unsigned int best,
int *dir)
{
- struct snd_pcm_hw_params *save = NULL;
+ struct snd_pcm_hw_params *save __free(kfree) = NULL;
int v;
unsigned int saved_min;
int last = 0;
@@ -404,38 +404,30 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
saved_min = min;
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
if (min >= 0) {
- struct snd_pcm_hw_params *params1;
+ struct snd_pcm_hw_params *params1 __free(kfree) = NULL;
if (max < 0)
goto _end;
if ((unsigned int)min == saved_min && mindir == valdir)
goto _end;
params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
- if (params1 == NULL) {
- kfree(save);
+ if (params1 == NULL)
return -ENOMEM;
- }
*params1 = *save;
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
- if (max < 0) {
- kfree(params1);
+ if (max < 0)
goto _end;
- }
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
*params = *params1;
last = 1;
}
- kfree(params1);
} else {
*params = *save;
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
- if (max < 0) {
- kfree(save);
+ if (max < 0)
return max;
- }
last = 1;
}
_end:
- kfree(save);
if (last)
v = snd_pcm_hw_param_last(pcm, params, var, dir);
else
@@ -789,7 +781,7 @@ static int choose_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, unsigned int best_rate)
{
const struct snd_interval *it;
- struct snd_pcm_hw_params *save;
+ struct snd_pcm_hw_params *save __free(kfree) = NULL;
unsigned int rate, prev;
save = kmalloc(sizeof(*save), GFP_KERNEL);
@@ -808,10 +800,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
ret = snd_pcm_hw_param_set(substream, params,
SNDRV_PCM_HW_PARAM_RATE,
rate, 0);
- if (ret == (int)rate) {
- kfree(save);
+ if (ret == (int)rate)
return rate;
- }
*params = *save;
}
prev = rate;
@@ -821,7 +811,6 @@ static int choose_rate(struct snd_pcm_substream *substream,
}
/* not found, use the nearest rate */
- kfree(save);
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
}
@@ -1085,8 +1074,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
runtime->oss.params = 0;
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
- if (runtime->dma_area)
- snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
+ snd_pcm_runtime_buffer_set_silence(runtime);
runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
@@ -1634,9 +1622,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
break;
result = 0;
set_current_state(TASK_INTERRUPTIBLE);
- snd_pcm_stream_lock_irq(substream);
- state = runtime->state;
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream)
+ state = runtime->state;
if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING);
break;
@@ -1847,7 +1834,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
int direct;
- struct snd_pcm_hw_params *params;
+ struct snd_pcm_hw_params *params __free(kfree) = NULL;
unsigned int formats = 0;
const struct snd_mask *format_mask;
int fmt;
@@ -1873,7 +1860,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
_snd_pcm_hw_params_any(params);
err = snd_pcm_hw_refine(substream, params);
if (err < 0)
- goto error;
+ return err;
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
for (fmt = 0; fmt < 32; ++fmt) {
if (snd_mask_test(format_mask, fmt)) {
@@ -1883,9 +1870,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
}
}
- error:
- kfree(params);
- return err < 0 ? err : formats;
+ return formats;
}
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
@@ -2017,9 +2002,8 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig
static int snd_pcm_oss_nonblock(struct file * file)
{
- spin_lock(&file->f_lock);
+ guard(spinlock)(&file->f_lock);
file->f_flags |= O_NONBLOCK;
- spin_unlock(&file->f_lock);
return 0;
}
@@ -2347,7 +2331,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
{
struct snd_pcm_oss_setup *setup;
- mutex_lock(&pcm->streams[stream].oss.setup_mutex);
+ guard(mutex)(&pcm->streams[stream].oss.setup_mutex);
do {
for (setup = pcm->streams[stream].oss.setup_list; setup;
setup = setup->next) {
@@ -2358,7 +2342,6 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
out:
if (setup)
*rsetup = *setup;
- mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
}
static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
@@ -2853,23 +2836,23 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
if (psubstream != NULL) {
struct snd_pcm_runtime *runtime = psubstream->runtime;
poll_wait(file, &runtime->sleep, wait);
- snd_pcm_stream_lock_irq(psubstream);
- if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
- (runtime->state != SNDRV_PCM_STATE_RUNNING ||
- snd_pcm_oss_playback_ready(psubstream)))
- mask |= EPOLLOUT | EPOLLWRNORM;
- snd_pcm_stream_unlock_irq(psubstream);
+ scoped_guard(pcm_stream_lock_irq, psubstream) {
+ if (runtime->state != SNDRV_PCM_STATE_DRAINING &&
+ (runtime->state != SNDRV_PCM_STATE_RUNNING ||
+ snd_pcm_oss_playback_ready(psubstream)))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+ }
}
if (csubstream != NULL) {
struct snd_pcm_runtime *runtime = csubstream->runtime;
snd_pcm_state_t ostate;
poll_wait(file, &runtime->sleep, wait);
- snd_pcm_stream_lock_irq(csubstream);
- ostate = runtime->state;
- if (ostate != SNDRV_PCM_STATE_RUNNING ||
- snd_pcm_oss_capture_ready(csubstream))
- mask |= EPOLLIN | EPOLLRDNORM;
- snd_pcm_stream_unlock_irq(csubstream);
+ scoped_guard(pcm_stream_lock_irq, csubstream) {
+ ostate = runtime->state;
+ if (ostate != SNDRV_PCM_STATE_RUNNING ||
+ snd_pcm_oss_capture_ready(csubstream))
+ mask |= EPOLLIN | EPOLLRDNORM;
+ }
if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
struct snd_pcm_oss_file ofile;
memset(&ofile, 0, sizeof(ofile));
@@ -2964,7 +2947,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
{
struct snd_pcm_str *pstr = entry->private_data;
struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
- mutex_lock(&pstr->oss.setup_mutex);
+ guard(mutex)(&pstr->oss.setup_mutex);
while (setup) {
snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
setup->task_name,
@@ -2978,7 +2961,6 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
setup->nosilence ? " no-silence" : "");
setup = setup->next;
}
- mutex_unlock(&pstr->oss.setup_mutex);
}
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
@@ -3004,12 +2986,11 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
struct snd_pcm_oss_setup *setup, *setup1, template;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
- mutex_lock(&pstr->oss.setup_mutex);
+ guard(mutex)(&pstr->oss.setup_mutex);
memset(&template, 0, sizeof(template));
ptr = snd_info_get_str(task_name, line, sizeof(task_name));
if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
snd_pcm_oss_proc_free_setup_list(pstr);
- mutex_unlock(&pstr->oss.setup_mutex);
continue;
}
for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -3049,7 +3030,6 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
setup = kmalloc(sizeof(*setup), GFP_KERNEL);
if (! setup) {
buffer->error = -ENOMEM;
- mutex_unlock(&pstr->oss.setup_mutex);
return;
}
if (pstr->oss.setup_list == NULL)
@@ -3063,12 +3043,10 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
if (! template.task_name) {
kfree(setup);
buffer->error = -ENOMEM;
- mutex_unlock(&pstr->oss.setup_mutex);
return;
}
}
*setup = template;
- mutex_unlock(&pstr->oss.setup_mutex);
}
}
@@ -3126,7 +3104,6 @@ static const struct file_operations snd_pcm_oss_f_reg =
.write = snd_pcm_oss_write,
.open = snd_pcm_oss_open,
.release = snd_pcm_oss_release,
- .llseek = no_llseek,
.poll = snd_pcm_oss_poll,
.unlocked_ioctl = snd_pcm_oss_ioctl,
.compat_ioctl = snd_pcm_oss_ioctl_compat,
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index 50a6b50f5db4..7b76cf64157e 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -74,7 +74,6 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *handle,
size_t extra,
struct snd_pcm_plugin **ret);
int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin);
-int snd_pcm_plugin_clear(struct snd_pcm_plugin **first);
int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames);
snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size);
snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size);
@@ -139,8 +138,6 @@ int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_channel,
size_t dst_offset,
size_t samples, snd_pcm_format_t format);
-void *snd_pcm_plug_buf_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t size);
-void snd_pcm_plug_buf_unlock(struct snd_pcm_substream *plug, void *ptr);
#else
static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
@@ -160,7 +157,7 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream,
void **bufs, snd_pcm_uframes_t frames);
#ifdef PLUGIN_DEBUG
-#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
+#define pdprintf(fmt, args...) pr_debug("plugin: " fmt, ##args)
#else
#define pdprintf(fmt, args...)
#endif
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 98269119347f..b56eeda5e30e 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -294,7 +294,7 @@ static int rate_action(struct snd_pcm_plugin *plugin,
default:
break;
}
- return 0; /* silenty ignore other actions */
+ return 0; /* silently ignore other actions */
}
int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 9d95e3731123..283aac441fa0 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -91,9 +91,8 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
if (get_user(device, (int __user *)arg))
return -EFAULT;
- mutex_lock(&register_mutex);
- device = snd_pcm_next(card, device);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_mutex)
+ device = snd_pcm_next(card, device);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
@@ -106,7 +105,6 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
struct snd_pcm *pcm;
struct snd_pcm_str *pstr;
struct snd_pcm_substream *substream;
- int err;
info = (struct snd_pcm_info __user *)arg;
if (get_user(device, &info->device))
@@ -118,35 +116,23 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
stream = array_index_nospec(stream, 2);
if (get_user(subdevice, &info->subdevice))
return -EFAULT;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
pcm = snd_pcm_get(card, device);
- if (pcm == NULL) {
- err = -ENXIO;
- goto _error;
- }
+ if (pcm == NULL)
+ return -ENXIO;
pstr = &pcm->streams[stream];
- if (pstr->substream_count == 0) {
- err = -ENOENT;
- goto _error;
- }
- if (subdevice >= pstr->substream_count) {
- err = -ENXIO;
- goto _error;
- }
+ if (pstr->substream_count == 0)
+ return -ENOENT;
+ if (subdevice >= pstr->substream_count)
+ return -ENXIO;
for (substream = pstr->substream; substream;
substream = substream->next)
if (substream->number == (int)subdevice)
break;
- if (substream == NULL) {
- err = -ENXIO;
- goto _error;
- }
- mutex_lock(&pcm->open_mutex);
- err = snd_pcm_info_user(substream, info);
- mutex_unlock(&pcm->open_mutex);
- _error:
- mutex_unlock(&register_mutex);
- return err;
+ if (substream == NULL)
+ return -ENXIO;
+ guard(mutex)(&pcm->open_mutex);
+ return snd_pcm_info_user(substream, info);
}
case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
{
@@ -211,6 +197,10 @@ static const char * const snd_pcm_format_names[] = {
FORMAT(DSD_U32_LE),
FORMAT(DSD_U16_BE),
FORMAT(DSD_U32_BE),
+ FORMAT(S20_LE),
+ FORMAT(S20_BE),
+ FORMAT(U20_LE),
+ FORMAT(U20_BE),
};
/**
@@ -221,9 +211,11 @@ static const char * const snd_pcm_format_names[] = {
*/
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
- if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
+ unsigned int format_num = (__force unsigned int)format;
+
+ if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num])
return "Unknown";
- return snd_pcm_format_names[(__force unsigned int)format];
+ return snd_pcm_format_names[format_num];
}
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
@@ -253,6 +245,7 @@ static const char * const snd_pcm_state_names[] = {
STATE(DRAINING),
STATE(PAUSED),
STATE(SUSPENDED),
+ STATE(DISCONNECTED),
};
static const char * const snd_pcm_access_names[] = {
@@ -265,6 +258,9 @@ static const char * const snd_pcm_access_names[] = {
static const char * const snd_pcm_subformat_names[] = {
SUBFORMAT(STD),
+ SUBFORMAT(MSBITS_MAX),
+ SUBFORMAT(MSBITS_20),
+ SUBFORMAT(MSBITS_24),
};
static const char * const snd_pcm_tstamp_mode_names[] = {
@@ -332,7 +328,7 @@ static const char *snd_pcm_oss_format_name(int format)
static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
struct snd_info_buffer *buffer)
{
- struct snd_pcm_info *info;
+ struct snd_pcm_info *info __free(kfree) = NULL;
int err;
if (! substream)
@@ -345,7 +341,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
err = snd_pcm_info(substream, info);
if (err < 0) {
snd_iprintf(buffer, "error %d\n", err);
- kfree(info);
return;
}
snd_iprintf(buffer, "card: %d\n", info->card);
@@ -359,7 +354,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
- kfree(info);
}
static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
@@ -381,15 +375,15 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
struct snd_pcm_substream *substream = entry->private_data;
struct snd_pcm_runtime *runtime;
- mutex_lock(&substream->pcm->open_mutex);
+ guard(mutex)(&substream->pcm->open_mutex);
runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- goto unlock;
+ return;
}
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- goto unlock;
+ return;
}
snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
@@ -408,8 +402,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
}
#endif
- unlock:
- mutex_unlock(&substream->pcm->open_mutex);
}
static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
@@ -418,15 +410,15 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
struct snd_pcm_substream *substream = entry->private_data;
struct snd_pcm_runtime *runtime;
- mutex_lock(&substream->pcm->open_mutex);
+ guard(mutex)(&substream->pcm->open_mutex);
runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- goto unlock;
+ return;
}
if (runtime->state == SNDRV_PCM_STATE_OPEN) {
snd_iprintf(buffer, "no setup\n");
- goto unlock;
+ return;
}
snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
@@ -436,8 +428,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
- unlock:
- mutex_unlock(&substream->pcm->open_mutex);
}
static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
@@ -448,17 +438,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
struct snd_pcm_status64 status;
int err;
- mutex_lock(&substream->pcm->open_mutex);
+ guard(mutex)(&substream->pcm->open_mutex);
runtime = substream->runtime;
if (!runtime) {
snd_iprintf(buffer, "closed\n");
- goto unlock;
+ return;
}
memset(&status, 0, sizeof(status));
err = snd_pcm_status64(substream, &status);
if (err < 0) {
snd_iprintf(buffer, "error %d\n", err);
- goto unlock;
+ return;
}
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
@@ -472,8 +462,9 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "-----\n");
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
- unlock:
- mutex_unlock(&substream->pcm->open_mutex);
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ snd_iprintf(buffer, "xrun_counter: %d\n", substream->xrun_counter);
+#endif
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -601,19 +592,17 @@ 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 = container_of(dev, struct snd_pcm_str, dev);
+ struct snd_pcm_str *pstr = dev_get_drvdata(dev);
if (!pstr->pcm->no_device_suspend)
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 */
@@ -650,11 +639,14 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
if (!substream_count)
return 0;
- snd_device_initialize(&pstr->dev, pcm->card);
- pstr->dev.groups = pcm_dev_attr_groups;
- pstr->dev.type = &pcm_dev_type;
- dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
+ err = snd_device_alloc(&pstr->dev, pcm->card);
+ if (err < 0)
+ return err;
+ dev_set_name(pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
+ pstr->dev->groups = pcm_dev_attr_groups;
+ pstr->dev->type = &pcm_dev_type;
+ dev_set_drvdata(pstr->dev, pstr);
if (!pcm->internal) {
err = snd_pcm_stream_proc_init(pstr);
@@ -814,9 +806,7 @@ static void free_chmap(struct snd_pcm_str *pstr)
if (pstr->chmap_kctl) {
struct snd_card *card = pstr->pcm->card;
- down_write(&card->controls_rwsem);
snd_ctl_remove(card, pstr->chmap_kctl);
- up_write(&card->controls_rwsem);
pstr->chmap_kctl = NULL;
}
}
@@ -847,7 +837,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
#endif
free_chmap(pstr);
if (pstr->substream_count)
- put_device(&pstr->dev);
+ put_device(pstr->dev);
}
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
@@ -981,6 +971,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
substream->pid = get_pid(task_pid(current));
pstr->substream_opened++;
*rsubstream = substream;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ substream->xrun_counter = 0;
+#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
return 0;
}
@@ -1000,9 +993,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
kfree(runtime->hw_constraints.rules);
/* Avoid concurrent access to runtime via PCM timer interface */
if (substream->timer) {
- spin_lock_irq(&substream->timer->lock);
- substream->runtime = NULL;
- spin_unlock_irq(&substream->timer->lock);
+ scoped_guard(spinlock_irq, &substream->timer->lock)
+ substream->runtime = NULL;
} else {
substream->runtime = NULL;
}
@@ -1017,7 +1009,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
static ssize_t pcm_class_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev);
+ struct snd_pcm_str *pstr = dev_get_drvdata(dev);
struct snd_pcm *pcm = pstr->pcm;
const char *str;
static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
@@ -1059,10 +1051,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
return -ENXIO;
pcm = device->device_data;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
err = snd_pcm_add(pcm);
if (err)
- goto unlock;
+ return err;
for (cidx = 0; cidx < 2; cidx++) {
int devtype = -1;
if (pcm->streams[cidx].substream == NULL)
@@ -1078,10 +1070,10 @@ static int snd_pcm_dev_register(struct snd_device *device)
/* register pcm */
err = snd_register_device(devtype, pcm->card, pcm->device,
&snd_pcm_f_ops[cidx], pcm,
- &pcm->streams[cidx].dev);
+ pcm->streams[cidx].dev);
if (err < 0) {
list_del_init(&pcm->list);
- goto unlock;
+ return err;
}
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -1089,9 +1081,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
}
pcm_call_notify(pcm, n_register);
-
- unlock:
- mutex_unlock(&register_mutex);
return err;
}
@@ -1101,8 +1090,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
struct snd_pcm_substream *substream;
int cidx;
- mutex_lock(&register_mutex);
- mutex_lock(&pcm->open_mutex);
+ guard(mutex)(&register_mutex);
+ guard(mutex)(&pcm->open_mutex);
wake_up(&pcm->open_wait);
list_del_init(&pcm->list);
@@ -1125,11 +1114,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
pcm_call_notify(pcm, n_disconnect);
for (cidx = 0; cidx < 2; cidx++) {
- snd_unregister_device(&pcm->streams[cidx].dev);
+ if (pcm->streams[cidx].dev)
+ snd_unregister_device(pcm->streams[cidx].dev);
free_chmap(&pcm->streams[cidx]);
}
- mutex_unlock(&pcm->open_mutex);
- mutex_unlock(&register_mutex);
return 0;
}
@@ -1154,7 +1142,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
!notify->n_unregister ||
!notify->n_disconnect))
return -EINVAL;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
if (nfree) {
list_del(&notify->list);
list_for_each_entry(pcm, &snd_pcm_devices, list)
@@ -1164,7 +1152,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
list_for_each_entry(pcm, &snd_pcm_devices, list)
notify->n_register(pcm);
}
- mutex_unlock(&register_mutex);
return 0;
}
EXPORT_SYMBOL(snd_pcm_notify);
@@ -1180,7 +1167,7 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
{
struct snd_pcm *pcm;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
list_for_each_entry(pcm, &snd_pcm_devices, list) {
snd_iprintf(buffer, "%02i-%02i: %s : %s",
pcm->card->number, pcm->device, pcm->id, pcm->name);
@@ -1192,7 +1179,6 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
snd_iprintf(buffer, "\n");
}
- mutex_unlock(&register_mutex);
}
static struct snd_info_entry *snd_pcm_proc_entry;
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 42c2ada8e888..54eb9bd8eb21 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -235,7 +235,7 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
int refine,
struct snd_pcm_hw_params32 __user *data32)
{
- struct snd_pcm_hw_params *data;
+ struct snd_pcm_hw_params *data __free(kfree) = NULL;
struct snd_pcm_runtime *runtime;
int err;
@@ -248,30 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
return -ENOMEM;
/* only fifo_size (RO from userspace) is different, so just copy all */
- if (copy_from_user(data, data32, sizeof(*data32))) {
- err = -EFAULT;
- goto error;
- }
+ if (copy_from_user(data, data32, sizeof(*data32)))
+ return -EFAULT;
- if (refine)
+ if (refine) {
err = snd_pcm_hw_refine(substream, data);
- else
+ if (err < 0)
+ return err;
+ err = fixup_unreferenced_params(substream, data);
+ } else {
err = snd_pcm_hw_params(substream, data);
+ }
if (err < 0)
- goto error;
+ return err;
if (copy_to_user(data32, data, sizeof(*data32)) ||
- put_user(data->fifo_size, &data32->fifo_size)) {
- err = -EFAULT;
- goto error;
- }
+ put_user(data->fifo_size, &data32->fifo_size))
+ return -EFAULT;
if (! refine) {
unsigned int new_boundary = recalculate_boundary(runtime);
if (new_boundary)
runtime->boundary = new_boundary;
}
- error:
- kfree(data);
return err;
}
@@ -334,7 +332,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
compat_caddr_t buf;
compat_caddr_t __user *bufptr;
u32 frames;
- void __user **bufs;
+ void __user **bufs __free(kfree) = NULL;
int err, ch, i;
if (! substream->runtime)
@@ -356,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
return -ENOMEM;
for (i = 0; i < ch; i++) {
u32 ptr;
- if (get_user(ptr, bufptr)) {
- kfree(bufs);
+ if (get_user(ptr, bufptr))
return -EFAULT;
- }
bufs[i] = compat_ptr(ptr);
bufptr++;
}
@@ -369,9 +365,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
err = snd_pcm_lib_readv(substream, bufs, frames);
if (err >= 0) {
if (put_user(err, &data32->result))
- err = -EFAULT;
+ return -EFAULT;
}
- kfree(bufs);
return err;
}
@@ -382,12 +377,10 @@ struct snd_pcm_mmap_status_x32 {
s32 pad1;
u32 hw_ptr;
u32 pad2; /* alignment */
- s64 tstamp_sec;
- s64 tstamp_nsec;
+ struct __snd_timespec64 tstamp;
snd_pcm_state_t suspended_state;
s32 pad3;
- s64 audio_tstamp_sec;
- s64 audio_tstamp_nsec;
+ struct __snd_timespec64 audio_tstamp;
} __packed;
struct snd_pcm_mmap_control_x32 {
@@ -423,9 +416,7 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
if (snd_BUG_ON(!runtime))
return -EINVAL;
- if (get_user(sflags, &src->flags) ||
- get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
- get_user(scontrol.avail_min, &src->c.control.avail_min))
+ if (snd_pcm_sync_ptr_get_user(sflags, scontrol, src))
return -EFAULT;
if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
@@ -437,33 +428,25 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
boundary = recalculate_boundary(runtime);
if (!boundary)
boundary = 0x7fffffff;
- snd_pcm_stream_lock_irq(substream);
- /* FIXME: we should consider the boundary for the sync from app */
- if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
- control->appl_ptr = scontrol.appl_ptr;
- else
- scontrol.appl_ptr = control->appl_ptr % boundary;
- if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
- control->avail_min = scontrol.avail_min;
- else
- scontrol.avail_min = control->avail_min;
- sstatus.state = status->state;
- sstatus.hw_ptr = status->hw_ptr % boundary;
- sstatus.tstamp = status->tstamp;
- sstatus.suspended_state = status->suspended_state;
- sstatus.audio_tstamp = status->audio_tstamp;
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ /* FIXME: we should consider the boundary for the sync from app */
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
+ control->appl_ptr = scontrol.appl_ptr;
+ else
+ scontrol.appl_ptr = control->appl_ptr % boundary;
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+ control->avail_min = scontrol.avail_min;
+ else
+ scontrol.avail_min = control->avail_min;
+ sstatus.state = status->state;
+ sstatus.hw_ptr = status->hw_ptr % boundary;
+ sstatus.tstamp = status->tstamp;
+ sstatus.suspended_state = status->suspended_state;
+ sstatus.audio_tstamp = status->audio_tstamp;
+ }
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
- if (put_user(sstatus.state, &src->s.status.state) ||
- put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
- put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
- put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
- put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
- put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
- put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
- put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
- put_user(scontrol.avail_min, &src->c.control.avail_min))
+ if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, src))
return -EFAULT;
return 0;
@@ -515,26 +498,24 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
if (err < 0)
return err;
}
- snd_pcm_stream_lock_irq(substream);
- if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
- err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
- if (err < 0) {
- snd_pcm_stream_unlock_irq(substream);
- return err;
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
+ err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
+ if (err < 0)
+ return err;
+ } else {
+ sync_cp->appl_ptr = control->appl_ptr;
}
- } else {
- sync_cp->appl_ptr = control->appl_ptr;
+ if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+ control->avail_min = sync_cp->avail_min;
+ else
+ sync_cp->avail_min = control->avail_min;
+ sync_ptr.s.status.state = status->state;
+ sync_ptr.s.status.hw_ptr = status->hw_ptr;
+ sync_ptr.s.status.tstamp = status->tstamp;
+ sync_ptr.s.status.suspended_state = status->suspended_state;
+ sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
}
- if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
- control->avail_min = sync_cp->avail_min;
- else
- sync_cp->avail_min = control->avail_min;
- sync_ptr.s.status.state = status->state;
- sync_ptr.s.status.hw_ptr = status->hw_ptr;
- sync_ptr.s.status.tstamp = status->tstamp;
- sync_ptr.s.status.suspended_state = status->suspended_state;
- sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
- snd_pcm_stream_unlock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index 494ec0c207fa..f0c17503df42 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -111,6 +111,7 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config->dst_addr = dma_data->addr;
slave_config->dst_maxburst = dma_data->maxburst;
+ slave_config->dst_port_window_size = dma_data->port_window_size;
if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)
slave_config->dst_addr_width =
DMA_SLAVE_BUSWIDTH_UNDEFINED;
@@ -119,6 +120,7 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
} else {
slave_config->src_addr = dma_data->addr;
slave_config->src_maxburst = dma_data->maxburst;
+ slave_config->src_port_window_size = dma_data->port_window_size;
if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)
slave_config->src_addr_width =
DMA_SLAVE_BUSWIDTH_UNDEFINED;
@@ -328,26 +330,36 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
-/**
- * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
- * @substream: PCM substream
- * @filter_fn: Filter function used to request the DMA channel
- * @filter_data: Data passed to the DMA filter function
- *
- * This function will request a DMA channel using the passed filter function and
- * data. The function should usually be called from the pcm open callback. Note
- * that this function will use private_data field of the substream's runtime. So
- * it is not available to your pcm driver implementation.
- *
- * Return: 0 on success, a negative error code otherwise
- */
-int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
- dma_filter_fn filter_fn, void *filter_data)
+int snd_dmaengine_pcm_sync_stop(struct snd_pcm_substream *substream)
{
- return snd_dmaengine_pcm_open(substream,
- snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+ if (status != DMA_PAUSED)
+ dmaengine_synchronize(prtd->dma_chan);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_sync_stop);
+
+static void __snd_dmaengine_pcm_close(struct snd_pcm_substream *substream,
+ bool release_channel)
+{
+ struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+ if (status == DMA_PAUSED)
+ dmaengine_terminate_async(prtd->dma_chan);
+
+ dmaengine_synchronize(prtd->dma_chan);
+ if (release_channel)
+ dma_release_channel(prtd->dma_chan);
+ kfree(prtd);
}
-EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
/**
* snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
@@ -357,11 +369,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
*/
int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{
- struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-
- dmaengine_synchronize(prtd->dma_chan);
- kfree(prtd);
-
+ __snd_dmaengine_pcm_close(substream, false);
return 0;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
@@ -377,12 +385,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
*/
int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
{
- struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-
- dmaengine_synchronize(prtd->dma_chan);
- dma_release_channel(prtd->dma_chan);
- kfree(prtd);
-
+ __snd_dmaengine_pcm_close(substream, true);
return 0;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
@@ -470,4 +473,5 @@ int snd_dmaengine_pcm_refine_runtime_hwparams(
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_refine_runtime_hwparams);
+MODULE_DESCRIPTION("PCM dmaengine helper APIs");
MODULE_LICENSE("GPL");
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
index 4b5faae5d16e..cb2eebaac85f 100644
--- a/sound/core/pcm_drm_eld.c
+++ b/sound/core/pcm_drm_eld.c
@@ -2,11 +2,28 @@
/*
* PCM DRM helpers
*/
+#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>
+#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */
+#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */
+
+#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */
+#define SAD1_RATE_32000_MASK BIT(0)
+#define SAD1_RATE_44100_MASK BIT(1)
+#define SAD1_RATE_48000_MASK BIT(2)
+#define SAD1_RATE_88200_MASK BIT(3)
+#define SAD1_RATE_96000_MASK BIT(4)
+#define SAD1_RATE_176400_MASK BIT(5)
+#define SAD1_RATE_192000_MASK BIT(6)
+
static const unsigned int eld_rates[] = {
32000,
44100,
@@ -17,9 +34,62 @@ static const unsigned int eld_rates[] = {
192000,
};
+static unsigned int map_rate_families(const u8 *sad,
+ unsigned int mask_32000,
+ unsigned int mask_44100,
+ unsigned int mask_48000)
+{
+ unsigned int rate_mask = 0;
+
+ if (sad[1] & SAD1_RATE_32000_MASK)
+ rate_mask |= mask_32000;
+ if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK))
+ rate_mask |= mask_44100;
+ if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK))
+ rate_mask |= mask_48000;
+ return rate_mask;
+}
+
+static unsigned int sad_rate_mask(const u8 *sad)
+{
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return sad[1] & SAD1_RATE_MASK;
+ case HDMI_AUDIO_CODING_TYPE_AC3:
+ case HDMI_AUDIO_CODING_TYPE_DTS:
+ return map_rate_families(sad,
+ SAD1_RATE_32000_MASK,
+ SAD1_RATE_44100_MASK,
+ SAD1_RATE_48000_MASK);
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
+ case HDMI_AUDIO_CODING_TYPE_MLP:
+ return map_rate_families(sad,
+ 0,
+ SAD1_RATE_176400_MASK,
+ SAD1_RATE_192000_MASK);
+ default:
+ /* TODO adjust for other compressed formats as well */
+ return sad[1] & SAD1_RATE_MASK;
+ }
+}
+
static unsigned int sad_max_channels(const u8 *sad)
{
- return 1 + (sad[0] & 7);
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
+ case HDMI_AUDIO_CODING_TYPE_AC3:
+ case HDMI_AUDIO_CODING_TYPE_DTS:
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
+ return 2;
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
+ case HDMI_AUDIO_CODING_TYPE_MLP:
+ return 8;
+ default:
+ /* TODO adjust for other compressed formats as well */
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
+ }
}
static int eld_limit_rates(struct snd_pcm_hw_params *params,
@@ -42,7 +112,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
* requested number of channels.
*/
if (c->min <= max_channels)
- rate_mask |= sad[1];
+ rate_mask |= sad_rate_mask(sad);
}
}
@@ -70,7 +140,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
rate_mask |= BIT(i);
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
- if (rate_mask & sad[1])
+ if (rate_mask & sad_rate_mask(sad))
t.max = max(t.max, sad_max_channels(sad));
}
@@ -94,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->sad_count)
+ 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_lib.c b/sound/core/pcm_lib.c
index 9c121a921b04..6eaa950504cf 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -184,6 +184,9 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream)
pcm_warn(substream->pcm, "XRUN: %s\n", name);
dump_stack_on_xrun(substream);
}
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ substream->xrun_counter++;
+#endif
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -516,21 +519,38 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
EXPORT_SYMBOL(snd_pcm_set_ops);
/**
- * snd_pcm_set_sync - set the PCM sync id
+ * snd_pcm_set_sync_per_card - set the PCM sync id with card number
* @substream: the pcm substream
+ * @params: modified hardware parameters
+ * @id: identifier (max 12 bytes)
+ * @len: identifier length (max 12 bytes)
+ *
+ * Sets the PCM sync identifier for the card with zero padding.
+ *
+ * User space or any user should use this 16-byte identifier for a comparison only
+ * to check if two IDs are similar or different. Special case is the identifier
+ * containing only zeros. Interpretation for this combination is - empty (not set).
+ * The contents of the identifier should not be interpreted in any other way.
+ *
+ * The synchronization ID must be unique per clock source (usually one sound card,
+ * but multiple soundcard may use one PCM word clock source which means that they
+ * are fully synchronized).
*
- * Sets the PCM sync identifier for the card.
+ * This routine composes this ID using card number in first four bytes and
+ * 12-byte additional ID. When other ID composition is used (e.g. for multiple
+ * sound cards), make sure that the composition does not clash with this
+ * composition scheme.
*/
-void snd_pcm_set_sync(struct snd_pcm_substream *substream)
+void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ const unsigned char *id, unsigned int len)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->sync.id32[0] = substream->pcm->card->number;
- runtime->sync.id32[1] = -1;
- runtime->sync.id32[2] = -1;
- runtime->sync.id32[3] = -1;
+ *(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
+ len = min(12, len);
+ memcpy(params->sync + 4, id, len);
+ memset(params->sync + 4 + len, 0, 12 - len);
}
-EXPORT_SYMBOL(snd_pcm_set_sync);
+EXPORT_SYMBOL_GPL(snd_pcm_set_sync_per_card);
/*
* Standard ioctl routine
@@ -1706,12 +1726,46 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
}
EXPORT_SYMBOL(snd_pcm_hw_param_last);
+/**
+ * snd_pcm_hw_params_bits - Get the number of bits per the sample.
+ * @p: hardware parameters
+ *
+ * Return: The number of bits per sample based on the format,
+ * subformat and msbits the specified hw params has.
+ */
+int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p)
+{
+ snd_pcm_subformat_t subformat = params_subformat(p);
+ snd_pcm_format_t format = params_format(p);
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_U32_LE:
+ case SNDRV_PCM_FORMAT_S32_BE:
+ case SNDRV_PCM_FORMAT_U32_BE:
+ switch (subformat) {
+ case SNDRV_PCM_SUBFORMAT_MSBITS_20:
+ return 20;
+ case SNDRV_PCM_SUBFORMAT_MSBITS_24:
+ return 24;
+ case SNDRV_PCM_SUBFORMAT_MSBITS_MAX:
+ case SNDRV_PCM_SUBFORMAT_STD:
+ default:
+ break;
+ }
+ fallthrough;
+ default:
+ return snd_pcm_format_width(format);
+ }
+}
+EXPORT_SYMBOL(snd_pcm_hw_params_bits);
+
static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
void *arg)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- snd_pcm_stream_lock_irqsave(substream, flags);
+
+ guard(pcm_stream_lock_irqsave)(substream);
if (snd_pcm_running(substream) &&
snd_pcm_update_hw_ptr(substream) >= 0)
runtime->status->hw_ptr %= runtime->buffer_size;
@@ -1719,7 +1773,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
runtime->status->hw_ptr = 0;
runtime->hw_ptr_wrap = 0;
}
- snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0;
}
@@ -1777,6 +1830,18 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
return 0;
}
+static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream,
+ void *arg)
+{
+ static const unsigned char id[12] = { 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff };
+
+ if (substream->runtime->std_sync_id)
+ snd_pcm_set_sync_per_card(substream, arg, id, sizeof(id));
+ return 0;
+}
+
/**
* snd_pcm_lib_ioctl - a generic PCM ioctl callback
* @substream: the pcm substream instance
@@ -1798,6 +1863,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
return snd_pcm_lib_ioctl_channel_info(substream, arg);
case SNDRV_PCM_IOCTL1_FIFO_SIZE:
return snd_pcm_lib_ioctl_fifo_size(substream, arg);
+ case SNDRV_PCM_IOCTL1_SYNC_ID:
+ return snd_pcm_lib_ioctl_sync_id(substream, arg);
}
return -ENXIO;
}
@@ -1865,14 +1932,11 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
*/
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
{
- unsigned long flags;
-
if (snd_BUG_ON(!substream))
return;
- snd_pcm_stream_lock_irqsave(substream, flags);
+ guard(pcm_stream_lock_irqsave)(substream);
snd_pcm_period_elapsed_under_stream_lock(substream);
- snd_pcm_stream_unlock_irqrestore(substream, flags);
}
EXPORT_SYMBOL(snd_pcm_period_elapsed);
@@ -1973,10 +2037,11 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
- void *buf, unsigned long bytes);
+ struct iov_iter *iter, unsigned long bytes);
typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *,
- snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f);
+ snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f,
+ bool);
/* calculate the target DMA-buffer position to be written/read */
static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
@@ -1986,32 +2051,24 @@ static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
channel * (runtime->dma_bytes / runtime->channels);
}
-/* default copy_user ops for write; used for both interleaved and non- modes */
+/* default copy ops for write; used for both interleaved and non- modes */
static int default_write_copy(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
- void *buf, unsigned long bytes)
+ struct iov_iter *iter, unsigned long bytes)
{
- if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff),
- (void __user *)buf, bytes))
+ if (copy_from_iter(get_dma_ptr(substream->runtime, channel, hwoff),
+ bytes, iter) != bytes)
return -EFAULT;
return 0;
}
-/* default copy_kernel ops for write */
-static int default_write_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long hwoff,
- void *buf, unsigned long bytes)
-{
- memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes);
- return 0;
-}
-
/* fill silence instead of copy data; called as a transfer helper
* from __snd_pcm_lib_write() or directly from noninterleaved_copy() when
* a NULL buffer is passed
*/
static int fill_silence(struct snd_pcm_substream *substream, int channel,
- unsigned long hwoff, void *buf, unsigned long bytes)
+ unsigned long hwoff, struct iov_iter *iter,
+ unsigned long bytes)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -2027,25 +2084,41 @@ static int fill_silence(struct snd_pcm_substream *substream, int channel,
return 0;
}
-/* default copy_user ops for read; used for both interleaved and non- modes */
+/* default copy ops for read; used for both interleaved and non- modes */
static int default_read_copy(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
- void *buf, unsigned long bytes)
+ struct iov_iter *iter, unsigned long bytes)
{
- if (copy_to_user((void __user *)buf,
- get_dma_ptr(substream->runtime, channel, hwoff),
- bytes))
+ if (copy_to_iter(get_dma_ptr(substream->runtime, channel, hwoff),
+ bytes, iter) != bytes)
return -EFAULT;
return 0;
}
-/* default copy_kernel ops for read */
-static int default_read_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long hwoff,
- void *buf, unsigned long bytes)
+/* call transfer with the filled iov_iter */
+static int do_transfer(struct snd_pcm_substream *substream, int c,
+ unsigned long hwoff, void *data, unsigned long bytes,
+ pcm_transfer_f transfer, bool in_kernel)
{
- memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes);
- return 0;
+ struct iov_iter iter;
+ int err, type;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ type = ITER_SOURCE;
+ else
+ type = ITER_DEST;
+
+ if (in_kernel) {
+ struct kvec kvec = { data, bytes };
+
+ iov_iter_kvec(&iter, type, &kvec, 1, bytes);
+ return transfer(substream, c, hwoff, &iter, bytes);
+ }
+
+ err = import_ubuf(type, (__force void __user *)data, bytes, &iter);
+ if (err)
+ return err;
+ return transfer(substream, c, hwoff, &iter, bytes);
}
/* call transfer function with the converted pointers and sizes;
@@ -2055,7 +2128,8 @@ static int interleaved_copy(struct snd_pcm_substream *substream,
snd_pcm_uframes_t hwoff, void *data,
snd_pcm_uframes_t off,
snd_pcm_uframes_t frames,
- pcm_transfer_f transfer)
+ pcm_transfer_f transfer,
+ bool in_kernel)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -2063,7 +2137,9 @@ static int interleaved_copy(struct snd_pcm_substream *substream,
hwoff = frames_to_bytes(runtime, hwoff);
off = frames_to_bytes(runtime, off);
frames = frames_to_bytes(runtime, frames);
- return transfer(substream, 0, hwoff, data + off, frames);
+
+ return do_transfer(substream, 0, hwoff, data + off, frames, transfer,
+ in_kernel);
}
/* call transfer function with the converted pointers and sizes for each
@@ -2073,7 +2149,8 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream,
snd_pcm_uframes_t hwoff, void *data,
snd_pcm_uframes_t off,
snd_pcm_uframes_t frames,
- pcm_transfer_f transfer)
+ pcm_transfer_f transfer,
+ bool in_kernel)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int channels = runtime->channels;
@@ -2091,8 +2168,8 @@ static int noninterleaved_copy(struct snd_pcm_substream *substream,
if (!data || !*bufs)
err = fill_silence(substream, c, hwoff, NULL, frames);
else
- err = transfer(substream, c, hwoff, *bufs + off,
- frames);
+ err = do_transfer(substream, c, hwoff, *bufs + off,
+ frames, transfer, in_kernel);
if (err < 0)
return err;
}
@@ -2108,10 +2185,10 @@ static int fill_silence_frames(struct snd_pcm_substream *substream,
if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED)
return interleaved_copy(substream, off, NULL, 0, frames,
- fill_silence);
+ fill_silence, true);
else
return noninterleaved_copy(substream, off, NULL, 0, frames,
- fill_silence);
+ fill_silence, true);
}
/* sanity-check for read/write methods */
@@ -2121,7 +2198,7 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream)
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
- if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area))
+ if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
return -EINVAL;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
@@ -2226,15 +2303,9 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
transfer = fill_silence;
else
return -EINVAL;
- } else if (in_kernel) {
- if (substream->ops->copy_kernel)
- transfer = substream->ops->copy_kernel;
- else
- transfer = is_playback ?
- default_write_copy_kernel : default_read_copy_kernel;
} else {
- if (substream->ops->copy_user)
- transfer = (pcm_transfer_f)substream->ops->copy_user;
+ if (substream->ops->copy)
+ transfer = substream->ops->copy;
else
transfer = is_playback ?
default_write_copy : default_read_copy;
@@ -2307,7 +2378,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
if (!is_playback)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
err = writer(substream, appl_ofs, data, offset, frames,
- transfer);
+ transfer, in_kernel);
if (is_playback)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
snd_pcm_stream_lock_irq(substream);
@@ -2519,6 +2590,7 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
.info = pcm_chmap_ctl_info,
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 7bde7fb64011..56725d36825b 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -9,7 +9,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
-#include <linux/vmalloc.h>
#include <linux/export.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -31,15 +30,37 @@ static unsigned long max_alloc_per_card = 32UL * 1024UL * 1024UL;
module_param(max_alloc_per_card, ulong, 0644);
MODULE_PARM_DESC(max_alloc_per_card, "Max total allocation bytes per card.");
+static void __update_allocated_size(struct snd_card *card, ssize_t bytes)
+{
+ card->total_pcm_alloc_bytes += bytes;
+}
+
+static void update_allocated_size(struct snd_card *card, ssize_t bytes)
+{
+ guard(mutex)(&card->memory_mutex);
+ __update_allocated_size(card, bytes);
+}
+
+static void decrease_allocated_size(struct snd_card *card, size_t bytes)
+{
+ guard(mutex)(&card->memory_mutex);
+ WARN_ON(card->total_pcm_alloc_bytes < bytes);
+ __update_allocated_size(card, -(ssize_t)bytes);
+}
+
static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
int str, size_t size, struct snd_dma_buffer *dmab)
{
enum dma_data_direction dir;
int err;
- if (max_alloc_per_card &&
- card->total_pcm_alloc_bytes + size > max_alloc_per_card)
- return -ENOMEM;
+ /* check and reserve the requested size */
+ scoped_guard(mutex, &card->memory_mutex) {
+ if (max_alloc_per_card &&
+ card->total_pcm_alloc_bytes + size > max_alloc_per_card)
+ return -ENOMEM;
+ __update_allocated_size(card, size);
+ }
if (str == SNDRV_PCM_STREAM_PLAYBACK)
dir = DMA_TO_DEVICE;
@@ -47,9 +68,14 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev,
dir = DMA_FROM_DEVICE;
err = snd_dma_alloc_dir_pages(type, dev, dir, size, dmab);
if (!err) {
- mutex_lock(&card->memory_mutex);
- card->total_pcm_alloc_bytes += dmab->bytes;
- mutex_unlock(&card->memory_mutex);
+ /* the actual allocation size might be bigger than requested,
+ * and we need to correct the account
+ */
+ if (dmab->bytes != size)
+ update_allocated_size(card, dmab->bytes - size);
+ } else {
+ /* take back on allocation failure */
+ decrease_allocated_size(card, size);
}
return err;
}
@@ -58,10 +84,7 @@ static void do_free_pages(struct snd_card *card, struct snd_dma_buffer *dmab)
{
if (!dmab->area)
return;
- mutex_lock(&card->memory_mutex);
- WARN_ON(card->total_pcm_alloc_bytes < dmab->bytes);
- card->total_pcm_alloc_bytes -= dmab->bytes;
- mutex_unlock(&card->memory_mutex);
+ decrease_allocated_size(card, dmab->bytes);
snd_dma_free_pages(dmab);
dmab->area = NULL;
}
@@ -160,23 +183,26 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
struct snd_pcm_substream *substream = entry->private_data;
struct snd_card *card = substream->pcm->card;
char line[64], str[64];
- size_t size;
+ unsigned long size;
struct snd_dma_buffer new_dmab;
- mutex_lock(&substream->pcm->open_mutex);
+ guard(mutex)(&substream->pcm->open_mutex);
if (substream->runtime) {
buffer->error = -EBUSY;
- goto unlock;
+ return;
}
if (!snd_info_get_line(buffer, line, sizeof(line))) {
snd_info_get_str(str, line, sizeof(str));
- size = simple_strtoul(str, NULL, 10) * 1024;
+ buffer->error = kstrtoul(str, 10, &size);
+ if (buffer->error != 0)
+ return;
+ size *= 1024;
if ((size != 0 && size < 8192) || size > substream->dma_max) {
buffer->error = -EINVAL;
- goto unlock;
+ return;
}
if (substream->dma_buffer.bytes == size)
- goto unlock;
+ return;
memset(&new_dmab, 0, sizeof(new_dmab));
new_dmab.dev = substream->dma_buffer.dev;
if (size > 0) {
@@ -186,11 +212,11 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
substream->stream,
size, &new_dmab) < 0) {
buffer->error = -ENOMEM;
- pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",
+ pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %lu\n",
substream->pcm->card->number, substream->pcm->device,
substream->stream ? 'c' : 'p', substream->number,
substream->pcm->name, size);
- goto unlock;
+ return;
}
substream->buffer_bytes_max = size;
} else {
@@ -202,8 +228,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
} else {
buffer->error = -EINVAL;
}
- unlock:
- mutex_unlock(&substream->pcm->open_mutex);
}
static inline void preallocate_info_init(struct snd_pcm_substream *substream)
@@ -434,7 +458,7 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
substream->stream,
size, dmab) < 0) {
kfree(dmab);
- pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",
+ pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot allocate for size %zu\n",
substream->pcm->card->number, substream->pcm->device,
substream->stream ? 'c' : 'p', substream->number,
substream->pcm->name, size);
@@ -475,61 +499,3 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
return 0;
}
EXPORT_SYMBOL(snd_pcm_lib_free_pages);
-
-int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
- size_t size, gfp_t gfp_flags)
-{
- struct snd_pcm_runtime *runtime;
-
- if (PCM_RUNTIME_CHECK(substream))
- return -EINVAL;
- runtime = substream->runtime;
- if (runtime->dma_area) {
- if (runtime->dma_bytes >= size)
- return 0; /* already large enough */
- vfree(runtime->dma_area);
- }
- runtime->dma_area = __vmalloc(size, gfp_flags);
- if (!runtime->dma_area)
- return -ENOMEM;
- runtime->dma_bytes = size;
- return 1;
-}
-EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
-
-/**
- * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
- * @substream: the substream with a buffer allocated by
- * snd_pcm_lib_alloc_vmalloc_buffer()
- *
- * Return: Zero if successful, or a negative error code on failure.
- */
-int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime;
-
- if (PCM_RUNTIME_CHECK(substream))
- return -EINVAL;
- runtime = substream->runtime;
- vfree(runtime->dma_area);
- runtime->dma_area = NULL;
- return 0;
-}
-EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
-
-/**
- * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct
- * @substream: the substream with a buffer allocated by
- * snd_pcm_lib_alloc_vmalloc_buffer()
- * @offset: offset in the buffer
- *
- * This function is to be used as the page callback in the PCM ops.
- *
- * Return: The page struct, or %NULL on failure.
- */
-struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
- unsigned long offset)
-{
- return vmalloc_to_page(substream->runtime->dma_area + offset);
-}
-EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 5588b6a1ee8b..71eec32a7a0a 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;
@@ -494,18 +494,20 @@ EXPORT_SYMBOL(snd_pcm_format_set_silence);
int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw)
{
int i;
+ unsigned int rmin, rmax;
+
+ rmin = UINT_MAX;
+ rmax = 0;
for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
if (hw->rates & (1 << i)) {
- hw->rate_min = snd_pcm_known_rates.list[i];
- break;
- }
- }
- for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
- if (hw->rates & (1 << i)) {
- hw->rate_max = snd_pcm_known_rates.list[i];
- break;
+ rmin = min(rmin, snd_pcm_known_rates.list[i]);
+ rmax = max(rmax, snd_pcm_known_rates.list[i]);
}
}
+ if (rmin > rmax)
+ return -EINVAL;
+ hw->rate_min = rmin;
+ hw->rate_max = rmax;
return 0;
}
EXPORT_SYMBOL(snd_pcm_hw_limit_rates);
@@ -584,33 +586,3 @@ unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
return rates_a & rates_b;
}
EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
-
-/**
- * snd_pcm_rate_range_to_bits - converts rate range to SNDRV_PCM_RATE_xxx bit
- * @rate_min: the minimum sample rate
- * @rate_max: the maximum sample rate
- *
- * This function has an implicit assumption: the rates in the given range have
- * only the pre-defined rates like 44100 or 16000.
- *
- * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate range,
- * or SNDRV_PCM_RATE_KNOT for an unknown range.
- */
-unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
- unsigned int rate_max)
-{
- unsigned int rates = 0;
- int i;
-
- for (i = 0; i < snd_pcm_known_rates.count; i++) {
- if (snd_pcm_known_rates.list[i] >= rate_min
- && snd_pcm_known_rates.list[i] <= rate_max)
- rates |= 1 << i;
- }
-
- if (!rates)
- rates = SNDRV_PCM_RATE_KNOT;
-
- return rates;
-}
-EXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 39a65d1415ab..68bee40c9ada 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -24,6 +24,7 @@
#include <sound/minors.h>
#include <linux/uio.h>
#include <linux/delay.h>
+#include <linux/bitops.h>
#include "pcm_local.h"
@@ -83,19 +84,24 @@ void snd_pcm_group_init(struct snd_pcm_group *group)
}
/* define group lock helpers */
-#define DEFINE_PCM_GROUP_LOCK(action, mutex_action) \
+#define DEFINE_PCM_GROUP_LOCK(action, bh_lock, bh_unlock, mutex_action) \
static void snd_pcm_group_ ## action(struct snd_pcm_group *group, bool nonatomic) \
{ \
- if (nonatomic) \
+ if (nonatomic) { \
mutex_ ## mutex_action(&group->mutex); \
- else \
- spin_ ## action(&group->lock); \
+ } else { \
+ if (IS_ENABLED(CONFIG_PREEMPT_RT) && bh_lock) \
+ local_bh_disable(); \
+ spin_ ## action(&group->lock); \
+ if (IS_ENABLED(CONFIG_PREEMPT_RT) && bh_unlock) \
+ local_bh_enable(); \
+ } \
}
-DEFINE_PCM_GROUP_LOCK(lock, lock);
-DEFINE_PCM_GROUP_LOCK(unlock, unlock);
-DEFINE_PCM_GROUP_LOCK(lock_irq, lock);
-DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock);
+DEFINE_PCM_GROUP_LOCK(lock, false, false, lock);
+DEFINE_PCM_GROUP_LOCK(unlock, false, false, unlock);
+DEFINE_PCM_GROUP_LOCK(lock_irq, true, false, lock);
+DEFINE_PCM_GROUP_LOCK(unlock_irq, false, true, unlock);
/**
* snd_pcm_stream_lock - Lock the PCM stream
@@ -236,7 +242,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user * _info)
{
- struct snd_pcm_info *info;
+ struct snd_pcm_info *info __free(kfree) = NULL;
int err;
info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -247,7 +253,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
if (copy_to_user(_info, info, sizeof(*info)))
err = -EFAULT;
}
- kfree(info);
return err;
}
@@ -359,7 +364,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_pcm_hw_constraints *constrs =
&substream->runtime->hw_constraints;
unsigned int k;
- unsigned int *rstamps;
+ unsigned int *rstamps __free(kfree) = NULL;
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp;
struct snd_pcm_hw_rule *r;
@@ -435,10 +440,8 @@ retry:
}
changed = r->func(params, r);
- if (changed < 0) {
- err = changed;
- goto out;
- }
+ if (changed < 0)
+ return changed;
/*
* When the parameter is changed, notify it to the caller
@@ -469,8 +472,6 @@ retry:
if (again)
goto retry;
- out:
- kfree(rstamps);
return err;
}
@@ -479,12 +480,34 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
{
const struct snd_interval *i;
const struct snd_mask *m;
+ struct snd_mask *m_rw;
int err;
if (!params->msbits) {
i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
if (snd_interval_single(i))
params->msbits = snd_interval_value(i);
+ m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ if (snd_mask_single(m)) {
+ snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+ params->msbits = snd_pcm_format_width(format);
+ }
+ }
+
+ if (params->msbits) {
+ m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ if (snd_mask_single(m)) {
+ snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+
+ if (snd_pcm_format_linear(format) &&
+ snd_pcm_format_width(format) != params->msbits) {
+ m_rw = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT);
+ snd_mask_reset(m_rw,
+ (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
+ if (snd_mask_empty(m_rw))
+ return -EINVAL;
+ }
+ }
}
if (!params->rate_den) {
@@ -516,6 +539,12 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
SNDRV_PCM_INFO_MMAP_VALID);
}
+ err = snd_pcm_ops_ioctl(substream,
+ SNDRV_PCM_IOCTL1_SYNC_ID,
+ params);
+ if (err < 0)
+ return err;
+
return 0;
}
@@ -554,7 +583,7 @@ EXPORT_SYMBOL(snd_pcm_hw_refine);
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{
- struct snd_pcm_hw_params *params;
+ struct snd_pcm_hw_params *params __free(kfree) = NULL;
int err;
params = memdup_user(_params, sizeof(*params));
@@ -563,17 +592,15 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
err = snd_pcm_hw_refine(substream, params);
if (err < 0)
- goto end;
+ return err;
err = fixup_unreferenced_params(substream, params);
if (err < 0)
- goto end;
+ return err;
if (copy_to_user(_params, params, sizeof(*params)))
- err = -EFAULT;
-end:
- kfree(params);
- return err;
+ return -EFAULT;
+ return 0;
}
static int period_to_usecs(struct snd_pcm_runtime *runtime)
@@ -594,10 +621,9 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
static void snd_pcm_set_state(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
__snd_pcm_set_state(substream->runtime, state);
- snd_pcm_stream_unlock_irq(substream);
}
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
@@ -703,6 +729,17 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime)
atomic_inc(&runtime->buffer_accessing);
}
+/* fill the PCM buffer with the current silence format; called from pcm_oss.c */
+void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime)
+{
+ snd_pcm_buffer_access_lock(runtime);
+ if (runtime->dma_area)
+ snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+ bytes_to_samples(runtime, runtime->dma_bytes));
+ snd_pcm_buffer_access_unlock(runtime);
+}
+EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence);
+
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
#define is_oss_stream(substream) ((substream)->oss.oss)
#else
@@ -723,20 +760,20 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
err = snd_pcm_buffer_access_lock(runtime);
if (err < 0)
return err;
- snd_pcm_stream_lock_irq(substream);
- switch (runtime->state) {
- case SNDRV_PCM_STATE_OPEN:
- case SNDRV_PCM_STATE_SETUP:
- case SNDRV_PCM_STATE_PREPARED:
- if (!is_oss_stream(substream) &&
- atomic_read(&substream->mmap_count))
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ switch (runtime->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_SETUP:
+ case SNDRV_PCM_STATE_PREPARED:
+ if (!is_oss_stream(substream) &&
+ atomic_read(&substream->mmap_count))
+ err = -EBADFD;
+ break;
+ default:
err = -EBADFD;
- break;
- default:
- err = -EBADFD;
- break;
+ break;
+ }
}
- snd_pcm_stream_unlock_irq(substream);
if (err)
goto unlock;
@@ -809,7 +846,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->boundary *= 2;
/* clear the buffer for avoiding possible kernel info leaks */
- if (runtime->dma_area && !substream->ops->copy_user) {
+ if (runtime->dma_area && !substream->ops->copy) {
size_t size = runtime->dma_bytes;
if (runtime->info & SNDRV_PCM_INFO_MMAP)
@@ -847,7 +884,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{
- struct snd_pcm_hw_params *params;
+ struct snd_pcm_hw_params *params __free(kfree) = NULL;
int err;
params = memdup_user(_params, sizeof(*params));
@@ -856,12 +893,10 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
err = snd_pcm_hw_params(substream, params);
if (err < 0)
- goto end;
+ return err;
if (copy_to_user(_params, params, sizeof(*params)))
- err = -EFAULT;
-end:
- kfree(params);
+ return -EFAULT;
return err;
}
@@ -888,18 +923,18 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
result = snd_pcm_buffer_access_lock(runtime);
if (result < 0)
return result;
- snd_pcm_stream_lock_irq(substream);
- switch (runtime->state) {
- case SNDRV_PCM_STATE_SETUP:
- case SNDRV_PCM_STATE_PREPARED:
- if (atomic_read(&substream->mmap_count))
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ switch (runtime->state) {
+ case SNDRV_PCM_STATE_SETUP:
+ case SNDRV_PCM_STATE_PREPARED:
+ if (atomic_read(&substream->mmap_count))
+ result = -EBADFD;
+ break;
+ default:
result = -EBADFD;
- break;
- default:
- result = -EBADFD;
- break;
+ break;
+ }
}
- snd_pcm_stream_unlock_irq(substream);
if (result)
goto unlock;
result = do_hw_free(substream);
@@ -919,12 +954,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
- snd_pcm_stream_lock_irq(substream);
- if (runtime->state == SNDRV_PCM_STATE_OPEN) {
- snd_pcm_stream_unlock_irq(substream);
- return -EBADFD;
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ if (runtime->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
}
- snd_pcm_stream_unlock_irq(substream);
if (params->tstamp_mode < 0 ||
params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
@@ -944,24 +977,24 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
err = 0;
- snd_pcm_stream_lock_irq(substream);
- runtime->tstamp_mode = params->tstamp_mode;
- if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
- runtime->tstamp_type = params->tstamp_type;
- runtime->period_step = params->period_step;
- runtime->control->avail_min = params->avail_min;
- runtime->start_threshold = params->start_threshold;
- runtime->stop_threshold = params->stop_threshold;
- runtime->silence_threshold = params->silence_threshold;
- runtime->silence_size = params->silence_size;
- params->boundary = runtime->boundary;
- if (snd_pcm_running(substream)) {
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
- snd_pcm_playback_silence(substream, ULONG_MAX);
- err = snd_pcm_update_state(substream, runtime);
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ runtime->tstamp_mode = params->tstamp_mode;
+ if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
+ runtime->tstamp_type = params->tstamp_type;
+ runtime->period_step = params->period_step;
+ runtime->control->avail_min = params->avail_min;
+ runtime->start_threshold = params->start_threshold;
+ runtime->stop_threshold = params->stop_threshold;
+ runtime->silence_threshold = params->silence_threshold;
+ runtime->silence_size = params->silence_size;
+ params->boundary = runtime->boundary;
+ if (snd_pcm_running(substream)) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ runtime->silence_size > 0)
+ snd_pcm_playback_silence(substream, ULONG_MAX);
+ err = snd_pcm_update_state(substream, runtime);
+ }
}
- snd_pcm_stream_unlock_irq(substream);
return err;
}
@@ -995,7 +1028,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
&runtime->audio_tstamp_config);
@@ -1016,7 +1049,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->state = runtime->state;
status->suspended_state = runtime->suspended_state;
if (status->state == SNDRV_PCM_STATE_OPEN)
- goto _end;
+ return 0;
status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
if (snd_pcm_running(substream)) {
@@ -1061,8 +1094,6 @@ int snd_pcm_status64(struct snd_pcm_substream *substream,
status->overrange = runtime->overrange;
runtime->avail_max = 0;
runtime->overrange = 0;
- _end:
- snd_pcm_stream_unlock_irq(substream);
return 0;
}
@@ -1147,12 +1178,10 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
channel = info->channel;
runtime = substream->runtime;
- snd_pcm_stream_lock_irq(substream);
- if (runtime->state == SNDRV_PCM_STATE_OPEN) {
- snd_pcm_stream_unlock_irq(substream);
- return -EBADFD;
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ if (runtime->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
}
- snd_pcm_stream_unlock_irq(substream);
if (channel >= runtime->channels)
return -EINVAL;
memset(info, 0, sizeof(*info));
@@ -1373,12 +1402,8 @@ static int snd_pcm_action_lock_irq(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
- int res;
-
- snd_pcm_stream_lock_irq(substream);
- res = snd_pcm_action(ops, substream, state);
- snd_pcm_stream_unlock_irq(substream);
- return res;
+ guard(pcm_stream_lock_irq)(substream);
+ return snd_pcm_action(ops, substream, state);
}
/*
@@ -1390,17 +1415,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
int res;
/* Guarantee the group members won't change during non-atomic action */
- down_read(&snd_pcm_link_rwsem);
+ guard(rwsem_read)(&snd_pcm_link_rwsem);
res = snd_pcm_buffer_access_lock(substream->runtime);
if (res < 0)
- goto unlock;
+ return res;
if (snd_pcm_stream_linked(substream))
res = snd_pcm_action_group(ops, substream, state, false);
else
res = snd_pcm_action_single(ops, substream, state);
snd_pcm_buffer_access_unlock(substream->runtime);
- unlock:
- up_read(&snd_pcm_link_rwsem);
return res;
}
@@ -1570,12 +1593,9 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
*/
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
{
- unsigned long flags;
-
- snd_pcm_stream_lock_irqsave(substream, flags);
+ guard(pcm_stream_lock_irqsave)(substream);
if (substream->runtime && snd_pcm_running(substream))
__snd_pcm_xrun(substream);
- snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
@@ -1605,10 +1625,6 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream,
{
if (substream->runtime->trigger_master != substream)
return 0;
- /* some drivers might use hw_ptr to recover from the pause -
- update the hw_ptr now */
- if (pause_pushed(state))
- snd_pcm_update_hw_ptr(substream);
/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
* a delta between the current jiffies, this gives a large enough
* delta, effectively to skip the check once.
@@ -1731,14 +1747,9 @@ static const struct action_ops snd_pcm_action_suspend = {
*/
static int snd_pcm_suspend(struct snd_pcm_substream *substream)
{
- int err;
- unsigned long flags;
-
- snd_pcm_stream_lock_irqsave(substream, flags);
- err = snd_pcm_action(&snd_pcm_action_suspend, substream,
- ACTION_ARG_IGNORE);
- snd_pcm_stream_unlock_irqrestore(substream, flags);
- return err;
+ guard(pcm_stream_lock_irqsave)(substream);
+ return snd_pcm_action(&snd_pcm_action_suspend, substream,
+ ACTION_ARG_IGNORE);
}
/**
@@ -1787,6 +1798,8 @@ static int snd_pcm_pre_resume(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ if (runtime->state != SNDRV_PCM_STATE_SUSPENDED)
+ return -EBADFD;
if (!(runtime->info & SNDRV_PCM_INFO_RESUME))
return -ENOSYS;
runtime->trigger_master = substream;
@@ -1854,22 +1867,17 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
static int snd_pcm_xrun(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- int result;
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
switch (runtime->state) {
case SNDRV_PCM_STATE_XRUN:
- result = 0; /* already there */
- break;
+ return 0; /* already there */
case SNDRV_PCM_STATE_RUNNING:
__snd_pcm_xrun(substream);
- result = 0;
- break;
+ return 0;
default:
- result = -EBADFD;
+ return -EBADFD;
}
- snd_pcm_stream_unlock_irq(substream);
- return result;
}
/*
@@ -1898,13 +1906,12 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
if (err < 0)
return err;
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
runtime->hw_ptr_base = 0;
runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
runtime->status->hw_ptr % runtime->period_size;
runtime->silence_start = runtime->status->hw_ptr;
runtime->silence_filled = 0;
- snd_pcm_stream_unlock_irq(substream);
return 0;
}
@@ -1912,12 +1919,11 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
runtime->control->appl_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
- snd_pcm_stream_unlock_irq(substream);
}
static const struct action_ops snd_pcm_action_reset = {
@@ -1993,16 +1999,16 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
else
f_flags = substream->f_flags;
- snd_pcm_stream_lock_irq(substream);
- switch (substream->runtime->state) {
- case SNDRV_PCM_STATE_PAUSED:
- snd_pcm_pause(substream, false);
- fallthrough;
- case SNDRV_PCM_STATE_SUSPENDED:
- snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
- break;
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ switch (substream->runtime->state) {
+ case SNDRV_PCM_STATE_PAUSED:
+ snd_pcm_pause(substream, false);
+ fallthrough;
+ case SNDRV_PCM_STATE_SUSPENDED:
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+ break;
+ }
}
- snd_pcm_stream_unlock_irq(substream);
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
substream,
@@ -2219,14 +2225,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
/* resume pause */
if (runtime->state == SNDRV_PCM_STATE_PAUSED)
snd_pcm_pause(substream, false);
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
- snd_pcm_stream_unlock_irq(substream);
return result;
}
@@ -2255,53 +2260,44 @@ static bool is_pcm_file(struct file *file)
*/
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{
- int res = 0;
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream1;
- struct snd_pcm_group *group, *target_group;
+ struct snd_pcm_group *group __free(kfree) = NULL;
+ struct snd_pcm_group *target_group;
bool nonatomic = substream->pcm->nonatomic;
- struct fd f = fdget(fd);
+ CLASS(fd, f)(fd);
- if (!f.file)
+ if (fd_empty(f))
return -EBADFD;
- if (!is_pcm_file(f.file)) {
- res = -EBADFD;
- goto _badf;
- }
- pcm_file = f.file->private_data;
+ if (!is_pcm_file(fd_file(f)))
+ return -EBADFD;
+
+ pcm_file = fd_file(f)->private_data;
substream1 = pcm_file->substream;
- if (substream == substream1) {
- res = -EINVAL;
- goto _badf;
- }
+ if (substream == substream1)
+ return -EINVAL;
group = kzalloc(sizeof(*group), GFP_KERNEL);
- if (!group) {
- res = -ENOMEM;
- goto _nolock;
- }
+ if (!group)
+ return -ENOMEM;
snd_pcm_group_init(group);
- down_write(&snd_pcm_link_rwsem);
+ guard(rwsem_write)(&snd_pcm_link_rwsem);
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN ||
substream->runtime->state != substream1->runtime->state ||
- substream->pcm->nonatomic != substream1->pcm->nonatomic) {
- res = -EBADFD;
- goto _end;
- }
- if (snd_pcm_stream_linked(substream1)) {
- res = -EALREADY;
- goto _end;
- }
+ substream->pcm->nonatomic != substream1->pcm->nonatomic)
+ return -EBADFD;
+ if (snd_pcm_stream_linked(substream1))
+ return -EALREADY;
- snd_pcm_stream_lock_irq(substream);
- if (!snd_pcm_stream_linked(substream)) {
- snd_pcm_group_assign(substream, group);
- group = NULL; /* assigned, don't free this one below */
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ if (!snd_pcm_stream_linked(substream)) {
+ snd_pcm_group_assign(substream, group);
+ group = NULL; /* assigned, don't free this one below */
+ }
+ target_group = substream->group;
}
- target_group = substream->group;
- snd_pcm_stream_unlock_irq(substream);
snd_pcm_group_lock_irq(target_group, nonatomic);
snd_pcm_stream_lock_nested(substream1);
@@ -2309,13 +2305,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
refcount_inc(&target_group->refs);
snd_pcm_stream_unlock(substream1);
snd_pcm_group_unlock_irq(target_group, nonatomic);
- _end:
- up_write(&snd_pcm_link_rwsem);
- _nolock:
- kfree(group);
- _badf:
- fdput(f);
- return res;
+ return 0;
}
static void relink_to_local(struct snd_pcm_substream *substream)
@@ -2330,14 +2320,11 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
struct snd_pcm_group *group;
bool nonatomic = substream->pcm->nonatomic;
bool do_free = false;
- int res = 0;
- down_write(&snd_pcm_link_rwsem);
+ guard(rwsem_write)(&snd_pcm_link_rwsem);
- if (!snd_pcm_stream_linked(substream)) {
- res = -EALREADY;
- goto _end;
- }
+ if (!snd_pcm_stream_linked(substream))
+ return -EALREADY;
group = substream->group;
snd_pcm_group_lock_irq(group, nonatomic);
@@ -2356,10 +2343,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
snd_pcm_group_unlock_irq(group, nonatomic);
if (do_free)
kfree(group);
-
- _end:
- up_write(&snd_pcm_link_rwsem);
- return res;
+ return 0;
}
/*
@@ -2451,13 +2435,17 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 ||\
+ SNDRV_PCM_RATE_128000 != 1 << 19
#error "Change this table"
#endif
+/* NOTE: the list is unsorted! */
static const unsigned int rates[] = {
5512, 8000, 11025, 16000, 22050, 32000, 44100,
- 48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000
+ 48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000,
+ /* extended */
+ 12000, 24000, 128000
};
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
@@ -2487,6 +2475,41 @@ static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
+static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_mask *sfmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT);
+ struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ u32 *subformats = rule->private;
+ snd_pcm_format_t f;
+ struct snd_mask m;
+
+ snd_mask_none(&m);
+ /* All PCMs support at least the default STD subformat. */
+ snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_STD);
+
+ pcm_for_each_format(f) {
+ if (!snd_mask_test(fmask, (__force unsigned)f))
+ continue;
+
+ if (f == SNDRV_PCM_FORMAT_S32_LE && *subformats)
+ m.bits[0] |= *subformats;
+ else if (snd_pcm_format_linear(f))
+ snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
+ }
+
+ return snd_mask_refine(sfmask, &m);
+}
+
+static int snd_pcm_hw_constraint_subformats(struct snd_pcm_runtime *runtime,
+ unsigned int cond, u32 *subformats)
+{
+ return snd_pcm_hw_rule_add(runtime, cond, -1,
+ snd_pcm_hw_rule_subformats, (void *)subformats,
+ SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+}
+
static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -2638,8 +2661,7 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
if (err < 0)
return err;
- err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT,
- PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD));
+ err = snd_pcm_hw_constraint_subformats(runtime, 0, &hw->subformats);
if (err < 0)
return err;
@@ -2898,10 +2920,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
/* block until the device gets woken up as it may touch the hardware */
snd_power_wait(pcm->card);
- mutex_lock(&pcm->open_mutex);
- snd_pcm_release_substream(substream);
- kfree(pcm_file);
- mutex_unlock(&pcm->open_mutex);
+ scoped_guard(mutex, &pcm->open_mutex) {
+ snd_pcm_release_substream(substream);
+ kfree(pcm_file);
+ }
wake_up(&pcm->open_wait);
module_put(pcm->card->module);
snd_card_file_remove(pcm->card, file);
@@ -2985,12 +3007,12 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
if (frames == 0)
return 0;
- snd_pcm_stream_lock_irq(substream);
- ret = do_pcm_hwsync(substream);
- if (!ret)
- ret = rewind_appl_ptr(substream, frames,
- snd_pcm_hw_avail(substream));
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ ret = do_pcm_hwsync(substream);
+ if (!ret)
+ ret = rewind_appl_ptr(substream, frames,
+ snd_pcm_hw_avail(substream));
+ }
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
@@ -3004,12 +3026,12 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
if (frames == 0)
return 0;
- snd_pcm_stream_lock_irq(substream);
- ret = do_pcm_hwsync(substream);
- if (!ret)
- ret = forward_appl_ptr(substream, frames,
- snd_pcm_avail(substream));
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ ret = do_pcm_hwsync(substream);
+ if (!ret)
+ ret = forward_appl_ptr(substream, frames,
+ snd_pcm_avail(substream));
+ }
if (ret >= 0)
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
return ret;
@@ -3020,11 +3042,11 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
{
int err;
- snd_pcm_stream_lock_irq(substream);
- err = do_pcm_hwsync(substream);
- if (delay && !err)
- *delay = snd_pcm_calc_delay(substream);
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ err = do_pcm_hwsync(substream);
+ if (delay && !err)
+ *delay = snd_pcm_calc_delay(substream);
+ }
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU);
return err;
@@ -3035,51 +3057,87 @@ static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream)
return snd_pcm_delay(substream, NULL);
}
+#define snd_pcm_sync_ptr_get_user(__f, __c, __ptr) ({ \
+ __label__ failed, failed_begin; \
+ int __err = -EFAULT; \
+ typeof(*(__ptr)) __user *__src = (__ptr); \
+ \
+ if (!user_read_access_begin(__src, sizeof(*__src))) \
+ goto failed_begin; \
+ unsafe_get_user(__f, &__src->flags, failed); \
+ unsafe_get_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \
+ unsafe_get_user(__c.avail_min, &__src->c.control.avail_min, failed); \
+ __err = 0; \
+failed: \
+ user_read_access_end(); \
+failed_begin: \
+ __err; \
+})
+
+#define snd_pcm_sync_ptr_put_user(__s, __c, __ptr) ({ \
+ __label__ failed, failed_begin; \
+ int __err = -EFAULT; \
+ typeof(*(__ptr)) __user *__src = (__ptr); \
+ \
+ if (!user_write_access_begin(__src, sizeof(*__src))) \
+ goto failed_begin; \
+ unsafe_put_user(__s.state, &__src->s.status.state, failed); \
+ unsafe_put_user(__s.hw_ptr, &__src->s.status.hw_ptr, failed); \
+ unsafe_put_user(__s.tstamp.tv_sec, &__src->s.status.tstamp.tv_sec, failed); \
+ unsafe_put_user(__s.tstamp.tv_nsec, &__src->s.status.tstamp.tv_nsec, failed); \
+ unsafe_put_user(__s.suspended_state, &__src->s.status.suspended_state, failed); \
+ unsafe_put_user(__s.audio_tstamp.tv_sec, &__src->s.status.audio_tstamp.tv_sec, failed); \
+ unsafe_put_user(__s.audio_tstamp.tv_nsec, &__src->s.status.audio_tstamp.tv_nsec, failed);\
+ unsafe_put_user(__c.appl_ptr, &__src->c.control.appl_ptr, failed); \
+ unsafe_put_user(__c.avail_min, &__src->c.control.avail_min, failed); \
+ __err = 0; \
+failed: \
+ user_write_access_end(); \
+failed_begin: \
+ __err; \
+})
+
static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr __user *_sync_ptr)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_pcm_sync_ptr sync_ptr;
volatile struct snd_pcm_mmap_status *status;
volatile struct snd_pcm_mmap_control *control;
+ u32 sflags;
+ struct snd_pcm_mmap_control scontrol;
+ struct snd_pcm_mmap_status sstatus;
int err;
- memset(&sync_ptr, 0, sizeof(sync_ptr));
- if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
+ if (snd_pcm_sync_ptr_get_user(sflags, scontrol, _sync_ptr))
return -EFAULT;
- if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control)))
- return -EFAULT;
status = runtime->status;
control = runtime->control;
- if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
+ if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
if (err < 0)
return err;
}
- snd_pcm_stream_lock_irq(substream);
- if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
- err = pcm_lib_apply_appl_ptr(substream,
- sync_ptr.c.control.appl_ptr);
- if (err < 0) {
- snd_pcm_stream_unlock_irq(substream);
- return err;
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
+ err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr);
+ if (err < 0)
+ return err;
+ } else {
+ scontrol.appl_ptr = control->appl_ptr;
}
- } else {
- sync_ptr.c.control.appl_ptr = control->appl_ptr;
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+ control->avail_min = scontrol.avail_min;
+ else
+ scontrol.avail_min = control->avail_min;
+ sstatus.state = status->state;
+ sstatus.hw_ptr = status->hw_ptr;
+ sstatus.tstamp = status->tstamp;
+ sstatus.suspended_state = status->suspended_state;
+ sstatus.audio_tstamp = status->audio_tstamp;
}
- if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
- control->avail_min = sync_ptr.c.control.avail_min;
- else
- sync_ptr.c.control.avail_min = control->avail_min;
- sync_ptr.s.status.state = status->state;
- sync_ptr.s.status.hw_ptr = status->hw_ptr;
- sync_ptr.s.status.tstamp = status->tstamp;
- sync_ptr.s.status.suspended_state = status->suspended_state;
- sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
- snd_pcm_stream_unlock_irq(substream);
- if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
- if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
+ if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, _sync_ptr))
return -EFAULT;
return 0;
}
@@ -3088,12 +3146,10 @@ struct snd_pcm_mmap_status32 {
snd_pcm_state_t state;
s32 pad1;
u32 hw_ptr;
- s32 tstamp_sec;
- s32 tstamp_nsec;
+ struct __snd_timespec tstamp;
snd_pcm_state_t suspended_state;
- s32 audio_tstamp_sec;
- s32 audio_tstamp_nsec;
-} __attribute__((packed));
+ struct __snd_timespec audio_tstamp;
+} __packed;
struct snd_pcm_mmap_control32 {
u32 appl_ptr;
@@ -3110,19 +3166,29 @@ struct snd_pcm_sync_ptr32 {
struct snd_pcm_mmap_control32 control;
unsigned char reserved[64];
} c;
-} __attribute__((packed));
+} __packed;
-/* recalcuate the boundary within 32bit */
+/* recalculate the boundary within 32bit */
static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t boundary;
+ snd_pcm_uframes_t border;
+ int order;
if (! runtime->buffer_size)
return 0;
- boundary = runtime->buffer_size;
- while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
- boundary *= 2;
- return boundary;
+
+ border = 0x7fffffffUL - runtime->buffer_size;
+ if (runtime->buffer_size > border)
+ return runtime->buffer_size;
+
+ order = __fls(border) - __fls(runtime->buffer_size);
+ boundary = runtime->buffer_size << order;
+
+ if (boundary <= border)
+ return boundary;
+ else
+ return boundary / 2;
}
static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
@@ -3140,9 +3206,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
if (snd_BUG_ON(!runtime))
return -EINVAL;
- if (get_user(sflags, &src->flags) ||
- get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
- get_user(scontrol.avail_min, &src->c.control.avail_min))
+ if (snd_pcm_sync_ptr_get_user(sflags, scontrol, src))
return -EFAULT;
if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
err = snd_pcm_hwsync(substream);
@@ -3154,38 +3218,28 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
boundary = recalculate_boundary(runtime);
if (! boundary)
boundary = 0x7fffffff;
- snd_pcm_stream_lock_irq(substream);
- /* FIXME: we should consider the boundary for the sync from app */
- if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
- err = pcm_lib_apply_appl_ptr(substream,
- scontrol.appl_ptr);
- if (err < 0) {
- snd_pcm_stream_unlock_irq(substream);
- return err;
- }
- } else
- scontrol.appl_ptr = control->appl_ptr % boundary;
- if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
- control->avail_min = scontrol.avail_min;
- else
- scontrol.avail_min = control->avail_min;
- sstatus.state = status->state;
- sstatus.hw_ptr = status->hw_ptr % boundary;
- sstatus.tstamp = status->tstamp;
- sstatus.suspended_state = status->suspended_state;
- sstatus.audio_tstamp = status->audio_tstamp;
- snd_pcm_stream_unlock_irq(substream);
+ scoped_guard(pcm_stream_lock_irq, substream) {
+ /* FIXME: we should consider the boundary for the sync from app */
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
+ err = pcm_lib_apply_appl_ptr(substream,
+ scontrol.appl_ptr);
+ if (err < 0)
+ return err;
+ } else
+ scontrol.appl_ptr = control->appl_ptr % boundary;
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+ control->avail_min = scontrol.avail_min;
+ else
+ scontrol.avail_min = control->avail_min;
+ sstatus.state = status->state;
+ sstatus.hw_ptr = status->hw_ptr % boundary;
+ sstatus.tstamp = status->tstamp;
+ sstatus.suspended_state = status->suspended_state;
+ sstatus.audio_tstamp = status->audio_tstamp;
+ }
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
- if (put_user(sstatus.state, &src->s.status.state) ||
- put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
- put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
- put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
- put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
- put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
- put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
- put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
- put_user(scontrol.avail_min, &src->c.control.avail_min))
+ if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, src))
return -EFAULT;
return 0;
@@ -3232,7 +3286,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
{
struct snd_xfern xfern;
struct snd_pcm_runtime *runtime = substream->runtime;
- void *bufs;
+ void *bufs __free(kfree) = NULL;
snd_pcm_sframes_t result;
if (runtime->state == SNDRV_PCM_STATE_OPEN)
@@ -3244,14 +3298,13 @@ 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)
result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
else
result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
- kfree(bufs);
if (put_user(result, &_xfern->result))
return -EFAULT;
return result < 0 ? result : 0;
@@ -3519,7 +3572,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
unsigned long i;
- void __user **bufs;
+ void __user **bufs __free(kfree) = NULL;
snd_pcm_uframes_t frames;
const struct iovec *iov = iter_iov(to);
@@ -3531,7 +3584,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
- if (!to->user_backed)
+ if (!user_backed_iter(to))
return -EINVAL;
if (to->nr_segs > 1024 || to->nr_segs != runtime->channels)
return -EINVAL;
@@ -3548,7 +3601,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
result = snd_pcm_lib_readv(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
- kfree(bufs);
return result;
}
@@ -3559,7 +3611,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
struct snd_pcm_runtime *runtime;
snd_pcm_sframes_t result;
unsigned long i;
- void __user **bufs;
+ void __user **bufs __free(kfree) = NULL;
snd_pcm_uframes_t frames;
const struct iovec *iov = iter_iov(from);
@@ -3571,7 +3623,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
if (runtime->state == SNDRV_PCM_STATE_OPEN ||
runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
- if (!from->user_backed)
+ if (!user_backed_iter(from))
return -EINVAL;
if (from->nr_segs > 128 || from->nr_segs != runtime->channels ||
!frame_aligned(runtime, iov->iov_len))
@@ -3587,7 +3639,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
result = snd_pcm_lib_writev(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
- kfree(bufs);
return result;
}
@@ -3616,7 +3667,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
poll_wait(file, &runtime->sleep, wait);
mask = 0;
- snd_pcm_stream_lock_irq(substream);
+ guard(pcm_stream_lock_irq)(substream);
avail = snd_pcm_avail(substream);
switch (runtime->state) {
case SNDRV_PCM_STATE_RUNNING:
@@ -3636,7 +3687,6 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
mask = ok | EPOLLERR;
break;
}
- snd_pcm_stream_unlock_irq(substream);
return mask;
}
@@ -3777,6 +3827,26 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
#endif /* coherent mmap */
/*
+ * snd_pcm_mmap_data_open - increase the mmap counter
+ */
+static void snd_pcm_mmap_data_open(struct vm_area_struct *area)
+{
+ struct snd_pcm_substream *substream = area->vm_private_data;
+
+ atomic_inc(&substream->mmap_count);
+}
+
+/*
+ * snd_pcm_mmap_data_close - decrease the mmap counter
+ */
+static void snd_pcm_mmap_data_close(struct vm_area_struct *area)
+{
+ struct snd_pcm_substream *substream = area->vm_private_data;
+
+ atomic_dec(&substream->mmap_count);
+}
+
+/*
* fault callback for mmapping a RAM page
*/
static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
@@ -3796,9 +3866,11 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
if (substream->ops->page)
page = substream->ops->page(substream, offset);
- else if (!snd_pcm_get_dma_buf(substream))
+ else if (!snd_pcm_get_dma_buf(substream)) {
+ if (WARN_ON_ONCE(!runtime->dma_area))
+ return VM_FAULT_SIGBUS;
page = virt_to_page(runtime->dma_area + offset);
- else
+ } else
page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset);
if (!page)
return VM_FAULT_SIGBUS;
@@ -4029,8 +4101,8 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams)
{
- struct snd_pcm_hw_params *params;
- struct snd_pcm_hw_params_old *oparams = NULL;
+ struct snd_pcm_hw_params *params __free(kfree) = NULL;
+ struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
int err;
params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -4038,34 +4110,28 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
return -ENOMEM;
oparams = memdup_user(_oparams, sizeof(*oparams));
- if (IS_ERR(oparams)) {
- err = PTR_ERR(oparams);
- goto out;
- }
+ if (IS_ERR(oparams))
+ return PTR_ERR(oparams);
snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_refine(substream, params);
if (err < 0)
- goto out_old;
+ return err;
err = fixup_unreferenced_params(substream, params);
if (err < 0)
- goto out_old;
+ return err;
snd_pcm_hw_convert_to_old_params(oparams, params);
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
- err = -EFAULT;
-out_old:
- kfree(oparams);
-out:
- kfree(params);
- return err;
+ return -EFAULT;
+ return 0;
}
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams)
{
- struct snd_pcm_hw_params *params;
- struct snd_pcm_hw_params_old *oparams = NULL;
+ struct snd_pcm_hw_params *params __free(kfree) = NULL;
+ struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL;
int err;
params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -4073,24 +4139,18 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
return -ENOMEM;
oparams = memdup_user(_oparams, sizeof(*oparams));
- if (IS_ERR(oparams)) {
- err = PTR_ERR(oparams);
- goto out;
- }
+ if (IS_ERR(oparams))
+ return PTR_ERR(oparams);
snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_params(substream, params);
if (err < 0)
- goto out_old;
+ return err;
snd_pcm_hw_convert_to_old_params(oparams, params);
if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
- err = -EFAULT;
-out_old:
- kfree(oparams);
-out:
- kfree(params);
- return err;
+ return -EFAULT;
+ return 0;
}
#endif /* CONFIG_SND_SUPPORT_OLD_API */
@@ -4130,7 +4190,6 @@ const struct file_operations snd_pcm_f_ops[2] = {
.write_iter = snd_pcm_writev,
.open = snd_pcm_playback_open,
.release = snd_pcm_release,
- .llseek = no_llseek,
.poll = snd_pcm_poll,
.unlocked_ioctl = snd_pcm_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
@@ -4144,7 +4203,6 @@ const struct file_operations snd_pcm_f_ops[2] = {
.read_iter = snd_pcm_readv,
.open = snd_pcm_capture_open,
.release = snd_pcm_release,
- .llseek = no_llseek,
.poll = snd_pcm_poll,
.unlocked_ioctl = snd_pcm_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index c43484b22b34..ab0e5bd70f8f 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -108,8 +108,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream)
if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0)
return;
sprintf(timer->name, "PCM %s %i-%i-%i",
- substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
- "capture" : "playback",
+ snd_pcm_direction_name(substream->stream),
tid.card, tid.device, tid.subdevice);
timer->hw = snd_pcm_timer;
if (snd_device_register(timer->card, timer) < 0) {
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h
index 350b40b906ca..adb9b1f3bbfa 100644
--- a/sound/core/pcm_trace.h
+++ b/sound/core/pcm_trace.h
@@ -95,7 +95,7 @@ TRACE_EVENT(hw_ptr_error,
__entry->device = (substream)->pcm->device;
__entry->number = (substream)->number;
__entry->stream = (substream)->stream;
- __assign_str(reason, why);
+ __assign_str(reason);
),
TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s",
__entry->card, __entry->device,
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 7147fda66d93..8969ee2757f1 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -21,6 +21,7 @@
#include <sound/control.h>
#include <sound/minors.h>
#include <sound/initval.h>
+#include <sound/ump.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
@@ -35,7 +36,6 @@ module_param_array(amidi_map, int, NULL, 0444);
MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
#endif /* CONFIG_SND_OSSEMUL */
-static int snd_rawmidi_free(struct snd_rawmidi *rmidi);
static int snd_rawmidi_dev_free(struct snd_device *device);
static int snd_rawmidi_dev_register(struct snd_device *device);
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
@@ -44,11 +44,11 @@ static LIST_HEAD(snd_rawmidi_devices);
static DEFINE_MUTEX(register_mutex);
#define rmidi_err(rmidi, fmt, args...) \
- dev_err(&(rmidi)->dev, fmt, ##args)
+ dev_err((rmidi)->dev, fmt, ##args)
#define rmidi_warn(rmidi, fmt, args...) \
- dev_warn(&(rmidi)->dev, fmt, ##args)
+ dev_warn((rmidi)->dev, fmt, ##args)
#define rmidi_dbg(rmidi, fmt, args...) \
- dev_dbg(&(rmidi)->dev, fmt, ##args)
+ dev_dbg((rmidi)->dev, fmt, ##args)
struct snd_rawmidi_status32 {
s32 stream;
@@ -73,6 +73,9 @@ struct snd_rawmidi_status64 {
#define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64)
+#define rawmidi_is_ump(rmidi) \
+ (IS_ENABLED(CONFIG_SND_UMP) && ((rmidi)->info_flags & SNDRV_RAWMIDI_INFO_UMP))
+
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
struct snd_rawmidi *rawmidi;
@@ -102,13 +105,8 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime)
static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
- bool ready;
-
- spin_lock_irqsave(&substream->lock, flags);
- ready = __snd_rawmidi_ready(substream->runtime);
- spin_unlock_irqrestore(&substream->lock, flags);
- return ready;
+ guard(spinlock_irqsave)(&substream->lock);
+ return __snd_rawmidi_ready(substream->runtime);
}
static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
@@ -181,9 +179,23 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
}
runtime->appl_ptr = runtime->hw_ptr = 0;
substream->runtime = runtime;
+ if (rawmidi_is_ump(substream->rmidi))
+ runtime->align = 3;
return 0;
}
+/* get the current alignment (either 0 or 3) */
+static inline int get_align(struct snd_rawmidi_runtime *runtime)
+{
+ if (IS_ENABLED(CONFIG_SND_UMP))
+ return runtime->align;
+ else
+ return 0;
+}
+
+/* get the trimmed size with the current alignment */
+#define get_aligned_size(runtime, size) ((size) & ~get_align(runtime))
+
static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
@@ -221,12 +233,9 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream,
bool is_input)
{
- unsigned long flags;
-
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (substream->opened && substream->runtime)
__reset_runtime_ptrs(substream->runtime, is_input);
- spin_unlock_irqrestore(&substream->lock, flags);
}
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
@@ -243,33 +252,29 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
long timeout;
struct snd_rawmidi_runtime *runtime;
- spin_lock_irq(&substream->lock);
- runtime = substream->runtime;
- if (!substream->opened || !runtime || !runtime->buffer) {
- err = -EINVAL;
- } else {
+ scoped_guard(spinlock_irq, &substream->lock) {
+ runtime = substream->runtime;
+ if (!substream->opened || !runtime || !runtime->buffer)
+ return -EINVAL;
snd_rawmidi_buffer_ref(runtime);
runtime->drain = 1;
}
- spin_unlock_irq(&substream->lock);
- if (err < 0)
- return err;
timeout = wait_event_interruptible_timeout(runtime->sleep,
(runtime->avail >= runtime->buffer_size),
10*HZ);
- spin_lock_irq(&substream->lock);
- if (signal_pending(current))
- err = -ERESTARTSYS;
- if (runtime->avail < runtime->buffer_size && !timeout) {
- rmidi_warn(substream->rmidi,
- "rawmidi drain error (avail = %li, buffer_size = %li)\n",
- (long)runtime->avail, (long)runtime->buffer_size);
- err = -EIO;
+ scoped_guard(spinlock_irq, &substream->lock) {
+ if (signal_pending(current))
+ err = -ERESTARTSYS;
+ if (runtime->avail < runtime->buffer_size && !timeout) {
+ rmidi_warn(substream->rmidi,
+ "rawmidi drain error (avail = %li, buffer_size = %li)\n",
+ (long)runtime->avail, (long)runtime->buffer_size);
+ err = -EIO;
+ }
+ runtime->drain = 0;
}
- runtime->drain = 0;
- spin_unlock_irq(&substream->lock);
if (err != -ERESTARTSYS) {
/* we need wait a while to make sure that Tx FIFOs are empty */
@@ -280,9 +285,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
snd_rawmidi_drop_output(substream);
}
- spin_lock_irq(&substream->lock);
- snd_rawmidi_buffer_unref(runtime);
- spin_unlock_irq(&substream->lock);
+ scoped_guard(spinlock_irq, &substream->lock)
+ snd_rawmidi_buffer_unref(runtime);
return err;
}
@@ -346,14 +350,13 @@ static int open_substream(struct snd_rawmidi *rmidi,
snd_rawmidi_runtime_free(substream);
return err;
}
- spin_lock_irq(&substream->lock);
+ guard(spinlock_irq)(&substream->lock);
substream->opened = 1;
substream->active_sensing = 0;
if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
substream->append = 1;
substream->pid = get_pid(task_pid(current));
rmidi->streams[substream->stream].substream_opened++;
- spin_unlock_irq(&substream->lock);
}
substream->use_count++;
return 0;
@@ -406,28 +409,18 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
}
/* called from sound/core/seq/seq_midi.c */
-int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
+int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
int mode, struct snd_rawmidi_file *rfile)
{
- struct snd_rawmidi *rmidi;
- int err = 0;
+ int err;
if (snd_BUG_ON(!rfile))
return -EINVAL;
+ if (!try_module_get(rmidi->card->module))
+ return -ENXIO;
- mutex_lock(&register_mutex);
- rmidi = snd_rawmidi_search(card, device);
- if (!rmidi)
- err = -ENODEV;
- else if (!try_module_get(rmidi->card->module))
- err = -ENXIO;
- mutex_unlock(&register_mutex);
- if (err < 0)
- return err;
-
- mutex_lock(&rmidi->open_mutex);
+ guard(mutex)(&rmidi->open_mutex);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
- mutex_unlock(&rmidi->open_mutex);
if (err < 0)
module_put(rmidi->card->module);
return err;
@@ -560,10 +553,10 @@ static void close_substream(struct snd_rawmidi *rmidi,
}
snd_rawmidi_buffer_ref_sync(substream);
}
- spin_lock_irq(&substream->lock);
- substream->opened = 0;
- substream->append = 0;
- spin_unlock_irq(&substream->lock);
+ scoped_guard(spinlock_irq, &substream->lock) {
+ substream->opened = 0;
+ substream->append = 0;
+ }
substream->ops->close(substream);
if (substream->runtime->private_free)
substream->runtime->private_free(substream);
@@ -578,7 +571,7 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
struct snd_rawmidi *rmidi;
rmidi = rfile->rmidi;
- mutex_lock(&rmidi->open_mutex);
+ guard(mutex)(&rmidi->open_mutex);
if (rfile->input) {
close_substream(rmidi, rfile->input, 1);
rfile->input = NULL;
@@ -588,7 +581,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
rfile->output = NULL;
}
rfile->rmidi = NULL;
- mutex_unlock(&rmidi->open_mutex);
wake_up(&rmidi->open_wait);
}
@@ -637,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;
- strcpy(info->id, rmidi->id);
- strcpy(info->name, rmidi->name);
- strcpy(info->subname, substream->name);
+ if (substream->inactive)
+ info->flags |= SNDRV_RAWMIDI_INFO_STREAM_INACTIVE;
+ strscpy(info->id, rmidi->id);
+ strscpy(info->name, rmidi->name);
+ strscpy(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;
}
@@ -687,12 +682,8 @@ static int __snd_rawmidi_info_select(struct snd_card *card,
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
{
- int ret;
-
- mutex_lock(&register_mutex);
- ret = __snd_rawmidi_info_select(card, info);
- mutex_unlock(&register_mutex);
- return ret;
+ guard(mutex)(&register_mutex);
+ return __snd_rawmidi_info_select(card, info);
}
EXPORT_SYMBOL(snd_rawmidi_info_select);
@@ -730,6 +721,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
return -EINVAL;
if (params->avail_min < 1 || params->avail_min > params->buffer_size)
return -EINVAL;
+ if (params->buffer_size & get_align(runtime))
+ return -EINVAL;
if (params->buffer_size != runtime->buffer_size) {
newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
if (!newbuf)
@@ -757,15 +750,12 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
int err;
snd_rawmidi_drain_output(substream);
- mutex_lock(&substream->rmidi->open_mutex);
+ guard(mutex)(&substream->rmidi->open_mutex);
if (substream->append && substream->use_count > 1)
- err = -EBUSY;
- else
- err = resize_runtime_buffer(substream, params, false);
-
+ return -EBUSY;
+ err = resize_runtime_buffer(substream, params, false);
if (!err)
substream->active_sensing = !params->no_active_sensing;
- mutex_unlock(&substream->rmidi->open_mutex);
return err;
}
EXPORT_SYMBOL(snd_rawmidi_output_params);
@@ -778,7 +768,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
int err;
snd_rawmidi_drain_input(substream);
- mutex_lock(&substream->rmidi->open_mutex);
+ guard(mutex)(&substream->rmidi->open_mutex);
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
err = -EINVAL;
else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
@@ -792,7 +782,6 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
substream->framing = framing;
substream->clock_type = clock_type;
}
- mutex_unlock(&substream->rmidi->open_mutex);
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_input_params);
@@ -804,9 +793,8 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
memset(status, 0, sizeof(*status));
status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
- spin_lock_irq(&substream->lock);
+ guard(spinlock_irq)(&substream->lock);
status->avail = runtime->avail;
- spin_unlock_irq(&substream->lock);
return 0;
}
@@ -817,11 +805,10 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
memset(status, 0, sizeof(*status));
status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
- spin_lock_irq(&substream->lock);
+ guard(spinlock_irq)(&substream->lock);
status->avail = runtime->avail;
status->xruns = runtime->xruns;
runtime->xruns = 0;
- spin_unlock_irq(&substream->lock);
return 0;
}
@@ -902,6 +889,7 @@ static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile,
static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct snd_rawmidi_file *rfile;
+ struct snd_rawmidi *rmidi;
void __user *argp = (void __user *)arg;
rfile = file->private_data;
@@ -993,12 +981,65 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
}
}
default:
- rmidi_dbg(rfile->rmidi,
- "rawmidi: unknown command = 0x%x\n", cmd);
+ rmidi = rfile->rmidi;
+ if (rmidi->ops && rmidi->ops->ioctl)
+ return rmidi->ops->ioctl(rmidi, cmd, argp);
+ rmidi_dbg(rmidi, "rawmidi: unknown command = 0x%x\n", cmd);
}
return -ENOTTY;
}
+/* ioctl to find the next device; either legacy or UMP depending on @find_ump */
+static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp,
+ bool find_ump)
+
+{
+ struct snd_rawmidi *rmidi;
+ int device;
+ bool is_ump;
+
+ if (get_user(device, argp))
+ return -EFAULT;
+ if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
+ device = SNDRV_RAWMIDI_DEVICES - 1;
+ scoped_guard(mutex, &register_mutex) {
+ device = device < 0 ? 0 : device + 1;
+ for (; device < SNDRV_RAWMIDI_DEVICES; device++) {
+ rmidi = snd_rawmidi_search(card, device);
+ if (!rmidi)
+ continue;
+ is_ump = rawmidi_is_ump(rmidi);
+ if (find_ump == is_ump)
+ break;
+ }
+ if (device == SNDRV_RAWMIDI_DEVICES)
+ device = -1;
+ }
+ if (put_user(device, argp))
+ return -EFAULT;
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_SND_UMP)
+/* inquiry of UMP endpoint and block info via control API */
+static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd,
+ void __user *argp)
+{
+ struct snd_ump_endpoint_info __user *info = argp;
+ struct snd_rawmidi *rmidi;
+ int device;
+
+ if (get_user(device, &info->device))
+ return -EFAULT;
+ guard(mutex)(&register_mutex);
+ rmidi = snd_rawmidi_search(card, device);
+ if (rmidi && rmidi->ops && rmidi->ops->ioctl)
+ return rmidi->ops->ioctl(rmidi, cmd, argp);
+ else
+ return -ENXIO;
+}
+#endif
+
static int snd_rawmidi_control_ioctl(struct snd_card *card,
struct snd_ctl_file *control,
unsigned int cmd,
@@ -1008,27 +1049,15 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
switch (cmd) {
case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
- {
- int device;
-
- if (get_user(device, (int __user *)argp))
- return -EFAULT;
- if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
- device = SNDRV_RAWMIDI_DEVICES - 1;
- mutex_lock(&register_mutex);
- device = device < 0 ? 0 : device + 1;
- while (device < SNDRV_RAWMIDI_DEVICES) {
- if (snd_rawmidi_search(card, device))
- break;
- device++;
- }
- if (device == SNDRV_RAWMIDI_DEVICES)
- device = -1;
- mutex_unlock(&register_mutex);
- if (put_user(device, (int __user *)argp))
- return -EFAULT;
- return 0;
- }
+ return snd_rawmidi_next_device(card, argp, false);
+#if IS_ENABLED(CONFIG_SND_UMP)
+ case SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE:
+ return snd_rawmidi_next_device(card, argp, true);
+ case SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO:
+ return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_ENDPOINT_INFO, argp);
+ case SNDRV_CTL_IOCTL_UMP_BLOCK_INFO:
+ return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_BLOCK_INFO, argp);
+#endif
case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
{
int val;
@@ -1052,12 +1081,13 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec };
int orig_count = src_count;
int frame_size = sizeof(struct snd_rawmidi_framing_tstamp);
+ int align = get_align(runtime);
BUILD_BUG_ON(frame_size != 0x20);
if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0))
return -EINVAL;
- while (src_count > 0) {
+ while (src_count > align) {
if ((int)(runtime->buffer_size - runtime->avail) < frame_size) {
runtime->xruns += src_count;
break;
@@ -1065,7 +1095,9 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH)
frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH;
else {
- frame.length = src_count;
+ frame.length = get_aligned_size(runtime, src_count);
+ if (!frame.length)
+ break;
memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH);
}
memcpy(frame.data, buffer, frame.length);
@@ -1111,24 +1143,24 @@ static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substr
int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
const unsigned char *buffer, int count)
{
- unsigned long flags;
struct timespec64 ts64 = get_framing_tstamp(substream);
int result = 0, count1;
struct snd_rawmidi_runtime *runtime;
- spin_lock_irqsave(&substream->lock, flags);
- if (!substream->opened) {
- result = -EBADFD;
- goto unlock;
- }
+ guard(spinlock_irqsave)(&substream->lock);
+ if (!substream->opened)
+ return -EBADFD;
runtime = substream->runtime;
if (!runtime || !runtime->buffer) {
rmidi_dbg(substream->rmidi,
"snd_rawmidi_receive: input is not active!!!\n");
- result = -EINVAL;
- goto unlock;
+ return -EINVAL;
}
+ count = get_aligned_size(runtime, count);
+ if (!count)
+ return result;
+
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
} else if (count == 1) { /* special case, faster code */
@@ -1148,6 +1180,9 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
count1 = count;
if (count1 > (int)(runtime->buffer_size - runtime->avail))
count1 = runtime->buffer_size - runtime->avail;
+ count1 = get_aligned_size(runtime, count1);
+ if (!count1)
+ return result;
memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
runtime->hw_ptr += count1;
runtime->hw_ptr %= runtime->buffer_size;
@@ -1175,8 +1210,6 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
else if (__snd_rawmidi_ready(runtime))
wake_up(&runtime->sleep);
}
- unlock:
- spin_unlock_irqrestore(&substream->lock, flags);
return result;
}
EXPORT_SYMBOL(snd_rawmidi_receive);
@@ -1298,20 +1331,15 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime;
- int result;
- unsigned long flags;
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
runtime = substream->runtime;
if (!substream->opened || !runtime || !runtime->buffer) {
rmidi_dbg(substream->rmidi,
"snd_rawmidi_transmit_empty: output is not active!!!\n");
- result = 1;
- } else {
- result = runtime->avail >= runtime->buffer_size;
+ return 1;
}
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return (runtime->avail >= runtime->buffer_size);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
@@ -1348,12 +1376,18 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
count1 = count;
if (count1 > (int)(runtime->buffer_size - runtime->avail))
count1 = runtime->buffer_size - runtime->avail;
+ count1 = get_aligned_size(runtime, count1);
+ if (!count1)
+ goto __skip;
memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1);
count -= count1;
result += count1;
if (count > 0) {
if (count > (int)(runtime->buffer_size - runtime->avail - count1))
count = runtime->buffer_size - runtime->avail - count1;
+ count = get_aligned_size(runtime, count);
+ if (!count)
+ goto __skip;
memcpy(buffer + count1, runtime->buffer, count);
result += count;
}
@@ -1379,16 +1413,10 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count)
{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened || !substream->runtime)
- result = -EBADFD;
- else
- result = __snd_rawmidi_transmit_peek(substream, buffer, count);
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return -EBADFD;
+ return __snd_rawmidi_transmit_peek(substream, buffer, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
@@ -1410,6 +1438,7 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
return -EINVAL;
}
snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
+ count = get_aligned_size(runtime, count);
runtime->hw_ptr += count;
runtime->hw_ptr %= runtime->buffer_size;
runtime->avail += count;
@@ -1434,16 +1463,10 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
*/
int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened || !substream->runtime)
- result = -EBADFD;
- else
- result = __snd_rawmidi_transmit_ack(substream, count);
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return -EBADFD;
+ return __snd_rawmidi_transmit_ack(substream, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
@@ -1460,21 +1483,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count)
{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened)
- result = -EBADFD;
- else {
- count = __snd_rawmidi_transmit_peek(substream, buffer, count);
- if (count <= 0)
- result = count;
- else
- result = __snd_rawmidi_transmit_ack(substream, count);
- }
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return -EBADFD;
+ count = __snd_rawmidi_transmit_peek(substream, buffer, count);
+ if (count <= 0)
+ return count;
+ return __snd_rawmidi_transmit_ack(substream, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit);
@@ -1487,17 +1502,15 @@ EXPORT_SYMBOL(snd_rawmidi_transmit);
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime;
- unsigned long flags;
int count = 0;
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
runtime = substream->runtime;
if (substream->opened && runtime &&
runtime->avail < runtime->buffer_size) {
count = runtime->buffer_size - runtime->avail;
__snd_rawmidi_transmit_ack(substream, count);
}
- spin_unlock_irqrestore(&substream->lock, flags);
return count;
}
EXPORT_SYMBOL(snd_rawmidi_proceed);
@@ -1696,7 +1709,12 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
- mutex_lock(&rmidi->open_mutex);
+ if (IS_ENABLED(CONFIG_SND_UMP))
+ snd_iprintf(buffer, "Type: %s\n",
+ rawmidi_is_ump(rmidi) ? "UMP" : "Legacy");
+ if (rmidi->ops && rmidi->ops->proc_read)
+ rmidi->ops->proc_read(entry, buffer);
+ guard(mutex)(&rmidi->open_mutex);
if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
list_for_each_entry(substream,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
@@ -1711,10 +1729,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Owner PID : %d\n",
pid_vnr(substream->pid));
runtime = substream->runtime;
- spin_lock_irq(&substream->lock);
- buffer_size = runtime->buffer_size;
- avail = runtime->avail;
- spin_unlock_irq(&substream->lock);
+ scoped_guard(spinlock_irq, &substream->lock) {
+ buffer_size = runtime->buffer_size;
+ avail = runtime->avail;
+ }
snd_iprintf(buffer,
" Mode : %s\n"
" Buffer size : %lu\n"
@@ -1738,11 +1756,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Owner PID : %d\n",
pid_vnr(substream->pid));
runtime = substream->runtime;
- spin_lock_irq(&substream->lock);
- buffer_size = runtime->buffer_size;
- avail = runtime->avail;
- xruns = runtime->xruns;
- spin_unlock_irq(&substream->lock);
+ scoped_guard(spinlock_irq, &substream->lock) {
+ buffer_size = runtime->buffer_size;
+ avail = runtime->avail;
+ xruns = runtime->xruns;
+ }
snd_iprintf(buffer,
" Buffer size : %lu\n"
" Avail : %lu\n"
@@ -1759,7 +1777,6 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
}
}
}
- mutex_unlock(&rmidi->open_mutex);
}
/*
@@ -1772,7 +1789,6 @@ static const struct file_operations snd_rawmidi_f_ops = {
.write = snd_rawmidi_write,
.open = snd_rawmidi_open,
.release = snd_rawmidi_release,
- .llseek = no_llseek,
.poll = snd_rawmidi_poll,
.unlocked_ioctl = snd_rawmidi_ioctl,
.compat_ioctl = snd_rawmidi_ioctl_compat,
@@ -1801,30 +1817,12 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
return 0;
}
-static void release_rawmidi_device(struct device *dev)
+/* used for both rawmidi and ump */
+int snd_rawmidi_init(struct snd_rawmidi *rmidi,
+ struct snd_card *card, char *id, int device,
+ int output_count, int input_count,
+ unsigned int info_flags)
{
- kfree(container_of(dev, struct snd_rawmidi, dev));
-}
-
-/**
- * snd_rawmidi_new - create a rawmidi instance
- * @card: the card instance
- * @id: the id string
- * @device: the device index
- * @output_count: the number of output streams
- * @input_count: the number of input streams
- * @rrawmidi: the pointer to store the new rawmidi instance
- *
- * Creates a new rawmidi instance.
- * Use snd_rawmidi_set_ops() to set the operators to the new instance.
- *
- * Return: Zero if successful, or a negative error code on failure.
- */
-int snd_rawmidi_new(struct snd_card *card, char *id, int device,
- int output_count, int input_count,
- struct snd_rawmidi **rrawmidi)
-{
- struct snd_rawmidi *rmidi;
int err;
static const struct snd_device_ops ops = {
.dev_free = snd_rawmidi_dev_free,
@@ -1832,50 +1830,79 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
.dev_disconnect = snd_rawmidi_dev_disconnect,
};
- if (snd_BUG_ON(!card))
- return -ENXIO;
- if (rrawmidi)
- *rrawmidi = NULL;
- rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
- if (!rmidi)
- return -ENOMEM;
rmidi->card = card;
rmidi->device = device;
mutex_init(&rmidi->open_mutex);
init_waitqueue_head(&rmidi->open_wait);
INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams);
INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);
+ rmidi->info_flags = info_flags;
if (id != NULL)
strscpy(rmidi->id, id, sizeof(rmidi->id));
- snd_device_initialize(&rmidi->dev, card);
- rmidi->dev.release = release_rawmidi_device;
- dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
+ err = snd_device_alloc(&rmidi->dev, card);
+ if (err < 0)
+ return err;
+ if (rawmidi_is_ump(rmidi))
+ dev_set_name(rmidi->dev, "umpC%iD%i", card->number, device);
+ else
+ dev_set_name(rmidi->dev, "midiC%iD%i", card->number, device);
err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
SNDRV_RAWMIDI_STREAM_INPUT,
input_count);
if (err < 0)
- goto error;
+ return err;
err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
SNDRV_RAWMIDI_STREAM_OUTPUT,
output_count);
if (err < 0)
- goto error;
+ return err;
err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops);
if (err < 0)
- goto error;
+ return err;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_rawmidi_init);
+/**
+ * snd_rawmidi_new - create a rawmidi instance
+ * @card: the card instance
+ * @id: the id string
+ * @device: the device index
+ * @output_count: the number of output streams
+ * @input_count: the number of input streams
+ * @rrawmidi: the pointer to store the new rawmidi instance
+ *
+ * Creates a new rawmidi instance.
+ * Use snd_rawmidi_set_ops() to set the operators to the new instance.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_rawmidi_new(struct snd_card *card, char *id, int device,
+ int output_count, int input_count,
+ struct snd_rawmidi **rrawmidi)
+{
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ if (rrawmidi)
+ *rrawmidi = NULL;
+ rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
+ if (!rmidi)
+ return -ENOMEM;
+ err = snd_rawmidi_init(rmidi, card, id, device,
+ output_count, input_count, 0);
+ if (err < 0) {
+ snd_rawmidi_free(rmidi);
+ return err;
+ }
if (rrawmidi)
*rrawmidi = rmidi;
return 0;
-
- error:
- snd_rawmidi_free(rmidi);
- return err;
}
EXPORT_SYMBOL(snd_rawmidi_new);
@@ -1890,7 +1917,8 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
}
}
-static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
+/* called from ump.c, too */
+int snd_rawmidi_free(struct snd_rawmidi *rmidi)
{
if (!rmidi)
return 0;
@@ -1904,9 +1932,11 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
if (rmidi->private_free)
rmidi->private_free(rmidi);
- put_device(&rmidi->dev);
+ put_device(rmidi->dev);
+ kfree(rmidi);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_rawmidi_free);
static int snd_rawmidi_dev_free(struct snd_device *device)
{
@@ -1934,18 +1964,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
return -ENOMEM;
err = 0;
- mutex_lock(&register_mutex);
- if (snd_rawmidi_search(rmidi->card, rmidi->device))
- err = -EBUSY;
- else
- list_add_tail(&rmidi->list, &snd_rawmidi_devices);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_mutex) {
+ if (snd_rawmidi_search(rmidi->card, rmidi->device))
+ err = -EBUSY;
+ else
+ list_add_tail(&rmidi->list, &snd_rawmidi_devices);
+ }
if (err < 0)
return err;
err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
rmidi->card, rmidi->device,
- &snd_rawmidi_f_ops, rmidi, &rmidi->dev);
+ &snd_rawmidi_f_ops, rmidi, rmidi->dev);
if (err < 0) {
rmidi_err(rmidi, "unable to register\n");
goto error;
@@ -1957,7 +1987,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
}
#ifdef CONFIG_SND_OSSEMUL
rmidi->ossreg = 0;
- if ((int)rmidi->device == midi_map[rmidi->card->number]) {
+ if (!rawmidi_is_ump(rmidi) &&
+ (int)rmidi->device == midi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
rmidi->card, 0, &snd_rawmidi_f_ops,
rmidi) < 0) {
@@ -1971,7 +2002,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
#endif
}
}
- if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
+ if (!rawmidi_is_ump(rmidi) &&
+ (int)rmidi->device == amidi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
rmidi->card, 1, &snd_rawmidi_f_ops,
rmidi) < 0) {
@@ -1995,7 +2027,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
}
rmidi->proc_entry = entry;
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
- if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
+ /* no own registration mechanism? */
+ if (!rmidi->ops || !rmidi->ops->dev_register) {
if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
rmidi->seq_dev->private_data = rmidi;
rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free;
@@ -2007,11 +2040,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
return 0;
error_unregister:
- snd_unregister_device(&rmidi->dev);
+ snd_unregister_device(rmidi->dev);
error:
- mutex_lock(&register_mutex);
- list_del(&rmidi->list);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_mutex)
+ list_del(&rmidi->list);
return err;
}
@@ -2020,8 +2052,8 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
struct snd_rawmidi *rmidi = device->device_data;
int dir;
- mutex_lock(&register_mutex);
- mutex_lock(&rmidi->open_mutex);
+ guard(mutex)(&register_mutex);
+ guard(mutex)(&rmidi->open_mutex);
wake_up(&rmidi->open_wait);
list_del_init(&rmidi->list);
for (dir = 0; dir < 2; dir++) {
@@ -2046,9 +2078,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
rmidi->ossreg = 0;
}
#endif /* CONFIG_SND_OSSEMUL */
- snd_unregister_device(&rmidi->dev);
- mutex_unlock(&rmidi->open_mutex);
- mutex_unlock(&register_mutex);
+ snd_unregister_device(rmidi->dev);
return 0;
}
@@ -2076,13 +2106,11 @@ EXPORT_SYMBOL(snd_rawmidi_set_ops);
static int __init alsa_rawmidi_init(void)
{
-
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
#ifdef CONFIG_SND_OSSEMUL
- { int i;
/* check device map table */
- for (i = 0; i < SNDRV_CARDS; i++) {
+ for (int i = 0; i < SNDRV_CARDS; i++) {
if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
i, midi_map[i]);
@@ -2094,7 +2122,6 @@ static int __init alsa_rawmidi_init(void)
amidi_map[i] = 1;
}
}
- }
#endif /* CONFIG_SND_OSSEMUL */
return 0;
}
diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
index 68a93443583c..2c6de6e113e4 100644
--- a/sound/core/rawmidi_compat.c
+++ b/sound/core/rawmidi_compat.c
@@ -15,7 +15,7 @@ struct snd_rawmidi_params32 {
unsigned int no_active_sensing; /* avoid bit-field */
unsigned int mode;
unsigned char reserved[12];
-} __attribute__((packed));
+} __packed;
static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_params32 __user *src)
@@ -51,7 +51,7 @@ struct compat_snd_rawmidi_status64 {
u32 avail;
u32 xruns;
unsigned char reserved[16];
-} __attribute__((packed));
+} __packed;
static int snd_rawmidi_ioctl_status_compat64(struct snd_rawmidi_file *rfile,
struct compat_snd_rawmidi_status64 __user *src)
@@ -111,6 +111,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign
case SNDRV_RAWMIDI_IOCTL_INFO:
case SNDRV_RAWMIDI_IOCTL_DROP:
case SNDRV_RAWMIDI_IOCTL_DRAIN:
+#if IS_ENABLED(CONFIG_SND_UMP)
+ case SNDRV_UMP_IOCTL_ENDPOINT_INFO:
+ case SNDRV_UMP_IOCTL_BLOCK_INFO:
+#endif
return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_RAWMIDI_IOCTL_PARAMS32:
return snd_rawmidi_ioctl_params_compat(rfile, argp);
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
index f84718a44980..e4f58cb985d4 100644
--- a/sound/core/seq/Kconfig
+++ b/sound/core/seq/Kconfig
@@ -60,4 +60,17 @@ config SND_SEQ_MIDI_EMUL
config SND_SEQ_VIRMIDI
tristate
+config SND_SEQ_UMP
+ bool "Support for UMP events"
+ 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
+ essential feature for enabling MIDI 2.0 support.
+ It includes the automatic conversion of ALSA sequencer events
+ among legacy and UMP clients.
+
+config SND_SEQ_UMP_CLIENT
+ def_tristate SND_UMP && SND_SEQ_UMP
+
endif # SND_SEQUENCER
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index 3a2177a7e50c..0904aa48d88b 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -4,21 +4,24 @@
# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
-snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
+snd-seq-y := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
seq_fifo.o seq_prioq.o seq_timer.o \
seq_system.o seq_ports.o
snd-seq-$(CONFIG_SND_PROC_FS) += seq_info.o
-snd-seq-midi-objs := seq_midi.o
-snd-seq-midi-emul-objs := seq_midi_emul.o
-snd-seq-midi-event-objs := seq_midi_event.o
-snd-seq-dummy-objs := seq_dummy.o
-snd-seq-virmidi-objs := seq_virmidi.o
+snd-seq-$(CONFIG_SND_SEQ_UMP) += seq_ump_convert.o
+snd-seq-midi-y := seq_midi.o
+snd-seq-midi-emul-y := seq_midi_emul.o
+snd-seq-midi-event-y := seq_midi_event.o
+snd-seq-dummy-y := seq_dummy.o
+snd-seq-virmidi-y := seq_virmidi.o
+snd-seq-ump-client-y := seq_ump_client.o
obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o
obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/
obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o
+obj-$(CONFIG_SND_SEQ_UMP_CLIENT) += snd-seq-ump-client.o
obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o
obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o
obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o
diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile
index f1a60878549a..4e4741834208 100644
--- a/sound/core/seq/oss/Makefile
+++ b/sound/core/seq/oss/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
#
-snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
+snd-seq-oss-y := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \
seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 77c1214acd90..02d30d8b6c3a 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -117,18 +117,15 @@ static DEFINE_MUTEX(register_mutex);
static int
odev_open(struct inode *inode, struct file *file)
{
- int level, rc;
+ int level;
if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC)
level = SNDRV_SEQ_OSS_MODE_MUSIC;
else
level = SNDRV_SEQ_OSS_MODE_SYNTH;
- mutex_lock(&register_mutex);
- rc = snd_seq_oss_open(file, level);
- mutex_unlock(&register_mutex);
-
- return rc;
+ guard(mutex)(&register_mutex);
+ return snd_seq_oss_open(file, level);
}
static int
@@ -140,10 +137,8 @@ odev_release(struct inode *inode, struct file *file)
if (!dp)
return 0;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
snd_seq_oss_release(dp);
- mutex_unlock(&register_mutex);
-
return 0;
}
@@ -229,13 +224,12 @@ register_device(void)
{
int rc;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
&seq_oss_f_ops, NULL);
if (rc < 0) {
pr_err("ALSA: seq_oss: can't register device seq\n");
- mutex_unlock(&register_mutex);
return rc;
}
rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
@@ -244,22 +238,19 @@ register_device(void)
if (rc < 0) {
pr_err("ALSA: seq_oss: can't register device music\n");
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
- mutex_unlock(&register_mutex);
return rc;
}
- mutex_unlock(&register_mutex);
return 0;
}
static void
unregister_device(void)
{
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)
pr_err("ALSA: seq_oss: error unregister device music\n");
if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
pr_err("ALSA: seq_oss: error unregister device seq\n");
- mutex_unlock(&register_mutex);
}
/*
@@ -273,12 +264,11 @@ static struct snd_info_entry *info_entry;
static void
info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf)
{
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
snd_seq_oss_system_info_read(buf);
snd_seq_oss_synth_info_read(buf);
snd_seq_oss_midi_info_read(buf);
- mutex_unlock(&register_mutex);
}
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index 6c2c4fb9b753..935cf3df0b30 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;
@@ -116,10 +115,6 @@ __poll_t snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_ta
void snd_seq_oss_reset(struct seq_oss_devinfo *dp);
-/* */
-void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time);
-
-
/* proc interface */
void snd_seq_oss_system_info_read(struct snd_info_buffer *buf);
void snd_seq_oss_midi_info_read(struct snd_info_buffer *buf);
@@ -142,12 +137,7 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a
static inline int
snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg)
{
- int err;
-
- snd_seq_client_ioctl_lock(dp->cseq);
- err = snd_seq_kernel_client_ctl(dp->cseq, type, arg);
- snd_seq_client_ioctl_unlock(dp->cseq);
- return err;
+ return snd_seq_kernel_client_ioctl(dp->cseq, type, arg);
}
/* fill the addresses in header */
@@ -161,8 +151,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(int bool);
-
#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 42d4e7535a82..973f057eb731 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -63,25 +63,23 @@ int __init
snd_seq_oss_create_client(void)
{
int rc;
- struct snd_seq_port_info *port;
+ struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_seq_port_callback port_callback;
port = kzalloc(sizeof(*port), GFP_KERNEL);
- if (!port) {
- rc = -ENOMEM;
- goto __error;
- }
+ if (!port)
+ return -ENOMEM;
/* create ALSA client */
rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
"OSS sequencer");
if (rc < 0)
- goto __error;
+ return rc;
system_client = rc;
/* create announcement receiver port */
- strcpy(port->name, "Receiver");
+ strscpy(port->name, "Receiver");
port->addr.client = system_client;
port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
port->type = 0;
@@ -104,19 +102,16 @@ snd_seq_oss_create_client(void)
subs.dest.port = system_port;
call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
}
- rc = 0;
/* look up midi devices */
schedule_work(&async_lookup_work);
- __error:
- kfree(port);
- return rc;
+ return 0;
}
/*
- * 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)
@@ -352,7 +347,7 @@ alloc_seq_queue(struct seq_oss_devinfo *dp)
memset(&qinfo, 0, sizeof(qinfo));
qinfo.owner = system_client;
qinfo.locked = 1;
- strcpy(qinfo.name, "OSS Sequencer Emulation");
+ strscpy(qinfo.name, "OSS Sequencer Emulation");
rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo);
if (rc < 0)
return rc;
@@ -454,12 +449,6 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp)
/*
* misc. functions for proc interface
*/
-char *
-enabled_str(int bool)
-{
- return bool ? "enabled" : "disabled";
-}
-
static const char *
filemode_str(int val)
{
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 07efb38f58ac..023e5d0a4351 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -37,8 +37,10 @@ struct seq_oss_midi {
struct snd_midi_event *coder; /* MIDI event coder */
struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */
snd_use_lock_t use_lock;
+ struct mutex open_mutex;
};
+DEFINE_FREE(seq_oss_midi, struct seq_oss_midi *, if (!IS_ERR_OR_NULL(_T)) snd_use_lock_free(&(_T)->use_lock))
/*
* midi device table
@@ -63,16 +65,13 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
int
snd_seq_oss_midi_lookup_ports(int client)
{
- struct snd_seq_client_info *clinfo;
- struct snd_seq_port_info *pinfo;
+ struct snd_seq_client_info *clinfo __free(kfree) = NULL;
+ struct snd_seq_port_info *pinfo __free(kfree) = NULL;
clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
- if (! clinfo || ! pinfo) {
- kfree(clinfo);
- kfree(pinfo);
+ if (!clinfo || !pinfo)
return -ENOMEM;
- }
clinfo->client = -1;
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
if (clinfo->client == client)
@@ -82,8 +81,6 @@ snd_seq_oss_midi_lookup_ports(int client)
while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
snd_seq_oss_midi_check_new_port(pinfo);
}
- kfree(clinfo);
- kfree(pinfo);
return 0;
}
@@ -94,13 +91,11 @@ static struct seq_oss_midi *
get_mdev(int dev)
{
struct seq_oss_midi *mdev;
- unsigned long flags;
- spin_lock_irqsave(&register_lock, flags);
+ guard(spinlock_irqsave)(&register_lock);
mdev = midi_devs[dev];
if (mdev)
snd_use_lock_use(&mdev->use_lock);
- spin_unlock_irqrestore(&register_lock, flags);
return mdev;
}
@@ -112,19 +107,16 @@ find_slot(int client, int port)
{
int i;
struct seq_oss_midi *mdev;
- unsigned long flags;
- spin_lock_irqsave(&register_lock, flags);
+ guard(spinlock_irqsave)(&register_lock);
for (i = 0; i < max_midi_devs; i++) {
mdev = midi_devs[i];
if (mdev && mdev->client == client && mdev->port == port) {
/* found! */
snd_use_lock_use(&mdev->use_lock);
- spin_unlock_irqrestore(&register_lock, flags);
return mdev;
}
}
- spin_unlock_irqrestore(&register_lock, flags);
return NULL;
}
@@ -139,7 +131,6 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
{
int i;
struct seq_oss_midi *mdev;
- unsigned long flags;
/* the port must include generic midi */
if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
@@ -172,6 +163,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
mdev->flags = pinfo->capability;
mdev->opened = 0;
snd_use_lock_init(&mdev->use_lock);
+ mutex_init(&mdev->open_mutex);
/* copy and truncate the name of synth device */
strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
@@ -188,14 +180,13 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
/*
* look for en empty slot
*/
- spin_lock_irqsave(&register_lock, flags);
+ guard(spinlock_irqsave)(&register_lock);
for (i = 0; i < max_midi_devs; i++) {
if (midi_devs[i] == NULL)
break;
}
if (i >= max_midi_devs) {
if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
- spin_unlock_irqrestore(&register_lock, flags);
snd_midi_event_free(mdev->coder);
kfree(mdev);
return -ENOMEM;
@@ -204,7 +195,6 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
}
mdev->seq_device = i;
midi_devs[mdev->seq_device] = mdev;
- spin_unlock_irqrestore(&register_lock, flags);
return 0;
}
@@ -216,26 +206,24 @@ int
snd_seq_oss_midi_check_exit_port(int client, int port)
{
struct seq_oss_midi *mdev;
- unsigned long flags;
int index;
mdev = find_slot(client, port);
if (mdev) {
- spin_lock_irqsave(&register_lock, flags);
- midi_devs[mdev->seq_device] = NULL;
- spin_unlock_irqrestore(&register_lock, flags);
+ scoped_guard(spinlock_irqsave, &register_lock) {
+ midi_devs[mdev->seq_device] = NULL;
+ }
snd_use_lock_free(&mdev->use_lock);
snd_use_lock_sync(&mdev->use_lock);
snd_midi_event_free(mdev->coder);
kfree(mdev);
}
- spin_lock_irqsave(&register_lock, flags);
+ guard(spinlock_irqsave)(&register_lock);
for (index = max_midi_devs - 1; index >= 0; index--) {
if (midi_devs[index])
break;
}
max_midi_devs = index + 1;
- spin_unlock_irqrestore(&register_lock, flags);
return 0;
}
@@ -248,9 +236,8 @@ snd_seq_oss_midi_clear_all(void)
{
int i;
struct seq_oss_midi *mdev;
- unsigned long flags;
- spin_lock_irqsave(&register_lock, flags);
+ guard(spinlock_irqsave)(&register_lock);
for (i = 0; i < max_midi_devs; i++) {
mdev = midi_devs[i];
if (mdev) {
@@ -260,7 +247,6 @@ snd_seq_oss_midi_clear_all(void)
}
}
max_midi_devs = 0;
- spin_unlock_irqrestore(&register_lock, flags);
}
@@ -270,9 +256,8 @@ snd_seq_oss_midi_clear_all(void)
void
snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
{
- spin_lock_irq(&register_lock);
+ guard(spinlock_irq)(&register_lock);
dp->max_mididev = max_midi_devs;
- spin_unlock_irq(&register_lock);
}
/*
@@ -320,18 +305,17 @@ int
snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
{
int perm;
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
struct snd_seq_port_subscribe subs;
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
+ guard(mutex)(&mdev->open_mutex);
/* already used? */
- if (mdev->opened && mdev->devinfo != dp) {
- snd_use_lock_free(&mdev->use_lock);
+ if (mdev->opened && mdev->devinfo != dp)
return -EBUSY;
- }
perm = 0;
if (is_write_mode(fmode))
@@ -339,16 +323,12 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
if (is_read_mode(fmode))
perm |= PERM_READ;
perm &= mdev->flags;
- if (perm == 0) {
- snd_use_lock_free(&mdev->use_lock);
+ if (perm == 0)
return -ENXIO;
- }
/* already opened? */
- if ((mdev->opened & perm) == perm) {
- snd_use_lock_free(&mdev->use_lock);
+ if ((mdev->opened & perm) == perm)
return 0;
- }
perm &= ~mdev->opened;
@@ -371,13 +351,10 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
mdev->opened |= PERM_READ;
}
- if (! mdev->opened) {
- snd_use_lock_free(&mdev->use_lock);
+ if (!mdev->opened)
return -ENXIO;
- }
mdev->devinfo = dp;
- snd_use_lock_free(&mdev->use_lock);
return 0;
}
@@ -387,16 +364,15 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
int
snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
{
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
struct snd_seq_port_subscribe subs;
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
- if (! mdev->opened || mdev->devinfo != dp) {
- snd_use_lock_free(&mdev->use_lock);
+ guard(mutex)(&mdev->open_mutex);
+ if (!mdev->opened || mdev->devinfo != dp)
return 0;
- }
memset(&subs, 0, sizeof(subs));
if (mdev->opened & PERM_WRITE) {
@@ -414,8 +390,6 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
mdev->opened = 0;
mdev->devinfo = NULL;
-
- snd_use_lock_free(&mdev->use_lock);
return 0;
}
@@ -425,7 +399,7 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
int
snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
{
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
int mode;
mdev = get_mididev(dp, dev);
@@ -438,7 +412,6 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
if (mdev->opened & PERM_READ)
mode |= SNDRV_SEQ_OSS_FILE_READ;
- snd_use_lock_free(&mdev->use_lock);
return mode;
}
@@ -449,15 +422,13 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
void
snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
{
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
mdev = get_mididev(dp, dev);
if (!mdev)
return;
- if (! mdev->opened) {
- snd_use_lock_free(&mdev->use_lock);
+ if (!mdev->opened)
return;
- }
if (mdev->opened & PERM_WRITE) {
struct snd_seq_event ev;
@@ -488,7 +459,6 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
}
}
// snd_seq_oss_midi_close(dp, dev);
- snd_use_lock_free(&mdev->use_lock);
}
@@ -498,14 +468,13 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
void
snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr)
{
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
mdev = get_mididev(dp, dev);
if (!mdev)
return;
addr->client = mdev->client;
addr->port = mdev->port;
- snd_use_lock_free(&mdev->use_lock);
}
@@ -516,26 +485,20 @@ int
snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
{
struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
- struct seq_oss_midi *mdev;
- int rc;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
if (dp->readq == NULL)
return 0;
mdev = find_slot(ev->source.client, ev->source.port);
if (!mdev)
return 0;
- if (! (mdev->opened & PERM_READ)) {
- snd_use_lock_free(&mdev->use_lock);
+ if (!(mdev->opened & PERM_READ))
return 0;
- }
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
- rc = send_synth_event(dp, ev, mdev->seq_device);
+ return send_synth_event(dp, ev, mdev->seq_device);
else
- rc = send_midi_event(dp, ev, mdev);
-
- snd_use_lock_free(&mdev->use_lock);
- return rc;
+ return send_midi_event(dp, ev, mdev);
}
/*
@@ -632,17 +595,15 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
int
snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
{
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
- snd_use_lock_free(&mdev->use_lock);
return 0;
}
- snd_use_lock_free(&mdev->use_lock);
return -EINVAL;
}
@@ -652,7 +613,7 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
int
snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf)
{
- struct seq_oss_midi *mdev;
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
mdev = get_mididev(dp, dev);
if (!mdev)
@@ -661,7 +622,6 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info
inf->dev_type = 0; /* FIXME: ?? */
inf->capabilities = 0; /* FIXME: ?? */
strscpy(inf->name, mdev->name, sizeof(inf->name));
- snd_use_lock_free(&mdev->use_lock);
return 0;
}
@@ -688,10 +648,11 @@ void
snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
{
int i;
- struct seq_oss_midi *mdev;
snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs);
for (i = 0; i < max_midi_devs; i++) {
+ struct seq_oss_midi *mdev __free(seq_oss_midi) = NULL;
+
snd_iprintf(buf, "\nmidi %d: ", i);
mdev = get_mdev(i);
if (mdev == NULL) {
@@ -703,7 +664,6 @@ snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
snd_iprintf(buf, " capability %s / opened %s\n",
capmode_str(mdev->flags),
capmode_str(mdev->opened));
- snd_use_lock_free(&mdev->use_lock);
}
}
#endif /* CONFIG_SND_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
index f0db5d3dcba4..bbaf72e70b35 100644
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -140,13 +140,9 @@ int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
int
snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
- if (q->qlen >= q->maxlen - 1) {
- spin_unlock_irqrestore(&q->lock, flags);
+ guard(spinlock_irqsave)(&q->lock);
+ if (q->qlen >= q->maxlen - 1)
return -ENOMEM;
- }
memcpy(&q->q[q->tail], ev, sizeof(*ev));
q->tail = (q->tail + 1) % q->maxlen;
@@ -155,8 +151,6 @@ snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
/* wake up sleeper */
wake_up(&q->midi_sleep);
- spin_unlock_irqrestore(&q->lock, flags);
-
return 0;
}
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index e3394919daa0..8c4e5913c7e6 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;
@@ -51,6 +44,7 @@ struct seq_oss_synth {
snd_use_lock_t use_lock;
};
+DEFINE_FREE(seq_oss_synth, struct seq_oss_synth *, if (!IS_ERR_OR_NULL(_T)) snd_use_lock_free(&(_T)->use_lock))
/*
* device table
@@ -92,7 +86,6 @@ snd_seq_oss_synth_probe(struct device *_dev)
int i;
struct seq_oss_synth *rec;
struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
- unsigned long flags;
rec = kzalloc(sizeof(*rec), GFP_KERNEL);
if (!rec)
@@ -110,23 +103,22 @@ snd_seq_oss_synth_probe(struct device *_dev)
strscpy(rec->name, dev->name, sizeof(rec->name));
/* registration */
- spin_lock_irqsave(&register_lock, flags);
- for (i = 0; i < max_synth_devs; i++) {
- if (synth_devs[i] == NULL)
- break;
- }
- if (i >= max_synth_devs) {
- if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
- spin_unlock_irqrestore(&register_lock, flags);
- pr_err("ALSA: seq_oss: no more synth slot\n");
- kfree(rec);
- return -ENOMEM;
+ scoped_guard(spinlock_irqsave, &register_lock) {
+ for (i = 0; i < max_synth_devs; i++) {
+ if (synth_devs[i] == NULL)
+ break;
+ }
+ if (i >= max_synth_devs) {
+ if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
+ pr_err("ALSA: seq_oss: no more synth slot\n");
+ kfree(rec);
+ return -ENOMEM;
+ }
+ max_synth_devs++;
}
- max_synth_devs++;
+ rec->seq_device = i;
+ synth_devs[i] = rec;
}
- rec->seq_device = i;
- synth_devs[i] = rec;
- spin_unlock_irqrestore(&register_lock, flags);
dev->driver_data = rec;
#ifdef SNDRV_OSS_INFO_DEV_SYNTH
if (i < SNDRV_CARDS)
@@ -142,27 +134,25 @@ snd_seq_oss_synth_remove(struct device *_dev)
struct snd_seq_device *dev = to_seq_dev(_dev);
int index;
struct seq_oss_synth *rec = dev->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&register_lock, flags);
- for (index = 0; index < max_synth_devs; index++) {
- if (synth_devs[index] == rec)
- break;
- }
- if (index >= max_synth_devs) {
- spin_unlock_irqrestore(&register_lock, flags);
- pr_err("ALSA: seq_oss: can't unregister synth\n");
- return -EINVAL;
- }
- synth_devs[index] = NULL;
- if (index == max_synth_devs - 1) {
- for (index--; index >= 0; index--) {
- if (synth_devs[index])
+ scoped_guard(spinlock_irqsave, &register_lock) {
+ for (index = 0; index < max_synth_devs; index++) {
+ if (synth_devs[index] == rec)
break;
}
- max_synth_devs = index + 1;
+ if (index >= max_synth_devs) {
+ pr_err("ALSA: seq_oss: can't unregister synth\n");
+ return -EINVAL;
+ }
+ synth_devs[index] = NULL;
+ if (index == max_synth_devs - 1) {
+ for (index--; index >= 0; index--) {
+ if (synth_devs[index])
+ break;
+ }
+ max_synth_devs = index + 1;
+ }
}
- spin_unlock_irqrestore(&register_lock, flags);
#ifdef SNDRV_OSS_INFO_DEV_SYNTH
if (rec->seq_device < SNDRV_CARDS)
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device);
@@ -181,13 +171,11 @@ static struct seq_oss_synth *
get_sdev(int dev)
{
struct seq_oss_synth *rec;
- unsigned long flags;
- spin_lock_irqsave(&register_lock, flags);
+ guard(spinlock_irqsave)(&register_lock);
rec = synth_devs[dev];
if (rec)
snd_use_lock_use(&rec->use_lock);
- spin_unlock_irqrestore(&register_lock, flags);
return rec;
}
@@ -200,20 +188,18 @@ void
snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
{
int i;
- struct seq_oss_synth *rec;
struct seq_oss_synthinfo *info;
dp->max_synthdev = max_synth_devs;
dp->synth_opened = 0;
memset(dp->synths, 0, sizeof(dp->synths));
for (i = 0; i < dp->max_synthdev; i++) {
- rec = get_sdev(i);
+ struct seq_oss_synth *rec __free(seq_oss_synth) = get_sdev(i);
+
if (rec == NULL)
continue;
- if (rec->oper.open == NULL || rec->oper.close == NULL) {
- snd_use_lock_free(&rec->use_lock);
+ if (rec->oper.open == NULL || rec->oper.close == NULL)
continue;
- }
info = &dp->synths[i];
info->arg.app_index = dp->port;
info->arg.file_mode = dp->file_mode;
@@ -223,13 +209,10 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
else
info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS;
info->opened = 0;
- if (!try_module_get(rec->oper.owner)) {
- snd_use_lock_free(&rec->use_lock);
+ if (!try_module_get(rec->oper.owner))
continue;
- }
if (rec->oper.open(&info->arg, rec->private_data) < 0) {
module_put(rec->oper.owner);
- snd_use_lock_free(&rec->use_lock);
continue;
}
info->nr_voices = rec->nr_voices;
@@ -238,7 +221,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
if (!info->ch) {
rec->oper.close(&info->arg);
module_put(rec->oper.owner);
- snd_use_lock_free(&rec->use_lock);
continue;
}
reset_channels(info);
@@ -246,7 +228,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
info->opened++;
rec->opened++;
dp->synth_opened++;
- snd_use_lock_free(&rec->use_lock);
}
}
@@ -293,7 +274,6 @@ void
snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
{
int i;
- struct seq_oss_synth *rec;
struct seq_oss_synthinfo *info;
if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
@@ -308,7 +288,9 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
midi_synth_dev.opened--;
}
} else {
- rec = get_sdev(i);
+ struct seq_oss_synth *rec __free(seq_oss_synth) =
+ get_sdev(i);
+
if (rec == NULL)
continue;
if (rec->opened > 0) {
@@ -316,10 +298,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
module_put(rec->oper.owner);
rec->opened = 0;
}
- snd_use_lock_free(&rec->use_lock);
}
- kfree(info->sysex);
- info->sysex = NULL;
kfree(info->ch);
info->ch = NULL;
}
@@ -389,14 +368,12 @@ reset_channels(struct seq_oss_synthinfo *info)
void
snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
{
- struct seq_oss_synth *rec;
+ struct seq_oss_synth *rec __free(seq_oss_synth) = NULL;
struct seq_oss_synthinfo *info;
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)
@@ -408,8 +385,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;
}
@@ -429,7 +404,6 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
ev.type = SNDRV_SEQ_EVENT_RESET;
snd_seq_oss_dispatch(dp, &ev, 0, 0);
}
- snd_use_lock_free(&rec->use_lock);
}
@@ -441,9 +415,8 @@ int
snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
const char __user *buf, int p, int c)
{
- struct seq_oss_synth *rec;
+ struct seq_oss_synth *rec __free(seq_oss_synth) = NULL;
struct seq_oss_synthinfo *info;
- int rc;
info = get_synthinfo_nospec(dp, dev);
if (!info)
@@ -456,11 +429,9 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
return -ENXIO;
if (rec->oper.load_patch == NULL)
- rc = -ENXIO;
+ return -ENXIO;
else
- rc = rec->oper.load_patch(&info->arg, fmt, buf, p, c);
- snd_use_lock_free(&rec->use_lock);
- return rc;
+ return rec->oper.load_patch(&info->arg, fmt, buf, p, c);
}
/*
@@ -469,76 +440,37 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
struct seq_oss_synthinfo *
snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev)
{
- struct seq_oss_synth *rec;
+ struct seq_oss_synth *rec __free(seq_oss_synth) = NULL;
rec = get_synthdev(dp, dev);
- if (rec) {
- snd_use_lock_free(&rec->use_lock);
+ if (rec)
return get_synthinfo_nospec(dp, dev);
- }
return NULL;
}
/*
* 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;
-
- info = snd_seq_oss_synth_info(dp, dev);
- if (!info)
- return -ENXIO;
+ unsigned char *p;
+ int len = 6;
- sysex = info->sysex;
- if (sysex == NULL) {
- sysex = kzalloc(sizeof(*sysex), GFP_KERNEL);
- if (sysex == NULL)
- return -ENOMEM;
- info->sysex = sysex;
- }
+ p = memchr(buf, 0xff, 6);
+ if (p)
+ len = p - buf + 1;
- 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;
}
/*
@@ -563,9 +495,8 @@ snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event
int
snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr)
{
- struct seq_oss_synth *rec;
+ struct seq_oss_synth *rec __free(seq_oss_synth) = NULL;
struct seq_oss_synthinfo *info;
- int rc;
info = get_synthinfo_nospec(dp, dev);
if (!info || info->is_midi)
@@ -574,11 +505,9 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u
if (!rec)
return -ENXIO;
if (rec->oper.ioctl == NULL)
- rc = -ENXIO;
+ return -ENXIO;
else
- rc = rec->oper.ioctl(&info->arg, cmd, addr);
- snd_use_lock_free(&rec->use_lock);
- return rc;
+ return rec->oper.ioctl(&info->arg, cmd, addr);
}
@@ -605,7 +534,6 @@ snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *
int
snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf)
{
- struct seq_oss_synth *rec;
struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev);
if (!info)
@@ -621,7 +549,9 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
inf->device = dev;
strscpy(inf->name, minf.name, sizeof(inf->name));
} else {
- rec = get_synthdev(dp, dev);
+ struct seq_oss_synth *rec __free(seq_oss_synth) =
+ get_synthdev(dp, dev);
+
if (!rec)
return -ENXIO;
inf->synth_type = rec->synth_type;
@@ -629,7 +559,6 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
inf->nr_voices = rec->nr_voices;
inf->device = dev;
strscpy(inf->name, rec->name, sizeof(inf->name));
- snd_use_lock_free(&rec->use_lock);
}
return 0;
}
@@ -643,10 +572,11 @@ void
snd_seq_oss_synth_info_read(struct snd_info_buffer *buf)
{
int i;
- struct seq_oss_synth *rec;
snd_iprintf(buf, "\nNumber of synth devices: %d\n", max_synth_devs);
for (i = 0; i < max_synth_devs; i++) {
+ struct seq_oss_synth *rec __free(seq_oss_synth) = NULL;
+
snd_iprintf(buf, "\nsynth %d: ", i);
rec = get_sdev(i);
if (rec == NULL) {
@@ -658,9 +588,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));
- snd_use_lock_free(&rec->use_lock);
+ str_enabled_disabled((long)rec->oper.ioctl),
+ str_enabled_disabled((long)rec->oper.load_patch));
}
}
#endif /* CONFIG_SND_PROC_FS */
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
index 3e3209ce53b1..a93ff8315b8e 100644
--- a/sound/core/seq/oss/seq_oss_writeq.c
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -122,13 +122,10 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
void
snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->sync_lock, flags);
+ guard(spinlock_irqsave)(&q->sync_lock);
q->sync_time = time;
q->sync_event_put = 0;
wake_up(&q->sync_sleep);
- spin_unlock_irqrestore(&q->sync_lock, flags);
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 2d707afa1ef1..f9a6e497f997 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -14,12 +14,14 @@
#include <linux/kmod.h>
#include <sound/seq_kernel.h>
+#include <sound/ump.h>
#include "seq_clientmgr.h"
#include "seq_memory.h"
#include "seq_queue.h"
#include "seq_timer.h"
#include "seq_info.h"
#include "seq_system.h"
+#include "seq_ump_convert.h"
#include <sound/seq_device.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
@@ -68,7 +70,11 @@ static int bounce_error_event(struct snd_seq_client *client,
int err, int atomic, int hop);
static int snd_seq_deliver_single_event(struct snd_seq_client *client,
struct snd_seq_event *event,
- int filter, int atomic, int hop);
+ int atomic, int hop);
+
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+static void free_ump_info(struct snd_seq_client *client);
+#endif
/*
*/
@@ -100,9 +106,8 @@ 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;
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
@@ -110,17 +115,15 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
clientid);
return NULL;
}
- spin_lock_irqsave(&clients_lock, flags);
- client = clientptr(clientid);
- if (client)
- goto __lock;
- if (clienttablock[clientid]) {
- spin_unlock_irqrestore(&clients_lock, flags);
- return NULL;
+ scoped_guard(spinlock_irqsave, &clients_lock) {
+ client = clientptr(clientid);
+ if (client)
+ return snd_seq_client_ref(client);
+ if (clienttablock[clientid])
+ return NULL;
}
- 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);
@@ -147,55 +150,29 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
snd_seq_device_load_drivers();
}
}
- spin_lock_irqsave(&clients_lock, flags);
- client = clientptr(clientid);
- if (client)
- goto __lock;
- spin_unlock_irqrestore(&clients_lock, flags);
+ scoped_guard(spinlock_irqsave, &clients_lock) {
+ client = clientptr(clientid);
+ if (client)
+ return snd_seq_client_ref(client);
+ }
}
#endif
return NULL;
-
- __lock:
- snd_use_lock_use(&client->use_lock);
- spin_unlock_irqrestore(&clients_lock, flags);
- return client;
}
-/* Take refcount and perform ioctl_mutex lock on the given client;
- * used only for OSS sequencer
- * Unlock via snd_seq_client_ioctl_unlock() below
- */
-bool snd_seq_client_ioctl_lock(int clientid)
+/* get snd_seq_client object for the given id quickly */
+struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
{
- struct snd_seq_client *client;
-
- client = snd_seq_client_use_ptr(clientid);
- if (!client)
- return false;
- mutex_lock(&client->ioctl_mutex);
- /* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */
- return true;
+ return client_use_ptr(clientid, false);
}
-EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock);
-/* Unlock and unref the given client; for OSS sequencer use only */
-void snd_seq_client_ioctl_unlock(int clientid)
+/* 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)
{
- struct snd_seq_client *client;
-
- client = snd_seq_client_use_ptr(clientid);
- if (WARN_ON(!client))
- return;
- mutex_unlock(&client->ioctl_mutex);
- /* The doubly unrefs below are intentional; the first one releases the
- * leftover from snd_seq_client_ioctl_lock() above, and the second one
- * is for releasing snd_seq_client_use_ptr() in this function
- */
- snd_seq_client_unlock(client);
- snd_seq_client_unlock(client);
+ return client_use_ptr(clientid, IS_ENABLED(CONFIG_MODULES));
}
-EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock);
static void usage_alloc(struct snd_seq_usage *res, int num)
{
@@ -239,27 +216,27 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
mutex_init(&client->ports_mutex);
INIT_LIST_HEAD(&client->ports_list_head);
mutex_init(&client->ioctl_mutex);
+ client->ump_endpoint_port = -1;
/* find free slot in the client table */
- spin_lock_irq(&clients_lock);
- if (client_index < 0) {
- for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
- c < SNDRV_SEQ_MAX_CLIENTS;
- c++) {
- if (clienttab[c] || clienttablock[c])
- continue;
- clienttab[client->number = c] = client;
- spin_unlock_irq(&clients_lock);
- return client;
- }
- } else {
- if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
- clienttab[client->number = client_index] = client;
- spin_unlock_irq(&clients_lock);
- return client;
+ scoped_guard(spinlock_irq, &clients_lock) {
+ if (client_index < 0) {
+ for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
+ c < SNDRV_SEQ_MAX_CLIENTS;
+ c++) {
+ if (clienttab[c] || clienttablock[c])
+ continue;
+ clienttab[client->number = c] = client;
+ return client;
+ }
+ } else {
+ if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
+ clienttab[client->number = client_index] = client;
+ return client;
+ }
}
}
- spin_unlock_irq(&clients_lock);
+
snd_seq_pool_delete(&client->pool);
kfree(client);
return NULL; /* no free slot found or busy, return failure code */
@@ -270,41 +247,41 @@ static int seq_free_client1(struct snd_seq_client *client)
{
if (!client)
return 0;
- spin_lock_irq(&clients_lock);
- clienttablock[client->number] = 1;
- clienttab[client->number] = NULL;
- spin_unlock_irq(&clients_lock);
+ scoped_guard(spinlock_irq, &clients_lock) {
+ clienttablock[client->number] = 1;
+ clienttab[client->number] = NULL;
+ }
snd_seq_delete_all_ports(client);
snd_seq_queue_client_leave(client->number);
snd_use_lock_sync(&client->use_lock);
if (client->pool)
snd_seq_pool_delete(&client->pool);
- spin_lock_irq(&clients_lock);
- clienttablock[client->number] = 0;
- spin_unlock_irq(&clients_lock);
+ scoped_guard(spinlock_irq, &clients_lock) {
+ clienttablock[client->number] = 0;
+ }
return 0;
}
static void seq_free_client(struct snd_seq_client * client)
{
- mutex_lock(&register_mutex);
- switch (client->type) {
- case NO_CLIENT:
- pr_warn("ALSA: seq: Trying to free unused client %d\n",
- client->number);
- break;
- case USER_CLIENT:
- case KERNEL_CLIENT:
- seq_free_client1(client);
- usage_free(&client_usage, 1);
- break;
+ scoped_guard(mutex, &register_mutex) {
+ switch (client->type) {
+ case NO_CLIENT:
+ pr_warn("ALSA: seq: Trying to free unused client %d\n",
+ client->number);
+ break;
+ case USER_CLIENT:
+ case KERNEL_CLIENT:
+ seq_free_client1(client);
+ usage_free(&client_usage, 1);
+ break;
- default:
- pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n",
- client->number, client->type);
+ default:
+ pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n",
+ client->number, client->type);
+ }
}
- mutex_unlock(&register_mutex);
snd_seq_system_client_ev_client_exit(client->number);
}
@@ -325,37 +302,34 @@ static int snd_seq_open(struct inode *inode, struct file *file)
if (err < 0)
return err;
- mutex_lock(&register_mutex);
- client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
- if (!client) {
- mutex_unlock(&register_mutex);
- return -ENOMEM; /* failure code */
- }
-
- mode = snd_seq_file_flags(file);
- if (mode & SNDRV_SEQ_LFLG_INPUT)
- client->accept_input = 1;
- if (mode & SNDRV_SEQ_LFLG_OUTPUT)
- client->accept_output = 1;
-
- user = &client->data.user;
- user->fifo = NULL;
- user->fifo_pool_size = 0;
-
- if (mode & SNDRV_SEQ_LFLG_INPUT) {
- user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS;
- user->fifo = snd_seq_fifo_new(user->fifo_pool_size);
- if (user->fifo == NULL) {
- seq_free_client1(client);
- kfree(client);
- mutex_unlock(&register_mutex);
- return -ENOMEM;
+ scoped_guard(mutex, &register_mutex) {
+ client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
+ if (!client)
+ return -ENOMEM; /* failure code */
+
+ mode = snd_seq_file_flags(file);
+ if (mode & SNDRV_SEQ_LFLG_INPUT)
+ client->accept_input = 1;
+ if (mode & SNDRV_SEQ_LFLG_OUTPUT)
+ client->accept_output = 1;
+
+ user = &client->data.user;
+ user->fifo = NULL;
+ user->fifo_pool_size = 0;
+
+ if (mode & SNDRV_SEQ_LFLG_INPUT) {
+ user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS;
+ user->fifo = snd_seq_fifo_new(user->fifo_pool_size);
+ if (user->fifo == NULL) {
+ seq_free_client1(client);
+ kfree(client);
+ return -ENOMEM;
+ }
}
- }
- usage_alloc(&client_usage, 1);
- client->type = USER_CLIENT;
- mutex_unlock(&register_mutex);
+ usage_alloc(&client_usage, 1);
+ client->type = USER_CLIENT;
+ }
c = client->number;
file->private_data = client;
@@ -380,6 +354,9 @@ static int snd_seq_release(struct inode *inode, struct file *file)
seq_free_client(client);
if (client->data.user.fifo)
snd_seq_fifo_delete(&client->data.user.fifo);
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ free_ump_info(client);
+#endif
put_pid(client->data.user.owner);
kfree(client);
}
@@ -387,6 +364,15 @@ static int snd_seq_release(struct inode *inode, struct file *file)
return 0;
}
+static bool event_is_compatible(const struct snd_seq_client *client,
+ const struct snd_seq_event *ev)
+{
+ if (snd_seq_ev_is_ump(ev) && !client->midi_version)
+ return false;
+ if (snd_seq_ev_is_ump(ev) && snd_seq_ev_is_variable(ev))
+ return false;
+ return true;
+}
/* handle client read() */
/* possible error values:
@@ -400,6 +386,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
{
struct snd_seq_client *client = file->private_data;
struct snd_seq_fifo *fifo;
+ size_t aligned_size;
int err;
long result = 0;
struct snd_seq_event_cell *cell;
@@ -429,45 +416,56 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
cell = NULL;
err = 0;
- snd_seq_fifo_lock(fifo);
+ guard(snd_seq_fifo)(fifo);
+
+ if (IS_ENABLED(CONFIG_SND_SEQ_UMP) && client->midi_version > 0)
+ aligned_size = sizeof(struct snd_seq_ump_event);
+ else
+ aligned_size = sizeof(struct snd_seq_event);
/* while data available in queue */
- while (count >= sizeof(struct snd_seq_event)) {
+ while (count >= aligned_size) {
int nonblock;
nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
err = snd_seq_fifo_cell_out(fifo, &cell, nonblock);
if (err < 0)
break;
+ if (!event_is_compatible(client, &cell->event)) {
+ snd_seq_cell_free(cell);
+ cell = NULL;
+ continue;
+ }
if (snd_seq_ev_is_variable(&cell->event)) {
- struct snd_seq_event tmpev;
- tmpev = cell->event;
+ struct snd_seq_ump_event tmpev;
+
+ memcpy(&tmpev, &cell->event, aligned_size);
tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
- if (copy_to_user(buf, &tmpev, sizeof(struct snd_seq_event))) {
+ if (copy_to_user(buf, &tmpev, aligned_size)) {
err = -EFAULT;
break;
}
- count -= sizeof(struct snd_seq_event);
- buf += sizeof(struct snd_seq_event);
+ count -= aligned_size;
+ buf += aligned_size;
err = snd_seq_expand_var_event(&cell->event, count,
(char __force *)buf, 0,
- sizeof(struct snd_seq_event));
+ aligned_size);
if (err < 0)
break;
result += err;
count -= err;
buf += err;
} else {
- if (copy_to_user(buf, &cell->event, sizeof(struct snd_seq_event))) {
+ if (copy_to_user(buf, &cell->event, aligned_size)) {
err = -EFAULT;
break;
}
- count -= sizeof(struct snd_seq_event);
- buf += sizeof(struct snd_seq_event);
+ count -= aligned_size;
+ buf += aligned_size;
}
snd_seq_cell_free(cell);
cell = NULL; /* to be sure */
- result += sizeof(struct snd_seq_event);
+ result += aligned_size;
}
if (err < 0) {
@@ -476,7 +474,6 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
if (err == -EAGAIN && result > 0)
err = 0;
}
- snd_seq_fifo_unlock(fifo);
return (err < 0) ? err : result;
}
@@ -494,28 +491,24 @@ static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags)
/*
* check if the destination client is available, and return the pointer
- * if filter is non-zero, client filter bitmap is tested.
*/
-static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event,
- int filter)
+static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event)
{
- struct snd_seq_client *dest;
+ struct snd_seq_client *dest __free(snd_seq_client) = NULL;
dest = snd_seq_client_use_ptr(event->dest.client);
if (dest == NULL)
return NULL;
if (! dest->accept_input)
- goto __not_avail;
+ return NULL;
+ if (snd_seq_ev_is_ump(event))
+ return no_free_ptr(dest); /* ok - no filter checks */
+
if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) &&
! test_bit(event->type, dest->event_filter))
- goto __not_avail;
- if (filter && !(dest->filter & filter))
- goto __not_avail;
+ return NULL;
- return dest; /* ok - accessible */
-__not_avail:
- snd_seq_client_unlock(dest);
- return NULL;
+ return no_free_ptr(dest); /* ok - accessible */
}
@@ -554,7 +547,7 @@ static int bounce_error_event(struct snd_seq_client *client,
bounce_ev.data.quote.origin = event->dest;
bounce_ev.data.quote.event = event;
bounce_ev.data.quote.value = -err; /* use positive value */
- result = snd_seq_deliver_single_event(NULL, &bounce_ev, 0, atomic, hop + 1);
+ result = snd_seq_deliver_single_event(NULL, &bounce_ev, atomic, hop + 1);
if (result < 0) {
client->event_lost++;
return result;
@@ -572,7 +565,7 @@ static int bounce_error_event(struct snd_seq_client *client,
static int update_timestamp_of_queue(struct snd_seq_event *event,
int queue, int real_time)
{
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
q = queueptr(queue);
if (! q)
@@ -586,72 +579,88 @@ static int update_timestamp_of_queue(struct snd_seq_event *event,
event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
}
- queuefree(q);
return 1;
}
-
-/*
- * deliver an event to the specified destination.
- * if filter is non-zero, client filter bitmap is tested.
- *
- * RETURN VALUE: 0 : if succeeded
- * <0 : error
- */
-static int snd_seq_deliver_single_event(struct snd_seq_client *client,
- struct snd_seq_event *event,
- int filter, int atomic, int hop)
+/* deliver a single event; called from below and UMP converter */
+int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop)
{
- struct snd_seq_client *dest = NULL;
- struct snd_seq_client_port *dest_port = NULL;
- int result = -ENOENT;
- int direct;
+ switch (dest->type) {
+ case USER_CLIENT:
+ if (!dest->data.user.fifo)
+ return 0;
+ return snd_seq_fifo_event_in(dest->data.user.fifo, event);
+ case KERNEL_CLIENT:
+ if (!dest_port->event_input)
+ return 0;
+ return dest_port->event_input(event,
+ snd_seq_ev_is_direct(event),
+ dest_port->private_data,
+ atomic, hop);
+ }
+ return 0;
+}
- direct = snd_seq_ev_is_direct(event);
+/* deliver a single event; called from snd_seq_deliver_single_event() */
+static int _snd_seq_deliver_single_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ struct snd_seq_client *dest __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *dest_port __free(snd_seq_port) = NULL;
- dest = get_event_dest_client(event, filter);
+ dest = get_event_dest_client(event);
if (dest == NULL)
- goto __skip;
+ return -ENOENT;
dest_port = snd_seq_port_use_ptr(dest, event->dest.port);
if (dest_port == NULL)
- goto __skip;
+ return -ENOENT;
/* check permission */
- if (! check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) {
- result = -EPERM;
- goto __skip;
- }
-
+ if (!check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE))
+ return -EPERM;
+
if (dest_port->timestamping)
update_timestamp_of_queue(event, dest_port->time_queue,
dest_port->time_real);
- switch (dest->type) {
- case USER_CLIENT:
- if (dest->data.user.fifo)
- result = snd_seq_fifo_event_in(dest->data.user.fifo, event);
- break;
-
- case KERNEL_CLIENT:
- if (dest_port->event_input == NULL)
- break;
- result = dest_port->event_input(event, direct,
- dest_port->private_data,
- atomic, hop);
- break;
- default:
- break;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ if (snd_seq_ev_is_ump(event)) {
+ if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT))
+ return snd_seq_deliver_from_ump(client, dest, dest_port,
+ event, atomic, hop);
+ else if (dest->type == USER_CLIENT &&
+ !snd_seq_client_is_ump(dest))
+ return 0; // drop the event
+ } else if (snd_seq_client_is_ump(dest)) {
+ if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT))
+ return snd_seq_deliver_to_ump(client, dest, dest_port,
+ event, atomic, hop);
}
+#endif /* CONFIG_SND_SEQ_UMP */
- __skip:
- if (dest_port)
- snd_seq_port_unlock(dest_port);
- if (dest)
- snd_seq_client_unlock(dest);
+ return __snd_seq_deliver_single_event(dest, dest_port, event,
+ atomic, hop);
+}
- if (result < 0 && !direct) {
- result = bounce_error_event(client, event, result, atomic, hop);
- }
+/*
+ * deliver an event to the specified destination.
+ * if filter is non-zero, client filter bitmap is tested.
+ *
+ * RETURN VALUE: 0 : if succeeded
+ * <0 : error
+ */
+static int snd_seq_deliver_single_event(struct snd_seq_client *client,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ int result = _snd_seq_deliver_single_event(client, event, atomic, hop);
+
+ if (result < 0 && !snd_seq_ev_is_direct(event))
+ return bounce_error_event(client, event, result, atomic, hop);
return result;
}
@@ -659,21 +668,26 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
/*
* send the event to all subscribers:
*/
-static int deliver_to_subscribers(struct snd_seq_client *client,
- struct snd_seq_event *event,
- int atomic, int hop)
+static int __deliver_to_subscribers(struct snd_seq_client *client,
+ struct snd_seq_event *event,
+ int port, int atomic, int hop)
{
+ struct snd_seq_client_port *src_port __free(snd_seq_port) = NULL;
struct snd_seq_subscribers *subs;
int err, result = 0, num_ev = 0;
- struct snd_seq_event event_saved;
- struct snd_seq_client_port *src_port;
+ union __snd_seq_event event_saved;
+ size_t saved_size;
struct snd_seq_port_subs_info *grp;
- src_port = snd_seq_port_use_ptr(client, event->source.port);
- if (src_port == NULL)
- return -EINVAL; /* invalid source port */
+ if (port < 0)
+ return 0;
+ src_port = snd_seq_port_use_ptr(client, port);
+ if (!src_port)
+ return 0;
+
/* save original event record */
- event_saved = *event;
+ saved_size = snd_seq_event_packet_size(event);
+ memcpy(&event_saved, event, saved_size);
grp = &src_port->c_src;
/* lock list */
@@ -690,8 +704,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
/* convert time according to flag with subscription */
update_timestamp_of_queue(event, subs->info.queue,
subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
- err = snd_seq_deliver_single_event(client, event,
- 0, atomic, hop);
+ err = snd_seq_deliver_single_event(client, event, atomic, hop);
if (err < 0) {
/* save first error that occurs and continue */
if (!result)
@@ -700,103 +713,47 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
}
num_ev++;
/* restore original event record */
- *event = event_saved;
+ memcpy(event, &event_saved, saved_size);
}
if (atomic)
read_unlock(&grp->list_lock);
else
up_read(&grp->list_mutex);
- *event = event_saved; /* restore */
- snd_seq_port_unlock(src_port);
+ memcpy(event, &event_saved, saved_size);
return (result < 0) ? result : num_ev;
}
-
-#ifdef SUPPORT_BROADCAST
-/*
- * broadcast to all ports:
- */
-static int port_broadcast_event(struct snd_seq_client *client,
- struct snd_seq_event *event,
- int atomic, int hop)
-{
- int num_ev = 0, err, result = 0;
- struct snd_seq_client *dest_client;
- struct snd_seq_client_port *port;
-
- dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
- if (dest_client == NULL)
- return 0; /* no matching destination */
-
- read_lock(&dest_client->ports_lock);
- list_for_each_entry(port, &dest_client->ports_list_head, list) {
- event->dest.port = port->addr.port;
- /* pass NULL as source client to avoid error bounce */
- err = snd_seq_deliver_single_event(NULL, event,
- SNDRV_SEQ_FILTER_BROADCAST,
- atomic, hop);
- if (err < 0) {
- /* save first error that occurs and continue */
- if (!result)
- result = err;
- continue;
- }
- num_ev++;
- }
- read_unlock(&dest_client->ports_lock);
- snd_seq_client_unlock(dest_client);
- event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
- return (result < 0) ? result : num_ev;
-}
-
-/*
- * send the event to all clients:
- * if destination port is also ADDRESS_BROADCAST, deliver to all ports.
- */
-static int broadcast_event(struct snd_seq_client *client,
- struct snd_seq_event *event, int atomic, int hop)
+static int deliver_to_subscribers(struct snd_seq_client *client,
+ struct snd_seq_event *event,
+ int atomic, int hop)
{
- int err, result = 0, num_ev = 0;
- int dest;
- struct snd_seq_addr addr;
-
- addr = event->dest; /* save */
-
- for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) {
- /* don't send to itself */
- if (dest == client->number)
- continue;
- event->dest.client = dest;
- event->dest.port = addr.port;
- if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST)
- err = port_broadcast_event(client, event, atomic, hop);
- else
- /* pass NULL as source client to avoid error bounce */
- err = snd_seq_deliver_single_event(NULL, event,
- SNDRV_SEQ_FILTER_BROADCAST,
- atomic, hop);
- if (err < 0) {
- /* save first error that occurs and continue */
- if (!result)
- result = err;
- continue;
- }
- num_ev += err;
- }
- event->dest = addr; /* restore */
- return (result < 0) ? result : num_ev;
-}
-
+ int ret;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ int ret2;
+#endif
-/* multicast - not supported yet */
-static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event,
- int atomic, int hop)
-{
- pr_debug("ALSA: seq: multicast not supported yet.\n");
- return 0; /* ignored */
+ ret = __deliver_to_subscribers(client, event,
+ event->source.port, atomic, hop);
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ if (!snd_seq_client_is_ump(client) || client->ump_endpoint_port < 0)
+ return ret;
+ /* If it's an event from EP port (and with a UMP group),
+ * deliver to subscribers of the corresponding UMP group port, too.
+ * Or, if it's from non-EP port, deliver to subscribers of EP port, too.
+ */
+ if (event->source.port == client->ump_endpoint_port)
+ ret2 = __deliver_to_subscribers(client, event,
+ snd_seq_ump_group_port(event),
+ atomic, hop);
+ else
+ ret2 = __deliver_to_subscribers(client, event,
+ client->ump_endpoint_port,
+ atomic, hop);
+ if (ret2 < 0)
+ return ret2;
+#endif
+ return ret;
}
-#endif /* SUPPORT_BROADCAST */
-
/* deliver an event to the destination port(s).
* if the event is to subscribers or broadcast, the event is dispatched
@@ -826,17 +783,8 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS ||
event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)
result = deliver_to_subscribers(client, event, atomic, hop);
-#ifdef SUPPORT_BROADCAST
- else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST ||
- event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST)
- result = broadcast_event(client, event, atomic, hop);
- else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS)
- result = multicast_event(client, event, atomic, hop);
- else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST)
- result = port_broadcast_event(client, event, atomic, hop);
-#endif
else
- result = snd_seq_deliver_single_event(client, event, 0, atomic, hop);
+ result = snd_seq_deliver_single_event(client, event, atomic, hop);
return result;
}
@@ -853,7 +801,7 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
*/
int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
{
- struct snd_seq_client *client;
+ struct snd_seq_client *client __free(snd_seq_client) = NULL;
int result;
if (snd_BUG_ON(!cell))
@@ -865,7 +813,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
return -EINVAL;
}
- if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) {
+ if (!snd_seq_ev_is_ump(&cell->event) &&
+ cell->event.type == SNDRV_SEQ_EVENT_NOTE) {
/* NOTE event:
* the event cell is re-used as a NOTE-OFF event and
* enqueued again.
@@ -889,7 +838,7 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
/* add the duration time */
switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) {
case SNDRV_SEQ_TIME_STAMP_TICK:
- ev->time.tick += ev->data.note.duration;
+ cell->event.time.tick += ev->data.note.duration;
break;
case SNDRV_SEQ_TIME_STAMP_REAL:
/* unit for duration is ms */
@@ -914,7 +863,6 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
snd_seq_cell_free(cell);
}
- snd_seq_client_unlock(client);
return result;
}
@@ -936,24 +884,18 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
event->queue = SNDRV_SEQ_QUEUE_DIRECT;
- } else
-#ifdef SUPPORT_BROADCAST
- if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) {
- event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST;
- event->queue = SNDRV_SEQ_QUEUE_DIRECT;
- }
-#endif
- if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
+ } else if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
/* check presence of source port */
- struct snd_seq_client_port *src_port = snd_seq_port_use_ptr(client, event->source.port);
- if (src_port == NULL)
+ struct snd_seq_client_port *src_port __free(snd_seq_port) =
+ snd_seq_port_use_ptr(client, event->source.port);
+ if (!src_port)
return -EINVAL;
- snd_seq_port_unlock(src_port);
}
/* direct event processing without enqueued */
if (snd_seq_ev_is_direct(event)) {
- if (event->type == SNDRV_SEQ_EVENT_NOTE)
+ if (!snd_seq_ev_is_ump(event) &&
+ event->type == SNDRV_SEQ_EVENT_NOTE)
return -EINVAL; /* this event must be enqueued! */
return snd_seq_deliver_event(client, event, atomic, hop);
}
@@ -1023,7 +965,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
struct snd_seq_client *client = file->private_data;
int written = 0, len;
int err, handled;
- struct snd_seq_event event;
+ union __snd_seq_event __event;
+ struct snd_seq_event *ev = &__event.legacy;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
return -ENXIO;
@@ -1049,49 +992,66 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
err = -EINVAL;
while (count >= sizeof(struct snd_seq_event)) {
/* Read in the event header from the user */
- len = sizeof(event);
- if (copy_from_user(&event, buf, len)) {
+ len = sizeof(struct snd_seq_event);
+ if (copy_from_user(ev, buf, len)) {
err = -EFAULT;
break;
}
- event.source.client = client->number; /* fill in client number */
+ /* read in the rest bytes for UMP events */
+ if (snd_seq_ev_is_ump(ev)) {
+ if (count < sizeof(struct snd_seq_ump_event))
+ break;
+ if (copy_from_user((char *)ev + len, buf + len,
+ sizeof(struct snd_seq_ump_event) - len)) {
+ err = -EFAULT;
+ break;
+ }
+ len = sizeof(struct snd_seq_ump_event);
+ }
+
+ ev->source.client = client->number; /* fill in client number */
/* Check for extension data length */
- if (check_event_type_and_length(&event)) {
+ if (check_event_type_and_length(ev)) {
err = -EINVAL;
break;
}
- /* check for special events */
- if (event.type == SNDRV_SEQ_EVENT_NONE)
- goto __skip_event;
- else if (snd_seq_ev_is_reserved(&event)) {
+ if (!event_is_compatible(client, ev)) {
err = -EINVAL;
break;
}
- if (snd_seq_ev_is_variable(&event)) {
- int extlen = event.data.ext.len & ~SNDRV_SEQ_EXT_MASK;
+ /* check for special events */
+ if (!snd_seq_ev_is_ump(ev)) {
+ if (ev->type == SNDRV_SEQ_EVENT_NONE)
+ goto __skip_event;
+ else if (snd_seq_ev_is_reserved(ev)) {
+ err = -EINVAL;
+ break;
+ }
+ }
+
+ if (snd_seq_ev_is_variable(ev)) {
+ int extlen = ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
if ((size_t)(extlen + len) > count) {
/* back out, will get an error this time or next */
err = -EINVAL;
break;
}
/* set user space pointer */
- event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
- event.data.ext.ptr = (char __force *)buf
- + sizeof(struct snd_seq_event);
+ ev->data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
+ ev->data.ext.ptr = (char __force *)buf + len;
len += extlen; /* increment data length */
} else {
#ifdef CONFIG_COMPAT
- if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
- void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]);
- event.data.ext.ptr = ptr;
- }
+ if (client->convert32 && snd_seq_ev_is_varusr(ev))
+ ev->data.ext.ptr =
+ (void __force *)compat_ptr(ev->data.raw32.d[1]);
#endif
}
/* ok, enqueue it */
- err = snd_seq_client_enqueue_event(client, &event, file,
+ err = snd_seq_client_enqueue_event(client, ev, file,
!(file->f_flags & O_NONBLOCK),
0, 0, &client->ioctl_mutex);
if (err < 0)
@@ -1140,8 +1100,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;
}
@@ -1159,6 +1118,12 @@ static int snd_seq_ioctl_pversion(struct snd_seq_client *client, void *arg)
return 0;
}
+static int snd_seq_ioctl_user_pversion(struct snd_seq_client *client, void *arg)
+{
+ client->user_pversion = *(unsigned int *)arg;
+ return 0;
+}
+
static int snd_seq_ioctl_client_id(struct snd_seq_client *client, void *arg)
{
int *client_id = arg;
@@ -1189,34 +1154,24 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void *arg)
static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg)
{
struct snd_seq_running_info *info = arg;
- struct snd_seq_client *cptr;
- int err = 0;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
/* 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 !!! */
#ifdef SNDRV_BIG_ENDIAN
- if (!info->big_endian) {
- err = -EINVAL;
- goto __err;
- }
+ if (!info->big_endian)
+ return -EINVAL;
#else
- if (info->big_endian) {
- err = -EINVAL;
- goto __err;
- }
-
+ if (info->big_endian)
+ return -EINVAL;
#endif
- if (info->cpu_mode > sizeof(long)) {
- err = -EINVAL;
- goto __err;
- }
+ if (info->cpu_mode > sizeof(long))
+ return -EINVAL;
cptr->convert32 = (info->cpu_mode < sizeof(long));
- __err:
- snd_seq_client_unlock(cptr);
- return err;
+ return 0;
}
/* CLIENT_INFO ioctl() */
@@ -1227,10 +1182,11 @@ static void get_client_info(struct snd_seq_client *cptr,
/* fill the info fields */
info->type = cptr->type;
- strcpy(info->name, cptr->name);
+ strscpy(info->name, cptr->name);
info->filter = cptr->filter;
info->event_lost = cptr->event_lost;
memcpy(info->event_filter, cptr->event_filter, 32);
+ info->group_filter = cptr->group_filter;
info->num_ports = cptr->num_ports;
if (cptr->type == USER_CLIENT)
@@ -1243,6 +1199,7 @@ static void get_client_info(struct snd_seq_client *cptr,
else
info->card = -1;
+ info->midi_version = cptr->midi_version;
memset(info->reserved, 0, sizeof(info->reserved));
}
@@ -1250,16 +1207,14 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_client_info *client_info = arg;
- struct snd_seq_client *cptr;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
/* 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 !!! */
get_client_info(cptr, client_info);
- snd_seq_client_unlock(cptr);
-
return 0;
}
@@ -1277,13 +1232,30 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
if (client->type != client_info->type)
return -EINVAL;
+ if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3)) {
+ /* check validity of midi_version field */
+ if (client_info->midi_version > SNDRV_SEQ_CLIENT_UMP_MIDI_2_0)
+ return -EINVAL;
+
+ /* check if UMP is supported in kernel */
+ if (!IS_ENABLED(CONFIG_SND_SEQ_UMP) &&
+ client_info->midi_version > 0)
+ return -EINVAL;
+ }
+
/* fill the info fields */
if (client_info->name[0])
strscpy(client->name, client_info->name, sizeof(client->name));
client->filter = client_info->filter;
client->event_lost = client_info->event_lost;
+ if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3))
+ 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;
}
@@ -1297,22 +1269,27 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
struct snd_seq_port_info *info = arg;
struct snd_seq_client_port *port;
struct snd_seq_port_callback *callback;
- int port_idx;
+ int port_idx, err;
/* it is not allowed to create the port for an another client */
if (info->addr.client != client->number)
return -EPERM;
+ if (client->type == USER_CLIENT && info->kernel)
+ return -EINVAL;
+ if ((info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT) &&
+ client->ump_endpoint_port >= 0)
+ return -EBUSY;
- port = snd_seq_create_port(client, (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info->addr.port : -1);
- if (port == NULL)
- return -ENOMEM;
-
- if (client->type == USER_CLIENT && info->kernel) {
- port_idx = port->addr.port;
- snd_seq_port_unlock(port);
- snd_seq_delete_port(client, port_idx);
+ if (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT)
+ port_idx = info->addr.port;
+ else
+ port_idx = -1;
+ if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN)
return -EINVAL;
- }
+ err = snd_seq_create_port(client, port_idx, &port);
+ if (err < 0)
+ return err;
+
if (client->type == KERNEL_CLIENT) {
callback = info->kernel;
if (callback) {
@@ -1331,6 +1308,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
info->addr = port->addr;
snd_seq_set_port_info(port, info);
+ if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT)
+ client->ump_endpoint_port = port->addr.port;
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
snd_seq_port_unlock(port);
@@ -1350,8 +1329,11 @@ static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg)
return -EPERM;
err = snd_seq_delete_port(client, info->addr.port);
- if (err >= 0)
+ if (err >= 0) {
+ if (client->ump_endpoint_port == info->addr.port)
+ client->ump_endpoint_port = -1;
snd_seq_system_client_ev_port_exit(client->number, info->addr.port);
+ }
return err;
}
@@ -1362,24 +1344,19 @@ static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg)
static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
{
struct snd_seq_port_info *info = arg;
- struct snd_seq_client *cptr;
- struct snd_seq_client_port *port;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *port __free(snd_seq_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;
port = snd_seq_port_use_ptr(cptr, info->addr.port);
- if (port == NULL) {
- snd_seq_client_unlock(cptr);
+ if (port == NULL)
return -ENOENT; /* don't change */
- }
/* get port info */
snd_seq_get_port_info(port, info);
- snd_seq_port_unlock(port);
- snd_seq_client_unlock(cptr);
-
return 0;
}
@@ -1390,14 +1367,16 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg)
{
struct snd_seq_port_info *info = arg;
- struct snd_seq_client_port *port;
+ struct snd_seq_client_port *port __free(snd_seq_port) = NULL;
if (info->addr.client != client->number) /* only set our own ports ! */
return -EPERM;
port = snd_seq_port_use_ptr(client, info->addr.port);
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;
}
@@ -1454,7 +1433,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 */
}
@@ -1465,41 +1444,34 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_port_subscribe *subs = arg;
- int result = -EINVAL;
- struct snd_seq_client *receiver = NULL, *sender = NULL;
- struct snd_seq_client_port *sport = NULL, *dport = NULL;
+ struct snd_seq_client *receiver __free(snd_seq_client) = NULL;
+ struct snd_seq_client *sender __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *sport __free(snd_seq_port) = NULL;
+ struct snd_seq_client_port *dport __free(snd_seq_port) = NULL;
+ int result;
- 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);
+ return -EINVAL;
+ sender = client_load_and_use_ptr(subs->sender.client);
if (!sender)
- goto __end;
+ return -EINVAL;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
- goto __end;
+ return -EINVAL;
dport = snd_seq_port_use_ptr(receiver, subs->dest.port);
if (!dport)
- goto __end;
+ return -EINVAL;
result = check_subscription_permission(client, sport, dport, subs);
if (result < 0)
- goto __end;
+ return result;
/* connect them */
result = snd_seq_port_connect(client, sender, sport, receiver, dport, subs);
if (! result) /* broadcast announce */
snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
- __end:
- if (sport)
- snd_seq_port_unlock(sport);
- if (dport)
- snd_seq_port_unlock(dport);
- if (sender)
- snd_seq_client_unlock(sender);
- if (receiver)
- snd_seq_client_unlock(receiver);
return result;
}
@@ -1511,40 +1483,33 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_port_subscribe *subs = arg;
- int result = -ENXIO;
- struct snd_seq_client *receiver = NULL, *sender = NULL;
- struct snd_seq_client_port *sport = NULL, *dport = NULL;
+ struct snd_seq_client *receiver __free(snd_seq_client) = NULL;
+ struct snd_seq_client *sender __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *sport __free(snd_seq_port) = NULL;
+ struct snd_seq_client_port *dport __free(snd_seq_port) = NULL;
+ int result;
receiver = snd_seq_client_use_ptr(subs->dest.client);
if (!receiver)
- goto __end;
+ return -ENXIO;
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
- goto __end;
+ return -ENXIO;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
- goto __end;
+ return -ENXIO;
dport = snd_seq_port_use_ptr(receiver, subs->dest.port);
if (!dport)
- goto __end;
+ return -ENXIO;
result = check_subscription_permission(client, sport, dport, subs);
if (result < 0)
- goto __end;
+ return result;
result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, subs);
if (! result) /* broadcast announce */
snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
- __end:
- if (sport)
- snd_seq_port_unlock(sport);
- if (dport)
- snd_seq_port_unlock(dport);
- if (sender)
- snd_seq_client_unlock(sender);
- if (receiver)
- snd_seq_client_unlock(receiver);
return result;
}
@@ -1553,7 +1518,7 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
{
struct snd_seq_queue_info *info = arg;
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
if (IS_ERR(q))
@@ -1567,7 +1532,6 @@ static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
if (!info->name[0])
snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
strscpy(q->name, info->name, sizeof(q->name));
- snd_use_lock_free(&q->use_lock);
return 0;
}
@@ -1585,7 +1549,7 @@ static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_queue_info *info = arg;
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
q = queueptr(info->queue);
if (q == NULL)
@@ -1596,7 +1560,6 @@ static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client,
info->owner = q->owner;
info->locked = q->locked;
strscpy(info->name, q->name, sizeof(info->name));
- queuefree(q);
return 0;
}
@@ -1606,7 +1569,7 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_queue_info *info = arg;
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
if (info->owner != client->number)
return -EINVAL;
@@ -1624,12 +1587,9 @@ static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client,
q = queueptr(info->queue);
if (! q)
return -EINVAL;
- if (q->owner != client->number) {
- queuefree(q);
+ if (q->owner != client->number)
return -EPERM;
- }
strscpy(q->name, info->name, sizeof(q->name));
- queuefree(q);
return 0;
}
@@ -1639,7 +1599,7 @@ static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_queue_info *info = arg;
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
q = snd_seq_queue_find_name(info->name);
if (q == NULL)
@@ -1647,7 +1607,6 @@ static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client,
info->queue = q->queue;
info->owner = q->owner;
info->locked = q->locked;
- queuefree(q);
return 0;
}
@@ -1657,7 +1616,7 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_queue_status *status = arg;
- struct snd_seq_queue *queue;
+ struct snd_seq_queue *queue __free(snd_seq_queue) = NULL;
struct snd_seq_timer *tmr;
queue = queueptr(status->queue);
@@ -1675,7 +1634,6 @@ static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client,
status->running = tmr->running;
status->flags = queue->flags;
- queuefree(queue);
return 0;
}
@@ -1686,7 +1644,7 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_queue_tempo *tempo = arg;
- struct snd_seq_queue *queue;
+ struct snd_seq_queue *queue __free(snd_seq_queue) = NULL;
struct snd_seq_timer *tmr;
queue = queueptr(tempo->queue);
@@ -1701,7 +1659,8 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
tempo->ppq = tmr->ppq;
tempo->skew_value = tmr->skew;
tempo->skew_base = tmr->skew_base;
- queuefree(queue);
+ if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 4))
+ tempo->tempo_base = tmr->tempo_base;
return 0;
}
@@ -1722,6 +1681,8 @@ static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
struct snd_seq_queue_tempo *tempo = arg;
int result;
+ if (client->user_pversion < SNDRV_PROTOCOL_VERSION(1, 0, 4))
+ tempo->tempo_base = 0;
result = snd_seq_set_queue_tempo(client->number, tempo);
return result < 0 ? result : 0;
}
@@ -1732,14 +1693,14 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_queue_timer *timer = arg;
- struct snd_seq_queue *queue;
+ struct snd_seq_queue *queue __free(snd_seq_queue) = NULL;
struct snd_seq_timer *tmr;
queue = queueptr(timer->queue);
if (queue == NULL)
return -EINVAL;
- mutex_lock(&queue->timer_mutex);
+ guard(mutex)(&queue->timer_mutex);
tmr = queue->timer;
memset(timer, 0, sizeof(*timer));
timer->queue = queue->queue;
@@ -1749,8 +1710,6 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client,
timer->u.alsa.id = tmr->alsa_id;
timer->u.alsa.resolution = tmr->preferred_resolution;
}
- mutex_unlock(&queue->timer_mutex);
- queuefree(queue);
return 0;
}
@@ -1767,13 +1726,13 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client,
return -EINVAL;
if (snd_seq_queue_check_access(timer->queue, client->number)) {
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
struct snd_seq_timer *tmr;
q = queueptr(timer->queue);
if (q == NULL)
return -ENXIO;
- mutex_lock(&q->timer_mutex);
+ guard(mutex)(&q->timer_mutex);
tmr = q->timer;
snd_seq_queue_timer_close(timer->queue);
tmr->type = timer->type;
@@ -1782,8 +1741,6 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client,
tmr->preferred_resolution = timer->u.alsa.resolution;
}
result = snd_seq_queue_timer_open(timer->queue);
- mutex_unlock(&q->timer_mutex);
- queuefree(q);
} else {
return -EPERM;
}
@@ -1831,9 +1788,9 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_client_pool *info = arg;
- struct snd_seq_client *cptr;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
- 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));
@@ -1850,7 +1807,6 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
info->input_pool = 0;
info->input_free = 0;
}
- snd_seq_client_unlock(cptr);
return 0;
}
@@ -1932,26 +1888,16 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_port_subscribe *subs = arg;
- int result;
- struct snd_seq_client *sender = NULL;
- struct snd_seq_client_port *sport = NULL;
+ struct snd_seq_client *sender __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *sport __free(snd_seq_port) = 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;
+ return -EINVAL;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
- goto __end;
- result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
- subs);
- __end:
- if (sport)
- snd_seq_port_unlock(sport);
- if (sender)
- snd_seq_client_unlock(sender);
-
- return result;
+ return -EINVAL;
+ return snd_seq_port_get_subscription(&sport->c_src, &subs->dest, subs);
}
@@ -1961,19 +1907,18 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
{
struct snd_seq_query_subs *subs = arg;
- int result = -ENXIO;
- struct snd_seq_client *cptr = NULL;
- struct snd_seq_client_port *port = NULL;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *port __free(snd_seq_port) = NULL;
struct snd_seq_port_subs_info *group;
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;
+ return -ENXIO;
port = snd_seq_port_use_ptr(cptr, subs->root.port);
if (!port)
- goto __end;
+ return -ENXIO;
switch (subs->type) {
case SNDRV_SEQ_QUERY_SUBS_READ:
@@ -1983,14 +1928,13 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
group = &port->c_dest;
break;
default:
- goto __end;
+ return -ENXIO;
}
- down_read(&group->list_mutex);
+ guard(rwsem_read)(&group->list_mutex);
/* search for the subscriber */
subs->num_subs = group->count;
i = 0;
- result = -ENOENT;
list_for_each(p, &group->list_head) {
if (i++ == subs->index) {
/* found! */
@@ -2004,19 +1948,11 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
}
subs->flags = s->info.flags;
subs->queue = s->info.queue;
- result = 0;
- break;
+ return 0;
}
}
- up_read(&group->list_mutex);
-
- __end:
- if (port)
- snd_seq_port_unlock(port);
- if (cptr)
- snd_seq_client_unlock(cptr);
- return result;
+ return -ENOENT;
}
@@ -2027,7 +1963,7 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_client_info *info = arg;
- struct snd_seq_client *cptr = NULL;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
/* search for next client */
if (info->client < INT_MAX)
@@ -2035,17 +1971,13 @@ 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);
- if (cptr)
- break; /* found */
+ cptr = client_load_and_use_ptr(info->client);
+ if (cptr) {
+ get_client_info(cptr, info);
+ return 0; /* found */
+ }
}
- if (cptr == NULL)
- return -ENOENT;
-
- get_client_info(cptr, info);
- snd_seq_client_unlock(cptr);
-
- return 0;
+ return -ENOENT;
}
/*
@@ -2055,30 +1987,163 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
void *arg)
{
struct snd_seq_port_info *info = arg;
- struct snd_seq_client *cptr;
- struct snd_seq_client_port *port = NULL;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *port __free(snd_seq_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;
/* search for next port */
info->addr.port++;
port = snd_seq_port_query_nearest(cptr, info);
- if (port == NULL) {
- snd_seq_client_unlock(cptr);
+ if (port == NULL)
return -ENOENT;
- }
/* get port info */
info->addr = port->addr;
snd_seq_get_port_info(port, info);
- snd_seq_port_unlock(port);
- snd_seq_client_unlock(cptr);
return 0;
}
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+#define NUM_UMP_INFOS (SNDRV_UMP_MAX_BLOCKS + 1)
+
+static void free_ump_info(struct snd_seq_client *client)
+{
+ int i;
+
+ if (!client->ump_info)
+ return;
+ for (i = 0; i < NUM_UMP_INFOS; i++)
+ kfree(client->ump_info[i]);
+ kfree(client->ump_info);
+ client->ump_info = NULL;
+}
+
+static void terminate_ump_info_strings(void *p, int type)
+{
+ if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) {
+ struct snd_ump_endpoint_info *ep = p;
+ ep->name[sizeof(ep->name) - 1] = 0;
+ } else {
+ struct snd_ump_block_info *bp = p;
+ bp->name[sizeof(bp->name) - 1] = 0;
+ }
+}
+
+#ifdef CONFIG_SND_PROC_FS
+static void dump_ump_info(struct snd_info_buffer *buffer,
+ struct snd_seq_client *client)
+{
+ struct snd_ump_endpoint_info *ep;
+ struct snd_ump_block_info *bp;
+ int i;
+
+ if (!client->ump_info)
+ return;
+ ep = client->ump_info[SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT];
+ if (ep && *ep->name)
+ snd_iprintf(buffer, " UMP Endpoint: \"%s\"\n", ep->name);
+ for (i = 0; i < SNDRV_UMP_MAX_BLOCKS; i++) {
+ bp = client->ump_info[i + 1];
+ if (bp && *bp->name) {
+ snd_iprintf(buffer, " UMP Block %d: \"%s\" [%s]\n",
+ i, bp->name,
+ bp->active ? "Active" : "Inactive");
+ snd_iprintf(buffer, " Groups: %d-%d\n",
+ bp->first_group + 1,
+ bp->first_group + bp->num_groups);
+ }
+ }
+}
+#endif
+
+/* UMP-specific ioctls -- called directly without data copy */
+static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct snd_seq_client_ump_info __user *argp =
+ (struct snd_seq_client_ump_info __user *)arg;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
+ int client, type, err = 0;
+ size_t size;
+ void *p;
+
+ if (get_user(client, &argp->client) || get_user(type, &argp->type))
+ return -EFAULT;
+ if (cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO &&
+ caller->number != client)
+ return -EPERM;
+ if (type < 0 || type >= NUM_UMP_INFOS)
+ return -EINVAL;
+ if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
+ size = sizeof(struct snd_ump_endpoint_info);
+ else
+ size = sizeof(struct snd_ump_block_info);
+ cptr = client_load_and_use_ptr(client);
+ if (!cptr)
+ return -ENOENT;
+
+ scoped_guard(mutex, &cptr->ioctl_mutex) {
+ if (!cptr->midi_version) {
+ err = -EBADFD;
+ break;
+ }
+
+ if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) {
+ if (!cptr->ump_info)
+ p = NULL;
+ else
+ p = cptr->ump_info[type];
+ if (!p) {
+ err = -ENODEV;
+ break;
+ }
+ if (copy_to_user(argp->info, p, size)) {
+ err = -EFAULT;
+ break;
+ }
+ } else {
+ if (cptr->type != USER_CLIENT) {
+ err = -EBADFD;
+ break;
+ }
+ if (!cptr->ump_info) {
+ cptr->ump_info = kcalloc(NUM_UMP_INFOS,
+ sizeof(void *), GFP_KERNEL);
+ if (!cptr->ump_info) {
+ err = -ENOMEM;
+ break;
+ }
+ }
+ p = memdup_user(argp->info, size);
+ if (IS_ERR(p)) {
+ err = PTR_ERR(p);
+ break;
+ }
+ kfree(cptr->ump_info[type]);
+ terminate_ump_info_strings(p, type);
+ cptr->ump_info[type] = p;
+ }
+
+ }
+ 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
+
/* -------------------------------------------------------- */
static const struct ioctl_handler {
@@ -2086,6 +2151,7 @@ static const struct ioctl_handler {
int (*func)(struct snd_seq_client *client, void *arg);
} ioctl_handlers[] = {
{ SNDRV_SEQ_IOCTL_PVERSION, snd_seq_ioctl_pversion },
+ { SNDRV_SEQ_IOCTL_USER_PVERSION, snd_seq_ioctl_user_pversion },
{ SNDRV_SEQ_IOCTL_CLIENT_ID, snd_seq_ioctl_client_id },
{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
@@ -2148,6 +2214,15 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd,
if (snd_BUG_ON(!client))
return -ENXIO;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ /* exception - handling large data */
+ switch (cmd) {
+ case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO:
+ case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO:
+ return snd_seq_ioctl_client_ump_info(client, cmd, arg);
+ }
+#endif
+
for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
if (handler->cmd == cmd)
break;
@@ -2167,9 +2242,9 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
}
- mutex_lock(&client->ioctl_mutex);
- err = handler->func(client, &buf);
- mutex_unlock(&client->ioctl_mutex);
+ scoped_guard(mutex, &client->ioctl_mutex) {
+ err = handler->func(client, &buf);
+ }
if (err >= 0) {
/* Some commands includes a bug in 'dir' field. */
if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT ||
@@ -2206,33 +2281,32 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)
return -EINVAL;
- mutex_lock(&register_mutex);
+ scoped_guard(mutex, &register_mutex) {
- if (card) {
- client_index += SNDRV_SEQ_GLOBAL_CLIENTS
- + card->number * SNDRV_SEQ_CLIENTS_PER_CARD;
- if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN)
- client_index = -1;
- }
+ if (card) {
+ client_index += SNDRV_SEQ_GLOBAL_CLIENTS
+ + card->number * SNDRV_SEQ_CLIENTS_PER_CARD;
+ if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN)
+ client_index = -1;
+ }
- /* empty write queue as default */
- client = seq_create_client1(client_index, 0);
- if (client == NULL) {
- mutex_unlock(&register_mutex);
- return -EBUSY; /* failure code */
- }
- usage_alloc(&client_usage, 1);
+ /* empty write queue as default */
+ client = seq_create_client1(client_index, 0);
+ if (client == NULL)
+ return -EBUSY; /* failure code */
+ usage_alloc(&client_usage, 1);
- client->accept_input = 1;
- client->accept_output = 1;
- client->data.kernel.card = card;
+ client->accept_input = 1;
+ client->accept_output = 1;
+ client->data.kernel.card = card;
+ client->user_pversion = SNDRV_SEQ_VERSION;
- va_start(args, name_fmt);
- vsnprintf(client->name, sizeof(client->name), name_fmt, args);
- va_end(args);
+ va_start(args, name_fmt);
+ vsnprintf(client->name, sizeof(client->name), name_fmt, args);
+ va_end(args);
- client->type = KERNEL_CLIENT;
- mutex_unlock(&register_mutex);
+ client->type = KERNEL_CLIENT;
+ }
/* make others aware this new client */
snd_seq_system_client_ev_client_start(client->number);
@@ -2268,16 +2342,17 @@ EXPORT_SYMBOL(snd_seq_delete_kernel_client);
int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
struct file *file, bool blocking)
{
- struct snd_seq_client *cptr;
- int result;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
if (snd_BUG_ON(!ev))
return -EINVAL;
- if (ev->type == SNDRV_SEQ_EVENT_NONE)
- return 0; /* ignore this */
- if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
- return -EINVAL; /* quoted events can't be enqueued */
+ if (!snd_seq_ev_is_ump(ev)) {
+ if (ev->type == SNDRV_SEQ_EVENT_NONE)
+ return 0; /* ignore this */
+ if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
+ return -EINVAL; /* quoted events can't be enqueued */
+ }
/* fill in client number */
ev->source.client = client;
@@ -2285,22 +2360,18 @@ 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;
if (!cptr->accept_output) {
- result = -EPERM;
+ return -EPERM;
} else { /* send it */
- mutex_lock(&cptr->ioctl_mutex);
- result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
- false, 0,
- &cptr->ioctl_mutex);
- mutex_unlock(&cptr->ioctl_mutex);
+ guard(mutex)(&cptr->ioctl_mutex);
+ return snd_seq_client_enqueue_event(cptr, ev, file, blocking,
+ false, 0,
+ &cptr->ioctl_mutex);
}
-
- snd_seq_client_unlock(cptr);
- return result;
}
EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
@@ -2314,8 +2385,7 @@ EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
int atomic, int hop)
{
- struct snd_seq_client *cptr;
- int result;
+ struct snd_seq_client *cptr __free(snd_seq_client) = NULL;
if (snd_BUG_ON(!ev))
return -EINVAL;
@@ -2332,15 +2402,27 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
return -EINVAL;
if (!cptr->accept_output)
- result = -EPERM;
+ return -EPERM;
else
- result = snd_seq_deliver_event(cptr, ev, atomic, hop);
-
- snd_seq_client_unlock(cptr);
- return result;
+ return snd_seq_deliver_event(cptr, ev, atomic, hop);
}
EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
+static int call_seq_client_ctl(struct snd_seq_client *client,
+ unsigned int cmd, void *arg)
+{
+ const struct ioctl_handler *handler;
+
+ for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
+ if (handler->cmd == cmd)
+ return handler->func(client, arg);
+ }
+
+ pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
+ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
+ return -ENOTTY;
+}
+
/**
* snd_seq_kernel_client_ctl - operate a command for a client with data in
* kernel space.
@@ -2355,24 +2437,29 @@ EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
*/
int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
{
- const struct ioctl_handler *handler;
struct snd_seq_client *client;
client = clientptr(clientid);
if (client == NULL)
return -ENXIO;
- for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
- if (handler->cmd == cmd)
- return handler->func(client, arg);
- }
-
- pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
- cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
- return -ENOTTY;
+ return call_seq_client_ctl(client, cmd, arg);
}
EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
+/* a similar like above but taking locks; used only from OSS sequencer layer */
+int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg)
+{
+ struct snd_seq_client *client __free(snd_seq_client) = NULL;
+
+ client = client_load_and_use_ptr(clientid);
+ if (!client)
+ return -ENXIO;
+ guard(mutex)(&client->ioctl_mutex);
+ return call_seq_client_ctl(client, cmd, arg);
+}
+EXPORT_SYMBOL_GPL(snd_seq_kernel_client_ioctl);
+
/* exported (for OSS emulator) */
int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait)
{
@@ -2382,14 +2469,27 @@ 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;
}
EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
+/* get a sequencer client object; for internal use from a kernel client */
+struct snd_seq_client *snd_seq_kernel_client_get(int id)
+{
+ return snd_seq_client_use_ptr(id);
+}
+EXPORT_SYMBOL_GPL(snd_seq_kernel_client_get);
+
+/* put a sequencer client object; for internal use from a kernel client */
+void snd_seq_kernel_client_put(struct snd_seq_client *cptr)
+{
+ if (cptr)
+ snd_seq_client_unref(cptr);
+}
+EXPORT_SYMBOL_GPL(snd_seq_kernel_client_put);
+
/*---------------------------------------------------------------------------*/
#ifdef CONFIG_SND_PROC_FS
@@ -2404,11 +2504,9 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
struct snd_seq_subscribers *s;
int count = 0;
- down_read(&group->list_mutex);
- if (list_empty(&group->list_head)) {
- up_read(&group->list_mutex);
+ guard(rwsem_read)(&group->list_mutex);
+ if (list_empty(&group->list_head))
return;
- }
snd_iprintf(buffer, msg);
list_for_each(p, &group->list_head) {
if (is_src)
@@ -2425,7 +2523,6 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
if (group->exclusive)
snd_iprintf(buffer, "[ex]");
}
- up_read(&group->list_mutex);
snd_iprintf(buffer, "\n");
}
@@ -2435,32 +2532,62 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')
+static const char *port_direction_name(unsigned char dir)
+{
+ static const char *names[4] = {
+ "-", "In", "Out", "In/Out"
+ };
+
+ if (dir > SNDRV_SEQ_PORT_DIR_BIDIRECTION)
+ return "Invalid";
+ return names[dir];
+}
+
static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
struct snd_seq_client *client)
{
struct snd_seq_client_port *p;
- mutex_lock(&client->ports_mutex);
+ guard(mutex)(&client->ports_mutex);
list_for_each_entry(p, &client->ports_list_head, list) {
- snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
+ if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE)
+ continue;
+ snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c) [%s]",
p->addr.port, p->name,
FLAG_PERM_RD(p->capability),
FLAG_PERM_WR(p->capability),
FLAG_PERM_EX(p->capability),
- FLAG_PERM_DUPLEX(p->capability));
+ FLAG_PERM_DUPLEX(p->capability),
+ port_direction_name(p->direction));
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ if (snd_seq_client_is_midi2(client) && p->is_midi1)
+ snd_iprintf(buffer, " [MIDI1]");
+#endif
+ snd_iprintf(buffer, "\n");
snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: ");
snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: ");
}
- mutex_unlock(&client->ports_mutex);
}
+static const char *midi_version_string(unsigned int version)
+{
+ switch (version) {
+ case SNDRV_SEQ_CLIENT_LEGACY_MIDI:
+ return "Legacy";
+ case SNDRV_SEQ_CLIENT_UMP_MIDI_1_0:
+ return "UMP MIDI1";
+ case SNDRV_SEQ_CLIENT_UMP_MIDI_2_0:
+ return "UMP MIDI2";
+ default:
+ return "Unknown";
+ }
+}
/* exported to seq_info.c */
void snd_seq_info_clients_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
int c;
- struct snd_seq_client *client;
snd_iprintf(buffer, "Client info\n");
snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur);
@@ -2470,17 +2597,22 @@ 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);
+ struct snd_seq_client *client __free(snd_seq_client) = NULL;
+
+ client = client_load_and_use_ptr(c);
if (client == NULL)
continue;
- if (client->type == NO_CLIENT) {
- snd_seq_client_unlock(client);
+ if (client->type == NO_CLIENT)
continue;
- }
- snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n",
+ guard(mutex)(&client->ioctl_mutex);
+ snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n",
c, client->name,
- client->type == USER_CLIENT ? "User" : "Kernel");
+ client->type == USER_CLIENT ? "User" : "Kernel",
+ midi_version_string(client->midi_version));
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ dump_ump_info(buffer, client);
+#endif
snd_seq_info_dump_ports(buffer, client);
if (snd_seq_write_pool_allocated(client)) {
snd_iprintf(buffer, " Output pool :\n");
@@ -2491,7 +2623,6 @@ 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, " ");
}
- snd_seq_client_unlock(client);
}
}
#endif /* CONFIG_SND_PROC_FS */
@@ -2510,13 +2641,12 @@ static const struct file_operations snd_seq_f_ops =
.write = snd_seq_write,
.open = snd_seq_open,
.release = snd_seq_release,
- .llseek = no_llseek,
.poll = snd_seq_poll,
.unlocked_ioctl = snd_seq_ioctl,
.compat_ioctl = snd_seq_ioctl_compat,
};
-static struct device seq_dev;
+static struct device *seq_dev;
/*
* register sequencer device
@@ -2525,15 +2655,17 @@ int __init snd_sequencer_device_init(void)
{
int err;
- snd_device_initialize(&seq_dev, NULL);
- dev_set_name(&seq_dev, "seq");
+ err = snd_device_alloc(&seq_dev, NULL);
+ if (err < 0)
+ return err;
+ dev_set_name(seq_dev, "seq");
- mutex_lock(&register_mutex);
- err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
- &snd_seq_f_ops, NULL, &seq_dev);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_mutex) {
+ err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
+ &snd_seq_f_ops, NULL, seq_dev);
+ }
if (err < 0) {
- put_device(&seq_dev);
+ put_device(seq_dev);
return err;
}
@@ -2547,6 +2679,6 @@ int __init snd_sequencer_device_init(void)
*/
void snd_sequencer_device_done(void)
{
- snd_unregister_device(&seq_dev);
- put_device(&seq_dev);
+ snd_unregister_device(seq_dev);
+ put_device(seq_dev);
}
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index 8cdd0ee53fb1..ece02c58db70 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -12,7 +12,6 @@
#include "seq_ports.h"
#include "seq_lock.h"
-
/* client manager */
struct snd_seq_user_client {
@@ -35,10 +34,13 @@ struct snd_seq_client {
snd_seq_client_type_t type;
unsigned int accept_input: 1,
accept_output: 1;
+ unsigned int midi_version;
+ unsigned int user_pversion;
char name[64]; /* client name */
int number; /* client number */
unsigned int filter; /* filter flags */
DECLARE_BITMAP(event_filter, 256);
+ unsigned short group_filter;
snd_use_lock_t use_lock;
int event_lost;
/* ports */
@@ -48,6 +50,7 @@ struct snd_seq_client {
struct mutex ports_mutex;
struct mutex ioctl_mutex;
int convert32; /* convert 32->64bit */
+ int ump_endpoint_port;
/* output pool */
struct snd_seq_pool *pool; /* memory pool for this client */
@@ -56,6 +59,9 @@ struct snd_seq_client {
struct snd_seq_user_client user;
struct snd_seq_kernel_client kernel;
} data;
+
+ /* for UMP */
+ void **ump_info;
};
/* usage statistics */
@@ -72,8 +78,20 @@ void snd_sequencer_device_done(void);
/* get locked pointer to client */
struct snd_seq_client *snd_seq_client_use_ptr(int clientid);
+static inline struct snd_seq_client *
+snd_seq_client_ref(struct snd_seq_client *client)
+{
+ snd_use_lock_use(&client->use_lock);
+ return client;
+}
+
/* unlock pointer to client */
-#define snd_seq_client_unlock(client) snd_use_lock_free(&(client)->use_lock)
+static inline void snd_seq_client_unref(struct snd_seq_client *client)
+{
+ snd_use_lock_free(&client->use_lock);
+}
+
+DEFINE_FREE(snd_seq_client, struct snd_seq_client *, if (!IS_ERR_OR_NULL(_T)) snd_seq_client_unref(_T))
/* dispatch event to client(s) */
int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop);
@@ -82,10 +100,28 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
int snd_seq_client_notify_subscription(int client, int port,
struct snd_seq_port_subscribe *info, int evtype);
+int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop);
+
/* only for OSS sequencer */
-bool snd_seq_client_ioctl_lock(int clientid);
-void snd_seq_client_ioctl_unlock(int clientid);
+int snd_seq_kernel_client_ioctl(int clientid, unsigned int cmd, void *arg);
extern int seq_client_load[15];
+/* for internal use between kernel sequencer clients */
+struct snd_seq_client *snd_seq_kernel_client_get(int client);
+void snd_seq_kernel_client_put(struct snd_seq_client *cptr);
+
+static inline bool snd_seq_client_is_ump(struct snd_seq_client *c)
+{
+ return c->midi_version != SNDRV_SEQ_CLIENT_LEGACY_MIDI;
+}
+
+static inline bool snd_seq_client_is_midi2(struct snd_seq_client *c)
+{
+ return c->midi_version == SNDRV_SEQ_CLIENT_UMP_MIDI_2_0;
+}
+
#endif
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
index 54723566ce24..643af4c1e838 100644
--- a/sound/core/seq/seq_compat.c
+++ b/sound/core/seq/seq_compat.c
@@ -31,8 +31,8 @@ struct snd_seq_port_info32 {
static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd,
struct snd_seq_port_info32 __user *data32)
{
- int err = -EFAULT;
- struct snd_seq_port_info *data;
+ struct snd_seq_port_info *data __free(kfree) = NULL;
+ int err;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -41,20 +41,18 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned
if (copy_from_user(data, data32, sizeof(*data32)) ||
get_user(data->flags, &data32->flags) ||
get_user(data->time_queue, &data32->time_queue))
- goto error;
+ return -EFAULT;
data->kernel = NULL;
err = snd_seq_kernel_client_ctl(client->number, cmd, data);
if (err < 0)
- goto error;
+ return err;
if (copy_to_user(data32, data, sizeof(*data32)) ||
put_user(data->flags, &data32->flags) ||
put_user(data->time_queue, &data32->time_queue))
- err = -EFAULT;
+ return -EFAULT;
- error:
- kfree(data);
return err;
}
@@ -81,10 +79,13 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
switch (cmd) {
case SNDRV_SEQ_IOCTL_PVERSION:
+ case SNDRV_SEQ_IOCTL_USER_PVERSION:
case SNDRV_SEQ_IOCTL_CLIENT_ID:
case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
+ case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO:
+ case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO:
case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index 8c18d8c4177e..783fc72c2ef6 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -58,6 +58,12 @@ MODULE_PARM_DESC(ports, "number of ports to be created");
module_param(duplex, bool, 0444);
MODULE_PARM_DESC(duplex, "create DUPLEX ports");
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+static int ump;
+module_param(ump, int, 0444);
+MODULE_PARM_DESC(ump, "UMP conversion (0: no convert, 1: MIDI 1.0, 2: MIDI 2.0)");
+#endif
+
struct snd_seq_dummy_port {
int client;
int port;
@@ -127,6 +133,7 @@ create_port(int idx, int type)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
if (duplex)
pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+ pinfo.direction = SNDRV_SEQ_PORT_DIR_BIDIRECTION;
pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
| SNDRV_SEQ_PORT_TYPE_SOFTWARE
| SNDRV_SEQ_PORT_TYPE_PORT;
@@ -151,6 +158,9 @@ static int __init
register_client(void)
{
struct snd_seq_dummy_port *rec1, *rec2;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ struct snd_seq_client *client;
+#endif
int i;
if (ports < 1) {
@@ -164,6 +174,25 @@ register_client(void)
if (my_client < 0)
return my_client;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ client = snd_seq_kernel_client_get(my_client);
+ if (!client)
+ return -EINVAL;
+ switch (ump) {
+ case 1:
+ client->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_1_0;
+ break;
+ case 2:
+ client->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_2_0;
+ break;
+ default:
+ /* don't convert events but just pass-through */
+ client->filter = SNDRV_SEQ_FILTER_NO_CONVERT;
+ break;
+ }
+ snd_seq_kernel_client_put(client);
+#endif
+
/* create ports */
for (i = 0; i < ports; i++) {
rec1 = create_port(i, 0);
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index f8e02e98709a..91cce1890111 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -88,12 +88,11 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f)
atomic_set(&f->overflow, 0);
snd_use_lock_sync(&f->use_lock);
- spin_lock_irq(&f->lock);
+ guard(spinlock_irq)(&f->lock);
/* drain the fifo */
while ((cell = fifo_cell_out(f)) != NULL) {
snd_seq_cell_free(cell);
}
- spin_unlock_irq(&f->lock);
}
@@ -102,38 +101,34 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
struct snd_seq_event *event)
{
struct snd_seq_event_cell *cell;
- unsigned long flags;
int err;
if (snd_BUG_ON(!f))
return -EINVAL;
- snd_use_lock_use(&f->use_lock);
+ guard(snd_seq_fifo)(f);
err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
if (err < 0) {
if ((err == -ENOMEM) || (err == -EAGAIN))
atomic_inc(&f->overflow);
- snd_use_lock_free(&f->use_lock);
return err;
}
/* append new cells to fifo */
- spin_lock_irqsave(&f->lock, flags);
- if (f->tail != NULL)
- f->tail->next = cell;
- f->tail = cell;
- if (f->head == NULL)
- f->head = cell;
- cell->next = NULL;
- f->cells++;
- spin_unlock_irqrestore(&f->lock, flags);
+ scoped_guard(spinlock_irqsave, &f->lock) {
+ if (f->tail != NULL)
+ f->tail->next = cell;
+ f->tail = cell;
+ if (f->head == NULL)
+ f->head = cell;
+ cell->next = NULL;
+ f->cells++;
+ }
/* wakeup client */
if (waitqueue_active(&f->input_sleep))
wake_up(&f->input_sleep);
- snd_use_lock_free(&f->use_lock);
-
return 0; /* success */
}
@@ -199,16 +194,13 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
struct snd_seq_event_cell *cell)
{
- unsigned long flags;
-
if (cell) {
- spin_lock_irqsave(&f->lock, flags);
+ guard(spinlock_irqsave)(&f->lock);
cell->next = f->head;
f->head = cell;
if (!f->tail)
f->tail = cell;
f->cells++;
- spin_unlock_irqrestore(&f->lock, flags);
}
}
@@ -218,6 +210,7 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file,
poll_table *wait)
{
poll_wait(file, &f->input_sleep, wait);
+ guard(spinlock_irq)(&f->lock);
return (f->cells > 0);
}
@@ -239,17 +232,17 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
return -ENOMEM;
}
- spin_lock_irq(&f->lock);
- /* remember old pool */
- oldpool = f->pool;
- oldhead = f->head;
- /* exchange pools */
- f->pool = newpool;
- f->head = NULL;
- f->tail = NULL;
- f->cells = 0;
- /* NOTE: overflow flag is not cleared */
- spin_unlock_irq(&f->lock);
+ scoped_guard(spinlock_irq, &f->lock) {
+ /* remember old pool */
+ oldpool = f->pool;
+ oldhead = f->head;
+ /* exchange pools */
+ f->pool = newpool;
+ f->head = NULL;
+ f->tail = NULL;
+ f->cells = 0;
+ /* NOTE: overflow flag is not cleared */
+ }
/* close the old pool and wait until all users are gone */
snd_seq_pool_mark_closing(oldpool);
@@ -268,16 +261,10 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
/* get the number of unused cells safely */
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
{
- unsigned long flags;
- int cells;
-
if (!f)
return 0;
- snd_use_lock_use(&f->use_lock);
- spin_lock_irqsave(&f->lock, flags);
- cells = snd_seq_unused_cells(f->pool);
- spin_unlock_irqrestore(&f->lock, flags);
- snd_use_lock_free(&f->use_lock);
- return cells;
+ guard(snd_seq_fifo)(f);
+ guard(spinlock_irqsave)(&f->lock);
+ return snd_seq_unused_cells(f->pool);
}
diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h
index b56a7b897c9c..4c9c49127746 100644
--- a/sound/core/seq/seq_fifo.h
+++ b/sound/core/seq/seq_fifo.h
@@ -37,6 +37,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, struct snd_seq_event *event);
/* lock fifo from release */
#define snd_seq_fifo_lock(fifo) snd_use_lock_use(&(fifo)->use_lock)
#define snd_seq_fifo_unlock(fifo) snd_use_lock_free(&(fifo)->use_lock)
+DEFINE_GUARD(snd_seq_fifo, struct snd_seq_fifo *, snd_seq_fifo_lock(_T), snd_seq_fifo_unlock(_T))
/* get a cell from fifo - fifo should be locked */
int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, struct snd_seq_event_cell **cellp, int nonblock);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 47ef6bc30c0e..ccde0ca3d208 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -63,8 +63,9 @@ static int get_var_len(const struct snd_seq_event *event)
return event->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
}
-int snd_seq_dump_var_event(const struct snd_seq_event *event,
- snd_seq_dump_func_t func, void *private_data)
+static int dump_var_event(const struct snd_seq_event *event,
+ snd_seq_dump_func_t func, void *private_data,
+ int offset, int maxlen)
{
int len, err;
struct snd_seq_event_cell *cell;
@@ -72,10 +73,16 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
len = get_var_len(event);
if (len <= 0)
return len;
+ if (len <= offset)
+ return 0;
+ if (maxlen && len > offset + maxlen)
+ len = offset + maxlen;
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
char buf[32];
char __user *curptr = (char __force __user *)event->data.ext.ptr;
+ curptr += offset;
+ len -= offset;
while (len > 0) {
int size = sizeof(buf);
if (len < size)
@@ -91,20 +98,35 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
return 0;
}
if (!(event->data.ext.len & SNDRV_SEQ_EXT_CHAINED))
- return func(private_data, event->data.ext.ptr, len);
+ return func(private_data, event->data.ext.ptr + offset,
+ len - offset);
cell = (struct snd_seq_event_cell *)event->data.ext.ptr;
for (; len > 0 && cell; cell = cell->next) {
int size = sizeof(struct snd_seq_event);
+ char *curptr = (char *)&cell->event;
+
+ if (offset >= size) {
+ offset -= size;
+ len -= size;
+ continue;
+ }
if (len < size)
size = len;
- err = func(private_data, &cell->event, size);
+ err = func(private_data, curptr + offset, size - offset);
if (err < 0)
return err;
+ offset = 0;
len -= size;
}
return 0;
}
+
+int snd_seq_dump_var_event(const struct snd_seq_event *event,
+ snd_seq_dump_func_t func, void *private_data)
+{
+ return dump_var_event(event, func, private_data, 0, 0);
+}
EXPORT_SYMBOL(snd_seq_dump_var_event);
@@ -132,11 +154,27 @@ static int seq_copy_in_user(void *ptr, void *src, int size)
return 0;
}
+static int expand_var_event(const struct snd_seq_event *event,
+ int offset, int size, char *buf, bool in_kernel)
+{
+ if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
+ if (! in_kernel)
+ return -EINVAL;
+ if (copy_from_user(buf,
+ (char __force __user *)event->data.ext.ptr + offset,
+ size))
+ return -EFAULT;
+ return 0;
+ }
+ return dump_var_event(event,
+ in_kernel ? seq_copy_in_kernel : seq_copy_in_user,
+ &buf, offset, size);
+}
+
int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char *buf,
int in_kernel, int size_aligned)
{
- int len, newlen;
- int err;
+ int len, newlen, err;
len = get_var_len(event);
if (len < 0)
@@ -146,21 +184,40 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
newlen = roundup(len, size_aligned);
if (count < newlen)
return -EAGAIN;
-
- if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
- if (! in_kernel)
- return -EINVAL;
- if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len))
+ err = expand_var_event(event, 0, len, buf, in_kernel);
+ if (err < 0)
+ return err;
+ if (len != newlen) {
+ if (in_kernel)
+ memset(buf + len, 0, newlen - len);
+ else if (clear_user((__force void __user *)buf + len,
+ newlen - len))
return -EFAULT;
- return newlen;
}
- err = snd_seq_dump_var_event(event,
- in_kernel ? seq_copy_in_kernel : seq_copy_in_user,
- &buf);
- return err < 0 ? err : newlen;
+ return newlen;
}
EXPORT_SYMBOL(snd_seq_expand_var_event);
+int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count,
+ char *buf, int offset)
+{
+ int len, err;
+
+ len = get_var_len(event);
+ if (len < 0)
+ return len;
+ if (len <= offset)
+ return 0;
+ len -= offset;
+ if (len > count)
+ len = count;
+ err = expand_var_event(event, offset, count, buf, true);
+ if (err < 0)
+ return err;
+ return len;
+}
+EXPORT_SYMBOL_GPL(snd_seq_expand_var_event_at);
+
/*
* release this cell, free extended data if available
*/
@@ -175,7 +232,6 @@ static inline void free_cell(struct snd_seq_pool *pool,
void snd_seq_cell_free(struct snd_seq_event_cell * cell)
{
- unsigned long flags;
struct snd_seq_pool *pool;
if (snd_BUG_ON(!cell))
@@ -184,7 +240,7 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
if (snd_BUG_ON(!pool))
return;
- spin_lock_irqsave(&pool->lock, flags);
+ guard(spinlock_irqsave)(&pool->lock);
free_cell(pool, cell);
if (snd_seq_ev_is_variable(&cell->event)) {
if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
@@ -202,7 +258,6 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
if (snd_seq_output_ok(pool))
wake_up(&pool->output_sleep);
}
- spin_unlock_irqrestore(&pool->lock, flags);
}
@@ -288,6 +343,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
int ncells, err;
unsigned int extlen;
struct snd_seq_event_cell *cell;
+ int size;
*cellp = NULL;
@@ -305,7 +361,12 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
return err;
/* copy the event */
- cell->event = *event;
+ size = snd_seq_event_packet_size(event);
+ memcpy(&cell->ump, event, size);
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ if (size < sizeof(cell->event))
+ cell->ump.raw.extra = 0;
+#endif
/* decompose */
if (snd_seq_ev_is_variable(event)) {
@@ -323,7 +384,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
tail = NULL;
while (ncells-- > 0) {
- int size = sizeof(struct snd_seq_event);
+ size = sizeof(struct snd_seq_event);
if (len < size)
size = len;
err = snd_seq_cell_alloc(pool, &tmp, nonblock, file,
@@ -366,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);
}
@@ -379,15 +441,15 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
if (snd_BUG_ON(!pool))
return -EINVAL;
- cellptr = kvmalloc_array(sizeof(struct snd_seq_event_cell), pool->size,
+ cellptr = kvmalloc_array(pool->size,
+ sizeof(struct snd_seq_event_cell),
GFP_KERNEL);
if (!cellptr)
return -ENOMEM;
/* add new cells to the free cell list */
- spin_lock_irq(&pool->lock);
+ guard(spinlock_irq)(&pool->lock);
if (pool->ptr) {
- spin_unlock_irq(&pool->lock);
kvfree(cellptr);
return 0;
}
@@ -406,20 +468,16 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
/* init statistics */
pool->max_used = 0;
pool->total_elements = pool->size;
- spin_unlock_irq(&pool->lock);
return 0;
}
/* refuse the further insertion to the pool */
void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
{
- unsigned long flags;
-
if (snd_BUG_ON(!pool))
return;
- spin_lock_irqsave(&pool->lock, flags);
+ guard(spinlock_irqsave)(&pool->lock);
pool->closing = 1;
- spin_unlock_irqrestore(&pool->lock, flags);
}
/* remove events */
@@ -438,18 +496,17 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
schedule_timeout_uninterruptible(1);
/* release all resources */
- spin_lock_irq(&pool->lock);
- ptr = pool->ptr;
- pool->ptr = NULL;
- pool->free = NULL;
- pool->total_elements = 0;
- spin_unlock_irq(&pool->lock);
+ scoped_guard(spinlock_irq, &pool->lock) {
+ ptr = pool->ptr;
+ pool->ptr = NULL;
+ pool->free = NULL;
+ pool->total_elements = 0;
+ }
kvfree(ptr);
- spin_lock_irq(&pool->lock);
+ guard(spinlock_irq)(&pool->lock);
pool->closing = 0;
- spin_unlock_irq(&pool->lock);
return 0;
}
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 7d7ff80f915e..7f7a2c0b187d 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -11,9 +11,26 @@
struct snd_info_buffer;
+/* aliasing for legacy and UMP event packet handling */
+union __snd_seq_event {
+ struct snd_seq_event legacy;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ struct snd_seq_ump_event ump;
+#endif
+ struct {
+ struct snd_seq_event event;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ u32 extra;
+#endif
+ } __packed raw;
+};
+
/* container for sequencer event (internal use) */
struct snd_seq_event_cell {
- struct snd_seq_event event;
+ union {
+ struct snd_seq_event event;
+ union __snd_seq_event ump;
+ };
struct snd_seq_pool *pool; /* used pool */
struct snd_seq_event_cell *next; /* next cell */
};
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 4589aac09154..581e138a3115 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -38,6 +38,7 @@ MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
/* data for this midi synth driver */
struct seq_midisynth {
struct snd_card *card;
+ struct snd_rawmidi *rmidi;
int device;
int subdevice;
struct snd_rawmidi_file input_rfile;
@@ -112,6 +113,12 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
return 0;
}
+/* callback for snd_seq_dump_var_event(), bridging to dump_midi() */
+static int __dump_midi(void *ptr, void *buf, int count)
+{
+ return dump_midi(ptr, buf, count);
+}
+
static int event_process_midi(struct snd_seq_event *ev, int direct,
void *private_data, int atomic, int hop)
{
@@ -131,7 +138,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
return 0;
}
- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
+ snd_seq_dump_var_event(ev, __dump_midi, substream);
snd_midi_event_reset_decode(msynth->parser);
} else {
if (msynth->parser == NULL)
@@ -168,8 +175,7 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
struct snd_rawmidi_params params;
/* open midi port */
- err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
- msynth->subdevice,
+ err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
&msynth->input_rfile);
if (err < 0) {
@@ -212,8 +218,7 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
struct snd_rawmidi_params params;
/* open midi port */
- err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
- msynth->subdevice,
+ err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile);
if (err < 0) {
@@ -265,8 +270,8 @@ snd_seq_midisynth_probe(struct device *_dev)
struct snd_seq_device *dev = to_seq_dev(_dev);
struct seq_midisynth_client *client;
struct seq_midisynth *msynth, *ms;
- struct snd_seq_port_info *port;
- struct snd_rawmidi_info *info;
+ struct snd_seq_port_info *port __free(kfree) = NULL;
+ struct snd_rawmidi_info *info __free(kfree) = NULL;
struct snd_rawmidi *rmidi = dev->private_data;
int newclient = 0;
unsigned int p, ports;
@@ -292,31 +297,24 @@ snd_seq_midisynth_probe(struct device *_dev)
ports = output_count;
if (ports < input_count)
ports = input_count;
- if (ports == 0) {
- kfree(info);
+ if (ports == 0)
return -ENODEV;
- }
if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
ports = 256 / SNDRV_RAWMIDI_DEVICES;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
client = synths[card->number];
if (client == NULL) {
newclient = 1;
client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL) {
- mutex_unlock(&register_mutex);
- kfree(info);
+ if (client == NULL)
return -ENOMEM;
- }
client->seq_client =
snd_seq_create_kernel_client(
card, 0, "%s", card->shortname[0] ?
(const char *)card->shortname : "External MIDI");
if (client->seq_client < 0) {
kfree(client);
- mutex_unlock(&register_mutex);
- kfree(info);
return -ENOMEM;
}
}
@@ -328,6 +326,7 @@ snd_seq_midisynth_probe(struct device *_dev)
for (p = 0; p < ports; p++) {
ms = &msynth[p];
+ ms->rmidi = rmidi;
if (snd_seq_midisynth_new(ms, card, device, p) < 0)
goto __nomem;
@@ -345,13 +344,13 @@ snd_seq_midisynth_probe(struct device *_dev)
info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
info->subdevice = p;
if (snd_rawmidi_info_select(card, info) >= 0)
- strcpy(port->name, info->subname);
+ strscpy(port->name, info->subname);
if (! port->name[0]) {
if (info->name[0]) {
if (ports > 1)
- snprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
+ scnprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
else
- snprintf(port->name, sizeof(port->name), "%s", info->name);
+ scnprintf(port->name, sizeof(port->name), "%s", info->name);
} else {
/* last resort */
if (ports > 1)
@@ -367,6 +366,10 @@ snd_seq_midisynth_probe(struct device *_dev)
if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+ if (port->capability & SNDRV_SEQ_PORT_CAP_READ)
+ port->direction |= SNDRV_SEQ_PORT_DIR_INPUT;
+ if (port->capability & SNDRV_SEQ_PORT_CAP_WRITE)
+ port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT;
port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
| SNDRV_SEQ_PORT_TYPE_HARDWARE
| SNDRV_SEQ_PORT_TYPE_PORT;
@@ -392,9 +395,6 @@ snd_seq_midisynth_probe(struct device *_dev)
client->num_ports++;
if (newclient)
synths[card->number] = client;
- mutex_unlock(&register_mutex);
- kfree(info);
- kfree(port);
return 0; /* success */
__nomem:
@@ -407,9 +407,6 @@ snd_seq_midisynth_probe(struct device *_dev)
snd_seq_delete_kernel_client(client->seq_client);
kfree(client);
}
- kfree(info);
- kfree(port);
- mutex_unlock(&register_mutex);
return -ENOMEM;
}
@@ -423,12 +420,10 @@ snd_seq_midisynth_remove(struct device *_dev)
struct snd_card *card = dev->card;
int device = dev->device, p, ports;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
client = synths[card->number];
- if (client == NULL || client->ports[device] == NULL) {
- mutex_unlock(&register_mutex);
+ if (client == NULL || client->ports[device] == NULL)
return -ENODEV;
- }
ports = client->ports_per_device[device];
client->ports_per_device[device] = 0;
msynth = client->ports[device];
@@ -442,7 +437,6 @@ snd_seq_midisynth_remove(struct device *_dev)
synths[card->number] = NULL;
kfree(client);
}
- mutex_unlock(&register_mutex);
return 0;
}
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
index 7511462fe071..fa9dfc53c3fc 100644
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -144,21 +144,15 @@ static inline void reset_encode(struct snd_midi_event *dev)
void snd_midi_event_reset_encode(struct snd_midi_event *dev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
+ guard(spinlock_irqsave)(&dev->lock);
reset_encode(dev);
- spin_unlock_irqrestore(&dev->lock, flags);
}
EXPORT_SYMBOL(snd_midi_event_reset_encode);
void snd_midi_event_reset_decode(struct snd_midi_event *dev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
+ guard(spinlock_irqsave)(&dev->lock);
dev->lastcmd = 0xff;
- spin_unlock_irqrestore(&dev->lock, flags);
}
EXPORT_SYMBOL(snd_midi_event_reset_decode);
@@ -177,7 +171,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
struct snd_seq_event *ev)
{
bool rc = false;
- unsigned long flags;
if (c >= MIDI_CMD_COMMON_CLOCK) {
/* real-time event */
@@ -187,7 +180,7 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
return ev->type != SNDRV_SEQ_EVENT_NONE;
}
- spin_lock_irqsave(&dev->lock, flags);
+ guard(spinlock_irqsave)(&dev->lock);
if ((c & 0x80) &&
(c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
/* new command */
@@ -236,7 +229,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
}
}
- spin_unlock_irqrestore(&dev->lock, flags);
return rc;
}
EXPORT_SYMBOL(snd_midi_event_encode_byte);
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 25fcf5a2c71c..40fa379847e5 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -48,17 +48,15 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
if (client == NULL)
return NULL;
- read_lock(&client->ports_lock);
+ guard(read_lock)(&client->ports_lock);
list_for_each_entry(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
snd_use_lock_use(&port->use_lock);
- read_unlock(&client->ports_lock);
return port;
}
}
- read_unlock(&client->ports_lock);
return NULL; /* not found */
}
@@ -69,11 +67,15 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
{
int num;
struct snd_seq_client_port *port, *found;
+ bool check_inactive = (pinfo->capability & SNDRV_SEQ_PORT_CAP_INACTIVE);
num = pinfo->addr.port;
found = NULL;
- read_lock(&client->ports_lock);
+ guard(read_lock)(&client->ports_lock);
list_for_each_entry(port, &client->ports_list_head, list) {
+ if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
+ !check_inactive)
+ continue; /* skip inactive ports */
if (port->addr.port < num)
continue;
if (port->addr.port == num) {
@@ -89,7 +91,6 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
else
snd_use_lock_use(&found->use_lock);
}
- read_unlock(&client->ports_lock);
return found;
}
@@ -107,42 +108,47 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
}
-/* create a port, port number is returned (-1 on failure);
+/* create a port, port number or a negative error code is returned
* the caller needs to unref the port via snd_seq_port_unlock() appropriately
*/
-struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
- int port)
+int snd_seq_create_port(struct snd_seq_client *client, int port,
+ struct snd_seq_client_port **port_ret)
{
struct snd_seq_client_port *new_port, *p;
- int num = -1;
+ int num;
+ *port_ret = NULL;
+
/* sanity check */
if (snd_BUG_ON(!client))
- return NULL;
+ return -EINVAL;
if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
- return NULL;
+ return -EINVAL;
}
/* create a new port */
new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
if (!new_port)
- return NULL; /* failure, out of memory */
+ return -ENOMEM; /* failure, out of memory */
/* init port data */
new_port->addr.client = client->number;
new_port->addr.port = -1;
new_port->owner = THIS_MODULE;
- sprintf(new_port->name, "port-%d", num);
snd_use_lock_init(&new_port->use_lock);
port_subs_info_init(&new_port->c_src);
port_subs_info_init(&new_port->c_dest);
snd_use_lock_use(&new_port->use_lock);
num = max(port, 0);
- mutex_lock(&client->ports_mutex);
- write_lock_irq(&client->ports_lock);
+ guard(mutex)(&client->ports_mutex);
+ guard(write_lock_irq)(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
+ if (p->addr.port == port) {
+ kfree(new_port);
+ return -EBUSY;
+ }
if (p->addr.port > num)
break;
if (port < 0) /* auto-probe mode */
@@ -153,10 +159,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
- write_unlock_irq(&client->ports_lock);
- mutex_unlock(&client->ports_mutex);
+ *port_ret = new_port;
- return new_port;
+ return num;
}
/* */
@@ -173,17 +178,10 @@ static int unsubscribe_port(struct snd_seq_client *client,
static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
struct snd_seq_client **cp)
{
- struct snd_seq_client_port *p;
*cp = snd_seq_client_use_ptr(addr->client);
- if (*cp) {
- p = snd_seq_port_use_ptr(*cp, addr->port);
- if (! p) {
- snd_seq_client_unlock(*cp);
- *cp = NULL;
- }
- return p;
- }
- return NULL;
+ if (!*cp)
+ return NULL;
+ return snd_seq_port_use_ptr(*cp, addr->port);
}
static void delete_and_unsubscribe_port(struct snd_seq_client *client,
@@ -213,8 +211,8 @@ static void clear_subscriber_list(struct snd_seq_client *client,
list_for_each_safe(p, n, &grp->list_head) {
struct snd_seq_subscribers *subs;
- struct snd_seq_client *c;
- struct snd_seq_client_port *aport;
+ struct snd_seq_client *c __free(snd_seq_client) = NULL;
+ struct snd_seq_client_port *aport __free(snd_seq_port) = NULL;
subs = get_subscriber(p, is_src);
if (is_src)
@@ -236,8 +234,6 @@ static void clear_subscriber_list(struct snd_seq_client *client,
/* ok we got the connected port */
delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
kfree(subs);
- snd_seq_port_unlock(aport);
- snd_seq_client_unlock(c);
}
}
@@ -269,19 +265,18 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
{
struct snd_seq_client_port *found = NULL, *p;
- mutex_lock(&client->ports_mutex);
- write_lock_irq(&client->ports_lock);
- list_for_each_entry(p, &client->ports_list_head, list) {
- if (p->addr.port == port) {
- /* ok found. delete from the list at first */
- list_del(&p->list);
- client->num_ports--;
- found = p;
- break;
+ scoped_guard(mutex, &client->ports_mutex) {
+ guard(write_lock_irq)(&client->ports_lock);
+ list_for_each_entry(p, &client->ports_list_head, list) {
+ if (p->addr.port == port) {
+ /* ok found. delete from the list at first */
+ list_del(&p->list);
+ client->num_ports--;
+ found = p;
+ break;
+ }
}
}
- write_unlock_irq(&client->ports_lock);
- mutex_unlock(&client->ports_mutex);
if (found)
return port_delete(client, found);
else
@@ -297,16 +292,16 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
/* move the port list to deleted_list, and
* clear the port list in the client data.
*/
- mutex_lock(&client->ports_mutex);
- write_lock_irq(&client->ports_lock);
- if (! list_empty(&client->ports_list_head)) {
- list_add(&deleted_list, &client->ports_list_head);
- list_del_init(&client->ports_list_head);
- } else {
- INIT_LIST_HEAD(&deleted_list);
+ guard(mutex)(&client->ports_mutex);
+ scoped_guard(write_lock_irq, &client->ports_lock) {
+ if (!list_empty(&client->ports_list_head)) {
+ list_add(&deleted_list, &client->ports_list_head);
+ list_del_init(&client->ports_list_head);
+ } else {
+ INIT_LIST_HEAD(&deleted_list);
+ }
+ client->num_ports = 0;
}
- client->num_ports = 0;
- write_unlock_irq(&client->ports_lock);
/* remove each port in deleted_list */
list_for_each_entry_safe(port, tmp, &deleted_list, list) {
@@ -314,7 +309,6 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
- mutex_unlock(&client->ports_mutex);
return 0;
}
@@ -345,6 +339,22 @@ int snd_seq_set_port_info(struct snd_seq_client_port * port,
port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0;
port->time_queue = info->time_queue;
+ /* UMP direction and group */
+ port->direction = info->direction;
+ port->ump_group = info->ump_group;
+ if (port->ump_group > SNDRV_UMP_MAX_GROUPS)
+ port->ump_group = 0;
+
+ /* fill default port direction */
+ if (!port->direction) {
+ if (info->capability & SNDRV_SEQ_PORT_CAP_READ)
+ port->direction |= SNDRV_SEQ_PORT_DIR_INPUT;
+ if (info->capability & SNDRV_SEQ_PORT_CAP_WRITE)
+ port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT;
+ }
+
+ port->is_midi1 = !!(info->flags & SNDRV_SEQ_PORT_FLG_IS_MIDI1);
+
return 0;
}
@@ -382,6 +392,13 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
info->time_queue = port->time_queue;
}
+ if (port->is_midi1)
+ info->flags |= SNDRV_SEQ_PORT_FLG_IS_MIDI1;
+
+ /* UMP direction and group */
+ info->direction = port->direction;
+ info->ump_group = port->ump_group;
+
return 0;
}
@@ -476,42 +493,37 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
int err;
grp = is_src ? &port->c_src : &port->c_dest;
- err = -EBUSY;
- down_write(&grp->list_mutex);
+ guard(rwsem_write)(&grp->list_mutex);
if (exclusive) {
if (!list_empty(&grp->list_head))
- goto __error;
+ return -EBUSY;
} else {
if (grp->exclusive)
- goto __error;
+ return -EBUSY;
/* check whether already exists */
list_for_each(p, &grp->list_head) {
s = get_subscriber(p, is_src);
if (match_subs_info(&subs->info, &s->info))
- goto __error;
+ return -EBUSY;
}
}
err = subscribe_port(client, port, grp, &subs->info, ack);
if (err < 0) {
grp->exclusive = 0;
- goto __error;
+ return err;
}
/* add to list */
- write_lock_irq(&grp->list_lock);
+ guard(write_lock_irq)(&grp->list_lock);
if (is_src)
list_add_tail(&subs->src_list, &grp->list_head);
else
list_add_tail(&subs->dest_list, &grp->list_head);
grp->exclusive = exclusive;
atomic_inc(&subs->ref_count);
- write_unlock_irq(&grp->list_lock);
- err = 0;
- __error:
- up_write(&grp->list_mutex);
- return err;
+ return 0;
}
/* called with grp->list_mutex held */
@@ -526,12 +538,12 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
grp = is_src ? &port->c_src : &port->c_dest;
list = is_src ? &subs->src_list : &subs->dest_list;
- write_lock_irq(&grp->list_lock);
- empty = list_empty(list);
- if (!empty)
- list_del_init(list);
- grp->exclusive = 0;
- write_unlock_irq(&grp->list_lock);
+ scoped_guard(write_lock_irq, &grp->list_lock) {
+ empty = list_empty(list);
+ if (!empty)
+ list_del_init(list);
+ grp->exclusive = 0;
+ }
if (!empty)
unsubscribe_port(client, port, grp, &subs->info, ack);
@@ -545,9 +557,8 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
struct snd_seq_port_subs_info *grp;
grp = is_src ? &port->c_src : &port->c_dest;
- down_write(&grp->list_mutex);
+ guard(rwsem_write)(&grp->list_mutex);
__delete_and_unsubscribe_port(client, port, subs, is_src, ack);
- up_write(&grp->list_mutex);
}
/* connect two ports */
@@ -609,18 +620,18 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
/* always start from deleting the dest port for avoiding concurrent
* deletions
*/
- down_write(&dest->list_mutex);
- /* look for the connection */
- list_for_each_entry(subs, &dest->list_head, dest_list) {
- if (match_subs_info(info, &subs->info)) {
- __delete_and_unsubscribe_port(dest_client, dest_port,
- subs, false,
- connector->number != dest_client->number);
- err = 0;
- break;
+ scoped_guard(rwsem_write, &dest->list_mutex) {
+ /* look for the connection */
+ list_for_each_entry(subs, &dest->list_head, dest_list) {
+ if (match_subs_info(info, &subs->info)) {
+ __delete_and_unsubscribe_port(dest_client, dest_port,
+ subs, false,
+ connector->number != dest_client->number);
+ err = 0;
+ break;
+ }
}
}
- up_write(&dest->list_mutex);
if (err < 0)
return err;
@@ -639,7 +650,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
struct snd_seq_subscribers *s;
int err = -ENOENT;
- down_read(&src_grp->list_mutex);
+ guard(rwsem_read)(&src_grp->list_mutex);
list_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
*subs = s->info;
@@ -647,7 +658,6 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
break;
}
}
- up_read(&src_grp->list_mutex);
return err;
}
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
index b1f2c4943174..40ed6cf7cb90 100644
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -7,6 +7,7 @@
#define __SND_SEQ_PORTS_H
#include <sound/seq_kernel.h>
+#include <sound/ump_convert.h>
#include "seq_lock.h"
/* list of 'exported' ports */
@@ -72,6 +73,15 @@ struct snd_seq_client_port {
int midi_voices;
int synth_voices;
+ /* UMP direction and group */
+ unsigned char direction;
+ unsigned char ump_group;
+
+ bool is_midi1; /* keep MIDI 1.0 protocol */
+
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+ struct ump_cvt_to_ump_bank midi2_bank[16]; /* per channel */
+#endif
};
struct snd_seq_client;
@@ -86,8 +96,11 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
/* unlock the port */
#define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock)
-/* create a port, port number is returned (-1 on failure) */
-struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port_index);
+DEFINE_FREE(snd_seq_port, struct snd_seq_client_port *, if (!IS_ERR_OR_NULL(_T)) snd_seq_port_unlock(_T))
+
+/* create a port, port number or a negative error code is returned */
+int snd_seq_create_port(struct snd_seq_client *client, int port_index,
+ struct snd_seq_client_port **port_ret);
/* delete a port */
int snd_seq_delete_port(struct snd_seq_client *client, int port);
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 1d857981e876..e649485a8772 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -132,7 +132,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
struct snd_seq_event_cell * cell)
{
struct snd_seq_event_cell *cur, *prev;
- unsigned long flags;
int count;
int prior;
@@ -142,7 +141,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
/* check flags */
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
- spin_lock_irqsave(&f->lock, flags);
+ guard(spinlock_irqsave)(&f->lock);
/* check if this element needs to inserted at the end (ie. ordered
data is inserted) This will be very likeley if a sequencer
@@ -154,7 +153,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
f->tail = cell;
cell->next = NULL;
f->cells++;
- spin_unlock_irqrestore(&f->lock, flags);
return 0;
}
}
@@ -179,7 +177,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
prev = cur;
cur = cur->next;
if (! --count) {
- spin_unlock_irqrestore(&f->lock, flags);
pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
return -EINVAL;
}
@@ -195,7 +192,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
if (cur == NULL) /* reached end of the list */
f->tail = cell;
f->cells++;
- spin_unlock_irqrestore(&f->lock, flags);
return 0;
}
@@ -213,14 +209,13 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
void *current_time)
{
struct snd_seq_event_cell *cell;
- unsigned long flags;
if (f == NULL) {
pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return NULL;
}
- spin_lock_irqsave(&f->lock, flags);
+ guard(spinlock_irqsave)(&f->lock);
cell = f->head;
if (cell && current_time && !event_is_ready(&cell->event, current_time))
cell = NULL;
@@ -235,7 +230,6 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
f->cells--;
}
- spin_unlock_irqrestore(&f->lock, flags);
return cell;
}
@@ -249,73 +243,43 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
return f->cells;
}
-static inline int prioq_match(struct snd_seq_event_cell *cell,
- int client, int timestamp)
-{
- if (cell->event.source.client == client ||
- cell->event.dest.client == client)
- return 1;
- if (!timestamp)
- return 0;
- switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
- case SNDRV_SEQ_TIME_STAMP_TICK:
- if (cell->event.time.tick)
- return 1;
- break;
- case SNDRV_SEQ_TIME_STAMP_REAL:
- if (cell->event.time.time.tv_sec ||
- cell->event.time.time.tv_nsec)
- return 1;
- break;
- }
- return 0;
-}
-
-/* remove cells for left client */
-void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
+/* remove cells matching with the condition */
+static void prioq_remove_cells(struct snd_seq_prioq *f,
+ bool (*match)(struct snd_seq_event_cell *cell,
+ void *arg),
+ void *arg)
{
register struct snd_seq_event_cell *cell, *next;
- unsigned long flags;
struct snd_seq_event_cell *prev = NULL;
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
/* collect all removed cells */
- spin_lock_irqsave(&f->lock, flags);
- cell = f->head;
- while (cell) {
- next = cell->next;
- if (prioq_match(cell, client, timestamp)) {
+ scoped_guard(spinlock_irqsave, &f->lock) {
+ for (cell = f->head; cell; cell = next) {
+ next = cell->next;
+ if (!match(cell, arg)) {
+ prev = cell;
+ continue;
+ }
+
/* remove cell from prioq */
- if (cell == f->head) {
+ if (cell == f->head)
f->head = cell->next;
- } else {
+ else
prev->next = cell->next;
- }
if (cell == f->tail)
f->tail = cell->next;
f->cells--;
+
/* add cell to free list */
cell->next = NULL;
- if (freefirst == NULL) {
+ if (freefirst == NULL)
freefirst = cell;
- } else {
+ else
freeprev->next = cell;
- }
freeprev = cell;
- } else {
-#if 0
- pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
- "client = %i\n",
- cell->event.type,
- cell->event.source.client,
- cell->event.dest.client,
- client);
-#endif
- prev = cell;
}
- cell = next;
}
- spin_unlock_irqrestore(&f->lock, flags);
/* remove selected cells */
while (freefirst) {
@@ -325,22 +289,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
}
}
-static int prioq_remove_match(struct snd_seq_remove_events *info,
- struct snd_seq_event *ev)
+struct prioq_match_arg {
+ int client;
+ int timestamp;
+};
+
+static inline bool prioq_match(struct snd_seq_event_cell *cell, void *arg)
+{
+ struct prioq_match_arg *v = arg;
+
+ if (cell->event.source.client == v->client ||
+ cell->event.dest.client == v->client)
+ return true;
+ if (!v->timestamp)
+ return false;
+ switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
+ case SNDRV_SEQ_TIME_STAMP_TICK:
+ if (cell->event.time.tick)
+ return true;
+ break;
+ case SNDRV_SEQ_TIME_STAMP_REAL:
+ if (cell->event.time.time.tv_sec ||
+ cell->event.time.time.tv_nsec)
+ return true;
+ break;
+ }
+ return false;
+}
+
+/* remove cells for left client */
+void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp)
{
+ struct prioq_match_arg arg = { client, timestamp };
+
+ return prioq_remove_cells(f, prioq_match, &arg);
+}
+
+struct prioq_remove_match_arg {
+ int client;
+ struct snd_seq_remove_events *info;
+};
+
+static bool prioq_remove_match(struct snd_seq_event_cell *cell, void *arg)
+{
+ struct prioq_remove_match_arg *v = arg;
+ struct snd_seq_event *ev = &cell->event;
+ struct snd_seq_remove_events *info = v->info;
int res;
+ if (ev->source.client != v->client)
+ return false;
+
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
if (ev->dest.client != info->dest.client ||
ev->dest.port != info->dest.port)
- return 0;
+ return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
if (! snd_seq_ev_is_channel_type(ev))
- return 0;
+ return false;
/* data.note.channel and data.control.channel are identical */
if (ev->data.note.channel != info->channel)
- return 0;
+ return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@@ -348,7 +358,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
else
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
if (!res)
- return 0;
+ return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@@ -356,81 +366,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
else
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
if (res)
- return 0;
+ return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
if (ev->type != info->type)
- return 0;
+ return false;
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
/* Do not remove off events */
switch (ev->type) {
case SNDRV_SEQ_EVENT_NOTEOFF:
/* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
- return 0;
+ return false;
default:
break;
}
}
if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
if (info->tag != ev->tag)
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* remove cells matching remove criteria */
void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
struct snd_seq_remove_events *info)
{
- struct snd_seq_event_cell *cell, *next;
- unsigned long flags;
- struct snd_seq_event_cell *prev = NULL;
- struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
-
- /* collect all removed cells */
- spin_lock_irqsave(&f->lock, flags);
- cell = f->head;
-
- while (cell) {
- next = cell->next;
- if (cell->event.source.client == client &&
- prioq_remove_match(info, &cell->event)) {
+ struct prioq_remove_match_arg arg = { client, info };
- /* remove cell from prioq */
- if (cell == f->head) {
- f->head = cell->next;
- } else {
- prev->next = cell->next;
- }
-
- if (cell == f->tail)
- f->tail = cell->next;
- f->cells--;
-
- /* add cell to free list */
- cell->next = NULL;
- if (freefirst == NULL) {
- freefirst = cell;
- } else {
- freeprev->next = cell;
- }
-
- freeprev = cell;
- } else {
- prev = cell;
- }
- cell = next;
- }
- spin_unlock_irqrestore(&f->lock, flags);
-
- /* remove selected cells */
- while (freefirst) {
- freenext = freefirst->next;
- snd_seq_cell_free(freefirst);
- freefirst = freenext;
- }
+ return prioq_remove_cells(f, prioq_remove_match, &arg);
}
-
-
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index bc933104c3ee..f5c0e401c8ae 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -50,43 +50,35 @@ int snd_seq_queue_get_cur_queues(void)
static int queue_list_add(struct snd_seq_queue *q)
{
int i;
- unsigned long flags;
- spin_lock_irqsave(&queue_list_lock, flags);
+ guard(spinlock_irqsave)(&queue_list_lock);
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if (! queue_list[i]) {
queue_list[i] = q;
q->queue = i;
num_queues++;
- spin_unlock_irqrestore(&queue_list_lock, flags);
return i;
}
}
- spin_unlock_irqrestore(&queue_list_lock, flags);
return -1;
}
static struct snd_seq_queue *queue_list_remove(int id, int client)
{
struct snd_seq_queue *q;
- unsigned long flags;
- spin_lock_irqsave(&queue_list_lock, flags);
+ guard(spinlock_irqsave)(&queue_list_lock);
q = queue_list[id];
if (q) {
- spin_lock(&q->owner_lock);
+ guard(spinlock)(&q->owner_lock);
if (q->owner == client) {
/* found */
q->klocked = 1;
- spin_unlock(&q->owner_lock);
queue_list[id] = NULL;
num_queues--;
- spin_unlock_irqrestore(&queue_list_lock, flags);
return q;
}
- spin_unlock(&q->owner_lock);
}
- spin_unlock_irqrestore(&queue_list_lock, flags);
return NULL;
}
@@ -203,15 +195,13 @@ int snd_seq_queue_delete(int client, int queueid)
struct snd_seq_queue *queueptr(int queueid)
{
struct snd_seq_queue *q;
- unsigned long flags;
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
return NULL;
- spin_lock_irqsave(&queue_list_lock, flags);
+ guard(spinlock_irqsave)(&queue_list_lock);
q = queue_list[queueid];
if (q)
snd_use_lock_use(&q->use_lock);
- spin_unlock_irqrestore(&queue_list_lock, flags);
return q;
}
@@ -219,14 +209,13 @@ struct snd_seq_queue *queueptr(int queueid)
struct snd_seq_queue *snd_seq_queue_find_name(char *name)
{
int i;
- struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
q = queueptr(i);
if (q) {
if (strncmp(q->name, name, sizeof(q->name)) == 0)
- return q;
- queuefree(q);
+ return no_free_ptr(q);
}
}
return NULL;
@@ -239,7 +228,6 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
{
- unsigned long flags;
struct snd_seq_event_cell *cell;
snd_seq_tick_time_t cur_tick;
snd_seq_real_time_t cur_time;
@@ -249,14 +237,13 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
return;
/* make this function non-reentrant */
- spin_lock_irqsave(&q->check_lock, flags);
- if (q->check_blocked) {
- q->check_again = 1;
- spin_unlock_irqrestore(&q->check_lock, flags);
- return; /* other thread is already checking queues */
+ scoped_guard(spinlock_irqsave, &q->check_lock) {
+ if (q->check_blocked) {
+ q->check_again = 1;
+ return; /* other thread is already checking queues */
+ }
+ q->check_blocked = 1;
}
- q->check_blocked = 1;
- spin_unlock_irqrestore(&q->check_lock, flags);
__again:
/* Process tick queue... */
@@ -283,16 +270,14 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
out:
/* free lock */
- spin_lock_irqsave(&q->check_lock, flags);
- if (q->check_again) {
- q->check_again = 0;
- if (processed < MAX_CELL_PROCESSES_IN_QUEUE) {
- spin_unlock_irqrestore(&q->check_lock, flags);
- goto __again;
+ scoped_guard(spinlock_irqsave, &q->check_lock) {
+ if (q->check_again) {
+ q->check_again = 0;
+ if (processed < MAX_CELL_PROCESSES_IN_QUEUE)
+ goto __again;
}
+ q->check_blocked = 0;
}
- q->check_blocked = 0;
- spin_unlock_irqrestore(&q->check_lock, flags);
}
@@ -300,7 +285,7 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop)
{
int dest, err;
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
if (snd_BUG_ON(!cell))
return -EINVAL;
@@ -335,16 +320,12 @@ int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop)
break;
}
- if (err < 0) {
- queuefree(q); /* unlock */
+ if (err < 0)
return err;
- }
/* trigger dispatching */
snd_seq_check_queue(q, atomic, hop);
- queuefree(q); /* unlock */
-
return 0;
}
@@ -361,41 +342,31 @@ static inline int check_access(struct snd_seq_queue *q, int client)
*/
static int queue_access_lock(struct snd_seq_queue *q, int client)
{
- unsigned long flags;
int access_ok;
- spin_lock_irqsave(&q->owner_lock, flags);
+ guard(spinlock_irqsave)(&q->owner_lock);
access_ok = check_access(q, client);
if (access_ok)
q->klocked = 1;
- spin_unlock_irqrestore(&q->owner_lock, flags);
return access_ok;
}
/* unlock the queue */
static inline void queue_access_unlock(struct snd_seq_queue *q)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->owner_lock, flags);
+ guard(spinlock_irqsave)(&q->owner_lock);
q->klocked = 0;
- spin_unlock_irqrestore(&q->owner_lock, flags);
}
/* exported - only checking permission */
int snd_seq_queue_check_access(int queueid, int client)
{
- struct snd_seq_queue *q = queueptr(queueid);
- int access_ok;
- unsigned long flags;
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(queueid);
if (! q)
return 0;
- spin_lock_irqsave(&q->owner_lock, flags);
- access_ok = check_access(q, client);
- spin_unlock_irqrestore(&q->owner_lock, flags);
- queuefree(q);
- return access_ok;
+ guard(spinlock_irqsave)(&q->owner_lock);
+ return check_access(q, client);
}
/*----------------------------------------------------------------*/
@@ -405,23 +376,19 @@ int snd_seq_queue_check_access(int queueid, int client)
*/
int snd_seq_queue_set_owner(int queueid, int client, int locked)
{
- struct snd_seq_queue *q = queueptr(queueid);
- unsigned long flags;
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(queueid);
if (q == NULL)
return -EINVAL;
- if (! queue_access_lock(q, client)) {
- queuefree(q);
+ if (!queue_access_lock(q, client))
return -EPERM;
- }
- spin_lock_irqsave(&q->owner_lock, flags);
- q->locked = locked ? 1 : 0;
- q->owner = client;
- spin_unlock_irqrestore(&q->owner_lock, flags);
+ scoped_guard(spinlock_irqsave, &q->owner_lock) {
+ q->locked = locked ? 1 : 0;
+ q->owner = client;
+ }
queue_access_unlock(q);
- queuefree(q);
return 0;
}
@@ -436,7 +403,7 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked)
int snd_seq_queue_timer_open(int queueid)
{
int result = 0;
- struct snd_seq_queue *queue;
+ struct snd_seq_queue *queue __free(snd_seq_queue) = NULL;
struct snd_seq_timer *tmr;
queue = queueptr(queueid);
@@ -448,7 +415,6 @@ int snd_seq_queue_timer_open(int queueid)
snd_seq_timer_defaults(tmr);
result = snd_seq_timer_open(queue);
}
- queuefree(queue);
return result;
}
@@ -457,14 +423,13 @@ int snd_seq_queue_timer_open(int queueid)
*/
int snd_seq_queue_timer_close(int queueid)
{
- struct snd_seq_queue *queue;
+ struct snd_seq_queue *queue __free(snd_seq_queue) = NULL;
int result = 0;
queue = queueptr(queueid);
if (queue == NULL)
return -EINVAL;
snd_seq_timer_close(queue);
- queuefree(queue);
return result;
}
@@ -472,22 +437,20 @@ int snd_seq_queue_timer_close(int queueid)
int snd_seq_queue_timer_set_tempo(int queueid, int client,
struct snd_seq_queue_tempo *info)
{
- struct snd_seq_queue *q = queueptr(queueid);
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(queueid);
int result;
if (q == NULL)
return -EINVAL;
- if (! queue_access_lock(q, client)) {
- queuefree(q);
+ if (!queue_access_lock(q, client))
return -EPERM;
- }
- result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq);
+ result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq,
+ info->tempo_base);
if (result >= 0 && info->skew_base > 0)
result = snd_seq_timer_set_skew(q->timer, info->skew_value,
info->skew_base);
queue_access_unlock(q);
- queuefree(q);
return result;
}
@@ -516,15 +479,13 @@ static void queue_use(struct snd_seq_queue *queue, int client, int use)
*/
int snd_seq_queue_use(int queueid, int client, int use)
{
- struct snd_seq_queue *queue;
+ struct snd_seq_queue *queue __free(snd_seq_queue) = NULL;
queue = queueptr(queueid);
if (queue == NULL)
return -EINVAL;
- mutex_lock(&queue->timer_mutex);
+ guard(mutex)(&queue->timer_mutex);
queue_use(queue, client, use);
- mutex_unlock(&queue->timer_mutex);
- queuefree(queue);
return 0;
}
@@ -535,15 +496,12 @@ int snd_seq_queue_use(int queueid, int client, int use)
*/
int snd_seq_queue_is_used(int queueid, int client)
{
- struct snd_seq_queue *q;
- int result;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
q = queueptr(queueid);
if (q == NULL)
return -EINVAL; /* invalid queue */
- result = test_bit(client, q->clients_bitmap) ? 1 : 0;
- queuefree(q);
- return result;
+ return test_bit(client, q->clients_bitmap) ? 1 : 0;
}
@@ -556,11 +514,10 @@ int snd_seq_queue_is_used(int queueid, int client)
void snd_seq_queue_client_leave(int client)
{
int i;
- struct snd_seq_queue *q;
/* delete own queues from queue list */
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
- q = queue_list_remove(i, client);
+ struct snd_seq_queue *q = queue_list_remove(i, client);
if (q)
queue_delete(q);
}
@@ -569,7 +526,7 @@ void snd_seq_queue_client_leave(int client)
* they are not owned by this client
*/
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
- q = queueptr(i);
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(i);
if (!q)
continue;
if (test_bit(client, q->clients_bitmap)) {
@@ -577,7 +534,6 @@ void snd_seq_queue_client_leave(int client)
snd_seq_prioq_leave(q->timeq, client, 0);
snd_seq_queue_use(q->queue, client, 0);
}
- queuefree(q);
}
}
@@ -585,30 +541,13 @@ void snd_seq_queue_client_leave(int client)
/*----------------------------------------------------------------*/
-/* remove cells from all queues */
-void snd_seq_queue_client_leave_cells(int client)
-{
- int i;
- struct snd_seq_queue *q;
-
- for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
- q = queueptr(i);
- if (!q)
- continue;
- snd_seq_prioq_leave(q->tickq, client, 0);
- snd_seq_prioq_leave(q->timeq, client, 0);
- queuefree(q);
- }
-}
-
/* remove cells based on flush criteria */
void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info)
{
int i;
- struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
- q = queueptr(i);
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(i);
if (!q)
continue;
if (test_bit(client, q->clients_bitmap) &&
@@ -617,7 +556,6 @@ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info)
snd_seq_prioq_remove_events(q->tickq, client, info);
snd_seq_prioq_remove_events(q->timeq, client, info);
}
- queuefree(q);
}
}
@@ -704,7 +642,7 @@ static void snd_seq_queue_process_event(struct snd_seq_queue *q,
*/
int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop)
{
- struct snd_seq_queue *q;
+ struct snd_seq_queue *q __free(snd_seq_queue) = NULL;
if (snd_BUG_ON(!ev))
return -EINVAL;
@@ -713,15 +651,12 @@ int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop)
if (q == NULL)
return -EINVAL;
- if (! queue_access_lock(q, ev->source.client)) {
- queuefree(q);
+ if (!queue_access_lock(q, ev->source.client))
return -EPERM;
- }
snd_seq_queue_process_event(q, ev, atomic, hop);
queue_access_unlock(q);
- queuefree(q);
return 0;
}
@@ -734,26 +669,25 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
int i, bpm;
- struct snd_seq_queue *q;
struct snd_seq_timer *tmr;
bool locked;
int owner;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
- q = queueptr(i);
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(i);
if (!q)
continue;
tmr = q->timer;
if (tmr->tempo)
- bpm = 60000000 / tmr->tempo;
+ bpm = (60000 * tmr->tempo_base) / tmr->tempo;
else
bpm = 0;
- spin_lock_irq(&q->owner_lock);
- locked = q->locked;
- owner = q->owner;
- spin_unlock_irq(&q->owner_lock);
+ scoped_guard(spinlock_irq, &q->owner_lock) {
+ locked = q->locked;
+ owner = q->owner;
+ }
snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
snd_iprintf(buffer, "owned by client : %d\n", owner);
@@ -763,11 +697,11 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped");
snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq);
snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo);
+ snd_iprintf(buffer, "tempo base : %d ns\n", tmr->tempo_base);
snd_iprintf(buffer, "current BPM : %d\n", bpm);
snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec);
snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick);
snd_iprintf(buffer, "\n");
- queuefree(q);
}
}
#endif /* CONFIG_SND_PROC_FS */
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index c69105dc1a10..afcd3c5484a6 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -66,7 +66,6 @@ void snd_seq_queue_client_leave(int client);
int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop);
/* Remove events */
-void snd_seq_queue_client_leave_cells(int client);
void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info);
/* return pointer to queue structure for specified id */
@@ -74,6 +73,8 @@ struct snd_seq_queue *queueptr(int queueid);
/* unlock */
#define queuefree(q) snd_use_lock_free(&(q)->use_lock)
+DEFINE_FREE(snd_seq_queue, struct snd_seq_queue *, if (!IS_ERR_OR_NULL(_T)) queuefree(_T))
+
/* return the (first) queue matching with the specified name */
struct snd_seq_queue *snd_seq_queue_find_name(char *name);
@@ -84,7 +85,6 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop);
int snd_seq_queue_check_access(int queueid, int client);
int snd_seq_queue_timer_set_tempo(int queueid, int client, struct snd_seq_queue_tempo *info);
int snd_seq_queue_set_owner(int queueid, int client, int locked);
-int snd_seq_queue_set_locked(int queueid, int client, int locked);
int snd_seq_queue_timer_open(int queueid);
int snd_seq_queue_timer_close(int queueid);
int snd_seq_queue_use(int queueid, int client, int use);
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c
index 32c2d9b57751..5b5603e5970b 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,25 +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 */
@@ -103,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)
{
@@ -126,7 +146,7 @@ int __init snd_seq_system_client_init(void)
}
/* register timer */
- strcpy(port->name, "Timer");
+ strscpy(port->name, "Timer");
port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
port->kernel = &pcallbacks;
@@ -140,9 +160,12 @@ int __init snd_seq_system_client_init(void)
goto error_port;
/* register announcement port */
- strcpy(port->name, "Announce");
+ strscpy(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_timer.c b/sound/core/seq/seq_timer.c
index 9863be6fd43e..29b018a212fc 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -20,14 +20,17 @@
static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
{
- if (tmr->tempo < 1000000)
- tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
+ unsigned int threshold =
+ tmr->tempo_base == 1000 ? 1000000 : 10000;
+
+ if (tmr->tempo < threshold)
+ tmr->tick.resolution = (tmr->tempo * tmr->tempo_base) / tmr->ppq;
else {
/* might overflow.. */
unsigned int s;
s = tmr->tempo % tmr->ppq;
- s = (s * 1000) / tmr->ppq;
- tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
+ s = (s * tmr->tempo_base) / tmr->ppq;
+ tmr->tick.resolution = (tmr->tempo / tmr->ppq) * tmr->tempo_base;
tmr->tick.resolution += s;
}
if (tmr->tick.resolution <= 0)
@@ -75,12 +78,11 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
/* setup defaults */
tmr->ppq = 96; /* 96 PPQ */
tmr->tempo = 500000; /* 120 BPM */
+ tmr->tempo_base = 1000; /* 1us */
snd_seq_timer_set_tick_resolution(tmr);
tmr->running = 0;
@@ -93,7 +95,6 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
tmr->preferred_resolution = seq_default_timer_resolution;
tmr->skew = tmr->skew_base = SKEW_BASE;
- spin_unlock_irqrestore(&tmr->lock, flags);
}
static void seq_timer_reset(struct snd_seq_timer *tmr)
@@ -108,11 +109,8 @@ static void seq_timer_reset(struct snd_seq_timer *tmr)
void snd_seq_timer_reset(struct snd_seq_timer *tmr)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
seq_timer_reset(tmr);
- spin_unlock_irqrestore(&tmr->lock, flags);
}
@@ -121,7 +119,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
unsigned long resolution,
unsigned long ticks)
{
- unsigned long flags;
struct snd_seq_queue *q = timeri->callback_data;
struct snd_seq_timer *tmr;
@@ -130,29 +127,27 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
tmr = q->timer;
if (tmr == NULL)
return;
- spin_lock_irqsave(&tmr->lock, flags);
- if (!tmr->running) {
- spin_unlock_irqrestore(&tmr->lock, flags);
- return;
- }
- resolution *= ticks;
- if (tmr->skew != tmr->skew_base) {
- /* FIXME: assuming skew_base = 0x10000 */
- resolution = (resolution >> 16) * tmr->skew +
- (((resolution & 0xffff) * tmr->skew) >> 16);
- }
+ scoped_guard(spinlock_irqsave, &tmr->lock) {
+ if (!tmr->running)
+ return;
- /* update timer */
- snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
+ resolution *= ticks;
+ if (tmr->skew != tmr->skew_base) {
+ /* FIXME: assuming skew_base = 0x10000 */
+ resolution = (resolution >> 16) * tmr->skew +
+ (((resolution & 0xffff) * tmr->skew) >> 16);
+ }
- /* calculate current tick */
- snd_seq_timer_update_tick(&tmr->tick, resolution);
+ /* update timer */
+ snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
- /* register actual time of this timer update */
- ktime_get_ts64(&tmr->last_update);
+ /* calculate current tick */
+ snd_seq_timer_update_tick(&tmr->tick, resolution);
- spin_unlock_irqrestore(&tmr->lock, flags);
+ /* register actual time of this timer update */
+ ktime_get_ts64(&tmr->last_update);
+ }
/* check queues and dispatch events */
snd_seq_check_queue(q, 1, 0);
@@ -161,45 +156,44 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
/* set current tempo */
int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
{
- unsigned long flags;
-
if (snd_BUG_ON(!tmr))
return -EINVAL;
if (tempo <= 0)
return -EINVAL;
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
if ((unsigned int)tempo != tmr->tempo) {
tmr->tempo = tempo;
snd_seq_timer_set_tick_resolution(tmr);
}
- spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
-/* set current tempo and ppq in a shot */
-int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
+/* set current tempo, ppq and base in a shot */
+int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
+ unsigned int tempo_base)
{
int changed;
- unsigned long flags;
if (snd_BUG_ON(!tmr))
return -EINVAL;
if (tempo <= 0 || ppq <= 0)
return -EINVAL;
- spin_lock_irqsave(&tmr->lock, flags);
+ /* allow only 10ns or 1us tempo base for now */
+ if (tempo_base && tempo_base != 10 && tempo_base != 1000)
+ return -EINVAL;
+ guard(spinlock_irqsave)(&tmr->lock);
if (tmr->running && (ppq != tmr->ppq)) {
/* refuse to change ppq on running timers */
/* because it will upset the song position (ticks) */
- spin_unlock_irqrestore(&tmr->lock, flags);
pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
return -EBUSY;
}
changed = (tempo != tmr->tempo) || (ppq != tmr->ppq);
tmr->tempo = tempo;
tmr->ppq = ppq;
+ tmr->tempo_base = tempo_base ? tempo_base : 1000;
if (changed)
snd_seq_timer_set_tick_resolution(tmr);
- spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@@ -207,15 +201,12 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
snd_seq_tick_time_t position)
{
- unsigned long flags;
-
if (snd_BUG_ON(!tmr))
return -EINVAL;
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
tmr->tick.cur_tick = position;
tmr->tick.fraction = 0;
- spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@@ -223,15 +214,12 @@ int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
snd_seq_real_time_t position)
{
- unsigned long flags;
-
if (snd_BUG_ON(!tmr))
return -EINVAL;
snd_seq_sanity_real_time(&position);
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
tmr->cur_time = position;
- spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@@ -239,8 +227,6 @@ int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
unsigned int base)
{
- unsigned long flags;
-
if (snd_BUG_ON(!tmr))
return -EINVAL;
@@ -249,9 +235,8 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
return -EINVAL;
}
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
tmr->skew = skew;
- spin_unlock_irqrestore(&tmr->lock, flags);
return 0;
}
@@ -296,12 +281,12 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
snd_timer_instance_free(t);
return err;
}
- spin_lock_irq(&tmr->lock);
- if (tmr->timeri)
- err = -EBUSY;
- else
- tmr->timeri = t;
- spin_unlock_irq(&tmr->lock);
+ scoped_guard(spinlock_irq, &tmr->lock) {
+ if (tmr->timeri)
+ err = -EBUSY;
+ else
+ tmr->timeri = t;
+ }
if (err < 0) {
snd_timer_close(t);
snd_timer_instance_free(t);
@@ -318,10 +303,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
tmr = q->timer;
if (snd_BUG_ON(!tmr))
return -EINVAL;
- spin_lock_irq(&tmr->lock);
- t = tmr->timeri;
- tmr->timeri = NULL;
- spin_unlock_irq(&tmr->lock);
+ scoped_guard(spinlock_irq, &tmr->lock) {
+ t = tmr->timeri;
+ tmr->timeri = NULL;
+ }
if (t) {
snd_timer_close(t);
snd_timer_instance_free(t);
@@ -342,13 +327,8 @@ static int seq_timer_stop(struct snd_seq_timer *tmr)
int snd_seq_timer_stop(struct snd_seq_timer *tmr)
{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&tmr->lock, flags);
- err = seq_timer_stop(tmr);
- spin_unlock_irqrestore(&tmr->lock, flags);
- return err;
+ guard(spinlock_irqsave)(&tmr->lock);
+ return seq_timer_stop(tmr);
}
static int initialize_timer(struct snd_seq_timer *tmr)
@@ -398,13 +378,8 @@ static int seq_timer_start(struct snd_seq_timer *tmr)
int snd_seq_timer_start(struct snd_seq_timer *tmr)
{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&tmr->lock, flags);
- err = seq_timer_start(tmr);
- spin_unlock_irqrestore(&tmr->lock, flags);
- return err;
+ guard(spinlock_irqsave)(&tmr->lock);
+ return seq_timer_start(tmr);
}
static int seq_timer_continue(struct snd_seq_timer *tmr)
@@ -426,13 +401,8 @@ static int seq_timer_continue(struct snd_seq_timer *tmr)
int snd_seq_timer_continue(struct snd_seq_timer *tmr)
{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&tmr->lock, flags);
- err = seq_timer_continue(tmr);
- spin_unlock_irqrestore(&tmr->lock, flags);
- return err;
+ guard(spinlock_irqsave)(&tmr->lock);
+ return seq_timer_continue(tmr);
}
/* return current 'real' time. use timeofday() to get better granularity. */
@@ -440,9 +410,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
bool adjust_ktime)
{
snd_seq_real_time_t cur_time;
- unsigned long flags;
- spin_lock_irqsave(&tmr->lock, flags);
+ guard(spinlock_irqsave)(&tmr->lock);
cur_time = tmr->cur_time;
if (adjust_ktime && tmr->running) {
struct timespec64 tm;
@@ -453,7 +422,6 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
cur_time.tv_sec += tm.tv_sec;
snd_seq_sanity_real_time(&cur_time);
}
- spin_unlock_irqrestore(&tmr->lock, flags);
return cur_time;
}
@@ -461,13 +429,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
high PPQ values) */
snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
{
- snd_seq_tick_time_t cur_tick;
- unsigned long flags;
-
- spin_lock_irqsave(&tmr->lock, flags);
- cur_tick = tmr->tick.cur_tick;
- spin_unlock_irqrestore(&tmr->lock, flags);
- return cur_tick;
+ guard(spinlock_irqsave)(&tmr->lock);
+ return tmr->tick.cur_tick;
}
@@ -477,29 +440,27 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
int idx;
- struct snd_seq_queue *q;
struct snd_seq_timer *tmr;
struct snd_timer_instance *ti;
unsigned long resolution;
for (idx = 0; idx < SNDRV_SEQ_MAX_QUEUES; idx++) {
- q = queueptr(idx);
+ struct snd_seq_queue *q __free(snd_seq_queue) = queueptr(idx);
+
if (q == NULL)
continue;
- mutex_lock(&q->timer_mutex);
- tmr = q->timer;
- if (!tmr)
- goto unlock;
- ti = tmr->timeri;
- if (!ti)
- goto unlock;
- snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
- resolution = snd_timer_resolution(ti) * tmr->ticks;
- snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
- snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
-unlock:
- mutex_unlock(&q->timer_mutex);
- queuefree(q);
+ scoped_guard(mutex, &q->timer_mutex) {
+ tmr = q->timer;
+ if (!tmr)
+ break;
+ ti = tmr->timeri;
+ if (!ti)
+ break;
+ snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
+ resolution = snd_timer_resolution(ti) * tmr->ticks;
+ snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
+ snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
+ }
}
}
#endif /* CONFIG_SND_PROC_FS */
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h
index 4bec57df8158..c8803216a3a4 100644
--- a/sound/core/seq/seq_timer.h
+++ b/sound/core/seq/seq_timer.h
@@ -36,6 +36,7 @@ struct snd_seq_timer {
unsigned int skew;
unsigned int skew_base;
+ unsigned int tempo_base;
struct timespec64 last_update; /* time of last clock update, used for interpolation */
@@ -108,15 +109,14 @@ static inline void snd_seq_inc_time_nsec(snd_seq_real_time_t *tm, unsigned long
struct snd_seq_queue;
int snd_seq_timer_open(struct snd_seq_queue *q);
int snd_seq_timer_close(struct snd_seq_queue *q);
-int snd_seq_timer_midi_open(struct snd_seq_queue *q);
-int snd_seq_timer_midi_close(struct snd_seq_queue *q);
void snd_seq_timer_defaults(struct snd_seq_timer *tmr);
void snd_seq_timer_reset(struct snd_seq_timer *tmr);
int snd_seq_timer_stop(struct snd_seq_timer *tmr);
int snd_seq_timer_start(struct snd_seq_timer *tmr);
int snd_seq_timer_continue(struct snd_seq_timer *tmr);
int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo);
-int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq);
+int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
+ unsigned int tempo_base);
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
new file mode 100644
index 000000000000..27247babb16d
--- /dev/null
+++ b/sound/core/seq/seq_ump_client.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* ALSA sequencer binding for UMP device */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/byteorder.h>
+#include <sound/core.h>
+#include <sound/ump.h>
+#include <sound/seq_kernel.h>
+#include <sound/seq_device.h>
+#include "seq_clientmgr.h"
+#include "seq_system.h"
+
+struct seq_ump_client;
+struct seq_ump_group;
+
+enum {
+ STR_IN = SNDRV_RAWMIDI_STREAM_INPUT,
+ STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT
+};
+
+/* context for UMP input parsing, per EP */
+struct seq_ump_input_buffer {
+ unsigned char len; /* total length in words */
+ unsigned char pending; /* pending words */
+ unsigned char type; /* parsed UMP packet type */
+ unsigned char group; /* parsed UMP packet group */
+ u32 buf[4]; /* incoming UMP packet */
+};
+
+/* sequencer client, per UMP EP (rawmidi) */
+struct seq_ump_client {
+ struct snd_ump_endpoint *ump; /* assigned endpoint */
+ int seq_client; /* sequencer client id */
+ int opened[2]; /* current opens for each direction */
+ struct snd_rawmidi_file out_rfile; /* rawmidi for output */
+ struct seq_ump_input_buffer input; /* input parser context */
+ void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
+ struct work_struct group_notify_work; /* FB change notification */
+};
+
+/* number of 32bit words for each UMP message type */
+static unsigned char ump_packet_words[0x10] = {
+ 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4
+};
+
+/* conversion between UMP group and seq port;
+ * assume the port number is equal with UMP group number (1-based)
+ */
+static unsigned char ump_group_to_seq_port(unsigned char group)
+{
+ return group + 1;
+}
+
+/* process the incoming rawmidi stream */
+static void seq_ump_input_receive(struct snd_ump_endpoint *ump,
+ const u32 *val, int words)
+{
+ struct seq_ump_client *client = ump->seq_client;
+ struct snd_seq_ump_event ev = {};
+
+ if (!client->opened[STR_IN])
+ return;
+
+ if (ump_is_groupless_msg(ump_message_type(*val)))
+ ev.source.port = 0; /* UMP EP port */
+ else
+ ev.source.port = ump_group_to_seq_port(ump_message_group(*val));
+ ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
+ ev.flags = SNDRV_SEQ_EVENT_UMP;
+ memcpy(ev.ump, val, words << 2);
+ snd_seq_kernel_client_dispatch(client->seq_client,
+ (struct snd_seq_event *)&ev,
+ true, 0);
+}
+
+/* process an input sequencer event; only deal with UMP types */
+static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
+ void *private_data, int atomic, int hop)
+{
+ struct seq_ump_client *client = private_data;
+ struct snd_rawmidi_substream *substream;
+ struct snd_seq_ump_event *ump_ev;
+ unsigned char type;
+ int len;
+
+ substream = client->out_rfile.output;
+ if (!substream)
+ return -ENODEV;
+ if (!snd_seq_ev_is_ump(ev))
+ return 0; /* invalid event, skip */
+ ump_ev = (struct snd_seq_ump_event *)ev;
+ type = ump_message_type(ump_ev->ump[0]);
+ len = ump_packet_words[type];
+ if (len > 4)
+ return 0; // invalid - skip
+ snd_rawmidi_kernel_write(substream, ev->data.raw8.d, len << 2);
+ return 0;
+}
+
+/* open the rawmidi */
+static int seq_ump_client_open(struct seq_ump_client *client, int dir)
+{
+ struct snd_ump_endpoint *ump = client->ump;
+ int err;
+
+ guard(mutex)(&ump->open_mutex);
+ if (dir == STR_OUT && !client->opened[dir]) {
+ err = snd_rawmidi_kernel_open(&ump->core, 0,
+ SNDRV_RAWMIDI_LFLG_OUTPUT |
+ SNDRV_RAWMIDI_LFLG_APPEND,
+ &client->out_rfile);
+ if (err < 0)
+ return err;
+ }
+ client->opened[dir]++;
+ return 0;
+}
+
+/* close the rawmidi */
+static int seq_ump_client_close(struct seq_ump_client *client, int dir)
+{
+ struct snd_ump_endpoint *ump = client->ump;
+
+ guard(mutex)(&ump->open_mutex);
+ if (!--client->opened[dir])
+ if (dir == STR_OUT)
+ snd_rawmidi_kernel_release(&client->out_rfile);
+ return 0;
+}
+
+/* sequencer subscription ops for each client */
+static int seq_ump_subscribe(void *pdata, struct snd_seq_port_subscribe *info)
+{
+ struct seq_ump_client *client = pdata;
+
+ return seq_ump_client_open(client, STR_IN);
+}
+
+static int seq_ump_unsubscribe(void *pdata, struct snd_seq_port_subscribe *info)
+{
+ struct seq_ump_client *client = pdata;
+
+ return seq_ump_client_close(client, STR_IN);
+}
+
+static int seq_ump_use(void *pdata, struct snd_seq_port_subscribe *info)
+{
+ struct seq_ump_client *client = pdata;
+
+ return seq_ump_client_open(client, STR_OUT);
+}
+
+static int seq_ump_unuse(void *pdata, struct snd_seq_port_subscribe *info)
+{
+ struct seq_ump_client *client = pdata;
+
+ return seq_ump_client_close(client, STR_OUT);
+}
+
+/* fill port_info from the given UMP EP and group info */
+static void fill_port_info(struct snd_seq_port_info *port,
+ struct seq_ump_client *client,
+ struct snd_ump_group *group)
+{
+ unsigned int rawmidi_info = client->ump->core.info_flags;
+
+ port->addr.client = client->seq_client;
+ port->addr.port = ump_group_to_seq_port(group->group);
+ port->capability = 0;
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT)
+ port->capability |= SNDRV_SEQ_PORT_CAP_WRITE |
+ SNDRV_SEQ_PORT_CAP_SYNC_WRITE |
+ SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT)
+ port->capability |= SNDRV_SEQ_PORT_CAP_READ |
+ SNDRV_SEQ_PORT_CAP_SYNC_READ |
+ SNDRV_SEQ_PORT_CAP_SUBS_READ;
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX)
+ port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+ if (group->dir_bits & (1 << STR_IN))
+ port->direction |= SNDRV_SEQ_PORT_DIR_INPUT;
+ if (group->dir_bits & (1 << STR_OUT))
+ port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT;
+ port->ump_group = group->group + 1;
+ if (!group->active)
+ port->capability |= SNDRV_SEQ_PORT_CAP_INACTIVE;
+ if (group->is_midi1)
+ port->flags |= SNDRV_SEQ_PORT_FLG_IS_MIDI1;
+ port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
+ SNDRV_SEQ_PORT_TYPE_MIDI_UMP |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_PORT;
+ port->midi_channels = 16;
+ if (*group->name)
+ snprintf(port->name, sizeof(port->name), "Group %d (%.53s)",
+ group->group + 1, group->name);
+ else
+ sprintf(port->name, "Group %d", group->group + 1);
+}
+
+/* skip non-existing group for static blocks */
+static bool skip_group(struct seq_ump_client *client, struct snd_ump_group *group)
+{
+ return !group->valid &&
+ (client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS);
+}
+
+/* create a new sequencer port per UMP group */
+static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
+{
+ struct snd_ump_group *group = &client->ump->groups[group_index];
+ struct snd_seq_port_info *port __free(kfree) = NULL;
+ struct snd_seq_port_callback pcallbacks;
+
+ if (skip_group(client, group))
+ return 0;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ fill_port_info(port, client, group);
+ port->flags |= SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
+ memset(&pcallbacks, 0, sizeof(pcallbacks));
+ pcallbacks.owner = THIS_MODULE;
+ pcallbacks.private_data = client;
+ pcallbacks.subscribe = seq_ump_subscribe;
+ pcallbacks.unsubscribe = seq_ump_unsubscribe;
+ pcallbacks.use = seq_ump_use;
+ pcallbacks.unuse = seq_ump_unuse;
+ pcallbacks.event_input = seq_ump_process_event;
+ port->kernel = &pcallbacks;
+ return snd_seq_kernel_client_ctl(client->seq_client,
+ SNDRV_SEQ_IOCTL_CREATE_PORT,
+ port);
+}
+
+/* update the sequencer ports; called from notify_fb_change callback */
+static void update_port_infos(struct seq_ump_client *client)
+{
+ struct snd_seq_port_info *old __free(kfree) = NULL;
+ struct snd_seq_port_info *new __free(kfree) = NULL;
+ int i, err;
+
+ old = kzalloc(sizeof(*old), GFP_KERNEL);
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!old || !new)
+ return;
+
+ for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
+ if (skip_group(client, &client->ump->groups[i]))
+ continue;
+
+ old->addr.client = client->seq_client;
+ old->addr.port = ump_group_to_seq_port(i);
+ err = snd_seq_kernel_client_ctl(client->seq_client,
+ SNDRV_SEQ_IOCTL_GET_PORT_INFO,
+ old);
+ if (err < 0)
+ continue;
+ fill_port_info(new, client, &client->ump->groups[i]);
+ if (old->capability == new->capability &&
+ !strcmp(old->name, new->name))
+ continue;
+ err = snd_seq_kernel_client_ctl(client->seq_client,
+ SNDRV_SEQ_IOCTL_SET_PORT_INFO,
+ new);
+ if (err < 0)
+ continue;
+ }
+}
+
+/* create a UMP Endpoint port */
+static int create_ump_endpoint_port(struct seq_ump_client *client)
+{
+ struct snd_seq_port_info *port __free(kfree) = NULL;
+ struct snd_seq_port_callback pcallbacks;
+ unsigned int rawmidi_info = client->ump->core.info_flags;
+ int err;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->addr.client = client->seq_client;
+ port->addr.port = 0; /* fixed */
+ port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
+ port->capability = SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT;
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) {
+ port->capability |= SNDRV_SEQ_PORT_CAP_READ |
+ SNDRV_SEQ_PORT_CAP_SYNC_READ |
+ SNDRV_SEQ_PORT_CAP_SUBS_READ;
+ port->direction |= SNDRV_SEQ_PORT_DIR_INPUT;
+ }
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) {
+ port->capability |= SNDRV_SEQ_PORT_CAP_WRITE |
+ SNDRV_SEQ_PORT_CAP_SYNC_WRITE |
+ SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
+ port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT;
+ }
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX)
+ port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+ port->ump_group = 0; /* no associated group, no conversion */
+ port->type = SNDRV_SEQ_PORT_TYPE_MIDI_UMP |
+ SNDRV_SEQ_PORT_TYPE_HARDWARE |
+ SNDRV_SEQ_PORT_TYPE_PORT;
+ port->midi_channels = 16;
+ strscpy(port->name, "MIDI 2.0");
+ memset(&pcallbacks, 0, sizeof(pcallbacks));
+ pcallbacks.owner = THIS_MODULE;
+ pcallbacks.private_data = client;
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) {
+ pcallbacks.subscribe = seq_ump_subscribe;
+ pcallbacks.unsubscribe = seq_ump_unsubscribe;
+ }
+ if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) {
+ pcallbacks.use = seq_ump_use;
+ pcallbacks.unuse = seq_ump_unuse;
+ pcallbacks.event_input = seq_ump_process_event;
+ }
+ port->kernel = &pcallbacks;
+ err = snd_seq_kernel_client_ctl(client->seq_client,
+ SNDRV_SEQ_IOCTL_CREATE_PORT,
+ port);
+ return err;
+}
+
+/* release the client resources */
+static void seq_ump_client_free(struct seq_ump_client *client)
+{
+ cancel_work_sync(&client->group_notify_work);
+
+ if (client->seq_client >= 0)
+ snd_seq_delete_kernel_client(client->seq_client);
+
+ client->ump->seq_ops = NULL;
+ client->ump->seq_client = NULL;
+
+ kfree(client);
+}
+
+/* update the MIDI version for the given client */
+static void setup_client_midi_version(struct seq_ump_client *client)
+{
+ struct snd_seq_client *cptr;
+
+ cptr = snd_seq_kernel_client_get(client->seq_client);
+ if (!cptr)
+ return;
+ if (client->ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
+ cptr->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_2_0;
+ else
+ cptr->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_1_0;
+ snd_seq_kernel_client_put(cptr);
+}
+
+/* set up client's group_filter bitmap */
+static void setup_client_group_filter(struct seq_ump_client *client)
+{
+ struct snd_seq_client *cptr;
+ unsigned int filter;
+ int p;
+
+ cptr = snd_seq_kernel_client_get(client->seq_client);
+ if (!cptr)
+ return;
+ filter = ~(1U << 0); /* always allow groupless messages */
+ for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
+ if (client->ump->groups[p].active)
+ filter &= ~(1U << (p + 1));
+ }
+ cptr->group_filter = filter;
+ snd_seq_kernel_client_put(cptr);
+}
+
+/* UMP group change notification */
+static void handle_group_notify(struct work_struct *work)
+{
+ struct seq_ump_client *client =
+ container_of(work, struct seq_ump_client, group_notify_work);
+
+ update_port_infos(client);
+ 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)
+{
+ struct seq_ump_client *client = ump->seq_client;
+
+ 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)
+{
+ struct seq_ump_client *client = ump->seq_client;
+
+ if (!client)
+ return -ENODEV;
+ 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,
+};
+
+/* create a sequencer client and ports for the given UMP endpoint */
+static int snd_seq_ump_probe(struct device *_dev)
+{
+ struct snd_seq_device *dev = to_seq_dev(_dev);
+ struct snd_ump_endpoint *ump = dev->private_data;
+ struct snd_card *card = dev->card;
+ struct seq_ump_client *client;
+ struct snd_ump_block *fb;
+ struct snd_seq_client *cptr;
+ int p, err;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+
+ INIT_WORK(&client->group_notify_work, handle_group_notify);
+ client->ump = ump;
+
+ client->seq_client =
+ snd_seq_create_kernel_client(card, ump->core.device,
+ ump->core.name);
+ if (client->seq_client < 0) {
+ err = client->seq_client;
+ goto error;
+ }
+
+ client->ump_info[0] = &ump->info;
+ list_for_each_entry(fb, &ump->block_list, list)
+ client->ump_info[fb->info.block_id + 1] = &fb->info;
+
+ setup_client_midi_version(client);
+
+ for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
+ err = seq_ump_group_init(client, p);
+ if (err < 0)
+ goto error;
+ }
+
+ setup_client_group_filter(client);
+
+ err = create_ump_endpoint_port(client);
+ if (err < 0)
+ goto error;
+
+ cptr = snd_seq_kernel_client_get(client->seq_client);
+ if (!cptr) {
+ err = -EINVAL;
+ goto error;
+ }
+ cptr->ump_info = client->ump_info;
+ snd_seq_kernel_client_put(cptr);
+
+ ump->seq_client = client;
+ ump->seq_ops = &seq_ump_ops;
+ return 0;
+
+ error:
+ seq_ump_client_free(client);
+ return err;
+}
+
+/* remove a sequencer client */
+static int snd_seq_ump_remove(struct device *_dev)
+{
+ struct snd_seq_device *dev = to_seq_dev(_dev);
+ struct snd_ump_endpoint *ump = dev->private_data;
+
+ if (ump->seq_client)
+ seq_ump_client_free(ump->seq_client);
+ return 0;
+}
+
+static struct snd_seq_driver seq_ump_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .probe = snd_seq_ump_probe,
+ .remove = snd_seq_ump_remove,
+ },
+ .id = SNDRV_SEQ_DEV_ID_UMP,
+ .argsize = 0,
+};
+
+module_snd_seq_driver(seq_ump_driver);
+
+MODULE_DESCRIPTION("ALSA sequencer client for UMP rawmidi");
+MODULE_LICENSE("GPL");
diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c
new file mode 100644
index 000000000000..db2f169cae11
--- /dev/null
+++ b/sound/core/seq/seq_ump_convert.c
@@ -0,0 +1,1305 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ALSA sequencer event conversion between UMP and legacy clients
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <sound/core.h>
+#include <sound/ump.h>
+#include <sound/ump_msg.h>
+#include "seq_ump_convert.h"
+
+/*
+ * Upgrade / downgrade value bits
+ */
+static u8 downscale_32_to_7bit(u32 src)
+{
+ return src >> 25;
+}
+
+static u16 downscale_32_to_14bit(u32 src)
+{
+ return src >> 18;
+}
+
+static u8 downscale_16_to_7bit(u16 src)
+{
+ return src >> 9;
+}
+
+static u16 upscale_7_to_16bit(u8 src)
+{
+ u16 val, repeat;
+
+ val = (u16)src << 9;
+ if (src <= 0x40)
+ return val;
+ repeat = src & 0x3f;
+ return val | (repeat << 3) | (repeat >> 3);
+}
+
+static u32 upscale_7_to_32bit(u8 src)
+{
+ u32 val, repeat;
+
+ val = src << 25;
+ if (src <= 0x40)
+ return val;
+ repeat = src & 0x3f;
+ return val | (repeat << 19) | (repeat << 13) |
+ (repeat << 7) | (repeat << 1) | (repeat >> 5);
+}
+
+static u32 upscale_14_to_32bit(u16 src)
+{
+ u32 val, repeat;
+
+ val = src << 18;
+ if (src <= 0x2000)
+ return val;
+ repeat = src & 0x1fff;
+ return val | (repeat << 5) | (repeat >> 8);
+}
+
+static unsigned char get_ump_group(struct snd_seq_client_port *port)
+{
+ return port->ump_group ? (port->ump_group - 1) : 0;
+}
+
+/* create a UMP header */
+#define make_raw_ump(port, type) \
+ ump_compose(type, get_ump_group(port), 0, 0)
+
+/*
+ * UMP -> MIDI1 sequencer event
+ */
+
+/* MIDI 1.0 CVM */
+
+/* encode note event */
+static void ump_midi1_to_note_ev(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.note.channel = val->note.channel;
+ ev->data.note.note = val->note.note;
+ ev->data.note.velocity = val->note.velocity;
+}
+
+/* encode one parameter controls */
+static void ump_midi1_to_ctrl_ev(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->caf.channel;
+ ev->data.control.value = val->caf.data;
+}
+
+/* encode pitch wheel change */
+static void ump_midi1_to_pitchbend_ev(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->pb.channel;
+ ev->data.control.value = (val->pb.data_msb << 7) | val->pb.data_lsb;
+ ev->data.control.value -= 8192;
+}
+
+/* encode midi control change */
+static void ump_midi1_to_cc_ev(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->cc.channel;
+ ev->data.control.param = val->cc.index;
+ ev->data.control.value = val->cc.data;
+}
+
+/* Encoding MIDI 1.0 UMP packet */
+struct seq_ump_midi1_to_ev {
+ int seq_type;
+ void (*encode)(const union snd_ump_midi1_msg *val, struct snd_seq_event *ev);
+};
+
+/* Encoders for MIDI1 status 0x80-0xe0 */
+static struct seq_ump_midi1_to_ev midi1_msg_encoders[] = {
+ {SNDRV_SEQ_EVENT_NOTEOFF, ump_midi1_to_note_ev}, /* 0x80 */
+ {SNDRV_SEQ_EVENT_NOTEON, ump_midi1_to_note_ev}, /* 0x90 */
+ {SNDRV_SEQ_EVENT_KEYPRESS, ump_midi1_to_note_ev}, /* 0xa0 */
+ {SNDRV_SEQ_EVENT_CONTROLLER, ump_midi1_to_cc_ev}, /* 0xb0 */
+ {SNDRV_SEQ_EVENT_PGMCHANGE, ump_midi1_to_ctrl_ev}, /* 0xc0 */
+ {SNDRV_SEQ_EVENT_CHANPRESS, ump_midi1_to_ctrl_ev}, /* 0xd0 */
+ {SNDRV_SEQ_EVENT_PITCHBEND, ump_midi1_to_pitchbend_ev}, /* 0xe0 */
+};
+
+static int cvt_ump_midi1_to_event(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ unsigned char status = val->note.status;
+
+ if (status < 0x8 || status > 0xe)
+ return 0; /* invalid - skip */
+ status -= 8;
+ ev->type = midi1_msg_encoders[status].seq_type;
+ ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
+ midi1_msg_encoders[status].encode(val, ev);
+ return 1;
+}
+
+/* MIDI System message */
+
+/* encode one parameter value*/
+static void ump_system_to_one_param_ev(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.value = val->system.parm1;
+}
+
+/* encode song position */
+static void ump_system_to_songpos_ev(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.value = (val->system.parm2 << 7) | val->system.parm1;
+}
+
+/* Encoders for 0xf0 - 0xff */
+static struct seq_ump_midi1_to_ev system_msg_encoders[] = {
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf0 */
+ {SNDRV_SEQ_EVENT_QFRAME, ump_system_to_one_param_ev}, /* 0xf1 */
+ {SNDRV_SEQ_EVENT_SONGPOS, ump_system_to_songpos_ev}, /* 0xf2 */
+ {SNDRV_SEQ_EVENT_SONGSEL, ump_system_to_one_param_ev}, /* 0xf3 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf4 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf5 */
+ {SNDRV_SEQ_EVENT_TUNE_REQUEST, NULL}, /* 0xf6 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf7 */
+ {SNDRV_SEQ_EVENT_CLOCK, NULL}, /* 0xf8 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf9 */
+ {SNDRV_SEQ_EVENT_START, NULL}, /* 0xfa */
+ {SNDRV_SEQ_EVENT_CONTINUE, NULL}, /* 0xfb */
+ {SNDRV_SEQ_EVENT_STOP, NULL}, /* 0xfc */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xfd */
+ {SNDRV_SEQ_EVENT_SENSING, NULL}, /* 0xfe */
+ {SNDRV_SEQ_EVENT_RESET, NULL}, /* 0xff */
+};
+
+static int cvt_ump_system_to_event(const union snd_ump_midi1_msg *val,
+ struct snd_seq_event *ev)
+{
+ unsigned char status = val->system.status;
+
+ if ((status & 0xf0) != UMP_MIDI1_MSG_REALTIME)
+ return 0; /* invalid status - skip */
+ status &= 0x0f;
+ ev->type = system_msg_encoders[status].seq_type;
+ ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
+ if (ev->type == SNDRV_SEQ_EVENT_NONE)
+ return 0;
+ if (system_msg_encoders[status].encode)
+ system_msg_encoders[status].encode(val, ev);
+ return 1;
+}
+
+/* MIDI 2.0 CVM */
+
+/* encode note event */
+static int ump_midi2_to_note_ev(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.note.channel = val->note.channel;
+ ev->data.note.note = val->note.note;
+ ev->data.note.velocity = downscale_16_to_7bit(val->note.velocity);
+ /* correct note-on velocity 0 to 1;
+ * it's no longer equivalent as not-off for MIDI 2.0
+ */
+ if (ev->type == SNDRV_SEQ_EVENT_NOTEON &&
+ !ev->data.note.velocity)
+ ev->data.note.velocity = 1;
+ return 1;
+}
+
+/* encode pitch wheel change */
+static int ump_midi2_to_pitchbend_ev(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->pb.channel;
+ ev->data.control.value = downscale_32_to_14bit(val->pb.data);
+ ev->data.control.value -= 8192;
+ return 1;
+}
+
+/* encode midi control change */
+static int ump_midi2_to_cc_ev(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->cc.channel;
+ ev->data.control.param = val->cc.index;
+ ev->data.control.value = downscale_32_to_7bit(val->cc.data);
+ return 1;
+}
+
+/* encode midi program change */
+static int ump_midi2_to_pgm_ev(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ int size = 1;
+
+ ev->data.control.channel = val->pg.channel;
+ if (val->pg.bank_valid) {
+ ev->type = SNDRV_SEQ_EVENT_CONTROL14;
+ ev->data.control.param = UMP_CC_BANK_SELECT;
+ ev->data.control.value = (val->pg.bank_msb << 7) | val->pg.bank_lsb;
+ ev[1] = ev[0];
+ ev++;
+ ev->type = SNDRV_SEQ_EVENT_PGMCHANGE;
+ size = 2;
+ }
+ ev->data.control.value = val->pg.program;
+ return size;
+}
+
+/* encode one parameter controls */
+static int ump_midi2_to_ctrl_ev(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->caf.channel;
+ ev->data.control.value = downscale_32_to_7bit(val->caf.data);
+ return 1;
+}
+
+/* encode RPN/NRPN */
+static int ump_midi2_to_rpn_ev(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ ev->data.control.channel = val->rpn.channel;
+ ev->data.control.param = (val->rpn.bank << 7) | val->rpn.index;
+ ev->data.control.value = downscale_32_to_14bit(val->rpn.data);
+ return 1;
+}
+
+/* Encoding MIDI 2.0 UMP Packet */
+struct seq_ump_midi2_to_ev {
+ int seq_type;
+ int (*encode)(const union snd_ump_midi2_msg *val, struct snd_seq_event *ev);
+};
+
+/* Encoders for MIDI2 status 0x00-0xf0 */
+static struct seq_ump_midi2_to_ev midi2_msg_encoders[] = {
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x00 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x10 */
+ {SNDRV_SEQ_EVENT_REGPARAM, ump_midi2_to_rpn_ev}, /* 0x20 */
+ {SNDRV_SEQ_EVENT_NONREGPARAM, ump_midi2_to_rpn_ev}, /* 0x30 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x40 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x50 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x60 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x70 */
+ {SNDRV_SEQ_EVENT_NOTEOFF, ump_midi2_to_note_ev}, /* 0x80 */
+ {SNDRV_SEQ_EVENT_NOTEON, ump_midi2_to_note_ev}, /* 0x90 */
+ {SNDRV_SEQ_EVENT_KEYPRESS, ump_midi2_to_note_ev}, /* 0xa0 */
+ {SNDRV_SEQ_EVENT_CONTROLLER, ump_midi2_to_cc_ev}, /* 0xb0 */
+ {SNDRV_SEQ_EVENT_PGMCHANGE, ump_midi2_to_pgm_ev}, /* 0xc0 */
+ {SNDRV_SEQ_EVENT_CHANPRESS, ump_midi2_to_ctrl_ev}, /* 0xd0 */
+ {SNDRV_SEQ_EVENT_PITCHBEND, ump_midi2_to_pitchbend_ev}, /* 0xe0 */
+ {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf0 */
+};
+
+static int cvt_ump_midi2_to_event(const union snd_ump_midi2_msg *val,
+ struct snd_seq_event *ev)
+{
+ unsigned char status = val->note.status;
+
+ ev->type = midi2_msg_encoders[status].seq_type;
+ if (ev->type == SNDRV_SEQ_EVENT_NONE)
+ return 0; /* skip */
+ ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
+ return midi2_msg_encoders[status].encode(val, ev);
+}
+
+/* parse and compose for a sysex var-length event */
+static int cvt_ump_sysex7_to_event(const u32 *data, unsigned char *buf,
+ struct snd_seq_event *ev)
+{
+ unsigned char status;
+ unsigned char bytes;
+ u32 val;
+ int size = 0;
+
+ val = data[0];
+ status = ump_sysex_message_status(val);
+ bytes = ump_sysex_message_length(val);
+ if (bytes > 6)
+ return 0; // skip
+
+ if (status == UMP_SYSEX_STATUS_SINGLE ||
+ status == UMP_SYSEX_STATUS_START) {
+ buf[0] = UMP_MIDI1_MSG_SYSEX_START;
+ size = 1;
+ }
+
+ if (bytes > 0)
+ buf[size++] = (val >> 8) & 0x7f;
+ if (bytes > 1)
+ buf[size++] = val & 0x7f;
+ val = data[1];
+ if (bytes > 2)
+ buf[size++] = (val >> 24) & 0x7f;
+ if (bytes > 3)
+ buf[size++] = (val >> 16) & 0x7f;
+ if (bytes > 4)
+ buf[size++] = (val >> 8) & 0x7f;
+ if (bytes > 5)
+ buf[size++] = val & 0x7f;
+
+ if (status == UMP_SYSEX_STATUS_SINGLE ||
+ status == UMP_SYSEX_STATUS_END)
+ buf[size++] = UMP_MIDI1_MSG_SYSEX_END;
+
+ ev->type = SNDRV_SEQ_EVENT_SYSEX;
+ ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
+ ev->data.ext.len = size;
+ ev->data.ext.ptr = buf;
+ return 1;
+}
+
+/* convert UMP packet from MIDI 1.0 to MIDI 2.0 and deliver it */
+static int cvt_ump_midi1_to_midi2(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *__event,
+ int atomic, int hop)
+{
+ struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event;
+ struct snd_seq_ump_event ev_cvt;
+ const union snd_ump_midi1_msg *midi1 = (const union snd_ump_midi1_msg *)event->ump;
+ union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)ev_cvt.ump;
+ struct ump_cvt_to_ump_bank *cc;
+
+ ev_cvt = *event;
+ memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump));
+
+ midi2->note.type = UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE;
+ midi2->note.group = midi1->note.group;
+ midi2->note.status = midi1->note.status;
+ midi2->note.channel = midi1->note.channel;
+ switch (midi1->note.status) {
+ case UMP_MSG_STATUS_NOTE_ON:
+ case UMP_MSG_STATUS_NOTE_OFF:
+ midi2->note.note = midi1->note.note;
+ midi2->note.velocity = upscale_7_to_16bit(midi1->note.velocity);
+ break;
+ case UMP_MSG_STATUS_POLY_PRESSURE:
+ midi2->paf.note = midi1->paf.note;
+ midi2->paf.data = upscale_7_to_32bit(midi1->paf.data);
+ break;
+ case UMP_MSG_STATUS_CC:
+ cc = &dest_port->midi2_bank[midi1->note.channel];
+ switch (midi1->cc.index) {
+ case UMP_CC_BANK_SELECT:
+ cc->bank_set = 1;
+ cc->cc_bank_msb = midi1->cc.data;
+ return 0; // skip
+ case UMP_CC_BANK_SELECT_LSB:
+ cc->bank_set = 1;
+ cc->cc_bank_lsb = midi1->cc.data;
+ return 0; // skip
+ }
+ midi2->cc.index = midi1->cc.index;
+ midi2->cc.data = upscale_7_to_32bit(midi1->cc.data);
+ break;
+ case UMP_MSG_STATUS_PROGRAM:
+ midi2->pg.program = midi1->pg.program;
+ cc = &dest_port->midi2_bank[midi1->note.channel];
+ if (cc->bank_set) {
+ midi2->pg.bank_valid = 1;
+ midi2->pg.bank_msb = cc->cc_bank_msb;
+ midi2->pg.bank_lsb = cc->cc_bank_lsb;
+ cc->bank_set = 0;
+ }
+ break;
+ case UMP_MSG_STATUS_CHANNEL_PRESSURE:
+ midi2->caf.data = upscale_7_to_32bit(midi1->caf.data);
+ break;
+ case UMP_MSG_STATUS_PITCH_BEND:
+ midi2->pb.data = upscale_14_to_32bit((midi1->pb.data_msb << 7) |
+ midi1->pb.data_lsb);
+ break;
+ default:
+ return 0;
+ }
+
+ return __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+}
+
+/* convert UMP packet from MIDI 2.0 to MIDI 1.0 and deliver it */
+static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *__event,
+ int atomic, int hop)
+{
+ struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event;
+ struct snd_seq_ump_event ev_cvt;
+ union snd_ump_midi1_msg *midi1 = (union snd_ump_midi1_msg *)ev_cvt.ump;
+ const union snd_ump_midi2_msg *midi2 = (const union snd_ump_midi2_msg *)event->ump;
+ int err;
+ u16 v;
+
+ ev_cvt = *event;
+ memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump));
+
+ midi1->note.type = UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE;
+ midi1->note.group = midi2->note.group;
+ midi1->note.status = midi2->note.status;
+ midi1->note.channel = midi2->note.channel;
+ switch (midi2->note.status) {
+ case UMP_MSG_STATUS_NOTE_ON:
+ case UMP_MSG_STATUS_NOTE_OFF:
+ midi1->note.note = midi2->note.note;
+ midi1->note.velocity = downscale_16_to_7bit(midi2->note.velocity);
+ break;
+ case UMP_MSG_STATUS_POLY_PRESSURE:
+ midi1->paf.note = midi2->paf.note;
+ midi1->paf.data = downscale_32_to_7bit(midi2->paf.data);
+ break;
+ case UMP_MSG_STATUS_CC:
+ midi1->cc.index = midi2->cc.index;
+ midi1->cc.data = downscale_32_to_7bit(midi2->cc.data);
+ break;
+ case UMP_MSG_STATUS_PROGRAM:
+ if (midi2->pg.bank_valid) {
+ midi1->cc.status = UMP_MSG_STATUS_CC;
+ midi1->cc.index = UMP_CC_BANK_SELECT;
+ midi1->cc.data = midi2->pg.bank_msb;
+ err = __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+ if (err < 0)
+ return err;
+ midi1->cc.index = UMP_CC_BANK_SELECT_LSB;
+ midi1->cc.data = midi2->pg.bank_lsb;
+ err = __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+ if (err < 0)
+ return err;
+ midi1->note.status = midi2->note.status;
+ }
+ midi1->pg.program = midi2->pg.program;
+ break;
+ case UMP_MSG_STATUS_CHANNEL_PRESSURE:
+ midi1->caf.data = downscale_32_to_7bit(midi2->caf.data);
+ break;
+ case UMP_MSG_STATUS_PITCH_BEND:
+ v = downscale_32_to_14bit(midi2->pb.data);
+ midi1->pb.data_msb = v >> 7;
+ midi1->pb.data_lsb = v & 0x7f;
+ break;
+ default:
+ return 0;
+ }
+
+ return __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+}
+
+/* convert UMP to a legacy ALSA seq event and deliver it */
+static int cvt_ump_to_any(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ unsigned char type,
+ int atomic, int hop)
+{
+ struct snd_seq_event ev_cvt[2]; /* up to two events */
+ struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event;
+ /* use the second event as a temp buffer for saving stack usage */
+ unsigned char *sysex_buf = (unsigned char *)(ev_cvt + 1);
+ unsigned char flags = event->flags & ~SNDRV_SEQ_EVENT_UMP;
+ int i, len, err;
+
+ ev_cvt[0] = ev_cvt[1] = *event;
+ ev_cvt[0].flags = flags;
+ ev_cvt[1].flags = flags;
+ switch (type) {
+ case UMP_MSG_TYPE_SYSTEM:
+ len = cvt_ump_system_to_event((union snd_ump_midi1_msg *)ump_ev->ump,
+ ev_cvt);
+ break;
+ case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
+ len = cvt_ump_midi1_to_event((union snd_ump_midi1_msg *)ump_ev->ump,
+ ev_cvt);
+ break;
+ case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
+ len = cvt_ump_midi2_to_event((union snd_ump_midi2_msg *)ump_ev->ump,
+ ev_cvt);
+ break;
+ case UMP_MSG_TYPE_DATA:
+ len = cvt_ump_sysex7_to_event(ump_ev->ump, sysex_buf, ev_cvt);
+ break;
+ default:
+ return 0;
+ }
+
+ for (i = 0; i < len; i++) {
+ err = __snd_seq_deliver_single_event(dest, dest_port,
+ &ev_cvt[i], atomic, hop);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Replace UMP group field with the destination and deliver */
+static int deliver_with_group_convert(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_ump_event *ump_ev,
+ int atomic, int hop)
+{
+ struct snd_seq_ump_event ev = *ump_ev;
+
+ /* rewrite the group to the destination port */
+ ev.ump[0] &= ~(0xfU << 24);
+ /* fill with the new group; the dest_port->ump_group field is 1-based */
+ ev.ump[0] |= ((dest_port->ump_group - 1) << 24);
+
+ return __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev,
+ atomic, hop);
+}
+
+/* apply the UMP event filter; return true to skip the event */
+static bool ump_event_filtered(struct snd_seq_client *dest,
+ const struct snd_seq_ump_event *ev)
+{
+ unsigned char group;
+
+ group = ump_message_group(ev->ump[0]);
+ if (ump_is_groupless_msg(ump_message_type(ev->ump[0])))
+ return dest->group_filter & (1U << 0);
+ /* check the bitmap for 1-based group number */
+ return dest->group_filter & (1U << (group + 1));
+}
+
+/* Convert from UMP packet and deliver */
+int snd_seq_deliver_from_ump(struct snd_seq_client *source,
+ struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event;
+ unsigned char type;
+
+ if (snd_seq_ev_is_variable(event))
+ return 0; // skip, no variable event for UMP, so far
+ if (ump_event_filtered(dest, ump_ev))
+ return 0; // skip if group filter is set and matching
+ type = ump_message_type(ump_ev->ump[0]);
+
+ if (snd_seq_client_is_ump(dest)) {
+ bool is_midi2 = snd_seq_client_is_midi2(dest) &&
+ !dest_port->is_midi1;
+
+ if (is_midi2 && type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE)
+ return cvt_ump_midi1_to_midi2(dest, dest_port,
+ event, atomic, hop);
+ else if (!is_midi2 && type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE)
+ return cvt_ump_midi2_to_midi1(dest, dest_port,
+ event, atomic, hop);
+ /* non-EP port and different group is set? */
+ if (dest_port->ump_group &&
+ !ump_is_groupless_msg(type) &&
+ ump_message_group(*ump_ev->ump) + 1 != dest_port->ump_group)
+ return deliver_with_group_convert(dest, dest_port,
+ ump_ev, atomic, hop);
+ /* copy as-is */
+ return __snd_seq_deliver_single_event(dest, dest_port,
+ event, atomic, hop);
+ }
+
+ return cvt_ump_to_any(dest, dest_port, event, type, atomic, hop);
+}
+
+/*
+ * MIDI1 sequencer event -> UMP conversion
+ */
+
+/* Conversion to UMP MIDI 1.0 */
+
+/* convert note on/off event to MIDI 1.0 UMP */
+static int note_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ if (!event->data.note.velocity)
+ status = UMP_MSG_STATUS_NOTE_OFF;
+ data->note.status = status;
+ data->note.channel = event->data.note.channel & 0x0f;
+ data->note.velocity = event->data.note.velocity & 0x7f;
+ data->note.note = event->data.note.note & 0x7f;
+ return 1;
+}
+
+/* convert CC event to MIDI 1.0 UMP */
+static int cc_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ data->cc.status = status;
+ data->cc.channel = event->data.control.channel & 0x0f;
+ data->cc.index = event->data.control.param;
+ data->cc.data = event->data.control.value;
+ return 1;
+}
+
+/* convert one-parameter control event to MIDI 1.0 UMP */
+static int ctrl_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ data->caf.status = status;
+ data->caf.channel = event->data.control.channel & 0x0f;
+ data->caf.data = event->data.control.value & 0x7f;
+ return 1;
+}
+
+/* convert pitchbend event to MIDI 1.0 UMP */
+static int pitchbend_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ int val = event->data.control.value + 8192;
+
+ val = clamp(val, 0, 0x3fff);
+ data->pb.status = status;
+ data->pb.channel = event->data.control.channel & 0x0f;
+ data->pb.data_msb = (val >> 7) & 0x7f;
+ data->pb.data_lsb = val & 0x7f;
+ return 1;
+}
+
+/* convert 14bit control event to MIDI 1.0 UMP; split to two events */
+static int ctrl14_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ data->cc.status = UMP_MSG_STATUS_CC;
+ data->cc.channel = event->data.control.channel & 0x0f;
+ data->cc.index = event->data.control.param & 0x7f;
+ if (event->data.control.param < 0x20) {
+ data->cc.data = (event->data.control.value >> 7) & 0x7f;
+ data[1] = data[0];
+ data[1].cc.index = event->data.control.param | 0x20;
+ data[1].cc.data = event->data.control.value & 0x7f;
+ return 2;
+ }
+
+ data->cc.data = event->data.control.value & 0x7f;
+ return 1;
+}
+
+/* convert RPN/NRPN event to MIDI 1.0 UMP; split to four events */
+static int rpn_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ bool is_rpn = (status == UMP_MSG_STATUS_RPN);
+
+ data->cc.status = UMP_MSG_STATUS_CC;
+ data->cc.channel = event->data.control.channel & 0x0f;
+ data[1] = data[2] = data[3] = data[0];
+
+ data[0].cc.index = is_rpn ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB;
+ data[0].cc.data = (event->data.control.param >> 7) & 0x7f;
+ data[1].cc.index = is_rpn ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB;
+ data[1].cc.data = event->data.control.param & 0x7f;
+ data[2].cc.index = UMP_CC_DATA;
+ data[2].cc.data = (event->data.control.value >> 7) & 0x7f;
+ data[3].cc.index = UMP_CC_DATA_LSB;
+ data[3].cc.data = event->data.control.value & 0x7f;
+ return 4;
+}
+
+/* convert system / RT message to UMP */
+static int system_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ data->system.type = UMP_MSG_TYPE_SYSTEM; // override
+ data->system.status = status;
+ return 1;
+}
+
+/* convert system / RT message with 1 parameter to UMP */
+static int system_1p_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ data->system.type = UMP_MSG_TYPE_SYSTEM; // override
+ data->system.status = status;
+ data->system.parm1 = event->data.control.value & 0x7f;
+ return 1;
+}
+
+/* convert system / RT message with two parameters to UMP */
+static int system_2p_ev_to_ump_midi1(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status)
+{
+ data->system.type = UMP_MSG_TYPE_SYSTEM; // override
+ data->system.status = status;
+ data->system.parm1 = event->data.control.value & 0x7f;
+ data->system.parm2 = (event->data.control.value >> 7) & 0x7f;
+ return 1;
+}
+
+/* Conversion to UMP MIDI 2.0 */
+
+/* convert note on/off event to MIDI 2.0 UMP */
+static int note_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ if (!event->data.note.velocity)
+ status = UMP_MSG_STATUS_NOTE_OFF;
+ data->note.status = status;
+ data->note.channel = event->data.note.channel & 0x0f;
+ data->note.note = event->data.note.note & 0x7f;
+ data->note.velocity = upscale_7_to_16bit(event->data.note.velocity & 0x7f);
+ return 1;
+}
+
+/* convert PAF event to MIDI 2.0 UMP */
+static int paf_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ data->paf.status = status;
+ data->paf.channel = event->data.note.channel & 0x0f;
+ data->paf.note = event->data.note.note & 0x7f;
+ data->paf.data = upscale_7_to_32bit(event->data.note.velocity & 0x7f);
+ return 1;
+}
+
+static void reset_rpn(struct ump_cvt_to_ump_bank *cc)
+{
+ cc->rpn_set = 0;
+ cc->nrpn_set = 0;
+ cc->cc_rpn_msb = cc->cc_rpn_lsb = 0;
+ cc->cc_data_msb = cc->cc_data_lsb = 0;
+ cc->cc_data_msb_set = cc->cc_data_lsb_set = 0;
+}
+
+/* set up the MIDI2 RPN/NRPN packet data from the parsed info */
+static int fill_rpn(struct ump_cvt_to_ump_bank *cc,
+ union snd_ump_midi2_msg *data,
+ unsigned char channel,
+ bool flush)
+{
+ if (!(cc->cc_data_lsb_set || cc->cc_data_msb_set))
+ return 0; // skip
+ /* when not flushing, wait for complete data set */
+ if (!flush && (!cc->cc_data_lsb_set || !cc->cc_data_msb_set))
+ return 0; // skip
+
+ if (cc->rpn_set) {
+ data->rpn.status = UMP_MSG_STATUS_RPN;
+ data->rpn.bank = cc->cc_rpn_msb;
+ data->rpn.index = cc->cc_rpn_lsb;
+ } else if (cc->nrpn_set) {
+ data->rpn.status = UMP_MSG_STATUS_NRPN;
+ data->rpn.bank = cc->cc_nrpn_msb;
+ data->rpn.index = cc->cc_nrpn_lsb;
+ } else {
+ return 0; // skip
+ }
+
+ data->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) |
+ cc->cc_data_lsb);
+ data->rpn.channel = channel;
+
+ reset_rpn(cc);
+ return 1;
+}
+
+/* convert CC event to MIDI 2.0 UMP */
+static int cc_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ unsigned char channel = event->data.control.channel & 0x0f;
+ unsigned char index = event->data.control.param & 0x7f;
+ unsigned char val = event->data.control.value & 0x7f;
+ struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
+ int ret;
+
+ /* process special CC's (bank/rpn/nrpn) */
+ switch (index) {
+ case UMP_CC_RPN_MSB:
+ ret = fill_rpn(cc, data, channel, true);
+ cc->rpn_set = 1;
+ cc->cc_rpn_msb = val;
+ if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
+ reset_rpn(cc);
+ return ret;
+ case UMP_CC_RPN_LSB:
+ ret = fill_rpn(cc, data, channel, true);
+ cc->rpn_set = 1;
+ cc->cc_rpn_lsb = val;
+ if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
+ reset_rpn(cc);
+ return ret;
+ case UMP_CC_NRPN_MSB:
+ ret = fill_rpn(cc, data, channel, true);
+ cc->nrpn_set = 1;
+ cc->cc_nrpn_msb = val;
+ return ret;
+ case UMP_CC_NRPN_LSB:
+ ret = fill_rpn(cc, data, channel, true);
+ cc->nrpn_set = 1;
+ cc->cc_nrpn_lsb = val;
+ return ret;
+ case UMP_CC_DATA:
+ cc->cc_data_msb_set = 1;
+ cc->cc_data_msb = val;
+ return fill_rpn(cc, data, channel, false);
+ case UMP_CC_BANK_SELECT:
+ cc->bank_set = 1;
+ cc->cc_bank_msb = val;
+ return 0; // skip
+ case UMP_CC_BANK_SELECT_LSB:
+ cc->bank_set = 1;
+ cc->cc_bank_lsb = val;
+ return 0; // skip
+ case UMP_CC_DATA_LSB:
+ cc->cc_data_lsb_set = 1;
+ cc->cc_data_lsb = val;
+ return fill_rpn(cc, data, channel, false);
+ }
+
+ data->cc.status = status;
+ data->cc.channel = channel;
+ data->cc.index = index;
+ data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
+ return 1;
+}
+
+/* convert one-parameter control event to MIDI 2.0 UMP */
+static int ctrl_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ data->caf.status = status;
+ data->caf.channel = event->data.control.channel & 0x0f;
+ data->caf.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
+ return 1;
+}
+
+/* convert program change event to MIDI 2.0 UMP */
+static int pgm_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ unsigned char channel = event->data.control.channel & 0x0f;
+ struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
+
+ data->pg.status = status;
+ data->pg.channel = channel;
+ data->pg.program = event->data.control.value & 0x7f;
+ if (cc->bank_set) {
+ data->pg.bank_valid = 1;
+ data->pg.bank_msb = cc->cc_bank_msb;
+ data->pg.bank_lsb = cc->cc_bank_lsb;
+ cc->bank_set = 0;
+ }
+ return 1;
+}
+
+/* convert pitchbend event to MIDI 2.0 UMP */
+static int pitchbend_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ int val = event->data.control.value + 8192;
+
+ val = clamp(val, 0, 0x3fff);
+ data->pb.status = status;
+ data->pb.channel = event->data.control.channel & 0x0f;
+ data->pb.data = upscale_14_to_32bit(val);
+ return 1;
+}
+
+/* convert 14bit control event to MIDI 2.0 UMP; split to two events */
+static int ctrl14_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ unsigned char channel = event->data.control.channel & 0x0f;
+ unsigned char index = event->data.control.param & 0x7f;
+ struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
+ unsigned char msb, lsb;
+ int ret;
+
+ msb = (event->data.control.value >> 7) & 0x7f;
+ lsb = event->data.control.value & 0x7f;
+ /* process special CC's (bank/rpn/nrpn) */
+ switch (index) {
+ case UMP_CC_BANK_SELECT:
+ cc->cc_bank_msb = msb;
+ fallthrough;
+ case UMP_CC_BANK_SELECT_LSB:
+ cc->bank_set = 1;
+ cc->cc_bank_lsb = lsb;
+ return 0; // skip
+ case UMP_CC_RPN_MSB:
+ case UMP_CC_RPN_LSB:
+ ret = fill_rpn(cc, data, channel, true);
+ cc->cc_rpn_msb = msb;
+ cc->cc_rpn_lsb = lsb;
+ cc->rpn_set = 1;
+ if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
+ reset_rpn(cc);
+ return ret;
+ case UMP_CC_NRPN_MSB:
+ case UMP_CC_NRPN_LSB:
+ ret = fill_rpn(cc, data, channel, true);
+ cc->cc_nrpn_msb = msb;
+ cc->nrpn_set = 1;
+ cc->cc_nrpn_lsb = lsb;
+ return ret;
+ case UMP_CC_DATA:
+ case UMP_CC_DATA_LSB:
+ cc->cc_data_msb_set = cc->cc_data_lsb_set = 1;
+ cc->cc_data_msb = msb;
+ cc->cc_data_lsb = lsb;
+ return fill_rpn(cc, data, channel, false);
+ }
+
+ data->cc.status = UMP_MSG_STATUS_CC;
+ data->cc.channel = channel;
+ data->cc.index = index;
+ if (event->data.control.param < 0x20) {
+ data->cc.data = upscale_7_to_32bit(msb);
+ data[1] = data[0];
+ data[1].cc.index = event->data.control.param | 0x20;
+ data[1].cc.data = upscale_7_to_32bit(lsb);
+ return 2;
+ }
+
+ data->cc.data = upscale_7_to_32bit(lsb);
+ return 1;
+}
+
+/* convert RPN/NRPN event to MIDI 2.0 UMP */
+static int rpn_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ data->rpn.status = status;
+ data->rpn.channel = event->data.control.channel;
+ data->rpn.bank = (event->data.control.param >> 7) & 0x7f;
+ data->rpn.index = event->data.control.param & 0x7f;
+ data->rpn.data = upscale_14_to_32bit(event->data.control.value & 0x3fff);
+ return 1;
+}
+
+/* convert system / RT message to UMP */
+static int system_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ return system_ev_to_ump_midi1(event, dest_port,
+ (union snd_ump_midi1_msg *)data,
+ status);
+}
+
+/* convert system / RT message with 1 parameter to UMP */
+static int system_1p_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ return system_1p_ev_to_ump_midi1(event, dest_port,
+ (union snd_ump_midi1_msg *)data,
+ status);
+}
+
+/* convert system / RT message with two parameters to UMP */
+static int system_2p_ev_to_ump_midi2(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status)
+{
+ return system_2p_ev_to_ump_midi1(event, dest_port,
+ (union snd_ump_midi1_msg *)data,
+ status);
+}
+
+struct seq_ev_to_ump {
+ int seq_type;
+ unsigned char status;
+ int (*midi1_encode)(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi1_msg *data,
+ unsigned char status);
+ int (*midi2_encode)(const struct snd_seq_event *event,
+ struct snd_seq_client_port *dest_port,
+ union snd_ump_midi2_msg *data,
+ unsigned char status);
+};
+
+static const struct seq_ev_to_ump seq_ev_ump_encoders[] = {
+ { SNDRV_SEQ_EVENT_NOTEON, UMP_MSG_STATUS_NOTE_ON,
+ note_ev_to_ump_midi1, note_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_NOTEOFF, UMP_MSG_STATUS_NOTE_OFF,
+ note_ev_to_ump_midi1, note_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_KEYPRESS, UMP_MSG_STATUS_POLY_PRESSURE,
+ note_ev_to_ump_midi1, paf_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_CONTROLLER, UMP_MSG_STATUS_CC,
+ cc_ev_to_ump_midi1, cc_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_PGMCHANGE, UMP_MSG_STATUS_PROGRAM,
+ ctrl_ev_to_ump_midi1, pgm_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_CHANPRESS, UMP_MSG_STATUS_CHANNEL_PRESSURE,
+ ctrl_ev_to_ump_midi1, ctrl_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_PITCHBEND, UMP_MSG_STATUS_PITCH_BEND,
+ pitchbend_ev_to_ump_midi1, pitchbend_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_CONTROL14, 0,
+ ctrl14_ev_to_ump_midi1, ctrl14_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_NONREGPARAM, UMP_MSG_STATUS_NRPN,
+ rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_REGPARAM, UMP_MSG_STATUS_RPN,
+ rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_QFRAME, UMP_SYSTEM_STATUS_MIDI_TIME_CODE,
+ system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_SONGPOS, UMP_SYSTEM_STATUS_SONG_POSITION,
+ system_2p_ev_to_ump_midi1, system_2p_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_SONGSEL, UMP_SYSTEM_STATUS_SONG_SELECT,
+ system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_TUNE_REQUEST, UMP_SYSTEM_STATUS_TUNE_REQUEST,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_CLOCK, UMP_SYSTEM_STATUS_TIMING_CLOCK,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_START, UMP_SYSTEM_STATUS_START,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_CONTINUE, UMP_SYSTEM_STATUS_CONTINUE,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_STOP, UMP_SYSTEM_STATUS_STOP,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_SENSING, UMP_SYSTEM_STATUS_ACTIVE_SENSING,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+ { SNDRV_SEQ_EVENT_RESET, UMP_SYSTEM_STATUS_RESET,
+ system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
+};
+
+static const struct seq_ev_to_ump *find_ump_encoder(int type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(seq_ev_ump_encoders); i++)
+ if (seq_ev_ump_encoders[i].seq_type == type)
+ return &seq_ev_ump_encoders[i];
+
+ return NULL;
+}
+
+static void setup_ump_event(struct snd_seq_ump_event *dest,
+ const struct snd_seq_event *src)
+{
+ memcpy(dest, src, sizeof(*src));
+ dest->type = 0;
+ dest->flags |= SNDRV_SEQ_EVENT_UMP;
+ dest->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
+ memset(dest->ump, 0, sizeof(dest->ump));
+}
+
+/* Convert ALSA seq event to UMP MIDI 1.0 and deliver it */
+static int cvt_to_ump_midi1(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ const struct seq_ev_to_ump *encoder;
+ struct snd_seq_ump_event ev_cvt;
+ union snd_ump_midi1_msg data[4];
+ int i, n, err;
+
+ encoder = find_ump_encoder(event->type);
+ if (!encoder)
+ return __snd_seq_deliver_single_event(dest, dest_port,
+ event, atomic, hop);
+
+ data->raw = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE);
+ n = encoder->midi1_encode(event, dest_port, data, encoder->status);
+ if (!n)
+ return 0;
+
+ setup_ump_event(&ev_cvt, event);
+ for (i = 0; i < n; i++) {
+ ev_cvt.ump[0] = data[i].raw;
+ err = __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Convert ALSA seq event to UMP MIDI 2.0 and deliver it */
+static int cvt_to_ump_midi2(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ const struct seq_ev_to_ump *encoder;
+ struct snd_seq_ump_event ev_cvt;
+ union snd_ump_midi2_msg data[2];
+ int i, n, err;
+
+ encoder = find_ump_encoder(event->type);
+ if (!encoder)
+ return __snd_seq_deliver_single_event(dest, dest_port,
+ event, atomic, hop);
+
+ data->raw[0] = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE);
+ data->raw[1] = 0;
+ n = encoder->midi2_encode(event, dest_port, data, encoder->status);
+ if (!n)
+ return 0;
+
+ setup_ump_event(&ev_cvt, event);
+ for (i = 0; i < n; i++) {
+ memcpy(ev_cvt.ump, &data[i], sizeof(data[i]));
+ err = __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Fill up a sysex7 UMP from the byte stream */
+static void fill_sysex7_ump(struct snd_seq_client_port *dest_port,
+ u32 *val, u8 status, u8 *buf, int len)
+{
+ memset(val, 0, 8);
+ memcpy((u8 *)val + 2, buf, len);
+#ifdef __LITTLE_ENDIAN
+ swab32_array(val, 2);
+#endif
+ val[0] |= ump_compose(UMP_MSG_TYPE_DATA, get_ump_group(dest_port),
+ status, len);
+}
+
+/* Convert sysex var event to UMP sysex7 packets and deliver them */
+static int cvt_sysex_to_ump(struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ struct snd_seq_ump_event ev_cvt;
+ unsigned char status;
+ u8 buf[8], *xbuf;
+ int offset = 0;
+ int len, err;
+ bool finished = false;
+
+ if (!snd_seq_ev_is_variable(event))
+ return 0;
+
+ setup_ump_event(&ev_cvt, event);
+ while (!finished) {
+ len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset);
+ if (len <= 0)
+ break;
+ if (WARN_ON(len > sizeof(buf)))
+ break;
+
+ xbuf = buf;
+ status = UMP_SYSEX_STATUS_CONTINUE;
+ /* truncate the sysex start-marker */
+ if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) {
+ status = UMP_SYSEX_STATUS_START;
+ len--;
+ offset++;
+ xbuf++;
+ }
+
+ /* if the last of this packet or the 1st byte of the next packet
+ * is the end-marker, finish the transfer with this packet
+ */
+ if (len > 0 && len < 8 &&
+ xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
+ if (status == UMP_SYSEX_STATUS_START)
+ status = UMP_SYSEX_STATUS_SINGLE;
+ else
+ status = UMP_SYSEX_STATUS_END;
+ len--;
+ finished = true;
+ }
+
+ len = min(len, 6);
+ fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len);
+ err = __snd_seq_deliver_single_event(dest, dest_port,
+ (struct snd_seq_event *)&ev_cvt,
+ atomic, hop);
+ if (err < 0)
+ return err;
+ offset += len;
+ }
+ return 0;
+}
+
+/* Convert to UMP packet and deliver */
+int snd_seq_deliver_to_ump(struct snd_seq_client *source,
+ struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop)
+{
+ if (dest->group_filter & (1U << dest_port->ump_group))
+ return 0; /* group filtered - skip the event */
+ if (event->type == SNDRV_SEQ_EVENT_SYSEX)
+ return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop);
+ else if (snd_seq_client_is_midi2(dest) && !dest_port->is_midi1)
+ return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop);
+ else
+ return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop);
+}
+
+/* return the UMP group-port number of the event;
+ * return -1 if groupless or non-UMP event
+ */
+int snd_seq_ump_group_port(const struct snd_seq_event *event)
+{
+ const struct snd_seq_ump_event *ump_ev =
+ (const struct snd_seq_ump_event *)event;
+ unsigned char type;
+
+ if (!snd_seq_ev_is_ump(event))
+ return -1;
+ type = ump_message_type(ump_ev->ump[0]);
+ if (ump_is_groupless_msg(type))
+ return -1;
+ /* group-port number starts from 1 */
+ return ump_message_group(ump_ev->ump[0]) + 1;
+}
diff --git a/sound/core/seq/seq_ump_convert.h b/sound/core/seq/seq_ump_convert.h
new file mode 100644
index 000000000000..4abf0a7637d7
--- /dev/null
+++ b/sound/core/seq/seq_ump_convert.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ALSA sequencer event conversion between UMP and legacy clients
+ */
+#ifndef __SEQ_UMP_CONVERT_H
+#define __SEQ_UMP_CONVERT_H
+
+#include "seq_clientmgr.h"
+#include "seq_ports.h"
+
+int snd_seq_deliver_from_ump(struct snd_seq_client *source,
+ struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop);
+int snd_seq_deliver_to_ump(struct snd_seq_client *source,
+ struct snd_seq_client *dest,
+ struct snd_seq_client_port *dest_port,
+ struct snd_seq_event *event,
+ int atomic, int hop);
+int snd_seq_ump_group_port(const struct snd_seq_event *event);
+
+#endif /* __SEQ_UMP_CONVERT_H */
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index f5cae49500c8..9e7fd4993a10 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -62,6 +62,13 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
/*
* decode input event and put to read buffer of each opened file
*/
+
+/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */
+static int dump_to_rawmidi(void *ptr, void *buf, int count)
+{
+ return snd_rawmidi_receive(ptr, buf, count);
+}
+
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
struct snd_seq_event *ev,
bool atomic)
@@ -80,7 +87,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
continue;
- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream);
+ snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
snd_midi_event_reset_decode(vmidi->parser);
} else {
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
@@ -192,11 +199,10 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
vmidi->client = rdev->client;
vmidi->port = rdev->port;
runtime->private_data = vmidi;
- down_write(&rdev->filelist_sem);
- write_lock_irq(&rdev->filelist_lock);
- list_add_tail(&vmidi->list, &rdev->filelist);
- write_unlock_irq(&rdev->filelist_lock);
- up_write(&rdev->filelist_sem);
+ scoped_guard(rwsem_write, &rdev->filelist_sem) {
+ guard(write_lock_irq)(&rdev->filelist_lock);
+ list_add_tail(&vmidi->list, &rdev->filelist);
+ }
vmidi->rdev = rdev;
return 0;
}
@@ -236,11 +242,10 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
struct snd_virmidi *vmidi = substream->runtime->private_data;
- down_write(&rdev->filelist_sem);
- write_lock_irq(&rdev->filelist_lock);
- list_del(&vmidi->list);
- write_unlock_irq(&rdev->filelist_lock);
- up_write(&rdev->filelist_sem);
+ scoped_guard(rwsem_write, &rdev->filelist_sem) {
+ guard(write_lock_irq)(&rdev->filelist_lock);
+ list_del(&vmidi->list);
+ }
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@@ -356,26 +361,22 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
{
int client;
struct snd_seq_port_callback pcallbacks;
- struct snd_seq_port_info *pinfo;
+ struct snd_seq_port_info *pinfo __free(kfree) = NULL;
int err;
if (rdev->client >= 0)
return 0;
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
- if (!pinfo) {
- err = -ENOMEM;
- goto __error;
- }
+ if (!pinfo)
+ return -ENOMEM;
client = snd_seq_create_kernel_client(rdev->card, rdev->device,
"%s %d-%d", rdev->rmidi->name,
rdev->card->number,
rdev->device);
- if (client < 0) {
- err = client;
- goto __error;
- }
+ if (client < 0)
+ return client;
rdev->client = client;
/* create a port */
@@ -385,6 +386,7 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+ pinfo->direction = SNDRV_SEQ_PORT_DIR_BIDIRECTION;
pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
| SNDRV_SEQ_PORT_TYPE_SOFTWARE
| SNDRV_SEQ_PORT_TYPE_PORT;
@@ -402,15 +404,11 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
if (err < 0) {
snd_seq_delete_kernel_client(client);
rdev->client = -1;
- goto __error;
+ return err;
}
rdev->port = pinfo->addr.port;
- err = 0; /* success */
-
- __error:
- kfree(pinfo);
- return err;
+ return 0; /* success */
}
@@ -499,7 +497,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
&rmidi);
if (err < 0)
return err;
- strcpy(rmidi->name, rmidi->id);
+ strscpy(rmidi->name, rmidi->id);
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
if (rdev == NULL) {
snd_device_free(card, rmidi);
diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c
index 7f3fd8eb016f..bac9f8603734 100644
--- a/sound/core/seq_device.c
+++ b/sound/core/seq_device.c
@@ -40,16 +40,16 @@ MODULE_LICENSE("GPL");
/*
* bus definition
*/
-static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
+static int snd_seq_bus_match(struct device *dev, const struct device_driver *drv)
{
struct snd_seq_device *sdev = to_seq_dev(dev);
- struct snd_seq_driver *sdrv = to_seq_drv(drv);
+ const struct snd_seq_driver *sdrv = to_seq_drv(drv);
return strcmp(sdrv->id, sdev->id) == 0 &&
sdrv->argsize == sdev->argsize;
}
-static struct bus_type snd_seq_bus_type = {
+static const struct bus_type snd_seq_bus_type = {
.name = "snd_seq",
.match = snd_seq_bus_match,
};
@@ -234,7 +234,7 @@ int snd_seq_device_new(struct snd_card *card, int device, const char *id,
put_device(&dev->dev);
return err;
}
-
+
if (result)
*result = dev;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index df5571d98629..6531a67f13b3 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -103,7 +103,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
if (minor >= ARRAY_SIZE(snd_minors))
return NULL;
- mutex_lock(&sound_mutex);
+ guard(mutex)(&sound_mutex);
mreg = snd_minors[minor];
if (mreg && mreg->type == type) {
private_data = mreg->private_data;
@@ -111,7 +111,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
get_device(&mreg->card_ptr->card_dev);
} else
private_data = NULL;
- mutex_unlock(&sound_mutex);
return private_data;
}
EXPORT_SYMBOL(snd_lookup_minor_data);
@@ -134,7 +133,7 @@ static struct snd_minor *autoload_device(unsigned int minor)
/* /dev/aloadSEQ */
snd_request_other(minor);
}
- mutex_lock(&sound_mutex); /* reacuire lock */
+ mutex_lock(&sound_mutex); /* reacquire lock */
return snd_minors[minor];
}
#else /* !CONFIG_MODULES */
@@ -150,17 +149,15 @@ static int snd_open(struct inode *inode, struct file *file)
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
- mutex_lock(&sound_mutex);
- mptr = snd_minors[minor];
- if (mptr == NULL) {
- mptr = autoload_device(minor);
- if (!mptr) {
- mutex_unlock(&sound_mutex);
- return -ENODEV;
+ scoped_guard(mutex, &sound_mutex) {
+ mptr = snd_minors[minor];
+ if (mptr == NULL) {
+ mptr = autoload_device(minor);
+ if (!mptr)
+ return -ENODEV;
}
+ new_fops = fops_get(mptr->f_ops);
}
- new_fops = fops_get(mptr->f_ops);
- mutex_unlock(&sound_mutex);
if (!new_fops)
return -ENODEV;
replace_fops(file, new_fops);
@@ -269,7 +266,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
preg->f_ops = f_ops;
preg->private_data = private_data;
preg->card_ptr = card;
- mutex_lock(&sound_mutex);
+ guard(mutex)(&sound_mutex);
minor = snd_find_free_minor(type, card, dev);
if (minor < 0) {
err = minor;
@@ -284,7 +281,6 @@ int snd_register_device(int type, struct snd_card *card, int dev,
snd_minors[minor] = preg;
error:
- mutex_unlock(&sound_mutex);
if (err < 0)
kfree(preg);
return err;
@@ -305,7 +301,7 @@ int snd_unregister_device(struct device *dev)
int minor;
struct snd_minor *preg;
- mutex_lock(&sound_mutex);
+ guard(mutex)(&sound_mutex);
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
preg = snd_minors[minor];
if (preg && preg->dev == dev) {
@@ -315,7 +311,6 @@ int snd_unregister_device(struct device *dev)
break;
}
}
- mutex_unlock(&sound_mutex);
if (minor >= ARRAY_SIZE(snd_minors))
return -ENOENT;
return 0;
@@ -355,7 +350,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
int minor;
struct snd_minor *mptr;
- mutex_lock(&sound_mutex);
+ guard(mutex)(&sound_mutex);
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
mptr = snd_minors[minor];
if (!mptr)
@@ -373,7 +368,6 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
snd_iprintf(buffer, "%3i: : %s\n", minor,
snd_device_type_name(mptr->type));
}
- mutex_unlock(&sound_mutex);
}
int __init snd_minor_info_init(void)
diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c
new file mode 100644
index 000000000000..84e337ecbddd
--- /dev/null
+++ b/sound/core/sound_kunit.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Sound core KUnit test
+ * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
+ */
+
+#include <kunit/test.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#define SILENCE_BUFFER_MAX_FRAMES 260
+#define SILENCE_BUFFER_SIZE (sizeof(u64) * SILENCE_BUFFER_MAX_FRAMES)
+#define SILENCE(...) { __VA_ARGS__ }
+#define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) { \
+ .format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits, \
+ .width = wd, .le = endianness, .sd = signd, .silence = silence_arr, \
+ .name = #fmt, \
+}
+
+#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1)
+#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1
+
+#define VALID_NAME "ValidName"
+#define NAME_W_SPEC_CHARS "In%v@1id name"
+#define NAME_W_SPACE "Test name"
+#define NAME_W_SPACE_REMOVED "Testname"
+
+#define TEST_FIRST_COMPONENT "Component1"
+#define TEST_SECOND_COMPONENT "Component2"
+
+struct snd_format_test_data {
+ snd_pcm_format_t format;
+ int physical_bits;
+ int width;
+ int le;
+ int sd;
+ unsigned char silence[8];
+ unsigned char *name;
+};
+
+struct avail_test_data {
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_uframes_t hw_ptr;
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t expected_avail;
+};
+
+static const struct snd_format_test_data valid_fmt[] = {
+ DEFINE_FORMAT(S8, 8, 8, -1, 1, SILENCE()),
+ DEFINE_FORMAT(U8, 8, 8, -1, 0, SILENCE(0x80)),
+ DEFINE_FORMAT(S16_LE, 16, 16, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S16_BE, 16, 16, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U16_LE, 16, 16, 1, 0, SILENCE(0x00, 0x80)),
+ DEFINE_FORMAT(U16_BE, 16, 16, 0, 0, SILENCE(0x80, 0x00)),
+ DEFINE_FORMAT(S24_LE, 32, 24, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S24_BE, 32, 24, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U24_LE, 32, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
+ DEFINE_FORMAT(U24_BE, 32, 24, 0, 0, SILENCE(0x00, 0x80, 0x00, 0x00)),
+ DEFINE_FORMAT(S32_LE, 32, 32, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S32_BE, 32, 32, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U32_LE, 32, 32, 1, 0, SILENCE(0x00, 0x00, 0x00, 0x80)),
+ DEFINE_FORMAT(U32_BE, 32, 32, 0, 0, SILENCE(0x80, 0x00, 0x00, 0x00)),
+ DEFINE_FORMAT(FLOAT_LE, 32, 32, 1, -1, SILENCE()),
+ DEFINE_FORMAT(FLOAT_BE, 32, 32, 0, -1, SILENCE()),
+ DEFINE_FORMAT(FLOAT64_LE, 64, 64, 1, -1, SILENCE()),
+ DEFINE_FORMAT(FLOAT64_BE, 64, 64, 0, -1, SILENCE()),
+ DEFINE_FORMAT(IEC958_SUBFRAME_LE, 32, 32, 1, -1, SILENCE()),
+ DEFINE_FORMAT(IEC958_SUBFRAME_BE, 32, 32, 0, -1, SILENCE()),
+ DEFINE_FORMAT(MU_LAW, 8, 8, -1, -1, SILENCE(0x7f)),
+ DEFINE_FORMAT(A_LAW, 8, 8, -1, -1, SILENCE(0x55)),
+ DEFINE_FORMAT(IMA_ADPCM, 4, 4, -1, -1, SILENCE()),
+ DEFINE_FORMAT(G723_24, 3, 3, -1, -1, SILENCE()),
+ DEFINE_FORMAT(G723_40, 5, 5, -1, -1, SILENCE()),
+ DEFINE_FORMAT(DSD_U8, 8, 8, 1, 0, SILENCE(0x69)),
+ DEFINE_FORMAT(DSD_U16_LE, 16, 16, 1, 0, SILENCE(0x69, 0x69)),
+ DEFINE_FORMAT(DSD_U32_LE, 32, 32, 1, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
+ DEFINE_FORMAT(DSD_U16_BE, 16, 16, 0, 0, SILENCE(0x69, 0x69)),
+ DEFINE_FORMAT(DSD_U32_BE, 32, 32, 0, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
+ DEFINE_FORMAT(S20_LE, 32, 20, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S20_BE, 32, 20, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U20_LE, 32, 20, 1, 0, SILENCE(0x00, 0x00, 0x08, 0x00)),
+ DEFINE_FORMAT(U20_BE, 32, 20, 0, 0, SILENCE(0x00, 0x08, 0x00, 0x00)),
+ DEFINE_FORMAT(S24_3LE, 24, 24, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S24_3BE, 24, 24, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U24_3LE, 24, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
+ DEFINE_FORMAT(U24_3BE, 24, 24, 0, 0, SILENCE(0x80, 0x00, 0x00)),
+ DEFINE_FORMAT(S20_3LE, 24, 20, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S20_3BE, 24, 20, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U20_3LE, 24, 20, 1, 0, SILENCE(0x00, 0x00, 0x08)),
+ DEFINE_FORMAT(U20_3BE, 24, 20, 0, 0, SILENCE(0x08, 0x00, 0x00)),
+ DEFINE_FORMAT(S18_3LE, 24, 18, 1, 1, SILENCE()),
+ DEFINE_FORMAT(S18_3BE, 24, 18, 0, 1, SILENCE()),
+ DEFINE_FORMAT(U18_3LE, 24, 18, 1, 0, SILENCE(0x00, 0x00, 0x02)),
+ DEFINE_FORMAT(U18_3BE, 24, 18, 0, 0, SILENCE(0x02, 0x00, 0x00)),
+ DEFINE_FORMAT(G723_24_1B, 8, 3, -1, -1, SILENCE()),
+ DEFINE_FORMAT(G723_40_1B, 8, 5, -1, -1, SILENCE()),
+};
+
+static void test_phys_format_size(struct kunit *test)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(valid_fmt[i].format),
+ valid_fmt[i].physical_bits);
+ }
+
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_1), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void test_format_width(struct kunit *test)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_width(valid_fmt[i].format),
+ valid_fmt[i].width);
+ }
+
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void test_format_signed(struct kunit *test)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_signed(valid_fmt[i].format),
+ valid_fmt[i].sd < 0 ? -EINVAL : valid_fmt[i].sd);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_unsigned(valid_fmt[i].format),
+ valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd);
+ }
+
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void test_format_endianness(struct kunit *test)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(valid_fmt[i].format),
+ valid_fmt[i].le < 0 ? -EINVAL : valid_fmt[i].le);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(valid_fmt[i].format),
+ valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le);
+ }
+
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_1), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_2), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_1), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_2), -EINVAL);
+}
+
+static void _test_fill_silence(struct kunit *test, const struct snd_format_test_data *data,
+ u8 *buffer, size_t samples_count)
+{
+ size_t sample_bytes = data->physical_bits >> 3;
+ u32 i;
+
+ KUNIT_ASSERT_EQ(test, snd_pcm_format_set_silence(data->format, buffer, samples_count), 0);
+ for (i = 0; i < samples_count * sample_bytes; i++)
+ KUNIT_EXPECT_EQ(test, buffer[i], data->silence[i % sample_bytes]);
+}
+
+static void test_format_fill_silence(struct kunit *test)
+{
+ static const u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES };
+ u8 *buffer;
+ u32 i, j;
+
+ buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
+
+ for (i = 0; i < ARRAY_SIZE(buf_samples); i++) {
+ for (j = 0; j < ARRAY_SIZE(valid_fmt); j++)
+ _test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]);
+ }
+
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT_1, buffer, 20), -EINVAL);
+ KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0);
+}
+
+static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size)
+{
+ snd_pcm_uframes_t boundary = buffer_size;
+
+ while (boundary * 2 <= 0x7fffffffUL - buffer_size)
+ boundary *= 2;
+ return boundary;
+}
+
+static const struct avail_test_data p_avail_data[] = {
+ /* buf_size + hw_ptr < appl_ptr => avail = buf_size + hw_ptr - appl_ptr + boundary */
+ { 128, 1000, 1129, 1073741824UL - 1 },
+ /*
+ * buf_size + hw_ptr - appl_ptr >= boundary =>
+ * => avail = buf_size + hw_ptr - appl_ptr - boundary
+ */
+ { 128, 1073741824UL, 10, 118 },
+ /* standard case: avail = buf_size + hw_ptr - appl_ptr */
+ { 128, 1000, 1001, 127 },
+};
+
+static void test_playback_avail(struct kunit *test)
+{
+ struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
+ u32 i;
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r);
+
+ r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
+ r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->status);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->control);
+
+ for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) {
+ r->buffer_size = p_avail_data[i].buffer_size;
+ r->boundary = calculate_boundary(r->buffer_size);
+ r->status->hw_ptr = p_avail_data[i].hw_ptr;
+ r->control->appl_ptr = p_avail_data[i].appl_ptr;
+ KUNIT_EXPECT_EQ(test, snd_pcm_playback_avail(r), p_avail_data[i].expected_avail);
+ }
+}
+
+static const struct avail_test_data c_avail_data[] = {
+ /* hw_ptr - appl_ptr < 0 => avail = hw_ptr - appl_ptr + boundary */
+ { 128, 1000, 1001, 1073741824UL - 1 },
+ /* standard case: avail = hw_ptr - appl_ptr */
+ { 128, 1001, 1000, 1 },
+};
+
+static void test_capture_avail(struct kunit *test)
+{
+ struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
+ u32 i;
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r);
+
+ r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
+ r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->status);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->control);
+
+ for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) {
+ r->buffer_size = c_avail_data[i].buffer_size;
+ r->boundary = calculate_boundary(r->buffer_size);
+ r->status->hw_ptr = c_avail_data[i].hw_ptr;
+ r->control->appl_ptr = c_avail_data[i].appl_ptr;
+ KUNIT_EXPECT_EQ(test, snd_pcm_capture_avail(r), c_avail_data[i].expected_avail);
+ }
+}
+
+static void test_card_set_id(struct kunit *test)
+{
+ struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, card);
+
+ snd_card_set_id(card, VALID_NAME);
+ KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME);
+
+ /* clear the first id character so we can set it again */
+ card->id[0] = '\0';
+ snd_card_set_id(card, NAME_W_SPEC_CHARS);
+ KUNIT_EXPECT_STRNEQ(test, card->id, NAME_W_SPEC_CHARS);
+
+ card->id[0] = '\0';
+ snd_card_set_id(card, NAME_W_SPACE);
+ kunit_info(test, "%s", card->id);
+ KUNIT_EXPECT_STREQ(test, card->id, NAME_W_SPACE_REMOVED);
+}
+
+static void test_pcm_format_name(struct kunit *test)
+{
+ u32 i;
+ const char *name;
+
+ for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
+ name = snd_pcm_format_name(valid_fmt[i].format);
+ KUNIT_ASSERT_NOT_NULL_MSG(test, name, "Don't have name for %s", valid_fmt[i].name);
+ KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name);
+ }
+
+ KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_1), "Unknown");
+ KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_2), "Unknown");
+}
+
+static void test_card_add_component(struct kunit *test)
+{
+ struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, card);
+
+ snd_component_add(card, TEST_FIRST_COMPONENT);
+ KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT);
+
+ snd_component_add(card, TEST_SECOND_COMPONENT);
+ KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT " " TEST_SECOND_COMPONENT);
+}
+
+static struct kunit_case sound_utils_cases[] = {
+ KUNIT_CASE(test_phys_format_size),
+ KUNIT_CASE(test_format_width),
+ KUNIT_CASE(test_format_endianness),
+ KUNIT_CASE(test_format_signed),
+ KUNIT_CASE(test_format_fill_silence),
+ KUNIT_CASE(test_playback_avail),
+ KUNIT_CASE(test_capture_avail),
+ KUNIT_CASE(test_card_set_id),
+ KUNIT_CASE(test_pcm_format_name),
+ KUNIT_CASE(test_card_add_component),
+ {},
+};
+
+static struct kunit_suite sound_utils_suite = {
+ .name = "sound-core-test",
+ .test_cases = sound_utils_cases,
+};
+
+kunit_test_suite(sound_utils_suite);
+MODULE_DESCRIPTION("Sound core KUnit test");
+MODULE_AUTHOR("Ivan Orlov");
+MODULE_LICENSE("GPL");
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 2751bf2ff61b..d65cc6fee2e6 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -29,7 +29,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
if (minor >= ARRAY_SIZE(snd_oss_minors))
return NULL;
- mutex_lock(&sound_oss_mutex);
+ guard(mutex)(&sound_oss_mutex);
mreg = snd_oss_minors[minor];
if (mreg && mreg->type == type) {
private_data = mreg->private_data;
@@ -37,7 +37,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
get_device(&mreg->card_ptr->card_dev);
} else
private_data = NULL;
- mutex_unlock(&sound_oss_mutex);
return private_data;
}
EXPORT_SYMBOL(snd_lookup_oss_minor_data);
@@ -106,7 +105,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
preg->f_ops = f_ops;
preg->private_data = private_data;
preg->card_ptr = card;
- mutex_lock(&sound_oss_mutex);
+ guard(mutex)(&sound_oss_mutex);
snd_oss_minors[minor] = preg;
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
switch (minor_unit) {
@@ -130,7 +129,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
goto __end;
snd_oss_minors[track2] = preg;
}
- mutex_unlock(&sound_oss_mutex);
return 0;
__end:
@@ -139,7 +137,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
if (register1 >= 0)
unregister_sound_special(register1);
snd_oss_minors[minor] = NULL;
- mutex_unlock(&sound_oss_mutex);
kfree(preg);
return -EBUSY;
}
@@ -156,12 +153,10 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
return 0;
if (minor < 0)
return minor;
- mutex_lock(&sound_oss_mutex);
+ guard(mutex)(&sound_oss_mutex);
mptr = snd_oss_minors[minor];
- if (mptr == NULL) {
- mutex_unlock(&sound_oss_mutex);
+ if (mptr == NULL)
return -ENOENT;
- }
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
case SNDRV_MINOR_OSS_PCM:
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
@@ -176,7 +171,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
if (track2 >= 0)
snd_oss_minors[track2] = NULL;
snd_oss_minors[minor] = NULL;
- mutex_unlock(&sound_oss_mutex);
/* call unregister_sound_special() outside sound_oss_mutex;
* otherwise may deadlock, as it can trigger the release of a card
@@ -220,7 +214,7 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
int minor;
struct snd_minor *mptr;
- mutex_lock(&sound_oss_mutex);
+ guard(mutex)(&sound_oss_mutex);
for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
mptr = snd_oss_minors[minor];
if (!mptr)
@@ -233,7 +227,6 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "%3i: : %s\n", minor,
snd_oss_device_type_name(mptr->type));
}
- mutex_unlock(&sound_oss_mutex);
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index e08a37c23add..d9fff5c87613 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -13,6 +13,8 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sched/signal.h>
+#include <linux/anon_inodes.h>
+#include <linux/idr.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/control.h>
@@ -109,6 +111,16 @@ struct snd_timer_status64 {
unsigned char reserved[64]; /* reserved */
};
+#ifdef CONFIG_SND_UTIMER
+#define SNDRV_UTIMERS_MAX_COUNT 128
+/* Internal data structure for keeping the state of the userspace-driven timer */
+struct snd_utimer {
+ char *name;
+ struct snd_timer *timer;
+ unsigned int id;
+};
+#endif
+
#define SNDRV_TIMER_IOCTL_STATUS64 _IOR('T', 0x14, struct snd_timer_status64)
/* list of timers */
@@ -224,14 +236,12 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
return -EBUSY;
list_move_tail(&slave->open_list, &master->slave_list_head);
master->timer->num_instances++;
- spin_lock_irq(&slave_active_lock);
- spin_lock(&master->timer->lock);
+ guard(spinlock_irq)(&slave_active_lock);
+ guard(spinlock)(&master->timer->lock);
slave->master = master;
slave->timer = master->timer;
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
list_add_tail(&slave->active_list, &master->slave_active_head);
- spin_unlock(&master->timer->lock);
- spin_unlock_irq(&slave_active_lock);
return 1;
}
@@ -382,6 +392,25 @@ list_added:
}
EXPORT_SYMBOL(snd_timer_open);
+/* remove slave links, called from snd_timer_close_locked() below */
+static void remove_slave_links(struct snd_timer_instance *timeri,
+ struct snd_timer *timer)
+{
+ struct snd_timer_instance *slave, *tmp;
+
+ guard(spinlock_irq)(&slave_active_lock);
+ guard(spinlock)(&timer->lock);
+ timeri->timer = NULL;
+ list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) {
+ list_move_tail(&slave->open_list, &snd_timer_slave_list);
+ timer->num_instances--;
+ slave->master = NULL;
+ slave->timer = NULL;
+ list_del_init(&slave->ack_list);
+ list_del_init(&slave->active_list);
+ }
+}
+
/*
* close a timer instance
* call this with register_mutex down.
@@ -390,12 +419,10 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
struct device **card_devp_to_put)
{
struct snd_timer *timer = timeri->timer;
- struct snd_timer_instance *slave, *tmp;
if (timer) {
- spin_lock_irq(&timer->lock);
+ guard(spinlock_irq)(&timer->lock);
timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
- spin_unlock_irq(&timer->lock);
}
if (!list_empty(&timeri->open_list)) {
@@ -418,21 +445,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
}
spin_unlock_irq(&timer->lock);
- /* remove slave links */
- spin_lock_irq(&slave_active_lock);
- spin_lock(&timer->lock);
- timeri->timer = NULL;
- list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
- open_list) {
- list_move_tail(&slave->open_list, &snd_timer_slave_list);
- timer->num_instances--;
- slave->master = NULL;
- slave->timer = NULL;
- list_del_init(&slave->ack_list);
- list_del_init(&slave->active_list);
- }
- spin_unlock(&timer->lock);
- spin_unlock_irq(&slave_active_lock);
+ remove_slave_links(timeri, timer);
/* slave doesn't need to release timer resources below */
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
@@ -459,9 +472,8 @@ void snd_timer_close(struct snd_timer_instance *timeri)
if (snd_BUG_ON(!timeri))
return;
- mutex_lock(&register_mutex);
- snd_timer_close_locked(timeri, &card_dev_to_put);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_mutex)
+ snd_timer_close_locked(timeri, &card_dev_to_put);
/* put_device() is called after unlock for avoiding deadlock */
if (card_dev_to_put)
put_device(card_dev_to_put);
@@ -480,15 +492,13 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
{
struct snd_timer * timer;
unsigned long ret = 0;
- unsigned long flags;
if (timeri == NULL)
return 0;
timer = timeri->timer;
if (timer) {
- spin_lock_irqsave(&timer->lock, flags);
+ guard(spinlock_irqsave)(&timer->lock);
ret = snd_timer_hw_resolution(timer);
- spin_unlock_irqrestore(&timer->lock, flags);
}
return ret;
}
@@ -532,25 +542,26 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
{
struct snd_timer *timer;
int result;
- unsigned long flags;
timer = timeri->timer;
if (!timer)
return -EINVAL;
- spin_lock_irqsave(&timer->lock, flags);
- if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
- result = -EINVAL;
- goto unlock;
- }
- if (timer->card && timer->card->shutdown) {
- result = -ENODEV;
- goto unlock;
- }
+ guard(spinlock_irqsave)(&timer->lock);
+ if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
+ return -EINVAL;
+ if (timer->card && timer->card->shutdown)
+ return -ENODEV;
if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
- SNDRV_TIMER_IFLG_START)) {
- result = -EBUSY;
- goto unlock;
+ SNDRV_TIMER_IFLG_START))
+ return -EBUSY;
+
+ /* check the actual time for the start tick;
+ * bail out as error if it's way too low (< 100us)
+ */
+ if (start && !(timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
+ if ((u64)snd_timer_hw_resolution(timer) * ticks < 100000)
+ return -EINVAL;
}
if (start)
@@ -577,8 +588,6 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
}
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
SNDRV_TIMER_EVENT_CONTINUE);
- unlock:
- spin_unlock_irqrestore(&timer->lock, flags);
return result;
}
@@ -586,53 +595,38 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
static int snd_timer_start_slave(struct snd_timer_instance *timeri,
bool start)
{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&slave_active_lock, flags);
- if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
- err = -EINVAL;
- goto unlock;
- }
- if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
- err = -EBUSY;
- goto unlock;
- }
+ guard(spinlock_irqsave)(&slave_active_lock);
+ if (timeri->flags & SNDRV_TIMER_IFLG_DEAD)
+ return -EINVAL;
+ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING)
+ return -EBUSY;
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
if (timeri->master && timeri->timer) {
- spin_lock(&timeri->timer->lock);
+ guard(spinlock)(&timeri->timer->lock);
list_add_tail(&timeri->active_list,
&timeri->master->slave_active_head);
snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
SNDRV_TIMER_EVENT_CONTINUE);
- spin_unlock(&timeri->timer->lock);
}
- err = 1; /* delayed start */
- unlock:
- spin_unlock_irqrestore(&slave_active_lock, flags);
- return err;
+ return 1; /* delayed start */
}
/* stop/pause a master timer */
static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
{
struct snd_timer *timer;
- int result = 0;
- unsigned long flags;
timer = timeri->timer;
if (!timer)
return -EINVAL;
- spin_lock_irqsave(&timer->lock, flags);
+ guard(spinlock_irqsave)(&timer->lock);
list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list);
if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
- SNDRV_TIMER_IFLG_START))) {
- result = -EBUSY;
- goto unlock;
- }
+ SNDRV_TIMER_IFLG_START)))
+ return -EBUSY;
if (timer->card && timer->card->shutdown)
- goto unlock;
+ return 0;
if (stop) {
timeri->cticks = timeri->ticks;
timeri->pticks = 0;
@@ -656,30 +650,25 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
SNDRV_TIMER_EVENT_PAUSE);
- unlock:
- spin_unlock_irqrestore(&timer->lock, flags);
- return result;
+ return 0;
}
/* stop/pause a slave timer */
static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
{
- unsigned long flags;
bool running;
- spin_lock_irqsave(&slave_active_lock, flags);
+ guard(spinlock_irqsave)(&slave_active_lock);
running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
if (timeri->timer) {
- spin_lock(&timeri->timer->lock);
+ guard(spinlock)(&timeri->timer->lock);
list_del_init(&timeri->ack_list);
list_del_init(&timeri->active_list);
if (running)
snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
SNDRV_TIMER_EVENT_PAUSE);
- spin_unlock(&timeri->timer->lock);
}
- spin_unlock_irqrestore(&slave_active_lock, flags);
return running ? 0 : -EBUSY;
}
@@ -804,12 +793,9 @@ static void snd_timer_process_callbacks(struct snd_timer *timer,
static void snd_timer_clear_callbacks(struct snd_timer *timer,
struct list_head *head)
{
- unsigned long flags;
-
- spin_lock_irqsave(&timer->lock, flags);
+ guard(spinlock_irqsave)(&timer->lock);
while (!list_empty(head))
list_del_init(head->next);
- spin_unlock_irqrestore(&timer->lock, flags);
}
/*
@@ -819,16 +805,14 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
static void snd_timer_work(struct work_struct *work)
{
struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
- unsigned long flags;
if (timer->card && timer->card->shutdown) {
snd_timer_clear_callbacks(timer, &timer->sack_list_head);
return;
}
- spin_lock_irqsave(&timer->lock, flags);
+ guard(spinlock_irqsave)(&timer->lock);
snd_timer_process_callbacks(timer, &timer->sack_list_head);
- spin_unlock_irqrestore(&timer->lock, flags);
}
/*
@@ -842,8 +826,6 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
struct snd_timer_instance *ti, *ts, *tmp;
unsigned long resolution;
struct list_head *ack_list_head;
- unsigned long flags;
- bool use_work = false;
if (timer == NULL)
return;
@@ -853,7 +835,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
return;
}
- spin_lock_irqsave(&timer->lock, flags);
+ guard(spinlock_irqsave)(&timer->lock);
/* remember the current resolution */
resolution = snd_timer_hw_resolution(timer);
@@ -919,10 +901,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
snd_timer_process_callbacks(timer, &timer->ack_list_head);
/* do we have any slow callbacks? */
- use_work = !list_empty(&timer->sack_list_head);
- spin_unlock_irqrestore(&timer->lock, flags);
-
- if (use_work)
+ if (!list_empty(&timer->sack_list_head))
queue_work(system_highpri_wq, &timer->task_work);
}
EXPORT_SYMBOL(snd_timer_interrupt);
@@ -988,7 +967,7 @@ static int snd_timer_free(struct snd_timer *timer)
if (!timer)
return 0;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
if (! list_empty(&timer->open_list_head)) {
struct list_head *p, *n;
struct snd_timer_instance *ti;
@@ -1000,7 +979,6 @@ static int snd_timer_free(struct snd_timer *timer)
}
}
list_del(&timer->device_list);
- mutex_unlock(&register_mutex);
if (timer->private_free)
timer->private_free(timer);
@@ -1025,7 +1003,7 @@ static int snd_timer_dev_register(struct snd_device *dev)
!timer->hw.resolution && timer->hw.c_resolution == NULL)
return -EINVAL;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
list_for_each_entry(timer1, &snd_timer_list, device_list) {
if (timer1->tmr_class > timer->tmr_class)
break;
@@ -1046,11 +1024,9 @@ static int snd_timer_dev_register(struct snd_device *dev)
if (timer1->tmr_subdevice < timer->tmr_subdevice)
continue;
/* conflicts.. */
- mutex_unlock(&register_mutex);
return -EBUSY;
}
list_add_tail(&timer->device_list, &timer1->device_list);
- mutex_unlock(&register_mutex);
return 0;
}
@@ -1059,20 +1035,18 @@ static int snd_timer_dev_disconnect(struct snd_device *device)
struct snd_timer *timer = device->device_data;
struct snd_timer_instance *ti;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
list_del_init(&timer->device_list);
/* wake up pending sleepers */
list_for_each_entry(ti, &timer->open_list_head, open_list) {
if (ti->disconnect)
ti->disconnect(ti);
}
- mutex_unlock(&register_mutex);
return 0;
}
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
{
- unsigned long flags;
unsigned long resolution = 0;
struct snd_timer_instance *ti, *ts;
@@ -1083,7 +1057,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
event > SNDRV_TIMER_EVENT_MRESUME))
return;
- spin_lock_irqsave(&timer->lock, flags);
+ guard(spinlock_irqsave)(&timer->lock);
if (event == SNDRV_TIMER_EVENT_MSTART ||
event == SNDRV_TIMER_EVENT_MCONTINUE ||
event == SNDRV_TIMER_EVENT_MRESUME)
@@ -1095,7 +1069,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst
if (ts->ccallback)
ts->ccallback(ts, event, tstamp, resolution);
}
- spin_unlock_irqrestore(&timer->lock, flags);
}
EXPORT_SYMBOL(snd_timer_notify);
@@ -1145,8 +1118,8 @@ struct snd_timer_system_private {
static void snd_timer_s_function(struct timer_list *t)
{
- struct snd_timer_system_private *priv = from_timer(priv, t,
- tlist);
+ struct snd_timer_system_private *priv = timer_container_of(priv, t,
+ tlist);
struct snd_timer *timer = priv->snd_timer;
unsigned long jiff = jiffies;
if (time_after(jiff, priv->last_expires))
@@ -1179,7 +1152,7 @@ static int snd_timer_s_stop(struct snd_timer * timer)
unsigned long jiff;
priv = (struct snd_timer_system_private *) timer->private_data;
- del_timer(&priv->tlist);
+ timer_delete(&priv->tlist);
jiff = jiffies;
if (time_before(jiff, priv->last_expires))
timer->sticks = priv->last_expires - jiff;
@@ -1194,14 +1167,14 @@ static int snd_timer_s_close(struct snd_timer *timer)
struct snd_timer_system_private *priv;
priv = (struct snd_timer_system_private *)timer->private_data;
- del_timer_sync(&priv->tlist);
+ timer_delete_sync(&priv->tlist);
return 0;
}
static const struct snd_timer_hardware snd_timer_system =
{
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK,
- .resolution = 1000000000L / HZ,
+ .resolution = NSEC_PER_SEC / HZ,
.ticks = 10000000L,
.close = snd_timer_s_close,
.start = snd_timer_s_start,
@@ -1222,7 +1195,7 @@ static int snd_timer_register_system(void)
err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer);
if (err < 0)
return err;
- strcpy(timer->name, "system timer");
+ strscpy(timer->name, "system timer");
timer->hw = snd_timer_system;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL) {
@@ -1246,8 +1219,9 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
{
struct snd_timer *timer;
struct snd_timer_instance *ti;
+ unsigned long resolution;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
list_for_each_entry(timer, &snd_timer_list, device_list) {
if (timer->card && timer->card->shutdown)
continue;
@@ -1269,10 +1243,12 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
timer->tmr_device, timer->tmr_subdevice);
}
snd_iprintf(buffer, "%s :", timer->name);
- if (timer->hw.resolution)
+ scoped_guard(spinlock_irq, &timer->lock)
+ resolution = snd_timer_hw_resolution(timer);
+ if (resolution)
snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
- timer->hw.resolution / 1000,
- timer->hw.resolution % 1000,
+ resolution / 1000,
+ resolution % 1000,
timer->hw.ticks);
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
@@ -1284,7 +1260,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
SNDRV_TIMER_IFLG_RUNNING))
? "running" : "stopped");
}
- mutex_unlock(&register_mutex);
}
static struct snd_info_entry *snd_timer_proc_entry;
@@ -1325,7 +1300,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
struct snd_timer_read *r;
int prev;
- spin_lock(&tu->qlock);
+ guard(spinlock)(&tu->qlock);
if (tu->qused > 0) {
prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
r = &tu->queue[prev];
@@ -1344,7 +1319,6 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
tu->qused++;
}
__wake:
- spin_unlock(&tu->qlock);
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
wake_up(&tu->qchange_sleep);
}
@@ -1368,7 +1342,6 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
{
struct snd_timer_user *tu = timeri->callback_data;
struct snd_timer_tread64 r1;
- unsigned long flags;
if (event >= SNDRV_TIMER_EVENT_START &&
event <= SNDRV_TIMER_EVENT_PAUSE)
@@ -1380,9 +1353,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
r1.tstamp_sec = tstamp->tv_sec;
r1.tstamp_nsec = tstamp->tv_nsec;
r1.val = resolution;
- spin_lock_irqsave(&tu->qlock, flags);
- snd_timer_user_append_to_tqueue(tu, &r1);
- spin_unlock_irqrestore(&tu->qlock, flags);
+ scoped_guard(spinlock_irqsave, &tu->qlock)
+ snd_timer_user_append_to_tqueue(tu, &r1);
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
wake_up(&tu->qchange_sleep);
}
@@ -1406,51 +1378,48 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
memset(&r1, 0, sizeof(r1));
memset(&tstamp, 0, sizeof(tstamp));
- spin_lock(&tu->qlock);
- if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
- (1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
- spin_unlock(&tu->qlock);
- return;
- }
- if (tu->last_resolution != resolution || ticks > 0) {
- if (timer_tstamp_monotonic)
- ktime_get_ts64(&tstamp);
- else
- ktime_get_real_ts64(&tstamp);
- }
- if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
- tu->last_resolution != resolution) {
- r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
+ scoped_guard(spinlock, &tu->qlock) {
+ if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
+ (1 << SNDRV_TIMER_EVENT_TICK))) == 0)
+ return;
+ if (tu->last_resolution != resolution || ticks > 0) {
+ if (timer_tstamp_monotonic)
+ ktime_get_ts64(&tstamp);
+ else
+ ktime_get_real_ts64(&tstamp);
+ }
+ if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
+ tu->last_resolution != resolution) {
+ r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
+ r1.tstamp_sec = tstamp.tv_sec;
+ r1.tstamp_nsec = tstamp.tv_nsec;
+ r1.val = resolution;
+ snd_timer_user_append_to_tqueue(tu, &r1);
+ tu->last_resolution = resolution;
+ append++;
+ }
+ if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
+ break;
+ if (ticks == 0)
+ break;
+ if (tu->qused > 0) {
+ prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
+ r = &tu->tqueue[prev];
+ if (r->event == SNDRV_TIMER_EVENT_TICK) {
+ r->tstamp_sec = tstamp.tv_sec;
+ r->tstamp_nsec = tstamp.tv_nsec;
+ r->val += ticks;
+ append++;
+ break;
+ }
+ }
+ r1.event = SNDRV_TIMER_EVENT_TICK;
r1.tstamp_sec = tstamp.tv_sec;
r1.tstamp_nsec = tstamp.tv_nsec;
- r1.val = resolution;
+ r1.val = ticks;
snd_timer_user_append_to_tqueue(tu, &r1);
- tu->last_resolution = resolution;
append++;
}
- if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
- goto __wake;
- if (ticks == 0)
- goto __wake;
- if (tu->qused > 0) {
- prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
- r = &tu->tqueue[prev];
- if (r->event == SNDRV_TIMER_EVENT_TICK) {
- r->tstamp_sec = tstamp.tv_sec;
- r->tstamp_nsec = tstamp.tv_nsec;
- r->val += ticks;
- append++;
- goto __wake;
- }
- }
- r1.event = SNDRV_TIMER_EVENT_TICK;
- r1.tstamp_sec = tstamp.tv_sec;
- r1.tstamp_nsec = tstamp.tv_nsec;
- r1.val = ticks;
- snd_timer_user_append_to_tqueue(tu, &r1);
- append++;
- __wake:
- spin_unlock(&tu->qlock);
if (append == 0)
return;
snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
@@ -1472,14 +1441,13 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size)
return -ENOMEM;
}
- spin_lock_irq(&tu->qlock);
+ guard(spinlock_irq)(&tu->qlock);
kfree(tu->queue);
kfree(tu->tqueue);
tu->queue_size = size;
tu->queue = queue;
tu->tqueue = tqueue;
tu->qhead = tu->qtail = tu->qused = 0;
- spin_unlock_irq(&tu->qlock);
return 0;
}
@@ -1515,12 +1483,12 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
if (file->private_data) {
tu = file->private_data;
file->private_data = NULL;
- mutex_lock(&tu->ioctl_lock);
- if (tu->timeri) {
- snd_timer_close(tu->timeri);
- snd_timer_instance_free(tu->timeri);
+ scoped_guard(mutex, &tu->ioctl_lock) {
+ if (tu->timeri) {
+ snd_timer_close(tu->timeri);
+ snd_timer_instance_free(tu->timeri);
+ }
}
- mutex_unlock(&tu->ioctl_lock);
snd_fasync_free(tu->fasync);
kfree(tu->queue);
kfree(tu->tqueue);
@@ -1547,92 +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;
- mutex_lock(&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);
}
}
- mutex_unlock(&register_mutex);
+}
+
+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;
@@ -1641,11 +1614,10 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
static int snd_timer_user_ginfo(struct file *file,
struct snd_timer_ginfo __user *_ginfo)
{
- struct snd_timer_ginfo *ginfo;
+ struct snd_timer_ginfo *ginfo __free(kfree) = NULL;
struct snd_timer_id tid;
struct snd_timer *t;
struct list_head *p;
- int err = 0;
ginfo = memdup_user(_ginfo, sizeof(*ginfo));
if (IS_ERR(ginfo))
@@ -1654,15 +1626,17 @@ static int snd_timer_user_ginfo(struct file *file,
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
- mutex_lock(&register_mutex);
- t = snd_timer_find(&tid);
- if (t != NULL) {
+ 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));
- ginfo->resolution = t->hw.resolution;
+ 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;
@@ -1670,39 +1644,25 @@ static int snd_timer_user_ginfo(struct file *file,
list_for_each(p, &t->open_list_head) {
ginfo->clients++;
}
- } else {
- err = -ENODEV;
}
- mutex_unlock(&register_mutex);
- if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
- err = -EFAULT;
- kfree(ginfo);
- return err;
+ if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
+ return -EFAULT;
+ return 0;
}
static int timer_set_gparams(struct snd_timer_gparams *gparams)
{
struct snd_timer *t;
- int err;
- mutex_lock(&register_mutex);
+ guard(mutex)(&register_mutex);
t = snd_timer_find(&gparams->tid);
- if (!t) {
- err = -ENODEV;
- goto _error;
- }
- if (!list_empty(&t->open_list_head)) {
- err = -EBUSY;
- goto _error;
- }
- if (!t->hw.set_period) {
- err = -ENOSYS;
- goto _error;
- }
- err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
-_error:
- mutex_unlock(&register_mutex);
- return err;
+ if (!t)
+ return -ENODEV;
+ if (!list_empty(&t->open_list_head))
+ return -EBUSY;
+ if (!t->hw.set_period)
+ return -ENOSYS;
+ return t->hw.set_period(t, gparams->period_num, gparams->period_den);
}
static int snd_timer_user_gparams(struct file *file,
@@ -1721,33 +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;
- mutex_lock(&register_mutex);
- t = snd_timer_find(&tid);
- if (t != NULL) {
- spin_lock_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;
}
- spin_unlock_irq(&t->lock);
- } else {
- err = -ENODEV;
}
- mutex_unlock(&register_mutex);
- 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,
@@ -1798,9 +1756,8 @@ static int snd_timer_user_info(struct file *file,
struct snd_timer_info __user *_info)
{
struct snd_timer_user *tu;
- struct snd_timer_info *info;
+ struct snd_timer_info *info __free(kfree) = NULL;
struct snd_timer *t;
- int err = 0;
tu = file->private_data;
if (!tu->timeri)
@@ -1817,11 +1774,11 @@ static int snd_timer_user_info(struct file *file,
info->flags |= SNDRV_TIMER_FLG_SLAVE;
strscpy(info->id, t->id, sizeof(info->id));
strscpy(info->name, t->name, sizeof(info->name));
- info->resolution = t->hw.resolution;
+ scoped_guard(spinlock_irq, &t->lock)
+ info->resolution = snd_timer_hw_resolution(t);
if (copy_to_user(_info, info, sizeof(*_info)))
- err = -EFAULT;
- kfree(info);
- return err;
+ return -EFAULT;
+ return 0;
}
static int snd_timer_user_params(struct file *file,
@@ -1879,45 +1836,47 @@ static int snd_timer_user_params(struct file *file,
goto _end;
}
snd_timer_stop(tu->timeri);
- spin_lock_irq(&t->lock);
- tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
- SNDRV_TIMER_IFLG_EXCLUSIVE|
- SNDRV_TIMER_IFLG_EARLY_EVENT);
- if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
- tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
- if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
- tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
- if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
- tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
- spin_unlock_irq(&t->lock);
+ scoped_guard(spinlock_irq, &t->lock) {
+ tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
+ SNDRV_TIMER_IFLG_EXCLUSIVE|
+ SNDRV_TIMER_IFLG_EARLY_EVENT);
+ if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
+ tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
+ if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
+ tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
+ if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
+ tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
+ }
if (params.queue_size > 0 &&
(unsigned int)tu->queue_size != params.queue_size) {
err = realloc_user_queue(tu, params.queue_size);
if (err < 0)
goto _end;
}
- spin_lock_irq(&tu->qlock);
- tu->qhead = tu->qtail = tu->qused = 0;
- if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
- if (tu->tread) {
- struct snd_timer_tread64 tread;
- memset(&tread, 0, sizeof(tread));
- tread.event = SNDRV_TIMER_EVENT_EARLY;
- tread.tstamp_sec = 0;
- tread.tstamp_nsec = 0;
- tread.val = 0;
- snd_timer_user_append_to_tqueue(tu, &tread);
- } else {
- struct snd_timer_read *r = &tu->queue[0];
- r->resolution = 0;
- r->ticks = 0;
- tu->qused++;
- tu->qtail++;
+ scoped_guard(spinlock_irq, &tu->qlock) {
+ tu->qhead = tu->qtail = tu->qused = 0;
+ if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
+ if (tu->tread) {
+ struct snd_timer_tread64 tread;
+
+ memset(&tread, 0, sizeof(tread));
+ tread.event = SNDRV_TIMER_EVENT_EARLY;
+ tread.tstamp_sec = 0;
+ tread.tstamp_nsec = 0;
+ tread.val = 0;
+ snd_timer_user_append_to_tqueue(tu, &tread);
+ } else {
+ struct snd_timer_read *r = &tu->queue[0];
+
+ r->resolution = 0;
+ r->ticks = 0;
+ tu->qused++;
+ tu->qtail++;
+ }
}
+ tu->filter = params.filter;
+ tu->ticks = params.ticks;
}
- tu->filter = params.filter;
- tu->ticks = params.ticks;
- spin_unlock_irq(&tu->qlock);
err = 0;
_end:
if (copy_to_user(_params, &params, sizeof(params)))
@@ -1940,9 +1899,8 @@ static int snd_timer_user_status32(struct file *file,
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
- spin_lock_irq(&tu->qlock);
- status.queue = tu->qused;
- spin_unlock_irq(&tu->qlock);
+ scoped_guard(spinlock_irq, &tu->qlock)
+ status.queue = tu->qused;
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
@@ -1963,9 +1921,8 @@ static int snd_timer_user_status64(struct file *file,
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
- spin_lock_irq(&tu->qlock);
- status.queue = tu->qused;
- spin_unlock_irq(&tu->qlock);
+ scoped_guard(spinlock_irq, &tu->qlock)
+ status.queue = tu->qused;
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
@@ -2071,6 +2028,217 @@ enum {
SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
};
+#ifdef CONFIG_SND_UTIMER
+/*
+ * Since userspace-driven timers are passed to userspace, we need to have an identifier
+ * which will allow us to use them (basically, the subdevice number of udriven timer).
+ */
+static DEFINE_IDA(snd_utimer_ids);
+
+static void snd_utimer_put_id(struct snd_utimer *utimer)
+{
+ int timer_id = utimer->id;
+
+ snd_BUG_ON(timer_id < 0 || timer_id >= SNDRV_UTIMERS_MAX_COUNT);
+ ida_free(&snd_utimer_ids, timer_id);
+}
+
+static int snd_utimer_take_id(void)
+{
+ return ida_alloc_max(&snd_utimer_ids, SNDRV_UTIMERS_MAX_COUNT - 1, GFP_KERNEL);
+}
+
+static void snd_utimer_free(struct snd_utimer *utimer)
+{
+ snd_timer_free(utimer->timer);
+ snd_utimer_put_id(utimer);
+ kfree(utimer->name);
+ kfree(utimer);
+}
+
+static int snd_utimer_release(struct inode *inode, struct file *file)
+{
+ struct snd_utimer *utimer = (struct snd_utimer *)file->private_data;
+
+ snd_utimer_free(utimer);
+ return 0;
+}
+
+static int snd_utimer_trigger(struct file *file)
+{
+ struct snd_utimer *utimer = (struct snd_utimer *)file->private_data;
+
+ snd_timer_interrupt(utimer->timer, utimer->timer->sticks);
+ return 0;
+}
+
+static long snd_utimer_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
+{
+ switch (ioctl) {
+ case SNDRV_TIMER_IOCTL_TRIGGER:
+ return snd_utimer_trigger(file);
+ }
+
+ return -ENOTTY;
+}
+
+static const struct file_operations snd_utimer_fops = {
+ .llseek = noop_llseek,
+ .release = snd_utimer_release,
+ .unlocked_ioctl = snd_utimer_ioctl,
+};
+
+static int snd_utimer_start(struct snd_timer *t)
+{
+ return 0;
+}
+
+static int snd_utimer_stop(struct snd_timer *t)
+{
+ return 0;
+}
+
+static int snd_utimer_open(struct snd_timer *t)
+{
+ return 0;
+}
+
+static int snd_utimer_close(struct snd_timer *t)
+{
+ return 0;
+}
+
+static const struct snd_timer_hardware timer_hw = {
+ .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
+ .open = snd_utimer_open,
+ .close = snd_utimer_close,
+ .start = snd_utimer_start,
+ .stop = snd_utimer_stop,
+};
+
+static int snd_utimer_create(struct snd_timer_uinfo *utimer_info,
+ struct snd_utimer **r_utimer)
+{
+ struct snd_utimer *utimer;
+ struct snd_timer *timer;
+ struct snd_timer_id tid;
+ int utimer_id;
+ int err = 0;
+
+ if (!utimer_info || utimer_info->resolution == 0)
+ return -EINVAL;
+
+ utimer = kzalloc(sizeof(*utimer), GFP_KERNEL);
+ if (!utimer)
+ return -ENOMEM;
+
+ /* We hold the ioctl lock here so we won't get a race condition when allocating id */
+ utimer_id = snd_utimer_take_id();
+ if (utimer_id < 0) {
+ err = utimer_id;
+ goto err_take_id;
+ }
+
+ utimer->id = utimer_id;
+
+ utimer->name = kasprintf(GFP_KERNEL, "snd-utimer%d", utimer_id);
+ if (!utimer->name) {
+ err = -ENOMEM;
+ goto err_get_name;
+ }
+
+ tid.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
+ tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
+ tid.card = -1;
+ tid.device = SNDRV_TIMER_GLOBAL_UDRIVEN;
+ tid.subdevice = utimer_id;
+
+ err = snd_timer_new(NULL, utimer->name, &tid, &timer);
+ if (err < 0) {
+ pr_err("Can't create userspace-driven timer\n");
+ goto err_timer_new;
+ }
+
+ timer->module = THIS_MODULE;
+ timer->hw = timer_hw;
+ timer->hw.resolution = utimer_info->resolution;
+ timer->hw.ticks = 1;
+ timer->max_instances = MAX_SLAVE_INSTANCES;
+
+ utimer->timer = timer;
+
+ err = snd_timer_global_register(timer);
+ if (err < 0) {
+ pr_err("Can't register a userspace-driven timer\n");
+ goto err_timer_reg;
+ }
+
+ *r_utimer = utimer;
+ return 0;
+
+err_timer_reg:
+ snd_timer_free(timer);
+err_timer_new:
+ kfree(utimer->name);
+err_get_name:
+ snd_utimer_put_id(utimer);
+err_take_id:
+ kfree(utimer);
+
+ return err;
+}
+
+static int snd_utimer_ioctl_create(struct file *file,
+ struct snd_timer_uinfo __user *_utimer_info)
+{
+ struct snd_utimer *utimer;
+ struct snd_timer_uinfo *utimer_info __free(kfree) = NULL;
+ int err, timer_fd;
+
+ utimer_info = memdup_user(_utimer_info, sizeof(*utimer_info));
+ if (IS_ERR(utimer_info))
+ return PTR_ERR(utimer_info);
+
+ err = snd_utimer_create(utimer_info, &utimer);
+ if (err < 0)
+ return err;
+
+ utimer_info->id = utimer->id;
+
+ timer_fd = anon_inode_getfd(utimer->name, &snd_utimer_fops, utimer, O_RDWR | O_CLOEXEC);
+ if (timer_fd < 0) {
+ snd_utimer_free(utimer);
+ return timer_fd;
+ }
+
+ utimer_info->fd = timer_fd;
+
+ err = copy_to_user(_utimer_info, utimer_info, sizeof(*utimer_info));
+ if (err) {
+ /*
+ * "Leak" the fd, as there is nothing we can do about it.
+ * It might have been closed already since anon_inode_getfd
+ * makes it available for userspace.
+ *
+ * We have to rely on the process exit path to do any
+ * necessary cleanup (e.g. releasing the file).
+ */
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+#else
+
+static int snd_utimer_ioctl_create(struct file *file,
+ struct snd_timer_uinfo __user *_utimer_info)
+{
+ return -ENOTTY;
+}
+
+#endif
+
static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
unsigned long arg, bool compat)
{
@@ -2115,6 +2283,8 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
case SNDRV_TIMER_IOCTL_PAUSE:
case SNDRV_TIMER_IOCTL_PAUSE_OLD:
return snd_timer_user_pause(file);
+ case SNDRV_TIMER_IOCTL_CREATE:
+ return snd_utimer_ioctl_create(file, argp);
}
return -ENOTTY;
}
@@ -2123,12 +2293,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct snd_timer_user *tu = file->private_data;
- long ret;
- mutex_lock(&tu->ioctl_lock);
- ret = __snd_timer_user_ioctl(file, cmd, arg, false);
- mutex_unlock(&tu->ioctl_lock);
- return ret;
+ guard(mutex)(&tu->ioctl_lock);
+ return __snd_timer_user_ioctl(file, cmd, arg, false);
}
static int snd_timer_user_fasync(int fd, struct file * file, int on)
@@ -2255,12 +2422,11 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
poll_wait(file, &tu->qchange_sleep, wait);
mask = 0;
- spin_lock_irq(&tu->qlock);
+ guard(spinlock_irq)(&tu->qlock);
if (tu->qused)
mask |= EPOLLIN | EPOLLRDNORM;
if (tu->disconnected)
mask |= EPOLLERR;
- spin_unlock_irq(&tu->qlock);
return mask;
}
@@ -2277,7 +2443,6 @@ static const struct file_operations snd_timer_f_ops =
.read = snd_timer_user_read,
.open = snd_timer_user_open,
.release = snd_timer_user_release,
- .llseek = no_llseek,
.poll = snd_timer_user_poll,
.unlocked_ioctl = snd_timer_user_ioctl,
.compat_ioctl = snd_timer_user_ioctl_compat,
@@ -2293,7 +2458,7 @@ static void snd_timer_free_all(void)
snd_timer_free(timer);
}
-static struct device timer_dev;
+static struct device *timer_dev;
/*
* ENTRY functions
@@ -2303,8 +2468,10 @@ static int __init alsa_timer_init(void)
{
int err;
- snd_device_initialize(&timer_dev, NULL);
- dev_set_name(&timer_dev, "timer");
+ err = snd_device_alloc(&timer_dev, NULL);
+ if (err < 0)
+ return err;
+ dev_set_name(timer_dev, "timer");
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
@@ -2318,7 +2485,7 @@ static int __init alsa_timer_init(void)
}
err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
- &snd_timer_f_ops, NULL, &timer_dev);
+ &snd_timer_f_ops, NULL, timer_dev);
if (err < 0) {
pr_err("ALSA: unable to register timer device (%i)\n", err);
snd_timer_free_all();
@@ -2329,15 +2496,15 @@ static int __init alsa_timer_init(void)
return 0;
put_timer:
- put_device(&timer_dev);
+ put_device(timer_dev);
return err;
}
static void __exit alsa_timer_exit(void)
{
- snd_unregister_device(&timer_dev);
+ snd_unregister_device(timer_dev);
snd_timer_free_all();
- put_device(&timer_dev);
+ put_device(timer_dev);
snd_timer_proc_done();
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index ee973b7b8044..4ae9eaeb5afb 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -115,10 +115,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct snd_timer_user *tu = file->private_data;
- long ret;
- mutex_lock(&tu->ioctl_lock);
- ret = __snd_timer_user_ioctl_compat(file, cmd, arg);
- mutex_unlock(&tu->ioctl_lock);
- return ret;
+ guard(mutex)(&tu->ioctl_lock);
+ return __snd_timer_user_ioctl_compat(file, cmd, arg);
}
diff --git a/sound/core/ump.c b/sound/core/ump.c
new file mode 100644
index 000000000000..8d8681a42ca5
--- /dev/null
+++ b/sound/core/ump.c
@@ -0,0 +1,1394 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal MIDI Packet (UMP) support
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+#include <sound/ump.h>
+#include <sound/ump_convert.h>
+
+#define ump_err(ump, fmt, args...) dev_err((ump)->core.dev, fmt, ##args)
+#define ump_warn(ump, fmt, args...) dev_warn((ump)->core.dev, fmt, ##args)
+#define ump_info(ump, fmt, args...) dev_info((ump)->core.dev, fmt, ##args)
+#define ump_dbg(ump, fmt, args...) dev_dbg((ump)->core.dev, fmt, ##args)
+
+static int snd_ump_dev_register(struct snd_rawmidi *rmidi);
+static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi);
+static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
+ void __user *argp);
+static void snd_ump_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer);
+static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream);
+static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream);
+static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream,
+ int up);
+static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream);
+
+static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
+ const u32 *buf, int size);
+#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
+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,
+ u32 *buffer, int count)
+{
+ return 0;
+}
+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,
+ .ioctl = snd_ump_ioctl,
+ .proc_read = snd_ump_proc_read,
+};
+
+static const struct snd_rawmidi_ops snd_ump_rawmidi_input_ops = {
+ .open = snd_ump_rawmidi_open,
+ .close = snd_ump_rawmidi_close,
+ .trigger = snd_ump_rawmidi_trigger,
+};
+
+static const struct snd_rawmidi_ops snd_ump_rawmidi_output_ops = {
+ .open = snd_ump_rawmidi_open,
+ .close = snd_ump_rawmidi_close,
+ .trigger = snd_ump_rawmidi_trigger,
+ .drain = snd_ump_rawmidi_drain,
+};
+
+static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi)
+{
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
+ struct snd_ump_block *fb;
+
+ while (!list_empty(&ump->block_list)) {
+ fb = list_first_entry(&ump->block_list, struct snd_ump_block,
+ list);
+ list_del(&fb->list);
+ if (fb->private_free)
+ fb->private_free(fb);
+ kfree(fb);
+ }
+
+ if (ump->private_free)
+ ump->private_free(ump);
+
+#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
+ kfree(ump->out_cvts);
+#endif
+}
+
+/**
+ * snd_ump_endpoint_new - create a UMP Endpoint object
+ * @card: the card instance
+ * @id: the id string for rawmidi
+ * @device: the device index for rawmidi
+ * @output: 1 for enabling output
+ * @input: 1 for enabling input
+ * @ump_ret: the pointer to store the new UMP instance
+ *
+ * Creates a new UMP Endpoint object. A UMP Endpoint is tied with one rawmidi
+ * instance with one input and/or one output rawmidi stream (either uni-
+ * or bi-directional). A UMP Endpoint may contain one or multiple UMP Blocks
+ * that consist of one or multiple UMP Groups.
+ *
+ * Use snd_rawmidi_set_ops() to set the operators to the new instance.
+ * Unlike snd_rawmidi_new(), this function sets up the info_flags by itself
+ * depending on the given @output and @input.
+ *
+ * The device has SNDRV_RAWMIDI_INFO_UMP flag set and a different device
+ * file ("umpCxDx") than a standard MIDI 1.x device ("midiCxDx") is
+ * created.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_ump_endpoint_new(struct snd_card *card, char *id, int device,
+ int output, int input,
+ struct snd_ump_endpoint **ump_ret)
+{
+ unsigned int info_flags = SNDRV_RAWMIDI_INFO_UMP;
+ struct snd_ump_endpoint *ump;
+ int err;
+
+ if (input)
+ info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ if (output)
+ info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+ if (input && output)
+ info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ ump = kzalloc(sizeof(*ump), GFP_KERNEL);
+ if (!ump)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&ump->block_list);
+ mutex_init(&ump->open_mutex);
+ init_waitqueue_head(&ump->stream_wait);
+#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
+ spin_lock_init(&ump->legacy_locks[0]);
+ spin_lock_init(&ump->legacy_locks[1]);
+#endif
+ err = snd_rawmidi_init(&ump->core, card, id, device,
+ output, input, info_flags);
+ if (err < 0) {
+ snd_rawmidi_free(&ump->core);
+ return err;
+ }
+
+ ump->info.card = card->number;
+ ump->info.device = device;
+
+ ump->core.private_free = snd_ump_endpoint_free;
+ ump->core.ops = &snd_ump_rawmidi_ops;
+ if (input)
+ snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_ump_rawmidi_input_ops);
+ if (output)
+ snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &snd_ump_rawmidi_output_ops);
+
+ ump_dbg(ump, "Created a UMP EP #%d (%s)\n", device, id);
+ *ump_ret = ump;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ump_endpoint_new);
+
+/*
+ * Device register / unregister hooks;
+ * do nothing, placeholders for avoiding the default rawmidi handling
+ */
+
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+static void snd_ump_dev_seq_free(struct snd_seq_device *device)
+{
+ struct snd_ump_endpoint *ump = device->private_data;
+
+ ump->seq_dev = NULL;
+}
+#endif
+
+static int snd_ump_dev_register(struct snd_rawmidi *rmidi)
+{
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
+ int err;
+
+ err = snd_seq_device_new(ump->core.card, ump->core.device,
+ SNDRV_SEQ_DEV_ID_UMP, 0, &ump->seq_dev);
+ if (err < 0)
+ return err;
+ ump->seq_dev->private_data = ump;
+ ump->seq_dev->private_free = snd_ump_dev_seq_free;
+ snd_device_register(ump->core.card, ump->seq_dev);
+#endif
+ return 0;
+}
+
+static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi)
+{
+ return 0;
+}
+
+static struct snd_ump_block *
+snd_ump_get_block(struct snd_ump_endpoint *ump, unsigned char id)
+{
+ struct snd_ump_block *fb;
+
+ list_for_each_entry(fb, &ump->block_list, list) {
+ if (fb->info.block_id == id)
+ return fb;
+ }
+ return NULL;
+}
+
+/*
+ * rawmidi ops for UMP endpoint
+ */
+static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
+ int dir = substream->stream;
+ int err;
+
+ if (ump->substreams[dir])
+ return -EBUSY;
+ err = ump->ops->open(ump, dir);
+ if (err < 0)
+ return err;
+ ump->substreams[dir] = substream;
+ return 0;
+}
+
+static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
+ int dir = substream->stream;
+
+ ump->substreams[dir] = NULL;
+ ump->ops->close(ump, dir);
+ return 0;
+}
+
+static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
+ int dir = substream->stream;
+
+ ump->ops->trigger(ump, dir, up);
+}
+
+static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
+
+ if (ump->ops->drain)
+ ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT);
+}
+
+/* number of 32bit words per message type */
+static unsigned char ump_packet_words[0x10] = {
+ 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4
+};
+
+/**
+ * snd_ump_receive_ump_val - parse the UMP packet data
+ * @ump: UMP endpoint
+ * @val: UMP packet data
+ *
+ * The data is copied onto ump->input_buf[].
+ * When a full packet is completed, returns the number of words (from 1 to 4).
+ * OTOH, if the packet is incomplete, returns 0.
+ */
+int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val)
+{
+ int words;
+
+ if (!ump->input_pending)
+ ump->input_pending = ump_packet_words[ump_message_type(val)];
+
+ ump->input_buf[ump->input_buf_head++] = val;
+ ump->input_pending--;
+ if (!ump->input_pending) {
+ words = ump->input_buf_head;
+ ump->input_buf_head = 0;
+ return words;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ump_receive_ump_val);
+
+/**
+ * snd_ump_receive - transfer UMP packets from the device
+ * @ump: the UMP endpoint
+ * @buffer: the buffer pointer to transfer
+ * @count: byte size to transfer
+ *
+ * Called from the driver to submit the received UMP packets from the device
+ * to user-space. It's essentially a wrapper of rawmidi_receive().
+ * The data to receive is in CPU-native endianness.
+ */
+int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count)
+{
+ struct snd_rawmidi_substream *substream;
+ const u32 *p = buffer;
+ int n, words = count >> 2;
+
+ while (words--) {
+ n = snd_ump_receive_ump_val(ump, *p++);
+ if (!n)
+ continue;
+ ump_handle_stream_msg(ump, ump->input_buf, n);
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+ if (ump->seq_ops)
+ ump->seq_ops->input_receive(ump, ump->input_buf, n);
+#endif
+ process_legacy_input(ump, ump->input_buf, n);
+ }
+
+ substream = ump->substreams[SNDRV_RAWMIDI_STREAM_INPUT];
+ if (!substream)
+ return 0;
+ return snd_rawmidi_receive(substream, (const char *)buffer, count);
+}
+EXPORT_SYMBOL_GPL(snd_ump_receive);
+
+/**
+ * snd_ump_transmit - transmit UMP packets
+ * @ump: the UMP endpoint
+ * @buffer: the buffer pointer to transfer
+ * @count: byte size to transfer
+ *
+ * Called from the driver to obtain the UMP packets from user-space to the
+ * device. It's essentially a wrapper of rawmidi_transmit().
+ * The data to transmit is in CPU-native endianness.
+ */
+int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count)
+{
+ struct snd_rawmidi_substream *substream =
+ ump->substreams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+ int err;
+
+ if (!substream)
+ return -ENODEV;
+ err = snd_rawmidi_transmit(substream, (char *)buffer, count);
+ /* received either data or an error? */
+ if (err)
+ return err;
+ return process_legacy_output(ump, buffer, count);
+}
+EXPORT_SYMBOL_GPL(snd_ump_transmit);
+
+/**
+ * snd_ump_block_new - Create a UMP block
+ * @ump: UMP object
+ * @blk: block ID number to create
+ * @direction: direction (in/out/bidirection)
+ * @first_group: the first group ID (0-based)
+ * @num_groups: the number of groups in this block
+ * @blk_ret: the pointer to store the resultant block object
+ */
+int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk,
+ unsigned int direction, unsigned int first_group,
+ unsigned int num_groups, struct snd_ump_block **blk_ret)
+{
+ struct snd_ump_block *fb, *p;
+
+ if (blk >= SNDRV_UMP_MAX_BLOCKS)
+ return -EINVAL;
+
+ if (snd_ump_get_block(ump, blk))
+ return -EBUSY;
+
+ fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+ if (!fb)
+ return -ENOMEM;
+
+ fb->ump = ump;
+ fb->info.card = ump->info.card;
+ fb->info.device = ump->info.device;
+ fb->info.block_id = blk;
+ if (blk >= ump->info.num_blocks)
+ ump->info.num_blocks = blk + 1;
+ fb->info.direction = direction;
+ fb->info.active = 1;
+ fb->info.first_group = first_group;
+ fb->info.num_groups = num_groups;
+ /* fill the default name, may be overwritten to a better name */
+ snprintf(fb->info.name, sizeof(fb->info.name), "Group %u-%u",
+ first_group + 1, first_group + num_groups);
+
+ /* put the entry in the ordered list */
+ list_for_each_entry(p, &ump->block_list, list) {
+ if (p->info.block_id > blk) {
+ list_add_tail(&fb->list, &p->list);
+ goto added;
+ }
+ }
+ list_add_tail(&fb->list, &ump->block_list);
+
+ added:
+ ump_dbg(ump, "Created a UMP Block #%d (%s)\n", blk, fb->info.name);
+ *blk_ret = fb;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ump_block_new);
+
+static int snd_ump_ioctl_block(struct snd_ump_endpoint *ump,
+ struct snd_ump_block_info __user *argp)
+{
+ struct snd_ump_block *fb;
+ unsigned char id;
+
+ if (get_user(id, &argp->block_id))
+ return -EFAULT;
+ fb = snd_ump_get_block(ump, id);
+ if (!fb)
+ return -ENOENT;
+ if (copy_to_user(argp, &fb->info, sizeof(fb->info)))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * Handle UMP-specific ioctls; called from snd_rawmidi_ioctl()
+ */
+static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
+ void __user *argp)
+{
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
+
+ switch (cmd) {
+ case SNDRV_UMP_IOCTL_ENDPOINT_INFO:
+ if (copy_to_user(argp, &ump->info, sizeof(ump->info)))
+ return -EFAULT;
+ return 0;
+ case SNDRV_UMP_IOCTL_BLOCK_INFO:
+ return snd_ump_ioctl_block(ump, argp);
+ default:
+ ump_dbg(ump, "rawmidi: unknown command = 0x%x\n", cmd);
+ return -ENOTTY;
+ }
+}
+
+static const char *ump_direction_string(int dir)
+{
+ switch (dir) {
+ case SNDRV_UMP_DIR_INPUT:
+ return "input";
+ case SNDRV_UMP_DIR_OUTPUT:
+ return "output";
+ case SNDRV_UMP_DIR_BIDIRECTION:
+ return "bidirection";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *ump_ui_hint_string(int dir)
+{
+ switch (dir) {
+ case SNDRV_UMP_BLOCK_UI_HINT_RECEIVER:
+ return "receiver";
+ case SNDRV_UMP_BLOCK_UI_HINT_SENDER:
+ return "sender";
+ case SNDRV_UMP_BLOCK_UI_HINT_BOTH:
+ return "both";
+ default:
+ return "unknown";
+ }
+}
+
+/* Additional proc file output */
+static void snd_ump_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_rawmidi *rmidi = entry->private_data;
+ struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
+ struct snd_ump_block *fb;
+
+ snd_iprintf(buffer, "EP Name: %s\n", ump->info.name);
+ snd_iprintf(buffer, "EP Product ID: %s\n", ump->info.product_id);
+ snd_iprintf(buffer, "UMP Version: 0x%04x\n", ump->info.version);
+ snd_iprintf(buffer, "Protocol Caps: 0x%08x\n", ump->info.protocol_caps);
+ snd_iprintf(buffer, "Protocol: 0x%08x\n", ump->info.protocol);
+ if (ump->info.version) {
+ snd_iprintf(buffer, "Manufacturer ID: 0x%08x\n",
+ ump->info.manufacturer_id);
+ snd_iprintf(buffer, "Family ID: 0x%04x\n", ump->info.family_id);
+ snd_iprintf(buffer, "Model ID: 0x%04x\n", ump->info.model_id);
+ snd_iprintf(buffer, "SW Revision: 0x%4phN\n", ump->info.sw_revision);
+ }
+ snd_iprintf(buffer, "Static Blocks: %s\n",
+ (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) ? "Yes" : "No");
+ snd_iprintf(buffer, "Num Blocks: %d\n\n", ump->info.num_blocks);
+
+ list_for_each_entry(fb, &ump->block_list, list) {
+ snd_iprintf(buffer, "Block %d (%s)\n", fb->info.block_id,
+ fb->info.name);
+ snd_iprintf(buffer, " Direction: %s\n",
+ ump_direction_string(fb->info.direction));
+ snd_iprintf(buffer, " Active: %s\n",
+ fb->info.active ? "Yes" : "No");
+ snd_iprintf(buffer, " Groups: %d-%d\n",
+ fb->info.first_group + 1,
+ fb->info.first_group + fb->info.num_groups);
+ snd_iprintf(buffer, " Is MIDI1: %s%s\n",
+ (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1) ? "Yes" : "No",
+ (fb->info.flags & SNDRV_UMP_BLOCK_IS_LOWSPEED) ? " (Low Speed)" : "");
+ if (ump->info.version) {
+ snd_iprintf(buffer, " MIDI-CI Version: %d\n",
+ fb->info.midi_ci_version);
+ snd_iprintf(buffer, " Sysex8 Streams: %d\n",
+ fb->info.sysex8_streams);
+ snd_iprintf(buffer, " UI Hint: %s\n",
+ ump_ui_hint_string(fb->info.ui_hint));
+ }
+ snd_iprintf(buffer, "\n");
+ }
+}
+
+/* update dir_bits and active flag for all groups in the client */
+void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
+{
+ struct snd_ump_block *fb;
+ struct snd_ump_group *group;
+ int i;
+
+ for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
+ group = &ump->groups[i];
+ *group->name = 0;
+ group->dir_bits = 0;
+ group->active = 0;
+ group->group = i;
+ group->valid = false;
+ group->is_midi1 = false;
+ }
+
+ list_for_each_entry(fb, &ump->block_list, list) {
+ if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
+ break;
+ group = &ump->groups[fb->info.first_group];
+ for (i = 0; i < fb->info.num_groups; i++, group++) {
+ group->valid = true;
+ if (fb->info.active)
+ group->active = 1;
+ if (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1)
+ group->is_midi1 = true;
+ switch (fb->info.direction) {
+ case SNDRV_UMP_DIR_INPUT:
+ group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT);
+ break;
+ case SNDRV_UMP_DIR_OUTPUT:
+ group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
+ break;
+ case SNDRV_UMP_DIR_BIDIRECTION:
+ group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT) |
+ (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
+ break;
+ }
+ if (!*fb->info.name)
+ continue;
+ if (*group->name)
+ strlcat(group->name, ", ", sizeof(group->name));
+ safe_append_string(group->name, sizeof(group->name),
+ fb->info.name, sizeof(fb->info.name));
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(snd_ump_update_group_attrs);
+
+/*
+ * UMP endpoint and function block handling
+ */
+
+/* open / close UMP streams for the internal stream msg communication */
+static int ump_request_open(struct snd_ump_endpoint *ump)
+{
+ return snd_rawmidi_kernel_open(&ump->core, 0,
+ SNDRV_RAWMIDI_LFLG_OUTPUT,
+ &ump->stream_rfile);
+}
+
+static void ump_request_close(struct snd_ump_endpoint *ump)
+{
+ snd_rawmidi_kernel_release(&ump->stream_rfile);
+}
+
+/* request a command and wait for the given response;
+ * @req1 and @req2 are u32 commands
+ * @reply is the expected UMP stream status
+ */
+static int ump_req_msg(struct snd_ump_endpoint *ump, u32 req1, u32 req2,
+ u32 reply)
+{
+ u32 buf[4];
+
+ ump_dbg(ump, "%s: request %08x %08x, wait-for %08x\n",
+ __func__, req1, req2, reply);
+ memset(buf, 0, sizeof(buf));
+ buf[0] = req1;
+ buf[1] = req2;
+ ump->stream_finished = 0;
+ ump->stream_wait_for = reply;
+ snd_rawmidi_kernel_write(ump->stream_rfile.output,
+ (unsigned char *)&buf, 16);
+ wait_event_timeout(ump->stream_wait, ump->stream_finished,
+ msecs_to_jiffies(500));
+ if (!READ_ONCE(ump->stream_finished)) {
+ ump_dbg(ump, "%s: request timed out\n", __func__);
+ return -ETIMEDOUT;
+ }
+ ump->stream_finished = 0;
+ ump_dbg(ump, "%s: reply: %08x %08x %08x %08x\n",
+ __func__, buf[0], buf[1], buf[2], buf[3]);
+ return 0;
+}
+
+/* append the received letters via UMP packet to the given string buffer;
+ * return 1 if the full string is received or 0 to continue
+ */
+static int ump_append_string(struct snd_ump_endpoint *ump, char *dest,
+ int maxsize, const u32 *buf, int offset)
+{
+ unsigned char format;
+ int c;
+
+ format = ump_stream_message_format(buf[0]);
+ if (format == UMP_STREAM_MSG_FORMAT_SINGLE ||
+ format == UMP_STREAM_MSG_FORMAT_START) {
+ c = 0;
+ } else {
+ c = strlen(dest);
+ if (c >= maxsize - 1)
+ return 1;
+ }
+
+ for (; offset < 16; offset++) {
+ dest[c] = buf[offset / 4] >> (3 - (offset % 4)) * 8;
+ if (!dest[c])
+ break;
+ if (++c >= maxsize - 1)
+ break;
+ }
+ dest[c] = 0;
+ return (format == UMP_STREAM_MSG_FORMAT_SINGLE ||
+ format == UMP_STREAM_MSG_FORMAT_END);
+}
+
+/* Choose the default protocol */
+static void choose_default_protocol(struct snd_ump_endpoint *ump)
+{
+ if (ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK)
+ return;
+ if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
+ ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI2;
+ else
+ 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)
+{
+ ump->info.version = (buf->ep_info.ump_version_major << 8) |
+ buf->ep_info.ump_version_minor;
+ ump->info.num_blocks = buf->ep_info.num_function_blocks;
+ if (ump->info.num_blocks > SNDRV_UMP_MAX_BLOCKS) {
+ ump_info(ump, "Invalid function blocks %d, fallback to 1\n",
+ ump->info.num_blocks);
+ ump->info.num_blocks = 1;
+ }
+
+ if (buf->ep_info.static_function_block)
+ ump->info.flags |= SNDRV_UMP_EP_INFO_STATIC_BLOCKS;
+
+ ump->info.protocol_caps = (buf->ep_info.protocol << 8) |
+ buf->ep_info.jrts;
+
+ ump_dbg(ump, "EP info: version=%x, num_blocks=%x, proto_caps=%x\n",
+ ump->info.version, ump->info.num_blocks, ump->info.protocol_caps);
+
+ ump->info.protocol &= ump->info.protocol_caps;
+ choose_default_protocol(ump);
+ seq_notify_ep_change(ump);
+
+ return 1; /* finished */
+}
+
+/* handle EP device info stream message; update the UMP attributes */
+static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump,
+ const union snd_ump_stream_msg *buf)
+{
+ ump->info.manufacturer_id = buf->device_info.manufacture_id & 0x7f7f7f;
+ ump->info.family_id = (buf->device_info.family_msb << 8) |
+ buf->device_info.family_lsb;
+ ump->info.model_id = (buf->device_info.model_msb << 8) |
+ buf->device_info.model_lsb;
+ ump->info.sw_revision[0] = (buf->device_info.sw_revision >> 24) & 0x7f;
+ ump->info.sw_revision[1] = (buf->device_info.sw_revision >> 16) & 0x7f;
+ ump->info.sw_revision[2] = (buf->device_info.sw_revision >> 8) & 0x7f;
+ ump->info.sw_revision[3] = buf->device_info.sw_revision & 0x7f;
+ ump_dbg(ump, "EP devinfo: manid=%08x, family=%04x, model=%04x, sw=%4phN\n",
+ ump->info.manufacturer_id,
+ 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)
+{
+ 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)
+{
+ 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 */
+static void seq_notify_protocol(struct snd_ump_endpoint *ump)
+{
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+ if (ump->seq_ops && ump->seq_ops->switch_protocol)
+ ump->seq_ops->switch_protocol(ump);
+#endif /* CONFIG_SND_SEQUENCER */
+}
+
+/**
+ * snd_ump_switch_protocol - switch MIDI protocol
+ * @ump: UMP endpoint
+ * @protocol: protocol to switch to
+ *
+ * Returns 1 if the protocol is actually switched, 0 if unchanged
+ */
+int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol)
+{
+ unsigned int type;
+
+ protocol &= ump->info.protocol_caps;
+ if (protocol == ump->info.protocol)
+ return 0;
+
+ type = protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK;
+ if (type != SNDRV_UMP_EP_INFO_PROTO_MIDI1 &&
+ type != SNDRV_UMP_EP_INFO_PROTO_MIDI2)
+ return 0;
+
+ ump->info.protocol = protocol;
+ ump_dbg(ump, "New protocol = %x (caps = %x)\n",
+ protocol, ump->info.protocol_caps);
+ seq_notify_protocol(ump);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(snd_ump_switch_protocol);
+
+/* handle EP stream config message; update the UMP protocol */
+static int ump_handle_stream_cfg_msg(struct snd_ump_endpoint *ump,
+ const union snd_ump_stream_msg *buf)
+{
+ unsigned int protocol =
+ (buf->stream_cfg.protocol << 8) | buf->stream_cfg.jrts;
+
+ snd_ump_switch_protocol(ump, protocol);
+ return 1; /* finished */
+}
+
+/* Extract Function Block info from UMP packet */
+static void fill_fb_info(struct snd_ump_endpoint *ump,
+ struct snd_ump_block_info *info,
+ const union snd_ump_stream_msg *buf)
+{
+ info->direction = buf->fb_info.direction;
+ info->ui_hint = buf->fb_info.ui_hint;
+ info->first_group = buf->fb_info.first_group;
+ info->num_groups = buf->fb_info.num_groups;
+ if (buf->fb_info.midi_10 < 2)
+ info->flags = buf->fb_info.midi_10;
+ else
+ info->flags = SNDRV_UMP_BLOCK_IS_MIDI1 | SNDRV_UMP_BLOCK_IS_LOWSPEED;
+ info->active = buf->fb_info.active;
+ info->midi_ci_version = buf->fb_info.midi_ci_version;
+ info->sysex8_streams = buf->fb_info.sysex8_streams;
+
+ ump_dbg(ump, "FB %d: dir=%d, active=%d, first_gp=%d, num_gp=%d, midici=%d, sysex8=%d, flags=0x%x\n",
+ info->block_id, info->direction, info->active,
+ info->first_group, info->num_groups, info->midi_ci_version,
+ info->sysex8_streams, info->flags);
+
+ if ((info->flags & SNDRV_UMP_BLOCK_IS_MIDI1) && info->num_groups != 1) {
+ info->num_groups = 1;
+ ump_dbg(ump, "FB %d: corrected groups to 1 for MIDI1\n",
+ info->block_id);
+ }
+}
+
+/* check whether the FB info gets updated by the current message */
+static bool is_fb_info_updated(struct snd_ump_endpoint *ump,
+ struct snd_ump_block *fb,
+ const union snd_ump_stream_msg *buf)
+{
+ char tmpbuf[offsetof(struct snd_ump_block_info, name)];
+
+ if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) {
+ ump_info(ump, "Skipping static FB info update (blk#%d)\n",
+ fb->info.block_id);
+ return 0;
+ }
+
+ memcpy(tmpbuf, &fb->info, sizeof(tmpbuf));
+ fill_fb_info(ump, (struct snd_ump_block_info *)tmpbuf, buf);
+ return memcmp(&fb->info, tmpbuf, sizeof(tmpbuf)) != 0;
+}
+
+/* notify the FB info/name change to sequencer */
+static void seq_notify_fb_change(struct snd_ump_endpoint *ump,
+ struct snd_ump_block *fb)
+{
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+ if (ump->seq_ops && ump->seq_ops->notify_fb_change)
+ ump->seq_ops->notify_fb_change(ump, fb);
+#endif
+}
+
+/* handle FB info message; update FB info if the block is present */
+static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
+ const union snd_ump_stream_msg *buf)
+{
+ unsigned char blk;
+ struct snd_ump_block *fb;
+
+ blk = buf->fb_info.function_block_id;
+ fb = snd_ump_get_block(ump, blk);
+
+ /* complain only if updated after parsing */
+ if (!fb && ump->parsed) {
+ ump_info(ump, "Function Block Info Update for non-existing block %d\n",
+ blk);
+ return -ENODEV;
+ }
+
+ /* When updated after the initial parse, check the FB info update */
+ if (ump->parsed && !is_fb_info_updated(ump, fb, buf))
+ return 1; /* no content change */
+
+ if (fb) {
+ fill_fb_info(ump, &fb->info, buf);
+ if (ump->parsed) {
+ snd_ump_update_group_attrs(ump);
+ update_legacy_names(ump);
+ seq_notify_fb_change(ump, fb);
+ }
+ }
+
+ return 1; /* finished */
+}
+
+/* handle FB name message; update the FB name string */
+static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
+ const union snd_ump_stream_msg *buf)
+{
+ unsigned char blk;
+ struct snd_ump_block *fb;
+ int ret;
+
+ blk = buf->fb_name.function_block_id;
+ fb = snd_ump_get_block(ump, blk);
+ if (!fb)
+ return -ENODEV;
+
+ if (ump->parsed &&
+ (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS)) {
+ ump_dbg(ump, "Skipping static FB name update (blk#%d)\n",
+ fb->info.block_id);
+ return 0;
+ }
+
+ ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
+ buf->raw, 3);
+ /* notify the FB name update to sequencer, too */
+ if (ret > 0 && ump->parsed) {
+ snd_ump_update_group_attrs(ump);
+ update_legacy_names(ump);
+ seq_notify_fb_change(ump, fb);
+ }
+ return ret;
+}
+
+static int create_block_from_fb_info(struct snd_ump_endpoint *ump, int blk)
+{
+ struct snd_ump_block *fb;
+ unsigned char direction, first_group, num_groups;
+ const union snd_ump_stream_msg *buf =
+ (const union snd_ump_stream_msg *)ump->input_buf;
+ u32 msg;
+ int err;
+
+ /* query the FB info once */
+ msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) |
+ (blk << 8) | UMP_STREAM_MSG_REQUEST_FB_INFO;
+ err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_INFO);
+ if (err < 0) {
+ ump_dbg(ump, "Unable to get FB info for block %d\n", blk);
+ return err;
+ }
+
+ /* the last input must be the FB info */
+ if (buf->fb_info.status != UMP_STREAM_MSG_STATUS_FB_INFO) {
+ ump_dbg(ump, "Inconsistent input: 0x%x\n", *buf->raw);
+ return -EINVAL;
+ }
+
+ direction = buf->fb_info.direction;
+ first_group = buf->fb_info.first_group;
+ num_groups = buf->fb_info.num_groups;
+
+ err = snd_ump_block_new(ump, blk, direction, first_group, num_groups,
+ &fb);
+ if (err < 0)
+ return err;
+
+ fill_fb_info(ump, &fb->info, buf);
+
+ msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) |
+ (blk << 8) | UMP_STREAM_MSG_REQUEST_FB_NAME;
+ err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_NAME);
+ if (err)
+ ump_dbg(ump, "Unable to get UMP FB name string #%d\n", blk);
+
+ return 0;
+}
+
+/* handle stream messages, called from snd_ump_receive() */
+static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
+ const u32 *buf, int size)
+{
+ const union snd_ump_stream_msg *msg;
+ unsigned int status;
+ int ret;
+
+ /* UMP stream message suppressed (for gadget UMP)? */
+ if (ump->no_process_stream)
+ return;
+
+ BUILD_BUG_ON(sizeof(*msg) != 16);
+ ump_dbg(ump, "Stream msg: %08x %08x %08x %08x\n",
+ buf[0], buf[1], buf[2], buf[3]);
+
+ if (size != 4 || ump_message_type(*buf) != UMP_MSG_TYPE_STREAM)
+ return;
+
+ msg = (const union snd_ump_stream_msg *)buf;
+ status = ump_stream_message_status(*buf);
+ switch (status) {
+ case UMP_STREAM_MSG_STATUS_EP_INFO:
+ ret = ump_handle_ep_info_msg(ump, msg);
+ break;
+ case UMP_STREAM_MSG_STATUS_DEVICE_INFO:
+ ret = ump_handle_device_info_msg(ump, msg);
+ break;
+ case UMP_STREAM_MSG_STATUS_EP_NAME:
+ ret = ump_handle_ep_name_msg(ump, msg);
+ break;
+ case UMP_STREAM_MSG_STATUS_PRODUCT_ID:
+ ret = ump_handle_product_id_msg(ump, msg);
+ break;
+ case UMP_STREAM_MSG_STATUS_STREAM_CFG:
+ ret = ump_handle_stream_cfg_msg(ump, msg);
+ break;
+ case UMP_STREAM_MSG_STATUS_FB_INFO:
+ ret = ump_handle_fb_info_msg(ump, msg);
+ break;
+ case UMP_STREAM_MSG_STATUS_FB_NAME:
+ ret = ump_handle_fb_name_msg(ump, msg);
+ break;
+ default:
+ return;
+ }
+
+ /* when the message has been processed fully, wake up */
+ if (ret > 0 && ump->stream_wait_for == status) {
+ WRITE_ONCE(ump->stream_finished, 1);
+ wake_up(&ump->stream_wait);
+ }
+}
+
+/**
+ * snd_ump_parse_endpoint - parse endpoint and create function blocks
+ * @ump: UMP object
+ *
+ * Returns 0 for successful parse, -ENODEV if device doesn't respond
+ * (or the query is unsupported), or other error code for serious errors.
+ */
+int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
+{
+ int blk, err;
+ u32 msg;
+
+ if (!(ump->core.info_flags & SNDRV_RAWMIDI_INFO_DUPLEX))
+ return -ENODEV;
+
+ err = ump_request_open(ump);
+ if (err < 0) {
+ ump_dbg(ump, "Unable to open rawmidi device: %d\n", err);
+ return err;
+ }
+
+ /* Check Endpoint Information */
+ msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_EP_DISCOVERY, 0) |
+ 0x0101; /* UMP version 1.1 */
+ err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_INFO,
+ UMP_STREAM_MSG_STATUS_EP_INFO);
+ if (err < 0) {
+ ump_dbg(ump, "Unable to get UMP EP info\n");
+ goto error;
+ }
+
+ /* Request Endpoint Device Info */
+ err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_DEVICE_INFO,
+ UMP_STREAM_MSG_STATUS_DEVICE_INFO);
+ if (err < 0)
+ ump_dbg(ump, "Unable to get UMP EP device info\n");
+
+ /* Request Endpoint Name */
+ err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_NAME,
+ UMP_STREAM_MSG_STATUS_EP_NAME);
+ 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);
+ if (err < 0)
+ ump_dbg(ump, "Unable to get UMP EP product ID string\n");
+
+ /* Get the current stream configuration */
+ err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_STREAM_CFG,
+ UMP_STREAM_MSG_STATUS_STREAM_CFG);
+ if (err < 0)
+ ump_dbg(ump, "Unable to get UMP EP stream config\n");
+
+ /* If no protocol is set by some reason, assume the valid one */
+ choose_default_protocol(ump);
+
+ /* Query and create blocks from Function Blocks */
+ for (blk = 0; blk < ump->info.num_blocks; blk++) {
+ err = create_block_from_fb_info(ump, blk);
+ if (err < 0)
+ continue;
+ }
+
+ /* initialize group attributions */
+ snd_ump_update_group_attrs(ump);
+
+ error:
+ ump->parsed = true;
+ ump_request_close(ump);
+ if (err == -ETIMEDOUT)
+ err = -ENODEV;
+ return err;
+}
+EXPORT_SYMBOL_GPL(snd_ump_parse_endpoint);
+
+#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
+/*
+ * Legacy rawmidi support
+ */
+static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ump_endpoint *ump = substream->rmidi->private_data;
+ int dir = substream->stream;
+ int group = ump->legacy_mapping[substream->number];
+ int err;
+
+ guard(mutex)(&ump->open_mutex);
+ if (ump->legacy_substreams[dir][group])
+ return -EBUSY;
+ if (!ump->groups[group].active)
+ return -ENODEV;
+ if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
+ if (!ump->legacy_out_opens) {
+ err = snd_rawmidi_kernel_open(&ump->core, 0,
+ SNDRV_RAWMIDI_LFLG_OUTPUT |
+ SNDRV_RAWMIDI_LFLG_APPEND,
+ &ump->legacy_out_rfile);
+ if (err < 0)
+ return err;
+ }
+ ump->legacy_out_opens++;
+ snd_ump_convert_reset(&ump->out_cvts[group]);
+ }
+ guard(spinlock_irq)(&ump->legacy_locks[dir]);
+ ump->legacy_substreams[dir][group] = substream;
+ return 0;
+}
+
+static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ump_endpoint *ump = substream->rmidi->private_data;
+ int dir = substream->stream;
+ int group = ump->legacy_mapping[substream->number];
+
+ guard(mutex)(&ump->open_mutex);
+ scoped_guard(spinlock_irq, &ump->legacy_locks[dir])
+ ump->legacy_substreams[dir][group] = NULL;
+ if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
+ if (!--ump->legacy_out_opens)
+ snd_rawmidi_kernel_release(&ump->legacy_out_rfile);
+ }
+ return 0;
+}
+
+static void snd_ump_legacy_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct snd_ump_endpoint *ump = substream->rmidi->private_data;
+ int dir = substream->stream;
+
+ ump->ops->trigger(ump, dir, up);
+}
+
+static void snd_ump_legacy_drain(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ump_endpoint *ump = substream->rmidi->private_data;
+
+ if (ump->ops->drain)
+ ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT);
+}
+
+static int snd_ump_legacy_dev_register(struct snd_rawmidi *rmidi)
+{
+ /* dummy, just for avoiding create superfluous seq clients */
+ return 0;
+}
+
+static const struct snd_rawmidi_ops snd_ump_legacy_input_ops = {
+ .open = snd_ump_legacy_open,
+ .close = snd_ump_legacy_close,
+ .trigger = snd_ump_legacy_trigger,
+};
+
+static const struct snd_rawmidi_ops snd_ump_legacy_output_ops = {
+ .open = snd_ump_legacy_open,
+ .close = snd_ump_legacy_close,
+ .trigger = snd_ump_legacy_trigger,
+ .drain = snd_ump_legacy_drain,
+};
+
+static const struct snd_rawmidi_global_ops snd_ump_legacy_ops = {
+ .dev_register = snd_ump_legacy_dev_register,
+};
+
+static int process_legacy_output(struct snd_ump_endpoint *ump,
+ u32 *buffer, int count)
+{
+ struct snd_rawmidi_substream *substream;
+ struct ump_cvt_to_ump *ctx;
+ const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT;
+ unsigned int protocol;
+ unsigned char c;
+ int group, size = 0;
+
+ if (!ump->out_cvts || !ump->legacy_out_opens)
+ return 0;
+
+ guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
+ for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) {
+ substream = ump->legacy_substreams[dir][group];
+ if (!substream)
+ continue;
+ ctx = &ump->out_cvts[group];
+ protocol = ump->info.protocol;
+ if ((protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2) &&
+ ump->groups[group].is_midi1)
+ protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1;
+ while (!ctx->ump_bytes &&
+ snd_rawmidi_transmit(substream, &c, 1) > 0)
+ snd_ump_convert_to_ump(ctx, group, protocol, c);
+ if (ctx->ump_bytes && ctx->ump_bytes <= count) {
+ size = ctx->ump_bytes;
+ memcpy(buffer, ctx->ump, size);
+ ctx->ump_bytes = 0;
+ break;
+ }
+ }
+ return size;
+}
+
+static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
+ int words)
+{
+ struct snd_rawmidi_substream *substream;
+ unsigned char buf[16];
+ unsigned char group;
+ const int dir = SNDRV_RAWMIDI_STREAM_INPUT;
+ int size;
+
+ size = snd_ump_convert_from_ump(src, buf, &group);
+ if (size <= 0)
+ return;
+ guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
+ substream = ump->legacy_substreams[dir][group];
+ if (substream)
+ snd_rawmidi_receive(substream, buf, size);
+}
+
+/* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */
+static int fill_legacy_mapping(struct snd_ump_endpoint *ump)
+{
+ struct snd_ump_block *fb;
+ unsigned int group_maps = 0;
+ int i, num;
+
+ if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) {
+ list_for_each_entry(fb, &ump->block_list, list) {
+ for (i = 0; i < fb->info.num_groups; i++)
+ group_maps |= 1U << (fb->info.first_group + i);
+ }
+ if (!group_maps)
+ ump_info(ump, "No UMP Group is found in FB\n");
+ }
+
+ /* use all groups for non-static case */
+ if (!group_maps)
+ group_maps = (1U << SNDRV_UMP_MAX_GROUPS) - 1;
+
+ num = 0;
+ for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++)
+ if (group_maps & (1U << i))
+ ump->legacy_mapping[num++] = i;
+
+ return num;
+}
+
+static void update_legacy_substreams(struct snd_ump_endpoint *ump,
+ struct snd_rawmidi *rmidi, int dir)
+{
+ struct snd_rawmidi_substream *s;
+ const char *name;
+ int idx;
+
+ list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
+ idx = ump->legacy_mapping[s->number];
+ name = ump->groups[idx].name;
+ if (!*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;
+ }
+}
+
+static void update_legacy_names(struct snd_ump_endpoint *ump)
+{
+ struct snd_rawmidi *rmidi = ump->legacy_rmidi;
+
+ 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,
+ char *id, int device)
+{
+ struct snd_rawmidi *rmidi;
+ bool input, output;
+ int err, num;
+
+ ump->out_cvts = kcalloc(SNDRV_UMP_MAX_GROUPS,
+ sizeof(*ump->out_cvts), GFP_KERNEL);
+ if (!ump->out_cvts)
+ return -ENOMEM;
+
+ num = fill_legacy_mapping(ump);
+
+ input = ump->core.info_flags & SNDRV_RAWMIDI_INFO_INPUT;
+ output = ump->core.info_flags & SNDRV_RAWMIDI_INFO_OUTPUT;
+ err = snd_rawmidi_new(ump->core.card, id, device,
+ output ? num : 0, input ? num : 0,
+ &rmidi);
+ if (err < 0) {
+ kfree(ump->out_cvts);
+ return err;
+ }
+
+ if (input)
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_ump_legacy_input_ops);
+ if (output)
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &snd_ump_legacy_output_ops);
+ 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;
+}
+EXPORT_SYMBOL_GPL(snd_ump_attach_legacy_rawmidi);
+#endif /* CONFIG_SND_UMP_LEGACY_RAWMIDI */
+
+MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/core/ump_convert.c b/sound/core/ump_convert.c
new file mode 100644
index 000000000000..0fe13d031656
--- /dev/null
+++ b/sound/core/ump_convert.c
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Helpers for UMP <-> MIDI 1.0 byte stream conversion
+ */
+
+#include <linux/module.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/asound.h>
+#include <sound/ump.h>
+#include <sound/ump_convert.h>
+
+/*
+ * Upgrade / downgrade value bits
+ */
+static u8 downscale_32_to_7bit(u32 src)
+{
+ return src >> 25;
+}
+
+static u16 downscale_32_to_14bit(u32 src)
+{
+ return src >> 18;
+}
+
+static u8 downscale_16_to_7bit(u16 src)
+{
+ return src >> 9;
+}
+
+static u16 upscale_7_to_16bit(u8 src)
+{
+ u16 val, repeat;
+
+ val = (u16)src << 9;
+ if (src <= 0x40)
+ return val;
+ repeat = src & 0x3f;
+ return val | (repeat << 3) | (repeat >> 3);
+}
+
+static u32 upscale_7_to_32bit(u8 src)
+{
+ u32 val, repeat;
+
+ val = src << 25;
+ if (src <= 0x40)
+ return val;
+ repeat = src & 0x3f;
+ return val | (repeat << 19) | (repeat << 13) |
+ (repeat << 7) | (repeat << 1) | (repeat >> 5);
+}
+
+static u32 upscale_14_to_32bit(u16 src)
+{
+ u32 val, repeat;
+
+ val = src << 18;
+ if (src <= 0x2000)
+ return val;
+ repeat = src & 0x1fff;
+ return val | (repeat << 5) | (repeat >> 8);
+}
+
+/*
+ * UMP -> MIDI 1 byte stream conversion
+ */
+/* convert a UMP System message to MIDI 1.0 byte stream */
+static int cvt_ump_system_to_legacy(u32 data, unsigned char *buf)
+{
+ buf[0] = ump_message_status_channel(data);
+ switch (ump_message_status_code(data)) {
+ case UMP_SYSTEM_STATUS_MIDI_TIME_CODE:
+ case UMP_SYSTEM_STATUS_SONG_SELECT:
+ buf[1] = (data >> 8) & 0x7f;
+ return 2;
+ case UMP_SYSTEM_STATUS_SONG_POSITION:
+ buf[1] = (data >> 8) & 0x7f;
+ buf[2] = data & 0x7f;
+ return 3;
+ default:
+ return 1;
+ }
+}
+
+/* convert a UMP MIDI 1.0 Channel Voice message to MIDI 1.0 byte stream */
+static int cvt_ump_midi1_to_legacy(u32 data, unsigned char *buf)
+{
+ buf[0] = ump_message_status_channel(data);
+ buf[1] = (data >> 8) & 0xff;
+ switch (ump_message_status_code(data)) {
+ case UMP_MSG_STATUS_PROGRAM:
+ case UMP_MSG_STATUS_CHANNEL_PRESSURE:
+ return 2;
+ default:
+ buf[2] = data & 0xff;
+ return 3;
+ }
+}
+
+/* convert a UMP MIDI 2.0 Channel Voice message to MIDI 1.0 byte stream */
+static int cvt_ump_midi2_to_legacy(const union snd_ump_midi2_msg *midi2,
+ unsigned char *buf)
+{
+ unsigned char status = midi2->note.status;
+ unsigned char channel = midi2->note.channel;
+ u16 v;
+
+ buf[0] = (status << 4) | channel;
+ switch (status) {
+ case UMP_MSG_STATUS_NOTE_OFF:
+ case UMP_MSG_STATUS_NOTE_ON:
+ buf[1] = midi2->note.note;
+ buf[2] = downscale_16_to_7bit(midi2->note.velocity);
+ if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2])
+ buf[2] = 1;
+ return 3;
+ case UMP_MSG_STATUS_POLY_PRESSURE:
+ buf[1] = midi2->paf.note;
+ buf[2] = downscale_32_to_7bit(midi2->paf.data);
+ return 3;
+ case UMP_MSG_STATUS_CC:
+ buf[1] = midi2->cc.index;
+ buf[2] = downscale_32_to_7bit(midi2->cc.data);
+ return 3;
+ case UMP_MSG_STATUS_CHANNEL_PRESSURE:
+ buf[1] = downscale_32_to_7bit(midi2->caf.data);
+ return 2;
+ case UMP_MSG_STATUS_PROGRAM:
+ if (midi2->pg.bank_valid) {
+ buf[0] = channel | (UMP_MSG_STATUS_CC << 4);
+ buf[1] = UMP_CC_BANK_SELECT;
+ buf[2] = midi2->pg.bank_msb;
+ buf[3] = channel | (UMP_MSG_STATUS_CC << 4);
+ buf[4] = UMP_CC_BANK_SELECT_LSB;
+ buf[5] = midi2->pg.bank_lsb;
+ buf[6] = channel | (UMP_MSG_STATUS_PROGRAM << 4);
+ buf[7] = midi2->pg.program;
+ return 8;
+ }
+ buf[1] = midi2->pg.program;
+ return 2;
+ case UMP_MSG_STATUS_PITCH_BEND:
+ v = downscale_32_to_14bit(midi2->pb.data);
+ buf[1] = v & 0x7f;
+ buf[2] = v >> 7;
+ return 3;
+ case UMP_MSG_STATUS_RPN:
+ case UMP_MSG_STATUS_NRPN:
+ buf[0] = channel | (UMP_MSG_STATUS_CC << 4);
+ buf[1] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB;
+ buf[2] = midi2->rpn.bank;
+ buf[3] = buf[0];
+ buf[4] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB;
+ buf[5] = midi2->rpn.index;
+ buf[6] = buf[0];
+ buf[7] = UMP_CC_DATA;
+ v = downscale_32_to_14bit(midi2->rpn.data);
+ buf[8] = v >> 7;
+ buf[9] = buf[0];
+ buf[10] = UMP_CC_DATA_LSB;
+ buf[11] = v & 0x7f;
+ return 12;
+ default:
+ return 0;
+ }
+}
+
+/* convert a UMP 7-bit SysEx message to MIDI 1.0 byte stream */
+static int cvt_ump_sysex7_to_legacy(const u32 *data, unsigned char *buf)
+{
+ unsigned char status;
+ unsigned char bytes;
+ int size, offset;
+
+ status = ump_sysex_message_status(*data);
+ if (status > UMP_SYSEX_STATUS_END)
+ return 0; // unsupported, skip
+ bytes = ump_sysex_message_length(*data);
+ if (bytes > 6)
+ return 0; // skip
+
+ size = 0;
+ if (status == UMP_SYSEX_STATUS_SINGLE ||
+ status == UMP_SYSEX_STATUS_START) {
+ buf[0] = UMP_MIDI1_MSG_SYSEX_START;
+ size = 1;
+ }
+
+ offset = 8;
+ for (; bytes; bytes--, size++) {
+ buf[size] = (*data >> offset) & 0x7f;
+ if (!offset) {
+ offset = 24;
+ data++;
+ } else {
+ offset -= 8;
+ }
+ }
+
+ if (status == UMP_SYSEX_STATUS_SINGLE ||
+ status == UMP_SYSEX_STATUS_END)
+ buf[size++] = UMP_MIDI1_MSG_SYSEX_END;
+
+ return size;
+}
+
+/**
+ * snd_ump_convert_from_ump - convert from UMP to legacy MIDI
+ * @data: UMP packet
+ * @buf: buffer to store legacy MIDI data
+ * @group_ret: pointer to store the target group
+ *
+ * Convert from a UMP packet @data to MIDI 1.0 bytes at @buf.
+ * The target group is stored at @group_ret.
+ *
+ * The function returns the number of bytes of MIDI 1.0 stream.
+ */
+int snd_ump_convert_from_ump(const u32 *data,
+ unsigned char *buf,
+ unsigned char *group_ret)
+{
+ *group_ret = ump_message_group(*data);
+
+ switch (ump_message_type(*data)) {
+ case UMP_MSG_TYPE_SYSTEM:
+ return cvt_ump_system_to_legacy(*data, buf);
+ case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
+ return cvt_ump_midi1_to_legacy(*data, buf);
+ case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
+ return cvt_ump_midi2_to_legacy((const union snd_ump_midi2_msg *)data,
+ buf);
+ case UMP_MSG_TYPE_DATA:
+ return cvt_ump_sysex7_to_legacy(data, buf);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ump_convert_from_ump);
+
+/*
+ * MIDI 1 byte stream -> UMP conversion
+ */
+/* convert MIDI 1.0 SysEx to a UMP packet */
+static int cvt_legacy_sysex_to_ump(struct ump_cvt_to_ump *cvt,
+ unsigned char group, u32 *data, bool finish)
+{
+ unsigned char status;
+ bool start = cvt->in_sysex == 1;
+ int i, offset;
+
+ if (start && finish)
+ status = UMP_SYSEX_STATUS_SINGLE;
+ else if (start)
+ status = UMP_SYSEX_STATUS_START;
+ else if (finish)
+ status = UMP_SYSEX_STATUS_END;
+ else
+ status = UMP_SYSEX_STATUS_CONTINUE;
+ *data = ump_compose(UMP_MSG_TYPE_DATA, group, status, cvt->len);
+ offset = 8;
+ for (i = 0; i < cvt->len; i++) {
+ *data |= cvt->buf[i] << offset;
+ if (!offset) {
+ offset = 24;
+ data++;
+ } else
+ offset -= 8;
+ }
+ cvt->len = 0;
+ if (finish)
+ cvt->in_sysex = 0;
+ else
+ cvt->in_sysex++;
+ return 8;
+}
+
+/* convert to a UMP System message */
+static int cvt_legacy_system_to_ump(struct ump_cvt_to_ump *cvt,
+ unsigned char group, u32 *data)
+{
+ data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, cvt->buf[0]);
+ if (cvt->cmd_bytes > 1)
+ data[0] |= cvt->buf[1] << 8;
+ if (cvt->cmd_bytes > 2)
+ data[0] |= cvt->buf[2];
+ return 4;
+}
+
+static void reset_rpn(struct ump_cvt_to_ump_bank *cc)
+{
+ cc->rpn_set = 0;
+ cc->nrpn_set = 0;
+ cc->cc_rpn_msb = cc->cc_rpn_lsb = 0;
+ cc->cc_data_msb = cc->cc_data_lsb = 0;
+ cc->cc_data_msb_set = cc->cc_data_lsb_set = 0;
+}
+
+static int fill_rpn(struct ump_cvt_to_ump_bank *cc,
+ union snd_ump_midi2_msg *midi2,
+ bool flush)
+{
+ if (!(cc->cc_data_lsb_set || cc->cc_data_msb_set))
+ return 0; // skip
+ /* when not flushing, wait for complete data set */
+ if (!flush && (!cc->cc_data_lsb_set || !cc->cc_data_msb_set))
+ return 0; // skip
+
+ if (cc->rpn_set) {
+ midi2->rpn.status = UMP_MSG_STATUS_RPN;
+ midi2->rpn.bank = cc->cc_rpn_msb;
+ midi2->rpn.index = cc->cc_rpn_lsb;
+ } else if (cc->nrpn_set) {
+ midi2->rpn.status = UMP_MSG_STATUS_NRPN;
+ midi2->rpn.bank = cc->cc_nrpn_msb;
+ midi2->rpn.index = cc->cc_nrpn_lsb;
+ } else {
+ return 0; // skip
+ }
+
+ midi2->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) |
+ cc->cc_data_lsb);
+
+ reset_rpn(cc);
+ return 1;
+}
+
+/* convert to a MIDI 1.0 Channel Voice message */
+static int cvt_legacy_cmd_to_ump(struct ump_cvt_to_ump *cvt,
+ unsigned char group,
+ unsigned int protocol,
+ u32 *data, unsigned char bytes)
+{
+ const unsigned char *buf = cvt->buf;
+ struct ump_cvt_to_ump_bank *cc;
+ union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)data;
+ unsigned char status, channel;
+ int ret;
+
+ BUILD_BUG_ON(sizeof(union snd_ump_midi1_msg) != 4);
+ BUILD_BUG_ON(sizeof(union snd_ump_midi2_msg) != 8);
+
+ /* for MIDI 1.0 UMP, it's easy, just pack it into UMP */
+ if (protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI1) {
+ data[0] = ump_compose(UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE,
+ group, 0, buf[0]);
+ data[0] |= buf[1] << 8;
+ if (bytes > 2)
+ data[0] |= buf[2];
+ return 4;
+ }
+
+ status = *buf >> 4;
+ channel = *buf & 0x0f;
+ cc = &cvt->bank[channel];
+
+ /* special handling: treat note-on with 0 velocity as note-off */
+ if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2])
+ status = UMP_MSG_STATUS_NOTE_OFF;
+
+ /* initialize the packet */
+ data[0] = ump_compose(UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE,
+ group, status, channel);
+ data[1] = 0;
+
+ switch (status) {
+ case UMP_MSG_STATUS_NOTE_ON:
+ case UMP_MSG_STATUS_NOTE_OFF:
+ midi2->note.note = buf[1];
+ midi2->note.velocity = upscale_7_to_16bit(buf[2]);
+ break;
+ case UMP_MSG_STATUS_POLY_PRESSURE:
+ midi2->paf.note = buf[1];
+ midi2->paf.data = upscale_7_to_32bit(buf[2]);
+ break;
+ case UMP_MSG_STATUS_CC:
+ switch (buf[1]) {
+ case UMP_CC_RPN_MSB:
+ ret = fill_rpn(cc, midi2, true);
+ cc->rpn_set = 1;
+ cc->cc_rpn_msb = buf[2];
+ if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
+ reset_rpn(cc);
+ return ret;
+ case UMP_CC_RPN_LSB:
+ ret = fill_rpn(cc, midi2, true);
+ cc->rpn_set = 1;
+ cc->cc_rpn_lsb = buf[2];
+ if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
+ reset_rpn(cc);
+ return ret;
+ case UMP_CC_NRPN_MSB:
+ ret = fill_rpn(cc, midi2, true);
+ cc->nrpn_set = 1;
+ cc->cc_nrpn_msb = buf[2];
+ return ret;
+ case UMP_CC_NRPN_LSB:
+ ret = fill_rpn(cc, midi2, true);
+ cc->nrpn_set = 1;
+ cc->cc_nrpn_lsb = buf[2];
+ return ret;
+ case UMP_CC_DATA:
+ cc->cc_data_msb_set = 1;
+ cc->cc_data_msb = buf[2];
+ return fill_rpn(cc, midi2, false);
+ case UMP_CC_BANK_SELECT:
+ cc->bank_set = 1;
+ cc->cc_bank_msb = buf[2];
+ return 0; // skip
+ case UMP_CC_BANK_SELECT_LSB:
+ cc->bank_set = 1;
+ cc->cc_bank_lsb = buf[2];
+ return 0; // skip
+ case UMP_CC_DATA_LSB:
+ cc->cc_data_lsb_set = 1;
+ cc->cc_data_lsb = buf[2];
+ return fill_rpn(cc, midi2, false);
+ default:
+ midi2->cc.index = buf[1];
+ midi2->cc.data = upscale_7_to_32bit(buf[2]);
+ break;
+ }
+ break;
+ case UMP_MSG_STATUS_PROGRAM:
+ midi2->pg.program = buf[1];
+ if (cc->bank_set) {
+ midi2->pg.bank_valid = 1;
+ midi2->pg.bank_msb = cc->cc_bank_msb;
+ midi2->pg.bank_lsb = cc->cc_bank_lsb;
+ cc->bank_set = 0;
+ }
+ break;
+ case UMP_MSG_STATUS_CHANNEL_PRESSURE:
+ midi2->caf.data = upscale_7_to_32bit(buf[1]);
+ break;
+ case UMP_MSG_STATUS_PITCH_BEND:
+ midi2->pb.data = upscale_14_to_32bit(buf[1] | (buf[2] << 7));
+ break;
+ default:
+ return 0;
+ }
+
+ return 8;
+}
+
+static int do_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group,
+ unsigned int protocol, unsigned char c, u32 *data)
+{
+ /* bytes for 0x80-0xf0 */
+ static unsigned char cmd_bytes[8] = {
+ 3, 3, 3, 3, 2, 2, 3, 0
+ };
+ /* bytes for 0xf0-0xff */
+ static unsigned char system_bytes[16] = {
+ 0, 2, 3, 2, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1
+ };
+ unsigned char bytes;
+
+ if (c == UMP_MIDI1_MSG_SYSEX_START) {
+ cvt->in_sysex = 1;
+ cvt->len = 0;
+ return 0;
+ }
+ if (c == UMP_MIDI1_MSG_SYSEX_END) {
+ if (!cvt->in_sysex)
+ return 0; /* skip */
+ return cvt_legacy_sysex_to_ump(cvt, group, data, true);
+ }
+
+ if ((c & 0xf0) == UMP_MIDI1_MSG_REALTIME) {
+ bytes = system_bytes[c & 0x0f];
+ if (!bytes)
+ return 0; /* skip */
+ if (bytes == 1) {
+ data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, c);
+ return 4;
+ }
+ cvt->buf[0] = c;
+ cvt->len = 1;
+ cvt->cmd_bytes = bytes;
+ cvt->in_sysex = 0; /* abort SysEx */
+ return 0;
+ }
+
+ if (c & 0x80) {
+ bytes = cmd_bytes[(c >> 4) & 7];
+ cvt->buf[0] = c;
+ cvt->len = 1;
+ cvt->cmd_bytes = bytes;
+ cvt->in_sysex = 0; /* abort SysEx */
+ return 0;
+ }
+
+ if (cvt->in_sysex) {
+ cvt->buf[cvt->len++] = c;
+ if (cvt->len == 6)
+ return cvt_legacy_sysex_to_ump(cvt, group, data, false);
+ return 0;
+ }
+
+ if (!cvt->len)
+ return 0;
+
+ cvt->buf[cvt->len++] = c;
+ if (cvt->len < cvt->cmd_bytes)
+ return 0;
+ cvt->len = 1;
+ if ((cvt->buf[0] & 0xf0) == UMP_MIDI1_MSG_REALTIME)
+ return cvt_legacy_system_to_ump(cvt, group, data);
+ return cvt_legacy_cmd_to_ump(cvt, group, protocol, data, cvt->cmd_bytes);
+}
+
+/**
+ * snd_ump_convert_to_ump - convert legacy MIDI byte to UMP packet
+ * @cvt: converter context
+ * @group: target UMP group
+ * @protocol: target UMP protocol
+ * @c: MIDI 1.0 byte data
+ *
+ * Feed a MIDI 1.0 byte @c and convert to a UMP packet if completed.
+ * The result is stored in the buffer in @cvt.
+ */
+void snd_ump_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group,
+ unsigned int protocol, unsigned char c)
+{
+ cvt->ump_bytes = do_convert_to_ump(cvt, group, protocol, c, cvt->ump);
+}
+EXPORT_SYMBOL_GPL(snd_ump_convert_to_ump);
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index d0f11f37889b..c657659b236c 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -56,7 +56,7 @@ struct link_follower {
static int follower_update(struct link_follower *follower)
{
- struct snd_ctl_elem_value *uctl;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
int err, ch;
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
@@ -65,18 +65,16 @@ static int follower_update(struct link_follower *follower)
uctl->id = follower->follower.id;
err = follower->follower.get(&follower->follower, uctl);
if (err < 0)
- goto error;
+ return err;
for (ch = 0; ch < follower->info.count; ch++)
follower->vals[ch] = uctl->value.integer.value[ch];
- error:
- kfree(uctl);
- return err < 0 ? err : 0;
+ return 0;
}
/* get the follower ctl info and save the initial values */
static int follower_init(struct link_follower *follower)
{
- struct snd_ctl_elem_info *uinfo;
+ struct snd_ctl_elem_info *uinfo __free(kfree) = NULL;
int err;
if (follower->info.count) {
@@ -91,22 +89,18 @@ static int follower_init(struct link_follower *follower)
return -ENOMEM;
uinfo->id = follower->follower.id;
err = follower->follower.info(&follower->follower, uinfo);
- if (err < 0) {
- kfree(uinfo);
+ if (err < 0)
return err;
- }
follower->info.type = uinfo->type;
follower->info.count = uinfo->count;
if (follower->info.count > 2 ||
(follower->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
follower->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
pr_err("ALSA: vmaster: invalid follower element\n");
- kfree(uinfo);
return -EINVAL;
}
follower->info.min_val = uinfo->value.integer.min;
follower->info.max_val = uinfo->value.integer.max;
- kfree(uinfo);
return follower_update(follower);
}
@@ -205,6 +199,12 @@ static int follower_put(struct snd_kcontrol *kcontrol,
if (err < 0)
return err;
for (ch = 0; ch < follower->info.count; ch++) {
+ if (ucontrol->value.integer.value[ch] < follower->info.min_val ||
+ ucontrol->value.integer.value[ch] > follower->info.max_val)
+ return -EINVAL;
+ }
+
+ for (ch = 0; ch < follower->info.count; ch++) {
if (follower->vals[ch] != ucontrol->value.integer.value[ch]) {
changed = 1;
follower->vals[ch] = ucontrol->value.integer.value[ch];
@@ -280,6 +280,34 @@ int _snd_ctl_add_follower(struct snd_kcontrol *master,
}
EXPORT_SYMBOL(_snd_ctl_add_follower);
+/**
+ * snd_ctl_add_followers - add multiple followers to vmaster
+ * @card: card instance
+ * @master: the target vmaster kcontrol object
+ * @list: NULL-terminated list of name strings of followers to be added
+ *
+ * Adds the multiple follower kcontrols with the given names.
+ * Returns 0 for success or a negative error code.
+ */
+int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master,
+ const char * const *list)
+{
+ struct snd_kcontrol *follower;
+ int err;
+
+ for (; *list; list++) {
+ follower = snd_ctl_find_id_mixer(card, *list);
+ if (follower) {
+ err = snd_ctl_add_follower(master, follower);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_add_followers);
+
/*
* ctl callbacks for master controls
*/
@@ -313,7 +341,7 @@ static int master_get(struct snd_kcontrol *kcontrol,
static int sync_followers(struct link_master *master, int old_val, int new_val)
{
struct link_follower *follower;
- struct snd_ctl_elem_value *uval;
+ struct snd_ctl_elem_value *uval __free(kfree) = NULL;
uval = kmalloc(sizeof(*uval), GFP_KERNEL);
if (!uval)
@@ -325,7 +353,6 @@ static int sync_followers(struct link_master *master, int old_val, int new_val)
master->val = new_val;
follower_put_val(follower, uval);
}
- kfree(uval);
return 0;
}
@@ -344,6 +371,8 @@ static int master_put(struct snd_kcontrol *kcontrol,
new_val = ucontrol->value.integer.value[0];
if (new_val == old_val)
return 0;
+ if (new_val < master->info.min_val || new_val > master->info.max_val)
+ return -EINVAL;
err = sync_followers(master, old_val, new_val);
if (err < 0)
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index be3009746f3a..6debd8e95cb7 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -109,6 +109,23 @@ config SND_ALOOP
To compile this driver as a module, choose M here: the module
will be called snd-aloop.
+config SND_PCMTEST
+ tristate "Virtual PCM test driver"
+ depends on DEBUG_FS
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for the Virtual PCM test driver.
+ This driver is aimed at extended testing of the userspace applications
+ which use the ALSA API, as well as the PCM middle layer testing.
+
+ It can generate random or pattern-based data into the capture stream,
+ check the playback stream for containing the selected pattern, inject
+ time delays during capture/playback, redefine the RESET ioctl operation
+ to perform the PCM middle layer testing and inject errors during the
+ PCM callbacks. It supports both interleaved and non-interleaved access
+ modes. You can find the corresponding selftest in the 'alsa'
+ selftests folder.
+
config SND_VIRMIDI
tristate "Virtual MIDI soundcard"
depends on SND_SEQUENCER
@@ -128,6 +145,7 @@ config SND_VIRMIDI
config SND_MTPAV
tristate "MOTU MidiTimePiece AV multiport MIDI"
+ depends on HAS_IOPORT
select SND_RAWMIDI
help
To use a MOTU MidiTimePiece AV multiport MIDI adapter
@@ -152,6 +170,7 @@ config SND_MTS64
config SND_SERIAL_U16550
tristate "UART16550 serial MIDI driver"
+ depends on HAS_IOPORT
select SND_RAWMIDI
help
To include support for MIDI serial port interfaces, say Y here
@@ -185,6 +204,7 @@ config SND_SERIAL_GENERIC
config SND_MPU401
tristate "Generic MPU-401 UART driver"
+ depends on HAS_IOPORT
select SND_MPU401_UART
help
Say Y here to include support for MIDI ports compatible with
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile
index b60303180a1b..a08bdd70ec9c 100644
--- a/sound/drivers/Makefile
+++ b/sound/drivers/Makefile
@@ -4,19 +4,21 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-dummy-objs := dummy.o
-snd-aloop-objs := aloop.o
-snd-mtpav-objs := mtpav.o
-snd-mts64-objs := mts64.o
-snd-portman2x4-objs := portman2x4.o
-snd-serial-u16550-objs := serial-u16550.o
-snd-serial-generic-objs := serial-generic.o
-snd-virmidi-objs := virmidi.o
+snd-dummy-y := dummy.o
+snd-aloop-y := aloop.o
+snd-mtpav-y := mtpav.o
+snd-mts64-y := mts64.o
+snd-pcmtest-y := pcmtest.o
+snd-portman2x4-y := portman2x4.o
+snd-serial-u16550-y := serial-u16550.o
+snd-serial-generic-y := serial-generic.o
+snd-virmidi-y := virmidi.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
+obj-$(CONFIG_SND_PCMTEST) += snd-pcmtest.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
obj-$(CONFIG_SND_SERIAL_GENERIC) += snd-serial-generic.o
obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index a38e602b4fc6..64ef03b2d579 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/module.h>
@@ -119,11 +120,13 @@ struct loopback_setup {
unsigned int rate_shift;
snd_pcm_format_t format;
unsigned int rate;
+ snd_pcm_access_t access;
unsigned int channels;
struct snd_ctl_elem_id active_id;
struct snd_ctl_elem_id format_id;
struct snd_ctl_elem_id rate_id;
struct snd_ctl_elem_id channels_id;
+ struct snd_ctl_elem_id access_id;
};
struct loopback {
@@ -158,6 +161,9 @@ struct loopback_pcm {
unsigned long last_jiffies;
/* If jiffies timer is used */
struct timer_list timer;
+
+ /* size of per channel buffer in case of non-interleaved access */
+ unsigned int channel_buf_n;
};
static struct platform_device *devices[SNDRV_CARDS];
@@ -256,7 +262,7 @@ static int loopback_snd_timer_start(struct loopback_pcm *dpcm)
/* call in cable->lock */
static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm)
{
- del_timer(&dpcm->timer);
+ timer_delete(&dpcm->timer);
dpcm->timer.expires = 0;
return 0;
@@ -287,7 +293,7 @@ static int loopback_snd_timer_stop(struct loopback_pcm *dpcm)
static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm)
{
- del_timer_sync(&dpcm->timer);
+ timer_delete_sync(&dpcm->timer);
return 0;
}
@@ -317,6 +323,17 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
return 0;
}
+static bool is_access_interleaved(snd_pcm_access_t access)
+{
+ switch (access) {
+ case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
+ case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
+ return true;
+ default:
+ return false;
+ }
+};
+
static int loopback_check_format(struct loopback_cable *cable, int stream)
{
struct snd_pcm_runtime *runtime, *cruntime;
@@ -335,7 +352,9 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
substream->runtime;
check = runtime->format != cruntime->format ||
runtime->rate != cruntime->rate ||
- runtime->channels != cruntime->channels;
+ runtime->channels != cruntime->channels ||
+ is_access_interleaved(runtime->access) !=
+ is_access_interleaved(cruntime->access);
if (!check)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -363,6 +382,12 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
&setup->channels_id);
setup->channels = runtime->channels;
}
+ if (is_access_interleaved(setup->access) !=
+ is_access_interleaved(runtime->access)) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &setup->access_id);
+ setup->access = runtime->access;
+ }
}
return 0;
}
@@ -389,39 +414,39 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
dpcm->last_jiffies = jiffies;
dpcm->pcm_rate_shift = 0;
dpcm->last_drift = 0;
- spin_lock(&cable->lock);
- cable->running |= stream;
- cable->pause &= ~stream;
- err = cable->ops->start(dpcm);
- spin_unlock(&cable->lock);
+ scoped_guard(spinlock, &cable->lock) {
+ cable->running |= stream;
+ cable->pause &= ~stream;
+ err = cable->ops->start(dpcm);
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_STOP:
- spin_lock(&cable->lock);
- cable->running &= ~stream;
- cable->pause &= ~stream;
- err = cable->ops->stop(dpcm);
- spin_unlock(&cable->lock);
+ scoped_guard(spinlock, &cable->lock) {
+ cable->running &= ~stream;
+ cable->pause &= ~stream;
+ err = cable->ops->stop(dpcm);
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- spin_lock(&cable->lock);
- cable->pause |= stream;
- err = cable->ops->stop(dpcm);
- spin_unlock(&cable->lock);
+ scoped_guard(spinlock, &cable->lock) {
+ cable->pause |= stream;
+ err = cable->ops->stop(dpcm);
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- spin_lock(&cable->lock);
- dpcm->last_jiffies = jiffies;
- cable->pause &= ~stream;
- err = cable->ops->start(dpcm);
- spin_unlock(&cable->lock);
+ scoped_guard(spinlock, &cable->lock) {
+ dpcm->last_jiffies = jiffies;
+ cable->pause &= ~stream;
+ err = cable->ops->start(dpcm);
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm);
break;
@@ -472,6 +497,7 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
dpcm->buf_pos = 0;
dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+ dpcm->channel_buf_n = dpcm->pcm_buffer_size / runtime->channels;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
/* clear capture buffer */
dpcm->silent_size = dpcm->pcm_buffer_size;
@@ -485,13 +511,12 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
dpcm->pcm_salign = salign;
dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
- mutex_lock(&dpcm->loopback->cable_lock);
+ guard(mutex)(&dpcm->loopback->cable_lock);
if (!(cable->valid & ~(1 << substream->stream)) ||
(get_setup(dpcm)->notify &&
substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
params_change(substream);
cable->valid |= 1 << substream->stream;
- mutex_unlock(&dpcm->loopback->cable_lock);
return 0;
}
@@ -522,6 +547,22 @@ static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
}
}
+static void copy_play_buf_part_n(struct loopback_pcm *play, struct loopback_pcm *capt,
+ unsigned int size, unsigned int src_off, unsigned int dst_off)
+{
+ unsigned int channels = capt->substream->runtime->channels;
+ unsigned int size_p_ch = size / channels;
+ unsigned int src_off_ch = src_off / channels;
+ unsigned int dst_off_ch = dst_off / channels;
+ int i;
+
+ for (i = 0; i < channels; i++) {
+ memcpy(capt->substream->runtime->dma_area + capt->channel_buf_n * i + dst_off_ch,
+ play->substream->runtime->dma_area + play->channel_buf_n * i + src_off_ch,
+ size_p_ch);
+ }
+}
+
static void copy_play_buf(struct loopback_pcm *play,
struct loopback_pcm *capt,
unsigned int bytes)
@@ -556,7 +597,10 @@ static void copy_play_buf(struct loopback_pcm *play,
size = play->pcm_buffer_size - src_off;
if (dst_off + size > capt->pcm_buffer_size)
size = capt->pcm_buffer_size - dst_off;
- memcpy(dst + dst_off, src + src_off, size);
+ if (!is_access_interleaved(runtime->access))
+ copy_play_buf_part_n(play, capt, size, src_off, dst_off);
+ else
+ memcpy(dst + dst_off, src + src_off, size);
capt->silent_size = 0;
bytes -= size;
if (!bytes)
@@ -655,22 +699,23 @@ static unsigned int loopback_jiffies_timer_pos_update
static void loopback_jiffies_timer_function(struct timer_list *t)
{
- struct loopback_pcm *dpcm = from_timer(dpcm, t, timer);
- unsigned long flags;
-
- spin_lock_irqsave(&dpcm->cable->lock, flags);
- if (loopback_jiffies_timer_pos_update(dpcm->cable) &
- (1 << dpcm->substream->stream)) {
- loopback_jiffies_timer_start(dpcm);
- if (dpcm->period_update_pending) {
- dpcm->period_update_pending = 0;
- spin_unlock_irqrestore(&dpcm->cable->lock, flags);
- /* need to unlock before calling below */
- snd_pcm_period_elapsed(dpcm->substream);
- return;
+ struct loopback_pcm *dpcm = timer_container_of(dpcm, t, timer);
+ bool period_elapsed = false;
+
+ scoped_guard(spinlock_irqsave, &dpcm->cable->lock) {
+ if (loopback_jiffies_timer_pos_update(dpcm->cable) &
+ (1 << dpcm->substream->stream)) {
+ loopback_jiffies_timer_start(dpcm);
+ if (dpcm->period_update_pending) {
+ dpcm->period_update_pending = 0;
+ period_elapsed = true;
+ break;
+ }
}
}
- spin_unlock_irqrestore(&dpcm->cable->lock, flags);
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(dpcm->substream);
}
/* call in cable->lock */
@@ -715,68 +760,68 @@ static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable,
struct snd_pcm_substream *substream_play, *substream_capt;
struct snd_pcm_runtime *valid_runtime;
unsigned int running, elapsed_bytes;
- unsigned long flags;
+ bool xrun = false;
- spin_lock_irqsave(&cable->lock, flags);
- running = cable->running ^ cable->pause;
- /* no need to do anything if no stream is running */
- if (!running) {
- spin_unlock_irqrestore(&cable->lock, flags);
- return;
- }
+ scoped_guard(spinlock_irqsave, &cable->lock) {
+ running = cable->running ^ cable->pause;
+ /* no need to do anything if no stream is running */
+ if (!running)
+ return;
- dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
- dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+ dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+ dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
- if (event == SNDRV_TIMER_EVENT_MSTOP) {
- if (!dpcm_play ||
- dpcm_play->substream->runtime->state !=
- SNDRV_PCM_STATE_DRAINING) {
- spin_unlock_irqrestore(&cable->lock, flags);
- return;
+ if (event == SNDRV_TIMER_EVENT_MSTOP) {
+ if (!dpcm_play ||
+ dpcm_play->substream->runtime->state !=
+ SNDRV_PCM_STATE_DRAINING)
+ return;
}
- }
- substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+ substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
dpcm_play->substream : NULL;
- substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ?
+ substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ?
dpcm_capt->substream : NULL;
- valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
- dpcm_play->substream->runtime :
- dpcm_capt->substream->runtime;
-
- /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */
- if (event == SNDRV_TIMER_EVENT_TICK) {
- /* The hardware rules guarantee that playback and capture period
- * are the same. Therefore only one device has to be checked
- * here.
- */
- if (loopback_snd_timer_check_resolution(valid_runtime,
- resolution) < 0) {
- spin_unlock_irqrestore(&cable->lock, flags);
- if (substream_play)
- snd_pcm_stop_xrun(substream_play);
- if (substream_capt)
- snd_pcm_stop_xrun(substream_capt);
- return;
+ valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+ dpcm_play->substream->runtime :
+ dpcm_capt->substream->runtime;
+
+ /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */
+ if (event == SNDRV_TIMER_EVENT_TICK) {
+ /* The hardware rules guarantee that playback and capture period
+ * are the same. Therefore only one device has to be checked
+ * here.
+ */
+ if (loopback_snd_timer_check_resolution(valid_runtime,
+ resolution) < 0) {
+ xrun = true;
+ break;
+ }
+ }
+
+ elapsed_bytes = frames_to_bytes(valid_runtime,
+ valid_runtime->period_size);
+ /* The same timer interrupt is used for playback and capture device */
+ if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
+ (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) {
+ copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes);
+ bytepos_finish(dpcm_play, elapsed_bytes);
+ bytepos_finish(dpcm_capt, elapsed_bytes);
+ } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+ bytepos_finish(dpcm_play, elapsed_bytes);
+ } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+ clear_capture_buf(dpcm_capt, elapsed_bytes);
+ bytepos_finish(dpcm_capt, elapsed_bytes);
}
}
- elapsed_bytes = frames_to_bytes(valid_runtime,
- valid_runtime->period_size);
- /* The same timer interrupt is used for playback and capture device */
- if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
- (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) {
- copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes);
- bytepos_finish(dpcm_play, elapsed_bytes);
- bytepos_finish(dpcm_capt, elapsed_bytes);
- } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
- bytepos_finish(dpcm_play, elapsed_bytes);
- } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
- clear_capture_buf(dpcm_capt, elapsed_bytes);
- bytepos_finish(dpcm_capt, elapsed_bytes);
+ if (xrun) {
+ if (substream_play)
+ snd_pcm_stop_xrun(substream_play);
+ if (substream_capt)
+ snd_pcm_stop_xrun(substream_capt);
+ return;
}
- spin_unlock_irqrestore(&cable->lock, flags);
if (substream_play)
snd_pcm_period_elapsed(substream_play);
@@ -856,8 +901,7 @@ static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
cable->snd_timer.id.device,
cable->snd_timer.id.subdevice);
snd_iprintf(buffer, " timer open:\t\t%s\n",
- (cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ?
- "capture" : "playback");
+ snd_pcm_direction_name(cable->snd_timer.stream));
}
static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
@@ -866,11 +910,10 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
struct loopback_pcm *dpcm = runtime->private_data;
snd_pcm_uframes_t pos;
- spin_lock(&dpcm->cable->lock);
+ guard(spinlock)(&dpcm->cable->lock);
if (dpcm->cable->ops->pos_update)
dpcm->cable->ops->pos_update(dpcm->cable);
pos = dpcm->buf_pos;
- spin_unlock(&dpcm->cable->lock);
return bytes_to_frames(runtime, pos);
}
@@ -878,15 +921,18 @@ static const struct snd_pcm_hardware loopback_pcm_hardware =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NONINTERLEAVED),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
- SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE |
+ SNDRV_PCM_FMTBIT_DSD_U8 |
+ SNDRV_PCM_FMTBIT_DSD_U16_LE | SNDRV_PCM_FMTBIT_DSD_U16_BE |
+ SNDRV_PCM_FMTBIT_DSD_U32_LE | SNDRV_PCM_FMTBIT_DSD_U32_BE),
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_768000,
.rate_min = 8000,
- .rate_max = 192000,
+ .rate_max = 768000,
.channels_min = 1,
.channels_max = 32,
.buffer_bytes_max = 2 * 1024 * 1024,
@@ -911,9 +957,8 @@ static int loopback_hw_free(struct snd_pcm_substream *substream)
struct loopback_pcm *dpcm = runtime->private_data;
struct loopback_cable *cable = dpcm->cable;
- mutex_lock(&dpcm->loopback->cable_lock);
+ guard(mutex)(&dpcm->loopback->cable_lock);
cable->valid &= ~(1 << substream->stream);
- mutex_unlock(&dpcm->loopback->cable_lock);
return 0;
}
@@ -933,10 +978,10 @@ static int rule_format(struct snd_pcm_hw_params *params,
struct snd_mask m;
snd_mask_none(&m);
- mutex_lock(&dpcm->loopback->cable_lock);
- m.bits[0] = (u_int32_t)cable->hw.formats;
- m.bits[1] = (u_int32_t)(cable->hw.formats >> 32);
- mutex_unlock(&dpcm->loopback->cable_lock);
+ scoped_guard(mutex, &dpcm->loopback->cable_lock) {
+ m.bits[0] = (u_int32_t)cable->hw.formats;
+ m.bits[1] = (u_int32_t)(cable->hw.formats >> 32);
+ }
return snd_mask_refine(hw_param_mask(params, rule->var), &m);
}
@@ -947,10 +992,10 @@ static int rule_rate(struct snd_pcm_hw_params *params,
struct loopback_cable *cable = dpcm->cable;
struct snd_interval t;
- mutex_lock(&dpcm->loopback->cable_lock);
- t.min = cable->hw.rate_min;
- t.max = cable->hw.rate_max;
- mutex_unlock(&dpcm->loopback->cable_lock);
+ scoped_guard(mutex, &dpcm->loopback->cable_lock) {
+ t.min = cable->hw.rate_min;
+ t.max = cable->hw.rate_max;
+ }
t.openmin = t.openmax = 0;
t.integer = 0;
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
@@ -963,10 +1008,10 @@ static int rule_channels(struct snd_pcm_hw_params *params,
struct loopback_cable *cable = dpcm->cable;
struct snd_interval t;
- mutex_lock(&dpcm->loopback->cable_lock);
- t.min = cable->hw.channels_min;
- t.max = cable->hw.channels_max;
- mutex_unlock(&dpcm->loopback->cable_lock);
+ scoped_guard(mutex, &dpcm->loopback->cable_lock) {
+ t.min = cable->hw.channels_min;
+ t.max = cable->hw.channels_max;
+ }
t.openmin = t.openmax = 0;
t.integer = 0;
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
@@ -979,10 +1024,10 @@ static int rule_period_bytes(struct snd_pcm_hw_params *params,
struct loopback_cable *cable = dpcm->cable;
struct snd_interval t;
- mutex_lock(&dpcm->loopback->cable_lock);
- t.min = cable->hw.period_bytes_min;
- t.max = cable->hw.period_bytes_max;
- mutex_unlock(&dpcm->loopback->cable_lock);
+ scoped_guard(mutex, &dpcm->loopback->cable_lock) {
+ t.min = cable->hw.period_bytes_min;
+ t.max = cable->hw.period_bytes_max;
+ }
t.openmin = 0;
t.openmax = 0;
t.integer = 0;
@@ -1000,9 +1045,8 @@ static void free_cable(struct snd_pcm_substream *substream)
return;
if (cable->streams[!substream->stream]) {
/* other stream is still alive */
- spin_lock_irq(&cable->lock);
+ guard(spinlock_irq)(&cable->lock);
cable->streams[substream->stream] = NULL;
- spin_unlock_irq(&cable->lock);
} else {
struct loopback_pcm *dpcm = substream->runtime->private_data;
@@ -1083,6 +1127,8 @@ static int loopback_parse_timer_id(const char *str,
}
}
}
+ if (card_idx == -1)
+ tid->dev_class = SNDRV_TIMER_CLASS_GLOBAL;
if (!err && tid) {
tid->card = card_idx;
tid->device = dev;
@@ -1189,12 +1235,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
int err = 0;
int dev = get_cable_index(substream);
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
- if (!dpcm) {
- err = -ENOMEM;
- goto unlock;
- }
+ if (!dpcm)
+ return -ENOMEM;
dpcm->loopback = loopback;
dpcm->substream = substream;
@@ -1268,16 +1312,15 @@ static int loopback_open(struct snd_pcm_substream *substream)
else
runtime->hw = cable->hw;
- spin_lock_irq(&cable->lock);
- cable->streams[substream->stream] = dpcm;
- spin_unlock_irq(&cable->lock);
+ scoped_guard(spinlock_irq, &cable->lock) {
+ cable->streams[substream->stream] = dpcm;
+ }
unlock:
if (err < 0) {
free_cable(substream);
kfree(dpcm);
}
- mutex_unlock(&loopback->cable_lock);
return err;
}
@@ -1289,9 +1332,8 @@ static int loopback_close(struct snd_pcm_substream *substream)
if (dpcm->cable->ops->close_substream)
err = dpcm->cable->ops->close_substream(dpcm);
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
free_cable(substream);
- mutex_unlock(&loopback->cable_lock);
return err;
}
@@ -1320,7 +1362,7 @@ static int loopback_pcm_new(struct loopback *loopback,
pcm->private_data = loopback;
pcm->info_flags = 0;
- strcpy(pcm->name, "Loopback PCM");
+ strscpy(pcm->name, "Loopback PCM");
loopback->pcm[device] = pcm;
return 0;
@@ -1342,11 +1384,10 @@ static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
{
struct loopback *loopback = snd_kcontrol_chip(kcontrol);
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
ucontrol->value.integer.value[0] =
loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].rate_shift;
- mutex_unlock(&loopback->cable_lock);
return 0;
}
@@ -1362,14 +1403,13 @@ static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
val = 80000;
if (val > 120000)
val = 120000;
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
if (val != loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].rate_shift) {
loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].rate_shift = val;
change = 1;
}
- mutex_unlock(&loopback->cable_lock);
return change;
}
@@ -1378,11 +1418,10 @@ static int loopback_notify_get(struct snd_kcontrol *kcontrol,
{
struct loopback *loopback = snd_kcontrol_chip(kcontrol);
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
ucontrol->value.integer.value[0] =
loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].notify;
- mutex_unlock(&loopback->cable_lock);
return 0;
}
@@ -1394,14 +1433,13 @@ static int loopback_notify_put(struct snd_kcontrol *kcontrol,
int change = 0;
val = ucontrol->value.integer.value[0] ? 1 : 0;
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
if (val != loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].notify) {
loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].notify = val;
change = 1;
}
- mutex_unlock(&loopback->cable_lock);
return change;
}
@@ -1413,14 +1451,13 @@ static int loopback_active_get(struct snd_kcontrol *kcontrol,
unsigned int val = 0;
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
if (cable != NULL) {
unsigned int running = cable->running ^ cable->pause;
val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0;
}
- mutex_unlock(&loopback->cable_lock);
ucontrol->value.integer.value[0] = val;
return 0;
}
@@ -1463,11 +1500,10 @@ static int loopback_rate_get(struct snd_kcontrol *kcontrol,
{
struct loopback *loopback = snd_kcontrol_chip(kcontrol);
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
ucontrol->value.integer.value[0] =
loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].rate;
- mutex_unlock(&loopback->cable_lock);
return 0;
}
@@ -1487,11 +1523,32 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol,
{
struct loopback *loopback = snd_kcontrol_chip(kcontrol);
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
ucontrol->value.integer.value[0] =
loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].channels;
- mutex_unlock(&loopback->cable_lock);
+ return 0;
+}
+
+static int loopback_access_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ const char * const texts[] = {"Interleaved", "Non-interleaved"};
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int loopback_access_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+ snd_pcm_access_t access;
+
+ guard(mutex)(&loopback->cable_lock);
+ access = loopback->setup[kcontrol->id.subdevice][kcontrol->id.device].access;
+
+ ucontrol->value.enumerated.item[0] = !is_access_interleaved(access);
+
return 0;
}
@@ -1541,7 +1598,15 @@ static const struct snd_kcontrol_new loopback_controls[] = {
.name = "PCM Slave Channels",
.info = loopback_channels_info,
.get = loopback_channels_get
-}
+},
+#define ACCESS_IDX 6
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Slave Access Mode",
+ .info = loopback_access_info,
+ .get = loopback_access_get,
+},
};
static int loopback_mixer_new(struct loopback *loopback, int notify)
@@ -1552,7 +1617,7 @@ static int loopback_mixer_new(struct loopback *loopback, int notify)
struct loopback_setup *setup;
int err, dev, substr, substr_count, idx;
- strcpy(card->mixername, "Loopback Mixer");
+ strscpy(card->mixername, "Loopback Mixer");
for (dev = 0; dev < 2; dev++) {
pcm = loopback->pcm[dev];
substr_count =
@@ -1562,6 +1627,7 @@ static int loopback_mixer_new(struct loopback *loopback, int notify)
setup->notify = notify;
setup->rate_shift = NO_PITCH;
setup->format = SNDRV_PCM_FORMAT_S16_LE;
+ setup->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
setup->rate = 48000;
setup->channels = 2;
for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
@@ -1593,6 +1659,9 @@ static int loopback_mixer_new(struct loopback *loopback, int notify)
case CHANNELS_IDX:
setup->channels_id = kctl->id;
break;
+ case ACCESS_IDX:
+ setup->access_id = kctl->id;
+ break;
default:
break;
}
@@ -1647,12 +1716,11 @@ static void print_cable_info(struct snd_info_entry *entry,
struct loopback *loopback = entry->private_data;
int sub, num;
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
num = entry->name[strlen(entry->name)-1];
num = num == '0' ? 0 : 1;
for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
print_substream_info(buffer, loopback, sub, num);
- mutex_unlock(&loopback->cable_lock);
}
static int loopback_cable_proc_new(struct loopback *loopback, int cidx)
@@ -1681,10 +1749,9 @@ static void print_timer_source_info(struct snd_info_entry *entry,
{
struct loopback *loopback = entry->private_data;
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
snd_iprintf(buffer, "%s\n",
loopback->timer_source ? loopback->timer_source : "");
- mutex_unlock(&loopback->cable_lock);
}
static void change_timer_source_info(struct snd_info_entry *entry,
@@ -1693,10 +1760,9 @@ static void change_timer_source_info(struct snd_info_entry *entry,
struct loopback *loopback = entry->private_data;
char line[64];
- mutex_lock(&loopback->cable_lock);
+ guard(mutex)(&loopback->cable_lock);
if (!snd_info_get_line(buffer, line, sizeof(line)))
loopback_set_timer_source(loopback, strim(line));
- mutex_unlock(&loopback->cable_lock);
}
static int loopback_timer_source_proc_new(struct loopback *loopback)
@@ -1741,8 +1807,8 @@ static int loopback_probe(struct platform_device *devptr)
loopback_cable_proc_new(loopback, 0);
loopback_cable_proc_new(loopback, 1);
loopback_timer_source_proc_new(loopback);
- strcpy(card->driver, "Loopback");
- strcpy(card->shortname, "Loopback");
+ strscpy(card->driver, "Loopback");
+ strscpy(card->shortname, "Loopback");
sprintf(card->longname, "Loopback %i", dev + 1);
err = snd_card_register(card);
if (err < 0)
@@ -1751,7 +1817,6 @@ static int loopback_probe(struct platform_device *devptr)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int loopback_suspend(struct device *pdev)
{
struct snd_card *card = dev_get_drvdata(pdev);
@@ -1768,11 +1833,7 @@ static int loopback_resume(struct device *pdev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume);
-#define LOOPBACK_PM_OPS &loopback_pm
-#else
-#define LOOPBACK_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume);
#define SND_LOOPBACK_DRIVER "snd_aloop"
@@ -1780,7 +1841,7 @@ static struct platform_driver loopback_driver = {
.probe = loopback_probe,
.driver = {
.name = SND_LOOPBACK_DRIVER,
- .pm = LOOPBACK_PM_OPS,
+ .pm = &loopback_pm,
},
};
@@ -1820,7 +1881,7 @@ static int __init alsa_card_loopback_init(void)
}
if (!cards) {
#ifdef MODULE
- printk(KERN_ERR "aloop: No loopback enabled\n");
+ pr_err("aloop: No loopback enabled\n");
#endif
loopback_unregister_all();
return -ENODEV;
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 9c17b49a2ae1..1860ff75fe15 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/hrtimer.h>
@@ -268,19 +269,19 @@ static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
static int dummy_systimer_start(struct snd_pcm_substream *substream)
{
struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
- spin_lock(&dpcm->lock);
+
+ guard(spinlock)(&dpcm->lock);
dpcm->base_time = jiffies;
dummy_systimer_rearm(dpcm);
- spin_unlock(&dpcm->lock);
return 0;
}
static int dummy_systimer_stop(struct snd_pcm_substream *substream)
{
struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
- spin_lock(&dpcm->lock);
- del_timer(&dpcm->timer);
- spin_unlock(&dpcm->lock);
+
+ guard(spinlock)(&dpcm->lock);
+ timer_delete(&dpcm->timer);
return 0;
}
@@ -301,16 +302,15 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
static void dummy_systimer_callback(struct timer_list *t)
{
- struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer);
- unsigned long flags;
+ struct dummy_systimer_pcm *dpcm = timer_container_of(dpcm, t, timer);
int elapsed = 0;
- spin_lock_irqsave(&dpcm->lock, flags);
- dummy_systimer_update(dpcm);
- dummy_systimer_rearm(dpcm);
- elapsed = dpcm->elapsed;
- dpcm->elapsed = 0;
- spin_unlock_irqrestore(&dpcm->lock, flags);
+ scoped_guard(spinlock_irqsave, &dpcm->lock) {
+ dummy_systimer_update(dpcm);
+ dummy_systimer_rearm(dpcm);
+ elapsed = dpcm->elapsed;
+ dpcm->elapsed = 0;
+ }
if (elapsed)
snd_pcm_period_elapsed(dpcm->substream);
}
@@ -319,13 +319,10 @@ static snd_pcm_uframes_t
dummy_systimer_pointer(struct snd_pcm_substream *substream)
{
struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
- snd_pcm_uframes_t pos;
- spin_lock(&dpcm->lock);
+ guard(spinlock)(&dpcm->lock);
dummy_systimer_update(dpcm);
- pos = dpcm->frac_pos / HZ;
- spin_unlock(&dpcm->lock);
- return pos;
+ return dpcm->frac_pos / HZ;
}
static int dummy_systimer_create(struct snd_pcm_substream *substream)
@@ -457,8 +454,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;
@@ -626,14 +622,7 @@ static int alloc_fake_buffer(void)
static int dummy_pcm_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long bytes)
-{
- return 0; /* do nothing */
-}
-
-static int dummy_pcm_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long bytes)
+ struct iov_iter *iter, unsigned long bytes)
{
return 0; /* do nothing */
}
@@ -667,8 +656,7 @@ static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {
.prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger,
.pointer = dummy_pcm_pointer,
- .copy_user = dummy_pcm_copy,
- .copy_kernel = dummy_pcm_copy_kernel,
+ .copy = dummy_pcm_copy,
.fill_silence = dummy_pcm_silence,
.page = dummy_pcm_page,
};
@@ -693,7 +681,7 @@ static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);
pcm->private_data = dummy;
pcm->info_flags = 0;
- strcpy(pcm->name, "Dummy PCM");
+ strscpy(pcm->name, "Dummy PCM");
if (!fake_buffer) {
snd_pcm_set_managed_buffer_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
@@ -732,10 +720,9 @@ static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,
struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
int addr = kcontrol->private_value;
- spin_lock_irq(&dummy->mixer_lock);
+ guard(spinlock_irq)(&dummy->mixer_lock);
ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];
ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];
- spin_unlock_irq(&dummy->mixer_lock);
return 0;
}
@@ -756,12 +743,11 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
right = mixer_volume_level_min;
if (right > mixer_volume_level_max)
right = mixer_volume_level_max;
- spin_lock_irq(&dummy->mixer_lock);
+ guard(spinlock_irq)(&dummy->mixer_lock);
change = dummy->mixer_volume[addr][0] != left ||
dummy->mixer_volume[addr][1] != right;
dummy->mixer_volume[addr][0] = left;
dummy->mixer_volume[addr][1] = right;
- spin_unlock_irq(&dummy->mixer_lock);
return change;
}
@@ -781,10 +767,9 @@ static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,
struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
int addr = kcontrol->private_value;
- spin_lock_irq(&dummy->mixer_lock);
+ guard(spinlock_irq)(&dummy->mixer_lock);
ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];
ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];
- spin_unlock_irq(&dummy->mixer_lock);
return 0;
}
@@ -796,12 +781,11 @@ static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
left = ucontrol->value.integer.value[0] & 1;
right = ucontrol->value.integer.value[1] & 1;
- spin_lock_irq(&dummy->mixer_lock);
+ guard(spinlock_irq)(&dummy->mixer_lock);
change = dummy->capture_source[addr][0] != left &&
dummy->capture_source[addr][1] != right;
dummy->capture_source[addr][0] = left;
dummy->capture_source[addr][1] = right;
- spin_unlock_irq(&dummy->mixer_lock);
return change;
}
@@ -884,7 +868,7 @@ static int snd_card_dummy_new_mixer(struct snd_dummy *dummy)
int err;
spin_lock_init(&dummy->mixer_lock);
- strcpy(card->mixername, "Dummy Mixer");
+ strscpy(card->mixername, "Dummy Mixer");
dummy->iobox = 1;
for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
@@ -1041,8 +1025,7 @@ static int snd_dummy_probe(struct platform_device *devptr)
dummy->card = card;
for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
if (strcmp(model[dev], (*mdl)->name) == 0) {
- printk(KERN_INFO
- "snd-dummy: Using model '%s' for card %i\n",
+ pr_info("snd-dummy: Using model '%s' for card %i\n",
(*mdl)->name, card->number);
m = dummy->model = *mdl;
break;
@@ -1093,8 +1076,8 @@ static int snd_dummy_probe(struct platform_device *devptr)
err = snd_card_dummy_new_mixer(dummy);
if (err < 0)
return err;
- strcpy(card->driver, "Dummy");
- strcpy(card->shortname, "Dummy");
+ strscpy(card->driver, "Dummy");
+ strscpy(card->shortname, "Dummy");
sprintf(card->longname, "Dummy %i", dev + 1);
dummy_proc_init(dummy);
@@ -1106,7 +1089,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int snd_dummy_suspend(struct device *pdev)
{
struct snd_card *card = dev_get_drvdata(pdev);
@@ -1123,11 +1105,7 @@ static int snd_dummy_resume(struct device *pdev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);
-#define SND_DUMMY_PM_OPS &snd_dummy_pm
-#else
-#define SND_DUMMY_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);
#define SND_DUMMY_DRIVER "snd_dummy"
@@ -1135,7 +1113,7 @@ static struct platform_driver snd_dummy_driver = {
.probe = snd_dummy_probe,
.driver = {
.name = SND_DUMMY_DRIVER,
- .pm = SND_DUMMY_PM_OPS,
+ .pm = &snd_dummy_pm,
},
};
@@ -1181,7 +1159,7 @@ static int __init alsa_card_dummy_init(void)
}
if (!cards) {
#ifdef MODULE
- printk(KERN_ERR "Dummy soundcard not found or device busy\n");
+ pr_err("Dummy soundcard not found or device busy\n");
#endif
snd_dummy_unregister_all();
return -ENODEV;
diff --git a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile
index 3dfd5b374c4f..0a96e238ee92 100644
--- a/sound/drivers/mpu401/Makefile
+++ b/sound/drivers/mpu401/Makefile
@@ -4,8 +4,8 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-mpu401-objs := mpu401.o
-snd-mpu401-uart-objs := mpu401_uart.o
+snd-mpu401-y := mpu401.o
+snd-mpu401-uart-y := mpu401_uart.o
obj-$(CONFIG_SND_MPU401_UART) += snd-mpu401-uart.o
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 3398aee33baa..d3f9424088d4 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -56,15 +56,15 @@ static int snd_mpu401_create(struct device *devptr, int dev,
int err;
if (!uart_enter[dev])
- snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
+ dev_err(devptr, "the uart_enter option is obsolete; remove it\n");
*rcard = NULL;
err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0)
return err;
- strcpy(card->driver, "MPU-401 UART");
- strcpy(card->shortname, card->driver);
+ strscpy(card->driver, "MPU-401 UART");
+ strscpy(card->shortname, card->driver);
sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);
if (irq[dev] >= 0) {
sprintf(card->longname + strlen(card->longname), "irq %d", irq[dev]);
@@ -75,7 +75,7 @@ static int snd_mpu401_create(struct device *devptr, int dev,
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0,
irq[dev], NULL);
if (err < 0) {
- printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]);
+ dev_err(devptr, "MPU401 not detected at 0x%lx\n", port[dev]);
return err;
}
@@ -90,11 +90,11 @@ static int snd_mpu401_probe(struct platform_device *devptr)
struct snd_card *card;
if (port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "specify port\n");
+ dev_err(&devptr->dev, "specify port\n");
return -EINVAL;
}
if (irq[dev] == SNDRV_AUTO_IRQ) {
- snd_printk(KERN_ERR "specify or disable IRQ\n");
+ dev_err(&devptr->dev, "specify or disable IRQ\n");
return -EINVAL;
}
err = snd_mpu401_create(&devptr->dev, dev, &card);
@@ -133,11 +133,11 @@ static int snd_mpu401_pnp(int dev, struct pnp_dev *device,
{
if (!pnp_port_valid(device, 0) ||
pnp_port_flags(device, 0) & IORESOURCE_DISABLED) {
- snd_printk(KERN_ERR "no PnP port\n");
+ dev_err(&device->dev, "no PnP port\n");
return -ENODEV;
}
if (pnp_port_len(device, 0) < IO_EXTENT) {
- snd_printk(KERN_ERR "PnP port length is %llu, expected %d\n",
+ dev_err(&device->dev, "PnP port length is %llu, expected %d\n",
(unsigned long long)pnp_port_len(device, 0),
IO_EXTENT);
return -ENODEV;
@@ -146,7 +146,7 @@ static int snd_mpu401_pnp(int dev, struct pnp_dev *device,
if (!pnp_irq_valid(device, 0) ||
pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) {
- snd_printk(KERN_WARNING "no PnP irq, using polling\n");
+ dev_warn(&device->dev, "no PnP irq, using polling\n");
irq[dev] = -1;
} else {
irq[dev] = pnp_irq(device, 0);
@@ -234,7 +234,7 @@ static int __init alsa_card_mpu401_init(void)
if (!snd_mpu401_devices) {
#ifdef MODULE
- printk(KERN_ERR "MPU-401 device not found or device busy\n");
+ pr_err("MPU-401 device not found or device busy\n");
#endif
snd_mpu401_unregister_all();
return -ENODEV;
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index f435b9b4ae24..4af89822bf32 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -73,34 +73,29 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu)
mpu->read(mpu, MPU401D(mpu));
#ifdef CONFIG_SND_DEBUG
if (timeout <= 0)
- snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n",
- mpu->read(mpu, MPU401C(mpu)));
+ dev_err(mpu->rmidi->dev,
+ "cmd: clear rx timeout (status = 0x%x)\n",
+ mpu->read(mpu, MPU401C(mpu)));
#endif
}
static void uart_interrupt_tx(struct snd_mpu401 *mpu)
{
- unsigned long flags;
-
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
- spin_lock_irqsave(&mpu->output_lock, flags);
+ guard(spinlock_irqsave)(&mpu->output_lock);
snd_mpu401_uart_output_write(mpu);
- spin_unlock_irqrestore(&mpu->output_lock, flags);
}
}
static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
{
- unsigned long flags;
-
if (mpu->info_flags & MPU401_INFO_INPUT) {
- spin_lock_irqsave(&mpu->input_lock, flags);
+ guard(spinlock_irqsave)(&mpu->input_lock);
if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
snd_mpu401_uart_input_read(mpu);
else
snd_mpu401_uart_clear_rx(mpu);
- spin_unlock_irqrestore(&mpu->input_lock, flags);
}
if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
/* ok. for better Tx performance try do some output
@@ -156,13 +151,12 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx);
*/
static void snd_mpu401_uart_timer(struct timer_list *t)
{
- struct snd_mpu401 *mpu = from_timer(mpu, t, timer);
- unsigned long flags;
+ struct snd_mpu401 *mpu = timer_container_of(mpu, t, timer);
- spin_lock_irqsave(&mpu->timer_lock, flags);
- /*mpu->mode |= MPU401_MODE_TIMER;*/
- mod_timer(&mpu->timer, 1 + jiffies);
- spin_unlock_irqrestore(&mpu->timer_lock, flags);
+ scoped_guard(spinlock_irqsave, &mpu->timer_lock) {
+ /*mpu->mode |= MPU401_MODE_TIMER;*/
+ mod_timer(&mpu->timer, 1 + jiffies);
+ }
if (mpu->rmidi)
_snd_mpu401_uart_interrupt(mpu);
}
@@ -172,16 +166,13 @@ static void snd_mpu401_uart_timer(struct timer_list *t)
*/
static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
{
- unsigned long flags;
-
- spin_lock_irqsave (&mpu->timer_lock, flags);
+ guard(spinlock_irqsave)(&mpu->timer_lock);
if (mpu->timer_invoked == 0) {
timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0);
mod_timer(&mpu->timer, 1 + jiffies);
}
mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
MPU401_MODE_OUTPUT_TIMER;
- spin_unlock_irqrestore (&mpu->timer_lock, flags);
}
/*
@@ -189,16 +180,13 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
*/
static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
{
- unsigned long flags;
-
- spin_lock_irqsave (&mpu->timer_lock, flags);
+ guard(spinlock_irqsave)(&mpu->timer_lock);
if (mpu->timer_invoked) {
mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER :
~MPU401_MODE_OUTPUT_TIMER;
if (! mpu->timer_invoked)
- del_timer(&mpu->timer);
+ timer_delete(&mpu->timer);
}
- spin_unlock_irqrestore (&mpu->timer_lock, flags);
}
/*
@@ -209,10 +197,9 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
int ack)
{
- unsigned long flags;
int timeout, ok;
- spin_lock_irqsave(&mpu->input_lock, flags);
+ guard(spinlock_irqsave)(&mpu->input_lock);
if (mpu->hardware != MPU401_HW_TRID4DWAVE) {
mpu->write(mpu, 0x00, MPU401D(mpu));
/*snd_mpu401_uart_clear_rx(mpu);*/
@@ -224,8 +211,9 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
udelay(10);
#ifdef CONFIG_SND_DEBUG
if (!timeout)
- snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n",
- mpu->read(mpu, MPU401C(mpu)));
+ dev_err(mpu->rmidi->dev,
+ "cmd: tx timeout (status = 0x%x)\n",
+ mpu->read(mpu, MPU401C(mpu)));
#endif
}
mpu->write(mpu, cmd, MPU401C(mpu));
@@ -242,12 +230,12 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
ok = 1;
} else
ok = 1;
- spin_unlock_irqrestore(&mpu->input_lock, flags);
if (!ok) {
- snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx "
- "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port,
- mpu->read(mpu, MPU401C(mpu)),
- mpu->read(mpu, MPU401D(mpu)));
+ dev_err(mpu->rmidi->dev,
+ "cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n",
+ cmd, mpu->port,
+ mpu->read(mpu, MPU401C(mpu)),
+ mpu->read(mpu, MPU401D(mpu)));
return 1;
}
return 0;
@@ -355,7 +343,6 @@ static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream)
static void
snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct snd_mpu401 *mpu;
int max = 64;
@@ -371,9 +358,8 @@ snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
}
/* read data in advance */
- spin_lock_irqsave(&mpu->input_lock, flags);
+ guard(spinlock_irqsave)(&mpu->input_lock);
snd_mpu401_uart_input_read(mpu);
- spin_unlock_irqrestore(&mpu->input_lock, flags);
} else {
if (mpu->info_flags & MPU401_INFO_USE_TIMER)
snd_mpu401_uart_remove_timer(mpu, 1);
@@ -442,7 +428,6 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
static void
snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct snd_mpu401 *mpu;
mpu = substream->rmidi->private_data;
@@ -457,9 +442,8 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
snd_mpu401_uart_add_timer(mpu, 0);
/* output pending data */
- spin_lock_irqsave(&mpu->output_lock, flags);
+ guard(spinlock_irqsave)(&mpu->output_lock);
snd_mpu401_uart_output_write(mpu);
- spin_unlock_irqrestore(&mpu->output_lock, flags);
} else {
if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
snd_mpu401_uart_remove_timer(mpu, 0);
@@ -546,13 +530,14 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
spin_lock_init(&mpu->timer_lock);
mpu->hardware = hardware;
mpu->irq = -1;
+ mpu->rmidi = rmidi;
if (! (info_flags & MPU401_INFO_INTEGRATED)) {
int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
mpu->res = request_region(port, res_size, "MPU401 UART");
if (!mpu->res) {
- snd_printk(KERN_ERR "mpu401_uart: "
- "unable to grab port 0x%lx size %d\n",
- port, res_size);
+ dev_err(rmidi->dev,
+ "mpu401_uart: unable to grab port 0x%lx size %d\n",
+ port, res_size);
err = -EBUSY;
goto free_device;
}
@@ -572,8 +557,8 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
if (irq >= 0) {
if (request_irq(irq, snd_mpu401_uart_interrupt, 0,
"MPU401 UART", (void *) mpu)) {
- snd_printk(KERN_ERR "mpu401_uart: "
- "unable to grab IRQ %d\n", irq);
+ dev_err(rmidi->dev,
+ "mpu401_uart: unable to grab IRQ %d\n", irq);
err = -EBUSY;
goto free_device;
}
@@ -599,7 +584,6 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
if (out_enable)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
}
- mpu->rmidi = rmidi;
if (rrawmidi)
*rrawmidi = rmidi;
return 0;
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index f212f233ea61..d31eadf4be5f 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -46,6 +46,7 @@
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include <linux/delay.h>
+#include <linux/string.h>
/*
* globals
@@ -285,10 +286,6 @@ static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
snd_mtpav_send_byte(mtp_card, 0xf5);
snd_mtpav_send_byte(mtp_card, portp->hwport);
- /*
- snd_printk(KERN_DEBUG "new outport: 0x%x\n",
- (unsigned int) portp->hwport);
- */
if (!(outbyte & 0x80) && portp->running_status)
snd_mtpav_send_byte(mtp_card, portp->running_status);
}
@@ -307,11 +304,9 @@ static void snd_mtpav_output_write(struct snd_rawmidi_substream *substream)
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
- spin_lock_irqsave(&mtp_card->spinlock, flags);
+ guard(spinlock_irqsave)(&mtp_card->spinlock);
snd_mtpav_output_port_write(mtp_card, portp, substream);
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
}
@@ -337,14 +332,12 @@ static int snd_mtpav_input_open(struct snd_rawmidi_substream *substream)
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
- spin_lock_irqsave(&mtp_card->spinlock, flags);
+ guard(spinlock_irqsave)(&mtp_card->spinlock);
portp->mode |= MTPAV_MODE_INPUT_OPENED;
portp->input = substream;
if (mtp_card->share_irq++ == 0)
snd_mtpav_mputreg(mtp_card, CREG, (SIGC_INTEN | SIGC_WRITE)); // enable pport interrupts
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
return 0;
}
@@ -355,14 +348,12 @@ static int snd_mtpav_input_close(struct snd_rawmidi_substream *substream)
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
- spin_lock_irqsave(&mtp_card->spinlock, flags);
+ guard(spinlock_irqsave)(&mtp_card->spinlock);
portp->mode &= ~MTPAV_MODE_INPUT_OPENED;
portp->input = NULL;
if (--mtp_card->share_irq == 0)
snd_mtpav_mputreg(mtp_card, CREG, 0); // disable pport interrupts
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
return 0;
}
@@ -373,15 +364,12 @@ static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
- spin_lock_irqsave(&mtp_card->spinlock, flags);
+ guard(spinlock_irqsave)(&mtp_card->spinlock);
if (up)
portp->mode |= MTPAV_MODE_INPUT_TRIGGERED;
else
portp->mode &= ~MTPAV_MODE_INPUT_TRIGGERED;
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
-
}
@@ -391,11 +379,10 @@ static void snd_mtpav_input_trigger(struct snd_rawmidi_substream *substream, int
static void snd_mtpav_output_timer(struct timer_list *t)
{
- unsigned long flags;
- struct mtpav *chip = from_timer(chip, t, timer);
+ struct mtpav *chip = timer_container_of(chip, t, timer);
int p;
- spin_lock_irqsave(&chip->spinlock, flags);
+ guard(spinlock_irqsave)(&chip->spinlock);
/* reprogram timer */
mod_timer(&chip->timer, 1 + jiffies);
/* process each port */
@@ -404,7 +391,6 @@ static void snd_mtpav_output_timer(struct timer_list *t)
if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED) && portp->output)
snd_mtpav_output_port_write(chip, portp, portp->output);
}
- spin_unlock_irqrestore(&chip->spinlock, flags);
}
/* spinlock held! */
@@ -416,7 +402,7 @@ static void snd_mtpav_add_output_timer(struct mtpav *chip)
/* spinlock held! */
static void snd_mtpav_remove_output_timer(struct mtpav *chip)
{
- del_timer(&chip->timer);
+ timer_delete(&chip->timer);
}
/*
@@ -426,12 +412,10 @@ static int snd_mtpav_output_open(struct snd_rawmidi_substream *substream)
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
- spin_lock_irqsave(&mtp_card->spinlock, flags);
+ guard(spinlock_irqsave)(&mtp_card->spinlock);
portp->mode |= MTPAV_MODE_OUTPUT_OPENED;
portp->output = substream;
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
return 0;
};
@@ -442,12 +426,10 @@ static int snd_mtpav_output_close(struct snd_rawmidi_substream *substream)
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
- spin_lock_irqsave(&mtp_card->spinlock, flags);
+ guard(spinlock_irqsave)(&mtp_card->spinlock);
portp->mode &= ~MTPAV_MODE_OUTPUT_OPENED;
portp->output = NULL;
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
return 0;
};
@@ -458,21 +440,20 @@ static void snd_mtpav_output_trigger(struct snd_rawmidi_substream *substream, in
{
struct mtpav *mtp_card = substream->rmidi->private_data;
struct mtpav_port *portp = &mtp_card->ports[substream->number];
- unsigned long flags;
-
- spin_lock_irqsave(&mtp_card->spinlock, flags);
- if (up) {
- if (! (portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) {
- if (mtp_card->istimer++ == 0)
- snd_mtpav_add_output_timer(mtp_card);
- portp->mode |= MTPAV_MODE_OUTPUT_TRIGGERED;
+
+ scoped_guard(spinlock_irqsave, &mtp_card->spinlock) {
+ if (up) {
+ if ((portp->mode & MTPAV_MODE_OUTPUT_TRIGGERED)) {
+ if (mtp_card->istimer++ == 0)
+ snd_mtpav_add_output_timer(mtp_card);
+ portp->mode |= MTPAV_MODE_OUTPUT_TRIGGERED;
+ }
+ } else {
+ portp->mode &= ~MTPAV_MODE_OUTPUT_TRIGGERED;
+ if (--mtp_card->istimer == 0)
+ snd_mtpav_remove_output_timer(mtp_card);
}
- } else {
- portp->mode &= ~MTPAV_MODE_OUTPUT_TRIGGERED;
- if (--mtp_card->istimer == 0)
- snd_mtpav_remove_output_timer(mtp_card);
}
- spin_unlock_irqrestore(&mtp_card->spinlock, flags);
if (up)
snd_mtpav_output_write(substream);
@@ -522,8 +503,6 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd)
u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
- /* printk(KERN_DEBUG "snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt); */
-
if (!(sbyt & SIGS_BYTE))
return;
@@ -555,9 +534,8 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
{
struct mtpav *mcard = dev_id;
- spin_lock(&mcard->spinlock);
+ guard(spinlock)(&mcard->spinlock);
snd_mtpav_read_bytes(mcard);
- spin_unlock(&mcard->spinlock);
return IRQ_HANDLED;
}
@@ -569,13 +547,13 @@ static int snd_mtpav_get_ISA(struct mtpav *mcard)
mcard->res_port = devm_request_region(mcard->card->dev, port, 3,
"MotuMTPAV MIDI");
if (!mcard->res_port) {
- snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
+ dev_err(mcard->card->dev, "MTVAP port 0x%lx is busy\n", port);
return -EBUSY;
}
mcard->port = port;
if (devm_request_irq(mcard->card->dev, irq, snd_mtpav_irqh, 0,
"MOTU MTPAV", mcard)) {
- snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
+ dev_err(mcard->card->dev, "MTVAP IRQ %d busy\n", irq);
return -EBUSY;
}
mcard->irq = irq;
@@ -611,11 +589,11 @@ static void snd_mtpav_set_name(struct mtpav *chip,
else if (substream->number >= 8 && substream->number < chip->num_ports * 2)
sprintf(substream->name, "MTP remote %d", (substream->number % chip->num_ports) + 1);
else if (substream->number == chip->num_ports * 2)
- strcpy(substream->name, "MTP computer");
+ strscpy(substream->name, "MTP computer");
else if (substream->number == chip->num_ports * 2 + 1)
- strcpy(substream->name, "MTP ADAT");
+ strscpy(substream->name, "MTP ADAT");
else
- strcpy(substream->name, "MTP broadcast");
+ strscpy(substream->name, "MTP broadcast");
}
static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
@@ -663,12 +641,10 @@ static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
static void snd_mtpav_free(struct snd_card *card)
{
struct mtpav *crd = card->private_data;
- unsigned long flags;
- spin_lock_irqsave(&crd->spinlock, flags);
+ guard(spinlock_irqsave)(&crd->spinlock);
if (crd->istimer > 0)
snd_mtpav_remove_output_timer(crd);
- spin_unlock_irqrestore(&crd->spinlock, flags);
}
/*
@@ -703,8 +679,8 @@ static int snd_mtpav_probe(struct platform_device *dev)
if (err < 0)
return err;
- strcpy(card->driver, "MTPAV");
- strcpy(card->shortname, "MTPAV on parallel port");
+ strscpy(card->driver, "MTPAV");
+ strscpy(card->shortname, "MTPAV on parallel port");
snprintf(card->longname, sizeof(card->longname),
"MTPAV on parallel port at 0x%lx", port);
@@ -717,7 +693,9 @@ static int snd_mtpav_probe(struct platform_device *dev)
card->private_free = snd_mtpav_free;
platform_set_drvdata(dev, card);
- printk(KERN_INFO "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", irq, port);
+ dev_info(card->dev,
+ "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n",
+ irq, port);
return 0;
}
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index 5cfd0e99a13f..fe50b48c10e7 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
@@ -431,9 +432,8 @@ static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl,
{
struct mts64 *mts = snd_kcontrol_chip(kctl);
- spin_lock_irq(&mts->lock);
+ guard(spinlock_irq)(&mts->lock);
uctl->value.integer.value[0] = mts->smpte_switch;
- spin_unlock_irq(&mts->lock);
return 0;
}
@@ -444,14 +444,12 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl,
struct snd_ctl_elem_value *uctl)
{
struct mts64 *mts = snd_kcontrol_chip(kctl);
- int changed = 0;
int val = !!uctl->value.integer.value[0];
- spin_lock_irq(&mts->lock);
+ guard(spinlock_irq)(&mts->lock);
if (mts->smpte_switch == val)
- goto __out;
+ return 0;
- changed = 1;
mts->smpte_switch = val;
if (mts->smpte_switch) {
mts64_smpte_start(mts->pardev->port,
@@ -461,9 +459,7 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl,
} else {
mts64_smpte_stop(mts->pardev->port);
}
-__out:
- spin_unlock_irq(&mts->lock);
- return changed;
+ return 1;
}
static const struct snd_kcontrol_new mts64_ctl_smpte_switch = {
@@ -514,9 +510,8 @@ static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl,
struct mts64 *mts = snd_kcontrol_chip(kctl);
int idx = kctl->private_value;
- spin_lock_irq(&mts->lock);
+ guard(spinlock_irq)(&mts->lock);
uctl->value.integer.value[0] = mts->time[idx];
- spin_unlock_irq(&mts->lock);
return 0;
}
@@ -527,16 +522,14 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl,
struct mts64 *mts = snd_kcontrol_chip(kctl);
int idx = kctl->private_value;
unsigned int time = uctl->value.integer.value[0] % 60;
- int changed = 0;
- spin_lock_irq(&mts->lock);
+ guard(spinlock_irq)(&mts->lock);
if (mts->time[idx] != time) {
- changed = 1;
mts->time[idx] = time;
+ return 1;
}
- spin_unlock_irq(&mts->lock);
- return changed;
+ return 0;
}
static const struct snd_kcontrol_new mts64_ctl_smpte_time_hours = {
@@ -599,9 +592,8 @@ static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl,
{
struct mts64 *mts = snd_kcontrol_chip(kctl);
- spin_lock_irq(&mts->lock);
+ guard(spinlock_irq)(&mts->lock);
uctl->value.enumerated.item[0] = mts->fps;
- spin_unlock_irq(&mts->lock);
return 0;
}
@@ -610,18 +602,16 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uctl)
{
struct mts64 *mts = snd_kcontrol_chip(kctl);
- int changed = 0;
if (uctl->value.enumerated.item[0] >= 5)
return -EINVAL;
- spin_lock_irq(&mts->lock);
+ guard(spinlock_irq)(&mts->lock);
if (mts->fps != uctl->value.enumerated.item[0]) {
- changed = 1;
mts->fps = uctl->value.enumerated.item[0];
+ return 1;
}
- spin_unlock_irq(&mts->lock);
- return changed;
+ return 0;
}
static const struct snd_kcontrol_new mts64_ctl_smpte_fps = {
@@ -652,8 +642,8 @@ static int snd_mts64_ctl_create(struct snd_card *card,
for (i = 0; control[i]; ++i) {
err = snd_ctl_add(card, snd_ctl_new1(control[i], mts));
if (err < 0) {
- snd_printd("Cannot create control: %s\n",
- control[i]->name);
+ dev_dbg(card->dev, "Cannot create control: %s\n",
+ control[i]->name);
return err;
}
}
@@ -686,15 +676,14 @@ static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream)
static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream)
{
struct mts64 *mts = substream->rmidi->private_data;
- unsigned long flags;
--(mts->open_count);
if (mts->open_count == 0) {
/* We need the spinlock_irqsave here because we can still
have IRQs at this point */
- spin_lock_irqsave(&mts->lock, flags);
- mts64_device_close(mts);
- spin_unlock_irqrestore(&mts->lock, flags);
+ scoped_guard(spinlock_irqsave, &mts->lock) {
+ mts64_device_close(mts);
+ }
msleep(500);
@@ -709,29 +698,24 @@ static void snd_mts64_rawmidi_output_trigger(struct snd_rawmidi_substream *subst
{
struct mts64 *mts = substream->rmidi->private_data;
u8 data;
- unsigned long flags;
- spin_lock_irqsave(&mts->lock, flags);
+ guard(spinlock_irqsave)(&mts->lock);
while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) {
mts64_write_midi(mts, data, substream->number+1);
snd_rawmidi_transmit_ack(substream, 1);
}
- spin_unlock_irqrestore(&mts->lock, flags);
}
static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substream,
int up)
{
struct mts64 *mts = substream->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&mts->lock, flags);
+ guard(spinlock_irqsave)(&mts->lock);
if (up)
mts->mode[substream->number] |= MTS64_MODE_INPUT_TRIGGERED;
else
mts->mode[substream->number] &= ~MTS64_MODE_INPUT_TRIGGERED;
-
- spin_unlock_irqrestore(&mts->lock, flags);
}
static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
@@ -763,7 +747,7 @@ static int snd_mts64_rawmidi_create(struct snd_card *card)
return err;
rmidi->private_data = mts;
- strcpy(rmidi->name, CARD_NAME);
+ strscpy(rmidi->name, CARD_NAME);
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -791,7 +775,7 @@ static int snd_mts64_rawmidi_create(struct snd_card *card)
mts->midi_input_substream[substream->number] = substream;
switch(substream->number) {
case MTS64_SMPTE_SUBSTREAM:
- strcpy(substream->name, "Miditerminal SMPTE");
+ strscpy(substream->name, "Miditerminal SMPTE");
break;
default:
sprintf(substream->name,
@@ -818,7 +802,7 @@ static void snd_mts64_interrupt(void *private)
if (!mts)
return;
- spin_lock(&mts->lock);
+ guard(spinlock)(&mts->lock);
ret = mts64_read(mts->pardev->port);
data = ret & 0x00ff;
status = ret >> 8;
@@ -827,13 +811,11 @@ static void snd_mts64_interrupt(void *private)
mts->current_midi_input_port = mts64_map_midi_input(data);
} else {
if (mts->current_midi_input_port == -1)
- goto __out;
+ return;
substream = mts->midi_input_substream[mts->current_midi_input_port];
if (mts->mode[substream->number] & MTS64_MODE_INPUT_TRIGGERED)
snd_rawmidi_receive(substream, &data, 1);
}
-__out:
- spin_unlock(&mts->lock);
}
static void snd_mts64_attach(struct parport *p)
@@ -882,7 +864,6 @@ static struct parport_driver mts64_parport_driver = {
.probe = snd_mts64_dev_probe,
.match_port = snd_mts64_attach,
.detach = snd_mts64_detach,
- .devmodel = true,
};
/*********************************************************************
@@ -927,11 +908,11 @@ static int snd_mts64_probe(struct platform_device *pdev)
err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
- snd_printd("Cannot create card\n");
+ dev_dbg(&pdev->dev, "Cannot create card\n");
return err;
}
- strcpy(card->driver, DRIVER_NAME);
- strcpy(card->shortname, "ESI " CARD_NAME);
+ strscpy(card->driver, DRIVER_NAME);
+ strscpy(card->shortname, "ESI " CARD_NAME);
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, p->base, p->irq);
@@ -941,21 +922,21 @@ static int snd_mts64_probe(struct platform_device *pdev)
&mts64_cb, /* callbacks */
pdev->id); /* device number */
if (!pardev) {
- snd_printd("Cannot register pardevice\n");
+ dev_dbg(card->dev, "Cannot register pardevice\n");
err = -EIO;
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
- snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
+ dev_dbg(card->dev, "Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto free_pardev;
}
err = snd_mts64_create(card, pardev, &mts);
if (err < 0) {
- snd_printd("Cannot create main component\n");
+ dev_dbg(card->dev, "Cannot create main component\n");
goto release_pardev;
}
card->private_data = mts;
@@ -969,7 +950,7 @@ static int snd_mts64_probe(struct platform_device *pdev)
err = snd_mts64_rawmidi_create(card);
if (err < 0) {
- snd_printd("Creating Rawmidi component failed\n");
+ dev_dbg(card->dev, "Creating Rawmidi component failed\n");
goto __err;
}
@@ -983,11 +964,11 @@ static int snd_mts64_probe(struct platform_device *pdev)
/* At this point card will be usable */
err = snd_card_register(card);
if (err < 0) {
- snd_printd("Cannot register card\n");
+ dev_dbg(card->dev, "Cannot register card\n");
goto __err;
}
- snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n", p->base);
+ dev_info(card->dev, "ESI Miditerminal 4140 on 0x%lx\n", p->base);
return 0;
release_pardev:
@@ -1009,7 +990,7 @@ static void snd_mts64_remove(struct platform_device *pdev)
static struct platform_driver snd_mts64_driver = {
.probe = snd_mts64_probe,
- .remove_new = snd_mts64_remove,
+ .remove = snd_mts64_remove,
.driver = {
.name = PLATFORM_DRIVER,
}
diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile
index 83bca9f1fbdf..cf4826308365 100644
--- a/sound/drivers/opl3/Makefile
+++ b/sound/drivers/opl3/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-opl3-lib-objs := opl3_lib.o opl3_synth.o
+snd-opl3-lib-y := opl3_lib.o opl3_synth.o
snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o
ifneq ($(CONFIG_SND_SEQUENCER_OSS),)
snd-opl3-synth-y += opl3_oss.o
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 6c1f1cc092d8..fa8a2ccbbd51 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -25,7 +25,6 @@ MODULE_LICENSE("GPL");
static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)
{
- unsigned long flags;
unsigned long port;
/*
@@ -35,20 +34,17 @@ static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigne
port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;
- spin_lock_irqsave(&opl3->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl3->reg_lock);
outb((unsigned char) cmd, port);
udelay(10);
outb((unsigned char) val, port + 1);
udelay(30);
-
- spin_unlock_irqrestore(&opl3->reg_lock, flags);
}
static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)
{
- unsigned long flags;
unsigned long port;
/*
@@ -58,7 +54,7 @@ static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigne
port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;
- spin_lock_irqsave(&opl3->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl3->reg_lock);
outb((unsigned char) cmd, port);
inb(opl3->l_port);
@@ -67,8 +63,6 @@ static void snd_opl3_command(struct snd_opl3 * opl3, unsigned short cmd, unsigne
outb((unsigned char) val, port + 1);
inb(opl3->l_port);
inb(opl3->l_port);
-
- spin_unlock_irqrestore(&opl3->reg_lock, flags);
}
static int snd_opl3_detect(struct snd_opl3 * opl3)
@@ -92,7 +86,7 @@ static int snd_opl3_detect(struct snd_opl3 * opl3)
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
signature = stat1 = inb(opl3->l_port); /* Status register */
if ((stat1 & 0xe0) != 0x00) { /* Should be 0x00 */
- snd_printd("OPL3: stat1 = 0x%x\n", stat1);
+ dev_dbg(opl3->card->dev, "OPL3: stat1 = 0x%x\n", stat1);
return -ENODEV;
}
/* Set timer1 to 0xff */
@@ -108,7 +102,7 @@ static int snd_opl3_detect(struct snd_opl3 * opl3)
/* Reset the IRQ of the FM chip */
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
if ((stat2 & 0xe0) != 0xc0) { /* There is no YM3812 */
- snd_printd("OPL3: stat2 = 0x%x\n", stat2);
+ dev_dbg(opl3->card->dev, "OPL3: stat2 = 0x%x\n", stat2);
return -ENODEV;
}
@@ -142,34 +136,30 @@ static int snd_opl3_detect(struct snd_opl3 * opl3)
static int snd_opl3_timer1_start(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
unsigned int ticks;
struct snd_opl3 *opl3;
opl3 = snd_timer_chip(timer);
- spin_lock_irqsave(&opl3->timer_lock, flags);
+ guard(spinlock_irqsave)(&opl3->timer_lock);
ticks = timer->sticks;
tmp = (opl3->timer_enable | OPL3_TIMER1_START) & ~OPL3_TIMER1_MASK;
opl3->timer_enable = tmp;
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 256 - ticks); /* timer 1 count */
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* enable timer 1 IRQ */
- spin_unlock_irqrestore(&opl3->timer_lock, flags);
return 0;
}
static int snd_opl3_timer1_stop(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
struct snd_opl3 *opl3;
opl3 = snd_timer_chip(timer);
- spin_lock_irqsave(&opl3->timer_lock, flags);
+ guard(spinlock_irqsave)(&opl3->timer_lock);
tmp = (opl3->timer_enable | OPL3_TIMER1_MASK) & ~OPL3_TIMER1_START;
opl3->timer_enable = tmp;
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* disable timer #1 */
- spin_unlock_irqrestore(&opl3->timer_lock, flags);
return 0;
}
@@ -179,34 +169,30 @@ static int snd_opl3_timer1_stop(struct snd_timer * timer)
static int snd_opl3_timer2_start(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
unsigned int ticks;
struct snd_opl3 *opl3;
opl3 = snd_timer_chip(timer);
- spin_lock_irqsave(&opl3->timer_lock, flags);
+ guard(spinlock_irqsave)(&opl3->timer_lock);
ticks = timer->sticks;
tmp = (opl3->timer_enable | OPL3_TIMER2_START) & ~OPL3_TIMER2_MASK;
opl3->timer_enable = tmp;
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER2, 256 - ticks); /* timer 1 count */
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* enable timer 1 IRQ */
- spin_unlock_irqrestore(&opl3->timer_lock, flags);
return 0;
}
static int snd_opl3_timer2_stop(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
struct snd_opl3 *opl3;
opl3 = snd_timer_chip(timer);
- spin_lock_irqsave(&opl3->timer_lock, flags);
+ guard(spinlock_irqsave)(&opl3->timer_lock);
tmp = (opl3->timer_enable | OPL3_TIMER2_MASK) & ~OPL3_TIMER2_START;
opl3->timer_enable = tmp;
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* disable timer #1 */
- spin_unlock_irqrestore(&opl3->timer_lock, flags);
return 0;
}
@@ -245,7 +231,7 @@ static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no)
tid.subdevice = 0;
err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer);
if (err >= 0) {
- strcpy(timer->name, "AdLib timer #1");
+ strscpy(timer->name, "AdLib timer #1");
timer->private_data = opl3;
timer->hw = snd_opl3_timer1;
}
@@ -266,7 +252,7 @@ static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no)
tid.subdevice = 0;
err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer);
if (err >= 0) {
- strcpy(timer->name, "AdLib timer #2");
+ strscpy(timer->name, "AdLib timer #2");
timer->private_data = opl3;
timer->hw = snd_opl3_timer2;
}
@@ -289,9 +275,6 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
opl3 = hw->private_data;
status = inb(opl3->l_port);
-#if 0
- snd_printk(KERN_DEBUG "AdLib IRQ status = 0x%x\n", status);
-#endif
if (!(status & 0x80))
return;
@@ -365,7 +348,8 @@ EXPORT_SYMBOL(snd_opl3_new);
int snd_opl3_init(struct snd_opl3 *opl3)
{
if (! opl3->command) {
- printk(KERN_ERR "snd_opl3_init: command not defined!\n");
+ dev_err(opl3->card->dev,
+ "snd_opl3_init: command not defined!\n");
return -EINVAL;
}
@@ -405,14 +389,14 @@ int snd_opl3_create(struct snd_card *card,
if (! integrated) {
opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)");
if (!opl3->res_l_port) {
- snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port);
+ dev_err(card->dev, "opl3: can't grab left port 0x%lx\n", l_port);
snd_device_free(card, opl3);
return -EBUSY;
}
if (r_port != 0) {
opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)");
if (!opl3->res_r_port) {
- snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port);
+ dev_err(card->dev, "opl3: can't grab right port 0x%lx\n", r_port);
snd_device_free(card, opl3);
return -EBUSY;
}
@@ -432,8 +416,8 @@ int snd_opl3_create(struct snd_card *card,
opl3->command = &snd_opl2_command;
err = snd_opl3_detect(opl3);
if (err < 0) {
- snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx\n",
- opl3->l_port, opl3->r_port);
+ dev_dbg(card->dev, "OPL2/3 chip not detected at 0x%lx/0x%lx\n",
+ opl3->l_port, opl3->r_port);
snd_device_free(card, opl3);
return err;
}
@@ -499,18 +483,18 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
if (device == 0)
hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;
#endif
- strcpy(hw->name, hw->id);
+ strscpy(hw->name, hw->id);
switch (opl3->hardware & OPL3_HW_MASK) {
case OPL3_HW_OPL2:
- strcpy(hw->name, "OPL2 FM");
+ strscpy(hw->name, "OPL2 FM");
hw->iface = SNDRV_HWDEP_IFACE_OPL2;
break;
case OPL3_HW_OPL3:
- strcpy(hw->name, "OPL3 FM");
+ strscpy(hw->name, "OPL3 FM");
hw->iface = SNDRV_HWDEP_IFACE_OPL3;
break;
case OPL3_HW_OPL4:
- strcpy(hw->name, "OPL4 FM");
+ strscpy(hw->name, "OPL4 FM");
hw->iface = SNDRV_HWDEP_IFACE_OPL4;
break;
}
@@ -526,7 +510,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,
sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) {
- strcpy(opl3->seq_dev->name, hw->name);
+ strscpy(opl3->seq_dev->name, hw->name);
*(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(opl3->seq_dev) = opl3;
}
#endif
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index e2b7be67f0e3..6d3c5b5a35ff 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -11,6 +11,13 @@
#include "opl3_voice.h"
#include <sound/asoundef.h>
+#ifdef DEBUG_MIDI
+#define opl3_dbg(opl3, fmt, ...) \
+ dev_dbg(((struct snd_opl3 *)(opl3))->card->dev, fmt, ##__VA_ARGS__)
+#else
+#define opl3_dbg(opl3, fmt, ...) do {} while (0)
+#endif
+
static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
struct snd_midi_channel *chan);
/*
@@ -107,14 +114,17 @@ static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum,
#ifdef DEBUG_ALLOC
-static void debug_alloc(struct snd_opl3 *opl3, char *s, int voice) {
+static void debug_alloc(struct snd_opl3 *opl3, char *s, int voice)
+{
int i;
- char *str = "x.24";
+ const char *str = "x.24";
+ char buf[MAX_OPL3_VOICES + 1];
- printk(KERN_DEBUG "time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
for (i = 0; i < opl3->max_voices; i++)
- printk(KERN_CONT "%c", *(str + opl3->voices[i].state + 1));
- printk(KERN_CONT "\n");
+ buf[i] = str[opl3->voices[i].state + 1];
+ buf[i] = 0;
+ dev_dbg(opl3->card->dev, "time %.5i: %s [%.2i]: %s\n",
+ opl3->use_time, s, voice, buf);
}
#endif
@@ -203,9 +213,10 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
for (i = 0; i < END; i++) {
if (best[i].voice >= 0) {
#ifdef DEBUG_ALLOC
- printk(KERN_DEBUG "%s %iop allocation on voice %i\n",
- alloc_type[i], instr_4op ? 4 : 2,
- best[i].voice);
+ dev_dbg(opl3->card->dev,
+ "%s %iop allocation on voice %i\n",
+ alloc_type[i], instr_4op ? 4 : 2,
+ best[i].voice);
#endif
return best[i].voice;
}
@@ -222,30 +233,28 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
void snd_opl3_timer_func(struct timer_list *t)
{
- struct snd_opl3 *opl3 = from_timer(opl3, t, tlist);
- unsigned long flags;
+ struct snd_opl3 *opl3 = timer_container_of(opl3, t, tlist);
int again = 0;
int i;
- spin_lock_irqsave(&opl3->voice_lock, flags);
- for (i = 0; i < opl3->max_voices; i++) {
- struct snd_opl3_voice *vp = &opl3->voices[i];
- if (vp->state > 0 && vp->note_off_check) {
- if (vp->note_off == jiffies)
- snd_opl3_note_off_unsafe(opl3, vp->note, 0,
- vp->chan);
- else
- again++;
+ scoped_guard(spinlock_irqsave, &opl3->voice_lock) {
+ for (i = 0; i < opl3->max_voices; i++) {
+ struct snd_opl3_voice *vp = &opl3->voices[i];
+ if (vp->state > 0 && vp->note_off_check) {
+ if (vp->note_off == jiffies)
+ snd_opl3_note_off_unsafe(opl3, vp->note, 0,
+ vp->chan);
+ else
+ again++;
+ }
}
}
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
- spin_lock_irqsave(&opl3->sys_timer_lock, flags);
+ guard(spinlock_irqsave)(&opl3->sys_timer_lock);
if (again)
mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */
else
opl3->sys_timer_status = 0;
- spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
}
/*
@@ -253,13 +262,11 @@ void snd_opl3_timer_func(struct timer_list *t)
*/
static void snd_opl3_start_timer(struct snd_opl3 *opl3)
{
- unsigned long flags;
- spin_lock_irqsave(&opl3->sys_timer_lock, flags);
+ guard(spinlock_irqsave)(&opl3->sys_timer_lock);
if (! opl3->sys_timer_status) {
mod_timer(&opl3->tlist, jiffies + 1);
opl3->sys_timer_status = 1;
}
- spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
}
/* ------------------------------ */
@@ -298,14 +305,11 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
struct fm_patch *patch;
struct fm_instrument *fm;
- unsigned long flags;
opl3 = p;
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "Note on, ch %i, inst %i, note %i, vel %i\n",
- chan->number, chan->midi_program, note, vel);
-#endif
+ opl3_dbg(opl3, "Note on, ch %i, inst %i, note %i, vel %i\n",
+ chan->number, chan->midi_program, note, vel);
/* in SYNTH mode, application takes care of voices */
/* in SEQ mode, drum voice numbers are notes on drum channel */
@@ -328,20 +332,17 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
prg = chan->midi_program;
}
- spin_lock_irqsave(&opl3->voice_lock, flags);
+ guard(spinlock_irqsave)(&opl3->voice_lock);
if (use_internal_drums) {
snd_opl3_drum_switch(opl3, note, vel, 1, chan);
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
}
__extra_prg:
patch = snd_opl3_find_patch(opl3, prg, bank, 0);
- if (!patch) {
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
+ if (!patch)
return;
- }
fm = &patch->inst;
switch (patch->type) {
@@ -355,13 +356,10 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
}
fallthrough;
default:
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
}
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG " --> OPL%i instrument: %s\n",
- instr_4op ? 3 : 2, patch->name);
-#endif
+ opl3_dbg(opl3, " --> OPL%i instrument: %s\n",
+ instr_4op ? 3 : 2, patch->name);
/* in SYNTH mode, application takes care of voices */
/* in SEQ mode, allocate voice on free OPL3 channel */
if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
@@ -371,10 +369,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
voice = snd_opl3_oss_map[chan->number];
}
- if (voice < 0) {
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
+ if (voice < 0)
return;
- }
if (voice < MAX_OPL2_VOICES) {
/* Left register block for voices 0 .. 8 */
@@ -422,10 +418,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
}
}
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG " --> setting OPL3 connection: 0x%x\n",
- opl3->connection_reg);
-#endif
+ opl3_dbg(opl3, " --> setting OPL3 connection: 0x%x\n",
+ opl3->connection_reg);
/*
* calculate volume depending on connection
* between FM operators (see include/opl3.h)
@@ -457,9 +451,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
/* Program the FM voice characteristics */
for (i = 0; i < (instr_4op ? 4 : 2); i++) {
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG " --> programming operator %i\n", i);
-#endif
+ opl3_dbg(opl3, " --> programming operator %i\n", i);
op_offset = snd_opl3_regmap[voice_offset][i];
/* Set OPL3 AM_VIB register of requested voice/operator */
@@ -537,9 +529,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
/* Set output sound flag */
blocknum |= OPL3_KEYON_BIT;
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG " --> trigger voice %i\n", voice);
-#endif
+ opl3_dbg(opl3, " --> trigger voice %i\n", voice);
/* Set OPL3 KEYON_BLOCK register of requested voice */
opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
opl3->command(opl3, opl3_reg, blocknum);
@@ -593,12 +583,9 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
bank = 0;
prg = extra_prg - 1;
}
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG " *** allocating extra program\n");
-#endif
+ opl3_dbg(opl3, " *** allocating extra program\n");
goto __extra_prg;
}
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
}
static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
@@ -624,9 +611,7 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
}
/* kill voice */
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG " --> kill voice %i\n", voice);
-#endif
+ opl3_dbg(opl3, " --> kill voice %i\n", voice);
opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
/* clear Key ON bit */
opl3->command(opl3, opl3_reg, vp->keyon_reg);
@@ -660,10 +645,8 @@ static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
opl3 = p;
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "Note off, ch %i, inst %i, note %i\n",
- chan->number, chan->midi_program, note);
-#endif
+ opl3_dbg(opl3, "Note off, ch %i, inst %i, note %i\n",
+ chan->number, chan->midi_program, note);
if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
if (chan->drum_channel && use_internal_drums) {
@@ -691,11 +674,9 @@ void snd_opl3_note_off(void *p, int note, int vel,
struct snd_midi_channel *chan)
{
struct snd_opl3 *opl3 = p;
- unsigned long flags;
- spin_lock_irqsave(&opl3->voice_lock, flags);
+ guard(spinlock_irqsave)(&opl3->voice_lock);
snd_opl3_note_off_unsafe(p, note, vel, chan);
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
}
/*
@@ -703,10 +684,8 @@ void snd_opl3_note_off(void *p, int note, int vel,
*/
void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *chan)
{
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "Key pressure, ch#: %i, inst#: %i\n",
- chan->number, chan->midi_program);
-#endif
+ opl3_dbg(p, "Key pressure, ch#: %i, inst#: %i\n",
+ chan->number, chan->midi_program);
}
/*
@@ -714,10 +693,8 @@ void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *cha
*/
void snd_opl3_terminate_note(void *p, int note, struct snd_midi_channel *chan)
{
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "Terminate note, ch#: %i, inst#: %i\n",
- chan->number, chan->midi_program);
-#endif
+ opl3_dbg(p, "Terminate note, ch#: %i, inst#: %i\n",
+ chan->number, chan->midi_program);
}
static void snd_opl3_update_pitch(struct snd_opl3 *opl3, int voice)
@@ -773,9 +750,7 @@ static void snd_opl3_pitch_ctrl(struct snd_opl3 *opl3, struct snd_midi_channel *
int voice;
struct snd_opl3_voice *vp;
- unsigned long flags;
-
- spin_lock_irqsave(&opl3->voice_lock, flags);
+ guard(spinlock_irqsave)(&opl3->voice_lock);
if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
for (voice = 0; voice < opl3->max_voices; voice++) {
@@ -791,7 +766,6 @@ static void snd_opl3_pitch_ctrl(struct snd_opl3 *opl3, struct snd_midi_channel *
snd_opl3_update_pitch(opl3, voice);
}
}
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
}
/*
@@ -803,10 +777,8 @@ void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan)
struct snd_opl3 *opl3;
opl3 = p;
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "Controller, TYPE = %i, ch#: %i, inst#: %i\n",
- type, chan->number, chan->midi_program);
-#endif
+ opl3_dbg(opl3, "Controller, TYPE = %i, ch#: %i, inst#: %i\n",
+ type, chan->number, chan->midi_program);
switch (type) {
case MIDI_CTL_MSB_MODWHEEL:
@@ -837,10 +809,8 @@ void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan)
void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
struct snd_midi_channel_set *chset)
{
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "NRPN, ch#: %i, inst#: %i\n",
- chan->number, chan->midi_program);
-#endif
+ opl3_dbg(p, "NRPN, ch#: %i, inst#: %i\n",
+ chan->number, chan->midi_program);
}
/*
@@ -849,7 +819,5 @@ void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
void snd_opl3_sysex(void *p, unsigned char *buf, int len,
int parsed, struct snd_midi_channel_set *chset)
{
-#ifdef DEBUG_MIDI
- snd_printk(KERN_DEBUG "SYSEX\n");
-#endif
+ opl3_dbg(p, "SYSEX\n");
}
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 7645365eec89..6d39b2b77b80 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -193,14 +193,14 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
return -EINVAL;
if (count < (int)sizeof(sbi)) {
- snd_printk(KERN_ERR "FM Error: Patch record too short\n");
+ dev_err(opl3->card->dev, "FM Error: Patch record too short\n");
return -EINVAL;
}
if (copy_from_user(&sbi, buf, sizeof(sbi)))
return -EFAULT;
if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
- snd_printk(KERN_ERR "FM Error: Invalid instrument number %d\n",
+ dev_err(opl3->card->dev, "FM Error: Invalid instrument number %d\n",
sbi.channel);
return -EINVAL;
}
@@ -220,13 +220,15 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
unsigned long ioarg)
{
+ struct snd_opl3 *opl3;
+
if (snd_BUG_ON(!arg))
return -ENXIO;
+ opl3 = arg->private_data;
switch (cmd) {
case SNDCTL_FM_LOAD_INSTR:
- snd_printk(KERN_ERR "OPL3: "
- "Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. "
- "Fix the program.\n");
+ dev_err(opl3->card->dev,
+ "OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
return -EINVAL;
case SNDCTL_SYNTH_MEMAVL:
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index 75de1299c3dc..d3278428d360 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -40,13 +40,11 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3)
int idx;
struct snd_hwdep *hwdep = opl3->hwdep;
- mutex_lock(&hwdep->open_mutex);
- if (hwdep->used) {
- mutex_unlock(&hwdep->open_mutex);
- return -EBUSY;
+ scoped_guard(mutex, &hwdep->open_mutex) {
+ if (hwdep->used)
+ return -EBUSY;
+ hwdep->used++;
}
- hwdep->used++;
- mutex_unlock(&hwdep->open_mutex);
snd_opl3_reset(opl3);
@@ -68,22 +66,21 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3)
void snd_opl3_synth_cleanup(struct snd_opl3 * opl3)
{
- unsigned long flags;
struct snd_hwdep *hwdep;
/* Stop system timer */
- spin_lock_irqsave(&opl3->sys_timer_lock, flags);
- if (opl3->sys_timer_status) {
- del_timer(&opl3->tlist);
- opl3->sys_timer_status = 0;
+ scoped_guard(spinlock_irq, &opl3->sys_timer_lock) {
+ if (opl3->sys_timer_status) {
+ timer_delete(&opl3->tlist);
+ opl3->sys_timer_status = 0;
+ }
}
- spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
snd_opl3_reset(opl3);
hwdep = opl3->hwdep;
- mutex_lock(&hwdep->open_mutex);
- hwdep->used--;
- mutex_unlock(&hwdep->open_mutex);
+ scoped_guard(mutex, &hwdep->open_mutex) {
+ hwdep->used--;
+ }
wake_up(&hwdep->open_wait);
}
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 97d30a833ac8..10f622b439a0 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -158,10 +158,8 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
return 0;
#endif
-#ifdef CONFIG_SND_DEBUG
default:
- snd_printk(KERN_WARNING "unknown IOCTL: 0x%x\n", cmd);
-#endif
+ dev_dbg(opl3->card->dev, "unknown IOCTL: 0x%x\n", cmd);
}
return -ENOTTY;
}
diff --git a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile
index 6e86a4092b4c..a841630b45c2 100644
--- a/sound/drivers/opl4/Makefile
+++ b/sound/drivers/opl4/Makefile
@@ -4,9 +4,9 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o
+snd-opl4-lib-y := opl4_lib.o opl4_mixer.o
snd-opl4-lib-$(CONFIG_SND_PROC_FS) += opl4_proc.o
-snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o
+snd-opl4-synth-y := opl4_seq.o opl4_synth.o yrw801.o
obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o
obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-opl4-synth.o
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c
index 035645eb5e8d..44fbc6bf0654 100644
--- a/sound/drivers/opl4/opl4_lib.c
+++ b/sound/drivers/opl4/opl4_lib.c
@@ -47,10 +47,9 @@ EXPORT_SYMBOL(snd_opl4_read);
void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size)
{
- unsigned long flags;
u8 memcfg;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
memcfg = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION);
snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg | OPL4_MODE_BIT);
@@ -65,18 +64,15 @@ void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size
insb(opl4->pcm_port + 1, buf, size);
snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg);
-
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
EXPORT_SYMBOL(snd_opl4_read_memory);
void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, int size)
{
- unsigned long flags;
u8 memcfg;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
memcfg = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION);
snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg | OPL4_MODE_BIT);
@@ -91,8 +87,6 @@ void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, i
outsb(opl4->pcm_port + 1, buf, size);
snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg);
-
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
EXPORT_SYMBOL(snd_opl4_write_memory);
@@ -114,7 +108,7 @@ static int snd_opl4_detect(struct snd_opl4 *opl4)
snd_opl4_enable_opl4(opl4);
id1 = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION);
- snd_printdd("OPL4[02]=%02x\n", id1);
+ dev_dbg(opl4->card->dev, "OPL4[02]=%02x\n", id1);
switch (id1 & OPL4_DEVICE_ID_MASK) {
case 0x20:
opl4->hardware = OPL3_HW_OPL4;
@@ -130,7 +124,7 @@ static int snd_opl4_detect(struct snd_opl4 *opl4)
snd_opl4_write(opl4, OPL4_REG_MIX_CONTROL_PCM, 0xff);
id1 = snd_opl4_read(opl4, OPL4_REG_MIX_CONTROL_FM);
id2 = snd_opl4_read(opl4, OPL4_REG_MIX_CONTROL_PCM);
- snd_printdd("OPL4 id1=%02x id2=%02x\n", id1, id2);
+ dev_dbg(opl4->card->dev, "OPL4 id1=%02x id2=%02x\n", id1, id2);
if (id1 != 0x00 || id2 != 0xff)
return -ENODEV;
@@ -152,7 +146,7 @@ static int snd_opl4_create_seq_dev(struct snd_opl4 *opl4, int seq_device)
opl4->seq_dev_num = seq_device;
if (snd_seq_device_new(opl4->card, seq_device, SNDRV_SEQ_DEV_ID_OPL4,
sizeof(struct snd_opl4 *), &opl4->seq_dev) >= 0) {
- strcpy(opl4->seq_dev->name, "OPL4 Wavetable");
+ strscpy(opl4->seq_dev->name, "OPL4 Wavetable");
*(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(opl4->seq_dev) = opl4;
opl4->seq_dev->private_data = opl4;
opl4->seq_dev->private_free = snd_opl4_seq_dev_free;
@@ -200,7 +194,7 @@ int snd_opl4_create(struct snd_card *card,
opl4->res_fm_port = request_region(fm_port, 8, "OPL4 FM");
opl4->res_pcm_port = request_region(pcm_port, 8, "OPL4 PCM/MIX");
if (!opl4->res_fm_port || !opl4->res_pcm_port) {
- snd_printk(KERN_ERR "opl4: can't grab ports 0x%lx, 0x%lx\n", fm_port, pcm_port);
+ dev_err(card->dev, "opl4: can't grab ports 0x%lx, 0x%lx\n", fm_port, pcm_port);
snd_opl4_free(opl4);
return -EBUSY;
}
@@ -214,7 +208,7 @@ int snd_opl4_create(struct snd_card *card,
err = snd_opl4_detect(opl4);
if (err < 0) {
snd_opl4_free(opl4);
- snd_printd("OPL4 chip not detected at %#lx/%#lx\n", fm_port, pcm_port);
+ dev_dbg(card->dev, "OPL4 chip not detected at %#lx/%#lx\n", fm_port, pcm_port);
return err;
}
diff --git a/sound/drivers/opl4/opl4_mixer.c b/sound/drivers/opl4/opl4_mixer.c
index fa1e6eff43ab..deebb8636437 100644
--- a/sound/drivers/opl4/opl4_mixer.c
+++ b/sound/drivers/opl4/opl4_mixer.c
@@ -19,13 +19,11 @@ static int snd_opl4_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
static int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
u8 reg = kcontrol->private_value;
u8 value;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
value = snd_opl4_read(opl4, reg);
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
ucontrol->value.integer.value[0] = 7 - (value & 7);
ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7);
return 0;
@@ -34,16 +32,14 @@ static int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
static int snd_opl4_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
u8 reg = kcontrol->private_value;
u8 value, old_value;
value = (7 - (ucontrol->value.integer.value[0] & 7)) |
((7 - (ucontrol->value.integer.value[1] & 7)) << 3);
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
old_value = snd_opl4_read(opl4, reg);
snd_opl4_write(opl4, reg, value);
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
return value != old_value;
}
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c
index f2149091e10a..fd0ba4704d9f 100644
--- a/sound/drivers/opl4/opl4_proc.c
+++ b/sound/drivers/opl4/opl4_proc.c
@@ -14,13 +14,10 @@ static int snd_opl4_mem_proc_open(struct snd_info_entry *entry,
{
struct snd_opl4 *opl4 = entry->private_data;
- mutex_lock(&opl4->access_mutex);
- if (opl4->memory_access) {
- mutex_unlock(&opl4->access_mutex);
+ guard(mutex)(&opl4->access_mutex);
+ if (opl4->memory_access)
return -EBUSY;
- }
opl4->memory_access++;
- mutex_unlock(&opl4->access_mutex);
return 0;
}
@@ -29,9 +26,8 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry,
{
struct snd_opl4 *opl4 = entry->private_data;
- mutex_lock(&opl4->access_mutex);
+ guard(mutex)(&opl4->access_mutex);
opl4->memory_access--;
- mutex_unlock(&opl4->access_mutex);
return 0;
}
diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c
index f59ca660c616..7bb22089a093 100644
--- a/sound/drivers/opl4/opl4_seq.c
+++ b/sound/drivers/opl4/opl4_seq.c
@@ -63,24 +63,18 @@ static int snd_opl4_seq_use(void *private_data, struct snd_seq_port_subscribe *i
struct snd_opl4 *opl4 = private_data;
int err;
- mutex_lock(&opl4->access_mutex);
-
- if (opl4->used) {
- mutex_unlock(&opl4->access_mutex);
- return -EBUSY;
- }
- opl4->used++;
-
- if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
- err = snd_opl4_seq_use_inc(opl4);
- if (err < 0) {
- mutex_unlock(&opl4->access_mutex);
- return err;
+ scoped_guard(mutex, &opl4->access_mutex) {
+ if (opl4->used)
+ return -EBUSY;
+ opl4->used++;
+
+ if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
+ err = snd_opl4_seq_use_inc(opl4);
+ if (err < 0)
+ return err;
}
}
- mutex_unlock(&opl4->access_mutex);
-
snd_opl4_synth_reset(opl4);
return 0;
}
@@ -91,9 +85,9 @@ static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe
snd_opl4_synth_shutdown(opl4);
- mutex_lock(&opl4->access_mutex);
- opl4->used--;
- mutex_unlock(&opl4->access_mutex);
+ scoped_guard(mutex, &opl4->access_mutex) {
+ opl4->used--;
+ }
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
snd_opl4_seq_use_dec(opl4);
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 34e2bd52bba1..82dbb8519ab1 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -272,13 +272,12 @@ static const unsigned char snd_opl4_volume_table[128] = {
*/
void snd_opl4_synth_reset(struct snd_opl4 *opl4)
{
- unsigned long flags;
int i;
- spin_lock_irqsave(&opl4->reg_lock, flags);
- for (i = 0; i < OPL4_MAX_VOICES; i++)
- snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT);
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &opl4->reg_lock) {
+ for (i = 0; i < OPL4_MAX_VOICES; i++)
+ snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT);
+ }
INIT_LIST_HEAD(&opl4->off_voices);
INIT_LIST_HEAD(&opl4->on_voices);
@@ -296,14 +295,12 @@ void snd_opl4_synth_reset(struct snd_opl4 *opl4)
*/
void snd_opl4_synth_shutdown(struct snd_opl4 *opl4)
{
- unsigned long flags;
int i;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
for (i = 0; i < OPL4_MAX_VOICES; i++)
snd_opl4_write(opl4, OPL4_REG_MISC + i,
opl4->voices[i].reg_misc & ~OPL4_KEY_ON_BIT);
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
/*
@@ -313,17 +310,15 @@ static void snd_opl4_do_for_note(struct snd_opl4 *opl4, int note, struct snd_mid
void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
int i;
- unsigned long flags;
struct opl4_voice *voice;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
for (i = 0; i < OPL4_MAX_VOICES; i++) {
voice = &opl4->voices[i];
if (voice->chan == chan && voice->note == note) {
func(opl4, voice);
}
}
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
/*
@@ -334,17 +329,15 @@ static void snd_opl4_do_for_channel(struct snd_opl4 *opl4,
void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
int i;
- unsigned long flags;
struct opl4_voice *voice;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
for (i = 0; i < OPL4_MAX_VOICES; i++) {
voice = &opl4->voices[i];
if (voice->chan == chan) {
func(opl4, voice);
}
}
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
/*
@@ -354,16 +347,14 @@ static void snd_opl4_do_for_all(struct snd_opl4 *opl4,
void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
int i;
- unsigned long flags;
struct opl4_voice *voice;
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
for (i = 0; i < OPL4_MAX_VOICES; i++) {
voice = &opl4->voices[i];
if (voice->chan)
func(opl4, voice);
}
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
static void snd_opl4_update_volume(struct snd_opl4 *opl4, struct opl4_voice *voice)
@@ -486,7 +477,6 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
struct opl4_voice *voice[2];
const struct opl4_sound *sound[2];
int voices = 0, i;
- unsigned long flags;
/* determine the number of voices and voice parameters */
i = chan->drum_channel ? 0x80 : (chan->midi_program & 0x7f);
@@ -501,41 +491,41 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
}
/* allocate and initialize the needed voices */
- spin_lock_irqsave(&opl4->reg_lock, flags);
- for (i = 0; i < voices; i++) {
- voice[i] = snd_opl4_get_voice(opl4);
- list_move_tail(&voice[i]->list, &opl4->on_voices);
- voice[i]->chan = chan;
- voice[i]->note = note;
- voice[i]->velocity = vel & 0x7f;
- voice[i]->sound = sound[i];
- }
+ scoped_guard(spinlock_irqsave, &opl4->reg_lock) {
+ for (i = 0; i < voices; i++) {
+ voice[i] = snd_opl4_get_voice(opl4);
+ list_move_tail(&voice[i]->list, &opl4->on_voices);
+ voice[i]->chan = chan;
+ voice[i]->note = note;
+ voice[i]->velocity = vel & 0x7f;
+ voice[i]->sound = sound[i];
+ }
- /* set tone number (triggers header loading) */
- for (i = 0; i < voices; i++) {
- voice[i]->reg_f_number =
- (sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8;
- snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number,
- voice[i]->reg_f_number);
- snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number,
- sound[i]->tone & 0xff);
- }
+ /* set tone number (triggers header loading) */
+ for (i = 0; i < voices; i++) {
+ voice[i]->reg_f_number =
+ (sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8;
+ snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number,
+ voice[i]->reg_f_number);
+ snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number,
+ sound[i]->tone & 0xff);
+ }
- /* set parameters which can be set while loading */
- for (i = 0; i < voices; i++) {
- voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
- snd_opl4_update_pan(opl4, voice[i]);
- snd_opl4_update_pitch(opl4, voice[i]);
- voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
- snd_opl4_update_volume(opl4, voice[i]);
+ /* set parameters which can be set while loading */
+ for (i = 0; i < voices; i++) {
+ voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
+ snd_opl4_update_pan(opl4, voice[i]);
+ snd_opl4_update_pitch(opl4, voice[i]);
+ voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
+ snd_opl4_update_volume(opl4, voice[i]);
+ }
}
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
/* wait for completion of loading */
snd_opl4_wait_for_wave_headers(opl4);
/* set remaining parameters */
- spin_lock_irqsave(&opl4->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl4->reg_lock);
for (i = 0; i < voices; i++) {
snd_opl4_update_tone_parameters(opl4, voice[i]);
voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato;
@@ -549,7 +539,6 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number,
voice[i]->reg_misc);
}
- spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)
diff --git a/sound/drivers/opl4/yrw801.c b/sound/drivers/opl4/yrw801.c
index 6c335492d082..9e464b84b905 100644
--- a/sound/drivers/opl4/yrw801.c
+++ b/sound/drivers/opl4/yrw801.c
@@ -43,7 +43,7 @@ int snd_yrw801_detect(struct snd_opl4 *opl4)
snd_opl4_read_memory(opl4, buf, 0x1ffffe, 2);
if (buf[0] != 0x01)
return -ENODEV;
- snd_printdd("YRW801 ROM version %02x.%02x\n", buf[0], buf[1]);
+ dev_dbg(opl4->card->dev, "YRW801 ROM version %02x.%02x\n", buf[0], buf[1]);
return 0;
}
diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c
new file mode 100644
index 000000000000..b8474631f0b5
--- /dev/null
+++ b/sound/drivers/pcmtest.c
@@ -0,0 +1,780 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Virtual ALSA driver for PCM testing/fuzzing
+ *
+ * Copyright 2023 Ivan Orlov <ivan.orlov0322@gmail.com>
+ *
+ * This is a simple virtual ALSA driver, which can be used for audio applications/PCM middle layer
+ * testing or fuzzing.
+ * It can:
+ * - Simulate 'playback' and 'capture' actions
+ * - Generate random or pattern-based capture data
+ * - Check playback buffer for containing looped template, and notify about the results
+ * through the debugfs entry
+ * - Inject delays into the playback and capturing processes. See 'inject_delay' parameter.
+ * - Inject errors during the PCM callbacks.
+ * - Register custom RESET ioctl and notify when it is called through the debugfs entry
+ * - Work in interleaved and non-interleaved modes
+ * - Support up to 8 substreams
+ * - Support up to 4 channels
+ * - Support framerates from 8 kHz to 48 kHz
+ *
+ * When driver works in the capture mode with multiple channels, it duplicates the looped
+ * pattern to each separate channel. For example, if we have 2 channels, format = U8, interleaved
+ * access mode and pattern 'abacaba', the DMA buffer will look like aabbccaabbaaaa..., so buffer for
+ * each channel will contain abacabaabacaba... Same for the non-interleaved mode.
+ *
+ * However, it may break the capturing on the higher framerates with small period size, so it is
+ * better to choose larger period sizes.
+ *
+ * You can find the corresponding selftest in the 'alsa' selftests folder.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+
+#define TIMER_PER_SEC 5
+#define TIMER_INTERVAL (HZ / TIMER_PER_SEC)
+#define DELAY_JIFFIES HZ
+#define PLAYBACK_SUBSTREAM_CNT 8
+#define CAPTURE_SUBSTREAM_CNT 8
+#define MAX_CHANNELS_NUM 4
+
+#define DEFAULT_PATTERN "abacaba"
+#define DEFAULT_PATTERN_LEN 7
+
+#define FILL_MODE_RAND 0
+#define FILL_MODE_PAT 1
+
+#define MAX_PATTERN_LEN 4096
+
+static int index = -1;
+static char *id = "pcmtest";
+static bool enable = true;
+static int inject_delay;
+static bool inject_hwpars_err;
+static bool inject_prepare_err;
+static bool inject_trigger_err;
+static bool inject_open_err;
+
+static short fill_mode = FILL_MODE_PAT;
+
+static u8 playback_capture_test;
+static u8 ioctl_reset_test;
+static struct dentry *driver_debug_dir;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for pcmtest soundcard");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for pcmtest soundcard");
+module_param(enable, bool, 0444);
+MODULE_PARM_DESC(enable, "Enable pcmtest soundcard.");
+module_param(fill_mode, short, 0600);
+MODULE_PARM_DESC(fill_mode, "Buffer fill mode: rand(0) or pattern(1)");
+module_param(inject_delay, int, 0600);
+MODULE_PARM_DESC(inject_delay, "Inject delays during playback/capture (in jiffies)");
+module_param(inject_hwpars_err, bool, 0600);
+MODULE_PARM_DESC(inject_hwpars_err, "Inject EBUSY error in the 'hw_params' callback");
+module_param(inject_prepare_err, bool, 0600);
+MODULE_PARM_DESC(inject_prepare_err, "Inject EINVAL error in the 'prepare' callback");
+module_param(inject_trigger_err, bool, 0600);
+MODULE_PARM_DESC(inject_trigger_err, "Inject EINVAL error in the 'trigger' callback");
+module_param(inject_open_err, bool, 0600);
+MODULE_PARM_DESC(inject_open_err, "Inject EBUSY error in the 'open' callback");
+
+struct pcmtst {
+ struct snd_pcm *pcm;
+ struct snd_card *card;
+ struct platform_device *pdev;
+};
+
+struct pcmtst_buf_iter {
+ size_t buf_pos; // position in the DMA buffer
+ size_t period_pos; // period-relative position
+ size_t b_rw; // Bytes to write on every timer tick
+ size_t s_rw_ch; // Samples to write to one channel on every tick
+ unsigned int sample_bytes; // sample_bits / 8
+ bool is_buf_corrupted; // playback test result indicator
+ size_t period_bytes; // bytes in a one period
+ bool interleaved; // Interleaved/Non-interleaved mode
+ size_t total_bytes; // Total bytes read/written
+ size_t chan_block; // Bytes in one channel buffer when non-interleaved
+ struct snd_pcm_substream *substream;
+ bool suspend; // We need to pause timer without shutting it down
+ struct timer_list timer_instance;
+};
+
+static struct snd_pcm_hardware snd_pcmtst_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_NONINTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = MAX_CHANNELS_NUM,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 4096,
+ .period_bytes_max = 32768,
+ .periods_min = 1,
+ .periods_max = 1024,
+};
+
+struct pattern_buf {
+ char *buf;
+ u32 len;
+};
+
+static int buf_allocated;
+static struct pattern_buf patt_bufs[MAX_CHANNELS_NUM];
+
+static inline void inc_buf_pos(struct pcmtst_buf_iter *v_iter, size_t by, size_t bytes)
+{
+ v_iter->total_bytes += by;
+ v_iter->buf_pos += by;
+ if (v_iter->buf_pos >= bytes)
+ v_iter->buf_pos %= bytes;
+}
+
+/*
+ * Position in the DMA buffer when we are in the non-interleaved mode. We increment buf_pos
+ * every time we write a byte to any channel, so the position in the current channel buffer is
+ * (position in the DMA buffer) / count_of_channels + size_of_channel_buf * current_channel
+ */
+static inline size_t buf_pos_n(struct pcmtst_buf_iter *v_iter, unsigned int channels,
+ unsigned int chan_num)
+{
+ return v_iter->buf_pos / channels + v_iter->chan_block * chan_num;
+}
+
+/*
+ * Get the count of bytes written for the current channel in the interleaved mode.
+ * This is (count of samples written for the current channel) * bytes_in_sample +
+ * (relative position in the current sample)
+ */
+static inline size_t ch_pos_i(size_t b_total, unsigned int channels, unsigned int b_sample)
+{
+ return b_total / channels / b_sample * b_sample + (b_total % b_sample);
+}
+
+static void check_buf_block_i(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ size_t i;
+ short ch_num;
+ u8 current_byte;
+
+ for (i = 0; i < v_iter->b_rw; i++) {
+ current_byte = runtime->dma_area[v_iter->buf_pos];
+ if (!current_byte)
+ break;
+ ch_num = (v_iter->total_bytes / v_iter->sample_bytes) % runtime->channels;
+ if (current_byte != patt_bufs[ch_num].buf[ch_pos_i(v_iter->total_bytes,
+ runtime->channels,
+ v_iter->sample_bytes)
+ % patt_bufs[ch_num].len]) {
+ v_iter->is_buf_corrupted = true;
+ break;
+ }
+ inc_buf_pos(v_iter, 1, runtime->dma_bytes);
+ }
+ // If we broke during the loop, add remaining bytes to the buffer position.
+ inc_buf_pos(v_iter, v_iter->b_rw - i, runtime->dma_bytes);
+}
+
+static void check_buf_block_ni(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ unsigned int channels = runtime->channels;
+ size_t i;
+ short ch_num;
+ u8 current_byte;
+
+ for (i = 0; i < v_iter->b_rw; i++) {
+ ch_num = i % channels;
+ current_byte = runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)];
+ if (!current_byte)
+ break;
+ if (current_byte != patt_bufs[ch_num].buf[(v_iter->total_bytes / channels)
+ % patt_bufs[ch_num].len]) {
+ v_iter->is_buf_corrupted = true;
+ break;
+ }
+ inc_buf_pos(v_iter, 1, runtime->dma_bytes);
+ }
+ inc_buf_pos(v_iter, v_iter->b_rw - i, runtime->dma_bytes);
+}
+
+/*
+ * Check one block of the buffer. Here we iterate the buffer until we find '0'. This condition is
+ * necessary because we need to detect when the reading/writing ends, so we assume that the pattern
+ * doesn't contain zeros.
+ */
+static void check_buf_block(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ if (v_iter->interleaved)
+ check_buf_block_i(v_iter, runtime);
+ else
+ check_buf_block_ni(v_iter, runtime);
+}
+
+/*
+ * Fill buffer in the non-interleaved mode. The order of samples is C0, ..., C0, C1, ..., C1, C2...
+ * The channel buffers lay in the DMA buffer continuously (see default copy
+ * handlers in the pcm_lib.c file).
+ *
+ * Here we increment the DMA buffer position every time we write a byte to any channel 'buffer'.
+ * We need this to simulate the correct hardware pointer moving.
+ */
+static void fill_block_pattern_n(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ size_t i;
+ unsigned int channels = runtime->channels;
+ short ch_num;
+
+ for (i = 0; i < v_iter->b_rw; i++) {
+ ch_num = i % channels;
+ runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)] =
+ patt_bufs[ch_num].buf[(v_iter->total_bytes / channels)
+ % patt_bufs[ch_num].len];
+ inc_buf_pos(v_iter, 1, runtime->dma_bytes);
+ }
+}
+
+// Fill buffer in the interleaved mode. The order of samples is C0, C1, C2, C0, C1, C2, ...
+static void fill_block_pattern_i(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ size_t sample;
+ size_t pos_in_ch, pos_pattern;
+ short ch, pos_sample;
+
+ pos_in_ch = ch_pos_i(v_iter->total_bytes, runtime->channels, v_iter->sample_bytes);
+
+ for (sample = 0; sample < v_iter->s_rw_ch; sample++) {
+ for (ch = 0; ch < runtime->channels; ch++) {
+ for (pos_sample = 0; pos_sample < v_iter->sample_bytes; pos_sample++) {
+ pos_pattern = (pos_in_ch + sample * v_iter->sample_bytes
+ + pos_sample) % patt_bufs[ch].len;
+ runtime->dma_area[v_iter->buf_pos] = patt_bufs[ch].buf[pos_pattern];
+ inc_buf_pos(v_iter, 1, runtime->dma_bytes);
+ }
+ }
+ }
+}
+
+static void fill_block_pattern(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ if (v_iter->interleaved)
+ fill_block_pattern_i(v_iter, runtime);
+ else
+ fill_block_pattern_n(v_iter, runtime);
+}
+
+static void fill_block_rand_n(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ unsigned int channels = runtime->channels;
+ // Remaining space in all channel buffers
+ size_t bytes_remain = runtime->dma_bytes - v_iter->buf_pos;
+ unsigned int i;
+
+ for (i = 0; i < channels; i++) {
+ if (v_iter->b_rw <= bytes_remain) {
+ //b_rw - count of bytes must be written for all channels at each timer tick
+ get_random_bytes(runtime->dma_area + buf_pos_n(v_iter, channels, i),
+ v_iter->b_rw / channels);
+ } else {
+ // Write to the end of buffer and start from the beginning of it
+ get_random_bytes(runtime->dma_area + buf_pos_n(v_iter, channels, i),
+ bytes_remain / channels);
+ get_random_bytes(runtime->dma_area + v_iter->chan_block * i,
+ (v_iter->b_rw - bytes_remain) / channels);
+ }
+ }
+ inc_buf_pos(v_iter, v_iter->b_rw, runtime->dma_bytes);
+}
+
+static void fill_block_rand_i(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ size_t in_cur_block = runtime->dma_bytes - v_iter->buf_pos;
+
+ if (v_iter->b_rw <= in_cur_block) {
+ get_random_bytes(&runtime->dma_area[v_iter->buf_pos], v_iter->b_rw);
+ } else {
+ get_random_bytes(&runtime->dma_area[v_iter->buf_pos], in_cur_block);
+ get_random_bytes(runtime->dma_area, v_iter->b_rw - in_cur_block);
+ }
+ inc_buf_pos(v_iter, v_iter->b_rw, runtime->dma_bytes);
+}
+
+static void fill_block_random(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ if (v_iter->interleaved)
+ fill_block_rand_i(v_iter, runtime);
+ else
+ fill_block_rand_n(v_iter, runtime);
+}
+
+static void fill_block(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
+{
+ switch (fill_mode) {
+ case FILL_MODE_RAND:
+ fill_block_random(v_iter, runtime);
+ break;
+ case FILL_MODE_PAT:
+ fill_block_pattern(v_iter, runtime);
+ break;
+ }
+}
+
+/*
+ * Here we iterate through the buffer by (buffer_size / iterates_per_second) bytes.
+ * The driver uses timer to simulate the hardware pointer moving, and notify the PCM middle layer
+ * about period elapsed.
+ */
+static void timer_timeout(struct timer_list *data)
+{
+ struct pcmtst_buf_iter *v_iter;
+ struct snd_pcm_substream *substream;
+
+ v_iter = timer_container_of(v_iter, data, timer_instance);
+ substream = v_iter->substream;
+
+ if (v_iter->suspend)
+ return;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !v_iter->is_buf_corrupted)
+ check_buf_block(v_iter, substream->runtime);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ fill_block(v_iter, substream->runtime);
+ else
+ inc_buf_pos(v_iter, v_iter->b_rw, substream->runtime->dma_bytes);
+
+ v_iter->period_pos += v_iter->b_rw;
+ if (v_iter->period_pos >= v_iter->period_bytes) {
+ v_iter->period_pos %= v_iter->period_bytes;
+ snd_pcm_period_elapsed(substream);
+ }
+
+ if (!v_iter->suspend)
+ mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL + inject_delay);
+}
+
+static int snd_pcmtst_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcmtst_buf_iter *v_iter;
+
+ if (inject_open_err)
+ return -EBUSY;
+
+ v_iter = kzalloc(sizeof(*v_iter), GFP_KERNEL);
+ if (!v_iter)
+ return -ENOMEM;
+
+ v_iter->substream = substream;
+ runtime->hw = snd_pcmtst_hw;
+ runtime->private_data = v_iter;
+
+ playback_capture_test = 0;
+ ioctl_reset_test = 0;
+
+ timer_setup(&v_iter->timer_instance, timer_timeout, 0);
+
+ return 0;
+}
+
+static int snd_pcmtst_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
+
+ timer_shutdown_sync(&v_iter->timer_instance);
+ playback_capture_test = !v_iter->is_buf_corrupted;
+ kfree(v_iter);
+ return 0;
+}
+
+static inline void reset_buf_iterator(struct pcmtst_buf_iter *v_iter)
+{
+ v_iter->buf_pos = 0;
+ v_iter->is_buf_corrupted = false;
+ v_iter->period_pos = 0;
+ v_iter->total_bytes = 0;
+}
+
+static inline void start_pcmtest_timer(struct pcmtst_buf_iter *v_iter)
+{
+ v_iter->suspend = false;
+ mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL);
+}
+
+static int snd_pcmtst_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
+
+ if (inject_trigger_err)
+ return -EINVAL;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ reset_buf_iterator(v_iter);
+ start_pcmtest_timer(v_iter);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ start_pcmtest_timer(v_iter);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ // We can't call timer_shutdown_sync here, as it is forbidden to sleep here
+ v_iter->suspend = true;
+ timer_delete(&v_iter->timer_instance);
+ break;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_pcmtst_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
+
+ return bytes_to_frames(substream->runtime, v_iter->buf_pos);
+}
+
+static int snd_pcmtst_free(struct pcmtst *pcmtst)
+{
+ if (!pcmtst)
+ return 0;
+ kfree(pcmtst);
+ return 0;
+}
+
+// These callbacks are required, but empty - all freeing occurs in pdev_remove
+static int snd_pcmtst_dev_free(struct snd_device *device)
+{
+ return 0;
+}
+
+static void pcmtst_pdev_release(struct device *dev)
+{
+}
+
+static int snd_pcmtst_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct pcmtst_buf_iter *v_iter = runtime->private_data;
+
+ if (inject_prepare_err)
+ return -EINVAL;
+
+ v_iter->sample_bytes = samples_to_bytes(runtime, 1);
+ v_iter->period_bytes = snd_pcm_lib_period_bytes(substream);
+ v_iter->interleaved = true;
+ if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ||
+ runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) {
+ v_iter->chan_block = snd_pcm_lib_buffer_bytes(substream) / runtime->channels;
+ v_iter->interleaved = false;
+ }
+ // We want to record RATE * ch_cnt samples per sec, it is rate * sample_bytes * ch_cnt bytes
+ v_iter->s_rw_ch = runtime->rate / TIMER_PER_SEC;
+ v_iter->b_rw = v_iter->s_rw_ch * v_iter->sample_bytes * runtime->channels;
+
+ return 0;
+}
+
+static int snd_pcmtst_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ if (inject_hwpars_err)
+ return -EBUSY;
+ return 0;
+}
+
+static int snd_pcmtst_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static int snd_pcmtst_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case SNDRV_PCM_IOCTL1_RESET:
+ ioctl_reset_test = 1;
+ break;
+ }
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int snd_pcmtst_sync_stop(struct snd_pcm_substream *substream)
+{
+ struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
+
+ timer_delete_sync(&v_iter->timer_instance);
+
+ return 0;
+}
+
+static const struct snd_pcm_ops snd_pcmtst_playback_ops = {
+ .open = snd_pcmtst_pcm_open,
+ .close = snd_pcmtst_pcm_close,
+ .trigger = snd_pcmtst_pcm_trigger,
+ .hw_params = snd_pcmtst_pcm_hw_params,
+ .ioctl = snd_pcmtst_ioctl,
+ .sync_stop = snd_pcmtst_sync_stop,
+ .hw_free = snd_pcmtst_pcm_hw_free,
+ .prepare = snd_pcmtst_pcm_prepare,
+ .pointer = snd_pcmtst_pcm_pointer,
+};
+
+static const struct snd_pcm_ops snd_pcmtst_capture_ops = {
+ .open = snd_pcmtst_pcm_open,
+ .close = snd_pcmtst_pcm_close,
+ .trigger = snd_pcmtst_pcm_trigger,
+ .hw_params = snd_pcmtst_pcm_hw_params,
+ .hw_free = snd_pcmtst_pcm_hw_free,
+ .ioctl = snd_pcmtst_ioctl,
+ .sync_stop = snd_pcmtst_sync_stop,
+ .prepare = snd_pcmtst_pcm_prepare,
+ .pointer = snd_pcmtst_pcm_pointer,
+};
+
+static int snd_pcmtst_new_pcm(struct pcmtst *pcmtst)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(pcmtst->card, "PCMTest", 0, PLAYBACK_SUBSTREAM_CNT,
+ CAPTURE_SUBSTREAM_CNT, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = pcmtst;
+ strscpy(pcm->name, "PCMTest");
+ pcmtst->pcm = pcm;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pcmtst_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pcmtst_capture_ops);
+
+ err = snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &pcmtst->pdev->dev,
+ 0, 128 * 1024);
+ return err;
+}
+
+static int snd_pcmtst_create(struct snd_card *card, struct platform_device *pdev,
+ struct pcmtst **r_pcmtst)
+{
+ struct pcmtst *pcmtst;
+ int err;
+ static const struct snd_device_ops ops = {
+ .dev_free = snd_pcmtst_dev_free,
+ };
+
+ pcmtst = kzalloc(sizeof(*pcmtst), GFP_KERNEL);
+ if (!pcmtst)
+ return -ENOMEM;
+ pcmtst->card = card;
+ pcmtst->pdev = pdev;
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pcmtst, &ops);
+ if (err < 0)
+ goto _err_free_chip;
+
+ err = snd_pcmtst_new_pcm(pcmtst);
+ if (err < 0)
+ goto _err_free_chip;
+
+ *r_pcmtst = pcmtst;
+ return 0;
+
+_err_free_chip:
+ snd_pcmtst_free(pcmtst);
+ return err;
+}
+
+static int pcmtst_probe(struct platform_device *pdev)
+{
+ struct snd_card *card;
+ struct pcmtst *pcmtst;
+ int err;
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+
+ err = snd_devm_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
+ err = snd_pcmtst_create(card, pdev, &pcmtst);
+ if (err < 0)
+ return err;
+
+ strscpy(card->driver, "PCM-TEST Driver");
+ strscpy(card->shortname, "PCM-Test");
+ strscpy(card->longname, "PCM-Test virtual driver");
+
+ err = snd_card_register(card);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(pdev, pcmtst);
+
+ return 0;
+}
+
+static void pdev_remove(struct platform_device *pdev)
+{
+ struct pcmtst *pcmtst = platform_get_drvdata(pdev);
+
+ snd_pcmtst_free(pcmtst);
+}
+
+static struct platform_device pcmtst_pdev = {
+ .name = "pcmtest",
+ .dev.release = pcmtst_pdev_release,
+};
+
+static struct platform_driver pcmtst_pdrv = {
+ .probe = pcmtst_probe,
+ .remove = pdev_remove,
+ .driver = {
+ .name = "pcmtest",
+ },
+};
+
+static ssize_t pattern_write(struct file *file, const char __user *u_buff, size_t len, loff_t *off)
+{
+ struct pattern_buf *patt_buf = file->f_inode->i_private;
+ ssize_t to_write = len;
+
+ if (*off + to_write > MAX_PATTERN_LEN)
+ to_write = MAX_PATTERN_LEN - *off;
+
+ // Crop silently everything over the buffer
+ if (to_write <= 0)
+ return len;
+
+ if (copy_from_user(patt_buf->buf + *off, u_buff, to_write))
+ return -EFAULT;
+
+ patt_buf->len = *off + to_write;
+ *off += to_write;
+
+ return to_write;
+}
+
+static ssize_t pattern_read(struct file *file, char __user *u_buff, size_t len, loff_t *off)
+{
+ struct pattern_buf *patt_buf = file->f_inode->i_private;
+ ssize_t to_read = len;
+
+ if (*off + to_read >= MAX_PATTERN_LEN)
+ to_read = MAX_PATTERN_LEN - *off;
+ if (to_read <= 0)
+ return 0;
+
+ if (copy_to_user(u_buff, patt_buf->buf + *off, to_read))
+ to_read = 0;
+ else
+ *off += to_read;
+
+ return to_read;
+}
+
+static const struct file_operations fill_pattern_fops = {
+ .read = pattern_read,
+ .write = pattern_write,
+};
+
+static int setup_patt_bufs(void)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(patt_bufs); i++) {
+ patt_bufs[i].buf = kmalloc(MAX_PATTERN_LEN, GFP_KERNEL);
+ if (!patt_bufs[i].buf)
+ break;
+ strscpy_pad(patt_bufs[i].buf, DEFAULT_PATTERN, MAX_PATTERN_LEN);
+ patt_bufs[i].len = DEFAULT_PATTERN_LEN;
+ }
+
+ return i;
+}
+
+static const char * const pattern_files[] = { "fill_pattern0", "fill_pattern1",
+ "fill_pattern2", "fill_pattern3"};
+static int init_debug_files(int buf_count)
+{
+ size_t i;
+ char len_file_name[32];
+
+ driver_debug_dir = debugfs_create_dir("pcmtest", NULL);
+ if (IS_ERR(driver_debug_dir))
+ return PTR_ERR(driver_debug_dir);
+ debugfs_create_u8("pc_test", 0444, driver_debug_dir, &playback_capture_test);
+ debugfs_create_u8("ioctl_test", 0444, driver_debug_dir, &ioctl_reset_test);
+
+ for (i = 0; i < buf_count; i++) {
+ debugfs_create_file(pattern_files[i], 0600, driver_debug_dir,
+ &patt_bufs[i], &fill_pattern_fops);
+ snprintf(len_file_name, sizeof(len_file_name), "%s_len", pattern_files[i]);
+ debugfs_create_u32(len_file_name, 0444, driver_debug_dir, &patt_bufs[i].len);
+ }
+
+ return 0;
+}
+
+static void free_pattern_buffers(void)
+{
+ int i;
+
+ for (i = 0; i < buf_allocated; i++)
+ kfree(patt_bufs[i].buf);
+}
+
+static void clear_debug_files(void)
+{
+ debugfs_remove_recursive(driver_debug_dir);
+}
+
+static int __init mod_init(void)
+{
+ int err = 0;
+
+ buf_allocated = setup_patt_bufs();
+ if (!buf_allocated)
+ return -ENOMEM;
+
+ snd_pcmtst_hw.channels_max = buf_allocated;
+
+ err = init_debug_files(buf_allocated);
+ if (err)
+ return err;
+ err = platform_device_register(&pcmtst_pdev);
+ if (err)
+ return err;
+ err = platform_driver_register(&pcmtst_pdrv);
+ if (err)
+ platform_device_unregister(&pcmtst_pdev);
+ return err;
+}
+
+static void __exit mod_exit(void)
+{
+ clear_debug_files();
+ free_pattern_buffers();
+
+ platform_driver_unregister(&pcmtst_pdrv);
+ platform_device_unregister(&pcmtst_pdev);
+}
+
+MODULE_DESCRIPTION("Virtual ALSA driver for PCM testing/fuzzing");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ivan Orlov");
+module_init(mod_init);
+module_exit(mod_exit);
diff --git a/sound/drivers/pcsp/Makefile b/sound/drivers/pcsp/Makefile
index 77dc0ee1b598..309c09497261 100644
--- a/sound/drivers/pcsp/Makefile
+++ b/sound/drivers/pcsp/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-pcsp-objs := pcsp.o pcsp_lib.o pcsp_mixer.o pcsp_input.o
+snd-pcsp-y := pcsp.o pcsp_lib.o pcsp_mixer.o pcsp_input.o
obj-$(CONFIG_SND_PCSP) += snd-pcsp.o
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index c7be1c395bcb..ff6bb375c900 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -47,11 +47,12 @@ static int snd_pcsp_create(struct snd_card *card)
if (!nopcm) {
if (resolution > PCSP_MAX_PERIOD_NS) {
- printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
- "(%unS)\n", resolution);
- printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
- "enabled.\n");
- printk(KERN_ERR "PCSP: Turned into nopcm mode.\n");
+ dev_err(card->dev,
+ "PCSP: Timer resolution is not sufficient (%unS)\n",
+ resolution);
+ dev_err(card->dev,
+ "PCSP: Make sure you have HPET and ACPI enabled.\n");
+ dev_err(card->dev, "PCSP: Turned into nopcm mode.\n");
nopcm = 1;
}
}
@@ -61,8 +62,8 @@ static int snd_pcsp_create(struct snd_card *card)
else
min_div = MAX_DIV;
#if PCSP_DEBUG
- printk(KERN_DEBUG "PCSP: lpj=%li, min_div=%i, res=%u\n",
- loops_per_jiffy, min_div, resolution);
+ dev_dbg(card->dev, "PCSP: lpj=%li, min_div=%i, res=%u\n",
+ loops_per_jiffy, min_div, resolution);
#endif
div = MAX_DIV / min_div;
@@ -102,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)
@@ -122,8 +122,8 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev)
if (err < 0)
return err;
- strcpy(card->driver, "PC-Speaker");
- strcpy(card->shortname, "pcsp");
+ strscpy(card->driver, "PC-Speaker");
+ strscpy(card->shortname, "pcsp");
sprintf(card->longname, "Internal PC-Speaker at port 0x%x",
pcsp_chip.port);
@@ -141,14 +141,14 @@ static int alsa_card_pcsp_init(struct device *dev)
err = snd_card_pcsp_probe(0, dev);
if (err) {
- printk(KERN_ERR "PC-Speaker initialization failed.\n");
+ dev_err(dev, "PC-Speaker initialization failed.\n");
return err;
}
/* Well, CONFIG_DEBUG_PAGEALLOC makes the sound horrible. Lets alert */
if (debug_pagealloc_enabled()) {
- printk(KERN_WARNING "PCSP: CONFIG_DEBUG_PAGEALLOC is enabled, "
- "which may make the sound noisy.\n");
+ dev_warn(dev,
+ "PCSP: CONFIG_DEBUG_PAGEALLOC is enabled, which may make the sound noisy.\n");
}
return 0;
@@ -176,7 +176,6 @@ static void pcsp_stop_beep(struct snd_pcsp *chip)
pcspkr_stop_sound();
}
-#ifdef CONFIG_PM_SLEEP
static int pcsp_suspend(struct device *dev)
{
struct snd_pcsp *chip = dev_get_drvdata(dev);
@@ -184,11 +183,7 @@ static int pcsp_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
-#define PCSP_PM_OPS &pcsp_pm
-#else
-#define PCSP_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
static void pcsp_shutdown(struct platform_device *dev)
{
@@ -199,7 +194,7 @@ static void pcsp_shutdown(struct platform_device *dev)
static struct platform_driver pcsp_platform_driver = {
.driver = {
.name = "pcspkr",
- .pm = PCSP_PM_OPS,
+ .pm = &pcsp_pm,
},
.probe = pcsp_probe,
.shutdown = pcsp_shutdown,
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 773db4bf0876..80b313f4fcd3 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -12,6 +12,7 @@
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <sound/core.h>
#include <sound/pcm.h>
#include "pcsp.h"
@@ -105,8 +106,8 @@ static void pcsp_pointer_update(struct snd_pcsp *chip)
periods_elapsed = chip->playback_ptr - chip->period_ptr;
if (periods_elapsed < 0) {
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: buffer_bytes mod period_bytes != 0 ? "
- "(%zi %zi %zi)\n",
+ dev_dbg(chip->card->dev,
+ "PCSP: buffer_bytes mod period_bytes != 0 ? (%zi %zi %zi)\n",
chip->playback_ptr, period_bytes, buffer_bytes);
#endif
periods_elapsed += buffer_bytes;
@@ -136,7 +137,7 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
pointer_update = !chip->thalf;
ns = pcsp_timer_update(chip);
if (!ns) {
- printk(KERN_WARNING "PCSP: unexpected stop\n");
+ dev_warn(chip->card->dev, "PCSP: unexpected stop\n");
return HRTIMER_NORESTART;
}
@@ -151,10 +152,10 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
static int pcsp_start_playing(struct snd_pcsp *chip)
{
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: start_playing called\n");
+ dev_dbg(chip->card->dev, "PCSP: start_playing called\n");
#endif
if (atomic_read(&chip->timer_active)) {
- printk(KERN_ERR "PCSP: Timer already active\n");
+ dev_err(chip->card->dev, "PCSP: Timer already active\n");
return -EIO;
}
@@ -172,7 +173,7 @@ static int pcsp_start_playing(struct snd_pcsp *chip)
static void pcsp_stop_playing(struct snd_pcsp *chip)
{
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: stop_playing called\n");
+ dev_dbg(chip->card->dev, "PCSP: stop_playing called\n");
#endif
if (!atomic_read(&chip->timer_active))
return;
@@ -201,7 +202,7 @@ static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
{
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: close called\n");
+ dev_dbg(chip->card->dev, "PCSP: close called\n");
#endif
pcsp_sync_stop(chip);
chip->playback_substream = NULL;
@@ -220,7 +221,7 @@ static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
{
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: hw_free called\n");
+ dev_dbg(chip->card->dev, "PCSP: hw_free called\n");
#endif
pcsp_sync_stop(chip);
return 0;
@@ -236,14 +237,13 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
snd_pcm_format_physical_width(substream->runtime->format) >> 3;
chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: prepare called, "
- "size=%zi psize=%zi f=%zi f1=%i fsize=%i\n",
- snd_pcm_lib_buffer_bytes(substream),
- snd_pcm_lib_period_bytes(substream),
- snd_pcm_lib_buffer_bytes(substream) /
- snd_pcm_lib_period_bytes(substream),
- substream->runtime->periods,
- chip->fmt_size);
+ dev_dbg(chip->card->dev, "PCSP: prepare called, size=%zi psize=%zi f=%zi f1=%i fsize=%i\n",
+ snd_pcm_lib_buffer_bytes(substream),
+ snd_pcm_lib_period_bytes(substream),
+ snd_pcm_lib_buffer_bytes(substream) /
+ snd_pcm_lib_period_bytes(substream),
+ substream->runtime->periods,
+ chip->fmt_size);
#endif
return 0;
}
@@ -252,7 +252,7 @@ static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: trigger called\n");
+ dev_dbg(chip->card->dev, "PCSP: trigger called\n");
#endif
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -306,10 +306,10 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream)
struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: open called\n");
+ dev_dbg(chip->card->dev, "PCSP: open called\n");
#endif
if (atomic_read(&chip->timer_active)) {
- printk(KERN_ERR "PCSP: still active!!\n");
+ dev_err(chip->card->dev, "PCSP: still active!!\n");
return -EBUSY;
}
runtime->hw = snd_pcsp_playback;
@@ -340,7 +340,7 @@ int snd_pcsp_new_pcm(struct snd_pcsp *chip)
chip->pcm->private_data = chip;
chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
- strcpy(chip->pcm->name, "pcsp");
+ strscpy(chip->pcm->name, "pcsp");
snd_pcm_set_managed_buffer_all(chip->pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c
index da33e5b620a7..27d6150329a8 100644
--- a/sound/drivers/pcsp/pcsp_mixer.c
+++ b/sound/drivers/pcsp/pcsp_mixer.c
@@ -73,7 +73,7 @@ static int pcsp_treble_put(struct snd_kcontrol *kcontrol,
if (treble != chip->treble) {
chip->treble = treble;
#if PCSP_DEBUG
- printk(KERN_INFO "PCSP: rate set to %li\n", PCSP_RATE());
+ dev_dbg(chip->card->dev, "PCSP: rate set to %li\n", PCSP_RATE());
#endif
changed = 1;
}
@@ -158,7 +158,7 @@ int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm)
if (err < 0)
return err;
- strcpy(card->mixername, "PC-Speaker");
+ strscpy(card->mixername, "PC-Speaker");
return 0;
}
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index 619e3f594477..b903a138fc2a 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -385,9 +385,8 @@ static void portman_flush_input(struct portman *pm, unsigned char port)
command = RXDATA1;
break;
default:
- snd_printk(KERN_WARNING
- "portman_flush_input() Won't flush port %i\n",
- port);
+ dev_warn(pm->card->dev, "%s Won't flush port %i\n",
+ __func__, port);
return;
}
@@ -497,29 +496,25 @@ static void snd_portman_midi_input_trigger(struct snd_rawmidi_substream *substre
int up)
{
struct portman *pm = substream->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&pm->reg_lock, flags);
+ guard(spinlock_irqsave)(&pm->reg_lock);
if (up)
pm->mode[substream->number] |= PORTMAN2X4_MODE_INPUT_TRIGGERED;
else
pm->mode[substream->number] &= ~PORTMAN2X4_MODE_INPUT_TRIGGERED;
- spin_unlock_irqrestore(&pm->reg_lock, flags);
}
static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substream,
int up)
{
struct portman *pm = substream->rmidi->private_data;
- unsigned long flags;
unsigned char byte;
- spin_lock_irqsave(&pm->reg_lock, flags);
+ guard(spinlock_irqsave)(&pm->reg_lock);
if (up) {
while ((snd_rawmidi_transmit(substream, &byte, 1) == 1))
portman_write_midi(pm, substream->number, byte);
}
- spin_unlock_irqrestore(&pm->reg_lock, flags);
}
static const struct snd_rawmidi_ops snd_portman_midi_output = {
@@ -550,7 +545,7 @@ static int snd_portman_rawmidi_create(struct snd_card *card)
return err;
rmidi->private_data = pm;
- strcpy(rmidi->name, CARD_NAME);
+ strscpy(rmidi->name, CARD_NAME);
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -591,7 +586,7 @@ static void snd_portman_interrupt(void *userdata)
unsigned char midivalue = 0;
struct portman *pm = ((struct snd_card*)userdata)->private_data;
- spin_lock(&pm->reg_lock);
+ guard(spinlock)(&pm->reg_lock);
/* While any input data is waiting */
while ((portman_read_status(pm) & INT_REQ) == INT_REQ) {
@@ -618,8 +613,6 @@ static void snd_portman_interrupt(void *userdata)
}
}
-
- spin_unlock(&pm->reg_lock);
}
static void snd_portman_attach(struct parport *p)
@@ -668,7 +661,6 @@ static struct parport_driver portman_parport_driver = {
.probe = snd_portman_dev_probe,
.match_port = snd_portman_attach,
.detach = snd_portman_detach,
- .devmodel = true,
};
/*********************************************************************
@@ -713,11 +705,11 @@ static int snd_portman_probe(struct platform_device *pdev)
err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
- snd_printd("Cannot create card\n");
+ dev_dbg(&pdev->dev, "Cannot create card\n");
return err;
}
- strcpy(card->driver, DRIVER_NAME);
- strcpy(card->shortname, CARD_NAME);
+ strscpy(card->driver, DRIVER_NAME);
+ strscpy(card->shortname, CARD_NAME);
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, p->base, p->irq);
@@ -727,21 +719,21 @@ static int snd_portman_probe(struct platform_device *pdev)
&portman_cb, /* callbacks */
pdev->id); /* device number */
if (pardev == NULL) {
- snd_printd("Cannot register pardevice\n");
+ dev_dbg(card->dev, "Cannot register pardevice\n");
err = -EIO;
goto __err;
}
/* claim parport */
if (parport_claim(pardev)) {
- snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base);
+ dev_dbg(card->dev, "Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO;
goto free_pardev;
}
err = portman_create(card, pardev, &pm);
if (err < 0) {
- snd_printd("Cannot create main component\n");
+ dev_dbg(card->dev, "Cannot create main component\n");
goto release_pardev;
}
card->private_data = pm;
@@ -755,7 +747,7 @@ static int snd_portman_probe(struct platform_device *pdev)
err = snd_portman_rawmidi_create(card);
if (err < 0) {
- snd_printd("Creating Rawmidi component failed\n");
+ dev_dbg(card->dev, "Creating Rawmidi component failed\n");
goto __err;
}
@@ -769,11 +761,11 @@ static int snd_portman_probe(struct platform_device *pdev)
/* At this point card will be usable */
err = snd_card_register(card);
if (err < 0) {
- snd_printd("Cannot register card\n");
+ dev_dbg(card->dev, "Cannot register card\n");
goto __err;
}
- snd_printk(KERN_INFO "Portman 2x4 on 0x%lx\n", p->base);
+ dev_info(card->dev, "Portman 2x4 on 0x%lx\n", p->base);
return 0;
release_pardev:
@@ -796,7 +788,7 @@ static void snd_portman_remove(struct platform_device *pdev)
static struct platform_driver snd_portman_driver = {
.probe = snd_portman_probe,
- .remove_new = snd_portman_remove,
+ .remove = snd_portman_remove,
.driver = {
.name = PLATFORM_DRIVER,
}
diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c
index e1f864dc7939..766206c6ca75 100644
--- a/sound/drivers/serial-generic.c
+++ b/sound/drivers/serial-generic.c
@@ -16,7 +16,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/serdev.h>
#include <linux/serial_reg.h>
#include <linux/slab.h>
@@ -37,6 +37,8 @@ MODULE_LICENSE("GPL");
#define SERIAL_TX_STATE_ACTIVE 1
#define SERIAL_TX_STATE_WAKEUP 2
+#define INTERNAL_BUF_SIZE 256
+
struct snd_serial_generic {
struct serdev_device *serdev;
@@ -51,6 +53,7 @@ struct snd_serial_generic {
struct work_struct tx_work;
unsigned long tx_state;
+ char tx_buf[INTERNAL_BUF_SIZE];
};
static void snd_serial_generic_tx_wakeup(struct snd_serial_generic *drvdata)
@@ -61,11 +64,8 @@ static void snd_serial_generic_tx_wakeup(struct snd_serial_generic *drvdata)
schedule_work(&drvdata->tx_work);
}
-#define INTERNAL_BUF_SIZE 256
-
static void snd_serial_generic_tx_work(struct work_struct *work)
{
- static char buf[INTERNAL_BUF_SIZE];
int num_bytes;
struct snd_serial_generic *drvdata = container_of(work, struct snd_serial_generic,
tx_work);
@@ -78,8 +78,10 @@ static void snd_serial_generic_tx_work(struct work_struct *work)
if (!test_bit(SERIAL_MODE_OUTPUT_OPEN, &drvdata->filemode))
break;
- num_bytes = snd_rawmidi_transmit_peek(substream, buf, INTERNAL_BUF_SIZE);
- num_bytes = serdev_device_write_buf(drvdata->serdev, buf, num_bytes);
+ num_bytes = snd_rawmidi_transmit_peek(substream, drvdata->tx_buf,
+ INTERNAL_BUF_SIZE);
+ num_bytes = serdev_device_write_buf(drvdata->serdev, drvdata->tx_buf,
+ num_bytes);
if (!num_bytes)
break;
@@ -100,8 +102,8 @@ static void snd_serial_generic_write_wakeup(struct serdev_device *serdev)
snd_serial_generic_tx_wakeup(drvdata);
}
-static int snd_serial_generic_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t count)
+static size_t snd_serial_generic_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t count)
{
int ret;
struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);
@@ -300,7 +302,7 @@ static int snd_serial_generic_rmidi(struct snd_serial_generic *drvdata,
&snd_serial_generic_input);
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&snd_serial_generic_output);
- strcpy(rrawmidi->name, drvdata->card->shortname);
+ strscpy(rrawmidi->name, drvdata->card->shortname);
snd_serial_generic_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
drvdata->serdev->ctrl->nr);
@@ -329,7 +331,7 @@ static int snd_serial_generic_probe(struct serdev_device *serdev)
if (err < 0)
return err;
- strcpy(card->driver, "SerialMIDI");
+ strscpy(card->driver, "SerialMIDI");
sprintf(card->shortname, "SerialMIDI-%d", serdev->ctrl->nr);
sprintf(card->longname, "Serial MIDI device at serial%d", serdev->ctrl->nr);
@@ -366,7 +368,7 @@ MODULE_DEVICE_TABLE(of, snd_serial_generic_dt_ids);
static struct serdev_device_driver snd_serial_generic_driver = {
.driver = {
.name = "snd-serial-generic",
- .of_match_table = of_match_ptr(snd_serial_generic_dt_ids),
+ .of_match_table = snd_serial_generic_dt_ids,
},
.probe = snd_serial_generic_probe,
};
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 3cbc7a4adcb4..3c28961091b1 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -166,7 +166,7 @@ static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
static inline void snd_uart16550_del_timer(struct snd_uart16550 *uart)
{
if (uart->timer_running) {
- del_timer(&uart->buffer_timer);
+ timer_delete(&uart->buffer_timer);
uart->timer_running = 0;
}
}
@@ -224,9 +224,9 @@ static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
if (status & UART_LSR_OE)
- snd_printk(KERN_WARNING
- "%s: Overrun on device at 0x%lx\n",
- uart->rmidi->name, uart->base);
+ dev_warn(uart->card->dev,
+ "%s: Overrun on device at 0x%lx\n",
+ uart->rmidi->name, uart->base);
}
/* remember the last stream */
@@ -281,29 +281,24 @@ static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
struct snd_uart16550 *uart;
uart = dev_id;
- spin_lock(&uart->open_lock);
- if (uart->filemode == SERIAL_MODE_NOT_OPENED) {
- spin_unlock(&uart->open_lock);
+ guard(spinlock)(&uart->open_lock);
+ if (uart->filemode == SERIAL_MODE_NOT_OPENED)
return IRQ_NONE;
- }
/* indicate to the UART that the interrupt has been serviced */
inb(uart->base + UART_IIR);
snd_uart16550_io_loop(uart);
- spin_unlock(&uart->open_lock);
return IRQ_HANDLED;
}
/* When the polling mode, this function calls snd_uart16550_io_loop. */
static void snd_uart16550_buffer_timer(struct timer_list *t)
{
- unsigned long flags;
struct snd_uart16550 *uart;
- uart = from_timer(uart, t, buffer_timer);
- spin_lock_irqsave(&uart->open_lock, flags);
+ uart = timer_container_of(uart, t, buffer_timer);
+ guard(spinlock_irqsave)(&uart->open_lock);
snd_uart16550_del_timer(uart);
snd_uart16550_io_loop(uart);
- spin_unlock_irqrestore(&uart->open_lock, flags);
}
/*
@@ -323,7 +318,8 @@ static int snd_uart16550_detect(struct snd_uart16550 *uart)
}
if (!devm_request_region(uart->card->dev, io_base, 8, "Serial MIDI")) {
- snd_printk(KERN_ERR "u16550: can't grab port 0x%lx\n", io_base);
+ dev_err(uart->card->dev,
+ "u16550: can't grab port 0x%lx\n", io_base);
return -EBUSY;
}
@@ -498,71 +494,61 @@ static void snd_uart16550_do_close(struct snd_uart16550 * uart)
static int snd_uart16550_input_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_uart16550 *uart = substream->rmidi->private_data;
- spin_lock_irqsave(&uart->open_lock, flags);
+ guard(spinlock_irqsave)(&uart->open_lock);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
snd_uart16550_do_open(uart);
uart->filemode |= SERIAL_MODE_INPUT_OPEN;
uart->midi_input[substream->number] = substream;
- spin_unlock_irqrestore(&uart->open_lock, flags);
return 0;
}
static int snd_uart16550_input_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_uart16550 *uart = substream->rmidi->private_data;
- spin_lock_irqsave(&uart->open_lock, flags);
+ guard(spinlock_irqsave)(&uart->open_lock);
uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
uart->midi_input[substream->number] = NULL;
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
snd_uart16550_do_close(uart);
- spin_unlock_irqrestore(&uart->open_lock, flags);
return 0;
}
static void snd_uart16550_input_trigger(struct snd_rawmidi_substream *substream,
int up)
{
- unsigned long flags;
struct snd_uart16550 *uart = substream->rmidi->private_data;
- spin_lock_irqsave(&uart->open_lock, flags);
+ guard(spinlock_irqsave)(&uart->open_lock);
if (up)
uart->filemode |= SERIAL_MODE_INPUT_TRIGGERED;
else
uart->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED;
- spin_unlock_irqrestore(&uart->open_lock, flags);
}
static int snd_uart16550_output_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_uart16550 *uart = substream->rmidi->private_data;
- spin_lock_irqsave(&uart->open_lock, flags);
+ guard(spinlock_irqsave)(&uart->open_lock);
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
snd_uart16550_do_open(uart);
uart->filemode |= SERIAL_MODE_OUTPUT_OPEN;
uart->midi_output[substream->number] = substream;
- spin_unlock_irqrestore(&uart->open_lock, flags);
return 0;
};
static int snd_uart16550_output_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_uart16550 *uart = substream->rmidi->private_data;
- spin_lock_irqsave(&uart->open_lock, flags);
+ guard(spinlock_irqsave)(&uart->open_lock);
uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN;
uart->midi_output[substream->number] = NULL;
if (uart->filemode == SERIAL_MODE_NOT_OPENED)
snd_uart16550_do_close(uart);
- spin_unlock_irqrestore(&uart->open_lock, flags);
return 0;
};
@@ -619,9 +605,9 @@ static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
}
} else {
if (!snd_uart16550_write_buffer(uart, midi_byte)) {
- snd_printk(KERN_WARNING
- "%s: Buffer overrun on device at 0x%lx\n",
- uart->rmidi->name, uart->base);
+ dev_warn(uart->card->dev,
+ "%s: Buffer overrun on device at 0x%lx\n",
+ uart->rmidi->name, uart->base);
return 0;
}
}
@@ -631,7 +617,6 @@ static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
unsigned char midi_byte, addr_byte;
struct snd_uart16550 *uart = substream->rmidi->private_data;
char first;
@@ -642,7 +627,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
* variables (ie buff_in & buff_out)
*/
- spin_lock_irqsave(&uart->open_lock, flags);
+ guard(spinlock_irqsave)(&uart->open_lock);
if (uart->irq < 0) /* polling */
snd_uart16550_io_loop(uart);
@@ -717,21 +702,19 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
}
lasttime = jiffies;
}
- spin_unlock_irqrestore(&uart->open_lock, flags);
}
static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream,
int up)
{
- unsigned long flags;
struct snd_uart16550 *uart = substream->rmidi->private_data;
- spin_lock_irqsave(&uart->open_lock, flags);
- if (up)
- uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;
- else
- uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;
- spin_unlock_irqrestore(&uart->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &uart->open_lock) {
+ if (up)
+ uart->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED;
+ else
+ uart->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED;
+ }
if (up)
snd_uart16550_output_write(substream);
}
@@ -775,15 +758,15 @@ static int snd_uart16550_create(struct snd_card *card,
err = snd_uart16550_detect(uart);
if (err <= 0) {
- printk(KERN_ERR "no UART detected at 0x%lx\n", iobase);
+ dev_err(card->dev, "no UART detected at 0x%lx\n", iobase);
return -ENODEV;
}
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
if (devm_request_irq(card->dev, irq, snd_uart16550_interrupt,
0, "Serial MIDI", uart)) {
- snd_printk(KERN_WARNING
- "irq %d busy. Using Polling.\n", irq);
+ dev_warn(card->dev,
+ "irq %d busy. Using Polling.\n", irq);
} else {
uart->irq = irq;
}
@@ -844,7 +827,7 @@ static int snd_uart16550_rmidi(struct snd_uart16550 *uart, int device,
&snd_uart16550_input);
snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&snd_uart16550_output);
- strcpy(rrawmidi->name, "Serial MIDI");
+ strscpy(rrawmidi->name, "Serial MIDI");
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
snd_uart16550_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
rrawmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
@@ -879,23 +862,23 @@ static int snd_serial_probe(struct platform_device *devptr)
case SNDRV_SERIAL_GENERIC:
break;
default:
- snd_printk(KERN_ERR
- "Adaptor type is out of range 0-%d (%d)\n",
- SNDRV_SERIAL_MAX_ADAPTOR, adaptor[dev]);
+ dev_err(&devptr->dev,
+ "Adaptor type is out of range 0-%d (%d)\n",
+ SNDRV_SERIAL_MAX_ADAPTOR, adaptor[dev]);
return -ENODEV;
}
if (outs[dev] < 1 || outs[dev] > SNDRV_SERIAL_MAX_OUTS) {
- snd_printk(KERN_ERR
- "Count of outputs is out of range 1-%d (%d)\n",
- SNDRV_SERIAL_MAX_OUTS, outs[dev]);
+ dev_err(&devptr->dev,
+ "Count of outputs is out of range 1-%d (%d)\n",
+ SNDRV_SERIAL_MAX_OUTS, outs[dev]);
return -ENODEV;
}
if (ins[dev] < 1 || ins[dev] > SNDRV_SERIAL_MAX_INS) {
- snd_printk(KERN_ERR
- "Count of inputs is out of range 1-%d (%d)\n",
- SNDRV_SERIAL_MAX_INS, ins[dev]);
+ dev_err(&devptr->dev,
+ "Count of inputs is out of range 1-%d (%d)\n",
+ SNDRV_SERIAL_MAX_INS, ins[dev]);
return -ENODEV;
}
@@ -904,8 +887,8 @@ static int snd_serial_probe(struct platform_device *devptr)
if (err < 0)
return err;
- strcpy(card->driver, "Serial");
- strcpy(card->shortname, "Serial MIDI (UART16550A)");
+ strscpy(card->driver, "Serial");
+ strscpy(card->shortname, "Serial MIDI (UART16550A)");
err = snd_uart16550_create(card, port[dev], irq[dev], speed[dev],
base[dev], adaptor[dev], droponfull[dev],
@@ -975,7 +958,7 @@ static int __init alsa_card_serial_init(void)
}
if (! cards) {
#ifdef MODULE
- printk(KERN_ERR "serial midi soundcard not found or device busy\n");
+ pr_err("serial midi soundcard not found or device busy\n");
#endif
snd_serial_unregister_all();
return -ENODEV;
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 58012de90c38..a204f42d1026 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -83,9 +83,9 @@ static int snd_virmidi_probe(struct platform_device *devptr)
vmidi->card = card;
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
- snd_printk(KERN_WARNING
- "too much midi devices for virmidi %d: force to use %d\n",
- dev, MAX_MIDI_DEVICES);
+ dev_warn(&devptr->dev,
+ "too much midi devices for virmidi %d: force to use %d\n",
+ dev, MAX_MIDI_DEVICES);
midi_devs[dev] = MAX_MIDI_DEVICES;
}
for (idx = 0; idx < midi_devs[dev]; idx++) {
@@ -95,11 +95,11 @@ static int snd_virmidi_probe(struct platform_device *devptr)
if (err < 0)
return err;
vmidi->midi[idx] = rmidi;
- strcpy(rmidi->name, "Virtual Raw MIDI");
+ strscpy(rmidi->name, "Virtual Raw MIDI");
}
- strcpy(card->driver, "VirMIDI");
- strcpy(card->shortname, "VirMIDI");
+ strscpy(card->driver, "VirMIDI");
+ strscpy(card->shortname, "VirMIDI");
sprintf(card->longname, "Virtual MIDI Card %i", dev + 1);
err = snd_card_register(card);
@@ -155,7 +155,7 @@ static int __init alsa_card_virmidi_init(void)
}
if (!cards) {
#ifdef MODULE
- printk(KERN_ERR "Card-VirMIDI soundcard not found or device busy\n");
+ pr_err("Card-VirMIDI soundcard not found or device busy\n");
#endif
snd_virmidi_unregister_all();
return -ENODEV;
diff --git a/sound/drivers/vx/Makefile b/sound/drivers/vx/Makefile
index d9f9ac670378..ae1b3e09283f 100644
--- a/sound/drivers/vx/Makefile
+++ b/sound/drivers/vx/Makefile
@@ -4,6 +4,6 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-vx-lib-objs := vx_core.o vx_hwdep.o vx_pcm.o vx_mixer.o vx_cmd.o vx_uer.o
+snd-vx-lib-y := vx_core.o vx_hwdep.o vx_pcm.o vx_mixer.o vx_cmd.o vx_uer.o
obj-$(CONFIG_SND_VX_LIB) += snd-vx-lib.o
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 18901e5bcfcf..52b93407bfe3 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -52,7 +52,9 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
return 0;
//msleep(10);
} while (time_after_eq(end_time, jiffies));
- snd_printd(KERN_DEBUG "vx_check_reg_bit: timeout, reg=%s, mask=0x%x, val=0x%x\n", reg_names[reg], mask, snd_vx_inb(chip, reg));
+ dev_dbg(chip->card->dev,
+ "vx_check_reg_bit: timeout, reg=%s, mask=0x%x, val=0x%x\n",
+ reg_names[reg], mask, snd_vx_inb(chip, reg));
return -EIO;
}
@@ -129,13 +131,14 @@ static int vx_transfer_end(struct vx_core *chip, int cmd)
if (err & ISR_ERR) {
err = vx_wait_for_rx_full(chip);
if (err < 0) {
- snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n");
+ dev_dbg(chip->card->dev,
+ "transfer_end: error in rx_full\n");
return err;
}
err = vx_inb(chip, RXH) << 16;
err |= vx_inb(chip, RXM) << 8;
err |= vx_inb(chip, RXL);
- snd_printd(KERN_DEBUG "transfer_end: error = 0x%x\n", err);
+ dev_dbg(chip->card->dev, "transfer_end: error = 0x%x\n", err);
return -(VX_ERR_MASK | err);
}
return 0;
@@ -239,20 +242,10 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
err = vx_reset_chk(chip);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n");
+ dev_dbg(chip->card->dev, "vx_send_msg: vx_reset_chk error\n");
return err;
}
-#if 0
- printk(KERN_DEBUG "rmh: cmd = 0x%06x, length = %d, stype = %d\n",
- rmh->Cmd[0], rmh->LgCmd, rmh->DspStat);
- if (rmh->LgCmd > 1) {
- printk(KERN_DEBUG " ");
- for (i = 1; i < rmh->LgCmd; i++)
- printk(KERN_CONT "0x%06x ", rmh->Cmd[i]);
- printk(KERN_CONT "\n");
- }
-#endif
/* Check bit M is set according to length of the command */
if (rmh->LgCmd > 1)
rmh->Cmd[0] |= MASK_MORE_THAN_1_WORD_COMMAND;
@@ -262,7 +255,7 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
/* Wait for TX empty */
err = vx_wait_isr_bit(chip, ISR_TX_EMPTY);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n");
+ dev_dbg(chip->card->dev, "vx_send_msg: wait tx empty error\n");
return err;
}
@@ -274,7 +267,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
/* Trigger irq MESSAGE */
err = vx_send_irq_dsp(chip, IRQ_MESSAGE);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n");
+ dev_dbg(chip->card->dev,
+ "vx_send_msg: send IRQ_MESSAGE error\n");
return err;
}
@@ -287,13 +281,15 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
if (vx_inb(chip, ISR) & ISR_ERR) {
err = vx_wait_for_rx_full(chip);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n");
+ dev_dbg(chip->card->dev,
+ "vx_send_msg: rx_full read error\n");
return err;
}
err = vx_inb(chip, RXH) << 16;
err |= vx_inb(chip, RXM) << 8;
err |= vx_inb(chip, RXL);
- snd_printd(KERN_DEBUG "msg got error = 0x%x at cmd[0]\n", err);
+ dev_dbg(chip->card->dev,
+ "msg got error = 0x%x at cmd[0]\n", err);
err = -(VX_ERR_MASK | err);
return err;
}
@@ -304,7 +300,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
/* Wait for TX ready */
err = vx_wait_isr_bit(chip, ISR_TX_READY);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n");
+ dev_dbg(chip->card->dev,
+ "vx_send_msg: tx_ready error\n");
return err;
}
@@ -316,14 +313,16 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
/* Trigger irq MESS_READ_NEXT */
err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n");
+ dev_dbg(chip->card->dev,
+ "vx_send_msg: IRQ_READ_NEXT error\n");
return err;
}
}
/* Wait for TX empty */
err = vx_wait_isr_bit(chip, ISR_TX_READY);
if (err < 0) {
- snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n");
+ dev_dbg(chip->card->dev,
+ "vx_send_msg: TX_READY error\n");
return err;
}
/* End of transfer */
@@ -345,12 +344,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
*/
int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh)
{
- int err;
-
- mutex_lock(&chip->lock);
- err = vx_send_msg_nolock(chip, rmh);
- mutex_unlock(&chip->lock);
- return err;
+ guard(mutex)(&chip->lock);
+ return vx_send_msg_nolock(chip, rmh);
}
@@ -372,9 +367,6 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd)
if (chip->chip_status & VX_STAT_IS_STALE)
return -EBUSY;
-#if 0
- printk(KERN_DEBUG "send_rih: cmd = 0x%x\n", cmd);
-#endif
err = vx_reset_chk(chip);
if (err < 0)
return err;
@@ -408,12 +400,8 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd)
*/
int vx_send_rih(struct vx_core *chip, int cmd)
{
- int err;
-
- mutex_lock(&chip->lock);
- err = vx_send_rih_nolock(chip, cmd);
- mutex_unlock(&chip->lock);
- return err;
+ guard(mutex)(&chip->lock);
+ return vx_send_rih_nolock(chip, cmd);
}
#define END_OF_RESET_WAIT_TIME 500 /* us */
@@ -453,7 +441,7 @@ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
if (no_fillup)
break;
if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) {
- snd_printk(KERN_ERR "dsp boot failed at %d\n", i);
+ dev_err(chip->card->dev, "dsp boot failed at %d\n", i);
return -EIO;
}
vx_outb(chip, TXH, 0);
@@ -462,7 +450,7 @@ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
} else {
const unsigned char *image = boot->data + i;
if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) {
- snd_printk(KERN_ERR "dsp boot failed at %d\n", i);
+ dev_err(chip->card->dev, "dsp boot failed at %d\n", i);
return -EIO;
}
vx_outb(chip, TXH, image[0]);
@@ -485,13 +473,12 @@ static int vx_test_irq_src(struct vx_core *chip, unsigned int *ret)
int err;
vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT);
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
err = vx_send_msg_nolock(chip, &chip->irq_rmh);
if (err < 0)
*ret = 0;
else
*ret = chip->irq_rmh.Stat[0];
- mutex_unlock(&chip->lock);
return err;
}
@@ -510,18 +497,12 @@ irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev)
if (vx_test_irq_src(chip, &events) < 0)
return IRQ_HANDLED;
-#if 0
- if (events & 0x000800)
- printk(KERN_ERR "DSP Stream underrun ! IRQ events = 0x%x\n", events);
-#endif
- // printk(KERN_DEBUG "IRQ events = 0x%x\n", events);
-
/* We must prevent any application using this DSP
* and block any further request until the application
* either unregisters or reloads the DSP
*/
if (events & FATAL_DSP_ERROR) {
- snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n");
+ dev_err(chip->card->dev, "vx_core: fatal DSP error!!\n");
return IRQ_HANDLED;
}
@@ -698,8 +679,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
/* Wait DSP ready for a new read */
err = vx_wait_isr_bit(chip, ISR_TX_EMPTY);
if (err < 0) {
- printk(KERN_ERR
- "dsp loading error at position %d\n", i);
+ dev_err(chip->card->dev,
+ "dsp loading error at position %d\n", i);
return err;
}
cptr = image;
@@ -713,7 +694,6 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
csum = (csum >> 24) | (csum << 8);
vx_outb(chip, TXL, *cptr++);
}
- snd_printdd(KERN_DEBUG "checksum = 0x%08x\n", csum);
msleep(200);
@@ -759,7 +739,8 @@ int snd_vx_resume(struct vx_core *chip)
continue;
err = chip->ops->load_dsp(chip, i, chip->firmware[i]);
if (err < 0) {
- snd_printk(KERN_ERR "vx: firmware resume error at DSP %d\n", i);
+ dev_err(chip->card->dev,
+ "vx: firmware resume error at DSP %d\n", i);
return -EIO;
}
}
@@ -816,7 +797,7 @@ struct vx_core *snd_vx_create(struct snd_card *card,
chip->card = card;
card->private_data = chip;
- strcpy(card->driver, hw->name);
+ strscpy(card->driver, hw->name);
sprintf(card->shortname, "Digigram %s", hw->name);
vx_proc_init(chip);
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index efbb644edba1..a7f8ddf4df5a 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -58,8 +58,8 @@ int snd_vx_setup_firmware(struct vx_core *chip)
if (! fw_files[chip->type][i])
continue;
sprintf(path, "vx/%s", fw_files[chip->type][i]);
- if (request_firmware(&fw, path, chip->dev)) {
- snd_printk(KERN_ERR "vx: can't load firmware %s\n", path);
+ if (request_firmware(&fw, path, chip->card->dev)) {
+ dev_err(chip->card->dev, "vx: can't load firmware %s\n", path);
return -ENOENT;
}
err = chip->ops->load_dsp(chip, i, fw);
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 53d78eb13c53..9dc5cecaa86a 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -25,9 +25,8 @@ static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int dat
if (chip->chip_status & VX_STAT_IS_STALE)
return;
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
chip->ops->write_codec(chip, codec, data);
- mutex_unlock(&chip->lock);
}
/*
@@ -166,9 +165,8 @@ static void vx_change_audio_source(struct vx_core *chip, int src)
if (chip->chip_status & VX_STAT_IS_STALE)
return;
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
chip->ops->change_audio_source(chip, src);
- mutex_unlock(&chip->lock);
}
@@ -411,10 +409,10 @@ static int vx_output_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
{
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
int codec = kcontrol->id.index;
- mutex_lock(&chip->mixer_mutex);
+
+ guard(mutex)(&chip->mixer_mutex);
ucontrol->value.integer.value[0] = chip->output_level[codec][0];
ucontrol->value.integer.value[1] = chip->output_level[codec][1];
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -429,16 +427,14 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
val[1] = ucontrol->value.integer.value[1];
if (val[0] > vmax || val[1] > vmax)
return -EINVAL;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (val[0] != chip->output_level[codec][0] ||
val[1] != chip->output_level[codec][1]) {
vx_set_analog_output_level(chip, codec, val[0], val[1]);
chip->output_level[codec][0] = val[0];
chip->output_level[codec][1] = val[1];
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -490,14 +486,12 @@ static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
if (ucontrol->value.enumerated.item[0] > 1)
return -EINVAL;
}
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) {
chip->audio_source_target = ucontrol->value.enumerated.item[0];
vx_sync_audio_source(chip);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -534,14 +528,12 @@ static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
if (ucontrol->value.enumerated.item[0] > 2)
return -EINVAL;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (chip->clock_mode != ucontrol->value.enumerated.item[0]) {
chip->clock_mode = ucontrol->value.enumerated.item[0];
vx_set_clock(chip, chip->freq);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -571,10 +563,9 @@ static int vx_audio_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
int audio = kcontrol->private_value & 0xff;
int capture = (kcontrol->private_value >> 8) & 1;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio];
ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1];
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -589,15 +580,13 @@ static int vx_audio_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
val[1] = ucontrol->value.integer.value[1];
if (val[0] > CVAL_MAX || val[1] > CVAL_MAX)
return -EINVAL;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (val[0] != chip->audio_gain[capture][audio] ||
val[1] != chip->audio_gain[capture][audio+1]) {
vx_set_audio_gain(chip, audio, capture, val[0]);
vx_set_audio_gain(chip, audio+1, capture, val[1]);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -606,10 +595,9 @@ static int vx_audio_monitor_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
int audio = kcontrol->private_value & 0xff;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
ucontrol->value.integer.value[0] = chip->audio_monitor[audio];
ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1];
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -624,17 +612,15 @@ static int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
if (val[0] > CVAL_MAX || val[1] > CVAL_MAX)
return -EINVAL;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (val[0] != chip->audio_monitor[audio] ||
val[1] != chip->audio_monitor[audio+1]) {
vx_set_monitor_level(chip, audio, val[0],
chip->audio_monitor_active[audio]);
vx_set_monitor_level(chip, audio+1, val[1],
chip->audio_monitor_active[audio+1]);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -645,10 +631,9 @@ static int vx_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
int audio = kcontrol->private_value & 0xff;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
ucontrol->value.integer.value[0] = chip->audio_active[audio];
ucontrol->value.integer.value[1] = chip->audio_active[audio+1];
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -657,17 +642,15 @@ static int vx_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
int audio = kcontrol->private_value & 0xff;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (ucontrol->value.integer.value[0] != chip->audio_active[audio] ||
ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) {
vx_set_audio_switch(chip, audio,
!!ucontrol->value.integer.value[0]);
vx_set_audio_switch(chip, audio+1,
!!ucontrol->value.integer.value[1]);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -676,10 +659,9 @@ static int vx_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
int audio = kcontrol->private_value & 0xff;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio];
ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1];
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -688,17 +670,15 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
int audio = kcontrol->private_value & 0xff;
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] ||
ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) {
vx_set_monitor_level(chip, audio, chip->audio_monitor[audio],
!!ucontrol->value.integer.value[0]);
vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1],
!!ucontrol->value.integer.value[1]);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -754,12 +734,11 @@ static int vx_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
{
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff;
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -781,14 +760,12 @@ static int vx_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
(ucontrol->value.iec958.status[1] << 8) |
(ucontrol->value.iec958.status[2] << 16) |
(ucontrol->value.iec958.status[3] << 24);
- mutex_lock(&chip->mixer_mutex);
+ guard(mutex)(&chip->mixer_mutex);
if (chip->uer_bits != val) {
chip->uer_bits = val;
vx_set_iec958_status(chip, val);
- mutex_unlock(&chip->mixer_mutex);
return 1;
}
- mutex_unlock(&chip->mixer_mutex);
return 0;
}
@@ -903,7 +880,7 @@ int snd_vx_mixer_new(struct vx_core *chip)
struct snd_card *card = chip->card;
char name[32];
- strcpy(card->mixername, card->driver);
+ strscpy(card->mixername, card->driver);
/* output level controls */
for (i = 0; i < chip->hw->num_outs; i++) {
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index ceaeb257003b..7fd8f413d6cf 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -190,8 +190,10 @@ static int vx_set_ibl(struct vx_core *chip, struct vx_ibl_info *info)
info->max_size = rmh.Stat[1];
info->min_size = rmh.Stat[2];
info->granularity = rmh.Stat[3];
- snd_printdd(KERN_DEBUG "vx_set_ibl: size = %d, max = %d, min = %d, gran = %d\n",
- info->size, info->max_size, info->min_size, info->granularity);
+ dev_dbg(chip->card->dev,
+ "%s: size = %d, max = %d, min = %d, gran = %d\n",
+ __func__, info->size, info->max_size, info->min_size,
+ info->granularity);
return 0;
}
@@ -616,24 +618,23 @@ static int vx_pcm_playback_transfer_chunk(struct vx_core *chip,
if (space < 0) {
/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
- snd_printd("error hbuffer\n");
+ dev_dbg(chip->card->dev, "error hbuffer\n");
return space;
}
if (space < size) {
vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
- snd_printd("no enough hbuffer space %d\n", space);
+ dev_dbg(chip->card->dev, "no enough hbuffer space %d\n", space);
return -EIO; /* XRUN */
}
/* we don't need irqsave here, because this function
* is called from either trigger callback or irq handler
*/
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
vx_pseudo_dma_write(chip, runtime, pipe, size);
err = vx_notify_end_of_buffer(chip, pipe);
/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
- mutex_unlock(&chip->lock);
return err;
}
@@ -795,7 +796,8 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs)
/* IEC958 status (raw-mode) was changed */
/* we reopen the pipe */
struct vx_rmh rmh;
- snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode);
+ dev_dbg(chip->card->dev,
+ "reopen the pipe with data_mode = %d\n", data_mode);
vx_init_rmh(&rmh, CMD_FREE_PIPE);
vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0);
err = vx_send_msg(chip, &rmh);
@@ -812,8 +814,9 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs)
}
if (chip->pcm_running && chip->freq != runtime->rate) {
- snd_printk(KERN_ERR "vx: cannot set different clock %d "
- "from the current %d\n", runtime->rate, chip->freq);
+ dev_err(chip->card->dev,
+ "vx: cannot set different clock %d from the current %d\n",
+ runtime->rate, chip->freq);
return -EINVAL;
}
vx_set_clock(chip, runtime->rate);
@@ -1091,7 +1094,7 @@ void vx_pcm_update_intr(struct vx_core *chip, unsigned int events)
chip->irq_rmh.Cmd[0] |= 0x00000002; /* SEL_END_OF_BUF_EVENTS */
if (vx_send_msg(chip, &chip->irq_rmh) < 0) {
- snd_printdd(KERN_ERR "msg send error!!\n");
+ dev_dbg(chip->card->dev, "msg send error!!\n");
return;
}
@@ -1141,7 +1144,8 @@ static int vx_init_audio_io(struct vx_core *chip)
vx_init_rmh(&rmh, CMD_SUPPORTED);
if (vx_send_msg(chip, &rmh) < 0) {
- snd_printk(KERN_ERR "vx: cannot get the supported audio data\n");
+ dev_err(chip->card->dev,
+ "vx: cannot get the supported audio data\n");
return -ENXIO;
}
@@ -1221,7 +1225,7 @@ int snd_vx_pcm_new(struct vx_core *chip)
pcm->private_free = snd_vx_pcm_free;
pcm->info_flags = 0;
pcm->nonatomic = true;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm[i] = pcm;
}
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index 884c40be19dc..1d90db3b0abd 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -49,7 +49,7 @@ static int vx_read_one_cbit(struct vx_core *chip, int index)
{
int val;
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
if (chip->type >= VX_TYPE_VXPOCKET) {
vx_outb(chip, CSUER, 1); /* read */
vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
@@ -59,7 +59,6 @@ static int vx_read_one_cbit(struct vx_core *chip, int index)
vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
val = (vx_inl(chip, RUER) >> 7) & 0x01;
}
- mutex_unlock(&chip->lock);
return val;
}
@@ -71,7 +70,7 @@ static int vx_read_one_cbit(struct vx_core *chip, int index)
static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
{
val = !!val; /* 0 or 1 */
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
if (vx_is_pcmcia(chip)) {
vx_outb(chip, CSUER, 0); /* write */
vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
@@ -79,7 +78,6 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
vx_outl(chip, CSUER, 0); /* write */
vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
}
- mutex_unlock(&chip->lock);
}
/*
@@ -178,10 +176,10 @@ static void vx_change_clock_source(struct vx_core *chip, int source)
{
/* we mute DAC to prevent clicks */
vx_toggle_dac_mute(chip, 1);
- mutex_lock(&chip->lock);
- chip->ops->set_clock_source(chip, source);
- chip->clock_source = source;
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock) {
+ chip->ops->set_clock_source(chip, source);
+ chip->clock_source = source;
+ }
/* unmute */
vx_toggle_dac_mute(chip, 0);
}
@@ -196,8 +194,9 @@ void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
/* Get real clock value */
clock = vx_calc_clock_from_freq(chip, freq);
- snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq);
- mutex_lock(&chip->lock);
+ dev_dbg(chip->card->dev,
+ "set internal clock to 0x%x from freq %d\n", clock, freq);
+ guard(mutex)(&chip->lock);
if (vx_is_pcmcia(chip)) {
vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f);
vx_outb(chip, LOFREQ, clock & 0xff);
@@ -205,7 +204,6 @@ void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f);
vx_outl(chip, LOFREQ, clock & 0xff);
}
- mutex_unlock(&chip->lock);
}
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index 22b6c779682a..5973c25c2add 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -175,6 +175,8 @@ config SND_FIREWIRE_MOTU
* 8pre
* 828mk3 (FireWire only)
* 828mk3 (Hybrid)
+ * 896mk3 (FireWire only)
+ * 896mk3 (Hybrid)
* Ultralite mk3 (FireWire only)
* Ultralite mk3 (Hybrid)
* Traveler mk3
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index 44a7b510b75b..45018a5c224f 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -2,9 +2,9 @@
# To find a header included by define_trace.h.
CFLAGS_amdtp-stream.o := -I$(src)
-snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
+snd-firewire-lib-y := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp-stream.o amdtp-am824.o
-snd-isight-objs := isight.o
+snd-isight-y := isight.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
obj-$(CONFIG_SND_DICE) += dice/
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index a13c0b408aad..5cdc34877fc1 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -77,6 +77,8 @@
// overrun. Actual device can skip more, then this module stops the packet streaming.
#define IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES 5
+static void pcm_period_work(struct work_struct *work);
+
/**
* amdtp_stream_init - initialize an AMDTP stream structure
* @s: the AMDTP stream to initialize
@@ -105,6 +107,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
s->flags = flags;
s->context = ERR_PTR(-1);
mutex_init(&s->mutex);
+ INIT_WORK(&s->period_work, pcm_period_work);
s->packet_index = 0;
init_waitqueue_head(&s->ready_wait);
@@ -169,6 +172,9 @@ static int apply_constraint_to_size(struct snd_pcm_hw_params *params,
step = max(step, amdtp_syt_intervals[i]);
}
+ if (step == 0)
+ return -EINVAL;
+
t.min = roundup(s->min, step);
t.max = rounddown(s->max, step);
t.integer = 1;
@@ -347,6 +353,7 @@ EXPORT_SYMBOL(amdtp_stream_get_max_payload);
*/
void amdtp_stream_pcm_prepare(struct amdtp_stream *s)
{
+ cancel_work_sync(&s->period_work);
s->pcm_buffer_pointer = 0;
s->pcm_period_pointer = 0;
}
@@ -611,19 +618,37 @@ static void update_pcm_pointers(struct amdtp_stream *s,
// The program in user process should periodically check the status of intermediate
// buffer associated to PCM substream to process PCM frames in the buffer, instead
// of receiving notification of period elapsed by poll wait.
- if (!pcm->runtime->no_period_wakeup) {
- if (in_softirq()) {
- // In software IRQ context for 1394 OHCI.
- snd_pcm_period_elapsed(pcm);
- } else {
- // In process context of ALSA PCM application under acquired lock of
- // PCM substream.
- snd_pcm_period_elapsed_under_stream_lock(pcm);
- }
- }
+ //
+ // Use another work item for period elapsed event to prevent the following AB/BA
+ // deadlock:
+ //
+ // thread 1 thread 2
+ // ================================= =================================
+ // A.work item (process) pcm ioctl (process)
+ // v v
+ // process_rx_packets() B.PCM stream lock
+ // process_tx_packets() v
+ // v callbacks in snd_pcm_ops
+ // update_pcm_pointers() v
+ // snd_pcm_elapsed() fw_iso_context_flush_completions()
+ // snd_pcm_stream_lock_irqsave() disable_work_sync()
+ // v v
+ // wait until release of B wait until A exits
+ if (!pcm->runtime->no_period_wakeup)
+ queue_work(system_highpri_wq, &s->period_work);
}
}
+static void pcm_period_work(struct work_struct *work)
+{
+ struct amdtp_stream *s = container_of(work, struct amdtp_stream,
+ period_work);
+ struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
+
+ if (pcm)
+ snd_pcm_period_elapsed(pcm);
+}
+
static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params,
bool sched_irq)
{
@@ -773,10 +798,14 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf,
} else {
unsigned int dbc_interval;
- if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
- dbc_interval = s->ctx_data.tx.dbc_interval;
- else
- dbc_interval = *data_blocks;
+ if (!(s->flags & CIP_DBC_IS_PAYLOAD_QUADLETS)) {
+ if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0)
+ dbc_interval = s->ctx_data.tx.dbc_interval;
+ else
+ dbc_interval = *data_blocks;
+ } else {
+ dbc_interval = payload_length / sizeof(__be32);
+ }
lost = dbc != ((*data_block_counter + dbc_interval) & 0xff);
}
@@ -951,7 +980,7 @@ static int generate_tx_packet_descs(struct amdtp_stream *s, struct pkt_desc *des
// to the reason.
unsigned int safe_cycle = increment_ohci_cycle_count(next_cycle,
IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES);
- lost = (compare_ohci_cycle_count(safe_cycle, cycle) > 0);
+ lost = (compare_ohci_cycle_count(safe_cycle, cycle) < 0);
}
if (lost) {
dev_err(&s->unit->device, "Detect discontinuity of cycle: %d %d\n",
@@ -1045,8 +1074,15 @@ static void generate_rx_packet_descs(struct amdtp_stream *s, struct pkt_desc *de
static inline void cancel_stream(struct amdtp_stream *s)
{
+ struct work_struct *work = current_work();
+
s->packet_index = -1;
- if (in_softirq())
+
+ // Detect work items for any isochronous context. The work item for pcm_period_work()
+ // should be avoided since the call of snd_pcm_period_elapsed() can reach via
+ // snd_pcm_ops.pointer() under acquiring PCM stream(group) lock and causes dead lock at
+ // snd_pcm_stop_xrun().
+ if (work && work != &s->period_work)
amdtp_stream_pcm_abort(s);
WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
}
@@ -1176,13 +1212,10 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
(void)fw_card_read_cycle_time(fw_parent_device(s->unit)->card, &curr_cycle_time);
for (i = 0; i < packets; ++i) {
- struct {
- struct fw_iso_packet params;
- __be32 header[CIP_HEADER_QUADLETS];
- } template = { {0}, {0} };
+ DEFINE_RAW_FLEX(struct fw_iso_packet, template, header, CIP_HEADER_QUADLETS);
bool sched_irq = false;
- build_it_pkt_header(s, desc->cycle, &template.params, pkt_header_length,
+ build_it_pkt_header(s, desc->cycle, template, pkt_header_length,
desc->data_blocks, desc->data_block_counter,
desc->syt, i, curr_cycle_time);
@@ -1194,7 +1227,7 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
}
}
- if (queue_out_packet(s, &template.params, sched_irq) < 0) {
+ if (queue_out_packet(s, template, sched_irq) < 0) {
cancel_stream(s);
return;
}
@@ -1655,20 +1688,16 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
struct pkt_desc *descs;
int i, type, tag, err;
- mutex_lock(&s->mutex);
+ guard(mutex)(&s->mutex);
if (WARN_ON(amdtp_stream_running(s) ||
- (s->data_block_quadlets < 1))) {
- err = -EBADFD;
- goto err_unlock;
- }
+ (s->data_block_quadlets < 1)))
+ return -EBADFD;
if (s->direction == AMDTP_IN_STREAM) {
// NOTE: IT context should be used for constant IRQ.
- if (is_irq_target) {
- err = -EINVAL;
- goto err_unlock;
- }
+ if (is_irq_target)
+ return -EINVAL;
s->data_block_counter = UINT_MAX;
} else {
@@ -1692,7 +1721,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
err = iso_packets_buffer_init(&s->buffer, s->unit, queue_size, max_ctx_payload_size, dir);
if (err < 0)
- goto err_unlock;
+ return err;
s->queue_size = queue_size;
s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
@@ -1813,8 +1842,6 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
if (err < 0)
goto err_pkt_descs;
- mutex_unlock(&s->mutex);
-
return 0;
err_pkt_descs:
kfree(s->packet_descs);
@@ -1830,8 +1857,6 @@ err_context:
s->context = ERR_PTR(-1);
err_buffer:
iso_packets_buffer_destroy(&s->buffer, s->unit);
-err_unlock:
- mutex_unlock(&s->mutex);
return err;
}
@@ -1848,11 +1873,11 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
{
struct amdtp_stream *irq_target = d->irq_target;
- // Process isochronous packets queued till recent isochronous cycle to handle PCM frames.
if (irq_target && amdtp_stream_running(irq_target)) {
- // In software IRQ context, the call causes dead-lock to disable the tasklet
- // synchronously.
- if (!in_softirq())
+ // The work item to call snd_pcm_period_elapsed() can reach here by the call of
+ // snd_pcm_ops.pointer(), however less packets would be available then. Therefore
+ // the following call is just for user process contexts.
+ if (current_work() != &s->period_work)
fw_iso_context_flush_completions(irq_target->context);
}
@@ -1901,13 +1926,12 @@ EXPORT_SYMBOL(amdtp_stream_update);
*/
static void amdtp_stream_stop(struct amdtp_stream *s)
{
- mutex_lock(&s->mutex);
+ guard(mutex)(&s->mutex);
- if (!amdtp_stream_running(s)) {
- mutex_unlock(&s->mutex);
+ if (!amdtp_stream_running(s))
return;
- }
+ cancel_work_sync(&s->period_work);
fw_iso_context_stop(s->context);
fw_iso_context_destroy(s->context);
s->context = ERR_PTR(-1);
@@ -1921,8 +1945,6 @@ static void amdtp_stream_stop(struct amdtp_stream *s)
if (s->domain->replay.enable)
kfree(s->ctx_data.tx.cache.descs);
}
-
- mutex_unlock(&s->mutex);
}
/**
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index b7ff44751ab9..ec10270c2cce 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -32,11 +32,14 @@
* allows 5 times as large as IEC 61883-6 defines.
* @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include
* valid EOH.
- * @CIP_NO_HEADERS: a lack of headers in packets
+ * @CIP_NO_HEADER: a lack of headers in packets
* @CIP_UNALIGHED_DBC: Only for in-stream. The value of dbc is not alighed to
* the value of current SYT_INTERVAL; e.g. initial value is not zero.
* @CIP_UNAWARE_SYT: For outgoing packet, the value in SYT field of CIP is 0xffff.
* For incoming packet, the value in SYT field of CIP is not handled.
+ * @CIP_DBC_IS_PAYLOAD_QUADLETS: Available for incoming packet, and only effective with
+ * CIP_DBC_IS_END_EVENT flag. The value of dbc field is the number of accumulated quadlets
+ * in CIP payload, instead of the number of accumulated data blocks.
*/
enum cip_flags {
CIP_NONBLOCKING = 0x00,
@@ -51,6 +54,7 @@ enum cip_flags {
CIP_NO_HEADER = 0x100,
CIP_UNALIGHED_DBC = 0x200,
CIP_UNAWARE_SYT = 0x400,
+ CIP_DBC_IS_PAYLOAD_QUADLETS = 0x800,
};
/**
@@ -187,6 +191,7 @@ struct amdtp_stream {
/* For a PCM substream processing. */
struct snd_pcm_substream *pcm;
+ struct work_struct period_work;
snd_pcm_uframes_t pcm_buffer_pointer;
unsigned int pcm_period_pointer;
unsigned int pcm_frame_multiplier;
diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile
index 14bc84c51ef5..b913e805bd7a 100644
--- a/sound/firewire/bebob/Makefile
+++ b/sound/firewire/bebob/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
+snd-bebob-y := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
bebob_pcm.o bebob_hwdep.o bebob_terratec.o \
bebob_yamaha_terratec.o bebob_focusrite.o bebob_maudio.o \
bebob.o
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index 06a7ced218e2..01e2c4cc03d4 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -15,7 +15,7 @@
MODULE_DESCRIPTION("BridgeCo BeBoB driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -105,9 +105,9 @@ name_device(struct snd_bebob *bebob)
if (err < 0)
goto end;
- strcpy(bebob->card->driver, "BeBoB");
- strcpy(bebob->card->shortname, model);
- strcpy(bebob->card->mixername, model);
+ strscpy(bebob->card->driver, "BeBoB");
+ strscpy(bebob->card->shortname, model);
+ strscpy(bebob->card->mixername, model);
snprintf(bebob->card->longname, sizeof(bebob->card->longname),
"%s %s (id:%d, rev:%d), GUID %08x%08x at %s, S%d",
vendor, model, hw_id, revision,
@@ -122,9 +122,9 @@ bebob_card_free(struct snd_card *card)
{
struct snd_bebob *bebob = card->private_data;
- mutex_lock(&devices_mutex);
- clear_bit(bebob->card_index, devices_used);
- mutex_unlock(&devices_mutex);
+ scoped_guard(mutex, &devices_mutex) {
+ clear_bit(bebob->card_index, devices_used);
+ }
snd_bebob_stream_destroy_duplex(bebob);
@@ -207,25 +207,21 @@ static int bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *en
return -ENODEV;
}
- mutex_lock(&devices_mutex);
- for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
- if (!test_bit(card_index, devices_used) && enable[card_index])
- break;
- }
- if (card_index >= SNDRV_CARDS) {
- mutex_unlock(&devices_mutex);
- return -ENOENT;
- }
+ scoped_guard(mutex, &devices_mutex) {
+ for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
+ if (!test_bit(card_index, devices_used) && enable[card_index])
+ break;
+ }
+ if (card_index >= SNDRV_CARDS)
+ return -ENOENT;
- err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
- sizeof(*bebob), &card);
- if (err < 0) {
- mutex_unlock(&devices_mutex);
- return err;
+ err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
+ sizeof(*bebob), &card);
+ if (err < 0)
+ return err;
+ card->private_free = bebob_card_free;
+ set_bit(card_index, devices_used);
}
- card->private_free = bebob_card_free;
- set_bit(card_index, devices_used);
- mutex_unlock(&devices_mutex);
bebob = card->private_data;
bebob->unit = fw_unit_get(unit);
diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c
index 6f9331655d43..216d1fceb6e7 100644
--- a/sound/firewire/bebob/bebob_hwdep.c
+++ b/sound/firewire/bebob/bebob_hwdep.c
@@ -53,18 +53,14 @@ static __poll_t
hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
{
struct snd_bebob *bebob = hwdep->private_data;
- __poll_t events;
poll_wait(file, &bebob->hwdep_wait, wait);
- spin_lock_irq(&bebob->lock);
+ guard(spinlock_irq)(&bebob->lock);
if (bebob->dev_lock_changed)
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&bebob->lock);
-
- return events;
+ return 0;
}
static int
@@ -90,39 +86,27 @@ hwdep_get_info(struct snd_bebob *bebob, void __user *arg)
static int
hwdep_lock(struct snd_bebob *bebob)
{
- int err;
-
- spin_lock_irq(&bebob->lock);
+ guard(spinlock_irq)(&bebob->lock);
if (bebob->dev_lock_count == 0) {
bebob->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&bebob->lock);
-
- return err;
}
static int
hwdep_unlock(struct snd_bebob *bebob)
{
- int err;
-
- spin_lock_irq(&bebob->lock);
+ guard(spinlock_irq)(&bebob->lock);
if (bebob->dev_lock_count == -1) {
bebob->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&bebob->lock);
-
- return err;
}
static int
@@ -130,10 +114,9 @@ hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_bebob *bebob = hwdep->private_data;
- spin_lock_irq(&bebob->lock);
+ guard(spinlock_irq)(&bebob->lock);
if (bebob->dev_lock_count == -1)
bebob->dev_lock_count = 0;
- spin_unlock_irq(&bebob->lock);
return 0;
}
@@ -183,7 +166,7 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
err = snd_hwdep_new(bebob->card, "BeBoB", 0, &hwdep);
if (err < 0)
goto end;
- strcpy(hwdep->name, "BeBoB");
+ strscpy(hwdep->name, "BeBoB");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB;
hwdep->ops = ops;
hwdep->private_data = bebob;
diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c
index 177699e1be11..376a9a175479 100644
--- a/sound/firewire/bebob/bebob_maudio.c
+++ b/sound/firewire/bebob/bebob_maudio.c
@@ -265,7 +265,7 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
if (!params)
return -ENOMEM;
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
bebob->maudio_special_quirk = (void *)params;
params->is1814 = is1814;
@@ -277,12 +277,12 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to initialize clock params: %d\n", err);
- goto end;
+ return err;
}
err = add_special_controls(bebob);
if (err < 0)
- goto end;
+ return err;
special_stream_formation_set(bebob);
@@ -293,8 +293,6 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
bebob->midi_input_ports = 2;
bebob->midi_output_ports = 2;
}
-end:
- mutex_unlock(&bebob->mutex);
return err;
}
@@ -383,14 +381,12 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl,
if (id >= ARRAY_SIZE(special_clk_types))
return -EINVAL;
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
err = avc_maudio_set_special_clk(bebob, id,
params->dig_in_fmt,
params->dig_out_fmt,
params->clk_lock);
- mutex_unlock(&bebob->mutex);
-
if (err >= 0)
err = 1;
@@ -456,14 +452,14 @@ static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl,
unsigned int dig_in_iface;
int err, val;
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
err = avc_audio_get_selector(bebob->unit, 0x00, 0x04,
&dig_in_iface);
if (err < 0) {
dev_err(&bebob->unit->device,
"fail to get digital input interface: %d\n", err);
- goto end;
+ return err;
}
/* encoded id for user value */
@@ -474,9 +470,7 @@ static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl,
val = 2;
uval->value.enumerated.item[0] = val;
-end:
- mutex_unlock(&bebob->mutex);
- return err;
+ return 0;
}
static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -494,7 +488,7 @@ static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl,
dig_in_fmt = (id >> 1) & 0x01;
dig_in_iface = id & 0x01;
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
err = avc_maudio_set_special_clk(bebob,
params->clk_src,
@@ -502,24 +496,19 @@ static int special_dig_in_iface_ctl_set(struct snd_kcontrol *kctl,
params->dig_out_fmt,
params->clk_lock);
if (err < 0)
- goto end;
+ return err;
/* For ADAT, optical interface is only available. */
- if (params->dig_in_fmt > 0) {
- err = 1;
- goto end;
- }
+ if (params->dig_in_fmt > 0)
+ return 1;
/* For S/PDIF, optical/coaxial interfaces are selectable. */
err = avc_audio_set_selector(bebob->unit, 0x00, 0x04, dig_in_iface);
if (err < 0)
dev_err(&bebob->unit->device,
"fail to set digital input interface: %d\n", err);
- err = 1;
-end:
special_stream_formation_set(bebob);
- mutex_unlock(&bebob->mutex);
- return err;
+ return 1;
}
static const struct snd_kcontrol_new special_dig_in_iface_ctl = {
.name = "Digital Input Interface",
@@ -546,9 +535,9 @@ static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl,
{
struct snd_bebob *bebob = snd_kcontrol_chip(kctl);
struct special_params *params = bebob->maudio_special_quirk;
- mutex_lock(&bebob->mutex);
+
+ guard(mutex)(&bebob->mutex);
uval->value.enumerated.item[0] = params->dig_out_fmt;
- mutex_unlock(&bebob->mutex);
return 0;
}
static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl,
@@ -563,7 +552,7 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl,
if (id >= ARRAY_SIZE(special_dig_out_iface_labels))
return -EINVAL;
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
err = avc_maudio_set_special_clk(bebob,
params->clk_src,
@@ -574,7 +563,6 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl,
err = 1;
}
- mutex_unlock(&bebob->mutex);
return err;
}
static const struct snd_kcontrol_new special_dig_out_iface_ctl = {
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c
index 6f597d03e7c1..678631f31d3c 100644
--- a/sound/firewire/bebob/bebob_midi.c
+++ b/sound/firewire/bebob/bebob_midi.c
@@ -16,15 +16,15 @@ static int midi_open(struct snd_rawmidi_substream *substream)
if (err < 0)
return err;
- mutex_lock(&bebob->mutex);
- err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
- if (err >= 0) {
- ++bebob->substreams_counter;
- err = snd_bebob_stream_start_duplex(bebob);
- if (err < 0)
- --bebob->substreams_counter;
+ scoped_guard(mutex, &bebob->mutex) {
+ err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
+ if (err >= 0) {
+ ++bebob->substreams_counter;
+ err = snd_bebob_stream_start_duplex(bebob);
+ if (err < 0)
+ --bebob->substreams_counter;
+ }
}
- mutex_unlock(&bebob->mutex);
if (err < 0)
snd_bebob_stream_lock_release(bebob);
@@ -35,10 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
- mutex_lock(&bebob->mutex);
- bebob->substreams_counter--;
- snd_bebob_stream_stop_duplex(bebob);
- mutex_unlock(&bebob->mutex);
+ scoped_guard(mutex, &bebob->mutex) {
+ bebob->substreams_counter--;
+ snd_bebob_stream_stop_duplex(bebob);
+ }
snd_bebob_stream_lock_release(bebob);
return 0;
@@ -47,9 +47,8 @@ static int midi_close(struct snd_rawmidi_substream *substream)
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_bebob *bebob = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&bebob->lock, flags);
+ guard(spinlock_irqsave)(&bebob->lock);
if (up)
amdtp_am824_midi_trigger(&bebob->tx_stream,
@@ -57,16 +56,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&bebob->tx_stream,
substrm->number, NULL);
-
- spin_unlock_irqrestore(&bebob->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_bebob *bebob = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&bebob->lock, flags);
+ guard(spinlock_irqsave)(&bebob->lock);
if (up)
amdtp_am824_midi_trigger(&bebob->rx_stream,
@@ -74,8 +70,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&bebob->rx_stream,
substrm->number, NULL);
-
- spin_unlock_irqrestore(&bebob->lock, flags);
}
static void set_midi_substream_names(struct snd_bebob *bebob,
@@ -84,9 +78,9 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
struct snd_rawmidi_substream *subs;
list_for_each_entry(subs, &str->substreams, list) {
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d",
- bebob->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ bebob->card->shortname, subs->number + 1);
}
}
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index ce49eef0fcba..692d33bac2d2 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -149,49 +149,42 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
goto err_locked;
- mutex_lock(&bebob->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
- (bebob->substreams_counter > 0 && d->events_per_period > 0)) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
- unsigned int sampling_rate;
-
- err = spec->get(bebob, &sampling_rate);
- if (err < 0) {
- mutex_unlock(&bebob->mutex);
- dev_err(&bebob->unit->device,
- "fail to get sampling rate: %d\n", err);
- goto err_locked;
- }
-
- substream->runtime->hw.rate_min = sampling_rate;
- substream->runtime->hw.rate_max = sampling_rate;
-
- if (frames_per_period > 0) {
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
+ scoped_guard(mutex, &bebob->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
+ (bebob->substreams_counter > 0 && d->events_per_period > 0)) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+ unsigned int sampling_rate;
+
+ err = spec->get(bebob, &sampling_rate);
if (err < 0) {
- mutex_unlock(&bebob->mutex);
+ dev_err(&bebob->unit->device,
+ "fail to get sampling rate: %d\n", err);
goto err_locked;
}
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&bebob->mutex);
- goto err_locked;
+ substream->runtime->hw.rate_min = sampling_rate;
+ substream->runtime->hw.rate_max = sampling_rate;
+
+ if (frames_per_period > 0) {
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
}
}
}
- mutex_unlock(&bebob->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -219,12 +212,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
err = snd_bebob_stream_reserve_duplex(bebob, rate,
frames_per_period, frames_per_buffer);
if (err >= 0)
++bebob->substreams_counter;
- mutex_unlock(&bebob->mutex);
}
return err;
@@ -234,15 +226,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
- mutex_lock(&bebob->mutex);
+ guard(mutex)(&bebob->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
bebob->substreams_counter--;
snd_bebob_stream_stop_duplex(bebob);
- mutex_unlock(&bebob->mutex);
-
return 0;
}
@@ -367,6 +357,7 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
goto end;
pcm->private_data = bebob;
+ pcm->nonatomic = true;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", bebob->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index 8629b14ded76..449cb17717f0 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -964,33 +964,24 @@ void snd_bebob_stream_lock_changed(struct snd_bebob *bebob)
int snd_bebob_stream_lock_try(struct snd_bebob *bebob)
{
- int err;
-
- spin_lock_irq(&bebob->lock);
+ guard(spinlock_irq)(&bebob->lock);
/* user land lock this */
- if (bebob->dev_lock_count < 0) {
- err = -EBUSY;
- goto end;
- }
+ if (bebob->dev_lock_count < 0)
+ return -EBUSY;
/* this is the first time */
if (bebob->dev_lock_count++ == 0)
snd_bebob_stream_lock_changed(bebob);
- err = 0;
-end:
- spin_unlock_irq(&bebob->lock);
- return err;
+ return 0;
}
void snd_bebob_stream_lock_release(struct snd_bebob *bebob)
{
- spin_lock_irq(&bebob->lock);
+ guard(spinlock_irq)(&bebob->lock);
if (WARN_ON(bebob->dev_lock_count <= 0))
- goto end;
+ return;
if (--bebob->dev_lock_count == 0)
snd_bebob_stream_lock_changed(bebob);
-end:
- spin_unlock_irq(&bebob->lock);
}
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index b596bec19774..b2b76c7c71b3 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -188,32 +188,23 @@ EXPORT_SYMBOL(cmp_connection_destroy);
int cmp_connection_reserve(struct cmp_connection *c,
unsigned int max_payload_bytes)
{
- int err;
-
- mutex_lock(&c->mutex);
+ guard(mutex)(&c->mutex);
- if (WARN_ON(c->resources.allocated)) {
- err = -EBUSY;
- goto end;
- }
+ if (WARN_ON(c->resources.allocated))
+ return -EBUSY;
c->speed = min(c->max_speed,
fw_parent_device(c->resources.unit)->max_speed);
- err = fw_iso_resources_allocate(&c->resources, max_payload_bytes,
- c->speed);
-end:
- mutex_unlock(&c->mutex);
-
- return err;
+ return fw_iso_resources_allocate(&c->resources, max_payload_bytes,
+ c->speed);
}
EXPORT_SYMBOL(cmp_connection_reserve);
void cmp_connection_release(struct cmp_connection *c)
{
- mutex_lock(&c->mutex);
+ guard(mutex)(&c->mutex);
fw_iso_resources_free(&c->resources);
- mutex_unlock(&c->mutex);
}
EXPORT_SYMBOL(cmp_connection_release);
@@ -304,12 +295,10 @@ int cmp_connection_establish(struct cmp_connection *c)
{
int err;
- mutex_lock(&c->mutex);
+ guard(mutex)(&c->mutex);
- if (WARN_ON(c->connected)) {
- mutex_unlock(&c->mutex);
+ if (WARN_ON(c->connected))
return -EISCONN;
- }
retry_after_bus_reset:
if (c->direction == CMP_OUTPUT)
@@ -327,59 +316,10 @@ retry_after_bus_reset:
if (err >= 0)
c->connected = true;
- mutex_unlock(&c->mutex);
-
return err;
}
EXPORT_SYMBOL(cmp_connection_establish);
-/**
- * cmp_connection_update - update the connection after a bus reset
- * @c: the connection manager
- *
- * This function must be called from the driver's .update handler to
- * reestablish any connection that might have been active.
- *
- * Returns zero on success, or a negative error code. On an error, the
- * connection is broken and the caller must stop transmitting iso packets.
- */
-int cmp_connection_update(struct cmp_connection *c)
-{
- int err;
-
- mutex_lock(&c->mutex);
-
- if (!c->connected) {
- mutex_unlock(&c->mutex);
- return 0;
- }
-
- err = fw_iso_resources_update(&c->resources);
- if (err < 0)
- goto err_unconnect;
-
- if (c->direction == CMP_OUTPUT)
- err = pcr_modify(c, opcr_set_modify, pcr_set_check,
- SUCCEED_ON_BUS_RESET);
- else
- err = pcr_modify(c, ipcr_set_modify, pcr_set_check,
- SUCCEED_ON_BUS_RESET);
-
- if (err < 0)
- goto err_unconnect;
-
- mutex_unlock(&c->mutex);
-
- return 0;
-
-err_unconnect:
- c->connected = false;
- mutex_unlock(&c->mutex);
-
- return err;
-}
-EXPORT_SYMBOL(cmp_connection_update);
-
static __be32 pcr_break_modify(struct cmp_connection *c, __be32 pcr)
{
return pcr & ~cpu_to_be32(PCR_BCAST_CONN | PCR_P2P_CONN_MASK);
@@ -397,19 +337,15 @@ void cmp_connection_break(struct cmp_connection *c)
{
int err;
- mutex_lock(&c->mutex);
+ guard(mutex)(&c->mutex);
- if (!c->connected) {
- mutex_unlock(&c->mutex);
+ if (!c->connected)
return;
- }
err = pcr_modify(c, pcr_break_modify, NULL, SUCCEED_ON_BUS_RESET);
if (err < 0)
cmp_error(c, "plug is still connected\n");
c->connected = false;
-
- mutex_unlock(&c->mutex);
}
EXPORT_SYMBOL(cmp_connection_break);
diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h
index 26ab88000e34..66fc08b742d2 100644
--- a/sound/firewire/cmp.h
+++ b/sound/firewire/cmp.h
@@ -47,7 +47,6 @@ int cmp_connection_reserve(struct cmp_connection *connection,
void cmp_connection_release(struct cmp_connection *connection);
int cmp_connection_establish(struct cmp_connection *connection);
-int cmp_connection_update(struct cmp_connection *connection);
void cmp_connection_break(struct cmp_connection *connection);
#endif
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile
index a5f3fbf28b8c..478cd7a08fb5 100644
--- a/sound/firewire/dice/Makefile
+++ b/sound/firewire/dice/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
+snd-dice-y := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o \
- dice-harman.o dice-focusrite.o
+ dice-harman.o dice-focusrite.o dice-weiss.o dice-teac.o
obj-$(CONFIG_SND_DICE) += snd-dice.o
diff --git a/sound/firewire/dice/dice-extension.c b/sound/firewire/dice/dice-extension.c
index 02f4a8318e38..48bfb3ad93ce 100644
--- a/sound/firewire/dice/dice-extension.c
+++ b/sound/firewire/dice/dice-extension.c
@@ -116,7 +116,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
break;
base_offset += EXT_APP_STREAM_ENTRIES;
- stream_count = be32_to_cpu(reg[0]);
+ stream_count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
err = read_stream_entries(dice, section_addr, base_offset,
stream_count, mode,
dice->tx_pcm_chs,
@@ -125,7 +125,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
break;
base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
- stream_count = be32_to_cpu(reg[1]);
+ stream_count = min_t(unsigned int, be32_to_cpu(reg[1]), MAX_STREAMS);
err = read_stream_entries(dice, section_addr, base_offset,
stream_count,
mode, dice->rx_pcm_chs,
diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c
index ffc0b97782d6..747ff0952483 100644
--- a/sound/firewire/dice/dice-hwdep.c
+++ b/sound/firewire/dice/dice-hwdep.c
@@ -55,18 +55,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_table *wait)
{
struct snd_dice *dice = hwdep->private_data;
- __poll_t events;
poll_wait(file, &dice->hwdep_wait, wait);
- spin_lock_irq(&dice->lock);
+ guard(spinlock_irq)(&dice->lock);
if (dice->dev_lock_changed || dice->notification_bits != 0)
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&dice->lock);
-
- return events;
+ return 0;
}
static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
@@ -90,48 +86,35 @@ static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
static int hwdep_lock(struct snd_dice *dice)
{
- int err;
-
- spin_lock_irq(&dice->lock);
+ guard(spinlock_irq)(&dice->lock);
if (dice->dev_lock_count == 0) {
dice->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&dice->lock);
-
- return err;
}
static int hwdep_unlock(struct snd_dice *dice)
{
- int err;
-
- spin_lock_irq(&dice->lock);
+ guard(spinlock_irq)(&dice->lock);
if (dice->dev_lock_count == -1) {
dice->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&dice->lock);
-
- return err;
}
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_dice *dice = hwdep->private_data;
- spin_lock_irq(&dice->lock);
+ guard(spinlock_irq)(&dice->lock);
if (dice->dev_lock_count == -1)
dice->dev_lock_count = 0;
- spin_unlock_irq(&dice->lock);
return 0;
}
@@ -179,7 +162,7 @@ int snd_dice_create_hwdep(struct snd_dice *dice)
err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
if (err < 0)
return err;
- strcpy(hwdep->name, "DICE");
+ strscpy(hwdep->name, "DICE");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
hwdep->ops = ops;
hwdep->private_data = dice;
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
index 4c2998034313..722bce379345 100644
--- a/sound/firewire/dice/dice-midi.c
+++ b/sound/firewire/dice/dice-midi.c
@@ -15,18 +15,16 @@ static int midi_open(struct snd_rawmidi_substream *substream)
if (err < 0)
return err;
- mutex_lock(&dice->mutex);
-
- err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0);
- if (err >= 0) {
- ++dice->substreams_counter;
- err = snd_dice_stream_start_duplex(dice);
- if (err < 0)
- --dice->substreams_counter;
+ scoped_guard(mutex, &dice->mutex) {
+ err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0);
+ if (err >= 0) {
+ ++dice->substreams_counter;
+ err = snd_dice_stream_start_duplex(dice);
+ if (err < 0)
+ --dice->substreams_counter;
+ }
}
- mutex_unlock(&dice->mutex);
-
if (err < 0)
snd_dice_stream_lock_release(dice);
@@ -37,12 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_dice *dice = substream->rmidi->private_data;
- mutex_lock(&dice->mutex);
-
- --dice->substreams_counter;
- snd_dice_stream_stop_duplex(dice);
-
- mutex_unlock(&dice->mutex);
+ scoped_guard(mutex, &dice->mutex) {
+ --dice->substreams_counter;
+ snd_dice_stream_stop_duplex(dice);
+ }
snd_dice_stream_lock_release(dice);
return 0;
@@ -51,9 +47,8 @@ static int midi_close(struct snd_rawmidi_substream *substream)
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_dice *dice = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&dice->lock, flags);
+ guard(spinlock_irqsave)(&dice->lock);
if (up)
amdtp_am824_midi_trigger(&dice->tx_stream[0],
@@ -61,16 +56,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&dice->tx_stream[0],
substrm->number, NULL);
-
- spin_unlock_irqrestore(&dice->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_dice *dice = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&dice->lock, flags);
+ guard(spinlock_irqsave)(&dice->lock);
if (up)
amdtp_am824_midi_trigger(&dice->rx_stream[0],
@@ -78,8 +70,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&dice->rx_stream[0],
substrm->number, NULL);
-
- spin_unlock_irqrestore(&dice->lock, flags);
}
static void set_midi_substream_names(struct snd_dice *dice,
@@ -88,8 +78,8 @@ static void set_midi_substream_names(struct snd_dice *dice,
struct snd_rawmidi_substream *subs;
list_for_each_entry(subs, &str->substreams, list) {
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d", dice->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d", dice->card->shortname, subs->number + 1);
}
}
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index d64366217d57..d5319cd2cc6f 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -196,53 +196,45 @@ static int pcm_open(struct snd_pcm_substream *substream)
break;
}
- mutex_lock(&dice->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if (!internal ||
- (dice->substreams_counter > 0 && d->events_per_period > 0)) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
- unsigned int rate;
-
- err = snd_dice_transaction_get_rate(dice, &rate);
- if (err < 0) {
- mutex_unlock(&dice->mutex);
- goto err_locked;
- }
-
- substream->runtime->hw.rate_min = rate;
- substream->runtime->hw.rate_max = rate;
-
- if (frames_per_period > 0) {
- // For double_pcm_frame quirk.
- if (rate > 96000 && !dice->disable_double_pcm_frames) {
- frames_per_period *= 2;
- frames_per_buffer *= 2;
- }
-
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
- if (err < 0) {
- mutex_unlock(&dice->mutex);
+ scoped_guard(mutex, &dice->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if (!internal ||
+ (dice->substreams_counter > 0 && d->events_per_period > 0)) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+ unsigned int rate;
+
+ err = snd_dice_transaction_get_rate(dice, &rate);
+ if (err < 0)
goto err_locked;
- }
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&dice->mutex);
- goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+
+ if (frames_per_period > 0) {
+ // For double_pcm_frame quirk.
+ if (rate > 96000 && !dice->disable_double_pcm_frames) {
+ frames_per_period *= 2;
+ frames_per_buffer *= 2;
+ }
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
}
}
}
- mutex_unlock(&dice->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -271,7 +263,7 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int events_per_period = params_period_size(hw_params);
unsigned int events_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&dice->mutex);
+ guard(mutex)(&dice->mutex);
// For double_pcm_frame quirk.
if (rate > 96000 && !dice->disable_double_pcm_frames) {
events_per_period /= 2;
@@ -281,7 +273,6 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
events_per_period, events_per_buffer);
if (err >= 0)
++dice->substreams_counter;
- mutex_unlock(&dice->mutex);
}
return err;
@@ -291,15 +282,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
- mutex_lock(&dice->mutex);
+ guard(mutex)(&dice->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--dice->substreams_counter;
snd_dice_stream_stop_duplex(dice);
- mutex_unlock(&dice->mutex);
-
return 0;
}
@@ -309,9 +298,9 @@ static int capture_prepare(struct snd_pcm_substream *substream)
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
int err;
- mutex_lock(&dice->mutex);
- err = snd_dice_stream_start_duplex(dice);
- mutex_unlock(&dice->mutex);
+ scoped_guard(mutex, &dice->mutex) {
+ err = snd_dice_stream_start_duplex(dice);
+ }
if (err >= 0)
amdtp_stream_pcm_prepare(stream);
@@ -323,9 +312,9 @@ static int playback_prepare(struct snd_pcm_substream *substream)
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
int err;
- mutex_lock(&dice->mutex);
- err = snd_dice_stream_start_duplex(dice);
- mutex_unlock(&dice->mutex);
+ scoped_guard(mutex, &dice->mutex) {
+ err = snd_dice_stream_start_duplex(dice);
+ }
if (err >= 0)
amdtp_stream_pcm_prepare(stream);
@@ -441,7 +430,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
if (err < 0)
return err;
pcm->private_data = dice;
- strcpy(pcm->name, dice->card->shortname);
+ pcm->nonatomic = true;
+ strscpy(pcm->name, dice->card->shortname);
if (capture > 0)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index 4c677c8546c7..d5ffe7c82993 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -677,32 +677,23 @@ static void dice_lock_changed(struct snd_dice *dice)
int snd_dice_stream_lock_try(struct snd_dice *dice)
{
- int err;
-
- spin_lock_irq(&dice->lock);
+ guard(spinlock_irq)(&dice->lock);
- if (dice->dev_lock_count < 0) {
- err = -EBUSY;
- goto out;
- }
+ if (dice->dev_lock_count < 0)
+ return -EBUSY;
if (dice->dev_lock_count++ == 0)
dice_lock_changed(dice);
- err = 0;
-out:
- spin_unlock_irq(&dice->lock);
- return err;
+ return 0;
}
void snd_dice_stream_lock_release(struct snd_dice *dice)
{
- spin_lock_irq(&dice->lock);
+ guard(spinlock_irq)(&dice->lock);
if (WARN_ON(dice->dev_lock_count <= 0))
- goto out;
+ return;
if (--dice->dev_lock_count == 0)
dice_lock_changed(dice);
-out:
- spin_unlock_irq(&dice->lock);
}
diff --git a/sound/firewire/dice/dice-teac.c b/sound/firewire/dice/dice-teac.c
new file mode 100644
index 000000000000..29febddfe3a5
--- /dev/null
+++ b/sound/firewire/dice/dice-teac.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+// dice-teac.c - a part of driver for DICE based devices
+//
+// Copyright (c) 2025 Takashi Sakamoto
+
+#include "dice.h"
+
+int snd_dice_detect_teac_formats(struct snd_dice *dice)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg, sizeof(reg));
+ if (err < 0)
+ return err;
+
+ dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_LOW] = 16;
+ dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_MIDDLE] = 16;
+ dice->tx_midi_ports[0] = 1;
+
+ data = be32_to_cpu(reg);
+ if (data > 1) {
+ dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_LOW] = 16;
+ dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_MIDDLE] = 16;
+ }
+
+ err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg, sizeof(reg));
+ if (err < 0)
+ return err;
+
+ dice->rx_pcm_chs[0][SND_DICE_RATE_MODE_LOW] = 16;
+ dice->rx_pcm_chs[0][SND_DICE_RATE_MODE_MIDDLE] = 16;
+ dice->rx_midi_ports[0] = 1;
+
+ data = be32_to_cpu(reg);
+ if (data > 1) {
+ dice->rx_pcm_chs[1][SND_DICE_RATE_MODE_LOW] = 16;
+ dice->rx_pcm_chs[1][SND_DICE_RATE_MODE_MIDDLE] = 16;
+ }
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c
index 92941ef83cd5..a3f7dfa990a4 100644
--- a/sound/firewire/dice/dice-transaction.c
+++ b/sound/firewire/dice/dice-transaction.c
@@ -136,7 +136,6 @@ static void dice_notification(struct fw_card *card, struct fw_request *request,
{
struct snd_dice *dice = callback_data;
u32 bits;
- unsigned long flags;
if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
fw_send_response(card, request, RCODE_TYPE_ERROR);
@@ -149,9 +148,9 @@ static void dice_notification(struct fw_card *card, struct fw_request *request,
bits = be32_to_cpup(data);
- spin_lock_irqsave(&dice->lock, flags);
- dice->notification_bits |= bits;
- spin_unlock_irqrestore(&dice->lock, flags);
+ scoped_guard(spinlock_irqsave, &dice->lock) {
+ dice->notification_bits |= bits;
+ }
fw_send_response(card, request, RCODE_COMPLETE);
diff --git a/sound/firewire/dice/dice-weiss.c b/sound/firewire/dice/dice-weiss.c
new file mode 100644
index 000000000000..129d43408956
--- /dev/null
+++ b/sound/firewire/dice/dice-weiss.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+// dice-weiss.c - a part of driver for DICE based devices
+//
+// Copyright (c) 2023 Rolf Anderegg and Michele Perrone
+
+#include "dice.h"
+
+struct dice_weiss_spec {
+ unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+ unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+};
+
+// Weiss DAC202: 192kHz 2-channel DAC
+static const struct dice_weiss_spec dac202 = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss MAN301: 192kHz 2-channel music archive network player
+static const struct dice_weiss_spec man301 = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss INT202: 192kHz unidirectional 2-channel digital Firewire nterface
+static const struct dice_weiss_spec int202 = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss INT203: 192kHz bidirectional 2-channel digital Firewire nterface
+static const struct dice_weiss_spec int203 = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss ADC2: 192kHz A/D converter with microphone preamps and line nputs
+static const struct dice_weiss_spec adc2 = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss DAC2/Minerva: 192kHz 2-channel DAC
+static const struct dice_weiss_spec dac2_minerva = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss Vesta: 192kHz 2-channel Firewire to AES/EBU interface
+static const struct dice_weiss_spec vesta = {
+ .tx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+ .rx_pcm_chs = {{2, 2, 2}, {0, 0, 0} },
+};
+
+// Weiss AFI1: 192kHz 24-channel Firewire to ADAT or AES/EBU interface
+static const struct dice_weiss_spec afi1 = {
+ .tx_pcm_chs = {{24, 16, 8}, {0, 0, 0} },
+ .rx_pcm_chs = {{24, 16, 8}, {0, 0, 0} },
+};
+
+int snd_dice_detect_weiss_formats(struct snd_dice *dice)
+{
+ static const struct {
+ u32 model_id;
+ const struct dice_weiss_spec *spec;
+ } *entry, entries[] = {
+ {0x000007, &dac202},
+ {0x000008, &dac202}, // Maya edition: same audio I/O as DAC202.
+ {0x000006, &int202},
+ {0x00000a, &int203},
+ {0x00000b, &man301},
+ {0x000001, &adc2},
+ {0x000003, &dac2_minerva},
+ {0x000002, &vesta},
+ {0x000004, &afi1},
+ };
+ struct fw_csr_iterator it;
+ int key, val, model_id;
+ int i;
+
+ model_id = 0;
+ fw_csr_iterator_init(&it, dice->unit->directory);
+ while (fw_csr_iterator_next(&it, &key, &val)) {
+ if (key == CSR_MODEL) {
+ model_id = val;
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i) {
+ entry = entries + i;
+ if (entry->model_id == model_id)
+ break;
+ }
+ if (i == ARRAY_SIZE(entries))
+ return -ENODEV;
+
+ memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs,
+ MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+ memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs,
+ MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 6036a5edbcb8..85d265c7d544 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -9,7 +9,7 @@
MODULE_DESCRIPTION("DICE driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
#define OUI_WEISS 0x001c6a
#define OUI_LOUD 0x000ff2
@@ -22,6 +22,7 @@ MODULE_LICENSE("GPL v2");
#define OUI_PRESONUS 0x000a92
#define OUI_HARMAN 0x000fd7
#define OUI_AVID 0x00a07e
+#define OUI_TEAC 0x00022e
#define DICE_CATEGORY_ID 0x04
#define WEISS_CATEGORY_ID 0x00
@@ -102,9 +103,9 @@ static void dice_card_strings(struct snd_dice *dice)
unsigned int i;
int err;
- strcpy(card->driver, "DICE");
+ strscpy(card->driver, "DICE");
- strcpy(card->shortname, "DICE");
+ strscpy(card->shortname, "DICE");
BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
card->shortname,
@@ -117,16 +118,16 @@ static void dice_card_strings(struct snd_dice *dice)
card->shortname[sizeof(card->shortname) - 1] = '\0';
}
- strcpy(vendor, "?");
+ strscpy(vendor, "?");
fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
- strcpy(model, "?");
+ strscpy(model, "?");
fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
snprintf(card->longname, sizeof(card->longname),
"%s %s (serial %u) at %s, S%d",
vendor, model, dev->config_rom[4] & 0x3fffff,
dev_name(&dice->unit->device), 100 << dev->max_speed);
- strcpy(card->mixername, "DICE");
+ strscpy(card->mixername, "DICE");
}
static void dice_card_free(struct snd_card *card)
@@ -238,9 +239,8 @@ static void dice_bus_reset(struct fw_unit *unit)
/* The handler address register becomes initialized. */
snd_dice_transaction_reinit(dice);
- mutex_lock(&dice->mutex);
+ guard(mutex)(&dice->mutex);
snd_dice_stream_update_duplex(dice);
- mutex_unlock(&dice->mutex);
}
#define DICE_INTERFACE 0x000001
@@ -392,10 +392,85 @@ static const struct ieee1394_device_id dice_id_table[] = {
.model_id = 0x0000de,
.driver_data = (kernel_ulong_t)snd_dice_detect_focusrite_pro40_tcd3070_formats,
},
+ // Weiss DAC202: 192kHz 2-channel DAC
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000007,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss DAC202: 192kHz 2-channel DAC (Maya edition)
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000008,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss MAN301: 192kHz 2-channel music archive network player
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x00000b,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss INT202: 192kHz unidirectional 2-channel digital Firewire face
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000006,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss INT203: 192kHz bidirectional 2-channel digital Firewire face
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x00000a,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss ADC2: 192kHz A/D converter with microphone preamps and inputs
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000001,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss DAC2/Minerva: 192kHz 2-channel DAC
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000003,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss Vesta: 192kHz 2-channel Firewire to AES/EBU interface
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000002,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
+ // Weiss AFI1: 192kHz 24-channel Firewire to ADAT or AES/EBU face
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = OUI_WEISS,
+ .model_id = 0x000004,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_weiss_formats,
+ },
{
.match_flags = IEEE1394_MATCH_VERSION,
.version = DICE_INTERFACE,
},
+ // Tascam IF-FW/DM MkII for DM-3200 and DM-4800.
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = OUI_TEAC,
+ .model_id = OUI_TEAC,
+ .specifier_id = OUI_TEAC,
+ .version = 0x800006,
+ .driver_data = (kernel_ulong_t)snd_dice_detect_teac_formats,
+ },
{ }
};
MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index 674f7d552c2e..7744ea6a0791 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -232,5 +232,7 @@ int snd_dice_detect_mytek_formats(struct snd_dice *dice);
int snd_dice_detect_presonus_formats(struct snd_dice *dice);
int snd_dice_detect_harman_formats(struct snd_dice *dice);
int snd_dice_detect_focusrite_pro40_tcd3070_formats(struct snd_dice *dice);
+int snd_dice_detect_weiss_formats(struct snd_dice *dice);
+int snd_dice_detect_teac_formats(struct snd_dice *dice);
#endif
diff --git a/sound/firewire/digi00x/Makefile b/sound/firewire/digi00x/Makefile
index 8add0cd9af3a..6dc18bd2e186 100644
--- a/sound/firewire/digi00x/Makefile
+++ b/sound/firewire/digi00x/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
+snd-firewire-digi00x-y := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
digi00x-pcm.o digi00x-hwdep.o \
digi00x-transaction.o digi00x-midi.o digi00x.o
obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
index aadf7d724856..435d18417cf0 100644
--- a/sound/firewire/digi00x/digi00x-hwdep.c
+++ b/sound/firewire/digi00x/digi00x-hwdep.c
@@ -63,18 +63,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_table *wait)
{
struct snd_dg00x *dg00x = hwdep->private_data;
- __poll_t events;
poll_wait(file, &dg00x->hwdep_wait, wait);
- spin_lock_irq(&dg00x->lock);
+ guard(spinlock_irq)(&dg00x->lock);
if (dg00x->dev_lock_changed || dg00x->msg)
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&dg00x->lock);
-
- return events;
+ return 0;
}
static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
@@ -98,48 +94,35 @@ static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
static int hwdep_lock(struct snd_dg00x *dg00x)
{
- int err;
-
- spin_lock_irq(&dg00x->lock);
+ guard(spinlock_irq)(&dg00x->lock);
if (dg00x->dev_lock_count == 0) {
dg00x->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&dg00x->lock);
-
- return err;
}
static int hwdep_unlock(struct snd_dg00x *dg00x)
{
- int err;
-
- spin_lock_irq(&dg00x->lock);
+ guard(spinlock_irq)(&dg00x->lock);
if (dg00x->dev_lock_count == -1) {
dg00x->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&dg00x->lock);
-
- return err;
}
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_dg00x *dg00x = hwdep->private_data;
- spin_lock_irq(&dg00x->lock);
+ guard(spinlock_irq)(&dg00x->lock);
if (dg00x->dev_lock_count == -1)
dg00x->dev_lock_count = 0;
- spin_unlock_irq(&dg00x->lock);
return 0;
}
@@ -188,7 +171,7 @@ int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
if (err < 0)
return err;
- strcpy(hwdep->name, "Digi00x");
+ strscpy(hwdep->name, "Digi00x");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
hwdep->ops = ops;
hwdep->private_data = dg00x;
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index 68eb8c39afa6..bcdaf003514b 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -16,15 +16,15 @@ static int midi_open(struct snd_rawmidi_substream *substream)
if (err < 0)
return err;
- mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
- if (err >= 0) {
- ++dg00x->substreams_counter;
- err = snd_dg00x_stream_start_duplex(dg00x);
- if (err < 0)
- --dg00x->substreams_counter;
+ scoped_guard(mutex, &dg00x->mutex) {
+ err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
+ if (err >= 0) {
+ ++dg00x->substreams_counter;
+ err = snd_dg00x_stream_start_duplex(dg00x);
+ if (err < 0)
+ --dg00x->substreams_counter;
+ }
}
- mutex_unlock(&dg00x->mutex);
if (err < 0)
snd_dg00x_stream_lock_release(dg00x);
@@ -35,10 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_dg00x *dg00x = substream->rmidi->private_data;
- mutex_lock(&dg00x->mutex);
- --dg00x->substreams_counter;
- snd_dg00x_stream_stop_duplex(dg00x);
- mutex_unlock(&dg00x->mutex);
+ scoped_guard(mutex, &dg00x->mutex) {
+ --dg00x->substreams_counter;
+ snd_dg00x_stream_stop_duplex(dg00x);
+ }
snd_dg00x_stream_lock_release(dg00x);
return 0;
@@ -49,21 +49,18 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
{
struct snd_dg00x *dg00x = substream->rmidi->private_data;
unsigned int port;
- unsigned long flags;
if (substream->rmidi->device == 0)
port = substream->number;
else
port = 2;
- spin_lock_irqsave(&dg00x->lock, flags);
+ guard(spinlock_irqsave)(&dg00x->lock);
if (up)
amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream);
else
amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL);
-
- spin_unlock_irqrestore(&dg00x->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
@@ -71,21 +68,18 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
{
struct snd_dg00x *dg00x = substream->rmidi->private_data;
unsigned int port;
- unsigned long flags;
if (substream->rmidi->device == 0)
port = substream->number;
else
port = 2;
- spin_lock_irqsave(&dg00x->lock, flags);
+ guard(spinlock_irqsave)(&dg00x->lock);
if (up)
amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream);
else
amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL);
-
- spin_unlock_irqrestore(&dg00x->lock, flags);
}
static void set_substream_names(struct snd_dg00x *dg00x,
@@ -100,14 +94,14 @@ static void set_substream_names(struct snd_dg00x *dg00x,
list_for_each_entry(subs, &str->substreams, list) {
if (!is_console) {
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d",
- dg00x->card->shortname,
- subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ dg00x->card->shortname,
+ subs->number + 1);
} else {
- snprintf(subs->name, sizeof(subs->name),
- "%s control",
- dg00x->card->shortname);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s control",
+ dg00x->card->shortname);
}
}
}
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index 3bd1575c9d9c..75f81545d50c 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -127,46 +127,38 @@ static int pcm_open(struct snd_pcm_substream *substream)
}
}
- mutex_lock(&dg00x->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
- (dg00x->substreams_counter > 0 && d->events_per_period > 0)) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
- unsigned int rate;
-
- err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
- if (err < 0) {
- mutex_unlock(&dg00x->mutex);
- goto err_locked;
- }
- substream->runtime->hw.rate_min = rate;
- substream->runtime->hw.rate_max = rate;
-
- if (frames_per_period > 0) {
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
- if (err < 0) {
- mutex_unlock(&dg00x->mutex);
- goto err_locked;
- }
-
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&dg00x->mutex);
+ scoped_guard(mutex, &dg00x->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
+ (dg00x->substreams_counter > 0 && d->events_per_period > 0)) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+ unsigned int rate;
+
+ err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
+ if (err < 0)
goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+
+ if (frames_per_period > 0) {
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
}
}
}
- mutex_unlock(&dg00x->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -195,12 +187,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&dg00x->mutex);
+ guard(mutex)(&dg00x->mutex);
err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
frames_per_period, frames_per_buffer);
if (err >= 0)
++dg00x->substreams_counter;
- mutex_unlock(&dg00x->mutex);
}
return err;
@@ -210,15 +201,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- mutex_lock(&dg00x->mutex);
+ guard(mutex)(&dg00x->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
- mutex_unlock(&dg00x->mutex);
-
return 0;
}
@@ -227,14 +216,12 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
struct snd_dg00x *dg00x = substream->private_data;
int err;
- mutex_lock(&dg00x->mutex);
+ guard(mutex)(&dg00x->mutex);
err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0)
amdtp_stream_pcm_prepare(&dg00x->tx_stream);
- mutex_unlock(&dg00x->mutex);
-
return err;
}
@@ -243,7 +230,7 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream)
struct snd_dg00x *dg00x = substream->private_data;
int err;
- mutex_lock(&dg00x->mutex);
+ guard(mutex)(&dg00x->mutex);
err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0) {
@@ -251,8 +238,6 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream)
amdtp_dot_reset(&dg00x->rx_stream);
}
- mutex_unlock(&dg00x->mutex);
-
return err;
}
@@ -350,6 +335,7 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
return err;
pcm->private_data = dg00x;
+ pcm->nonatomic = true;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", dg00x->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
index 295163bb8abb..250ffdb26ebd 100644
--- a/sound/firewire/digi00x/digi00x-stream.c
+++ b/sound/firewire/digi00x/digi00x-stream.c
@@ -427,33 +427,24 @@ void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
{
- int err;
-
- spin_lock_irq(&dg00x->lock);
+ guard(spinlock_irq)(&dg00x->lock);
/* user land lock this */
- if (dg00x->dev_lock_count < 0) {
- err = -EBUSY;
- goto end;
- }
+ if (dg00x->dev_lock_count < 0)
+ return -EBUSY;
/* this is the first time */
if (dg00x->dev_lock_count++ == 0)
snd_dg00x_stream_lock_changed(dg00x);
- err = 0;
-end:
- spin_unlock_irq(&dg00x->lock);
- return err;
+ return 0;
}
void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
{
- spin_lock_irq(&dg00x->lock);
+ guard(spinlock_irq)(&dg00x->lock);
if (WARN_ON(dg00x->dev_lock_count <= 0))
- goto end;
+ return;
if (--dg00x->dev_lock_count == 0)
snd_dg00x_stream_lock_changed(dg00x);
-end:
- spin_unlock_irq(&dg00x->lock);
}
diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c
index cf0bcf1c5956..8a1667159930 100644
--- a/sound/firewire/digi00x/digi00x-transaction.c
+++ b/sound/firewire/digi00x/digi00x-transaction.c
@@ -11,11 +11,9 @@
static void handle_unknown_message(struct snd_dg00x *dg00x,
unsigned long long offset, __be32 *buf)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dg00x->lock, flags);
- dg00x->msg = be32_to_cpu(*buf);
- spin_unlock_irqrestore(&dg00x->lock, flags);
+ scoped_guard(spinlock_irqsave, &dg00x->lock) {
+ dg00x->msg = be32_to_cpu(*buf);
+ }
wake_up(&dg00x->hwdep_wait);
}
diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c
index 995302808c27..f73a9fc8adb1 100644
--- a/sound/firewire/digi00x/digi00x.c
+++ b/sound/firewire/digi00x/digi00x.c
@@ -9,7 +9,7 @@
MODULE_DESCRIPTION("Digidesign Digi 002/003 family Driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
#define VENDOR_DIGIDESIGN 0x00a07e
#define MODEL_CONSOLE 0x000001
@@ -30,9 +30,9 @@ static int name_card(struct snd_dg00x *dg00x)
model = skip_spaces(name);
- strcpy(dg00x->card->driver, "Digi00x");
- strcpy(dg00x->card->shortname, model);
- strcpy(dg00x->card->mixername, model);
+ strscpy(dg00x->card->driver, "Digi00x");
+ strscpy(dg00x->card->shortname, model);
+ strscpy(dg00x->card->mixername, model);
snprintf(dg00x->card->longname, sizeof(dg00x->card->longname),
"Digidesign %s, GUID %08x%08x at %s, S%d", model,
fw_dev->config_rom[3], fw_dev->config_rom[4],
@@ -116,9 +116,8 @@ static void snd_dg00x_update(struct fw_unit *unit)
snd_dg00x_transaction_reregister(dg00x);
- mutex_lock(&dg00x->mutex);
+ guard(mutex)(&dg00x->mutex);
snd_dg00x_stream_update_duplex(dg00x);
- mutex_unlock(&dg00x->mutex);
}
static void snd_dg00x_remove(struct fw_unit *unit)
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c
index df44dd5dc4b2..e60bfd0ee4ac 100644
--- a/sound/firewire/fcp.c
+++ b/sound/firewire/fcp.c
@@ -242,9 +242,9 @@ int fcp_avc_transaction(struct fw_unit *unit,
init_waitqueue_head(&t.wait);
t.deferrable = (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03);
- spin_lock_irq(&transactions_lock);
- list_add_tail(&t.list, &transactions);
- spin_unlock_irq(&transactions_lock);
+ scoped_guard(spinlock_irq, &transactions_lock) {
+ list_add_tail(&t.list, &transactions);
+ }
for (;;) {
tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST
@@ -280,9 +280,9 @@ deferred:
}
}
- spin_lock_irq(&transactions_lock);
- list_del(&t.list);
- spin_unlock_irq(&transactions_lock);
+ scoped_guard(spinlock_irq, &transactions_lock) {
+ list_del(&t.list);
+ }
return ret;
}
@@ -300,7 +300,7 @@ void fcp_bus_reset(struct fw_unit *unit)
{
struct fcp_transaction *t;
- spin_lock_irq(&transactions_lock);
+ guard(spinlock_irq)(&transactions_lock);
list_for_each_entry(t, &transactions, list) {
if (t->unit == unit &&
(t->state == STATE_PENDING ||
@@ -309,7 +309,6 @@ void fcp_bus_reset(struct fw_unit *unit)
wake_up(&t->wait);
}
}
- spin_unlock_irq(&transactions_lock);
}
EXPORT_SYMBOL(fcp_bus_reset);
@@ -341,12 +340,11 @@ static void fcp_response(struct fw_card *card, struct fw_request *request,
void *data, size_t length, void *callback_data)
{
struct fcp_transaction *t;
- unsigned long flags;
if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC)
return;
- spin_lock_irqsave(&transactions_lock, flags);
+ guard(spinlock_irqsave)(&transactions_lock);
list_for_each_entry(t, &transactions, list) {
struct fw_device *device = fw_parent_device(t->unit);
if (device->card != card ||
@@ -370,7 +368,6 @@ static void fcp_response(struct fw_card *card, struct fw_request *request,
wake_up(&t->wait);
}
}
- spin_unlock_irqrestore(&transactions_lock, flags);
}
static struct fw_address_handler response_register_handler = {
diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile
index 3aef221ce4b0..b397d95877a0 100644
--- a/sound/firewire/fireface/Makefile
+++ b/sound/firewire/fireface/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
+snd-fireface-y := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o \
ff-protocol-latter.o
obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
diff --git a/sound/firewire/fireface/ff-hwdep.c b/sound/firewire/fireface/ff-hwdep.c
index 8a741b3b0436..5976abf2e1ab 100644
--- a/sound/firewire/fireface/ff-hwdep.c
+++ b/sound/firewire/fireface/ff-hwdep.c
@@ -72,18 +72,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_table *wait)
{
struct snd_ff *ff = hwdep->private_data;
- __poll_t events;
poll_wait(file, &ff->hwdep_wait, wait);
- spin_lock_irq(&ff->lock);
+ guard(spinlock_irq)(&ff->lock);
if (ff->dev_lock_changed || has_msg(ff))
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&ff->lock);
-
- return events;
+ return 0;
}
static int hwdep_get_info(struct snd_ff *ff, void __user *arg)
@@ -107,48 +103,35 @@ static int hwdep_get_info(struct snd_ff *ff, void __user *arg)
static int hwdep_lock(struct snd_ff *ff)
{
- int err;
-
- spin_lock_irq(&ff->lock);
+ guard(spinlock_irq)(&ff->lock);
if (ff->dev_lock_count == 0) {
ff->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&ff->lock);
-
- return err;
}
static int hwdep_unlock(struct snd_ff *ff)
{
- int err;
-
- spin_lock_irq(&ff->lock);
+ guard(spinlock_irq)(&ff->lock);
if (ff->dev_lock_count == -1) {
ff->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&ff->lock);
-
- return err;
}
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_ff *ff = hwdep->private_data;
- spin_lock_irq(&ff->lock);
+ guard(spinlock_irq)(&ff->lock);
if (ff->dev_lock_count == -1)
ff->dev_lock_count = 0;
- spin_unlock_irq(&ff->lock);
return 0;
}
@@ -197,7 +180,7 @@ int snd_ff_create_hwdep_devices(struct snd_ff *ff)
if (err < 0)
return err;
- strcpy(hwdep->name, ff->card->driver);
+ strscpy(hwdep->name, ff->card->driver);
hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREFACE;
hwdep->ops = hwdep_ops;
hwdep->private_data = ff;
diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c
index 25821d186b87..9f6aa490e5bf 100644
--- a/sound/firewire/fireface/ff-midi.c
+++ b/sound/firewire/fireface/ff-midi.c
@@ -46,31 +46,25 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
int up)
{
struct snd_ff *ff = substream->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&ff->lock, flags);
+ guard(spinlock_irqsave)(&ff->lock);
if (up)
WRITE_ONCE(ff->tx_midi_substreams[substream->number],
substream);
else
WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
-
- spin_unlock_irqrestore(&ff->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
int up)
{
struct snd_ff *ff = substream->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&ff->lock, flags);
+ guard(spinlock_irqsave)(&ff->lock);
if (up || !ff->rx_midi_error[substream->number])
schedule_work(&ff->rx_midi_work[substream->number]);
-
- spin_unlock_irqrestore(&ff->lock, flags);
}
static void set_midi_substream_names(struct snd_rawmidi_str *stream,
@@ -79,8 +73,8 @@ static void set_midi_substream_names(struct snd_rawmidi_str *stream,
struct snd_rawmidi_substream *substream;
list_for_each_entry(substream, &stream->substreams, list) {
- snprintf(substream->name, sizeof(substream->name),
- "%s MIDI %d", name, substream->number + 1);
+ scnprintf(substream->name, sizeof(substream->name),
+ "%s MIDI %d", name, substream->number + 1);
}
}
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index ec915671a79b..7ad8204fbfe8 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -156,56 +156,49 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
goto release_lock;
- mutex_lock(&ff->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if (src != SND_FF_CLOCK_SRC_INTERNAL) {
- for (i = 0; i < CIP_SFC_COUNT; ++i) {
- if (amdtp_rate_table[i] == rate)
- break;
- }
-
- // The unit is configured at sampling frequency which packet
- // streaming engine can't support.
- if (i >= CIP_SFC_COUNT) {
- mutex_unlock(&ff->mutex);
- err = -EIO;
- goto release_lock;
- }
-
- substream->runtime->hw.rate_min = rate;
- substream->runtime->hw.rate_max = rate;
- } else {
- if (ff->substreams_counter > 0) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
-
- rate = amdtp_rate_table[ff->rx_stream.sfc];
- substream->runtime->hw.rate_min = rate;
- substream->runtime->hw.rate_max = rate;
+ scoped_guard(mutex, &ff->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if (src != SND_FF_CLOCK_SRC_INTERNAL) {
+ for (i = 0; i < CIP_SFC_COUNT; ++i) {
+ if (amdtp_rate_table[i] == rate)
+ break;
+ }
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
- if (err < 0) {
- mutex_unlock(&ff->mutex);
+ // The unit is configured at sampling frequency which packet
+ // streaming engine can't support.
+ if (i >= CIP_SFC_COUNT) {
+ err = -EIO;
goto release_lock;
}
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&ff->mutex);
- goto release_lock;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+ } else {
+ if (ff->substreams_counter > 0) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+
+ rate = amdtp_rate_table[ff->rx_stream.sfc];
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto release_lock;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto release_lock;
}
}
}
- mutex_unlock(&ff->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -235,12 +228,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&ff->mutex);
+ guard(mutex)(&ff->mutex);
err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period,
frames_per_buffer);
if (err >= 0)
++ff->substreams_counter;
- mutex_unlock(&ff->mutex);
}
return err;
@@ -250,15 +242,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_ff *ff = substream->private_data;
- mutex_lock(&ff->mutex);
+ guard(mutex)(&ff->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--ff->substreams_counter;
snd_ff_stream_stop_duplex(ff);
- mutex_unlock(&ff->mutex);
-
return 0;
}
@@ -268,14 +258,12 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- mutex_lock(&ff->mutex);
+ guard(mutex)(&ff->mutex);
err = snd_ff_stream_start_duplex(ff, runtime->rate);
if (err >= 0)
amdtp_stream_pcm_prepare(&ff->tx_stream);
- mutex_unlock(&ff->mutex);
-
return err;
}
@@ -285,14 +273,12 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- mutex_lock(&ff->mutex);
+ guard(mutex)(&ff->mutex);
err = snd_ff_stream_start_duplex(ff, runtime->rate);
if (err >= 0)
amdtp_stream_pcm_prepare(&ff->rx_stream);
- mutex_unlock(&ff->mutex);
-
return err;
}
@@ -390,6 +376,7 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
return err;
pcm->private_data = ff;
+ pcm->nonatomic = true;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", ff->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
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/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index 95bf405adb3d..ba42490f2b0e 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -253,33 +253,24 @@ void snd_ff_stream_lock_changed(struct snd_ff *ff)
int snd_ff_stream_lock_try(struct snd_ff *ff)
{
- int err;
-
- spin_lock_irq(&ff->lock);
+ guard(spinlock_irq)(&ff->lock);
/* user land lock this */
- if (ff->dev_lock_count < 0) {
- err = -EBUSY;
- goto end;
- }
+ if (ff->dev_lock_count < 0)
+ return -EBUSY;
/* this is the first time */
if (ff->dev_lock_count++ == 0)
snd_ff_stream_lock_changed(ff);
- err = 0;
-end:
- spin_unlock_irq(&ff->lock);
- return err;
+ return 0;
}
void snd_ff_stream_lock_release(struct snd_ff *ff)
{
- spin_lock_irq(&ff->lock);
+ guard(spinlock_irq)(&ff->lock);
if (WARN_ON(ff->dev_lock_count <= 0))
- goto end;
+ return;
if (--ff->dev_lock_count == 0)
snd_ff_stream_lock_changed(ff);
-end:
- spin_unlock_irq(&ff->lock);
}
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 6b89e39f4a43..436da0a3bdcc 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -132,15 +132,13 @@ static void handle_msg(struct fw_card *card, struct fw_request *request, int tco
struct snd_ff *ff = callback_data;
__le32 *buf = data;
u32 tstamp = fw_request_get_timestamp(request);
- unsigned long flag;
fw_send_response(card, request, RCODE_COMPLETE);
offset -= ff->async_handler.offset;
- spin_lock_irqsave(&ff->lock, flag);
+ guard(spinlock_irqsave)(&ff->lock);
ff->spec->protocol->handle_msg(ff, (unsigned int)offset, buf, length, tstamp);
- spin_unlock_irqrestore(&ff->lock, flag);
}
static int allocate_own_address(struct snd_ff *ff, int i)
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index 448e972028d9..5d2c4fbf4434 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -11,12 +11,12 @@
MODULE_DESCRIPTION("RME Fireface series Driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
static void name_card(struct snd_ff *ff)
{
struct fw_device *fw_dev = fw_parent_device(ff->unit);
- const char *const names[] = {
+ static const char *const names[] = {
[SND_FF_UNIT_VERSION_FF800] = "Fireface800",
[SND_FF_UNIT_VERSION_FF400] = "Fireface400",
[SND_FF_UNIT_VERSION_UFX] = "FirefaceUFX",
@@ -27,9 +27,9 @@ static void name_card(struct snd_ff *ff)
name = names[ff->unit_version];
- strcpy(ff->card->driver, "Fireface");
- strcpy(ff->card->shortname, name);
- strcpy(ff->card->mixername, name);
+ strscpy(ff->card->driver, "Fireface");
+ strscpy(ff->card->shortname, name);
+ strscpy(ff->card->mixername, name);
snprintf(ff->card->longname, sizeof(ff->card->longname),
"RME %s, GUID %08x%08x at %s, S%d", name,
fw_dev->config_rom[3], fw_dev->config_rom[4],
diff --git a/sound/firewire/fireworks/Makefile b/sound/firewire/fireworks/Makefile
index 3386121b2a04..baaf3066c9b1 100644
--- a/sound/firewire/fireworks/Makefile
+++ b/sound/firewire/fireworks/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \
+snd-fireworks-y := fireworks_transaction.o fireworks_command.o \
fireworks_stream.o fireworks_proc.o fireworks_midi.o \
fireworks_pcm.o fireworks_hwdep.o fireworks.o
obj-$(CONFIG_SND_FIREWORKS) += snd-fireworks.o
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c
index ffb6dd796243..3378c7dce88a 100644
--- a/sound/firewire/fireworks/fireworks.c
+++ b/sound/firewire/fireworks/fireworks.c
@@ -18,7 +18,7 @@
MODULE_DESCRIPTION("Echo Fireworks driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -90,14 +90,14 @@ get_hardware_info(struct snd_efw *efw)
(hwinfo->arm_version >> 16) & 0xff);
efw->firmware_version = hwinfo->arm_version;
- strcpy(efw->card->driver, "Fireworks");
- strcpy(efw->card->shortname, hwinfo->model_name);
- strcpy(efw->card->mixername, hwinfo->model_name);
- snprintf(efw->card->longname, sizeof(efw->card->longname),
- "%s %s v%s, GUID %08x%08x at %s, S%d",
- hwinfo->vendor_name, hwinfo->model_name, version,
- hwinfo->guid_hi, hwinfo->guid_lo,
- dev_name(&efw->unit->device), 100 << fw_dev->max_speed);
+ strscpy(efw->card->driver, "Fireworks");
+ strscpy(efw->card->shortname, hwinfo->model_name);
+ strscpy(efw->card->mixername, hwinfo->model_name);
+ scnprintf(efw->card->longname, sizeof(efw->card->longname),
+ "%s %s v%s, GUID %08x%08x at %s, S%d",
+ hwinfo->vendor_name, hwinfo->model_name, version,
+ hwinfo->guid_hi, hwinfo->guid_lo,
+ dev_name(&efw->unit->device), 100 << fw_dev->max_speed);
if (hwinfo->flags & BIT(FLAG_RESP_ADDR_CHANGABLE))
efw->resp_addr_changable = true;
@@ -188,9 +188,9 @@ efw_card_free(struct snd_card *card)
{
struct snd_efw *efw = card->private_data;
- mutex_lock(&devices_mutex);
- clear_bit(efw->card_index, devices_used);
- mutex_unlock(&devices_mutex);
+ scoped_guard(mutex, &devices_mutex) {
+ clear_bit(efw->card_index, devices_used);
+ }
snd_efw_stream_destroy_duplex(efw);
snd_efw_transaction_remove_instance(efw);
@@ -207,25 +207,21 @@ static int efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entr
int err;
// check registered cards.
- mutex_lock(&devices_mutex);
- for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
- if (!test_bit(card_index, devices_used) && enable[card_index])
- break;
- }
- if (card_index >= SNDRV_CARDS) {
- mutex_unlock(&devices_mutex);
- return -ENOENT;
- }
-
- err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
- sizeof(*efw), &card);
- if (err < 0) {
- mutex_unlock(&devices_mutex);
- return err;
+ scoped_guard(mutex, &devices_mutex) {
+ for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
+ if (!test_bit(card_index, devices_used) && enable[card_index])
+ break;
+ }
+ if (card_index >= SNDRV_CARDS)
+ return -ENOENT;
+
+ err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
+ sizeof(*efw), &card);
+ if (err < 0)
+ return err;
+ card->private_free = efw_card_free;
+ set_bit(card_index, devices_used);
}
- card->private_free = efw_card_free;
- set_bit(card_index, devices_used);
- mutex_unlock(&devices_mutex);
efw = card->private_data;
efw->unit = fw_unit_get(unit);
@@ -287,9 +283,8 @@ static void efw_update(struct fw_unit *unit)
snd_efw_transaction_bus_reset(efw->unit);
- mutex_lock(&efw->mutex);
+ guard(mutex)(&efw->mutex);
snd_efw_stream_update_duplex(efw);
- mutex_unlock(&efw->mutex);
}
static void efw_remove(struct fw_unit *unit)
diff --git a/sound/firewire/fireworks/fireworks_command.c b/sound/firewire/fireworks/fireworks_command.c
index 7e255fc2c6e4..2b595ee0bc35 100644
--- a/sound/firewire/fireworks/fireworks_command.c
+++ b/sound/firewire/fireworks/fireworks_command.c
@@ -119,14 +119,14 @@ efw_transaction(struct snd_efw *efw, unsigned int category,
return -ENOMEM;
/* to keep consistency of sequence number */
- spin_lock(&efw->lock);
- if ((efw->seqnum < KERNEL_SEQNUM_MIN) ||
- (efw->seqnum >= KERNEL_SEQNUM_MAX - 2))
- efw->seqnum = KERNEL_SEQNUM_MIN;
- else
- efw->seqnum += 2;
- seqnum = efw->seqnum;
- spin_unlock(&efw->lock);
+ scoped_guard(spinlock, &efw->lock) {
+ if ((efw->seqnum < KERNEL_SEQNUM_MIN) ||
+ (efw->seqnum >= KERNEL_SEQNUM_MAX - 2))
+ efw->seqnum = KERNEL_SEQNUM_MIN;
+ else
+ efw->seqnum += 2;
+ seqnum = efw->seqnum;
+ }
/* fill transaction header fields */
cmd_bytes = sizeof(struct snd_efw_transaction) + param_bytes;
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c
index 3a53914277d3..7d6bd8ceeab3 100644
--- a/sound/firewire/fireworks/fireworks_hwdep.c
+++ b/sound/firewire/fireworks/fireworks_hwdep.c
@@ -103,12 +103,10 @@ hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
};
- spin_lock_irq(&efw->lock);
-
- event.lock_status.status = (efw->dev_lock_count > 0);
- efw->dev_lock_changed = false;
-
- spin_unlock_irq(&efw->lock);
+ scoped_guard(spinlock_irq, &efw->lock) {
+ event.lock_status.status = (efw->dev_lock_count > 0);
+ efw->dev_lock_changed = false;
+ }
count = min_t(long, count, sizeof(event.lock_status));
@@ -192,13 +190,11 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
poll_wait(file, &efw->hwdep_wait, wait);
- spin_lock_irq(&efw->lock);
+ guard(spinlock_irq)(&efw->lock);
if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr)
events = EPOLLIN | EPOLLRDNORM;
else
events = 0;
- spin_unlock_irq(&efw->lock);
-
return events | EPOLLOUT;
}
@@ -225,39 +221,27 @@ hwdep_get_info(struct snd_efw *efw, void __user *arg)
static int
hwdep_lock(struct snd_efw *efw)
{
- int err;
-
- spin_lock_irq(&efw->lock);
+ guard(spinlock_irq)(&efw->lock);
if (efw->dev_lock_count == 0) {
efw->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&efw->lock);
-
- return err;
}
static int
hwdep_unlock(struct snd_efw *efw)
{
- int err;
-
- spin_lock_irq(&efw->lock);
+ guard(spinlock_irq)(&efw->lock);
if (efw->dev_lock_count == -1) {
efw->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&efw->lock);
-
- return err;
}
static int
@@ -265,10 +249,9 @@ hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_efw *efw = hwdep->private_data;
- spin_lock_irq(&efw->lock);
+ guard(spinlock_irq)(&efw->lock);
if (efw->dev_lock_count == -1)
efw->dev_lock_count = 0;
- spin_unlock_irq(&efw->lock);
return 0;
}
@@ -319,7 +302,7 @@ int snd_efw_create_hwdep_device(struct snd_efw *efw)
err = snd_hwdep_new(efw->card, "Fireworks", 0, &hwdep);
if (err < 0)
goto end;
- strcpy(hwdep->name, "Fireworks");
+ strscpy(hwdep->name, "Fireworks");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS;
hwdep->ops = ops;
hwdep->private_data = efw;
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c
index 84621e356848..405106a6aef9 100644
--- a/sound/firewire/fireworks/fireworks_midi.c
+++ b/sound/firewire/fireworks/fireworks_midi.c
@@ -14,20 +14,19 @@ static int midi_open(struct snd_rawmidi_substream *substream)
err = snd_efw_stream_lock_try(efw);
if (err < 0)
- goto end;
-
- mutex_lock(&efw->mutex);
- err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0);
- if (err >= 0) {
- ++efw->substreams_counter;
- err = snd_efw_stream_start_duplex(efw);
- if (err < 0)
- --efw->substreams_counter;
+ return err;
+
+ scoped_guard(mutex, &efw->mutex) {
+ err = snd_efw_stream_reserve_duplex(efw, 0, 0, 0);
+ if (err >= 0) {
+ ++efw->substreams_counter;
+ err = snd_efw_stream_start_duplex(efw);
+ if (err < 0)
+ --efw->substreams_counter;
+ }
}
- mutex_unlock(&efw->mutex);
if (err < 0)
snd_efw_stream_lock_release(efw);
-end:
return err;
}
@@ -35,10 +34,10 @@ static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_efw *efw = substream->rmidi->private_data;
- mutex_lock(&efw->mutex);
- --efw->substreams_counter;
- snd_efw_stream_stop_duplex(efw);
- mutex_unlock(&efw->mutex);
+ scoped_guard(mutex, &efw->mutex) {
+ --efw->substreams_counter;
+ snd_efw_stream_stop_duplex(efw);
+ }
snd_efw_stream_lock_release(efw);
return 0;
@@ -47,9 +46,8 @@ static int midi_close(struct snd_rawmidi_substream *substream)
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_efw *efw = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&efw->lock, flags);
+ guard(spinlock_irqsave)(&efw->lock);
if (up)
amdtp_am824_midi_trigger(&efw->tx_stream,
@@ -57,16 +55,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&efw->tx_stream,
substrm->number, NULL);
-
- spin_unlock_irqrestore(&efw->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_efw *efw = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&efw->lock, flags);
+ guard(spinlock_irqsave)(&efw->lock);
if (up)
amdtp_am824_midi_trigger(&efw->rx_stream,
@@ -74,8 +69,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&efw->rx_stream,
substrm->number, NULL);
-
- spin_unlock_irqrestore(&efw->lock, flags);
}
static void set_midi_substream_names(struct snd_efw *efw,
@@ -84,8 +77,8 @@ static void set_midi_substream_names(struct snd_efw *efw,
struct snd_rawmidi_substream *subs;
list_for_each_entry(subs, &str->substreams, list) {
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d", efw->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d", efw->card->shortname, subs->number + 1);
}
}
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index c3c21860b245..9399293a9fe9 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -189,46 +189,38 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
goto err_locked;
- mutex_lock(&efw->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||
- (efw->substreams_counter > 0 && d->events_per_period > 0)) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
- unsigned int sampling_rate;
-
- err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);
- if (err < 0) {
- mutex_unlock(&efw->mutex);
- goto err_locked;
- }
- substream->runtime->hw.rate_min = sampling_rate;
- substream->runtime->hw.rate_max = sampling_rate;
-
- if (frames_per_period > 0) {
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
- if (err < 0) {
- mutex_unlock(&efw->mutex);
- goto err_locked;
- }
-
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&efw->mutex);
+ scoped_guard(mutex, &efw->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||
+ (efw->substreams_counter > 0 && d->events_per_period > 0)) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+ unsigned int sampling_rate;
+
+ err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);
+ if (err < 0)
goto err_locked;
+ substream->runtime->hw.rate_min = sampling_rate;
+ substream->runtime->hw.rate_max = sampling_rate;
+
+ if (frames_per_period > 0) {
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
}
}
}
- mutex_unlock(&efw->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -255,12 +247,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&efw->mutex);
+ guard(mutex)(&efw->mutex);
err = snd_efw_stream_reserve_duplex(efw, rate,
frames_per_period, frames_per_buffer);
if (err >= 0)
++efw->substreams_counter;
- mutex_unlock(&efw->mutex);
}
return err;
@@ -270,15 +261,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_efw *efw = substream->private_data;
- mutex_lock(&efw->mutex);
+ guard(mutex)(&efw->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--efw->substreams_counter;
snd_efw_stream_stop_duplex(efw);
- mutex_unlock(&efw->mutex);
-
return 0;
}
@@ -397,6 +386,7 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
goto end;
pcm->private_data = efw;
+ pcm->nonatomic = true;
snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 53dbd4d4b0d0..974084e1c083 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -345,33 +345,24 @@ void snd_efw_stream_lock_changed(struct snd_efw *efw)
int snd_efw_stream_lock_try(struct snd_efw *efw)
{
- int err;
-
- spin_lock_irq(&efw->lock);
+ guard(spinlock_irq)(&efw->lock);
/* user land lock this */
- if (efw->dev_lock_count < 0) {
- err = -EBUSY;
- goto end;
- }
+ if (efw->dev_lock_count < 0)
+ return -EBUSY;
/* this is the first time */
if (efw->dev_lock_count++ == 0)
snd_efw_stream_lock_changed(efw);
- err = 0;
-end:
- spin_unlock_irq(&efw->lock);
- return err;
+ return 0;
}
void snd_efw_stream_lock_release(struct snd_efw *efw)
{
- spin_lock_irq(&efw->lock);
+ guard(spinlock_irq)(&efw->lock);
if (WARN_ON(efw->dev_lock_count <= 0))
- goto end;
+ return;
if (--efw->dev_lock_count == 0)
snd_efw_stream_lock_changed(efw);
-end:
- spin_unlock_irq(&efw->lock);
}
diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c
index 9f8c53b39f95..5c859773fe06 100644
--- a/sound/firewire/fireworks/fireworks_transaction.c
+++ b/sound/firewire/fireworks/fireworks_transaction.c
@@ -82,9 +82,9 @@ int snd_efw_transaction_run(struct fw_unit *unit,
t.state = STATE_PENDING;
init_waitqueue_head(&t.wait);
- spin_lock_irq(&transaction_queues_lock);
- list_add_tail(&t.list, &transaction_queues);
- spin_unlock_irq(&transaction_queues_lock);
+ scoped_guard(spinlock_irq, &transaction_queues_lock) {
+ list_add_tail(&t.list, &transaction_queues);
+ }
tries = 0;
do {
@@ -107,9 +107,9 @@ int snd_efw_transaction_run(struct fw_unit *unit,
}
} while (1);
- spin_lock_irq(&transaction_queues_lock);
- list_del(&t.list);
- spin_unlock_irq(&transaction_queues_lock);
+ scoped_guard(spinlock_irq, &transaction_queues_lock) {
+ list_del(&t.list);
+ }
return ret;
}
@@ -123,7 +123,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
t = (struct snd_efw_transaction *)data;
length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
- spin_lock(&efw->lock);
+ guard(spinlock)(&efw->lock);
if (efw->push_ptr < efw->pull_ptr)
capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
@@ -134,7 +134,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
/* confirm enough space for this response */
if (capacity < length) {
*rcode = RCODE_CONFLICT_ERROR;
- goto end;
+ return;
}
/* copy to ring buffer */
@@ -157,8 +157,6 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
wake_up(&efw->hwdep_wait);
*rcode = RCODE_COMPLETE;
-end:
- spin_unlock_irq(&efw->lock);
}
static void
@@ -169,7 +167,7 @@ handle_resp_for_user(struct fw_card *card, int generation, int source,
struct snd_efw *efw;
unsigned int i;
- spin_lock_irq(&instances_lock);
+ guard(spinlock_irq)(&instances_lock);
for (i = 0; i < SNDRV_CARDS; i++) {
efw = instances[i];
@@ -186,11 +184,9 @@ handle_resp_for_user(struct fw_card *card, int generation, int source,
break;
}
if (i == SNDRV_CARDS)
- goto end;
+ return;
copy_resp_to_buf(efw, data, length, rcode);
-end:
- spin_unlock(&instances_lock);
}
static void
@@ -199,9 +195,8 @@ handle_resp_for_kernel(struct fw_card *card, int generation, int source,
{
struct fw_device *device;
struct transaction_queue *t;
- unsigned long flags;
- spin_lock_irqsave(&transaction_queues_lock, flags);
+ guard(spinlock_irqsave)(&transaction_queues_lock);
list_for_each_entry(t, &transaction_queues, list) {
device = fw_parent_device(t->unit);
if ((device->card != card) ||
@@ -219,7 +214,6 @@ handle_resp_for_kernel(struct fw_card *card, int generation, int source,
*rcode = RCODE_COMPLETE;
}
}
- spin_unlock_irqrestore(&transaction_queues_lock, flags);
}
static void
@@ -259,7 +253,7 @@ void snd_efw_transaction_add_instance(struct snd_efw *efw)
{
unsigned int i;
- spin_lock_irq(&instances_lock);
+ guard(spinlock_irq)(&instances_lock);
for (i = 0; i < SNDRV_CARDS; i++) {
if (instances[i] != NULL)
@@ -267,30 +261,26 @@ void snd_efw_transaction_add_instance(struct snd_efw *efw)
instances[i] = efw;
break;
}
-
- spin_unlock_irq(&instances_lock);
}
void snd_efw_transaction_remove_instance(struct snd_efw *efw)
{
unsigned int i;
- spin_lock_irq(&instances_lock);
+ guard(spinlock_irq)(&instances_lock);
for (i = 0; i < SNDRV_CARDS; i++) {
if (instances[i] != efw)
continue;
instances[i] = NULL;
}
-
- spin_unlock_irq(&instances_lock);
}
void snd_efw_transaction_bus_reset(struct fw_unit *unit)
{
struct transaction_queue *t;
- spin_lock_irq(&transaction_queues_lock);
+ guard(spinlock_irq)(&transaction_queues_lock);
list_for_each_entry(t, &transaction_queues, list) {
if ((t->unit == unit) &&
(t->state == STATE_PENDING)) {
@@ -298,7 +288,6 @@ void snd_efw_transaction_bus_reset(struct fw_unit *unit)
wake_up(&t->wait);
}
}
- spin_unlock_irq(&transaction_queues_lock);
}
static struct fw_address_handler resp_register_handler = {
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index 6655af53b367..2b7f071d593b 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -77,7 +77,7 @@ struct audio_payload {
MODULE_DESCRIPTION("iSight audio driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
static struct fw_iso_packet audio_packet = {
.payload_length = sizeof(struct audio_payload),
@@ -327,9 +327,8 @@ static int isight_hw_free(struct snd_pcm_substream *substream)
WRITE_ONCE(isight->pcm_active, false);
- mutex_lock(&isight->mutex);
+ guard(mutex)(&isight->mutex);
isight_stop_streaming(isight);
- mutex_unlock(&isight->mutex);
return 0;
}
@@ -400,16 +399,12 @@ error:
static int isight_prepare(struct snd_pcm_substream *substream)
{
struct isight *isight = substream->private_data;
- int err;
isight->buffer_pointer = 0;
isight->period_counter = 0;
- mutex_lock(&isight->mutex);
- err = isight_start_streaming(isight);
- mutex_unlock(&isight->mutex);
-
- return err;
+ guard(mutex)(&isight->mutex);
+ return isight_start_streaming(isight);
}
static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -454,7 +449,8 @@ static int isight_create_pcm(struct isight *isight)
if (err < 0)
return err;
pcm->private_data = isight;
- strcpy(pcm->name, "iSight");
+ pcm->nonatomic = true;
+ strscpy(pcm->name, "iSight");
isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
isight->pcm->ops = &ops;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
@@ -637,13 +633,13 @@ static int isight_probe(struct fw_unit *unit,
card->private_free = isight_card_free;
- strcpy(card->driver, "iSight");
- strcpy(card->shortname, "Apple iSight");
+ strscpy(card->driver, "iSight");
+ strscpy(card->shortname, "Apple iSight");
snprintf(card->longname, sizeof(card->longname),
"Apple iSight (GUID %08x%08x) at %s, S%d",
fw_dev->config_rom[3], fw_dev->config_rom[4],
dev_name(&unit->device), 100 << fw_dev->max_speed);
- strcpy(card->mixername, "iSight");
+ strscpy(card->mixername, "iSight");
err = isight_create_pcm(isight);
if (err < 0)
@@ -676,9 +672,8 @@ static void isight_bus_reset(struct fw_unit *unit)
if (fw_iso_resources_update(&isight->resources) < 0) {
isight_pcm_abort(isight);
- mutex_lock(&isight->mutex);
+ guard(mutex)(&isight->mutex);
isight_stop_streaming(isight);
- mutex_unlock(&isight->mutex);
}
}
@@ -690,9 +685,9 @@ static void isight_remove(struct fw_unit *unit)
snd_card_disconnect(isight->card);
- mutex_lock(&isight->mutex);
- isight_stop_streaming(isight);
- mutex_unlock(&isight->mutex);
+ scoped_guard(mutex, &isight->mutex) {
+ isight_stop_streaming(isight);
+ }
// Block till all of ALSA character devices are released.
snd_card_free(isight->card);
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
index 84f71b2eaa82..4f63279225c5 100644
--- a/sound/firewire/iso-resources.c
+++ b/sound/firewire/iso-resources.c
@@ -114,38 +114,34 @@ int fw_iso_resources_allocate(struct fw_iso_resources *r,
r->bandwidth = packet_bandwidth(max_payload_bytes, speed);
retry_after_bus_reset:
- spin_lock_irq(&card->lock);
- r->generation = card->generation;
- r->bandwidth_overhead = current_bandwidth_overhead(card);
- spin_unlock_irq(&card->lock);
+ scoped_guard(spinlock_irq, &card->lock) {
+ r->generation = card->generation;
+ r->bandwidth_overhead = current_bandwidth_overhead(card);
+ }
err = wait_isoch_resource_delay_after_bus_reset(card);
if (err < 0)
return err;
- mutex_lock(&r->mutex);
-
- bandwidth = r->bandwidth + r->bandwidth_overhead;
- fw_iso_resource_manage(card, r->generation, r->channels_mask,
- &channel, &bandwidth, true);
- if (channel == -EAGAIN) {
- mutex_unlock(&r->mutex);
- goto retry_after_bus_reset;
- }
- if (channel >= 0) {
- r->channel = channel;
- r->allocated = true;
- } else {
- if (channel == -EBUSY)
- dev_err(&r->unit->device,
- "isochronous resources exhausted\n");
- else
- dev_err(&r->unit->device,
- "isochronous resource allocation failed\n");
+ scoped_guard(mutex, &r->mutex) {
+ bandwidth = r->bandwidth + r->bandwidth_overhead;
+ fw_iso_resource_manage(card, r->generation, r->channels_mask,
+ &channel, &bandwidth, true);
+ if (channel == -EAGAIN)
+ goto retry_after_bus_reset;
+ if (channel >= 0) {
+ r->channel = channel;
+ r->allocated = true;
+ } else {
+ if (channel == -EBUSY)
+ dev_err(&r->unit->device,
+ "isochronous resources exhausted\n");
+ else
+ dev_err(&r->unit->device,
+ "isochronous resource allocation failed\n");
+ }
}
- mutex_unlock(&r->mutex);
-
return channel;
}
EXPORT_SYMBOL(fw_iso_resources_allocate);
@@ -166,17 +162,15 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
struct fw_card *card = fw_parent_device(r->unit)->card;
int bandwidth, channel;
- mutex_lock(&r->mutex);
+ guard(mutex)(&r->mutex);
- if (!r->allocated) {
- mutex_unlock(&r->mutex);
+ if (!r->allocated)
return 0;
- }
- spin_lock_irq(&card->lock);
- r->generation = card->generation;
- r->bandwidth_overhead = current_bandwidth_overhead(card);
- spin_unlock_irq(&card->lock);
+ scoped_guard(spinlock_irq, &card->lock) {
+ r->generation = card->generation;
+ r->bandwidth_overhead = current_bandwidth_overhead(card);
+ }
bandwidth = r->bandwidth + r->bandwidth_overhead;
@@ -196,8 +190,6 @@ int fw_iso_resources_update(struct fw_iso_resources *r)
"isochronous resource allocation failed\n");
}
- mutex_unlock(&r->mutex);
-
return channel;
}
EXPORT_SYMBOL(fw_iso_resources_update);
@@ -218,7 +210,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
return;
card = fw_parent_device(r->unit)->card;
- mutex_lock(&r->mutex);
+ guard(mutex)(&r->mutex);
if (r->allocated) {
bandwidth = r->bandwidth + r->bandwidth_overhead;
@@ -230,7 +222,5 @@ void fw_iso_resources_free(struct fw_iso_resources *r)
r->allocated = false;
}
-
- mutex_unlock(&r->mutex);
}
EXPORT_SYMBOL(fw_iso_resources_free);
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
index e0a2337e8f27..654e1a6050a9 100644
--- a/sound/firewire/lib.c
+++ b/sound/firewire/lib.c
@@ -69,4 +69,4 @@ EXPORT_SYMBOL(snd_fw_transaction);
MODULE_DESCRIPTION("FireWire audio helper functions");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
index 3bef2a0b1e2e..df0fe886dbc0 100644
--- a/sound/firewire/motu/Makefile
+++ b/sound/firewire/motu/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
CFLAGS_amdtp-motu.o := -I$(src)
-snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
+snd-firewire-motu-y := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
motu-protocol-v2.o motu-protocol-v3.o \
motu-protocol-v1.o motu-register-dsp-message-parser.o \
diff --git a/sound/firewire/motu/motu-command-dsp-message-parser.c b/sound/firewire/motu/motu-command-dsp-message-parser.c
index 5d8a86a12f1f..c6440e6e360b 100644
--- a/sound/firewire/motu/motu-command-dsp-message-parser.c
+++ b/sound/firewire/motu/motu-command-dsp-message-parser.c
@@ -87,10 +87,9 @@ void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,
unsigned int data_block_quadlets = s->data_block_quadlets;
struct msg_parser *parser = motu->message_parser;
unsigned int interval = parser->interval;
- unsigned long flags;
int i;
- spin_lock_irqsave(&parser->lock, flags);
+ guard(spinlock_irqsave)(&parser->lock);
for (i = 0; i < count; ++i) {
__be32 *buffer = desc->ctx_payload;
@@ -168,17 +167,13 @@ void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,
}
}
}
-
- spin_unlock_irqrestore(&parser->lock, flags);
}
void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
struct snd_firewire_motu_command_dsp_meter *meter)
{
struct msg_parser *parser = motu->message_parser;
- unsigned long flags;
- spin_lock_irqsave(&parser->lock, flags);
+ guard(spinlock_irqsave)(&parser->lock);
memcpy(meter, &parser->meter, sizeof(*meter));
- spin_unlock_irqrestore(&parser->lock, flags);
}
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c
index 88d1f4b56e4b..981c19430cb0 100644
--- a/sound/firewire/motu/motu-hwdep.c
+++ b/sound/firewire/motu/motu-hwdep.c
@@ -100,18 +100,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_table *wait)
{
struct snd_motu *motu = hwdep->private_data;
- __poll_t events;
poll_wait(file, &motu->hwdep_wait, wait);
- spin_lock_irq(&motu->lock);
+ guard(spinlock_irq)(&motu->lock);
if (motu->dev_lock_changed || motu->msg || has_dsp_event(motu))
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&motu->lock);
-
- return events | EPOLLOUT;
+ return 0;
}
static int hwdep_get_info(struct snd_motu *motu, void __user *arg)
@@ -135,48 +131,35 @@ static int hwdep_get_info(struct snd_motu *motu, void __user *arg)
static int hwdep_lock(struct snd_motu *motu)
{
- int err;
-
- spin_lock_irq(&motu->lock);
+ guard(spinlock_irq)(&motu->lock);
if (motu->dev_lock_count == 0) {
motu->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&motu->lock);
-
- return err;
}
static int hwdep_unlock(struct snd_motu *motu)
{
- int err;
-
- spin_lock_irq(&motu->lock);
+ guard(spinlock_irq)(&motu->lock);
if (motu->dev_lock_count == -1) {
motu->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&motu->lock);
-
- return err;
}
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_motu *motu = hwdep->private_data;
- spin_lock_irq(&motu->lock);
+ guard(spinlock_irq)(&motu->lock);
if (motu->dev_lock_count == -1)
motu->dev_lock_count = 0;
- spin_unlock_irq(&motu->lock);
return 0;
}
@@ -290,7 +273,7 @@ int snd_motu_create_hwdep_device(struct snd_motu *motu)
if (err < 0)
return err;
- strcpy(hwdep->name, "MOTU");
+ strscpy(hwdep->name, "MOTU");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU;
hwdep->ops = ops;
hwdep->private_data = motu;
diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c
index 2365f7dfde26..85e3260f9349 100644
--- a/sound/firewire/motu/motu-midi.c
+++ b/sound/firewire/motu/motu-midi.c
@@ -15,18 +15,16 @@ static int midi_open(struct snd_rawmidi_substream *substream)
if (err < 0)
return err;
- mutex_lock(&motu->mutex);
-
- err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0);
- if (err >= 0) {
- ++motu->substreams_counter;
- err = snd_motu_stream_start_duplex(motu);
- if (err < 0)
- --motu->substreams_counter;
+ scoped_guard(mutex, &motu->mutex) {
+ err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0);
+ if (err >= 0) {
+ ++motu->substreams_counter;
+ err = snd_motu_stream_start_duplex(motu);
+ if (err < 0)
+ --motu->substreams_counter;
+ }
}
- mutex_unlock(&motu->mutex);
-
if (err < 0)
snd_motu_stream_lock_release(motu);
@@ -37,12 +35,10 @@ static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_motu *motu = substream->rmidi->private_data;
- mutex_lock(&motu->mutex);
-
- --motu->substreams_counter;
- snd_motu_stream_stop_duplex(motu);
-
- mutex_unlock(&motu->mutex);
+ scoped_guard(mutex, &motu->mutex) {
+ --motu->substreams_counter;
+ snd_motu_stream_stop_duplex(motu);
+ }
snd_motu_stream_lock_release(motu);
return 0;
@@ -51,9 +47,8 @@ static int midi_close(struct snd_rawmidi_substream *substream)
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_motu *motu = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&motu->lock, flags);
+ guard(spinlock_irqsave)(&motu->lock);
if (up)
amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
@@ -61,16 +56,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
NULL);
-
- spin_unlock_irqrestore(&motu->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_motu *motu = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&motu->lock, flags);
+ guard(spinlock_irqsave)(&motu->lock);
if (up)
amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
@@ -78,8 +70,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
NULL);
-
- spin_unlock_irqrestore(&motu->lock, flags);
}
static void set_midi_substream_names(struct snd_motu *motu,
@@ -88,8 +78,8 @@ static void set_midi_substream_names(struct snd_motu *motu,
struct snd_rawmidi_substream *subs;
list_for_each_entry(subs, &str->substreams, list) {
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d", motu->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d", motu->card->shortname, subs->number + 1);
}
}
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c
index d410c2efbde5..600c571edf02 100644
--- a/sound/firewire/motu/motu-pcm.c
+++ b/sound/firewire/motu/motu-pcm.c
@@ -138,59 +138,56 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
return err;
- mutex_lock(&motu->mutex);
-
- err = snd_motu_stream_cache_packet_formats(motu);
- if (err < 0)
- goto err_locked;
-
- err = init_hw_info(motu, substream);
- if (err < 0)
- goto err_locked;
+ scoped_guard(mutex, &motu->mutex) {
+ err = snd_motu_stream_cache_packet_formats(motu);
+ if (err < 0)
+ goto err_locked;
- err = snd_motu_protocol_get_clock_source(motu, &src);
- if (err < 0)
- goto err_locked;
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL &&
- src != SND_MOTU_CLOCK_SOURCE_SPH) ||
- (motu->substreams_counter > 0 && d->events_per_period > 0)) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
- unsigned int rate;
-
- err = snd_motu_protocol_get_clock_rate(motu, &rate);
+ err = init_hw_info(motu, substream);
if (err < 0)
goto err_locked;
- substream->runtime->hw.rate_min = rate;
- substream->runtime->hw.rate_max = rate;
+ err = snd_motu_protocol_get_clock_source(motu, &src);
+ if (err < 0)
+ goto err_locked;
- if (frames_per_period > 0) {
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL &&
+ src != SND_MOTU_CLOCK_SOURCE_SPH) ||
+ (motu->substreams_counter > 0 && d->events_per_period > 0)) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+ unsigned int rate;
+
+ err = snd_motu_protocol_get_clock_rate(motu, &rate);
if (err < 0)
goto err_locked;
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0)
- goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+
+ if (frames_per_period > 0) {
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
+ }
}
}
snd_pcm_set_sync(substream);
- mutex_unlock(&motu->mutex);
-
return 0;
err_locked:
- mutex_unlock(&motu->mutex);
snd_motu_stream_lock_release(motu);
return err;
}
@@ -215,12 +212,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&motu->mutex);
+ guard(mutex)(&motu->mutex);
err = snd_motu_stream_reserve_duplex(motu, rate,
frames_per_period, frames_per_buffer);
if (err >= 0)
++motu->substreams_counter;
- mutex_unlock(&motu->mutex);
}
return err;
@@ -230,15 +226,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_motu *motu = substream->private_data;
- mutex_lock(&motu->mutex);
+ guard(mutex)(&motu->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--motu->substreams_counter;
snd_motu_stream_stop_duplex(motu);
- mutex_unlock(&motu->mutex);
-
return 0;
}
@@ -247,9 +241,9 @@ static int capture_prepare(struct snd_pcm_substream *substream)
struct snd_motu *motu = substream->private_data;
int err;
- mutex_lock(&motu->mutex);
- err = snd_motu_stream_start_duplex(motu);
- mutex_unlock(&motu->mutex);
+ scoped_guard(mutex, &motu->mutex) {
+ err = snd_motu_stream_start_duplex(motu);
+ }
if (err >= 0)
amdtp_stream_pcm_prepare(&motu->tx_stream);
@@ -260,9 +254,9 @@ static int playback_prepare(struct snd_pcm_substream *substream)
struct snd_motu *motu = substream->private_data;
int err;
- mutex_lock(&motu->mutex);
- err = snd_motu_stream_start_duplex(motu);
- mutex_unlock(&motu->mutex);
+ scoped_guard(mutex, &motu->mutex) {
+ err = snd_motu_stream_start_duplex(motu);
+ }
if (err >= 0)
amdtp_stream_pcm_prepare(&motu->rx_stream);
@@ -360,7 +354,8 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
if (err < 0)
return err;
pcm->private_data = motu;
- strcpy(pcm->name, motu->card->shortname);
+ pcm->nonatomic = true;
+ strscpy(pcm->name, motu->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c
index 8a0426920a76..7254fdfe046a 100644
--- a/sound/firewire/motu/motu-protocol-v3.c
+++ b/sound/firewire/motu/motu-protocol-v3.c
@@ -261,6 +261,7 @@ int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
if (motu->spec == &snd_motu_spec_828mk3_fw ||
motu->spec == &snd_motu_spec_828mk3_hybrid ||
+ motu->spec == &snd_motu_spec_896mk3 ||
motu->spec == &snd_motu_spec_traveler_mk3 ||
motu->spec == &snd_motu_spec_track16)
return detect_packet_formats_with_opt_ifaces(motu, data);
@@ -288,6 +289,14 @@ const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = {
.rx_fixed_pcm_chunks = {14, 14, 14}, // Additional 4 dummy chunks at higher rate.
};
+const struct snd_motu_spec snd_motu_spec_896mk3 = {
+ .name = "896mk3",
+ .protocol_version = SND_MOTU_PROTOCOL_V3,
+ .flags = SND_MOTU_SPEC_COMMAND_DSP,
+ .tx_fixed_pcm_chunks = {18, 14, 10},
+ .rx_fixed_pcm_chunks = {18, 14, 10},
+};
+
const struct snd_motu_spec snd_motu_spec_traveler_mk3 = {
.name = "TravelerMk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,
diff --git a/sound/firewire/motu/motu-register-dsp-message-parser.c b/sound/firewire/motu/motu-register-dsp-message-parser.c
index ef3b0b0f0dab..a8053e3ef065 100644
--- a/sound/firewire/motu/motu-register-dsp-message-parser.c
+++ b/sound/firewire/motu/motu-register-dsp-message-parser.c
@@ -150,10 +150,9 @@ void snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s,
struct msg_parser *parser = motu->message_parser;
bool meter_pos_quirk = parser->meter_pos_quirk;
unsigned int pos = parser->push_pos;
- unsigned long flags;
int i;
- spin_lock_irqsave(&parser->lock, flags);
+ guard(spinlock_irqsave)(&parser->lock);
for (i = 0; i < count; ++i) {
__be32 *buffer = desc->ctx_payload;
@@ -363,30 +362,24 @@ void snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s,
if (pos != parser->push_pos)
wake_up(&motu->hwdep_wait);
-
- spin_unlock_irqrestore(&parser->lock, flags);
}
void snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
struct snd_firewire_motu_register_dsp_meter *meter)
{
struct msg_parser *parser = motu->message_parser;
- unsigned long flags;
- spin_lock_irqsave(&parser->lock, flags);
+ guard(spinlock_irqsave)(&parser->lock);
memcpy(meter, &parser->meter, sizeof(*meter));
- spin_unlock_irqrestore(&parser->lock, flags);
}
void snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu,
struct snd_firewire_motu_register_dsp_parameter *param)
{
struct msg_parser *parser = motu->message_parser;
- unsigned long flags;
- spin_lock_irqsave(&parser->lock, flags);
+ guard(spinlock_irqsave)(&parser->lock);
memcpy(param, &parser->param, sizeof(*param));
- spin_unlock_irqrestore(&parser->lock, flags);
}
unsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu)
@@ -403,12 +396,11 @@ bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32
{
struct msg_parser *parser = motu->message_parser;
unsigned int pos = parser->pull_pos;
- unsigned long flags;
if (pos == parser->push_pos)
return false;
- spin_lock_irqsave(&parser->lock, flags);
+ guard(spinlock_irqsave)(&parser->lock);
*event = parser->event_queue[pos];
@@ -417,7 +409,5 @@ bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32
pos = 0;
parser->pull_pos = pos;
- spin_unlock_irqrestore(&parser->lock, flags);
-
return true;
}
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
index 64aec9c3eefd..e5f21360cfb7 100644
--- a/sound/firewire/motu/motu-stream.c
+++ b/sound/firewire/motu/motu-stream.c
@@ -407,32 +407,23 @@ static void motu_lock_changed(struct snd_motu *motu)
int snd_motu_stream_lock_try(struct snd_motu *motu)
{
- int err;
-
- spin_lock_irq(&motu->lock);
+ guard(spinlock_irq)(&motu->lock);
- if (motu->dev_lock_count < 0) {
- err = -EBUSY;
- goto out;
- }
+ if (motu->dev_lock_count < 0)
+ return -EBUSY;
if (motu->dev_lock_count++ == 0)
motu_lock_changed(motu);
- err = 0;
-out:
- spin_unlock_irq(&motu->lock);
- return err;
+ return 0;
}
void snd_motu_stream_lock_release(struct snd_motu *motu)
{
- spin_lock_irq(&motu->lock);
+ guard(spinlock_irq)(&motu->lock);
if (WARN_ON(motu->dev_lock_count <= 0))
- goto out;
+ return;
if (--motu->dev_lock_count == 0)
motu_lock_changed(motu);
-out:
- spin_unlock_irq(&motu->lock);
}
diff --git a/sound/firewire/motu/motu-transaction.c b/sound/firewire/motu/motu-transaction.c
index 2dc1d6e59144..804f4208cf81 100644
--- a/sound/firewire/motu/motu-transaction.c
+++ b/sound/firewire/motu/motu-transaction.c
@@ -51,7 +51,6 @@ static void handle_message(struct fw_card *card, struct fw_request *request,
{
struct snd_motu *motu = callback_data;
__be32 *buf = (__be32 *)data;
- unsigned long flags;
if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
fw_send_response(card, request, RCODE_COMPLETE);
@@ -63,9 +62,9 @@ static void handle_message(struct fw_card *card, struct fw_request *request,
return;
}
- spin_lock_irqsave(&motu->lock, flags);
- motu->msg = be32_to_cpu(*buf);
- spin_unlock_irqrestore(&motu->lock, flags);
+ scoped_guard(spinlock_irqsave, &motu->lock) {
+ motu->msg = be32_to_cpu(*buf);
+ }
fw_send_response(card, request, RCODE_COMPLETE);
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index f8b7fe38751c..fd2a9dddbfa6 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -11,7 +11,7 @@
MODULE_DESCRIPTION("MOTU FireWire driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT] = {
/* mode 0 */
@@ -41,9 +41,9 @@ static void name_card(struct snd_motu *motu)
}
}
- strcpy(motu->card->driver, "FW-MOTU");
- strcpy(motu->card->shortname, motu->spec->name);
- strcpy(motu->card->mixername, motu->spec->name);
+ strscpy(motu->card->driver, "FW-MOTU");
+ strscpy(motu->card->shortname, motu->spec->name);
+ strscpy(motu->card->mixername, motu->spec->name);
snprintf(motu->card->longname, sizeof(motu->card->longname),
"MOTU %s (version:%06x), GUID %08x%08x at %s, S%d",
motu->spec->name, version,
@@ -168,10 +168,12 @@ static const struct ieee1394_device_id motu_id_table[] = {
SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite),
SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3_fw), // FireWire only.
+ SND_MOTU_DEV_ENTRY(0x000017, &snd_motu_spec_896mk3), // FireWire only.
SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only.
SND_MOTU_DEV_ENTRY(0x00001b, &snd_motu_spec_traveler_mk3),
SND_MOTU_DEV_ENTRY(0x000030, &snd_motu_spec_ultralite_mk3), // Hybrid.
SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3_hybrid), // Hybrid.
+ SND_MOTU_DEV_ENTRY(0x000037, &snd_motu_spec_896mk3), // Hybrid.
SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express),
SND_MOTU_DEV_ENTRY(0x000039, &snd_motu_spec_track16),
SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre),
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index 3b1dc98a7be0..c66be0a89ccf 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -138,6 +138,7 @@ extern const struct snd_motu_spec snd_motu_spec_8pre;
extern const struct snd_motu_spec snd_motu_spec_828mk3_fw;
extern const struct snd_motu_spec snd_motu_spec_828mk3_hybrid;
+extern const struct snd_motu_spec snd_motu_spec_896mk3;
extern const struct snd_motu_spec snd_motu_spec_traveler_mk3;
extern const struct snd_motu_spec snd_motu_spec_ultralite_mk3;
extern const struct snd_motu_spec snd_motu_spec_audio_express;
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
index 669d1e8238df..9ac8893a926f 100644
--- a/sound/firewire/oxfw/Makefile
+++ b/sound/firewire/oxfw/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \
+snd-oxfw-y := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \
oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw-scs1x.o oxfw.o
obj-$(CONFIG_SND_OXFW) += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c
index a0fe99618554..f8ac362fc73a 100644
--- a/sound/firewire/oxfw/oxfw-hwdep.c
+++ b/sound/firewire/oxfw/oxfw-hwdep.c
@@ -53,18 +53,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_table *wait)
{
struct snd_oxfw *oxfw = hwdep->private_data;
- __poll_t events;
poll_wait(file, &oxfw->hwdep_wait, wait);
- spin_lock_irq(&oxfw->lock);
+ guard(spinlock_irq)(&oxfw->lock);
if (oxfw->dev_lock_changed)
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&oxfw->lock);
-
- return events;
+ return 0;
}
static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
@@ -88,48 +84,35 @@ static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
static int hwdep_lock(struct snd_oxfw *oxfw)
{
- int err;
-
- spin_lock_irq(&oxfw->lock);
+ guard(spinlock_irq)(&oxfw->lock);
if (oxfw->dev_lock_count == 0) {
oxfw->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&oxfw->lock);
-
- return err;
}
static int hwdep_unlock(struct snd_oxfw *oxfw)
{
- int err;
-
- spin_lock_irq(&oxfw->lock);
+ guard(spinlock_irq)(&oxfw->lock);
if (oxfw->dev_lock_count == -1) {
oxfw->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&oxfw->lock);
-
- return err;
}
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_oxfw *oxfw = hwdep->private_data;
- spin_lock_irq(&oxfw->lock);
+ guard(spinlock_irq)(&oxfw->lock);
if (oxfw->dev_lock_count == -1)
oxfw->dev_lock_count = 0;
- spin_unlock_irq(&oxfw->lock);
return 0;
}
@@ -177,7 +160,7 @@ int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
if (err < 0)
goto end;
- strcpy(hwdep->name, oxfw->card->driver);
+ strscpy(hwdep->name, oxfw->card->driver);
hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
hwdep->ops = hwdep_ops;
hwdep->private_data = oxfw;
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
index 775cba3f1f02..a16bf885f918 100644
--- a/sound/firewire/oxfw/oxfw-midi.c
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -16,18 +16,16 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
if (err < 0)
return err;
- mutex_lock(&oxfw->mutex);
-
- err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
- if (err >= 0) {
- ++oxfw->substreams_count;
- err = snd_oxfw_stream_start_duplex(oxfw);
- if (err < 0)
- --oxfw->substreams_count;
+ scoped_guard(mutex, &oxfw->mutex) {
+ err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
+ if (err >= 0) {
+ ++oxfw->substreams_count;
+ err = snd_oxfw_stream_start_duplex(oxfw);
+ if (err < 0)
+ --oxfw->substreams_count;
+ }
}
- mutex_unlock(&oxfw->mutex);
-
if (err < 0)
snd_oxfw_stream_lock_release(oxfw);
@@ -43,16 +41,14 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
if (err < 0)
return err;
- mutex_lock(&oxfw->mutex);
-
- err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
- if (err >= 0) {
- ++oxfw->substreams_count;
- err = snd_oxfw_stream_start_duplex(oxfw);
+ scoped_guard(mutex, &oxfw->mutex) {
+ err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
+ if (err >= 0) {
+ ++oxfw->substreams_count;
+ err = snd_oxfw_stream_start_duplex(oxfw);
+ }
}
- mutex_unlock(&oxfw->mutex);
-
if (err < 0)
snd_oxfw_stream_lock_release(oxfw);
@@ -63,12 +59,10 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
{
struct snd_oxfw *oxfw = substream->rmidi->private_data;
- mutex_lock(&oxfw->mutex);
-
- --oxfw->substreams_count;
- snd_oxfw_stream_stop_duplex(oxfw);
-
- mutex_unlock(&oxfw->mutex);
+ scoped_guard(mutex, &oxfw->mutex) {
+ --oxfw->substreams_count;
+ snd_oxfw_stream_stop_duplex(oxfw);
+ }
snd_oxfw_stream_lock_release(oxfw);
return 0;
@@ -78,12 +72,10 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
{
struct snd_oxfw *oxfw = substream->rmidi->private_data;
- mutex_lock(&oxfw->mutex);
-
- --oxfw->substreams_count;
- snd_oxfw_stream_stop_duplex(oxfw);
-
- mutex_unlock(&oxfw->mutex);
+ scoped_guard(mutex, &oxfw->mutex) {
+ --oxfw->substreams_count;
+ snd_oxfw_stream_stop_duplex(oxfw);
+ }
snd_oxfw_stream_lock_release(oxfw);
return 0;
@@ -92,9 +84,8 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_oxfw *oxfw = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&oxfw->lock, flags);
+ guard(spinlock_irqsave)(&oxfw->lock);
if (up)
amdtp_am824_midi_trigger(&oxfw->tx_stream,
@@ -102,16 +93,13 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&oxfw->tx_stream,
substrm->number, NULL);
-
- spin_unlock_irqrestore(&oxfw->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_oxfw *oxfw = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&oxfw->lock, flags);
+ guard(spinlock_irqsave)(&oxfw->lock);
if (up)
amdtp_am824_midi_trigger(&oxfw->rx_stream,
@@ -119,8 +107,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
else
amdtp_am824_midi_trigger(&oxfw->rx_stream,
substrm->number, NULL);
-
- spin_unlock_irqrestore(&oxfw->lock, flags);
}
static void set_midi_substream_names(struct snd_oxfw *oxfw,
@@ -129,9 +115,9 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw,
struct snd_rawmidi_substream *subs;
list_for_each_entry(subs, &str->substreams, list) {
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d",
- oxfw->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ oxfw->card->shortname, subs->number + 1);
}
}
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index 5f43a0b826d2..774b8a763795 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -181,42 +181,34 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
goto err_locked;
- mutex_lock(&oxfw->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if (oxfw->substreams_count > 0 && d->events_per_period > 0) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
-
- err = limit_to_current_params(substream);
- if (err < 0) {
- mutex_unlock(&oxfw->mutex);
- goto err_locked;
- }
-
- if (frames_per_period > 0) {
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
- if (err < 0) {
- mutex_unlock(&oxfw->mutex);
+ scoped_guard(mutex, &oxfw->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if (oxfw->substreams_count > 0 && d->events_per_period > 0) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+
+ err = limit_to_current_params(substream);
+ if (err < 0)
goto err_locked;
- }
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&oxfw->mutex);
- goto err_locked;
+ if (frames_per_period > 0) {
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
}
}
}
- mutex_unlock(&oxfw->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -245,13 +237,12 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&oxfw->mutex);
+ guard(mutex)(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
rate, channels, frames_per_period,
frames_per_buffer);
if (err >= 0)
++oxfw->substreams_count;
- mutex_unlock(&oxfw->mutex);
}
return err;
@@ -268,13 +259,12 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&oxfw->mutex);
+ guard(mutex)(&oxfw->mutex);
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream,
rate, channels, frames_per_period,
frames_per_buffer);
if (err >= 0)
++oxfw->substreams_count;
- mutex_unlock(&oxfw->mutex);
}
return err;
@@ -284,30 +274,26 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_oxfw *oxfw = substream->private_data;
- mutex_lock(&oxfw->mutex);
+ guard(mutex)(&oxfw->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--oxfw->substreams_count;
snd_oxfw_stream_stop_duplex(oxfw);
- mutex_unlock(&oxfw->mutex);
-
return 0;
}
static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
{
struct snd_oxfw *oxfw = substream->private_data;
- mutex_lock(&oxfw->mutex);
+ guard(mutex)(&oxfw->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--oxfw->substreams_count;
snd_oxfw_stream_stop_duplex(oxfw);
- mutex_unlock(&oxfw->mutex);
-
return 0;
}
@@ -316,30 +302,28 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
struct snd_oxfw *oxfw = substream->private_data;
int err;
- mutex_lock(&oxfw->mutex);
- err = snd_oxfw_stream_start_duplex(oxfw);
- mutex_unlock(&oxfw->mutex);
- if (err < 0)
- goto end;
+ scoped_guard(mutex, &oxfw->mutex) {
+ err = snd_oxfw_stream_start_duplex(oxfw);
+ if (err < 0)
+ return err;
+ }
amdtp_stream_pcm_prepare(&oxfw->tx_stream);
-end:
- return err;
+ return 0;
}
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_oxfw *oxfw = substream->private_data;
int err;
- mutex_lock(&oxfw->mutex);
- err = snd_oxfw_stream_start_duplex(oxfw);
- mutex_unlock(&oxfw->mutex);
- if (err < 0)
- goto end;
+ scoped_guard(mutex, &oxfw->mutex) {
+ err = snd_oxfw_stream_start_duplex(oxfw);
+ if (err < 0)
+ return err;
+ }
amdtp_stream_pcm_prepare(&oxfw->rx_stream);
-end:
- return err;
+ return 0;
}
static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -440,7 +424,8 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
return err;
pcm->private_data = oxfw;
- strcpy(pcm->name, oxfw->card->shortname);
+ pcm->nonatomic = true;
+ strscpy(pcm->name, oxfw->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
if (cap > 0)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index f4a702def397..5e36d7153a7b 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -177,6 +177,8 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
flags |= CIP_JUMBO_PAYLOAD;
if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS)
flags |= CIP_WRONG_DBS;
+ if (oxfw->quirks & SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS)
+ flags |= CIP_DBC_IS_END_EVENT | CIP_DBC_IS_PAYLOAD_QUADLETS;
} else {
conn = &oxfw->in_conn;
c_dir = CMP_INPUT;
@@ -486,26 +488,57 @@ int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
enum avc_general_plug_dir dir,
struct snd_oxfw_stream_formation *formation)
{
- u8 *format;
- unsigned int len;
int err;
- len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
- format = kmalloc(len, GFP_KERNEL);
- if (format == NULL)
- return -ENOMEM;
+ if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
+ u8 *format;
+ unsigned int len;
- err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
- if (err < 0)
- goto end;
- if (len < 3) {
- err = -EIO;
- goto end;
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ format = kmalloc(len, GFP_KERNEL);
+ if (format == NULL)
+ return -ENOMEM;
+
+ err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
+ if (err >= 0) {
+ if (len < 3)
+ err = -EIO;
+ else
+ err = snd_oxfw_stream_parse_format(format, formation);
+ }
+
+ kfree(format);
+ } else {
+ // Miglia Harmony Audio does not support Extended Stream Format Information
+ // command. Use the duplicated hard-coded format, instead.
+ unsigned int rate;
+ u8 *const *formats;
+ int i;
+
+ err = avc_general_get_sig_fmt(oxfw->unit, &rate, dir, 0);
+ if (err < 0)
+ return err;
+
+ if (dir == AVC_GENERAL_PLUG_DIR_IN)
+ formats = oxfw->rx_stream_formats;
+ else
+ formats = oxfw->tx_stream_formats;
+
+ for (i = 0; (i < SND_OXFW_STREAM_FORMAT_ENTRIES); ++i) {
+ if (!formats[i])
+ continue;
+
+ err = snd_oxfw_stream_parse_format(formats[i], formation);
+ if (err < 0)
+ continue;
+
+ if (formation->rate == rate)
+ break;
+ }
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
+ return -EIO;
}
- err = snd_oxfw_stream_parse_format(format, formation);
-end:
- kfree(format);
return err;
}
@@ -515,7 +548,7 @@ end:
* in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
* Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
*/
-int snd_oxfw_stream_parse_format(u8 *format,
+int snd_oxfw_stream_parse_format(const u8 *format,
struct snd_oxfw_stream_formation *formation)
{
unsigned int i, e, channels, type;
@@ -600,14 +633,33 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
unsigned int i, eid;
int err;
- /* get format at current sampling rate */
- err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
- if (err < 0) {
- dev_err(&oxfw->unit->device,
- "fail to get current stream format for isoc %s plug %d:%d\n",
- (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
- pid, err);
- goto end;
+ // get format at current sampling rate.
+ if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
+ err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get current stream format for isoc %s plug %d:%d\n",
+ (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
+ pid, err);
+ goto end;
+ }
+ } else {
+ // Miglia Harmony Audio does not support Extended Stream Format Information
+ // command. Use the hard-coded format, instead.
+ buf[0] = 0x90;
+ buf[1] = 0x40;
+ buf[2] = avc_stream_rate_table[0];
+ buf[3] = 0x00;
+ buf[4] = 0x01;
+
+ if (dir == AVC_GENERAL_PLUG_DIR_IN)
+ buf[5] = 0x08;
+ else
+ buf[5] = 0x02;
+
+ buf[6] = 0x06;
+
+ *len = 7;
}
/* parse and set stream format */
@@ -814,33 +866,24 @@ void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
{
- int err;
-
- spin_lock_irq(&oxfw->lock);
+ guard(spinlock_irq)(&oxfw->lock);
/* user land lock this */
- if (oxfw->dev_lock_count < 0) {
- err = -EBUSY;
- goto end;
- }
+ if (oxfw->dev_lock_count < 0)
+ return -EBUSY;
/* this is the first time */
if (oxfw->dev_lock_count++ == 0)
snd_oxfw_stream_lock_changed(oxfw);
- err = 0;
-end:
- spin_unlock_irq(&oxfw->lock);
- return err;
+ return 0;
}
void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
{
- spin_lock_irq(&oxfw->lock);
+ guard(spinlock_irq)(&oxfw->lock);
if (WARN_ON(oxfw->dev_lock_count <= 0))
- goto end;
+ return;
if (--oxfw->dev_lock_count == 0)
snd_oxfw_stream_lock_changed(oxfw);
-end:
- spin_unlock_irq(&oxfw->lock);
}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index b496f87841ae..5039bd79b18e 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -21,6 +21,7 @@
#define VENDOR_TASCAM 0x00022e
#define OUI_STANTON 0x001260
#define OUI_APOGEE 0x0003db
+#define OUI_OXFORD 0x0030e0
#define MODEL_SATELLITE 0x00200f
#define MODEL_SCS1M 0x001000
@@ -32,7 +33,7 @@
MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-firewire-speakers");
MODULE_ALIAS("snd-scs1x");
@@ -44,7 +45,7 @@ struct compat_info {
static bool detect_loud_models(struct fw_unit *unit)
{
- const char *const models[] = {
+ static const char *const models[] = {
"Onyxi",
"Onyx-i",
"Onyx 1640i",
@@ -104,15 +105,15 @@ static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *ent
m = model;
}
- strcpy(oxfw->card->driver, d);
- strcpy(oxfw->card->mixername, m);
- strcpy(oxfw->card->shortname, m);
+ strscpy(oxfw->card->driver, d);
+ strscpy(oxfw->card->mixername, m);
+ strscpy(oxfw->card->shortname, m);
- snprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
- "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
- v, m, firmware >> 20, firmware & 0xffff,
- fw_dev->config_rom[3], fw_dev->config_rom[4],
- dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
+ scnprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
+ "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
+ v, m, firmware >> 20, firmware & 0xffff,
+ fw_dev->config_rom[3], fw_dev->config_rom[4],
+ dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
end:
return err;
}
@@ -232,6 +233,11 @@ static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
if (err < 0)
goto error;
+ if (entry->vendor_id == OUI_OXFORD && entry->model_id == 0x00f970) {
+ oxfw->quirks |= SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED |
+ SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS;
+ }
+
err = snd_oxfw_stream_discover(oxfw);
if (err < 0)
goto error;
@@ -277,9 +283,8 @@ static void oxfw_bus_reset(struct fw_unit *unit)
fcp_bus_reset(oxfw->unit);
if (oxfw->has_output || oxfw->has_input) {
- mutex_lock(&oxfw->mutex);
+ guard(mutex)(&oxfw->mutex);
snd_oxfw_stream_update_duplex(oxfw);
- mutex_unlock(&oxfw->mutex);
}
if (oxfw->quirks & SND_OXFW_QUIRK_SCS_TRANSACTION)
@@ -330,6 +335,9 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
//
OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave),
OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers),
+ // Miglia HarmonyAudio (HA02). The numeric vendor ID is ASIC vendor and the model ID is the
+ // default value of ASIC.
+ OXFW_DEV_ENTRY(OUI_OXFORD, 0x00f970, NULL),
// Behringer,F-Control Audio 202. The value of SYT field is not reliable at all.
OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL),
// Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff.
@@ -337,7 +345,6 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
// Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is
// installed to avoid the postpone, the value of SYT field is always 0xffff.
OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL),
- // Miglia HarmonyAudio. Not yet identified.
//
// OXFW971 devices:
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index d728e451a25c..39ea9a6dde33 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -52,6 +52,11 @@ enum snd_oxfw_quirk {
// performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO
// are ignored, thus driver should transfer packets with timestamp.
SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20,
+ // Miglia Harmony Audio does not support AV/C Stream Format Information command.
+ SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED = 0x40,
+ // Miglia Harmony Audio transmits CIP in which the value of dbc field expresses the number
+ // of accumulated payload quadlets including the packet.
+ SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS = 0x80,
};
/* This is an arbitrary number for convinience. */
@@ -136,7 +141,7 @@ struct snd_oxfw_stream_formation {
unsigned int pcm;
unsigned int midi;
};
-int snd_oxfw_stream_parse_format(u8 *format,
+int snd_oxfw_stream_parse_format(const u8 *format,
struct snd_oxfw_stream_formation *formation);
int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
enum avc_general_plug_dir dir,
diff --git a/sound/firewire/tascam/Makefile b/sound/firewire/tascam/Makefile
index a1d21f244d64..43fed14cf172 100644
--- a/sound/firewire/tascam/Makefile
+++ b/sound/firewire/tascam/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-firewire-tascam-objs := tascam-proc.o amdtp-tascam.o tascam-stream.o \
+snd-firewire-tascam-y := tascam-proc.o amdtp-tascam.o tascam-stream.o \
tascam-pcm.o tascam-hwdep.o tascam-transaction.o \
tascam-midi.o tascam.o
obj-$(CONFIG_SND_FIREWIRE_TASCAM) += snd-firewire-tascam.o
diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c
index 0b42d6559008..59c339d9b5fb 100644
--- a/sound/firewire/tascam/amdtp-tascam.c
+++ b/sound/firewire/tascam/amdtp-tascam.c
@@ -157,15 +157,14 @@ static void read_status_messages(struct amdtp_stream *s,
if ((before ^ after) & mask) {
struct snd_firewire_tascam_change *entry =
&tscm->queue[tscm->push_pos];
- unsigned long flag;
- spin_lock_irqsave(&tscm->lock, flag);
- entry->index = index;
- entry->before = before;
- entry->after = after;
- if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
- tscm->push_pos = 0;
- spin_unlock_irqrestore(&tscm->lock, flag);
+ scoped_guard(spinlock_irqsave, &tscm->lock) {
+ entry->index = index;
+ entry->before = before;
+ entry->after = after;
+ if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
+ tscm->push_pos = 0;
+ }
wake_up(&tscm->hwdep_wait);
}
@@ -238,7 +237,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
err = amdtp_stream_init(s, unit, dir, flags, fmt,
process_ctx_payloads, sizeof(struct amdtp_tscm));
if (err < 0)
- return 0;
+ return err;
if (dir == AMDTP_OUT_STREAM) {
// Use fixed value for FDF field.
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 74eed9505665..867b4ea1096e 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -130,18 +130,14 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_table *wait)
{
struct snd_tscm *tscm = hwdep->private_data;
- __poll_t events;
poll_wait(file, &tscm->hwdep_wait, wait);
- spin_lock_irq(&tscm->lock);
+ guard(spinlock_irq)(&tscm->lock);
if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
- events = EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
else
- events = 0;
- spin_unlock_irq(&tscm->lock);
-
- return events;
+ return 0;
}
static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg)
@@ -165,38 +161,26 @@ static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg)
static int hwdep_lock(struct snd_tscm *tscm)
{
- int err;
-
- spin_lock_irq(&tscm->lock);
+ guard(spinlock_irq)(&tscm->lock);
if (tscm->dev_lock_count == 0) {
tscm->dev_lock_count = -1;
- err = 0;
+ return 0;
} else {
- err = -EBUSY;
+ return -EBUSY;
}
-
- spin_unlock_irq(&tscm->lock);
-
- return err;
}
static int hwdep_unlock(struct snd_tscm *tscm)
{
- int err;
-
- spin_lock_irq(&tscm->lock);
+ guard(spinlock_irq)(&tscm->lock);
if (tscm->dev_lock_count == -1) {
tscm->dev_lock_count = 0;
- err = 0;
+ return 0;
} else {
- err = -EBADFD;
+ return -EBADFD;
}
-
- spin_unlock_irq(&tscm->lock);
-
- return err;
}
static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg)
@@ -211,10 +195,9 @@ static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
{
struct snd_tscm *tscm = hwdep->private_data;
- spin_lock_irq(&tscm->lock);
+ guard(spinlock_irq)(&tscm->lock);
if (tscm->dev_lock_count == -1)
tscm->dev_lock_count = 0;
- spin_unlock_irq(&tscm->lock);
return 0;
}
@@ -265,7 +248,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
if (err < 0)
return err;
- strcpy(hwdep->name, "Tascam");
+ strscpy(hwdep->name, "Tascam");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM;
hwdep->ops = ops;
hwdep->private_data = tscm;
diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c
index 02eed2dce435..1bf9d7b3da33 100644
--- a/sound/firewire/tascam/tascam-midi.c
+++ b/sound/firewire/tascam/tascam-midi.c
@@ -43,30 +43,24 @@ static void midi_playback_drain(struct snd_rawmidi_substream *substream)
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_tscm *tscm = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&tscm->lock, flags);
+ guard(spinlock_irqsave)(&tscm->lock);
if (up)
tscm->tx_midi_substreams[substrm->number] = substrm;
else
tscm->tx_midi_substreams[substrm->number] = NULL;
-
- spin_unlock_irqrestore(&tscm->lock, flags);
}
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
{
struct snd_tscm *tscm = substrm->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&tscm->lock, flags);
+ guard(spinlock_irqsave)(&tscm->lock);
if (up)
snd_fw_async_midi_port_run(&tscm->out_ports[substrm->number],
substrm);
-
- spin_unlock_irqrestore(&tscm->lock, flags);
}
int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
@@ -108,9 +102,9 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
/* TODO: support virtual MIDI ports. */
if (subs->number < tscm->spec->midi_capture_ports) {
/* Hardware MIDI ports. */
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d",
- tscm->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ tscm->card->shortname, subs->number + 1);
}
}
@@ -123,9 +117,9 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
list_for_each_entry(subs, &stream->substreams, list) {
if (subs->number < tscm->spec->midi_playback_ports) {
/* Hardware MIDI ports only. */
- snprintf(subs->name, sizeof(subs->name),
- "%s MIDI %d",
- tscm->card->shortname, subs->number + 1);
+ scnprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ tscm->card->shortname, subs->number + 1);
}
}
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index f6da571707ac..d885fef0c8ca 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -59,43 +59,35 @@ static int pcm_open(struct snd_pcm_substream *substream)
if (err < 0)
goto err_locked;
- mutex_lock(&tscm->mutex);
-
- // When source of clock is not internal or any stream is reserved for
- // transmission of PCM frames, the available sampling rate is limited
- // at current one.
- if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) {
- unsigned int frames_per_period = d->events_per_period;
- unsigned int frames_per_buffer = d->events_per_buffer;
- unsigned int rate;
-
- err = snd_tscm_stream_get_rate(tscm, &rate);
- if (err < 0) {
- mutex_unlock(&tscm->mutex);
- goto err_locked;
- }
- substream->runtime->hw.rate_min = rate;
- substream->runtime->hw.rate_max = rate;
-
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- frames_per_period, frames_per_period);
- if (err < 0) {
- mutex_unlock(&tscm->mutex);
- goto err_locked;
- }
-
- err = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
- frames_per_buffer, frames_per_buffer);
- if (err < 0) {
- mutex_unlock(&tscm->mutex);
- goto err_locked;
+ scoped_guard(mutex, &tscm->mutex) {
+ // When source of clock is not internal or any stream is reserved for
+ // transmission of PCM frames, the available sampling rate is limited
+ // at current one.
+ if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) {
+ unsigned int frames_per_period = d->events_per_period;
+ unsigned int frames_per_buffer = d->events_per_buffer;
+ unsigned int rate;
+
+ err = snd_tscm_stream_get_rate(tscm, &rate);
+ if (err < 0)
+ goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ frames_per_period, frames_per_period);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ frames_per_buffer, frames_per_buffer);
+ if (err < 0)
+ goto err_locked;
}
}
- mutex_unlock(&tscm->mutex);
-
snd_pcm_set_sync(substream);
return 0;
@@ -124,12 +116,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int frames_per_period = params_period_size(hw_params);
unsigned int frames_per_buffer = params_buffer_size(hw_params);
- mutex_lock(&tscm->mutex);
+ guard(mutex)(&tscm->mutex);
err = snd_tscm_stream_reserve_duplex(tscm, rate,
frames_per_period, frames_per_buffer);
if (err >= 0)
++tscm->substreams_counter;
- mutex_unlock(&tscm->mutex);
}
return err;
@@ -139,15 +130,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_tscm *tscm = substream->private_data;
- mutex_lock(&tscm->mutex);
+ guard(mutex)(&tscm->mutex);
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
--tscm->substreams_counter;
snd_tscm_stream_stop_duplex(tscm);
- mutex_unlock(&tscm->mutex);
-
return 0;
}
@@ -157,14 +146,12 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- mutex_lock(&tscm->mutex);
+ guard(mutex)(&tscm->mutex);
err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
if (err >= 0)
amdtp_stream_pcm_prepare(&tscm->tx_stream);
- mutex_unlock(&tscm->mutex);
-
return err;
}
@@ -174,14 +161,12 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- mutex_lock(&tscm->mutex);
+ guard(mutex)(&tscm->mutex);
err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
if (err >= 0)
amdtp_stream_pcm_prepare(&tscm->rx_stream);
- mutex_unlock(&tscm->mutex);
-
return err;
}
@@ -279,6 +264,7 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
return err;
pcm->private_data = tscm;
+ pcm->nonatomic = true;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", tscm->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
index dfe783d01d7d..4ecd151a46c1 100644
--- a/sound/firewire/tascam/tascam-stream.c
+++ b/sound/firewire/tascam/tascam-stream.c
@@ -282,20 +282,22 @@ static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
struct amdtp_stream *stream)
{
struct fw_iso_resources *resources;
+ int speed;
int err;
- if (stream == &tscm->tx_stream)
+ if (stream == &tscm->tx_stream) {
resources = &tscm->tx_resources;
- else
+ speed = fw_parent_device(tscm->unit)->max_speed;
+ } else {
resources = &tscm->rx_resources;
+ speed = SCODE_400;
+ }
err = amdtp_tscm_set_parameters(stream, rate);
if (err < 0)
return err;
- return fw_iso_resources_allocate(resources,
- amdtp_stream_get_max_payload(stream),
- fw_parent_device(tscm->unit)->max_speed);
+ return fw_iso_resources_allocate(resources, amdtp_stream_get_max_payload(stream), speed);
}
static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s)
@@ -455,7 +457,6 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
}
if (!amdtp_stream_running(&tscm->rx_stream)) {
- int spd = fw_parent_device(tscm->unit)->max_speed;
unsigned int tx_init_skip_cycles;
err = set_stream_formats(tscm, rate);
@@ -466,13 +467,13 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
if (err < 0)
goto error;
- err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,
- tscm->rx_resources.channel, spd);
+ err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream, tscm->rx_resources.channel,
+ fw_parent_device(tscm->unit)->max_speed);
if (err < 0)
goto error;
- err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,
- tscm->tx_resources.channel, spd);
+ err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream, tscm->tx_resources.channel,
+ SCODE_400);
if (err < 0)
goto error;
@@ -527,33 +528,24 @@ void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
int snd_tscm_stream_lock_try(struct snd_tscm *tscm)
{
- int err;
-
- spin_lock_irq(&tscm->lock);
+ guard(spinlock_irq)(&tscm->lock);
/* user land lock this */
- if (tscm->dev_lock_count < 0) {
- err = -EBUSY;
- goto end;
- }
+ if (tscm->dev_lock_count < 0)
+ return -EBUSY;
/* this is the first time */
if (tscm->dev_lock_count++ == 0)
snd_tscm_stream_lock_changed(tscm);
- err = 0;
-end:
- spin_unlock_irq(&tscm->lock);
- return err;
+ return 0;
}
void snd_tscm_stream_lock_release(struct snd_tscm *tscm)
{
- spin_lock_irq(&tscm->lock);
+ guard(spinlock_irq)(&tscm->lock);
if (WARN_ON(tscm->dev_lock_count <= 0))
- goto end;
+ return;
if (--tscm->dev_lock_count == 0)
snd_tscm_stream_lock_changed(tscm);
-end:
- spin_unlock_irq(&tscm->lock);
}
diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c
index eb58d3fcf087..f4092df8650c 100644
--- a/sound/firewire/tascam/tascam.c
+++ b/sound/firewire/tascam/tascam.c
@@ -9,7 +9,7 @@
MODULE_DESCRIPTION("TASCAM FireWire series Driver");
MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
static const struct snd_tscm_spec model_specs[] = {
{
@@ -73,9 +73,9 @@ static int identify_model(struct snd_tscm *tscm)
if (tscm->spec == NULL)
return -ENODEV;
- strcpy(tscm->card->driver, "FW-TASCAM");
- strcpy(tscm->card->shortname, model);
- strcpy(tscm->card->mixername, model);
+ strscpy(tscm->card->driver, "FW-TASCAM");
+ strscpy(tscm->card->shortname, model);
+ strscpy(tscm->card->mixername, model);
snprintf(tscm->card->longname, sizeof(tscm->card->longname),
"TASCAM %s, GUID %08x%08x at %s, S%d", model,
fw_dev->config_rom[3], fw_dev->config_rom[4],
@@ -158,9 +158,8 @@ static void snd_tscm_update(struct fw_unit *unit)
snd_tscm_transaction_reregister(tscm);
- mutex_lock(&tscm->mutex);
+ guard(mutex)(&tscm->mutex);
snd_tscm_stream_update_duplex(tscm);
- mutex_unlock(&tscm->mutex);
}
static void snd_tscm_remove(struct fw_unit *unit)
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index 741179ccbd4e..7797f44b3d0c 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -1,65 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
-config SND_HDA_CORE
- tristate
- select REGMAP
+menu "HD-Audio"
-config SND_HDA_DSP_LOADER
- bool
+source "sound/hda/common/Kconfig"
+source "sound/hda/controllers/Kconfig"
+source "sound/hda/codecs/Kconfig"
+source "sound/hda/core/Kconfig"
-config SND_HDA_ALIGNED_MMIO
- bool
-
-config SND_HDA_COMPONENT
- bool
-
-config SND_HDA_I915
- bool
- select SND_HDA_COMPONENT
-
-config SND_HDA_EXT_CORE
- tristate
- select SND_HDA_CORE
-
-config SND_HDA_PREALLOC_SIZE
- int "Pre-allocated buffer size for HD-audio driver" if !SND_DMA_SGBUF
- range 0 32768
- default 0 if SND_DMA_SGBUF
- default 64 if !SND_DMA_SGBUF
- help
- Specifies the default pre-allocated buffer-size in kB for the
- HD-audio driver. A larger buffer (e.g. 2048) is preferred
- for systems using PulseAudio. The default 64 is chosen just
- for compatibility reasons.
- On x86 systems, the default is zero as we need no preallocation.
-
- Note that the pre-allocation size can be changed dynamically
- via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
-
-config SND_INTEL_NHLT
- bool
- # this config should be selected only for Intel ACPI platforms.
- # A fallback is provided so that the code compiles in all cases.
-
-config SND_INTEL_DSP_CONFIG
- tristate
- select SND_INTEL_NHLT if ACPI
- select SND_INTEL_SOUNDWIRE_ACPI if ACPI
- # this config should be selected only for Intel DSP platforms.
- # A fallback is provided so that the code compiles in all cases.
-
-config SND_INTEL_SOUNDWIRE_ACPI
- tristate
-
-config SND_INTEL_BYT_PREFER_SOF
- bool "Prefer SOF driver over SST on BY/CHT platforms"
- depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL
- default n
- help
- The kernel has 2 drivers for the Low Power Engine audio-block on
- Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF
- driver. If both drivers are enabled then the kernel will default
- to using the old SST driver, unless told otherwise through the
- snd_intel_dspcfg.dsp_driver module-parameter.
-
- Set this option to Y to make the kernel default to the new SOF
- driver instead.
+endmenu
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index 78f487a635f8..d9a6def582ef 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,22 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
-snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
- hdac_regmap.o hdac_controller.o hdac_stream.o array.o hdmi_chmap.o
-
-snd-hda-core-objs += trace.o
-CFLAGS_trace.o := -I$(src)
-
-# for sync with i915 gfx driver
-snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o
-snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o
-
-obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
-
-#extended hda
-obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
-
-snd-intel-dspcfg-objs := intel-dsp-config.o
-snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o
-obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o
-
-snd-intel-sdw-acpi-objs := intel-sdw-acpi.o
-obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o
+obj-y += core/
+obj-$(CONFIG_SND_HDA) += common/
+obj-$(CONFIG_SND_HDA) += codecs/
+# this must be the last entry after codec drivers;
+# otherwise the codec drivers won't be hooked before the PCI probe
+# when built in kernel
+obj-$(CONFIG_SND_HDA) += controllers/
diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
new file mode 100644
index 000000000000..addbc9424336
--- /dev/null
+++ b/sound/hda/codecs/Kconfig
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: GPL-2.0-only
+if SND_HDA
+
+config SND_HDA_GENERIC_LEDS
+ bool
+
+config SND_HDA_CODEC_ANALOG
+ tristate "Build Analog Devices HD-audio codec support"
+ select SND_HDA_GENERIC
+ help
+ Say Y or M here to include Analog Devices HD-audio codec support in
+ snd-hda-intel driver, such as AD1986A.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m
+
+config SND_HDA_CODEC_SIGMATEL
+ tristate "Build IDT/Sigmatel HD-audio codec support"
+ select SND_HDA_GENERIC
+ select SND_HDA_GENERIC_LEDS
+ help
+ Say Y or M here to include IDT (Sigmatel) HD-audio codec support in
+ snd-hda-intel driver, such as STAC9200.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m
+
+config SND_HDA_CODEC_VIA
+ tristate "Build VIA HD-audio codec support"
+ select SND_HDA_GENERIC
+ help
+ Say Y or M here to include VIA HD-audio codec support in
+ snd-hda-intel driver, such as VT1708.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
+
+config SND_HDA_CODEC_CONEXANT
+ tristate "Build Conexant HD-audio codec support"
+ select SND_HDA_GENERIC
+ select SND_HDA_GENERIC_LEDS
+ help
+ Say Y or M here to include Conexant HD-audio codec support in
+ snd-hda-intel driver, such as CX20549.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
+
+config SND_HDA_CODEC_SENARYTECH
+ tristate "Build Senarytech HD-audio codec support"
+ select SND_HDA_GENERIC
+ select SND_HDA_GENERIC_LEDS
+ help
+ Say Y or M here to include Senarytech HD-audio codec support in
+ snd-hda-intel driver, such as SN6186.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_SENARYTECH=m
+
+config SND_HDA_CODEC_CA0110
+ tristate "Build Creative CA0110-IBG codec support"
+ select SND_HDA_GENERIC
+ help
+ Say Y or M here to include Creative CA0110-IBG codec support in
+ snd-hda-intel driver, found on some Creative X-Fi cards.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m
+
+config SND_HDA_CODEC_CA0132
+ tristate "Build Creative CA0132 codec support"
+ help
+ Say Y or M here to include Creative CA0132 codec support in
+ snd-hda-intel driver.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m
+
+config SND_HDA_CODEC_CA0132_DSP
+ bool "Support new DSP code for CA0132 codec"
+ depends on SND_HDA_CODEC_CA0132
+ default y
+ select SND_HDA_DSP_LOADER
+ select FW_LOADER
+ help
+ Say Y here to enable the DSP for Creative CA0132 for extended
+ features like equalizer or echo cancellation.
+
+ Note that this option requires the external firmware file
+ (ctefx.bin).
+
+config SND_HDA_CODEC_CMEDIA
+ tristate "Build C-Media HD-audio codec support"
+ select SND_HDA_GENERIC
+ help
+ Say Y or M here to include C-Media HD-audio codec support in
+ snd-hda-intel driver, such as CMI9880.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
+
+config SND_HDA_CODEC_CM9825
+ tristate "Build C-Media CM9825 HD-audio codec support"
+ select SND_HDA_GENERIC
+ help
+ Say Y or M here to include C-Media CM9825 HD-audio codec support in
+ snd-hda-intel driver
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CM9825=m
+
+config SND_HDA_CODEC_SI3054
+ tristate "Build Silicon Labs 3054 HD-modem codec support"
+ help
+ Say Y or M here to include Silicon Labs 3054 HD-modem codec
+ (and compatibles) support in snd-hda-intel driver.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m
+
+config SND_HDA_GENERIC
+ tristate "Enable generic HD-audio codec parser"
+ select SND_CTL_LED if SND_HDA_GENERIC_LEDS
+ select LEDS_CLASS if SND_HDA_GENERIC_LEDS
+ help
+ Say Y or M here to enable the generic HD-audio codec parser
+ in snd-hda-intel driver.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_GENERIC=m
+
+source "sound/hda/codecs/realtek/Kconfig"
+source "sound/hda/codecs/cirrus/Kconfig"
+source "sound/hda/codecs/hdmi/Kconfig"
+source "sound/hda/codecs/side-codecs/Kconfig"
+
+endif # SND_HDA
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
new file mode 100644
index 000000000000..e7f03e281999
--- /dev/null
+++ b/sound/hda/codecs/Makefile
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../common
+
+snd-hda-codec-generic-y := generic.o
+snd-hda-codec-cmedia-y := cmedia.o
+snd-hda-codec-cm9825-y := cm9825.o
+snd-hda-codec-analog-y := analog.o
+snd-hda-codec-ca0110-y := ca0110.o
+snd-hda-codec-ca0132-y := ca0132.o
+snd-hda-codec-cmedia-y := cmedia.o
+snd-hda-codec-conexant-y := conexant.o
+snd-hda-codec-idt-y := sigmatel.o
+snd-hda-codec-senarytech-y := senarytech.o
+snd-hda-codec-si3054-y := si3054.o
+snd-hda-codec-via-y := via.o
+
+obj-y += cirrus/
+obj-y += hdmi/
+obj-y += realtek/
+obj-y += side-codecs/
+
+# codec drivers
+obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
+obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
+obj-$(CONFIG_SND_HDA_CODEC_CM9825) += snd-hda-codec-cm9825.o
+obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
+obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
+obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
+obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
+obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
+obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
+obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
diff --git a/sound/pci/hda/patch_analog.c b/sound/hda/codecs/analog.c
index 8afe6000f7da..357ad5a6c0db 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/hda/codecs/analog.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ * HD audio codec driver for AD1882, AD1884, AD1981HD, AD1983, AD1984,
* AD1986A, AD1988
*
* Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
@@ -16,11 +16,20 @@
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
+enum {
+ MODEL_AD1882,
+ MODEL_AD1884,
+ MODEL_AD1981,
+ MODEL_AD1983,
+ MODEL_AD1986A,
+ MODEL_AD1988,
+};
struct ad198x_spec {
struct hda_gen_spec gen;
+ int model;
/* for auto parser */
int smux_paths[4];
@@ -72,7 +81,6 @@ static int create_beep_ctls(struct hda_codec *codec)
#define create_beep_ctls(codec) 0
#endif
-#ifdef CONFIG_PM
static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
hda_nid_t hp)
{
@@ -112,13 +120,12 @@ static void ad198x_power_eapd(struct hda_codec *codec)
}
}
-static int ad198x_suspend(struct hda_codec *codec)
+static int ad_codec_suspend(struct hda_codec *codec)
{
snd_hda_shutup_pins(codec);
ad198x_power_eapd(codec);
return 0;
}
-#endif
/* follow EAPD via vmaster hook */
static void ad_vmaster_eapd_hook(void *private_data, int enabled)
@@ -139,7 +146,7 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled)
* Automatic parse of I/O pins from the BIOS configuration
*/
-static int ad198x_auto_build_controls(struct hda_codec *codec)
+static int ad_codec_build_controls(struct hda_codec *codec)
{
int err;
@@ -152,19 +159,6 @@ static int ad198x_auto_build_controls(struct hda_codec *codec)
return 0;
}
-static const struct hda_codec_ops ad198x_auto_patch_ops = {
- .build_controls = ad198x_auto_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = snd_hda_gen_init,
- .free = snd_hda_gen_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .check_power_status = snd_hda_gen_check_power_status,
- .suspend = ad198x_suspend,
-#endif
-};
-
-
static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
{
struct ad198x_spec *spec = codec->spec;
@@ -202,7 +196,6 @@ static int alloc_ad_spec(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
snd_hda_gen_spec_init(&spec->gen);
- codec->patch_ops = ad198x_auto_patch_ops;
return 0;
}
@@ -349,7 +342,7 @@ static const struct hda_fixup ad1986a_fixups[] = {
},
};
-static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
+static const struct hda_quirk ad1986a_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),
SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
@@ -379,10 +372,10 @@ static const struct hda_model_fixup ad1986a_fixup_models[] = {
/*
*/
-static int patch_ad1986a(struct hda_codec *codec)
+static int ad1986a_probe(struct hda_codec *codec)
{
int err;
- struct ad198x_spec *spec;
+ struct ad198x_spec *spec = codec->spec;
static const hda_nid_t preferred_pairs[] = {
0x1a, 0x03,
0x1b, 0x03,
@@ -392,11 +385,6 @@ static int patch_ad1986a(struct hda_codec *codec)
0
};
- err = alloc_ad_spec(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
-
/* AD1986A has the inverted EAPD implementation */
codec->inv_eapd = 1;
@@ -422,10 +410,8 @@ static int patch_ad1986a(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = ad198x_parse_auto_config(codec, false);
- if (err < 0) {
- snd_hda_gen_free(codec);
+ if (err < 0)
return err;
- }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -511,18 +497,13 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
return 0;
}
-static int patch_ad1983(struct hda_codec *codec)
+static int ad1983_probe(struct hda_codec *codec)
{
static const hda_nid_t conn_0c[] = { 0x08 };
static const hda_nid_t conn_0d[] = { 0x09 };
- struct ad198x_spec *spec;
+ struct ad198x_spec *spec = codec->spec;
int err;
- err = alloc_ad_spec(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
-
spec->gen.mixer_nid = 0x0e;
spec->gen.beep_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
@@ -533,15 +514,11 @@ static int patch_ad1983(struct hda_codec *codec)
err = ad198x_parse_auto_config(codec, false);
if (err < 0)
- goto error;
+ return err;
err = ad1983_add_spdif_mux_ctl(codec);
if (err < 0)
- goto error;
+ return err;
return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
}
@@ -592,7 +569,7 @@ static const struct hda_fixup ad1981_fixups[] = {
},
};
-static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
+static const struct hda_quirk ad1981_fixup_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
@@ -601,16 +578,11 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
{}
};
-static int patch_ad1981(struct hda_codec *codec)
+static int ad1981_probe(struct hda_codec *codec)
{
- struct ad198x_spec *spec;
+ struct ad198x_spec *spec = codec->spec;
int err;
- err = alloc_ad_spec(codec);
- if (err < 0)
- return -ENOMEM;
- spec = codec->spec;
-
spec->gen.mixer_nid = 0x0e;
spec->gen.beep_nid = 0x10;
set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
@@ -620,18 +592,14 @@ static int patch_ad1981(struct hda_codec *codec)
err = ad198x_parse_auto_config(codec, false);
if (err < 0)
- goto error;
+ return err;
err = ad1983_add_spdif_mux_ctl(codec);
if (err < 0)
- goto error;
+ return err;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
}
@@ -759,7 +727,7 @@ static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
if (spec->cur_smux == val)
return 0;
- mutex_lock(&codec->control_mutex);
+ guard(mutex)(&codec->control_mutex);
path = snd_hda_get_path_from_idx(codec,
spec->smux_paths[spec->cur_smux]);
if (path)
@@ -768,7 +736,6 @@ static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
if (path)
snd_hda_activate_path(codec, path, true, true);
spec->cur_smux = val;
- mutex_unlock(&codec->control_mutex);
return 1;
}
@@ -780,7 +747,7 @@ static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
.put = ad1988_auto_smux_enum_put,
};
-static int ad1988_auto_init(struct hda_codec *codec)
+static int ad_codec_init(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
int i, err;
@@ -788,6 +755,8 @@ static int ad1988_auto_init(struct hda_codec *codec)
err = snd_hda_gen_init(codec);
if (err < 0)
return err;
+ if (spec->model != MODEL_AD1988)
+ return 0;
if (!spec->gen.autocfg.dig_outs)
return 0;
@@ -858,8 +827,6 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
return -ENOMEM;
- codec->patch_ops.init = ad1988_auto_init;
-
return 0;
}
@@ -893,16 +860,11 @@ static const struct hda_model_fixup ad1988_fixup_models[] = {
{}
};
-static int patch_ad1988(struct hda_codec *codec)
+static int ad1988_probe(struct hda_codec *codec)
{
- struct ad198x_spec *spec;
+ struct ad198x_spec *spec = codec->spec;
int err;
- err = alloc_ad_spec(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
-
spec->gen.mixer_nid = 0x20;
spec->gen.mixer_merge_nid = 0x21;
spec->gen.beep_nid = 0x10;
@@ -913,18 +875,14 @@ static int patch_ad1988(struct hda_codec *codec)
err = ad198x_parse_auto_config(codec, true);
if (err < 0)
- goto error;
+ return err;
err = ad1988_add_spdif_mux_ctl(codec);
if (err < 0)
- goto error;
+ return err;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
}
@@ -1065,7 +1023,7 @@ static const struct hda_fixup ad1884_fixups[] = {
},
};
-static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
+static const struct hda_quirk ad1884_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
@@ -1073,16 +1031,11 @@ static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
};
-static int patch_ad1884(struct hda_codec *codec)
+static int ad1884_probe(struct hda_codec *codec)
{
- struct ad198x_spec *spec;
+ struct ad198x_spec *spec = codec->spec;
int err;
- err = alloc_ad_spec(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
-
spec->gen.mixer_nid = 0x20;
spec->gen.mixer_merge_nid = 0x21;
spec->gen.beep_nid = 0x10;
@@ -1093,18 +1046,14 @@ static int patch_ad1884(struct hda_codec *codec)
err = ad198x_parse_auto_config(codec, true);
if (err < 0)
- goto error;
+ return err;
err = ad1983_add_spdif_mux_ctl(codec);
if (err < 0)
- goto error;
+ return err;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
}
/*
@@ -1119,53 +1068,99 @@ static int patch_ad1884(struct hda_codec *codec)
* port-G - rear clfe-out (6stack)
*/
-static int patch_ad1882(struct hda_codec *codec)
+static int ad1882_probe(struct hda_codec *codec)
{
- struct ad198x_spec *spec;
+ struct ad198x_spec *spec = codec->spec;
int err;
- err = alloc_ad_spec(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
-
spec->gen.mixer_nid = 0x20;
spec->gen.mixer_merge_nid = 0x21;
spec->gen.beep_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
err = ad198x_parse_auto_config(codec, true);
if (err < 0)
- goto error;
+ return err;
err = ad1988_add_spdif_mux_ctl(codec);
if (err < 0)
- goto error;
+ return err;
return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
}
-
/*
- * patch entries
+ * driver entries
*/
+static int ad_codec_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
+{
+ struct ad198x_spec *spec;
+ int err;
+
+ err = alloc_ad_spec(codec);
+ if (err < 0)
+ return -ENOMEM;
+ spec = codec->spec;
+ spec->model = id->driver_data;
+
+ switch (spec->model) {
+ case MODEL_AD1882:
+ err = ad1882_probe(codec);
+ break;
+ case MODEL_AD1884:
+ err = ad1884_probe(codec);
+ break;
+ case MODEL_AD1981:
+ err = ad1981_probe(codec);
+ break;
+ case MODEL_AD1983:
+ err = ad1983_probe(codec);
+ break;
+ case MODEL_AD1986A:
+ err = ad1986a_probe(codec);
+ break;
+ case MODEL_AD1988:
+ err = ad1988_probe(codec);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err < 0) {
+ snd_hda_gen_remove(codec);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct hda_codec_ops ad_codec_ops = {
+ .probe = ad_codec_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = ad_codec_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = ad_codec_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = ad_codec_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
static const struct hda_device_id snd_hda_id_analog[] = {
- HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
- HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
- HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
- HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
- HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
- HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
- HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
- HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
- HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
- HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
- HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
- HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
- HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
- HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
- HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
+ HDA_CODEC_ID_MODEL(0x11d4184a, "AD1884A", MODEL_AD1884),
+ HDA_CODEC_ID_MODEL(0x11d41882, "AD1882", MODEL_AD1882),
+ HDA_CODEC_ID_MODEL(0x11d41883, "AD1883", MODEL_AD1884),
+ HDA_CODEC_ID_MODEL(0x11d41884, "AD1884", MODEL_AD1884),
+ HDA_CODEC_ID_MODEL(0x11d4194a, "AD1984A", MODEL_AD1884),
+ HDA_CODEC_ID_MODEL(0x11d4194b, "AD1984B", MODEL_AD1884),
+ HDA_CODEC_ID_MODEL(0x11d41981, "AD1981", MODEL_AD1981),
+ HDA_CODEC_ID_MODEL(0x11d41983, "AD1983", MODEL_AD1983),
+ HDA_CODEC_ID_MODEL(0x11d41984, "AD1984", MODEL_AD1884),
+ HDA_CODEC_ID_MODEL(0x11d41986, "AD1986A", MODEL_AD1986A),
+ HDA_CODEC_ID_MODEL(0x11d41988, "AD1988", MODEL_AD1988),
+ HDA_CODEC_ID_MODEL(0x11d4198b, "AD1988B", MODEL_AD1988),
+ HDA_CODEC_ID_MODEL(0x11d4882a, "AD1882A", MODEL_AD1882),
+ HDA_CODEC_ID_MODEL(0x11d4989a, "AD1989A", MODEL_AD1988),
+ HDA_CODEC_ID_MODEL(0x11d4989b, "AD1989B", MODEL_AD1988),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
@@ -1175,6 +1170,7 @@ MODULE_DESCRIPTION("Analog Devices HD-audio codec");
static struct hda_codec_driver analog_driver = {
.id = snd_hda_id_analog,
+ .ops = &ad_codec_ops,
};
module_hda_codec_driver(analog_driver);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/hda/codecs/ca0110.c
index 1818ce67f761..c75a9ff9460d 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/hda/codecs/ca0110.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HD audio interface patch for Creative X-Fi CA0110-IBG chip
+ * HD audio codec driver for Creative X-Fi CA0110-IBG chip
*
* Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
*/
@@ -13,16 +13,7 @@
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
-#include "hda_generic.h"
-
-
-static const struct hda_codec_ops ca0110_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = snd_hda_gen_init,
- .free = snd_hda_gen_free,
- .unsol_event = snd_hda_jack_unsol_event,
-};
+#include "generic.h"
static int ca0110_parse_auto_config(struct hda_codec *codec)
{
@@ -39,8 +30,7 @@ static int ca0110_parse_auto_config(struct hda_codec *codec)
return 0;
}
-
-static int patch_ca0110(struct hda_codec *codec)
+static int ca0110_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
struct hda_gen_spec *spec;
int err;
@@ -50,7 +40,6 @@ static int patch_ca0110(struct hda_codec *codec)
return -ENOMEM;
snd_hda_gen_spec_init(spec);
codec->spec = spec;
- codec->patch_ops = ca0110_patch_ops;
spec->multi_cap_vol = 1;
codec->bus->core.needs_damn_long_delay = 1;
@@ -62,18 +51,27 @@ static int patch_ca0110(struct hda_codec *codec)
return 0;
error:
- snd_hda_gen_free(codec);
+ snd_hda_gen_remove(codec);
return err;
}
+static const struct hda_codec_ops ca0110_codec_ops = {
+ .probe = ca0110_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = snd_hda_gen_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+};
+
/*
- * patch entries
+ * driver entries
*/
static const struct hda_device_id snd_hda_id_ca0110[] = {
- HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110),
- HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110),
- HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110),
+ HDA_CODEC_ID(0x1102000a, "CA0110-IBG"),
+ HDA_CODEC_ID(0x1102000b, "CA0110-IBG"),
+ HDA_CODEC_ID(0x1102000d, "SB0880 X-Fi"),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110);
@@ -83,6 +81,7 @@ MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
static struct hda_codec_driver ca0110_driver = {
.id = snd_hda_id_ca0110,
+ .ops = &ca0110_codec_ops,
};
module_hda_codec_driver(ca0110_driver);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/hda/codecs/ca0132.c
index 099722ebaed8..dd054aedd501 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HD audio interface patch for Creative CA0132 chip
+ * HD audio codec driver for Creative CA0132 chip
*
* Copyright (c) 2011, Creative Technology Ltd.
*
- * Based on patch_ca0110.c
+ * Based on ca0110.c
* Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
*/
@@ -28,7 +28,7 @@
#include "ca0132_regs.h"
/* Enable this to see controls for tuning purpose. */
-/*#define ENABLE_TUNING_CONTROLS*/
+#define ENABLE_TUNING_CONTROLS
#ifdef ENABLE_TUNING_CONTROLS
#include <sound/tlv.h>
@@ -174,7 +174,7 @@ static const unsigned int effect_slider_defaults[] = {67, 65, 50, 74, 50};
#define DSP_SPEAKER_OUT_LATENCY 7
struct ct_effect {
- char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ const char *name;
hda_nid_t nid;
int mid; /*effect module ID*/
int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/
@@ -305,7 +305,7 @@ enum {
};
struct ct_tuning_ctl {
- char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ const char *name;
hda_nid_t parent_nid;
hda_nid_t nid;
int mid; /*effect module ID*/
@@ -418,14 +418,14 @@ static const struct ct_tuning_ctl ca0132_tuning_ctls[] = {
#define VOICEFX_MAX_PARAM_COUNT 9
struct ct_voicefx {
- char *name;
+ const char *name;
hda_nid_t nid;
int mid;
int reqs[VOICEFX_MAX_PARAM_COUNT]; /*effect module request*/
};
struct ct_voicefx_preset {
- char *name; /*preset name*/
+ const char *name; /*preset name*/
unsigned int vals[VOICEFX_MAX_PARAM_COUNT];
};
@@ -514,14 +514,14 @@ static const struct ct_voicefx_preset ca0132_voicefx_presets[] = {
#define EQ_PRESET_MAX_PARAM_COUNT 11
struct ct_eq {
- char *name;
+ const char *name;
hda_nid_t nid;
int mid;
int reqs[EQ_PRESET_MAX_PARAM_COUNT]; /*effect module request*/
};
struct ct_eq_preset {
- char *name; /*preset name*/
+ const char *name; /*preset name*/
unsigned int vals[EQ_PRESET_MAX_PARAM_COUNT];
};
@@ -679,7 +679,7 @@ enum {
};
struct ca0132_alt_speaker_channel_cfg {
- char *name;
+ const char *name;
unsigned int val;
};
@@ -755,7 +755,7 @@ static const struct ae_ca0113_output_set ae7_ca0113_output_presets = {
/* ae5 ca0113 command sequences to set headphone gain levels. */
#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4
struct ae5_headphone_gain_set {
- char *name;
+ const char *name;
unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS];
};
@@ -772,7 +772,7 @@ static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = {
};
struct ae5_filter_set {
- char *name;
+ const char *name;
unsigned int val;
};
@@ -1134,7 +1134,6 @@ struct ca0132_spec {
struct hda_codec *codec;
struct delayed_work unsol_hp_work;
- int quirk;
#ifdef ENABLE_TUNING_CONTROLS
long cur_ctl_vals[TUNING_CTLS_COUNT];
@@ -1166,7 +1165,6 @@ struct ca0132_spec {
* CA0132 quirks table
*/
enum {
- QUIRK_NONE,
QUIRK_ALIENWARE,
QUIRK_ALIENWARE_M17XR4,
QUIRK_SBZ,
@@ -1176,10 +1174,11 @@ enum {
QUIRK_R3D,
QUIRK_AE5,
QUIRK_AE7,
+ QUIRK_NONE = HDA_FIXUP_ID_NOT_SET,
};
#ifdef CONFIG_PCI
-#define ca0132_quirk(spec) ((spec)->quirk)
+#define ca0132_quirk(spec) ((spec)->codec->fixup_id)
#define ca0132_use_pci_mmio(spec) ((spec)->use_pci_mmio)
#define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions)
#define ca0132_use_alt_controls(spec) ((spec)->use_alt_controls)
@@ -1293,7 +1292,7 @@ static const struct hda_pintbl ae7_pincfgs[] = {
{}
};
-static const struct snd_pci_quirk ca0132_quirks[] = {
+static const struct hda_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4),
SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
@@ -1306,6 +1305,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x3842, 0x104b, "EVGA X299 Dark", QUIRK_R3DI),
SND_PCI_QUIRK(0x3842, 0x1055, "EVGA Z390 DARK", QUIRK_R3DI),
SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D),
@@ -1315,6 +1315,19 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
{}
};
+static const struct hda_model_fixup ca0132_quirk_models[] = {
+ { .id = QUIRK_ALIENWARE, .name = "alienware" },
+ { .id = QUIRK_ALIENWARE_M17XR4, .name = "alienware-m17xr4" },
+ { .id = QUIRK_SBZ, .name = "sbz" },
+ { .id = QUIRK_ZXR, .name = "zxr" },
+ { .id = QUIRK_ZXR_DBPRO, .name = "zxr-dbpro" },
+ { .id = QUIRK_R3DI, .name = "r3di" },
+ { .id = QUIRK_R3D, .name = "r3d" },
+ { .id = QUIRK_AE5, .name = "ae5" },
+ { .id = QUIRK_AE7, .name = "ae7" },
+ {}
+};
+
/* Output selection quirk info structures. */
#define MAX_QUIRK_MMIO_GPIO_SET_VALS 3
#define MAX_QUIRK_SCP_SET_VALS 2
@@ -1671,20 +1684,14 @@ static int chipio_write(struct hda_codec *codec,
struct ca0132_spec *spec = codec->spec;
int err;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx);
if (err < 0)
- goto exit;
-
- err = chipio_write_data(codec, data);
- if (err < 0)
- goto exit;
+ return err;
-exit:
- mutex_unlock(&spec->chipio_mutex);
- return err;
+ return chipio_write_data(codec, data);
}
/*
@@ -1722,16 +1729,12 @@ static int chipio_write_multiple(struct hda_codec *codec,
struct ca0132_spec *spec = codec->spec;
int status;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
status = chipio_write_address(codec, chip_addx);
if (status < 0)
- goto error;
-
- status = chipio_write_data_multiple(codec, data, count);
-error:
- mutex_unlock(&spec->chipio_mutex);
+ return status;
- return status;
+ return chipio_write_data_multiple(codec, data, count);
}
/*
@@ -1744,20 +1747,14 @@ static int chipio_read(struct hda_codec *codec,
struct ca0132_spec *spec = codec->spec;
int err;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx);
if (err < 0)
- goto exit;
-
- err = chipio_read_data(codec, data);
- if (err < 0)
- goto exit;
+ return err;
-exit:
- mutex_unlock(&spec->chipio_mutex);
- return err;
+ return chipio_read_data(codec, data);
}
/*
@@ -1790,7 +1787,7 @@ static void chipio_set_control_param(struct hda_codec *codec,
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_SET, val);
} else {
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_ID_SET,
@@ -1799,7 +1796,6 @@ static void chipio_set_control_param(struct hda_codec *codec,
VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
param_val);
}
- mutex_unlock(&spec->chipio_mutex);
}
}
@@ -1964,12 +1960,10 @@ static void chipio_8051_write_exram(struct hda_codec *codec,
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
chipio_8051_set_address(codec, addr);
chipio_8051_set_data(codec, data);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void chipio_8051_write_exram_no_mutex(struct hda_codec *codec,
@@ -1992,12 +1986,10 @@ static void chipio_8051_write_pll_pmu(struct hda_codec *codec,
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
chipio_8051_set_address(codec, addr & 0xff);
chipio_8051_set_data_pll(codec, data);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void chipio_8051_write_pll_pmu_no_mutex(struct hda_codec *codec,
@@ -2014,13 +2006,11 @@ static void chipio_enable_clocks(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
chipio_8051_write_pll_pmu_no_mutex(codec, 0x00, 0xff);
chipio_8051_write_pll_pmu_no_mutex(codec, 0x05, 0x0b);
chipio_8051_write_pll_pmu_no_mutex(codec, 0x06, 0xff);
-
- mutex_unlock(&spec->chipio_mutex);
}
/*
@@ -2071,22 +2061,20 @@ static int dspio_write(struct hda_codec *codec, unsigned int scp_data)
dspio_write_wait(codec);
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW,
scp_data & 0xffff);
if (status < 0)
- goto error;
+ return status;
status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH,
scp_data >> 16);
if (status < 0)
- goto error;
+ return status;
/* OK, now check if the write itself has executed*/
status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_STATUS, 0);
-error:
- mutex_unlock(&spec->chipio_mutex);
return (status == VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL) ?
-EIO : 0;
@@ -3021,8 +3009,7 @@ static int dma_convert_to_hda_format(struct hda_codec *codec,
{
unsigned int format_val;
- format_val = snd_hdac_calc_stream_format(sample_rate,
- channels, SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+ format_val = snd_hdac_stream_format(channels, 32, sample_rate);
if (hda_format)
*hda_format = (unsigned short)format_val;
@@ -4224,21 +4211,19 @@ static const unsigned int equalizer_vals_lookup[] = {
static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid,
const unsigned int *lookup, int idx)
{
- int i = 0;
+ int i;
- for (i = 0; i < TUNING_CTLS_COUNT; i++)
- if (nid == ca0132_tuning_ctls[i].nid)
- goto found;
+ for (i = 0; i < TUNING_CTLS_COUNT; i++) {
+ if (nid == ca0132_tuning_ctls[i].nid) {
+ CLASS(snd_hda_power, pm)(codec);
+ dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20,
+ ca0132_tuning_ctls[i].req,
+ &(lookup[idx]), sizeof(unsigned int));
+ return 1;
+ }
+ }
return -EINVAL;
-found:
- snd_hda_power_up(codec);
- dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20,
- ca0132_tuning_ctls[i].req,
- &(lookup[idx]), sizeof(unsigned int));
- snd_hda_power_down(codec);
-
- return 1;
}
static int tuning_ctl_get(struct snd_kcontrol *kcontrol,
@@ -4373,8 +4358,8 @@ static int add_tuning_control(struct hda_codec *codec,
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
- knew.tlv.c = 0;
- knew.tlv.p = 0;
+ knew.tlv.c = NULL;
+ knew.tlv.p = NULL;
switch (pnid) {
case VOICE_FOCUS:
knew.info = voice_focus_ctl_info;
@@ -4398,7 +4383,7 @@ static int add_tuning_control(struct hda_codec *codec,
}
knew.private_value =
HDA_COMPOSE_AMP_VAL(nid, 1, 0, type);
- sprintf(namestr, "%s %s Volume", name, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "%s %s Volume", name, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
@@ -4453,7 +4438,7 @@ static int ca0132_select_out(struct hda_codec *codec)
codec_dbg(codec, "ca0132_select_out\n");
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
@@ -4474,12 +4459,12 @@ static int ca0132_select_out(struct hda_codec *codec)
tmp = FLOAT_ONE;
err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
if (err < 0)
- goto exit;
+ return err;
/*enable speaker EQ*/
tmp = FLOAT_ONE;
err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
if (err < 0)
- goto exit;
+ return err;
/* Setup EAPD */
snd_hda_codec_write(codec, spec->out_pins[1], 0,
@@ -4507,12 +4492,12 @@ static int ca0132_select_out(struct hda_codec *codec)
tmp = FLOAT_ZERO;
err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
if (err < 0)
- goto exit;
+ return err;
/*disable speaker EQ*/
tmp = FLOAT_ZERO;
err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
if (err < 0)
- goto exit;
+ return err;
/* Setup EAPD */
snd_hda_codec_write(codec, spec->out_pins[0], 0,
@@ -4536,10 +4521,7 @@ static int ca0132_select_out(struct hda_codec *codec)
pin_ctl | PIN_HP);
}
-exit:
- snd_hda_power_down_pm(codec);
-
- return err < 0 ? err : 0;
+ return 0;
}
static int ae5_headphone_gain_set(struct hda_codec *codec, long val);
@@ -4763,7 +4745,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
codec_dbg(codec, "%s\n", __func__);
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
@@ -4788,10 +4770,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
/* Begin DSP output switch, mute DSP volume. */
err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_MUTE, FLOAT_ONE);
if (err < 0)
- goto exit;
+ return err;
- if (ca0132_alt_select_out_quirk_set(codec) < 0)
- goto exit;
+ err = ca0132_alt_select_out_quirk_set(codec);
+ if (err < 0)
+ return err;
switch (spec->cur_out_type) {
case SPEAKER_OUT:
@@ -4822,7 +4805,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
if (err < 0)
- goto exit;
+ return err;
break;
case HEADPHONE_OUT:
@@ -4849,7 +4832,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO);
if (err < 0)
- goto exit;
+ return err;
break;
}
/*
@@ -4864,7 +4847,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
/* Set speaker EQ bypass attenuation to 0. */
err = dspio_set_uint_param(codec, 0x8f, 0x01, FLOAT_ZERO);
if (err < 0)
- goto exit;
+ return err;
/*
* Although unused on all cards but the AE series, this is always set
@@ -4873,30 +4856,29 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_TUNING_USE_SPEAKER_EQ, FLOAT_ZERO);
if (err < 0)
- goto exit;
+ return err;
if (spec->cur_out_type == SPEAKER_OUT)
err = ca0132_alt_surround_set_bass_redirection(codec,
spec->bass_redirection_val);
else
err = ca0132_alt_surround_set_bass_redirection(codec, 0);
+ if (err < 0)
+ return err;
/* Unmute DSP now that we're done with output selection. */
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_TUNING_MUTE, FLOAT_ZERO);
if (err < 0)
- goto exit;
+ return err;
if (spec->cur_out_type == SPEAKER_OUT) {
err = ca0132_alt_set_full_range_speaker(codec);
if (err < 0)
- goto exit;
+ return err;
}
-exit:
- snd_hda_power_down_pm(codec);
-
- return err < 0 ? err : 0;
+ return 0;
}
static void ca0132_unsol_hp_delayed(struct work_struct *work)
@@ -5044,7 +5026,7 @@ static int ca0132_select_mic(struct hda_codec *codec)
codec_dbg(codec, "ca0132_select_mic\n");
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
@@ -5077,8 +5059,6 @@ static int ca0132_select_mic(struct hda_codec *codec)
ca0132_effects_set(codec, VOICE_FOCUS, 0);
}
- snd_hda_power_down_pm(codec);
-
return 0;
}
@@ -5095,7 +5075,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
codec_dbg(codec, "%s\n", __func__);
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
chipio_set_stream_control(codec, 0x03, 0);
chipio_set_stream_control(codec, 0x04, 0);
@@ -5258,7 +5238,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
}
ca0132_cvoice_switch_set(codec);
- snd_hda_power_down_pm(codec);
return 0;
}
@@ -5580,13 +5559,12 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
int ch = get_amp_channels(kcontrol);
unsigned long pval;
- mutex_lock(&codec->control_mutex);
+ guard(mutex)(&codec->control_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch,
0, dir);
ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
}
return ret;
@@ -5596,12 +5574,10 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
static void ca0132_alt_bass_redirection_xover_set(struct hda_codec *codec,
long idx)
{
- snd_hda_power_up(codec);
+ CLASS(snd_hda_power, pm)(codec);
dspio_set_param(codec, 0x96, 0x20, SPEAKER_BASS_REDIRECT_XOVER_FREQ,
&(float_xbass_xover_lookup[idx]), sizeof(unsigned int));
-
- snd_hda_power_down(codec);
}
/*
@@ -5627,7 +5603,7 @@ static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid,
else
y = 1;
- snd_hda_power_up(codec);
+ CLASS(snd_hda_power, pm)(codec);
if (nid == XBASS_XOVER) {
for (i = 0; i < OUT_EFFECTS_COUNT; i++)
if (ca0132_effects[i].nid == X_BASS)
@@ -5647,8 +5623,6 @@ static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid,
&(lookup[idx]), sizeof(unsigned int));
}
- snd_hda_power_down(codec);
-
return 0;
}
@@ -5775,7 +5749,7 @@ static int ca0132_alt_effect_slider_put(struct snd_kcontrol *kcontrol,
static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- char *sfx = "dB";
+ const char *sfx = "dB";
char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -5784,7 +5758,7 @@ static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS)
uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1;
sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx);
- strcpy(uinfo->value.enumerated.name, namestr);
+ strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5827,7 +5801,7 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- char *sfx = " Ohms)";
+ const char *sfx = " Ohms)";
char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -5838,7 +5812,7 @@ static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
sprintf(namestr, "%s %s",
ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
sfx);
- strcpy(uinfo->value.enumerated.name, namestr);
+ strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5891,7 +5865,7 @@ static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
sprintf(namestr, "%s",
ae5_filter_presets[uinfo->value.enumerated.item].name);
- strcpy(uinfo->value.enumerated.name, namestr);
+ strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5940,7 +5914,7 @@ static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
in_src_str[uinfo->value.enumerated.item]);
return 0;
}
@@ -5992,7 +5966,7 @@ static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
out_type_str[uinfo->value.enumerated.item]);
return 0;
}
@@ -6043,7 +6017,7 @@ static int ca0132_alt_speaker_channel_cfg_get_info(struct snd_kcontrol *kcontrol
uinfo->value.enumerated.items = items;
if (uinfo->value.enumerated.item >= items)
uinfo->value.enumerated.item = items - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
speaker_channel_cfgs[uinfo->value.enumerated.item].name);
return 0;
}
@@ -6096,7 +6070,7 @@ static int ca0132_alt_svm_setting_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = NUM_OF_SVM_SETTINGS;
if (uinfo->value.enumerated.item >= NUM_OF_SVM_SETTINGS)
uinfo->value.enumerated.item = NUM_OF_SVM_SETTINGS - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
out_svm_set_enum_str[uinfo->value.enumerated.item]);
return 0;
}
@@ -6160,7 +6134,7 @@ static int ca0132_alt_eq_preset_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = items;
if (uinfo->value.enumerated.item >= items)
uinfo->value.enumerated.item = items - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
ca0132_alt_eq_presets[uinfo->value.enumerated.item].name);
return 0;
}
@@ -6217,7 +6191,7 @@ static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = items;
if (uinfo->value.enumerated.item >= items)
uinfo->value.enumerated.item = items - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
ca0132_voicefx_presets[uinfo->value.enumerated.item].name);
return 0;
}
@@ -6327,12 +6301,11 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
hda_nid_t nid = get_amp_nid(kcontrol);
int ch = get_amp_channels(kcontrol);
long *valp = ucontrol->value.integer.value;
- int changed = 1;
codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n",
nid, *valp);
- snd_hda_power_up(codec);
+ CLASS(snd_hda_power, pm)(codec);
/* vnode */
if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) {
if (ch & 1) {
@@ -6343,30 +6316,26 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
spec->vnode_rswitch[nid - VNODE_START_NID] = *valp;
valp++;
}
- changed = ca0132_vnode_switch_set(kcontrol, ucontrol);
- goto exit;
+ return ca0132_vnode_switch_set(kcontrol, ucontrol);
}
/* PE */
if (nid == PLAY_ENHANCEMENT) {
spec->effects_switch[nid - EFFECT_START_NID] = *valp;
- changed = ca0132_pe_switch_set(codec);
- goto exit;
+ return ca0132_pe_switch_set(codec);
}
/* CrystalVoice */
if (nid == CRYSTAL_VOICE) {
spec->effects_switch[nid - EFFECT_START_NID] = *valp;
- changed = ca0132_cvoice_switch_set(codec);
- goto exit;
+ return ca0132_cvoice_switch_set(codec);
}
/* out and in effects */
if (((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) ||
((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID))) {
spec->effects_switch[nid - EFFECT_START_NID] = *valp;
- changed = ca0132_effects_set(codec, nid, *valp);
- goto exit;
+ return ca0132_effects_set(codec, nid, *valp);
}
/* mic boost */
@@ -6374,24 +6343,22 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
spec->cur_mic_boost = *valp;
if (ca0132_use_alt_functions(spec)) {
if (spec->in_enum_val != REAR_LINE_IN)
- changed = ca0132_mic_boost_set(codec, *valp);
+ return ca0132_mic_boost_set(codec, *valp);
} else {
/* Mic boost does not apply to Digital Mic */
if (spec->cur_mic_type != DIGITAL_MIC)
- changed = ca0132_mic_boost_set(codec, *valp);
+ return ca0132_mic_boost_set(codec, *valp);
}
- goto exit;
+ return 1;
}
if (nid == ZXR_HEADPHONE_GAIN) {
spec->zxr_gain_set = *valp;
if (spec->cur_out_type == HEADPHONE_OUT)
- changed = zxr_headphone_gain_set(codec, *valp);
+ return zxr_headphone_gain_set(codec, *valp);
else
- changed = 0;
-
- goto exit;
+ return 0;
}
if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) {
@@ -6399,7 +6366,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
if (spec->cur_out_type == SPEAKER_OUT)
ca0132_alt_set_full_range_speaker(codec);
- changed = 0;
+ return 0;
}
if (nid == BASS_REDIRECTION) {
@@ -6407,12 +6374,10 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
if (spec->cur_out_type == SPEAKER_OUT)
ca0132_alt_surround_set_bass_redirection(codec, *valp);
- changed = 0;
+ return 0;
}
-exit:
- snd_hda_power_down(codec);
- return changed;
+ return 1;
}
/*
@@ -6468,22 +6433,22 @@ static int ca0132_volume_info(struct snd_kcontrol *kcontrol,
case VNID_SPK:
/* follow shared_out info */
nid = spec->shared_out_nid;
- mutex_lock(&codec->control_mutex);
- pval = kcontrol->private_value;
- kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
- err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
- kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
+ scoped_guard(mutex, &codec->control_mutex) {
+ pval = kcontrol->private_value;
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+ err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+ kcontrol->private_value = pval;
+ }
break;
case VNID_MIC:
/* follow shared_mic info */
nid = spec->shared_mic_nid;
- mutex_lock(&codec->control_mutex);
- pval = kcontrol->private_value;
- kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
- err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
- kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
+ scoped_guard(mutex, &codec->control_mutex) {
+ pval = kcontrol->private_value;
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+ err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+ kcontrol->private_value = pval;
+ }
break;
default:
err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
@@ -6540,15 +6505,13 @@ static int ca0132_volume_put(struct snd_kcontrol *kcontrol,
int dir = get_amp_direction(kcontrol);
unsigned long pval;
- snd_hda_power_up(codec);
- mutex_lock(&codec->control_mutex);
+ CLASS(snd_hda_power, pm)(codec);
+ guard(mutex)(&codec->control_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch,
0, dir);
changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
- snd_hda_power_down(codec);
}
return changed;
@@ -6568,7 +6531,6 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol,
int ch = get_amp_channels(kcontrol);
long *valp = ucontrol->value.integer.value;
hda_nid_t vnid = 0;
- int changed;
switch (nid) {
case 0x02:
@@ -6589,14 +6551,10 @@ static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol,
valp++;
}
- snd_hda_power_up(codec);
+ CLASS(snd_hda_power, pm)(codec);
ca0132_alt_dsp_volume_put(codec, vnid);
- mutex_lock(&codec->control_mutex);
- changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
- mutex_unlock(&codec->control_mutex);
- snd_hda_power_down(codec);
-
- return changed;
+ guard(mutex)(&codec->control_mutex);
+ return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
}
static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
@@ -6614,22 +6572,22 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
case VNID_SPK:
/* follow shared_out tlv */
nid = spec->shared_out_nid;
- mutex_lock(&codec->control_mutex);
- pval = kcontrol->private_value;
- kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
- err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
- kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
+ scoped_guard(mutex, &codec->control_mutex) {
+ pval = kcontrol->private_value;
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+ err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+ kcontrol->private_value = pval;
+ }
break;
case VNID_MIC:
/* follow shared_mic tlv */
nid = spec->shared_mic_nid;
- mutex_lock(&codec->control_mutex);
- pval = kcontrol->private_value;
- kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
- err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
- kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
+ scoped_guard(mutex, &codec->control_mutex) {
+ pval = kcontrol->private_value;
+ kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+ err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+ kcontrol->private_value = pval;
+ }
break;
default:
err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
@@ -7511,12 +7469,10 @@ static void ca0132_init_analog_mic2(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
chipio_8051_write_exram_no_mutex(codec, 0x1920, 0x00);
chipio_8051_write_exram_no_mutex(codec, 0x192d, 0x00);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void ca0132_refresh_widget_caps(struct hda_codec *codec)
@@ -7606,19 +7562,17 @@ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
* Check if any of the default streams are active, and if they are,
* stop them.
*/
- mutex_lock(&spec->chipio_mutex);
+ scoped_guard(mutex, &spec->chipio_mutex) {
+ for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
+ chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp);
- for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
- chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp);
-
- if (tmp) {
- chipio_set_stream_control(codec,
- dsp_dma_stream_ids[i], 0);
+ if (tmp) {
+ chipio_set_stream_control(codec,
+ dsp_dma_stream_ids[i], 0);
+ }
}
}
- mutex_unlock(&spec->chipio_mutex);
-
/*
* If all DSP streams are inactive, there should be no active DSP DMA
* channels. Check and make sure this is the case, and if it isn't,
@@ -7626,7 +7580,7 @@ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
*/
ca0132_alt_free_active_dma_channels(codec);
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
/* Make sure stream 0x0c is six channels. */
chipio_set_stream_channels(codec, 0x0c, 6);
@@ -7638,8 +7592,6 @@ static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
/* Give the DSP some time to setup the DMA channel. */
msleep(75);
}
-
- mutex_unlock(&spec->chipio_mutex);
}
/*
@@ -7831,7 +7783,7 @@ static void sbz_connect_streams(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n");
@@ -7846,8 +7798,6 @@ static void sbz_connect_streams(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x14, 1);
codec_dbg(codec, "Connect Streams exited, mutex released.\n");
-
- mutex_unlock(&spec->chipio_mutex);
}
/*
@@ -7861,7 +7811,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
const struct chipio_stream_remap_data *dsp_out_remap_data;
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n");
/* Remap DAC0's output ports. */
@@ -7886,7 +7836,6 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
chipio_remap_stream(codec, dsp_out_remap_data);
codec_dbg(codec, "Startup Data exited, mutex released.\n");
- mutex_unlock(&spec->chipio_mutex);
}
static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
@@ -7978,7 +7927,7 @@ static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
@@ -7996,15 +7945,13 @@ static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7);
ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void ae5_post_dsp_startup_data(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
@@ -8028,15 +7975,13 @@ static void ae5_post_dsp_startup_data(struct hda_codec *codec)
ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void ae7_post_dsp_setup_ports(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
/* Seems to share the same port remapping as the SBZ. */
chipio_remap_stream(codec, &stream_remap_data[1]);
@@ -8049,15 +7994,13 @@ static void ae7_post_dsp_setup_ports(struct hda_codec *codec)
ca0113_mmio_command_set(codec, 0x48, 0x12, 0xff);
ca0113_mmio_command_set(codec, 0x48, 0x13, 0xff);
ca0113_mmio_command_set(codec, 0x48, 0x14, 0x7f);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
@@ -8072,8 +8015,6 @@ static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec)
chipio_set_stream_control(codec, 0x18, 1);
chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
-
- mutex_unlock(&spec->chipio_mutex);
}
static void ae7_post_dsp_pll_setup(struct hda_codec *codec)
@@ -8101,7 +8042,7 @@ static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec)
};
unsigned int i;
- mutex_lock(&spec->chipio_mutex);
+ guard(mutex)(&spec->chipio_mutex);
chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7);
@@ -8163,8 +8104,6 @@ static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec)
*/
ae7_post_dsp_pll_setup(codec);
chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
-
- mutex_unlock(&spec->chipio_mutex);
}
/*
@@ -8649,14 +8588,13 @@ static void ca0132_process_dsp_response(struct hda_codec *codec,
struct ca0132_spec *spec = codec->spec;
codec_dbg(codec, "ca0132_process_dsp_response\n");
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
if (spec->wait_scp) {
if (dspio_get_response_data(codec) >= 0)
spec->wait_scp = 0;
}
dspio_clear_response_queue(codec);
- snd_hda_power_down_pm(codec);
}
static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
@@ -9106,7 +9044,7 @@ static void sbz_dsp_startup_check(struct hda_codec *codec)
codec_info(codec, "Reloading... Tries left: %d", reload);
sbz_exit_chip(codec);
spec->dsp_state = DSP_DOWNLOAD_INIT;
- codec->patch_ops.init(codec);
+ snd_hda_codec_init(codec);
failure = 0;
for (i = 0; i < 4; i++) {
chipio_read(codec, cur_address, &dsp_data_check[i]);
@@ -9531,7 +9469,7 @@ static int ca0132_init(struct hda_codec *codec)
if (ca0132_use_pci_mmio(spec))
ca0132_mmio_init(codec);
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7)
ae5_register_set(codec);
@@ -9611,8 +9549,6 @@ static int ca0132_init(struct hda_codec *codec)
ca0132_pe_switch_set(codec);
}
- snd_hda_power_down_pm(codec);
-
return 0;
}
@@ -9682,34 +9618,6 @@ static void dbpro_free(struct hda_codec *codec)
kfree(codec->spec);
}
-#ifdef CONFIG_PM
-static int ca0132_suspend(struct hda_codec *codec)
-{
- struct ca0132_spec *spec = codec->spec;
-
- cancel_delayed_work_sync(&spec->unsol_hp_work);
- return 0;
-}
-#endif
-
-static const struct hda_codec_ops ca0132_patch_ops = {
- .build_controls = ca0132_build_controls,
- .build_pcms = ca0132_build_pcms,
- .init = ca0132_init,
- .free = ca0132_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = ca0132_suspend,
-#endif
-};
-
-static const struct hda_codec_ops dbpro_patch_ops = {
- .build_controls = dbpro_build_controls,
- .build_pcms = dbpro_build_pcms,
- .init = dbpro_init,
- .free = dbpro_free,
-};
-
static void ca0132_config(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
@@ -9961,28 +9869,36 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
*/
static void sbz_detect_quirk(struct hda_codec *codec)
{
- struct ca0132_spec *spec = codec->spec;
-
switch (codec->core.subsystem_id) {
case 0x11020033:
- spec->quirk = QUIRK_ZXR;
+ codec->fixup_id = QUIRK_ZXR;
break;
case 0x1102003f:
- spec->quirk = QUIRK_ZXR_DBPRO;
+ codec->fixup_id = QUIRK_ZXR_DBPRO;
break;
default:
- spec->quirk = QUIRK_SBZ;
+ codec->fixup_id = QUIRK_SBZ;
break;
}
}
-static int patch_ca0132(struct hda_codec *codec)
+static void ca0132_codec_remove(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ return dbpro_free(codec);
+ else
+ return ca0132_free(codec);
+}
+
+static int ca0132_codec_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
{
struct ca0132_spec *spec;
int err;
- const struct snd_pci_quirk *quirk;
- codec_dbg(codec, "patch_ca0132\n");
+ codec_dbg(codec, "%s\n", __func__);
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
@@ -9991,19 +9907,10 @@ static int patch_ca0132(struct hda_codec *codec)
spec->codec = codec;
/* Detect codec quirk */
- quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
- if (quirk)
- spec->quirk = quirk->value;
- else
- spec->quirk = QUIRK_NONE;
+ snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL);
if (ca0132_quirk(spec) == QUIRK_SBZ)
sbz_detect_quirk(codec);
- if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
- codec->patch_ops = dbpro_patch_ops;
- else
- codec->patch_ops = ca0132_patch_ops;
-
codec->pcm_format_first = 1;
codec->no_sticky_stream = 1;
@@ -10072,7 +9979,7 @@ static int patch_ca0132(struct hda_codec *codec)
spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
if (spec->mem_base == NULL) {
codec_warn(codec, "pci_iomap failed! Setting quirk to QUIRK_NONE.");
- spec->quirk = QUIRK_NONE;
+ codec->fixup_id = QUIRK_NONE;
}
}
#endif
@@ -10099,15 +10006,63 @@ static int patch_ca0132(struct hda_codec *codec)
return 0;
error:
- ca0132_free(codec);
+ ca0132_codec_remove(codec);
return err;
}
+static int ca0132_codec_build_controls(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ return dbpro_build_controls(codec);
+ else
+ return ca0132_build_controls(codec);
+}
+
+static int ca0132_codec_build_pcms(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ return dbpro_build_pcms(codec);
+ else
+ return ca0132_build_pcms(codec);
+}
+
+static int ca0132_codec_init(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ return dbpro_init(codec);
+ else
+ return ca0132_init(codec);
+}
+
+static int ca0132_codec_suspend(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ cancel_delayed_work_sync(&spec->unsol_hp_work);
+ return 0;
+}
+
+static const struct hda_codec_ops ca0132_codec_ops = {
+ .probe = ca0132_codec_probe,
+ .remove = ca0132_codec_remove,
+ .build_controls = ca0132_codec_build_controls,
+ .build_pcms = ca0132_codec_build_pcms,
+ .init = ca0132_codec_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = ca0132_codec_suspend,
+};
+
/*
- * patch entries
+ * driver entries
*/
static const struct hda_device_id snd_hda_id_ca0132[] = {
- HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132),
+ HDA_CODEC_ID(0x11020011, "CA0132"),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132);
@@ -10117,6 +10072,7 @@ MODULE_DESCRIPTION("Creative Sound Core3D codec");
static struct hda_codec_driver ca0132_driver = {
.id = snd_hda_id_ca0132,
+ .ops = &ca0132_codec_ops,
};
module_hda_codec_driver(ca0132_driver);
diff --git a/sound/pci/hda/ca0132_regs.h b/sound/hda/codecs/ca0132_regs.h
index 0ead571fb447..dc0153df3d5c 100644
--- a/sound/pci/hda/ca0132_regs.h
+++ b/sound/hda/codecs/ca0132_regs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * HD audio interface patch for Creative CA0132 chip.
+ * HD audio codec driver for Creative CA0132 chip.
* CA0132 registers defines.
*
* Copyright (c) 2011, Creative Technology Ltd.
diff --git a/sound/hda/codecs/cirrus/Kconfig b/sound/hda/codecs/cirrus/Kconfig
new file mode 100644
index 000000000000..ec6cbcaf64f0
--- /dev/null
+++ b/sound/hda/codecs/cirrus/Kconfig
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig SND_HDA_CODEC_CIRRUS
+ tristate "Cirrus Logic HD-audio codec support"
+ help
+ Say Y or M here to include Cirrus Logic HD-audio codec support.
+
+ This will enable both CS420x and CS421x HD-audio codec drivers
+ as default, but you can enable/disable each codec driver
+ individually, too (only when CONFIG_EXPERT is set).
+
+if SND_HDA_CODEC_CIRRUS
+
+config SND_HDA_CODEC_CS420X
+ tristate "Build Cirrus Logic CS420x codec support" if EXPERT
+ select SND_HDA_GENERIC
+ default y
+ help
+ Say Y or M here to include Cirrus Logic CS420x codec support
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CS420X=m
+
+config SND_HDA_CODEC_CS421X
+ tristate "Build Cirrus Logic CS421x codec support" if EXPERT
+ select SND_HDA_GENERIC
+ default y
+ help
+ Say Y or M here to include Cirrus Logic CS421x codec support
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CS421X=m
+
+config SND_HDA_CODEC_CS8409
+ tristate "Build Cirrus Logic HDA bridge support"
+ select SND_HDA_GENERIC
+ help
+ Say Y or M here to include Cirrus Logic HDA bridge support
+ such as CS8409.
+
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m
+
+endif
diff --git a/sound/hda/codecs/cirrus/Makefile b/sound/hda/codecs/cirrus/Makefile
new file mode 100644
index 000000000000..dda1873ebcf5
--- /dev/null
+++ b/sound/hda/codecs/cirrus/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-cs420x-y := cs420x.o
+snd-hda-codec-cs421x-y := cs421x.o
+snd-hda-codec-cs8409-y := cs8409.o cs8409-tables.o
+
+obj-$(CONFIG_SND_HDA_CODEC_CS420X) += snd-hda-codec-cs420x.o
+obj-$(CONFIG_SND_HDA_CODEC_CS421X) += snd-hda-codec-cs421x.o
+obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/hda/codecs/cirrus/cs420x.c
index 6807b4708a17..13f5f1711fa4 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/hda/codecs/cirrus/cs420x.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HD audio interface patch for Cirrus Logic CS420x chip
+ * Cirrus Logic CS420x HD-audio codec
*
* Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
*/
@@ -15,10 +15,7 @@
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
-#include "hda_generic.h"
-
-/*
- */
+#include "../generic.h"
struct cs_spec {
struct hda_gen_spec gen;
@@ -29,10 +26,6 @@ struct cs_spec {
unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
- /* CS421x */
- unsigned int spdif_detect:1;
- unsigned int spdif_present:1;
- unsigned int sense_b:1;
hda_nid_t vendor_nid;
/* for MBP SPDIF control */
@@ -56,13 +49,6 @@ enum {
CS420X_APPLE = CS420X_GPIO_13,
};
-/* CS421x boards */
-enum {
- CS421X_CDB4210,
- CS421X_SENSE_B,
- CS421X_STUMPY,
-};
-
/* Vendor-specific processing widget */
#define CS420X_VENDOR_NID 0x11
#define CS_DIG_OUT1_PIN_NID 0x10
@@ -105,28 +91,6 @@ enum {
/* Cirrus Logic CS4208 */
#define CS4208_VENDOR_NID 0x24
-/*
- * Cirrus Logic CS4210
- *
- * 1 DAC => HP(sense) / Speakers,
- * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
- * 1 SPDIF OUT => SPDIF Trasmitter(sense)
- */
-#define CS4210_DAC_NID 0x02
-#define CS4210_ADC_NID 0x03
-#define CS4210_VENDOR_NID 0x0B
-#define CS421X_DMIC_PIN_NID 0x09 /* Port E */
-#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */
-
-#define CS421X_IDX_DEV_CFG 0x01
-#define CS421X_IDX_ADC_CFG 0x02
-#define CS421X_IDX_DAC_CFG 0x03
-#define CS421X_IDX_SPK_CTL 0x04
-
-/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
-#define CS4213_VENDOR_NID 0x09
-
-
static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
{
struct cs_spec *spec = codec->spec;
@@ -158,9 +122,6 @@ static void cs_automute(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
- /* mute HPs if spdif jack (SENSE_B) is present */
- spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
-
snd_hda_gen_update_outputs(codec);
if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
@@ -331,16 +292,6 @@ static int cs_build_controls(struct hda_codec *codec)
return 0;
}
-#define cs_free snd_hda_gen_free
-
-static const struct hda_codec_ops cs_patch_ops = {
- .build_controls = cs_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = cs_init,
- .free = cs_free,
- .unsol_event = snd_hda_jack_unsol_event,
-};
-
static int cs_parse_auto_config(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
@@ -385,7 +336,7 @@ static const struct hda_model_fixup cs420x_models[] = {
{}
};
-static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
+static const struct hda_quirk cs420x_fixup_tbl[] = {
SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
@@ -584,17 +535,10 @@ static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
return spec;
}
-static int patch_cs420x(struct hda_codec *codec)
+static int cs420x_probe(struct hda_codec *codec)
{
- struct cs_spec *spec;
int err;
- spec = cs_alloc_spec(codec, CS420X_VENDOR_NID);
- if (!spec)
- return -ENOMEM;
-
- codec->patch_ops = cs_patch_ops;
- spec->gen.automute_hook = cs_automute;
codec->single_adc_amp = 1;
snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
@@ -603,15 +547,11 @@ static int patch_cs420x(struct hda_codec *codec)
err = cs_parse_auto_config(codec);
if (err < 0)
- goto error;
+ return err;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
-
- error:
- cs_free(codec);
- return err;
}
/*
@@ -634,17 +574,18 @@ static const struct hda_model_fixup cs4208_models[] = {
{}
};
-static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
+static const struct hda_quirk cs4208_fixup_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
{} /* terminator */
};
/* codec SSID matching */
-static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
+static const struct hda_quirk cs4208_mac_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
+ SND_PCI_QUIRK(0x106b, 0x7800, "MacPro 6,1", CS4208_MACMINI),
SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
{} /* terminator */
};
@@ -766,17 +707,11 @@ static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
}
-static int patch_cs4208(struct hda_codec *codec)
+static int cs4208_probe(struct hda_codec *codec)
{
- struct cs_spec *spec;
+ struct cs_spec *spec = codec->spec;
int err;
- spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
- if (!spec)
- return -ENOMEM;
-
- codec->patch_ops = cs_patch_ops;
- spec->gen.automute_hook = cs_automute;
/* exclude NID 0x10 (HP) from output volumes due to different steps */
spec->gen.out_vol_mask = 1ULL << 0x10;
@@ -792,456 +727,60 @@ static int patch_cs4208(struct hda_codec *codec)
err = cs_parse_auto_config(codec);
if (err < 0)
- goto error;
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- cs_free(codec);
- return err;
-}
-
-/*
- * Cirrus Logic CS4210
- *
- * 1 DAC => HP(sense) / Speakers,
- * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
- * 1 SPDIF OUT => SPDIF Trasmitter(sense)
- */
-
-/* CS4210 board names */
-static const struct hda_model_fixup cs421x_models[] = {
- { .id = CS421X_CDB4210, .name = "cdb4210" },
- { .id = CS421X_STUMPY, .name = "stumpy" },
- {}
-};
-
-static const struct snd_pci_quirk cs421x_fixup_tbl[] = {
- /* Test Intel board + CDB2410 */
- SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
- {} /* terminator */
-};
-
-/* CS4210 board pinconfigs */
-/* Default CS4210 (CDB4210)*/
-static const struct hda_pintbl cdb4210_pincfgs[] = {
- { 0x05, 0x0321401f },
- { 0x06, 0x90170010 },
- { 0x07, 0x03813031 },
- { 0x08, 0xb7a70037 },
- { 0x09, 0xb7a6003e },
- { 0x0a, 0x034510f0 },
- {} /* terminator */
-};
-
-/* Stumpy ChromeBox */
-static const struct hda_pintbl stumpy_pincfgs[] = {
- { 0x05, 0x022120f0 },
- { 0x06, 0x901700f0 },
- { 0x07, 0x02a120f0 },
- { 0x08, 0x77a70037 },
- { 0x09, 0x77a6003e },
- { 0x0a, 0x434510f0 },
- {} /* terminator */
-};
-
-/* Setup GPIO/SENSE for each board (if used) */
-static void cs421x_fixup_sense_b(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct cs_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- spec->sense_b = 1;
-}
-
-static const struct hda_fixup cs421x_fixups[] = {
- [CS421X_CDB4210] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = cdb4210_pincfgs,
- .chained = true,
- .chain_id = CS421X_SENSE_B,
- },
- [CS421X_SENSE_B] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = cs421x_fixup_sense_b,
- },
- [CS421X_STUMPY] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = stumpy_pincfgs,
- },
-};
-
-static const struct hda_verb cs421x_coef_init_verbs[] = {
- {0x0B, AC_VERB_SET_PROC_STATE, 1},
- {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
- /*
- * Disable Coefficient Index Auto-Increment(DAI)=1,
- * PDREF=0
- */
- {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
-
- {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
- /* ADC SZCMode = Digital Soft Ramp */
- {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
-
- {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
- {0x0B, AC_VERB_SET_PROC_COEF,
- (0x0002 /* DAC SZCMode = Digital Soft Ramp */
- | 0x0004 /* Mute DAC on FIFO error */
- | 0x0008 /* Enable DAC High Pass Filter */
- )},
- {} /* terminator */
-};
-
-/* Errata: CS4210 rev A1 Silicon
- *
- * http://www.cirrus.com/en/pubs/errata/
- *
- * Description:
- * 1. Performance degredation is present in the ADC.
- * 2. Speaker output is not completely muted upon HP detect.
- * 3. Noise is present when clipping occurs on the amplified
- * speaker outputs.
- *
- * Workaround:
- * The following verb sequence written to the registers during
- * initialization will correct the issues listed above.
- */
-
-static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
- {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
-
- {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
- {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
-
- {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
- {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
-
- {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
- {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
-
- {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
- {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
-
- {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
- {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
-
- {} /* terminator */
-};
-
-/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
-static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
-
-static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 3;
- return 0;
-}
-
-static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-
- ucontrol->value.integer.value[0] =
- cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
- return 0;
-}
-
-static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-
- unsigned int vol = ucontrol->value.integer.value[0];
- unsigned int coef =
- cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
- unsigned int original_coef = coef;
-
- coef &= ~0x0003;
- coef |= (vol & 0x0003);
- if (original_coef != coef) {
- cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
- return 1;
- }
-
- return 0;
-}
-
-static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
-
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- .name = "Speaker Boost Playback Volume",
- .info = cs421x_boost_vol_info,
- .get = cs421x_boost_vol_get,
- .put = cs421x_boost_vol_put,
- .tlv = { .p = cs421x_speaker_boost_db_scale },
-};
-
-static void cs4210_pinmux_init(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
- unsigned int def_conf, coef;
-
- /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
- coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
-
- if (spec->gpio_mask)
- coef |= 0x0008; /* B1,B2 are GPIOs */
- else
- coef &= ~0x0008;
-
- if (spec->sense_b)
- coef |= 0x0010; /* B2 is SENSE_B, not inverted */
- else
- coef &= ~0x0010;
-
- cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
-
- if ((spec->gpio_mask || spec->sense_b) &&
- is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
-
- /*
- * GPIO or SENSE_B forced - disconnect the DMIC pin.
- */
- def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
- def_conf &= ~AC_DEFCFG_PORT_CONN;
- def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
- snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
- }
-}
-
-static void cs4210_spdif_automute(struct hda_codec *codec,
- struct hda_jack_callback *tbl)
-{
- struct cs_spec *spec = codec->spec;
- bool spdif_present = false;
- hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
-
- /* detect on spdif is specific to CS4210 */
- if (!spec->spdif_detect ||
- spec->vendor_nid != CS4210_VENDOR_NID)
- return;
-
- spdif_present = snd_hda_jack_detect(codec, spdif_pin);
- if (spdif_present == spec->spdif_present)
- return;
-
- spec->spdif_present = spdif_present;
- /* SPDIF TX on/off */
- snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
-
- cs_automute(codec);
-}
-
-static void parse_cs421x_digital(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->gen.autocfg;
- int i;
-
- for (i = 0; i < cfg->dig_outs; i++) {
- hda_nid_t nid = cfg->dig_out_pins[i];
-
- if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
- spec->spdif_detect = 1;
- snd_hda_jack_detect_enable_callback(codec, nid,
- cs4210_spdif_automute);
- }
- }
-}
-
-static int cs421x_init(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
-
- if (spec->vendor_nid == CS4210_VENDOR_NID) {
- snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
- snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
- cs4210_pinmux_init(codec);
- }
-
- snd_hda_gen_init(codec);
-
- if (spec->gpio_mask) {
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
- spec->gpio_mask);
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
- spec->gpio_dir);
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_data);
- }
-
- init_input_coef(codec);
-
- cs4210_spdif_automute(codec, NULL);
-
- return 0;
-}
-
-static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
-{
- unsigned int caps;
-
- /* set the upper-limit for mixer amp to 0dB */
- caps = query_amp_caps(codec, dac, HDA_OUTPUT);
- caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
- caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
- << AC_AMPCAP_NUM_STEPS_SHIFT;
- snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
-}
-
-static int cs421x_parse_auto_config(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
- hda_nid_t dac = CS4210_DAC_NID;
- int err;
-
- fix_volume_caps(codec, dac);
-
- err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
- if (err < 0)
return err;
- err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
- if (err < 0)
- return err;
-
- parse_cs421x_digital(codec);
-
- if (spec->gen.autocfg.speaker_outs &&
- spec->vendor_nid == CS4210_VENDOR_NID) {
- if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
- &cs421x_speaker_boost_ctl))
- return -ENOMEM;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-/*
- * Manage PDREF, when transitioning to D3hot
- * (DAC,ADC) -> D3, PDREF=1, AFG->D3
- */
-static int cs421x_suspend(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
- unsigned int coef;
-
- snd_hda_shutup_pins(codec);
-
- snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
- snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-
- if (spec->vendor_nid == CS4210_VENDOR_NID) {
- coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
- coef |= 0x0004; /* PDREF */
- cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
- }
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
}
-#endif
-
-static const struct hda_codec_ops cs421x_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = cs421x_init,
- .free = cs_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = cs421x_suspend,
-#endif
-};
-static int patch_cs4210(struct hda_codec *codec)
+static int cs_codec_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
{
struct cs_spec *spec;
int err;
- spec = cs_alloc_spec(codec, CS4210_VENDOR_NID);
+ spec = cs_alloc_spec(codec, id->driver_data);
if (!spec)
return -ENOMEM;
-
- codec->patch_ops = cs421x_patch_ops;
spec->gen.automute_hook = cs_automute;
- snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
- cs421x_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- /*
- * Update the GPIO/DMIC/SENSE_B pinmux before the configuration
- * is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
- * is disabled.
- */
- cs4210_pinmux_init(codec);
-
- err = cs421x_parse_auto_config(codec);
+ if (spec->vendor_nid == CS4208_VENDOR_NID)
+ err = cs4208_probe(codec);
+ else
+ err = cs420x_probe(codec);
if (err < 0)
- goto error;
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- cs_free(codec);
+ snd_hda_gen_remove(codec);
return err;
}
-static int patch_cs4213(struct hda_codec *codec)
-{
- struct cs_spec *spec;
- int err;
-
- spec = cs_alloc_spec(codec, CS4213_VENDOR_NID);
- if (!spec)
- return -ENOMEM;
-
- codec->patch_ops = cs421x_patch_ops;
-
- err = cs421x_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- cs_free(codec);
- return err;
-}
+static const struct hda_codec_ops cs_codec_ops = {
+ .probe = cs_codec_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = cs_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cs_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
/*
- * patch entries
+ * driver entries
*/
-static const struct hda_device_id snd_hda_id_cirrus[] = {
- HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
- HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
- HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
- HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
- HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
+static const struct hda_device_id snd_hda_id_cs420x[] = {
+ HDA_CODEC_ID_MODEL(0x10134206, "CS4206", CS420X_VENDOR_NID),
+ HDA_CODEC_ID_MODEL(0x10134207, "CS4207", CS420X_VENDOR_NID),
+ HDA_CODEC_ID_MODEL(0x10134208, "CS4208", CS4208_VENDOR_NID),
{} /* terminator */
};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs420x);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
+MODULE_DESCRIPTION("Cirrus Logic CS420x HD-audio codec");
-static struct hda_codec_driver cirrus_driver = {
- .id = snd_hda_id_cirrus,
+static struct hda_codec_driver cs420x_driver = {
+ .id = snd_hda_id_cs420x,
+ .ops = &cs_codec_ops,
};
-module_hda_codec_driver(cirrus_driver);
+module_hda_codec_driver(cs420x_driver);
diff --git a/sound/hda/codecs/cirrus/cs421x.c b/sound/hda/codecs/cirrus/cs421x.c
new file mode 100644
index 000000000000..a93e2e0bb391
--- /dev/null
+++ b/sound/hda/codecs/cirrus/cs421x.c
@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cirrus Logic CS421x HD-audio codec
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <linux/pci.h>
+#include <sound/tlv.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "../generic.h"
+
+struct cs_spec {
+ struct hda_gen_spec gen;
+
+ unsigned int gpio_mask;
+ unsigned int gpio_dir;
+ unsigned int gpio_data;
+ unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
+ unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
+
+ /* CS421x */
+ unsigned int spdif_detect:1;
+ unsigned int spdif_present:1;
+ unsigned int sense_b:1;
+ hda_nid_t vendor_nid;
+
+ /* for MBP SPDIF control */
+ int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+};
+
+/* CS421x boards */
+enum {
+ CS421X_CDB4210,
+ CS421X_SENSE_B,
+ CS421X_STUMPY,
+};
+
+/* Vendor-specific processing widget */
+#define CS_DIG_OUT1_PIN_NID 0x10
+#define CS_DIG_OUT2_PIN_NID 0x15
+#define CS_DMIC1_PIN_NID 0x0e
+#define CS_DMIC2_PIN_NID 0x12
+
+/* coef indices */
+#define IDX_SPDIF_STAT 0x0000
+#define IDX_SPDIF_CTL 0x0001
+#define IDX_ADC_CFG 0x0002
+/* SZC bitmask, 4 modes below:
+ * 0 = immediate,
+ * 1 = digital immediate, analog zero-cross
+ * 2 = digtail & analog soft-ramp
+ * 3 = digital soft-ramp, analog zero-cross
+ */
+#define CS_COEF_ADC_SZC_MASK (3 << 0)
+#define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */
+#define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */
+/* PGA mode: 0 = differential, 1 = signle-ended */
+#define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */
+#define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */
+#define IDX_DAC_CFG 0x0003
+/* SZC bitmask, 4 modes below:
+ * 0 = Immediate
+ * 1 = zero-cross
+ * 2 = soft-ramp
+ * 3 = soft-ramp on zero-cross
+ */
+#define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */
+#define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */
+#define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */
+
+#define IDX_BEEP_CFG 0x0004
+/* 0x0008 - test reg key */
+/* 0x0009 - 0x0014 -> 12 test regs */
+/* 0x0015 - visibility reg */
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Transmitter(sense)
+ */
+#define CS4210_DAC_NID 0x02
+#define CS4210_ADC_NID 0x03
+#define CS4210_VENDOR_NID 0x0B
+#define CS421X_DMIC_PIN_NID 0x09 /* Port E */
+#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */
+
+#define CS421X_IDX_DEV_CFG 0x01
+#define CS421X_IDX_ADC_CFG 0x02
+#define CS421X_IDX_DAC_CFG 0x03
+#define CS421X_IDX_SPK_CTL 0x04
+
+/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
+#define CS4213_VENDOR_NID 0x09
+
+
+static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
+{
+ struct cs_spec *spec = codec->spec;
+
+ snd_hda_codec_write(codec, spec->vendor_nid, 0,
+ AC_VERB_SET_COEF_INDEX, idx);
+ return snd_hda_codec_read(codec, spec->vendor_nid, 0,
+ AC_VERB_GET_PROC_COEF, 0);
+}
+
+static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
+ unsigned int coef)
+{
+ struct cs_spec *spec = codec->spec;
+
+ snd_hda_codec_write(codec, spec->vendor_nid, 0,
+ AC_VERB_SET_COEF_INDEX, idx);
+ snd_hda_codec_write(codec, spec->vendor_nid, 0,
+ AC_VERB_SET_PROC_COEF, coef);
+}
+
+/*
+ * auto-mute and auto-mic switching
+ * CS421x auto-output redirecting
+ * HP/SPK/SPDIF
+ */
+
+static void cs_automute(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ /* mute HPs if spdif jack (SENSE_B) is present */
+ spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
+
+ snd_hda_gen_update_outputs(codec);
+
+ if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
+ if (spec->gen.automute_speaker)
+ spec->gpio_data = spec->gen.hp_jack_present ?
+ spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
+ else
+ spec->gpio_data =
+ spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+ snd_hda_codec_write(codec, 0x01, 0,
+ AC_VERB_SET_GPIO_DATA, spec->gpio_data);
+ }
+}
+
+static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int val;
+
+ val = snd_hda_codec_get_pincfg(codec, nid);
+ return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
+}
+
+static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
+{
+ struct cs_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return NULL;
+ codec->spec = spec;
+ spec->vendor_nid = vendor_nid;
+ codec->power_save_node = 1;
+ snd_hda_gen_spec_init(&spec->gen);
+
+ return spec;
+}
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Transmitter(sense)
+ */
+
+/* CS4210 board names */
+static const struct hda_model_fixup cs421x_models[] = {
+ { .id = CS421X_CDB4210, .name = "cdb4210" },
+ { .id = CS421X_STUMPY, .name = "stumpy" },
+ {}
+};
+
+static const struct hda_quirk cs421x_fixup_tbl[] = {
+ /* Test Intel board + CDB2410 */
+ SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
+ {} /* terminator */
+};
+
+/* CS4210 board pinconfigs */
+/* Default CS4210 (CDB4210)*/
+static const struct hda_pintbl cdb4210_pincfgs[] = {
+ { 0x05, 0x0321401f },
+ { 0x06, 0x90170010 },
+ { 0x07, 0x03813031 },
+ { 0x08, 0xb7a70037 },
+ { 0x09, 0xb7a6003e },
+ { 0x0a, 0x034510f0 },
+ {} /* terminator */
+};
+
+/* Stumpy ChromeBox */
+static const struct hda_pintbl stumpy_pincfgs[] = {
+ { 0x05, 0x022120f0 },
+ { 0x06, 0x901700f0 },
+ { 0x07, 0x02a120f0 },
+ { 0x08, 0x77a70037 },
+ { 0x09, 0x77a6003e },
+ { 0x0a, 0x434510f0 },
+ {} /* terminator */
+};
+
+/* Setup GPIO/SENSE for each board (if used) */
+static void cs421x_fixup_sense_b(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct cs_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->sense_b = 1;
+}
+
+static const struct hda_fixup cs421x_fixups[] = {
+ [CS421X_CDB4210] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cdb4210_pincfgs,
+ .chained = true,
+ .chain_id = CS421X_SENSE_B,
+ },
+ [CS421X_SENSE_B] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs421x_fixup_sense_b,
+ },
+ [CS421X_STUMPY] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = stumpy_pincfgs,
+ },
+};
+
+static const struct hda_verb cs421x_coef_init_verbs[] = {
+ {0x0B, AC_VERB_SET_PROC_STATE, 1},
+ {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
+ /*
+ * Disable Coefficient Index Auto-Increment(DAI)=1,
+ * PDREF=0
+ */
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
+ /* ADC SZCMode = Digital Soft Ramp */
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
+ {0x0B, AC_VERB_SET_PROC_COEF,
+ (0x0002 /* DAC SZCMode = Digital Soft Ramp */
+ | 0x0004 /* Mute DAC on FIFO error */
+ | 0x0008 /* Enable DAC High Pass Filter */
+ )},
+ {} /* terminator */
+};
+
+/* Errata: CS4210 rev A1 Silicon
+ *
+ * http://www.cirrus.com/en/pubs/errata/
+ *
+ * Description:
+ * 1. Performance degredation is present in the ADC.
+ * 2. Speaker output is not completely muted upon HP detect.
+ * 3. Noise is present when clipping occurs on the amplified
+ * speaker outputs.
+ *
+ * Workaround:
+ * The following verb sequence written to the registers during
+ * initialization will correct the issues listed above.
+ */
+
+static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
+ {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
+
+ {} /* terminator */
+};
+
+/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
+static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
+
+static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 3;
+ return 0;
+}
+
+static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
+ return 0;
+}
+
+static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ unsigned int vol = ucontrol->value.integer.value[0];
+ unsigned int coef =
+ cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
+ unsigned int original_coef = coef;
+
+ coef &= ~0x0003;
+ coef |= (vol & 0x0003);
+ if (original_coef != coef) {
+ cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
+
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Speaker Boost Playback Volume",
+ .info = cs421x_boost_vol_info,
+ .get = cs421x_boost_vol_get,
+ .put = cs421x_boost_vol_put,
+ .tlv = { .p = cs421x_speaker_boost_db_scale },
+};
+
+static void cs4210_pinmux_init(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ unsigned int def_conf, coef;
+
+ /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
+ coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+
+ if (spec->gpio_mask)
+ coef |= 0x0008; /* B1,B2 are GPIOs */
+ else
+ coef &= ~0x0008;
+
+ if (spec->sense_b)
+ coef |= 0x0010; /* B2 is SENSE_B, not inverted */
+ else
+ coef &= ~0x0010;
+
+ cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+ if ((spec->gpio_mask || spec->sense_b) &&
+ is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
+
+ /*
+ * GPIO or SENSE_B forced - disconnect the DMIC pin.
+ */
+ def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
+ def_conf &= ~AC_DEFCFG_PORT_CONN;
+ def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
+ snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
+ }
+}
+
+static void cs4210_spdif_automute(struct hda_codec *codec,
+ struct hda_jack_callback *tbl)
+{
+ struct cs_spec *spec = codec->spec;
+ bool spdif_present = false;
+ hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
+
+ /* detect on spdif is specific to CS4210 */
+ if (!spec->spdif_detect ||
+ spec->vendor_nid != CS4210_VENDOR_NID)
+ return;
+
+ spdif_present = snd_hda_jack_detect(codec, spdif_pin);
+ if (spdif_present == spec->spdif_present)
+ return;
+
+ spec->spdif_present = spdif_present;
+ /* SPDIF TX on/off */
+ snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
+
+ cs_automute(codec);
+}
+
+static void parse_cs421x_digital(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+ int i;
+
+ for (i = 0; i < cfg->dig_outs; i++) {
+ hda_nid_t nid = cfg->dig_out_pins[i];
+
+ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+ spec->spdif_detect = 1;
+ snd_hda_jack_detect_enable_callback(codec, nid,
+ cs4210_spdif_automute);
+ }
+ }
+}
+
+static int cs421x_init(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ if (spec->vendor_nid == CS4210_VENDOR_NID) {
+ snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
+ snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
+ cs4210_pinmux_init(codec);
+ }
+
+ snd_hda_gen_init(codec);
+
+ if (spec->gpio_mask) {
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+ spec->gpio_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+ spec->gpio_dir);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+ }
+
+ cs4210_spdif_automute(codec, NULL);
+
+ return 0;
+}
+
+static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
+{
+ unsigned int caps;
+
+ /* set the upper-limit for mixer amp to 0dB */
+ caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+ caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
+ caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
+ << AC_AMPCAP_NUM_STEPS_SHIFT;
+ snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
+}
+
+static int cs421x_parse_auto_config(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ hda_nid_t dac = CS4210_DAC_NID;
+ int err;
+
+ fix_volume_caps(codec, dac);
+
+ err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+ if (err < 0)
+ return err;
+
+ err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+ if (err < 0)
+ return err;
+
+ parse_cs421x_digital(codec);
+
+ if (spec->gen.autocfg.speaker_outs &&
+ spec->vendor_nid == CS4210_VENDOR_NID) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &cs421x_speaker_boost_ctl))
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Manage PDREF, when transitioning to D3hot
+ * (DAC,ADC) -> D3, PDREF=1, AFG->D3
+ */
+static int cs421x_suspend(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ unsigned int coef;
+
+ snd_hda_shutup_pins(codec);
+
+ snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+ if (spec->vendor_nid == CS4210_VENDOR_NID) {
+ coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+ coef |= 0x0004; /* PDREF */
+ cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+ }
+
+ return 0;
+}
+
+static int cs421x_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct cs_spec *spec;
+ int err;
+
+ spec = cs_alloc_spec(codec, id->driver_data);
+ if (!spec)
+ return -ENOMEM;
+
+ spec->gen.automute_hook = cs_automute;
+
+ if (spec->vendor_nid == CS4210_VENDOR_NID) {
+ snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
+ cs421x_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ /*
+ * Update the GPIO/DMIC/SENSE_B pinmux before the configuration
+ * is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
+ * is disabled.
+ */
+ cs4210_pinmux_init(codec);
+ }
+
+ err = cs421x_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops cs421x_codec_ops = {
+ .probe = cs421x_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cs421x_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = cs421x_suspend,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_cs421x[] = {
+ HDA_CODEC_ID_MODEL(0x10134210, "CS4210", CS4210_VENDOR_NID),
+ HDA_CODEC_ID_MODEL(0x10134213, "CS4213", CS4213_VENDOR_NID),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs421x);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cirrus Logic CS421x HD-audio codec");
+
+static struct hda_codec_driver cs421x_driver = {
+ .id = snd_hda_id_cs421x,
+ .ops = &cs421x_codec_ops,
+};
+
+module_hda_codec_driver(cs421x_driver);
diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/hda/codecs/cirrus/cs8409-tables.c
index b288874e401e..8c703b714a71 100644
--- a/sound/pci/hda/patch_cs8409-tables.c
+++ b/sound/hda/codecs/cirrus/cs8409-tables.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * patch_cs8409-tables.c -- HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * cs8409-tables.c -- HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip
*
* Copyright (C) 2021 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
@@ -8,7 +8,7 @@
* Author: Lucas Tanure <tanureal@opensource.cirrus.com>
*/
-#include "patch_cs8409.h"
+#include "cs8409.h"
/******************************************************************************
* CS42L42 Specific Data
@@ -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 },
@@ -473,7 +473,7 @@ struct sub_codec dolphin_cs42l42_1 = {
* Arrays Used for all projects using CS8409
******************************************************************************/
-const struct snd_pci_quirk cs8409_fixup_tbl[] = {
+const struct hda_quirk cs8409_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
@@ -550,6 +550,10 @@ const struct snd_pci_quirk cs8409_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN),
SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN),
SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN),
+ SND_PCI_QUIRK(0x1028, 0x0C73, "Dolphin", CS8409_DOLPHIN),
+ SND_PCI_QUIRK(0x1028, 0x0C75, "Dolphin", CS8409_DOLPHIN),
+ SND_PCI_QUIRK(0x1028, 0x0C7D, "Dolphin", CS8409_DOLPHIN),
+ SND_PCI_QUIRK(0x1028, 0x0C7F, "Dolphin", CS8409_DOLPHIN),
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/hda/codecs/cirrus/cs8409.c
index 0ba1fbcbb21e..2c02d3be89ee 100644
--- a/sound/pci/hda/patch_cs8409.c
+++ b/sound/hda/codecs/cirrus/cs8409.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip
*
* Copyright (C) 2021 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
@@ -13,7 +13,7 @@
#include <linux/mutex.h>
#include <linux/iopoll.h>
-#include "patch_cs8409.h"
+#include "cs8409.h"
/******************************************************************************
* CS8409 Specific Functions
@@ -92,13 +92,12 @@ static void cs8409_disable_i2c_clock(struct hda_codec *codec)
{
struct cs8409_spec *spec = codec->spec;
- mutex_lock(&spec->i2c_mux);
+ guard(mutex)(&spec->i2c_mux);
if (spec->i2c_clck_enabled) {
cs8409_vendor_coef_set(spec->codec, 0x0,
cs8409_vendor_coef_get(spec->codec, 0x0) & 0xfffffff7);
spec->i2c_clck_enabled = 0;
}
- mutex_unlock(&spec->i2c_mux);
}
/*
@@ -204,7 +203,7 @@ static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr)
if (scodec->suspended)
return -EPERM;
- mutex_lock(&spec->i2c_mux);
+ guard(mutex)(&spec->i2c_mux);
cs8409_enable_i2c_clock(codec);
cs8409_set_i2c_dev_addr(codec, scodec->addr);
@@ -219,12 +218,9 @@ static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr)
/* Register in bits 15-8 and the data in 7-0 */
read_data = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD);
- mutex_unlock(&spec->i2c_mux);
-
return read_data & 0x0ff;
error:
- mutex_unlock(&spec->i2c_mux);
codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
return -EIO;
}
@@ -247,7 +243,7 @@ static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_para
if (scodec->suspended)
return -EPERM;
- mutex_lock(&spec->i2c_mux);
+ guard(mutex)(&spec->i2c_mux);
cs8409_set_i2c_dev_addr(codec, scodec->addr);
for (i = 0; i < count; i++) {
@@ -264,12 +260,9 @@ static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_para
seq[i].value = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD) & 0xff;
}
- mutex_unlock(&spec->i2c_mux);
-
return 0;
error:
- mutex_unlock(&spec->i2c_mux);
codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
return -EIO;
}
@@ -291,7 +284,7 @@ static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigne
if (scodec->suspended)
return -EPERM;
- mutex_lock(&spec->i2c_mux);
+ guard(mutex)(&spec->i2c_mux);
cs8409_enable_i2c_clock(codec);
cs8409_set_i2c_dev_addr(codec, scodec->addr);
@@ -305,11 +298,9 @@ static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigne
if (cs8409_i2c_wait_complete(codec) < 0)
goto error;
- mutex_unlock(&spec->i2c_mux);
return 0;
error:
- mutex_unlock(&spec->i2c_mux);
codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
return -EIO;
}
@@ -333,7 +324,7 @@ static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i
if (scodec->suspended)
return -EPERM;
- mutex_lock(&spec->i2c_mux);
+ guard(mutex)(&spec->i2c_mux);
cs8409_set_i2c_dev_addr(codec, scodec->addr);
for (i = 0; i < count; i++) {
@@ -346,14 +337,16 @@ 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);
-
return 0;
error:
- mutex_unlock(&spec->i2c_mux);
codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
return -EIO;
}
@@ -876,7 +869,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 +881,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);
- usleep_range(30000, 35000);
/* 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
@@ -909,7 +903,6 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
cs42l42_enable_jack_detect(cs42l42);
}
-#ifdef CONFIG_PM
static void cs42l42_suspend(struct sub_codec *cs42l42)
{
struct hda_codec *codec = cs42l42->codec;
@@ -921,7 +914,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 },
@@ -948,9 +941,8 @@ static void cs42l42_suspend(struct sub_codec *cs42l42)
spec->gpio_data &= ~cs42l42->reset_gpio;
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
}
-#endif
-static void cs8409_free(struct hda_codec *codec)
+static void cs8409_remove(struct hda_codec *codec)
{
struct cs8409_spec *spec = codec->spec;
@@ -958,7 +950,7 @@ static void cs8409_free(struct hda_codec *codec)
cancel_delayed_work_sync(&spec->i2c_clk_work);
cs8409_disable_i2c_clock(codec);
- snd_hda_gen_free(codec);
+ snd_hda_gen_remove(codec);
}
/******************************************************************************
@@ -1003,7 +995,16 @@ static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned in
}
}
-#ifdef CONFIG_PM
+static void cs8409_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ struct cs8409_spec *spec = codec->spec;
+
+ if (spec->unsol_event)
+ spec->unsol_event(codec, res);
+ else
+ cs8409_cs42l42_jack_unsol_event(codec, res);
+}
+
/* Manage PDREF, when transition to D3hot */
static int cs8409_cs42l42_suspend(struct hda_codec *codec)
{
@@ -1025,7 +1026,6 @@ static int cs8409_cs42l42_suspend(struct hda_codec *codec)
return 0;
}
-#endif
/* Vendor specific HW configuration
* PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
@@ -1074,17 +1074,6 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
cs8409_enable_ur(codec, 1);
}
-static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
- .build_controls = cs8409_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = cs8409_init,
- .free = cs8409_free,
- .unsol_event = cs8409_cs42l42_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = cs8409_cs42l42_suspend,
-#endif
-};
-
static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
unsigned int *res)
{
@@ -1134,7 +1123,6 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
spec->scodecs[CS8409_CODEC0] = &cs8409_cs42l42_codec;
spec->num_scodecs = 1;
spec->scodecs[CS8409_CODEC0]->codec = codec;
- codec->patch_ops = cs8409_cs42l42_patch_ops;
spec->gen.suppress_auto_mute = 1;
spec->gen.no_primary_hp = 1;
@@ -1304,17 +1292,6 @@ static void dolphin_hw_init(struct hda_codec *codec)
cs8409_enable_ur(codec, 1);
}
-static const struct hda_codec_ops cs8409_dolphin_patch_ops = {
- .build_controls = cs8409_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = cs8409_init,
- .free = cs8409_free,
- .unsol_event = dolphin_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = cs8409_cs42l42_suspend,
-#endif
-};
-
static int dolphin_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
unsigned int *res)
{
@@ -1371,8 +1348,9 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac
spec->scodecs[CS8409_CODEC1] = &dolphin_cs42l42_1;
spec->scodecs[CS8409_CODEC1]->codec = codec;
spec->num_scodecs = 2;
+ spec->gen.suppress_vmaster = 1;
- codec->patch_ops = cs8409_dolphin_patch_ops;
+ spec->unsol_event = dolphin_jack_unsol_event;
/* GPIO 1,5 out, 0,4 in */
spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio |
@@ -1410,8 +1388,9 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac
kctrl = snd_hda_gen_add_kctl(&spec->gen, "Line Out Playback Volume",
&cs42l42_dac_volume_mixer);
/* Update Line Out kcontrol template */
- kctrl->private_value = HDA_COMPOSE_AMP_VAL_OFS(DOLPHIN_HP_PIN_NID, 3, CS8409_CODEC1,
- HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE;
+ if (kctrl)
+ kctrl->private_value = HDA_COMPOSE_AMP_VAL_OFS(DOLPHIN_HP_PIN_NID, 3, CS8409_CODEC1,
+ HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE;
cs8409_enable_ur(codec, 0);
snd_hda_codec_set_name(codec, "CS8409/CS42L42");
break;
@@ -1444,7 +1423,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac
}
}
-static int patch_cs8409(struct hda_codec *codec)
+static int cs8409_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
int err;
@@ -1461,7 +1440,7 @@ static int patch_cs8409(struct hda_codec *codec)
err = cs8409_parse_auto_config(codec);
if (err < 0) {
- cs8409_free(codec);
+ cs8409_remove(codec);
return err;
}
@@ -1469,14 +1448,26 @@ static int patch_cs8409(struct hda_codec *codec)
return 0;
}
+static const struct hda_codec_ops cs8409_codec_ops = {
+ .probe = cs8409_probe,
+ .remove = cs8409_remove,
+ .build_controls = cs8409_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cs8409_init,
+ .unsol_event = cs8409_unsol_event,
+ .suspend = cs8409_cs42l42_suspend,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
static const struct hda_device_id snd_hda_id_cs8409[] = {
- HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409),
+ HDA_CODEC_ID(0x10138409, "CS8409"),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs8409);
static struct hda_codec_driver cs8409_driver = {
.id = snd_hda_id_cs8409,
+ .ops = &cs8409_codec_ops,
};
module_hda_codec_driver(cs8409_driver);
diff --git a/sound/pci/hda/patch_cs8409.h b/sound/hda/codecs/cirrus/cs8409.h
index 2a8dfb4ff046..7fe56f4a73bc 100644
--- a/sound/pci/hda/patch_cs8409.h
+++ b/sound/hda/codecs/cirrus/cs8409.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip
*
* Copyright (C) 2021 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
@@ -17,7 +17,7 @@
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
/* CS8409 Specific Definitions */
@@ -229,9 +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_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 */
@@ -289,6 +290,7 @@ enum {
struct cs8409_i2c_param {
unsigned int addr;
unsigned int value;
+ unsigned int delay;
};
struct cs8409_cir_param {
@@ -343,6 +345,8 @@ struct cs8409_spec {
/* verb exec op override */
int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
unsigned int *res);
+ /* unsol_event op override */
+ void (*unsol_event)(struct hda_codec *codec, unsigned int res);
};
extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
@@ -354,7 +358,7 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback;
extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture;
-extern const struct snd_pci_quirk cs8409_fixup_tbl[];
+extern const struct hda_quirk cs8409_fixup_tbl[];
extern const struct hda_model_fixup cs8409_models[];
extern const struct hda_fixup cs8409_fixups[];
extern const struct hda_verb cs8409_cs42l42_init_verbs[];
diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
new file mode 100644
index 000000000000..5c474ce44348
--- /dev/null
+++ b/sound/hda/codecs/cm9825.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * CM9825 HD-audio codec
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+/* CM9825 Offset Definitions */
+
+#define CM9825_VERB_SET_HPF_1 0x781
+#define CM9825_VERB_SET_HPF_2 0x785
+#define CM9825_VERB_SET_PLL 0x7a0
+#define CM9825_VERB_SET_NEG 0x7a1
+#define CM9825_VERB_SET_ADCL 0x7a2
+#define CM9825_VERB_SET_DACL 0x7a3
+#define CM9825_VERB_SET_MBIAS 0x7a4
+#define CM9825_VERB_SET_VNEG 0x7a8
+#define CM9825_VERB_SET_D2S 0x7a9
+#define CM9825_VERB_SET_DACTRL 0x7aa
+#define CM9825_VERB_SET_PDNEG 0x7ac
+#define CM9825_VERB_SET_VDO 0x7ad
+#define CM9825_VERB_SET_CDALR 0x7b0
+#define CM9825_VERB_SET_MTCBA 0x7b1
+#define CM9825_VERB_SET_OTP 0x7b2
+#define CM9825_VERB_SET_OCP 0x7b3
+#define CM9825_VERB_SET_GAD 0x7b4
+#define CM9825_VERB_SET_TMOD 0x7b5
+#define CM9825_VERB_SET_SNR 0x7b6
+
+struct cmi_spec {
+ struct hda_gen_spec gen;
+ const struct hda_verb *chip_d0_verbs;
+ const struct hda_verb *chip_d3_verbs;
+ const struct hda_verb *chip_hp_present_verbs;
+ const struct hda_verb *chip_hp_remove_verbs;
+ struct hda_codec *codec;
+ struct delayed_work unsol_hp_work;
+ int quirk;
+};
+
+static const struct hda_verb cm9825_std_d3_verbs[] = {
+ /* chip sleep verbs */
+ {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */
+ {0x43, CM9825_VERB_SET_PLL, 0x01}, /* PLL set */
+ {0x43, CM9825_VERB_SET_NEG, 0xc2}, /* NEG set */
+ {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */
+ {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */
+ {0x43, CM9825_VERB_SET_VNEG, 0x50}, /* VOL NEG */
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */
+ {0x43, CM9825_VERB_SET_PDNEG, 0x04}, /* SEL OSC */
+ {0x43, CM9825_VERB_SET_CDALR, 0xf6}, /* Class D */
+ {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */
+ {}
+};
+
+static const struct hda_verb cm9825_std_d0_verbs[] = {
+ /* chip init verbs */
+ {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* EAPD set */
+ {0x43, CM9825_VERB_SET_SNR, 0x30}, /* SNR set */
+ {0x43, CM9825_VERB_SET_PLL, 0x00}, /* PLL set */
+ {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */
+ {0x43, CM9825_VERB_SET_DACL, 0x02}, /* DACL */
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */
+ {0x43, CM9825_VERB_SET_VNEG, 0x56}, /* VOL NEG */
+ {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */
+ {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */
+ {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, /* SEL OSC */
+ {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */
+ {0x43, CM9825_VERB_SET_CDALR, 0xf4}, /* Class D */
+ {0x43, CM9825_VERB_SET_OTP, 0xcd}, /* OTP set */
+ {0x43, CM9825_VERB_SET_MTCBA, 0x61}, /* SR set */
+ {0x43, CM9825_VERB_SET_OCP, 0x33}, /* OTP set */
+ {0x43, CM9825_VERB_SET_GAD, 0x07}, /* ADC -3db */
+ {0x43, CM9825_VERB_SET_TMOD, 0x26}, /* Class D clk */
+ {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
+ AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d}, /* Gain set */
+ {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
+ AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d}, /* Gain set */
+ {0x43, CM9825_VERB_SET_HPF_1, 0x40}, /* HPF set */
+ {0x43, CM9825_VERB_SET_HPF_2, 0x40}, /* HPF set */
+ {}
+};
+
+static const struct hda_verb cm9825_hp_present_verbs[] = {
+ {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, /* PIN off */
+ {0x43, CM9825_VERB_SET_ADCL, 0x88}, /* ADC */
+ {0x43, CM9825_VERB_SET_DACL, 0xaa}, /* DACL */
+ {0x43, CM9825_VERB_SET_MBIAS, 0x10}, /* MBIAS */
+ {0x43, CM9825_VERB_SET_D2S, 0xf2}, /* depop */
+ {0x43, CM9825_VERB_SET_DACTRL, 0x00}, /* DACTRL set */
+ {0x43, CM9825_VERB_SET_VDO, 0xc4}, /* VDO set */
+ {}
+};
+
+static const struct hda_verb cm9825_hp_remove_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x00}, /* ADC */
+ {0x43, CM9825_VERB_SET_DACL, 0x56}, /* DACL */
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00}, /* MBIAS */
+ {0x43, CM9825_VERB_SET_D2S, 0x62}, /* depop */
+ {0x43, CM9825_VERB_SET_DACTRL, 0xe0}, /* DACTRL set */
+ {0x43, CM9825_VERB_SET_VDO, 0x80}, /* VDO set */
+ {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PIN on */
+ {}
+};
+
+static void cm9825_unsol_hp_delayed(struct work_struct *work)
+{
+ struct cmi_spec *spec =
+ container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
+ struct hda_jack_tbl *jack;
+ hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+ bool hp_jack_plugin = false;
+ int err = 0;
+
+ hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
+
+ codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
+ (int)hp_jack_plugin, hp_pin);
+
+ if (!hp_jack_plugin) {
+ err =
+ snd_hda_codec_write(spec->codec, 0x42, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+ if (err)
+ codec_dbg(spec->codec, "codec_write err %d\n", err);
+
+ snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
+ } else {
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_hp_present_verbs);
+ }
+
+ jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
+ if (jack) {
+ jack->block_report = 0;
+ snd_hda_jack_report_sync(spec->codec);
+ }
+}
+
+static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+ struct cmi_spec *spec = codec->spec;
+ struct hda_jack_tbl *tbl;
+
+ /* Delay enabling the HP amp, to let the mic-detection
+ * state machine run.
+ */
+
+ codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
+
+ tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+ if (tbl)
+ tbl->block_report = 1;
+ schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
+}
+
+static void cm9825_setup_unsol(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+
+ hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+
+ snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
+}
+
+static int cm9825_init(struct hda_codec *codec)
+{
+ snd_hda_gen_init(codec);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+ return 0;
+}
+
+static void cm9825_remove(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+
+ cancel_delayed_work_sync(&spec->unsol_hp_work);
+ snd_hda_gen_remove(codec);
+}
+
+static int cm9825_suspend(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+
+ cancel_delayed_work_sync(&spec->unsol_hp_work);
+
+ snd_hda_sequence_write(codec, spec->chip_d3_verbs);
+
+ return 0;
+}
+
+static int cm9825_resume(struct hda_codec *codec)
+{
+ struct cmi_spec *spec = codec->spec;
+ hda_nid_t hp_pin = 0;
+ bool hp_jack_plugin = false;
+ int err;
+
+ err =
+ snd_hda_codec_write(spec->codec, 0x42, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
+ if (err)
+ codec_dbg(codec, "codec_write err %d\n", err);
+
+ msleep(150); /* for depop noise */
+
+ snd_hda_codec_init(codec);
+
+ hp_pin = spec->gen.autocfg.hp_pins[0];
+ hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
+
+ codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
+ (int)hp_jack_plugin, hp_pin);
+
+ if (!hp_jack_plugin) {
+ err =
+ snd_hda_codec_write(spec->codec, 0x42, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+
+ if (err)
+ codec_dbg(codec, "codec_write err %d\n", err);
+
+ snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
+ }
+
+ snd_hda_regmap_sync(codec);
+ hda_call_check_power_status(codec, 0x01);
+
+ return 0;
+}
+
+static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct cmi_spec *spec;
+ struct auto_pin_cfg *cfg;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
+ codec->spec = spec;
+ spec->codec = codec;
+ cfg = &spec->gen.autocfg;
+ snd_hda_gen_spec_init(&spec->gen);
+ spec->chip_d0_verbs = cm9825_std_d0_verbs;
+ spec->chip_d3_verbs = cm9825_std_d3_verbs;
+ spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
+ spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
+
+ snd_hda_sequence_write(codec, spec->chip_d0_verbs);
+
+ err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+ if (err < 0)
+ goto error;
+ err = snd_hda_gen_parse_auto_config(codec, cfg);
+ if (err < 0)
+ goto error;
+
+ cm9825_setup_unsol(codec);
+
+ return 0;
+
+ error:
+ cm9825_remove(codec);
+
+ codec_info(codec, "Enter err %d\n", err);
+
+ return err;
+}
+
+static const struct hda_codec_ops cm9825_codec_ops = {
+ .probe = cm9825_probe,
+ .remove = cm9825_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cm9825_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = cm9825_suspend,
+ .resume = cm9825_resume,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_cm9825[] = {
+ HDA_CODEC_ID(0x13f69825, "CM9825"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CM9825 HD-audio codec");
+
+static struct hda_codec_driver cm9825_driver = {
+ .id = snd_hda_id_cm9825,
+ .ops = &cm9825_codec_ops,
+};
+
+module_hda_codec_driver(cm9825_driver);
diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c
new file mode 100644
index 000000000000..15e5a1118a6e
--- /dev/null
+++ b/sound/hda/codecs/cmedia.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal codec driver for Intel High Definition Audio Codec
+ *
+ * HD audio codec driver for C-Media CMI9880
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct hda_gen_spec *spec;
+ struct auto_pin_cfg *cfg;
+ bool is_cmi8888 = id->vendor_id == 0x13f68888;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+ cfg = &spec->autocfg;
+ snd_hda_gen_spec_init(spec);
+
+ if (is_cmi8888) {
+ /* mask NID 0x10 from the playback volume selection;
+ * it's a headphone boost volume handled manually below
+ */
+ spec->out_vol_mask = (1ULL << 0x10);
+ }
+
+ err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+ if (err < 0)
+ goto error;
+ err = snd_hda_gen_parse_auto_config(codec, cfg);
+ if (err < 0)
+ goto error;
+
+ err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+ if (err < 0)
+ goto error;
+ err = snd_hda_gen_parse_auto_config(codec, cfg);
+ if (err < 0)
+ goto error;
+
+ if (is_cmi8888) {
+ if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
+ AC_JACK_HP_OUT) {
+ static const struct snd_kcontrol_new amp_kctl =
+ HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
+ 0x10, 0, HDA_OUTPUT);
+ if (!snd_hda_gen_add_kctl(spec, NULL, &amp_kctl)) {
+ err = -ENOMEM;
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops cmedia_codec_ops = {
+ .probe = cmedia_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = snd_hda_gen_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_cmedia[] = {
+ HDA_CODEC_ID(0x13f68888, "CMI8888"),
+ HDA_CODEC_ID(0x13f69880, "CMI9880"),
+ HDA_CODEC_ID(0x434d4980, "CMI9880"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("C-Media HD-audio codec");
+
+static struct hda_codec_driver cmedia_driver = {
+ .id = snd_hda_id_cmedia,
+ .ops = &cmedia_codec_ops,
+};
+
+module_hda_codec_driver(cmedia_driver);
diff --git a/sound/pci/hda/patch_conexant.c b/sound/hda/codecs/conexant.c
index a889cccdd607..5fcbc1312c69 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HD audio interface patch for Conexant HDA audio codec
+ * HD audio codec driver for Conexant HDA audio codec
*
* Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
* Takashi Iwai <tiwai@suse.de>
@@ -19,7 +19,7 @@
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
struct conexant_spec {
struct hda_gen_spec gen;
@@ -32,7 +32,7 @@ struct conexant_spec {
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
- /* OPLC XO specific */
+ /* OLPC XO specific */
bool recording;
bool dc_enable;
unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
@@ -42,7 +42,7 @@ struct conexant_spec {
unsigned int gpio_led;
unsigned int gpio_mute_led_mask;
unsigned int gpio_mic_led_mask;
-
+ bool is_cx11880_sn6140;
};
@@ -164,7 +164,28 @@ static void cxt_init_gpio_led(struct hda_codec *codec)
}
}
-static int cx_auto_init(struct hda_codec *codec)
+static void cx_fixup_headset_recog(struct hda_codec *codec)
+{
+ unsigned int mic_present;
+
+ /* fix some headset type recognize fail issue, such as EDIFIER headset */
+ /* set micbias output current comparator threshold from 66% to 55%. */
+ snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010);
+ /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register
+ * value adjustment trim from 2.2K ohms to 2.0K ohms.
+ */
+ snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10);
+ /* fix reboot headset type recognize fail issue */
+ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
+ if (mic_present & AC_PINSENSE_PRESENCE)
+ /* enable headset mic VREF */
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
+ else
+ /* disable headset mic VREF */
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
+}
+
+static int cx_init(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
snd_hda_gen_init(codec);
@@ -174,6 +195,9 @@ static int cx_auto_init(struct hda_codec *codec)
cxt_init_gpio_led(codec);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+ if (spec->is_cx11880_sn6140)
+ cx_fixup_headset_recog(codec);
+
return 0;
}
@@ -186,31 +210,59 @@ static void cx_auto_shutdown(struct hda_codec *codec)
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
}
-static void cx_auto_free(struct hda_codec *codec)
+static void cx_remove(struct hda_codec *codec)
{
cx_auto_shutdown(codec);
- snd_hda_gen_free(codec);
+ snd_hda_gen_remove(codec);
+}
+
+static void cx_process_headset_plugin(struct hda_codec *codec)
+{
+ unsigned int val;
+ unsigned int count = 0;
+
+ /* Wait headset detect done. */
+ do {
+ val = snd_hda_codec_read(codec, 0x1c, 0, 0xca0, 0x0);
+ if (val & 0x080) {
+ codec_dbg(codec, "headset type detect done!\n");
+ break;
+ }
+ msleep(20);
+ count++;
+ } while (count < 3);
+ val = snd_hda_codec_read(codec, 0x1c, 0, 0xcb0, 0x0);
+ if (val & 0x800) {
+ codec_dbg(codec, "headset plugin, type is CTIA\n");
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
+ } else if (val & 0x400) {
+ codec_dbg(codec, "headset plugin, type is OMTP\n");
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
+ } else {
+ codec_dbg(codec, "headphone plugin\n");
+ }
+}
+
+static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event)
+{
+ unsigned int mic_present;
+
+ /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled,
+ * the node 19 can only be configured to microphone or disabled.
+ * Check hp&mic tag to process headset plugin & plugout.
+ */
+ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
+ if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
+ else
+ cx_process_headset_plugin(codec);
}
-#ifdef CONFIG_PM
-static int cx_auto_suspend(struct hda_codec *codec)
+static int cx_suspend(struct hda_codec *codec)
{
cx_auto_shutdown(codec);
return 0;
}
-#endif
-
-static const struct hda_codec_ops cx_auto_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = cx_auto_init,
- .free = cx_auto_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = cx_auto_suspend,
- .check_power_status = snd_hda_gen_check_power_status,
-#endif
-};
/*
* pin fix-up
@@ -229,6 +281,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,
@@ -239,13 +292,20 @@ enum {
CXT_FIXUP_HP_SPECTRE,
CXT_FIXUP_HP_GATE_MIC,
CXT_FIXUP_MUTE_LED_GPIO,
+ CXT_FIXUP_HP_ELITEONE_OUT_DIS,
CXT_FIXUP_HP_ZBOOK_MUTE_LED,
CXT_FIXUP_HEADSET_MIC,
CXT_FIXUP_HP_MIC_NO_PRESENCE,
+ CXT_PINCFG_SWS_JS201D,
+ CXT_PINCFG_TOP_SPEAKER,
+ CXT_FIXUP_HP_A_U,
};
/* for hda_fixup_thinkpad_acpi() */
-#include "thinkpad_helper.c"
+#include "helpers/thinkpad.c"
+
+/* for hda_fixup_ideapad_acpi() */
+#include "helpers/ideapad_hotkey_led.c"
static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -254,6 +314,19 @@ static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
spec->gen.inv_dmic_split = 1;
}
+/* fix widget control pin settings */
+static void cxt_fixup_update_pinctl(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PROBE) {
+ /* Unset OUT_EN for this Node pin, leaving only HP_EN.
+ * This is the value stored in the codec register after
+ * the correct initialization of the previous windows boot.
+ */
+ snd_hda_set_pin_ctl_cache(codec, 0x1d, AC_PINCTL_HP_EN);
+ }
+}
+
static void cxt5066_increase_mic_boost(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -334,7 +407,7 @@ static void cxt_fixup_headset_mic(struct hda_codec *codec,
}
}
-/* OPLC XO 1.5 fixup */
+/* OLPC XO 1.5 fixup */
/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
* through the microphone jack.
@@ -696,6 +769,18 @@ static void cxt_setup_mute_led(struct hda_codec *codec,
}
}
+static void cxt_setup_gpio_unmute(struct hda_codec *codec,
+ unsigned int gpio_mute_mask)
+{
+ if (gpio_mute_mask) {
+ // set gpio data to 0.
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0);
+ }
+}
+
static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -710,6 +795,15 @@ static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
cxt_setup_mute_led(codec, 0x10, 0x20);
}
+static void cxt_fixup_hp_a_u(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ // Init vers in BIOS mute the spk/hp by set gpio high to avoid pop noise,
+ // so need to unmute once by clearing the gpio data when runs into the system.
+ if (action == HDA_FIXUP_ACT_INIT)
+ cxt_setup_gpio_unmute(codec, 0x2);
+}
+
/* ThinkPad X200 & co with cxt5051 */
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -739,6 +833,17 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = {
{}
};
+/* SuoWoSi/South-holding JS201D with sn6140 */
+static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
+ { 0x16, 0x03211040 }, /* hp out */
+ { 0x17, 0x91170110 }, /* SPK/Class_D */
+ { 0x18, 0x95a70130 }, /* Internal mic */
+ { 0x19, 0x03a11020 }, /* Headset Mic */
+ { 0x1a, 0x40f001f0 }, /* Not used */
+ { 0x21, 0x40f001f0 }, /* Not used */
+ {}
+};
+
static const struct hda_fixup cxt_fixups[] = {
[CXT_PINCFG_LENOVO_X200] = {
.type = HDA_FIXUP_PINS,
@@ -817,6 +922,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,
@@ -877,6 +988,10 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_mute_led_gpio,
},
+ [CXT_FIXUP_HP_ELITEONE_OUT_DIS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_update_pinctl,
+ },
[CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_hp_zbook_mute_led,
@@ -894,9 +1009,24 @@ static const struct hda_fixup cxt_fixups[] = {
.chained = true,
.chain_id = CXT_FIXUP_HEADSET_MIC,
},
+ [CXT_PINCFG_SWS_JS201D] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cxt_pincfg_sws_js201d,
+ },
+ [CXT_PINCFG_TOP_SPEAKER] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1d, 0x82170111 },
+ { }
+ },
+ },
+ [CXT_FIXUP_HP_A_U] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_hp_a_u,
+ },
};
-static const struct snd_pci_quirk cxt5045_fixups[] = {
+static const struct hda_quirk cxt5045_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
/* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
@@ -916,7 +1046,7 @@ static const struct hda_model_fixup cxt5045_fixup_models[] = {
{}
};
-static const struct snd_pci_quirk cxt5047_fixups[] = {
+static const struct hda_quirk cxt5047_fixups[] = {
/* HP laptops have really bad sound over 0 dB on NID 0x10.
*/
SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
@@ -928,7 +1058,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = {
{}
};
-static const struct snd_pci_quirk cxt5051_fixups[] = {
+static const struct hda_quirk cxt5051_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
{}
@@ -939,7 +1069,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = {
{}
};
-static const struct snd_pci_quirk cxt5066_fixups[] = {
+static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
@@ -950,6 +1080,7 @@ static const struct snd_pci_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),
@@ -959,6 +1090,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
+ SND_PCI_QUIRK(0x103c, 0x83e5, "HP EliteOne 1000 G2", CXT_FIXUP_HP_ELITEONE_OUT_DIS),
SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
@@ -967,6 +1099,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
+ SND_PCI_QUIRK(0x14f1, 0x0252, "MBX-Z60MR100", CXT_FIXUP_HP_A_U),
+ SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
@@ -986,9 +1120,11 @@ static const struct snd_pci_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),
+ HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER),
{}
};
@@ -998,6 +1134,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" },
@@ -1007,6 +1144,9 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
{ .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
{ .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
{ .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
+ { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" },
+ { .id = CXT_PINCFG_TOP_SPEAKER, .name = "sirius-top-speaker" },
+ { .id = CXT_FIXUP_HP_A_U, .name = "HP-U-support" },
{}
};
@@ -1028,7 +1168,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)
spec->gen.dac_min_mute = true;
}
-static int patch_conexant_auto(struct hda_codec *codec)
+static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
struct conexant_spec *spec;
int err;
@@ -1040,7 +1180,15 @@ static int patch_conexant_auto(struct hda_codec *codec)
return -ENOMEM;
snd_hda_gen_spec_init(&spec->gen);
codec->spec = spec;
- codec->patch_ops = cx_auto_patch_ops;
+
+ /* init cx11880/sn6140 flag and reset headset_present_flag */
+ switch (codec->core.vendor_id) {
+ case 0x14f11f86:
+ case 0x14f11f87:
+ spec->is_cx11880_sn6140 = true;
+ snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
+ break;
+ }
cx_auto_parse_eapd(codec);
spec->gen.own_eapd_ctl = 1;
@@ -1117,47 +1265,59 @@ static int patch_conexant_auto(struct hda_codec *codec)
return 0;
error:
- cx_auto_free(codec);
+ cx_remove(codec);
return err;
}
+static const struct hda_codec_ops cx_codec_ops = {
+ .probe = cx_probe,
+ .remove = cx_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cx_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = cx_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
/*
*/
static const struct hda_device_id snd_hda_id_conexant[] = {
- HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
+ HDA_CODEC_ID(0x14f11f86, "CX11880"),
+ HDA_CODEC_ID(0x14f11f87, "SN6140"),
+ HDA_CODEC_ID(0x14f12008, "CX8200"),
+ HDA_CODEC_ID(0x14f120d0, "CX11970"),
+ HDA_CODEC_ID(0x14f120d1, "SN6180"),
+ HDA_CODEC_ID(0x14f15045, "CX20549 (Venice)"),
+ HDA_CODEC_ID(0x14f15047, "CX20551 (Waikiki)"),
+ HDA_CODEC_ID(0x14f15051, "CX20561 (Hermosa)"),
+ HDA_CODEC_ID(0x14f15066, "CX20582 (Pebble)"),
+ HDA_CODEC_ID(0x14f15067, "CX20583 (Pebble HSF)"),
+ HDA_CODEC_ID(0x14f15068, "CX20584"),
+ HDA_CODEC_ID(0x14f15069, "CX20585"),
+ HDA_CODEC_ID(0x14f1506c, "CX20588"),
+ HDA_CODEC_ID(0x14f1506e, "CX20590"),
+ HDA_CODEC_ID(0x14f15097, "CX20631"),
+ HDA_CODEC_ID(0x14f15098, "CX20632"),
+ HDA_CODEC_ID(0x14f150a1, "CX20641"),
+ HDA_CODEC_ID(0x14f150a2, "CX20642"),
+ HDA_CODEC_ID(0x14f150ab, "CX20651"),
+ HDA_CODEC_ID(0x14f150ac, "CX20652"),
+ HDA_CODEC_ID(0x14f150b8, "CX20664"),
+ HDA_CODEC_ID(0x14f150b9, "CX20665"),
+ HDA_CODEC_ID(0x14f150f1, "CX21722"),
+ HDA_CODEC_ID(0x14f150f2, "CX20722"),
+ HDA_CODEC_ID(0x14f150f3, "CX21724"),
+ HDA_CODEC_ID(0x14f150f4, "CX20724"),
+ HDA_CODEC_ID(0x14f1510f, "CX20751/2"),
+ HDA_CODEC_ID(0x14f15110, "CX20751/2"),
+ HDA_CODEC_ID(0x14f15111, "CX20753/4"),
+ HDA_CODEC_ID(0x14f15113, "CX20755"),
+ HDA_CODEC_ID(0x14f15114, "CX20756"),
+ HDA_CODEC_ID(0x14f15115, "CX20757"),
+ HDA_CODEC_ID(0x14f151d7, "CX20952"),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
@@ -1167,6 +1327,7 @@ MODULE_DESCRIPTION("Conexant HD-audio codec");
static struct hda_codec_driver conexant_driver = {
.id = snd_hda_id_conexant,
+ .ops = &cx_codec_ops,
};
module_hda_codec_driver(conexant_driver);
diff --git a/sound/pci/hda/hda_generic.c b/sound/hda/codecs/generic.c
index dbf7aa88e0e3..7bcf9aef8275 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/hda/codecs/generic.c
@@ -25,7 +25,7 @@
#include "hda_auto_parser.h"
#include "hda_jack.h"
#include "hda_beep.h"
-#include "hda_generic.h"
+#include "generic.h"
/**
@@ -998,7 +998,11 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
const char *sfx, int cidx, unsigned long val)
{
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
- snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+ int len;
+
+ len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+ if (snd_BUG_ON(len >= sizeof(name)))
+ return -EINVAL;
if (!add_control(spec, type, name, cidx, val))
return -ENOMEM;
return 0;
@@ -1114,12 +1118,11 @@ static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
unsigned long pval;
int err;
- mutex_lock(&codec->control_mutex);
+ guard(mutex)(&codec->control_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
return err;
}
@@ -1132,7 +1135,7 @@ static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
sync_auto_mute_bits(kcontrol, ucontrol);
- mutex_lock(&codec->control_mutex);
+ guard(mutex)(&codec->control_mutex);
pval = kcontrol->private_value;
indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
for (i = 0; i < indices; i++) {
@@ -1144,7 +1147,6 @@ static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
change |= err;
}
kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
@@ -1379,7 +1381,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs,
struct nid_path *path;
hda_nid_t pin = pins[i];
- if (!spec->obey_preferred_dacs) {
+ if (!spec->preferred_dacs) {
path = snd_hda_get_path_from_idx(codec, path_idx[i]);
if (path) {
badness += assign_out_path_ctls(codec, path);
@@ -1391,7 +1393,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs,
if (dacs[i]) {
if (is_dac_already_used(codec, dacs[i]))
badness += bad->shared_primary;
- } else if (spec->obey_preferred_dacs) {
+ } else if (spec->preferred_dacs) {
badness += BAD_NO_PRIMARY_DAC;
}
@@ -1982,7 +1984,7 @@ static int parse_output_paths(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- struct auto_pin_cfg *best_cfg;
+ struct auto_pin_cfg *best_cfg __free(kfree) = NULL;
unsigned int val;
int best_badness = INT_MAX;
int badness;
@@ -1998,10 +2000,8 @@ static int parse_output_paths(struct hda_codec *codec)
for (;;) {
badness = fill_and_eval_dacs(codec, fill_hardwired,
fill_mio_first);
- if (badness < 0) {
- kfree(best_cfg);
+ if (badness < 0)
return badness;
- }
debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
cfg->line_out_type, fill_hardwired, fill_mio_first,
badness);
@@ -2094,7 +2094,6 @@ static int parse_output_paths(struct hda_codec *codec)
if (spec->indep_hp && !indep_hp_possible(codec))
spec->indep_hp = 0;
- kfree(best_cfg);
return 0;
}
@@ -2245,11 +2244,9 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol,
unsigned int select = ucontrol->value.enumerated.item[0];
int ret = 0;
- mutex_lock(&spec->pcm_mutex);
- if (spec->active_streams) {
- ret = -EBUSY;
- goto unlock;
- }
+ guard(mutex)(&spec->pcm_mutex);
+ if (spec->active_streams)
+ return -EBUSY;
if (spec->indep_hp_enabled != select) {
hda_nid_t *dacp;
@@ -2281,8 +2278,6 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol,
call_hp_automute(codec, NULL);
ret = 1;
}
- unlock:
- mutex_unlock(&spec->pcm_mutex);
return ret;
}
@@ -2824,7 +2819,7 @@ static int in_jack_mode_info(struct snd_kcontrol *kcontrol,
snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps),
vref_texts);
/* set the right text */
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]);
return 0;
}
@@ -2937,7 +2932,7 @@ static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
text = "Mic In";
}
- strcpy(uinfo->value.enumerated.name, text);
+ strscpy(uinfo->value.enumerated.name, text);
return 0;
}
@@ -3471,22 +3466,20 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol,
imux = &spec->input_mux;
adc_idx = kcontrol->id.index;
- mutex_lock(&codec->control_mutex);
- for (i = 0; i < imux->num_items; i++) {
- path = get_input_path(codec, adc_idx, i);
- if (!path || !path->ctls[type])
- continue;
- kcontrol->private_value = path->ctls[type];
- ret = func(kcontrol, ucontrol);
- if (ret < 0) {
- err = ret;
- break;
+ scoped_guard(mutex, &codec->control_mutex) {
+ for (i = 0; i < imux->num_items; i++) {
+ path = get_input_path(codec, adc_idx, i);
+ if (!path || !path->ctls[type])
+ continue;
+ kcontrol->private_value = path->ctls[type];
+ ret = func(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ err = 1;
}
- if (ret > 0)
- err = 1;
}
- mutex_unlock(&codec->control_mutex);
- if (err >= 0 && spec->cap_sync_hook)
+ if (spec->cap_sync_hook)
spec->cap_sync_hook(codec, kcontrol, ucontrol);
return err;
}
@@ -3942,7 +3935,6 @@ static int create_mute_led_cdev(struct hda_codec *codec,
cdev->max_brightness = 1;
cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
cdev->brightness_set_blocking = callback;
- cdev->brightness = ledtrig_audio_get(idx);
cdev->flags = LED_CORE_SUSPENDRESUME;
err = led_classdev_register(&codec->core.dev, cdev);
@@ -4943,7 +4935,7 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
* @nid: audio widget
* @on: power on/off flag
*
- * Set this in patch_ops.stream_pm. Only valid with power_save_node flag.
+ * Set this in hda_codec_ops.stream_pm. Only valid with power_save_node flag.
*/
void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
{
@@ -4952,6 +4944,69 @@ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
}
EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
+/* forcibly mute the speaker output without caching; return true if updated */
+static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid)
+{
+ if (!nid)
+ return false;
+ if (!nid_has_mute(codec, nid, HDA_OUTPUT))
+ return false; /* no mute, skip */
+ if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+ snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) &
+ HDA_AMP_MUTE)
+ return false; /* both channels already muted, skip */
+
+ /* direct amp update without caching */
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT |
+ AC_AMP_SET_RIGHT | HDA_AMP_MUTE);
+ return true;
+}
+
+/**
+ * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs
+ * @codec: the HDA codec
+ *
+ * Forcibly mute the speaker outputs, to be called at suspend or shutdown.
+ *
+ * The mute state done by this function isn't cached, hence the original state
+ * will be restored at resume.
+ *
+ * Return true if the mute state has been changed.
+ */
+bool snd_hda_gen_shutup_speakers(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ const int *paths;
+ const struct nid_path *path;
+ int i, p, num_paths;
+ bool updated = false;
+
+ /* if already powered off, do nothing */
+ if (!snd_hdac_is_power_on(&codec->core))
+ return false;
+
+ if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
+ paths = spec->out_paths;
+ num_paths = spec->autocfg.line_outs;
+ } else {
+ paths = spec->speaker_paths;
+ num_paths = spec->autocfg.speaker_outs;
+ }
+
+ for (i = 0; i < num_paths; i++) {
+ path = snd_hda_get_path_from_idx(codec, paths[i]);
+ if (!path)
+ continue;
+ for (p = 0; p < path->depth; p++)
+ if (force_mute_output_path(codec, path->path[p]))
+ updated = true;
+ }
+
+ return updated;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers);
+
/**
* snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
* set up the hda_gen_spec
@@ -5124,8 +5179,6 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
if (spec->power_down_unused || codec->power_save_node) {
if (!codec->power_filter)
codec->power_filter = snd_hda_gen_path_power_filter;
- if (!codec->patch_ops.stream_pm)
- codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
}
if (!spec->no_analog && spec->beep_nid) {
@@ -5164,7 +5217,7 @@ static const char * const follower_pfxs[] = {
* snd_hda_gen_build_controls - Build controls from the parsed results
* @codec: the HDA codec
*
- * Pass this to build_controls patch_ops.
+ * Pass this to build_controls hda_codec_ops.
*/
int snd_hda_gen_build_controls(struct hda_codec *codec)
{
@@ -5268,17 +5321,17 @@ static int playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_gen_spec *spec = codec->spec;
int err;
- mutex_lock(&spec->pcm_mutex);
+ guard(mutex)(&spec->pcm_mutex);
err = snd_hda_multi_out_analog_open(codec,
&spec->multiout, substream,
hinfo);
- if (!err) {
- spec->active_streams |= 1 << STREAM_MULTI_OUT;
- call_pcm_playback_hook(hinfo, codec, substream,
- HDA_GEN_PCM_ACT_OPEN);
- }
- mutex_unlock(&spec->pcm_mutex);
- return err;
+ if (err < 0)
+ return err;
+
+ spec->active_streams |= 1 << STREAM_MULTI_OUT;
+ call_pcm_playback_hook(hinfo, codec, substream,
+ HDA_GEN_PCM_ACT_OPEN);
+ return 0;
}
static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -5317,11 +5370,11 @@ static int playback_pcm_close(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct hda_gen_spec *spec = codec->spec;
- mutex_lock(&spec->pcm_mutex);
+
+ guard(mutex)(&spec->pcm_mutex);
spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
call_pcm_playback_hook(hinfo, codec, substream,
HDA_GEN_PCM_ACT_CLOSE);
- mutex_unlock(&spec->pcm_mutex);
return 0;
}
@@ -5370,14 +5423,13 @@ static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_gen_spec *spec = codec->spec;
int err = 0;
- mutex_lock(&spec->pcm_mutex);
+ guard(mutex)(&spec->pcm_mutex);
if (spec->indep_hp && !spec->indep_hp_enabled)
err = -EBUSY;
else
spec->active_streams |= 1 << STREAM_INDEP_HP;
call_pcm_playback_hook(hinfo, codec, substream,
HDA_GEN_PCM_ACT_OPEN);
- mutex_unlock(&spec->pcm_mutex);
return err;
}
@@ -5386,11 +5438,11 @@ static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct hda_gen_spec *spec = codec->spec;
- mutex_lock(&spec->pcm_mutex);
+
+ guard(mutex)(&spec->pcm_mutex);
spec->active_streams &= ~(1 << STREAM_INDEP_HP);
call_pcm_playback_hook(hinfo, codec, substream,
HDA_GEN_PCM_ACT_CLOSE);
- mutex_unlock(&spec->pcm_mutex);
return 0;
}
@@ -5677,7 +5729,7 @@ static void setup_pcm_stream(struct hda_pcm_stream *str,
* snd_hda_gen_build_pcms - build PCM streams based on the parsed results
* @codec: the HDA codec
*
- * Pass this to build_pcms patch_ops.
+ * Pass this to build_pcms hda_codec_ops.
*/
int snd_hda_gen_build_pcms(struct hda_codec *codec)
{
@@ -5966,7 +6018,7 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec)
* snd_hda_gen_init - initialize the generic spec
* @codec: the HDA codec
*
- * This can be put as patch_ops init function.
+ * This can be put as hda_codec_ops init function.
*/
int snd_hda_gen_init(struct hda_codec *codec)
{
@@ -6004,27 +6056,26 @@ int snd_hda_gen_init(struct hda_codec *codec)
EXPORT_SYMBOL_GPL(snd_hda_gen_init);
/**
- * snd_hda_gen_free - free the generic spec
+ * snd_hda_gen_remove - free the generic spec
* @codec: the HDA codec
*
- * This can be put as patch_ops free function.
+ * This can be put as hda_codec_ops remove function.
*/
-void snd_hda_gen_free(struct hda_codec *codec)
+void snd_hda_gen_remove(struct hda_codec *codec)
{
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
snd_hda_gen_spec_free(codec->spec);
kfree(codec->spec);
codec->spec = NULL;
}
-EXPORT_SYMBOL_GPL(snd_hda_gen_free);
+EXPORT_SYMBOL_GPL(snd_hda_gen_remove);
-#ifdef CONFIG_PM
/**
* snd_hda_gen_check_power_status - check the loopback power save state
* @codec: the HDA codec
* @nid: NID to inspect
*
- * This can be put as patch_ops check_power_status function.
+ * This can be put as hda_codec_ops check_power_status function.
*/
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
@@ -6032,29 +6083,14 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
}
EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
-#endif
/*
* the generic codec support
*/
-static const struct hda_codec_ops generic_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = snd_hda_gen_init,
- .free = snd_hda_gen_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .check_power_status = snd_hda_gen_check_power_status,
-#endif
-};
-
-/*
- * snd_hda_parse_generic_codec - Generic codec parser
- * @codec: the HDA codec
- */
-static int snd_hda_parse_generic_codec(struct hda_codec *codec)
+static int snd_hda_gen_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
{
struct hda_gen_spec *spec;
int err;
@@ -6073,22 +6109,34 @@ static int snd_hda_parse_generic_codec(struct hda_codec *codec)
if (err < 0)
goto error;
- codec->patch_ops = generic_patch_ops;
return 0;
error:
- snd_hda_gen_free(codec);
+ snd_hda_gen_remove(codec);
return err;
}
+static const struct hda_codec_ops generic_codec_ops = {
+ .probe = snd_hda_gen_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = snd_hda_gen_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
static const struct hda_device_id snd_hda_id_generic[] = {
- HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
+ HDA_CODEC_ID(0x1af40021, "Generic"), /* QEMU */
+ HDA_CODEC_ID(HDA_CODEC_ID_GENERIC, "Generic"),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
static struct hda_codec_driver generic_driver = {
.id = snd_hda_id_generic,
+ .ops = &generic_codec_ops,
};
module_hda_codec_driver(generic_driver);
diff --git a/sound/pci/hda/hda_generic.h b/sound/hda/codecs/generic.h
index 34eba40cc6e6..524591821f8c 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/hda/codecs/generic.h
@@ -9,6 +9,9 @@
#define __SOUND_HDA_GENERIC_H
#include <linux/leds.h>
+#include "hda_auto_parser.h"
+
+struct hda_jack_callback;
/* table entry for multi-io paths */
struct hda_multi_io {
@@ -229,7 +232,6 @@ struct hda_gen_spec {
unsigned int power_down_unused:1; /* power down unused widgets */
unsigned int dac_min_mute:1; /* minimal = mute for DACs */
unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
- unsigned int obey_preferred_dacs:1; /* obey preferred_dacs assignment */
/* other internal flags */
unsigned int no_analog:1; /* digital I/O only */
@@ -309,7 +311,7 @@ enum {
int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
int snd_hda_gen_init(struct hda_codec *codec);
-void snd_hda_gen_free(struct hda_codec *codec);
+void snd_hda_gen_remove(struct hda_codec *codec);
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
@@ -337,9 +339,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
struct hda_jack_callback *jack);
void snd_hda_gen_update_outputs(struct hda_codec *codec);
-#ifdef CONFIG_PM
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
-#endif
unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state);
@@ -352,5 +352,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
int (*callback)(struct led_classdev *,
enum led_brightness));
+bool snd_hda_gen_shutup_speakers(struct hda_codec *codec);
#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/hda/codecs/hdmi/Kconfig b/sound/hda/codecs/hdmi/Kconfig
new file mode 100644
index 000000000000..6ea3553ba9f8
--- /dev/null
+++ b/sound/hda/codecs/hdmi/Kconfig
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig SND_HDA_CODEC_HDMI
+ tristate "HD-audio HDMI codec support"
+ help
+ Say Y or M here to include HD-audio HDMI/DislayPort codec support.
+
+ This will enable all HDMI/DP codec drivers as default, but you can
+ enable/disable each codec driver individually, too (only when
+ CONFIG_EXPERT is set).
+
+if SND_HDA_CODEC_HDMI
+
+config SND_HDA_CODEC_HDMI_GENERIC
+ tristate "Generic HDMI/DisplayPort HD-audio codec support" if EXPERT
+ select SND_DYNAMIC_MINORS
+ select SND_PCM_ELD
+ default y
+ help
+ Say Y or M here to include Generic HDMI and DisplayPort HD-audio
+ codec support.
+
+ Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS
+ to assure the multiple streams for DP-MST support.
+
+config SND_HDA_CODEC_HDMI_SIMPLE
+ tristate "Simple HDMI/DisplayPort HD-audio codec support" if EXPERT
+ default y
+ help
+ Say Y or M here to include Simple HDMI and DisplayPort HD-audio
+ codec support for VIA and other codecs.
+
+config SND_HDA_CODEC_HDMI_INTEL
+ tristate "Intel HDMI/DisplayPort HD-audio codec support" if EXPERT
+ select SND_HDA_CODEC_HDMI_GENERIC
+ default y
+ help
+ Say Y or M here to include Intel graphics HDMI and DisplayPort
+ HD-audio codec support.
+
+config SND_HDA_INTEL_HDMI_SILENT_STREAM
+ bool "Enable Silent Stream always for HDMI"
+ depends on SND_HDA_CODEC_HDMI_INTEL
+ help
+ Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
+ for HDMI on hardware that supports the feature.
+
+ When enabled, the HDMI/DisplayPort codec will continue to provide
+ a continuous clock and a valid but silent data stream to
+ any connected external receiver. This allows to avoid gaps
+ at start of playback. Many receivers require multiple seconds
+ to start playing audio after the clock has been stopped.
+ This feature can impact power consumption as resources
+ are kept reserved both at transmitter and receiver.
+
+config SND_HDA_CODEC_HDMI_ATI
+ tristate "AMD/ATI HDMI/DisplayPort HD-audio codec support" if EXPERT
+ select SND_HDA_CODEC_HDMI_GENERIC
+ default y
+ help
+ Say Y or M here to include AMD/ATI graphics HDMI and DisplayPort
+ HD-audio codec support.
+
+config SND_HDA_CODEC_HDMI_NVIDIA
+ tristate "Nvidia HDMI/DisplayPort HD-audio codec support" if EXPERT
+ select SND_HDA_CODEC_HDMI_GENERIC
+ default y
+ help
+ Say Y or M here to include HDMI and DisplayPort HD-audio codec
+ support for the recent Nvidia graphics cards.
+
+config SND_HDA_CODEC_HDMI_NVIDIA_MCP
+ tristate "Legacy Nvidia HDMI/DisplayPort HD-audio codec support" if EXPERT
+ select SND_HDA_CODEC_HDMI_SIMPLE
+ default y
+ help
+ Say Y or M here to include HDMI and DisplayPort HD-audio codec
+ support for the legacy Nvidia graphics like MCP73, MCP67, MCP77/78.
+
+config SND_HDA_CODEC_HDMI_TEGRA
+ tristate "Nvidia Tegra HDMI/DisplayPort HD-audio codec support" if EXPERT
+ select SND_HDA_CODEC_HDMI_GENERIC
+ default y
+ help
+ Say Y or M here to include HDMI and DisplayPort HD-audio codec
+ support for Nvidia Tegra.
+
+endif
diff --git a/sound/hda/codecs/hdmi/Makefile b/sound/hda/codecs/hdmi/Makefile
new file mode 100644
index 000000000000..0e49a9421e3b
--- /dev/null
+++ b/sound/hda/codecs/hdmi/Makefile
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-hdmi-y := hdmi.o eld.o
+snd-hda-codec-simplehdmi-y := simplehdmi.o
+snd-hda-codec-intelhdmi-y := intelhdmi.o
+snd-hda-codec-atihdmi-y := atihdmi.o
+snd-hda-codec-nvhdmi-y := nvhdmi.o
+snd-hda-codec-nvhdmi-mcp-y := nvhdmi-mcp.o
+snd-hda-codec-tegrahdmi-y := tegrahdmi.o
+
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_GENERIC) += snd-hda-codec-hdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_SIMPLE) += snd-hda-codec-simplehdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_INTEL) += snd-hda-codec-intelhdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_ATI) += snd-hda-codec-atihdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_NVIDIA) += snd-hda-codec-nvhdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP) += snd-hda-codec-nvhdmi-mcp.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_TEGRA) += snd-hda-codec-tegrahdmi.o
diff --git a/sound/hda/codecs/hdmi/atihdmi.c b/sound/hda/codecs/hdmi/atihdmi.c
new file mode 100644
index 000000000000..44366f75de33
--- /dev/null
+++ b/sound/hda/codecs/hdmi/atihdmi.c
@@ -0,0 +1,615 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ATI/AMD codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/unaligned.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+#define is_amdhdmi_rev3_or_later(codec) \
+ ((codec)->core.vendor_id == 0x1002aa01 && \
+ ((codec)->core.revision_id & 0xff00) >= 0x0300)
+#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
+
+/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
+#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771
+#define ATI_VERB_SET_DOWNMIX_INFO 0x772
+#define ATI_VERB_SET_MULTICHANNEL_01 0x777
+#define ATI_VERB_SET_MULTICHANNEL_23 0x778
+#define ATI_VERB_SET_MULTICHANNEL_45 0x779
+#define ATI_VERB_SET_MULTICHANNEL_67 0x77a
+#define ATI_VERB_SET_HBR_CONTROL 0x77c
+#define ATI_VERB_SET_MULTICHANNEL_1 0x785
+#define ATI_VERB_SET_MULTICHANNEL_3 0x786
+#define ATI_VERB_SET_MULTICHANNEL_5 0x787
+#define ATI_VERB_SET_MULTICHANNEL_7 0x788
+#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
+#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71
+#define ATI_VERB_GET_DOWNMIX_INFO 0xf72
+#define ATI_VERB_GET_MULTICHANNEL_01 0xf77
+#define ATI_VERB_GET_MULTICHANNEL_23 0xf78
+#define ATI_VERB_GET_MULTICHANNEL_45 0xf79
+#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a
+#define ATI_VERB_GET_HBR_CONTROL 0xf7c
+#define ATI_VERB_GET_MULTICHANNEL_1 0xf85
+#define ATI_VERB_GET_MULTICHANNEL_3 0xf86
+#define ATI_VERB_GET_MULTICHANNEL_5 0xf87
+#define ATI_VERB_GET_MULTICHANNEL_7 0xf88
+#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89
+
+/* AMD specific HDA cvt verbs */
+#define ATI_VERB_SET_RAMP_RATE 0x770
+#define ATI_VERB_GET_RAMP_RATE 0xf70
+
+#define ATI_OUT_ENABLE 0x1
+
+#define ATI_MULTICHANNEL_MODE_PAIRED 0
+#define ATI_MULTICHANNEL_MODE_SINGLE 1
+
+#define ATI_HBR_CAPABLE 0x01
+#define ATI_HBR_ENABLE 0x10
+
+/* ATI/AMD specific ELD emulation */
+
+#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776
+#define ATI_VERB_SET_SINK_INFO_INDEX 0x780
+#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70
+#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76
+#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
+#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80
+#define ATI_VERB_GET_SINK_INFO_DATA 0xf81
+
+#define ATI_SPKALLOC_SPKALLOC 0x007f
+#define ATI_SPKALLOC_TYPE_HDMI 0x0100
+#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200
+
+/* first three bytes are just standard SAD */
+#define ATI_AUDIODESC_CHANNELS 0x00000007
+#define ATI_AUDIODESC_RATES 0x0000ff00
+#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000
+
+/* in standard HDMI VSDB format */
+#define ATI_DELAY_VIDEO_LATENCY 0x000000ff
+#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00
+
+enum ati_sink_info_idx {
+ ATI_INFO_IDX_MANUFACTURER_ID = 0,
+ ATI_INFO_IDX_PRODUCT_ID = 1,
+ ATI_INFO_IDX_SINK_DESC_LEN = 2,
+ ATI_INFO_IDX_PORT_ID_LOW = 3,
+ ATI_INFO_IDX_PORT_ID_HIGH = 4,
+ ATI_INFO_IDX_SINK_DESC_FIRST = 5,
+ ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */
+};
+
+static int get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char *buf, int *eld_size, bool rev3_or_later)
+{
+ int spkalloc, ati_sad, aud_synch;
+ int sink_desc_len = 0;
+ int pos, i;
+
+ /* ATI/AMD does not have ELD, emulate it */
+
+ spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
+
+ if (spkalloc <= 0) {
+ codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
+ return -EINVAL;
+ }
+
+ memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
+
+ /* version */
+ buf[0] = ELD_VER_CEA_861D << 3;
+
+ /* speaker allocation from EDID */
+ buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
+
+ /* is DisplayPort? */
+ if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
+ buf[5] |= 0x04;
+
+ pos = ELD_FIXED_BYTES;
+
+ if (rev3_or_later) {
+ int sink_info;
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le32(sink_info, buf + 8);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le32(sink_info, buf + 12);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le16(sink_info, buf + 16);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le16(sink_info, buf + 18);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
+ sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+
+ if (sink_desc_len > ELD_MAX_MNL) {
+ codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
+ sink_desc_len);
+ sink_desc_len = ELD_MAX_MNL;
+ }
+
+ buf[4] |= sink_desc_len;
+
+ for (i = 0; i < sink_desc_len; i++) {
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
+ buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ }
+ }
+
+ for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
+ if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
+ continue; /* not handled by ATI/AMD */
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
+ ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
+
+ if (ati_sad <= 0)
+ continue;
+
+ if (ati_sad & ATI_AUDIODESC_RATES) {
+ /* format is supported, copy SAD as-is */
+ buf[pos++] = (ati_sad & 0x0000ff) >> 0;
+ buf[pos++] = (ati_sad & 0x00ff00) >> 8;
+ buf[pos++] = (ati_sad & 0xff0000) >> 16;
+ }
+
+ if (i == AUDIO_CODING_TYPE_LPCM
+ && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
+ && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
+ /* for PCM there is a separate stereo rate mask */
+ buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
+ /* rates from the extra byte */
+ buf[pos++] = (ati_sad & 0xff000000) >> 24;
+ buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
+ }
+ }
+
+ if (pos == ELD_FIXED_BYTES + sink_desc_len) {
+ codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
+ return -EINVAL;
+ }
+
+ /*
+ * HDMI VSDB latency format:
+ * separately for both audio and video:
+ * 0 field not valid or unknown latency
+ * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb)
+ * 255 audio/video not supported
+ *
+ * HDA latency format:
+ * single value indicating video latency relative to audio:
+ * 0 unknown or 0ms
+ * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa)
+ * [251..255] reserved
+ */
+ aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
+ if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
+ int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
+ int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
+
+ if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
+ video_latency_hdmi > audio_latency_hdmi)
+ buf[6] = video_latency_hdmi - audio_latency_hdmi;
+ /* else unknown/invalid or 0ms or video ahead of audio, so use zero */
+ }
+
+ /* SAD count */
+ buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
+
+ /* Baseline ELD block length is 4-byte aligned */
+ pos = round_up(pos, 4);
+
+ /* Baseline ELD length (4-byte header is not counted in) */
+ buf[2] = (pos - 4) / 4;
+
+ *eld_size = pos;
+
+ return 0;
+}
+
+static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+ int dev_id, unsigned char *buf, int *eld_size)
+{
+ WARN_ON(dev_id != 0);
+ /* call hda_eld.c ATI/AMD-specific function */
+ return get_eld_ati(codec, nid, buf, eld_size,
+ is_amdhdmi_rev3_or_later(codec));
+}
+
+static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id, int ca,
+ int active_channels, int conn_type)
+{
+ WARN_ON(dev_id != 0);
+ snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
+}
+
+static int atihdmi_paired_swap_fc_lfe(int pos)
+{
+ /*
+ * ATI/AMD have automatic FC/LFE swap built-in
+ * when in pairwise mapping mode.
+ */
+
+ switch (pos) {
+ /* see channel_allocations[].speakers[] */
+ case 2: return 3;
+ case 3: return 2;
+ default: return pos;
+ }
+}
+
+static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
+ int ca, int chs, unsigned char *map)
+{
+ struct hdac_cea_channel_speaker_allocation *cap;
+ int i, j;
+
+ /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
+
+ cap = snd_hdac_get_ch_alloc_from_ca(ca);
+ for (i = 0; i < chs; ++i) {
+ int mask = snd_hdac_chmap_to_spk_mask(map[i]);
+ bool ok = false;
+ bool companion_ok = false;
+
+ if (!mask)
+ continue;
+
+ for (j = 0 + i % 2; j < 8; j += 2) {
+ int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
+
+ if (cap->speakers[chan_idx] == mask) {
+ /* channel is in a supported position */
+ ok = true;
+
+ if (i % 2 == 0 && i + 1 < chs) {
+ /* even channel, check the odd companion */
+ int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
+ int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
+ int comp_mask_act = cap->speakers[comp_chan_idx];
+
+ if (comp_mask_req == comp_mask_act)
+ companion_ok = true;
+ else
+ return -EINVAL;
+ }
+ break;
+ }
+ }
+
+ if (!ok)
+ return -EINVAL;
+
+ if (companion_ok)
+ i++; /* companion channel already checked */
+ }
+
+ return 0;
+}
+
+static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
+ hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
+{
+ struct hda_codec *codec = hdac_to_hda_codec(hdac);
+ int verb;
+ int ati_channel_setup = 0;
+
+ if (hdmi_slot > 7)
+ return -EINVAL;
+
+ if (!has_amd_full_remap_support(codec)) {
+ hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
+
+ /* In case this is an odd slot but without stream channel, do not
+ * disable the slot since the corresponding even slot could have a
+ * channel. In case neither have a channel, the slot pair will be
+ * disabled when this function is called for the even slot.
+ */
+ if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
+ return 0;
+
+ hdmi_slot -= hdmi_slot % 2;
+
+ if (stream_channel != 0xf)
+ stream_channel -= stream_channel % 2;
+ }
+
+ verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
+
+ /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
+
+ if (stream_channel != 0xf)
+ ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
+
+ return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
+}
+
+static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
+ hda_nid_t pin_nid, int asp_slot)
+{
+ struct hda_codec *codec = hdac_to_hda_codec(hdac);
+ bool was_odd = false;
+ int ati_asp_slot = asp_slot;
+ int verb;
+ int ati_channel_setup;
+
+ if (asp_slot > 7)
+ return -EINVAL;
+
+ if (!has_amd_full_remap_support(codec)) {
+ ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
+ if (ati_asp_slot % 2 != 0) {
+ ati_asp_slot -= 1;
+ was_odd = true;
+ }
+ }
+
+ verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
+
+ ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
+
+ if (!(ati_channel_setup & ATI_OUT_ENABLE))
+ return 0xf;
+
+ return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
+}
+
+static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
+ struct hdac_chmap *chmap,
+ struct hdac_cea_channel_speaker_allocation *cap,
+ int channels)
+{
+ int c;
+
+ /*
+ * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
+ * we need to take that into account (a single channel may take 2
+ * channel slots if we need to carry a silent channel next to it).
+ * On Rev3+ AMD codecs this function is not used.
+ */
+ int chanpairs = 0;
+
+ /* We only produce even-numbered channel count TLVs */
+ if ((channels % 2) != 0)
+ return -1;
+
+ for (c = 0; c < 7; c += 2) {
+ if (cap->speakers[c] || cap->speakers[c+1])
+ chanpairs++;
+ }
+
+ if (chanpairs * 2 != channels)
+ return -1;
+
+ return SNDRV_CTL_TLVT_CHMAP_PAIRED;
+}
+
+static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
+ struct hdac_cea_channel_speaker_allocation *cap,
+ unsigned int *chmap, int channels)
+{
+ /* produce paired maps for pre-rev3 ATI/AMD codecs */
+ int count = 0;
+ int c;
+
+ for (c = 7; c >= 0; c--) {
+ int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
+ int spk = cap->speakers[chan];
+
+ if (!spk) {
+ /* add N/A channel if the companion channel is occupied */
+ if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
+ chmap[count++] = SNDRV_CHMAP_NA;
+
+ continue;
+ }
+
+ chmap[count++] = snd_hdac_spk_to_chmap(spk);
+ }
+
+ WARN_ON(count != channels);
+}
+
+static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+ int dev_id, bool hbr)
+{
+ int hbr_ctl, hbr_ctl_new;
+
+ WARN_ON(dev_id != 0);
+
+ hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
+ if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
+ if (hbr)
+ hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
+ else
+ hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
+
+ codec_dbg(codec,
+ "%s: NID=0x%x, %shbr-ctl=0x%x\n",
+ __func__,
+ pin_nid,
+ hbr_ctl == hbr_ctl_new ? "" : "new-",
+ hbr_ctl_new);
+
+ if (hbr_ctl != hbr_ctl_new)
+ snd_hda_codec_write(codec, pin_nid, 0,
+ ATI_VERB_SET_HBR_CONTROL,
+ hbr_ctl_new);
+
+ } else if (hbr)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, int dev_id,
+ u32 stream_tag, int format)
+{
+ if (is_amdhdmi_rev3_or_later(codec)) {
+ int ramp_rate = 180; /* default as per AMD spec */
+ /* disable ramp-up/down for non-pcm as per AMD spec */
+ if (format & AC_FMT_TYPE_NON_PCM)
+ ramp_rate = 0;
+
+ snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
+ }
+
+ return snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+ stream_tag, format);
+}
+
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx, err;
+
+ err = snd_hda_hdmi_generic_init(codec);
+
+ if (err)
+ return err;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+ /* make sure downmix information in infoframe is zero */
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
+
+ /* enable channel-wise remap mode if supported */
+ if (has_amd_full_remap_support(codec))
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ ATI_VERB_SET_MULTICHANNEL_MODE,
+ ATI_MULTICHANNEL_MODE_SINGLE);
+ }
+ codec->auto_runtime_pm = 1;
+
+ return 0;
+}
+
+/* map from pin NID to port; port is 0-based */
+/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
+static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
+{
+ return pin_nid / 2 - 1;
+}
+
+/* reverse-map from port to pin NID: see above */
+static int atihdmi_port2pin(struct hda_codec *codec, int port)
+{
+ return port * 2 + 3;
+}
+
+static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
+ .pin2port = atihdmi_pin2port,
+ .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify,
+ .master_bind = snd_hda_hdmi_acomp_master_bind,
+ .master_unbind = snd_hda_hdmi_acomp_master_unbind,
+};
+
+static int atihdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct hdmi_spec *spec;
+ struct hdmi_spec_per_cvt *per_cvt;
+ int err, cvt_idx;
+
+ err = snd_hda_hdmi_generic_probe(codec);
+ if (err)
+ return err;
+
+ spec = codec->spec;
+
+ spec->static_pcm_mapping = true;
+
+ spec->ops.pin_get_eld = atihdmi_pin_get_eld;
+ spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
+ spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
+ spec->ops.setup_stream = atihdmi_setup_stream;
+
+ spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
+ spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
+
+ if (!has_amd_full_remap_support(codec)) {
+ /* override to ATI/AMD-specific versions with pairwise mapping */
+ spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+ atihdmi_paired_chmap_cea_alloc_validate_get_type;
+ spec->chmap.ops.cea_alloc_to_tlv_chmap =
+ atihdmi_paired_cea_alloc_to_tlv_chmap;
+ spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
+ }
+
+ /* ATI/AMD converters do not advertise all of their capabilities */
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+ per_cvt = get_cvt(spec, cvt_idx);
+ per_cvt->channels_max = max(per_cvt->channels_max, 8u);
+ per_cvt->rates |= SUPPORTED_RATES;
+ per_cvt->formats |= SUPPORTED_FORMATS;
+ per_cvt->maxbps = max(per_cvt->maxbps, 24u);
+ }
+
+ spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
+
+ /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
+ * the link-down as is. Tell the core to allow it.
+ */
+ codec->link_down_at_suspend = 1;
+
+ snd_hda_hdmi_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
+
+ return 0;
+}
+
+static const struct hda_codec_ops atihdmi_codec_ops = {
+ .probe = atihdmi_probe,
+ .remove = snd_hda_hdmi_generic_remove,
+ .init = atihdmi_init,
+ .build_pcms = snd_hda_hdmi_generic_build_pcms,
+ .build_controls = snd_hda_hdmi_generic_build_controls,
+ .unsol_event = snd_hda_hdmi_generic_unsol_event,
+ .suspend = snd_hda_hdmi_generic_suspend,
+ .resume = snd_hda_hdmi_generic_resume,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_atihdmi[] = {
+ HDA_CODEC_ID(0x1002793c, "RS600 HDMI"),
+ HDA_CODEC_ID(0x10027919, "RS600 HDMI"),
+ HDA_CODEC_ID(0x1002791a, "RS690/780 HDMI"),
+ HDA_CODEC_ID(0x1002aa01, "R6xx HDMI"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD/ATI HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver atihdmi_driver = {
+ .id = snd_hda_id_atihdmi,
+ .ops = &atihdmi_codec_ops,
+};
+
+module_hda_codec_driver(atihdmi_driver);
diff --git a/sound/hda/codecs/hdmi/eld.c b/sound/hda/codecs/hdmi/eld.c
new file mode 100644
index 000000000000..1464fd1c675b
--- /dev/null
+++ b/sound/hda/codecs/hdmi/eld.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Generic routines and proc interface for ELD(EDID Like Data) information
+ *
+ * Copyright(c) 2008 Intel Corporation.
+ * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * Authors:
+ * Wu Fengguang <wfg@linux.intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/hda_chmap.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+
+enum cea_edid_versions {
+ CEA_EDID_VER_NONE = 0,
+ CEA_EDID_VER_CEA861 = 1,
+ CEA_EDID_VER_CEA861A = 2,
+ CEA_EDID_VER_CEA861BCD = 3,
+ CEA_EDID_VER_RESERVED = 4,
+};
+
+/*
+ * The following two lists are shared between
+ * - HDMI audio InfoFrame (source to sink)
+ * - CEA E-EDID Extension (sink to source)
+ */
+
+static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
+ int byte_index)
+{
+ unsigned int val;
+
+ val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_HDMI_ELDD, byte_index);
+#ifdef BE_PARANOID
+ codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+#endif
+ return val;
+}
+
+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,
+ AC_DIPSIZE_ELD_BUF);
+}
+
+int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char *buf, int *eld_size)
+{
+ int i;
+ int ret = 0;
+ int size;
+
+ /*
+ * ELD size is initialized to zero in caller function. If no errors and
+ * ELD is valid, actual eld_size is assigned.
+ */
+
+ size = snd_hdmi_get_eld_size(codec, nid);
+ if (size == 0) {
+ /* wfg: workaround for ASUS P5E-VM HDMI board */
+ codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
+ size = 128;
+ }
+ if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
+ codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
+ return -ERANGE;
+ }
+
+ /* set ELD buffer */
+ for (i = 0; i < size; i++) {
+ unsigned int val = hdmi_get_eld_data(codec, nid, i);
+ /*
+ * Graphics driver might be writing to ELD buffer right now.
+ * Just abort. The caller will repoll after a while.
+ */
+ if (!(val & AC_ELDD_ELD_VALID)) {
+ codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
+ ret = -EINVAL;
+ goto error;
+ }
+ val &= AC_ELDD_ELD_DATA;
+ /*
+ * The first byte cannot be zero. This can happen on some DVI
+ * connections. Some Intel chips may also need some 250ms delay
+ * to return non-zero ELD data, even when the graphics driver
+ * correctly writes ELD content before setting ELD_valid bit.
+ */
+ if (!val && !i) {
+ codec_dbg(codec, "HDMI: 0 ELD data\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ buf[i] = val;
+ }
+
+ *eld_size = size;
+error:
+ return ret;
+}
+
+#ifdef CONFIG_SND_PROC_FS
+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)
+{
+ 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_print_eld_info(&eld->info, buffer);
+}
+
+void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_parsed_hdmi_eld *e = &eld->info;
+ char line[64];
+ char name[64];
+ char *sname;
+ long long val;
+ unsigned int n;
+
+ while (!snd_info_get_line(buffer, line, sizeof(line))) {
+ if (sscanf(line, "%s %llx", name, &val) != 2)
+ continue;
+ /*
+ * We don't allow modification to these fields:
+ * monitor_name manufacture_id product_id
+ * eld_version edid_version
+ */
+ if (!strcmp(name, "monitor_present"))
+ eld->monitor_present = val;
+ else if (!strcmp(name, "eld_valid"))
+ eld->eld_valid = val;
+ else if (!strcmp(name, "connection_type"))
+ e->conn_type = val;
+ else if (!strcmp(name, "port_id"))
+ e->port_id = val;
+ else if (!strcmp(name, "support_hdcp"))
+ e->support_hdcp = val;
+ else if (!strcmp(name, "support_ai"))
+ e->support_ai = val;
+ else if (!strcmp(name, "audio_sync_delay"))
+ e->aud_synch_delay = val;
+ else if (!strcmp(name, "speakers"))
+ e->spk_alloc = val;
+ else if (!strcmp(name, "sad_count"))
+ e->sad_count = val;
+ else if (!strncmp(name, "sad", 3)) {
+ sname = name + 4;
+ n = name[3] - '0';
+ if (name[4] >= '0' && name[4] <= '9') {
+ sname++;
+ n = 10 * n + name[4] - '0';
+ }
+ if (n >= ELD_MAX_SAD)
+ continue;
+ if (!strcmp(sname, "_coding_type"))
+ e->sad[n].format = val;
+ else if (!strcmp(sname, "_channels"))
+ e->sad[n].channels = val;
+ else if (!strcmp(sname, "_rates"))
+ e->sad[n].rates = val;
+ else if (!strcmp(sname, "_bits"))
+ e->sad[n].sample_bits = val;
+ else if (!strcmp(sname, "_max_bitrate"))
+ e->sad[n].max_bitrate = val;
+ else if (!strcmp(sname, "_profile"))
+ e->sad[n].profile = val;
+ if (n >= e->sad_count)
+ e->sad_count = n + 1;
+ }
+ }
+}
+#endif /* CONFIG_SND_PROC_FS */
+
+/* update PCM info based on ELD */
+void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
+ struct hda_pcm_stream *hinfo)
+{
+ u32 rates;
+ u64 formats;
+ unsigned int maxbps;
+ unsigned int channels_max;
+ int i;
+
+ /* assume basic audio support (the basic audio flag is not in ELD;
+ * however, all audio capable sinks are required to support basic
+ * audio) */
+ rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000;
+ formats = SNDRV_PCM_FMTBIT_S16_LE;
+ maxbps = 16;
+ channels_max = 2;
+ for (i = 0; i < e->sad_count; 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 & ELD_PCM_BITS_20) {
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ if (maxbps < 20)
+ maxbps = 20;
+ }
+ if (a->sample_bits & ELD_PCM_BITS_24) {
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ if (maxbps < 24)
+ maxbps = 24;
+ }
+ }
+ }
+
+ /* restrict the parameters by the values the codec provides */
+ hinfo->rates &= rates;
+ hinfo->formats &= formats;
+ hinfo->maxbps = min(hinfo->maxbps, maxbps);
+ hinfo->channels_max = min(hinfo->channels_max, channels_max);
+}
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
new file mode 100644
index 000000000000..111c9b5335af
--- /dev/null
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -0,0 +1,2363 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * hdmi.c - routines for HDMI/DisplayPort codecs
+ *
+ * Copyright(c) 2008-2010 Intel Corporation
+ * Copyright (c) 2006 ATI Technologies Inc.
+ * Copyright (c) 2008 NVIDIA Corp. All rights reserved.
+ * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
+ * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * Authors:
+ * Wu Fengguang <wfg@linux.intel.com>
+ *
+ * Maintained by:
+ * Wu Fengguang <wfg@linux.intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/asoundef.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_chmap.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_jack.h"
+#include "hda_controller.h"
+#include "hdmi_local.h"
+
+static bool static_hdmi_pcm;
+module_param(static_hdmi_pcm, bool, 0644);
+MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
+
+static bool enable_acomp = true;
+module_param(enable_acomp, bool, 0444);
+MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
+
+static bool enable_all_pins;
+module_param(enable_all_pins, bool, 0444);
+MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins");
+
+int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+ struct hdmi_spec_per_pin *per_pin;
+
+ /*
+ * (dev_id == -1) means it is NON-MST pin
+ * return the first virtual pin on this port
+ */
+ if (dev_id == -1)
+ dev_id = 0;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ per_pin = get_pin(spec, pin_idx);
+ if ((per_pin->pin_nid == pin_nid) &&
+ (per_pin->dev_id == dev_id))
+ return pin_idx;
+ }
+
+ codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_pin_id_to_pin_index, "SND_HDA_CODEC_HDMI");
+
+static int hinfo_to_pcm_index(struct hda_codec *codec,
+ struct hda_pcm_stream *hinfo)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pcm_idx;
+
+ for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++)
+ if (get_pcm_rec(spec, pcm_idx)->stream == hinfo)
+ return pcm_idx;
+
+ codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo);
+ return -EINVAL;
+}
+
+static int hinfo_to_pin_index(struct hda_codec *codec,
+ struct hda_pcm_stream *hinfo)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ per_pin = get_pin(spec, pin_idx);
+ if (per_pin->pcm &&
+ per_pin->pcm->pcm->stream == hinfo)
+ return pin_idx;
+ }
+
+ codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo,
+ hinfo_to_pcm_index(codec, hinfo));
+ return -EINVAL;
+}
+
+static struct hdmi_spec_per_pin *pcm_idx_to_pin(struct hdmi_spec *spec,
+ int pcm_idx)
+{
+ int i;
+ struct hdmi_spec_per_pin *per_pin;
+
+ for (i = 0; i < spec->num_pins; i++) {
+ per_pin = get_pin(spec, i);
+ if (per_pin->pcm_idx == pcm_idx)
+ return per_pin;
+ }
+ return NULL;
+}
+
+static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int cvt_idx;
+
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
+ if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
+ return cvt_idx;
+
+ codec_warn(codec, "HDMI: cvt NID 0x%x not registered\n", cvt_nid);
+ return -EINVAL;
+}
+
+static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_eld *eld;
+ int pcm_idx;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+
+ pcm_idx = kcontrol->private_value;
+ guard(mutex)(&spec->pcm_lock);
+ per_pin = pcm_idx_to_pin(spec, pcm_idx);
+ if (!per_pin) {
+ /* no pin is bound to the pcm */
+ uinfo->count = 0;
+ return 0;
+ }
+ eld = &per_pin->sink_eld;
+ uinfo->count = eld->eld_valid ? eld->eld_size : 0;
+ return 0;
+}
+
+static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_eld *eld;
+ int pcm_idx;
+
+ pcm_idx = kcontrol->private_value;
+ guard(mutex)(&spec->pcm_lock);
+ per_pin = pcm_idx_to_pin(spec, pcm_idx);
+ if (!per_pin) {
+ /* no pin is bound to the pcm */
+ memset(ucontrol->value.bytes.data, 0,
+ ARRAY_SIZE(ucontrol->value.bytes.data));
+ return 0;
+ }
+
+ eld = &per_pin->sink_eld;
+ if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
+ eld->eld_size > ELD_MAX_SIZE) {
+ snd_BUG();
+ return -EINVAL;
+ }
+
+ memset(ucontrol->value.bytes.data, 0,
+ ARRAY_SIZE(ucontrol->value.bytes.data));
+ if (eld->eld_valid)
+ memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
+ eld->eld_size);
+ return 0;
+}
+
+static const struct snd_kcontrol_new eld_bytes_ctl = {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+ SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "ELD",
+ .info = hdmi_eld_ctl_info,
+ .get = hdmi_eld_ctl_get,
+};
+
+static int hdmi_create_eld_ctl(struct hda_codec *codec, int pcm_idx,
+ int device)
+{
+ struct snd_kcontrol *kctl;
+ struct hdmi_spec *spec = codec->spec;
+ int err;
+
+ kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->private_value = pcm_idx;
+ kctl->id.device = device;
+
+ /* no pin nid is associated with the kctl now
+ * tbd: associate pin nid to eld ctl later
+ */
+ err = snd_hda_ctl_add(codec, 0, kctl);
+ if (err < 0)
+ return err;
+
+ get_hdmi_pcm(spec, pcm_idx)->eld_ctl = kctl;
+ return 0;
+}
+
+#ifdef BE_PARANOID
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
+ int *packet_index, int *byte_index)
+{
+ int val;
+
+ val = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_HDMI_DIP_INDEX, 0);
+
+ *packet_index = val >> 5;
+ *byte_index = val & 0x1f;
+}
+#endif
+
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
+ int packet_index, int byte_index)
+{
+ int val;
+
+ val = (packet_index << 5) | (byte_index & 0x1f);
+
+ snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
+ unsigned char val)
+{
+ snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+}
+
+static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_out;
+
+ /* Unmute */
+ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+ if (spec->dyn_pin_out)
+ /* Disable pin out until stream is active */
+ pin_out = 0;
+ else
+ /* Enable pin out: some machines with GM965 gets broken output
+ * when the pin is disabled or changed while using with HDMI
+ */
+ pin_out = PIN_OUT;
+
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
+}
+
+/*
+ * ELD proc files
+ */
+
+#ifdef CONFIG_SND_PROC_FS
+static void print_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_spec_per_pin *per_pin = entry->private_data;
+
+ guard(mutex)(&per_pin->lock);
+ snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer, per_pin->pin_nid,
+ per_pin->dev_id, per_pin->cvt_nid);
+}
+
+static void write_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_spec_per_pin *per_pin = entry->private_data;
+
+ guard(mutex)(&per_pin->lock);
+ snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
+}
+
+static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
+{
+ char name[32];
+ struct hda_codec *codec = per_pin->codec;
+ struct snd_info_entry *entry;
+ int err;
+
+ snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
+ err = snd_card_proc_new(codec->card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, per_pin, print_eld_info);
+ entry->c.text.write = write_eld_info;
+ entry->mode |= 0200;
+ per_pin->proc_entry = entry;
+
+ return 0;
+}
+
+static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
+{
+ if (!per_pin->codec->bus->shutdown) {
+ snd_info_free_entry(per_pin->proc_entry);
+ per_pin->proc_entry = NULL;
+ }
+}
+#else
+static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
+ int index)
+{
+ return 0;
+}
+static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
+{
+}
+#endif
+
+/*
+ * Audio InfoFrame routines
+ */
+
+/*
+ * Enable Audio InfoFrame Transmission
+ */
+static void hdmi_start_infoframe_trans(struct hda_codec *codec,
+ hda_nid_t pin_nid)
+{
+ hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+ snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+ AC_DIPXMIT_BEST);
+}
+
+/*
+ * Disable Audio InfoFrame Transmission
+ */
+static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
+ hda_nid_t pin_nid)
+{
+ hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+ snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+ AC_DIPXMIT_DISABLE);
+}
+
+static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ int i;
+ int size;
+
+ size = snd_hdmi_get_eld_size(codec, pin_nid);
+ codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
+
+ for (i = 0; i < 8; i++) {
+ size = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_HDMI_DIP_SIZE, i);
+ codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+ }
+#endif
+}
+
+static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+#ifdef BE_PARANOID
+ int i, j;
+ int size;
+ int pi, bi;
+ for (i = 0; i < 8; i++) {
+ size = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_HDMI_DIP_SIZE, i);
+ if (size == 0)
+ continue;
+
+ hdmi_set_dip_index(codec, pin_nid, i, 0x0);
+ for (j = 1; j < 1000; j++) {
+ hdmi_write_dip_byte(codec, pin_nid, 0x0);
+ hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
+ if (pi != i)
+ codec_dbg(codec, "dip index %d: %d != %d\n",
+ bi, pi, i);
+ if (bi == 0) /* byte index wrapped around */
+ break;
+ }
+ codec_dbg(codec,
+ "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
+ i, size, j);
+ }
+#endif
+}
+
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
+{
+ u8 *bytes = (u8 *)hdmi_ai;
+ u8 sum = 0;
+ int i;
+
+ hdmi_ai->checksum = 0;
+
+ for (i = 0; i < sizeof(*hdmi_ai); i++)
+ sum += bytes[i];
+
+ hdmi_ai->checksum = -sum;
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+ hda_nid_t pin_nid,
+ u8 *dip, int size)
+{
+ int i;
+
+ hdmi_debug_dip_size(codec, pin_nid);
+ hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
+
+ hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+ for (i = 0; i < size; i++)
+ hdmi_write_dip_byte(codec, pin_nid, dip[i]);
+}
+
+static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
+ u8 *dip, int size)
+{
+ u8 val;
+ int i;
+
+ hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+ if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
+ != AC_DIPXMIT_BEST)
+ return false;
+
+ for (i = 0; i < size; i++) {
+ val = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_HDMI_DIP_DATA, 0);
+ if (val != dip[i])
+ return false;
+ }
+
+ return true;
+}
+
+static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+ int dev_id, unsigned char *buf, int *eld_size)
+{
+ snd_hda_set_dev_select(codec, nid, dev_id);
+
+ return snd_hdmi_get_eld(codec, nid, buf, eld_size);
+}
+
+static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id,
+ int ca, int active_channels,
+ int conn_type)
+{
+ struct hdmi_spec *spec = codec->spec;
+ union audio_infoframe ai;
+
+ memset(&ai, 0, sizeof(ai));
+ if ((conn_type == 0) || /* HDMI */
+ /* Nvidia DisplayPort: Nvidia HW expects same layout as HDMI */
+ (conn_type == 1 && spec->nv_dp_workaround)) {
+ struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
+
+ if (conn_type == 0) { /* HDMI */
+ hdmi_ai->type = 0x84;
+ hdmi_ai->ver = 0x01;
+ hdmi_ai->len = 0x0a;
+ } else {/* Nvidia DP */
+ hdmi_ai->type = 0x84;
+ hdmi_ai->ver = 0x1b;
+ hdmi_ai->len = 0x11 << 2;
+ }
+ hdmi_ai->CC02_CT47 = active_channels - 1;
+ hdmi_ai->CA = ca;
+ hdmi_checksum_audio_infoframe(hdmi_ai);
+ } else if (conn_type == 1) { /* DisplayPort */
+ struct dp_audio_infoframe *dp_ai = &ai.dp;
+
+ dp_ai->type = 0x84;
+ dp_ai->len = 0x1b;
+ dp_ai->ver = 0x11 << 2;
+ dp_ai->CC02_CT47 = active_channels - 1;
+ dp_ai->CA = ca;
+ } else {
+ codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid);
+ return;
+ }
+
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
+ /*
+ * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+ * sizeof(*dp_ai) to avoid partial match/update problems when
+ * the user switches between HDMI/DP monitors.
+ */
+ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+ sizeof(ai))) {
+ codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n",
+ __func__, pin_nid, active_channels, ca);
+ hdmi_stop_infoframe_trans(codec, pin_nid);
+ hdmi_fill_audio_infoframe(codec, pin_nid,
+ ai.bytes, sizeof(ai));
+ hdmi_start_infoframe_trans(codec, pin_nid);
+ }
+}
+
+void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ bool non_pcm)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdac_chmap *chmap = &spec->chmap;
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int dev_id = per_pin->dev_id;
+ int channels = per_pin->channels;
+ int active_channels;
+ struct hdmi_eld *eld;
+ int ca;
+
+ if (!channels)
+ return;
+
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
+ /* some HW (e.g. HSW+) needs reprogramming the amp at each time */
+ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+
+ eld = &per_pin->sink_eld;
+
+ ca = snd_hdac_channel_allocation(&codec->core,
+ eld->info.spk_alloc, channels,
+ per_pin->chmap_set, non_pcm, per_pin->chmap);
+
+ active_channels = snd_hdac_get_active_channels(ca);
+
+ chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid,
+ active_channels);
+
+ /*
+ * always configure channel mapping, it may have been changed by the
+ * user in the meantime
+ */
+ snd_hdac_setup_channel_mapping(&spec->chmap,
+ pin_nid, non_pcm, ca, channels,
+ per_pin->chmap, per_pin->chmap_set);
+
+ spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
+ ca, active_channels, eld->info.conn_type);
+
+ per_pin->non_pcm = non_pcm;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_audio_infoframe, "SND_HDA_CODEC_HDMI");
+
+/*
+ * Unsolicited events
+ */
+
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
+
+void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec,
+ hda_nid_t nid, int dev_id)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
+
+ if (pin_idx < 0)
+ return;
+ guard(mutex)(&spec->pcm_lock);
+ hdmi_present_sense(get_pin(spec, pin_idx), 1);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_check_presence_and_report,
+ "SND_HDA_CODEC_HDMI");
+
+static void jack_callback(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ /* stop polling when notification is enabled */
+ if (codec_has_acomp(codec))
+ return;
+
+ snd_hda_hdmi_check_presence_and_report(codec, jack->nid, jack->dev_id);
+}
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
+ struct hda_jack_tbl *jack)
+{
+ jack->jack_dirty = 1;
+
+ codec_dbg(codec,
+ "HDMI hot plug event: Codec=%d NID=0x%x Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
+ codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA),
+ !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
+
+ snd_hda_hdmi_check_presence_and_report(codec, jack->nid, jack->dev_id);
+}
+
+static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+ int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+ int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+ int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
+ int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
+
+ codec_info(codec,
+ "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+ codec->addr,
+ tag,
+ subtag,
+ cp_state,
+ cp_ready);
+
+ /* TODO */
+ if (cp_state) {
+ ;
+ }
+ if (cp_ready) {
+ ;
+ }
+}
+
+void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+ int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+ struct hda_jack_tbl *jack;
+
+ if (codec_has_acomp(codec))
+ return;
+
+ if (codec->dp_mst) {
+ int dev_entry =
+ (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
+
+ jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry);
+ } else {
+ jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0);
+ }
+
+ if (!jack) {
+ codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
+ return;
+ }
+
+ if (subtag == 0)
+ hdmi_intrinsic_event(codec, res, jack);
+ else
+ hdmi_non_intrinsic_event(codec, res);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_unsol_event, "SND_HDA_CODEC_HDMI");
+
+/*
+ * Callbacks
+ */
+
+/* HBR should be Non-PCM, 8 channels */
+#define is_hbr_format(format) \
+ ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
+
+static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+ int dev_id, bool hbr)
+{
+ int pinctl, new_pinctl;
+
+ if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
+ pinctl = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+ if (pinctl < 0)
+ return hbr ? -EINVAL : 0;
+
+ new_pinctl = pinctl & ~AC_PINCTL_EPT;
+ if (hbr)
+ new_pinctl |= AC_PINCTL_EPT_HBR;
+ else
+ new_pinctl |= AC_PINCTL_EPT_NATIVE;
+
+ codec_dbg(codec,
+ "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
+ pin_nid,
+ pinctl == new_pinctl ? "" : "new-",
+ new_pinctl);
+
+ if (pinctl != new_pinctl)
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ new_pinctl);
+ } else if (hbr)
+ return -EINVAL;
+
+ return 0;
+}
+
+int snd_hda_hdmi_setup_stream(struct hda_codec *codec,
+ hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, int dev_id,
+ u32 stream_tag, int format)
+{
+ struct hdmi_spec *spec = codec->spec;
+ unsigned int param;
+ int err;
+
+ err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id,
+ is_hbr_format(format));
+
+ if (err) {
+ codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
+ return err;
+ }
+
+ if (spec->intel_hsw_fixup) {
+
+ /*
+ * on recent platforms IEC Coding Type is required for HBR
+ * support, read current Digital Converter settings and set
+ * ICT bitfield if needed.
+ */
+ param = snd_hda_codec_read(codec, cvt_nid, 0,
+ AC_VERB_GET_DIGI_CONVERT_1, 0);
+
+ param = (param >> 16) & ~(AC_DIG3_ICT);
+
+ /* on recent platforms ICT mode is required for HBR support */
+ if (is_hbr_format(format))
+ param |= 0x1;
+
+ snd_hda_codec_write(codec, cvt_nid, 0,
+ AC_VERB_SET_DIGI_CONVERT_3, param);
+ }
+
+ snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_stream, "SND_HDA_CODEC_HDMI");
+
+/* Try to find an available converter
+ * If pin_idx is less then zero, just try to find an available converter.
+ * Otherwise, try to find an available converter and get the cvt mux index
+ * of the pin.
+ */
+static int hdmi_choose_cvt(struct hda_codec *codec,
+ int pin_idx, int *cvt_id,
+ bool silent)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int cvt_idx, mux_idx = 0;
+
+ /* pin_idx < 0 means no pin will be bound to the converter */
+ if (pin_idx < 0)
+ per_pin = NULL;
+ else
+ per_pin = get_pin(spec, pin_idx);
+
+ if (per_pin && per_pin->silent_stream) {
+ cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
+ per_cvt = get_cvt(spec, cvt_idx);
+ if (per_cvt->assigned && !silent)
+ return -EBUSY;
+ if (cvt_id)
+ *cvt_id = cvt_idx;
+ return 0;
+ }
+
+ /* Dynamically assign converter to stream */
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+ per_cvt = get_cvt(spec, cvt_idx);
+
+ /* Must not already be assigned */
+ if (per_cvt->assigned || per_cvt->silent_stream)
+ continue;
+ if (per_pin == NULL)
+ break;
+ /* Must be in pin's mux's list of converters */
+ for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+ if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
+ break;
+ /* Not in mux list */
+ if (mux_idx == per_pin->num_mux_nids)
+ continue;
+ break;
+ }
+
+ /* No free converters */
+ if (cvt_idx == spec->num_cvts)
+ return -EBUSY;
+
+ if (per_pin != NULL)
+ per_pin->mux_idx = mux_idx;
+
+ if (cvt_id)
+ *cvt_id = cvt_idx;
+
+ return 0;
+}
+
+/* skeleton caller of pin_cvt_fixup ops */
+static void pin_cvt_fixup(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ hda_nid_t cvt_nid)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (spec->ops.pin_cvt_fixup)
+ spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
+}
+
+/* called in hdmi_pcm_open when no pin is assigned to the PCM */
+static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int cvt_idx, pcm_idx;
+ struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int err;
+
+ pcm_idx = hinfo_to_pcm_index(codec, hinfo);
+ if (pcm_idx < 0)
+ return -EINVAL;
+
+ err = hdmi_choose_cvt(codec, -1, &cvt_idx, false);
+ if (err)
+ return err;
+
+ per_cvt = get_cvt(spec, cvt_idx);
+ per_cvt->assigned = true;
+ hinfo->nid = per_cvt->cvt_nid;
+
+ pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
+
+ set_bit(pcm_idx, &spec->pcm_in_use);
+ /* todo: setup spdif ctls assign */
+
+ /* Initially set the converter's capabilities */
+ hinfo->channels_min = per_cvt->channels_min;
+ hinfo->channels_max = per_cvt->channels_max;
+ hinfo->rates = per_cvt->rates;
+ hinfo->formats = per_cvt->formats;
+ hinfo->maxbps = per_cvt->maxbps;
+
+ /* Store the updated parameters */
+ runtime->hw.channels_min = hinfo->channels_min;
+ runtime->hw.channels_max = hinfo->channels_max;
+ runtime->hw.formats = hinfo->formats;
+ runtime->hw.rates = hinfo->rates;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ return 0;
+}
+
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int pin_idx, cvt_idx, pcm_idx;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_eld *eld;
+ struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int err;
+
+ /* Validate hinfo */
+ pcm_idx = hinfo_to_pcm_index(codec, hinfo);
+ if (pcm_idx < 0)
+ return -EINVAL;
+
+ guard(mutex)(&spec->pcm_lock);
+ pin_idx = hinfo_to_pin_index(codec, hinfo);
+ /* no pin is assigned to the PCM
+ * PA need pcm open successfully when probe
+ */
+ if (pin_idx < 0)
+ return hdmi_pcm_open_no_pin(hinfo, codec, substream);
+
+ err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false);
+ if (err < 0)
+ return err;
+
+ per_cvt = get_cvt(spec, cvt_idx);
+ /* Claim converter */
+ per_cvt->assigned = true;
+
+ set_bit(pcm_idx, &spec->pcm_in_use);
+ per_pin = get_pin(spec, pin_idx);
+ per_pin->cvt_nid = per_cvt->cvt_nid;
+ hinfo->nid = per_cvt->cvt_nid;
+
+ /* flip stripe flag for the assigned stream if supported */
+ if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
+ azx_stream(get_azx_dev(substream))->stripe = 1;
+
+ snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ per_pin->mux_idx);
+
+ /* configure unused pins to choose other converters */
+ pin_cvt_fixup(codec, per_pin, 0);
+
+ snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
+
+ /* Initially set the converter's capabilities */
+ hinfo->channels_min = per_cvt->channels_min;
+ hinfo->channels_max = per_cvt->channels_max;
+ hinfo->rates = per_cvt->rates;
+ hinfo->formats = per_cvt->formats;
+ hinfo->maxbps = per_cvt->maxbps;
+
+ eld = &per_pin->sink_eld;
+ /* Restrict capabilities by ELD if this isn't disabled */
+ if (!static_hdmi_pcm && eld->eld_valid) {
+ snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
+ if (hinfo->channels_min > hinfo->channels_max ||
+ !hinfo->rates || !hinfo->formats) {
+ per_cvt->assigned = false;
+ hinfo->nid = 0;
+ snd_hda_spdif_ctls_unassign(codec, pcm_idx);
+ return -ENODEV;
+ }
+ }
+
+ /* Store the updated parameters */
+ runtime->hw.channels_min = hinfo->channels_min;
+ runtime->hw.channels_max = hinfo->channels_max;
+ runtime->hw.formats = hinfo->formats;
+ runtime->hw.rates = hinfo->rates;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ return 0;
+}
+
+/*
+ * HDA/HDMI auto parsing
+ */
+static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int dev_id = per_pin->dev_id;
+ int conns;
+
+ if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
+ codec_warn(codec,
+ "HDMI: pin NID 0x%x wcaps %#x does not support connection list\n",
+ pin_nid, get_wcaps(codec, pin_nid));
+ return -EINVAL;
+ }
+
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
+ if (spec->intel_hsw_fixup) {
+ conns = spec->num_cvts;
+ memcpy(per_pin->mux_nids, spec->cvt_nids,
+ sizeof(hda_nid_t) * conns);
+ } else {
+ conns = snd_hda_get_raw_connections(codec, pin_nid,
+ per_pin->mux_nids,
+ HDA_MAX_CONNECTIONS);
+ }
+
+ /* all the device entries on the same pin have the same conn list */
+ per_pin->num_mux_nids = conns;
+
+ return 0;
+}
+
+static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ int i;
+
+ for (i = 0; i < spec->pcm_used; i++) {
+ if (!test_bit(i, &spec->pcm_bitmap))
+ return i;
+ }
+ return -EBUSY;
+}
+
+static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ int idx;
+
+ /* pcm already be attached to the pin */
+ if (per_pin->pcm)
+ return;
+ /* try the previously used slot at first */
+ idx = per_pin->prev_pcm_idx;
+ if (idx >= 0) {
+ if (!test_bit(idx, &spec->pcm_bitmap))
+ goto found;
+ per_pin->prev_pcm_idx = -1; /* no longer valid, clear it */
+ }
+ idx = hdmi_find_pcm_slot(spec, per_pin);
+ if (idx == -EBUSY)
+ return;
+ found:
+ per_pin->pcm_idx = idx;
+ per_pin->pcm = get_hdmi_pcm(spec, idx);
+ set_bit(idx, &spec->pcm_bitmap);
+}
+
+static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ int idx;
+
+ /* pcm already be detached from the pin */
+ if (!per_pin->pcm)
+ return;
+ idx = per_pin->pcm_idx;
+ per_pin->pcm_idx = -1;
+ per_pin->prev_pcm_idx = idx; /* remember the previous index */
+ per_pin->pcm = NULL;
+ if (idx >= 0 && idx < spec->pcm_used)
+ clear_bit(idx, &spec->pcm_bitmap);
+}
+
+static int hdmi_get_pin_cvt_mux(struct hdmi_spec *spec,
+ struct hdmi_spec_per_pin *per_pin, hda_nid_t cvt_nid)
+{
+ int mux_idx;
+
+ for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+ if (per_pin->mux_nids[mux_idx] == cvt_nid)
+ break;
+ return mux_idx;
+}
+
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid);
+
+static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hda_codec *codec = per_pin->codec;
+ struct hda_pcm *pcm;
+ struct hda_pcm_stream *hinfo;
+ struct snd_pcm_substream *substream;
+ int mux_idx;
+ bool non_pcm;
+
+ if (per_pin->pcm_idx < 0 || per_pin->pcm_idx >= spec->pcm_used)
+ return;
+ pcm = get_pcm_rec(spec, per_pin->pcm_idx);
+ if (!pcm->pcm)
+ return;
+ if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use))
+ return;
+
+ /* hdmi audio only uses playback and one substream */
+ hinfo = pcm->stream;
+ substream = pcm->pcm->streams[0].substream;
+
+ per_pin->cvt_nid = hinfo->nid;
+
+ mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
+ if (mux_idx < per_pin->num_mux_nids) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+ }
+ snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
+
+ non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
+ if (substream->runtime)
+ per_pin->channels = substream->runtime->channels;
+ per_pin->setup = true;
+ per_pin->mux_idx = mux_idx;
+
+ snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+}
+
+static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used)
+ snd_hda_spdif_ctls_unassign(per_pin->codec, per_pin->pcm_idx);
+
+ per_pin->chmap_set = false;
+ memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
+
+ per_pin->setup = false;
+ per_pin->channels = 0;
+}
+
+static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (per_pin->pcm_idx >= 0)
+ return spec->pcm_rec[per_pin->pcm_idx].jack;
+ else
+ return NULL;
+}
+
+/* update per_pin ELD from the given new ELD;
+ * setup info frame and notification accordingly
+ * also notify ELD kctl and report jack status changes
+ */
+static void update_eld(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ struct hdmi_eld *eld,
+ int repoll)
+{
+ struct hdmi_eld *pin_eld = &per_pin->sink_eld;
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_jack *pcm_jack;
+ bool old_eld_valid = pin_eld->eld_valid;
+ bool eld_changed;
+ int pcm_idx;
+
+ if (eld->eld_valid) {
+ if (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,
+ msecs_to_jiffies(300));
+ return;
+ }
+ }
+ }
+
+ if (!eld->eld_valid || eld->eld_size <= 0 || eld->info.sad_count <= 0) {
+ eld->eld_valid = false;
+ eld->eld_size = 0;
+ }
+
+ /* for monitor disconnection, save pcm_idx firstly */
+ pcm_idx = per_pin->pcm_idx;
+
+ /*
+ * pcm_idx >=0 before update_eld() means it is in monitor
+ * disconnected event. Jack must be fetched before update_eld().
+ */
+ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
+ if (!spec->static_pcm_mapping) {
+ if (eld->eld_valid) {
+ hdmi_attach_hda_pcm(spec, per_pin);
+ hdmi_pcm_setup_pin(spec, per_pin);
+ } else {
+ hdmi_pcm_reset_pin(spec, per_pin);
+ hdmi_detach_hda_pcm(spec, per_pin);
+ }
+ }
+
+ /* if pcm_idx == -1, it means this is in monitor connection event
+ * we can get the correct pcm_idx now.
+ */
+ if (pcm_idx == -1)
+ pcm_idx = per_pin->pcm_idx;
+ if (!pcm_jack)
+ pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
+ if (eld->eld_valid)
+ 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);
+ if (!eld_changed && eld->eld_valid && pin_eld->eld_valid)
+ if (pin_eld->eld_size != eld->eld_size ||
+ memcmp(pin_eld->eld_buffer, eld->eld_buffer,
+ eld->eld_size) != 0)
+ eld_changed = true;
+
+ if (eld_changed) {
+ pin_eld->monitor_present = eld->monitor_present;
+ pin_eld->eld_valid = eld->eld_valid;
+ pin_eld->eld_size = eld->eld_size;
+ if (eld->eld_valid)
+ memcpy(pin_eld->eld_buffer, eld->eld_buffer,
+ eld->eld_size);
+ pin_eld->info = eld->info;
+ }
+
+ /*
+ * Re-setup pin and infoframe. This is needed e.g. when
+ * - sink is first plugged-in
+ * - transcoder can change during stream playback on Haswell
+ * and this can make HW reset converter selection on a pin.
+ */
+ if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
+ pin_cvt_fixup(codec, per_pin, 0);
+ snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+ }
+
+ if (eld_changed && pcm_idx >= 0)
+ snd_ctl_notify(codec->card,
+ SNDRV_CTL_EVENT_MASK_VALUE |
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
+
+ if (eld_changed && pcm_jack)
+ snd_jack_report(pcm_jack,
+ (eld->monitor_present && eld->eld_valid) ?
+ SND_JACK_AVOUT : 0);
+}
+
+/* update ELD and jack state via HD-audio verbs */
+static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
+ int repoll)
+{
+ struct hda_codec *codec = per_pin->codec;
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_eld *eld = &spec->temp_eld;
+ struct device *dev = hda_codec_dev(codec);
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int dev_id = per_pin->dev_id;
+ /*
+ * Always execute a GetPinSense verb here, even when called from
+ * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
+ * response's PD bit is not the real PD value, but indicates that
+ * the real PD value changed. An older version of the HD-audio
+ * specification worked this way. Hence, we just ignore the data in
+ * the unsolicited response to avoid custom WARs.
+ */
+ int present;
+
+#ifdef CONFIG_PM
+ if (dev->power.runtime_status == RPM_SUSPENDING)
+ return;
+#endif
+
+ CLASS(snd_hda_power_pm, pm)(codec);
+ if (pm.err < 0 && pm_runtime_suspended(dev))
+ return;
+
+ present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
+
+ guard(mutex)(&per_pin->lock);
+ eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
+ if (eld->monitor_present)
+ eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
+ else
+ eld->eld_valid = false;
+
+ codec_dbg(codec,
+ "HDMI status: Codec=%d NID=0x%x Presence_Detect=%d ELD_Valid=%d\n",
+ codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
+
+ if (eld->eld_valid) {
+ if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
+ eld->eld_buffer, &eld->eld_size) < 0)
+ eld->eld_valid = false;
+ }
+
+ update_eld(codec, per_pin, eld, repoll);
+}
+
+static void silent_stream_enable(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_cvt *per_cvt;
+ int cvt_idx, pin_idx, err;
+
+ /*
+ * Power-up will call hdmi_present_sense, so the PM calls
+ * have to be done without mutex held.
+ */
+
+ CLASS(snd_hda_power_pm, pm)(codec);
+ if (pm.err < 0 && pm.err != -EACCES) {
+ codec_err(codec,
+ "Failed to power up codec for silent stream enable ret=[%d]\n", pm.err);
+ return;
+ }
+
+ guard(mutex)(&per_pin->lock);
+
+ if (per_pin->setup) {
+ codec_dbg(codec, "hdmi: PCM already open, no silent stream\n");
+ return;
+ }
+
+ pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id);
+ err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, true);
+ if (err) {
+ codec_err(codec, "hdmi: no free converter to enable silent mode\n");
+ return;
+ }
+
+ per_cvt = get_cvt(spec, cvt_idx);
+ per_cvt->silent_stream = true;
+ per_pin->cvt_nid = per_cvt->cvt_nid;
+ per_pin->silent_stream = true;
+
+ codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n",
+ per_pin->pin_nid, per_cvt->cvt_nid);
+
+ snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ per_pin->mux_idx);
+
+ /* configure unused pins to choose other converters */
+ pin_cvt_fixup(codec, per_pin, 0);
+
+ spec->ops.silent_stream(codec, per_pin, true);
+}
+
+static void silent_stream_disable(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_cvt *per_cvt;
+ int cvt_idx;
+
+ CLASS(snd_hda_power_pm, pm)(codec);
+ if (pm.err < 0 && pm.err != -EACCES) {
+ codec_err(codec,
+ "Failed to power up codec for silent stream disable ret=[%d]\n",
+ pm.err);
+ return;
+ }
+
+ guard(mutex)(&per_pin->lock);
+ if (!per_pin->silent_stream)
+ return;
+
+ codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n",
+ per_pin->pin_nid, per_pin->cvt_nid);
+
+ cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
+ if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) {
+ per_cvt = get_cvt(spec, cvt_idx);
+ per_cvt->silent_stream = false;
+ }
+
+ spec->ops.silent_stream(codec, per_pin, false);
+
+ per_pin->cvt_nid = 0;
+ per_pin->silent_stream = false;
+}
+
+/* update ELD and jack state via audio component */
+static void sync_eld_via_acomp(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_eld *eld = &spec->temp_eld;
+ bool monitor_prev, monitor_next;
+
+ scoped_guard(mutex, &per_pin->lock) {
+ eld->monitor_present = false;
+ monitor_prev = per_pin->sink_eld.monitor_present;
+ eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
+ per_pin->dev_id, &eld->monitor_present,
+ eld->eld_buffer, ELD_MAX_SIZE);
+ eld->eld_valid = (eld->eld_size > 0);
+ update_eld(codec, per_pin, eld, 0);
+ monitor_next = per_pin->sink_eld.monitor_present;
+ }
+
+ if (spec->silent_stream_type) {
+ if (!monitor_prev && monitor_next)
+ silent_stream_enable(codec, per_pin);
+ else if (monitor_prev && !monitor_next)
+ silent_stream_disable(codec, per_pin);
+ }
+}
+
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+{
+ struct hda_codec *codec = per_pin->codec;
+
+ if (!codec_has_acomp(codec))
+ hdmi_present_sense_via_verbs(per_pin, repoll);
+ else
+ sync_eld_via_acomp(codec, per_pin);
+}
+
+static void hdmi_repoll_eld(struct work_struct *work)
+{
+ struct hdmi_spec_per_pin *per_pin =
+ container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
+ struct hda_codec *codec = per_pin->codec;
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_jack_tbl *jack;
+
+ jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
+ per_pin->dev_id);
+ if (jack)
+ jack->jack_dirty = 1;
+
+ if (per_pin->repoll_count++ > 6)
+ per_pin->repoll_count = 0;
+
+ guard(mutex)(&spec->pcm_lock);
+ hdmi_present_sense(per_pin, per_pin->repoll_count);
+}
+
+static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+ struct hdmi_spec *spec = codec->spec;
+ unsigned int caps, config;
+ int pin_idx;
+ struct hdmi_spec_per_pin *per_pin;
+ int err;
+ int dev_num, i;
+
+ caps = snd_hda_query_pin_caps(codec, pin_nid);
+ if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
+ return 0;
+
+ /*
+ * For DP MST audio, Configuration Default is the same for
+ * all device entries on the same pin
+ */
+ config = snd_hda_codec_get_pincfg(codec, pin_nid);
+ if (get_defcfg_connect(config) == AC_JACK_PORT_NONE &&
+ !spec->force_connect)
+ return 0;
+
+ /*
+ * To simplify the implementation, malloc all
+ * the virtual pins in the initialization statically
+ */
+ if (spec->intel_hsw_fixup) {
+ /*
+ * On Intel platforms, device entries count returned
+ * by AC_PAR_DEVLIST_LEN is dynamic, and depends on
+ * the type of receiver that is connected. Allocate pin
+ * structures based on worst case.
+ */
+ dev_num = spec->dev_num;
+ } else if (codec->dp_mst) {
+ dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
+ /*
+ * spec->dev_num is the maxinum number of device entries
+ * among all the pins
+ */
+ spec->dev_num = (spec->dev_num > dev_num) ?
+ spec->dev_num : dev_num;
+ } else {
+ /*
+ * If the platform doesn't support DP MST,
+ * manually set dev_num to 1. This means
+ * the pin has only one device entry.
+ */
+ dev_num = 1;
+ spec->dev_num = 1;
+ }
+
+ for (i = 0; i < dev_num; i++) {
+ pin_idx = spec->num_pins;
+ per_pin = snd_array_new(&spec->pins);
+
+ if (!per_pin)
+ return -ENOMEM;
+
+ per_pin->pcm = NULL;
+ per_pin->pcm_idx = -1;
+ per_pin->prev_pcm_idx = -1;
+ per_pin->pin_nid = pin_nid;
+ per_pin->pin_nid_idx = spec->num_nids;
+ per_pin->dev_id = i;
+ per_pin->non_pcm = false;
+ snd_hda_set_dev_select(codec, pin_nid, i);
+ err = hdmi_read_pin_conn(codec, pin_idx);
+ if (err < 0)
+ return err;
+ if (!is_jack_detectable(codec, pin_nid))
+ codec_warn(codec, "HDMI: pin NID 0x%x - jack not detectable\n", pin_nid);
+ spec->num_pins++;
+ }
+ spec->num_nids++;
+
+ return 0;
+}
+
+static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_cvt *per_cvt;
+ unsigned int chans;
+ int err;
+
+ chans = get_wcaps(codec, cvt_nid);
+ chans = get_wcaps_channels(chans);
+
+ per_cvt = snd_array_new(&spec->cvts);
+ if (!per_cvt)
+ return -ENOMEM;
+
+ per_cvt->cvt_nid = cvt_nid;
+ per_cvt->channels_min = 2;
+ if (chans <= 16) {
+ per_cvt->channels_max = chans;
+ if (chans > spec->chmap.channels_max)
+ spec->chmap.channels_max = chans;
+ }
+
+ err = snd_hda_query_supported_pcm(codec, cvt_nid,
+ &per_cvt->rates,
+ &per_cvt->formats,
+ NULL,
+ &per_cvt->maxbps);
+ if (err < 0)
+ return err;
+
+ if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
+ spec->cvt_nids[spec->num_cvts] = cvt_nid;
+ spec->num_cvts++;
+
+ return 0;
+}
+
+static const struct snd_pci_quirk force_connect_list[] = {
+ SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1),
+ SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1),
+ SND_PCI_QUIRK(0x103c, 0x845a, "HP EliteDesk 800 G4 DM 65W", 1),
+ SND_PCI_QUIRK(0x103c, 0x83f3, "HP ProDesk 400", 1),
+ SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
+ SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
+ SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
+ SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
+ SND_PCI_QUIRK(0x1043, 0x86ae, "ASUS", 1), /* Z170 PRO */
+ SND_PCI_QUIRK(0x1043, 0x86c7, "ASUS", 1), /* Z170M PLUS */
+ SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
+ SND_PCI_QUIRK(0x8086, 0x2060, "Intel NUC5CPYB", 1),
+ SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
+ {}
+};
+
+int snd_hda_hdmi_parse_codec(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ hda_nid_t start_nid;
+ unsigned int caps;
+ int i, nodes;
+ const struct snd_pci_quirk *q;
+
+ nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
+ if (!start_nid || nodes < 0) {
+ codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
+ return -EINVAL;
+ }
+
+ if (enable_all_pins)
+ spec->force_connect = true;
+
+ q = snd_pci_quirk_lookup(codec->bus->pci, force_connect_list);
+
+ if (q && q->value)
+ spec->force_connect = true;
+
+ /*
+ * hdmi_add_pin() assumes total amount of converters to
+ * be known, so first discover all converters
+ */
+ for (i = 0; i < nodes; i++) {
+ hda_nid_t nid = start_nid + i;
+
+ caps = get_wcaps(codec, nid);
+
+ if (!(caps & AC_WCAP_DIGITAL))
+ continue;
+
+ if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
+ hdmi_add_cvt(codec, nid);
+ }
+
+ /* discover audio pins */
+ for (i = 0; i < nodes; i++) {
+ hda_nid_t nid = start_nid + i;
+
+ caps = get_wcaps(codec, nid);
+
+ if (!(caps & AC_WCAP_DIGITAL))
+ continue;
+
+ if (get_wcaps_type(caps) == AC_WID_PIN)
+ hdmi_add_pin(codec, nid);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_parse_codec, "SND_HDA_CODEC_HDMI");
+
+/*
+ */
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+ struct hda_spdif_out *spdif;
+
+ guard(mutex)(&codec->spdif_mutex);
+ spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
+ /* Add sanity check to pass klockwork check.
+ * This should never happen.
+ */
+ if (WARN_ON(spdif == NULL))
+ return true;
+ return !!(spdif->status & IEC958_AES0_NONAUDIO);
+}
+
+/*
+ * HDMI callbacks
+ */
+
+int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ hda_nid_t cvt_nid = hinfo->nid;
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+ struct hdmi_spec_per_pin *per_pin;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ bool non_pcm;
+ int pinctl, stripe;
+
+ guard(mutex)(&spec->pcm_lock);
+ pin_idx = hinfo_to_pin_index(codec, hinfo);
+ if (pin_idx < 0) {
+ /* when pcm is not bound to a pin skip pin setup and return 0
+ * to make audio playback be ongoing
+ */
+ pin_cvt_fixup(codec, NULL, cvt_nid);
+ snd_hda_codec_setup_stream(codec, cvt_nid,
+ stream_tag, 0, format);
+ return 0;
+ }
+
+ per_pin = get_pin(spec, pin_idx);
+
+ /* Verify pin:cvt selections to avoid silent audio after S3.
+ * After S3, the audio driver restores pin:cvt selections
+ * but this can happen before gfx is ready and such selection
+ * is overlooked by HW. Thus multiple pins can share a same
+ * default convertor and mute control will affect each other,
+ * which can cause a resumed audio playback become silent
+ * after S3.
+ */
+ pin_cvt_fixup(codec, per_pin, 0);
+
+ /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
+ /* Todo: add DP1.2 MST audio support later */
+ if (codec_has_acomp(codec))
+ snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
+ per_pin->dev_id, runtime->rate);
+
+ non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
+ scoped_guard(mutex, &per_pin->lock) {
+ per_pin->channels = substream->runtime->channels;
+ per_pin->setup = true;
+
+ if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) {
+ stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core,
+ substream);
+ snd_hda_codec_write(codec, cvt_nid, 0,
+ AC_VERB_SET_STRIPE_CONTROL,
+ stripe);
+ }
+
+ snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+ }
+ if (spec->dyn_pin_out) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
+ pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl | PIN_OUT);
+ }
+
+ /* snd_hda_set_dev_select() has been called before */
+ return spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid,
+ per_pin->dev_id, stream_tag, format);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_prepare, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_cleanup, "SND_HDA_CODEC_HDMI");
+
+static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int cvt_idx, pin_idx, pcm_idx;
+ struct hdmi_spec_per_cvt *per_cvt;
+ struct hdmi_spec_per_pin *per_pin;
+ int pinctl;
+
+ guard(mutex)(&spec->pcm_lock);
+ if (hinfo->nid) {
+ pcm_idx = hinfo_to_pcm_index(codec, hinfo);
+ if (snd_BUG_ON(pcm_idx < 0))
+ return -EINVAL;
+ cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
+ if (snd_BUG_ON(cvt_idx < 0))
+ return -EINVAL;
+ per_cvt = get_cvt(spec, cvt_idx);
+ per_cvt->assigned = false;
+ hinfo->nid = 0;
+
+ azx_stream(get_azx_dev(substream))->stripe = 0;
+
+ snd_hda_spdif_ctls_unassign(codec, pcm_idx);
+ clear_bit(pcm_idx, &spec->pcm_in_use);
+ pin_idx = hinfo_to_pin_index(codec, hinfo);
+ /*
+ * In such a case, return 0 to match the behavior in
+ * hdmi_pcm_open()
+ */
+ if (pin_idx < 0)
+ return 0;
+
+ per_pin = get_pin(spec, pin_idx);
+
+ if (spec->dyn_pin_out) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
+ pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl & ~PIN_OUT);
+ }
+
+ guard(mutex)(&per_pin->lock);
+ per_pin->chmap_set = false;
+ memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
+
+ per_pin->setup = false;
+ per_pin->channels = 0;
+ }
+
+ return 0;
+}
+
+static const struct hda_pcm_ops generic_ops = {
+ .open = hdmi_pcm_open,
+ .close = hdmi_pcm_close,
+ .prepare = snd_hda_hdmi_generic_pcm_prepare,
+ .cleanup = snd_hda_hdmi_generic_pcm_cleanup,
+};
+
+static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
+{
+ struct hda_codec *codec = hdac_to_hda_codec(hdac);
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+ if (!per_pin)
+ return 0;
+
+ return per_pin->sink_eld.info.spk_alloc;
+}
+
+static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
+ unsigned char *chmap)
+{
+ struct hda_codec *codec = hdac_to_hda_codec(hdac);
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+ /* chmap is already set to 0 in caller */
+ if (!per_pin)
+ return;
+
+ memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap));
+}
+
+static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
+ unsigned char *chmap, int prepared)
+{
+ struct hda_codec *codec = hdac_to_hda_codec(hdac);
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+ if (!per_pin)
+ return;
+ guard(mutex)(&per_pin->lock);
+ per_pin->chmap_set = true;
+ memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
+ if (prepared)
+ snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+}
+
+static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
+{
+ struct hda_codec *codec = hdac_to_hda_codec(hdac);
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+ return per_pin ? true:false;
+}
+
+int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int idx, pcm_num;
+
+ /* limit the PCM devices to the codec converters or available PINs */
+ pcm_num = min(spec->num_cvts, spec->num_pins);
+ codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num);
+
+ for (idx = 0; idx < pcm_num; idx++) {
+ struct hdmi_spec_per_cvt *per_cvt;
+ struct hda_pcm *info;
+ struct hda_pcm_stream *pstr;
+
+ info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
+ if (!info)
+ return -ENOMEM;
+
+ spec->pcm_rec[idx].pcm = info;
+ spec->pcm_used++;
+ info->pcm_type = HDA_PCM_TYPE_HDMI;
+ info->own_chmap = true;
+
+ pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+ pstr->substreams = 1;
+ pstr->ops = generic_ops;
+
+ per_cvt = get_cvt(spec, 0);
+ pstr->channels_min = per_cvt->channels_min;
+ pstr->channels_max = per_cvt->channels_max;
+
+ /* pcm number is less than pcm_rec array size */
+ if (spec->pcm_used >= ARRAY_SIZE(spec->pcm_rec))
+ break;
+ /* other pstr fields are set in open */
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_build_pcms, "SND_HDA_CODEC_HDMI");
+
+static void free_hdmi_jack_priv(struct snd_jack *jack)
+{
+ struct hdmi_pcm *pcm = jack->private_data;
+
+ pcm->jack = NULL;
+}
+
+static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
+{
+ char hdmi_str[32] = "HDMI/DP";
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_jack *jack;
+ int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
+ int err;
+
+ if (pcmdev > 0)
+ sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+
+ err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
+ true, false);
+ if (err < 0)
+ return err;
+
+ spec->pcm_rec[pcm_idx].jack = jack;
+ jack->private_data = &spec->pcm_rec[pcm_idx];
+ jack->private_free = free_hdmi_jack_priv;
+ return 0;
+}
+
+int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int dev, err;
+ int pin_idx, pcm_idx;
+
+ for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
+ if (!get_pcm_rec(spec, pcm_idx)->pcm) {
+ /* no PCM: mark this for skipping permanently */
+ set_bit(pcm_idx, &spec->pcm_bitmap);
+ continue;
+ }
+
+ err = generic_hdmi_build_jack(codec, pcm_idx);
+ if (err < 0)
+ return err;
+
+ /* create the spdif for each pcm
+ * pin will be bound when monitor is connected
+ */
+ err = snd_hda_create_dig_out_ctls(codec,
+ 0, spec->cvt_nids[0],
+ HDA_PCM_TYPE_HDMI);
+ if (err < 0)
+ return err;
+ snd_hda_spdif_ctls_unassign(codec, pcm_idx);
+
+ dev = get_pcm_rec(spec, pcm_idx)->device;
+ if (dev != SNDRV_PCM_INVALID_DEVICE) {
+ /* add control for ELD Bytes */
+ err = hdmi_create_eld_ctl(codec, pcm_idx, dev);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ struct hdmi_eld *pin_eld = &per_pin->sink_eld;
+
+ if (spec->static_pcm_mapping) {
+ hdmi_attach_hda_pcm(spec, per_pin);
+ hdmi_pcm_setup_pin(spec, per_pin);
+ }
+
+ pin_eld->eld_valid = false;
+ hdmi_present_sense(per_pin, 0);
+ }
+
+ /* add channel maps */
+ for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
+ struct hda_pcm *pcm;
+
+ pcm = get_pcm_rec(spec, pcm_idx);
+ if (!pcm || !pcm->pcm)
+ break;
+ err = snd_hdac_add_chmap_ctls(pcm->pcm, pcm_idx, &spec->chmap);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_build_controls, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+ per_pin->codec = codec;
+ mutex_init(&per_pin->lock);
+ INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
+ eld_proc_new(per_pin, pin_idx);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init_per_pins, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_generic_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+
+ guard(mutex)(&spec->bind_lock);
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int dev_id = per_pin->dev_id;
+
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
+ hdmi_init_pin(codec, pin_nid);
+ if (codec_has_acomp(codec))
+ continue;
+ snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id,
+ jack_callback);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init, "SND_HDA_CODEC_HDMI");
+
+static void hdmi_array_init(struct hdmi_spec *spec, int nums)
+{
+ snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
+ snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
+}
+
+static void hdmi_array_free(struct hdmi_spec *spec)
+{
+ snd_array_free(&spec->pins);
+ snd_array_free(&spec->cvts);
+}
+
+void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (spec) {
+ hdmi_array_free(spec);
+ kfree(spec);
+ codec->spec = NULL;
+ }
+ codec->dp_mst = false;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_spec_free, "SND_HDA_CODEC_HDMI");
+
+void snd_hda_hdmi_generic_remove(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx, pcm_idx;
+
+ if (spec->acomp_registered) {
+ snd_hdac_acomp_exit(&codec->bus->core);
+ } else if (codec_has_acomp(codec)) {
+ snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
+ }
+ codec->relaxed_resume = 0;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ cancel_delayed_work_sync(&per_pin->work);
+ eld_proc_free(per_pin);
+ }
+
+ for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
+ if (spec->pcm_rec[pcm_idx].jack == NULL)
+ continue;
+ snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack);
+ }
+
+ snd_hda_hdmi_generic_spec_free(codec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_remove, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_generic_suspend(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ cancel_delayed_work_sync(&per_pin->work);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_suspend, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_generic_resume(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx;
+
+ snd_hda_codec_init(codec);
+ snd_hda_regmap_sync(codec);
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+ hdmi_present_sense(per_pin, 1);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_resume, "SND_HDA_CODEC_HDMI");
+
+static const struct hdmi_ops generic_standard_hdmi_ops = {
+ .pin_get_eld = hdmi_pin_get_eld,
+ .pin_setup_infoframe = hdmi_pin_setup_infoframe,
+ .pin_hbr_setup = hdmi_pin_hbr_setup,
+ .setup_stream = snd_hda_hdmi_setup_stream,
+};
+
+/* allocate codec->spec and assign/initialize generic parser ops */
+int snd_hda_hdmi_generic_alloc(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ spec->codec = codec;
+ spec->ops = generic_standard_hdmi_ops;
+ spec->dev_num = 1; /* initialize to 1 */
+ mutex_init(&spec->pcm_lock);
+ mutex_init(&spec->bind_lock);
+ snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
+
+ spec->chmap.ops.get_chmap = hdmi_get_chmap;
+ spec->chmap.ops.set_chmap = hdmi_set_chmap;
+ spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
+ spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc;
+
+ codec->spec = spec;
+ hdmi_array_init(spec, 4);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_alloc, "SND_HDA_CODEC_HDMI");
+
+/* generic HDMI parser */
+int snd_hda_hdmi_generic_probe(struct hda_codec *codec)
+{
+ int err;
+
+ err = snd_hda_hdmi_generic_alloc(codec);
+ if (err < 0)
+ return err;
+
+ err = snd_hda_hdmi_parse_codec(codec);
+ if (err < 0) {
+ snd_hda_hdmi_generic_spec_free(codec);
+ return err;
+ }
+
+ snd_hda_hdmi_generic_init_per_pins(codec);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_probe, "SND_HDA_CODEC_HDMI");
+
+/*
+ * generic audio component binding
+ */
+
+/* turn on / off the unsol event jack detection dynamically */
+static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid,
+ int dev_id, bool use_acomp)
+{
+ struct hda_jack_tbl *tbl;
+
+ tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
+ if (tbl) {
+ /* clear unsol even if component notifier is used, or re-enable
+ * if notifier is cleared
+ */
+ unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag);
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE, val);
+ }
+}
+
+/* set up / clear component notifier dynamically */
+static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
+ bool use_acomp)
+{
+ struct hdmi_spec *spec;
+ int i;
+
+ spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops);
+ guard(mutex)(&spec->bind_lock);
+ spec->use_acomp_notifier = use_acomp;
+ spec->codec->relaxed_resume = use_acomp;
+ spec->codec->bus->keep_power = 0;
+ /* reprogram each jack detection logic depending on the notifier */
+ for (i = 0; i < spec->num_pins; i++)
+ reprogram_jack_detect(spec->codec,
+ get_pin(spec, i)->pin_nid,
+ get_pin(spec, i)->dev_id,
+ use_acomp);
+}
+
+/* enable / disable the notifier via master bind / unbind */
+int snd_hda_hdmi_acomp_master_bind(struct device *dev,
+ struct drm_audio_component *acomp)
+{
+ generic_acomp_notifier_set(acomp, true);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_master_bind, "SND_HDA_CODEC_HDMI");
+
+void snd_hda_hdmi_acomp_master_unbind(struct device *dev,
+ struct drm_audio_component *acomp)
+{
+ generic_acomp_notifier_set(acomp, false);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_master_unbind, "SND_HDA_CODEC_HDMI");
+
+/* check whether both HD-audio and DRM PCI devices belong to the same bus */
+static int match_bound_vga(struct device *dev, int subtype, void *data)
+{
+ struct hdac_bus *bus = data;
+ struct pci_dev *pci, *master;
+
+ if (!dev_is_pci(dev) || !dev_is_pci(bus->dev))
+ return 0;
+ master = to_pci_dev(bus->dev);
+ pci = to_pci_dev(dev);
+ return master->bus == pci->bus;
+}
+
+/* audio component notifier for AMD/Nvidia HDMI codecs */
+void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
+{
+ struct hda_codec *codec = audio_ptr;
+ struct hdmi_spec *spec = codec->spec;
+ hda_nid_t pin_nid = spec->port2pin(codec, port);
+
+ if (!pin_nid)
+ return;
+ if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN)
+ return;
+ /* skip notification during system suspend (but not in runtime PM);
+ * the state will be updated at resume
+ */
+ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+ return;
+
+ snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_pin_eld_notify, "SND_HDA_CODEC_HDMI");
+
+/* set up the private drm_audio_ops from the template */
+void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec,
+ const struct drm_audio_component_audio_ops *ops)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ spec->drm_audio_ops.audio_ptr = codec;
+ /* intel_audio_codec_enable() or intel_audio_codec_disable()
+ * will call pin_eld_notify with using audio_ptr pointer
+ * We need make sure audio_ptr is really setup
+ */
+ wmb();
+ spec->drm_audio_ops.pin2port = ops->pin2port;
+ spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify;
+ spec->drm_audio_ops.master_bind = ops->master_bind;
+ spec->drm_audio_ops.master_unbind = ops->master_unbind;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_drm_audio_ops, "SND_HDA_CODEC_HDMI");
+
+/* initialize the generic HDMI audio component */
+void snd_hda_hdmi_acomp_init(struct hda_codec *codec,
+ const struct drm_audio_component_audio_ops *ops,
+ int (*port2pin)(struct hda_codec *, int))
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (!enable_acomp) {
+ codec_info(codec, "audio component disabled by module option\n");
+ return;
+ }
+
+ spec->port2pin = port2pin;
+ snd_hda_hdmi_setup_drm_audio_ops(codec, ops);
+ if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
+ match_bound_vga, 0)) {
+ spec->acomp_registered = true;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_init, "SND_HDA_CODEC_HDMI");
+
+/*
+ */
+
+enum {
+ MODEL_GENERIC,
+ MODEL_GF,
+};
+
+static int generichdmi_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
+{
+ int err;
+
+ err = snd_hda_hdmi_generic_probe(codec);
+ if (err < 0)
+ return err;
+ /*
+ * Glenfly GPUs have two codecs, stream switches from one codec to
+ * another, need to do actual clean-ups in codec_cleanup_stream
+ */
+ if (id->driver_data == MODEL_GF)
+ codec->no_sticky_stream = 1;
+
+ return 0;
+}
+
+static const struct hda_codec_ops generichdmi_codec_ops = {
+ .probe = generichdmi_probe,
+ .remove = snd_hda_hdmi_generic_remove,
+ .init = snd_hda_hdmi_generic_init,
+ .build_pcms = snd_hda_hdmi_generic_build_pcms,
+ .build_controls = snd_hda_hdmi_generic_build_controls,
+ .unsol_event = snd_hda_hdmi_generic_unsol_event,
+ .suspend = snd_hda_hdmi_generic_suspend,
+ .resume = snd_hda_hdmi_generic_resume,
+};
+
+/*
+ */
+static const struct hda_device_id snd_hda_id_generichdmi[] = {
+ HDA_CODEC_ID_MODEL(0x00147a47, "Loongson HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10951390, "SiI1390 HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10951392, "SiI1392 HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x11069f84, "VX11 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x11069f85, "VX11 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x17e80047, "Chrontel HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x1d179f86, "ZX-100S HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f87, "ZX-100S HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f88, "KX-5000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f89, "KX-5000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f8a, "KX-6000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f8b, "KX-6000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f8c, "KX-6000G HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f8d, "KX-6000G HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f8e, "KX-7000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f8f, "KX-7000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x1d179f90, "KX-7000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x67663d82, "Arise 82 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x67663d83, "Arise 83 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x67663d84, "Arise 84 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x67663d85, "Arise 85 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x67663d86, "Arise 86 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x67663d87, "Arise 87 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x80862801, "Bearlake HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x80862802, "Cantiga HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x80862803, "Eaglelake HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x80862880, "CedarTrail HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x808629fb, "Crestline HDMI", MODEL_GENERIC),
+ /* special ID for generic HDMI */
+ HDA_CODEC_ID_MODEL(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", MODEL_GENERIC),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generichdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic HDMI HD-audio codec");
+
+static struct hda_codec_driver generichdmi_driver = {
+ .id = snd_hda_id_generichdmi,
+ .ops = &generichdmi_codec_ops,
+};
+
+module_hda_codec_driver(generichdmi_driver);
diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h
new file mode 100644
index 000000000000..548241ad3fa9
--- /dev/null
+++ b/sound/hda/codecs/hdmi/hdmi_local.h
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD-audio HDMI codec driver
+ */
+
+#ifndef __HDA_HDMI_LOCAL_H
+#define __HDA_HDMI_LOCAL_H
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_chmap.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+
+struct hdmi_spec_per_cvt {
+ hda_nid_t cvt_nid;
+ bool assigned; /* the stream has been assigned */
+ bool silent_stream; /* silent stream activated */
+ unsigned int channels_min;
+ unsigned int channels_max;
+ u32 rates;
+ u64 formats;
+ unsigned int maxbps;
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS 32
+
+struct hdmi_spec_per_pin {
+ hda_nid_t pin_nid;
+ int dev_id;
+ /* pin idx, different device entries on the same pin use the same idx */
+ int pin_nid_idx;
+ int num_mux_nids;
+ hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+ int mux_idx;
+ hda_nid_t cvt_nid;
+
+ struct hda_codec *codec;
+ struct hdmi_eld sink_eld;
+ struct mutex lock;
+ struct delayed_work work;
+ struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
+ int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
+ int prev_pcm_idx; /* previously assigned pcm index */
+ int repoll_count;
+ bool setup; /* the stream has been set up by prepare callback */
+ bool silent_stream;
+ int channels; /* current number of channels */
+ bool non_pcm;
+ bool chmap_set; /* channel-map override by ALSA API? */
+ unsigned char chmap[8]; /* ALSA API channel-map */
+#ifdef CONFIG_SND_PROC_FS
+ struct snd_info_entry *proc_entry;
+#endif
+};
+
+/* operations used by generic code that can be overridden by codec drivers */
+struct hdmi_ops {
+ int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
+ int dev_id, unsigned char *buf, int *eld_size);
+
+ void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
+ int dev_id,
+ int ca, int active_channels, int conn_type);
+
+ /* enable/disable HBR (HD passthrough) */
+ int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
+ int dev_id, bool hbr);
+
+ int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+ int format);
+
+ void (*pin_cvt_fixup)(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ hda_nid_t cvt_nid);
+
+ void (*silent_stream)(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ bool enable);
+};
+
+struct hdmi_pcm {
+ struct hda_pcm *pcm;
+ struct snd_jack *jack;
+ struct snd_kcontrol *eld_ctl;
+};
+
+enum {
+ SILENT_STREAM_OFF = 0,
+ SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */
+ SILENT_STREAM_I915, /* Intel i915 extension */
+};
+
+struct hdmi_spec {
+ struct hda_codec *codec;
+ int num_cvts;
+ struct snd_array cvts; /* struct hdmi_spec_per_cvt */
+ hda_nid_t cvt_nids[4]; /* only for haswell fix */
+
+ /*
+ * num_pins is the number of virtual pins
+ * for example, there are 3 pins, and each pin
+ * has 4 device entries, then the num_pins is 12
+ */
+ int num_pins;
+ /*
+ * num_nids is the number of real pins
+ * In the above example, num_nids is 3
+ */
+ int num_nids;
+ /*
+ * dev_num is the number of device entries
+ * on each pin.
+ * In the above example, dev_num is 4
+ */
+ int dev_num;
+ struct snd_array pins; /* struct hdmi_spec_per_pin */
+ struct hdmi_pcm pcm_rec[8];
+ struct mutex pcm_lock;
+ struct mutex bind_lock; /* for audio component binding */
+ /* pcm_bitmap means which pcms have been assigned to pins*/
+ unsigned long pcm_bitmap;
+ int pcm_used; /* counter of pcm_rec[] */
+ /* bitmap shows whether the pcm is opened in user space
+ * bit 0 means the first playback PCM (PCM3);
+ * bit 1 means the second playback PCM, and so on.
+ */
+ unsigned long pcm_in_use;
+
+ struct hdmi_eld temp_eld;
+ struct hdmi_ops ops;
+
+ bool dyn_pin_out;
+ bool static_pcm_mapping;
+ /* hdmi interrupt trigger control flag for Nvidia codec */
+ bool hdmi_intr_trig_ctrl;
+ bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
+
+ bool intel_hsw_fixup; /* apply Intel platform-specific fixups */
+ /*
+ * Non-generic VIA/NVIDIA specific
+ */
+ struct hda_multi_out multiout;
+ struct hda_pcm_stream pcm_playback;
+
+ bool use_acomp_notifier; /* use eld_notify callback for hotplug */
+ bool acomp_registered; /* audio component registered in this driver */
+ bool force_connect; /* force connectivity */
+ struct drm_audio_component_audio_ops drm_audio_ops;
+ int (*port2pin)(struct hda_codec *codec, int port); /* reverse port/pin mapping */
+
+ struct hdac_chmap chmap;
+ hda_nid_t vendor_nid;
+ const int *port_map;
+ int port_num;
+ int silent_stream_type;
+
+ const struct snd_pcm_hw_constraint_list *hw_constraints_channels;
+};
+
+#ifdef CONFIG_SND_HDA_COMPONENT
+static inline bool codec_has_acomp(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ return spec->use_acomp_notifier;
+}
+#else
+#define codec_has_acomp(codec) false
+#endif
+
+struct hdmi_audio_infoframe {
+ u8 type; /* 0x84 */
+ u8 ver; /* 0x01 */
+ u8 len; /* 0x0a */
+
+ u8 checksum;
+
+ u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
+ u8 SS01_SF24;
+ u8 CXT04;
+ u8 CA;
+ u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+struct dp_audio_infoframe {
+ u8 type; /* 0x84 */
+ u8 len; /* 0x1b */
+ u8 ver; /* 0x11 << 2 */
+
+ u8 CC02_CT47; /* match with HDMI infoframe from this on */
+ u8 SS01_SF24;
+ u8 CXT04;
+ u8 CA;
+ u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+union audio_infoframe {
+ struct hdmi_audio_infoframe hdmi;
+ struct dp_audio_infoframe dp;
+ DECLARE_FLEX_ARRAY(u8, bytes);
+};
+
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS 16
+#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+ (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS 24
+#define SUPPORTED_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
+/*
+ * HDMI routines
+ */
+
+#define get_pin(spec, idx) \
+ ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
+#define get_cvt(spec, idx) \
+ ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx))
+/* obtain hdmi_pcm object assigned to idx */
+#define get_hdmi_pcm(spec, idx) (&(spec)->pcm_rec[idx])
+/* obtain hda_pcm object assigned to idx */
+#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
+
+/* Generic HDMI codec support */
+int snd_hda_hdmi_generic_alloc(struct hda_codec *codec);
+int snd_hda_hdmi_parse_codec(struct hda_codec *codec);
+int snd_hda_hdmi_generic_probe(struct hda_codec *codec);
+void snd_hda_hdmi_generic_remove(struct hda_codec *codec);
+
+int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec);
+int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec);
+int snd_hda_hdmi_generic_init(struct hda_codec *codec);
+int snd_hda_hdmi_generic_suspend(struct hda_codec *codec);
+int snd_hda_hdmi_generic_resume(struct hda_codec *codec);
+void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res);
+
+int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id);
+#define pin_id_to_pin_index(codec, pin, dev) \
+ snd_hda_hdmi_pin_id_to_pin_index(codec, pin, dev)
+int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec);
+void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec);
+int snd_hda_hdmi_setup_stream(struct hda_codec *codec,
+ hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, int dev_id,
+ u32 stream_tag, int format);
+
+int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream);
+int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream);
+
+void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec,
+ hda_nid_t nid, int dev_id);
+void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ bool non_pcm);
+
+/* Audio component support */
+void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec,
+ const struct drm_audio_component_audio_ops *ops);
+void snd_hda_hdmi_acomp_init(struct hda_codec *codec,
+ const struct drm_audio_component_audio_ops *ops,
+ int (*port2pin)(struct hda_codec *, int));
+void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id);
+int snd_hda_hdmi_acomp_master_bind(struct device *dev,
+ struct drm_audio_component *acomp);
+void snd_hda_hdmi_acomp_master_unbind(struct device *dev,
+ struct drm_audio_component *acomp);
+
+/* Simple / legacy HDMI codec support */
+int snd_hda_hdmi_simple_probe(struct hda_codec *codec,
+ hda_nid_t cvt_nid, hda_nid_t pin_nid);
+void snd_hda_hdmi_simple_remove(struct hda_codec *codec);
+
+int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec);
+int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec);
+int snd_hda_hdmi_simple_init(struct hda_codec *codec);
+void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec,
+ unsigned int res);
+int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream);
+
+#endif /* __HDA_HDMI_LOCAL_H */
diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c
new file mode 100644
index 000000000000..9460c8db39a9
--- /dev/null
+++ b/sound/hda/codecs/hdmi/intelhdmi.c
@@ -0,0 +1,812 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Intel HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+static bool enable_silent_stream =
+IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
+module_param(enable_silent_stream, bool, 0644);
+MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
+
+enum {
+ MODEL_HSW,
+ MODEL_GLK,
+ MODEL_ICL,
+ MODEL_TGL,
+ MODEL_ADLP,
+ MODEL_BYT,
+ MODEL_CPT,
+};
+
+#define INTEL_GET_VENDOR_VERB 0xf81
+#define INTEL_SET_VENDOR_VERB 0x781
+#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
+#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
+
+static void intel_haswell_enable_all_pins(struct hda_codec *codec,
+ bool update_tree)
+{
+ unsigned int vendor_param;
+ struct hdmi_spec *spec = codec->spec;
+
+ vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+ INTEL_GET_VENDOR_VERB, 0);
+ if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
+ return;
+
+ vendor_param |= INTEL_EN_ALL_PIN_CVTS;
+ vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+ INTEL_SET_VENDOR_VERB, vendor_param);
+ if (vendor_param == -1)
+ return;
+
+ if (update_tree)
+ snd_hda_codec_update_widgets(codec);
+}
+
+static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
+{
+ unsigned int vendor_param;
+ struct hdmi_spec *spec = codec->spec;
+
+ vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+ INTEL_GET_VENDOR_VERB, 0);
+ if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
+ return;
+
+ /* enable DP1.2 mode */
+ vendor_param |= INTEL_EN_DP12;
+ snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
+ snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
+ INTEL_SET_VENDOR_VERB, vendor_param);
+}
+
+/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
+ * Otherwise you may get severe h/w communication errors.
+ */
+static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state)
+{
+ /* check codec->spec: it can be called before the probe gets called */
+ if (codec->spec) {
+ if (power_state == AC_PWRST_D0) {
+ intel_haswell_enable_all_pins(codec, false);
+ intel_haswell_fixup_enable_dp12(codec);
+ }
+ }
+
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state);
+}
+
+/* There is a fixed mapping between audio pin node and display port.
+ * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ *
+ * on VLV, ILK:
+ * Pin Widget 4 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 5 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 6 - PORT D (port = 3 in i915 driver)
+ */
+static int intel_base_nid(struct hda_codec *codec)
+{
+ switch (codec->core.vendor_id) {
+ case 0x80860054: /* ILK */
+ case 0x80862804: /* ILK */
+ case 0x80862882: /* VLV */
+ return 4;
+ default:
+ return 5;
+ }
+}
+
+static int intel_pin2port(void *audio_ptr, int pin_nid)
+{
+ struct hda_codec *codec = audio_ptr;
+ struct hdmi_spec *spec = codec->spec;
+ int base_nid, i;
+
+ if (!spec->port_num) {
+ base_nid = intel_base_nid(codec);
+ if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
+ return -1;
+ return pin_nid - base_nid + 1;
+ }
+
+ /*
+ * looking for the pin number in the mapping table and return
+ * the index which indicate the port number
+ */
+ for (i = 0; i < spec->port_num; i++) {
+ if (pin_nid == spec->port_map[i])
+ return i;
+ }
+
+ codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
+ return -1;
+}
+
+static int intel_port2pin(struct hda_codec *codec, int port)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (!spec->port_num) {
+ /* we assume only from port-B to port-D */
+ if (port < 1 || port > 3)
+ return 0;
+ return port + intel_base_nid(codec) - 1;
+ }
+
+ if (port < 0 || port >= spec->port_num)
+ return 0;
+ return spec->port_map[port];
+}
+
+static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
+{
+ struct hda_codec *codec = audio_ptr;
+ int pin_nid;
+ int dev_id = pipe;
+
+ pin_nid = intel_port2pin(codec, port);
+ if (!pin_nid)
+ return;
+ /* skip notification during system suspend (but not in runtime PM);
+ * the state will be updated at resume
+ */
+ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+ return;
+
+ snd_hdac_i915_set_bclk(&codec->bus->core);
+ snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id);
+}
+
+static const struct drm_audio_component_audio_ops intel_audio_ops = {
+ .pin2port = intel_pin2port,
+ .pin_eld_notify = intel_pin_eld_notify,
+};
+
+/* register i915 component pin_eld_notify callback */
+static void register_i915_notifier(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ spec->use_acomp_notifier = true;
+ spec->port2pin = intel_port2pin;
+ snd_hda_hdmi_setup_drm_audio_ops(codec, &intel_audio_ops);
+ snd_hdac_acomp_register_notifier(&codec->bus->core,
+ &spec->drm_audio_ops);
+ /* no need for forcible resume for jack check thanks to notifier */
+ codec->relaxed_resume = 1;
+}
+
+#define I915_SILENT_RATE 48000
+#define I915_SILENT_CHANNELS 2
+#define I915_SILENT_FORMAT_BITS 16
+#define I915_SILENT_FMT_MASK 0xf
+
+static void silent_stream_enable_i915(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ unsigned int format;
+
+ snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
+ per_pin->dev_id, I915_SILENT_RATE);
+
+ /* trigger silent stream generation in hw */
+ format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS,
+ I915_SILENT_RATE);
+ snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
+ I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
+ usleep_range(100, 200);
+ snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
+
+ per_pin->channels = I915_SILENT_CHANNELS;
+ snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+}
+
+static void silent_stream_set_kae(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ bool enable)
+{
+ unsigned int param;
+
+ codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
+
+ param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
+ param = (param >> 16) & 0xff;
+
+ if (enable)
+ param |= AC_DIG3_KAE;
+ else
+ param &= ~AC_DIG3_KAE;
+
+ snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
+}
+
+static void i915_set_silent_stream(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ bool enable)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ switch (spec->silent_stream_type) {
+ case SILENT_STREAM_KAE:
+ if (enable) {
+ silent_stream_enable_i915(codec, per_pin);
+ silent_stream_set_kae(codec, per_pin, true);
+ } else {
+ silent_stream_set_kae(codec, per_pin, false);
+ }
+ break;
+ case SILENT_STREAM_I915:
+ if (enable) {
+ silent_stream_enable_i915(codec, per_pin);
+ snd_hda_power_up_pm(codec);
+ } else {
+ /* release ref taken in silent_stream_enable() */
+ snd_hda_power_down_pm(codec);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void haswell_verify_D0(struct hda_codec *codec,
+ hda_nid_t cvt_nid, hda_nid_t nid)
+{
+ int pwr;
+
+ /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+ * thus pins could only choose converter 0 for use. Make sure the
+ * converters are in correct power state
+ */
+ if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
+ snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+ if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D0);
+ msleep(40);
+ pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+ pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+ codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
+ }
+}
+
+/* Assure the pin select the right convetor */
+static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int mux_idx, curr;
+
+ mux_idx = per_pin->mux_idx;
+ curr = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+ if (curr != mux_idx)
+ snd_hda_codec_write_cache(codec, pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+}
+
+/* get the mux index for the converter of the pins
+ * converter's mux index is the same for all pins on Intel platform
+ */
+static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
+ hda_nid_t cvt_nid)
+{
+ int i;
+
+ for (i = 0; i < spec->num_cvts; i++)
+ if (spec->cvt_nids[i] == cvt_nid)
+ return i;
+ return -EINVAL;
+}
+
+/* Intel HDMI workaround to fix audio routing issue:
+ * For some Intel display codecs, pins share the same connection list.
+ * So a conveter can be selected by multiple pins and playback on any of these
+ * pins will generate sound on the external display, because audio flows from
+ * the same converter to the display pipeline. Also muting one pin may make
+ * other pins have no sound output.
+ * So this function assures that an assigned converter for a pin is not selected
+ * by any other pins.
+ */
+static void intel_not_share_assigned_cvt(struct hda_codec *codec,
+ hda_nid_t pin_nid,
+ int dev_id, int mux_idx)
+{
+ struct hdmi_spec *spec = codec->spec;
+ hda_nid_t nid;
+ int cvt_idx, curr;
+ struct hdmi_spec_per_cvt *per_cvt;
+ struct hdmi_spec_per_pin *per_pin;
+ int pin_idx;
+
+ /* configure the pins connections */
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ int dev_id_saved;
+ int dev_num;
+
+ per_pin = get_pin(spec, pin_idx);
+ /*
+ * pin not connected to monitor
+ * no need to operate on it
+ */
+ if (!per_pin->pcm)
+ continue;
+
+ if ((per_pin->pin_nid == pin_nid) &&
+ (per_pin->dev_id == dev_id))
+ continue;
+
+ /*
+ * if per_pin->dev_id >= dev_num,
+ * snd_hda_get_dev_select() will fail,
+ * and the following operation is unpredictable.
+ * So skip this situation.
+ */
+ dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
+ if (per_pin->dev_id >= dev_num)
+ continue;
+
+ nid = per_pin->pin_nid;
+
+ /*
+ * Calling this function should not impact
+ * on the device entry selection
+ * So let's save the dev id for each pin,
+ * and restore it when return
+ */
+ dev_id_saved = snd_hda_get_dev_select(codec, nid);
+ snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
+ curr = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+ if (curr != mux_idx) {
+ snd_hda_set_dev_select(codec, nid, dev_id_saved);
+ continue;
+ }
+
+
+ /* choose an unassigned converter. The conveters in the
+ * connection list are in the same order as in the codec.
+ */
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+ per_cvt = get_cvt(spec, cvt_idx);
+ if (!per_cvt->assigned) {
+ codec_dbg(codec,
+ "choose cvt %d for pin NID 0x%x\n",
+ cvt_idx, nid);
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ cvt_idx);
+ break;
+ }
+ }
+ snd_hda_set_dev_select(codec, nid, dev_id_saved);
+ }
+}
+
+/* A wrapper of intel_not_share_asigned_cvt() */
+static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
+{
+ int mux_idx;
+ struct hdmi_spec *spec = codec->spec;
+
+ /* On Intel platform, the mapping of converter nid to
+ * mux index of the pins are always the same.
+ * The pin nid may be 0, this means all pins will not
+ * share the converter.
+ */
+ mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
+ if (mux_idx >= 0)
+ intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
+}
+
+/* setup_stream ops override for HSW+ */
+static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+ int format)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
+ struct hdmi_spec_per_pin *per_pin;
+ int res;
+
+ if (pin_idx < 0)
+ per_pin = NULL;
+ else
+ per_pin = get_pin(spec, pin_idx);
+
+ haswell_verify_D0(codec, cvt_nid, pin_nid);
+
+ if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+ silent_stream_set_kae(codec, per_pin, false);
+ /* wait for pending transfers in codec to clear */
+ usleep_range(100, 200);
+ }
+
+ res = snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+ stream_tag, format);
+
+ if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+ usleep_range(100, 200);
+ silent_stream_set_kae(codec, per_pin, true);
+ }
+
+ return res;
+}
+
+/* pin_cvt_fixup ops override for HSW+ and VLV+ */
+static void i915_pin_cvt_fixup(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ hda_nid_t cvt_nid)
+{
+ if (per_pin) {
+ haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
+ intel_verify_pin_cvt_connect(codec, per_pin);
+ intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+ per_pin->dev_id, per_pin->mux_idx);
+ } else {
+ intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
+ }
+}
+
+static int i915_hdmi_suspend(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ bool silent_streams = false;
+ int pin_idx, res;
+
+ res = snd_hda_hdmi_generic_suspend(codec);
+ if (spec->silent_stream_type != SILENT_STREAM_KAE)
+ return res;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+ if (per_pin->silent_stream) {
+ silent_streams = true;
+ break;
+ }
+ }
+
+ if (silent_streams) {
+ /*
+ * stream-id should remain programmed when codec goes
+ * to runtime suspend
+ */
+ codec->no_stream_clean_at_suspend = 1;
+
+ /*
+ * the system might go to S3, in which case keep-alive
+ * must be reprogrammed upon resume
+ */
+ codec->forced_resume = 1;
+
+ codec_dbg(codec, "HDMI: KAE active at suspend\n");
+ } else {
+ codec->no_stream_clean_at_suspend = 0;
+ codec->forced_resume = 0;
+ }
+
+ return res;
+}
+
+static int i915_hdmi_resume(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx, res;
+
+ res = snd_hda_hdmi_generic_resume(codec);
+ if (spec->silent_stream_type != SILENT_STREAM_KAE)
+ return res;
+
+ /* KAE not programmed at suspend, nothing to do here */
+ if (!codec->no_stream_clean_at_suspend)
+ return res;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+ /*
+ * If system was in suspend with monitor connected,
+ * the codec setting may have been lost. Re-enable
+ * keep-alive.
+ */
+ if (per_pin->silent_stream) {
+ unsigned int param;
+
+ param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
+ AC_VERB_GET_CONV, 0);
+ if (!param) {
+ codec_dbg(codec, "HDMI: KAE: restore stream id\n");
+ silent_stream_enable_i915(codec, per_pin);
+ }
+
+ param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
+ AC_VERB_GET_DIGI_CONVERT_1, 0);
+ if (!(param & (AC_DIG3_KAE << 16))) {
+ codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
+ silent_stream_set_kae(codec, per_pin, true);
+ }
+ }
+ }
+
+ return res;
+}
+
+/* precondition and allocation for Intel codecs */
+static int alloc_intel_hdmi(struct hda_codec *codec)
+{
+ /* requires i915 binding */
+ if (!codec->bus->core.audio_component) {
+ codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+ /* set probe_id here to prevent generic fallback binding */
+ codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
+ return -ENODEV;
+ }
+
+ return snd_hda_hdmi_generic_alloc(codec);
+}
+
+/* parse and post-process for Intel codecs */
+static int parse_intel_hdmi(struct hda_codec *codec)
+{
+ int err, retries = 3;
+
+ do {
+ err = snd_hda_hdmi_parse_codec(codec);
+ } while (err < 0 && retries--);
+
+ if (err < 0)
+ return err;
+
+ snd_hda_hdmi_generic_init_per_pins(codec);
+ register_i915_notifier(codec);
+ return 0;
+}
+
+/* Intel Haswell and onwards; audio component with eld notifier */
+static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
+ const int *port_map, int port_num, int dev_num,
+ bool send_silent_stream)
+{
+ struct hdmi_spec *spec;
+
+ spec = codec->spec;
+ codec->dp_mst = true;
+ spec->vendor_nid = vendor_nid;
+ spec->port_map = port_map;
+ spec->port_num = port_num;
+ spec->intel_hsw_fixup = true;
+ spec->dev_num = dev_num;
+
+ intel_haswell_enable_all_pins(codec, true);
+ intel_haswell_fixup_enable_dp12(codec);
+
+ codec->display_power_control = 1;
+
+ codec->depop_delay = 0;
+ codec->auto_runtime_pm = 1;
+
+ spec->ops.setup_stream = i915_hsw_setup_stream;
+ spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+ spec->ops.silent_stream = i915_set_silent_stream;
+
+ /*
+ * Enable silent stream feature, if it is enabled via
+ * module param or Kconfig option
+ */
+ if (send_silent_stream)
+ spec->silent_stream_type = SILENT_STREAM_I915;
+
+ return parse_intel_hdmi(codec);
+}
+
+static int probe_i915_hsw_hdmi(struct hda_codec *codec)
+{
+ return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
+ enable_silent_stream);
+}
+
+static int probe_i915_glk_hdmi(struct hda_codec *codec)
+{
+ /*
+ * Silent stream calls audio component .get_power() from
+ * .pin_eld_notify(). On GLK this will deadlock in i915 due
+ * to the audio vs. CDCLK workaround.
+ */
+ return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
+}
+
+static int probe_i915_icl_hdmi(struct hda_codec *codec)
+{
+ /*
+ * pin to port mapping table where the value indicate the pin number and
+ * the index indicate the port number.
+ */
+ static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
+
+ return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
+ enable_silent_stream);
+}
+
+static int probe_i915_tgl_hdmi(struct hda_codec *codec)
+{
+ /*
+ * pin to port mapping table where the value indicate the pin number and
+ * the index indicate the port number.
+ */
+ static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+ return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
+ enable_silent_stream);
+}
+
+static int probe_i915_adlp_hdmi(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int res;
+
+ res = probe_i915_tgl_hdmi(codec);
+ if (!res) {
+ spec = codec->spec;
+
+ if (spec->silent_stream_type)
+ spec->silent_stream_type = SILENT_STREAM_KAE;
+ }
+
+ return res;
+}
+
+/* Intel Baytrail and Braswell; with eld notifier */
+static int probe_i915_byt_hdmi(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+
+ spec = codec->spec;
+
+ /* For Valleyview/Cherryview, only the display codec is in the display
+ * power well and can use link_power ops to request/release the power.
+ */
+ codec->display_power_control = 1;
+
+ codec->depop_delay = 0;
+ codec->auto_runtime_pm = 1;
+
+ spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
+ return parse_intel_hdmi(codec);
+}
+
+/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
+static int probe_i915_cpt_hdmi(struct hda_codec *codec)
+{
+ return parse_intel_hdmi(codec);
+}
+
+/*
+ * common driver probe
+ */
+static int intelhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ int err;
+
+ err = alloc_intel_hdmi(codec);
+ if (err < 0)
+ return err;
+
+ switch (id->driver_data) {
+ case MODEL_HSW:
+ err = probe_i915_hsw_hdmi(codec);
+ break;
+ case MODEL_GLK:
+ err = probe_i915_glk_hdmi(codec);
+ break;
+ case MODEL_ICL:
+ err = probe_i915_icl_hdmi(codec);
+ break;
+ case MODEL_TGL:
+ err = probe_i915_tgl_hdmi(codec);
+ break;
+ case MODEL_ADLP:
+ err = probe_i915_adlp_hdmi(codec);
+ break;
+ case MODEL_BYT:
+ err = probe_i915_byt_hdmi(codec);
+ break;
+ case MODEL_CPT:
+ err = probe_i915_cpt_hdmi(codec);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err < 0) {
+ snd_hda_hdmi_generic_spec_free(codec);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct hda_codec_ops intelhdmi_codec_ops = {
+ .probe = intelhdmi_probe,
+ .remove = snd_hda_hdmi_generic_remove,
+ .init = snd_hda_hdmi_generic_init,
+ .build_pcms = snd_hda_hdmi_generic_build_pcms,
+ .build_controls = snd_hda_hdmi_generic_build_controls,
+ .unsol_event = snd_hda_hdmi_generic_unsol_event,
+ .suspend = i915_hdmi_suspend,
+ .resume = i915_hdmi_resume,
+ .set_power_state = haswell_set_power_state,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_intelhdmi[] = {
+ HDA_CODEC_ID_MODEL(0x80860054, "IbexPeak HDMI", MODEL_CPT),
+ HDA_CODEC_ID_MODEL(0x80862800, "Geminilake HDMI", MODEL_GLK),
+ HDA_CODEC_ID_MODEL(0x80862804, "IbexPeak HDMI", MODEL_CPT),
+ HDA_CODEC_ID_MODEL(0x80862805, "CougarPoint HDMI", MODEL_CPT),
+ HDA_CODEC_ID_MODEL(0x80862806, "PantherPoint HDMI", MODEL_CPT),
+ HDA_CODEC_ID_MODEL(0x80862807, "Haswell HDMI", MODEL_HSW),
+ HDA_CODEC_ID_MODEL(0x80862808, "Broadwell HDMI", MODEL_HSW),
+ HDA_CODEC_ID_MODEL(0x80862809, "Skylake HDMI", MODEL_HSW),
+ HDA_CODEC_ID_MODEL(0x8086280a, "Broxton HDMI", MODEL_HSW),
+ HDA_CODEC_ID_MODEL(0x8086280b, "Kabylake HDMI", MODEL_HSW),
+ HDA_CODEC_ID_MODEL(0x8086280c, "Cannonlake HDMI", MODEL_GLK),
+ HDA_CODEC_ID_MODEL(0x8086280d, "Geminilake HDMI", MODEL_GLK),
+ HDA_CODEC_ID_MODEL(0x8086280f, "Icelake HDMI", MODEL_ICL),
+ HDA_CODEC_ID_MODEL(0x80862812, "Tigerlake HDMI", MODEL_TGL),
+ HDA_CODEC_ID_MODEL(0x80862814, "DG1 HDMI", MODEL_TGL),
+ HDA_CODEC_ID_MODEL(0x80862815, "Alderlake HDMI", MODEL_TGL),
+ HDA_CODEC_ID_MODEL(0x80862816, "Rocketlake HDMI", MODEL_TGL),
+ HDA_CODEC_ID_MODEL(0x80862818, "Raptorlake HDMI", MODEL_TGL),
+ HDA_CODEC_ID_MODEL(0x80862819, "DG2 HDMI", MODEL_TGL),
+ HDA_CODEC_ID_MODEL(0x8086281a, "Jasperlake HDMI", MODEL_ICL),
+ HDA_CODEC_ID_MODEL(0x8086281b, "Elkhartlake HDMI", MODEL_ICL),
+ HDA_CODEC_ID_MODEL(0x8086281c, "Alderlake-P HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x8086281d, "Meteor Lake HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x8086281e, "Battlemage HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x8086281f, "Raptor Lake P HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x80862820, "Lunar Lake HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x80862822, "Panther Lake HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x80862823, "Wildcat Lake HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x80862824, "Nova Lake HDMI", MODEL_ADLP),
+ HDA_CODEC_ID_MODEL(0x80862882, "Valleyview2 HDMI", MODEL_BYT),
+ HDA_CODEC_ID_MODEL(0x80862883, "Braswell HDMI", MODEL_BYT),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_intelhdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver intelhdmi_driver = {
+ .id = snd_hda_id_intelhdmi,
+ .ops = &intelhdmi_codec_ops,
+};
+
+module_hda_codec_driver(intelhdmi_driver);
diff --git a/sound/hda/codecs/hdmi/nvhdmi-mcp.c b/sound/hda/codecs/hdmi/nvhdmi-mcp.c
new file mode 100644
index 000000000000..1c5fdfe872f2
--- /dev/null
+++ b/sound/hda/codecs/hdmi/nvhdmi-mcp.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Legacy Nvidia HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+enum { MODEL_2CH, MODEL_8CH };
+
+#define Nv_VERB_SET_Channel_Allocation 0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
+#define Nv_VERB_SET_Audio_Protection_On 0xF98
+#define Nv_VERB_SET_Audio_Protection_Off 0xF99
+
+#define nvhdmi_master_con_nid_7x 0x04
+#define nvhdmi_master_pin_nid_7x 0x05
+
+static const hda_nid_t nvhdmi_con_nids_7x[4] = {
+ /*front, rear, clfe, rear_surr */
+ 0x6, 0x8, 0xa, 0xc,
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
+ /* set audio protect on */
+ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+ /* enable digital output on pin widget */
+ { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ {} /* terminator */
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
+ /* set audio protect on */
+ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+ /* enable digital output on pin widget */
+ { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+ {} /* terminator */
+};
+
+static int nvhdmi_mcp_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (spec->multiout.max_channels == 2)
+ snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
+ else
+ snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
+ return 0;
+}
+
+static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
+ int channels)
+{
+ unsigned int chanmask;
+ int chan = channels ? (channels - 1) : 1;
+
+ switch (channels) {
+ default:
+ case 0:
+ case 2:
+ chanmask = 0x00;
+ break;
+ case 4:
+ chanmask = 0x08;
+ break;
+ case 6:
+ chanmask = 0x0b;
+ break;
+ case 8:
+ chanmask = 0x13;
+ break;
+ }
+
+ /* Set the audio infoframe channel allocation and checksum fields. The
+ * channel count is computed implicitly by the hardware.
+ */
+ snd_hda_codec_write(codec, 0x1, 0,
+ Nv_VERB_SET_Channel_Allocation, chanmask);
+
+ snd_hda_codec_write(codec, 0x1, 0,
+ Nv_VERB_SET_Info_Frame_Checksum,
+ (0x71 - chan - chanmask));
+}
+
+static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int i;
+
+ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
+ 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+ for (i = 0; i < 4; i++) {
+ /* set the stream id */
+ snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+ AC_VERB_SET_CHANNEL_STREAMID, 0);
+ /* set the stream format */
+ snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+ AC_VERB_SET_STREAM_FORMAT, 0);
+ }
+
+ /* The audio hardware sends a channel count of 0x7 (8ch) when all the
+ * streams are disabled.
+ */
+ nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
+
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ int chs;
+ unsigned int dataDCC2, channel_id;
+ int i;
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_spdif_out *spdif;
+ struct hdmi_spec_per_cvt *per_cvt;
+
+ guard(mutex)(&codec->spdif_mutex);
+ per_cvt = get_cvt(spec, 0);
+ spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
+
+ chs = substream->runtime->channels;
+
+ dataDCC2 = 0x2;
+
+ /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+ if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
+ snd_hda_codec_write(codec,
+ nvhdmi_master_con_nid_7x,
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
+
+ /* set the stream id */
+ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+ /* set the stream format */
+ snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+ AC_VERB_SET_STREAM_FORMAT, format);
+
+ /* turn on again (if needed) */
+ /* enable and set the channel status audio/data flag */
+ if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
+ snd_hda_codec_write(codec,
+ nvhdmi_master_con_nid_7x,
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ spdif->ctls & 0xff);
+ snd_hda_codec_write(codec,
+ nvhdmi_master_con_nid_7x,
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (chs == 2)
+ channel_id = 0;
+ else
+ channel_id = i * 2;
+
+ /* turn off SPDIF once;
+ *otherwise the IEC958 bits won't be updated
+ */
+ if (codec->spdif_status_reset &&
+ (spdif->ctls & AC_DIG1_ENABLE))
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
+ /* set the stream id */
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_CHANNEL_STREAMID,
+ (stream_tag << 4) | channel_id);
+ /* set the stream format */
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_STREAM_FORMAT,
+ format);
+ /* turn on again (if needed) */
+ /* enable and set the channel status audio/data flag */
+ if (codec->spdif_status_reset &&
+ (spdif->ctls & AC_DIG1_ENABLE)) {
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ spdif->ctls & 0xff);
+ snd_hda_codec_write(codec,
+ nvhdmi_con_nids_7x[i],
+ 0,
+ AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+ }
+ }
+
+ nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
+
+ return 0;
+}
+
+static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 8,
+ .nid = nvhdmi_master_con_nid_7x,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
+ .ops = {
+ .open = snd_hda_hdmi_simple_pcm_open,
+ .close = nvhdmi_8ch_7x_pcm_close,
+ .prepare = nvhdmi_8ch_7x_pcm_prepare
+ },
+};
+
+static int nvhdmi_mcp_build_pcms(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_hdmi_simple_build_pcms(codec);
+ if (!err && spec->multiout.max_channels == 8) {
+ struct hda_pcm *info = get_pcm_rec(spec, 0);
+
+ info->own_chmap = true;
+ }
+ return err;
+}
+
+static int nvhdmi_mcp_build_controls(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_pcm *info;
+ struct snd_pcm_chmap *chmap;
+ int err;
+
+ err = snd_hda_hdmi_simple_build_controls(codec);
+ if (err < 0)
+ return err;
+
+ if (spec->multiout.max_channels != 8)
+ return 0;
+
+ /* add channel maps */
+ info = get_pcm_rec(spec, 0);
+ err = snd_pcm_add_chmap_ctls(info->pcm,
+ SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, 8, 0, &chmap);
+ if (err < 0)
+ return err;
+ switch (codec->preset->vendor_id) {
+ case 0x10de0002:
+ case 0x10de0003:
+ case 0x10de0005:
+ case 0x10de0006:
+ chmap->channel_mask = (1U << 2) | (1U << 8);
+ break;
+ case 0x10de0007:
+ chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
+ }
+ return 0;
+}
+
+static const unsigned int channels_2_6_8[] = {
+ 2, 6, 8
+};
+
+static const unsigned int channels_2_8[] = {
+ 2, 8
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
+ .count = ARRAY_SIZE(channels_2_6_8),
+ .list = channels_2_6_8,
+ .mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
+ .count = ARRAY_SIZE(channels_2_8),
+ .list = channels_2_8,
+ .mask = 0,
+};
+
+static int nvhdmi_mcp_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
+{
+ struct hdmi_spec *spec;
+ int err;
+
+ err = snd_hda_hdmi_simple_probe(codec, nvhdmi_master_con_nid_7x,
+ nvhdmi_master_pin_nid_7x);
+ if (err < 0)
+ return err;
+
+ /* override the PCM rates, etc, as the codec doesn't give full list */
+ spec = codec->spec;
+ spec->pcm_playback.rates = SUPPORTED_RATES;
+ spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
+ spec->pcm_playback.formats = SUPPORTED_FORMATS;
+ spec->nv_dp_workaround = true;
+
+ if (id->driver_data == MODEL_2CH)
+ return 0;
+
+ spec->multiout.max_channels = 8;
+ spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
+
+ switch (codec->preset->vendor_id) {
+ case 0x10de0002:
+ case 0x10de0003:
+ case 0x10de0005:
+ case 0x10de0006:
+ spec->hw_constraints_channels = &hw_constraints_2_8_channels;
+ break;
+ case 0x10de0007:
+ spec->hw_constraints_channels = &hw_constraints_2_6_8_channels;
+ break;
+ default:
+ break;
+ }
+
+ /* Initialize the audio infoframe channel mask and checksum to something
+ * valid
+ */
+ nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
+
+ return 0;
+}
+
+static const struct hda_codec_ops nvhdmi_mcp_codec_ops = {
+ .probe = nvhdmi_mcp_probe,
+ .remove = snd_hda_hdmi_simple_remove,
+ .build_pcms = nvhdmi_mcp_build_pcms,
+ .build_controls = nvhdmi_mcp_build_controls,
+ .init = nvhdmi_mcp_init,
+ .unsol_event = snd_hda_hdmi_simple_unsol_event,
+};
+
+static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = {
+ HDA_CODEC_ID_MODEL(0x10de0001, "MCP73 HDMI", MODEL_2CH),
+ HDA_CODEC_ID_MODEL(0x10de0002, "MCP77/78 HDMI", MODEL_8CH),
+ HDA_CODEC_ID_MODEL(0x10de0003, "MCP77/78 HDMI", MODEL_8CH),
+ HDA_CODEC_ID_MODEL(0x10de0004, "GPU 04 HDMI", MODEL_8CH),
+ HDA_CODEC_ID_MODEL(0x10de0005, "MCP77/78 HDMI", MODEL_8CH),
+ HDA_CODEC_ID_MODEL(0x10de0006, "MCP77/78 HDMI", MODEL_8CH),
+ HDA_CODEC_ID_MODEL(0x10de0007, "MCP79/7A HDMI", MODEL_8CH),
+ HDA_CODEC_ID_MODEL(0x10de0067, "MCP67 HDMI", MODEL_2CH),
+ HDA_CODEC_ID_MODEL(0x10de8001, "MCP73 HDMI", MODEL_2CH),
+ HDA_CODEC_ID_MODEL(0x10de8067, "MCP67/68 HDMI", MODEL_2CH),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Legacy Nvidia HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver nvhdmi_mcp_driver = {
+ .id = snd_hda_id_nvhdmi_mcp,
+ .ops = &nvhdmi_mcp_codec_ops,
+};
+
+module_hda_codec_driver(nvhdmi_mcp_driver);
diff --git a/sound/hda/codecs/hdmi/nvhdmi.c b/sound/hda/codecs/hdmi/nvhdmi.c
new file mode 100644
index 000000000000..94671ad24b5e
--- /dev/null
+++ b/sound/hda/codecs/hdmi/nvhdmi.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Nvidia HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+enum {
+ MODEL_GENERIC,
+ MODEL_LEGACY,
+};
+
+/*
+ * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
+ * - 0x10de0015
+ * - 0x10de0040
+ */
+static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
+ struct hdac_cea_channel_speaker_allocation *cap, int channels)
+{
+ if (cap->ca_index == 0x00 && channels == 2)
+ return SNDRV_CTL_TLVT_CHMAP_FIXED;
+
+ /* If the speaker allocation matches the channel count, it is OK. */
+ if (cap->channels != channels)
+ return -1;
+
+ /* all channels are remappable freely */
+ return SNDRV_CTL_TLVT_CHMAP_VAR;
+}
+
+static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
+ int ca, int chs, unsigned char *map)
+{
+ if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
+ return -EINVAL;
+
+ return 0;
+}
+
+/* map from pin NID to port; port is 0-based */
+/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
+static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
+{
+ return pin_nid - 4;
+}
+
+/* reverse-map from port to pin NID: see above */
+static int nvhdmi_port2pin(struct hda_codec *codec, int port)
+{
+ return port + 4;
+}
+
+static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
+ .pin2port = nvhdmi_pin2port,
+ .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify,
+ .master_bind = snd_hda_hdmi_acomp_master_bind,
+ .master_unbind = snd_hda_hdmi_acomp_master_unbind,
+};
+
+static int probe_generic(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int err;
+
+ err = snd_hda_hdmi_generic_alloc(codec);
+ if (err < 0)
+ return err;
+ codec->dp_mst = true;
+
+ spec = codec->spec;
+
+ err = snd_hda_hdmi_parse_codec(codec);
+ if (err < 0) {
+ snd_hda_hdmi_generic_spec_free(codec);
+ return err;
+ }
+
+ snd_hda_hdmi_generic_init_per_pins(codec);
+
+ spec->dyn_pin_out = true;
+
+ spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+ nvhdmi_chmap_cea_alloc_validate_get_type;
+ spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+ spec->nv_dp_workaround = true;
+
+ codec->link_down_at_suspend = 1;
+
+ snd_hda_hdmi_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
+
+ return 0;
+}
+
+static int probe_legacy(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int err;
+
+ err = snd_hda_hdmi_generic_probe(codec);
+ if (err)
+ return err;
+
+ spec = codec->spec;
+ spec->dyn_pin_out = true;
+
+ spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+ nvhdmi_chmap_cea_alloc_validate_get_type;
+ spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+ spec->nv_dp_workaround = true;
+
+ codec->link_down_at_suspend = 1;
+
+ return 0;
+}
+
+static int nvhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ if (id->driver_data == MODEL_LEGACY)
+ return probe_legacy(codec);
+ else
+ return probe_generic(codec);
+}
+
+static const struct hda_codec_ops nvhdmi_codec_ops = {
+ .probe = nvhdmi_probe,
+ .remove = snd_hda_hdmi_generic_remove,
+ .init = snd_hda_hdmi_generic_init,
+ .build_pcms = snd_hda_hdmi_generic_build_pcms,
+ .build_controls = snd_hda_hdmi_generic_build_controls,
+ .unsol_event = snd_hda_hdmi_generic_unsol_event,
+ .suspend = snd_hda_hdmi_generic_suspend,
+ .resume = snd_hda_hdmi_generic_resume,
+};
+
+static const struct hda_device_id snd_hda_id_nvhdmi[] = {
+ HDA_CODEC_ID_MODEL(0x10de0008, "GPU 08 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0009, "GPU 09 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de000a, "GPU 0a HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de000b, "GPU 0b HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de000c, "MCP89 HDMI", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de000d, "GPU 0d HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0010, "GPU 10 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0011, "GPU 11 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0012, "GPU 12 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0013, "GPU 13 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0014, "GPU 14 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0015, "GPU 15 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0016, "GPU 16 HDMI/DP", MODEL_LEGACY),
+ /* 17 is known to be absent */
+ HDA_CODEC_ID_MODEL(0x10de0018, "GPU 18 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0019, "GPU 19 HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de001a, "GPU 1a HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de001b, "GPU 1b HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de001c, "GPU 1c HDMI/DP", MODEL_LEGACY),
+ HDA_CODEC_ID_MODEL(0x10de0040, "GPU 40 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0041, "GPU 41 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0042, "GPU 42 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0043, "GPU 43 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0044, "GPU 44 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0045, "GPU 45 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0050, "GPU 50 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0051, "GPU 51 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0052, "GPU 52 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0060, "GPU 60 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0061, "GPU 61 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0062, "GPU 62 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0070, "GPU 70 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0071, "GPU 71 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0072, "GPU 72 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0073, "GPU 73 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0074, "GPU 74 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0076, "GPU 76 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de007b, "GPU 7b HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de007c, "GPU 7c HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de007d, "GPU 7d HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de007e, "GPU 7e HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0080, "GPU 80 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0081, "GPU 81 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0082, "GPU 82 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0083, "GPU 83 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0084, "GPU 84 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0090, "GPU 90 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0091, "GPU 91 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0092, "GPU 92 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0093, "GPU 93 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0094, "GPU 94 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0095, "GPU 95 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0097, "GPU 97 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0098, "GPU 98 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de0099, "GPU 99 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de009a, "GPU 9a HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de009b, "GPU 9b HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de009c, "GPU 9c HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de009d, "GPU 9d HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de009e, "GPU 9e HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de009f, "GPU 9f HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a0, "GPU a0 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a1, "GPU a1 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a3, "GPU a3 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a4, "GPU a4 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a5, "GPU a5 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a6, "GPU a6 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a7, "GPU a7 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a8, "GPU a8 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00a9, "GPU a9 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00aa, "GPU aa HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00ab, "GPU ab HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00ad, "GPU ad HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00ae, "GPU ae HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00af, "GPU af HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00b0, "GPU b0 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00b1, "GPU b1 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00c0, "GPU c0 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00c1, "GPU c1 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00c3, "GPU c3 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00c4, "GPU c4 HDMI/DP", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x10de00c5, "GPU c5 HDMI/DP", MODEL_GENERIC),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver nvhdmi_driver = {
+ .id = snd_hda_id_nvhdmi,
+ .ops = &nvhdmi_codec_ops,
+};
+
+module_hda_codec_driver(nvhdmi_driver);
diff --git a/sound/hda/codecs/hdmi/simplehdmi.c b/sound/hda/codecs/hdmi/simplehdmi.c
new file mode 100644
index 000000000000..193c8dc882af
--- /dev/null
+++ b/sound/hda/codecs/hdmi/simplehdmi.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Non-generic simple HDMI codec support
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "hdmi_local.h"
+#include "hda_jack.h"
+
+int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_pcm *info;
+ unsigned int chans;
+ struct hda_pcm_stream *pstr;
+ struct hdmi_spec_per_cvt *per_cvt;
+
+ per_cvt = get_cvt(spec, 0);
+ chans = get_wcaps(codec, per_cvt->cvt_nid);
+ chans = get_wcaps_channels(chans);
+
+ info = snd_hda_codec_pcm_new(codec, "HDMI 0");
+ if (!info)
+ return -ENOMEM;
+ spec->pcm_rec[0].pcm = info;
+ info->pcm_type = HDA_PCM_TYPE_HDMI;
+ pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+ *pstr = spec->pcm_playback;
+ pstr->nid = per_cvt->cvt_nid;
+ if (pstr->channels_max <= 2 && chans && chans <= 16)
+ pstr->channels_max = chans;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_build_pcms, "SND_HDA_CODEC_HDMI");
+
+/* unsolicited event for jack sensing */
+void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ snd_hda_jack_set_dirty_all(codec);
+ snd_hda_jack_report_sync(codec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_unsol_event, "SND_HDA_CODEC_HDMI");
+
+static void free_hdmi_jack_priv(struct snd_jack *jack)
+{
+ struct hdmi_pcm *pcm = jack->private_data;
+
+ pcm->jack = NULL;
+}
+
+static int simple_hdmi_build_jack(struct hda_codec *codec)
+{
+ char hdmi_str[32] = "HDMI/DP";
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_jack *jack;
+ struct hdmi_pcm *pcmp = get_hdmi_pcm(spec, 0);
+ int pcmdev = pcmp->pcm->device;
+ int err;
+
+ if (pcmdev > 0)
+ sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+
+ err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
+ true, false);
+ if (err < 0)
+ return err;
+
+ pcmp->jack = jack;
+ jack->private_data = pcmp;
+ jack->private_free = free_hdmi_jack_priv;
+ return 0;
+}
+
+int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_cvt *per_cvt;
+ int err;
+
+ per_cvt = get_cvt(spec, 0);
+ err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
+ per_cvt->cvt_nid,
+ HDA_PCM_TYPE_HDMI);
+ if (err < 0)
+ return err;
+ return simple_hdmi_build_jack(codec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_build_controls, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_simple_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
+ hda_nid_t pin = per_pin->pin_nid;
+
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ /* some codecs require to unmute the pin */
+ if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+ snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_init, "SND_HDA_CODEC_HDMI");
+
+void snd_hda_hdmi_simple_remove(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ snd_array_free(&spec->pins);
+ snd_array_free(&spec->cvts);
+ kfree(spec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_remove, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ if (spec->hw_constraints_channels) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ spec->hw_constraints_channels);
+ } else {
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ }
+
+ return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_pcm_open, "SND_HDA_CODEC_HDMI");
+
+static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+ stream_tag, format, substream);
+}
+
+static const struct hda_pcm_stream simple_pcm_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .ops = {
+ .open = snd_hda_hdmi_simple_pcm_open,
+ .close = simple_playback_pcm_close,
+ .prepare = simple_playback_pcm_prepare
+ },
+};
+
+int snd_hda_hdmi_simple_probe(struct hda_codec *codec,
+ hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+ struct hdmi_spec *spec;
+ struct hdmi_spec_per_cvt *per_cvt;
+ struct hdmi_spec_per_pin *per_pin;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ spec->codec = codec;
+ codec->spec = spec;
+ snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), 1);
+ snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), 1);
+
+ spec->multiout.num_dacs = 0; /* no analog */
+ spec->multiout.max_channels = 2;
+ spec->multiout.dig_out_nid = cvt_nid;
+ spec->num_cvts = 1;
+ spec->num_pins = 1;
+ per_pin = snd_array_new(&spec->pins);
+ per_cvt = snd_array_new(&spec->cvts);
+ if (!per_pin || !per_cvt) {
+ snd_hda_hdmi_simple_remove(codec);
+ return -ENOMEM;
+ }
+ per_cvt->cvt_nid = cvt_nid;
+ per_pin->pin_nid = pin_nid;
+ spec->pcm_playback = simple_pcm_playback;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_probe, "SND_HDA_CODEC_HDMI");
+
+/*
+ * driver entries
+ */
+
+enum { MODEL_VIA };
+
+/* VIA HDMI Implementation */
+#define VIAHDMI_CVT_NID 0x02 /* audio converter1 */
+#define VIAHDMI_PIN_NID 0x03 /* HDMI output pin1 */
+
+static int simplehdmi_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
+{
+ switch (id->driver_data) {
+ case MODEL_VIA:
+ return snd_hda_hdmi_simple_probe(codec, VIAHDMI_CVT_NID,
+ VIAHDMI_PIN_NID);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct hda_codec_ops simplehdmi_codec_ops = {
+ .probe = simplehdmi_probe,
+ .remove = snd_hda_hdmi_simple_remove,
+ .build_controls = snd_hda_hdmi_simple_build_controls,
+ .build_pcms = snd_hda_hdmi_simple_build_pcms,
+ .init = snd_hda_hdmi_simple_init,
+ .unsol_event = snd_hda_hdmi_simple_unsol_event,
+};
+
+static const struct hda_device_id snd_hda_id_simplehdmi[] = {
+ HDA_CODEC_ID_MODEL(0x11069f80, "VX900 HDMI/DP", MODEL_VIA),
+ HDA_CODEC_ID_MODEL(0x11069f81, "VX900 HDMI/DP", MODEL_VIA),
+ {} /* terminator */
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simple HDMI HD-audio codec support");
+
+static struct hda_codec_driver simplehdmi_driver = {
+ .id = snd_hda_id_simplehdmi,
+ .ops = &simplehdmi_codec_ops,
+};
+
+module_hda_codec_driver(simplehdmi_driver);
diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c
new file mode 100644
index 000000000000..5f6fe31aa202
--- /dev/null
+++ b/sound/hda/codecs/hdmi/tegrahdmi.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Nvidia Tegra HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+enum {
+ MODEL_TEGRA,
+ MODEL_TEGRA234,
+};
+
+/*
+ * The HDA codec on NVIDIA Tegra contains two scratch registers that are
+ * accessed using vendor-defined verbs. These registers can be used for
+ * interoperability between the HDA and HDMI drivers.
+ */
+
+/* Audio Function Group node */
+#define NVIDIA_AFG_NID 0x01
+
+/*
+ * The SCRATCH0 register is used to notify the HDMI codec of changes in audio
+ * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
+ * be raised in the HDMI codec. The remainder of the bits is arbitrary. This
+ * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
+ * additional bit (at position 30) to signal the validity of the format.
+ *
+ * | 31 | 30 | 29 16 | 15 0 |
+ * +---------+-------+--------+--------+
+ * | TRIGGER | VALID | UNUSED | FORMAT |
+ * +-----------------------------------|
+ *
+ * Note that for the trigger bit to take effect it needs to change value
+ * (i.e. it needs to be toggled). The trigger bit is not applicable from
+ * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
+ * trigger to hdmi.
+ */
+#define NVIDIA_SET_HOST_INTR 0xf80
+#define NVIDIA_GET_SCRATCH0 0xfa6
+#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7
+#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8
+#define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9
+#define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa
+#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
+#define NVIDIA_SCRATCH_VALID (1 << 6)
+
+#define NVIDIA_GET_SCRATCH1 0xfab
+#define NVIDIA_SET_SCRATCH1_BYTE0 0xfac
+#define NVIDIA_SET_SCRATCH1_BYTE1 0xfad
+#define NVIDIA_SET_SCRATCH1_BYTE2 0xfae
+#define NVIDIA_SET_SCRATCH1_BYTE3 0xfaf
+
+/*
+ * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
+ * the format is invalidated so that the HDMI codec can be disabled.
+ */
+static void tegra_hdmi_set_format(struct hda_codec *codec,
+ hda_nid_t cvt_nid,
+ unsigned int format)
+{
+ unsigned int value;
+ unsigned int nid = NVIDIA_AFG_NID;
+ struct hdmi_spec *spec = codec->spec;
+
+ /*
+ * Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
+ * This resulted in moving scratch registers from audio function
+ * group to converter widget context. So CVT NID should be used for
+ * scratch register read/write for DP MST supported Tegra HDA codec.
+ */
+ if (codec->dp_mst)
+ nid = cvt_nid;
+
+ /* bits [31:30] contain the trigger and valid bits */
+ value = snd_hda_codec_read(codec, nid, 0,
+ NVIDIA_GET_SCRATCH0, 0);
+ value = (value >> 24) & 0xff;
+
+ /* bits [15:0] are used to store the HDA format */
+ snd_hda_codec_write(codec, nid, 0,
+ NVIDIA_SET_SCRATCH0_BYTE0,
+ (format >> 0) & 0xff);
+ snd_hda_codec_write(codec, nid, 0,
+ NVIDIA_SET_SCRATCH0_BYTE1,
+ (format >> 8) & 0xff);
+
+ /* bits [16:24] are unused */
+ snd_hda_codec_write(codec, nid, 0,
+ NVIDIA_SET_SCRATCH0_BYTE2, 0);
+
+ /*
+ * Bit 30 signals that the data is valid and hence that HDMI audio can
+ * be enabled.
+ */
+ if (format == 0)
+ value &= ~NVIDIA_SCRATCH_VALID;
+ else
+ value |= NVIDIA_SCRATCH_VALID;
+
+ if (spec->hdmi_intr_trig_ctrl) {
+ /*
+ * For Tegra HDA Codec design from TEGRA234 onwards, the
+ * Interrupt to hdmi driver is triggered by writing
+ * non-zero values to verb 0xF80 instead of 31st bit of
+ * scratch register.
+ */
+ snd_hda_codec_write(codec, nid, 0,
+ NVIDIA_SET_SCRATCH0_BYTE3, value);
+ snd_hda_codec_write(codec, nid, 0,
+ NVIDIA_SET_HOST_INTR, 0x1);
+ } else {
+ /*
+ * Whenever the 31st trigger bit is toggled, an interrupt is raised
+ * in the HDMI codec. The HDMI driver will use that as trigger
+ * to update its configuration.
+ */
+ value ^= NVIDIA_SCRATCH_TRIGGER;
+
+ snd_hda_codec_write(codec, nid, 0,
+ NVIDIA_SET_SCRATCH0_BYTE3, value);
+ }
+}
+
+static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ int err;
+
+ err = snd_hda_hdmi_generic_pcm_prepare(hinfo, codec, stream_tag,
+ format, substream);
+ if (err < 0)
+ return err;
+
+ /* notify the HDMI codec of the format change */
+ tegra_hdmi_set_format(codec, hinfo->nid, format);
+
+ return 0;
+}
+
+static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ /* invalidate the format in the HDMI codec */
+ tegra_hdmi_set_format(codec, hinfo->nid, 0);
+
+ return snd_hda_hdmi_generic_pcm_cleanup(hinfo, codec, substream);
+}
+
+static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
+{
+ struct hdmi_spec *spec = codec->spec;
+ unsigned int i;
+
+ for (i = 0; i < spec->num_pins; i++) {
+ struct hda_pcm *pcm = get_pcm_rec(spec, i);
+
+ if (pcm->pcm_type == type)
+ return pcm;
+ }
+
+ return NULL;
+}
+
+static int tegra_hdmi_build_pcms(struct hda_codec *codec)
+{
+ struct hda_pcm_stream *stream;
+ struct hda_pcm *pcm;
+ int err;
+
+ err = snd_hda_hdmi_generic_build_pcms(codec);
+ if (err < 0)
+ return err;
+
+ pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
+ if (!pcm)
+ return -ENODEV;
+
+ /*
+ * Override ->prepare() and ->cleanup() operations to notify the HDMI
+ * codec about format changes.
+ */
+ stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
+ stream->ops.prepare = tegra_hdmi_pcm_prepare;
+ stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
+
+ return 0;
+}
+
+/*
+ * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
+ * - 0x10de0015
+ * - 0x10de0040
+ */
+static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
+ struct hdac_cea_channel_speaker_allocation *cap, int channels)
+{
+ if (cap->ca_index == 0x00 && channels == 2)
+ return SNDRV_CTL_TLVT_CHMAP_FIXED;
+
+ /* If the speaker allocation matches the channel count, it is OK. */
+ if (cap->channels != channels)
+ return -1;
+
+ /* all channels are remappable freely */
+ return SNDRV_CTL_TLVT_CHMAP_VAR;
+}
+
+static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
+ int ca, int chs, unsigned char *map)
+{
+ if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tegra_hdmi_init(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int i, err;
+
+ err = snd_hda_hdmi_parse_codec(codec);
+ if (err < 0) {
+ snd_hda_hdmi_generic_spec_free(codec);
+ return err;
+ }
+
+ for (i = 0; i < spec->num_cvts; i++)
+ snd_hda_codec_write(codec, spec->cvt_nids[i], 0,
+ AC_VERB_SET_DIGI_CONVERT_1,
+ AC_DIG1_ENABLE);
+
+ snd_hda_hdmi_generic_init_per_pins(codec);
+
+ codec->depop_delay = 10;
+ spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+ nvhdmi_chmap_cea_alloc_validate_get_type;
+ spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+
+ spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+ nvhdmi_chmap_cea_alloc_validate_get_type;
+ spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+ spec->nv_dp_workaround = true;
+
+ return 0;
+}
+
+static int tegrahdmi_probe(struct hda_codec *codec,
+ const struct hda_device_id *id)
+{
+ struct hdmi_spec *spec;
+ int err;
+
+ err = snd_hda_hdmi_generic_alloc(codec);
+ if (err < 0)
+ return err;
+
+ if (id->driver_data == MODEL_TEGRA234) {
+ codec->dp_mst = true;
+ spec = codec->spec;
+ spec->dyn_pin_out = true;
+ spec->hdmi_intr_trig_ctrl = true;
+ }
+
+ return tegra_hdmi_init(codec);
+}
+
+static const struct hda_codec_ops tegrahdmi_codec_ops = {
+ .probe = tegrahdmi_probe,
+ .remove = snd_hda_hdmi_generic_remove,
+ .init = snd_hda_hdmi_generic_init,
+ .build_pcms = tegra_hdmi_build_pcms,
+ .build_controls = snd_hda_hdmi_generic_build_controls,
+ .unsol_event = snd_hda_hdmi_generic_unsol_event,
+ .suspend = snd_hda_hdmi_generic_suspend,
+ .resume = snd_hda_hdmi_generic_resume,
+};
+
+static const struct hda_device_id snd_hda_id_tegrahdmi[] = {
+ HDA_CODEC_ID_MODEL(0x10de0020, "Tegra30 HDMI", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de0022, "Tegra114 HDMI", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de0028, "Tegra124 HDMI", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de0029, "Tegra210 HDMI/DP", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de002d, "Tegra186 HDMI/DP0", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de002e, "Tegra186 HDMI/DP1", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de002f, "Tegra194 HDMI/DP2", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de0030, "Tegra194 HDMI/DP3", MODEL_TEGRA),
+ HDA_CODEC_ID_MODEL(0x10de0031, "Tegra234 HDMI/DP", MODEL_TEGRA234),
+ HDA_CODEC_ID_MODEL(0x10de0033, "SoC 33 HDMI/DP", MODEL_TEGRA234),
+ HDA_CODEC_ID_MODEL(0x10de0034, "Tegra264 HDMI/DP", MODEL_TEGRA234),
+ HDA_CODEC_ID_MODEL(0x10de0035, "SoC 35 HDMI/DP", MODEL_TEGRA234),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_tegrahdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia Tegra HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver tegrahdmi_driver = {
+ .id = snd_hda_id_tegrahdmi,
+ .ops = &tegrahdmi_codec_ops,
+};
+
+module_hda_codec_driver(tegrahdmi_driver);
diff --git a/sound/pci/hda/hp_x360_helper.c b/sound/hda/codecs/helpers/hp_x360.c
index 969542c57358..969542c57358 100644
--- a/sound/pci/hda/hp_x360_helper.c
+++ b/sound/hda/codecs/helpers/hp_x360.c
diff --git a/sound/hda/codecs/helpers/ideapad_hotkey_led.c b/sound/hda/codecs/helpers/ideapad_hotkey_led.c
new file mode 100644
index 000000000000..c10d97964d49
--- /dev/null
+++ b/sound/hda/codecs/helpers/ideapad_hotkey_led.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/ideapad_s740_helper.c b/sound/hda/codecs/helpers/ideapad_s740.c
index 564b9086e52d..564b9086e52d 100644
--- a/sound/pci/hda/ideapad_s740_helper.c
+++ b/sound/hda/codecs/helpers/ideapad_s740.c
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/hda/codecs/helpers/thinkpad.c
index de4d8deed102..de4d8deed102 100644
--- a/sound/pci/hda/thinkpad_helper.c
+++ b/sound/hda/codecs/helpers/thinkpad.c
diff --git a/sound/hda/codecs/realtek/Kconfig b/sound/hda/codecs/realtek/Kconfig
new file mode 100644
index 000000000000..cdc6d9509a01
--- /dev/null
+++ b/sound/hda/codecs/realtek/Kconfig
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig SND_HDA_CODEC_REALTEK
+ tristate "Realtek HD-audio codec support"
+ help
+ Say Y or M here to include Realtek HD-audio codec support.
+
+ This will enable all Realtek HD-audio codec drivers as default,
+ but you can enable/disable each codec driver individually, too
+ (only when CONFIG_EXPERT is set).
+
+if SND_HDA_CODEC_REALTEK
+
+config SND_HDA_CODEC_REALTEK_LIB
+ tristate
+ select SND_HDA_GENERIC
+ select SND_HDA_GENERIC_LEDS
+ select SND_HDA_SCODEC_COMPONENT
+
+config SND_HDA_CODEC_ALC260
+ tristate "Build Realtek ALC260 HD-audio codec support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC260 HD-audio codec support
+
+config SND_HDA_CODEC_ALC262
+ tristate "Build Realtek ALC262 HD-audio codec support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC262 HD-audio codec support
+
+config SND_HDA_CODEC_ALC268
+ tristate "Build Realtek ALC268 HD-audio codec support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC268 and compatible HD-audio
+ codec support
+
+config SND_HDA_CODEC_ALC269
+ tristate "Build Realtek ALC269 HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC269 and compatible HD-audio
+ codec support
+
+config SND_HDA_CODEC_ALC662
+ tristate "Build Realtek ALC662 HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC662 and compatible HD-audio
+ codec support
+
+config SND_HDA_CODEC_ALC680
+ tristate "Build Realtek ALC680 HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC680 HD-audio codec support
+
+config SND_HDA_CODEC_ALC861
+ tristate "Build Realtek ALC861 HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC861 HD-audio codec support
+
+config SND_HDA_CODEC_ALC861VD
+ tristate "Build Realtek ALC861-VD HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC861-VD HD-audio codec support
+
+config SND_HDA_CODEC_ALC880
+ tristate "Build Realtek ALC880 HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC880 HD-audio codec support
+
+config SND_HDA_CODEC_ALC882
+ tristate "Build Realtek ALC882 HD-audio codecs support" if EXPERT
+ depends on INPUT
+ select SND_HDA_CODEC_REALTEK_LIB
+ default y
+ help
+ Say Y or M here to include Realtek ALC882 and compatible HD-audio
+ codec support
+
+endif
diff --git a/sound/hda/codecs/realtek/Makefile b/sound/hda/codecs/realtek/Makefile
new file mode 100644
index 000000000000..c6ee4e526a40
--- /dev/null
+++ b/sound/hda/codecs/realtek/Makefile
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-realtek-lib-y := realtek.o
+snd-hda-codec-alc260-y := alc260.o
+snd-hda-codec-alc262-y := alc262.o
+snd-hda-codec-alc268-y := alc268.o
+snd-hda-codec-alc269-y := alc269.o
+snd-hda-codec-alc662-y := alc662.o
+snd-hda-codec-alc680-y := alc680.o
+snd-hda-codec-alc861-y := alc861.o
+snd-hda-codec-alc861vd-y := alc861vd.o
+snd-hda-codec-alc880-y := alc880.o
+snd-hda-codec-alc882-y := alc882.o
+
+obj-$(CONFIG_SND_HDA_CODEC_REALTEK_LIB) += snd-hda-codec-realtek-lib.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC260) += snd-hda-codec-alc260.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC262) += snd-hda-codec-alc262.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC268) += snd-hda-codec-alc268.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC269) += snd-hda-codec-alc269.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC662) += snd-hda-codec-alc662.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC680) += snd-hda-codec-alc680.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC861) += snd-hda-codec-alc861.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC861VD) += snd-hda-codec-alc861vd.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC880) += snd-hda-codec-alc880.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC882) += snd-hda-codec-alc882.o
diff --git a/sound/hda/codecs/realtek/alc260.c b/sound/hda/codecs/realtek/alc260.c
new file mode 100644
index 000000000000..8bd47079dccb
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc260.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC260 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc260_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
+ static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
+ return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
+}
+
+/*
+ * Pin config fixes
+ */
+enum {
+ ALC260_FIXUP_HP_DC5750,
+ ALC260_FIXUP_HP_PIN_0F,
+ ALC260_FIXUP_COEF,
+ ALC260_FIXUP_GPIO1,
+ ALC260_FIXUP_GPIO1_TOGGLE,
+ ALC260_FIXUP_REPLACER,
+ ALC260_FIXUP_HP_B1900,
+ ALC260_FIXUP_KN1,
+ ALC260_FIXUP_FSC_S7020,
+ ALC260_FIXUP_FSC_S7020_JWSE,
+ ALC260_FIXUP_VAIO_PINS,
+};
+
+static void alc260_gpio1_automute(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
+}
+
+static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action == HDA_FIXUP_ACT_PROBE) {
+ /* although the machine has only one output pin, we need to
+ * toggle GPIO1 according to the jack state
+ */
+ spec->gen.automute_hook = alc260_gpio1_automute;
+ spec->gen.detect_hp = 1;
+ spec->gen.automute_speaker = 1;
+ spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
+ snd_hda_jack_detect_enable_callback(codec, 0x0f,
+ snd_hda_gen_hp_automute);
+ alc_setup_gpio(codec, 0x01);
+ }
+}
+
+static void alc260_fixup_kn1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x0f, 0x02214000 }, /* HP/speaker */
+ { 0x12, 0x90a60160 }, /* int mic */
+ { 0x13, 0x02a19000 }, /* ext mic */
+ { 0x18, 0x01446000 }, /* SPDIF out */
+ /* disable bogus I/O pins */
+ { 0x10, 0x411111f0 },
+ { 0x11, 0x411111f0 },
+ { 0x14, 0x411111f0 },
+ { 0x15, 0x411111f0 },
+ { 0x16, 0x411111f0 },
+ { 0x17, 0x411111f0 },
+ { 0x19, 0x411111f0 },
+ { }
+ };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ spec->init_amp = ALC_INIT_NONE;
+ break;
+ }
+}
+
+static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->init_amp = ALC_INIT_NONE;
+}
+
+static void alc260_fixup_fsc_s7020_jwse(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->gen.add_jack_modes = 1;
+ spec->gen.hp_mic = 1;
+ }
+}
+
+static const struct hda_fixup alc260_fixups[] = {
+ [ALC260_FIXUP_HP_DC5750] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x11, 0x90130110 }, /* speaker */
+ { }
+ }
+ },
+ [ALC260_FIXUP_HP_PIN_0F] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x0f, 0x01214000 }, /* HP */
+ { }
+ }
+ },
+ [ALC260_FIXUP_COEF] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 },
+ { }
+ },
+ },
+ [ALC260_FIXUP_GPIO1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
+ },
+ [ALC260_FIXUP_GPIO1_TOGGLE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc260_fixup_gpio1_toggle,
+ .chained = true,
+ .chain_id = ALC260_FIXUP_HP_PIN_0F,
+ },
+ [ALC260_FIXUP_REPLACER] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
+ },
+ [ALC260_FIXUP_HP_B1900] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc260_fixup_gpio1_toggle,
+ .chained = true,
+ .chain_id = ALC260_FIXUP_COEF,
+ },
+ [ALC260_FIXUP_KN1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc260_fixup_kn1,
+ },
+ [ALC260_FIXUP_FSC_S7020] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc260_fixup_fsc_s7020,
+ },
+ [ALC260_FIXUP_FSC_S7020_JWSE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc260_fixup_fsc_s7020_jwse,
+ .chained = true,
+ .chain_id = ALC260_FIXUP_FSC_S7020,
+ },
+ [ALC260_FIXUP_VAIO_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* Pin configs are missing completely on some VAIOs */
+ { 0x0f, 0x01211020 },
+ { 0x10, 0x0001003f },
+ { 0x11, 0x411111f0 },
+ { 0x12, 0x01a15930 },
+ { 0x13, 0x411111f0 },
+ { 0x14, 0x411111f0 },
+ { 0x15, 0x411111f0 },
+ { 0x16, 0x411111f0 },
+ { 0x17, 0x411111f0 },
+ { 0x18, 0x411111f0 },
+ { 0x19, 0x411111f0 },
+ { }
+ }
+ },
+};
+
+static const struct hda_quirk alc260_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
+ SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
+ SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
+ SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
+ SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
+ SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
+ SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
+ SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
+ SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
+ SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
+ SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
+ SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
+ {}
+};
+
+static const struct hda_model_fixup alc260_fixup_models[] = {
+ {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
+ {.id = ALC260_FIXUP_COEF, .name = "coef"},
+ {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
+ {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
+ {}
+};
+
+/*
+ */
+static int alc260_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x07);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+ /* as quite a few machines require HP amp for speaker outputs,
+ * it's easier to enable it unconditionally; even if it's unneeded,
+ * it's almost harmless.
+ */
+ spec->gen.prefer_hp_amp = 1;
+ spec->gen.beep_nid = 0x01;
+
+ spec->shutup = alc_eapd_shutup;
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
+ alc260_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ /* automatic parse from the BIOS config */
+ err = alc260_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc260_codec_ops = {
+ .probe = alc260_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc260[] = {
+ HDA_CODEC_ID(0x10ec0260, "ALC260"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC260 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc260_driver = {
+ .id = snd_hda_id_alc260,
+ .ops = &alc260_codec_ops,
+};
+
+module_hda_codec_driver(alc260_driver);
diff --git a/sound/hda/codecs/realtek/alc262.c b/sound/hda/codecs/realtek/alc262.c
new file mode 100644
index 000000000000..3ec06cf5d2a6
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc262.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC262 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc262_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
+}
+
+/*
+ * Pin config fixes
+ */
+enum {
+ ALC262_FIXUP_FSC_H270,
+ ALC262_FIXUP_FSC_S7110,
+ ALC262_FIXUP_HP_Z200,
+ ALC262_FIXUP_TYAN,
+ ALC262_FIXUP_LENOVO_3000,
+ ALC262_FIXUP_BENQ,
+ ALC262_FIXUP_BENQ_T31,
+ ALC262_FIXUP_INV_DMIC,
+ ALC262_FIXUP_INTEL_BAYLEYBAY,
+};
+
+static const struct hda_fixup alc262_fixups[] = {
+ [ALC262_FIXUP_FSC_H270] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0221142f }, /* front HP */
+ { 0x1b, 0x0121141f }, /* rear HP */
+ { }
+ }
+ },
+ [ALC262_FIXUP_FSC_S7110] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x90170110 }, /* speaker */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC262_FIXUP_BENQ,
+ },
+ [ALC262_FIXUP_HP_Z200] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x99130120 }, /* internal speaker */
+ { }
+ }
+ },
+ [ALC262_FIXUP_TYAN] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x1993e1f0 }, /* int AUX */
+ { }
+ }
+ },
+ [ALC262_FIXUP_LENOVO_3000] = {
+ .type = HDA_FIXUP_PINCTLS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, PIN_VREF50 },
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC262_FIXUP_BENQ,
+ },
+ [ALC262_FIXUP_BENQ] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+ {}
+ }
+ },
+ [ALC262_FIXUP_BENQ_T31] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+ {}
+ }
+ },
+ [ALC262_FIXUP_INV_DMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_inv_dmic,
+ },
+ [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_no_depop_delay,
+ },
+};
+
+static const struct hda_quirk alc262_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
+ SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
+ SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
+ SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
+ SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
+ SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
+ SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
+ SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
+ SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
+ SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
+ {}
+};
+
+static const struct hda_model_fixup alc262_fixup_models[] = {
+ {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
+ {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
+ {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
+ {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
+ {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
+ {.id = ALC262_FIXUP_BENQ, .name = "benq"},
+ {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
+ {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
+ {}
+};
+
+/*
+ */
+static int alc262_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+ spec->gen.shared_mic_vref_pin = 0x18;
+
+ spec->shutup = alc_eapd_shutup;
+
+#if 0
+ /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
+ * under-run
+ */
+ alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
+#endif
+ alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
+ alc262_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ alc_auto_parse_customize_define(codec);
+
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x01;
+
+ /* automatic parse from the BIOS config */
+ err = alc262_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc262_codec_ops = {
+ .probe = alc262_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc262[] = {
+ HDA_CODEC_ID(0x10ec0262, "ALC262"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC262 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc262_driver = {
+ .id = snd_hda_id_alc262,
+ .ops = &alc262_codec_ops,
+};
+
+module_hda_codec_driver(alc262_driver);
diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c
new file mode 100644
index 000000000000..4b565fb7bd1c
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc268.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/* bind Beep switches of both NID 0x0f and 0x10 */
+static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned long pval;
+ int err;
+
+ guard(mutex)(&codec->control_mutex);
+ pval = kcontrol->private_value;
+ kcontrol->private_value = (pval & ~0xff) | 0x0f;
+ err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+ if (err >= 0) {
+ kcontrol->private_value = (pval & ~0xff) | 0x10;
+ err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+ }
+ kcontrol->private_value = pval;
+ return err;
+}
+
+static const struct snd_kcontrol_new alc268_beep_mixer[] = {
+ HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Beep Playback Switch",
+ .subdevice = HDA_SUBDEV_AMP_FLAG,
+ .info = snd_hda_mixer_amp_switch_info,
+ .get = snd_hda_mixer_amp_switch_get,
+ .put = alc268_beep_switch_put,
+ .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
+ },
+};
+
+/* set PCBEEP vol = 0, mute connections */
+static const struct hda_verb alc268_beep_init_verbs[] = {
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ { }
+};
+
+enum {
+ ALC268_FIXUP_INV_DMIC,
+ ALC268_FIXUP_HP_EAPD,
+ ALC268_FIXUP_SPDIF,
+};
+
+static const struct hda_fixup alc268_fixups[] = {
+ [ALC268_FIXUP_INV_DMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_inv_dmic,
+ },
+ [ALC268_FIXUP_HP_EAPD] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
+ {}
+ }
+ },
+ [ALC268_FIXUP_SPDIF] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x014b1180 }, /* enable SPDIF out */
+ {}
+ }
+ },
+};
+
+static const struct hda_model_fixup alc268_fixup_models[] = {
+ {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
+ {.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
+ {}
+};
+
+static const struct hda_quirk alc268_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
+ SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
+ /* below is codec SSID since multiple Toshiba laptops have the
+ * same PCI SSID 1179:ff00
+ */
+ SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
+ {}
+};
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, NULL, alc268_ssids);
+}
+
+/*
+ */
+static int alc268_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int i, err;
+
+ /* ALC268 has no aa-loopback mixer */
+ err = alc_alloc_spec(codec, 0);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x01;
+
+ spec->shutup = alc_eapd_shutup;
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ /* automatic parse from the BIOS config */
+ err = alc268_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (err > 0 && !spec->gen.no_analog &&
+ spec->gen.autocfg.speaker_pins[0] != 0x1d) {
+ for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &alc268_beep_mixer[i])) {
+ err = -ENOMEM;
+ goto error;
+ }
+ }
+ snd_hda_add_verbs(codec, alc268_beep_init_verbs);
+ if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+ /* override the amp caps for beep generator */
+ snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+ (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (0 << AC_AMPCAP_MUTE_SHIFT));
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc268_codec_ops = {
+ .probe = alc268_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc268[] = {
+ HDA_CODEC_ID(0x10ec0267, "ALC267"),
+ HDA_CODEC_ID(0x10ec0268, "ALC268"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc268);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC267/268 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc268_driver = {
+ .id = snd_hda_id_alc268,
+ .ops = &alc268_codec_ops,
+};
+
+module_hda_codec_driver(alc268_driver);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/hda/codecs/realtek/alc269.c
index a7e4765eff80..d90a6c01f63b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -1,3127 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for Realtek ALC codecs
- *
- * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
- * PeiSen Hou <pshou@realtek.com.tw>
- * Takashi Iwai <tiwai@suse.de>
- * Jonathan Woithe <jwoithe@just42.net>
- */
+//
+// Realtek ALC269 and compatible codecs
+//
#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/dmi.h>
#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/leds.h>
-#include <linux/ctype.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-#include "hda_component.h"
+#include "realtek.h"
/* keep halting ALC5505 DSP, for power saving */
#define HALT_REALTEK_ALC5505
-/* extra amp-initialization sequence types */
-enum {
- ALC_INIT_UNDEFINED,
- ALC_INIT_NONE,
- ALC_INIT_DEFAULT,
-};
-
-enum {
- ALC_HEADSET_MODE_UNKNOWN,
- ALC_HEADSET_MODE_UNPLUGGED,
- ALC_HEADSET_MODE_HEADSET,
- ALC_HEADSET_MODE_MIC,
- ALC_HEADSET_MODE_HEADPHONE,
-};
-
-enum {
- ALC_HEADSET_TYPE_UNKNOWN,
- ALC_HEADSET_TYPE_CTIA,
- ALC_HEADSET_TYPE_OMTP,
-};
-
-enum {
- ALC_KEY_MICMUTE_INDEX,
-};
-
-struct alc_customize_define {
- unsigned int sku_cfg;
- unsigned char port_connectivity;
- unsigned char check_sum;
- unsigned char customization;
- unsigned char external_amp;
- unsigned int enable_pcbeep:1;
- unsigned int platform_type:1;
- unsigned int swap:1;
- unsigned int override:1;
- unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
-};
-
-struct alc_coef_led {
- unsigned int idx;
- unsigned int mask;
- unsigned int on;
- unsigned int off;
-};
-
-struct alc_spec {
- struct hda_gen_spec gen; /* must be at head */
-
- /* codec parameterization */
- struct alc_customize_define cdefine;
- unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
-
- /* GPIO bits */
- unsigned int gpio_mask;
- unsigned int gpio_dir;
- unsigned int gpio_data;
- bool gpio_write_delay; /* add a delay before writing gpio_data */
-
- /* mute LED for HP laptops, see vref_mute_led_set() */
- int mute_led_polarity;
- int micmute_led_polarity;
- hda_nid_t mute_led_nid;
- hda_nid_t cap_mute_led_nid;
-
- unsigned int gpio_mute_led_mask;
- unsigned int gpio_mic_led_mask;
- struct alc_coef_led mute_led_coef;
- struct alc_coef_led mic_led_coef;
- struct mutex coef_mutex;
-
- hda_nid_t headset_mic_pin;
- hda_nid_t headphone_mic_pin;
- int current_headset_mode;
- int current_headset_type;
-
- /* hooks */
- void (*init_hook)(struct hda_codec *codec);
-#ifdef CONFIG_PM
- void (*power_hook)(struct hda_codec *codec);
-#endif
- void (*shutup)(struct hda_codec *codec);
-
- int init_amp;
- int codec_variant; /* flag for other variants */
- unsigned int has_alc5505_dsp:1;
- unsigned int no_depop_delay:1;
- unsigned int done_hp_init:1;
- unsigned int no_shutup_pins:1;
- unsigned int ultra_low_power:1;
- unsigned int has_hs_key:1;
- unsigned int no_internal_mic_pin:1;
-
- /* for PLL fix */
- hda_nid_t pll_nid;
- unsigned int pll_coef_idx, pll_coef_bit;
- unsigned int coef0;
- struct input_dev *kb_dev;
- u8 alc_mute_keycode_map[1];
-
- /* component binding */
- struct component_match *match;
- struct hda_component comps[HDA_MAX_COMPONENTS];
-};
-
-/*
- * COEF access helper functions
- */
-
-static void coef_mutex_lock(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- snd_hda_power_up_pm(codec);
- mutex_lock(&spec->coef_mutex);
-}
-
-static void coef_mutex_unlock(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- mutex_unlock(&spec->coef_mutex);
- snd_hda_power_down_pm(codec);
-}
-
-static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx)
-{
- unsigned int val;
-
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
- val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
- return val;
-}
-
-static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx)
-{
- unsigned int val;
-
- coef_mutex_lock(codec);
- val = __alc_read_coefex_idx(codec, nid, coef_idx);
- coef_mutex_unlock(codec);
- return val;
-}
-
-#define alc_read_coef_idx(codec, coef_idx) \
- alc_read_coefex_idx(codec, 0x20, coef_idx)
-
-static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx, unsigned int coef_val)
-{
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
-}
-
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx, unsigned int coef_val)
-{
- coef_mutex_lock(codec);
- __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
- coef_mutex_unlock(codec);
-}
-
-#define alc_write_coef_idx(codec, coef_idx, coef_val) \
- alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
-
-static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx, unsigned int mask,
- unsigned int bits_set)
-{
- unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
-
- if (val != -1)
- __alc_write_coefex_idx(codec, nid, coef_idx,
- (val & ~mask) | bits_set);
-}
-
-static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx, unsigned int mask,
- unsigned int bits_set)
-{
- coef_mutex_lock(codec);
- __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
- coef_mutex_unlock(codec);
-}
-
-#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \
- alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
-
-/* a special bypass for COEF 0; read the cached value at the second time */
-static unsigned int alc_get_coef0(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (!spec->coef0)
- spec->coef0 = alc_read_coef_idx(codec, 0);
- return spec->coef0;
-}
-
-/* coef writes/updates batch */
-struct coef_fw {
- unsigned char nid;
- unsigned char idx;
- unsigned short mask;
- unsigned short val;
-};
-
-#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
- { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
-#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
-#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
-#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
-
-static void alc_process_coef_fw(struct hda_codec *codec,
- const struct coef_fw *fw)
-{
- coef_mutex_lock(codec);
- for (; fw->nid; fw++) {
- if (fw->mask == (unsigned short)-1)
- __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
- else
- __alc_update_coefex_idx(codec, fw->nid, fw->idx,
- fw->mask, fw->val);
- }
- coef_mutex_unlock(codec);
-}
-
-/*
- * GPIO setup tables, used in initialization
- */
-
-/* Enable GPIO mask and set output */
-static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->gpio_mask |= mask;
- spec->gpio_dir |= mask;
- spec->gpio_data |= mask;
-}
-
-static void alc_write_gpio_data(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_data);
-}
-
-static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
- bool on)
-{
- struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_data;
-
- if (on)
- spec->gpio_data |= mask;
- else
- spec->gpio_data &= ~mask;
- if (oldval != spec->gpio_data)
- alc_write_gpio_data(codec);
-}
-
-static void alc_write_gpio(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (!spec->gpio_mask)
- return;
-
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
- if (spec->gpio_write_delay)
- msleep(1);
- alc_write_gpio_data(codec);
-}
-
-static void alc_fixup_gpio(struct hda_codec *codec, int action,
- unsigned int mask)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- alc_setup_gpio(codec, mask);
-}
-
-static void alc_fixup_gpio1(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- alc_fixup_gpio(codec, action, 0x01);
-}
-
-static void alc_fixup_gpio2(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- alc_fixup_gpio(codec, action, 0x02);
-}
-
-static void alc_fixup_gpio3(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- alc_fixup_gpio(codec, action, 0x03);
-}
-
-static void alc_fixup_gpio4(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- alc_fixup_gpio(codec, action, 0x04);
-}
-
-static void alc_fixup_micmute_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- snd_hda_gen_add_micmute_led_cdev(codec, NULL);
-}
-
-/*
- * Fix hardware PLL issue
- * On some codecs, the analog PLL gating control must be off while
- * the default value is 1.
- */
-static void alc_fix_pll(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (spec->pll_nid)
- alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
- 1 << spec->pll_coef_bit, 0);
-}
-
-static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
- unsigned int coef_idx, unsigned int coef_bit)
-{
- struct alc_spec *spec = codec->spec;
- spec->pll_nid = nid;
- spec->pll_coef_idx = coef_idx;
- spec->pll_coef_bit = coef_bit;
- alc_fix_pll(codec);
-}
-
-/* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- unsigned int val;
- struct snd_kcontrol *kctl;
- struct snd_ctl_elem_value *uctl;
-
- kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
- if (!kctl)
- return;
- uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
- if (!uctl)
- return;
- val = snd_hda_codec_read(codec, jack->nid, 0,
- AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
- val &= HDA_AMP_VOLMASK;
- uctl->value.integer.value[0] = val;
- uctl->value.integer.value[1] = val;
- kctl->put(kctl, uctl);
- kfree(uctl);
-}
-
-static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
-{
- /* For some reason, the res given from ALC880 is broken.
- Here we adjust it properly. */
- snd_hda_jack_unsol_event(codec, res >> 2);
-}
-
-/* Change EAPD to verb control */
-static void alc_fill_eapd_coef(struct hda_codec *codec)
-{
- int coef;
-
- coef = alc_get_coef0(codec);
-
- switch (codec->core.vendor_id) {
- case 0x10ec0262:
- alc_update_coef_idx(codec, 0x7, 0, 1<<5);
- break;
- case 0x10ec0267:
- case 0x10ec0268:
- alc_update_coef_idx(codec, 0x7, 0, 1<<13);
- break;
- case 0x10ec0269:
- if ((coef & 0x00f0) == 0x0010)
- alc_update_coef_idx(codec, 0xd, 0, 1<<14);
- if ((coef & 0x00f0) == 0x0020)
- alc_update_coef_idx(codec, 0x4, 1<<15, 0);
- if ((coef & 0x00f0) == 0x0030)
- alc_update_coef_idx(codec, 0x10, 1<<9, 0);
- break;
- case 0x10ec0280:
- case 0x10ec0284:
- case 0x10ec0290:
- case 0x10ec0292:
- alc_update_coef_idx(codec, 0x4, 1<<15, 0);
- break;
- case 0x10ec0225:
- case 0x10ec0295:
- case 0x10ec0299:
- alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
- fallthrough;
- case 0x10ec0215:
- case 0x10ec0230:
- case 0x10ec0233:
- case 0x10ec0235:
- case 0x10ec0236:
- case 0x10ec0245:
- case 0x10ec0255:
- case 0x10ec0256:
- case 0x19e58326:
- case 0x10ec0257:
- case 0x10ec0282:
- case 0x10ec0283:
- case 0x10ec0286:
- case 0x10ec0288:
- case 0x10ec0285:
- case 0x10ec0298:
- case 0x10ec0289:
- case 0x10ec0300:
- alc_update_coef_idx(codec, 0x10, 1<<9, 0);
- break;
- case 0x10ec0275:
- alc_update_coef_idx(codec, 0xe, 0, 1<<0);
- break;
- case 0x10ec0287:
- alc_update_coef_idx(codec, 0x10, 1<<9, 0);
- alc_write_coef_idx(codec, 0x8, 0x4ab7);
- break;
- case 0x10ec0293:
- alc_update_coef_idx(codec, 0xa, 1<<13, 0);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- case 0x10ec0700:
- case 0x10ec0701:
- case 0x10ec0703:
- case 0x10ec0711:
- alc_update_coef_idx(codec, 0x10, 1<<15, 0);
- break;
- case 0x10ec0662:
- if ((coef & 0x00f0) == 0x0030)
- alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
- break;
- case 0x10ec0272:
- case 0x10ec0273:
- case 0x10ec0663:
- case 0x10ec0665:
- case 0x10ec0670:
- case 0x10ec0671:
- case 0x10ec0672:
- alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
- break;
- case 0x10ec0222:
- case 0x10ec0623:
- alc_update_coef_idx(codec, 0x19, 1<<13, 0);
- break;
- case 0x10ec0668:
- alc_update_coef_idx(codec, 0x7, 3<<13, 0);
- break;
- case 0x10ec0867:
- alc_update_coef_idx(codec, 0x4, 1<<10, 0);
- break;
- case 0x10ec0888:
- if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
- alc_update_coef_idx(codec, 0x7, 1<<5, 0);
- break;
- case 0x10ec0892:
- case 0x10ec0897:
- alc_update_coef_idx(codec, 0x7, 1<<5, 0);
- break;
- case 0x10ec0899:
- case 0x10ec0900:
- case 0x10ec0b00:
- case 0x10ec1168:
- case 0x10ec1220:
- alc_update_coef_idx(codec, 0x7, 1<<1, 0);
- break;
- }
-}
-
-/* additional initialization for ALC888 variants */
-static void alc888_coef_init(struct hda_codec *codec)
-{
- switch (alc_get_coef0(codec) & 0x00f0) {
- /* alc888-VA */
- case 0x00:
- /* alc888-VB */
- case 0x10:
- alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
- break;
- }
-}
-
-/* turn on/off EAPD control (only if available) */
-static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
-{
- if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
- return;
- if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
- on ? 2 : 0);
-}
-
-/* turn on/off EAPD controls of the codec */
-static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
-{
- /* We currently only handle front, HP */
- static const hda_nid_t pins[] = {
- 0x0f, 0x10, 0x14, 0x15, 0x17, 0
- };
- const hda_nid_t *p;
- for (p = pins; *p; p++)
- set_eapd(codec, *p, on);
-}
-
-static int find_ext_mic_pin(struct hda_codec *codec);
-
-static void alc_headset_mic_no_shutup(struct hda_codec *codec)
-{
- const struct hda_pincfg *pin;
- int mic_pin = find_ext_mic_pin(codec);
- int i;
-
- /* don't shut up pins when unloading the driver; otherwise it breaks
- * the default pin setup at the next load of the driver
- */
- if (codec->bus->shutdown)
- return;
-
- snd_array_for_each(&codec->init_pins, i, pin) {
- /* use read here for syncing after issuing each verb */
- if (pin->nid != mic_pin)
- snd_hda_codec_read(codec, pin->nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
- }
-
- codec->pins_shutup = 1;
-}
-
-static void alc_shutup_pins(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- switch (codec->core.vendor_id) {
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- case 0x10ec0283:
- case 0x10ec0286:
- case 0x10ec0288:
- case 0x10ec0298:
- alc_headset_mic_no_shutup(codec);
- break;
- default:
- if (!spec->no_shutup_pins)
- snd_hda_shutup_pins(codec);
- break;
- }
-}
-
-/* generic shutup callback;
- * just turning off EAPD and a little pause for avoiding pop-noise
- */
-static void alc_eapd_shutup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- alc_auto_setup_eapd(codec, false);
- if (!spec->no_depop_delay)
- msleep(200);
- alc_shutup_pins(codec);
-}
-
-/* generic EAPD initialization */
-static void alc_auto_init_amp(struct hda_codec *codec, int type)
-{
- alc_auto_setup_eapd(codec, true);
- alc_write_gpio(codec);
- switch (type) {
- case ALC_INIT_DEFAULT:
- switch (codec->core.vendor_id) {
- case 0x10ec0260:
- alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
- break;
- case 0x10ec0880:
- case 0x10ec0882:
- case 0x10ec0883:
- case 0x10ec0885:
- alc_update_coef_idx(codec, 7, 0, 0x2030);
- break;
- case 0x10ec0888:
- alc888_coef_init(codec);
- break;
- }
- break;
- }
-}
-
-/* get a primary headphone pin if available */
-static hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
-{
- if (spec->gen.autocfg.hp_pins[0])
- return spec->gen.autocfg.hp_pins[0];
- if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
- return spec->gen.autocfg.line_out_pins[0];
- return 0;
-}
-
-/*
- * Realtek SSID verification
- */
-
-/* Could be any non-zero and even value. When used as fixup, tells
- * the driver to ignore any present sku defines.
- */
-#define ALC_FIXUP_SKU_IGNORE (2)
-
-static void alc_fixup_sku_ignore(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->cdefine.fixup = 1;
- spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
- }
-}
-
-static void alc_fixup_no_depop_delay(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PROBE) {
- spec->no_depop_delay = 1;
- codec->depop_delay = 0;
- }
-}
-
-static int alc_auto_parse_customize_define(struct hda_codec *codec)
-{
- unsigned int ass, tmp, i;
- unsigned nid = 0;
- struct alc_spec *spec = codec->spec;
-
- spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
-
- if (spec->cdefine.fixup) {
- ass = spec->cdefine.sku_cfg;
- if (ass == ALC_FIXUP_SKU_IGNORE)
- return -1;
- goto do_sku;
- }
-
- if (!codec->bus->pci)
- return -1;
- ass = codec->core.subsystem_id & 0xffff;
- if (ass != codec->bus->pci->subsystem_device && (ass & 1))
- goto do_sku;
-
- nid = 0x1d;
- if (codec->core.vendor_id == 0x10ec0260)
- nid = 0x17;
- ass = snd_hda_codec_get_pincfg(codec, nid);
-
- if (!(ass & 1)) {
- codec_info(codec, "%s: SKU not ready 0x%08x\n",
- codec->core.chip_name, ass);
- return -1;
- }
-
- /* check sum */
- tmp = 0;
- for (i = 1; i < 16; i++) {
- if ((ass >> i) & 1)
- tmp++;
- }
- if (((ass >> 16) & 0xf) != tmp)
- return -1;
-
- spec->cdefine.port_connectivity = ass >> 30;
- spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
- spec->cdefine.check_sum = (ass >> 16) & 0xf;
- spec->cdefine.customization = ass >> 8;
-do_sku:
- spec->cdefine.sku_cfg = ass;
- spec->cdefine.external_amp = (ass & 0x38) >> 3;
- spec->cdefine.platform_type = (ass & 0x4) >> 2;
- spec->cdefine.swap = (ass & 0x2) >> 1;
- spec->cdefine.override = ass & 0x1;
-
- codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
- nid, spec->cdefine.sku_cfg);
- codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
- spec->cdefine.port_connectivity);
- codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
- codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
- codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
- codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
- codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
- codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
- codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
-
- return 0;
-}
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
- int i;
- for (i = 0; i < nums; i++)
- if (list[i] == nid)
- return i;
- return -1;
-}
-/* return true if the given NID is found in the list */
-static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
- return find_idx_in_nid_list(nid, list, nums) >= 0;
-}
-
-/* check subsystem ID and set up device-specific initialization;
- * return 1 if initialized, 0 if invalid SSID
- */
-/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
- * 31 ~ 16 : Manufacture ID
- * 15 ~ 8 : SKU ID
- * 7 ~ 0 : Assembly ID
- * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
- */
-static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
-{
- unsigned int ass, tmp, i;
- unsigned nid;
- struct alc_spec *spec = codec->spec;
-
- if (spec->cdefine.fixup) {
- ass = spec->cdefine.sku_cfg;
- if (ass == ALC_FIXUP_SKU_IGNORE)
- return 0;
- goto do_sku;
- }
-
- ass = codec->core.subsystem_id & 0xffff;
- if (codec->bus->pci &&
- ass != codec->bus->pci->subsystem_device && (ass & 1))
- goto do_sku;
-
- /* invalid SSID, check the special NID pin defcfg instead */
- /*
- * 31~30 : port connectivity
- * 29~21 : reserve
- * 20 : PCBEEP input
- * 19~16 : Check sum (15:1)
- * 15~1 : Custom
- * 0 : override
- */
- nid = 0x1d;
- if (codec->core.vendor_id == 0x10ec0260)
- nid = 0x17;
- ass = snd_hda_codec_get_pincfg(codec, nid);
- codec_dbg(codec,
- "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
- ass, nid);
- if (!(ass & 1))
- return 0;
- if ((ass >> 30) != 1) /* no physical connection */
- return 0;
-
- /* check sum */
- tmp = 0;
- for (i = 1; i < 16; i++) {
- if ((ass >> i) & 1)
- tmp++;
- }
- if (((ass >> 16) & 0xf) != tmp)
- return 0;
-do_sku:
- codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
- ass & 0xffff, codec->core.vendor_id);
- /*
- * 0 : override
- * 1 : Swap Jack
- * 2 : 0 --> Desktop, 1 --> Laptop
- * 3~5 : External Amplifier control
- * 7~6 : Reserved
- */
- tmp = (ass & 0x38) >> 3; /* external Amp control */
- if (spec->init_amp == ALC_INIT_UNDEFINED) {
- switch (tmp) {
- case 1:
- alc_setup_gpio(codec, 0x01);
- break;
- case 3:
- alc_setup_gpio(codec, 0x02);
- break;
- case 7:
- alc_setup_gpio(codec, 0x04);
- break;
- case 5:
- default:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
- }
- }
-
- /* is laptop or Desktop and enable the function "Mute internal speaker
- * when the external headphone out jack is plugged"
- */
- if (!(ass & 0x8000))
- return 1;
- /*
- * 10~8 : Jack location
- * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
- * 14~13: Resvered
- * 15 : 1 --> enable the function "Mute internal speaker
- * when the external headphone out jack is plugged"
- */
- if (!alc_get_hp_pin(spec)) {
- hda_nid_t nid;
- tmp = (ass >> 11) & 0x3; /* HP to chassis */
- nid = ports[tmp];
- if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
- spec->gen.autocfg.line_outs))
- return 1;
- spec->gen.autocfg.hp_pins[0] = nid;
- }
- return 1;
-}
-
-/* Check the validity of ALC subsystem-id
- * ports contains an array of 4 pin NIDs for port-A, E, D and I */
-static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
-{
- if (!alc_subsystem_id(codec, ports)) {
- struct alc_spec *spec = codec->spec;
- if (spec->init_amp == ALC_INIT_UNDEFINED) {
- codec_dbg(codec,
- "realtek: Enable default setup for auto mode as fallback\n");
- spec->init_amp = ALC_INIT_DEFAULT;
- }
- }
-}
-
-/*
- */
-
-static void alc_fixup_inv_dmic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->gen.inv_dmic_split = 1;
-}
-
-
-static int alc_build_controls(struct hda_codec *codec)
-{
- int err;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
- return 0;
-}
-
-
-/*
- * Common callbacks
- */
-
-static void alc_pre_init(struct hda_codec *codec)
-{
- alc_fill_eapd_coef(codec);
-}
-
-#define is_s3_resume(codec) \
- ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
-#define is_s4_resume(codec) \
- ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
-
-static int alc_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- /* hibernation resume needs the full chip initialization */
- if (is_s4_resume(codec))
- alc_pre_init(codec);
-
- if (spec->init_hook)
- spec->init_hook(codec);
-
- spec->gen.skip_verbs = 1; /* applied in below */
- snd_hda_gen_init(codec);
- alc_fix_pll(codec);
- alc_auto_init_amp(codec, spec->init_amp);
- snd_hda_apply_verbs(codec); /* apply verbs here after own init */
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
- return 0;
-}
-
-#define alc_free snd_hda_gen_free
-
-#ifdef CONFIG_PM
-static inline void alc_shutup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (!snd_hda_get_bool_hint(codec, "shutup"))
- return; /* disabled explicitly by hints */
-
- if (spec && spec->shutup)
- spec->shutup(codec);
- else
- alc_shutup_pins(codec);
-}
-
-static void alc_power_eapd(struct hda_codec *codec)
-{
- alc_auto_setup_eapd(codec, false);
-}
-
-static int alc_suspend(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc_shutup(codec);
- if (spec && spec->power_hook)
- spec->power_hook(codec);
- return 0;
-}
-
-static int alc_resume(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (!spec->no_depop_delay)
- msleep(150); /* to avoid pop noise */
- codec->patch_ops.init(codec);
- snd_hda_regmap_sync(codec);
- hda_call_check_power_status(codec, 0x01);
- return 0;
-}
-#endif
-
-/*
- */
-static const struct hda_codec_ops alc_patch_ops = {
- .build_controls = alc_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = alc_init,
- .free = alc_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .resume = alc_resume,
- .suspend = alc_suspend,
- .check_power_status = snd_hda_gen_check_power_status,
-#endif
-};
-
-
-#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
-
-/*
- * Rename codecs appropriately from COEF value or subvendor id
- */
-struct alc_codec_rename_table {
- unsigned int vendor_id;
- unsigned short coef_mask;
- unsigned short coef_bits;
- const char *name;
-};
-
-struct alc_codec_rename_pci_table {
- unsigned int codec_vendor_id;
- unsigned short pci_subvendor;
- unsigned short pci_subdevice;
- const char *name;
-};
-
-static const struct alc_codec_rename_table rename_tbl[] = {
- { 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
- { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
- { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
- { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
- { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
- { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
- { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
- { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
- { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
- { 0x10ec0662, 0xffff, 0x4020, "ALC656" },
- { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
- { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
- { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
- { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
- { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
- { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
- { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
- { } /* terminator */
-};
-
-static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
- { 0x10ec0280, 0x1028, 0, "ALC3220" },
- { 0x10ec0282, 0x1028, 0, "ALC3221" },
- { 0x10ec0283, 0x1028, 0, "ALC3223" },
- { 0x10ec0288, 0x1028, 0, "ALC3263" },
- { 0x10ec0292, 0x1028, 0, "ALC3226" },
- { 0x10ec0293, 0x1028, 0, "ALC3235" },
- { 0x10ec0255, 0x1028, 0, "ALC3234" },
- { 0x10ec0668, 0x1028, 0, "ALC3661" },
- { 0x10ec0275, 0x1028, 0, "ALC3260" },
- { 0x10ec0899, 0x1028, 0, "ALC3861" },
- { 0x10ec0298, 0x1028, 0, "ALC3266" },
- { 0x10ec0236, 0x1028, 0, "ALC3204" },
- { 0x10ec0256, 0x1028, 0, "ALC3246" },
- { 0x10ec0225, 0x1028, 0, "ALC3253" },
- { 0x10ec0295, 0x1028, 0, "ALC3254" },
- { 0x10ec0299, 0x1028, 0, "ALC3271" },
- { 0x10ec0670, 0x1025, 0, "ALC669X" },
- { 0x10ec0676, 0x1025, 0, "ALC679X" },
- { 0x10ec0282, 0x1043, 0, "ALC3229" },
- { 0x10ec0233, 0x1043, 0, "ALC3236" },
- { 0x10ec0280, 0x103c, 0, "ALC3228" },
- { 0x10ec0282, 0x103c, 0, "ALC3227" },
- { 0x10ec0286, 0x103c, 0, "ALC3242" },
- { 0x10ec0290, 0x103c, 0, "ALC3241" },
- { 0x10ec0668, 0x103c, 0, "ALC3662" },
- { 0x10ec0283, 0x17aa, 0, "ALC3239" },
- { 0x10ec0292, 0x17aa, 0, "ALC3232" },
- { } /* terminator */
-};
-
-static int alc_codec_rename_from_preset(struct hda_codec *codec)
-{
- const struct alc_codec_rename_table *p;
- const struct alc_codec_rename_pci_table *q;
-
- for (p = rename_tbl; p->vendor_id; p++) {
- if (p->vendor_id != codec->core.vendor_id)
- continue;
- if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
- return alc_codec_rename(codec, p->name);
- }
-
- if (!codec->bus->pci)
- return 0;
- for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
- if (q->codec_vendor_id != codec->core.vendor_id)
- continue;
- if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
- continue;
- if (!q->pci_subdevice ||
- q->pci_subdevice == codec->bus->pci->subsystem_device)
- return alc_codec_rename(codec, q->name);
- }
-
- return 0;
-}
-
-
-/*
- * Digital-beep handlers
- */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-
-/* additional beep mixers; private_value will be overwritten */
-static const struct snd_kcontrol_new alc_beep_mixer[] = {
- HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
- HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
-};
-
-/* set up and create beep controls */
-static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
- int idx, int dir)
-{
- struct snd_kcontrol_new *knew;
- unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
- knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
- &alc_beep_mixer[i]);
- if (!knew)
- return -ENOMEM;
- knew->private_value = beep_amp;
- }
- return 0;
-}
-
-static const struct snd_pci_quirk beep_allow_list[] = {
- SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
- SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
- SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
- SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
- SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
- SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
- SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
- SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
- SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
- /* denylist -- no beep available */
- SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
- SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
- {}
-};
-
-static inline int has_cdefine_beep(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- const struct snd_pci_quirk *q;
- q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
- if (q)
- return q->value;
- return spec->cdefine.enable_pcbeep;
-}
-#else
-#define set_beep_amp(spec, nid, idx, dir) 0
-#define has_cdefine_beep(codec) 0
-#endif
-
-/* parse the BIOS configuration and set up the alc_spec */
-/* return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
-static int alc_parse_auto_config(struct hda_codec *codec,
- const hda_nid_t *ignore_nids,
- const hda_nid_t *ssid_nids)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->gen.autocfg;
- int err;
-
- err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
- spec->parse_flags);
- if (err < 0)
- return err;
-
- if (ssid_nids)
- alc_ssid_check(codec, ssid_nids);
-
- err = snd_hda_gen_parse_auto_config(codec, cfg);
- if (err < 0)
- return err;
-
- return 1;
-}
-
-/* common preparation job for alc_spec */
-static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
-{
- struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- int err;
-
- if (!spec)
- return -ENOMEM;
- codec->spec = spec;
- snd_hda_gen_spec_init(&spec->gen);
- spec->gen.mixer_nid = mixer_nid;
- spec->gen.own_eapd_ctl = 1;
- codec->single_adc_amp = 1;
- /* FIXME: do we need this for all Realtek codec models? */
- codec->spdif_status_reset = 1;
- codec->forced_resume = 1;
- codec->patch_ops = alc_patch_ops;
- mutex_init(&spec->coef_mutex);
-
- err = alc_codec_rename_from_preset(codec);
- if (err < 0) {
- kfree(spec);
- return err;
- }
- return 0;
-}
-
-static int alc880_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
- static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
- return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
-}
-
-/*
- * ALC880 fix-ups
- */
-enum {
- ALC880_FIXUP_GPIO1,
- ALC880_FIXUP_GPIO2,
- ALC880_FIXUP_MEDION_RIM,
- ALC880_FIXUP_LG,
- ALC880_FIXUP_LG_LW25,
- ALC880_FIXUP_W810,
- ALC880_FIXUP_EAPD_COEF,
- ALC880_FIXUP_TCL_S700,
- ALC880_FIXUP_VOL_KNOB,
- ALC880_FIXUP_FUJITSU,
- ALC880_FIXUP_F1734,
- ALC880_FIXUP_UNIWILL,
- ALC880_FIXUP_UNIWILL_DIG,
- ALC880_FIXUP_Z71V,
- ALC880_FIXUP_ASUS_W5A,
- ALC880_FIXUP_3ST_BASE,
- ALC880_FIXUP_3ST,
- ALC880_FIXUP_3ST_DIG,
- ALC880_FIXUP_5ST_BASE,
- ALC880_FIXUP_5ST,
- ALC880_FIXUP_5ST_DIG,
- ALC880_FIXUP_6ST_BASE,
- ALC880_FIXUP_6ST,
- ALC880_FIXUP_6ST_DIG,
- ALC880_FIXUP_6ST_AUTOMUTE,
-};
-
-/* enable the volume-knob widget support on NID 0x21 */
-static void alc880_fixup_vol_knob(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PROBE)
- snd_hda_jack_detect_enable_callback(codec, 0x21,
- alc_update_knob_master);
-}
-
-static const struct hda_fixup alc880_fixups[] = {
- [ALC880_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio1,
- },
- [ALC880_FIXUP_GPIO2] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio2,
- },
- [ALC880_FIXUP_MEDION_RIM] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_GPIO2,
- },
- [ALC880_FIXUP_LG] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- /* disable bogus unused pins */
- { 0x16, 0x411111f0 },
- { 0x18, 0x411111f0 },
- { 0x1a, 0x411111f0 },
- { }
- }
- },
- [ALC880_FIXUP_LG_LW25] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1a, 0x0181344f }, /* line-in */
- { 0x1b, 0x0321403f }, /* headphone */
- { }
- }
- },
- [ALC880_FIXUP_W810] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- /* disable bogus unused pins */
- { 0x17, 0x411111f0 },
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_GPIO2,
- },
- [ALC880_FIXUP_EAPD_COEF] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* change to EAPD mode */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
- {}
- },
- },
- [ALC880_FIXUP_TCL_S700] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* change to EAPD mode */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
- {}
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_GPIO2,
- },
- [ALC880_FIXUP_VOL_KNOB] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc880_fixup_vol_knob,
- },
- [ALC880_FIXUP_FUJITSU] = {
- /* override all pins as BIOS on old Amilo is broken */
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x0121401f }, /* HP */
- { 0x15, 0x99030120 }, /* speaker */
- { 0x16, 0x99030130 }, /* bass speaker */
- { 0x17, 0x411111f0 }, /* N/A */
- { 0x18, 0x411111f0 }, /* N/A */
- { 0x19, 0x01a19950 }, /* mic-in */
- { 0x1a, 0x411111f0 }, /* N/A */
- { 0x1b, 0x411111f0 }, /* N/A */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- { 0x1e, 0x01454140 }, /* SPDIF out */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_VOL_KNOB,
- },
- [ALC880_FIXUP_F1734] = {
- /* almost compatible with FUJITSU, but no bass and SPDIF */
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x0121401f }, /* HP */
- { 0x15, 0x99030120 }, /* speaker */
- { 0x16, 0x411111f0 }, /* N/A */
- { 0x17, 0x411111f0 }, /* N/A */
- { 0x18, 0x411111f0 }, /* N/A */
- { 0x19, 0x01a19950 }, /* mic-in */
- { 0x1a, 0x411111f0 }, /* N/A */
- { 0x1b, 0x411111f0 }, /* N/A */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- { 0x1e, 0x411111f0 }, /* N/A */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_VOL_KNOB,
- },
- [ALC880_FIXUP_UNIWILL] = {
- /* need to fix HP and speaker pins to be parsed correctly */
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x0121411f }, /* HP */
- { 0x15, 0x99030120 }, /* speaker */
- { 0x16, 0x99030130 }, /* bass speaker */
- { }
- },
- },
- [ALC880_FIXUP_UNIWILL_DIG] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- /* disable bogus unused pins */
- { 0x17, 0x411111f0 },
- { 0x19, 0x411111f0 },
- { 0x1b, 0x411111f0 },
- { 0x1f, 0x411111f0 },
- { }
- }
- },
- [ALC880_FIXUP_Z71V] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- /* set up the whole pins as BIOS is utterly broken */
- { 0x14, 0x99030120 }, /* speaker */
- { 0x15, 0x0121411f }, /* HP */
- { 0x16, 0x411111f0 }, /* N/A */
- { 0x17, 0x411111f0 }, /* N/A */
- { 0x18, 0x01a19950 }, /* mic-in */
- { 0x19, 0x411111f0 }, /* N/A */
- { 0x1a, 0x01813031 }, /* line-in */
- { 0x1b, 0x411111f0 }, /* N/A */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- { 0x1e, 0x0144111e }, /* SPDIF */
- { }
- }
- },
- [ALC880_FIXUP_ASUS_W5A] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- /* set up the whole pins as BIOS is utterly broken */
- { 0x14, 0x0121411f }, /* HP */
- { 0x15, 0x411111f0 }, /* N/A */
- { 0x16, 0x411111f0 }, /* N/A */
- { 0x17, 0x411111f0 }, /* N/A */
- { 0x18, 0x90a60160 }, /* mic */
- { 0x19, 0x411111f0 }, /* N/A */
- { 0x1a, 0x411111f0 }, /* N/A */
- { 0x1b, 0x411111f0 }, /* N/A */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- { 0x1e, 0xb743111e }, /* SPDIF out */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_GPIO1,
- },
- [ALC880_FIXUP_3ST_BASE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x01014010 }, /* line-out */
- { 0x15, 0x411111f0 }, /* N/A */
- { 0x16, 0x411111f0 }, /* N/A */
- { 0x17, 0x411111f0 }, /* N/A */
- { 0x18, 0x01a19c30 }, /* mic-in */
- { 0x19, 0x0121411f }, /* HP */
- { 0x1a, 0x01813031 }, /* line-in */
- { 0x1b, 0x02a19c40 }, /* front-mic */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- /* 0x1e is filled in below */
- { 0x1f, 0x411111f0 }, /* N/A */
- { }
- }
- },
- [ALC880_FIXUP_3ST] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x411111f0 }, /* N/A */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_3ST_BASE,
- },
- [ALC880_FIXUP_3ST_DIG] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x0144111e }, /* SPDIF */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_3ST_BASE,
- },
- [ALC880_FIXUP_5ST_BASE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x01014010 }, /* front */
- { 0x15, 0x411111f0 }, /* N/A */
- { 0x16, 0x01011411 }, /* CLFE */
- { 0x17, 0x01016412 }, /* surr */
- { 0x18, 0x01a19c30 }, /* mic-in */
- { 0x19, 0x0121411f }, /* HP */
- { 0x1a, 0x01813031 }, /* line-in */
- { 0x1b, 0x02a19c40 }, /* front-mic */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- /* 0x1e is filled in below */
- { 0x1f, 0x411111f0 }, /* N/A */
- { }
- }
- },
- [ALC880_FIXUP_5ST] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x411111f0 }, /* N/A */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_5ST_BASE,
- },
- [ALC880_FIXUP_5ST_DIG] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x0144111e }, /* SPDIF */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_5ST_BASE,
- },
- [ALC880_FIXUP_6ST_BASE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x01014010 }, /* front */
- { 0x15, 0x01016412 }, /* surr */
- { 0x16, 0x01011411 }, /* CLFE */
- { 0x17, 0x01012414 }, /* side */
- { 0x18, 0x01a19c30 }, /* mic-in */
- { 0x19, 0x02a19c40 }, /* front-mic */
- { 0x1a, 0x01813031 }, /* line-in */
- { 0x1b, 0x0121411f }, /* HP */
- { 0x1c, 0x411111f0 }, /* N/A */
- { 0x1d, 0x411111f0 }, /* N/A */
- /* 0x1e is filled in below */
- { 0x1f, 0x411111f0 }, /* N/A */
- { }
- }
- },
- [ALC880_FIXUP_6ST] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x411111f0 }, /* N/A */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_6ST_BASE,
- },
- [ALC880_FIXUP_6ST_DIG] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x0144111e }, /* SPDIF */
- { }
- },
- .chained = true,
- .chain_id = ALC880_FIXUP_6ST_BASE,
- },
- [ALC880_FIXUP_6ST_AUTOMUTE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1b, 0x0121401f }, /* HP with jack detect */
- { }
- },
- .chained_before = true,
- .chain_id = ALC880_FIXUP_6ST_BASE,
- },
-};
-
-static const struct snd_pci_quirk alc880_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
- SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
- SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
- SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
- SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
- SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
- SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
- SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
- SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
- SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
- SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
- SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
- SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
- SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
- SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
- SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
- SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
- SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
- SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
- SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
- SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
- SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
- SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
-
- /* Below is the copied entries from alc880_quirks.c.
- * It's not quite sure whether BIOS sets the correct pin-config table
- * on these machines, thus they are kept to be compatible with
- * the old static quirks. Once when it's confirmed to work without
- * these overrides, it'd be better to remove.
- */
- SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
- SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
- SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
- SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
- SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
- SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
- SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
- SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
- SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
- SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
- SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
- /* default Intel */
- SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
- SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
- SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
- {}
-};
-
-static const struct hda_model_fixup alc880_fixup_models[] = {
- {.id = ALC880_FIXUP_3ST, .name = "3stack"},
- {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
- {.id = ALC880_FIXUP_5ST, .name = "5stack"},
- {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
- {.id = ALC880_FIXUP_6ST, .name = "6stack"},
- {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
- {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
- {}
-};
-
-
-/*
- * OK, here we have finally the patch for ALC880
- */
-static int patch_alc880(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x0b);
- if (err < 0)
- return err;
-
- spec = codec->spec;
- spec->gen.need_dac_fix = 1;
- spec->gen.beep_nid = 0x01;
-
- codec->patch_ops.unsol_event = alc880_unsol_event;
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
- alc880_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- /* automatic parse from the BIOS config */
- err = alc880_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog) {
- err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-
-/*
- * ALC260 support
- */
-static int alc260_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
- static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
- return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
-}
-
-/*
- * Pin config fixes
- */
-enum {
- ALC260_FIXUP_HP_DC5750,
- ALC260_FIXUP_HP_PIN_0F,
- ALC260_FIXUP_COEF,
- ALC260_FIXUP_GPIO1,
- ALC260_FIXUP_GPIO1_TOGGLE,
- ALC260_FIXUP_REPLACER,
- ALC260_FIXUP_HP_B1900,
- ALC260_FIXUP_KN1,
- ALC260_FIXUP_FSC_S7020,
- ALC260_FIXUP_FSC_S7020_JWSE,
- ALC260_FIXUP_VAIO_PINS,
-};
-
-static void alc260_gpio1_automute(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
-}
-
-static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PROBE) {
- /* although the machine has only one output pin, we need to
- * toggle GPIO1 according to the jack state
- */
- spec->gen.automute_hook = alc260_gpio1_automute;
- spec->gen.detect_hp = 1;
- spec->gen.automute_speaker = 1;
- spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
- snd_hda_jack_detect_enable_callback(codec, 0x0f,
- snd_hda_gen_hp_automute);
- alc_setup_gpio(codec, 0x01);
- }
-}
-
-static void alc260_fixup_kn1(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- static const struct hda_pintbl pincfgs[] = {
- { 0x0f, 0x02214000 }, /* HP/speaker */
- { 0x12, 0x90a60160 }, /* int mic */
- { 0x13, 0x02a19000 }, /* ext mic */
- { 0x18, 0x01446000 }, /* SPDIF out */
- /* disable bogus I/O pins */
- { 0x10, 0x411111f0 },
- { 0x11, 0x411111f0 },
- { 0x14, 0x411111f0 },
- { 0x15, 0x411111f0 },
- { 0x16, 0x411111f0 },
- { 0x17, 0x411111f0 },
- { 0x19, 0x411111f0 },
- { }
- };
-
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- snd_hda_apply_pincfgs(codec, pincfgs);
- spec->init_amp = ALC_INIT_NONE;
- break;
- }
-}
-
-static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- spec->init_amp = ALC_INIT_NONE;
-}
-
-static void alc260_fixup_fsc_s7020_jwse(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->gen.add_jack_modes = 1;
- spec->gen.hp_mic = 1;
- }
-}
-
-static const struct hda_fixup alc260_fixups[] = {
- [ALC260_FIXUP_HP_DC5750] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x11, 0x90130110 }, /* speaker */
- { }
- }
- },
- [ALC260_FIXUP_HP_PIN_0F] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x0f, 0x01214000 }, /* HP */
- { }
- }
- },
- [ALC260_FIXUP_COEF] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 },
- { }
- },
- },
- [ALC260_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio1,
- },
- [ALC260_FIXUP_GPIO1_TOGGLE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc260_fixup_gpio1_toggle,
- .chained = true,
- .chain_id = ALC260_FIXUP_HP_PIN_0F,
- },
- [ALC260_FIXUP_REPLACER] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 },
- { }
- },
- .chained = true,
- .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
- },
- [ALC260_FIXUP_HP_B1900] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc260_fixup_gpio1_toggle,
- .chained = true,
- .chain_id = ALC260_FIXUP_COEF,
- },
- [ALC260_FIXUP_KN1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc260_fixup_kn1,
- },
- [ALC260_FIXUP_FSC_S7020] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc260_fixup_fsc_s7020,
- },
- [ALC260_FIXUP_FSC_S7020_JWSE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc260_fixup_fsc_s7020_jwse,
- .chained = true,
- .chain_id = ALC260_FIXUP_FSC_S7020,
- },
- [ALC260_FIXUP_VAIO_PINS] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- /* Pin configs are missing completely on some VAIOs */
- { 0x0f, 0x01211020 },
- { 0x10, 0x0001003f },
- { 0x11, 0x411111f0 },
- { 0x12, 0x01a15930 },
- { 0x13, 0x411111f0 },
- { 0x14, 0x411111f0 },
- { 0x15, 0x411111f0 },
- { 0x16, 0x411111f0 },
- { 0x17, 0x411111f0 },
- { 0x18, 0x411111f0 },
- { 0x19, 0x411111f0 },
- { }
- }
- },
-};
-
-static const struct snd_pci_quirk alc260_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
- SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
- SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
- SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
- SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
- SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
- SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
- SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
- SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
- SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
- SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
- SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
- {}
-};
-
-static const struct hda_model_fixup alc260_fixup_models[] = {
- {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
- {.id = ALC260_FIXUP_COEF, .name = "coef"},
- {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
- {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
- {}
-};
-
-/*
- */
-static int patch_alc260(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x07);
- if (err < 0)
- return err;
-
- spec = codec->spec;
- /* as quite a few machines require HP amp for speaker outputs,
- * it's easier to enable it unconditionally; even if it's unneeded,
- * it's almost harmless.
- */
- spec->gen.prefer_hp_amp = 1;
- spec->gen.beep_nid = 0x01;
-
- spec->shutup = alc_eapd_shutup;
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
- alc260_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- /* automatic parse from the BIOS config */
- err = alc260_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog) {
- err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-
-/*
- * ALC882/883/885/888/889 support
- *
- * ALC882 is almost identical with ALC880 but has cleaner and more flexible
- * configuration. Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs. This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-
-/*
- * Pin config fixes
- */
-enum {
- ALC882_FIXUP_ABIT_AW9D_MAX,
- ALC882_FIXUP_LENOVO_Y530,
- ALC882_FIXUP_PB_M5210,
- ALC882_FIXUP_ACER_ASPIRE_7736,
- ALC882_FIXUP_ASUS_W90V,
- ALC889_FIXUP_CD,
- ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
- ALC889_FIXUP_VAIO_TT,
- ALC888_FIXUP_EEE1601,
- ALC886_FIXUP_EAPD,
- ALC882_FIXUP_EAPD,
- ALC883_FIXUP_EAPD,
- ALC883_FIXUP_ACER_EAPD,
- ALC882_FIXUP_GPIO1,
- ALC882_FIXUP_GPIO2,
- ALC882_FIXUP_GPIO3,
- ALC889_FIXUP_COEF,
- ALC882_FIXUP_ASUS_W2JC,
- ALC882_FIXUP_ACER_ASPIRE_4930G,
- ALC882_FIXUP_ACER_ASPIRE_8930G,
- ALC882_FIXUP_ASPIRE_8930G_VERBS,
- ALC885_FIXUP_MACPRO_GPIO,
- ALC889_FIXUP_DAC_ROUTE,
- ALC889_FIXUP_MBP_VREF,
- ALC889_FIXUP_IMAC91_VREF,
- ALC889_FIXUP_MBA11_VREF,
- ALC889_FIXUP_MBA21_VREF,
- ALC889_FIXUP_MP11_VREF,
- ALC889_FIXUP_MP41_VREF,
- ALC882_FIXUP_INV_DMIC,
- ALC882_FIXUP_NO_PRIMARY_HP,
- ALC887_FIXUP_ASUS_BASS,
- ALC887_FIXUP_BASS_CHMAP,
- ALC1220_FIXUP_GB_DUAL_CODECS,
- ALC1220_FIXUP_GB_X570,
- ALC1220_FIXUP_CLEVO_P950,
- ALC1220_FIXUP_CLEVO_PB51ED,
- ALC1220_FIXUP_CLEVO_PB51ED_PINS,
- ALC887_FIXUP_ASUS_AUDIO,
- ALC887_FIXUP_ASUS_HMIC,
- ALCS1200A_FIXUP_MIC_VREF,
-};
-
-static void alc889_fixup_coef(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action != HDA_FIXUP_ACT_INIT)
- return;
- alc_update_coef_idx(codec, 7, 0, 0x2030);
-}
-
-/* set up GPIO at initialization */
-static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->gpio_write_delay = true;
- alc_fixup_gpio3(codec, fix, action);
-}
-
-/* Fix the connection of some pins for ALC889:
- * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
- * work correctly (bko#42740)
- */
-static void alc889_fixup_dac_route(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- /* fake the connections during parsing the tree */
- static const hda_nid_t conn1[] = { 0x0c, 0x0d };
- static const hda_nid_t conn2[] = { 0x0e, 0x0f };
- snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
- snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
- snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
- snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
- } else if (action == HDA_FIXUP_ACT_PROBE) {
- /* restore the connections */
- static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
- snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
- snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
- snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
- snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
- }
-}
-
-/* Set VREF on HP pin */
-static void alc889_fixup_mbp_vref(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
- struct alc_spec *spec = codec->spec;
- int i;
-
- if (action != HDA_FIXUP_ACT_INIT)
- return;
- for (i = 0; i < ARRAY_SIZE(nids); i++) {
- unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
- if (get_defcfg_device(val) != AC_JACK_HP_OUT)
- continue;
- val = snd_hda_codec_get_pin_target(codec, nids[i]);
- val |= AC_PINCTL_VREF_80;
- snd_hda_set_pin_ctl(codec, nids[i], val);
- spec->gen.keep_vref_in_automute = 1;
- break;
- }
-}
-
-static void alc889_fixup_mac_pins(struct hda_codec *codec,
- const hda_nid_t *nids, int num_nids)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < num_nids; i++) {
- unsigned int val;
- val = snd_hda_codec_get_pin_target(codec, nids[i]);
- val |= AC_PINCTL_VREF_50;
- snd_hda_set_pin_ctl(codec, nids[i], val);
- }
- spec->gen.keep_vref_in_automute = 1;
-}
-
-/* Set VREF on speaker pins on imac91 */
-static void alc889_fixup_imac91_vref(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- static const hda_nid_t nids[] = { 0x18, 0x1a };
-
- if (action == HDA_FIXUP_ACT_INIT)
- alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Set VREF on speaker pins on mba11 */
-static void alc889_fixup_mba11_vref(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- static const hda_nid_t nids[] = { 0x18 };
-
- if (action == HDA_FIXUP_ACT_INIT)
- alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Set VREF on speaker pins on mba21 */
-static void alc889_fixup_mba21_vref(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- static const hda_nid_t nids[] = { 0x18, 0x19 };
-
- if (action == HDA_FIXUP_ACT_INIT)
- alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Don't take HP output as primary
- * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
- * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
- */
-static void alc882_fixup_no_primary_hp(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->gen.no_primary_hp = 1;
- spec->gen.no_multi_io = 1;
- }
-}
-
-static void alc_fixup_bass_chmap(struct hda_codec *codec,
- const struct hda_fixup *fix, int action);
-
-/* For dual-codec configuration, we need to disable some features to avoid
- * conflicts of kctls and PCM streams
- */
-static void alc_fixup_dual_codecs(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- /* disable vmaster */
- spec->gen.suppress_vmaster = 1;
- /* auto-mute and auto-mic switch don't work with multiple codecs */
- spec->gen.suppress_auto_mute = 1;
- spec->gen.suppress_auto_mic = 1;
- /* disable aamix as well */
- spec->gen.mixer_nid = 0;
- /* add location prefix to avoid conflicts */
- codec->force_pin_prefix = 1;
-}
-
-static void rename_ctl(struct hda_codec *codec, const char *oldname,
- const char *newname)
-{
- struct snd_kcontrol *kctl;
-
- kctl = snd_hda_find_mixer_ctl(codec, oldname);
- if (kctl)
- snd_ctl_rename(codec->card, kctl, newname);
-}
-
-static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- alc_fixup_dual_codecs(codec, fix, action);
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- /* override card longname to provide a unique UCM profile */
- strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
- break;
- case HDA_FIXUP_ACT_BUILD:
- /* rename Capture controls depending on the codec */
- rename_ctl(codec, "Capture Volume",
- codec->addr == 0 ?
- "Rear-Panel Capture Volume" :
- "Front-Panel Capture Volume");
- rename_ctl(codec, "Capture Switch",
- codec->addr == 0 ?
- "Rear-Panel Capture Switch" :
- "Front-Panel Capture Switch");
- break;
- }
-}
-
-static void alc1220_fixup_gb_x570(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- static const hda_nid_t conn1[] = { 0x0c };
- static const struct coef_fw gb_x570_coefs[] = {
- WRITE_COEF(0x07, 0x03c0),
- WRITE_COEF(0x1a, 0x01c1),
- WRITE_COEF(0x1b, 0x0202),
- WRITE_COEF(0x43, 0x3005),
- {}
- };
-
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
- snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
- break;
- case HDA_FIXUP_ACT_INIT:
- alc_process_coef_fw(codec, gb_x570_coefs);
- break;
- }
-}
-
-static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- static const hda_nid_t conn1[] = { 0x0c };
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
-
- alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
- /* We therefore want to make sure 0x14 (front headphone) and
- * 0x1b (speakers) use the stereo DAC 0x02
- */
- snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
- snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
-}
-
-static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action);
-
-static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- alc1220_fixup_clevo_p950(codec, fix, action);
- alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
-}
-
-static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- struct alc_spec *spec = codec->spec;
- unsigned int vref;
-
- snd_hda_gen_hp_automute(codec, jack);
-
- if (spec->gen.hp_jack_present)
- vref = AC_PINCTL_VREF_80;
- else
- vref = AC_PINCTL_VREF_HIZ;
- snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
-}
-
-static void alc887_fixup_asus_jack(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- if (action != HDA_FIXUP_ACT_PROBE)
- return;
- snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
- spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
-}
-
-static const struct hda_fixup alc882_fixups[] = {
- [ALC882_FIXUP_ABIT_AW9D_MAX] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x01080104 }, /* side */
- { 0x16, 0x01011012 }, /* rear */
- { 0x17, 0x01016011 }, /* clfe */
- { }
- }
- },
- [ALC882_FIXUP_LENOVO_Y530] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x99130112 }, /* rear int speakers */
- { 0x16, 0x99130111 }, /* subwoofer */
- { }
- }
- },
- [ALC882_FIXUP_PB_M5210] = {
- .type = HDA_FIXUP_PINCTLS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, PIN_VREF50 },
- {}
- }
- },
- [ALC882_FIXUP_ACER_ASPIRE_7736] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_sku_ignore,
- },
- [ALC882_FIXUP_ASUS_W90V] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x16, 0x99130110 }, /* fix sequence for CLFE */
- { }
- }
- },
- [ALC889_FIXUP_CD] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1c, 0x993301f0 }, /* CD */
- { }
- }
- },
- [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
- { }
- },
- .chained = true,
- .chain_id = ALC889_FIXUP_CD,
- },
- [ALC889_FIXUP_VAIO_TT] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x17, 0x90170111 }, /* hidden surround speaker */
- { }
- }
- },
- [ALC888_FIXUP_EEE1601] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 },
- { }
- }
- },
- [ALC886_FIXUP_EAPD] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* change to EAPD mode */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
- { }
- }
- },
- [ALC882_FIXUP_EAPD] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* change to EAPD mode */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
- { }
- }
- },
- [ALC883_FIXUP_EAPD] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* change to EAPD mode */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
- { }
- }
- },
- [ALC883_FIXUP_ACER_EAPD] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* eanable EAPD on Acer laptops */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
- { }
- }
- },
- [ALC882_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio1,
- },
- [ALC882_FIXUP_GPIO2] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio2,
- },
- [ALC882_FIXUP_GPIO3] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio3,
- },
- [ALC882_FIXUP_ASUS_W2JC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_gpio1,
- .chained = true,
- .chain_id = ALC882_FIXUP_EAPD,
- },
- [ALC889_FIXUP_COEF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_coef,
- },
- [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x16, 0x99130111 }, /* CLFE speaker */
- { 0x17, 0x99130112 }, /* surround speaker */
- { }
- },
- .chained = true,
- .chain_id = ALC882_FIXUP_GPIO1,
- },
- [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x16, 0x99130111 }, /* CLFE speaker */
- { 0x1b, 0x99130112 }, /* surround speaker */
- { }
- },
- .chained = true,
- .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
- },
- [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
- /* additional init verbs for Acer Aspire 8930G */
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* Enable all DACs */
- /* DAC DISABLE/MUTE 1? */
- /* setting bits 1-5 disables DAC nids 0x02-0x06
- * apparently. Init=0x38 */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
- /* DAC DISABLE/MUTE 2? */
- /* some bit here disables the other DACs.
- * Init=0x4900 */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
- /* DMIC fix
- * This laptop has a stereo digital microphone.
- * The mics are only 1cm apart which makes the stereo
- * useless. However, either the mic or the ALC889
- * makes the signal become a difference/sum signal
- * instead of standard stereo, which is annoying.
- * So instead we flip this bit which makes the
- * codec replicate the sum signal to both channels,
- * turning it into a normal mono mic.
- */
- /* DMIC_CONTROL? Init value = 0x0001 */
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
- { }
- },
- .chained = true,
- .chain_id = ALC882_FIXUP_GPIO1,
- },
- [ALC885_FIXUP_MACPRO_GPIO] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc885_fixup_macpro_gpio,
- },
- [ALC889_FIXUP_DAC_ROUTE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_dac_route,
- },
- [ALC889_FIXUP_MBP_VREF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_mbp_vref,
- .chained = true,
- .chain_id = ALC882_FIXUP_GPIO1,
- },
- [ALC889_FIXUP_IMAC91_VREF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_imac91_vref,
- .chained = true,
- .chain_id = ALC882_FIXUP_GPIO1,
- },
- [ALC889_FIXUP_MBA11_VREF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_mba11_vref,
- .chained = true,
- .chain_id = ALC889_FIXUP_MBP_VREF,
- },
- [ALC889_FIXUP_MBA21_VREF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_mba21_vref,
- .chained = true,
- .chain_id = ALC889_FIXUP_MBP_VREF,
- },
- [ALC889_FIXUP_MP11_VREF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_mba11_vref,
- .chained = true,
- .chain_id = ALC885_FIXUP_MACPRO_GPIO,
- },
- [ALC889_FIXUP_MP41_VREF] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc889_fixup_mbp_vref,
- .chained = true,
- .chain_id = ALC885_FIXUP_MACPRO_GPIO,
- },
- [ALC882_FIXUP_INV_DMIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_inv_dmic,
- },
- [ALC882_FIXUP_NO_PRIMARY_HP] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc882_fixup_no_primary_hp,
- },
- [ALC887_FIXUP_ASUS_BASS] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- {0x16, 0x99130130}, /* bass speaker */
- {}
- },
- .chained = true,
- .chain_id = ALC887_FIXUP_BASS_CHMAP,
- },
- [ALC887_FIXUP_BASS_CHMAP] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_bass_chmap,
- },
- [ALC1220_FIXUP_GB_DUAL_CODECS] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc1220_fixup_gb_dual_codecs,
- },
- [ALC1220_FIXUP_GB_X570] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc1220_fixup_gb_x570,
- },
- [ALC1220_FIXUP_CLEVO_P950] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc1220_fixup_clevo_p950,
- },
- [ALC1220_FIXUP_CLEVO_PB51ED] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc1220_fixup_clevo_pb51ed,
- },
- [ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
- {}
- },
- .chained = true,
- .chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
- },
- [ALC887_FIXUP_ASUS_AUDIO] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
- { 0x19, 0x22219420 },
- {}
- },
- },
- [ALC887_FIXUP_ASUS_HMIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc887_fixup_asus_jack,
- .chained = true,
- .chain_id = ALC887_FIXUP_ASUS_AUDIO,
- },
- [ALCS1200A_FIXUP_MIC_VREF] = {
- .type = HDA_FIXUP_PINCTLS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x18, PIN_VREF50 }, /* rear mic */
- { 0x19, PIN_VREF50 }, /* front mic */
- {}
- }
- },
-};
-
-static const struct snd_pci_quirk alc882_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
- SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
- ALC882_FIXUP_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
- ALC882_FIXUP_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
- ALC882_FIXUP_ACER_ASPIRE_8930G),
- SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
- ALC882_FIXUP_ACER_ASPIRE_8930G),
- SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
- ALC882_FIXUP_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
- SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
- ALC882_FIXUP_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
- ALC882_FIXUP_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
- ALC882_FIXUP_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
- SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
- SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
- SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
- SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
- SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
- SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
- SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
- SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
- SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
- SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
- SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
- SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
- SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
- SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
- SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
-
- /* All Apple entries are in codec SSIDs */
- SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
- SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
- SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
- SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
- SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
- SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
- SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
- SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
- SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
- SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
- SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
- SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
- SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
- SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
- SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
-
- SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
- SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
- SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
- SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
- SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
- SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
- SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
- SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
- SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
- SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
- SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
- SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
- SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
- SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
- SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
- SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
- SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
- SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
- {}
-};
-
-static const struct hda_model_fixup alc882_fixup_models[] = {
- {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
- {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
- {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
- {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
- {.id = ALC889_FIXUP_CD, .name = "cd"},
- {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
- {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
- {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
- {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
- {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
- {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
- {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
- {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
- {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
- {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
- {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
- {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
- {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
- {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
- {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
- {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
- {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
- {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
- {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
- {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
- {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
- {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
- {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
- {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
- {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
- {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
- {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
- {}
-};
-
-static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
- SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
- {0x14, 0x01014010},
- {0x15, 0x01011012},
- {0x16, 0x01016011},
- {0x18, 0x01a19040},
- {0x19, 0x02a19050},
- {0x1a, 0x0181304f},
- {0x1b, 0x0221401f},
- {0x1e, 0x01456130}),
- SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
- {0x14, 0x01015010},
- {0x15, 0x01011012},
- {0x16, 0x01011011},
- {0x18, 0x01a11040},
- {0x19, 0x02a19050},
- {0x1a, 0x0181104f},
- {0x1b, 0x0221401f},
- {0x1e, 0x01451130}),
- {}
-};
-
-/*
- * BIOS auto configuration
- */
-/* almost identical with ALC880 parser... */
-static int alc882_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
- static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
- return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
-}
-
-/*
- */
-static int patch_alc882(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x0b);
- if (err < 0)
- return err;
-
- spec = codec->spec;
-
- switch (codec->core.vendor_id) {
- case 0x10ec0882:
- case 0x10ec0885:
- case 0x10ec0900:
- case 0x10ec0b00:
- case 0x10ec1220:
- break;
- default:
- /* ALC883 and variants */
- alc_fix_pll_init(codec, 0x20, 0x0a, 10);
- break;
- }
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
- alc882_fixups);
- snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- alc_auto_parse_customize_define(codec);
-
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x01;
-
- /* automatic parse from the BIOS config */
- err = alc882_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog && spec->gen.beep_nid) {
- err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-
-/*
- * ALC262 support
- */
-static int alc262_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
- static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
- return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
-}
-
-/*
- * Pin config fixes
- */
-enum {
- ALC262_FIXUP_FSC_H270,
- ALC262_FIXUP_FSC_S7110,
- ALC262_FIXUP_HP_Z200,
- ALC262_FIXUP_TYAN,
- ALC262_FIXUP_LENOVO_3000,
- ALC262_FIXUP_BENQ,
- ALC262_FIXUP_BENQ_T31,
- ALC262_FIXUP_INV_DMIC,
- ALC262_FIXUP_INTEL_BAYLEYBAY,
-};
-
-static const struct hda_fixup alc262_fixups[] = {
- [ALC262_FIXUP_FSC_H270] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x15, 0x0221142f }, /* front HP */
- { 0x1b, 0x0121141f }, /* rear HP */
- { }
- }
- },
- [ALC262_FIXUP_FSC_S7110] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x90170110 }, /* speaker */
- { }
- },
- .chained = true,
- .chain_id = ALC262_FIXUP_BENQ,
- },
- [ALC262_FIXUP_HP_Z200] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x16, 0x99130120 }, /* internal speaker */
- { }
- }
- },
- [ALC262_FIXUP_TYAN] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x1993e1f0 }, /* int AUX */
- { }
- }
- },
- [ALC262_FIXUP_LENOVO_3000] = {
- .type = HDA_FIXUP_PINCTLS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, PIN_VREF50 },
- {}
- },
- .chained = true,
- .chain_id = ALC262_FIXUP_BENQ,
- },
- [ALC262_FIXUP_BENQ] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
- {}
- }
- },
- [ALC262_FIXUP_BENQ_T31] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
- {}
- }
- },
- [ALC262_FIXUP_INV_DMIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_inv_dmic,
- },
- [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_no_depop_delay,
- },
-};
-
-static const struct snd_pci_quirk alc262_fixup_tbl[] = {
- SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
- SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
- SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
- SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
- SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
- SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
- SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
- SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
- SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
- SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
- {}
-};
-
-static const struct hda_model_fixup alc262_fixup_models[] = {
- {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
- {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
- {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
- {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
- {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
- {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
- {.id = ALC262_FIXUP_BENQ, .name = "benq"},
- {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
- {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
- {}
-};
-
-/*
- */
-static int patch_alc262(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x0b);
- if (err < 0)
- return err;
-
- spec = codec->spec;
- spec->gen.shared_mic_vref_pin = 0x18;
-
- spec->shutup = alc_eapd_shutup;
-
-#if 0
- /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
- * under-run
- */
- alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
-#endif
- alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
- alc262_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- alc_auto_parse_customize_define(codec);
-
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x01;
-
- /* automatic parse from the BIOS config */
- err = alc262_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog && spec->gen.beep_nid) {
- err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-/*
- * ALC268
- */
-/* bind Beep switches of both NID 0x0f and 0x10 */
-static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned long pval;
- int err;
-
- mutex_lock(&codec->control_mutex);
- pval = kcontrol->private_value;
- kcontrol->private_value = (pval & ~0xff) | 0x0f;
- err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
- if (err >= 0) {
- kcontrol->private_value = (pval & ~0xff) | 0x10;
- err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
- }
- kcontrol->private_value = pval;
- mutex_unlock(&codec->control_mutex);
- return err;
-}
-
-static const struct snd_kcontrol_new alc268_beep_mixer[] = {
- HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Beep Playback Switch",
- .subdevice = HDA_SUBDEV_AMP_FLAG,
- .info = snd_hda_mixer_amp_switch_info,
- .get = snd_hda_mixer_amp_switch_get,
- .put = alc268_beep_switch_put,
- .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
- },
-};
-
-/* set PCBEEP vol = 0, mute connections */
-static const struct hda_verb alc268_beep_init_verbs[] = {
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- { }
-};
-
-enum {
- ALC268_FIXUP_INV_DMIC,
- ALC268_FIXUP_HP_EAPD,
- ALC268_FIXUP_SPDIF,
-};
-
-static const struct hda_fixup alc268_fixups[] = {
- [ALC268_FIXUP_INV_DMIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_inv_dmic,
- },
- [ALC268_FIXUP_HP_EAPD] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
- {}
- }
- },
- [ALC268_FIXUP_SPDIF] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1e, 0x014b1180 }, /* enable SPDIF out */
- {}
- }
- },
-};
-
-static const struct hda_model_fixup alc268_fixup_models[] = {
- {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
- {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
- {.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
- {}
-};
-
-static const struct snd_pci_quirk alc268_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
- SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
- /* below is codec SSID since multiple Toshiba laptops have the
- * same PCI SSID 1179:ff00
- */
- SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
- {}
-};
-
-/*
- * BIOS auto configuration
- */
-static int alc268_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
- return alc_parse_auto_config(codec, NULL, alc268_ssids);
-}
-
-/*
- */
-static int patch_alc268(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int i, err;
-
- /* ALC268 has no aa-loopback mixer */
- err = alc_alloc_spec(codec, 0);
- if (err < 0)
- return err;
-
- spec = codec->spec;
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x01;
-
- spec->shutup = alc_eapd_shutup;
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- /* automatic parse from the BIOS config */
- err = alc268_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (err > 0 && !spec->gen.no_analog &&
- spec->gen.autocfg.speaker_pins[0] != 0x1d) {
- for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
- if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
- &alc268_beep_mixer[i])) {
- err = -ENOMEM;
- goto error;
- }
- }
- snd_hda_add_verbs(codec, alc268_beep_init_verbs);
- if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
- /* override the amp caps for beep generator */
- snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
- (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
- (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
- (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
- (0 << AC_AMPCAP_MUTE_SHIFT));
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-/*
- * ALC269
- */
-
static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
};
@@ -3254,6 +142,7 @@ static void alc_disable_headset_jack_key(struct hda_codec *codec)
case 0x10ec0230:
case 0x10ec0236:
case 0x10ec0256:
+ case 0x10ec0257:
case 0x19e58326:
alc_write_coef_idx(codec, 0x48, 0x0);
alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
@@ -3283,6 +172,7 @@ static void alc_enable_headset_jack_key(struct hda_codec *codec)
case 0x10ec0230:
case 0x10ec0236:
case 0x10ec0256:
+ case 0x10ec0257:
case 0x19e58326:
alc_write_coef_idx(codec, 0x48, 0xd011);
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
@@ -3583,25 +473,22 @@ static void alc256_init(struct hda_codec *codec)
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
- if (hp_pin_sense)
+ if (hp_pin_sense) {
msleep(2);
+ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
- alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp_pin_sense || spec->ultra_low_power)
- msleep(85);
-
- snd_hda_codec_write(codec, hp_pin, 0,
+ snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- if (hp_pin_sense || spec->ultra_low_power)
- msleep(100);
+ msleep(75);
+
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ msleep(75);
+ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+ }
alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
- alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
/*
@@ -3622,32 +509,32 @@ static void alc256_shutup(struct hda_codec *codec)
if (!hp_pin)
hp_pin = 0x21;
- hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
- if (hp_pin_sense)
- msleep(2);
-
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp_pin_sense || spec->ultra_low_power)
- msleep(85);
+ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
/* 3k pull low control for Headset jack. */
/* NOTE: call this before clearing the pin, otherwise codec stalls */
/* If disable 3k pulldown control for alc257, the Mic detection will not work correctly
* when booting with headset plugged. So skip setting it for the codec alc257
*/
- if (codec->core.vendor_id != 0x10ec0236 &&
- codec->core.vendor_id != 0x10ec0257)
+ if (spec->en_3kpull_low)
alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
- if (!spec->no_shutup_pins)
+ hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+ if (hp_pin_sense) {
+ msleep(2);
+
snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ msleep(75);
+
+ if (!spec->no_shutup_pins)
+ snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
- if (hp_pin_sense || spec->ultra_low_power)
- msleep(100);
+ msleep(75);
+ }
alc_auto_setup_eapd(codec, false);
alc_shutup_pins(codec);
@@ -3669,6 +556,7 @@ static void alc285_hp_init(struct hda_codec *codec)
int i, val;
int coef38, coef0d, coef36;
+ alc_write_coefex_idx(codec, 0x58, 0x00, 0x1888); /* write default value */
alc_update_coef_idx(codec, 0x4a, 1<<15, 1<<15); /* Reset HP JD */
coef38 = alc_read_coef_idx(codec, 0x38); /* Amp control */
coef0d = alc_read_coef_idx(codec, 0x0d); /* Digital Misc control */
@@ -3741,33 +629,29 @@ static void alc225_init(struct hda_codec *codec)
hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
hp2_pin_sense = snd_hda_jack_detect(codec, 0x16);
- if (hp1_pin_sense || hp2_pin_sense)
+ if (hp1_pin_sense || hp2_pin_sense) {
msleep(2);
+ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+
+ 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, 0x16, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ msleep(75);
- alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-
- if (hp1_pin_sense || spec->ultra_low_power)
- 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, 0x16, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
- msleep(85);
-
- if (hp1_pin_sense || spec->ultra_low_power)
- 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, 0x16, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-
- if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
- msleep(100);
+ 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, 0x16, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
- alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+ msleep(75);
+ alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
+ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+ }
}
static void alc225_shutup(struct hda_codec *codec)
@@ -3779,36 +663,35 @@ static void alc225_shutup(struct hda_codec *codec)
if (!hp_pin)
hp_pin = 0x21;
- alc_disable_headset_jack_key(codec);
- /* 3k pull low control for Headset jack. */
- alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
-
hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
hp2_pin_sense = snd_hda_jack_detect(codec, 0x16);
- if (hp1_pin_sense || hp2_pin_sense)
+ if (hp1_pin_sense || hp2_pin_sense) {
+ alc_disable_headset_jack_key(codec);
+ /* 3k pull low control for Headset jack. */
+ alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
msleep(2);
- if (hp1_pin_sense || spec->ultra_low_power)
- 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, 0x16, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
- msleep(85);
+ 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, 0x16, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- if (hp1_pin_sense || spec->ultra_low_power)
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
- if (hp2_pin_sense)
- snd_hda_codec_write(codec, 0x16, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ msleep(75);
- if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
- msleep(100);
+ 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, 0x16, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ msleep(75);
+ alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
+ alc_enable_headset_jack_key(codec);
+ }
alc_auto_setup_eapd(codec, false);
alc_shutup_pins(codec);
if (spec->ultra_low_power) {
@@ -3819,9 +702,79 @@ static void alc225_shutup(struct hda_codec *codec)
alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4);
msleep(30);
}
+}
- alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
- alc_enable_headset_jack_key(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)
@@ -3837,20 +790,18 @@ static void alc_default_init(struct hda_codec *codec)
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
- if (hp_pin_sense)
+ if (hp_pin_sense) {
msleep(2);
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp_pin_sense)
- msleep(85);
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ msleep(75);
- if (hp_pin_sense)
- msleep(100);
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ msleep(75);
+ }
}
static void alc_default_shutup(struct hda_codec *codec)
@@ -3866,22 +817,20 @@ static void alc_default_shutup(struct hda_codec *codec)
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
- if (hp_pin_sense)
+ if (hp_pin_sense) {
msleep(2);
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp_pin_sense)
- msleep(85);
-
- if (!spec->no_shutup_pins)
snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- if (hp_pin_sense)
- msleep(100);
+ msleep(75);
+ if (!spec->no_shutup_pins)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+ msleep(75);
+ }
alc_auto_setup_eapd(codec, false);
alc_shutup_pins(codec);
}
@@ -3923,8 +872,7 @@ static void alc294_init(struct hda_codec *codec)
struct alc_spec *spec = codec->spec;
/* required only at boot or S4 resume time */
- if (!spec->done_hp_init ||
- codec->core.dev.power.power_state.event == PM_EVENT_RESTORE) {
+ if (!spec->done_hp_init || is_s4_resume(codec)) {
alc294_hp_init(codec);
spec->done_hp_init = true;
}
@@ -4023,7 +971,6 @@ static void alc5505_dsp_init(struct hda_codec *codec)
#define alc5505_dsp_resume(codec) alc5505_dsp_back_from_halt(codec)
#endif
-#ifdef CONFIG_PM
static int alc269_suspend(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -4045,7 +992,7 @@ static int alc269_resume(struct hda_codec *codec)
msleep(150);
}
- codec->patch_ops.init(codec);
+ snd_hda_codec_init(codec);
if (spec->codec_variant == ALC269_TYPE_ALC269VB)
alc269vb_toggle_power_output(codec, 1);
@@ -4069,7 +1016,6 @@ static int alc269_resume(struct hda_codec *codec)
return 0;
}
-#endif /* CONFIG_PM */
static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -4100,15 +1046,6 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
alc_update_coef_idx(codec, 0x1e, 0, 0x80);
}
-static void alc269_fixup_headset_mic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-}
-
static void alc271_fixup_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4286,9 +1223,8 @@ static void alc_update_vref_led(struct hda_codec *codec, hda_nid_t pin,
pinval &= ~AC_PINCTL_VREFEN;
pinval |= on ? AC_PINCTL_VREF_80 : AC_PINCTL_VREF_HIZ;
/* temporarily power up/down for setting VREF */
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power_pm, pm)(codec);
snd_hda_set_pin_ctl_cache(codec, pin, pinval);
- snd_hda_power_down_pm(codec);
}
/* update mute-LED according to the speaker mute state via mic VREF pin */
@@ -4379,61 +1315,6 @@ static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
}
-/* update LED status via GPIO */
-static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
- int polarity, bool enabled)
-{
- if (polarity)
- enabled = !enabled;
- alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
-}
-
-/* turn on/off mute LED via GPIO per vmaster hook */
-static int gpio_mute_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
- struct alc_spec *spec = codec->spec;
-
- alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
- spec->mute_led_polarity, !brightness);
- return 0;
-}
-
-/* turn on/off mic-mute LED via GPIO per capture hook */
-static int micmute_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
- struct alc_spec *spec = codec->spec;
-
- alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
- spec->micmute_led_polarity, !brightness);
- return 0;
-}
-
-/* setup mute and mic-mute GPIO bits, add hooks appropriately */
-static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
- int action,
- unsigned int mute_mask,
- unsigned int micmute_mask)
-{
- struct alc_spec *spec = codec->spec;
-
- alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- if (mute_mask) {
- spec->gpio_mute_led_mask = mute_mask;
- snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
- }
- if (micmute_mask) {
- spec->gpio_mic_led_mask = micmute_mask;
- snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
- }
-}
-
static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4623,6 +1504,53 @@ static void alc236_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
}
}
+static void alc236_fixup_hp_mute_led_coefbit2(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 = 0x07;
+ spec->mute_led_coef.mask = 1;
+ spec->mute_led_coef.on = 1;
+ spec->mute_led_coef.off = 0;
+ snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+ }
+}
+
+static void alc245_fixup_hp_mute_led_coefbit(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 = 0x0b;
+ spec->mute_led_coef.mask = 3 << 2;
+ spec->mute_led_coef.on = 2 << 2;
+ spec->mute_led_coef.off = 1 << 2;
+ snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+ }
+}
+
+static void alc245_fixup_hp_mute_led_v1_coefbit(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 = 0x0b;
+ spec->mute_led_coef.mask = 3 << 2;
+ spec->mute_led_coef.on = 1 << 3;
+ spec->mute_led_coef.off = 0;
+ snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+ }
+}
+
/* turn on/off mic-mute LED per capture hook by coef bit */
static int coef_micmute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
@@ -4673,6 +1601,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)
{
@@ -4755,7 +1698,134 @@ static void alc298_fixup_samsung_amp(struct hda_codec *codec,
}
}
-#if IS_REACHABLE(CONFIG_INPUT)
+struct alc298_samsung_v2_amp_desc {
+ unsigned short nid;
+ int init_seq_size;
+ unsigned short init_seq[18][2];
+};
+
+static const struct alc298_samsung_v2_amp_desc
+alc298_samsung_v2_amp_desc_tbl[] = {
+ { 0x38, 18, {
+ { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+ { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe },
+ { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+ { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+ { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 },
+ { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 }
+ }},
+ { 0x39, 18, {
+ { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+ { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd },
+ { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+ { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+ { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 },
+ { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 }
+ }},
+ { 0x3c, 15, {
+ { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+ { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe },
+ { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+ { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+ { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d }
+ }},
+ { 0x3d, 15, {
+ { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+ { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd },
+ { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+ { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+ { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d }
+ }}
+};
+
+static void alc298_samsung_v2_enable_amps(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ static const unsigned short enable_seq[][2] = {
+ { 0x203a, 0x0081 }, { 0x23ff, 0x0001 },
+ };
+ int i, j;
+
+ for (i = 0; i < spec->num_speaker_amps; i++) {
+ alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
+ for (j = 0; j < ARRAY_SIZE(enable_seq); j++)
+ alc298_samsung_write_coef_pack(codec, enable_seq[j]);
+ codec_dbg(codec, "alc298_samsung_v2: Enabled speaker amp 0x%02x\n",
+ alc298_samsung_v2_amp_desc_tbl[i].nid);
+ }
+}
+
+static void alc298_samsung_v2_disable_amps(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ static const unsigned short disable_seq[][2] = {
+ { 0x23ff, 0x0000 }, { 0x203a, 0x0080 },
+ };
+ int i, j;
+
+ for (i = 0; i < spec->num_speaker_amps; i++) {
+ alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
+ for (j = 0; j < ARRAY_SIZE(disable_seq); j++)
+ alc298_samsung_write_coef_pack(codec, disable_seq[j]);
+ codec_dbg(codec, "alc298_samsung_v2: Disabled speaker amp 0x%02x\n",
+ alc298_samsung_v2_amp_desc_tbl[i].nid);
+ }
+}
+
+static void alc298_samsung_v2_playback_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
+{
+ /* Dynamically enable/disable speaker amps before and after playback */
+ if (action == HDA_GEN_PCM_ACT_OPEN)
+ alc298_samsung_v2_enable_amps(codec);
+ if (action == HDA_GEN_PCM_ACT_CLOSE)
+ alc298_samsung_v2_disable_amps(codec);
+}
+
+static void alc298_samsung_v2_init_amps(struct hda_codec *codec,
+ int num_speaker_amps)
+{
+ struct alc_spec *spec = codec->spec;
+ int i, j;
+
+ /* Set spec's num_speaker_amps before doing anything else */
+ spec->num_speaker_amps = num_speaker_amps;
+
+ /* Disable speaker amps before init to prevent any physical damage */
+ alc298_samsung_v2_disable_amps(codec);
+
+ /* Initialize the speaker amps */
+ for (i = 0; i < spec->num_speaker_amps; i++) {
+ alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
+ for (j = 0; j < alc298_samsung_v2_amp_desc_tbl[i].init_seq_size; j++) {
+ alc298_samsung_write_coef_pack(codec,
+ alc298_samsung_v2_amp_desc_tbl[i].init_seq[j]);
+ }
+ alc_write_coef_idx(codec, 0x89, 0x0);
+ codec_dbg(codec, "alc298_samsung_v2: Initialized speaker amp 0x%02x\n",
+ alc298_samsung_v2_amp_desc_tbl[i].nid);
+ }
+
+ /* register hook to enable speaker amps only when they are needed */
+ spec->gen.pcm_playback_hook = alc298_samsung_v2_playback_hook;
+}
+
+static void alc298_fixup_samsung_amp_v2_2_amps(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PROBE)
+ alc298_samsung_v2_init_amps(codec, 2);
+}
+
+static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PROBE)
+ alc298_samsung_v2_init_amps(codec, 4);
+}
+
static void gpio2_mic_hotkey_event(struct hda_codec *codec,
struct hda_jack_callback *event)
{
@@ -4864,10 +1934,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)
@@ -4881,957 +1947,14 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
}
}
-static const struct coef_fw alc225_pre_hsmode[] = {
- UPDATE_COEF(0x4a, 1<<8, 0),
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
- UPDATE_COEF(0x63, 3<<14, 3<<14),
- UPDATE_COEF(0x4a, 3<<4, 2<<4),
- UPDATE_COEF(0x4a, 3<<10, 3<<10),
- UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
- UPDATE_COEF(0x4a, 3<<10, 0),
- {}
-};
-
-static void alc_headset_mode_unplugged(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- static const struct coef_fw coef0255[] = {
- WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
- WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
- WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
- WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
- {}
- };
- static const struct coef_fw coef0256[] = {
- WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
- WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
- WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
- WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
- {}
- };
- static const struct coef_fw coef0233[] = {
- WRITE_COEF(0x1b, 0x0c0b),
- WRITE_COEF(0x45, 0xc429),
- UPDATE_COEF(0x35, 0x4000, 0),
- WRITE_COEF(0x06, 0x2104),
- WRITE_COEF(0x1a, 0x0001),
- WRITE_COEF(0x26, 0x0004),
- WRITE_COEF(0x32, 0x42a3),
- {}
- };
- static const struct coef_fw coef0288[] = {
- UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
- UPDATE_COEF(0x50, 0x2000, 0x2000),
- UPDATE_COEF(0x56, 0x0006, 0x0006),
- UPDATE_COEF(0x66, 0x0008, 0),
- UPDATE_COEF(0x67, 0x2000, 0),
- {}
- };
- static const struct coef_fw coef0298[] = {
- UPDATE_COEF(0x19, 0x1300, 0x0300),
- {}
- };
- static const struct coef_fw coef0292[] = {
- WRITE_COEF(0x76, 0x000e),
- WRITE_COEF(0x6c, 0x2400),
- WRITE_COEF(0x18, 0x7308),
- WRITE_COEF(0x6b, 0xc429),
- {}
- };
- static const struct coef_fw coef0293[] = {
- UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
- UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
- UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
- UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
- WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
- UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
- {}
- };
- static const struct coef_fw coef0668[] = {
- WRITE_COEF(0x15, 0x0d40),
- WRITE_COEF(0xb7, 0x802b),
- {}
- };
- static const struct coef_fw coef0225[] = {
- UPDATE_COEF(0x63, 3<<14, 0),
- {}
- };
- static const struct coef_fw coef0274[] = {
- UPDATE_COEF(0x4a, 0x0100, 0),
- UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
- UPDATE_COEF(0x6b, 0xf000, 0x5000),
- UPDATE_COEF(0x4a, 0x0010, 0),
- UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
- WRITE_COEF(0x45, 0x5289),
- UPDATE_COEF(0x4a, 0x0c00, 0),
- {}
- };
-
- if (spec->no_internal_mic_pin) {
- alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
- return;
- }
-
- switch (codec->core.vendor_id) {
- case 0x10ec0255:
- alc_process_coef_fw(codec, coef0255);
- break;
- case 0x10ec0230:
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- alc_process_coef_fw(codec, coef0256);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- alc_process_coef_fw(codec, coef0274);
- break;
- case 0x10ec0233:
- case 0x10ec0283:
- alc_process_coef_fw(codec, coef0233);
- break;
- case 0x10ec0286:
- case 0x10ec0288:
- alc_process_coef_fw(codec, coef0288);
- break;
- case 0x10ec0298:
- alc_process_coef_fw(codec, coef0298);
- alc_process_coef_fw(codec, coef0288);
- break;
- case 0x10ec0292:
- alc_process_coef_fw(codec, coef0292);
- break;
- case 0x10ec0293:
- alc_process_coef_fw(codec, coef0293);
- break;
- case 0x10ec0668:
- alc_process_coef_fw(codec, coef0668);
- break;
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- alc_process_coef_fw(codec, alc225_pre_hsmode);
- alc_process_coef_fw(codec, coef0225);
- break;
- case 0x10ec0867:
- alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
- break;
- }
- codec_dbg(codec, "Headset jack set to unplugged mode.\n");
-}
-
-
-static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
- hda_nid_t mic_pin)
-{
- static const struct coef_fw coef0255[] = {
- WRITE_COEFEX(0x57, 0x03, 0x8aa6),
- WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
- {}
- };
- static const struct coef_fw coef0256[] = {
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
- WRITE_COEFEX(0x57, 0x03, 0x09a3),
- WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
- {}
- };
- static const struct coef_fw coef0233[] = {
- UPDATE_COEF(0x35, 0, 1<<14),
- WRITE_COEF(0x06, 0x2100),
- WRITE_COEF(0x1a, 0x0021),
- WRITE_COEF(0x26, 0x008c),
- {}
- };
- static const struct coef_fw coef0288[] = {
- UPDATE_COEF(0x4f, 0x00c0, 0),
- UPDATE_COEF(0x50, 0x2000, 0),
- UPDATE_COEF(0x56, 0x0006, 0),
- UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
- UPDATE_COEF(0x66, 0x0008, 0x0008),
- UPDATE_COEF(0x67, 0x2000, 0x2000),
- {}
- };
- static const struct coef_fw coef0292[] = {
- WRITE_COEF(0x19, 0xa208),
- WRITE_COEF(0x2e, 0xacf0),
- {}
- };
- static const struct coef_fw coef0293[] = {
- UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
- UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
- UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
- {}
- };
- static const struct coef_fw coef0688[] = {
- WRITE_COEF(0xb7, 0x802b),
- WRITE_COEF(0xb5, 0x1040),
- UPDATE_COEF(0xc3, 0, 1<<12),
- {}
- };
- static const struct coef_fw coef0225[] = {
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
- UPDATE_COEF(0x4a, 3<<4, 2<<4),
- UPDATE_COEF(0x63, 3<<14, 0),
- {}
- };
- static const struct coef_fw coef0274[] = {
- UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
- UPDATE_COEF(0x4a, 0x0010, 0),
- UPDATE_COEF(0x6b, 0xf000, 0),
- {}
- };
-
- switch (codec->core.vendor_id) {
- case 0x10ec0255:
- alc_write_coef_idx(codec, 0x45, 0xc489);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0255);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0230:
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- alc_write_coef_idx(codec, 0x45, 0xc489);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0256);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- alc_write_coef_idx(codec, 0x45, 0x4689);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0274);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0233:
- case 0x10ec0283:
- alc_write_coef_idx(codec, 0x45, 0xc429);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0233);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0286:
- case 0x10ec0288:
- case 0x10ec0298:
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0288);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0292:
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0292);
- break;
- case 0x10ec0293:
- /* Set to TRS mode */
- alc_write_coef_idx(codec, 0x45, 0xc429);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0293);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0867:
- alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
- fallthrough;
- case 0x10ec0221:
- case 0x10ec0662:
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0668:
- alc_write_coef_idx(codec, 0x11, 0x0001);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0688);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- alc_process_coef_fw(codec, alc225_pre_hsmode);
- alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
- snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
- alc_process_coef_fw(codec, coef0225);
- snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
- break;
- }
- codec_dbg(codec, "Headset jack set to mic-in mode.\n");
-}
-
-static void alc_headset_mode_default(struct hda_codec *codec)
-{
- static const struct coef_fw coef0225[] = {
- UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
- UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
- UPDATE_COEF(0x49, 3<<8, 0<<8),
- UPDATE_COEF(0x4a, 3<<4, 3<<4),
- UPDATE_COEF(0x63, 3<<14, 0),
- UPDATE_COEF(0x67, 0xf000, 0x3000),
- {}
- };
- static const struct coef_fw coef0255[] = {
- WRITE_COEF(0x45, 0xc089),
- WRITE_COEF(0x45, 0xc489),
- WRITE_COEFEX(0x57, 0x03, 0x8ea6),
- WRITE_COEF(0x49, 0x0049),
- {}
- };
- static const struct coef_fw coef0256[] = {
- WRITE_COEF(0x45, 0xc489),
- WRITE_COEFEX(0x57, 0x03, 0x0da3),
- WRITE_COEF(0x49, 0x0049),
- UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
- WRITE_COEF(0x06, 0x6100),
- {}
- };
- static const struct coef_fw coef0233[] = {
- WRITE_COEF(0x06, 0x2100),
- WRITE_COEF(0x32, 0x4ea3),
- {}
- };
- static const struct coef_fw coef0288[] = {
- UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
- UPDATE_COEF(0x50, 0x2000, 0x2000),
- UPDATE_COEF(0x56, 0x0006, 0x0006),
- UPDATE_COEF(0x66, 0x0008, 0),
- UPDATE_COEF(0x67, 0x2000, 0),
- {}
- };
- static const struct coef_fw coef0292[] = {
- WRITE_COEF(0x76, 0x000e),
- WRITE_COEF(0x6c, 0x2400),
- WRITE_COEF(0x6b, 0xc429),
- WRITE_COEF(0x18, 0x7308),
- {}
- };
- static const struct coef_fw coef0293[] = {
- UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
- WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
- UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
- {}
- };
- static const struct coef_fw coef0688[] = {
- WRITE_COEF(0x11, 0x0041),
- WRITE_COEF(0x15, 0x0d40),
- WRITE_COEF(0xb7, 0x802b),
- {}
- };
- static const struct coef_fw coef0274[] = {
- WRITE_COEF(0x45, 0x4289),
- UPDATE_COEF(0x4a, 0x0010, 0x0010),
- UPDATE_COEF(0x6b, 0x0f00, 0),
- UPDATE_COEF(0x49, 0x0300, 0x0300),
- {}
- };
-
- switch (codec->core.vendor_id) {
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- alc_process_coef_fw(codec, alc225_pre_hsmode);
- alc_process_coef_fw(codec, coef0225);
- break;
- case 0x10ec0255:
- alc_process_coef_fw(codec, coef0255);
- break;
- case 0x10ec0230:
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- alc_write_coef_idx(codec, 0x1b, 0x0e4b);
- alc_write_coef_idx(codec, 0x45, 0xc089);
- msleep(50);
- alc_process_coef_fw(codec, coef0256);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- alc_process_coef_fw(codec, coef0274);
- break;
- case 0x10ec0233:
- case 0x10ec0283:
- alc_process_coef_fw(codec, coef0233);
- break;
- case 0x10ec0286:
- case 0x10ec0288:
- case 0x10ec0298:
- alc_process_coef_fw(codec, coef0288);
- break;
- case 0x10ec0292:
- alc_process_coef_fw(codec, coef0292);
- break;
- case 0x10ec0293:
- alc_process_coef_fw(codec, coef0293);
- break;
- case 0x10ec0668:
- alc_process_coef_fw(codec, coef0688);
- break;
- case 0x10ec0867:
- alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
- break;
- }
- codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
-}
-
-/* Iphone type */
-static void alc_headset_mode_ctia(struct hda_codec *codec)
-{
- int val;
-
- static const struct coef_fw coef0255[] = {
- WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
- WRITE_COEF(0x1b, 0x0c2b),
- WRITE_COEFEX(0x57, 0x03, 0x8ea6),
- {}
- };
- static const struct coef_fw coef0256[] = {
- WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
- WRITE_COEF(0x1b, 0x0e6b),
- {}
- };
- static const struct coef_fw coef0233[] = {
- WRITE_COEF(0x45, 0xd429),
- WRITE_COEF(0x1b, 0x0c2b),
- WRITE_COEF(0x32, 0x4ea3),
- {}
- };
- static const struct coef_fw coef0288[] = {
- UPDATE_COEF(0x50, 0x2000, 0x2000),
- UPDATE_COEF(0x56, 0x0006, 0x0006),
- UPDATE_COEF(0x66, 0x0008, 0),
- UPDATE_COEF(0x67, 0x2000, 0),
- {}
- };
- static const struct coef_fw coef0292[] = {
- WRITE_COEF(0x6b, 0xd429),
- WRITE_COEF(0x76, 0x0008),
- WRITE_COEF(0x18, 0x7388),
- {}
- };
- static const struct coef_fw coef0293[] = {
- WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
- UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
- {}
- };
- static const struct coef_fw coef0688[] = {
- WRITE_COEF(0x11, 0x0001),
- WRITE_COEF(0x15, 0x0d60),
- WRITE_COEF(0xc3, 0x0000),
- {}
- };
- static const struct coef_fw coef0225_1[] = {
- UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
- UPDATE_COEF(0x63, 3<<14, 2<<14),
- {}
- };
- static const struct coef_fw coef0225_2[] = {
- UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
- UPDATE_COEF(0x63, 3<<14, 1<<14),
- {}
- };
-
- switch (codec->core.vendor_id) {
- case 0x10ec0255:
- alc_process_coef_fw(codec, coef0255);
- break;
- case 0x10ec0230:
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- alc_process_coef_fw(codec, coef0256);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- alc_write_coef_idx(codec, 0x45, 0xd689);
- break;
- case 0x10ec0233:
- case 0x10ec0283:
- alc_process_coef_fw(codec, coef0233);
- break;
- case 0x10ec0298:
- val = alc_read_coef_idx(codec, 0x50);
- if (val & (1 << 12)) {
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
- alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
- msleep(300);
- } else {
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
- alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
- msleep(300);
- }
- break;
- case 0x10ec0286:
- case 0x10ec0288:
- alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
- msleep(300);
- alc_process_coef_fw(codec, coef0288);
- break;
- case 0x10ec0292:
- alc_process_coef_fw(codec, coef0292);
- break;
- case 0x10ec0293:
- alc_process_coef_fw(codec, coef0293);
- break;
- case 0x10ec0668:
- alc_process_coef_fw(codec, coef0688);
- break;
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- val = alc_read_coef_idx(codec, 0x45);
- if (val & (1 << 9))
- alc_process_coef_fw(codec, coef0225_2);
- else
- alc_process_coef_fw(codec, coef0225_1);
- break;
- case 0x10ec0867:
- alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
- break;
- }
- codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
-}
-
-/* Nokia type */
-static void alc_headset_mode_omtp(struct hda_codec *codec)
-{
- static const struct coef_fw coef0255[] = {
- WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
- WRITE_COEF(0x1b, 0x0c2b),
- WRITE_COEFEX(0x57, 0x03, 0x8ea6),
- {}
- };
- static const struct coef_fw coef0256[] = {
- WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
- WRITE_COEF(0x1b, 0x0e6b),
- {}
- };
- static const struct coef_fw coef0233[] = {
- WRITE_COEF(0x45, 0xe429),
- WRITE_COEF(0x1b, 0x0c2b),
- WRITE_COEF(0x32, 0x4ea3),
- {}
- };
- static const struct coef_fw coef0288[] = {
- UPDATE_COEF(0x50, 0x2000, 0x2000),
- UPDATE_COEF(0x56, 0x0006, 0x0006),
- UPDATE_COEF(0x66, 0x0008, 0),
- UPDATE_COEF(0x67, 0x2000, 0),
- {}
- };
- static const struct coef_fw coef0292[] = {
- WRITE_COEF(0x6b, 0xe429),
- WRITE_COEF(0x76, 0x0008),
- WRITE_COEF(0x18, 0x7388),
- {}
- };
- static const struct coef_fw coef0293[] = {
- WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
- UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
- {}
- };
- static const struct coef_fw coef0688[] = {
- WRITE_COEF(0x11, 0x0001),
- WRITE_COEF(0x15, 0x0d50),
- WRITE_COEF(0xc3, 0x0000),
- {}
- };
- static const struct coef_fw coef0225[] = {
- UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
- UPDATE_COEF(0x63, 3<<14, 2<<14),
- {}
- };
-
- switch (codec->core.vendor_id) {
- case 0x10ec0255:
- alc_process_coef_fw(codec, coef0255);
- break;
- case 0x10ec0230:
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- alc_process_coef_fw(codec, coef0256);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- alc_write_coef_idx(codec, 0x45, 0xe689);
- break;
- case 0x10ec0233:
- case 0x10ec0283:
- alc_process_coef_fw(codec, coef0233);
- break;
- case 0x10ec0298:
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
- alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
- msleep(300);
- break;
- case 0x10ec0286:
- case 0x10ec0288:
- alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
- msleep(300);
- alc_process_coef_fw(codec, coef0288);
- break;
- case 0x10ec0292:
- alc_process_coef_fw(codec, coef0292);
- break;
- case 0x10ec0293:
- alc_process_coef_fw(codec, coef0293);
- break;
- case 0x10ec0668:
- alc_process_coef_fw(codec, coef0688);
- break;
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- alc_process_coef_fw(codec, coef0225);
- break;
- }
- codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
-}
-
-static void alc_determine_headset_type(struct hda_codec *codec)
-{
- int val;
- bool is_ctia = false;
- struct alc_spec *spec = codec->spec;
- static const struct coef_fw coef0255[] = {
- WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
- WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
- conteol) */
- {}
- };
- static const struct coef_fw coef0288[] = {
- UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
- {}
- };
- static const struct coef_fw coef0298[] = {
- UPDATE_COEF(0x50, 0x2000, 0x2000),
- UPDATE_COEF(0x56, 0x0006, 0x0006),
- UPDATE_COEF(0x66, 0x0008, 0),
- UPDATE_COEF(0x67, 0x2000, 0),
- UPDATE_COEF(0x19, 0x1300, 0x1300),
- {}
- };
- static const struct coef_fw coef0293[] = {
- UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
- WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
- {}
- };
- static const struct coef_fw coef0688[] = {
- WRITE_COEF(0x11, 0x0001),
- WRITE_COEF(0xb7, 0x802b),
- WRITE_COEF(0x15, 0x0d60),
- WRITE_COEF(0xc3, 0x0c00),
- {}
- };
- static const struct coef_fw coef0274[] = {
- UPDATE_COEF(0x4a, 0x0010, 0),
- UPDATE_COEF(0x4a, 0x8000, 0),
- WRITE_COEF(0x45, 0xd289),
- UPDATE_COEF(0x49, 0x0300, 0x0300),
- {}
- };
-
- if (spec->no_internal_mic_pin) {
- alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
- return;
- }
-
- switch (codec->core.vendor_id) {
- case 0x10ec0255:
- alc_process_coef_fw(codec, coef0255);
- msleep(300);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x0070) == 0x0070;
- break;
- case 0x10ec0230:
- case 0x10ec0236:
- case 0x10ec0256:
- case 0x19e58326:
- alc_write_coef_idx(codec, 0x1b, 0x0e4b);
- alc_write_coef_idx(codec, 0x06, 0x6104);
- alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
-
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- msleep(80);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
- alc_process_coef_fw(codec, coef0255);
- msleep(300);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x0070) == 0x0070;
-
- alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
- alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- msleep(80);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- break;
- case 0x10ec0234:
- case 0x10ec0274:
- case 0x10ec0294:
- alc_process_coef_fw(codec, coef0274);
- msleep(850);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x00f0) == 0x00f0;
- break;
- case 0x10ec0233:
- case 0x10ec0283:
- alc_write_coef_idx(codec, 0x45, 0xd029);
- msleep(300);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x0070) == 0x0070;
- break;
- case 0x10ec0298:
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- msleep(100);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
- msleep(200);
-
- val = alc_read_coef_idx(codec, 0x50);
- if (val & (1 << 12)) {
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
- alc_process_coef_fw(codec, coef0288);
- msleep(350);
- val = alc_read_coef_idx(codec, 0x50);
- is_ctia = (val & 0x0070) == 0x0070;
- } else {
- alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
- alc_process_coef_fw(codec, coef0288);
- msleep(350);
- val = alc_read_coef_idx(codec, 0x50);
- is_ctia = (val & 0x0070) == 0x0070;
- }
- alc_process_coef_fw(codec, coef0298);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
- msleep(75);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- break;
- case 0x10ec0286:
- case 0x10ec0288:
- alc_process_coef_fw(codec, coef0288);
- msleep(350);
- val = alc_read_coef_idx(codec, 0x50);
- is_ctia = (val & 0x0070) == 0x0070;
- break;
- case 0x10ec0292:
- alc_write_coef_idx(codec, 0x6b, 0xd429);
- msleep(300);
- val = alc_read_coef_idx(codec, 0x6c);
- is_ctia = (val & 0x001c) == 0x001c;
- break;
- case 0x10ec0293:
- alc_process_coef_fw(codec, coef0293);
- msleep(300);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x0070) == 0x0070;
- break;
- case 0x10ec0668:
- alc_process_coef_fw(codec, coef0688);
- msleep(300);
- val = alc_read_coef_idx(codec, 0xbe);
- is_ctia = (val & 0x1c02) == 0x1c02;
- break;
- case 0x10ec0215:
- case 0x10ec0225:
- case 0x10ec0285:
- case 0x10ec0295:
- case 0x10ec0289:
- case 0x10ec0299:
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- msleep(80);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
- alc_process_coef_fw(codec, alc225_pre_hsmode);
- alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
- val = alc_read_coef_idx(codec, 0x45);
- if (val & (1 << 9)) {
- alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
- alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
- msleep(800);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x00f0) == 0x00f0;
- } else {
- alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
- alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
- msleep(800);
- val = alc_read_coef_idx(codec, 0x46);
- is_ctia = (val & 0x00f0) == 0x00f0;
- }
- alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
- alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
- alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
-
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- msleep(80);
- snd_hda_codec_write(codec, 0x21, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- break;
- case 0x10ec0867:
- is_ctia = true;
- break;
- }
-
- codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
- is_ctia ? "yes" : "no");
- spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
-}
-
-static void alc_update_headset_mode(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
- hda_nid_t hp_pin = alc_get_hp_pin(spec);
-
- int new_headset_mode;
-
- if (!snd_hda_jack_detect(codec, hp_pin))
- new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
- else if (mux_pin == spec->headset_mic_pin)
- new_headset_mode = ALC_HEADSET_MODE_HEADSET;
- else if (mux_pin == spec->headphone_mic_pin)
- new_headset_mode = ALC_HEADSET_MODE_MIC;
- else
- new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
-
- if (new_headset_mode == spec->current_headset_mode) {
- snd_hda_gen_update_outputs(codec);
- return;
- }
-
- switch (new_headset_mode) {
- case ALC_HEADSET_MODE_UNPLUGGED:
- alc_headset_mode_unplugged(codec);
- spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
- spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
- spec->gen.hp_jack_present = false;
- break;
- case ALC_HEADSET_MODE_HEADSET:
- if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
- alc_determine_headset_type(codec);
- if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
- alc_headset_mode_ctia(codec);
- else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
- alc_headset_mode_omtp(codec);
- spec->gen.hp_jack_present = true;
- break;
- case ALC_HEADSET_MODE_MIC:
- alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
- spec->gen.hp_jack_present = false;
- break;
- case ALC_HEADSET_MODE_HEADPHONE:
- alc_headset_mode_default(codec);
- spec->gen.hp_jack_present = true;
- break;
- }
- if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
- snd_hda_set_pin_ctl_cache(codec, hp_pin,
- AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
- if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
- snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
- PIN_VREFHIZ);
- }
- spec->current_headset_mode = new_headset_mode;
-
- snd_hda_gen_update_outputs(codec);
-}
-
-static void alc_update_headset_mode_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- alc_update_headset_mode(codec);
-}
-
-static void alc_update_headset_jack_cb(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- snd_hda_gen_hp_automute(codec, jack);
- alc_update_headset_mode(codec);
-}
-
-static void alc_probe_headset_mode(struct hda_codec *codec)
-{
- int i;
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-
- /* Find mic pins */
- for (i = 0; i < cfg->num_inputs; i++) {
- if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
- spec->headset_mic_pin = cfg->inputs[i].pin;
- if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
- spec->headphone_mic_pin = cfg->inputs[i].pin;
- }
-
- WARN_ON(spec->gen.cap_sync_hook);
- spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
- spec->gen.automute_hook = alc_update_headset_mode;
- spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
-}
-
-static void alc_fixup_headset_mode(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;
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
- break;
- case HDA_FIXUP_ACT_PROBE:
- alc_probe_headset_mode(codec);
- break;
- case HDA_FIXUP_ACT_INIT:
- if (is_s3_resume(codec) || is_s4_resume(codec)) {
- spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
- spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
- }
- alc_update_headset_mode(codec);
- break;
- }
-}
-
-static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- struct alc_spec *spec = codec->spec;
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
- }
- else
- alc_fixup_headset_mode(codec, fix, action);
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->micmute_led_polarity = 1;
+ alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
}
static void alc255_set_default_jack_type(struct hda_codec *codec)
@@ -5883,7 +2006,7 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
alc255_set_default_jack_type(codec);
- }
+ }
else
alc_fixup_headset_mode(codec, fix, action);
}
@@ -5911,15 +2034,6 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
}
}
-static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- struct alc_spec *spec = codec->spec;
- spec->gen.auto_mute_via_amp = 1;
- }
-}
-
static void alc_fixup_no_shutup(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -5929,16 +2043,6 @@ static void alc_fixup_no_shutup(struct hda_codec *codec,
}
}
-static void alc_fixup_disable_aamix(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- struct alc_spec *spec = codec->spec;
- /* Disable AA-loopback as it causes white noise */
- spec->gen.mixer_nid = 0;
- }
-}
-
/* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */
static void alc_fixup_tpt440_dock(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -6009,94 +2113,6 @@ static void alc295_fixup_asus_dacs(struct hda_codec *codec,
spec->gen.preferred_dacs = preferred_pairs;
}
-static void alc_shutup_dell_xps13(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int hp_pin = alc_get_hp_pin(spec);
-
- /* Prevent pop noises when headphones are plugged in */
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- msleep(20);
-}
-
-static void alc_fixup_dell_xps13(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- struct hda_input_mux *imux = &spec->gen.input_mux;
- int i;
-
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
- * it causes a click noise at start up
- */
- snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
- spec->shutup = alc_shutup_dell_xps13;
- break;
- case HDA_FIXUP_ACT_PROBE:
- /* Make the internal mic the default input source. */
- for (i = 0; i < imux->num_items; i++) {
- if (spec->gen.imux_pins[i] == 0x12) {
- spec->gen.cur_mux[0] = i;
- break;
- }
- }
- break;
- }
-}
-
-static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
- spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
-
- /* Disable boost for mic-in permanently. (This code is only called
- from quirks that guarantee that the headphone is at NID 0x1b.) */
- snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
- snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
- } else
- alc_fixup_headset_mode(codec, fix, action);
-}
-
-static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- alc_write_coef_idx(codec, 0xc4, 0x8000);
- alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
- snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
- }
- alc_fixup_headset_mode(codec, fix, action);
-}
-
-/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
-static int find_ext_mic_pin(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->gen.autocfg;
- hda_nid_t nid;
- unsigned int defcfg;
- int i;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- if (cfg->inputs[i].type != AUTO_PIN_MIC)
- continue;
- nid = cfg->inputs[i].pin;
- defcfg = snd_hda_codec_get_pincfg(codec, nid);
- if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
- continue;
- return nid;
- }
-
- return 0;
-}
-
static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
const struct hda_fixup *fix,
int action)
@@ -6104,7 +2120,7 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PROBE) {
- int mic_pin = find_ext_mic_pin(codec);
+ int mic_pin = alc_find_ext_mic_pin(codec);
int hp_pin = alc_get_hp_pin(spec);
if (snd_BUG_ON(!mic_pin || !hp_pin))
@@ -6292,6 +2308,17 @@ static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec,
}
}
+/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */
+static void alc294_fixup_bass_speaker_15(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ static const hda_nid_t conn[] = { 0x02, 0x03 };
+ snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
+ snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+ }
+}
+
/* Hook to update amp GPIO4 for automute */
static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
struct hda_jack_callback *jack)
@@ -6371,30 +2398,6 @@ static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec,
}
}
-static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
- const struct hda_fixup *fix,
- int action)
-{
- alc_fixup_dual_codecs(codec, fix, action);
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- /* override card longname to provide a unique UCM profile */
- strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
- break;
- case HDA_FIXUP_ACT_BUILD:
- /* rename Capture controls depending on the codec */
- rename_ctl(codec, "Capture Volume",
- codec->addr == 0 ?
- "Rear-Panel Capture Volume" :
- "Front-Panel Capture Volume");
- rename_ctl(codec, "Capture Switch",
- codec->addr == 0 ?
- "Rear-Panel Capture Switch" :
- "Front-Panel Capture Switch");
- break;
- }
-}
-
static void alc225_fixup_s3_pop_noise(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -6422,6 +2425,25 @@ static void alc274_fixup_bind_dacs(struct hda_codec *codec,
codec->power_save_node = 0;
}
+/* avoid DAC 0x06 for speaker switch 0x17; it has no volume control */
+static void alc274_fixup_hp_aio_bind_dacs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
+ /* The speaker is routed to the Node 0x06 by a mistake, thus the
+ * speaker's volume can't be adjusted since the node doesn't have
+ * Amp-out capability. Assure the speaker and lineout pin to be
+ * coupled with DAC NID 0x02.
+ */
+ static const hda_nid_t preferred_pairs[] = {
+ 0x16, 0x02, 0x17, 0x02, 0x21, 0x03, 0
+ };
+ struct alc_spec *spec = codec->spec;
+
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ spec->gen.preferred_dacs = preferred_pairs;
+}
+
/* avoid DAC 0x06 for bass speaker 0x17; it has no volume control */
static void alc289_fixup_asus_ga401(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -6431,10 +2453,8 @@ static void alc289_fixup_asus_ga401(struct hda_codec *codec,
};
struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
spec->gen.preferred_dacs = preferred_pairs;
- spec->gen.obey_preferred_dacs = 1;
- }
}
/* The DAC of NID 0x3 will introduce click/pop noise on headphones, so invalidate it */
@@ -6463,6 +2483,7 @@ static void alc_combo_jack_hp_jd_restart(struct hda_codec *codec)
case 0x10ec0236:
case 0x10ec0255:
case 0x10ec0256:
+ case 0x10ec0257:
case 0x19e58326:
alc_update_coef_idx(codec, 0x1b, 0x8000, 1 << 15); /* Reset HP JD */
alc_update_coef_idx(codec, 0x1b, 0x8000, 0 << 15);
@@ -6485,6 +2506,23 @@ static void alc295_fixup_chromebook(struct hda_codec *codec,
}
}
+static void alc256_fixup_chromebook(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ if (codec->core.subsystem_id == 0x10280d76)
+ spec->gen.suppress_auto_mute = 0;
+ else
+ spec->gen.suppress_auto_mute = 1;
+ spec->gen.suppress_auto_mic = 1;
+ spec->en_3kpull_low = false;
+ break;
+ }
+}
+
static void alc_fixup_disable_mic_vref(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -6630,6 +2668,41 @@ static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec,
}
}
+/* GPIO1 = amplifier on/off */
+static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02 };
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x14, 0x90170110 }, /* front/high speakers */
+ { 0x17, 0x90170130 }, /* back/bass speakers */
+ { }
+ };
+
+ // enable mute led
+ alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* needed for amp of back speakers */
+ spec->gpio_mask |= 0x01;
+ spec->gpio_dir |= 0x01;
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ /* share DAC to have unified volume control */
+ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /* need to toggle GPIO to enable the amp of back speakers */
+ alc_update_gpio_data(codec, 0x01, true);
+ msleep(100);
+ alc_update_gpio_data(codec, 0x01, false);
+ break;
+ }
+}
+
static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -6648,8 +2721,86 @@ static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
}
}
+static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ static const struct coef_fw coefs[] = {
+ WRITE_COEF(0x08, 0x6a0c), WRITE_COEF(0x0d, 0xa023),
+ WRITE_COEF(0x10, 0x0320), WRITE_COEF(0x1a, 0x8c03),
+ WRITE_COEF(0x25, 0x1800), WRITE_COEF(0x26, 0x003a),
+ WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb014),
+ WRITE_COEF(0x2b, 0x1dfe), WRITE_COEF(0x37, 0xfe15),
+ WRITE_COEF(0x38, 0x7909), WRITE_COEF(0x45, 0xd489),
+ WRITE_COEF(0x46, 0x00f4), WRITE_COEF(0x4a, 0x21e0),
+ WRITE_COEF(0x66, 0x03f0), WRITE_COEF(0x67, 0x1000),
+ WRITE_COEF(0x6e, 0x1005), { }
+ };
+
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x12, 0xb7a60130 }, /* Internal microphone*/
+ { 0x14, 0x90170150 }, /* B&O soundbar speakers */
+ { 0x17, 0x90170153 }, /* Side speakers */
+ { 0x19, 0x03a11040 }, /* Headset microphone */
+ { }
+ };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+
+ /* Fixes volume control problem for side speakers */
+ alc295_fixup_disable_dac3(codec, fix, action);
+
+ /* Fixes no sound from headset speaker */
+ snd_hda_codec_amp_stereo(codec, 0x21, HDA_OUTPUT, 0, -1, 0);
+
+ /* Auto-enable headset mic when plugged */
+ snd_hda_jack_set_gating_jack(codec, 0x19, 0x21);
+
+ /* Headset mic volume enhancement */
+ snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREF50);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ alc_process_coef_fw(codec, coefs);
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ rename_ctl(codec, "Bass Speaker Playback Volume",
+ "B&O-Tuned Playback Volume");
+ rename_ctl(codec, "Front Playback Switch",
+ "B&O Soundbar Playback Switch");
+ rename_ctl(codec, "Bass Speaker Playback Switch",
+ "Side Speaker Playback Switch");
+ break;
+ }
+}
+
+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"
+#include "../helpers/thinkpad.c"
static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -6658,6 +2809,15 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
hda_fixup_thinkpad_acpi(codec, fix, action);
}
+/* for hda_fixup_ideapad_acpi() */
+#include "../helpers/ideapad_hotkey_led.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,
@@ -6672,12 +2832,29 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
}
}
+static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct hda_codec *cdc = data;
+ struct alc_spec *spec = cdc->spec;
+
+ codec_info(cdc, "ACPI Notification %d\n", event);
+
+ hda_component_acpi_device_notify(&spec->comps, handle, event, data);
+}
+
static int comp_bind(struct device *dev)
{
struct hda_codec *cdc = dev_to_hda_codec(dev);
struct alc_spec *spec = cdc->spec;
+ int ret;
+
+ ret = hda_component_manager_bind(cdc, &spec->comps);
+ if (ret)
+ return ret;
- return component_bind_all(dev, spec->comps);
+ return hda_component_manager_bind_acpi_notifications(cdc,
+ &spec->comps,
+ comp_acpi_device_notify, cdc);
}
static void comp_unbind(struct device *dev)
@@ -6685,7 +2862,8 @@ static void comp_unbind(struct device *dev)
struct hda_codec *cdc = dev_to_hda_codec(dev);
struct alc_spec *spec = cdc->spec;
- component_unbind_all(dev, spec->comps);
+ hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify);
+ hda_component_manager_unbind(cdc, &spec->comps);
}
static const struct component_master_ops comp_master_ops = {
@@ -6697,101 +2875,177 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_
struct snd_pcm_substream *sub, int action)
{
struct alc_spec *spec = cdc->spec;
- int i;
- for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
- if (spec->comps[i].dev)
- spec->comps[i].playback_hook(spec->comps[i].dev, action);
- }
+ hda_component_manager_playback_hook(&spec->comps, action);
}
-struct cs35l41_dev_name {
- const char *bus;
- const char *hid;
- int index;
-};
-
-/* match the device name in a slightly relaxed manner */
-static int comp_match_cs35l41_dev_name(struct device *dev, void *data)
+static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
+ const char *hid, const char *match_str, int count)
{
- struct cs35l41_dev_name *p = data;
- const char *d = dev_name(dev);
- int n = strlen(p->bus);
- char tmp[32];
-
- /* check the bus name */
- if (strncmp(d, p->bus, n))
- return 0;
- /* skip the bus number */
- if (isdigit(d[n]))
- n++;
- /* the rest must be exact matching */
- snprintf(tmp, sizeof(tmp), "-%s:00-cs35l41-hda.%d", p->hid, p->index);
- return !strcmp(d + n, tmp);
-}
-
-static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
- const char *hid, int count)
-{
- struct device *dev = hda_codec_dev(cdc);
struct alc_spec *spec = cdc->spec;
- struct cs35l41_dev_name *rec;
- int ret, i;
+ int ret;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
- for (i = 0; i < count; i++) {
- rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
- if (!rec)
- return;
- rec->bus = bus;
- rec->hid = hid;
- rec->index = i;
- spec->comps[i].codec = cdc;
- component_match_add(dev, &spec->match,
- comp_match_cs35l41_dev_name, rec);
- }
- ret = component_master_add_with_match(dev, &comp_master_ops, spec->match);
+ ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid,
+ match_str, &comp_master_ops);
if (ret)
- codec_err(cdc, "Fail to register component aggregator %d\n", ret);
- else
- spec->gen.pcm_playback_hook = comp_generic_playback_hook;
+ return;
+
+ spec->gen.pcm_playback_hook = comp_generic_playback_hook;
+ break;
+ case HDA_FIXUP_ACT_FREE:
+ hda_component_manager_free(&spec->comps, &comp_master_ops);
break;
}
}
+static void find_cirrus_companion_amps(struct hda_codec *cdc)
+{
+ struct device *dev = hda_codec_dev(cdc);
+ struct acpi_device *adev;
+ struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
+ const char *bus = NULL;
+ static const struct {
+ const char *hid;
+ const char *name;
+ } acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
+ { "CSC3556", "cs35l56-hda" },
+ { "CSC3557", "cs35l57-hda" }};
+ char *match;
+ int i, count = 0, count_devindex = 0;
+
+ for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
+ adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
+ if (adev)
+ break;
+ }
+ if (!adev) {
+ codec_dbg(cdc, "Did not find ACPI entry for a Cirrus Amp\n");
+ return;
+ }
+
+ count = i2c_acpi_client_count(adev);
+ if (count > 0) {
+ bus = "i2c";
+ } else {
+ count = acpi_spi_count_resources(adev);
+ if (count > 0)
+ bus = "spi";
+ }
+
+ fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
+ acpi_dev_put(adev);
+
+ if (!bus) {
+ codec_err(cdc, "Did not find any buses for %s\n", acpi_ids[i].hid);
+ return;
+ }
+
+ if (!fwnode) {
+ codec_err(cdc, "Could not get fwnode for %s\n", acpi_ids[i].hid);
+ return;
+ }
+
+ /*
+ * When available the cirrus,dev-index property is an accurate
+ * count of the amps in a system and is used in preference to
+ * the count of bus devices that can contain additional address
+ * alias entries.
+ */
+ count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
+ if (count_devindex > 0)
+ count = count_devindex;
+
+ match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
+ if (!match)
+ return;
+ codec_info(cdc, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
+ comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
+}
+
static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2);
+ comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
}
static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2);
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void cs35l41_fixup_spi_one(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 1);
}
static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 4);
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
}
static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
int action)
{
- cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2);
+ comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
}
static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
int action)
{
- cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2);
+ comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ /*
+ * The same SSID has been re-used in different hardware, they have
+ * different codecs and the newer GA403U has a ALC285.
+ */
+ if (cdc->core.vendor_id != 0x10ec0285)
+ alc_fixup_inv_dmic(cdc, fix, action);
}
+static void tas2781_fixup_tias_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
+{
+ 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 tas2781_fixup_txnw_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "i2c", "TXNW2781", "-%s:00-tas2781-hda.%d", 1);
+}
+
+static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
+ const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
+}
+
+static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+}
+
+
/* for alc295_fixup_hp_top_speakers */
-#include "hp_x360_helper.c"
+#include "../helpers/hp_x360.c"
/* for alc285_fixup_ideapad_s740_coef() */
-#include "ideapad_s740_helper.c"
+#include "../helpers/ideapad_s740.c"
static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
@@ -6853,6 +3107,25 @@ static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
}
}
+static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ u32 caps;
+ u8 nsteps, offs;
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+
+ caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
+ nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
+ offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
+ caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
+ caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
+
+ if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
+ codec_warn(codec, "failed to override amp caps for NID 0x3\n");
+}
+
static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
const struct hda_fixup *fix,
int action)
@@ -6916,6 +3189,9 @@ static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
};
struct alc_spec *spec = codec->spec;
+ /* Support Audio mute LED and Mic mute LED on keyboard */
+ hda_fixup_ideapad_acpi(codec, fix, action);
+
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
snd_hda_apply_pincfgs(codec, pincfgs);
@@ -6953,6 +3229,245 @@ static void alc295_fixup_dell_inspiron_top_speakers(struct hda_codec *codec,
}
}
+/* Forcibly assign NID 0x03 to HP while NID 0x02 to SPK */
+static void alc287_fixup_bind_dacs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
+ static const hda_nid_t preferred_pairs[] = {
+ 0x17, 0x02, 0x21, 0x03, 0
+ };
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ spec->gen.preferred_dacs = preferred_pairs;
+ spec->gen.auto_mute_via_amp = 1;
+ if (spec->gen.autocfg.speaker_pins[0] != 0x14) {
+ snd_hda_codec_write_cache(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ 0x0); /* Make sure 0x14 was disable */
+ }
+}
+
+/* Fix none verb table of Headset Mic pin */
+static void alc2xx_fixup_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x19, 0x03a1103c },
+ { }
+ };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ break;
+ }
+}
+
+static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /*
+ * The Pin Complex 0x14 for the treble speakers is wrongly reported as
+ * unconnected.
+ * The Pin Complex 0x17 for the bass speakers has the lowest association
+ * and sequence values so shift it up a bit to squeeze 0x14 in.
+ */
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x14, 0x90170110 }, // top/treble
+ { 0x17, 0x90170111 }, // bottom/bass
+ { }
+ };
+
+ /*
+ * Force DAC 0x02 for the bass speakers 0x17.
+ */
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ }
+
+ cs35l41_fixup_i2c_two(codec, fix, action);
+ alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+ alc245_fixup_hp_gpio_led(codec, fix, action);
+}
+
+/* some changes for Spectre x360 16, 2024 model */
+static void alc245_fixup_hp_spectre_x360_16_aa0xxx(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /*
+ * The Pin Complex 0x14 for the treble speakers is wrongly reported as
+ * unconnected.
+ * The Pin Complex 0x17 for the bass speakers has the lowest association
+ * and sequence values so shift it up a bit to squeeze 0x14 in.
+ */
+ struct alc_spec *spec = codec->spec;
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x14, 0x90170110 }, // top/treble
+ { 0x17, 0x90170111 }, // bottom/bass
+ { }
+ };
+
+ /*
+ * Force DAC 0x02 for the bass speakers 0x17.
+ */
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* needed for amp of back speakers */
+ spec->gpio_mask |= 0x01;
+ spec->gpio_dir |= 0x01;
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /* need to toggle GPIO to enable the amp of back speakers */
+ alc_update_gpio_data(codec, 0x01, true);
+ msleep(100);
+ alc_update_gpio_data(codec, 0x01, false);
+ break;
+ }
+
+ cs35l41_fixup_i2c_two(codec, fix, action);
+ alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+ alc245_fixup_hp_gpio_led(codec, fix, action);
+}
+
+static void alc245_fixup_hp_zbook_firefly_g12a(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.auto_mute_via_amp = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ }
+
+ cs35l41_fixup_i2c_two(codec, fix, action);
+ alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+ alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
+/*
+ * ALC287 PCM hooks
+ */
+static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
+{
+ switch (action) {
+ case HDA_GEN_PCM_ACT_OPEN:
+ alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
+ alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
+ break;
+ }
+}
+
+static void alc287_s4_power_gpio3_default(struct hda_codec *codec)
+{
+ if (is_s4_suspend(codec)) {
+ alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
+ }
+}
+
+static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct coef_fw coefs[] = {
+ WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC300),
+ WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
+ WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301),
+ WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
+ };
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11);
+ alc_process_coef_fw(codec, coefs);
+ spec->power_hook = alc287_s4_power_gpio3_default;
+ spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
+}
+/* GPIO2: mute led GPIO3: micmute led */
+static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.auto_mute_via_amp = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ }
+
+ tas2781_fixup_spi(codec, fix, action);
+ alc_fixup_hp_gpio_led(codec, action, 0x04, 0x0);
+ alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+/* JD2: mute led GPIO3: micmute led */
+static void alc245_tas2781_i2c_hp_fixup_muteled(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.auto_mute_via_amp = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ }
+
+ tas2781_fixup_txnw_i2c(codec, fix, action);
+ alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+ alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+/*
+ * 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);
+}
+
+/* Swap DAC assignments for HP and speaker */
+static void alc288_fixup_surface_swap_dacs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static hda_nid_t preferred_pairs[] = {
+ 0x21, 0x03, 0x14, 0x02, 0
+ };
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+
+ spec->gen.preferred_dacs = preferred_pairs;
+}
+
enum {
ALC269_FIXUP_GPIO2,
ALC269_FIXUP_SONY_VAIO,
@@ -6993,6 +3508,7 @@ enum {
ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
@@ -7021,11 +3537,17 @@ 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,
+ ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO,
ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC255_FIXUP_HEADSET_MODE,
ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
@@ -7044,6 +3566,8 @@ enum {
ALC280_FIXUP_HP_9480M,
ALC245_FIXUP_HP_X360_AMP,
ALC285_FIXUP_HP_SPECTRE_X360_EB1,
+ ALC285_FIXUP_HP_SPECTRE_X360_DF1,
+ ALC285_FIXUP_HP_ENVY_X360,
ALC288_FIXUP_DELL_HEADSET_MODE,
ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC288_FIXUP_DELL_XPS_13,
@@ -7058,6 +3582,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,
@@ -7065,6 +3590,9 @@ enum {
ALC285_FIXUP_SPEAKER2_TO_DAC1,
ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1,
ALC285_FIXUP_ASUS_HEADSET_MIC,
+ ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS,
+ ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1,
+ ALC285_FIXUP_ASUS_I2C_HEADSET_MIC,
ALC280_FIXUP_HP_HEADSET_MIC,
ALC221_FIXUP_HP_FRONT_MIC,
ALC292_FIXUP_TPT460,
@@ -7100,6 +3628,7 @@ enum {
ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
ALC294_FIXUP_ASUS_MIC,
ALC294_FIXUP_ASUS_HEADSET_MIC,
+ ALC294_FIXUP_ASUS_I2C_HEADSET_MIC,
ALC294_FIXUP_ASUS_SPK,
ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
@@ -7112,14 +3641,21 @@ enum {
ALC286_FIXUP_ACER_AIO_HEADSET_MIC,
ALC256_FIXUP_ASUS_HEADSET_MIC,
ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
+ ALC255_FIXUP_PREDATOR_SUBWOOFER,
ALC299_FIXUP_PREDATOR_SPK,
ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE,
+ ALC289_FIXUP_DELL_SPK1,
ALC289_FIXUP_DELL_SPK2,
ALC289_FIXUP_DUAL_SPK,
+ ALC289_FIXUP_RTK_AMP_DUAL_SPK,
ALC294_FIXUP_SPK2_TO_DAC1,
ALC294_FIXUP_ASUS_DUAL_SPK,
ALC285_FIXUP_THINKPAD_X1_GEN7,
ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+ ALC294_FIXUP_ASUS_ALLY,
+ ALC294_FIXUP_ASUS_ALLY_PINS,
+ ALC294_FIXUP_ASUS_ALLY_VERBS,
+ ALC294_FIXUP_ASUS_ALLY_SPEAKER,
ALC294_FIXUP_ASUS_HPE,
ALC294_FIXUP_ASUS_COEF_1B,
ALC294_FIXUP_ASUS_GX502_HP,
@@ -7133,10 +3669,15 @@ 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,
ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
+ ALC236_FIXUP_LENOVO_INV_DMIC,
ALC298_FIXUP_SAMSUNG_AMP,
+ ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
+ ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS,
ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -7160,6 +3701,7 @@ enum {
ALC274_FIXUP_HP_MIC,
ALC274_FIXUP_HP_HEADSET_MIC,
ALC274_FIXUP_HP_ENVY_GPIO,
+ ALC274_FIXUP_ASUS_ZEN_AIO_27,
ALC256_FIXUP_ASUS_HPE,
ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
ALC287_FIXUP_HP_GPIO_LED,
@@ -7192,6 +3734,8 @@ enum {
ALC287_FIXUP_LEGION_16ACHG6,
ALC287_FIXUP_CS35L41_I2C_2,
ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED,
+ ALC287_FIXUP_CS35L41_I2C_4,
+ ALC245_FIXUP_CS35L41_SPI_1,
ALC245_FIXUP_CS35L41_SPI_2,
ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED,
ALC245_FIXUP_CS35L41_SPI_4,
@@ -7201,8 +3745,52 @@ enum {
ALC287_FIXUP_LEGION_16ITHG6,
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
+ ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN,
ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS,
ALC236_FIXUP_DELL_DUAL_CODECS,
+ ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
+ ALC287_FIXUP_TAS2781_I2C,
+ ALC295_FIXUP_DELL_TAS2781_I2C,
+ ALC245_FIXUP_TAS2781_SPI_2,
+ ALC287_FIXUP_TXNW2781_I2C,
+ ALC287_FIXUP_YOGA7_14ARB7_I2C,
+ ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
+ ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT,
+ ALC245_FIXUP_HP_X360_MUTE_LEDS,
+ ALC287_FIXUP_THINKPAD_I2S_SPK,
+ ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
+ ALC2XX_FIXUP_HEADSET_MIC,
+ ALC289_FIXUP_DELL_CS35L41_SPI_2,
+ ALC294_FIXUP_CS35L41_I2C_2,
+ ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
+ ALC256_FIXUP_HEADPHONE_AMP_VOL,
+ ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
+ ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX,
+ ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A,
+ ALC285_FIXUP_ASUS_GA403U,
+ ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC,
+ ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1,
+ ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
+ ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1,
+ ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318,
+ ALC256_FIXUP_CHROME_BOOK,
+ ALC245_FIXUP_CLEVO_NOISY_MIC,
+ ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
+ ALC233_FIXUP_MEDION_MTL_SPK,
+ ALC294_FIXUP_BASS_SPEAKER_15,
+ ALC283_FIXUP_DELL_HP_RESUME,
+ ALC294_FIXUP_ASUS_CS35L41_SPI_2,
+ ALC274_FIXUP_HP_AIO_BIND_DACS,
+ ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2,
+ ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
+ ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
+ ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
+ ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
+ ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE,
+ ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED,
+ ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED,
+ ALC288_FIXUP_SURFACE_SWAP_DACS,
+ ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -7318,7 +3906,7 @@ static const struct hda_fixup alc269_fixups[] = {
},
[ALC269_FIXUP_HEADSET_MIC] = {
.type = HDA_FIXUP_FUNC,
- .v.func = alc269_fixup_headset_mic,
+ .v.func = alc_fixup_headset_mic,
},
[ALC269_FIXUP_QUANTA_MUTE] = {
.type = HDA_FIXUP_FUNC,
@@ -7356,6 +3944,33 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_pincfg_U7x7_headset_mic,
},
+ [ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170151 }, /* use as internal speaker (LFE) */
+ { 0x1b, 0x90170152 }, /* use as internal speaker (back) */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+ },
+ [ALC269VC_FIXUP_INFINIX_Y4_MAX] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x90170150 }, /* use as internal speaker */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+ },
+ [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, 0x03a19020 }, /* headset mic */
+ { 0x1b, 0x90170150 }, /* speaker */
+ { }
+ },
+ },
[ALC269_FIXUP_AMIC] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -7466,6 +4081,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE
},
+ [ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
[ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -7712,6 +4333,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,
@@ -7746,6 +4373,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_HEADSET_MODE
},
+ [ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
[ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -7963,6 +4596,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,
@@ -8051,6 +4688,31 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1
},
+ [ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170120 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC285_FIXUP_ASUS_HEADSET_MIC
+ },
+ [ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_CS35L41_I2C_2
+ },
+ [ALC285_FIXUP_ASUS_I2C_HEADSET_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a11050 },
+ { 0x1b, 0x03a11c30 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1
+ },
[ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8284,6 +4946,15 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MIC
},
+ [ALC294_FIXUP_ASUS_I2C_HEADSET_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a19020 }, /* use as headset mic */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC287_FIXUP_CS35L41_I2C_2
+ },
[ALC294_FIXUP_ASUS_SPK] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
@@ -8387,6 +5058,13 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
},
+ [ALC255_FIXUP_PREDATOR_SUBWOOFER] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170151 }, /* use as internal speaker (LFE) */
+ { 0x1b, 0x90170152 } /* use as internal speaker (back) */
+ }
+ },
[ALC299_FIXUP_PREDATOR_SPK] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8394,6 +5072,12 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
}
},
+ [ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_i2c_two,
+ .chained = true,
+ .chain_id = ALC255_FIXUP_PREDATOR_SUBWOOFER
+ },
[ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8404,6 +5088,15 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
},
+ [ALC289_FIXUP_DELL_SPK1] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170140 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE
+ },
[ALC289_FIXUP_DELL_SPK2] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8419,6 +5112,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC289_FIXUP_DELL_SPK2
},
+ [ALC289_FIXUP_RTK_AMP_DUAL_SPK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ .chained = true,
+ .chain_id = ALC289_FIXUP_DELL_SPK1
+ },
[ALC294_FIXUP_SPK2_TO_DAC1] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_speaker2_to_dac1,
@@ -8432,6 +5131,47 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC294_FIXUP_SPK2_TO_DAC1
},
+ [ALC294_FIXUP_ASUS_ALLY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_i2c_two,
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
+ },
+ [ALC294_FIXUP_ASUS_ALLY_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a11050 },
+ { 0x1a, 0x03a11c30 },
+ { 0x21, 0x03211420 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_ALLY_VERBS
+ },
+ [ALC294_FIXUP_ASUS_ALLY_VERBS] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x46 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0004 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x47 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0xa47a },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0049},
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x201b },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x4278},
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER
+ },
+ [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ },
[ALC285_FIXUP_THINKPAD_X1_GEN7] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_thinkpad_x1_gen7,
@@ -8482,6 +5222,12 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc294_fixup_gx502_hp,
},
+ [ALC295_FIXUP_DELL_TAS2781_I2C] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = tas2781_fixup_tias_i2c,
+ .chained = true,
+ .chain_id = ALC289_FIXUP_DUAL_SPK
+ },
[ALC294_FIXUP_ASUS_GU502_PINS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8556,6 +5302,16 @@ 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,
+ },
[ALC236_FIXUP_HP_GPIO_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc236_fixup_hp_gpio_led,
@@ -8568,12 +5324,36 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc236_fixup_hp_mute_led_micmute_vref,
},
+ [ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc236_fixup_hp_mute_led_coefbit2,
+ .chained = true,
+ .chain_id = ALC236_FIXUP_HP_GPIO_LED,
+ },
+ [ALC236_FIXUP_LENOVO_INV_DMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_inv_dmic,
+ .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,
.chained = true,
.chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET
},
+ [ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc298_fixup_samsung_amp_v2_2_amps
+ },
+ [ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc298_fixup_samsung_amp_v2_4_amps
+ },
[ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
@@ -8784,6 +5564,26 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc274_fixup_hp_envy_gpio,
},
+ [ALC274_FIXUP_ASUS_ZEN_AIO_27] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0xc420 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0249 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x202b },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x62 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0xa007 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x5060 },
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC2XX_FIXUP_HEADSET_MIC,
+ },
[ALC256_FIXUP_ASUS_HPE] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
@@ -8885,6 +5685,16 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_spectre_x360_eb1
},
+ [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_spectre_x360_df1
+ },
+ [ALC285_FIXUP_HP_ENVY_X360] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_envy_x360,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT,
+ },
[ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_ideapad_s740_coef,
@@ -9069,8 +5879,6 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC287_FIXUP_CS35L41_I2C_2] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs35l41_fixup_i2c_two,
- .chained = true,
- .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
},
[ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED] = {
.type = HDA_FIXUP_FUNC,
@@ -9078,10 +5886,18 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC285_FIXUP_HP_MUTE_LED,
},
+ [ALC287_FIXUP_CS35L41_I2C_4] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_i2c_four,
+ },
[ALC245_FIXUP_CS35L41_SPI_2] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs35l41_fixup_spi_two,
},
+ [ALC245_FIXUP_CS35L41_SPI_1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_spi_one,
+ },
[ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs35l41_fixup_spi_two,
@@ -9195,6 +6011,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
},
+ [ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_CS35L41_I2C_2,
+ },
[ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc295_fixup_dell_inspiron_top_speakers,
@@ -9207,9 +6029,236 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
},
+ [ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_i2c_two,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+ },
+ [ALC287_FIXUP_TAS2781_I2C] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = tas2781_fixup_tias_i2c,
+ .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_TXNW2781_I2C] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = tas2781_fixup_txnw_i2c,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+ },
+ [ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = yoga7_14arb7_fixup_i2c,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+ },
+ [ALC245_FIXUP_HP_MUTE_LED_COEFBIT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_mute_led_coefbit,
+ },
+ [ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_mute_led_v1_coefbit,
+ },
+ [ALC245_FIXUP_HP_X360_MUTE_LEDS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_mute_led_coefbit,
+ .chained = true,
+ .chain_id = ALC245_FIXUP_HP_GPIO_LED
+ },
+ [ALC287_FIXUP_THINKPAD_I2S_SPK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_bind_dacs,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+ },
+ [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_bind_dacs,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
+ },
+ [ALC2XX_FIXUP_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc2xx_fixup_headset_mic,
+ },
+ [ALC289_FIXUP_DELL_CS35L41_SPI_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_spi_two,
+ .chained = true,
+ .chain_id = ALC289_FIXUP_DUAL_SPK
+ },
+ [ALC294_FIXUP_CS35L41_I2C_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_i2c_two,
+ },
+ [ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc256_fixup_acer_sfg16_micmute_led,
+ },
+ [ALC256_FIXUP_HEADPHONE_AMP_VOL] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc256_decrease_headphone_amp_val,
+ },
+ [ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_spectre_x360_eu0xxx,
+ },
+ [ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_spectre_x360_16_aa0xxx,
+ },
+ [ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_hp_zbook_firefly_g12a,
+ },
+ [ALC285_FIXUP_ASUS_GA403U] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_asus_ga403u,
+ },
+ [ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a11050 },
+ { 0x1b, 0x03a11c30 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1
+ },
+ [ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
+ },
+ [ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a11050 },
+ { 0x1b, 0x03a11c30 },
+ { }
+ },
+ },
+ [ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_ASUS_GA403U,
+ },
+ [ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_lenovo_thinkpad_with_alc1318,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+ },
+ [ALC256_FIXUP_CHROME_BOOK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc256_fixup_chromebook,
+ .chained = true,
+ .chain_id = ALC225_FIXUP_HEADSET_JACK
+ },
+ [ALC245_FIXUP_CLEVO_NOISY_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
+ },
+ [ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+ { 0x1b, 0x20a11040 }, /* dock mic */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+ },
+ [ALC233_FIXUP_MEDION_MTL_SPK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x90170110 },
+ { }
+ },
+ },
+ [ALC294_FIXUP_BASS_SPEAKER_15] = {
+ .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,
+ },
+ [ALC294_FIXUP_ASUS_CS35L41_SPI_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l41_fixup_spi_two,
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC,
+ },
+ [ALC274_FIXUP_HP_AIO_BIND_DACS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc274_fixup_hp_aio_bind_dacs,
+ },
+ [ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a11050 },
+ { 0x1b, 0x03a11c30 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1
+ },
+ [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
+ },
+ [ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
+ },
+ [ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170151 }, /* Internal Speaker LFE */
+ { 0x1e, 0x90170150 }, /* Internal Speaker */
+ { }
+ },
+ },
+ [ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+ { 0x1a, 0x22a190a0 }, /* dock mic */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+ },
+ [ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_tas2781_spi_hp_fixup_muteled,
+ },
+ [ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_tas2781_i2c_hp_fixup_muteled,
+ },
+ [ALC288_FIXUP_SURFACE_SWAP_DACS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc288_fixup_surface_swap_dacs,
+ },
};
-static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
@@ -9222,6 +6271,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF),
+ SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK),
SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC),
@@ -9231,10 +6281,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1166, "Acer Veriton N4640G", ALC269_FIXUP_LIFEBOOK),
SND_PCI_QUIRK(0x1025, 0x1167, "Acer Veriton N6640G", ALC269_FIXUP_LIFEBOOK),
+ SND_PCI_QUIRK(0x1025, 0x1177, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
+ SND_PCI_QUIRK(0x1025, 0x1178, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK),
SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1269, "Acer SWIFT SF314-54", ALC256_FIXUP_ACER_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x126a, "Acer Swift SF114-32", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
@@ -9244,11 +6297,17 @@ static const struct snd_pci_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),
SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
+ SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
@@ -9260,6 +6319,7 @@ static const struct snd_pci_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),
@@ -9291,6 +6351,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
+ SND_PCI_QUIRK(0x1028, 0x0879, "Dell Latitude 5420 Rugged", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
@@ -9308,15 +6369,34 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x0b27, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0b28, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+ SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0c0b, "Dell Oasis 14 RPL-P", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x0c0e, "Dell Oasis 16", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1c, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1d, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1e, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
+ SND_PCI_QUIRK(0x1028, 0x0c28, "Dell Inspiron 16 Plus 7630", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+ SND_PCI_QUIRK(0x1028, 0x0c4d, "Dell", ALC287_FIXUP_CS35L41_I2C_4),
+ SND_PCI_QUIRK(0x1028, 0x0c94, "Dell Polaris 3 metal", ALC295_FIXUP_DELL_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1028, 0x0c96, "Dell Polaris 2in1", ALC295_FIXUP_DELL_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1028, 0x0cbd, "Dell Oasis 13 CS MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cbe, "Dell Oasis 13 2-IN-1 MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cbf, "Dell Oasis 13 Low Weight MTU-L", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cc0, "Dell Oasis 13", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x0cc1, "Dell Oasis 14 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cc2, "Dell Oasis 14 2-in-1 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cc3, "Dell Oasis 14 Low Weight MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cc4, "Dell Oasis 16 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1028, 0x0cc5, "Dell Oasis 14", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -9390,14 +6470,25 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x841c, "HP Pavilion 15-CK0xx", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+ SND_PCI_QUIRK(0x103c, 0x84a6, "HP 250 G7 Notebook PC", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+ SND_PCI_QUIRK(0x103c, 0x84ae, "HP 15-db0403ng", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
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, 0x8548, "HP EliteBook x360 830 G6", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED),
+ 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, 0x8603, "HP Omen 17-cb0xxx", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x860c, "HP ZBook 17 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+ SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1),
SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
@@ -9408,7 +6499,8 @@ static const struct snd_pci_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),
SND_PCI_QUIRK(0x103c, 0x8780, "HP ZBook Fury 17 G7 Mobile Workstation",
@@ -9418,7 +6510,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x87cc, "HP Pavilion 15-eg0xxx", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
@@ -9427,10 +6523,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87f6, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
+ SND_PCI_QUIRK(0x103c, 0x87fd, "HP Laptop 14-dq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x87fe, "HP Laptop 15s-fq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8805, "HP ProBook 650 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x880d, "HP EliteBook 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
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),
@@ -9440,12 +6540,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
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),
SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x88dd, "HP Pavilion 15z-ec200", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x890e, "HP 255 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8919, "HP Pavilion Aero Laptop 13-be0xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x896d, "HP ZBook Firefly 16 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x896e, "HP EliteBook x360 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -9454,13 +6559,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8973, "HP EliteBook 860 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8974, "HP EliteBook 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4),
+ SND_PCI_QUIRK(0x103c, 0x898a, "HP Pavilion 15-eg100", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8991, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8992, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8994, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8995, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x89a0, "HP Laptop 15-dw4xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x89a4, "HP ProBook 440 G9", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x89a6, "HP ProBook 450 G9", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x89aa, "HP EliteBook 630 G9", ALC236_FIXUP_HP_GPIO_LED),
@@ -9471,28 +6579,57 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x89da, "HP Spectre x360 14t-ea100", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+ SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8a26, "HP Victus 16-d1xxx (MB 8A26)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
+ SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a75, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a76, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a77, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ab9, "HP EliteBook 840 G8 (MB 8AB8)", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b44, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b45, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b46, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8b5f, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b65, "HP ProBook 455 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b66, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
- SND_PCI_QUIRK(0x103c, 0x8b70, "HP EliteBook 835 G10", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x103c, 0x8b72, "HP EliteBook 845 G10", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x103c, 0x8b74, "HP EliteBook 845W G10", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8b70, "HP EliteBook 835 G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8b72, "HP EliteBook 845 G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8b74, "HP EliteBook 845W G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b77, "HP ElieBook 865 G10", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8b7a, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b7d, "HP", ALC236_FIXUP_HP_GPIO_LED),
@@ -9500,42 +6637,227 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8b8a, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b8b, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b8d, "HP", ALC236_FIXUP_HP_GPIO_LED),
- SND_PCI_QUIRK(0x103c, 0x8b8f, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8b8f, "HP", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8bd4, "HP Victus 16-s0xxx (MB 8BD4)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8bd6, "HP Pavilion Aero Laptop 13z-be200", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
- SND_PCI_QUIRK(0x103c, 0x8c26, "HP HP EliteBook 800G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+ SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
+ SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+ SND_PCI_QUIRK(0x103c, 0x8c2d, "HP Victus 15-fa1xxx (MB 8C2D)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c4d, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c4e, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c7b, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c7c, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c7d, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c7e, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c7f, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c80, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c81, "HP EliteBook 665 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c89, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c8d, "HP ProBook 440 G11", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c8e, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8c99, "HP Victus 16-r1xxx (MB 8C99)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8c9c, "HP Victus 16-s1xxx (MB 8C9C)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+ SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+ SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+ SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+ 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, 0x8d07, "HP Victus 15-fb2xxx (MB 8D07)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8d18, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
+ 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, 0x8dd4, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
+ 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, 0x8ded, "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, 0x8def, "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, 0x8df1, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dfb, "HP EliteBook 6 G1a 14", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dfd, "HP EliteBook 6 G1a 16", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 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", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+ SND_PCI_QUIRK(0x103c, 0x8e1d, "HP ZBook X Gli 16 G12", ALC236_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, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", 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(0x103c, 0x8eb6, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8eb7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8eb8, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ec1, "HP 200 G2i", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ec4, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ec5, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ece, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ecf, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ed2, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ed5, "HP EliteBook 8 Flip G2i 13", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ed6, "HP EliteBook 8 G2i 13", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ed7, "HP EliteBook 8 G2i 14", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ed8, "HP EliteBook 8 G2i 16", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ed9, "HP ZBook Firefly 14W", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8eda, "HP ZBook Firefly 16W", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ee4, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8ee5, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8f0c, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f41, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
+ SND_PCI_QUIRK(0x1043, 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),
SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK),
+ SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ 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, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
- SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
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, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
- SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604V", ALC285_FIXUP_ASUS_HEADSET_MIC),
- SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603V", ALC285_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1454, "ASUS PM3406CKA", ALC287_FIXUP_CS35L41_I2C_2),
+ 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),
+ SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x14f2, "ASUS VivoBook X515JA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
+ SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
+ SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS UX7602VI/BZ", ALC245_FIXUP_CS35L41_SPI_2),
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, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
@@ -9543,33 +6865,91 @@ static const struct snd_pci_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, 0x1a8e, "ASUS G712LWS", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
- SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x1b13, "ASUS U41SV/GA403U", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1b93, "ASUS G614JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1c03, "ASUS UM3406HA", ALC294_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x1c33, "ASUS UX5304MA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1c63, "ASUS GU605M", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+ SND_PCI_QUIRK(0x1043, 0x1c80, "ASUS VivoBook TP401", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
- SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+ SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS G713PI/PU/PV/PVN", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
- SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402", ALC245_FIXUP_CS35L41_SPI_2),
+ 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, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
+ SND_PCI_QUIRK(0x1043, 0x1e63, "ASUS H7606W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+ SND_PCI_QUIRK(0x1043, 0x1e83, "ASUS GA605W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
+ SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RCLA72", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
+ 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", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x3071, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30c1, "ASUS B3605CCA / P3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30d1, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_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", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x3391, "ASUS PM3606CKA", ALC287_FIXUP_CS35L41_I2C_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),
+ SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
+ 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),
SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
+ SND_PCI_QUIRK(0x1043, 0x88f4, "ASUS NUC14LNS", ALC245_FIXUP_CS35L41_SPI_1),
SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -9584,34 +6964,52 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
+ SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+ SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
- SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
+ SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1414, 0x9c20, "Microsoft Surface Pro 2/3", ALC288_FIXUP_SURFACE_SWAP_DACS),
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP),
+ SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP),
+ SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP),
+ SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
+ SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
+ SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+ SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+ SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK),
+ SND_PCI_QUIRK(0x152d, 0x1262, "Huawei NBLB-WAX9N", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1558, 0x0353, "Clevo V35[05]SN[CDE]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x28c1, "Clevo V370VND", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1558, 0x35a1, "Clevo V3[56]0EN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x35b1, "Clevo V3[57]0WN[MNP]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9636,7 +7034,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x51b1, "Clevo NS50AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9671,8 +7072,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL5[03]RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xa554, "VAIO VJFH52", ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xa559, "VAIO RPL", ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL50NU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xa650, "Clevo NP[567]0SN[CD]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xa671, "Clevo NP70SN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xa741, "Clevo V54x_6x_TNE", ALC245_FIXUP_CLEVO_NOISY_MIC),
+ SND_PCI_QUIRK(0x1558, 0xa743, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
+ SND_PCI_QUIRK(0x1558, 0xa763, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9706,6 +7113,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
+ SND_PCI_QUIRK(0x17aa, 0x2234, "Thinkpad ICE-1", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
@@ -9718,14 +7126,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22c2, "Thinkpad X1 Extreme Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
- SND_PCI_QUIRK(0x17aa, 0x22f1, "Thinkpad", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x22f2, "Thinkpad", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x22f3, "Thinkpad", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x2316, "Thinkpad P1 Gen 6", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x2317, "Thinkpad P1 Gen 6", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x22f1, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x22f2, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x22f3, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x2316, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x2317, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
+ SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
+ SND_PCI_QUIRK(0x17aa, 0x2326, "Hera2", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -9737,11 +7148,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
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),
- SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+ 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),
SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
+ HDA_CODEC_QUIRK(0x17aa, 0x3820, "IdeaPad 330-17IKB 81DM", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF),
@@ -9753,8 +7170,66 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
+ SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
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, 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),
+ SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x387f, "Yoga S780-16 pro dual LX", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3880, "Yoga S780-16 pro dual YC", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3882, "Lenovo Yoga Pro 7 14APH8", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3891, "Lenovo Yoga Pro 7 14AHP9", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38a5, "Y580P AMD dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
+ HDA_CODEC_QUIRK(0x17aa, 0x391c, "Lenovo Yoga 7 2-in-1 14AKP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x38b7, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38c7, "Thinkbook 13x Gen 4", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38c8, "Thinkbook 13x Gen 4", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38d2, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38d3, "Yoga S990-16 Pro IMH YC Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38d4, "Yoga S990-16 Pro IMH VECO Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38d5, "Yoga S990-16 Pro IMH YC Quad", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38d6, "Yoga S990-16 Pro IMH VECO Quad", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38d7, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
+ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3929, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x392b, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -9779,16 +7254,24 @@ static const struct snd_pci_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),
+ SND_PCI_QUIRK(0x1854, 0x0441, "LG CQ6 AIO", ALC256_FIXUP_HEADPHONE_AMP_VOL),
+ SND_PCI_QUIRK(0x1854, 0x0488, "LG gram 16 (16Z90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+ SND_PCI_QUIRK(0x1854, 0x0489, "LG gram 16 (16Z90R-A)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+ SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
+ SND_PCI_QUIRK(0x1c6c, 0x122a, "Positivo N14AP7", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1c6c, 0x1251, "Positivo N14KP6-TG", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
SND_PCI_QUIRK(0x1d05, 0x1096, "TongFang GMxMRxx", ALC269_FIXUP_NO_SHUTUP),
@@ -9799,15 +7282,37 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d05, 0x1147, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x1d05, 0x115c, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP),
+ SND_PCI_QUIRK(0x1d05, 0x1387, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d05, 0x300f, "TongFang X6AR5xxY", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d05, 0x3019, "TongFang X6FR5xxY", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
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(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_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),
+ SND_PCI_QUIRK(0x2782, 0x1407, "Positivo P15X", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC),
+ SND_PCI_QUIRK(0x2782, 0x1409, "Positivo K116J", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC),
+ SND_PCI_QUIRK(0x2782, 0x1701, "Infinix Y4 Max", ALC269VC_FIXUP_INFINIX_Y4_MAX),
+ SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX),
+ SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
+ SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK),
SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
+ SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0xf111, 0x0006, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0xf111, 0x0009, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0xf111, 0x000b, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0xf111, 0x000c, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
#if 0
/* Below is a quirk table taken from the old code.
@@ -9860,11 +7365,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
{}
};
-static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = {
+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),
{}
};
@@ -9886,6 +7391,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
{.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"},
{.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"},
+ {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, .name = "dell-headset4-quiet"},
{.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
{.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
{.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
@@ -9928,6 +7434,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"},
@@ -9977,10 +7484,13 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
{.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-headset-jack"},
{.id = ALC295_FIXUP_CHROME_BOOK, .name = "alc-chrome-book"},
+ {.id = ALC256_FIXUP_CHROME_BOOK, .name = "alc-2024y-chromebook"},
{.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"},
{.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"},
{.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},
{.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"},
+ {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, .name = "alc298-samsung-amp-v2-2-amps"},
+ {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, .name = "alc298-samsung-amp-v2-4-amps"},
{.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"},
{.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"},
{.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"},
@@ -9988,11 +7498,15 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"},
{.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
{.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
+ {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"},
+ {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"},
{.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
{.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
{.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
{.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"},
{.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"},
+ {.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"},
+ {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
{}
};
#define ALC225_STANDARD_PINS \
@@ -10288,6 +7802,14 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x17, 0x90170111},
{0x19, 0x03a11030},
{0x21, 0x03211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
+ {0x17, 0x90170110},
+ {0x19, 0x03a11030},
+ {0x21, 0x03211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
+ {0x17, 0x90170110}, /* 0x231f with RTK I2S AMP */
+ {0x19, 0x04a11040},
+ {0x21, 0x04211020}),
SND_HDA_PIN_QUIRK(0x10ec0286, 0x1025, "Acer", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
{0x12, 0x90a60130},
{0x17, 0x90170110},
@@ -10382,22 +7904,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x12, 0x90a60130},
{0x17, 0x90170110},
{0x21, 0x03211020}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
- {0x14, 0x90170110},
- {0x21, 0x04211020}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
- {0x14, 0x90170110},
- {0x21, 0x04211030}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
- ALC295_STANDARD_PINS,
- {0x17, 0x21014020},
- {0x18, 0x21a19030}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
- ALC295_STANDARD_PINS,
- {0x17, 0x21014040},
- {0x18, 0x21a19050}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
- ALC295_STANDARD_PINS),
SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_STANDARD_PINS,
{0x17, 0x90170110}),
@@ -10438,18 +7944,27 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
* at most one tbl is allowed to define for the same vendor and same codec
*/
static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1025, "Acer", ALC2XX_FIXUP_HEADSET_MIC,
+ {0x19, 0x40000000}),
SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
{0x19, 0x40000000},
{0x1b, 0x40000000}),
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET,
+ {0x19, 0x40000000},
+ {0x1b, 0x40000000}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x19, 0x40000000},
{0x1a, 0x40000000}),
- SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
{0x19, 0x40000000},
{0x1a, 0x40000000}),
- SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
+ SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
{0x19, 0x40000000},
{0x1a, 0x40000000}),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC2XX_FIXUP_HEADSET_MIC,
+ {0x19, 0x40000000}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1558, "Clevo", ALC2XX_FIXUP_HEADSET_MIC,
+ {0x19, 0x40000000}),
{}
};
@@ -10493,9 +8008,19 @@ static void alc269_fill_coef(struct hda_codec *codec)
alc_update_coef_idx(codec, 0x4, 0, 1<<11);
}
+static void alc269_remove(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (spec)
+ hda_component_manager_free(&spec->comps, &comp_master_ops);
+
+ snd_hda_gen_remove(codec);
+}
+
/*
*/
-static int patch_alc269(struct hda_codec *codec)
+static int alc269_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
struct alc_spec *spec;
int err;
@@ -10507,11 +8032,8 @@ static int patch_alc269(struct hda_codec *codec)
spec = codec->spec;
spec->gen.shared_mic_vref_pin = 0x18;
codec->power_save_node = 0;
+ spec->en_3kpull_low = true;
-#ifdef CONFIG_PM
- codec->patch_ops.suspend = alc269_suspend;
- codec->patch_ops.resume = alc269_resume;
-#endif
spec->shutup = alc_default_shutup;
spec->init_hook = alc_default_init;
@@ -10589,12 +8111,16 @@ static int patch_alc269(struct hda_codec *codec)
spec->shutup = alc256_shutup;
spec->init_hook = alc256_init;
spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
+ if (codec->core.vendor_id == 0x10ec0236 &&
+ codec->bus->pci->vendor != PCI_VENDOR_ID_AMD)
+ spec->en_3kpull_low = false;
break;
case 0x10ec0257:
spec->codec_variant = ALC269_TYPE_ALC257;
spec->shutup = alc256_shutup;
spec->init_hook = alc256_init;
spec->gen.mixer_nid = 0;
+ spec->en_3kpull_low = false;
break;
case 0x10ec0215:
case 0x10ec0245:
@@ -10634,8 +8160,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:
@@ -10672,6 +8201,13 @@ static int patch_alc269(struct hda_codec *codec)
snd_hda_pick_pin_fixup(codec, alc269_fallback_pin_fixup_tbl, alc269_fixups, false);
snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
alc269_fixups);
+
+ /*
+ * Check whether ACPI describes companion amplifiers that require
+ * component binding
+ */
+ find_cirrus_companion_amps(codec);
+
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
alc_auto_parse_customize_define(codec);
@@ -10695,1395 +8231,81 @@ static int patch_alc269(struct hda_codec *codec)
return 0;
error:
- alc_free(codec);
- return err;
-}
-
-/*
- * ALC861
- */
-
-static int alc861_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
- static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
- return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
-}
-
-/* Pin config fixes */
-enum {
- ALC861_FIXUP_FSC_AMILO_PI1505,
- ALC861_FIXUP_AMP_VREF_0F,
- ALC861_FIXUP_NO_JACK_DETECT,
- ALC861_FIXUP_ASUS_A6RP,
- ALC660_FIXUP_ASUS_W7J,
-};
-
-/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
-static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- unsigned int val;
-
- if (action != HDA_FIXUP_ACT_INIT)
- return;
- val = snd_hda_codec_get_pin_target(codec, 0x0f);
- if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
- val |= AC_PINCTL_IN_EN;
- val |= AC_PINCTL_VREF_50;
- snd_hda_set_pin_ctl(codec, 0x0f, val);
- spec->gen.keep_vref_in_automute = 1;
-}
-
-/* suppress the jack-detection */
-static void alc_fixup_no_jack_detect(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- codec->no_jack_detect = 1;
-}
-
-static const struct hda_fixup alc861_fixups[] = {
- [ALC861_FIXUP_FSC_AMILO_PI1505] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x0b, 0x0221101f }, /* HP */
- { 0x0f, 0x90170310 }, /* speaker */
- { }
- }
- },
- [ALC861_FIXUP_AMP_VREF_0F] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc861_fixup_asus_amp_vref_0f,
- },
- [ALC861_FIXUP_NO_JACK_DETECT] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_no_jack_detect,
- },
- [ALC861_FIXUP_ASUS_A6RP] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc861_fixup_asus_amp_vref_0f,
- .chained = true,
- .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
- },
- [ALC660_FIXUP_ASUS_W7J] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* ASUS W7J needs a magic pin setup on unused NID 0x10
- * for enabling outputs
- */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- { }
- },
- }
-};
-
-static const struct snd_pci_quirk alc861_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
- SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
- SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
- SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
- SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
- SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
- SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
- {}
-};
-
-/*
- */
-static int patch_alc861(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x15);
- if (err < 0)
- return err;
-
- spec = codec->spec;
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x23;
-
-#ifdef CONFIG_PM
- spec->power_hook = alc_power_eapd;
-#endif
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- /* automatic parse from the BIOS config */
- err = alc861_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog) {
- err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-/*
- * ALC861-VD support
- *
- * Based on ALC882
- *
- * In addition, an independent DAC
- */
-static int alc861vd_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
- static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
- return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
-}
-
-enum {
- ALC660VD_FIX_ASUS_GPIO1,
- ALC861VD_FIX_DALLAS,
-};
-
-/* exclude VREF80 */
-static void alc861vd_fixup_dallas(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
- snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
- }
-}
-
-/* reset GPIO1 */
-static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
- spec->gpio_mask |= 0x02;
- alc_fixup_gpio(codec, action, 0x01);
-}
-
-static const struct hda_fixup alc861vd_fixups[] = {
- [ALC660VD_FIX_ASUS_GPIO1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc660vd_fixup_asus_gpio1,
- },
- [ALC861VD_FIX_DALLAS] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc861vd_fixup_dallas,
- },
-};
-
-static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
- SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
- SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
- SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
- {}
-};
-
-/*
- */
-static int patch_alc861vd(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x0b);
- if (err < 0)
- return err;
-
- spec = codec->spec;
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x23;
-
- spec->shutup = alc_eapd_shutup;
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- /* automatic parse from the BIOS config */
- err = alc861vd_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog) {
- err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
+ alc269_remove(codec);
return err;
}
-/*
- * ALC662 support
- *
- * ALC662 is almost identical with ALC880 but has cleaner and more flexible
- * configuration. Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs. This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-
-/*
- * BIOS auto configuration
- */
-
-static int alc662_parse_auto_config(struct hda_codec *codec)
-{
- static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
- static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
- static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
- const hda_nid_t *ssids;
-
- if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
- codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
- codec->core.vendor_id == 0x10ec0671)
- ssids = alc663_ssids;
- else
- ssids = alc662_ssids;
- return alc_parse_auto_config(codec, alc662_ignore, ssids);
-}
-
-static void alc272_fixup_mario(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
- (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
- (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
- (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
- (0 << AC_AMPCAP_MUTE_SHIFT)))
- codec_warn(codec, "failed to override amp caps for NID 0x2\n");
-}
-
-static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
- { .channels = 2,
- .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
- { .channels = 4,
- .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
- SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
- { }
-};
-
-/* override the 2.1 chmap */
-static void alc_fixup_bass_chmap(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- if (action == HDA_FIXUP_ACT_BUILD) {
- struct alc_spec *spec = codec->spec;
- spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
- }
-}
-
-/* avoid D3 for keeping GPIO up */
-static unsigned int gpio_led_power_filter(struct hda_codec *codec,
- hda_nid_t nid,
- unsigned int power_state)
-{
- struct alc_spec *spec = codec->spec;
- if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
- return AC_PWRST_D0;
- return power_state;
-}
-
-static void alc662_fixup_led_gpio1(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->mute_led_polarity = 1;
- codec->power_filter = gpio_led_power_filter;
- }
-}
-
-static void alc662_usi_automute_hook(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- struct alc_spec *spec = codec->spec;
- int vref;
- msleep(200);
- snd_hda_gen_hp_automute(codec, jack);
-
- vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
- msleep(100);
- snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- vref);
-}
-
-static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
- spec->gen.hp_automute_hook = alc662_usi_automute_hook;
- }
-}
-
-static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
- struct hda_jack_callback *cb)
-{
- /* surround speakers at 0x1b already get muted automatically when
- * headphones are plugged in, but we have to mute/unmute the remaining
- * channels manually:
- * 0x15 - front left/front right
- * 0x18 - front center/ LFE
- */
- if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
- snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
- snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
- } else {
- snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
- snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
- }
-}
-
-static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- /* Pin 0x1b: shared headphones jack and surround speakers */
- if (!is_jack_detectable(codec, 0x1b))
- return;
-
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- snd_hda_jack_detect_enable_callback(codec, 0x1b,
- alc662_aspire_ethos_mute_speakers);
- /* subwoofer needs an extra GPIO setting to become audible */
- alc_setup_gpio(codec, 0x02);
- break;
- case HDA_FIXUP_ACT_INIT:
- /* Make sure to start in a correct state, i.e. if
- * headphones have been plugged in before powering up the system
- */
- alc662_aspire_ethos_mute_speakers(codec, NULL);
- break;
- }
-}
-
-static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- static const struct hda_pintbl pincfgs[] = {
- { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
- { 0x1b, 0x0181304f },
- { }
- };
-
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- spec->gen.mixer_nid = 0;
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
- snd_hda_apply_pincfgs(codec, pincfgs);
- break;
- case HDA_FIXUP_ACT_INIT:
- alc_write_coef_idx(codec, 0x19, 0xa054);
- break;
- }
-}
-
-static void alc897_hp_automute_hook(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- struct alc_spec *spec = codec->spec;
- int vref;
-
- snd_hda_gen_hp_automute(codec, jack);
- vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
- snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- vref);
-}
-
-static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.hp_automute_hook = alc897_hp_automute_hook;
- }
-}
-
-static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct alc_spec *spec = codec->spec;
-
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
- spec->gen.hp_automute_hook = alc897_hp_automute_hook;
- }
-}
-
-static const struct coef_fw alc668_coefs[] = {
- WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
- WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
- WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b, 0x0),
- WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
- WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
- WRITE_COEF(0x13, 0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
- WRITE_COEF(0x19, 0x0), WRITE_COEF(0x1a, 0x0), WRITE_COEF(0x1b, 0x0),
- WRITE_COEF(0x1c, 0x0), WRITE_COEF(0x1d, 0x0), WRITE_COEF(0x1e, 0x7418),
- WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
- WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
- WRITE_COEF(0x27, 0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
- WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
- WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac, 0x0),
- WRITE_COEF(0xad, 0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
- WRITE_COEF(0xb0, 0x0), WRITE_COEF(0xb1, 0x0), WRITE_COEF(0xb2, 0x0),
- WRITE_COEF(0xb3, 0x0), WRITE_COEF(0xb4, 0x0), WRITE_COEF(0xb5, 0x1040),
- WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
- WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
- WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
- WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
- {}
-};
-
-static void alc668_restore_default_value(struct hda_codec *codec)
-{
- alc_process_coef_fw(codec, alc668_coefs);
-}
-
-enum {
- ALC662_FIXUP_ASPIRE,
- ALC662_FIXUP_LED_GPIO1,
- ALC662_FIXUP_IDEAPAD,
- ALC272_FIXUP_MARIO,
- ALC662_FIXUP_CZC_ET26,
- ALC662_FIXUP_CZC_P10T,
- ALC662_FIXUP_SKU_IGNORE,
- ALC662_FIXUP_HP_RP5800,
- ALC662_FIXUP_ASUS_MODE1,
- ALC662_FIXUP_ASUS_MODE2,
- ALC662_FIXUP_ASUS_MODE3,
- ALC662_FIXUP_ASUS_MODE4,
- ALC662_FIXUP_ASUS_MODE5,
- ALC662_FIXUP_ASUS_MODE6,
- ALC662_FIXUP_ASUS_MODE7,
- ALC662_FIXUP_ASUS_MODE8,
- ALC662_FIXUP_NO_JACK_DETECT,
- ALC662_FIXUP_ZOTAC_Z68,
- ALC662_FIXUP_INV_DMIC,
- ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
- ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
- ALC662_FIXUP_HEADSET_MODE,
- ALC668_FIXUP_HEADSET_MODE,
- ALC662_FIXUP_BASS_MODE4_CHMAP,
- ALC662_FIXUP_BASS_16,
- ALC662_FIXUP_BASS_1A,
- ALC662_FIXUP_BASS_CHMAP,
- ALC668_FIXUP_AUTO_MUTE,
- ALC668_FIXUP_DELL_DISABLE_AAMIX,
- ALC668_FIXUP_DELL_XPS13,
- ALC662_FIXUP_ASUS_Nx50,
- ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
- ALC668_FIXUP_ASUS_Nx51,
- ALC668_FIXUP_MIC_COEF,
- ALC668_FIXUP_ASUS_G751,
- ALC891_FIXUP_HEADSET_MODE,
- ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
- ALC662_FIXUP_ACER_VERITON,
- ALC892_FIXUP_ASROCK_MOBO,
- ALC662_FIXUP_USI_FUNC,
- ALC662_FIXUP_USI_HEADSET_MODE,
- ALC662_FIXUP_LENOVO_MULTI_CODECS,
- ALC669_FIXUP_ACER_ASPIRE_ETHOS,
- ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
- ALC671_FIXUP_HP_HEADSET_MIC2,
- ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
- ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
- ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
- ALC668_FIXUP_HEADSET_MIC,
- ALC668_FIXUP_MIC_DET_COEF,
- ALC897_FIXUP_LENOVO_HEADSET_MIC,
- ALC897_FIXUP_HEADSET_MIC_PIN,
- ALC897_FIXUP_HP_HSMIC_VERB,
- ALC897_FIXUP_LENOVO_HEADSET_MODE,
- ALC897_FIXUP_HEADSET_MIC_PIN2,
-};
-
-static const struct hda_fixup alc662_fixups[] = {
- [ALC662_FIXUP_ASPIRE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x99130112 }, /* subwoofer */
- { }
- }
- },
- [ALC662_FIXUP_LED_GPIO1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc662_fixup_led_gpio1,
- },
- [ALC662_FIXUP_IDEAPAD] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x17, 0x99130112 }, /* subwoofer */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_LED_GPIO1,
- },
- [ALC272_FIXUP_MARIO] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc272_fixup_mario,
- },
- [ALC662_FIXUP_CZC_ET26] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- {0x12, 0x403cc000},
- {0x14, 0x90170110}, /* speaker */
- {0x15, 0x411111f0},
- {0x16, 0x411111f0},
- {0x18, 0x01a19030}, /* mic */
- {0x19, 0x90a7013f}, /* int-mic */
- {0x1a, 0x01014020},
- {0x1b, 0x0121401f},
- {0x1c, 0x411111f0},
- {0x1d, 0x411111f0},
- {0x1e, 0x40478e35},
- {}
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_CZC_P10T] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
- {}
- }
- },
- [ALC662_FIXUP_SKU_IGNORE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_sku_ignore,
- },
- [ALC662_FIXUP_HP_RP5800] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x0221201f }, /* HP out */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE1] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x18, 0x01a19c20 }, /* mic */
- { 0x19, 0x99a3092f }, /* int-mic */
- { 0x21, 0x0121401f }, /* HP out */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE2] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x18, 0x01a19820 }, /* mic */
- { 0x19, 0x99a3092f }, /* int-mic */
- { 0x1b, 0x0121401f }, /* HP out */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE3] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x15, 0x0121441f }, /* HP */
- { 0x18, 0x01a19840 }, /* mic */
- { 0x19, 0x99a3094f }, /* int-mic */
- { 0x21, 0x01211420 }, /* HP2 */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE4] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x16, 0x99130111 }, /* speaker */
- { 0x18, 0x01a19840 }, /* mic */
- { 0x19, 0x99a3094f }, /* int-mic */
- { 0x21, 0x0121441f }, /* HP */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE5] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x15, 0x0121441f }, /* HP */
- { 0x16, 0x99130111 }, /* speaker */
- { 0x18, 0x01a19840 }, /* mic */
- { 0x19, 0x99a3094f }, /* int-mic */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE6] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x15, 0x01211420 }, /* HP2 */
- { 0x18, 0x01a19840 }, /* mic */
- { 0x19, 0x99a3094f }, /* int-mic */
- { 0x1b, 0x0121441f }, /* HP */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE7] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x17, 0x99130111 }, /* speaker */
- { 0x18, 0x01a19840 }, /* mic */
- { 0x19, 0x99a3094f }, /* int-mic */
- { 0x1b, 0x01214020 }, /* HP */
- { 0x21, 0x0121401f }, /* HP */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_ASUS_MODE8] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x14, 0x99130110 }, /* speaker */
- { 0x12, 0x99a30970 }, /* int-mic */
- { 0x15, 0x01214020 }, /* HP */
- { 0x17, 0x99130111 }, /* speaker */
- { 0x18, 0x01a19840 }, /* mic */
- { 0x21, 0x0121401f }, /* HP */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_SKU_IGNORE
- },
- [ALC662_FIXUP_NO_JACK_DETECT] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_no_jack_detect,
- },
- [ALC662_FIXUP_ZOTAC_Z68] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1b, 0x02214020 }, /* Front HP */
- { }
- }
- },
- [ALC662_FIXUP_INV_DMIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_inv_dmic,
- },
- [ALC668_FIXUP_DELL_XPS13] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_dell_xps13,
- .chained = true,
- .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
- },
- [ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_disable_aamix,
- .chained = true,
- .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
- },
- [ALC668_FIXUP_AUTO_MUTE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_auto_mute_via_amp,
- .chained = true,
- .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
- },
- [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
- /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_HEADSET_MODE
- },
- [ALC662_FIXUP_HEADSET_MODE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_headset_mode_alc662,
- },
- [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
- { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
- { }
- },
- .chained = true,
- .chain_id = ALC668_FIXUP_HEADSET_MODE
- },
- [ALC668_FIXUP_HEADSET_MODE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_headset_mode_alc668,
- },
- [ALC662_FIXUP_BASS_MODE4_CHMAP] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_bass_chmap,
- .chained = true,
- .chain_id = ALC662_FIXUP_ASUS_MODE4
- },
- [ALC662_FIXUP_BASS_16] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- {0x16, 0x80106111}, /* bass speaker */
- {}
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_BASS_CHMAP,
- },
- [ALC662_FIXUP_BASS_1A] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- {0x1a, 0x80106111}, /* bass speaker */
- {}
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_BASS_CHMAP,
- },
- [ALC662_FIXUP_BASS_CHMAP] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_bass_chmap,
- },
- [ALC662_FIXUP_ASUS_Nx50] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_auto_mute_via_amp,
- .chained = true,
- .chain_id = ALC662_FIXUP_BASS_1A
- },
- [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_headset_mode_alc668,
- .chain_id = ALC662_FIXUP_BASS_CHMAP
- },
- [ALC668_FIXUP_ASUS_Nx51] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
- { 0x1a, 0x90170151 }, /* bass speaker */
- { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
- {}
- },
- .chained = true,
- .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
- },
- [ALC668_FIXUP_MIC_COEF] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
- {}
- },
- },
- [ALC668_FIXUP_ASUS_G751] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x16, 0x0421101f }, /* HP */
- {}
- },
- .chained = true,
- .chain_id = ALC668_FIXUP_MIC_COEF
- },
- [ALC891_FIXUP_HEADSET_MODE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc_fixup_headset_mode,
- },
- [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
- { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
- { }
- },
- .chained = true,
- .chain_id = ALC891_FIXUP_HEADSET_MODE
- },
- [ALC662_FIXUP_ACER_VERITON] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x50170120 }, /* no internal speaker */
- { }
- }
- },
- [ALC892_FIXUP_ASROCK_MOBO] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x40f000f0 }, /* disabled */
- { 0x16, 0x40f000f0 }, /* disabled */
- { }
- }
- },
- [ALC662_FIXUP_USI_FUNC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc662_fixup_usi_headset_mic,
- },
- [ALC662_FIXUP_USI_HEADSET_MODE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
- { 0x18, 0x01a1903d },
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_USI_FUNC
- },
- [ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
- },
- [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc662_fixup_aspire_ethos_hp,
- },
- [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x15, 0x92130110 }, /* front speakers */
- { 0x18, 0x99130111 }, /* center/subwoofer */
- { 0x1b, 0x11130012 }, /* surround plus jack for HP */
- { }
- },
- .chained = true,
- .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
- },
- [ALC671_FIXUP_HP_HEADSET_MIC2] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc671_fixup_hp_headset_mic2,
- },
- [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_USI_FUNC
- },
- [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
- { 0x1b, 0x0221144f },
- { }
- },
- .chained = true,
- .chain_id = ALC662_FIXUP_USI_FUNC
- },
- [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1b, 0x04a1112c },
- { }
- },
- .chained = true,
- .chain_id = ALC668_FIXUP_HEADSET_MIC
- },
- [ALC668_FIXUP_HEADSET_MIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc269_fixup_headset_mic,
- .chained = true,
- .chain_id = ALC668_FIXUP_MIC_DET_COEF
- },
- [ALC668_FIXUP_MIC_DET_COEF] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
- { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
- {}
- },
- },
- [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc897_fixup_lenovo_headset_mic,
- },
- [ALC897_FIXUP_HEADSET_MIC_PIN] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1a, 0x03a11050 },
- { }
- },
- .chained = true,
- .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
- },
- [ALC897_FIXUP_HP_HSMIC_VERB] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
- { }
- },
- },
- [ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc897_fixup_lenovo_headset_mode,
- },
- [ALC897_FIXUP_HEADSET_MIC_PIN2] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
- { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
- { }
- },
- .chained = true,
- .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
- },
-};
-
-static const struct snd_pci_quirk alc662_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
- SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
- SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
- SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
- SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
- SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
- SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
- SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
- SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
- SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
- SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
- SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
- SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
- SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
- SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
- SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
- SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
- SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
- SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
- SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
- SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
- SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
- SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
- SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
- SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
- SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
- SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
- SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
- SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
- SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
- SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
- SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
- SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
- SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
- SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
- SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
- SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
- SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
- SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
- SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
- SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
- SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
- SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
- SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
- SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
- SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
- SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
-
-#if 0
- /* Below is a quirk table taken from the old code.
- * Basically the device should work as is without the fixup table.
- * If BIOS doesn't give a proper info, enable the corresponding
- * fixup entry.
- */
- SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
- SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
- SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
- SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
- SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
- SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
- SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
- SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
-#endif
- {}
-};
-
-static const struct hda_model_fixup alc662_fixup_models[] = {
- {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
- {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
- {.id = ALC272_FIXUP_MARIO, .name = "mario"},
- {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
- {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
- {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
- {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
- {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
- {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
- {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
- {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
- {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
- {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
- {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
- {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
- {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
- {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
- {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
- {.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
- {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
- {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
- {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
- {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
- {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
- {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
- {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
- {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
- {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
- {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
- {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
- {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
- {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
- {}
-};
-
-static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
- SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
- {0x17, 0x02211010},
- {0x18, 0x01a19030},
- {0x1a, 0x01813040},
- {0x21, 0x01014020}),
- SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
- {0x16, 0x01813030},
- {0x17, 0x02211010},
- {0x18, 0x01a19040},
- {0x21, 0x01014020}),
- SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
- {0x14, 0x01014010},
- {0x18, 0x01a19020},
- {0x1a, 0x0181302f},
- {0x1b, 0x0221401f}),
- SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
- {0x12, 0x99a30130},
- {0x14, 0x90170110},
- {0x15, 0x0321101f},
- {0x16, 0x03011020}),
- SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
- {0x12, 0x99a30140},
- {0x14, 0x90170110},
- {0x15, 0x0321101f},
- {0x16, 0x03011020}),
- SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
- {0x12, 0x99a30150},
- {0x14, 0x90170110},
- {0x15, 0x0321101f},
- {0x16, 0x03011020}),
- SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
- {0x14, 0x90170110},
- {0x15, 0x0321101f},
- {0x16, 0x03011020}),
- SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
- {0x12, 0x90a60130},
- {0x14, 0x90170110},
- {0x15, 0x0321101f}),
- SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
- {0x14, 0x01014010},
- {0x17, 0x90170150},
- {0x19, 0x02a11060},
- {0x1b, 0x01813030},
- {0x21, 0x02211020}),
- SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
- {0x14, 0x01014010},
- {0x18, 0x01a19040},
- {0x1b, 0x01813030},
- {0x21, 0x02211020}),
- SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
- {0x14, 0x01014020},
- {0x17, 0x90170110},
- {0x18, 0x01a19050},
- {0x1b, 0x01813040},
- {0x21, 0x02211030}),
- {}
+static const struct hda_codec_ops alc269_codec_ops = {
+ .probe = alc269_probe,
+ .remove = alc269_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = alc269_suspend,
+ .resume = alc269_resume,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
};
/*
+ * driver entries
*/
-static int patch_alc662(struct hda_codec *codec)
-{
- struct alc_spec *spec;
- int err;
-
- err = alc_alloc_spec(codec, 0x0b);
- if (err < 0)
- return err;
-
- spec = codec->spec;
-
- spec->shutup = alc_eapd_shutup;
-
- /* handle multiple HPs as is */
- spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
-
- alc_fix_pll_init(codec, 0x20, 0x04, 15);
-
- switch (codec->core.vendor_id) {
- case 0x10ec0668:
- spec->init_hook = alc668_restore_default_value;
- break;
- }
-
- alc_pre_init(codec);
-
- snd_hda_pick_fixup(codec, alc662_fixup_models,
- alc662_fixup_tbl, alc662_fixups);
- snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- alc_auto_parse_customize_define(codec);
-
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x01;
-
- if ((alc_get_coef0(codec) & (1 << 14)) &&
- codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1) {
- err = alc_codec_rename(codec, "ALC272X");
- if (err < 0)
- goto error;
- }
-
- /* automatic parse from the BIOS config */
- err = alc662_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- if (!spec->gen.no_analog && spec->gen.beep_nid) {
- switch (codec->core.vendor_id) {
- case 0x10ec0662:
- err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- break;
- case 0x10ec0272:
- case 0x10ec0663:
- case 0x10ec0665:
- case 0x10ec0668:
- err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
- break;
- case 0x10ec0273:
- err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
- break;
- }
- if (err < 0)
- goto error;
- }
-
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
- return 0;
-
- error:
- alc_free(codec);
- return err;
-}
-
-/*
- * ALC680 support
- */
-
-static int alc680_parse_auto_config(struct hda_codec *codec)
-{
- return alc_parse_auto_config(codec, NULL, NULL);
-}
-
-/*
- */
-static int patch_alc680(struct hda_codec *codec)
-{
- int err;
-
- /* ALC680 has no aa-loopback mixer */
- err = alc_alloc_spec(codec, 0);
- if (err < 0)
- return err;
-
- /* automatic parse from the BIOS config */
- err = alc680_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
-
- return 0;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_realtek[] = {
- HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0230, "ALC236", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
- HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
- HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
- HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
- HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0287, "ALC287", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0289, "ALC289", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269),
- HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
- HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
- HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
- HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
- HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
- HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
- HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
- HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269),
- HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
- HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
- HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
- HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
- HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
- HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
- HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
- HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269),
+static const struct hda_device_id snd_hda_id_alc269[] = {
+ HDA_CODEC_ID(0x10ec0215, "ALC215"),
+ HDA_CODEC_ID(0x10ec0221, "ALC221"),
+ HDA_CODEC_ID(0x10ec0222, "ALC222"),
+ HDA_CODEC_ID(0x10ec0225, "ALC225"),
+ HDA_CODEC_ID(0x10ec0230, "ALC236"),
+ HDA_CODEC_ID(0x10ec0231, "ALC231"),
+ HDA_CODEC_ID(0x10ec0233, "ALC233"),
+ HDA_CODEC_ID(0x10ec0234, "ALC234"),
+ HDA_CODEC_ID(0x10ec0235, "ALC233"),
+ HDA_CODEC_ID(0x10ec0236, "ALC236"),
+ HDA_CODEC_ID(0x10ec0245, "ALC245"),
+ HDA_CODEC_ID(0x10ec0255, "ALC255"),
+ HDA_CODEC_ID(0x10ec0256, "ALC256"),
+ HDA_CODEC_ID(0x10ec0257, "ALC257"),
+ HDA_CODEC_ID(0x10ec0269, "ALC269"),
+ HDA_CODEC_ID(0x10ec0270, "ALC270"),
+ HDA_CODEC_ID(0x10ec0274, "ALC274"),
+ HDA_CODEC_ID(0x10ec0275, "ALC275"),
+ HDA_CODEC_ID(0x10ec0276, "ALC276"),
+ HDA_CODEC_ID(0x10ec0280, "ALC280"),
+ HDA_CODEC_ID(0x10ec0282, "ALC282"),
+ HDA_CODEC_ID(0x10ec0283, "ALC283"),
+ HDA_CODEC_ID(0x10ec0284, "ALC284"),
+ HDA_CODEC_ID(0x10ec0285, "ALC285"),
+ HDA_CODEC_ID(0x10ec0286, "ALC286"),
+ HDA_CODEC_ID(0x10ec0287, "ALC287"),
+ HDA_CODEC_ID(0x10ec0288, "ALC288"),
+ HDA_CODEC_ID(0x10ec0289, "ALC289"),
+ HDA_CODEC_ID(0x10ec0290, "ALC290"),
+ HDA_CODEC_ID(0x10ec0292, "ALC292"),
+ HDA_CODEC_ID(0x10ec0293, "ALC293"),
+ HDA_CODEC_ID(0x10ec0294, "ALC294"),
+ HDA_CODEC_ID(0x10ec0295, "ALC295"),
+ HDA_CODEC_ID(0x10ec0298, "ALC298"),
+ HDA_CODEC_ID(0x10ec0299, "ALC299"),
+ HDA_CODEC_ID(0x10ec0300, "ALC300"),
+ HDA_CODEC_ID(0x10ec0623, "ALC623"),
+ HDA_CODEC_ID(0x10ec0700, "ALC700"),
+ HDA_CODEC_ID(0x10ec0701, "ALC701"),
+ HDA_CODEC_ID(0x10ec0703, "ALC703"),
+ HDA_CODEC_ID(0x10ec0711, "ALC711"),
+ HDA_CODEC_ID(0x19e58326, "HW8326"),
{} /* terminator */
};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc269);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Realtek HD-audio codec");
+MODULE_DESCRIPTION("Realtek ALC269 and compatible HD-audio codecs");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
-static struct hda_codec_driver realtek_driver = {
- .id = snd_hda_id_realtek,
+static struct hda_codec_driver alc269_driver = {
+ .id = snd_hda_id_alc269,
+ .ops = &alc269_codec_ops,
};
-module_hda_codec_driver(realtek_driver);
+module_hda_codec_driver(alc269_driver);
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
new file mode 100644
index 000000000000..5073165d1f3c
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -0,0 +1,1116 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC662 and compatible codecs
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/*
+ * ALC662 support
+ *
+ * ALC662 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration. Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs. This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+
+/*
+ * BIOS auto configuration
+ */
+
+static int alc662_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
+ static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ const hda_nid_t *ssids;
+
+ if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
+ codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
+ codec->core.vendor_id == 0x10ec0671)
+ ssids = alc663_ssids;
+ else
+ ssids = alc662_ssids;
+ return alc_parse_auto_config(codec, alc662_ignore, ssids);
+}
+
+static void alc272_fixup_mario(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
+ (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (0 << AC_AMPCAP_MUTE_SHIFT)))
+ codec_warn(codec, "failed to override amp caps for NID 0x2\n");
+}
+
+/* avoid D3 for keeping GPIO up */
+static unsigned int gpio_led_power_filter(struct hda_codec *codec,
+ hda_nid_t nid,
+ unsigned int power_state)
+{
+ struct alc_spec *spec = codec->spec;
+ if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
+ return AC_PWRST_D0;
+ return power_state;
+}
+
+static void alc662_fixup_led_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->mute_led_polarity = 1;
+ codec->power_filter = gpio_led_power_filter;
+ }
+}
+
+static void alc662_usi_automute_hook(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ struct alc_spec *spec = codec->spec;
+ int vref;
+ msleep(200);
+ snd_hda_gen_hp_automute(codec, jack);
+
+ vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+ msleep(100);
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ vref);
+}
+
+static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ spec->gen.hp_automute_hook = alc662_usi_automute_hook;
+ }
+}
+
+static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
+ struct hda_jack_callback *cb)
+{
+ /* surround speakers at 0x1b already get muted automatically when
+ * headphones are plugged in, but we have to mute/unmute the remaining
+ * channels manually:
+ * 0x15 - front left/front right
+ * 0x18 - front center/ LFE
+ */
+ if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
+ snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
+ snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+ } else {
+ snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
+ snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
+ }
+}
+
+static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /* Pin 0x1b: shared headphones jack and surround speakers */
+ if (!is_jack_detectable(codec, 0x1b))
+ return;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_jack_detect_enable_callback(codec, 0x1b,
+ alc662_aspire_ethos_mute_speakers);
+ /* subwoofer needs an extra GPIO setting to become audible */
+ alc_setup_gpio(codec, 0x02);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /* Make sure to start in a correct state, i.e. if
+ * headphones have been plugged in before powering up the system
+ */
+ alc662_aspire_ethos_mute_speakers(codec, NULL);
+ break;
+ }
+}
+
+static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ static const struct hda_pintbl pincfgs[] = {
+ { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
+ { 0x1b, 0x0181304f },
+ { }
+ };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.mixer_nid = 0;
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ snd_hda_apply_pincfgs(codec, pincfgs);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ alc_write_coef_idx(codec, 0x19, 0xa054);
+ break;
+ }
+}
+
+static void alc897_hp_automute_hook(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ struct alc_spec *spec = codec->spec;
+ int vref;
+
+ snd_hda_gen_hp_automute(codec, jack);
+ vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
+ snd_hda_set_pin_ctl(codec, 0x1b, vref);
+}
+
+static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+ spec->no_shutup_pins = 1;
+ }
+ if (action == HDA_FIXUP_ACT_PROBE) {
+ snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
+ }
+}
+
+static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+ }
+}
+
+static const struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+ WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b, 0x0),
+ WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
+ WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0x13, 0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
+ WRITE_COEF(0x19, 0x0), WRITE_COEF(0x1a, 0x0), WRITE_COEF(0x1b, 0x0),
+ WRITE_COEF(0x1c, 0x0), WRITE_COEF(0x1d, 0x0), WRITE_COEF(0x1e, 0x7418),
+ WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
+ WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
+ WRITE_COEF(0x27, 0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
+ WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
+ WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac, 0x0),
+ WRITE_COEF(0xad, 0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
+ WRITE_COEF(0xb0, 0x0), WRITE_COEF(0xb1, 0x0), WRITE_COEF(0xb2, 0x0),
+ WRITE_COEF(0xb3, 0x0), WRITE_COEF(0xb4, 0x0), WRITE_COEF(0xb5, 0x1040),
+ WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
+ WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
+ WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
+ WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
+ {}
+};
+
+static void alc668_restore_default_value(struct hda_codec *codec)
+{
+ alc_process_coef_fw(codec, alc668_coefs);
+}
+
+static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
+
+ /* Disable boost for mic-in permanently. (This code is only called
+ from quirks that guarantee that the headphone is at NID 0x1b.) */
+ snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
+ snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
+ } else
+ alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ alc_write_coef_idx(codec, 0xc4, 0x8000);
+ alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
+ snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+ }
+ alc_fixup_headset_mode(codec, fix, action);
+}
+
+enum {
+ ALC662_FIXUP_ASPIRE,
+ ALC662_FIXUP_LED_GPIO1,
+ ALC662_FIXUP_IDEAPAD,
+ ALC272_FIXUP_MARIO,
+ ALC662_FIXUP_CZC_ET26,
+ ALC662_FIXUP_CZC_P10T,
+ ALC662_FIXUP_SKU_IGNORE,
+ ALC662_FIXUP_HP_RP5800,
+ ALC662_FIXUP_ASUS_MODE1,
+ ALC662_FIXUP_ASUS_MODE2,
+ ALC662_FIXUP_ASUS_MODE3,
+ ALC662_FIXUP_ASUS_MODE4,
+ ALC662_FIXUP_ASUS_MODE5,
+ ALC662_FIXUP_ASUS_MODE6,
+ ALC662_FIXUP_ASUS_MODE7,
+ ALC662_FIXUP_ASUS_MODE8,
+ ALC662_FIXUP_NO_JACK_DETECT,
+ ALC662_FIXUP_ZOTAC_Z68,
+ ALC662_FIXUP_INV_DMIC,
+ ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+ ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+ ALC662_FIXUP_HEADSET_MODE,
+ ALC668_FIXUP_HEADSET_MODE,
+ ALC662_FIXUP_BASS_MODE4_CHMAP,
+ ALC662_FIXUP_BASS_16,
+ ALC662_FIXUP_BASS_1A,
+ ALC662_FIXUP_BASS_CHMAP,
+ ALC668_FIXUP_AUTO_MUTE,
+ ALC668_FIXUP_DELL_DISABLE_AAMIX,
+ ALC668_FIXUP_DELL_XPS13,
+ ALC662_FIXUP_ASUS_Nx50,
+ ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
+ ALC668_FIXUP_ASUS_Nx51,
+ ALC668_FIXUP_MIC_COEF,
+ ALC668_FIXUP_ASUS_G751,
+ ALC891_FIXUP_HEADSET_MODE,
+ ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+ ALC662_FIXUP_ACER_VERITON,
+ ALC892_FIXUP_ASROCK_MOBO,
+ ALC662_FIXUP_USI_FUNC,
+ ALC662_FIXUP_USI_HEADSET_MODE,
+ ALC662_FIXUP_LENOVO_MULTI_CODECS,
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS,
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
+ ALC671_FIXUP_HP_HEADSET_MIC2,
+ ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
+ ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
+ ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
+ ALC668_FIXUP_HEADSET_MIC,
+ ALC668_FIXUP_MIC_DET_COEF,
+ ALC897_FIXUP_LENOVO_HEADSET_MIC,
+ ALC897_FIXUP_HEADSET_MIC_PIN,
+ ALC897_FIXUP_HP_HSMIC_VERB,
+ ALC897_FIXUP_LENOVO_HEADSET_MODE,
+ ALC897_FIXUP_HEADSET_MIC_PIN2,
+ ALC897_FIXUP_UNIS_H3C_X500S,
+ ALC897_FIXUP_HEADSET_MIC_PIN3,
+};
+
+static const struct hda_fixup alc662_fixups[] = {
+ [ALC662_FIXUP_ASPIRE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x99130112 }, /* subwoofer */
+ { }
+ }
+ },
+ [ALC662_FIXUP_LED_GPIO1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc662_fixup_led_gpio1,
+ },
+ [ALC662_FIXUP_IDEAPAD] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x99130112 }, /* subwoofer */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_LED_GPIO1,
+ },
+ [ALC272_FIXUP_MARIO] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc272_fixup_mario,
+ },
+ [ALC662_FIXUP_CZC_ET26] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x12, 0x403cc000},
+ {0x14, 0x90170110}, /* speaker */
+ {0x15, 0x411111f0},
+ {0x16, 0x411111f0},
+ {0x18, 0x01a19030}, /* mic */
+ {0x19, 0x90a7013f}, /* int-mic */
+ {0x1a, 0x01014020},
+ {0x1b, 0x0121401f},
+ {0x1c, 0x411111f0},
+ {0x1d, 0x411111f0},
+ {0x1e, 0x40478e35},
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_CZC_P10T] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+ {}
+ }
+ },
+ [ALC662_FIXUP_SKU_IGNORE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_sku_ignore,
+ },
+ [ALC662_FIXUP_HP_RP5800] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x0221201f }, /* HP out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE1] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x18, 0x01a19c20 }, /* mic */
+ { 0x19, 0x99a3092f }, /* int-mic */
+ { 0x21, 0x0121401f }, /* HP out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE2] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x18, 0x01a19820 }, /* mic */
+ { 0x19, 0x99a3092f }, /* int-mic */
+ { 0x1b, 0x0121401f }, /* HP out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE3] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0121441f }, /* HP */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x21, 0x01211420 }, /* HP2 */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE4] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x16, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x21, 0x0121441f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE5] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0121441f }, /* HP */
+ { 0x16, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE6] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x01211420 }, /* HP2 */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x1b, 0x0121441f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE7] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x17, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x1b, 0x01214020 }, /* HP */
+ { 0x21, 0x0121401f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE8] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x12, 0x99a30970 }, /* int-mic */
+ { 0x15, 0x01214020 }, /* HP */
+ { 0x17, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x21, 0x0121401f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_NO_JACK_DETECT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_no_jack_detect,
+ },
+ [ALC662_FIXUP_ZOTAC_Z68] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x02214020 }, /* Front HP */
+ { }
+ }
+ },
+ [ALC662_FIXUP_INV_DMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_inv_dmic,
+ },
+ [ALC668_FIXUP_DELL_XPS13] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_dell_xps13,
+ .chained = true,
+ .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
+ },
+ [ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_disable_aamix,
+ .chained = true,
+ .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+ },
+ [ALC668_FIXUP_AUTO_MUTE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_auto_mute_via_amp,
+ .chained = true,
+ .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+ },
+ [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+ /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_HEADSET_MODE
+ },
+ [ALC662_FIXUP_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode_alc662,
+ },
+ [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+ { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC668_FIXUP_HEADSET_MODE
+ },
+ [ALC668_FIXUP_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode_alc668,
+ },
+ [ALC662_FIXUP_BASS_MODE4_CHMAP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_bass_chmap,
+ .chained = true,
+ .chain_id = ALC662_FIXUP_ASUS_MODE4
+ },
+ [ALC662_FIXUP_BASS_16] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x16, 0x80106111}, /* bass speaker */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_BASS_CHMAP,
+ },
+ [ALC662_FIXUP_BASS_1A] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x1a, 0x80106111}, /* bass speaker */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_BASS_CHMAP,
+ },
+ [ALC662_FIXUP_BASS_CHMAP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_bass_chmap,
+ },
+ [ALC662_FIXUP_ASUS_Nx50] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_auto_mute_via_amp,
+ .chained = true,
+ .chain_id = ALC662_FIXUP_BASS_1A
+ },
+ [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode_alc668,
+ .chain_id = ALC662_FIXUP_BASS_CHMAP
+ },
+ [ALC668_FIXUP_ASUS_Nx51] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+ { 0x1a, 0x90170151 }, /* bass speaker */
+ { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
+ },
+ [ALC668_FIXUP_MIC_COEF] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
+ {}
+ },
+ },
+ [ALC668_FIXUP_ASUS_G751] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x0421101f }, /* HP */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC668_FIXUP_MIC_COEF
+ },
+ [ALC891_FIXUP_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode,
+ },
+ [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+ { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC891_FIXUP_HEADSET_MODE
+ },
+ [ALC662_FIXUP_ACER_VERITON] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x50170120 }, /* no internal speaker */
+ { }
+ }
+ },
+ [ALC892_FIXUP_ASROCK_MOBO] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x40f000f0 }, /* disabled */
+ { 0x16, 0x40f000f0 }, /* disabled */
+ { }
+ }
+ },
+ [ALC662_FIXUP_USI_FUNC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc662_fixup_usi_headset_mic,
+ },
+ [ALC662_FIXUP_USI_HEADSET_MODE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
+ { 0x18, 0x01a1903d },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_USI_FUNC
+ },
+ [ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+ },
+ [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc662_fixup_aspire_ethos_hp,
+ },
+ [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x92130110 }, /* front speakers */
+ { 0x18, 0x99130111 }, /* center/subwoofer */
+ { 0x1b, 0x11130012 }, /* surround plus jack for HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
+ },
+ [ALC671_FIXUP_HP_HEADSET_MIC2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc671_fixup_hp_headset_mic2,
+ },
+ [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_USI_FUNC
+ },
+ [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+ { 0x1b, 0x0221144f },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_USI_FUNC
+ },
+ [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x04a1112c },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC668_FIXUP_HEADSET_MIC
+ },
+ [ALC668_FIXUP_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mic,
+ .chained = true,
+ .chain_id = ALC668_FIXUP_MIC_DET_COEF
+ },
+ [ALC668_FIXUP_MIC_DET_COEF] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
+ {}
+ },
+ },
+ [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc897_fixup_lenovo_headset_mic,
+ },
+ [ALC897_FIXUP_HEADSET_MIC_PIN] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x03a11050 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
+ },
+ [ALC897_FIXUP_HP_HSMIC_VERB] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ },
+ [ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc897_fixup_lenovo_headset_mode,
+ },
+ [ALC897_FIXUP_HEADSET_MIC_PIN2] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
+ },
+ [ALC897_FIXUP_UNIS_H3C_X500S] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
+ {}
+ },
+ },
+ [ALC897_FIXUP_HEADSET_MIC_PIN3] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x03a11050 }, /* use as headset mic */
+ { }
+ },
+ },
+};
+
+static const struct hda_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
+ SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+ SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
+ SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
+ SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
+ SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
+ SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+ SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+ SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
+ SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
+ SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
+ SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
+ SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
+ SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
+ SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
+ SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+ SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
+ SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
+ SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
+ SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
+ SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
+ SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+ SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
+ SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
+ SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
+ SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
+ SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
+ SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
+ SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
+ SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
+ SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
+
+#if 0
+ /* Below is a quirk table taken from the old code.
+ * Basically the device should work as is without the fixup table.
+ * If BIOS doesn't give a proper info, enable the corresponding
+ * fixup entry.
+ */
+ SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
+ SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
+ SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
+ SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+ SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+ SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
+ SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+ SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
+#endif
+ {}
+};
+
+static const struct hda_model_fixup alc662_fixup_models[] = {
+ {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
+ {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
+ {.id = ALC272_FIXUP_MARIO, .name = "mario"},
+ {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
+ {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
+ {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
+ {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
+ {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
+ {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
+ {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
+ {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
+ {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
+ {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
+ {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
+ {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+ {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
+ {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
+ {.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
+ {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
+ {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
+ {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
+ {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
+ {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+ {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
+ {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
+ {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
+ {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
+ {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
+ {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
+ {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
+ {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
+ {.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
+ {}
+};
+
+static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
+ SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+ {0x17, 0x02211010},
+ {0x18, 0x01a19030},
+ {0x1a, 0x01813040},
+ {0x21, 0x01014020}),
+ SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+ {0x16, 0x01813030},
+ {0x17, 0x02211010},
+ {0x18, 0x01a19040},
+ {0x21, 0x01014020}),
+ SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+ {0x14, 0x01014010},
+ {0x18, 0x01a19020},
+ {0x1a, 0x0181302f},
+ {0x1b, 0x0221401f}),
+ SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+ {0x12, 0x99a30130},
+ {0x14, 0x90170110},
+ {0x15, 0x0321101f},
+ {0x16, 0x03011020}),
+ SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+ {0x12, 0x99a30140},
+ {0x14, 0x90170110},
+ {0x15, 0x0321101f},
+ {0x16, 0x03011020}),
+ SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+ {0x12, 0x99a30150},
+ {0x14, 0x90170110},
+ {0x15, 0x0321101f},
+ {0x16, 0x03011020}),
+ SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+ {0x14, 0x90170110},
+ {0x15, 0x0321101f},
+ {0x16, 0x03011020}),
+ SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
+ {0x12, 0x90a60130},
+ {0x14, 0x90170110},
+ {0x15, 0x0321101f}),
+ SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+ {0x14, 0x01014010},
+ {0x17, 0x90170150},
+ {0x19, 0x02a11060},
+ {0x1b, 0x01813030},
+ {0x21, 0x02211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+ {0x14, 0x01014010},
+ {0x18, 0x01a19040},
+ {0x1b, 0x01813030},
+ {0x21, 0x02211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+ {0x14, 0x01014020},
+ {0x17, 0x90170110},
+ {0x18, 0x01a19050},
+ {0x1b, 0x01813040},
+ {0x21, 0x02211030}),
+ {}
+};
+
+/*
+ */
+static int alc662_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+
+ spec->shutup = alc_eapd_shutup;
+
+ /* handle multiple HPs as is */
+ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+
+ alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0668:
+ spec->init_hook = alc668_restore_default_value;
+ break;
+ }
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, alc662_fixup_models,
+ alc662_fixup_tbl, alc662_fixups);
+ snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ alc_auto_parse_customize_define(codec);
+
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x01;
+
+ if ((alc_get_coef0(codec) & (1 << 14)) &&
+ codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
+ spec->cdefine.platform_type == 1) {
+ err = alc_codec_rename(codec, "ALC272X");
+ if (err < 0)
+ goto error;
+ }
+
+ /* automatic parse from the BIOS config */
+ err = alc662_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ switch (codec->core.vendor_id) {
+ case 0x10ec0662:
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ break;
+ case 0x10ec0272:
+ case 0x10ec0663:
+ case 0x10ec0665:
+ case 0x10ec0668:
+ err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+ break;
+ case 0x10ec0273:
+ err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+ break;
+ }
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc662_codec_ops = {
+ .probe = alc662_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc662[] = {
+ HDA_CODEC_ID(0x10ec0272, "ALC272"),
+ HDA_CODEC_ID_REV(0x10ec0662, 0x100101, "ALC662 rev1"),
+ HDA_CODEC_ID_REV(0x10ec0662, 0x100300, "ALC662 rev3"),
+ HDA_CODEC_ID(0x10ec0663, "ALC663"),
+ HDA_CODEC_ID(0x10ec0665, "ALC665"),
+ HDA_CODEC_ID(0x10ec0667, "ALC667"),
+ HDA_CODEC_ID(0x10ec0668, "ALC668"),
+ HDA_CODEC_ID(0x10ec0670, "ALC670"),
+ HDA_CODEC_ID(0x10ec0671, "ALC671"),
+ HDA_CODEC_ID(0x10ec0867, "ALC891"),
+ HDA_CODEC_ID(0x10ec0892, "ALC892"),
+ HDA_CODEC_ID(0x10ec0897, "ALC897"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc662);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC662 and compatible HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc662_driver = {
+ .id = snd_hda_id_alc662,
+ .ops = &alc662_codec_ops,
+};
+
+module_hda_codec_driver(alc662_driver);
diff --git a/sound/hda/codecs/realtek/alc680.c b/sound/hda/codecs/realtek/alc680.c
new file mode 100644
index 000000000000..8aab1026243c
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc680.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC680 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc680_parse_auto_config(struct hda_codec *codec)
+{
+ return alc_parse_auto_config(codec, NULL, NULL);
+}
+
+/*
+ */
+static int alc680_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ int err;
+
+ /* ALC680 has no aa-loopback mixer */
+ err = alc_alloc_spec(codec, 0);
+ if (err < 0)
+ return err;
+
+ /* automatic parse from the BIOS config */
+ err = alc680_parse_auto_config(codec);
+ if (err < 0) {
+ snd_hda_gen_remove(codec);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct hda_codec_ops alc680_codec_ops = {
+ .probe = alc680_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc680[] = {
+ HDA_CODEC_ID(0x10ec0680, "ALC680"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc680);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC680 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc680_driver = {
+ .id = snd_hda_id_alc680,
+ .ops = &alc680_codec_ops,
+};
+
+module_hda_codec_driver(alc680_driver);
diff --git a/sound/hda/codecs/realtek/alc861.c b/sound/hda/codecs/realtek/alc861.c
new file mode 100644
index 000000000000..270037c6504a
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc861.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC861 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc861_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
+ return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
+}
+
+/* Pin config fixes */
+enum {
+ ALC861_FIXUP_FSC_AMILO_PI1505,
+ ALC861_FIXUP_AMP_VREF_0F,
+ ALC861_FIXUP_NO_JACK_DETECT,
+ ALC861_FIXUP_ASUS_A6RP,
+ ALC660_FIXUP_ASUS_W7J,
+};
+
+/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
+static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int val;
+
+ if (action != HDA_FIXUP_ACT_INIT)
+ return;
+ val = snd_hda_codec_get_pin_target(codec, 0x0f);
+ if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
+ val |= AC_PINCTL_IN_EN;
+ val |= AC_PINCTL_VREF_50;
+ snd_hda_set_pin_ctl(codec, 0x0f, val);
+ spec->gen.keep_vref_in_automute = 1;
+}
+
+static const struct hda_fixup alc861_fixups[] = {
+ [ALC861_FIXUP_FSC_AMILO_PI1505] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x0b, 0x0221101f }, /* HP */
+ { 0x0f, 0x90170310 }, /* speaker */
+ { }
+ }
+ },
+ [ALC861_FIXUP_AMP_VREF_0F] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc861_fixup_asus_amp_vref_0f,
+ },
+ [ALC861_FIXUP_NO_JACK_DETECT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_no_jack_detect,
+ },
+ [ALC861_FIXUP_ASUS_A6RP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc861_fixup_asus_amp_vref_0f,
+ .chained = true,
+ .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+ },
+ [ALC660_FIXUP_ASUS_W7J] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* ASUS W7J needs a magic pin setup on unused NID 0x10
+ * for enabling outputs
+ */
+ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ { }
+ },
+ }
+};
+
+static const struct hda_quirk alc861_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
+ SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
+ SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
+ SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
+ SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
+ SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
+ SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
+ {}
+};
+
+/*
+ */
+static int alc861_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x15);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x23;
+
+ spec->power_hook = alc_power_eapd;
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ /* automatic parse from the BIOS config */
+ err = alc861_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc861_codec_ops = {
+ .probe = alc861_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc861[] = {
+ HDA_CODEC_ID_REV(0x10ec0861, 0x100340, "ALC660"),
+ HDA_CODEC_ID(0x10ec0861, "ALC861"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC861 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc861_driver = {
+ .id = snd_hda_id_alc861,
+ .ops = &alc861_codec_ops,
+};
+
+module_hda_codec_driver(alc861_driver);
diff --git a/sound/hda/codecs/realtek/alc861vd.c b/sound/hda/codecs/realtek/alc861vd.c
new file mode 100644
index 000000000000..44264e0d6e56
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc861vd.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC861-VD codec
+// Based on ALC882
+// In addition, an independent DAC
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
+}
+
+enum {
+ ALC660VD_FIX_ASUS_GPIO1,
+ ALC861VD_FIX_DALLAS,
+};
+
+/* exclude VREF80 */
+static void alc861vd_fixup_dallas(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
+ snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
+ }
+}
+
+/* reset GPIO1 */
+static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->gpio_mask |= 0x02;
+ alc_fixup_gpio(codec, action, 0x01);
+}
+
+static const struct hda_fixup alc861vd_fixups[] = {
+ [ALC660VD_FIX_ASUS_GPIO1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc660vd_fixup_asus_gpio1,
+ },
+ [ALC861VD_FIX_DALLAS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc861vd_fixup_dallas,
+ },
+};
+
+static const struct hda_quirk alc861vd_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
+ SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+ SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
+ {}
+};
+
+/*
+ */
+static int alc861vd_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x23;
+
+ spec->shutup = alc_eapd_shutup;
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ /* automatic parse from the BIOS config */
+ err = alc861vd_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc861vd_codec_ops = {
+ .probe = alc861vd_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc861vd[] = {
+ HDA_CODEC_ID(0x10ec0660, "ALC660-VD"),
+ HDA_CODEC_ID(0x10ec0862, "ALC861-VD"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861vd);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC861-VD HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc861vd_driver = {
+ .id = snd_hda_id_alc861vd,
+ .ops = &alc861vd_codec_ops,
+};
+
+module_hda_codec_driver(alc861vd_driver);
diff --git a/sound/hda/codecs/realtek/alc880.c b/sound/hda/codecs/realtek/alc880.c
new file mode 100644
index 000000000000..bf1bdf11ec2d
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc880.c
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC880 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ /* For some reason, the res given from ALC880 is broken.
+ Here we adjust it properly. */
+ snd_hda_jack_unsol_event(codec, res >> 2);
+}
+
+static int alc880_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
+}
+
+/*
+ * ALC880 fix-ups
+ */
+enum {
+ ALC880_FIXUP_GPIO1,
+ ALC880_FIXUP_GPIO2,
+ ALC880_FIXUP_MEDION_RIM,
+ ALC880_FIXUP_LG,
+ ALC880_FIXUP_LG_LW25,
+ ALC880_FIXUP_W810,
+ ALC880_FIXUP_EAPD_COEF,
+ ALC880_FIXUP_TCL_S700,
+ ALC880_FIXUP_VOL_KNOB,
+ ALC880_FIXUP_FUJITSU,
+ ALC880_FIXUP_F1734,
+ ALC880_FIXUP_UNIWILL,
+ ALC880_FIXUP_UNIWILL_DIG,
+ ALC880_FIXUP_Z71V,
+ ALC880_FIXUP_ASUS_W5A,
+ ALC880_FIXUP_3ST_BASE,
+ ALC880_FIXUP_3ST,
+ ALC880_FIXUP_3ST_DIG,
+ ALC880_FIXUP_5ST_BASE,
+ ALC880_FIXUP_5ST,
+ ALC880_FIXUP_5ST_DIG,
+ ALC880_FIXUP_6ST_BASE,
+ ALC880_FIXUP_6ST,
+ ALC880_FIXUP_6ST_DIG,
+ ALC880_FIXUP_6ST_AUTOMUTE,
+};
+
+/* enable the volume-knob widget support on NID 0x21 */
+static void alc880_fixup_vol_knob(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PROBE)
+ snd_hda_jack_detect_enable_callback(codec, 0x21,
+ alc_update_knob_master);
+}
+
+static const struct hda_fixup alc880_fixups[] = {
+ [ALC880_FIXUP_GPIO1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
+ },
+ [ALC880_FIXUP_GPIO2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio2,
+ },
+ [ALC880_FIXUP_MEDION_RIM] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_GPIO2,
+ },
+ [ALC880_FIXUP_LG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* disable bogus unused pins */
+ { 0x16, 0x411111f0 },
+ { 0x18, 0x411111f0 },
+ { 0x1a, 0x411111f0 },
+ { }
+ }
+ },
+ [ALC880_FIXUP_LG_LW25] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x0181344f }, /* line-in */
+ { 0x1b, 0x0321403f }, /* headphone */
+ { }
+ }
+ },
+ [ALC880_FIXUP_W810] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* disable bogus unused pins */
+ { 0x17, 0x411111f0 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_GPIO2,
+ },
+ [ALC880_FIXUP_EAPD_COEF] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* change to EAPD mode */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
+ {}
+ },
+ },
+ [ALC880_FIXUP_TCL_S700] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* change to EAPD mode */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_GPIO2,
+ },
+ [ALC880_FIXUP_VOL_KNOB] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc880_fixup_vol_knob,
+ },
+ [ALC880_FIXUP_FUJITSU] = {
+ /* override all pins as BIOS on old Amilo is broken */
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x0121401f }, /* HP */
+ { 0x15, 0x99030120 }, /* speaker */
+ { 0x16, 0x99030130 }, /* bass speaker */
+ { 0x17, 0x411111f0 }, /* N/A */
+ { 0x18, 0x411111f0 }, /* N/A */
+ { 0x19, 0x01a19950 }, /* mic-in */
+ { 0x1a, 0x411111f0 }, /* N/A */
+ { 0x1b, 0x411111f0 }, /* N/A */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ { 0x1e, 0x01454140 }, /* SPDIF out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_VOL_KNOB,
+ },
+ [ALC880_FIXUP_F1734] = {
+ /* almost compatible with FUJITSU, but no bass and SPDIF */
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x0121401f }, /* HP */
+ { 0x15, 0x99030120 }, /* speaker */
+ { 0x16, 0x411111f0 }, /* N/A */
+ { 0x17, 0x411111f0 }, /* N/A */
+ { 0x18, 0x411111f0 }, /* N/A */
+ { 0x19, 0x01a19950 }, /* mic-in */
+ { 0x1a, 0x411111f0 }, /* N/A */
+ { 0x1b, 0x411111f0 }, /* N/A */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ { 0x1e, 0x411111f0 }, /* N/A */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_VOL_KNOB,
+ },
+ [ALC880_FIXUP_UNIWILL] = {
+ /* need to fix HP and speaker pins to be parsed correctly */
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x0121411f }, /* HP */
+ { 0x15, 0x99030120 }, /* speaker */
+ { 0x16, 0x99030130 }, /* bass speaker */
+ { }
+ },
+ },
+ [ALC880_FIXUP_UNIWILL_DIG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* disable bogus unused pins */
+ { 0x17, 0x411111f0 },
+ { 0x19, 0x411111f0 },
+ { 0x1b, 0x411111f0 },
+ { 0x1f, 0x411111f0 },
+ { }
+ }
+ },
+ [ALC880_FIXUP_Z71V] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* set up the whole pins as BIOS is utterly broken */
+ { 0x14, 0x99030120 }, /* speaker */
+ { 0x15, 0x0121411f }, /* HP */
+ { 0x16, 0x411111f0 }, /* N/A */
+ { 0x17, 0x411111f0 }, /* N/A */
+ { 0x18, 0x01a19950 }, /* mic-in */
+ { 0x19, 0x411111f0 }, /* N/A */
+ { 0x1a, 0x01813031 }, /* line-in */
+ { 0x1b, 0x411111f0 }, /* N/A */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ { 0x1e, 0x0144111e }, /* SPDIF */
+ { }
+ }
+ },
+ [ALC880_FIXUP_ASUS_W5A] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* set up the whole pins as BIOS is utterly broken */
+ { 0x14, 0x0121411f }, /* HP */
+ { 0x15, 0x411111f0 }, /* N/A */
+ { 0x16, 0x411111f0 }, /* N/A */
+ { 0x17, 0x411111f0 }, /* N/A */
+ { 0x18, 0x90a60160 }, /* mic */
+ { 0x19, 0x411111f0 }, /* N/A */
+ { 0x1a, 0x411111f0 }, /* N/A */
+ { 0x1b, 0x411111f0 }, /* N/A */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ { 0x1e, 0xb743111e }, /* SPDIF out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_GPIO1,
+ },
+ [ALC880_FIXUP_3ST_BASE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x01014010 }, /* line-out */
+ { 0x15, 0x411111f0 }, /* N/A */
+ { 0x16, 0x411111f0 }, /* N/A */
+ { 0x17, 0x411111f0 }, /* N/A */
+ { 0x18, 0x01a19c30 }, /* mic-in */
+ { 0x19, 0x0121411f }, /* HP */
+ { 0x1a, 0x01813031 }, /* line-in */
+ { 0x1b, 0x02a19c40 }, /* front-mic */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ /* 0x1e is filled in below */
+ { 0x1f, 0x411111f0 }, /* N/A */
+ { }
+ }
+ },
+ [ALC880_FIXUP_3ST] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x411111f0 }, /* N/A */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_3ST_BASE,
+ },
+ [ALC880_FIXUP_3ST_DIG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x0144111e }, /* SPDIF */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_3ST_BASE,
+ },
+ [ALC880_FIXUP_5ST_BASE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x01014010 }, /* front */
+ { 0x15, 0x411111f0 }, /* N/A */
+ { 0x16, 0x01011411 }, /* CLFE */
+ { 0x17, 0x01016412 }, /* surr */
+ { 0x18, 0x01a19c30 }, /* mic-in */
+ { 0x19, 0x0121411f }, /* HP */
+ { 0x1a, 0x01813031 }, /* line-in */
+ { 0x1b, 0x02a19c40 }, /* front-mic */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ /* 0x1e is filled in below */
+ { 0x1f, 0x411111f0 }, /* N/A */
+ { }
+ }
+ },
+ [ALC880_FIXUP_5ST] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x411111f0 }, /* N/A */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_5ST_BASE,
+ },
+ [ALC880_FIXUP_5ST_DIG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x0144111e }, /* SPDIF */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_5ST_BASE,
+ },
+ [ALC880_FIXUP_6ST_BASE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x01014010 }, /* front */
+ { 0x15, 0x01016412 }, /* surr */
+ { 0x16, 0x01011411 }, /* CLFE */
+ { 0x17, 0x01012414 }, /* side */
+ { 0x18, 0x01a19c30 }, /* mic-in */
+ { 0x19, 0x02a19c40 }, /* front-mic */
+ { 0x1a, 0x01813031 }, /* line-in */
+ { 0x1b, 0x0121411f }, /* HP */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ /* 0x1e is filled in below */
+ { 0x1f, 0x411111f0 }, /* N/A */
+ { }
+ }
+ },
+ [ALC880_FIXUP_6ST] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x411111f0 }, /* N/A */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_6ST_BASE,
+ },
+ [ALC880_FIXUP_6ST_DIG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x0144111e }, /* SPDIF */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_6ST_BASE,
+ },
+ [ALC880_FIXUP_6ST_AUTOMUTE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x0121401f }, /* HP with jack detect */
+ { }
+ },
+ .chained_before = true,
+ .chain_id = ALC880_FIXUP_6ST_BASE,
+ },
+};
+
+static const struct hda_quirk alc880_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
+ SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
+ SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
+ SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
+ SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
+ SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
+ SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
+ SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
+ SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
+ SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
+ SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
+ SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
+ SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+ SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
+ SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
+ SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
+ SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
+ SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
+ SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
+ SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
+ SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
+ SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
+ SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
+
+ /* Below is the copied entries from alc880_quirks.c.
+ * It's not quite sure whether BIOS sets the correct pin-config table
+ * on these machines, thus they are kept to be compatible with
+ * the old static quirks. Once when it's confirmed to work without
+ * these overrides, it'd be better to remove.
+ */
+ SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
+ SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
+ SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
+ SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
+ SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
+ SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
+ SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
+ SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
+ SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
+ SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+ /* default Intel */
+ SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
+ SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
+ SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
+ {}
+};
+
+static const struct hda_model_fixup alc880_fixup_models[] = {
+ {.id = ALC880_FIXUP_3ST, .name = "3stack"},
+ {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
+ {.id = ALC880_FIXUP_5ST, .name = "5stack"},
+ {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
+ {.id = ALC880_FIXUP_6ST, .name = "6stack"},
+ {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
+ {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
+ {}
+};
+
+
+/*
+ * OK, here we have finally the probe for ALC880
+ */
+static int alc880_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+ spec->gen.need_dac_fix = 1;
+ spec->gen.beep_nid = 0x01;
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
+ alc880_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ /* automatic parse from the BIOS config */
+ err = alc880_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc880_codec_ops = {
+ .probe = alc880_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = alc880_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc880[] = {
+ HDA_CODEC_ID(0x10ec0880, "ALC880"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC880 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc880_driver = {
+ .id = snd_hda_id_alc880,
+ .ops = &alc880_codec_ops,
+};
+
+module_hda_codec_driver(alc880_driver);
diff --git a/sound/hda/codecs/realtek/alc882.c b/sound/hda/codecs/realtek/alc882.c
new file mode 100644
index 000000000000..529fecd5baa0
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc882.c
@@ -0,0 +1,861 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC882/883/885/888/889 codec support
+//
+// ALC882 is almost identical with ALC880 but has cleaner and more flexible
+// configuration. Each pin widget can choose any input DACs and a mixer.
+// Each ADC is connected from a mixer of all inputs. This makes possible
+// 6-channel independent captures.
+//
+// In addition, an independent DAC for the multi-playback (not used in this
+// driver yet).
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/*
+ * Pin config fixes
+ */
+enum {
+ ALC882_FIXUP_ABIT_AW9D_MAX,
+ ALC882_FIXUP_LENOVO_Y530,
+ ALC882_FIXUP_PB_M5210,
+ ALC882_FIXUP_ACER_ASPIRE_7736,
+ ALC882_FIXUP_ASUS_W90V,
+ ALC889_FIXUP_CD,
+ ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
+ ALC889_FIXUP_VAIO_TT,
+ ALC888_FIXUP_EEE1601,
+ ALC886_FIXUP_EAPD,
+ ALC882_FIXUP_EAPD,
+ ALC883_FIXUP_EAPD,
+ ALC883_FIXUP_ACER_EAPD,
+ ALC882_FIXUP_GPIO1,
+ ALC882_FIXUP_GPIO2,
+ ALC882_FIXUP_GPIO3,
+ ALC889_FIXUP_COEF,
+ ALC882_FIXUP_ASUS_W2JC,
+ ALC882_FIXUP_ACER_ASPIRE_4930G,
+ ALC882_FIXUP_ACER_ASPIRE_8930G,
+ ALC882_FIXUP_ASPIRE_8930G_VERBS,
+ ALC885_FIXUP_MACPRO_GPIO,
+ ALC889_FIXUP_DAC_ROUTE,
+ ALC889_FIXUP_MBP_VREF,
+ ALC889_FIXUP_IMAC91_VREF,
+ ALC889_FIXUP_MBA11_VREF,
+ ALC889_FIXUP_MBA21_VREF,
+ ALC889_FIXUP_MP11_VREF,
+ ALC889_FIXUP_MP41_VREF,
+ ALC882_FIXUP_INV_DMIC,
+ ALC882_FIXUP_NO_PRIMARY_HP,
+ ALC887_FIXUP_ASUS_BASS,
+ ALC887_FIXUP_BASS_CHMAP,
+ ALC1220_FIXUP_GB_DUAL_CODECS,
+ ALC1220_FIXUP_GB_X570,
+ ALC1220_FIXUP_CLEVO_P950,
+ ALC1220_FIXUP_CLEVO_PB51ED,
+ ALC1220_FIXUP_CLEVO_PB51ED_PINS,
+ ALC887_FIXUP_ASUS_AUDIO,
+ ALC887_FIXUP_ASUS_HMIC,
+ ALCS1200A_FIXUP_MIC_VREF,
+ ALC888VD_FIXUP_MIC_100VREF,
+};
+
+static void alc889_fixup_coef(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action != HDA_FIXUP_ACT_INIT)
+ return;
+ alc_update_coef_idx(codec, 7, 0, 0x2030);
+}
+
+/* set up GPIO at initialization */
+static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->gpio_write_delay = true;
+ alc_fixup_gpio3(codec, fix, action);
+}
+
+/* Fix the connection of some pins for ALC889:
+ * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
+ * work correctly (bko#42740)
+ */
+static void alc889_fixup_dac_route(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ /* fake the connections during parsing the tree */
+ static const hda_nid_t conn1[] = { 0x0c, 0x0d };
+ static const hda_nid_t conn2[] = { 0x0e, 0x0f };
+ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+ snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
+ snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
+ snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
+ } else if (action == HDA_FIXUP_ACT_PROBE) {
+ /* restore the connections */
+ static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
+ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+ snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
+ snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
+ snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
+ }
+}
+
+/* Set VREF on HP pin */
+static void alc889_fixup_mbp_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ if (action != HDA_FIXUP_ACT_INIT)
+ return;
+ for (i = 0; i < ARRAY_SIZE(nids); i++) {
+ unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
+ if (get_defcfg_device(val) != AC_JACK_HP_OUT)
+ continue;
+ val = snd_hda_codec_get_pin_target(codec, nids[i]);
+ val |= AC_PINCTL_VREF_80;
+ snd_hda_set_pin_ctl(codec, nids[i], val);
+ spec->gen.keep_vref_in_automute = 1;
+ break;
+ }
+}
+
+static void alc889_fixup_mac_pins(struct hda_codec *codec,
+ const hda_nid_t *nids, int num_nids)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < num_nids; i++) {
+ unsigned int val;
+ val = snd_hda_codec_get_pin_target(codec, nids[i]);
+ val |= AC_PINCTL_VREF_50;
+ snd_hda_set_pin_ctl(codec, nids[i], val);
+ }
+ spec->gen.keep_vref_in_automute = 1;
+}
+
+/* Set VREF on speaker pins on imac91 */
+static void alc889_fixup_imac91_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const hda_nid_t nids[] = { 0x18, 0x1a };
+
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba11 */
+static void alc889_fixup_mba11_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const hda_nid_t nids[] = { 0x18 };
+
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba21 */
+static void alc889_fixup_mba21_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static const hda_nid_t nids[] = { 0x18, 0x19 };
+
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Don't take HP output as primary
+ * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
+ * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
+ */
+static void alc882_fixup_no_primary_hp(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->gen.no_primary_hp = 1;
+ spec->gen.no_multi_io = 1;
+ }
+}
+
+static void alc1220_fixup_gb_x570(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ static const hda_nid_t conn1[] = { 0x0c };
+ static const struct coef_fw gb_x570_coefs[] = {
+ WRITE_COEF(0x07, 0x03c0),
+ WRITE_COEF(0x1a, 0x01c1),
+ WRITE_COEF(0x1b, 0x0202),
+ WRITE_COEF(0x43, 0x3005),
+ {}
+ };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+ snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ alc_process_coef_fw(codec, gb_x570_coefs);
+ break;
+ }
+}
+
+static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ static const hda_nid_t conn1[] = { 0x0c };
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+
+ alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
+ /* We therefore want to make sure 0x14 (front headphone) and
+ * 0x1b (speakers) use the stereo DAC 0x02
+ */
+ snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+ snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
+}
+
+static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ alc1220_fixup_clevo_p950(codec, fix, action);
+ alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
+}
+
+static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int vref;
+
+ snd_hda_gen_hp_automute(codec, jack);
+
+ if (spec->gen.hp_jack_present)
+ vref = AC_PINCTL_VREF_80;
+ else
+ vref = AC_PINCTL_VREF_HIZ;
+ snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
+}
+
+static void alc887_fixup_asus_jack(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action != HDA_FIXUP_ACT_PROBE)
+ return;
+ snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
+ spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
+}
+
+static const struct hda_fixup alc882_fixups[] = {
+ [ALC882_FIXUP_ABIT_AW9D_MAX] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x01080104 }, /* side */
+ { 0x16, 0x01011012 }, /* rear */
+ { 0x17, 0x01016011 }, /* clfe */
+ { }
+ }
+ },
+ [ALC882_FIXUP_LENOVO_Y530] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x99130112 }, /* rear int speakers */
+ { 0x16, 0x99130111 }, /* subwoofer */
+ { }
+ }
+ },
+ [ALC882_FIXUP_PB_M5210] = {
+ .type = HDA_FIXUP_PINCTLS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, PIN_VREF50 },
+ {}
+ }
+ },
+ [ALC882_FIXUP_ACER_ASPIRE_7736] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_sku_ignore,
+ },
+ [ALC882_FIXUP_ASUS_W90V] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x99130110 }, /* fix sequence for CLFE */
+ { }
+ }
+ },
+ [ALC889_FIXUP_CD] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1c, 0x993301f0 }, /* CD */
+ { }
+ }
+ },
+ [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC889_FIXUP_CD,
+ },
+ [ALC889_FIXUP_VAIO_TT] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170111 }, /* hidden surround speaker */
+ { }
+ }
+ },
+ [ALC888_FIXUP_EEE1601] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 },
+ { }
+ }
+ },
+ [ALC886_FIXUP_EAPD] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* change to EAPD mode */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
+ { }
+ }
+ },
+ [ALC882_FIXUP_EAPD] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* change to EAPD mode */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
+ { }
+ }
+ },
+ [ALC883_FIXUP_EAPD] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* change to EAPD mode */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+ { }
+ }
+ },
+ [ALC883_FIXUP_ACER_EAPD] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* eanable EAPD on Acer laptops */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+ { }
+ }
+ },
+ [ALC882_FIXUP_GPIO1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
+ },
+ [ALC882_FIXUP_GPIO2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio2,
+ },
+ [ALC882_FIXUP_GPIO3] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio3,
+ },
+ [ALC882_FIXUP_ASUS_W2JC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
+ .chained = true,
+ .chain_id = ALC882_FIXUP_EAPD,
+ },
+ [ALC889_FIXUP_COEF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_coef,
+ },
+ [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x99130111 }, /* CLFE speaker */
+ { 0x17, 0x99130112 }, /* surround speaker */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC882_FIXUP_GPIO1,
+ },
+ [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x99130111 }, /* CLFE speaker */
+ { 0x1b, 0x99130112 }, /* surround speaker */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
+ },
+ [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
+ /* additional init verbs for Acer Aspire 8930G */
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* Enable all DACs */
+ /* DAC DISABLE/MUTE 1? */
+ /* setting bits 1-5 disables DAC nids 0x02-0x06
+ * apparently. Init=0x38 */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+ /* DAC DISABLE/MUTE 2? */
+ /* some bit here disables the other DACs.
+ * Init=0x4900 */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+ /* DMIC fix
+ * This laptop has a stereo digital microphone.
+ * The mics are only 1cm apart which makes the stereo
+ * useless. However, either the mic or the ALC889
+ * makes the signal become a difference/sum signal
+ * instead of standard stereo, which is annoying.
+ * So instead we flip this bit which makes the
+ * codec replicate the sum signal to both channels,
+ * turning it into a normal mono mic.
+ */
+ /* DMIC_CONTROL? Init value = 0x0001 */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC882_FIXUP_GPIO1,
+ },
+ [ALC885_FIXUP_MACPRO_GPIO] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc885_fixup_macpro_gpio,
+ },
+ [ALC889_FIXUP_DAC_ROUTE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_dac_route,
+ },
+ [ALC889_FIXUP_MBP_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mbp_vref,
+ .chained = true,
+ .chain_id = ALC882_FIXUP_GPIO1,
+ },
+ [ALC889_FIXUP_IMAC91_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_imac91_vref,
+ .chained = true,
+ .chain_id = ALC882_FIXUP_GPIO1,
+ },
+ [ALC889_FIXUP_MBA11_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mba11_vref,
+ .chained = true,
+ .chain_id = ALC889_FIXUP_MBP_VREF,
+ },
+ [ALC889_FIXUP_MBA21_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mba21_vref,
+ .chained = true,
+ .chain_id = ALC889_FIXUP_MBP_VREF,
+ },
+ [ALC889_FIXUP_MP11_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mba11_vref,
+ .chained = true,
+ .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+ },
+ [ALC889_FIXUP_MP41_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mbp_vref,
+ .chained = true,
+ .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+ },
+ [ALC882_FIXUP_INV_DMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_inv_dmic,
+ },
+ [ALC882_FIXUP_NO_PRIMARY_HP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc882_fixup_no_primary_hp,
+ },
+ [ALC887_FIXUP_ASUS_BASS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x16, 0x99130130}, /* bass speaker */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC887_FIXUP_BASS_CHMAP,
+ },
+ [ALC887_FIXUP_BASS_CHMAP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_bass_chmap,
+ },
+ [ALC1220_FIXUP_GB_DUAL_CODECS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc1220_fixup_gb_dual_codecs,
+ },
+ [ALC1220_FIXUP_GB_X570] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc1220_fixup_gb_x570,
+ },
+ [ALC1220_FIXUP_CLEVO_P950] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc1220_fixup_clevo_p950,
+ },
+ [ALC1220_FIXUP_CLEVO_PB51ED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc1220_fixup_clevo_pb51ed,
+ },
+ [ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
+ },
+ [ALC887_FIXUP_ASUS_AUDIO] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
+ { 0x19, 0x22219420 },
+ {}
+ },
+ },
+ [ALC887_FIXUP_ASUS_HMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc887_fixup_asus_jack,
+ .chained = true,
+ .chain_id = ALC887_FIXUP_ASUS_AUDIO,
+ },
+ [ALCS1200A_FIXUP_MIC_VREF] = {
+ .type = HDA_FIXUP_PINCTLS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, PIN_VREF50 }, /* rear mic */
+ { 0x19, PIN_VREF50 }, /* front mic */
+ {}
+ }
+ },
+ [ALC888VD_FIXUP_MIC_100VREF] = {
+ .type = HDA_FIXUP_PINCTLS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, PIN_VREF100 }, /* headset mic */
+ {}
+ }
+ },
+};
+
+static const struct hda_quirk alc882_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
+ SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+ ALC882_FIXUP_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
+ ALC882_FIXUP_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+ ALC882_FIXUP_ACER_ASPIRE_8930G),
+ SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+ ALC882_FIXUP_ACER_ASPIRE_8930G),
+ SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+ ALC882_FIXUP_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
+ SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+ ALC882_FIXUP_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+ ALC882_FIXUP_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
+ ALC882_FIXUP_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
+ SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
+ SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
+ SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
+ SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
+ SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
+ SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
+ SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
+ SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
+ SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
+ SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
+ SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
+
+ /* All Apple entries are in codec SSIDs */
+ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
+ SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
+ SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
+ SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
+ SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
+ SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
+
+ SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
+ SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+ SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
+ SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
+ SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
+ SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
+ SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
+ SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+ SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
+ SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
+ SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
+ SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
+ SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
+ {}
+};
+
+static const struct hda_model_fixup alc882_fixup_models[] = {
+ {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
+ {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
+ {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
+ {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
+ {.id = ALC889_FIXUP_CD, .name = "cd"},
+ {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
+ {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
+ {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
+ {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
+ {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
+ {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
+ {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
+ {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
+ {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
+ {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
+ {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
+ {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
+ {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
+ {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
+ {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
+ {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
+ {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
+ {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
+ {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
+ {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
+ {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
+ {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+ {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
+ {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+ {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
+ {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
+ {}
+};
+
+static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
+ SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
+ {0x14, 0x01014010},
+ {0x15, 0x01011012},
+ {0x16, 0x01016011},
+ {0x18, 0x01a19040},
+ {0x19, 0x02a19050},
+ {0x1a, 0x0181304f},
+ {0x1b, 0x0221401f},
+ {0x1e, 0x01456130}),
+ SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
+ {0x14, 0x01015010},
+ {0x15, 0x01011012},
+ {0x16, 0x01011011},
+ {0x18, 0x01a11040},
+ {0x19, 0x02a19050},
+ {0x1a, 0x0181104f},
+ {0x1b, 0x0221401f},
+ {0x1e, 0x01451130}),
+ {}
+};
+
+/*
+ * BIOS auto configuration
+ */
+/* almost identical with ALC880 parser... */
+static int alc882_parse_auto_config(struct hda_codec *codec)
+{
+ static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
+}
+
+/*
+ */
+static int alc882_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct alc_spec *spec;
+ int err;
+
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0882:
+ case 0x10ec0885:
+ case 0x10ec0900:
+ case 0x10ec0b00:
+ case 0x10ec1220:
+ break;
+ default:
+ /* ALC883 and variants */
+ alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+ break;
+ }
+
+ alc_pre_init(codec);
+
+ snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
+ alc882_fixups);
+ snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ alc_auto_parse_customize_define(codec);
+
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x01;
+
+ /* automatic parse from the BIOS config */
+ err = alc882_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ snd_hda_gen_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops alc882_codec_ops = {
+ .probe = alc882_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = alc_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = alc_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .resume = alc_resume,
+ .suspend = alc_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc882[] = {
+ HDA_CODEC_ID_REV(0x10ec0662, 0x100002, "ALC662 rev2"),
+ HDA_CODEC_ID(0x10ec0882, "ALC882"),
+ HDA_CODEC_ID(0x10ec0883, "ALC883"),
+ HDA_CODEC_ID_REV(0x10ec0885, 0x100101, "ALC889A"),
+ HDA_CODEC_ID_REV(0x10ec0885, 0x100103, "ALC889A"),
+ HDA_CODEC_ID(0x10ec0885, "ALC885"),
+ HDA_CODEC_ID(0x10ec0887, "ALC887"),
+ HDA_CODEC_ID_REV(0x10ec0888, 0x100101, "ALC1200"),
+ HDA_CODEC_ID(0x10ec0888, "ALC888"),
+ HDA_CODEC_ID(0x10ec0889, "ALC889"),
+ HDA_CODEC_ID(0x10ec0899, "ALC898"),
+ HDA_CODEC_ID(0x10ec0900, "ALC1150"),
+ HDA_CODEC_ID(0x10ec0b00, "ALCS1200A"),
+ HDA_CODEC_ID(0x10ec1168, "ALC1220"),
+ HDA_CODEC_ID(0x10ec1220, "ALC1220"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc882);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC882 and compatible HD-audio codecs");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc882_driver = {
+ .id = snd_hda_id_alc882,
+ .ops = &alc882_codec_ops,
+};
+
+module_hda_codec_driver(alc882_driver);
diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c
new file mode 100644
index 000000000000..ca377a5adadb
--- /dev/null
+++ b/sound/hda/codecs/realtek/realtek.c
@@ -0,0 +1,2271 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek HD-audio codec support code
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx)
+{
+ unsigned int val;
+
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+ val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+ return val;
+}
+
+int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx)
+{
+ guard(coef_mutex)(codec);
+ return __alc_read_coefex_idx(codec, nid, coef_idx);
+}
+EXPORT_SYMBOL_NS_GPL(alc_read_coefex_idx, "SND_HDA_CODEC_REALTEK");
+
+static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int coef_val)
+{
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
+}
+
+void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int coef_val)
+{
+ guard(coef_mutex)(codec);
+ __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
+}
+EXPORT_SYMBOL_NS_GPL(alc_write_coefex_idx, "SND_HDA_CODEC_REALTEK");
+
+static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int mask,
+ unsigned int bits_set)
+{
+ unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
+
+ if (val != -1)
+ __alc_write_coefex_idx(codec, nid, coef_idx,
+ (val & ~mask) | bits_set);
+}
+
+void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int mask,
+ unsigned int bits_set)
+{
+ guard(coef_mutex)(codec);
+ __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_coefex_idx, "SND_HDA_CODEC_REALTEK");
+
+/* a special bypass for COEF 0; read the cached value at the second time */
+unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->coef0)
+ spec->coef0 = alc_read_coef_idx(codec, 0);
+ return spec->coef0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_get_coef0, "SND_HDA_CODEC_REALTEK");
+
+void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw)
+{
+ guard(coef_mutex)(codec);
+ for (; fw->nid; fw++) {
+ if (fw->mask == (unsigned short)-1)
+ __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+ else
+ __alc_update_coefex_idx(codec, fw->nid, fw->idx,
+ fw->mask, fw->val);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_process_coef_fw, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * GPIO setup tables, used in initialization
+ */
+
+/* Enable GPIO mask and set output */
+void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->gpio_mask |= mask;
+ spec->gpio_dir |= mask;
+ spec->gpio_data |= mask;
+}
+EXPORT_SYMBOL_NS_GPL(alc_setup_gpio, "SND_HDA_CODEC_REALTEK");
+
+void alc_write_gpio_data(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+}
+EXPORT_SYMBOL_NS_GPL(alc_write_gpio_data, "SND_HDA_CODEC_REALTEK");
+
+void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+ bool on)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int oldval = spec->gpio_data;
+
+ if (on)
+ spec->gpio_data |= mask;
+ else
+ spec->gpio_data &= ~mask;
+ if (oldval != spec->gpio_data)
+ alc_write_gpio_data(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_gpio_data, "SND_HDA_CODEC_REALTEK");
+
+void alc_write_gpio(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->gpio_mask)
+ return;
+
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
+ if (spec->gpio_write_delay)
+ msleep(1);
+ alc_write_gpio_data(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_write_gpio, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ alc_setup_gpio(codec, mask);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x01);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio1, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio2(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x02);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio2, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio3(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x03);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio3, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio4(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x04);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio4, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_micmute_led, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * Fix hardware PLL issue
+ * On some codecs, the analog PLL gating control must be off while
+ * the default value is 1.
+ */
+void alc_fix_pll(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (spec->pll_nid)
+ alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
+ 1 << spec->pll_coef_bit, 0);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fix_pll, "SND_HDA_CODEC_REALTEK");
+
+void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int coef_bit)
+{
+ struct alc_spec *spec = codec->spec;
+ spec->pll_nid = nid;
+ spec->pll_coef_idx = coef_idx;
+ spec->pll_coef_bit = coef_bit;
+ alc_fix_pll(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fix_pll_init, "SND_HDA_CODEC_REALTEK");
+
+/* update the master volume per volume-knob's unsol event */
+void alc_update_knob_master(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ unsigned int val;
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_value *uctl __free(kfree) = NULL;
+
+ kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
+ if (!kctl)
+ return;
+ uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
+ if (!uctl)
+ return;
+ val = snd_hda_codec_read(codec, jack->nid, 0,
+ AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+ val &= HDA_AMP_VOLMASK;
+ uctl->value.integer.value[0] = val;
+ uctl->value.integer.value[1] = val;
+ kctl->put(kctl, uctl);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_knob_master, "SND_HDA_CODEC_REALTEK");
+
+/* Change EAPD to verb control */
+void alc_fill_eapd_coef(struct hda_codec *codec)
+{
+ int coef;
+
+ coef = alc_get_coef0(codec);
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0262:
+ alc_update_coef_idx(codec, 0x7, 0, 1<<5);
+ break;
+ case 0x10ec0267:
+ case 0x10ec0268:
+ alc_update_coef_idx(codec, 0x7, 0, 1<<13);
+ break;
+ case 0x10ec0269:
+ if ((coef & 0x00f0) == 0x0010)
+ alc_update_coef_idx(codec, 0xd, 0, 1<<14);
+ if ((coef & 0x00f0) == 0x0020)
+ alc_update_coef_idx(codec, 0x4, 1<<15, 0);
+ if ((coef & 0x00f0) == 0x0030)
+ alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+ break;
+ case 0x10ec0280:
+ case 0x10ec0284:
+ case 0x10ec0290:
+ case 0x10ec0292:
+ alc_update_coef_idx(codec, 0x4, 1<<15, 0);
+ break;
+ case 0x10ec0225:
+ case 0x10ec0295:
+ case 0x10ec0299:
+ alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+ fallthrough;
+ case 0x10ec0215:
+ case 0x10ec0236:
+ case 0x10ec0245:
+ case 0x10ec0256:
+ case 0x10ec0257:
+ case 0x10ec0285:
+ case 0x10ec0289:
+ alc_update_coef_idx(codec, 0x36, 1<<13, 0);
+ fallthrough;
+ case 0x10ec0230:
+ case 0x10ec0233:
+ case 0x10ec0235:
+ case 0x10ec0255:
+ case 0x19e58326:
+ case 0x10ec0282:
+ case 0x10ec0283:
+ case 0x10ec0286:
+ case 0x10ec0288:
+ case 0x10ec0298:
+ case 0x10ec0300:
+ alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+ break;
+ case 0x10ec0275:
+ alc_update_coef_idx(codec, 0xe, 0, 1<<0);
+ break;
+ case 0x10ec0287:
+ alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+ alc_write_coef_idx(codec, 0x8, 0x4ab7);
+ break;
+ case 0x10ec0293:
+ alc_update_coef_idx(codec, 0xa, 1<<13, 0);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ alc_write_coef_idx(codec, 0x6e, 0x0c25);
+ fallthrough;
+ case 0x10ec0294:
+ case 0x10ec0700:
+ case 0x10ec0701:
+ case 0x10ec0703:
+ case 0x10ec0711:
+ alc_update_coef_idx(codec, 0x10, 1<<15, 0);
+ break;
+ case 0x10ec0662:
+ if ((coef & 0x00f0) == 0x0030)
+ alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
+ break;
+ case 0x10ec0272:
+ case 0x10ec0273:
+ case 0x10ec0663:
+ case 0x10ec0665:
+ case 0x10ec0670:
+ case 0x10ec0671:
+ case 0x10ec0672:
+ alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
+ break;
+ case 0x10ec0222:
+ case 0x10ec0623:
+ alc_update_coef_idx(codec, 0x19, 1<<13, 0);
+ break;
+ case 0x10ec0668:
+ alc_update_coef_idx(codec, 0x7, 3<<13, 0);
+ break;
+ case 0x10ec0867:
+ alc_update_coef_idx(codec, 0x4, 1<<10, 0);
+ break;
+ case 0x10ec0888:
+ if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
+ alc_update_coef_idx(codec, 0x7, 1<<5, 0);
+ break;
+ case 0x10ec0892:
+ case 0x10ec0897:
+ alc_update_coef_idx(codec, 0x7, 1<<5, 0);
+ break;
+ case 0x10ec0899:
+ case 0x10ec0900:
+ case 0x10ec0b00:
+ case 0x10ec1168:
+ case 0x10ec1220:
+ alc_update_coef_idx(codec, 0x7, 1<<1, 0);
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fill_eapd_coef, "SND_HDA_CODEC_REALTEK");
+
+/* turn on/off EAPD control (only if available) */
+static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
+{
+ if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ return;
+ if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+ on ? 2 : 0);
+}
+
+/* turn on/off EAPD controls of the codec */
+void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
+{
+ /* We currently only handle front, HP */
+ static const hda_nid_t pins[] = {
+ 0x0f, 0x10, 0x14, 0x15, 0x17, 0
+ };
+ const hda_nid_t *p;
+ for (p = pins; *p; p++)
+ set_eapd(codec, *p, on);
+}
+EXPORT_SYMBOL_NS_GPL(alc_auto_setup_eapd, "SND_HDA_CODEC_REALTEK");
+
+/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
+int alc_find_ext_mic_pin(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+ hda_nid_t nid;
+ unsigned int defcfg;
+ int i;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].type != AUTO_PIN_MIC)
+ continue;
+ nid = cfg->inputs[i].pin;
+ defcfg = snd_hda_codec_get_pincfg(codec, nid);
+ if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
+ continue;
+ return nid;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_find_ext_mic_pin, "SND_HDA_CODEC_REALTEK");
+
+void alc_headset_mic_no_shutup(struct hda_codec *codec)
+{
+ const struct hda_pincfg *pin;
+ int mic_pin = alc_find_ext_mic_pin(codec);
+ int i;
+
+ /* don't shut up pins when unloading the driver; otherwise it breaks
+ * the default pin setup at the next load of the driver
+ */
+ if (codec->bus->shutdown)
+ return;
+
+ snd_array_for_each(&codec->init_pins, i, pin) {
+ /* use read here for syncing after issuing each verb */
+ if (pin->nid != mic_pin)
+ snd_hda_codec_read(codec, pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+ }
+
+ codec->pins_shutup = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_headset_mic_no_shutup, "SND_HDA_CODEC_REALTEK");
+
+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:
+ case 0x10ec0257:
+ case 0x19e58326:
+ case 0x10ec0283:
+ case 0x10ec0285:
+ case 0x10ec0286:
+ case 0x10ec0287:
+ case 0x10ec0288:
+ case 0x10ec0295:
+ case 0x10ec0298:
+ alc_headset_mic_no_shutup(codec);
+ break;
+ default:
+ snd_hda_shutup_pins(codec);
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_shutup_pins, "SND_HDA_CODEC_REALTEK");
+
+/* generic shutup callback;
+ * just turning off EAPD and a little pause for avoiding pop-noise
+ */
+void alc_eapd_shutup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ alc_auto_setup_eapd(codec, false);
+ if (!spec->no_depop_delay)
+ msleep(200);
+ alc_shutup_pins(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_eapd_shutup, "SND_HDA_CODEC_REALTEK");
+
+/* additional initialization for ALC888 variants */
+static void alc888_coef_init(struct hda_codec *codec)
+{
+ switch (alc_get_coef0(codec) & 0x00f0) {
+ /* alc888-VA */
+ case 0x00:
+ /* alc888-VB */
+ case 0x10:
+ alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
+ break;
+ }
+}
+
+/* generic EAPD initialization */
+void alc_auto_init_amp(struct hda_codec *codec, int type)
+{
+ alc_auto_setup_eapd(codec, true);
+ alc_write_gpio(codec);
+ switch (type) {
+ case ALC_INIT_DEFAULT:
+ switch (codec->core.vendor_id) {
+ case 0x10ec0260:
+ alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
+ break;
+ case 0x10ec0880:
+ case 0x10ec0882:
+ case 0x10ec0883:
+ case 0x10ec0885:
+ alc_update_coef_idx(codec, 7, 0, 0x2030);
+ break;
+ case 0x10ec0888:
+ alc888_coef_init(codec);
+ break;
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_auto_init_amp, "SND_HDA_CODEC_REALTEK");
+
+/* get a primary headphone pin if available */
+hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
+{
+ if (spec->gen.autocfg.hp_pins[0])
+ return spec->gen.autocfg.hp_pins[0];
+ if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
+ return spec->gen.autocfg.line_out_pins[0];
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_get_hp_pin, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * Realtek SSID verification
+ */
+
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
+void alc_fixup_sku_ignore(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->cdefine.fixup = 1;
+ spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_sku_ignore, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_no_depop_delay(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PROBE) {
+ spec->no_depop_delay = 1;
+ codec->depop_delay = 0;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_no_depop_delay, "SND_HDA_CODEC_REALTEK");
+
+int alc_auto_parse_customize_define(struct hda_codec *codec)
+{
+ unsigned int ass, tmp, i;
+ unsigned nid = 0;
+ struct alc_spec *spec = codec->spec;
+
+ spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+
+ if (spec->cdefine.fixup) {
+ ass = spec->cdefine.sku_cfg;
+ if (ass == ALC_FIXUP_SKU_IGNORE)
+ return -1;
+ goto do_sku;
+ }
+
+ if (!codec->bus->pci)
+ return -1;
+ ass = codec->core.subsystem_id & 0xffff;
+ if (ass != codec->bus->pci->subsystem_device && (ass & 1))
+ goto do_sku;
+
+ nid = 0x1d;
+ if (codec->core.vendor_id == 0x10ec0260)
+ nid = 0x17;
+ ass = snd_hda_codec_get_pincfg(codec, nid);
+
+ if (!(ass & 1)) {
+ codec_info(codec, "%s: SKU not ready 0x%08x\n",
+ codec->core.chip_name, ass);
+ return -1;
+ }
+
+ /* check sum */
+ tmp = 0;
+ for (i = 1; i < 16; i++) {
+ if ((ass >> i) & 1)
+ tmp++;
+ }
+ if (((ass >> 16) & 0xf) != tmp)
+ return -1;
+
+ spec->cdefine.port_connectivity = ass >> 30;
+ spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
+ spec->cdefine.check_sum = (ass >> 16) & 0xf;
+ spec->cdefine.customization = ass >> 8;
+do_sku:
+ spec->cdefine.sku_cfg = ass;
+ spec->cdefine.external_amp = (ass & 0x38) >> 3;
+ spec->cdefine.platform_type = (ass & 0x4) >> 2;
+ spec->cdefine.swap = (ass & 0x2) >> 1;
+ spec->cdefine.override = ass & 0x1;
+
+ codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
+ nid, spec->cdefine.sku_cfg);
+ codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
+ spec->cdefine.port_connectivity);
+ codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
+ codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
+ codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
+ codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
+ codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
+ codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
+ codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_auto_parse_customize_define, "SND_HDA_CODEC_REALTEK");
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+ int i;
+ for (i = 0; i < nums; i++)
+ if (list[i] == nid)
+ return i;
+ return -1;
+}
+/* return true if the given NID is found in the list */
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+ return find_idx_in_nid_list(nid, list, nums) >= 0;
+}
+
+/* check subsystem ID and set up device-specific initialization;
+ * return 1 if initialized, 0 if invalid SSID
+ */
+/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
+ * 31 ~ 16 : Manufacture ID
+ * 15 ~ 8 : SKU ID
+ * 7 ~ 0 : Assembly ID
+ * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
+ */
+int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
+{
+ unsigned int ass, tmp, i;
+ unsigned nid;
+ struct alc_spec *spec = codec->spec;
+
+ if (spec->cdefine.fixup) {
+ ass = spec->cdefine.sku_cfg;
+ if (ass == ALC_FIXUP_SKU_IGNORE)
+ return 0;
+ goto do_sku;
+ }
+
+ ass = codec->core.subsystem_id & 0xffff;
+ if (codec->bus->pci &&
+ ass != codec->bus->pci->subsystem_device && (ass & 1))
+ goto do_sku;
+
+ /* invalid SSID, check the special NID pin defcfg instead */
+ /*
+ * 31~30 : port connectivity
+ * 29~21 : reserve
+ * 20 : PCBEEP input
+ * 19~16 : Check sum (15:1)
+ * 15~1 : Custom
+ * 0 : override
+ */
+ nid = 0x1d;
+ if (codec->core.vendor_id == 0x10ec0260)
+ nid = 0x17;
+ ass = snd_hda_codec_get_pincfg(codec, nid);
+ codec_dbg(codec,
+ "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
+ ass, nid);
+ if (!(ass & 1))
+ return 0;
+ if ((ass >> 30) != 1) /* no physical connection */
+ return 0;
+
+ /* check sum */
+ tmp = 0;
+ for (i = 1; i < 16; i++) {
+ if ((ass >> i) & 1)
+ tmp++;
+ }
+ if (((ass >> 16) & 0xf) != tmp)
+ return 0;
+do_sku:
+ codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+ ass & 0xffff, codec->core.vendor_id);
+ /*
+ * 0 : override
+ * 1 : Swap Jack
+ * 2 : 0 --> Desktop, 1 --> Laptop
+ * 3~5 : External Amplifier control
+ * 7~6 : Reserved
+ */
+ tmp = (ass & 0x38) >> 3; /* external Amp control */
+ if (spec->init_amp == ALC_INIT_UNDEFINED) {
+ switch (tmp) {
+ case 1:
+ alc_setup_gpio(codec, 0x01);
+ break;
+ case 3:
+ alc_setup_gpio(codec, 0x02);
+ break;
+ case 7:
+ alc_setup_gpio(codec, 0x04);
+ break;
+ case 5:
+ default:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
+ }
+ }
+
+ /* is laptop or Desktop and enable the function "Mute internal speaker
+ * when the external headphone out jack is plugged"
+ */
+ if (!(ass & 0x8000))
+ return 1;
+ /*
+ * 10~8 : Jack location
+ * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
+ * 14~13: Resvered
+ * 15 : 1 --> enable the function "Mute internal speaker
+ * when the external headphone out jack is plugged"
+ */
+ if (!alc_get_hp_pin(spec)) {
+ hda_nid_t nid;
+ tmp = (ass >> 11) & 0x3; /* HP to chassis */
+ nid = ports[tmp];
+ if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
+ spec->gen.autocfg.line_outs))
+ return 1;
+ spec->gen.autocfg.hp_pins[0] = nid;
+ }
+ return 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_subsystem_id, "SND_HDA_CODEC_REALTEK");
+
+/* Check the validity of ALC subsystem-id
+ * ports contains an array of 4 pin NIDs for port-A, E, D and I */
+void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
+{
+ if (!alc_subsystem_id(codec, ports)) {
+ struct alc_spec *spec = codec->spec;
+ if (spec->init_amp == ALC_INIT_UNDEFINED) {
+ codec_dbg(codec,
+ "realtek: Enable default setup for auto mode as fallback\n");
+ spec->init_amp = ALC_INIT_DEFAULT;
+ }
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_ssid_check, "SND_HDA_CODEC_REALTEK");
+
+/* inverted digital-mic */
+void alc_fixup_inv_dmic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->gen.inv_dmic_split = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_inv_dmic, "SND_HDA_CODEC_REALTEK");
+
+int alc_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = snd_hda_gen_build_controls(codec);
+ if (err < 0)
+ return err;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_build_controls, "SND_HDA_CODEC_REALTEK");
+
+int alc_init(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ /* hibernation resume needs the full chip initialization */
+ if (is_s4_resume(codec))
+ alc_pre_init(codec);
+
+ if (spec->init_hook)
+ spec->init_hook(codec);
+
+ spec->gen.skip_verbs = 1; /* applied in below */
+ snd_hda_gen_init(codec);
+ alc_fix_pll(codec);
+ alc_auto_init_amp(codec, spec->init_amp);
+ snd_hda_apply_verbs(codec); /* apply verbs here after own init */
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_init, "SND_HDA_CODEC_REALTEK");
+
+void alc_shutup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!snd_hda_get_bool_hint(codec, "shutup"))
+ return; /* disabled explicitly by hints */
+
+ if (spec && spec->shutup)
+ spec->shutup(codec);
+ else
+ alc_shutup_pins(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_shutup, "SND_HDA_CODEC_REALTEK");
+
+void alc_power_eapd(struct hda_codec *codec)
+{
+ alc_auto_setup_eapd(codec, false);
+}
+EXPORT_SYMBOL_NS_GPL(alc_power_eapd, "SND_HDA_CODEC_REALTEK");
+
+int alc_suspend(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ alc_shutup(codec);
+ if (spec && spec->power_hook)
+ spec->power_hook(codec);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_suspend, "SND_HDA_CODEC_REALTEK");
+
+int alc_resume(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->no_depop_delay)
+ msleep(150); /* to avoid pop noise */
+ snd_hda_codec_init(codec);
+ snd_hda_regmap_sync(codec);
+ hda_call_check_power_status(codec, 0x01);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_resume, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * Rename codecs appropriately from COEF value or subvendor id
+ */
+struct alc_codec_rename_table {
+ unsigned int vendor_id;
+ unsigned short coef_mask;
+ unsigned short coef_bits;
+ const char *name;
+};
+
+struct alc_codec_rename_pci_table {
+ unsigned int codec_vendor_id;
+ unsigned short pci_subvendor;
+ unsigned short pci_subdevice;
+ const char *name;
+};
+
+static const struct alc_codec_rename_table rename_tbl[] = {
+ { 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
+ { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
+ { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
+ { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
+ { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
+ { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
+ { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
+ { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
+ { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
+ { 0x10ec0662, 0xffff, 0x4020, "ALC656" },
+ { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
+ { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
+ { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
+ { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
+ { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
+ { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
+ { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
+ { } /* terminator */
+};
+
+static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
+ { 0x10ec0280, 0x1028, 0, "ALC3220" },
+ { 0x10ec0282, 0x1028, 0, "ALC3221" },
+ { 0x10ec0283, 0x1028, 0, "ALC3223" },
+ { 0x10ec0288, 0x1028, 0, "ALC3263" },
+ { 0x10ec0292, 0x1028, 0, "ALC3226" },
+ { 0x10ec0293, 0x1028, 0, "ALC3235" },
+ { 0x10ec0255, 0x1028, 0, "ALC3234" },
+ { 0x10ec0668, 0x1028, 0, "ALC3661" },
+ { 0x10ec0275, 0x1028, 0, "ALC3260" },
+ { 0x10ec0899, 0x1028, 0, "ALC3861" },
+ { 0x10ec0298, 0x1028, 0, "ALC3266" },
+ { 0x10ec0236, 0x1028, 0, "ALC3204" },
+ { 0x10ec0256, 0x1028, 0, "ALC3246" },
+ { 0x10ec0225, 0x1028, 0, "ALC3253" },
+ { 0x10ec0295, 0x1028, 0, "ALC3254" },
+ { 0x10ec0299, 0x1028, 0, "ALC3271" },
+ { 0x10ec0670, 0x1025, 0, "ALC669X" },
+ { 0x10ec0676, 0x1025, 0, "ALC679X" },
+ { 0x10ec0282, 0x1043, 0, "ALC3229" },
+ { 0x10ec0233, 0x1043, 0, "ALC3236" },
+ { 0x10ec0280, 0x103c, 0, "ALC3228" },
+ { 0x10ec0282, 0x103c, 0, "ALC3227" },
+ { 0x10ec0286, 0x103c, 0, "ALC3242" },
+ { 0x10ec0290, 0x103c, 0, "ALC3241" },
+ { 0x10ec0668, 0x103c, 0, "ALC3662" },
+ { 0x10ec0283, 0x17aa, 0, "ALC3239" },
+ { 0x10ec0292, 0x17aa, 0, "ALC3232" },
+ { 0x10ec0257, 0x12f0, 0, "ALC3328" },
+ { } /* terminator */
+};
+
+static int alc_codec_rename_from_preset(struct hda_codec *codec)
+{
+ const struct alc_codec_rename_table *p;
+ const struct alc_codec_rename_pci_table *q;
+
+ for (p = rename_tbl; p->vendor_id; p++) {
+ if (p->vendor_id != codec->core.vendor_id)
+ continue;
+ if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
+ return alc_codec_rename(codec, p->name);
+ }
+
+ if (!codec->bus->pci)
+ return 0;
+ for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
+ if (q->codec_vendor_id != codec->core.vendor_id)
+ continue;
+ if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
+ continue;
+ if (!q->pci_subdevice ||
+ q->pci_subdevice == codec->bus->pci->subsystem_device)
+ return alc_codec_rename(codec, q->name);
+ }
+
+ return 0;
+}
+
+/*
+ * Digital-beep handlers
+ */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
+ HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+ HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
+};
+
+/* set up and create beep controls */
+int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir)
+{
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &alc_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_set_beep_amp, "SND_HDA_CODEC_REALTEK");
+
+static const struct snd_pci_quirk beep_allow_list[] = {
+ SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
+ SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
+ SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+ SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+ SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
+ SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
+ /* denylist -- no beep available */
+ SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
+ SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
+ {}
+};
+
+int alc_has_cdefine_beep(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ const struct snd_pci_quirk *q;
+ q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
+ if (q)
+ return q->value;
+ return spec->cdefine.enable_pcbeep;
+}
+EXPORT_SYMBOL_NS_GPL(alc_has_cdefine_beep, "SND_HDA_CODEC_REALTEK");
+
+#endif /* CONFIG_SND_HDA_INPUT_BEEP */
+
+/* parse the BIOS configuration and set up the alc_spec */
+/* return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ */
+int alc_parse_auto_config(struct hda_codec *codec,
+ const hda_nid_t *ignore_nids,
+ const hda_nid_t *ssid_nids)
+{
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+ int err;
+
+ err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
+ spec->parse_flags);
+ if (err < 0)
+ return err;
+
+ if (ssid_nids)
+ alc_ssid_check(codec, ssid_nids);
+
+ err = snd_hda_gen_parse_auto_config(codec, cfg);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_parse_auto_config, "SND_HDA_CODEC_REALTEK");
+
+/* common preparation job for alc_spec */
+int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
+{
+ struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ int err;
+
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+ snd_hda_gen_spec_init(&spec->gen);
+ spec->gen.mixer_nid = mixer_nid;
+ spec->gen.own_eapd_ctl = 1;
+ codec->single_adc_amp = 1;
+ /* FIXME: do we need this for all Realtek codec models? */
+ codec->spdif_status_reset = 1;
+ codec->forced_resume = 1;
+ mutex_init(&spec->coef_mutex);
+
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0) {
+ kfree(spec);
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_alloc_spec, "SND_HDA_CODEC_REALTEK");
+
+/* For dual-codec configuration, we need to disable some features to avoid
+ * conflicts of kctls and PCM streams
+ */
+void alc_fixup_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ /* disable vmaster */
+ spec->gen.suppress_vmaster = 1;
+ /* auto-mute and auto-mic switch don't work with multiple codecs */
+ spec->gen.suppress_auto_mute = 1;
+ spec->gen.suppress_auto_mic = 1;
+ /* disable aamix as well */
+ spec->gen.mixer_nid = 0;
+ /* add location prefix to avoid conflicts */
+ codec->force_pin_prefix = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_dual_codecs, "SND_HDA_CODEC_REALTEK");
+
+static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
+ { }
+};
+
+/* override the 2.1 chmap */
+void alc_fixup_bass_chmap(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_BUILD) {
+ struct alc_spec *spec = codec->spec;
+ spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_bass_chmap, "SND_HDA_CODEC_REALTEK");
+
+/* exported as it's used by multiple codecs */
+void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ alc_fixup_dual_codecs(codec, fix, action);
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* override card longname to provide a unique UCM profile */
+ strscpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ /* rename Capture controls depending on the codec */
+ rename_ctl(codec, "Capture Volume",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Volume" :
+ "Front-Panel Capture Volume");
+ rename_ctl(codec, "Capture Switch",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Switch" :
+ "Front-Panel Capture Switch");
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc1220_fixup_gb_dual_codecs, "SND_HDA_CODEC_REALTEK");
+
+void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ alc_fixup_dual_codecs(codec, fix, action);
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* override card longname to provide a unique UCM profile */
+ strscpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ /* rename Capture controls depending on the codec */
+ rename_ctl(codec, "Capture Volume",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Volume" :
+ "Front-Panel Capture Volume");
+ rename_ctl(codec, "Capture Switch",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Switch" :
+ "Front-Panel Capture Switch");
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc233_alc662_fixup_lenovo_dual_codecs, "SND_HDA_CODEC_REALTEK");
+
+static void alc_shutup_dell_xps13(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int hp_pin = alc_get_hp_pin(spec);
+
+ /* Prevent pop noises when headphones are plugged in */
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ msleep(20);
+}
+
+void alc_fixup_dell_xps13(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ struct hda_input_mux *imux = &spec->gen.input_mux;
+ int i;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
+ * it causes a click noise at start up
+ */
+ snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+ spec->shutup = alc_shutup_dell_xps13;
+ break;
+ case HDA_FIXUP_ACT_PROBE:
+ /* Make the internal mic the default input source. */
+ for (i = 0; i < imux->num_items; i++) {
+ if (spec->gen.imux_pins[i] == 0x12) {
+ spec->gen.cur_mux[0] = i;
+ break;
+ }
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_dell_xps13, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * headset handling
+ */
+
+static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
+{
+ if (delay <= 0)
+ delay = 75;
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ msleep(delay);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ msleep(delay);
+}
+
+static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
+{
+ if (delay <= 0)
+ delay = 75;
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ msleep(delay);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ msleep(delay);
+}
+
+static const struct coef_fw alc225_pre_hsmode[] = {
+ UPDATE_COEF(0x4a, 1<<8, 0),
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+ UPDATE_COEF(0x63, 3<<14, 3<<14),
+ UPDATE_COEF(0x4a, 3<<4, 2<<4),
+ UPDATE_COEF(0x4a, 3<<10, 3<<10),
+ UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+ UPDATE_COEF(0x4a, 3<<10, 0),
+ {}
+};
+
+static void alc_headset_mode_unplugged(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+ WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+ WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+ {}
+ };
+ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
+ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+ WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+ WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+ {}
+ };
+ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x1b, 0x0c0b),
+ WRITE_COEF(0x45, 0xc429),
+ UPDATE_COEF(0x35, 0x4000, 0),
+ WRITE_COEF(0x06, 0x2104),
+ WRITE_COEF(0x1a, 0x0001),
+ WRITE_COEF(0x26, 0x0004),
+ WRITE_COEF(0x32, 0x42a3),
+ {}
+ };
+ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+ static const struct coef_fw coef0298[] = {
+ UPDATE_COEF(0x19, 0x1300, 0x0300),
+ {}
+ };
+ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x76, 0x000e),
+ WRITE_COEF(0x6c, 0x2400),
+ WRITE_COEF(0x18, 0x7308),
+ WRITE_COEF(0x6b, 0xc429),
+ {}
+ };
+ static const struct coef_fw coef0293[] = {
+ UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
+ UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
+ UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
+ UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
+ WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
+ UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+ {}
+ };
+ static const struct coef_fw coef0668[] = {
+ WRITE_COEF(0x15, 0x0d40),
+ WRITE_COEF(0xb7, 0x802b),
+ {}
+ };
+ static const struct coef_fw coef0225[] = {
+ UPDATE_COEF(0x63, 3<<14, 0),
+ {}
+ };
+ static const struct coef_fw coef0274[] = {
+ UPDATE_COEF(0x4a, 0x0100, 0),
+ UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
+ UPDATE_COEF(0x6b, 0xf000, 0x5000),
+ UPDATE_COEF(0x4a, 0x0010, 0),
+ UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
+ WRITE_COEF(0x45, 0x5289),
+ UPDATE_COEF(0x4a, 0x0c00, 0),
+ {}
+ };
+
+ if (spec->no_internal_mic_pin) {
+ alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+ return;
+ }
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0255:
+ alc_process_coef_fw(codec, coef0255);
+ break;
+ case 0x10ec0230:
+ case 0x10ec0236:
+ case 0x10ec0256:
+ case 0x19e58326:
+ alc_hp_mute_disable(codec, 75);
+ alc_process_coef_fw(codec, coef0256);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+ alc_process_coef_fw(codec, coef0274);
+ break;
+ case 0x10ec0233:
+ case 0x10ec0283:
+ alc_process_coef_fw(codec, coef0233);
+ break;
+ case 0x10ec0286:
+ case 0x10ec0288:
+ alc_process_coef_fw(codec, coef0288);
+ break;
+ case 0x10ec0298:
+ alc_process_coef_fw(codec, coef0298);
+ alc_process_coef_fw(codec, coef0288);
+ break;
+ case 0x10ec0292:
+ alc_process_coef_fw(codec, coef0292);
+ break;
+ case 0x10ec0293:
+ alc_process_coef_fw(codec, coef0293);
+ break;
+ case 0x10ec0668:
+ alc_process_coef_fw(codec, coef0668);
+ break;
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_hp_mute_disable(codec, 75);
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
+ alc_process_coef_fw(codec, coef0225);
+ break;
+ case 0x10ec0867:
+ alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+ break;
+ }
+ codec_dbg(codec, "Headset jack set to unplugged mode.\n");
+}
+
+
+static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+ hda_nid_t mic_pin)
+{
+ static const struct coef_fw coef0255[] = {
+ WRITE_COEFEX(0x57, 0x03, 0x8aa6),
+ WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+ {}
+ };
+ static const struct coef_fw coef0256[] = {
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
+ WRITE_COEFEX(0x57, 0x03, 0x09a3),
+ WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+ {}
+ };
+ static const struct coef_fw coef0233[] = {
+ UPDATE_COEF(0x35, 0, 1<<14),
+ WRITE_COEF(0x06, 0x2100),
+ WRITE_COEF(0x1a, 0x0021),
+ WRITE_COEF(0x26, 0x008c),
+ {}
+ };
+ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0x00c0, 0),
+ UPDATE_COEF(0x50, 0x2000, 0),
+ UPDATE_COEF(0x56, 0x0006, 0),
+ UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+ UPDATE_COEF(0x66, 0x0008, 0x0008),
+ UPDATE_COEF(0x67, 0x2000, 0x2000),
+ {}
+ };
+ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x19, 0xa208),
+ WRITE_COEF(0x2e, 0xacf0),
+ {}
+ };
+ static const struct coef_fw coef0293[] = {
+ UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
+ UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
+ UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+ {}
+ };
+ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0xb7, 0x802b),
+ WRITE_COEF(0xb5, 0x1040),
+ UPDATE_COEF(0xc3, 0, 1<<12),
+ {}
+ };
+ static const struct coef_fw coef0225[] = {
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
+ UPDATE_COEF(0x4a, 3<<4, 2<<4),
+ UPDATE_COEF(0x63, 3<<14, 0),
+ {}
+ };
+ static const struct coef_fw coef0274[] = {
+ UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
+ UPDATE_COEF(0x4a, 0x0010, 0),
+ UPDATE_COEF(0x6b, 0xf000, 0),
+ {}
+ };
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0255:
+ alc_write_coef_idx(codec, 0x45, 0xc489);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0255);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0230:
+ case 0x10ec0236:
+ case 0x10ec0256:
+ case 0x19e58326:
+ alc_write_coef_idx(codec, 0x45, 0xc489);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0256);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+ alc_write_coef_idx(codec, 0x45, 0x4689);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0274);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0233:
+ case 0x10ec0283:
+ alc_write_coef_idx(codec, 0x45, 0xc429);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0233);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0286:
+ case 0x10ec0288:
+ case 0x10ec0298:
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0288);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0292:
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0292);
+ break;
+ case 0x10ec0293:
+ /* Set to TRS mode */
+ alc_write_coef_idx(codec, 0x45, 0xc429);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0293);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0867:
+ alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
+ fallthrough;
+ case 0x10ec0221:
+ case 0x10ec0662:
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0668:
+ alc_write_coef_idx(codec, 0x11, 0x0001);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0688);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
+ alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_process_coef_fw(codec, coef0225);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
+ }
+ codec_dbg(codec, "Headset jack set to mic-in mode.\n");
+}
+
+static void alc_headset_mode_default(struct hda_codec *codec)
+{
+ static const struct coef_fw coef0225[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+ UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+ UPDATE_COEF(0x49, 3<<8, 0<<8),
+ UPDATE_COEF(0x4a, 3<<4, 3<<4),
+ UPDATE_COEF(0x63, 3<<14, 0),
+ UPDATE_COEF(0x67, 0xf000, 0x3000),
+ {}
+ };
+ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xc089),
+ WRITE_COEF(0x45, 0xc489),
+ WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+ WRITE_COEF(0x49, 0x0049),
+ {}
+ };
+ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xc489),
+ WRITE_COEFEX(0x57, 0x03, 0x0da3),
+ WRITE_COEF(0x49, 0x0049),
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+ WRITE_COEF(0x06, 0x6100),
+ {}
+ };
+ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x06, 0x2100),
+ WRITE_COEF(0x32, 0x4ea3),
+ {}
+ };
+ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x76, 0x000e),
+ WRITE_COEF(0x6c, 0x2400),
+ WRITE_COEF(0x6b, 0xc429),
+ WRITE_COEF(0x18, 0x7308),
+ {}
+ };
+ static const struct coef_fw coef0293[] = {
+ UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+ WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
+ UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+ {}
+ };
+ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0041),
+ WRITE_COEF(0x15, 0x0d40),
+ WRITE_COEF(0xb7, 0x802b),
+ {}
+ };
+ static const struct coef_fw coef0274[] = {
+ WRITE_COEF(0x45, 0x4289),
+ UPDATE_COEF(0x4a, 0x0010, 0x0010),
+ UPDATE_COEF(0x6b, 0x0f00, 0),
+ UPDATE_COEF(0x49, 0x0300, 0x0300),
+ {}
+ };
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
+ alc_process_coef_fw(codec, coef0225);
+ alc_hp_enable_unmute(codec, 75);
+ break;
+ case 0x10ec0255:
+ alc_process_coef_fw(codec, coef0255);
+ break;
+ case 0x10ec0230:
+ case 0x10ec0236:
+ case 0x10ec0256:
+ case 0x19e58326:
+ alc_write_coef_idx(codec, 0x1b, 0x0e4b);
+ alc_write_coef_idx(codec, 0x45, 0xc089);
+ msleep(50);
+ alc_process_coef_fw(codec, coef0256);
+ alc_hp_enable_unmute(codec, 75);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+ alc_process_coef_fw(codec, coef0274);
+ break;
+ case 0x10ec0233:
+ case 0x10ec0283:
+ alc_process_coef_fw(codec, coef0233);
+ break;
+ case 0x10ec0286:
+ case 0x10ec0288:
+ case 0x10ec0298:
+ alc_process_coef_fw(codec, coef0288);
+ break;
+ case 0x10ec0292:
+ alc_process_coef_fw(codec, coef0292);
+ break;
+ case 0x10ec0293:
+ alc_process_coef_fw(codec, coef0293);
+ break;
+ case 0x10ec0668:
+ alc_process_coef_fw(codec, coef0688);
+ break;
+ case 0x10ec0867:
+ alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+ break;
+ }
+ codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
+}
+
+/* Iphone type */
+static void alc_headset_mode_ctia(struct hda_codec *codec)
+{
+ int val;
+
+ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+ {}
+ };
+ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+ WRITE_COEF(0x1b, 0x0e6b),
+ {}
+ };
+ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x45, 0xd429),
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEF(0x32, 0x4ea3),
+ {}
+ };
+ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x6b, 0xd429),
+ WRITE_COEF(0x76, 0x0008),
+ WRITE_COEF(0x18, 0x7388),
+ {}
+ };
+ static const struct coef_fw coef0293[] = {
+ WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
+ UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+ {}
+ };
+ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0x15, 0x0d60),
+ WRITE_COEF(0xc3, 0x0000),
+ {}
+ };
+ static const struct coef_fw coef0225_1[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+ UPDATE_COEF(0x63, 3<<14, 2<<14),
+ {}
+ };
+ static const struct coef_fw coef0225_2[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+ UPDATE_COEF(0x63, 3<<14, 1<<14),
+ {}
+ };
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0255:
+ alc_process_coef_fw(codec, coef0255);
+ break;
+ case 0x10ec0230:
+ case 0x10ec0236:
+ case 0x10ec0256:
+ case 0x19e58326:
+ alc_process_coef_fw(codec, coef0256);
+ alc_hp_enable_unmute(codec, 75);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+ alc_write_coef_idx(codec, 0x45, 0xd689);
+ break;
+ case 0x10ec0233:
+ case 0x10ec0283:
+ alc_process_coef_fw(codec, coef0233);
+ break;
+ case 0x10ec0298:
+ val = alc_read_coef_idx(codec, 0x50);
+ if (val & (1 << 12)) {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+ msleep(300);
+ } else {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+ msleep(300);
+ }
+ break;
+ case 0x10ec0286:
+ case 0x10ec0288:
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+ msleep(300);
+ alc_process_coef_fw(codec, coef0288);
+ break;
+ case 0x10ec0292:
+ alc_process_coef_fw(codec, coef0292);
+ break;
+ case 0x10ec0293:
+ alc_process_coef_fw(codec, coef0293);
+ break;
+ case 0x10ec0668:
+ alc_process_coef_fw(codec, coef0688);
+ break;
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ val = alc_read_coef_idx(codec, 0x45);
+ if (val & (1 << 9))
+ alc_process_coef_fw(codec, coef0225_2);
+ else
+ alc_process_coef_fw(codec, coef0225_1);
+ alc_hp_enable_unmute(codec, 75);
+ break;
+ case 0x10ec0867:
+ alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+ break;
+ }
+ codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
+}
+
+/* Nokia type */
+static void alc_headset_mode_omtp(struct hda_codec *codec)
+{
+ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+ {}
+ };
+ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+ WRITE_COEF(0x1b, 0x0e6b),
+ {}
+ };
+ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x45, 0xe429),
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEF(0x32, 0x4ea3),
+ {}
+ };
+ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x6b, 0xe429),
+ WRITE_COEF(0x76, 0x0008),
+ WRITE_COEF(0x18, 0x7388),
+ {}
+ };
+ static const struct coef_fw coef0293[] = {
+ WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
+ UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+ {}
+ };
+ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0x15, 0x0d50),
+ WRITE_COEF(0xc3, 0x0000),
+ {}
+ };
+ static const struct coef_fw coef0225[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
+ UPDATE_COEF(0x63, 3<<14, 2<<14),
+ {}
+ };
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0255:
+ alc_process_coef_fw(codec, coef0255);
+ break;
+ case 0x10ec0230:
+ case 0x10ec0236:
+ case 0x10ec0256:
+ case 0x19e58326:
+ alc_process_coef_fw(codec, coef0256);
+ alc_hp_enable_unmute(codec, 75);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+ alc_write_coef_idx(codec, 0x45, 0xe689);
+ break;
+ case 0x10ec0233:
+ case 0x10ec0283:
+ alc_process_coef_fw(codec, coef0233);
+ break;
+ case 0x10ec0298:
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+ msleep(300);
+ break;
+ case 0x10ec0286:
+ case 0x10ec0288:
+ alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+ msleep(300);
+ alc_process_coef_fw(codec, coef0288);
+ break;
+ case 0x10ec0292:
+ alc_process_coef_fw(codec, coef0292);
+ break;
+ case 0x10ec0293:
+ alc_process_coef_fw(codec, coef0293);
+ break;
+ case 0x10ec0668:
+ alc_process_coef_fw(codec, coef0688);
+ break;
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_process_coef_fw(codec, coef0225);
+ alc_hp_enable_unmute(codec, 75);
+ break;
+ }
+ codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
+}
+
+static void alc_determine_headset_type(struct hda_codec *codec)
+{
+ int val;
+ bool is_ctia = false;
+ struct alc_spec *spec = codec->spec;
+ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
+ WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
+ conteol) */
+ {}
+ };
+ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
+ {}
+ };
+ static const struct coef_fw coef0298[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ UPDATE_COEF(0x19, 0x1300, 0x1300),
+ {}
+ };
+ static const struct coef_fw coef0293[] = {
+ UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
+ WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
+ {}
+ };
+ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0xb7, 0x802b),
+ WRITE_COEF(0x15, 0x0d60),
+ WRITE_COEF(0xc3, 0x0c00),
+ {}
+ };
+ static const struct coef_fw coef0274[] = {
+ UPDATE_COEF(0x4a, 0x0010, 0),
+ UPDATE_COEF(0x4a, 0x8000, 0),
+ WRITE_COEF(0x45, 0xd289),
+ UPDATE_COEF(0x49, 0x0300, 0x0300),
+ {}
+ };
+
+ if (spec->no_internal_mic_pin) {
+ alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+ return;
+ }
+
+ switch (codec->core.vendor_id) {
+ case 0x10ec0255:
+ alc_process_coef_fw(codec, coef0255);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x0070) == 0x0070;
+ break;
+ case 0x10ec0230:
+ case 0x10ec0236:
+ case 0x10ec0256:
+ case 0x19e58326:
+ alc_write_coef_idx(codec, 0x1b, 0x0e4b);
+ alc_write_coef_idx(codec, 0x06, 0x6104);
+ alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
+
+ alc_process_coef_fw(codec, coef0255);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x0070) == 0x0070;
+ if (!is_ctia) {
+ alc_write_coef_idx(codec, 0x45, 0xe089);
+ msleep(100);
+ val = alc_read_coef_idx(codec, 0x46);
+ if ((val & 0x0070) == 0x0070)
+ is_ctia = false;
+ else
+ is_ctia = true;
+ }
+ alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
+ alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+ break;
+ case 0x10ec0234:
+ case 0x10ec0274:
+ case 0x10ec0294:
+ alc_process_coef_fw(codec, coef0274);
+ msleep(850);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x00f0) == 0x00f0;
+ break;
+ case 0x10ec0233:
+ case 0x10ec0283:
+ alc_write_coef_idx(codec, 0x45, 0xd029);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x0070) == 0x0070;
+ break;
+ case 0x10ec0298:
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ msleep(100);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ msleep(200);
+
+ val = alc_read_coef_idx(codec, 0x50);
+ if (val & (1 << 12)) {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+ alc_process_coef_fw(codec, coef0288);
+ msleep(350);
+ val = alc_read_coef_idx(codec, 0x50);
+ is_ctia = (val & 0x0070) == 0x0070;
+ } else {
+ alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+ alc_process_coef_fw(codec, coef0288);
+ msleep(350);
+ val = alc_read_coef_idx(codec, 0x50);
+ is_ctia = (val & 0x0070) == 0x0070;
+ }
+ alc_process_coef_fw(codec, coef0298);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ msleep(75);
+ snd_hda_codec_write(codec, 0x21, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ break;
+ case 0x10ec0286:
+ case 0x10ec0288:
+ alc_process_coef_fw(codec, coef0288);
+ msleep(350);
+ val = alc_read_coef_idx(codec, 0x50);
+ is_ctia = (val & 0x0070) == 0x0070;
+ break;
+ case 0x10ec0292:
+ alc_write_coef_idx(codec, 0x6b, 0xd429);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x6c);
+ is_ctia = (val & 0x001c) == 0x001c;
+ break;
+ case 0x10ec0293:
+ alc_process_coef_fw(codec, coef0293);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x0070) == 0x0070;
+ break;
+ case 0x10ec0668:
+ alc_process_coef_fw(codec, coef0688);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0xbe);
+ is_ctia = (val & 0x1c02) == 0x1c02;
+ break;
+ case 0x10ec0215:
+ case 0x10ec0225:
+ case 0x10ec0285:
+ case 0x10ec0295:
+ case 0x10ec0289:
+ case 0x10ec0299:
+ alc_process_coef_fw(codec, alc225_pre_hsmode);
+ alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
+ val = alc_read_coef_idx(codec, 0x45);
+ if (val & (1 << 9)) {
+ alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+ alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
+ msleep(800);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x00f0) == 0x00f0;
+ } else {
+ alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+ alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+ msleep(800);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x00f0) == 0x00f0;
+ }
+ if (!is_ctia) {
+ alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
+ alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+ msleep(100);
+ val = alc_read_coef_idx(codec, 0x46);
+ if ((val & 0x00f0) == 0x00f0)
+ is_ctia = false;
+ else
+ is_ctia = true;
+ }
+ alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
+ alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
+ alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+ break;
+ case 0x10ec0867:
+ is_ctia = true;
+ break;
+ }
+
+ codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
+ str_yes_no(is_ctia));
+ spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
+}
+
+static void alc_update_headset_mode(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+ hda_nid_t hp_pin = alc_get_hp_pin(spec);
+
+ int new_headset_mode;
+
+ if (!snd_hda_jack_detect(codec, hp_pin))
+ new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
+ else if (mux_pin == spec->headset_mic_pin)
+ new_headset_mode = ALC_HEADSET_MODE_HEADSET;
+ else if (mux_pin == spec->headphone_mic_pin)
+ new_headset_mode = ALC_HEADSET_MODE_MIC;
+ else
+ new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
+
+ if (new_headset_mode == spec->current_headset_mode) {
+ snd_hda_gen_update_outputs(codec);
+ return;
+ }
+
+ switch (new_headset_mode) {
+ case ALC_HEADSET_MODE_UNPLUGGED:
+ alc_headset_mode_unplugged(codec);
+ spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
+ spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
+ spec->gen.hp_jack_present = false;
+ break;
+ case ALC_HEADSET_MODE_HEADSET:
+ if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
+ alc_determine_headset_type(codec);
+ if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
+ alc_headset_mode_ctia(codec);
+ else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
+ alc_headset_mode_omtp(codec);
+ spec->gen.hp_jack_present = true;
+ break;
+ case ALC_HEADSET_MODE_MIC:
+ alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
+ spec->gen.hp_jack_present = false;
+ break;
+ case ALC_HEADSET_MODE_HEADPHONE:
+ alc_headset_mode_default(codec);
+ spec->gen.hp_jack_present = true;
+ break;
+ }
+ if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
+ snd_hda_set_pin_ctl_cache(codec, hp_pin,
+ AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+ if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
+ snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
+ PIN_VREFHIZ);
+ }
+ spec->current_headset_mode = new_headset_mode;
+
+ snd_hda_gen_update_outputs(codec);
+}
+
+static void alc_update_headset_mode_hook(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ alc_update_headset_mode(codec);
+}
+
+void alc_update_headset_jack_cb(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ snd_hda_gen_hp_automute(codec, jack);
+ alc_update_headset_mode(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_headset_jack_cb, "SND_HDA_CODEC_REALTEK");
+
+static void alc_probe_headset_mode(struct hda_codec *codec)
+{
+ int i;
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+ /* Find mic pins */
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
+ spec->headset_mic_pin = cfg->inputs[i].pin;
+ if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
+ spec->headphone_mic_pin = cfg->inputs[i].pin;
+ }
+
+ WARN_ON(spec->gen.cap_sync_hook);
+ spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
+ spec->gen.automute_hook = alc_update_headset_mode;
+ spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
+}
+
+void alc_fixup_headset_mode(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
+ break;
+ case HDA_FIXUP_ACT_PROBE:
+ alc_probe_headset_mode(codec);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ if (is_s3_resume(codec) || is_s4_resume(codec)) {
+ spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
+ spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
+ }
+ alc_update_headset_mode(codec);
+ break;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct alc_spec *spec = codec->spec;
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ }
+ else
+ alc_fixup_headset_mode(codec, fix, action);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode_no_hp_mic, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mic, "SND_HDA_CODEC_REALTEK");
+
+/* update LED status via GPIO */
+void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+ int polarity, bool enabled)
+{
+ if (polarity)
+ enabled = !enabled;
+ alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_gpio_led, "SND_HDA_CODEC_REALTEK");
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static int micmute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+ struct alc_spec *spec = codec->spec;
+
+ alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ spec->micmute_led_polarity, !brightness);
+ return 0;
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static int gpio_mute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+ struct alc_spec *spec = codec->spec;
+
+ alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
+ spec->mute_led_polarity, !brightness);
+ return 0;
+}
+
+/* setup mute and mic-mute GPIO bits, add hooks appropriately */
+void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+ int action,
+ unsigned int mute_mask,
+ unsigned int micmute_mask)
+{
+ struct alc_spec *spec = codec->spec;
+
+ alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ if (mute_mask) {
+ spec->gpio_mute_led_mask = mute_mask;
+ snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
+ }
+ if (micmute_mask) {
+ spec->gpio_mic_led_mask = micmute_mask;
+ snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_hp_gpio_led, "SND_HDA_CODEC_REALTEK");
+
+/* suppress the jack-detection */
+void alc_fixup_no_jack_detect(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ codec->no_jack_detect = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_no_jack_detect, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_disable_aamix(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct alc_spec *spec = codec->spec;
+ /* Disable AA-loopback as it causes white noise */
+ spec->gen.mixer_nid = 0;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_disable_aamix, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct alc_spec *spec = codec->spec;
+ spec->gen.auto_mute_via_amp = 1;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_auto_mute_via_amp, "SND_HDA_CODEC_REALTEK");
+
+MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek HD-audio codec helper");
diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h
new file mode 100644
index 000000000000..b2a919904c4c
--- /dev/null
+++ b/sound/hda/codecs/realtek/realtek.h
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek HD-audio codec support code
+//
+
+#ifndef __HDA_REALTEK_H
+#define __HDA_REALTEK_H
+
+#include <linux/acpi.h>
+#include <linux/cleanup.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "../side-codecs/hda_component.h"
+
+/* extra amp-initialization sequence types */
+enum {
+ ALC_INIT_UNDEFINED,
+ ALC_INIT_NONE,
+ ALC_INIT_DEFAULT,
+};
+
+enum {
+ ALC_HEADSET_MODE_UNKNOWN,
+ ALC_HEADSET_MODE_UNPLUGGED,
+ ALC_HEADSET_MODE_HEADSET,
+ ALC_HEADSET_MODE_MIC,
+ ALC_HEADSET_MODE_HEADPHONE,
+};
+
+enum {
+ ALC_HEADSET_TYPE_UNKNOWN,
+ ALC_HEADSET_TYPE_CTIA,
+ ALC_HEADSET_TYPE_OMTP,
+};
+
+enum {
+ ALC_KEY_MICMUTE_INDEX,
+};
+
+struct alc_customize_define {
+ unsigned int sku_cfg;
+ unsigned char port_connectivity;
+ unsigned char check_sum;
+ unsigned char customization;
+ unsigned char external_amp;
+ unsigned int enable_pcbeep:1;
+ unsigned int platform_type:1;
+ unsigned int swap:1;
+ unsigned int override:1;
+ unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
+};
+
+struct alc_coef_led {
+ unsigned int idx;
+ unsigned int mask;
+ unsigned int on;
+ unsigned int off;
+};
+
+struct alc_spec {
+ struct hda_gen_spec gen; /* must be at head */
+
+ /* codec parameterization */
+ struct alc_customize_define cdefine;
+ unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+ /* GPIO bits */
+ unsigned int gpio_mask;
+ unsigned int gpio_dir;
+ unsigned int gpio_data;
+ bool gpio_write_delay; /* add a delay before writing gpio_data */
+
+ /* mute LED for HP laptops, see vref_mute_led_set() */
+ int mute_led_polarity;
+ int micmute_led_polarity;
+ hda_nid_t mute_led_nid;
+ hda_nid_t cap_mute_led_nid;
+
+ unsigned int gpio_mute_led_mask;
+ unsigned int gpio_mic_led_mask;
+ struct alc_coef_led mute_led_coef;
+ struct alc_coef_led mic_led_coef;
+ struct mutex coef_mutex;
+
+ hda_nid_t headset_mic_pin;
+ hda_nid_t headphone_mic_pin;
+ int current_headset_mode;
+ int current_headset_type;
+
+ /* hooks */
+ void (*init_hook)(struct hda_codec *codec);
+ void (*power_hook)(struct hda_codec *codec);
+ void (*shutup)(struct hda_codec *codec);
+
+ int init_amp;
+ int codec_variant; /* flag for other variants */
+ unsigned int has_alc5505_dsp:1;
+ unsigned int no_depop_delay:1;
+ unsigned int done_hp_init:1;
+ unsigned int no_shutup_pins:1;
+ unsigned int ultra_low_power:1;
+ unsigned int has_hs_key:1;
+ unsigned int no_internal_mic_pin:1;
+ unsigned int en_3kpull_low:1;
+ int num_speaker_amps;
+
+ /* for PLL fix */
+ hda_nid_t pll_nid;
+ unsigned int pll_coef_idx, pll_coef_bit;
+ unsigned int coef0;
+ struct input_dev *kb_dev;
+ u8 alc_mute_keycode_map[1];
+
+ /* component binding */
+ struct hda_component_parent comps;
+};
+
+int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx);
+void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int coef_val);
+void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int mask,
+ unsigned int bits_set);
+#define alc_read_coef_idx(codec, coef_idx) \
+ alc_read_coefex_idx(codec, 0x20, coef_idx)
+#define alc_write_coef_idx(codec, coef_idx, coef_val) \
+ alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
+#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \
+ alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
+
+unsigned int alc_get_coef0(struct hda_codec *codec);
+
+/* coef writes/updates batch */
+struct coef_fw {
+ unsigned char nid;
+ unsigned char idx;
+ unsigned short mask;
+ unsigned short val;
+};
+
+#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
+ { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
+#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
+#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
+#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
+
+void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw);
+
+/*
+ * GPIO helpers
+ */
+void alc_setup_gpio(struct hda_codec *codec, unsigned int mask);
+void alc_write_gpio_data(struct hda_codec *codec);
+void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+ bool on);
+void alc_write_gpio(struct hda_codec *codec);
+
+/* common GPIO fixups */
+void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask);
+void alc_fixup_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_gpio2(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_gpio3(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_gpio4(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+
+/*
+ * Common init code, callbacks and helpers
+ */
+void alc_fix_pll(struct hda_codec *codec);
+void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int coef_bit);
+void alc_fill_eapd_coef(struct hda_codec *codec);
+void alc_auto_setup_eapd(struct hda_codec *codec, bool on);
+
+int alc_find_ext_mic_pin(struct hda_codec *codec);
+void alc_headset_mic_no_shutup(struct hda_codec *codec);
+void alc_shutup_pins(struct hda_codec *codec);
+void alc_eapd_shutup(struct hda_codec *codec);
+void alc_auto_init_amp(struct hda_codec *codec, int type);
+hda_nid_t alc_get_hp_pin(struct alc_spec *spec);
+int alc_auto_parse_customize_define(struct hda_codec *codec);
+int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports);
+void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports);
+int alc_build_controls(struct hda_codec *codec);
+void alc_update_knob_master(struct hda_codec *codec,
+ struct hda_jack_callback *jack);
+
+static inline void alc_pre_init(struct hda_codec *codec)
+{
+ alc_fill_eapd_coef(codec);
+}
+
+#define is_s3_resume(codec) \
+ ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
+#define is_s4_resume(codec) \
+ ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
+#define is_s4_suspend(codec) \
+ ((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
+
+int alc_init(struct hda_codec *codec);
+void alc_shutup(struct hda_codec *codec);
+void alc_power_eapd(struct hda_codec *codec);
+int alc_suspend(struct hda_codec *codec);
+int alc_resume(struct hda_codec *codec);
+
+int alc_parse_auto_config(struct hda_codec *codec,
+ const hda_nid_t *ignore_nids,
+ const hda_nid_t *ssid_nids);
+int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid);
+
+#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir);
+int alc_has_cdefine_beep(struct hda_codec *codec);
+#define set_beep_amp alc_set_beep_amp
+#define has_cdefine_beep alc_has_cdefine_beep
+#else
+#define set_beep_amp(spec, nid, idx, dir) 0
+#define has_cdefine_beep(codec) 0
+#endif
+
+static inline void rename_ctl(struct hda_codec *codec, const char *oldname,
+ const char *newname)
+{
+ struct snd_kcontrol *kctl;
+
+ kctl = snd_hda_find_mixer_ctl(codec, oldname);
+ if (kctl)
+ snd_ctl_rename(codec->card, kctl, newname);
+}
+
+/* Common fixups */
+void alc_fixup_sku_ignore(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_no_depop_delay(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_inv_dmic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_bass_chmap(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_headset_mode(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_update_headset_jack_cb(struct hda_codec *codec,
+ struct hda_jack_callback *jack);
+void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+ int polarity, bool enabled);
+void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+ int action,
+ unsigned int mute_mask,
+ unsigned int micmute_mask);
+void alc_fixup_no_jack_detect(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_disable_aamix(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+
+/* device-specific, but used by multiple codec drivers */
+void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action);
+void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action);
+void alc_fixup_dell_xps13(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+
+/*
+ * COEF access helper functions
+ */
+static inline void coef_mutex_lock(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ snd_hda_power_up_pm(codec);
+ mutex_lock(&spec->coef_mutex);
+}
+
+static inline void coef_mutex_unlock(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ mutex_unlock(&spec->coef_mutex);
+ snd_hda_power_down_pm(codec);
+}
+
+DEFINE_GUARD(coef_mutex, struct hda_codec *, coef_mutex_lock(_T), coef_mutex_unlock(_T))
+
+#endif /* __HDA_REALTEK_H */
diff --git a/sound/hda/codecs/senarytech.c b/sound/hda/codecs/senarytech.c
new file mode 100644
index 000000000000..63cda57cf786
--- /dev/null
+++ b/sound/hda/codecs/senarytech.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio codec driver for Senary HDA audio codec
+ *
+ * Initially based on conexant.c
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+/* GPIO node ID */
+#define SENARY_GPIO_NODE 0x01
+
+struct senary_spec {
+ struct hda_gen_spec gen;
+
+ /* extra EAPD pins */
+ unsigned int num_eapds;
+ hda_nid_t eapds[4];
+ hda_nid_t mute_led_eapd;
+
+ unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+ int mute_led_polarity;
+ unsigned int gpio_led;
+ unsigned int gpio_mute_led_mask;
+ unsigned int gpio_mic_led_mask;
+};
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new senary_beep_mixer[] = {
+ HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+};
+
+static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid,
+ int idx, int dir)
+{
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+ int i;
+
+ spec->gen.beep_nid = nid;
+ for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &senary_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
+ }
+ return 0;
+}
+
+static int senary_auto_parse_beep(struct hda_codec *codec)
+{
+ struct senary_spec *spec = codec->spec;
+ hda_nid_t nid;
+
+ for_each_hda_codec_node(nid, codec)
+ if ((get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) &&
+ (get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_AMP_OVRD)))
+ return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+ return 0;
+}
+#else
+#define senary_auto_parse_beep(codec) 0
+#endif
+
+/* parse EAPDs */
+static void senary_auto_parse_eapd(struct hda_codec *codec)
+{
+ struct senary_spec *spec = codec->spec;
+ hda_nid_t nid;
+
+ for_each_hda_codec_node(nid, codec) {
+ if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ continue;
+ if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+ continue;
+ spec->eapds[spec->num_eapds++] = nid;
+ if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+ break;
+ }
+}
+
+static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+ const hda_nid_t *pins, bool on)
+{
+ int i;
+
+ for (i = 0; i < num_pins; i++) {
+ if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+ snd_hda_codec_write(codec, pins[i], 0,
+ AC_VERB_SET_EAPD_BTLENABLE,
+ on ? 0x02 : 0);
+ }
+}
+
+/* turn on/off EAPD according to Master switch */
+static void senary_auto_vmaster_hook(void *private_data, int enabled)
+{
+ struct hda_codec *codec = private_data;
+ struct senary_spec *spec = codec->spec;
+
+ senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
+}
+
+static void senary_init_gpio_led(struct hda_codec *codec)
+{
+ struct senary_spec *spec = codec->spec;
+ unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
+
+ if (mask) {
+ snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_MASK,
+ mask);
+ snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_DIRECTION,
+ mask);
+ snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_led);
+ }
+}
+
+static int senary_init(struct hda_codec *codec)
+{
+ snd_hda_gen_init(codec);
+ senary_init_gpio_led(codec);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+ return 0;
+}
+
+static void senary_shutdown(struct hda_codec *codec)
+{
+ struct senary_spec *spec = codec->spec;
+
+ /* Turn the problematic codec into D3 to avoid spurious noises
+ * from the internal speaker during (and after) reboot
+ */
+ senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
+}
+
+static void senary_remove(struct hda_codec *codec)
+{
+ senary_shutdown(codec);
+ snd_hda_gen_remove(codec);
+}
+
+static int senary_suspend(struct hda_codec *codec)
+{
+ senary_shutdown(codec);
+ return 0;
+}
+
+static int senary_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct senary_spec *spec;
+ int err;
+
+ codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ snd_hda_gen_spec_init(&spec->gen);
+ codec->spec = spec;
+
+ senary_auto_parse_eapd(codec);
+ spec->gen.own_eapd_ctl = 1;
+
+ if (!spec->gen.vmaster_mute.hook)
+ spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
+ spec->parse_flags);
+ if (err < 0)
+ goto error;
+
+ err = senary_auto_parse_beep(codec);
+ if (err < 0)
+ goto error;
+
+ err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+ if (err < 0)
+ goto error;
+
+ /* Some laptops with Senary chips show stalls in S3 resume,
+ * which falls into the single-cmd mode.
+ * Better to make reset, then.
+ */
+ if (!codec->bus->core.sync_write) {
+ codec_info(codec,
+ "Enable sync_write for stable communication\n");
+ codec->bus->core.sync_write = 1;
+ codec->bus->allow_bus_reset = 1;
+ }
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ senary_remove(codec);
+ return err;
+}
+
+static const struct hda_codec_ops senary_codec_ops = {
+ .probe = senary_probe,
+ .remove = senary_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = senary_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = senary_suspend,
+ .check_power_status = snd_hda_gen_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ */
+
+static const struct hda_device_id snd_hda_id_senary[] = {
+ HDA_CODEC_ID(0x1fa86186, "SN6186"),
+ {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Senarytech HD-audio codec");
+
+static struct hda_codec_driver senary_driver = {
+ .id = snd_hda_id_senary,
+ .ops = &senary_codec_ops,
+};
+
+module_hda_codec_driver(senary_driver);
diff --git a/sound/pci/hda/patch_si3054.c b/sound/hda/codecs/si3054.c
index 763eae80a148..87cf9da9f3bf 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/hda/codecs/si3054.c
@@ -2,7 +2,7 @@
/*
* Universal Interface for Intel High Definition Audio Codec
*
- * HD audio interface patch for Silicon Labs 3054/5 modem codec
+ * HD audio codec driver for Silicon Labs 3054/5 modem codec
*
* Copyright (c) 2005 Sasha Khapyorsky <sashak@alsa-project.org>
* Takashi Iwai <tiwai@suse.de>
@@ -246,50 +246,48 @@ static int si3054_init(struct hda_codec *codec)
return 0;
}
-static void si3054_free(struct hda_codec *codec)
+static void si3054_remove(struct hda_codec *codec)
{
kfree(codec->spec);
}
-
/*
*/
-static const struct hda_codec_ops si3054_patch_ops = {
- .build_controls = si3054_build_controls,
- .build_pcms = si3054_build_pcms,
- .init = si3054_init,
- .free = si3054_free,
-};
-
-static int patch_si3054(struct hda_codec *codec)
+static int si3054_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
- struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
+ codec->spec = kzalloc(sizeof(struct si3054_spec), GFP_KERNEL);
+ if (!codec->spec)
return -ENOMEM;
- codec->spec = spec;
- codec->patch_ops = si3054_patch_ops;
return 0;
}
+static const struct hda_codec_ops si3054_codec_ops = {
+ .probe = si3054_probe,
+ .remove = si3054_remove,
+ .build_controls = si3054_build_controls,
+ .build_pcms = si3054_build_pcms,
+ .init = si3054_init,
+};
+
/*
- * patch entries
+ * driver entries
*/
static const struct hda_device_id snd_hda_id_si3054[] = {
- HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054),
- HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054),
+ HDA_CODEC_ID(0x163c3055, "Si3054"),
+ HDA_CODEC_ID(0x163c3155, "Si3054"),
+ HDA_CODEC_ID(0x11c13026, "Si3054"),
+ HDA_CODEC_ID(0x11c13055, "Si3054"),
+ HDA_CODEC_ID(0x11c13155, "Si3054"),
+ HDA_CODEC_ID(0x10573055, "Si3054"),
+ HDA_CODEC_ID(0x10573057, "Si3054"),
+ HDA_CODEC_ID(0x10573155, "Si3054"),
/* VIA HDA on Clevo m540 */
- HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054),
+ HDA_CODEC_ID(0x11063288, "Si3054"),
/* Asus A8J Modem (SM56) */
- HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054),
+ HDA_CODEC_ID(0x15433155, "Si3054"),
/* LG LW20 modem */
- HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054),
+ HDA_CODEC_ID(0x18540018, "Si3054"),
{}
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054);
@@ -299,6 +297,7 @@ MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
static struct hda_codec_driver si3054_driver = {
.id = snd_hda_id_si3054,
+ .ops = &si3054_codec_ops,
};
module_hda_codec_driver(si3054_driver);
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
new file mode 100644
index 000000000000..f674e9a9c7d7
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -0,0 +1,143 @@
+config SND_HDA_CIRRUS_SCODEC
+ tristate
+
+config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
+ tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
+ depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This builds KUnit tests for the cirrus side-codec library.
+ For more information on KUnit and unit tests in general,
+ please refer to the KUnit documentation in
+ Documentation/dev-tools/kunit/.
+ If in doubt, say "N".
+
+config SND_HDA_SCODEC_CS35L41
+ tristate
+ select SND_HDA_GENERIC
+ select REGMAP_IRQ
+ select FW_CS_DSP
+
+config SND_HDA_SCODEC_COMPONENT
+ tristate
+
+config SND_HDA_SCODEC_CS35L41_I2C
+ tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
+ depends on I2C
+ depends on ACPI
+ depends on EFI
+ depends on SND_SOC
+ select SND_SOC_CS35L41_LIB
+ select SND_HDA_SCODEC_CS35L41
+ select SND_SOC_CS_AMP_LIB
+ help
+ Say Y or M here to include CS35L41 I2C HD-audio side codec support
+ in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+ depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m
+
+config SND_HDA_SCODEC_CS35L41_SPI
+ tristate "Build CS35L41 HD-audio codec support for SPI Bus"
+ depends on SPI_MASTER
+ depends on ACPI
+ depends on EFI
+ depends on SND_SOC
+ select SND_SOC_CS35L41_LIB
+ select SND_HDA_SCODEC_CS35L41
+ select SND_SOC_CS_AMP_LIB
+ help
+ Say Y or M here to include CS35L41 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_CS35L41_SPI=m
+
+config SND_HDA_SCODEC_CS35L56
+ tristate
+
+config SND_HDA_SCODEC_CS35L56_I2C
+ tristate "Build CS35L56 HD-audio side codec support for I2C Bus"
+ depends on I2C
+ depends on ACPI
+ depends on SND_SOC
+ select FW_CS_DSP
+ imply SERIAL_MULTI_INSTANTIATE
+ select SND_HDA_GENERIC
+ select SND_SOC_CS35L56_SHARED
+ select SND_HDA_SCODEC_CS35L56
+ select SND_HDA_CIRRUS_SCODEC
+ select SND_SOC_CS_AMP_LIB
+ help
+ Say Y or M here to include CS35L56 amplifier support with
+ I2C control.
+
+config SND_HDA_SCODEC_CS35L56_SPI
+ tristate "Build CS35L56 HD-audio side codec support for SPI Bus"
+ depends on SPI_MASTER
+ depends on ACPI
+ depends on SND_SOC
+ select FW_CS_DSP
+ imply SERIAL_MULTI_INSTANTIATE
+ select SND_HDA_GENERIC
+ select SND_SOC_CS35L56_SHARED
+ select SND_HDA_SCODEC_CS35L56
+ select SND_HDA_CIRRUS_SCODEC
+ select SND_SOC_CS_AMP_LIB
+ help
+ Say Y or M here to include CS35L56 amplifier support with
+ SPI control.
+
+menu "CS35L56 driver options"
+ depends on SND_HDA_SCODEC_CS35L56
+
+config SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS
+ bool "CS35L56 create debugfs for factory calibration"
+ default N
+ depends on DEBUG_FS
+ select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
+ help
+ Create debugfs entries used during factory-line manufacture
+ for factory calibration.
+
+ If unsure select "N".
+endmenu
+
+config SND_HDA_SCODEC_TAS2781
+ tristate
+ select SND_HDA_GENERIC
+
+config SND_HDA_SCODEC_TAS2781_I2C
+ tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
+ depends on I2C
+ depends on ACPI
+ depends on EFI
+ depends on SND_SOC
+ select SND_HDA_SCODEC_TAS2781
+ select SND_SOC_TAS2781_COMLIB_I2C
+ select SND_SOC_TAS2781_FMWLIB
+ select CRC32
+ help
+ Say Y or M here to include TAS2781 I2C HD-audio side codec support
+ in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+ depends on SND_HDA=y && SND_HDA_SCODEC_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 SND_HDA_SCODEC_TAS2781
+ select SND_SOC_TAS2781_COMLIB
+ select SND_SOC_TAS2781_FMWLIB
+ select CRC8
+ 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
diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile
new file mode 100644
index 000000000000..245e84f6a121
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/Makefile
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-cirrus-scodec-y := cirrus_scodec.o
+snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o
+snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o
+snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o
+snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o
+snd-hda-scodec-cs35l56-y := cs35l56_hda.o
+snd-hda-scodec-cs35l56-i2c-y := cs35l56_hda_i2c.o
+snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o
+snd-hda-scodec-component-y := hda_component.o
+snd-hda-scodec-tas2781-y := tas2781_hda.o
+snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o
+snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o
+
+obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
+obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
+obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.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
diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec.c b/sound/hda/codecs/side-codecs/cirrus_scodec.c
new file mode 100644
index 000000000000..3c670207ba30
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cirrus_scodec.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Common code for Cirrus side-codecs.
+//
+// Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/dev_printk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+
+#include "cirrus_scodec.h"
+
+int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
+ int num_amps, int fixed_gpio_id)
+{
+ struct gpio_desc *speaker_id_desc;
+ int speaker_id = -ENOENT;
+
+ if (fixed_gpio_id >= 0) {
+ dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
+ speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
+ if (IS_ERR(speaker_id_desc)) {
+ speaker_id = PTR_ERR(speaker_id_desc);
+ return speaker_id;
+ }
+ speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
+ gpiod_put(speaker_id_desc);
+ } else {
+ int base_index;
+ int gpios_per_amp;
+ int count;
+ int tmp;
+ int i;
+
+ count = gpiod_count(dev, "spk-id");
+ if (count > 0) {
+ speaker_id = 0;
+ gpios_per_amp = count / num_amps;
+ base_index = gpios_per_amp * amp_index;
+
+ if (count % num_amps)
+ return -EINVAL;
+
+ dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
+
+ for (i = 0; i < gpios_per_amp; i++) {
+ speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
+ GPIOD_IN);
+ if (IS_ERR(speaker_id_desc)) {
+ speaker_id = PTR_ERR(speaker_id_desc);
+ break;
+ }
+ tmp = gpiod_get_value_cansleep(speaker_id_desc);
+ gpiod_put(speaker_id_desc);
+ if (tmp < 0) {
+ speaker_id = tmp;
+ break;
+ }
+ speaker_id |= tmp << i;
+ }
+ }
+ }
+
+ dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
+
+ return speaker_id;
+}
+EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, "SND_HDA_CIRRUS_SCODEC");
+
+MODULE_DESCRIPTION("HDA Cirrus side-codec library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec.h b/sound/hda/codecs/side-codecs/cirrus_scodec.h
new file mode 100644
index 000000000000..ba2041d8ef24
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cirrus_scodec.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef CIRRUS_SCODEC_H
+#define CIRRUS_SCODEC_H
+
+int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
+ int num_amps, int fixed_gpio_id);
+
+#endif /* CIRRUS_SCODEC_H */
diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c
new file mode 100644
index 000000000000..3cca750857b6
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// KUnit test for the Cirrus side-codec library.
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/platform_device.h>
+#include <kunit/resource.h>
+#include <kunit/test.h>
+#include <linux/device.h>
+#include <linux/device/faux.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "cirrus_scodec.h"
+
+KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
+ struct faux_device *)
+KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper,
+ device_remove_software_node,
+ struct device *)
+
+struct cirrus_scodec_test_gpio {
+ unsigned int pin_state;
+ struct gpio_chip chip;
+};
+
+struct cirrus_scodec_test_priv {
+ struct faux_device *amp_dev;
+ struct platform_device *gpio_pdev;
+ struct cirrus_scodec_test_gpio *gpio_priv;
+};
+
+static int cirrus_scodec_test_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int cirrus_scodec_test_gpio_direction_in(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return 0;
+}
+
+static int cirrus_scodec_test_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct cirrus_scodec_test_gpio *gpio_priv = gpiochip_get_data(chip);
+
+ return !!(gpio_priv->pin_state & BIT(offset));
+}
+
+static int cirrus_scodec_test_gpio_direction_out(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ return -EOPNOTSUPP;
+}
+
+static int cirrus_scodec_test_gpio_set(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ return -EOPNOTSUPP;
+}
+
+static int cirrus_scodec_test_gpio_set_config(struct gpio_chip *gc,
+ unsigned int offset,
+ unsigned long config)
+{
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_LEVEL:
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ return -EOPNOTSUPP;
+ default:
+ return 0;
+ }
+}
+
+static const struct gpio_chip cirrus_scodec_test_gpio_chip = {
+ .label = "cirrus_scodec_test_gpio",
+ .owner = THIS_MODULE,
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
+ .get_direction = cirrus_scodec_test_gpio_get_direction,
+ .direction_input = cirrus_scodec_test_gpio_direction_in,
+ .get = cirrus_scodec_test_gpio_get,
+ .direction_output = cirrus_scodec_test_gpio_direction_out,
+ .set = cirrus_scodec_test_gpio_set,
+ .set_config = cirrus_scodec_test_gpio_set_config,
+ .base = -1,
+ .ngpio = 32,
+};
+
+static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev)
+{
+ struct cirrus_scodec_test_gpio *gpio_priv;
+ int ret;
+
+ gpio_priv = devm_kzalloc(&pdev->dev, sizeof(*gpio_priv), GFP_KERNEL);
+ if (!gpio_priv)
+ return -ENOMEM;
+
+ /* GPIO core modifies our struct gpio_chip so use a copy */
+ gpio_priv->chip = cirrus_scodec_test_gpio_chip;
+ ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n");
+
+ dev_set_drvdata(&pdev->dev, gpio_priv);
+
+ return 0;
+}
+
+static struct platform_driver cirrus_scodec_test_gpio_driver = {
+ .driver.name = "cirrus_scodec_test_gpio_drv",
+ .driver.owner = THIS_MODULE,
+ .probe = cirrus_scodec_test_gpio_probe,
+};
+
+/* software_node referencing the gpio driver */
+static const struct software_node cirrus_scodec_test_gpio_swnode = {
+ .name = "cirrus_scodec_test_gpio",
+};
+
+static void cirrus_scodec_test_create_gpio(struct kunit *test)
+{
+ struct cirrus_scodec_test_priv *priv = test->priv;
+
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_platform_driver_register(test, &cirrus_scodec_test_gpio_driver));
+
+ priv->gpio_pdev = kunit_platform_device_alloc(test,
+ cirrus_scodec_test_gpio_driver.driver.name,
+ PLATFORM_DEVID_NONE);
+ KUNIT_ASSERT_NOT_NULL(test, priv->gpio_pdev);
+
+ KUNIT_ASSERT_EQ(test, 0, device_add_software_node(&priv->gpio_pdev->dev,
+ &cirrus_scodec_test_gpio_swnode));
+ KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test,
+ device_remove_software_node_wrapper,
+ &priv->gpio_pdev->dev));
+
+ KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, priv->gpio_pdev));
+
+ priv->gpio_priv = dev_get_drvdata(&priv->gpio_pdev->dev);
+ KUNIT_ASSERT_NOT_NULL(test, priv->gpio_priv);
+}
+
+static void cirrus_scodec_test_set_gpio_ref_arg(struct software_node_ref_args *arg,
+ int gpio_num)
+{
+ struct software_node_ref_args template =
+ SOFTWARE_NODE_REFERENCE(&cirrus_scodec_test_gpio_swnode, gpio_num, 0);
+
+ *arg = template;
+}
+
+static int cirrus_scodec_test_set_spkid_swnode(struct kunit *test,
+ struct device *dev,
+ struct software_node_ref_args *args,
+ int num_args)
+{
+ const struct property_entry props_template[] = {
+ PROPERTY_ENTRY_REF_ARRAY_LEN("spk-id-gpios", args, num_args),
+ { }
+ };
+ struct property_entry *props;
+ struct software_node *node;
+
+ node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ props = kunit_kzalloc(test, sizeof(props_template), GFP_KERNEL);
+ if (!props)
+ return -ENOMEM;
+
+ memcpy(props, props_template, sizeof(props_template));
+ node->properties = props;
+
+ return device_add_software_node(dev, node);
+}
+
+struct cirrus_scodec_test_spkid_param {
+ int num_amps;
+ int gpios_per_amp;
+ int num_amps_sharing;
+};
+
+static void cirrus_scodec_test_spkid_parse(struct kunit *test)
+{
+ struct cirrus_scodec_test_priv *priv = test->priv;
+ const struct cirrus_scodec_test_spkid_param *param = test->param_value;
+ int num_spk_id_refs = param->num_amps * param->gpios_per_amp;
+ struct software_node_ref_args *refs;
+ struct device *dev = &priv->amp_dev->dev;
+ unsigned int v;
+ int i, ret;
+
+ refs = kunit_kcalloc(test, num_spk_id_refs, sizeof(*refs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, refs);
+
+ for (i = 0, v = 0; i < num_spk_id_refs; ) {
+ cirrus_scodec_test_set_gpio_ref_arg(&refs[i++], v++);
+
+ /*
+ * If amps are sharing GPIOs repeat the last set of
+ * GPIOs until we've done that number of amps.
+ * We have done all GPIOs for an amp when i is a multiple
+ * of gpios_per_amp.
+ * We have done all amps sharing the same GPIOs when i is
+ * a multiple of (gpios_per_amp * num_amps_sharing).
+ */
+ if (!(i % param->gpios_per_amp) &&
+ (i % (param->gpios_per_amp * param->num_amps_sharing)))
+ v -= param->gpios_per_amp;
+ }
+
+ ret = cirrus_scodec_test_set_spkid_swnode(test, dev, refs, num_spk_id_refs);
+ KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Failed to add swnode\n");
+
+ for (i = 0; i < param->num_amps; ++i) {
+ for (v = 0; v < (1 << param->gpios_per_amp); ++v) {
+ /* Set only the GPIO bits used by this amp */
+ priv->gpio_priv->pin_state =
+ v << (param->gpios_per_amp * (i / param->num_amps_sharing));
+
+ ret = cirrus_scodec_get_speaker_id(dev, i, param->num_amps, -1);
+ KUNIT_EXPECT_EQ_MSG(test, ret, v,
+ "get_speaker_id failed amp:%d pin_state:%#x\n",
+ i, priv->gpio_priv->pin_state);
+ }
+ }
+}
+
+static void cirrus_scodec_test_no_spkid(struct kunit *test)
+{
+ struct cirrus_scodec_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ int ret;
+
+ ret = cirrus_scodec_get_speaker_id(dev, 0, 4, -1);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+static int cirrus_scodec_test_case_init(struct kunit *test)
+{
+ struct cirrus_scodec_test_priv *priv;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ test->priv = priv;
+
+ /* Create dummy GPIO */
+ cirrus_scodec_test_create_gpio(test);
+
+ /* Create dummy amp driver dev */
+ priv->amp_dev = faux_device_create("cirrus_scodec_test_amp_drv", NULL, NULL);
+ KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
+ KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test,
+ faux_device_destroy_wrapper,
+ priv->amp_dev));
+
+ return 0;
+}
+
+static const struct cirrus_scodec_test_spkid_param cirrus_scodec_test_spkid_param_cases[] = {
+ { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 1 },
+ { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 1 },
+ { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 1 },
+ { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 1 },
+ { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 1 },
+ { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 1 },
+ { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 1 },
+ { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 1 },
+ { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 1 },
+ { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 1 },
+ { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 1 },
+ { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 1 },
+
+ /* Same GPIO shared by all amps */
+ { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 2 },
+ { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 2 },
+ { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 2 },
+ { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 2 },
+ { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 3 },
+ { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 3 },
+ { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 3 },
+ { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 3 },
+ { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 4 },
+ { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 4 },
+ { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 4 },
+ { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 4 },
+
+ /* Two sets of shared GPIOs */
+ { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 2 },
+ { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 2 },
+ { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 2 },
+ { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 2 },
+};
+
+static void cirrus_scodec_test_spkid_param_desc(const struct cirrus_scodec_test_spkid_param *param,
+ char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE, "amps:%d gpios_per_amp:%d num_amps_sharing:%d",
+ param->num_amps, param->gpios_per_amp, param->num_amps_sharing);
+}
+
+KUNIT_ARRAY_PARAM(cirrus_scodec_test_spkid, cirrus_scodec_test_spkid_param_cases,
+ cirrus_scodec_test_spkid_param_desc);
+
+static struct kunit_case cirrus_scodec_test_cases[] = {
+ KUNIT_CASE_PARAM(cirrus_scodec_test_spkid_parse, cirrus_scodec_test_spkid_gen_params),
+ KUNIT_CASE(cirrus_scodec_test_no_spkid),
+ { } /* terminator */
+};
+
+static struct kunit_suite cirrus_scodec_test_suite = {
+ .name = "snd-hda-scodec-cs35l56-test",
+ .init = cirrus_scodec_test_case_init,
+ .test_cases = cirrus_scodec_test_cases,
+};
+
+kunit_test_suite(cirrus_scodec_test_suite);
+
+MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");
+MODULE_DESCRIPTION("KUnit test for the Cirrus side-codec library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
index b5210abb5141..c0f2a3ff77a1 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -12,15 +12,16 @@
#include <sound/hda_codec.h>
#include <sound/soc.h>
#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/vmalloc.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
#include "hda_component.h"
#include "cs35l41_hda.h"
-#include "hda_cs_dsp_ctl.h"
+#include "cs35l41_hda_property.h"
-#define CS35L41_FIRMWARE_ROOT "cirrus/"
#define CS35L41_PART "cs35l41"
#define HALO_STATE_DSP_CTL_NAME "HALO_STATE"
@@ -32,58 +33,102 @@
#define CAL_AMBIENT_DSP_CTL_NAME "CAL_AMBIENT"
#define CAL_DSP_CTL_TYPE 5
#define CAL_DSP_CTL_ALG 205
+#define CS35L41_UUID "50d90cdc-3de4-4f18-b528-c7fe3b71f40d"
+#define CS35L41_DSM_GET_MUTE 5
+#define CS35L41_NOTIFY_EVENT 0x91
+#define CS35L41_TUNING_SIG 0x109A4A35
+
+enum cs35l41_tuning_param_types {
+ TUNING_PARAM_GAIN,
+};
+
+struct cs35l41_tuning_param_hdr {
+ __le32 tuning_index;
+ __le32 type;
+ __le32 size;
+} __packed;
+
+struct cs35l41_tuning_param {
+ struct cs35l41_tuning_param_hdr hdr;
+ union {
+ __le32 gain;
+ };
+} __packed;
+
+struct cs35l41_tuning_params {
+ __le32 signature;
+ __le32 version;
+ __le32 size;
+ __le32 num_entries;
+ u8 data[];
+} __packed;
+
+/* Firmware calibration controls */
+static const struct cirrus_amp_cal_controls cs35l41_calibration_controls = {
+ .alg_id = CAL_DSP_CTL_ALG,
+ .mem_region = CAL_DSP_CTL_TYPE,
+ .ambient = CAL_AMBIENT_DSP_CTL_NAME,
+ .calr = CAL_R_DSP_CTL_NAME,
+ .status = CAL_STATUS_DSP_CTL_NAME,
+ .checksum = CAL_CHECKSUM_DSP_CTL_NAME,
+};
+
+enum cs35l41_hda_fw_id {
+ CS35L41_HDA_FW_SPK_PROT,
+ CS35L41_HDA_FW_SPK_CALI,
+ CS35L41_HDA_FW_SPK_DIAG,
+ CS35L41_HDA_FW_MISC,
+ CS35L41_HDA_NUM_FW
+};
+
+static const char * const cs35l41_hda_fw_ids[CS35L41_HDA_NUM_FW] = {
+ [CS35L41_HDA_FW_SPK_PROT] = "spk-prot",
+ [CS35L41_HDA_FW_SPK_CALI] = "spk-cali",
+ [CS35L41_HDA_FW_SPK_DIAG] = "spk-diag",
+ [CS35L41_HDA_FW_MISC] = "misc",
+};
static bool firmware_autostart = 1;
module_param(firmware_autostart, bool, 0444);
MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot"
"(0=Disable, 1=Enable) (default=1); ");
+static const char channel_name[3] = { 'L', 'R', 'C' };
+
static const struct reg_sequence cs35l41_hda_config[] = {
{ CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
{ CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz
- { CS35L41_SP_ENABLES, 0x00010000 }, // ASP_RX1_EN = 1
{ CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
{ CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
- { CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused
{ CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot
{ CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot
- { CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1
{ CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON
{ CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON
- { CS35L41_ASP_TX3_SRC, 0x00000032 }, // ASPTX3 SRC = ERRVOL
- { CS35L41_ASP_TX4_SRC, 0x00000033 }, // ASPTX4 SRC = CLASSH_TGT
- { CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1
- { CS35L41_DSP1_RX2_SRC, 0x00000009 }, // DSP1RX2 SRC = ASPRX2
{ CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON
{ CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON
+};
+
+static const struct reg_sequence cs35l41_hda_config_no_dsp[] = {
+ { CS35L41_SP_HIZ_CTRL, 0x00000002 }, // Hi-Z unused
+ { CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1
+ { CS35L41_ASP_TX3_SRC, 0x00000000 }, // ASPTX3 SRC = ZERO FILL
+ { CS35L41_ASP_TX4_SRC, 0x00000000 }, // ASPTX4 SRC = ZERO FILL
{ CS35L41_DSP1_RX5_SRC, 0x00000020 }, // DSP1RX5 SRC = ERRVOL
- { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB
- { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB
+ { CS35L41_DSP1_RX6_SRC, 0x00000021 }, // DSP1RX6 SRC = CLASSH_TGT
};
static const struct reg_sequence cs35l41_hda_config_dsp[] = {
- { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
- { CS35L41_DSP_CLK_CTRL, 0x00000003 }, // DSP CLK EN
- { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz
- { CS35L41_SP_ENABLES, 0x00010001 }, // ASP_RX1_EN = 1, ASP_TX1_EN = 1
- { CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
- { CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
{ CS35L41_SP_HIZ_CTRL, 0x00000003 }, // Hi-Z unused/disabled
- { CS35L41_SP_TX_WL, 0x00000018 }, // 24 cycles/slot
- { CS35L41_SP_RX_WL, 0x00000018 }, // 24 cycles/slot
- { CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = ERR_VOL
- { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON
- { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON
+ { CS35L41_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = DSP1TX1
{ CS35L41_ASP_TX3_SRC, 0x00000028 }, // ASPTX3 SRC = VPMON
{ CS35L41_ASP_TX4_SRC, 0x00000029 }, // ASPTX4 SRC = VBSTMON
- { CS35L41_DSP1_RX1_SRC, 0x00000008 }, // DSP1RX1 SRC = ASPRX1
- { CS35L41_DSP1_RX2_SRC, 0x00000008 }, // DSP1RX2 SRC = ASPRX1
- { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON
- { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON
- { CS35L41_DSP1_RX5_SRC, 0x00000029 }, // DSP1RX5 SRC = VBSTMON
+ { CS35L41_DSP1_RX6_SRC, 0x00000029 }, // DSP1RX6 SRC = VBSTMON
+};
+
+static const struct reg_sequence cs35l41_hda_unmute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB
- { CS35L41_AMP_GAIN_CTRL, 0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB
+ { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB
};
static const struct reg_sequence cs35l41_hda_mute[] = {
@@ -91,24 +136,34 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM Mute
};
-static void cs35l41_add_controls(struct cs35l41_hda *cs35l41)
+static const struct cs_dsp_client_ops client_ops = {
+ /* cs_dsp requires the client to provide this even if it is empty */
+};
+
+static int cs35l41_request_tuning_param_file(struct cs35l41_hda *cs35l41, char *tuning_filename,
+ const struct firmware **firmware, char **filename,
+ const char *ssid)
{
- struct hda_cs_dsp_ctl_info info;
+ int ret = 0;
- info.device_name = cs35l41->amp_name;
- info.fw_type = cs35l41->firmware_type;
- info.card = cs35l41->codec->card;
+ /* Filename is the same as the tuning file with "cfg" suffix */
+ *filename = kasprintf(GFP_KERNEL, "%scfg", tuning_filename);
+ if (*filename == NULL)
+ return -ENOMEM;
- hda_cs_dsp_add_controls(&cs35l41->cs_dsp, &info);
-}
+ ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
+ if (ret != 0) {
+ dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
+ kfree(*filename);
+ *filename = NULL;
+ }
-static const struct cs_dsp_client_ops client_ops = {
- .control_remove = hda_cs_dsp_control_remove,
-};
+ return ret;
+}
static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
const struct firmware **firmware, char **filename,
- const char *dir, const char *ssid, const char *amp_name,
+ const char *ssid, const char *amp_name,
int spkid, const char *filetype)
{
const char * const dsp_name = cs35l41->cs_dsp.name;
@@ -116,24 +171,24 @@ static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
int ret = 0;
if (spkid > -1 && ssid && amp_name)
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d-%s.%s", dir, CS35L41_PART,
- dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+ *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART,
+ dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
ssid, spkid, amp_name, filetype);
else if (spkid > -1 && ssid)
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d.%s", dir, CS35L41_PART,
- dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+ *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d.%s", CS35L41_PART,
+ dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
ssid, spkid, filetype);
else if (ssid && amp_name)
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, CS35L41_PART,
- dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+ *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-%s.%s", CS35L41_PART,
+ dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
ssid, amp_name, filetype);
else if (ssid)
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, CS35L41_PART,
- dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+ *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s.%s", CS35L41_PART,
+ dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
ssid, filetype);
else
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, CS35L41_PART,
- dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+ *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s.%s", CS35L41_PART,
+ dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
filetype);
if (*filename == NULL)
@@ -173,65 +228,110 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT,
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
cs35l41->speaker_id, "wmfw");
if (!ret) {
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
- return cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
- cs35l41->acpi_subsystem_id, cs35l41->amp_name,
- cs35l41->speaker_id, "bin");
+ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+ cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+ cs35l41->speaker_id, "bin");
+ if (ret)
+ goto coeff_err;
+
+ return 0;
}
/* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+ cs35l41->acpi_subsystem_id,
cs35l41->amp_name, -1, "wmfw");
if (!ret) {
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
- return cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
- cs35l41->acpi_subsystem_id, cs35l41->amp_name,
- cs35l41->speaker_id, "bin");
+ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+ cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+ cs35l41->speaker_id, "bin");
+ if (ret)
+ goto coeff_err;
+
+ return 0;
}
/* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+ cs35l41->acpi_subsystem_id,
NULL, cs35l41->speaker_id, "wmfw");
if (!ret) {
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
cs35l41->acpi_subsystem_id,
cs35l41->amp_name, cs35l41->speaker_id, "bin");
if (ret)
/* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
- return cs35l41_request_firmware_file(cs35l41, coeff_firmware,
- coeff_filename, CS35L41_FIRMWARE_ROOT,
- cs35l41->acpi_subsystem_id, NULL,
- cs35l41->speaker_id, "bin");
+ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
+ coeff_filename,
+ cs35l41->acpi_subsystem_id, NULL,
+ cs35l41->speaker_id, "bin");
+ if (ret)
+ goto coeff_err;
+
+ return 0;
}
/* try cirrus/part-dspN-fwtype-sub.wmfw */
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+ cs35l41->acpi_subsystem_id,
NULL, -1, "wmfw");
if (!ret) {
/* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
cs35l41->speaker_id, "bin");
if (ret)
/* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
- return cs35l41_request_firmware_file(cs35l41, coeff_firmware,
- coeff_filename, CS35L41_FIRMWARE_ROOT,
- cs35l41->acpi_subsystem_id, NULL,
- cs35l41->speaker_id, "bin");
+ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
+ coeff_filename,
+ cs35l41->acpi_subsystem_id, NULL,
+ cs35l41->speaker_id, "bin");
+ if (ret)
+ goto coeff_err;
+ }
+
+ return ret;
+coeff_err:
+ release_firmware(*wmfw_firmware);
+ kfree(*wmfw_filename);
+ return ret;
+}
+
+static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41,
+ const struct firmware **wmfw_firmware,
+ char **wmfw_filename,
+ const struct firmware **coeff_firmware,
+ char **coeff_filename)
+{
+ int ret;
+
+ /* Handle fallback */
+ dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
+
+ /* fallback try cirrus/part-dspN-fwtype.wmfw */
+ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+ NULL, NULL, -1, "wmfw");
+ if (ret)
+ goto err;
+
+ /* fallback try cirrus/part-dspN-fwtype.bin */
+ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+ NULL, NULL, -1, "bin");
+ if (ret) {
+ release_firmware(*wmfw_firmware);
+ kfree(*wmfw_filename);
+ goto err;
}
+ return 0;
+err:
+ dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
return ret;
}
@@ -247,155 +347,212 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
ret = cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
coeff_firmware, coeff_filename);
goto out;
-
}
/* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+ cs35l41->acpi_subsystem_id,
cs35l41->amp_name, -1, "wmfw");
if (!ret) {
/* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-1, "bin");
+ if (ret)
+ goto coeff_err;
+
goto out;
}
/* try cirrus/part-dspN-fwtype-sub.wmfw */
ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+ cs35l41->acpi_subsystem_id,
NULL, -1, "wmfw");
if (!ret) {
/* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
cs35l41->acpi_subsystem_id,
cs35l41->amp_name, -1, "bin");
if (ret)
/* try cirrus/part-dspN-fwtype-sub.bin */
ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT,
cs35l41->acpi_subsystem_id, NULL, -1,
"bin");
+ if (ret)
+ goto coeff_err;
}
out:
- if (!ret)
- return 0;
+ if (ret)
+ /* if all attempts at finding firmware fail, try fallback */
+ goto fallback;
- /* Handle fallback */
- dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
+ return 0;
+coeff_err:
release_firmware(*wmfw_firmware);
kfree(*wmfw_filename);
+fallback:
+ return cs35l41_fallback_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+ coeff_firmware, coeff_filename);
+}
- /* fallback try cirrus/part-dspN-fwtype.wmfw */
- ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
- CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
- if (!ret)
- /* fallback try cirrus/part-dspN-fwtype.bin */
- ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
- CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
- if (ret) {
- release_firmware(*wmfw_firmware);
- kfree(*wmfw_filename);
- dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
- }
- return ret;
+static void cs35l41_hda_apply_calibration(struct cs35l41_hda *cs35l41)
+{
+ int ret;
+
+ if (!cs35l41->cal_data_valid)
+ return;
+
+ ret = cs_amp_write_cal_coeffs(&cs35l41->cs_dsp, &cs35l41_calibration_controls,
+ &cs35l41->cal_data);
+ if (ret < 0)
+ dev_warn(cs35l41->dev, "Failed to apply calibration: %d\n", ret);
+ else
+ dev_info(cs35l41->dev, "Calibration applied: R0=%d\n", cs35l41->cal_data.calR);
}
-#if IS_ENABLED(CONFIG_EFI)
-static int cs35l41_apply_calibration(struct cs35l41_hda *cs35l41, unsigned int ambient,
- unsigned int r0, unsigned int status, unsigned int checksum)
+static int cs35l41_read_silicon_uid(struct cs35l41_hda *cs35l41, u64 *uid)
{
+ u32 tmp;
int ret;
- ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_AMBIENT_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
- CAL_DSP_CTL_ALG, &ambient, 4);
+ ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS2, &tmp);
if (ret) {
- dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_AMBIENT_DSP_CTL_NAME,
- ret);
+ dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS2: %d\n", ret);
return ret;
}
- ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_R_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
- CAL_DSP_CTL_ALG, &r0, 4);
+
+ *uid = tmp;
+ *uid <<= 32;
+
+ ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS1, &tmp);
if (ret) {
- dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_R_DSP_CTL_NAME, ret);
+ dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS1: %d\n", ret);
return ret;
}
- ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_STATUS_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
- CAL_DSP_CTL_ALG, &status, 4);
- if (ret) {
- dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_STATUS_DSP_CTL_NAME,
- ret);
+
+ *uid |= tmp;
+
+ dev_dbg(cs35l41->dev, "UniqueID = %#llx\n", *uid);
+
+ return 0;
+}
+
+static int cs35l41_get_calibration(struct cs35l41_hda *cs35l41)
+{
+ u64 silicon_uid;
+ int ret;
+
+ ret = cs35l41_read_silicon_uid(cs35l41, &silicon_uid);
+ if (ret < 0)
return ret;
- }
- ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_CHECKSUM_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
- CAL_DSP_CTL_ALG, &checksum, 4);
- if (ret) {
- dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_CHECKSUM_DSP_CTL_NAME,
- ret);
+
+ ret = cs_amp_get_efi_calibration_data(cs35l41->dev, silicon_uid,
+ cs35l41->index,
+ &cs35l41->cal_data);
+
+ /* Only return an error status if probe should be aborted */
+ if ((ret == -ENOENT) || (ret == -EOVERFLOW))
+ return 0;
+
+ if (ret < 0)
return ret;
- }
+
+ cs35l41->cal_data_valid = true;
return 0;
}
-static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41)
+
+static void cs35l41_set_default_tuning_params(struct cs35l41_hda *cs35l41)
{
- static 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"CirrusSmartAmpCalibrationData";
- const struct cs35l41_amp_efi_data *efi_data;
- const struct cs35l41_amp_cal_data *cl;
- unsigned long data_size = 0;
- efi_status_t status;
- int ret = 0;
- u8 *data = NULL;
- u32 attr;
+ cs35l41->tuning_gain = DEFAULT_AMP_GAIN_PCM;
+}
- /* Get real size of UEFI variable */
- status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data);
- if (status == EFI_BUFFER_TOO_SMALL) {
- ret = -ENODEV;
- /* Allocate data buffer of data_size bytes */
- data = vmalloc(data_size);
- if (!data)
- return -ENOMEM;
- /* Get variable contents into buffer */
- status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data);
- if (status == EFI_SUCCESS) {
- efi_data = (struct cs35l41_amp_efi_data *)data;
- dev_dbg(cs35l41->dev, "Calibration: Size=%d, Amp Count=%d\n",
- efi_data->size, efi_data->count);
- if (efi_data->count > cs35l41->index) {
- cl = &efi_data->data[cs35l41->index];
- dev_dbg(cs35l41->dev,
- "Calibration: Ambient=%02x, Status=%02x, R0=%d\n",
- cl->calAmbient, cl->calStatus, cl->calR);
-
- /* Calibration can only be applied whilst the DSP is not running */
- ret = cs35l41_apply_calibration(cs35l41,
- cpu_to_be32(cl->calAmbient),
- cpu_to_be32(cl->calR),
- cpu_to_be32(cl->calStatus),
- cpu_to_be32(cl->calR + 1));
- }
+static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct firmware *firmware)
+{
+ struct cs35l41_tuning_params *params;
+ unsigned int offset = 0;
+ unsigned int end;
+ int i;
+
+ params = (void *)&firmware->data[0];
+
+ if (le32_to_cpu(params->size) != firmware->size) {
+ dev_err(cs35l41->dev, "Wrong Size for Tuning Param file. Expected %d got %zu\n",
+ le32_to_cpu(params->size), firmware->size);
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(params->version) != 1) {
+ dev_err(cs35l41->dev, "Unsupported Tuning Param Version: %d\n",
+ le32_to_cpu(params->version));
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(params->signature) != CS35L41_TUNING_SIG) {
+ dev_err(cs35l41->dev,
+ "Mismatched Signature for Tuning Param file. Expected %#x got %#x\n",
+ CS35L41_TUNING_SIG, le32_to_cpu(params->signature));
+ return -EINVAL;
+ }
+
+ end = firmware->size - sizeof(struct cs35l41_tuning_params);
+
+ for (i = 0; i < le32_to_cpu(params->num_entries); i++) {
+ struct cs35l41_tuning_param *param;
+
+ if ((offset >= end) || ((offset + sizeof(struct cs35l41_tuning_param_hdr)) >= end))
+ return -EFAULT;
+
+ param = (void *)&params->data[offset];
+ offset += le32_to_cpu(param->hdr.size);
+
+ if (offset > end)
+ return -EFAULT;
+
+ switch (le32_to_cpu(param->hdr.type)) {
+ case TUNING_PARAM_GAIN:
+ cs35l41->tuning_gain = le32_to_cpu(param->gain);
+ dev_dbg(cs35l41->dev, "Applying Gain: %d\n", cs35l41->tuning_gain);
+ break;
+ default:
+ break;
}
- vfree(data);
}
- return ret;
+
+ return 0;
}
-#else
-static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41)
+
+static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename)
{
- dev_warn(cs35l41->dev, "Calibration not supported without EFI support.\n");
- return 0;
+ const struct firmware *tuning_param_file = NULL;
+ char *tuning_param_filename = NULL;
+ int ret;
+
+ ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file,
+ &tuning_param_filename, cs35l41->acpi_subsystem_id);
+ if (ret) {
+ dev_dbg(cs35l41->dev, "Missing Tuning Param for file: %s: %d\n", tuning_filename,
+ ret);
+ return 0;
+ }
+
+ ret = cs35l41_read_tuning_params(cs35l41, tuning_param_file);
+ if (ret) {
+ dev_err(cs35l41->dev, "Error reading Tuning Params from file: %s: %d\n",
+ tuning_param_filename, ret);
+ /* Reset to default Tuning Parameters */
+ cs35l41_set_default_tuning_params(cs35l41);
+ }
+
+ release_firmware(tuning_param_file);
+ kfree(tuning_param_filename);
+
+ return ret;
}
-#endif
static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
{
@@ -416,27 +573,33 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
cs35l41->halo_initialized = true;
}
+ cs35l41_set_default_tuning_params(cs35l41);
+
ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename,
&coeff_firmware, &coeff_filename);
if (ret < 0)
return ret;
dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename);
- if (coeff_filename)
+ if (coeff_filename) {
dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename);
- else
+ ret = cs35l41_load_tuning_params(cs35l41, coeff_filename);
+ if (ret)
+ dev_warn(cs35l41->dev, "Unable to load Tuning Parameters: %d\n", ret);
+ } else {
dev_warn(cs35l41->dev, "No Coefficient File available.\n");
+ }
ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
- hda_cs_dsp_fw_ids[cs35l41->firmware_type]);
+ cs35l41_hda_fw_ids[cs35l41->firmware_type]);
if (ret)
- goto err_release;
-
- cs35l41_add_controls(cs35l41);
+ goto err;
- ret = cs35l41_save_calibration(cs35l41);
+ cs35l41_hda_apply_calibration(cs35l41);
-err_release:
+err:
+ if (ret)
+ cs35l41_set_default_tuning_params(cs35l41);
release_firmware(wmfw_firmware);
release_firmware(coeff_firmware);
kfree(wmfw_filename);
@@ -449,9 +612,9 @@ static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
{
struct cs_dsp *dsp = &cs35l41->cs_dsp;
+ cs35l41_set_default_tuning_params(cs35l41);
cs_dsp_stop(dsp);
cs_dsp_power_down(dsp);
- cs35l41->firmware_running = false;
dev_dbg(cs35l41->dev, "Unloaded Firmware\n");
}
@@ -461,11 +624,10 @@ static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
cancel_work_sync(&cs35l41->fw_load_work);
- mutex_lock(&cs35l41->fw_mutex);
+ guard(mutex)(&cs35l41->fw_mutex);
cs35l41_shutdown_dsp(cs35l41);
cs_dsp_remove(dsp);
cs35l41->halo_initialized = false;
- mutex_unlock(&cs35l41->fw_mutex);
}
/* Protection release cycle to get the speaker out of Safe-Mode */
@@ -483,110 +645,303 @@ static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
cs35l41->irq_errors = 0;
}
-static void cs35l41_hda_playback_hook(struct device *dev, int action)
+static void cs35l41_update_mixer(struct cs35l41_hda *cs35l41)
+{
+ struct regmap *reg = cs35l41->regmap;
+ unsigned int asp_en = 0;
+ unsigned int dsp1rx2_src = 0;
+
+ regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
+
+ if (cs35l41->cs_dsp.running) {
+ asp_en |= CS35L41_ASP_TX1_EN_MASK; // ASP_TX1_EN = 1
+ regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
+ ARRAY_SIZE(cs35l41_hda_config_dsp));
+ if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST)
+ regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON);
+ else
+ regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON);
+ } else {
+ regmap_multi_reg_write(reg, cs35l41_hda_config_no_dsp,
+ ARRAY_SIZE(cs35l41_hda_config_no_dsp));
+ }
+
+ if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER) {
+ asp_en |= CS35L41_ASP_RX2_EN_MASK; // ASP_RX2_EN = 1
+ dsp1rx2_src = 0x00000009; // DSP1RX2 SRC = ASPRX2
+ } else {
+ dsp1rx2_src = 0x00000008; // DSP1RX2 SRC = ASPRX1
+ }
+
+ asp_en |= CS35L41_ASP_RX1_EN_MASK; // ASP_RX1_EN = 1
+
+ regmap_write(reg, CS35L41_SP_ENABLES, asp_en);
+ regmap_write(reg, CS35L41_DSP1_RX1_SRC, 0x00000008); // DSP1RX1 SRC = ASPRX1
+ regmap_write(reg, CS35L41_DSP1_RX2_SRC, dsp1rx2_src);
+}
+
+static void cs35l41_hda_play_start(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
struct regmap *reg = cs35l41->regmap;
- int ret = 0;
+
+ dev_dbg(dev, "Play (Start)\n");
+
+ if (cs35l41->playback_started) {
+ dev_dbg(dev, "Playback already started.");
+ return;
+ }
+
+ cs35l41->playback_started = true;
+
+ cs35l41_update_mixer(cs35l41);
+
+ if (cs35l41->cs_dsp.running) {
+ regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+ CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
+ 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
+ cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME);
+ }
+ regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
+ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+ regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
+
+}
+
+static void cs35l41_mute(struct device *dev, bool mute)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+ struct regmap *reg = cs35l41->regmap;
+ unsigned int amp_gain;
+
+ dev_dbg(dev, "Mute(%d:%d) Playback Started: %d\n", mute, cs35l41->mute_override,
+ cs35l41->playback_started);
+
+ if (cs35l41->playback_started) {
+ if (mute || cs35l41->mute_override) {
+ dev_dbg(dev, "Muting\n");
+ regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
+ } else {
+ dev_dbg(dev, "Unmuting\n");
+ if (cs35l41->cs_dsp.running) {
+ dev_dbg(dev, "Using Tuned Gain: %d\n", cs35l41->tuning_gain);
+ amp_gain = (cs35l41->tuning_gain << CS35L41_AMP_GAIN_PCM_SHIFT) |
+ (DEFAULT_AMP_GAIN_PDM << CS35L41_AMP_GAIN_PDM_SHIFT);
+
+ /* AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB */
+ regmap_write(reg, CS35L41_AMP_DIG_VOL_CTRL, 0x00008000);
+ regmap_write(reg, CS35L41_AMP_GAIN_CTRL, amp_gain);
+ } else {
+ regmap_multi_reg_write(reg, cs35l41_hda_unmute,
+ ARRAY_SIZE(cs35l41_hda_unmute));
+ }
+ }
+ }
+}
+
+static void cs35l41_hda_play_done(struct device *dev)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+ struct regmap *reg = cs35l41->regmap;
+
+ dev_dbg(dev, "Play (Complete)\n");
+
+ cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1,
+ &cs35l41->cs_dsp);
+ cs35l41_mute(dev, false);
+}
+
+static void cs35l41_hda_pause_start(struct device *dev)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+ struct regmap *reg = cs35l41->regmap;
+
+ dev_dbg(dev, "Pause (Start)\n");
+
+ cs35l41_mute(dev, true);
+ cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0,
+ &cs35l41->cs_dsp);
+}
+
+static void cs35l41_hda_pause_done(struct device *dev)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+ struct regmap *reg = cs35l41->regmap;
+
+ dev_dbg(dev, "Pause (Complete)\n");
+
+ regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
+ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+ regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
+ if (cs35l41->cs_dsp.running) {
+ cs35l41_set_cspl_mbox_cmd(dev, reg, CSPL_MBOX_CMD_PAUSE);
+ regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+ CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
+ 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
+ }
+ cs35l41_irq_release(cs35l41);
+ cs35l41->playback_started = false;
+}
+
+static void cs35l41_hda_pre_playback_hook(struct device *dev, int action)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+ switch (action) {
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ cs35l41_hda_pause_start(dev);
+ }
+ break;
+ default:
+ break;
+ }
+}
+static void cs35l41_hda_playback_hook(struct device *dev, int action)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
+ /*
+ * All amps must be resumed before we can start playing back.
+ * This ensures, for external boost, that all amps are in AMP_SAFE mode.
+ * Do this in HDA_GEN_PCM_ACT_OPEN, since this is run prior to any of the
+ * other actions.
+ */
pm_runtime_get_sync(dev);
- mutex_lock(&cs35l41->fw_mutex);
- cs35l41->playback_started = true;
- if (cs35l41->firmware_running) {
- regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
- ARRAY_SIZE(cs35l41_hda_config_dsp));
- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
- CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
- 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
- cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
- CSPL_MBOX_CMD_RESUME);
- } else {
- regmap_multi_reg_write(reg, cs35l41_hda_config,
- ARRAY_SIZE(cs35l41_hda_config));
- }
- ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
- CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
- if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
- regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
- mutex_unlock(&cs35l41->fw_mutex);
break;
case HDA_GEN_PCM_ACT_PREPARE:
- mutex_lock(&cs35l41->fw_mutex);
- ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1, NULL);
- mutex_unlock(&cs35l41->fw_mutex);
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ cs35l41_hda_play_start(dev);
+ }
break;
case HDA_GEN_PCM_ACT_CLEANUP:
- mutex_lock(&cs35l41->fw_mutex);
- regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
- ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0, NULL);
- mutex_unlock(&cs35l41->fw_mutex);
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ cs35l41_hda_pause_done(dev);
+ }
break;
case HDA_GEN_PCM_ACT_CLOSE:
- mutex_lock(&cs35l41->fw_mutex);
- ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
- CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
- if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
- regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
- if (cs35l41->firmware_running) {
- cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
- CSPL_MBOX_CMD_PAUSE);
- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
- CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
- 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ if (!cs35l41->cs_dsp.running && cs35l41->request_fw_load &&
+ !cs35l41->fw_request_ongoing) {
+ dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n");
+ cs35l41->fw_request_ongoing = true;
+ schedule_work(&cs35l41->fw_load_work);
+ }
}
- cs35l41_irq_release(cs35l41);
- cs35l41->playback_started = false;
- mutex_unlock(&cs35l41->fw_mutex);
- pm_runtime_mark_last_busy(dev);
+ /*
+ * Playback must be finished for all amps before we start runtime suspend.
+ * This ensures no amps are playing back when we start putting them to sleep.
+ */
pm_runtime_put_autosuspend(dev);
break;
default:
- dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
break;
}
-
- if (ret)
- dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret);
}
-static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+static void cs35l41_hda_post_playback_hook(struct device *dev, int action)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
- static const char * const channel_name[] = { "L", "R" };
+
+ switch (action) {
+ case HDA_GEN_PCM_ACT_PREPARE:
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ cs35l41_hda_play_done(dev);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int cs35l41_hda_channel_map(struct cs35l41_hda *cs35l41)
+{
+ unsigned int tx_num = 0;
+ unsigned int *tx_slot = NULL;
+ unsigned int rx_num;
+ unsigned int *rx_slot;
+ unsigned int mono = 0;
if (!cs35l41->amp_name) {
- if (*rx_slot >= ARRAY_SIZE(channel_name))
+ if (cs35l41->hw_cfg.spk_pos >= ARRAY_SIZE(channel_name))
return -EINVAL;
- cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%s%d",
- channel_name[*rx_slot], cs35l41->channel_index);
+ cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%c%d",
+ channel_name[cs35l41->hw_cfg.spk_pos],
+ cs35l41->channel_index);
if (!cs35l41->amp_name)
return -ENOMEM;
}
+ rx_num = 1;
+ if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER)
+ rx_slot = &mono;
+ else
+ rx_slot = &cs35l41->hw_cfg.spk_pos;
+
return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num,
rx_slot);
}
-static void cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
+static int cs35l41_verify_id(struct cs35l41_hda *cs35l41, unsigned int *regid, unsigned int *reg_revid)
{
- mutex_lock(&cs35l41->fw_mutex);
- if (cs35l41->firmware_running) {
+ unsigned int mtl_revid, chipid;
+ int ret;
- regcache_cache_only(cs35l41->regmap, false);
+ ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, regid);
+ if (ret) {
+ dev_err_probe(cs35l41->dev, ret, "Get Device ID failed\n");
+ return ret;
+ }
- cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
- cs35l41_shutdown_dsp(cs35l41);
- cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
+ ret = regmap_read(cs35l41->regmap, CS35L41_REVID, reg_revid);
+ if (ret) {
+ dev_err_probe(cs35l41->dev, ret, "Get Revision ID failed\n");
+ return ret;
+ }
+
+ mtl_revid = *reg_revid & CS35L41_MTLREVID_MASK;
- regcache_cache_only(cs35l41->regmap, true);
- regcache_mark_dirty(cs35l41->regmap);
+ chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
+ if (*regid != chipid) {
+ dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", *regid, chipid);
+ return -ENODEV;
}
- mutex_unlock(&cs35l41->fw_mutex);
+
+ return 0;
+}
+
+static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
+{
+ guard(mutex)(&cs35l41->fw_mutex);
+ if (cs35l41->cs_dsp.running) {
+ cs35l41->cs_dsp.running = false;
+ cs35l41->cs_dsp.booted = false;
+ }
+ regcache_mark_dirty(cs35l41->regmap);
+
+ return 0;
+}
+
+static int cs35l41_system_suspend_prep(struct device *dev)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+ dev_dbg(cs35l41->dev, "System Suspend Prepare\n");
+
+ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+ dev_err_once(cs35l41->dev, "System Suspend not supported\n");
+ return 0; /* don't block the whole system suspend */
+ }
+
+ guard(mutex)(&cs35l41->fw_mutex);
+ if (cs35l41->playback_started)
+ cs35l41_hda_pause_start(dev);
+
+ return 0;
}
static int cs35l41_system_suspend(struct device *dev)
@@ -601,17 +956,54 @@ static int cs35l41_system_suspend(struct device *dev)
return 0; /* don't block the whole system suspend */
}
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ if (cs35l41->playback_started)
+ cs35l41_hda_pause_done(dev);
+ }
+
ret = pm_runtime_force_suspend(dev);
- if (ret)
+ if (ret) {
+ dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret);
return ret;
+ }
/* Shutdown DSP before system suspend */
- cs35l41_ready_for_reset(cs35l41);
+ ret = cs35l41_ready_for_reset(cs35l41);
+ if (ret)
+ dev_err(dev, "System Suspend Failed, not ready for Reset: %d\n", ret);
+
+ if (cs35l41->reset_gpio) {
+ dev_info(cs35l41->dev, "Asserting Reset\n");
+ gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
+ usleep_range(2000, 2100);
+ }
+
+ dev_dbg(cs35l41->dev, "System Suspended\n");
+
+ return ret;
+}
+
+static int cs35l41_wait_boot_done(struct cs35l41_hda *cs35l41)
+{
+ unsigned int int_status;
+ int ret;
+
+ ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
+ int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
+ if (ret) {
+ dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE\n");
+ return ret;
+ }
+
+ ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status);
+ if (ret || (int_status & CS35L41_OTP_BOOT_ERR)) {
+ dev_err(cs35l41->dev, "OTP Boot status %x error\n",
+ int_status & CS35L41_OTP_BOOT_ERR);
+ if (!ret)
+ ret = -EIO;
+ return ret;
+ }
- /*
- * Reset GPIO may be shared, so cannot reset here.
- * However beyond this point, amps may be powered down.
- */
return 0;
}
@@ -628,20 +1020,36 @@ static int cs35l41_system_resume(struct device *dev)
}
if (cs35l41->reset_gpio) {
+ gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
usleep_range(2000, 2100);
gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
}
usleep_range(2000, 2100);
+ regcache_cache_only(cs35l41->regmap, false);
+
+ regmap_write(cs35l41->regmap, CS35L41_SFT_RESET, CS35L41_SOFTWARE_RESET);
+ usleep_range(2000, 2100);
+
+ ret = cs35l41_wait_boot_done(cs35l41);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(cs35l41->regmap, true);
+
ret = pm_runtime_force_resume(dev);
+ if (ret) {
+ dev_err(dev, "System Resume Failed: Unable to runtime resume: %d\n", ret);
+ return ret;
+ }
- mutex_lock(&cs35l41->fw_mutex);
- if (!ret && cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
+ guard(mutex)(&cs35l41->fw_mutex);
+
+ if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
cs35l41->fw_request_ongoing = true;
schedule_work(&cs35l41->fw_load_work);
}
- mutex_unlock(&cs35l41->fw_mutex);
return ret;
}
@@ -658,7 +1066,7 @@ static int cs35l41_runtime_idle(struct device *dev)
static int cs35l41_runtime_suspend(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
- int ret = 0;
+ int ret;
dev_dbg(cs35l41->dev, "Runtime Suspend\n");
@@ -667,27 +1075,13 @@ static int cs35l41_runtime_suspend(struct device *dev)
return 0;
}
- mutex_lock(&cs35l41->fw_mutex);
+ guard(mutex)(&cs35l41->fw_mutex);
- if (cs35l41->playback_started) {
- regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute,
- ARRAY_SIZE(cs35l41_hda_mute));
- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, NULL);
- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
- CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
- if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
- regmap_write(cs35l41->regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
- CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
- 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
- cs35l41->playback_started = false;
- }
-
- if (cs35l41->firmware_running) {
+ if (cs35l41->cs_dsp.running) {
ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap,
cs35l41->hw_cfg.bst_type);
if (ret)
- goto err;
+ return ret;
} else {
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
}
@@ -695,16 +1089,14 @@ static int cs35l41_runtime_suspend(struct device *dev)
regcache_cache_only(cs35l41->regmap, true);
regcache_mark_dirty(cs35l41->regmap);
-err:
- mutex_unlock(&cs35l41->fw_mutex);
-
- return ret;
+ return 0;
}
static int cs35l41_runtime_resume(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
- int ret = 0;
+ unsigned int regid, reg_revid;
+ int ret;
dev_dbg(cs35l41->dev, "Runtime Resume\n");
@@ -713,41 +1105,57 @@ static int cs35l41_runtime_resume(struct device *dev)
return 0;
}
- mutex_lock(&cs35l41->fw_mutex);
+ guard(mutex)(&cs35l41->fw_mutex);
regcache_cache_only(cs35l41->regmap, false);
- if (cs35l41->firmware_running) {
+ if (cs35l41->cs_dsp.running) {
ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
if (ret) {
dev_warn(cs35l41->dev, "Unable to exit Hibernate.");
- goto err;
+ return ret;
}
}
+ ret = cs35l41_verify_id(cs35l41, &regid, &reg_revid);
+ if (ret)
+ return ret;
+
/* Test key needs to be unlocked to allow the OTP settings to re-apply */
cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
ret = regcache_sync(cs35l41->regmap);
cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
if (ret) {
dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
- goto err;
+ return ret;
}
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
-err:
- mutex_unlock(&cs35l41->fw_mutex);
+ dev_dbg(cs35l41->dev, "CS35L41 Resumed (%x), Revision: %02X\n", regid, reg_revid);
- return ret;
+ return 0;
+}
+
+static int cs35l41_hda_read_ctl(struct cs_dsp *dsp, const char *name, int type,
+ unsigned int alg, void *buf, size_t len)
+{
+ guard(mutex)(&dsp->pwr_lock);
+ return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len);
}
static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
{
- int halo_sts;
+ unsigned int fw_status;
+ __be32 halo_sts;
int ret;
+ if (cs35l41->bypass_fw) {
+ dev_warn(cs35l41->dev, "Bypassing Firmware.\n");
+ return 0;
+ }
+
ret = cs35l41_init_dsp(cs35l41);
if (ret) {
dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret);
@@ -766,20 +1174,44 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
goto clean_dsp;
}
- ret = read_poll_timeout(hda_cs_dsp_read_ctl, ret,
+ ret = read_poll_timeout(cs35l41_hda_read_ctl, ret,
be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN,
1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME,
HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG,
&halo_sts, sizeof(halo_sts));
if (ret) {
- dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %d\n",
+ dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %u\n",
halo_sts);
goto clean_dsp;
}
- cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE);
- cs35l41->firmware_running = true;
+ ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &fw_status);
+ if (ret < 0) {
+ dev_err(cs35l41->dev,
+ "Failed to read firmware status: %d\n", ret);
+ goto clean_dsp;
+ }
+
+ switch (fw_status) {
+ case CSPL_MBOX_STS_RUNNING:
+ case CSPL_MBOX_STS_PAUSED:
+ break;
+ default:
+ dev_err(cs35l41->dev, "Firmware status is invalid: %u\n",
+ fw_status);
+ ret = -EINVAL;
+ goto clean_dsp;
+ }
+
+ ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE);
+ if (ret) {
+ dev_err(cs35l41->dev, "Error waiting for DSP to pause: %u\n", ret);
+ goto clean_dsp;
+ }
+
+ dev_info(cs35l41->dev, "Firmware Loaded - Type: %s, Gain: %d\n",
+ cs35l41_hda_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain);
return 0;
@@ -790,10 +1222,10 @@ clean_dsp:
static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
{
- if (cs35l41->firmware_running && !load) {
+ if (cs35l41->cs_dsp.running && !load) {
dev_dbg(cs35l41->dev, "Unloading Firmware\n");
cs35l41_shutdown_dsp(cs35l41);
- } else if (!cs35l41->firmware_running && load) {
+ } else if (!cs35l41->cs_dsp.running && load) {
dev_dbg(cs35l41->dev, "Loading Firmware\n");
cs35l41_smart_amp(cs35l41);
} else {
@@ -810,24 +1242,31 @@ static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static int cs35l41_mute_override_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = cs35l41->mute_override;
+ return 0;
+}
+
static void cs35l41_fw_load_work(struct work_struct *work)
{
struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work);
pm_runtime_get_sync(cs35l41->dev);
- mutex_lock(&cs35l41->fw_mutex);
-
- /* Recheck if playback is ongoing, mutex will block playback during firmware loading */
- if (cs35l41->playback_started)
- dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n");
- else
- cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
+ scoped_guard(mutex, &cs35l41->fw_mutex) {
+ /* Recheck if playback is ongoing, mutex will block playback during firmware loading */
+ if (cs35l41->playback_started)
+ dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n");
+ else
+ cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
- cs35l41->fw_request_ongoing = false;
- mutex_unlock(&cs35l41->fw_mutex);
+ cs35l41->fw_request_ongoing = false;
+ }
- pm_runtime_mark_last_busy(cs35l41->dev);
pm_runtime_put_autosuspend(cs35l41->dev);
}
@@ -835,34 +1274,26 @@ static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
- unsigned int ret = 0;
-
- mutex_lock(&cs35l41->fw_mutex);
if (cs35l41->request_fw_load == ucontrol->value.integer.value[0])
- goto err;
+ return 0;
if (cs35l41->fw_request_ongoing) {
dev_dbg(cs35l41->dev, "Existing request not complete\n");
- ret = -EBUSY;
- goto err;
+ return -EBUSY;
}
/* Check if playback is ongoing when initial request is made */
if (cs35l41->playback_started) {
dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
- ret = -EBUSY;
- goto err;
+ return -EBUSY;
}
cs35l41->fw_request_ongoing = true;
cs35l41->request_fw_load = ucontrol->value.integer.value[0];
schedule_work(&cs35l41->fw_load_work);
-err:
- mutex_unlock(&cs35l41->fw_mutex);
-
- return ret;
+ return 1;
}
static int cs35l41_fw_type_ctl_get(struct snd_kcontrol *kcontrol,
@@ -880,9 +1311,13 @@ static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol,
{
struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
- if (ucontrol->value.enumerated.item[0] < HDA_CS_DSP_NUM_FW) {
- cs35l41->firmware_type = ucontrol->value.enumerated.item[0];
- return 0;
+ if (ucontrol->value.enumerated.item[0] < CS35L41_HDA_NUM_FW) {
+ if (cs35l41->firmware_type != ucontrol->value.enumerated.item[0]) {
+ cs35l41->firmware_type = ucontrol->value.enumerated.item[0];
+ return 1;
+ } else {
+ return 0;
+ }
}
return -EINVAL;
@@ -890,13 +1325,14 @@ static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol,
static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(hda_cs_dsp_fw_ids), hda_cs_dsp_fw_ids);
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(cs35l41_hda_fw_ids), cs35l41_hda_fw_ids);
}
static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
{
char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char fw_load_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ char mute_override_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
struct snd_kcontrol_new fw_type_ctl = {
.name = fw_type_ctl_name,
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
@@ -911,12 +1347,21 @@ static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
.get = cs35l41_fw_load_ctl_get,
.put = cs35l41_fw_load_ctl_put,
};
+ struct snd_kcontrol_new mute_override_ctl = {
+ .name = mute_override_ctl_name,
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = snd_ctl_boolean_mono_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .get = cs35l41_mute_override_ctl_get,
+ };
int ret;
scnprintf(fw_type_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Type",
cs35l41->amp_name);
scnprintf(fw_load_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Load",
cs35l41->amp_name);
+ scnprintf(mute_override_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s Forced Mute Status",
+ cs35l41->amp_name);
ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41));
if (ret) {
@@ -934,34 +1379,95 @@ static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name);
+ ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&mute_override_ctl, cs35l41));
+ if (ret) {
+ dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", mute_override_ctl.name,
+ ret);
+ return ret;
+ }
+
+ dev_dbg(cs35l41->dev, "Added Control %s\n", mute_override_ctl.name);
+
return 0;
}
+static bool cs35l41_dsm_supported(acpi_handle handle, unsigned int commands)
+{
+ guid_t guid;
+
+ guid_parse(CS35L41_UUID, &guid);
+
+ return acpi_check_dsm(handle, &guid, 0, BIT(commands));
+}
+
+static int cs35l41_get_acpi_mute_state(struct cs35l41_hda *cs35l41, acpi_handle handle)
+{
+ guid_t guid;
+ union acpi_object *ret;
+ int mute = -ENODEV;
+
+ guid_parse(CS35L41_UUID, &guid);
+
+ if (cs35l41_dsm_supported(handle, CS35L41_DSM_GET_MUTE)) {
+ ret = acpi_evaluate_dsm(handle, &guid, 0, CS35L41_DSM_GET_MUTE, NULL);
+ if (!ret)
+ return -EINVAL;
+ mute = *ret->buffer.pointer;
+ dev_dbg(cs35l41->dev, "CS35L41_DSM_GET_MUTE: %d\n", mute);
+ }
+
+ dev_dbg(cs35l41->dev, "%s: %d\n", __func__, mute);
+
+ return mute;
+}
+
+static void cs35l41_acpi_device_notify(acpi_handle handle, u32 event, struct device *dev)
+{
+ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+ int mute;
+
+ if (event != CS35L41_NOTIFY_EVENT)
+ return;
+
+ mute = cs35l41_get_acpi_mute_state(cs35l41, handle);
+ if (mute < 0) {
+ dev_warn(cs35l41->dev, "Unable to retrieve mute state: %d\n", mute);
+ return;
+ }
+
+ dev_dbg(cs35l41->dev, "Requesting mute value: %d\n", mute);
+ cs35l41->mute_override = (mute > 0);
+ cs35l41_mute(cs35l41->dev, cs35l41->mute_override);
+}
+
static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
- struct hda_component *comps = master_data;
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+ unsigned int sleep_flags;
int ret = 0;
- if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS)
+ comp = hda_component_from_index(parent, cs35l41->index);
+ if (!comp)
return -EINVAL;
- comps = &comps[cs35l41->index];
- if (comps->dev)
+ if (comp->dev)
return -EBUSY;
pm_runtime_get_sync(dev);
mutex_lock(&cs35l41->fw_mutex);
- comps->dev = dev;
+ comp->dev = dev;
+ cs35l41->codec = parent->codec;
if (!cs35l41->acpi_subsystem_id)
cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x",
- comps->codec->core.subsystem_id);
- cs35l41->codec = comps->codec;
- strscpy(comps->name, dev_name(dev), sizeof(comps->name));
+ cs35l41->codec->core.subsystem_id);
+
+ strscpy(comp->name, dev_name(dev), sizeof(comp->name));
- cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT;
+ cs35l41->firmware_type = CS35L41_HDA_FW_SPK_PROT;
if (firmware_autostart) {
dev_dbg(cs35l41->dev, "Firmware Autostart.\n");
@@ -974,23 +1480,54 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
ret = cs35l41_create_controls(cs35l41);
- comps->playback_hook = cs35l41_hda_playback_hook;
+ comp->playback_hook = cs35l41_hda_playback_hook;
+ comp->pre_playback_hook = cs35l41_hda_pre_playback_hook;
+ comp->post_playback_hook = cs35l41_hda_post_playback_hook;
+ comp->acpi_notify = cs35l41_acpi_device_notify;
+ comp->adev = cs35l41->dacpi;
+
+ comp->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comp->adev),
+ CS35L41_DSM_GET_MUTE);
+
+ cs35l41->mute_override = cs35l41_get_acpi_mute_state(cs35l41,
+ acpi_device_handle(cs35l41->dacpi)) > 0;
mutex_unlock(&cs35l41->fw_mutex);
- pm_runtime_mark_last_busy(dev);
+ sleep_flags = lock_system_sleep();
+ if (!device_link_add(&cs35l41->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS))
+ dev_warn(dev, "Unable to create device link\n");
+ unlock_system_sleep(sleep_flags);
+
pm_runtime_put_autosuspend(dev);
+ dev_info(cs35l41->dev,
+ "CS35L41 Bound - SSID: %s, BST: %d, VSPK: %d, CH: %c, FW EN: %d, SPKID: %d\n",
+ cs35l41->acpi_subsystem_id, cs35l41->hw_cfg.bst_type,
+ cs35l41->hw_cfg.gpio1.func == CS35l41_VSPK_SWITCH,
+ channel_name[cs35l41->hw_cfg.spk_pos],
+ cs35l41->cs_dsp.running, cs35l41->speaker_id);
+
return ret;
}
static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
- struct hda_component *comps = master_data;
-
- if (comps[cs35l41->index].dev == dev)
- memset(&comps[cs35l41->index], 0, sizeof(*comps));
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+ unsigned int sleep_flags;
+
+ comp = hda_component_from_index(parent, cs35l41->index);
+ if (!comp)
+ return;
+
+ if (comp->dev == dev) {
+ sleep_flags = lock_system_sleep();
+ device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev);
+ unlock_system_sleep(sleep_flags);
+ memset(comp, 0, sizeof(*comp));
+ }
}
static const struct component_ops cs35l41_hda_comp_ops = {
@@ -1076,7 +1613,7 @@ static const struct regmap_irq cs35l41_reg_irqs[] = {
CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
};
-static struct regmap_irq_chip cs35l41_regmap_irq_chip = {
+static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
.name = "cs35l41 IRQ1 Controller",
.status_base = CS35L41_IRQ1_STATUS1,
.mask_base = CS35L41_IRQ1_MASK1,
@@ -1087,13 +1624,56 @@ static struct regmap_irq_chip cs35l41_regmap_irq_chip = {
.runtime_pm = true,
};
+static void cs35l41_configure_interrupt(struct cs35l41_hda *cs35l41, int irq_pol)
+{
+ int irq;
+ int ret;
+ int i;
+
+ if (!cs35l41->irq) {
+ dev_warn(cs35l41->dev, "No Interrupt Found");
+ goto err;
+ }
+
+ ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
+ IRQF_ONESHOT | IRQF_SHARED | irq_pol,
+ 0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
+ if (ret) {
+ dev_dbg(cs35l41->dev, "Unable to add IRQ Chip: %d.", ret);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
+ irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
+ if (irq < 0) {
+ ret = irq;
+ dev_dbg(cs35l41->dev, "Unable to map IRQ %s: %d.", cs35l41_irqs[i].name,
+ ret);
+ goto err;
+ }
+
+ ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
+ cs35l41_irqs[i].handler,
+ IRQF_ONESHOT | IRQF_SHARED | irq_pol,
+ cs35l41_irqs[i].name, cs35l41);
+ if (ret) {
+ dev_dbg(cs35l41->dev, "Unable to allocate IRQ %s:: %d.",
+ cs35l41_irqs[i].name, ret);
+ goto err;
+ }
+ }
+ return;
+err:
+ dev_warn(cs35l41->dev,
+ "IRQ Config Failed. Amp errors may not be recoverable without reboot.");
+}
+
static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
{
struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
bool using_irq = false;
- int irq, irq_pol;
+ int irq_pol;
int ret;
- int i;
if (!cs35l41->hw_cfg.valid)
return -EINVAL;
@@ -1136,32 +1716,13 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
- if (cs35l41->irq && using_irq) {
- ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
- IRQF_ONESHOT | IRQF_SHARED | irq_pol,
- 0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
- if (ret)
- return ret;
-
- for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
- irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
- if (irq < 0)
- return irq;
-
- ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
- cs35l41_irqs[i].handler,
- IRQF_ONESHOT | IRQF_SHARED | irq_pol,
- cs35l41_irqs[i].name, cs35l41);
- if (ret)
- return ret;
- }
- }
+ if (using_irq)
+ cs35l41_configure_interrupt(cs35l41, irq_pol);
- return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
+ return cs35l41_hda_channel_map(cs35l41);
}
-static int cs35l41_get_speaker_id(struct device *dev, int amp_index,
- int num_amps, int fixed_gpio_id)
+int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id)
{
struct gpio_desc *speaker_id_desc;
int speaker_id = -ENODEV;
@@ -1215,80 +1776,19 @@ static int cs35l41_get_speaker_id(struct device *dev, int amp_index,
return speaker_id;
}
-/*
- * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
- * And devices created by serial-multi-instantiate don't have their device struct
- * pointing to the correct fwnode, so acpi_dev must be used here.
- * And devm functions expect that the device requesting the resource has the correct
- * fwnode.
- */
-static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
- const char *hid)
-{
- struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-
- /* check I2C address to assign the index */
- cs35l41->index = id == 0x40 ? 0 : 1;
- cs35l41->channel_index = 0;
- cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
- cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
- hw_cfg->spk_pos = cs35l41->index;
- hw_cfg->gpio2.func = CS35L41_INTERRUPT;
- hw_cfg->gpio2.valid = true;
- hw_cfg->valid = true;
-
- if (strncmp(hid, "CLSA0100", 8) == 0) {
- hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
- } else if (strncmp(hid, "CLSA0101", 8) == 0) {
- hw_cfg->bst_type = CS35L41_EXT_BOOST;
- hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
- hw_cfg->gpio1.valid = true;
- } else {
- /*
- * Note: CLSA010(0/1) are special cases which use a slightly different design.
- * All other HIDs e.g. CSC3551 require valid ACPI _DSD properties to be supported.
- */
- dev_err(cs35l41->dev, "Error: ACPI _DSD Properties are missing for HID %s.\n", hid);
- hw_cfg->valid = false;
- hw_cfg->gpio1.valid = false;
- hw_cfg->gpio2.valid = false;
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
+int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id)
{
struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
u32 values[HDA_MAX_COMPONENTS];
- struct acpi_device *adev;
- struct device *physdev;
- const char *sub;
char *property;
size_t nval;
int i, ret;
- adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
- if (!adev) {
- dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
- return -ENODEV;
- }
-
- physdev = get_device(acpi_get_first_physical_node(adev));
- acpi_dev_put(adev);
-
- sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
- if (IS_ERR(sub))
- sub = NULL;
- cs35l41->acpi_subsystem_id = sub;
-
property = "cirrus,dev-index";
ret = device_property_count_u32(physdev, property);
- if (ret <= 0) {
- ret = cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid);
- goto err_put_physdev;
- }
+ if (ret <= 0)
+ goto err;
+
if (ret > ARRAY_SIZE(values)) {
ret = -EINVAL;
goto err;
@@ -1315,8 +1815,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
/* To use the same release code for all laptop variants we can't use devm_ version of
* gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
*/
- cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index,
- GPIOD_OUT_LOW, "cs35l41-reset");
+ cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
+ cs35l41->index, GPIOD_OUT_LOW,
+ "cs35l41-reset");
property = "cirrus,speaker-position";
ret = device_property_read_u32_array(physdev, property, values, nval);
@@ -1372,22 +1873,72 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
hw_cfg->bst_type = CS35L41_EXT_BOOST;
hw_cfg->valid = true;
- put_device(physdev);
return 0;
-
err:
dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
-err_put_physdev:
- put_device(physdev);
+ hw_cfg->valid = false;
+ hw_cfg->gpio1.valid = false;
+ hw_cfg->gpio2.valid = false;
+ acpi_dev_put(cs35l41->dacpi);
return ret;
}
+static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
+{
+ struct acpi_device *adev;
+ struct device *physdev;
+ struct spi_device *spi;
+ const char *sub;
+ int ret;
+
+ adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+ if (!adev) {
+ dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
+ return -ENODEV;
+ }
+
+ cs35l41->dacpi = adev;
+ physdev = get_device(acpi_get_first_physical_node(adev));
+
+ sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+ if (IS_ERR(sub))
+ sub = NULL;
+ cs35l41->acpi_subsystem_id = sub;
+
+ ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
+ if (!ret) {
+ dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
+ goto out;
+ }
+
+ ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id);
+ if (ret) {
+ put_device(physdev);
+ return ret;
+ }
+out:
+ put_device(physdev);
+
+ cs35l41->bypass_fw = false;
+ if (cs35l41->control_bus == SPI) {
+ spi = to_spi_device(cs35l41->dev);
+ if (spi->max_speed_hz < CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ) {
+ dev_warn(cs35l41->dev,
+ "SPI speed is too slow to support firmware download: %d Hz.\n",
+ spi->max_speed_hz);
+ cs35l41->bypass_fw = true;
+ }
+ }
+
+ return 0;
+}
+
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
- struct regmap *regmap)
+ struct regmap *regmap, enum control_bus control_bus)
{
- unsigned int int_sts, regid, reg_revid, mtl_revid, chipid, int_status;
+ unsigned int regid, reg_revid;
struct cs35l41_hda *cs35l41;
int ret;
@@ -1404,6 +1955,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
cs35l41->dev = dev;
cs35l41->irq = irq;
cs35l41->regmap = regmap;
+ cs35l41->control_bus = control_bus;
dev_set_drvdata(dev, cs35l41);
ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
@@ -1421,47 +1973,22 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
}
}
if (cs35l41->reset_gpio) {
+ gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
usleep_range(2000, 2100);
gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
}
usleep_range(2000, 2100);
+ regmap_write(cs35l41->regmap, CS35L41_SFT_RESET, CS35L41_SOFTWARE_RESET);
+ usleep_range(2000, 2100);
- ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
- int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
- if (ret) {
- dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE: %d\n", ret);
- goto err;
- }
-
- ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_sts);
- if (ret || (int_sts & CS35L41_OTP_BOOT_ERR)) {
- dev_err(cs35l41->dev, "OTP Boot status %x error: %d\n",
- int_sts & CS35L41_OTP_BOOT_ERR, ret);
- ret = -EIO;
- goto err;
- }
-
- ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid);
- if (ret) {
- dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret);
- goto err;
- }
-
- ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid);
- if (ret) {
- dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret);
+ ret = cs35l41_wait_boot_done(cs35l41);
+ if (ret)
goto err;
- }
-
- mtl_revid = reg_revid & CS35L41_MTLREVID_MASK;
- chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
- if (regid != chipid) {
- dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", regid, chipid);
- ret = -ENODEV;
+ ret = cs35l41_verify_id(cs35l41, &regid, &reg_revid);
+ if (ret)
goto err;
- }
ret = cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
if (ret)
@@ -1473,7 +2000,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
if (ret) {
- dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "OTP Unpack failed\n");
goto err;
}
@@ -1481,12 +2008,17 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
if (ret)
goto err;
+ ret = cs35l41_get_calibration(cs35l41);
+ if (ret && ret != -ENOENT)
+ goto err;
+
+ cs35l41_mute(cs35l41->dev, true);
+
INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work);
mutex_init(&cs35l41->fw_mutex);
pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
pm_runtime_use_autosuspend(cs35l41->dev);
- pm_runtime_mark_last_busy(cs35l41->dev);
pm_runtime_set_active(cs35l41->dev);
pm_runtime_get_noresume(cs35l41->dev);
pm_runtime_enable(cs35l41->dev);
@@ -1499,9 +2031,8 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
if (ret) {
- dev_err(cs35l41->dev, "Register component failed: %d\n", ret);
- pm_runtime_disable(cs35l41->dev);
- goto err;
+ dev_err_probe(cs35l41->dev, ret, "Register component failed\n");
+ goto err_pm;
}
dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid);
@@ -1509,6 +2040,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
return 0;
err_pm:
+ pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev);
pm_runtime_put_noidle(cs35l41->dev);
@@ -1516,42 +2048,51 @@ err:
if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
+ gpiod_put(cs35l41->cs_gpio);
+ acpi_dev_put(cs35l41->dacpi);
kfree(cs35l41->acpi_subsystem_id);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, SND_HDA_SCODEC_CS35L41);
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, "SND_HDA_SCODEC_CS35L41");
void cs35l41_hda_remove(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+ component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
+
pm_runtime_get_sync(cs35l41->dev);
+ pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev);
if (cs35l41->halo_initialized)
cs35l41_remove_dsp(cs35l41);
- component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
+ acpi_dev_put(cs35l41->dacpi);
pm_runtime_put_noidle(cs35l41->dev);
if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
+ gpiod_put(cs35l41->cs_gpio);
kfree(cs35l41->acpi_subsystem_id);
}
-EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, "SND_HDA_SCODEC_CS35L41");
const struct dev_pm_ops cs35l41_hda_pm_ops = {
RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
cs35l41_runtime_idle)
+ .prepare = cs35l41_system_suspend_prep,
SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
};
-EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, "SND_HDA_SCODEC_CS35L41");
MODULE_DESCRIPTION("CS35L41 HDA Driver");
-MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(FW_CS_DSP);
+MODULE_IMPORT_NS("FW_CS_DSP");
+MODULE_FIRMWARE("cirrus/cs35l41-*.wmfw");
+MODULE_FIRMWARE("cirrus/cs35l41-*.bin");
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/hda/codecs/side-codecs/cs35l41_hda.h
index bdb35f3be68a..7d003c598e93 100644
--- a/sound/pci/hda/cs35l41_hda.h
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.h
@@ -10,15 +10,21 @@
#ifndef __CS35L41_HDA_H__
#define __CS35L41_HDA_H__
+#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/device.h>
#include <sound/cs35l41.h>
+#include <sound/cs-amp-lib.h>
#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/firmware/cirrus/wmfw.h>
+#define CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ 1000000
+#define DEFAULT_AMP_GAIN_PCM 17 /* 17.5dB Gain */
+#define DEFAULT_AMP_GAIN_PDM 19 /* 19.5dB Gain */
+
struct cs35l41_amp_cal_data {
u32 calTarget[2];
u32 calTime[2];
@@ -34,8 +40,9 @@ struct cs35l41_amp_efi_data {
} __packed;
enum cs35l41_hda_spk_pos {
- CS35l41_LEFT,
- CS35l41_RIGHT,
+ CS35L41_LEFT,
+ CS35L41_RIGHT,
+ CS35L41_CENTER,
};
enum cs35l41_hda_gpio_function {
@@ -45,10 +52,16 @@ enum cs35l41_hda_gpio_function {
CS35l41_SYNC,
};
+enum control_bus {
+ I2C,
+ SPI
+};
+
struct cs35l41_hda {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
+ struct gpio_desc *cs_gpio;
struct cs35l41_hw_cfg hw_cfg;
struct hda_codec *codec;
@@ -70,6 +83,14 @@ struct cs35l41_hda {
bool halo_initialized;
bool playback_started;
struct cs_dsp cs_dsp;
+ struct acpi_device *dacpi;
+ bool mute_override;
+ enum control_bus control_bus;
+ bool bypass_fw;
+ unsigned int tuning_gain;
+ struct cirrus_amp_cal_data cal_data;
+ bool cal_data_valid;
+
};
enum halo_state {
@@ -81,7 +102,9 @@ enum halo_state {
extern const struct dev_pm_ops cs35l41_hda_pm_ops;
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
- struct regmap *regmap);
+ struct regmap *regmap, enum control_bus control_bus);
void cs35l41_hda_remove(struct device *dev);
+int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id);
+int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id);
#endif /*__CS35L41_HDA_H__*/
diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c
index 7826b1a12d7d..e77495413c21 100644
--- a/sound/pci/hda/cs35l41_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c
@@ -30,7 +30,7 @@ static int cs35l41_hda_i2c_probe(struct i2c_client *clt)
return -ENODEV;
return cs35l41_hda_probe(&clt->dev, device_name, clt->addr, clt->irq,
- devm_regmap_init_i2c(clt, &cs35l41_regmap_i2c));
+ devm_regmap_init_i2c(clt, &cs35l41_regmap_i2c), I2C);
}
static void cs35l41_hda_i2c_remove(struct i2c_client *clt)
@@ -39,7 +39,7 @@ static void cs35l41_hda_i2c_remove(struct i2c_client *clt)
}
static const struct i2c_device_id cs35l41_hda_i2c_id[] = {
- { "cs35l41-hda", 0 },
+ { "cs35l41-hda" },
{}
};
@@ -58,12 +58,12 @@ static struct i2c_driver cs35l41_i2c_driver = {
.pm = &cs35l41_hda_pm_ops,
},
.id_table = cs35l41_hda_i2c_id,
- .probe_new = cs35l41_hda_i2c_probe,
+ .probe = cs35l41_hda_i2c_probe,
.remove = cs35l41_hda_i2c_remove,
};
module_i2c_driver(cs35l41_i2c_driver);
MODULE_DESCRIPTION("HDA CS35L41 driver");
-MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L41);
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41");
MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
new file mode 100644
index 000000000000..16d5ea77192f
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
@@ -0,0 +1,582 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS35L41 ALSA HDA Property driver
+//
+// Copyright 2023 Cirrus Logic, Inc.
+//
+// Author: Stefan Binding <sbinding@opensource.cirrus.com>
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/string.h>
+#include "cs35l41_hda_property.h"
+#include <linux/spi/spi.h>
+
+#define MAX_AMPS 4
+
+struct cs35l41_config {
+ const char *ssid;
+ int num_amps;
+ enum {
+ INTERNAL,
+ EXTERNAL
+ } boost_type;
+ u8 channel[MAX_AMPS];
+ int reset_gpio_index; /* -1 if no reset gpio */
+ int spkid_gpio_index; /* -1 if no spkid gpio */
+ int cs_gpio_index; /* -1 if no cs gpio, or cs-gpios already exists, max num amps == 2 */
+ int boost_ind_nanohenry; /* Required if boost_type == Internal */
+ int boost_peak_milliamp; /* Required if boost_type == Internal */
+ int boost_cap_microfarad; /* Required if boost_type == Internal */
+};
+
+static const struct cs35l41_config cs35l41_config_table[] = {
+ { "10251826", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "1025182C", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "10251844", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
+ { "10280C4D", 4, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT }, 0, 1, -1, 1000, 4500, 24 },
+/*
+ * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type.
+ * We can override the _DSD to correct the boost type here.
+ * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists
+ * in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD.
+ */
+ { "103C89C6", 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 },
+ { "103C8A28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A29", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A2A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A2B", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A2C", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A2D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
+ { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+ { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+ { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+ { "103C8C4D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C4E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },
+ { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431473", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+ { "10431483", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+ { "10431493", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "104314D3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "104314E3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431503", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431533", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431573", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431663", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+ { "10431683", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "104316A3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "104316D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "104316F3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431B93", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431CDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431CEF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "10431E12", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+ { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
+ { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "10433A20", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10433A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10433A40", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10433A50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "10433A60", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+ { "17AA3865", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+ { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+ { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+ { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "17AA38B7", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+ { "17AA38C7", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
+ { "17AA38C8", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
+ { "17AA38F9", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+ { "17AA38FA", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+ { "17AA3929", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
+ { "17AA392B", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
+ {}
+};
+
+static int cs35l41_add_gpios(struct cs35l41_hda *cs35l41, struct device *physdev, int reset_gpio,
+ int spkid_gpio, int cs_gpio_index, int num_amps)
+{
+ struct acpi_gpio_mapping *gpio_mapping = NULL;
+ struct acpi_gpio_params *reset_gpio_params = NULL;
+ struct acpi_gpio_params *spkid_gpio_params = NULL;
+ struct acpi_gpio_params *cs_gpio_params = NULL;
+ unsigned int num_entries = 0;
+ unsigned int reset_index, spkid_index, csgpio_index;
+ int i;
+
+ /*
+ * GPIO Mapping only needs to be done once, since it would be available for subsequent amps
+ */
+ if (cs35l41->dacpi->driver_gpios)
+ return 0;
+
+ if (reset_gpio >= 0) {
+ reset_index = num_entries;
+ num_entries++;
+ }
+
+ if (spkid_gpio >= 0) {
+ spkid_index = num_entries;
+ num_entries++;
+ }
+
+ if ((cs_gpio_index >= 0) && (num_amps == 2)) {
+ csgpio_index = num_entries;
+ num_entries++;
+ }
+
+ if (!num_entries)
+ return 0;
+
+ /* must include termination entry */
+ num_entries++;
+
+ gpio_mapping = devm_kcalloc(physdev, num_entries, sizeof(struct acpi_gpio_mapping),
+ GFP_KERNEL);
+
+ if (!gpio_mapping)
+ goto err;
+
+ if (reset_gpio >= 0) {
+ gpio_mapping[reset_index].name = "reset-gpios";
+ reset_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
+ GFP_KERNEL);
+ if (!reset_gpio_params)
+ goto err;
+
+ for (i = 0; i < num_amps; i++)
+ reset_gpio_params[i].crs_entry_index = reset_gpio;
+
+ gpio_mapping[reset_index].data = reset_gpio_params;
+ gpio_mapping[reset_index].size = num_amps;
+ }
+
+ if (spkid_gpio >= 0) {
+ gpio_mapping[spkid_index].name = "spk-id-gpios";
+ spkid_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
+ GFP_KERNEL);
+ if (!spkid_gpio_params)
+ goto err;
+
+ for (i = 0; i < num_amps; i++)
+ spkid_gpio_params[i].crs_entry_index = spkid_gpio;
+
+ gpio_mapping[spkid_index].data = spkid_gpio_params;
+ gpio_mapping[spkid_index].size = num_amps;
+ }
+
+ if ((cs_gpio_index >= 0) && (num_amps == 2)) {
+ gpio_mapping[csgpio_index].name = "cs-gpios";
+ /* only one GPIO CS is supported without using _DSD, obtained using index 0 */
+ cs_gpio_params = devm_kzalloc(physdev, sizeof(struct acpi_gpio_params), GFP_KERNEL);
+ if (!cs_gpio_params)
+ goto err;
+
+ cs_gpio_params->crs_entry_index = cs_gpio_index;
+
+ gpio_mapping[csgpio_index].data = cs_gpio_params;
+ gpio_mapping[csgpio_index].size = 1;
+ }
+
+ return devm_acpi_dev_add_driver_gpios(physdev, gpio_mapping);
+err:
+ devm_kfree(physdev, gpio_mapping);
+ devm_kfree(physdev, reset_gpio_params);
+ devm_kfree(physdev, spkid_gpio_params);
+ devm_kfree(physdev, cs_gpio_params);
+ return -ENOMEM;
+}
+
+static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+ const struct cs35l41_config *cfg;
+ struct gpio_desc *cs_gpiod;
+ struct spi_device *spi;
+ bool dsd_found;
+ int ret;
+ int i;
+
+ for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
+ if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
+ break;
+ }
+
+ if (!cfg->ssid)
+ return -ENOENT;
+
+ if (!cs35l41->dacpi || cs35l41->dacpi != ACPI_COMPANION(physdev)) {
+ dev_err(cs35l41->dev, "ACPI Device does not match, cannot override _DSD.\n");
+ return -ENODEV;
+ }
+
+ dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
+
+ dsd_found = acpi_dev_has_props(cs35l41->dacpi);
+
+ if (!dsd_found) {
+ ret = cs35l41_add_gpios(cs35l41, physdev, cfg->reset_gpio_index,
+ cfg->spkid_gpio_index, cfg->cs_gpio_index,
+ cfg->num_amps);
+ if (ret) {
+ dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
+ return ret;
+ }
+ } else if (cfg->reset_gpio_index >= 0 || cfg->spkid_gpio_index >= 0) {
+ dev_warn(cs35l41->dev, "Cannot add Reset/Speaker ID/SPI CS GPIO Mapping, "
+ "_DSD already exists.\n");
+ }
+
+ if (cs35l41->control_bus == SPI) {
+ cs35l41->index = id;
+
+ /*
+ * Manually set the Chip Select for the second amp <cs_gpio_index> in the node.
+ * This is only supported for systems with 2 amps, since we cannot expand the
+ * default number of chip selects without using cs-gpios
+ * The CS GPIO must be set high prior to communicating with the first amp (which
+ * uses a native chip select), to ensure the second amp does not clash with the
+ * first.
+ */
+ if (IS_ENABLED(CONFIG_SPI) && cfg->cs_gpio_index >= 0) {
+ spi = to_spi_device(cs35l41->dev);
+
+ if (cfg->num_amps != 2) {
+ dev_warn(cs35l41->dev,
+ "Cannot update SPI CS, Number of Amps (%d) != 2\n",
+ cfg->num_amps);
+ } else if (dsd_found) {
+ dev_warn(cs35l41->dev,
+ "Cannot update SPI CS, _DSD already exists.\n");
+ } else {
+ /*
+ * This is obtained using driver_gpios, since only one GPIO for CS
+ * exists, this can be obtained using index 0.
+ */
+ cs_gpiod = gpiod_get_index(physdev, "cs", 0, GPIOD_OUT_LOW);
+ if (IS_ERR(cs_gpiod)) {
+ dev_err(cs35l41->dev,
+ "Unable to get Chip Select GPIO descriptor\n");
+ return PTR_ERR(cs_gpiod);
+ }
+ if (id == 1) {
+ spi_set_csgpiod(spi, 0, cs_gpiod);
+ cs35l41->cs_gpio = cs_gpiod;
+ } else {
+ gpiod_set_value_cansleep(cs_gpiod, true);
+ gpiod_put(cs_gpiod);
+ }
+ spi_setup(spi);
+ }
+ }
+ } else {
+ if (cfg->num_amps > 2)
+ /*
+ * i2c addresses for 3/4 amps are used in order: 0x40, 0x41, 0x42, 0x43,
+ * subtracting 0x40 would give zero-based index
+ */
+ cs35l41->index = id - 0x40;
+ else
+ /* i2c addr 0x40 for first amp (always), 0x41/0x42 for 2nd amp */
+ cs35l41->index = id == 0x40 ? 0 : 1;
+ }
+
+ cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
+ cs35l41->index, GPIOD_OUT_LOW,
+ "cs35l41-reset");
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, cfg->num_amps, -1);
+
+ hw_cfg->spk_pos = cfg->channel[cs35l41->index];
+
+ cs35l41->channel_index = 0;
+ for (i = 0; i < cs35l41->index; i++)
+ if (cfg->channel[i] == hw_cfg->spk_pos)
+ cs35l41->channel_index++;
+
+ if (cfg->boost_type == INTERNAL) {
+ hw_cfg->bst_type = CS35L41_INT_BOOST;
+ hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
+ hw_cfg->bst_ipk = cfg->boost_peak_milliamp;
+ hw_cfg->bst_cap = cfg->boost_cap_microfarad;
+ hw_cfg->gpio1.func = CS35L41_NOT_USED;
+ hw_cfg->gpio1.valid = true;
+ } else {
+ hw_cfg->bst_type = CS35L41_EXT_BOOST;
+ hw_cfg->bst_ind = -1;
+ hw_cfg->bst_ipk = -1;
+ hw_cfg->bst_cap = -1;
+ hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+ hw_cfg->gpio1.valid = true;
+ }
+
+ hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+ hw_cfg->gpio2.valid = true;
+ hw_cfg->valid = true;
+
+ return 0;
+}
+
+/*
+ * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has
+ * its own speaker id.
+ */
+static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+ /* If _DSD exists for this laptop, we cannot support it through here */
+ if (acpi_dev_has_props(cs35l41->dacpi))
+ return -ENOENT;
+
+ /* check I2C address to assign the index */
+ cs35l41->index = id == 0x40 ? 0 : 1;
+ cs35l41->channel_index = 0;
+ cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+ if (cs35l41->index == 0)
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);
+ else
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+ hw_cfg->spk_pos = cs35l41->index;
+ hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+ hw_cfg->gpio2.valid = true;
+ hw_cfg->valid = true;
+
+ hw_cfg->bst_type = CS35L41_INT_BOOST;
+ hw_cfg->bst_ind = 1000;
+ hw_cfg->bst_ipk = 4100;
+ hw_cfg->bst_cap = 24;
+ hw_cfg->gpio1.func = CS35L41_NOT_USED;
+ hw_cfg->gpio1.valid = true;
+
+ return 0;
+}
+
+/*
+ * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
+ * And devices created by serial-multi-instantiate don't have their device struct
+ * pointing to the correct fwnode, so acpi_dev must be used here.
+ * And devm functions expect that the device requesting the resource has the correct
+ * fwnode.
+ */
+static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+ /* check I2C address to assign the index */
+ cs35l41->index = id == 0x40 ? 0 : 1;
+ cs35l41->channel_index = 0;
+ cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+ hw_cfg->spk_pos = cs35l41->index;
+ hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+ hw_cfg->gpio2.valid = true;
+ hw_cfg->valid = true;
+
+ if (strcmp(hid, "CLSA0100") == 0) {
+ hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
+ } else if (strcmp(hid, "CLSA0101") == 0) {
+ hw_cfg->bst_type = CS35L41_EXT_BOOST;
+ hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+ hw_cfg->gpio1.valid = true;
+ }
+
+ return 0;
+}
+
+static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ int ret;
+
+ ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2);
+ if (ret) {
+ dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
+ return ret;
+ }
+
+ return cs35l41_hda_parse_acpi(cs35l41, physdev, id);
+}
+
+struct cs35l41_prop_model {
+ const char *hid;
+ const char *ssid;
+ int (*add_prop)(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid);
+};
+
+static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
+ { "CLSA0100", NULL, lenovo_legion_no_acpi },
+ { "CLSA0101", NULL, lenovo_legion_no_acpi },
+ { "CSC3551", "10251826", generic_dsd_config },
+ { "CSC3551", "1025182C", generic_dsd_config },
+ { "CSC3551", "10251844", generic_dsd_config },
+ { "CSC3551", "10280B27", generic_dsd_config },
+ { "CSC3551", "10280B28", generic_dsd_config },
+ { "CSC3551", "10280BEB", generic_dsd_config },
+ { "CSC3551", "10280C4D", generic_dsd_config },
+ { "CSC3551", "103C89C6", generic_dsd_config },
+ { "CSC3551", "103C8A28", generic_dsd_config },
+ { "CSC3551", "103C8A29", generic_dsd_config },
+ { "CSC3551", "103C8A2A", generic_dsd_config },
+ { "CSC3551", "103C8A2B", generic_dsd_config },
+ { "CSC3551", "103C8A2C", generic_dsd_config },
+ { "CSC3551", "103C8A2D", generic_dsd_config },
+ { "CSC3551", "103C8A2E", generic_dsd_config },
+ { "CSC3551", "103C8A30", generic_dsd_config },
+ { "CSC3551", "103C8A31", generic_dsd_config },
+ { "CSC3551", "103C8A6E", generic_dsd_config },
+ { "CSC3551", "103C8BB3", generic_dsd_config },
+ { "CSC3551", "103C8BB4", generic_dsd_config },
+ { "CSC3551", "103C8BDD", generic_dsd_config },
+ { "CSC3551", "103C8BDE", generic_dsd_config },
+ { "CSC3551", "103C8BDF", generic_dsd_config },
+ { "CSC3551", "103C8BE0", generic_dsd_config },
+ { "CSC3551", "103C8BE1", generic_dsd_config },
+ { "CSC3551", "103C8BE2", generic_dsd_config },
+ { "CSC3551", "103C8BE3", generic_dsd_config },
+ { "CSC3551", "103C8BE5", generic_dsd_config },
+ { "CSC3551", "103C8BE6", generic_dsd_config },
+ { "CSC3551", "103C8BE7", generic_dsd_config },
+ { "CSC3551", "103C8BE8", generic_dsd_config },
+ { "CSC3551", "103C8BE9", generic_dsd_config },
+ { "CSC3551", "103C8B3A", generic_dsd_config },
+ { "CSC3551", "103C8C15", generic_dsd_config },
+ { "CSC3551", "103C8C16", generic_dsd_config },
+ { "CSC3551", "103C8C17", generic_dsd_config },
+ { "CSC3551", "103C8C4D", generic_dsd_config },
+ { "CSC3551", "103C8C4E", generic_dsd_config },
+ { "CSC3551", "103C8C4F", generic_dsd_config },
+ { "CSC3551", "103C8C50", generic_dsd_config },
+ { "CSC3551", "103C8C51", generic_dsd_config },
+ { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8CDD", generic_dsd_config },
+ { "CSC3551", "103C8CDE", generic_dsd_config },
+ { "CSC3551", "104312AF", generic_dsd_config },
+ { "CSC3551", "10431433", generic_dsd_config },
+ { "CSC3551", "10431463", generic_dsd_config },
+ { "CSC3551", "10431473", generic_dsd_config },
+ { "CSC3551", "10431483", generic_dsd_config },
+ { "CSC3551", "10431493", generic_dsd_config },
+ { "CSC3551", "104314D3", generic_dsd_config },
+ { "CSC3551", "104314E3", generic_dsd_config },
+ { "CSC3551", "10431503", generic_dsd_config },
+ { "CSC3551", "10431533", generic_dsd_config },
+ { "CSC3551", "10431573", generic_dsd_config },
+ { "CSC3551", "10431663", generic_dsd_config },
+ { "CSC3551", "10431683", generic_dsd_config },
+ { "CSC3551", "104316A3", generic_dsd_config },
+ { "CSC3551", "104316D3", generic_dsd_config },
+ { "CSC3551", "104316F3", generic_dsd_config },
+ { "CSC3551", "104317F3", generic_dsd_config },
+ { "CSC3551", "10431863", generic_dsd_config },
+ { "CSC3551", "104318D3", generic_dsd_config },
+ { "CSC3551", "10431A63", missing_speaker_id_gpio2 },
+ { "CSC3551", "10431A83", generic_dsd_config },
+ { "CSC3551", "10431B93", generic_dsd_config },
+ { "CSC3551", "10431C9F", generic_dsd_config },
+ { "CSC3551", "10431CAF", generic_dsd_config },
+ { "CSC3551", "10431CCF", generic_dsd_config },
+ { "CSC3551", "10431CDF", generic_dsd_config },
+ { "CSC3551", "10431CEF", generic_dsd_config },
+ { "CSC3551", "10431D1F", generic_dsd_config },
+ { "CSC3551", "10431DA2", generic_dsd_config },
+ { "CSC3551", "10431E02", generic_dsd_config },
+ { "CSC3551", "10431E12", generic_dsd_config },
+ { "CSC3551", "10431EE2", generic_dsd_config },
+ { "CSC3551", "10431F12", generic_dsd_config },
+ { "CSC3551", "10431F1F", generic_dsd_config },
+ { "CSC3551", "10431F62", generic_dsd_config },
+ { "CSC3551", "10433A20", generic_dsd_config },
+ { "CSC3551", "10433A30", generic_dsd_config },
+ { "CSC3551", "10433A40", generic_dsd_config },
+ { "CSC3551", "10433A50", generic_dsd_config },
+ { "CSC3551", "10433A60", generic_dsd_config },
+ { "CSC3551", "17AA3865", generic_dsd_config },
+ { "CSC3551", "17AA3866", generic_dsd_config },
+ { "CSC3551", "17AA386E", generic_dsd_config },
+ { "CSC3551", "17AA386F", generic_dsd_config },
+ { "CSC3551", "17AA3877", generic_dsd_config },
+ { "CSC3551", "17AA3878", generic_dsd_config },
+ { "CSC3551", "17AA38A9", generic_dsd_config },
+ { "CSC3551", "17AA38AB", generic_dsd_config },
+ { "CSC3551", "17AA38B4", generic_dsd_config },
+ { "CSC3551", "17AA38B5", generic_dsd_config },
+ { "CSC3551", "17AA38B6", generic_dsd_config },
+ { "CSC3551", "17AA38B7", generic_dsd_config },
+ { "CSC3551", "17AA38C7", generic_dsd_config },
+ { "CSC3551", "17AA38C8", generic_dsd_config },
+ { "CSC3551", "17AA38F9", generic_dsd_config },
+ { "CSC3551", "17AA38FA", generic_dsd_config },
+ { "CSC3551", "17AA3929", generic_dsd_config },
+ { "CSC3551", "17AA392B", generic_dsd_config },
+ {}
+};
+
+int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ const struct cs35l41_prop_model *model;
+
+ for (model = cs35l41_prop_model_table; model->hid; model++) {
+ if (!strcmp(model->hid, hid) &&
+ (!model->ssid ||
+ (cs35l41->acpi_subsystem_id &&
+ !strcasecmp(model->ssid, cs35l41->acpi_subsystem_id))))
+ return model->add_prop(cs35l41, physdev, id, hid);
+ }
+
+ return -ENOENT;
+}
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.h b/sound/hda/codecs/side-codecs/cs35l41_hda_property.h
new file mode 100644
index 000000000000..fd834042e2fd
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda_property.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * CS35L41 ALSA HDA Property driver
+ *
+ * Copyright 2023 Cirrus Logic, Inc.
+ *
+ * Author: Stefan Binding <sbinding@opensource.cirrus.com>
+ */
+
+#ifndef CS35L41_HDA_PROP_H
+#define CS35L41_HDA_PROP_H
+
+#include <linux/device.h>
+#include "cs35l41_hda.h"
+
+int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid);
+#endif /* CS35L41_HDA_PROP_H */
diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c
index eb287aa5f782..2acbaf8467a0 100644
--- a/sound/pci/hda/cs35l41_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c
@@ -26,7 +26,7 @@ static int cs35l41_hda_spi_probe(struct spi_device *spi)
return -ENODEV;
return cs35l41_hda_probe(&spi->dev, device_name, spi_get_chipselect(spi, 0), spi->irq,
- devm_regmap_init_spi(spi, &cs35l41_regmap_spi));
+ devm_regmap_init_spi(spi, &cs35l41_regmap_spi), SPI);
}
static void cs35l41_hda_spi_remove(struct spi_device *spi)
@@ -38,6 +38,7 @@ static const struct spi_device_id cs35l41_hda_spi_id[] = {
{ "cs35l41-hda", 0 },
{}
};
+MODULE_DEVICE_TABLE(spi, cs35l41_hda_spi_id);
static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
{ "CSC3551", 0 },
@@ -58,6 +59,6 @@ static struct spi_driver cs35l41_spi_driver = {
module_spi_driver(cs35l41_spi_driver);
MODULE_DESCRIPTION("HDA CS35L41 driver");
-MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L41);
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41");
MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
new file mode 100644
index 000000000000..f7ba92e11957
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -0,0 +1,1286 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// HDA audio driver for Cirrus Logic CS35L56 smart amp
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+//
+
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/cs-amp-lib.h>
+#include <sound/hda_codec.h>
+#include <sound/tlv.h>
+#include "cirrus_scodec.h"
+#include "cs35l56_hda.h"
+#include "hda_component.h"
+#include "../generic.h"
+
+ /*
+ * The cs35l56_hda_dai_config[] reg sequence configures the device as
+ * ASP1_BCLK_FREQ = 3.072 MHz
+ * ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S
+ * ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots
+ * ASP1_RX_WL = 24 bits per sample
+ * ASP1_TX_WL = 24 bits per sample
+ * ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled
+ *
+ * Override any Windows-specific mixer settings applied by the firmware.
+ */
+static const struct reg_sequence cs35l56_hda_dai_config[] = {
+ { CS35L56_ASP1_CONTROL1, 0x00000021 },
+ { CS35L56_ASP1_CONTROL2, 0x20200200 },
+ { CS35L56_ASP1_CONTROL3, 0x00000003 },
+ { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
+ { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
+ { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
+ { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
+ { CS35L56_ASP1_ENABLES1, 0x00000000 },
+ { CS35L56_ASP1TX1_INPUT, 0x00000018 },
+ { CS35L56_ASP1TX2_INPUT, 0x00000019 },
+ { CS35L56_ASP1TX3_INPUT, 0x00000020 },
+ { CS35L56_ASP1TX4_INPUT, 0x00000028 },
+
+};
+
+static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56)
+{
+ /* Wait for patching to complete */
+ flush_work(&cs35l56->dsp_work);
+}
+
+static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
+{
+ unsigned int val;
+ int ret;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ pm_runtime_get_sync(cs35l56->base.dev);
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);
+ if (ret == 0) {
+ /* Wait for firmware to enter PS0 power state */
+ ret = regmap_read_poll_timeout(cs35l56->base.regmap,
+ cs35l56->base.fw_reg->transducer_actual_ps,
+ val, (val == CS35L56_PS0),
+ CS35L56_PS0_POLL_US,
+ CS35L56_PS0_TIMEOUT_US);
+ if (ret)
+ dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
+ }
+ regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+ BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
+ cs35l56->asp_tx_mask);
+ cs35l56->playing = true;
+}
+
+static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56)
+{
+ cs35l56->playing = false;
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
+ regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+ BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
+ BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) |
+ BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT));
+
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
+}
+
+static void cs35l56_hda_playback_hook(struct device *dev, int action)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action);
+
+ switch (action) {
+ case HDA_GEN_PCM_ACT_PREPARE:
+ if (cs35l56->playing)
+ break;
+
+ /* If we're suspended: flag that resume should start playback */
+ if (cs35l56->suspended) {
+ cs35l56->playing = true;
+ break;
+ }
+
+ cs35l56_hda_play(cs35l56);
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ if (!cs35l56->playing)
+ break;
+
+ cs35l56_hda_pause(cs35l56);
+ break;
+ default:
+ break;
+ }
+}
+
+static int cs35l56_hda_runtime_suspend(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ if (cs35l56->cs_dsp.booted)
+ cs_dsp_stop(&cs35l56->cs_dsp);
+
+ return cs35l56_runtime_suspend_common(&cs35l56->base);
+}
+
+static int cs35l56_hda_runtime_resume(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = cs35l56_runtime_resume_common(&cs35l56->base, false);
+ if (ret < 0)
+ return ret;
+
+ if (cs35l56->cs_dsp.booted) {
+ ret = cs_dsp_run(&cs35l56->cs_dsp);
+ if (ret) {
+ dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
+ regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ CS35L56_MBOX_CMD_HIBERNATE_NOW);
+
+ regcache_cache_only(cs35l56->base.regmap, true);
+
+ return ret;
+}
+
+static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC;
+ if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC)
+ uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1;
+ strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name));
+
+ return 0;
+}
+
+static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+ unsigned int reg_val;
+ int i;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
+ reg_val &= CS35L56_ASP_TXn_SRC_MASK;
+
+ for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
+ if (cs35l56_tx_input_values[i] == reg_val) {
+ ucontrol->value.enumerated.item[0] = i;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+ unsigned int item = ucontrol->value.enumerated.item[0];
+ bool changed;
+
+ if (item >= CS35L56_NUM_INPUT_SRC)
+ return -EINVAL;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
+ CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
+ &changed);
+
+ return changed;
+}
+
+static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN;
+ uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX;
+ return 0;
+}
+
+static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+ unsigned int pos;
+ int ret;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ ret = regmap_read(cs35l56->base.regmap,
+ cs35l56->base.fw_reg->posture_number, &pos);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = pos;
+
+ return 0;
+}
+
+static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+ unsigned long pos = ucontrol->value.integer.value[0];
+ bool changed;
+ int ret;
+
+ if ((pos < CS35L56_MAIN_POSTURE_MIN) ||
+ (pos > CS35L56_MAIN_POSTURE_MAX))
+ return -EINVAL;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->posture_number,
+ CS35L56_MAIN_POSTURE_MASK, pos, &changed);
+ if (ret)
+ return ret;
+
+ return changed;
+}
+
+static const struct {
+ const char *name;
+ unsigned int reg;
+} cs35l56_hda_mixer_controls[] = {
+ { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT },
+ { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT },
+ { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT },
+ { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT },
+};
+
+static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0);
+
+static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.step = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
+ CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
+
+ return 0;
+}
+
+static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+ unsigned int raw_vol;
+ int vol;
+ int ret;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ ret = regmap_read(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, &raw_vol);
+
+ if (ret)
+ return ret;
+
+ vol = (s16)(raw_vol & 0xFFFF);
+ vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
+
+ if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT))
+ vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1));
+
+ ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
+
+ return 0;
+}
+
+static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+ long vol = ucontrol->value.integer.value[0];
+ unsigned int raw_vol;
+ bool changed;
+ int ret;
+
+ if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
+ CS35L56_MAIN_RENDER_USER_VOLUME_MIN)))
+ return -EINVAL;
+
+ raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<
+ CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MASK, raw_vol, &changed);
+ if (ret)
+ return ret;
+
+ return changed;
+}
+
+static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56)
+{
+ struct snd_kcontrol_new ctl_template = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = cs35l56_hda_posture_info,
+ .get = cs35l56_hda_posture_get,
+ .put = cs35l56_hda_posture_put,
+ };
+ char name[64];
+ int i;
+
+ snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name);
+ ctl_template.name = name;
+ cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56);
+ if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl))
+ dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
+
+ /* Mixer controls */
+ ctl_template.info = cs35l56_hda_mixer_info;
+ ctl_template.get = cs35l56_hda_mixer_get;
+ ctl_template.put = cs35l56_hda_mixer_put;
+
+ BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls));
+
+ for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) {
+ snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name,
+ cs35l56_hda_mixer_controls[i].name);
+ ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg;
+ cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56);
+ if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) {
+ dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n",
+ ctl_template.name);
+ }
+ }
+
+ ctl_template.info = cs35l56_hda_vol_info;
+ ctl_template.get = cs35l56_hda_vol_get;
+ ctl_template.put = cs35l56_hda_vol_put;
+ ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ);
+ ctl_template.tlv.p = cs35l56_hda_vol_tlv;
+ snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name);
+ ctl_template.name = name;
+ cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56);
+ if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl))
+ dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
+}
+
+static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--)
+ snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]);
+
+ snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl);
+ snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);
+}
+
+static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
+ /* cs_dsp requires the client to provide this even if it is empty */
+};
+
+static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
+ const struct firmware **firmware, char **filename,
+ const char *base_name, const char *system_name,
+ const char *amp_name,
+ const char *filetype)
+{
+ char *s, c;
+ int ret = 0;
+
+ if (system_name && amp_name)
+ *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,
+ system_name, amp_name, filetype);
+ else if (system_name)
+ *filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,
+ system_name, filetype);
+ else
+ *filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);
+
+ if (!*filename)
+ return -ENOMEM;
+
+ /*
+ * Make sure that filename is lower-case and any non alpha-numeric
+ * characters except full stop and forward slash are replaced with
+ * hyphens.
+ */
+ s = *filename;
+ while (*s) {
+ c = *s;
+ if (isalnum(c))
+ *s = tolower(c);
+ else if (c != '.' && c != '/')
+ *s = '-';
+ s++;
+ }
+
+ ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev);
+ if (ret) {
+ dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename);
+ kfree(*filename);
+ *filename = NULL;
+ return ret;
+ }
+
+ dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename);
+
+ return 0;
+}
+
+static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
+ unsigned int preloaded_fw_ver,
+ const struct firmware **wmfw_firmware,
+ char **wmfw_filename,
+ const struct firmware **coeff_firmware,
+ char **coeff_filename)
+{
+ const char *system_name = cs35l56->system_name;
+ const char *amp_name = cs35l56->amp_name;
+ char base_name[37];
+ int ret;
+
+ if (preloaded_fw_ver) {
+ snprintf(base_name, sizeof(base_name),
+ "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",
+ cs35l56->base.type,
+ cs35l56->base.rev,
+ cs35l56->base.secured ? "-s" : "",
+ preloaded_fw_ver & 0xffffff);
+ } else {
+ snprintf(base_name, sizeof(base_name),
+ "cirrus/cs35l%02x-%02x%s-dsp1-misc",
+ cs35l56->base.type,
+ cs35l56->base.rev,
+ cs35l56->base.secured ? "-s" : "");
+ }
+
+ if (system_name && amp_name) {
+ if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+ base_name, system_name, amp_name, "wmfw")) {
+ cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+ base_name, system_name, amp_name, "bin");
+ return;
+ }
+ }
+
+ if (system_name) {
+ if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+ base_name, system_name, NULL, "wmfw")) {
+ if (amp_name)
+ cs35l56_hda_request_firmware_file(cs35l56,
+ coeff_firmware, coeff_filename,
+ base_name, system_name,
+ amp_name, "bin");
+ if (!*coeff_firmware)
+ cs35l56_hda_request_firmware_file(cs35l56,
+ coeff_firmware, coeff_filename,
+ base_name, system_name,
+ NULL, "bin");
+ return;
+ }
+
+ /*
+ * Check for system-specific bin files without wmfw before
+ * falling back to generic firmware
+ */
+ if (amp_name)
+ cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+ base_name, system_name, amp_name, "bin");
+ if (!*coeff_firmware)
+ cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+ base_name, system_name, NULL, "bin");
+
+ if (*coeff_firmware)
+ return;
+ }
+
+ ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+ base_name, NULL, NULL, "wmfw");
+ if (!ret) {
+ cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+ base_name, NULL, NULL, "bin");
+ return;
+ }
+
+ if (!*coeff_firmware)
+ cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+ base_name, NULL, NULL, "bin");
+}
+
+static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
+ char *wmfw_filename,
+ const struct firmware *coeff_firmware,
+ char *coeff_filename)
+{
+ release_firmware(wmfw_firmware);
+ kfree(wmfw_filename);
+
+ release_firmware(coeff_firmware);
+ kfree(coeff_filename);
+}
+
+static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
+{
+ int ret;
+
+ if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
+ return -EACCES;
+
+ ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
+ &cs35l56_calibration_controls,
+ &cs35l56->base.cal_data);
+ if (ret < 0) {
+ dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(cs35l56->base.dev, "Calibration applied\n");
+
+ return 0;
+}
+
+static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
+{
+ const struct firmware *coeff_firmware = NULL;
+ const struct firmware *wmfw_firmware = NULL;
+ char *coeff_filename = NULL;
+ char *wmfw_filename = NULL;
+ unsigned int preloaded_fw_ver;
+ bool firmware_missing;
+ int ret;
+
+ /*
+ * Prepare for a new DSP power-up. If the DSP has had firmware
+ * downloaded previously then it needs to be powered down so that it
+ * can be updated.
+ */
+ if (cs35l56->base.fw_patched)
+ cs_dsp_power_down(&cs35l56->cs_dsp);
+
+ cs35l56->base.fw_patched = false;
+
+ ret = pm_runtime_resume_and_get(cs35l56->base.dev);
+ if (ret < 0) {
+ dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret);
+ return;
+ }
+
+ /*
+ * The firmware can only be upgraded if it is currently running
+ * from the built-in ROM. If not, the wmfw/bin must be for the
+ * version of firmware that is running on the chip.
+ */
+ ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);
+ if (ret)
+ goto err_pm_put;
+
+ if (firmware_missing)
+ preloaded_fw_ver = 0;
+
+ cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,
+ &wmfw_firmware, &wmfw_filename,
+ &coeff_firmware, &coeff_filename);
+
+ /*
+ * If the BIOS didn't patch the firmware a bin file is mandatory to
+ * enable the ASP·
+ */
+ if (!coeff_firmware && firmware_missing) {
+ dev_err(cs35l56->base.dev, ".bin file required but not found\n");
+ goto err_fw_release;
+ }
+
+ mutex_lock(&cs35l56->base.irq_lock);
+
+ /*
+ * If the firmware hasn't been patched it must be shutdown before
+ * doing a full patch and reset afterwards. If it is already
+ * running a patched version the firmware files only contain
+ * tunings and we can use the lower cost reinit sequence instead.
+ */
+ if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
+ ret = cs35l56_firmware_shutdown(&cs35l56->base);
+ if (ret)
+ goto err;
+ }
+
+ ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
+ coeff_firmware, coeff_filename, "misc");
+ if (ret) {
+ dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
+ goto err;
+ }
+
+ if (wmfw_filename)
+ dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);
+
+ if (coeff_filename)
+ dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
+
+ /* If we downloaded firmware, reset the device and wait for it to boot */
+ if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
+ cs35l56_system_reset(&cs35l56->base, false);
+ regcache_mark_dirty(cs35l56->base.regmap);
+ ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
+ if (ret)
+ goto err_powered_up;
+
+ regcache_cache_only(cs35l56->base.regmap, false);
+ }
+
+ /* Disable auto-hibernate so that runtime_pm has control */
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ if (ret)
+ goto err_powered_up;
+
+ regcache_sync(cs35l56->base.regmap);
+
+ regmap_clear_bits(cs35l56->base.regmap,
+ cs35l56->base.fw_reg->prot_sts,
+ CS35L56_FIRMWARE_MISSING);
+ cs35l56->base.fw_patched = true;
+
+ ret = cs_dsp_run(&cs35l56->cs_dsp);
+ if (ret)
+ dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
+
+ /* Don't need to check return code, it's not fatal if this fails */
+ cs35l56_hda_apply_calibration(cs35l56);
+
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
+ if (ret)
+ cs_dsp_stop(&cs35l56->cs_dsp);
+
+ cs35l56_log_tuning(&cs35l56->base, &cs35l56->cs_dsp);
+
+err_powered_up:
+ if (!cs35l56->base.fw_patched)
+ cs_dsp_power_down(&cs35l56->cs_dsp);
+err:
+ mutex_unlock(&cs35l56->base.irq_lock);
+err_fw_release:
+ cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
+ coeff_firmware, coeff_filename);
+err_pm_put:
+ pm_runtime_put(cs35l56->base.dev);
+}
+
+static void cs35l56_hda_dsp_work(struct work_struct *work)
+{
+ struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work);
+
+ cs35l56_hda_fw_load(cs35l56);
+}
+
+static ssize_t cs35l56_hda_debugfs_calibrate_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ ssize_t ret;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_calibrate_debugfs_write(cs35l56_base, from, count, ppos);
+ pm_runtime_autosuspend(cs35l56_base->dev);
+
+ return ret;
+}
+
+static ssize_t cs35l56_hda_debugfs_cal_temperature_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ ssize_t ret;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_cal_ambient_debugfs_write(cs35l56_base, from, count, ppos);
+ pm_runtime_autosuspend(cs35l56_base->dev);
+
+ return ret;
+}
+
+static ssize_t cs35l56_hda_debugfs_cal_data_read(struct file *file,
+ char __user *to,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ ssize_t ret;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_cal_data_debugfs_read(cs35l56_base, to, count, ppos);
+ pm_runtime_autosuspend(cs35l56_base->dev);
+
+ return ret;
+}
+
+static ssize_t cs35l56_hda_debugfs_cal_data_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_hda *cs35l56 = cs35l56_hda_from_base(cs35l56_base);
+ ssize_t ret;
+
+ ret = cs35l56_cal_data_debugfs_write(cs35l56_base, from, count, ppos);
+ if (ret == -ENODATA)
+ return count; /* Ignore writes of empty cal blobs */
+
+ if (ret < 0)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_hda_apply_calibration(cs35l56);
+ if (ret == 0)
+ cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_AUDIO_REINIT);
+ else
+ count = -EIO;
+
+ pm_runtime_autosuspend(cs35l56_base->dev);
+
+ return count;
+}
+
+static const struct cs35l56_cal_debugfs_fops cs35l56_hda_cal_debugfs_fops = {
+ .calibrate = {
+ .write = cs35l56_hda_debugfs_calibrate_write,
+ },
+ .cal_temperature = {
+ .write = cs35l56_hda_debugfs_cal_temperature_write,
+ },
+ .cal_data = {
+ .read = cs35l56_hda_debugfs_cal_data_read,
+ .write = cs35l56_hda_debugfs_cal_data_write,
+ },
+};
+
+static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, cs35l56->index);
+ if (!comp)
+ return -EINVAL;
+
+ if (comp->dev)
+ return -EBUSY;
+
+ comp->dev = dev;
+ cs35l56->codec = parent->codec;
+ strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+ comp->playback_hook = cs35l56_hda_playback_hook;
+
+ queue_work(system_long_wq, &cs35l56->dsp_work);
+
+ cs35l56_hda_create_controls(cs35l56);
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+ cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);
+ cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
+#endif
+
+ if (IS_ENABLED(CONFIG_SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS))
+ cs35l56_create_cal_debugfs(&cs35l56->base, &cs35l56_hda_cal_debugfs_fops);
+
+ dev_dbg(cs35l56->base.dev, "Bound\n");
+
+ return 0;
+}
+
+static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ cancel_work_sync(&cs35l56->dsp_work);
+
+ cs35l56_remove_cal_debugfs(&cs35l56->base);
+ cs35l56_hda_remove_controls(cs35l56);
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+ cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);
+ debugfs_remove_recursive(cs35l56->debugfs_root);
+#endif
+
+ if (cs35l56->base.fw_patched)
+ cs_dsp_power_down(&cs35l56->cs_dsp);
+
+ comp = hda_component_from_index(parent, cs35l56->index);
+ if (comp && (comp->dev == dev))
+ memset(comp, 0, sizeof(*comp));
+
+ cs35l56->codec = NULL;
+
+ dev_dbg(cs35l56->base.dev, "Unbound\n");
+}
+
+static const struct component_ops cs35l56_hda_comp_ops = {
+ .bind = cs35l56_hda_bind,
+ .unbind = cs35l56_hda_unbind,
+};
+
+static int cs35l56_hda_system_suspend(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ cs35l56_hda_wait_dsp_ready(cs35l56);
+
+ if (cs35l56->playing)
+ cs35l56_hda_pause(cs35l56);
+
+ cs35l56->suspended = true;
+
+ /*
+ * The interrupt line is normally shared, but after we start suspending
+ * we can't check if our device is the source of an interrupt, and can't
+ * clear it. Prevent this race by temporarily disabling the parent irq
+ * until we reach _no_irq.
+ */
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int cs35l56_hda_system_suspend_late(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ /*
+ * RESET is usually shared by all amps so it must not be asserted until
+ * all driver instances have done their suspend() stage.
+ */
+ if (cs35l56->base.reset_gpio) {
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+ cs35l56_wait_min_reset_pulse();
+ }
+
+ return 0;
+}
+
+static int cs35l56_hda_system_suspend_no_irq(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
+ if (cs35l56->base.irq)
+ enable_irq(cs35l56->base.irq);
+
+ return 0;
+}
+
+static int cs35l56_hda_system_resume_no_irq(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ /*
+ * WAKE interrupts unmask if the CS35L56 hibernates, which can cause
+ * spurious interrupts, and the interrupt line is normally shared.
+ * We can't check if our device is the source of an interrupt, and can't
+ * clear it, until it has fully resumed. Prevent this race by temporarily
+ * disabling the parent irq until we complete resume().
+ */
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);
+
+ return 0;
+}
+
+static int cs35l56_hda_system_resume_early(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ /* Ensure a spec-compliant RESET pulse. */
+ if (cs35l56->base.reset_gpio) {
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+ cs35l56_wait_min_reset_pulse();
+
+ /* Release shared RESET before drivers start resume(). */
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
+ cs35l56_wait_control_port_ready();
+ }
+
+ return 0;
+}
+
+static int cs35l56_hda_system_resume(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+ int ret;
+
+ /* Undo pm_runtime_force_suspend() before re-enabling the irq */
+ ret = pm_runtime_force_resume(dev);
+ if (cs35l56->base.irq)
+ enable_irq(cs35l56->base.irq);
+
+ if (ret)
+ return ret;
+
+ cs35l56->suspended = false;
+
+ if (!cs35l56->codec)
+ return 0;
+
+ ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
+ dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
+ if (ret > 0)
+ queue_work(system_long_wq, &cs35l56->dsp_work);
+
+ if (cs35l56->playing)
+ cs35l56_hda_play(cs35l56);
+
+ return 0;
+}
+
+static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr)
+{
+ /* The cirrus,dev-index property has the wrong values */
+ switch (*bus_addr) {
+ case 0x30:
+ cs35l56->index = 1;
+ return 0;
+ case 0x31:
+ cs35l56->index = 0;
+ return 0;
+ default:
+ /* There is a pseudo-address for broadcast to both amps - ignore it */
+ dev_dbg(cs35l56->base.dev, "Ignoring I2C address %#x\n", *bus_addr);
+ return 0;
+ }
+}
+
+static const struct {
+ const char *sub;
+ int (*fixup_fn)(struct cs35l56_hda *cs35l56, int *bus_addr);
+} cs35l56_hda_fixups[] = {
+ {
+ .sub = "17AA390B", /* Lenovo Yoga Book 9i GenX */
+ .fixup_fn = cs35l56_hda_fixup_yoga9,
+ },
+};
+
+static int cs35l56_hda_apply_platform_fixups(struct cs35l56_hda *cs35l56, const char *sub,
+ int *bus_addr)
+{
+ int i;
+
+ if (IS_ERR(sub))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(cs35l56_hda_fixups); i++) {
+ if (strcasecmp(cs35l56_hda_fixups[i].sub, sub) == 0) {
+ dev_dbg(cs35l56->base.dev, "Applying fixup for %s\n",
+ cs35l56_hda_fixups[i].sub);
+ return (cs35l56_hda_fixups[i].fixup_fn)(cs35l56, bus_addr);
+ }
+ }
+
+ return 0;
+}
+
+static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
+{
+ u32 values[HDA_MAX_COMPONENTS];
+ char hid_string[8];
+ struct acpi_device *adev;
+ const char *property, *sub;
+ size_t nval;
+ int i, ret;
+
+ /*
+ * ACPI_COMPANION isn't available when this driver was instantiated by
+ * the serial-multi-instantiate driver, so lookup the node by HID
+ */
+ if (!ACPI_COMPANION(cs35l56->base.dev)) {
+ snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);
+ adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);
+ if (!adev) {
+ dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
+ dev_name(cs35l56->base.dev));
+ return -ENODEV;
+ }
+ ACPI_COMPANION_SET(cs35l56->base.dev, adev);
+ }
+
+ /* Initialize things that could be overwritten by a fixup */
+ cs35l56->index = -1;
+
+ sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
+ ret = cs35l56_hda_apply_platform_fixups(cs35l56, sub, &id);
+ if (ret)
+ return ret;
+
+ if (cs35l56->index == -1) {
+ property = "cirrus,dev-index";
+ ret = device_property_count_u32(cs35l56->base.dev, property);
+ if (ret <= 0)
+ goto err;
+
+ if (ret > ARRAY_SIZE(values)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ nval = ret;
+
+ ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < nval; i++) {
+ if (values[i] == id) {
+ cs35l56->index = i;
+ break;
+ }
+ }
+
+ /*
+ * It's not an error for the ID to be missing: for I2C there can be
+ * an alias address that is not a real device. So reject silently.
+ */
+ if (cs35l56->index == -1) {
+ dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ if (IS_ERR(sub)) {
+ dev_info(cs35l56->base.dev,
+ "Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
+ PTR_ERR(sub));
+ } else {
+ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
+ if (ret == -ENOENT) {
+ cs35l56->system_name = sub;
+ } else if (ret >= 0) {
+ cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret);
+ kfree(sub);
+ if (!cs35l56->system_name)
+ return -ENOMEM;
+ } else {
+ return ret;
+ }
+ }
+
+ cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,
+ "reset",
+ cs35l56->index,
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cs35l56->base.reset_gpio)) {
+ ret = PTR_ERR(cs35l56->base.reset_gpio);
+
+ /*
+ * If RESET is shared the first amp to probe will grab the reset
+ * line and reset all the amps
+ */
+ if (ret != -EBUSY)
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
+
+ dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
+ cs35l56->base.reset_gpio = NULL;
+ }
+
+ return 0;
+
+err:
+ if (ret != -ENODEV)
+ dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);
+
+ return ret;
+}
+
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
+{
+ int ret;
+
+ mutex_init(&cs35l56->base.irq_lock);
+ dev_set_drvdata(cs35l56->base.dev, cs35l56);
+
+ INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work);
+
+ ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
+ if (ret)
+ goto err;
+
+ cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",
+ cs35l56->index + 1);
+ if (!cs35l56->amp_name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ cs35l56->base.type = hid & 0xff;
+ cs35l56->base.cal_index = cs35l56->index;
+
+ cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
+ cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
+
+ if (cs35l56->base.reset_gpio) {
+ dev_dbg(cs35l56->base.dev, "Hard reset\n");
+
+ /*
+ * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the
+ * ACPI defines a different default state. So explicitly set low.
+ */
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+ cs35l56_wait_min_reset_pulse();
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
+ }
+
+ ret = cs35l56_hw_init(&cs35l56->base);
+ if (ret < 0)
+ goto err;
+
+ /* Reset the device and wait for it to boot */
+ cs35l56_system_reset(&cs35l56->base, false);
+ ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
+ if (ret)
+ goto err;
+
+ regcache_cache_only(cs35l56->base.regmap, false);
+
+ ret = cs35l56_set_patch(&cs35l56->base);
+ if (ret)
+ goto err;
+
+ regcache_mark_dirty(cs35l56->base.regmap);
+ regcache_sync(cs35l56->base.regmap);
+
+ /* Disable auto-hibernate so that runtime_pm has control */
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ if (ret)
+ goto err;
+
+ ret = cs35l56_get_calibration(&cs35l56->base);
+ if (ret)
+ goto err;
+
+ ret = cs_dsp_halo_init(&cs35l56->cs_dsp);
+ if (ret) {
+ dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");
+ goto err;
+ }
+
+ dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
+ cs35l56->system_name, cs35l56->amp_name);
+
+ regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
+ ARRAY_SIZE(cs35l56_hda_dai_config));
+
+ /*
+ * By default only enable one ASP1TXn, where n=amplifier index,
+ * This prevents multiple amps trying to drive the same slot.
+ */
+ cs35l56->asp_tx_mask = BIT(cs35l56->index);
+
+ pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);
+ pm_runtime_use_autosuspend(cs35l56->base.dev);
+ pm_runtime_set_active(cs35l56->base.dev);
+ pm_runtime_mark_last_busy(cs35l56->base.dev);
+ pm_runtime_enable(cs35l56->base.dev);
+
+ cs35l56->base.init_done = true;
+
+ ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
+ if (ret) {
+ dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
+ goto pm_err;
+ }
+
+ return 0;
+
+pm_err:
+ pm_runtime_disable(cs35l56->base.dev);
+ cs_dsp_remove(&cs35l56->cs_dsp);
+err:
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56");
+
+void cs35l56_hda_remove(struct device *dev)
+{
+ struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+ component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);
+
+ pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
+ pm_runtime_get_sync(cs35l56->base.dev);
+ pm_runtime_disable(cs35l56->base.dev);
+
+ cs_dsp_remove(&cs35l56->cs_dsp);
+
+ kfree(cs35l56->system_name);
+ pm_runtime_put_noidle(cs35l56->base.dev);
+
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56");
+
+const struct dev_pm_ops cs35l56_hda_pm_ops = {
+ RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)
+ LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,
+ cs35l56_hda_system_resume_early)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,
+ cs35l56_hda_system_resume_no_irq)
+};
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56");
+
+MODULE_DESCRIPTION("CS35L56 HDA Driver");
+MODULE_IMPORT_NS("FW_CS_DSP");
+MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("cirrus/cs35l54-*.wmfw");
+MODULE_FIRMWARE("cirrus/cs35l54-*.bin");
+MODULE_FIRMWARE("cirrus/cs35l56-*.wmfw");
+MODULE_FIRMWARE("cirrus/cs35l56-*.bin");
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h
new file mode 100644
index 000000000000..cb4b5e7356a3
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * HDA audio driver for Cirrus Logic CS35L56 smart amp
+ *
+ * Copyright (C) 2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __CS35L56_HDA_H__
+#define __CS35L56_HDA_H__
+
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <sound/cs35l56.h>
+
+struct dentry;
+
+struct cs35l56_hda {
+ struct cs35l56_base base;
+ struct hda_codec *codec;
+ struct work_struct dsp_work;
+
+ int index;
+ const char *system_name;
+ const char *amp_name;
+
+ struct cs_dsp cs_dsp;
+ bool playing;
+ bool suspended;
+ u8 asp_tx_mask;
+
+ struct snd_kcontrol *posture_ctl;
+ struct snd_kcontrol *volume_ctl;
+ struct snd_kcontrol *mixer_ctl[4];
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+ struct dentry *debugfs_root;
+#endif
+};
+
+static inline struct cs35l56_hda *cs35l56_hda_from_base(struct cs35l56_base *cs35l56_base)
+{
+ return container_of(cs35l56_base, struct cs35l56_hda, base);
+}
+
+extern const struct dev_pm_ops cs35l56_hda_pm_ops;
+
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
+void cs35l56_hda_remove(struct device *dev);
+
+#endif /*__CS35L56_HDA_H__*/
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c
new file mode 100644
index 000000000000..1072f17385ac
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// CS35L56 HDA audio driver I2C binding
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "cs35l56_hda.h"
+
+static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
+{
+ const struct i2c_device_id *id = i2c_client_get_device_id(clt);
+ struct cs35l56_hda *cs35l56;
+ int ret;
+
+ cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL);
+ if (!cs35l56)
+ return -ENOMEM;
+
+ cs35l56->base.dev = &clt->dev;
+
+#ifdef CS35L56_WAKE_HOLD_TIME_US
+ cs35l56->base.can_hibernate = true;
+#endif
+
+ cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
+ dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, clt->addr);
+ if (ret)
+ return ret;
+ ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
+ if (ret < 0)
+ cs35l56_hda_remove(cs35l56->base.dev);
+
+ return ret;
+}
+
+static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
+{
+ cs35l56_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
+ { "cs35l54-hda", 0x3554 },
+ { "cs35l56-hda", 0x3556 },
+ { "cs35l57-hda", 0x3557 },
+ {}
+};
+
+static const struct acpi_device_id cs35l56_acpi_hda_match[] = {
+ { "CSC3554", 0 },
+ { "CSC3556", 0 },
+ { "CSC3557", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match);
+
+static struct i2c_driver cs35l56_hda_i2c_driver = {
+ .driver = {
+ .name = "cs35l56-hda",
+ .acpi_match_table = cs35l56_acpi_hda_match,
+ .pm = &cs35l56_hda_pm_ops,
+ },
+ .id_table = cs35l56_hda_i2c_id,
+ .probe = cs35l56_hda_i2c_probe,
+ .remove = cs35l56_hda_i2c_remove,
+};
+module_i2c_driver(cs35l56_hda_i2c_driver);
+
+MODULE_DESCRIPTION("HDA CS35L56 I2C driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c
new file mode 100644
index 000000000000..f802c83c57b4
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// CS35L56 HDA audio driver SPI binding
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "cs35l56_hda.h"
+
+static int cs35l56_hda_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct cs35l56_hda *cs35l56;
+ int ret;
+
+ cs35l56 = devm_kzalloc(&spi->dev, sizeof(*cs35l56), GFP_KERNEL);
+ if (!cs35l56)
+ 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;
+#endif
+
+ cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
+ dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, spi_get_chipselect(spi, 0));
+ if (ret)
+ return ret;
+ ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
+ if (ret < 0)
+ cs35l56_hda_remove(cs35l56->base.dev);
+
+ return ret;
+}
+
+static void cs35l56_hda_spi_remove(struct spi_device *spi)
+{
+ cs35l56_hda_remove(&spi->dev);
+}
+
+static const struct spi_device_id cs35l56_hda_spi_id[] = {
+ { "cs35l54-hda", 0x3554 },
+ { "cs35l56-hda", 0x3556 },
+ { "cs35l57-hda", 0x3557 },
+ {}
+};
+
+static const struct acpi_device_id cs35l56_acpi_hda_match[] = {
+ { "CSC3554", 0 },
+ { "CSC3556", 0 },
+ { "CSC3557", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match);
+
+static struct spi_driver cs35l56_hda_spi_driver = {
+ .driver = {
+ .name = "cs35l56-hda",
+ .acpi_match_table = cs35l56_acpi_hda_match,
+ .pm = &cs35l56_hda_pm_ops,
+ },
+ .id_table = cs35l56_hda_spi_id,
+ .probe = cs35l56_hda_spi_probe,
+ .remove = cs35l56_hda_spi_remove,
+};
+module_spi_driver(cs35l56_hda_spi_driver);
+
+MODULE_DESCRIPTION("HDA CS35L56 SPI driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/hda_component.c b/sound/hda/codecs/side-codecs/hda_component.c
new file mode 100644
index 000000000000..8a2a200600a7
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/hda_component.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio Component Binding Interface
+ *
+ * Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/acpi.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/hda_codec.h>
+#include "hda_component.h"
+#include "hda_local.h"
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component_parent *parent,
+ acpi_handle handle, u32 event, void *data)
+{
+ struct hda_component *comp;
+ int i;
+
+ guard(mutex)(&parent->mutex);
+ for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+ comp = hda_component_from_index(parent, i);
+ if (comp->dev && comp->acpi_notify)
+ comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, "SND_HDA_SCODEC_COMPONENT");
+
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component_parent *parent,
+ acpi_notify_handler handler, void *data)
+{
+ bool support_notifications = false;
+ struct acpi_device *adev;
+ struct hda_component *comp;
+ int ret;
+ int i;
+
+ adev = parent->comps[0].adev;
+ if (!acpi_device_handle(adev))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+ comp = hda_component_from_index(parent, i);
+ support_notifications = support_notifications ||
+ comp->acpi_notifications_supported;
+ }
+
+ if (support_notifications) {
+ ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
+ handler, data);
+ if (ret < 0) {
+ codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
+ return 0;
+ }
+
+ codec_dbg(cdc, "Notify handler installed\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT");
+
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component_parent *parent,
+ acpi_notify_handler handler)
+{
+ struct acpi_device *adev;
+ int ret;
+
+ adev = parent->comps[0].adev;
+ if (!acpi_device_handle(adev))
+ return;
+
+ ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, handler);
+ if (ret < 0)
+ codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT");
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action)
+{
+ struct hda_component *comp;
+ int i;
+
+ guard(mutex)(&parent->mutex);
+ for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+ comp = hda_component_from_index(parent, i);
+ if (comp->dev && comp->pre_playback_hook)
+ comp->pre_playback_hook(comp->dev, action);
+ }
+ for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+ comp = hda_component_from_index(parent, i);
+ if (comp->dev && comp->playback_hook)
+ comp->playback_hook(comp->dev, action);
+ }
+ for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+ comp = hda_component_from_index(parent, i);
+ if (comp->dev && comp->post_playback_hook)
+ comp->post_playback_hook(comp->dev, action);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, "SND_HDA_SCODEC_COMPONENT");
+
+struct hda_scodec_match {
+ const char *bus;
+ const char *hid;
+ const char *match_str;
+ int index;
+};
+
+/* match the device name in a slightly relaxed manner */
+static int hda_comp_match_dev_name(struct device *dev, void *data)
+{
+ struct hda_scodec_match *p = data;
+ const char *d = dev_name(dev);
+ int n = strlen(p->bus);
+ char tmp[32];
+
+ /* check the bus name */
+ if (strncmp(d, p->bus, n))
+ return 0;
+ /* skip the bus number */
+ if (isdigit(d[n]))
+ n++;
+ /* the rest must be exact matching */
+ snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index);
+ return !strcmp(d + n, tmp);
+}
+
+int hda_component_manager_bind(struct hda_codec *cdc,
+ struct hda_component_parent *parent)
+{
+ /* Init shared and component specific data */
+ memset(parent->comps, 0, sizeof(parent->comps));
+
+ guard(mutex)(&parent->mutex);
+ return component_bind_all(hda_codec_dev(cdc), parent);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, "SND_HDA_SCODEC_COMPONENT");
+
+int hda_component_manager_init(struct hda_codec *cdc,
+ struct hda_component_parent *parent, int count,
+ const char *bus, const char *hid,
+ const char *match_str,
+ const struct component_master_ops *ops)
+{
+ struct device *dev = hda_codec_dev(cdc);
+ struct component_match *match = NULL;
+ struct hda_scodec_match *sm;
+ int ret, i;
+
+ if (parent->codec) {
+ codec_err(cdc, "Component binding already created (SSID: %x)\n",
+ cdc->core.subsystem_id);
+ return -EINVAL;
+ }
+ parent->codec = cdc;
+
+ mutex_init(&parent->mutex);
+
+ for (i = 0; i < count; i++) {
+ sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL);
+ if (!sm)
+ return -ENOMEM;
+
+ sm->bus = bus;
+ sm->hid = hid;
+ sm->match_str = match_str;
+ sm->index = i;
+ component_match_add(dev, &match, hda_comp_match_dev_name, sm);
+ if (IS_ERR(match)) {
+ codec_err(cdc, "Fail to add component %ld\n", PTR_ERR(match));
+ return PTR_ERR(match);
+ }
+ }
+
+ ret = component_master_add_with_match(dev, ops, match);
+ if (ret)
+ codec_err(cdc, "Fail to register component aggregator %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, "SND_HDA_SCODEC_COMPONENT");
+
+void hda_component_manager_free(struct hda_component_parent *parent,
+ const struct component_master_ops *ops)
+{
+ struct device *dev;
+
+ if (!parent->codec)
+ return;
+
+ dev = hda_codec_dev(parent->codec);
+
+ component_master_del(dev, ops);
+
+ parent->codec = NULL;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, "SND_HDA_SCODEC_COMPONENT");
+
+MODULE_DESCRIPTION("HD Audio component binding library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/hda_component.h b/sound/hda/codecs/side-codecs/hda_component.h
new file mode 100644
index 000000000000..075137a73bae
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/hda_component.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HD audio Component Binding Interface
+ *
+ * Copyright (C) 2021 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __HDA_COMPONENT_H__
+#define __HDA_COMPONENT_H__
+
+#include <linux/acpi.h>
+#include <linux/component.h>
+#include <linux/mutex.h>
+#include <sound/hda_codec.h>
+
+#define HDA_MAX_COMPONENTS 4
+#define HDA_MAX_NAME_SIZE 50
+
+struct hda_component {
+ struct device *dev;
+ char name[HDA_MAX_NAME_SIZE];
+ struct acpi_device *adev;
+ bool acpi_notifications_supported;
+ void (*acpi_notify)(acpi_handle handle, u32 event, struct device *dev);
+ void (*pre_playback_hook)(struct device *dev, int action);
+ void (*playback_hook)(struct device *dev, int action);
+ void (*post_playback_hook)(struct device *dev, int action);
+};
+
+struct hda_component_parent {
+ struct mutex mutex;
+ struct hda_codec *codec;
+ struct hda_component comps[HDA_MAX_COMPONENTS];
+};
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component_parent *parent,
+ acpi_handle handle, u32 event, void *data);
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component_parent *parent,
+ acpi_notify_handler handler, void *data);
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component_parent *parent,
+ acpi_notify_handler handler);
+#else
+static inline void hda_component_acpi_device_notify(struct hda_component_parent *parent,
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+}
+
+static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component_parent *parent,
+ acpi_notify_handler handler,
+ void *data)
+
+{
+ return 0;
+}
+
+static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component_parent *parent,
+ acpi_notify_handler handler)
+{
+}
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action);
+
+int hda_component_manager_init(struct hda_codec *cdc,
+ struct hda_component_parent *parent, int count,
+ const char *bus, const char *hid,
+ const char *match_str,
+ const struct component_master_ops *ops);
+
+void hda_component_manager_free(struct hda_component_parent *parent,
+ const struct component_master_ops *ops);
+
+int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent);
+
+static inline struct hda_component *hda_component_from_index(struct hda_component_parent *parent,
+ int index)
+{
+ if (!parent)
+ return NULL;
+
+ if (index < 0 || index >= ARRAY_SIZE(parent->comps))
+ return NULL;
+
+ return &parent->comps[index];
+}
+
+static inline void hda_component_manager_unbind(struct hda_codec *cdc,
+ struct hda_component_parent *parent)
+{
+ guard(mutex)(&parent->mutex);
+ component_unbind_all(hda_codec_dev(cdc), parent);
+}
+
+#endif /* ifndef __HDA_COMPONENT_H__ */
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda.c b/sound/hda/codecs/side-codecs/tas2781_hda.c
new file mode 100644
index 000000000000..96e6d82dc69e
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/tas2781_hda.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA Shared Lib for I2C&SPI driver
+//
+// Copyright 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/component.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+
+#include "tas2781_hda.h"
+
+#define CALIBRATION_DATA_AREA_NUM 2
+
+const efi_guid_t tasdev_fct_efi_guid[] = {
+ /* DELL */
+ EFI_GUID(0xcc92382d, 0x6337, 0x41cb, 0xa8, 0x8b, 0x8e, 0xce, 0x74,
+ 0x91, 0xea, 0x9f),
+ /* HP */
+ EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a,
+ 0xa3, 0x5d, 0xb3),
+ /* LENOVO & OTHERS */
+ EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, 0x43, 0xa3, 0xf4,
+ 0x31, 0x0a, 0x92),
+};
+EXPORT_SYMBOL_NS_GPL(tasdev_fct_efi_guid, "SND_HDA_SCODEC_TAS2781");
+
+/*
+ * The order of calibrated-data writing function is a bit different from the
+ * order in UEFI. Here is the conversion to match the order of calibrated-data
+ * writing function.
+ */
+static void cali_cnv(unsigned char *data, unsigned int base, int offset)
+{
+ struct cali_reg reg_data;
+
+ memcpy(&reg_data, &data[base], sizeof(reg_data));
+ /* the data order has to be swapped between r0_low_reg and inv0_reg */
+ swap(reg_data.r0_low_reg, reg_data.invr0_reg);
+
+ cpu_to_be32_array((__force __be32 *)(data + offset + 1),
+ (u32 *)&reg_data, TASDEV_CALIB_N);
+}
+
+static void tas2781_apply_calib(struct tasdevice_priv *p)
+{
+ struct calidata *cali_data = &p->cali_data;
+ struct cali_reg *r = &cali_data->cali_reg_array;
+ unsigned char *data = cali_data->data;
+ unsigned int *tmp_val = (unsigned int *)data;
+ unsigned int cali_reg[TASDEV_CALIB_N] = {
+ TASDEVICE_REG(0, 0x17, 0x74),
+ TASDEVICE_REG(0, 0x18, 0x0c),
+ TASDEVICE_REG(0, 0x18, 0x14),
+ TASDEVICE_REG(0, 0x13, 0x70),
+ TASDEVICE_REG(0, 0x18, 0x7c),
+ };
+ unsigned int crc, oft, node_num;
+ unsigned char *buf;
+ int i, j, k, l;
+
+ 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)
+ * Data-Group-Sum (4 bytes)
+ * TimeStamp of Calibration (4 bytes)
+ * for (i = 0; i < Data-Group-Sum; i++) {
+ * if (Data type != 0x80) (4 bytes)
+ * Calibrated Data of Device #i (20 bytes)
+ * else
+ * Calibration registers address (5*4 = 20 bytes)
+ * # V2: No reg addr in data grp section.
+ * # V3: Normally the last grp is the reg addr.
+ * }
+ * 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]) {
+ cali_data->total_sz = 0;
+ dev_err(p->dev, "%s: CRC error\n", __func__);
+ return;
+ }
+ node_num = tmp_val[1];
+
+ for (j = 0, k = 0; j < node_num; j++) {
+ oft = j * 6 + 3;
+ if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
+ for (i = 0; i < TASDEV_CALIB_N; i++) {
+ buf = &data[(oft + i + 1) * 4];
+ cali_reg[i] = TASDEVICE_REG(buf[1],
+ buf[2], buf[3]);
+ }
+ } else {
+ l = j * (cali_data->cali_dat_sz_per_dev + 1);
+ if (k >= p->ndev || l > oft * 4) {
+ dev_err(p->dev, "%s: dev sum error\n",
+ __func__);
+ cali_data->total_sz = 0;
+ return;
+ }
+
+ data[l] = k;
+ oft++;
+ cali_cnv(data, 4 * oft, l);
+ k++;
+ }
+ }
+ } 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]) {
+ cali_data->total_sz = 0;
+ dev_err(p->dev, "%s: V1 CRC error\n", __func__);
+ return;
+ }
+
+ for (j = p->ndev - 1; j >= 0; j--) {
+ l = j * (cali_data->cali_dat_sz_per_dev + 1);
+ cali_cnv(data, cali_data->cali_dat_sz_per_dev * j, l);
+ data[l] = j;
+ }
+ }
+
+ if (p->dspbin_typ == TASDEV_BASIC) {
+ r->r0_reg = cali_reg[0];
+ r->invr0_reg = cali_reg[1];
+ r->r0_low_reg = cali_reg[2];
+ r->pow_reg = cali_reg[3];
+ r->tlimit_reg = cali_reg[4];
+ }
+
+ p->is_user_space_calidata = true;
+ cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
+}
+
+/*
+ * Update the calibration data, including speaker impedance, f0, etc,
+ * into algo. Calibrate data is done by manufacturer in the factory.
+ * The data is 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.
+ */
+int tas2781_save_calibration(struct tas2781_hda *hda)
+{
+ /*
+ * GUID was used for data access in BIOS, it was provided by board
+ * manufactory.
+ */
+ efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
+ /*
+ * Some devices save the calibrated data into L"CALI_DATA",
+ * and others into L"SmartAmpCalibrationData".
+ */
+ static efi_char16_t *efi_name[CALIBRATION_DATA_AREA_NUM] = {
+ L"CALI_DATA",
+ L"SmartAmpCalibrationData",
+ };
+ struct tasdevice_priv *p = hda->priv;
+ struct calidata *cali_data = &p->cali_data;
+ unsigned long total_sz = 0;
+ unsigned int attr, size;
+ unsigned char *data;
+ efi_status_t status;
+ int i;
+
+ if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
+ dev_err(p->dev, "%s: NO EFI FOUND!\n", __func__);
+ return -EINVAL;
+ }
+
+ if (hda->catlog_id < LENOVO)
+ efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
+
+ cali_data->cali_dat_sz_per_dev = 20;
+ size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
+ for (i = 0; i < CALIBRATION_DATA_AREA_NUM; i++) {
+ /* Get real size of UEFI variable */
+ status = efi.get_variable(efi_name[i], &efi_guid, &attr,
+ &total_sz, NULL);
+ cali_data->total_sz = total_sz > size ? total_sz : size;
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ /* Allocate data buffer of data_size bytes */
+ data = cali_data->data = devm_kzalloc(p->dev,
+ cali_data->total_sz, GFP_KERNEL);
+ if (!data) {
+ status = -ENOMEM;
+ continue;
+ }
+ /* Get variable contents into buffer */
+ status = efi.get_variable(efi_name[i], &efi_guid,
+ &attr, &cali_data->total_sz, data);
+ }
+ /* Check whether get the calibrated data */
+ if (status == EFI_SUCCESS)
+ break;
+ }
+
+ if (status != EFI_SUCCESS) {
+ cali_data->total_sz = 0;
+ return status;
+ }
+
+ tas2781_apply_calib(p);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
+
+void tas2781_hda_remove(struct device *dev,
+ const struct component_ops *ops)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ component_del(tas_hda->dev, ops);
+
+ pm_runtime_get_sync(tas_hda->dev);
+ pm_runtime_disable(tas_hda->dev);
+
+ pm_runtime_put_noidle(tas_hda->dev);
+
+ tasdevice_remove(tas_hda->priv);
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
+
+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;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
+
+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;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_config(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = tas_fw->nr_configurations - 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
+
+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;
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+ kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
+
+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 profile_id = ucontrol->value.integer.value[0];
+ int max = tas_priv->rcabin.ncfgs - 1;
+ int val, ret = 0;
+
+ val = clamp(profile_id, 0, max);
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+ kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
+
+ if (tas_priv->rcabin.profile_cfg_id != val) {
+ tas_priv->rcabin.profile_cfg_id = val;
+ ret = 1;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
+
+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;
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+ kcontrol->id.name, tas_priv->cur_prog);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_program_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+ int nr_program = ucontrol->value.integer.value[0];
+ int max = tas_fw->nr_programs - 1;
+ int val, ret = 0;
+
+ val = clamp(nr_program, 0, max);
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+ kcontrol->id.name, tas_priv->cur_prog, val);
+
+ if (tas_priv->cur_prog != val) {
+ tas_priv->cur_prog = val;
+ ret = 1;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
+
+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;
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+ kcontrol->id.name, tas_priv->cur_conf);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+ int nr_config = ucontrol->value.integer.value[0];
+ int max = tas_fw->nr_configurations - 1;
+ int val, ret = 0;
+
+ val = clamp(nr_config, 0, max);
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+ kcontrol->id.name, tas_priv->cur_conf, val);
+
+ if (tas_priv->cur_conf != val) {
+ tas_priv->cur_conf = val;
+ ret = 1;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
+
+MODULE_DESCRIPTION("TAS2781 HDA Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda.h b/sound/hda/codecs/side-codecs/tas2781_hda.h
new file mode 100644
index 000000000000..66188909a0bb
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/tas2781_hda.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * HDA audio driver for Texas Instruments TAS2781 smart amp
+ *
+ * Copyright (C) 2025 Texas Instruments, Inc.
+ */
+#ifndef __TAS2781_HDA_H__
+#define __TAS2781_HDA_H__
+
+#include <sound/asound.h>
+
+/* Flag of calibration registers address. */
+#define TASDEV_UEFI_CALI_REG_ADDR_FLG BIT(7)
+
+#define TASDEV_CALIB_N 5
+
+/*
+ * 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, \
+}
+
+enum device_catlog_id {
+ DELL = 0,
+ HP,
+ LENOVO,
+ OTHERS
+};
+
+struct tas2781_hda {
+ struct device *dev;
+ struct tasdevice_priv *priv;
+ struct snd_kcontrol *dsp_prog_ctl;
+ struct snd_kcontrol *dsp_conf_ctl;
+ struct snd_kcontrol *prof_ctl;
+ enum device_catlog_id catlog_id;
+ void *hda_priv;
+};
+
+extern const efi_guid_t tasdev_fct_efi_guid[];
+
+int tas2781_save_calibration(struct tas2781_hda *p);
+void tas2781_hda_remove(struct device *dev,
+ const struct component_ops *ops);
+int tasdevice_info_profile(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uctl);
+int tasdevice_info_programs(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uctl);
+int tasdevice_info_config(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uctl);
+int tasdevice_set_profile_id(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl);
+int tasdevice_get_profile_id(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl);
+int tasdevice_program_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl);
+int tasdevice_program_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl);
+int tasdevice_config_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl);
+int tasdevice_config_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl);
+
+#endif
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
new file mode 100644
index 000000000000..c8619995b1d7
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -0,0 +1,834 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA I2C driver
+//
+// Copyright 2023 - 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+// Current maintainer: Baojun Xu <baojun.xu@ti.com>
+
+#include <linux/unaligned.h>
+#include <linux/acpi.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pci_ids.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/hda_codec.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+#include <sound/tas2781-comlib-i2c.h>
+#include <sound/tlv.h>
+#include <sound/tas2770-tlv.h>
+#include <sound/tas2781-tlv.h>
+#include <sound/tas5825-tlv.h>
+
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_component.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "tas2781_hda.h"
+
+#define TAS2563_CAL_VAR_NAME_MAX 16
+#define TAS2563_CAL_ARRAY_SIZE 80
+#define TAS2563_CAL_DATA_SIZE 4
+#define TAS2563_MAX_CHANNELS 4
+#define TAS2563_CAL_CH_SIZE 20
+
+#define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48)
+#define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c)
+#define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40)
+#define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14)
+#define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34)
+
+enum device_chip_id {
+ HDA_TAS2563,
+ HDA_TAS2770,
+ HDA_TAS2781,
+ HDA_TAS5825,
+ HDA_OTHERS
+};
+
+struct tas2781_hda_i2c_priv {
+ struct snd_kcontrol *snd_ctls[2];
+ int (*save_calibration)(struct tas2781_hda *h);
+
+ int hda_chip_id;
+};
+
+static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
+{
+ struct tasdevice_priv *tas_priv = data;
+ struct acpi_resource_i2c_serialbus *sb;
+
+ if (i2c_acpi_get_i2c_resource(ares, &sb)) {
+ if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS &&
+ sb->slave_address != tas_priv->global_addr) {
+ tas_priv->tasdevice[tas_priv->ndev].dev_addr =
+ (unsigned int)sb->slave_address;
+ tas_priv->ndev++;
+ }
+ }
+ return 1;
+}
+
+static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };
+
+static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
+ { "speakerid-gpios", &speakerid_gpios, 1 },
+ { }
+};
+
+static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
+{
+ struct gpio_desc *speaker_id;
+ struct acpi_device *adev;
+ struct device *physdev;
+ LIST_HEAD(resources);
+ const char *sub;
+ uint32_t subid;
+ int ret;
+
+ adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+ if (!adev) {
+ dev_err(p->dev,
+ "Failed to find an ACPI device for %s\n", hid);
+ return -ENODEV;
+ }
+
+ physdev = get_device(acpi_get_first_physical_node(adev));
+ ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
+ if (ret < 0) {
+ dev_err(p->dev, "Failed to get ACPI resource.\n");
+ goto err;
+ }
+ sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+ if (IS_ERR(sub)) {
+ /* No subsys id in older tas2563 projects. */
+ if (!strncmp(hid, "INT8866", sizeof("INT8866")))
+ goto end_2563;
+ dev_err(p->dev, "Failed to get SUBSYS ID.\n");
+ ret = PTR_ERR(sub);
+ goto err;
+ }
+ /* Speaker id was needed for ASUS projects. */
+ ret = kstrtou32(sub, 16, &subid);
+ if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
+ ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
+ if (ret < 0) {
+ dev_err(p->dev, "Failed to add driver gpio %d.\n",
+ ret);
+ p->speaker_id = -1;
+ goto end_2563;
+ }
+
+ speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev),
+ "speakerid", 0, GPIOD_IN, NULL);
+ if (!IS_ERR(speaker_id)) {
+ p->speaker_id = gpiod_get_value_cansleep(speaker_id);
+ dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n",
+ p->speaker_id);
+ gpiod_put(speaker_id);
+ } else {
+ p->speaker_id = -1;
+ ret = PTR_ERR(speaker_id);
+ dev_err(p->dev, "Get speaker id gpio failed %d.\n",
+ ret);
+ }
+
+ acpi_dev_remove_driver_gpios(adev);
+ } else {
+ p->speaker_id = -1;
+ }
+
+end_2563:
+ acpi_dev_free_resource_list(&resources);
+ strscpy(p->dev_name, hid, sizeof(p->dev_name));
+ put_device(physdev);
+ acpi_dev_put(adev);
+
+ return 0;
+
+err:
+ dev_err(p->dev, "read acpi error, ret: %d\n", ret);
+ put_device(physdev);
+ acpi_dev_put(adev);
+
+ return ret;
+}
+
+static void tas2781_hda_playback_hook(struct device *dev, int action)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action);
+ switch (action) {
+ case HDA_GEN_PCM_ACT_OPEN:
+ pm_runtime_get_sync(dev);
+ scoped_guard(mutex, &tas_hda->priv->codec_lock) {
+ tasdevice_tuning_switch(tas_hda->priv, 0);
+ tas_hda->priv->playback_started = true;
+ }
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
+ scoped_guard(mutex, &tas_hda->priv->codec_lock) {
+ tasdevice_tuning_switch(tas_hda->priv, 1);
+ tas_hda->priv->playback_started = false;
+ }
+
+ pm_runtime_put_autosuspend(dev);
+ break;
+ default:
+ break;
+ }
+}
+
+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;
+ int ret;
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",
+ __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
+
+ return ret;
+}
+
+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;
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",
+ __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
+
+ /* The check of the given value is in tasdevice_amp_putvol. */
+ return tasdevice_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);
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
+ __func__, kcontrol->id.name, 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];
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
+ __func__, kcontrol->id.name,
+ tas_priv->force_fwload_status, val);
+
+ if (tas_priv->force_fwload_status == val)
+ change = false;
+ else {
+ change = true;
+ tas_priv->force_fwload_status = val;
+ }
+
+ return change;
+}
+
+static const struct snd_kcontrol_new tas2770_snd_controls[] = {
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2770_AMP_LEVEL,
+ 0, 0, 20, 0, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas2770_amp_tlv),
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2770_DVC_LEVEL,
+ 0, 0, 200, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas2770_dvc_tlv),
+};
+
+static const struct snd_kcontrol_new tas2781_snd_controls[] = {
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL,
+ 1, 0, 20, 0, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas2781_amp_tlv),
+ ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas5825_snd_controls[] = {
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL,
+ 0, 0, 31, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_amp_tlv),
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL,
+ 0, 0, 254, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_dvc_tlv),
+ ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+ tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tasdevice_prof_ctrl = {
+ .name = "Speaker Profile Id",
+ .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 tasdevice_dsp_prog_ctrl = {
+ .name = "Speaker Program Id",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_programs,
+ .get = tasdevice_program_get,
+ .put = tasdevice_program_put,
+};
+
+static const struct snd_kcontrol_new tasdevice_dsp_conf_ctrl = {
+ .name = "Speaker Config Id",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_config,
+ .get = tasdevice_config_get,
+ .put = tasdevice_config_put,
+};
+
+static int tas2563_save_calibration(struct tas2781_hda *h)
+{
+ efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
+ char *vars[TASDEV_CALIB_N] = {
+ "R0_%d", "R0_Low_%d", "InvR0_%d", "Power_%d", "TLim_%d"
+ };
+ efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX];
+ unsigned long max_size = TAS2563_CAL_DATA_SIZE;
+ unsigned char var8[TAS2563_CAL_VAR_NAME_MAX];
+ struct tasdevice_priv *p = h->priv;
+ struct calidata *cd = &p->cali_data;
+ struct cali_reg *r = &cd->cali_reg_array;
+ unsigned int offset = 0;
+ unsigned char *data;
+ __be32 bedata;
+ efi_status_t status;
+ unsigned int attr;
+ int ret, i, j, k;
+
+ if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
+ dev_err(p->dev, "%s: NO EFI FOUND!\n", __func__);
+ return -EINVAL;
+ }
+
+ cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N;
+
+ /* extra byte for each device is the device number */
+ cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev;
+ data = cd->data = devm_kzalloc(p->dev, cd->total_sz,
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (i = 0; i < p->ndev; ++i) {
+ data[offset] = i;
+ offset++;
+ for (j = 0; j < TASDEV_CALIB_N; ++j) {
+ /* EFI name for calibration started with 1, not 0 */
+ ret = snprintf(var8, sizeof(var8), vars[j], i + 1);
+ if (ret < 0 || ret >= sizeof(var8) - 1) {
+ dev_err(p->dev, "%s: Read %s failed\n",
+ __func__, var8);
+ return -EINVAL;
+ }
+ /*
+ * Our variable names are ASCII by construction, but
+ * EFI names are wide chars. Convert and zero-pad.
+ */
+ memset(efi_name, 0, sizeof(efi_name));
+ for (k = 0; k < sizeof(var8) && var8[k]; k++)
+ efi_name[k] = var8[k];
+ status = efi.get_variable(efi_name,
+ &efi_guid, &attr, &max_size,
+ &data[offset]);
+ if (status != EFI_SUCCESS ||
+ max_size != TAS2563_CAL_DATA_SIZE) {
+ dev_warn(p->dev,
+ "Dev %d: Caldat[%d] read failed %ld\n",
+ i, j, status);
+ return -EINVAL;
+ }
+ bedata = cpu_to_be32(*(uint32_t *)&data[offset]);
+ memcpy(&data[offset], &bedata, sizeof(bedata));
+ offset += TAS2563_CAL_DATA_SIZE;
+ }
+ }
+
+ if (cd->total_sz != offset) {
+ dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) mismatch\n",
+ __func__, cd->total_sz, offset);
+ return -EINVAL;
+ }
+
+ r->r0_reg = TAS2563_CAL_R0;
+ r->invr0_reg = TAS2563_CAL_INVR0;
+ r->r0_low_reg = TAS2563_CAL_R0_LOW;
+ r->pow_reg = TAS2563_CAL_POWER;
+ r->tlimit_reg = TAS2563_CAL_TLIM;
+
+ /*
+ * TAS2781_FMWLIB supports two solutions of calibrated data. One is
+ * from the driver itself: driver reads the calibrated files directly
+ * during probe; The other from user space: during init of audio hal,
+ * the audio hal will pass the calibrated data via kcontrol interface.
+ * Driver will store this data in "struct calidata" for use. For hda
+ * device, calibrated data are usunally saved into UEFI. So Hda side
+ * codec driver use the mixture of these two solutions, driver reads
+ * the data from UEFI, then store this data in "struct calidata" for
+ * use.
+ */
+ p->is_user_space_calidata = true;
+
+ return 0;
+}
+
+static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
+{
+ struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
+ 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(hda_priv->snd_ctls) - 1; i >= 0; i--)
+ snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]);
+
+ snd_ctl_remove(codec->card, tas_hda->prof_ctl);
+}
+
+static void tasdev_add_kcontrols(struct tasdevice_priv *tas_priv,
+ struct snd_kcontrol **ctls, struct hda_codec *codec,
+ const struct snd_kcontrol_new *tas_snd_ctrls, int num_ctls)
+{
+ int i, ret;
+
+ for (i = 0; i < num_ctls; i++) {
+ ctls[i] = snd_ctl_new1(
+ &tas_snd_ctrls[i], tas_priv);
+ ret = snd_ctl_add(codec->card, ctls[i]);
+ if (ret) {
+ dev_err(tas_priv->dev,
+ "Failed to add KControl %s = %d\n",
+ tas_snd_ctrls[i].name, ret);
+ break;
+ }
+ }
+}
+
+static void tasdevice_dspfw_init(void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
+ struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
+ struct hda_codec *codec = tas_priv->codec;
+ int ret;
+
+ tasdevice_dsp_remove(tas_priv);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+ if (tas_priv->speaker_id >= 0) {
+ snprintf(tas_priv->coef_binaryname,
+ sizeof(tas_priv->coef_binaryname),
+ "TAS2XXX%04X%d.bin",
+ lower_16_bits(codec->core.subsystem_id),
+ tas_priv->speaker_id);
+ } else {
+ snprintf(tas_priv->coef_binaryname,
+ sizeof(tas_priv->coef_binaryname),
+ "TAS2XXX%04X.bin",
+ lower_16_bits(codec->core.subsystem_id));
+ }
+ ret = tasdevice_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;
+ return;
+ }
+ tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_prog_ctl, codec,
+ &tasdevice_dsp_prog_ctrl, 1);
+ tasdev_add_kcontrols(tas_priv, &tas_hda->dsp_conf_ctl, codec,
+ &tasdevice_dsp_conf_ctrl, 1);
+
+ tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+ tasdevice_prmg_load(tas_priv, 0);
+ if (tas_priv->fmw->nr_programs > 0)
+ tas_priv->cur_prog = 0;
+ if (tas_priv->fmw->nr_configurations > 0)
+ tas_priv->cur_conf = 0;
+
+ /* Init common setting for different audio profiles */
+ if (tas_priv->rcabin.init_profile_id >= 0)
+ tasdevice_select_cfg_blk(tas_priv,
+ tas_priv->rcabin.init_profile_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+
+ /* If calibrated data occurs error, dsp will still works with default
+ * calibrated data inside algo.
+ */
+ hda_priv->save_calibration(tas_hda);
+}
+
+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 tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
+ struct hda_codec *codec = tas_priv->codec;
+ int ret;
+
+ pm_runtime_get_sync(tas_priv->dev);
+ mutex_lock(&tas_priv->codec_lock);
+
+ ret = tasdevice_rca_parser(tas_priv, fmw);
+ if (ret)
+ goto out;
+
+ tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
+ tasdev_add_kcontrols(tas_priv, &tas_hda->prof_ctl, codec,
+ &tasdevice_prof_ctrl, 1);
+
+ switch (hda_priv->hda_chip_id) {
+ case HDA_TAS2770:
+ tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,
+ &tas2770_snd_controls[0],
+ ARRAY_SIZE(tas2770_snd_controls));
+ break;
+ case HDA_TAS2781:
+ tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,
+ &tas2781_snd_controls[0],
+ ARRAY_SIZE(tas2781_snd_controls));
+ tasdevice_dspfw_init(context);
+ break;
+ case HDA_TAS5825:
+ tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,
+ &tas5825_snd_controls[0],
+ ARRAY_SIZE(tas5825_snd_controls));
+ tasdevice_dspfw_init(context);
+ break;
+ case HDA_TAS2563:
+ tasdevice_dspfw_init(context);
+ break;
+ default:
+ break;
+ }
+
+out:
+ mutex_unlock(&tas_hda->priv->codec_lock);
+ release_firmware(fmw);
+ pm_runtime_put_autosuspend(tas_hda->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;
+ unsigned int subid;
+ int ret;
+
+ comp = hda_component_from_index(parent, tas_hda->priv->index);
+ if (!comp)
+ return -EINVAL;
+
+ if (comp->dev)
+ return -EBUSY;
+
+ codec = parent->codec;
+ subid = codec->core.subsystem_id >> 16;
+
+ switch (subid) {
+ case 0x1028:
+ tas_hda->catlog_id = DELL;
+ break;
+ default:
+ tas_hda->catlog_id = LENOVO;
+ break;
+ }
+
+ pm_runtime_get_sync(dev);
+
+ comp->dev = dev;
+
+ strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+ ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);
+ if (!ret)
+ comp->playback_hook = tas2781_hda_playback_hook;
+
+ 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_config_info_remove(tas_hda->priv);
+ tasdevice_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 int tas2781_hda_i2c_probe(struct i2c_client *clt)
+{
+ struct tas2781_hda_i2c_priv *hda_priv;
+ struct tas2781_hda *tas_hda;
+ const char *device_name;
+ int ret;
+
+ tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);
+ if (!tas_hda)
+ return -ENOMEM;
+
+ hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL);
+ if (!hda_priv)
+ return -ENOMEM;
+
+ tas_hda->hda_priv = hda_priv;
+
+ dev_set_drvdata(&clt->dev, tas_hda);
+ tas_hda->dev = &clt->dev;
+
+ tas_hda->priv = tasdevice_kzalloc(clt);
+ if (!tas_hda->priv)
+ return -ENOMEM;
+
+ if (strstr(dev_name(&clt->dev), "TIAS2781")) {
+ /*
+ * TAS2781, integrated on-chip DSP with
+ * global I2C address supported.
+ */
+ device_name = "TIAS2781";
+ hda_priv->hda_chip_id = HDA_TAS2781;
+ hda_priv->save_calibration = tas2781_save_calibration;
+ tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
+ } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) {
+ /*
+ * TAS2770, has no on-chip DSP, so no calibration data
+ * required; has no global I2C address supported.
+ */
+ device_name = "TXNW2770";
+ hda_priv->hda_chip_id = HDA_TAS2770;
+ } else if (strstarts(dev_name(&clt->dev),
+ "i2c-TXNW2781:00-tas2781-hda.0")) {
+ device_name = "TXNW2781";
+ hda_priv->hda_chip_id = HDA_TAS2781;
+ hda_priv->save_calibration = tas2781_save_calibration;
+ tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
+ } else if (strstr(dev_name(&clt->dev), "INT8866")) {
+ /*
+ * TAS2563, integrated on-chip DSP with
+ * global I2C address supported.
+ */
+ device_name = "INT8866";
+ hda_priv->hda_chip_id = HDA_TAS2563;
+ hda_priv->save_calibration = tas2563_save_calibration;
+ tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
+ } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW5825")) {
+ /*
+ * TAS5825, integrated on-chip DSP without
+ * global I2C address and calibration supported.
+ */
+ device_name = "TXNW5825";
+ hda_priv->hda_chip_id = HDA_TAS5825;
+ tas_hda->priv->chip_id = TAS5825;
+ } else {
+ return -ENODEV;
+ }
+
+ tas_hda->priv->irq = clt->irq;
+ ret = tas2781_read_acpi(tas_hda->priv, device_name);
+ if (ret)
+ return dev_err_probe(tas_hda->dev, ret,
+ "Platform not supported\n");
+
+ ret = tasdevice_init(tas_hda->priv);
+ if (ret)
+ goto err;
+
+ pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000);
+ pm_runtime_use_autosuspend(tas_hda->dev);
+ pm_runtime_mark_last_busy(tas_hda->dev);
+ pm_runtime_set_active(tas_hda->dev);
+ pm_runtime_enable(tas_hda->dev);
+
+ tasdevice_reset(tas_hda->priv);
+
+ ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);
+ if (ret) {
+ dev_err(tas_hda->dev, "Register component failed: %d\n", ret);
+ pm_runtime_disable(tas_hda->dev);
+ }
+
+err:
+ if (ret)
+ tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
+ return ret;
+}
+
+static void tas2781_hda_i2c_remove(struct i2c_client *clt)
+{
+ tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
+}
+
+static int tas2781_runtime_suspend(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ dev_dbg(tas_hda->dev, "Runtime Suspend\n");
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+
+ /* The driver powers up the amplifiers at module load time.
+ * Stop the playback if it's unused.
+ */
+ if (tas_hda->priv->playback_started) {
+ tasdevice_tuning_switch(tas_hda->priv, 1);
+ tas_hda->priv->playback_started = false;
+ }
+
+ return 0;
+}
+
+static int tas2781_runtime_resume(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ dev_dbg(tas_hda->dev, "Runtime Resume\n");
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+
+ tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
+
+ return 0;
+}
+
+static int tas2781_system_suspend(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ dev_dbg(tas_hda->priv->dev, "System Suspend\n");
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+
+ /* Shutdown chip before system suspend */
+ if (tas_hda->priv->playback_started)
+ tasdevice_tuning_switch(tas_hda->priv, 1);
+
+ /*
+ * Reset GPIO may be shared, so cannot reset here.
+ * However beyond this point, amps may be powered down.
+ */
+ return 0;
+}
+
+static int tas2781_system_resume(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ int i;
+
+ dev_dbg(tas_hda->priv->dev, "System Resume\n");
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+
+ for (i = 0; i < tas_hda->priv->ndev; i++) {
+ tas_hda->priv->tasdevice[i].cur_book = -1;
+ tas_hda->priv->tasdevice[i].cur_prog = -1;
+ tas_hda->priv->tasdevice[i].cur_conf = -1;
+ }
+ tasdevice_reset(tas_hda->priv);
+ tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
+
+ /* Init common setting for different audio profiles */
+ if (tas_hda->priv->rcabin.init_profile_id >= 0)
+ tasdevice_select_cfg_blk(tas_hda->priv,
+ tas_hda->priv->rcabin.init_profile_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+
+ if (tas_hda->priv->playback_started)
+ tasdevice_tuning_switch(tas_hda->priv, 0);
+
+ return 0;
+}
+
+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 i2c_device_id tas2781_hda_i2c_id[] = {
+ { "tas2781-hda" },
+ {}
+};
+
+static const struct acpi_device_id tas2781_acpi_hda_match[] = {
+ {"INT8866", 0 },
+ {"TIAS2781", 0 },
+ {"TXNW2770", 0 },
+ {"TXNW2781", 0 },
+ {"TXNW5825", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
+
+static struct i2c_driver tas2781_hda_i2c_driver = {
+ .driver = {
+ .name = "tas2781-hda",
+ .acpi_match_table = tas2781_acpi_hda_match,
+ .pm = &tas2781_hda_pm_ops,
+ },
+ .id_table = tas2781_hda_i2c_id,
+ .probe = tas2781_hda_i2c_probe,
+ .remove = tas2781_hda_i2c_remove,
+};
+module_i2c_driver(tas2781_hda_i2c_driver);
+
+MODULE_DESCRIPTION("TAS2781 HDA Driver");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
new file mode 100644
index 000000000000..b9a55672bf15
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -0,0 +1,956 @@
+// 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/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.h>
+#include <sound/tlv.h>
+#include <sound/tas2781-tlv.h>
+
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_component.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "tas2781_hda.h"
+
+#define TASDEVICE_RANGE_MAX_SIZE (256 * 128)
+#define TASDEVICE_WIN_LEN 128
+#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ)
+/* Flag of calibration registers address. */
+#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7)
+#define TASDEV_UEFI_CALI_REG_ADDR_FLG BIT(7)
+
+/* System Reset Check Register */
+#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
+#define TAS2781_REG_CLK_CONFIG_RESET 0x19
+
+struct tas2781_hda_spi_priv {
+ struct snd_kcontrol *snd_ctls[3];
+};
+
+static const struct regmap_range_cfg tasdevice_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = TASDEVICE_RANGE_MAX_SIZE,
+ .selector_reg = TASDEVICE_PAGE_SELECT,
+ .selector_mask = GENMASK(7, 0),
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = TASDEVICE_WIN_LEN,
+ },
+};
+
+static const struct regmap_config tasdevice_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .zero_flag_mask = true,
+ .read_flag_mask = 0x01,
+ .reg_shift = -1,
+ .cache_type = REGCACHE_NONE,
+ .ranges = tasdevice_ranges,
+ .num_ranges = ARRAY_SIZE(tasdevice_ranges),
+ .max_register = TASDEVICE_RANGE_MAX_SIZE,
+};
+
+static int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned int *val)
+{
+ int 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 = tasdevice_dev_bulk_read(tas_priv, chn, reg,
+ data, sizeof(data));
+ *val = data[1];
+ } else {
+ ret = tasdevice_dev_read(tas_priv, chn, reg, val);
+ }
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ int 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 buf[TASDEVICE_WIN_LEN + 1];
+
+ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
+ buf, len + 1);
+ memcpy(data, buf + 1, len);
+ } else {
+ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, data, len);
+ }
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned int mask,
+ unsigned int value)
+{
+ 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_dev_read(tas_priv, chn, reg, &val);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = tasdevice_dev_write(tas_priv, chn, 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 int tasdevice_spi_change_chn_book(struct tasdevice_priv *p,
+ unsigned short chn, int book)
+{
+ int ret = 0;
+
+ if (chn == p->index) {
+ struct tasdevice *tasdev = &p->tasdevice[chn];
+ struct regmap *map = p->regmap;
+
+ if (tasdev->cur_book != book) {
+ ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book);
+ if (ret < 0)
+ dev_err(p->dev, "%s, E=%d\n", __func__, ret);
+ else
+ tasdev->cur_book = book;
+ }
+ } else {
+ ret = -EXDEV;
+ dev_dbg(p->dev, "Not error, %s ignore channel(%d)\n",
+ __func__, chn);
+ }
+
+ 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);
+ } else {
+ ret = tasdevice_dev_write(tas_dev, tas_dev->index,
+ TASDEVICE_REG_SWRESET, TASDEVICE_REG_SWRESET_RESET);
+ if (ret < 0) {
+ dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret);
+ return;
+ }
+ 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->ndev);
+ 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->tasdevice[tas_priv->index].cur_book = -1;
+ tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
+ tas_priv->tasdevice[tas_priv->index].cur_prog = -1;
+
+ tas_priv->isspi = true;
+
+ tas_priv->update_bits = tasdevice_spi_dev_update_bits;
+ tas_priv->change_chn_book = tasdevice_spi_change_chn_book;
+ tas_priv->dev_read = tasdevice_spi_dev_read;
+ tas_priv->dev_bulk_read = tasdevice_spi_dev_bulk_read;
+
+ 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, tas_priv->index,
+ 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;
+
+ ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index, 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 *p,
+ 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_dev_write(p, p->index, mc->reg, (unsigned int)val);
+ if (ret)
+ dev_err(p->dev, "set digital vol err in dev %d\n", p->index);
+
+ return ret;
+}
+
+static int tasdevice_spi_digital_getvol(struct tasdevice_priv *p,
+ struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ int max = mc->max;
+ int ret, val;
+
+ ret = tasdevice_spi_dev_read(p, p->index, mc->reg, &val);
+ if (ret) {
+ dev_err(p->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));
+ 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;
+ }
+ p->ndev = 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);
+ struct tasdevice_priv *tas_priv = tas_hda->priv;
+
+ if (action == HDA_GEN_PCM_ACT_OPEN) {
+ pm_runtime_get_sync(dev);
+ guard(mutex)(&tas_priv->codec_lock);
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
+ tasdevice_tuning_switch(tas_hda->priv, 0);
+ } else if (action == HDA_GEN_PCM_ACT_CLOSE) {
+ guard(mutex)(&tas_priv->codec_lock);
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
+ tasdevice_tuning_switch(tas_priv, 1);
+ pm_runtime_put_autosuspend(dev);
+ }
+}
+
+/*
+ * 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;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ 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;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ 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;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ 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;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ 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 struct snd_kcontrol_new tas2781_snd_ctls[] = {
+ ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0,
+ tas2781_amp_getvol, tas2781_amp_putvol,
+ tas2781_amp_tlv),
+ ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1,
+ tas2781_digital_getvol, tas2781_digital_putvol,
+ tas2781_dvc_tlv),
+ ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get,
+ tas2781_force_fwload_put),
+};
+
+static struct snd_kcontrol_new tas2781_prof_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_profile,
+ .get = tasdevice_get_profile_id,
+ .put = tasdevice_set_profile_id,
+};
+
+static struct snd_kcontrol_new tas2781_dsp_ctls[] = {
+ /* Speaker Program */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_programs,
+ .get = tasdevice_program_get,
+ .put = tasdevice_program_put,
+ },
+ /* Speaker Config */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_config,
+ .get = tasdevice_config_get,
+ .put = tasdevice_config_put,
+ },
+};
+
+static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
+{
+ struct hda_codec *codec = tas_hda->priv->codec;
+ struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv;
+
+ 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(h_priv->snd_ctls) - 1; i >= 0; i--)
+ snd_ctl_remove(codec->card, h_priv->snd_ctls[i]);
+
+ snd_ctl_remove(codec->card, tas_hda->prof_ctl);
+}
+
+static int tas2781_hda_spi_prf_ctl(struct tas2781_hda *h)
+{
+ struct tasdevice_priv *p = h->priv;
+ struct hda_codec *c = p->codec;
+ char name[64];
+ int rc;
+
+ snprintf(name, sizeof(name), "Speaker-%d Profile Id", p->index);
+ tas2781_prof_ctl.name = name;
+ h->prof_ctl = snd_ctl_new1(&tas2781_prof_ctl, p);
+ rc = snd_ctl_add(c->card, h->prof_ctl);
+ if (rc)
+ dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+ tas2781_prof_ctl.name, rc);
+ return rc;
+}
+
+static int tas2781_hda_spi_snd_ctls(struct tas2781_hda *h)
+{
+ struct tas2781_hda_spi_priv *h_priv = h->hda_priv;
+ struct tasdevice_priv *p = h->priv;
+ struct hda_codec *c = p->codec;
+ char name[64];
+ int i = 0;
+ int rc;
+
+ snprintf(name, sizeof(name), "Speaker-%d Analog Volume", p->index);
+ tas2781_snd_ctls[i].name = name;
+ h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+ rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+ if (rc) {
+ dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+ tas2781_snd_ctls[i].name, rc);
+ return rc;
+ }
+ i++;
+ snprintf(name, sizeof(name), "Speaker-%d Digital Volume", p->index);
+ tas2781_snd_ctls[i].name = name;
+ h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+ rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+ if (rc) {
+ dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+ tas2781_snd_ctls[i].name, rc);
+ return rc;
+ }
+ i++;
+ snprintf(name, sizeof(name), "Froce Speaker-%d FW Load", p->index);
+ tas2781_snd_ctls[i].name = name;
+ h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+ rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+ if (rc) {
+ dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+ tas2781_snd_ctls[i].name, rc);
+ }
+ return rc;
+}
+
+static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h)
+{
+ struct tasdevice_priv *p = h->priv;
+ struct hda_codec *c = p->codec;
+ char name[64];
+ int i = 0;
+ int rc;
+
+ snprintf(name, sizeof(name), "Speaker-%d Program Id", p->index);
+ tas2781_dsp_ctls[i].name = name;
+ h->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
+ rc = snd_ctl_add(c->card, h->dsp_prog_ctl);
+ if (rc) {
+ dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+ tas2781_dsp_ctls[i].name, rc);
+ return rc;
+ }
+ i++;
+ snprintf(name, sizeof(name), "Speaker-%d Config Id", p->index);
+ tas2781_dsp_ctls[i].name = name;
+ h->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
+ rc = snd_ctl_add(c->card, h->dsp_conf_ctl);
+ if (rc) {
+ dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+ tas2781_dsp_ctls[i].name, rc);
+ }
+
+ return rc;
+}
+
+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 ret, val;
+
+ pm_runtime_get_sync(tas_priv->dev);
+ guard(mutex)(&tas_priv->codec_lock);
+
+ ret = tasdevice_rca_parser(tas_priv, fmw);
+ if (ret)
+ goto out;
+
+ /* Add control one time only. */
+ ret = tas2781_hda_spi_prf_ctl(tas_hda);
+ if (ret)
+ goto out;
+
+ ret = tas2781_hda_spi_snd_ctls(tas_hda);
+ if (ret)
+ goto out;
+
+ tasdevice_dsp_remove(tas_priv);
+
+ tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+ scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X-%01d.bin",
+ lower_16_bits(codec->core.subsystem_id), tas_priv->index);
+ ret = tasdevice_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;
+ }
+
+ ret = tas2781_hda_spi_dsp_ctls(tas_hda);
+ if (ret)
+ goto out;
+ /* Perform AMP reset before firmware download. */
+ 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, tas_priv->index,
+ TAS2781_REG_CLK_CONFIG, &val);
+ if (ret < 0)
+ goto out;
+
+ if (val == TAS2781_REG_CLK_CONFIG_RESET) {
+ ret = tasdevice_prmg_load(tas_priv, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "FW download failed = %d\n",
+ ret);
+ goto out;
+ }
+ tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+ }
+ if (tas_priv->fmw->nr_programs > 0)
+ tas_priv->tasdevice[tas_priv->index].cur_prog = 0;
+ if (tas_priv->fmw->nr_configurations > 0)
+ tas_priv->tasdevice[tas_priv->index].cur_conf = 0;
+
+ /*
+ * If calibrated data occurs error, dsp will still works with default
+ * calibrated data inside algo.
+ */
+ tas2781_save_calibration(tas_hda);
+out:
+ release_firmware(fmw);
+ 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_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 tasdevice_priv *tas_priv = tas_hda->priv;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, tas_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_config_info_remove(tas_priv);
+ tasdevice_dsp_remove(tas_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 int tas2781_hda_spi_probe(struct spi_device *spi)
+{
+ struct tas2781_hda_spi_priv *hda_priv;
+ 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;
+
+ hda_priv = devm_kzalloc(&spi->dev, sizeof(*hda_priv), GFP_KERNEL);
+ if (!hda_priv)
+ return -ENOMEM;
+
+ tas_hda->hda_priv = hda_priv;
+ 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";
+ } 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);
+
+ pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
+ pm_runtime_use_autosuspend(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);
+
+ ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
+ if (ret) {
+ dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
+ pm_runtime_disable(tas_priv->dev);
+ tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
+ }
+
+ return ret;
+}
+
+static void tas2781_hda_spi_remove(struct spi_device *spi)
+{
+ tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
+}
+
+static int tas2781_runtime_suspend(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ struct tasdevice_priv *tas_priv = tas_hda->priv;
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
+ && tas_priv->playback_started)
+ tasdevice_tuning_switch(tas_priv, 1);
+
+ tas_priv->tasdevice[tas_priv->index].cur_book = -1;
+ tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
+
+ return 0;
+}
+
+static int tas2781_runtime_resume(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ struct tasdevice_priv *tas_priv = tas_hda->priv;
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
+ && tas_priv->playback_started)
+ tasdevice_tuning_switch(tas_priv, 0);
+
+ return 0;
+}
+
+static int tas2781_system_suspend(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ struct tasdevice_priv *tas_priv = tas_hda->priv;
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ /* Shutdown chip before system suspend */
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
+ && tas_priv->playback_started)
+ tasdevice_tuning_switch(tas_priv, 1);
+
+ return 0;
+}
+
+static int tas2781_system_resume(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ struct tasdevice_priv *tas_priv = tas_hda->priv;
+ int ret, val;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ ret = tas_priv->dev_read(tas_priv, tas_priv->index,
+ TAS2781_REG_CLK_CONFIG, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val == TAS2781_REG_CLK_CONFIG_RESET) {
+ tas_priv->tasdevice[tas_priv->index].cur_book = -1;
+ tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
+ tas_priv->tasdevice[tas_priv->index].cur_prog = -1;
+
+ ret = tasdevice_prmg_load(tas_priv, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev,
+ "FW download failed = %d\n", ret);
+ return ret;
+ }
+ tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+
+ if (tas_priv->playback_started)
+ tasdevice_tuning_switch(tas_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");
+MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/hda/codecs/sigmatel.c
index 61258b0aac8d..ecbee408d771 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/hda/codecs/sigmatel.c
@@ -2,12 +2,12 @@
/*
* Universal Interface for Intel High Definition Audio Codec
*
- * HD audio interface patch for SigmaTel STAC92xx
+ * HD audio codec driver for SigmaTel STAC92xx
*
* Copyright (c) 2005 Embedded Alley Solutions, Inc.
* Matt Porter <mporter@embeddedalley.com>
*
- * Based on patch_cmedia.c and patch_realtek.c
+ * Based on cmedia.c and realtek.c
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
*/
@@ -24,7 +24,7 @@
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
enum {
STAC_REF,
@@ -1462,7 +1462,7 @@ static const struct hda_model_fixup stac9200_models[] = {
{}
};
-static const struct snd_pci_quirk stac9200_fixup_tbl[] = {
+static const struct hda_quirk stac9200_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_REF),
@@ -1683,7 +1683,7 @@ static const struct hda_model_fixup stac925x_models[] = {
{}
};
-static const struct snd_pci_quirk stac925x_fixup_tbl[] = {
+static const struct hda_quirk stac925x_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
@@ -1957,7 +1957,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
{}
};
-static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
+static const struct hda_quirk stac92hd73xx_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_92HD73XX_REF),
@@ -2154,10 +2154,8 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
-#ifdef CONFIG_PM
/* resetting controller clears GPIO, so we need to keep on */
codec->core.power_caps &= ~AC_PWRST_CLKSTOP;
-#endif
}
}
@@ -2755,7 +2753,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = {
{}
};
-static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
+static const struct hda_quirk stac92hd83xxx_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_92HD83XXX_REF),
@@ -3238,7 +3236,7 @@ static const struct hda_model_fixup stac92hd71bxx_models[] = {
{}
};
-static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = {
+static const struct hda_quirk stac92hd71bxx_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_92HD71BXX_REF),
@@ -3498,7 +3496,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = {
};
/* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */
-static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = {
+static const struct hda_quirk stac922x_intel_mac_fixup_tbl[] = {
SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3),
SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1),
SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2),
@@ -3642,7 +3640,7 @@ static const struct hda_model_fixup stac922x_models[] = {
{}
};
-static const struct snd_pci_quirk stac922x_fixup_tbl[] = {
+static const struct hda_quirk stac922x_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_D945_REF),
@@ -3970,7 +3968,7 @@ static const struct hda_model_fixup stac927x_models[] = {
{}
};
-static const struct snd_pci_quirk stac927x_fixup_tbl[] = {
+static const struct hda_quirk stac927x_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_D965_REF),
@@ -4180,7 +4178,7 @@ static const struct hda_model_fixup stac9205_models[] = {
{}
};
-static const struct snd_pci_quirk stac9205_fixup_tbl[] = {
+static const struct hda_quirk stac9205_fixup_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_9205_REF),
@@ -4257,7 +4255,7 @@ static const struct hda_fixup stac92hd95_fixups[] = {
},
};
-static const struct snd_pci_quirk stac92hd95_fixup_tbl[] = {
+static const struct hda_quirk stac92hd95_fixup_tbl[] = {
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS),
{} /* terminator */
};
@@ -4393,8 +4391,6 @@ static int stac_init(struct hda_codec *codec)
return 0;
}
-#define stac_free snd_hda_gen_free
-
#ifdef CONFIG_SND_PROC_FS
static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
@@ -4442,7 +4438,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
#define stac927x_proc_hook NULL
#endif
-#ifdef CONFIG_PM
static int stac_suspend(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -4456,20 +4451,6 @@ static int stac_suspend(struct hda_codec *codec)
return 0;
}
-#else
-#define stac_suspend NULL
-#endif /* CONFIG_PM */
-
-static const struct hda_codec_ops stac_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = stac_init,
- .free = stac_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = stac_suspend,
-#endif
-};
static int alloc_stac_spec(struct hda_codec *codec)
{
@@ -4482,19 +4463,14 @@ static int alloc_stac_spec(struct hda_codec *codec)
codec->spec = spec;
codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
spec->gen.dac_min_mute = true;
- codec->patch_ops = stac_patch_ops;
return 0;
}
-static int patch_stac9200(struct hda_codec *codec)
+static int probe_stac9200(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
@@ -4508,25 +4484,19 @@ static int patch_stac9200(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
}
-static int patch_stac925x(struct hda_codec *codec)
+static int probe_stac925x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
@@ -4538,26 +4508,20 @@ static int patch_stac925x(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
}
-static int patch_stac92hd73xx(struct hda_codec *codec)
+static int probe_stac92hd73xx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
int num_dacs;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
/* enable power_save_node only for new 92HD89xx chips, as it causes
* click noises on old 92HD73xx chips.
@@ -4612,10 +4576,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
snd_hda_add_verbs(codec, stac92hd73xx_core_init);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
/* Don't GPIO-mute speakers if there are no internal speakers, because
* the GPIO might be necessary for Headphone
@@ -4654,15 +4616,11 @@ static void stac_setup_gpio(struct hda_codec *codec)
}
}
-static int patch_stac92hd83xxx(struct hda_codec *codec)
+static int probe_stac92hd83xxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
/* longer delay needed for D3 */
codec->core.power_caps &= ~AC_PWRST_EPSS;
@@ -4687,10 +4645,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
stac_setup_gpio(codec);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
codec->proc_widget_hook = stac92hd_proc_hook;
@@ -4703,15 +4659,11 @@ static const hda_nid_t stac92hd95_pwr_nids[] = {
0x0a, 0x0b, 0x0c, 0x0d
};
-static int patch_stac92hd95(struct hda_codec *codec)
+static int probe_stac92hd95(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
/* longer delay needed for D3 */
codec->core.power_caps &= ~AC_PWRST_EPSS;
@@ -4733,10 +4685,8 @@ static int patch_stac92hd95(struct hda_codec *codec)
stac_setup_gpio(codec);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
codec->proc_widget_hook = stac92hd_proc_hook;
@@ -4745,16 +4695,12 @@ static int patch_stac92hd95(struct hda_codec *codec)
return 0;
}
-static int patch_stac92hd71bxx(struct hda_codec *codec)
+static int probe_stac92hd71bxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
const hda_nid_t *unmute_nids = stac92hd71bxx_unmute_nids;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
/* disabled power_save_node since it causes noises on a Dell machine */
/* codec->power_save_node = 1; */
@@ -4817,10 +4763,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
stac_setup_gpio(codec);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
codec->proc_widget_hook = stac92hd7x_proc_hook;
@@ -4829,15 +4773,11 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
return 0;
}
-static int patch_stac922x(struct hda_codec *codec)
+static int probe_stac922x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
@@ -4856,10 +4796,8 @@ static int patch_stac922x(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -4871,15 +4809,11 @@ static const char * const stac927x_spdif_labels[] = {
"Analog Mux 2", "Analog Mux 3", NULL
};
-static int patch_stac927x(struct hda_codec *codec)
+static int probe_stac927x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
@@ -4905,10 +4839,8 @@ static int patch_stac927x(struct hda_codec *codec)
snd_hda_add_verbs(codec, stac927x_core_init);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
codec->proc_widget_hook = stac927x_proc_hook;
@@ -4929,15 +4861,11 @@ static int patch_stac927x(struct hda_codec *codec)
return 0;
}
-static int patch_stac9205(struct hda_codec *codec)
+static int probe_stac9205(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
@@ -4963,10 +4891,8 @@ static int patch_stac9205(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
+ if (err < 0)
return err;
- }
codec->proc_widget_hook = stac9205_proc_hook;
@@ -5010,21 +4936,17 @@ static const struct hda_fixup stac9872_fixups[] = {
},
};
-static const struct snd_pci_quirk stac9872_fixup_tbl[] = {
+static const struct hda_quirk stac9872_fixup_tbl[] = {
SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
"Sony VAIO F/S", STAC_9872_VAIO),
{} /* terminator */
};
-static int patch_stac9872(struct hda_codec *codec)
+static int probe_stac9872(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec);
- if (err < 0)
- return err;
-
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
@@ -5036,125 +4958,202 @@ static int patch_stac9872(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
err = stac_parse_auto_config(codec);
- if (err < 0) {
- stac_free(codec);
- return -EINVAL;
- }
+ if (err < 0)
+ return err;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
}
+/*
+ * common driver probe
+ */
+
+enum {
+ MODEL_STAC9200,
+ MODEL_STAC9205,
+ MODEL_STAC922X,
+ MODEL_STAC925X,
+ MODEL_STAC927X,
+ MODEL_STAC9872,
+ MODEL_STAC92HD71BXX,
+ MODEL_STAC92HD73XX,
+ MODEL_STAC92HD83XXX,
+ MODEL_STAC92HD95,
+};
+
+static int stac_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ int err;
+
+ err = alloc_stac_spec(codec);
+ if (err < 0)
+ return err;
+
+ switch (id->driver_data) {
+ case MODEL_STAC9200:
+ err = probe_stac9200(codec);
+ break;
+ case MODEL_STAC9205:
+ err = probe_stac9205(codec);
+ break;
+ case MODEL_STAC922X:
+ err = probe_stac922x(codec);
+ break;
+ case MODEL_STAC925X:
+ err = probe_stac925x(codec);
+ break;
+ case MODEL_STAC927X:
+ err = probe_stac927x(codec);
+ break;
+ case MODEL_STAC9872:
+ err = probe_stac9872(codec);
+ break;
+ case MODEL_STAC92HD71BXX:
+ err = probe_stac92hd71bxx(codec);
+ break;
+ case MODEL_STAC92HD73XX:
+ err = probe_stac92hd73xx(codec);
+ break;
+ case MODEL_STAC92HD83XXX:
+ err = probe_stac92hd83xxx(codec);
+ break;
+ case MODEL_STAC92HD95:
+ err = probe_stac92hd95(codec);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err < 0) {
+ snd_hda_gen_remove(codec);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct hda_codec_ops stac_codec_ops = {
+ .probe = stac_probe,
+ .remove = snd_hda_gen_remove,
+ .build_controls = snd_hda_gen_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = stac_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = stac_suspend,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
/*
- * patch entries
+ * driver entries
*/
static const struct hda_device_id snd_hda_id_sigmatel[] = {
- HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200),
- HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x),
- HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x),
- HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x),
- HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x),
- HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x),
- HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
- HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847632, "STAC9202", patch_stac925x),
- HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x),
- HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x),
- HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x),
- HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x),
- HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x),
- HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x),
- HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x),
+ HDA_CODEC_ID_MODEL(0x83847690, "STAC9200", MODEL_STAC9200),
+ HDA_CODEC_ID_MODEL(0x83847882, "STAC9220 A1", MODEL_STAC922X),
+ HDA_CODEC_ID_MODEL(0x83847680, "STAC9221 A1", MODEL_STAC922X),
+ HDA_CODEC_ID_MODEL(0x83847880, "STAC9220 A2", MODEL_STAC922X),
+ HDA_CODEC_ID_MODEL(0x83847681, "STAC9220D/9223D A2", MODEL_STAC922X),
+ HDA_CODEC_ID_MODEL(0x83847682, "STAC9221 A2", MODEL_STAC922X),
+ HDA_CODEC_ID_MODEL(0x83847683, "STAC9221D A2", MODEL_STAC922X),
+ HDA_CODEC_ID_MODEL(0x83847618, "STAC9227", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847619, "STAC9227", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847638, "STAC92HD700", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847616, "STAC9228", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847617, "STAC9228", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847614, "STAC9229", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847615, "STAC9229", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847620, "STAC9274", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847621, "STAC9274D", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847622, "STAC9273X", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847623, "STAC9273D", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847624, "STAC9272X", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847625, "STAC9272D", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847626, "STAC9271X", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847627, "STAC9271D", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847628, "STAC9274X5NH", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847629, "STAC9274D5NH", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847632, "STAC9202", MODEL_STAC925X),
+ HDA_CODEC_ID_MODEL(0x83847633, "STAC9202D", MODEL_STAC925X),
+ HDA_CODEC_ID_MODEL(0x83847634, "STAC9250", MODEL_STAC925X),
+ HDA_CODEC_ID_MODEL(0x83847635, "STAC9250D", MODEL_STAC925X),
+ HDA_CODEC_ID_MODEL(0x83847636, "STAC9251", MODEL_STAC925X),
+ HDA_CODEC_ID_MODEL(0x83847637, "STAC9250D", MODEL_STAC925X),
+ HDA_CODEC_ID_MODEL(0x83847645, "92HD206X", MODEL_STAC927X),
+ HDA_CODEC_ID_MODEL(0x83847646, "92HD206D", MODEL_STAC927X),
/* The following does not take into account .id=0x83847661 when subsys =
* 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
* currently not fully supported.
*/
- HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872),
- HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872),
- HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872),
- HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205),
- HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205),
- HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95),
- HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx),
- HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx),
- HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx),
- HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx),
+ HDA_CODEC_ID_MODEL(0x83847661, "CXD9872RD/K", MODEL_STAC9872),
+ HDA_CODEC_ID_MODEL(0x83847662, "STAC9872AK", MODEL_STAC9872),
+ HDA_CODEC_ID_MODEL(0x83847664, "CXD9872AKD", MODEL_STAC9872),
+ HDA_CODEC_ID_MODEL(0x83847698, "STAC9205", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a0, "STAC9205", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a1, "STAC9205D", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a2, "STAC9204", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a3, "STAC9204D", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a4, "STAC9255", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a5, "STAC9255D", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a6, "STAC9254", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x838476a7, "STAC9254D", MODEL_STAC9205),
+ HDA_CODEC_ID_MODEL(0x111d7603, "92HD75B3X5", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d7604, "92HD83C1X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76d4, "92HD83C1C5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d7605, "92HD81B1X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76d5, "92HD81B1C5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76d1, "92HD87B1/3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76d9, "92HD87B2/4", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d7666, "92HD88B3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d7667, "92HD88B1", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d7668, "92HD88B2", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d7669, "92HD88B4", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d7608, "92HD75B2X5", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d7674, "92HD73D1X5", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d7675, "92HD73C1X5", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d7676, "92HD73E1X5", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d7695, "92HD95", MODEL_STAC92HD95),
+ HDA_CODEC_ID_MODEL(0x111d76b0, "92HD71B8X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b1, "92HD71B8X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b2, "92HD71B7X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b3, "92HD71B7X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b4, "92HD71B6X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b5, "92HD71B6X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b6, "92HD71B5X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76b7, "92HD71B5X", MODEL_STAC92HD71BXX),
+ HDA_CODEC_ID_MODEL(0x111d76c0, "92HD89C3", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c1, "92HD89C2", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c2, "92HD89C1", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c3, "92HD89B3", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c4, "92HD89B2", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c5, "92HD89B1", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c6, "92HD89E3", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c7, "92HD89E2", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c8, "92HD89E1", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76c9, "92HD89D3", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76ca, "92HD89D2", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76cb, "92HD89D1", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76cc, "92HD89F3", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76cd, "92HD89F2", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76ce, "92HD89F1", MODEL_STAC92HD73XX),
+ HDA_CODEC_ID_MODEL(0x111d76df, "92HD93BXX", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76e0, "92HD91BXX", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76e3, "92HD98BXX", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76e5, "92HD99BXX", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76e7, "92HD90BXX", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76e8, "92HD66B1X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76e9, "92HD66B2X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76ea, "92HD66B3X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76eb, "92HD66C1X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76ec, "92HD66C2X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76ed, "92HD66C3X5", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76ee, "92HD66B1X3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76ef, "92HD66B2X3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76f0, "92HD66B3X3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76f1, "92HD66C1X3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76f2, "92HD66C2X3", MODEL_STAC92HD83XXX),
+ HDA_CODEC_ID_MODEL(0x111d76f3, "92HD66C3/65", MODEL_STAC92HD83XXX),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel);
@@ -5164,6 +5163,7 @@ MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
static struct hda_codec_driver sigmatel_driver = {
.id = snd_hda_id_sigmatel,
+ .ops = &stac_codec_ops,
};
module_hda_codec_driver(sigmatel_driver);
diff --git a/sound/pci/hda/patch_via.c b/sound/hda/codecs/via.c
index 2994f85bc1b9..6becea9bb810 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/hda/codecs/via.c
@@ -2,7 +2,7 @@
/*
* Universal Interface for Intel High Definition Audio Codec
*
- * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
+ * HD audio codec driver for VIA VT17xx/VT18xx/VT20xx codec
*
* (C) 2006-2009 VIA Technology, Inc.
* (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
@@ -43,7 +43,7 @@
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
/* Pin Widget NID */
#define VT1708_HP_PIN_NID 0x20
@@ -52,8 +52,10 @@
enum VIA_HDA_CODEC {
UNKNOWN = -1,
VT1708,
+ VT1709,
VT1709_10CH,
VT1709_6CH,
+ VT1708B,
VT1708B_8CH,
VT1708B_4CH,
VT1708S,
@@ -66,6 +68,7 @@ enum VIA_HDA_CODEC {
VT1802,
VT1705CF,
VT1808,
+ VT3476,
CODEC_TYPES,
};
@@ -95,8 +98,6 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream,
int action);
-static const struct hda_codec_ops via_patch_ops; /* defined below */
-
static struct via_spec *via_new_spec(struct hda_codec *codec)
{
struct via_spec *spec;
@@ -118,7 +119,6 @@ static struct via_spec *via_new_spec(struct hda_codec *codec)
spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
codec->power_save_node = 1;
spec->gen.power_down_unused = 1;
- codec->patch_ops = via_patch_ops;
return spec;
}
@@ -373,13 +373,12 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
vt1708_update_hp_work(codec);
}
-static void via_free(struct hda_codec *codec)
+static void via_remove(struct hda_codec *codec)
{
vt1708_stop_hp_work(codec);
- snd_hda_gen_free(codec);
+ snd_hda_gen_remove(codec);
}
-#ifdef CONFIG_PM
static int via_suspend(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -396,13 +395,11 @@ static int via_resume(struct hda_codec *codec)
{
/* some delay here to make jack detection working (bko#98921) */
msleep(10);
- codec->patch_ops.init(codec);
+ snd_hda_codec_init(codec);
snd_hda_regmap_sync(codec);
return 0;
}
-#endif
-#ifdef CONFIG_PM
static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
struct via_spec *spec = codec->spec;
@@ -410,27 +407,10 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
vt1708_update_hp_work(codec);
return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid);
}
-#endif
/*
*/
-static int via_init(struct hda_codec *codec);
-
-static const struct hda_codec_ops via_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = via_init,
- .free = via_free,
- .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
- .suspend = via_suspend,
- .resume = via_resume,
- .check_power_status = via_check_power_status,
-#endif
-};
-
-
static const struct hda_verb vt1708_init_verbs[] = {
/* power down jack detect function */
{0x1, 0xf81, 0x1},
@@ -547,19 +527,21 @@ static int via_init(struct hda_codec *codec)
return 0;
}
-static int vt1708_build_controls(struct hda_codec *codec)
+static int via_build_controls(struct hda_codec *codec)
{
/* In order not to create "Phantom Jack" controls,
temporary enable jackpoll */
int err;
int old_interval = codec->jackpoll_interval;
- codec->jackpoll_interval = msecs_to_jiffies(100);
+ if (old_interval)
+ codec->jackpoll_interval = msecs_to_jiffies(100);
err = snd_hda_gen_build_controls(codec);
- codec->jackpoll_interval = old_interval;
+ if (old_interval)
+ codec->jackpoll_interval = old_interval;
return err;
}
-static int vt1708_build_pcms(struct hda_codec *codec)
+static int via_build_pcms(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
int i, err;
@@ -586,19 +568,11 @@ static int vt1708_build_pcms(struct hda_codec *codec)
return 0;
}
-static int patch_vt1708(struct hda_codec *codec)
+static int probe_vt1708(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
- /* override some patch_ops */
- codec->patch_ops.build_controls = vt1708_build_controls;
- codec->patch_ops.build_pcms = vt1708_build_pcms;
spec->gen.mixer_nid = 0x17;
/* set jackpoll_interval while parsing the codec */
@@ -617,81 +591,47 @@ static int patch_vt1708(struct hda_codec *codec)
err = snd_hda_add_verbs(codec, vt1708_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
if (err < 0)
- goto error;
+ return err;
/* add jack detect on/off control */
- if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {
- err = -ENOMEM;
- goto error;
- }
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl))
+ return -ENOMEM;
/* clear jackpoll_interval again; it's set dynamically */
codec->jackpoll_interval = 0;
return 0;
-
- error:
- via_free(codec);
- return err;
}
-static int patch_vt1709(struct hda_codec *codec)
+static int probe_vt1709(struct hda_codec *codec)
{
- struct via_spec *spec;
- int err;
-
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
+ struct via_spec *spec = codec->spec;
spec->gen.mixer_nid = 0x18;
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
-static int patch_vt1708S(struct hda_codec *codec);
-static int patch_vt1708B(struct hda_codec *codec)
+static int probe_vt1708S(struct hda_codec *codec);
+static int probe_vt1708B(struct hda_codec *codec)
{
- struct via_spec *spec;
- int err;
+ struct via_spec *spec = codec->spec;
if (get_codec_type(codec) == VT1708BCE)
- return patch_vt1708S(codec);
-
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
+ return probe_vt1708S(codec);
spec->gen.mixer_nid = 0x16;
/* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
-/* Patch for VT1708S */
+/* Support for VT1708S */
static const struct hda_verb vt1708S_init_verbs[] = {
/* Enable Mic Boost Volume backdoor */
{0x1, 0xf98, 0x1},
@@ -712,16 +652,11 @@ static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
(0 << AC_AMPCAP_MUTE_SHIFT));
}
-static int patch_vt1708S(struct hda_codec *codec)
+static int probe_vt1708S(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x16;
override_mic_boost(codec, 0x1a, 0, 3, 40);
override_mic_boost(codec, 0x1e, 0, 3, 40);
@@ -735,21 +670,12 @@ static int patch_vt1708S(struct hda_codec *codec)
err = snd_hda_add_verbs(codec, vt1708S_init_verbs);
if (err < 0)
- goto error;
-
- /* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
+ return err;
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
-/* Patch for VT1702 */
+/* Support for VT1702 */
static const struct hda_verb vt1702_init_verbs[] = {
/* mixer enable */
@@ -759,16 +685,11 @@ static const struct hda_verb vt1702_init_verbs[] = {
{ }
};
-static int patch_vt1702(struct hda_codec *codec)
+static int probe_vt1702(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x1a;
/* limit AA path volume to 0 dB */
@@ -780,21 +701,13 @@ static int patch_vt1702(struct hda_codec *codec)
err = snd_hda_add_verbs(codec, vt1702_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
-/* Patch for VT1718S */
+/* Support for VT1718S */
static const struct hda_verb vt1718S_init_verbs[] = {
/* Enable MW0 adjust Gain 5 */
@@ -842,16 +755,11 @@ static int add_secret_dac_path(struct hda_codec *codec)
}
-static int patch_vt1718S(struct hda_codec *codec)
+static int probe_vt1718S(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x21;
override_mic_boost(codec, 0x2b, 0, 3, 40);
override_mic_boost(codec, 0x29, 0, 3, 40);
@@ -859,21 +767,13 @@ static int patch_vt1718S(struct hda_codec *codec)
err = snd_hda_add_verbs(codec, vt1718S_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
-/* Patch for VT1716S */
+/* Support for VT1716S */
static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -939,41 +839,30 @@ static const struct hda_verb vt1716S_init_verbs[] = {
{ }
};
-static int patch_vt1716S(struct hda_codec *codec)
+static int probe_vt1716S(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x16;
override_mic_boost(codec, 0x1a, 0, 3, 40);
override_mic_boost(codec, 0x1e, 0, 3, 40);
err = snd_hda_add_verbs(codec, vt1716S_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
if (err < 0)
- goto error;
+ return err;
if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||
!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||
- !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {
- err = -ENOMEM;
- goto error;
- }
+ !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer))
+ return -ENOMEM;
return 0;
-
- error:
- via_free(codec);
- return err;
}
/* for vt2002P */
@@ -1041,7 +930,7 @@ static const struct hda_fixup via_fixups[] = {
},
};
-static const struct snd_pci_quirk vt2002p_fixups[] = {
+static const struct hda_quirk vt2002p_fixups[] = {
SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE),
SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75),
SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
@@ -1061,17 +950,12 @@ static void fix_vt1802_connections(struct hda_codec *codec)
snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
}
-/* patch for vt2002P */
-static int patch_vt2002P(struct hda_codec *codec)
+/* Support for vt2002P */
+static int probe_vt2002P(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x21;
override_mic_boost(codec, 0x2b, 0, 3, 40);
override_mic_boost(codec, 0x29, 0, 3, 40);
@@ -1087,18 +971,10 @@ static int patch_vt2002P(struct hda_codec *codec)
else
err = snd_hda_add_verbs(codec, vt2002P_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
/* for vt1812 */
@@ -1111,17 +987,11 @@ static const struct hda_verb vt1812_init_verbs[] = {
{ }
};
-/* patch for vt1812 */
-static int patch_vt1812(struct hda_codec *codec)
+static int probe_vt1812(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x21;
override_mic_boost(codec, 0x2b, 0, 3, 40);
override_mic_boost(codec, 0x29, 0, 3, 40);
@@ -1129,21 +999,13 @@ static int patch_vt1812(struct hda_codec *codec)
err = snd_hda_add_verbs(codec, vt1812_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- via_free(codec);
- return err;
+ return via_parse_auto_config(codec);
}
-/* patch for vt3476 */
+/* Support for vt3476 */
static const struct hda_verb vt3476_init_verbs[] = {
/* Enable DMic 8/16/32K */
@@ -1155,96 +1017,155 @@ static const struct hda_verb vt3476_init_verbs[] = {
{ }
};
-static int patch_vt3476(struct hda_codec *codec)
+static int probe_vt3476(struct hda_codec *codec)
{
- struct via_spec *spec;
+ struct via_spec *spec = codec->spec;
int err;
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
spec->gen.mixer_nid = 0x3f;
add_secret_dac_path(codec);
err = snd_hda_add_verbs(codec, vt3476_init_verbs);
if (err < 0)
- goto error;
+ return err;
/* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0)
- goto error;
+ return via_parse_auto_config(codec);
- return 0;
+}
- error:
- via_free(codec);
- return err;
+/*
+ * common driver probe
+ */
+static int via_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = via_new_spec(codec);
+ if (!spec)
+ return -ENOMEM;
+
+ switch (id->driver_data) {
+ case VT1708:
+ err = probe_vt1708(codec);
+ break;
+ case VT1709:
+ err = probe_vt1709(codec);
+ break;
+ case VT1708B:
+ err = probe_vt1708B(codec);
+ break;
+ case VT1708S:
+ err = probe_vt1708S(codec);
+ break;
+ case VT1702:
+ err = probe_vt1702(codec);
+ break;
+ case VT1718S:
+ err = probe_vt1718S(codec);
+ break;
+ case VT1716S:
+ err = probe_vt1716S(codec);
+ break;
+ case VT2002P:
+ err = probe_vt2002P(codec);
+ break;
+ case VT1812:
+ err = probe_vt1812(codec);
+ break;
+ case VT3476:
+ err = probe_vt3476(codec);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err < 0) {
+ via_remove(codec);
+ return err;
+ }
+
+ return 0;
}
+static const struct hda_codec_ops via_codec_ops = {
+ .probe = via_probe,
+ .remove = via_remove,
+ .build_controls = via_build_controls,
+ .build_pcms = via_build_pcms,
+ .init = via_init,
+ .unsol_event = snd_hda_jack_unsol_event,
+ .suspend = via_suspend,
+ .resume = via_resume,
+ .check_power_status = via_check_power_status,
+ .stream_pm = snd_hda_gen_stream_pm,
+};
+
/*
- * patch entries
+ * driver entries
*/
static const struct hda_device_id snd_hda_id_via[] = {
- HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708),
- HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708),
- HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708),
- HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708),
- HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709),
- HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B),
- HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702),
- HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S),
- HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S),
- HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S),
- HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S),
- HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S),
- HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S),
- HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P),
- HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P),
- HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812),
- HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S),
- HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P),
- HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P),
- HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476),
- HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476),
- HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476),
+ HDA_CODEC_ID_MODEL(0x11061708, "VT1708", VT1708),
+ HDA_CODEC_ID_MODEL(0x11061709, "VT1708", VT1708),
+ HDA_CODEC_ID_MODEL(0x1106170a, "VT1708", VT1708),
+ HDA_CODEC_ID_MODEL(0x1106170b, "VT1708", VT1708),
+ HDA_CODEC_ID_MODEL(0x1106e710, "VT1709 10-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e711, "VT1709 10-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e712, "VT1709 10-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e713, "VT1709 10-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e714, "VT1709 6-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e715, "VT1709 6-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e716, "VT1709 6-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e717, "VT1709 6-Ch", VT1709),
+ HDA_CODEC_ID_MODEL(0x1106e720, "VT1708B 8-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e721, "VT1708B 8-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e722, "VT1708B 8-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e723, "VT1708B 8-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e724, "VT1708B 4-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e725, "VT1708B 4-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e726, "VT1708B 4-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x1106e727, "VT1708B 4-Ch", VT1708B),
+ HDA_CODEC_ID_MODEL(0x11060397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11061397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11062397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11063397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11064397, "VT1705", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11065397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11066397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11067397, "VT1708S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11060398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11061398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11062398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11063398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11064398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11065398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11066398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11067398, "VT1702", VT1702),
+ HDA_CODEC_ID_MODEL(0x11060428, "VT1718S", VT1718S),
+ HDA_CODEC_ID_MODEL(0x11064428, "VT1718S", VT1718S),
+ HDA_CODEC_ID_MODEL(0x11060441, "VT2020", VT1718S),
+ HDA_CODEC_ID_MODEL(0x11064441, "VT1828S", VT1718S),
+ HDA_CODEC_ID_MODEL(0x11060433, "VT1716S", VT1716S),
+ HDA_CODEC_ID_MODEL(0x1106a721, "VT1716S", VT1716S),
+ HDA_CODEC_ID_MODEL(0x11060438, "VT2002P", VT2002P),
+ HDA_CODEC_ID_MODEL(0x11064438, "VT2002P", VT2002P),
+ HDA_CODEC_ID_MODEL(0x11060448, "VT1812", VT1812),
+ HDA_CODEC_ID_MODEL(0x11060440, "VT1818S", VT1708S),
+ HDA_CODEC_ID_MODEL(0x11060446, "VT1802", VT2002P),
+ HDA_CODEC_ID_MODEL(0x11068446, "VT1802", VT2002P),
+ HDA_CODEC_ID_MODEL(0x11064760, "VT1705CF", VT3476),
+ HDA_CODEC_ID_MODEL(0x11064761, "VT1708SCE", VT3476),
+ HDA_CODEC_ID_MODEL(0x11064762, "VT1808", VT3476),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via);
static struct hda_codec_driver via_driver = {
.id = snd_hda_id_via,
+ .ops = &via_codec_ops,
};
MODULE_LICENSE("GPL");
diff --git a/sound/hda/common/Kconfig b/sound/hda/common/Kconfig
new file mode 100644
index 000000000000..f38e1947fb3e
--- /dev/null
+++ b/sound/hda/common/Kconfig
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SND_HDA
+ tristate
+ select SND_PCM
+ select SND_VMASTER
+ select SND_JACK
+ select SND_HDA_CORE
+
+if SND_HDA
+
+config SND_HDA_HWDEP
+ bool "Build hwdep interface for HD-audio driver"
+ select SND_HWDEP
+ help
+ Say Y here to build a hwdep interface for HD-audio driver.
+ This interface can be used for out-of-band communication
+ with codecs for debugging purposes.
+
+config SND_HDA_RECONFIG
+ bool "Allow dynamic codec reconfiguration"
+ help
+ Say Y here to enable the HD-audio codec re-configuration feature.
+ It allows user to clear the whole codec configuration, change the
+ codec setup, add extra verbs, and re-configure the codec dynamically.
+
+ Note that this item alone doesn't provide the sysfs interface, but
+ enables the feature just for the patch loader below.
+ If you need the traditional sysfs entries for the manual interaction,
+ turn on CONFIG_SND_HDA_HWDEP as well.
+
+config SND_HDA_INPUT_BEEP
+ bool "Support digital beep via input layer"
+ depends on INPUT=y || INPUT=SND_HDA
+ help
+ Say Y here to build a digital beep interface for HD-audio
+ driver. This interface is used to generate digital beeps.
+
+config SND_HDA_INPUT_BEEP_MODE
+ int "Digital beep registration mode (0=off, 1=on)"
+ depends on SND_HDA_INPUT_BEEP=y
+ default "1"
+ range 0 1
+ help
+ Set 0 to disable the digital beep interface for HD-audio by default.
+ Set 1 to always enable the digital beep interface for HD-audio by
+ default.
+
+config SND_HDA_PATCH_LOADER
+ bool "Support initialization patch loading for HD-audio"
+ select FW_LOADER
+ select SND_HDA_RECONFIG
+ help
+ Say Y here to allow the HD-audio driver to load a pseudo
+ firmware file ("patch") for overriding the BIOS setup at
+ start up. The "patch" file can be specified via patch module
+ option, such as patch=hda-init.
+
+config SND_HDA_POWER_SAVE_DEFAULT
+ int "Default time-out for HD-audio power-save mode"
+ depends on PM
+ default 0
+ help
+ The default time-out value in seconds for HD-audio automatic
+ power-save mode. 0 means to disable the power-save mode.
+
+config SND_HDA_CTL_DEV_ID
+ bool "Use the device identifier field for controls"
+ depends on SND_HDA_INTEL
+ help
+ Say Y to use the device identifier field for (mixer)
+ controls (old behaviour until this option is available).
+
+ When enabled, the multiple HDA codecs may set the device
+ field in control (mixer) element identifiers. The use
+ of this field is not recommended and defined for mixer controls.
+
+ The old behaviour (Y) is obsolete and will be removed. Consider
+ to not enable this option.
+
+config SND_HDA_PREALLOC_SIZE
+ int "Pre-allocated buffer size for HD-audio driver"
+ range 0 32768
+ default 0 if SND_DMA_SGBUF
+ default 64 if !SND_DMA_SGBUF
+ help
+ Specifies the default pre-allocated buffer-size in kB for the
+ HD-audio driver. A larger buffer (e.g. 2048) is preferred
+ for systems using PulseAudio. The default 64 is chosen just
+ for compatibility reasons.
+ On x86 systems, the default is zero as S/G allocation works
+ and no preallocation is needed in most cases.
+
+ Note that the pre-allocation size can be changed dynamically
+ via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
+
+endif
diff --git a/sound/hda/common/Makefile b/sound/hda/common/Makefile
new file mode 100644
index 000000000000..3344fa0efe75
--- /dev/null
+++ b/sound/hda/common/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-hda-codec-y := bind.o codec.o jack.o auto_parser.o sysfs.o
+snd-hda-codec-y += controller.o
+snd-hda-codec-$(CONFIG_SND_PROC_FS) += proc.o
+
+snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hwdep.o
+snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += beep.o
+
+# for trace-points
+CFLAGS_controller.o := -I$(src)
+
+# common driver
+obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/hda/common/auto_parser.c
index 7c6b1fe8dfcc..8923813ce424 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/hda/common/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);
@@ -933,6 +939,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
bool match_all_pins)
{
const struct snd_hda_pin_quirk *pq;
+ const char *name = NULL;
if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
return;
@@ -946,9 +953,10 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
codec->fixup_id = pq->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
codec->fixup_name = pq->name;
- codec_dbg(codec, "%s: picked fixup %s (pin match)\n",
- codec->core.chip_name, codec->fixup_name);
+ name = pq->name;
#endif
+ codec_info(codec, "%s: picked fixup %s (pin match)\n",
+ codec->core.chip_name, name ? name : "");
codec->fixup_list = fixlist;
return;
}
@@ -956,6 +964,28 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup);
+/* check whether the given quirk entry matches with vendor/device pair */
+static bool hda_quirk_match(u16 vendor, u16 device, const struct hda_quirk *q)
+{
+ if (q->subvendor != vendor)
+ return false;
+ return !q->subdevice ||
+ (device & q->subdevice_mask) == q->subdevice;
+}
+
+/* look through the quirk list and return the matching entry */
+static const struct hda_quirk *
+hda_quirk_lookup_id(u16 vendor, u16 device, const struct hda_quirk *list)
+{
+ const struct hda_quirk *q;
+
+ for (q = list; q->subvendor || q->subdevice; q++) {
+ if (hda_quirk_match(vendor, device, q))
+ return q;
+ }
+ return NULL;
+}
+
/**
* snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string
* @codec: the HDA codec
@@ -975,14 +1005,16 @@ EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup);
*/
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
- const struct snd_pci_quirk *quirk,
+ const struct hda_quirk *quirk,
const struct hda_fixup *fixlist)
{
- const struct snd_pci_quirk *q;
+ const struct hda_quirk *q;
int id = HDA_FIXUP_ID_NOT_SET;
const char *name = NULL;
const char *type = NULL;
unsigned int vendor, device;
+ u16 pci_vendor, pci_device;
+ u16 codec_vendor, codec_device;
if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
return;
@@ -991,8 +1023,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
id = HDA_FIXUP_ID_NO_FIXUP;
fixlist = NULL;
- codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n",
- codec->core.chip_name);
+ codec_info(codec, "%s: picked no fixup (nofixup specified)\n",
+ codec->core.chip_name);
goto found;
}
@@ -1002,8 +1034,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
if (!strcmp(codec->modelname, models->name)) {
id = models->id;
name = models->name;
- codec_dbg(codec, "%s: picked fixup %s (model specified)\n",
- codec->core.chip_name, codec->fixup_name);
+ codec_info(codec, "%s: picked fixup %s (model specified)\n",
+ codec->core.chip_name, name);
goto found;
}
models++;
@@ -1013,27 +1045,42 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
if (!quirk)
return;
+ if (codec->bus->pci) {
+ pci_vendor = codec->bus->pci->subsystem_vendor;
+ pci_device = codec->bus->pci->subsystem_device;
+ }
+
+ codec_vendor = codec->core.subsystem_id >> 16;
+ codec_device = codec->core.subsystem_id & 0xffff;
+
/* match with the SSID alias given by the model string "XXXX:YYYY" */
if (codec->modelname &&
sscanf(codec->modelname, "%04x:%04x", &vendor, &device) == 2) {
- q = snd_pci_quirk_lookup_id(vendor, device, quirk);
+ q = hda_quirk_lookup_id(vendor, device, quirk);
if (q) {
type = "alias SSID";
goto found_device;
}
}
- /* match with the PCI SSID */
- q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (q) {
- type = "PCI SSID";
- goto found_device;
+ /* match primarily with the PCI SSID */
+ for (q = quirk; q->subvendor || q->subdevice; q++) {
+ /* if the entry is specific to codec SSID, check with it */
+ if (!codec->bus->pci || q->match_codec_ssid) {
+ if (hda_quirk_match(codec_vendor, codec_device, q)) {
+ type = "codec SSID";
+ goto found_device;
+ }
+ } else {
+ if (hda_quirk_match(pci_vendor, pci_device, q)) {
+ type = "PCI SSID";
+ goto found_device;
+ }
+ }
}
/* match with the codec SSID */
- q = snd_pci_quirk_lookup_id(codec->core.subsystem_id >> 16,
- codec->core.subsystem_id & 0xffff,
- quirk);
+ q = hda_quirk_lookup_id(codec_vendor, codec_device, quirk);
if (q) {
type = "codec SSID";
goto found_device;
@@ -1046,9 +1093,9 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
#ifdef CONFIG_SND_DEBUG_VERBOSE
name = q->name;
#endif
- codec_dbg(codec, "%s: picked fixup %s for %s %04x:%04x\n",
- codec->core.chip_name, name ? name : "",
- type, q->subvendor, q->subdevice);
+ codec_info(codec, "%s: picked fixup %s for %s %04x:%04x\n",
+ codec->core.chip_name, name ? name : "",
+ type, q->subvendor, q->subdevice);
found:
codec->fixup_id = id;
codec->fixup_list = fixlist;
diff --git a/sound/pci/hda/hda_beep.c b/sound/hda/common/beep.c
index e63621bcb214..13a7d92e8d8d 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/hda/common/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)
@@ -231,7 +234,6 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
codec->beep = beep;
INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
- mutex_init(&beep->mutex);
input_dev = input_allocate_device();
if (!input_dev) {
diff --git a/sound/pci/hda/hda_bind.c b/sound/hda/common/bind.c
index b7ca2a83fbb0..bb1090b65699 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/hda/common/bind.c
@@ -18,10 +18,10 @@
/*
* find a matching codec id
*/
-static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
+static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *drv)
{
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
- struct hda_codec_driver *driver =
+ const struct hda_codec_driver *driver =
container_of(drv, struct hda_codec_driver, core);
const struct hda_device_id *list;
/* check probe_id instead of vendor_id if set */
@@ -42,17 +42,18 @@ static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
{
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
/* ignore unsol events during shutdown */
- if (codec->bus->shutdown)
+ if (codec->card->shutdown || codec->bus->shutdown)
return;
/* ignore unsol events during system suspend/resume */
if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
return;
- if (codec->patch_ops.unsol_event)
- codec->patch_ops.unsol_event(codec, ev);
+ if (driver->ops->unsol_event)
+ driver->ops->unsol_event(codec, ev);
}
/**
@@ -87,7 +88,7 @@ static int hda_codec_driver_probe(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
struct module *owner = dev->driver->owner;
- hda_codec_patch_t patch;
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
int err;
if (codec->bus->core.ext_ops) {
@@ -111,13 +112,14 @@ static int hda_codec_driver_probe(struct device *dev)
goto error;
}
- patch = (hda_codec_patch_t)codec->preset->driver_data;
- if (patch) {
- err = patch(codec);
- if (err < 0)
- goto error_module_put;
+ if (WARN_ON(!(driver->ops && driver->ops->probe))) {
+ err = -EINVAL;
+ goto error_module_put;
}
+ err = driver->ops->probe(codec, codec->preset);
+ if (err < 0)
+ goto error_module_put;
err = snd_hda_codec_build_pcms(codec);
if (err < 0)
goto error_module;
@@ -136,8 +138,8 @@ static int hda_codec_driver_probe(struct device *dev)
return 0;
error_module:
- if (codec->patch_ops.free)
- codec->patch_ops.free(codec);
+ if (driver->ops->remove)
+ driver->ops->remove(codec);
error_module_put:
module_put(owner);
@@ -150,6 +152,7 @@ static int hda_codec_driver_probe(struct device *dev)
static int hda_codec_driver_remove(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
if (codec->bus->core.ext_ops) {
if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
@@ -163,8 +166,8 @@ static int hda_codec_driver_remove(struct device *dev)
wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
snd_power_sync_ref(codec->bus->card);
- if (codec->patch_ops.free)
- codec->patch_ops.free(codec);
+ if (driver->ops->remove)
+ driver->ops->remove(codec);
snd_hda_codec_cleanup_for_unbind(codec);
codec->preset = NULL;
module_put(dev->driver->owner);
@@ -185,7 +188,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;
@@ -305,7 +308,7 @@ static int codec_bind_generic(struct hda_codec *codec)
* @codec: the HDA codec
*
* Start parsing of the given codec tree and (re-)initialize the whole
- * patch instance.
+ * codec driver binding.
*
* Returns 0 if successful or a negative error code.
*/
diff --git a/sound/pci/hda/hda_codec.c b/sound/hda/common/codec.c
index 9f79c0ac2bda..c6d44168c7f9 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/hda/common/codec.c
@@ -8,6 +8,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/pm.h>
@@ -31,6 +32,22 @@
#define codec_has_clkstop(codec) \
((codec)->core.power_caps & AC_PWRST_CLKSTOP)
+static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec,
+ unsigned int cmd, unsigned int flags,
+ unsigned int *res)
+{
+ int err;
+
+ CLASS(snd_hda_power_pm, pm)(codec);
+ guard(mutex)(&bus->core.cmd_mutex);
+ if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
+ bus->no_response_fallback = 1;
+ err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr,
+ cmd, res);
+ bus->no_response_fallback = 0;
+ return err;
+}
+
/*
* Send and receive a verb - passed to exec_verb override for hdac_device
*/
@@ -45,15 +62,7 @@ static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd,
return -1;
again:
- snd_hda_power_up_pm(codec);
- mutex_lock(&bus->core.cmd_mutex);
- if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
- bus->no_response_fallback = 1;
- err = snd_hdac_bus_exec_verb_unlocked(&bus->core, codec->core.addr,
- cmd, res);
- bus->no_response_fallback = 0;
- mutex_unlock(&bus->core.cmd_mutex);
- snd_hda_power_down_pm(codec);
+ err = call_exec_verb(bus, codec, cmd, flags, res);
if (!codec_in_pm(codec) && res && err == -EAGAIN) {
if (bus->response_reset) {
codec_dbg(codec,
@@ -88,7 +97,7 @@ struct hda_conn_list {
struct list_head list;
int len;
hda_nid_t nid;
- hda_nid_t conns[];
+ hda_nid_t conns[] __counted_by(len);
};
/* look up the cached results */
@@ -300,7 +309,7 @@ EXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid)
{
unsigned int wcaps = get_wcaps(codec, nid);
- unsigned int parm;
+ int parm;
if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) ||
get_wcaps_type(wcaps) != AC_WID_PIN)
@@ -323,18 +332,16 @@ EXPORT_SYMBOL_GPL(snd_hda_get_num_devices);
* Copy the device list. This info is dynamic and so not cached.
* Currently called only from hda_proc.c, so not exported.
*/
-int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
- u8 *dev_list, int max_devices)
+unsigned int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
+ u8 *dev_list, unsigned int max_devices)
{
- unsigned int parm;
- int i, dev_len, devices;
+ unsigned int parm, i, dev_len, devices;
parm = snd_hda_get_num_devices(codec, nid);
if (!parm) /* not multi-stream capable */
return 0;
- dev_len = parm + 1;
- dev_len = dev_len < max_devices ? dev_len : max_devices;
+ dev_len = min(parm + 1, max_devices);
devices = 0;
while (devices < dev_len) {
@@ -479,15 +486,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
{
struct hda_pincfg *pin;
- /* the check below may be invalid when pins are added by a fixup
- * dynamically (e.g. via snd_hda_codec_update_widgets()), so disabled
- * for now
- */
- /*
- if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
- return -EINVAL;
- */
-
pin = look_up_pincfg(codec, list, nid);
if (!pin) {
pin = snd_array_new(list);
@@ -532,11 +530,11 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
#ifdef CONFIG_SND_HDA_RECONFIG
{
unsigned int cfg = 0;
- mutex_lock(&codec->user_mutex);
- pin = look_up_pincfg(codec, &codec->user_pins, nid);
- if (pin)
- cfg = pin->cfg;
- mutex_unlock(&codec->user_mutex);
+ scoped_guard(mutex, &codec->user_mutex) {
+ pin = look_up_pincfg(codec, &codec->user_pins, nid);
+ if (pin)
+ cfg = pin->cfg;
+ }
if (cfg)
return cfg;
}
@@ -616,7 +614,6 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_shutup_pins);
-#ifdef CONFIG_PM
/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
static void restore_shutup_pins(struct hda_codec *codec)
{
@@ -634,31 +631,21 @@ static void restore_shutup_pins(struct hda_codec *codec)
}
codec->pins_shutup = 0;
}
-#endif
static void hda_jackpoll_work(struct work_struct *work)
{
struct hda_codec *codec =
container_of(work, struct hda_codec, jackpoll_work.work);
- /* for non-polling trigger: we need nothing if already powered on */
- if (!codec->jackpoll_interval && snd_hdac_is_power_on(&codec->core))
+ if (!codec->jackpoll_interval)
return;
/* the power-up/down sequence triggers the runtime resume */
- snd_hda_power_up_pm(codec);
+ CLASS(snd_hda_power, pm)(codec);
/* update jacks manually if polling is required, too */
- if (codec->jackpoll_interval) {
- snd_hda_jack_set_dirty_all(codec);
- snd_hda_jack_poll_all(codec);
- }
- snd_hda_power_down_pm(codec);
-
- if (!codec->jackpoll_interval)
- return;
-
- schedule_delayed_work(&codec->jackpoll_work,
- codec->jackpoll_interval);
+ snd_hda_jack_set_dirty_all(codec);
+ snd_hda_jack_poll_all(codec);
+ schedule_delayed_work(&codec->jackpoll_work, codec->jackpoll_interval);
}
/* release all pincfg lists */
@@ -785,7 +772,6 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
snd_hda_ctls_clear(codec);
codec_release_pcms(codec);
snd_hda_detach_beep_device(codec);
- memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
snd_hda_jack_tbl_clear(codec);
codec->proc_widget_hook = NULL;
codec->spec = NULL;
@@ -1001,9 +987,7 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
codec->card = card;
codec->addr = codec_addr;
-#ifdef CONFIG_PM
codec->power_jiffies = jiffies;
-#endif
snd_hda_sysfs_init(codec);
@@ -1135,6 +1119,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag,
int channel_id, int format)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hda_codec *c;
struct hda_cvt_setup *p;
int type;
@@ -1150,8 +1135,8 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
if (!p)
return;
- if (codec->patch_ops.stream_pm)
- codec->patch_ops.stream_pm(codec, nid, true);
+ if (driver->ops->stream_pm)
+ driver->ops->stream_pm(codec, nid, true);
if (codec->pcm_format_first)
update_pcm_format(codec, p, nid, format);
update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
@@ -1211,7 +1196,9 @@ EXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream);
static void really_cleanup_stream(struct hda_codec *codec,
struct hda_cvt_setup *q)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
hda_nid_t nid = q->nid;
+
if (q->stream_tag || q->channel_id)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
if (q->format_id)
@@ -1219,8 +1206,8 @@ static void really_cleanup_stream(struct hda_codec *codec,
);
memset(q, 0, sizeof(*q));
q->nid = nid;
- if (codec->patch_ops.stream_pm)
- codec->patch_ops.stream_pm(codec, nid, false);
+ if (driver->ops->stream_pm)
+ driver->ops->stream_pm(codec, nid, false);
}
/* clean up the all conflicting obsolete streams */
@@ -1238,7 +1225,6 @@ static void purify_inactive_streams(struct hda_codec *codec)
}
}
-#ifdef CONFIG_PM
/* clean up all streams; called from suspend */
static void hda_cleanup_all_streams(struct hda_codec *codec)
{
@@ -1250,7 +1236,6 @@ static void hda_cleanup_all_streams(struct hda_codec *codec)
really_cleanup_stream(codec, p);
}
}
-#endif
/*
* amp access functions
@@ -1502,7 +1487,7 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
/* ofs = 0: raw max value */
maxval = get_amp_max_value(codec, nid, dir, 0);
if (val > maxval)
- val = maxval;
+ return -EINVAL;
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
HDA_AMP_VOLMASK, val);
}
@@ -1553,13 +1538,21 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
unsigned int ofs = get_amp_offset(kcontrol);
long *valp = ucontrol->value.integer.value;
int change = 0;
+ int err;
if (chs & 1) {
- change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
+ err = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
+ if (err < 0)
+ return err;
+ change |= err;
valp++;
}
- if (chs & 2)
- change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
+ if (chs & 2) {
+ err = update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
+ if (err < 0)
+ return err;
+ change |= err;
+ }
return change;
}
EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
@@ -1651,7 +1644,7 @@ find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx)
id.index = idx;
if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
return NULL;
- strcpy(id.name, name);
+ strscpy(id.name, name);
return snd_ctl_find_id(codec->card, &id);
}
@@ -1730,37 +1723,6 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
EXPORT_SYMBOL_GPL(snd_hda_ctl_add);
/**
- * snd_hda_add_nid - Assign a NID to a control element
- * @codec: HD-audio codec
- * @nid: corresponding NID (optional)
- * @kctl: the control element to assign
- * @index: index to kctl
- *
- * Add the given control element to an array inside the codec instance.
- * This function is used when #snd_hda_ctl_add cannot be used for 1:1
- * NID:KCTL mapping - for example "Capture Source" selector.
- */
-int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
- unsigned int index, hda_nid_t nid)
-{
- struct hda_nid_item *item;
-
- if (nid > 0) {
- item = snd_array_new(&codec->nids);
- if (!item)
- return -ENOMEM;
- item->kctl = kctl;
- item->index = index;
- item->nid = nid;
- return 0;
- }
- codec_err(codec, "no NID for mapping control %s:%d:%d\n",
- kctl->id.name, kctl->id.index, index);
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(snd_hda_add_nid);
-
-/**
* snd_hda_ctls_clear - Clear all controls assigned to the given codec
* @codec: HD-audio codec
*/
@@ -1769,10 +1731,8 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
int i;
struct hda_nid_item *items = codec->mixers.list;
- down_write(&codec->card->controls_rwsem);
for (i = 0; i < codec->mixers.used; i++)
snd_ctl_remove(codec->card, items[i].kctl);
- up_write(&codec->card->controls_rwsem);
snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
}
@@ -1788,9 +1748,9 @@ int snd_hda_lock_devices(struct hda_bus *bus)
struct snd_card *card = bus->card;
struct hda_codec *codec;
- spin_lock(&card->files_lock);
+ guard(spinlock)(&card->files_lock);
if (card->shutdown)
- goto err_unlock;
+ return -EINVAL;
card->shutdown = 1;
if (!list_empty(&card->ctl_files))
goto err_clear;
@@ -1805,13 +1765,10 @@ int snd_hda_lock_devices(struct hda_bus *bus)
goto err_clear;
}
}
- spin_unlock(&card->files_lock);
return 0;
err_clear:
card->shutdown = 0;
- err_unlock:
- spin_unlock(&card->files_lock);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(snd_hda_lock_devices);
@@ -1824,9 +1781,8 @@ void snd_hda_unlock_devices(struct hda_bus *bus)
{
struct snd_card *card = bus->card;
- spin_lock(&card->files_lock);
+ guard(spinlock)(&card->files_lock);
card->shutdown = 0;
- spin_unlock(&card->files_lock);
}
EXPORT_SYMBOL_GPL(snd_hda_unlock_devices);
@@ -1898,14 +1854,14 @@ static int check_follower_present(struct hda_codec *codec,
/* call kctl->put with the given value(s) */
static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
{
- struct snd_ctl_elem_value *ucontrol;
+ struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL;
+
ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
if (!ucontrol)
return -ENOMEM;
ucontrol->value.integer.value[0] = val;
ucontrol->value.integer.value[1] = val;
kctl->put(kctl, ucontrol);
- kfree(ucontrol);
return 0;
}
@@ -2157,15 +2113,20 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
int change = 0;
if (chs & 1) {
+ if (*valp < 0 || *valp > 1)
+ return -EINVAL;
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
HDA_AMP_MUTE,
*valp ? 0 : HDA_AMP_MUTE);
valp++;
}
- if (chs & 2)
+ if (chs & 2) {
+ if (*valp < 0 || *valp > 1)
+ return -EINVAL;
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
HDA_AMP_MUTE,
*valp ? 0 : HDA_AMP_MUTE);
+ }
hda_call_check_power_status(codec, nid);
return change;
}
@@ -2213,13 +2174,12 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
if (WARN_ON(codec->spdif_out.used <= idx))
return -EINVAL;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
ucontrol->value.iec958.status[0] = spdif->status & 0xff;
ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
@@ -2322,7 +2282,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
if (WARN_ON(codec->spdif_out.used <= idx))
return -EINVAL;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
nid = spdif->nid;
spdif->status = ucontrol->value.iec958.status[0] |
@@ -2335,7 +2295,6 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
spdif->ctls = val;
if (change && nid != (u16)-1)
set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
- mutex_unlock(&codec->spdif_mutex);
return change;
}
@@ -2350,10 +2309,9 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
if (WARN_ON(codec->spdif_out.used <= idx))
return -EINVAL;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
@@ -2380,7 +2338,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
if (WARN_ON(codec->spdif_out.used <= idx))
return -EINVAL;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
nid = spdif->nid;
val = spdif->ctls & ~AC_DIG1_ENABLE;
@@ -2390,7 +2348,6 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
spdif->ctls = val;
if (change && nid != (u16)-1)
set_spdif_ctls(codec, nid, val & 0xff, -1);
- mutex_unlock(&codec->spdif_mutex);
return change;
}
@@ -2433,7 +2390,7 @@ static const struct snd_kcontrol_new dig_mixes[] = {
* @cvt_nid: converter NID
* @type: HDA_PCM_TYPE_*
* Creates controls related with the digital output.
- * Called from each patch supporting the digital out.
+ * Called from each codec driver supporting the digital out.
*
* Returns 0 if successful, or a negative error code.
*/
@@ -2458,10 +2415,16 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
type == HDA_PCM_TYPE_HDMI) {
/* suppose a single SPDIF device */
for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
+ struct snd_ctl_elem_id id;
+
kctl = find_mixer_ctl(codec, dig_mix->name, 0, 0);
if (!kctl)
break;
- kctl->id.index = spdif_index;
+ id = kctl->id;
+ id.index = spdif_index;
+ err = snd_ctl_rename_id(codec->card, &kctl->id, &id);
+ if (err < 0)
+ return err;
}
bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
}
@@ -2529,10 +2492,9 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
if (WARN_ON(codec->spdif_out.used <= idx))
return;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
spdif->nid = (u16)-1;
- mutex_unlock(&codec->spdif_mutex);
}
EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign);
@@ -2551,14 +2513,13 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
if (WARN_ON(codec->spdif_out.used <= idx))
return;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
spdif = snd_array_elem(&codec->spdif_out, idx);
if (spdif->nid != nid) {
spdif->nid = nid;
val = spdif->ctls;
set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
}
- mutex_unlock(&codec->spdif_mutex);
}
EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign);
@@ -2633,14 +2594,13 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,
unsigned int val = !!ucontrol->value.integer.value[0];
int change;
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
change = codec->spdif_in_enable != val;
if (change) {
codec->spdif_in_enable = val;
snd_hdac_regmap_write(&codec->core, nid,
AC_VERB_SET_DIGI_CONVERT_1, val);
}
- mutex_unlock(&codec->spdif_mutex);
return change;
}
@@ -2686,7 +2646,7 @@ static const struct snd_kcontrol_new dig_in_ctls[] = {
* @nid: audio in widget NID
*
* Creates controls related with the SPDIF input.
- * Called from each patch supporting the SPDIF in.
+ * Called from each codec driver supporting the SPDIF in.
*
* Returns 0 if successful, or a negative error code.
*/
@@ -2783,6 +2743,7 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter);
static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
hda_nid_t fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
int count;
unsigned int state;
@@ -2799,9 +2760,9 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
/* repeat power states setting at most 10 times*/
for (count = 0; count < 10; count++) {
- if (codec->patch_ops.set_power_state)
- codec->patch_ops.set_power_state(codec, fg,
- power_state);
+ /* might be called before binding to driver, too */
+ if (driver && driver->ops && driver->ops->set_power_state)
+ driver->ops->set_power_state(codec, fg, power_state);
else {
state = power_state;
if (codec->power_filter)
@@ -2856,7 +2817,6 @@ static void hda_exec_init_verbs(struct hda_codec *codec)
static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
#endif
-#ifdef CONFIG_PM
/* update the power on/off account with the current jiffies */
static void update_power_acct(struct hda_codec *codec, bool on)
{
@@ -2880,11 +2840,12 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
*/
static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
unsigned int state;
snd_hdac_enter_pm(&codec->core);
- if (codec->patch_ops.suspend)
- codec->patch_ops.suspend(codec);
+ if (driver->ops->suspend)
+ driver->ops->suspend(codec);
if (!codec->no_stream_clean_at_suspend)
hda_cleanup_all_streams(codec);
state = hda_set_power_state(codec, AC_PWRST_D3);
@@ -2898,6 +2859,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
*/
static void hda_call_codec_resume(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
snd_hdac_enter_pm(&codec->core);
if (codec->core.regmap)
regcache_mark_dirty(codec->core.regmap);
@@ -2908,20 +2871,19 @@ static void hda_call_codec_resume(struct hda_codec *codec)
restore_shutup_pins(codec);
hda_exec_init_verbs(codec);
snd_hda_jack_set_dirty_all(codec);
- if (codec->patch_ops.resume)
- codec->patch_ops.resume(codec);
+ if (driver->ops->resume)
+ driver->ops->resume(codec);
else {
- if (codec->patch_ops.init)
- codec->patch_ops.init(codec);
+ snd_hda_codec_init(codec);
snd_hda_regmap_sync(codec);
}
- if (codec->jackpoll_interval)
- hda_jackpoll_work(&codec->jackpoll_work.work);
- else
- snd_hda_jack_report_sync(codec);
+ snd_hda_jack_report_sync(codec);
codec->core.dev.power.power_state = PMSG_ON;
snd_hdac_leave_pm(&codec->core);
+ if (codec->jackpoll_interval)
+ schedule_delayed_work(&codec->jackpoll_work,
+ codec->jackpoll_interval);
}
static int hda_codec_runtime_suspend(struct device *dev)
@@ -2933,8 +2895,6 @@ static int hda_codec_runtime_suspend(struct device *dev)
if (!codec->card)
return 0;
- cancel_delayed_work_sync(&codec->jackpoll_work);
-
state = hda_call_codec_suspend(codec);
if (codec->link_down_at_suspend ||
(codec_has_clkstop(codec) && codec_has_epss(codec) &&
@@ -2942,10 +2902,6 @@ static int hda_codec_runtime_suspend(struct device *dev)
snd_hdac_codec_link_down(&codec->core);
snd_hda_codec_display_power(codec, false);
- if (codec->bus->jackpoll_in_suspend &&
- (dev->power.power_state.event != PM_EVENT_SUSPEND))
- schedule_delayed_work(&codec->jackpoll_work,
- codec->jackpoll_interval);
return 0;
}
@@ -2964,9 +2920,15 @@ static int hda_codec_runtime_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM */
+static int hda_codec_runtime_idle(struct device *dev)
+{
+ struct hda_codec *codec = dev_to_hda_codec(dev);
+
+ if (codec->jackpoll_interval && !codec->bus->jackpoll_in_suspend)
+ return -EBUSY;
+ return 0;
+}
-#ifdef CONFIG_PM_SLEEP
static int hda_codec_pm_prepare(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
@@ -3021,22 +2983,19 @@ static int hda_codec_pm_restore(struct device *dev)
dev->power.power_state = PMSG_RESTORE;
return pm_runtime_force_resume(dev);
}
-#endif /* CONFIG_PM_SLEEP */
/* referred in hda_bind.c */
const struct dev_pm_ops hda_codec_driver_pm = {
-#ifdef CONFIG_PM_SLEEP
- .prepare = hda_codec_pm_prepare,
- .complete = hda_codec_pm_complete,
- .suspend = hda_codec_pm_suspend,
- .resume = hda_codec_pm_resume,
- .freeze = hda_codec_pm_freeze,
- .thaw = hda_codec_pm_thaw,
- .poweroff = hda_codec_pm_suspend,
- .restore = hda_codec_pm_restore,
-#endif /* CONFIG_PM_SLEEP */
- SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume,
- NULL)
+ .prepare = pm_sleep_ptr(hda_codec_pm_prepare),
+ .complete = pm_sleep_ptr(hda_codec_pm_complete),
+ .suspend = pm_sleep_ptr(hda_codec_pm_suspend),
+ .resume = pm_sleep_ptr(hda_codec_pm_resume),
+ .freeze = pm_sleep_ptr(hda_codec_pm_freeze),
+ .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_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume,
+ hda_codec_runtime_idle)
};
/* suspend the codec at shutdown; called from driver's shutdown callback */
@@ -3048,6 +3007,7 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)
if (!codec->core.registered)
return;
+ codec->jackpoll_interval = 0; /* don't poll any longer */
cancel_delayed_work_sync(&codec->jackpoll_work);
list_for_each_entry(cpcm, &codec->pcm_list_head, list)
snd_pcm_suspend_all(cpcm->pcm);
@@ -3099,25 +3059,31 @@ EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps);
int snd_hda_codec_build_controls(struct hda_codec *codec)
{
- int err = 0;
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+ int err;
+
hda_exec_init_verbs(codec);
/* continue to initialize... */
- if (codec->patch_ops.init)
- err = codec->patch_ops.init(codec);
- if (!err && codec->patch_ops.build_controls)
- err = codec->patch_ops.build_controls(codec);
+ err = snd_hda_codec_init(codec);
if (err < 0)
return err;
+ if (driver->ops->build_controls) {
+ err = driver->ops->build_controls(codec);
+ if (err < 0)
+ return err;
+ }
+
/* we create chmaps here instead of build_pcms */
err = add_std_chmaps(codec);
if (err < 0)
return err;
+ snd_hda_jack_report_sync(codec); /* call at the last init point */
if (codec->jackpoll_interval)
- hda_jackpoll_work(&codec->jackpoll_work.work);
- else
- snd_hda_jack_report_sync(codec); /* call at the last init point */
+ schedule_delayed_work(&codec->jackpoll_work,
+ codec->jackpoll_interval);
+
sync_power_up_states(codec);
return 0;
}
@@ -3161,6 +3127,7 @@ static int set_pcm_default_values(struct hda_codec *codec,
err = snd_hda_query_supported_pcm(codec, info->nid,
info->rates ? NULL : &info->rates,
info->formats ? NULL : &info->formats,
+ info->subformats ? NULL : &info->subformats,
info->maxbps ? NULL : &info->maxbps);
if (err < 0)
return err;
@@ -3203,7 +3170,8 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
int ret;
- mutex_lock(&codec->bus->prepare_mutex);
+
+ guard(mutex)(&codec->bus->prepare_mutex);
if (hinfo->ops.prepare)
ret = hinfo->ops.prepare(hinfo, codec, stream, format,
substream);
@@ -3211,7 +3179,6 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
ret = -ENODEV;
if (ret >= 0)
purify_inactive_streams(codec);
- mutex_unlock(&codec->bus->prepare_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_hda_codec_prepare);
@@ -3228,10 +3195,9 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
- mutex_lock(&codec->bus->prepare_mutex);
+ guard(mutex)(&codec->bus->prepare_mutex);
if (hinfo->ops.cleanup)
hinfo->ops.cleanup(hinfo, codec, substream);
- mutex_unlock(&codec->bus->prepare_mutex);
}
EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
@@ -3291,16 +3257,17 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
/* call build_pcms ops of the given codec and set up the default parameters */
int snd_hda_codec_parse_pcms(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hda_pcm *cpcm;
int err;
if (!list_empty(&codec->pcm_list_head))
return 0; /* already parsed */
- if (!codec->patch_ops.build_pcms)
+ if (!driver->ops->build_pcms)
return 0;
- err = codec->patch_ops.build_pcms(codec);
+ err = driver->ops->build_pcms(codec);
if (err < 0) {
codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
codec->core.addr, err);
@@ -3310,7 +3277,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
int stream;
- for (stream = 0; stream < 2; stream++) {
+ for_each_pcm_streams(stream) {
struct hda_pcm_stream *info = &cpcm->stream[stream];
if (!info->substreams)
@@ -3422,7 +3389,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
-#ifdef CONFIG_PM
/**
* snd_hda_codec_set_power_save - Configure codec's runtime PM
* @codec: codec device to configure
@@ -3513,7 +3479,6 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
-#endif
/*
* input MUX helper
@@ -3537,7 +3502,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux,
index = uinfo->value.enumerated.item;
if (index >= imux->num_items)
index = imux->num_items - 1;
- strcpy(uinfo->value.enumerated.name, imux->items[index].label);
+ strscpy(uinfo->value.enumerated.name, imux->items[index].label);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_input_mux_info);
@@ -3662,12 +3627,11 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
int snd_hda_multi_out_dig_open(struct hda_codec *codec,
struct hda_multi_out *mout)
{
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
/* already opened as analog dup; reset it once */
cleanup_dig_out_stream(codec, mout->dig_out_nid);
mout->dig_out_used = HDA_DIG_EXCLUSIVE;
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open);
@@ -3686,9 +3650,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
unsigned int format,
struct snd_pcm_substream *substream)
{
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
@@ -3701,9 +3664,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
struct hda_multi_out *mout)
{
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
cleanup_dig_out_stream(codec, mout->dig_out_nid);
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);
@@ -3716,9 +3678,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);
int snd_hda_multi_out_dig_close(struct hda_codec *codec,
struct hda_multi_out *mout)
{
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
mout->dig_out_used = 0;
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close);
@@ -3755,9 +3716,10 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
&mout->spdif_rates,
&mout->spdif_formats,
+ NULL,
&mout->spdif_maxbps);
}
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
if (mout->share_spdif) {
if ((runtime->hw.rates & mout->spdif_rates) &&
(runtime->hw.formats & mout->spdif_formats)) {
@@ -3770,7 +3732,6 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
/* FIXME: need notify? */
}
}
- mutex_unlock(&codec->spdif_mutex);
}
return snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
@@ -3799,23 +3760,23 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
struct hda_spdif_out *spdif;
int i;
- mutex_lock(&codec->spdif_mutex);
- spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
- if (mout->dig_out_nid && mout->share_spdif &&
- mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
- if (chs == 2 && spdif != NULL &&
- snd_hda_is_supported_format(codec, mout->dig_out_nid,
- format) &&
- !(spdif->status & IEC958_AES0_NONAUDIO)) {
- mout->dig_out_used = HDA_DIG_ANALOG_DUP;
- setup_dig_out_stream(codec, mout->dig_out_nid,
- stream_tag, format);
- } else {
- mout->dig_out_used = 0;
- cleanup_dig_out_stream(codec, mout->dig_out_nid);
+ scoped_guard(mutex, &codec->spdif_mutex) {
+ spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
+ if (mout->dig_out_nid && mout->share_spdif &&
+ mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+ if (chs == 2 && spdif != NULL &&
+ snd_hda_is_supported_format(codec, mout->dig_out_nid,
+ format) &&
+ !(spdif->status & IEC958_AES0_NONAUDIO)) {
+ mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+ setup_dig_out_stream(codec, mout->dig_out_nid,
+ stream_tag, format);
+ } else {
+ mout->dig_out_used = 0;
+ cleanup_dig_out_stream(codec, mout->dig_out_nid);
+ }
}
}
- mutex_unlock(&codec->spdif_mutex);
/* front */
snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
@@ -3882,12 +3843,11 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
if (mout->extra_out_nid[i])
snd_hda_codec_cleanup_stream(codec,
mout->extra_out_nid[i]);
- mutex_lock(&codec->spdif_mutex);
+ guard(mutex)(&codec->spdif_mutex);
if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
cleanup_dig_out_stream(codec, mout->dig_out_nid);
mout->dig_out_used = 0;
}
- mutex_unlock(&codec->spdif_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup);
@@ -4056,12 +4016,10 @@ void snd_hda_bus_reset_codecs(struct hda_bus *bus)
/* FIXME: maybe a better way needed for forced reset */
if (current_work() != &codec->jackpoll_work.work)
cancel_delayed_work_sync(&codec->jackpoll_work);
-#ifdef CONFIG_PM
if (hda_codec_is_power_on(codec)) {
hda_call_codec_suspend(codec);
hda_call_codec_resume(codec);
}
-#endif
}
}
diff --git a/sound/pci/hda/hda_controller.c b/sound/hda/common/controller.c
index 406779625fb5..b1cfd9bd4dcb 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/hda/common/controller.c
@@ -3,7 +3,7 @@
*
* Implementation of primary alsa driver code base for Intel HD Audio.
*
- * Copyright(c) 2004 Intel Corporation. All rights reserved.
+ * Copyright(c) 2004 Intel Corporation
*
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
* PeiSen Hou <pshou@realtek.com.tw>
@@ -24,15 +24,19 @@
#include <sound/core.h>
#include <sound/initval.h>
+#include <sound/pcm_params.h>
#include "hda_controller.h"
#include "hda_local.h"
#define CREATE_TRACE_POINTS
-#include "hda_controller_trace.h"
+#include "controller_trace.h"
/* DSP lock helpers */
-#define dsp_lock(dev) snd_hdac_dsp_lock(azx_stream(dev))
-#define dsp_unlock(dev) snd_hdac_dsp_unlock(azx_stream(dev))
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+#define guard_dsp_lock(dev) guard(snd_hdac_dsp_lock)(azx_stream(dev))
+#else
+#define guard_dsp_lock(dev) do {} while (0)
+#endif
#define dsp_is_locked(dev) snd_hdac_stream_is_locked(azx_stream(dev))
/* assign a stream for the PCM */
@@ -92,12 +96,12 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
struct azx_dev *azx_dev = get_azx_dev(substream);
trace_azx_pcm_close(chip, azx_dev);
- mutex_lock(&chip->open_mutex);
- azx_release_device(azx_dev);
- if (hinfo->ops.close)
- hinfo->ops.close(hinfo, apcm->codec, substream);
- snd_hda_power_down(apcm->codec);
- mutex_unlock(&chip->open_mutex);
+ scoped_guard(mutex, &chip->open_mutex) {
+ azx_release_device(azx_dev);
+ if (hinfo->ops.close)
+ hinfo->ops.close(hinfo, apcm->codec, substream);
+ snd_hda_power_down(apcm->codec);
+ }
snd_hda_codec_pcm_put(apcm->info);
return 0;
}
@@ -108,22 +112,24 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
- int ret = 0;
+ struct hdac_stream *hdas = azx_stream(azx_dev);
trace_azx_pcm_hw_params(chip, azx_dev);
- dsp_lock(azx_dev);
- if (dsp_is_locked(azx_dev)) {
- ret = -EBUSY;
- goto unlock;
- }
-
- azx_dev->core.bufsize = 0;
- azx_dev->core.period_bytes = 0;
- azx_dev->core.format_val = 0;
+ guard_dsp_lock(azx_dev);
+ if (dsp_is_locked(azx_dev))
+ return -EBUSY;
+
+ /* Set up BDLEs here, return -ENOMEM if too many BDLEs are required */
+ hdas->bufsize = params_buffer_bytes(hw_params);
+ hdas->period_bytes = params_period_bytes(hw_params);
+ hdas->format_val = 0;
+ hdas->no_period_wakeup =
+ (hw_params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+ (hw_params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
+ if (snd_hdac_stream_setup_periods(hdas) < 0)
+ return -ENOMEM;
-unlock:
- dsp_unlock(azx_dev);
- return ret;
+ return 0;
}
static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
@@ -133,14 +139,13 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
/* reset BDL address */
- dsp_lock(azx_dev);
+ guard_dsp_lock(azx_dev);
if (!dsp_is_locked(azx_dev))
snd_hdac_stream_cleanup(azx_stream(azx_dev));
snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
azx_stream(azx_dev)->prepared = 0;
- dsp_unlock(azx_dev);
return 0;
}
@@ -151,38 +156,33 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
struct azx_dev *azx_dev = get_azx_dev(substream);
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int format_val, stream_tag;
+ unsigned int format_val, stream_tag, bits;
int err;
struct hda_spdif_out *spdif =
snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
unsigned short ctls = spdif ? spdif->ctls : 0;
trace_azx_pcm_prepare(chip, azx_dev);
- dsp_lock(azx_dev);
- if (dsp_is_locked(azx_dev)) {
- err = -EBUSY;
- goto unlock;
- }
+ guard_dsp_lock(azx_dev);
+ if (dsp_is_locked(azx_dev))
+ return -EBUSY;
snd_hdac_stream_reset(azx_stream(azx_dev));
- format_val = snd_hdac_calc_stream_format(runtime->rate,
- runtime->channels,
- runtime->format,
- hinfo->maxbps,
- ctls);
+ bits = snd_hdac_stream_format_bits(runtime->format, SNDRV_PCM_SUBFORMAT_STD, hinfo->maxbps);
+
+ format_val = snd_hdac_spdif_stream_format(runtime->channels, bits, runtime->rate, ctls);
if (!format_val) {
dev_err(chip->card->dev,
"invalid format_val, rate=%d, ch=%d, format=%d\n",
runtime->rate, runtime->channels, runtime->format);
- err = -EINVAL;
- goto unlock;
+ return -EINVAL;
}
err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val);
if (err < 0)
- goto unlock;
+ return err;
- snd_hdac_stream_setup(azx_stream(azx_dev));
+ snd_hdac_stream_setup(azx_stream(azx_dev), false);
stream_tag = azx_dev->core.stream_tag;
/* CA-IBG chips need the playback stream starting from 1 */
@@ -191,12 +191,11 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
stream_tag -= chip->capture_streams;
err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
azx_dev->core.format_val, substream);
+ if (err < 0)
+ return err;
- unlock:
- if (!err)
- azx_stream(azx_dev)->prepared = 1;
- dsp_unlock(azx_dev);
- return err;
+ azx_stream(azx_dev)->prepared = 1;
+ return 0;
}
static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -246,32 +245,29 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_pcm_trigger_done(s, substream);
}
- spin_lock(&bus->reg_lock);
-
- /* first, set SYNC bits of corresponding streams */
- snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg);
+ scoped_guard(spinlock, &bus->reg_lock) {
+ /* first, set SYNC bits of corresponding streams */
+ snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg);
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- azx_dev = get_azx_dev(s);
- if (start) {
- azx_dev->insufficient = 1;
- snd_hdac_stream_start(azx_stream(azx_dev));
- } else {
- snd_hdac_stream_stop(azx_stream(azx_dev));
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_dev = get_azx_dev(s);
+ if (start) {
+ azx_dev->insufficient = 1;
+ snd_hdac_stream_start(azx_stream(azx_dev));
+ } else {
+ snd_hdac_stream_stop(azx_stream(azx_dev));
+ }
}
}
- spin_unlock(&bus->reg_lock);
snd_hdac_stream_sync(hstr, start, sbits);
- spin_lock(&bus->reg_lock);
+ guard(spinlock)(&bus->reg_lock);
/* reset SYNC bits */
snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg);
- if (start)
- snd_hdac_stream_timecounter_init(hstr, sbits);
- spin_unlock(&bus->reg_lock);
+ snd_hdac_stream_timecounter_init(hstr, sbits, start);
return 0;
}
@@ -457,7 +453,8 @@ static int azx_get_sync_time(ktime_t *device,
*device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) /
((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate));
- *system = convert_art_to_tsc(tsc_counter);
+ system->cycles = tsc_counter;
+ system->cs_id = CSID_X86_ART;
return 0;
}
@@ -908,7 +905,7 @@ static int azx_send_cmd(struct hdac_bus *bus, unsigned int val)
if (chip->disabled)
return 0;
- if (chip->single_cmd)
+ if (chip->single_cmd || bus->use_pio_for_commands)
return azx_single_send_cmd(bus, val);
else
return snd_hdac_bus_send_cmd(bus, val);
@@ -922,7 +919,7 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,
if (chip->disabled)
return 0;
- if (chip->single_cmd)
+ if (chip->single_cmd || bus->use_pio_for_commands)
return azx_single_get_response(bus, addr, res);
else
return azx_rirb_get_response(bus, addr, res);
@@ -965,19 +962,18 @@ int snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
azx_dev = azx_get_dsp_loader_dev(chip);
hstr = azx_stream(azx_dev);
- spin_lock_irq(&bus->reg_lock);
- if (hstr->opened) {
- chip->saved_azx_dev = *azx_dev;
- saved = true;
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ if (hstr->opened) {
+ chip->saved_azx_dev = *azx_dev;
+ saved = true;
+ }
}
- spin_unlock_irq(&bus->reg_lock);
err = snd_hdac_dsp_prepare(hstr, format, byte_size, bufp);
if (err < 0) {
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
if (saved)
*azx_dev = chip->saved_azx_dev;
- spin_unlock_irq(&bus->reg_lock);
return err;
}
@@ -1008,11 +1004,10 @@ void snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
return;
snd_hdac_dsp_cleanup(hstr, dmab);
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
if (hstr->opened)
*azx_dev = chip->saved_azx_dev;
hstr->locked = false;
- spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_cleanup);
#endif /* CONFIG_SND_HDA_DSP_LOADER */
@@ -1069,16 +1064,14 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
bool active, handled = false;
int repeat = 0; /* count for avoiding endless loop */
-#ifdef CONFIG_PM
if (azx_has_pm_runtime(chip))
if (!pm_runtime_active(chip->card->dev))
return IRQ_NONE;
-#endif
- spin_lock(&bus->reg_lock);
+ guard(spinlock)(&bus->reg_lock);
if (chip->disabled)
- goto unlock;
+ return IRQ_NONE;
do {
status = azx_readl(chip, INTSTS);
@@ -1110,9 +1103,6 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
}
} while (active && ++repeat < 10);
- unlock:
- spin_unlock(&bus->reg_lock);
-
return IRQ_RETVAL(handled);
}
EXPORT_SYMBOL_GPL(azx_interrupt);
@@ -1132,12 +1122,12 @@ static int probe_codec(struct azx *chip, int addr)
int err;
unsigned int res = -1;
- mutex_lock(&bus->cmd_mutex);
- chip->probing = 1;
- azx_send_cmd(bus, cmd);
- err = azx_get_response(bus, addr, &res);
- chip->probing = 0;
- mutex_unlock(&bus->cmd_mutex);
+ scoped_guard(mutex, &bus->cmd_mutex) {
+ chip->probing = 1;
+ azx_send_cmd(bus, cmd);
+ err = azx_get_response(bus, addr, &res);
+ chip->probing = 0;
+ }
if (err < 0 || res == -1)
return -EIO;
dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
@@ -1182,6 +1172,9 @@ int azx_bus_init(struct azx *chip, const char *model)
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY)
bus->core.align_bdle_4k = true;
+ if (chip->driver_caps & AZX_DCAPS_PIO_COMMANDS)
+ bus->core.use_pio_for_commands = true;
+
/* enable sync_write flag for stable communication as default */
bus->core.sync_write = 1;
@@ -1209,6 +1202,9 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
dev_warn(chip->card->dev,
"Codec #%d probe error; disabling it...\n", c);
bus->codec_mask &= ~(1 << c);
+ /* no codecs */
+ if (bus->codec_mask == 0)
+ break;
/* More badly, accessing to a non-existing
* codec often screws up the controller chip,
* and disturbs the further communications.
diff --git a/sound/pci/hda/hda_controller_trace.h b/sound/hda/common/controller_trace.h
index bf48304e230a..7f5841f8919e 100644
--- a/sound/pci/hda/hda_controller_trace.h
+++ b/sound/hda/common/controller_trace.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hda_controller
-#define TRACE_INCLUDE_FILE hda_controller_trace
+#define TRACE_INCLUDE_FILE controller_trace
#if !defined(_TRACE_HDA_CONTROLLER_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HDA_CONTROLLER_H
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/hda/common/hda_auto_parser.h
index df63d66af1ab..87af3d8c02f7 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/hda/common/hda_auto_parser.h
@@ -8,6 +8,8 @@
#ifndef __SOUND_HDA_AUTO_PARSER_H
#define __SOUND_HDA_AUTO_PARSER_H
+#include "hda_local.h"
+
/*
* Helper for automatic pin configuration
*/
@@ -35,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.h b/sound/hda/common/hda_beep.h
index db76e3ddba65..923ea862446a 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/hda/common/hda_beep.h
@@ -27,7 +27,6 @@ struct hda_beep {
unsigned int playing:1;
unsigned int keep_power_at_enable:1; /* set by driver */
struct work_struct beep_work; /* scheduled task for beep event */
- struct mutex mutex;
void (*power_hook)(struct hda_beep *beep, bool on);
};
diff --git a/sound/pci/hda/hda_controller.h b/sound/hda/common/hda_controller.h
index 8556031bcd68..c2d0109866e6 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/hda/common/hda_controller.h
@@ -45,6 +45,7 @@
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
+#define AZX_DCAPS_PIO_COMMANDS (1 << 31) /* Use PIO instead of CORB for commands */
enum {
AZX_SNOOP_TYPE_NONE,
diff --git a/sound/pci/hda/hda_jack.h b/sound/hda/common/hda_jack.h
index ff7d289c034b..ff7d289c034b 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/hda/common/hda_jack.h
diff --git a/sound/pci/hda/hda_local.h b/sound/hda/common/hda_local.h
index 53a5a62b78fa..a7e53277a0fe 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/hda/common/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.
@@ -292,6 +294,32 @@ struct hda_fixup {
} v;
};
+/*
+ * extended form of snd_pci_quirk:
+ * for PCI SSID matching, use SND_PCI_QUIRK() like before;
+ * for codec SSID matching, use the new HDA_CODEC_QUIRK() instead
+ */
+struct hda_quirk {
+ unsigned short subvendor; /* PCI subvendor ID */
+ unsigned short subdevice; /* PCI subdevice ID */
+ unsigned short subdevice_mask; /* bitmask to match */
+ bool match_codec_ssid; /* match only with codec SSID */
+ int value; /* value */
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ const char *name; /* name of the device (optional) */
+#endif
+};
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+#define HDA_CODEC_QUIRK(vend, dev, xname, val) \
+ { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname),\
+ .match_codec_ssid = true }
+#else
+#define HDA_CODEC_QUIRK(vend, dev, xname, val) \
+ { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), \
+ .match_codec_ssid = true }
+#endif
+
struct snd_hda_pin_quirk {
unsigned int codec; /* Codec vendor/device ID */
unsigned short subvendor; /* PCI subvendor ID */
@@ -351,7 +379,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action);
void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth);
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
- const struct snd_pci_quirk *quirk,
+ const struct hda_quirk *quirk,
const struct hda_fixup *fixlist);
void snd_hda_pick_pin_fixup(struct hda_codec *codec,
const struct snd_hda_pin_quirk *pin_quirk,
@@ -543,8 +571,6 @@ struct hda_nid_item {
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol *kctl);
-int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
- unsigned int index, hda_nid_t nid);
void snd_hda_ctls_clear(struct hda_codec *codec);
/*
@@ -626,6 +652,15 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
void snd_hda_codec_shutdown(struct hda_codec *codec);
+static inline int snd_hda_codec_init(struct hda_codec *codec)
+{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
+ if (driver->ops->init)
+ return driver->ops->init(codec);
+ return 0;
+}
+
/*
* AMP control callbacks
*/
@@ -649,67 +684,20 @@ 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,
- unsigned char *buf, int *eld_size,
- bool rev3_or_later);
-
#ifdef CONFIG_SND_PROC_FS
void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
struct snd_info_buffer *buffer,
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/hda/common/hwdep.c
index 125e97fe0b1c..9325e5c3cbe6 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/hda/common/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;
}
@@ -114,8 +112,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
#endif
/* for sysfs */
- hwdep->dev.groups = snd_hda_dev_attr_groups;
- dev_set_drvdata(&hwdep->dev, codec);
+ hwdep->dev->groups = snd_hda_dev_attr_groups;
+ dev_set_drvdata(hwdep->dev, codec);
return 0;
}
diff --git a/sound/pci/hda/hda_jack.c b/sound/hda/common/jack.c
index 7d7786df60ea..7d7786df60ea 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/hda/common/jack.c
diff --git a/sound/pci/hda/hda_proc.c b/sound/hda/common/proc.c
index 00c2eeb2c472..5f3f61519ba6 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/hda/common/proc.c
@@ -716,16 +716,15 @@ static void print_device_list(struct snd_info_buffer *buffer,
{
int i, curr = -1;
u8 dev_list[AC_MAX_DEV_LIST_LEN];
- int devlist_len;
+ unsigned int devlist_len;
devlist_len = snd_hda_get_devices(codec, nid, dev_list,
AC_MAX_DEV_LIST_LEN);
- snd_iprintf(buffer, " Devices: %d\n", devlist_len);
- if (devlist_len <= 0)
+ snd_iprintf(buffer, " Devices: %u\n", devlist_len);
+ if (devlist_len == 0)
return;
- curr = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_DEVICE_SEL, 0);
+ curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DEVICE_SEL, 0);
for (i = 0; i < devlist_len; i++) {
if (i == curr)
@@ -782,7 +781,7 @@ static void print_codec_info(struct snd_info_entry *entry,
fg = codec->core.afg;
if (!fg)
return;
- snd_hda_power_up(codec);
+ CLASS(snd_hda_power, pm)(codec);
snd_iprintf(buffer, "Default PCM:\n");
print_pcm_caps(buffer, codec, fg);
snd_iprintf(buffer, "Default Amp-In caps: ");
@@ -795,7 +794,6 @@ static void print_codec_info(struct snd_info_entry *entry,
nodes = snd_hda_get_sub_nodes(codec, fg, &nid);
if (! nid || nodes < 0) {
snd_iprintf(buffer, "Invalid AFG subtree\n");
- snd_hda_power_down(codec);
return;
}
@@ -932,7 +930,6 @@ static void print_codec_info(struct snd_info_entry *entry,
kfree(conn);
}
- snd_hda_power_down(codec);
}
/*
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/hda/common/sysfs.c
index 69ebc37a4d6f..f8c8483fd5e5 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/hda/common/sysfs.c
@@ -26,7 +26,6 @@ struct hda_hint {
const char *val; /* contained in the same alloc as key */
};
-#ifdef CONFIG_PM
static ssize_t power_on_acct_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -47,7 +46,6 @@ static ssize_t power_off_acct_show(struct device *dev,
static DEVICE_ATTR_RO(power_on_acct);
static DEVICE_ATTR_RO(power_off_acct);
-#endif /* CONFIG_PM */
#define CODEC_INFO_SHOW(type, field) \
static ssize_t type##_show(struct device *dev, \
@@ -83,12 +81,12 @@ static ssize_t pin_configs_show(struct hda_codec *codec,
{
const struct hda_pincfg *pin;
int i, len = 0;
- mutex_lock(&codec->user_mutex);
+
+ guard(mutex)(&codec->user_mutex);
snd_array_for_each(list, i, pin) {
len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n",
pin->nid, pin->cfg);
}
- mutex_unlock(&codec->user_mutex);
return len;
}
@@ -131,21 +129,18 @@ static int reconfig_codec(struct hda_codec *codec)
{
int err;
- snd_hda_power_up(codec);
+ CLASS(snd_hda_power, pm)(codec);
codec_info(codec, "hda-codec: reconfiguring\n");
err = snd_hda_codec_reset(codec);
if (err < 0) {
codec_err(codec,
"The codec is being used, can't reconfigure.\n");
- goto error;
+ return err;
}
err = device_reprobe(hda_codec_dev(codec));
if (err < 0)
- goto error;
- err = snd_card_register(codec->card);
- error:
- snd_hda_power_down(codec);
- return err;
+ return err;
+ return snd_card_register(codec->card);
}
/*
@@ -220,12 +215,12 @@ static ssize_t init_verbs_show(struct device *dev,
struct hda_codec *codec = dev_get_drvdata(dev);
const struct hda_verb *v;
int i, len = 0;
- mutex_lock(&codec->user_mutex);
+
+ guard(mutex)(&codec->user_mutex);
snd_array_for_each(&codec->init_verbs, i, v) {
len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n",
v->nid, v->verb, v->param);
}
- mutex_unlock(&codec->user_mutex);
return len;
}
@@ -238,16 +233,13 @@ static int parse_init_verbs(struct hda_codec *codec, const char *buf)
return -EINVAL;
if (!nid || !verb)
return -EINVAL;
- mutex_lock(&codec->user_mutex);
+ guard(mutex)(&codec->user_mutex);
v = snd_array_new(&codec->init_verbs);
- if (!v) {
- mutex_unlock(&codec->user_mutex);
+ if (!v)
return -ENOMEM;
- }
v->nid = nid;
v->verb = verb;
v->param = param;
- mutex_unlock(&codec->user_mutex);
return 0;
}
@@ -269,12 +261,12 @@ static ssize_t hints_show(struct device *dev,
struct hda_codec *codec = dev_get_drvdata(dev);
const struct hda_hint *hint;
int i, len = 0;
- mutex_lock(&codec->user_mutex);
+
+ guard(mutex)(&codec->user_mutex);
snd_array_for_each(&codec->hints, i, hint) {
len += sysfs_emit_at(buf, len, "%s = %s\n",
hint->key, hint->val);
}
- mutex_unlock(&codec->user_mutex);
return len;
}
@@ -307,9 +299,9 @@ static void remove_trail_spaces(char *str)
static int parse_hints(struct hda_codec *codec, const char *buf)
{
- char *key, *val;
+ char *key __free(kfree) = NULL;
+ char *val;
struct hda_hint *hint;
- int err = 0;
buf = skip_spaces(buf);
if (!*buf || *buf == '#' || *buf == '\n')
@@ -321,39 +313,29 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
return -ENOMEM;
/* extract key and val */
val = strchr(key, '=');
- if (!val) {
- kfree(key);
+ if (!val)
return -EINVAL;
- }
*val++ = 0;
val = skip_spaces(val);
remove_trail_spaces(key);
remove_trail_spaces(val);
- mutex_lock(&codec->user_mutex);
+ guard(mutex)(&codec->user_mutex);
hint = get_hint(codec, key);
if (hint) {
/* replace */
kfree(hint->key);
- hint->key = key;
- hint->val = val;
- goto unlock;
+ goto replace;
}
/* allocate a new hint entry */
if (codec->hints.used >= MAX_HINTS)
- hint = NULL;
- else
- hint = snd_array_new(&codec->hints);
- if (hint) {
- hint->key = key;
- hint->val = val;
- } else {
- err = -ENOMEM;
- }
- unlock:
- mutex_unlock(&codec->user_mutex);
- if (err)
- kfree(key);
- return err;
+ return -ENOMEM;
+ hint = snd_array_new(&codec->hints);
+ if (!hint)
+ return -ENOMEM;
+ replace:
+ hint->key = no_free_ptr(key);
+ hint->val = val;
+ return 0;
}
static ssize_t hints_store(struct device *dev,
@@ -377,16 +359,14 @@ static ssize_t user_pin_configs_show(struct device *dev,
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
{
- int nid, cfg, err;
+ int nid, cfg;
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
return -EINVAL;
if (!nid)
return -EINVAL;
- mutex_lock(&codec->user_mutex);
- err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
- mutex_unlock(&codec->user_mutex);
- return err;
+ guard(mutex)(&codec->user_mutex);
+ return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
}
static ssize_t user_pin_configs_store(struct device *dev,
@@ -434,26 +414,19 @@ EXPORT_SYMBOL_GPL(snd_hda_get_hint);
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
const char *p;
- int ret;
- mutex_lock(&codec->user_mutex);
+ guard(mutex)(&codec->user_mutex);
p = snd_hda_get_hint(codec, key);
if (!p || !*p)
- ret = -ENOENT;
- else {
- switch (toupper(*p)) {
- case 'T': /* true */
- case 'Y': /* yes */
- case '1':
- ret = 1;
- break;
- default:
- ret = 0;
- break;
- }
+ return -ENOENT;
+ switch (toupper(*p)) {
+ case 'T': /* true */
+ case 'Y': /* yes */
+ case '1':
+ return 1;
+ default:
+ return 0;
}
- mutex_unlock(&codec->user_mutex);
- return ret;
}
EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
@@ -471,20 +444,17 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
const char *p;
unsigned long val;
- int ret;
- mutex_lock(&codec->user_mutex);
+ guard(mutex)(&codec->user_mutex);
p = snd_hda_get_hint(codec, key);
if (!p)
- ret = -ENOENT;
+ return -ENOENT;
else if (kstrtoul(p, 0, &val))
- ret = -EINVAL;
+ return -EINVAL;
else {
*valp = val;
- ret = 0;
+ return 0;
}
- mutex_unlock(&codec->user_mutex);
- return ret;
}
EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
#endif /* CONFIG_SND_HDA_RECONFIG */
@@ -650,7 +620,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;
@@ -745,10 +715,8 @@ static struct attribute *hda_dev_attrs[] = {
&dev_attr_modelname.attr,
&dev_attr_init_pin_configs.attr,
&dev_attr_driver_pin_configs.attr,
-#ifdef CONFIG_PM
&dev_attr_power_on_acct.attr,
&dev_attr_power_off_acct.attr,
-#endif
#ifdef CONFIG_SND_HDA_RECONFIG
&dev_attr_init_verbs.attr,
&dev_attr_hints.attr,
diff --git a/sound/hda/controllers/Kconfig b/sound/hda/controllers/Kconfig
new file mode 100644
index 000000000000..34721f50b055
--- /dev/null
+++ b/sound/hda/controllers/Kconfig
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_HDA_INTEL
+ tristate "HD Audio PCI"
+ depends on SND_PCI
+ select SND_HDA
+ select SND_INTEL_DSP_CONFIG
+ help
+ Say Y here to include support for Intel "High Definition
+ Audio" (Azalia) and its compatible devices.
+
+ This option enables the HD-audio controller. Don't forget
+ to choose the appropriate HD-audio codec options.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hda-intel.
+
+config SND_HDA_TEGRA
+ tristate "NVIDIA Tegra HD Audio"
+ depends on ARCH_TEGRA
+ select SND_HDA
+ select SND_HDA_ALIGNED_MMIO
+ help
+ Say Y here to support the HDA controller present in NVIDIA
+ Tegra SoCs
+
+ This options enables support for the HD Audio controller
+ present in some NVIDIA Tegra SoCs, used to communicate audio
+ to the HDMI output.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hda-tegra.
+
+config SND_HDA_ACPI
+ tristate "HD Audio ACPI"
+ depends on ACPI
+ select SND_HDA
+ help
+ Say Y here to include support for Azalia-compatible HDA controllers
+ which are advertised via ACPI objects.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hda-acpi.
diff --git a/sound/hda/controllers/Makefile b/sound/hda/controllers/Makefile
new file mode 100644
index 000000000000..a4bcd055e9ae
--- /dev/null
+++ b/sound/hda/controllers/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-hda-intel-y := intel.o
+snd-hda-tegra-y := tegra.o
+snd-hda-acpi-y := acpi.o
+
+subdir-ccflags-y += -I$(src)/../common
+
+# for trace-points
+CFLAGS_intel.o := -I$(src)
+
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
+obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
+obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o
diff --git a/sound/hda/controllers/acpi.c b/sound/hda/controllers/acpi.c
new file mode 100644
index 000000000000..505cc97e0ee9
--- /dev/null
+++ b/sound/hda/controllers/acpi.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ALSA driver for ACPI-based HDA Controllers.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+
+#include <sound/hda_codec.h>
+
+#include "hda_controller.h"
+
+struct hda_acpi {
+ struct azx azx;
+ struct snd_card *card;
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct work_struct probe_work;
+ const struct hda_data *data;
+};
+
+/**
+ * struct hda_data - Optional device-specific data
+ * @short_name: Used for the ALSA card name; defaults to KBUILD_MODNAME
+ * @long_name: Used for longer description; defaults to short_name
+ * @flags: Passed to &azx->driver_caps
+ *
+ * A pointer to a record of this type may be stored in the
+ * &acpi_device_id->driver_data field of an ACPI match table entry in order to
+ * customize the naming and behavior of a particular device. All fields are
+ * optional and sensible defaults will be selected in their absence.
+ */
+struct hda_data {
+ const char *short_name;
+ const char *long_name;
+ unsigned long flags;
+};
+
+static int hda_acpi_dev_disconnect(struct snd_device *device)
+{
+ struct azx *chip = device->device_data;
+
+ chip->bus.shutdown = 1;
+ return 0;
+}
+
+static int hda_acpi_dev_free(struct snd_device *device)
+{
+ struct azx *azx = device->device_data;
+ struct hda_acpi *hda = container_of(azx, struct hda_acpi, azx);
+
+ cancel_work_sync(&hda->probe_work);
+ if (azx_bus(azx)->chip_init) {
+ azx_stop_all_streams(azx);
+ azx_stop_chip(azx);
+ }
+
+ azx_free_stream_pages(azx);
+ azx_free_streams(azx);
+ snd_hdac_bus_exit(azx_bus(azx));
+
+ return 0;
+}
+
+static int hda_acpi_init(struct hda_acpi *hda)
+{
+ struct hdac_bus *bus = azx_bus(&hda->azx);
+ struct snd_card *card = hda->azx.card;
+ struct device *dev = &hda->pdev->dev;
+ struct azx *azx = &hda->azx;
+ struct resource *res;
+ unsigned short gcap;
+ const char *sname, *lname;
+ int err, irq;
+
+ /* The base address for the HDA registers and the interrupt are wrapped
+ * in an ACPI _CRS object which can be parsed by platform_get_irq() and
+ * devm_platform_get_and_ioremap_resource()
+ */
+
+ irq = platform_get_irq(hda->pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ hda->regs = devm_platform_get_and_ioremap_resource(hda->pdev, 0, &res);
+ if (IS_ERR(hda->regs))
+ return PTR_ERR(hda->regs);
+
+ bus->remap_addr = hda->regs;
+ bus->addr = res->start;
+
+ err = devm_request_irq(dev, irq, azx_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, azx);
+ if (err) {
+ dev_err(dev, "unable to request IRQ %d, disabling device\n",
+ irq);
+ return err;
+ }
+ bus->irq = irq;
+ bus->dma_stop_delay = 100;
+ card->sync_irq = bus->irq;
+
+ gcap = azx_readw(azx, GCAP);
+ dev_dbg(dev, "chipset global capabilities = 0x%x\n", gcap);
+
+ azx->align_buffer_size = 1;
+
+ azx->capture_streams = (gcap >> 8) & 0x0f;
+ azx->playback_streams = (gcap >> 12) & 0x0f;
+
+ azx->capture_index_offset = 0;
+ azx->playback_index_offset = azx->capture_streams;
+ azx->num_streams = azx->playback_streams + azx->capture_streams;
+
+ err = azx_init_streams(azx);
+ if (err < 0) {
+ dev_err(dev, "failed to initialize streams: %d\n", err);
+ return err;
+ }
+
+ err = azx_alloc_stream_pages(azx);
+ if (err < 0) {
+ dev_err(dev, "failed to allocate stream pages: %d\n", err);
+ return err;
+ }
+
+ azx_init_chip(azx, 1);
+
+ if (!bus->codec_mask) {
+ dev_err(dev, "no codecs found!\n");
+ return -ENODEV;
+ }
+
+ strscpy(card->driver, "hda-acpi");
+
+ sname = hda->data->short_name ? hda->data->short_name : KBUILD_MODNAME;
+
+ if (strlen(sname) > sizeof(card->shortname))
+ dev_info(dev, "truncating shortname for card %s\n", sname);
+ strscpy(card->shortname, sname);
+
+ lname = hda->data->long_name ? hda->data->long_name : sname;
+
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx irq %i", lname, bus->addr, bus->irq);
+
+ return 0;
+}
+
+static void hda_acpi_probe_work(struct work_struct *work)
+{
+ struct hda_acpi *hda = container_of(work, struct hda_acpi, probe_work);
+ struct azx *chip = &hda->azx;
+ int err;
+
+ err = hda_acpi_init(hda);
+ if (err < 0)
+ return;
+
+ err = azx_probe_codecs(chip, 8);
+ if (err < 0)
+ return;
+
+ err = azx_codec_configure(chip);
+ if (err < 0)
+ return;
+
+ err = snd_card_register(chip->card);
+ if (err < 0)
+ return;
+
+ chip->running = 1;
+}
+
+static int hda_acpi_create(struct hda_acpi *hda)
+{
+ static const struct snd_device_ops ops = {
+ .dev_disconnect = hda_acpi_dev_disconnect,
+ .dev_free = hda_acpi_dev_free,
+ };
+ static const struct hda_controller_ops null_ops;
+ struct azx *azx = &hda->azx;
+ int err;
+
+ mutex_init(&azx->open_mutex);
+ azx->card = hda->card;
+ INIT_LIST_HEAD(&azx->pcm_list);
+
+ azx->ops = &null_ops;
+ azx->driver_caps = hda->data->flags;
+ azx->driver_type = hda->data->flags & 0xff;
+ azx->codec_probe_mask = -1;
+
+ err = azx_bus_init(azx, NULL);
+ if (err < 0)
+ return err;
+
+ err = snd_device_new(hda->card, SNDRV_DEV_LOWLEVEL, &hda->azx, &ops);
+ if (err < 0) {
+ dev_err(&hda->pdev->dev, "Error creating device\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int hda_acpi_probe(struct platform_device *pdev)
+{
+ struct hda_acpi *hda;
+ int err;
+
+ hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
+ if (!hda)
+ return -ENOMEM;
+
+ hda->pdev = pdev;
+ hda->data = acpi_device_get_match_data(&pdev->dev);
+
+ /* Fall back to defaults if the table didn't have a *struct hda_data */
+ if (!hda->data)
+ hda->data = devm_kzalloc(&pdev->dev, sizeof(*hda->data),
+ GFP_KERNEL);
+ if (!hda->data)
+ return -ENOMEM;
+
+ err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &hda->card);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Error creating card!\n");
+ return err;
+ }
+
+ INIT_WORK(&hda->probe_work, hda_acpi_probe_work);
+
+ err = hda_acpi_create(hda);
+ if (err < 0)
+ goto out_free;
+ hda->card->private_data = &hda->azx;
+
+ dev_set_drvdata(&pdev->dev, hda->card);
+
+ schedule_work(&hda->probe_work);
+
+ return 0;
+
+out_free:
+ snd_card_free(hda->card);
+ return err;
+}
+
+static void hda_acpi_remove(struct platform_device *pdev)
+{
+ snd_card_free(dev_get_drvdata(&pdev->dev));
+}
+
+static void hda_acpi_shutdown(struct platform_device *pdev)
+{
+ struct snd_card *card = dev_get_drvdata(&pdev->dev);
+ struct azx *chip;
+
+ if (!card)
+ return;
+ chip = card->private_data;
+ if (chip && chip->running)
+ azx_stop_chip(chip);
+}
+
+static int hda_acpi_suspend(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_suspend(dev);
+ if (rc < 0)
+ return rc;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ return 0;
+}
+
+static int hda_acpi_resume(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_resume(dev);
+ if (rc < 0)
+ return rc;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+
+static const struct dev_pm_ops hda_acpi_pm = {
+ SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume)
+};
+
+static const struct hda_data nvidia_hda_data = {
+ .short_name = "NVIDIA",
+ .long_name = "NVIDIA HDA Controller",
+ .flags = AZX_DCAPS_CORBRP_SELF_CLEAR,
+};
+
+static const struct acpi_device_id hda_acpi_match[] = {
+ { .id = "NVDA2014", .driver_data = (uintptr_t) &nvidia_hda_data },
+ { .id = "NVDA2015", .driver_data = (uintptr_t) &nvidia_hda_data },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, hda_acpi_match);
+
+static struct platform_driver hda_acpi_platform_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .pm = &hda_acpi_pm,
+ .acpi_match_table = hda_acpi_match,
+ },
+ .probe = hda_acpi_probe,
+ .remove = hda_acpi_remove,
+ .shutdown = hda_acpi_shutdown,
+};
+module_platform_driver(hda_acpi_platform_driver);
+
+MODULE_DESCRIPTION("Driver for ACPI-based HDA Controllers");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_intel.c b/sound/hda/controllers/intel.c
index 3226691ac923..1e8e3d61291a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/hda/controllers/intel.c
@@ -4,7 +4,7 @@
* hda_intel.c - Implementation of primary alsa driver code base
* for Intel HD Audio.
*
- * Copyright(c) 2004 Intel Corporation. All rights reserved.
+ * Copyright(c) 2004 Intel Corporation
*
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
* PeiSen Hou <pshou@realtek.com.tw>
@@ -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 */
@@ -53,11 +54,10 @@
#include <linux/apple-gmux.h>
#include <linux/firmware.h>
#include <sound/hda_codec.h>
-#include "hda_controller.h"
-#include "hda_intel.h"
+#include "intel.h"
#define CREATE_TRACE_POINTS
-#include "hda_intel_trace.h"
+#include "intel_trace.h"
/* position fix mode */
enum {
@@ -175,8 +175,8 @@ module_param(power_save, xint, 0644);
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
"(in second, 0 = disable).");
-static bool pm_blacklist = true;
-module_param(pm_blacklist, bool, 0644);
+static int pm_blacklist = -1;
+module_param(pm_blacklist, bint, 0644);
MODULE_PARM_DESC(pm_blacklist, "Enable power-management denylist");
/* reset the HD-audio controller in power save mode.
@@ -186,8 +186,10 @@ MODULE_PARM_DESC(pm_blacklist, "Enable power-management denylist");
static bool power_save_controller = 1;
module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
-#else
+#else /* CONFIG_PM */
#define power_save 0
+#define pm_blacklist 0
+#define power_save_controller false
#endif /* CONFIG_PM */
static int align_buffer_size = -1;
@@ -237,6 +239,8 @@ enum {
AZX_DRIVER_CTHDA,
AZX_DRIVER_CMEDIA,
AZX_DRIVER_ZHAOXIN,
+ AZX_DRIVER_ZHAOXINHDMI,
+ AZX_DRIVER_LOONGSON,
AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */
};
@@ -288,6 +292,9 @@ enum {
#define AZX_DCAPS_INTEL_BROXTON AZX_DCAPS_INTEL_SKYLAKE
+#define AZX_DCAPS_INTEL_LNL \
+ (AZX_DCAPS_INTEL_SKYLAKE | AZX_DCAPS_PIO_COMMANDS)
+
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB |\
@@ -329,18 +336,6 @@ enum {
#define needs_eld_notify_link(chip) false
#endif
-#define CONTROLLER_IN_GPU(pci) (((pci)->vendor == 0x8086) && \
- (((pci)->device == 0x0a0c) || \
- ((pci)->device == 0x0c0c) || \
- ((pci)->device == 0x0d0c) || \
- ((pci)->device == 0x160c) || \
- ((pci)->device == 0x490d) || \
- ((pci)->device == 0x4f90) || \
- ((pci)->device == 0x4f91) || \
- ((pci)->device == 0x4f92)))
-
-#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
-
static const char * const driver_short_names[] = {
[AZX_DRIVER_ICH] = "HDA Intel",
[AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -360,6 +355,8 @@ static const char * const driver_short_names[] = {
[AZX_DRIVER_CTHDA] = "HDA Creative",
[AZX_DRIVER_CMEDIA] = "HDA C-Media",
[AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
+ [AZX_DRIVER_ZHAOXINHDMI] = "HDA Zhaoxin HDMI",
+ [AZX_DRIVER_LOONGSON] = "HDA Loongson",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
@@ -571,7 +568,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
snd_hdac_set_codec_wakeup(bus, false);
/* reduce dma latency to avoid noise */
- if (IS_BXT(pci))
+ if (HDA_CONTROLLER_IS_APL(pci))
bxt_reduce_dma_latency(chip);
if (bus->mlcap != NULL)
@@ -653,6 +650,13 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
unsigned int pos;
snd_pcm_uframes_t hwptr, target;
+ /*
+ * The value of the WALLCLK register is always 0
+ * on the Loongson controller, so we return directly.
+ */
+ if (chip->driver_type == AZX_DRIVER_LOONGSON)
+ return 1;
+
wallclk = azx_readl(chip, WALLCLK) - azx_dev->core.start_wallclk;
if (wallclk < (azx_dev->core.period_wallclk * 2) / 3)
return -1; /* bogus (too early) interrupt */
@@ -760,17 +764,24 @@ static void azx_clear_irq_pending(struct azx *chip)
struct hdac_bus *bus = azx_bus(chip);
struct hdac_stream *s;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
list_for_each_entry(s, &bus->stream_list, list) {
struct azx_dev *azx_dev = stream_to_azx_dev(s);
azx_dev->irq_pending = 0;
}
- spin_unlock_irq(&bus->reg_lock);
}
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{
struct hdac_bus *bus = azx_bus(chip);
+ int ret;
+
+ if (!chip->msi || pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_MSI) < 0) {
+ ret = pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_INTX);
+ if (ret < 0)
+ return ret;
+ chip->msi = 0;
+ }
if (request_irq(chip->pci->irq, azx_interrupt,
chip->msi ? 0 : IRQF_SHARED,
@@ -784,7 +795,6 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
}
bus->irq = chip->pci->irq;
chip->card->sync_irq = bus->irq;
- pci_intx(chip->pci, !chip->msi);
return 0;
}
@@ -809,7 +819,7 @@ static unsigned int azx_via_get_position(struct azx *chip,
mod_dma_pos = le32_to_cpu(*azx_dev->core.posbuf);
mod_dma_pos %= azx_dev->core.period_bytes;
- fifo_size = azx_stream(azx_dev)->fifo_size - 1;
+ fifo_size = azx_stream(azx_dev)->fifo_size;
if (azx_dev->insufficient) {
/* Link position never gather than FIFO size */
@@ -893,7 +903,6 @@ static void __azx_shutdown_chip(struct azx *chip, bool skip_link_reset)
display_power(chip, false);
}
-#ifdef CONFIG_PM
static DEFINE_MUTEX(card_list_lock);
static LIST_HEAD(card_list);
@@ -905,21 +914,21 @@ static void azx_shutdown_chip(struct azx *chip)
static void azx_add_card_list(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
- mutex_lock(&card_list_lock);
+
+ guard(mutex)(&card_list_lock);
list_add(&hda->list, &card_list);
- mutex_unlock(&card_list_lock);
}
static void azx_del_card_list(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
- mutex_lock(&card_list_lock);
+
+ guard(mutex)(&card_list_lock);
list_del_init(&hda->list);
- mutex_unlock(&card_list_lock);
}
/* trigger power-save check at writing parameter */
-static int param_set_xint(const char *val, const struct kernel_param *kp)
+static int __maybe_unused param_set_xint(const char *val, const struct kernel_param *kp)
{
struct hda_intel *hda;
struct azx *chip;
@@ -929,14 +938,17 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
if (ret || prev == power_save)
return ret;
- mutex_lock(&card_list_lock);
+ if (pm_blacklist > 0)
+ return 0;
+
+ guard(mutex)(&card_list_lock);
list_for_each_entry(hda, &card_list, list) {
chip = &hda->chip;
- if (!hda->probe_continued || chip->disabled)
+ if (!hda->probe_continued || chip->disabled ||
+ hda->runtime_pm_disabled)
continue;
snd_hda_set_power_save(&chip->bus, power_save * 1000);
}
- mutex_unlock(&card_list_lock);
return 0;
}
@@ -990,7 +1002,6 @@ static void __azx_runtime_resume(struct azx *chip)
display_power(chip, false);
}
-#ifdef CONFIG_PM_SLEEP
static int azx_prepare(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -1028,22 +1039,12 @@ static int azx_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
- struct hdac_bus *bus;
if (!azx_is_pm_ready(card))
return 0;
chip = card->private_data;
- bus = azx_bus(chip);
azx_shutdown_chip(chip);
- if (bus->irq >= 0) {
- free_irq(bus->irq, chip);
- bus->irq = -1;
- chip->card->sync_irq = -1;
- }
-
- if (chip->msi)
- pci_disable_msi(chip->pci);
trace_azx_suspend(chip);
return 0;
@@ -1058,11 +1059,6 @@ static int azx_resume(struct device *dev)
return 0;
chip = card->private_data;
- if (chip->msi)
- if (pci_enable_msi(chip->pci) < 0)
- chip->msi = 0;
- if (azx_acquire_irq(chip, 1) < 0)
- return -EIO;
__azx_runtime_resume(chip);
@@ -1100,7 +1096,6 @@ static int azx_thaw_noirq(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static int azx_runtime_suspend(struct device *dev)
{
@@ -1162,23 +1157,14 @@ static int azx_runtime_idle(struct device *dev)
}
static const struct dev_pm_ops azx_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
-#ifdef CONFIG_PM_SLEEP
- .prepare = azx_prepare,
- .complete = azx_complete,
- .freeze_noirq = azx_freeze_noirq,
- .thaw_noirq = azx_thaw_noirq,
-#endif
- SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
+ SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
+ .prepare = pm_sleep_ptr(azx_prepare),
+ .complete = pm_sleep_ptr(azx_complete),
+ .freeze_noirq = pm_sleep_ptr(azx_freeze_noirq),
+ .thaw_noirq = pm_sleep_ptr(azx_thaw_noirq),
+ RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
};
-#define AZX_PM_OPS &azx_pm
-#else
-#define azx_add_card_list(chip) /* NOP */
-#define azx_del_card_list(chip) /* NOP */
-#define AZX_PM_OPS NULL
-#endif /* CONFIG_PM */
-
static int azx_probe_continue(struct azx *chip);
@@ -1366,8 +1352,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) {
@@ -1420,17 +1419,11 @@ static bool atpx_present(void)
acpi_handle dhandle, atpx_handle;
acpi_status status;
- while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
- dhandle = ACPI_HANDLE(&pdev->dev);
- if (dhandle) {
- status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
- if (ACPI_SUCCESS(status)) {
- pci_dev_put(pdev);
- return true;
- }
- }
- }
- while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
+ while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
+ if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
+ (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))
+ continue;
+
dhandle = ACPI_HANDLE(&pdev->dev);
if (dhandle) {
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
@@ -1469,7 +1462,7 @@ static struct pci_dev *get_bound_vga(struct pci_dev *pci)
* the dGPU is the one who is involved in
* vgaswitcheroo.
*/
- if (((p->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
+ if (pci_is_display(p) &&
(atpx_present() || apple_gmux_detect(NULL, NULL)))
return p;
pci_dev_put(p);
@@ -1481,7 +1474,7 @@ static struct pci_dev *get_bound_vga(struct pci_dev *pci)
p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
pci->bus->number, 0);
if (p) {
- if ((p->class >> 16) == PCI_BASE_CLASS_DISPLAY)
+ if (pci_is_display(p))
return p;
pci_dev_put(p);
}
@@ -1738,9 +1731,11 @@ static int default_bdl_pos_adj(struct azx *chip)
/* some exceptions: Atoms seem problematic with value 1 */
if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) {
switch (chip->pci->device) {
- case 0x0f04: /* Baytrail */
- case 0x2284: /* Braswell */
+ case PCI_DEVICE_ID_INTEL_HDA_BYT:
+ case PCI_DEVICE_ID_INTEL_HDA_BSW:
return 32;
+ case PCI_DEVICE_ID_INTEL_HDA_APL:
+ return 64;
}
}
@@ -1754,6 +1749,8 @@ static int default_bdl_pos_adj(struct azx *chip)
case AZX_DRIVER_ICH:
case AZX_DRIVER_PCH:
return 1;
+ case AZX_DRIVER_ZHAOXINHDMI:
+ return 128;
default:
return 32;
}
@@ -1823,7 +1820,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
/* use the non-cached pages in non-snoop mode */
if (!azx_snoop(chip))
- azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC_SG;
+ azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC;
if (chip->driver_type == AZX_DRIVER_NVIDIA) {
dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
@@ -1873,12 +1870,22 @@ static int azx_first_init(struct azx *chip)
if (chip->driver_type == AZX_DRIVER_GFHDMI)
bus->polling_mode = 1;
- err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio");
- if (err < 0)
- return err;
+ if (chip->driver_type == AZX_DRIVER_LOONGSON) {
+ bus->polling_mode = 1;
+ bus->not_use_interrupts = 1;
+ bus->access_sdnctl_in_dword = 1;
+ if (!chip->jackpoll_interval)
+ chip->jackpoll_interval = msecs_to_jiffies(1500);
+ }
+
+ if (chip->driver_type == AZX_DRIVER_ZHAOXINHDMI)
+ bus->polling_mode = 1;
+
+ bus->remap_addr = pcim_iomap_region(pci, 0, "ICH HD audio");
+ if (IS_ERR(bus->remap_addr))
+ return PTR_ERR(bus->remap_addr);
bus->addr = pci_resource_start(pci, 0);
- bus->remap_addr = pcim_iomap_table(pci)[0];
if (chip->driver_type == AZX_DRIVER_SKL)
snd_hdac_bus_parse_capabilities(bus);
@@ -1896,13 +1903,9 @@ static int azx_first_init(struct azx *chip)
chip->gts_present = true;
#endif
- if (chip->msi) {
- if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
- dev_dbg(card->dev, "Disabling 64bit MSI\n");
- pci->no_64bit_msi = true;
- }
- if (pci_enable_msi(pci) < 0)
- chip->msi = 0;
+ if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) {
+ dev_dbg(card->dev, "Disabling 64bit MSI\n");
+ pci->no_64bit_msi = true;
}
pci_set_master(pci);
@@ -1974,6 +1977,7 @@ static int azx_first_init(struct azx *chip)
chip->capture_streams = ATIHDMI_NUM_CAPTURE;
break;
case AZX_DRIVER_GFHDMI:
+ case AZX_DRIVER_ZHAOXINHDMI:
case AZX_DRIVER_GENERIC:
default:
chip->playback_streams = ICH6_NUM_PLAYBACK;
@@ -2018,7 +2022,7 @@ static int azx_first_init(struct azx *chip)
if (azx_acquire_irq(chip, 0) < 0)
return -EBUSY;
- strcpy(card->driver, "HDA-Intel");
+ strscpy(card->driver, "HDA-Intel");
strscpy(card->shortname, driver_short_names[chip->driver_type],
sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
@@ -2054,7 +2058,7 @@ static int disable_msi_reset_irq(struct azx *chip)
free_irq(bus->irq, chip);
bus->irq = -1;
chip->card->sync_irq = -1;
- pci_disable_msi(chip->pci);
+ pci_free_irq_vectors(chip->pci);
chip->msi = 0;
err = azx_acquire_irq(chip, 1);
if (err < 0)
@@ -2071,6 +2075,28 @@ static const struct pci_device_id driver_denylist[] = {
{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1043, 0x874f) }, /* ASUS ROG Zenith II / Strix */
{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb59) }, /* MSI TRX40 Creator */
{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb60) }, /* MSI TRX40 */
+ { PCI_DEVICE_SUB(0x1022, 0x15e3, 0x1462, 0xee59) }, /* MSI X870E Tomahawk WiFi */
+ {}
+};
+
+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,
+ },
{}
};
@@ -2084,6 +2110,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;
@@ -2096,6 +2123,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;
@@ -2132,6 +2165,39 @@ static int azx_probe(struct pci_dev *pci,
pci_set_drvdata(pci, card);
+#ifdef CONFIG_SND_HDA_I915
+ /* bind with i915 if needed */
+ if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) {
+ err = snd_hdac_i915_init(azx_bus(chip));
+ if (err < 0) {
+ if (err == -EPROBE_DEFER)
+ goto out_free;
+
+ /* if the controller is bound only with HDMI/DP
+ * (for HSW and BDW), we need to abort the probe;
+ * for other chips, still continue probing as other
+ * codecs can be on the same link.
+ */
+ if (HDA_CONTROLLER_IN_GPU(pci)) {
+ dev_err_probe(card->dev, err,
+ "HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");
+
+ goto out_free;
+ } else {
+ /* don't bother any longer */
+ chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
+ }
+ }
+
+ /* HSW/BDW controllers need this power */
+ if (HDA_CONTROLLER_IN_GPU(pci))
+ hda->need_i915_power = true;
+ }
+#else
+ if (HDA_CONTROLLER_IN_GPU(pci))
+ dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
+#endif
+
err = register_vga_switcheroo(chip);
if (err < 0) {
dev_err(card->dev, "Error registering vga_switcheroo client\n");
@@ -2159,11 +2225,6 @@ static int azx_probe(struct pci_dev *pci,
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
-#ifndef CONFIG_SND_HDA_I915
- if (CONTROLLER_IN_GPU(pci))
- dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
-#endif
-
if (schedule_probe)
schedule_delayed_work(&hda->probe_work, 0);
@@ -2173,11 +2234,11 @@ static int azx_probe(struct pci_dev *pci,
return 0;
out_free:
+ pci_set_drvdata(pci, NULL);
snd_card_free(card);
return err;
}
-#ifdef CONFIG_PM
/* On some boards setting power_save to a non 0 value leads to clicking /
* popping sounds when ever we enter/leave powersaving mode. Ideally we would
* figure out how to avoid these sounds, but that is not always feasible.
@@ -2208,22 +2269,28 @@ static const struct snd_pci_quirk power_save_denylist[] = {
SND_PCI_QUIRK(0x8086, 0x2068, "Intel NUC7i3BNB", 0),
/* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
+ SND_PCI_QUIRK(0x17aa, 0x316e, "Lenovo ThinkCentre M70q", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1689623 */
SND_PCI_QUIRK(0x17aa, 0x367b, "Lenovo IdeaCentre B550", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */
SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0),
/* https://bugs.launchpad.net/bugs/1821663 */
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),
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=220210 */
+ SND_PCI_QUIRK(0x17aa, 0x5079, "Lenovo Thinkpad E15", 0),
{}
};
-#endif /* CONFIG_PM */
static void set_default_power_save(struct azx *chip)
{
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
int val = power_save;
-#ifdef CONFIG_PM
- if (pm_blacklist) {
+ if (pm_blacklist < 0) {
const struct snd_pci_quirk *q;
q = snd_pci_quirk_lookup(chip->pci, power_save_denylist);
@@ -2231,9 +2298,12 @@ static void set_default_power_save(struct azx *chip)
dev_info(chip->card->dev, "device %04x:%04x is on the power_save denylist, forcing power_save to 0\n",
q->subvendor, q->subdevice);
val = 0;
+ hda->runtime_pm_disabled = 1;
}
+ } else if (pm_blacklist > 0) {
+ dev_info(chip->card->dev, "Forcing power_save to 0 via option\n");
+ val = 0;
}
-#endif /* CONFIG_PM */
snd_hda_set_power_save(&chip->bus, val * 1000);
}
@@ -2259,30 +2329,6 @@ static int azx_probe_continue(struct azx *chip)
to_hda_bus(bus)->bus_probing = 1;
hda->probe_continued = 1;
- /* bind with i915 if needed */
- if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) {
- err = snd_hdac_i915_init(bus);
- if (err < 0) {
- /* if the controller is bound only with HDMI/DP
- * (for HSW and BDW), we need to abort the probe;
- * for other chips, still continue probing as other
- * codecs can be on the same link.
- */
- if (CONTROLLER_IN_GPU(pci)) {
- dev_err(chip->card->dev,
- "HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");
- goto out_free;
- } else {
- /* don't bother any longer */
- chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
- }
- }
-
- /* HSW/BDW controllers need this power */
- if (CONTROLLER_IN_GPU(pci))
- hda->need_i915_power = true;
- }
-
/* Request display power well for the HDA controller or codec. For
* Haswell/Broadwell, both the display HDA controller and codec need
* this power. For other platforms, like Baytrail/Braswell, only the
@@ -2313,10 +2359,6 @@ static int azx_probe_continue(struct azx *chip)
chip->fw->data);
if (err < 0)
goto out_free;
-#ifndef CONFIG_PM
- release_firmware(chip->fw); /* no longer needed */
- chip->fw = NULL;
-#endif
}
#endif
@@ -2413,351 +2455,295 @@ static void azx_shutdown(struct pci_dev *pci)
/* PCI IDs */
static const struct pci_device_id azx_ids[] = {
/* CPT */
- { PCI_DEVICE(0x8086, 0x1c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ { PCI_DEVICE_DATA(INTEL, HDA_CPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
/* PBG */
- { PCI_DEVICE(0x8086, 0x1d20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ { PCI_DEVICE_DATA(INTEL, HDA_PBG, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
/* Panther Point */
- { PCI_DEVICE(0x8086, 0x1e20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ { PCI_DEVICE_DATA(INTEL, HDA_PPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
/* Lynx Point */
- { PCI_DEVICE(0x8086, 0x8c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ { PCI_DEVICE_DATA(INTEL, HDA_LPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
/* 9 Series */
- { PCI_DEVICE(0x8086, 0x8ca0),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ { PCI_DEVICE_DATA(INTEL, HDA_9_SERIES, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
/* Wellsburg */
- { PCI_DEVICE(0x8086, 0x8d20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
- { PCI_DEVICE(0x8086, 0x8d21),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ { PCI_DEVICE_DATA(INTEL, HDA_WBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
+ { PCI_DEVICE_DATA(INTEL, HDA_WBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
/* Lewisburg */
- { PCI_DEVICE(0x8086, 0xa1f0),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
- { PCI_DEVICE(0x8086, 0xa270),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
+ { PCI_DEVICE_DATA(INTEL, HDA_LBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_LBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) },
/* Lynx Point-LP */
- { PCI_DEVICE(0x8086, 0x9c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
/* Lynx Point-LP */
- { PCI_DEVICE(0x8086, 0x9c21),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
/* Wildcat Point-LP */
- { PCI_DEVICE(0x8086, 0x9ca0),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
- /* Sunrise Point */
- { PCI_DEVICE(0x8086, 0xa170),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
- /* Sunrise Point-LP */
- { PCI_DEVICE(0x8086, 0x9d70),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+ { PCI_DEVICE_DATA(INTEL, HDA_WPT_LP, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
+ /* Skylake (Sunrise Point) */
+ { PCI_DEVICE_DATA(INTEL, HDA_SKL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ /* Skylake-LP (Sunrise Point-LP) */
+ { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Kabylake */
- { PCI_DEVICE(0x8086, 0xa171),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Kabylake-LP */
- { PCI_DEVICE(0x8086, 0x9d71),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Kabylake-H */
- { PCI_DEVICE(0x8086, 0xa2f0),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Coffelake */
- { PCI_DEVICE(0x8086, 0xa348),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Cannonlake */
- { PCI_DEVICE(0x8086, 0x9dc8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* CometLake-LP */
- { PCI_DEVICE(0x8086, 0x02C8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* CometLake-H */
- { PCI_DEVICE(0x8086, 0x06C8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0xf1c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RKL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* CometLake-S */
- { PCI_DEVICE(0x8086, 0xa3f0),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* CometLake-R */
- { PCI_DEVICE(0x8086, 0xf0c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_R, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Icelake */
- { PCI_DEVICE(0x8086, 0x34c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Icelake-H */
- { PCI_DEVICE(0x8086, 0x3dc8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Jasperlake */
- { PCI_DEVICE(0x8086, 0x38c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x4dc8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Tigerlake */
- { PCI_DEVICE(0x8086, 0xa0c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Tigerlake-H */
- { PCI_DEVICE(0x8086, 0x43c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* DG1 */
- { PCI_DEVICE(0x8086, 0x490d),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_DG1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* DG2 */
- { PCI_DEVICE(0x8086, 0x4f90),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x4f91),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x4f92),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_DG2_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_DG2_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_DG2_2, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Alderlake-S */
- { PCI_DEVICE(0x8086, 0x7ad0),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Alderlake-P */
- { PCI_DEVICE(0x8086, 0x51c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x51c9),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x51cd),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Alderlake-M */
- { PCI_DEVICE(0x8086, 0x51cc),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Alderlake-N */
- { PCI_DEVICE(0x8086, 0x54c8),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Elkhart Lake */
- { PCI_DEVICE(0x8086, 0x4b55),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x4b58),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Raptor Lake */
- { PCI_DEVICE(0x8086, 0x7a50),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x51ca),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x51cb),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x51ce),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- { PCI_DEVICE(0x8086, 0x51cf),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- /* Meteorlake-P */
- { PCI_DEVICE(0x8086, 0x7e28),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ { PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ /* Battlemage */
+ { PCI_DEVICE_DATA(INTEL, HDA_BMG, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Lunarlake-P */
- { PCI_DEVICE(0x8086, 0xa828),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
- /* Broxton-P(Apollolake) */
- { PCI_DEVICE(0x8086, 0x5a98),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
- /* Broxton-T */
- { PCI_DEVICE(0x8086, 0x1a98),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+ { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
+ /* Arrow Lake-S */
+ { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+ /* Arrow Lake */
+ { 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) },
+ /* Wildcat Lake */
+ { PCI_DEVICE_DATA(INTEL, HDA_WCL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
+ /* Nova Lake */
+ { PCI_DEVICE_DATA(INTEL, HDA_NVL_S, 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 */
- { PCI_DEVICE(0x8086, 0x3198),
- .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+ { PCI_DEVICE_DATA(INTEL, HDA_GML, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
/* Haswell */
- { PCI_DEVICE(0x8086, 0x0a0c),
- .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
- { PCI_DEVICE(0x8086, 0x0c0c),
- .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
- { PCI_DEVICE(0x8086, 0x0d0c),
- .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
+ { PCI_DEVICE_DATA(INTEL, HDA_HSW_0, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
+ { PCI_DEVICE_DATA(INTEL, HDA_HSW_2, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
+ { PCI_DEVICE_DATA(INTEL, HDA_HSW_3, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
/* Broadwell */
- { PCI_DEVICE(0x8086, 0x160c),
- .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL },
+ { PCI_DEVICE_DATA(INTEL, HDA_BDW, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL) },
/* 5 Series/3400 */
- { PCI_DEVICE(0x8086, 0x3b56),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
- { PCI_DEVICE(0x8086, 0x3b57),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_0, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) },
+ { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_1, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) },
/* Poulsbo */
- { PCI_DEVICE(0x8086, 0x811b),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE |
- AZX_DCAPS_POSFIX_LPIB },
+ { PCI_DEVICE_DATA(INTEL, HDA_POULSBO, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE |
+ AZX_DCAPS_POSFIX_LPIB) },
/* Oaktrail */
- { PCI_DEVICE(0x8086, 0x080a),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
+ { PCI_DEVICE_DATA(INTEL, HDA_OAKTRAIL, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE) },
/* BayTrail */
- { PCI_DEVICE(0x8086, 0x0f04),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL },
+ { PCI_DEVICE_DATA(INTEL, HDA_BYT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL) },
/* Braswell */
- { PCI_DEVICE(0x8086, 0x2284),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL },
+ { PCI_DEVICE_DATA(INTEL, HDA_BSW, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL) },
/* ICH6 */
- { PCI_DEVICE(0x8086, 0x2668),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH6, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ICH7 */
- { PCI_DEVICE(0x8086, 0x27d8),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH7, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ESB2 */
- { PCI_DEVICE(0x8086, 0x269a),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ESB2, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ICH8 */
- { PCI_DEVICE(0x8086, 0x284b),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH8, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ICH9 */
- { PCI_DEVICE(0x8086, 0x293e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH9_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ICH9 */
- { PCI_DEVICE(0x8086, 0x293f),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH9_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ICH10 */
- { PCI_DEVICE(0x8086, 0x3a3e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH10_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* ICH10 */
- { PCI_DEVICE(0x8086, 0x3a6e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICH10_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
/* Generic Intel */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE },
/* ATI SB 450/600/700/800/900 */
- { PCI_DEVICE(0x1002, 0x437b),
+ { PCI_VDEVICE(ATI, 0x437b),
.driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
- { PCI_DEVICE(0x1002, 0x4383),
+ { PCI_VDEVICE(ATI, 0x4383),
.driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
/* AMD Hudson */
- { PCI_DEVICE(0x1022, 0x780d),
+ { PCI_VDEVICE(AMD, 0x780d),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
/* AMD, X370 & co */
- { PCI_DEVICE(0x1022, 0x1457),
+ { PCI_VDEVICE(AMD, 0x1457),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
/* AMD, X570 & co */
- { PCI_DEVICE(0x1022, 0x1487),
+ { PCI_VDEVICE(AMD, 0x1487),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
/* AMD Stoney */
- { PCI_DEVICE(0x1022, 0x157a),
+ { PCI_VDEVICE(AMD, 0x157a),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
AZX_DCAPS_PM_RUNTIME },
/* AMD Raven */
- { PCI_DEVICE(0x1022, 0x15e3),
+ { PCI_VDEVICE(AMD, 0x15e3),
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
/* ATI HDMI */
- { PCI_DEVICE(0x1002, 0x0002),
+ { PCI_VDEVICE(ATI, 0x0002),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0x1308),
+ { PCI_VDEVICE(ATI, 0x1308),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0x157a),
+ { PCI_VDEVICE(ATI, 0x157a),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0x15b3),
+ { PCI_VDEVICE(ATI, 0x15b3),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0x793b),
+ { PCI_VDEVICE(ATI, 0x793b),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0x7919),
+ { PCI_VDEVICE(ATI, 0x7919),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0x960f),
+ { PCI_VDEVICE(ATI, 0x960f),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0x970f),
+ { PCI_VDEVICE(ATI, 0x970f),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0x9840),
+ { PCI_VDEVICE(ATI, 0x9840),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0xaa00),
+ { PCI_VDEVICE(ATI, 0xaa00),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa08),
+ { PCI_VDEVICE(ATI, 0xaa08),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa10),
+ { PCI_VDEVICE(ATI, 0xaa10),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa18),
+ { PCI_VDEVICE(ATI, 0xaa18),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa20),
+ { PCI_VDEVICE(ATI, 0xaa20),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa28),
+ { PCI_VDEVICE(ATI, 0xaa28),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa30),
+ { PCI_VDEVICE(ATI, 0xaa30),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa38),
+ { PCI_VDEVICE(ATI, 0xaa38),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa40),
+ { PCI_VDEVICE(ATI, 0xaa40),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa48),
+ { PCI_VDEVICE(ATI, 0xaa48),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa50),
+ { PCI_VDEVICE(ATI, 0xaa50),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa58),
+ { PCI_VDEVICE(ATI, 0xaa58),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa60),
+ { PCI_VDEVICE(ATI, 0xaa60),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa68),
+ { PCI_VDEVICE(ATI, 0xaa68),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa80),
+ { PCI_VDEVICE(ATI, 0xaa80),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa88),
+ { PCI_VDEVICE(ATI, 0xaa88),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa90),
+ { PCI_VDEVICE(ATI, 0xaa90),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0xaa98),
+ { PCI_VDEVICE(ATI, 0xaa98),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
- { PCI_DEVICE(0x1002, 0x9902),
+ { PCI_VDEVICE(ATI, 0x9902),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0xaaa0),
+ { PCI_VDEVICE(ATI, 0xaaa0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0xaaa8),
+ { PCI_VDEVICE(ATI, 0xaaa8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0xaab0),
+ { PCI_VDEVICE(ATI, 0xaab0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
- { PCI_DEVICE(0x1002, 0xaac0),
+ { PCI_VDEVICE(ATI, 0xaac0),
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
+ AZX_DCAPS_PM_RUNTIME },
+ { PCI_VDEVICE(ATI, 0xaac8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xaac8),
+ { PCI_VDEVICE(ATI, 0xaad8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xaad8),
+ { PCI_VDEVICE(ATI, 0xaae0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xaae0),
+ { PCI_VDEVICE(ATI, 0xaae8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xaae8),
+ { PCI_VDEVICE(ATI, 0xaaf0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xaaf0),
+ { PCI_VDEVICE(ATI, 0xaaf8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xaaf8),
+ { PCI_VDEVICE(ATI, 0xab00),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab00),
+ { PCI_VDEVICE(ATI, 0xab08),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab08),
+ { PCI_VDEVICE(ATI, 0xab10),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab10),
+ { PCI_VDEVICE(ATI, 0xab18),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab18),
+ { PCI_VDEVICE(ATI, 0xab20),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab20),
+ { PCI_VDEVICE(ATI, 0xab28),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab28),
+ { PCI_VDEVICE(ATI, 0xab30),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab30),
+ { PCI_VDEVICE(ATI, 0xab38),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
- { PCI_DEVICE(0x1002, 0xab38),
+ { PCI_VDEVICE(ATI, 0xab40),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
/* GLENFLY */
- { PCI_DEVICE(0x6766, PCI_ANY_ID),
+ { PCI_DEVICE(PCI_VENDOR_ID_GLENFLY, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB |
AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
/* VIA VT8251/VT8237A */
- { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+ { PCI_VDEVICE(VIA, 0x3288), .driver_data = AZX_DRIVER_VIA },
/* VIA GFX VT7122/VX900 */
- { PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
+ { PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
/* VIA GFX VT6122/VX11 */
- { PCI_DEVICE(0x1106, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
+ { PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
/* SIS966 */
- { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
+ { PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS },
/* ULI M5461 */
- { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
+ { PCI_VDEVICE(AL, 0x5461), .driver_data = AZX_DRIVER_ULI },
/* NVIDIA MCP */
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
@@ -2770,9 +2756,9 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
/* Creative X-Fi (CA0110-IBG) */
/* CTHDA chips */
- { PCI_DEVICE(0x1102, 0x0010),
+ { PCI_VDEVICE(CREATIVE, 0x0010),
.driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
- { PCI_DEVICE(0x1102, 0x0012),
+ { PCI_VDEVICE(CREATIVE, 0x0012),
.driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
#if !IS_ENABLED(CONFIG_SND_CTXFI)
/* the following entry conflicts with snd-ctxfi driver,
@@ -2786,18 +2772,18 @@ static const struct pci_device_id azx_ids[] = {
AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
#else
/* this entry seems still valid -- i.e. without emu20kx chip */
- { PCI_DEVICE(0x1102, 0x0009),
+ { PCI_VDEVICE(CREATIVE, 0x0009),
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
#endif
/* CM8888 */
- { PCI_DEVICE(0x13f6, 0x5011),
+ { PCI_VDEVICE(CMEDIA, 0x5011),
.driver_data = AZX_DRIVER_CMEDIA |
AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF },
/* Vortex86MX */
- { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
+ { PCI_VDEVICE(RDC, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
/* VMware HDAudio */
- { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
+ { PCI_VDEVICE(VMWARE, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
@@ -2808,7 +2794,27 @@ static const struct pci_device_id azx_ids[] = {
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
/* Zhaoxin */
- { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
+ { PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
+ { PCI_VDEVICE(ZHAOXIN, 0x9141),
+ .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB |
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
+ { PCI_VDEVICE(ZHAOXIN, 0x9142),
+ .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB |
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
+ { PCI_VDEVICE(ZHAOXIN, 0x9144),
+ .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB |
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
+ { PCI_VDEVICE(ZHAOXIN, 0x9145),
+ .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB |
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
+ { PCI_VDEVICE(ZHAOXIN, 0x9146),
+ .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB |
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
+ /* Loongson HDAudio*/
+ { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA),
+ .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
+ { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
+ .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
@@ -2821,7 +2827,7 @@ static struct pci_driver azx_driver = {
.remove = azx_remove,
.shutdown = azx_shutdown,
.driver = {
- .pm = AZX_PM_OPS,
+ .pm = pm_ptr(&azx_pm),
},
};
diff --git a/sound/pci/hda/hda_intel.h b/sound/hda/controllers/intel.h
index 0f39418f9328..2d1725f86ef1 100644
--- a/sound/pci/hda/hda_intel.h
+++ b/sound/hda/controllers/intel.h
@@ -22,6 +22,7 @@ struct hda_intel {
/* extra flags */
unsigned int irq_pending_warned:1;
unsigned int probe_continued:1;
+ unsigned int runtime_pm_disabled:1;
/* vga_switcheroo setup */
unsigned int use_vga_switcheroo:1;
diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/hda/controllers/intel_trace.h
index 73a7adfa192d..fb10ab9e7e55 100644
--- a/sound/pci/hda/hda_intel_trace.h
+++ b/sound/hda/controllers/intel_trace.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hda_intel
-#define TRACE_INCLUDE_FILE hda_intel_trace
+#define TRACE_INCLUDE_FILE intel_trace
#if !defined(_TRACE_HDA_INTEL_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HDA_INTEL_H
@@ -34,7 +34,6 @@ DEFINE_EVENT(hda_pm, azx_resume,
TP_ARGS(chip)
);
-#ifdef CONFIG_PM
DEFINE_EVENT(hda_pm, azx_runtime_suspend,
TP_PROTO(struct azx *chip),
TP_ARGS(chip)
@@ -44,7 +43,6 @@ DEFINE_EVENT(hda_pm, azx_runtime_resume,
TP_PROTO(struct azx *chip),
TP_ARGS(chip)
);
-#endif
#endif /* _TRACE_HDA_INTEL_H */
diff --git a/sound/pci/hda/hda_tegra.c b/sound/hda/controllers/tegra.c
index 9d0ab043880b..6ab338f37db5 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/hda/controllers/tegra.c
@@ -16,7 +16,8 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/time.h>
@@ -71,6 +72,10 @@
struct hda_tegra_soc {
bool has_hda2codec_2x_reset;
bool has_hda2hdmi;
+ bool has_hda2codec_2x;
+ bool input_stream;
+ bool always_on;
+ bool requires_init;
};
struct hda_tegra {
@@ -124,7 +129,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;
@@ -137,7 +142,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;
@@ -150,7 +155,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;
@@ -169,7 +174,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;
@@ -186,7 +191,9 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
if (rc != 0)
return rc;
if (chip->running) {
- hda_tegra_init(hda);
+ if (hda->soc->requires_init)
+ hda_tegra_init(hda);
+
azx_init_chip(chip, 1);
/* disable controller wake up event*/
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
@@ -203,10 +210,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)
@@ -251,7 +256,8 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
bus->remap_addr = hda->regs + HDA_BAR0;
bus->addr = res->start + HDA_BAR0;
- hda_tegra_init(hda);
+ if (hda->soc->requires_init)
+ hda_tegra_init(hda);
return 0;
}
@@ -324,7 +330,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
* starts with offset 0 which is wrong as HW register for output stream
* offset starts with 4.
*/
- if (of_device_is_compatible(np, "nvidia,tegra234-hda"))
+ if (!hda->soc->input_stream)
chip->capture_streams = 4;
chip->playback_streams = (gcap >> 12) & 0x0f;
@@ -378,14 +384,14 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
}
/* driver name */
- strncpy(card->driver, drv_name, sizeof(card->driver));
+ strscpy(card->driver, drv_name);
/* shortname for card */
sname = of_get_property(np, "nvidia,model", NULL);
if (!sname)
sname = drv_name;
if (strlen(sname) > sizeof(card->shortname))
dev_info(card->dev, "truncating shortname for card\n");
- strncpy(card->shortname, sname, sizeof(card->shortname));
+ strscpy(card->shortname, sname);
/* longname for card */
snprintf(card->longname, sizeof(card->longname),
@@ -420,7 +426,6 @@ static int hda_tegra_create(struct snd_card *card,
chip->driver_caps = driver_caps;
chip->driver_type = driver_caps & 0xff;
chip->dev_index = 0;
- chip->jackpoll_interval = msecs_to_jiffies(5000);
INIT_LIST_HEAD(&chip->pcm_list);
chip->codec_probe_mask = -1;
@@ -437,7 +442,16 @@ static int hda_tegra_create(struct snd_card *card,
chip->bus.core.sync_write = 0;
chip->bus.core.needs_damn_long_delay = 1;
chip->bus.core.aligned_mmio = 1;
- chip->bus.jackpoll_in_suspend = 1;
+
+ /*
+ * HDA power domain and clocks are always on for Tegra264 and
+ * the jack detection logic would work always, so no need of
+ * jack polling mechanism running.
+ */
+ if (!hda->soc->always_on) {
+ chip->jackpoll_interval = msecs_to_jiffies(5000);
+ chip->bus.jackpoll_in_suspend = 1;
+ }
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
@@ -451,22 +465,44 @@ static int hda_tegra_create(struct snd_card *card,
static const struct hda_tegra_soc tegra30_data = {
.has_hda2codec_2x_reset = true,
.has_hda2hdmi = true,
+ .has_hda2codec_2x = true,
+ .input_stream = true,
+ .always_on = false,
+ .requires_init = true,
};
static const struct hda_tegra_soc tegra194_data = {
.has_hda2codec_2x_reset = false,
.has_hda2hdmi = true,
+ .has_hda2codec_2x = true,
+ .input_stream = true,
+ .always_on = false,
+ .requires_init = true,
};
static const struct hda_tegra_soc tegra234_data = {
.has_hda2codec_2x_reset = true,
.has_hda2hdmi = false,
+ .has_hda2codec_2x = true,
+ .input_stream = false,
+ .always_on = false,
+ .requires_init = true,
+};
+
+static const struct hda_tegra_soc tegra264_data = {
+ .has_hda2codec_2x_reset = true,
+ .has_hda2hdmi = false,
+ .has_hda2codec_2x = false,
+ .input_stream = false,
+ .always_on = true,
+ .requires_init = false,
};
static const struct of_device_id hda_tegra_match[] = {
{ .compatible = "nvidia,tegra30-hda", .data = &tegra30_data },
{ .compatible = "nvidia,tegra194-hda", .data = &tegra194_data },
{ .compatible = "nvidia,tegra234-hda", .data = &tegra234_data },
+ { .compatible = "nvidia,tegra264-hda", .data = &tegra264_data },
{},
};
MODULE_DEVICE_TABLE(of, hda_tegra_match);
@@ -521,7 +557,9 @@ static int hda_tegra_probe(struct platform_device *pdev)
hda->clocks[hda->nclocks++].id = "hda";
if (hda->soc->has_hda2hdmi)
hda->clocks[hda->nclocks++].id = "hda2hdmi";
- hda->clocks[hda->nclocks++].id = "hda2codec_2x";
+
+ if (hda->soc->has_hda2codec_2x)
+ hda->clocks[hda->nclocks++].id = "hda2codec_2x";
err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks);
if (err < 0)
@@ -601,11 +639,11 @@ 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,
- .remove_new = hda_tegra_remove,
+ .remove = hda_tegra_remove,
.shutdown = hda_tegra_shutdown,
};
module_platform_driver(tegra_platform_hda);
diff --git a/sound/hda/core/Kconfig b/sound/hda/core/Kconfig
new file mode 100644
index 000000000000..bfdcf6384c52
--- /dev/null
+++ b/sound/hda/core/Kconfig
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_HDA_CORE
+ tristate
+ select REGMAP
+
+config SND_HDA_DSP_LOADER
+ bool
+
+config SND_HDA_ALIGNED_MMIO
+ bool
+
+config SND_HDA_COMPONENT
+ bool
+
+config SND_HDA_I915
+ bool
+ select SND_HDA_COMPONENT
+
+config SND_HDA_EXT_CORE
+ tristate
+ select SND_HDA_CORE
+
+config SND_INTEL_NHLT
+ bool
+ # this config should be selected only for Intel ACPI platforms.
+ # A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_DSP_CONFIG
+ tristate
+ select ACPI_NHLT if ACPI
+ select SND_INTEL_NHLT if ACPI
+ select SND_INTEL_SOUNDWIRE_ACPI if ACPI
+ # this config should be selected only for Intel DSP platforms.
+ # A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_SOUNDWIRE_ACPI
+ tristate
+
+config SND_INTEL_BYT_PREFER_SOF
+ bool "Prefer SOF driver over SST on BY/CHT platforms"
+ depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL
+ default n
+ help
+ The kernel has 2 drivers for the Low Power Engine audio-block on
+ Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF
+ driver. If both drivers are enabled then the kernel will default
+ to using the old SST driver, unless told otherwise through the
+ snd_intel_dspcfg.dsp_driver module-parameter.
+
+ Set this option to Y to make the kernel default to the new SOF
+ driver instead.
diff --git a/sound/hda/core/Makefile b/sound/hda/core/Makefile
new file mode 100644
index 000000000000..89cb46143050
--- /dev/null
+++ b/sound/hda/core/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-hda-core-y := hda_bus_type.o bus.o device.o sysfs.o \
+ regmap.o controller.o stream.o array.o hdmi_chmap.o
+
+snd-hda-core-y += trace.o
+CFLAGS_trace.o := -I$(src)
+
+# for sync with i915 gfx driver
+snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += component.o
+snd-hda-core-$(CONFIG_SND_HDA_I915) += i915.o
+
+obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
+
+#extended hda
+obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
+
+snd-intel-dspcfg-y := intel-dsp-config.o
+snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o
+obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o
+
+snd-intel-sdw-acpi-y := intel-sdw-acpi.o
+obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o
diff --git a/sound/hda/array.c b/sound/hda/core/array.c
index a204dcee0034..a204dcee0034 100644
--- a/sound/hda/array.c
+++ b/sound/hda/core/array.c
diff --git a/sound/hda/hdac_bus.c b/sound/hda/core/bus.c
index d497414a5538..9b196c915f37 100644
--- a/sound/hda/hdac_bus.c
+++ b/sound/hda/core/bus.c
@@ -87,12 +87,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_exit);
int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
unsigned int cmd, unsigned int *res)
{
- int err;
-
- mutex_lock(&bus->cmd_mutex);
- err = snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res);
- mutex_unlock(&bus->cmd_mutex);
- return err;
+ guard(mutex)(&bus->cmd_mutex);
+ return snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res);
}
/**
diff --git a/sound/hda/hdac_component.c b/sound/hda/core/component.c
index bb37e7e0bd79..04755903880e 100644
--- a/sound/hda/hdac_component.c
+++ b/sound/hda/core/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,17 +67,16 @@ 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);
+ guard(mutex)(&bus->lock);
if (enable)
set_bit(idx, &bus->display_power_status);
else
clear_bit(idx, &bus->display_power_status);
if (!acomp || !acomp->ops)
- goto unlock;
+ return;
if (bus->display_power_status) {
if (!bus->display_power_active) {
@@ -100,8 +99,6 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
bus->display_power_active = 0;
}
}
- unlock:
- mutex_unlock(&bus->lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
diff --git a/sound/hda/hdac_controller.c b/sound/hda/core/controller.c
index 3c7af6558249..a7c00ad80117 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/core/controller.c
@@ -44,7 +44,7 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
{
WARN_ON_ONCE(!bus->rb.area);
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
/* CORB set up */
bus->corb.addr = bus->rb.addr;
bus->corb.buf = (__le32 *)bus->rb.area;
@@ -62,7 +62,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
azx_clear_corbrp(bus);
/* enable corb dma */
- snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);
+ if (!bus->use_pio_for_commands)
+ snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);
/* RIRB set up */
bus->rirb.addr = bus->rb.addr + 2048;
@@ -79,10 +80,12 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
/* set N=1, get RIRB response interrupt for new entry */
snd_hdac_chip_writew(bus, RINTCNT, 1);
/* enable rirb dma and response irq */
- snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
+ if (bus->not_use_interrupts)
+ snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN);
+ else
+ snd_hdac_chip_writeb(bus, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
/* Accept unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
- spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_init_cmd_io);
@@ -108,18 +111,17 @@ static void hdac_wait_for_cmd_dmas(struct hdac_bus *bus)
*/
void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus)
{
- spin_lock_irq(&bus->reg_lock);
- /* disable ringbuffer DMAs */
- snd_hdac_chip_writeb(bus, RIRBCTL, 0);
- snd_hdac_chip_writeb(bus, CORBCTL, 0);
- spin_unlock_irq(&bus->reg_lock);
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ /* disable ringbuffer DMAs */
+ snd_hdac_chip_writeb(bus, RIRBCTL, 0);
+ snd_hdac_chip_writeb(bus, CORBCTL, 0);
+ }
hdac_wait_for_cmd_dmas(bus);
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
/* disable unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, 0);
- spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_cmd_io);
@@ -132,19 +134,94 @@ static unsigned int azx_command_addr(u32 cmd)
return addr;
}
+/* receive an Immediate Response with PIO */
+static int snd_hdac_bus_wait_for_pio_response(struct hdac_bus *bus,
+ unsigned int addr)
+{
+ int timeout = 50;
+
+ while (timeout--) {
+ /* check IRV bit */
+ if (snd_hdac_chip_readw(bus, IRS) & AZX_IRS_VALID) {
+ /* reuse rirb.res as the response return value */
+ bus->rirb.res[addr] = snd_hdac_chip_readl(bus, IR);
+ return 0;
+ }
+ udelay(1);
+ }
+
+ dev_dbg_ratelimited(bus->dev, "get_response_pio timeout: IRS=%#x\n",
+ snd_hdac_chip_readw(bus, IRS));
+
+ bus->rirb.res[addr] = -1;
+
+ return -EIO;
+}
+
/**
- * snd_hdac_bus_send_cmd - send a command verb via CORB
+ * snd_hdac_bus_send_cmd_pio - send a command verb via Immediate Command
* @bus: HD-audio core bus
* @val: encoded verb value to send
*
* Returns zero for success or a negative error code.
*/
-int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
+static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val)
+{
+ unsigned int addr = azx_command_addr(val);
+ int timeout = 50;
+
+ guard(spinlock_irq)(&bus->reg_lock);
+
+ while (timeout--) {
+ /* check ICB bit */
+ if (!((snd_hdac_chip_readw(bus, IRS) & AZX_IRS_BUSY))) {
+ /* Clear IRV bit */
+ snd_hdac_chip_updatew(bus, IRS, AZX_IRS_VALID, AZX_IRS_VALID);
+ snd_hdac_chip_writel(bus, IC, val);
+ /* Set ICB bit */
+ snd_hdac_chip_updatew(bus, IRS, AZX_IRS_BUSY, AZX_IRS_BUSY);
+
+ return snd_hdac_bus_wait_for_pio_response(bus, addr);
+ }
+ udelay(1);
+ }
+
+ dev_dbg_ratelimited(bus->dev, "send_cmd_pio timeout: IRS=%#x, val=%#x\n",
+ snd_hdac_chip_readw(bus, IRS), val);
+
+ return -EIO;
+}
+
+/**
+ * snd_hdac_bus_get_response_pio - receive a response via Immediate Response
+ * @bus: HD-audio core bus
+ * @addr: codec address
+ * @res: pointer to store the value, NULL when not needed
+ *
+ * Returns zero if a value is read, or a negative error code.
+ */
+static int snd_hdac_bus_get_response_pio(struct hdac_bus *bus,
+ unsigned int addr, unsigned int *res)
+{
+ if (res)
+ *res = bus->rirb.res[addr];
+
+ return 0;
+}
+
+/**
+ * snd_hdac_bus_send_cmd_corb - send a command verb via CORB
+ * @bus: HD-audio core bus
+ * @val: encoded verb value to send
+ *
+ * Returns zero for success or a negative error code.
+ */
+static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val)
{
unsigned int addr = azx_command_addr(val);
unsigned int wp, rp;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
bus->last_cmd[azx_command_addr(val)] = val;
@@ -152,7 +229,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
wp = snd_hdac_chip_readw(bus, CORBWP);
if (wp == 0xffff) {
/* something wrong, controller likely turned to D3 */
- spin_unlock_irq(&bus->reg_lock);
return -EIO;
}
wp++;
@@ -161,7 +237,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
rp = snd_hdac_chip_readw(bus, CORBRP);
if (wp == rp) {
/* oops, it's full */
- spin_unlock_irq(&bus->reg_lock);
return -EAGAIN;
}
@@ -169,11 +244,8 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
bus->corb.buf[wp] = cpu_to_le32(val);
snd_hdac_chip_writew(bus, CORBWP, wp);
- spin_unlock_irq(&bus->reg_lock);
-
return 0;
}
-EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd);
#define AZX_RIRB_EX_UNSOL_EV (1<<4)
@@ -231,15 +303,15 @@ void snd_hdac_bus_update_rirb(struct hdac_bus *bus)
EXPORT_SYMBOL_GPL(snd_hdac_bus_update_rirb);
/**
- * snd_hdac_bus_get_response - receive a response via RIRB
+ * snd_hdac_bus_get_response_rirb - receive a response via RIRB
* @bus: HD-audio core bus
* @addr: codec address
* @res: pointer to store the value, NULL when not needed
*
* Returns zero if a value is read, or a negative error code.
*/
-int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
- unsigned int *res)
+static int snd_hdac_bus_get_response_rirb(struct hdac_bus *bus,
+ unsigned int addr, unsigned int *res)
{
unsigned long timeout;
unsigned long loopcounter;
@@ -250,21 +322,20 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
timeout = jiffies + msecs_to_jiffies(1000);
for (loopcounter = 0;; loopcounter++) {
- spin_lock_irq(&bus->reg_lock);
- if (!bus->polling_mode)
- prepare_to_wait(&bus->rirb_wq, &wait,
- TASK_UNINTERRUPTIBLE);
- if (bus->polling_mode)
- snd_hdac_bus_update_rirb(bus);
- if (!bus->rirb.cmds[addr]) {
- if (res)
- *res = bus->rirb.res[addr]; /* the last value */
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
if (!bus->polling_mode)
- finish_wait(&bus->rirb_wq, &wait);
- spin_unlock_irq(&bus->reg_lock);
- return 0;
+ prepare_to_wait(&bus->rirb_wq, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (bus->polling_mode)
+ snd_hdac_bus_update_rirb(bus);
+ if (!bus->rirb.cmds[addr]) {
+ if (res)
+ *res = bus->rirb.res[addr]; /* the last value */
+ if (!bus->polling_mode)
+ finish_wait(&bus->rirb_wq, &wait);
+ return 0;
+ }
}
- spin_unlock_irq(&bus->reg_lock);
if (time_after(jiffies, timeout))
break;
#define LOOP_COUNT_MAX 3000
@@ -290,6 +361,39 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
return -EIO;
}
+
+/**
+ * snd_hdac_bus_send_cmd - send a command verb via CORB or PIO
+ * @bus: HD-audio core bus
+ * @val: encoded verb value to send
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
+{
+ if (bus->use_pio_for_commands)
+ return snd_hdac_bus_send_cmd_pio(bus, val);
+
+ return snd_hdac_bus_send_cmd_corb(bus, val);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd);
+
+/**
+ * snd_hdac_bus_get_response - receive a response via RIRB or PIO
+ * @bus: HD-audio core bus
+ * @addr: codec address
+ * @res: pointer to store the value, NULL when not needed
+ *
+ * Returns zero if a value is read, or a negative error code.
+ */
+int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
+ unsigned int *res)
+{
+ if (bus->use_pio_for_commands)
+ return snd_hdac_bus_get_response_pio(bus, addr, res);
+
+ return snd_hdac_bus_get_response_rirb(bus, addr, res);
+}
EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);
#define HDAC_MAX_CAPS 10
diff --git a/sound/hda/hdac_device.c b/sound/hda/core/device.c
index accc9d279ce5..160c8d0453b0 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/core/device.c
@@ -13,6 +13,7 @@
#include <sound/hdaudio.h>
#include <sound/hda_regmap.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include "local.h"
static void setup_fg_nodes(struct hdac_device *codec);
@@ -146,9 +147,9 @@ int snd_hdac_device_register(struct hdac_device *codec)
err = device_add(&codec->dev);
if (err < 0)
return err;
- mutex_lock(&codec->widget_lock);
- err = hda_widget_sysfs_init(codec);
- mutex_unlock(&codec->widget_lock);
+ scoped_guard(mutex, &codec->widget_lock) {
+ err = hda_widget_sysfs_init(codec);
+ }
if (err < 0) {
device_del(&codec->dev);
return err;
@@ -165,9 +166,9 @@ EXPORT_SYMBOL_GPL(snd_hdac_device_register);
void snd_hdac_device_unregister(struct hdac_device *codec)
{
if (device_is_registered(&codec->dev)) {
- mutex_lock(&codec->widget_lock);
- hda_widget_sysfs_exit(codec);
- mutex_unlock(&codec->widget_lock);
+ scoped_guard(mutex, &codec->widget_lock) {
+ hda_widget_sysfs_exit(codec);
+ }
device_del(&codec->dev);
snd_hdac_bus_remove_device(codec->bus, codec);
}
@@ -410,36 +411,33 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec)
* Serialize against multiple threads trying to update the sysfs
* widgets array.
*/
- mutex_lock(&codec->widget_lock);
+ guard(mutex)(&codec->widget_lock);
nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
if (!start_nid || nums <= 0 || nums >= 0xff) {
dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n",
codec->afg);
- err = -EINVAL;
- goto unlock;
+ return -EINVAL;
}
err = hda_widget_sysfs_reinit(codec, start_nid, nums);
if (err < 0)
- goto unlock;
+ return err;
codec->num_nodes = nums;
codec->start_nid = start_nid;
codec->end_nid = start_nid + nums;
-unlock:
- mutex_unlock(&codec->widget_lock);
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
/* return CONNLIST_LEN parameter of the given widget */
static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid)
{
- unsigned int wcaps = get_wcaps(codec, nid);
+ unsigned int wcaps = snd_hdac_get_wcaps(codec, nid);
unsigned int parm;
if (!(wcaps & AC_WCAP_CONN_LIST) &&
- get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+ snd_hdac_get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
return 0;
parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN);
@@ -580,7 +578,6 @@ int snd_hdac_power_down(struct hdac_device *codec)
{
struct device *dev = &codec->dev;
- pm_runtime_mark_last_busy(dev);
return pm_runtime_put_autosuspend(dev);
}
EXPORT_SYMBOL_GPL(snd_hdac_power_down);
@@ -611,7 +608,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
int snd_hdac_keep_power_up(struct hdac_device *codec)
{
if (!atomic_inc_not_zero(&codec->in_pm)) {
- int ret = pm_runtime_get_if_in_use(&codec->dev);
+ int ret = pm_runtime_get_if_active(&codec->dev);
if (!ret)
return -1;
if (ret < 0)
@@ -645,6 +642,7 @@ struct hda_vendor_id {
};
static const struct hda_vendor_id hda_vendor_ids[] = {
+ { 0x0014, "Loongson" },
{ 0x1002, "ATI" },
{ 0x1013, "Cirrus Logic" },
{ 0x1057, "Motorola" },
@@ -663,6 +661,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = {
{ 0x19e5, "Huawei" },
{ 0x1aec, "Wolfson Microelectronics" },
{ 0x1af4, "QEMU" },
+ { 0x1fa8, "Senarytech" },
{ 0x434d, "C-Media" },
{ 0x8086, "Intel" },
{ 0x8384, "SigmaTel" },
@@ -724,40 +723,85 @@ static const struct hda_rate_tbl rate_bits[] = {
{ 0 } /* terminator */
};
+static snd_pcm_format_t snd_hdac_format_normalize(snd_pcm_format_t format)
+{
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S20_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ return SNDRV_PCM_FORMAT_S32_LE;
+
+ case SNDRV_PCM_FORMAT_U20_LE:
+ case SNDRV_PCM_FORMAT_U24_LE:
+ return SNDRV_PCM_FORMAT_U32_LE;
+
+ case SNDRV_PCM_FORMAT_S20_BE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ return SNDRV_PCM_FORMAT_S32_BE;
+
+ case SNDRV_PCM_FORMAT_U20_BE:
+ case SNDRV_PCM_FORMAT_U24_BE:
+ return SNDRV_PCM_FORMAT_U32_BE;
+
+ default:
+ return format;
+ }
+}
+
/**
- * snd_hdac_calc_stream_format - calculate the format bitset
- * @rate: the sample rate
- * @channels: the number of channels
- * @format: the PCM format (SNDRV_PCM_FORMAT_XXX)
- * @maxbps: the max. bps
- * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant)
+ * snd_hdac_stream_format_bits - obtain bits per sample value.
+ * @format: the PCM format.
+ * @subformat: the PCM subformat.
+ * @maxbits: the maximum bits per sample.
*
- * Calculate the format bitset from the given rate, channels and th PCM format.
+ * Return: The number of bits per sample.
+ */
+unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat,
+ unsigned int maxbits)
+{
+ struct snd_pcm_hw_params params;
+ unsigned int bits;
+
+ memset(&params, 0, sizeof(params));
+
+ params_set_format(&params, snd_hdac_format_normalize(format));
+ snd_mask_set(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT),
+ (__force unsigned int)subformat);
+
+ bits = snd_pcm_hw_params_bits(&params);
+ if (maxbits)
+ return min(bits, maxbits);
+ return bits;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_format_bits);
+
+/**
+ * snd_hdac_stream_format - convert format parameters to SDxFMT value.
+ * @channels: the number of channels.
+ * @bits: bits per sample.
+ * @rate: the sample rate.
*
- * Return zero if invalid.
+ * Return: The format bitset or zero if invalid.
*/
-unsigned int snd_hdac_calc_stream_format(unsigned int rate,
- unsigned int channels,
- snd_pcm_format_t format,
- unsigned int maxbps,
- unsigned short spdif_ctls)
+unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate)
{
- int i;
unsigned int val = 0;
+ int i;
- for (i = 0; rate_bits[i].hz; i++)
+ for (i = 0; rate_bits[i].hz; i++) {
if (rate_bits[i].hz == rate) {
val = rate_bits[i].hda_fmt;
break;
}
+ }
+
if (!rate_bits[i].hz)
return 0;
- if (channels == 0 || channels > 8)
+ if (channels == 0 || channels > 16)
return 0;
val |= channels - 1;
- switch (snd_pcm_format_width(format)) {
+ switch (bits) {
case 8:
val |= AC_FMT_BITS_8;
break;
@@ -765,32 +809,49 @@ unsigned int snd_hdac_calc_stream_format(unsigned int rate,
val |= AC_FMT_BITS_16;
break;
case 20:
+ val |= AC_FMT_BITS_20;
+ break;
case 24:
+ val |= AC_FMT_BITS_24;
+ break;
case 32:
- if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
- val |= AC_FMT_BITS_32;
- else if (maxbps >= 24)
- val |= AC_FMT_BITS_24;
- else
- val |= AC_FMT_BITS_20;
+ val |= AC_FMT_BITS_32;
break;
default:
return 0;
}
- if (spdif_ctls & AC_DIG1_NONAUDIO)
+ return val;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_stream_format);
+
+/**
+ * snd_hdac_spdif_stream_format - convert format parameters to SDxFMT value.
+ * @channels: the number of channels.
+ * @bits: bits per sample.
+ * @rate: the sample rate.
+ * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant).
+ *
+ * Return: The format bitset or zero if invalid.
+ */
+unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits,
+ unsigned int rate, unsigned short spdif_ctls)
+{
+ unsigned int val = snd_hdac_stream_format(channels, bits, rate);
+
+ if (val && spdif_ctls & AC_DIG1_NONAUDIO)
val |= AC_FMT_TYPE_NON_PCM;
return val;
}
-EXPORT_SYMBOL_GPL(snd_hdac_calc_stream_format);
+EXPORT_SYMBOL_GPL(snd_hdac_spdif_stream_format);
static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid)
{
unsigned int val = 0;
if (nid != codec->afg &&
- (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+ (snd_hdac_get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM);
if (!val || val == -1)
val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM);
@@ -816,19 +877,21 @@ static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid)
* @nid: NID to query
* @ratesp: the pointer to store the detected rate bitflags
* @formatsp: the pointer to store the detected formats
+ * @subformatsp: the pointer to store the detected subformats for S32_LE format
* @bpsp: the pointer to store the detected format widths
*
- * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp
- * or @bsps argument is ignored.
+ * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp,
+ * @subformatsp or @bpsp argument is ignored.
*
* Returns 0 if successful, otherwise a negative error code.
*/
int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
- u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
+ u32 *ratesp, u64 *formatsp, u32 *subformatsp,
+ unsigned int *bpsp)
{
unsigned int i, val, wcaps;
- wcaps = get_wcaps(codec, nid);
+ wcaps = snd_hdac_get_wcaps(codec, nid);
val = query_pcm_param(codec, nid);
if (ratesp) {
@@ -847,9 +910,10 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
*ratesp = rates;
}
- if (formatsp || bpsp) {
- u64 formats = 0;
+ if (formatsp || subformatsp || bpsp) {
unsigned int streams, bps;
+ u32 subformats = 0;
+ u64 formats = 0;
streams = query_stream_param(codec, nid);
if (!streams)
@@ -865,24 +929,24 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
formats |= SNDRV_PCM_FMTBIT_S16_LE;
bps = 16;
}
- if (wcaps & AC_WCAP_DIGITAL) {
- if (val & AC_SUPPCM_BITS_32)
+ if (val & AC_SUPPCM_BITS_20) {
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_20;
+ bps = 20;
+ }
+ if (val & AC_SUPPCM_BITS_24) {
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_24;
+ bps = 24;
+ }
+ if (val & AC_SUPPCM_BITS_32) {
+ if (wcaps & AC_WCAP_DIGITAL) {
formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
- if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24))
+ } else {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (val & AC_SUPPCM_BITS_24)
- bps = 24;
- else if (val & AC_SUPPCM_BITS_20)
- bps = 20;
- } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|
- AC_SUPPCM_BITS_32)) {
- formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (val & AC_SUPPCM_BITS_32)
+ subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_MAX;
bps = 32;
- else if (val & AC_SUPPCM_BITS_24)
- bps = 24;
- else if (val & AC_SUPPCM_BITS_20)
- bps = 20;
+ }
}
}
#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
@@ -910,6 +974,8 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
}
if (formatsp)
*formatsp = formats;
+ if (subformatsp)
+ *subformatsp = subformats;
if (bpsp)
*bpsp = bps;
}
diff --git a/sound/hda/ext/Makefile b/sound/hda/core/ext/Makefile
index 154779bdc0ba..85190a7eb5de 100644
--- a/sound/hda/ext/Makefile
+++ b/sound/hda/core/ext/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-hda-ext-core-objs := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o
+snd-hda-ext-core-y := bus.o controller.o stream.o
obj-$(CONFIG_SND_HDA_EXT_CORE) += snd-hda-ext-core.o
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/core/ext/bus.c
index 6004ea1c373e..6004ea1c373e 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/core/ext/bus.c
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/core/ext/controller.c
index 6199bb60ccf0..9eea3ea2dae0 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/core/ext/controller.c
@@ -9,6 +9,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/hda_register.h>
@@ -81,6 +82,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
int idx;
u32 link_count;
struct hdac_ext_link *hlink;
+ u32 leptr;
link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
@@ -96,6 +98,12 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
(AZX_ML_INTERVAL * idx);
hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
+ hlink->slcount = FIELD_GET(AZX_ML_HDA_LCAP_SLCOUNT, hlink->lcaps) + 1;
+
+ if (hdac_ext_link_alt(hlink)) {
+ leptr = readl(hlink->ml_addr + AZX_REG_ML_LEPTR);
+ hlink->id = FIELD_GET(AZX_REG_ML_LEPTR_ID, leptr);
+ }
/* since link in On, update the ref */
hlink->ref_count = 1;
@@ -125,6 +133,17 @@ void snd_hdac_ext_link_free_all(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all);
+struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_id(struct hdac_bus *bus, u32 id)
+{
+ struct hdac_ext_link *hlink;
+
+ list_for_each_entry(hlink, &bus->hlink_list, list)
+ if (hdac_ext_link_alt(hlink) && hlink->id == id)
+ return hlink;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_id);
+
/**
* snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address
* @bus: hlink's parent bus device
@@ -281,7 +300,7 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
unsigned long codec_mask;
int ret = 0;
- mutex_lock(&bus->lock);
+ guard(mutex)(&bus->lock);
/*
* if we move from 0 to 1, count will be 1 so power up this link
@@ -312,7 +331,6 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
bus->codec_mask = codec_mask;
}
- mutex_unlock(&bus->lock);
return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
@@ -324,7 +342,7 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
struct hdac_ext_link *hlink_tmp;
bool link_up = false;
- mutex_lock(&bus->lock);
+ guard(mutex)(&bus->lock);
/*
* if we move from 1 to 0, count will be 0
@@ -350,7 +368,6 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
}
}
- mutex_unlock(&bus->lock);
return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/core/ext/stream.c
index 11b7119cc47e..b4759198e51d 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/core/ext/stream.c
@@ -10,6 +10,8 @@
*/
#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/hda_register.h>
@@ -17,6 +19,39 @@
#include <sound/compress_driver.h>
/**
+ * snd_hdac_ext_host_stream_setup - Setup a HOST stream.
+ * @hext_stream: HDAudio stream to set up.
+ * @code_loading: Whether the stream is for PCM or code-loading.
+ *
+ * Return: Zero on success or negative error code.
+ */
+int snd_hdac_ext_host_stream_setup(struct hdac_ext_stream *hext_stream, bool code_loading)
+{
+ return hext_stream->host_setup(hdac_stream(hext_stream), code_loading);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_host_stream_setup);
+
+/**
+ * snd_hdac_apl_host_stream_setup - Setup a HOST stream following procedure
+ * recommended for ApolloLake devices.
+ * @hstream: HDAudio stream to set up.
+ * @code_loading: Whether the stream is for PCM or code-loading.
+ *
+ * Return: Zero on success or negative error code.
+ */
+static int snd_hdac_apl_host_stream_setup(struct hdac_stream *hstream, bool code_loading)
+{
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+ int ret;
+
+ snd_hdac_ext_stream_decouple(hstream->bus, hext_stream, false);
+ ret = snd_hdac_stream_setup(hstream, code_loading);
+ snd_hdac_ext_stream_decouple(hstream->bus, hext_stream, true);
+
+ return ret;
+}
+
+/**
* snd_hdac_ext_stream_init - initialize each stream (aka device)
* @bus: HD-audio core bus
* @hext_stream: HD-audio ext core stream object to initialize
@@ -55,9 +90,16 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
int num_stream, int dir)
{
+ struct pci_dev *pci = to_pci_dev(bus->dev);
+ int (*setup_op)(struct hdac_stream *, bool);
int stream_tag = 0;
int i, tag, idx = start_idx;
+ if (pci->device == PCI_DEVICE_ID_INTEL_HDA_APL)
+ setup_op = snd_hdac_apl_host_stream_setup;
+ else
+ setup_op = snd_hdac_stream_setup;
+
for (i = 0; i < num_stream; i++) {
struct hdac_ext_stream *hext_stream =
kzalloc(sizeof(*hext_stream), GFP_KERNEL);
@@ -66,6 +108,7 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
tag = ++stream_tag;
snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag);
idx++;
+ hext_stream->host_setup = setup_op;
}
return 0;
@@ -120,9 +163,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple_locked);
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
struct hdac_ext_stream *hext_stream, bool decouple)
{
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
snd_hdac_ext_stream_decouple_locked(bus, hext_stream, decouple);
- spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple);
@@ -222,7 +264,7 @@ hdac_ext_link_dma_stream_assign(struct hdac_bus *bus,
return NULL;
}
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream = container_of(hstream,
struct hdac_ext_stream,
@@ -242,7 +284,6 @@ hdac_ext_link_dma_stream_assign(struct hdac_bus *bus,
res->link_locked = 1;
res->link_substream = substream;
}
- spin_unlock_irq(&bus->reg_lock);
return res;
}
@@ -258,7 +299,7 @@ hdac_ext_host_dma_stream_assign(struct hdac_bus *bus,
return NULL;
}
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream = container_of(hstream,
struct hdac_ext_stream,
@@ -277,7 +318,6 @@ hdac_ext_host_dma_stream_assign(struct hdac_bus *bus,
res->hstream.running = 0;
res->hstream.substream = substream;
}
- spin_unlock_irq(&bus->reg_lock);
return res;
}
@@ -344,22 +384,22 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
break;
case HDAC_EXT_STREAM_TYPE_HOST:
- spin_lock_irq(&bus->reg_lock);
- /* couple link only if not in use */
- if (!hext_stream->link_locked)
- snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
- snd_hdac_stream_release_locked(&hext_stream->hstream);
- spin_unlock_irq(&bus->reg_lock);
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ /* couple link only if not in use */
+ if (!hext_stream->link_locked)
+ snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
+ snd_hdac_stream_release_locked(&hext_stream->hstream);
+ }
break;
case HDAC_EXT_STREAM_TYPE_LINK:
- spin_lock_irq(&bus->reg_lock);
- /* couple host only if not in use */
- if (!hext_stream->hstream.opened)
- snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
- hext_stream->link_locked = 0;
- hext_stream->link_substream = NULL;
- spin_unlock_irq(&bus->reg_lock);
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ /* couple host only if not in use */
+ if (!hext_stream->hstream.opened)
+ snd_hdac_ext_stream_decouple_locked(bus, hext_stream, false);
+ hext_stream->link_locked = 0;
+ hext_stream->link_substream = NULL;
+ }
break;
default:
@@ -384,7 +424,7 @@ struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
@@ -403,7 +443,6 @@ struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
res->hstream.running = 0;
res->hstream.cstream = cstream;
}
- spin_unlock_irq(&bus->reg_lock);
return res;
}
diff --git a/sound/hda/hda_bus_type.c b/sound/hda/core/hda_bus_type.c
index 4cd94178df9f..eb72a7af2e56 100644
--- a/sound/hda/hda_bus_type.c
+++ b/sound/hda/core/hda_bus_type.c
@@ -21,7 +21,7 @@ MODULE_LICENSE("GPL");
* driver id_table and returns the matching device id entry.
*/
const struct hda_device_id *
-hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv)
+hdac_get_device_id(struct hdac_device *hdev, const struct hdac_driver *drv)
{
if (drv->id_table) {
const struct hda_device_id *id = drv->id_table;
@@ -38,7 +38,7 @@ hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv)
}
EXPORT_SYMBOL_GPL(hdac_get_device_id);
-static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
+static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv)
{
if (hdac_get_device_id(dev, drv))
return 1;
@@ -46,10 +46,10 @@ static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
return 0;
}
-static int hda_bus_match(struct device *dev, struct device_driver *drv)
+static int hda_bus_match(struct device *dev, const struct device_driver *drv)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
- struct hdac_driver *hdrv = drv_to_hdac_driver(drv);
+ const struct hdac_driver *hdrv = drv_to_hdac_driver(drv);
if (hdev->type != hdrv->type)
return 0;
@@ -76,7 +76,7 @@ static int hda_uevent(const struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-struct bus_type snd_hda_bus_type = {
+const struct bus_type snd_hda_bus_type = {
.name = "hdaudio",
.match = hda_bus_match,
.uevent = hda_uevent,
diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c
index 5d8e1d944b0a..7b276047f85a 100644
--- a/sound/hda/hdmi_chmap.c
+++ b/sound/hda/core/hdmi_chmap.c
@@ -753,6 +753,20 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
return 0;
}
+/* a simple sanity check for input values to chmap kcontrol */
+static int chmap_value_check(struct hdac_chmap *hchmap,
+ const struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+
+ for (i = 0; i < hchmap->channels_max; i++) {
+ if (ucontrol->value.integer.value[i] < 0 ||
+ ucontrol->value.integer.value[i] > SNDRV_CHMAP_LAST)
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -764,6 +778,10 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
unsigned char chmap[8], per_pin_chmap[8];
int i, err, ca, prepared = 0;
+ err = chmap_value_check(hchmap, ucontrol);
+ if (err < 0)
+ return err;
+
/* No monitor is connected in dyn_pcm_assign.
* It's invalid to setup the chmap
*/
diff --git a/sound/hda/hdac_i915.c b/sound/hda/core/i915.c
index 161a9711cd63..44438c799f95 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/core/i915.c
@@ -10,11 +10,12 @@
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/hda_register.h>
+#include <video/nomodeset.h>
-#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \
- ((pci)->device == 0x0c0c) || \
- ((pci)->device == 0x0d0c) || \
- ((pci)->device == 0x160c))
+static int gpu_bind = -1;
+module_param(gpu_bind, int, 0644);
+MODULE_PARM_DESC(gpu_bind, "Whether to bind sound component to GPU "
+ "(1=always, 0=never, -1=on nomodeset(default))");
/**
* snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW
@@ -39,7 +40,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq)
return; /* only for i915 binding */
- if (!IS_HSW_CONTROLLER(pci))
+ if (!HDA_CONTROLLER_IS_HSW(pci))
return; /* only HSW/BDW */
cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
@@ -80,14 +81,20 @@ static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac)
if (bus_a == bus_b)
return true;
- /*
- * on i915 discrete GPUs with embedded HDA audio, the two
- * devices are connected via 2nd level PCI bridge
- */
bus_a = bus_a->parent;
bus_b = bus_b->parent;
+
+ /* connected via parent bus (may be NULL!) */
+ if (bus_a == bus_b)
+ return true;
+
if (!bus_a || !bus_b)
return false;
+
+ /*
+ * on i915 discrete GPUs with embedded HDA audio, the two
+ * devices are connected via 2nd level PCI bridge
+ */
bus_a = bus_a->parent;
bus_b = bus_b->parent;
if (bus_a && bus_a == bus_b)
@@ -108,7 +115,8 @@ static int i915_component_master_match(struct device *dev, int subcomponent,
hdac_pci = to_pci_dev(bus->dev);
i915_pci = to_pci_dev(dev);
- if (!strcmp(dev->driver->name, "i915") &&
+ if ((!strcmp(dev->driver->name, "i915") ||
+ !strcmp(dev->driver->name, "xe")) &&
subcomponent == I915_COMPONENT_AUDIO &&
connectivity_check(i915_pci, hdac_pci))
return 1;
@@ -119,12 +127,41 @@ static int i915_component_master_match(struct device *dev, int subcomponent,
/* check whether Intel graphics is present and reachable */
static int i915_gfx_present(struct pci_dev *hdac_pci)
{
+ /* List of known platforms with no i915 support. */
+ static const struct pci_device_id denylist[] = {
+ /* CNL */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a40), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a41), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a42), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a44), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a49), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4a), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4c), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a50), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a51), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a52), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a54), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a59), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5a), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5c), 0x030000, 0xff0000 },
+ /* LKF */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9840), 0x030000, 0xff0000 },
+ {}
+ };
struct pci_dev *display_dev = NULL;
+ if (!gpu_bind || (gpu_bind < 0 && video_firmware_drivers_only()))
+ return false;
+
for_each_pci_dev(display_dev) {
- if (display_dev->vendor == PCI_VENDOR_ID_INTEL &&
- (display_dev->class >> 16) == PCI_BASE_CLASS_DISPLAY &&
- connectivity_check(display_dev, hdac_pci)) {
+ if (display_dev->vendor != PCI_VENDOR_ID_INTEL ||
+ !pci_is_display(display_dev))
+ continue;
+
+ if (pci_match_id(denylist, display_dev))
+ continue;
+
+ if (connectivity_check(display_dev, hdac_pci)) {
pci_dev_put(display_dev);
return true;
}
@@ -162,17 +199,9 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
if (!acomp)
return -ENODEV;
if (!acomp->ops) {
- if (!IS_ENABLED(CONFIG_MODULES) ||
- !request_module("i915")) {
- /* 60s timeout */
- wait_for_completion_killable_timeout(&acomp->master_bind_complete,
- msecs_to_jiffies(60 * 1000));
- }
- }
- if (!acomp->ops) {
- dev_info(bus->dev, "couldn't bind with audio component\n");
snd_hdac_acomp_exit(bus);
- return -ENODEV;
+ return dev_err_probe(bus->dev, -EPROBE_DEFER,
+ "couldn't bind with audio component\n");
}
return 0;
}
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c
index 317bdf6dcbef..c401c0658421 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/core/intel-dsp-config.c
@@ -13,10 +13,12 @@
#include <sound/intel-nhlt.h>
#include <sound/soc-acpi.h>
+#include <acpi/nhlt.h>
+
static int dsp_driver;
module_param(dsp_driver, int, 0444);
-MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
+MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF, 4=AVS)");
#define FLAG_SST BIT(0)
#define FLAG_SOF BIT(1)
@@ -50,46 +52,35 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
{
.flags = FLAG_SOF,
- .device = 0x119a,
- },
-#endif
-/* Broxton-T */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
- {
- .flags = FLAG_SOF,
- .device = 0x1a98,
+ .device = PCI_DEVICE_ID_INTEL_SST_TNG,
},
#endif
/*
- * Apollolake (Broxton-P)
+ * Skylake, Kabylake, Apollolake
* the legacy HDAudio driver is used except on Up Squared (SOF) and
* Chromebooks (SST), as well as devices based on the ES8336 codec
*/
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS)
{
- .flags = FLAG_SOF,
- .device = 0x5a98,
+ .flags = FLAG_SST,
+ .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
.dmi_table = (const struct dmi_system_id []) {
{
- .ident = "Up Squared",
+ .ident = "Google Chromebooks",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
- DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
}
},
{}
}
},
{
- .flags = FLAG_SOF,
- .device = 0x5a98,
- .codec_hid = &essx_83x6,
+ .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
+ .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
{
.flags = FLAG_SST,
- .device = 0x5a98,
+ .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -100,17 +91,13 @@ static const struct config_entry config_table[] = {
{}
}
},
-#endif
-/*
- * Skylake and Kabylake use legacy HDAudio driver except for Google
- * Chromebooks (SST)
- */
-
-/* Sunrise Point-LP */
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
+ {
+ .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
+ .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
+ },
{
.flags = FLAG_SST,
- .device = 0x9d70,
+ .device = PCI_DEVICE_ID_INTEL_HDA_APL,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -122,28 +109,40 @@ static const struct config_entry config_table[] = {
}
},
{
- .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
- .device = 0x9d70,
+ .flags = FLAG_SST,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
},
-#endif
-/* Kabylake-LP */
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
{
.flags = FLAG_SST,
- .device = 0x9d71,
+ .device = PCI_DEVICE_ID_INTEL_HDA_FCL,
+ },
+#else /* AVS disabled; force to legacy as SOF doesn't work for SKL or KBL */
+ {
+ .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
+ },
+ {
+ .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
+ },
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
+ {
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_APL,
.dmi_table = (const struct dmi_system_id []) {
{
- .ident = "Google Chromebooks",
+ .ident = "Up Squared",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
+ DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
}
},
{}
}
},
{
- .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
- .device = 0x9d71,
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_APL,
+ .codec_hid = &essx_83x6,
},
#endif
@@ -155,7 +154,7 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
{
.flags = FLAG_SOF,
- .device = 0x3198,
+ .device = PCI_DEVICE_ID_INTEL_HDA_GML,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -168,16 +167,16 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF,
- .device = 0x3198,
+ .device = PCI_DEVICE_ID_INTEL_HDA_GML,
.codec_hid = &essx_83x6,
},
#endif
/*
- * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
- * HDAudio driver except for Google Chromebooks and when DMICs are
- * present. Two cases are required since Coreboot does not expose NHLT
- * tables.
+ * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake, AlderLake,
+ * RaptorLake, MeteorLake use legacy HDAudio driver except for Google
+ * Chromebooks and when DMICs are present. Two cases are required since
+ * Coreboot does not expose NHLT tables.
*
* When the Chromebook quirk is not present, it's based on information
* that no such device exists. When the quirk is present, it could be
@@ -188,7 +187,7 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
{
.flags = FLAG_SOF,
- .device = 0x9dc8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -207,12 +206,12 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF,
- .device = 0x09dc8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x9dc8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
},
#endif
@@ -220,7 +219,7 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
{
.flags = FLAG_SOF,
- .device = 0xa348,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -233,7 +232,7 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0xa348,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
},
#endif
@@ -241,7 +240,7 @@ static const struct config_entry config_table[] = {
/* Cometlake-LP */
{
.flags = FLAG_SOF,
- .device = 0x02c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -267,17 +266,17 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF,
- .device = 0x02c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x02c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
},
/* Cometlake-H */
{
.flags = FLAG_SOF,
- .device = 0x06c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
.dmi_table = (const struct dmi_system_id []) {
{
.matches = {
@@ -296,12 +295,12 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF,
- .device = 0x06c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x06c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
},
#endif
@@ -309,7 +308,7 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
{
.flags = FLAG_SOF,
- .device = 0x34c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -322,12 +321,12 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF,
- .device = 0x34c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x34c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
},
#endif
@@ -335,7 +334,7 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
{
.flags = FLAG_SOF,
- .device = 0x4dc8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -343,17 +342,23 @@ static const struct config_entry config_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
}
},
+ {
+ .ident = "Google firmware",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VERSION, "Google"),
+ }
+ },
{}
}
},
{
.flags = FLAG_SOF,
- .device = 0x4dc8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
- .device = 0x4dc8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
},
#endif
@@ -361,7 +366,7 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
{
.flags = FLAG_SOF,
- .device = 0xa0c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
.dmi_table = (const struct dmi_system_id []) {
{
.ident = "Google Chromebooks",
@@ -380,16 +385,16 @@ static const struct config_entry config_table[] = {
},
{
.flags = FLAG_SOF,
- .device = 0xa0c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0xa0c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x43c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H,
},
#endif
@@ -397,78 +402,121 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
- .device = 0x4b55,
+ .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
- .device = 0x4b58,
+ .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3,
},
#endif
-/* Alder Lake */
+/* Alder Lake / Raptor Lake */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
- /* Alderlake-S */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x7ad0,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S,
},
- /* RaptorLake-S */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x7a50,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S,
+ },
+ {
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .ident = "Google Chromebooks",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ }
+ },
+ {}
+ }
},
- /* Alderlake-P */
{
.flags = FLAG_SOF,
- .device = 0x51c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51cd,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX,
},
- /* Alderlake-PS */
{
.flags = FLAG_SOF,
- .device = 0x51c9,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51c9,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
},
- /* Alderlake-M */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51cc,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M,
+ },
+ {
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .ident = "Google Chromebooks",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ }
+ },
+ {}
+ }
},
- /* Alderlake-N */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x54c8,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
+ },
+ {
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .ident = "Google Chromebooks",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ }
+ },
+ {}
+ }
},
- /* RaptorLake-P */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51ca,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
+ },
+ {
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .ident = "Google Chromebooks",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ }
+ },
+ {}
+ }
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51cb,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
},
- /* RaptorLake-M */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51ce,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
},
- /* RaptorLake-PX */
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x51cf,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX,
},
#endif
@@ -476,8 +524,65 @@ static const struct config_entry config_table[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE)
/* Meteorlake-P */
{
+ .flags = FLAG_SOF,
+ .device = PCI_DEVICE_ID_INTEL_HDA_MTL,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .ident = "Google Chromebooks",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ }
+ },
+ {}
+ }
+ },
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_MTL,
+ },
+ /* ArrowLake-S */
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ARL_S,
+ },
+ /* ArrowLake */
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_ARL,
+ },
+#endif
+
+/* Lunar Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE)
+ /* Lunarlake-P */
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P,
+ },
+#endif
+
+ /* Panther Lake, Wildcat Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_PANTHERLAKE)
+ {
+ .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,
+ },
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_WCL,
+ },
+
+#endif
+
+ /* Nova Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOVALAKE)
+ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
- .device = 0x7e28,
+ .device = PCI_DEVICE_ID_INTEL_HDA_NVL_S,
},
#endif
@@ -497,9 +602,32 @@ static const struct config_entry *snd_intel_dsp_find_config
if (table->codec_hid) {
int i;
- for (i = 0; i < table->codec_hid->num_codecs; i++)
- if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
+ for (i = 0; i < table->codec_hid->num_codecs; i++) {
+ struct nhlt_acpi_table *nhlt;
+ bool ssp_found = false;
+
+ if (!acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
+ continue;
+
+ nhlt = intel_nhlt_init(&pci->dev);
+ if (!nhlt) {
+ dev_warn(&pci->dev, "%s: NHLT table not found, skipped HID %s\n",
+ __func__, table->codec_hid->codecs[i]);
+ continue;
+ }
+
+ if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP) &&
+ intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S))
+ ssp_found = true;
+
+ intel_nhlt_free(nhlt);
+
+ if (ssp_found)
break;
+
+ dev_warn(&pci->dev, "%s: no valid SSP found for HID %s, skipped\n",
+ __func__, table->codec_hid->codecs[i]);
+ }
if (i == table->codec_hid->num_codecs)
continue;
}
@@ -510,15 +638,15 @@ static const struct config_entry *snd_intel_dsp_find_config
static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
{
- struct nhlt_acpi_table *nhlt;
int ret = 0;
- nhlt = intel_nhlt_init(&pci->dev);
- if (nhlt) {
- if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
- ret = 1;
- intel_nhlt_free(nhlt);
- }
+ acpi_nhlt_get_gbl_table();
+
+ if (acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1))
+ ret = 1;
+
+ acpi_nhlt_put_gbl_table();
+
return ret;
}
@@ -530,6 +658,8 @@ static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
int ret;
handle = ACPI_HANDLE(&pci->dev);
+ if (!handle)
+ return -ENODEV;
ret = sdw_intel_acpi_scan(handle, &info);
if (ret < 0)
@@ -549,7 +679,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
const struct config_entry *cfg;
/* Intel vendor only */
- if (pci->vendor != 0x8086)
+ if (pci->vendor != PCI_VENDOR_ID_INTEL)
return SND_INTEL_DSP_DRIVER_ANY;
/*
@@ -557,12 +687,12 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
* for HDMI/DP support, ignore kernel parameter
*/
switch (pci->device) {
- case 0x160c: /* Broadwell */
- case 0x0a0c: /* Haswell */
- case 0x0c0c:
- case 0x0d0c:
- case 0x0f04: /* Baytrail */
- case 0x2284: /* Braswell */
+ case PCI_DEVICE_ID_INTEL_HDA_BDW:
+ case PCI_DEVICE_ID_INTEL_HDA_HSW_0:
+ case PCI_DEVICE_ID_INTEL_HDA_HSW_2:
+ case PCI_DEVICE_ID_INTEL_HDA_HSW_3:
+ case PCI_DEVICE_ID_INTEL_HDA_BYT:
+ case PCI_DEVICE_ID_INTEL_HDA_BSW:
return SND_INTEL_DSP_DRIVER_ANY;
}
@@ -583,7 +713,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
return SND_INTEL_DSP_DRIVER_LEGACY;
}
- dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+ dev_dbg(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
/* find the configuration for the specific device */
cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
@@ -593,12 +723,12 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
if (cfg->flags & FLAG_SOF) {
if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
snd_intel_dsp_check_soundwire(pci) > 0) {
- dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
+ dev_info_once(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
return SND_INTEL_DSP_DRIVER_SOF;
}
if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
snd_intel_dsp_check_dmic(pci)) {
- dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
+ dev_info_once(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
return SND_INTEL_DSP_DRIVER_SOF;
}
if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
@@ -609,7 +739,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
if (cfg->flags & FLAG_SST) {
if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
if (snd_intel_dsp_check_dmic(pci)) {
- dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
+ dev_info_once(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
return SND_INTEL_DSP_DRIVER_SST;
}
} else {
@@ -640,6 +770,10 @@ static const struct config_entry acpi_config_table[] = {
/* BayTrail */
{
.flags = FLAG_SST_OR_SOF_BYT,
+ .acpi_hid = "LPE0F28",
+ },
+ {
+ .flags = FLAG_SST_OR_SOF_BYT,
.acpi_hid = "80860F28",
},
/* CherryTrail */
@@ -714,4 +848,4 @@ EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel DSP config driver");
-MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
+MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI");
diff --git a/sound/hda/intel-nhlt.c b/sound/hda/core/intel-nhlt.c
index 2c4dfc0b7e34..6d72a871bda0 100644
--- a/sound/hda/intel-nhlt.c
+++ b/sound/hda/core/intel-nhlt.c
@@ -238,7 +238,7 @@ EXPORT_SYMBOL(intel_nhlt_ssp_mclk_mask);
static struct nhlt_specific_cfg *
nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
- u32 rate, u8 vbps, u8 bps)
+ u32 rate, u8 vbps, u8 bps, bool ignore_vbps)
{
struct nhlt_fmt_cfg *cfg = fmt->fmt_config;
struct wav_fmt *wfmt;
@@ -255,8 +255,12 @@ nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
dev_dbg(dev, "Endpoint format: ch=%d fmt=%d/%d rate=%d\n",
wfmt->channels, _vbps, _bps, wfmt->samples_per_sec);
+ /*
+ * When looking for exact match of configuration ignore the vbps
+ * from NHLT table when ignore_vbps is true
+ */
if (wfmt->channels == num_ch && wfmt->samples_per_sec == rate &&
- vbps == _vbps && bps == _bps)
+ (ignore_vbps || vbps == _vbps) && bps == _bps)
return &cfg->config;
cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size);
@@ -289,6 +293,7 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
{
struct nhlt_specific_cfg *cfg;
struct nhlt_endpoint *epnt;
+ bool ignore_vbps = false;
struct nhlt_fmt *fmt;
int i;
@@ -298,7 +303,26 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
dev_dbg(dev, "Looking for configuration:\n");
dev_dbg(dev, " vbus_id=%d link_type=%d dir=%d, dev_type=%d\n",
bus_id, link_type, dir, dev_type);
- dev_dbg(dev, " ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate);
+ if (link_type == NHLT_LINK_DMIC && bps == 32 && (vbps == 24 || vbps == 32)) {
+ /*
+ * The DMIC hardware supports only one type of 32 bits sample
+ * size, which is 24 bit sampling on the MSB side and bits[1:0]
+ * are used for indicating the channel number.
+ * It has been observed that some NHLT tables have the vbps
+ * specified as 32 while some uses 24.
+ * The format these variations describe are identical, the
+ * hardware is configured and behaves the same way.
+ * Note: when the samples assumed to be vbps=32 then the 'noise'
+ * introduced by the lower two bits (channel number) have no
+ * real life implication on audio quality.
+ */
+ dev_dbg(dev,
+ " ch=%d fmt=%d rate=%d (vbps is ignored for DMIC 32bit format)\n",
+ num_ch, bps, rate);
+ ignore_vbps = true;
+ } else {
+ dev_dbg(dev, " ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate);
+ }
dev_dbg(dev, "Endpoint count=%d\n", nhlt->endpoint_count);
epnt = (struct nhlt_endpoint *)nhlt->desc;
@@ -307,7 +331,8 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
if (nhlt_check_ep_match(dev, epnt, bus_id, link_type, dir, dev_type)) {
fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
- cfg = nhlt_get_specific_cfg(dev, fmt, num_ch, rate, vbps, bps);
+ cfg = nhlt_get_specific_cfg(dev, fmt, num_ch, rate,
+ vbps, bps, ignore_vbps);
if (cfg)
return cfg;
}
@@ -318,3 +343,46 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
return NULL;
}
EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob);
+
+int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt,
+ u8 virtual_bus_id)
+{
+ struct nhlt_endpoint *epnt;
+ int i;
+
+ if (!nhlt) {
+ dev_err(dev, "%s: NHLT table is missing (query for SSP%d)\n",
+ __func__, virtual_bus_id);
+ return -EINVAL;
+ }
+
+ epnt = (struct nhlt_endpoint *)nhlt->desc;
+ for (i = 0; i < nhlt->endpoint_count; i++) {
+ /* for SSP link the virtual bus id is the SSP port number */
+ if (epnt->linktype == NHLT_LINK_SSP &&
+ epnt->virtual_bus_id == virtual_bus_id) {
+ dev_dbg(dev, "SSP%d: dev_type=%d\n", virtual_bus_id,
+ epnt->device_type);
+ return epnt->device_type;
+ }
+
+ epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
+ }
+
+ dev_err(dev, "%s: No match for SSP%d in NHLT table\n", __func__,
+ virtual_bus_id);
+
+ dev_dbg(dev, "Available endpoints:\n");
+ epnt = (struct nhlt_endpoint *)nhlt->desc;
+ for (i = 0; i < nhlt->endpoint_count; i++) {
+ dev_dbg(dev,
+ "%d: link_type: %d, vbus_id: %d, dir: %d, dev_type: %d\n",
+ i, epnt->linktype, epnt->virtual_bus_id,
+ epnt->direction, epnt->device_type);
+
+ epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(intel_nhlt_ssp_device_type);
diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/core/intel-sdw-acpi.c
index 5cb92f7ccbca..d3511135f7d3 100644
--- a/sound/hda/intel-sdw-acpi.c
+++ b/sound/hda/core/intel-sdw-acpi.c
@@ -11,19 +11,22 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/export.h>
-#include <linux/fwnode.h>
#include <linux/module.h>
+#include <linux/property.h>
#include <linux/soundwire/sdw_intel.h>
#include <linux/string.h>
#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
-#define SDW_MAX_LINKS 4
static int ctrl_link_mask;
module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
-static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
+static ulong ctrl_addr = 0x40000000;
+module_param_named(sdw_ctrl_addr, ctrl_addr, ulong, 0444);
+MODULE_PARM_DESC(sdw_ctrl_addr, "Intel SoundWire Controller _ADR");
+
+static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx)
{
struct fwnode_handle *link;
char name[32];
@@ -31,7 +34,7 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
/* Find master handle */
snprintf(name, sizeof(name),
- "mipi-sdw-link-%d-subproperties", i);
+ "mipi-sdw-link-%hhu-subproperties", idx);
link = fwnode_get_named_child_node(fw_node, name);
if (!link)
@@ -41,6 +44,8 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
"intel-quirk-mask",
&quirk_mask);
+ fwnode_handle_put(link);
+
if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
return false;
@@ -51,18 +56,21 @@ static int
sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
{
struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
- int ret, i;
- u8 count;
+ struct fwnode_handle *fwnode;
+ unsigned long list;
+ unsigned int i;
+ u32 count;
+ u32 tmp;
+ int ret;
if (!adev)
return -EINVAL;
- /* Found controller, find links supported */
- count = 0;
- ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
- "mipi-sdw-master-count", &count, 1);
+ fwnode = acpi_fwnode_handle(adev);
/*
+ * Found controller, find links supported
+ *
* In theory we could check the number of links supported in
* hardware, but in that step we cannot assume SoundWire IP is
* powered.
@@ -73,17 +81,25 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
*
* We will check the hardware capabilities in the startup() step
*/
-
+ ret = fwnode_property_read_u32(fwnode, "mipi-sdw-manager-list", &tmp);
if (ret) {
- dev_err(&adev->dev,
- "Failed to read mipi-sdw-master-count: %d\n", ret);
- return -EINVAL;
+ ret = fwnode_property_read_u32(fwnode, "mipi-sdw-master-count", &count);
+ if (ret) {
+ dev_err(&adev->dev,
+ "Failed to read mipi-sdw-master-count: %d\n",
+ ret);
+ return ret;
+ }
+ list = GENMASK(count - 1, 0);
+ } else {
+ list = tmp;
+ count = hweight32(list);
}
/* Check count is within bounds */
- if (count > SDW_MAX_LINKS) {
+ if (count > SDW_INTEL_MAX_LINKS) {
dev_err(&adev->dev, "Link count %d exceeds max %d\n",
- count, SDW_MAX_LINKS);
+ count, SDW_INTEL_MAX_LINKS);
return -EINVAL;
}
@@ -96,14 +112,14 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
info->count = count;
info->link_mask = 0;
- for (i = 0; i < count; i++) {
+ for_each_set_bit(i, &list, SDW_INTEL_MAX_LINKS) {
if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
dev_dbg(&adev->dev,
"Link %d masked, will not be enabled\n", i);
continue;
}
- if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
+ if (!is_link_enabled(fwnode, i)) {
dev_dbg(&adev->dev,
"Link %d not selected in firmware\n", i);
continue;
@@ -119,11 +135,11 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
void *cdata, void **return_value)
{
struct sdw_intel_acpi_info *info = cdata;
- acpi_status status;
u64 adr;
+ int ret;
- status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
- if (ACPI_FAILURE(status))
+ ret = acpi_get_local_u64_address(handle, &adr);
+ if (ret < 0)
return AE_OK; /* keep going */
if (!acpi_fetch_acpi_dev(handle)) {
@@ -141,6 +157,9 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
return AE_OK; /* keep going */
+ if (adr != ctrl_addr)
+ return AE_OK; /* keep going */
+
/* found the correct SoundWire controller */
info->handle = handle;
@@ -158,7 +177,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
* sdw_intel_startup() is required for creation of devices and bus
* startup
*/
-int sdw_intel_acpi_scan(acpi_handle *parent_handle,
+int sdw_intel_acpi_scan(acpi_handle parent_handle,
struct sdw_intel_acpi_info *info)
{
acpi_status status;
@@ -179,7 +198,7 @@ int sdw_intel_acpi_scan(acpi_handle *parent_handle,
return sdw_intel_scan_controller(info);
}
-EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SND_INTEL_SOUNDWIRE_ACPI);
+EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, "SND_INTEL_SOUNDWIRE_ACPI");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Intel Soundwire ACPI helpers");
diff --git a/sound/hda/local.h b/sound/hda/core/local.h
index 896ba142e8bc..5f03b203c416 100644
--- a/sound/hda/local.h
+++ b/sound/hda/core/local.h
@@ -6,27 +6,6 @@
#ifndef __HDAC_LOCAL_H
#define __HDAC_LOCAL_H
-#define get_wcaps(codec, nid) \
- snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
-
-/* get the widget type from widget capability bits */
-static inline int get_wcaps_type(unsigned int wcaps)
-{
- if (!wcaps)
- return -1; /* invalid type */
- return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-}
-
-static inline unsigned int get_wcaps_channels(u32 wcaps)
-{
- unsigned int chans;
-
- chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
- chans = (chans + 1) * 2;
-
- return chans;
-}
-
extern const struct attribute_group *hdac_dev_attr_groups[];
int hda_widget_sysfs_init(struct hdac_device *codec);
int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid,
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/core/regmap.c
index 7cfaa908ff57..e7b866fc52c1 100644
--- a/sound/hda/hdac_regmap.c
+++ b/sound/hda/core/regmap.c
@@ -357,7 +357,7 @@ static const struct regmap_config hda_regmap_cfg = {
.writeable_reg = hda_writeable_reg,
.readable_reg = hda_readable_reg,
.volatile_reg = hda_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_read = hda_reg_read,
.reg_write = hda_reg_write,
.use_single_read = true,
@@ -425,15 +425,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
unsigned int val)
{
- int err;
-
- mutex_lock(&codec->regmap_lock);
+ guard(mutex)(&codec->regmap_lock);
if (!codec->regmap)
- err = hda_reg_write(codec, reg, val);
+ return hda_reg_write(codec, reg, val);
else
- err = regmap_write(codec->regmap, reg, val);
- mutex_unlock(&codec->regmap_lock);
- return err;
+ return regmap_write(codec->regmap, reg, val);
}
/* a helper macro to call @func_call; retry with power-up if failed */
@@ -466,15 +462,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
unsigned int *val, bool uncached)
{
- int err;
-
- mutex_lock(&codec->regmap_lock);
+ guard(mutex)(&codec->regmap_lock);
if (uncached || !codec->regmap)
- err = hda_reg_read(codec, reg, val);
+ return hda_reg_read(codec, reg, val);
else
- err = regmap_read(codec->regmap, reg, val);
- mutex_unlock(&codec->regmap_lock);
- return err;
+ return regmap_read(codec->regmap, reg, val);
}
static int __snd_hdac_regmap_read_raw(struct hdac_device *codec,
@@ -515,7 +507,7 @@ static int reg_raw_update(struct hdac_device *codec, unsigned int reg,
bool change;
int err;
- mutex_lock(&codec->regmap_lock);
+ guard(mutex)(&codec->regmap_lock);
if (codec->regmap) {
err = regmap_update_bits_check(codec->regmap, reg, mask, val,
&change);
@@ -533,7 +525,6 @@ static int reg_raw_update(struct hdac_device *codec, unsigned int reg,
}
}
}
- mutex_unlock(&codec->regmap_lock);
return err;
}
@@ -556,20 +547,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
static int reg_raw_update_once(struct hdac_device *codec, unsigned int reg,
unsigned int mask, unsigned int val)
{
- unsigned int orig;
- int err;
-
if (!codec->regmap)
return reg_raw_update(codec, reg, mask, val);
- mutex_lock(&codec->regmap_lock);
- regcache_cache_only(codec->regmap, true);
- err = regmap_read(codec->regmap, reg, &orig);
- regcache_cache_only(codec->regmap, false);
- if (err < 0)
- err = regmap_update_bits(codec->regmap, reg, mask, val);
- mutex_unlock(&codec->regmap_lock);
- return err;
+ guard(mutex)(&codec->regmap_lock);
+ /* Discard any updates to already initialised registers. */
+ if (!regcache_reg_cached(codec->regmap, reg))
+ return regmap_update_bits(codec->regmap, reg, mask, val);
+ return 0;
}
/**
@@ -596,10 +581,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw_once);
*/
void snd_hdac_regmap_sync(struct hdac_device *codec)
{
- if (codec->regmap) {
- mutex_lock(&codec->regmap_lock);
+ guard(mutex)(&codec->regmap_lock);
+ if (codec->regmap)
regcache_sync(codec->regmap);
- mutex_unlock(&codec->regmap_lock);
- }
}
EXPORT_SYMBOL_GPL(snd_hdac_regmap_sync);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/core/stream.c
index 1f56fd33b9af..579ec544ef4a 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/core/stream.c
@@ -150,7 +150,11 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev)
stripe_ctl);
}
/* set DMA start and interrupt mask */
- snd_hdac_stream_updateb(azx_dev, SD_CTL,
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL,
+ 0, SD_CTL_DMA_START | SD_INT_MASK);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL,
0, SD_CTL_DMA_START | SD_INT_MASK);
azx_dev->running = true;
}
@@ -248,12 +252,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_reset);
/**
* snd_hdac_stream_setup - set up the SD for streaming
* @azx_dev: HD-audio core stream to set up
+ * @code_loading: Whether the stream is for PCM or code-loading.
*/
-int snd_hdac_stream_setup(struct hdac_stream *azx_dev)
+int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading)
{
struct hdac_bus *bus = azx_dev->bus;
struct snd_pcm_runtime *runtime;
unsigned int val;
+ u16 reg;
+ int ret;
if (azx_dev->substream)
runtime = azx_dev->substream->runtime;
@@ -296,7 +303,15 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev)
/* set the interrupt enable bits in the descriptor control register */
snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_INT_MASK);
- azx_dev->fifo_size = snd_hdac_stream_readw(azx_dev, SD_FIFOSIZE) + 1;
+ if (!code_loading) {
+ /* Once SDxFMT is set, the controller programs SDxFIFOS to non-zero value. */
+ ret = snd_hdac_stream_readw_poll(azx_dev, SD_FIFOSIZE, reg,
+ reg & AZX_SD_FIFOSIZE_MASK, 3, 300);
+ if (ret)
+ dev_dbg(bus->dev, "polling SD_FIFOSIZE 0x%04x failed: %d\n",
+ AZX_REG_SD_FIFOSIZE, ret);
+ azx_dev->fifo_size = reg;
+ }
/* when LPIB delay correction gives a small negative value,
* we ignore it; currently set the threshold statically to
@@ -350,10 +365,12 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
struct hdac_stream *res = NULL;
/* make a non-zero unique key for the substream */
- int key = (substream->pcm->device << 16) | (substream->number << 2) |
- (substream->stream + 1);
+ int key = (substream->number << 2) | (substream->stream + 1);
- spin_lock_irq(&bus->reg_lock);
+ if (substream->pcm)
+ key |= (substream->pcm->device << 16);
+
+ guard(spinlock_irq)(&bus->reg_lock);
list_for_each_entry(azx_dev, &bus->stream_list, list) {
if (azx_dev->direction != substream->stream)
continue;
@@ -372,7 +389,6 @@ struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
res->assigned_key = key;
res->substream = substream;
}
- spin_unlock_irq(&bus->reg_lock);
return res;
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_assign);
@@ -402,9 +418,8 @@ void snd_hdac_stream_release(struct hdac_stream *azx_dev)
{
struct hdac_bus *bus = azx_dev->bus;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
snd_hdac_stream_release_locked(azx_dev);
- spin_unlock_irq(&bus->reg_lock);
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_release);
@@ -475,32 +490,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);
@@ -550,10 +554,37 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
return 0;
error:
- dev_err(bus->dev, "Too many BDL entries: buffer=%d, period=%d\n",
+ dev_dbg(bus->dev, "Too many BDL entries: buffer=%d, period=%d\n",
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);
/**
@@ -601,7 +632,7 @@ int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_set_params);
-static u64 azx_cc_read(const struct cyclecounter *cc)
+static u64 azx_cc_read(struct cyclecounter *cc)
{
struct hdac_stream *azx_dev = container_of(cc, struct hdac_stream, cc);
@@ -640,6 +671,7 @@ static void azx_timecounter_init(struct hdac_stream *azx_dev,
* snd_hdac_stream_timecounter_init - initialize time counter
* @azx_dev: HD-audio core stream (master stream)
* @streams: bit flags of streams to set up
+ * @start: true for PCM trigger start, false for other cases
*
* Initializes the time counter of streams marked by the bit flags (each
* bit corresponds to the stream index).
@@ -647,26 +679,28 @@ static void azx_timecounter_init(struct hdac_stream *azx_dev,
* updated accordingly, too.
*/
void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
- unsigned int streams)
+ unsigned int streams, bool start)
{
struct hdac_bus *bus = azx_dev->bus;
struct snd_pcm_runtime *runtime = azx_dev->substream->runtime;
struct hdac_stream *s;
bool inited = false;
u64 cycle_last = 0;
- int i = 0;
+
+ if (!start)
+ goto skip;
list_for_each_entry(s, &bus->stream_list, list) {
- if (streams & (1 << i)) {
+ if ((streams & (1 << s->index))) {
azx_timecounter_init(s, inited, cycle_last);
if (!inited) {
inited = true;
cycle_last = s->tc.cycle_last;
}
}
- i++;
}
+skip:
snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
runtime->trigger_tstamp_latched = true;
}
@@ -709,14 +743,13 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
unsigned int streams)
{
struct hdac_bus *bus = azx_dev->bus;
- int i, nwait, timeout;
+ int nwait, timeout;
struct hdac_stream *s;
for (timeout = 5000; timeout; timeout--) {
nwait = 0;
- i = 0;
list_for_each_entry(s, &bus->stream_list, list) {
- if (!(streams & (1 << i++)))
+ if (!(streams & (1 << s->index)))
continue;
if (start) {
@@ -791,25 +824,6 @@ int snd_hdac_stream_set_spib(struct hdac_bus *bus,
EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib);
/**
- * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream
- * @bus: HD-audio core bus
- * @azx_dev: hdac_stream
- *
- * Return maxfifo for the stream
- */
-int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus,
- struct hdac_stream *azx_dev)
-{
- if (!bus->spbcap) {
- dev_err(bus->dev, "Address of SPB capability is NULL\n");
- return -EINVAL;
- }
-
- return readl(azx_dev->fifo_addr);
-}
-EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo);
-
-/**
* snd_hdac_stream_drsm_enable - enable DMA resume for a stream
* @bus: HD-audio core bus
* @enable: flag to enable/disable DRSM
@@ -904,18 +918,14 @@ 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);
- spin_lock_irq(&bus->reg_lock);
- if (azx_dev->running || azx_dev->locked) {
- spin_unlock_irq(&bus->reg_lock);
- err = -EBUSY;
- goto unlock;
+ guard(snd_hdac_dsp_lock)(azx_dev);
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ if (azx_dev->running || azx_dev->locked)
+ return -EBUSY;
+ azx_dev->locked = true;
}
- azx_dev->locked = true;
- spin_unlock_irq(&bus->reg_lock);
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev,
byte_size, bufp);
@@ -924,33 +934,26 @@ 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;
- snd_hdac_stream_setup(azx_dev);
- snd_hdac_dsp_unlock(azx_dev);
+ snd_hdac_stream_setup(azx_dev, true);
return azx_dev->stream_tag;
error:
snd_dma_free_pages(bufp);
err_alloc:
- spin_lock_irq(&bus->reg_lock);
- azx_dev->locked = false;
- spin_unlock_irq(&bus->reg_lock);
- unlock:
- snd_hdac_dsp_unlock(azx_dev);
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ azx_dev->locked = false;
+ }
return err;
}
EXPORT_SYMBOL_GPL(snd_hdac_dsp_prepare);
@@ -982,7 +985,7 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
if (!dmab->area || !azx_dev->locked)
return;
- snd_hdac_dsp_lock(azx_dev);
+ guard(snd_hdac_dsp_lock)(azx_dev);
/* reset BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
@@ -994,10 +997,8 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
snd_dma_free_pages(dmab);
dmab->area = NULL;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
azx_dev->locked = false;
- spin_unlock_irq(&bus->reg_lock);
- snd_hdac_dsp_unlock(azx_dev);
}
EXPORT_SYMBOL_GPL(snd_hdac_dsp_cleanup);
#endif /* CONFIG_SND_HDA_DSP_LOADER */
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/core/sysfs.c
index 60b0a70428d5..bffe52859dba 100644
--- a/sound/hda/hdac_sysfs.c
+++ b/sound/hda/core/sysfs.c
@@ -161,13 +161,13 @@ static const struct kobj_type widget_ktype = {
static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid,
struct widget_attribute *attr, char *buf)
{
- return sysfs_emit(buf, "0x%08x\n", get_wcaps(codec, nid));
+ return sysfs_emit(buf, "0x%08x\n", snd_hdac_get_wcaps(codec, nid));
}
static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
struct widget_attribute *attr, char *buf)
{
- if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ if (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid)) != AC_WID_PIN)
return 0;
return sysfs_emit(buf, "0x%08x\n",
snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
@@ -178,7 +178,7 @@ static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
{
unsigned int val;
- if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ if (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid)) != AC_WID_PIN)
return 0;
if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
return 0;
@@ -189,7 +189,7 @@ static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid)
{
if (nid == codec->afg || nid == codec->mfg)
return true;
- switch (get_wcaps_type(get_wcaps(codec, nid))) {
+ switch (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid))) {
case AC_WID_AUD_OUT:
case AC_WID_AUD_IN:
return true;
@@ -219,7 +219,7 @@ static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
struct widget_attribute *attr, char *buf)
{
- if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+ if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
return 0;
return sysfs_emit(buf, "0x%08x\n",
snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
@@ -228,7 +228,7 @@ static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
struct widget_attribute *attr, char *buf)
{
- if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+ if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
return 0;
return sysfs_emit(buf, "0x%08x\n",
snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
@@ -237,7 +237,7 @@ static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
struct widget_attribute *attr, char *buf)
{
- if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER))
+ if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_POWER))
return 0;
return sysfs_emit(buf, "0x%08x\n",
snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
diff --git a/sound/hda/trace.c b/sound/hda/core/trace.c
index ca2d6bd94518..ca2d6bd94518 100644
--- a/sound/hda/trace.c
+++ b/sound/hda/core/trace.c
diff --git a/sound/hda/trace.h b/sound/hda/core/trace.h
index 2cc493434a8f..280c42f3eb75 100644
--- a/sound/hda/trace.h
+++ b/sound/hda/core/trace.h
@@ -24,7 +24,7 @@ TRACE_EVENT(hda_send_cmd,
__field(u32, cmd)
),
TP_fast_assign(
- __assign_str(name, dev_name((bus)->dev));
+ __assign_str(name);
__entry->cmd = cmd;
),
TP_printk("[%s:%d] val=0x%08x", __get_str(name), __entry->cmd >> 28, __entry->cmd)
@@ -39,7 +39,7 @@ TRACE_EVENT(hda_get_response,
__field(u32, res)
),
TP_fast_assign(
- __assign_str(name, dev_name((bus)->dev));
+ __assign_str(name);
__entry->addr = addr;
__entry->res = res;
),
@@ -55,7 +55,7 @@ TRACE_EVENT(hda_unsol_event,
__field(u32, res_ex)
),
TP_fast_assign(
- __assign_str(name, dev_name((bus)->dev));
+ __assign_str(name);
__entry->res = res;
__entry->res_ex = res_ex;
),
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index 09978855e08e..c827f9f70a33 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -4,9 +4,9 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-i2c-objs := i2c.o
-snd-cs8427-objs := cs8427.o
-snd-tea6330t-objs := tea6330t.o
+snd-i2c-y := i2c.o
+snd-cs8427-y := cs8427.o
+snd-tea6330t-y := tea6330t.o
obj-$(CONFIG_SND) += other/
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index f58b14b49045..46f081268348 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/bitrev.h>
#include <linux/module.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -52,8 +52,9 @@ int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
buf[1] = val;
err = snd_i2c_sendbytes(device, buf, 2);
if (err != 2) {
- snd_printk(KERN_ERR "unable to send bytes 0x%02x:0x%02x "
- "to CS8427 (%i)\n", buf[0], buf[1], err);
+ dev_err(device->bus->card->dev,
+ "unable to send bytes 0x%02x:0x%02x to CS8427 (%i)\n",
+ buf[0], buf[1], err);
return err < 0 ? err : -EIO;
}
return 0;
@@ -68,14 +69,14 @@ static int snd_cs8427_reg_read(struct snd_i2c_device *device, unsigned char reg)
err = snd_i2c_sendbytes(device, &reg, 1);
if (err != 1) {
- snd_printk(KERN_ERR "unable to send register 0x%x byte "
- "to CS8427\n", reg);
+ dev_err(device->bus->card->dev,
+ "unable to send register 0x%x byte to CS8427\n", reg);
return err < 0 ? err : -EIO;
}
err = snd_i2c_readbytes(device, &buf, 1);
if (err != 1) {
- snd_printk(KERN_ERR "unable to read register 0x%x byte "
- "from CS8427\n", reg);
+ dev_err(device->bus->card->dev,
+ "unable to read register 0x%x byte from CS8427\n", reg);
return err < 0 ? err : -EIO;
}
return buf;
@@ -195,16 +196,18 @@ int snd_cs8427_init(struct snd_i2c_bus *bus,
err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER);
if (err != CS8427_VER8427A) {
/* give second chance */
- snd_printk(KERN_WARNING "invalid CS8427 signature 0x%x: "
- "let me try again...\n", err);
+ dev_warn(device->bus->card->dev,
+ "invalid CS8427 signature 0x%x: let me try again...\n",
+ err);
err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER);
}
if (err != CS8427_VER8427A) {
snd_i2c_unlock(bus);
- snd_printk(KERN_ERR "unable to find CS8427 signature "
- "(expected 0x%x, read 0x%x),\n",
- CS8427_VER8427A, err);
- snd_printk(KERN_ERR " initialization is not completed\n");
+ dev_err(device->bus->card->dev,
+ "unable to find CS8427 signature (expected 0x%x, read 0x%x),\n",
+ CS8427_VER8427A, err);
+ dev_err(device->bus->card->dev,
+ " initialization is not completed\n");
return -EFAULT;
}
/* turn off run bit while making changes to configuration */
@@ -289,7 +292,7 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
snd_i2c_sendbytes(device, buf, 1);
snd_i2c_readbytes(device, buf, 127);
for (xx = 0; xx < 127; xx++)
- printk(KERN_DEBUG "reg[0x%x] = 0x%x\n", xx+1, buf[xx]);
+ dev_dbg(device->bus->card->dev, "reg[0x%x] = 0x%x\n", xx+1, buf[xx]);
}
#endif
@@ -392,15 +395,15 @@ static int snd_cs8427_qsubcode_get(struct snd_kcontrol *kcontrol,
snd_i2c_lock(device->bus);
err = snd_i2c_sendbytes(device, &reg, 1);
if (err != 1) {
- snd_printk(KERN_ERR "unable to send register 0x%x byte "
- "to CS8427\n", reg);
+ dev_err(device->bus->card->dev,
+ "unable to send register 0x%x byte to CS8427\n", reg);
snd_i2c_unlock(device->bus);
return err < 0 ? err : -EIO;
}
err = snd_i2c_readbytes(device, ucontrol->value.bytes.data, 10);
if (err != 10) {
- snd_printk(KERN_ERR "unable to read Q-subcode bytes "
- "from CS8427\n");
+ dev_err(device->bus->card->dev,
+ "unable to read Q-subcode bytes from CS8427\n");
snd_i2c_unlock(device->bus);
return err < 0 ? err : -EIO;
}
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 1a4ce1236146..0a2c0d147ab8 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -4,11 +4,11 @@
# Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ak4114-objs := ak4114.o
-snd-ak4117-objs := ak4117.o
-snd-ak4113-objs := ak4113.o
-snd-ak4xxx-adda-objs := ak4xxx-adda.o
-snd-pt2258-objs := pt2258.o
+snd-ak4114-y := ak4114.o
+snd-ak4117-y := ak4117.o
+snd-ak4113-y := ak4113.o
+snd-ak4xxx-adda-y := ak4xxx-adda.o
+snd-pt2258-y := pt2258.o
# Module Dependency
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c
index e7213092eb4f..70b3f7e17f9e 100644
--- a/sound/i2c/other/ak4113.c
+++ b/sound/i2c/other/ak4113.c
@@ -127,9 +127,9 @@ void snd_ak4113_reinit(struct ak4113 *chip)
{
if (atomic_inc_return(&chip->wq_processing) == 1)
cancel_delayed_work_sync(&chip->work);
- mutex_lock(&chip->reinit_mutex);
- ak4113_init_regs(chip);
- mutex_unlock(&chip->reinit_mutex);
+ scoped_guard(mutex, &chip->reinit_mutex) {
+ ak4113_init_regs(chip);
+ }
/* bring up statistics / event queing */
if (atomic_dec_and_test(&chip->wq_processing))
schedule_delayed_work(&chip->work, HZ / 10);
@@ -185,11 +185,10 @@ static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol,
{
struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
ucontrol->value.integer.value[0] =
chip->errors[kcontrol->private_value];
chip->errors[kcontrol->private_value] = 0;
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -235,14 +234,13 @@ static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol,
int change;
u8 old_val;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
old_val = chip->regmap[AK4113_REG_IO1];
change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val);
if (change)
reg_write(chip, AK4113_REG_IO1,
(old_val & (~AK4113_IPS(0xff))) |
(AK4113_IPS(ucontrol->value.integer.value[0])));
- spin_unlock_irq(&chip->lock);
return change;
}
@@ -532,27 +530,27 @@ int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags)
goto __rate;
rcs0 = reg_read(ak4113, AK4113_REG_RCS0);
rcs2 = reg_read(ak4113, AK4113_REG_RCS2);
- spin_lock_irqsave(&ak4113->lock, _flags);
- if (rcs0 & AK4113_PAR)
- ak4113->errors[AK4113_PARITY_ERRORS]++;
- if (rcs0 & AK4113_V)
- ak4113->errors[AK4113_V_BIT_ERRORS]++;
- if (rcs2 & AK4113_CCRC)
- ak4113->errors[AK4113_CCRC_ERRORS]++;
- if (rcs2 & AK4113_QCRC)
- ak4113->errors[AK4113_QCRC_ERRORS]++;
- c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
- AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^
- (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
- AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK));
- c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
- AK4113_DAT | 0xf0)) ^
- (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
- AK4113_DAT | 0xf0));
- ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC);
- ak4113->rcs1 = rcs1;
- ak4113->rcs2 = rcs2;
- spin_unlock_irqrestore(&ak4113->lock, _flags);
+ scoped_guard(spinlock_irqsave, &ak4113->lock) {
+ if (rcs0 & AK4113_PAR)
+ ak4113->errors[AK4113_PARITY_ERRORS]++;
+ if (rcs0 & AK4113_V)
+ ak4113->errors[AK4113_V_BIT_ERRORS]++;
+ if (rcs2 & AK4113_CCRC)
+ ak4113->errors[AK4113_CCRC_ERRORS]++;
+ if (rcs2 & AK4113_QCRC)
+ ak4113->errors[AK4113_QCRC_ERRORS]++;
+ c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
+ AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^
+ (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
+ AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK));
+ c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
+ AK4113_DAT | 0xf0)) ^
+ (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
+ AK4113_DAT | 0xf0));
+ ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC);
+ ak4113->rcs1 = rcs1;
+ ak4113->rcs2 = rcs2;
+ }
if (rcs0 & AK4113_PAR)
snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
@@ -599,8 +597,6 @@ __rate:
(runtime->rate != res)) {
snd_pcm_stream_lock_irqsave(ak4113->substream, _flags);
if (snd_pcm_running(ak4113->substream)) {
- /*printk(KERN_DEBUG "rate changed (%i <- %i)\n",
- * runtime->rate, res); */
snd_pcm_stop(ak4113->substream,
SNDRV_PCM_STATE_DRAINING);
wake_up(&runtime->sleep);
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index c0cffe28989b..0e3a272c1490 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -38,17 +38,6 @@ static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg)
return ak4114->read(ak4114->private_data, reg);
}
-#if 0
-static void reg_dump(struct ak4114 *ak4114)
-{
- int i;
-
- printk(KERN_DEBUG "AK4114 REG DUMP:\n");
- for (i = 0; i < 0x20; i++)
- printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < ARRAY_SIZE(ak4114->regmap) ? ak4114->regmap[i] : 0);
-}
-#endif
-
static void snd_ak4114_free(struct ak4114 *chip)
{
atomic_inc(&chip->wq_processing); /* don't schedule new work */
@@ -143,9 +132,9 @@ void snd_ak4114_reinit(struct ak4114 *chip)
{
if (atomic_inc_return(&chip->wq_processing) == 1)
cancel_delayed_work_sync(&chip->work);
- mutex_lock(&chip->reinit_mutex);
- ak4114_init_regs(chip);
- mutex_unlock(&chip->reinit_mutex);
+ scoped_guard(mutex, &chip->reinit_mutex) {
+ ak4114_init_regs(chip);
+ }
/* bring up statistics / event queing */
if (atomic_dec_and_test(&chip->wq_processing))
schedule_delayed_work(&chip->work, HZ / 10);
@@ -181,11 +170,10 @@ static int snd_ak4114_in_error_get(struct snd_kcontrol *kcontrol,
{
struct ak4114 *chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
ucontrol->value.integer.value[0] =
chip->errors[kcontrol->private_value];
chip->errors[kcontrol->private_value] = 0;
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -563,21 +551,21 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags)
if (flags & AK4114_CHECK_NO_STAT)
goto __rate;
rcs0 = reg_read(ak4114, AK4114_REG_RCS0);
- spin_lock_irqsave(&ak4114->lock, _flags);
- if (rcs0 & AK4114_PAR)
- ak4114->errors[AK4114_PARITY_ERRORS]++;
- if (rcs1 & AK4114_V)
- ak4114->errors[AK4114_V_BIT_ERRORS]++;
- if (rcs1 & AK4114_CCRC)
- ak4114->errors[AK4114_CCRC_ERRORS]++;
- if (rcs1 & AK4114_QCRC)
- ak4114->errors[AK4114_QCRC_ERRORS]++;
- c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^
- (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK));
- c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0);
- ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT);
- ak4114->rcs1 = rcs1;
- spin_unlock_irqrestore(&ak4114->lock, _flags);
+ scoped_guard(spinlock_irqsave, &ak4114->lock) {
+ if (rcs0 & AK4114_PAR)
+ ak4114->errors[AK4114_PARITY_ERRORS]++;
+ if (rcs1 & AK4114_V)
+ ak4114->errors[AK4114_V_BIT_ERRORS]++;
+ if (rcs1 & AK4114_CCRC)
+ ak4114->errors[AK4114_CCRC_ERRORS]++;
+ if (rcs1 & AK4114_QCRC)
+ ak4114->errors[AK4114_QCRC_ERRORS]++;
+ c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^
+ (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK));
+ c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0);
+ ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT);
+ ak4114->rcs1 = rcs1;
+ }
ak4114_notify(ak4114, rcs0, rcs1, c0, c1);
if (ak4114->change_callback && (c0 | c1) != 0)
@@ -589,7 +577,6 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags)
if (!(flags & AK4114_CHECK_NO_RATE) && runtime && runtime->rate != res) {
snd_pcm_stream_lock_irqsave(ak4114->capture_substream, _flags);
if (snd_pcm_running(ak4114->capture_substream)) {
- // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res);
snd_pcm_stop(ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING);
res = 1;
}
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index 640501bb3ca6..d2ec20f885f0 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -34,17 +34,6 @@ static inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg)
return ak4117->read(ak4117->private_data, reg);
}
-#if 0
-static void reg_dump(struct ak4117 *ak4117)
-{
- int i;
-
- printk(KERN_DEBUG "AK4117 REG DUMP:\n");
- for (i = 0; i < 0x1b; i++)
- printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0);
-}
-#endif
-
static void snd_ak4117_free(struct ak4117 *chip)
{
timer_shutdown_sync(&chip->timer);
@@ -110,7 +99,7 @@ void snd_ak4117_reinit(struct ak4117 *chip)
{
unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg;
- del_timer(&chip->timer);
+ timer_delete(&chip->timer);
chip->init = 1;
/* bring the chip to reset state and powerdown state */
reg_write(chip, AK4117_REG_PWRDN, 0);
@@ -155,11 +144,10 @@ static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol,
{
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
ucontrol->value.integer.value[0] =
chip->errors[kcontrol->private_value];
chip->errors[kcontrol->private_value] = 0;
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -203,12 +191,11 @@ static int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol,
int change;
u8 old_val;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
old_val = chip->regmap[AK4117_REG_IO];
change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0);
if (change)
reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0));
- spin_unlock_irq(&chip->lock);
return change;
}
@@ -452,24 +439,23 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags)
goto __rate;
rcs0 = reg_read(ak4117, AK4117_REG_RCS0);
rcs2 = reg_read(ak4117, AK4117_REG_RCS2);
- // printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2);
- spin_lock_irqsave(&ak4117->lock, _flags);
- if (rcs0 & AK4117_PAR)
- ak4117->errors[AK4117_PARITY_ERRORS]++;
- if (rcs0 & AK4117_V)
- ak4117->errors[AK4117_V_BIT_ERRORS]++;
- if (rcs2 & AK4117_CCRC)
- ak4117->errors[AK4117_CCRC_ERRORS]++;
- if (rcs2 & AK4117_QCRC)
- ak4117->errors[AK4117_QCRC_ERRORS]++;
- c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^
- (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK));
- c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^
- (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f));
- ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
- ak4117->rcs1 = rcs1;
- ak4117->rcs2 = rcs2;
- spin_unlock_irqrestore(&ak4117->lock, _flags);
+ scoped_guard(spinlock_irqsave, &ak4117->lock) {
+ if (rcs0 & AK4117_PAR)
+ ak4117->errors[AK4117_PARITY_ERRORS]++;
+ if (rcs0 & AK4117_V)
+ ak4117->errors[AK4117_V_BIT_ERRORS]++;
+ if (rcs2 & AK4117_CCRC)
+ ak4117->errors[AK4117_CCRC_ERRORS]++;
+ if (rcs2 & AK4117_QCRC)
+ ak4117->errors[AK4117_QCRC_ERRORS]++;
+ c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^
+ (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK));
+ c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^
+ (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f));
+ ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
+ ak4117->rcs1 = rcs1;
+ ak4117->rcs2 = rcs2;
+ }
if (rcs0 & AK4117_PAR)
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id);
@@ -505,7 +491,6 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags)
if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) {
snd_pcm_stream_lock_irqsave(ak4117->substream, _flags);
if (snd_pcm_running(ak4117->substream)) {
- // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res);
snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING);
wake_up(&runtime->sleep);
res = 1;
@@ -517,7 +502,7 @@ int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags)
static void snd_ak4117_timer(struct timer_list *t)
{
- struct ak4117 *chip = from_timer(chip, t, timer);
+ struct ak4117 *chip = timer_container_of(chip, t, timer);
if (chip->init)
return;
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 7d15093844b9..b24c80410d45 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -391,8 +391,6 @@ static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
nval = mask - nval;
if (AK_GET_NEEDSMSB(kcontrol->private_value))
nval |= 0x80;
- /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
- nval %x\n", chip, addr, nval); */
snd_akm4xxx_write(ak, chip, addr, nval);
return 1;
}
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c
index c913f223892a..0fbac827124b 100644
--- a/sound/i2c/other/pt2258.c
+++ b/sound/i2c/other/pt2258.c
@@ -63,7 +63,7 @@ int snd_pt2258_reset(struct snd_pt2258 *pt)
__error:
snd_i2c_unlock(pt->i2c_bus);
- snd_printk(KERN_ERR "PT2258 reset failed\n");
+ dev_err(pt->card->dev, "PT2258 reset failed\n");
return -EIO;
}
@@ -80,7 +80,7 @@ static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_pt2258 *pt = kcontrol->private_data;
+ struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol);
int base = kcontrol->private_value;
/* chip does not support register reads */
@@ -92,7 +92,7 @@ static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_pt2258 *pt = kcontrol->private_data;
+ struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol);
int base = kcontrol->private_value;
unsigned char bytes[2];
int val0, val1;
@@ -124,7 +124,7 @@ static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
__error:
snd_i2c_unlock(pt->i2c_bus);
- snd_printk(KERN_ERR "PT2258 access failed\n");
+ dev_err(pt->card->dev, "PT2258 access failed\n");
return -EIO;
}
@@ -133,7 +133,7 @@ static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_pt2258 *pt = kcontrol->private_data;
+ struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = !pt->mute;
return 0;
@@ -142,7 +142,7 @@ static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_pt2258 *pt = kcontrol->private_data;
+ struct snd_pt2258 *pt = snd_kcontrol_chip(kcontrol);
unsigned char bytes[2];
int val;
@@ -161,7 +161,7 @@ static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
__error:
snd_i2c_unlock(pt->i2c_bus);
- snd_printk(KERN_ERR "PT2258 access failed 2\n");
+ dev_err(pt->card->dev, "PT2258 access failed 2\n");
return -EIO;
}
diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c
index 037d6293f728..676d58054944 100644
--- a/sound/i2c/tea6330t.c
+++ b/sound/i2c/tea6330t.c
@@ -56,9 +56,6 @@ int snd_tea6330t_detect(struct snd_i2c_bus *bus, int equalizer)
static void snd_tea6330t_set(struct tea6330t *tea,
unsigned char addr, unsigned char value)
{
-#if 0
- printk(KERN_DEBUG "set - 0x%x/0x%x\n", addr, value);
-#endif
snd_i2c_write(tea->bus, TEA6330T_ADDR, addr, value, 1);
}
#endif
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 6ffa48dd5983..f8159179e38d 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -23,6 +23,7 @@ menuconfig SND_ISA
bool "ISA sound devices"
depends on ISA || COMPILE_TEST
depends on ISA_DMA_API
+ depends on HAS_IOPORT
default y
help
Support for sound devices connected via the ISA bus.
diff --git a/sound/isa/Makefile b/sound/isa/Makefile
index 5eaddbf4a712..2135d68a15ac 100644
--- a/sound/isa/Makefile
+++ b/sound/isa/Makefile
@@ -4,15 +4,15 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-adlib-objs := adlib.o
-snd-als100-objs := als100.o
-snd-azt2320-objs := azt2320.o
-snd-cmi8328-objs := cmi8328.o
-snd-cmi8330-objs := cmi8330.o
-snd-es18xx-objs := es18xx.o
-snd-opl3sa2-objs := opl3sa2.o
-snd-sc6000-objs := sc6000.o
-snd-sscape-objs := sscape.o
+snd-adlib-y := adlib.o
+snd-als100-y := als100.o
+snd-azt2320-y := azt2320.o
+snd-cmi8328-y := cmi8328.o
+snd-cmi8330-y := cmi8330.o
+snd-es18xx-y := es18xx.o
+snd-opl3sa2-y := opl3sa2.o
+snd-sc6000-y := sc6000.o
+snd-sscape-y := sscape.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
diff --git a/sound/isa/ad1816a/Makefile b/sound/isa/ad1816a/Makefile
index 93def7f16933..573325228534 100644
--- a/sound/isa/ad1816a/Makefile
+++ b/sound/isa/ad1816a/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ad1816a-objs := ad1816a.o ad1816a_lib.o
+snd-ad1816a-y := ad1816a.o ad1816a_lib.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AD1816A) += snd-ad1816a.o
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 9ac873773129..8e84d4091f1e 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -17,8 +17,6 @@
#include <sound/mpu401.h>
#include <sound/opl3.h>
-#define PFX "ad1816a: "
-
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
MODULE_DESCRIPTION("AD1816A, AD1815");
MODULE_LICENSE("GPL");
@@ -87,7 +85,7 @@ static int snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
err = pnp_activate_dev(pdev);
if (err < 0) {
- printk(KERN_ERR PFX "AUDIO PnP configure failure\n");
+ dev_err(&pdev->dev, "AUDIO PnP configure failure\n");
return -EBUSY;
}
@@ -100,13 +98,13 @@ static int snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
pdev = pnp_request_card_device(card, id->devs[1].id, NULL);
if (pdev == NULL) {
mpu_port[dev] = -1;
- snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
+ pr_warn("MPU401 device busy, skipping.\n");
return 0;
}
err = pnp_activate_dev(pdev);
if (err < 0) {
- printk(KERN_ERR PFX "MPU401 PnP configure failure\n");
+ dev_err(&pdev->dev, "MPU401 PnP configure failure\n");
mpu_port[dev] = -1;
} else {
mpu_port[dev] = pnp_port_start(pdev, 0);
@@ -145,8 +143,8 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
if (clockfreq[dev] >= 5000 && clockfreq[dev] <= 100000)
chip->clock_freq = clockfreq[dev];
- strcpy(card->driver, "AD1816A");
- strcpy(card->shortname, "ADI SoundPort AD1816A");
+ strscpy(card->driver, "AD1816A");
+ strscpy(card->shortname, "ADI SoundPort AD1816A");
sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
@@ -166,14 +164,16 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port[dev], 0, mpu_irq[dev],
NULL) < 0)
- printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpu_port[dev]);
+ dev_err(card->dev, "no MPU-401 device at 0x%lx.\n",
+ mpu_port[dev]);
}
if (fm_port[dev] > 0) {
if (snd_opl3_create(card,
fm_port[dev], fm_port[dev] + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
- printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx.\n", fm_port[dev], fm_port[dev] + 2);
+ dev_err(card->dev, "no OPL device at 0x%lx-0x%lx.\n",
+ fm_port[dev], fm_port[dev] + 2);
} else {
error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (error < 0)
@@ -252,7 +252,7 @@ static int __init alsa_card_ad1816a_init(void)
if (!ad1816a_devices) {
pnp_unregister_card_driver(&ad1816a_pnpc_driver);
#ifdef MODULE
- printk(KERN_ERR "no AD1816A based soundcards found.\n");
+ pr_err("no AD1816A based soundcards found.\n");
#endif /* MODULE */
return -ENODEV;
}
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 132a095dca2c..50f62304de61 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -25,7 +25,7 @@ static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
if (inb(AD1816A_REG(AD1816A_CHIP_STATUS)) & AD1816A_READY)
return 0;
- snd_printk(KERN_WARNING "chip busy.\n");
+ dev_warn(chip->card->dev, "chip busy.\n");
return -EBUSY;
}
@@ -96,14 +96,10 @@ static unsigned char snd_ad1816a_get_format(struct snd_ad1816a *chip,
static int snd_ad1816a_open(struct snd_ad1816a *chip, unsigned int mode)
{
- unsigned long flags;
+ guard(spinlock_irqsave)(&chip->lock);
- spin_lock_irqsave(&chip->lock, flags);
-
- if (chip->mode & mode) {
- spin_unlock_irqrestore(&chip->lock, flags);
+ if (chip->mode & mode)
return -EAGAIN;
- }
switch ((mode &= AD1816A_MODE_OPEN)) {
case AD1816A_MODE_PLAYBACK:
@@ -126,15 +122,12 @@ static int snd_ad1816a_open(struct snd_ad1816a *chip, unsigned int mode)
}
chip->mode |= mode;
- spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
switch ((mode &= AD1816A_MODE_OPEN)) {
case AD1816A_MODE_PLAYBACK:
@@ -158,8 +151,6 @@ static void snd_ad1816a_close(struct snd_ad1816a *chip, unsigned int mode)
chip->mode &= ~mode;
if (!(chip->mode & AD1816A_MODE_OPEN))
chip->mode = 0;
-
- spin_unlock_irqrestore(&chip->lock, flags);
}
@@ -171,22 +162,22 @@ static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_STOP:
- spin_lock(&chip->lock);
- cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
- /* if (what & AD1816A_PLAYBACK_ENABLE) */
- /* That is not valid, because playback and capture enable
- * are the same bit pattern, just to different addresses
- */
- if (! iscapture)
- snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
- AD1816A_PLAYBACK_ENABLE, cmd);
- else
- snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
- AD1816A_CAPTURE_ENABLE, cmd);
- spin_unlock(&chip->lock);
+ scoped_guard(spinlock, &chip->lock) {
+ cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
+ /* if (what & AD1816A_PLAYBACK_ENABLE) */
+ /* That is not valid, because playback and capture enable
+ * are the same bit pattern, just to different addresses
+ */
+ if (!iscapture)
+ snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
+ AD1816A_PLAYBACK_ENABLE, cmd);
+ else
+ snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
+ AD1816A_CAPTURE_ENABLE, cmd);
+ }
break;
default:
- snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
+ dev_warn(chip->card->dev, "invalid trigger mode 0x%x.\n", what);
error = -EINVAL;
}
@@ -210,11 +201,10 @@ static int snd_ad1816a_capture_trigger(struct snd_pcm_substream *substream, int
static int snd_ad1816a_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
- unsigned long flags;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int size, rate;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
chip->p_dma_size = size = snd_pcm_lib_buffer_bytes(substream);
snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
@@ -234,19 +224,16 @@ static int snd_ad1816a_playback_prepare(struct snd_pcm_substream *substream)
snd_ad1816a_write(chip, AD1816A_PLAYBACK_BASE_COUNT,
snd_pcm_lib_period_bytes(substream) / 4 - 1);
-
- spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int snd_ad1816a_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
- unsigned long flags;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int size, rate;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
chip->c_dma_size = size = snd_pcm_lib_buffer_bytes(substream);
snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
@@ -266,8 +253,6 @@ static int snd_ad1816a_capture_prepare(struct snd_pcm_substream *substream)
snd_ad1816a_write(chip, AD1816A_CAPTURE_BASE_COUNT,
snd_pcm_lib_period_bytes(substream) / 4 - 1);
-
- spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -298,9 +283,9 @@ static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id)
struct snd_ad1816a *chip = dev_id;
unsigned char status;
- spin_lock(&chip->lock);
- status = snd_ad1816a_in(chip, AD1816A_INTERRUPT_STATUS);
- spin_unlock(&chip->lock);
+ scoped_guard(spinlock, &chip->lock) {
+ status = snd_ad1816a_in(chip, AD1816A_INTERRUPT_STATUS);
+ }
if ((status & AD1816A_PLAYBACK_IRQ_PENDING) && chip->playback_substream)
snd_pcm_period_elapsed(chip->playback_substream);
@@ -311,9 +296,9 @@ static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id)
if ((status & AD1816A_TIMER_IRQ_PENDING) && chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
- spin_lock(&chip->lock);
- snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00);
- spin_unlock(&chip->lock);
+ scoped_guard(spinlock, &chip->lock) {
+ snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00);
+ }
return IRQ_HANDLED;
}
@@ -381,9 +366,9 @@ static unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer)
static int snd_ad1816a_timer_start(struct snd_timer *timer)
{
unsigned short bits;
- unsigned long flags;
struct snd_ad1816a *chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->lock, flags);
+
+ guard(spinlock_irqsave)(&chip->lock);
bits = snd_ad1816a_read(chip, AD1816A_INTERRUPT_ENABLE);
if (!(bits & AD1816A_TIMER_ENABLE)) {
@@ -393,20 +378,16 @@ static int snd_ad1816a_timer_start(struct snd_timer *timer)
snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
AD1816A_TIMER_ENABLE, 0xffff);
}
- spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int snd_ad1816a_timer_stop(struct snd_timer *timer)
{
- unsigned long flags;
struct snd_ad1816a *chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
snd_ad1816a_write_mask(chip, AD1816A_INTERRUPT_ENABLE,
AD1816A_TIMER_ENABLE, 0x0000);
-
- spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -474,9 +455,7 @@ static int snd_ad1816a_capture_close(struct snd_pcm_substream *substream)
static void snd_ad1816a_init(struct snd_ad1816a *chip)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
snd_ad1816a_out(chip, AD1816A_INTERRUPT_STATUS, 0x00);
snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
@@ -488,40 +467,32 @@ static void snd_ad1816a_init(struct snd_ad1816a *chip)
AD1816A_CAPTURE_NOT_EQUAL | AD1816A_WSS_ENABLE, 0xffff);
snd_ad1816a_write(chip, AD1816A_DSP_CONFIG, 0x0000);
snd_ad1816a_write(chip, AD1816A_POWERDOWN_CTRL, 0x0000);
-
- spin_unlock_irqrestore(&chip->lock, flags);
}
#ifdef CONFIG_PM
void snd_ad1816a_suspend(struct snd_ad1816a *chip)
{
int reg;
- unsigned long flags;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
for (reg = 0; reg < 48; reg++)
chip->image[reg] = snd_ad1816a_read(chip, reg);
- spin_unlock_irqrestore(&chip->lock, flags);
}
void snd_ad1816a_resume(struct snd_ad1816a *chip)
{
int reg;
- unsigned long flags;
snd_ad1816a_init(chip);
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
for (reg = 0; reg < 48; reg++)
snd_ad1816a_write(chip, reg, chip->image[reg]);
- spin_unlock_irqrestore(&chip->lock, flags);
}
#endif
static int snd_ad1816a_probe(struct snd_ad1816a *chip)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
switch (chip->version = snd_ad1816a_read(chip, AD1816A_VERSION_ID)) {
case 0:
@@ -536,8 +507,6 @@ static int snd_ad1816a_probe(struct snd_ad1816a *chip)
default:
chip->hardware = AD1816A_HW_AUTO;
}
-
- spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -548,8 +517,8 @@ static const char *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
case AD1816A_HW_AD1815: return "AD1815";
case AD1816A_HW_AD18MAX10: return "AD18max10";
default:
- snd_printk(KERN_WARNING "Unknown chip version %d:%d.\n",
- chip->version, chip->hardware);
+ dev_warn(chip->card->dev, "Unknown chip version %d:%d.\n",
+ chip->version, chip->hardware);
return "AD1816A - unknown";
}
}
@@ -566,23 +535,23 @@ int snd_ad1816a_create(struct snd_card *card,
chip->res_port = devm_request_region(card->dev, port, 16, "AD1816A");
if (!chip->res_port) {
- snd_printk(KERN_ERR "ad1816a: can't grab port 0x%lx\n", port);
+ dev_err(card->dev, "ad1816a: can't grab port 0x%lx\n", port);
return -EBUSY;
}
if (devm_request_irq(card->dev, irq, snd_ad1816a_interrupt, 0,
"AD1816A", (void *) chip)) {
- snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq);
+ dev_err(card->dev, "ad1816a: can't grab IRQ %d\n", irq);
return -EBUSY;
}
chip->irq = irq;
card->sync_irq = chip->irq;
if (snd_devm_request_dma(card->dev, dma1, "AD1816A - 1")) {
- snd_printk(KERN_ERR "ad1816a: can't grab DMA1 %d\n", dma1);
+ dev_err(card->dev, "ad1816a: can't grab DMA1 %d\n", dma1);
return -EBUSY;
}
chip->dma1 = dma1;
if (snd_devm_request_dma(card->dev, dma2, "AD1816A - 2")) {
- snd_printk(KERN_ERR "ad1816a: can't grab DMA2 %d\n", dma2);
+ dev_err(card->dev, "ad1816a: can't grab DMA2 %d\n", dma2);
return -EBUSY;
}
chip->dma2 = dma2;
@@ -631,7 +600,7 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device)
pcm->private_data = chip;
pcm->info_flags = (chip->dma1 == chip->dma2 ) ? SNDRV_PCM_INFO_JOINT_DUPLEX : 0;
- strcpy(pcm->name, snd_ad1816a_chip_id(chip));
+ strscpy(pcm->name, snd_ad1816a_chip_id(chip));
snd_ad1816a_init(chip);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, chip->card->dev,
@@ -655,7 +624,7 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device)
error = snd_timer_new(chip->card, "AD1816A", &tid, &timer);
if (error < 0)
return error;
- strcpy(timer->name, snd_ad1816a_chip_id(chip));
+ strscpy(timer->name, snd_ad1816a_chip_id(chip));
timer->private_data = chip;
chip->timer = timer;
timer->hw = snd_ad1816a_timer_table;
@@ -679,12 +648,10 @@ static int snd_ad1816a_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned short val;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
val = snd_ad1816a_read(chip, AD1816A_ADC_SOURCE_SEL);
- spin_unlock_irqrestore(&chip->lock, flags);
ucontrol->value.enumerated.item[0] = (val >> 12) & 7;
ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
return 0;
@@ -693,7 +660,6 @@ static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned short val;
int change;
@@ -702,10 +668,9 @@ static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
return -EINVAL;
val = (ucontrol->value.enumerated.item[0] << 12) |
(ucontrol->value.enumerated.item[1] << 4);
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
change = snd_ad1816a_read(chip, AD1816A_ADC_SOURCE_SEL) != val;
snd_ad1816a_write(chip, AD1816A_ADC_SOURCE_SEL, val);
- spin_unlock_irqrestore(&chip->lock, flags);
return change;
}
@@ -735,15 +700,13 @@ static int snd_ad1816a_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_ad1816a_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
ucontrol->value.integer.value[0] = (snd_ad1816a_read(chip, reg) >> shift) & mask;
- spin_unlock_irqrestore(&chip->lock, flags);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -752,7 +715,6 @@ static int snd_ad1816a_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -764,12 +726,11 @@ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (invert)
val = mask - val;
val <<= shift;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
old_val = snd_ad1816a_read(chip, reg);
val = (old_val & ~(mask << shift)) | val;
change = val != old_val;
snd_ad1816a_write(chip, reg, val);
- spin_unlock_irqrestore(&chip->lock, flags);
return change;
}
@@ -800,7 +761,6 @@ static int snd_ad1816a_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift_left = (kcontrol->private_value >> 8) & 0x0f;
int shift_right = (kcontrol->private_value >> 12) & 0x0f;
@@ -808,11 +768,10 @@ static int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
int invert = (kcontrol->private_value >> 24) & 0xff;
unsigned short val;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
val = snd_ad1816a_read(chip, reg);
ucontrol->value.integer.value[0] = (val >> shift_left) & mask;
ucontrol->value.integer.value[1] = (val >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->lock, flags);
if (invert) {
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
@@ -823,7 +782,6 @@ static int snd_ad1816a_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ad1816a *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift_left = (kcontrol->private_value >> 8) & 0x0f;
int shift_right = (kcontrol->private_value >> 12) & 0x0f;
@@ -840,12 +798,11 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
old_val = snd_ad1816a_read(chip, reg);
val1 = (old_val & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
change = val1 != old_val;
snd_ad1816a_write(chip, reg, val1);
- spin_unlock_irqrestore(&chip->lock, flags);
return change;
}
@@ -912,7 +869,7 @@ int snd_ad1816a_mixer(struct snd_ad1816a *chip)
card = chip->card;
- strcpy(card->mixername, snd_ad1816a_chip_id(chip));
+ strscpy(card->mixername, snd_ad1816a_chip_id(chip));
for (idx = 0; idx < ARRAY_SIZE(snd_ad1816a_controls); idx++) {
err = snd_ctl_add(card, snd_ctl_new1(&snd_ad1816a_controls[idx], chip));
diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile
index 4eab89bbc845..5fdfc1c9f059 100644
--- a/sound/isa/ad1848/Makefile
+++ b/sound/isa/ad1848/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ad1848-objs := ad1848.o
+snd-ad1848-y := ad1848.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AD1848) += snd-ad1848.o
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index c471ac2aa450..401d8df28d87 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -96,13 +96,13 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
if (!thinkpad[n])
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %d, dma %d",
- chip->pcm->name, chip->port, irq[n], dma1[n]);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %d, dma %d",
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
else
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %d, dma %d [Thinkpad]",
- chip->pcm->name, chip->port, irq[n], dma1[n]);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %d, dma %d [Thinkpad]",
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
error = snd_card_register(card);
if (error < 0)
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
index f079ba4ef1a0..03fb2bce9255 100644
--- a/sound/isa/adlib.c
+++ b/sound/isa/adlib.c
@@ -61,8 +61,8 @@ static int snd_adlib_probe(struct device *dev, unsigned int n)
return -EBUSY;
}
- strcpy(card->driver, DEV_NAME);
- strcpy(card->shortname, CRD_NAME);
+ strscpy(card->driver, DEV_NAME);
+ strscpy(card->shortname, CRD_NAME);
sprintf(card->longname, CRD_NAME " at %#lx", port[n]);
error = snd_opl3_create(card, port[n], port[n] + 2, OPL3_HW_AUTO, 1, &opl3);
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index d582eff64082..cfc241bd252e 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -23,8 +23,6 @@
#include <sound/opl3.h>
#include <sound/sb.h>
-#define PFX "als100: "
-
MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
MODULE_LICENSE("GPL");
@@ -112,7 +110,7 @@ static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
+ dev_err(&pdev->dev, "AUDIO pnp configure failure\n");
return err;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -135,7 +133,7 @@ static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
__mpu_error:
if (pdev) {
pnp_release_card_device(pdev);
- snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
+ dev_err(&pdev->dev, "MPU401 pnp configure failure, skipping\n");
}
acard->devmpu = NULL;
mpu_port[dev] = -1;
@@ -151,7 +149,7 @@ static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
__fm_error:
if (pdev) {
pnp_release_card_device(pdev);
- snd_printk(KERN_ERR PFX "OPL3 pnp configure failure, skipping\n");
+ dev_err(&pdev->dev, "OPL3 pnp configure failure, skipping\n");
}
acard->devopl = NULL;
fm_port[dev] = -1;
@@ -194,14 +192,14 @@ static int snd_card_als100_probe(int dev,
acard->chip = chip;
if (pid->driver_data == SB_HW_DT019X) {
- strcpy(card->driver, "DT-019X");
- strcpy(card->shortname, "Diamond Tech. DT-019X");
+ strscpy(card->driver, "DT-019X");
+ strscpy(card->shortname, "Diamond Tech. DT-019X");
snprintf(card->longname, sizeof(card->longname),
"Diamond Tech. DT-019X, %s at 0x%lx, irq %d, dma %d",
chip->name, chip->port, irq[dev], dma8[dev]);
} else {
- strcpy(card->driver, "ALS100");
- strcpy(card->shortname, "Avance Logic ALS100");
+ strscpy(card->driver, "ALS100");
+ strscpy(card->shortname, "Avance Logic ALS100");
snprintf(card->longname, sizeof(card->longname),
"Avance Logic ALS100, %s at 0x%lx, irq %d, dma %d&%d",
chip->name, chip->port, irq[dev], dma8[dev],
@@ -230,15 +228,15 @@ static int snd_card_als100_probe(int dev,
mpu_port[dev], 0,
mpu_irq[dev],
NULL) < 0)
- snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
+ dev_err(card->dev, "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
}
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
if (snd_opl3_create(card,
fm_port[dev], fm_port[dev] + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
- snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
- fm_port[dev], fm_port[dev] + 2);
+ dev_err(card->dev, "no OPL device at 0x%lx-0x%lx\n",
+ fm_port[dev], fm_port[dev] + 2);
} else {
error = snd_opl3_timer_new(opl3, 0, 1);
if (error < 0)
@@ -324,7 +322,7 @@ static int __init alsa_card_als100_init(void)
if (!als100_devices) {
pnp_unregister_card_driver(&als100_pnpc_driver);
#ifdef MODULE
- snd_printk(KERN_ERR "no Avance Logic based soundcards found\n");
+ pr_err("no Avance Logic based soundcards found\n");
#endif
return -ENODEV;
}
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index 761cd198df2b..588b9f0831d3 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -30,8 +30,6 @@
#include <sound/mpu401.h>
#include <sound/opl3.h>
-#define PFX "azt2320: "
-
MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
MODULE_DESCRIPTION("Aztech Systems AZT2320");
MODULE_LICENSE("GPL");
@@ -99,7 +97,7 @@ static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
+ dev_err(&pdev->dev, "AUDIO pnp configure failure\n");
return err;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -120,7 +118,7 @@ static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
__mpu_error:
if (pdev) {
pnp_release_card_device(pdev);
- snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
+ dev_err(&pdev->dev, "MPU401 pnp configure failure, skipping\n");
}
acard->devmpu = NULL;
mpu_port[dev] = -1;
@@ -191,8 +189,8 @@ static int snd_card_azt2320_probe(int dev,
if (error < 0)
return error;
- strcpy(card->driver, "AZT2320");
- strcpy(card->shortname, "Aztech AZT2320");
+ strscpy(card->driver, "AZT2320");
+ strscpy(card->shortname, "Aztech AZT2320");
sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
@@ -210,15 +208,15 @@ static int snd_card_azt2320_probe(int dev,
if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
mpu_port[dev], 0,
mpu_irq[dev], NULL) < 0)
- snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
+ dev_err(card->dev, "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
}
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
if (snd_opl3_create(card,
fm_port[dev], fm_port[dev] + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
- snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
- fm_port[dev], fm_port[dev] + 2);
+ dev_err(card->dev, "no OPL device at 0x%lx-0x%lx\n",
+ fm_port[dev], fm_port[dev] + 2);
} else {
error = snd_opl3_timer_new(opl3, 1, 2);
if (error < 0)
@@ -303,7 +301,7 @@ static int __init alsa_card_azt2320_init(void)
if (!azt2320_devices) {
pnp_unregister_card_driver(&azt2320_pnpc_driver);
#ifdef MODULE
- snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
+ pr_err("no AZT2320 based soundcards found\n");
#endif
return -ENODEV;
}
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
index 8902cfb830f7..4e6d823af103 100644
--- a/sound/isa/cmi8328.c
+++ b/sound/isa/cmi8328.c
@@ -155,37 +155,37 @@ static int snd_cmi8328_mixer(struct snd_wss *chip)
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* rename AUX0 switch to CD */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "CD Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
+ strscpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "error renaming control\n");
+ dev_err(card->dev, "error renaming control\n");
return err;
}
/* rename AUX0 volume to CD */
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "CD Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "CD Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "error renaming control\n");
+ dev_err(card->dev, "error renaming control\n");
return err;
}
/* rename AUX1 switch to Synth */
- strcpy(id1.name, "Aux Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
id1.index = 1;
- strcpy(id2.name, "Synth Playback Switch");
+ strscpy(id2.name, "Synth Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "error renaming control\n");
+ dev_err(card->dev, "error renaming control\n");
return err;
}
/* rename AUX1 volume to Synth */
- strcpy(id1.name, "Aux Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
id1.index = 1;
- strcpy(id2.name, "Synth Playback Volume");
+ strscpy(id2.name, "Synth Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "error renaming control\n");
+ dev_err(card->dev, "error renaming control\n");
return err;
}
@@ -251,35 +251,35 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
if (irq[ndev] == SNDRV_AUTO_IRQ) {
irq[ndev] = snd_legacy_find_free_irq(irqs);
if (irq[ndev] < 0) {
- snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ dev_err(pdev, "unable to find a free IRQ\n");
return -EBUSY;
}
}
if (dma1[ndev] == SNDRV_AUTO_DMA) {
dma1[ndev] = snd_legacy_find_free_dma(dma1s);
if (dma1[ndev] < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ dev_err(pdev, "unable to find a free DMA1\n");
return -EBUSY;
}
}
if (dma2[ndev] == SNDRV_AUTO_DMA) {
dma2[ndev] = snd_legacy_find_free_dma(dma2s[dma1[ndev] % 4]);
if (dma2[ndev] < 0) {
- snd_printk(KERN_WARNING "unable to find a free DMA2, full-duplex will not work\n");
+ dev_warn(pdev, "unable to find a free DMA2, full-duplex will not work\n");
dma2[ndev] = -1;
}
}
/* configure WSS IRQ... */
pos = array_find(irqs, irq[ndev]);
if (pos < 0) {
- snd_printk(KERN_ERR "invalid IRQ %d\n", irq[ndev]);
+ dev_err(pdev, "invalid IRQ %d\n", irq[ndev]);
return -EINVAL;
}
val = irq_bits[pos] << 3;
/* ...and DMA... */
pos = array_find(dma1s, dma1[ndev]);
if (pos < 0) {
- snd_printk(KERN_ERR "invalid DMA1 %d\n", dma1[ndev]);
+ dev_err(pdev, "invalid DMA1 %d\n", dma1[ndev]);
return -EINVAL;
}
val |= dma_bits[pos];
@@ -287,7 +287,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
if (dma2[ndev] >= 0 && dma1[ndev] != dma2[ndev]) {
pos = array_find(dma2s[dma1[ndev]], dma2[ndev]);
if (pos < 0) {
- snd_printk(KERN_ERR "invalid DMA2 %d\n", dma2[ndev]);
+ dev_err(pdev, "invalid DMA2 %d\n", dma2[ndev]);
return -EINVAL;
}
val |= 0x04; /* enable separate capture DMA */
@@ -320,50 +320,50 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
return err;
if (snd_wss_timer(cmi->wss, 0) < 0)
- snd_printk(KERN_WARNING "error initializing WSS timer\n");
+ dev_warn(pdev, "error initializing WSS timer\n");
if (mpuport[ndev] == SNDRV_AUTO_PORT) {
mpuport[ndev] = snd_legacy_find_free_ioport(mpu_ports, 2);
if (mpuport[ndev] < 0)
- snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+ dev_err(pdev, "unable to find a free MPU401 port\n");
}
if (mpuirq[ndev] == SNDRV_AUTO_IRQ) {
mpuirq[ndev] = snd_legacy_find_free_irq(mpu_irqs);
if (mpuirq[ndev] < 0)
- snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+ dev_err(pdev, "unable to find a free MPU401 IRQ\n");
}
/* enable and configure MPU401 */
if (mpuport[ndev] > 0 && mpuirq[ndev] > 0) {
val = CFG2_MPU_ENABLE;
pos = array_find_l(mpu_ports, mpuport[ndev]);
if (pos < 0)
- snd_printk(KERN_WARNING "invalid MPU401 port 0x%lx\n",
- mpuport[ndev]);
+ dev_warn(pdev, "invalid MPU401 port 0x%lx\n",
+ mpuport[ndev]);
else {
val |= mpu_port_bits[pos] << 5;
pos = array_find(mpu_irqs, mpuirq[ndev]);
if (pos < 0)
- snd_printk(KERN_WARNING "invalid MPU401 IRQ %d\n",
- mpuirq[ndev]);
+ dev_warn(pdev, "invalid MPU401 IRQ %d\n",
+ mpuirq[ndev]);
else {
val |= mpu_irq_bits[pos] << 3;
snd_cmi8328_cfg_write(port, CFG2, val);
if (snd_mpu401_uart_new(card, 0,
MPU401_HW_MPU401, mpuport[ndev],
0, mpuirq[ndev], NULL) < 0)
- snd_printk(KERN_ERR "error initializing MPU401\n");
+ dev_err(pdev, "error initializing MPU401\n");
}
}
}
/* OPL3 is hardwired to 0x388 and cannot be disabled */
if (snd_opl3_create(card, 0x388, 0x38a, OPL3_HW_AUTO, 0, &opl3) < 0)
- snd_printk(KERN_ERR "error initializing OPL3\n");
+ dev_err(pdev, "error initializing OPL3\n");
else
if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0)
- snd_printk(KERN_WARNING "error initializing OPL3 hwdep\n");
+ dev_warn(pdev, "error initializing OPL3 hwdep\n");
- strcpy(card->driver, "CMI8328");
- strcpy(card->shortname, "C-Media CMI8328");
+ strscpy(card->driver, "CMI8328");
+ strscpy(card->shortname, "C-Media CMI8328");
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d",
card->shortname, cmi->wss->port, irq[ndev], dma1[ndev],
(dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]);
@@ -378,7 +378,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
/* gameport is hardwired to 0x200 */
res = devm_request_region(pdev, 0x200, 8, "CMI8328 gameport");
if (!res)
- snd_printk(KERN_WARNING "unable to allocate gameport I/O port\n");
+ dev_warn(pdev, "unable to allocate gameport I/O port\n");
else {
struct gameport *gp = cmi->gameport = gameport_allocate_port();
if (cmi->gameport) {
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index f209b16c5229..3d1f19321b9e 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -269,18 +269,17 @@ static const unsigned char cmi8330_sb_init_values[][2] = {
static int cmi8330_add_sb_mixers(struct snd_sb *chip)
{
int idx, err;
- unsigned long flags;
- spin_lock_irqsave(&chip->mixer_lock, flags);
- snd_sbmixer_write(chip, 0x00, 0x00); /* mixer reset */
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ snd_sbmixer_write(chip, 0x00, 0x00); /* mixer reset */
+ }
/* mute and zero volume channels */
for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_init_values); idx++) {
- spin_lock_irqsave(&chip->mixer_lock, flags);
- snd_sbmixer_write(chip, cmi8330_sb_init_values[idx][0],
- cmi8330_sb_init_values[idx][1]);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ snd_sbmixer_write(chip, cmi8330_sb_init_values[idx][0],
+ cmi8330_sb_init_values[idx][1]);
+ }
}
for (idx = 0; idx < ARRAY_SIZE(cmi8330_sb_mixers); idx++) {
@@ -297,7 +296,7 @@ static int snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 *acard)
unsigned int idx;
int err;
- strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
+ strscpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) {
err = snd_ctl_add(card,
@@ -342,7 +341,7 @@ static int snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "AD1848 PnP configure failure\n");
+ dev_err(&pdev->dev, "AD1848 PnP configure failure\n");
return -EBUSY;
}
wssport[dev] = pnp_port_start(pdev, 0);
@@ -356,7 +355,7 @@ static int snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "SB16 PnP configure failure\n");
+ dev_err(&pdev->dev, "SB16 PnP configure failure\n");
return -EBUSY;
}
sbport[dev] = pnp_port_start(pdev, 0);
@@ -376,7 +375,7 @@ static int snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
err = pnp_activate_dev(pdev);
if (err < 0)
- snd_printk(KERN_ERR "MPU-401 PnP configure failure: will be disabled\n");
+ dev_err(&pdev->dev, "MPU-401 PnP configure failure: will be disabled\n");
else {
mpuport[dev] = pnp_port_start(pdev, 0);
mpuirq[dev] = pnp_irq(pdev, 0);
@@ -437,7 +436,7 @@ static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip)
err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm);
if (err < 0)
return err;
- strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330");
+ strscpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330");
pcm->private_data = chip;
/* SB16 */
@@ -498,8 +497,6 @@ static int snd_cmi8330_resume(struct snd_card *card)
#define is_isapnp_selected(dev) 0
#endif
-#define PFX "cmi8330: "
-
static int snd_cmi8330_card_new(struct device *pdev, int dev,
struct snd_card **cardp)
{
@@ -510,7 +507,7 @@ static int snd_cmi8330_card_new(struct device *pdev, int dev,
err = snd_devm_card_new(pdev, index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_cmi8330), &card);
if (err < 0) {
- snd_printk(KERN_ERR PFX "could not get a new card\n");
+ dev_err(pdev, "could not get a new card\n");
return err;
}
acard = card->private_data;
@@ -531,11 +528,11 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev)
wssdma[dev], -1,
WSS_HW_DETECT, 0, &acard->wss);
if (err < 0) {
- snd_printk(KERN_ERR PFX "AD1848 device busy??\n");
+ dev_err(card->dev, "AD1848 device busy??\n");
return err;
}
if (acard->wss->hardware != WSS_HW_CMI8330) {
- snd_printk(KERN_ERR PFX "AD1848 not found during probe\n");
+ dev_err(card->dev, "AD1848 not found during probe\n");
return -ENODEV;
}
@@ -546,11 +543,11 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev)
sbdma16[dev],
SB_HW_AUTO, &acard->sb);
if (err < 0) {
- snd_printk(KERN_ERR PFX "SB16 device busy??\n");
+ dev_err(card->dev, "SB16 device busy??\n");
return err;
}
if (acard->sb->hardware != SB_HW_16) {
- snd_printk(KERN_ERR PFX "SB16 not found during probe\n");
+ dev_err(card->dev, "SB16 not found during probe\n");
return -ENODEV;
}
@@ -561,22 +558,22 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev)
err = snd_cmi8330_mixer(card, acard);
if (err < 0) {
- snd_printk(KERN_ERR PFX "failed to create mixers\n");
+ dev_err(card->dev, "failed to create mixers\n");
return err;
}
err = snd_cmi8330_pcm(card, acard);
if (err < 0) {
- snd_printk(KERN_ERR PFX "failed to create pcms\n");
+ dev_err(card->dev, "failed to create pcms\n");
return err;
}
if (fmport[dev] != SNDRV_AUTO_PORT) {
if (snd_opl3_create(card,
fmport[dev], fmport[dev] + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
- snd_printk(KERN_ERR PFX
- "no OPL device at 0x%lx-0x%lx ?\n",
- fmport[dev], fmport[dev] + 2);
+ dev_err(card->dev,
+ "no OPL device at 0x%lx-0x%lx ?\n",
+ fmport[dev], fmport[dev] + 2);
} else {
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
@@ -588,12 +585,12 @@ static int snd_cmi8330_probe(struct snd_card *card, int dev)
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpuport[dev], 0, mpuirq[dev],
NULL) < 0)
- printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n",
+ dev_err(card->dev, "no MPU-401 device at 0x%lx.\n",
mpuport[dev]);
}
- strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
- strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D");
+ strscpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D");
+ strscpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D");
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
card->shortname,
acard->wss->port,
@@ -609,11 +606,11 @@ static int snd_cmi8330_isa_match(struct device *pdev,
if (!enable[dev] || is_isapnp_selected(dev))
return 0;
if (wssport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify wssport\n");
+ dev_err(pdev, "specify wssport\n");
return 0;
}
if (sbport[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify sbport\n");
+ dev_err(pdev, "specify sbport\n");
return 0;
}
return 1;
@@ -683,7 +680,7 @@ static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
return res;
res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid);
if (res < 0) {
- snd_printk(KERN_ERR PFX "PnP detection failed\n");
+ dev_err(card->dev, "PnP detection failed\n");
return res;
}
res = snd_cmi8330_probe(card, dev);
diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile
index 91c6b8d64424..013a777d23fa 100644
--- a/sound/isa/cs423x/Makefile
+++ b/sound/isa/cs423x/Makefile
@@ -4,8 +4,8 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-cs4231-objs := cs4231.o
-snd-cs4236-objs := cs4236.o cs4236_lib.o
+snd-cs4231-y := cs4231.o
+snd-cs4236-y := cs4236.o cs4236_lib.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index 1e8923385366..c87be4be6df1 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -98,13 +98,13 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
if (dma2[n] < 0)
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %d, dma %d",
- chip->pcm->name, chip->port, irq[n], dma1[n]);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %d, dma %d",
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
else
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %d, dma %d&%d",
- chip->pcm->name, chip->port, irq[n], dma1[n], dma2[n]);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %d, dma %d&%d",
+ chip->pcm->name, chip->port, irq[n], dma1[n], dma2[n]);
error = snd_wss_mixer(chip);
if (error < 0)
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 10112e1bb25d..e36cc147651a 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -204,7 +204,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
static int snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev)
{
if (pnp_activate_dev(pdev) < 0) {
- printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n");
+ dev_err(&pdev->dev, IDENT " WSS PnP configure failed for WSS (out of resources?)\n");
return -EBUSY;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -214,10 +214,12 @@ static int snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev)
irq[dev] = pnp_irq(pdev, 0);
dma1[dev] = pnp_dma(pdev, 0);
dma2[dev] = pnp_dma(pdev, 1) == 4 ? -1 : (int)pnp_dma(pdev, 1);
- snd_printdd("isapnp WSS: wss port=0x%lx, fm port=0x%lx, sb port=0x%lx\n",
- port[dev], fm_port[dev], sb_port[dev]);
- snd_printdd("isapnp WSS: irq=%i, dma1=%i, dma2=%i\n",
- irq[dev], dma1[dev], dma2[dev]);
+ dev_dbg(&pdev->dev,
+ "isapnp WSS: wss port=0x%lx, fm port=0x%lx, sb port=0x%lx\n",
+ port[dev], fm_port[dev], sb_port[dev]);
+ dev_dbg(&pdev->dev,
+ "isapnp WSS: irq=%i, dma1=%i, dma2=%i\n",
+ irq[dev], dma1[dev], dma2[dev]);
return 0;
}
@@ -225,11 +227,11 @@ static int snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev)
static int snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev)
{
if (pnp_activate_dev(pdev) < 0) {
- printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n");
+ dev_err(&pdev->dev, IDENT " CTRL PnP configure failed for WSS (out of resources?)\n");
return -EBUSY;
}
cport[dev] = pnp_port_start(pdev, 0);
- snd_printdd("isapnp CTRL: control port=0x%lx\n", cport[dev]);
+ dev_dbg(&pdev->dev, "isapnp CTRL: control port=0x%lx\n", cport[dev]);
return 0;
}
@@ -237,7 +239,7 @@ static int snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev)
static int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
{
if (pnp_activate_dev(pdev) < 0) {
- printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n");
+ dev_err(&pdev->dev, IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n");
mpu_port[dev] = SNDRV_AUTO_PORT;
mpu_irq[dev] = SNDRV_AUTO_IRQ;
} else {
@@ -250,7 +252,7 @@ static int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
mpu_irq[dev] = -1; /* disable interrupt */
}
}
- snd_printdd("isapnp MPU: port=0x%lx, irq=%i\n", mpu_port[dev], mpu_irq[dev]);
+ dev_dbg(&pdev->dev, "isapnp MPU: port=0x%lx, irq=%i\n", mpu_port[dev], mpu_irq[dev]);
return 0;
}
@@ -333,7 +335,8 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) {
if (!devm_request_region(card->dev, sb_port[dev], 16,
IDENT " SB")) {
- printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]);
+ dev_err(card->dev, IDENT ": unable to register SB port at 0x%lx\n",
+ sb_port[dev]);
return -EBUSY;
}
}
@@ -367,14 +370,14 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
strscpy(card->driver, chip->pcm->name, sizeof(card->driver));
strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
if (dma2[dev] < 0)
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i, dma %i",
- chip->pcm->name, chip->port, irq[dev], dma1[dev]);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i, dma %i",
+ chip->pcm->name, chip->port, irq[dev], dma1[dev]);
else
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i, dma %i&%d",
- chip->pcm->name, chip->port, irq[dev], dma1[dev],
- dma2[dev]);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i, dma %i&%d",
+ chip->pcm->name, chip->port, irq[dev], dma1[dev],
+ dma2[dev]);
err = snd_wss_timer(chip, 0);
if (err < 0)
@@ -384,7 +387,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
if (snd_opl3_create(card,
fm_port[dev], fm_port[dev] + 2,
OPL3_HW_OPL3_CS, 0, &opl3) < 0) {
- printk(KERN_WARNING IDENT ": OPL3 not detected\n");
+ dev_warn(card->dev, IDENT ": OPL3 not detected\n");
} else {
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
@@ -398,7 +401,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232,
mpu_port[dev], 0,
mpu_irq[dev], NULL) < 0)
- printk(KERN_WARNING IDENT ": MPU401 not detected\n");
+ dev_warn(card->dev, IDENT ": MPU401 not detected\n");
}
return snd_card_register(card);
@@ -507,7 +510,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
return -ENODEV;
/* prepare second id */
- strcpy(cid, pdev->id[0].id);
+ strscpy(cid, pdev->id[0].id);
cid[5] = '1';
cdev = NULL;
list_for_each_entry(iter, &(pdev->protocol->devices), protocol_list) {
@@ -521,7 +524,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
return err;
err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
if (err < 0) {
- printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
+ dev_err(card->dev, "PnP BIOS detection failed for " IDENT "\n");
return err;
}
err = snd_cs423x_probe(card, dev);
@@ -573,7 +576,7 @@ static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
return res;
res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid);
if (res < 0) {
- printk(KERN_ERR "isapnp detection failed and probing for " IDENT
+ dev_err(card->dev, "isapnp detection failed and probing for " IDENT
" is not supported\n");
return res;
}
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index 35f25911adcf..e2c29e831020 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -169,10 +169,9 @@ static void snd_cs4236_playback_format(struct snd_wss *chip,
struct snd_pcm_hw_params *params,
unsigned char pdfr)
{
- unsigned long flags;
unsigned char rate = divisor_to_rate_register(params->rate_den);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
/* set fast playback format change and clean playback FIFO */
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
chip->image[CS4231_ALT_FEATURE_1] | 0x10);
@@ -180,17 +179,15 @@ static void snd_cs4236_playback_format(struct snd_wss *chip,
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_cs4236_capture_format(struct snd_wss *chip,
struct snd_pcm_hw_params *params,
unsigned char cdfr)
{
- unsigned long flags;
unsigned char rate = divisor_to_rate_register(params->rate_den);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
/* set fast capture format change and clean capture FIFO */
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
chip->image[CS4231_ALT_FEATURE_1] | 0x20);
@@ -198,7 +195,6 @@ static void snd_cs4236_capture_format(struct snd_wss *chip,
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
#ifdef CONFIG_PM
@@ -206,48 +202,45 @@ static void snd_cs4236_capture_format(struct snd_wss *chip,
static void snd_cs4236_suspend(struct snd_wss *chip)
{
int reg;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
for (reg = 0; reg < 32; reg++)
chip->image[reg] = snd_wss_in(chip, reg);
for (reg = 0; reg < 18; reg++)
chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
for (reg = 2; reg < 9; reg++)
chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_cs4236_resume(struct snd_wss *chip)
{
int reg;
- unsigned long flags;
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (reg = 0; reg < 32; reg++) {
- switch (reg) {
- case CS4236_EXT_REG:
- case CS4231_VERSION:
- case 27: /* why? CS4235 - master left */
- case 29: /* why? CS4235 - master right */
- break;
- default:
- snd_wss_out(chip, reg, chip->image[reg]);
- break;
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ for (reg = 0; reg < 32; reg++) {
+ switch (reg) {
+ case CS4236_EXT_REG:
+ case CS4231_VERSION:
+ case 27: /* why? CS4235 - master left */
+ case 29: /* why? CS4235 - master right */
+ break;
+ default:
+ snd_wss_out(chip, reg, chip->image[reg]);
+ break;
+ }
}
- }
- for (reg = 0; reg < 18; reg++)
- snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
- for (reg = 2; reg < 9; reg++) {
- switch (reg) {
- case 7:
- break;
- default:
- snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
+ for (reg = 0; reg < 18; reg++)
+ snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
+ for (reg = 2; reg < 9; reg++) {
+ switch (reg) {
+ case 7:
+ break;
+ default:
+ snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
+ }
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
}
@@ -279,8 +272,8 @@ int snd_cs4236_create(struct snd_card *card,
return err;
if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
- snd_printd("chip is not CS4236+, hardware=0x%x\n",
- chip->hardware);
+ dev_dbg(card->dev, "chip is not CS4236+, hardware=0x%x\n",
+ chip->hardware);
*rchip = chip;
return 0;
}
@@ -288,25 +281,25 @@ int snd_cs4236_create(struct snd_card *card,
{
int idx;
for (idx = 0; idx < 8; idx++)
- snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
- idx, inb(chip->cport + idx));
+ dev_dbg(card->dev, "CD%i = 0x%x\n",
+ idx, inb(chip->cport + idx));
for (idx = 0; idx < 9; idx++)
- snd_printk(KERN_DEBUG "C%i = 0x%x\n",
- idx, snd_cs4236_ctrl_in(chip, idx));
+ dev_dbg(card->dev, "C%i = 0x%x\n",
+ idx, snd_cs4236_ctrl_in(chip, idx));
}
#endif
if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "please, specify control port "
- "for CS4236+ chips\n");
+ dev_err(card->dev, "please, specify control port for CS4236+ chips\n");
return -ENODEV;
}
ver1 = snd_cs4236_ctrl_in(chip, 1);
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
- snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
- cport, ver1, ver2);
+ dev_dbg(card->dev, "CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
+ cport, ver1, ver2);
if (ver1 != ver2) {
- snd_printk(KERN_ERR "CS4236+ chip detected, but "
- "control port 0x%lx is not valid\n", cport);
+ dev_err(card->dev,
+ "CS4236+ chip detected, but control port 0x%lx is not valid\n",
+ cport);
return -ENODEV;
}
snd_cs4236_ctrl_out(chip, 0, 0x00);
@@ -403,15 +396,13 @@ static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -420,7 +411,6 @@ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -432,11 +422,10 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
if (invert)
val = mask - val;
val <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val;
change = val != chip->eimage[CS4236_REG(reg)];
snd_cs4236_ext_out(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -449,15 +438,13 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -466,7 +453,6 @@ static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -478,11 +464,10 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (invert)
val = mask - val;
val <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val = (chip->cimage[reg] & ~(mask << shift)) | val;
change = val != chip->cimage[reg];
snd_cs4236_ctrl_out(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -516,7 +501,6 @@ static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -524,10 +508,9 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int mask = (kcontrol->private_value >> 24) & 0xff;
int invert = (kcontrol->private_value >> 22) & 1;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask;
ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert) {
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
@@ -538,7 +521,6 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -556,7 +538,7 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (left_reg != right_reg) {
val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1;
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
@@ -568,7 +550,6 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
change = val1 != chip->eimage[CS4236_REG(left_reg)];
snd_cs4236_ext_out(chip, left_reg, val1);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -592,7 +573,6 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -600,10 +580,9 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
int mask = (kcontrol->private_value >> 24) & 0xff;
int invert = (kcontrol->private_value >> 22) & 1;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert) {
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
@@ -614,7 +593,6 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -632,13 +610,12 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
snd_wss_out(chip, left_reg, val1);
snd_cs4236_ext_out(chip, right_reg, val2);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -658,31 +635,27 @@ static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f);
ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned short val1, val2;
val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f);
val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1;
val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -719,31 +692,27 @@ static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]);
ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned short val1, val2;
val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]);
val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -929,57 +898,53 @@ WSS_DOUBLE("Analog Loopback Switch", 0,
static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
#if 0
- printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
- "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
- snd_wss_in(chip, CS4231_ALT_FEATURE_1),
- snd_cs4236_ctrl_in(chip, 3),
- snd_cs4236_ctrl_in(chip, 4),
- snd_cs4236_ctrl_in(chip, 5),
- snd_cs4236_ctrl_in(chip, 6),
- snd_cs4236_ctrl_in(chip, 8));
+ dev_dbg(chip->card->dev,
+ "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ snd_wss_in(chip, CS4231_ALT_FEATURE_1),
+ snd_cs4236_ctrl_in(chip, 3),
+ snd_cs4236_ctrl_in(chip, 4),
+ snd_cs4236_ctrl_in(chip, 5),
+ snd_cs4236_ctrl_in(chip, 6),
+ snd_cs4236_ctrl_in(chip, 8));
#endif
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned short enable, val;
enable = ucontrol->value.integer.value[0] & 1;
- mutex_lock(&chip->mce_mutex);
+ guard(mutex)(&chip->mce_mutex);
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
- change = val != chip->image[CS4231_ALT_FEATURE_1];
- snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
- val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
- snd_cs4236_ctrl_out(chip, 4, val);
- udelay(100);
- val &= ~0x40;
- snd_cs4236_ctrl_out(chip, 4, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
+ change = val != chip->image[CS4231_ALT_FEATURE_1];
+ snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
+ val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
+ snd_cs4236_ctrl_out(chip, 4, val);
+ udelay(100);
+ val &= ~0x40;
+ snd_cs4236_ctrl_out(chip, 4, val);
+ }
snd_wss_mce_down(chip);
- mutex_unlock(&chip->mce_mutex);
#if 0
- printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
- "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
- snd_wss_in(chip, CS4231_ALT_FEATURE_1),
- snd_cs4236_ctrl_in(chip, 3),
- snd_cs4236_ctrl_in(chip, 4),
- snd_cs4236_ctrl_in(chip, 5),
- snd_cs4236_ctrl_in(chip, 6),
- snd_cs4236_ctrl_in(chip, 8));
+ dev_dbg(chip->card->dev,
+ "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ snd_wss_in(chip, CS4231_ALT_FEATURE_1),
+ snd_cs4236_ctrl_in(chip, 3),
+ snd_cs4236_ctrl_in(chip, 4),
+ snd_cs4236_ctrl_in(chip, 5),
+ snd_cs4236_ctrl_in(chip, 6),
+ snd_cs4236_ctrl_in(chip, 8));
#endif
return change;
}
@@ -1023,7 +988,7 @@ int snd_cs4236_mixer(struct snd_wss *chip)
if (snd_BUG_ON(!chip || !chip->card))
return -EINVAL;
card = chip->card;
- strcpy(card->mixername, snd_wss_chip_id(chip));
+ strscpy(card->mixername, snd_wss_chip_id(chip));
if (chip->hardware == WSS_HW_CS4235 ||
chip->hardware == WSS_HW_CS4239) {
diff --git a/sound/isa/es1688/Makefile b/sound/isa/es1688/Makefile
index c683ac36c50e..7d6c44a8eaad 100644
--- a/sound/isa/es1688/Makefile
+++ b/sound/isa/es1688/Makefile
@@ -4,8 +4,8 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-es1688-lib-objs := es1688_lib.o
-snd-es1688-objs := es1688.o
+snd-es1688-lib-y := es1688_lib.o
+snd-es1688-y := es1688.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ES1688) += snd-es1688.o snd-es1688-lib.o
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index f935b56eeec7..6a95dfb7600a 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -130,9 +130,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
strscpy(card->driver, "ES1688", sizeof(card->driver));
strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
- chip->irq, chip->dma8);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
+ chip->irq, chip->dma8);
if (fm_port[n] == SNDRV_AUTO_PORT)
fm_port[n] = port[n]; /* share the same port */
@@ -213,7 +213,7 @@ static int snd_card_es968_pnp(struct snd_card *card, unsigned int n,
error = pnp_activate_dev(pdev);
if (error < 0) {
- snd_printk(KERN_ERR "ES968 pnp configure failure\n");
+ dev_err(card->dev, "ES968 pnp configure failure\n");
return error;
}
port[n] = pnp_port_start(pdev, 0);
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 8554cb2263c1..59987dbc9ae9 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -30,9 +30,7 @@ static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)
outb(val, ES1688P(chip, COMMAND));
return 1;
}
-#ifdef CONFIG_SND_DEBUG
- printk(KERN_DEBUG "snd_es1688_dsp_command: timeout (0x%x)\n", val);
-#endif
+ dev_dbg(chip->card->dev, "%s: timeout (0x%x)\n", __func__, val);
return 0;
}
@@ -43,7 +41,8 @@ static int snd_es1688_dsp_get_byte(struct snd_es1688 *chip)
for (i = 1000; i; i--)
if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80)
return inb(ES1688P(chip, READ));
- snd_printd("es1688 get byte failed: 0x%lx = 0x%x!!!\n", ES1688P(chip, DATA_AVAIL), inb(ES1688P(chip, DATA_AVAIL)));
+ dev_dbg(chip->card->dev, "es1688 get byte failed: 0x%lx = 0x%x!!!\n",
+ ES1688P(chip, DATA_AVAIL), inb(ES1688P(chip, DATA_AVAIL)));
return -ENODEV;
}
@@ -95,7 +94,8 @@ int snd_es1688_reset(struct snd_es1688 *chip)
udelay(30);
for (i = 0; i < 1000 && !(inb(ES1688P(chip, DATA_AVAIL)) & 0x80); i++);
if (inb(ES1688P(chip, READ)) != 0xaa) {
- snd_printd("ess_reset at 0x%lx: failed!!!\n", chip->port);
+ dev_dbg(chip->card->dev, "ess_reset at 0x%lx: failed!!!\n",
+ chip->port);
return -ENODEV;
}
snd_es1688_dsp_command(chip, 0xc6); /* enable extended mode */
@@ -105,7 +105,6 @@ EXPORT_SYMBOL(snd_es1688_reset);
static int snd_es1688_probe(struct snd_es1688 *chip)
{
- unsigned long flags;
unsigned short major, minor;
int i;
@@ -113,39 +112,39 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
* initialization sequence
*/
- spin_lock_irqsave(&chip->reg_lock, flags); /* Some ESS1688 cards need this */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */
- inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
- inb(ES1688P(chip, ENABLE0)); /* ENABLE0 */
-
- if (snd_es1688_reset(chip) < 0) {
- snd_printdd("ESS: [0x%lx] reset failed... 0x%x\n", chip->port, inb(ES1688P(chip, READ)));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return -ENODEV;
- }
- snd_es1688_dsp_command(chip, 0xe7); /* return identification */
-
- for (i = 1000, major = minor = 0; i; i--) {
- if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80) {
- if (major == 0) {
- major = inb(ES1688P(chip, READ));
- } else {
- minor = inb(ES1688P(chip, READ));
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) { /* Some ESS1688 cards need this */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE2)); /* ENABLE2 */
+ inb(ES1688P(chip, ENABLE1)); /* ENABLE1 */
+ inb(ES1688P(chip, ENABLE0)); /* ENABLE0 */
+
+ if (snd_es1688_reset(chip) < 0) {
+ dev_dbg(chip->card->dev, "ESS: [0x%lx] reset failed... 0x%x\n",
+ chip->port, inb(ES1688P(chip, READ)));
+ return -ENODEV;
+ }
+ snd_es1688_dsp_command(chip, 0xe7); /* return identification */
+
+ for (i = 1000, major = minor = 0; i; i--) {
+ if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80) {
+ if (major == 0)
+ major = inb(ES1688P(chip, READ));
+ else
+ minor = inb(ES1688P(chip, READ));
}
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- snd_printdd("ESS: [0x%lx] found.. major = 0x%x, minor = 0x%x\n", chip->port, major, minor);
+ dev_dbg(chip->card->dev,
+ "ESS: [0x%lx] found.. major = 0x%x, minor = 0x%x\n",
+ chip->port, major, minor);
chip->version = (major << 8) | minor;
if (!chip->version)
@@ -153,27 +152,28 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
switch (chip->version & 0xfff0) {
case 0x4880:
- snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, "
- "but driver is in another place\n", chip->port);
+ dev_err(chip->card->dev,
+ "[0x%lx] ESS: AudioDrive ES488 detected, but driver is in another place\n",
+ chip->port);
return -ENODEV;
case 0x6880:
break;
default:
- snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip "
- "with version 0x%x (Jazz16 soundcard?)\n",
- chip->port, chip->version);
+ dev_err(chip->card->dev,
+ "[0x%lx] ESS: unknown AudioDrive chip with version 0x%x (Jazz16 soundcard?)\n",
+ chip->port, chip->version);
return -ENODEV;
}
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */
- snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */
+ snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */
+ }
/* enable joystick, but disable OPL3 */
- spin_lock_irqsave(&chip->mixer_lock, flags);
- snd_es1688_mixer_write(chip, 0x40, 0x01);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ snd_es1688_mixer_write(chip, 0x40, 0x01);
+ }
return 0;
}
@@ -181,7 +181,6 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
static int snd_es1688_init(struct snd_es1688 * chip, int enable)
{
static const int irqs[16] = {-1, -1, 0, -1, -1, 1, -1, 2, -1, 0, 3, -1, -1, -1, -1, -1};
- unsigned long flags;
int cfg, irq_bits, dma, dma_bits, tmp, tmp1;
/* ok.. setup MPU-401 port and joystick and OPL3 */
@@ -210,38 +209,36 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
}
}
}
-#if 0
- snd_printk(KERN_DEBUG "mpu cfg = 0x%x\n", cfg);
-#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_mixer_write(chip, 0x40, cfg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_mixer_write(chip, 0x40, cfg);
+ }
/* --- */
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_read(chip, 0xb1);
- snd_es1688_read(chip, 0xb2);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_read(chip, 0xb1);
+ snd_es1688_read(chip, 0xb2);
+ }
if (enable) {
cfg = 0xf0; /* enable only DMA counter interrupt */
irq_bits = irqs[chip->irq & 0x0f];
if (irq_bits < 0) {
- snd_printk(KERN_ERR "[0x%lx] ESS: bad IRQ %d "
- "for ES1688 chip!!\n",
- chip->port, chip->irq);
+ dev_err(chip->card->dev,
+ "[0x%lx] ESS: bad IRQ %d for ES1688 chip!!\n",
+ chip->port, chip->irq);
#if 0
irq_bits = 0;
cfg = 0x10;
#endif
return -EINVAL;
}
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_write(chip, 0xb1, cfg | (irq_bits << 2));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_write(chip, 0xb1, cfg | (irq_bits << 2));
+ }
cfg = 0xf0; /* extended mode DMA enable */
dma = chip->dma8;
if (dma > 3 || dma == 2) {
- snd_printk(KERN_ERR "[0x%lx] ESS: bad DMA channel %d "
- "for ES1688 chip!!\n", chip->port, dma);
+ dev_err(chip->card->dev,
+ "[0x%lx] ESS: bad DMA channel %d for ES1688 chip!!\n",
+ chip->port, dma);
#if 0
dma_bits = 0;
cfg = 0x00; /* disable all DMA */
@@ -252,20 +249,20 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
if (dma != 3)
dma_bits++;
}
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_write(chip, 0xb2, cfg | (dma_bits << 2));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_write(chip, 0xb2, cfg | (dma_bits << 2));
+ }
} else {
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */
- snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_write(chip, 0xb1, 0x10); /* disable IRQ */
+ snd_es1688_write(chip, 0xb2, 0x00); /* disable DMA */
+ }
+ }
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_read(chip, 0xb1);
+ snd_es1688_read(chip, 0xb2);
+ snd_es1688_reset(chip);
}
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_read(chip, 0xb1);
- snd_es1688_read(chip, 0xb2);
- snd_es1688_reset(chip);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -318,74 +315,70 @@ static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char va
} else if (cmd != SNDRV_PCM_TRIGGER_START) {
return -EINVAL;
}
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
chip->trigger_value = value;
val = snd_es1688_read(chip, 0xb8);
- if ((val < 0) || (val & 0x0f) == value) {
- spin_unlock(&chip->reg_lock);
+ if ((val < 0) || (val & 0x0f) == value)
return -EINVAL; /* something is wrong */
- }
#if 0
- printk(KERN_DEBUG "trigger: val = 0x%x, value = 0x%x\n", val, value);
- printk(KERN_DEBUG "trigger: pointer = 0x%x\n",
- snd_dma_pointer(chip->dma8, chip->dma_size));
+ dev_dbg(chip->card->dev, "trigger: val = 0x%x, value = 0x%x\n", val, value);
+ dev_dbg(chip->card->dev, "trigger: pointer = 0x%x\n",
+ snd_dma_pointer(chip->dma8, chip->dma_size));
#endif
snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);
- spin_unlock(&chip->reg_lock);
return 0;
}
static int snd_es1688_playback_prepare(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
chip->dma_size = size;
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_reset(chip);
- snd_es1688_set_rate(chip, substream);
- snd_es1688_write(chip, 0xb8, 4); /* auto init DMA mode */
- snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));
- snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */
- if (runtime->channels == 1) {
- if (snd_pcm_format_width(runtime->format) == 8) {
- /* 8. bit mono */
- snd_es1688_write(chip, 0xb6, 0x80);
- snd_es1688_write(chip, 0xb7, 0x51);
- snd_es1688_write(chip, 0xb7, 0xd0);
- } else {
- /* 16. bit mono */
- snd_es1688_write(chip, 0xb6, 0x00);
- snd_es1688_write(chip, 0xb7, 0x71);
- snd_es1688_write(chip, 0xb7, 0xf4);
- }
- } else {
- if (snd_pcm_format_width(runtime->format) == 8) {
- /* 8. bit stereo */
- snd_es1688_write(chip, 0xb6, 0x80);
- snd_es1688_write(chip, 0xb7, 0x51);
- snd_es1688_write(chip, 0xb7, 0x98);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_reset(chip);
+ snd_es1688_set_rate(chip, substream);
+ snd_es1688_write(chip, 0xb8, 4); /* auto init DMA mode */
+ snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));
+ snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */
+ if (runtime->channels == 1) {
+ if (snd_pcm_format_width(runtime->format) == 8) {
+ /* 8. bit mono */
+ snd_es1688_write(chip, 0xb6, 0x80);
+ snd_es1688_write(chip, 0xb7, 0x51);
+ snd_es1688_write(chip, 0xb7, 0xd0);
+ } else {
+ /* 16. bit mono */
+ snd_es1688_write(chip, 0xb6, 0x00);
+ snd_es1688_write(chip, 0xb7, 0x71);
+ snd_es1688_write(chip, 0xb7, 0xf4);
+ }
} else {
- /* 16. bit stereo */
- snd_es1688_write(chip, 0xb6, 0x00);
- snd_es1688_write(chip, 0xb7, 0x71);
- snd_es1688_write(chip, 0xb7, 0xbc);
+ if (snd_pcm_format_width(runtime->format) == 8) {
+ /* 8. bit stereo */
+ snd_es1688_write(chip, 0xb6, 0x80);
+ snd_es1688_write(chip, 0xb7, 0x51);
+ snd_es1688_write(chip, 0xb7, 0x98);
+ } else {
+ /* 16. bit stereo */
+ snd_es1688_write(chip, 0xb6, 0x00);
+ snd_es1688_write(chip, 0xb7, 0x71);
+ snd_es1688_write(chip, 0xb7, 0xbc);
+ }
}
+ snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);
+ snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);
+ snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKON);
}
- snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);
- snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);
- snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKON);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
/* --- */
count = -count;
snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_write(chip, 0xa4, (unsigned char) count);
- snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_write(chip, 0xa4, (unsigned char) count);
+ snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));
+ }
return 0;
}
@@ -398,51 +391,50 @@ static int snd_es1688_playback_trigger(struct snd_pcm_substream *substream,
static int snd_es1688_capture_prepare(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
chip->dma_size = size;
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_reset(chip);
- snd_es1688_set_rate(chip, substream);
- snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKOFF);
- snd_es1688_write(chip, 0xb8, 0x0e); /* auto init DMA mode */
- snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));
- snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */
- if (runtime->channels == 1) {
- if (snd_pcm_format_width(runtime->format) == 8) {
- /* 8. bit mono */
- snd_es1688_write(chip, 0xb7, 0x51);
- snd_es1688_write(chip, 0xb7, 0xd0);
- } else {
- /* 16. bit mono */
- snd_es1688_write(chip, 0xb7, 0x71);
- snd_es1688_write(chip, 0xb7, 0xf4);
- }
- } else {
- if (snd_pcm_format_width(runtime->format) == 8) {
- /* 8. bit stereo */
- snd_es1688_write(chip, 0xb7, 0x51);
- snd_es1688_write(chip, 0xb7, 0x98);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_reset(chip);
+ snd_es1688_set_rate(chip, substream);
+ snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKOFF);
+ snd_es1688_write(chip, 0xb8, 0x0e); /* auto init DMA mode */
+ snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));
+ snd_es1688_write(chip, 0xb9, 2); /* demand mode (4 bytes/request) */
+ if (runtime->channels == 1) {
+ if (snd_pcm_format_width(runtime->format) == 8) {
+ /* 8. bit mono */
+ snd_es1688_write(chip, 0xb7, 0x51);
+ snd_es1688_write(chip, 0xb7, 0xd0);
+ } else {
+ /* 16. bit mono */
+ snd_es1688_write(chip, 0xb7, 0x71);
+ snd_es1688_write(chip, 0xb7, 0xf4);
+ }
} else {
- /* 16. bit stereo */
- snd_es1688_write(chip, 0xb7, 0x71);
- snd_es1688_write(chip, 0xb7, 0xbc);
+ if (snd_pcm_format_width(runtime->format) == 8) {
+ /* 8. bit stereo */
+ snd_es1688_write(chip, 0xb7, 0x51);
+ snd_es1688_write(chip, 0xb7, 0x98);
+ } else {
+ /* 16. bit stereo */
+ snd_es1688_write(chip, 0xb7, 0x71);
+ snd_es1688_write(chip, 0xb7, 0xbc);
+ }
}
+ snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);
+ snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);
}
- snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);
- snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
/* --- */
count = -count;
snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_es1688_write(chip, 0xa4, (unsigned char) count);
- snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_es1688_write(chip, 0xa4, (unsigned char) count);
+ snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));
+ }
return 0;
}
@@ -620,20 +612,21 @@ int snd_es1688_create(struct snd_card *card,
if (chip == NULL)
return -ENOMEM;
+ chip->card = card;
chip->irq = -1;
chip->dma8 = -1;
chip->hardware = ES1688_HW_UNDEF;
chip->res_port = request_region(port + 4, 12, "ES1688");
if (chip->res_port == NULL) {
- snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4);
+ dev_err(card->dev, "es1688: can't grab port 0x%lx\n", port + 4);
err = -EBUSY;
goto exit;
}
err = request_irq(irq, snd_es1688_interrupt, 0, "ES1688", (void *) chip);
if (err < 0) {
- snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq);
+ dev_err(card->dev, "es1688: can't grab IRQ %d\n", irq);
goto exit;
}
@@ -642,7 +635,7 @@ int snd_es1688_create(struct snd_card *card,
err = request_dma(dma8, "ES1688");
if (err < 0) {
- snd_printk(KERN_ERR "es1688: can't grab DMA8 %d\n", dma8);
+ dev_err(card->dev, "es1688: can't grab DMA8 %d\n", dma8);
goto exit;
}
chip->dma8 = dma8;
@@ -703,7 +696,7 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device)
pcm->private_data = chip;
pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
- strcpy(pcm->name, snd_es1688_chip_id(chip));
+ strscpy(pcm->name, snd_es1688_chip_id(chip));
chip->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev,
@@ -735,19 +728,17 @@ static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
static int snd_es1688_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned char oval, nval;
int change;
if (ucontrol->value.enumerated.item[0] > 8)
return -EINVAL;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
oval = snd_es1688_mixer_read(chip, ES1688_REC_DEV);
nval = (ucontrol->value.enumerated.item[0] & 7) | (oval & ~15);
change = nval != oval;
if (change)
snd_es1688_mixer_write(chip, ES1688_REC_DEV, nval);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -771,15 +762,13 @@ static int snd_es1688_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_es1688_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (snd_es1688_mixer_read(chip, reg) >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -788,7 +777,6 @@ static int snd_es1688_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_es1688_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -800,13 +788,12 @@ static int snd_es1688_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
if (invert)
nval = mask - nval;
nval <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
oval = snd_es1688_mixer_read(chip, reg);
nval = (oval & ~(mask << shift)) | nval;
change = nval != oval;
if (change)
snd_es1688_mixer_write(chip, reg, nval);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -830,7 +817,6 @@ static int snd_es1688_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -839,7 +825,7 @@ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int invert = (kcontrol->private_value >> 22) & 1;
unsigned char left, right;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (left_reg < 0xa0)
left = snd_es1688_mixer_read(chip, left_reg);
else
@@ -851,7 +837,6 @@ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
right = snd_es1688_read(chip, right_reg);
} else
right = left;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
ucontrol->value.integer.value[0] = (left >> shift_left) & mask;
ucontrol->value.integer.value[1] = (right >> shift_right) & mask;
if (invert) {
@@ -864,7 +849,6 @@ static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -882,7 +866,7 @@ static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (left_reg != right_reg) {
if (left_reg < 0xa0)
oval1 = snd_es1688_mixer_read(chip, left_reg);
@@ -920,7 +904,6 @@ static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -968,7 +951,7 @@ int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip)
if (snd_BUG_ON(!chip || !card))
return -EINVAL;
- strcpy(card->mixername, snd_es1688_chip_id(chip));
+ strscpy(card->mixername, snd_es1688_chip_id(chip));
for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) {
err = snd_ctl_add(card, snd_ctl_new1(&snd_es1688_controls[idx], chip));
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 0a32845b1017..1da7b400a17b 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -82,9 +82,8 @@
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-#define PFX "es18xx: "
-
struct snd_es18xx {
+ struct snd_card *card;
unsigned long port; /* port of ESS chip */
unsigned long ctrl_port; /* Control port of ESS chip */
int irq; /* IRQ number of ESS chip */
@@ -165,7 +164,7 @@ static int snd_es18xx_dsp_command(struct snd_es18xx *chip, unsigned char val)
outb(val, chip->port + 0x0C);
return 0;
}
- snd_printk(KERN_ERR "dsp_command: timeout (0x%x)\n", val);
+ dev_err(chip->card->dev, "dsp_command: timeout (0x%x)\n", val);
return -EINVAL;
}
@@ -176,8 +175,8 @@ static int snd_es18xx_dsp_get_byte(struct snd_es18xx *chip)
for(i = MILLISECOND/10; i; i--)
if (inb(chip->port + 0x0C) & 0x40)
return inb(chip->port + 0x0A);
- snd_printk(KERN_ERR "dsp_get_byte failed: 0x%lx = 0x%x!!!\n",
- chip->port + 0x0A, inb(chip->port + 0x0A));
+ dev_err(chip->card->dev, "dsp_get_byte failed: 0x%lx = 0x%x!!!\n",
+ chip->port + 0x0A, inb(chip->port + 0x0A));
return -ENODEV;
}
@@ -186,40 +185,35 @@ static int snd_es18xx_dsp_get_byte(struct snd_es18xx *chip)
static int snd_es18xx_write(struct snd_es18xx *chip,
unsigned char reg, unsigned char data)
{
- unsigned long flags;
int ret;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ret = snd_es18xx_dsp_command(chip, reg);
if (ret < 0)
- goto end;
+ return ret;
ret = snd_es18xx_dsp_command(chip, data);
- end:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, data);
+ dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, data);
#endif
return ret;
}
static int snd_es18xx_read(struct snd_es18xx *chip, unsigned char reg)
{
- unsigned long flags;
int ret, data;
- spin_lock_irqsave(&chip->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->reg_lock);
ret = snd_es18xx_dsp_command(chip, 0xC0);
if (ret < 0)
- goto end;
+ return ret;
ret = snd_es18xx_dsp_command(chip, reg);
if (ret < 0)
- goto end;
+ return ret;
data = snd_es18xx_dsp_get_byte(chip);
ret = data;
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Reg %02x now is %02x (%d)\n", reg, data, ret);
+ dev_dbg(chip->card->dev, "Reg %02x now is %02x (%d)\n", reg, data, ret);
#endif
- end:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return ret;
}
@@ -229,62 +223,55 @@ static int snd_es18xx_bits(struct snd_es18xx *chip, unsigned char reg,
{
int ret;
unsigned char old, new, oval;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->reg_lock);
ret = snd_es18xx_dsp_command(chip, 0xC0);
if (ret < 0)
- goto end;
+ return ret;
ret = snd_es18xx_dsp_command(chip, reg);
if (ret < 0)
- goto end;
+ return ret;
ret = snd_es18xx_dsp_get_byte(chip);
- if (ret < 0) {
- goto end;
- }
+ if (ret < 0)
+ return ret;
old = ret;
oval = old & mask;
if (val != oval) {
ret = snd_es18xx_dsp_command(chip, reg);
if (ret < 0)
- goto end;
+ return ret;
new = (old & ~mask) | (val & mask);
ret = snd_es18xx_dsp_command(chip, new);
if (ret < 0)
- goto end;
+ return ret;
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x (%d)\n",
- reg, old, new, ret);
+ dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x (%d)\n",
+ reg, old, new, ret);
#endif
}
- ret = oval;
- end:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return ret;
+ return oval;
}
static inline void snd_es18xx_mixer_write(struct snd_es18xx *chip,
unsigned char reg, unsigned char data)
{
- unsigned long flags;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, chip->port + 0x04);
outb(data, chip->port + 0x05);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, data);
+ dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, data);
#endif
}
static inline int snd_es18xx_mixer_read(struct snd_es18xx *chip, unsigned char reg)
{
- unsigned long flags;
int data;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, chip->port + 0x04);
data = inb(chip->port + 0x05);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data);
+ dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data);
#endif
return data;
}
@@ -294,8 +281,8 @@ static inline int snd_es18xx_mixer_bits(struct snd_es18xx *chip, unsigned char r
unsigned char mask, unsigned char val)
{
unsigned char old, new, oval;
- unsigned long flags;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, chip->port + 0x04);
old = inb(chip->port + 0x05);
oval = old & mask;
@@ -303,11 +290,10 @@ static inline int snd_es18xx_mixer_bits(struct snd_es18xx *chip, unsigned char r
new = (old & ~mask) | (val & mask);
outb(new, chip->port + 0x05);
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n",
- reg, old, new);
+ dev_dbg(chip->card->dev, "Mixer reg %02x was %02x, set to %02x\n",
+ reg, old, new);
#endif
}
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
return oval;
}
@@ -315,17 +301,16 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch
unsigned char mask)
{
int old, expected, new;
- unsigned long flags;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, chip->port + 0x04);
old = inb(chip->port + 0x05);
expected = old ^ mask;
outb(expected, chip->port + 0x05);
new = inb(chip->port + 0x05);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x, now is %02x\n",
- reg, old, expected, new);
+ dev_dbg(chip->card->dev, "Mixer reg %02x was %02x, set to %02x, now is %02x\n",
+ reg, old, expected, new);
#endif
return expected == new;
}
@@ -1356,7 +1341,7 @@ static void snd_es18xx_config_write(struct snd_es18xx *chip,
outb(reg, chip->ctrl_port);
outb(data, chip->ctrl_port + 1);
#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Config reg %02x set to %02x\n", reg, data);
+ dev_dbg(chip->card->dev, "Config reg %02x set to %02x\n", reg, data);
#endif
}
@@ -1425,7 +1410,7 @@ static int snd_es18xx_initialize(struct snd_es18xx *chip,
irqmask = 3;
break;
default:
- snd_printk(KERN_ERR "invalid irq %d\n", chip->irq);
+ dev_err(chip->card->dev, "invalid irq %d\n", chip->irq);
return -ENODEV;
}
switch (chip->dma1) {
@@ -1439,7 +1424,7 @@ static int snd_es18xx_initialize(struct snd_es18xx *chip,
dma1mask = 3;
break;
default:
- snd_printk(KERN_ERR "invalid dma1 %d\n", chip->dma1);
+ dev_err(chip->card->dev, "invalid dma1 %d\n", chip->dma1);
return -ENODEV;
}
switch (chip->dma2) {
@@ -1456,7 +1441,7 @@ static int snd_es18xx_initialize(struct snd_es18xx *chip,
dma2mask = 3;
break;
default:
- snd_printk(KERN_ERR "invalid dma2 %d\n", chip->dma2);
+ dev_err(chip->card->dev, "invalid dma2 %d\n", chip->dma2);
return -ENODEV;
}
@@ -1531,7 +1516,7 @@ static int snd_es18xx_identify(struct snd_card *card, struct snd_es18xx *chip)
/* reset */
if (snd_es18xx_reset(chip) < 0) {
- snd_printk(KERN_ERR "reset at 0x%lx failed!!!\n", chip->port);
+ dev_err(card->dev, "reset at 0x%lx failed!!!\n", chip->port);
return -ENODEV;
}
@@ -1569,7 +1554,7 @@ static int snd_es18xx_identify(struct snd_card *card, struct snd_es18xx *chip)
if (!devm_request_region(card->dev, chip->ctrl_port, 8,
"ES18xx - CTRL")) {
- snd_printk(KERN_ERR PFX "unable go grab port 0x%lx\n", chip->ctrl_port);
+ dev_err(card->dev, "unable go grab port 0x%lx\n", chip->ctrl_port);
return -EBUSY;
}
@@ -1601,7 +1586,7 @@ static int snd_es18xx_probe(struct snd_card *card,
unsigned long fm_port)
{
if (snd_es18xx_identify(card, chip) < 0) {
- snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port);
+ dev_err(card->dev, "[0x%lx] ESS chip not found\n", chip->port);
return -ENODEV;
}
@@ -1623,12 +1608,12 @@ static int snd_es18xx_probe(struct snd_card *card,
chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT;
break;
default:
- snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
- chip->port, chip->version);
+ dev_err(card->dev, "[0x%lx] unsupported chip ES%x\n",
+ chip->port, chip->version);
return -ENODEV;
}
- snd_printd("[0x%lx] ESS%x chip found\n", chip->port, chip->version);
+ dev_dbg(card->dev, "[0x%lx] ESS%x chip found\n", chip->port, chip->version);
if (chip->dma1 == chip->dma2)
chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME);
@@ -1725,6 +1710,7 @@ static int snd_es18xx_new_device(struct snd_card *card,
{
struct snd_es18xx *chip = card->private_data;
+ chip->card = card;
spin_lock_init(&chip->reg_lock);
spin_lock_init(&chip->mixer_lock);
chip->port = port;
@@ -1735,27 +1721,27 @@ static int snd_es18xx_new_device(struct snd_card *card,
chip->active = 0;
if (!devm_request_region(card->dev, port, 16, "ES18xx")) {
- snd_printk(KERN_ERR PFX "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)) {
- snd_printk(KERN_ERR PFX "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")) {
- snd_printk(KERN_ERR PFX "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")) {
- snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2);
+ dev_err(card->dev, "unable to grab DMA2 %d\n", dma2);
return -EBUSY;
}
chip->dma2 = dma2;
@@ -1771,7 +1757,7 @@ static int snd_es18xx_mixer(struct snd_card *card)
int err;
unsigned int idx;
- strcpy(card->mixername, chip->pcm->name);
+ strscpy(card->mixername, chip->pcm->name);
for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) {
struct snd_kcontrol *kctl;
@@ -1954,7 +1940,7 @@ MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);
static int snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
{
if (pnp_activate_dev(pdev) < 0) {
- snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
+ dev_err(&pdev->dev, "PnP configure failure (out of resources?)\n");
return -EBUSY;
}
/* ok. hack using Vendor-Defined Card-Level registers */
@@ -1973,8 +1959,12 @@ static int snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
dma1[dev] = pnp_dma(pdev, 0);
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]);
- snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
+ dev_dbg(&pdev->dev,
+ "PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n",
+ port[dev], fm_port[dev], mpu_port[dev]);
+ dev_dbg(&pdev->dev,
+ "PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n",
+ dma1[dev], dma2[dev], irq[dev]);
return 0;
}
@@ -2022,11 +2012,12 @@ static int snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
/* Control port initialization */
if (pnp_activate_dev(chip->devc) < 0) {
- snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
+ dev_err(chip->card->dev,
+ "PnP control configure failure (out of resources?)\n");
return -EAGAIN;
}
- snd_printdd("pnp: port=0x%llx\n",
- (unsigned long long)pnp_port_start(chip->devc, 0));
+ dev_dbg(chip->card->dev, "pnp: port=0x%llx\n",
+ (unsigned long long)pnp_port_start(chip->devc, 0));
if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0)
return -EBUSY;
@@ -2084,9 +2075,9 @@ static int snd_audiodrive_probe(struct snd_card *card, int dev)
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
OPL3_HW_OPL3, 0, &opl3) < 0) {
- snd_printk(KERN_WARNING PFX
- "opl3 not detected at 0x%lx\n",
- fm_port[dev]);
+ dev_warn(card->dev,
+ "opl3 not detected at 0x%lx\n",
+ fm_port[dev]);
} else {
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
@@ -2134,21 +2125,21 @@ static int snd_es18xx_isa_probe(struct device *pdev, unsigned int dev)
if (irq[dev] == SNDRV_AUTO_IRQ) {
irq[dev] = snd_legacy_find_free_irq(possible_irqs);
if (irq[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
+ dev_err(pdev, "unable to find a free IRQ\n");
return -EBUSY;
}
}
if (dma1[dev] == SNDRV_AUTO_DMA) {
dma1[dev] = snd_legacy_find_free_dma(possible_dmas);
if (dma1[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA1\n");
+ dev_err(pdev, "unable to find a free DMA1\n");
return -EBUSY;
}
}
if (dma2[dev] == SNDRV_AUTO_DMA) {
dma2[dev] = snd_legacy_find_free_dma(possible_dmas);
if (dma2[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA2\n");
+ dev_err(pdev, "unable to find a free DMA2\n");
return -EBUSY;
}
}
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile
index ff861f238093..2dbd519860a6 100644
--- a/sound/isa/galaxy/Makefile
+++ b/sound/isa/galaxy/Makefile
@@ -4,8 +4,8 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
#
-snd-azt1605-objs := azt1605.o
-snd-azt2316-objs := azt2316.o
+snd-azt1605-y := azt1605.o
+snd-azt2316-y := azt2316.o
obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
index 3164eb8510fa..b0f1562d0fc0 100644
--- a/sound/isa/galaxy/galaxy.c
+++ b/sound/isa/galaxy/galaxy.c
@@ -542,8 +542,8 @@ static int __snd_galaxy_probe(struct device *dev, unsigned int n)
return err;
}
- strcpy(card->driver, DRV_NAME);
- strcpy(card->shortname, DRV_NAME);
+ strscpy(card->driver, DRV_NAME);
+ strscpy(card->shortname, DRV_NAME);
sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
card->shortname, port[n], wss_port[n], irq[n], dma1[n],
dma2[n]);
diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile
index c6f32ffd3420..4924c1904fa4 100644
--- a/sound/isa/gus/Makefile
+++ b/sound/isa/gus/Makefile
@@ -4,18 +4,18 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-gus-lib-objs := gus_main.o \
+snd-gus-lib-y := gus_main.o \
gus_io.o gus_irq.o gus_timer.o \
gus_mem.o gus_mem_proc.o gus_dram.o gus_dma.o gus_volume.o \
gus_pcm.o gus_mixer.o \
gus_uart.o \
gus_reset.o
-snd-gusclassic-objs := gusclassic.o
-snd-gusextreme-objs := gusextreme.o
-snd-gusmax-objs := gusmax.o
-snd-interwave-objs := interwave.o
-snd-interwave-stb-objs := interwave-stb.o
+snd-gusclassic-y := gusclassic.o
+snd-gusextreme-y := gusextreme.o
+snd-gusmax-y := gusmax.o
+snd-interwave-y := interwave.o
+snd-interwave-stb-y := interwave-stb.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
index 6d664dd8dde0..ffc69e26227e 100644
--- a/sound/isa/gus/gus_dma.c
+++ b/sound/isa/gus/gus_dma.c
@@ -11,12 +11,9 @@
static void snd_gf1_dma_ack(struct snd_gus_card * gus)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00);
snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
static void snd_gf1_dma_program(struct snd_gus_card * gus,
@@ -25,20 +22,22 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
unsigned int count,
unsigned int cmd)
{
- unsigned long flags;
unsigned int address;
unsigned char dma_cmd;
unsigned int address_high;
- snd_printdd("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
- addr, buf_addr, count);
+ dev_dbg(gus->card->dev,
+ "dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
+ addr, buf_addr, count);
if (gus->gf1.dma1 > 3) {
if (gus->gf1.enh_mode) {
address = addr >> 1;
} else {
if (addr & 0x1f) {
- snd_printd("snd_gf1_dma_transfer: unaligned address (0x%x)?\n", addr);
+ dev_dbg(gus->card->dev,
+ "%s: unaligned address (0x%x)?\n",
+ __func__, addr);
return;
}
address = (addr & 0x000c0000) | ((addr & 0x0003ffff) >> 1);
@@ -63,10 +62,11 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
snd_gf1_dma_ack(gus);
snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
#if 0
- snd_printk(KERN_DEBUG "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
- address << 1, count, dma_cmd);
+ dev_dbg(gus->card->dev,
+ "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
+ address << 1, count, dma_cmd);
#endif
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
if (gus->gf1.enh_mode) {
address_high = ((address >> 16) & 0x000000f0) | (address & 0x0000000f);
snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4));
@@ -74,7 +74,6 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
} else
snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4));
snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, dma_cmd);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
static struct snd_gf1_dma_block *snd_gf1_dma_next_block(struct snd_gus_card * gus)
@@ -116,41 +115,37 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
snd_gf1_dma_ack(gus);
if (gus->gf1.dma_ack)
gus->gf1.dma_ack(gus, gus->gf1.dma_private_data);
- spin_lock(&gus->dma_lock);
- if (gus->gf1.dma_data_pcm == NULL &&
- gus->gf1.dma_data_synth == NULL) {
- gus->gf1.dma_ack = NULL;
- gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER;
- spin_unlock(&gus->dma_lock);
- return;
+ scoped_guard(spinlock, &gus->dma_lock) {
+ if (gus->gf1.dma_data_pcm == NULL &&
+ gus->gf1.dma_data_synth == NULL) {
+ gus->gf1.dma_ack = NULL;
+ gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER;
+ return;
+ }
+ block = snd_gf1_dma_next_block(gus);
}
- block = snd_gf1_dma_next_block(gus);
- spin_unlock(&gus->dma_lock);
if (!block)
return;
snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
kfree(block);
#if 0
- snd_printd(KERN_DEBUG "program dma (IRQ) - "
- "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
- block->addr, block->buf_addr, block->count, block->cmd);
+ dev_dbg(gus->card->dev,
+ "program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, block->buf_addr, block->count, block->cmd);
#endif
}
int snd_gf1_dma_init(struct snd_gus_card * gus)
{
- mutex_lock(&gus->dma_mutex);
+ guard(mutex)(&gus->dma_mutex);
gus->gf1.dma_shared++;
- if (gus->gf1.dma_shared > 1) {
- mutex_unlock(&gus->dma_mutex);
+ if (gus->gf1.dma_shared > 1)
return 0;
- }
gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt;
gus->gf1.dma_data_pcm =
gus->gf1.dma_data_pcm_last =
gus->gf1.dma_data_synth =
gus->gf1.dma_data_synth_last = NULL;
- mutex_unlock(&gus->dma_mutex);
return 0;
}
@@ -158,7 +153,7 @@ int snd_gf1_dma_done(struct snd_gus_card * gus)
{
struct snd_gf1_dma_block *block;
- mutex_lock(&gus->dma_mutex);
+ guard(mutex)(&gus->dma_mutex);
gus->gf1.dma_shared--;
if (!gus->gf1.dma_shared) {
snd_dma_disable(gus->gf1.dma1);
@@ -175,7 +170,6 @@ int snd_gf1_dma_done(struct snd_gus_card * gus)
gus->gf1.dma_data_pcm_last =
gus->gf1.dma_data_synth_last = NULL;
}
- mutex_unlock(&gus->dma_mutex);
return 0;
}
@@ -184,8 +178,8 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
int atomic,
int synth)
{
- unsigned long flags;
struct snd_gf1_dma_block *block;
+ struct snd_gf1_dma_block *free_block = NULL;
block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL);
if (!block)
@@ -194,43 +188,48 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
*block = *__block;
block->next = NULL;
- snd_printdd("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
- block->addr, (long) block->buffer, block->count,
- block->cmd);
-
- snd_printdd("gus->gf1.dma_data_pcm_last = 0x%lx\n",
- (long)gus->gf1.dma_data_pcm_last);
- snd_printdd("gus->gf1.dma_data_pcm = 0x%lx\n",
- (long)gus->gf1.dma_data_pcm);
-
- spin_lock_irqsave(&gus->dma_lock, flags);
- if (synth) {
- if (gus->gf1.dma_data_synth_last) {
- gus->gf1.dma_data_synth_last->next = block;
- gus->gf1.dma_data_synth_last = block;
+ dev_dbg(gus->card->dev,
+ "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, (long) block->buffer, block->count,
+ block->cmd);
+
+ dev_dbg(gus->card->dev,
+ "gus->gf1.dma_data_pcm_last = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm_last);
+ dev_dbg(gus->card->dev,
+ "gus->gf1.dma_data_pcm = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm);
+
+ scoped_guard(spinlock_irqsave, &gus->dma_lock) {
+ if (synth) {
+ if (gus->gf1.dma_data_synth_last) {
+ gus->gf1.dma_data_synth_last->next = block;
+ gus->gf1.dma_data_synth_last = block;
+ } else {
+ gus->gf1.dma_data_synth =
+ gus->gf1.dma_data_synth_last = block;
+ }
} else {
- gus->gf1.dma_data_synth =
- gus->gf1.dma_data_synth_last = block;
+ if (gus->gf1.dma_data_pcm_last) {
+ gus->gf1.dma_data_pcm_last->next = block;
+ gus->gf1.dma_data_pcm_last = block;
+ } else {
+ gus->gf1.dma_data_pcm =
+ gus->gf1.dma_data_pcm_last = block;
+ }
}
- } else {
- if (gus->gf1.dma_data_pcm_last) {
- gus->gf1.dma_data_pcm_last->next = block;
- gus->gf1.dma_data_pcm_last = block;
- } else {
- gus->gf1.dma_data_pcm =
- gus->gf1.dma_data_pcm_last = block;
+ if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) {
+ gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER;
+ free_block = snd_gf1_dma_next_block(gus);
}
}
- if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) {
- gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER;
- block = snd_gf1_dma_next_block(gus);
- spin_unlock_irqrestore(&gus->dma_lock, flags);
- if (block == NULL)
- return 0;
- snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
- kfree(block);
- return 0;
+
+ if (free_block) {
+ snd_gf1_dma_program(gus, free_block->addr, free_block->buf_addr,
+ free_block->count,
+ (unsigned short)free_block->cmd);
+ kfree(free_block);
}
- spin_unlock_irqrestore(&gus->dma_lock, flags);
+
return 0;
}
diff --git a/sound/isa/gus/gus_dram.c b/sound/isa/gus/gus_dram.c
index 5cebc0119d0a..50fe738ee3ea 100644
--- a/sound/isa/gus/gus_dram.c
+++ b/sound/isa/gus/gus_dram.c
@@ -13,7 +13,6 @@
static int snd_gus_dram_poke(struct snd_gus_card *gus, char __user *_buffer,
unsigned int address, unsigned int size)
{
- unsigned long flags;
unsigned int size1, size2;
char buffer[256], *pbuffer;
@@ -22,11 +21,10 @@ static int snd_gus_dram_poke(struct snd_gus_card *gus, char __user *_buffer,
if (copy_from_user(buffer, _buffer, size1))
return -EFAULT;
if (gus->interwave) {
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
snd_gf1_dram_addr(gus, address);
outsb(GUSP(gus, DRAM), buffer, size1);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
address += size1;
} else {
pbuffer = buffer;
@@ -51,19 +49,17 @@ static int snd_gus_dram_peek(struct snd_gus_card *gus, char __user *_buffer,
unsigned int address, unsigned int size,
int rom)
{
- unsigned long flags;
unsigned int size1, size2;
char buffer[256], *pbuffer;
while (size > 0) {
size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
if (gus->interwave) {
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, rom ? 0x03 : 0x01);
snd_gf1_dram_addr(gus, address);
insb(GUSP(gus, DRAM), buffer, size1);
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
address += size1;
} else {
pbuffer = buffer;
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c
index fb7b5e2636b8..3e6f35084f26 100644
--- a/sound/isa/gus/gus_io.c
+++ b/sound/isa/gus/gus_io.c
@@ -177,99 +177,37 @@ unsigned int snd_gf1_read_addr(struct snd_gus_card * gus,
void snd_gf1_i_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
__snd_gf1_ctrl_stop(gus, reg);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
void snd_gf1_i_write8(struct snd_gus_card * gus,
unsigned char reg,
unsigned char data)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
__snd_gf1_write8(gus, reg, data);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
unsigned char snd_gf1_i_look8(struct snd_gus_card * gus, unsigned char reg)
{
- unsigned long flags;
- unsigned char res;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
- res = __snd_gf1_look8(gus, reg);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return res;
+ guard(spinlock_irqsave)(&gus->reg_lock);
+ return __snd_gf1_look8(gus, reg);
}
void snd_gf1_i_write16(struct snd_gus_card * gus,
unsigned char reg,
unsigned int data)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
__snd_gf1_write16(gus, reg, data);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
unsigned short snd_gf1_i_look16(struct snd_gus_card * gus, unsigned char reg)
{
- unsigned long flags;
- unsigned short res;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
- res = __snd_gf1_look16(gus, reg);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return res;
-}
-
-#if 0
-
-void snd_gf1_i_adlib_write(struct snd_gus_card * gus,
- unsigned char reg,
- unsigned char data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
- __snd_gf1_adlib_write(gus, reg, data);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
-}
-
-void snd_gf1_i_write_addr(struct snd_gus_card * gus, unsigned char reg,
- unsigned int addr, short w_16bit)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
- __snd_gf1_write_addr(gus, reg, addr, w_16bit);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
-}
-
-#endif /* 0 */
-
-#ifdef CONFIG_SND_DEBUG
-static unsigned int snd_gf1_i_read_addr(struct snd_gus_card * gus,
- unsigned char reg, short w_16bit)
-{
- unsigned int res;
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
- res = __snd_gf1_read_addr(gus, reg, w_16bit);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return res;
+ guard(spinlock_irqsave)(&gus->reg_lock);
+ return __snd_gf1_look16(gus, reg);
}
-#endif
-
-/*
-
- */
void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr)
{
@@ -285,9 +223,7 @@ void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr)
void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char data)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
mb();
outw((unsigned short) addr, gus->gf1.reg_data16);
@@ -297,15 +233,11 @@ void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char da
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
mb();
outb(data, gus->gf1.reg_dram);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr)
{
- unsigned long flags;
- unsigned char res;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
mb();
outw((unsigned short) addr, gus->gf1.reg_data16);
@@ -314,22 +246,16 @@ unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr)
mb();
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
mb();
- res = inb(gus->gf1.reg_dram);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return res;
+ return inb(gus->gf1.reg_dram);
}
#if 0
void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short data)
{
- unsigned long flags;
-
-#ifdef CONFIG_SND_DEBUG
if (!gus->interwave)
- snd_printk(KERN_DEBUG "snd_gf1_pokew - GF1!!!\n");
-#endif
- spin_lock_irqsave(&gus->reg_lock, flags);
+ dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
+ guard(spinlock_irqsave)(&gus->reg_lock);
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
mb();
outw((unsigned short) addr, gus->gf1.reg_data16);
@@ -341,19 +267,13 @@ void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short
outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
mb();
outw(data, gus->gf1.reg_data16);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr)
{
- unsigned long flags;
- unsigned short res;
-
-#ifdef CONFIG_SND_DEBUG
if (!gus->interwave)
- snd_printk(KERN_DEBUG "snd_gf1_peekw - GF1!!!\n");
-#endif
- spin_lock_irqsave(&gus->reg_lock, flags);
+ dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
+ guard(spinlock_irqsave)(&gus->reg_lock);
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
mb();
outw((unsigned short) addr, gus->gf1.reg_data16);
@@ -364,25 +284,20 @@ unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr)
mb();
outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
mb();
- res = inw(gus->gf1.reg_data16);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- return res;
+ return inw(gus->gf1.reg_data16);
}
void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr,
unsigned short value, unsigned int count)
{
unsigned long port;
- unsigned long flags;
-#ifdef CONFIG_SND_DEBUG
if (!gus->interwave)
- snd_printk(KERN_DEBUG "snd_gf1_dram_setmem - GF1!!!\n");
-#endif
+ dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
addr &= ~1;
count >>= 1;
port = GUSP(gus, GF1DATALOW);
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
mb();
outw((unsigned short) addr, gus->gf1.reg_data16);
@@ -394,7 +309,6 @@ void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr,
outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
while (count--)
outw(value, port);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
#endif /* 0 */
@@ -424,102 +338,3 @@ void snd_gf1_select_active_voices(struct snd_gus_card * gus)
udelay(100);
}
}
-
-#ifdef CONFIG_SND_DEBUG
-
-void snd_gf1_print_voice_registers(struct snd_gus_card * gus)
-{
- unsigned char mode;
- int voice, ctrl;
-
- voice = gus->gf1.active_voice;
- printk(KERN_INFO " -%i- GF1 voice ctrl, ramp ctrl = 0x%x, 0x%x\n", voice, ctrl = snd_gf1_i_read8(gus, 0), snd_gf1_i_read8(gus, 0x0d));
- printk(KERN_INFO " -%i- GF1 frequency = 0x%x\n", voice, snd_gf1_i_read16(gus, 1));
- printk(KERN_INFO " -%i- GF1 loop start, end = 0x%x (0x%x), 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 2, ctrl & 4), snd_gf1_i_read_addr(gus, 2, (ctrl & 4) ^ 4), snd_gf1_i_read_addr(gus, 4, ctrl & 4), snd_gf1_i_read_addr(gus, 4, (ctrl & 4) ^ 4));
- printk(KERN_INFO " -%i- GF1 ramp start, end, rate = 0x%x, 0x%x, 0x%x\n", voice, snd_gf1_i_read8(gus, 7), snd_gf1_i_read8(gus, 8), snd_gf1_i_read8(gus, 6));
- printk(KERN_INFO" -%i- GF1 volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 9));
- printk(KERN_INFO " -%i- GF1 position = 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 0x0a, ctrl & 4), snd_gf1_i_read_addr(gus, 0x0a, (ctrl & 4) ^ 4));
- if (gus->interwave && snd_gf1_i_read8(gus, 0x19) & 0x01) { /* enhanced mode */
- mode = snd_gf1_i_read8(gus, 0x15);
- printk(KERN_INFO " -%i- GFA1 mode = 0x%x\n", voice, mode);
- if (mode & 0x01) { /* Effect processor */
- printk(KERN_INFO " -%i- GFA1 effect address = 0x%x\n", voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4));
- printk(KERN_INFO " -%i- GFA1 effect volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x16));
- printk(KERN_INFO " -%i- GFA1 effect volume final = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x1d));
- printk(KERN_INFO " -%i- GFA1 effect accumulator = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x14));
- }
- if (mode & 0x20) {
- printk(KERN_INFO " -%i- GFA1 left offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x13), snd_gf1_i_read16(gus, 0x13) >> 4);
- printk(KERN_INFO " -%i- GFA1 left offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1c), snd_gf1_i_read16(gus, 0x1c) >> 4);
- printk(KERN_INFO " -%i- GFA1 right offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x0c), snd_gf1_i_read16(gus, 0x0c) >> 4);
- printk(KERN_INFO " -%i- GFA1 right offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1b), snd_gf1_i_read16(gus, 0x1b) >> 4);
- } else
- printk(KERN_INFO " -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c));
- } else
- printk(KERN_INFO " -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c));
-}
-
-#if 0
-
-void snd_gf1_print_global_registers(struct snd_gus_card * gus)
-{
- unsigned char global_mode = 0x00;
-
- printk(KERN_INFO " -G- GF1 active voices = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ACTIVE_VOICES));
- if (gus->interwave) {
- global_mode = snd_gf1_i_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE);
- printk(KERN_INFO " -G- GF1 global mode = 0x%x\n", global_mode);
- }
- if (global_mode & 0x02) /* LFO enabled? */
- printk(KERN_INFO " -G- GF1 LFO base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_LFO_BASE));
- printk(KERN_INFO " -G- GF1 voices IRQ read = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VOICES_IRQ_READ));
- printk(KERN_INFO " -G- GF1 DRAM DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL));
- printk(KERN_INFO " -G- GF1 DRAM DMA high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW));
- printk(KERN_INFO " -G- GF1 DRAM IO high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_IO_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_IO_LOW));
- if (!gus->interwave)
- printk(KERN_INFO " -G- GF1 record DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL));
- printk(KERN_INFO " -G- GF1 DRAM IO 16 = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_DRAM_IO16));
- if (gus->gf1.enh_mode) {
- printk(KERN_INFO " -G- GFA1 memory config = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG));
- printk(KERN_INFO " -G- GFA1 memory control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MEMORY_CONTROL));
- printk(KERN_INFO " -G- GFA1 FIFO record base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR));
- printk(KERN_INFO " -G- GFA1 FIFO playback base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR));
- printk(KERN_INFO " -G- GFA1 interleave control = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_INTERLEAVE));
- }
-}
-
-void snd_gf1_print_setup_registers(struct snd_gus_card * gus)
-{
- printk(KERN_INFO " -S- mix control = 0x%x\n", inb(GUSP(gus, MIXCNTRLREG)));
- printk(KERN_INFO " -S- IRQ status = 0x%x\n", inb(GUSP(gus, IRQSTAT)));
- printk(KERN_INFO " -S- timer control = 0x%x\n", inb(GUSP(gus, TIMERCNTRL)));
- printk(KERN_INFO " -S- timer data = 0x%x\n", inb(GUSP(gus, TIMERDATA)));
- printk(KERN_INFO " -S- status read = 0x%x\n", inb(GUSP(gus, REGCNTRLS)));
- printk(KERN_INFO " -S- Sound Blaster control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL));
- printk(KERN_INFO " -S- AdLib timer 1/2 = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1), snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2));
- printk(KERN_INFO " -S- reset = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET));
- if (gus->interwave) {
- printk(KERN_INFO " -S- compatibility = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_COMPATIBILITY));
- printk(KERN_INFO " -S- decode control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DECODE_CONTROL));
- printk(KERN_INFO " -S- version number = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER));
- printk(KERN_INFO " -S- MPU-401 emul. control A/B = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A), snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B));
- printk(KERN_INFO " -S- emulation IRQ = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_EMULATION_IRQ));
- }
-}
-
-void snd_gf1_peek_print_block(struct snd_gus_card * gus, unsigned int addr, int count, int w_16bit)
-{
- if (!w_16bit) {
- while (count-- > 0)
- printk(count > 0 ? "%02x:" : "%02x", snd_gf1_peek(gus, addr++));
- } else {
- while (count-- > 0) {
- printk(count > 0 ? "%04x:" : "%04x", snd_gf1_peek(gus, addr) | (snd_gf1_peek(gus, addr + 1) << 8));
- addr += 2;
- }
- }
-}
-
-#endif /* 0 */
-
-#endif
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
index 226b8438aa70..0e1054402c91 100644
--- a/sound/isa/gus/gus_irq.c
+++ b/sound/isa/gus/gus_irq.c
@@ -26,7 +26,6 @@ __again:
if (status == 0)
return IRQ_RETVAL(handled);
handled = 1;
- /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
if (status & 0x02) {
STAT_ADD(gus->gf1.interrupt_stat_midi_in);
if (gus->gf1.interrupt_handler_midi_in)
@@ -50,9 +49,9 @@ __again:
continue; /* multi request */
already |= _current_; /* mark request */
#if 0
- printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
- "voice_verify = %i\n",
- voice, voice_status, inb(GUSP(gus, GF1PAGE)));
+ dev_dbg(gus->card->dev,
+ "voice = %i, voice_status = 0x%x, voice_verify = %i\n",
+ voice, voice_status, inb(GUSP(gus, GF1PAGE)));
#endif
pvoice = &gus->gf1.voices[voice];
if (pvoice->use) {
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 3b46490271fe..5f50a39c6f16 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -22,18 +22,6 @@ MODULE_LICENSE("GPL");
static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches);
-int snd_gus_use_inc(struct snd_gus_card * gus)
-{
- if (!try_module_get(gus->card->module))
- return 0;
- return 1;
-}
-
-void snd_gus_use_dec(struct snd_gus_card * gus)
-{
- module_put(gus->card->module);
-}
-
static int snd_gus_joystick_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -54,16 +42,14 @@ static int snd_gus_joystick_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int snd_gus_joystick_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned char nval;
nval = ucontrol->value.integer.value[0] & 31;
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
change = gus->joystick_dac != nval;
gus->joystick_dac = nval;
snd_gf1_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return change;
}
@@ -158,32 +144,32 @@ int snd_gus_create(struct snd_card *card,
/* allocate resources */
gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)");
if (!gus->gf1.res_port1) {
- snd_printk(KERN_ERR "gus: can't grab SB port 0x%lx\n", port);
+ dev_err(card->dev, "gus: can't grab SB port 0x%lx\n", port);
snd_gus_free(gus);
return -EBUSY;
}
gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)");
if (!gus->gf1.res_port2) {
- snd_printk(KERN_ERR "gus: can't grab synth port 0x%lx\n", port + 0x100);
+ dev_err(card->dev, "gus: can't grab synth port 0x%lx\n", port + 0x100);
snd_gus_free(gus);
return -EBUSY;
}
if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) {
- snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq);
+ dev_err(card->dev, "gus: can't grab irq %d\n", irq);
snd_gus_free(gus);
return -EBUSY;
}
gus->gf1.irq = irq;
card->sync_irq = irq;
if (request_dma(dma1, "GUS - 1")) {
- snd_printk(KERN_ERR "gus: can't grab DMA1 %d\n", dma1);
+ dev_err(card->dev, "gus: can't grab DMA1 %d\n", dma1);
snd_gus_free(gus);
return -EBUSY;
}
gus->gf1.dma1 = dma1;
if (dma2 >= 0 && dma1 != dma2) {
if (request_dma(dma2, "GUS - 2")) {
- snd_printk(KERN_ERR "gus: can't grab DMA2 %d\n", dma2);
+ dev_err(card->dev, "gus: can't grab DMA2 %d\n", dma2);
snd_gus_free(gus);
return -EBUSY;
}
@@ -229,7 +215,9 @@ static int snd_gus_detect_memory(struct snd_gus_card * gus)
snd_gf1_poke(gus, 0L, 0xaa);
snd_gf1_poke(gus, 1L, 0x55);
if (snd_gf1_peek(gus, 0L) != 0xaa || snd_gf1_peek(gus, 1L) != 0x55) {
- snd_printk(KERN_ERR "plain GF1 card at 0x%lx without onboard DRAM?\n", gus->gf1.port);
+ dev_err(gus->card->dev,
+ "plain GF1 card at 0x%lx without onboard DRAM?\n",
+ gus->gf1.port);
return -ENOMEM;
}
for (idx = 1, d = 0xab; idx < 4; idx++, d++) {
@@ -259,7 +247,6 @@ static int snd_gus_detect_memory(struct snd_gus_card * gus)
static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
{
struct snd_card *card;
- unsigned long flags;
int irq, dma1, dma2;
static const unsigned char irqs[16] =
{0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
@@ -287,14 +274,14 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
if ((dma1 & 7) == 0 || (dma2 & 7) == 0) {
- snd_printk(KERN_ERR "Error! DMA isn't defined.\n");
+ dev_err(gus->card->dev, "Error! DMA isn't defined.\n");
return -EINVAL;
}
irq = gus->gf1.irq;
irq = abs(irq);
irq = irqs[irq & 0x0f];
if (irq == 0) {
- snd_printk(KERN_ERR "Error! IRQ isn't defined.\n");
+ dev_err(gus->card->dev, "Error! IRQ isn't defined.\n");
return -EINVAL;
}
irq |= 0x40;
@@ -302,34 +289,34 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
card->mixer.mix_ctrl_reg |= 0x10;
#endif
- spin_lock_irqsave(&gus->reg_lock, flags);
- outb(5, GUSP(gus, REGCNTRLS));
- outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- outb(0x00, GUSP(gus, IRQDMACNTRLREG));
- outb(0, GUSP(gus, REGCNTRLS));
- spin_unlock_irqrestore(&gus->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ outb(5, GUSP(gus, REGCNTRLS));
+ outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ outb(0x00, GUSP(gus, IRQDMACNTRLREG));
+ outb(0, GUSP(gus, REGCNTRLS));
+ }
udelay(100);
- spin_lock_irqsave(&gus->reg_lock, flags);
- outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- outb(dma1, GUSP(gus, IRQDMACNTRLREG));
- if (latches) {
- outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- outb(irq, GUSP(gus, IRQDMACNTRLREG));
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ outb(dma1, GUSP(gus, IRQDMACNTRLREG));
+ if (latches) {
+ outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ outb(irq, GUSP(gus, IRQDMACNTRLREG));
+ }
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
udelay(100);
- spin_lock_irqsave(&gus->reg_lock, flags);
- outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- outb(dma1, GUSP(gus, IRQDMACNTRLREG));
- if (latches) {
- outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- outb(irq, GUSP(gus, IRQDMACNTRLREG));
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ outb(dma1, GUSP(gus, IRQDMACNTRLREG));
+ if (latches) {
+ outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ outb(irq, GUSP(gus, IRQDMACNTRLREG));
+ }
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
snd_gf1_delay(gus);
@@ -337,29 +324,28 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
gus->mix_cntrl_reg |= 0x08; /* enable latches */
else
gus->mix_cntrl_reg &= ~0x08; /* disable latches */
- spin_lock_irqsave(&gus->reg_lock, flags);
- outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- outb(0, GUSP(gus, GF1PAGE));
- spin_unlock_irqrestore(&gus->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ outb(0, GUSP(gus, GF1PAGE));
+ }
return 0;
}
static int snd_gus_check_version(struct snd_gus_card * gus)
{
- unsigned long flags;
unsigned char val, rev;
struct snd_card *card;
card = gus->card;
- spin_lock_irqsave(&gus->reg_lock, flags);
- outb(0x20, GUSP(gus, REGCNTRLS));
- val = inb(GUSP(gus, REGCNTRLS));
- rev = inb(GUSP(gus, BOARDVERSION));
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- snd_printdd("GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev);
- strcpy(card->driver, "GUS");
- strcpy(card->longname, "Gravis UltraSound Classic (2.4)");
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ outb(0x20, GUSP(gus, REGCNTRLS));
+ val = inb(GUSP(gus, REGCNTRLS));
+ rev = inb(GUSP(gus, BOARDVERSION));
+ }
+ dev_dbg(card->dev, "GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev);
+ strscpy(card->driver, "GUS");
+ strscpy(card->longname, "Gravis UltraSound Classic (2.4)");
if ((val != 255 && (val & 0x06)) || (rev >= 5 && rev != 255)) {
if (rev >= 5 && rev <= 9) {
gus->ics_flag = 1;
@@ -370,20 +356,23 @@ static int snd_gus_check_version(struct snd_gus_card * gus)
}
if (rev >= 10 && rev != 255) {
if (rev >= 10 && rev <= 11) {
- strcpy(card->driver, "GUS MAX");
- strcpy(card->longname, "Gravis UltraSound MAX");
+ strscpy(card->driver, "GUS MAX");
+ strscpy(card->longname, "Gravis UltraSound MAX");
gus->max_flag = 1;
} else if (rev == 0x30) {
- strcpy(card->driver, "GUS ACE");
- strcpy(card->longname, "Gravis UltraSound Ace");
+ strscpy(card->driver, "GUS ACE");
+ strscpy(card->longname, "Gravis UltraSound Ace");
gus->ace_flag = 1;
} else if (rev == 0x50) {
- strcpy(card->driver, "GUS Extreme");
- strcpy(card->longname, "Gravis UltraSound Extreme");
+ strscpy(card->driver, "GUS Extreme");
+ strscpy(card->longname, "Gravis UltraSound Extreme");
gus->ess_flag = 1;
} else {
- snd_printk(KERN_ERR "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val);
- snd_printk(KERN_ERR " please - report to <perex@perex.cz>\n");
+ dev_err(card->dev,
+ "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n",
+ gus->gf1.port, rev, val);
+ dev_err(card->dev,
+ " please - report to <perex@perex.cz>\n");
}
}
}
@@ -400,7 +389,7 @@ int snd_gus_initialize(struct snd_gus_card *gus)
if (!gus->interwave) {
err = snd_gus_check_version(gus);
if (err < 0) {
- snd_printk(KERN_ERR "version check failed\n");
+ dev_err(gus->card->dev, "version check failed\n");
return err;
}
err = snd_gus_detect_memory(gus);
@@ -438,8 +427,6 @@ EXPORT_SYMBOL(snd_gf1_new_mixer);
/* gus_pcm.c */
EXPORT_SYMBOL(snd_gf1_pcm_new);
/* gus.c */
-EXPORT_SYMBOL(snd_gus_use_inc);
-EXPORT_SYMBOL(snd_gus_use_dec);
EXPORT_SYMBOL(snd_gus_create);
EXPORT_SYMBOL(snd_gus_initialize);
/* gus_irq.c */
@@ -456,4 +443,3 @@ EXPORT_SYMBOL(snd_gf1_translate_freq);
EXPORT_SYMBOL(snd_gf1_mem_alloc);
EXPORT_SYMBOL(snd_gf1_mem_xfree);
EXPORT_SYMBOL(snd_gf1_mem_free);
-EXPORT_SYMBOL(snd_gf1_mem_lock);
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index 3e56c01c4544..8d95d8d5abdf 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -15,15 +15,6 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer);
#endif
-void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup)
-{
- if (!xup) {
- mutex_lock(&alloc->memory_mutex);
- } else {
- mutex_unlock(&alloc->memory_mutex);
- }
-}
-
static struct snd_gf1_mem_block *
snd_gf1_mem_xalloc(struct snd_gf1_mem *alloc, struct snd_gf1_mem_block *block,
const char *name)
@@ -50,7 +41,6 @@ snd_gf1_mem_xalloc(struct snd_gf1_mem *alloc, struct snd_gf1_mem_block *block,
alloc->first = nblock;
else
nblock->prev->next = nblock;
- mutex_unlock(&alloc->memory_mutex);
return nblock;
}
pblock = pblock->next;
@@ -71,7 +61,6 @@ int snd_gf1_mem_xfree(struct snd_gf1_mem * alloc, struct snd_gf1_mem_block * blo
{
if (block->share) { /* ok.. shared block */
block->share--;
- mutex_unlock(&alloc->memory_mutex);
return 0;
}
if (alloc->first == block) {
@@ -183,46 +172,37 @@ struct snd_gf1_mem_block *snd_gf1_mem_alloc(struct snd_gf1_mem * alloc, int owne
{
struct snd_gf1_mem_block block, *nblock;
- snd_gf1_mem_lock(alloc, 0);
+ guard(mutex)(&alloc->memory_mutex);
if (share_id != NULL) {
nblock = snd_gf1_mem_share(alloc, share_id);
if (nblock != NULL) {
if (size != (int)nblock->size) {
/* TODO: remove in the future */
- snd_printk(KERN_ERR "snd_gf1_mem_alloc - share: sizes differ\n");
+ pr_err("%s - share: sizes differ\n", __func__);
goto __std;
}
nblock->share++;
- snd_gf1_mem_lock(alloc, 1);
return NULL;
}
}
__std:
- if (snd_gf1_mem_find(alloc, &block, size, w_16, align) < 0) {
- snd_gf1_mem_lock(alloc, 1);
+ if (snd_gf1_mem_find(alloc, &block, size, w_16, align) < 0)
return NULL;
- }
if (share_id != NULL)
memcpy(&block.share_id, share_id, sizeof(block.share_id));
block.owner = owner;
nblock = snd_gf1_mem_xalloc(alloc, &block, name);
- snd_gf1_mem_lock(alloc, 1);
return nblock;
}
int snd_gf1_mem_free(struct snd_gf1_mem * alloc, unsigned int address)
{
- int result;
struct snd_gf1_mem_block *block;
- snd_gf1_mem_lock(alloc, 0);
+ guard(mutex)(&alloc->memory_mutex);
block = snd_gf1_mem_look(alloc, address);
- if (block) {
- result = snd_gf1_mem_xfree(alloc, block);
- snd_gf1_mem_lock(alloc, 1);
- return result;
- }
- snd_gf1_mem_lock(alloc, 1);
+ if (block)
+ return snd_gf1_mem_xfree(alloc, block);
return -EINVAL;
}
@@ -282,7 +262,7 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
gus = entry->private_data;
alloc = &gus->gf1.mem_alloc;
- mutex_lock(&alloc->memory_mutex);
+ guard(mutex)(&alloc->memory_mutex);
snd_iprintf(buffer, "8-bit banks : \n ");
for (i = 0; i < 4; i++)
snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : "");
@@ -326,7 +306,6 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
}
snd_iprintf(buffer, " Total: memory = %i, used = %i, free = %i\n",
total, used, total - used);
- mutex_unlock(&alloc->memory_mutex);
#if 0
ultra_iprintf(buffer, " Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n",
ultra_memory_free_size(card, &card->gf1.mem_alloc),
diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c
index 03f9cfcbf601..9bfdb4e45a5d 100644
--- a/sound/isa/gus/gus_mixer.c
+++ b/sound/isa/gus/gus_mixer.c
@@ -37,7 +37,6 @@ static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int shift = kcontrol->private_value & 0xff;
int invert = (kcontrol->private_value >> 8) & 1;
int change;
@@ -47,13 +46,12 @@ static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
if (invert)
nval ^= 1;
nval <<= shift;
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
oval = gus->mix_cntrl_reg;
nval = (oval & ~(1 << shift)) | nval;
change = nval != oval;
outb(gus->mix_cntrl_reg = nval, GUSP(gus, MIXCNTRLREG));
outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return change;
}
@@ -75,14 +73,12 @@ static int snd_ics_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
static int snd_ics_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int addr = kcontrol->private_value & 0xff;
unsigned char left, right;
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
left = gus->gf1.ics_regs[addr][0];
right = gus->gf1.ics_regs[addr][1];
- spin_unlock_irqrestore(&gus->reg_lock, flags);
ucontrol->value.integer.value[0] = left & 127;
ucontrol->value.integer.value[1] = right & 127;
return 0;
@@ -91,14 +87,13 @@ static int snd_ics_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int addr = kcontrol->private_value & 0xff;
int change;
unsigned char val1, val2, oval1, oval2;
val1 = ucontrol->value.integer.value[0] & 127;
val2 = ucontrol->value.integer.value[1] & 127;
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
oval1 = gus->gf1.ics_regs[addr][0];
oval2 = gus->gf1.ics_regs[addr][1];
change = val1 != oval1 || val2 != oval2;
@@ -116,7 +111,6 @@ static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
outb(2, GUSP(gus, MIXDATAPORT));
outb(addr | 3, GUSP(gus, MIXCNTRLPORT));
outb((unsigned char) val2, GUSP(gus, MIXDATAPORT));
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return change;
}
@@ -152,7 +146,7 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus)
if (gus->ics_flag)
snd_component_add(card, "ICS2101");
if (card->mixername[0] == '\0') {
- strcpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1");
+ strscpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1");
} else {
if (gus->ics_flag)
strcat(card->mixername, ",ICS2101");
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 230f65a0e4b0..9249cbff30f3 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -67,10 +67,6 @@ static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,
count += offset & 31;
offset &= ~31;
- /*
- snd_printk(KERN_DEBUG "block change - offset = 0x%x, count = 0x%x\n",
- offset, count);
- */
memset(&block, 0, sizeof(block));
block.cmd = SNDRV_GF1_DMA_IRQ;
if (snd_pcm_format_unsigned(runtime->format))
@@ -93,7 +89,6 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct gus_pcm_private *pcmp = runtime->private_data;
struct snd_gus_card * gus = pcmp->gus;
- unsigned long flags;
unsigned char voice_ctrl, ramp_ctrl;
unsigned short rate;
unsigned int curr, begin, end;
@@ -101,14 +96,12 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
unsigned char pan;
unsigned int voice;
- spin_lock_irqsave(&pcmp->lock, flags);
- if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {
- spin_unlock_irqrestore(&pcmp->lock, flags);
- return;
+ scoped_guard(spinlock_irqsave, &pcmp->lock) {
+ if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE)
+ return;
+ pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE;
+ pcmp->final_volume = 0;
}
- pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE;
- pcmp->final_volume = 0;
- spin_unlock_irqrestore(&pcmp->lock, flags);
rate = snd_gf1_translate_freq(gus, runtime->rate << 4);
/* enable WAVE IRQ */
voice_ctrl = snd_pcm_format_width(runtime->format) == 16 ? 0x24 : 0x20;
@@ -123,14 +116,9 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
end = curr + (pcmp->block_size / runtime->channels);
end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
- /*
- snd_printk(KERN_DEBUG "init: curr=0x%x, begin=0x%x, end=0x%x, "
- "ctrl=0x%x, ramp=0x%x, rate=0x%x\n",
- curr, begin, end, voice_ctrl, ramp_ctrl, rate);
- */
pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);
snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, pan);
snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, rate);
@@ -146,9 +134,9 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
snd_gf1_delay(gus);
snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
- spin_lock_irqsave(&gus->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&gus->reg_lock);
for (voice = 0; voice < pcmp->voices; voice++) {
snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);
if (gus->gf1.enh_mode)
@@ -165,7 +153,6 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
voice_ctrl &= ~0x20; /* disable IRQ for next voice */
}
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,
@@ -178,65 +165,65 @@ static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,
unsigned int end, step;
if (!pvoice->private_data) {
- snd_printd("snd_gf1_pcm: unknown wave irq?\n");
+ dev_dbg(gus->card->dev, "%s: unknown wave irq?\n", __func__);
snd_gf1_smart_stop_voice(gus, pvoice->number);
return;
}
pcmp = pvoice->private_data;
if (pcmp == NULL) {
- snd_printd("snd_gf1_pcm: unknown wave irq?\n");
+ dev_dbg(gus->card->dev, "%s: unknown wave irq?\n", __func__);
snd_gf1_smart_stop_voice(gus, pvoice->number);
return;
}
gus = pcmp->gus;
runtime = pcmp->substream->runtime;
- spin_lock(&gus->reg_lock);
- snd_gf1_select_voice(gus, pvoice->number);
- voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b;
- ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
+ scoped_guard(spinlock, &gus->reg_lock) {
+ snd_gf1_select_voice(gus, pvoice->number);
+ voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b;
+ ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
#if 0
- snd_gf1_select_voice(gus, pvoice->number);
- printk(KERN_DEBUG "position = 0x%x\n",
- (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
- snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
- printk(KERN_DEBUG "position = 0x%x\n",
- (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
- snd_gf1_select_voice(gus, pvoice->number);
+ snd_gf1_select_voice(gus, pvoice->number);
+ dev_dbg(gus->card->dev, "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
+ dev_dbg(gus->card->dev, "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ snd_gf1_select_voice(gus, pvoice->number);
#endif
- pcmp->bpos++;
- pcmp->bpos %= pcmp->blocks;
- if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */
- voice_ctrl |= 0x08; /* enable loop */
- } else {
- ramp_ctrl |= 0x04; /* enable rollover */
- }
- end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels);
- end -= voice_ctrl & 4 ? 2 : 1;
- step = pcmp->dma_size / runtime->channels;
- voice_ctrl |= 0x20;
- if (!pcmp->final_volume) {
- ramp_ctrl |= 0x20;
- ramp_ctrl &= ~0x03;
- }
- for (idx = 0; idx < pcmp->voices; idx++, end += step) {
- snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);
- snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4);
- snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
- snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
- voice_ctrl &= ~0x20;
- }
- if (!gus->gf1.enh_mode) {
- snd_gf1_delay(gus);
+ pcmp->bpos++;
+ pcmp->bpos %= pcmp->blocks;
+ if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */
+ voice_ctrl |= 0x08; /* enable loop */
+ } else {
+ ramp_ctrl |= 0x04; /* enable rollover */
+ }
+ end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels);
+ end -= voice_ctrl & 4 ? 2 : 1;
+ step = pcmp->dma_size / runtime->channels;
voice_ctrl |= 0x20;
- for (idx = 0; idx < pcmp->voices; idx++) {
+ if (!pcmp->final_volume) {
+ ramp_ctrl |= 0x20;
+ ramp_ctrl &= ~0x03;
+ }
+ for (idx = 0; idx < pcmp->voices; idx++, end += step) {
snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);
+ snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4);
snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
voice_ctrl &= ~0x20;
}
+ if (!gus->gf1.enh_mode) {
+ snd_gf1_delay(gus);
+ voice_ctrl |= 0x20;
+ for (idx = 0; idx < pcmp->voices; idx++) {
+ snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);
+ snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);
+ snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);
+ voice_ctrl &= ~0x20;
+ }
+ }
}
- spin_unlock(&gus->reg_lock);
snd_pcm_period_elapsed(pcmp->substream);
#if 0
@@ -261,10 +248,10 @@ static void snd_gf1_pcm_interrupt_volume(struct snd_gus_card * gus,
struct gus_pcm_private *pcmp = pvoice->private_data;
/* stop ramp, but leave rollover bit untouched */
- spin_lock(&gus->reg_lock);
- snd_gf1_select_voice(gus, pvoice->number);
- snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- spin_unlock(&gus->reg_lock);
+ scoped_guard(spinlock, &gus->reg_lock) {
+ snd_gf1_select_voice(gus, pvoice->number);
+ snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
+ }
if (pcmp == NULL)
return;
/* are we active? */
@@ -275,11 +262,10 @@ static void snd_gf1_pcm_interrupt_volume(struct snd_gus_card * gus,
if (pcmp->substream == NULL)
return;
vol = !cvoice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
- spin_lock(&gus->reg_lock);
+ guard(spinlock)(&gus->reg_lock);
snd_gf1_select_voice(gus, pvoice->number);
snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
pcmp->final_volume = 1;
- spin_unlock(&gus->reg_lock);
}
static void snd_gf1_pcm_volume_change(struct snd_gus_card * gus)
@@ -291,20 +277,14 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,
int w16, int invert)
{
unsigned int len;
- unsigned long flags;
- /*
- printk(KERN_DEBUG
- "poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n",
- (int)buf, pos, count, gus->gf1.port);
- */
while (count > 0) {
len = count;
if (len > 512) /* limit, to allow IRQ */
len = 512;
count -= len;
if (gus->interwave) {
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01 | (invert ? 0x08 : 0x00));
snd_gf1_dram_addr(gus, pos);
if (w16) {
@@ -313,7 +293,6 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,
} else {
outsb(GUSP(gus, DRAM), buf, len);
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
buf += 512;
pos += 512;
} else {
@@ -369,7 +348,7 @@ static int playback_copy_ack(struct snd_pcm_substream *substream,
static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,
int voice, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct gus_pcm_private *pcmp = runtime->private_data;
@@ -378,28 +357,12 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,
bpos = get_bpos(pcmp, voice, pos, len);
if (bpos < 0)
- return pos;
- if (copy_from_user(runtime->dma_area + bpos, src, len))
+ return bpos;
+ if (copy_from_iter(runtime->dma_area + bpos, len, src) != len)
return -EFAULT;
return playback_copy_ack(substream, bpos, len);
}
-static int snd_gf1_pcm_playback_copy_kernel(struct snd_pcm_substream *substream,
- int voice, unsigned long pos,
- void *src, unsigned long count)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct gus_pcm_private *pcmp = runtime->private_data;
- unsigned int len = count;
- int bpos;
-
- bpos = get_bpos(pcmp, voice, pos, len);
- if (bpos < 0)
- return pos;
- memcpy(runtime->dma_area + bpos, src, len);
- return playback_copy_ack(substream, bpos, len);
-}
-
static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
int voice, unsigned long pos,
unsigned long count)
@@ -411,7 +374,7 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,
bpos = get_bpos(pcmp, voice, pos, len);
if (bpos < 0)
- return pos;
+ return bpos;
snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos,
bytes_to_samples(runtime, count));
return playback_copy_ack(substream, bpos, len);
@@ -509,9 +472,9 @@ static int snd_gf1_pcm_playback_trigger(struct snd_pcm_substream *substream,
if (cmd == SNDRV_PCM_TRIGGER_START) {
snd_gf1_pcm_trigger_up(substream);
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- spin_lock(&pcmp->lock);
- pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE;
- spin_unlock(&pcmp->lock);
+ scoped_guard(spinlock, &pcmp->lock) {
+ pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE;
+ }
voice = pcmp->pvoices[0]->number;
snd_gf1_stop_voices(gus, voice, voice);
if (pcmp->pvoices[1]) {
@@ -533,7 +496,7 @@ static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(struct snd_pcm_substream *
unsigned char voice_ctrl;
pos = 0;
- spin_lock(&gus->reg_lock);
+ guard(spinlock)(&gus->reg_lock);
if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {
snd_gf1_select_voice(gus, pcmp->pvoices[0]->number);
voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
@@ -542,7 +505,6 @@ static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(struct snd_pcm_substream *
pos <<= 1;
pos = bytes_to_frames(runtime, pos);
}
- spin_unlock(&gus->reg_lock);
return pos;
}
@@ -602,10 +564,9 @@ static int snd_gf1_pcm_capture_trigger(struct snd_pcm_substream *substream,
return -EINVAL;
}
- spin_lock(&gus->reg_lock);
+ guard(spinlock)(&gus->reg_lock);
snd_gf1_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, val);
snd_gf1_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL);
- spin_unlock(&gus->reg_lock);
return 0;
}
@@ -689,8 +650,9 @@ static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_gf1_pcm_playback_free;
#if 0
- printk(KERN_DEBUG "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",
- (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
+ dev_dbg(gus->card->dev,
+ "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",
+ (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
#endif
err = snd_gf1_dma_init(gus);
if (err < 0)
@@ -711,7 +673,7 @@ static int snd_gf1_pcm_playback_close(struct snd_pcm_substream *substream)
struct gus_pcm_private *pcmp = runtime->private_data;
if (!wait_event_timeout(pcmp->sleep, (atomic_read(&pcmp->dma_count) <= 0), 2*HZ))
- snd_printk(KERN_ERR "gf1 pcm - serious DMA problem\n");
+ dev_err(gus->card->dev, "gf1 pcm - serious DMA problem\n");
snd_gf1_dma_done(gus);
return 0;
@@ -753,19 +715,16 @@ static int snd_gf1_pcm_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_gf1_pcm_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);
+ guard(spinlock_irqsave)(&gus->pcm_volume_level_lock);
ucontrol->value.integer.value[0] = gus->gf1.pcm_volume_level_left1;
ucontrol->value.integer.value[1] = gus->gf1.pcm_volume_level_right1;
- spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);
return 0;
}
static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned int idx;
unsigned short val1, val2, vol;
@@ -774,33 +733,32 @@ static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
val1 = ucontrol->value.integer.value[0] & 127;
val2 = ucontrol->value.integer.value[1] & 127;
- spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);
- change = val1 != gus->gf1.pcm_volume_level_left1 ||
- val2 != gus->gf1.pcm_volume_level_right1;
- gus->gf1.pcm_volume_level_left1 = val1;
- gus->gf1.pcm_volume_level_right1 = val2;
- gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4;
- gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4;
- spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);
+ scoped_guard(spinlock_irqsave, &gus->pcm_volume_level_lock) {
+ change = val1 != gus->gf1.pcm_volume_level_left1 ||
+ val2 != gus->gf1.pcm_volume_level_right1;
+ gus->gf1.pcm_volume_level_left1 = val1;
+ gus->gf1.pcm_volume_level_right1 = val2;
+ gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4;
+ gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4;
+ }
/* are we active? */
- spin_lock_irqsave(&gus->voice_alloc, flags);
- for (idx = 0; idx < 32; idx++) {
- pvoice = &gus->gf1.voices[idx];
- if (!pvoice->pcm)
- continue;
- pcmp = pvoice->private_data;
- if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))
- continue;
- /* load real volume - better precision */
- spin_lock(&gus->reg_lock);
- snd_gf1_select_voice(gus, pvoice->number);
- snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
- snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
- pcmp->final_volume = 1;
- spin_unlock(&gus->reg_lock);
+ scoped_guard(spinlock_irqsave, &gus->voice_alloc) {
+ for (idx = 0; idx < 32; idx++) {
+ pvoice = &gus->gf1.voices[idx];
+ if (!pvoice->pcm)
+ continue;
+ pcmp = pvoice->private_data;
+ if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))
+ continue;
+ /* load real volume - better precision */
+ guard(spinlock)(&gus->reg_lock);
+ snd_gf1_select_voice(gus, pvoice->number);
+ snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
+ vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
+ snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);
+ pcmp->final_volume = 1;
+ }
}
- spin_unlock_irqrestore(&gus->voice_alloc, flags);
return change;
}
@@ -830,8 +788,7 @@ static const struct snd_pcm_ops snd_gf1_pcm_playback_ops = {
.prepare = snd_gf1_pcm_playback_prepare,
.trigger = snd_gf1_pcm_playback_trigger,
.pointer = snd_gf1_pcm_playback_pointer,
- .copy_user = snd_gf1_pcm_playback_copy,
- .copy_kernel = snd_gf1_pcm_playback_copy_kernel,
+ .copy = snd_gf1_pcm_playback_copy,
.fill_silence = snd_gf1_pcm_playback_silence,
};
@@ -881,7 +838,7 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
SNDRV_DMA_TYPE_DEV, card->dev,
64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024);
}
- strcpy(pcm->name, pcm->id);
+ strscpy(pcm->name, pcm->id);
if (gus->interwave) {
sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
}
@@ -892,10 +849,10 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus);
else
kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus);
+ kctl->id.index = control_index;
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
- kctl->id.index = control_index;
return 0;
}
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c
index 9a1ab5872c4f..a7a3e764bb77 100644
--- a/sound/isa/gus/gus_reset.c
+++ b/sound/isa/gus/gus_reset.c
@@ -9,9 +9,6 @@
#include <sound/core.h>
#include <sound/gus.h>
-extern int snd_gf1_synth_init(struct snd_gus_card * gus);
-extern void snd_gf1_synth_done(struct snd_gus_card * gus);
-
/*
* ok.. default interrupt handlers...
*/
@@ -83,26 +80,20 @@ void snd_gf1_set_default_handlers(struct snd_gus_card * gus, unsigned int what)
static void snd_gf1_clear_regs(struct snd_gus_card * gus)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
inb(GUSP(gus, IRQSTAT));
snd_gf1_write8(gus, 0x41, 0); /* DRAM DMA Control Register */
snd_gf1_write8(gus, 0x45, 0); /* Timer Control */
snd_gf1_write8(gus, 0x49, 0); /* Sampling Control Register */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
static void snd_gf1_look_regs(struct snd_gus_card * gus)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_look8(gus, 0x41); /* DRAM DMA Control Register */
snd_gf1_look8(gus, 0x49); /* Sampling Control Register */
inb(GUSP(gus, IRQSTAT));
snd_gf1_read8(gus, 0x0f); /* IRQ Source Register */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
/*
@@ -111,42 +102,35 @@ static void snd_gf1_look_regs(struct snd_gus_card * gus)
void snd_gf1_smart_stop_voice(struct snd_gus_card * gus, unsigned short voice)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_select_voice(gus, voice);
#if 0
- printk(KERN_DEBUG " -%i- smart stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));
+ dev_dbg(gus->card->dev,
+ " -%i- smart stop voice - volume = 0x%x\n",
+ voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));
#endif
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
void snd_gf1_stop_voice(struct snd_gus_card * gus, unsigned short voice)
{
- unsigned long flags;
-
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_select_voice(gus, voice);
#if 0
- printk(KERN_DEBUG " -%i- stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));
+ dev_dbg(gus->card->dev,
+ " -%i- stop voice - volume = 0x%x\n",
+ voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));
#endif
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
if (gus->gf1.enh_mode)
snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
-#if 0
- snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_VIBRATO);
- snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_TREMOLO);
-#endif
}
static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min,
unsigned short v_max)
{
- unsigned long flags;
unsigned int daddr;
unsigned short i, w_16;
@@ -156,7 +140,7 @@ static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min
if (gus->gf1.syn_voices)
gus->gf1.syn_voices[i].flags = ~VFLG_DYNAMIC;
#endif
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_select_voice(gus, i);
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); /* Voice Control Register = voice stop */
snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); /* Volume Ramp Control Register = ramp off */
@@ -177,23 +161,17 @@ static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min
snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, 0);
snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, 0);
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
-#if 0
- snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_VIBRATO);
- snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_TREMOLO);
-#endif
}
}
void snd_gf1_stop_voices(struct snd_gus_card * gus, unsigned short v_min, unsigned short v_max)
{
- unsigned long flags;
short i, ramp_ok;
unsigned short ramp_end;
if (!in_interrupt()) { /* this can't be done in interrupt */
for (i = v_min, ramp_ok = 0; i <= v_max; i++) {
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
snd_gf1_select_voice(gus, i);
ramp_end = snd_gf1_read16(gus, 9) >> 8;
if (ramp_end > SNDRV_GF1_MIN_OFFSET) {
@@ -207,7 +185,6 @@ void snd_gf1_stop_voices(struct snd_gus_card * gus, unsigned short v_min, unsign
snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, 0x40);
}
}
- spin_unlock_irqrestore(&gus->reg_lock, flags);
}
msleep_interruptible(50);
}
@@ -240,21 +217,17 @@ static void snd_gf1_alloc_voice_use(struct snd_gus_card * gus,
struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, int client, int port)
{
struct snd_gus_voice *pvoice;
- unsigned long flags;
int idx;
- spin_lock_irqsave(&gus->voice_alloc, flags);
+ guard(spinlock_irqsave)(&gus->voice_alloc);
if (type == SNDRV_GF1_VOICE_TYPE_PCM) {
- if (gus->gf1.pcm_alloc_voices >= gus->gf1.pcm_channels) {
- spin_unlock_irqrestore(&gus->voice_alloc, flags);
+ if (gus->gf1.pcm_alloc_voices >= gus->gf1.pcm_channels)
return NULL;
- }
}
for (idx = 0; idx < 32; idx++) {
pvoice = &gus->gf1.voices[idx];
if (!pvoice->use) {
snd_gf1_alloc_voice_use(gus, pvoice, type, client, port);
- spin_unlock_irqrestore(&gus->voice_alloc, flags);
return pvoice;
}
}
@@ -263,32 +236,29 @@ struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, i
if (pvoice->midi && !pvoice->client) {
snd_gf1_clear_voices(gus, pvoice->number, pvoice->number);
snd_gf1_alloc_voice_use(gus, pvoice, type, client, port);
- spin_unlock_irqrestore(&gus->voice_alloc, flags);
return pvoice;
}
}
- spin_unlock_irqrestore(&gus->voice_alloc, flags);
return NULL;
}
void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice)
{
- unsigned long flags;
void (*private_free)(struct snd_gus_voice *voice);
if (voice == NULL || !voice->use)
return;
snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_VOICE | voice->number);
snd_gf1_clear_voices(gus, voice->number, voice->number);
- spin_lock_irqsave(&gus->voice_alloc, flags);
- private_free = voice->private_free;
- voice->private_free = NULL;
- voice->private_data = NULL;
- if (voice->pcm)
- gus->gf1.pcm_alloc_voices--;
- voice->use = voice->pcm = 0;
- voice->sample_ops = NULL;
- spin_unlock_irqrestore(&gus->voice_alloc, flags);
+ scoped_guard(spinlock_irqsave, &gus->voice_alloc) {
+ private_free = voice->private_free;
+ voice->private_free = NULL;
+ voice->private_data = NULL;
+ if (voice->pcm)
+ gus->gf1.pcm_alloc_voices--;
+ voice->use = voice->pcm = 0;
+ voice->sample_ops = NULL;
+ }
if (private_free)
private_free(voice);
}
@@ -299,7 +269,6 @@ void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice)
int snd_gf1_start(struct snd_gus_card * gus)
{
- unsigned long flags;
unsigned int i;
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
@@ -331,9 +300,7 @@ int snd_gf1_start(struct snd_gus_card * gus)
} else {
gus->gf1.sw_lfo = 1;
}
-#if 0
- snd_gf1_lfo_init(gus);
-#endif
+
if (gus->gf1.memory > 0)
for (i = 0; i < 4; i++)
snd_gf1_poke(gus, gus->gf1.default_voice_address + i, 0);
@@ -350,10 +317,10 @@ int snd_gf1_start(struct snd_gus_card * gus)
}
while ((snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ) & 0xc0) != 0xc0);
- spin_lock_irqsave(&gus->reg_lock, flags);
- outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
- outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
- spin_unlock_irqrestore(&gus->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
+ outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
+ }
snd_gf1_timers_init(gus);
snd_gf1_look_regs(gus);
@@ -387,8 +354,6 @@ int snd_gf1_stop(struct snd_gus_card * gus)
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* disable IRQ & DAC */
snd_gf1_timers_done(gus);
snd_gf1_mem_done(gus);
-#if 0
- snd_gf1_lfo_done(gus);
-#endif
+
return 0;
}
diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c
index 047ddbc6192f..e3a8847e02cf 100644
--- a/sound/isa/gus/gus_timer.c
+++ b/sound/isa/gus/gus_timer.c
@@ -16,33 +16,29 @@
static int snd_gf1_timer1_start(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
unsigned int ticks;
struct snd_gus_card *gus;
gus = snd_timer_chip(timer);
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
ticks = timer->sticks;
tmp = (gus->gf1.timer_enabled |= 4);
snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks); /* timer 1 count */
snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 1 IRQ */
snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return 0;
}
static int snd_gf1_timer1_stop(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
struct snd_gus_card *gus;
gus = snd_timer_chip(timer);
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
tmp = (gus->gf1.timer_enabled &= ~4);
snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return 0;
}
@@ -52,33 +48,29 @@ static int snd_gf1_timer1_stop(struct snd_timer * timer)
static int snd_gf1_timer2_start(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
unsigned int ticks;
struct snd_gus_card *gus;
gus = snd_timer_chip(timer);
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
ticks = timer->sticks;
tmp = (gus->gf1.timer_enabled |= 8);
snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks); /* timer 2 count */
snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 2 IRQ */
snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return 0;
}
static int snd_gf1_timer2_stop(struct snd_timer * timer)
{
- unsigned long flags;
unsigned char tmp;
struct snd_gus_card *gus;
gus = snd_timer_chip(timer);
- spin_lock_irqsave(&gus->reg_lock, flags);
+ guard(spinlock_irqsave)(&gus->reg_lock);
tmp = (gus->gf1.timer_enabled &= ~8);
snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */
- spin_unlock_irqrestore(&gus->reg_lock, flags);
return 0;
}
@@ -156,7 +148,7 @@ void snd_gf1_timers_init(struct snd_gus_card * gus)
tid.subdevice = 0;
if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
- strcpy(timer->name, "GF1 timer #1");
+ strscpy(timer->name, "GF1 timer #1");
timer->private_data = gus;
timer->private_free = snd_gf1_timer1_free;
timer->hw = snd_gf1_timer1;
@@ -166,7 +158,7 @@ void snd_gf1_timers_init(struct snd_gus_card * gus)
tid.device++;
if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
- strcpy(timer->name, "GF1 timer #2");
+ strscpy(timer->name, "GF1 timer #2");
timer->private_data = gus;
timer->private_free = snd_gf1_timer2_free;
timer->hw = snd_gf1_timer2;
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index 3975848160e7..770d8f3e4cff 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -49,13 +49,12 @@ static void snd_gf1_interrupt_midi_in(struct snd_gus_card * gus)
static void snd_gf1_interrupt_midi_out(struct snd_gus_card * gus)
{
char byte;
- unsigned long flags;
/* try unlock output */
if (snd_gf1_uart_stat(gus) & 0x01)
snd_gf1_interrupt_midi_in(gus);
- spin_lock_irqsave(&gus->uart_cmd_lock, flags);
+ guard(spinlock_irqsave)(&gus->uart_cmd_lock);
if (snd_gf1_uart_stat(gus) & 0x02) { /* Tx FIFO free? */
if (snd_rawmidi_transmit(gus->midi_substream_output, &byte, 1) != 1) { /* no other bytes or error */
snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20); /* disable Tx interrupt */
@@ -63,7 +62,6 @@ static void snd_gf1_interrupt_midi_out(struct snd_gus_card * gus)
snd_gf1_uart_put(gus, byte);
}
}
- spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
}
static void snd_gf1_uart_reset(struct snd_gus_card * gus, int close)
@@ -77,31 +75,30 @@ static void snd_gf1_uart_reset(struct snd_gus_card * gus, int close)
static int snd_gf1_uart_output_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_gus_card *gus;
gus = substream->rmidi->private_data;
- spin_lock_irqsave(&gus->uart_cmd_lock, flags);
+ guard(spinlock_irqsave)(&gus->uart_cmd_lock);
if (!(gus->gf1.uart_cmd & 0x80)) { /* input active? */
snd_gf1_uart_reset(gus, 0);
}
gus->gf1.interrupt_handler_midi_out = snd_gf1_interrupt_midi_out;
gus->midi_substream_output = substream;
- spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
#if 0
- snd_printk(KERN_DEBUG "write init - cmd = 0x%x, stat = 0x%x\n", gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
+ dev_dbg(gus->card->dev,
+ "write init - cmd = 0x%x, stat = 0x%x\n",
+ gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
#endif
return 0;
}
static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_gus_card *gus;
int i;
gus = substream->rmidi->private_data;
- spin_lock_irqsave(&gus->uart_cmd_lock, flags);
+ guard(spinlock_irqsave)(&gus->uart_cmd_lock);
if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) {
snd_gf1_uart_reset(gus, 0);
}
@@ -111,60 +108,53 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
for (i = 0; i < 1000 && (snd_gf1_uart_stat(gus) & 0x01); i++)
snd_gf1_uart_get(gus); /* clean Rx */
if (i >= 1000)
- snd_printk(KERN_ERR "gus midi uart init read - cleanup error\n");
+ dev_err(gus->card->dev, "gus midi uart init read - cleanup error\n");
}
- spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
#if 0
- snd_printk(KERN_DEBUG
- "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
- gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
- snd_printk(KERN_DEBUG
- "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
- "(page = 0x%x)\n",
- gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
- inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
+ dev_dbg(gus->card->dev,
+ "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
+ gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
+ dev_dbg(gus->card->dev,
+ "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n",
+ gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
+ inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
#endif
return 0;
}
static int snd_gf1_uart_output_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_gus_card *gus;
gus = substream->rmidi->private_data;
- spin_lock_irqsave(&gus->uart_cmd_lock, flags);
+ guard(spinlock_irqsave)(&gus->uart_cmd_lock);
if (gus->gf1.interrupt_handler_midi_in != snd_gf1_interrupt_midi_in)
snd_gf1_uart_reset(gus, 1);
snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_OUT);
gus->midi_substream_output = NULL;
- spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
return 0;
}
static int snd_gf1_uart_input_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_gus_card *gus;
gus = substream->rmidi->private_data;
- spin_lock_irqsave(&gus->uart_cmd_lock, flags);
+ guard(spinlock_irqsave)(&gus->uart_cmd_lock);
if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out)
snd_gf1_uart_reset(gus, 1);
snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_IN);
gus->midi_substream_input = NULL;
- spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
return 0;
}
static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct snd_gus_card *gus;
- unsigned long flags;
gus = substream->rmidi->private_data;
- spin_lock_irqsave(&gus->uart_cmd_lock, flags);
+ guard(spinlock_irqsave)(&gus->uart_cmd_lock);
if (up) {
if ((gus->gf1.uart_cmd & 0x80) == 0)
snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x80); /* enable Rx interrupts */
@@ -172,7 +162,6 @@ static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream *substream,
if (gus->gf1.uart_cmd & 0x80)
snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x80); /* disable Rx interrupts */
}
- spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
}
static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -235,7 +224,7 @@ int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device)
err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi);
if (err < 0)
return err;
- strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
+ strscpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_gf1_uart_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_gf1_uart_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c
index ed72196a361b..e729621756cf 100644
--- a/sound/isa/gus/gus_volume.c
+++ b/sound/isa/gus/gus_volume.c
@@ -104,7 +104,8 @@ unsigned short snd_gf1_translate_freq(struct snd_gus_card * gus, unsigned int fr
freq16 = 50;
if (freq16 & 0xf8000000) {
freq16 = ~0xf8000000;
- snd_printk(KERN_ERR "snd_gf1_translate_freq: overflow - freq = 0x%x\n", freq16);
+ dev_err(gus->card->dev, "%s: overflow - freq = 0x%x\n",
+ __func__, freq16);
}
return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq;
}
@@ -189,14 +190,14 @@ unsigned short snd_gf1_compute_freq(unsigned int freq,
fc = (freq << 10) / rate;
if (fc > 97391L) {
fc = 97391;
- snd_printk(KERN_ERR "patch: (1) fc frequency overflow - %u\n", fc);
+ pr_err("patch: (1) fc frequency overflow - %u\n", fc);
}
fc = (fc * 44100UL) / mix_rate;
while (scale--)
fc <<= 1;
if (fc > 65535L) {
fc = 65535;
- snd_printk(KERN_ERR "patch: (2) fc frequency overflow - %u\n", fc);
+ pr_err("patch: (2) fc frequency overflow - %u\n", fc);
}
return (unsigned short) fc;
}
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 09cc53ceea2a..101202acefb3 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -115,7 +115,7 @@ static int snd_gusclassic_detect(struct snd_gus_card *gus)
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 0) {
- snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
return -ENODEV;
}
udelay(160);
@@ -123,7 +123,7 @@ static int snd_gusclassic_detect(struct snd_gus_card *gus)
udelay(160);
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 1) {
- snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
return -ENODEV;
}
return 0;
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 63d9f2d75df0..ed921b89b00a 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -145,7 +145,6 @@ static int snd_gusextreme_gus_card_create(struct snd_card *card,
static int snd_gusextreme_detect(struct snd_gus_card *gus,
struct snd_es1688 *es1688)
{
- unsigned long flags;
unsigned char d;
/*
@@ -162,24 +161,24 @@ static int snd_gusextreme_detect(struct snd_gus_card *gus,
* 0x260 = 2,2,1
*/
- spin_lock_irqsave(&es1688->mixer_lock, flags);
- snd_es1688_mixer_write(es1688, 0x40, 0x0b); /* don't change!!! */
- spin_unlock_irqrestore(&es1688->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &es1688->mixer_lock) {
+ snd_es1688_mixer_write(es1688, 0x40, 0x0b); /* don't change!!! */
+ }
- spin_lock_irqsave(&es1688->reg_lock, flags);
- outb(gus->gf1.port & 0x040 ? 2 : 0, ES1688P(es1688, INIT1));
- outb(0, 0x201);
- outb(gus->gf1.port & 0x020 ? 2 : 0, ES1688P(es1688, INIT1));
- outb(0, 0x201);
- outb(gus->gf1.port & 0x010 ? 3 : 1, ES1688P(es1688, INIT1));
- spin_unlock_irqrestore(&es1688->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &es1688->reg_lock) {
+ outb(gus->gf1.port & 0x040 ? 2 : 0, ES1688P(es1688, INIT1));
+ outb(0, 0x201);
+ outb(gus->gf1.port & 0x020 ? 2 : 0, ES1688P(es1688, INIT1));
+ outb(0, 0x201);
+ outb(gus->gf1.port & 0x010 ? 3 : 1, ES1688P(es1688, INIT1));
+ }
udelay(100);
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 0) {
- snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
return -EIO;
}
udelay(160);
@@ -187,7 +186,7 @@ static int snd_gusextreme_detect(struct snd_gus_card *gus,
udelay(160);
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 1) {
- snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
return -EIO;
}
@@ -204,15 +203,15 @@ static int snd_gusextreme_mixer(struct snd_card *card)
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* reassign AUX to SYNTHESIZER */
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "Synth Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "Synth Playback Volume");
error = snd_ctl_rename_id(card, &id1, &id2);
if (error < 0)
return error;
/* reassign Master Playback Switch to Synth Playback Switch */
- strcpy(id1.name, "Master Playback Switch");
- strcpy(id2.name, "Synth Playback Switch");
+ strscpy(id1.name, "Master Playback Switch");
+ strscpy(id2.name, "Synth Playback Switch");
error = snd_ctl_rename_id(card, &id1, &id2);
if (error < 0)
return error;
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index 6834c0560064..b572411c4422 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -64,8 +64,6 @@ struct snd_gusmax {
unsigned short pcm_status_reg;
};
-#define PFX "gusmax: "
-
static int snd_gusmax_detect(struct snd_gus_card *gus)
{
unsigned char d;
@@ -73,7 +71,7 @@ static int snd_gusmax_detect(struct snd_gus_card *gus)
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 0) {
- snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
return -ENODEV;
}
udelay(160);
@@ -81,7 +79,7 @@ static int snd_gusmax_detect(struct snd_gus_card *gus)
udelay(160);
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 1) {
- snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
return -ENODEV;
}
@@ -136,24 +134,24 @@ static int snd_gusmax_mixer(struct snd_wss *chip)
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* reassign AUXA to SYNTHESIZER */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "Synth Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
+ strscpy(id2.name, "Synth Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "Synth Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "Synth Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
/* reassign AUXB to CD */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "CD Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strscpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "CD Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "CD Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
@@ -206,7 +204,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
if (xirq < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
+ dev_err(pdev, "unable to find a free IRQ\n");
return -EBUSY;
}
}
@@ -214,7 +212,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (xdma1 == SNDRV_AUTO_DMA) {
xdma1 = snd_legacy_find_free_dma(possible_dmas);
if (xdma1 < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA1\n");
+ dev_err(pdev, "unable to find a free DMA1\n");
return -EBUSY;
}
}
@@ -222,7 +220,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (xdma2 == SNDRV_AUTO_DMA) {
xdma2 = snd_legacy_find_free_dma(possible_dmas);
if (xdma2 < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA2\n");
+ dev_err(pdev, "unable to find a free DMA2\n");
return -EBUSY;
}
}
@@ -267,13 +265,13 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
return err;
if (!gus->max_flag) {
- snd_printk(KERN_ERR PFX "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port);
+ dev_err(pdev, "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port);
return -ENODEV;
}
if (devm_request_irq(card->dev, xirq, snd_gusmax_interrupt, 0,
"GUS MAX", (void *)maxcard)) {
- snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
+ dev_err(pdev, "unable to grab IRQ %d\n", xirq);
return -EBUSY;
}
maxcard->irq = xirq;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index a04a9d3253f8..18adcd35e117 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -52,11 +52,9 @@ static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
static int effect[SNDRV_CARDS];
#ifdef SNDRV_STB
-#define PFX "interwave-stb: "
#define INTERWAVE_DRIVER "snd_interwave_stb"
#define INTERWAVE_PNP_DRIVER "interwave-stb"
#else
-#define PFX "interwave: "
#define INTERWAVE_DRIVER "snd_interwave"
#define INTERWAVE_PNP_DRIVER "interwave"
#endif
@@ -148,7 +146,7 @@ static void snd_interwave_i2c_setlines(struct snd_i2c_bus *bus, int ctrl, int da
unsigned long port = bus->private_value;
#if 0
- printk(KERN_DEBUG "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
+ dev_dbg(bus->card->dev, "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
#endif
outb((data << 1) | ctrl, port);
udelay(10);
@@ -161,7 +159,7 @@ static int snd_interwave_i2c_getclockline(struct snd_i2c_bus *bus)
res = inb(port) & 1;
#if 0
- printk(KERN_DEBUG "i2c_getclockline - 0x%lx -> %i\n", port, res);
+ dev_dbg(bus->card->dev, "i2c_getclockline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -175,7 +173,7 @@ static int snd_interwave_i2c_getdataline(struct snd_i2c_bus *bus, int ack)
udelay(10);
res = (inb(port) & 2) >> 1;
#if 0
- printk(KERN_DEBUG "i2c_getdataline - 0x%lx -> %i\n", port, res);
+ dev_dbg(bus->card->dev, "i2c_getdataline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -215,7 +213,7 @@ static int snd_interwave_detect_stb(struct snd_interwave *iwcard,
"InterWave (I2C bus)");
}
if (iwcard->i2c_res == NULL) {
- snd_printk(KERN_ERR "interwave: can't grab i2c bus port\n");
+ dev_err(card->dev, "interwave: can't grab i2c bus port\n");
return -ENODEV;
}
@@ -241,14 +239,13 @@ static int snd_interwave_detect(struct snd_interwave *iwcard,
#endif
)
{
- unsigned long flags;
unsigned char rev1, rev2;
int d;
snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 0) {
- snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
return -ENODEV;
}
udelay(160);
@@ -256,21 +253,24 @@ static int snd_interwave_detect(struct snd_interwave *iwcard,
udelay(160);
d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
if ((d & 0x07) != 1) {
- snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
+ dev_dbg(gus->card->dev, "[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
return -ENODEV;
}
- spin_lock_irqsave(&gus->reg_lock, flags);
- rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
- snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1);
- rev2 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
- snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, rev1);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
- snd_printdd("[0x%lx] InterWave check - rev1=0x%x, rev2=0x%x\n", gus->gf1.port, rev1, rev2);
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1);
+ rev2 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, rev1);
+ }
+ dev_dbg(gus->card->dev,
+ "[0x%lx] InterWave check - rev1=0x%x, rev2=0x%x\n",
+ gus->gf1.port, rev1, rev2);
if ((rev1 & 0xf0) == (rev2 & 0xf0) &&
(rev1 & 0x0f) != (rev2 & 0x0f)) {
- snd_printdd("[0x%lx] InterWave check - passed\n", gus->gf1.port);
+ dev_dbg(gus->card->dev,
+ "[0x%lx] InterWave check - passed\n", gus->gf1.port);
gus->interwave = 1;
- strcpy(gus->card->shortname, "AMD InterWave");
+ strscpy(gus->card->shortname, "AMD InterWave");
gus->revision = rev1 >> 4;
#ifndef SNDRV_STB
return 0; /* ok.. We have an InterWave board */
@@ -278,7 +278,7 @@ static int snd_interwave_detect(struct snd_interwave *iwcard,
return snd_interwave_detect_stb(iwcard, gus, dev, rbus);
#endif
}
- snd_printdd("[0x%lx] InterWave check - failed\n", gus->gf1.port);
+ dev_dbg(gus->card->dev, "[0x%lx] InterWave check - failed\n", gus->gf1.port);
return -ENODEV;
}
@@ -327,7 +327,7 @@ static void snd_interwave_bank_sizes(struct snd_gus_card *gus, int *sizes)
snd_gf1_poke(gus, local, d);
snd_gf1_poke(gus, local + 1, d + 1);
#if 0
- printk(KERN_DEBUG "d = 0x%x, local = 0x%x, "
+ dev_dbg(gus->card->dev, "d = 0x%x, local = 0x%x, "
"local + 1 = 0x%x, idx << 22 = 0x%x\n",
d,
snd_gf1_peek(gus, local),
@@ -342,7 +342,7 @@ static void snd_interwave_bank_sizes(struct snd_gus_card *gus, int *sizes)
}
}
#if 0
- printk(KERN_DEBUG "sizes: %i %i %i %i\n",
+ dev_dbg(gus->card->dev, "sizes: %i %i %i %i\n",
sizes[0], sizes[1], sizes[2], sizes[3]);
#endif
}
@@ -397,12 +397,12 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus)
lmct = (psizes[3] << 24) | (psizes[2] << 16) |
(psizes[1] << 8) | psizes[0];
#if 0
- printk(KERN_DEBUG "lmct = 0x%08x\n", lmct);
+ dev_dbg(gus->card->dev, "lmct = 0x%08x\n", lmct);
#endif
for (i = 0; i < ARRAY_SIZE(lmc); i++)
if (lmct == lmc[i]) {
#if 0
- printk(KERN_DEBUG "found !!! %i\n", i);
+ dev_dbg(gus->card->dev, "found !!! %i\n", i);
#endif
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
snd_interwave_bank_sizes(gus, psizes);
@@ -456,18 +456,16 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus)
static void snd_interwave_init(int dev, struct snd_gus_card *gus)
{
- unsigned long flags;
-
/* ok.. some InterWave specific initialization */
- spin_lock_irqsave(&gus->reg_lock, flags);
- snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00);
- snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f);
- snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49);
- snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11);
- snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00);
- snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30);
- snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00);
- spin_unlock_irqrestore(&gus->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00);
+ }
gus->equal_irq = 1;
gus->codec_flag = 1;
gus->interwave = 1;
@@ -499,11 +497,11 @@ static int snd_interwave_mixer(struct snd_wss *chip)
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
#if 0
/* remove mono microphone controls */
- strcpy(id1.name, "Mic Playback Switch");
+ strscpy(id1.name, "Mic Playback Switch");
err = snd_ctl_remove_id(card, &id1);
if (err < 0)
return err;
- strcpy(id1.name, "Mic Playback Volume");
+ strscpy(id1.name, "Mic Playback Volume");
err = snd_ctl_remove_id(card, &id1);
if (err < 0)
return err;
@@ -519,24 +517,24 @@ static int snd_interwave_mixer(struct snd_wss *chip)
snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f);
snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f);
/* reassign AUXA to SYNTHESIZER */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "Synth Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
+ strscpy(id2.name, "Synth Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "Synth Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "Synth Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
/* reassign AUXB to CD */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "CD Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strscpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "CD Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "CD Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
@@ -566,12 +564,12 @@ static int snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n");
+ dev_err(&pdev->dev, "InterWave PnP configure failure (out of resources?)\n");
return err;
}
if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) ||
pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) {
- snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n");
+ dev_err(&pdev->dev, "PnP configure failure (wrong ports)\n");
return -ENOENT;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -579,22 +577,26 @@ static int snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
if (dma2[dev] >= 0)
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("isapnp IW: sb port=0x%llx, gf1 port=0x%llx, codec port=0x%llx\n",
- (unsigned long long)pnp_port_start(pdev, 0),
- (unsigned long long)pnp_port_start(pdev, 1),
- (unsigned long long)pnp_port_start(pdev, 2));
- snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]);
+ dev_dbg(&pdev->dev,
+ "isapnp IW: sb port=0x%llx, gf1 port=0x%llx, codec port=0x%llx\n",
+ (unsigned long long)pnp_port_start(pdev, 0),
+ (unsigned long long)pnp_port_start(pdev, 1),
+ (unsigned long long)pnp_port_start(pdev, 2));
+ dev_dbg(&pdev->dev,
+ "isapnp IW: dma1=%i, dma2=%i, irq=%i\n",
+ dma1[dev], dma2[dev], irq[dev]);
#ifdef SNDRV_STB
/* Tone Control initialization */
pdev = iwcard->devtc;
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n");
+ dev_err(&pdev->dev,
+ "InterWave ToneControl PnP configure failure (out of resources?)\n");
return err;
}
port_tc[dev] = pnp_port_start(pdev, 0);
- snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]);
+ dev_dbg(&pdev->dev, "isapnp IW: tone control port=0x%lx\n", port_tc[dev]);
#endif
return 0;
}
@@ -660,7 +662,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev,
if (devm_request_irq(card->dev, xirq, snd_interwave_interrupt, 0,
"InterWave", iwcard)) {
- snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", xirq);
return -EBUSY;
}
iwcard->irq = xirq;
@@ -708,14 +710,14 @@ static int snd_interwave_probe(struct snd_card *card, int dev,
memset(&id1, 0, sizeof(id1));
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id1.name, "Master Playback Switch");
- strcpy(id2.name, id1.name);
+ strscpy(id1.name, "Master Playback Switch");
+ strscpy(id2.name, id1.name);
id2.index = 1;
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Master Playback Volume");
- strcpy(id2.name, id1.name);
+ strscpy(id1.name, "Master Playback Volume");
+ strscpy(id2.name, id1.name);
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
@@ -737,8 +739,8 @@ static int snd_interwave_probe(struct snd_card *card, int dev,
#else
str = "InterWave STB";
#endif
- strcpy(card->driver, str);
- strcpy(card->shortname, str);
+ strscpy(card->driver, str);
+ strscpy(card->shortname, str);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %d",
str,
gus->gf1.port,
@@ -780,21 +782,21 @@ static int snd_interwave_isa_probe(struct device *pdev,
if (irq[dev] == SNDRV_AUTO_IRQ) {
irq[dev] = snd_legacy_find_free_irq(possible_irqs);
if (irq[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
+ dev_err(pdev, "unable to find a free IRQ\n");
return -EBUSY;
}
}
if (dma1[dev] == SNDRV_AUTO_DMA) {
dma1[dev] = snd_legacy_find_free_dma(possible_dmas);
if (dma1[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA1\n");
+ dev_err(pdev, "unable to find a free DMA1\n");
return -EBUSY;
}
}
if (dma2[dev] == SNDRV_AUTO_DMA) {
dma2[dev] = snd_legacy_find_free_dma(possible_dmas);
if (dma2[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA2\n");
+ dev_err(pdev, "unable to find a free DMA2\n");
return -EBUSY;
}
}
diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
index ec231a7b1d5e..d56412aae857 100644
--- a/sound/isa/msnd/Makefile
+++ b/sound/isa/msnd/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
-snd-msnd-lib-objs := msnd.o msnd_midi.o msnd_pinnacle_mixer.o
-snd-msnd-pinnacle-objs := msnd_pinnacle.o
-snd-msnd-classic-objs := msnd_classic.o
+snd-msnd-lib-y := msnd.o msnd_pinnacle_mixer.o
+snd-msnd-pinnacle-y := msnd_pinnacle.o
+snd-msnd-classic-y := msnd_classic.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o snd-msnd-lib.o
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
index c3fd1eb301bb..5e350234d572 100644
--- a/sound/isa/msnd/msnd.c
+++ b/sound/isa/msnd/msnd.c
@@ -76,17 +76,13 @@ static int snd_msnd_wait_HC0(struct snd_msnd *dev)
int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
+ guard(spinlock_irqsave)(&dev->lock);
if (snd_msnd_wait_HC0(dev) == 0) {
outb(cmd, dev->io + HP_CVR);
- spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
- spin_unlock_irqrestore(&dev->lock, flags);
- snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
+ dev_dbg(dev->card->dev, LOGNAME ": Send DSP command timeout\n");
return -EIO;
}
@@ -104,7 +100,7 @@ int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
return 0;
}
- snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
+ dev_dbg(dev->card->dev, LOGNAME ": Send host word timeout\n");
return -EIO;
}
@@ -115,7 +111,7 @@ int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
int i;
if (len % 3 != 0) {
- snd_printk(KERN_ERR LOGNAME
+ dev_err(dev->card->dev, LOGNAME
": Upload host data not multiple of 3!\n");
return -EINVAL;
}
@@ -133,14 +129,12 @@ EXPORT_SYMBOL(snd_msnd_upload_host);
int snd_msnd_enable_irq(struct snd_msnd *dev)
{
- unsigned long flags;
-
if (dev->irq_ref++)
return 0;
- snd_printdd(LOGNAME ": Enabling IRQ\n");
+ dev_dbg(dev->card->dev, LOGNAME ": Enabling IRQ\n");
- spin_lock_irqsave(&dev->lock, flags);
+ guard(spinlock_irqsave)(&dev->lock);
if (snd_msnd_wait_TXDE(dev) == 0) {
outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
if (dev->type == msndClassic)
@@ -151,12 +145,10 @@ int snd_msnd_enable_irq(struct snd_msnd *dev)
enable_irq(dev->irq);
snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
dev->dspq_buff_size);
- spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
- spin_unlock_irqrestore(&dev->lock, flags);
- snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
+ dev_dbg(dev->card->dev, LOGNAME ": Enable IRQ failed\n");
return -EIO;
}
@@ -164,29 +156,25 @@ EXPORT_SYMBOL(snd_msnd_enable_irq);
int snd_msnd_disable_irq(struct snd_msnd *dev)
{
- unsigned long flags;
-
if (--dev->irq_ref > 0)
return 0;
if (dev->irq_ref < 0)
- snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
- dev->irq_ref);
+ dev_dbg(dev->card->dev, LOGNAME ": IRQ ref count is %d\n",
+ dev->irq_ref);
- snd_printdd(LOGNAME ": Disabling IRQ\n");
+ dev_dbg(dev->card->dev, LOGNAME ": Disabling IRQ\n");
- spin_lock_irqsave(&dev->lock, flags);
+ guard(spinlock_irqsave)(&dev->lock);
if (snd_msnd_wait_TXDE(dev) == 0) {
outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
if (dev->type == msndClassic)
outb(HPIRQ_NONE, dev->io + HP_IRQM);
disable_irq(dev->irq);
- spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
- spin_unlock_irqrestore(&dev->lock, flags);
- snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
+ dev_dbg(dev->card->dev, LOGNAME ": Disable IRQ failed\n");
return -EIO;
}
@@ -220,8 +208,8 @@ void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
snd_msnd_disable_irq(chip);
if (file) {
- snd_printd(KERN_INFO LOGNAME
- ": Stopping read for %p\n", file);
+ dev_dbg(chip->card->dev, LOGNAME
+ ": Stopping read for %p\n", file);
chip->mode &= ~FMODE_READ;
}
clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
@@ -233,8 +221,8 @@ void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
}
snd_msnd_disable_irq(chip);
if (file) {
- snd_printd(KERN_INFO
- LOGNAME ": Stopping write for %p\n", file);
+ dev_dbg(chip->card->dev,
+ LOGNAME ": Stopping write for %p\n", file);
chip->mode &= ~FMODE_WRITE;
}
clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
@@ -329,12 +317,6 @@ int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
++nbanks;
/* Then advance the tail */
- /*
- if (protect)
- snd_printd(KERN_INFO "B %X %lX\n",
- bank_num, xtime.tv_usec);
- */
-
DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
/* Tell the DSP to play the bank */
@@ -343,10 +325,6 @@ int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
if (2 == bank_num)
break;
}
- /*
- if (protect)
- snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
- */
/* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
return nbanks;
}
@@ -386,7 +364,6 @@ static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
{
int n;
void __iomem *pDAQ;
- /* unsigned long flags; */
/* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
@@ -398,15 +375,15 @@ static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
chip->DARQ + JQS_wTail);
#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
- spin_lock_irqsave(&chip->lock, flags);
- outb(HPBLKSEL_1, chip->io + HP_BLKS);
- memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
- outb(HPBLKSEL_0, chip->io + HP_BLKS);
- spin_unlock_irqrestore(&chip->lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->lock) {
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ }
#endif
chip->capturePeriodBytes = pcm_count;
- snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
+ dev_dbg(chip->card->dev, "%s() %i\n", __func__, pcm_count);
pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
@@ -533,21 +510,21 @@ static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
int result = 0;
if (cmd == SNDRV_PCM_TRIGGER_START) {
- snd_printdd("snd_msnd_playback_trigger(START)\n");
+ dev_dbg(chip->card->dev, "%s(START)\n", __func__);
chip->banksPlayed = 0;
set_bit(F_WRITING, &chip->flags);
snd_msnd_DAPQ(chip, 1);
} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- snd_printdd("snd_msnd_playback_trigger(STop)\n");
+ dev_dbg(chip->card->dev, "%s(STOP)\n", __func__);
/* interrupt diagnostic, comment this out later */
clear_bit(F_WRITING, &chip->flags);
snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
} else {
- snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
+ dev_dbg(chip->card->dev, "%s(?????)\n", __func__);
result = -EINVAL;
}
- snd_printdd("snd_msnd_playback_trigger() ENDE\n");
+ dev_dbg(chip->card->dev, "%s() ENDE\n", __func__);
return result;
}
@@ -683,7 +660,7 @@ int snd_msnd_pcm(struct snd_card *card, int device)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
pcm->private_data = chip;
- strcpy(pcm->name, "Hurricane");
+ strscpy(pcm->name, "Hurricane");
return 0;
}
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
index 533d71cee9ba..3d7810ed9186 100644
--- a/sound/isa/msnd/msnd.h
+++ b/sound/isa/msnd/msnd.h
@@ -216,7 +216,6 @@ struct snd_msnd {
int captureLimit;
int capturePeriods;
struct snd_card *card;
- void *msndmidi_mpu;
struct snd_rawmidi *rmidi;
/* Hardware resources */
@@ -286,9 +285,6 @@ int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
int snd_msnd_DARQ(struct snd_msnd *chip, int start);
int snd_msnd_pcm(struct snd_card *card, int device);
-int snd_msndmidi_new(struct snd_card *card, int device);
-void snd_msndmidi_input_read(void *mpu);
-
void snd_msndmix_setup(struct snd_msnd *chip);
int snd_msndmix_new(struct snd_card *card);
int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc);
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
deleted file mode 100644
index 7c61caaf99ad..000000000000
--- a/sound/isa/msnd/msnd_midi.c
+++ /dev/null
@@ -1,167 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- * Copyright (c) 2009 by Krzysztof Helt
- * Routines for control of MPU-401 in UART mode
- *
- * MPU-401 supports UART mode which is not capable generate transmit
- * interrupts thus output is done via polling. Also, if irq < 0, then
- * input is done also via polling. Do not expect good performance.
- */
-
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <linux/export.h>
-#include <sound/core.h>
-#include <sound/rawmidi.h>
-
-#include "msnd.h"
-
-#define MSNDMIDI_MODE_BIT_INPUT 0
-#define MSNDMIDI_MODE_BIT_OUTPUT 1
-#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2
-#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER 3
-
-struct snd_msndmidi {
- struct snd_msnd *dev;
-
- unsigned long mode; /* MSNDMIDI_MODE_XXXX */
-
- struct snd_rawmidi_substream *substream_input;
-
- spinlock_t input_lock;
-};
-
-/*
- * input/output open/close - protected by open_mutex in rawmidi.c
- */
-static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
-{
- struct snd_msndmidi *mpu;
-
- snd_printdd("snd_msndmidi_input_open()\n");
-
- mpu = substream->rmidi->private_data;
-
- mpu->substream_input = substream;
-
- snd_msnd_enable_irq(mpu->dev);
-
- snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
- set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
- return 0;
-}
-
-static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
-{
- struct snd_msndmidi *mpu;
-
- mpu = substream->rmidi->private_data;
- snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
- clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
- mpu->substream_input = NULL;
- snd_msnd_disable_irq(mpu->dev);
- return 0;
-}
-
-static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
-{
- u16 tail;
-
- tail = readw(mpu->dev->MIDQ + JQS_wTail);
- writew(tail, mpu->dev->MIDQ + JQS_wHead);
-}
-
-/*
- * trigger input
- */
-static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream,
- int up)
-{
- unsigned long flags;
- struct snd_msndmidi *mpu;
-
- snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
-
- mpu = substream->rmidi->private_data;
- spin_lock_irqsave(&mpu->input_lock, flags);
- if (up) {
- if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
- &mpu->mode))
- snd_msndmidi_input_drop(mpu);
- } else {
- clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
- }
- spin_unlock_irqrestore(&mpu->input_lock, flags);
- if (up)
- snd_msndmidi_input_read(mpu);
-}
-
-void snd_msndmidi_input_read(void *mpuv)
-{
- unsigned long flags;
- struct snd_msndmidi *mpu = mpuv;
- void __iomem *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
- u16 head, tail, size;
-
- spin_lock_irqsave(&mpu->input_lock, flags);
- head = readw(mpu->dev->MIDQ + JQS_wHead);
- tail = readw(mpu->dev->MIDQ + JQS_wTail);
- size = readw(mpu->dev->MIDQ + JQS_wSize);
- if (head > size || tail > size)
- goto out;
- while (head != tail) {
- unsigned char val = readw(pwMIDQData + 2 * head);
-
- if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
- snd_rawmidi_receive(mpu->substream_input, &val, 1);
- if (++head > size)
- head = 0;
- writew(head, mpu->dev->MIDQ + JQS_wHead);
- }
- out:
- spin_unlock_irqrestore(&mpu->input_lock, flags);
-}
-EXPORT_SYMBOL(snd_msndmidi_input_read);
-
-static const struct snd_rawmidi_ops snd_msndmidi_input = {
- .open = snd_msndmidi_input_open,
- .close = snd_msndmidi_input_close,
- .trigger = snd_msndmidi_input_trigger,
-};
-
-static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
-{
- struct snd_msndmidi *mpu = rmidi->private_data;
- kfree(mpu);
-}
-
-int snd_msndmidi_new(struct snd_card *card, int device)
-{
- struct snd_msnd *chip = card->private_data;
- struct snd_msndmidi *mpu;
- struct snd_rawmidi *rmidi;
- int err;
-
- err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
- if (err < 0)
- return err;
- mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
- if (mpu == NULL) {
- snd_device_free(card, rmidi);
- return -ENOMEM;
- }
- mpu->dev = chip;
- chip->msndmidi_mpu = mpu;
- rmidi->private_data = mpu;
- rmidi->private_free = snd_msndmidi_free;
- spin_lock_init(&mpu->input_lock);
- strcpy(rmidi->name, "MSND MIDI");
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &snd_msndmidi_input);
- rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
- return 0;
-}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 4433a92f08e7..c4eec391cd29 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -81,11 +81,12 @@ static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
switch (HIBYTE(wMessage)) {
case HIMT_PLAY_DONE: {
if (chip->banksPlayed < 3)
- snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
+ dev_dbg(chip->card->dev, "%08X: HIMT_PLAY_DONE: %i\n",
(unsigned)jiffies, LOBYTE(wMessage));
if (chip->last_playbank == LOBYTE(wMessage)) {
- snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
+ dev_dbg(chip->card->dev,
+ "chip.last_playbank == LOBYTE(wMessage)\n");
break;
}
chip->banksPlayed++;
@@ -121,33 +122,29 @@ static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
case HIDSP_PLAY_UNDER:
#endif
case HIDSP_INT_PLAY_UNDER:
- snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
+ dev_dbg(chip->card->dev,
+ LOGNAME ": Play underflow %i\n",
chip->banksPlayed);
if (chip->banksPlayed > 2)
clear_bit(F_WRITING, &chip->flags);
break;
case HIDSP_INT_RECORD_OVER:
- snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
+ dev_dbg(chip->card->dev, LOGNAME ": Record overflow\n");
clear_bit(F_READING, &chip->flags);
break;
default:
- snd_printd(KERN_WARNING LOGNAME
- ": DSP message %d 0x%02x\n",
- LOBYTE(wMessage), LOBYTE(wMessage));
+ dev_dbg(chip->card->dev, LOGNAME
+ ": DSP message %d 0x%02x\n",
+ LOBYTE(wMessage), LOBYTE(wMessage));
break;
}
break;
- case HIMT_MIDI_IN_UCHAR:
- if (chip->msndmidi_mpu)
- snd_msndmidi_input_read(chip->msndmidi_mpu);
- break;
-
default:
- snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
- HIBYTE(wMessage), HIBYTE(wMessage));
+ dev_dbg(chip->card->dev, LOGNAME ": HIMT message %d 0x%02x\n",
+ HIBYTE(wMessage), HIBYTE(wMessage));
break;
}
}
@@ -180,8 +177,9 @@ static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
}
-static int snd_msnd_reset_dsp(long io, unsigned char *info)
+static int snd_msnd_reset_dsp(struct snd_msnd *chip, unsigned char *info)
{
+ long io = chip->io;
int timeout = 100;
outb(HPDSPRESET_ON, io + HP_DSPR);
@@ -197,7 +195,7 @@ static int snd_msnd_reset_dsp(long io, unsigned char *info)
return 0;
msleep(1);
}
- snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+ dev_err(chip->card->dev, LOGNAME ": Cannot reset DSP\n");
return -EIO;
}
@@ -213,19 +211,19 @@ static int snd_msnd_probe(struct snd_card *card)
#endif
if (!request_region(chip->io, DSP_NUMIO, "probing")) {
- snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+ dev_err(card->dev, LOGNAME ": I/O port conflict\n");
return -ENODEV;
}
- if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
+ if (snd_msnd_reset_dsp(chip, &info) < 0) {
release_region(chip->io, DSP_NUMIO);
return -ENODEV;
}
#ifdef MSND_CLASSIC
- strcpy(card->shortname, "Classic/Tahiti/Monterey");
- strcpy(card->longname, "Turtle Beach Multisound");
- printk(KERN_INFO LOGNAME ": %s, "
+ strscpy(card->shortname, "Classic/Tahiti/Monterey");
+ strscpy(card->longname, "Turtle Beach Multisound");
+ dev_info(card->dev, LOGNAME ": %s, "
"I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
card->shortname,
chip->io, chip->io + DSP_NUMIO - 1,
@@ -253,39 +251,39 @@ static int snd_msnd_probe(struct snd_card *card)
switch (info & 0x7) {
case 0x0:
rev = "I";
- strcpy(card->shortname, pin);
+ strscpy(card->shortname, pin);
break;
case 0x1:
rev = "F";
- strcpy(card->shortname, pin);
+ strscpy(card->shortname, pin);
break;
case 0x2:
rev = "G";
- strcpy(card->shortname, pin);
+ strscpy(card->shortname, pin);
break;
case 0x3:
rev = "H";
- strcpy(card->shortname, pin);
+ strscpy(card->shortname, pin);
break;
case 0x4:
rev = "E";
- strcpy(card->shortname, fiji);
+ strscpy(card->shortname, fiji);
break;
case 0x5:
rev = "C";
- strcpy(card->shortname, fiji);
+ strscpy(card->shortname, fiji);
break;
case 0x6:
rev = "D";
- strcpy(card->shortname, fiji);
+ strscpy(card->shortname, fiji);
break;
case 0x7:
rev = "A-B (Fiji) or A-E (Pinnacle)";
- strcpy(card->shortname, pinfiji);
+ strscpy(card->shortname, pinfiji);
break;
}
- strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
- printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
+ strscpy(card->longname, "Turtle Beach Multisound Pinnacle");
+ dev_info(card->dev, LOGNAME ": %s revision %s, Xilinx version %s, "
"I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
card->shortname,
rev, xv,
@@ -302,7 +300,6 @@ static int snd_msnd_init_sma(struct snd_msnd *chip)
{
static int initted;
u16 mastVolLeft, mastVolRight;
- unsigned long flags;
#ifdef MSND_CLASSIC
outb(chip->memid, chip->io + HP_MEMM);
@@ -319,11 +316,11 @@ static int snd_msnd_init_sma(struct snd_msnd *chip)
memset_io(chip->mappedbase, 0, 0x8000);
/* Critical section: bank 1 access */
- spin_lock_irqsave(&chip->lock, flags);
- outb(HPBLKSEL_1, chip->io + HP_BLKS);
- memset_io(chip->mappedbase, 0, 0x8000);
- outb(HPBLKSEL_0, chip->io + HP_BLKS);
- spin_unlock_irqrestore(&chip->lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->lock) {
+ outb(HPBLKSEL_1, chip->io + HP_BLKS);
+ memset_io(chip->mappedbase, 0, 0x8000);
+ outb(HPBLKSEL_0, chip->io + HP_BLKS);
+ }
/* Digital audio play queue */
chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
@@ -377,22 +374,22 @@ static int upload_dsp_code(struct snd_card *card)
err = request_firmware(&init_fw, INITCODEFILE, card->dev);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+ dev_err(card->dev, LOGNAME ": Error loading " INITCODEFILE);
goto cleanup1;
}
err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+ dev_err(card->dev, LOGNAME ": Error loading " PERMCODEFILE);
goto cleanup;
}
memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
- printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ dev_warn(card->dev, LOGNAME ": Error uploading to DSP\n");
err = -ENODEV;
goto cleanup;
}
- printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
+ dev_info(card->dev, LOGNAME ": DSP firmware uploaded\n");
err = 0;
cleanup:
@@ -425,17 +422,17 @@ static int snd_msnd_initialize(struct snd_card *card)
#endif
err = snd_msnd_init_sma(chip);
if (err < 0) {
- printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+ dev_warn(card->dev, LOGNAME ": Cannot initialize SMA\n");
return err;
}
- err = snd_msnd_reset_dsp(chip->io, NULL);
+ err = snd_msnd_reset_dsp(chip, NULL);
if (err < 0)
return err;
err = upload_dsp_code(card);
if (err < 0) {
- printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+ dev_warn(card->dev, LOGNAME ": Cannot upload DSP code\n");
return err;
}
@@ -444,7 +441,7 @@ static int snd_msnd_initialize(struct snd_card *card)
while (readw(chip->mappedbase)) {
msleep(1);
if (!timeout--) {
- snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
+ dev_err(card->dev, LOGNAME ": DSP reset timeout\n");
return -EIO;
}
}
@@ -466,7 +463,7 @@ static int snd_msnd_dsp_full_reset(struct snd_card *card)
rv = snd_msnd_initialize(card);
if (rv)
- printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+ dev_warn(card->dev, LOGNAME ": DSP reset failed\n");
snd_msndmix_force_recsrc(chip, 0);
clear_bit(F_RESETTING, &chip->flags);
return rv;
@@ -483,7 +480,7 @@ static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
{
- snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
+ dev_dbg(chip->card->dev, "snd_msnd_calibrate_adc(%i)\n", srate);
writew(srate, chip->SMA + SMA_wCalFreqAtoD);
if (chip->calibrate_signal == 0)
writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
@@ -496,7 +493,7 @@ static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
schedule_timeout_interruptible(msecs_to_jiffies(333));
return 0;
}
- printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
+ dev_warn(chip->card->dev, LOGNAME ": ADC calibration failed\n");
return -EIO;
}
@@ -527,7 +524,7 @@ static int snd_msnd_attach(struct snd_card *card)
err = devm_request_irq(card->dev, chip->irq, snd_msnd_interrupt, 0,
card->shortname, chip);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
+ dev_err(card->dev, LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
return err;
}
card->sync_irq = chip->irq;
@@ -537,14 +534,14 @@ static int snd_msnd_attach(struct snd_card *card)
if (!devm_request_mem_region(card->dev, chip->base, BUFFSIZE,
card->shortname)) {
- printk(KERN_ERR LOGNAME
+ dev_err(card->dev, LOGNAME
": unable to grab memory region 0x%lx-0x%lx\n",
chip->base, chip->base + BUFFSIZE - 1);
return -EBUSY;
}
chip->mappedbase = devm_ioremap(card->dev, chip->base, 0x8000);
if (!chip->mappedbase) {
- printk(KERN_ERR LOGNAME
+ dev_err(card->dev, LOGNAME
": unable to map memory region 0x%lx-0x%lx\n",
chip->base, chip->base + BUFFSIZE - 1);
return -EIO;
@@ -556,13 +553,13 @@ static int snd_msnd_attach(struct snd_card *card)
err = snd_msnd_pcm(card, 0);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
+ dev_err(card->dev, LOGNAME ": error creating new PCM device\n");
return err;
}
err = snd_msndmix_new(card);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
+ dev_err(card->dev, LOGNAME ": error creating new Mixer device\n");
return err;
}
@@ -577,7 +574,7 @@ static int snd_msnd_attach(struct snd_card *card)
mpu_irq[0],
&chip->rmidi);
if (err < 0) {
- printk(KERN_ERR LOGNAME
+ dev_err(card->dev, LOGNAME
": error creating new Midi device\n");
return err;
}
@@ -604,103 +601,104 @@ static int snd_msnd_attach(struct snd_card *card)
/* Pinnacle/Fiji Logical Device Configuration */
-static int snd_msnd_write_cfg(int cfg, int reg, int value)
+static int snd_msnd_write_cfg(struct snd_msnd *chip, int cfg, int reg, int value)
{
outb(reg, cfg);
outb(value, cfg + 1);
if (value != inb(cfg + 1)) {
- printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
+ dev_err(chip->card->dev, LOGNAME ": %s: I/O error\n", __func__);
return -EIO;
}
return 0;
}
-static int snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
+static int snd_msnd_write_cfg_io0(struct snd_msnd *chip, int cfg, int num, u16 io)
{
- if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_IO0_BASEHI, HIBYTE(io)))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_IO0_BASELO, LOBYTE(io)))
return -EIO;
return 0;
}
-static int snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
+static int snd_msnd_write_cfg_io1(struct snd_msnd *chip, int cfg, int num, u16 io)
{
- if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_IO1_BASEHI, HIBYTE(io)))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_IO1_BASELO, LOBYTE(io)))
return -EIO;
return 0;
}
-static int snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
+static int snd_msnd_write_cfg_irq(struct snd_msnd *chip, int cfg, int num, u16 irq)
{
- if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
return -EIO;
return 0;
}
-static int snd_msnd_write_cfg_mem(int cfg, int num, int mem)
+static int snd_msnd_write_cfg_mem(struct snd_msnd *chip, int cfg, int num, int mem)
{
u16 wmem;
mem >>= 8;
wmem = (u16)(mem & 0xfff);
- if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_MEMBASELO, LOBYTE(wmem)))
return -EIO;
- if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
+ if (wmem && snd_msnd_write_cfg(chip, cfg, IREG_MEMCONTROL,
MEMTYPE_HIADDR | MEMTYPE_16BIT))
return -EIO;
return 0;
}
-static int snd_msnd_activate_logical(int cfg, int num)
+static int snd_msnd_activate_logical(struct snd_msnd *chip, int cfg, int num)
{
- if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))
return -EIO;
- if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_ACTIVATE, LD_ACTIVATE))
return -EIO;
return 0;
}
-static int snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
+static int snd_msnd_write_cfg_logical(struct snd_msnd *chip,
+ int cfg, int num, u16 io0,
u16 io1, u16 irq, int mem)
{
- if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+ if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))
return -EIO;
- if (snd_msnd_write_cfg_io0(cfg, num, io0))
+ if (snd_msnd_write_cfg_io0(chip, cfg, num, io0))
return -EIO;
- if (snd_msnd_write_cfg_io1(cfg, num, io1))
+ if (snd_msnd_write_cfg_io1(chip, cfg, num, io1))
return -EIO;
- if (snd_msnd_write_cfg_irq(cfg, num, irq))
+ if (snd_msnd_write_cfg_irq(chip, cfg, num, irq))
return -EIO;
- if (snd_msnd_write_cfg_mem(cfg, num, mem))
+ if (snd_msnd_write_cfg_mem(chip, cfg, num, mem))
return -EIO;
- if (snd_msnd_activate_logical(cfg, num))
+ if (snd_msnd_activate_logical(chip, cfg, num))
return -EIO;
return 0;
}
-static int snd_msnd_pinnacle_cfg_reset(int cfg)
+static int snd_msnd_pinnacle_cfg_reset(struct snd_msnd *chip, int cfg)
{
int i;
/* Reset devices if told to */
- printk(KERN_INFO LOGNAME ": Resetting all devices\n");
+ dev_info(chip->card->dev, LOGNAME ": Resetting all devices\n");
for (i = 0; i < 4; ++i)
- if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
+ if (snd_msnd_write_cfg_logical(chip, cfg, i, 0, 0, 0, 0))
return -EIO;
return 0;
@@ -779,7 +777,7 @@ static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
return 0;
if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
- printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+ dev_warn(pdev, LOGNAME ": io, irq and mem must be set\n");
return 0;
}
@@ -792,14 +790,14 @@ static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
io[i] == 0x220 ||
io[i] == 0x210 ||
io[i] == 0x3e0)) {
- printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
+ dev_err(pdev, LOGNAME ": \"io\" - DSP I/O base must be set "
" to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
"or 0x3E0\n");
return 0;
}
#else
if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
- printk(KERN_ERR LOGNAME
+ dev_err(pdev, LOGNAME
": \"io\" - DSP I/O base must within the range 0x100 "
"to 0x3E0 and must be evenly divisible by 0x10\n");
return 0;
@@ -812,7 +810,7 @@ static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
irq[i] == 10 ||
irq[i] == 11 ||
irq[i] == 12)) {
- printk(KERN_ERR LOGNAME
+ dev_err(pdev, LOGNAME
": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
return 0;
}
@@ -823,7 +821,7 @@ static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
mem[i] == 0xd8000 ||
mem[i] == 0xe0000 ||
mem[i] == 0xe8000)) {
- printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+ dev_err(pdev, LOGNAME ": \"mem\" - must be set to "
"0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
"0xe8000\n");
return 0;
@@ -831,9 +829,9 @@ static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
#ifndef MSND_CLASSIC
if (cfg[i] == SNDRV_AUTO_PORT) {
- printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ dev_info(pdev, LOGNAME ": Assuming PnP mode\n");
} else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
- printk(KERN_INFO LOGNAME
+ dev_info(pdev, LOGNAME
": Config port must be 0x250, 0x260 or 0x270 "
"(or unspecified for PnP mode)\n");
return 0;
@@ -854,7 +852,7 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
|| cfg[idx] == SNDRV_AUTO_PORT
#endif
) {
- printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
+ dev_info(pdev, LOGNAME ": Assuming PnP mode\n");
return -ENODEV;
}
@@ -897,21 +895,21 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
chip->memid = HPMEM_E800; break;
}
#else
- printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
- cfg[idx]);
+ dev_info(pdev, LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
+ cfg[idx]);
if (!devm_request_region(card->dev, cfg[idx], 2,
"Pinnacle/Fiji Config")) {
- printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
- cfg[idx]);
+ dev_err(pdev, LOGNAME ": Config port 0x%lx conflict\n",
+ cfg[idx]);
return -EIO;
}
if (reset[idx])
- if (snd_msnd_pinnacle_cfg_reset(cfg[idx]))
+ if (snd_msnd_pinnacle_cfg_reset(chip, cfg[idx]))
return -EIO;
/* DSP */
- err = snd_msnd_write_cfg_logical(cfg[idx], 0,
+ err = snd_msnd_write_cfg_logical(chip, cfg[idx], 0,
io[idx], 0,
irq[idx], mem[idx]);
@@ -923,10 +921,10 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
/* MPU */
if (mpu_io[idx] != SNDRV_AUTO_PORT
&& mpu_irq[idx] != SNDRV_AUTO_IRQ) {
- printk(KERN_INFO LOGNAME
+ dev_info(pdev, LOGNAME
": Configuring MPU to I/O 0x%lx IRQ %d\n",
mpu_io[idx], mpu_irq[idx]);
- err = snd_msnd_write_cfg_logical(cfg[idx], 1,
+ err = snd_msnd_write_cfg_logical(chip, cfg[idx], 1,
mpu_io[idx], 0,
mpu_irq[idx], 0);
@@ -938,10 +936,10 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
if (ide_io0[idx] != SNDRV_AUTO_PORT
&& ide_io1[idx] != SNDRV_AUTO_PORT
&& ide_irq[idx] != SNDRV_AUTO_IRQ) {
- printk(KERN_INFO LOGNAME
+ dev_info(pdev, LOGNAME
": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
ide_io0[idx], ide_io1[idx], ide_irq[idx]);
- err = snd_msnd_write_cfg_logical(cfg[idx], 2,
+ err = snd_msnd_write_cfg_logical(chip, cfg[idx], 2,
ide_io0[idx], ide_io1[idx],
ide_irq[idx], 0);
@@ -951,10 +949,10 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
/* Joystick */
if (joystick_io[idx] != SNDRV_AUTO_PORT) {
- printk(KERN_INFO LOGNAME
+ dev_info(pdev, LOGNAME
": Configuring joystick to I/O 0x%lx\n",
joystick_io[idx]);
- err = snd_msnd_write_cfg_logical(cfg[idx], 3,
+ err = snd_msnd_write_cfg_logical(chip, cfg[idx], 3,
joystick_io[idx], 0,
0, 0);
@@ -989,13 +987,13 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
spin_lock_init(&chip->lock);
err = snd_msnd_probe(card);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": Probe failed\n");
+ dev_err(pdev, LOGNAME ": Probe failed\n");
return err;
}
err = snd_msnd_attach(card);
if (err < 0) {
- printk(KERN_ERR LOGNAME ": Attach failed\n");
+ dev_err(pdev, LOGNAME ": Attach failed\n");
return err;
}
dev_set_drvdata(pdev, card);
@@ -1042,12 +1040,12 @@ static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
return -ENODEV;
if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
- printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
+ dev_info(&pcard->card->dev, "msnd_pinnacle: device is inactive\n");
return -EBUSY;
}
if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
- printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
+ dev_info(&pcard->card->dev, "msnd_pinnacle: MPU device is inactive\n");
return -EBUSY;
}
@@ -1098,13 +1096,13 @@ static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
spin_lock_init(&chip->lock);
ret = snd_msnd_probe(card);
if (ret < 0) {
- printk(KERN_ERR LOGNAME ": Probe failed\n");
+ dev_err(&pcard->card->dev, LOGNAME ": Probe failed\n");
return ret;
}
ret = snd_msnd_attach(card);
if (ret < 0) {
- printk(KERN_ERR LOGNAME ": Attach failed\n");
+ dev_err(&pcard->card->dev, LOGNAME ": Attach failed\n");
return ret;
}
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
index 63633bd41e5b..ec354483b9f8 100644
--- a/sound/isa/msnd/msnd_pinnacle_mixer.c
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -136,14 +136,12 @@ static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
{
struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
int addr = kcontrol->private_value;
- unsigned long flags;
- spin_lock_irqsave(&msnd->mixer_lock, flags);
+ guard(spinlock_irqsave)(&msnd->mixer_lock);
ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
ucontrol->value.integer.value[0] /= 0xFFFF;
ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
ucontrol->value.integer.value[1] /= 0xFFFF;
- spin_unlock_irqrestore(&msnd->mixer_lock, flags);
return 0;
}
@@ -253,15 +251,13 @@ static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
int change, addr = kcontrol->private_value;
int left, right;
- unsigned long flags;
left = ucontrol->value.integer.value[0] % 101;
right = ucontrol->value.integer.value[1] % 101;
- spin_lock_irqsave(&msnd->mixer_lock, flags);
+ guard(spinlock_irqsave)(&msnd->mixer_lock);
change = msnd->left_levels[addr] != left
|| msnd->right_levels[addr] != right;
snd_msndmix_set(msnd, addr, left, right);
- spin_unlock_irqrestore(&msnd->mixer_lock, flags);
return change;
}
@@ -299,7 +295,7 @@ int snd_msndmix_new(struct snd_card *card)
if (snd_BUG_ON(!chip))
return -EINVAL;
spin_lock_init(&chip->mixer_lock);
- strcpy(card->mixername, "MSND Pinnacle Mixer");
+ strscpy(card->mixername, "MSND Pinnacle Mixer");
for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++) {
err = snd_ctl_add(card,
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index bad1490a66a0..8c1767697b62 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -108,6 +108,7 @@ struct snd_opl3sa2 {
int irq;
int single_dma;
spinlock_t reg_lock;
+ struct snd_card *card;
struct snd_hwdep *synth;
struct snd_rawmidi *rmidi;
struct snd_wss *wss;
@@ -157,12 +158,12 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char
unsigned char result;
#if 0
outb(0x1d, port); /* password */
- printk(KERN_DEBUG "read [0x%lx] = 0x%x\n", port, inb(port));
+ dev_dbg(chip->card->dev, "read [0x%lx] = 0x%x\n", port, inb(port));
#endif
outb(reg, chip->port); /* register */
result = inb(chip->port + 1);
#if 0
- printk(KERN_DEBUG "read [0x%lx] = 0x%x [0x%x]\n",
+ dev_dbg(chip->card->dev, "read [0x%lx] = 0x%x [0x%x]\n",
port, result, inb(port));
#endif
return result;
@@ -171,13 +172,8 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char
/* read control port (with spinlock) */
static unsigned char snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char reg)
{
- unsigned long flags;
- unsigned char result;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- result = __snd_opl3sa2_read(chip, reg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return result;
+ guard(spinlock_irqsave)(&chip->reg_lock);
+ return __snd_opl3sa2_read(chip, reg);
}
/* write control port (w/o spinlock) */
@@ -194,10 +190,8 @@ static void __snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, uns
/* write control port (with spinlock) */
static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsigned char value)
{
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
__snd_opl3sa2_write(chip, reg, value);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static int snd_opl3sa2_detect(struct snd_card *card)
@@ -211,17 +205,13 @@ static int snd_opl3sa2_detect(struct snd_card *card)
chip->res_port = devm_request_region(card->dev, port, 2,
"OPL3-SA control");
if (!chip->res_port) {
- snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
+ dev_err(card->dev, "can't grab port 0x%lx\n", port);
return -EBUSY;
}
- /*
- snd_printk(KERN_DEBUG "REG 0A = 0x%x\n",
- snd_opl3sa2_read(chip, 0x0a));
- */
chip->version = 0;
tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC);
if (tmp == 0xff) {
- snd_printd("OPL3-SA [0x%lx] detect = 0x%x\n", port, tmp);
+ dev_dbg(card->dev, "OPL3-SA [0x%lx] detect = 0x%x\n", port, tmp);
return -ENODEV;
}
switch (tmp & 0x07) {
@@ -243,7 +233,7 @@ static int snd_opl3sa2_detect(struct snd_card *card)
snd_opl3sa2_write(chip, OPL3SA2_MISC, tmp ^ 7);
tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MISC);
if (tmp1 != tmp) {
- snd_printd("OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1);
+ dev_dbg(card->dev, "OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1);
return -ENODEV;
}
/* try if the MIC register is accessible */
@@ -251,7 +241,7 @@ static int snd_opl3sa2_detect(struct snd_card *card)
snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x8a);
tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC);
if ((tmp1 & 0x9f) != 0x8a) {
- snd_printd("OPL3-SA [0x%lx] detect (2) = 0x%x (0x%x)\n", port, tmp, tmp1);
+ dev_dbg(card->dev, "OPL3-SA [0x%lx] detect (2) = 0x%x (0x%x)\n", port, tmp, tmp1);
return -ENODEV;
}
snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x9f);
@@ -339,15 +329,13 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->ctlregs[reg] >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -356,7 +344,6 @@ static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -368,12 +355,11 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
if (invert)
val = mask - val;
val <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
oval = chip->ctlregs[reg];
val = (oval & ~(mask << shift)) | val;
change = val != oval;
__snd_opl3sa2_write(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -394,7 +380,6 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -402,10 +387,9 @@ static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
int mask = (kcontrol->private_value >> 24) & 0xff;
int invert = (kcontrol->private_value >> 22) & 1;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->ctlregs[left_reg] >> shift_left) & mask;
ucontrol->value.integer.value[1] = (chip->ctlregs[right_reg] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert) {
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
@@ -416,7 +400,6 @@ static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -434,7 +417,7 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (left_reg != right_reg) {
oval1 = chip->ctlregs[left_reg];
oval2 = chip->ctlregs[right_reg];
@@ -449,7 +432,6 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
change = val1 != oval1;
__snd_opl3sa2_write(chip, left_reg, val1);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -491,33 +473,33 @@ static int snd_opl3sa2_mixer(struct snd_card *card)
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* reassign AUX0 to CD */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "CD Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
+ strscpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n");
+ dev_err(card->dev, "Cannot rename opl3sa2 control\n");
return err;
}
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "CD Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "CD Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n");
+ dev_err(card->dev, "Cannot rename opl3sa2 control\n");
return err;
}
/* reassign AUX1 to FM */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "FM Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strscpy(id2.name, "FM Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n");
+ dev_err(card->dev, "Cannot rename opl3sa2 control\n");
return err;
}
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "FM Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "FM Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n");
+ dev_err(card->dev, "Cannot rename opl3sa2 control\n");
return err;
}
/* add OPL3SA2 controls */
@@ -591,7 +573,7 @@ static int snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
struct pnp_dev *pdev)
{
if (pnp_activate_dev(pdev) < 0) {
- snd_printk(KERN_ERR "PnP configure failure (out of resources?)\n");
+ dev_err(chip->card->dev, "PnP configure failure (out of resources?)\n");
return -EBUSY;
}
sb_port[dev] = pnp_port_start(pdev, 0);
@@ -602,9 +584,9 @@ static int snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
dma1[dev] = pnp_dma(pdev, 0);
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
+ dev_dbg(chip->card->dev, "%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
- snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
+ dev_dbg(chip->card->dev, "%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
return 0;
}
@@ -621,8 +603,8 @@ static int snd_opl3sa2_card_new(struct device *pdev, int dev,
sizeof(struct snd_opl3sa2), &card);
if (err < 0)
return err;
- strcpy(card->driver, "OPL3SA2");
- strcpy(card->shortname, "Yamaha OPL3-SA");
+ strscpy(card->driver, "OPL3SA2");
+ strscpy(card->shortname, "Yamaha OPL3-SA");
chip = card->private_data;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
@@ -640,6 +622,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
/* initialise this card from supplied (or default) parameter*/
chip = card->private_data;
+ chip->card = card;
chip->ymode = opl3sa3_ymode[dev] & 0x03 ;
chip->port = port[dev];
xirq = irq[dev];
@@ -653,7 +636,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
err = devm_request_irq(card->dev, xirq, snd_opl3sa2_interrupt, 0,
"OPL3-SA2", card);
if (err) {
- snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq);
+ dev_err(card->dev, "can't grab IRQ %d\n", xirq);
return -ENODEV;
}
chip->irq = xirq;
@@ -663,7 +646,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
xirq, xdma1, xdma2,
WSS_HW_OPL3SA2, WSS_HWSHARE_IRQ, &wss);
if (err < 0) {
- snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4);
+ dev_dbg(card->dev, "Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4);
return err;
}
chip->wss = wss;
@@ -770,7 +753,7 @@ static int snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
pdev = pnp_request_card_device(pcard, id->devs[0].id, NULL);
if (pdev == NULL) {
- snd_printk(KERN_ERR PFX "can't get pnp device from id '%s'\n",
+ dev_err(&pcard->card->dev, "can't get pnp device from id '%s'\n",
id->devs[0].id);
return -EBUSY;
}
@@ -828,19 +811,19 @@ static int snd_opl3sa2_isa_match(struct device *pdev,
return 0;
#endif
if (port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify port\n");
+ dev_err(pdev, "specify port\n");
return 0;
}
if (wss_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify wss_port\n");
+ dev_err(pdev, "specify wss_port\n");
return 0;
}
if (fm_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify fm_port\n");
+ dev_err(pdev, "specify fm_port\n");
return 0;
}
if (midi_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR PFX "specify midi_port\n");
+ dev_err(pdev, "specify midi_port\n");
return 0;
}
return 1;
diff --git a/sound/isa/opti9xx/Makefile b/sound/isa/opti9xx/Makefile
index a9dcdeb502bd..44a2fb220456 100644
--- a/sound/isa/opti9xx/Makefile
+++ b/sound/isa/opti9xx/Makefile
@@ -4,10 +4,10 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-opti92x-ad1848-objs := opti92x-ad1848.o
-snd-opti92x-cs4231-objs := opti92x-cs4231.o
-snd-opti93x-objs := opti93x.o
-snd-miro-objs := miro.o
+snd-opti92x-ad1848-y := opti92x-ad1848.o
+snd-opti92x-cs4231-y := opti92x-cs4231.o
+snd-opti93x-y := opti93x.o
+snd-miro-y := miro.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opti92x-ad1848.o
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 59242baed576..c320af3e9a05 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -111,6 +111,7 @@ struct snd_miro {
long mpu_port;
int mpu_irq;
+ struct snd_card *card;
struct snd_miro_aci *aci;
};
@@ -151,8 +152,9 @@ static int aci_busy_wait(struct snd_miro_aci *aci)
byte = inb(aci->aci_port + ACI_REG_BUSY);
if ((byte & 1) == 0) {
if (timeout >= ACI_MINTIME)
- snd_printd("aci ready in round %ld.\n",
- timeout-ACI_MINTIME);
+ dev_dbg(aci->card->dev,
+ "aci ready in round %ld.\n",
+ timeout-ACI_MINTIME);
return byte;
}
if (timeout >= ACI_MINTIME) {
@@ -174,7 +176,7 @@ static int aci_busy_wait(struct snd_miro_aci *aci)
}
}
}
- snd_printk(KERN_ERR "aci_busy_wait() time out\n");
+ dev_err(aci->card->dev, "%s() time out\n", __func__);
return -EBUSY;
}
@@ -184,7 +186,7 @@ static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte)
outb(byte, aci->aci_port + ACI_REG_COMMAND);
return 0;
} else {
- snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte);
+ dev_err(aci->card->dev, "aci busy, %s(0x%x) stopped.\n", __func__, byte);
return -EBUSY;
}
}
@@ -197,7 +199,7 @@ static inline int aci_read(struct snd_miro_aci *aci)
byte = inb(aci->aci_port + ACI_REG_STATUS);
return byte;
} else {
- snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n");
+ dev_err(aci->card->dev, "aci busy, %s() stopped.\n", __func__);
return -EBUSY;
}
}
@@ -260,8 +262,8 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol,
value = aci_getvalue(miro->aci, ACI_S_GENERAL);
if (value < 0) {
- snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n",
- value);
+ dev_err(miro->card->dev, "%s() failed: %d\n", __func__,
+ value);
return value;
}
@@ -280,8 +282,8 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol,
error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value);
if (error < 0) {
- snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n",
- error);
+ dev_err(miro->card->dev, "%s() failed: %d\n", __func__,
+ error);
return error;
}
@@ -322,8 +324,8 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
value = aci_getvalue(miro->aci, ACI_GET_PREAMP);
if (value < 0) {
- snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n",
- value);
+ dev_err(miro->card->dev, "%s() failed: %d\n", __func__,
+ value);
return value;
}
@@ -342,8 +344,8 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol,
error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value);
if (error < 0) {
- snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n",
- error);
+ dev_err(miro->card->dev, "%s() failed: %d\n", __func__,
+ error);
return error;
}
@@ -374,7 +376,8 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol,
error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value);
if (error < 0) {
- snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error);
+ dev_err(miro->card->dev, "%s() to %d failed: %d\n", __func__,
+ value, error);
return error;
}
@@ -430,13 +433,15 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol,
right_val = aci_getvalue(miro->aci, right_reg);
if (right_val < 0) {
- snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val);
+ dev_err(miro->card->dev, "aci_getvalue(%d) failed: %d\n",
+ right_reg, right_val);
return right_val;
}
left_val = aci_getvalue(miro->aci, left_reg);
if (left_val < 0) {
- snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val);
+ dev_err(miro->card->dev, "aci_getvalue(%d) failed: %d\n",
+ left_reg, left_val);
return left_val;
}
@@ -489,13 +494,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
left_old = aci_getvalue(aci, getreg_left);
if (left_old < 0) {
- snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old);
+ dev_err(miro->card->dev, "aci_getvalue(%d) failed: %d\n",
+ getreg_left, left_old);
return left_old;
}
right_old = aci_getvalue(aci, getreg_right);
if (right_old < 0) {
- snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old);
+ dev_err(miro->card->dev, "aci_getvalue(%d) failed: %d\n",
+ getreg_right, right_old);
return right_old;
}
@@ -515,15 +522,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
if (left >= 0) {
error = aci_setvalue(aci, setreg_left, left);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- left, error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ left, error);
return error;
}
} else {
error = aci_setvalue(aci, setreg_left, 0x80 - left);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- 0x80 - left, error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ 0x80 - left, error);
return error;
}
}
@@ -531,15 +538,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
if (right >= 0) {
error = aci_setvalue(aci, setreg_right, right);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- right, error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ right, error);
return error;
}
} else {
error = aci_setvalue(aci, setreg_right, 0x80 - right);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- 0x80 - right, error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ 0x80 - right, error);
return error;
}
}
@@ -557,14 +564,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
error = aci_setvalue(aci, setreg_left, 0x20 - left);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- 0x20 - left, error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ 0x20 - left, error);
return error;
}
error = aci_setvalue(aci, setreg_right, 0x20 - right);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- 0x20 - right, error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ 0x20 - right, error);
return error;
}
}
@@ -667,7 +674,7 @@ static int snd_set_aci_init_values(struct snd_miro *miro)
if ((aci->aci_product == 'A') && wss) {
error = aci_setvalue(aci, ACI_SET_WSS, wss);
if (error < 0) {
- snd_printk(KERN_ERR "enabling WSS mode failed\n");
+ dev_err(miro->card->dev, "enabling WSS mode failed\n");
return error;
}
}
@@ -677,7 +684,7 @@ static int snd_set_aci_init_values(struct snd_miro *miro)
if (ide) {
error = aci_setvalue(aci, ACI_SET_IDE, ide);
if (error < 0) {
- snd_printk(KERN_ERR "enabling IDE port failed\n");
+ dev_err(miro->card->dev, "enabling IDE port failed\n");
return error;
}
}
@@ -688,8 +695,8 @@ static int snd_set_aci_init_values(struct snd_miro *miro)
error = aci_setvalue(aci, aci_init_values[idx][0],
aci_init_values[idx][1]);
if (error < 0) {
- snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
- aci_init_values[idx][0], error);
+ dev_err(miro->card->dev, "aci_setvalue(%d) failed: %d\n",
+ aci_init_values[idx][0], error);
return error;
}
}
@@ -711,10 +718,10 @@ static int snd_miro_mixer(struct snd_card *card,
switch (miro->hardware) {
case OPTi9XX_HW_82C924:
- strcpy(card->mixername, "ACI & OPTi924");
+ strscpy(card->mixername, "ACI & OPTi924");
break;
case OPTi9XX_HW_82C929:
- strcpy(card->mixername, "ACI & OPTi929");
+ strscpy(card->mixername, "ACI & OPTi929");
break;
default:
snd_BUG();
@@ -772,7 +779,7 @@ static int snd_miro_init(struct snd_miro *chip,
static const int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
chip->hardware = hardware;
- strcpy(chip->name, snd_opti9xx_names[hardware]);
+ strscpy(chip->name, snd_opti9xx_names[hardware]);
chip->mc_base_size = opti9xx_mc_size[hardware];
@@ -805,7 +812,7 @@ static int snd_miro_init(struct snd_miro *chip,
break;
default:
- snd_printk(KERN_ERR "sorry, no support for %d\n", hardware);
+ dev_err(chip->card->dev, "sorry, no support for %d\n", hardware);
return -ENODEV;
}
@@ -815,10 +822,9 @@ static int snd_miro_init(struct snd_miro *chip,
static unsigned char snd_miro_read(struct snd_miro *chip,
unsigned char reg)
{
- unsigned long flags;
unsigned char retval = 0xff;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
outb(chip->password, chip->mc_base + chip->pwd_reg);
switch (chip->hardware) {
@@ -836,19 +842,16 @@ static unsigned char snd_miro_read(struct snd_miro *chip,
break;
default:
- snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
+ dev_err(chip->card->dev, "sorry, no support for %d\n", chip->hardware);
}
- spin_unlock_irqrestore(&chip->lock, flags);
return retval;
}
static void snd_miro_write(struct snd_miro *chip, unsigned char reg,
unsigned char value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
outb(chip->password, chip->mc_base + chip->pwd_reg);
switch (chip->hardware) {
@@ -866,10 +869,8 @@ static void snd_miro_write(struct snd_miro *chip, unsigned char reg,
break;
default:
- snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
+ dev_err(chip->card->dev, "sorry, no support for %d\n", chip->hardware);
}
-
- spin_unlock_irqrestore(&chip->lock, flags);
}
static inline void snd_miro_write_mask(struct snd_miro *chip,
@@ -1006,7 +1007,6 @@ static int snd_miro_configure(struct snd_miro *chip)
unsigned char dma_bits;
unsigned char mpu_port_bits = 0;
unsigned char mpu_irq_bits;
- unsigned long flags;
snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
@@ -1022,7 +1022,7 @@ static int snd_miro_configure(struct snd_miro *chip)
snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c);
break;
default:
- snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
+ dev_err(chip->card->dev, "chip %d not supported\n", chip->hardware);
return -EINVAL;
}
@@ -1045,7 +1045,7 @@ static int snd_miro_configure(struct snd_miro *chip)
wss_base_bits = 0x02;
break;
default:
- snd_printk(KERN_ERR "WSS port 0x%lx not valid\n", chip->wss_base);
+ dev_err(chip->card->dev, "WSS port 0x%lx not valid\n", chip->wss_base);
goto __skip_base;
}
snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
@@ -1068,7 +1068,7 @@ __skip_base:
irq_bits = 0x04;
break;
default:
- snd_printk(KERN_ERR "WSS irq # %d not valid\n", chip->irq);
+ dev_err(chip->card->dev, "WSS irq # %d not valid\n", chip->irq);
goto __skip_resources;
}
@@ -1083,12 +1083,12 @@ __skip_base:
dma_bits = 0x03;
break;
default:
- snd_printk(KERN_ERR "WSS dma1 # %d not valid\n", chip->dma1);
+ dev_err(chip->card->dev, "WSS dma1 # %d not valid\n", chip->dma1);
goto __skip_resources;
}
if (chip->dma1 == chip->dma2) {
- snd_printk(KERN_ERR "don't want to share dmas\n");
+ dev_err(chip->card->dev, "don't want to share dmas\n");
return -EBUSY;
}
@@ -1097,14 +1097,14 @@ __skip_base:
case 1:
break;
default:
- snd_printk(KERN_ERR "WSS dma2 # %d not valid\n", chip->dma2);
+ dev_err(chip->card->dev, "WSS dma2 # %d not valid\n", chip->dma2);
goto __skip_resources;
}
dma_bits |= 0x04;
- spin_lock_irqsave(&chip->lock, flags);
- outb(irq_bits << 3 | dma_bits, chip->wss_base);
- spin_unlock_irqrestore(&chip->lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->lock) {
+ outb(irq_bits << 3 | dma_bits, chip->wss_base);
+ }
__skip_resources:
if (chip->hardware > OPTi9XX_HW_82C928) {
@@ -1125,8 +1125,8 @@ __skip_resources:
mpu_port_bits = 0x00;
break;
default:
- snd_printk(KERN_ERR "MPU-401 port 0x%lx not valid\n",
- chip->mpu_port);
+ dev_err(chip->card->dev, "MPU-401 port 0x%lx not valid\n",
+ chip->mpu_port);
goto __skip_mpu;
}
@@ -1144,8 +1144,8 @@ __skip_resources:
mpu_irq_bits = 0x01;
break;
default:
- snd_printk(KERN_ERR "MPU-401 irq # %d not valid\n",
- chip->mpu_irq);
+ dev_err(chip->card->dev, "MPU-401 irq # %d not valid\n",
+ chip->mpu_irq);
goto __skip_mpu;
}
@@ -1208,6 +1208,7 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
miro->aci = aci;
+ aci->card = card;
mutex_init(&aci->aci_mutex);
/* get ACI port from OPTi9xx MC 4 */
@@ -1218,37 +1219,37 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
miro->res_aci_port =
devm_request_region(card->dev, aci->aci_port, 3, "miro aci");
if (miro->res_aci_port == NULL) {
- snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n",
- aci->aci_port, aci->aci_port+2);
+ dev_err(card->dev, "aci i/o area 0x%lx-0x%lx already used.\n",
+ aci->aci_port, aci->aci_port+2);
return -ENOMEM;
}
/* force ACI into a known state */
for (i = 0; i < 3; i++)
if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) {
- snd_printk(KERN_ERR "can't force aci into known state.\n");
+ dev_err(card->dev, "can't force aci into known state.\n");
return -ENXIO;
}
aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
if (aci->aci_vendor < 0 || aci->aci_product < 0) {
- snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n",
- aci->aci_port);
+ dev_err(card->dev, "can't read aci id on 0x%lx.\n",
+ aci->aci_port);
return -ENXIO;
}
aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1);
if (aci->aci_version < 0) {
- snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n",
- aci->aci_port);
+ dev_err(card->dev, "can't read aci version on 0x%lx.\n",
+ aci->aci_port);
return -ENXIO;
}
if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 ||
snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
- snd_printk(KERN_ERR "can't initialize aci.\n");
+ dev_err(card->dev, "can't initialize aci.\n");
return -ENXIO;
}
@@ -1268,14 +1269,14 @@ static int snd_miro_probe(struct snd_card *card)
miro->mc_base_size,
"miro (OPTi9xx MC)");
if (miro->res_mc_base == NULL) {
- snd_printk(KERN_ERR "request for OPTI9xx MC failed\n");
+ dev_err(card->dev, "request for OPTI9xx MC failed\n");
return -ENOMEM;
}
}
error = snd_card_miro_aci_detect(card, miro);
if (error < 0) {
- snd_printk(KERN_ERR "unable to detect aci chip\n");
+ dev_err(card->dev, "unable to detect aci chip\n");
return -ENODEV;
}
@@ -1335,19 +1336,19 @@ static int snd_miro_probe(struct snd_card *card)
default:
sprintf(card->shortname,
"unknown miro");
- snd_printk(KERN_INFO "unknown miro aci id\n");
+ dev_info(card->dev, "unknown miro aci id\n");
break;
}
} else {
- snd_printk(KERN_INFO "found unsupported aci card\n");
+ dev_info(card->dev, "found unsupported aci card\n");
sprintf(card->shortname, "unknown Cardinal Technologies");
}
- strcpy(card->driver, "miro");
- snprintf(card->longname, sizeof(card->longname),
- "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, miro->name, codec->pcm->name,
- miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
+ strscpy(card->driver, "miro");
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
+ card->shortname, miro->name, codec->pcm->name,
+ miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
rmidi = NULL;
@@ -1355,8 +1356,8 @@ static int snd_miro_probe(struct snd_card *card)
error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port, 0, miro->mpu_irq, &rmidi);
if (error < 0)
- snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
- mpu_port);
+ dev_warn(card->dev, "no MPU-401 device at 0x%lx?\n",
+ mpu_port);
}
if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
@@ -1365,8 +1366,8 @@ static int snd_miro_probe(struct snd_card *card)
if (snd_opl4_create(card, fm_port, fm_port - 8,
2, &opl3, &opl4) < 0)
- snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n",
- fm_port);
+ dev_warn(card->dev, "no OPL4 device at 0x%lx\n",
+ fm_port);
}
error = snd_set_aci_init_values(miro);
@@ -1410,14 +1411,14 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
error = snd_card_miro_detect(card, miro);
if (error < 0) {
- snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n");
+ dev_err(card->dev, "unable to detect OPTi9xx chip\n");
return -ENODEV;
}
if (port == SNDRV_AUTO_PORT) {
port = snd_legacy_find_free_ioport(possible_ports, 4);
if (port < 0) {
- snd_printk(KERN_ERR "unable to find a free WSS port\n");
+ dev_err(card->dev, "unable to find a free WSS port\n");
return -EBUSY;
}
}
@@ -1425,8 +1426,8 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
if (mpu_port == SNDRV_AUTO_PORT) {
mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2);
if (mpu_port < 0) {
- snd_printk(KERN_ERR
- "unable to find a free MPU401 port\n");
+ dev_err(card->dev,
+ "unable to find a free MPU401 port\n");
return -EBUSY;
}
}
@@ -1434,29 +1435,29 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
if (irq == SNDRV_AUTO_IRQ) {
irq = snd_legacy_find_free_irq(possible_irqs);
if (irq < 0) {
- snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ dev_err(card->dev, "unable to find a free IRQ\n");
return -EBUSY;
}
}
if (mpu_irq == SNDRV_AUTO_IRQ) {
mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs);
if (mpu_irq < 0) {
- snd_printk(KERN_ERR
- "unable to find a free MPU401 IRQ\n");
+ dev_err(card->dev,
+ "unable to find a free MPU401 IRQ\n");
return -EBUSY;
}
}
if (dma1 == SNDRV_AUTO_DMA) {
dma1 = snd_legacy_find_free_dma(possible_dma1s);
if (dma1 < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ dev_err(card->dev, "unable to find a free DMA1\n");
return -EBUSY;
}
}
if (dma2 == SNDRV_AUTO_DMA) {
dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]);
if (dma2 < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA2\n");
+ dev_err(card->dev, "unable to find a free DMA2\n");
return -EBUSY;
}
}
@@ -1505,14 +1506,14 @@ static int snd_card_miro_pnp(struct snd_miro *chip,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
+ dev_err(chip->card->dev, "AUDIO pnp configure failure: %d\n", err);
return err;
}
err = pnp_activate_dev(devmc);
if (err < 0) {
- snd_printk(KERN_ERR "MC pnp configure failure: %d\n",
- err);
+ dev_err(chip->card->dev, "MC pnp configure failure: %d\n",
+ err);
return err;
}
@@ -1533,7 +1534,7 @@ static int snd_card_miro_pnp(struct snd_miro *chip,
if (mpu_port > 0) {
err = pnp_activate_dev(devmpu);
if (err < 0) {
- snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
+ dev_err(chip->card->dev, "MPU401 pnp configure failure\n");
mpu_port = -1;
return err;
}
@@ -1560,6 +1561,7 @@ static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
return err;
miro = card->private_data;
+ miro->card = card;
err = snd_card_miro_pnp(miro, pcard, pid);
if (err)
@@ -1572,7 +1574,7 @@ static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
err = snd_miro_opti_check(card, miro);
if (err) {
- snd_printk(KERN_ERR "OPTI chip not found\n");
+ dev_err(card->dev, "OPTI chip not found\n");
return err;
}
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 4beeb32fe2a7..abaa3ed3ab5c 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -109,6 +109,7 @@ MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
#endif /* OPTi93X */
struct snd_opti9xx {
+ struct snd_card *card;
unsigned short hardware;
unsigned char password;
char name[7];
@@ -170,7 +171,7 @@ static int snd_opti9xx_init(struct snd_opti9xx *chip,
static const int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
chip->hardware = hardware;
- strcpy(chip->name, snd_opti9xx_names[hardware]);
+ strscpy(chip->name, snd_opti9xx_names[hardware]);
spin_lock_init(&chip->lock);
@@ -218,7 +219,7 @@ static int snd_opti9xx_init(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk(KERN_ERR "chip %d not supported\n", hardware);
+ dev_err(chip->card->dev, "chip %d not supported\n", hardware);
return -ENODEV;
}
return 0;
@@ -227,10 +228,9 @@ static int snd_opti9xx_init(struct snd_opti9xx *chip,
static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
unsigned char reg)
{
- unsigned long flags;
unsigned char retval = 0xff;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
outb(chip->password, chip->mc_base + chip->pwd_reg);
switch (chip->hardware) {
@@ -261,19 +261,16 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
+ dev_err(chip->card->dev, "chip %d not supported\n", chip->hardware);
}
- spin_unlock_irqrestore(&chip->lock, flags);
return retval;
}
static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
unsigned char value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
outb(chip->password, chip->mc_base + chip->pwd_reg);
switch (chip->hardware) {
@@ -304,10 +301,8 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
#endif /* OPTi93X */
default:
- snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
+ dev_err(chip->card->dev, "chip %d not supported\n", chip->hardware);
}
-
- spin_unlock_irqrestore(&chip->lock, flags);
}
@@ -400,7 +395,7 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
+ dev_err(chip->card->dev, "chip %d not supported\n", chip->hardware);
return -EINVAL;
}
@@ -423,7 +418,7 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
wss_base_bits = 0x02;
break;
default:
- snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", port);
+ dev_warn(chip->card->dev, "WSS port 0x%lx not valid\n", port);
goto __skip_base;
}
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
@@ -448,7 +443,7 @@ __skip_base:
irq_bits = 0x04;
break;
default:
- snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq);
+ dev_warn(chip->card->dev, "WSS irq # %d not valid\n", irq);
goto __skip_resources;
}
@@ -463,13 +458,13 @@ __skip_base:
dma_bits = 0x03;
break;
default:
- snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1);
+ dev_warn(chip->card->dev, "WSS dma1 # %d not valid\n", dma1);
goto __skip_resources;
}
#if defined(CS4231) || defined(OPTi93X)
if (dma1 == dma2) {
- snd_printk(KERN_ERR "don't want to share dmas\n");
+ dev_err(chip->card->dev, "don't want to share dmas\n");
return -EBUSY;
}
@@ -478,14 +473,14 @@ __skip_base:
case 1:
break;
default:
- snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2);
+ dev_warn(chip->card->dev, "WSS dma2 # %d not valid\n", dma2);
goto __skip_resources;
}
dma_bits |= 0x04;
#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 */
@@ -509,8 +504,8 @@ __skip_resources:
mpu_port_bits = 0x00;
break;
default:
- snd_printk(KERN_WARNING
- "MPU-401 port 0x%lx not valid\n", mpu_port);
+ dev_warn(chip->card->dev,
+ "MPU-401 port 0x%lx not valid\n", mpu_port);
goto __skip_mpu;
}
@@ -528,8 +523,8 @@ __skip_resources:
mpu_irq_bits = 0x01;
break;
default:
- snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
- mpu_irq);
+ dev_warn(chip->card->dev, "MPU-401 irq # %d not valid\n",
+ mpu_irq);
goto __skip_mpu;
}
@@ -593,35 +588,35 @@ static int snd_opti93x_mixer(struct snd_wss *chip)
card = chip->card;
- strcpy(card->mixername, chip->pcm->name);
+ strscpy(card->mixername, chip->pcm->name);
memset(&id1, 0, sizeof(id1));
memset(&id2, 0, sizeof(id2));
id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* reassign AUX0 switch to CD */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "CD Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
+ strscpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot rename opti93x control\n");
+ dev_err(card->dev, "Cannot rename opti93x control\n");
return err;
}
/* reassign AUX1 switch to FM */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "FM Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strscpy(id2.name, "FM Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot rename opti93x control\n");
+ dev_err(card->dev, "Cannot rename opti93x control\n");
return err;
}
/* remove AUX1 volume */
- strcpy(id1.name, "Aux Playback Volume"); id1.index = 1;
+ strscpy(id1.name, "Aux Playback Volume"); id1.index = 1;
snd_ctl_remove_id(card, &id1);
/* Replace WSS volume controls with OPTi93x volume controls */
id1.index = 0;
for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
- strcpy(id1.name, snd_opti93x_controls[idx].name);
+ strscpy(id1.name, snd_opti93x_controls[idx].name);
snd_ctl_remove_id(card, &id1);
err = snd_ctl_add(card,
@@ -658,9 +653,6 @@ static int snd_opti9xx_read_check(struct snd_card *card,
struct snd_opti9xx *chip)
{
unsigned char value;
-#ifdef OPTi93X
- unsigned long flags;
-#endif
chip->res_mc_base =
devm_request_region(card->dev, chip->mc_base,
@@ -679,10 +671,10 @@ static int snd_opti9xx_read_check(struct snd_card *card,
if (!chip->res_mc_indir)
return -EBUSY;
- spin_lock_irqsave(&chip->lock, flags);
- outb(chip->password, chip->mc_base + chip->pwd_reg);
- outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base);
- spin_unlock_irqrestore(&chip->lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->lock) {
+ outb(chip->password, chip->mc_base + chip->pwd_reg);
+ outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base);
+ }
value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7));
snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value);
@@ -740,7 +732,7 @@ static int snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
+ dev_err(chip->card->dev, "AUDIO pnp configure failure: %d\n", err);
return err;
}
@@ -757,7 +749,7 @@ static int snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
err = pnp_activate_dev(devmc);
if (err < 0) {
- snd_printk(KERN_ERR "MC pnp configure failure: %d\n", err);
+ dev_err(chip->card->dev, "MC pnp configure failure: %d\n", err);
return err;
}
@@ -781,7 +773,7 @@ static int snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
if (devmpu && mpu_port > 0) {
err = pnp_activate_dev(devmpu);
if (err < 0) {
- snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
+ dev_err(chip->card->dev, "MPU401 pnp configure failure\n");
mpu_port = -1;
} else {
mpu_port = pnp_port_start(devmpu, 0);
@@ -811,7 +803,7 @@ static int snd_opti9xx_probe(struct snd_card *card)
if (port == SNDRV_AUTO_PORT) {
port = snd_legacy_find_free_ioport(possible_ports, 4);
if (port < 0) {
- snd_printk(KERN_ERR "unable to find a free WSS port\n");
+ dev_err(card->dev, "unable to find a free WSS port\n");
return -EBUSY;
}
}
@@ -850,24 +842,24 @@ static int snd_opti9xx_probe(struct snd_card *card)
error = devm_request_irq(card->dev, irq, snd_opti93x_interrupt,
0, DEV_NAME" - WSS", chip);
if (error < 0) {
- snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq);
+ dev_err(card->dev, "opti9xx: can't grab IRQ %d\n", irq);
return error;
}
#endif
chip->irq = irq;
card->sync_irq = chip->irq;
- strcpy(card->driver, chip->name);
+ strscpy(card->driver, chip->name);
sprintf(card->shortname, "OPTi %s", card->driver);
#if defined(CS4231) || defined(OPTi93X)
- snprintf(card->longname, sizeof(card->longname),
- "%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, codec->pcm->name,
- chip->wss_base + 4, irq, dma1, xdma2);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s, %s at 0x%lx, irq %d, dma %d&%d",
+ card->shortname, codec->pcm->name,
+ chip->wss_base + 4, irq, dma1, xdma2);
#else
- snprintf(card->longname, sizeof(card->longname),
- "%s, %s at 0x%lx, irq %d, dma %d",
- card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
- dma1);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s, %s at 0x%lx, irq %d, dma %d",
+ card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
+ dma1);
#endif /* CS4231 || OPTi93X */
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
@@ -876,8 +868,8 @@ static int snd_opti9xx_probe(struct snd_card *card)
error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port, 0, mpu_irq, &rmidi);
if (error)
- snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
- mpu_port);
+ dev_warn(card->dev, "no MPU-401 device at 0x%lx?\n",
+ mpu_port);
}
if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
@@ -900,8 +892,8 @@ static int snd_opti9xx_probe(struct snd_card *card)
#endif /* !OPTi93X */
if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
- snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
- fm_port, fm_port + 4 - 1);
+ dev_warn(card->dev, "no OPL device at 0x%lx-0x%lx\n",
+ fm_port, fm_port + 4 - 1);
}
if (opl3) {
error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
@@ -958,28 +950,28 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
if (mpu_port == SNDRV_AUTO_PORT) {
mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2);
if (mpu_port < 0) {
- snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+ dev_err(devptr, "unable to find a free MPU401 port\n");
return -EBUSY;
}
}
if (irq == SNDRV_AUTO_IRQ) {
irq = snd_legacy_find_free_irq(possible_irqs);
if (irq < 0) {
- snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ dev_err(devptr, "unable to find a free IRQ\n");
return -EBUSY;
}
}
if (mpu_irq == SNDRV_AUTO_IRQ) {
mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs);
if (mpu_irq < 0) {
- snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+ dev_err(devptr, "unable to find a free MPU401 IRQ\n");
return -EBUSY;
}
}
if (dma1 == SNDRV_AUTO_DMA) {
dma1 = snd_legacy_find_free_dma(possible_dma1s);
if (dma1 < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA1\n");
+ dev_err(devptr, "unable to find a free DMA1\n");
return -EBUSY;
}
}
@@ -987,7 +979,7 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
if (dma2 == SNDRV_AUTO_DMA) {
dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]);
if (dma2 < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA2\n");
+ dev_err(devptr, "unable to find a free DMA2\n");
return -EBUSY;
}
}
@@ -1076,6 +1068,7 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
if (error < 0)
return error;
chip = card->private_data;
+ chip->card = card;
hw = snd_card_opti9xx_pnp(chip, pcard, pid);
switch (hw) {
@@ -1097,7 +1090,7 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
return error;
error = snd_opti9xx_read_check(card, chip);
if (error) {
- snd_printk(KERN_ERR "OPTI chip not found\n");
+ dev_err(card->dev, "OPTI chip not found\n");
return error;
}
error = snd_opti9xx_probe(card);
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
index f174a5b3c8e4..96a926feb17a 100644
--- a/sound/isa/sb/Makefile
+++ b/sound/isa/sb/Makefile
@@ -4,15 +4,15 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-sb-common-objs := sb_common.o sb_mixer.o
-snd-sb8-dsp-objs := sb8_main.o sb8_midi.o
-snd-sb16-dsp-objs := sb16_main.o
-snd-sb16-csp-objs := sb16_csp.o
-snd-sb8-objs := sb8.o
-snd-sb16-objs := sb16.o
-snd-sbawe-objs := sbawe.o emu8000.o
-snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
-snd-jazz16-objs := jazz16.o
+snd-sb-common-y := sb_common.o sb_mixer.o
+snd-sb8-dsp-y := sb8_main.o sb8_midi.o
+snd-sb16-dsp-y := sb16_main.o
+snd-sb16-csp-y := sb16_csp.o
+snd-sb8-y := sb8.o
+snd-sb16-y := sb16.o
+snd-sbawe-y := sbawe.o emu8000.o
+snd-emu8000-synth-y := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
+snd-jazz16-y := jazz16.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index e02029677743..12c296ee34ec 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -14,6 +14,7 @@
#include <linux/export.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <sound/emu8000.h>
#include <sound/emu8000_reg.h>
@@ -34,60 +35,49 @@
/* Write a word */
void snd_emu8000_poke(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
{
- unsigned long flags;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irqsave)(&emu->reg_lock);
if (reg != emu->last_reg) {
outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
emu->last_reg = reg;
}
outw((unsigned short)val, port); /* Send data */
- spin_unlock_irqrestore(&emu->reg_lock, flags);
}
/* Read a word */
unsigned short snd_emu8000_peek(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
{
- unsigned short res;
- unsigned long flags;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irqsave)(&emu->reg_lock);
if (reg != emu->last_reg) {
outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
emu->last_reg = reg;
}
- res = inw(port); /* Read data */
- spin_unlock_irqrestore(&emu->reg_lock, flags);
- return res;
+ return inw(port); /* Read data */
}
/* Write a double word */
void snd_emu8000_poke_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
{
- unsigned long flags;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irqsave)(&emu->reg_lock);
if (reg != emu->last_reg) {
outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
emu->last_reg = reg;
}
outw((unsigned short)val, port); /* Send low word of data */
outw((unsigned short)(val>>16), port+2); /* Send high word of data */
- spin_unlock_irqrestore(&emu->reg_lock, flags);
}
/* Read a double word */
unsigned int snd_emu8000_peek_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
{
unsigned short low;
- unsigned int res;
- unsigned long flags;
- spin_lock_irqsave(&emu->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&emu->reg_lock);
if (reg != emu->last_reg) {
outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
emu->last_reg = reg;
}
low = inw(port); /* Read low word of data */
- res = low + (inw(port+2) << 16);
- spin_unlock_irqrestore(&emu->reg_lock, flags);
- return res;
+ return low + (inw(port+2) << 16);
}
/*
@@ -160,8 +150,8 @@ snd_emu8000_detect(struct snd_emu8000 *emu)
if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)
return -ENODEV;
- snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",
- emu->port1);
+ dev_dbg(emu->card->dev, "EMU8000 [0x%lx]: Synth chip found\n",
+ emu->port1);
return 0;
}
@@ -455,8 +445,6 @@ skip_detect:
/*exported*/ void
snd_emu8000_init_fm(struct snd_emu8000 *emu)
{
- unsigned long flags;
-
/* Initialize the last two channels for DRAM refresh and producing
the reverb and chorus effects for Yamaha OPL-3 synthesizer */
@@ -478,12 +466,12 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu)
snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
- spin_lock_irqsave(&emu->reg_lock, flags);
- while (!(inw(EMU8000_PTR(emu)) & 0x1000))
- ;
- while ((inw(EMU8000_PTR(emu)) & 0x1000))
- ;
- spin_unlock_irqrestore(&emu->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &emu->reg_lock) {
+ while (!(inw(EMU8000_PTR(emu)) & 0x1000))
+ ;
+ while ((inw(EMU8000_PTR(emu)) & 0x1000))
+ ;
+ }
snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
/* this is really odd part.. */
outb(0x3C, EMU8000_PTR(emu));
@@ -652,7 +640,7 @@ snd_emu8000_load_chorus_fx(struct snd_emu8000 *emu, int mode, const void __user
{
struct soundfont_chorus_fx rec;
if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
- snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
+ dev_warn(emu->card->dev, "invalid chorus mode %d for uploading\n", mode);
return -EINVAL;
}
if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
@@ -780,7 +768,7 @@ snd_emu8000_load_reverb_fx(struct snd_emu8000 *emu, int mode, const void __user
struct soundfont_reverb_fx rec;
if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
- snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
+ dev_warn(emu->card->dev, "invalid reverb mode %d for uploading\n", mode);
return -EINVAL;
}
if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
@@ -837,20 +825,19 @@ static int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned short val1;
val1 = ucontrol->value.integer.value[0] % 12;
- spin_lock_irqsave(&emu->control_lock, flags);
- if (kcontrol->private_value) {
- change = val1 != emu->treble_level;
- emu->treble_level = val1;
- } else {
- change = val1 != emu->bass_level;
- emu->bass_level = val1;
+ scoped_guard(spinlock_irqsave, &emu->control_lock) {
+ if (kcontrol->private_value) {
+ change = val1 != emu->treble_level;
+ emu->treble_level = val1;
+ } else {
+ change = val1 != emu->bass_level;
+ emu->bass_level = val1;
+ }
}
- spin_unlock_irqrestore(&emu->control_lock, flags);
snd_emu8000_update_equalizer(emu);
return change;
}
@@ -898,21 +885,20 @@ static int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl
static int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned short val1;
- spin_lock_irqsave(&emu->control_lock, flags);
- if (kcontrol->private_value) {
- val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
- change = val1 != emu->chorus_mode;
- emu->chorus_mode = val1;
- } else {
- val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
- change = val1 != emu->reverb_mode;
- emu->reverb_mode = val1;
+ scoped_guard(spinlock_irqsave, &emu->control_lock) {
+ if (kcontrol->private_value) {
+ val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
+ change = val1 != emu->chorus_mode;
+ emu->chorus_mode = val1;
+ } else {
+ val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
+ change = val1 != emu->reverb_mode;
+ emu->reverb_mode = val1;
+ }
}
- spin_unlock_irqrestore(&emu->control_lock, flags);
if (change) {
if (kcontrol->private_value)
snd_emu8000_update_chorus_mode(emu);
@@ -965,20 +951,19 @@ static int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
static int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned short val1;
val1 = ucontrol->value.integer.value[0] % 256;
- spin_lock_irqsave(&emu->control_lock, flags);
- if (kcontrol->private_value) {
- change = val1 != emu->fm_chorus_depth;
- emu->fm_chorus_depth = val1;
- } else {
- change = val1 != emu->fm_reverb_depth;
- emu->fm_reverb_depth = val1;
+ scoped_guard(spinlock_irqsave, &emu->control_lock) {
+ if (kcontrol->private_value) {
+ change = val1 != emu->fm_chorus_depth;
+ emu->fm_chorus_depth = val1;
+ } else {
+ change = val1 != emu->fm_reverb_depth;
+ emu->fm_reverb_depth = val1;
+ }
}
- spin_unlock_irqrestore(&emu->control_lock, flags);
if (change)
snd_emu8000_init_fm(emu);
return change;
@@ -1039,12 +1024,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
return 0;
__error:
- for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
- down_write(&card->controls_rwsem);
- if (emu->controls[i])
- snd_ctl_remove(card, emu->controls[i]);
- up_write(&card->controls_rwsem);
- }
+ for (i = 0; i < EMU8000_NUM_CONTROLS; i++)
+ snd_ctl_remove(card, emu->controls[i]);
return err;
}
@@ -1076,7 +1057,8 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
if (!devm_request_region(card->dev, hw->port1, 4, "Emu8000-1") ||
!devm_request_region(card->dev, hw->port2, 4, "Emu8000-2") ||
!devm_request_region(card->dev, hw->port3, 4, "Emu8000-3")) {
- snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
+ dev_err(card->dev, "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n",
+ hw->port1, hw->port2, hw->port3);
return -EBUSY;
}
hw->mem_size = 0;
@@ -1099,7 +1081,7 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
sizeof(struct snd_emu8000*), &awe) >= 0) {
- strcpy(awe->name, "EMU-8000");
+ strscpy(awe->name, "EMU-8000");
*(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
}
#else
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 8c1e7f2bfc34..d60174ec8b39 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -148,13 +148,6 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
if (snd_BUG_ON(!sp))
return -EINVAL;
- if (sp->v.size == 0)
- return 0;
-
- /* be sure loop points start < end */
- if (sp->v.loopstart > sp->v.loopend)
- swap(sp->v.loopstart, sp->v.loopend);
-
/* compute true data size to be loaded */
truesize = sp->v.size;
if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
@@ -164,7 +157,6 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
sp->block = snd_util_mem_alloc(hdr, truesize * 2);
if (sp->block == NULL) {
- /*snd_printd("EMU8000: out of memory\n");*/
/* not ENOMEM (for compatibility) */
return -ENOSPC;
}
@@ -177,12 +169,6 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
return -EFAULT;
}
- /* recalculate address offset */
- sp->v.end -= sp->v.start;
- sp->v.loopstart -= sp->v.start;
- sp->v.loopend -= sp->v.start;
- sp->v.start = 0;
-
/* dram position (in word) -- mem_offset is byte */
dram_offset = EMU8000_DRAM_OFFSET + (sp->block->offset >> 1);
dram_start = dram_offset;
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index c8afc4347c54..656a655d618d 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -182,30 +182,32 @@ static inline int emu8k_get_curpos(struct snd_emu8k_pcm *rec, int ch)
*/
static void emu8k_pcm_timer_func(struct timer_list *t)
{
- struct snd_emu8k_pcm *rec = from_timer(rec, t, timer);
+ struct snd_emu8k_pcm *rec = timer_container_of(rec, t, timer);
int ptr, delta;
+ bool period_elapsed = false;
+
+ scoped_guard(spinlock, &rec->timer_lock) {
+ /* update the current pointer */
+ ptr = emu8k_get_curpos(rec, 0);
+ if (ptr < rec->last_ptr)
+ delta = ptr + rec->buf_size - rec->last_ptr;
+ else
+ delta = ptr - rec->last_ptr;
+ rec->period_pos += delta;
+ rec->last_ptr = ptr;
+
+ /* reprogram timer */
+ mod_timer(&rec->timer, jiffies + 1);
- spin_lock(&rec->timer_lock);
- /* update the current pointer */
- ptr = emu8k_get_curpos(rec, 0);
- if (ptr < rec->last_ptr)
- delta = ptr + rec->buf_size - rec->last_ptr;
- else
- delta = ptr - rec->last_ptr;
- rec->period_pos += delta;
- rec->last_ptr = ptr;
-
- /* reprogram timer */
- mod_timer(&rec->timer, jiffies + 1);
+ /* update period */
+ if (rec->period_pos >= (int)rec->period_size) {
+ rec->period_pos %= rec->period_size;
+ period_elapsed = true;
+ }
+ }
- /* update period */
- if (rec->period_pos >= (int)rec->period_size) {
- rec->period_pos %= rec->period_size;
- spin_unlock(&rec->timer_lock);
+ if (period_elapsed)
snd_pcm_period_elapsed(rec->substream);
- return;
- }
- spin_unlock(&rec->timer_lock);
}
@@ -321,7 +323,6 @@ static void setup_voice(struct snd_emu8k_pcm *rec, int ch)
*/
static void start_voice(struct snd_emu8k_pcm *rec, int ch)
{
- unsigned long flags;
struct snd_emu8000 *hw = rec->emu;
unsigned int temp, aux;
int pt = calc_pitch_target(rec->pitch);
@@ -343,12 +344,11 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch)
EMU8000_CPF_WRITE(hw, ch, pt << 16);
/* start timer */
- spin_lock_irqsave(&rec->timer_lock, flags);
+ guard(spinlock_irqsave)(&rec->timer_lock);
if (! rec->timer_running) {
mod_timer(&rec->timer, jiffies + 1);
rec->timer_running = 1;
}
- spin_unlock_irqrestore(&rec->timer_lock, flags);
}
/*
@@ -356,18 +356,16 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch)
*/
static void stop_voice(struct snd_emu8k_pcm *rec, int ch)
{
- unsigned long flags;
struct snd_emu8000 *hw = rec->emu;
EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);
/* stop timer */
- spin_lock_irqsave(&rec->timer_lock, flags);
+ guard(spinlock_irqsave)(&rec->timer_lock);
if (rec->timer_running) {
- del_timer(&rec->timer);
+ timer_delete(&rec->timer);
rec->timer_running = 0;
}
- spin_unlock_irqrestore(&rec->timer_lock, flags);
}
static int emu8k_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
@@ -409,39 +407,25 @@ do { \
return -EAGAIN;\
} while (0)
-enum {
- COPY_USER, COPY_KERNEL, FILL_SILENCE,
-};
-
-#define GET_VAL(sval, buf, mode) \
+#define GET_VAL(sval, iter) \
do { \
- switch (mode) { \
- case FILL_SILENCE: \
+ if (!iter) \
sval = 0; \
- break; \
- case COPY_KERNEL: \
- sval = *buf++; \
- break; \
- default: \
- if (get_user(sval, (unsigned short __user *)buf)) \
- return -EFAULT; \
- buf++; \
- break; \
- } \
+ else if (copy_from_iter(&sval, 2, iter) != 2) \
+ return -EFAULT; \
} while (0)
#ifdef USE_NONINTERLEAVE
-#define LOOP_WRITE(rec, offset, _buf, count, mode) \
+#define LOOP_WRITE(rec, offset, iter, count) \
do { \
struct snd_emu8000 *emu = (rec)->emu; \
- unsigned short *buf = (__force unsigned short *)(_buf); \
snd_emu8000_write_wait(emu, 1); \
EMU8000_SMALW_WRITE(emu, offset); \
while (count > 0) { \
unsigned short sval; \
CHECK_SCHEDULER(); \
- GET_VAL(sval, buf, mode); \
+ GET_VAL(sval, iter); \
EMU8000_SMLD_WRITE(emu, sval); \
count--; \
} \
@@ -450,27 +434,14 @@ enum {
/* copy one channel block */
static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
int voice, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct snd_emu8k_pcm *rec = subs->runtime->private_data;
/* convert to word unit */
pos = (pos << 1) + rec->loop_start[voice];
count <<= 1;
- LOOP_WRITE(rec, pos, src, count, COPY_USER);
- return 0;
-}
-
-static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs,
- int voice, unsigned long pos,
- void *src, unsigned long count)
-{
- struct snd_emu8k_pcm *rec = subs->runtime->private_data;
-
- /* convert to word unit */
- pos = (pos << 1) + rec->loop_start[voice];
- count <<= 1;
- LOOP_WRITE(rec, pos, src, count, COPY_KERNEL);
+ LOOP_WRITE(rec, pos, src, count);
return 0;
}
@@ -483,16 +454,15 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
/* convert to word unit */
pos = (pos << 1) + rec->loop_start[voice];
count <<= 1;
- LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE);
+ LOOP_WRITE(rec, pos, NULL, count);
return 0;
}
#else /* interleave */
-#define LOOP_WRITE(rec, pos, _buf, count, mode) \
+#define LOOP_WRITE(rec, pos, iter, count) \
do { \
struct snd_emu8000 *emu = rec->emu; \
- unsigned short *buf = (__force unsigned short *)(_buf); \
snd_emu8000_write_wait(emu, 1); \
EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); \
if (rec->voices > 1) \
@@ -500,11 +470,11 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
while (count > 0) { \
unsigned short sval; \
CHECK_SCHEDULER(); \
- GET_VAL(sval, buf, mode); \
+ GET_VAL(sval, iter); \
EMU8000_SMLD_WRITE(emu, sval); \
if (rec->voices > 1) { \
CHECK_SCHEDULER(); \
- GET_VAL(sval, buf, mode); \
+ GET_VAL(sval, iter); \
EMU8000_SMRD_WRITE(emu, sval); \
} \
count--; \
@@ -518,27 +488,14 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
*/
static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
int voice, unsigned long pos,
- void __user *src, unsigned long count)
-{
- struct snd_emu8k_pcm *rec = subs->runtime->private_data;
-
- /* convert to frames */
- pos = bytes_to_frames(subs->runtime, pos);
- count = bytes_to_frames(subs->runtime, count);
- LOOP_WRITE(rec, pos, src, count, COPY_USER);
- return 0;
-}
-
-static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs,
- int voice, unsigned long pos,
- void *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct snd_emu8k_pcm *rec = subs->runtime->private_data;
/* convert to frames */
pos = bytes_to_frames(subs->runtime, pos);
count = bytes_to_frames(subs->runtime, count);
- LOOP_WRITE(rec, pos, src, count, COPY_KERNEL);
+ LOOP_WRITE(rec, pos, src, count);
return 0;
}
@@ -550,7 +507,7 @@ static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
/* convert to frames */
pos = bytes_to_frames(subs->runtime, pos);
count = bytes_to_frames(subs->runtime, count);
- LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE);
+ LOOP_WRITE(rec, pos, NULL, count);
return 0;
}
#endif
@@ -666,8 +623,7 @@ static const struct snd_pcm_ops emu8k_pcm_ops = {
.prepare = emu8k_pcm_prepare,
.trigger = emu8k_pcm_trigger,
.pointer = emu8k_pcm_pointer,
- .copy_user = emu8k_pcm_copy,
- .copy_kernel = emu8k_pcm_copy_kernel,
+ .copy = emu8k_pcm_copy,
.fill_silence = emu8k_pcm_silence,
};
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
index 0edfb6875278..9bec85ec55b4 100644
--- a/sound/isa/sb/emu8000_synth.c
+++ b/sound/isa/sb/emu8000_synth.c
@@ -45,7 +45,7 @@ static int snd_emu8000_probe(struct device *_dev)
emu->num_ports = hw->seq_ports;
if (hw->memhdr) {
- snd_printk(KERN_ERR "memhdr is already initialized!?\n");
+ dev_err(hw->card->dev, "memhdr is already initialized!?\n");
snd_util_memhdr_free(hw->memhdr);
}
hw->memhdr = snd_util_memhdr_new(hw->mem_size);
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
index 64936c917170..69d9bfb6c14c 100644
--- a/sound/isa/sb/jazz16.c
+++ b/sound/isa/sb/jazz16.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/string.h>
#include <asm/dma.h>
#include <linux/isa.h>
#include <sound/core.h>
@@ -75,13 +76,14 @@ static irqreturn_t jazz16_interrupt(int irq, void *chip)
return snd_sb8dsp_interrupt(chip);
}
-static int jazz16_configure_ports(unsigned long port,
+static int jazz16_configure_ports(struct snd_card *card,
+ unsigned long port,
unsigned long mpu_port, int idx)
{
unsigned char val;
if (!request_region(0x201, 1, "jazz16 config")) {
- snd_printk(KERN_ERR "config port region is already in use.\n");
+ dev_err(card->dev, "config port region is already in use.\n");
return -EBUSY;
}
outb(SB_JAZZ16_WAKEUP - idx, 0x201);
@@ -96,15 +98,15 @@ static int jazz16_configure_ports(unsigned long port,
return 0;
}
-static int jazz16_detect_board(unsigned long port,
+static int jazz16_detect_board(struct snd_card *card, unsigned long port,
unsigned long mpu_port)
{
int err;
int val;
- struct snd_sb chip;
+ struct snd_sb chip = {};
if (!request_region(port, 0x10, "jazz16")) {
- snd_printk(KERN_ERR "I/O port region is already in use.\n");
+ dev_err(card->dev, "I/O port region is already in use.\n");
return -EBUSY;
}
/* just to call snd_sbdsp_command/reset/get_byte() */
@@ -113,7 +115,7 @@ static int jazz16_detect_board(unsigned long port,
err = snd_sbdsp_reset(&chip);
if (err < 0)
for (val = 0; val < 4; val++) {
- err = jazz16_configure_ports(port, mpu_port, val);
+ err = jazz16_configure_ports(card, port, mpu_port, val);
if (err < 0)
break;
@@ -143,8 +145,8 @@ static int jazz16_detect_board(unsigned long port,
}
snd_sbdsp_get_byte(&chip);
err = snd_sbdsp_get_byte(&chip);
- snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
- val, err);
+ dev_dbg(card->dev, "Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
+ val, err);
err = 0;
@@ -185,31 +187,31 @@ static int snd_jazz16_match(struct device *devptr, unsigned int dev)
if (!enable[dev])
return 0;
if (port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "please specify port\n");
+ dev_err(devptr, "please specify port\n");
return 0;
} else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
- snd_printk(KERN_ERR "incorrect port specified\n");
+ dev_err(devptr, "incorrect port specified\n");
return 0;
}
if (dma8[dev] != SNDRV_AUTO_DMA &&
dma8[dev] != 1 && dma8[dev] != 3) {
- snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
+ dev_err(devptr, "dma8 must be 1 or 3\n");
return 0;
}
if (dma16[dev] != SNDRV_AUTO_DMA &&
dma16[dev] != 5 && dma16[dev] != 7) {
- snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
+ dev_err(devptr, "dma16 must be 5 or 7\n");
return 0;
}
if (mpu_port[dev] != SNDRV_AUTO_PORT &&
(mpu_port[dev] & ~0x030) != 0x300) {
- snd_printk(KERN_ERR "incorrect mpu_port specified\n");
+ dev_err(devptr, "incorrect mpu_port specified\n");
return 0;
}
if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
- snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
+ dev_err(devptr, "mpu_irq must be 2, 3, 5 or 7\n");
return 0;
}
return 1;
@@ -237,7 +239,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
if (xirq < 0) {
- snd_printk(KERN_ERR "unable to find a free IRQ\n");
+ dev_err(devptr, "unable to find a free IRQ\n");
return -EBUSY;
}
}
@@ -245,7 +247,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
if (xdma8 == SNDRV_AUTO_DMA) {
xdma8 = snd_legacy_find_free_dma(possible_dmas8);
if (xdma8 < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA8\n");
+ dev_err(devptr, "unable to find a free DMA8\n");
return -EBUSY;
}
}
@@ -253,7 +255,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
if (xdma16 == SNDRV_AUTO_DMA) {
xdma16 = snd_legacy_find_free_dma(possible_dmas16);
if (xdma16 < 0) {
- snd_printk(KERN_ERR "unable to find a free DMA16\n");
+ dev_err(devptr, "unable to find a free DMA16\n");
return -EBUSY;
}
}
@@ -261,9 +263,9 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
xmpu_port = mpu_port[dev];
if (xmpu_port == SNDRV_AUTO_PORT)
xmpu_port = 0;
- err = jazz16_detect_board(port[dev], xmpu_port);
+ err = jazz16_detect_board(card, port[dev], xmpu_port);
if (err < 0) {
- printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
+ dev_err(devptr, "Media Vision Jazz16 board not detected\n");
return err;
}
err = snd_sbdsp_create(card, port[dev], irq[dev],
@@ -279,14 +281,14 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
xmpu_irq = 0;
err = jazz16_configure_board(chip, xmpu_irq);
if (err < 0) {
- printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
+ dev_err(devptr, "Media Vision Jazz16 configuration failed\n");
return err;
}
jazz16->chip = chip;
- strcpy(card->driver, "jazz16");
- strcpy(card->shortname, "Media Vision Jazz16");
+ strscpy(card->driver, "jazz16");
+ strscpy(card->shortname, "Media Vision Jazz16");
sprintf(card->longname,
"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
port[dev], xirq, xdma8, xdma16);
@@ -301,8 +303,8 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
err = snd_opl3_create(card, chip->port, chip->port + 2,
OPL3_HW_AUTO, 1, &opl3);
if (err < 0)
- snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
- chip->port, chip->port + 2);
+ dev_warn(devptr, "no OPL device at 0x%lx-0x%lx\n",
+ chip->port, chip->port + 2);
else {
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
@@ -317,8 +319,8 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
mpu_port[dev], 0,
mpu_irq[dev],
NULL) < 0)
- snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
- mpu_port[dev]);
+ dev_err(devptr, "no MPU-401 device at 0x%lx\n",
+ mpu_port[dev]);
}
err = snd_card_register(card);
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index e89b095aa282..208d1942a015 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -10,6 +10,7 @@
#include <linux/err.h>
#include <linux/isa.h>
#include <linux/module.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/sb16_csp.h>
@@ -21,12 +22,6 @@
#define SNDRV_LEGACY_FIND_FREE_DMA
#include <sound/initval.h>
-#ifdef SNDRV_SBAWE
-#define PFX "sbawe: "
-#else
-#define PFX "sb16: "
-#endif
-
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
#ifndef SNDRV_SBAWE
@@ -246,7 +241,7 @@ static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
+ dev_err(&pdev->dev, "AUDIO pnp configure failure\n");
return err;
}
port[dev] = pnp_port_start(pdev, 0);
@@ -255,10 +250,10 @@ static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
dma8[dev] = pnp_dma(pdev, 0);
dma16[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
- port[dev], mpu_port[dev], fm_port[dev]);
- snd_printdd("pnp SB16: dma1=%i, dma2=%i, irq=%i\n",
- dma8[dev], dma16[dev], irq[dev]);
+ dev_dbg(&pdev->dev, "pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
+ port[dev], mpu_port[dev], fm_port[dev]);
+ dev_dbg(&pdev->dev, "pnp SB16: dma1=%i, dma2=%i, irq=%i\n",
+ dma8[dev], dma16[dev], irq[dev]);
#ifdef SNDRV_SBAWE_EMU8000
/* WaveTable initialization */
pdev = acard->devwt;
@@ -268,13 +263,13 @@ static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
goto __wt_error;
}
awe_port[dev] = pnp_port_start(pdev, 0);
- snd_printdd("pnp SB16: wavetable port=0x%llx\n",
- (unsigned long long)pnp_port_start(pdev, 0));
+ dev_dbg(&pdev->dev, "pnp SB16: wavetable port=0x%llx\n",
+ (unsigned long long)pnp_port_start(pdev, 0));
} else {
__wt_error:
if (pdev) {
pnp_release_card_device(pdev);
- snd_printk(KERN_ERR PFX "WaveTable pnp configure failure\n");
+ dev_err(&pdev->dev, "WaveTable pnp configure failure\n");
}
acard->devwt = NULL;
awe_port[dev] = -1;
@@ -315,7 +310,6 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
#ifdef CONFIG_SND_SB16_CSP
struct snd_hwdep *xcsp = NULL;
#endif
- unsigned long flags;
int err;
xirq = irq[dev];
@@ -329,7 +323,7 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
acard->chip = chip;
if (chip->hardware != SB_HW_16) {
- snd_printk(KERN_ERR PFX "SB 16 chip was not detected at 0x%lx\n", port[dev]);
+ dev_err(card->dev, "SB 16 chip was not detected at 0x%lx\n", port[dev]);
return -ENODEV;
}
chip->mpu_port = mpu_port[dev];
@@ -343,12 +337,12 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
if (err < 0)
return err;
- strcpy(card->driver,
+ strscpy(card->driver,
#ifdef SNDRV_SBAWE_EMU8000
awe_port[dev] > 0 ? "SB AWE" :
#endif
"SB16");
- strcpy(card->shortname, chip->name);
+ strscpy(card->shortname, chip->name);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma ",
chip->name,
chip->port,
@@ -379,8 +373,8 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
OPL3_HW_OPL3,
acard->fm_res != NULL || fm_port[dev] == port[dev],
&opl3) < 0) {
- snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
- fm_port[dev], fm_port[dev] + 2);
+ dev_err(card->dev, "no OPL device at 0x%lx-0x%lx\n",
+ fm_port[dev], fm_port[dev] + 2);
} else {
#ifdef SNDRV_SBAWE_EMU8000
int seqdev = awe_port[dev] > 0 ? 2 : 1;
@@ -405,7 +399,9 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
chip->csp = xcsp->private_data;
chip->hardware = SB_HW_16CSP;
} else {
- snd_printk(KERN_INFO PFX "warning - CSP chip not detected on soundcard #%i\n", dev + 1);
+ dev_info(card->dev,
+ "warning - CSP chip not detected on soundcard #%i\n",
+ dev + 1);
}
}
#endif
@@ -414,7 +410,9 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
err = snd_emu8000_new(card, 1, awe_port[dev],
seq_ports[dev], NULL);
if (err < 0) {
- snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]);
+ dev_err(card->dev,
+ "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n",
+ awe_port[dev]);
return err;
}
@@ -422,11 +420,11 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
#endif
/* setup Mic AGC */
- spin_lock_irqsave(&chip->mixer_lock, flags);
- snd_sbmixer_write(chip, SB_DSP4_MIC_AGC,
- (snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) |
- (mic_agc[dev] ? 0x00 : 0x01));
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ snd_sbmixer_write(chip, SB_DSP4_MIC_AGC,
+ (snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) |
+ (mic_agc[dev] ? 0x00 : 0x01));
+ }
err = snd_card_register(card);
if (err < 0)
@@ -502,21 +500,21 @@ static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
if (irq[dev] == SNDRV_AUTO_IRQ) {
irq[dev] = snd_legacy_find_free_irq(possible_irqs);
if (irq[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
+ dev_err(pdev, "unable to find a free IRQ\n");
return -EBUSY;
}
}
if (dma8[dev] == SNDRV_AUTO_DMA) {
dma8[dev] = snd_legacy_find_free_dma(possible_dmas8);
if (dma8[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n");
+ dev_err(pdev, "unable to find a free 8-bit DMA\n");
return -EBUSY;
}
}
if (dma16[dev] == SNDRV_AUTO_DMA) {
dma16[dev] = snd_legacy_find_free_dma(possible_dmas16);
if (dma16[dev] < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n");
+ dev_err(pdev, "unable to find a free 16-bit DMA\n");
return -EBUSY;
}
}
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 7ad8c5f7b664..9ad71a9fc18d 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>
@@ -264,14 +265,10 @@ static int snd_sb_csp_release(struct snd_hwdep * hw, struct file *file)
*/
static int snd_sb_csp_use(struct snd_sb_csp * p)
{
- mutex_lock(&p->access_mutex);
- if (p->used) {
- mutex_unlock(&p->access_mutex);
+ guard(mutex)(&p->access_mutex);
+ if (p->used)
return -EAGAIN;
- }
p->used++;
- mutex_unlock(&p->access_mutex);
-
return 0;
}
@@ -281,10 +278,8 @@ static int snd_sb_csp_use(struct snd_sb_csp * p)
*/
static int snd_sb_csp_unuse(struct snd_sb_csp * p)
{
- mutex_lock(&p->access_mutex);
+ guard(mutex)(&p->access_mutex);
p->used--;
- mutex_unlock(&p->access_mutex);
-
return 0;
}
@@ -296,6 +291,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
struct snd_sb_csp_microcode __user * mcode)
{
struct snd_sb_csp_mc_header info;
+ struct device *dev = p->chip->card->dev;
unsigned char __user *data_ptr;
unsigned char __user *data_end;
@@ -305,7 +301,6 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
__le32 item_type;
struct desc_header funcdesc_h;
- unsigned long flags;
int err;
if (copy_from_user(&info, mcode, sizeof(info)))
@@ -316,7 +311,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
return -EFAULT;
if ((le32_to_cpu(file_h.name) != RIFF_HEADER) ||
(le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {
- snd_printd("%s: Invalid RIFF header\n", __func__);
+ dev_dbg(dev, "%s: Invalid RIFF header\n", __func__);
return -EINVAL;
}
data_ptr += sizeof(file_h);
@@ -325,7 +320,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
return -EFAULT;
if (le32_to_cpu(item_type) != CSP__HEADER) {
- snd_printd("%s: Invalid RIFF file type\n", __func__);
+ dev_dbg(dev, "%s: Invalid RIFF file type\n", __func__);
return -EINVAL;
}
data_ptr += sizeof (item_type);
@@ -380,7 +375,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
return -EFAULT;
if (le32_to_cpu(code_h.name) != MAIN_HEADER) {
- snd_printd("%s: Missing 'main' microcode\n", __func__);
+ dev_dbg(dev, "%s: Missing 'main' microcode\n", __func__);
return -EINVAL;
}
data_ptr += sizeof(code_h);
@@ -423,9 +418,9 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
default: /* other codecs are unsupported */
p->acc_format = p->acc_width = p->acc_rates = 0;
p->mode = 0;
- snd_printd("%s: Unsupported CSP codec type: 0x%04x\n",
- __func__,
- le16_to_cpu(funcdesc_h.VOC_type));
+ dev_dbg(dev, "%s: Unsupported CSP codec type: 0x%04x\n",
+ __func__,
+ le16_to_cpu(funcdesc_h.VOC_type));
return -EINVAL;
}
p->acc_channels = le16_to_cpu(funcdesc_h.flags_stereo_mono);
@@ -433,17 +428,16 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
p->acc_rates = le16_to_cpu(funcdesc_h.flags_rates);
/* Decouple CSP from IRQ and DMAREQ lines */
- spin_lock_irqsave(&p->chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&p->chip->reg_lock);
set_mode_register(p->chip, 0xfc);
set_mode_register(p->chip, 0x00);
- spin_unlock_irqrestore(&p->chip->reg_lock, flags);
/* finished loading successfully */
p->running = SNDRV_SB_CSP_ST_LOADED; /* set LOADED flag */
return 0;
}
}
- snd_printd("%s: Function #%d not found\n", __func__, info.func_req);
+ dev_dbg(dev, "%s: Function #%d not found\n", __func__, info.func_req);
return -EINVAL;
}
@@ -546,10 +540,8 @@ static int set_mode_register(struct snd_sb *chip, unsigned char mode)
static int csp_detect(struct snd_sb *chip, int *version)
{
unsigned char csp_test1, csp_test2;
- unsigned long flags;
- int result = -ENODEV;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
set_codec_parameter(chip, 0x00, 0x00);
set_mode_register(chip, 0xfc); /* 0xfc = ?? */
@@ -558,23 +550,21 @@ static int csp_detect(struct snd_sb *chip, int *version)
set_register(chip, 0x83, ~csp_test1);
csp_test2 = read_register(chip, 0x83);
if (csp_test2 != (csp_test1 ^ 0xff))
- goto __fail;
+ return -ENODEV;
set_register(chip, 0x83, csp_test1);
csp_test2 = read_register(chip, 0x83);
if (csp_test2 != csp_test1)
- goto __fail;
+ return -ENODEV;
set_mode_register(chip, 0x00); /* 0x00 = ? */
*version = get_version(chip);
snd_sbdsp_reset(chip); /* reset DSP after getversion! */
if (*version >= 0x10 && *version <= 0x1f)
- result = 0; /* valid version id */
+ return 0; /* valid version id */
- __fail:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return result;
+ return -ENODEV;
}
/*
@@ -597,7 +587,9 @@ static int get_version(struct snd_sb *chip)
static int snd_sb_csp_check_version(struct snd_sb_csp * p)
{
if (p->version < 0x10 || p->version > 0x1f) {
- snd_printd("%s: Invalid CSP version: 0x%x\n", __func__, p->version);
+ dev_dbg(p->chip->card->dev,
+ "%s: Invalid CSP version: 0x%x\n",
+ __func__, p->version);
return 1;
}
return 0;
@@ -610,14 +602,12 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
{
int status, i;
int err;
- int result = -EIO;
- unsigned long flags;
- spin_lock_irqsave(&p->chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&p->chip->reg_lock);
snd_sbdsp_command(p->chip, 0x01); /* CSP download command */
if (snd_sbdsp_get_byte(p->chip)) {
- snd_printd("%s: Download command failed\n", __func__);
- goto __fail;
+ dev_dbg(p->chip->card->dev, "%s: Download command failed\n", __func__);
+ return -EIO;
}
/* Send CSP low byte (size - 1) */
snd_sbdsp_command(p->chip, (unsigned char)(size - 1));
@@ -627,10 +617,10 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
/* load from kernel space */
while (size--) {
if (!snd_sbdsp_command(p->chip, *buf++))
- goto __fail;
+ return -EIO;
}
if (snd_sbdsp_get_byte(p->chip))
- goto __fail;
+ return -EIO;
if (load_flags & SNDRV_SB_CSP_LOAD_INITBLOCK) {
i = 0;
@@ -643,8 +633,10 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
udelay (10);
}
if (status != 0x55) {
- snd_printd("%s: Microcode initialization failed\n", __func__);
- goto __fail;
+ dev_dbg(p->chip->card->dev,
+ "%s: Microcode initialization failed\n",
+ __func__);
+ return -EIO;
}
} else {
/*
@@ -652,24 +644,21 @@ static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int
* Start CSP chip if no 16bit DMA channel is set - some kind
* of autorun or perhaps a bugfix?
*/
- spin_lock(&p->chip->mixer_lock);
- status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP);
- spin_unlock(&p->chip->mixer_lock);
+ scoped_guard(spinlock, &p->chip->mixer_lock) {
+ status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP);
+ }
if (!(status & (SB_DMASETUP_DMA7 | SB_DMASETUP_DMA6 | SB_DMASETUP_DMA5))) {
err = (set_codec_parameter(p->chip, 0xaa, 0x00) ||
set_codec_parameter(p->chip, 0xff, 0x00));
snd_sbdsp_reset(p->chip); /* really! */
if (err)
- goto __fail;
+ return -EIO;
set_mode_register(p->chip, 0xc0); /* c0 = STOP */
set_mode_register(p->chip, 0x70); /* 70 = RUN */
}
}
- result = 0;
- __fail:
- spin_unlock_irqrestore(&p->chip->reg_lock, flags);
- return result;
+ return 0;
}
static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags)
@@ -716,7 +705,6 @@ static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
*/
static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode)
{
- unsigned long flags;
int err = 0;
/* if CSP is running or manually loaded then exit */
@@ -757,10 +745,9 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt,
default:
/* Decouple CSP from IRQ and DMAREQ lines */
if (p->running & SNDRV_SB_CSP_ST_AUTO) {
- spin_lock_irqsave(&p->chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&p->chip->reg_lock);
set_mode_register(p->chip, 0xfc);
set_mode_register(p->chip, 0x00);
- spin_unlock_irqrestore(&p->chip->reg_lock, flags);
p->running = 0; /* clear autoloaded flag */
}
return -EINVAL;
@@ -788,78 +775,77 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt,
*/
static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channels)
{
+ struct device *dev = p->chip->card->dev;
unsigned char s_type; /* sample type */
unsigned char mixL, mixR;
int result = -EIO;
- unsigned long flags;
if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {
- snd_printd("%s: Microcode not loaded\n", __func__);
+ dev_dbg(dev, "%s: Microcode not loaded\n", __func__);
return -ENXIO;
}
if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
- snd_printd("%s: CSP already running\n", __func__);
+ dev_dbg(dev, "%s: CSP already running\n", __func__);
return -EBUSY;
}
if (!(sample_width & p->acc_width)) {
- snd_printd("%s: Unsupported PCM sample width\n", __func__);
+ dev_dbg(dev, "%s: Unsupported PCM sample width\n", __func__);
return -EINVAL;
}
if (!(channels & p->acc_channels)) {
- snd_printd("%s: Invalid number of channels\n", __func__);
+ dev_dbg(dev, "%s: Invalid number of channels\n", __func__);
return -EINVAL;
}
/* Mute PCM volume */
- spin_lock_irqsave(&p->chip->mixer_lock, flags);
- mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
- mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
- spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
-
- spin_lock(&p->chip->reg_lock);
- set_mode_register(p->chip, 0xc0); /* c0 = STOP */
- set_mode_register(p->chip, 0x70); /* 70 = RUN */
-
- s_type = 0x00;
- if (channels == SNDRV_SB_CSP_MONO)
- s_type = 0x11; /* 000n 000n (n = 1 if mono) */
- if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT)
- s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */
-
- if (set_codec_parameter(p->chip, 0x81, s_type)) {
- snd_printd("%s: Set sample type command failed\n", __func__);
- goto __fail;
- }
- if (set_codec_parameter(p->chip, 0x80, 0x00)) {
- snd_printd("%s: Codec start command failed\n", __func__);
- goto __fail;
+ scoped_guard(spinlock_irqsave, &p->chip->mixer_lock) {
+ mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
+ mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
}
- p->run_width = sample_width;
- p->run_channels = channels;
- p->running |= SNDRV_SB_CSP_ST_RUNNING;
+ scoped_guard(spinlock, &p->chip->reg_lock) {
+ set_mode_register(p->chip, 0xc0); /* c0 = STOP */
+ set_mode_register(p->chip, 0x70); /* 70 = RUN */
- if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) {
- set_codec_parameter(p->chip, 0xe0, 0x01);
- /* enable QSound decoder */
- set_codec_parameter(p->chip, 0x00, 0xff);
- set_codec_parameter(p->chip, 0x01, 0xff);
- p->running |= SNDRV_SB_CSP_ST_QSOUND;
- /* set QSound startup value */
- snd_sb_csp_qsound_transfer(p);
- }
- result = 0;
+ s_type = 0x00;
+ if (channels == SNDRV_SB_CSP_MONO)
+ s_type = 0x11; /* 000n 000n (n = 1 if mono) */
+ if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT)
+ s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */
- __fail:
- spin_unlock(&p->chip->reg_lock);
+ if (set_codec_parameter(p->chip, 0x81, s_type)) {
+ dev_dbg(dev, "%s: Set sample type command failed\n", __func__);
+ break;
+ }
+ if (set_codec_parameter(p->chip, 0x80, 0x00)) {
+ dev_dbg(dev, "%s: Codec start command failed\n", __func__);
+ break;
+ }
+ p->run_width = sample_width;
+ p->run_channels = channels;
+
+ p->running |= SNDRV_SB_CSP_ST_RUNNING;
+
+ if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) {
+ set_codec_parameter(p->chip, 0xe0, 0x01);
+ /* enable QSound decoder */
+ set_codec_parameter(p->chip, 0x00, 0xff);
+ set_codec_parameter(p->chip, 0x01, 0xff);
+ p->running |= SNDRV_SB_CSP_ST_QSOUND;
+ /* set QSound startup value */
+ snd_sb_csp_qsound_transfer(p);
+ }
+ result = 0;
+ }
/* restore PCM volume */
- spin_lock_irqsave(&p->chip->mixer_lock, flags);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
- spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
+ if (result < 0) {
+ guard(spinlock_irqsave)(&p->chip->mixer_lock);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
+ }
return result;
}
@@ -871,36 +857,35 @@ static int snd_sb_csp_stop(struct snd_sb_csp * p)
{
int result;
unsigned char mixL, mixR;
- unsigned long flags;
if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))
return 0;
/* Mute PCM volume */
- spin_lock_irqsave(&p->chip->mixer_lock, flags);
- mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
- mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
- spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
-
- spin_lock(&p->chip->reg_lock);
- if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
- set_codec_parameter(p->chip, 0xe0, 0x01);
- /* disable QSound decoder */
- set_codec_parameter(p->chip, 0x00, 0x00);
- set_codec_parameter(p->chip, 0x01, 0x00);
+ scoped_guard(spinlock_irqsave, &p->chip->mixer_lock) {
+ mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
+ mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
+ }
+
+ scoped_guard(spinlock, &p->chip->reg_lock) {
+ if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
+ set_codec_parameter(p->chip, 0xe0, 0x01);
+ /* disable QSound decoder */
+ set_codec_parameter(p->chip, 0x00, 0x00);
+ set_codec_parameter(p->chip, 0x01, 0x00);
- p->running &= ~SNDRV_SB_CSP_ST_QSOUND;
+ p->running &= ~SNDRV_SB_CSP_ST_QSOUND;
+ }
+ result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */
}
- result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */
- spin_unlock(&p->chip->reg_lock);
/* restore PCM volume */
- spin_lock_irqsave(&p->chip->mixer_lock, flags);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
- snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
- spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &p->chip->mixer_lock) {
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
+ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
+ }
if (!(result))
p->running &= ~(SNDRV_SB_CSP_ST_PAUSED | SNDRV_SB_CSP_ST_RUNNING);
@@ -913,14 +898,13 @@ static int snd_sb_csp_stop(struct snd_sb_csp * p)
static int snd_sb_csp_pause(struct snd_sb_csp * p)
{
int result;
- unsigned long flags;
if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))
return -EBUSY;
- spin_lock_irqsave(&p->chip->reg_lock, flags);
- result = set_codec_parameter(p->chip, 0x80, 0xff);
- spin_unlock_irqrestore(&p->chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &p->chip->reg_lock) {
+ result = set_codec_parameter(p->chip, 0x80, 0xff);
+ }
if (!(result))
p->running |= SNDRV_SB_CSP_ST_PAUSED;
@@ -933,14 +917,13 @@ static int snd_sb_csp_pause(struct snd_sb_csp * p)
static int snd_sb_csp_restart(struct snd_sb_csp * p)
{
int result;
- unsigned long flags;
if (!(p->running & SNDRV_SB_CSP_ST_PAUSED))
return -EBUSY;
- spin_lock_irqsave(&p->chip->reg_lock, flags);
- result = set_codec_parameter(p->chip, 0x80, 0x00);
- spin_unlock_irqrestore(&p->chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &p->chip->reg_lock) {
+ result = set_codec_parameter(p->chip, 0x80, 0x00);
+ }
if (!(result))
p->running &= ~SNDRV_SB_CSP_ST_PAUSED;
@@ -966,15 +949,13 @@ static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_sb_qsound_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned char nval;
nval = ucontrol->value.integer.value[0] & 0x01;
- spin_lock_irqsave(&p->q_lock, flags);
+ guard(spinlock_irqsave)(&p->q_lock);
change = p->q_enabled != nval;
p->q_enabled = nval;
- spin_unlock_irqrestore(&p->q_lock, flags);
return change;
}
@@ -990,19 +971,16 @@ static int snd_sb_qsound_space_info(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_sb_qsound_space_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&p->q_lock, flags);
+ guard(spinlock_irqsave)(&p->q_lock);
ucontrol->value.integer.value[0] = p->qpos_left;
ucontrol->value.integer.value[1] = p->qpos_right;
- spin_unlock_irqrestore(&p->q_lock, flags);
return 0;
}
static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned char nval1, nval2;
@@ -1012,12 +990,11 @@ static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl
nval2 = ucontrol->value.integer.value[1];
if (nval2 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)
nval2 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
- spin_lock_irqsave(&p->q_lock, flags);
+ guard(spinlock_irqsave)(&p->q_lock);
change = p->qpos_left != nval1 || p->qpos_right != nval2;
p->qpos_left = nval1;
p->qpos_right = nval2;
p->qpos_changed = change;
- spin_unlock_irqrestore(&p->q_lock, flags);
return change;
}
@@ -1073,28 +1050,20 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p)
static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
{
struct snd_card *card;
- unsigned long flags;
if (snd_BUG_ON(!p))
return;
card = p->chip->card;
- down_write(&card->controls_rwsem);
- if (p->qsound_switch) {
- snd_ctl_remove(card, p->qsound_switch);
- p->qsound_switch = NULL;
- }
- if (p->qsound_space) {
- snd_ctl_remove(card, p->qsound_space);
- p->qsound_space = NULL;
- }
- up_write(&card->controls_rwsem);
+ snd_ctl_remove(card, p->qsound_switch);
+ p->qsound_switch = NULL;
+ snd_ctl_remove(card, p->qsound_space);
+ p->qsound_space = NULL;
/* cancel pending transfer of QSound parameters */
- spin_lock_irqsave (&p->q_lock, flags);
+ guard(spinlock_irqsave)(&p->q_lock);
p->qpos_changed = 0;
- spin_unlock_irqrestore (&p->q_lock, flags);
}
/*
@@ -1105,7 +1074,7 @@ static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p)
{
int err = -ENXIO;
- spin_lock(&p->q_lock);
+ guard(spinlock)(&p->q_lock);
if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
set_codec_parameter(p->chip, 0xe0, 0x01);
/* left channel */
@@ -1117,7 +1086,6 @@ static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p)
err = 0;
}
p->qpos_changed = 0;
- spin_unlock(&p->q_lock);
return err;
}
@@ -1157,8 +1125,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/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index a9b87e159b2d..4d64db4f5852 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -130,9 +130,8 @@ static void snd_sb16_csp_update(struct snd_sb *chip)
struct snd_sb_csp *csp = chip->csp;
if (csp->qpos_changed) {
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
csp->ops.csp_qsound_transfer (csp);
- spin_unlock(&chip->reg_lock);
}
}
}
@@ -213,9 +212,7 @@ static void snd_sb16_setup_rate(struct snd_sb *chip,
unsigned short rate,
int channel)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16))
snd_sb_ack_16bit(chip);
else
@@ -229,12 +226,10 @@ static void snd_sb16_setup_rate(struct snd_sb *chip,
snd_sbdsp_command(chip, rate >> 8);
snd_sbdsp_command(chip, rate & 0xff);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static int snd_sb16_playback_prepare(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned char format;
@@ -253,7 +248,7 @@ static int snd_sb16_playback_prepare(struct snd_pcm_substream *substream)
snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
count = snd_pcm_lib_period_bytes(substream);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (chip->mode & SB_MODE_PLAYBACK_16) {
count >>= 1;
count--;
@@ -270,7 +265,6 @@ static int snd_sb16_playback_prepare(struct snd_pcm_substream *substream)
snd_sbdsp_command(chip, count >> 8);
snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -278,9 +272,8 @@ static int snd_sb16_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
- int result = 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -296,15 +289,13 @@ static int snd_sb16_playback_trigger(struct snd_pcm_substream *substream,
chip->mode &= ~SB_RATE_LOCK_PLAYBACK;
break;
default:
- result = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
- return result;
+ return 0;
}
static int snd_sb16_capture_prepare(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned char format;
@@ -322,7 +313,7 @@ static int snd_sb16_capture_prepare(struct snd_pcm_substream *substream)
snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
count = snd_pcm_lib_period_bytes(substream);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (chip->mode & SB_MODE_CAPTURE_16) {
count >>= 1;
count--;
@@ -339,7 +330,6 @@ static int snd_sb16_capture_prepare(struct snd_pcm_substream *substream)
snd_sbdsp_command(chip, count >> 8);
snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -347,9 +337,8 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
- int result = 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -365,10 +354,9 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream,
chip->mode &= ~SB_RATE_LOCK_CAPTURE;
break;
default:
- result = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
- return result;
+ return 0;
}
irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
@@ -377,9 +365,9 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
unsigned char status;
int ok;
- spin_lock(&chip->mixer_lock);
- status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
- spin_unlock(&chip->mixer_lock);
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
+ }
if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)
chip->rmidi_callback(irq, chip->rmidi->private_data);
if (status & SB_IRQTYPE_8BIT) {
@@ -393,11 +381,11 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
snd_pcm_period_elapsed(chip->capture_substream);
ok++;
}
- spin_lock(&chip->reg_lock);
- if (!ok)
- snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
- snd_sb_ack_8bit(chip);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ if (!ok)
+ snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
+ snd_sb_ack_8bit(chip);
+ }
}
if (status & SB_IRQTYPE_16BIT) {
ok = 0;
@@ -410,11 +398,11 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
snd_pcm_period_elapsed(chip->capture_substream);
ok++;
}
- spin_lock(&chip->reg_lock);
- if (!ok)
- snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);
- snd_sb_ack_16bit(chip);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ if (!ok)
+ snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);
+ snd_sb_ack_16bit(chip);
+ }
}
return IRQ_HANDLED;
}
@@ -491,15 +479,12 @@ static const struct snd_pcm_hardware snd_sb16_capture =
static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- spin_lock_irqsave(&chip->open_lock, flags);
- if (chip->mode & SB_MODE_PLAYBACK) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
+ if (chip->mode & SB_MODE_PLAYBACK)
return -EAGAIN;
- }
runtime->hw = snd_sb16_playback;
/* skip if 16 bit DMA was reserved for capture */
@@ -533,7 +518,6 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
runtime->hw.period_bytes_max = 64 * 1024;
goto __open_ok;
}
- spin_unlock_irqrestore(&chip->open_lock, flags);
return -EAGAIN;
__open_ok:
@@ -547,34 +531,28 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
if (chip->mode & SB_RATE_LOCK)
runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
chip->playback_substream = substream;
- spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
static int snd_sb16_playback_close(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
snd_sb16_csp_playback_close(chip);
- spin_lock_irqsave(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
chip->playback_substream = NULL;
chip->mode &= ~SB_MODE_PLAYBACK;
- spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- spin_lock_irqsave(&chip->open_lock, flags);
- if (chip->mode & SB_MODE_CAPTURE) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
+ if (chip->mode & SB_MODE_CAPTURE)
return -EAGAIN;
- }
runtime->hw = snd_sb16_capture;
/* skip if 16 bit DMA was reserved for playback */
@@ -608,7 +586,6 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
runtime->hw.period_bytes_max = 64 * 1024;
goto __open_ok;
}
- spin_unlock_irqrestore(&chip->open_lock, flags);
return -EAGAIN;
__open_ok:
@@ -622,20 +599,17 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
if (chip->mode & SB_RATE_LOCK)
runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
chip->capture_substream = substream;
- spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
static int snd_sb16_capture_close(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
snd_sb16_csp_capture_close(chip);
- spin_lock_irqsave(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
chip->capture_substream = NULL;
chip->mode &= ~SB_MODE_CAPTURE;
- spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
@@ -688,29 +662,33 @@ static int snd_sb16_dma_control_info(struct snd_kcontrol *kcontrol, struct snd_c
static int snd_sb16_dma_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.enumerated.item[0] = snd_sb16_get_dma_mode(chip);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_sb16_dma_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned char nval, oval;
int change;
+ if (chip->mode & (SB_MODE_PLAYBACK | SB_MODE_CAPTURE))
+ return -EBUSY;
+
nval = ucontrol->value.enumerated.item[0];
if (nval > 2)
return -EINVAL;
- spin_lock_irqsave(&chip->reg_lock, flags);
- oval = snd_sb16_get_dma_mode(chip);
- change = nval != oval;
- snd_sb16_set_dma_mode(chip, nval);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ oval = snd_sb16_get_dma_mode(chip);
+ change = nval != oval;
+ snd_sb16_set_dma_mode(chip, nval);
+ }
+ if (change) {
+ snd_dma_disable(chip->dma8);
+ snd_dma_disable(chip->dma16);
+ }
return change;
}
@@ -728,15 +706,13 @@ static const struct snd_kcontrol_new snd_sb16_dma_control = {
int snd_sb16dsp_configure(struct snd_sb * chip)
{
- unsigned long flags;
unsigned char irqreg = 0, dmareg = 0, mpureg;
unsigned char realirq, realdma, realmpureg;
/* note: mpu register should be present only on SB16 Vibra soundcards */
- // printk(KERN_DEBUG "codec->irq=%i, codec->dma8=%i, codec->dma16=%i\n", chip->irq, chip->dma8, chip->dma16);
- spin_lock_irqsave(&chip->mixer_lock, flags);
- mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06;
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06;
+ }
switch (chip->irq) {
case 2:
case 9:
@@ -794,22 +770,27 @@ int snd_sb16dsp_configure(struct snd_sb * chip)
default:
mpureg |= 0x02; /* disable MPU */
}
- spin_lock_irqsave(&chip->mixer_lock, flags);
- snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg);
- realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg);
+ realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP);
- snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg);
- realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP);
+ snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg);
+ realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP);
- snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg);
- realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP);
-
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg);
+ realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP);
+ }
if ((~realirq) & irqreg || (~realdma) & dmareg) {
- snd_printk(KERN_ERR "SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", chip->port);
- snd_printk(KERN_ERR "SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, realirq, realdma, realmpureg);
- snd_printk(KERN_ERR "SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, irqreg, dmareg, mpureg);
+ dev_err(chip->card->dev,
+ "SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n",
+ chip->port);
+ dev_err(chip->card->dev,
+ "SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n",
+ chip->port, realirq, realdma, realmpureg);
+ dev_err(chip->card->dev,
+ "SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n",
+ chip->port, irqreg, dmareg, mpureg);
return -ENODEV;
}
return 0;
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index e5ef1777161f..6d5131265913 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -9,6 +9,7 @@
#include <linux/isa.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/opl3.h>
@@ -123,11 +124,11 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
if (chip->hardware >= SB_HW_16) {
if (chip->hardware == SB_HW_ALS100)
- snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
- port[dev]);
+ dev_warn(pdev, "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
+ port[dev]);
else
- snd_printk(KERN_WARNING "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
- port[dev]);
+ dev_warn(pdev, "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
+ port[dev]);
return -ENODEV;
}
@@ -143,12 +144,12 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
err = snd_opl3_create(card, chip->port + 8, 0,
OPL3_HW_AUTO, 1, &opl3);
if (err < 0)
- snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8);
+ dev_warn(pdev, "sb8: no OPL device at 0x%lx\n", chip->port + 8);
} else {
err = snd_opl3_create(card, chip->port, chip->port + 2,
OPL3_HW_AUTO, 1, &opl3);
if (err < 0) {
- snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n",
+ dev_warn(pdev, "sb8: no OPL device at 0x%lx-0x%lx\n",
chip->port, chip->port + 2);
}
}
@@ -162,8 +163,8 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
if (err < 0)
return err;
- strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
- strcpy(card->shortname, chip->name);
+ strscpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
+ strscpy(card->shortname, chip->name);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
chip->name,
chip->port,
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
index 2ed176a5a574..a4b5725255cf 100644
--- a/sound/isa/sb/sb8_main.c
+++ b/sound/isa/sb/sb8_main.c
@@ -89,7 +89,6 @@ static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params,
static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int mixreg, rate, size, count;
@@ -142,48 +141,48 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
}
size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
- if (chip->hardware == SB_HW_JAZZ16)
- snd_sbdsp_command(chip, format);
- else if (stereo) {
- /* set playback stereo mode */
- spin_lock(&chip->mixer_lock);
- mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
- snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02);
- spin_unlock(&chip->mixer_lock);
-
- /* Soundblaster hardware programming reference guide, 3-23 */
- snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
- runtime->dma_area[0] = 0x80;
- snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
- /* force interrupt */
- snd_sbdsp_command(chip, SB_DSP_OUTPUT);
- snd_sbdsp_command(chip, 0);
- snd_sbdsp_command(chip, 0);
- }
- snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
- if (stereo) {
- snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
- spin_lock(&chip->mixer_lock);
- /* save output filter status and turn it off */
- mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT);
- snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20);
- spin_unlock(&chip->mixer_lock);
- /* just use force_mode16 for temporary storate... */
- chip->force_mode16 = mixreg;
- } else {
- snd_sbdsp_command(chip, 256 - runtime->rate_den);
- }
- if (chip->playback_format != SB_DSP_OUTPUT) {
- if (chip->mode & SB_MODE_PLAYBACK_16)
- count /= 2;
- count--;
- snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
- snd_sbdsp_command(chip, count & 0xff);
- snd_sbdsp_command(chip, count >> 8);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
+ if (chip->hardware == SB_HW_JAZZ16)
+ snd_sbdsp_command(chip, format);
+ else if (stereo) {
+ /* set playback stereo mode */
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
+ snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02);
+ }
+
+ /* Soundblaster hardware programming reference guide, 3-23 */
+ snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
+ runtime->dma_area[0] = 0x80;
+ snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
+ /* force interrupt */
+ snd_sbdsp_command(chip, SB_DSP_OUTPUT);
+ snd_sbdsp_command(chip, 0);
+ snd_sbdsp_command(chip, 0);
+ }
+ snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
+ if (stereo) {
+ snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ /* save output filter status and turn it off */
+ mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT);
+ snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20);
+ }
+ /* just use force_mode16 for temporary storate... */
+ chip->force_mode16 = mixreg;
+ } else {
+ snd_sbdsp_command(chip, 256 - runtime->rate_den);
+ }
+ if (chip->playback_format != SB_DSP_OUTPUT) {
+ if (chip->mode & SB_MODE_PLAYBACK_16)
+ count /= 2;
+ count--;
+ snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
+ snd_sbdsp_command(chip, count & 0xff);
+ snd_sbdsp_command(chip, count >> 8);
+ }
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_dma_program(dma, runtime->dma_addr,
size, DMA_MODE_WRITE | DMA_AUTOINIT);
return 0;
@@ -192,11 +191,10 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
unsigned int count;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_sbdsp_command(chip, chip->playback_format);
@@ -211,23 +209,20 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
snd_sbdsp_reset(chip);
if (runtime->channels > 1) {
- spin_lock(&chip->mixer_lock);
+ guard(spinlock)(&chip->mixer_lock);
/* restore output filter and set hardware to mono mode */
snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02);
- spin_unlock(&chip->mixer_lock);
}
} else {
snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
}
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int mixreg, rate, size, count;
@@ -281,34 +276,34 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
}
size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
- if (chip->hardware == SB_HW_JAZZ16)
- snd_sbdsp_command(chip, format);
- else if (stereo)
- snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
- snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
- if (stereo) {
- snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
- spin_lock(&chip->mixer_lock);
- /* save input filter status and turn it off */
- mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);
- snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);
- spin_unlock(&chip->mixer_lock);
- /* just use force_mode16 for temporary storate... */
- chip->force_mode16 = mixreg;
- } else {
- snd_sbdsp_command(chip, 256 - runtime->rate_den);
- }
- if (chip->capture_format != SB_DSP_INPUT) {
- if (chip->mode & SB_MODE_PLAYBACK_16)
- count /= 2;
- count--;
- snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
- snd_sbdsp_command(chip, count & 0xff);
- snd_sbdsp_command(chip, count >> 8);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
+ if (chip->hardware == SB_HW_JAZZ16)
+ snd_sbdsp_command(chip, format);
+ else if (stereo)
+ snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
+ snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
+ if (stereo) {
+ snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ /* save input filter status and turn it off */
+ mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);
+ snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);
+ }
+ /* just use force_mode16 for temporary storate... */
+ chip->force_mode16 = mixreg;
+ } else {
+ snd_sbdsp_command(chip, 256 - runtime->rate_den);
+ }
+ if (chip->capture_format != SB_DSP_INPUT) {
+ if (chip->mode & SB_MODE_PLAYBACK_16)
+ count /= 2;
+ count--;
+ snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
+ snd_sbdsp_command(chip, count & 0xff);
+ snd_sbdsp_command(chip, count >> 8);
+ }
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_dma_program(dma, runtime->dma_addr,
size, DMA_MODE_READ | DMA_AUTOINIT);
return 0;
@@ -317,11 +312,10 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
unsigned int count;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_sbdsp_command(chip, chip->capture_format);
@@ -337,9 +331,9 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
snd_sbdsp_reset(chip);
if (runtime->channels > 1) {
/* restore input filter status */
- spin_lock(&chip->mixer_lock);
- snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);
- spin_unlock(&chip->mixer_lock);
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);
+ }
/* set hardware to mono mode */
snd_sbdsp_command(chip, SB_DSP_MONO_8BIT);
}
@@ -348,7 +342,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
}
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -464,15 +457,12 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
{
struct snd_sb *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- spin_lock_irqsave(&chip->open_lock, flags);
- if (chip->open) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- return -EAGAIN;
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ if (chip->open)
+ return -EAGAIN;
+ chip->open |= SB_OPEN_PCM;
}
- chip->open |= SB_OPEN_PCM;
- spin_unlock_irqrestore(&chip->open_lock, flags);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
chip->playback_substream = substream;
runtime->hw = snd_sb8_playback;
@@ -525,18 +515,16 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
static int snd_sb8_close(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip = snd_pcm_substream_chip(substream);
chip->playback_substream = NULL;
chip->capture_substream = NULL;
- spin_lock_irqsave(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
chip->open &= ~SB_OPEN_PCM;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
chip->mode &= ~SB_MODE_PLAYBACK;
else
chip->mode &= ~SB_MODE_CAPTURE;
- spin_unlock_irqrestore(&chip->open_lock, flags);
return 0;
}
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
index 618366d5d984..1d41f2470697 100644
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -14,6 +14,7 @@
*/
#include <linux/io.h>
+#include <linux/string.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/sb.h>
@@ -34,7 +35,7 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)
return IRQ_NONE;
}
- spin_lock(&chip->midi_input_lock);
+ guard(spinlock)(&chip->midi_input_lock);
while (max-- > 0) {
if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
byte = inb(SBP(chip, READ));
@@ -43,108 +44,90 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)
}
}
}
- spin_unlock(&chip->midi_input_lock);
return IRQ_HANDLED;
}
static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip;
unsigned int valid_open_flags;
chip = substream->rmidi->private_data;
valid_open_flags = chip->hardware >= SB_HW_20
? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0;
- spin_lock_irqsave(&chip->open_lock, flags);
- if (chip->open & ~valid_open_flags) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- return -EAGAIN;
- }
- chip->open |= SB_OPEN_MIDI_INPUT;
- chip->midi_substream_input = substream;
- if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- snd_sbdsp_reset(chip); /* reset DSP */
- if (chip->hardware >= SB_HW_20)
- snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
- } else {
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ if (chip->open & ~valid_open_flags)
+ return -EAGAIN;
+ chip->open |= SB_OPEN_MIDI_INPUT;
+ chip->midi_substream_input = substream;
+ if (chip->open & SB_OPEN_MIDI_OUTPUT)
+ return 0;
}
+ snd_sbdsp_reset(chip); /* reset DSP */
+ if (chip->hardware >= SB_HW_20)
+ snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
return 0;
}
static int snd_sb8dsp_midi_output_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip;
unsigned int valid_open_flags;
chip = substream->rmidi->private_data;
valid_open_flags = chip->hardware >= SB_HW_20
? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0;
- spin_lock_irqsave(&chip->open_lock, flags);
- if (chip->open & ~valid_open_flags) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- return -EAGAIN;
- }
- chip->open |= SB_OPEN_MIDI_OUTPUT;
- chip->midi_substream_output = substream;
- if (!(chip->open & SB_OPEN_MIDI_INPUT)) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- snd_sbdsp_reset(chip); /* reset DSP */
- if (chip->hardware >= SB_HW_20)
- snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
- } else {
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ if (chip->open & ~valid_open_flags)
+ return -EAGAIN;
+ chip->open |= SB_OPEN_MIDI_OUTPUT;
+ chip->midi_substream_output = substream;
+ if (chip->open & SB_OPEN_MIDI_INPUT)
+ return 0;
}
+ snd_sbdsp_reset(chip); /* reset DSP */
+ if (chip->hardware >= SB_HW_20)
+ snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
return 0;
}
static int snd_sb8dsp_midi_input_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip;
chip = substream->rmidi->private_data;
- spin_lock_irqsave(&chip->open_lock, flags);
- chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER);
- chip->midi_substream_input = NULL;
- if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- snd_sbdsp_reset(chip); /* reset DSP */
- } else {
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER);
+ chip->midi_substream_input = NULL;
+ if (chip->open & SB_OPEN_MIDI_OUTPUT)
+ return 0;
}
+ snd_sbdsp_reset(chip); /* reset DSP */
return 0;
}
static int snd_sb8dsp_midi_output_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip;
chip = substream->rmidi->private_data;
- del_timer_sync(&chip->midi_timer);
- spin_lock_irqsave(&chip->open_lock, flags);
- chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER);
- chip->midi_substream_output = NULL;
- if (!(chip->open & SB_OPEN_MIDI_INPUT)) {
- spin_unlock_irqrestore(&chip->open_lock, flags);
- snd_sbdsp_reset(chip); /* reset DSP */
- } else {
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ timer_delete_sync(&chip->midi_timer);
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER);
+ chip->midi_substream_output = NULL;
+ if (chip->open & SB_OPEN_MIDI_INPUT)
+ return 0;
}
+ snd_sbdsp_reset(chip); /* reset DSP */
return 0;
}
static void snd_sb8dsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct snd_sb *chip;
chip = substream->rmidi->private_data;
- spin_lock_irqsave(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
if (up) {
if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) {
if (chip->hardware < SB_HW_20)
@@ -158,12 +141,10 @@ static void snd_sb8dsp_midi_input_trigger(struct snd_rawmidi_substream *substrea
chip->open &= ~SB_OPEN_MIDI_INPUT_TRIGGER;
}
}
- spin_unlock_irqrestore(&chip->open_lock, flags);
}
static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
struct snd_sb *chip;
char byte;
int max = 32;
@@ -171,11 +152,10 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream
/* how big is Tx FIFO? */
chip = substream->rmidi->private_data;
while (max-- > 0) {
- spin_lock_irqsave(&chip->open_lock, flags);
+ guard(spinlock_irqsave)(&chip->open_lock);
if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) {
chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
- del_timer(&chip->midi_timer);
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ timer_delete(&chip->midi_timer);
break;
}
if (chip->hardware >= SB_HW_20) {
@@ -184,7 +164,6 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream
;
if (timeout == 0) {
/* Tx FIFO full - try again later */
- spin_unlock_irqrestore(&chip->open_lock, flags);
break;
}
outb(byte, SBP(chip, WRITE));
@@ -193,40 +172,37 @@ static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream
snd_sbdsp_command(chip, byte);
}
snd_rawmidi_transmit_ack(substream, 1);
- spin_unlock_irqrestore(&chip->open_lock, flags);
}
}
static void snd_sb8dsp_midi_output_timer(struct timer_list *t)
{
- struct snd_sb *chip = from_timer(chip, t, midi_timer);
+ struct snd_sb *chip = timer_container_of(chip, t, midi_timer);
struct snd_rawmidi_substream *substream = chip->midi_substream_output;
- unsigned long flags;
- spin_lock_irqsave(&chip->open_lock, flags);
- mod_timer(&chip->midi_timer, 1 + jiffies);
- spin_unlock_irqrestore(&chip->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ mod_timer(&chip->midi_timer, 1 + jiffies);
+ }
snd_sb8dsp_midi_output_write(substream);
}
static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct snd_sb *chip;
chip = substream->rmidi->private_data;
- spin_lock_irqsave(&chip->open_lock, flags);
- if (up) {
- if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
- mod_timer(&chip->midi_timer, 1 + jiffies);
- chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
- }
- } else {
- if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) {
- chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
+ scoped_guard(spinlock_irqsave, &chip->open_lock) {
+ if (up) {
+ if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
+ mod_timer(&chip->midi_timer, 1 + jiffies);
+ chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
+ }
+ } else {
+ if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) {
+ chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
+ }
}
}
- spin_unlock_irqrestore(&chip->open_lock, flags);
if (up)
snd_sb8dsp_midi_output_write(substream);
@@ -254,7 +230,7 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device)
err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi);
if (err < 0)
return err;
- strcpy(rmidi->name, "SB8 MIDI");
+ strscpy(rmidi->name, "SB8 MIDI");
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_sb8dsp_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT;
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index c0e319d14210..f2848559e6da 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -31,14 +31,14 @@ int snd_sbdsp_command(struct snd_sb *chip, unsigned char val)
{
int i;
#ifdef IO_DEBUG
- snd_printk(KERN_DEBUG "command 0x%x\n", val);
+ dev_dbg(chip->card->dev, "command 0x%x\n", val);
#endif
for (i = BUSY_LOOPS; i; i--)
if ((inb(SBP(chip, STATUS)) & 0x80) == 0) {
outb(val, SBP(chip, COMMAND));
return 1;
}
- snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);
+ dev_dbg(chip->card->dev, "%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);
return 0;
}
@@ -50,12 +50,12 @@ int snd_sbdsp_get_byte(struct snd_sb *chip)
if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
val = inb(SBP(chip, READ));
#ifdef IO_DEBUG
- snd_printk(KERN_DEBUG "get_byte 0x%x\n", val);
+ dev_dbg(chip->card->dev, "get_byte 0x%x\n", val);
#endif
return val;
}
}
- snd_printd("%s [0x%lx]: timeout\n", __func__, chip->port);
+ dev_dbg(chip->card->dev, "%s [0x%lx]: timeout\n", __func__, chip->port);
return -ENODEV;
}
@@ -74,7 +74,8 @@ int snd_sbdsp_reset(struct snd_sb *chip)
else
break;
}
- snd_printdd("%s [0x%lx] failed...\n", __func__, chip->port);
+ if (chip->card)
+ dev_dbg(chip->card->dev, "%s [0x%lx] failed...\n", __func__, chip->port);
return -ENODEV;
}
@@ -93,27 +94,22 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
int version;
int major, minor;
char *str;
- unsigned long flags;
/*
* initialization sequence
*/
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (snd_sbdsp_reset(chip) < 0) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return -ENODEV;
- }
- version = snd_sbdsp_version(chip);
- if (version < 0) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return -ENODEV;
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ if (snd_sbdsp_reset(chip) < 0)
+ return -ENODEV;
+ version = snd_sbdsp_version(chip);
+ if (version < 0)
+ return -ENODEV;
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
major = version >> 8;
minor = version & 0xff;
- snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
- chip->port, major, minor);
+ dev_dbg(chip->card->dev, "SB [0x%lx]: DSP chip found, version = %i.%i\n",
+ chip->port, major, minor);
switch (chip->hardware) {
case SB_HW_AUTO:
@@ -140,8 +136,8 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
str = "16";
break;
default:
- snd_printk(KERN_INFO "SB [0x%lx]: unknown DSP chip version %i.%i\n",
- chip->port, major, minor);
+ dev_info(chip->card->dev, "SB [0x%lx]: unknown DSP chip version %i.%i\n",
+ chip->port, major, minor);
return -ENODEV;
}
break;
@@ -200,7 +196,7 @@ int snd_sbdsp_create(struct snd_card *card,
hardware == SB_HW_CS5530) ?
IRQF_SHARED : 0,
"SoundBlaster", (void *) chip)) {
- snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
+ dev_err(card->dev, "sb: can't grab irq %d\n", irq);
return -EBUSY;
}
chip->irq = irq;
@@ -212,14 +208,14 @@ int snd_sbdsp_create(struct snd_card *card,
chip->res_port = devm_request_region(card->dev, port, 16,
"SoundBlaster");
if (!chip->res_port) {
- snd_printk(KERN_ERR "sb: can't grab port 0x%lx\n", port);
+ dev_err(card->dev, "sb: can't grab port 0x%lx\n", port);
return -EBUSY;
}
#ifdef CONFIG_ISA
if (dma8 >= 0 && snd_devm_request_dma(card->dev, dma8,
"SoundBlaster - 8bit")) {
- snd_printk(KERN_ERR "sb: can't grab DMA8 %d\n", dma8);
+ dev_err(card->dev, "sb: can't grab DMA8 %d\n", dma8);
return -EBUSY;
}
chip->dma8 = dma8;
@@ -229,7 +225,7 @@ int snd_sbdsp_create(struct snd_card *card,
dma16 = -1;
} else if (snd_devm_request_dma(card->dev, dma16,
"SoundBlaster - 16bit")) {
- snd_printk(KERN_ERR "sb: can't grab DMA16 %d\n", dma16);
+ dev_err(card->dev, "sb: can't grab DMA16 %d\n", dma16);
return -EBUSY;
}
}
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index fffd681e5bf7..95173b18cee3 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -6,6 +6,7 @@
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/string.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/sb.h>
@@ -20,7 +21,7 @@ void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char dat
outb(data, SBP(chip, MIXER_DATA));
udelay(10);
#ifdef IO_DEBUG
- snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);
+ dev_dbg(chip->card->dev, "mixer_write 0x%x 0x%x\n", reg, data);
#endif
}
@@ -33,7 +34,7 @@ unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
result = inb(SBP(chip, MIXER_DATA));
udelay(10);
#ifdef IO_DEBUG
- snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
+ dev_dbg(chip->card->dev, "mixer_read 0x%x 0x%x\n", reg, result);
#endif
return result;
}
@@ -56,15 +57,13 @@ static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 16) & 0xff;
int mask = (kcontrol->private_value >> 24) & 0xff;
unsigned char val;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
ucontrol->value.integer.value[0] = val;
return 0;
}
@@ -72,7 +71,6 @@ static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 16) & 0x07;
int mask = (kcontrol->private_value >> 24) & 0xff;
@@ -80,13 +78,12 @@ static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_
unsigned char val, oval;
val = (ucontrol->value.integer.value[0] & mask) << shift;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval = snd_sbmixer_read(sb, reg);
val = (oval & ~(mask << shift)) | val;
change = val != oval;
if (change)
snd_sbmixer_write(sb, reg, val);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
return change;
}
@@ -108,7 +105,6 @@ static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int left_shift = (kcontrol->private_value >> 16) & 0x07;
@@ -116,10 +112,9 @@ static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
int mask = (kcontrol->private_value >> 24) & 0xff;
unsigned char left, right;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
ucontrol->value.integer.value[0] = left;
ucontrol->value.integer.value[1] = right;
return 0;
@@ -128,7 +123,6 @@ static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int left_shift = (kcontrol->private_value >> 16) & 0x07;
@@ -139,7 +133,7 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
left = (ucontrol->value.integer.value[0] & mask) << left_shift;
right = (ucontrol->value.integer.value[1] & mask) << right_shift;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
if (left_reg == right_reg) {
oleft = snd_sbmixer_read(sb, left_reg);
left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
@@ -157,7 +151,6 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
snd_sbmixer_write(sb, right_reg, right);
}
}
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
return change;
}
@@ -177,12 +170,11 @@ static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned char oval;
- spin_lock_irqsave(&sb->mixer_lock, flags);
- oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &sb->mixer_lock) {
+ oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
+ }
switch (oval & 0x07) {
case SB_DT019X_CAP_CD:
ucontrol->value.enumerated.item[0] = 0;
@@ -213,7 +205,6 @@ static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned char nval, oval;
@@ -238,12 +229,11 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl
default:
nval = SB_DT019X_CAP_MAIN;
}
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
change = nval != oval;
if (change)
snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
return change;
}
@@ -265,12 +255,10 @@ static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned char oval;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
oval >>= 6;
if (oval > 2)
oval = 2;
@@ -283,13 +271,12 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned char nval, oval;
if (ucontrol->value.enumerated.item[0] > 2)
return -EINVAL;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
nval = (oval & ~(3 << 6))
@@ -297,7 +284,6 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
change = nval != oval;
if (change)
snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
return change;
}
@@ -318,12 +304,10 @@ static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned char oval;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
switch ((oval >> 0x01) & 0x03) {
case SB_DSP_MIXS_CD:
ucontrol->value.enumerated.item[0] = 1;
@@ -341,7 +325,6 @@ static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change;
unsigned char nval, oval;
@@ -358,13 +341,12 @@ static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_el
nval = SB_DSP_MIXS_MIC;
}
nval <<= 1;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
nval |= oval & ~0x06;
change = nval != oval;
if (change)
snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
return change;
}
@@ -384,17 +366,15 @@ static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd
static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg1 = kcontrol->private_value & 0xff;
int reg2 = (kcontrol->private_value >> 8) & 0xff;
int left_shift = (kcontrol->private_value >> 16) & 0x0f;
int right_shift = (kcontrol->private_value >> 24) & 0x0f;
unsigned char val1, val2;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
val1 = snd_sbmixer_read(sb, reg1);
val2 = snd_sbmixer_read(sb, reg2);
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
@@ -405,7 +385,6 @@ static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_
static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg1 = kcontrol->private_value & 0xff;
int reg2 = (kcontrol->private_value >> 8) & 0xff;
int left_shift = (kcontrol->private_value >> 16) & 0x0f;
@@ -413,7 +392,7 @@ static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_
int change;
unsigned char val1, val2, oval1, oval2;
- spin_lock_irqsave(&sb->mixer_lock, flags);
+ guard(spinlock_irqsave)(&sb->mixer_lock);
oval1 = snd_sbmixer_read(sb, reg1);
oval2 = snd_sbmixer_read(sb, reg2);
val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
@@ -427,7 +406,6 @@ static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_
snd_sbmixer_write(sb, reg1, val1);
snd_sbmixer_write(sb, reg2, val2);
}
- spin_unlock_irqrestore(&sb->mixer_lock, flags);
return change;
}
@@ -696,20 +674,18 @@ static int snd_sbmixer_init(struct snd_sb *chip,
int map_count,
char *name)
{
- unsigned long flags;
struct snd_card *card = chip->card;
int idx, err;
/* mixer reset */
- spin_lock_irqsave(&chip->mixer_lock, flags);
- snd_sbmixer_write(chip, 0x00, 0x00);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
+ snd_sbmixer_write(chip, 0x00, 0x00);
+ }
/* mute and zero volume channels */
for (idx = 0; idx < map_count; idx++) {
- spin_lock_irqsave(&chip->mixer_lock, flags);
+ guard(spinlock_irqsave)(&chip->mixer_lock);
snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
}
for (idx = 0; idx < controls_count; idx++) {
@@ -718,7 +694,7 @@ static int snd_sbmixer_init(struct snd_sb *chip,
return err;
}
snd_component_add(card, name);
- strcpy(card->mixername, name);
+ strscpy(card->mixername, name);
return 0;
}
@@ -799,7 +775,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
return err;
break;
default:
- strcpy(card->mixername, "???");
+ strscpy(card->mixername, "???");
}
return 0;
}
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 60398fced046..6d618cc2ba45 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -204,7 +204,7 @@ static int sc6000_read(char __iomem *vport)
}
-static int sc6000_write(char __iomem *vport, int cmd)
+static int sc6000_write(struct device *devptr, char __iomem *vport, int cmd)
{
unsigned char val;
int loop = 500000;
@@ -221,18 +221,19 @@ static int sc6000_write(char __iomem *vport, int cmd)
cpu_relax();
} while (loop--);
- snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd);
+ dev_err(devptr, "DSP Command (0x%x) timeout.\n", cmd);
return -EIO;
}
-static int sc6000_dsp_get_answer(char __iomem *vport, int command,
+static int sc6000_dsp_get_answer(struct device *devptr,
+ char __iomem *vport, int command,
char *data, int data_len)
{
int len = 0;
- if (sc6000_write(vport, command)) {
- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command);
+ if (sc6000_write(devptr, vport, command)) {
+ dev_err(devptr, "CMD 0x%x: failed!\n", command);
return -EIO;
}
@@ -265,82 +266,86 @@ static int sc6000_dsp_reset(char __iomem *vport)
}
/* detection and initialization */
-static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg)
+static int sc6000_hw_cfg_write(struct device *devptr,
+ char __iomem *vport, const int *cfg)
{
- if (sc6000_write(vport, COMMAND_6C) < 0) {
- snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C);
+ if (sc6000_write(devptr, vport, COMMAND_6C) < 0) {
+ dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C);
return -EIO;
}
- if (sc6000_write(vport, COMMAND_5C) < 0) {
- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C);
+ if (sc6000_write(devptr, vport, COMMAND_5C) < 0) {
+ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_5C);
return -EIO;
}
- if (sc6000_write(vport, cfg[0]) < 0) {
- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]);
+ if (sc6000_write(devptr, vport, cfg[0]) < 0) {
+ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[0]);
return -EIO;
}
- if (sc6000_write(vport, cfg[1]) < 0) {
- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]);
+ if (sc6000_write(devptr, vport, cfg[1]) < 0) {
+ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[1]);
return -EIO;
}
- if (sc6000_write(vport, COMMAND_C5) < 0) {
- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5);
+ if (sc6000_write(devptr, vport, COMMAND_C5) < 0) {
+ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_C5);
return -EIO;
}
return 0;
}
-static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg)
+static int sc6000_cfg_write(struct device *devptr,
+ char __iomem *vport, unsigned char softcfg)
{
- if (sc6000_write(vport, WRITE_MDIRQ_CFG)) {
- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
+ if (sc6000_write(devptr, vport, WRITE_MDIRQ_CFG)) {
+ dev_err(devptr, "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
return -EIO;
}
- if (sc6000_write(vport, softcfg)) {
- snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n");
+ if (sc6000_write(devptr, vport, softcfg)) {
+ dev_err(devptr, "%s: failed!\n", __func__);
return -EIO;
}
return 0;
}
-static int sc6000_setup_board(char __iomem *vport, int config)
+static int sc6000_setup_board(struct device *devptr,
+ char __iomem *vport, int config)
{
int loop = 10;
do {
- if (sc6000_write(vport, COMMAND_88)) {
- snd_printk(KERN_ERR "CMD 0x%x: failed!\n",
- COMMAND_88);
+ if (sc6000_write(devptr, vport, COMMAND_88)) {
+ dev_err(devptr, "CMD 0x%x: failed!\n",
+ COMMAND_88);
return -EIO;
}
} while ((sc6000_wait_data(vport) < 0) && loop--);
if (sc6000_read(vport) < 0) {
- snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n",
- COMMAND_88);
+ dev_err(devptr, "sc6000_read after CMD 0x%x: failed\n",
+ COMMAND_88);
return -EIO;
}
- if (sc6000_cfg_write(vport, config))
+ if (sc6000_cfg_write(devptr, vport, config))
return -ENODEV;
return 0;
}
-static int sc6000_init_mss(char __iomem *vport, int config,
+static int sc6000_init_mss(struct device *devptr,
+ char __iomem *vport, int config,
char __iomem *vmss_port, int mss_config)
{
- if (sc6000_write(vport, DSP_INIT_MSS)) {
- snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n",
- DSP_INIT_MSS);
+ if (sc6000_write(devptr, vport, DSP_INIT_MSS)) {
+ dev_err(devptr, "%s [0x%x]: failed!\n", __func__,
+ DSP_INIT_MSS);
return -EIO;
}
msleep(10);
- if (sc6000_cfg_write(vport, config))
+ if (sc6000_cfg_write(devptr, vport, config))
return -EIO;
iowrite8(mss_config, vmss_port);
@@ -348,7 +353,8 @@ static int sc6000_init_mss(char __iomem *vport, int config,
return 0;
}
-static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg,
+static void sc6000_hw_cfg_encode(struct device *devptr,
+ char __iomem *vport, int *cfg,
long xport, long xmpu,
long xmss_port, int joystick)
{
@@ -367,10 +373,11 @@ static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg,
cfg[0] |= 0x02;
cfg[1] |= 0x80; /* enable WSS system */
cfg[1] &= ~0x40; /* disable IDE */
- snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]);
+ dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]);
}
-static int sc6000_init_board(char __iomem *vport,
+static int sc6000_init_board(struct device *devptr,
+ char __iomem *vport,
char __iomem *vmss_port, int dev)
{
char answer[15];
@@ -384,14 +391,14 @@ static int sc6000_init_board(char __iomem *vport,
err = sc6000_dsp_reset(vport);
if (err < 0) {
- snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n");
+ dev_err(devptr, "sc6000_dsp_reset: failed!\n");
return err;
}
memset(answer, 0, sizeof(answer));
- err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15);
+ err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15);
if (err <= 0) {
- snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n");
+ dev_err(devptr, "sc6000_dsp_copyright: failed!\n");
return -ENODEV;
}
/*
@@ -399,52 +406,52 @@ static int sc6000_init_board(char __iomem *vport,
* if we have something different, we have to be warned.
*/
if (strncmp("SC-6000", answer, 7))
- snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n");
+ dev_warn(devptr, "Warning: non SC-6000 audio card!\n");
- if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) {
- snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n");
+ if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) {
+ dev_err(devptr, "sc6000_dsp_version: failed!\n");
return -ENODEV;
}
- printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n",
+ dev_info(devptr, "Detected model: %s, DSP version %d.%d\n",
answer, version[0], version[1]);
/* set configuration */
- sc6000_write(vport, COMMAND_5C);
+ sc6000_write(devptr, vport, COMMAND_5C);
if (sc6000_read(vport) < 0)
old = 1;
if (!old) {
int cfg[2];
- sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev],
+ sc6000_hw_cfg_encode(devptr,
+ vport, &cfg[0], port[dev], mpu_port[dev],
mss_port[dev], joystick[dev]);
- if (sc6000_hw_cfg_write(vport, cfg) < 0) {
- snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n");
+ if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) {
+ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n");
return -EIO;
}
}
- err = sc6000_setup_board(vport, config);
+ err = sc6000_setup_board(devptr, vport, config);
if (err < 0) {
- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
+ dev_err(devptr, "sc6000_setup_board: failed!\n");
return -ENODEV;
}
sc6000_dsp_reset(vport);
if (!old) {
- sc6000_write(vport, COMMAND_60);
- sc6000_write(vport, 0x02);
+ sc6000_write(devptr, vport, COMMAND_60);
+ sc6000_write(devptr, vport, 0x02);
sc6000_dsp_reset(vport);
}
- err = sc6000_setup_board(vport, config);
+ err = sc6000_setup_board(devptr, vport, config);
if (err < 0) {
- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
+ dev_err(devptr, "sc6000_setup_board: failed!\n");
return -ENODEV;
}
- err = sc6000_init_mss(vport, config, vmss_port, mss_config);
+ err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config);
if (err < 0) {
- snd_printk(KERN_ERR "Cannot initialize "
- "Microsoft Sound System mode.\n");
+ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n");
return -ENODEV;
}
@@ -462,24 +469,24 @@ static int snd_sc6000_mixer(struct snd_wss *chip)
id1.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
/* reassign AUX0 to FM */
- strcpy(id1.name, "Aux Playback Switch");
- strcpy(id2.name, "FM Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch");
+ strscpy(id2.name, "FM Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "FM Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "FM Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
/* reassign AUX1 to CD */
- strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
- strcpy(id2.name, "CD Playback Switch");
+ strscpy(id1.name, "Aux Playback Switch"); id1.index = 1;
+ strscpy(id2.name, "CD Playback Switch");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
- strcpy(id1.name, "Aux Playback Volume");
- strcpy(id2.name, "CD Playback Volume");
+ strscpy(id1.name, "Aux Playback Volume");
+ strscpy(id2.name, "CD Playback Volume");
err = snd_ctl_rename_id(card, &id1, &id2);
if (err < 0)
return err;
@@ -491,39 +498,39 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev)
if (!enable[dev])
return 0;
if (port[dev] == SNDRV_AUTO_PORT) {
- printk(KERN_ERR PFX "specify IO port\n");
+ dev_err(devptr, "specify IO port\n");
return 0;
}
if (mss_port[dev] == SNDRV_AUTO_PORT) {
- printk(KERN_ERR PFX "specify MSS port\n");
+ dev_err(devptr, "specify MSS port\n");
return 0;
}
if (port[dev] != 0x220 && port[dev] != 0x240) {
- printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n");
+ dev_err(devptr, "Port must be 0x220 or 0x240\n");
return 0;
}
if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) {
- printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n");
+ dev_err(devptr, "MSS port must be 0x530 or 0xe80\n");
return 0;
}
if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) {
- printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]);
+ dev_err(devptr, "invalid IRQ %d\n", irq[dev]);
return 0;
}
if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) {
- printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]);
+ dev_err(devptr, "invalid DMA %d\n", dma[dev]);
return 0;
}
if (mpu_port[dev] != SNDRV_AUTO_PORT &&
(mpu_port[dev] & ~0x30L) != 0x300) {
- printk(KERN_ERR PFX "invalid MPU-401 port %lx\n",
+ dev_err(devptr, "invalid MPU-401 port %lx\n",
mpu_port[dev]);
return 0;
}
if (mpu_port[dev] != SNDRV_AUTO_PORT &&
mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 &&
!sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) {
- printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]);
+ dev_err(devptr, "invalid MPU-401 IRQ %d\n", mpu_irq[dev]);
return 0;
}
return 1;
@@ -534,7 +541,7 @@ static void snd_sc6000_free(struct snd_card *card)
char __iomem *vport = (char __force __iomem *)card->private_data;
if (vport)
- sc6000_setup_board(vport, 0);
+ sc6000_setup_board(card->dev, vport, 0);
}
static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
@@ -558,7 +565,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
if (xirq < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
+ dev_err(devptr, "unable to find a free IRQ\n");
return -EBUSY;
}
}
@@ -566,42 +573,39 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
if (xdma == SNDRV_AUTO_DMA) {
xdma = snd_legacy_find_free_dma(possible_dmas);
if (xdma < 0) {
- snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
+ dev_err(devptr, "unable to find a free DMA\n");
return -EBUSY;
}
}
if (!devm_request_region(devptr, port[dev], 0x10, DRV_NAME)) {
- snd_printk(KERN_ERR PFX
- "I/O port region is already in use.\n");
+ dev_err(devptr, "I/O port region is already in use.\n");
return -EBUSY;
}
vport = devm_ioport_map(devptr, port[dev], 0x10);
if (!vport) {
- snd_printk(KERN_ERR PFX
- "I/O port cannot be iomapped.\n");
+ dev_err(devptr, "I/O port cannot be iomapped.\n");
return -EBUSY;
}
card->private_data = (void __force *)vport;
/* to make it marked as used */
if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) {
- snd_printk(KERN_ERR PFX
- "SC-6000 port I/O port region is already in use.\n");
+ dev_err(devptr,
+ "SC-6000 port I/O port region is already in use.\n");
return -EBUSY;
}
vmss_port = devm_ioport_map(devptr, mss_port[dev], 4);
if (!vmss_port) {
- snd_printk(KERN_ERR PFX
- "MSS port I/O cannot be iomapped.\n");
+ dev_err(devptr, "MSS port I/O cannot be iomapped.\n");
return -EBUSY;
}
- snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n",
- port[dev], xirq, xdma,
- mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
+ dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n",
+ port[dev], xirq, xdma,
+ mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
- err = sc6000_init_board(vport, vmss_port, dev);
+ err = sc6000_init_board(devptr, vport, vmss_port, dev);
if (err < 0)
return err;
card->private_free = snd_sc6000_free;
@@ -613,25 +617,24 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
err = snd_wss_pcm(chip, 0);
if (err < 0) {
- snd_printk(KERN_ERR PFX
- "error creating new WSS PCM device\n");
+ dev_err(devptr, "error creating new WSS PCM device\n");
return err;
}
err = snd_wss_mixer(chip);
if (err < 0) {
- snd_printk(KERN_ERR PFX "error creating new WSS mixer\n");
+ dev_err(devptr, "error creating new WSS mixer\n");
return err;
}
err = snd_sc6000_mixer(chip);
if (err < 0) {
- snd_printk(KERN_ERR PFX "the mixer rewrite failed\n");
+ dev_err(devptr, "the mixer rewrite failed\n");
return err;
}
if (snd_opl3_create(card,
0x388, 0x388 + 2,
OPL3_HW_AUTO, 0, &opl3) < 0) {
- snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n",
- 0x388, 0x388 + 2);
+ dev_err(devptr, "no OPL device at 0x%x-0x%x ?\n",
+ 0x388, 0x388 + 2);
} else {
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
@@ -645,12 +648,12 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev)
MPU401_HW_MPU401,
mpu_port[dev], 0,
mpu_irq[dev], NULL) < 0)
- snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n",
- mpu_port[dev]);
+ dev_err(devptr, "no MPU-401 device at 0x%lx ?\n",
+ mpu_port[dev]);
}
- strcpy(card->driver, DRV_NAME);
- strcpy(card->shortname, "SC-6000");
+ strscpy(card->driver, DRV_NAME);
+ strscpy(card->shortname, "SC-6000");
sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d",
mss_port[dev], xirq, xdma);
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 0bc0025f7c19..a31ca75774a6 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -138,6 +138,7 @@ struct soundscape {
struct snd_wss *chip;
unsigned char midi_vol;
+ struct device *dev;
};
#define INVALID_IRQ ((unsigned)-1)
@@ -161,9 +162,9 @@ static struct snd_dma_buffer *get_dmabuf(struct soundscape *s,
if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
s->chip->card->dev,
size, buf) < 0) {
- snd_printk(KERN_ERR "sscape: Failed to allocate "
- "%lu bytes for DMA\n",
- size);
+ dev_err(s->dev,
+ "sscape: Failed to allocate %lu bytes for DMA\n",
+ size);
return NULL;
}
}
@@ -199,11 +200,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg,
static void sscape_write(struct soundscape *s, enum GA_REG reg,
unsigned char val)
{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
+ guard(spinlock_irqsave)(&s->lock);
sscape_write_unsafe(s->io_base, reg, val);
- spin_unlock_irqrestore(&s->lock, flags);
}
/*
@@ -366,12 +364,11 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
do {
- unsigned long flags;
int x;
- spin_lock_irqsave(&s->lock, flags);
- x = host_read_unsafe(s->io_base);
- spin_unlock_irqrestore(&s->lock, flags);
+ scoped_guard(spinlock_irqsave, &s->lock) {
+ x = host_read_unsafe(s->io_base);
+ }
if (x == 0xfe || x == 0xff)
return 1;
@@ -393,12 +390,11 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
do {
- unsigned long flags;
int x;
- spin_lock_irqsave(&s->lock, flags);
- x = host_read_unsafe(s->io_base);
- spin_unlock_irqrestore(&s->lock, flags);
+ scoped_guard(spinlock_irqsave, &s->lock) {
+ x = host_read_unsafe(s->io_base);
+ }
if (x == 0xfe)
return 1;
@@ -414,7 +410,6 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
static int upload_dma_data(struct soundscape *s, const unsigned char *data,
size_t size)
{
- unsigned long flags;
struct snd_dma_buffer dma;
int ret;
unsigned char val;
@@ -422,63 +417,57 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data,
if (!get_dmabuf(s, &dma, PAGE_ALIGN(32 * 1024)))
return -ENOMEM;
- spin_lock_irqsave(&s->lock, flags);
-
- /*
- * Reset the board ...
- */
- val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f);
-
- /*
- * Enable the DMA channels and configure them ...
- */
- val = (s->chip->dma1 << 4) | DMA_8BIT;
- sscape_write_unsafe(s->io_base, GA_DMAA_REG, val);
- sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
-
- /*
- * Take the board out of reset ...
- */
- val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80);
+ scoped_guard(spinlock_irqsave, &s->lock) {
- /*
- * Upload the firmware to the SoundScape
- * board through the DMA channel ...
- */
- while (size != 0) {
- unsigned long len;
+ /*
+ * Reset the board ...
+ */
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f);
- len = min(size, dma.bytes);
- memcpy(dma.area, data, len);
- data += len;
- size -= len;
+ /*
+ * Enable the DMA channels and configure them ...
+ */
+ val = (s->chip->dma1 << 4) | DMA_8BIT;
+ sscape_write_unsafe(s->io_base, GA_DMAA_REG, val);
+ sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
- snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
- sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
- if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
- /*
- * Don't forget to release this spinlock we're holding
- */
- spin_unlock_irqrestore(&s->lock, flags);
+ /*
+ * Take the board out of reset ...
+ */
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80);
- snd_printk(KERN_ERR
- "sscape: DMA upload has timed out\n");
- ret = -EAGAIN;
- goto _release_dma;
- }
- } /* while */
+ /*
+ * Upload the firmware to the SoundScape
+ * board through the DMA channel ...
+ */
+ while (size != 0) {
+ unsigned long len;
+
+ len = min(size, dma.bytes);
+ memcpy(dma.area, data, len);
+ data += len;
+ size -= len;
+
+ snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
+ sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
+ if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
+ dev_err(s->dev, "sscape: DMA upload has timed out\n");
+ ret = -EAGAIN;
+ goto _release_dma;
+ }
+ } /* while */
- set_host_mode_unsafe(s->io_base);
- outb(0x0, s->io_base);
+ set_host_mode_unsafe(s->io_base);
+ outb(0x0, s->io_base);
- /*
- * Boot the board ... (I think)
- */
- val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40);
- spin_unlock_irqrestore(&s->lock, flags);
+ /*
+ * Boot the board ... (I think)
+ */
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40);
+ }
/*
* If all has gone well, then the board should acknowledge
@@ -487,12 +476,11 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data,
*/
ret = 0;
if (!obp_startup_ack(s, 5000)) {
- snd_printk(KERN_ERR "sscape: No response "
- "from on-board processor after upload\n");
+ dev_err(s->dev,
+ "sscape: No response from on-board processor after upload\n");
ret = -EAGAIN;
} else if (!host_startup_ack(s, 5000)) {
- snd_printk(KERN_ERR
- "sscape: SoundScape failed to initialise\n");
+ dev_err(s->dev, "sscape: SoundScape failed to initialise\n");
ret = -EAGAIN;
}
@@ -514,33 +502,30 @@ _release_dma:
static int sscape_upload_bootblock(struct snd_card *card)
{
struct soundscape *sscape = get_card_soundscape(card);
- unsigned long flags;
const struct firmware *init_fw = NULL;
int data = 0;
int ret;
ret = request_firmware(&init_fw, "scope.cod", card->dev);
if (ret < 0) {
- snd_printk(KERN_ERR "sscape: Error loading scope.cod");
+ dev_err(card->dev, "sscape: Error loading scope.cod");
return ret;
}
ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
release_firmware(init_fw);
- spin_lock_irqsave(&sscape->lock, flags);
+ guard(spinlock_irqsave)(&sscape->lock);
if (ret == 0)
data = host_read_ctrl_unsafe(sscape->io_base, 100);
if (data & 0x10)
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
- spin_unlock_irqrestore(&sscape->lock, flags);
-
data &= 0xf;
if (ret == 0 && data > 7) {
- snd_printk(KERN_ERR
- "sscape: timeout reading firmware version\n");
+ dev_err(card->dev,
+ "sscape: timeout reading firmware version\n");
ret = -EAGAIN;
}
@@ -557,18 +542,18 @@ static int sscape_upload_microcode(struct snd_card *card, int version)
char name[14];
int err;
- snprintf(name, sizeof(name), "sndscape.co%d", version);
+ scnprintf(name, sizeof(name), "sndscape.co%d", version);
err = request_firmware(&init_fw, name, card->dev);
if (err < 0) {
- snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d",
- version);
+ dev_err(card->dev, "sscape: Error loading sndscape.co%d",
+ version);
return err;
}
err = upload_dma_data(sscape, init_fw->data, init_fw->size);
if (err == 0)
- snd_printk(KERN_INFO "sscape: MIDI firmware loaded %zu KBs\n",
- init_fw->size >> 10);
+ dev_info(card->dev, "sscape: MIDI firmware loaded %zu KBs\n",
+ init_fw->size >> 10);
release_firmware(init_fw);
@@ -594,11 +579,9 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
struct snd_wss *chip = snd_kcontrol_chip(kctl);
struct snd_card *card = chip->card;
register struct soundscape *s = get_card_soundscape(card);
- unsigned long flags;
- spin_lock_irqsave(&s->lock, flags);
+ guard(spinlock_irqsave)(&s->lock);
uctl->value.integer.value[0] = s->midi_vol;
- spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@@ -608,11 +591,10 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
struct snd_wss *chip = snd_kcontrol_chip(kctl);
struct snd_card *card = chip->card;
struct soundscape *s = get_card_soundscape(card);
- unsigned long flags;
int change;
unsigned char new_val;
- spin_lock_irqsave(&s->lock, flags);
+ guard(spinlock_irqsave)(&s->lock);
new_val = uctl->value.integer.value[0] & 127;
/*
@@ -643,7 +625,6 @@ __skip_change:
*/
set_midi_mode_unsafe(s->io_base);
- spin_unlock_irqrestore(&s->lock, flags);
return change;
}
@@ -783,8 +764,8 @@ _done:
static int mpu401_open(struct snd_mpu401 *mpu)
{
if (!verify_mpu401(mpu)) {
- snd_printk(KERN_ERR "sscape: MIDI disabled, "
- "please load firmware\n");
+ dev_err(mpu->rmidi->card->dev,
+ "sscape: MIDI disabled, please load firmware\n");
return -ENODEV;
}
@@ -853,8 +834,6 @@ static int create_ad1845(struct snd_card *card, unsigned port,
err = snd_wss_create(card, port, -1, irq, dma1, dma2,
codec_type, WSS_HWSHARE_DMA1, &chip);
if (!err) {
- unsigned long flags;
-
if (sscape->type != SSCAPE_VIVO) {
/*
* The input clock frequency on the SoundScape must
@@ -862,31 +841,31 @@ static int create_ad1845(struct snd_card *card, unsigned port,
* to get the playback to sound correct ...
*/
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, AD1845_CLOCK, 0x20);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_wss_out(chip, AD1845_CLOCK, 0x20);
+ }
snd_wss_mce_down(chip);
}
err = snd_wss_pcm(chip, 0);
if (err < 0) {
- snd_printk(KERN_ERR "sscape: No PCM device "
- "for AD1845 chip\n");
+ dev_err(card->dev,
+ "sscape: No PCM device for AD1845 chip\n");
goto _error;
}
err = snd_wss_mixer(chip);
if (err < 0) {
- snd_printk(KERN_ERR "sscape: No mixer device "
- "for AD1845 chip\n");
+ dev_err(card->dev,
+ "sscape: No mixer device for AD1845 chip\n");
goto _error;
}
if (chip->hardware != WSS_HW_AD1848) {
err = snd_wss_timer(chip, 0);
if (err < 0) {
- snd_printk(KERN_ERR "sscape: No timer device "
- "for AD1845 chip\n");
+ dev_err(card->dev,
+ "sscape: No timer device for AD1845 chip\n");
goto _error;
}
}
@@ -895,8 +874,8 @@ static int create_ad1845(struct snd_card *card, unsigned port,
err = snd_ctl_add(card,
snd_ctl_new1(&midi_mixer_ctl, chip));
if (err < 0) {
- snd_printk(KERN_ERR "sscape: Could not create "
- "MIDI mixer control\n");
+ dev_err(card->dev,
+ "sscape: Could not create MIDI mixer control\n");
goto _error;
}
}
@@ -921,7 +900,6 @@ static int create_sscape(int dev, struct snd_card *card)
unsigned mpu_irq_cfg;
struct resource *io_res;
struct resource *wss_res;
- unsigned long flags;
int err;
int val;
const char *name;
@@ -932,8 +910,8 @@ static int create_sscape(int dev, struct snd_card *card)
*/
io_res = devm_request_region(card->dev, port[dev], 8, "SoundScape");
if (!io_res) {
- snd_printk(KERN_ERR
- "sscape: can't grab port 0x%lx\n", port[dev]);
+ dev_err(card->dev,
+ "sscape: can't grab port 0x%lx\n", port[dev]);
return -EBUSY;
}
wss_res = NULL;
@@ -941,8 +919,8 @@ static int create_sscape(int dev, struct snd_card *card)
wss_res = devm_request_region(card->dev, wss_port[dev], 4,
"SoundScape");
if (!wss_res) {
- snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n",
- wss_port[dev]);
+ dev_err(card->dev, "sscape: can't grab port 0x%lx\n",
+ wss_port[dev]);
return -EBUSY;
}
}
@@ -952,7 +930,7 @@ static int create_sscape(int dev, struct snd_card *card)
*/
err = snd_devm_request_dma(card->dev, dma[dev], "SoundScape");
if (err < 0) {
- snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]);
+ dev_err(card->dev, "sscape: can't grab DMA %d\n", dma[dev]);
return err;
}
@@ -962,7 +940,7 @@ static int create_sscape(int dev, struct snd_card *card)
sscape->io_base = port[dev];
if (!detect_sscape(sscape, wss_port[dev])) {
- printk(KERN_ERR "sscape: hardware not detected at 0x%x\n",
+ dev_err(card->dev, "sscape: hardware not detected at 0x%x\n",
sscape->io_base);
return -ENODEV;
}
@@ -985,21 +963,21 @@ static int create_sscape(int dev, struct snd_card *card)
break;
}
- printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
- name, sscape->io_base, irq[dev], dma[dev]);
+ dev_info(card->dev, "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
+ name, sscape->io_base, irq[dev], dma[dev]);
/*
* Check that the user didn't pass us garbage data ...
*/
irq_cfg = get_irq_config(sscape->type, irq[dev]);
if (irq_cfg == INVALID_IRQ) {
- snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
+ dev_err(card->dev, "sscape: Invalid IRQ %d\n", irq[dev]);
return -ENXIO;
}
mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
if (mpu_irq_cfg == INVALID_IRQ) {
- snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
+ dev_err(card->dev, "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
return -ENXIO;
}
@@ -1007,34 +985,34 @@ static int create_sscape(int dev, struct snd_card *card)
* Tell the on-board devices where their resources are (I think -
* I can't be sure without a datasheet ... So many magic values!)
*/
- spin_lock_irqsave(&sscape->lock, flags);
+ scoped_guard(spinlock_irqsave, &sscape->lock) {
- sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
- sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
+ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
+ sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
- /*
- * Enable and configure the DMA channels ...
- */
- sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
- dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
- sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
- sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
-
- mpu_irq_cfg |= mpu_irq_cfg << 2;
- val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7;
- if (joystick[dev])
- val |= 8;
- sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10);
- sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
- sscape_write_unsafe(sscape->io_base,
- GA_CDCFG_REG, 0x09 | DMA_8BIT
- | (dma[dev] << 4) | (irq_cfg << 1));
- /*
- * Enable the master IRQ ...
- */
- sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
+ /*
+ * Enable and configure the DMA channels ...
+ */
+ sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
+ dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
+ sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
+ sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
+
+ mpu_irq_cfg |= mpu_irq_cfg << 2;
+ val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7;
+ if (joystick[dev])
+ val |= 8;
+ sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10);
+ sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
+ sscape_write_unsafe(sscape->io_base,
+ GA_CDCFG_REG, 0x09 | DMA_8BIT
+ | (dma[dev] << 4) | (irq_cfg << 1));
+ /*
+ * Enable the master IRQ ...
+ */
+ sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
- spin_unlock_irqrestore(&sscape->lock, flags);
+ }
/*
* We have now enabled the codec chip, and so we should
@@ -1043,13 +1021,13 @@ static int create_sscape(int dev, struct snd_card *card)
err = create_ad1845(card, wss_port[dev], irq[dev],
dma[dev], dma2[dev]);
if (err < 0) {
- snd_printk(KERN_ERR
- "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
- wss_port[dev], irq[dev]);
+ dev_err(card->dev,
+ "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
+ wss_port[dev], irq[dev]);
return err;
}
- strcpy(card->driver, "SoundScape");
- strcpy(card->shortname, name);
+ strscpy(card->driver, "SoundScape");
+ strscpy(card->shortname, name);
snprintf(card->longname, sizeof(card->longname),
"%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
name, sscape->chip->port, sscape->chip->irq,
@@ -1065,16 +1043,16 @@ static int create_sscape(int dev, struct snd_card *card)
err = create_mpu401(card, MIDI_DEVNUM, port[dev],
mpu_irq[dev]);
if (err < 0) {
- snd_printk(KERN_ERR "sscape: Failed to create "
- "MPU-401 device at 0x%lx\n",
- port[dev]);
+ dev_err(card->dev,
+ "sscape: Failed to create MPU-401 device at 0x%lx\n",
+ port[dev]);
return err;
}
/*
* Initialize mixer
*/
- spin_lock_irqsave(&sscape->lock, flags);
+ guard(spinlock_irqsave)(&sscape->lock);
sscape->midi_vol = 0;
host_write_ctrl_unsafe(sscape->io_base,
CMD_SET_MIDI_VOL, 100);
@@ -1091,7 +1069,6 @@ static int create_sscape(int dev, struct snd_card *card)
host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
set_midi_mode_unsafe(sscape->io_base);
- spin_unlock_irqrestore(&sscape->lock, flags);
}
}
@@ -1110,9 +1087,8 @@ static int snd_sscape_match(struct device *pdev, unsigned int i)
if (irq[i] == SNDRV_AUTO_IRQ ||
mpu_irq[i] == SNDRV_AUTO_IRQ ||
dma[i] == SNDRV_AUTO_DMA) {
- printk(KERN_INFO
- "sscape: insufficient parameters, "
- "need IO, IRQ, MPU-IRQ and DMA\n");
+ dev_info(pdev,
+ "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n");
return 0;
}
@@ -1131,6 +1107,7 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
return ret;
sscape = get_card_soundscape(card);
+ sscape->dev = pdev;
sscape->type = SSCAPE;
dma[dev] &= 0x03;
@@ -1141,7 +1118,7 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
ret = snd_card_register(card);
if (ret < 0) {
- snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
+ dev_err(pdev, "sscape: Failed to register sound card\n");
return ret;
}
dev_set_drvdata(pdev, card);
@@ -1194,7 +1171,7 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
if (!pnp_is_active(dev)) {
if (pnp_activate_dev(dev) < 0) {
- snd_printk(KERN_INFO "sscape: device is inactive\n");
+ dev_info(&dev->dev, "sscape: device is inactive\n");
return -EBUSY;
}
}
@@ -1210,6 +1187,7 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
return ret;
sscape = get_card_soundscape(card);
+ sscape->dev = card->dev;
/*
* Identify card model ...
@@ -1240,7 +1218,7 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
ret = snd_card_register(card);
if (ret < 0) {
- snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
+ dev_err(card->dev, "sscape: Failed to register sound card\n");
return ret;
}
diff --git a/sound/isa/wavefront/Makefile b/sound/isa/wavefront/Makefile
index b8406dce81f5..3ba85fb2e6cd 100644
--- a/sound/isa/wavefront/Makefile
+++ b/sound/isa/wavefront/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-wavefront-objs := wavefront.o wavefront_fx.o wavefront_synth.o wavefront_midi.o
+snd-wavefront-y := wavefront.o wavefront_fx.o wavefront_synth.o wavefront_midi.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_WAVEFRONT) += snd-wavefront.o
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index e6e46a0266b0..07c68568091d 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -140,7 +140,7 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "PnP WSS pnp configure failure\n");
+ dev_err(&pdev->dev, "PnP WSS pnp configure failure\n");
return err;
}
@@ -156,7 +156,7 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n");
+ dev_err(&pdev->dev, "PnP ICS2115 pnp configure failure\n");
return err;
}
@@ -174,26 +174,27 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n");
+ dev_err(&pdev->dev, "PnP MPU401 pnp configure failure\n");
cs4232_mpu_port[dev] = SNDRV_AUTO_PORT;
} else {
cs4232_mpu_port[dev] = pnp_port_start(pdev, 0);
cs4232_mpu_irq[dev] = pnp_irq(pdev, 0);
}
- snd_printk (KERN_INFO "CS4232 MPU: port=0x%lx, irq=%i\n",
- cs4232_mpu_port[dev],
- cs4232_mpu_irq[dev]);
+ dev_info(&pdev->dev, "CS4232 MPU: port=0x%lx, irq=%i\n",
+ cs4232_mpu_port[dev],
+ cs4232_mpu_irq[dev]);
}
- snd_printdd ("CS4232: pcm port=0x%lx, fm port=0x%lx, dma1=%i, dma2=%i, irq=%i\nICS2115: port=0x%lx, irq=%i\n",
- cs4232_pcm_port[dev],
- fm_port[dev],
- dma1[dev],
- dma2[dev],
- cs4232_pcm_irq[dev],
- ics2115_port[dev],
- ics2115_irq[dev]);
+ dev_dbg(&pdev->dev,
+ "CS4232: pcm port=0x%lx, fm port=0x%lx, dma1=%i, dma2=%i, irq=%i\nICS2115: port=0x%lx, irq=%i\n",
+ cs4232_pcm_port[dev],
+ fm_port[dev],
+ dma1[dev],
+ dma2[dev],
+ cs4232_pcm_irq[dev],
+ ics2115_port[dev],
+ ics2115_irq[dev]);
return 0;
}
@@ -233,7 +234,7 @@ static struct snd_hwdep *snd_wavefront_new_synth(struct snd_card *card,
if (snd_hwdep_new(card, "WaveFront", hw_dev, &wavefront_synth) < 0)
return NULL;
- strcpy (wavefront_synth->name,
+ strscpy (wavefront_synth->name,
"WaveFront (ICS2115) wavetable synthesizer");
wavefront_synth->ops.open = snd_wavefront_synth_open;
wavefront_synth->ops.release = snd_wavefront_synth_release;
@@ -251,7 +252,7 @@ static struct snd_hwdep *snd_wavefront_new_fx(struct snd_card *card,
struct snd_hwdep *fx_processor;
if (snd_wavefront_fx_start (&acard->wavefront)) {
- snd_printk (KERN_ERR "cannot initialize YSS225 FX processor");
+ dev_err(card->dev, "cannot initialize YSS225 FX processor");
return NULL;
}
@@ -282,7 +283,7 @@ static struct snd_rawmidi *snd_wavefront_new_midi(struct snd_card *card,
first = 0;
acard->wavefront.midi.base = port;
if (snd_wavefront_midi_start (acard)) {
- snd_printk (KERN_ERR "cannot initialize MIDI interface\n");
+ dev_err(card->dev, "cannot initialize MIDI interface\n");
return NULL;
}
}
@@ -291,10 +292,10 @@ static struct snd_rawmidi *snd_wavefront_new_midi(struct snd_card *card,
return NULL;
if (mpu == internal_mpu) {
- strcpy(rmidi->name, "WaveFront MIDI (Internal)");
+ strscpy(rmidi->name, "WaveFront MIDI (Internal)");
rmidi->private_data = &internal_id;
} else {
- strcpy(rmidi->name, "WaveFront MIDI (External)");
+ strscpy(rmidi->name, "WaveFront MIDI (External)");
rmidi->private_data = &external_id;
}
@@ -349,7 +350,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
cs4232_pcm_irq[dev], dma1[dev], dma2[dev],
WSS_HW_DETECT, 0, &chip);
if (err < 0) {
- snd_printk(KERN_ERR "can't allocate WSS device\n");
+ dev_err(card->dev, "can't allocate WSS device\n");
return err;
}
@@ -369,7 +370,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
OPL3_HW_OPL3_CS, 0, &opl3);
if (err < 0) {
- snd_printk (KERN_ERR "can't allocate or detect OPL3 synth\n");
+ dev_err(card->dev, "can't allocate or detect OPL3 synth\n");
return err;
}
@@ -385,14 +386,14 @@ snd_wavefront_probe (struct snd_card *card, int dev)
devm_request_region(card->dev, ics2115_port[dev], 16,
"ICS2115");
if (acard->wavefront.res_base == NULL) {
- snd_printk(KERN_ERR "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n",
- ics2115_port[dev], ics2115_port[dev] + 16 - 1);
+ dev_err(card->dev, "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n",
+ ics2115_port[dev], ics2115_port[dev] + 16 - 1);
return -EBUSY;
}
if (devm_request_irq(card->dev, ics2115_irq[dev],
snd_wavefront_ics2115_interrupt,
0, "ICS2115", acard)) {
- snd_printk(KERN_ERR "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]);
+ dev_err(card->dev, "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]);
return -EBUSY;
}
@@ -402,11 +403,11 @@ snd_wavefront_probe (struct snd_card *card, int dev)
wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard);
if (wavefront_synth == NULL) {
- snd_printk (KERN_ERR "can't create WaveFront synth device\n");
+ dev_err(card->dev, "can't create WaveFront synth device\n");
return -ENOMEM;
}
- strcpy (wavefront_synth->name, "ICS2115 Wavetable MIDI Synthesizer");
+ strscpy (wavefront_synth->name, "ICS2115 Wavetable MIDI Synthesizer");
wavefront_synth->iface = SNDRV_HWDEP_IFACE_ICS2115;
hw_dev++;
@@ -414,7 +415,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
err = snd_wss_mixer(chip);
if (err < 0) {
- snd_printk (KERN_ERR "can't allocate mixer device\n");
+ dev_err(card->dev, "can't allocate mixer device\n");
return err;
}
@@ -425,7 +426,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
cs4232_mpu_port[dev], 0,
cs4232_mpu_irq[dev], NULL);
if (err < 0) {
- snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n");
+ dev_err(card->dev, "can't allocate CS4232 MPU-401 device\n");
return err;
}
midi_dev++;
@@ -441,7 +442,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
ics2115_port[dev],
internal_mpu);
if (ics2115_internal_rmidi == NULL) {
- snd_printk (KERN_ERR "can't setup ICS2115 internal MIDI device\n");
+ dev_err(card->dev, "can't setup ICS2115 internal MIDI device\n");
return -ENOMEM;
}
midi_dev++;
@@ -457,7 +458,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
ics2115_port[dev],
external_mpu);
if (ics2115_external_rmidi == NULL) {
- snd_printk (KERN_ERR "can't setup ICS2115 external MIDI device\n");
+ dev_err(card->dev, "can't setup ICS2115 external MIDI device\n");
return -ENOMEM;
}
midi_dev++;
@@ -471,18 +472,18 @@ snd_wavefront_probe (struct snd_card *card, int dev)
acard,
ics2115_port[dev]);
if (fx_processor == NULL) {
- snd_printk (KERN_ERR "can't setup FX device\n");
+ dev_err(card->dev, "can't setup FX device\n");
return -ENOMEM;
}
hw_dev++;
- strcpy(card->driver, "Tropez+");
- strcpy(card->shortname, "Turtle Beach Tropez+");
+ strscpy(card->driver, "Tropez+");
+ strscpy(card->shortname, "Turtle Beach Tropez+");
} else {
/* Need a way to distinguish between Maui and Tropez */
- strcpy(card->driver, "WaveFront");
- strcpy(card->shortname, "Turtle Beach WaveFront");
+ strscpy(card->driver, "WaveFront");
+ strscpy(card->shortname, "Turtle Beach WaveFront");
}
/* ----- Register the card --------- */
@@ -525,11 +526,11 @@ static int snd_wavefront_isa_match(struct device *pdev,
return 0;
#endif
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "specify CS4232 port\n");
+ dev_err(pdev, "specify CS4232 port\n");
return 0;
}
if (ics2115_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk(KERN_ERR "specify ICS2115 port\n");
+ dev_err(pdev, "specify ICS2115 port\n");
return 0;
}
return 1;
@@ -585,7 +586,7 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
if (snd_wavefront_pnp (dev, card->private_data, pcard, pid) < 0) {
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk (KERN_ERR "isapnp detection failed\n");
+ dev_err(card->dev, "isapnp detection failed\n");
return -ENODEV;
}
}
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 3c21324b2a0e..beca35ce04f3 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -38,7 +38,7 @@ wavefront_fx_idle (snd_wavefront_t *dev)
}
if (x & 0x80) {
- snd_printk ("FX device never idle.\n");
+ dev_err(dev->card->dev, "FX device never idle.\n");
return 0;
}
@@ -64,14 +64,14 @@ wavefront_fx_memset (snd_wavefront_t *dev,
unsigned short *data)
{
if (page < 0 || page > 7) {
- snd_printk ("FX memset: "
- "page must be >= 0 and <= 7\n");
+ dev_err(dev->card->dev,
+ "FX memset: page must be >= 0 and <= 7\n");
return -EINVAL;
}
if (addr < 0 || addr > 0x7f) {
- snd_printk ("FX memset: "
- "addr must be >= 0 and <= 7f\n");
+ dev_err(dev->card->dev,
+ "FX memset: addr must be >= 0 and <= 7f\n");
return -EINVAL;
}
@@ -83,7 +83,7 @@ wavefront_fx_memset (snd_wavefront_t *dev,
outb ((data[0] >> 8), dev->fx_dsp_msb);
outb ((data[0] & 0xff), dev->fx_dsp_lsb);
- snd_printk ("FX: addr %d:%x set to 0x%x\n",
+ dev_err(dev->card->dev, "FX: addr %d:%x set to 0x%x\n",
page, addr, data[0]);
} else {
@@ -102,9 +102,9 @@ wavefront_fx_memset (snd_wavefront_t *dev,
}
if (i != cnt) {
- snd_printk ("FX memset "
- "(0x%x, 0x%x, 0x%lx, %d) incomplete\n",
- page, addr, (unsigned long) data, cnt);
+ dev_err(dev->card->dev,
+ "FX memset (0x%x, 0x%x, 0x%lx, %d) incomplete\n",
+ page, addr, (unsigned long) data, cnt);
return -EIO;
}
}
@@ -123,7 +123,7 @@ snd_wavefront_fx_detect (snd_wavefront_t *dev)
*/
if (inb (dev->fx_status) & 0x80) {
- snd_printk ("Hmm, probably a Maui or Tropez.\n");
+ dev_err(dev->card->dev, "Hmm, probably a Maui or Tropez.\n");
return -1;
}
@@ -180,20 +180,20 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
case WFFX_MEMSET:
if (r.data[2] <= 0) {
- snd_printk ("cannot write "
- "<= 0 bytes to FX\n");
+ dev_err(dev->card->dev,
+ "cannot write <= 0 bytes to FX\n");
return -EIO;
} else if (r.data[2] == 1) {
pd = (unsigned short *) &r.data[3];
} else {
if (r.data[2] > 256) {
- snd_printk ("cannot write "
- "> 512 bytes to FX\n");
+ dev_err(dev->card->dev,
+ "cannot write > 512 bytes to FX\n");
return -EIO;
}
- page_data = memdup_user((unsigned char __user *)
- r.data[3],
- r.data[2] * sizeof(short));
+ page_data = memdup_array_user((unsigned char __user *)
+ r.data[3],
+ r.data[2], sizeof(short));
if (IS_ERR(page_data))
return PTR_ERR(page_data);
pd = page_data;
@@ -208,8 +208,8 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file,
break;
default:
- snd_printk ("FX: ioctl %d not yet supported\n",
- r.request);
+ dev_err(dev->card->dev, "FX: ioctl %d not yet supported\n",
+ r.request);
return -ENOTTY;
}
return err;
@@ -254,8 +254,8 @@ snd_wavefront_fx_start (snd_wavefront_t *dev)
goto out;
}
} else {
- snd_printk(KERN_ERR "invalid address"
- " in register data\n");
+ dev_err(dev->card->dev,
+ "invalid address in register data\n");
err = -1;
goto out;
}
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index 72e775ac7ad7..69d87c4cafae 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -113,7 +113,6 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
{
snd_wavefront_midi_t *midi = &card->wavefront.midi;
snd_wavefront_mpu_id mpu;
- unsigned long flags;
unsigned char midi_byte;
int max = 256, mask = 1;
int timeout;
@@ -142,11 +141,9 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
break;
}
- spin_lock_irqsave (&midi->virtual, flags);
- if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) {
- spin_unlock_irqrestore (&midi->virtual, flags);
+ guard(spinlock_irqsave)(&midi->virtual);
+ if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0)
goto __second;
- }
if (output_ready (midi)) {
if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
if (!midi->isvirtual ||
@@ -157,17 +154,14 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
} else {
if (midi->istimer) {
if (--midi->istimer <= 0)
- del_timer(&midi->timer);
+ timer_delete(&midi->timer);
}
midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
- spin_unlock_irqrestore (&midi->virtual, flags);
goto __second;
}
} else {
- spin_unlock_irqrestore (&midi->virtual, flags);
return;
}
- spin_unlock_irqrestore (&midi->virtual, flags);
}
__second:
@@ -185,15 +179,13 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
break;
}
- spin_lock_irqsave (&midi->virtual, flags);
+ guard(spinlock_irqsave)(&midi->virtual);
if (!midi->isvirtual)
mask = 0;
mpu = midi->output_mpu ^ mask;
mask = 0; /* don't invert the value from now */
- if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) {
- spin_unlock_irqrestore (&midi->virtual, flags);
+ if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0)
return;
- }
if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
goto __timer;
if (output_ready (midi)) {
@@ -212,23 +204,19 @@ static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
__timer:
if (midi->istimer) {
if (--midi->istimer <= 0)
- del_timer(&midi->timer);
+ timer_delete(&midi->timer);
}
midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
- spin_unlock_irqrestore (&midi->virtual, flags);
return;
}
} else {
- spin_unlock_irqrestore (&midi->virtual, flags);
return;
}
- spin_unlock_irqrestore (&midi->virtual, flags);
}
}
static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
@@ -243,17 +231,15 @@ static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream
if (!midi)
return -EIO;
- spin_lock_irqsave (&midi->open, flags);
+ guard(spinlock_irqsave)(&midi->open);
midi->mode[mpu] |= MPU401_MODE_INPUT;
midi->substream_input[mpu] = substream;
- spin_unlock_irqrestore (&midi->open, flags);
return 0;
}
static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
@@ -268,17 +254,15 @@ static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substrea
if (!midi)
return -EIO;
- spin_lock_irqsave (&midi->open, flags);
+ guard(spinlock_irqsave)(&midi->open);
midi->mode[mpu] |= MPU401_MODE_OUTPUT;
midi->substream_output[mpu] = substream;
- spin_unlock_irqrestore (&midi->open, flags);
return 0;
}
static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
@@ -293,16 +277,15 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea
if (!midi)
return -EIO;
- spin_lock_irqsave (&midi->open, flags);
+ guard(spinlock_irqsave)(&midi->open);
+ midi->substream_input[mpu] = NULL;
midi->mode[mpu] &= ~MPU401_MODE_INPUT;
- spin_unlock_irqrestore (&midi->open, flags);
return 0;
}
static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
@@ -317,15 +300,14 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre
if (!midi)
return -EIO;
- spin_lock_irqsave (&midi->open, flags);
+ guard(spinlock_irqsave)(&midi->open);
+ midi->substream_output[mpu] = NULL;
midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
- spin_unlock_irqrestore (&midi->open, flags);
return 0;
}
static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
@@ -341,30 +323,27 @@ static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *subst
if (!midi)
return;
- spin_lock_irqsave (&midi->virtual, flags);
+ guard(spinlock_irqsave)(&midi->virtual);
if (up) {
midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
} else {
midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
}
- spin_unlock_irqrestore (&midi->virtual, flags);
}
static void snd_wavefront_midi_output_timer(struct timer_list *t)
{
- snd_wavefront_midi_t *midi = from_timer(midi, t, timer);
+ snd_wavefront_midi_t *midi = timer_container_of(midi, t, timer);
snd_wavefront_card_t *card = midi->timer_card;
- unsigned long flags;
- spin_lock_irqsave (&midi->virtual, flags);
- mod_timer(&midi->timer, 1 + jiffies);
- spin_unlock_irqrestore (&midi->virtual, flags);
+ scoped_guard(spinlock_irqsave, &midi->virtual) {
+ mod_timer(&midi->timer, 1 + jiffies);
+ }
snd_wavefront_midi_output_write(card);
}
static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
snd_wavefront_mpu_id mpu;
@@ -380,22 +359,22 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs
if (!midi)
return;
- spin_lock_irqsave (&midi->virtual, flags);
- if (up) {
- if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
- if (!midi->istimer) {
- timer_setup(&midi->timer,
- snd_wavefront_midi_output_timer,
- 0);
- mod_timer(&midi->timer, 1 + jiffies);
+ scoped_guard(spinlock_irqsave, &midi->virtual) {
+ if (up) {
+ if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
+ if (!midi->istimer) {
+ timer_setup(&midi->timer,
+ snd_wavefront_midi_output_timer,
+ 0);
+ mod_timer(&midi->timer, 1 + jiffies);
+ }
+ midi->istimer++;
+ midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
}
- midi->istimer++;
- midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
+ } else {
+ midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
}
- } else {
- midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
}
- spin_unlock_irqrestore (&midi->virtual, flags);
if (up)
snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
@@ -405,7 +384,6 @@ void
snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
{
- unsigned long flags;
snd_wavefront_midi_t *midi;
static struct snd_rawmidi_substream *substream = NULL;
static int mpu = external_mpu;
@@ -419,37 +397,37 @@ snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
return;
}
- spin_lock_irqsave (&midi->virtual, flags);
- while (--max) {
-
- if (input_avail (midi)) {
- byte = read_data (midi);
-
- if (midi->isvirtual) {
- if (byte == WF_EXTERNAL_SWITCH) {
- substream = midi->substream_input[external_mpu];
- mpu = external_mpu;
- } else if (byte == WF_INTERNAL_SWITCH) {
- substream = midi->substream_output[internal_mpu];
+ scoped_guard(spinlock_irqsave, &midi->virtual) {
+ while (--max) {
+
+ if (input_avail(midi)) {
+ byte = read_data(midi);
+
+ if (midi->isvirtual) {
+ if (byte == WF_EXTERNAL_SWITCH) {
+ substream = midi->substream_input[external_mpu];
+ mpu = external_mpu;
+ } else if (byte == WF_INTERNAL_SWITCH) {
+ substream = midi->substream_output[internal_mpu];
+ mpu = internal_mpu;
+ } /* else just leave it as it is */
+ } else {
+ substream = midi->substream_input[internal_mpu];
mpu = internal_mpu;
- } /* else just leave it as it is */
- } else {
- substream = midi->substream_input[internal_mpu];
- mpu = internal_mpu;
- }
+ }
- if (substream == NULL) {
- continue;
- }
+ if (substream == NULL) {
+ continue;
+ }
- if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
- snd_rawmidi_receive(substream, &byte, 1);
+ if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
+ snd_rawmidi_receive(substream, &byte, 1);
+ }
+ } else {
+ break;
}
- } else {
- break;
}
- }
- spin_unlock_irqrestore (&midi->virtual, flags);
+ }
snd_wavefront_midi_output_write(card);
}
@@ -471,13 +449,10 @@ void
snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
{
- unsigned long flags;
-
- spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
+ guard(spinlock_irqsave)(&card->wavefront.midi.virtual);
// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
card->wavefront.midi.isvirtual = 0;
- spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
}
int
@@ -501,7 +476,8 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
for (i = 0; i < 30000 && !output_ready (midi); i++);
if (!output_ready (midi)) {
- snd_printk ("MIDI interface not ready for command\n");
+ dev_err(card->wavefront.card->dev,
+ "MIDI interface not ready for command\n");
return -1;
}
@@ -523,7 +499,8 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
}
if (!ok) {
- snd_printk ("cannot set UART mode for MIDI interface");
+ dev_err(card->wavefront.card->dev,
+ "cannot set UART mode for MIDI interface");
dev->interrupts_are_midi = 0;
return -1;
}
@@ -531,7 +508,8 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
/* Route external MIDI to WaveFront synth (by default) */
if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
- snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
+ dev_warn(card->wavefront.card->dev,
+ "can't enable MIDI-IN-2-synth routing.\n");
/* XXX error ? */
}
@@ -547,14 +525,16 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
*/
if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) {
- snd_printk ("virtual MIDI mode not disabled\n");
+ dev_warn(card->wavefront.card->dev,
+ "virtual MIDI mode not disabled\n");
return 0; /* We're OK, but missing the external MIDI dev */
}
snd_wavefront_midi_enable_virtual (card);
if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
- snd_printk ("cannot enable virtual MIDI mode.\n");
+ dev_warn(card->wavefront.card->dev,
+ "cannot enable virtual MIDI mode.\n");
snd_wavefront_midi_disable_virtual (card);
}
return 0;
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 13ce96148fa3..0d78533e1cfd 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -116,7 +116,7 @@ MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
#define DPRINT(cond, ...) \
if ((dev->debug & (cond)) == (cond)) { \
- snd_printk (__VA_ARGS__); \
+ pr_debug(__VA_ARGS__); \
}
#else
#define DPRINT(cond, args...)
@@ -341,7 +341,7 @@ snd_wavefront_cmd (snd_wavefront_t *dev,
wfcmd = wavefront_get_command(cmd);
if (!wfcmd) {
- snd_printk ("command 0x%x not supported.\n",
+ dev_err(dev->card->dev, "command 0x%x not supported.\n",
cmd);
return 1;
}
@@ -623,7 +623,7 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
/* check sample status */
if (snd_wavefront_cmd (dev, WFC_GET_NSAMPLES, rbuf, wbuf)) {
- snd_printk ("cannot request sample count.\n");
+ dev_err(dev->card->dev, "cannot request sample count.\n");
return -1;
}
@@ -635,8 +635,8 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
wbuf[1] = i >> 7;
if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
- snd_printk(KERN_WARNING "cannot identify sample "
- "type of slot %d\n", i);
+ dev_warn(dev->card->dev,
+ "cannot identify sample type of slot %d\n", i);
dev->sample_status[i] = WF_ST_EMPTY;
continue;
}
@@ -661,9 +661,9 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
break;
default:
- snd_printk ("unknown sample type for "
- "slot %d (0x%x)\n",
- i, rbuf[0]);
+ dev_err(dev->card->dev,
+ "unknown sample type for slot %d (0x%x)\n",
+ i, rbuf[0]);
}
if (rbuf[0] != WF_ST_EMPTY) {
@@ -671,9 +671,10 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
}
}
- snd_printk ("%d samples used (%d real, %d aliases, %d multi), "
- "%d empty\n", dev->samples_used, sc_real, sc_alias, sc_multi,
- WF_MAX_SAMPLE - dev->samples_used);
+ dev_info(dev->card->dev,
+ "%d samples used (%d real, %d aliases, %d multi), %d empty\n",
+ dev->samples_used, sc_real, sc_alias, sc_multi,
+ WF_MAX_SAMPLE - dev->samples_used);
return (0);
@@ -706,8 +707,8 @@ wavefront_get_patch_status (snd_wavefront_t *dev)
} else if (x == 3) { /* Bad patch number */
dev->patch_status[i] = 0;
} else {
- snd_printk ("upload patch "
- "error 0x%x\n", x);
+ dev_err(dev->card->dev,
+ "upload patch error 0x%x\n", x);
dev->patch_status[i] = 0;
return 1;
}
@@ -724,7 +725,8 @@ wavefront_get_patch_status (snd_wavefront_t *dev)
}
}
- snd_printk ("%d patch slots filled, %d in use\n", cnt, cnt2);
+ dev_info(dev->card->dev, "%d patch slots filled, %d in use\n",
+ cnt, cnt2);
return (0);
}
@@ -760,8 +762,8 @@ wavefront_get_program_status (snd_wavefront_t *dev)
} else if (x == 1) { /* Bad program number */
dev->prog_status[i] = 0;
} else {
- snd_printk ("upload program "
- "error 0x%x\n", x);
+ dev_err(dev->card->dev,
+ "upload program error 0x%x\n", x);
dev->prog_status[i] = 0;
}
}
@@ -772,7 +774,7 @@ wavefront_get_program_status (snd_wavefront_t *dev)
}
}
- snd_printk ("%d programs slots in use\n", cnt);
+ dev_info(dev->card->dev, "%d programs slots in use\n", cnt);
return (0);
}
@@ -796,7 +798,7 @@ wavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header)
munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES);
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) {
- snd_printk ("download patch failed\n");
+ dev_err(dev->card->dev, "download patch failed\n");
return -EIO;
}
@@ -837,7 +839,7 @@ wavefront_send_program (snd_wavefront_t *dev, wavefront_patch_info *header)
munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES);
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
- snd_printk ("download patch failed\n");
+ dev_err(dev->card->dev, "download patch failed\n");
return -EIO;
}
@@ -851,7 +853,7 @@ wavefront_freemem (snd_wavefront_t *dev)
char rbuf[8];
if (snd_wavefront_cmd (dev, WFC_REPORT_FREE_MEMORY, rbuf, NULL)) {
- snd_printk ("can't get memory stats.\n");
+ dev_err(dev->card->dev, "can't get memory stats.\n");
return -1;
} else {
return demunge_int32 (rbuf, 4);
@@ -901,7 +903,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
x = wavefront_find_free_sample(dev);
if (x < 0)
return -ENOMEM;
- snd_printk ("unspecified sample => %d\n", x);
+ dev_info(dev->card->dev, "unspecified sample => %d\n", x);
header->number = x;
}
@@ -935,9 +937,9 @@ wavefront_send_sample (snd_wavefront_t *dev,
if (dev->rom_samples_rdonly) {
if (dev->sample_status[header->number] & WF_SLOT_ROM) {
- snd_printk ("sample slot %d "
- "write protected\n",
- header->number);
+ dev_err(dev->card->dev,
+ "sample slot %d write protected\n",
+ header->number);
return -EACCES;
}
}
@@ -948,10 +950,10 @@ wavefront_send_sample (snd_wavefront_t *dev,
if (header->size) {
dev->freemem = wavefront_freemem (dev);
- if (dev->freemem < (int)header->size) {
- snd_printk ("insufficient memory to "
- "load %d byte sample.\n",
- header->size);
+ if (dev->freemem < 0 || dev->freemem < header->size) {
+ dev_err(dev->card->dev,
+ "insufficient memory to load %u byte sample.\n",
+ header->size);
return -ENOMEM;
}
@@ -960,8 +962,8 @@ wavefront_send_sample (snd_wavefront_t *dev,
skip = WF_GET_CHANNEL(&header->hdr.s);
if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
- snd_printk ("channel selection only "
- "possible on 16-bit samples");
+ dev_err(dev->card->dev,
+ "channel selection only possible on 16-bit samples");
return -EINVAL;
}
@@ -1057,8 +1059,8 @@ wavefront_send_sample (snd_wavefront_t *dev,
header->size ?
WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER,
NULL, sample_hdr)) {
- snd_printk ("sample %sdownload refused.\n",
- header->size ? "" : "header ");
+ dev_err(dev->card->dev, "sample %sdownload refused.\n",
+ header->size ? "" : "header ");
return -EIO;
}
@@ -1083,8 +1085,8 @@ wavefront_send_sample (snd_wavefront_t *dev,
}
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
- snd_printk ("download block "
- "request refused.\n");
+ dev_err(dev->card->dev,
+ "download block request refused.\n");
return -EIO;
}
@@ -1145,13 +1147,13 @@ wavefront_send_sample (snd_wavefront_t *dev,
dma_ack = wavefront_read(dev);
if (dma_ack != WF_DMA_ACK) {
if (dma_ack == -1) {
- snd_printk ("upload sample "
- "DMA ack timeout\n");
+ dev_err(dev->card->dev,
+ "upload sample DMA ack timeout\n");
return -EIO;
} else {
- snd_printk ("upload sample "
- "DMA ack error 0x%x\n",
- dma_ack);
+ dev_err(dev->card->dev,
+ "upload sample DMA ack error 0x%x\n",
+ dma_ack);
return -EIO;
}
}
@@ -1195,7 +1197,7 @@ wavefront_send_alias (snd_wavefront_t *dev, wavefront_patch_info *header)
munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2);
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
- snd_printk ("download alias failed.\n");
+ dev_err(dev->card->dev, "download alias failed.\n");
return -EIO;
}
@@ -1248,7 +1250,7 @@ wavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header)
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE,
(unsigned char *) (long) ((num_samples*2)+3),
msample_hdr)) {
- snd_printk ("download of multisample failed.\n");
+ dev_err(dev->card->dev, "download of multisample failed.\n");
kfree(msample_hdr);
return -EIO;
}
@@ -1271,7 +1273,7 @@ wavefront_fetch_multisample (snd_wavefront_t *dev,
munge_int32 (header->number, number, 2);
if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
- snd_printk ("upload multisample failed.\n");
+ dev_err(dev->card->dev, "upload multisample failed.\n");
return -EIO;
}
@@ -1290,16 +1292,16 @@ wavefront_fetch_multisample (snd_wavefront_t *dev,
val = wavefront_read(dev);
if (val == -1) {
- snd_printk ("upload multisample failed "
- "during sample loop.\n");
+ dev_err(dev->card->dev,
+ "upload multisample failed during sample loop.\n");
return -EIO;
}
d[0] = val;
val = wavefront_read(dev);
if (val == -1) {
- snd_printk ("upload multisample failed "
- "during sample loop.\n");
+ dev_err(dev->card->dev,
+ "upload multisample failed during sample loop.\n");
return -EIO;
}
d[1] = val;
@@ -1334,7 +1336,7 @@ wavefront_send_drum (snd_wavefront_t *dev, wavefront_patch_info *header)
}
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
- snd_printk ("download drum failed.\n");
+ dev_err(dev->card->dev, "download drum failed.\n");
return -EIO;
}
@@ -1352,7 +1354,7 @@ wavefront_find_free_sample (snd_wavefront_t *dev)
return i;
}
}
- snd_printk ("no free sample slots!\n");
+ dev_err(dev->card->dev, "no free sample slots!\n");
return -1;
}
@@ -1368,7 +1370,7 @@ wavefront_find_free_patch (snd_wavefront_t *dev)
return i;
}
}
- snd_printk ("no free patch slots!\n");
+ dev_err(dev->card->dev, "no free patch slots!\n");
return -1;
}
#endif
@@ -1385,7 +1387,7 @@ wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr)
if (copy_from_user (header, addr, sizeof(wavefront_patch_info) -
sizeof(wavefront_any))) {
- snd_printk ("bad address for load patch.\n");
+ dev_err(dev->card->dev, "bad address for load patch.\n");
err = -EFAULT;
goto __error;
}
@@ -1463,8 +1465,8 @@ wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr)
break;
default:
- snd_printk ("unknown patch type %d.\n",
- header->subkey);
+ dev_err(dev->card->dev, "unknown patch type %d.\n",
+ header->subkey);
err = -EINVAL;
break;
}
@@ -1527,13 +1529,13 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
switch (wc->cmd) {
case WFC_DISABLE_INTERRUPTS:
- snd_printk ("interrupts disabled.\n");
+ dev_dbg(dev->card->dev, "interrupts disabled.\n");
outb (0x80|0x20, dev->control_port);
dev->interrupts_are_midi = 1;
return 0;
case WFC_ENABLE_INTERRUPTS:
- snd_printk ("interrupts enabled.\n");
+ dev_dbg(dev->card->dev, "interrupts enabled.\n");
outb (0x80|0x40|0x20, dev->control_port);
dev->interrupts_are_midi = 1;
return 0;
@@ -1550,7 +1552,7 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
case WFC_IDENTIFY_SLOT_TYPE:
i = wc->wbuf[0] | (wc->wbuf[1] << 7);
if (i <0 || i >= WF_MAX_SAMPLE) {
- snd_printk ("invalid slot ID %d\n",
+ dev_err(dev->card->dev, "invalid slot ID %d\n",
i);
wc->status = EINVAL;
return -EINVAL;
@@ -1561,7 +1563,7 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
case WFC_DEBUG_DRIVER:
dev->debug = wc->wbuf[0];
- snd_printk ("debug = 0x%x\n", dev->debug);
+ dev_dbg(dev->card->dev, "debug = 0x%x\n", dev->debug);
return 0;
case WFC_UPLOAD_PATCH:
@@ -1578,8 +1580,8 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
return 0;
case WFC_UPLOAD_SAMPLE_ALIAS:
- snd_printk ("support for sample alias upload "
- "being considered.\n");
+ dev_err(dev->card->dev,
+ "support for sample alias upload being considered.\n");
wc->status = EINVAL;
return -EINVAL;
}
@@ -1620,9 +1622,8 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
break;
case WFC_UPLOAD_SAMPLE_ALIAS:
- snd_printk ("support for "
- "sample aliases still "
- "being considered.\n");
+ dev_err(dev->card->dev,
+ "support for sample aliases still being considered.\n");
break;
case WFC_VMIDI_OFF:
@@ -1740,10 +1741,10 @@ snd_wavefront_internal_interrupt (snd_wavefront_card_t *card)
return;
}
- spin_lock(&dev->irq_lock);
- dev->irq_ok = 1;
- dev->irq_cnt++;
- spin_unlock(&dev->irq_lock);
+ scoped_guard(spinlock, &dev->irq_lock) {
+ dev->irq_ok = 1;
+ dev->irq_cnt++;
+ }
wake_up(&dev->interrupt_sleeper);
}
@@ -1760,7 +1761,7 @@ snd_wavefront_internal_interrupt (snd_wavefront_card_t *card)
*/
static int
-snd_wavefront_interrupt_bits (int irq)
+snd_wavefront_interrupt_bits(snd_wavefront_t *dev, int irq)
{
int bits;
@@ -1780,7 +1781,7 @@ snd_wavefront_interrupt_bits (int irq)
break;
default:
- snd_printk ("invalid IRQ %d\n", irq);
+ dev_err(dev->card->dev, "invalid IRQ %d\n", irq);
bits = -1;
}
@@ -1795,11 +1796,11 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev,
wait_queue_entry_t wait;
init_waitqueue_entry(&wait, current);
- spin_lock_irq(&dev->irq_lock);
- add_wait_queue(&dev->interrupt_sleeper, &wait);
- dev->irq_ok = 0;
- outb (val,port);
- spin_unlock_irq(&dev->irq_lock);
+ scoped_guard(spinlock_irq, &dev->irq_lock) {
+ add_wait_queue(&dev->interrupt_sleeper, &wait);
+ dev->irq_ok = 0;
+ outb(val, port);
+ }
while (!dev->irq_ok && time_before(jiffies, timeout)) {
schedule_timeout_uninterruptible(1);
barrier();
@@ -1815,7 +1816,7 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
/* IRQ already checked */
- bits = snd_wavefront_interrupt_bits (dev->irq);
+ bits = snd_wavefront_interrupt_bits(dev, dev->irq);
/* try reset of port */
@@ -1885,7 +1886,7 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
*/
if (!dev->irq_ok) {
- snd_printk ("intr not received after h/w un-reset.\n");
+ dev_err(dev->card->dev, "intr not received after h/w un-reset.\n");
goto gone_bad;
}
@@ -1909,18 +1910,18 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
dev->data_port, ramcheck_time*HZ);
if (!dev->irq_ok) {
- snd_printk ("post-RAM-check interrupt not received.\n");
+ dev_err(dev->card->dev, "post-RAM-check interrupt not received.\n");
goto gone_bad;
}
if (!wavefront_wait (dev, STAT_CAN_READ)) {
- snd_printk ("no response to HW version cmd.\n");
+ dev_err(dev->card->dev, "no response to HW version cmd.\n");
goto gone_bad;
}
hwv[0] = wavefront_read(dev);
if (hwv[0] == -1) {
- snd_printk ("board not responding correctly.\n");
+ dev_err(dev->card->dev, "board not responding correctly.\n");
goto gone_bad;
}
@@ -1932,11 +1933,11 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
hwv[0] = wavefront_read(dev);
if (hwv[0] == -1) {
- snd_printk ("on-board RAM test failed "
- "(bad error code).\n");
+ dev_err(dev->card->dev,
+ "on-board RAM test failed (bad error code).\n");
} else {
- snd_printk ("on-board RAM test failed "
- "(error code: 0x%x).\n",
+ dev_err(dev->card->dev,
+ "on-board RAM test failed (error code: 0x%x).\n",
hwv[0]);
}
goto gone_bad;
@@ -1946,12 +1947,12 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
hwv[1] = wavefront_read(dev);
if (hwv[1] == -1) {
- snd_printk ("incorrect h/w response.\n");
+ dev_err(dev->card->dev, "incorrect h/w response.\n");
goto gone_bad;
}
- snd_printk ("hardware version %d.%d\n",
- hwv[0], hwv[1]);
+ dev_info(dev->card->dev, "hardware version %d.%d\n",
+ hwv[0], hwv[1]);
return 0;
@@ -1971,7 +1972,7 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
err = request_firmware(&firmware, path, dev->card->dev);
if (err < 0) {
- snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path);
+ dev_err(dev->card->dev, "firmware (%s) download failed!!!\n", path);
return 1;
}
@@ -1982,16 +1983,16 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
if (section_length == 0)
break;
if (section_length < 0 || section_length > WF_SECTION_MAX) {
- snd_printk(KERN_ERR
- "invalid firmware section length %d\n",
- section_length);
+ dev_err(dev->card->dev,
+ "invalid firmware section length %d\n",
+ section_length);
goto failure;
}
buf++;
len++;
if (firmware->size < len + section_length) {
- snd_printk(KERN_ERR "firmware section read error.\n");
+ dev_err(dev->card->dev, "firmware section read error.\n");
goto failure;
}
@@ -2008,15 +2009,14 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
/* get ACK */
if (!wavefront_wait(dev, STAT_CAN_READ)) {
- snd_printk(KERN_ERR "time out for firmware ACK.\n");
+ dev_err(dev->card->dev, "time out for firmware ACK.\n");
goto failure;
}
err = inb(dev->data_port);
if (err != WF_ACK) {
- snd_printk(KERN_ERR
- "download of section #%d not "
- "acknowledged, ack = 0x%x\n",
- section_cnt_downloaded + 1, err);
+ dev_err(dev->card->dev,
+ "download of section #%d not acknowledged, ack = 0x%x\n",
+ section_cnt_downloaded + 1, err);
goto failure;
}
@@ -2028,7 +2028,7 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
failure:
release_firmware(firmware);
- snd_printk(KERN_ERR "firmware download failed!!!\n");
+ dev_err(dev->card->dev, "firmware download failed!!!\n");
return 1;
}
@@ -2040,7 +2040,7 @@ wavefront_do_reset (snd_wavefront_t *dev)
char voices[1];
if (wavefront_reset_to_cleanliness (dev)) {
- snd_printk ("hw reset failed.\n");
+ dev_err(dev->card->dev, "hw reset failed.\n");
goto gone_bad;
}
@@ -2064,7 +2064,7 @@ wavefront_do_reset (snd_wavefront_t *dev)
(osrun_time*HZ));
if (!dev->irq_ok) {
- snd_printk ("no post-OS interrupt.\n");
+ dev_err(dev->card->dev, "no post-OS interrupt.\n");
goto gone_bad;
}
@@ -2074,7 +2074,7 @@ wavefront_do_reset (snd_wavefront_t *dev)
dev->data_port, (10*HZ));
if (!dev->irq_ok) {
- snd_printk ("no post-OS interrupt(2).\n");
+ dev_err(dev->card->dev, "no post-OS interrupt(2).\n");
goto gone_bad;
}
@@ -2094,20 +2094,20 @@ wavefront_do_reset (snd_wavefront_t *dev)
if (dev->freemem < 0)
goto gone_bad;
- snd_printk ("available DRAM %dk\n", dev->freemem / 1024);
+ dev_info(dev->card->dev, "available DRAM %dk\n", dev->freemem / 1024);
if (wavefront_write (dev, 0xf0) ||
wavefront_write (dev, 1) ||
(wavefront_read (dev) < 0)) {
dev->debug = 0;
- snd_printk ("MPU emulation mode not set.\n");
+ dev_err(dev->card->dev, "MPU emulation mode not set.\n");
goto gone_bad;
}
voices[0] = 32;
if (snd_wavefront_cmd (dev, WFC_SET_NVOICES, NULL, voices)) {
- snd_printk ("cannot set number of voices to 32.\n");
+ dev_err(dev->card->dev, "cannot set number of voices to 32.\n");
goto gone_bad;
}
@@ -2187,8 +2187,8 @@ snd_wavefront_detect (snd_wavefront_card_t *card)
dev->fw_version[0] = rbuf[0];
dev->fw_version[1] = rbuf[1];
- snd_printk ("firmware %d.%d already loaded.\n",
- rbuf[0], rbuf[1]);
+ dev_info(dev->card->dev, "firmware %d.%d already loaded.\n",
+ rbuf[0], rbuf[1]);
/* check that a command actually works */
@@ -2197,22 +2197,24 @@ snd_wavefront_detect (snd_wavefront_card_t *card)
dev->hw_version[0] = rbuf[0];
dev->hw_version[1] = rbuf[1];
} else {
- snd_printk ("not raw, but no "
- "hardware version!\n");
+ dev_err(dev->card->dev,
+ "not raw, but no hardware version!\n");
return -1;
}
if (!wf_raw) {
return 0;
} else {
- snd_printk ("reloading firmware as you requested.\n");
+ dev_info(dev->card->dev,
+ "reloading firmware as you requested.\n");
dev->israw = 1;
}
} else {
dev->israw = 1;
- snd_printk ("no response to firmware probe, assume raw.\n");
+ dev_info(dev->card->dev,
+ "no response to firmware probe, assume raw.\n");
}
diff --git a/sound/isa/wss/Makefile b/sound/isa/wss/Makefile
index 34d0636b3dc3..f23e71d0d5d4 100644
--- a/sound/isa/wss/Makefile
+++ b/sound/isa/wss/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2008 by Jaroslav Kysela <perex@perex.cz>
#
-snd-wss-lib-objs := wss_lib.o
+snd-wss-lib-y := wss_lib.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_WSS_LIB) += snd-wss-lib.o
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 026061b55ee9..6cf88625bbc3 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -187,15 +187,16 @@ void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk(KERN_DEBUG "out: auto calibration time out "
- "- reg = 0x%x, value = 0x%x\n", reg, value);
+ dev_dbg(chip->card->dev,
+ "out: auto calibration time out - reg = 0x%x, value = 0x%x\n",
+ reg, value);
#endif
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
wss_outb(chip, CS4231P(REG), value);
chip->image[reg] = value;
mb();
- snd_printdd("codec out - reg 0x%x = 0x%x\n",
- chip->mce_bit | reg, value);
+ dev_dbg(chip->card->dev, "codec out - reg 0x%x = 0x%x\n",
+ chip->mce_bit | reg, value);
}
EXPORT_SYMBOL(snd_wss_out);
@@ -204,8 +205,8 @@ unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk(KERN_DEBUG "in: auto calibration time out "
- "- reg = 0x%x\n", reg);
+ dev_dbg(chip->card->dev,
+ "in: auto calibration time out - reg = 0x%x\n", reg);
#endif
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
mb();
@@ -222,7 +223,7 @@ void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
wss_outb(chip, CS4231P(REG), val);
chip->eimage[CS4236_REG(reg)] = val;
#if 0
- printk(KERN_DEBUG "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+ dev_dbg(chip->card->dev, "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
#endif
}
EXPORT_SYMBOL(snd_cs4236_ext_out);
@@ -238,8 +239,8 @@ unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
{
unsigned char res;
res = wss_inb(chip, CS4231P(REG));
- printk(KERN_DEBUG "ext in : reg = 0x%x, val = 0x%x\n",
- reg, res);
+ dev_dbg(chip->card->dev, "ext in : reg = 0x%x, val = 0x%x\n",
+ reg, res);
return res;
}
#endif
@@ -250,87 +251,87 @@ EXPORT_SYMBOL(snd_cs4236_ext_in);
static void snd_wss_debug(struct snd_wss *chip)
{
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"CS4231 REGS: INDEX = 0x%02x "
" STATUS = 0x%02x\n",
wss_inb(chip, CS4231P(REGSEL)),
wss_inb(chip, CS4231P(STATUS)));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x00: left input = 0x%02x "
" 0x10: alt 1 (CFIG 2) = 0x%02x\n",
snd_wss_in(chip, 0x00),
snd_wss_in(chip, 0x10));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x01: right input = 0x%02x "
" 0x11: alt 2 (CFIG 3) = 0x%02x\n",
snd_wss_in(chip, 0x01),
snd_wss_in(chip, 0x11));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x02: GF1 left input = 0x%02x "
" 0x12: left line in = 0x%02x\n",
snd_wss_in(chip, 0x02),
snd_wss_in(chip, 0x12));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x03: GF1 right input = 0x%02x "
" 0x13: right line in = 0x%02x\n",
snd_wss_in(chip, 0x03),
snd_wss_in(chip, 0x13));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x04: CD left input = 0x%02x "
" 0x14: timer low = 0x%02x\n",
snd_wss_in(chip, 0x04),
snd_wss_in(chip, 0x14));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x05: CD right input = 0x%02x "
" 0x15: timer high = 0x%02x\n",
snd_wss_in(chip, 0x05),
snd_wss_in(chip, 0x15));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x06: left output = 0x%02x "
" 0x16: left MIC (PnP) = 0x%02x\n",
snd_wss_in(chip, 0x06),
snd_wss_in(chip, 0x16));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x07: right output = 0x%02x "
" 0x17: right MIC (PnP) = 0x%02x\n",
snd_wss_in(chip, 0x07),
snd_wss_in(chip, 0x17));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x08: playback format = 0x%02x "
" 0x18: IRQ status = 0x%02x\n",
snd_wss_in(chip, 0x08),
snd_wss_in(chip, 0x18));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x09: iface (CFIG 1) = 0x%02x "
" 0x19: left line out = 0x%02x\n",
snd_wss_in(chip, 0x09),
snd_wss_in(chip, 0x19));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x0a: pin control = 0x%02x "
" 0x1a: mono control = 0x%02x\n",
snd_wss_in(chip, 0x0a),
snd_wss_in(chip, 0x1a));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x0b: init & status = 0x%02x "
" 0x1b: right line out = 0x%02x\n",
snd_wss_in(chip, 0x0b),
snd_wss_in(chip, 0x1b));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x0c: revision & mode = 0x%02x "
" 0x1c: record format = 0x%02x\n",
snd_wss_in(chip, 0x0c),
snd_wss_in(chip, 0x1c));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x0d: loopback = 0x%02x "
" 0x1d: var freq (PnP) = 0x%02x\n",
snd_wss_in(chip, 0x0d),
snd_wss_in(chip, 0x1d));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x0e: ply upr count = 0x%02x "
" 0x1e: ply lwr count = 0x%02x\n",
snd_wss_in(chip, 0x0e),
snd_wss_in(chip, 0x1e));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
" 0x0f: rec upr count = 0x%02x "
" 0x1f: rec lwr count = 0x%02x\n",
snd_wss_in(chip, 0x0f),
@@ -359,32 +360,29 @@ static void snd_wss_busy_wait(struct snd_wss *chip)
void snd_wss_mce_up(struct snd_wss *chip)
{
- unsigned long flags;
int timeout;
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk(KERN_DEBUG
- "mce_up - auto calibration time out (0)\n");
+ dev_dbg(chip->card->dev,
+ "mce_up - auto calibration time out (0)\n");
#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
chip->mce_bit |= CS4231_MCE;
timeout = wss_inb(chip, CS4231P(REGSEL));
if (timeout == 0x80)
- snd_printk(KERN_DEBUG "mce_up [0x%lx]: "
- "serious init problem - codec still busy\n",
- chip->port);
+ dev_dbg(chip->card->dev,
+ "mce_up [0x%lx]: serious init problem - codec still busy\n",
+ chip->port);
if (!(timeout & CS4231_MCE))
wss_outb(chip, CS4231P(REGSEL),
chip->mce_bit | (timeout & 0x1f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
EXPORT_SYMBOL(snd_wss_mce_up);
void snd_wss_mce_down(struct snd_wss *chip)
{
- unsigned long flags;
unsigned long end_time;
int timeout;
int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848;
@@ -393,19 +391,19 @@ void snd_wss_mce_down(struct snd_wss *chip)
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk(KERN_DEBUG "mce_down [0x%lx] - "
- "auto calibration time out (0)\n",
- (long)CS4231P(REGSEL));
+ dev_dbg(chip->card->dev,
+ "mce_down [0x%lx] - auto calibration time out (0)\n",
+ (long)CS4231P(REGSEL));
#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->mce_bit &= ~CS4231_MCE;
- timeout = wss_inb(chip, CS4231P(REGSEL));
- wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ chip->mce_bit &= ~CS4231_MCE;
+ timeout = wss_inb(chip, CS4231P(REGSEL));
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+ }
if (timeout == 0x80)
- snd_printk(KERN_DEBUG "mce_down [0x%lx]: "
- "serious init problem - codec still busy\n",
- chip->port);
+ dev_dbg(chip->card->dev,
+ "mce_down [0x%lx]: serious init problem - codec still busy\n",
+ chip->port);
if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
return;
@@ -416,7 +414,7 @@ void snd_wss_mce_down(struct snd_wss *chip)
*/
msleep(1);
- snd_printdd("(1) jiffies = %lu\n", jiffies);
+ dev_dbg(chip->card->dev, "(1) jiffies = %lu\n", jiffies);
/* check condition up to 250 ms */
end_time = jiffies + msecs_to_jiffies(250);
@@ -424,27 +422,29 @@ void snd_wss_mce_down(struct snd_wss *chip)
CS4231_CALIB_IN_PROGRESS) {
if (time_after(jiffies, end_time)) {
- snd_printk(KERN_ERR "mce_down - "
- "auto calibration time out (2)\n");
+ dev_err(chip->card->dev,
+ "mce_down - auto calibration time out (2)\n");
return;
}
msleep(1);
}
- snd_printdd("(2) jiffies = %lu\n", jiffies);
+ dev_dbg(chip->card->dev, "(2) jiffies = %lu\n", jiffies);
/* check condition up to 100 ms */
end_time = jiffies + msecs_to_jiffies(100);
while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
if (time_after(jiffies, end_time)) {
- snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
+ dev_err(chip->card->dev,
+ "mce_down - auto calibration time out (3)\n");
return;
}
msleep(1);
}
- snd_printdd("(3) jiffies = %lu\n", jiffies);
- snd_printd("mce_down - exit = 0x%x\n", wss_inb(chip, CS4231P(REGSEL)));
+ dev_dbg(chip->card->dev, "(3) jiffies = %lu\n", jiffies);
+ dev_dbg(chip->card->dev, "mce_down - exit = 0x%x\n",
+ wss_inb(chip, CS4231P(REGSEL)));
}
EXPORT_SYMBOL(snd_wss_mce_down);
@@ -493,7 +493,7 @@ static int snd_wss_trigger(struct snd_pcm_substream *substream,
snd_pcm_trigger_done(s, substream);
}
}
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
if (do_start) {
chip->image[CS4231_IFACE_CTRL] |= what;
if (chip->trigger)
@@ -504,7 +504,6 @@ static int snd_wss_trigger(struct snd_pcm_substream *substream,
chip->trigger(chip, what, 0);
}
snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
- spin_unlock(&chip->reg_lock);
#if 0
snd_wss_debug(chip);
#endif
@@ -543,21 +542,18 @@ static unsigned char snd_wss_get_format(struct snd_wss *chip,
if (channels > 1)
rformat |= CS4231_STEREO;
#if 0
- snd_printk(KERN_DEBUG "get_format: 0x%x (mode=0x%x)\n", format, mode);
+ dev_dbg(chip->card->dev, "get_format: 0x%x (mode=0x%x)\n", format, mode);
#endif
return rformat;
}
static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
{
- unsigned long flags;
mute = mute ? 0x80 : 0;
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->calibrate_mute == mute) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
+ if (chip->calibrate_mute == mute)
return;
- }
if (!mute) {
snd_wss_dout(chip, CS4231_LEFT_INPUT,
chip->image[CS4231_LEFT_INPUT]);
@@ -605,20 +601,18 @@ static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]);
}
chip->calibrate_mute = mute;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_wss_playback_format(struct snd_wss *chip,
struct snd_pcm_hw_params *params,
unsigned char pdfr)
{
- unsigned long flags;
int full_calib = 1;
- mutex_lock(&chip->mce_mutex);
+ guard(mutex)(&chip->mce_mutex);
if (chip->hardware == WSS_HW_CS4231A ||
(chip->hardware & WSS_HW_CS4232_MASK)) {
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
chip->image[CS4231_ALT_FEATURE_1] | 0x10);
@@ -630,7 +624,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
udelay(100); /* Fixes audible clicks at least on GUS MAX */
full_calib = 0;
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
} else if (chip->hardware == WSS_HW_AD1845) {
unsigned rate = params_rate(params);
@@ -643,30 +636,28 @@ static void snd_wss_playback_format(struct snd_wss *chip,
* NOTE: We seem to need to write to the MSB before the LSB
* to get the correct sample frequency.
*/
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0));
snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
full_calib = 0;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if (full_calib) {
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) {
- if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)
- pdfr = (pdfr & 0xf0) |
- (chip->image[CS4231_REC_FORMAT] & 0x0f);
- } else {
- chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) {
+ if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)
+ pdfr = (pdfr & 0xf0) |
+ (chip->image[CS4231_REC_FORMAT] & 0x0f);
+ } else {
+ chip->image[CS4231_PLAYBK_FORMAT] = pdfr;
+ }
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr);
}
- snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (chip->hardware == WSS_HW_OPL3SA2)
udelay(100); /* this seems to help */
snd_wss_mce_down(chip);
}
- mutex_unlock(&chip->mce_mutex);
}
static void snd_wss_capture_format(struct snd_wss *chip,
@@ -676,10 +667,10 @@ static void snd_wss_capture_format(struct snd_wss *chip,
unsigned long flags;
int full_calib = 1;
- mutex_lock(&chip->mce_mutex);
+ guard(mutex)(&chip->mce_mutex);
if (chip->hardware == WSS_HW_CS4231A ||
(chip->hardware & WSS_HW_CS4232_MASK)) {
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */
(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
@@ -690,7 +681,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
chip->image[CS4231_ALT_FEATURE_1] &= ~0x20);
full_calib = 0;
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
} else if (chip->hardware == WSS_HW_AD1845) {
unsigned rate = params_rate(params);
@@ -703,12 +693,11 @@ static void snd_wss_capture_format(struct snd_wss *chip,
* NOTE: We seem to need to write to the MSB before the LSB
* to get the correct sample frequency.
*/
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0));
snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
full_calib = 0;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if (full_calib) {
snd_wss_mce_up(chip);
@@ -733,7 +722,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
}
- mutex_unlock(&chip->mce_mutex);
}
/*
@@ -751,10 +739,10 @@ static unsigned long snd_wss_timer_resolution(struct snd_timer *timer)
static int snd_wss_timer_start(struct snd_timer *timer)
{
- unsigned long flags;
unsigned int ticks;
struct snd_wss *chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->reg_lock);
ticks = timer->sticks;
if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
(unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
@@ -769,109 +757,100 @@ static int snd_wss_timer_start(struct snd_timer *timer)
chip->image[CS4231_ALT_FEATURE_1] |
CS4231_TIMER_ENABLE);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_wss_timer_stop(struct snd_timer *timer)
{
- unsigned long flags;
struct snd_wss *chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->reg_lock);
chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE;
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
chip->image[CS4231_ALT_FEATURE_1]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static void snd_wss_init(struct snd_wss *chip)
{
- unsigned long flags;
-
snd_wss_calibrate_mute(chip, 1);
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk(KERN_DEBUG "init: (1)\n");
+ dev_dbg(chip->card->dev, "init: (1)\n");
#endif
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
- CS4231_PLAYBACK_PIO |
- CS4231_RECORD_ENABLE |
- CS4231_RECORD_PIO |
- CS4231_CALIB_MODE);
- chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
- snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
+ CS4231_PLAYBACK_PIO |
+ CS4231_RECORD_ENABLE |
+ CS4231_RECORD_PIO |
+ CS4231_CALIB_MODE);
+ chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
+ snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+ }
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk(KERN_DEBUG "init: (2)\n");
+ dev_dbg(chip->card->dev, "init: (2)\n");
#endif
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
- snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
- snd_wss_out(chip,
- CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
+ snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+ snd_wss_out(chip,
+ CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
+ }
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk(KERN_DEBUG "init: (3) - afei = 0x%x\n",
- chip->image[CS4231_ALT_FEATURE_1]);
+ dev_dbg(chip->card->dev, "init: (3) - afei = 0x%x\n",
+ chip->image[CS4231_ALT_FEATURE_1]);
#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_ALT_FEATURE_2,
- chip->image[CS4231_ALT_FEATURE_2]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_wss_out(chip, CS4231_ALT_FEATURE_2,
+ chip->image[CS4231_ALT_FEATURE_2]);
+ }
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
- chip->image[CS4231_PLAYBK_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+ chip->image[CS4231_PLAYBK_FORMAT]);
+ }
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk(KERN_DEBUG "init: (4)\n");
+ dev_dbg(chip->card->dev, "init: (4)\n");
#endif
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (!(chip->hardware & WSS_HW_AD1848_MASK))
- snd_wss_out(chip, CS4231_REC_FORMAT,
- chip->image[CS4231_REC_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ snd_wss_out(chip, CS4231_REC_FORMAT,
+ chip->image[CS4231_REC_FORMAT]);
+ }
snd_wss_mce_down(chip);
snd_wss_calibrate_mute(chip, 0);
#ifdef SNDRV_DEBUG_MCE
- snd_printk(KERN_DEBUG "init: (5)\n");
+ dev_dbg(chip->card->dev, "init: (5)\n");
#endif
}
static int snd_wss_open(struct snd_wss *chip, unsigned int mode)
{
- unsigned long flags;
-
- mutex_lock(&chip->open_mutex);
+ guard(mutex)(&chip->open_mutex);
if ((chip->mode & mode) ||
- ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) {
- mutex_unlock(&chip->open_mutex);
+ ((chip->mode & WSS_MODE_OPEN) && chip->single_dma))
return -EAGAIN;
- }
if (chip->mode & WSS_MODE_OPEN) {
chip->mode |= mode;
- mutex_unlock(&chip->open_mutex);
return 0;
}
/* ok. now enable and ack CODEC IRQ */
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (!(chip->hardware & WSS_HW_AD1848_MASK)) {
snd_wss_out(chip, CS4231_IRQ_STATUS,
CS4231_PLAYBACK_IRQ |
@@ -890,10 +869,8 @@ static int snd_wss_open(struct snd_wss *chip, unsigned int mode)
CS4231_TIMER_IRQ);
snd_wss_out(chip, CS4231_IRQ_STATUS, 0);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->mode = mode;
- mutex_unlock(&chip->open_mutex);
return 0;
}
@@ -901,12 +878,10 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
{
unsigned long flags;
- mutex_lock(&chip->open_mutex);
+ guard(mutex)(&chip->open_mutex);
chip->mode &= ~mode;
- if (chip->mode & WSS_MODE_OPEN) {
- mutex_unlock(&chip->open_mutex);
+ if (chip->mode & WSS_MODE_OPEN)
return;
- }
/* disable IRQ */
spin_lock_irqsave(&chip->reg_lock, flags);
if (!(chip->hardware & WSS_HW_AD1848_MASK))
@@ -940,7 +915,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
spin_unlock_irqrestore(&chip->reg_lock, flags);
chip->mode = 0;
- mutex_unlock(&chip->open_mutex);
}
/*
@@ -994,18 +968,16 @@ static int snd_wss_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_wss *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
chip->p_dma_size = size;
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO);
snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1;
snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count);
snd_wss_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
#if 0
snd_wss_debug(chip);
#endif
@@ -1029,11 +1001,10 @@ static int snd_wss_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_wss *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
chip->c_dma_size = size;
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
@@ -1053,18 +1024,16 @@ static int snd_wss_capture_prepare(struct snd_pcm_substream *substream)
snd_wss_out(chip, CS4231_REC_UPR_CNT,
(unsigned char) (count >> 8));
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
void snd_wss_overrange(struct snd_wss *chip)
{
- unsigned long flags;
unsigned char res;
- spin_lock_irqsave(&chip->reg_lock, flags);
- res = snd_wss_in(chip, CS4231_TEST_INIT);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ res = snd_wss_in(chip, CS4231_TEST_INIT);
+ }
if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */
chip->capture_substream->runtime->overrange++;
}
@@ -1110,13 +1079,12 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
}
}
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
status = ~CS4231_ALL_IRQS | ~status;
if (chip->hardware & WSS_HW_AD1848_MASK)
wss_outb(chip, CS4231P(STATUS), 0);
else
snd_wss_out(chip, CS4231_IRQ_STATUS, status);
- spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
EXPORT_SYMBOL(snd_wss_interrupt);
@@ -1150,10 +1118,8 @@ static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *subst
static int snd_ad1848_probe(struct snd_wss *chip)
{
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
- unsigned long flags;
unsigned char r;
unsigned short hardware = 0;
- int err = 0;
int i;
while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
@@ -1161,7 +1127,7 @@ static int snd_ad1848_probe(struct snd_wss *chip)
return -ENODEV;
cond_resched();
}
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
/* set CS423x MODE 1 */
snd_wss_dout(chip, CS4231_MISC_INFO, 0);
@@ -1170,19 +1136,15 @@ static int snd_ad1848_probe(struct snd_wss *chip)
r = snd_wss_in(chip, CS4231_RIGHT_INPUT);
if (r != 0x45) {
/* RMGE always high on AD1847 */
- if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) {
- err = -ENODEV;
- goto out;
- }
+ if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45)
+ return -ENODEV;
hardware = WSS_HW_AD1847;
} else {
snd_wss_dout(chip, CS4231_LEFT_INPUT, 0xaa);
r = snd_wss_in(chip, CS4231_LEFT_INPUT);
/* L/RMGE always low on AT2320 */
- if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) {
- err = -ENODEV;
- goto out;
- }
+ if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa)
+ return -ENODEV;
}
/* clear pending IRQ */
@@ -1191,11 +1153,11 @@ static int snd_ad1848_probe(struct snd_wss *chip)
mb();
if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT)
- goto out;
+ return 0;
if (hardware) {
chip->hardware = hardware;
- goto out;
+ return 0;
}
r = snd_wss_in(chip, CS4231_MISC_INFO);
@@ -1224,14 +1186,11 @@ static int snd_ad1848_probe(struct snd_wss *chip)
chip->hardware = WSS_HW_AD1848;
out_mode:
snd_wss_dout(chip, CS4231_MISC_INFO, 0);
-out:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return err;
+ return 0;
}
static int snd_wss_probe(struct snd_wss *chip)
{
- unsigned long flags;
int i, id, rev, regnum;
unsigned char *ptr;
unsigned int hw;
@@ -1247,21 +1206,21 @@ static int snd_wss_probe(struct snd_wss *chip)
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
msleep(2);
else {
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_wss_out(chip, CS4231_MISC_INFO,
CS4231_MODE2);
id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (id == 0x0a)
break; /* this is valid value */
}
}
- snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
+ dev_dbg(chip->card->dev, "wss: port = 0x%lx, id = 0x%x\n",
+ chip->port, id);
if (id != 0x0a)
return -ENODEV; /* no valid device found */
rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
- snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
+ dev_dbg(chip->card->dev, "CS4231: VERSION (I25) = 0x%x\n", rev);
if (rev == 0x80) {
unsigned char tmp = snd_wss_in(chip, 23);
snd_wss_out(chip, 23, ~tmp);
@@ -1280,16 +1239,16 @@ static int snd_wss_probe(struct snd_wss *chip)
} else if (rev == 0x03) {
chip->hardware = WSS_HW_CS4236B;
} else {
- snd_printk(KERN_ERR
- "unknown CS chip with version 0x%x\n", rev);
+ dev_err(chip->card->dev,
+ "unknown CS chip with version 0x%x\n", rev);
return -ENODEV; /* unknown CS4231 chip? */
}
}
- spin_lock_irqsave(&chip->reg_lock, flags);
- wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */
- wss_outb(chip, CS4231P(STATUS), 0);
- mb();
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */
+ wss_outb(chip, CS4231P(STATUS), 0);
+ mb();
+ }
if (!(chip->hardware & WSS_HW_AD1848_MASK))
chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
@@ -1324,10 +1283,10 @@ static int snd_wss_probe(struct snd_wss *chip)
ptr = (unsigned char *) &chip->image;
regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
snd_wss_mce_down(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (i = 0; i < regnum; i++) /* ok.. fill all registers */
- snd_wss_out(chip, i, *ptr++);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ for (i = 0; i < regnum; i++) /* ok.. fill all registers */
+ snd_wss_out(chip, i, *ptr++);
+ }
snd_wss_mce_up(chip);
snd_wss_mce_down(chip);
@@ -1340,7 +1299,9 @@ static int snd_wss_probe(struct snd_wss *chip)
snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);
id = snd_cs4236_ext_in(chip, CS4236_VERSION);
snd_cs4236_ext_out(chip, CS4236_VERSION, rev);
- snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);
+ dev_dbg(chip->card->dev,
+ "CS4231: ext version; rev = 0x%x, id = 0x%x\n",
+ rev, id);
if ((id & 0x1f) == 0x1d) { /* CS4235 */
chip->hardware = WSS_HW_CS4235;
switch (id >> 5) {
@@ -1349,10 +1310,9 @@ static int snd_wss_probe(struct snd_wss *chip)
case 6:
break;
default:
- snd_printk(KERN_WARNING
- "unknown CS4235 chip "
- "(enhanced version = 0x%x)\n",
- id);
+ dev_warn(chip->card->dev,
+ "unknown CS4235 chip (enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x0b) { /* CS4236/B */
switch (id >> 5) {
@@ -1363,10 +1323,9 @@ static int snd_wss_probe(struct snd_wss *chip)
chip->hardware = WSS_HW_CS4236B;
break;
default:
- snd_printk(KERN_WARNING
- "unknown CS4236 chip "
- "(enhanced version = 0x%x)\n",
- id);
+ dev_warn(chip->card->dev,
+ "unknown CS4236 chip (enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x08) { /* CS4237B */
chip->hardware = WSS_HW_CS4237B;
@@ -1377,10 +1336,9 @@ static int snd_wss_probe(struct snd_wss *chip)
case 7:
break;
default:
- snd_printk(KERN_WARNING
- "unknown CS4237B chip "
- "(enhanced version = 0x%x)\n",
- id);
+ dev_warn(chip->card->dev,
+ "unknown CS4237B chip (enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x09) { /* CS4238B */
chip->hardware = WSS_HW_CS4238B;
@@ -1390,10 +1348,9 @@ static int snd_wss_probe(struct snd_wss *chip)
case 7:
break;
default:
- snd_printk(KERN_WARNING
- "unknown CS4238B chip "
- "(enhanced version = 0x%x)\n",
- id);
+ dev_warn(chip->card->dev,
+ "unknown CS4238B chip (enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x1e) { /* CS4239 */
chip->hardware = WSS_HW_CS4239;
@@ -1403,15 +1360,14 @@ static int snd_wss_probe(struct snd_wss *chip)
case 6:
break;
default:
- snd_printk(KERN_WARNING
- "unknown CS4239 chip "
- "(enhanced version = 0x%x)\n",
- id);
+ dev_warn(chip->card->dev,
+ "unknown CS4239 chip (enhanced version = 0x%x)\n",
+ id);
}
} else {
- snd_printk(KERN_WARNING
- "unknown CS4236/CS423xB chip "
- "(enhanced version = 0x%x)\n", id);
+ dev_warn(chip->card->dev,
+ "unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n",
+ id);
}
}
}
@@ -1595,12 +1551,11 @@ static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on)
static void snd_wss_suspend(struct snd_wss *chip)
{
int reg;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (reg = 0; reg < 32; reg++)
- chip->image[reg] = snd_wss_in(chip, reg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ for (reg = 0; reg < 32; reg++)
+ chip->image[reg] = snd_wss_in(chip, reg);
+ }
if (chip->thinkpad_flag)
snd_wss_thinkpad_twiddle(chip, 0);
}
@@ -1609,27 +1564,26 @@ static void snd_wss_suspend(struct snd_wss *chip)
static void snd_wss_resume(struct snd_wss *chip)
{
int reg;
- unsigned long flags;
/* int timeout; */
if (chip->thinkpad_flag)
snd_wss_thinkpad_twiddle(chip, 1);
snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- for (reg = 0; reg < 32; reg++) {
- switch (reg) {
- case CS4231_VERSION:
- break;
- default:
- snd_wss_out(chip, reg, chip->image[reg]);
- break;
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ for (reg = 0; reg < 32; reg++) {
+ switch (reg) {
+ case CS4231_VERSION:
+ break;
+ default:
+ snd_wss_out(chip, reg, chip->image[reg]);
+ break;
+ }
}
+ /* Yamaha needs this to resume properly */
+ if (chip->hardware == WSS_HW_OPL3SA2)
+ snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
+ chip->image[CS4231_PLAYBK_FORMAT]);
}
- /* Yamaha needs this to resume properly */
- if (chip->hardware == WSS_HW_OPL3SA2)
- snd_wss_out(chip, CS4231_PLAYBK_FORMAT,
- chip->image[CS4231_PLAYBK_FORMAT]);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
#if 1
snd_wss_mce_down(chip);
#else
@@ -1638,14 +1592,15 @@ static void snd_wss_resume(struct snd_wss *chip)
include rescheduling. -- iwai
*/
snd_wss_busy_wait(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- chip->mce_bit &= ~CS4231_MCE;
- timeout = wss_inb(chip, CS4231P(REGSEL));
- wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ chip->mce_bit &= ~CS4231_MCE;
+ timeout = wss_inb(chip, CS4231P(REGSEL));
+ wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
+ }
if (timeout == 0x80)
- snd_printk(KERN_ERR "down [0x%lx]: serious init problem "
- "- codec still busy\n", chip->port);
+ dev_err(chip->card->dev
+ "down [0x%lx]: serious init problem - codec still busy\n",
+ chip->port);
if ((timeout & CS4231_MCE) == 0 ||
!(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
return;
@@ -1757,7 +1712,7 @@ int snd_wss_create(struct snd_card *card,
chip->res_port = devm_request_region(card->dev, port, 4, "WSS");
if (!chip->res_port) {
- snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port);
+ dev_err(chip->card->dev, "wss: can't grab port 0x%lx\n", port);
return -EBUSY;
}
chip->port = port;
@@ -1765,7 +1720,7 @@ int snd_wss_create(struct snd_card *card,
chip->res_cport = devm_request_region(card->dev, cport, 8,
"CS4232 Control");
if (!chip->res_cport) {
- snd_printk(KERN_ERR
+ dev_err(chip->card->dev,
"wss: can't grab control port 0x%lx\n", cport);
return -ENODEV;
}
@@ -1774,20 +1729,20 @@ int snd_wss_create(struct snd_card *card,
if (!(hwshare & WSS_HWSHARE_IRQ))
if (devm_request_irq(card->dev, irq, snd_wss_interrupt, 0,
"WSS", (void *) chip)) {
- snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
+ dev_err(chip->card->dev, "wss: can't grab IRQ %d\n", irq);
return -EBUSY;
}
chip->irq = irq;
card->sync_irq = chip->irq;
if (!(hwshare & WSS_HWSHARE_DMA1) &&
snd_devm_request_dma(card->dev, dma1, "WSS - 1")) {
- snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1);
+ dev_err(chip->card->dev, "wss: can't grab DMA1 %d\n", dma1);
return -EBUSY;
}
chip->dma1 = dma1;
if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 &&
snd_devm_request_dma(card->dev, dma2, "WSS - 2")) {
- snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2);
+ dev_err(chip->card->dev, "wss: can't grab DMA2 %d\n", dma2);
return -EBUSY;
}
if (dma1 == dma2 || dma2 < 0) {
@@ -1810,8 +1765,8 @@ int snd_wss_create(struct snd_card *card,
#if 0
if (chip->hardware & WSS_HW_CS4232_MASK) {
if (chip->res_cport == NULL)
- snd_printk(KERN_ERR "CS4232 control port features are "
- "not accessible\n");
+ dev_err(chip->card->dev,
+ "CS4232 control port features are not accessible\n");
}
#endif
@@ -1863,7 +1818,7 @@ int snd_wss_pcm(struct snd_wss *chip, int device)
pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;
if (chip->hardware != WSS_HW_INTERWAVE)
pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
- strcpy(pcm->name, snd_wss_chip_id(chip));
+ strscpy(pcm->name, snd_wss_chip_id(chip));
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, chip->card->dev,
64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
@@ -1894,7 +1849,7 @@ int snd_wss_timer(struct snd_wss *chip, int device)
err = snd_timer_new(chip->card, "CS4231", &tid, &timer);
if (err < 0)
return err;
- strcpy(timer->name, snd_wss_chip_id(chip));
+ strscpy(timer->name, snd_wss_chip_id(chip));
timer->private_data = chip;
timer->private_free = snd_wss_timer_free;
timer->hw = snd_wss_timer_table;
@@ -1942,12 +1897,10 @@ static int snd_wss_get_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -1955,7 +1908,6 @@ static int snd_wss_put_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned short left, right;
int change;
@@ -1964,14 +1916,13 @@ static int snd_wss_put_mux(struct snd_kcontrol *kcontrol,
return -EINVAL;
left = ucontrol->value.enumerated.item[0] << 6;
right = ucontrol->value.enumerated.item[1] << 6;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
change = left != chip->image[CS4231_LEFT_INPUT] ||
right != chip->image[CS4231_RIGHT_INPUT];
snd_wss_out(chip, CS4231_LEFT_INPUT, left);
snd_wss_out(chip, CS4231_RIGHT_INPUT, right);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -1992,15 +1943,13 @@ int snd_wss_get_single(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -2011,7 +1960,6 @@ int snd_wss_put_single(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
@@ -2023,11 +1971,10 @@ int snd_wss_put_single(struct snd_kcontrol *kcontrol,
if (invert)
val = mask - val;
val <<= shift;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val = (chip->image[reg] & ~(mask << shift)) | val;
change = val != chip->image[reg];
snd_wss_out(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
EXPORT_SYMBOL(snd_wss_put_single);
@@ -2049,7 +1996,6 @@ int snd_wss_get_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -2057,10 +2003,9 @@ int snd_wss_get_double(struct snd_kcontrol *kcontrol,
int mask = (kcontrol->private_value >> 24) & 0xff;
int invert = (kcontrol->private_value >> 22) & 1;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert) {
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
@@ -2073,7 +2018,6 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int left_reg = kcontrol->private_value & 0xff;
int right_reg = (kcontrol->private_value >> 8) & 0xff;
int shift_left = (kcontrol->private_value >> 16) & 0x07;
@@ -2091,7 +2035,7 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol,
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (left_reg != right_reg) {
val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
@@ -2105,7 +2049,6 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol,
change = val1 != chip->image[left_reg];
snd_wss_out(chip, left_reg, val1);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
EXPORT_SYMBOL(snd_wss_put_double);
@@ -2174,7 +2117,7 @@ int snd_wss_mixer(struct snd_wss *chip)
card = chip->card;
- strcpy(card->mixername, chip->pcm->name);
+ strscpy(card->mixername, chip->pcm->name);
/* Use only the first 11 entries on AD1848 */
if (chip->hardware & WSS_HW_AD1848_MASK)
diff --git a/sound/mips/Makefile b/sound/mips/Makefile
index 7c86268b2bf3..bfbf3bda487b 100644
--- a/sound/mips/Makefile
+++ b/sound/mips/Makefile
@@ -3,8 +3,8 @@
# Makefile for ALSA
#
-snd-sgi-o2-objs := sgio2audio.o ad1843.o
-snd-sgi-hal2-objs := hal2.o
+snd-sgi-o2-y := sgio2audio.o ad1843.o
+snd-sgi-hal2-y := hal2.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c
index 3c26334227bb..f88e6a6733a5 100644
--- a/sound/mips/hal2.c
+++ b/sound/mips/hal2.c
@@ -706,7 +706,7 @@ static int hal2_pcm_create(struct snd_hal2 *hal2)
return err;
pcm->private_data = hal2;
- strcpy(pcm->name, "SGI HAL2");
+ strscpy(pcm->name, "SGI HAL2");
/* set operators */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -862,8 +862,8 @@ static int hal2_probe(struct platform_device *pdev)
return err;
}
- strcpy(card->driver, "SGI HAL2 Audio");
- strcpy(card->shortname, "SGI HAL2 Audio");
+ strscpy(card->driver, "SGI HAL2 Audio");
+ strscpy(card->shortname, "SGI HAL2 Audio");
sprintf(card->longname, "%s irq %i",
card->shortname,
SGI_HPCDMA_IRQ);
@@ -886,7 +886,7 @@ static void hal2_remove(struct platform_device *pdev)
static struct platform_driver hal2_driver = {
.probe = hal2_probe,
- .remove_new = hal2_remove,
+ .remove = hal2_remove,
.driver = {
.name = "sgihal2",
}
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index a8551ccdd1bf..077fdf2181c1 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/module.h>
#include <asm/ip32/ip32_ints.h>
@@ -102,9 +103,8 @@ static int read_ad1843_reg(void *priv, int reg)
{
struct snd_sgio2audio *chip = priv;
int val;
- unsigned long flags;
- spin_lock_irqsave(&chip->ad1843_lock, flags);
+ guard(spinlock_irqsave)(&chip->ad1843_lock);
writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) |
CODEC_CONTROL_READ, &mace->perif.audio.codec_control);
@@ -114,7 +114,6 @@ static int read_ad1843_reg(void *priv, int reg)
val = readq(&mace->perif.audio.codec_read);
- spin_unlock_irqrestore(&chip->ad1843_lock, flags);
return val;
}
@@ -125,9 +124,8 @@ static int write_ad1843_reg(void *priv, int reg, int word)
{
struct snd_sgio2audio *chip = priv;
int val;
- unsigned long flags;
- spin_lock_irqsave(&chip->ad1843_lock, flags);
+ guard(spinlock_irqsave)(&chip->ad1843_lock);
writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) |
(word << CODEC_CONTROL_WORD_SHIFT),
@@ -136,7 +134,6 @@ static int write_ad1843_reg(void *priv, int reg, int word)
val = readq(&mace->perif.audio.codec_control); /* flush bus */
udelay(200);
- spin_unlock_irqrestore(&chip->ad1843_lock, flags);
return 0;
}
@@ -350,10 +347,9 @@ static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip,
u64 *src;
s16 *dst;
u64 x;
- unsigned long flags;
struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime;
- spin_lock_irqsave(&chip->channel[ch].lock, flags);
+ guard(spinlock_irqsave)(&chip->channel[ch].lock);
src_base = (unsigned long) chip->ring_base | (ch << CHANNEL_RING_SHIFT);
src_pos = readq(&mace->perif.audio.chan[ch].read_ptr);
@@ -382,7 +378,6 @@ static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip,
writeq(src_pos, &mace->perif.audio.chan[ch].read_ptr); /* in bytes */
chip->channel[ch].pos = dst_pos;
- spin_unlock_irqrestore(&chip->channel[ch].lock, flags);
return ret;
}
@@ -398,10 +393,9 @@ static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip,
int src_pos;
u64 *dst;
s16 *src;
- unsigned long flags;
struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime;
- spin_lock_irqsave(&chip->channel[ch].lock, flags);
+ guard(spinlock_irqsave)(&chip->channel[ch].lock);
dst_base = (unsigned long)chip->ring_base | (ch << CHANNEL_RING_SHIFT);
dst_pos = readq(&mace->perif.audio.chan[ch].write_ptr);
@@ -432,7 +426,6 @@ static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip,
writeq(dst_pos, &mace->perif.audio.chan[ch].write_ptr); /* in bytes */
chip->channel[ch].pos = src_pos;
- spin_unlock_irqrestore(&chip->channel[ch].lock, flags);
return ret;
}
@@ -583,9 +576,8 @@ static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_sgio2audio_chan *chan = substream->runtime->private_data;
int ch = chan->idx;
- unsigned long flags;
- spin_lock_irqsave(&chip->channel[ch].lock, flags);
+ guard(spinlock_irqsave)(&chip->channel[ch].lock);
/* Setup the pseudo-dma transfer pointers. */
chip->channel[ch].pos = 0;
@@ -609,7 +601,6 @@ static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream)
runtime->channels);
break;
}
- spin_unlock_irqrestore(&chip->channel[ch].lock, flags);
return 0;
}
@@ -685,7 +676,7 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, "SGI O2 DAC1");
+ strscpy(pcm->name, "SGI O2 DAC1");
/* set operators */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -700,7 +691,7 @@ static int snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, "SGI O2 DAC2");
+ strscpy(pcm->name, "SGI O2 DAC2");
/* set operators */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -892,8 +883,8 @@ static int snd_sgio2audio_probe(struct platform_device *pdev)
return err;
}
- strcpy(card->driver, "SGI O2 Audio");
- strcpy(card->shortname, "SGI O2 Audio");
+ strscpy(card->driver, "SGI O2 Audio");
+ strscpy(card->shortname, "SGI O2 Audio");
sprintf(card->longname, "%s irq %i-%i",
card->shortname,
MACEISA_AUDIO1_DMAT_IRQ,
@@ -917,8 +908,8 @@ static void snd_sgio2audio_remove(struct platform_device *pdev)
static struct platform_driver sgio2audio_driver = {
.probe = snd_sgio2audio_probe,
- .remove_new = snd_sgio2audio_remove,
- .driver = {
+ .remove = snd_sgio2audio_remove,
+ .driver = {
.name = "sgio2audio",
}
};
diff --git a/sound/mips/snd-n64.c b/sound/mips/snd-n64.c
index bff6d85b8fe2..f17e63f2ff5a 100644
--- a/sound/mips/snd-n64.c
+++ b/sound/mips/snd-n64.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -80,10 +81,9 @@ static u32 n64mi_read_reg(struct n64audio *priv, const u8 reg)
static void n64audio_push(struct n64audio *priv)
{
struct snd_pcm_runtime *runtime = priv->chan.substream->runtime;
- unsigned long flags;
u32 count;
- spin_lock_irqsave(&priv->chan.lock, flags);
+ guard(spinlock_irqsave)(&priv->chan.lock);
count = priv->chan.writesize;
@@ -103,15 +103,12 @@ static void n64audio_push(struct n64audio *priv)
priv->chan.nextpos %= priv->chan.bufsize;
runtime->delay = runtime->period_size;
-
- spin_unlock_irqrestore(&priv->chan.lock, flags);
}
static irqreturn_t n64audio_isr(int irq, void *dev_id)
{
struct n64audio *priv = dev_id;
const u32 intrs = n64mi_read_reg(priv, MI_INTR_REG);
- unsigned long flags;
// Check it's ours
if (!(intrs & MI_INTR_AI))
@@ -120,11 +117,9 @@ static irqreturn_t n64audio_isr(int irq, void *dev_id)
n64audio_write_reg(priv, AI_STATUS_REG, 1);
if (priv->chan.substream && snd_pcm_running(priv->chan.substream)) {
- spin_lock_irqsave(&priv->chan.lock, flags);
-
- priv->chan.pos = priv->chan.nextpos;
-
- spin_unlock_irqrestore(&priv->chan.lock, flags);
+ scoped_guard(spinlock_irqsave, &priv->chan.lock) {
+ priv->chan.pos = priv->chan.nextpos;
+ }
snd_pcm_period_elapsed(priv->chan.substream);
if (priv->chan.substream && snd_pcm_running(priv->chan.substream))
@@ -220,7 +215,7 @@ static int n64audio_pcm_prepare(struct snd_pcm_substream *substream)
rate = 16;
n64audio_write_reg(priv, AI_BITCLOCK_REG, rate - 1);
- spin_lock_irq(&priv->chan.lock);
+ guard(spinlock_irq)(&priv->chan.lock);
/* Setup the pseudo-dma transfer pointers. */
priv->chan.pos = 0;
@@ -229,7 +224,6 @@ static int n64audio_pcm_prepare(struct snd_pcm_substream *substream)
priv->chan.writesize = snd_pcm_lib_period_bytes(substream);
priv->chan.bufsize = snd_pcm_lib_buffer_bytes(substream);
- spin_unlock_irq(&priv->chan.lock);
return 0;
}
@@ -327,14 +321,14 @@ static int __init n64audio_probe(struct platform_device *pdev)
goto fail_dma_alloc;
pcm->private_data = priv;
- strcpy(pcm->name, "N64 Audio");
+ strscpy(pcm->name, "N64 Audio");
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &n64audio_pcm_ops);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, card->dev, 0, 0);
- strcpy(card->driver, "N64 Audio");
- strcpy(card->shortname, "N64 Audio");
- strcpy(card->longname, "N64 Audio");
+ strscpy(card->driver, "N64 Audio");
+ strscpy(card->shortname, "N64 Audio");
+ strscpy(card->longname, "N64 Audio");
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index 81c6a9830727..6188469de8af 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -1618,4 +1618,6 @@ static void __exit dmasound_atari_cleanup(void)
module_init(dmasound_atari_init);
module_exit(dmasound_atari_cleanup);
+
+MODULE_DESCRIPTION("Atari TT and Falcon DMA Sound Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 164335d3c200..dea2d9b18fc9 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -204,6 +204,7 @@ module_param(numWriteBufs, int, 0);
static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */
module_param(writeBufSize, int, 0);
+MODULE_DESCRIPTION("Atari/Amiga/Q40 core DMA sound driver");
MODULE_LICENSE("GPL");
static int sq_unit = -1;
@@ -380,7 +381,6 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
static const struct file_operations mixer_fops =
{
.owner = THIS_MODULE,
- .llseek = no_llseek,
.unlocked_ioctl = mixer_unlocked_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.open = mixer_open,
@@ -1154,7 +1154,6 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
static const struct file_operations sq_fops =
{
.owner = THIS_MODULE,
- .llseek = no_llseek,
.write = sq_write,
.poll = sq_poll,
.unlocked_ioctl = sq_unlocked_ioctl,
@@ -1350,7 +1349,6 @@ static ssize_t state_read(struct file *file, char __user *buf, size_t count,
static const struct file_operations state_fops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
.read = state_read,
.open = state_open,
.release = state_release,
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
index 23cf8284ce36..8d443a3663d3 100644
--- a/sound/oss/dmasound/dmasound_paula.c
+++ b/sound/oss/dmasound/dmasound_paula.c
@@ -720,20 +720,26 @@ static int __init amiga_audio_probe(struct platform_device *pdev)
return dmasound_init();
}
-static int __exit amiga_audio_remove(struct platform_device *pdev)
+static void __exit amiga_audio_remove(struct platform_device *pdev)
{
dmasound_deinit();
- return 0;
}
-static struct platform_driver amiga_audio_driver = {
+/*
+ * amiga_audio_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver amiga_audio_driver __refdata = {
.remove = __exit_p(amiga_audio_remove),
- .driver = {
+ .driver = {
.name = "amiga-audio",
},
};
module_platform_driver_probe(amiga_audio_driver, amiga_audio_probe);
+MODULE_DESCRIPTION("Amiga Paula DMA Sound Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:amiga-audio");
diff --git a/sound/parisc/Makefile b/sound/parisc/Makefile
index 10891c3b7d91..84c71490fb72 100644
--- a/sound/parisc/Makefile
+++ b/sound/parisc/Makefile
@@ -3,7 +3,7 @@
# Makefile for ALSA
#
-snd-harmony-objs := harmony.o
+snd-harmony-y := harmony.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_HARMONY) += snd-harmony.o
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index db9c296dd688..4b5a54da25fb 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -140,32 +140,25 @@ harmony_enable_interrupts(struct snd_harmony *h)
static void
harmony_mute(struct snd_harmony *h)
{
- unsigned long flags;
-
- spin_lock_irqsave(&h->mixer_lock, flags);
+ guard(spinlock_irqsave)(&h->mixer_lock);
harmony_wait_for_control(h);
harmony_write(h, HARMONY_GAINCTL, HARMONY_GAIN_SILENCE);
- spin_unlock_irqrestore(&h->mixer_lock, flags);
}
static void
harmony_unmute(struct snd_harmony *h)
{
- unsigned long flags;
-
- spin_lock_irqsave(&h->mixer_lock, flags);
+ guard(spinlock_irqsave)(&h->mixer_lock);
harmony_wait_for_control(h);
harmony_write(h, HARMONY_GAINCTL, h->st.gain);
- spin_unlock_irqrestore(&h->mixer_lock, flags);
}
static void
harmony_set_control(struct snd_harmony *h)
{
u32 ctrl;
- unsigned long flags;
- spin_lock_irqsave(&h->lock, flags);
+ guard(spinlock_irqsave)(&h->lock);
ctrl = (HARMONY_CNTL_C |
(h->st.format << 6) |
@@ -174,8 +167,6 @@ harmony_set_control(struct snd_harmony *h)
harmony_wait_for_control(h);
harmony_write(h, HARMONY_CNTL, ctrl);
-
- spin_unlock_irqrestore(&h->lock, flags);
}
static irqreturn_t
@@ -184,53 +175,53 @@ snd_harmony_interrupt(int irq, void *dev)
u32 dstatus;
struct snd_harmony *h = dev;
- spin_lock(&h->lock);
- harmony_disable_interrupts(h);
- harmony_wait_for_control(h);
- dstatus = harmony_read(h, HARMONY_DSTATUS);
- spin_unlock(&h->lock);
+ scoped_guard(spinlock, &h->lock) {
+ harmony_disable_interrupts(h);
+ harmony_wait_for_control(h);
+ dstatus = harmony_read(h, HARMONY_DSTATUS);
+ }
if (dstatus & HARMONY_DSTATUS_PN) {
if (h->psubs && h->st.playing) {
- spin_lock(&h->lock);
- h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
- h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */
-
- harmony_write(h, HARMONY_PNXTADD,
- h->pbuf.addr + h->pbuf.buf);
- h->stats.play_intr++;
- spin_unlock(&h->lock);
+ scoped_guard(spinlock, &h->lock) {
+ h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
+ h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */
+
+ harmony_write(h, HARMONY_PNXTADD,
+ h->pbuf.addr + h->pbuf.buf);
+ h->stats.play_intr++;
+ }
snd_pcm_period_elapsed(h->psubs);
} else {
- spin_lock(&h->lock);
- harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
- h->stats.silence_intr++;
- spin_unlock(&h->lock);
+ scoped_guard(spinlock, &h->lock) {
+ harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
+ h->stats.silence_intr++;
+ }
}
}
if (dstatus & HARMONY_DSTATUS_RN) {
if (h->csubs && h->st.capturing) {
- spin_lock(&h->lock);
- h->cbuf.buf += h->cbuf.count;
- h->cbuf.buf %= h->cbuf.size;
-
- harmony_write(h, HARMONY_RNXTADD,
- h->cbuf.addr + h->cbuf.buf);
- h->stats.rec_intr++;
- spin_unlock(&h->lock);
+ scoped_guard(spinlock, &h->lock) {
+ h->cbuf.buf += h->cbuf.count;
+ h->cbuf.buf %= h->cbuf.size;
+
+ harmony_write(h, HARMONY_RNXTADD,
+ h->cbuf.addr + h->cbuf.buf);
+ h->stats.rec_intr++;
+ }
snd_pcm_period_elapsed(h->csubs);
} else {
- spin_lock(&h->lock);
- harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
- h->stats.graveyard_intr++;
- spin_unlock(&h->lock);
+ scoped_guard(spinlock, &h->lock) {
+ harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
+ h->stats.graveyard_intr++;
+ }
}
}
- spin_lock(&h->lock);
- harmony_enable_interrupts(h);
- spin_unlock(&h->lock);
+ scoped_guard(spinlock, &h->lock) {
+ harmony_enable_interrupts(h);
+ }
return IRQ_HANDLED;
}
@@ -297,7 +288,7 @@ snd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd)
if (h->st.capturing)
return -EBUSY;
- spin_lock(&h->lock);
+ guard(spinlock)(&h->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
h->st.playing = 1;
@@ -316,11 +307,9 @@ snd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_SUSPEND:
default:
- spin_unlock(&h->lock);
snd_BUG();
return -EINVAL;
}
- spin_unlock(&h->lock);
return 0;
}
@@ -333,7 +322,7 @@ snd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd)
if (h->st.playing)
return -EBUSY;
- spin_lock(&h->lock);
+ guard(spinlock)(&h->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
h->st.capturing = 1;
@@ -352,11 +341,9 @@ snd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_SUSPEND:
default:
- spin_unlock(&h->lock);
snd_BUG();
return -EINVAL;
}
- spin_unlock(&h->lock);
return 0;
}
@@ -601,7 +588,7 @@ snd_harmony_pcm_init(struct snd_harmony *h)
pcm->private_data = h;
pcm->info_flags = 0;
- strcpy(pcm->name, "harmony");
+ strscpy(pcm->name, "harmony");
h->pcm = pcm;
h->psubs = NULL;
@@ -674,7 +661,7 @@ snd_harmony_volume_get(struct snd_kcontrol *kc,
int invert = (kc->private_value >> 24) & 0xff;
int left, right;
- spin_lock_irq(&h->mixer_lock);
+ guard(spinlock_irq)(&h->mixer_lock);
left = (h->st.gain >> shift_left) & mask;
right = (h->st.gain >> shift_right) & mask;
@@ -687,8 +674,6 @@ snd_harmony_volume_get(struct snd_kcontrol *kc,
if (shift_left != shift_right)
ucontrol->value.integer.value[1] = right;
- spin_unlock_irq(&h->mixer_lock);
-
return 0;
}
@@ -704,7 +689,7 @@ snd_harmony_volume_put(struct snd_kcontrol *kc,
int left, right;
int old_gain = h->st.gain;
- spin_lock_irq(&h->mixer_lock);
+ guard(spinlock_irq)(&h->mixer_lock);
left = ucontrol->value.integer.value[0] & mask;
if (invert)
@@ -722,8 +707,6 @@ snd_harmony_volume_put(struct snd_kcontrol *kc,
snd_harmony_set_new_gain(h);
- spin_unlock_irq(&h->mixer_lock);
-
return h->st.gain != old_gain;
}
@@ -743,13 +726,11 @@ snd_harmony_captureroute_get(struct snd_kcontrol *kc,
struct snd_harmony *h = snd_kcontrol_chip(kc);
int value;
- spin_lock_irq(&h->mixer_lock);
+ guard(spinlock_irq)(&h->mixer_lock);
value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1;
ucontrol->value.enumerated.item[0] = value;
- spin_unlock_irq(&h->mixer_lock);
-
return 0;
}
@@ -761,7 +742,7 @@ snd_harmony_captureroute_put(struct snd_kcontrol *kc,
int value;
int old_gain = h->st.gain;
- spin_lock_irq(&h->mixer_lock);
+ guard(spinlock_irq)(&h->mixer_lock);
value = ucontrol->value.enumerated.item[0] & 1;
h->st.gain &= ~HARMONY_GAIN_IS_MASK;
@@ -769,8 +750,6 @@ snd_harmony_captureroute_put(struct snd_kcontrol *kc,
snd_harmony_set_new_gain(h);
- spin_unlock_irq(&h->mixer_lock);
-
return h->st.gain != old_gain;
}
@@ -823,7 +802,7 @@ snd_harmony_mixer_init(struct snd_harmony *h)
if (snd_BUG_ON(!h))
return -EINVAL;
card = h->card;
- strcpy(card->mixername, "Harmony Gain control interface");
+ strscpy(card->mixername, "Harmony Gain control interface");
for (idx = 0; idx < HARMONY_CONTROLS; idx++) {
err = snd_ctl_add(card,
@@ -937,8 +916,8 @@ snd_harmony_probe(struct parisc_device *padev)
if (err < 0)
goto free_and_ret;
- strcpy(card->driver, "harmony");
- strcpy(card->shortname, "Harmony");
+ strscpy(card->driver, "harmony");
+ strscpy(card->shortname, "Harmony");
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, h->hpa, h->irq);
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 861958451ef5..e0996a9d90b0 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -26,7 +26,7 @@ config SND_ALS300
select SND_PCM
select SND_AC97_CODEC
select SND_OPL3_LIB
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
@@ -36,6 +36,7 @@ config SND_ALS300
config SND_ALS4000
tristate "Avance Logic ALS4000"
depends on ISA_DMA_API
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -51,7 +52,7 @@ config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for the integrated AC97 sound
device on motherboards using the ALi M5451 Audio Controller
@@ -96,6 +97,7 @@ config SND_ATIIXP_MODEM
config SND_AU8810
tristate "Aureal Advantage"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -110,6 +112,7 @@ config SND_AU8810
config SND_AU8820
tristate "Aureal Vortex"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -123,6 +126,7 @@ config SND_AU8820
config SND_AU8830
tristate "Aureal Vortex 2"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -157,7 +161,7 @@ config SND_AZT3328
select SND_RAWMIDI
select SND_AC97_CODEC
select SND_TIMER
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
@@ -193,6 +197,7 @@ config SND_BT87X_OVERCLOCK
config SND_CA0106
tristate "SB Audigy LS / Live 24bit"
+ depends on HAS_IOPORT
select SND_AC97_CODEC
select SND_RAWMIDI
select SND_VMASTER
@@ -205,6 +210,7 @@ config SND_CA0106
config SND_CMIPCI
tristate "C-Media 8338, 8738, 8768, 8770"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
@@ -221,6 +227,7 @@ config SND_OXYGEN_LIB
config SND_OXYGEN
tristate "C-Media 8786, 8787, 8788 (Oxygen)"
+ depends on HAS_IOPORT
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -246,6 +253,7 @@ config SND_OXYGEN
config SND_CS4281
tristate "Cirrus Logic (Sound Fusion) CS4281"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_RAWMIDI
select SND_AC97_CODEC
@@ -257,6 +265,7 @@ config SND_CS4281
config SND_CS46XX
tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_AC97_CODEC
select FW_LOADER
@@ -290,6 +299,7 @@ config SND_CS5530
config SND_CS5535AUDIO
tristate "CS5535/CS5536 Audio"
depends on X86_32 || MIPS || COMPILE_TEST
+ depends on HAS_IOPORT
select SND_PCM
select SND_AC97_CODEC
help
@@ -307,6 +317,7 @@ config SND_CS5535AUDIO
config SND_CTXFI
tristate "Creative Sound Blaster X-Fi"
+ depends on HAS_IOPORT
select SND_PCM
help
If you want to use soundcards based on Creative Sound Blastr X-Fi
@@ -468,7 +479,7 @@ config SND_EMU10K1
select SND_AC97_CODEC
select SND_TIMER
select SND_SEQ_DEVICE if SND_SEQUENCER != n
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y to include support for Sound Blaster PCI 512, Live!,
Audigy and E-MU APS/0404/1010/1212/1616/1820 soundcards.
@@ -491,7 +502,7 @@ config SND_EMU10K1X
tristate "Emu10k1X (Dell OEM Version)"
select SND_AC97_CODEC
select SND_RAWMIDI
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for the Dell OEM version of the
Sound Blaster Live!.
@@ -501,6 +512,7 @@ config SND_EMU10K1X
config SND_ENS1370
tristate "(Creative) Ensoniq AudioPCI 1370"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_PCM
help
@@ -511,6 +523,7 @@ config SND_ENS1370
config SND_ENS1371
tristate "(Creative) Ensoniq AudioPCI 1371/1373"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_AC97_CODEC
help
@@ -525,7 +538,7 @@ config SND_ES1938
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on ESS Solo-1
(ES1938, ES1946, ES1969) chips.
@@ -537,7 +550,7 @@ config SND_ES1968
tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on ESS Maestro
1/2/2E chips.
@@ -569,6 +582,7 @@ config SND_ES1968_RADIO
config SND_FM801
tristate "ForteMedia FM801"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
@@ -624,7 +638,7 @@ config SND_ICE1712
select SND_MPU401_UART
select SND_AC97_CODEC
select BITREVERSE
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on the
ICE1712 (Envy24) chip.
@@ -640,6 +654,7 @@ config SND_ICE1712
config SND_ICE1724
tristate "ICE/VT1724/1720 (Envy24HT/PT)"
+ depends on HAS_IOPORT
select SND_RAWMIDI
select SND_AC97_CODEC
select SND_VMASTER
@@ -712,7 +727,7 @@ config SND_LX6464ES
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on ESS Maestro 3
(Allegro) chips.
@@ -753,6 +768,7 @@ config SND_NM256
config SND_PCXHR
tristate "Digigram PCXHR"
+ depends on HAS_IOPORT
select FW_LOADER
select SND_PCM
select SND_HWDEP
@@ -764,6 +780,7 @@ config SND_PCXHR
config SND_RIPTIDE
tristate "Conexant Riptide"
+ depends on HAS_IOPORT
select FW_LOADER
select SND_OPL3_LIB
select SND_MPU401_UART
@@ -808,6 +825,7 @@ config SND_RME9652
config SND_SE6X
tristate "Studio Evolution SE6X"
depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict
+ depends on HAS_IOPORT
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -830,7 +848,7 @@ config SND_SONICVIBES
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on the S3
SonicVibes chip.
@@ -842,7 +860,7 @@ config SND_TRIDENT
tristate "Trident 4D-Wave DX/NX; SiS 7018"
select SND_MPU401_UART
select SND_AC97_CODEC
- depends on ZONE_DMA
+ depends on ZONE_DMA && HAS_IOPORT
help
Say Y here to include support for soundcards based on Trident
4D-Wave DX/NX or SiS 7018 chips.
@@ -852,6 +870,7 @@ config SND_TRIDENT
config SND_VIA82XX
tristate "VIA 82C686A/B, 8233/8235 AC97 Controller"
+ depends on HAS_IOPORT
select SND_MPU401_UART
select SND_AC97_CODEC
help
@@ -863,6 +882,7 @@ config SND_VIA82XX
config SND_VIA82XX_MODEM
tristate "VIA 82C686A/B, 8233 based Modems"
+ depends on HAS_IOPORT
select SND_AC97_CODEC
help
Say Y here to include support for the integrated MC97 modem on
@@ -873,6 +893,7 @@ config SND_VIA82XX_MODEM
config SND_VIRTUOSO
tristate "Asus Virtuoso 66/100/200 (Xonar)"
+ depends on HAS_IOPORT
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -889,6 +910,7 @@ config SND_VIRTUOSO
config SND_VX222
tristate "Digigram VX222"
+ depends on HAS_IOPORT
select SND_VX_LIB
help
Say Y here to include support for Digigram VX222 soundcards.
@@ -898,6 +920,7 @@ config SND_VX222
config SND_YMFPCI
tristate "Yamaha YMF724/740/744/754"
+ depends on HAS_IOPORT
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
@@ -910,5 +933,3 @@ config SND_YMFPCI
will be called snd-ymfpci.
endif # SND_PCI
-
-source "sound/pci/hda/Kconfig"
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 04cac7469139..9d5e8e12ae73 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -4,30 +4,30 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ad1889-objs := ad1889.o
-snd-als300-objs := als300.o
-snd-als4000-objs := als4000.o
-snd-atiixp-objs := atiixp.o
-snd-atiixp-modem-objs := atiixp_modem.o
-snd-azt3328-objs := azt3328.o
-snd-bt87x-objs := bt87x.o
-snd-cmipci-objs := cmipci.o
-snd-cs4281-objs := cs4281.o
-snd-cs5530-objs := cs5530.o
-snd-ens1370-objs := ens1370.o ak4531_codec.o
-snd-ens1371-objs := ens1371.o
-snd-es1938-objs := es1938.o
-snd-es1968-objs := es1968.o
-snd-fm801-objs := fm801.o
-snd-intel8x0-objs := intel8x0.o
-snd-intel8x0m-objs := intel8x0m.o
-snd-maestro3-objs := maestro3.o
-snd-rme32-objs := rme32.o
-snd-rme96-objs := rme96.o
-snd-sis7019-objs := sis7019.o
-snd-sonicvibes-objs := sonicvibes.o
-snd-via82xx-objs := via82xx.o
-snd-via82xx-modem-objs := via82xx_modem.o
+snd-ad1889-y := ad1889.o
+snd-als300-y := als300.o
+snd-als4000-y := als4000.o
+snd-atiixp-y := atiixp.o
+snd-atiixp-modem-y := atiixp_modem.o
+snd-azt3328-y := azt3328.o
+snd-bt87x-y := bt87x.o
+snd-cmipci-y := cmipci.o
+snd-cs4281-y := cs4281.o
+snd-cs5530-y := cs5530.o
+snd-ens1370-y := ens1370.o ak4531_codec.o
+snd-ens1371-y := ens1371.o
+snd-es1938-y := es1938.o
+snd-es1968-y := es1968.o
+snd-fm801-y := fm801.o
+snd-intel8x0-y := intel8x0.o
+snd-intel8x0m-y := intel8x0m.o
+snd-maestro3-y := maestro3.o
+snd-rme32-y := rme32.o
+snd-rme96-y := rme96.o
+snd-sis7019-y := sis7019.o
+snd-sonicvibes-y := sonicvibes.o
+snd-via82xx-y := via82xx.o
+snd-via82xx-modem-y := via82xx_modem.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AD1889) += snd-ad1889.o
@@ -69,7 +69,6 @@ obj-$(CONFIG_SND) += \
lx6464es/ \
echoaudio/ \
emu10k1/ \
- hda/ \
ice1712/ \
korg1212/ \
mixart/ \
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 9afc5906d662..c54bdefa5afe 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -326,11 +326,10 @@ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned sh
{
if (!snd_ac97_valid_reg(ac97, reg))
return;
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
ac97->regs[reg] = value;
ac97->bus->ops->write(ac97, reg, value);
set_bit(reg, ac97->reg_accessed);
- mutex_unlock(&ac97->reg_mutex);
}
EXPORT_SYMBOL(snd_ac97_write_cache);
@@ -353,14 +352,13 @@ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short va
if (!snd_ac97_valid_reg(ac97, reg))
return -EINVAL;
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
change = ac97->regs[reg] != value;
if (change) {
ac97->regs[reg] = value;
ac97->bus->ops->write(ac97, reg, value);
}
set_bit(reg, ac97->reg_accessed);
- mutex_unlock(&ac97->reg_mutex);
return change;
}
@@ -381,14 +379,10 @@ EXPORT_SYMBOL(snd_ac97_update);
*/
int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value)
{
- int change;
-
if (!snd_ac97_valid_reg(ac97, reg))
return -EINVAL;
- mutex_lock(&ac97->reg_mutex);
- change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);
- mutex_unlock(&ac97->reg_mutex);
- return change;
+ guard(mutex)(&ac97->reg_mutex);
+ return snd_ac97_update_bits_nolock(ac97, reg, mask, value);
}
EXPORT_SYMBOL(snd_ac97_update_bits);
@@ -416,12 +410,12 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns
int change;
unsigned short old, new, cfg;
- mutex_lock(&ac97->page_mutex);
+ guard(mutex)(&ac97->page_mutex);
old = ac97->spec.ad18xx.pcmreg[codec];
new = (old & ~mask) | (value & mask);
change = old != new;
if (change) {
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG);
ac97->spec.ad18xx.pcmreg[codec] = new;
/* select single codec */
@@ -433,9 +427,7 @@ static int snd_ac97_ad18xx_update_pcm_bits(struct snd_ac97 *ac97, int codec, uns
/* select all codecs */
ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG,
cfg | 0x7000);
- mutex_unlock(&ac97->reg_mutex);
}
- mutex_unlock(&ac97->page_mutex);
return change;
}
@@ -716,12 +708,11 @@ static int snd_ac97_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_
{
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
ucontrol->value.iec958.status[0] = ac97->spdif_status & 0xff;
ucontrol->value.iec958.status[1] = (ac97->spdif_status >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (ac97->spdif_status >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (ac97->spdif_status >> 24) & 0xff;
- mutex_unlock(&ac97->reg_mutex);
return 0;
}
@@ -760,7 +751,7 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_
}
}
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
change = ac97->spdif_status != new;
ac97->spdif_status = new;
@@ -794,7 +785,6 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
}
}
- mutex_unlock(&ac97->reg_mutex);
return change;
}
@@ -811,7 +801,7 @@ static int snd_ac97_put_spsa(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
value = (ucontrol->value.integer.value[0] & mask);
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
mask <<= shift;
value <<= shift;
old = snd_ac97_read_cache(ac97, reg);
@@ -825,7 +815,6 @@ static int snd_ac97_put_spsa(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
if (extst & AC97_EA_SPDIF)
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
}
- mutex_unlock(&ac97->reg_mutex);
return change;
}
@@ -936,10 +925,9 @@ static int snd_ac97_ad18xx_pcm_get_volume(struct snd_kcontrol *kcontrol, struct
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
int codec = kcontrol->private_value & 3;
- mutex_lock(&ac97->page_mutex);
+ guard(mutex)(&ac97->page_mutex);
ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31);
ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31);
- mutex_unlock(&ac97->page_mutex);
return 0;
}
@@ -1840,7 +1828,8 @@ static const struct ac97_codec_id *look_for_codec_id(const struct ac97_codec_id
return NULL;
}
-void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int modem)
+void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name,
+ size_t maxlen, int modem)
{
const struct ac97_codec_id *pid;
@@ -1852,7 +1841,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m
if (! pid)
return;
- strcpy(name, pid->name);
+ strscpy(name, pid->name, maxlen);
if (ac97 && pid->patch) {
if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||
(! modem && ! (pid->flags & AC97_MODEM_PATCH)))
@@ -1861,17 +1850,19 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m
pid = look_for_codec_id(snd_ac97_codec_ids, id);
if (pid) {
- strcat(name, " ");
- strcat(name, pid->name);
+ strlcat(name, " ", maxlen);
+ strlcat(name, pid->name, maxlen);
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)))
pid->patch(ac97);
}
- } else
- sprintf(name + strlen(name), " id %x", id & 0xff);
+ } else {
+ int l = strlen(name);
+ snprintf(name + l, maxlen - l, " id %x", id & 0xff);
+ }
}
/**
@@ -2069,10 +2060,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
.dev_disconnect = snd_ac97_dev_disconnect,
};
- if (rac97)
- *rac97 = NULL;
- if (snd_BUG_ON(!bus || !template))
+ if (snd_BUG_ON(!bus || !template || !rac97))
return -EINVAL;
+ *rac97 = NULL;
if (snd_BUG_ON(template->num >= 4))
return -EINVAL;
if (bus->codec[template->num])
@@ -2296,15 +2286,15 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
/* additional initializations */
if (bus->ops->init)
bus->ops->init(ac97);
- snd_ac97_get_name(ac97, ac97->id, name, !ac97_is_audio(ac97));
- snd_ac97_get_name(NULL, ac97->id, name, !ac97_is_audio(ac97)); // ac97->id might be changed in the special setup code
+ snd_ac97_get_name(ac97, ac97->id, name, sizeof(name), !ac97_is_audio(ac97));
+ snd_ac97_get_name(NULL, ac97->id, name, sizeof(name), !ac97_is_audio(ac97)); // ac97->id might be changed in the special setup code
if (! ac97->build_ops)
ac97->build_ops = &null_build_ops;
if (ac97_is_audio(ac97)) {
char comp[16];
if (card->mixername[0] == '\0') {
- strcpy(card->mixername, name);
+ strscpy(card->mixername, name);
} else {
if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {
strcat(card->mixername, ",");
@@ -2325,7 +2315,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
if (ac97_is_modem(ac97)) {
char comp[16];
if (card->mixername[0] == '\0') {
- strcpy(card->mixername, name);
+ strscpy(card->mixername, name);
} else {
if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {
strcat(card->mixername, ",");
@@ -2462,8 +2452,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
* (for avoiding loud click noises for many (OSS) apps
* that open/close frequently)
*/
- schedule_delayed_work(&ac97->power_work,
- msecs_to_jiffies(power_save * 1000));
+ schedule_delayed_work(&ac97->power_work, secs_to_jiffies(power_save));
else {
cancel_delayed_work(&ac97->power_work);
update_power_regs(ac97);
diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h
index 8eeae2dec552..965284eb4b33 100644
--- a/sound/pci/ac97/ac97_local.h
+++ b/sound/pci/ac97/ac97_local.h
@@ -8,7 +8,7 @@
*/
void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name,
- int modem);
+ size_t maxlen, int modem);
int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg,
unsigned short mask, unsigned short value);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 4b5f33de70d5..64cc39dd2008 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -41,12 +41,9 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro
static void reset_tlv(struct snd_ac97 *ac97, const char *name,
const unsigned int *tlv)
{
- struct snd_ctl_elem_id sid;
struct snd_kcontrol *kctl;
- memset(&sid, 0, sizeof(sid));
- strcpy(sid.name, name);
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kctl = snd_ctl_find_id(ac97->bus->card, &sid);
+
+ kctl = snd_ctl_find_id_mixer(ac97->bus->card, name);
if (kctl && kctl->tlv.p)
kctl->tlv.p = tlv;
}
@@ -57,12 +54,11 @@ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsi
unsigned short page_save;
int ret;
- mutex_lock(&ac97->page_mutex);
+ guard(mutex)(&ac97->page_mutex);
page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
ret = snd_ac97_update_bits(ac97, reg, mask, value);
snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
- mutex_unlock(&ac97->page_mutex); /* unlock paging */
return ret;
}
@@ -301,7 +297,7 @@ static int patch_yamaha_ymf7x3_3d(struct snd_ac97 *ac97)
err = snd_ctl_add(ac97->bus->card, kctl);
if (err < 0)
return err;
- strcpy(kctl->id.name, "3D Control - Wide");
+ strscpy(kctl->id.name, "3D Control - Wide");
kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
err = snd_ctl_add(ac97->bus->card,
@@ -894,7 +890,7 @@ static int patch_sigmatel_stac9700_3d(struct snd_ac97 * ac97)
err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97));
if (err < 0)
return err;
- strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
+ strscpy(kctl->id.name, "3D Control Sigmatel - Depth");
kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
return 0;
@@ -909,13 +905,13 @@ static int patch_sigmatel_stac9708_3d(struct snd_ac97 * ac97)
err = snd_ctl_add(ac97->bus->card, kctl);
if (err < 0)
return err;
- strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
+ strscpy(kctl->id.name, "3D Control Sigmatel - Depth");
kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 0, 3, 0);
kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97);
err = snd_ctl_add(ac97->bus->card, kctl);
if (err < 0)
return err;
- strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
+ strscpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
return 0;
@@ -979,12 +975,11 @@ static int snd_ac97_stac9708_put_bias(struct snd_kcontrol *kcontrol, struct snd_
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
int err;
- mutex_lock(&ac97->page_mutex);
+ guard(mutex)(&ac97->page_mutex);
snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010,
(ucontrol->value.integer.value[0] & 1) << 4);
snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0);
- mutex_unlock(&ac97->page_mutex);
return err;
}
@@ -3431,11 +3426,7 @@ static const char * const follower_sws_vt1616[] = {
static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
const char *name)
{
- struct snd_ctl_elem_id id;
- memset(&id, 0, sizeof(id));
- id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id.name, name);
- return snd_ctl_find_id(ac97->bus->card, &id);
+ return snd_ctl_find_id_mixer(ac97->bus->card, name);
}
/* create a virtual master control and add followers */
@@ -3444,7 +3435,6 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
const char * const *followers)
{
struct snd_kcontrol *kctl;
- const char * const *s;
int err;
kctl = snd_ctl_make_virtual_master(name, tlv);
@@ -3454,20 +3444,7 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
if (err < 0)
return err;
- for (s = followers; *s; s++) {
- struct snd_kcontrol *sctl;
-
- sctl = snd_ac97_find_mixer_ctl(ac97, *s);
- if (!sctl) {
- dev_dbg(ac97->bus->card->dev,
- "Cannot find follower %s, skipped\n", *s);
- continue;
- }
- err = snd_ctl_add_follower(kctl, sctl);
- if (err < 0)
- return err;
- }
- return 0;
+ return snd_ctl_add_followers(ac97->bus->card, kctl, followers);
}
static int patch_vt1616_specific(struct snd_ac97 * ac97)
@@ -3720,7 +3697,7 @@ static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol,
unsigned short datpag, uaj;
struct snd_ac97 *pac97 = snd_kcontrol_chip(kcontrol);
- mutex_lock(&pac97->page_mutex);
+ guard(mutex)(&pac97->page_mutex);
datpag = snd_ac97_read(pac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, 0);
@@ -3729,7 +3706,6 @@ static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol,
vt1618_uaj[kcontrol->private_value].mask;
snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, datpag);
- mutex_unlock(&pac97->page_mutex);
ucontrol->value.enumerated.item[0] = uaj >>
vt1618_uaj[kcontrol->private_value].shift;
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index 5fee8e89790f..4715d88ff8f4 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -192,7 +192,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate)
mask = AC97_SC_SPSR_MASK;
}
- mutex_lock(&ac97->reg_mutex);
+ guard(mutex)(&ac97->reg_mutex);
old = snd_ac97_read(ac97, reg) & mask;
if (old != bits) {
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
@@ -217,7 +217,6 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate)
ac97->spdif_status = sbits;
}
snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
- mutex_unlock(&ac97->reg_mutex);
return 0;
}
@@ -571,33 +570,31 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
return err;
}
}
- spin_lock_irq(&pcm->bus->bus_lock);
- for (i = 3; i < 12; i++) {
- if (!(slots & (1 << i)))
- continue;
- ok_flag = 0;
- for (cidx = 0; cidx < 4; cidx++) {
- if (bus->used_slots[pcm->stream][cidx] & (1 << i)) {
- spin_unlock_irq(&pcm->bus->bus_lock);
- err = -EBUSY;
- goto error;
+ scoped_guard(spinlock_irq, &pcm->bus->bus_lock) {
+ for (i = 3; i < 12; i++) {
+ if (!(slots & (1 << i)))
+ continue;
+ ok_flag = 0;
+ for (cidx = 0; cidx < 4; cidx++) {
+ if (bus->used_slots[pcm->stream][cidx] & (1 << i)) {
+ err = -EBUSY;
+ goto error;
+ }
+ if (pcm->r[r].rslots[cidx] & (1 << i)) {
+ bus->used_slots[pcm->stream][cidx] |= (1 << i);
+ ok_flag++;
+ }
}
- if (pcm->r[r].rslots[cidx] & (1 << i)) {
- bus->used_slots[pcm->stream][cidx] |= (1 << i);
- ok_flag++;
+ if (!ok_flag) {
+ dev_err(bus->card->dev,
+ "cannot find configuration for AC97 slot %i\n",
+ i);
+ err = -EAGAIN;
+ goto error;
}
}
- if (!ok_flag) {
- spin_unlock_irq(&pcm->bus->bus_lock);
- dev_err(bus->card->dev,
- "cannot find configuration for AC97 slot %i\n",
- i);
- err = -EAGAIN;
- goto error;
- }
+ pcm->cur_dbl = r;
}
- pcm->cur_dbl = r;
- spin_unlock_irq(&pcm->bus->bus_lock);
for (i = 3; i < 12; i++) {
if (!(slots & (1 << i)))
continue;
@@ -665,7 +662,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
#endif
bus = pcm->bus;
- spin_lock_irq(&pcm->bus->bus_lock);
+ guard(spinlock_irq)(&pcm->bus->bus_lock);
for (i = 3; i < 12; i++) {
if (!(slots & (1 << i)))
continue;
@@ -674,7 +671,6 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
}
pcm->aslots = 0;
pcm->cur_dbl = 0;
- spin_unlock_irq(&pcm->bus->bus_lock);
return 0;
}
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
index 5426f7bc9884..1c9d76994b3a 100644
--- a/sound/pci/ac97/ac97_proc.c
+++ b/sound/pci/ac97/ac97_proc.c
@@ -98,7 +98,7 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe
static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" };
static const char *double_rate_slots[4] = { "10/11", "7/8", "reserved", "reserved" };
- snd_ac97_get_name(NULL, ac97->id, name, 0);
+ snd_ac97_get_name(NULL, ac97->id, name, sizeof(name), 0);
snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
@@ -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]);
@@ -329,7 +329,7 @@ static void snd_ac97_proc_read(struct snd_info_entry *entry, struct snd_info_buf
{
struct snd_ac97 *ac97 = entry->private_data;
- mutex_lock(&ac97->page_mutex);
+ guard(mutex)(&ac97->page_mutex);
if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86
int idx;
for (idx = 0; idx < 3; idx++)
@@ -355,7 +355,6 @@ static void snd_ac97_proc_read(struct snd_info_entry *entry, struct snd_info_buf
} else {
snd_ac97_proc_read_main(ac97, buffer, 0);
}
- mutex_unlock(&ac97->page_mutex);
}
#ifdef CONFIG_SND_DEBUG
@@ -365,7 +364,8 @@ static void snd_ac97_proc_regs_write(struct snd_info_entry *entry, struct snd_in
struct snd_ac97 *ac97 = entry->private_data;
char line[64];
unsigned int reg, val;
- mutex_lock(&ac97->page_mutex);
+
+ guard(mutex)(&ac97->page_mutex);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
@@ -373,7 +373,6 @@ static void snd_ac97_proc_regs_write(struct snd_info_entry *entry, struct snd_in
if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff)
snd_ac97_write_cache(ac97, reg, val);
}
- mutex_unlock(&ac97->page_mutex);
}
#endif
@@ -392,7 +391,7 @@ static void snd_ac97_proc_regs_read(struct snd_info_entry *entry,
{
struct snd_ac97 *ac97 = entry->private_data;
- mutex_lock(&ac97->page_mutex);
+ guard(mutex)(&ac97->page_mutex);
if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86
int idx;
@@ -408,7 +407,6 @@ static void snd_ac97_proc_regs_read(struct snd_info_entry *entry,
} else {
snd_ac97_proc_regs_read_main(ac97, buffer, 0);
}
- mutex_unlock(&ac97->page_mutex);
}
void snd_ac97_proc_init(struct snd_ac97 * ac97)
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 50e30704bf6f..f4ec404c0d15 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -353,7 +353,7 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss)
reg |= AD_DS_WSMC_WAST;
/* let's make sure we don't clobber ourselves */
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
chip->wave.size = size;
chip->wave.reg = reg;
@@ -372,8 +372,6 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss)
/* writes flush */
ad1889_readw(chip, AD_DS_WSMC);
- spin_unlock_irq(&chip->lock);
-
dev_dbg(chip->card->dev,
"prepare playback: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n",
chip->wave.addr, count, size, reg, rt->rate);
@@ -403,7 +401,7 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss)
reg |= AD_DS_RAMC_ADST;
/* let's make sure we don't clobber ourselves */
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
chip->ramc.size = size;
chip->ramc.reg = reg;
@@ -419,8 +417,6 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss)
/* writes flush */
ad1889_readw(chip, AD_DS_RAMC);
- spin_unlock_irq(&chip->lock);
-
dev_dbg(chip->card->dev,
"prepare capture: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n",
chip->ramc.addr, count, size, reg, rt->rate);
@@ -605,7 +601,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
chip->psubs = NULL;
@@ -626,7 +622,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 +638,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 +650,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 +665,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) ?
@@ -775,7 +771,7 @@ snd_ad1889_free(struct snd_card *card)
{
struct snd_ad1889 *chip = card->private_data;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
ad1889_mute(chip);
@@ -785,8 +781,6 @@ snd_ad1889_free(struct snd_card *card)
/* clear DISR. If we don't, we'd better jump off the Eiffel Tower */
ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI);
ad1889_readl(chip, AD_DMA_DISR); /* flush, dammit! */
-
- spin_unlock_irq(&chip->lock);
}
static int
@@ -810,12 +804,11 @@ snd_ad1889_create(struct snd_card *card, struct pci_dev *pci)
chip->irq = -1;
/* (1) PCI resource allocation */
- err = pcim_iomap_regions(pci, 1 << 0, card->driver);
- if (err < 0)
- return err;
+ chip->iobase = pcim_iomap_region(pci, 0, card->driver);
+ if (IS_ERR(chip->iobase))
+ return PTR_ERR(chip->iobase);
chip->bar = pci_resource_start(pci, 0);
- chip->iobase = pcim_iomap_table(pci)[0];
pci_set_master(pci);
@@ -867,8 +860,8 @@ __snd_ad1889_probe(struct pci_dev *pci,
return err;
chip = card->private_data;
- strcpy(card->driver, "AD1889");
- strcpy(card->shortname, "Analog Devices AD1889");
+ strscpy(card->driver, "AD1889");
+ strscpy(card->shortname, "Analog Devices AD1889");
/* (3) */
err = snd_ad1889_create(card, pci);
diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c
index 6af88e7b86f8..cdad47e4098d 100644
--- a/sound/pci/ak4531_codec.c
+++ b/sound/pci/ak4531_codec.c
@@ -77,9 +77,8 @@ static int snd_ak4531_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int invert = (kcontrol->private_value >> 22) & 1;
int val;
- mutex_lock(&ak4531->reg_mutex);
+ guard(mutex)(&ak4531->reg_mutex);
val = (ak4531->regs[reg] >> shift) & mask;
- mutex_unlock(&ak4531->reg_mutex);
if (invert) {
val = mask - val;
}
@@ -102,11 +101,10 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
val = mask - val;
}
val <<= shift;
- mutex_lock(&ak4531->reg_mutex);
+ guard(mutex)(&ak4531->reg_mutex);
val = (ak4531->regs[reg] & ~(mask << shift)) | val;
change = val != ak4531->regs[reg];
ak4531->write(ak4531, reg, ak4531->regs[reg] = val);
- mutex_unlock(&ak4531->reg_mutex);
return change;
}
@@ -146,10 +144,9 @@ static int snd_ak4531_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int invert = (kcontrol->private_value >> 22) & 1;
int left, right;
- mutex_lock(&ak4531->reg_mutex);
+ guard(mutex)(&ak4531->reg_mutex);
left = (ak4531->regs[left_reg] >> left_shift) & mask;
right = (ak4531->regs[right_reg] >> right_shift) & mask;
- mutex_unlock(&ak4531->reg_mutex);
if (invert) {
left = mask - left;
right = mask - right;
@@ -179,7 +176,7 @@ static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
left <<= left_shift;
right <<= right_shift;
- mutex_lock(&ak4531->reg_mutex);
+ guard(mutex)(&ak4531->reg_mutex);
if (left_reg == right_reg) {
left = (ak4531->regs[left_reg] & ~((mask << left_shift) | (mask << right_shift))) | left | right;
change = left != ak4531->regs[left_reg];
@@ -191,7 +188,6 @@ static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left);
ak4531->write(ak4531, right_reg, ak4531->regs[right_reg] = right);
}
- mutex_unlock(&ak4531->reg_mutex);
return change;
}
@@ -218,12 +214,11 @@ static int snd_ak4531_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
int left_shift = (kcontrol->private_value >> 16) & 0x0f;
int right_shift = (kcontrol->private_value >> 24) & 0x0f;
- mutex_lock(&ak4531->reg_mutex);
+ guard(mutex)(&ak4531->reg_mutex);
ucontrol->value.integer.value[0] = (ak4531->regs[reg1] >> left_shift) & 1;
ucontrol->value.integer.value[1] = (ak4531->regs[reg2] >> left_shift) & 1;
ucontrol->value.integer.value[2] = (ak4531->regs[reg1] >> right_shift) & 1;
ucontrol->value.integer.value[3] = (ak4531->regs[reg2] >> right_shift) & 1;
- mutex_unlock(&ak4531->reg_mutex);
return 0;
}
@@ -237,7 +232,7 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
int change;
int val1, val2;
- mutex_lock(&ak4531->reg_mutex);
+ guard(mutex)(&ak4531->reg_mutex);
val1 = ak4531->regs[reg1] & ~((1 << left_shift) | (1 << right_shift));
val2 = ak4531->regs[reg2] & ~((1 << left_shift) | (1 << right_shift));
val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
@@ -247,7 +242,6 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl
change = val1 != ak4531->regs[reg1] || val2 != ak4531->regs[reg2];
ak4531->write(ak4531, reg1, ak4531->regs[reg1] = val1);
ak4531->write(ak4531, reg2, ak4531->regs[reg2] = val2);
- mutex_unlock(&ak4531->reg_mutex);
return change;
}
@@ -389,7 +383,7 @@ int snd_ak4531_mixer(struct snd_card *card,
snd_ak4531_free(ak4531);
return err;
}
- strcpy(card->mixername, "Asahi Kasei AK4531");
+ strscpy(card->mixername, "Asahi Kasei AK4531");
ak4531->write(ak4531, AK4531_RESET, 0x03); /* no RST, PD */
udelay(100);
ak4531->write(ak4531, AK4531_CLOCK, 0x00); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off LRCLK2 PLL */
diff --git a/sound/pci/ali5451/Makefile b/sound/pci/ali5451/Makefile
index 8156198fbaeb..e319a4c1d6b2 100644
--- a/sound/pci/ali5451/Makefile
+++ b/sound/pci/ali5451/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ali5451-objs := ali5451.o
+snd-ali5451-y := ali5451.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ALI5451) += snd-ali5451.o
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 2378a39abaeb..571d89a6a8da 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -243,9 +243,7 @@ struct snd_ali {
spinlock_t reg_lock;
spinlock_t voice_alloc;
-#ifdef CONFIG_PM_SLEEP
- struct snd_ali_image *image;
-#endif
+ struct snd_ali_image image;
};
static const struct pci_device_id snd_ali_ids[] = {
@@ -294,7 +292,7 @@ static int snd_ali_codec_ready(struct snd_ali *codec,
}
snd_ali_5451_poke(codec, port, res & ~0x8000);
- dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n ");
+ dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n");
return -EIO;
}
@@ -913,13 +911,12 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec,
dev_dbg(codec->card->dev, "alloc_voice: type=%d rec=%d\n", type, rec);
- spin_lock_irq(&codec->voice_alloc);
+ guard(spinlock_irq)(&codec->voice_alloc);
if (type == SNDRV_ALI_VOICE_TYPE_PCM) {
idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) :
snd_ali_find_free_channel(codec,rec);
if (idx < 0) {
dev_err(codec->card->dev, "ali_alloc_voice: err.\n");
- spin_unlock_irq(&codec->voice_alloc);
return NULL;
}
pvoice = &(codec->synth.voices[idx]);
@@ -927,10 +924,8 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec,
pvoice->use = 1;
pvoice->pcm = 1;
pvoice->mode = rec;
- spin_unlock_irq(&codec->voice_alloc);
return pvoice;
}
- spin_unlock_irq(&codec->voice_alloc);
return NULL;
}
@@ -945,16 +940,16 @@ static void snd_ali_free_voice(struct snd_ali * codec,
if (!pvoice->use)
return;
snd_ali_clear_voices(codec, pvoice->number, pvoice->number);
- spin_lock_irq(&codec->voice_alloc);
- private_free = pvoice->private_free;
- private_data = pvoice->private_data;
- pvoice->private_free = NULL;
- pvoice->private_data = NULL;
- if (pvoice->pcm)
- snd_ali_free_channel_pcm(codec, pvoice->number);
- pvoice->use = pvoice->pcm = pvoice->synth = 0;
- pvoice->substream = NULL;
- spin_unlock_irq(&codec->voice_alloc);
+ scoped_guard(spinlock_irq, &codec->voice_alloc) {
+ private_free = pvoice->private_free;
+ private_data = pvoice->private_data;
+ pvoice->private_free = NULL;
+ pvoice->private_data = NULL;
+ if (pvoice->pcm)
+ snd_ali_free_channel_pcm(codec, pvoice->number);
+ pvoice->use = pvoice->pcm = pvoice->synth = 0;
+ pvoice->substream = NULL;
+ }
if (private_free)
private_free(private_data);
}
@@ -1111,7 +1106,7 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream,
snd_pcm_trigger_done(s, substream);
}
}
- spin_lock(&codec->reg_lock);
+ guard(spinlock)(&codec->reg_lock);
if (!do_start)
outl(what, ALI_REG(codec, ALI_STOP));
val = inl(ALI_REG(codec, ALI_AINTEN));
@@ -1123,7 +1118,6 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream,
if (do_start)
outl(what, ALI_REG(codec, ALI_START));
dev_dbg(codec->card->dev, "trigger: what=%xh whati=%xh\n", what, whati);
- spin_unlock(&codec->reg_lock);
return 0;
}
@@ -1191,8 +1185,8 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
dev_dbg(codec->card->dev, "playback_prepare ...\n");
- spin_lock_irq(&codec->reg_lock);
-
+ guard(spinlock_irq)(&codec->reg_lock);
+
/* set Delta (rate) value */
Delta = snd_ali_convert_rate(runtime->rate, 0);
@@ -1261,7 +1255,6 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
CTRL,
EC);
}
- spin_unlock_irq(&codec->reg_lock);
return 0;
}
@@ -1362,14 +1355,11 @@ snd_ali_playback_pointer(struct snd_pcm_substream *substream)
struct snd_ali_voice *pvoice = runtime->private_data;
unsigned int cso;
- spin_lock(&codec->reg_lock);
- if (!pvoice->running) {
- spin_unlock(&codec->reg_lock);
+ guard(spinlock)(&codec->reg_lock);
+ if (!pvoice->running)
return 0;
- }
outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
- spin_unlock(&codec->reg_lock);
dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso);
cso %= runtime->buffer_size;
@@ -1384,14 +1374,11 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream)
struct snd_ali_voice *pvoice = runtime->private_data;
unsigned int cso;
- spin_lock(&codec->reg_lock);
- if (!pvoice->running) {
- spin_unlock(&codec->reg_lock);
+ guard(spinlock)(&codec->reg_lock);
+ if (!pvoice->running)
return 0;
- }
outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
- spin_unlock(&codec->reg_lock);
cso %= runtime->buffer_size;
return cso;
@@ -1647,7 +1634,7 @@ static int snd_ali_pcm(struct snd_ali *codec, int device,
pcm->info_flags = 0;
pcm->dev_class = desc->class;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
- strcpy(pcm->name, desc->name);
+ strscpy(pcm->name, desc->name);
codec->pcm[0] = pcm;
return 0;
}
@@ -1690,12 +1677,12 @@ static int snd_ali_build_pcms(struct snd_ali *codec)
static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_ali *codec = kcontrol->private_data;
+ struct snd_ali *codec = snd_kcontrol_chip(kcontrol);
unsigned int spdif_enable;
spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0;
- spin_lock_irq(&codec->reg_lock);
+ guard(spinlock_irq)(&codec->reg_lock);
switch (kcontrol->private_value) {
case 0:
spdif_enable = (codec->spdif_mask & 0x02) ? 1 : 0;
@@ -1711,19 +1698,18 @@ static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol,
break;
}
ucontrol->value.integer.value[0] = spdif_enable;
- spin_unlock_irq(&codec->reg_lock);
return 0;
}
static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_ali *codec = kcontrol->private_data;
+ struct snd_ali *codec = snd_kcontrol_chip(kcontrol);
unsigned int change = 0, spdif_enable = 0;
spdif_enable = ucontrol->value.integer.value[0] ? 1 : 0;
- spin_lock_irq(&codec->reg_lock);
+ guard(spinlock_irq)(&codec->reg_lock);
switch (kcontrol->private_value) {
case 0:
change = (codec->spdif_mask & 0x02) ? 1 : 0;
@@ -1768,7 +1754,6 @@ static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol,
default:
break;
}
- spin_unlock_irq(&codec->reg_lock);
return change;
}
@@ -1824,23 +1809,18 @@ static int snd_ali_mixer(struct snd_ali *codec)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int ali_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ali *chip = card->private_data;
- struct snd_ali_image *im;
+ struct snd_ali_image *im = &chip->image;
int i, j;
- im = chip->image;
- if (!im)
- return 0;
-
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
for (i = 0; i < chip->num_of_codecs; i++)
snd_ac97_suspend(chip->ac97[i]);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
im->regs[ALI_MISCINT >> 2] = inl(ALI_REG(chip, ALI_MISCINT));
/* im->regs[ALI_START >> 2] = inl(ALI_REG(chip, ALI_START)); */
@@ -1864,7 +1844,6 @@ static int ali_suspend(struct device *dev)
/* stop all HW channel */
outl(0xffffffff, ALI_REG(chip, ALI_STOP));
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1872,34 +1851,28 @@ static int ali_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ali *chip = card->private_data;
- struct snd_ali_image *im;
+ struct snd_ali_image *im = &chip->image;
int i, j;
- im = chip->image;
- if (!im)
- return 0;
-
- spin_lock_irq(&chip->reg_lock);
-
- for (i = 0; i < ALI_CHANNELS; i++) {
- outb(i, ALI_REG(chip, ALI_GC_CIR));
- for (j = 0; j < ALI_CHANNEL_REGS; j++)
- outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0));
- }
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ for (i = 0; i < ALI_CHANNELS; i++) {
+ outb(i, ALI_REG(chip, ALI_GC_CIR));
+ for (j = 0; j < ALI_CHANNEL_REGS; j++)
+ outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0));
+ }
- for (i = 0; i < ALI_GLOBAL_REGS; i++) {
- if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) ||
- (i*4 == ALI_START))
- continue;
- outl(im->regs[i], ALI_REG(chip, i*4));
+ for (i = 0; i < ALI_GLOBAL_REGS; i++) {
+ if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) ||
+ (i*4 == ALI_START))
+ continue;
+ outl(im->regs[i], ALI_REG(chip, i*4));
+ }
+
+ /* start HW channel */
+ outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START));
+ /* restore IRQ enable bits */
+ outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT));
}
-
- /* start HW channel */
- outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START));
- /* restore IRQ enable bits */
- outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT));
-
- spin_unlock_irq(&chip->reg_lock);
for (i = 0 ; i < chip->num_of_codecs; i++)
snd_ac97_resume(chip->ac97[i]);
@@ -1908,11 +1881,7 @@ static int ali_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
-#define ALI_PM_OPS &ali_pm
-#else
-#define ALI_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
static void snd_ali_free(struct snd_card *card)
{
@@ -2004,7 +1973,7 @@ static int snd_ali_resources(struct snd_ali *codec)
int err;
dev_dbg(codec->card->dev, "resources allocation ...\n");
- err = pci_request_regions(codec->pci, "ALI 5451");
+ err = pcim_request_all_regions(codec->pci, "ALI 5451");
if (err < 0)
return err;
codec->port = pci_resource_start(codec->pci, 0);
@@ -2112,13 +2081,6 @@ static int snd_ali_create(struct snd_card *card,
return err;
}
-#ifdef CONFIG_PM_SLEEP
- codec->image = devm_kmalloc(&pci->dev, sizeof(*codec->image),
- GFP_KERNEL);
- if (!codec->image)
- dev_warn(card->dev, "can't allocate apm buffer\n");
-#endif
-
snd_ali_enable_address_interrupt(codec);
codec->hw_initialized = 1;
return 0;
@@ -2155,8 +2117,8 @@ static int __snd_ali_probe(struct pci_dev *pci,
snd_ali_proc_init(codec);
- strcpy(card->driver, "ALI5451");
- strcpy(card->shortname, "ALI 5451");
+ strscpy(card->driver, "ALI5451");
+ strscpy(card->shortname, "ALI 5451");
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, codec->port, codec->irq);
@@ -2181,7 +2143,7 @@ static struct pci_driver ali5451_driver = {
.id_table = snd_ali_ids,
.probe = snd_ali_probe,
.driver = {
- .pm = ALI_PM_OPS,
+ .pm = &ali_pm,
},
};
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index c70aff060120..733e84def5a7 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -402,7 +402,7 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
tmp &= ~TRANSFER_START;
@@ -419,7 +419,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
runtime->dma_addr);
snd_als300_gcr_write(chip->port, PLAYBACK_END,
runtime->dma_addr + buffer_bytes - 1);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -431,7 +430,7 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL);
tmp &= ~TRANSFER_START;
@@ -448,7 +447,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
runtime->dma_addr);
snd_als300_gcr_write(chip->port, RECORD_END,
runtime->dma_addr + buffer_bytes - 1);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -463,7 +461,7 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
data = substream->runtime->private_data;
reg = data->control_register;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -492,7 +490,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
snd_als300_dbgplay("TRIGGER INVALID\n");
ret = -EINVAL;
}
- spin_unlock(&chip->reg_lock);
return ret;
}
@@ -506,10 +503,10 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
data = substream->runtime->private_data;
period_bytes = snd_pcm_lib_period_bytes(substream);
- spin_lock(&chip->reg_lock);
- current_ptr = (u16) snd_als300_gcr_read(chip->port,
- data->block_counter_register) + 4;
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ current_ptr = (u16) snd_als300_gcr_read(chip->port,
+ data->block_counter_register) + 4;
+ }
if (current_ptr > period_bytes)
current_ptr = 0;
else
@@ -546,7 +543,7 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
if (err < 0)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, "ALS300");
+ strscpy(pcm->name, "ALS300");
chip->pcm = pcm;
/* set operators */
@@ -563,10 +560,9 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
static void snd_als300_init(struct snd_als300 *chip)
{
- unsigned long flags;
u32 tmp;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16)
& 0x0000000F;
/* Setup DRAM */
@@ -591,7 +587,6 @@ static void snd_als300_init(struct snd_als300 *chip)
tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL,
tmp & ~TRANSFER_START);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static int snd_als300_create(struct snd_card *card,
@@ -617,7 +612,7 @@ static int snd_als300_create(struct snd_card *card,
chip->chip_type = chip_type;
spin_lock_init(&chip->reg_lock);
- err = pci_request_regions(pci, "ALS300");
+ err = pcim_request_all_regions(pci, "ALS300");
if (err < 0)
return err;
@@ -654,7 +649,6 @@ static int snd_als300_create(struct snd_card *card,
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int snd_als300_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -677,11 +671,7 @@ static int snd_als300_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume);
-#define SND_ALS300_PM_OPS &snd_als300_pm
-#else
-#define SND_ALS300_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume);
static int snd_als300_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
@@ -710,7 +700,7 @@ static int snd_als300_probe(struct pci_dev *pci,
if (err < 0)
goto error;
- strcpy(card->driver, "ALS300");
+ strscpy(card->driver, "ALS300");
if (chip->chip_type == DEVICE_ALS300_PLUS)
/* don't know much about ALS300+ yet
* print revision number for now */
@@ -739,7 +729,7 @@ static struct pci_driver als300_driver = {
.id_table = snd_als300_ids,
.probe = snd_als300_probe,
.driver = {
- .pm = SND_ALS300_PM_OPS,
+ .pm = &snd_als300_pm,
},
};
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index f33aeb692a11..33034e07b3d6 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -369,14 +369,14 @@ static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream)
count >>= 1;
count--;
- spin_lock_irq(&chip->reg_lock);
- snd_als4000_set_rate(chip, runtime->rate);
- snd_als4000_set_capture_dma(chip, runtime->dma_addr, size);
- spin_unlock_irq(&chip->reg_lock);
- spin_lock_irq(&chip->mixer_lock);
- snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff);
- snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8);
- spin_unlock_irq(&chip->mixer_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ snd_als4000_set_rate(chip, runtime->rate);
+ snd_als4000_set_capture_dma(chip, runtime->dma_addr, size);
+ }
+ scoped_guard(spinlock_irq, &chip->mixer_lock) {
+ snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff);
+ snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8);
+ }
return 0;
}
@@ -402,7 +402,7 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream)
* reordering, ...). Something seems to get enabled on playback
* that I haven't found out how to disable again, which then causes
* the switching pops to reach the speakers the next time here. */
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_als4000_set_rate(chip, runtime->rate);
snd_als4000_set_playback_dma(chip, runtime->dma_addr, size);
@@ -413,7 +413,6 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream)
snd_sbdsp_command(chip, count & 0xff);
snd_sbdsp_command(chip, count >> 8);
snd_sbdsp_command(chip, playback_cmd(chip).dma_off);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -429,7 +428,7 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int
Probably need to take reg_lock as outer (or inner??) lock, too.
(or serialize both lock operations? probably not, though... - racy?)
*/
- spin_lock(&chip->mixer_lock);
+ guard(spinlock)(&chip->mixer_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -447,7 +446,6 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int
result = -EINVAL;
break;
}
- spin_unlock(&chip->mixer_lock);
return result;
}
@@ -456,7 +454,7 @@ static int snd_als4000_playback_trigger(struct snd_pcm_substream *substream, int
struct snd_sb *chip = snd_pcm_substream_chip(substream);
int result = 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -472,7 +470,6 @@ static int snd_als4000_playback_trigger(struct snd_pcm_substream *substream, int
result = -EINVAL;
break;
}
- spin_unlock(&chip->reg_lock);
return result;
}
@@ -481,9 +478,9 @@ static snd_pcm_uframes_t snd_als4000_capture_pointer(struct snd_pcm_substream *s
struct snd_sb *chip = snd_pcm_substream_chip(substream);
unsigned int result;
- spin_lock(&chip->reg_lock);
- result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR);
+ }
result &= 0xffff;
return bytes_to_frames( substream->runtime, result );
}
@@ -493,9 +490,9 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream *
struct snd_sb *chip = snd_pcm_substream_chip(substream);
unsigned result;
- spin_lock(&chip->reg_lock);
- result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR);
+ }
result &= 0xffff;
return bytes_to_frames( substream->runtime, result );
}
@@ -536,10 +533,10 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
snd_als4k_iobase_writeb(chip->alt_port,
ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU, pci_irqstatus);
- spin_lock(&chip->mixer_lock);
- /* SPECS_PAGE: 20 */
- sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
- spin_unlock(&chip->mixer_lock);
+ scoped_guard(spinlock, &chip->mixer_lock) {
+ /* SPECS_PAGE: 20 */
+ sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
+ }
if (sb_irqstatus & SB_IRQTYPE_8BIT)
snd_sb_ack_8bit(chip);
@@ -709,18 +706,18 @@ static void snd_als4000_configure(struct snd_sb *chip)
int i;
/* do some more configuration */
- spin_lock_irq(&chip->mixer_lock);
- tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG);
- snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
- tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
- /* always select DMA channel 0, since we do not actually use DMA
- * SPECS_PAGE: 19/20 */
- snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0);
- snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
- tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
- spin_unlock_irq(&chip->mixer_lock);
+ scoped_guard(spinlock_irq, &chip->mixer_lock) {
+ tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG);
+ snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
+ tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
+ /* always select DMA channel 0, since we do not actually use DMA
+ * SPECS_PAGE: 19/20 */
+ snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0);
+ snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG,
+ tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE);
+ }
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
/* enable interrupts */
snd_als4k_gcr_write(chip, ALS4K_GCR8C_MISC_CTRL,
ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE);
@@ -731,7 +728,6 @@ static void snd_als4000_configure(struct snd_sb *chip)
/* enable burst mode to prevent dropouts during high PCI bus usage */
snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
(snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04);
- spin_unlock_irq(&chip->reg_lock);
}
#ifdef SUPPORT_JOYSTICK
@@ -836,7 +832,7 @@ static int __snd_card_als4000_probe(struct pci_dev *pci,
return -ENXIO;
}
- err = pci_request_regions(pci, "ALS4000");
+ err = pcim_request_all_regions(pci, "ALS4000");
if (err < 0)
return err;
iobase = pci_resource_start(pci, 0);
@@ -877,8 +873,8 @@ static int __snd_card_als4000_probe(struct pci_dev *pci,
snd_als4000_configure(chip);
- strcpy(card->driver, "ALS4000");
- strcpy(card->shortname, "Avance Logic ALS4000");
+ strscpy(card->driver, "ALS4000");
+ strscpy(card->shortname, "Avance Logic ALS4000");
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, chip->alt_port, chip->irq);
@@ -936,7 +932,6 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
return snd_card_free_on_error(&pci->dev, __snd_card_als4000_probe(pci, pci_id));
}
-#ifdef CONFIG_PM_SLEEP
static int snd_als4000_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -968,18 +963,14 @@ static int snd_als4000_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume);
-#define SND_ALS4000_PM_OPS &snd_als4000_pm
-#else
-#define SND_ALS4000_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume);
static struct pci_driver als4000_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_als4000_ids,
.probe = snd_card_als4000_probe,
.driver = {
- .pm = SND_ALS4000_PM_OPS,
+ .pm = &snd_als4000_pm,
},
};
diff --git a/sound/pci/asihpi/Makefile b/sound/pci/asihpi/Makefile
index 8351f8f5b523..d558a974fa7e 100644
--- a/sound/pci/asihpi/Makefile
+++ b/sound/pci/asihpi/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-asihpi-objs := asihpi.o hpioctl.o hpimsginit.o\
+snd-asihpi-y := asihpi.o hpioctl.o hpimsginit.o\
hpicmn.o hpifunc.o hpidebug.o hpidspcd.o\
hpios.o hpi6000.o hpi6205.o hpimsgx.o
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 001786e2aba1..fd0a67b772d1 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -36,19 +36,10 @@ MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx "
HPI_VER_STRING);
-#if defined CONFIG_SND_DEBUG_VERBOSE
-/**
- * snd_printddd - very verbose debug printk
- * @format: format string
- *
- * Works like snd_printk() for debugging purposes.
- * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set.
- * Must set snd module debug parameter to 3 to enable at runtime.
- */
-#define snd_printddd(format, args...) \
- __snd_printk(3, __FILE__, __LINE__, format, ##args)
+#ifdef ASIHPI_VERBOSE_DEBUG
+#define asihpi_dbg(format, args...) pr_debug(format, ##args)
#else
-#define snd_printddd(format, args...) do { } while (0)
+#define asihpi_dbg(format, args...) do { } while (0)
#endif
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */
@@ -260,8 +251,7 @@ static inline u16 hpi_stream_group_reset(u32 h_stream)
static u16 handle_error(u16 err, int line, char *filename)
{
if (err)
- printk(KERN_WARNING
- "in file %s, line %d: HPI error %d\n",
+ pr_warn("in file %s, line %d: HPI error %d\n",
filename, line, err);
return err;
}
@@ -273,16 +263,18 @@ static u16 handle_error(u16 err, int line, char *filename)
static void print_hwparams(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *p)
{
+ struct device *dev = substream->pcm->card->dev;
char name[16];
+
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printdd("%s HWPARAMS\n", name);
- snd_printdd(" samplerate=%dHz channels=%d format=%d subformat=%d\n",
+ dev_dbg(dev, "%s HWPARAMS\n", name);
+ dev_dbg(dev, " samplerate=%dHz channels=%d format=%d subformat=%d\n",
params_rate(p), params_channels(p),
params_format(p), params_subformat(p));
- snd_printdd(" buffer=%dB period=%dB period_size=%dB periods=%d\n",
+ dev_dbg(dev, " buffer=%dB period=%dB period_size=%dB periods=%d\n",
params_buffer_bytes(p), params_period_bytes(p),
params_period_size(p), params_periods(p));
- snd_printdd(" buffer_size=%d access=%d data_rate=%dB/s\n",
+ dev_dbg(dev, " buffer_size=%d access=%d data_rate=%dB/s\n",
params_buffer_size(p), params_access(p),
params_rate(p) * params_channels(p) *
snd_pcm_format_width(params_format(p)) / 8);
@@ -317,7 +309,8 @@ static const snd_pcm_format_t hpi_to_alsa_formats[] = {
};
-static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
+static int snd_card_asihpi_format_alsa2hpi(struct snd_card_asihpi *asihpi,
+ snd_pcm_format_t alsa_format,
u16 *hpi_format)
{
u16 format;
@@ -330,8 +323,8 @@ static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsa_format,
}
}
- snd_printd(KERN_WARNING "failed match for alsa format %d\n",
- alsa_format);
+ dev_dbg(asihpi->card->dev, "failed match for alsa format %d\n",
+ alsa_format);
*hpi_format = 0;
return -EINVAL;
}
@@ -439,7 +432,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int bytes_per_sec;
print_hwparams(substream, params);
- err = snd_card_asihpi_format_alsa2hpi(params_format(params), &format);
+ err = snd_card_asihpi_format_alsa2hpi(card, params_format(params), &format);
if (err)
return err;
@@ -461,17 +454,17 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
err = hpi_stream_host_buffer_attach(dpcm->h_stream,
params_buffer_bytes(params), runtime->dma_addr);
if (err == 0) {
- snd_printdd(
+ dev_dbg(card->card->dev,
"stream_host_buffer_attach success %u %lu\n",
params_buffer_bytes(params),
(unsigned long)runtime->dma_addr);
} else {
- snd_printd("stream_host_buffer_attach error %d\n",
- err);
+ dev_dbg(card->card->dev,
+ "stream_host_buffer_attach error %d\n", err);
return -ENOMEM;
}
- err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
+ hpi_stream_get_info_ex(dpcm->h_stream, NULL,
&dpcm->hpi_buffer_attached, NULL, NULL, NULL);
}
bytes_per_sec = params_rate(params) * params_channels(params);
@@ -525,7 +518,7 @@ static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
dpcm->respawn_timer = 0;
- del_timer(&dpcm->timer);
+ timer_delete(&dpcm->timer);
}
static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream)
@@ -569,7 +562,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_printdd("%s trigger start\n", name);
+ dev_dbg(card->card->dev, "%s trigger start\n", name);
snd_pcm_group_for_each_entry(s, substream) {
struct snd_pcm_runtime *runtime = s->runtime;
struct snd_card_asihpi_pcm *ds = runtime->private_data;
@@ -590,7 +583,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
* data??
*/
unsigned int preload = ds->period_bytes * 1;
- snd_printddd("%d preload %d\n", s->number, preload);
+ asihpi_dbg("%d preload %d\n", s->number, preload);
hpi_handle_error(hpi_outstream_write_buf(
ds->h_stream,
&runtime->dma_area[0],
@@ -600,7 +593,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
}
if (card->support_grouping) {
- snd_printdd("%d group\n", s->number);
+ dev_dbg(card->card->dev, "%d group\n", s->number);
e = hpi_stream_group_add(
dpcm->h_stream,
ds->h_stream);
@@ -621,7 +614,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_printdd("%s trigger stop\n", name);
+ dev_dbg(card->card->dev, "%s trigger stop\n", name);
card->pcm_stop(substream);
snd_pcm_group_for_each_entry(s, substream) {
if (snd_pcm_substream_chip(s) != card)
@@ -635,7 +628,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
__snd_pcm_set_state(s->runtime, SNDRV_PCM_STATE_SETUP);
if (card->support_grouping) {
- snd_printdd("%d group\n", s->number);
+ dev_dbg(card->card->dev, "%d group\n", s->number);
snd_pcm_trigger_done(s, substream);
} else
break;
@@ -652,17 +645,17 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_printdd("%s trigger pause release\n", name);
+ dev_dbg(card->card->dev, "%s trigger pause release\n", name);
card->pcm_start(substream);
hpi_handle_error(hpi_stream_start(dpcm->h_stream));
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_printdd("%s trigger pause push\n", name);
+ dev_dbg(card->card->dev, "%s trigger pause push\n", name);
card->pcm_stop(substream);
hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
break;
default:
- snd_printd(KERN_ERR "\tINVALID\n");
+ dev_dbg(card->card->dev, "\tINVALID\n");
return -EINVAL;
}
@@ -716,7 +709,7 @@ static inline unsigned int modulo_min(unsigned int a, unsigned int b,
*/
static void snd_card_asihpi_timer_function(struct timer_list *t)
{
- struct snd_card_asihpi_pcm *dpcm = from_timer(dpcm, t, timer);
+ struct snd_card_asihpi_pcm *dpcm = timer_container_of(dpcm, t, timer);
struct snd_pcm_substream *substream = dpcm->substream;
struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime;
@@ -760,12 +753,13 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
if (state == HPI_STATE_STOPPED) {
if (bytes_avail == 0) {
hpi_handle_error(hpi_stream_start(ds->h_stream));
- snd_printdd("P%d start\n", s->number);
+ dev_dbg(card->card->dev,
+ "P%d start\n", s->number);
ds->drained_count = 0;
}
} else if (state == HPI_STATE_DRAINED) {
- snd_printd(KERN_WARNING "P%d drained\n",
- s->number);
+ dev_dbg(card->card->dev,
+ "P%d drained\n", s->number);
ds->drained_count++;
if (ds->drained_count > 20) {
snd_pcm_stop_xrun(s);
@@ -790,7 +784,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
newdata);
}
- snd_printddd(
+ asihpi_dbg(
"timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n",
name, s->number, state,
ds->pcm_buf_elapsed_dma_ofs,
@@ -821,7 +815,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
next_jiffies = max(next_jiffies, 1U);
dpcm->timer.expires = jiffies + next_jiffies;
- snd_printddd("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n",
+ asihpi_dbg("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n",
next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
snd_pcm_group_for_each_entry(s, substream) {
@@ -854,7 +848,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
}
if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_printddd("write1, P=%d, xfer=%d, buf_ofs=%d\n",
+ asihpi_dbg("write1, P=%d, xfer=%d, buf_ofs=%d\n",
s->number, xfer1, buf_ofs);
hpi_handle_error(
hpi_outstream_write_buf(
@@ -864,7 +858,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
if (xfer2) {
pd = s->runtime->dma_area;
- snd_printddd("write2, P=%d, xfer=%d, buf_ofs=%d\n",
+ asihpi_dbg("write2, P=%d, xfer=%d, buf_ofs=%d\n",
s->number,
xfercount - xfer1, buf_ofs);
hpi_handle_error(
@@ -874,7 +868,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
&ds->format));
}
} else {
- snd_printddd("read1, C=%d, xfer=%d\n",
+ asihpi_dbg("read1, C=%d, xfer=%d\n",
s->number, xfer1);
hpi_handle_error(
hpi_instream_read_buf(
@@ -882,7 +876,7 @@ static void snd_card_asihpi_timer_function(struct timer_list *t)
pd, xfer1));
if (xfer2) {
pd = s->runtime->dma_area;
- snd_printddd("read2, C=%d, xfer=%d\n",
+ asihpi_dbg("read2, C=%d, xfer=%d\n",
s->number, xfer2);
hpi_handle_error(
hpi_instream_read_buf(
@@ -919,8 +913,6 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- snd_printdd("P%d prepare\n", substream->number);
-
hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
dpcm->pcm_buf_host_rw_ofs = 0;
dpcm->pcm_buf_dma_ofs = 0;
@@ -938,7 +930,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
snd_pcm_debug_name(substream, name, sizeof(name));
ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
- snd_printddd("%s, pointer=%ld\n", name, (unsigned long)ptr);
+ asihpi_dbg("%s, pointer=%ld\n", name, (unsigned long)ptr);
return ptr;
}
@@ -990,12 +982,12 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
err = hpi_outstream_open(card->hpi->adapter->index,
substream->number, &dpcm->h_stream);
hpi_handle_error(err);
- if (err)
+ if (err) {
kfree(dpcm);
- if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
- return -EBUSY;
- if (err)
+ if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
+ return -EBUSY;
return -EIO;
+ }
/*? also check ASI5000 samplerate source
If external, only support external rate.
@@ -1060,8 +1052,6 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
card->update_interval_frames, UINT_MAX);
- snd_printdd("playback open\n");
-
return 0;
}
@@ -1071,8 +1061,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
- snd_printdd("playback close\n");
-
return 0;
}
@@ -1095,7 +1083,7 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printddd("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs);
+ asihpi_dbg("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs);
/* NOTE Unlike playback can't use actual samples_played
for the capture position, because those samples aren't yet in
the local buffer available for reading.
@@ -1113,7 +1101,6 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
dpcm->pcm_buf_dma_ofs = 0;
dpcm->pcm_buf_elapsed_dma_ofs = 0;
- snd_printdd("Capture Prepare %d\n", substream->number);
return 0;
}
@@ -1162,18 +1149,19 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
if (dpcm == NULL)
return -ENOMEM;
- snd_printdd("capture open adapter %d stream %d\n",
- card->hpi->adapter->index, substream->number);
+
+ dev_dbg(card->card->dev, "capture open adapter %d stream %d\n",
+ card->hpi->adapter->index, substream->number);
err = hpi_handle_error(
hpi_instream_open(card->hpi->adapter->index,
substream->number, &dpcm->h_stream));
- if (err)
+ if (err) {
kfree(dpcm);
- if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
- return -EBUSY;
- if (err)
+ if (err == HPI_ERROR_OBJ_ALREADY_OPEN)
+ return -EBUSY;
return -EIO;
+ }
timer_setup(&dpcm->timer, snd_card_asihpi_timer_function, 0);
dpcm->substream = substream;
@@ -1269,7 +1257,7 @@ static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device)
pcm->private_data = asihpi;
pcm->info_flags = 0;
- strcpy(pcm->name, "Asihpi PCM");
+ strscpy(pcm->name, "Asihpi PCM");
/*? do we want to emulate MMAP for non-BBM cards?
Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
@@ -1413,8 +1401,6 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
hpi_ctl->src_node_index,
dir, name);
}
- /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name,
- hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
}
/*------------------------------------------------------------
@@ -2175,9 +2161,8 @@ static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
return 0;
}
}
- snd_printd(KERN_WARNING
- "Control %x failed to match mux source %hu %hu\n",
- h_control, source_type, source_index);
+ pr_warn("%s: Control %x failed to match mux source %hu %hu\n",
+ __func__, h_control, source_type, source_index);
ucontrol->value.enumerated.item[0] = 0;
return 0;
}
@@ -2315,8 +2300,7 @@ static const char * const sampleclock_sources[] = {
static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct snd_card_asihpi *asihpi =
- (struct snd_card_asihpi *)(kcontrol->private_data);
+ struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
struct clk_cache *clkcache = &asihpi->cc;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
@@ -2326,7 +2310,7 @@ static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.item =
uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
clkcache->s[uinfo->value.enumerated.item].name);
return 0;
}
@@ -2334,8 +2318,7 @@ static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_card_asihpi *asihpi =
- (struct snd_card_asihpi *)(kcontrol->private_data);
+ struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
struct clk_cache *clkcache = &asihpi->cc;
u32 h_control = kcontrol->private_value;
u16 source, srcindex = 0;
@@ -2362,8 +2345,7 @@ static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_card_asihpi *asihpi =
- (struct snd_card_asihpi *)(kcontrol->private_data);
+ struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
struct clk_cache *clkcache = &asihpi->cc;
unsigned int item;
int change;
@@ -2548,7 +2530,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (snd_BUG_ON(!asihpi))
return -EINVAL;
card = asihpi->card;
- strcpy(card->mixername, "Asihpi Mixer");
+ strscpy(card->mixername, "Asihpi Mixer");
err =
hpi_mixer_open(asihpi->hpi->adapter->index,
@@ -2759,7 +2741,7 @@ static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device)
err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
if (err < 0)
return err;
- strcpy(hw->name, "asihpi (HPI)");
+ strscpy(hw->name, "asihpi (HPI)");
hw->iface = SNDRV_HWDEP_IFACE_LAST;
hw->ops.open = snd_asihpi_hpi_open;
hw->ops.ioctl = snd_asihpi_hpi_ioctl;
@@ -2907,7 +2889,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
by enable_hwdep module param*/
snd_asihpi_hpi_new(asihpi, 0);
- strcpy(card->driver, "ASIHPI");
+ strscpy(card->driver, "ASIHPI");
sprintf(card->shortname, "AudioScience ASI%4X",
asihpi->hpi->adapter->type);
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h
index 3aebec763fb8..04a5cf6572cd 100644
--- a/sound/pci/asihpi/hpi.h
+++ b/sound/pci/asihpi/hpi.h
@@ -1191,19 +1191,6 @@ u16 hpi_adapter_set_mode_ex(u16 adapter_index, u32 adapter_mode,
u16 hpi_adapter_get_mode(u16 adapter_index, u32 *padapter_mode);
-u16 hpi_adapter_get_assert2(u16 adapter_index, u16 *p_assert_count,
- char *psz_assert, u32 *p_param1, u32 *p_param2,
- u32 *p_dsp_string_addr, u16 *p_processor_id);
-
-u16 hpi_adapter_test_assert(u16 adapter_index, u16 assert_id);
-
-u16 hpi_adapter_enable_capability(u16 adapter_index, u16 capability, u32 key);
-
-u16 hpi_adapter_self_test(u16 adapter_index);
-
-u16 hpi_adapter_debug_read(u16 adapter_index, u32 dsp_address, char *p_bytes,
- int *count_bytes);
-
u16 hpi_adapter_set_property(u16 adapter_index, u16 property, u16 paramter1,
u16 paramter2);
@@ -1488,9 +1475,6 @@ u16 hpi_pad_get_program_type(u32 h_control, u32 *ppTY);
u16 hpi_pad_get_rdsPI(u32 h_control, u32 *ppI);
-u16 hpi_pad_get_program_type_string(u32 h_control, const u32 data_type,
- const u32 pTY, char *psz_string, const u32 string_length);
-
/****************************/
/* AES/EBU Receiver control */
/****************************/
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index 72aa135d69f8..b08578c93c6a 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -608,7 +608,7 @@ static void adapter_get_asserts(struct hpi_adapter_obj *pao,
phr->u.ax.assert.p2 = 0;
phr->u.ax.assert.count = 1; /* assert count */
phr->u.ax.assert.dsp_index = -1; /* "dsp index" */
- strcpy(phr->u.ax.assert.sz_message, "PCI2040 error");
+ strscpy(phr->u.ax.assert.sz_message, "PCI2040 error");
phr->u.ax.assert.dsp_msg_addr = 0;
gw_pci_read_asserts = 0;
gw_pci_write_asserts = 0;
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index 6859d51389f5..e569e3b33b8e 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -1394,17 +1394,12 @@ u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index,
void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
/* used in PnP OS/driver */
-u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
- u16 *pw_adapter_index);
-
u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status);
u16 hpi_instream_host_buffer_get_info(u32 h_instream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status);
-u16 hpi_adapter_restart(u16 adapter_index);
-
/*
The following 3 functions were last declared in header files for
driver 3.10. HPI_ControlQuery() used to be the recommended way
diff --git a/sound/pci/asihpi/hpidebug.h b/sound/pci/asihpi/hpidebug.h
index c24ed69eb743..c6dfc229213d 100644
--- a/sound/pci/asihpi/hpidebug.h
+++ b/sound/pci/asihpi/hpidebug.h
@@ -29,16 +29,15 @@ enum { HPI_DEBUG_LEVEL_ERROR = 0, /* always log errors */
the start of each message, eg see linux kernel hpios.h */
#ifdef SOURCEFILE_NAME
+#undef FILE_LINE
#define FILE_LINE SOURCEFILE_NAME ":" __stringify(__LINE__) " "
-#else
-#define FILE_LINE __FILE__ ":" __stringify(__LINE__) " "
#endif
#define HPI_DEBUG_ASSERT(expression) \
do { \
if (!(expression)) { \
printk(KERN_ERR FILE_LINE \
- "ASSERT " __stringify(expression)); \
+ " ASSERT " __stringify(expression)); \
} \
} while (0)
@@ -46,7 +45,7 @@ enum { HPI_DEBUG_LEVEL_ERROR = 0, /* always log errors */
do { \
if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
printk(HPI_DEBUG_FLAG_##level \
- FILE_LINE __VA_ARGS__); \
+ FILE_LINE " " __VA_ARGS__); \
} \
} while (0)
@@ -70,7 +69,7 @@ void hpi_debug_data(u16 *pdata, u32 len);
do { \
if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
hpi_debug_message(phm, HPI_DEBUG_FLAG_##level \
- FILE_LINE __stringify(level)); \
+ FILE_LINE " " __stringify(level)); \
} \
} while (0)
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
index d0caef299481..b68e6bfbbfba 100644
--- a/sound/pci/asihpi/hpimsgx.c
+++ b/sound/pci/asihpi/hpimsgx.c
@@ -708,7 +708,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm,
phr->error = HPI_ERROR_PROCESSING_MESSAGE;
return phr->error;
}
- if (hr.error == 0) {
+ if (hr.error == 0 && hr.u.s.adapter_index < HPI_MAX_ADAPTERS) {
/* the adapter was created successfully
save the mapping for future use */
hpi_entry_points[hr.u.s.adapter_index] = entry_point_func;
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 477a5b4b50bc..9fb0c8e503df 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -356,7 +356,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
memset(&adapter, 0, sizeof(adapter));
- dev_printk(KERN_DEBUG, &pci_dev->dev,
+ dev_dbg(&pci_dev->dev,
"probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor,
pci_dev->device, pci_dev->subsystem_vendor,
pci_dev->subsystem_device, pci_dev->devfn);
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 43d01f1847ed..2a0c59d5afa5 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -345,7 +345,6 @@ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma,
{
unsigned int i;
u32 addr, desc_addr;
- unsigned long flags;
if (periods > ATI_MAX_DESCRIPTORS)
return -ENOMEM;
@@ -363,11 +362,11 @@ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma,
return 0;
/* reset DMA before changing the descriptor table */
- spin_lock_irqsave(&chip->reg_lock, flags);
- writel(0, chip->remap_addr + dma->ops->llp_offset);
- dma->ops->enable_dma(chip, 0);
- dma->ops->enable_dma(chip, 1);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ writel(0, chip->remap_addr + dma->ops->llp_offset);
+ dma->ops->enable_dma(chip, 0);
+ dma->ops->enable_dma(chip, 1);
+ }
/* fill the entries */
addr = (u32)substream->runtime->dma_addr;
@@ -520,7 +519,6 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int snd_atiixp_aclink_down(struct atiixp *chip)
{
// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -530,7 +528,6 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
ATI_REG_CMD_POWERDOWN);
return 0;
}
-#endif
/*
* auto-detection of codecs
@@ -713,7 +710,7 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
!dma->ops->flush_dma))
return -EINVAL;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -747,7 +744,6 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_atiixp_check_bus_busy(chip);
}
}
- spin_unlock(&chip->reg_lock);
return err;
}
@@ -861,7 +857,7 @@ static int snd_atiixp_spdif_prepare(struct snd_pcm_substream *substream)
{
struct atiixp *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
if (chip->spdif_over_aclink) {
unsigned int data;
/* enable slots 10/11 */
@@ -879,7 +875,6 @@ static int snd_atiixp_spdif_prepare(struct snd_pcm_substream *substream)
atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0);
atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, 0);
}
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -889,7 +884,7 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
struct atiixp *chip = snd_pcm_substream_chip(substream);
unsigned int data;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK;
switch (substream->runtime->channels) {
case 8:
@@ -924,7 +919,6 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
atiixp_update(chip, 6CH_REORDER, ATI_REG_6CH_REORDER_EN,
substream->runtime->channels >= 6 ? ATI_REG_6CH_REORDER_EN: 0);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -933,11 +927,10 @@ static int snd_atiixp_capture_prepare(struct snd_pcm_substream *substream)
{
struct atiixp *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_IN,
substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ?
ATI_REG_CMD_INTERLEAVE_IN : 0);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1045,9 +1038,9 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,
runtime->private_data = dma;
/* enable DMA bits */
- spin_lock_irq(&chip->reg_lock);
- dma->ops->enable_dma(chip, 1);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ dma->ops->enable_dma(chip, 1);
+ }
dma->opened = 1;
return 0;
@@ -1060,9 +1053,9 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
/* disable DMA bits */
if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
return -EINVAL;
- spin_lock_irq(&chip->reg_lock);
- dma->ops->enable_dma(chip, 0);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ dma->ops->enable_dma(chip, 0);
+ }
dma->substream = NULL;
dma->opened = 0;
return 0;
@@ -1075,9 +1068,8 @@ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream)
struct atiixp *chip = snd_pcm_substream_chip(substream);
int err;
- mutex_lock(&chip->open_mutex);
+ guard(mutex)(&chip->open_mutex);
err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
- mutex_unlock(&chip->open_mutex);
if (err < 0)
return err;
substream->runtime->hw.channels_max = chip->max_channels;
@@ -1091,11 +1083,9 @@ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream)
static int snd_atiixp_playback_close(struct snd_pcm_substream *substream)
{
struct atiixp *chip = snd_pcm_substream_chip(substream);
- int err;
- mutex_lock(&chip->open_mutex);
- err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
- mutex_unlock(&chip->open_mutex);
- return err;
+
+ guard(mutex)(&chip->open_mutex);
+ return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
}
static int snd_atiixp_capture_open(struct snd_pcm_substream *substream)
@@ -1113,27 +1103,23 @@ static int snd_atiixp_capture_close(struct snd_pcm_substream *substream)
static int snd_atiixp_spdif_open(struct snd_pcm_substream *substream)
{
struct atiixp *chip = snd_pcm_substream_chip(substream);
- int err;
- mutex_lock(&chip->open_mutex);
+
+ guard(mutex)(&chip->open_mutex);
if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */
- err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);
+ return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);
else
- err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);
- mutex_unlock(&chip->open_mutex);
- return err;
+ return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);
}
static int snd_atiixp_spdif_close(struct snd_pcm_substream *substream)
{
struct atiixp *chip = snd_pcm_substream_chip(substream);
- int err;
- mutex_lock(&chip->open_mutex);
+
+ guard(mutex)(&chip->open_mutex);
if (chip->spdif_over_aclink)
- err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+ return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
else
- err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
- mutex_unlock(&chip->open_mutex);
- return err;
+ return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
}
/* AC97 playback */
@@ -1273,7 +1259,7 @@ static int snd_atiixp_pcm_new(struct atiixp *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);
pcm->private_data = chip;
- strcpy(pcm->name, "ATI IXP AC97");
+ strscpy(pcm->name, "ATI IXP AC97");
chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1303,9 +1289,9 @@ static int snd_atiixp_pcm_new(struct atiixp *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops);
pcm->private_data = chip;
if (chip->spdif_over_aclink)
- strcpy(pcm->name, "ATI IXP IEC958 (AC97)");
+ strscpy(pcm->name, "ATI IXP IEC958 (AC97)");
else
- strcpy(pcm->name, "ATI IXP IEC958 (Direct)");
+ strscpy(pcm->name, "ATI IXP IEC958 (Direct)");
chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1357,10 +1343,9 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
if (status & CODEC_CHECK_BITS) {
unsigned int detected;
detected = status & CODEC_CHECK_BITS;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
chip->codec_not_ready_bits |= detected;
atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */
- spin_unlock(&chip->reg_lock);
}
/* ack */
@@ -1454,7 +1439,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock,
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1499,12 +1483,7 @@ static int snd_atiixp_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
-#define SND_ATIIXP_PM_OPS &snd_atiixp_pm
-#else
-#define SND_ATIIXP_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
-
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
/*
* proc interface for register dump
@@ -1552,11 +1531,10 @@ static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci)
chip->card = card;
chip->pci = pci;
chip->irq = -1;
- err = pcim_iomap_regions(pci, 1 << 0, "ATI IXP AC97");
- if (err < 0)
- return err;
+ chip->remap_addr = pcim_iomap_region(pci, 0, "ATI IXP AC97");
+ if (IS_ERR(chip->remap_addr))
+ return PTR_ERR(chip->remap_addr);
chip->addr = pci_resource_start(pci, 0);
- chip->remap_addr = pcim_iomap_table(pci)[0];
if (devm_request_irq(&pci->dev, pci->irq, snd_atiixp_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1585,8 +1563,8 @@ static int __snd_atiixp_probe(struct pci_dev *pci,
return err;
chip = card->private_data;
- strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA");
- strcpy(card->shortname, "ATI IXP");
+ strscpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA");
+ strscpy(card->shortname, "ATI IXP");
err = snd_atiixp_init(card, pci);
if (err < 0)
return err;
@@ -1634,7 +1612,7 @@ static struct pci_driver atiixp_driver = {
.id_table = snd_atiixp_ids,
.probe = snd_atiixp_probe,
.driver = {
- .pm = SND_ATIIXP_PM_OPS,
+ .pm = &snd_atiixp_pm,
},
};
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 8864c4c3c7e1..91f31e2ad3d3 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -314,7 +314,6 @@ static int atiixp_build_dma_packets(struct atiixp_modem *chip,
{
unsigned int i;
u32 addr, desc_addr;
- unsigned long flags;
if (periods > ATI_MAX_DESCRIPTORS)
return -ENOMEM;
@@ -330,11 +329,11 @@ static int atiixp_build_dma_packets(struct atiixp_modem *chip,
return 0;
/* reset DMA before changing the descriptor table */
- spin_lock_irqsave(&chip->reg_lock, flags);
- writel(0, chip->remap_addr + dma->ops->llp_offset);
- dma->ops->enable_dma(chip, 0);
- dma->ops->enable_dma(chip, 1);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ writel(0, chip->remap_addr + dma->ops->llp_offset);
+ dma->ops->enable_dma(chip, 0);
+ dma->ops->enable_dma(chip, 1);
+ }
/* fill the entries */
addr = (u32)substream->runtime->dma_addr;
@@ -496,7 +495,6 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
{
// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -506,7 +504,6 @@ static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
ATI_REG_CMD_POWERDOWN);
return 0;
}
-#endif
/*
* auto-detection of codecs
@@ -663,7 +660,7 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
!dma->ops->flush_dma))
return -EINVAL;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch(cmd) {
case SNDRV_PCM_TRIGGER_START:
dma->ops->enable_transfer(chip, 1);
@@ -684,7 +681,6 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_atiixp_check_bus_busy(chip);
}
}
- spin_unlock(&chip->reg_lock);
return err;
}
@@ -755,13 +751,12 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
unsigned int data;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
/* set output threshold */
data = atiixp_read(chip, MODEM_OUT_FIFO);
data &= ~ATI_REG_MODEM_OUT1_DMA_THRESHOLD_MASK;
data |= 0x04 << ATI_REG_MODEM_OUT1_DMA_THRESHOLD_SHIFT;
atiixp_write(chip, MODEM_OUT_FIFO, data);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -866,9 +861,9 @@ static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,
runtime->private_data = dma;
/* enable DMA bits */
- spin_lock_irq(&chip->reg_lock);
- dma->ops->enable_dma(chip, 1);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ dma->ops->enable_dma(chip, 1);
+ }
dma->opened = 1;
return 0;
@@ -881,9 +876,9 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
/* disable DMA bits */
if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
return -EINVAL;
- spin_lock_irq(&chip->reg_lock);
- dma->ops->enable_dma(chip, 0);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ dma->ops->enable_dma(chip, 0);
+ }
dma->substream = NULL;
dma->opened = 0;
return 0;
@@ -894,24 +889,17 @@ static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
static int snd_atiixp_playback_open(struct snd_pcm_substream *substream)
{
struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
- int err;
- mutex_lock(&chip->open_mutex);
- err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
- mutex_unlock(&chip->open_mutex);
- if (err < 0)
- return err;
- return 0;
+ guard(mutex)(&chip->open_mutex);
+ return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
}
static int snd_atiixp_playback_close(struct snd_pcm_substream *substream)
{
struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
- int err;
- mutex_lock(&chip->open_mutex);
- err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
- mutex_unlock(&chip->open_mutex);
- return err;
+
+ guard(mutex)(&chip->open_mutex);
+ return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
}
static int snd_atiixp_capture_open(struct snd_pcm_substream *substream)
@@ -984,7 +972,7 @@ static int snd_atiixp_pcm_new(struct atiixp_modem *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);
pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
pcm->private_data = chip;
- strcpy(pcm->name, "ATI IXP MC97");
+ strscpy(pcm->name, "ATI IXP MC97");
chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1022,10 +1010,9 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
if (status & CODEC_CHECK_BITS) {
unsigned int detected;
detected = status & CODEC_CHECK_BITS;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
chip->codec_not_ready_bits |= detected;
atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */
- spin_unlock(&chip->reg_lock);
}
/* ack */
@@ -1094,7 +1081,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1128,11 +1114,7 @@ static int snd_atiixp_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
-#define SND_ATIIXP_PM_OPS &snd_atiixp_pm
-#else
-#define SND_ATIIXP_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
/*
* proc interface for register dump
@@ -1181,11 +1163,10 @@ static int snd_atiixp_init(struct snd_card *card, struct pci_dev *pci)
chip->card = card;
chip->pci = pci;
chip->irq = -1;
- err = pcim_iomap_regions(pci, 1 << 0, "ATI IXP MC97");
- if (err < 0)
- return err;
+ chip->remap_addr = pcim_iomap_region(pci, 0, "ATI IXP MC97");
+ if (IS_ERR(chip->remap_addr))
+ return PTR_ERR(chip->remap_addr);
chip->addr = pci_resource_start(pci, 0);
- chip->remap_addr = pcim_iomap_table(pci)[0];
if (devm_request_irq(&pci->dev, pci->irq, snd_atiixp_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1214,8 +1195,8 @@ static int __snd_atiixp_probe(struct pci_dev *pci,
return err;
chip = card->private_data;
- strcpy(card->driver, "ATIIXP-MODEM");
- strcpy(card->shortname, "ATI IXP Modem");
+ strscpy(card->driver, "ATIIXP-MODEM");
+ strscpy(card->shortname, "ATI IXP Modem");
err = snd_atiixp_init(card, pci);
if (err < 0)
return err;
@@ -1258,7 +1239,7 @@ static struct pci_driver atiixp_modem_driver = {
.id_table = snd_atiixp_ids,
.probe = snd_atiixp_probe,
.driver = {
- .pm = SND_ATIIXP_PM_OPS,
+ .pm = &snd_atiixp_pm,
},
};
diff --git a/sound/pci/au88x0/Makefile b/sound/pci/au88x0/Makefile
index 78ab11562f4d..5ec5abdee28d 100644
--- a/sound/pci/au88x0/Makefile
+++ b/sound/pci/au88x0/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
-snd-au8810-objs := au8810.o
-snd-au8820-objs := au8820.o
-snd-au8830-objs := au8830.o
+snd-au8810-y := au8810.o
+snd-au8820-y := au8820.o
+snd-au8830-y := au8830.o
obj-$(CONFIG_SND_AU8810) += snd-au8810.o
obj-$(CONFIG_SND_AU8820) += snd-au8820.o
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index eb234153691b..bb02945793f0 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -10,7 +10,7 @@
* Thanks to the ALSA developers, they helped a lot working out
* the ALSA part.
* Thanks also to Sourceforge for maintaining the old binary drivers,
- * and the forum, where developers could comunicate.
+ * and the forum, where developers could communicate.
*
* Now at least i can play Legacy DOOM with MIDI music :-)
*/
@@ -160,12 +160,11 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci)
// (1) PCI resource allocation
// Get MMIO area
//
- err = pcim_iomap_regions(pci, 1 << 0, CARD_NAME_SHORT);
- if (err)
- return err;
+ chip->mmio = pcim_iomap_region(pci, 0, KBUILD_MODNAME);
+ if (IS_ERR(chip->mmio))
+ return PTR_ERR(chip->mmio);
chip->io = pci_resource_start(pci, 0);
- chip->mmio = pcim_iomap_table(pci)[0];
/* Init audio core.
* This must be done before we do request_irq otherwise we can get spurious
@@ -221,7 +220,7 @@ __snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
snd_vortex_workaround(pci, pcifix[dev]);
// Card details needed in snd_vortex_midi
- strcpy(card->driver, CARD_NAME_SHORT);
+ strscpy(card->driver, CARD_NAME_SHORT);
sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT);
sprintf(card->longname, "%s at 0x%lx irq %i",
card->shortname, chip->io, chip->irq);
@@ -271,7 +270,7 @@ __snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
snd_vortex_synth_arg_t *arg;
arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
- strcpy(wave->name, "Aureal Synth");
+ strscpy(wave->name, "Aureal Synth");
arg->hwptr = vortex;
arg->index = 1;
arg->seq_ports = seq_ports[dev];
@@ -281,11 +280,11 @@ __snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
// (5)
err = pci_read_config_word(pci, PCI_DEVICE_ID, &chip->device);
- if (err < 0)
- return err;
+ if (err)
+ return pcibios_err_to_errno(err);
err = pci_read_config_word(pci, PCI_VENDOR_ID, &chip->vendor);
- if (err < 0)
- return err;
+ if (err)
+ return pcibios_err_to_errno(err);
chip->rev = pci->revision;
#ifdef CHIP_AU8830
if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index eabaee0463fe..d5cafaa229f1 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -754,7 +754,7 @@ snd_vortex_a3d_filter_info(struct snd_kcontrol *kcontrol,
static int
snd_vortex_a3d_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- //a3dsrc_t *a = kcontrol->private_data;
+ //a3dsrc_t *a = snd_kcontrol_chip(kcontrol);
/* No read yet. Would this be really useable/needed ? */
return 0;
@@ -764,7 +764,7 @@ static int
snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- a3dsrc_t *a = kcontrol->private_data;
+ a3dsrc_t *a = snd_kcontrol_chip(kcontrol);
int i;
int coord[6];
for (i = 0; i < 6; i++)
@@ -781,7 +781,7 @@ static int
snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- a3dsrc_t *a = kcontrol->private_data;
+ a3dsrc_t *a = snd_kcontrol_chip(kcontrol);
int coord[6];
int i;
for (i = 0; i < 6; i++)
@@ -800,7 +800,7 @@ static int
snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- a3dsrc_t *a = kcontrol->private_data;
+ a3dsrc_t *a = snd_kcontrol_chip(kcontrol);
int l, r;
/* There may be some scale tranlation needed here. */
l = ucontrol->value.integer.value[0];
@@ -816,7 +816,7 @@ static int
snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- a3dsrc_t *a = kcontrol->private_data;
+ a3dsrc_t *a = snd_kcontrol_chip(kcontrol);
int i;
int params[6];
for (i = 0; i < 6; i++)
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index f217c02dfdfa..e5d867637336 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -1195,7 +1195,7 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
snd_pcm_sgbuf_get_addr(dma->substream,
dma->period_bytes * p));
- /* Force write thru cache. */
+ /* Force write through cache. */
hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE +
(((adbdma << 2) + pp) << 2));
}
@@ -1237,7 +1237,7 @@ static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
snd_pcm_sgbuf_get_addr(dma->substream,
dma->period_bytes * p));
- /* Force write thru cache. */
+ /* Force write through cache. */
hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (((adbdma << 2)+pp) << 2));
}
}
@@ -1466,7 +1466,7 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
(((wtdma << 2) + pp) << 2),
snd_pcm_sgbuf_get_addr(dma->substream,
dma->period_bytes * p));
- /* Force write thru cache. */
+ /* Force write through cache. */
hwread(vortex->mmio, VORTEX_WTDMA_BUFBASE +
(((wtdma << 2) + pp) << 2));
}
@@ -1854,7 +1854,7 @@ vortex_connection_mixin_mix(vortex_t * vortex, int en, unsigned char mixin,
vortex_mix_disableinput(vortex, mix, mixin, a);
}
-// Connect absolut address to mixin.
+// Connect absolute address to mixin.
static void
vortex_connection_adb_mixin(vortex_t * vortex, int en,
unsigned char channel, unsigned char source,
@@ -1880,7 +1880,7 @@ vortex_connection_src_src_adbdma(vortex_t * vortex, int en,
ADB_DMA(adbdma));
}
-// mix to absolut address.
+// mix to absolute address.
static void
vortex_connection_mix_adb(vortex_t * vortex, int en, unsigned char ch,
unsigned char mix, unsigned char dest)
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index 71c13100d7ef..81a63b5bb31c 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -568,7 +568,7 @@ static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
eqlzr_t *eq = &(vortex->eq);
vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
- vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
+ vortex_EqHw_SetRightGainsTarget(vortex, eq->this130 + eq->this10);
return 0;
}
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
index aeba684b8d18..00781a7fd28c 100644
--- a/sound/pci/au88x0/au88x0_mixer.c
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -15,7 +15,7 @@ static int remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
memset(&id, 0, sizeof(id));
- strcpy(id.name, name);
+ strscpy(id.name, name);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(card, &id);
}
diff --git a/sound/pci/aw2/Makefile b/sound/pci/aw2/Makefile
index f9045afb4cda..c246f7c7f2bf 100644
--- a/sound/pci/aw2/Makefile
+++ b/sound/pci/aw2/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-aw2-objs := aw2-alsa.o aw2-saa7146.o
+snd-aw2-y := aw2-alsa.o aw2-saa7146.o
obj-$(CONFIG_SND_AW2) += snd-aw2.o
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 29a4bcdec237..e2c501f4394c 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -225,11 +225,10 @@ static int snd_aw2_create(struct snd_card *card,
chip->irq = -1;
/* (1) PCI resource allocation */
- err = pcim_iomap_regions(pci, 1 << 0, "Audiowerk2");
- if (err < 0)
- return err;
+ chip->iobase_virt = pcim_iomap_region(pci, 0, "Audiowerk2");
+ if (IS_ERR(chip->iobase_virt))
+ return PTR_ERR(chip->iobase_virt);
chip->iobase_phys = pci_resource_start(pci, 0);
- chip->iobase_virt = pcim_iomap_table(pci)[0];
/* (2) initialization of the chip hardware */
snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
@@ -282,8 +281,8 @@ static int snd_aw2_probe(struct pci_dev *pci,
/* init spinlock */
spin_lock_init(&chip->reg_lock);
/* (4) Define driver ID and name string */
- strcpy(card->driver, "aw2");
- strcpy(card->shortname, "Audiowerk2");
+ strscpy(card->driver, "aw2");
+ strscpy(card->shortname, "Audiowerk2");
sprintf(card->longname, "%s with SAA7146 irq %i",
card->shortname, chip->irq);
@@ -348,7 +347,7 @@ static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long period_size, buffer_size;
- mutex_lock(&chip->mtx);
+ guard(mutex)(&chip->mtx);
period_size = snd_pcm_lib_period_bytes(substream);
buffer_size = snd_pcm_lib_buffer_bytes(substream);
@@ -364,8 +363,6 @@ static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream)
snd_pcm_period_elapsed,
(void *)substream);
- mutex_unlock(&chip->mtx);
-
return 0;
}
@@ -377,7 +374,7 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long period_size, buffer_size;
- mutex_lock(&chip->mtx);
+ guard(mutex)(&chip->mtx);
period_size = snd_pcm_lib_period_bytes(substream);
buffer_size = snd_pcm_lib_buffer_bytes(substream);
@@ -393,8 +390,6 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream)
snd_pcm_period_elapsed,
(void *)substream);
- mutex_unlock(&chip->mtx);
-
return 0;
}
@@ -402,10 +397,10 @@ static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream)
static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
int cmd)
{
- int status = 0;
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
struct aw2 *chip = pcm_device->chip;
- spin_lock(&chip->reg_lock);
+
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_aw2_saa7146_pcm_trigger_start_playback(&chip->saa7146,
@@ -418,20 +413,19 @@ static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
stream_number);
break;
default:
- status = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
- return status;
+ return 0;
}
/* capture trigger callback */
static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
int cmd)
{
- int status = 0;
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
struct aw2 *chip = pcm_device->chip;
- spin_lock(&chip->reg_lock);
+
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_aw2_saa7146_pcm_trigger_start_capture(&chip->saa7146,
@@ -444,10 +438,9 @@ static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
stream_number);
break;
default:
- status = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
- return status;
+ return 0;
}
/* playback pointer callback */
@@ -510,7 +503,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_ANA];
/* Set PCM device name */
- strcpy(pcm_playback_ana->name, "Analog playback");
+ strscpy(pcm_playback_ana->name, "Analog playback");
/* Associate private data to PCM device */
pcm_playback_ana->private_data = pcm_device;
/* set operators of PCM device */
@@ -542,7 +535,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_DIG];
/* Set PCM device name */
- strcpy(pcm_playback_num->name, "Digital playback");
+ strscpy(pcm_playback_num->name, "Digital playback");
/* Associate private data to PCM device */
pcm_playback_num->private_data = pcm_device;
/* set operators of PCM device */
@@ -575,7 +568,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
pcm_device = &chip->device_capture[NUM_STREAM_CAPTURE_ANA];
/* Set PCM device name */
- strcpy(pcm_capture->name, "Capture");
+ strscpy(pcm_capture->name, "Capture");
/* Associate private data to PCM device */
pcm_capture->private_data = pcm_device;
/* set operators of PCM device */
diff --git a/sound/pci/aw2/aw2-saa7146.h b/sound/pci/aw2/aw2-saa7146.h
index b5c5a71c0ac3..3a3de56b9b07 100644
--- a/sound/pci/aw2/aw2-saa7146.h
+++ b/sound/pci/aw2/aw2-saa7146.h
@@ -19,11 +19,12 @@
#define NUM_STREAM_CAPTURE_ANA 0
-typedef void (*snd_aw2_saa7146_it_cb) (void *);
+struct snd_pcm_substream;
+typedef void (*snd_aw2_saa7146_it_cb) (struct snd_pcm_substream *);
struct snd_aw2_saa7146_cb_param {
snd_aw2_saa7146_it_cb p_it_callback;
- void *p_callback_param;
+ struct snd_pcm_substream *p_callback_param;
};
/* definition of the chip-specific record */
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 0c6754bf9455..6cdf76e2b7d2 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -295,7 +295,6 @@ struct snd_azf3328 {
* CONFIG_PM register storage below, but that's slightly difficult. */
u16 shadow_reg_ctrl_6AH;
-#ifdef CONFIG_PM_SLEEP
/* register value containers for power management
* Note: not always full I/O range preserved (similar to Win driver!) */
u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
@@ -303,7 +302,6 @@ struct snd_azf3328 {
u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4];
u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4];
u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4];
-#endif
};
static const struct pci_device_id snd_azf3328_ids[] = {
@@ -414,25 +412,25 @@ snd_azf3328_ctrl_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value)
outl(value, chip->ctrl_io + reg);
}
-static inline void
+static inline void __maybe_unused
snd_azf3328_game_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value)
{
outb(value, chip->game_io + reg);
}
-static inline void
+static inline void __maybe_unused
snd_azf3328_game_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
{
outw(value, chip->game_io + reg);
}
-static inline u8
+static inline u8 __maybe_unused
snd_azf3328_game_inb(const struct snd_azf3328 *chip, unsigned reg)
{
return inb(chip->game_io + reg);
}
-static inline u16
+static inline u16 __maybe_unused
snd_azf3328_game_inw(const struct snd_azf3328 *chip, unsigned reg)
{
return inw(chip->game_io + reg);
@@ -1190,7 +1188,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
return err;
}
snd_component_add(card, "AZF3328 mixer");
- strcpy(card->mixername, "AZF3328 mixer");
+ strscpy(card->mixername, "AZF3328 mixer");
return 0;
}
@@ -1203,7 +1201,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
unsigned int channels
)
{
- unsigned long flags;
u16 val = 0xff00;
u8 freq = 0;
@@ -1222,7 +1219,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
case AZF_FREQ_22050: freq = SOUNDFORMAT_FREQ_22050; break;
case AZF_FREQ_32000: freq = SOUNDFORMAT_FREQ_32000; break;
default:
- snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
+ pr_warn("azf3328: unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
fallthrough;
case AZF_FREQ_44100: freq = SOUNDFORMAT_FREQ_44100; break;
case AZF_FREQ_48000: freq = SOUNDFORMAT_FREQ_48000; break;
@@ -1246,7 +1243,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
if (format_width == 16)
val |= SOUNDFORMAT_FLAG_16BIT;
- spin_lock_irqsave(codec->lock, flags);
+ guard(spinlock_irqsave)(codec->lock);
/* set bitrate/format */
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val);
@@ -1268,8 +1265,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
DMA_EPILOGUE_SOMETHING |
DMA_SOMETHING_ELSE
);
-
- spin_unlock_irqrestore(codec->lock, flags);
}
static inline void
@@ -1375,15 +1370,13 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
if (!codec->running) {
/* AZF3328 uses a two buffer pointer DMA transfer approach */
- unsigned long flags;
-
/* width 32bit (prevent overflow): */
u32 area_length;
struct codec_setup_io {
u32 dma_start_1;
u32 dma_start_2;
u32 dma_lengths;
- } __attribute__((packed)) setup_io;
+ } __packed setup_io;
area_length = buffer_bytes/2;
@@ -1407,11 +1400,10 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
/* build combined I/O buffer length word */
setup_io.dma_lengths = (area_length << 16) | (area_length);
- spin_lock_irqsave(codec->lock, flags);
+ guard(spinlock_irqsave)(codec->lock);
snd_azf3328_codec_outl_multi(
codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3
);
- spin_unlock_irqrestore(codec->lock, flags);
}
}
@@ -1466,48 +1458,48 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_pcm_format_width(runtime->format),
runtime->channels);
- spin_lock(codec->lock);
- /* first, remember current value: */
- flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
+ scoped_guard(spinlock, codec->lock) {
+ /* first, remember current value: */
+ flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
- /* stop transfer */
- flags1 &= ~DMA_RESUME;
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
+ /* stop transfer */
+ flags1 &= ~DMA_RESUME;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- /* FIXME: clear interrupts or what??? */
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
- spin_unlock(codec->lock);
+ /* FIXME: clear interrupts or what??? */
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
+ }
snd_azf3328_codec_setdmaa(chip, codec, runtime->dma_addr,
snd_pcm_lib_period_bytes(substream),
snd_pcm_lib_buffer_bytes(substream)
);
- spin_lock(codec->lock);
+ scoped_guard(spinlock, codec->lock) {
#ifdef WIN9X
- /* FIXME: enable playback/recording??? */
- flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2;
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
-
- /* start transfer again */
- /* FIXME: what is this value (0x0010)??? */
- flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING;
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
+ /* FIXME: enable playback/recording??? */
+ flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
+
+ /* start transfer again */
+ /* FIXME: what is this value (0x0010)??? */
+ flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
#else /* NT4 */
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
- 0x0000);
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
- DMA_RUN_SOMETHING1);
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
- DMA_RUN_SOMETHING1 |
- DMA_RUN_SOMETHING2);
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
- DMA_RESUME |
- SOMETHING_ALMOST_ALWAYS_SET |
- DMA_EPILOGUE_SOMETHING |
- DMA_SOMETHING_ELSE);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ 0x0000);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ DMA_RUN_SOMETHING1);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ DMA_RUN_SOMETHING1 |
+ DMA_RUN_SOMETHING2);
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ DMA_RESUME |
+ SOMETHING_ALMOST_ALWAYS_SET |
+ DMA_EPILOGUE_SOMETHING |
+ DMA_SOMETHING_ELSE);
#endif
- spin_unlock(codec->lock);
+ }
snd_azf3328_ctrl_codec_activity(chip, codec->type, 1);
if (is_main_mixer_playback_codec) {
@@ -1523,14 +1515,14 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME:
dev_dbg(chip->card->dev, "PCM RESUME %s\n", codec->name);
/* resume codec if we were active */
- spin_lock(codec->lock);
- if (codec->running)
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
- snd_azf3328_codec_inw(
- codec, IDX_IO_CODEC_DMA_FLAGS
- ) | DMA_RESUME
- );
- spin_unlock(codec->lock);
+ scoped_guard(spinlock, codec->lock) {
+ if (codec->running)
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
+ snd_azf3328_codec_inw(
+ codec, IDX_IO_CODEC_DMA_FLAGS
+ ) | DMA_RESUME
+ );
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
dev_dbg(chip->card->dev, "PCM STOP %s\n", codec->name);
@@ -1543,22 +1535,22 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
);
}
- spin_lock(codec->lock);
- /* first, remember current value: */
- flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
+ scoped_guard(spinlock, codec->lock) {
+ /* first, remember current value: */
+ flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
- /* stop transfer */
- flags1 &= ~DMA_RESUME;
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
+ /* stop transfer */
+ flags1 &= ~DMA_RESUME;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- /* hmm, is this really required? we're resetting the same bit
- * immediately thereafter... */
- flags1 |= DMA_RUN_SOMETHING1;
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
+ /* hmm, is this really required? we're resetting the same bit
+ * immediately thereafter... */
+ flags1 |= DMA_RUN_SOMETHING1;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- flags1 &= ~DMA_RUN_SOMETHING1;
- snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- spin_unlock(codec->lock);
+ flags1 &= ~DMA_RUN_SOMETHING1;
+ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
+ }
snd_azf3328_ctrl_codec_activity(chip, codec->type, 0);
if (is_main_mixer_playback_codec) {
@@ -1726,12 +1718,11 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
struct snd_azf3328 *chip = gameport_get_port_data(gameport);
int i;
u8 val;
- unsigned long flags;
if (snd_BUG_ON(!chip))
return 0;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE);
*buttons = (~(val) >> 4) & 0xf;
@@ -1768,7 +1759,6 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val);
snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
for (i = 0; i < ARRAY_SIZE(chip->axes); i++) {
axes[i] = chip->axes[i];
@@ -1865,11 +1855,11 @@ snd_azf3328_pcm_interrupt(struct snd_azf3328 *chip,
if (!(status & (1 << codec_type)))
continue;
- spin_lock(codec->lock);
- which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE);
- /* ack all IRQ types immediately */
- snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which);
- spin_unlock(codec->lock);
+ scoped_guard(spinlock, codec->lock) {
+ which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE);
+ /* ack all IRQ types immediately */
+ snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which);
+ }
if (codec->substream) {
snd_pcm_period_elapsed(codec->substream);
@@ -1914,9 +1904,9 @@ snd_azf3328_interrupt(int irq, void *dev_id)
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
/* ACK timer */
- spin_lock(&chip->reg_lock);
- snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);
+ }
dev_dbg(chip->card->dev, "timer IRQ\n");
}
@@ -2097,7 +2087,7 @@ snd_azf3328_pcm(struct snd_azf3328 *chip)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
/* same pcm object for playback/capture (see snd_pcm_new() above) */
chip->pcm[AZF_CODEC_PLAYBACK] = pcm;
chip->pcm[AZF_CODEC_CAPTURE] = pcm;
@@ -2114,7 +2104,7 @@ snd_azf3328_pcm(struct snd_azf3328 *chip)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm[AZF_CODEC_I2S_OUT] = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
@@ -2139,7 +2129,6 @@ static int
snd_azf3328_timer_start(struct snd_timer *timer)
{
struct snd_azf3328 *chip;
- unsigned long flags;
unsigned int delay;
chip = snd_timer_chip(timer);
@@ -2154,9 +2143,8 @@ snd_azf3328_timer_start(struct snd_timer *timer)
}
dev_dbg(chip->card->dev, "setting timer countdown value %d\n", delay);
delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -2164,10 +2152,9 @@ static int
snd_azf3328_timer_stop(struct snd_timer *timer)
{
struct snd_azf3328 *chip;
- unsigned long flags;
chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
/* disable timer countdown and interrupt */
/* Hmm, should we write TIMER_IRQ_ACK here?
YES indeed, otherwise a rogue timer operation - which prompts
@@ -2176,7 +2163,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
Simply manually poking 0x04 _once_ immediately successfully stops
the hardware/ALSA interrupt activity. */
snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -2219,7 +2205,7 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
if (err < 0)
goto out;
- strcpy(timer->name, "AZF3328 timer");
+ strscpy(timer->name, "AZF3328 timer");
timer->private_data = chip;
timer->hw = snd_azf3328_timer_hw;
@@ -2349,7 +2335,7 @@ snd_azf3328_create(struct snd_card *card,
return -ENXIO;
}
- err = pci_request_regions(pci, "Aztech AZF3328");
+ err = pcim_request_all_regions(pci, "Aztech AZF3328");
if (err < 0)
return err;
@@ -2408,10 +2394,9 @@ snd_azf3328_create(struct snd_card *card,
codec->running = true;
snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
- spin_lock_irq(codec->lock);
+ guard(spinlock_irq)(codec->lock);
snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS,
dma_init);
- spin_unlock_irq(codec->lock);
}
return 0;
@@ -2439,8 +2424,8 @@ __snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return err;
chip = card->private_data;
- strcpy(card->driver, "AZF3328");
- strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
+ strscpy(card->driver, "AZF3328");
+ strscpy(card->shortname, "Aztech AZF3328 (PCI168)");
err = snd_azf3328_create(card, pci, pci_id->driver_data);
if (err < 0)
@@ -2517,7 +2502,6 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return snd_card_free_on_error(&pci->dev, __snd_azf3328_probe(pci, pci_id));
}
-#ifdef CONFIG_PM_SLEEP
static inline void
snd_azf3328_suspend_regs(const struct snd_azf3328 *chip,
unsigned long io_addr, unsigned count, u32 *saved_regs)
@@ -2633,18 +2617,14 @@ snd_azf3328_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume);
-#define SND_AZF3328_PM_OPS &snd_azf3328_pm
-#else
-#define SND_AZF3328_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume);
static struct pci_driver azf3328_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_azf3328_ids,
.probe = snd_azf3328_probe,
.driver = {
- .pm = SND_AZF3328_PM_OPS,
+ .pm = &snd_azf3328_pm,
},
};
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 621985bfee5d..383def1f2af7 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -431,10 +431,10 @@ static int snd_bt87x_close(struct snd_pcm_substream *substream)
{
struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
- chip->reg_control |= CTL_A_PWRDN;
- snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ chip->reg_control |= CTL_A_PWRDN;
+ snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
+ }
chip->substream = NULL;
clear_bit(0, &chip->opened);
@@ -466,20 +466,19 @@ static int snd_bt87x_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int decimation;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->reg_control &= ~(CTL_DA_SDR_MASK | CTL_DA_SBR);
decimation = (ANALOG_CLOCK + runtime->rate / 4) / runtime->rate;
chip->reg_control |= decimation << CTL_DA_SDR_SHIFT;
if (runtime->format == SNDRV_PCM_FORMAT_S8)
chip->reg_control |= CTL_DA_SBR;
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
static int snd_bt87x_start(struct snd_bt87x *chip)
{
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
chip->current_line = 0;
chip->reg_control |= CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN;
snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr);
@@ -487,18 +486,16 @@ static int snd_bt87x_start(struct snd_bt87x *chip)
chip->line_bytes | (chip->lines << 16));
snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask);
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
- spin_unlock(&chip->reg_lock);
return 0;
}
static int snd_bt87x_stop(struct snd_bt87x *chip)
{
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
chip->reg_control &= ~(CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN);
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
snd_bt87x_writel(chip, REG_INT_MASK, 0);
snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
- spin_unlock(&chip->reg_lock);
return 0;
}
@@ -560,13 +557,12 @@ static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol,
u32 old_control;
int changed;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
old_control = chip->reg_control;
chip->reg_control = (chip->reg_control & ~CTL_A_GAIN_MASK)
| (value->value.integer.value[0] << CTL_A_GAIN_SHIFT);
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
changed = old_control != chip->reg_control;
- spin_unlock_irq(&chip->reg_lock);
return changed;
}
@@ -596,13 +592,12 @@ static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol,
u32 old_control;
int changed;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
old_control = chip->reg_control;
chip->reg_control = (chip->reg_control & ~CTL_A_G2X)
| (value->value.integer.value[0] ? CTL_A_G2X : 0);
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
changed = chip->reg_control != old_control;
- spin_unlock_irq(&chip->reg_lock);
return changed;
}
@@ -638,13 +633,12 @@ static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol,
u32 old_control;
int changed;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
old_control = chip->reg_control;
chip->reg_control = (chip->reg_control & ~CTL_A_SEL_MASK)
| (value->value.enumerated.item[0] << CTL_A_SEL_SHIFT);
snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
changed = chip->reg_control != old_control;
- spin_unlock_irq(&chip->reg_lock);
return changed;
}
@@ -672,7 +666,7 @@ static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name)
if (err < 0)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
&chip->pci->dev,
@@ -696,10 +690,9 @@ static int snd_bt87x_create(struct snd_card *card,
chip->irq = -1;
spin_lock_init(&chip->reg_lock);
- err = pcim_iomap_regions(pci, 1 << 0, "Bt87x audio");
- if (err < 0)
- return err;
- chip->mmio = pcim_iomap_table(pci)[0];
+ chip->mmio = pcim_iomap_region(pci, 0, "Bt87x audio");
+ if (IS_ERR(chip->mmio))
+ return PTR_ERR(chip->mmio);
chip->reg_control = CTL_A_PWRDN | CTL_DA_ES2 |
CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT);
@@ -873,12 +866,12 @@ static int __snd_bt87x_probe(struct pci_dev *pci,
chip->board.no_analog ? "no " : "",
chip->board.no_digital ? "no " : "", chip->board.dig_rate);
- strcpy(card->driver, "Bt87x");
+ strscpy(card->driver, "Bt87x");
sprintf(card->shortname, "Brooktree Bt%x", pci->device);
sprintf(card->longname, "%s at %#llx, irq %i",
card->shortname, (unsigned long long)pci_resource_start(pci, 0),
chip->irq);
- strcpy(card->mixername, "Bt87x");
+ strscpy(card->mixername, "Bt87x");
err = snd_card_register(card);
if (err < 0)
diff --git a/sound/pci/ca0106/Makefile b/sound/pci/ca0106/Makefile
index 9e51d3df3ee8..693dc4d80925 100644
--- a/sound/pci/ca0106/Makefile
+++ b/sound/pci/ca0106/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-ca0106-objs := ca0106_main.o ca0106_mixer.o ca_midi.o
+snd-ca0106-y := ca0106_main.o ca0106_mixer.o ca_midi.o
snd-ca0106-$(CONFIG_SND_PROC_FS) += ca0106_proc.o
obj-$(CONFIG_SND_CA0106) += snd-ca0106.o
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index cf1bac7a435f..41774e2ef53f 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -332,16 +332,13 @@ unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu,
unsigned int reg,
unsigned int chn)
{
- unsigned long flags;
- unsigned int regptr, val;
+ unsigned int regptr;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(regptr, emu->port + CA0106_PTR);
- val = inl(emu->port + CA0106_DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inl(emu->port + CA0106_DATA);
}
void snd_ca0106_ptr_write(struct snd_ca0106 *emu,
@@ -350,14 +347,12 @@ void snd_ca0106_ptr_write(struct snd_ca0106 *emu,
unsigned int data)
{
unsigned int regptr;
- unsigned long flags;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(regptr, emu->port + CA0106_PTR);
outl(data, emu->port + CA0106_DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
int snd_ca0106_spi_write(struct snd_ca0106 * emu,
@@ -451,24 +446,20 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int intr_enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
intr_enable = inl(emu->port + CA0106_INTE) | intrenb;
outl(intr_enable, emu->port + CA0106_INTE);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int intr_enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
intr_enable = inl(emu->port + CA0106_INTE) & ~intrenb;
outl(intr_enable, emu->port + CA0106_INTE);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
@@ -1138,26 +1129,20 @@ static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
struct snd_ca0106 *emu = ac97->private_data;
- unsigned long flags;
- unsigned short val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outb(reg, emu->port + CA0106_AC97ADDRESS);
- val = inw(emu->port + CA0106_AC97DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inw(emu->port + CA0106_AC97DATA);
}
static void snd_ca0106_ac97_write(struct snd_ac97 *ac97,
unsigned short reg, unsigned short val)
{
struct snd_ca0106 *emu = ac97->private_data;
- unsigned long flags;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outb(reg, emu->port + CA0106_AC97ADDRESS);
outw(val, emu->port + CA0106_AC97DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static int snd_ca0106_ac97(struct snd_ca0106 *chip)
@@ -1315,7 +1300,7 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
}
pcm->info_flags = 0;
- strcpy(pcm->name, "CA0106");
+ strscpy(pcm->name, "CA0106");
for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
substream;
@@ -1593,7 +1578,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
spin_lock_init(&chip->emu_lock);
- err = pci_request_regions(pci, "snd_ca0106");
+ err = pcim_request_all_regions(pci, "snd_ca0106");
if (err < 0)
return err;
chip->port = pci_resource_start(pci, 0);
@@ -1617,8 +1602,8 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n",
chip->model, pci->revision, chip->serial);
- strcpy(card->driver, "CA0106");
- strcpy(card->shortname, "CA0106");
+ strscpy(card->driver, "CA0106");
+ strscpy(card->shortname, "CA0106");
for (c = ca0106_chip_details; c->serial; c++) {
if (subsystem[dev]) {
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index f6381c098d4f..f7b6b2db889b 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -701,24 +701,14 @@ static int remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
memset(&id, 0, sizeof(id));
- strcpy(id.name, name);
+ strscpy(id.name, name);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(card, &id);
}
-static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
-{
- struct snd_ctl_elem_id sid;
- memset(&sid, 0, sizeof(sid));
- /* FIXME: strcpy is bad. */
- strcpy(sid.name, name);
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- return snd_ctl_find_id(card, &sid);
-}
-
static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
{
- struct snd_kcontrol *kctl = ctl_find(card, src);
+ struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src);
if (kctl) {
snd_ctl_rename(card, kctl, dst);
return 0;
@@ -761,16 +751,6 @@ static const char * const follower_sws[] = {
NULL
};
-static void add_followers(struct snd_card *card,
- struct snd_kcontrol *master, const char * const *list)
-{
- for (; *list; list++) {
- struct snd_kcontrol *follower = ctl_find(card, *list);
- if (follower)
- snd_ctl_add_follower(master, follower);
- }
-}
-
int snd_ca0106_mixer(struct snd_ca0106 *emu)
{
int err;
@@ -852,7 +832,9 @@ int snd_ca0106_mixer(struct snd_ca0106 *emu)
err = snd_ctl_add(card, vmaster);
if (err < 0)
return err;
- add_followers(card, vmaster, follower_vols);
+ err = snd_ctl_add_followers(card, vmaster, follower_vols);
+ if (err < 0)
+ return err;
if (emu->details->spi_dac) {
vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
@@ -862,10 +844,12 @@ int snd_ca0106_mixer(struct snd_ca0106 *emu)
err = snd_ctl_add(card, vmaster);
if (err < 0)
return err;
- add_followers(card, vmaster, follower_sws);
+ err = snd_ctl_add_followers(card, vmaster, follower_sws);
+ if (err < 0)
+ return err;
}
- strcpy(card->mixername, "CA0106");
+ strscpy(card->mixername, "CA0106");
return 0;
}
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c
index c99603e137e5..c181e4954579 100644
--- a/sound/pci/ca0106/ca0106_proc.c
+++ b/sound/pci/ca0106/ca0106_proc.c
@@ -281,16 +281,14 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_ca0106 *emu = entry->private_data;
- unsigned long flags;
char line[64];
u32 reg, val;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
if (reg < 0x40 && val <= 0xffffffff) {
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(val, emu->port + (reg & 0xfffffffc));
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
}
}
@@ -300,13 +298,13 @@ static void snd_ca0106_proc_reg_read32(struct snd_info_entry *entry,
{
struct snd_ca0106 *emu = entry->private_data;
unsigned long value;
- unsigned long flags;
int i;
+
snd_iprintf(buffer, "Registers:\n\n");
for(i = 0; i < 0x20; i+=4) {
- spin_lock_irqsave(&emu->emu_lock, flags);
- value = inl(emu->port + i);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ scoped_guard(spinlock_irqsave, &emu->emu_lock) {
+ value = inl(emu->port + i);
+ }
snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
}
}
@@ -316,13 +314,13 @@ static void snd_ca0106_proc_reg_read16(struct snd_info_entry *entry,
{
struct snd_ca0106 *emu = entry->private_data;
unsigned int value;
- unsigned long flags;
int i;
+
snd_iprintf(buffer, "Registers:\n\n");
for(i = 0; i < 0x20; i+=2) {
- spin_lock_irqsave(&emu->emu_lock, flags);
- value = inw(emu->port + i);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ scoped_guard(spinlock_irqsave, &emu->emu_lock) {
+ value = inw(emu->port + i);
+ }
snd_iprintf(buffer, "Register %02X: %04X\n", i, value);
}
}
@@ -332,13 +330,13 @@ static void snd_ca0106_proc_reg_read8(struct snd_info_entry *entry,
{
struct snd_ca0106 *emu = entry->private_data;
unsigned int value;
- unsigned long flags;
int i;
+
snd_iprintf(buffer, "Registers:\n\n");
for(i = 0; i < 0x20; i+=1) {
- spin_lock_irqsave(&emu->emu_lock, flags);
- value = inb(emu->port + i);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ scoped_guard(spinlock_irqsave, &emu->emu_lock) {
+ value = inb(emu->port + i);
+ }
snd_iprintf(buffer, "Register %02X: %02X\n", i, value);
}
}
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
index 957e60f64821..6efd93abddb5 100644
--- a/sound/pci/ca0106/ca_midi.c
+++ b/sound/pci/ca0106/ca_midi.c
@@ -45,58 +45,54 @@ static void ca_midi_interrupt(struct snd_ca_midi *midi, unsigned int status)
return;
}
- spin_lock(&midi->input_lock);
- if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) {
- if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
- ca_midi_clear_rx(midi);
- } else {
- byte = ca_midi_read_data(midi);
- if(midi->substream_input)
- snd_rawmidi_receive(midi->substream_input, &byte, 1);
-
-
+ scoped_guard(spinlock, &midi->input_lock) {
+ if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) {
+ if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
+ ca_midi_clear_rx(midi);
+ } else {
+ byte = ca_midi_read_data(midi);
+ if (midi->substream_input)
+ snd_rawmidi_receive(midi->substream_input, &byte, 1);
+ }
}
}
- spin_unlock(&midi->input_lock);
- spin_lock(&midi->output_lock);
- if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) {
- if (midi->substream_output &&
- snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
- ca_midi_write_data(midi, byte);
- } else {
- midi->interrupt_disable(midi,midi->tx_enable);
+ scoped_guard(spinlock, &midi->output_lock) {
+ if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) {
+ if (midi->substream_output &&
+ snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
+ ca_midi_write_data(midi, byte);
+ } else {
+ midi->interrupt_disable(midi, midi->tx_enable);
+ }
}
}
- spin_unlock(&midi->output_lock);
-
}
static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack)
{
- unsigned long flags;
int timeout, ok;
- spin_lock_irqsave(&midi->input_lock, flags);
- ca_midi_write_data(midi, 0x00);
- /* ca_midi_clear_rx(midi); */
-
- ca_midi_write_cmd(midi, cmd);
- if (ack) {
- ok = 0;
- timeout = 10000;
- while (!ok && timeout-- > 0) {
- if (ca_midi_input_avail(midi)) {
- if (ca_midi_read_data(midi) == midi->ack)
- ok = 1;
+ scoped_guard(spinlock_irqsave, &midi->input_lock) {
+ ca_midi_write_data(midi, 0x00);
+ /* ca_midi_clear_rx(midi); */
+
+ ca_midi_write_cmd(midi, cmd);
+ if (ack) {
+ ok = 0;
+ timeout = 10000;
+ while (!ok && timeout-- > 0) {
+ if (ca_midi_input_avail(midi)) {
+ if (ca_midi_read_data(midi) == midi->ack)
+ ok = 1;
+ }
}
- }
- if (!ok && ca_midi_read_data(midi) == midi->ack)
+ if (!ok && ca_midi_read_data(midi) == midi->ack)
+ ok = 1;
+ } else {
ok = 1;
- } else {
- ok = 1;
+ }
}
- spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok)
pr_err("ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
cmd,
@@ -108,83 +104,69 @@ static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack)
static int ca_midi_input_open(struct snd_rawmidi_substream *substream)
{
struct snd_ca_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
if (snd_BUG_ON(!midi->dev_id))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->midi_mode |= CA_MIDI_MODE_INPUT;
- midi->substream_input = substream;
- if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- ca_midi_cmd(midi, midi->reset, 1);
- ca_midi_cmd(midi, midi->enter_uart, 1);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ midi->midi_mode |= CA_MIDI_MODE_INPUT;
+ midi->substream_input = substream;
+ if (midi->midi_mode & CA_MIDI_MODE_OUTPUT)
+ return 0;
}
+ ca_midi_cmd(midi, midi->reset, 1);
+ ca_midi_cmd(midi, midi->enter_uart, 1);
return 0;
}
static int ca_midi_output_open(struct snd_rawmidi_substream *substream)
{
struct snd_ca_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
if (snd_BUG_ON(!midi->dev_id))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->midi_mode |= CA_MIDI_MODE_OUTPUT;
- midi->substream_output = substream;
- if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- ca_midi_cmd(midi, midi->reset, 1);
- ca_midi_cmd(midi, midi->enter_uart, 1);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ midi->midi_mode |= CA_MIDI_MODE_OUTPUT;
+ midi->substream_output = substream;
+ if (midi->midi_mode & CA_MIDI_MODE_INPUT)
+ return 0;
}
+ ca_midi_cmd(midi, midi->reset, 1);
+ ca_midi_cmd(midi, midi->enter_uart, 1);
return 0;
}
static int ca_midi_input_close(struct snd_rawmidi_substream *substream)
{
struct snd_ca_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
if (snd_BUG_ON(!midi->dev_id))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->interrupt_disable(midi,midi->rx_enable);
- midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
- midi->substream_input = NULL;
- if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- ca_midi_cmd(midi, midi->reset, 0);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ midi->interrupt_disable(midi, midi->rx_enable);
+ midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
+ midi->substream_input = NULL;
+ if (midi->midi_mode & CA_MIDI_MODE_OUTPUT)
+ return 0;
}
+ ca_midi_cmd(midi, midi->reset, 0);
return 0;
}
static int ca_midi_output_close(struct snd_rawmidi_substream *substream)
{
struct snd_ca_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
if (snd_BUG_ON(!midi->dev_id))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
-
- midi->interrupt_disable(midi,midi->tx_enable);
- midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT;
- midi->substream_output = NULL;
-
- if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- ca_midi_cmd(midi, midi->reset, 0);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ midi->interrupt_disable(midi, midi->tx_enable);
+ midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT;
+ midi->substream_output = NULL;
+ if (midi->midi_mode & CA_MIDI_MODE_INPUT)
+ return 0;
}
+ ca_midi_cmd(midi, midi->reset, 0);
return 0;
}
@@ -205,7 +187,6 @@ static void ca_midi_input_trigger(struct snd_rawmidi_substream *substream, int u
static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct snd_ca_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
if (snd_BUG_ON(!midi->dev_id))
return;
@@ -214,25 +195,23 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int
int max = 4;
unsigned char byte;
- spin_lock_irqsave(&midi->output_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->output_lock) {
- /* try to send some amount of bytes here before interrupts */
- while (max > 0) {
- if (ca_midi_output_ready(midi)) {
- if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) ||
- snd_rawmidi_transmit(substream, &byte, 1) != 1) {
- /* no more data */
- spin_unlock_irqrestore(&midi->output_lock, flags);
- return;
+ /* try to send some amount of bytes here before interrupts */
+ while (max > 0) {
+ if (ca_midi_output_ready(midi)) {
+ if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) ||
+ snd_rawmidi_transmit(substream, &byte, 1) != 1) {
+ /* no more data */
+ return;
+ }
+ ca_midi_write_data(midi, byte);
+ max--;
+ } else {
+ break;
}
- ca_midi_write_data(midi, byte);
- max--;
- } else {
- break;
}
}
-
- spin_unlock_irqrestore(&midi->output_lock, flags);
midi->interrupt_enable(midi,midi->tx_enable);
} else {
@@ -287,7 +266,7 @@ int ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name)
spin_lock_init(&midi->input_lock);
spin_lock_init(&midi->output_lock);
- strcpy(rmidi->name, name);
+ strscpy(rmidi->name, name);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &ca_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &ca_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 727db6d43391..0666be543474 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -486,10 +486,8 @@ struct cmipci {
spinlock_t reg_lock;
-#ifdef CONFIG_PM_SLEEP
unsigned int saved_regs[0x20];
unsigned char saved_mixers[0x20];
-#endif
};
@@ -666,14 +664,11 @@ static int snd_cmipci_playback2_hw_params(struct snd_pcm_substream *substream,
{
struct cmipci *cm = snd_pcm_substream_chip(substream);
if (params_channels(hw_params) > 2) {
- mutex_lock(&cm->open_mutex);
- if (cm->opened[CM_CH_PLAY]) {
- mutex_unlock(&cm->open_mutex);
+ guard(mutex)(&cm->open_mutex);
+ if (cm->opened[CM_CH_PLAY])
return -EBUSY;
- }
/* reserve the channel A */
cm->opened[CM_CH_PLAY] = CM_OPEN_PLAYBACK_MULTI;
- mutex_unlock(&cm->open_mutex);
}
return 0;
}
@@ -717,7 +712,7 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann
}
if (cm->can_multi_ch) {
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
if (channels > 2) {
snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG);
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC);
@@ -740,7 +735,6 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann
snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
else
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
- spin_unlock_irq(&cm->reg_lock);
}
return 0;
}
@@ -781,7 +775,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
period_size = (period_size * runtime->channels) / 2;
}
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
/* set buffer address */
reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1;
@@ -847,7 +841,6 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
}
rec->running = 0;
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -859,14 +852,13 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec,
int cmd)
{
unsigned int inthld, chen, reset, pause;
- int result = 0;
inthld = CM_CH0_INT_EN << rec->ch;
chen = CM_CHEN0 << rec->ch;
reset = CM_RST_CH0 << rec->ch;
pause = CM_PAUSE0 << rec->ch;
- spin_lock(&cm->reg_lock);
+ guard(spinlock)(&cm->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
rec->running = 1;
@@ -898,11 +890,9 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec,
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
break;
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&cm->reg_lock);
- return result;
+ return 0;
}
/*
@@ -992,10 +982,9 @@ static int snd_cmipci_spdif_default_get(struct snd_kcontrol *kcontrol,
struct cmipci *chip = snd_kcontrol_chip(kcontrol);
int i;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
for (i = 0; i < 4; i++)
ucontrol->value.iec958.status[i] = (chip->dig_status >> (i * 8)) & 0xff;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1007,12 +996,11 @@ static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol,
unsigned int val;
val = 0;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
for (i = 0; i < 4; i++)
val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
change = val != chip->dig_status;
chip->dig_status = val;
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1066,10 +1054,9 @@ static int snd_cmipci_spdif_stream_get(struct snd_kcontrol *kcontrol,
struct cmipci *chip = snd_kcontrol_chip(kcontrol);
int i;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
for (i = 0; i < 4; i++)
ucontrol->value.iec958.status[i] = (chip->dig_pcm_status >> (i * 8)) & 0xff;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1081,12 +1068,11 @@ static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol,
unsigned int val;
val = 0;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
for (i = 0; i < 4; i++)
val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
change = val != chip->dig_pcm_status;
chip->dig_pcm_status = val;
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1230,7 +1216,7 @@ static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *sub
return err;
}
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
cm->spdif_playback_avail = up;
if (up) {
/* they are controlled via "IEC958 Output Switch" */
@@ -1256,7 +1242,6 @@ static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *sub
snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF);
setup_ac3(cm, subs, 0, 0);
}
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -1322,32 +1307,32 @@ static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec)
/* configure for 16 bits, 2 channels, 8 kHz */
if (runtime->channels > 2)
set_dac_channels(cm, rec, 2);
- spin_lock_irq(&cm->reg_lock);
- val = snd_cmipci_read(cm, CM_REG_FUNCTRL1);
- val &= ~(CM_ASFC_MASK << (rec->ch * 3));
- val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3);
- snd_cmipci_write(cm, CM_REG_FUNCTRL1, val);
- val = snd_cmipci_read(cm, CM_REG_CHFORMAT);
- val &= ~(CM_CH0FMT_MASK << (rec->ch * 2));
- val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2);
- if (cm->can_96k)
- val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2));
- snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
+ scoped_guard(spinlock_irq, &cm->reg_lock) {
+ val = snd_cmipci_read(cm, CM_REG_FUNCTRL1);
+ val &= ~(CM_ASFC_MASK << (rec->ch * 3));
+ val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3);
+ snd_cmipci_write(cm, CM_REG_FUNCTRL1, val);
+ val = snd_cmipci_read(cm, CM_REG_CHFORMAT);
+ val &= ~(CM_CH0FMT_MASK << (rec->ch * 2));
+ val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2);
+ if (cm->can_96k)
+ val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2));
+ snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
- /* start stream (we don't need interrupts) */
- cm->ctrl |= CM_CHEN0 << rec->ch;
- snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
- spin_unlock_irq(&cm->reg_lock);
+ /* start stream (we don't need interrupts) */
+ cm->ctrl |= CM_CHEN0 << rec->ch;
+ snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
+ }
msleep(1);
/* stop and reset stream */
- spin_lock_irq(&cm->reg_lock);
- cm->ctrl &= ~(CM_CHEN0 << rec->ch);
- val = CM_RST_CH0 << rec->ch;
- snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val);
- snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val);
- spin_unlock_irq(&cm->reg_lock);
+ scoped_guard(spinlock_irq, &cm->reg_lock) {
+ cm->ctrl &= ~(CM_CHEN0 << rec->ch);
+ val = CM_RST_CH0 << rec->ch;
+ snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val);
+ snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val);
+ }
rec->needs_silencing = 0;
}
@@ -1381,20 +1366,19 @@ static int snd_cmipci_capture_spdif_prepare(struct snd_pcm_substream *substream)
{
struct cmipci *cm = snd_pcm_substream_chip(substream);
- spin_lock_irq(&cm->reg_lock);
- snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);
- if (cm->can_96k) {
- if (substream->runtime->rate > 48000)
- snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
+ scoped_guard(spinlock_irq, &cm->reg_lock) {
+ snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);
+ if (cm->can_96k) {
+ if (substream->runtime->rate > 48000)
+ snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
+ else
+ snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
+ }
+ if (snd_pcm_format_width(substream->runtime->format) > 16)
+ snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
else
- snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
+ snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
}
- if (snd_pcm_format_width(substream->runtime->format) > 16)
- snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
- else
- snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
-
- spin_unlock_irq(&cm->reg_lock);
return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream);
}
@@ -1403,10 +1387,9 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs)
{
struct cmipci *cm = snd_pcm_substream_chip(subs);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -1426,14 +1409,14 @@ static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id)
return IRQ_NONE;
/* acknowledge interrupt */
- spin_lock(&cm->reg_lock);
- if (status & CM_CHINT0)
- mask |= CM_CH0_INT_EN;
- if (status & CM_CHINT1)
- mask |= CM_CH1_INT_EN;
- snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask);
- snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask);
- spin_unlock(&cm->reg_lock);
+ scoped_guard(spinlock, &cm->reg_lock) {
+ if (status & CM_CHINT0)
+ mask |= CM_CH0_INT_EN;
+ if (status & CM_CHINT1)
+ mask |= CM_CH1_INT_EN;
+ snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask);
+ snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask);
+ }
if (cm->rmidi && (status & CM_UARTINT))
snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data);
@@ -1572,14 +1555,6 @@ static const struct snd_pcm_hardware snd_cmipci_capture_spdif =
.fifo_size = 0,
};
-static const unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050,
- 32000, 44100, 48000, 88200, 96000, 128000 };
-static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = ARRAY_SIZE(rate_constraints),
- .list = rate_constraints,
- .mask = 0,
-};
-
/*
* check device open/close
*/
@@ -1592,21 +1567,17 @@ static int open_device_check(struct cmipci *cm, int mode, struct snd_pcm_substre
* pcm framework doesn't pass file pointer before actually opened,
* we can't know whether blocking mode or not in open callback..
*/
- mutex_lock(&cm->open_mutex);
- if (cm->opened[ch]) {
- mutex_unlock(&cm->open_mutex);
+ guard(mutex)(&cm->open_mutex);
+ if (cm->opened[ch])
return -EBUSY;
- }
cm->opened[ch] = mode;
cm->channel[ch].substream = subs;
if (! (mode & CM_OPEN_DAC)) {
/* disable dual DAC mode */
cm->channel[ch].is_dac = 0;
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC);
- spin_unlock_irq(&cm->reg_lock);
}
- mutex_unlock(&cm->open_mutex);
return 0;
}
@@ -1614,7 +1585,7 @@ static void close_device_check(struct cmipci *cm, int mode)
{
int ch = mode & CM_OPEN_CH_MASK;
- mutex_lock(&cm->open_mutex);
+ guard(mutex)(&cm->open_mutex);
if (cm->opened[ch] == mode) {
if (cm->channel[ch].substream) {
snd_cmipci_ch_reset(cm, ch);
@@ -1625,12 +1596,10 @@ static void close_device_check(struct cmipci *cm, int mode)
if (! cm->channel[ch].is_dac) {
/* enable dual DAC mode again */
cm->channel[ch].is_dac = 1;
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC);
- spin_unlock_irq(&cm->reg_lock);
}
}
- mutex_unlock(&cm->open_mutex);
}
/*
@@ -1651,11 +1620,9 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream)
SNDRV_PCM_RATE_96000;
runtime->hw.rate_max = 96000;
} else if (cm->chip_version == 55) {
- err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- if (err < 0)
- return err;
- runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+ runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_128000;
runtime->hw.rate_max = 128000;
}
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
@@ -1677,11 +1644,9 @@ static int snd_cmipci_capture_open(struct snd_pcm_substream *substream)
runtime->hw.rate_min = 41000;
runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
} else if (cm->chip_version == 55) {
- err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- if (err < 0)
- return err;
- runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+ runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_128000;
runtime->hw.rate_max = 128000;
}
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
@@ -1699,7 +1664,7 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream)
if (err < 0)
return err;
runtime->hw = snd_cmipci_playback2;
- mutex_lock(&cm->open_mutex);
+ guard(mutex)(&cm->open_mutex);
if (! cm->opened[CM_CH_PLAY]) {
if (cm->can_multi_ch) {
runtime->hw.channels_max = cm->max_channels;
@@ -1711,17 +1676,14 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8);
}
}
- mutex_unlock(&cm->open_mutex);
if (cm->chip_version == 68) {
runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000;
runtime->hw.rate_max = 96000;
} else if (cm->chip_version == 55) {
- err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
- if (err < 0)
- return err;
- runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+ runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_128000;
runtime->hw.rate_max = 128000;
}
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
@@ -1884,7 +1846,7 @@ static int snd_cmipci_pcm_new(struct cmipci *cm, int device)
pcm->private_data = cm;
pcm->info_flags = 0;
- strcpy(pcm->name, "C-Media PCI DAC/ADC");
+ strscpy(pcm->name, "C-Media PCI DAC/ADC");
cm->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1906,7 +1868,7 @@ static int snd_cmipci_pcm2_new(struct cmipci *cm, int device)
pcm->private_data = cm;
pcm->info_flags = 0;
- strcpy(pcm->name, "C-Media PCI 2nd DAC");
+ strscpy(pcm->name, "C-Media PCI 2nd DAC");
cm->pcm2 = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1929,7 +1891,7 @@ static int snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device)
pcm->private_data = cm;
pcm->info_flags = 0;
- strcpy(pcm->name, "C-Media PCI IEC958");
+ strscpy(pcm->name, "C-Media PCI IEC958");
cm->pcm_spdif = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -2026,7 +1988,7 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol,
int val;
cmipci_sb_reg_decode(&reg, kcontrol->private_value);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
val = (snd_cmipci_mixer_read(cm, reg.left_reg) >> reg.left_shift) & reg.mask;
if (reg.invert)
val = reg.mask - val;
@@ -2037,7 +1999,6 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol,
val = reg.mask - val;
ucontrol->value.integer.value[1] = val;
}
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -2061,7 +2022,7 @@ static int snd_cmipci_put_volume(struct snd_kcontrol *kcontrol,
right <<= reg.right_shift;
} else
right = 0;
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
oleft = snd_cmipci_mixer_read(cm, reg.left_reg);
left |= oleft & ~(reg.mask << reg.left_shift);
change = left != oleft;
@@ -2076,7 +2037,6 @@ static int snd_cmipci_put_volume(struct snd_kcontrol *kcontrol,
snd_cmipci_mixer_write(cm, reg.right_reg, right);
} else
snd_cmipci_mixer_write(cm, reg.left_reg, left);
- spin_unlock_irq(&cm->reg_lock);
return change;
}
@@ -2108,10 +2068,9 @@ static int snd_cmipci_get_input_sw(struct snd_kcontrol *kcontrol,
int val1, val2;
cmipci_sb_reg_decode(&reg, kcontrol->private_value);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
val1 = snd_cmipci_mixer_read(cm, reg.left_reg);
val2 = snd_cmipci_mixer_read(cm, reg.right_reg);
- spin_unlock_irq(&cm->reg_lock);
ucontrol->value.integer.value[0] = (val1 >> reg.left_shift) & 1;
ucontrol->value.integer.value[1] = (val2 >> reg.left_shift) & 1;
ucontrol->value.integer.value[2] = (val1 >> reg.right_shift) & 1;
@@ -2128,7 +2087,7 @@ static int snd_cmipci_put_input_sw(struct snd_kcontrol *kcontrol,
int val1, val2, oval1, oval2;
cmipci_sb_reg_decode(&reg, kcontrol->private_value);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
oval1 = snd_cmipci_mixer_read(cm, reg.left_reg);
oval2 = snd_cmipci_mixer_read(cm, reg.right_reg);
val1 = oval1 & ~((1 << reg.left_shift) | (1 << reg.right_shift));
@@ -2140,7 +2099,6 @@ static int snd_cmipci_put_input_sw(struct snd_kcontrol *kcontrol,
change = val1 != oval1 || val2 != oval2;
snd_cmipci_mixer_write(cm, reg.left_reg, val1);
snd_cmipci_mixer_write(cm, reg.right_reg, val2);
- spin_unlock_irq(&cm->reg_lock);
return change;
}
@@ -2198,7 +2156,7 @@ static int snd_cmipci_get_native_mixer(struct snd_kcontrol *kcontrol,
unsigned char oreg, val;
cmipci_sb_reg_decode(&reg, kcontrol->private_value);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
oreg = inb(cm->iobase + reg.left_reg);
val = (oreg >> reg.left_shift) & reg.mask;
if (reg.invert)
@@ -2210,7 +2168,6 @@ static int snd_cmipci_get_native_mixer(struct snd_kcontrol *kcontrol,
val = reg.mask - val;
ucontrol->value.integer.value[1] = val;
}
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -2222,7 +2179,7 @@ static int snd_cmipci_put_native_mixer(struct snd_kcontrol *kcontrol,
unsigned char oreg, nreg, val;
cmipci_sb_reg_decode(&reg, kcontrol->private_value);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
oreg = inb(cm->iobase + reg.left_reg);
val = ucontrol->value.integer.value[0] & reg.mask;
if (reg.invert)
@@ -2237,7 +2194,6 @@ static int snd_cmipci_put_native_mixer(struct snd_kcontrol *kcontrol,
nreg |= (val << reg.right_shift);
}
outb(nreg, cm->iobase + reg.left_reg);
- spin_unlock_irq(&cm->reg_lock);
return (nreg != oreg);
}
@@ -2324,10 +2280,9 @@ static int _snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol,
unsigned int val;
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
if (args->ac3_sensitive && cm->mixer_insensitive) {
ucontrol->value.integer.value[0] = 0;
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
if (args->is_byte)
@@ -2335,7 +2290,6 @@ static int _snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol,
else
val = snd_cmipci_read(cm, args->reg);
ucontrol->value.integer.value[0] = ((val & args->mask) == args->mask_on) ? 1 : 0;
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -2357,10 +2311,9 @@ static int _snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol,
int change;
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
if (args->ac3_sensitive && cm->mixer_insensitive) {
/* ignored */
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
if (args->is_byte)
@@ -2380,7 +2333,6 @@ static int _snd_cmipci_uswitch_put(struct snd_kcontrol *kcontrol,
else
snd_cmipci_write(cm, args->reg, val);
}
- spin_unlock_irq(&cm->reg_lock);
return change;
}
@@ -2513,9 +2465,8 @@ static int snd_cmipci_line_in_mode_get(struct snd_kcontrol *kcontrol,
{
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
ucontrol->value.enumerated.item[0] = get_line_in_mode(cm);
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -2525,7 +2476,7 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol,
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
int change;
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
if (ucontrol->value.enumerated.item[0] == 2)
change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CENTR2LIN | CM_BASE2LIN);
else
@@ -2534,7 +2485,6 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol,
change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN);
else
change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN);
- spin_unlock_irq(&cm->reg_lock);
return change;
}
@@ -2550,11 +2500,11 @@ static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
+
/* same bit as spdi_phase */
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
ucontrol->value.enumerated.item[0] =
(snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0;
- spin_unlock_irq(&cm->reg_lock);
return 0;
}
@@ -2564,12 +2514,11 @@ static int snd_cmipci_mic_in_mode_put(struct snd_kcontrol *kcontrol,
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
int change;
- spin_lock_irq(&cm->reg_lock);
+ guard(spinlock_irq)(&cm->reg_lock);
if (ucontrol->value.enumerated.item[0])
change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE);
else
change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE);
- spin_unlock_irq(&cm->reg_lock);
return change;
}
@@ -2649,11 +2598,11 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
card = cm->card;
- strcpy(card->mixername, "CMedia PCI");
+ strscpy(card->mixername, "CMedia PCI");
- spin_lock_irq(&cm->reg_lock);
- snd_cmipci_mixer_write(cm, 0x00, 0x00); /* mixer reset */
- spin_unlock_irq(&cm->reg_lock);
+ scoped_guard(spinlock_irq, &cm->reg_lock) {
+ snd_cmipci_mixer_write(cm, 0x00, 0x00); /* mixer reset */
+ }
for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_mixers); idx++) {
if (cm->chip_version == 68) { // 8768 has no PCM volume
@@ -2688,20 +2637,20 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
}
if (cm->can_ac3_hw) {
kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm);
+ kctl->id.device = pcm_spdif_device;
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
- kctl->id.device = pcm_spdif_device;
kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm);
+ kctl->id.device = pcm_spdif_device;
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
- kctl->id.device = pcm_spdif_device;
kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm);
+ kctl->id.device = pcm_spdif_device;
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
- kctl->id.device = pcm_spdif_device;
}
if (cm->chip_version <= 37) {
sw = snd_cmipci_old_mixer_switches;
@@ -2734,12 +2683,8 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
}
for (idx = 0; idx < CM_SAVED_MIXERS; idx++) {
- struct snd_ctl_elem_id elem_id;
struct snd_kcontrol *ctl;
- memset(&elem_id, 0, sizeof(elem_id));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(elem_id.name, cm_saved_mixer[idx].name);
- ctl = snd_ctl_find_id(cm->card, &elem_id);
+ ctl = snd_ctl_find_id_mixer(cm->card, cm_saved_mixer[idx].name);
if (ctl)
cm->mixer_res_ctl[idx] = ctl;
}
@@ -3000,7 +2945,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
cm->channel[1].ch = 1;
cm->channel[0].is_dac = cm->channel[1].is_dac = 1; /* dual DAC mode */
- err = pci_request_regions(pci, card->driver);
+ err = pcim_request_all_regions(pci, card->driver);
if (err < 0)
return err;
cm->iobase = pci_resource_start(pci, 0);
@@ -3028,11 +2973,12 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
pci->device != PCI_DEVICE_ID_CMEDIA_CM8338B)
query_chip(cm);
/* added -MCx suffix for chip supporting multi-channels */
- if (cm->can_multi_ch)
- sprintf(cm->card->driver + strlen(cm->card->driver),
- "-MC%d", cm->max_channels);
- else if (cm->can_ac3_sw)
- strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
+ if (cm->can_multi_ch) {
+ int l = strlen(cm->card->driver);
+ scnprintf(cm->card->driver + l, sizeof(cm->card->driver) - l,
+ "-MC%d", cm->max_channels);
+ } else if (cm->can_ac3_sw)
+ strlcat(cm->card->driver, "-SWIEC", sizeof(cm->card->driver));
cm->dig_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
cm->dig_pcm_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
@@ -3104,13 +3050,15 @@ 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)
- sprintf(modelstr, " (model %d)", cm->chip_version);
+ scnprintf(modelstr, sizeof(modelstr),
+ " (model %d)", cm->chip_version);
else
modelstr[0] = '\0';
- sprintf(card->longname, "%s%s at %#lx, irq %i",
- card->shortname, modelstr, cm->iobase, cm->irq);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s%s at %#lx, irq %i",
+ card->shortname, modelstr, cm->iobase, cm->irq);
if (cm->chip_version >= 39) {
val = snd_cmipci_read_b(cm, CM_REG_MPU_PCI + 1);
@@ -3234,14 +3182,14 @@ static int snd_cmipci_probe(struct pci_dev *pci,
switch (pci->device) {
case PCI_DEVICE_ID_CMEDIA_CM8738:
case PCI_DEVICE_ID_CMEDIA_CM8738B:
- strcpy(card->driver, "CMI8738");
+ strscpy(card->driver, "CMI8738");
break;
case PCI_DEVICE_ID_CMEDIA_CM8338A:
case PCI_DEVICE_ID_CMEDIA_CM8338B:
- strcpy(card->driver, "CMI8338");
+ strscpy(card->driver, "CMI8338");
break;
default:
- strcpy(card->driver, "CMIPCI");
+ strscpy(card->driver, "CMIPCI");
break;
}
@@ -3262,7 +3210,6 @@ static int snd_cmipci_probe(struct pci_dev *pci,
return err;
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -3326,18 +3273,14 @@ static int snd_cmipci_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
-#define SND_CMIPCI_PM_OPS &snd_cmipci_pm
-#else
-#define SND_CMIPCI_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
static struct pci_driver cmipci_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cmipci_ids,
.probe = snd_cmipci_probe,
.driver = {
- .pm = SND_CMIPCI_PM_OPS,
+ .pm = &snd_cmipci_pm,
},
};
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 0c9cadf7b3b8..d00b2c9fb1e3 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -470,10 +470,7 @@ struct cs4281 {
struct gameport *gameport;
-#ifdef CONFIG_PM_SLEEP
u32 suspend_regs[SUSPEND_REGISTERS];
-#endif
-
};
static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
@@ -654,7 +651,7 @@ static int snd_cs4281_trigger(struct snd_pcm_substream *substream, int cmd)
struct cs4281_dma *dma = substream->runtime->private_data;
struct cs4281 *chip = snd_pcm_substream_chip(substream);
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dma->valDCR |= BA0_DCR_MSK;
@@ -681,13 +678,11 @@ static int snd_cs4281_trigger(struct snd_pcm_substream *substream, int cmd)
dma->valFCR &= ~BA0_FCR_FEN;
break;
default:
- spin_unlock(&chip->reg_lock);
return -EINVAL;
}
snd_cs4281_pokeBA0(chip, dma->regDMR, dma->valDMR);
snd_cs4281_pokeBA0(chip, dma->regFCR, dma->valFCR);
snd_cs4281_pokeBA0(chip, dma->regDCR, dma->valDCR);
- spin_unlock(&chip->reg_lock);
return 0;
}
@@ -785,9 +780,8 @@ static int snd_cs4281_playback_prepare(struct snd_pcm_substream *substream)
struct cs4281_dma *dma = runtime->private_data;
struct cs4281 *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_cs4281_mode(chip, dma, runtime, 0, 1);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -797,9 +791,8 @@ static int snd_cs4281_capture_prepare(struct snd_pcm_substream *substream)
struct cs4281_dma *dma = runtime->private_data;
struct cs4281 *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_cs4281_mode(chip, dma, runtime, 1, 1);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -953,7 +946,7 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, "CS4281");
+ strscpy(pcm->name, "CS4281");
chip->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
@@ -1305,14 +1298,15 @@ static int snd_cs4281_create(struct snd_card *card,
}
chip->dual_codec = dual_codec;
- err = pcim_iomap_regions(pci, 0x03, "CS4281"); /* 2 BARs */
- if (err < 0)
- return err;
+ chip->ba0 = pcim_iomap_region(pci, 0, "CS4281");
+ if (IS_ERR(chip->ba0))
+ return PTR_ERR(chip->ba0);
chip->ba0_addr = pci_resource_start(pci, 0);
- chip->ba1_addr = pci_resource_start(pci, 1);
- chip->ba0 = pcim_iomap_table(pci)[0];
- chip->ba1 = pcim_iomap_table(pci)[1];
+ chip->ba1 = pcim_iomap_region(pci, 1, "CS4281");
+ if (IS_ERR(chip->ba1))
+ return PTR_ERR(chip->ba1);
+ chip->ba1_addr = pci_resource_start(pci, 1);
if (devm_request_irq(&pci->dev, pci->irq, snd_cs4281_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1582,7 +1576,7 @@ static int snd_cs4281_midi_input_open(struct snd_rawmidi_substream *substream)
{
struct cs4281 *chip = substream->rmidi->private_data;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->midcr |= BA0_MIDCR_RXE;
chip->midi_input = substream;
if (!(chip->uartm & CS4281_MODE_OUTPUT)) {
@@ -1590,7 +1584,6 @@ static int snd_cs4281_midi_input_open(struct snd_rawmidi_substream *substream)
} else {
snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1598,7 +1591,7 @@ static int snd_cs4281_midi_input_close(struct snd_rawmidi_substream *substream)
{
struct cs4281 *chip = substream->rmidi->private_data;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->midcr &= ~(BA0_MIDCR_RXE | BA0_MIDCR_RIE);
chip->midi_input = NULL;
if (!(chip->uartm & CS4281_MODE_OUTPUT)) {
@@ -1607,7 +1600,6 @@ static int snd_cs4281_midi_input_close(struct snd_rawmidi_substream *substream)
snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
chip->uartm &= ~CS4281_MODE_INPUT;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1615,7 +1607,7 @@ static int snd_cs4281_midi_output_open(struct snd_rawmidi_substream *substream)
{
struct cs4281 *chip = substream->rmidi->private_data;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->uartm |= CS4281_MODE_OUTPUT;
chip->midcr |= BA0_MIDCR_TXE;
chip->midi_output = substream;
@@ -1624,7 +1616,6 @@ static int snd_cs4281_midi_output_open(struct snd_rawmidi_substream *substream)
} else {
snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1632,7 +1623,7 @@ static int snd_cs4281_midi_output_close(struct snd_rawmidi_substream *substream)
{
struct cs4281 *chip = substream->rmidi->private_data;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->midcr &= ~(BA0_MIDCR_TXE | BA0_MIDCR_TIE);
chip->midi_output = NULL;
if (!(chip->uartm & CS4281_MODE_INPUT)) {
@@ -1641,16 +1632,14 @@ static int snd_cs4281_midi_output_close(struct snd_rawmidi_substream *substream)
snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
chip->uartm &= ~CS4281_MODE_OUTPUT;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
static void snd_cs4281_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct cs4281 *chip = substream->rmidi->private_data;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (up) {
if ((chip->midcr & BA0_MIDCR_RIE) == 0) {
chip->midcr |= BA0_MIDCR_RIE;
@@ -1662,16 +1651,14 @@ static void snd_cs4281_midi_input_trigger(struct snd_rawmidi_substream *substrea
snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct cs4281 *chip = substream->rmidi->private_data;
unsigned char byte;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (up) {
if ((chip->midcr & BA0_MIDCR_TIE) == 0) {
chip->midcr |= BA0_MIDCR_TIE;
@@ -1692,7 +1679,6 @@ static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substre
snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static const struct snd_rawmidi_ops snd_cs4281_midi_output =
@@ -1717,7 +1703,7 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device)
err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi);
if (err < 0)
return err;
- strcpy(rmidi->name, "CS4281");
+ strscpy(rmidi->name, "CS4281");
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs4281_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_cs4281_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -1745,10 +1731,12 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
}
if (status & (BA0_HISR_DMA(0)|BA0_HISR_DMA(1)|BA0_HISR_DMA(2)|BA0_HISR_DMA(3))) {
- for (dma = 0; dma < 4; dma++)
+ for (dma = 0; dma < 4; dma++) {
+ bool period_elapsed = false;
+ cdma = &chip->dma[dma];
+
if (status & BA0_HISR_DMA(dma)) {
- cdma = &chip->dma[dma];
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
/* ack DMA IRQ */
val = snd_cs4281_peekBA0(chip, cdma->regHDSR);
/* workaround, sometimes CS4281 acknowledges */
@@ -1757,24 +1745,24 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
if ((val & BA0_HDSR_DHTC) && !(cdma->frag & 1)) {
cdma->frag--;
chip->spurious_dhtc_irq++;
- spin_unlock(&chip->reg_lock);
continue;
}
if ((val & BA0_HDSR_DTC) && (cdma->frag & 1)) {
cdma->frag--;
chip->spurious_dtc_irq++;
- spin_unlock(&chip->reg_lock);
continue;
}
- spin_unlock(&chip->reg_lock);
- snd_pcm_period_elapsed(cdma->substream);
+ period_elapsed = true;
}
+ if (period_elapsed)
+ snd_pcm_period_elapsed(cdma->substream);
+ }
}
if ((status & BA0_HISR_MIDI) && chip->rmidi) {
unsigned char c;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_RBE) == 0) {
c = snd_cs4281_peekBA0(chip, BA0_MIDRP);
if ((chip->midcr & BA0_MIDCR_RIE) == 0)
@@ -1791,7 +1779,6 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
}
snd_cs4281_pokeBA0(chip, BA0_MIDWP, c);
}
- spin_unlock(&chip->reg_lock);
}
/* EOI to the PCI part... reenables interrupts */
@@ -1807,7 +1794,6 @@ static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd,
unsigned char val)
{
- unsigned long flags;
struct cs4281 *chip = opl3->private_data;
void __iomem *port;
@@ -1816,15 +1802,13 @@ static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd,
else
port = chip->ba0 + BA0_B0AP; /* left port */
- spin_lock_irqsave(&opl3->reg_lock, flags);
+ guard(spinlock_irqsave)(&opl3->reg_lock);
writel((unsigned int)cmd, port);
udelay(10);
writel((unsigned int)val, port + 4);
udelay(30);
-
- spin_unlock_irqrestore(&opl3->reg_lock, flags);
}
static int __snd_cs4281_probe(struct pci_dev *pci,
@@ -1872,8 +1856,8 @@ static int __snd_cs4281_probe(struct pci_dev *pci,
if (err < 0)
return err;
snd_cs4281_create_gameport(chip);
- strcpy(card->driver, "CS4281");
- strcpy(card->shortname, "Cirrus Logic CS4281");
+ strscpy(card->driver, "CS4281");
+ strscpy(card->shortname, "Cirrus Logic CS4281");
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname,
chip->ba0_addr,
@@ -1897,8 +1881,6 @@ static int snd_cs4281_probe(struct pci_dev *pci,
/*
* Power Management
*/
-#ifdef CONFIG_PM_SLEEP
-
static const int saved_regs[SUSPEND_REGISTERS] = {
BA0_JSCTL,
BA0_GPIOR,
@@ -1987,18 +1969,14 @@ static int cs4281_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
-#define CS4281_PM_OPS &cs4281_pm
-#else
-#define CS4281_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
static struct pci_driver cs4281_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cs4281_ids,
.probe = snd_cs4281_probe,
.driver = {
- .pm = CS4281_PM_OPS,
+ .pm = &cs4281_pm,
},
};
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 8634004a606b..9c1995737eb7 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -107,8 +107,8 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
snd_cs46xx_gameport(chip);
- strcpy(card->driver, "CS46xx");
- strcpy(card->shortname, "Sound Fusion CS46xx");
+ strscpy(card->driver, "CS46xx");
+ strscpy(card->shortname, "Sound Fusion CS46xx");
sprintf(card->longname, "%s at 0x%lx/0x%lx, irq %i",
card->shortname,
chip->ba0_addr,
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 7d882b33d45e..b96ab7fd464c 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -707,7 +707,6 @@ static void snd_cs46xx_proc_stop(struct snd_cs46xx *chip)
static void snd_cs46xx_set_play_sample_rate(struct snd_cs46xx *chip, unsigned int rate)
{
- unsigned long flags;
unsigned int tmp1, tmp2;
unsigned int phiIncr;
unsigned int correctionPerGOF, correctionPerSec;
@@ -744,16 +743,14 @@ static void snd_cs46xx_set_play_sample_rate(struct snd_cs46xx *chip, unsigned in
/*
* Fill in the SampleRateConverter control block.
*/
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_cs46xx_poke(chip, BA1_PSRC,
((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
snd_cs46xx_poke(chip, BA1_PPI, phiIncr);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned int rate)
{
- unsigned long flags;
unsigned int phiIncr, coeffIncr, tmp1, tmp2;
unsigned int correctionPerGOF, correctionPerSec, initialDelay;
unsigned int frameGroupLength, cnt;
@@ -818,14 +815,14 @@ static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned
/*
* Fill in the VariDecimate control block.
*/
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs46xx_poke(chip, BA1_CSRC,
- ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
- snd_cs46xx_poke(chip, BA1_CCI, coeffIncr);
- snd_cs46xx_poke(chip, BA1_CD,
- (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
- snd_cs46xx_poke(chip, BA1_CPI, phiIncr);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_cs46xx_poke(chip, BA1_CSRC,
+ ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
+ snd_cs46xx_poke(chip, BA1_CCI, coeffIncr);
+ snd_cs46xx_poke(chip, BA1_CD,
+ (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
+ snd_cs46xx_poke(chip, BA1_CPI, phiIncr);
+ }
/*
* Figure out the frame group length for the write back task. Basically,
@@ -848,13 +845,12 @@ static void snd_cs46xx_set_capture_sample_rate(struct snd_cs46xx *chip, unsigned
/*
* Fill in the WriteBack control block.
*/
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_cs46xx_poke(chip, BA1_CFG1, frameGroupLength);
snd_cs46xx_poke(chip, BA1_CFG2, (0x00800000 | frameGroupLength));
snd_cs46xx_poke(chip, BA1_CCST, 0x0000FFFF);
snd_cs46xx_poke(chip, BA1_CSPB, ((65536 * rate) / 24000));
snd_cs46xx_poke(chip, (BA1_CSPB + 4), 0x0000FFFF);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
/*
@@ -969,15 +965,14 @@ static int snd_cs46xx_playback_trigger(struct snd_pcm_substream *substream,
if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream);
#else
- spin_lock(&chip->reg_lock);
- if (substream->runtime->periods != CS46XX_FRAGS)
- snd_cs46xx_playback_transfer(substream);
- { unsigned int tmp;
- tmp = snd_cs46xx_peek(chip, BA1_PCTL);
- tmp &= 0x0000ffff;
- snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ unsigned int tmp;
+ if (substream->runtime->periods != CS46XX_FRAGS)
+ snd_cs46xx_playback_transfer(substream);
+ tmp = snd_cs46xx_peek(chip, BA1_PCTL);
+ tmp &= 0x0000ffff;
+ snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp);
}
- spin_unlock(&chip->reg_lock);
#endif
break;
case SNDRV_PCM_TRIGGER_STOP:
@@ -990,13 +985,12 @@ static int snd_cs46xx_playback_trigger(struct snd_pcm_substream *substream,
if (!cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
#else
- spin_lock(&chip->reg_lock);
- { unsigned int tmp;
- tmp = snd_cs46xx_peek(chip, BA1_PCTL);
- tmp &= 0x0000ffff;
- snd_cs46xx_poke(chip, BA1_PCTL, tmp);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ unsigned int tmp;
+ tmp = snd_cs46xx_peek(chip, BA1_PCTL);
+ tmp &= 0x0000ffff;
+ snd_cs46xx_poke(chip, BA1_PCTL, tmp);
}
- spin_unlock(&chip->reg_lock);
#endif
break;
default:
@@ -1012,9 +1006,8 @@ static int snd_cs46xx_capture_trigger(struct snd_pcm_substream *substream,
{
struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
unsigned int tmp;
- int result = 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -1029,12 +1022,9 @@ static int snd_cs46xx_capture_trigger(struct snd_pcm_substream *substream,
snd_cs46xx_poke(chip, BA1_CCTL, tmp);
break;
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
-
- return result;
+ return 0;
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -1093,24 +1083,17 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
if (snd_BUG_ON(!sample_rate))
return -ENXIO;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
- if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
- mutex_unlock(&chip->spos_mutex);
+ if (_cs46xx_adjust_sample_rate(chip, cpcm, sample_rate))
return -ENXIO;
- }
snd_BUG_ON(!cpcm->pcm_channel);
- if (!cpcm->pcm_channel) {
- mutex_unlock(&chip->spos_mutex);
+ if (!cpcm->pcm_channel)
return -ENXIO;
- }
-
- if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) {
- mutex_unlock(&chip->spos_mutex);
+ if (cs46xx_dsp_pcm_channel_set_period(chip, cpcm->pcm_channel, period_size))
return -EINVAL;
- }
dev_dbg(chip->card->dev,
"period_size (%d), periods (%d) buffer_size(%d)\n",
@@ -1144,12 +1127,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
if (runtime->dma_area == cpcm->hw_buf.area)
snd_pcm_set_runtime_buffer(substream, NULL);
err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
- if (err < 0) {
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
- mutex_unlock(&chip->spos_mutex);
-#endif
+ if (err < 0)
return err;
- }
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
@@ -1169,10 +1148,6 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
}
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
- mutex_unlock(&chip->spos_mutex);
-#endif
-
return 0;
}
@@ -1386,7 +1361,7 @@ static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id)
if ((status1 & HISR_MIDI) && chip->rmidi) {
unsigned char c;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) {
c = snd_cs46xx_peekBA0(chip, BA0_MIDRP);
if ((chip->midcr & MIDCR_RIE) == 0)
@@ -1403,7 +1378,6 @@ static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id)
}
snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c);
}
- spin_unlock(&chip->reg_lock);
}
/*
* EOI to the PCI part....reenables interrupts
@@ -1495,16 +1469,14 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in
cpcm->substream = substream;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- mutex_lock(&chip->spos_mutex);
- cpcm->pcm_channel = NULL;
- cpcm->pcm_channel_id = pcm_channel_id;
-
+ scoped_guard(mutex, &chip->spos_mutex) {
+ cpcm->pcm_channel = NULL;
+ cpcm->pcm_channel_id = pcm_channel_id;
+ }
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
&hw_constraints_period_sizes);
-
- mutex_unlock(&chip->spos_mutex);
#else
chip->playback_pcm = cpcm; /* HACK */
#endif
@@ -1541,9 +1513,9 @@ static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream)
dev_dbg(chip->card->dev, "open raw iec958 channel\n");
- mutex_lock(&chip->spos_mutex);
- cs46xx_iec958_pre_open (chip);
- mutex_unlock(&chip->spos_mutex);
+ scoped_guard(mutex, &chip->spos_mutex) {
+ cs46xx_iec958_pre_open(chip);
+ }
return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);
}
@@ -1559,9 +1531,9 @@ static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream)
err = snd_cs46xx_playback_close(substream);
- mutex_lock(&chip->spos_mutex);
- cs46xx_iec958_post_close (chip);
- mutex_unlock(&chip->spos_mutex);
+ scoped_guard(mutex, &chip->spos_mutex) {
+ cs46xx_iec958_post_close(chip);
+ }
return err;
}
@@ -1602,12 +1574,12 @@ static int snd_cs46xx_playback_close(struct snd_pcm_substream *substream)
if (!cpcm) return -ENXIO;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- mutex_lock(&chip->spos_mutex);
- if (cpcm->pcm_channel) {
- cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel);
- cpcm->pcm_channel = NULL;
+ scoped_guard(mutex, &chip->spos_mutex) {
+ if (cpcm->pcm_channel) {
+ cs46xx_dsp_destroy_pcm_channel(chip, cpcm->pcm_channel);
+ cpcm->pcm_channel = NULL;
+ }
}
- mutex_unlock(&chip->spos_mutex);
#else
chip->playback_pcm = NULL;
#endif
@@ -1760,7 +1732,7 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "CS46xx");
+ strscpy(pcm->name, "CS46xx");
chip->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1787,7 +1759,7 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "CS46xx - Rear");
+ strscpy(pcm->name, "CS46xx - Rear");
chip->pcm_rear = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1812,7 +1784,7 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "CS46xx - Center LFE");
+ strscpy(pcm->name, "CS46xx - Center LFE");
chip->pcm_center_lfe = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1837,7 +1809,7 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "CS46xx - IEC958");
+ strscpy(pcm->name, "CS46xx - IEC958");
chip->pcm_iec958 = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1982,15 +1954,15 @@ static int snd_cs46xx_iec958_put(struct snd_kcontrol *kcontrol,
switch (kcontrol->private_value) {
case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT:
- mutex_lock(&chip->spos_mutex);
- change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
- if (ucontrol->value.integer.value[0] && !change)
- cs46xx_dsp_enable_spdif_out(chip);
- else if (change && !ucontrol->value.integer.value[0])
- cs46xx_dsp_disable_spdif_out(chip);
-
- res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
- mutex_unlock(&chip->spos_mutex);
+ scoped_guard(mutex, &chip->spos_mutex) {
+ change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
+ if (ucontrol->value.integer.value[0] && !change)
+ cs46xx_dsp_enable_spdif_out(chip);
+ else if (change && !ucontrol->value.integer.value[0])
+ cs46xx_dsp_disable_spdif_out(chip);
+
+ res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
+ }
break;
case CS46XX_MIXER_SPDIF_INPUT_ELEMENT:
change = chip->dsp_spos_instance->spdif_status_in;
@@ -2131,12 +2103,11 @@ static int snd_cs46xx_spdif_default_get(struct snd_kcontrol *kcontrol,
struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff);
ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff);
ucontrol->value.iec958.status[2] = 0;
ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff);
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -2149,7 +2120,7 @@ static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol,
unsigned int val;
int change;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) |
((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[2]) << 16) |
((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) |
@@ -2163,8 +2134,6 @@ static int snd_cs46xx_spdif_default_put(struct snd_kcontrol *kcontrol,
if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) )
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
- mutex_unlock(&chip->spos_mutex);
-
return change;
}
@@ -2184,12 +2153,11 @@ static int snd_cs46xx_spdif_stream_get(struct snd_kcontrol *kcontrol,
struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff);
ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff);
ucontrol->value.iec958.status[2] = 0;
ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff);
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -2202,7 +2170,7 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol,
unsigned int val;
int change;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) |
((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[1]) << 16) |
((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) |
@@ -2216,8 +2184,6 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol,
if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN )
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
- mutex_unlock(&chip->spos_mutex);
-
return change;
}
@@ -2449,7 +2415,6 @@ static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec)
int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
{
struct snd_card *card = chip->card;
- struct snd_ctl_elem_id id;
int err;
unsigned int idx;
static const struct snd_ac97_bus_ops ops = {
@@ -2490,10 +2455,8 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
}
/* get EAPD mixer switch (for voyetra hack) */
- memset(&id, 0, sizeof(id));
- id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id.name, "External Amplifier");
- chip->eapd_switch = snd_ctl_find_id(chip->card, &id);
+ chip->eapd_switch = snd_ctl_find_id_mixer(chip->card,
+ "External Amplifier");
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (chip->nr_ac97_codecs == 1) {
@@ -2535,7 +2498,7 @@ static int snd_cs46xx_midi_input_open(struct snd_rawmidi_substream *substream)
struct snd_cs46xx *chip = substream->rmidi->private_data;
chip->active_ctrl(chip, 1);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->uartm |= CS46XX_MODE_INPUT;
chip->midcr |= MIDCR_RXE;
chip->midi_input = substream;
@@ -2544,7 +2507,6 @@ static int snd_cs46xx_midi_input_open(struct snd_rawmidi_substream *substream)
} else {
snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -2552,16 +2514,16 @@ static int snd_cs46xx_midi_input_close(struct snd_rawmidi_substream *substream)
{
struct snd_cs46xx *chip = substream->rmidi->private_data;
- spin_lock_irq(&chip->reg_lock);
- chip->midcr &= ~(MIDCR_RXE | MIDCR_RIE);
- chip->midi_input = NULL;
- if (!(chip->uartm & CS46XX_MODE_OUTPUT)) {
- snd_cs46xx_midi_reset(chip);
- } else {
- snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ chip->midcr &= ~(MIDCR_RXE | MIDCR_RIE);
+ chip->midi_input = NULL;
+ if (!(chip->uartm & CS46XX_MODE_OUTPUT)) {
+ snd_cs46xx_midi_reset(chip);
+ } else {
+ snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
+ }
+ chip->uartm &= ~CS46XX_MODE_INPUT;
}
- chip->uartm &= ~CS46XX_MODE_INPUT;
- spin_unlock_irq(&chip->reg_lock);
chip->active_ctrl(chip, -1);
return 0;
}
@@ -2572,7 +2534,7 @@ static int snd_cs46xx_midi_output_open(struct snd_rawmidi_substream *substream)
chip->active_ctrl(chip, 1);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->uartm |= CS46XX_MODE_OUTPUT;
chip->midcr |= MIDCR_TXE;
chip->midi_output = substream;
@@ -2581,7 +2543,6 @@ static int snd_cs46xx_midi_output_open(struct snd_rawmidi_substream *substream)
} else {
snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -2589,26 +2550,25 @@ static int snd_cs46xx_midi_output_close(struct snd_rawmidi_substream *substream)
{
struct snd_cs46xx *chip = substream->rmidi->private_data;
- spin_lock_irq(&chip->reg_lock);
- chip->midcr &= ~(MIDCR_TXE | MIDCR_TIE);
- chip->midi_output = NULL;
- if (!(chip->uartm & CS46XX_MODE_INPUT)) {
- snd_cs46xx_midi_reset(chip);
- } else {
- snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ chip->midcr &= ~(MIDCR_TXE | MIDCR_TIE);
+ chip->midi_output = NULL;
+ if (!(chip->uartm & CS46XX_MODE_INPUT)) {
+ snd_cs46xx_midi_reset(chip);
+ } else {
+ snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
+ }
+ chip->uartm &= ~CS46XX_MODE_OUTPUT;
}
- chip->uartm &= ~CS46XX_MODE_OUTPUT;
- spin_unlock_irq(&chip->reg_lock);
chip->active_ctrl(chip, -1);
return 0;
}
static void snd_cs46xx_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct snd_cs46xx *chip = substream->rmidi->private_data;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (up) {
if ((chip->midcr & MIDCR_RIE) == 0) {
chip->midcr |= MIDCR_RIE;
@@ -2620,16 +2580,14 @@ static void snd_cs46xx_midi_input_trigger(struct snd_rawmidi_substream *substrea
snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct snd_cs46xx *chip = substream->rmidi->private_data;
unsigned char byte;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (up) {
if ((chip->midcr & MIDCR_TIE) == 0) {
chip->midcr |= MIDCR_TIE;
@@ -2650,7 +2608,6 @@ static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substre
snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static const struct snd_rawmidi_ops snd_cs46xx_midi_output =
@@ -2675,7 +2632,7 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device)
err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi);
if (err < 0)
return err;
- strcpy(rmidi->name, "CS46XX");
+ strscpy(rmidi->name, "CS46XX");
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs46xx_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_cs46xx_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -3842,7 +3799,7 @@ int snd_cs46xx_create(struct snd_card *card,
chip->pci = pci;
chip->irq = -1;
- err = pci_request_regions(pci, "CS46xx");
+ err = pcim_request_all_regions(pci, "CS46xx");
if (err < 0)
return err;
chip->ba0_addr = pci_resource_start(pci, 0);
@@ -3856,27 +3813,27 @@ int snd_cs46xx_create(struct snd_card *card,
}
region = &chip->region.name.ba0;
- strcpy(region->name, "CS46xx_BA0");
+ strscpy(region->name, "CS46xx_BA0");
region->base = chip->ba0_addr;
region->size = CS46XX_BA0_SIZE;
region = &chip->region.name.data0;
- strcpy(region->name, "CS46xx_BA1_data0");
+ strscpy(region->name, "CS46xx_BA1_data0");
region->base = chip->ba1_addr + BA1_SP_DMEM0;
region->size = CS46XX_BA1_DATA0_SIZE;
region = &chip->region.name.data1;
- strcpy(region->name, "CS46xx_BA1_data1");
+ strscpy(region->name, "CS46xx_BA1_data1");
region->base = chip->ba1_addr + BA1_SP_DMEM1;
region->size = CS46XX_BA1_DATA1_SIZE;
region = &chip->region.name.pmem;
- strcpy(region->name, "CS46xx_BA1_pmem");
+ strscpy(region->name, "CS46xx_BA1_pmem");
region->base = chip->ba1_addr + BA1_SP_PMEM;
region->size = CS46XX_BA1_PRG_SIZE;
region = &chip->region.name.reg;
- strcpy(region->name, "CS46xx_BA1_reg");
+ strscpy(region->name, "CS46xx_BA1_reg");
region->base = chip->ba1_addr + BA1_SP_REG;
region->size = CS46XX_BA1_REG_SIZE;
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 1db6bc58d6a6..3d34575a0e8f 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -203,7 +203,7 @@ add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type)
index = find_free_symbol_index (ins);
- strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
+ strscpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
ins->symbol_table.symbols[index].address = address;
ins->symbol_table.symbols[index].symbol_type = type;
ins->symbol_table.symbols[index].module = NULL;
@@ -283,7 +283,7 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
if (snd_BUG_ON(!ins))
return;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
for (i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted) continue;
@@ -297,7 +297,6 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
vfree(ins->symbol_table.symbols);
kfree(ins->modules);
kfree(ins);
- mutex_unlock(&chip->spos_mutex);
}
static int dsp_load_parameter(struct snd_cs46xx *chip,
@@ -525,7 +524,7 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry,
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
int i,j;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
snd_iprintf(buffer, "MODULES:\n");
for ( i = 0; i < ins->nmodules; ++i ) {
snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
@@ -538,7 +537,6 @@ static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry,
desc->segment_type,desc->offset, desc->size);
}
}
- mutex_unlock(&chip->spos_mutex);
}
static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
@@ -549,7 +547,7 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
int i, j, col;
void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
snd_iprintf(buffer, "TASK TREES:\n");
for ( i = 0; i < ins->ntask; ++i) {
snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
@@ -566,7 +564,6 @@ static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
}
snd_iprintf(buffer,"\n");
- mutex_unlock(&chip->spos_mutex);
}
static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
@@ -576,7 +573,7 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
int i;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
snd_iprintf(buffer, "SCB's:\n");
for ( i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted)
@@ -599,7 +596,6 @@ static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
}
snd_iprintf(buffer,"\n");
- mutex_unlock(&chip->spos_mutex);
}
static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry,
@@ -831,14 +827,13 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
snd_info_set_text_ops(entry, chip,
cs46xx_dsp_proc_scb_read);
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
/* register/update SCB's entries on proc */
for (i = 0; i < ins->nscb; ++i) {
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
}
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -851,12 +846,13 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
if (!ins)
return 0;
- mutex_lock(&chip->spos_mutex);
- for (i = 0; i < ins->nscb; ++i) {
- if (ins->scbs[i].deleted) continue;
- cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
+ scoped_guard(mutex, &chip->spos_mutex) {
+ for (i = 0; i < ins->nscb; ++i) {
+ if (ins->scbs[i].deleted)
+ continue;
+ cs46xx_dsp_proc_free_scb_desc((ins->scbs + i));
+ }
}
- mutex_unlock(&chip->spos_mutex);
snd_info_free_entry(ins->proc_dsp_dir);
ins->proc_dsp_dir = NULL;
@@ -923,7 +919,7 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam
index = find_free_scb_index (ins);
memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
- strcpy(ins->scbs[index].scb_name, name);
+ strscpy(ins->scbs[index].scb_name, name);
ins->scbs[index].address = dest;
ins->scbs[index].index = index;
ins->scbs[index].ref_count = 1;
@@ -953,9 +949,9 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
}
if (name)
- strcpy(ins->tasks[ins->ntask].task_name, name);
+ strscpy(ins->tasks[ins->ntask].task_name, name);
else
- strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
+ strscpy(ins->tasks[ins->ntask].task_name, "(NULL)");
ins->tasks[ins->ntask].address = dest;
ins->tasks[ins->ntask].size = size;
@@ -1677,7 +1673,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
if (snd_BUG_ON(!ins->spdif_in_src))
return -EINVAL;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
/* time countdown enable */
@@ -1700,7 +1696,7 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
ins->spdif_in_src,
SCB_ON_PARENT_SUBLIST_SCB);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
/* reset SPDIF input sample buffer pointer */
/*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
@@ -1713,15 +1709,12 @@ int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
/* unmute SRC volume */
cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff);
- spin_unlock_irq(&chip->reg_lock);
-
/* set SPDIF input sample rate and unmute
NOTE: only 48khz support for SPDIF input this time */
/* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
/* monitor state */
ins->spdif_status_in = 1;
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -1735,17 +1728,16 @@ int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip)
if (snd_BUG_ON(!ins->spdif_in_src))
return -EINVAL;
- mutex_lock(&chip->spos_mutex);
+ scoped_guard(mutex, &chip->spos_mutex) {
+ /* Remove the asynchronous receiver SCB */
+ cs46xx_dsp_remove_scb(chip, ins->asynch_rx_scb);
+ ins->asynch_rx_scb = NULL;
- /* Remove the asynchronous receiver SCB */
- cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
- ins->asynch_rx_scb = NULL;
+ cs46xx_src_unlink(chip, ins->spdif_in_src);
- cs46xx_src_unlink(chip,ins->spdif_in_src);
-
- /* monitor state */
- ins->spdif_status_in = 0;
- mutex_unlock(&chip->spos_mutex);
+ /* monitor state */
+ ins->spdif_status_in = 0;
+ }
/* restore amplifier */
chip->active_ctrl(chip, -1);
@@ -1763,10 +1755,9 @@ int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip)
if (snd_BUG_ON(!ins->ref_snoop_scb))
return -EINVAL;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
"PCMSerialInput_Wave");
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -1778,10 +1769,9 @@ int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip)
if (snd_BUG_ON(!ins->pcm_input))
return -EINVAL;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
cs46xx_dsp_remove_scb (chip,ins->pcm_input);
ins->pcm_input = NULL;
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -1795,10 +1785,9 @@ int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip)
if (snd_BUG_ON(!ins->codec_in_scb))
return -EINVAL;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
"PCMSerialInput_ADC");
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -1810,10 +1799,9 @@ int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip)
if (snd_BUG_ON(!ins->adc_input))
return -EINVAL;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
cs46xx_dsp_remove_scb (chip,ins->adc_input);
ins->adc_input = NULL;
- mutex_unlock(&chip->spos_mutex);
return 0;
}
@@ -1861,7 +1849,7 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right)
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
struct dsp_scb_descriptor * scb;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
/* main output */
scb = ins->master_mix_scb->sub_list_ptr;
@@ -1880,8 +1868,6 @@ int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right)
ins->dac_volume_left = left;
ins->dac_volume_right = right;
- mutex_unlock(&chip->spos_mutex);
-
return 0;
}
@@ -1889,7 +1875,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
if (ins->asynch_rx_scb != NULL)
cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
@@ -1898,8 +1884,6 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
ins->spdif_input_volume_left = left;
ins->spdif_input_volume_right = right;
- mutex_unlock(&chip->spos_mutex);
-
return 0;
}
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 1f90ca723f4d..32ed415bf427 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -63,7 +63,7 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
int j,col;
void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
- mutex_lock(&chip->spos_mutex);
+ guard(mutex)(&chip->spos_mutex);
snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
for (col = 0,j = 0;j < 0x10; j++,col++) {
@@ -91,7 +91,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
scb->task_entry->address);
snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
- mutex_unlock(&chip->spos_mutex);
}
#endif
@@ -160,7 +159,6 @@ static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer
void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
- unsigned long flags;
/* check integrety */
if (snd_BUG_ON(scb->index < 0 ||
@@ -176,9 +174,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
goto _end;
#endif
- spin_lock_irqsave(&chip->reg_lock, flags);
- _dsp_unlink_scb (chip,scb);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ _dsp_unlink_scb(chip, scb);
+ }
cs46xx_dsp_proc_free_scb_desc(scb);
if (snd_BUG_ON(!scb->scb_symbol))
@@ -201,13 +199,6 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
if (ins->scb_highest_frag_index > ins->nscb) {
ins->scb_highest_frag_index = ins->nscb;
}
-
-#if 0
- /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
- for(i = scb->index + 1;i < ins->nscb; ++i) {
- ins->scbs[i - 1].index = i - 1;
- }
-#endif
}
@@ -270,8 +261,6 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
struct dsp_scb_descriptor * scb;
- unsigned long flags;
-
if (snd_BUG_ON(!ins->the_null_scb))
return NULL;
@@ -325,12 +314,10 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
snd_BUG();
}
- spin_lock_irqsave(&chip->reg_lock, flags);
-
- /* update entry in DSP RAM */
- cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
-
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ /* update entry in DSP RAM */
+ cs46xx_dsp_spos_update_scb(chip, scb->parent_scb_ptr);
+ }
}
@@ -1227,7 +1214,6 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
/* struct dsp_scb_descriptor * pcm_parent_scb; */
char scb_name[DSP_MAX_SCB_NAME];
int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
- unsigned long flags;
switch (pcm_channel_id) {
case DSP_PCM_MAIN_CHANNEL:
@@ -1364,7 +1350,7 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
return NULL;
}
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
ins->pcm_channels[pcm_index].sample_rate = sample_rate;
ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
ins->pcm_channels[pcm_index].src_scb = src_scb;
@@ -1375,7 +1361,6 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
ins->npcm_channels ++;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return (ins->pcm_channels + pcm_index);
}
@@ -1463,20 +1448,19 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
struct dsp_pcm_channel_descriptor * pcm_channel)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
- unsigned long flags;
if (snd_BUG_ON(!pcm_channel->active ||
ins->npcm_channels <= 0 ||
pcm_channel->src_scb->ref_count <= 0))
return;
- spin_lock_irqsave(&chip->reg_lock, flags);
- pcm_channel->unlinked = 1;
- pcm_channel->active = 0;
- pcm_channel->private_data = NULL;
- pcm_channel->src_scb->ref_count --;
- ins->npcm_channels --;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ pcm_channel->unlinked = 1;
+ pcm_channel->active = 0;
+ pcm_channel->private_data = NULL;
+ pcm_channel->src_scb->ref_count--;
+ ins->npcm_channels--;
+ }
cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
@@ -1495,22 +1479,17 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
struct dsp_pcm_channel_descriptor * pcm_channel)
{
- unsigned long flags;
-
if (snd_BUG_ON(!pcm_channel->active ||
chip->dsp_spos_instance->npcm_channels <= 0))
return -EIO;
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (pcm_channel->unlinked) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
+ if (pcm_channel->unlinked)
return -EIO;
- }
pcm_channel->unlinked = 1;
_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -1521,14 +1500,11 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
struct dsp_scb_descriptor * parent_scb;
struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
- if (pcm_channel->unlinked == 0) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (pcm_channel->unlinked == 0)
return -EIO;
- }
parent_scb = src_scb;
@@ -1549,7 +1525,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
cs46xx_dsp_spos_update_scb(chip,parent_scb);
pcm_channel->unlinked = 0;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -1582,17 +1557,14 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s
int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
{
- unsigned long flags;
-
if (snd_BUG_ON(!src->parent_scb_ptr))
return -EINVAL;
/* mute SCB */
cs46xx_dsp_scb_set_volume (chip,src,0,0);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
_dsp_unlink_scb (chip,src);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index 93ff029e6583..292b65aa758a 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -91,11 +91,10 @@ static int snd_cs5530_create(struct snd_card *card,
chip->card = card;
chip->pci = pci;
- err = pcim_iomap_regions(pci, 1 << 0, "CS5530");
- if (err < 0)
- return err;
+ mem = pcim_iomap_region(pci, 0, "CS5530");
+ if (IS_ERR(mem))
+ return PTR_ERR(mem);
chip->pci_base = pci_resource_start(pci, 0);
- mem = pcim_iomap_table(pci)[0];
map = readw(mem + 0x18);
/* Map bits
@@ -208,8 +207,8 @@ static int snd_cs5530_probe(struct pci_dev *pci,
if (err < 0)
return err;
- strcpy(card->driver, "CS5530");
- strcpy(card->shortname, "CS5530 Audio");
+ strscpy(card->driver, "CS5530");
+ strscpy(card->shortname, "CS5530 Audio");
sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
err = snd_card_register(card);
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 440b8f9b40c9..0ebf6c02b1ef 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -176,9 +176,10 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
static void process_bm0_irq(struct cs5535audio *cs5535au)
{
u8 bm_stat;
- spin_lock(&cs5535au->reg_lock);
- bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS);
- spin_unlock(&cs5535au->reg_lock);
+
+ scoped_guard(spinlock, &cs5535au->reg_lock) {
+ bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS);
+ }
if (bm_stat & EOP) {
snd_pcm_period_elapsed(cs5535au->playback_substream);
} else {
@@ -191,9 +192,10 @@ static void process_bm0_irq(struct cs5535audio *cs5535au)
static void process_bm1_irq(struct cs5535audio *cs5535au)
{
u8 bm_stat;
- spin_lock(&cs5535au->reg_lock);
- bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS);
- spin_unlock(&cs5535au->reg_lock);
+
+ scoped_guard(spinlock, &cs5535au->reg_lock) {
+ bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS);
+ }
if (bm_stat & EOP)
snd_pcm_period_elapsed(cs5535au->capture_substream);
}
@@ -262,7 +264,7 @@ static int snd_cs5535audio_create(struct snd_card *card,
cs5535au->pci = pci;
cs5535au->irq = -1;
- err = pci_request_regions(pci, "CS5535 Audio");
+ err = pcim_request_all_regions(pci, "CS5535 Audio");
if (err < 0)
return err;
@@ -315,9 +317,9 @@ static int __snd_cs5535audio_probe(struct pci_dev *pci,
if (err < 0)
return err;
- strcpy(card->driver, DRIVER_NAME);
+ strscpy(card->driver, DRIVER_NAME);
- strcpy(card->shortname, "CS5535 Audio");
+ strscpy(card->shortname, "CS5535 Audio");
sprintf(card->longname, "%s %s at 0x%lx, irq %i",
card->shortname, card->driver,
cs5535au->port, cs5535au->irq);
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 9c88e99e3750..48b99a07e3bc 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -150,10 +150,9 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
dma->substream = substream;
dma->period_bytes = period_bytes;
dma->periods = periods;
- spin_lock_irq(&cs5535au->reg_lock);
+ guard(spinlock_irq)(&cs5535au->reg_lock);
dma->ops->disable_dma(cs5535au);
dma->ops->setup_prd(cs5535au, jmpprd_addr);
- spin_unlock_irq(&cs5535au->reg_lock);
return 0;
}
@@ -276,9 +275,8 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
struct cs5535audio_dma *dma = substream->runtime->private_data;
- int err = 0;
- spin_lock(&cs5535au->reg_lock);
+ guard(spinlock)(&cs5535au->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dma->ops->pause_dma(cs5535au);
@@ -300,11 +298,9 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
break;
default:
dev_err(cs5535au->card->dev, "unhandled trigger\n");
- err = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&cs5535au->reg_lock);
- return err;
+ return 0;
}
static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream
@@ -423,7 +419,7 @@ int snd_cs5535audio_pcm(struct cs5535audio *cs5535au)
pcm->private_data = cs5535au;
pcm->info_flags = 0;
- strcpy(pcm->name, "CS5535 Audio");
+ strscpy(pcm->name, "CS5535 Audio");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&cs5535au->pci->dev,
diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile
index 70888706a0af..ff2b1cba3a3c 100644
--- a/sound/pci/ctxfi/Makefile
+++ b/sound/pci/ctxfi/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
+snd-ctxfi-y := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \
cthw20k2.o cthw20k1.o
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
index d074727c3e21..bb4658592636 100644
--- a/sound/pci/ctxfi/ctamixer.c
+++ b/sound/pci/ctxfi/ctamixer.c
@@ -231,7 +231,6 @@ static int get_amixer_rsc(struct amixer_mgr *mgr,
int err, i;
unsigned int idx;
struct amixer *amixer;
- unsigned long flags;
*ramixer = NULL;
@@ -243,15 +242,15 @@ static int get_amixer_rsc(struct amixer_mgr *mgr,
/* Check whether there are sufficient
* amixer resources to meet request. */
err = 0;
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i = 0; i < desc->msr; i++) {
- err = mgr_get_resource(&mgr->mgr, 1, &idx);
- if (err)
- break;
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i = 0; i < desc->msr; i++) {
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
+ if (err)
+ break;
- amixer->idx[i] = idx;
+ amixer->idx[i] = idx;
+ }
}
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (err) {
dev_err(mgr->card->dev,
"Can't meet AMIXER resource request!\n");
@@ -267,32 +266,30 @@ static int get_amixer_rsc(struct amixer_mgr *mgr,
return 0;
error:
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i--; i >= 0; i--)
- mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i--; i >= 0; i--)
+ mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+ }
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
kfree(amixer);
return err;
}
static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
{
- unsigned long flags;
int i;
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i = 0; i < amixer->rsc.msr; i++)
- mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i = 0; i < amixer->rsc.msr; i++)
+ mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
+ }
amixer_rsc_uninit(amixer);
kfree(amixer);
return 0;
}
-int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
+int amixer_mgr_create(struct hw *hw, void **ramixer_mgr)
{
int err;
struct amixer_mgr *amixer_mgr;
@@ -321,8 +318,9 @@ error:
return err;
}
-int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
+int amixer_mgr_destroy(void *ptr)
{
+ struct amixer_mgr *amixer_mgr = ptr;
rsc_mgr_uninit(&amixer_mgr->mgr);
kfree(amixer_mgr);
return 0;
@@ -386,7 +384,6 @@ static int get_sum_rsc(struct sum_mgr *mgr,
int err, i;
unsigned int idx;
struct sum *sum;
- unsigned long flags;
*rsum = NULL;
@@ -397,15 +394,15 @@ static int get_sum_rsc(struct sum_mgr *mgr,
/* Check whether there are sufficient sum resources to meet request. */
err = 0;
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i = 0; i < desc->msr; i++) {
- err = mgr_get_resource(&mgr->mgr, 1, &idx);
- if (err)
- break;
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i = 0; i < desc->msr; i++) {
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
+ if (err)
+ break;
- sum->idx[i] = idx;
+ sum->idx[i] = idx;
+ }
}
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (err) {
dev_err(mgr->card->dev,
"Can't meet SUM resource request!\n");
@@ -421,32 +418,29 @@ static int get_sum_rsc(struct sum_mgr *mgr,
return 0;
error:
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i--; i >= 0; i--)
- mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i--; i >= 0; i--)
+ mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
+ }
kfree(sum);
return err;
}
static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
{
- unsigned long flags;
int i;
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i = 0; i < sum->rsc.msr; i++)
- mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i = 0; i < sum->rsc.msr; i++)
+ mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
+ }
sum_rsc_uninit(sum);
kfree(sum);
return 0;
}
-int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
+int sum_mgr_create(struct hw *hw, void **rsum_mgr)
{
int err;
struct sum_mgr *sum_mgr;
@@ -475,8 +469,9 @@ error:
return err;
}
-int sum_mgr_destroy(struct sum_mgr *sum_mgr)
+int sum_mgr_destroy(void *ptr)
{
+ struct sum_mgr *sum_mgr = ptr;
rsc_mgr_uninit(&sum_mgr->mgr);
kfree(sum_mgr);
return 0;
diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h
index 4498e6139d0e..8fc017da6bda 100644
--- a/sound/pci/ctxfi/ctamixer.h
+++ b/sound/pci/ctxfi/ctamixer.h
@@ -43,8 +43,8 @@ struct sum_mgr {
};
/* Constructor and destructor of daio resource manager */
-int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr);
-int sum_mgr_destroy(struct sum_mgr *sum_mgr);
+int sum_mgr_create(struct hw *hw, void **ptr);
+int sum_mgr_destroy(void *ptr);
/* Define the descriptor of a amixer resource */
struct amixer_rsc_ops;
@@ -89,7 +89,7 @@ struct amixer_mgr {
};
/* Constructor and destructor of amixer resource manager */
-int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr);
-int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
+int amixer_mgr_create(struct hw *hw, void **ramixer_mgr);
+int amixer_mgr_destroy(void *amixer_mgr);
#endif /* CTAMIXER_H */
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index fbdb8a3d5b8e..227d8c8490e1 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -25,6 +25,9 @@
#include <sound/control.h>
#include <sound/asoundef.h>
+#define NUM_ATC_SRCS 6
+#define NUM_ATC_PCM (2 * 4)
+
#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */
#define MAX_MULTI_CHN 8
@@ -60,6 +63,7 @@ static const struct snd_pci_quirk subsys_20k2_list[] = {
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
CTHENDRIX),
+ SND_PCI_QUIRK(0x160b, 0x0101, "OK0010", CTOK0010),
{ } /* terminator */
};
@@ -75,6 +79,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
[CTHENDRIX] = "Hendrix",
[CTSB0880] = "SB0880",
[CTSB1270] = "SB1270",
+ [CTOK0010] = "OK0010",
[CT20K2_UNKNOWN] = "Unknown",
};
@@ -105,23 +110,20 @@ static struct {
.public_name = "Mixer"}
};
-typedef int (*create_t)(struct hw *, void **);
-typedef int (*destroy_t)(void *);
-
static struct {
int (*create)(struct hw *hw, void **rmgr);
int (*destroy)(void *mgr);
} rsc_mgr_funcs[NUM_RSCTYP] = {
- [SRC] = { .create = (create_t)src_mgr_create,
- .destroy = (destroy_t)src_mgr_destroy },
- [SRCIMP] = { .create = (create_t)srcimp_mgr_create,
- .destroy = (destroy_t)srcimp_mgr_destroy },
- [AMIXER] = { .create = (create_t)amixer_mgr_create,
- .destroy = (destroy_t)amixer_mgr_destroy },
- [SUM] = { .create = (create_t)sum_mgr_create,
- .destroy = (destroy_t)sum_mgr_destroy },
- [DAIO] = { .create = (create_t)daio_mgr_create,
- .destroy = (destroy_t)daio_mgr_destroy }
+ [SRC] = { .create = src_mgr_create,
+ .destroy = src_mgr_destroy },
+ [SRCIMP] = { .create = srcimp_mgr_create,
+ .destroy = srcimp_mgr_destroy },
+ [AMIXER] = { .create = amixer_mgr_create,
+ .destroy = amixer_mgr_destroy },
+ [SUM] = { .create = sum_mgr_create,
+ .destroy = sum_mgr_destroy },
+ [DAIO] = { .create = daio_mgr_create,
+ .destroy = daio_mgr_destroy }
};
static int
@@ -298,10 +300,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
src = apcm->src;
for (i = 0; i < n_amixer; i++) {
amixer = apcm->amixers[i];
- mutex_lock(&atc->atc_mutex);
- amixer->ops->setup(amixer, &src->rsc,
- INIT_VOL, atc->pcm[i+device*2]);
- mutex_unlock(&atc->atc_mutex);
+ scoped_guard(mutex, &atc->atc_mutex) {
+ amixer->ops->setup(amixer, &src->rsc,
+ INIT_VOL, atc->pcm[i+device*2]);
+ }
src = src->ops->next_interleave(src);
if (!src)
src = apcm->src;
@@ -877,7 +879,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
return -ENOENT;
}
- mutex_lock(&atc->atc_mutex);
+ guard(mutex)(&atc->atc_mutex);
dao->ops->get_spos(dao, &status);
if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
status &= ~(IEC958_AES3_CON_FS << 24);
@@ -887,7 +889,6 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
}
if ((rate != atc->pll_rate) && (32000 != rate))
err = atc_pll_init(atc, rate);
- mutex_unlock(&atc->atc_mutex);
return err;
}
@@ -924,13 +925,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
src = apcm->src;
}
/* Connect to SPDIFOO */
- mutex_lock(&atc->atc_mutex);
- dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
- amixer = apcm->amixers[0];
- dao->ops->set_left_input(dao, &amixer->rsc);
- amixer = apcm->amixers[1];
- dao->ops->set_right_input(dao, &amixer->rsc);
- mutex_unlock(&atc->atc_mutex);
+ scoped_guard(mutex, &atc->atc_mutex) {
+ dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
+ amixer = apcm->amixers[0];
+ dao->ops->set_left_input(dao, &amixer->rsc);
+ amixer = apcm->amixers[1];
+ dao->ops->set_right_input(dao, &amixer->rsc);
+ }
ct_timer_prepare(apcm->timer);
@@ -988,6 +989,24 @@ static struct capabilities atc_capabilities(struct ct_atc *atc)
return hw->capabilities(hw);
}
+static void atc_dedicated_rca_select(struct ct_atc *atc)
+{
+ struct dao *dao;
+ struct ct_mixer *mixer = atc->mixer;
+ struct rsc *rscs[2] = {NULL};
+
+ dao = container_of(atc->daios[atc->rca_state ? RCA : LINEO1],
+ struct dao, daio);
+ dao->ops->clear_left_input(dao);
+ dao->ops->clear_right_input(dao);
+
+ mixer->get_output_ports(mixer, MIX_WAVE_FRONT, &rscs[0], &rscs[1]);
+ dao = container_of(atc->daios[atc->rca_state ? LINEO1 : RCA],
+ struct dao, daio);
+ dao->ops->set_left_input(dao, rscs[0]);
+ dao->ops->set_right_input(dao, rscs[1]);
+}
+
static int atc_output_switch_get(struct ct_atc *atc)
{
struct hw *hw = atc->hw;
@@ -1089,6 +1108,11 @@ static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
return atc_daio_unmute(atc, state, MIC);
}
+static int atc_rca_unmute(struct ct_atc *atc, unsigned char state)
+{
+ return atc_daio_unmute(atc, state, RCA);
+}
+
static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
{
return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1118,7 +1142,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
struct rsc *rscs[2] = {NULL};
unsigned int spos = 0;
- mutex_lock(&atc->atc_mutex);
+ guard(mutex)(&atc->atc_mutex);
dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
da_dsc.msr = state ? 1 : atc->msr;
da_dsc.passthru = state ? 1 : 0;
@@ -1136,7 +1160,6 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
}
dao->ops->set_spos(dao, spos);
dao->ops->commit_write(dao);
- mutex_unlock(&atc->atc_mutex);
return err;
}
@@ -1166,9 +1189,11 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->daios) {
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
- for (i = 0; i < atc->n_daio; i++) {
+ for (i = 0; i < NUM_DAIOTYP; i++) {
daio = atc->daios[i];
- if (daio->type < LINEIM) {
+ if (!daio)
+ continue;
+ if (daio->output) {
dao = container_of(daio, struct dao, daio);
dao->ops->clear_left_input(dao);
dao->ops->clear_right_input(dao);
@@ -1181,8 +1206,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->pcm) {
sum_mgr = atc->rsc_mgrs[SUM];
- for (i = 0; i < atc->n_pcm; i++)
- sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
+ for (i = 0; i < NUM_ATC_PCM; i++)
+ if (atc->pcm[i])
+ sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
kfree(atc->pcm);
atc->pcm = NULL;
@@ -1190,8 +1216,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->srcs) {
src_mgr = atc->rsc_mgrs[SRC];
- for (i = 0; i < atc->n_src; i++)
- src_mgr->put_src(src_mgr, atc->srcs[i]);
+ for (i = 0; i < NUM_ATC_SRCS; i++)
+ if (atc->srcs[i])
+ src_mgr->put_src(src_mgr, atc->srcs[i]);
kfree(atc->srcs);
atc->srcs = NULL;
@@ -1199,7 +1226,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->srcimps) {
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
- for (i = 0; i < atc->n_srcimp; i++) {
+ for (i = 0; i < NUM_ATC_SRCS; i++) {
+ if (!atc->srcimps[i])
+ continue;
srcimp = atc->srcimps[i];
srcimp->ops->unmap(srcimp);
srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
@@ -1299,6 +1328,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
atc->chip_name, atc->model_name,
vendor_id, device_id);
+ atc->rca_state = 0;
return 0;
}
@@ -1372,32 +1402,35 @@ static int atc_get_resources(struct ct_atc *atc)
struct srcimp_mgr *srcimp_mgr;
struct sum_desc sum_dsc = {0};
struct sum_mgr *sum_mgr;
- int err, i, num_srcs, num_daios;
+ struct capabilities cap;
+ int err, i;
- num_daios = ((atc->model == CTSB1270) ? 8 : 7);
- num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
+ cap = atc->capabilities(atc);
- atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL);
+ atc->daios = kcalloc(NUM_DAIOTYP, sizeof(void *), GFP_KERNEL);
if (!atc->daios)
return -ENOMEM;
- atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
+ atc->srcs = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
if (!atc->srcs)
return -ENOMEM;
- atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
+ atc->srcimps = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
if (!atc->srcimps)
return -ENOMEM;
- atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL);
+ atc->pcm = kcalloc(NUM_ATC_PCM, sizeof(void *), GFP_KERNEL);
if (!atc->pcm)
return -ENOMEM;
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
da_desc.msr = atc->msr;
- for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+ for (i = 0; i < NUM_DAIOTYP; i++) {
+ if (((i == MIC) && !cap.dedicated_mic) || ((i == RCA) && !cap.dedicated_rca))
+ continue;
da_desc.type = (atc->model != CTSB073X) ? i :
((i == SPDIFIO) ? SPDIFI1 : i);
+ da_desc.output = (i < LINEIM) || (i == RCA);
err = daio_mgr->get_daio(daio_mgr, &da_desc,
(struct daio **)&atc->daios[i]);
if (err) {
@@ -1406,42 +1439,39 @@ static int atc_get_resources(struct ct_atc *atc)
i);
return err;
}
- atc->n_daio++;
}
src_mgr = atc->rsc_mgrs[SRC];
src_dsc.multi = 1;
src_dsc.msr = atc->msr;
src_dsc.mode = ARCRW;
- for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
+ for (i = 0; i < NUM_ATC_SRCS; i++) {
+ if (((i > 3) && !cap.dedicated_mic))
+ continue;
err = src_mgr->get_src(src_mgr, &src_dsc,
(struct src **)&atc->srcs[i]);
if (err)
return err;
-
- atc->n_src++;
}
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
srcimp_dsc.msr = 8;
- for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
+ for (i = 0; i < NUM_ATC_SRCS; i++) {
+ if (((i > 3) && !cap.dedicated_mic))
+ continue;
err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
(struct srcimp **)&atc->srcimps[i]);
if (err)
return err;
-
- atc->n_srcimp++;
}
sum_mgr = atc->rsc_mgrs[SUM];
sum_dsc.msr = atc->msr;
- for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
+ for (i = 0; i < NUM_ATC_PCM; i++) {
err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
(struct sum **)&atc->pcm[i]);
if (err)
return err;
-
- atc->n_pcm++;
}
return 0;
@@ -1494,9 +1524,11 @@ static void atc_connect_resources(struct ct_atc *atc)
struct sum *sum;
struct ct_mixer *mixer;
struct rsc *rscs[2] = {NULL};
+ struct capabilities cap;
int i, j;
mixer = atc->mixer;
+ cap = atc->capabilities(atc);
for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
@@ -1505,6 +1537,11 @@ static void atc_connect_resources(struct ct_atc *atc)
dao->ops->set_right_input(dao, rscs[1]);
}
+ if (cap.dedicated_rca) {
+ /* SE-300PCIE has a dedicated DAC for the RCA. */
+ atc_dedicated_rca_select(atc);
+ }
+
dai = container_of(atc->daios[LINEIM], struct dai, daio);
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
(struct src **)&atc->srcs[2],
@@ -1514,8 +1551,9 @@ static void atc_connect_resources(struct ct_atc *atc)
src = atc->srcs[3];
mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
- if (atc->model == CTSB1270) {
+ if (cap.dedicated_mic) {
/* Titanium HD has a dedicated ADC for the Mic. */
+ /* SE-300PCIE has a 4-channel ADC. */
dai = container_of(atc->daios[MIC], struct dai, daio);
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
(struct src **)&atc->srcs[4],
@@ -1637,12 +1675,14 @@ static const struct ct_atc atc_preset = {
.line_rear_unmute = atc_line_rear_unmute,
.line_in_unmute = atc_line_in_unmute,
.mic_unmute = atc_mic_unmute,
+ .rca_unmute = atc_rca_unmute,
.spdif_out_unmute = atc_spdif_out_unmute,
.spdif_in_unmute = atc_spdif_in_unmute,
.spdif_out_get_status = atc_spdif_out_get_status,
.spdif_out_set_status = atc_spdif_out_set_status,
.spdif_out_passthru = atc_spdif_out_passthru,
.capabilities = atc_capabilities,
+ .dedicated_rca_select = atc_dedicated_rca_select,
.output_switch_get = atc_output_switch_get,
.output_switch_put = atc_output_switch_put,
.mic_source_switch_get = atc_mic_source_switch_get,
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 0bc7b71d910b..ca0a9d5b86d8 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -82,6 +82,8 @@ struct ct_atc {
const char *chip_name;
const char *model_name;
+ unsigned char rca_state; /* 0 = dedicated RCA, 1 = 7.1ch Front */
+
struct ct_vm *vm; /* device virtual memory manager for this card */
int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
@@ -113,12 +115,14 @@ struct ct_atc {
int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
+ int (*rca_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
struct capabilities (*capabilities)(struct ct_atc *atc);
+ void (*dedicated_rca_select)(struct ct_atc *atc);
int (*output_switch_get)(struct ct_atc *atc);
int (*output_switch_put)(struct ct_atc *atc, int position);
int (*mic_source_switch_get)(struct ct_atc *atc);
@@ -132,10 +136,6 @@ struct ct_atc {
void **pcm; /* SUMs for collecting all pcm stream */
void **srcs; /* Sample Rate Converters for input signal */
void **srcimps; /* input mappers for SRCs */
- unsigned char n_daio;
- unsigned char n_src;
- unsigned char n_srcimp;
- unsigned char n_pcm;
struct ct_timer *timer;
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 7fc720046ce2..1c8f8efd836c 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -18,8 +18,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
-#define DAIO_OUT_MAX SPDIFOO
-
struct daio_usage {
unsigned short data;
};
@@ -47,6 +45,7 @@ static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
[LINEO4] = {.left = 0x70, .right = 0x71},
[LINEIM] = {.left = 0x45, .right = 0xc5},
[MIC] = {.left = 0x55, .right = 0xd5},
+ [RCA] = {.left = 0x30, .right = 0x31},
[SPDIFOO] = {.left = 0x00, .right = 0x01},
[SPDIFIO] = {.left = 0x05, .right = 0x85},
};
@@ -125,6 +124,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
case LINEO4: return 6;
case LINEIM: return 4;
case MIC: return 5;
+ case RCA: return 3;
default: return -EINVAL;
}
default:
@@ -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 = {
@@ -351,7 +329,7 @@ static int daio_rsc_init(struct daio *daio,
goto error1;
/* Set daio->rscl/r->ops to daio specific ones */
- if (desc->type <= DAIO_OUT_MAX) {
+ if (desc->output) {
daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
} else {
switch (hw->chip_type) {
@@ -366,6 +344,7 @@ static int daio_rsc_init(struct daio *daio,
}
}
daio->type = desc->type;
+ daio->output = desc->output;
return 0;
@@ -412,7 +391,7 @@ static int dao_rsc_init(struct dao *dao,
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
conf = (desc->msr & 0x7) | (desc->passthru << 3);
- hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
+ hw->daio_mgr_dao_init(hw, mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw), conf);
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw));
@@ -455,6 +434,7 @@ static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
dsc.type = dao->daio.type;
dsc.msr = desc->msr;
dsc.passthru = desc->passthru;
+ dsc.output = dao->daio.output;
dao_rsc_uninit(dao);
return dao_rsc_init(dao, &dsc, mgr);
}
@@ -525,14 +505,13 @@ static int get_daio_rsc(struct daio_mgr *mgr,
struct daio **rdaio)
{
int err;
- unsigned long flags;
*rdaio = NULL;
/* Check whether there are sufficient daio resources to meet request. */
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
+ }
if (err) {
dev_err(mgr->card->dev,
"Can't meet DAIO resource request!\n");
@@ -541,7 +520,7 @@ static int get_daio_rsc(struct daio_mgr *mgr,
err = -ENOMEM;
/* Allocate mem for daio resource */
- if (desc->type <= DAIO_OUT_MAX) {
+ if (desc->output) {
struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);
if (!dao)
goto error;
@@ -573,24 +552,22 @@ static int get_daio_rsc(struct daio_mgr *mgr,
return 0;
error:
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- daio_mgr_put_rsc(&mgr->mgr, desc->type);
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ daio_mgr_put_rsc(&mgr->mgr, desc->type);
+ }
return err;
}
static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
{
- unsigned long flags;
-
mgr->daio_disable(mgr, daio);
mgr->commit_write(mgr);
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- daio_mgr_put_rsc(&mgr->mgr, daio->type);
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ daio_mgr_put_rsc(&mgr->mgr, daio->type);
+ }
- if (daio->type <= DAIO_OUT_MAX) {
+ if (daio->output) {
dao_rsc_uninit(container_of(daio, struct dao, daio));
kfree(container_of(daio, struct dao, daio));
} else {
@@ -605,7 +582,7 @@ static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
- if (DAIO_OUT_MAX >= daio->type) {
+ if (daio->output) {
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
@@ -619,7 +596,7 @@ static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
- if (DAIO_OUT_MAX >= daio->type) {
+ if (daio->output) {
hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
@@ -644,34 +621,26 @@ static int daio_map_op(void *data, struct imapper *entry)
static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)
{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&mgr->imap_lock, flags);
+ guard(spinlock_irqsave)(&mgr->imap_lock);
if (!entry->addr && mgr->init_imap_added) {
input_mapper_delete(&mgr->imappers, mgr->init_imap,
daio_map_op, mgr);
mgr->init_imap_added = 0;
}
- err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);
- spin_unlock_irqrestore(&mgr->imap_lock, flags);
-
- return err;
+ return input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);
}
static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry)
{
- unsigned long flags;
int err;
- spin_lock_irqsave(&mgr->imap_lock, flags);
+ guard(spinlock_irqsave)(&mgr->imap_lock);
err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr);
if (list_empty(&mgr->imappers)) {
input_mapper_add(&mgr->imappers, mgr->init_imap,
daio_map_op, mgr);
mgr->init_imap_added = 1;
}
- spin_unlock_irqrestore(&mgr->imap_lock, flags);
return err;
}
@@ -684,7 +653,7 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr)
return 0;
}
-int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr)
+int daio_mgr_create(struct hw *hw, void **rdaio_mgr)
{
int err, i;
struct daio_mgr *daio_mgr;
@@ -738,14 +707,14 @@ error1:
return err;
}
-int daio_mgr_destroy(struct daio_mgr *daio_mgr)
+int daio_mgr_destroy(void *ptr)
{
- unsigned long flags;
+ struct daio_mgr *daio_mgr = ptr;
/* free daio input mapper list */
- spin_lock_irqsave(&daio_mgr->imap_lock, flags);
- free_input_mapper_list(&daio_mgr->imappers);
- spin_unlock_irqrestore(&daio_mgr->imap_lock, flags);
+ scoped_guard(spinlock_irqsave, &daio_mgr->imap_lock) {
+ free_input_mapper_list(&daio_mgr->imappers);
+ }
rsc_mgr_uninit(&daio_mgr->mgr);
kfree(daio_mgr);
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index bd6310f48013..ff77d55539a5 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -31,6 +31,7 @@ enum DAIOTYP {
LINEIM,
SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */
MIC, /* Dedicated mic on Titanium HD */
+ RCA, /* Dedicated RCA on SE-300PCIE */
SPDIFI1, /* S/PDIF In on internal Drive Bay */
NUM_DAIOTYP
};
@@ -43,6 +44,7 @@ struct daio {
struct rsc rscl; /* Basic resource info for left TX/RX */
struct rsc rscr; /* Basic resource info for right TX/RX */
enum DAIOTYP type;
+ unsigned char output;
};
struct dao {
@@ -91,6 +93,7 @@ struct daio_desc {
unsigned int type:4;
unsigned int msr:4;
unsigned int passthru:1;
+ unsigned int output:1;
};
struct daio_mgr {
@@ -115,7 +118,7 @@ struct daio_mgr {
};
/* Constructor and destructor of daio resource manager */
-int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr);
-int daio_mgr_destroy(struct daio_mgr *daio_mgr);
+int daio_mgr_create(struct hw *hw, void **ptr);
+int daio_mgr_destroy(void *ptr);
#endif /* CTDAIO_H */
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 2875cec83b8f..a3051fdd31f6 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -38,6 +38,7 @@ enum CTCARDS {
CTHENDRIX,
CTSB0880,
CTSB1270,
+ CTOK0010,
CT20K2_UNKNOWN,
NUM_CTCARDS /* This should always be the last */
};
@@ -62,6 +63,7 @@ struct card_conf {
struct capabilities {
unsigned int digit_io_switch:1;
unsigned int dedicated_mic:1;
+ unsigned int dedicated_rca:1;
unsigned int output_switch:1;
unsigned int mic_source_switch:1;
};
@@ -167,7 +169,7 @@ struct hw {
int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
- int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
+ int (*daio_mgr_dao_init)(struct hw *hw, void *blk, unsigned int idx,
unsigned int conf);
int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 9edbf5d8c3c7..ea0a928937b6 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1031,7 +1031,7 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
return 0;
}
-static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
{
struct daio_mgr_ctrl_blk *ctl = blk;
@@ -1775,6 +1775,7 @@ static struct capabilities hw_capabilities(struct hw *hw)
/* SB073x and Vista compatible cards have no digit IO switch */
cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
cap.dedicated_mic = 0;
+ cap.dedicated_rca = 0;
cap.output_switch = 0;
cap.mic_source_switch = 0;
@@ -2091,57 +2092,30 @@ static int hw_resume(struct hw *hw, struct card_conf *info)
static u32 hw_read_20kx(struct hw *hw, u32 reg)
{
- u32 value;
- unsigned long flags;
-
- spin_lock_irqsave(
- &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+ guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_20k1_lock);
outl(reg, hw->io_base + 0x0);
- value = inl(hw->io_base + 0x4);
- spin_unlock_irqrestore(
- &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
-
- return value;
+ return inl(hw->io_base + 0x4);
}
static void hw_write_20kx(struct hw *hw, u32 reg, u32 data)
{
- unsigned long flags;
-
- spin_lock_irqsave(
- &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
+ guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_20k1_lock);
outl(reg, hw->io_base + 0x0);
outl(data, hw->io_base + 0x4);
- spin_unlock_irqrestore(
- &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags);
-
}
static u32 hw_read_pci(struct hw *hw, u32 reg)
{
- u32 value;
- unsigned long flags;
-
- spin_lock_irqsave(
- &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+ guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_pci_lock);
outl(reg, hw->io_base + 0x10);
- value = inl(hw->io_base + 0x14);
- spin_unlock_irqrestore(
- &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
-
- return value;
+ return inl(hw->io_base + 0x14);
}
static void hw_write_pci(struct hw *hw, u32 reg, u32 data)
{
- unsigned long flags;
-
- spin_lock_irqsave(
- &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
+ guard(spinlock_irqsave)(&container_of(hw, struct hw20k1, hw)->reg_pci_lock);
outl(reg, hw->io_base + 0x10);
outl(data, hw->io_base + 0x14);
- spin_unlock_irqrestore(
- &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags);
}
static const struct hw ct20k1_preset = {
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 55af8ef29838..fac88f5590c9 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -910,7 +910,7 @@ static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
struct dao_ctrl_blk *ctl = blk;
if (ctl->dirty.bf.atxcsl) {
- if (idx < 4) {
+ if ((idx < 4) && ((hw->model != CTOK0010) || (idx < 3))) {
/* S/PDIF SPOSx */
hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
ctl->atxcsl);
@@ -985,11 +985,12 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
return 0;
}
-static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw, void *blk, unsigned int idx, unsigned int conf)
{
struct daio_mgr_ctrl_blk *ctl = blk;
- if (idx < 4) {
+ /* Port 3 is dedicated to RCA on SE-300PCIE */
+ if ((idx < 4) && ((hw->model != CTOK0010) || (idx < 3))) {
/* S/PDIF output */
switch ((conf & 0xf)) {
case 1:
@@ -1176,6 +1177,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+ } else if ((4 == info->msr) && (hw->model == CTOK0010)) {
+ hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21212121);
+ hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
+ hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
} else {
dev_alert(hw->card->dev,
"ERROR!!! Invalid sampling rate!!!\n");
@@ -1183,7 +1188,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
}
for (i = 0; i < 8; i++) {
- if (i <= 3) {
+ /* Port 3 is configured as I2S on SE-300PCIE */
+ if ((i < 4) && ((hw->model != CTOK0010) || (i < 3))) {
/* This comment looks wrong since loop is over 4 */
/* channels and emu20k2 supports 4 spdif IOs. */
/* 1st 3 channels are SPDIFs (SB0960) */
@@ -1637,6 +1643,13 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
hw_write_20kx(hw, GPIO_DATA, data);
hw_dac_start(hw);
return 0;
+ } else if (hw->model == CTOK0010) {
+ hw_dac_stop(hw);
+ data = hw_read_20kx(hw, GPIO_DATA);
+ data |= 0x1000;
+ hw_write_20kx(hw, GPIO_DATA, data);
+ hw_dac_start(hw);
+ return 0;
}
/* Set DAC reset bit as output */
@@ -1756,9 +1769,11 @@ End:
static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
{
u32 data;
- if (hw->model == CTSB1270) {
+ if ((hw->model == CTSB1270) || (hw->model == CTOK0010)) {
/* Titanium HD has two ADC chips, one for line in and one */
- /* for MIC. We don't need to switch the ADC input. */
+ /* for MIC. Also, SE-300PCIE has a single ADC chip that */
+ /* simultaneously supports 4-channel input. We don't need */
+ /* to switch the ADC input. */
return 1;
}
data = hw_read_20kx(hw, GPIO_DATA);
@@ -1826,6 +1841,32 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
return 0;
}
+static void hw_adc_stop(struct hw *hw)
+{
+ u32 data;
+ /* Reset the ADC (reset is active low). */
+ data = hw_read_20kx(hw, GPIO_DATA);
+ data &= ~(0x1 << 15);
+ hw_write_20kx(hw, GPIO_DATA, data);
+ usleep_range(10000, 11000);
+}
+
+static void hw_adc_start(struct hw *hw)
+{
+ u32 data;
+ /* Return the ADC to normal operation. */
+ data = hw_read_20kx(hw, GPIO_DATA);
+ data |= (0x1 << 15);
+ hw_write_20kx(hw, GPIO_DATA, data);
+ msleep(50);
+}
+
+static void hw_adc_reset(struct hw *hw)
+{
+ hw_adc_stop(hw);
+ hw_adc_start(hw);
+}
+
static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
{
int err;
@@ -1836,6 +1877,12 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
data |= (0x1 << 15);
hw_write_20kx(hw, GPIO_CTRL, data);
+ if (hw->model == CTOK0010) {
+ /* Manual ADC setup for SE-300PCIE is not needed. */
+ hw_adc_reset(hw);
+ return 0;
+ }
+
/* Initialize I2C */
err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
if (err < 0) {
@@ -1843,10 +1890,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
goto error;
}
- /* Reset the ADC (reset is active low). */
- data = hw_read_20kx(hw, GPIO_DATA);
- data &= ~(0x1 << 15);
- hw_write_20kx(hw, GPIO_DATA, data);
+ hw_adc_stop(hw);
if (hw->model == CTSB1270) {
/* Set up the PCM4220 ADC on Titanium HD */
@@ -1860,11 +1904,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
hw_write_20kx(hw, GPIO_DATA, data);
}
- usleep_range(10000, 11000);
- /* Return the ADC to normal operation. */
- data |= (0x1 << 15);
- hw_write_20kx(hw, GPIO_DATA, data);
- msleep(50);
+ hw_adc_start(hw);
/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
/* invert bit, interface format to I2S, word length to 24-bit, */
@@ -1910,7 +1950,8 @@ static struct capabilities hw_capabilities(struct hw *hw)
struct capabilities cap;
cap.digit_io_switch = 0;
- cap.dedicated_mic = hw->model == CTSB1270;
+ cap.dedicated_mic = (hw->model == CTSB1270) || (hw->model == CTOK0010);
+ cap.dedicated_rca = hw->model == CTOK0010;
cap.output_switch = hw->model == CTSB1270;
cap.mic_source_switch = hw->model == CTSB1270;
@@ -2147,15 +2188,17 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
/* Reset all SRC pending interrupts */
hw_write_20kx(hw, SRC_IP, 0);
- if (hw->model != CTSB1270) {
+ if (hw->model == CTSB1270) {
+ hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+ } else if (hw->model == CTOK0010) {
+ hw_write_20kx(hw, GPIO_CTRL, 0x9902);
+ } else {
/* TODO: detect the card ID and configure GPIO accordingly. */
/* Configures GPIO (0xD802 0x98028) */
/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
/* Configures GPIO (SB0880) */
/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
hw_write_20kx(hw, GPIO_CTRL, 0xD802);
- } else {
- hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
}
/* Enable audio ring */
hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index 6797fde3d788..fc9fde284fb3 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -547,8 +547,14 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
atc->mic_unmute(atc, state);
else if (MIXER_SPDIFI_C_S == type)
atc->spdif_in_unmute(atc, state);
- else if (MIXER_WAVEF_P_S == type)
- atc->line_front_unmute(atc, state);
+ else if (MIXER_WAVEF_P_S == type) {
+ if (cap.dedicated_rca) {
+ atc->rca_unmute(atc, atc->rca_state ? 0 : state);
+ atc->line_front_unmute(atc, atc->rca_state ? state : 0);
+ } else {
+ atc->line_front_unmute(atc, state);
+ }
+ }
else if (MIXER_WAVES_P_S == type)
atc->line_surround_unmute(atc, state);
else if (MIXER_WAVEC_P_S == type)
@@ -612,6 +618,57 @@ static struct snd_kcontrol_new swh_ctl = {
.put = ct_alsa_mix_switch_put
};
+static int dedicated_rca_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = {
+ "RCA", "Front"
+ };
+
+ return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int dedicated_rca_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = atc->rca_state;
+ return 0;
+}
+
+static int dedicated_rca_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+ unsigned int rca_state = ucontrol->value.enumerated.item[0];
+ unsigned char state;
+
+ if (rca_state > 1)
+ return -EINVAL;
+
+ if (rca_state == atc->rca_state)
+ return 0;
+
+ state = get_switch_state(atc->mixer, MIXER_WAVEF_P_S);
+ do_switch(atc, MIXER_WAVEF_P_S, 0);
+
+ atc->rca_state = rca_state;
+ atc->dedicated_rca_select(atc);
+
+ do_switch(atc, MIXER_WAVEF_P_S, state);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new rca_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Playback Route",
+ .info = dedicated_rca_info,
+ .get = dedicated_rca_get,
+ .put = dedicated_rca_put,
+};
+
static int ct_spdif_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -784,7 +841,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
if (err)
return err;
}
- atc->line_front_unmute(atc, 1);
+
+ if (cap.dedicated_rca) {
+ err = ct_mixer_kcontrol_new(mixer, &rca_ctl);
+ if (err)
+ return err;
+
+ atc->line_front_unmute(atc, 0);
+ atc->rca_unmute(atc, 1);
+ } else {
+ atc->line_front_unmute(atc, 1);
+ }
set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
atc->line_surround_unmute(atc, 0);
set_switch_state(mixer, MIXER_WAVES_P_S, 0);
@@ -1219,7 +1286,7 @@ int ct_alsa_mix_create(struct ct_atc *atc,
if (err)
return err;
- strcpy(atc->card->mixername, device_name);
+ strscpy(atc->card->mixername, device_name);
return 0;
}
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
index 4a94b4708a77..46afc9604c08 100644
--- a/sound/pci/ctxfi/ctsrc.c
+++ b/sound/pci/ctxfi/ctsrc.c
@@ -414,18 +414,16 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
unsigned int idx = SRC_RESOURCE_NUM;
int err;
struct src *src;
- unsigned long flags;
*rsrc = NULL;
/* Check whether there are sufficient src resources to meet request. */
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- if (MEMRD == desc->mode)
- err = mgr_get_resource(&mgr->mgr, desc->multi, &idx);
- else
- err = mgr_get_resource(&mgr->mgr, 1, &idx);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ if (MEMRD == desc->mode)
+ err = mgr_get_resource(&mgr->mgr, desc->multi, &idx);
+ else
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
+ }
if (err) {
dev_err(mgr->card->dev,
"Can't meet SRC resource request!\n");
@@ -454,29 +452,25 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
error2:
kfree(src);
error1:
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- if (MEMRD == desc->mode)
- mgr_put_resource(&mgr->mgr, desc->multi, idx);
- else
- mgr_put_resource(&mgr->mgr, 1, idx);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ if (MEMRD == desc->mode)
+ mgr_put_resource(&mgr->mgr, desc->multi, idx);
+ else
+ mgr_put_resource(&mgr->mgr, 1, idx);
+ }
return err;
}
static int put_src_rsc(struct src_mgr *mgr, struct src *src)
{
- unsigned long flags;
-
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- src->rsc.ops->master(&src->rsc);
- if (MEMRD == src->mode)
- mgr_put_resource(&mgr->mgr, src->multi,
- src->rsc.ops->index(&src->rsc));
- else
- mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc));
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ src->rsc.ops->master(&src->rsc);
+ if (MEMRD == src->mode)
+ mgr_put_resource(&mgr->mgr, src->multi,
+ src->rsc.ops->index(&src->rsc));
+ else
+ mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc));
+ }
src_rsc_uninit(src, mgr);
kfree(src);
@@ -540,7 +534,7 @@ static int src_mgr_commit_write(struct src_mgr *mgr)
return 0;
}
-int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr)
+int src_mgr_create(struct hw *hw, void **rsrc_mgr)
{
int err, i;
struct src_mgr *src_mgr;
@@ -580,8 +574,9 @@ error1:
return err;
}
-int src_mgr_destroy(struct src_mgr *src_mgr)
+int src_mgr_destroy(void *ptr)
{
+ struct src_mgr *src_mgr = ptr;
rsc_mgr_uninit(&src_mgr->mgr);
kfree(src_mgr);
@@ -713,7 +708,6 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
int err, i;
unsigned int idx;
struct srcimp *srcimp;
- unsigned long flags;
*rsrcimp = NULL;
@@ -724,15 +718,15 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
/* Check whether there are sufficient SRCIMP resources. */
err = 0;
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i = 0; i < desc->msr; i++) {
- err = mgr_get_resource(&mgr->mgr, 1, &idx);
- if (err)
- break;
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i = 0; i < desc->msr; i++) {
+ err = mgr_get_resource(&mgr->mgr, 1, &idx);
+ if (err)
+ break;
- srcimp->idx[i] = idx;
+ srcimp->idx[i] = idx;
+ }
}
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (err) {
dev_err(mgr->card->dev,
"Can't meet SRCIMP resource request!\n");
@@ -748,25 +742,22 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
return 0;
error1:
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i--; i >= 0; i--)
- mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i--; i >= 0; i--)
+ mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
+ }
kfree(srcimp);
return err;
}
static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp)
{
- unsigned long flags;
int i;
- spin_lock_irqsave(&mgr->mgr_lock, flags);
- for (i = 0; i < srcimp->rsc.msr; i++)
- mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
-
- spin_unlock_irqrestore(&mgr->mgr_lock, flags);
+ scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
+ for (i = 0; i < srcimp->rsc.msr; i++)
+ mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]);
+ }
srcimp_rsc_uninit(srcimp);
kfree(srcimp);
@@ -789,39 +780,31 @@ static int srcimp_map_op(void *data, struct imapper *entry)
static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry)
{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&mgr->imap_lock, flags);
+ guard(spinlock_irqsave)(&mgr->imap_lock);
if ((0 == entry->addr) && (mgr->init_imap_added)) {
input_mapper_delete(&mgr->imappers,
mgr->init_imap, srcimp_map_op, mgr);
mgr->init_imap_added = 0;
}
- err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr);
- spin_unlock_irqrestore(&mgr->imap_lock, flags);
-
- return err;
+ return input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr);
}
static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry)
{
- unsigned long flags;
int err;
- spin_lock_irqsave(&mgr->imap_lock, flags);
+ guard(spinlock_irqsave)(&mgr->imap_lock);
err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr);
if (list_empty(&mgr->imappers)) {
input_mapper_add(&mgr->imappers, mgr->init_imap,
srcimp_map_op, mgr);
mgr->init_imap_added = 1;
}
- spin_unlock_irqrestore(&mgr->imap_lock, flags);
return err;
}
-int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr)
+int srcimp_mgr_create(struct hw *hw, void **rsrcimp_mgr)
{
int err;
struct srcimp_mgr *srcimp_mgr;
@@ -866,14 +849,14 @@ error1:
return err;
}
-int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr)
+int srcimp_mgr_destroy(void *ptr)
{
- unsigned long flags;
+ struct srcimp_mgr *srcimp_mgr = ptr;
/* free src input mapper list */
- spin_lock_irqsave(&srcimp_mgr->imap_lock, flags);
- free_input_mapper_list(&srcimp_mgr->imappers);
- spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags);
+ scoped_guard(spinlock_irqsave, &srcimp_mgr->imap_lock) {
+ free_input_mapper_list(&srcimp_mgr->imappers);
+ }
rsc_mgr_uninit(&srcimp_mgr->mgr);
kfree(srcimp_mgr);
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h
index 1124daf50c9b..e6366cc6a7ae 100644
--- a/sound/pci/ctxfi/ctsrc.h
+++ b/sound/pci/ctxfi/ctsrc.h
@@ -139,10 +139,10 @@ struct srcimp_mgr {
};
/* Constructor and destructor of SRC resource manager */
-int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr);
-int src_mgr_destroy(struct src_mgr *src_mgr);
+int src_mgr_create(struct hw *hw, void **ptr);
+int src_mgr_destroy(void *ptr);
/* Constructor and destructor of SRCIMP resource manager */
-int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr);
-int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr);
+int srcimp_mgr_create(struct hw *hw, void **ptr);
+int srcimp_mgr_destroy(void *ptr);
#endif /* CTSRC_H */
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
index 0bb447ccd77c..609b10320ff7 100644
--- a/sound/pci/ctxfi/cttimer.c
+++ b/sound/pci/ctxfi/cttimer.c
@@ -62,13 +62,12 @@ struct ct_timer {
static void ct_systimer_callback(struct timer_list *t)
{
- struct ct_timer_instance *ti = from_timer(ti, t, timer);
+ struct ct_timer_instance *ti = timer_container_of(ti, t, timer);
struct snd_pcm_substream *substream = ti->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct ct_atc_pcm *apcm = ti->apcm;
unsigned int period_size = runtime->period_size;
unsigned int buffer_size = runtime->buffer_size;
- unsigned long flags;
unsigned int position, dist, interval;
position = substream->ops->pointer(substream);
@@ -82,10 +81,9 @@ static void ct_systimer_callback(struct timer_list *t)
* at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
interval = ((period_size - (position % period_size))
* HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
- spin_lock_irqsave(&ti->lock, flags);
+ guard(spinlock_irqsave)(&ti->lock);
if (ti->running)
mod_timer(&ti->timer, jiffies + interval);
- spin_unlock_irqrestore(&ti->lock, flags);
}
static void ct_systimer_init(struct ct_timer_instance *ti)
@@ -96,30 +94,25 @@ static void ct_systimer_init(struct ct_timer_instance *ti)
static void ct_systimer_start(struct ct_timer_instance *ti)
{
struct snd_pcm_runtime *runtime = ti->substream->runtime;
- unsigned long flags;
- spin_lock_irqsave(&ti->lock, flags);
+ guard(spinlock_irqsave)(&ti->lock);
ti->running = 1;
mod_timer(&ti->timer,
jiffies + (runtime->period_size * HZ +
(runtime->rate - 1)) / runtime->rate);
- spin_unlock_irqrestore(&ti->lock, flags);
}
static void ct_systimer_stop(struct ct_timer_instance *ti)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ti->lock, flags);
+ guard(spinlock_irqsave)(&ti->lock);
ti->running = 0;
- del_timer(&ti->timer);
- spin_unlock_irqrestore(&ti->lock, flags);
+ timer_delete(&ti->timer);
}
static void ct_systimer_prepare(struct ct_timer_instance *ti)
{
ct_systimer_stop(ti);
- try_to_del_timer_sync(&ti->timer);
+ timer_delete_sync_try(&ti->timer);
}
#define ct_systimer_free ct_systimer_prepare
@@ -229,25 +222,22 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
static void ct_xfitimer_check_period(struct ct_timer *atimer)
{
struct ct_timer_instance *ti;
- unsigned long flags;
- spin_lock_irqsave(&atimer->list_lock, flags);
+ guard(spinlock_irqsave)(&atimer->list_lock);
list_for_each_entry(ti, &atimer->instance_head, instance_list) {
if (ti->running && ti->need_update) {
ti->need_update = 0;
ti->apcm->interrupt(ti->apcm);
}
}
- spin_unlock_irqrestore(&atimer->list_lock, flags);
}
/* Handle timer-interrupt */
static void ct_xfitimer_callback(struct ct_timer *atimer)
{
int update;
- unsigned long flags;
- spin_lock_irqsave(&atimer->lock, flags);
+ guard(spinlock_irqsave)(&atimer->lock);
atimer->irq_handling = 1;
do {
update = ct_xfitimer_reprogram(atimer, 1);
@@ -257,7 +247,6 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
spin_lock(&atimer->lock);
} while (atimer->reprogram);
atimer->irq_handling = 0;
- spin_unlock_irqrestore(&atimer->lock, flags);
}
static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
@@ -271,45 +260,39 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
/* start/stop the timer */
static void ct_xfitimer_update(struct ct_timer *atimer)
{
- unsigned long flags;
-
- spin_lock_irqsave(&atimer->lock, flags);
+ guard(spinlock_irqsave)(&atimer->lock);
if (atimer->irq_handling) {
/* reached from IRQ handler; let it handle later */
atimer->reprogram = 1;
- spin_unlock_irqrestore(&atimer->lock, flags);
return;
}
ct_xfitimer_irq_stop(atimer);
ct_xfitimer_reprogram(atimer, 0);
- spin_unlock_irqrestore(&atimer->lock, flags);
}
static void ct_xfitimer_start(struct ct_timer_instance *ti)
{
struct ct_timer *atimer = ti->timer_base;
- unsigned long flags;
- spin_lock_irqsave(&atimer->lock, flags);
- if (list_empty(&ti->running_list))
- atimer->wc = ct_xfitimer_get_wc(atimer);
- ti->running = 1;
- ti->need_update = 0;
- list_add(&ti->running_list, &atimer->running_head);
- spin_unlock_irqrestore(&atimer->lock, flags);
+ scoped_guard(spinlock_irqsave, &atimer->lock) {
+ if (list_empty(&ti->running_list))
+ atimer->wc = ct_xfitimer_get_wc(atimer);
+ ti->running = 1;
+ ti->need_update = 0;
+ list_add(&ti->running_list, &atimer->running_head);
+ }
ct_xfitimer_update(atimer);
}
static void ct_xfitimer_stop(struct ct_timer_instance *ti)
{
struct ct_timer *atimer = ti->timer_base;
- unsigned long flags;
- spin_lock_irqsave(&atimer->lock, flags);
- list_del_init(&ti->running_list);
- ti->running = 0;
- spin_unlock_irqrestore(&atimer->lock, flags);
+ scoped_guard(spinlock_irqsave, &atimer->lock) {
+ list_del_init(&ti->running_list);
+ ti->running = 0;
+ }
ct_xfitimer_update(atimer);
}
@@ -347,9 +330,9 @@ ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
if (atimer->ops->init)
atimer->ops->init(ti);
- spin_lock_irq(&atimer->list_lock);
- list_add(&ti->instance_list, &atimer->instance_head);
- spin_unlock_irq(&atimer->list_lock);
+ scoped_guard(spinlock_irq, &atimer->list_lock) {
+ list_add(&ti->instance_list, &atimer->instance_head);
+ }
return ti;
}
@@ -382,9 +365,9 @@ void ct_timer_instance_free(struct ct_timer_instance *ti)
if (atimer->ops->free_instance)
atimer->ops->free_instance(ti);
- spin_lock_irq(&atimer->list_lock);
- list_del(&ti->instance_list);
- spin_unlock_irq(&atimer->list_lock);
+ scoped_guard(spinlock_irq, &atimer->list_lock) {
+ list_del(&ti->instance_list);
+ }
kfree(ti);
}
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index 7a805c4a58e1..823d6e240a07 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -29,7 +29,7 @@
static struct ct_vm_block *
get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc)
{
- struct ct_vm_block *block = NULL, *entry;
+ struct ct_vm_block *block, *entry;
struct list_head *pos;
size = CT_PAGE_ALIGN(size);
@@ -39,26 +39,25 @@ get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc)
return NULL;
}
- mutex_lock(&vm->lock);
+ guard(mutex)(&vm->lock);
list_for_each(pos, &vm->unused) {
entry = list_entry(pos, struct ct_vm_block, list);
if (entry->size >= size)
break; /* found a block that is big enough */
}
if (pos == &vm->unused)
- goto out;
+ return NULL;
if (entry->size == size) {
/* Move the vm node from unused list to used list directly */
list_move(&entry->list, &vm->used);
vm->size -= size;
- block = entry;
- goto out;
+ return entry;
}
block = kzalloc(sizeof(*block), GFP_KERNEL);
if (!block)
- goto out;
+ return NULL;
block->addr = entry->addr;
block->size = size;
@@ -67,8 +66,6 @@ get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc)
entry->size -= size;
vm->size -= size;
- out:
- mutex_unlock(&vm->lock);
return block;
}
@@ -79,7 +76,7 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
block->size = CT_PAGE_ALIGN(block->size);
- mutex_lock(&vm->lock);
+ guard(mutex)(&vm->lock);
list_del(&block->list);
vm->size += block->size;
@@ -116,7 +113,6 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
pos = pre;
pre = pos->prev;
}
- mutex_unlock(&vm->lock);
}
/* Map host addr (kmalloced/vmalloced) to device logical addr. */
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index 713d36ea40cb..d8dd84d41c87 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -98,8 +98,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (err < 0)
goto error;
- strcpy(card->driver, "SB-XFi");
- strcpy(card->shortname, "Creative X-Fi");
+ strscpy(card->driver, "SB-XFi");
+ strscpy(card->shortname, "Creative X-Fi");
snprintf(card->longname, sizeof(card->longname), "%s %s %s",
card->shortname, atc->chip_name, atc->model_name);
diff --git a/sound/pci/echoaudio/Makefile b/sound/pci/echoaudio/Makefile
index 4865b8fe7434..96667641c7cf 100644
--- a/sound/pci/echoaudio/Makefile
+++ b/sound/pci/echoaudio/Makefile
@@ -4,20 +4,20 @@
# Copyright (c) 2003 by Giuliano Pochini <pochini@shiny.it>
#
-snd-darla20-objs := darla20.o
-snd-gina20-objs := gina20.o
-snd-layla20-objs := layla20.o
-snd-darla24-objs := darla24.o
-snd-gina24-objs := gina24.o
-snd-layla24-objs := layla24.o
-snd-mona-objs := mona.o
-snd-mia-objs := mia.o
-snd-echo3g-objs := echo3g.o
-snd-indigo-objs := indigo.o
-snd-indigoio-objs := indigoio.o
-snd-indigodj-objs := indigodj.o
-snd-indigoiox-objs := indigoiox.o
-snd-indigodjx-objs := indigodjx.o
+snd-darla20-y := darla20.o
+snd-gina20-y := gina20.o
+snd-layla20-y := layla20.o
+snd-darla24-y := darla24.o
+snd-gina24-y := gina24.o
+snd-layla24-y := layla24.o
+snd-mona-y := mona.o
+snd-mia-y := mia.o
+snd-echo3g-y := echo3g.o
+snd-indigo-y := indigo.o
+snd-indigoio-y := indigoio.o
+snd-indigodj-y := indigodj.o
+snd-indigoiox-y := indigoiox.o
+snd-indigodjx-y := indigodjx.o
obj-$(CONFIG_SND_DARLA20) += snd-darla20.o
obj-$(CONFIG_SND_GINA20) += snd-gina20.o
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index c70c3ac4e99a..f2c8602a1ad7 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -6,6 +6,7 @@
*/
#include <linux/module.h>
+#include <linux/string.h>
MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
MODULE_LICENSE("GPL v2");
@@ -34,7 +35,6 @@ static int get_firmware(const struct firmware **fw_entry,
int err;
char name[30];
-#ifdef CONFIG_PM_SLEEP
if (chip->fw_cache[fw_index]) {
dev_dbg(chip->card->dev,
"firmware requested: %s is cached\n",
@@ -42,7 +42,6 @@ static int get_firmware(const struct firmware **fw_entry,
*fw_entry = chip->fw_cache[fw_index];
return 0;
}
-#endif
dev_dbg(chip->card->dev,
"firmware requested: %s\n", card_fw[fw_index].data);
@@ -51,10 +50,8 @@ static int get_firmware(const struct firmware **fw_entry,
if (err < 0)
dev_err(chip->card->dev,
"get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM_SLEEP
else
chip->fw_cache[fw_index] = *fw_entry;
-#endif
return err;
}
@@ -63,18 +60,13 @@ static int get_firmware(const struct firmware **fw_entry,
static void free_firmware(const struct firmware *fw_entry,
struct echoaudio *chip)
{
-#ifdef CONFIG_PM_SLEEP
dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n");
-#else
- release_firmware(fw_entry);
-#endif
}
static void free_firmware_cache(struct echoaudio *chip)
{
-#ifdef CONFIG_PM_SLEEP
int i;
for (i = 0; i < 8 ; i++)
@@ -82,8 +74,6 @@ static void free_firmware_cache(struct echoaudio *chip)
release_firmware(chip->fw_cache[i]);
dev_dbg(chip->card->dev, "release_firmware(%d)\n", i);
}
-
-#endif
}
@@ -247,7 +237,7 @@ static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
struct snd_interval fixed;
int err;
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
if (chip->can_set_rate) {
err = 0;
@@ -257,7 +247,6 @@ static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
err = snd_interval_refine(rate, &fixed);
}
- mutex_unlock(&chip->mode_mutex);
return err;
}
@@ -425,7 +414,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
int err, max_channels;
max_channels = num_digital_busses_in(chip) - substream->number;
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
err = pcm_open(substream, max_channels);
else /* If the card has ADAT, subtract the 6 channels
@@ -434,24 +423,22 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
if (err < 0)
- goto din_exit;
+ return err;
err = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
hw_rule_capture_channels_by_format, NULL,
SNDRV_PCM_HW_PARAM_FORMAT, -1);
if (err < 0)
- goto din_exit;
+ return err;
err = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
hw_rule_capture_format_by_channels, NULL,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (err < 0)
- goto din_exit;
+ return err;
-din_exit:
- mutex_unlock(&chip->mode_mutex);
- return err;
+ return 0;
}
@@ -464,7 +451,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
int err, max_channels;
max_channels = num_digital_busses_out(chip) - substream->number;
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
err = pcm_open(substream, max_channels);
else /* If the card has ADAT, subtract the 6 channels
@@ -473,7 +460,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
if (err < 0)
- goto dout_exit;
+ return err;
err = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -481,18 +468,16 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
NULL, SNDRV_PCM_HW_PARAM_FORMAT,
-1);
if (err < 0)
- goto dout_exit;
+ return err;
err = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_FORMAT,
hw_rule_playback_format_by_channels,
NULL, SNDRV_PCM_HW_PARAM_CHANNELS,
-1);
if (err < 0)
- goto dout_exit;
+ return err;
-dout_exit:
- mutex_unlock(&chip->mode_mutex);
- return err;
+ return 0;
}
#endif /* !ECHOCARD_HAS_VMIXER */
@@ -509,7 +494,7 @@ static int pcm_close(struct snd_pcm_substream *substream)
* freed by its callback
*/
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
dev_dbg(chip->card->dev, "pcm_open opencount=%d can_set_rate=%d, rate_set=%d",
chip->opencount, chip->can_set_rate, chip->rate_set);
@@ -526,7 +511,6 @@ static int pcm_close(struct snd_pcm_substream *substream)
break;
}
- mutex_unlock(&chip->mode_mutex);
return 0;
}
@@ -547,22 +531,21 @@ static int init_engine(struct snd_pcm_substream *substream,
/* Sets up che hardware. If it's already initialized, reset and
* redo with the new parameters
*/
- spin_lock_irq(&chip->lock);
- if (pipe->index >= 0) {
- dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index);
- err = free_pipes(chip, pipe);
- snd_BUG_ON(err);
- chip->substream[pipe->index] = NULL;
- }
+ scoped_guard(spinlock_irq, &chip->lock) {
+ if (pipe->index >= 0) {
+ dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index);
+ err = free_pipes(chip, pipe);
+ snd_BUG_ON(err);
+ chip->substream[pipe->index] = NULL;
+ }
- err = allocate_pipes(chip, pipe, pipe_index, interleave);
- if (err < 0) {
- spin_unlock_irq(&chip->lock);
- dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n",
- pipe_index, err);
- return err;
+ err = allocate_pipes(chip, pipe, pipe_index, interleave);
+ if (err < 0) {
+ dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n",
+ pipe_index, err);
+ return err;
+ }
}
- spin_unlock_irq(&chip->lock);
dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index);
dev_dbg(chip->card->dev,
@@ -610,9 +593,8 @@ static int init_engine(struct snd_pcm_substream *substream,
smp_wmb();
chip->substream[pipe_index] = substream;
chip->rate_set = 1;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -674,14 +656,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
chip = snd_pcm_substream_chip(substream);
pipe = (struct audiopipe *) substream->runtime->private_data;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
if (pipe->index >= 0) {
dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index);
free_pipes(chip, pipe);
chip->substream[pipe->index] = NULL;
pipe->index = -1;
}
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -731,15 +712,12 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
* exclusive control
*/
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
- if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index))) {
- spin_unlock_irq(&chip->lock);
+ if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index)))
return -EINVAL;
- }
set_audio_format(chip, pipe_index, &format);
- spin_unlock_irq(&chip->lock);
return 0;
}
@@ -763,7 +741,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
}
- spin_lock(&chip->lock);
+ guard(spinlock)(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
@@ -811,7 +789,6 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
default:
err = -EINVAL;
}
- spin_unlock(&chip->lock);
return err;
}
@@ -927,7 +904,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
return err;
pcm->private_data = chip;
chip->analog_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
@@ -940,7 +917,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
return err;
pcm->private_data = chip;
chip->digital_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
#endif /* ECHOCARD_HAS_DIGITAL_IO */
@@ -960,7 +937,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
return err;
pcm->private_data = chip;
chip->analog_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
@@ -974,7 +951,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
return err;
pcm->private_data = chip;
chip->digital_pcm = pcm;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
snd_echo_preallocate_pages(pcm, &chip->pci->dev);
@@ -1028,7 +1005,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_busses_out(chip); c++) {
gain = ucontrol->value.integer.value[c];
/* Ignore out of range values */
@@ -1041,7 +1018,6 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
}
if (changed)
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1109,7 +1085,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_analog_busses_in(chip); c++) {
gain = ucontrol->value.integer.value[c];
/* Ignore out of range values */
@@ -1122,7 +1098,6 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
}
if (changed)
update_input_line_level(chip);
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1178,7 +1153,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_analog_busses_out(chip); c++) {
if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) {
set_nominal_level(chip, c,
@@ -1188,7 +1163,6 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
}
if (changed)
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1241,7 +1215,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
changed = 0;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (c = 0; c < num_analog_busses_in(chip); c++) {
if (chip->nominal_level[bx_analog_in(chip) + c] !=
ucontrol->value.integer.value[c]) {
@@ -1254,7 +1228,6 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
update_output_line_level(chip); /* "Output" is not a mistake
* here.
*/
- spin_unlock_irq(&chip->lock);
return changed;
}
@@ -1314,10 +1287,9 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
return -EINVAL;
if (chip->monitor_gain[out][in] != gain) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_monitor_gain(chip, out, in, gain);
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
changed = 1;
}
return changed;
@@ -1377,10 +1349,9 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
return -EINVAL;
if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]);
update_vmixer_level(chip);
- spin_unlock_irq(&chip->lock);
changed = 1;
}
return changed;
@@ -1450,7 +1421,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
if (dmode != chip->digital_mode) {
/* mode_mutex is required to make this operation atomic wrt
pcm_digital_*_open() and set_input_clock() functions. */
- mutex_lock(&chip->mode_mutex);
+ guard(mutex)(&chip->mode_mutex);
/* Do not allow the user to change the digital mode when a pcm
device is open because it also changes the number of channels
@@ -1470,7 +1441,6 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
if (changed >= 0)
changed = 1; /* No errors */
}
- mutex_unlock(&chip->mode_mutex);
}
return changed;
}
@@ -1517,9 +1487,8 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol,
chip = snd_kcontrol_chip(kcontrol);
mode = !!ucontrol->value.enumerated.item[0];
if (mode != chip->professional_spdif) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_professional_spdif(chip, mode);
- spin_unlock_irq(&chip->lock);
return 1;
}
return 0;
@@ -1583,13 +1552,11 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
dclock = chip->clock_source_list[eclock];
if (chip->input_clock != dclock) {
- mutex_lock(&chip->mode_mutex);
- spin_lock_irq(&chip->lock);
+ guard(mutex)(&chip->mode_mutex);
+ guard(spinlock_irq)(&chip->lock);
changed = set_input_clock(chip, dclock);
if (!changed)
changed = 1; /* no errors */
- spin_unlock_irq(&chip->lock);
- mutex_unlock(&chip->mode_mutex);
}
if (changed < 0)
@@ -1633,9 +1600,8 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol,
power = !!ucontrol->value.integer.value[0];
if (chip->phantom_power != power) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
changed = set_phantom_power(chip, power);
- spin_unlock_irq(&chip->lock);
if (changed == 0)
changed = 1; /* no errors */
}
@@ -1676,9 +1642,8 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,
automute = !!ucontrol->value.integer.value[0];
if (chip->digital_in_automute != automute) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
changed = set_input_auto_mute(chip, automute);
- spin_unlock_irq(&chip->lock);
if (changed == 0)
changed = 1; /* no errors */
}
@@ -1706,9 +1671,8 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,
struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_meters_on(chip, ucontrol->value.integer.value[0]);
- spin_unlock_irq(&chip->lock);
return 1;
}
@@ -1921,7 +1885,7 @@ static int snd_echo_create(struct snd_card *card,
chip->can_set_rate = 1;
/* PCI resource allocation */
- err = pci_request_regions(pci, ECHOCARD_NAME);
+ err = pcim_request_all_regions(pci, ECHOCARD_NAME);
if (err < 0)
return err;
@@ -1977,7 +1941,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)
@@ -1987,7 +1950,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)
@@ -1998,8 +1960,8 @@ static int __snd_echo_probe(struct pci_dev *pci,
if (err < 0)
return err;
- strcpy(card->driver, "Echo_" ECHOCARD_NAME);
- strcpy(card->shortname, chip->card_name);
+ strscpy(card->driver, "Echo_" ECHOCARD_NAME);
+ strscpy(card->shortname, chip->card_name);
dsp = "56301";
if (pci_id->device == 0x3410)
@@ -2091,7 +2053,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;
@@ -2103,7 +2065,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;
@@ -2146,8 +2108,6 @@ static int snd_echo_probe(struct pci_dev *pci,
}
-#if defined(CONFIG_PM_SLEEP)
-
static int snd_echo_suspend(struct device *dev)
{
struct echoaudio *chip = dev_get_drvdata(dev);
@@ -2157,17 +2117,13 @@ static int snd_echo_suspend(struct device *dev)
if (chip->midi_out)
snd_echo_midi_output_trigger(chip->midi_out, 0);
#endif
- spin_lock_irq(&chip->lock);
- if (wait_handshake(chip)) {
- spin_unlock_irq(&chip->lock);
- return -EIO;
- }
- clear_handshake(chip);
- if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) {
- spin_unlock_irq(&chip->lock);
- return -EIO;
+ scoped_guard(spinlock_irq, &chip->lock) {
+ if (wait_handshake(chip))
+ return -EIO;
+ clear_handshake(chip);
+ if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0)
+ return -EIO;
}
- spin_unlock_irq(&chip->lock);
chip->dsp_code = NULL;
free_irq(chip->irq, chip);
@@ -2237,11 +2193,7 @@ static int snd_echo_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
-#define SND_ECHO_PM_OPS &snd_echo_pm
-#else
-#define SND_ECHO_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
/******************************************************************************
Everything starts and ends here
@@ -2253,7 +2205,7 @@ static struct pci_driver echo_driver = {
.id_table = snd_echo_ids,
.probe = snd_echo_probe,
.driver = {
- .pm = SND_ECHO_PM_OPS,
+ .pm = &snd_echo_pm,
},
};
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index d51de3e4edfa..511f2fcc0fb9 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -422,9 +422,7 @@ struct echoaudio {
u32 __iomem *dsp_registers; /* DSP's register base */
u32 active_mask; /* Chs. active mask or
* punks out */
-#ifdef CONFIG_PM_SLEEP
const struct firmware *fw_cache[8]; /* Cached firmwares */
-#endif
#ifdef ECHOCARD_HAS_MIDI
u16 mtc_state; /* State for MIDI input parsing state machine */
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index cc3c79387194..c9ee98ea3c71 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -119,7 +119,7 @@ static int set_digital_mode(struct echoaudio *chip, u8 mode)
* updated by the DSP comm object. */
if (err >= 0 && previous_mode != mode &&
(previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
for (o = 0; o < num_busses_out(chip); o++)
for (i = 0; i < num_busses_in(chip); i++)
set_monitor_gain(chip, o, i,
@@ -134,7 +134,6 @@ static int set_digital_mode(struct echoaudio *chip, u8 mode)
for (o = 0; o < num_busses_out(chip); o++)
set_output_gain(chip, o, chip->output_gain[o]);
update_output_line_level(chip);
- spin_unlock_irq(&chip->lock);
}
return err;
@@ -274,7 +273,6 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->digital_mode == DIGITAL_MODE_ADAT))
return -EINVAL;
- clock = 0;
control_reg = le32_to_cpu(chip->comm_page->control_register);
control_reg &= E3G_CLOCK_CLEAR_MASK;
@@ -397,7 +395,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return -EINVAL;
}
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
if (incompatible_clock) {
chip->sample_rate = 48000;
@@ -423,7 +421,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
}
err = write_control_reg(chip, control_reg, get_frq_reg(chip), 1);
- spin_unlock_irq(&chip->lock);
if (err < 0)
return err;
chip->digital_mode = mode;
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c
index 56e9d1b9b330..78fbac9f3eac 100644
--- a/sound/pci/echoaudio/gina24_dsp.c
+++ b/sound/pci/echoaudio/gina24_dsp.c
@@ -305,7 +305,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return -EINVAL;
}
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
if (incompatible_clock) { /* Switch to 48KHz, internal */
chip->sample_rate = 48000;
@@ -336,7 +336,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
}
err = write_control_reg(chip, control_reg, true);
- spin_unlock_irq(&chip->lock);
if (err < 0)
return err;
chip->digital_mode = mode;
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index ef27805d63f6..decfccb1e803 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -358,16 +358,15 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
if (incompatible_clock) { /* Switch to 48KHz, internal */
chip->sample_rate = 48000;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
set_input_clock(chip, ECHO_CLOCK_INTERNAL);
- spin_unlock_irq(&chip->lock);
}
/* switch_asic() can sleep */
if (switch_asic(chip, asic) < 0)
return -EIO;
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
/* Tweak the control register */
control_reg = le32_to_cpu(chip->comm_page->control_register);
@@ -387,7 +386,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
}
err = write_control_reg(chip, control_reg, true);
- spin_unlock_irq(&chip->lock);
if (err < 0)
return err;
chip->digital_mode = mode;
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index 47b2c023ee3d..dd5212644844 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -167,9 +167,8 @@ static void snd_echo_midi_input_trigger(struct snd_rawmidi_substream *substream,
struct echoaudio *chip = substream->rmidi->private_data;
if (up != chip->midi_input_enabled) {
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
enable_midi_input(chip, up);
- spin_unlock_irq(&chip->lock);
chip->midi_input_enabled = up;
}
}
@@ -200,15 +199,14 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream)
static void snd_echo_midi_output_write(struct timer_list *t)
{
- struct echoaudio *chip = from_timer(chip, t, timer);
- unsigned long flags;
+ struct echoaudio *chip = timer_container_of(chip, t, timer);
int bytes, sent, time;
unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1];
/* No interrupts are involved: we have to check at regular intervals
if the card's output buffer has room for new data. */
sent = 0;
- spin_lock_irqsave(&chip->lock, flags);
+ guard(spinlock_irqsave)(&chip->lock);
chip->midi_full = 0;
if (!snd_rawmidi_transmit_empty(chip->midi_out)) {
bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
@@ -242,7 +240,6 @@ static void snd_echo_midi_output_write(struct timer_list *t)
dev_dbg(chip->card->dev,
"Timer armed(%d)\n", ((time * HZ + 999) / 1000));
}
- spin_unlock_irqrestore(&chip->lock, flags);
}
@@ -251,25 +248,29 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
int up)
{
struct echoaudio *chip = substream->rmidi->private_data;
+ bool remove_timer = false;
dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up);
- spin_lock_irq(&chip->lock);
- if (up) {
- if (!chip->tinuse) {
- timer_setup(&chip->timer, snd_echo_midi_output_write,
- 0);
- chip->tinuse = 1;
- }
- } else {
- if (chip->tinuse) {
- chip->tinuse = 0;
- spin_unlock_irq(&chip->lock);
- del_timer_sync(&chip->timer);
- dev_dbg(chip->card->dev, "Timer removed\n");
- return;
+ scoped_guard(spinlock_irq, &chip->lock) {
+ if (up) {
+ if (!chip->tinuse) {
+ timer_setup(&chip->timer, snd_echo_midi_output_write,
+ 0);
+ chip->tinuse = 1;
+ }
+ } else {
+ if (chip->tinuse) {
+ chip->tinuse = 0;
+ remove_timer = true;
+ }
}
}
- spin_unlock_irq(&chip->lock);
+
+ if (remove_timer) {
+ timer_delete_sync(&chip->timer);
+ dev_dbg(chip->card->dev, "Timer removed\n");
+ return;
+ }
if (up && !chip->midi_full)
snd_echo_midi_output_write(&chip->timer);
@@ -311,7 +312,7 @@ static int snd_echo_midi_create(struct snd_card *card,
if (err < 0)
return err;
- strcpy(chip->rmidi->name, card->shortname);
+ strscpy(chip->rmidi->name, card->shortname);
chip->rmidi->private_data = chip;
snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c
index f8e7bb6ce040..9bb6a174745c 100644
--- a/sound/pci/echoaudio/mona_dsp.c
+++ b/sound/pci/echoaudio/mona_dsp.c
@@ -381,7 +381,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return -EINVAL;
}
- spin_lock_irq(&chip->lock);
+ guard(spinlock_irq)(&chip->lock);
if (incompatible_clock) { /* Switch to 48KHz, internal */
chip->sample_rate = 48000;
@@ -413,7 +413,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
}
err = write_control_reg(chip, control_reg, false);
- spin_unlock_irq(&chip->lock);
if (err < 0)
return err;
chip->digital_mode = mode;
diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile
index 17d5527be319..1f325abcb3ef 100644
--- a/sound/pci/emu10k1/Makefile
+++ b/sound/pci/emu10k1/Makefile
@@ -4,12 +4,12 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-emu10k1-objs := emu10k1.o emu10k1_main.o \
+snd-emu10k1-y := emu10k1.o emu10k1_main.o \
irq.o memory.o voice.o emumpu401.o emupcm.o io.o \
emumixer.o emufx.o timer.o p16v.o
snd-emu10k1-$(CONFIG_SND_PROC_FS) += emuproc.o
-snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o
-snd-emu10k1x-objs := emu10k1x.o
+snd-emu10k1-synth-y := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o
+snd-emu10k1x-y := emu10k1x.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index b8163f26004a..548e7d049901 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -2,13 +2,12 @@
/*
* The driver for the EMU10K1 (SB Live!) based soundcards
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
- * Added support for Audigy 2 Value.
+ * James Courtier-Dutton <James@superbug.co.uk>
*/
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/string.h>
#include <linux/time.h>
#include <linux/module.h>
#include <sound/core.h>
@@ -34,7 +33,6 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
static bool enable_ir[SNDRV_CARDS];
static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
-static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
@@ -56,8 +54,6 @@ module_param_array(enable_ir, bool, NULL, 0444);
MODULE_PARM_DESC(enable_ir, "Enable IR.");
module_param_array(subsystem, uint, NULL, 0444);
MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
-module_param_array(delay_pcm_irq, uint, NULL, 0444);
-MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0).");
/*
* Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400
*/
@@ -103,13 +99,14 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
enable_ir[dev], subsystem[dev]);
if (err < 0)
return err;
- emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
err = snd_emu10k1_pcm(emu, 0);
if (err < 0)
return err;
- err = snd_emu10k1_pcm_mic(emu, 1);
- if (err < 0)
- return err;
+ if (emu->card_capabilities->ac97_chip) {
+ err = snd_emu10k1_pcm_mic(emu, 1);
+ if (err < 0)
+ return err;
+ }
err = snd_emu10k1_pcm_efx(emu, 2);
if (err < 0)
return err;
@@ -158,7 +155,7 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
} else {
struct snd_emu10k1_synth_arg *arg;
arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
- strcpy(wave->name, "Emu-10k1 Synth");
+ strscpy(wave->name, "Emu-10k1 Synth");
arg->hwptr = emu;
arg->index = 1;
arg->seq_ports = seq_ports[dev];
@@ -178,9 +175,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
if (err < 0)
return err;
- if (emu->card_capabilities->emu_model)
- schedule_delayed_work(&emu->emu1010.firmware_work, 0);
-
pci_set_drvdata(pci, card);
dev++;
return 0;
@@ -196,7 +190,7 @@ static int snd_emu10k1_suspend(struct device *dev)
emu->suspend = 1;
- cancel_delayed_work_sync(&emu->emu1010.firmware_work);
+ cancel_work_sync(&emu->emu1010.work);
snd_ac97_suspend(emu->ac97);
@@ -226,9 +220,6 @@ static int snd_emu10k1_resume(struct device *dev)
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- if (emu->card_capabilities->emu_model)
- schedule_delayed_work(&emu->emu1010.firmware_work, 0);
-
return 0;
}
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index 9455df18f7b2..ef26e4d3e2a3 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -33,9 +33,9 @@ static void release_voice(struct snd_emux_voice *vp);
static void update_voice(struct snd_emux_voice *vp, int update);
static void terminate_voice(struct snd_emux_voice *vp);
static void free_voice(struct snd_emux_voice *vp);
-static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
-static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
-static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
+static u32 make_fmmod(struct snd_emux_voice *vp);
+static u32 make_fm2frq2(struct snd_emux_voice *vp);
+static int get_pitch_shift(struct snd_emux *emu);
/*
* Ensure a value is between two points
@@ -59,6 +59,7 @@ static const struct snd_emux_operators emu10k1_ops = {
.free_voice = free_voice,
.sample_new = snd_emu10k1_sample_new,
.sample_free = snd_emu10k1_sample_free,
+ .get_pitch_shift = get_pitch_shift,
};
void
@@ -116,14 +117,13 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
static void
release_voice(struct snd_emux_voice *vp)
{
- int dcysusv;
struct snd_emu10k1 *hw;
hw = vp->hw;
- dcysusv = (unsigned char)vp->reg.parm.modrelease | DCYSUSM_PHASE1_MASK;
- snd_emu10k1_ptr_write(hw, DCYSUSM, vp->ch, dcysusv);
- dcysusv = (unsigned char)vp->reg.parm.volrelease | DCYSUSV_PHASE1_MASK | DCYSUSV_CHANNELENABLE_MASK;
- snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, dcysusv);
+ snd_emu10k1_ptr_write_multiple(hw, vp->ch,
+ DCYSUSM, (unsigned char)vp->reg.parm.modrelease | DCYSUSM_PHASE1_MASK,
+ DCYSUSV, (unsigned char)vp->reg.parm.volrelease | DCYSUSV_PHASE1_MASK | DCYSUSV_CHANNELENABLE_MASK,
+ REGLIST_END);
}
@@ -138,8 +138,13 @@ terminate_voice(struct snd_emux_voice *vp)
if (snd_BUG_ON(!vp))
return;
hw = vp->hw;
- snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch,
- DCYSUSV_PHASE1_MASK | DCYSUSV_DECAYTIME_MASK | DCYSUSV_CHANNELENABLE_MASK);
+ snd_emu10k1_ptr_write_multiple(hw, vp->ch,
+ DCYSUSV, 0,
+ VTFT, VTFT_FILTERTARGET_MASK,
+ CVCF, CVCF_CURRENTFILTER_MASK,
+ PTRX, 0,
+ CPF, 0,
+ REGLIST_END);
if (vp->block) {
struct snd_emu10k1_memblk *emem;
emem = (struct snd_emu10k1_memblk *)vp->block;
@@ -162,11 +167,6 @@ free_voice(struct snd_emux_voice *vp)
/* Problem apparent on plug, unplug then plug */
/* on the Audigy 2 ZS Notebook. */
if (hw && (vp->ch >= 0)) {
- snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00);
- snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK);
- // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0);
- snd_emu10k1_ptr_write(hw, VTFT, vp->ch, 0xffff);
- snd_emu10k1_ptr_write(hw, CVCF, vp->ch, 0xffff);
snd_emu10k1_voice_free(hw, &hw->voices[vp->ch]);
vp->emu->num_voices--;
vp->ch = -1;
@@ -192,13 +192,13 @@ update_voice(struct snd_emux_voice *vp, int update)
snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_B, vp->ch, vp->aaux);
}
if (update & SNDRV_EMUX_UPDATE_FMMOD)
- set_fmmod(hw, vp);
+ snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, make_fmmod(vp));
if (update & SNDRV_EMUX_UPDATE_TREMFREQ)
snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq);
if (update & SNDRV_EMUX_UPDATE_FM2FRQ2)
- set_fm2frq2(hw, vp);
+ snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, make_fm2frq2(vp));
if (update & SNDRV_EMUX_UPDATE_Q)
- set_filterQ(hw, vp);
+ snd_emu10k1_ptr_write(hw, CCCA_RESONANCE, vp->ch, vp->reg.parm.filterQ);
}
@@ -255,7 +255,7 @@ lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,
/* check if sample is finished playing (non-looping only) */
if (bp != best + V_OFF && bp != best + V_FREE &&
(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {
- val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch);
+ val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64 + 3;
if (val >= vp->reg.loopstart)
bp = best + V_OFF;
}
@@ -289,7 +289,7 @@ get_voice(struct snd_emux *emu, struct snd_emux_port *port)
if (vp->ch < 0) {
/* allocate a voice */
struct snd_emu10k1_voice *hwvoice;
- if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, &hwvoice) < 0 || hwvoice == NULL)
+ if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, 1, NULL, &hwvoice) < 0)
continue;
vp->ch = hwvoice->number;
emu->num_voices++;
@@ -310,6 +310,8 @@ start_voice(struct snd_emux_voice *vp)
{
unsigned int temp;
int ch;
+ bool w_16;
+ u32 psst, dsl, map, ccca, vtarget;
unsigned int addr, mapped_offset;
struct snd_midi_channel *chan;
struct snd_emu10k1 *hw;
@@ -320,6 +322,7 @@ start_voice(struct snd_emux_voice *vp)
if (snd_BUG_ON(ch < 0))
return -EINVAL;
chan = vp->chan;
+ w_16 = !(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS);
emem = (struct snd_emu10k1_memblk *)vp->block;
if (emem == NULL)
@@ -329,7 +332,7 @@ start_voice(struct snd_emux_voice *vp)
/* dev_err(hw->card->devK, "emu: cannot map!\n"); */
return -ENOMEM;
}
- mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1;
+ mapped_offset = snd_emu10k1_memblk_offset(emem) >> w_16;
vp->reg.start += mapped_offset;
vp->reg.end += mapped_offset;
vp->reg.loopstart += mapped_offset;
@@ -347,114 +350,98 @@ start_voice(struct snd_emux_voice *vp)
snd_emu10k1_ptr_write(hw, FXRT, ch, temp);
}
- /* channel to be silent and idle */
- snd_emu10k1_ptr_write(hw, DCYSUSV, ch, 0);
- snd_emu10k1_ptr_write(hw, VTFT, ch, VTFT_FILTERTARGET_MASK);
- snd_emu10k1_ptr_write(hw, CVCF, ch, CVCF_CURRENTFILTER_MASK);
- snd_emu10k1_ptr_write(hw, PTRX, ch, 0);
- snd_emu10k1_ptr_write(hw, CPF, ch, 0);
-
- /* set pitch offset */
- snd_emu10k1_ptr_write(hw, IP, vp->ch, vp->apitch);
-
- /* set envelope parameters */
- snd_emu10k1_ptr_write(hw, ENVVAL, ch, vp->reg.parm.moddelay);
- snd_emu10k1_ptr_write(hw, ATKHLDM, ch, vp->reg.parm.modatkhld);
- snd_emu10k1_ptr_write(hw, DCYSUSM, ch, vp->reg.parm.moddcysus);
- snd_emu10k1_ptr_write(hw, ENVVOL, ch, vp->reg.parm.voldelay);
- snd_emu10k1_ptr_write(hw, ATKHLDV, ch, vp->reg.parm.volatkhld);
- /* decay/sustain parameter for volume envelope is used
- for triggerg the voice */
-
- /* cutoff and volume */
- temp = (unsigned int)vp->acutoff << 8 | (unsigned char)vp->avol;
- snd_emu10k1_ptr_write(hw, IFATN, vp->ch, temp);
-
- /* modulation envelope heights */
- snd_emu10k1_ptr_write(hw, PEFE, ch, vp->reg.parm.pefe);
-
- /* lfo1/2 delay */
- snd_emu10k1_ptr_write(hw, LFOVAL1, ch, vp->reg.parm.lfo1delay);
- snd_emu10k1_ptr_write(hw, LFOVAL2, ch, vp->reg.parm.lfo2delay);
-
- /* lfo1 pitch & cutoff shift */
- set_fmmod(hw, vp);
- /* lfo1 volume & freq */
- snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq);
- /* lfo2 pitch & freq */
- set_fm2frq2(hw, vp);
-
- /* reverb and loop start (reverb 8bit, MSB) */
temp = vp->reg.parm.reverb;
temp += (int)vp->chan->control[MIDI_CTL_E1_REVERB_DEPTH] * 9 / 10;
LIMITMAX(temp, 255);
addr = vp->reg.loopstart;
- snd_emu10k1_ptr_write(hw, PSST, vp->ch, (temp << 24) | addr);
+ psst = (temp << 24) | addr;
- /* chorus & loop end (chorus 8bit, MSB) */
addr = vp->reg.loopend;
temp = vp->reg.parm.chorus;
temp += (int)chan->control[MIDI_CTL_E3_CHORUS_DEPTH] * 9 / 10;
LIMITMAX(temp, 255);
- temp = (temp <<24) | addr;
- snd_emu10k1_ptr_write(hw, DSL, ch, temp);
+ dsl = (temp << 24) | addr;
- /* clear filter delay memory */
- snd_emu10k1_ptr_write(hw, Z1, ch, 0);
- snd_emu10k1_ptr_write(hw, Z2, ch, 0);
+ map = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
- /* invalidate maps */
- temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
- snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
- snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
-#if 0
- /* cache */
- {
- unsigned int val, sample;
- val = 32;
- if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS)
- sample = 0x80808080;
- else {
- sample = 0;
- val *= 2;
- }
-
- /* cache */
- snd_emu10k1_ptr_write(hw, CCR, ch, 0x1c << 16);
- snd_emu10k1_ptr_write(hw, CDE, ch, sample);
- snd_emu10k1_ptr_write(hw, CDF, ch, sample);
-
- /* invalidate maps */
- temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
- snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
- snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
-
- /* fill cache */
- val -= 4;
- val <<= 25;
- val |= 0x1c << 16;
- snd_emu10k1_ptr_write(hw, CCR, ch, val);
- }
-#endif
-
- /* Q & current address (Q 4bit value, MSB) */
- addr = vp->reg.start;
+ addr = vp->reg.start + 64 - 3;
temp = vp->reg.parm.filterQ;
- temp = (temp<<28) | addr;
+ ccca = (temp << 28) | addr;
if (vp->apitch < 0xe400)
- temp |= CCCA_INTERPROM_0;
+ ccca |= CCCA_INTERPROM_0;
else {
unsigned int shift = (vp->apitch - 0xe000) >> 10;
- temp |= shift << 25;
+ ccca |= shift << 25;
}
- if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS)
- temp |= CCCA_8BITSELECT;
- snd_emu10k1_ptr_write(hw, CCCA, ch, temp);
-
- /* reset volume */
- temp = (unsigned int)vp->vtarget << 16;
- snd_emu10k1_ptr_write(hw, VTFT, ch, temp | vp->ftarget);
- snd_emu10k1_ptr_write(hw, CVCF, ch, temp | CVCF_CURRENTFILTER_MASK);
+ if (!w_16)
+ ccca |= CCCA_8BITSELECT;
+
+ vtarget = (unsigned int)vp->vtarget << 16;
+
+ snd_emu10k1_ptr_write_multiple(hw, ch,
+ /* channel to be silent and idle */
+ DCYSUSV, 0,
+ VTFT, VTFT_FILTERTARGET_MASK,
+ CVCF, CVCF_CURRENTFILTER_MASK,
+ PTRX, 0,
+ CPF, 0,
+
+ /* set pitch offset */
+ IP, vp->apitch,
+
+ /* set envelope parameters */
+ ENVVAL, vp->reg.parm.moddelay,
+ ATKHLDM, vp->reg.parm.modatkhld,
+ DCYSUSM, vp->reg.parm.moddcysus,
+ ENVVOL, vp->reg.parm.voldelay,
+ ATKHLDV, vp->reg.parm.volatkhld,
+ /* decay/sustain parameter for volume envelope is used
+ for triggerg the voice */
+
+ /* cutoff and volume */
+ IFATN, (unsigned int)vp->acutoff << 8 | (unsigned char)vp->avol,
+
+ /* modulation envelope heights */
+ PEFE, vp->reg.parm.pefe,
+
+ /* lfo1/2 delay */
+ LFOVAL1, vp->reg.parm.lfo1delay,
+ LFOVAL2, vp->reg.parm.lfo2delay,
+
+ /* lfo1 pitch & cutoff shift */
+ FMMOD, make_fmmod(vp),
+ /* lfo1 volume & freq */
+ TREMFRQ, vp->reg.parm.tremfrq,
+ /* lfo2 pitch & freq */
+ FM2FRQ2, make_fm2frq2(vp),
+
+ /* reverb and loop start (reverb 8bit, MSB) */
+ PSST, psst,
+
+ /* chorus & loop end (chorus 8bit, MSB) */
+ DSL, dsl,
+
+ /* clear filter delay memory */
+ Z1, 0,
+ Z2, 0,
+
+ /* invalidate maps */
+ MAPA, map,
+ MAPB, map,
+
+ /* Q & current address (Q 4bit value, MSB) */
+ CCCA, ccca,
+
+ /* cache */
+ CCR, REG_VAL_PUT(CCR_CACHEINVALIDSIZE, 64),
+
+ /* reset volume */
+ VTFT, vtarget | vp->ftarget,
+ CVCF, vtarget | CVCF_CURRENTFILTER_MASK,
+
+ REGLIST_END);
+
+ hw->voices[ch].dirty = 1;
return 0;
}
@@ -464,7 +451,7 @@ start_voice(struct snd_emux_voice *vp)
static void
trigger_voice(struct snd_emux_voice *vp)
{
- unsigned int temp, ptarget;
+ unsigned int ptarget;
struct snd_emu10k1 *hw;
struct snd_emu10k1_memblk *emem;
@@ -479,24 +466,25 @@ trigger_voice(struct snd_emux_voice *vp)
#else
ptarget = IP_TO_CP(vp->apitch);
#endif
- /* set pitch target and pan (volume) */
- temp = ptarget | (vp->apan << 8) | vp->aaux;
- snd_emu10k1_ptr_write(hw, PTRX, vp->ch, temp);
+ snd_emu10k1_ptr_write_multiple(hw, vp->ch,
+ /* set pitch target and pan (volume) */
+ PTRX, ptarget | (vp->apan << 8) | vp->aaux,
- /* pitch target */
- snd_emu10k1_ptr_write(hw, CPF, vp->ch, ptarget);
+ /* current pitch and fractional address */
+ CPF, ptarget,
- /* trigger voice */
- snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, vp->reg.parm.voldcysus|DCYSUSV_CHANNELENABLE_MASK);
+ /* enable envelope engine */
+ DCYSUSV, vp->reg.parm.voldcysus | DCYSUSV_CHANNELENABLE_MASK,
+
+ REGLIST_END);
}
#define MOD_SENSE 18
-/* set lfo1 modulation height and cutoff */
-static void
-set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp)
+/* calculate lfo1 modulation height and cutoff register */
+static u32
+make_fmmod(struct snd_emux_voice *vp)
{
- unsigned short fmmod;
short pitch;
unsigned char cutoff;
int modulation;
@@ -506,15 +494,13 @@ set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp)
modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;
pitch += (MOD_SENSE * modulation) / 1200;
LIMITVALUE(pitch, -128, 127);
- fmmod = ((unsigned char)pitch<<8) | cutoff;
- snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, fmmod);
+ return ((unsigned char)pitch << 8) | cutoff;
}
-/* set lfo2 pitch & frequency */
-static void
-set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp)
+/* calculate set lfo2 pitch & frequency register */
+static u32
+make_fm2frq2(struct snd_emux_voice *vp)
{
- unsigned short fm2frq2;
short pitch;
unsigned char freq;
int modulation;
@@ -524,13 +510,13 @@ set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp)
modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;
pitch += (MOD_SENSE * modulation) / 1200;
LIMITVALUE(pitch, -128, 127);
- fm2frq2 = ((unsigned char)pitch<<8) | freq;
- snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, fm2frq2);
+ return ((unsigned char)pitch << 8) | freq;
}
-/* set filterQ */
-static void
-set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp)
+static int get_pitch_shift(struct snd_emux *emu)
{
- snd_emu10k1_ptr_write(hw, CCCA_RESONANCE, vp->ch, vp->reg.parm.filterQ);
+ struct snd_emu10k1 *hw = emu->hw;
+
+ return (hw->card_capabilities->emu_model &&
+ hw->emu1010.word_clock == 44100) ? 0 : -501;
}
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 192208c291d6..b2fe2d164ba8 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1,19 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * James Courtier-Dutton <James@superbug.co.uk>
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
* Creative Labs, Inc.
- * Routines for control of EMU10K1 chips
- *
- * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
- * Added support for Audigy 2 Value.
- * Added EMU 1010 support.
- * General bug fixes and enhancements.
*
- * BUGS:
- * --
- *
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips
*/
#include <linux/sched.h>
@@ -57,46 +49,49 @@ MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch)
{
- snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0);
- snd_emu10k1_ptr_write(emu, IP, ch, 0);
- snd_emu10k1_ptr_write(emu, VTFT, ch, VTFT_FILTERTARGET_MASK);
- snd_emu10k1_ptr_write(emu, CVCF, ch, CVCF_CURRENTFILTER_MASK);
- snd_emu10k1_ptr_write(emu, PTRX, ch, 0);
- snd_emu10k1_ptr_write(emu, CPF, ch, 0);
- snd_emu10k1_ptr_write(emu, CCR, ch, 0);
-
- snd_emu10k1_ptr_write(emu, PSST, ch, 0);
- snd_emu10k1_ptr_write(emu, DSL, ch, 0x10);
- snd_emu10k1_ptr_write(emu, CCCA, ch, 0);
- snd_emu10k1_ptr_write(emu, Z1, ch, 0);
- snd_emu10k1_ptr_write(emu, Z2, ch, 0);
- snd_emu10k1_ptr_write(emu, FXRT, ch, 0x32100000);
-
- snd_emu10k1_ptr_write(emu, ATKHLDM, ch, 0);
- snd_emu10k1_ptr_write(emu, DCYSUSM, ch, 0);
- snd_emu10k1_ptr_write(emu, IFATN, ch, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
- snd_emu10k1_ptr_write(emu, PEFE, ch, 0);
- snd_emu10k1_ptr_write(emu, FMMOD, ch, 0);
- snd_emu10k1_ptr_write(emu, TREMFRQ, ch, 24); /* 1 Hz */
- snd_emu10k1_ptr_write(emu, FM2FRQ2, ch, 24); /* 1 Hz */
- snd_emu10k1_ptr_write(emu, TEMPENV, ch, 0);
-
- /*** these are last so OFF prevents writing ***/
- snd_emu10k1_ptr_write(emu, LFOVAL2, ch, 0);
- snd_emu10k1_ptr_write(emu, LFOVAL1, ch, 0);
- snd_emu10k1_ptr_write(emu, ATKHLDV, ch, 0);
- snd_emu10k1_ptr_write(emu, ENVVOL, ch, 0);
- snd_emu10k1_ptr_write(emu, ENVVAL, ch, 0);
+ snd_emu10k1_ptr_write_multiple(emu, ch,
+ DCYSUSV, 0,
+ VTFT, VTFT_FILTERTARGET_MASK,
+ CVCF, CVCF_CURRENTFILTER_MASK,
+ PTRX, 0,
+ CPF, 0,
+ CCR, 0,
+
+ PSST, 0,
+ DSL, 0x10,
+ CCCA, 0,
+ Z1, 0,
+ Z2, 0,
+ FXRT, 0x32100000,
+
+ // The rest is meaningless as long as DCYSUSV_CHANNELENABLE_MASK is zero
+ DCYSUSM, 0,
+ ATKHLDV, 0,
+ ATKHLDM, 0,
+ IP, 0,
+ IFATN, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK,
+ PEFE, 0,
+ FMMOD, 0,
+ TREMFRQ, 24, /* 1 Hz */
+ FM2FRQ2, 24, /* 1 Hz */
+ LFOVAL2, 0,
+ LFOVAL1, 0,
+ ENVVOL, 0,
+ ENVVAL, 0,
+
+ REGLIST_END);
/* Audigy extra stuffs */
if (emu->audigy) {
- snd_emu10k1_ptr_write(emu, A_CSBA, ch, 0);
- snd_emu10k1_ptr_write(emu, A_CSDC, ch, 0);
- snd_emu10k1_ptr_write(emu, A_CSFE, ch, 0);
- snd_emu10k1_ptr_write(emu, A_CSHG, ch, 0);
- snd_emu10k1_ptr_write(emu, A_FXRT1, ch, 0x03020100);
- snd_emu10k1_ptr_write(emu, A_FXRT2, ch, 0x3f3f3f3f);
- snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, ch, 0);
+ snd_emu10k1_ptr_write_multiple(emu, ch,
+ A_CSBA, 0,
+ A_CSDC, 0,
+ A_CSFE, 0,
+ A_CSHG, 0,
+ A_FXRT1, 0x03020100,
+ A_FXRT2, 0x07060504,
+ A_SENDAMOUNTS, 0,
+ REGLIST_END);
}
}
@@ -150,22 +145,26 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir)
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK |
HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
- /* reset recording buffers */
- snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE);
- snd_emu10k1_ptr_write(emu, MICBA, 0, 0);
- snd_emu10k1_ptr_write(emu, FXBS, 0, ADCBS_BUFSIZE_NONE);
- snd_emu10k1_ptr_write(emu, FXBA, 0, 0);
- snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE);
- snd_emu10k1_ptr_write(emu, ADCBA, 0, 0);
-
- /* disable channel interrupt */
outl(0, emu->port + INTE);
- snd_emu10k1_ptr_write(emu, CLIEL, 0, 0);
- snd_emu10k1_ptr_write(emu, CLIEH, 0, 0);
- /* disable stop on loop end */
- snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);
- snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ /* reset recording buffers */
+ MICBS, ADCBS_BUFSIZE_NONE,
+ MICBA, 0,
+ FXBS, ADCBS_BUFSIZE_NONE,
+ FXBA, 0,
+ ADCBS, ADCBS_BUFSIZE_NONE,
+ ADCBA, 0,
+
+ /* disable channel interrupt */
+ CLIEL, 0,
+ CLIEH, 0,
+
+ /* disable stop on loop end */
+ SOLEL, 0,
+ SOLEH, 0,
+
+ REGLIST_END);
if (emu->audigy) {
/* set SPDIF bypass mode */
@@ -179,9 +178,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir)
for (ch = 0; ch < NUM_G; ch++)
snd_emu10k1_voice_init(emu, ch);
- snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0]);
- snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1]);
- snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2]);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ SPCS0, emu->spdif_bits[0],
+ SPCS1, emu->spdif_bits[1],
+ SPCS2, emu->spdif_bits[2],
+ REGLIST_END);
if (emu->card_capabilities->emu_model) {
} else if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
@@ -382,7 +383,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
}
#endif
- snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
+ if (emu->card_capabilities->emu_model)
+ snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE | INTE_A_GPIOENABLE);
+ else
+ snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
}
int snd_emu10k1_done(struct snd_emu10k1 *emu)
@@ -392,41 +396,48 @@ int snd_emu10k1_done(struct snd_emu10k1 *emu)
outl(0, emu->port + INTE);
/*
- * Shutdown the chip
+ * Shutdown the voices
*/
- for (ch = 0; ch < NUM_G; ch++)
- snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0);
for (ch = 0; ch < NUM_G; ch++) {
- snd_emu10k1_ptr_write(emu, VTFT, ch, 0);
- snd_emu10k1_ptr_write(emu, CVCF, ch, 0);
- snd_emu10k1_ptr_write(emu, PTRX, ch, 0);
- snd_emu10k1_ptr_write(emu, CPF, ch, 0);
+ snd_emu10k1_ptr_write_multiple(emu, ch,
+ DCYSUSV, 0,
+ VTFT, 0,
+ CVCF, 0,
+ PTRX, 0,
+ CPF, 0,
+ REGLIST_END);
}
- /* reset recording buffers */
- snd_emu10k1_ptr_write(emu, MICBS, 0, 0);
- snd_emu10k1_ptr_write(emu, MICBA, 0, 0);
- snd_emu10k1_ptr_write(emu, FXBS, 0, 0);
- snd_emu10k1_ptr_write(emu, FXBA, 0, 0);
- snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
- snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE);
- snd_emu10k1_ptr_write(emu, ADCBA, 0, 0);
- snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K);
- snd_emu10k1_ptr_write(emu, TCB, 0, 0);
+ // stop the DSP
if (emu->audigy)
snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP);
else
snd_emu10k1_ptr_write(emu, DBG, 0, EMU10K1_DBG_SINGLE_STEP);
- /* disable channel interrupt */
- snd_emu10k1_ptr_write(emu, CLIEL, 0, 0);
- snd_emu10k1_ptr_write(emu, CLIEH, 0, 0);
- snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);
- snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ /* reset recording buffers */
+ MICBS, 0,
+ MICBA, 0,
+ FXBS, 0,
+ FXBA, 0,
+ FXWC, 0,
+ ADCBS, ADCBS_BUFSIZE_NONE,
+ ADCBA, 0,
+ TCBS, TCBS_BUFFSIZE_16K,
+ TCB, 0,
+
+ /* disable channel interrupt */
+ CLIEL, 0,
+ CLIEH, 0,
+ SOLEL, 0,
+ SOLEH, 0,
+
+ PTB, 0,
+
+ REGLIST_END);
/* disable audio and lock cache */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
- snd_emu10k1_ptr_write(emu, PTB, 0, 0);
return 0;
}
@@ -641,53 +652,6 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
return 0;
}
-static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
- const struct firmware *fw_entry)
-{
- int n, i;
- u16 reg;
- u8 value;
- __always_unused u16 write_post;
- unsigned long flags;
-
- if (!fw_entry)
- return -EIO;
-
- /* The FPGA is a Xilinx Spartan IIE XC2S50E */
- /* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */
- /* GPIO7 -> FPGA PGMN
- * GPIO6 -> FPGA CCLK
- * GPIO5 -> FPGA DIN
- * FPGA CONFIG OFF -> FPGA PGMN
- */
- spin_lock_irqsave(&emu->emu_lock, flags);
- outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */
- write_post = inw(emu->port + A_GPIO);
- udelay(100);
- outw(0x80, emu->port + A_GPIO); /* Leave bit 7 set during netlist setup. */
- write_post = inw(emu->port + A_GPIO);
- udelay(100); /* Allow FPGA memory to clean */
- for (n = 0; n < fw_entry->size; n++) {
- value = fw_entry->data[n];
- for (i = 0; i < 8; i++) {
- reg = 0x80;
- if (value & 0x1)
- reg = reg | 0x20;
- value = value >> 1;
- outw(reg, emu->port + A_GPIO);
- write_post = inw(emu->port + A_GPIO);
- outw(reg | 0x40, emu->port + A_GPIO);
- write_post = inw(emu->port + A_GPIO);
- }
- }
- /* After programming, set GPIO bit 4 high again. */
- outw(0x10, emu->port + A_GPIO);
- write_post = inw(emu->port + A_GPIO);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
-
- return 0;
-}
-
/* firmware file names, per model, init-fw and dock-fw (optional) */
static const char * const firmware_names[5][2] = {
[EMU_MODEL_EMU1010] = {
@@ -719,73 +683,114 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
return err;
}
- return snd_emu1010_load_firmware_entry(emu, *fw);
+ snd_emu1010_load_firmware_entry(emu, dock, *fw);
+ return 0;
}
-static void emu1010_firmware_work(struct work_struct *work)
+static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
{
- struct snd_emu10k1 *emu;
- u32 tmp, tmp2, reg;
+ u32 tmp, tmp2;
int err;
- emu = container_of(work, struct snd_emu10k1,
- emu1010.firmware_work.work);
- if (emu->card->shutdown)
+ // The docking events clearly arrive prematurely - while the
+ // Dock's FPGA seems to be successfully programmed, the Dock
+ // fails to initialize subsequently if we don't give it some
+ // time to "warm up" here.
+ msleep(200);
+
+ dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
+ err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
+ if (err < 0)
return;
-#ifdef CONFIG_PM_SLEEP
- if (emu->suspend)
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
+ dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
+ if ((tmp & 0x1f) != 0x15) {
+ /* FPGA failed to be programmed */
+ dev_err(emu->card->dev,
+ "emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
+ tmp);
return;
-#endif
- snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
+ }
+ dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");
+
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
+ dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
+
+ /* Allow DLL to settle, to sync clocking between 1010 and Dock */
+ msleep(10);
+}
+
+static void emu1010_dock_event(struct snd_emu10k1 *emu)
+{
+ u32 reg;
+
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
- /* Return to Audio Dock programming mode */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware\n");
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
- EMU_HANA_FPGA_CONFIG_AUDIODOCK);
- err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
- if (err < 0)
- goto next;
-
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
- snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp);
- dev_info(emu->card->dev,
- "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp);
- /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
- dev_info(emu->card->dev,
- "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
- if ((tmp & 0x1f) != 0x15) {
- /* FPGA failed to be programmed */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
- tmp);
- goto next;
- }
- dev_info(emu->card->dev,
- "emu1010: Audio Dock Firmware loaded\n");
- snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
- snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
- dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
- /* Sync clocking between 1010 and Dock */
- /* Allow DLL to settle */
- msleep(10);
+ snd_emu1010_load_dock_firmware(emu);
/* Unmute all. Default is muted after a firmware load */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
- } else if (!reg && emu->emu1010.last_reg) {
+ } else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
/* Audio Dock removed */
dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
/* The hardware auto-mutes all, so we unmute again */
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
}
+}
+
+static void emu1010_clock_event(struct snd_emu10k1 *emu)
+{
+ struct snd_ctl_elem_id id;
- next:
- emu->emu1010.last_reg = reg;
- if (!emu->card->shutdown)
- schedule_delayed_work(&emu->emu1010.firmware_work,
- msecs_to_jiffies(1000));
+ scoped_guard(spinlock_irq, &emu->reg_lock) {
+ // This is the only thing that can actually happen.
+ emu->emu1010.clock_source = emu->emu1010.clock_fallback;
+ emu->emu1010.wclock = 1 - emu->emu1010.clock_source;
+ snd_emu1010_update_clock(emu);
+ }
+ snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0);
+ snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
+}
+
+static void emu1010_work(struct work_struct *work)
+{
+ struct snd_emu10k1 *emu;
+ u32 sts;
+
+ emu = container_of(work, struct snd_emu10k1, emu1010.work);
+ if (emu->card->shutdown)
+ return;
+#ifdef CONFIG_PM_SLEEP
+ if (emu->suspend)
+ return;
+#endif
+
+ guard(snd_emu1010_fpga_lock)(emu);
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
+
+ // The distinction of the IRQ status bits is unreliable,
+ // so we dispatch later based on option card status.
+ if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
+ emu1010_dock_event(emu);
+
+ if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
+ emu1010_clock_event(emu);
+}
+
+static void emu1010_interrupt(struct snd_emu10k1 *emu)
+{
+ // We get an interrupt on each GPIO input pin change, but we
+ // care only about the ones triggered by the dedicated pin.
+ u16 sts = inw(emu->port + A_GPIO);
+ u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
+ if (!(sts & bit))
+ return;
+
+ schedule_work(&emu->emu1010.work);
}
/*
@@ -798,7 +803,6 @@ static void emu1010_firmware_work(struct work_struct *work)
*/
static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
{
- unsigned int i;
u32 tmp, tmp2, reg;
int err;
@@ -808,28 +812,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
* Proper init follows in snd_emu10k1_init(). */
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
- /* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
-
- /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
- dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg);
- if ((reg & 0x3f) == 0x15) {
- /* FPGA netlist already present so clear it */
- /* Return to programming mode */
-
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_HANA);
- }
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
- dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg);
- if ((reg & 0x3f) == 0x15) {
- /* FPGA failed to return to programming mode */
- dev_info(emu->card->dev,
- "emu1010: FPGA failed to return to programming mode\n");
- return -ENODEV;
- }
- dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg);
+ guard(snd_emu1010_fpga_lock)(emu);
+ dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n");
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
if (err < 0) {
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
@@ -855,9 +840,16 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
- /* Optical -> ADAT I/O */
- emu->emu1010.optical_in = 1; /* IN_ADAT */
- emu->emu1010.optical_out = 1; /* OUT_ADAT */
+ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
+ snd_emu1010_load_dock_firmware(emu);
+ if (emu->card_capabilities->no_adat) {
+ emu->emu1010.optical_in = 0; /* IN_SPDIF */
+ emu->emu1010.optical_out = 0; /* OUT_SPDIF */
+ } else {
+ /* Optical -> ADAT I/O */
+ emu->emu1010.optical_in = 1; /* IN_ADAT */
+ emu->emu1010.optical_out = 1; /* OUT_ADAT */
+ }
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
@@ -875,267 +867,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
/* MIDI routing */
snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, EMU_HANA_MIDI_INA_FROM_HAMOA | EMU_HANA_MIDI_INB_FROM_DOCK2);
snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, EMU_HANA_MIDI_OUT_DOCK2 | EMU_HANA_MIDI_OUT_SYNC2);
- /* IRQ Enable: All on */
- /* snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x0f); */
- /* IRQ Enable: All off */
- snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
- emu->emu1010.internal_clock = 1; /* 48000 */
+ emu->gpio_interrupt = emu1010_interrupt;
+ // Note: The Audigy INTE is set later
+ snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE,
+ EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST | EMU_HANA_IRQ_WCLK_CHANGED);
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg); // Clear pending IRQs
+
+ emu->emu1010.clock_source = 1; /* 48000 */
+ emu->emu1010.clock_fallback = 1; /* 48000 */
/* Default WCLK set to 48kHz. */
snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K);
/* Word Clock source, Internal 48kHz x1 */
+ emu->emu1010.wclock = EMU_HANA_WCLOCK_INT_48K;
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
/* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
- /* Audio Dock LEDs. */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_LOCK | EMU_HANA_DOCK_LEDS_2_48K);
+ snd_emu1010_update_clock(emu);
-#if 0
- /* For 96kHz */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2);
-#endif
-#if 0
- /* For 192kHz */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4);
-#endif
-#if 1
- /* For 48kHz */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
- /* Pavel Hofman - setting defaults for 8 more capture channels
- * Defaults only, users will set their own values anyways, let's
- * just copy/paste.
- */
-
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_9, EMU_SRC_DOCK_MIC_B1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_A, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_B, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_ADC1_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_ADC1_RIGHT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_E, EMU_SRC_DOCK_ADC2_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_F, EMU_SRC_DOCK_ADC2_RIGHT1);
-#endif
-#if 0
- /* Original */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2);
-#endif
- for (i = 0; i < 0x20; i++) {
- /* AudioDock Elink <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE);
- }
- for (i = 0; i < 4; i++) {
- /* Hana SPDIF Out <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE);
- }
- for (i = 0; i < 7; i++) {
- /* Hamoa DAC <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE);
- }
- for (i = 0; i < 7; i++) {
- /* Hana ADAT Out <- Silence */
- snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE);
- }
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1);
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1);
+ // The routes are all set to EMU_SRC_SILENCE due to the reset,
+ // so it is safe to simply enable the outputs.
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
-#if 0
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */
-#endif
- /* Default outputs */
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
- /* 1616(M) cardbus default outputs */
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[0] = 17;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[1] = 18;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
- emu->emu1010.output_source[2] = 19;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
- emu->emu1010.output_source[3] = 20;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
- emu->emu1010.output_source[4] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
- emu->emu1010.output_source[5] = 22;
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_MANA_DAC_LEFT, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[16] = 17;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_MANA_DAC_RIGHT, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[17] = 18;
- } else {
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[0] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[1] = 22;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
- emu->emu1010.output_source[2] = 23;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
- emu->emu1010.output_source[3] = 24;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
- emu->emu1010.output_source[4] = 25;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
- emu->emu1010.output_source[5] = 26;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6);
- emu->emu1010.output_source[6] = 27;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7);
- emu->emu1010.output_source[7] = 28;
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[8] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[9] = 22;
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[10] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[11] = 22;
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[12] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[13] = 22;
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[14] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[15] = 22;
- /* ALICE2 bus 0xa0 */
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0);
- emu->emu1010.output_source[16] = 21;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1);
- emu->emu1010.output_source[17] = 22;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2);
- emu->emu1010.output_source[18] = 23;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3);
- emu->emu1010.output_source[19] = 24;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4);
- emu->emu1010.output_source[20] = 25;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5);
- emu->emu1010.output_source[21] = 26;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6);
- emu->emu1010.output_source[22] = 27;
- snd_emu1010_fpga_link_dst_src_write(emu,
- EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7);
- emu->emu1010.output_source[23] = 28;
- }
-
return 0;
}
/*
@@ -1158,9 +910,10 @@ static void snd_emu10k1_free(struct snd_card *card)
}
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
/* Disable 48Volt power to Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0);
}
- cancel_delayed_work_sync(&emu->emu1010.firmware_work);
+ cancel_work_sync(&emu->emu1010.work);
+ mutex_destroy(&emu->emu1010.lock);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
snd_util_memhdr_free(emu->memhdr);
@@ -1310,7 +1063,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
/* Does NOT support sync daughter card (obviously). */
/* Tested by James@superbug.co.uk 4th Nov 2007. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
- .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]",
+ .driver = "Audigy2", .name = "E-MU 02 CardBus [MAEM8950]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1323,7 +1076,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
* MicroDock[M] to make it an E-MU 1616[m]. */
/* Does NOT support sync daughter card. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
- .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]",
+ .driver = "Audigy2", .name = "E-MU 1010b PCI [MAEM8960]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1337,7 +1090,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
* still work. */
/* Does NOT support sync daughter card. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102,
- .driver = "Audigy2", .name = "E-mu 1010 PCIe [MAEM8986]",
+ .driver = "Audigy2", .name = "E-MU 1010 PCIe [MAEM8986]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0108_chip = 1,
@@ -1349,7 +1102,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
* AudioDock[M] to make it an E-MU 1820[m]. */
/* Supports sync daughter card. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
- .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]",
+ .driver = "Audigy2", .name = "E-MU 1010 [MAEM8810]",
.id = "EMU1010",
.emu10k2_chip = 1,
.ca0102_chip = 1,
@@ -1359,30 +1112,33 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
/* Supports sync daughter card. */
/* Tested by oswald.buddenhagen@gmx.de Mar 2023. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
- .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]",
+ .driver = "Audigy2", .name = "E-MU 0404b PCI [MAEM8852]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0108_chip = 1,
- .spk71 = 1,
+ .spk20 = 1,
+ .no_adat = 1,
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */
/* This is MAEM8850 "HanaLite" */
/* Supports sync daughter card. */
/* Tested by James@superbug.co.uk 20-3-2007. */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102,
- .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]",
+ .driver = "Audigy2", .name = "E-MU 0404 [MAEM8850]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0102_chip = 1,
- .spk71 = 1,
+ .spk20 = 1,
+ .no_adat = 1,
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
/* EMU0404 PCIe */
/* Does NOT support sync daughter card. */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40051102,
- .driver = "Audigy2", .name = "E-mu 0404 PCIe [MAEM8984]",
+ .driver = "Audigy2", .name = "E-MU 0404 PCIe [MAEM8984]",
.id = "EMU0404",
.emu10k2_chip = 1,
.ca0108_chip = 1,
- .spk71 = 1,
+ .spk20 = 1,
+ .no_adat = 1,
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 PCIe ver_03 */
{.vendor = 0x1102, .device = 0x0008,
.driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]",
@@ -1645,7 +1401,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = {
.ac97_chip = 1,
.sblive51 = 1} ,
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
- .driver = "EMU10K1", .name = "E-mu APS [PC545]",
+ .driver = "EMU10K1", .name = "E-MU APS [PC545]",
.id = "APS",
.emu10k1_chip = 1,
.ecard = 1} ,
@@ -1736,7 +1492,8 @@ int snd_emu10k1_create(struct snd_card *card,
emu->irq = -1;
emu->synth = NULL;
emu->get_synth_voice = NULL;
- INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
+ INIT_WORK(&emu->emu1010.work, emu1010_work);
+ mutex_init(&emu->emu1010.lock);
/* read revision & serial */
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
@@ -1801,7 +1558,7 @@ int snd_emu10k1_create(struct snd_card *card,
else
emu->gpr_base = FXGPREGBASE;
- err = pci_request_regions(pci, "EMU10K1");
+ err = pcim_request_all_regions(pci, "EMU10K1");
if (err < 0)
return err;
emu->port = pci_resource_start(pci, 0);
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 89890f24509f..806b4f95cad1 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -16,7 +16,7 @@
#define BLANK_LOOP_START 4
#define BLANK_LOOP_END 8
#define BLANK_LOOP_SIZE 12
-#define BLANK_HEAD_SIZE 32
+#define BLANK_HEAD_SIZE 3
/*
* allocate a sample block and copy data from userspace
@@ -26,56 +26,77 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
struct snd_util_memhdr *hdr,
const void __user *data, long count)
{
+ u8 fill;
+ u32 xor;
+ int shift;
int offset;
int truesize, size, blocksize;
- __maybe_unused int loopsize;
- int loopend, sampleend;
- unsigned int start_addr;
+ int loop_start, loop_end, loop_size, data_end, unroll;
struct snd_emu10k1 *emu;
emu = rec->hw;
if (snd_BUG_ON(!sp || !hdr))
return -EINVAL;
- if (sp->v.size == 0) {
- dev_dbg(emu->card->dev,
- "emu: rom font for sample %d\n", sp->v.sample);
- return 0;
+ if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP | SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
+ /* should instead return -ENOTSUPP; but compatibility */
+ dev_warn(emu->card->dev,
+ "Emu10k1 wavetable patch %d with unsupported loop feature\n",
+ sp->v.sample);
}
- /* recalculate address offset */
- sp->v.end -= sp->v.start;
- sp->v.loopstart -= sp->v.start;
- sp->v.loopend -= sp->v.start;
- sp->v.start = 0;
-
- /* some samples have invalid data. the addresses are corrected in voice info */
- sampleend = sp->v.end;
- if (sampleend > sp->v.size)
- sampleend = sp->v.size;
- loopend = sp->v.loopend;
- if (loopend > sampleend)
- loopend = sampleend;
-
- /* be sure loop points start < end */
- if (sp->v.loopstart >= sp->v.loopend)
- swap(sp->v.loopstart, sp->v.loopend);
+ if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
+ shift = 0;
+ fill = 0x80;
+ xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080;
+ } else {
+ shift = 1;
+ fill = 0;
+ xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0;
+ }
/* compute true data size to be loaded */
truesize = sp->v.size + BLANK_HEAD_SIZE;
- loopsize = 0;
-#if 0 /* not supported */
- if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
- loopsize = sp->v.loopend - sp->v.loopstart;
- truesize += loopsize;
-#endif
- if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
+ if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
truesize += BLANK_LOOP_SIZE;
+ /* if no blank loop is attached in the sample, add it */
+ if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
+ sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
+ sp->v.loopend = sp->v.end + BLANK_LOOP_END;
+ }
+ }
+
+ loop_start = sp->v.loopstart;
+ loop_end = sp->v.loopend;
+ loop_size = loop_end - loop_start;
+ if (!loop_size)
+ return -EINVAL;
+ data_end = sp->v.end;
+
+ /* recalculate offset */
+ sp->v.start += BLANK_HEAD_SIZE;
+ sp->v.end += BLANK_HEAD_SIZE;
+ sp->v.loopstart += BLANK_HEAD_SIZE;
+ sp->v.loopend += BLANK_HEAD_SIZE;
+
+ // Automatic pre-filling of the cache does not work in the presence
+ // of loops (*), and we don't want to fill it manually, as that is
+ // fiddly and slow. So we unroll the loop until the loop end is
+ // beyond the cache size.
+ // (*) Strictly speaking, a single iteration is supported (that's
+ // how it works when the playback engine runs), but handling this
+ // special case is not worth it.
+ unroll = 0;
+ while (sp->v.loopend < 64) {
+ truesize += loop_size;
+ sp->v.loopstart += loop_size;
+ sp->v.loopend += loop_size;
+ sp->v.end += loop_size;
+ unroll++;
+ }
/* try to allocate a memory block */
- blocksize = truesize;
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
- blocksize *= 2;
+ blocksize = truesize << shift;
sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
if (sp->block == NULL) {
dev_dbg(emu->card->dev,
@@ -88,110 +109,43 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
/* write blank samples at head */
offset = 0;
- size = BLANK_HEAD_SIZE;
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
- size *= 2;
- if (offset + size > blocksize)
- return -EINVAL;
- snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
- offset += size;
-
- /* copy start->loopend */
- size = loopend;
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
- size *= 2;
- if (offset + size > blocksize)
- return -EINVAL;
- if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
- snd_emu10k1_synth_free(emu, sp->block);
- sp->block = NULL;
- return -EFAULT;
- }
+ size = BLANK_HEAD_SIZE << shift;
+ snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill);
offset += size;
- data += size;
-
-#if 0 /* not supported yet */
- /* handle reverse (or bidirectional) loop */
- if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
- /* copy loop in reverse */
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
- int woffset;
- unsigned short *wblock = (unsigned short*)block;
- woffset = offset / 2;
- if (offset + loopsize * 2 > blocksize)
- return -EINVAL;
- for (i = 0; i < loopsize; i++)
- wblock[woffset + i] = wblock[woffset - i -1];
- offset += loopsize * 2;
- } else {
- if (offset + loopsize > blocksize)
- return -EINVAL;
- for (i = 0; i < loopsize; i++)
- block[offset + i] = block[offset - i -1];
- offset += loopsize;
- }
- /* modify loop pointers */
- if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
- sp->v.loopend += loopsize;
- } else {
- sp->v.loopstart += loopsize;
- sp->v.loopend += loopsize;
+ /* copy provided samples */
+ if (unroll && loop_end <= data_end) {
+ size = loop_end << shift;
+ if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
+ goto faulty;
+ offset += size;
+
+ data += loop_start << shift;
+ while (--unroll > 0) {
+ size = loop_size << shift;
+ if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
+ goto faulty;
+ offset += size;
}
- /* add sample pointer */
- sp->v.end += loopsize;
- }
-#endif
- /* loopend -> sample end */
- size = sp->v.size - loopend;
- if (size < 0)
- return -EINVAL;
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
- size *= 2;
- if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
- snd_emu10k1_synth_free(emu, sp->block);
- sp->block = NULL;
- return -EFAULT;
+ size = (data_end - loop_start) << shift;
+ } else {
+ size = data_end << shift;
}
+ if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
+ goto faulty;
offset += size;
/* clear rest of samples (if any) */
if (offset < blocksize)
- snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
-
- if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
- /* if no blank loop is attached in the sample, add it */
- if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
- sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
- sp->v.loopend = sp->v.end + BLANK_LOOP_END;
- }
- }
-
-#if 0 /* not supported yet */
- if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
- /* unsigned -> signed */
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
- unsigned short *wblock = (unsigned short*)block;
- for (i = 0; i < truesize; i++)
- wblock[i] ^= 0x8000;
- } else {
- for (i = 0; i < truesize; i++)
- block[i] ^= 0x80;
- }
- }
-#endif
-
- /* recalculate offset */
- start_addr = BLANK_HEAD_SIZE * 2;
- if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
- start_addr >>= 1;
- sp->v.start += start_addr;
- sp->v.end += start_addr;
- sp->v.loopstart += start_addr;
- sp->v.loopend += start_addr;
+ snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);
return 0;
+
+faulty:
+ snd_emu10k1_synth_free(emu, sp->block);
+ sp->block = NULL;
+ return -EFAULT;
}
/*
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c
index 549013a4a80b..662d20eb9689 100644
--- a/sound/pci/emu10k1/emu10k1_synth.c
+++ b/sound/pci/emu10k1/emu10k1_synth.c
@@ -22,7 +22,6 @@ static int snd_emu10k1_synth_probe(struct device *_dev)
struct snd_emux *emux;
struct snd_emu10k1 *hw;
struct snd_emu10k1_synth_arg *arg;
- unsigned long flags;
arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
if (arg == NULL)
@@ -43,7 +42,6 @@ static int snd_emu10k1_synth_probe(struct device *_dev)
emux->hw = hw;
emux->max_voices = arg->max_voices;
emux->num_ports = arg->seq_ports;
- emux->pitch_shift = -501;
emux->memhdr = hw->memhdr;
/* maximum two ports */
emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2;
@@ -57,10 +55,9 @@ static int snd_emu10k1_synth_probe(struct device *_dev)
return -ENOMEM;
}
- spin_lock_irqsave(&hw->voice_lock, flags);
+ guard(spinlock_irq)(&hw->voice_lock);
hw->synth = emux;
hw->get_synth_voice = snd_emu10k1_synth_get_voice;
- spin_unlock_irqrestore(&hw->voice_lock, flags);
dev->driver_data = emux;
@@ -72,7 +69,6 @@ static int snd_emu10k1_synth_remove(struct device *_dev)
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_emux *emux;
struct snd_emu10k1 *hw;
- unsigned long flags;
if (dev->driver_data == NULL)
return 0; /* not registered actually */
@@ -80,10 +76,10 @@ static int snd_emu10k1_synth_remove(struct device *_dev)
emux = dev->driver_data;
hw = emux->hw;
- spin_lock_irqsave(&hw->voice_lock, flags);
- hw->synth = NULL;
- hw->get_synth_voice = NULL;
- spin_unlock_irqrestore(&hw->voice_lock, flags);
+ scoped_guard(spinlock_irq, &hw->voice_lock) {
+ hw->synth = NULL;
+ hw->get_synth_voice = NULL;
+ }
snd_emux_free(emux);
return 0;
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 89043392f3ec..9607a0f7174b 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -20,6 +20,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
@@ -280,16 +281,13 @@ static unsigned int snd_emu10k1x_ptr_read(struct emu10k1x * emu,
unsigned int reg,
unsigned int chn)
{
- unsigned long flags;
- unsigned int regptr, val;
+ unsigned int regptr;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(regptr, emu->port + PTR);
- val = inl(emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inl(emu->port + DATA);
}
static void snd_emu10k1x_ptr_write(struct emu10k1x *emu,
@@ -298,45 +296,36 @@ static void snd_emu10k1x_ptr_write(struct emu10k1x *emu,
unsigned int data)
{
unsigned int regptr;
- unsigned long flags;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(regptr, emu->port + PTR);
outl(data, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_emu10k1x_intr_enable(struct emu10k1x *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int intr_enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
intr_enable = inl(emu->port + INTE) | intrenb;
outl(intr_enable, emu->port + INTE);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_emu10k1x_intr_disable(struct emu10k1x *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int intr_enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
intr_enable = inl(emu->port + INTE) & ~intrenb;
outl(intr_enable, emu->port + INTE);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_emu10k1x_gpio_write(struct emu10k1x *emu, unsigned int value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(value, emu->port + GPIO);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_emu10k1x_pcm_free_substream(struct snd_pcm_runtime *runtime)
@@ -693,26 +682,20 @@ static unsigned short snd_emu10k1x_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
struct emu10k1x *emu = ac97->private_data;
- unsigned long flags;
- unsigned short val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outb(reg, emu->port + AC97ADDRESS);
- val = inw(emu->port + AC97DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inw(emu->port + AC97DATA);
}
static void snd_emu10k1x_ac97_write(struct snd_ac97 *ac97,
unsigned short reg, unsigned short val)
{
struct emu10k1x *emu = ac97->private_data;
- unsigned long flags;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outb(reg, emu->port + AC97ADDRESS);
outw(val, emu->port + AC97DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static int snd_emu10k1x_ac97(struct emu10k1x *chip)
@@ -840,15 +823,15 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device)
pcm->info_flags = 0;
switch(device) {
case 0:
- strcpy(pcm->name, "EMU10K1X Front");
+ strscpy(pcm->name, "EMU10K1X Front");
map = snd_pcm_std_chmaps;
break;
case 1:
- strcpy(pcm->name, "EMU10K1X Rear");
+ strscpy(pcm->name, "EMU10K1X Rear");
map = surround_map;
break;
case 2:
- strcpy(pcm->name, "EMU10K1X Center/LFE");
+ strscpy(pcm->name, "EMU10K1X Center/LFE");
map = clfe_map;
break;
}
@@ -884,7 +867,7 @@ static int snd_emu10k1x_create(struct snd_card *card,
spin_lock_init(&chip->emu_lock);
spin_lock_init(&chip->voice_lock);
- err = pci_request_regions(pci, "EMU10K1X");
+ err = pcim_request_all_regions(pci, "EMU10K1X");
if (err < 0)
return err;
chip->port = pci_resource_start(pci, 0);
@@ -965,14 +948,12 @@ static void snd_emu10k1x_proc_reg_read(struct snd_info_entry *entry,
{
struct emu10k1x *emu = entry->private_data;
unsigned long value,value1,value2;
- unsigned long flags;
int i;
snd_iprintf(buffer, "Registers:\n\n");
for(i = 0; i < 0x20; i+=4) {
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
value = inl(emu->port + i);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
}
snd_iprintf(buffer, "\nRegisters\n\n");
@@ -1205,28 +1186,28 @@ static void do_emu10k1x_midi_interrupt(struct emu10k1x *emu,
return;
}
- spin_lock(&midi->input_lock);
- if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
- if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
- mpu401_clear_rx(emu, midi);
- } else {
- byte = mpu401_read_data(emu, midi);
- if (midi->substream_input)
- snd_rawmidi_receive(midi->substream_input, &byte, 1);
+ scoped_guard(spinlock, &midi->input_lock) {
+ if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
+ if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
+ mpu401_clear_rx(emu, midi);
+ } else {
+ byte = mpu401_read_data(emu, midi);
+ if (midi->substream_input)
+ snd_rawmidi_receive(midi->substream_input, &byte, 1);
+ }
}
}
- spin_unlock(&midi->input_lock);
- spin_lock(&midi->output_lock);
- if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
- if (midi->substream_output &&
- snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
- mpu401_write_data(emu, midi, byte);
- } else {
- snd_emu10k1x_intr_disable(emu, midi->tx_enable);
+ scoped_guard(spinlock, &midi->output_lock) {
+ if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
+ if (midi->substream_output &&
+ snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
+ mpu401_write_data(emu, midi, byte);
+ } else {
+ snd_emu10k1x_intr_disable(emu, midi->tx_enable);
+ }
}
}
- spin_unlock(&midi->output_lock);
}
static void snd_emu10k1x_midi_interrupt(struct emu10k1x *emu, unsigned int status)
@@ -1237,29 +1218,28 @@ static void snd_emu10k1x_midi_interrupt(struct emu10k1x *emu, unsigned int statu
static int snd_emu10k1x_midi_cmd(struct emu10k1x * emu,
struct emu10k1x_midi *midi, unsigned char cmd, int ack)
{
- unsigned long flags;
int timeout, ok;
- spin_lock_irqsave(&midi->input_lock, flags);
- mpu401_write_data(emu, midi, 0x00);
- /* mpu401_clear_rx(emu, midi); */
-
- mpu401_write_cmd(emu, midi, cmd);
- if (ack) {
- ok = 0;
- timeout = 10000;
- while (!ok && timeout-- > 0) {
- if (mpu401_input_avail(emu, midi)) {
- if (mpu401_read_data(emu, midi) == MPU401_ACK)
- ok = 1;
+ scoped_guard(spinlock_irqsave, &midi->input_lock) {
+ mpu401_write_data(emu, midi, 0x00);
+ /* mpu401_clear_rx(emu, midi); */
+
+ mpu401_write_cmd(emu, midi, cmd);
+ if (ack) {
+ ok = 0;
+ timeout = 10000;
+ while (!ok && timeout-- > 0) {
+ if (mpu401_input_avail(emu, midi)) {
+ if (mpu401_read_data(emu, midi) == MPU401_ACK)
+ ok = 1;
+ }
}
- }
- if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
+ if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
+ ok = 1;
+ } else {
ok = 1;
- } else {
- ok = 1;
+ }
}
- spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok) {
dev_err(emu->card->dev,
"midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
@@ -1275,100 +1255,78 @@ static int snd_emu10k1x_midi_input_open(struct snd_rawmidi_substream *substream)
{
struct emu10k1x *emu;
struct emu10k1x_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT;
- midi->substream_input = substream;
- if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1))
- goto error_out;
- if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
- goto error_out;
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT;
+ midi->substream_input = substream;
+ if (midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)
+ return 0;
}
+ if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1))
+ return -EIO;
+ if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
+ return -EIO;
return 0;
-
-error_out:
- return -EIO;
}
static int snd_emu10k1x_midi_output_open(struct snd_rawmidi_substream *substream)
{
struct emu10k1x *emu;
struct emu10k1x_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT;
- midi->substream_output = substream;
- if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1))
- goto error_out;
- if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
- goto error_out;
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT;
+ midi->substream_output = substream;
+ if (midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)
+ return 0;
}
+ if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1))
+ return -EIO;
+ if (snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
+ return -EIO;
return 0;
-
-error_out:
- return -EIO;
}
static int snd_emu10k1x_midi_input_close(struct snd_rawmidi_substream *substream)
{
struct emu10k1x *emu;
struct emu10k1x_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
- int err = 0;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- snd_emu10k1x_intr_disable(emu, midi->rx_enable);
- midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT;
- midi->substream_input = NULL;
- if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- err = snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ snd_emu10k1x_intr_disable(emu, midi->rx_enable);
+ midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT;
+ midi->substream_input = NULL;
+ if (midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)
+ return 0;
}
- return err;
+ return snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0);
}
static int snd_emu10k1x_midi_output_close(struct snd_rawmidi_substream *substream)
{
struct emu10k1x *emu;
struct emu10k1x_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
- int err = 0;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- snd_emu10k1x_intr_disable(emu, midi->tx_enable);
- midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT;
- midi->substream_output = NULL;
- if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- err = snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irqsave, &midi->open_lock) {
+ snd_emu10k1x_intr_disable(emu, midi->tx_enable);
+ midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT;
+ midi->substream_output = NULL;
+ if (midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)
+ return 0;
}
- return err;
+ return snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0);
}
static void snd_emu10k1x_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -1389,7 +1347,6 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst
{
struct emu10k1x *emu;
struct emu10k1x_midi *midi = substream->rmidi->private_data;
- unsigned long flags;
emu = midi->emu;
if (snd_BUG_ON(!emu))
@@ -1400,22 +1357,21 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst
unsigned char byte;
/* try to send some amount of bytes here before interrupts */
- spin_lock_irqsave(&midi->output_lock, flags);
- while (max > 0) {
- if (mpu401_output_ready(emu, midi)) {
- if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) ||
- snd_rawmidi_transmit(substream, &byte, 1) != 1) {
- /* no more data */
- spin_unlock_irqrestore(&midi->output_lock, flags);
- return;
+ scoped_guard(spinlock_irqsave, &midi->output_lock) {
+ while (max > 0) {
+ if (mpu401_output_ready(emu, midi)) {
+ if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) ||
+ snd_rawmidi_transmit(substream, &byte, 1) != 1) {
+ /* no more data */
+ return;
+ }
+ mpu401_write_data(emu, midi, byte);
+ max--;
+ } else {
+ break;
}
- mpu401_write_data(emu, midi, byte);
- max--;
- } else {
- break;
}
}
- spin_unlock_irqrestore(&midi->output_lock, flags);
snd_emu10k1x_intr_enable(emu, midi->tx_enable);
} else {
snd_emu10k1x_intr_disable(emu, midi->tx_enable);
@@ -1461,7 +1417,7 @@ static int emu10k1x_midi_init(struct emu10k1x *emu,
spin_lock_init(&midi->open_lock);
spin_lock_init(&midi->input_lock);
spin_lock_init(&midi->output_lock);
- strcpy(rmidi->name, name);
+ strscpy(rmidi->name, name);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1x_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1x_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
@@ -1540,8 +1496,8 @@ static int __snd_emu10k1x_probe(struct pci_dev *pci,
snd_emu10k1x_proc_init(chip);
- strcpy(card->driver, "EMU10K1X");
- strcpy(card->shortname, "Dell Sound Blaster Live!");
+ strscpy(card->driver, "EMU10K1X");
+ strscpy(card->shortname, "Dell Sound Blaster Live!");
sprintf(card->longname, "%s at 0x%lx irq %i",
card->shortname, chip->port, chip->irq);
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 3f64ccab0e63..37af7bf76347 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1,23 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * James Courtier-Dutton <James@superbug.co.uk>
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
* Creative Labs, Inc.
- * Routines for effect processor FX8010
- *
- * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
- * Added EMU 1010 support.
- *
- * BUGS:
- * --
*
- * TODO:
- * --
+ * Routines for effect processor FX8010
*/
#include <linux/pci.h>
#include <linux/capability.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/mutex.h>
@@ -46,26 +41,45 @@ MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
* Tables
*/
-static const char * const fxbuses[16] = {
+// Playback channel labels; corresponds with the public FXBUS_* defines.
+// Unlike the tables below, this is not determined by the hardware.
+const char * const snd_emu10k1_fxbus[32] = {
/* 0x00 */ "PCM Left",
/* 0x01 */ "PCM Right",
- /* 0x02 */ "PCM Surround Left",
- /* 0x03 */ "PCM Surround Right",
+ /* 0x02 */ "PCM Rear Left",
+ /* 0x03 */ "PCM Rear Right",
/* 0x04 */ "MIDI Left",
/* 0x05 */ "MIDI Right",
- /* 0x06 */ "Center",
- /* 0x07 */ "LFE",
- /* 0x08 */ NULL,
- /* 0x09 */ NULL,
+ /* 0x06 */ "PCM Center",
+ /* 0x07 */ "PCM LFE",
+ /* 0x08 */ "PCM Front Left",
+ /* 0x09 */ "PCM Front Right",
/* 0x0a */ NULL,
/* 0x0b */ NULL,
/* 0x0c */ "MIDI Reverb",
/* 0x0d */ "MIDI Chorus",
- /* 0x0e */ NULL,
- /* 0x0f */ NULL
+ /* 0x0e */ "PCM Side Left",
+ /* 0x0f */ "PCM Side Right",
+ /* 0x10 */ NULL,
+ /* 0x11 */ NULL,
+ /* 0x12 */ NULL,
+ /* 0x13 */ NULL,
+ /* 0x14 */ "Passthrough Left",
+ /* 0x15 */ "Passthrough Right",
+ /* 0x16 */ NULL,
+ /* 0x17 */ NULL,
+ /* 0x18 */ NULL,
+ /* 0x19 */ NULL,
+ /* 0x1a */ NULL,
+ /* 0x1b */ NULL,
+ /* 0x1c */ NULL,
+ /* 0x1d */ NULL,
+ /* 0x1e */ NULL,
+ /* 0x1f */ NULL
};
-static const char * const creative_ins[16] = {
+// Physical inputs; corresponds with the public EXTIN_* defines.
+const char * const snd_emu10k1_sblive_ins[16] = {
/* 0x00 */ "AC97 Left",
/* 0x01 */ "AC97 Right",
/* 0x02 */ "TTL IEC958 Left",
@@ -84,7 +98,8 @@ static const char * const creative_ins[16] = {
/* 0x0f */ NULL
};
-static const char * const audigy_ins[16] = {
+// Physical inputs; corresponds with the public A_EXTIN_* defines.
+const char * const snd_emu10k1_audigy_ins[16] = {
/* 0x00 */ "AC97 Left",
/* 0x01 */ "AC97 Right",
/* 0x02 */ "Audigy CD Left",
@@ -103,7 +118,8 @@ static const char * const audigy_ins[16] = {
/* 0x0f */ NULL
};
-static const char * const creative_outs[32] = {
+// Physical outputs; corresponds with the public EXTOUT_* defines.
+const char * const snd_emu10k1_sblive_outs[32] = {
/* 0x00 */ "AC97 Left",
/* 0x01 */ "AC97 Right",
/* 0x02 */ "Optical IEC958 Left",
@@ -120,6 +136,7 @@ static const char * const creative_outs[32] = {
/* 0x0d */ "AC97 Surround Left",
/* 0x0e */ "AC97 Surround Right",
/* 0x0f */ NULL,
+ // This is actually the FXBUS2 range; SB Live! 5.1 only.
/* 0x10 */ NULL,
/* 0x11 */ "Analog Center",
/* 0x12 */ "Analog LFE",
@@ -138,7 +155,8 @@ static const char * const creative_outs[32] = {
/* 0x1f */ NULL,
};
-static const char * const audigy_outs[32] = {
+// Physical outputs; corresponds with the public A_EXTOUT_* defines.
+const char * const snd_emu10k1_audigy_outs[32] = {
/* 0x00 */ "Digital Front Left",
/* 0x01 */ "Digital Front Right",
/* 0x02 */ "Digital Center",
@@ -173,6 +191,18 @@ static const char * const audigy_outs[32] = {
/* 0x1f */ NULL,
};
+// On the SB Live! 5.1, FXBUS2[1] and FXBUS2[2] are occupied by EXTOUT_ACENTER
+// and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
+//
+// Since only 14 of the 16 EXTINs are used, this is not a big problem.
+// We route AC97 to FX capture 14 and 15, SPDIF_CD to FX capture 0 and 3,
+// and the rest of the EXTINs to the corresponding FX capture channel.
+// Multitrack recorders will still see the center/LFE output signal
+// on the second and third "input" channel.
+const s8 snd_emu10k1_sblive51_fxbus2_map[16] = {
+ 2, -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1
+};
+
static const u32 bass_table[41][5] = {
{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
@@ -318,16 +348,12 @@ static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_fx8010_ctl *ctl =
(struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
- unsigned long flags;
unsigned int i;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (i = 0; i < ctl->vcount; i++)
ucontrol->value.integer.value[i] = ctl->value[i];
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
@@ -336,12 +362,10 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_fx8010_ctl *ctl =
(struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
- unsigned long flags;
- unsigned int nval, val;
+ int nval, val;
unsigned int i, j;
int change = 0;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (i = 0; i < ctl->vcount; i++) {
nval = ucontrol->value.integer.value[i];
if (nval < ctl->min)
@@ -355,9 +379,16 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl
case EMU10K1_GPR_TRANSLATION_NONE:
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
break;
+ case EMU10K1_GPR_TRANSLATION_NEGATE:
+ snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, ~val);
+ break;
case EMU10K1_GPR_TRANSLATION_TABLE100:
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
break;
+ case EMU10K1_GPR_TRANSLATION_NEG_TABLE100:
+ snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0,
+ val == 100 ? 0x80000000 : -(int)db_table[val]);
+ break;
case EMU10K1_GPR_TRANSLATION_BASS:
if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
change = -EIO;
@@ -380,7 +411,6 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl
}
}
__error:
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -410,13 +440,11 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
void *private_data,
struct snd_emu10k1_fx8010_irq *irq)
{
- unsigned long flags;
-
irq->handler = handler;
irq->gpr_running = gpr_running;
irq->private_data = private_data;
irq->next = NULL;
- spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
+ guard(spinlock_irqsave)(&emu->fx8010.irq_lock);
if (emu->fx8010.irq_handlers == NULL) {
emu->fx8010.irq_handlers = irq;
emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
@@ -425,7 +453,6 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
irq->next = emu->fx8010.irq_handlers;
emu->fx8010.irq_handlers = irq;
}
- spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
return 0;
}
@@ -433,9 +460,8 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_irq *irq)
{
struct snd_emu10k1_fx8010_irq *tmp;
- unsigned long flags;
- spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
+ guard(spinlock_irqsave)(&emu->fx8010.irq_lock);
tmp = emu->fx8010.irq_handlers;
if (tmp == irq) {
emu->fx8010.irq_handlers = tmp->next;
@@ -449,7 +475,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
if (tmp)
tmp->next = tmp->next->next;
}
- spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
return 0;
}
@@ -764,18 +789,43 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
continue;
gctl_id = (struct snd_ctl_elem_id *)&gctl->id;
- down_read(&emu->card->controls_rwsem);
if (snd_ctl_find_id(emu->card, gctl_id)) {
- up_read(&emu->card->controls_rwsem);
err = -EEXIST;
goto __error;
}
- up_read(&emu->card->controls_rwsem);
if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) {
err = -EINVAL;
goto __error;
}
+ switch (gctl->translation) {
+ case EMU10K1_GPR_TRANSLATION_NONE:
+ case EMU10K1_GPR_TRANSLATION_NEGATE:
+ break;
+ case EMU10K1_GPR_TRANSLATION_TABLE100:
+ case EMU10K1_GPR_TRANSLATION_NEG_TABLE100:
+ if (gctl->min != 0 || gctl->max != 100) {
+ err = -EINVAL;
+ goto __error;
+ }
+ break;
+ case EMU10K1_GPR_TRANSLATION_BASS:
+ case EMU10K1_GPR_TRANSLATION_TREBLE:
+ if (gctl->min != 0 || gctl->max != 40) {
+ err = -EINVAL;
+ goto __error;
+ }
+ break;
+ case EMU10K1_GPR_TRANSLATION_ONOFF:
+ if (gctl->min != 0 || gctl->max != 1) {
+ err = -EINVAL;
+ goto __error;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ goto __error;
+ }
}
for (i = 0; i < icode->gpr_list_control_count; i++) {
/* FIXME: we need to check the WRITE access */
@@ -914,11 +964,9 @@ static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
in_kernel);
if (err < 0)
return err;
- down_write(&card->controls_rwsem);
ctl = snd_emu10k1_look_for_ctl(emu, &id);
if (ctl)
snd_ctl_remove(card, ctl->kcontrol);
- up_write(&card->controls_rwsem);
}
return 0;
}
@@ -973,12 +1021,12 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_code *icode,
bool in_kernel)
{
- int err = 0;
+ int err;
- mutex_lock(&emu->fx8010.lock);
+ guard(mutex)(&emu->fx8010.lock);
err = snd_emu10k1_verify_controls(emu, icode, in_kernel);
if (err < 0)
- goto __error;
+ return err;
strscpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
/* stop FX processor - this may be dangerous, but it's better to miss
some samples than generate wrong ones - [jk] */
@@ -989,27 +1037,25 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
/* ok, do the main job */
err = snd_emu10k1_del_controls(emu, icode, in_kernel);
if (err < 0)
- goto __error;
+ return err;
err = snd_emu10k1_gpr_poke(emu, icode, in_kernel);
if (err < 0)
- goto __error;
+ return err;
err = snd_emu10k1_tram_poke(emu, icode, in_kernel);
if (err < 0)
- goto __error;
+ return err;
err = snd_emu10k1_code_poke(emu, icode, in_kernel);
if (err < 0)
- goto __error;
+ return err;
err = snd_emu10k1_add_controls(emu, icode, in_kernel);
if (err < 0)
- goto __error;
+ return err;
/* start FX processor when the DSP code is updated */
if (emu->audigy)
snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
else
snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
- __error:
- mutex_unlock(&emu->fx8010.lock);
- return err;
+ return 0;
}
static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
@@ -1017,7 +1063,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
{
int err;
- mutex_lock(&emu->fx8010.lock);
+ guard(mutex)(&emu->fx8010.lock);
strscpy(icode->name, emu->fx8010.name, sizeof(icode->name));
/* ok, do the main job */
err = snd_emu10k1_gpr_peek(emu, icode);
@@ -1027,7 +1073,6 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
err = snd_emu10k1_code_peek(emu, icode);
if (err >= 0)
err = snd_emu10k1_list_controls(emu, icode);
- mutex_unlock(&emu->fx8010.lock);
return err;
}
@@ -1035,7 +1080,6 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_pcm_rec *ipcm)
{
unsigned int i;
- int err = 0;
struct snd_emu10k1_fx8010_pcm *pcm;
if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
@@ -1045,20 +1089,16 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
if (ipcm->channels > 32)
return -EINVAL;
pcm = &emu->fx8010.pcm[ipcm->substream];
- mutex_lock(&emu->fx8010.lock);
- spin_lock_irq(&emu->reg_lock);
- if (pcm->opened) {
- err = -EBUSY;
- goto __error;
- }
+ guard(mutex)(&emu->fx8010.lock);
+ guard(spinlock_irq)(&emu->reg_lock);
+ if (pcm->opened)
+ return -EBUSY;
if (ipcm->channels == 0) { /* remove */
pcm->valid = 0;
} else {
/* FIXME: we need to add universal code to the PCM transfer routine */
- if (ipcm->channels != 2) {
- err = -EINVAL;
- goto __error;
- }
+ if (ipcm->channels != 2)
+ return -EINVAL;
pcm->valid = 1;
pcm->opened = 0;
pcm->channels = ipcm->channels;
@@ -1073,17 +1113,13 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
for (i = 0; i < pcm->channels; i++)
pcm->etram[i] = ipcm->etram[i];
}
- __error:
- spin_unlock_irq(&emu->reg_lock);
- mutex_unlock(&emu->fx8010.lock);
- return err;
+ return 0;
}
static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
struct snd_emu10k1_fx8010_pcm_rec *ipcm)
{
unsigned int i;
- int err = 0;
struct snd_emu10k1_fx8010_pcm *pcm;
if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
@@ -1091,8 +1127,8 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
ipcm->substream = array_index_nospec(ipcm->substream,
EMU10K1_FX8010_PCM_COUNT);
pcm = &emu->fx8010.pcm[ipcm->substream];
- mutex_lock(&emu->fx8010.lock);
- spin_lock_irq(&emu->reg_lock);
+ guard(mutex)(&emu->fx8010.lock);
+ guard(spinlock_irq)(&emu->reg_lock);
ipcm->channels = pcm->channels;
ipcm->tram_start = pcm->tram_start;
ipcm->buffer_size = pcm->buffer_size;
@@ -1106,9 +1142,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
ipcm->etram[i] = pcm->etram[i];
ipcm->res1 = ipcm->res2 = 0;
ipcm->pad = 0;
- spin_unlock_irq(&emu->reg_lock);
- mutex_unlock(&emu->fx8010.lock);
- return err;
+ return 0;
}
#define SND_EMU10K1_GPR_CONTROLS 44
@@ -1116,55 +1150,63 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
#define SND_EMU10K1_PLAYBACK_CHANNELS 8
#define SND_EMU10K1_CAPTURE_CHANNELS 4
+#define HR_VAL(v) ((v) * 0x80000000LL / 100 - 1)
+
static void
-snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
- const char *name, int gpr, int defval)
+snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
+ const char *name, int gpr, int defval, int defval_hr)
{
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, name);
+ strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
- ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
if (high_res_gpr_volume) {
- ctl->min = 0;
+ ctl->min = -1;
ctl->max = 0x7fffffff;
ctl->tlv = snd_emu10k1_db_linear;
- ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE;
+ defval = defval_hr;
} else {
ctl->min = 0;
ctl->max = 100;
ctl->tlv = snd_emu10k1_db_scale1;
- ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100;
}
+ ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
}
+#define snd_emu10k1_init_mono_control(ctl, name, gpr, defval) \
+ snd_emu10k1_init_mono_control2(ctl, name, gpr, defval, HR_VAL(defval))
static void
-snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
- const char *name, int gpr, int defval)
+snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
+ const char *name, int gpr, int defval, int defval_hr)
{
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, name);
+ strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 2;
- ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
- ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
if (high_res_gpr_volume) {
- ctl->min = 0;
+ ctl->min = -1;
ctl->max = 0x7fffffff;
ctl->tlv = snd_emu10k1_db_linear;
- ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE;
+ defval = defval_hr;
} else {
ctl->min = 0;
ctl->max = 100;
ctl->tlv = snd_emu10k1_db_scale1;
- ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+ ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100;
}
+ ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
+ ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
}
+#define snd_emu10k1_init_stereo_control(ctl, name, gpr, defval) \
+ snd_emu10k1_init_stereo_control2(ctl, name, gpr, defval, HR_VAL(defval))
static void
snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval)
{
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, name);
+ strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
ctl->min = 0;
@@ -1177,7 +1219,7 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
const char *name, int gpr, int defval)
{
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, name);
+ strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 2;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
@@ -1191,35 +1233,50 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
* to 2 x 16-bit registers in Audigy - their values are read via DMA.
* Conversion is performed by Audigy DSP instructions of FX8010.
*/
-static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
+static void snd_emu10k1_audigy_dsp_convert_32_to_2x16(
struct snd_emu10k1_fx8010_code *icode,
u32 *ptr, int tmp, int bit_shifter16,
int reg_in, int reg_out)
{
- A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
- A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
- A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
- A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
- A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
- A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
- A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
- A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
- return 1;
+ // This leaves the low word in place, which is fine,
+ // as the low bits are completely ignored subsequently.
+ // reg_out[1] = reg_in
+ A_OP(icode, ptr, iACC3, reg_out + 1, reg_in, A_C_00000000, A_C_00000000);
+ // It is fine to read reg_in multiple times.
+ // tmp = reg_in << 15
+ A_OP(icode, ptr, iMACINT1, A_GPR(tmp), A_C_00000000, reg_in, A_GPR(bit_shifter16));
+ // Left-shift once more. This is a separate step, as the
+ // signed multiplication would clobber the MSB.
+ // reg_out[0] = tmp + ((tmp << 31) >> 31)
+ A_OP(icode, ptr, iMAC3, reg_out, A_GPR(tmp), A_GPR(tmp), A_C_80000000);
}
+#define ENUM_GPR(name, size) name, name ## _dummy = name + (size) - 1
+
/*
* initial DSP configuration for Audigy
*/
static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
{
- int err, z, gpr, nctl;
- int bit_shifter16;
- const int playback = 10;
- const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
- const int stereo_mix = capture + 2;
- const int tmp = 0x88;
- u32 ptr;
+ int err, z, nctl;
+ enum {
+ ENUM_GPR(playback, SND_EMU10K1_PLAYBACK_CHANNELS),
+ ENUM_GPR(stereo_mix, 2),
+ ENUM_GPR(capture, 2),
+ ENUM_GPR(bit_shifter16, 1),
+ // The fixed allocation of these breaks the pattern, but why not.
+ // Splitting these into left/right is questionable, as it will break
+ // down for center/lfe. But it works for stereo/quadro, so whatever.
+ ENUM_GPR(bass_gpr, 2 * 5), // two sides, five coefficients
+ ENUM_GPR(treble_gpr, 2 * 5),
+ ENUM_GPR(bass_tmp, SND_EMU10K1_PLAYBACK_CHANNELS * 4), // four delay stages
+ ENUM_GPR(treble_tmp, SND_EMU10K1_PLAYBACK_CHANNELS * 4),
+ ENUM_GPR(tmp, 3),
+ num_static_gprs
+ };
+ int gpr = num_static_gprs;
+ u32 ptr, ptr_skip;
struct snd_emu10k1_fx8010_code *icode = NULL;
struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
u32 *gpr_map;
@@ -1250,47 +1307,43 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
/* clear TRAM data & address lines */
memset(icode->tram_valid, 0xff, 256 / 8);
- strcpy(icode->name, "Audigy DSP code for ALSA");
+ strscpy(icode->name, "Audigy DSP code for ALSA");
ptr = 0;
nctl = 0;
- gpr = stereo_mix + 10;
- gpr_map[gpr++] = 0x00007fff;
- gpr_map[gpr++] = 0x00008000;
- gpr_map[gpr++] = 0x0000ffff;
- bit_shifter16 = gpr;
+ gpr_map[bit_shifter16] = 0x00008000;
#if 1
/* PCM front Playback Volume (independent from stereo mix)
- * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
- * where gpr contains attenuation from corresponding mixer control
+ * playback = -gpr * FXBUS_PCM_LEFT_FRONT >> 31
+ * where gpr contains negated attenuation from corresponding mixer control
* (snd_emu10k1_init_stereo_control)
*/
- A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
gpr += 2;
/* PCM Surround Playback (independent from stereo mix) */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
gpr += 2;
/* PCM Side Playback (independent from stereo mix) */
if (emu->card_capabilities->spk71) {
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
gpr += 2;
}
/* PCM Center Playback (independent from stereo mix) */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
gpr++;
/* PCM LFE Playback (independent from stereo mix) */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
gpr++;
@@ -1298,160 +1351,174 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
* Stereo Mix
*/
/* Wave (PCM) Playback Volume (will be renamed later) */
- A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
- A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
gpr += 2;
/* Synth Playback */
- A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
- A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
gpr += 2;
/* Wave (PCM) Capture */
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
gpr += 2;
/* Synth Capture */
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
gpr += 2;
-
+
+ // We need to double the volume, as we configure the voices for half volume,
+ // which is necessary for bit-identical reproduction.
+ { static_assert(stereo_mix == playback + SND_EMU10K1_PLAYBACK_CHANNELS); }
+ for (z = 0; z < SND_EMU10K1_PLAYBACK_CHANNELS + 2; z++)
+ A_OP(icode, &ptr, iACC3, A_GPR(playback + z), A_GPR(playback + z), A_GPR(playback + z), A_C_00000000);
+
/*
* inputs
*/
#define A_ADD_VOLUME_IN(var,vol,input) \
-A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
+ A_OP(icode, &ptr, iMAC1, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
if (emu->card_capabilities->emu_model) {
/* EMU1010 DSP 0 and DSP 1 Capture */
// The 24 MSB hold the actual value. We implicitly discard the 16 LSB.
if (emu->card_capabilities->ca0108_chip) {
- /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
- A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp));
- A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001);
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp));
+ // For unclear reasons, the EMU32IN cannot be the Y operand!
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A3_EMU32IN(0x0), A_GPR(gpr));
+ // A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels
+ // need to be delayed as well; we use an auxiliary register for that.
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A3_EMU32IN(0x1), A_C_00000000, A_C_00000000);
} else {
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
- A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_P16VIN(0x0), A_GPR(gpr));
+ // A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels
+ // need to be delayed as well; we use an auxiliary register for that.
+ A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
}
snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
- gpr += 2;
- }
- /* AC'97 Playback Volume - used only for mic (renamed later) */
- A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
- A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
- gpr += 2;
- /* AC'97 Capture Volume - used only for mic */
- A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
- A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
- gpr += 2;
+ gpr_map[gpr + 2] = 0x00000000;
+ gpr += 3;
+ } else {
+ if (emu->card_capabilities->ac97_chip) {
+ /* AC'97 Playback Volume - used only for mic (renamed later) */
+ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
+ A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
+ gpr += 2;
+ /* AC'97 Capture Volume - used only for mic */
+ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
+ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
+ gpr += 2;
+
+ /* mic capture buffer */
+ A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), A_C_40000000, A_EXTIN(A_EXTIN_AC97_R));
+ }
- /* mic capture buffer */
- A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), A_C_40000000, A_EXTIN(A_EXTIN_AC97_R));
+ /* Audigy CD Playback Volume */
+ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
+ A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++],
+ emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
+ gpr, 0);
+ gpr += 2;
+ /* Audigy CD Capture Volume */
+ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
+ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++],
+ emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
+ gpr, 0);
+ gpr += 2;
- /* Audigy CD Playback Volume */
- A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
- A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
- gpr, 0);
- gpr += 2;
- /* Audigy CD Capture Volume */
- A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
- A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
- gpr, 0);
- gpr += 2;
+ /* Optical SPDIF Playback Volume */
+ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
+ A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
+ gpr += 2;
+ /* Optical SPDIF Capture Volume */
+ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
+ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
+ gpr += 2;
- /* Optical SPDIF Playback Volume */
- A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
- A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
- gpr += 2;
- /* Optical SPDIF Capture Volume */
- A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
- A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
- gpr += 2;
+ /* Line2 Playback Volume */
+ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
+ A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++],
+ emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
+ gpr, 0);
+ gpr += 2;
+ /* Line2 Capture Volume */
+ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
+ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++],
+ emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
+ gpr, 0);
+ gpr += 2;
- /* Line2 Playback Volume */
- A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
- A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
- gpr, 0);
- gpr += 2;
- /* Line2 Capture Volume */
- A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
- A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
- gpr, 0);
- gpr += 2;
-
- /* Philips ADC Playback Volume */
- A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
- A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
- gpr += 2;
- /* Philips ADC Capture Volume */
- A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
- A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
- gpr += 2;
+ /* Philips ADC Playback Volume */
+ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
+ A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
+ gpr += 2;
+ /* Philips ADC Capture Volume */
+ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
+ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
+ gpr += 2;
- /* Aux2 Playback Volume */
- A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
- A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
- gpr, 0);
- gpr += 2;
- /* Aux2 Capture Volume */
- A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
- A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++],
- emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
- gpr, 0);
- gpr += 2;
+ /* Aux2 Playback Volume */
+ A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
+ A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++],
+ emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
+ gpr, 0);
+ gpr += 2;
+ /* Aux2 Capture Volume */
+ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
+ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
+ snd_emu10k1_init_stereo_control(&controls[nctl++],
+ emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
+ gpr, 0);
+ gpr += 2;
+ }
/* Stereo Mix Front Playback Volume */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
gpr += 2;
/* Stereo Mix Surround Playback */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
gpr += 2;
/* Stereo Mix Center Playback */
/* Center = sub = Left/2 + Right/2 */
A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), A_C_40000000, A_GPR(stereo_mix+1));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
gpr++;
/* Stereo Mix LFE Playback */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
gpr++;
if (emu->card_capabilities->spk71) {
/* Stereo Mix Side Playback */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
gpr += 2;
}
@@ -1476,21 +1543,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
/*
* Process tone control
*/
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), A_GPR(playback + 2), A_C_00000000, A_C_00000000); /* rear left */
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */
- if (emu->card_capabilities->spk71) {
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */
- }
-
-
ctl = &controls[nctl + 0];
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, "Tone Control - Bass");
+ strscpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
ctl->min = 0;
@@ -1499,43 +1554,46 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[nctl + 1];
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, "Tone Control - Treble");
+ strscpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
ctl->min = 0;
ctl->max = 40;
ctl->value[0] = ctl->value[1] = 20;
ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
-
-#define BASS_GPR 0x8c
-#define TREBLE_GPR 0x96
-
for (z = 0; z < 5; z++) {
int j;
for (j = 0; j < 2; j++) {
- controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
- controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
+ controls[nctl + 0].gpr[z * 2 + j] = bass_gpr + z * 2 + j;
+ controls[nctl + 1].gpr[z * 2 + j] = treble_gpr + z * 2 + j;
}
}
+ nctl += 2;
+
+ A_OP(icode, &ptr, iACC3, A_C_00000000, A_GPR(gpr), A_C_00000000, A_C_00000000);
+ snd_emu10k1_init_mono_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
+ gpr++;
+ A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_CC_REG_ZERO, A_GPR(gpr));
+ ptr_skip = ptr;
for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
int j, k, l, d;
for (j = 0; j < 2; j++) { /* left/right */
- k = 0xb0 + (z * 8) + (j * 4);
- l = 0xe0 + (z * 8) + (j * 4);
- d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
-
- A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
- A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
- A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
- A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
- A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
+ k = bass_tmp + (z * 8) + (j * 4);
+ l = treble_tmp + (z * 8) + (j * 4);
+ d = playback + z * 2 + j;
+
+ A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(bass_gpr + 0 + j));
+ A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(bass_gpr + 4 + j));
+ A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(bass_gpr + 2 + j));
+ A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(bass_gpr + 8 + j));
+ A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(bass_gpr + 6 + j));
A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
- A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
- A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
- A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
- A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
- A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
+ A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(treble_gpr + 0 + j));
+ A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(treble_gpr + 4 + j));
+ A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(treble_gpr + 2 + j));
+ A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(treble_gpr + 8 + j));
+ A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(treble_gpr + 6 + j));
A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
@@ -1544,90 +1602,70 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
break;
}
}
- nctl += 2;
-
-#undef BASS_GPR
-#undef TREBLE_GPR
-
- for (z = 0; z < 8; z++) {
- A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
- A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
- A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
- A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
- }
- snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
- gpr += 2;
+ gpr_map[gpr++] = ptr - ptr_skip;
/* Master volume (will be renamed later) */
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS));
- A_OP(icode, &ptr, iMAC0, A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS));
+ for (z = 0; z < 8; z++)
+ A_OP(icode, &ptr, iMAC1, A_GPR(playback+z), A_C_00000000, A_GPR(gpr), A_GPR(playback+z));
snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
- gpr += 2;
-
- /* analog speakers */
- A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
- A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
- A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
- A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
- if (emu->card_capabilities->spk71)
- A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
-
- /* headphone */
- A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
+ gpr++;
- /* digital outputs */
- /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
if (emu->card_capabilities->emu_model) {
/* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
dev_info(emu->card->dev, "EMU outputs on\n");
for (z = 0; z < 8; z++) {
if (emu->card_capabilities->ca0108_chip) {
- A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
+ A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + z), A_C_00000000, A_C_00000000);
} else {
- A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
+ A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + z), A_C_00000000, A_C_00000000);
}
}
- }
+ } else {
+ /* analog speakers */
+ A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback);
+ A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2);
+ A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4);
+ A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5);
+ if (emu->card_capabilities->spk71)
+ A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6);
- /* IEC958 Optical Raw Playback Switch */
- gpr_map[gpr++] = 0;
- gpr_map[gpr++] = 0x1008;
- gpr_map[gpr++] = 0xffff0000;
- for (z = 0; z < 2; z++) {
- A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
- A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
- A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
- A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
- A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
- A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
- A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
- if ((z==1) && (emu->card_capabilities->spdif_bug)) {
- /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
- dev_info(emu->card->dev,
- "Installing spdif_bug patch: %s\n",
- emu->card_capabilities->name);
- A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
- } else {
- A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+ /* headphone */
+ A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback);
+
+ /* IEC958 Optical Raw Playback Switch */
+ gpr_map[gpr++] = 0;
+ gpr_map[gpr++] = 0x1008;
+ gpr_map[gpr++] = 0xffff0000;
+ for (z = 0; z < 2; z++) {
+ A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
+ A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
+ A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
+ A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
+ A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
+ A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
+ A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
+ if ((z==1) && (emu->card_capabilities->spdif_bug)) {
+ /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
+ dev_info(emu->card->dev,
+ "Installing spdif_bug patch: %s\n",
+ emu->card_capabilities->name);
+ A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+ } else {
+ A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
+ }
}
+ snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
+ gpr += 2;
+
+ A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2);
+ A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4);
+ A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5);
}
- snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
- gpr += 2;
-
- A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
- A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
- A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* ADC buffer */
#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
- A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
+ A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback);
#else
A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
@@ -1639,11 +1677,17 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
dev_info(emu->card->dev, "EMU2 inputs on\n");
/* Note that the Tina[2] DSPs have 16 more EMU32 inputs which we don't use. */
- for (z = 0; z < 0x10; z++) {
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(
+ icode, &ptr, tmp, bit_shifter16, A3_EMU32IN(0), A_FXBUS2(0));
+ // A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels
+ // need to be delayed as well; we use an auxiliary register for that.
+ for (z = 1; z < 0x10; z++) {
snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
bit_shifter16,
- A3_EMU32IN(z),
+ A_GPR(gpr),
A_FXBUS2(z*2) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr), A3_EMU32IN(z), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
}
} else {
dev_info(emu->card->dev, "EMU inputs on\n");
@@ -1653,102 +1697,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
gpr, tmp);
*/
- /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
- /* A_P16VIN(0) is delayed by one sample,
- * so all other A_P16VIN channels will need to also be delayed
- */
- /* Left ADC in. 1 of 2 */
snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
- /* Right ADC in 1 of 2 */
- gpr_map[gpr++] = 0x00000000;
- /* Delaying by one sample: instead of copying the input
- * value A_P16VIN to output A_FXBUS2 as in the first channel,
- * we use an auxiliary register, delaying the value by one
- * sample
- */
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
- /* For 96kHz mode */
- /* Left ADC in. 2 of 2 */
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
- /* Right ADC in 2 of 2 */
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
- /* Pavel Hofman - we still have voices, A_FXBUS2s, and
- * A_P16VINs available -
- * let's add 8 more capture channels - total of 16
- */
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x10));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x12));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x14));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x16));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x18));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x1a));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x1c));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
- A_C_00000000, A_C_00000000);
- gpr_map[gpr++] = 0x00000000;
- snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
- bit_shifter16,
- A_GPR(gpr - 1),
- A_FXBUS2(0x1e));
- A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
- A_C_00000000, A_C_00000000);
+ /* A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels
+ * will need to also be delayed; we use an auxiliary register for that. */
+ for (z = 1; z < 0x10; z++) {
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr), A_FXBUS2(z * 2) );
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr), A_P16VIN(z), A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ }
}
#if 0
@@ -1772,11 +1728,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
* ok, set up done..
*/
- if (gpr > tmp) {
+ if (gpr > 512) {
snd_BUG();
err = -EIO;
goto __err;
}
+
/* clear remaining instruction memory */
while (ptr < 0x400)
A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
@@ -1801,30 +1758,14 @@ __err_gpr:
* initial DSP configuration for Emu10k1
*/
-/* when volume = max, then copy only to avoid volume modification */
-/* with iMAC0 (negative values) */
+/* Volumes are in the [-2^31, 0] range, zero being mute. */
static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
{
- OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
- OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
- OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
- OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
+ OP(icode, ptr, iMAC1, dst, C_00000000, src, vol);
}
static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
{
- OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
- OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
- OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
- OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
- OP(icode, ptr, iMAC0, dst, dst, src, vol);
-}
-static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
-{
- OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
- OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
- OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
- OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
- OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
+ OP(icode, ptr, iMAC1, dst, dst, src, vol);
}
#define VOLUME(icode, ptr, dst, src, vol) \
@@ -1836,7 +1777,7 @@ static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst
#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
_volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
#define VOLUME_OUT(icode, ptr, dst, src, vol) \
- _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
+ _volume(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
#define _SWITCH(icode, ptr, dst, src, sw) \
OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
#define SWITCH(icode, ptr, dst, src, sw) \
@@ -1852,7 +1793,7 @@ static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst
static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
{
int err, i, z, gpr, tmp, playback, capture;
- u32 ptr;
+ u32 ptr, ptr_skip;
struct snd_emu10k1_fx8010_code *icode;
struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
@@ -1890,12 +1831,12 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/* clear TRAM data & address lines */
memset(icode->tram_valid, 0xff, 160 / 8);
- strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
+ strscpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
ptr = 0; i = 0;
/* we have 12 inputs */
playback = SND_EMU10K1_INPUTS;
/* we have 6 playback channels and tone control doubles */
- capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
+ capture = playback + SND_EMU10K1_PLAYBACK_CHANNELS;
gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
tmp = 0x88; /* we need 4 temporary GPR */
/* from 0x8c to 0xff is the area for tone control */
@@ -1903,18 +1844,18 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/*
* Process FX Buses
*/
- OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
+ OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000008);
OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
- OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
- OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
+ OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000008);
+ OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000008);
/* Raw S/PDIF PCM */
ipcm->substream = 0;
@@ -2008,7 +1949,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/* Wave Center/LFE Playback Volume */
OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
- OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
+ OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000004);
VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
@@ -2199,16 +2140,9 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/*
* Process tone control
*/
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
-
ctl = &controls[i + 0];
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, "Tone Control - Bass");
+ strscpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
ctl->min = 0;
@@ -2218,7 +2152,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[i + 1];
ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(ctl->id.name, "Tone Control - Treble");
+ strscpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
ctl->min = 0;
@@ -2237,12 +2171,19 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
}
}
+ i += 2;
+
+ OP(icode, &ptr, iACC3, C_00000000, GPR(gpr), C_00000000, C_00000000);
+ snd_emu10k1_init_mono_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
+ gpr++;
+ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr));
+ ptr_skip = ptr;
for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
int j, k, l, d;
for (j = 0; j < 2; j++) { /* left/right */
k = 0xa0 + (z * 8) + (j * 4);
l = 0xd0 + (z * 8) + (j * 4);
- d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
+ d = playback + z * 2 + j;
OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
@@ -2264,20 +2205,11 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
break;
}
}
- i += 2;
+ gpr_map[gpr++] = ptr - ptr_skip;
#undef BASS_GPR
#undef TREBLE_GPR
- for (z = 0; z < 6; z++) {
- SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
- SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
- SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
- OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
- }
- snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
- gpr += 2;
-
/*
* Process outputs
*/
@@ -2285,7 +2217,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/* AC'97 Playback Volume */
for (z = 0; z < 2; z++)
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + z), C_00000000, C_00000000);
}
if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
@@ -2294,7 +2226,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
for (z = 0; z < 2; z++) {
SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
- SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
+ SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
@@ -2309,9 +2241,9 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/* Headphone Playback Volume */
for (z = 0; z < 2; z++) {
- SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
+ SWITCH(icode, &ptr, tmp + 0, playback + 4 + z, gpr + 2 + z);
SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
- SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
+ SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
}
@@ -2328,29 +2260,29 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
for (z = 0; z < 2; z++)
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + 2 + z), C_00000000, C_00000000);
if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
for (z = 0; z < 2; z++)
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + 2 + z), C_00000000, C_00000000);
if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + 4), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + 4), C_00000000, C_00000000);
#else
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + 0), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + 0), C_00000000, C_00000000);
#endif
}
if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + 5), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + 5), C_00000000, C_00000000);
#else
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
- OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + 1), C_00000000, C_00000000);
+ OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + 1), C_00000000, C_00000000);
#endif
}
@@ -2364,21 +2296,11 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
/* EFX capture - capture the 16 EXTINS */
if (emu->card_capabilities->sblive51) {
- /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
- * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
- *
- * Since only 14 of the 16 EXTINs are used, this is not a big problem.
- * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
- * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
- * channel. Multitrack recorders will still see the center/lfe output signal
- * on the second and third channels.
- */
- OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
- OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
- OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
- OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
- for (z = 4; z < 14; z++)
- OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
+ for (z = 0; z < 16; z++) {
+ s8 c = snd_emu10k1_sblive51_fxbus2_map[z];
+ if (c != -1)
+ OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(c));
+ }
} else {
for (z = 0; z < 16; z++)
OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
@@ -2474,9 +2396,9 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
}
if ((emu->fx8010.etram_pages.bytes / 2) == size)
return 0;
- spin_lock_irq(&emu->emu_lock);
- outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
- spin_unlock_irq(&emu->emu_lock);
+ scoped_guard(spinlock_irq, &emu->emu_lock) {
+ outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
+ }
snd_emu10k1_ptr_write(emu, TCB, 0, 0);
snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K);
if (emu->fx8010.etram_pages.area != NULL) {
@@ -2492,9 +2414,9 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
memset(emu->fx8010.etram_pages.area, 0, size * 2);
snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
- spin_lock_irq(&emu->emu_lock);
- outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
- spin_unlock_irq(&emu->emu_lock);
+ scoped_guard(spinlock_irq, &emu->emu_lock) {
+ outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
+ }
}
return 0;
@@ -2522,9 +2444,9 @@ static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
info->internal_tram_size = emu->fx8010.itram_size;
info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
- fxbus = fxbuses;
- extin = emu->audigy ? audigy_ins : creative_ins;
- extout = emu->audigy ? audigy_outs : creative_outs;
+ fxbus = snd_emu10k1_fxbus;
+ extin = emu->audigy ? snd_emu10k1_audigy_ins : snd_emu10k1_sblive_ins;
+ extout = emu->audigy ? snd_emu10k1_audigy_outs : snd_emu10k1_sblive_outs;
extin_mask = emu->audigy ? ~0 : emu->fx8010.extin_mask;
extout_mask = emu->audigy ? ~0 : emu->fx8010.extout_mask;
for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
@@ -2606,9 +2528,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un
return -EPERM;
if (get_user(addr, (unsigned int __user *)argp))
return -EFAULT;
- mutex_lock(&emu->fx8010.lock);
- res = snd_emu10k1_fx8010_tram_setup(emu, addr);
- mutex_unlock(&emu->fx8010.lock);
+ scoped_guard(mutex, &emu->fx8010.lock) {
+ res = snd_emu10k1_fx8010_tram_setup(emu, addr);
+ }
return res;
case SNDRV_EMU10K1_IOCTL_STOP:
if (!capable(CAP_SYS_ADMIN))
@@ -2683,7 +2605,7 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
err = snd_hwdep_new(emu->card, "FX8010", device, &hw);
if (err < 0)
return err;
- strcpy(hw->name, "EMU10K1 (FX8010)");
+ strscpy(hw->name, "EMU10K1 (FX8010)");
hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
hw->ops.open = snd_emu10k1_fx8010_open;
hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 3ebc7c36a444..f4906ab30c02 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -2,22 +2,17 @@
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
* Takashi Iwai <tiwai@suse.de>
+ * Lee Revell <rlrevell@joe-job.com>
+ * James Courtier-Dutton <James@superbug.co.uk>
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
* Creative Labs, Inc.
- * Routines for control of EMU10K1 chips / mixer routines
- * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
- *
- * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
- * Added EMU 1010 support.
- *
- * BUGS:
- * --
*
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips / mixer routines
*/
#include <linux/time.h>
#include <linux/init.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
#include <linux/delay.h>
@@ -29,6 +24,24 @@
static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
+
+static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl,
+ const char * const *ctls, unsigned nctls)
+{
+ struct snd_kcontrol_new kctl = *tpl;
+ int err;
+
+ for (unsigned i = 0; i < nctls; i++) {
+ kctl.name = ctls[i];
+ kctl.private_value = i;
+ err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+
static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
@@ -41,17 +54,14 @@ static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- unsigned long flags;
/* Limit: emu->spdif_bits */
if (idx >= 3)
return -EINVAL;
- spin_lock_irqsave(&emu->reg_lock, flags);
ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
@@ -65,292 +75,354 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
return 0;
}
+#define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx
+#define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx)
+
+#define ADAT_PS(pfx, sfx) \
+ pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \
+ pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx
+
+#define PAIR_REGS(base, one, two) \
+ base ## one ## 1, \
+ base ## two ## 1
+
+#define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT)
+
+#define ADAT_REGS(base) \
+ base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7
+
/*
- * Items labels in enum mixer controls assigning source data to
- * each destination
+ * List of data sources available for each destination
*/
+
+#define DSP_TEXTS \
+ "DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \
+ "DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \
+ "DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \
+ "DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31"
+
+#define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "")
+#define LR_TEXTS(base) LR_PS(base, "")
+#define ADAT_TEXTS(pfx) ADAT_PS(pfx, "")
+
+#define EMU32_SRC_REGS \
+ EMU_SRC_ALICE_EMU32A, \
+ EMU_SRC_ALICE_EMU32A+1, \
+ EMU_SRC_ALICE_EMU32A+2, \
+ EMU_SRC_ALICE_EMU32A+3, \
+ EMU_SRC_ALICE_EMU32A+4, \
+ EMU_SRC_ALICE_EMU32A+5, \
+ EMU_SRC_ALICE_EMU32A+6, \
+ EMU_SRC_ALICE_EMU32A+7, \
+ EMU_SRC_ALICE_EMU32A+8, \
+ EMU_SRC_ALICE_EMU32A+9, \
+ EMU_SRC_ALICE_EMU32A+0xa, \
+ EMU_SRC_ALICE_EMU32A+0xb, \
+ EMU_SRC_ALICE_EMU32A+0xc, \
+ EMU_SRC_ALICE_EMU32A+0xd, \
+ EMU_SRC_ALICE_EMU32A+0xe, \
+ EMU_SRC_ALICE_EMU32A+0xf, \
+ EMU_SRC_ALICE_EMU32B, \
+ EMU_SRC_ALICE_EMU32B+1, \
+ EMU_SRC_ALICE_EMU32B+2, \
+ EMU_SRC_ALICE_EMU32B+3, \
+ EMU_SRC_ALICE_EMU32B+4, \
+ EMU_SRC_ALICE_EMU32B+5, \
+ EMU_SRC_ALICE_EMU32B+6, \
+ EMU_SRC_ALICE_EMU32B+7, \
+ EMU_SRC_ALICE_EMU32B+8, \
+ EMU_SRC_ALICE_EMU32B+9, \
+ EMU_SRC_ALICE_EMU32B+0xa, \
+ EMU_SRC_ALICE_EMU32B+0xb, \
+ EMU_SRC_ALICE_EMU32B+0xc, \
+ EMU_SRC_ALICE_EMU32B+0xd, \
+ EMU_SRC_ALICE_EMU32B+0xe, \
+ EMU_SRC_ALICE_EMU32B+0xf
+
+/* 1010 rev1 */
+
+#define EMU1010_COMMON_TEXTS \
+ "Silence", \
+ PAIR_TEXTS("Dock Mic", "A", "B"), \
+ LR_TEXTS("Dock ADC1"), \
+ LR_TEXTS("Dock ADC2"), \
+ LR_TEXTS("Dock ADC3"), \
+ LR_TEXTS("0202 ADC"), \
+ LR_TEXTS("1010 SPDIF"), \
+ ADAT_TEXTS("1010 ")
+
static const char * const emu1010_src_texts[] = {
- "Silence",
- "Dock Mic A",
- "Dock Mic B",
- "Dock ADC1 Left",
- "Dock ADC1 Right",
- "Dock ADC2 Left",
- "Dock ADC2 Right",
- "Dock ADC3 Left",
- "Dock ADC3 Right",
- "0202 ADC Left",
- "0202 ADC Right",
- "0202 SPDIF Left",
- "0202 SPDIF Right",
- "ADAT 0",
- "ADAT 1",
- "ADAT 2",
- "ADAT 3",
- "ADAT 4",
- "ADAT 5",
- "ADAT 6",
- "ADAT 7",
- "DSP 0",
- "DSP 1",
- "DSP 2",
- "DSP 3",
- "DSP 4",
- "DSP 5",
- "DSP 6",
- "DSP 7",
- "DSP 8",
- "DSP 9",
- "DSP 10",
- "DSP 11",
- "DSP 12",
- "DSP 13",
- "DSP 14",
- "DSP 15",
- "DSP 16",
- "DSP 17",
- "DSP 18",
- "DSP 19",
- "DSP 20",
- "DSP 21",
- "DSP 22",
- "DSP 23",
- "DSP 24",
- "DSP 25",
- "DSP 26",
- "DSP 27",
- "DSP 28",
- "DSP 29",
- "DSP 30",
- "DSP 31",
+ EMU1010_COMMON_TEXTS,
+ DSP_TEXTS,
+};
+
+static const unsigned short emu1010_src_regs[] = {
+ EMU_SRC_SILENCE,
+ PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
+ LR_REGS(EMU_SRC_DOCK_ADC1),
+ LR_REGS(EMU_SRC_DOCK_ADC2),
+ LR_REGS(EMU_SRC_DOCK_ADC3),
+ LR_REGS(EMU_SRC_HAMOA_ADC),
+ LR_REGS(EMU_SRC_HANA_SPDIF),
+ ADAT_REGS(EMU_SRC_HANA_ADAT),
+ EMU32_SRC_REGS,
+};
+static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts));
+
+/* 1010 rev2 */
+
+#define EMU1010b_COMMON_TEXTS \
+ "Silence", \
+ PAIR_TEXTS("Dock Mic", "A", "B"), \
+ LR_TEXTS("Dock ADC1"), \
+ LR_TEXTS("Dock ADC2"), \
+ LR_TEXTS("0202 ADC"), \
+ LR_TEXTS("Dock SPDIF"), \
+ LR_TEXTS("1010 SPDIF"), \
+ ADAT_TEXTS("Dock "), \
+ ADAT_TEXTS("1010 ")
+
+static const char * const emu1010b_src_texts[] = {
+ EMU1010b_COMMON_TEXTS,
+ DSP_TEXTS,
+};
+
+static const unsigned short emu1010b_src_regs[] = {
+ EMU_SRC_SILENCE,
+ PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
+ LR_REGS(EMU_SRC_DOCK_ADC1),
+ LR_REGS(EMU_SRC_DOCK_ADC2),
+ LR_REGS(EMU_SRC_HAMOA_ADC),
+ LR_REGS(EMU_SRC_MDOCK_SPDIF),
+ LR_REGS(EMU_SRC_HANA_SPDIF),
+ ADAT_REGS(EMU_SRC_MDOCK_ADAT),
+ ADAT_REGS(EMU_SRC_HANA_ADAT),
+ EMU32_SRC_REGS,
};
+static_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts));
/* 1616(m) cardbus */
+#define EMU1616_COMMON_TEXTS \
+ "Silence", \
+ PAIR_TEXTS("Mic", "A", "B"), \
+ LR_TEXTS("ADC1"), \
+ LR_TEXTS("ADC2"), \
+ LR_TEXTS("SPDIF"), \
+ ADAT_TEXTS("")
+
static const char * const emu1616_src_texts[] = {
- "Silence",
- "Dock Mic A",
- "Dock Mic B",
- "Dock ADC1 Left",
- "Dock ADC1 Right",
- "Dock ADC2 Left",
- "Dock ADC2 Right",
- "Dock SPDIF Left",
- "Dock SPDIF Right",
- "ADAT 0",
- "ADAT 1",
- "ADAT 2",
- "ADAT 3",
- "ADAT 4",
- "ADAT 5",
- "ADAT 6",
- "ADAT 7",
- "DSP 0",
- "DSP 1",
- "DSP 2",
- "DSP 3",
- "DSP 4",
- "DSP 5",
- "DSP 6",
- "DSP 7",
- "DSP 8",
- "DSP 9",
- "DSP 10",
- "DSP 11",
- "DSP 12",
- "DSP 13",
- "DSP 14",
- "DSP 15",
- "DSP 16",
- "DSP 17",
- "DSP 18",
- "DSP 19",
- "DSP 20",
- "DSP 21",
- "DSP 22",
- "DSP 23",
- "DSP 24",
- "DSP 25",
- "DSP 26",
- "DSP 27",
- "DSP 28",
- "DSP 29",
- "DSP 30",
- "DSP 31",
+ EMU1616_COMMON_TEXTS,
+ DSP_TEXTS,
};
+static const unsigned short emu1616_src_regs[] = {
+ EMU_SRC_SILENCE,
+ PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
+ LR_REGS(EMU_SRC_DOCK_ADC1),
+ LR_REGS(EMU_SRC_DOCK_ADC2),
+ LR_REGS(EMU_SRC_MDOCK_SPDIF),
+ ADAT_REGS(EMU_SRC_MDOCK_ADAT),
+ EMU32_SRC_REGS,
+};
+static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts));
-/*
- * List of data sources available for each destination
- */
-static const unsigned int emu1010_src_regs[] = {
- EMU_SRC_SILENCE,/* 0 */
- EMU_SRC_DOCK_MIC_A1, /* 1 */
- EMU_SRC_DOCK_MIC_B1, /* 2 */
- EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
- EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
- EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
- EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
- EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
- EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
- EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
- EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
- EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
- EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
- EMU_SRC_HANA_ADAT, /* 13 */
- EMU_SRC_HANA_ADAT+1, /* 14 */
- EMU_SRC_HANA_ADAT+2, /* 15 */
- EMU_SRC_HANA_ADAT+3, /* 16 */
- EMU_SRC_HANA_ADAT+4, /* 17 */
- EMU_SRC_HANA_ADAT+5, /* 18 */
- EMU_SRC_HANA_ADAT+6, /* 19 */
- EMU_SRC_HANA_ADAT+7, /* 20 */
- EMU_SRC_ALICE_EMU32A, /* 21 */
- EMU_SRC_ALICE_EMU32A+1, /* 22 */
- EMU_SRC_ALICE_EMU32A+2, /* 23 */
- EMU_SRC_ALICE_EMU32A+3, /* 24 */
- EMU_SRC_ALICE_EMU32A+4, /* 25 */
- EMU_SRC_ALICE_EMU32A+5, /* 26 */
- EMU_SRC_ALICE_EMU32A+6, /* 27 */
- EMU_SRC_ALICE_EMU32A+7, /* 28 */
- EMU_SRC_ALICE_EMU32A+8, /* 29 */
- EMU_SRC_ALICE_EMU32A+9, /* 30 */
- EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
- EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
- EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
- EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
- EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
- EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
- EMU_SRC_ALICE_EMU32B, /* 37 */
- EMU_SRC_ALICE_EMU32B+1, /* 38 */
- EMU_SRC_ALICE_EMU32B+2, /* 39 */
- EMU_SRC_ALICE_EMU32B+3, /* 40 */
- EMU_SRC_ALICE_EMU32B+4, /* 41 */
- EMU_SRC_ALICE_EMU32B+5, /* 42 */
- EMU_SRC_ALICE_EMU32B+6, /* 43 */
- EMU_SRC_ALICE_EMU32B+7, /* 44 */
- EMU_SRC_ALICE_EMU32B+8, /* 45 */
- EMU_SRC_ALICE_EMU32B+9, /* 46 */
- EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
- EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
- EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
- EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
- EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
- EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
+/* 0404 rev1 & rev2 */
+
+#define EMU0404_COMMON_TEXTS \
+ "Silence", \
+ LR_TEXTS("ADC"), \
+ LR_TEXTS("SPDIF")
+
+static const char * const emu0404_src_texts[] = {
+ EMU0404_COMMON_TEXTS,
+ DSP_TEXTS,
};
-/* 1616(m) cardbus */
-static const unsigned int emu1616_src_regs[] = {
+static const unsigned short emu0404_src_regs[] = {
EMU_SRC_SILENCE,
- EMU_SRC_DOCK_MIC_A1,
- EMU_SRC_DOCK_MIC_B1,
- EMU_SRC_DOCK_ADC1_LEFT1,
- EMU_SRC_DOCK_ADC1_RIGHT1,
- EMU_SRC_DOCK_ADC2_LEFT1,
- EMU_SRC_DOCK_ADC2_RIGHT1,
- EMU_SRC_MDOCK_SPDIF_LEFT1,
- EMU_SRC_MDOCK_SPDIF_RIGHT1,
- EMU_SRC_MDOCK_ADAT,
- EMU_SRC_MDOCK_ADAT+1,
- EMU_SRC_MDOCK_ADAT+2,
- EMU_SRC_MDOCK_ADAT+3,
- EMU_SRC_MDOCK_ADAT+4,
- EMU_SRC_MDOCK_ADAT+5,
- EMU_SRC_MDOCK_ADAT+6,
- EMU_SRC_MDOCK_ADAT+7,
- EMU_SRC_ALICE_EMU32A,
- EMU_SRC_ALICE_EMU32A+1,
- EMU_SRC_ALICE_EMU32A+2,
- EMU_SRC_ALICE_EMU32A+3,
- EMU_SRC_ALICE_EMU32A+4,
- EMU_SRC_ALICE_EMU32A+5,
- EMU_SRC_ALICE_EMU32A+6,
- EMU_SRC_ALICE_EMU32A+7,
- EMU_SRC_ALICE_EMU32A+8,
- EMU_SRC_ALICE_EMU32A+9,
- EMU_SRC_ALICE_EMU32A+0xa,
- EMU_SRC_ALICE_EMU32A+0xb,
- EMU_SRC_ALICE_EMU32A+0xc,
- EMU_SRC_ALICE_EMU32A+0xd,
- EMU_SRC_ALICE_EMU32A+0xe,
- EMU_SRC_ALICE_EMU32A+0xf,
- EMU_SRC_ALICE_EMU32B,
- EMU_SRC_ALICE_EMU32B+1,
- EMU_SRC_ALICE_EMU32B+2,
- EMU_SRC_ALICE_EMU32B+3,
- EMU_SRC_ALICE_EMU32B+4,
- EMU_SRC_ALICE_EMU32B+5,
- EMU_SRC_ALICE_EMU32B+6,
- EMU_SRC_ALICE_EMU32B+7,
- EMU_SRC_ALICE_EMU32B+8,
- EMU_SRC_ALICE_EMU32B+9,
- EMU_SRC_ALICE_EMU32B+0xa,
- EMU_SRC_ALICE_EMU32B+0xb,
- EMU_SRC_ALICE_EMU32B+0xc,
- EMU_SRC_ALICE_EMU32B+0xd,
- EMU_SRC_ALICE_EMU32B+0xe,
- EMU_SRC_ALICE_EMU32B+0xf,
+ LR_REGS(EMU_SRC_HAMOA_ADC),
+ LR_REGS(EMU_SRC_HANA_SPDIF),
+ EMU32_SRC_REGS,
};
+static_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts));
/*
* Data destinations - physical EMU outputs.
* Each destination has an enum mixer control to choose a data source
*/
-static const unsigned int emu1010_output_dst[] = {
- EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
- EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
- EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
- EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
- EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
- EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
- EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
- EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
- EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
- EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
- EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
- EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
- EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
- EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
- EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
- EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
- EMU_DST_HANA_ADAT, /* 16 */
- EMU_DST_HANA_ADAT+1, /* 17 */
- EMU_DST_HANA_ADAT+2, /* 18 */
- EMU_DST_HANA_ADAT+3, /* 19 */
- EMU_DST_HANA_ADAT+4, /* 20 */
- EMU_DST_HANA_ADAT+5, /* 21 */
- EMU_DST_HANA_ADAT+6, /* 22 */
- EMU_DST_HANA_ADAT+7, /* 23 */
+
+#define LR_CTLS(base) LR_PS(base, " Playback Enum")
+#define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
+
+/* 1010 rev1 */
+
+static const char * const emu1010_output_texts[] = {
+ LR_CTLS("Dock DAC1"),
+ LR_CTLS("Dock DAC2"),
+ LR_CTLS("Dock DAC3"),
+ LR_CTLS("Dock DAC4"),
+ LR_CTLS("Dock Phones"),
+ LR_CTLS("Dock SPDIF"),
+ LR_CTLS("0202 DAC"),
+ LR_CTLS("1010 SPDIF"),
+ ADAT_CTLS("1010 "),
+};
+static_assert(ARRAY_SIZE(emu1010_output_texts) <= NUM_OUTPUT_DESTS);
+
+static const unsigned short emu1010_output_dst[] = {
+ LR_REGS(EMU_DST_DOCK_DAC1),
+ LR_REGS(EMU_DST_DOCK_DAC2),
+ LR_REGS(EMU_DST_DOCK_DAC3),
+ LR_REGS(EMU_DST_DOCK_DAC4),
+ LR_REGS(EMU_DST_DOCK_PHONES),
+ LR_REGS(EMU_DST_DOCK_SPDIF),
+ LR_REGS(EMU_DST_HAMOA_DAC),
+ LR_REGS(EMU_DST_HANA_SPDIF),
+ ADAT_REGS(EMU_DST_HANA_ADAT),
+};
+static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
+
+static const unsigned short emu1010_output_dflt[] = {
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
+ EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
+};
+static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
+
+/* 1010 rev2 */
+
+static const char * const snd_emu1010b_output_texts[] = {
+ LR_CTLS("Dock DAC1"),
+ LR_CTLS("Dock DAC2"),
+ LR_CTLS("Dock DAC3"),
+ LR_CTLS("Dock SPDIF"),
+ ADAT_CTLS("Dock "),
+ LR_CTLS("0202 DAC"),
+ LR_CTLS("1010 SPDIF"),
+ ADAT_CTLS("1010 "),
+};
+static_assert(ARRAY_SIZE(snd_emu1010b_output_texts) <= NUM_OUTPUT_DESTS);
+
+static const unsigned short emu1010b_output_dst[] = {
+ LR_REGS(EMU_DST_DOCK_DAC1),
+ LR_REGS(EMU_DST_DOCK_DAC2),
+ LR_REGS(EMU_DST_DOCK_DAC3),
+ LR_REGS(EMU_DST_MDOCK_SPDIF),
+ ADAT_REGS(EMU_DST_MDOCK_ADAT),
+ LR_REGS(EMU_DST_HAMOA_DAC),
+ LR_REGS(EMU_DST_HANA_SPDIF),
+ ADAT_REGS(EMU_DST_HANA_ADAT),
+};
+static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts));
+
+static const unsigned short emu1010b_output_dflt[] = {
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
};
/* 1616(m) cardbus */
-static const unsigned int emu1616_output_dst[] = {
- EMU_DST_DOCK_DAC1_LEFT1,
- EMU_DST_DOCK_DAC1_RIGHT1,
- EMU_DST_DOCK_DAC2_LEFT1,
- EMU_DST_DOCK_DAC2_RIGHT1,
- EMU_DST_DOCK_DAC3_LEFT1,
- EMU_DST_DOCK_DAC3_RIGHT1,
- EMU_DST_MDOCK_SPDIF_LEFT1,
- EMU_DST_MDOCK_SPDIF_RIGHT1,
- EMU_DST_MDOCK_ADAT,
- EMU_DST_MDOCK_ADAT+1,
- EMU_DST_MDOCK_ADAT+2,
- EMU_DST_MDOCK_ADAT+3,
- EMU_DST_MDOCK_ADAT+4,
- EMU_DST_MDOCK_ADAT+5,
- EMU_DST_MDOCK_ADAT+6,
- EMU_DST_MDOCK_ADAT+7,
- EMU_DST_MANA_DAC_LEFT,
- EMU_DST_MANA_DAC_RIGHT,
+
+static const char * const snd_emu1616_output_texts[] = {
+ LR_CTLS("Dock DAC1"),
+ LR_CTLS("Dock DAC2"),
+ LR_CTLS("Dock DAC3"),
+ LR_CTLS("Dock SPDIF"),
+ ADAT_CTLS("Dock "),
+ LR_CTLS("Mana DAC"),
+};
+static_assert(ARRAY_SIZE(snd_emu1616_output_texts) <= NUM_OUTPUT_DESTS);
+
+static const unsigned short emu1616_output_dst[] = {
+ LR_REGS(EMU_DST_DOCK_DAC1),
+ LR_REGS(EMU_DST_DOCK_DAC2),
+ LR_REGS(EMU_DST_DOCK_DAC3),
+ LR_REGS(EMU_DST_MDOCK_SPDIF),
+ ADAT_REGS(EMU_DST_MDOCK_ADAT),
+ EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
+};
+static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
+
+static const unsigned short emu1616_output_dflt[] = {
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
+ EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+};
+static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
+
+/* 0404 rev1 & rev2 */
+
+static const char * const snd_emu0404_output_texts[] = {
+ LR_CTLS("DAC"),
+ LR_CTLS("SPDIF"),
};
+static_assert(ARRAY_SIZE(snd_emu0404_output_texts) <= NUM_OUTPUT_DESTS);
+
+static const unsigned short emu0404_output_dst[] = {
+ LR_REGS(EMU_DST_HAMOA_DAC),
+ LR_REGS(EMU_DST_HANA_SPDIF),
+};
+static_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts));
+
+static const unsigned short emu0404_output_dflt[] = {
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+ EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
+};
+static_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst));
/*
* Data destinations - FPGA outputs going to Alice2 (Audigy) for
* capture (EMU32 + I2S links)
* Each destination has an enum mixer control to choose a data source
*/
-static const unsigned int emu1010_input_dst[] = {
+
+static const char * const emu1010_input_texts[] = {
+ "DSP 0 Capture Enum",
+ "DSP 1 Capture Enum",
+ "DSP 2 Capture Enum",
+ "DSP 3 Capture Enum",
+ "DSP 4 Capture Enum",
+ "DSP 5 Capture Enum",
+ "DSP 6 Capture Enum",
+ "DSP 7 Capture Enum",
+ "DSP 8 Capture Enum",
+ "DSP 9 Capture Enum",
+ "DSP A Capture Enum",
+ "DSP B Capture Enum",
+ "DSP C Capture Enum",
+ "DSP D Capture Enum",
+ "DSP E Capture Enum",
+ "DSP F Capture Enum",
+ /* These exist only on rev1 EMU1010 cards. */
+ "DSP 10 Capture Enum",
+ "DSP 11 Capture Enum",
+ "DSP 12 Capture Enum",
+ "DSP 13 Capture Enum",
+ "DSP 14 Capture Enum",
+ "DSP 15 Capture Enum",
+};
+static_assert(ARRAY_SIZE(emu1010_input_texts) <= NUM_INPUT_DESTS);
+
+static const unsigned short emu1010_input_dst[] = {
EMU_DST_ALICE2_EMU32_0,
EMU_DST_ALICE2_EMU32_1,
EMU_DST_ALICE2_EMU32_2,
@@ -375,29 +447,199 @@ static const unsigned int emu1010_input_dst[] = {
EMU_DST_ALICE_I2S2_LEFT,
EMU_DST_ALICE_I2S2_RIGHT,
};
+static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
+
+static const unsigned short emu1010_input_dflt[] = {
+ EMU_SRC_DOCK_MIC_A1,
+ EMU_SRC_DOCK_MIC_B1,
+ EMU_SRC_HAMOA_ADC_LEFT1,
+ EMU_SRC_HAMOA_ADC_RIGHT1,
+ EMU_SRC_DOCK_ADC1_LEFT1,
+ EMU_SRC_DOCK_ADC1_RIGHT1,
+ EMU_SRC_DOCK_ADC2_LEFT1,
+ EMU_SRC_DOCK_ADC2_RIGHT1,
+ /* Pavel Hofman - setting defaults for all capture channels.
+ * Defaults only, users will set their own values anyways, let's
+ * just copy/paste. */
+ EMU_SRC_DOCK_MIC_A1,
+ EMU_SRC_DOCK_MIC_B1,
+ EMU_SRC_HAMOA_ADC_LEFT1,
+ EMU_SRC_HAMOA_ADC_RIGHT1,
+ EMU_SRC_DOCK_ADC1_LEFT1,
+ EMU_SRC_DOCK_ADC1_RIGHT1,
+ EMU_SRC_DOCK_ADC2_LEFT1,
+ EMU_SRC_DOCK_ADC2_RIGHT1,
+
+ EMU_SRC_DOCK_ADC1_LEFT1,
+ EMU_SRC_DOCK_ADC1_RIGHT1,
+ EMU_SRC_DOCK_ADC2_LEFT1,
+ EMU_SRC_DOCK_ADC2_RIGHT1,
+ EMU_SRC_DOCK_ADC3_LEFT1,
+ EMU_SRC_DOCK_ADC3_RIGHT1,
+};
+static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
+
+static const unsigned short emu0404_input_dflt[] = {
+ EMU_SRC_HAMOA_ADC_LEFT1,
+ EMU_SRC_HAMOA_ADC_RIGHT1,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_HANA_SPDIF_LEFT1,
+ EMU_SRC_HANA_SPDIF_RIGHT1,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+ EMU_SRC_SILENCE,
+};
+
+struct snd_emu1010_routing_info {
+ const char * const *src_texts;
+ const char * const *out_texts;
+ const unsigned short *src_regs;
+ const unsigned short *out_regs;
+ const unsigned short *in_regs;
+ const unsigned short *out_dflts;
+ const unsigned short *in_dflts;
+ unsigned n_srcs;
+ unsigned n_outs;
+ unsigned n_ins;
+};
+
+static const struct snd_emu1010_routing_info emu1010_routing_info[] = {
+ {
+ /* rev1 1010 */
+ .src_regs = emu1010_src_regs,
+ .src_texts = emu1010_src_texts,
+ .n_srcs = ARRAY_SIZE(emu1010_src_texts),
+
+ .out_dflts = emu1010_output_dflt,
+ .out_regs = emu1010_output_dst,
+ .out_texts = emu1010_output_texts,
+ .n_outs = ARRAY_SIZE(emu1010_output_dst),
+
+ .in_dflts = emu1010_input_dflt,
+ .in_regs = emu1010_input_dst,
+ .n_ins = ARRAY_SIZE(emu1010_input_dst),
+ },
+ {
+ /* rev2 1010 */
+ .src_regs = emu1010b_src_regs,
+ .src_texts = emu1010b_src_texts,
+ .n_srcs = ARRAY_SIZE(emu1010b_src_texts),
+
+ .out_dflts = emu1010b_output_dflt,
+ .out_regs = emu1010b_output_dst,
+ .out_texts = snd_emu1010b_output_texts,
+ .n_outs = ARRAY_SIZE(emu1010b_output_dst),
+
+ .in_dflts = emu1010_input_dflt,
+ .in_regs = emu1010_input_dst,
+ .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
+ },
+ {
+ /* 1616(m) cardbus */
+ .src_regs = emu1616_src_regs,
+ .src_texts = emu1616_src_texts,
+ .n_srcs = ARRAY_SIZE(emu1616_src_texts),
+
+ .out_dflts = emu1616_output_dflt,
+ .out_regs = emu1616_output_dst,
+ .out_texts = snd_emu1616_output_texts,
+ .n_outs = ARRAY_SIZE(emu1616_output_dst),
+
+ .in_dflts = emu1010_input_dflt,
+ .in_regs = emu1010_input_dst,
+ .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
+ },
+ {
+ /* 0404 */
+ .src_regs = emu0404_src_regs,
+ .src_texts = emu0404_src_texts,
+ .n_srcs = ARRAY_SIZE(emu0404_src_texts),
+
+ .out_dflts = emu0404_output_dflt,
+ .out_regs = emu0404_output_dst,
+ .out_texts = snd_emu0404_output_texts,
+ .n_outs = ARRAY_SIZE(emu0404_output_dflt),
+
+ .in_dflts = emu0404_input_dflt,
+ .in_regs = emu1010_input_dst,
+ .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
+ },
+};
+
+static unsigned emu1010_idx(struct snd_emu10k1 *emu)
+{
+ return emu->card_capabilities->emu_model - 1;
+}
+
+static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
+ int channel, int src)
+{
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu_ri->out_regs[channel], emu_ri->src_regs[src]);
+}
+
+static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
+ int channel, int src)
+{
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ emu_ri->in_regs[channel], emu_ri->src_regs[src]);
+}
+
+static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
+{
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+
+ for (unsigned i = 0; i < emu_ri->n_outs; i++)
+ snd_emu1010_output_source_apply(
+ emu, i, emu->emu1010.output_source[i]);
+ for (unsigned i = 0; i < emu_ri->n_ins; i++)
+ snd_emu1010_input_source_apply(
+ emu, i, emu->emu1010.input_source[i]);
+}
+
+static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
+ unsigned val)
+{
+ for (unsigned i = 0; i < emu_ri->n_srcs; i++)
+ if (val == emu_ri->src_regs[i])
+ return i;
+ return 0;
+}
static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
- return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
- else
- return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
+ return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
}
static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int channel;
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+ unsigned channel = kcontrol->private_value;
- channel = (kcontrol->private_value) & 0xff;
- /* Limit: emu1010_output_dst, emu->emu1010.output_source */
- if (channel >= 24 ||
- (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
- channel >= 18))
+ if (channel >= emu_ri->n_outs)
return -EINVAL;
ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
return 0;
@@ -407,41 +649,42 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int val;
- unsigned int channel;
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+ unsigned val = ucontrol->value.enumerated.item[0];
+ unsigned channel = kcontrol->private_value;
+ int change;
- val = ucontrol->value.enumerated.item[0];
- if (val >= 53 ||
- (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
- val >= 49))
+ if (val >= emu_ri->n_srcs)
return -EINVAL;
- channel = (kcontrol->private_value) & 0xff;
- /* Limit: emu1010_output_dst, emu->emu1010.output_source */
- if (channel >= 24 ||
- (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
- channel >= 18))
+ if (channel >= emu_ri->n_outs)
return -EINVAL;
- if (emu->emu1010.output_source[channel] == val)
- return 0;
- emu->emu1010.output_source[channel] = val;
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
- snd_emu1010_fpga_link_dst_src_write(emu,
- emu1616_output_dst[channel], emu1616_src_regs[val]);
- else
- snd_emu1010_fpga_link_dst_src_write(emu,
- emu1010_output_dst[channel], emu1010_src_regs[val]);
- return 1;
+ change = (emu->emu1010.output_source[channel] != val);
+ if (change) {
+ emu->emu1010.output_source[channel] = val;
+ guard(snd_emu1010_fpga_lock)(emu);
+ snd_emu1010_output_source_apply(emu, channel, val);
+ }
+ return change;
}
+static const struct snd_kcontrol_new emu1010_output_source_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_emu1010_input_output_source_info,
+ .get = snd_emu1010_output_source_get,
+ .put = snd_emu1010_output_source_put
+};
+
static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int channel;
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+ unsigned channel = kcontrol->private_value;
- channel = (kcontrol->private_value) & 0xff;
- /* Limit: emu1010_input_dst, emu->emu1010.input_source */
- if (channel >= 22)
+ if (channel >= emu_ri->n_ins)
return -EINVAL;
ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
return 0;
@@ -451,134 +694,70 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int val;
- unsigned int channel;
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+ unsigned val = ucontrol->value.enumerated.item[0];
+ unsigned channel = kcontrol->private_value;
+ int change;
- val = ucontrol->value.enumerated.item[0];
- if (val >= 53 ||
- (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
- val >= 49))
+ if (val >= emu_ri->n_srcs)
return -EINVAL;
- channel = (kcontrol->private_value) & 0xff;
- /* Limit: emu1010_input_dst, emu->emu1010.input_source */
- if (channel >= 22)
+ if (channel >= emu_ri->n_ins)
return -EINVAL;
- if (emu->emu1010.input_source[channel] == val)
- return 0;
- emu->emu1010.input_source[channel] = val;
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
- snd_emu1010_fpga_link_dst_src_write(emu,
- emu1010_input_dst[channel], emu1616_src_regs[val]);
- else
- snd_emu1010_fpga_link_dst_src_write(emu,
- emu1010_input_dst[channel], emu1010_src_regs[val]);
- return 1;
+ change = (emu->emu1010.input_source[channel] != val);
+ if (change) {
+ emu->emu1010.input_source[channel] = val;
+ guard(snd_emu1010_fpga_lock)(emu);
+ snd_emu1010_input_source_apply(emu, channel, val);
+ }
+ return change;
}
-#define EMU1010_SOURCE_OUTPUT(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = snd_emu1010_input_output_source_info, \
- .get = snd_emu1010_output_source_get, \
- .put = snd_emu1010_output_source_put, \
- .private_value = chid \
-}
-
-static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = {
- EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
- EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
- EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
- EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
- EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
- EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
- EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
- EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
- EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
- EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
- EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
- EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
- EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
- EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
- EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
- EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
- EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
+static const struct snd_kcontrol_new emu1010_input_source_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_emu1010_input_output_source_info,
+ .get = snd_emu1010_input_source_get,
+ .put = snd_emu1010_input_source_put
};
+static int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
+{
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu1010_idx(emu)];
+ int err;
-/* 1616(m) cardbus */
-static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = {
- EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
- EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
- EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
- EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
- EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
- EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
- EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
- EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
- EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
- EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
- EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
-};
+ err = add_ctls(emu, &emu1010_output_source_ctl,
+ emu_ri->out_texts, emu_ri->n_outs);
+ if (err < 0)
+ return err;
+ err = add_ctls(emu, &emu1010_input_source_ctl,
+ emu1010_input_texts, emu_ri->n_ins);
+ return err;
+}
-#define EMU1010_SOURCE_INPUT(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = snd_emu1010_input_output_source_info, \
- .get = snd_emu1010_input_source_get, \
- .put = snd_emu1010_input_source_put, \
- .private_value = chid \
-}
-
-static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = {
- EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
- EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
- EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
- EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
- EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
- EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
- EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
- EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
- EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
- EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
- EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
- EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
- EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
- EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
- EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
- EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
- EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
- EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
- EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
- EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
- EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
- EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
+static const char * const snd_emu1010_adc_pads[] = {
+ "ADC1 14dB PAD 0202 Capture Switch",
+ "ADC1 14dB PAD Audio Dock Capture Switch",
+ "ADC2 14dB PAD Audio Dock Capture Switch",
+ "ADC3 14dB PAD Audio Dock Capture Switch",
};
-
+static const unsigned short snd_emu1010_adc_pad_regs[] = {
+ EMU_HANA_0202_ADC_PAD1,
+ EMU_HANA_DOCK_ADC_PAD1,
+ EMU_HANA_DOCK_ADC_PAD2,
+ EMU_HANA_DOCK_ADC_PAD3,
+};
#define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info
static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
+
ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
return 0;
}
@@ -586,39 +765,48 @@ static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
unsigned int val, cache;
+ int change;
+
val = ucontrol->value.integer.value[0];
cache = emu->emu1010.adc_pads;
if (val == 1)
cache = cache | mask;
else
cache = cache & ~mask;
- if (cache != emu->emu1010.adc_pads) {
- snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
+ change = (cache != emu->emu1010.adc_pads);
+ if (change) {
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache );
emu->emu1010.adc_pads = cache;
}
- return 0;
+ return change;
}
+static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_emu1010_adc_pads_info,
+ .get = snd_emu1010_adc_pads_get,
+ .put = snd_emu1010_adc_pads_put
+};
-#define EMU1010_ADC_PADS(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = snd_emu1010_adc_pads_info, \
- .get = snd_emu1010_adc_pads_get, \
- .put = snd_emu1010_adc_pads_put, \
- .private_value = chid \
-}
+static const char * const snd_emu1010_dac_pads[] = {
+ "DAC1 0202 14dB PAD Playback Switch",
+ "DAC1 Audio Dock 14dB PAD Playback Switch",
+ "DAC2 Audio Dock 14dB PAD Playback Switch",
+ "DAC3 Audio Dock 14dB PAD Playback Switch",
+ "DAC4 Audio Dock 14dB PAD Playback Switch",
+};
-static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
- EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
- EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
- EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
- EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
+static const unsigned short snd_emu1010_dac_regs[] = {
+ EMU_HANA_0202_DAC_PAD1,
+ EMU_HANA_DOCK_DAC_PAD1,
+ EMU_HANA_DOCK_DAC_PAD2,
+ EMU_HANA_DOCK_DAC_PAD3,
+ EMU_HANA_DOCK_DAC_PAD4,
};
#define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info
@@ -626,7 +814,8 @@ static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
+
ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
return 0;
}
@@ -634,163 +823,238 @@ static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- unsigned int mask = kcontrol->private_value & 0xff;
+ unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
unsigned int val, cache;
+ int change;
+
val = ucontrol->value.integer.value[0];
cache = emu->emu1010.dac_pads;
if (val == 1)
cache = cache | mask;
else
cache = cache & ~mask;
- if (cache != emu->emu1010.dac_pads) {
- snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
+ change = (cache != emu->emu1010.dac_pads);
+ if (change) {
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache );
emu->emu1010.dac_pads = cache;
}
- return 0;
+ return change;
}
+static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_emu1010_dac_pads_info,
+ .get = snd_emu1010_dac_pads_get,
+ .put = snd_emu1010_dac_pads_put
+};
-#define EMU1010_DAC_PADS(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .info = snd_emu1010_dac_pads_info, \
- .get = snd_emu1010_dac_pads_get, \
- .put = snd_emu1010_dac_pads_put, \
- .private_value = chid \
-}
+struct snd_emu1010_pads_info {
+ const char * const *adc_ctls, * const *dac_ctls;
+ unsigned n_adc_ctls, n_dac_ctls;
+};
+
+static const struct snd_emu1010_pads_info emu1010_pads_info[] = {
+ {
+ /* rev1 1010 */
+ .adc_ctls = snd_emu1010_adc_pads,
+ .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
+ .dac_ctls = snd_emu1010_dac_pads,
+ .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
+ },
+ {
+ /* rev2 1010 */
+ .adc_ctls = snd_emu1010_adc_pads,
+ .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1,
+ .dac_ctls = snd_emu1010_dac_pads,
+ .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1,
+ },
+ {
+ /* 1616(m) cardbus */
+ .adc_ctls = snd_emu1010_adc_pads + 1,
+ .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
+ .dac_ctls = snd_emu1010_dac_pads + 1,
+ .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
+ },
+ {
+ /* 0404 */
+ .adc_ctls = NULL,
+ .n_adc_ctls = 0,
+ .dac_ctls = NULL,
+ .n_dac_ctls = 0,
+ },
+};
+
+static const char * const emu1010_clock_texts[] = {
+ "44100", "48000", "SPDIF", "ADAT", "Dock", "BNC"
+};
+
+static const u8 emu1010_clock_vals[] = {
+ EMU_HANA_WCLOCK_INT_44_1K,
+ EMU_HANA_WCLOCK_INT_48K,
+ EMU_HANA_WCLOCK_HANA_SPDIF_IN,
+ EMU_HANA_WCLOCK_HANA_ADAT_IN,
+ EMU_HANA_WCLOCK_2ND_HANA,
+ EMU_HANA_WCLOCK_SYNC_BNC,
+};
+
+static const char * const emu0404_clock_texts[] = {
+ "44100", "48000", "SPDIF", "BNC"
+};
-static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
- EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
- EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
- EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
- EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
- EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
+static const u8 emu0404_clock_vals[] = {
+ EMU_HANA_WCLOCK_INT_44_1K,
+ EMU_HANA_WCLOCK_INT_48K,
+ EMU_HANA_WCLOCK_HANA_SPDIF_IN,
+ EMU_HANA_WCLOCK_SYNC_BNC,
};
+struct snd_emu1010_clock_info {
+ const char * const *texts;
+ const u8 *vals;
+ unsigned num;
+};
-static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
+static const struct snd_emu1010_clock_info emu1010_clock_info[] = {
+ {
+ // rev1 1010
+ .texts = emu1010_clock_texts,
+ .vals = emu1010_clock_vals,
+ .num = ARRAY_SIZE(emu1010_clock_vals),
+ },
+ {
+ // rev2 1010
+ .texts = emu1010_clock_texts,
+ .vals = emu1010_clock_vals,
+ .num = ARRAY_SIZE(emu1010_clock_vals) - 1,
+ },
+ {
+ // 1616(m) CardBus
+ .texts = emu1010_clock_texts,
+ // TODO: determine what is actually available.
+ // Pedantically, *every* source comes from the 2nd FPGA, as the
+ // card itself has no own (digital) audio ports. The user manual
+ // claims that ADAT and S/PDIF clock sources are separate, which
+ // can mean two things: either E-MU mapped the dock's sources to
+ // the primary ones, or they determine the meaning of the "Dock"
+ // source depending on how the ports are actually configured
+ // (which the 2nd FPGA must be doing anyway).
+ .vals = emu1010_clock_vals,
+ .num = ARRAY_SIZE(emu1010_clock_vals),
+ },
+ {
+ // 0404
+ .texts = emu0404_clock_texts,
+ .vals = emu0404_clock_vals,
+ .num = ARRAY_SIZE(emu0404_clock_vals),
+ },
+};
+
+static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char * const texts[4] = {
- "44100", "48000", "SPDIF", "ADAT"
- };
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ const struct snd_emu1010_clock_info *emu_ci =
+ &emu1010_clock_info[emu1010_idx(emu)];
- return snd_ctl_enum_info(uinfo, 1, 4, texts);
+ return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts);
}
-static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
+static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
+ ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source;
return 0;
}
-static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
+static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ const struct snd_emu1010_clock_info *emu_ci =
+ &emu1010_clock_info[emu1010_idx(emu)];
unsigned int val;
- int change = 0;
val = ucontrol->value.enumerated.item[0] ;
- /* Limit: uinfo->value.enumerated.items = 4; */
- if (val >= 4)
+ if (val >= emu_ci->num)
return -EINVAL;
- change = (emu->emu1010.internal_clock != val);
+ guard(snd_emu1010_fpga_lock)(emu);
+ scoped_guard(spinlock_irq, &emu->reg_lock) {
+ if (emu->emu1010.clock_source == val)
+ return 0;
+ emu->emu1010.clock_source = val;
+ emu->emu1010.wclock = emu_ci->vals[val];
+ snd_emu1010_update_clock(emu);
+
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE);
+ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock);
+ }
+
+ msleep(10); // Allow DLL to settle
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
+ return 1;
+}
+
+static const struct snd_kcontrol_new snd_emu1010_clock_source =
+{
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Source",
+ .count = 1,
+ .info = snd_emu1010_clock_source_info,
+ .get = snd_emu1010_clock_source_get,
+ .put = snd_emu1010_clock_source_put
+};
+
+static int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char * const texts[2] = {
+ "44100", "48000"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
+}
+
+static int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback;
+ return 0;
+}
+
+static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+ unsigned int val = ucontrol->value.enumerated.item[0];
+ int change;
+
+ if (val >= 2)
+ return -EINVAL;
+ change = (emu->emu1010.clock_fallback != val);
if (change) {
- emu->emu1010.internal_clock = val;
- switch (val) {
- case 0:
- /* 44100 */
- /* Mute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
- /* Default fallback clock 44.1kHz */
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
- /* Word Clock source, Internal 44.1kHz x1 */
- snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
- EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
- /* Set LEDs on Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
- EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
- /* Allow DLL to settle */
- msleep(10);
- /* Unmute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
- break;
- case 1:
- /* 48000 */
- /* Mute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
- /* Default fallback clock 48kHz */
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
- /* Word Clock source, Internal 48kHz x1 */
- snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
- EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
- /* Set LEDs on Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
- EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
- /* Allow DLL to settle */
- msleep(10);
- /* Unmute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
- break;
-
- case 2: /* Take clock from S/PDIF IN */
- /* Mute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
- /* Default fallback clock 48kHz */
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
- /* Word Clock source, sync to S/PDIF input */
- snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
- EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
- /* Set LEDs on Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
- EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
- /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
- /* Allow DLL to settle */
- msleep(10);
- /* Unmute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
- break;
-
- case 3:
- /* Take clock from ADAT IN */
- /* Mute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
- /* Default fallback clock 48kHz */
- snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
- /* Word Clock source, sync to ADAT input */
- snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
- EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
- /* Set LEDs on Audio Dock */
- snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
- /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
- /* Allow DLL to settle */
- msleep(10);
- /* Unmute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
-
-
- break;
- }
+ emu->emu1010.clock_fallback = val;
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val);
}
- return change;
+ return change;
}
-static const struct snd_kcontrol_new snd_emu1010_internal_clock =
+static const struct snd_kcontrol_new snd_emu1010_clock_fallback =
{
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Clock Internal Rate",
- .count = 1,
- .info = snd_emu1010_internal_clock_info,
- .get = snd_emu1010_internal_clock_get,
- .put = snd_emu1010_internal_clock_put
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Fallback",
+ .count = 1,
+ .info = snd_emu1010_clock_fallback_info,
+ .get = snd_emu1010_clock_fallback_get,
+ .put = snd_emu1010_clock_fallback_put
};
static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
@@ -829,7 +1093,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
emu->emu1010.optical_out = val;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
}
return change;
}
@@ -880,7 +1144,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
emu->emu1010.optical_in = val;
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
- snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
+ snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
}
return change;
}
@@ -927,7 +1191,6 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
unsigned int ngain, ogain;
u16 gpio;
int change = 0;
- unsigned long flags;
u32 source;
/* If the capture source has changed,
* update the capture volume from the cached value
@@ -941,13 +1204,13 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
change = (emu->i2c_capture_source != source_id);
if (change) {
snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
- spin_lock_irqsave(&emu->emu_lock, flags);
- gpio = inw(emu->port + A_IOCFG);
- if (source_id==0)
- outw(gpio | 0x4, emu->port + A_IOCFG);
- else
- outw(gpio & ~0x4, emu->port + A_IOCFG);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ scoped_guard(spinlock_irq, &emu->emu_lock) {
+ gpio = inw(emu->port + A_IOCFG);
+ if (source_id == 0)
+ outw(gpio | 0x4, emu->port + A_IOCFG);
+ else
+ outw(gpio & ~0x4, emu->port + A_IOCFG);
+ }
ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
@@ -1039,22 +1302,19 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
-#define I2C_VOLUME(xname,chid) \
-{ \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
- SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
- .info = snd_audigy_i2c_volume_info, \
- .get = snd_audigy_i2c_volume_get, \
- .put = snd_audigy_i2c_volume_put, \
- .tlv = { .p = snd_audigy_db_scale2 }, \
- .private_value = chid \
-}
-
+static const struct snd_kcontrol_new i2c_volume_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = snd_audigy_i2c_volume_info,
+ .get = snd_audigy_i2c_volume_get,
+ .put = snd_audigy_i2c_volume_put,
+ .tlv = { .p = snd_audigy_db_scale2 }
+};
-static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
- I2C_VOLUME("Mic Capture Volume", 0),
- I2C_VOLUME("Line Capture Volume", 0)
+static const char * const snd_audigy_i2c_volume_ctls[] = {
+ "Mic Capture Volume",
+ "Line Capture Volume",
};
#if 0
@@ -1070,10 +1330,7 @@ static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
unsigned int tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&emu->reg_lock, flags);
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
switch (tmp & A_SPDIF_RATE_MASK) {
case A_SPDIF_44100:
@@ -1088,7 +1345,6 @@ static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
default:
ucontrol->value.enumerated.item[0] = 1;
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
@@ -1098,7 +1354,6 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
int change;
unsigned int reg, val, tmp;
- unsigned long flags;
switch(ucontrol->value.enumerated.item[0]) {
case 0:
@@ -1116,14 +1371,13 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
}
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->reg_lock);
reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp = reg & ~A_SPDIF_RATE_MASK;
tmp |= val;
change = (tmp != reg);
if (change)
snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1146,7 +1400,6 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
int change;
unsigned int val;
- unsigned long flags;
/* Limit: emu->spdif_bits */
if (idx >= 3)
@@ -1155,13 +1408,11 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
(ucontrol->value.iec958.status[1] << 8) |
(ucontrol->value.iec958.status[2] << 16) |
(ucontrol->value.iec958.status[3] << 24);
- spin_lock_irqsave(&emu->reg_lock, flags);
change = val != emu->spdif_bits[idx];
if (change) {
snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
emu->spdif_bits[idx] = val;
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1189,10 +1440,10 @@ static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
{
if (emu->audigy) {
- snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
- snd_emu10k1_compose_audigy_fxrt1(route));
- snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
- snd_emu10k1_compose_audigy_fxrt2(route));
+ snd_emu10k1_ptr_write_multiple(emu, voice,
+ A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(route),
+ A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(route),
+ REGLIST_END);
} else {
snd_emu10k1_ptr_write(emu, FXRT, voice,
snd_emu10k1_compose_send_routing(route));
@@ -1206,11 +1457,8 @@ static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsig
snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
if (emu->audigy) {
- unsigned int val = ((unsigned int)volume[4] << 24) |
- ((unsigned int)volume[5] << 16) |
- ((unsigned int)volume[6] << 8) |
- (unsigned int)volume[7];
- snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
+ snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
+ snd_emu10k1_compose_audigy_sendamounts(volume));
}
}
@@ -1229,7 +1477,6 @@ static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct s
static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
@@ -1237,19 +1484,16 @@ static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
int num_efx = emu->audigy ? 8 : 4;
int mask = emu->audigy ? 0x3f : 0x0f;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (voice = 0; voice < 3; voice++)
for (idx = 0; idx < num_efx; idx++)
ucontrol->value.integer.value[(voice * num_efx) + idx] =
mix->send_routing[voice][idx] & mask;
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
@@ -1257,7 +1501,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
int num_efx = emu->audigy ? 8 : 4;
int mask = emu->audigy ? 0x3f : 0x0f;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->reg_lock);
for (voice = 0; voice < 3; voice++)
for (idx = 0; idx < num_efx; idx++) {
val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
@@ -1266,18 +1510,17 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
change = 1;
}
}
- if (change && mix->epcm) {
- if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
+ if (change && mix->epcm && mix->epcm->voices[0]) {
+ if (!mix->epcm->voices[0]->last) {
update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
&mix->send_routing[1][0]);
- update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
+ update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number + 1,
&mix->send_routing[2][0]);
- } else if (mix->epcm->voices[0]) {
+ } else {
update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
&mix->send_routing[0][0]);
}
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1305,31 +1548,27 @@ static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct sn
static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
int idx;
int num_efx = emu->audigy ? 8 : 4;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (idx = 0; idx < 3*num_efx; idx++)
ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
int change = 0, idx, val;
int num_efx = emu->audigy ? 8 : 4;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->reg_lock);
for (idx = 0; idx < 3*num_efx; idx++) {
val = ucontrol->value.integer.value[idx] & 255;
if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
@@ -1337,18 +1576,17 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
change = 1;
}
}
- if (change && mix->epcm) {
- if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
+ if (change && mix->epcm && mix->epcm->voices[0]) {
+ if (!mix->epcm->voices[0]->last) {
update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
&mix->send_volume[1][0]);
- update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
+ update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number + 1,
&mix->send_volume[2][0]);
- } else if (mix->epcm->voices[0]) {
+ } else {
update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
&mix->send_volume[0][0]);
}
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1368,7 +1606,7 @@ static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 3;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 0xffff;
+ uinfo->value.integer.max = 0x1fffd;
return 0;
}
@@ -1378,42 +1616,38 @@ static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
- unsigned long flags;
int idx;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (idx = 0; idx < 3; idx++)
- ucontrol->value.integer.value[idx] = mix->attn[idx];
- spin_unlock_irqrestore(&emu->reg_lock, flags);
+ ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
return 0;
}
static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
int change = 0, idx, val;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->reg_lock);
for (idx = 0; idx < 3; idx++) {
- val = ucontrol->value.integer.value[idx] & 0xffff;
+ unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
+ val = uval * 0x8000U / 0xffffU;
if (mix->attn[idx] != val) {
mix->attn[idx] = val;
change = 1;
}
}
- if (change && mix->epcm) {
- if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
+ if (change && mix->epcm && mix->epcm->voices[0]) {
+ if (!mix->epcm->voices[0]->last) {
snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
- snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
- } else if (mix->epcm->voices[0]) {
+ snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number + 1, mix->attn[2]);
+ } else {
snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
}
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1443,7 +1677,6 @@ static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, stru
static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
@@ -1451,18 +1684,15 @@ static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
int num_efx = emu->audigy ? 8 : 4;
int mask = emu->audigy ? 0x3f : 0x0f;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (idx = 0; idx < num_efx; idx++)
ucontrol->value.integer.value[idx] =
mix->send_routing[0][idx] & mask;
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
@@ -1470,7 +1700,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
int num_efx = emu->audigy ? 8 : 4;
int mask = emu->audigy ? 0x3f : 0x0f;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->reg_lock);
for (idx = 0; idx < num_efx; idx++) {
val = ucontrol->value.integer.value[idx] & mask;
if (mix->send_routing[0][idx] != val) {
@@ -1485,7 +1715,6 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
&mix->send_routing[0][0]);
}
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1513,31 +1742,27 @@ static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struc
static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
int idx;
int num_efx = emu->audigy ? 8 : 4;
- spin_lock_irqsave(&emu->reg_lock, flags);
for (idx = 0; idx < num_efx; idx++)
ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
int change = 0, idx, val;
int num_efx = emu->audigy ? 8 : 4;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->reg_lock);
for (idx = 0; idx < num_efx; idx++) {
val = ucontrol->value.integer.value[idx] & 255;
if (mix->send_volume[0][idx] != val) {
@@ -1551,7 +1776,6 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
&mix->send_volume[0][0]);
}
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1572,7 +1796,7 @@ static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_c
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 0xffff;
+ uinfo->value.integer.max = 0x1fffd;
return 0;
}
@@ -1582,25 +1806,23 @@ static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
struct snd_emu10k1_pcm_mixer *mix =
&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
- unsigned long flags;
- spin_lock_irqsave(&emu->reg_lock, flags);
- ucontrol->value.integer.value[0] = mix->attn[0];
- spin_unlock_irqrestore(&emu->reg_lock, flags);
+ ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
return 0;
}
static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
int change = 0, val;
+ unsigned uval;
- spin_lock_irqsave(&emu->reg_lock, flags);
- val = ucontrol->value.integer.value[0] & 0xffff;
+ guard(spinlock_irq)(&emu->reg_lock);
+ uval = ucontrol->value.integer.value[0] & 0x1ffff;
+ val = uval * 0x8000U / 0xffffU;
if (mix->attn[0] != val) {
mix->attn[0] = val;
change = 1;
@@ -1610,7 +1832,6 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
}
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1646,7 +1867,6 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- unsigned long flags;
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
unsigned int reg, val, sw;
int change = 0;
@@ -1654,7 +1874,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
sw = ucontrol->value.integer.value[0];
if (emu->card_capabilities->invert_shared_spdif)
sw = !sw;
- spin_lock_irqsave(&emu->reg_lock, flags);
+ guard(spinlock_irq)(&emu->emu_lock);
if ( emu->card_capabilities->i2c_adc) {
/* Do nothing for Audigy 2 ZS Notebook */
} else if (emu->audigy) {
@@ -1675,7 +1895,6 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
reg |= val;
outl(reg | val, emu->port + HCFG);
}
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return change;
}
@@ -1750,23 +1969,14 @@ static int remove_ctl(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id;
memset(&id, 0, sizeof(id));
- strcpy(id.name, name);
+ strscpy(id.name, name);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(card, &id);
}
-static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
-{
- struct snd_ctl_elem_id sid;
- memset(&sid, 0, sizeof(sid));
- strcpy(sid.name, name);
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- return snd_ctl_find_id(card, &sid);
-}
-
static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
{
- struct snd_kcontrol *kctl = ctl_find(card, src);
+ struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src);
if (kctl) {
snd_ctl_rename(card, kctl, dst);
return 0;
@@ -1777,7 +1987,7 @@ static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
int pcm_device, int multi_device)
{
- int err, pcm;
+ int err;
struct snd_kcontrol *kctl;
struct snd_card *card = emu->card;
const char * const *c;
@@ -1964,11 +2174,11 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
} else {
no_ac97:
if (emu->card_capabilities->ecard)
- strcpy(emu->card->mixername, "EMU APS");
+ strscpy(emu->card->mixername, "EMU APS");
else if (emu->audigy)
- strcpy(emu->card->mixername, "SB Audigy");
+ strscpy(emu->card->mixername, "SB Audigy");
else
- strcpy(emu->card->mixername, "Emu10k1");
+ strscpy(emu->card->mixername, "Emu10k1");
}
if (emu->audigy)
@@ -2041,49 +2251,7 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if (err)
return err;
- /* initialize the routing and volume table for each pcm playback stream */
- for (pcm = 0; pcm < 32; pcm++) {
- struct snd_emu10k1_pcm_mixer *mix;
- int v;
-
- mix = &emu->pcm_mixer[pcm];
- mix->epcm = NULL;
-
- for (v = 0; v < 4; v++)
- mix->send_routing[0][v] =
- mix->send_routing[1][v] =
- mix->send_routing[2][v] = v;
-
- memset(&mix->send_volume, 0, sizeof(mix->send_volume));
- mix->send_volume[0][0] = mix->send_volume[0][1] =
- mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
-
- mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
- }
-
- /* initialize the routing and volume table for the multichannel playback stream */
- for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
- struct snd_emu10k1_pcm_mixer *mix;
- int v;
-
- mix = &emu->efx_pcm_mixer[pcm];
- mix->epcm = NULL;
-
- mix->send_routing[0][0] = pcm;
- mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
- for (v = 0; v < 2; v++)
- mix->send_routing[0][2+v] = 13+v;
- if (emu->audigy)
- for (v = 0; v < 4; v++)
- mix->send_routing[0][4+v] = 60+v;
-
- memset(&mix->send_volume, 0, sizeof(mix->send_volume));
- mix->send_volume[0][0] = 255;
-
- mix->attn[0] = 0xffff;
- }
-
- if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
+ if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
/* sb live! and audigy */
kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
if (!kctl)
@@ -2135,105 +2303,66 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
return err;
}
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
- /* 1616(m) cardbus */
- int i;
-
- for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
- emu));
- if (err < 0)
- return err;
- }
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
- emu));
- if (err < 0)
- return err;
- }
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
- if (err < 0)
- return err;
- }
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
- if (err < 0)
- return err;
+ if (emu->card_capabilities->emu_model) {
+ unsigned i, emu_idx = emu1010_idx(emu);
+ const struct snd_emu1010_routing_info *emu_ri =
+ &emu1010_routing_info[emu_idx];
+ const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
+
+ for (i = 0; i < emu_ri->n_ins; i++)
+ emu->emu1010.input_source[i] =
+ emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
+ for (i = 0; i < emu_ri->n_outs; i++)
+ emu->emu1010.output_source[i] =
+ emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
+ scoped_guard(snd_emu1010_fpga_lock, emu) {
+ snd_emu1010_apply_sources(emu);
}
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+
+ kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
+ err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_optical_out, emu));
+ snd_ctl_new1(&snd_emu1010_clock_fallback, emu));
if (err < 0)
return err;
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_optical_in, emu));
+
+ err = add_ctls(emu, &emu1010_adc_pads_ctl,
+ emu_pi->adc_ctls, emu_pi->n_adc_ctls);
+ if (err < 0)
+ return err;
+ err = add_ctls(emu, &emu1010_dac_pads_ctl,
+ emu_pi->dac_ctls, emu_pi->n_dac_ctls);
if (err < 0)
return err;
- } else if (emu->card_capabilities->emu_model) {
- /* all other e-mu cards for now */
- int i;
-
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
- emu));
- if (err < 0)
- return err;
- }
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
- emu));
- if (err < 0)
- return err;
- }
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
+ if (!emu->card_capabilities->no_adat) {
err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+ snd_ctl_new1(&snd_emu1010_optical_out, emu));
if (err < 0)
return err;
- }
- for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+ snd_ctl_new1(&snd_emu1010_optical_in, emu));
if (err < 0)
return err;
}
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_internal_clock, emu));
- if (err < 0)
- return err;
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_optical_out, emu));
- if (err < 0)
- return err;
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_emu1010_optical_in, emu));
+
+ err = add_emu1010_source_mixers(emu);
if (err < 0)
return err;
}
if ( emu->card_capabilities->i2c_adc) {
- int i;
-
err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
if (err < 0)
return err;
- for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
- err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
- if (err < 0)
- return err;
- }
+ err = add_ctls(emu, &i2c_volume_ctl,
+ snd_audigy_i2c_volume_ctls,
+ ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
+ if (err < 0)
+ return err;
}
if (emu->card_capabilities->ac97_chip && emu->audigy) {
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index 3ce9b2129ce6..c102a3599225 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -68,28 +68,28 @@ static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k
return;
}
- spin_lock(&midi->input_lock);
- if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
- if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
- mpu401_clear_rx(emu, midi);
- } else {
- byte = mpu401_read_data(emu, midi);
- if (midi->substream_input)
- snd_rawmidi_receive(midi->substream_input, &byte, 1);
+ scoped_guard(spinlock, &midi->input_lock) {
+ if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
+ if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
+ mpu401_clear_rx(emu, midi);
+ } else {
+ byte = mpu401_read_data(emu, midi);
+ if (midi->substream_input)
+ snd_rawmidi_receive(midi->substream_input, &byte, 1);
+ }
}
}
- spin_unlock(&midi->input_lock);
- spin_lock(&midi->output_lock);
- if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
- if (midi->substream_output &&
- snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
- mpu401_write_data(emu, midi, byte);
- } else {
- snd_emu10k1_intr_disable(emu, midi->tx_enable);
+ scoped_guard(spinlock, &midi->output_lock) {
+ if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
+ if (midi->substream_output &&
+ snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
+ mpu401_write_data(emu, midi, byte);
+ } else {
+ snd_emu10k1_intr_disable(emu, midi->tx_enable);
+ }
}
}
- spin_unlock(&midi->output_lock);
}
static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
@@ -104,29 +104,28 @@ static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int st
static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack)
{
- unsigned long flags;
int timeout, ok;
- spin_lock_irqsave(&midi->input_lock, flags);
- mpu401_write_data(emu, midi, 0x00);
- /* mpu401_clear_rx(emu, midi); */
-
- mpu401_write_cmd(emu, midi, cmd);
- if (ack) {
- ok = 0;
- timeout = 10000;
- while (!ok && timeout-- > 0) {
- if (mpu401_input_avail(emu, midi)) {
- if (mpu401_read_data(emu, midi) == MPU401_ACK)
- ok = 1;
+ scoped_guard(spinlock_irq, &midi->input_lock) {
+ mpu401_write_data(emu, midi, 0x00);
+ /* mpu401_clear_rx(emu, midi); */
+
+ mpu401_write_cmd(emu, midi, cmd);
+ if (ack) {
+ ok = 0;
+ timeout = 10000;
+ while (!ok && timeout-- > 0) {
+ if (mpu401_input_avail(emu, midi)) {
+ if (mpu401_read_data(emu, midi) == MPU401_ACK)
+ ok = 1;
+ }
}
- }
- if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
+ if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
+ ok = 1;
+ } else {
ok = 1;
- } else {
- ok = 1;
+ }
}
- spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok) {
dev_err(emu->card->dev,
"midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
@@ -142,100 +141,78 @@ static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
{
struct snd_emu10k1 *emu;
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
- unsigned long flags;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
- midi->substream_input = substream;
- if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
- goto error_out;
- if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
- goto error_out;
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irq, &midi->open_lock) {
+ midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
+ midi->substream_input = substream;
+ if (midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)
+ return 0;
}
+ if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
+ return -EIO;
+ if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
+ return -EIO;
return 0;
-
-error_out:
- return -EIO;
}
static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
{
struct snd_emu10k1 *emu;
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
- unsigned long flags;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
- midi->substream_output = substream;
- if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
- goto error_out;
- if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
- goto error_out;
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irq, &midi->open_lock) {
+ midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
+ midi->substream_output = substream;
+ if (midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)
+ return 0;
}
+ if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
+ return -EIO;
+ if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
+ return -EIO;
return 0;
-
-error_out:
- return -EIO;
}
static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
{
struct snd_emu10k1 *emu;
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
- unsigned long flags;
- int err = 0;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- snd_emu10k1_intr_disable(emu, midi->rx_enable);
- midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
- midi->substream_input = NULL;
- if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irq, &midi->open_lock) {
+ snd_emu10k1_intr_disable(emu, midi->rx_enable);
+ midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
+ midi->substream_input = NULL;
+ if (midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)
+ return 0;
}
- return err;
+ return snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
}
static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream)
{
struct snd_emu10k1 *emu;
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
- unsigned long flags;
- int err = 0;
emu = midi->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
- spin_lock_irqsave(&midi->open_lock, flags);
- snd_emu10k1_intr_disable(emu, midi->tx_enable);
- midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
- midi->substream_output = NULL;
- if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
- spin_unlock_irqrestore(&midi->open_lock, flags);
- err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
- } else {
- spin_unlock_irqrestore(&midi->open_lock, flags);
+ scoped_guard(spinlock_irq, &midi->open_lock) {
+ snd_emu10k1_intr_disable(emu, midi->tx_enable);
+ midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
+ midi->substream_output = NULL;
+ if (midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)
+ return 0;
}
- return err;
+ return snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
}
static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -256,7 +233,6 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr
{
struct snd_emu10k1 *emu;
struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
- unsigned long flags;
emu = midi->emu;
if (snd_BUG_ON(!emu))
@@ -267,22 +243,21 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr
unsigned char byte;
/* try to send some amount of bytes here before interrupts */
- spin_lock_irqsave(&midi->output_lock, flags);
- while (max > 0) {
- if (mpu401_output_ready(emu, midi)) {
- if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) ||
- snd_rawmidi_transmit(substream, &byte, 1) != 1) {
- /* no more data */
- spin_unlock_irqrestore(&midi->output_lock, flags);
- return;
+ scoped_guard(spinlock_irq, &midi->output_lock) {
+ while (max > 0) {
+ if (mpu401_output_ready(emu, midi)) {
+ if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) ||
+ snd_rawmidi_transmit(substream, &byte, 1) != 1) {
+ /* no more data */
+ return;
+ }
+ mpu401_write_data(emu, midi, byte);
+ max--;
+ } else {
+ break;
}
- mpu401_write_data(emu, midi, byte);
- max--;
- } else {
- break;
}
}
- spin_unlock_irqrestore(&midi->output_lock, flags);
snd_emu10k1_intr_enable(emu, midi->tx_enable);
} else {
snd_emu10k1_intr_disable(emu, midi->tx_enable);
@@ -326,7 +301,7 @@ static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *m
spin_lock_init(&midi->open_lock);
spin_lock_init(&midi->input_lock);
spin_lock_init(&midi->output_lock);
- strcpy(rmidi->name, name);
+ strscpy(rmidi->name, name);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index e8d2f0f6fbb3..071c75ba81fd 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1,15 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Lee Revell <rlrevell@joe-job.com>
+ * James Courtier-Dutton <James@superbug.co.uk>
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
* Creative Labs, Inc.
- * Routines for control of EMU10K1 chips / PCM routines
- * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
- *
- * BUGS:
- * --
*
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips / PCM routines
*/
#include <linux/pci.h>
@@ -76,65 +73,64 @@ static void snd_emu10k1_pcm_efx_interrupt(struct snd_emu10k1 *emu,
snd_pcm_period_elapsed(emu->pcm_capture_efx_substream);
}
-static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voices)
+static void snd_emu10k1_pcm_free_voices(struct snd_emu10k1_pcm *epcm)
{
- int err, i;
-
- if (epcm->voices[1] != NULL && voices < 2) {
- snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]);
- epcm->voices[1] = NULL;
- }
- for (i = 0; i < voices; i++) {
- if (epcm->voices[i] == NULL)
- break;
- }
- if (i == voices)
- return 0; /* already allocated */
-
- for (i = 0; i < ARRAY_SIZE(epcm->voices); i++) {
+ for (unsigned i = 0; i < ARRAY_SIZE(epcm->voices); i++) {
if (epcm->voices[i]) {
snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
epcm->voices[i] = NULL;
}
}
+}
+
+static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm *epcm,
+ int type, int count, int channels)
+{
+ int err;
+
+ snd_emu10k1_pcm_free_voices(epcm);
+
err = snd_emu10k1_voice_alloc(epcm->emu,
- epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX,
- voices,
- &epcm->voices[0]);
-
+ type, count, channels,
+ epcm, &epcm->voices[0]);
if (err < 0)
return err;
- epcm->voices[0]->epcm = epcm;
- if (voices > 1) {
- for (i = 1; i < voices; i++) {
- epcm->voices[i] = &epcm->emu->voices[(epcm->voices[0]->number + i) % NUM_G];
- epcm->voices[i]->epcm = epcm;
- }
- }
+
if (epcm->extra == NULL) {
+ // The hardware supports only (half-)loop interrupts, so to support an
+ // arbitrary number of periods per buffer, we use an extra voice with a
+ // period-sized loop as the interrupt source. Additionally, the interrupt
+ // timing of the hardware is "suboptimal" and needs some compensation.
err = snd_emu10k1_voice_alloc(epcm->emu,
- epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX,
- 1,
- &epcm->extra);
+ type + 1, 1, 1,
+ epcm, &epcm->extra);
if (err < 0) {
/*
dev_dbg(emu->card->dev, "pcm_channel_alloc: "
"failed extra: voices=%d, frame=%d\n",
voices, frame);
*/
- for (i = 0; i < voices; i++) {
- snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
- epcm->voices[i] = NULL;
- }
+ snd_emu10k1_pcm_free_voices(epcm);
return err;
}
- epcm->extra->epcm = epcm;
epcm->extra->interrupt = snd_emu10k1_pcm_interrupt;
}
+
return 0;
}
-static const unsigned int capture_period_sizes[31] = {
+// Primes 2-7 and 2^n multiples thereof, up to 16.
+static const unsigned int efx_capture_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_efx_capture_channels = {
+ .count = ARRAY_SIZE(efx_capture_channels),
+ .list = efx_capture_channels,
+ .mask = 0
+};
+
+static const unsigned int capture_buffer_sizes[31] = {
384, 448, 512, 640,
384*2, 448*2, 512*2, 640*2,
384*4, 448*4, 512*4, 640*4,
@@ -145,19 +141,9 @@ static const unsigned int capture_period_sizes[31] = {
384*128,448*128,512*128
};
-static const struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = {
+static const struct snd_pcm_hw_constraint_list hw_constraints_capture_buffer_sizes = {
.count = 31,
- .list = capture_period_sizes,
- .mask = 0
-};
-
-static const unsigned int capture_rates[8] = {
- 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = {
- .count = 8,
- .list = capture_rates,
+ .list = capture_buffer_sizes,
.mask = 0
};
@@ -183,7 +169,7 @@ static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate)
switch (rate) {
case 8000: return A_ADCCR_SAMPLERATE_8;
case 11025: return A_ADCCR_SAMPLERATE_11;
- case 12000: return A_ADCCR_SAMPLERATE_12; /* really supported? */
+ case 12000: return A_ADCCR_SAMPLERATE_12;
case 16000: return ADCCR_SAMPLERATE_16;
case 22050: return ADCCR_SAMPLERATE_22;
case 24000: return ADCCR_SAMPLERATE_24;
@@ -196,6 +182,33 @@ static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate)
}
}
+static void snd_emu10k1_constrain_capture_rates(struct snd_emu10k1 *emu,
+ struct snd_pcm_runtime *runtime)
+{
+ if (emu->card_capabilities->emu_model &&
+ emu->emu1010.word_clock == 44100) {
+ runtime->hw.rates = SNDRV_PCM_RATE_11025 | \
+ SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_44100;
+ runtime->hw.rate_min = 11025;
+ runtime->hw.rate_max = 44100;
+ } else if (emu->audigy) {
+ runtime->hw.rates = SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_12000 |
+ SNDRV_PCM_RATE_24000;
+ }
+}
+
+static void snd_emu1010_constrain_efx_rate(struct snd_emu10k1 *emu,
+ struct snd_pcm_runtime *runtime)
+{
+ int rate;
+
+ rate = emu->emu1010.word_clock;
+ runtime->hw.rate_min = runtime->hw.rate_max = rate;
+ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
+}
+
static unsigned int emu10k1_calc_pitch_target(unsigned int rate)
{
unsigned int pitch_target;
@@ -232,145 +245,104 @@ static unsigned int emu10k1_select_interprom(unsigned int pitch_target)
return CCCA_INTERPROM_2;
}
-/*
- * calculate cache invalidate size
- *
- * stereo: channel is stereo
- * w_16: using 16bit samples
- *
- * returns: cache invalidate size in samples
- */
-static inline int emu10k1_ccis(int stereo, int w_16)
+static u16 emu10k1_send_target_from_amount(u8 amount)
{
- if (w_16) {
- return stereo ? 24 : 26;
- } else {
- return stereo ? 24*2 : 26*2;
- }
+ static const u8 shifts[8] = { 4, 4, 5, 6, 7, 8, 9, 10 };
+ static const u16 offsets[8] = { 0, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 };
+ u8 exp;
+
+ if (amount == 0xff)
+ return 0xffff;
+ exp = amount >> 5;
+ return ((amount & 0x1f) << shifts[exp]) + offsets[exp];
}
static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
- int master, int extra,
struct snd_emu10k1_voice *evoice,
+ bool w_16, bool stereo,
unsigned int start_addr,
unsigned int end_addr,
- struct snd_emu10k1_pcm_mixer *mix)
+ const unsigned char *send_routing,
+ const unsigned char *send_amount)
{
- struct snd_pcm_substream *substream = evoice->epcm->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int silent_page, tmp;
- int voice, stereo, w_16;
- unsigned char send_amount[8];
- unsigned char send_routing[8];
- unsigned long flags;
- unsigned int pitch_target;
- unsigned int ccis;
+ unsigned int silent_page;
+ int voice;
voice = evoice->number;
- stereo = runtime->channels == 2;
- w_16 = snd_pcm_format_width(runtime->format) == 16;
- if (!extra && stereo) {
- start_addr >>= 1;
- end_addr >>= 1;
- }
- if (w_16) {
- start_addr >>= 1;
- end_addr >>= 1;
+ silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) |
+ (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
+ snd_emu10k1_ptr_write_multiple(emu, voice,
+ // Not really necessary for the slave, but it doesn't hurt
+ CPF, stereo ? CPF_STEREO_MASK : 0,
+ // Assumption that PT is already 0 so no harm overwriting
+ PTRX, (send_amount[0] << 8) | send_amount[1],
+ // Stereo slaves don't need to have the addresses set, but it doesn't hurt
+ DSL, end_addr | (send_amount[3] << 24),
+ PSST, start_addr | (send_amount[2] << 24),
+ CCCA, emu10k1_select_interprom(evoice->epcm->pitch_target) |
+ (w_16 ? 0 : CCCA_8BITSELECT),
+ // Clear filter delay memory
+ Z1, 0,
+ Z2, 0,
+ // Invalidate maps
+ MAPA, silent_page,
+ MAPB, silent_page,
+ // Disable filter (in conjunction with CCCA_RESONANCE == 0)
+ VTFT, VTFT_FILTERTARGET_MASK,
+ CVCF, CVCF_CURRENTFILTER_MASK,
+ REGLIST_END);
+ // Setup routing
+ if (emu->audigy) {
+ snd_emu10k1_ptr_write_multiple(emu, voice,
+ A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(send_routing),
+ A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(send_routing),
+ A_SENDAMOUNTS, snd_emu10k1_compose_audigy_sendamounts(send_amount),
+ REGLIST_END);
+ for (int i = 0; i < 4; i++) {
+ u32 aml = emu10k1_send_target_from_amount(send_amount[2 * i]);
+ u32 amh = emu10k1_send_target_from_amount(send_amount[2 * i + 1]);
+ snd_emu10k1_ptr_write(emu, A_CSBA + i, voice, (amh << 16) | aml);
+ }
+ } else {
+ snd_emu10k1_ptr_write(emu, FXRT, voice,
+ snd_emu10k1_compose_send_routing(send_routing));
}
- spin_lock_irqsave(&emu->reg_lock, flags);
+ emu->voices[voice].dirty = 1;
+}
- /* volume parameters */
- if (extra) {
- memset(send_routing, 0, sizeof(send_routing));
- send_routing[0] = 0;
- send_routing[1] = 1;
- send_routing[2] = 2;
- send_routing[3] = 3;
- memset(send_amount, 0, sizeof(send_amount));
- } else {
- /* mono, left, right (master voice = left) */
- tmp = stereo ? (master ? 1 : 2) : 0;
- memcpy(send_routing, &mix->send_routing[tmp][0], 8);
- memcpy(send_amount, &mix->send_volume[tmp][0], 8);
- }
+static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice,
+ bool w_16, bool stereo,
+ unsigned int start_addr,
+ unsigned int end_addr,
+ struct snd_emu10k1_pcm_mixer *mix)
+{
+ guard(spinlock_irq)(&emu->reg_lock);
+ snd_emu10k1_pcm_init_voice(emu, evoice, w_16, stereo,
+ start_addr, end_addr,
+ &mix->send_routing[stereo][0],
+ &mix->send_volume[stereo][0]);
+ if (stereo)
+ snd_emu10k1_pcm_init_voice(emu, evoice + 1, w_16, true,
+ start_addr, end_addr,
+ &mix->send_routing[2][0],
+ &mix->send_volume[2][0]);
+}
- ccis = emu10k1_ccis(stereo, w_16);
-
- if (master) {
- evoice->epcm->ccca_start_addr = start_addr + ccis;
- if (extra) {
- start_addr += ccis;
- end_addr += ccis + emu->delay_pcm_irq;
- }
- if (stereo && !extra) {
- snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK);
- snd_emu10k1_ptr_write(emu, CPF, (voice + 1), CPF_STEREO_MASK);
- } else {
- snd_emu10k1_ptr_write(emu, CPF, voice, 0);
- }
- }
+static void snd_emu10k1_pcm_init_extra_voice(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice,
+ bool w_16,
+ unsigned int start_addr,
+ unsigned int end_addr)
+{
+ static const unsigned char send_routing[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ static const unsigned char send_amount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- /* setup routing */
- if (emu->audigy) {
- snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
- snd_emu10k1_compose_audigy_fxrt1(send_routing));
- snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
- snd_emu10k1_compose_audigy_fxrt2(send_routing));
- snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
- ((unsigned int)send_amount[4] << 24) |
- ((unsigned int)send_amount[5] << 16) |
- ((unsigned int)send_amount[6] << 8) |
- (unsigned int)send_amount[7]);
- } else
- snd_emu10k1_ptr_write(emu, FXRT, voice,
- snd_emu10k1_compose_send_routing(send_routing));
- /* Assumption that PT is already 0 so no harm overwriting */
- snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
- snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
- snd_emu10k1_ptr_write(emu, PSST, voice,
- (start_addr + (extra ? emu->delay_pcm_irq : 0)) |
- (send_amount[2] << 24));
- if (emu->card_capabilities->emu_model)
- pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
- else
- pitch_target = emu10k1_calc_pitch_target(runtime->rate);
- if (extra)
- snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr |
- emu10k1_select_interprom(pitch_target) |
- (w_16 ? 0 : CCCA_8BITSELECT));
- else
- snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) |
- emu10k1_select_interprom(pitch_target) |
- (w_16 ? 0 : CCCA_8BITSELECT));
- /* Clear filter delay memory */
- snd_emu10k1_ptr_write(emu, Z1, voice, 0);
- snd_emu10k1_ptr_write(emu, Z2, voice, 0);
- /* invalidate maps */
- silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
- snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
- snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
- /* modulation envelope */
- snd_emu10k1_ptr_write(emu, VTFT, voice, VTFT_FILTERTARGET_MASK);
- snd_emu10k1_ptr_write(emu, CVCF, voice, CVCF_CURRENTFILTER_MASK);
- snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0);
- snd_emu10k1_ptr_write(emu, DCYSUSM, voice, 0x007f);
- snd_emu10k1_ptr_write(emu, LFOVAL1, voice, 0x8000);
- snd_emu10k1_ptr_write(emu, LFOVAL2, voice, 0x8000);
- snd_emu10k1_ptr_write(emu, FMMOD, voice, 0);
- snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0);
- snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0);
- snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000);
- /* volume envelope */
- snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f);
- snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000);
- /* filter envelope */
- snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f);
- /* pitch envelope */
- snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0);
-
- spin_unlock_irqrestore(&emu->reg_lock, flags);
+ snd_emu10k1_pcm_init_voice(emu, evoice, w_16, false,
+ start_addr, end_addr,
+ send_routing, send_amount);
}
static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
@@ -380,9 +352,19 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
size_t alloc_size;
+ int type, channels, count;
int err;
- err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params));
+ if (epcm->type == PLAYBACK_EMUVOICE) {
+ type = EMU10K1_PCM;
+ channels = 1;
+ count = params_channels(hw_params);
+ } else {
+ type = EMU10K1_EFX;
+ channels = params_channels(hw_params);
+ count = 1;
+ }
+ err = snd_emu10k1_pcm_channel_alloc(epcm, type, count, channels);
if (err < 0)
return err;
@@ -415,7 +397,6 @@ static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm;
- int i;
if (runtime->private_data == NULL)
return 0;
@@ -424,12 +405,7 @@ static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream)
snd_emu10k1_voice_free(epcm->emu, epcm->extra);
epcm->extra = NULL;
}
- for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
- if (epcm->voices[i]) {
- snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);
- epcm->voices[i] = NULL;
- }
- }
+ snd_emu10k1_pcm_free_voices(epcm);
if (epcm->memblk) {
snd_emu10k1_free_pages(emu, epcm->memblk);
epcm->memblk = NULL;
@@ -444,26 +420,28 @@ static int snd_emu10k1_playback_prepare(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
+ bool w_16 = snd_pcm_format_width(runtime->format) == 16;
+ bool stereo = runtime->channels == 2;
unsigned int start_addr, end_addr;
+ unsigned int rate;
+
+ rate = runtime->rate;
+ if (emu->card_capabilities->emu_model &&
+ emu->emu1010.word_clock == 44100)
+ rate = rate * 480 / 441;
+ epcm->pitch_target = emu10k1_calc_pitch_target(rate);
+
+ start_addr = epcm->start_addr >> w_16;
+ end_addr = start_addr + runtime->period_size;
+ snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, w_16,
+ start_addr, end_addr);
+ start_addr >>= stereo;
+ epcm->ccca_start_addr = start_addr;
+ end_addr = start_addr + runtime->buffer_size;
+ snd_emu10k1_pcm_init_voices(emu, epcm->voices[0], w_16, stereo,
+ start_addr, end_addr,
+ &emu->pcm_mixer[substream->number]);
- start_addr = epcm->start_addr;
- end_addr = snd_pcm_lib_period_bytes(substream);
- if (runtime->channels == 2) {
- start_addr >>= 1;
- end_addr >>= 1;
- }
- end_addr += start_addr;
- snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,
- start_addr, end_addr, NULL);
- start_addr = epcm->start_addr;
- end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream);
- snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0],
- start_addr, end_addr,
- &emu->pcm_mixer[substream->number]);
- if (epcm->voices[1])
- snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1],
- start_addr, end_addr,
- &emu->pcm_mixer[substream->number]);
return 0;
}
@@ -472,28 +450,25 @@ static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream)
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
- unsigned int start_addr, end_addr;
- unsigned int channel_size;
- int i;
+ unsigned int start_addr;
+ unsigned int extra_size, channel_size;
+ unsigned int i;
- start_addr = epcm->start_addr;
- end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream);
+ epcm->pitch_target = PITCH_48000;
- channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK;
+ start_addr = epcm->start_addr >> 1; // 16-bit voices
- snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,
- start_addr, start_addr + (channel_size / 2), NULL);
+ extra_size = runtime->period_size;
+ channel_size = runtime->buffer_size;
- /* only difference with the master voice is we use it for the pointer */
- snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0],
- start_addr, start_addr + channel_size,
- &emu->efx_pcm_mixer[0]);
+ snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, true,
+ start_addr, start_addr + extra_size);
- start_addr += channel_size;
- for (i = 1; i < NUM_EFX_PLAYBACK; i++) {
- snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[i],
- start_addr, start_addr + channel_size,
- &emu->efx_pcm_mixer[i]);
+ epcm->ccca_start_addr = start_addr;
+ for (i = 0; i < runtime->channels; i++) {
+ snd_emu10k1_pcm_init_voices(emu, epcm->voices[i], true, false,
+ start_addr, start_addr + channel_size,
+ &emu->efx_pcm_mixer[i]);
start_addr += channel_size;
}
@@ -510,13 +485,12 @@ static const struct snd_pcm_hardware snd_emu10k1_efx_playback =
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
- .channels_min = NUM_EFX_PLAYBACK,
+ .channels_min = 1,
.channels_max = NUM_EFX_PLAYBACK,
- .buffer_bytes_max = (64*1024),
- .period_bytes_min = 64,
- .period_bytes_max = (64*1024),
+ .buffer_bytes_max = (128*1024),
+ .period_bytes_max = (128*1024),
.periods_min = 2,
- .periods_max = 2,
+ .periods_max = 1024,
.fifo_size = 0,
};
@@ -534,9 +508,17 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);
break;
case CAPTURE_EFX:
+ if (emu->card_capabilities->emu_model) {
+ // The upper 32 16-bit capture voices, two for each of the 16 32-bit channels.
+ // The lower voices are occupied by A_EXTOUT_*_CAP*.
+ epcm->capture_cr_val = 0;
+ epcm->capture_cr_val2 = 0xffffffff >> (32 - runtime->channels * 2);
+ }
if (emu->audigy) {
- snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0);
- snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ A_FXWC1, 0,
+ A_FXWC2, 0,
+ REGLIST_END);
} else
snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
break;
@@ -547,7 +529,7 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream);
epcm->capture_bs_val = 0;
for (idx = 0; idx < 31; idx++) {
- if (capture_period_sizes[idx] == epcm->capture_bufsize) {
+ if (capture_buffer_sizes[idx] == epcm->capture_bufsize) {
epcm->capture_bs_val = idx + 1;
break;
}
@@ -557,132 +539,181 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream)
epcm->capture_bs_val++;
}
if (epcm->type == CAPTURE_AC97ADC) {
+ unsigned rate = runtime->rate;
+ if (!(runtime->hw.rates & SNDRV_PCM_RATE_48000))
+ rate = rate * 480 / 441;
+
epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
if (runtime->channels > 1)
epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
epcm->capture_cr_val |= emu->audigy ?
- snd_emu10k1_audigy_capture_rate_reg(runtime->rate) :
- snd_emu10k1_capture_rate_reg(runtime->rate);
+ snd_emu10k1_audigy_capture_rate_reg(rate) :
+ snd_emu10k1_capture_rate_reg(rate);
}
return 0;
}
-static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int extra, struct snd_emu10k1_voice *evoice)
+static void snd_emu10k1_playback_fill_cache(struct snd_emu10k1 *emu,
+ unsigned voice,
+ u32 sample, bool stereo)
{
- struct snd_pcm_runtime *runtime;
- unsigned int voice, stereo, i, ccis, cra = 64, cs, sample;
+ u32 ccr;
- if (evoice == NULL)
- return;
- runtime = evoice->epcm->substream->runtime;
- voice = evoice->number;
- stereo = (!extra && runtime->channels == 2);
- sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;
- ccis = emu10k1_ccis(stereo, sample == 0);
- /* set cs to 2 * number of cache registers beside the invalidated */
- cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1;
- if (cs > 16) cs = 16;
- for (i = 0; i < cs; i++) {
+ // We assume that the cache is resting at this point (i.e.,
+ // CCR_CACHEINVALIDSIZE is very small).
+
+ // Clear leading frames. For simplicitly, this does too much,
+ // except for 16-bit stereo. And the interpolator will actually
+ // access them at all only when we're pitch-shifting.
+ for (int i = 0; i < 3; i++)
snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample);
- if (stereo) {
- snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample);
- }
- }
- /* reset cache */
- snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);
- snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);
+
+ // Fill cache
+ ccr = (64 - 3) << REG_SHIFT(CCR_CACHEINVALIDSIZE);
if (stereo) {
- snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);
- snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);
+ // The engine goes haywire if CCR_READADDRESS is out of sync
+ snd_emu10k1_ptr_write(emu, CCR, voice + 1, ccr);
}
- /* fill cache */
- snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
- if (stereo) {
- snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);
+ snd_emu10k1_ptr_write(emu, CCR, voice, ccr);
+}
+
+static void snd_emu10k1_playback_prepare_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_pcm *epcm,
+ bool w_16, bool stereo,
+ int channels)
+{
+ struct snd_pcm_substream *substream = epcm->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned eloop_start = epcm->start_addr >> w_16;
+ unsigned loop_start = eloop_start >> stereo;
+ unsigned eloop_size = runtime->period_size;
+ unsigned loop_size = runtime->buffer_size;
+ u32 sample = w_16 ? 0 : 0x80808080;
+
+ // To make the playback actually start at the 1st frame,
+ // we need to compensate for two circumstances:
+ // - The actual position is delayed by the cache size (64 frames)
+ // - The interpolator is centered around the 4th frame
+ loop_start += (epcm->resume_pos + 64 - 3) % loop_size;
+ for (int i = 0; i < channels; i++) {
+ unsigned voice = epcm->voices[i]->number;
+ snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, voice, loop_start);
+ loop_start += loop_size;
+ snd_emu10k1_playback_fill_cache(emu, voice, sample, stereo);
}
+
+ // The interrupt is triggered when CCCA_CURRADDR (CA) wraps around,
+ // which is ahead of the actual playback position, so the interrupt
+ // source needs to be delayed.
+ //
+ // In principle, this wouldn't need to be the cache's entire size - in
+ // practice, CCR_CACHEINVALIDSIZE (CIS) > `fetch threshold` has never
+ // been observed, and assuming 40 _bytes_ should be safe.
+ //
+ // The cache fills are somewhat random, which makes it impossible to
+ // align them with the interrupts. This makes a non-delayed interrupt
+ // source not practical, as the interrupt handler would have to wait
+ // for (CA - CIS) >= period_boundary for every channel in the stream.
+ //
+ // This is why all other (open) drivers for these chips use timer-based
+ // interrupts.
+ //
+ eloop_start += (epcm->resume_pos + eloop_size - 3) % eloop_size;
+ snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, epcm->extra->number, eloop_start);
+
+ // It takes a moment until the cache fills complete,
+ // but the unmuting takes long enough for that.
}
-static void snd_emu10k1_playback_prepare_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice,
- int master, int extra,
- struct snd_emu10k1_pcm_mixer *mix)
+static void snd_emu10k1_playback_commit_volume(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice,
+ unsigned int vattn)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
- unsigned int attn, vattn;
- unsigned int voice, tmp;
+ snd_emu10k1_ptr_write_multiple(emu, evoice->number,
+ VTFT, vattn | VTFT_FILTERTARGET_MASK,
+ CVCF, vattn | CVCF_CURRENTFILTER_MASK,
+ REGLIST_END);
+}
- if (evoice == NULL) /* skip second voice for mono */
- return;
- substream = evoice->epcm->substream;
- runtime = substream->runtime;
- voice = evoice->number;
+static void snd_emu10k1_playback_unmute_voice(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice,
+ bool stereo, bool master,
+ struct snd_emu10k1_pcm_mixer *mix)
+{
+ unsigned int vattn;
+ unsigned int tmp;
- attn = extra ? 0 : 0x00ff;
- tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0;
- vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0;
- snd_emu10k1_ptr_write(emu, IFATN, voice, attn);
- snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | VTFT_FILTERTARGET_MASK);
- snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | CVCF_CURRENTFILTER_MASK);
- snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f);
- snd_emu10k1_voice_clear_loop_stop(emu, voice);
+ tmp = stereo ? (master ? 1 : 2) : 0;
+ vattn = mix->attn[tmp] << 16;
+ snd_emu10k1_playback_commit_volume(emu, evoice, vattn);
}
-static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice, int master, int extra)
+static void snd_emu10k1_playback_unmute_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice,
+ bool stereo,
+ struct snd_emu10k1_pcm_mixer *mix)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
- unsigned int voice, pitch, pitch_target;
+ snd_emu10k1_playback_unmute_voice(emu, evoice, stereo, true, mix);
+ if (stereo)
+ snd_emu10k1_playback_unmute_voice(emu, evoice + 1, true, false, mix);
+}
- if (evoice == NULL) /* skip second voice for mono */
- return;
- substream = evoice->epcm->substream;
- runtime = substream->runtime;
- voice = evoice->number;
+static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice)
+{
+ snd_emu10k1_playback_commit_volume(emu, evoice, 0);
+}
- pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
- if (emu->card_capabilities->emu_model)
- pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
- else
- pitch_target = emu10k1_calc_pitch_target(runtime->rate);
- snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
- if (master || evoice->epcm->type == PLAYBACK_EFX)
- snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
- snd_emu10k1_ptr_write(emu, IP, voice, pitch);
- if (extra)
- snd_emu10k1_voice_intr_enable(emu, voice);
+static void snd_emu10k1_playback_mute_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice,
+ bool stereo)
+{
+ snd_emu10k1_playback_mute_voice(emu, evoice);
+ if (stereo)
+ snd_emu10k1_playback_mute_voice(emu, evoice + 1);
+}
+
+static void snd_emu10k1_playback_commit_pitch(struct snd_emu10k1 *emu,
+ u32 voice, u32 pitch_target)
+{
+ u32 ptrx = snd_emu10k1_ptr_read(emu, PTRX, voice);
+ u32 cpf = snd_emu10k1_ptr_read(emu, CPF, voice);
+ snd_emu10k1_ptr_write_multiple(emu, voice,
+ PTRX, (ptrx & ~PTRX_PITCHTARGET_MASK) | pitch_target,
+ CPF, (cpf & ~(CPF_CURRENTPITCH_MASK | CPF_FRACADDRESS_MASK)) | pitch_target,
+ REGLIST_END);
}
-static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice)
+static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice)
+{
+ unsigned int voice;
+
+ voice = evoice->number;
+ snd_emu10k1_playback_commit_pitch(emu, voice, evoice->epcm->pitch_target << 16);
+}
+
+static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *evoice)
{
unsigned int voice;
- if (evoice == NULL)
- return;
voice = evoice->number;
- snd_emu10k1_voice_intr_disable(emu, voice);
- snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0);
- snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0);
- snd_emu10k1_ptr_write(emu, IFATN, voice, 0xffff);
- snd_emu10k1_ptr_write(emu, VTFT, voice, VTFT_FILTERTARGET_MASK);
- snd_emu10k1_ptr_write(emu, CVCF, voice, CVCF_CURRENTFILTER_MASK);
- snd_emu10k1_ptr_write(emu, IP, voice, 0);
+ snd_emu10k1_playback_commit_pitch(emu, voice, 0);
}
-static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu,
- struct snd_emu10k1_pcm *epcm,
- struct snd_pcm_substream *substream,
- struct snd_pcm_runtime *runtime)
+static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_pcm *epcm)
{
- unsigned int ptr, period_pos;
+ epcm->running = 1;
+ snd_emu10k1_voice_intr_enable(emu, epcm->extra->number);
+}
- /* try to sychronize the current position for the interrupt
- source voice */
- period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt;
- period_pos %= runtime->period_size;
- ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number);
- ptr &= ~0x00ffffff;
- ptr |= epcm->ccca_start_addr + period_pos;
- snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr);
+static void snd_emu10k1_playback_set_stopped(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_pcm *epcm)
+{
+ snd_emu10k1_voice_intr_disable(emu, epcm->extra->number);
+ epcm->running = 0;
}
static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
@@ -692,46 +723,39 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
struct snd_emu10k1_pcm_mixer *mix;
- int result = 0;
+ bool w_16 = snd_pcm_format_width(runtime->format) == 16;
+ bool stereo = runtime->channels == 2;
/*
dev_dbg(emu->card->dev,
"trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
(int)emu, cmd, substream->ops->pointer(substream))
*/
- spin_lock(&emu->reg_lock);
+ guard(spinlock)(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); /* do we need this? */
- snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]);
+ snd_emu10k1_playback_prepare_voices(emu, epcm, w_16, stereo, 1);
fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
- snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime);
mix = &emu->pcm_mixer[substream->number];
- snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix);
- snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix);
- snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL);
- snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0);
- snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0);
- snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1);
- epcm->running = 1;
+ snd_emu10k1_playback_unmute_voices(emu, epcm->voices[0], stereo, mix);
+ snd_emu10k1_playback_set_running(emu, epcm);
+ snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0]);
+ snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- epcm->running = 0;
snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]);
- snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]);
snd_emu10k1_playback_stop_voice(emu, epcm->extra);
+ snd_emu10k1_playback_set_stopped(emu, epcm);
+ snd_emu10k1_playback_mute_voices(emu, epcm->voices[0], stereo);
break;
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&emu->reg_lock);
- return result;
+ return 0;
}
static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
@@ -740,9 +764,8 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
- int result = 0;
- spin_lock(&emu->reg_lock);
+ guard(spinlock)(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -759,8 +782,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
break;
case CAPTURE_EFX:
if (emu->audigy) {
- snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);
- snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ A_FXWC1, epcm->capture_cr_val,
+ A_FXWC2, epcm->capture_cr_val2,
+ REGLIST_END);
dev_dbg(emu->card->dev,
"cr_val=0x%x, cr_val2=0x%x\n",
epcm->capture_cr_val,
@@ -787,8 +812,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
break;
case CAPTURE_EFX:
if (emu->audigy) {
- snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0);
- snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ A_FXWC1, 0,
+ A_FXWC2, 0,
+ REGLIST_END);
} else
snd_emu10k1_ptr_write(emu, FXWC, 0, 0);
break;
@@ -797,10 +824,9 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
}
break;
default:
- result = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&emu->reg_lock);
- return result;
+ return 0;
}
static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *substream)
@@ -808,24 +834,27 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
- unsigned int ptr;
+ int ptr;
if (!epcm->running)
return 0;
+
ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff;
-#if 0 /* Perex's code */
- ptr += runtime->buffer_size;
ptr -= epcm->ccca_start_addr;
- ptr %= runtime->buffer_size;
-#else /* EMU10K1 Open Source code from Creative */
- if (ptr < epcm->ccca_start_addr)
- ptr += runtime->buffer_size - epcm->ccca_start_addr;
- else {
- ptr -= epcm->ccca_start_addr;
- if (ptr >= runtime->buffer_size)
- ptr -= runtime->buffer_size;
- }
-#endif
+
+ // This is the size of the whole cache minus the interpolator read-ahead,
+ // which leads us to the actual playback position.
+ //
+ // The cache is constantly kept mostly filled, so in principle we could
+ // return a more advanced position representing how far the hardware has
+ // already read the buffer, and set runtime->delay accordingly. However,
+ // this would be slightly different for every channel (and remarkably slow
+ // to obtain), so only a fixed worst-case value would be practical.
+ //
+ ptr -= 64 - 3;
+ if (ptr < 0)
+ ptr += runtime->buffer_size;
+
/*
dev_dbg(emu->card->dev,
"ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
@@ -835,6 +864,49 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
return ptr;
}
+static u64 snd_emu10k1_efx_playback_voice_mask(struct snd_emu10k1_pcm *epcm,
+ int channels)
+{
+ u64 mask = 0;
+
+ for (int i = 0; i < channels; i++) {
+ int voice = epcm->voices[i]->number;
+ mask |= 1ULL << voice;
+ }
+ return mask;
+}
+
+static void snd_emu10k1_efx_playback_freeze_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_pcm *epcm,
+ int channels)
+{
+ for (int i = 0; i < channels; i++) {
+ int voice = epcm->voices[i]->number;
+ snd_emu10k1_ptr_write(emu, CPF_STOP, voice, 1);
+ snd_emu10k1_playback_commit_pitch(emu, voice, PITCH_48000 << 16);
+ }
+}
+
+static void snd_emu10k1_efx_playback_unmute_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_pcm *epcm,
+ int channels)
+{
+ for (int i = 0; i < channels; i++)
+ snd_emu10k1_playback_unmute_voice(emu, epcm->voices[i], false, true,
+ &emu->efx_pcm_mixer[i]);
+}
+
+static void snd_emu10k1_efx_playback_stop_voices(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_pcm *epcm,
+ int channels)
+{
+ for (int i = 0; i < channels; i++)
+ snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
+ snd_emu10k1_playback_set_stopped(emu, epcm);
+
+ for (int i = 0; i < channels; i++)
+ snd_emu10k1_playback_mute_voice(emu, epcm->voices[i]);
+}
static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
@@ -842,46 +914,60 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_emu10k1_pcm *epcm = runtime->private_data;
- int i;
+ u64 mask;
int result = 0;
- spin_lock(&emu->reg_lock);
+ guard(spinlock)(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- /* prepare voices */
- for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
- snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]);
- }
- snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra);
- fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL);
- snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0,
- &emu->efx_pcm_mixer[0]);
- for (i = 1; i < NUM_EFX_PLAYBACK; i++)
- snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0, 0,
- &emu->efx_pcm_mixer[i]);
- snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 0, 0);
- snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1);
- for (i = 1; i < NUM_EFX_PLAYBACK; i++)
- snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0);
- epcm->running = 1;
+ mask = snd_emu10k1_efx_playback_voice_mask(
+ epcm, runtime->channels);
+ for (int i = 0; i < 10; i++) {
+ // Note that the freeze is not interruptible, so we make no
+ // effort to reset the bits outside the error handling here.
+ snd_emu10k1_voice_set_loop_stop_multiple(emu, mask);
+ snd_emu10k1_efx_playback_freeze_voices(
+ emu, epcm, runtime->channels);
+ snd_emu10k1_playback_prepare_voices(
+ emu, epcm, true, false, runtime->channels);
+
+ // It might seem to make more sense to unmute the voices only after
+ // they have been started, to potentially avoid torturing the speakers
+ // if something goes wrong. However, we cannot unmute atomically,
+ // which means that we'd get some mild artifacts in the regular case.
+ snd_emu10k1_efx_playback_unmute_voices(emu, epcm, runtime->channels);
+
+ snd_emu10k1_playback_set_running(emu, epcm);
+ result = snd_emu10k1_voice_clear_loop_stop_multiple_atomic(emu, mask);
+ if (result == 0) {
+ // The extra voice is allowed to lag a bit
+ snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
+ return 0;
+ }
+
+ snd_emu10k1_efx_playback_stop_voices(
+ emu, epcm, runtime->channels);
+
+ if (result != -EAGAIN)
+ break;
+ // The sync start can legitimately fail due to NMIs, etc.
+ }
+ snd_emu10k1_voice_clear_loop_stop_multiple(emu, mask);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- epcm->running = 0;
- for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
- snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
- }
snd_emu10k1_playback_stop_voice(emu, epcm->extra);
+ snd_emu10k1_efx_playback_stop_voices(
+ emu, epcm, runtime->channels);
+
+ epcm->resume_pos = snd_emu10k1_playback_pointer(substream);
break;
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&emu->reg_lock);
return result;
}
@@ -920,9 +1006,8 @@ static const struct snd_pcm_hardware snd_emu10k1_playback =
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (128*1024),
- .period_bytes_min = 64,
.period_bytes_max = (128*1024),
- .periods_min = 1,
+ .periods_min = 2,
.periods_max = 1024,
.fifo_size = 0,
};
@@ -938,7 +1023,7 @@ static const struct snd_pcm_hardware snd_emu10k1_capture =
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_24000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
@@ -958,13 +1043,11 @@ static const struct snd_pcm_hardware snd_emu10k1_capture_efx =
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
- .rate_min = 44100,
- .rate_max = 192000,
- .channels_min = 8,
- .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 16,
.buffer_bytes_max = (64*1024),
.period_bytes_min = 384,
.period_bytes_max = (64*1024),
@@ -1025,13 +1108,29 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_emu10k1_playback_set_constraints(struct snd_pcm_runtime *runtime)
+{
+ int err;
+
+ // The buffer size must be a multiple of the period size, to avoid a
+ // mismatch between the extra voice and the regular voices.
+ err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ return err;
+ // The hardware is typically the cache's size of 64 frames ahead.
+ // Leave enough time for actually filling up the buffer.
+ err = snd_pcm_hw_constraint_minmax(
+ runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 128, UINT_MAX);
+ return err;
+}
+
static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
{
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_emu10k1_pcm *epcm;
struct snd_emu10k1_pcm_mixer *mix;
struct snd_pcm_runtime *runtime = substream->runtime;
- int i;
+ int i, j, err;
epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
if (epcm == NULL)
@@ -1043,13 +1142,21 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_efx_playback;
-
+ if (emu->card_capabilities->emu_model)
+ snd_emu1010_constrain_efx_rate(emu, runtime);
+ err = snd_emu10k1_playback_set_constraints(runtime);
+ if (err < 0) {
+ kfree(epcm);
+ return err;
+ }
+
for (i = 0; i < NUM_EFX_PLAYBACK; i++) {
mix = &emu->efx_pcm_mixer[i];
- mix->send_routing[0][0] = i;
+ for (j = 0; j < 8; j++)
+ mix->send_routing[0][j] = i + j;
memset(&mix->send_volume, 0, sizeof(mix->send_volume));
mix->send_volume[0][0] = 255;
- mix->attn[0] = 0xffff;
+ mix->attn[0] = 0x8000;
mix->epcm = epcm;
snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1);
}
@@ -1073,18 +1180,13 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_playback;
- err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0) {
- kfree(epcm);
- return err;
- }
- err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
+ err = snd_emu10k1_playback_set_constraints(runtime);
if (err < 0) {
kfree(epcm);
return err;
}
- if (emu->card_capabilities->emu_model && emu->emu1010.internal_clock == 0)
- sample_rate = 44100;
+ if (emu->card_capabilities->emu_model)
+ sample_rate = emu->emu1010.word_clock;
else
sample_rate = 48000;
err = snd_pcm_hw_rule_noresample(runtime, sample_rate);
@@ -1093,12 +1195,12 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
return err;
}
mix = &emu->pcm_mixer[substream->number];
- for (i = 0; i < 4; i++)
+ for (i = 0; i < 8; i++)
mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;
memset(&mix->send_volume, 0, sizeof(mix->send_volume));
mix->send_volume[0][0] = mix->send_volume[0][1] =
mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
- mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
+ mix->attn[0] = mix->attn[1] = mix->attn[2] = 0x8000;
mix->epcm = epcm;
snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1);
return 0;
@@ -1134,10 +1236,11 @@ static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream)
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_capture;
+ snd_emu10k1_constrain_capture_rates(emu, runtime);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ &hw_constraints_capture_buffer_sizes);
emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt;
emu->pcm_capture_substream = substream;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates);
return 0;
}
@@ -1172,10 +1275,10 @@ static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream)
runtime->hw = snd_emu10k1_capture;
runtime->hw.rates = SNDRV_PCM_RATE_8000;
runtime->hw.rate_min = runtime->hw.rate_max = 8000;
- runtime->hw.channels_min = 1;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ &hw_constraints_capture_buffer_sizes);
emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt;
emu->pcm_capture_mic_substream = substream;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes);
return 0;
}
@@ -1194,7 +1297,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
struct snd_emu10k1_pcm *epcm;
struct snd_pcm_runtime *runtime = substream->runtime;
int nefx = emu->audigy ? 64 : 32;
- int idx;
+ int idx, err;
epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
if (epcm == NULL)
@@ -1210,20 +1313,9 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
substream->runtime->private_data = epcm;
substream->runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_capture_efx;
- runtime->hw.rates = SNDRV_PCM_RATE_48000;
- runtime->hw.rate_min = runtime->hw.rate_max = 48000;
- spin_lock_irq(&emu->reg_lock);
if (emu->card_capabilities->emu_model) {
- /* TODO
- * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
- * rate_min = 44100,
- * rate_max = 192000,
- * channels_min = 16,
- * channels_max = 16,
- * Need to add mixer control to fix sample rate
- *
+ snd_emu1010_constrain_efx_rate(emu, runtime);
+ /*
* There are 32 mono channels of 16bits each.
* 24bit Audio uses 2x channels over 16bit,
* 96kHz uses 2x channels over 48kHz,
@@ -1234,41 +1326,17 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
* 1010rev2 and 1616(m) cards have double that,
* but we don't exceed 16 channels anyway.
*/
-#if 1
- switch (emu->emu1010.internal_clock) {
- case 0:
- /* For 44.1kHz */
- runtime->hw.rates = SNDRV_PCM_RATE_44100;
- runtime->hw.rate_min = runtime->hw.rate_max = 44100;
- runtime->hw.channels_min =
- runtime->hw.channels_max = 16;
- break;
- case 1:
- /* For 48kHz */
- runtime->hw.rates = SNDRV_PCM_RATE_48000;
- runtime->hw.rate_min = runtime->hw.rate_max = 48000;
- runtime->hw.channels_min =
- runtime->hw.channels_max = 16;
- break;
- }
-#endif
#if 0
/* For 96kHz */
- runtime->hw.rates = SNDRV_PCM_RATE_96000;
- runtime->hw.rate_min = runtime->hw.rate_max = 96000;
runtime->hw.channels_min = runtime->hw.channels_max = 4;
#endif
#if 0
/* For 192kHz */
- runtime->hw.rates = SNDRV_PCM_RATE_192000;
- runtime->hw.rate_min = runtime->hw.rate_max = 192000;
runtime->hw.channels_min = runtime->hw.channels_max = 2;
#endif
runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
- /* efx_voices_mask[0] is expected to be zero
- * efx_voices_mask[1] is expected to have 32bits set
- */
} else {
+ guard(spinlock_irq)(&emu->reg_lock);
runtime->hw.channels_min = runtime->hw.channels_max = 0;
for (idx = 0; idx < nefx; idx++) {
if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) {
@@ -1276,13 +1344,19 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
runtime->hw.channels_max++;
}
}
+ epcm->capture_cr_val = emu->efx_voices_mask[0];
+ epcm->capture_cr_val2 = emu->efx_voices_mask[1];
}
- epcm->capture_cr_val = emu->efx_voices_mask[0];
- epcm->capture_cr_val2 = emu->efx_voices_mask[1];
- spin_unlock_irq(&emu->reg_lock);
+ err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &hw_constraints_efx_capture_channels);
+ if (err < 0) {
+ kfree(epcm);
+ return err;
+ }
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ &hw_constraints_capture_buffer_sizes);
emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt;
emu->pcm_capture_efx_substream = substream;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes);
return 0;
}
@@ -1341,7 +1415,7 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
- strcpy(pcm->name, "ADC Capture/Standard PCM Playback");
+ strscpy(pcm->name, "ADC Capture/Standard PCM Playback");
emu->pcm = pcm;
/* playback substream can't use managed buffers due to alignment */
@@ -1373,7 +1447,7 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
- strcpy(pcm->name, "Multichannel Playback");
+ strscpy(pcm->name, "Multichannel Playback");
emu->pcm_multi = pcm;
for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)
@@ -1407,7 +1481,7 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops);
pcm->info_flags = 0;
- strcpy(pcm->name, "Mic Capture");
+ strscpy(pcm->name, "Mic Capture");
emu->pcm_mic = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
@@ -1433,10 +1507,8 @@ static int snd_emu10k1_pcm_efx_voices_mask_get(struct snd_kcontrol *kcontrol, st
int nefx = emu->audigy ? 64 : 32;
int idx;
- spin_lock_irq(&emu->reg_lock);
for (idx = 0; idx < nefx; idx++)
ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0;
- spin_unlock_irq(&emu->reg_lock);
return 0;
}
@@ -1445,7 +1517,6 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
unsigned int nval[2], bits;
int nefx = emu->audigy ? 64 : 32;
- int nefxb = emu->audigy ? 7 : 6;
int change, idx;
nval[0] = nval[1] = 0;
@@ -1455,20 +1526,14 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st
bits++;
}
- // Check that the number of requested channels is a power of two
- // not bigger than the number of available channels.
- for (idx = 0; idx < nefxb; idx++)
- if (1 << idx == bits)
- break;
- if (idx >= nefxb)
+ if (bits == 9 || bits == 11 || bits == 13 || bits == 15 || bits > 16)
return -EINVAL;
- spin_lock_irq(&emu->reg_lock);
+ guard(spinlock_irq)(&emu->reg_lock);
change = (nval[0] != emu->efx_voices_mask[0]) ||
(nval[1] != emu->efx_voices_mask[1]);
emu->efx_voices_mask[0] = nval[0];
emu->efx_voices_mask[1] = nval[1];
- spin_unlock_irq(&emu->reg_lock);
return change;
}
@@ -1592,12 +1657,14 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre
pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);
pcm->tram_shift = 0;
- snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0); /* reset */
- snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); /* reset */
- snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size);
- snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0); /* reset ptr number */
- snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size);
- snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size);
+ snd_emu10k1_ptr_write_multiple(emu, 0,
+ emu->gpr_base + pcm->gpr_running, 0, /* reset */
+ emu->gpr_base + pcm->gpr_trigger, 0, /* reset */
+ emu->gpr_base + pcm->gpr_size, runtime->buffer_size,
+ emu->gpr_base + pcm->gpr_ptr, 0, /* reset ptr number */
+ emu->gpr_base + pcm->gpr_count, runtime->period_size,
+ emu->gpr_base + pcm->gpr_tmpcount, runtime->period_size,
+ REGLIST_END);
for (i = 0; i < pcm->channels; i++)
snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels));
return 0;
@@ -1607,9 +1674,9 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre
{
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
- int result = 0;
+ int result;
- spin_lock(&emu->reg_lock);
+ guard(spinlock)(&emu->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* follow thru */
@@ -1629,7 +1696,7 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre
#endif
result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);
if (result < 0)
- goto __err;
+ return result;
snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */
snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);
break;
@@ -1642,12 +1709,9 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre
pcm->tram_shift = 0;
break;
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- __err:
- spin_unlock(&emu->reg_lock);
- return result;
+ return 0;
}
static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(struct snd_pcm_substream *substream)
@@ -1691,13 +1755,10 @@ static int snd_emu10k1_fx8010_playback_open(struct snd_pcm_substream *substream)
runtime->hw = snd_emu10k1_fx8010_playback;
runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels;
runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2;
- spin_lock_irq(&emu->reg_lock);
- if (pcm->valid == 0) {
- spin_unlock_irq(&emu->reg_lock);
+ guard(spinlock_irq)(&emu->reg_lock);
+ if (pcm->valid == 0)
return -ENODEV;
- }
pcm->opened = 1;
- spin_unlock_irq(&emu->reg_lock);
return 0;
}
@@ -1706,9 +1767,8 @@ static int snd_emu10k1_fx8010_playback_close(struct snd_pcm_substream *substream
struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);
struct snd_emu10k1_fx8010_pcm *pcm = &emu->fx8010.pcm[substream->number];
- spin_lock_irq(&emu->reg_lock);
+ guard(spinlock_irq)(&emu->reg_lock);
pcm->opened = 0;
- spin_unlock_irq(&emu->reg_lock);
return 0;
}
@@ -1740,42 +1800,34 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
pcm->info_flags = 0;
if (emu->audigy)
- strcpy(pcm->name, "Multichannel Capture");
+ strscpy(pcm->name, "Multichannel Capture");
else
- strcpy(pcm->name, "Multichannel Capture/PT Playback");
+ strscpy(pcm->name, "Multichannel Capture/PT Playback");
emu->pcm_efx = pcm;
- /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs
- * to these
- */
-
- if (emu->audigy) {
- emu->efx_voices_mask[0] = 0;
- if (emu->card_capabilities->emu_model)
- /* Pavel Hofman - 32 voices will be used for
- * capture (write mode) -
- * each bit = corresponding voice
- */
- emu->efx_voices_mask[1] = 0xffffffff;
- else
+ if (!emu->card_capabilities->emu_model) {
+ // On Sound Blasters, the DSP code copies the EXTINs to FXBUS2.
+ // The mask determines which of these and the EXTOUTs the multi-
+ // channel capture actually records (the channel order is fixed).
+ if (emu->audigy) {
+ emu->efx_voices_mask[0] = 0;
emu->efx_voices_mask[1] = 0xffff;
+ } else {
+ emu->efx_voices_mask[0] = 0xffff0000;
+ emu->efx_voices_mask[1] = 0;
+ }
+ kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.device = device;
+ err = snd_ctl_add(emu->card, kctl);
+ if (err < 0)
+ return err;
} else {
- emu->efx_voices_mask[0] = 0xffff0000;
- emu->efx_voices_mask[1] = 0;
+ // On E-MU cards, the DSP code copies the P16VINs/EMU32INs to
+ // FXBUS2. These are already selected & routed by the FPGA,
+ // so there is no need to apply additional masking.
}
- /* For emu1010, the control has to set 32 upper bits (voices)
- * out of the 64 bits (voices) to true for the 16-channels capture
- * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
- * is already defined but the snd_emu10k1_pcm_efx_voices_mask
- * control can override this register's value.
- */
- kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
- if (!kctl)
- return -ENOMEM;
- kctl->id.device = device;
- err = snd_ctl_add(emu->card, kctl);
- if (err < 0)
- return err;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
64*1024, 64*1024);
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index bec72dc60a41..f6186b5be049 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -1,21 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Lee Revell <rlrevell@joe-job.com>
+ * James Courtier-Dutton <James@superbug.co.uk>
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
* Creative Labs, Inc.
- * Routines for control of EMU10K1 chips / proc interface routines
- *
- * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
- * Added EMU 1010 support.
*
- * BUGS:
- * --
- *
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips / proc interface routines
*/
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
#include "p16v.h"
@@ -37,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);
@@ -51,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);
}
@@ -66,158 +62,100 @@ static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu,
static void snd_emu10k1_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- /* FIXME - output names are in emufx.c too */
- static const char * const creative_outs[32] = {
- /* 00 */ "AC97 Left",
- /* 01 */ "AC97 Right",
- /* 02 */ "Optical IEC958 Left",
- /* 03 */ "Optical IEC958 Right",
- /* 04 */ "Center",
- /* 05 */ "LFE",
- /* 06 */ "Headphone Left",
- /* 07 */ "Headphone Right",
- /* 08 */ "Surround Left",
- /* 09 */ "Surround Right",
- /* 10 */ "PCM Capture Left",
- /* 11 */ "PCM Capture Right",
- /* 12 */ "MIC Capture",
- /* 13 */ "AC97 Surround Left",
- /* 14 */ "AC97 Surround Right",
- /* 15 */ "???",
- /* 16 */ "???",
- /* 17 */ "Analog Center",
- /* 18 */ "Analog LFE",
- /* 19 */ "???",
- /* 20 */ "???",
- /* 21 */ "???",
- /* 22 */ "???",
- /* 23 */ "???",
- /* 24 */ "???",
- /* 25 */ "???",
- /* 26 */ "???",
- /* 27 */ "???",
- /* 28 */ "???",
- /* 29 */ "???",
- /* 30 */ "???",
- /* 31 */ "???"
- };
-
- static const char * const audigy_outs[64] = {
- /* 00 */ "Digital Front Left",
- /* 01 */ "Digital Front Right",
- /* 02 */ "Digital Center",
- /* 03 */ "Digital LEF",
- /* 04 */ "Headphone Left",
- /* 05 */ "Headphone Right",
- /* 06 */ "Digital Rear Left",
- /* 07 */ "Digital Rear Right",
- /* 08 */ "Front Left",
- /* 09 */ "Front Right",
- /* 10 */ "Center",
- /* 11 */ "LFE",
- /* 12 */ "???",
- /* 13 */ "???",
- /* 14 */ "Rear Left",
- /* 15 */ "Rear Right",
- /* 16 */ "AC97 Front Left",
- /* 17 */ "AC97 Front Right",
- /* 18 */ "ADC Capture Left",
- /* 19 */ "ADC Capture Right",
- /* 20 */ "???",
- /* 21 */ "???",
- /* 22 */ "???",
- /* 23 */ "???",
- /* 24 */ "???",
- /* 25 */ "???",
- /* 26 */ "???",
- /* 27 */ "???",
- /* 28 */ "???",
- /* 29 */ "???",
- /* 30 */ "???",
- /* 31 */ "???",
- /* 32 */ "FXBUS2_0",
- /* 33 */ "FXBUS2_1",
- /* 34 */ "FXBUS2_2",
- /* 35 */ "FXBUS2_3",
- /* 36 */ "FXBUS2_4",
- /* 37 */ "FXBUS2_5",
- /* 38 */ "FXBUS2_6",
- /* 39 */ "FXBUS2_7",
- /* 40 */ "FXBUS2_8",
- /* 41 */ "FXBUS2_9",
- /* 42 */ "FXBUS2_10",
- /* 43 */ "FXBUS2_11",
- /* 44 */ "FXBUS2_12",
- /* 45 */ "FXBUS2_13",
- /* 46 */ "FXBUS2_14",
- /* 47 */ "FXBUS2_15",
- /* 48 */ "FXBUS2_16",
- /* 49 */ "FXBUS2_17",
- /* 50 */ "FXBUS2_18",
- /* 51 */ "FXBUS2_19",
- /* 52 */ "FXBUS2_20",
- /* 53 */ "FXBUS2_21",
- /* 54 */ "FXBUS2_22",
- /* 55 */ "FXBUS2_23",
- /* 56 */ "FXBUS2_24",
- /* 57 */ "FXBUS2_25",
- /* 58 */ "FXBUS2_26",
- /* 59 */ "FXBUS2_27",
- /* 60 */ "FXBUS2_28",
- /* 61 */ "FXBUS2_29",
- /* 62 */ "FXBUS2_30",
- /* 63 */ "FXBUS2_31"
- };
-
struct snd_emu10k1 *emu = entry->private_data;
- unsigned int val, val1;
- int nefx = emu->audigy ? 64 : 32;
- const char * const *outputs = emu->audigy ? audigy_outs : creative_outs;
+ const char * const *inputs = emu->audigy ?
+ snd_emu10k1_audigy_ins : snd_emu10k1_sblive_ins;
+ const char * const *outputs = emu->audigy ?
+ snd_emu10k1_audigy_outs : snd_emu10k1_sblive_outs;
+ unsigned short extin_mask = emu->audigy ? ~0 : emu->fx8010.extin_mask;
+ unsigned short extout_mask = emu->audigy ? ~0 : emu->fx8010.extout_mask;
+ unsigned int val, val1, ptrx, psst, dsl, snda;
+ int nefx = emu->audigy ? 32 : 16;
int idx;
snd_iprintf(buffer, "EMU10K1\n\n");
snd_iprintf(buffer, "Card : %s\n",
- emu->audigy ? "Audigy" : (emu->card_capabilities->ecard ? "EMU APS" : "Creative"));
+ emu->card_capabilities->emu_model ? "E-MU D.A.S." :
+ emu->card_capabilities->ecard ? "E-MU A.P.S." :
+ emu->audigy ? "SB Audigy" : "SB Live!");
snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size);
snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2);
- snd_iprintf(buffer, "\n");
- snd_iprintf(buffer, "Effect Send Routing :\n");
+
+ snd_iprintf(buffer, "\nEffect Send Routing & Amounts:\n");
for (idx = 0; idx < NUM_G; idx++) {
- val = emu->audigy ?
- snd_emu10k1_ptr_read(emu, A_FXRT1, idx) :
- snd_emu10k1_ptr_read(emu, FXRT, idx);
- val1 = emu->audigy ?
- snd_emu10k1_ptr_read(emu, A_FXRT2, idx) :
- 0;
+ ptrx = snd_emu10k1_ptr_read(emu, PTRX, idx);
+ psst = snd_emu10k1_ptr_read(emu, PSST, idx);
+ dsl = snd_emu10k1_ptr_read(emu, DSL, idx);
if (emu->audigy) {
- snd_iprintf(buffer, "Ch%i: A=%i, B=%i, C=%i, D=%i, ",
+ val = snd_emu10k1_ptr_read(emu, A_FXRT1, idx);
+ val1 = snd_emu10k1_ptr_read(emu, A_FXRT2, idx);
+ snda = snd_emu10k1_ptr_read(emu, A_SENDAMOUNTS, idx);
+ snd_iprintf(buffer, "Ch%-2i: A=%2i:%02x, B=%2i:%02x, C=%2i:%02x, D=%2i:%02x, ",
idx,
- val & 0x3f,
- (val >> 8) & 0x3f,
- (val >> 16) & 0x3f,
- (val >> 24) & 0x3f);
- snd_iprintf(buffer, "E=%i, F=%i, G=%i, H=%i\n",
- val1 & 0x3f,
- (val1 >> 8) & 0x3f,
- (val1 >> 16) & 0x3f,
- (val1 >> 24) & 0x3f);
+ val & 0x3f, REG_VAL_GET(PTRX_FXSENDAMOUNT_A, ptrx),
+ (val >> 8) & 0x3f, REG_VAL_GET(PTRX_FXSENDAMOUNT_B, ptrx),
+ (val >> 16) & 0x3f, REG_VAL_GET(PSST_FXSENDAMOUNT_C, psst),
+ (val >> 24) & 0x3f, REG_VAL_GET(DSL_FXSENDAMOUNT_D, dsl));
+ snd_iprintf(buffer, "E=%2i:%02x, F=%2i:%02x, G=%2i:%02x, H=%2i:%02x\n",
+ val1 & 0x3f, (snda >> 24) & 0xff,
+ (val1 >> 8) & 0x3f, (snda >> 16) & 0xff,
+ (val1 >> 16) & 0x3f, (snda >> 8) & 0xff,
+ (val1 >> 24) & 0x3f, snda & 0xff);
} else {
- snd_iprintf(buffer, "Ch%i: A=%i, B=%i, C=%i, D=%i\n",
+ val = snd_emu10k1_ptr_read(emu, FXRT, idx);
+ snd_iprintf(buffer, "Ch%-2i: A=%2i:%02x, B=%2i:%02x, C=%2i:%02x, D=%2i:%02x\n",
idx,
- (val >> 16) & 0x0f,
- (val >> 20) & 0x0f,
- (val >> 24) & 0x0f,
- (val >> 28) & 0x0f);
+ (val >> 16) & 0x0f, REG_VAL_GET(PTRX_FXSENDAMOUNT_A, ptrx),
+ (val >> 20) & 0x0f, REG_VAL_GET(PTRX_FXSENDAMOUNT_B, ptrx),
+ (val >> 24) & 0x0f, REG_VAL_GET(PSST_FXSENDAMOUNT_C, psst),
+ (val >> 28) & 0x0f, REG_VAL_GET(DSL_FXSENDAMOUNT_D, dsl));
}
}
- snd_iprintf(buffer, "\nCaptured FX Outputs :\n");
- for (idx = 0; idx < nefx; idx++) {
- if (emu->efx_voices_mask[idx/32] & (1 << (idx%32)))
- snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]);
+ snd_iprintf(buffer, "\nEffect Send Targets:\n");
+ // Audigy actually has 64, but we don't use them all.
+ for (idx = 0; idx < 32; idx++) {
+ const char *c = snd_emu10k1_fxbus[idx];
+ if (c)
+ snd_iprintf(buffer, " Channel %02i [%s]\n", idx, c);
+ }
+ if (!emu->card_capabilities->emu_model) {
+ snd_iprintf(buffer, "\nOutput Channels:\n");
+ for (idx = 0; idx < 32; idx++)
+ if (outputs[idx] && (extout_mask & (1 << idx)))
+ snd_iprintf(buffer, " Channel %02i [%s]\n", idx, outputs[idx]);
+ snd_iprintf(buffer, "\nInput Channels:\n");
+ for (idx = 0; idx < 16; idx++)
+ if (inputs[idx] && (extin_mask & (1 << idx)))
+ snd_iprintf(buffer, " Channel %02i [%s]\n", idx, inputs[idx]);
+ snd_iprintf(buffer, "\nMultichannel Capture Sources:\n");
+ for (idx = 0; idx < nefx; idx++)
+ if (emu->efx_voices_mask[0] & (1 << idx))
+ snd_iprintf(buffer, " Channel %02i [Output: %s]\n",
+ idx, outputs[idx] ? outputs[idx] : "???");
+ if (emu->audigy) {
+ for (idx = 0; idx < 32; idx++)
+ if (emu->efx_voices_mask[1] & (1 << idx))
+ snd_iprintf(buffer, " Channel %02i [Input: %s]\n",
+ idx + 32, inputs[idx] ? inputs[idx] : "???");
+ } else {
+ for (idx = 0; idx < 16; idx++) {
+ if (emu->efx_voices_mask[0] & ((1 << 16) << idx)) {
+ if (emu->card_capabilities->sblive51) {
+ s8 c = snd_emu10k1_sblive51_fxbus2_map[idx];
+ if (c == -1)
+ snd_iprintf(buffer, " Channel %02i [Output: %s]\n",
+ idx + 16, outputs[idx + 16]);
+ else
+ snd_iprintf(buffer, " Channel %02i [Input: %s]\n",
+ idx + 16, inputs[c]);
+ } else {
+ snd_iprintf(buffer, " Channel %02i [Input: %s]\n",
+ idx + 16, inputs[idx] ? inputs[idx] : "???");
+ }
+ }
+ }
+ }
}
- snd_iprintf(buffer, "\nAll FX Outputs :\n");
- for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++)
- snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]);
}
static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
@@ -226,27 +164,42 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
struct snd_emu10k1 *emu = entry->private_data;
u32 value;
u32 value2;
- u32 rate;
if (emu->card_capabilities->emu_model) {
- snd_emu1010_fpga_read(emu, 0x38, &value);
- if ((value & 0x1) == 0) {
- snd_emu1010_fpga_read(emu, 0x2a, &value);
- snd_emu1010_fpga_read(emu, 0x2b, &value2);
- rate = 0x1770000 / (((value << 5) | value2)+1);
- snd_iprintf(buffer, "ADAT Locked : %u\n", rate);
- } else {
- snd_iprintf(buffer, "ADAT Unlocked\n");
- }
- snd_emu1010_fpga_read(emu, 0x20, &value);
- if ((value & 0x4) == 0) {
- snd_emu1010_fpga_read(emu, 0x28, &value);
- snd_emu1010_fpga_read(emu, 0x29, &value2);
- rate = 0x1770000 / (((value << 5) | value2)+1);
- snd_iprintf(buffer, "SPDIF Locked : %d\n", rate);
- } else {
- snd_iprintf(buffer, "SPDIF Unlocked\n");
+ guard(snd_emu1010_fpga_lock)(emu);
+
+ // This represents the S/PDIF lock status on 0404b, which is
+ // kinda weird and unhelpful, because monitoring it via IRQ is
+ // impractical (one gets an IRQ flood as long as it is desynced).
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &value);
+ snd_iprintf(buffer, "Lock status 1: %#x\n", value & 0x10);
+
+ // Bit 0x1 in LO being 0 is supposedly for ADAT lock.
+ // The registers are always all zero on 0404b.
+ snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_LO, &value);
+ snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_HI, &value2);
+ snd_iprintf(buffer, "Lock status 2: %#x %#x\n", value, value2);
+
+ snd_iprintf(buffer, "S/PDIF rate: %dHz\n",
+ snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_SPDIF_IN));
+ if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) {
+ snd_iprintf(buffer, "ADAT rate: %dHz\n",
+ snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_ADAT_IN));
+ snd_iprintf(buffer, "Dock rate: %dHz\n",
+ snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_2ND_HANA));
}
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU0404 ||
+ emu->card_capabilities->emu_model == EMU_MODEL_EMU1010)
+ snd_iprintf(buffer, "BNC rate: %dHz\n",
+ snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_SYNC_BNC));
+
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value);
+ if (value & EMU_HANA_SPDIF_MODE_RX_INVALID)
+ snd_iprintf(buffer, "\nS/PDIF input invalid\n");
+ else
+ snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n",
+ value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer",
+ value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : "");
} else {
snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS);
snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
@@ -254,7 +207,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
}
@@ -273,37 +226,148 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry,
}
}
-static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry,
+struct emu10k1_reg_entry {
+ unsigned short base, size;
+ const char *name;
+};
+
+static const struct emu10k1_reg_entry sblive_reg_entries[] = {
+ { 0, 0x10, "FXBUS" },
+ { 0x10, 0x10, "EXTIN" },
+ { 0x20, 0x10, "EXTOUT" },
+ { 0x30, 0x10, "FXBUS2" },
+ { 0x40, 0x20, NULL }, // Constants
+ { 0x100, 0x100, "GPR" },
+ { 0x200, 0x80, "ITRAM_DATA" },
+ { 0x280, 0x20, "ETRAM_DATA" },
+ { 0x300, 0x80, "ITRAM_ADDR" },
+ { 0x380, 0x20, "ETRAM_ADDR" },
+ { 0x400, 0, NULL }
+};
+
+static const struct emu10k1_reg_entry audigy_reg_entries[] = {
+ { 0, 0x40, "FXBUS" },
+ { 0x40, 0x10, "EXTIN" },
+ { 0x50, 0x10, "P16VIN" },
+ { 0x60, 0x20, "EXTOUT" },
+ { 0x80, 0x20, "FXBUS2" },
+ { 0xa0, 0x10, "EMU32OUTH" },
+ { 0xb0, 0x10, "EMU32OUTL" },
+ { 0xc0, 0x20, NULL }, // Constants
+ // This can't be quite right - overlap.
+ //{ 0x100, 0xc0, "ITRAM_CTL" },
+ //{ 0x1c0, 0x40, "ETRAM_CTL" },
+ { 0x160, 0x20, "A3_EMU32IN" },
+ { 0x1e0, 0x20, "A3_EMU32OUT" },
+ { 0x200, 0xc0, "ITRAM_DATA" },
+ { 0x2c0, 0x40, "ETRAM_DATA" },
+ { 0x300, 0xc0, "ITRAM_ADDR" },
+ { 0x3c0, 0x40, "ETRAM_ADDR" },
+ { 0x400, 0x200, "GPR" },
+ { 0x600, 0, NULL }
+};
+
+static const char * const emu10k1_const_entries[] = {
+ "C_00000000",
+ "C_00000001",
+ "C_00000002",
+ "C_00000003",
+ "C_00000004",
+ "C_00000008",
+ "C_00000010",
+ "C_00000020",
+ "C_00000100",
+ "C_00010000",
+ "C_00000800",
+ "C_10000000",
+ "C_20000000",
+ "C_40000000",
+ "C_80000000",
+ "C_7fffffff",
+ "C_ffffffff",
+ "C_fffffffe",
+ "C_c0000000",
+ "C_4f1bbcdc",
+ "C_5a7ef9db",
+ "C_00100000",
+ "GPR_ACCU",
+ "GPR_COND",
+ "GPR_NOISE0",
+ "GPR_NOISE1",
+ "GPR_IRQ",
+ "GPR_DBAC",
+ "GPR_DBACE",
+ "???",
+};
+
+static int disasm_emu10k1_reg(char *buffer,
+ const struct emu10k1_reg_entry *entries,
+ unsigned reg, const char *pfx)
+{
+ for (int i = 0; ; i++) {
+ unsigned base = entries[i].base;
+ unsigned size = entries[i].size;
+ if (!size)
+ return sprintf(buffer, "%s0x%03x", pfx, reg);
+ if (reg >= base && reg < base + size) {
+ const char *name = entries[i].name;
+ reg -= base;
+ if (name)
+ return sprintf(buffer, "%s%s(%u)", pfx, name, reg);
+ return sprintf(buffer, "%s%s", pfx, emu10k1_const_entries[reg]);
+ }
+ }
+}
+
+static int disasm_sblive_reg(char *buffer, unsigned reg, const char *pfx)
+{
+ return disasm_emu10k1_reg(buffer, sblive_reg_entries, reg, pfx);
+}
+
+static int disasm_audigy_reg(char *buffer, unsigned reg, const char *pfx)
+{
+ return disasm_emu10k1_reg(buffer, audigy_reg_entries, reg, pfx);
+}
+
+static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
u32 pc;
struct snd_emu10k1 *emu = entry->private_data;
+ static const char * const insns[16] = {
+ "MAC0", "MAC1", "MAC2", "MAC3", "MACINT0", "MACINT1", "ACC3", "MACMV",
+ "ANDXOR", "TSTNEG", "LIMITGE", "LIMITLT", "LOG", "EXP", "INTERP", "SKIP",
+ };
+ static const char spaces[] = " ";
+ const int nspaces = sizeof(spaces) - 1;
snd_iprintf(buffer, "FX8010 Instruction List '%s'\n", emu->fx8010.name);
snd_iprintf(buffer, " Code dump :\n");
for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) {
u32 low, high;
+ int len;
+ char buf[100];
+ char *bufp = buf;
low = snd_emu10k1_efx_read(emu, pc * 2);
high = snd_emu10k1_efx_read(emu, pc * 2 + 1);
- if (emu->audigy)
- snd_iprintf(buffer, " OP(0x%02x, 0x%03x, 0x%03x, 0x%03x, 0x%03x) /* 0x%04x: 0x%08x%08x */\n",
- (high >> 24) & 0x0f,
- (high >> 12) & 0x7ff,
- (high >> 0) & 0x7ff,
- (low >> 12) & 0x7ff,
- (low >> 0) & 0x7ff,
- pc,
- high, low);
- else
- snd_iprintf(buffer, " OP(0x%02x, 0x%03x, 0x%03x, 0x%03x, 0x%03x) /* 0x%04x: 0x%08x%08x */\n",
- (high >> 20) & 0x0f,
- (high >> 10) & 0x3ff,
- (high >> 0) & 0x3ff,
- (low >> 10) & 0x3ff,
- (low >> 0) & 0x3ff,
- pc,
- high, low);
+ if (emu->audigy) {
+ bufp += sprintf(bufp, " %-7s ", insns[(high >> 24) & 0x0f]);
+ bufp += disasm_audigy_reg(bufp, (high >> 12) & 0x7ff, "");
+ bufp += disasm_audigy_reg(bufp, (high >> 0) & 0x7ff, ", ");
+ bufp += disasm_audigy_reg(bufp, (low >> 12) & 0x7ff, ", ");
+ bufp += disasm_audigy_reg(bufp, (low >> 0) & 0x7ff, ", ");
+ } else {
+ bufp += sprintf(bufp, " %-7s ", insns[(high >> 20) & 0x0f]);
+ bufp += disasm_sblive_reg(bufp, (high >> 10) & 0x3ff, "");
+ bufp += disasm_sblive_reg(bufp, (high >> 0) & 0x3ff, ", ");
+ bufp += disasm_sblive_reg(bufp, (low >> 10) & 0x3ff, ", ");
+ bufp += disasm_sblive_reg(bufp, (low >> 0) & 0x3ff, ", ");
+ }
+ len = (int)(ptrdiff_t)(bufp - buf);
+ snd_iprintf(buffer, "%s %s /* 0x%04x: 0x%08x%08x */\n",
+ buf, &spaces[nspaces - clamp(65 - len, 0, nspaces)],
+ pc, high, low);
}
}
@@ -365,32 +429,78 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry,
struct snd_emu10k1 *emu = entry->private_data;
struct snd_emu10k1_voice *voice;
int idx;
-
- snd_iprintf(buffer, "ch\tuse\tpcm\tefx\tsynth\tmidi\n");
+ static const char * const types[] = {
+ "Unused", "EFX", "EFX IRQ", "PCM", "PCM IRQ", "Synth"
+ };
+ static_assert(ARRAY_SIZE(types) == EMU10K1_NUM_TYPES);
+
+ snd_iprintf(buffer, "ch\tdirty\tlast\tuse\n");
for (idx = 0; idx < NUM_G; idx++) {
voice = &emu->voices[idx];
- snd_iprintf(buffer, "%i\t%i\t%i\t%i\t%i\t%i\n",
+ snd_iprintf(buffer, "%i\t%u\t%u\t%s\n",
idx,
- voice->use,
- voice->pcm,
- voice->efx,
- voice->synth,
- voice->midi);
+ voice->dirty,
+ voice->last,
+ types[voice->use]);
}
}
#ifdef CONFIG_SND_DEBUG
+
+static void snd_emu_proc_emu1010_link_read(struct snd_emu10k1 *emu,
+ struct snd_info_buffer *buffer,
+ u32 dst)
+{
+ u32 src = snd_emu1010_fpga_link_dst_src_read(emu, dst);
+ snd_iprintf(buffer, "%04x: %04x\n", dst, src);
+}
+
static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_emu10k1 *emu = entry->private_data;
u32 value;
int i;
+
+ guard(snd_emu1010_fpga_lock)(emu);
+
snd_iprintf(buffer, "EMU1010 Registers:\n\n");
for(i = 0; i < 0x40; i+=1) {
snd_emu1010_fpga_read(emu, i, &value);
- snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f);
+ snd_iprintf(buffer, "%02x: %02x\n", i, value);
+ }
+
+ snd_iprintf(buffer, "\nEMU1010 Routes:\n\n");
+
+ for (i = 0; i < 16; i++) // To Alice2/Tina[2] via EMU32
+ snd_emu_proc_emu1010_link_read(emu, buffer, i);
+ if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404)
+ for (i = 0; i < 32; i++) // To Dock via EDI
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x100 + i);
+ if (emu->card_capabilities->emu_model != EMU_MODEL_EMU1616)
+ for (i = 0; i < 8; i++) // To Hamoa/local
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x200 + i);
+ for (i = 0; i < 8; i++) // To Hamoa/Mana/local
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x300 + i);
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
+ for (i = 0; i < 16; i++) // To Tina2 via EMU32
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x400 + i);
+ } else if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) {
+ for (i = 0; i < 8; i++) // To Hana ADAT
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x400 + i);
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010B) {
+ for (i = 0; i < 16; i++) // To Tina via EMU32
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x500 + i);
+ } else {
+ // To Alice2 via I2S
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x500);
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x501);
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x600);
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x601);
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x700);
+ snd_emu_proc_emu1010_link_read(emu, buffer, 0x701);
+ }
}
}
@@ -399,13 +509,10 @@ static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
{
struct snd_emu10k1 *emu = entry->private_data;
unsigned long value;
- unsigned long flags;
int i;
snd_iprintf(buffer, "IO Registers:\n\n");
for(i = 0; i < 0x40; i+=4) {
- spin_lock_irqsave(&emu->emu_lock, flags);
value = inl(emu->port + i);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
snd_iprintf(buffer, "%02X: %08lX\n", i, value);
}
}
@@ -414,16 +521,13 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_emu10k1 *emu = entry->private_data;
- unsigned long flags;
char line[64];
u32 reg, val;
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
if (reg < 0x40 && val <= 0xffffffff) {
- spin_lock_irqsave(&emu->emu_lock, flags);
outl(val, emu->port + (reg & 0xfffffffc));
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
}
}
@@ -433,16 +537,13 @@ static unsigned int snd_ptr_read(struct snd_emu10k1 * emu,
unsigned int reg,
unsigned int chn)
{
- unsigned long flags;
- unsigned int regptr, val;
+ unsigned int regptr;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irq)(&emu->emu_lock);
outl(regptr, emu->port + iobase + PTR);
- val = inl(emu->port + iobase + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inl(emu->port + iobase + DATA);
}
static void snd_ptr_write(struct snd_emu10k1 *emu,
@@ -452,14 +553,12 @@ static void snd_ptr_write(struct snd_emu10k1 *emu,
unsigned int data)
{
unsigned int regptr;
- unsigned long flags;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irq)(&emu->emu_lock);
outl(regptr, emu->port + iobase + PTR);
outl(data, emu->port + iobase + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
@@ -485,7 +584,8 @@ static void snd_emu_proc_ptr_reg_read(struct snd_info_entry *entry,
}
static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer, int iobase)
+ struct snd_info_buffer *buffer,
+ int iobase, int length, int voices)
{
struct snd_emu10k1 *emu = entry->private_data;
char line[64];
@@ -493,7 +593,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
continue;
- if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3)
+ if (reg < length && channel_id < voices)
snd_ptr_write(emu, iobase, reg, channel_id, val);
}
}
@@ -501,13 +601,15 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry,
static void snd_emu_proc_ptr_reg_write00(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- snd_emu_proc_ptr_reg_write(entry, buffer, 0);
+ snd_emu_proc_ptr_reg_write(entry, buffer, 0, 0x80, 64);
}
static void snd_emu_proc_ptr_reg_write20(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- snd_emu_proc_ptr_reg_write(entry, buffer, 0x20);
+ struct snd_emu10k1 *emu = entry->private_data;
+ snd_emu_proc_ptr_reg_write(entry, buffer, 0x20,
+ emu->card_capabilities->ca0108_chip ? 0xa0 : 0x80, 4);
}
@@ -563,15 +665,19 @@ int snd_emu10k1_proc_init(struct snd_emu10k1 *emu)
snd_card_rw_proc_new(emu->card, "ptr_regs00b", emu,
snd_emu_proc_ptr_reg_read00b,
snd_emu_proc_ptr_reg_write00);
- snd_card_rw_proc_new(emu->card, "ptr_regs20a", emu,
- snd_emu_proc_ptr_reg_read20a,
- snd_emu_proc_ptr_reg_write20);
- snd_card_rw_proc_new(emu->card, "ptr_regs20b", emu,
- snd_emu_proc_ptr_reg_read20b,
- snd_emu_proc_ptr_reg_write20);
- snd_card_rw_proc_new(emu->card, "ptr_regs20c", emu,
- snd_emu_proc_ptr_reg_read20c,
- snd_emu_proc_ptr_reg_write20);
+ if (!emu->card_capabilities->emu_model &&
+ (emu->card_capabilities->ca0151_chip || emu->card_capabilities->ca0108_chip)) {
+ snd_card_rw_proc_new(emu->card, "ptr_regs20a", emu,
+ snd_emu_proc_ptr_reg_read20a,
+ snd_emu_proc_ptr_reg_write20);
+ snd_card_rw_proc_new(emu->card, "ptr_regs20b", emu,
+ snd_emu_proc_ptr_reg_read20b,
+ snd_emu_proc_ptr_reg_write20);
+ if (emu->card_capabilities->ca0108_chip)
+ snd_card_rw_proc_new(emu->card, "ptr_regs20c", emu,
+ snd_emu_proc_ptr_reg_read20c,
+ snd_emu_proc_ptr_reg_write20);
+ }
#endif
snd_card_ro_proc_new(emu->card, "emu10k1", emu, snd_emu10k1_proc_read);
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index cfb96a67aa35..9c897c3e8c28 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -1,14 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Lee Revell <rlrevell@joe-job.com>
+ * James Courtier-Dutton <James@superbug.co.uk>
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
* Creative Labs, Inc.
- * Routines for control of EMU10K1 chips
- *
- * BUGS:
- * --
*
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips
*/
#include <linux/time.h>
@@ -18,33 +16,41 @@
#include <linux/export.h>
#include "p17v.h"
+static inline bool check_ptr_reg(struct snd_emu10k1 *emu, unsigned int reg)
+{
+ if (snd_BUG_ON(!emu))
+ return false;
+ if (snd_BUG_ON(reg & (emu->audigy ? (0xffff0000 & ~A_PTR_ADDRESS_MASK)
+ : (0xffff0000 & ~PTR_ADDRESS_MASK))))
+ return false;
+ if (snd_BUG_ON(reg & 0x0000ffff & ~PTR_CHANNELNUM_MASK))
+ return false;
+ return true;
+}
+
unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
{
- unsigned long flags;
unsigned int regptr, val;
unsigned int mask;
- mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
- regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
+ regptr = (reg << 16) | chn;
+ if (!check_ptr_reg(emu, regptr))
+ return 0;
+
+ scoped_guard(spinlock_irqsave, &emu->emu_lock) {
+ outl(regptr, emu->port + PTR);
+ val = inl(emu->port + DATA);
+ }
if (reg & 0xff000000) {
unsigned char size, offset;
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
- outl(regptr, emu->port + PTR);
- val = inl(emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ mask = (1 << size) - 1;
- return (val & mask) >> offset;
+ return (val >> offset) & mask;
} else {
- spin_lock_irqsave(&emu->emu_lock, flags);
- outl(regptr, emu->port + PTR);
- val = inl(emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
return val;
}
}
@@ -54,51 +60,74 @@ EXPORT_SYMBOL(snd_emu10k1_ptr_read);
void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
{
unsigned int regptr;
- unsigned long flags;
unsigned int mask;
- if (snd_BUG_ON(!emu))
+ regptr = (reg << 16) | chn;
+ if (!check_ptr_reg(emu, regptr))
return;
- mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
- regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (reg & 0xff000000) {
unsigned char size, offset;
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
- data = (data << offset) & mask;
+ mask = (1 << size) - 1;
+ if (snd_BUG_ON(data & ~mask))
+ return;
+ mask <<= offset;
+ data <<= offset;
- spin_lock_irqsave(&emu->emu_lock, flags);
outl(regptr, emu->port + PTR);
data |= inl(emu->port + DATA) & ~mask;
- outl(data, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
} else {
- spin_lock_irqsave(&emu->emu_lock, flags);
outl(regptr, emu->port + PTR);
- outl(data, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
+ outl(data, emu->port + DATA);
}
EXPORT_SYMBOL(snd_emu10k1_ptr_write);
+void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, ...)
+{
+ va_list va;
+ u32 addr_mask;
+
+ if (snd_BUG_ON(!emu))
+ return;
+ if (snd_BUG_ON(chn & ~PTR_CHANNELNUM_MASK))
+ return;
+ addr_mask = ~((emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK) >> 16);
+
+ va_start(va, chn);
+ guard(spinlock_irqsave)(&emu->emu_lock);
+ for (;;) {
+ u32 data;
+ u32 reg = va_arg(va, u32);
+ if (reg == REGLIST_END)
+ break;
+ data = va_arg(va, u32);
+ if (snd_BUG_ON(reg & addr_mask)) // Only raw registers supported here
+ continue;
+ outl((reg << 16) | chn, emu->port + PTR);
+ outl(data, emu->port + DATA);
+ }
+ va_end(va);
+}
+
+EXPORT_SYMBOL(snd_emu10k1_ptr_write_multiple);
+
unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
unsigned int reg,
unsigned int chn)
{
- unsigned long flags;
- unsigned int regptr, val;
+ unsigned int regptr;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(regptr, emu->port + PTR2);
- val = inl(emu->port + DATA2);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inl(emu->port + DATA2);
}
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
@@ -107,14 +136,12 @@ void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
unsigned int data)
{
unsigned int regptr;
- unsigned long flags;
regptr = (reg << 16) | chn;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outl(regptr, emu->port + PTR2);
outl(data, emu->port + DATA2);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
@@ -123,22 +150,19 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
unsigned int reset, set;
unsigned int reg, tmp;
int n, result;
- int err = 0;
/* This function is not re-entrant, so protect against it. */
- spin_lock(&emu->spi_lock);
+ guard(spinlock)(&emu->spi_lock);
if (emu->card_capabilities->ca0108_chip)
reg = P17V_SPI;
else {
/* For other chip types the SPI register
* is currently unknown. */
- err = 1;
- goto spi_write_exit;
+ return 1;
}
if (data > 0xffff) {
/* Only 16bit values allowed */
- err = 1;
- goto spi_write_exit;
+ return 1;
}
tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
@@ -159,15 +183,11 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
}
if (result) {
/* Timed out */
- err = 1;
- goto spi_write_exit;
+ return 1;
}
snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
- err = 0;
-spi_write_exit:
- spin_unlock(&emu->spi_lock);
- return err;
+ return 0;
}
/* The ADC does not support i2c read, so only write is implemented */
@@ -179,7 +199,6 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
int timeout = 0;
int status;
int retry;
- int err = 0;
if ((reg > 0x7f) || (value > 0x1ff)) {
dev_err(emu->card->dev, "i2c_write: invalid values.\n");
@@ -187,7 +206,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
}
/* This function is not re-entrant, so protect against it. */
- spin_lock(&emu->i2c_lock);
+ guard(spinlock)(&emu->i2c_lock);
tmp = reg << 25 | value << 16;
@@ -226,23 +245,19 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
status, reg, value);
/* dump_stack(); */
- err = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&emu->i2c_lock);
- return err;
+ return 0;
}
-void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
+static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 value)
{
- unsigned long flags;
-
if (snd_BUG_ON(reg > 0x3f))
return;
reg += 0x40; /* 0x40 upwards are registers. */
if (snd_BUG_ON(value > 0x3f)) /* 0 to 0x3f are values */
return;
- spin_lock_irqsave(&emu->emu_lock, flags);
outw(reg, emu->port + A_GPIO);
udelay(10);
outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */
@@ -250,25 +265,40 @@ void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
outw(value, emu->port + A_GPIO);
udelay(10);
outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */
- spin_unlock_irqrestore(&emu->emu_lock, flags);
+ udelay(10);
+}
+
+void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
+{
+ if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
+ return;
+ snd_emu1010_fpga_write_locked(emu, reg, value);
+}
+
+void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value)
+{
+ guard(snd_emu1010_fpga_lock)(emu);
+ snd_emu1010_fpga_write_locked(emu, reg, value);
}
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
{
// The higest input pin is used as the designated interrupt trigger,
// so it needs to be masked out.
+ // But note that any other input pin change will also cause an IRQ,
+ // so using this function often causes an IRQ as a side effect.
u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f;
- unsigned long flags;
+
+ if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
+ return;
if (snd_BUG_ON(reg > 0x3f))
return;
reg += 0x40; /* 0x40 upwards are registers. */
- spin_lock_irqsave(&emu->emu_lock, flags);
outw(reg, emu->port + A_GPIO);
udelay(10);
outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */
udelay(10);
*value = ((inw(emu->port + A_GPIO) >> 8) & mask);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
/* Each Destination has one and only one Source,
@@ -286,34 +316,167 @@ void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 s
snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f);
}
+u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst)
+{
+ u32 hi, lo;
+
+ if (snd_BUG_ON(dst & ~0x71f))
+ return 0;
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
+ snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SRCHI, &hi);
+ snd_emu1010_fpga_read(emu, EMU_HANA_SRCLO, &lo);
+ return (hi << 8) | lo;
+}
+
+int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src)
+{
+ u32 reg_lo, reg_hi, value, value2;
+
+ switch (src) {
+ case EMU_HANA_WCLOCK_HANA_SPDIF_IN:
+ snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value);
+ if (value & EMU_HANA_SPDIF_MODE_RX_INVALID)
+ return 0;
+ reg_lo = EMU_HANA_WC_SPDIF_LO;
+ reg_hi = EMU_HANA_WC_SPDIF_HI;
+ break;
+ case EMU_HANA_WCLOCK_HANA_ADAT_IN:
+ reg_lo = EMU_HANA_WC_ADAT_LO;
+ reg_hi = EMU_HANA_WC_ADAT_HI;
+ break;
+ case EMU_HANA_WCLOCK_SYNC_BNC:
+ reg_lo = EMU_HANA_WC_BNC_LO;
+ reg_hi = EMU_HANA_WC_BNC_HI;
+ break;
+ case EMU_HANA_WCLOCK_2ND_HANA:
+ reg_lo = EMU_HANA2_WC_SPDIF_LO;
+ reg_hi = EMU_HANA2_WC_SPDIF_HI;
+ break;
+ default:
+ return 0;
+ }
+ snd_emu1010_fpga_read(emu, reg_hi, &value);
+ snd_emu1010_fpga_read(emu, reg_lo, &value2);
+ // FIXME: The /4 is valid for 0404b, but contradicts all other info.
+ return 0x1770000 / 4 / (((value << 5) | value2) + 1);
+}
+
+void snd_emu1010_update_clock(struct snd_emu10k1 *emu)
+{
+ int clock;
+ u32 leds;
+
+ switch (emu->emu1010.wclock) {
+ case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X:
+ clock = 44100;
+ leds = EMU_HANA_DOCK_LEDS_2_44K;
+ break;
+ case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X:
+ clock = 48000;
+ leds = EMU_HANA_DOCK_LEDS_2_48K;
+ break;
+ default:
+ clock = snd_emu1010_get_raw_rate(
+ emu, emu->emu1010.wclock & EMU_HANA_WCLOCK_SRC_MASK);
+ // The raw rate reading is rather coarse (it cannot accurately
+ // represent 44.1 kHz) and fluctuates slightly. Luckily, the
+ // clock comes from digital inputs, which use standardized rates.
+ // So we round to the closest standard rate and ignore discrepancies.
+ if (clock < 46000) {
+ clock = 44100;
+ leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_44K;
+ } else {
+ clock = 48000;
+ leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_48K;
+ }
+ break;
+ }
+ emu->emu1010.word_clock = clock;
+
+ // FIXME: this should probably represent the AND of all currently
+ // used sources' lock status. But we don't know how to get that ...
+ leds |= EMU_HANA_DOCK_LEDS_2_LOCK;
+
+ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, leds);
+}
+
+void snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, int dock,
+ const struct firmware *fw_entry)
+{
+ __always_unused u16 write_post;
+
+ // On E-MU 1010 rev1 the FPGA is a Xilinx Spartan IIE XC2S50E.
+ // On E-MU 0404b it is a Xilinx Spartan III XC3S50.
+ // The wiring is as follows:
+ // GPO7 -> FPGA input & 1K resistor -> FPGA /PGMN <- FPGA output
+ // In normal operation, the active low reset line is held up by
+ // an FPGA output, while the GPO pin performs its duty as control
+ // register access strobe signal. Writing the respective bit to
+ // EMU_HANA_FPGA_CONFIG puts the FPGA output into high-Z mode, at
+ // which point the GPO pin can control the reset line through the
+ // resistor.
+ // GPO6 -> FPGA CCLK & FPGA input
+ // GPO5 -> FPGA DIN (dual function)
+
+ // If the FPGA is already programmed, return it to programming mode
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ dock ? EMU_HANA_FPGA_CONFIG_AUDIODOCK :
+ EMU_HANA_FPGA_CONFIG_HANA);
+
+ // Assert reset line for 100uS
+ outw(0x00, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ udelay(100);
+ outw(0x80, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ udelay(100); // Allow FPGA memory to clean
+
+ // Upload the netlist. Keep reset line high!
+ for (int n = 0; n < fw_entry->size; n++) {
+ u8 value = fw_entry->data[n];
+ for (int i = 0; i < 8; i++) {
+ u16 reg = 0x80;
+ if (value & 1)
+ reg |= 0x20;
+ value >>= 1;
+ outw(reg, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ outw(reg | 0x40, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+ }
+ }
+
+ // After programming, set GPIO bit 4 high again.
+ // This appears to be a config word that the rev1 Hana
+ // firmware reads; weird things happen without this.
+ outw(0x10, emu->port + A_GPIO);
+ write_post = inw(emu->port + A_GPIO);
+}
+
void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
enable = inl(emu->port + INTE) | intrenb;
outl(enable, emu->port + INTE);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
enable = inl(emu->port + INTE) & ~intrenb;
outl(enable, emu->port + INTE);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
unsigned int val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(CLIEH << 16, emu->port + PTR);
val = inl(emu->port + DATA);
@@ -324,15 +487,13 @@ void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenu
val |= 1 << voicenum;
}
outl(val, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
unsigned int val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(CLIEH << 16, emu->port + PTR);
val = inl(emu->port + DATA);
@@ -343,14 +504,11 @@ void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicen
val &= ~(1 << voicenum);
}
outl(val, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(CLIPH << 16, emu->port + PTR);
voicenum = 1 << (voicenum - 32);
@@ -359,15 +517,13 @@ void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
voicenum = 1 << voicenum;
}
outl(voicenum, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
unsigned int val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(HLIEH << 16, emu->port + PTR);
val = inl(emu->port + DATA);
@@ -378,15 +534,13 @@ void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned i
val |= 1 << voicenum;
}
outl(val, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
unsigned int val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(HLIEH << 16, emu->port + PTR);
val = inl(emu->port + DATA);
@@ -397,14 +551,11 @@ void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned
val &= ~(1 << voicenum);
}
outl(val, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
-
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(HLIPH << 16, emu->port + PTR);
voicenum = 1 << (voicenum - 32);
@@ -413,15 +564,14 @@ void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int
voicenum = 1 << voicenum;
}
outl(voicenum, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
+#if 0
void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
unsigned int sol;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(SOLEH << 16, emu->port + PTR);
sol = inl(emu->port + DATA);
@@ -432,15 +582,13 @@ void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voice
sol |= 1 << voicenum;
}
outl(sol, emu->port + DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
{
- unsigned long flags;
unsigned int sol;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
if (voicenum >= 32) {
outl(SOLEH << 16, emu->port + PTR);
sol = inl(emu->port + DATA);
@@ -451,7 +599,83 @@ void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voi
sol &= ~(1 << voicenum);
}
outl(sol, emu->port + DATA);
+}
+#endif
+
+void snd_emu10k1_voice_set_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices)
+{
+ guard(spinlock_irqsave)(&emu->emu_lock);
+ outl(SOLEL << 16, emu->port + PTR);
+ outl(inl(emu->port + DATA) | (u32)voices, emu->port + DATA);
+ outl(SOLEH << 16, emu->port + PTR);
+ outl(inl(emu->port + DATA) | (u32)(voices >> 32), emu->port + DATA);
+}
+
+void snd_emu10k1_voice_clear_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices)
+{
+ guard(spinlock_irqsave)(&emu->emu_lock);
+ outl(SOLEL << 16, emu->port + PTR);
+ outl(inl(emu->port + DATA) & (u32)~voices, emu->port + DATA);
+ outl(SOLEH << 16, emu->port + PTR);
+ outl(inl(emu->port + DATA) & (u32)(~voices >> 32), emu->port + DATA);
+}
+
+int snd_emu10k1_voice_clear_loop_stop_multiple_atomic(struct snd_emu10k1 *emu, u64 voices)
+{
+ unsigned long flags;
+ u32 soll, solh;
+ int ret = -EIO;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+
+ outl(SOLEL << 16, emu->port + PTR);
+ soll = inl(emu->port + DATA);
+ outl(SOLEH << 16, emu->port + PTR);
+ solh = inl(emu->port + DATA);
+
+ soll &= (u32)~voices;
+ solh &= (u32)(~voices >> 32);
+
+ for (int tries = 0; tries < 1000; tries++) {
+ const u32 quart = 1U << (REG_SIZE(WC_CURRENTCHANNEL) - 2);
+ // First we wait for the third quarter of the sample cycle ...
+ u32 wc = inl(emu->port + WC);
+ u32 cc = REG_VAL_GET(WC_CURRENTCHANNEL, wc);
+ if (cc >= quart * 2 && cc < quart * 3) {
+ // ... and release the low voices, while the high ones are serviced.
+ outl(SOLEL << 16, emu->port + PTR);
+ outl(soll, emu->port + DATA);
+ // Then we wait for the first quarter of the next sample cycle ...
+ for (; tries < 1000; tries++) {
+ cc = REG_VAL_GET(WC_CURRENTCHANNEL, inl(emu->port + WC));
+ if (cc < quart)
+ goto good;
+ // We will block for 10+ us with interrupts disabled. This is
+ // not nice at all, but necessary for reasonable reliability.
+ udelay(1);
+ }
+ break;
+ good:
+ // ... and release the high voices, while the low ones are serviced.
+ outl(SOLEH << 16, emu->port + PTR);
+ outl(solh, emu->port + DATA);
+ // Finally we verify that nothing interfered in fact.
+ if (REG_VAL_GET(WC_SAMPLECOUNTER, inl(emu->port + WC)) ==
+ ((REG_VAL_GET(WC_SAMPLECOUNTER, wc) + 1) & REG_MASK0(WC_SAMPLECOUNTER))) {
+ ret = 0;
+ } else {
+ ret = -EAGAIN;
+ }
+ break;
+ }
+ // Don't block for too long
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ udelay(1);
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ }
+
spin_unlock_irqrestore(&emu->emu_lock, flags);
+ return ret;
}
void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
@@ -476,84 +700,17 @@ void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
struct snd_emu10k1 *emu = ac97->private_data;
- unsigned long flags;
- unsigned short val;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outb(reg, emu->port + AC97ADDRESS);
- val = inw(emu->port + AC97DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
- return val;
+ return inw(emu->port + AC97DATA);
}
void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
{
struct snd_emu10k1 *emu = ac97->private_data;
- unsigned long flags;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
outb(reg, emu->port + AC97ADDRESS);
outw(data, emu->port + AC97DATA);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
-}
-
-/*
- * convert rate to pitch
- */
-
-unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
-{
- static const u32 logMagTable[128] = {
- 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
- 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
- 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
- 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
- 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
- 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
- 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
- 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
- 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
- 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
- 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
- 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
- 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
- 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
- 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
- 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
- };
- static const char logSlopeTable[128] = {
- 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
- 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
- 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
- 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
- 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
- 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
- 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
- 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
- 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
- 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
- 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
- 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
- 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
- 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
- };
- int i;
-
- if (rate == 0)
- return 0; /* Bail out if no leading "1" */
- rate *= 11185; /* Scale 48000 to 0x20002380 */
- for (i = 31; i > 0; i--) {
- if (rate & 0x80000000) { /* Detect leading "1" */
- return (((unsigned int) (i - 15) << 20) +
- logMagTable[0x7f & (rate >> 24)] +
- (0x7f & (rate >> 17)) *
- logSlopeTable[0x7f & (rate >> 24)]);
- }
- rate <<= 1;
- }
-
- return 0; /* Should never reach this point */
}
-
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c
index dfb44e5e69a7..71aa90b9cc88 100644
--- a/sound/pci/emu10k1/irq.c
+++ b/sound/pci/emu10k1/irq.c
@@ -3,12 +3,6 @@
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Creative Labs, Inc.
* Routines for IRQ control of EMU10K1 chips
- *
- * BUGS:
- * --
- *
- * TODO:
- * --
*/
#include <linux/time.h>
@@ -22,15 +16,18 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
int handled = 0;
int timeout = 0;
- while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
- timeout++;
- orig_status = status;
+ while ((status = inl(emu->port + IPR)) != 0) {
handled = 1;
if ((status & 0xffffffff) == 0xffffffff) {
dev_info(emu->card->dev,
"Suspected sound card removal\n");
break;
}
+ if (++timeout == 1000) {
+ dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
+ break;
+ }
+ orig_status = status;
if (status & IPR_PCIERROR) {
dev_err(emu->card->dev, "interrupt: PCI error\n");
snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
@@ -44,12 +41,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
}
if (status & IPR_CHANNELLOOP) {
+ struct snd_emu10k1_voice *pvoice;
int voice;
int voice_max = status & IPR_CHANNELNUMBERMASK;
u32 val;
- struct snd_emu10k1_voice *pvoice = emu->voices;
val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
+ pvoice = emu->voices;
for (voice = 0; voice <= voice_max; voice++) {
if (voice == 0x20)
val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
@@ -65,6 +63,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
pvoice++;
}
val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
+ pvoice = emu->voices;
for (voice = 0; voice <= voice_max; voice++) {
if (voice == 0x20)
val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
@@ -79,9 +78,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
val >>= 1;
pvoice++;
}
- status &= ~IPR_CHANNELLOOP;
+ status &= ~(IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK);
}
- status &= ~IPR_CHANNELNUMBERMASK;
if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
if (emu->capture_interrupt)
emu->capture_interrupt(emu, status);
@@ -145,33 +143,20 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
outl(0, emu->port + INTE2);
status &= ~IPR_P16V;
}
+ if (status & IPR_A_GPIO) {
+ if (emu->gpio_interrupt)
+ emu->gpio_interrupt(emu);
+ else
+ snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE);
+ status &= ~IPR_A_GPIO;
+ }
if (status) {
- unsigned int bits;
dev_err(emu->card->dev,
"unhandled interrupt: 0x%08x\n", status);
- //make sure any interrupts we don't handle are disabled:
- bits = INTE_FXDSPENABLE |
- INTE_PCIERRORENABLE |
- INTE_VOLINCRENABLE |
- INTE_VOLDECRENABLE |
- INTE_MUTEENABLE |
- INTE_MICBUFENABLE |
- INTE_ADCBUFENABLE |
- INTE_EFXBUFENABLE |
- INTE_GPSPDIFENABLE |
- INTE_CDSPDIFENABLE |
- INTE_INTERVALTIMERENB |
- INTE_MIDITXENABLE |
- INTE_MIDIRXENABLE;
- if (emu->audigy)
- bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
- snd_emu10k1_intr_disable(emu, bits);
}
outl(orig_status, emu->port + IPR); /* ack all */
}
- if (timeout == 1000)
- dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
return IRQ_RETVAL(handled);
}
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index edb3f1763719..be889a4ccf9a 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -261,14 +261,12 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b
int size;
struct list_head *p, *nextp;
struct snd_emu10k1_memblk *deleted;
- unsigned long flags;
- spin_lock_irqsave(&emu->memblk_lock, flags);
+ guard(spinlock_irqsave)(&emu->memblk_lock);
if (blk->mapped_page >= 0) {
/* update order link */
list_move_tail(&blk->mapped_order_link,
&emu->mapped_order_link_head);
- spin_unlock_irqrestore(&emu->memblk_lock, flags);
return 0;
}
err = map_memblk(emu, blk);
@@ -289,7 +287,6 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b
}
}
}
- spin_unlock_irqrestore(&emu->memblk_lock, flags);
return err;
}
@@ -315,14 +312,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
if (snd_BUG_ON(!hdr))
return NULL;
- idx = runtime->period_size >= runtime->buffer_size ?
- (emu->delay_pcm_irq * 2) : 0;
- mutex_lock(&hdr->block_mutex);
- blk = search_empty(emu, runtime->dma_bytes + idx);
- if (blk == NULL) {
- mutex_unlock(&hdr->block_mutex);
+ guard(mutex)(&hdr->block_mutex);
+ blk = search_empty(emu, runtime->dma_bytes);
+ if (blk == NULL)
return NULL;
- }
/* fill buffer addresses but pointers are not stored so that
* snd_free_pci_page() is not called in synth_free()
*/
@@ -337,7 +330,6 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
if (! is_valid_page(emu, addr)) {
dev_err_ratelimited(emu->card->dev,
"emu: failure page = %d\n", idx);
- mutex_unlock(&hdr->block_mutex);
return NULL;
}
emu->page_addr_table[page] = addr;
@@ -349,10 +341,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
err = snd_emu10k1_memblk_map(emu, blk);
if (err < 0) {
__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);
- mutex_unlock(&hdr->block_mutex);
return NULL;
}
- mutex_unlock(&hdr->block_mutex);
return (struct snd_util_memblk *)blk;
}
@@ -409,19 +399,15 @@ snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size)
struct snd_emu10k1_memblk *blk;
struct snd_util_memhdr *hdr = hw->memhdr;
- mutex_lock(&hdr->block_mutex);
+ guard(mutex)(&hdr->block_mutex);
blk = (struct snd_emu10k1_memblk *)__snd_util_mem_alloc(hdr, size);
- if (blk == NULL) {
- mutex_unlock(&hdr->block_mutex);
+ if (blk == NULL)
return NULL;
- }
if (synth_alloc_pages(hw, blk)) {
__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);
- mutex_unlock(&hdr->block_mutex);
return NULL;
}
snd_emu10k1_memblk_map(hw, blk);
- mutex_unlock(&hdr->block_mutex);
return (struct snd_util_memblk *)blk;
}
@@ -435,16 +421,14 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk)
{
struct snd_util_memhdr *hdr = emu->memhdr;
struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk;
- unsigned long flags;
- mutex_lock(&hdr->block_mutex);
- spin_lock_irqsave(&emu->memblk_lock, flags);
- if (blk->mapped_page >= 0)
- unmap_memblk(emu, blk);
- spin_unlock_irqrestore(&emu->memblk_lock, flags);
+ guard(mutex)(&hdr->block_mutex);
+ scoped_guard(spinlock_irqsave, &emu->memblk_lock) {
+ if (blk->mapped_page >= 0)
+ unmap_memblk(emu, blk);
+ }
synth_free_pages(emu, blk);
- __snd_util_mem_free(hdr, memblk);
- mutex_unlock(&hdr->block_mutex);
+ __snd_util_mem_free(hdr, memblk);
return 0;
}
@@ -567,15 +551,18 @@ static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset)
}
/*
- * bzero(blk + offset, size)
+ * memset(blk + offset, value, size)
*/
-int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,
- int offset, int size)
+int snd_emu10k1_synth_memset(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,
+ int offset, int size, u8 value)
{
int page, nextofs, end_offset, temp, temp1;
void *ptr;
struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk;
+ if (snd_BUG_ON(offset + size > p->mem.size))
+ return -EFAULT;
+
offset += blk->offset & (PAGE_SIZE - 1);
end_offset = offset + size;
page = get_aligned_page(offset);
@@ -587,25 +574,55 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk
temp = temp1;
ptr = offset_ptr(emu, page + p->first_page, offset);
if (ptr)
- memset(ptr, 0, temp);
+ memset(ptr, value, temp);
offset = nextofs;
page++;
} while (offset < end_offset);
return 0;
}
-EXPORT_SYMBOL(snd_emu10k1_synth_bzero);
+EXPORT_SYMBOL(snd_emu10k1_synth_memset);
+
+// Note that the value is assumed to be suitably repetitive.
+static void xor_range(void *ptr, int size, u32 value)
+{
+ if ((long)ptr & 1) {
+ *(u8 *)ptr ^= (u8)value;
+ ptr++;
+ size--;
+ }
+ if (size > 1 && ((long)ptr & 2)) {
+ *(u16 *)ptr ^= (u16)value;
+ ptr += 2;
+ size -= 2;
+ }
+ while (size > 3) {
+ *(u32 *)ptr ^= value;
+ ptr += 4;
+ size -= 4;
+ }
+ if (size > 1) {
+ *(u16 *)ptr ^= (u16)value;
+ ptr += 2;
+ size -= 2;
+ }
+ if (size > 0)
+ *(u8 *)ptr ^= (u8)value;
+}
/*
- * copy_from_user(blk + offset, data, size)
+ * copy_from_user(blk + offset, data, size) ^ xor
*/
int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,
- int offset, const char __user *data, int size)
+ int offset, const char __user *data, int size, u32 xor)
{
int page, nextofs, end_offset, temp, temp1;
void *ptr;
struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk;
+ if (snd_BUG_ON(offset + size > p->mem.size))
+ return -EFAULT;
+
offset += blk->offset & (PAGE_SIZE - 1);
end_offset = offset + size;
page = get_aligned_page(offset);
@@ -616,8 +633,12 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me
if (temp1 < temp)
temp = temp1;
ptr = offset_ptr(emu, page + p->first_page, offset);
- if (ptr && copy_from_user(ptr, data, temp))
- return -EFAULT;
+ if (ptr) {
+ if (copy_from_user(ptr, data, temp))
+ return -EFAULT;
+ if (xor)
+ xor_range(ptr, temp, xor);
+ }
offset = nextofs;
data += temp;
page++;
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index e7f097cae574..b74128e61254 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -174,11 +174,6 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
if (err < 0)
return err;
- runtime->sync.id32[0] = substream->pcm->card->number;
- runtime->sync.id32[1] = 'P';
- runtime->sync.id32[2] = 16;
- runtime->sync.id32[3] = 'V';
-
return 0;
}
@@ -226,6 +221,17 @@ static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream)
return snd_p16v_pcm_open_capture_channel(substream, 0);
}
+static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) {
+ static const unsigned char id[4] = { 'P', '1', '6', 'V' };
+ snd_pcm_set_sync_per_card(substream, arg, id, 4);
+ return 0;
+ }
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
/* prepare playback callback */
static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
{
@@ -336,24 +342,20 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)
static void snd_p16v_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int enable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
enable = inl(emu->port + INTE2) | intrenb;
outl(enable, emu->port + INTE2);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_p16v_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
{
- unsigned long flags;
unsigned int disable;
- spin_lock_irqsave(&emu->emu_lock, flags);
+ guard(spinlock_irqsave)(&emu->emu_lock);
disable = inl(emu->port + INTE2) & (~intrenb);
outl(disable, emu->port + INTE2);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static void snd_p16v_interrupt(struct snd_emu10k1 *emu)
@@ -531,6 +533,7 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops snd_p16v_playback_front_ops = {
.open = snd_p16v_pcm_open_playback_front,
.close = snd_p16v_pcm_close_playback,
+ .ioctl = snd_p16v_pcm_ioctl_playback,
.prepare = snd_p16v_pcm_prepare_playback,
.trigger = snd_p16v_pcm_trigger_playback,
.pointer = snd_p16v_pcm_pointer_playback,
@@ -566,7 +569,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
- strcpy(pcm->name, "p16v");
+ strscpy(pcm->name, "p16v");
emu->pcm_p16v = pcm;
emu->p16v_interrupt = snd_p16v_interrupt;
diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h
index 9d429ad1feff..95ab8071751b 100644
--- a/sound/pci/emu10k1/p16v.h
+++ b/sound/pci/emu10k1/p16v.h
@@ -2,62 +2,6 @@
/*
* Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver p16v chips
- * Version: 0.21
- *
- * FEATURES currently supported:
- * Output fixed at S32_LE, 2 channel to hw:0,0
- * Rates: 44.1, 48, 96, 192.
- *
- * Changelog:
- * 0.8
- * Use separate card based buffer for periods table.
- * 0.9
- * Use 2 channel output streams instead of 8 channel.
- * (8 channel output streams might be good for ASIO type output)
- * Corrected speaker output, so Front -> Front etc.
- * 0.10
- * Fixed missed interrupts.
- * 0.11
- * Add Sound card model number and names.
- * Add Analog volume controls.
- * 0.12
- * Corrected playback interrupts. Now interrupt per period, instead of half period.
- * 0.13
- * Use single trigger for multichannel.
- * 0.14
- * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo.
- * 0.15
- * Force buffer_size / period_size == INTEGER.
- * 0.16
- * Update p16v.c to work with changed alsa api.
- * 0.17
- * Update p16v.c to work with changed alsa api. Removed boot_devs.
- * 0.18
- * Merging with snd-emu10k1 driver.
- * 0.19
- * One stereo channel at 24bit now works.
- * 0.20
- * Added better register defines.
- * 0.21
- * Split from p16v.c
- *
- * BUGS:
- * Some stability problems when unloading the snd-p16v kernel module.
- * --
- *
- * TODO:
- * SPDIF out.
- * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz.
- * Currently capture fixed at 48000Hz.
- *
- * --
- * GENERAL INFO:
- * Model: SB0240
- * P16V Chip: CA0151-DBS
- * Audigy 2 Chip: CA0102-IAT
- * AC97 Codec: STAC 9721
- * ADC: Philips 1361T (Stereo 24bit)
- * DAC: CS4382-K (8-channel, 24bit, 192Khz)
*
* This code was initially based on code from ALSA's emu10k1x.c which is:
* Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h
index d4ada1c430c8..ee4f4ab4b79c 100644
--- a/sound/pci/emu10k1/p17v.h
+++ b/sound/pci/emu10k1/p17v.h
@@ -2,7 +2,6 @@
/*
* Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver p17v chips
- * Version: 0.01
*/
/******************************************************************************/
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c
index 2435d3ba68f7..1231ae2bf931 100644
--- a/sound/pci/emu10k1/timer.c
+++ b/sound/pci/emu10k1/timer.c
@@ -2,13 +2,9 @@
/*
* Copyright (c) by Lee Revell <rlrevell@joe-job.com>
* Clemens Ladisch <clemens@ladisch.de>
- * Routines for control of EMU10K1 chips
- *
- * BUGS:
- * --
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
*
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips
*/
#include <linux/time.h>
@@ -18,46 +14,56 @@
static int snd_emu10k1_timer_start(struct snd_timer *timer)
{
struct snd_emu10k1 *emu;
- unsigned long flags;
unsigned int delay;
emu = snd_timer_chip(timer);
delay = timer->sticks - 1;
if (delay < 5 ) /* minimum time is 5 ticks */
delay = 5;
- spin_lock_irqsave(&emu->reg_lock, flags);
snd_emu10k1_intr_enable(emu, INTE_INTERVALTIMERENB);
outw(delay & TIMER_RATE_MASK, emu->port + TIMER);
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
static int snd_emu10k1_timer_stop(struct snd_timer *timer)
{
struct snd_emu10k1 *emu;
- unsigned long flags;
emu = snd_timer_chip(timer);
- spin_lock_irqsave(&emu->reg_lock, flags);
snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
- spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
+static unsigned long snd_emu10k1_timer_c_resolution(struct snd_timer *timer)
+{
+ struct snd_emu10k1 *emu = snd_timer_chip(timer);
+
+ if (emu->card_capabilities->emu_model &&
+ emu->emu1010.word_clock == 44100)
+ return 22676; // 1 sample @ 44.1 kHz = 22.675736...us
+ else
+ return 20833; // 1 sample @ 48 kHz = 20.833...us
+}
+
static int snd_emu10k1_timer_precise_resolution(struct snd_timer *timer,
unsigned long *num, unsigned long *den)
{
+ struct snd_emu10k1 *emu = snd_timer_chip(timer);
+
*num = 1;
- *den = 48000;
+ if (emu->card_capabilities->emu_model)
+ *den = emu->emu1010.word_clock;
+ else
+ *den = 48000;
return 0;
}
static const struct snd_timer_hardware snd_emu10k1_timer_hw = {
.flags = SNDRV_TIMER_HW_AUTO,
- .resolution = 20833, /* 1 sample @ 48KHZ = 20.833...us */
.ticks = 1024,
.start = snd_emu10k1_timer_start,
.stop = snd_emu10k1_timer_stop,
+ .c_resolution = snd_emu10k1_timer_c_resolution,
.precise_resolution = snd_emu10k1_timer_precise_resolution,
};
@@ -74,7 +80,7 @@ int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device)
tid.subdevice = 0;
err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer);
if (err >= 0) {
- strcpy(timer->name, "EMU10K1 timer");
+ strscpy(timer->name, "EMU10K1 timer");
timer->private_data = emu;
timer->hw = snd_emu10k1_timer_hw;
}
diff --git a/sound/pci/emu10k1/tina2.h b/sound/pci/emu10k1/tina2.h
index 7fd235345292..e3fcb290271c 100644
--- a/sound/pci/emu10k1/tina2.h
+++ b/sound/pci/emu10k1/tina2.h
@@ -2,7 +2,6 @@
/*
* Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
* Driver tina2 chips
- * Version: 0.1
*/
/********************************************************************************************************/
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index cbeb8443492c..7fe1d1727768 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -1,17 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- * Creative Labs, Inc.
* Lee Revell <rlrevell@joe-job.com>
- * Routines for control of EMU10K1 chips - voice manager
- *
- * Rewrote voice allocator for multichannel support - rlrevell 12/2004
- *
- * BUGS:
- * --
+ * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
+ * Creative Labs, Inc.
*
- * TODO:
- * --
+ * Routines for control of EMU10K1 chips - voice manager
*/
#include <linux/time.h>
@@ -23,112 +17,101 @@
* allocator uses a round robin scheme. The next free voice is tracked in
* the card record and each allocation begins where the last left off. The
* hardware requires stereo interleaved voices be aligned to an even/odd
- * boundary. For multichannel voice allocation we ensure than the block of
- * voices does not cross the 32 voice boundary. This simplifies the
- * multichannel support and ensures we can use a single write to the
- * (set|clear)_loop_stop registers. Otherwise (for example) the voices would
- * get out of sync when pausing/resuming a stream.
+ * boundary.
* --rlrevell
*/
static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
- struct snd_emu10k1_voice **rvoice)
+ struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice)
{
struct snd_emu10k1_voice *voice;
- int i, j, k, first_voice, last_voice, skip;
+ int i, j, k, skip;
- *rvoice = NULL;
- first_voice = last_voice = 0;
- for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
+ for (i = emu->next_free_voice, j = 0; j < NUM_G; i = (i + skip) % NUM_G, j += skip) {
/*
dev_dbg(emu->card->dev, "i %d j %d next free %d!\n",
i, j, emu->next_free_voice);
*/
- i %= NUM_G;
/* stereo voices must be even/odd */
- if ((number == 2) && (i % 2)) {
- i++;
+ if ((number > 1) && (i % 2)) {
+ skip = 1;
continue;
}
-
- skip = 0;
+
for (k = 0; k < number; k++) {
- voice = &emu->voices[(i+k) % NUM_G];
+ voice = &emu->voices[i + k];
if (voice->use) {
- skip = 1;
- break;
+ skip = k + 1;
+ goto next;
}
}
- if (!skip) {
- /* dev_dbg(emu->card->dev, "allocated voice %d\n", i); */
- first_voice = i;
- last_voice = (i + number) % NUM_G;
- emu->next_free_voice = last_voice;
- break;
- }
- }
-
- if (first_voice == last_voice)
- return -ENOMEM;
-
- for (i = 0; i < number; i++) {
- voice = &emu->voices[(first_voice + i) % NUM_G];
- /*
- dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n",
- voice->number, idx-first_voice+1, number);
- */
- voice->use = 1;
- switch (type) {
- case EMU10K1_PCM:
- voice->pcm = 1;
- break;
- case EMU10K1_SYNTH:
- voice->synth = 1;
- break;
- case EMU10K1_MIDI:
- voice->midi = 1;
- break;
- case EMU10K1_EFX:
- voice->efx = 1;
- break;
+
+ for (k = 0; k < number; k++) {
+ voice = &emu->voices[i + k];
+ voice->use = type;
+ voice->epcm = epcm;
+ /* dev_dbg(emu->card->dev, "allocated voice %d\n", i + k); */
}
+ voice->last = 1;
+
+ *rvoice = &emu->voices[i];
+ emu->next_free_voice = (i + number) % NUM_G;
+ return 0;
+
+ next: ;
}
- *rvoice = &emu->voices[first_voice];
- return 0;
+ return -ENOMEM; // -EBUSY would have been better
}
-int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number,
- struct snd_emu10k1_voice **rvoice)
+static void voice_free(struct snd_emu10k1 *emu,
+ struct snd_emu10k1_voice *pvoice)
+{
+ if (pvoice->dirty)
+ snd_emu10k1_voice_init(emu, pvoice->number);
+ pvoice->interrupt = NULL;
+ pvoice->use = pvoice->dirty = pvoice->last = 0;
+ pvoice->epcm = NULL;
+}
+
+int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels,
+ struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice)
{
- unsigned long flags;
int result;
if (snd_BUG_ON(!rvoice))
return -EINVAL;
- if (snd_BUG_ON(!number))
+ if (snd_BUG_ON(!count))
+ return -EINVAL;
+ if (snd_BUG_ON(!channels))
return -EINVAL;
- spin_lock_irqsave(&emu->voice_lock, flags);
- for (;;) {
- result = voice_alloc(emu, type, number, rvoice);
- if (result == 0 || type == EMU10K1_SYNTH || type == EMU10K1_MIDI)
- break;
-
- /* free a voice from synth */
- if (emu->get_synth_voice) {
+ guard(spinlock_irqsave)(&emu->voice_lock);
+ for (int got = 0; got < channels; ) {
+ result = voice_alloc(emu, type, count, epcm, &rvoice[got]);
+ if (result == 0) {
+ got++;
+ /*
+ dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n",
+ rvoice[got - 1]->number, got, want);
+ */
+ continue;
+ }
+ if (type != EMU10K1_SYNTH && emu->get_synth_voice) {
+ /* free a voice from synth */
result = emu->get_synth_voice(emu);
if (result >= 0) {
- struct snd_emu10k1_voice *pvoice = &emu->voices[result];
- pvoice->interrupt = NULL;
- pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
- pvoice->epcm = NULL;
+ voice_free(emu, &emu->voices[result]);
+ continue;
}
}
- if (result < 0)
- break;
+ for (int i = 0; i < got; i++) {
+ for (int j = 0; j < count; j++)
+ voice_free(emu, rvoice[i] + j);
+ rvoice[i] = NULL;
+ }
+ break;
}
- spin_unlock_irqrestore(&emu->voice_lock, flags);
return result;
}
@@ -138,16 +121,15 @@ EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
struct snd_emu10k1_voice *pvoice)
{
- unsigned long flags;
+ int last;
if (snd_BUG_ON(!pvoice))
return -EINVAL;
- spin_lock_irqsave(&emu->voice_lock, flags);
- pvoice->interrupt = NULL;
- pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
- pvoice->epcm = NULL;
- snd_emu10k1_voice_init(emu, pvoice->number);
- spin_unlock_irqrestore(&emu->voice_lock, flags);
+ guard(spinlock_irqsave)(&emu->voice_lock);
+ do {
+ last = pvoice->last;
+ voice_free(emu, pvoice++);
+ } while (!last);
return 0;
}
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 89210b2c7342..657056a59175 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -596,7 +596,7 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97,
unsigned int t, x, flag;
flag = is_ev1938(ensoniq) ? EV_1938_CODEC_MAGIC : 0;
- mutex_lock(&ensoniq->src_mutex);
+ guard(mutex)(&ensoniq->src_mutex);
for (t = 0; t < POLL_COUNT; t++) {
if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) {
/* save the current state for latter */
@@ -622,11 +622,9 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97,
/* restore SRC reg */
snd_es1371_wait_src_ready(ensoniq);
outl(x, ES_REG(ensoniq, 1371_SMPRATE));
- mutex_unlock(&ensoniq->src_mutex);
return;
}
}
- mutex_unlock(&ensoniq->src_mutex);
dev_err(ensoniq->card->dev, "codec write timeout at 0x%lx [0x%x]\n",
ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
}
@@ -713,7 +711,7 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate)
{
unsigned int n, truncm, freq;
- mutex_lock(&ensoniq->src_mutex);
+ guard(mutex)(&ensoniq->src_mutex);
n = rate / 3000;
if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9)))
n--;
@@ -737,14 +735,13 @@ static void snd_es1371_adc_rate(struct ensoniq * ensoniq, unsigned int rate)
snd_es1371_src_write(ensoniq, ES_SMPREG_ADC + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff);
snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC, n << 8);
snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC + 1, n << 8);
- mutex_unlock(&ensoniq->src_mutex);
}
static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate)
{
unsigned int freq, r;
- mutex_lock(&ensoniq->src_mutex);
+ guard(mutex)(&ensoniq->src_mutex);
freq = DIV_ROUND_CLOSEST(rate << 15, 3000);
r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
ES_1371_DIS_P2 | ES_1371_DIS_R1)) |
@@ -758,14 +755,13 @@ static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate)
r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
ES_1371_DIS_P2 | ES_1371_DIS_R1));
outl(r, ES_REG(ensoniq, 1371_SMPRATE));
- mutex_unlock(&ensoniq->src_mutex);
}
static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate)
{
unsigned int freq, r;
- mutex_lock(&ensoniq->src_mutex);
+ guard(mutex)(&ensoniq->src_mutex);
freq = DIV_ROUND_CLOSEST(rate << 15, 3000);
r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
ES_1371_DIS_P1 | ES_1371_DIS_R1)) |
@@ -780,7 +776,6 @@ static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate)
r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
ES_1371_DIS_P1 | ES_1371_DIS_R1));
outl(r, ES_REG(ensoniq, 1371_SMPRATE));
- mutex_unlock(&ensoniq->src_mutex);
}
#endif /* CHIP1371 */
@@ -804,13 +799,13 @@ static int snd_ensoniq_trigger(struct snd_pcm_substream *substream, int cmd)
} else if (s == ensoniq->capture_substream)
return -EINVAL;
}
- spin_lock(&ensoniq->reg_lock);
- if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
- ensoniq->sctrl |= what;
- else
- ensoniq->sctrl &= ~what;
- outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
- spin_unlock(&ensoniq->reg_lock);
+ scoped_guard(spinlock, &ensoniq->reg_lock) {
+ if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+ ensoniq->sctrl |= what;
+ else
+ ensoniq->sctrl &= ~what;
+ outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
+ }
break;
}
case SNDRV_PCM_TRIGGER_START:
@@ -830,13 +825,13 @@ static int snd_ensoniq_trigger(struct snd_pcm_substream *substream, int cmd)
snd_pcm_trigger_done(s, substream);
}
}
- spin_lock(&ensoniq->reg_lock);
- if (cmd == SNDRV_PCM_TRIGGER_START)
- ensoniq->ctrl |= what;
- else
- ensoniq->ctrl &= ~what;
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- spin_unlock(&ensoniq->reg_lock);
+ scoped_guard(spinlock, &ensoniq->reg_lock) {
+ if (cmd == SNDRV_PCM_TRIGGER_START)
+ ensoniq->ctrl |= what;
+ else
+ ensoniq->ctrl &= ~what;
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ }
break;
}
default:
@@ -861,36 +856,36 @@ static int snd_ensoniq_playback1_prepare(struct snd_pcm_substream *substream)
mode |= 0x02;
if (runtime->channels > 1)
mode |= 0x01;
- spin_lock_irq(&ensoniq->reg_lock);
- ensoniq->ctrl &= ~ES_DAC1_EN;
+ scoped_guard(spinlock_irq, &ensoniq->reg_lock) {
+ ensoniq->ctrl &= ~ES_DAC1_EN;
#ifdef CHIP1371
- /* 48k doesn't need SRC (it breaks AC3-passthru) */
- if (runtime->rate == 48000)
- ensoniq->ctrl |= ES_1373_BYPASS_P1;
- else
- ensoniq->ctrl &= ~ES_1373_BYPASS_P1;
+ /* 48k doesn't need SRC (it breaks AC3-passthru) */
+ if (runtime->rate == 48000)
+ ensoniq->ctrl |= ES_1373_BYPASS_P1;
+ else
+ ensoniq->ctrl &= ~ES_1373_BYPASS_P1;
#endif
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
- outl(runtime->dma_addr, ES_REG(ensoniq, DAC1_FRAME));
- outl((ensoniq->p1_dma_size >> 2) - 1, ES_REG(ensoniq, DAC1_SIZE));
- ensoniq->sctrl &= ~(ES_P1_LOOP_SEL | ES_P1_PAUSE | ES_P1_SCT_RLD | ES_P1_MODEM);
- ensoniq->sctrl |= ES_P1_INT_EN | ES_P1_MODEO(mode);
- outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
- outl((ensoniq->p1_period_size >> snd_ensoniq_sample_shift[mode]) - 1,
- ES_REG(ensoniq, DAC1_COUNT));
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
+ outl(runtime->dma_addr, ES_REG(ensoniq, DAC1_FRAME));
+ outl((ensoniq->p1_dma_size >> 2) - 1, ES_REG(ensoniq, DAC1_SIZE));
+ ensoniq->sctrl &= ~(ES_P1_LOOP_SEL | ES_P1_PAUSE | ES_P1_SCT_RLD | ES_P1_MODEM);
+ ensoniq->sctrl |= ES_P1_INT_EN | ES_P1_MODEO(mode);
+ outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
+ outl((ensoniq->p1_period_size >> snd_ensoniq_sample_shift[mode]) - 1,
+ ES_REG(ensoniq, DAC1_COUNT));
#ifdef CHIP1370
- ensoniq->ctrl &= ~ES_1370_WTSRSELM;
- switch (runtime->rate) {
- case 5512: ensoniq->ctrl |= ES_1370_WTSRSEL(0); break;
- case 11025: ensoniq->ctrl |= ES_1370_WTSRSEL(1); break;
- case 22050: ensoniq->ctrl |= ES_1370_WTSRSEL(2); break;
- case 44100: ensoniq->ctrl |= ES_1370_WTSRSEL(3); break;
- default: snd_BUG();
- }
+ ensoniq->ctrl &= ~ES_1370_WTSRSELM;
+ switch (runtime->rate) {
+ case 5512: ensoniq->ctrl |= ES_1370_WTSRSEL(0); break;
+ case 11025: ensoniq->ctrl |= ES_1370_WTSRSEL(1); break;
+ case 22050: ensoniq->ctrl |= ES_1370_WTSRSEL(2); break;
+ case 44100: ensoniq->ctrl |= ES_1370_WTSRSEL(3); break;
+ default: snd_BUG();
+ }
#endif
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- spin_unlock_irq(&ensoniq->reg_lock);
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ }
#ifndef CHIP1370
snd_es1371_dac1_rate(ensoniq, runtime->rate);
#endif
@@ -909,28 +904,28 @@ static int snd_ensoniq_playback2_prepare(struct snd_pcm_substream *substream)
mode |= 0x02;
if (runtime->channels > 1)
mode |= 0x01;
- spin_lock_irq(&ensoniq->reg_lock);
- ensoniq->ctrl &= ~ES_DAC2_EN;
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
- outl(runtime->dma_addr, ES_REG(ensoniq, DAC2_FRAME));
- outl((ensoniq->p2_dma_size >> 2) - 1, ES_REG(ensoniq, DAC2_SIZE));
- ensoniq->sctrl &= ~(ES_P2_LOOP_SEL | ES_P2_PAUSE | ES_P2_DAC_SEN |
- ES_P2_END_INCM | ES_P2_ST_INCM | ES_P2_MODEM);
- ensoniq->sctrl |= ES_P2_INT_EN | ES_P2_MODEO(mode) |
- ES_P2_END_INCO(mode & 2 ? 2 : 1) | ES_P2_ST_INCO(0);
- outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
- outl((ensoniq->p2_period_size >> snd_ensoniq_sample_shift[mode]) - 1,
- ES_REG(ensoniq, DAC2_COUNT));
+ scoped_guard(spinlock_irq, &ensoniq->reg_lock) {
+ ensoniq->ctrl &= ~ES_DAC2_EN;
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
+ outl(runtime->dma_addr, ES_REG(ensoniq, DAC2_FRAME));
+ outl((ensoniq->p2_dma_size >> 2) - 1, ES_REG(ensoniq, DAC2_SIZE));
+ ensoniq->sctrl &= ~(ES_P2_LOOP_SEL | ES_P2_PAUSE | ES_P2_DAC_SEN |
+ ES_P2_END_INCM | ES_P2_ST_INCM | ES_P2_MODEM);
+ ensoniq->sctrl |= ES_P2_INT_EN | ES_P2_MODEO(mode) |
+ ES_P2_END_INCO(mode & 2 ? 2 : 1) | ES_P2_ST_INCO(0);
+ outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
+ outl((ensoniq->p2_period_size >> snd_ensoniq_sample_shift[mode]) - 1,
+ ES_REG(ensoniq, DAC2_COUNT));
#ifdef CHIP1370
- if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_CAPTURE)) {
- ensoniq->ctrl &= ~ES_1370_PCLKDIVM;
- ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate));
- ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_PLAY2;
- }
+ if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_CAPTURE)) {
+ ensoniq->ctrl &= ~ES_1370_PCLKDIVM;
+ ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate));
+ ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_PLAY2;
+ }
#endif
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- spin_unlock_irq(&ensoniq->reg_lock);
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ }
#ifndef CHIP1370
snd_es1371_dac2_rate(ensoniq, runtime->rate);
#endif
@@ -949,26 +944,26 @@ static int snd_ensoniq_capture_prepare(struct snd_pcm_substream *substream)
mode |= 0x02;
if (runtime->channels > 1)
mode |= 0x01;
- spin_lock_irq(&ensoniq->reg_lock);
- ensoniq->ctrl &= ~ES_ADC_EN;
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE));
- outl(runtime->dma_addr, ES_REG(ensoniq, ADC_FRAME));
- outl((ensoniq->c_dma_size >> 2) - 1, ES_REG(ensoniq, ADC_SIZE));
- ensoniq->sctrl &= ~(ES_R1_LOOP_SEL | ES_R1_MODEM);
- ensoniq->sctrl |= ES_R1_INT_EN | ES_R1_MODEO(mode);
- outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
- outl((ensoniq->c_period_size >> snd_ensoniq_sample_shift[mode]) - 1,
- ES_REG(ensoniq, ADC_COUNT));
+ scoped_guard(spinlock_irq, &ensoniq->reg_lock) {
+ ensoniq->ctrl &= ~ES_ADC_EN;
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE));
+ outl(runtime->dma_addr, ES_REG(ensoniq, ADC_FRAME));
+ outl((ensoniq->c_dma_size >> 2) - 1, ES_REG(ensoniq, ADC_SIZE));
+ ensoniq->sctrl &= ~(ES_R1_LOOP_SEL | ES_R1_MODEM);
+ ensoniq->sctrl |= ES_R1_INT_EN | ES_R1_MODEO(mode);
+ outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
+ outl((ensoniq->c_period_size >> snd_ensoniq_sample_shift[mode]) - 1,
+ ES_REG(ensoniq, ADC_COUNT));
#ifdef CHIP1370
- if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_PLAY2)) {
- ensoniq->ctrl &= ~ES_1370_PCLKDIVM;
- ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate));
- ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_CAPTURE;
- }
+ if (!(ensoniq->u.es1370.pclkdiv_lock & ES_MODE_PLAY2)) {
+ ensoniq->ctrl &= ~ES_1370_PCLKDIVM;
+ ensoniq->ctrl |= ES_1370_PCLKDIVO(ES_1370_SRTODIV(runtime->rate));
+ ensoniq->u.es1370.pclkdiv_lock |= ES_MODE_CAPTURE;
+ }
#endif
- outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- spin_unlock_irq(&ensoniq->reg_lock);
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ }
#ifndef CHIP1370
snd_es1371_adc_rate(ensoniq, runtime->rate);
#endif
@@ -980,16 +975,14 @@ static snd_pcm_uframes_t snd_ensoniq_playback1_pointer(struct snd_pcm_substream
struct ensoniq *ensoniq = snd_pcm_substream_chip(substream);
size_t ptr;
- spin_lock(&ensoniq->reg_lock);
+ guard(spinlock)(&ensoniq->reg_lock);
if (inl(ES_REG(ensoniq, CONTROL)) & ES_DAC1_EN) {
outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, DAC1_SIZE)));
- ptr = bytes_to_frames(substream->runtime, ptr);
+ return bytes_to_frames(substream->runtime, ptr);
} else {
- ptr = 0;
+ return 0;
}
- spin_unlock(&ensoniq->reg_lock);
- return ptr;
}
static snd_pcm_uframes_t snd_ensoniq_playback2_pointer(struct snd_pcm_substream *substream)
@@ -997,16 +990,14 @@ static snd_pcm_uframes_t snd_ensoniq_playback2_pointer(struct snd_pcm_substream
struct ensoniq *ensoniq = snd_pcm_substream_chip(substream);
size_t ptr;
- spin_lock(&ensoniq->reg_lock);
+ guard(spinlock)(&ensoniq->reg_lock);
if (inl(ES_REG(ensoniq, CONTROL)) & ES_DAC2_EN) {
outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, DAC2_SIZE)));
- ptr = bytes_to_frames(substream->runtime, ptr);
+ return bytes_to_frames(substream->runtime, ptr);
} else {
- ptr = 0;
+ return 0;
}
- spin_unlock(&ensoniq->reg_lock);
- return ptr;
}
static snd_pcm_uframes_t snd_ensoniq_capture_pointer(struct snd_pcm_substream *substream)
@@ -1014,16 +1005,14 @@ static snd_pcm_uframes_t snd_ensoniq_capture_pointer(struct snd_pcm_substream *s
struct ensoniq *ensoniq = snd_pcm_substream_chip(substream);
size_t ptr;
- spin_lock(&ensoniq->reg_lock);
+ guard(spinlock)(&ensoniq->reg_lock);
if (inl(ES_REG(ensoniq, CONTROL)) & ES_ADC_EN) {
outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE));
ptr = ES_REG_FCURR_COUNTI(inl(ES_REG(ensoniq, ADC_SIZE)));
- ptr = bytes_to_frames(substream->runtime, ptr);
+ return bytes_to_frames(substream->runtime, ptr);
} else {
- ptr = 0;
+ return 0;
}
- spin_unlock(&ensoniq->reg_lock);
- return ptr;
}
static const struct snd_pcm_hardware snd_ensoniq_playback1 =
@@ -1101,10 +1090,10 @@ static int snd_ensoniq_playback1_open(struct snd_pcm_substream *substream)
ensoniq->playback1_substream = substream;
runtime->hw = snd_ensoniq_playback1;
snd_pcm_set_sync(substream);
- spin_lock_irq(&ensoniq->reg_lock);
- if (ensoniq->spdif && ensoniq->playback2_substream == NULL)
- ensoniq->spdif_stream = ensoniq->spdif_default;
- spin_unlock_irq(&ensoniq->reg_lock);
+ scoped_guard(spinlock_irq, &ensoniq->reg_lock) {
+ if (ensoniq->spdif && ensoniq->playback2_substream == NULL)
+ ensoniq->spdif_stream = ensoniq->spdif_default;
+ }
#ifdef CHIP1370
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_es1370_hw_constraints_rates);
@@ -1124,10 +1113,10 @@ static int snd_ensoniq_playback2_open(struct snd_pcm_substream *substream)
ensoniq->playback2_substream = substream;
runtime->hw = snd_ensoniq_playback2;
snd_pcm_set_sync(substream);
- spin_lock_irq(&ensoniq->reg_lock);
- if (ensoniq->spdif && ensoniq->playback1_substream == NULL)
- ensoniq->spdif_stream = ensoniq->spdif_default;
- spin_unlock_irq(&ensoniq->reg_lock);
+ scoped_guard(spinlock_irq, &ensoniq->reg_lock) {
+ if (ensoniq->spdif && ensoniq->playback1_substream == NULL)
+ ensoniq->spdif_stream = ensoniq->spdif_default;
+ }
#ifdef CHIP1370
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_es1370_hw_constraints_clock);
@@ -1171,12 +1160,11 @@ static int snd_ensoniq_playback2_close(struct snd_pcm_substream *substream)
struct ensoniq *ensoniq = snd_pcm_substream_chip(substream);
ensoniq->playback2_substream = NULL;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
#ifdef CHIP1370
ensoniq->u.es1370.pclkdiv_lock &= ~ES_MODE_PLAY2;
#endif
ensoniq->mode &= ~ES_MODE_PLAY2;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1185,12 +1173,11 @@ static int snd_ensoniq_capture_close(struct snd_pcm_substream *substream)
struct ensoniq *ensoniq = snd_pcm_substream_chip(substream);
ensoniq->capture_substream = NULL;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
#ifdef CHIP1370
ensoniq->u.es1370.pclkdiv_lock &= ~ES_MODE_CAPTURE;
#endif
ensoniq->mode &= ~ES_MODE_CAPTURE;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1244,7 +1231,7 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device)
pcm->private_data = ensoniq;
pcm->info_flags = 0;
- strcpy(pcm->name, CHIP_NAME " DAC2/ADC");
+ strscpy(pcm->name, CHIP_NAME " DAC2/ADC");
ensoniq->pcm1 = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1276,7 +1263,7 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device)
#endif
pcm->private_data = ensoniq;
pcm->info_flags = 0;
- strcpy(pcm->name, CHIP_NAME " DAC1");
+ strscpy(pcm->name, CHIP_NAME " DAC1");
ensoniq->pcm2 = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1312,12 +1299,12 @@ static int snd_ens1373_spdif_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&ensoniq->reg_lock);
+
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ucontrol->value.iec958.status[0] = (ensoniq->spdif_default >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (ensoniq->spdif_default >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (ensoniq->spdif_default >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (ensoniq->spdif_default >> 24) & 0xff;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1332,13 +1319,12 @@ static int snd_ens1373_spdif_default_put(struct snd_kcontrol *kcontrol,
((u32)ucontrol->value.iec958.status[1] << 8) |
((u32)ucontrol->value.iec958.status[2] << 16) |
((u32)ucontrol->value.iec958.status[3] << 24);
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
change = ensoniq->spdif_default != val;
ensoniq->spdif_default = val;
if (change && ensoniq->playback1_substream == NULL &&
ensoniq->playback2_substream == NULL)
outl(val, ES_REG(ensoniq, CHANNEL_STATUS));
- spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
@@ -1356,12 +1342,12 @@ static int snd_ens1373_spdif_stream_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&ensoniq->reg_lock);
+
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ucontrol->value.iec958.status[0] = (ensoniq->spdif_stream >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (ensoniq->spdif_stream >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (ensoniq->spdif_stream >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (ensoniq->spdif_stream >> 24) & 0xff;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1376,13 +1362,12 @@ static int snd_ens1373_spdif_stream_put(struct snd_kcontrol *kcontrol,
((u32)ucontrol->value.iec958.status[1] << 8) |
((u32)ucontrol->value.iec958.status[2] << 16) |
((u32)ucontrol->value.iec958.status[3] << 24);
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
change = ensoniq->spdif_stream != val;
ensoniq->spdif_stream = val;
if (change && (ensoniq->playback1_substream != NULL ||
ensoniq->playback2_substream != NULL))
outl(val, ES_REG(ensoniq, CHANNEL_STATUS));
- spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
@@ -1397,9 +1382,8 @@ static int snd_es1371_spdif_get(struct snd_kcontrol *kcontrol,
{
struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1373_SPDIF_THRU ? 1 : 0;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1412,7 +1396,7 @@ static int snd_es1371_spdif_put(struct snd_kcontrol *kcontrol,
nval1 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_THRU : 0;
nval2 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_EN : 0;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
change = (ensoniq->ctrl & ES_1373_SPDIF_THRU) != nval1;
ensoniq->ctrl &= ~ES_1373_SPDIF_THRU;
ensoniq->ctrl |= nval1;
@@ -1420,7 +1404,6 @@ static int snd_es1371_spdif_put(struct snd_kcontrol *kcontrol,
ensoniq->cssr |= nval2;
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
- spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
@@ -1460,12 +1443,11 @@ static int snd_es1373_rear_get(struct snd_kcontrol *kcontrol,
struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);
int val = 0;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
if ((ensoniq->cssr & (ES_1373_REAR_BIT27|ES_1373_REAR_BIT26|
ES_1373_REAR_BIT24)) == ES_1373_REAR_BIT26)
val = 1;
ucontrol->value.integer.value[0] = val;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1478,13 +1460,12 @@ static int snd_es1373_rear_put(struct snd_kcontrol *kcontrol,
nval1 = ucontrol->value.integer.value[0] ?
ES_1373_REAR_BIT26 : (ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
change = (ensoniq->cssr & (ES_1373_REAR_BIT27|
ES_1373_REAR_BIT26|ES_1373_REAR_BIT24)) != nval1;
ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT26|ES_1373_REAR_BIT24);
ensoniq->cssr |= nval1;
outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
- spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
@@ -1505,11 +1486,10 @@ static int snd_es1373_line_get(struct snd_kcontrol *kcontrol,
struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);
int val = 0;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
if (ensoniq->ctrl & ES_1371_GPIO_OUT(4))
val = 1;
ucontrol->value.integer.value[0] = val;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1520,7 +1500,7 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol,
int changed;
unsigned int ctrl;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ctrl = ensoniq->ctrl;
if (ucontrol->value.integer.value[0])
ensoniq->ctrl |= ES_1371_GPIO_OUT(4); /* switch line-in -> rear out */
@@ -1529,7 +1509,6 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol,
changed = (ctrl != ensoniq->ctrl);
if (changed)
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- spin_unlock_irq(&ensoniq->reg_lock);
return changed;
}
@@ -1665,9 +1644,8 @@ static int snd_ensoniq_control_get(struct snd_kcontrol *kcontrol,
struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);
int mask = kcontrol->private_value;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ucontrol->value.integer.value[0] = ensoniq->ctrl & mask ? 1 : 0;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -1680,12 +1658,11 @@ static int snd_ensoniq_control_put(struct snd_kcontrol *kcontrol,
int change;
nval = ucontrol->value.integer.value[0] ? mask : 0;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
change = (ensoniq->ctrl & mask) != nval;
ensoniq->ctrl &= ~mask;
ensoniq->ctrl |= nval;
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
- spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
@@ -1850,12 +1827,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);
@@ -1968,7 +1945,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
}
-#ifdef CONFIG_PM_SLEEP
static int snd_ensoniq_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -2007,11 +1983,7 @@ static int snd_ensoniq_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume);
-#define SND_ENSONIQ_PM_OPS &snd_ensoniq_pm
-#else
-#define SND_ENSONIQ_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume);
static int snd_ensoniq_create(struct snd_card *card,
struct pci_dev *pci)
@@ -2027,7 +1999,7 @@ static int snd_ensoniq_create(struct snd_card *card,
ensoniq->card = card;
ensoniq->pci = pci;
ensoniq->irq = -1;
- err = pci_request_regions(pci, "Ensoniq AudioPCI");
+ err = pcim_request_all_regions(pci, "Ensoniq AudioPCI");
if (err < 0)
return err;
ensoniq->port = pci_resource_start(pci, 0);
@@ -2084,19 +2056,19 @@ static void snd_ensoniq_midi_interrupt(struct ensoniq * ensoniq)
if (rmidi == NULL)
return;
/* do Rx at first */
- spin_lock(&ensoniq->reg_lock);
- mask = ensoniq->uartm & ES_MODE_INPUT ? ES_RXRDY : 0;
- while (mask) {
- status = inb(ES_REG(ensoniq, UART_STATUS));
- if ((status & mask) == 0)
- break;
- byte = inb(ES_REG(ensoniq, UART_DATA));
- snd_rawmidi_receive(ensoniq->midi_input, &byte, 1);
+ scoped_guard(spinlock, &ensoniq->reg_lock) {
+ mask = ensoniq->uartm & ES_MODE_INPUT ? ES_RXRDY : 0;
+ while (mask) {
+ status = inb(ES_REG(ensoniq, UART_STATUS));
+ if ((status & mask) == 0)
+ break;
+ byte = inb(ES_REG(ensoniq, UART_DATA));
+ snd_rawmidi_receive(ensoniq->midi_input, &byte, 1);
+ }
}
- spin_unlock(&ensoniq->reg_lock);
/* do Tx at second */
- spin_lock(&ensoniq->reg_lock);
+ guard(spinlock)(&ensoniq->reg_lock);
mask = ensoniq->uartm & ES_MODE_OUTPUT ? ES_TXRDY : 0;
while (mask) {
status = inb(ES_REG(ensoniq, UART_STATUS));
@@ -2110,14 +2082,13 @@ static void snd_ensoniq_midi_interrupt(struct ensoniq * ensoniq)
outb(byte, ES_REG(ensoniq, UART_DATA));
}
}
- spin_unlock(&ensoniq->reg_lock);
}
static int snd_ensoniq_midi_input_open(struct snd_rawmidi_substream *substream)
{
struct ensoniq *ensoniq = substream->rmidi->private_data;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ensoniq->uartm |= ES_MODE_INPUT;
ensoniq->midi_input = substream;
if (!(ensoniq->uartm & ES_MODE_OUTPUT)) {
@@ -2125,7 +2096,6 @@ static int snd_ensoniq_midi_input_open(struct snd_rawmidi_substream *substream)
outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL));
outl(ensoniq->ctrl |= ES_UART_EN, ES_REG(ensoniq, CONTROL));
}
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -2133,7 +2103,7 @@ static int snd_ensoniq_midi_input_close(struct snd_rawmidi_substream *substream)
{
struct ensoniq *ensoniq = substream->rmidi->private_data;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
if (!(ensoniq->uartm & ES_MODE_OUTPUT)) {
outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL));
outl(ensoniq->ctrl &= ~ES_UART_EN, ES_REG(ensoniq, CONTROL));
@@ -2142,7 +2112,6 @@ static int snd_ensoniq_midi_input_close(struct snd_rawmidi_substream *substream)
}
ensoniq->midi_input = NULL;
ensoniq->uartm &= ~ES_MODE_INPUT;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -2150,7 +2119,7 @@ static int snd_ensoniq_midi_output_open(struct snd_rawmidi_substream *substream)
{
struct ensoniq *ensoniq = substream->rmidi->private_data;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
ensoniq->uartm |= ES_MODE_OUTPUT;
ensoniq->midi_output = substream;
if (!(ensoniq->uartm & ES_MODE_INPUT)) {
@@ -2158,7 +2127,6 @@ static int snd_ensoniq_midi_output_open(struct snd_rawmidi_substream *substream)
outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL));
outl(ensoniq->ctrl |= ES_UART_EN, ES_REG(ensoniq, CONTROL));
}
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
@@ -2166,7 +2134,7 @@ static int snd_ensoniq_midi_output_close(struct snd_rawmidi_substream *substream
{
struct ensoniq *ensoniq = substream->rmidi->private_data;
- spin_lock_irq(&ensoniq->reg_lock);
+ guard(spinlock_irq)(&ensoniq->reg_lock);
if (!(ensoniq->uartm & ES_MODE_INPUT)) {
outb(ensoniq->uartc = 0, ES_REG(ensoniq, UART_CONTROL));
outl(ensoniq->ctrl &= ~ES_UART_EN, ES_REG(ensoniq, CONTROL));
@@ -2175,17 +2143,15 @@ static int snd_ensoniq_midi_output_close(struct snd_rawmidi_substream *substream
}
ensoniq->midi_output = NULL;
ensoniq->uartm &= ~ES_MODE_OUTPUT;
- spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
static void snd_ensoniq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct ensoniq *ensoniq = substream->rmidi->private_data;
int idx;
- spin_lock_irqsave(&ensoniq->reg_lock, flags);
+ guard(spinlock_irqsave)(&ensoniq->reg_lock);
if (up) {
if ((ensoniq->uartc & ES_RXINTEN) == 0) {
/* empty input FIFO */
@@ -2200,16 +2166,14 @@ static void snd_ensoniq_midi_input_trigger(struct snd_rawmidi_substream *substre
outb(ensoniq->uartc, ES_REG(ensoniq, UART_CONTROL));
}
}
- spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
}
static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
- unsigned long flags;
struct ensoniq *ensoniq = substream->rmidi->private_data;
unsigned char byte;
- spin_lock_irqsave(&ensoniq->reg_lock, flags);
+ guard(spinlock_irqsave)(&ensoniq->reg_lock);
if (up) {
if (ES_TXINTENI(ensoniq->uartc) == 0) {
ensoniq->uartc |= ES_TXINTENO(1);
@@ -2230,7 +2194,6 @@ static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substr
outb(ensoniq->uartc, ES_REG(ensoniq, UART_CONTROL));
}
}
- spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
}
static const struct snd_rawmidi_ops snd_ensoniq_midi_output =
@@ -2255,7 +2218,7 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device)
err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi);
if (err < 0)
return err;
- strcpy(rmidi->name, CHIP_NAME);
+ strscpy(rmidi->name, CHIP_NAME);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_ensoniq_midi_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT |
@@ -2281,17 +2244,17 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id)
if (!(status & ES_INTR))
return IRQ_NONE;
- spin_lock(&ensoniq->reg_lock);
- sctrl = ensoniq->sctrl;
- if (status & ES_DAC1)
- sctrl &= ~ES_P1_INT_EN;
- if (status & ES_DAC2)
- sctrl &= ~ES_P2_INT_EN;
- if (status & ES_ADC)
- sctrl &= ~ES_R1_INT_EN;
- outl(sctrl, ES_REG(ensoniq, SERIAL));
- outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
- spin_unlock(&ensoniq->reg_lock);
+ scoped_guard(spinlock, &ensoniq->reg_lock) {
+ sctrl = ensoniq->sctrl;
+ if (status & ES_DAC1)
+ sctrl &= ~ES_P1_INT_EN;
+ if (status & ES_DAC2)
+ sctrl &= ~ES_P2_INT_EN;
+ if (status & ES_ADC)
+ sctrl &= ~ES_R1_INT_EN;
+ outl(sctrl, ES_REG(ensoniq, SERIAL));
+ outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
+ }
if (status & ES_UART)
snd_ensoniq_midi_interrupt(ensoniq);
@@ -2351,9 +2314,9 @@ static int __snd_audiopci_probe(struct pci_dev *pci,
snd_ensoniq_create_gameport(ensoniq, dev);
- strcpy(card->driver, DRIVER_NAME);
+ strscpy(card->driver, DRIVER_NAME);
- strcpy(card->shortname, "Ensoniq AudioPCI");
+ strscpy(card->shortname, "Ensoniq AudioPCI");
sprintf(card->longname, "%s %s at 0x%lx, irq %i",
card->shortname,
card->driver,
@@ -2380,7 +2343,7 @@ static struct pci_driver ens137x_driver = {
.id_table = snd_audiopci_ids,
.probe = snd_audiopci_probe,
.driver = {
- .pm = SND_ENSONIQ_PM_OPS,
+ .pm = &snd_ensoniq_pm,
},
};
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index e34ec6f89e7e..280125eff362 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -216,9 +216,7 @@ struct es1938 {
#ifdef SUPPORT_JOYSTICK
struct gameport *gameport;
#endif
-#ifdef CONFIG_PM_SLEEP
unsigned char saved_regs[SAVED_REG_SIZE];
-#endif
};
static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
@@ -239,11 +237,9 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids);
* -----------------------------------------------------------------*/
static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsigned char val)
{
- unsigned long flags;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, SLSB_REG(chip, MIXERADDR));
outb(val, SLSB_REG(chip, MIXERDATA));
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val);
}
@@ -253,11 +249,10 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig
static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg)
{
int data;
- unsigned long flags;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, SLSB_REG(chip, MIXERADDR));
data = inb(SLSB_REG(chip, MIXERDATA));
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data);
return data;
}
@@ -268,9 +263,9 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg)
static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg,
unsigned char mask, unsigned char val)
{
- unsigned long flags;
unsigned char old, new, oval;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->mixer_lock);
outb(reg, SLSB_REG(chip, MIXERADDR));
old = inb(SLSB_REG(chip, MIXERDATA));
oval = old & mask;
@@ -281,7 +276,6 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg,
"Mixer reg %02x was %02x, set to %02x\n",
reg, old, new);
}
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
return oval;
}
@@ -324,11 +318,9 @@ static int snd_es1938_get_byte(struct es1938 *chip)
* -----------------------------------------------------------------*/
static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned char val)
{
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_es1938_write_cmd(chip, reg);
snd_es1938_write_cmd(chip, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val);
}
@@ -338,12 +330,11 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch
static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg)
{
unsigned char val;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_es1938_write_cmd(chip, ESS_CMD_READREG);
snd_es1938_write_cmd(chip, reg);
val = snd_es1938_get_byte(chip);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val);
return val;
}
@@ -354,9 +345,9 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg)
static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char mask,
unsigned char val)
{
- unsigned long flags;
unsigned char old, new, oval;
- spin_lock_irqsave(&chip->reg_lock, flags);
+
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_es1938_write_cmd(chip, ESS_CMD_READREG);
snd_es1938_write_cmd(chip, reg);
old = snd_es1938_get_byte(chip);
@@ -368,7 +359,6 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char
dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n",
reg, old, new);
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return oval;
}
@@ -824,7 +814,7 @@ static snd_pcm_uframes_t snd_es1938_playback_pointer(struct snd_pcm_substream *s
static int snd_es1938_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct es1938 *chip = snd_pcm_substream_chip(substream);
@@ -832,36 +822,17 @@ static int snd_es1938_capture_copy(struct snd_pcm_substream *substream,
if (snd_BUG_ON(pos + count > chip->dma1_size))
return -EINVAL;
if (pos + count < chip->dma1_size) {
- if (copy_to_user(dst, runtime->dma_area + pos + 1, count))
+ if (copy_to_iter(runtime->dma_area + pos + 1, count, dst) != count)
return -EFAULT;
} else {
- if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1))
+ if (copy_to_iter(runtime->dma_area + pos + 1, count - 1, dst) != count - 1)
return -EFAULT;
- if (put_user(runtime->dma_area[0],
- ((unsigned char __user *)dst) + count - 1))
+ if (copy_to_iter(runtime->dma_area, 1, dst) != 1)
return -EFAULT;
}
return 0;
}
-static int snd_es1938_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct es1938 *chip = snd_pcm_substream_chip(substream);
-
- if (snd_BUG_ON(pos + count > chip->dma1_size))
- return -EINVAL;
- if (pos + count < chip->dma1_size) {
- memcpy(dst, runtime->dma_area + pos + 1, count);
- } else {
- memcpy(dst, runtime->dma_area + pos + 1, count - 1);
- runtime->dma_area[0] = *((unsigned char *)dst + count - 1);
- }
- return 0;
-}
-
/* ----------------------------------------------------------------------
* Audio1 Capture (ADC)
* ----------------------------------------------------------------------*/
@@ -987,8 +958,7 @@ static const struct snd_pcm_ops snd_es1938_capture_ops = {
.prepare = snd_es1938_capture_prepare,
.trigger = snd_es1938_capture_trigger,
.pointer = snd_es1938_capture_pointer,
- .copy_user = snd_es1938_capture_copy,
- .copy_kernel = snd_es1938_capture_copy_kernel,
+ .copy = snd_es1938_capture_copy,
};
static int snd_es1938_new_pcm(struct es1938 *chip, int device)
@@ -1004,7 +974,7 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, "ESS Solo-1");
+ strscpy(pcm->name, "ESS Solo-1");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pci->dev, 64*1024, 64*1024);
@@ -1415,7 +1385,6 @@ static void snd_es1938_chip_init(struct es1938 *chip)
outb(0, SLDM_REG(chip, DMACLEAR));
}
-#ifdef CONFIG_PM_SLEEP
/*
* PM support
*/
@@ -1481,11 +1450,7 @@ static int es1938_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
-#define ES1938_PM_OPS &es1938_pm
-#else
-#define ES1938_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
#ifdef SUPPORT_JOYSTICK
static int snd_es1938_create_gameport(struct es1938 *chip)
@@ -1558,7 +1523,7 @@ static int snd_es1938_create(struct snd_card *card,
chip->card = card;
chip->pci = pci;
chip->irq = -1;
- err = pci_request_regions(pci, "ESS Solo-1");
+ err = pcim_request_all_regions(pci, "ESS Solo-1");
if (err < 0)
return err;
chip->io_port = pci_resource_start(pci, 0);
@@ -1685,7 +1650,7 @@ static int snd_es1938_mixer(struct es1938 *chip)
card = chip->card;
- strcpy(card->mixername, "ESS Solo-1");
+ strscpy(card->mixername, "ESS Solo-1");
for (idx = 0; idx < ARRAY_SIZE(snd_es1938_controls); idx++) {
struct snd_kcontrol *kctl;
@@ -1747,8 +1712,8 @@ static int __snd_es1938_probe(struct pci_dev *pci,
if (err < 0)
return err;
- strcpy(card->driver, "ES1938");
- strcpy(card->shortname, "ESS ES1938 (Solo-1)");
+ strscpy(card->driver, "ES1938");
+ strscpy(card->shortname, "ESS ES1938 (Solo-1)");
sprintf(card->longname, "%s rev %i, irq %i",
card->shortname,
chip->revision,
@@ -1807,7 +1772,7 @@ static struct pci_driver es1938_driver = {
.id_table = snd_es1938_ids,
.probe = snd_es1938_probe,
.driver = {
- .pm = ES1938_PM_OPS,
+ .pm = &es1938_pm,
},
};
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 4a7e20bb11bc..51aee2c4d461 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -473,9 +473,7 @@ struct esschan {
/* linked list */
struct list_head list;
-#ifdef CONFIG_PM_SLEEP
u16 wc_map[4];
-#endif
};
struct es1968 {
@@ -526,9 +524,7 @@ struct es1968 {
struct list_head substream_list;
spinlock_t substream_lock;
-#ifdef CONFIG_PM_SLEEP
u16 apu_map[NR_APUS][NR_APU_REGS];
-#endif
#ifdef SUPPORT_JOYSTICK
struct gameport *gameport;
@@ -578,10 +574,8 @@ static void __maestro_write(struct es1968 *chip, u16 reg, u16 data)
static inline void maestro_write(struct es1968 *chip, u16 reg, u16 data)
{
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
__maestro_write(chip, reg, data);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
/* no spinlock */
@@ -596,12 +590,8 @@ static u16 __maestro_read(struct es1968 *chip, u16 reg)
static inline u16 maestro_read(struct es1968 *chip, u16 reg)
{
- unsigned long flags;
- u16 result;
- spin_lock_irqsave(&chip->reg_lock, flags);
- result = __maestro_read(chip, reg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return result;
+ guard(spinlock_irqsave)(&chip->reg_lock);
+ return __maestro_read(chip, reg);
}
/* Wait for the codec bus to be free */
@@ -689,9 +679,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
{
if (snd_BUG_ON(channel >= NR_APUS))
return;
-#ifdef CONFIG_PM_SLEEP
chip->apu_map[channel][reg] = data;
-#endif
reg |= (channel << 4);
apu_index_set(chip, reg);
apu_data_set(chip, data);
@@ -699,10 +687,8 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
static void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
{
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
__apu_set_register(chip, channel, reg, data);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
@@ -716,62 +702,40 @@ static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
static u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
{
- unsigned long flags;
- u16 v;
- spin_lock_irqsave(&chip->reg_lock, flags);
- v = __apu_get_register(chip, channel, reg);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return v;
+ guard(spinlock_irqsave)(&chip->reg_lock);
+ return __apu_get_register(chip, channel, reg);
}
#if 0 /* ASSP is not supported */
static void assp_set_register(struct es1968 *chip, u32 reg, u32 value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave),(&chip->reg_lock);
outl(reg, chip->io_port + ASSP_INDEX);
outl(value, chip->io_port + ASSP_DATA);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static u32 assp_get_register(struct es1968 *chip, u32 reg)
{
- unsigned long flags;
- u32 value;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
outl(reg, chip->io_port + ASSP_INDEX);
- value = inl(chip->io_port + ASSP_DATA);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- return value;
+ return inl(chip->io_port + ASSP_DATA);
}
#endif
static void wave_set_register(struct es1968 *chip, u16 reg, u16 value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
outw(reg, chip->io_port + WC_INDEX);
outw(value, chip->io_port + WC_DATA);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static u16 wave_get_register(struct es1968 *chip, u16 reg)
{
- unsigned long flags;
- u16 value;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
outw(reg, chip->io_port + WC_INDEX);
- value = inw(chip->io_port + WC_DATA);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- return value;
+ return inw(chip->io_port + WC_DATA);
}
/* *******************
@@ -930,7 +894,7 @@ static inline void snd_es1968_trigger_apu(struct es1968 *esm, int apu, int mode)
static void snd_es1968_pcm_start(struct es1968 *chip, struct esschan *es)
{
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
__apu_set_register(chip, es->apu[0], 5, es->base[0]);
snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]);
if (es->mode == ESM_MODE_CAPTURE) {
@@ -945,19 +909,17 @@ static void snd_es1968_pcm_start(struct es1968 *chip, struct esschan *es)
snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]);
}
}
- spin_unlock(&chip->reg_lock);
}
static void snd_es1968_pcm_stop(struct es1968 *chip, struct esschan *es)
{
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
snd_es1968_trigger_apu(chip, es->apu[0], 0);
snd_es1968_trigger_apu(chip, es->apu[1], 0);
if (es->mode == ESM_MODE_CAPTURE) {
snd_es1968_trigger_apu(chip, es->apu[2], 0);
snd_es1968_trigger_apu(chip, es->apu[3], 0);
}
- spin_unlock(&chip->reg_lock);
}
/* set the wavecache control reg */
@@ -976,9 +938,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es
/* set the wavecache control reg */
wave_set_register(chip, es->apu[channel] << 3, tmpval);
-#ifdef CONFIG_PM_SLEEP
es->wc_map[channel] = tmpval;
-#endif
}
@@ -989,7 +949,6 @@ static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es,
int high_apu = 0;
int channel, apu;
int i, size;
- unsigned long flags;
u32 freq;
size = es->dma_size >> es->wav_shift;
@@ -1059,12 +1018,12 @@ static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es,
apu_set_register(chip, apu, 10, 0x8F08);
}
- spin_lock_irqsave(&chip->reg_lock, flags);
- /* clear WP interrupts */
- outw(1, chip->io_port + 0x04);
- /* enable WP ints */
- outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ /* clear WP interrupts */
+ outw(1, chip->io_port + 0x04);
+ /* enable WP ints */
+ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);
+ }
freq = runtime->rate;
/* set frequency */
@@ -1135,7 +1094,6 @@ static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es,
{
int size;
u32 freq;
- unsigned long flags;
size = es->dma_size >> es->wav_shift;
@@ -1187,12 +1145,11 @@ static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es,
snd_es1968_apu_set_freq(chip, es->apu[2], freq);
snd_es1968_apu_set_freq(chip, es->apu[3], freq);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
/* clear WP interrupts */
outw(1, chip->io_port + 0x04);
/* enable WP ints */
outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
/*******************
@@ -1236,7 +1193,7 @@ static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct es1968 *chip = snd_pcm_substream_chip(substream);
struct esschan *es = substream->runtime->private_data;
- spin_lock(&chip->substream_lock);
+ guard(spinlock)(&chip->substream_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -1257,7 +1214,6 @@ static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_es1968_bob_dec(chip);
break;
}
- spin_unlock(&chip->substream_lock);
return 0;
}
@@ -1326,12 +1282,11 @@ static int calc_available_memory_size(struct es1968 *chip)
int max_size = 0;
struct esm_memory *buf;
- mutex_lock(&chip->memory_mutex);
+ guard(mutex)(&chip->memory_mutex);
list_for_each_entry(buf, &chip->buf_list, list) {
if (buf->empty && buf->buf.bytes > max_size)
max_size = buf->buf.bytes;
}
- mutex_unlock(&chip->memory_mutex);
if (max_size >= 128*1024)
max_size = 127*1024;
return max_size;
@@ -1343,21 +1298,18 @@ static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size)
struct esm_memory *buf;
size = ALIGN(size, ESM_MEM_ALIGN);
- mutex_lock(&chip->memory_mutex);
+ guard(mutex)(&chip->memory_mutex);
list_for_each_entry(buf, &chip->buf_list, list) {
if (buf->empty && buf->buf.bytes >= size)
goto __found;
}
- mutex_unlock(&chip->memory_mutex);
return NULL;
__found:
if (buf->buf.bytes > size) {
struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL);
- if (chunk == NULL) {
- mutex_unlock(&chip->memory_mutex);
+ if (chunk == NULL)
return NULL;
- }
chunk->buf = buf->buf;
chunk->buf.bytes -= size;
chunk->buf.area += size;
@@ -1367,7 +1319,6 @@ __found:
list_add(&chunk->list, &buf->list);
}
buf->empty = 0;
- mutex_unlock(&chip->memory_mutex);
return buf;
}
@@ -1376,7 +1327,7 @@ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf)
{
struct esm_memory *chunk;
- mutex_lock(&chip->memory_mutex);
+ guard(mutex)(&chip->memory_mutex);
buf->empty = 1;
if (buf->list.prev != &chip->buf_list) {
chunk = list_entry(buf->list.prev, struct esm_memory, list);
@@ -1395,7 +1346,6 @@ static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf)
kfree(chunk);
}
}
- mutex_unlock(&chip->memory_mutex);
}
static void snd_es1968_free_dmabuf(struct es1968 *chip)
@@ -1557,9 +1507,8 @@ static int snd_es1968_playback_open(struct snd_pcm_substream *substream)
runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =
calc_available_memory_size(chip);
- spin_lock_irq(&chip->substream_lock);
+ guard(spinlock_irq)(&chip->substream_lock);
list_add(&es->list, &chip->substream_list);
- spin_unlock_irq(&chip->substream_lock);
return 0;
}
@@ -1569,7 +1518,7 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct es1968 *chip = snd_pcm_substream_chip(substream);
struct esschan *es;
- int apu1, apu2;
+ int err, apu1, apu2;
apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE);
if (apu1 < 0)
@@ -1613,11 +1562,12 @@ static int snd_es1968_capture_open(struct snd_pcm_substream *substream)
runtime->hw = snd_es1968_capture;
runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =
calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */
- snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
+ if (err < 0)
+ return err;
- spin_lock_irq(&chip->substream_lock);
+ guard(spinlock_irq)(&chip->substream_lock);
list_add(&es->list, &chip->substream_list);
- spin_unlock_irq(&chip->substream_lock);
return 0;
}
@@ -1630,9 +1580,9 @@ static int snd_es1968_playback_close(struct snd_pcm_substream *substream)
if (substream->runtime->private_data == NULL)
return 0;
es = substream->runtime->private_data;
- spin_lock_irq(&chip->substream_lock);
- list_del(&es->list);
- spin_unlock_irq(&chip->substream_lock);
+ scoped_guard(spinlock_irq, &chip->substream_lock) {
+ list_del(&es->list);
+ }
snd_es1968_free_apu_pair(chip, es->apu[0]);
kfree(es);
@@ -1647,9 +1597,9 @@ static int snd_es1968_capture_close(struct snd_pcm_substream *substream)
if (substream->runtime->private_data == NULL)
return 0;
es = substream->runtime->private_data;
- spin_lock_irq(&chip->substream_lock);
- list_del(&es->list);
- spin_unlock_irq(&chip->substream_lock);
+ scoped_guard(spinlock_irq, &chip->substream_lock) {
+ list_del(&es->list);
+ }
snd_es1968_free_memory(chip, es->mixbuf);
snd_es1968_free_apu_pair(chip, es->apu[0]);
snd_es1968_free_apu_pair(chip, es->apu[2]);
@@ -1730,29 +1680,29 @@ static void es1968_measure_clock(struct es1968 *chip)
apu_set_register(chip, apu, 9, 0xD000);
apu_set_register(chip, apu, 10, 0x8F08);
apu_set_register(chip, apu, 11, 0x0000);
- spin_lock_irq(&chip->reg_lock);
- outw(1, chip->io_port + 0x04); /* clear WP interrupts */
- outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ outw(1, chip->io_port + 0x04); /* clear WP interrupts */
+ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */
+ }
snd_es1968_apu_set_freq(chip, apu, ((unsigned int)48000 << 16) / chip->clock); /* 48000 Hz */
chip->in_measurement = 1;
chip->measure_apu = apu;
- spin_lock_irq(&chip->reg_lock);
- snd_es1968_bob_inc(chip, ESM_BOB_FREQ);
- __apu_set_register(chip, apu, 5, pa & 0xffff);
- snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);
- start_time = ktime_get();
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ snd_es1968_bob_inc(chip, ESM_BOB_FREQ);
+ __apu_set_register(chip, apu, 5, pa & 0xffff);
+ snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);
+ start_time = ktime_get();
+ }
msleep(50);
- spin_lock_irq(&chip->reg_lock);
- offset = __apu_get_register(chip, apu, 5);
- stop_time = ktime_get();
- snd_es1968_trigger_apu(chip, apu, 0); /* stop */
- snd_es1968_bob_dec(chip);
- chip->in_measurement = 0;
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ offset = __apu_get_register(chip, apu, 5);
+ stop_time = ktime_get();
+ snd_es1968_trigger_apu(chip, apu, 0); /* stop */
+ snd_es1968_bob_dec(chip);
+ chip->in_measurement = 0;
+ }
/* check the current position */
offset -= (pa & 0xffff);
@@ -1818,7 +1768,7 @@ snd_es1968_pcm(struct es1968 *chip, int device)
pcm->info_flags = 0;
- strcpy(pcm->name, "ESS Maestro");
+ strscpy(pcm->name, "ESS Maestro");
chip->pcm = pcm;
@@ -1976,15 +1926,15 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
if (event & ESM_SOUND_IRQ) {
struct esschan *es;
- spin_lock(&chip->substream_lock);
- list_for_each_entry(es, &chip->substream_list, list) {
- if (es->running) {
- snd_es1968_update_pcm(chip, es);
- if (es->fmt & ESS_FMT_STEREO)
- snd_es1968_suppress_jitter(chip, es);
+ scoped_guard(spinlock, &chip->substream_lock) {
+ list_for_each_entry(es, &chip->substream_list, list) {
+ if (es->running) {
+ snd_es1968_update_pcm(chip, es);
+ if (es->fmt & ESS_FMT_STEREO)
+ snd_es1968_suppress_jitter(chip, es);
+ }
}
}
- spin_unlock(&chip->substream_lock);
if (chip->in_measurement) {
unsigned int curp = __apu_get_register(chip, chip->measure_apu, 5);
if (curp < chip->measure_lastpos)
@@ -2005,9 +1955,6 @@ snd_es1968_mixer(struct es1968 *chip)
{
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
-#ifndef CONFIG_SND_ES1968_INPUT
- struct snd_ctl_elem_id elem_id;
-#endif
int err;
static const struct snd_ac97_bus_ops ops = {
.write = snd_es1968_ac97_write,
@@ -2027,14 +1974,10 @@ snd_es1968_mixer(struct es1968 *chip)
#ifndef CONFIG_SND_ES1968_INPUT
/* attach master switch / volumes for h/w volume control */
- memset(&elem_id, 0, sizeof(elem_id));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(elem_id.name, "Master Playback Switch");
- chip->master_switch = snd_ctl_find_id(chip->card, &elem_id);
- memset(&elem_id, 0, sizeof(elem_id));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(elem_id.name, "Master Playback Volume");
- chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
+ chip->master_switch = snd_ctl_find_id_mixer(chip->card,
+ "Master Playback Switch");
+ chip->master_volume = snd_ctl_find_id_mixer(chip->card,
+ "Master Playback Volume");
#endif
return 0;
@@ -2363,7 +2306,6 @@ static void snd_es1968_start_irq(struct es1968 *chip)
outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
}
-#ifdef CONFIG_PM_SLEEP
/*
* PM support
*/
@@ -2425,11 +2367,7 @@ static int es1968_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
-#define ES1968_PM_OPS &es1968_pm
-#else
-#define ES1968_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
#ifdef SUPPORT_JOYSTICK
#define JOYSTICK_ADDR 0x200
@@ -2667,7 +2605,7 @@ static int snd_es1968_create(struct snd_card *card,
chip->playback_streams = play_streams;
chip->capture_streams = capt_streams;
- err = pci_request_regions(pci, "ESS Maestro");
+ err = pcim_request_all_regions(pci, "ESS Maestro");
if (err < 0)
return err;
chip->io_port = pci_resource_start(pci, 0);
@@ -2779,16 +2717,16 @@ static int __snd_es1968_probe(struct pci_dev *pci,
switch (chip->type) {
case TYPE_MAESTRO2E:
- strcpy(card->driver, "ES1978");
- strcpy(card->shortname, "ESS ES1978 (Maestro 2E)");
+ strscpy(card->driver, "ES1978");
+ strscpy(card->shortname, "ESS ES1978 (Maestro 2E)");
break;
case TYPE_MAESTRO2:
- strcpy(card->driver, "ES1968");
- strcpy(card->shortname, "ESS ES1968 (Maestro 2)");
+ strscpy(card->driver, "ES1968");
+ strscpy(card->shortname, "ESS ES1968 (Maestro 2)");
break;
case TYPE_MAESTRO:
- strcpy(card->driver, "ESM1");
- strcpy(card->shortname, "ESS Maestro 1");
+ strscpy(card->driver, "ESM1");
+ strscpy(card->shortname, "ESS Maestro 1");
break;
}
@@ -2859,7 +2797,7 @@ static struct pci_driver es1968_driver = {
.id_table = snd_es1968_ids,
.probe = snd_es1968_probe,
.driver = {
- .pm = ES1968_PM_OPS,
+ .pm = &es1968_pm,
},
};
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 62b3cb126c6d..4ca992449ea3 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -222,9 +222,7 @@ struct fm801 {
struct snd_tea575x tea;
#endif
-#ifdef CONFIG_PM_SLEEP
u16 saved_regs[0x20];
-#endif
};
/*
@@ -281,16 +279,14 @@ static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg,
unsigned short mask, unsigned short value)
{
int change;
- unsigned long flags;
unsigned short old, new;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
old = fm801_ioread16(chip, reg);
new = (old & ~mask) | value;
change = old != new;
if (change)
fm801_iowrite16(chip, reg, new);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return change;
}
@@ -395,7 +391,7 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream,
{
struct fm801 *chip = snd_pcm_substream_chip(substream);
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
chip->ply_ctrl &= ~(FM801_BUF1_LAST |
@@ -416,12 +412,10 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream,
chip->ply_ctrl &= ~FM801_PAUSE;
break;
default:
- spin_unlock(&chip->reg_lock);
snd_BUG();
return -EINVAL;
}
fm801_writew(chip, PLY_CTRL, chip->ply_ctrl);
- spin_unlock(&chip->reg_lock);
return 0;
}
@@ -430,7 +424,7 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream,
{
struct fm801 *chip = snd_pcm_substream_chip(substream);
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
chip->cap_ctrl &= ~(FM801_BUF1_LAST |
@@ -451,12 +445,10 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream,
chip->cap_ctrl &= ~FM801_PAUSE;
break;
default:
- spin_unlock(&chip->reg_lock);
snd_BUG();
return -EINVAL;
}
fm801_writew(chip, CAP_CTRL, chip->cap_ctrl);
- spin_unlock(&chip->reg_lock);
return 0;
}
@@ -467,7 +459,7 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream)
chip->ply_size = snd_pcm_lib_buffer_bytes(substream);
chip->ply_count = snd_pcm_lib_period_bytes(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->ply_ctrl &= ~(FM801_START | FM801_16BIT |
FM801_STEREO | FM801_RATE_MASK |
FM801_CHANNELS_MASK);
@@ -489,7 +481,6 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream)
fm801_writel(chip, PLY_BUF1, chip->ply_buffer);
fm801_writel(chip, PLY_BUF2,
chip->ply_buffer + (chip->ply_count % chip->ply_size));
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -500,7 +491,7 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream)
chip->cap_size = snd_pcm_lib_buffer_bytes(substream);
chip->cap_count = snd_pcm_lib_period_bytes(substream);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->cap_ctrl &= ~(FM801_START | FM801_16BIT |
FM801_STEREO | FM801_RATE_MASK);
if (snd_pcm_format_width(runtime->format) == 16)
@@ -516,7 +507,6 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream)
fm801_writel(chip, CAP_BUF1, chip->cap_buffer);
fm801_writel(chip, CAP_BUF2,
chip->cap_buffer + (chip->cap_count % chip->cap_size));
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -527,13 +517,12 @@ static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *su
if (!(chip->ply_ctrl & FM801_START))
return 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
ptr = chip->ply_pos + (chip->ply_count - 1) - fm801_readw(chip, PLY_COUNT);
if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_PLAYBACK) {
ptr += chip->ply_count;
ptr %= chip->ply_size;
}
- spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, ptr);
}
@@ -544,13 +533,12 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub
if (!(chip->cap_ctrl & FM801_START))
return 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
ptr = chip->cap_pos + (chip->cap_count - 1) - fm801_readw(chip, CAP_COUNT);
if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_CAPTURE) {
ptr += chip->cap_count;
ptr %= chip->cap_size;
}
- spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, ptr);
}
@@ -567,31 +555,31 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
/* ack first */
fm801_writew(chip, IRQ_STATUS, status);
if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) {
- spin_lock(&chip->reg_lock);
- chip->ply_buf++;
- chip->ply_pos += chip->ply_count;
- chip->ply_pos %= chip->ply_size;
- tmp = chip->ply_pos + chip->ply_count;
- tmp %= chip->ply_size;
- if (chip->ply_buf & 1)
- fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp);
- else
- fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ chip->ply_buf++;
+ chip->ply_pos += chip->ply_count;
+ chip->ply_pos %= chip->ply_size;
+ tmp = chip->ply_pos + chip->ply_count;
+ tmp %= chip->ply_size;
+ if (chip->ply_buf & 1)
+ fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp);
+ else
+ fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp);
+ }
snd_pcm_period_elapsed(chip->playback_substream);
}
if (chip->pcm && (status & FM801_IRQ_CAPTURE) && chip->capture_substream) {
- spin_lock(&chip->reg_lock);
- chip->cap_buf++;
- chip->cap_pos += chip->cap_count;
- chip->cap_pos %= chip->cap_size;
- tmp = chip->cap_pos + chip->cap_count;
- tmp %= chip->cap_size;
- if (chip->cap_buf & 1)
- fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp);
- else
- fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ chip->cap_buf++;
+ chip->cap_pos += chip->cap_count;
+ chip->cap_pos %= chip->cap_size;
+ tmp = chip->cap_pos + chip->cap_count;
+ tmp %= chip->cap_size;
+ if (chip->cap_buf & 1)
+ fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp);
+ else
+ fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp);
+ }
snd_pcm_period_elapsed(chip->capture_substream);
}
if (chip->rmidi && (status & FM801_IRQ_MPU))
@@ -728,7 +716,7 @@ static int snd_fm801_pcm(struct fm801 *chip, int device)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, "FM801");
+ strscpy(pcm->name, "FM801");
chip->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &pdev->dev,
@@ -926,10 +914,9 @@ static int snd_fm801_get_double(struct snd_kcontrol *kcontrol,
int invert = (kcontrol->private_value >> 24) & 0xff;
long *value = ucontrol->value.integer.value;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
value[0] = (fm801_ioread16(chip, reg) >> shift_left) & mask;
value[1] = (fm801_ioread16(chip, reg) >> shift_right) & mask;
- spin_unlock_irq(&chip->reg_lock);
if (invert) {
value[0] = mask - value[0];
value[1] = mask - value[1];
@@ -1193,7 +1180,7 @@ static int snd_fm801_create(struct snd_card *card,
chip->dev = &pci->dev;
chip->irq = -1;
chip->tea575x_tuner = tea575x_tuner;
- err = pci_request_regions(pci, "FM801");
+ err = pcim_request_all_regions(pci, "FM801");
if (err < 0)
return err;
chip->port = pci_resource_start(pci, 0);
@@ -1293,8 +1280,8 @@ static int __snd_card_fm801_probe(struct pci_dev *pci,
if (err < 0)
return err;
- strcpy(card->driver, "FM801");
- strcpy(card->shortname, "ForteMedia FM801-");
+ strscpy(card->driver, "FM801");
+ strscpy(card->shortname, "ForteMedia FM801-");
strcat(card->shortname, chip->multichannel ? "AU" : "AS");
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, chip->port, chip->irq);
@@ -1339,7 +1326,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
return snd_card_free_on_error(&pci->dev, __snd_card_fm801_probe(pci, pci_id));
}
-#ifdef CONFIG_PM_SLEEP
static const unsigned char saved_regs[] = {
FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,
FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2,
@@ -1396,18 +1382,14 @@ static int snd_fm801_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
-#define SND_FM801_PM_OPS &snd_fm801_pm
-#else
-#define SND_FM801_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
static struct pci_driver fm801_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_fm801_ids,
.probe = snd_card_fm801_probe,
.driver = {
- .pm = SND_FM801_PM_OPS,
+ .pm = &snd_fm801_pm,
},
};
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
deleted file mode 100644
index 886255a03e8b..000000000000
--- a/sound/pci/hda/Kconfig
+++ /dev/null
@@ -1,321 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-menu "HD-Audio"
-
-config SND_HDA
- tristate
- select SND_PCM
- select SND_VMASTER
- select SND_JACK
- select SND_HDA_CORE
-
-config SND_HDA_GENERIC_LEDS
- bool
-
-config SND_HDA_INTEL
- tristate "HD Audio PCI"
- depends on SND_PCI
- select SND_HDA
- select SND_INTEL_DSP_CONFIG
- help
- Say Y here to include support for Intel "High Definition
- Audio" (Azalia) and its compatible devices.
-
- This option enables the HD-audio controller. Don't forget
- to choose the appropriate codec options below.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-hda-intel.
-
-config SND_HDA_TEGRA
- tristate "NVIDIA Tegra HD Audio"
- depends on ARCH_TEGRA
- select SND_HDA
- select SND_HDA_ALIGNED_MMIO
- help
- Say Y here to support the HDA controller present in NVIDIA
- Tegra SoCs
-
- This options enables support for the HD Audio controller
- present in some NVIDIA Tegra SoCs, used to communicate audio
- to the HDMI output.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-hda-tegra.
-
-if SND_HDA
-
-config SND_HDA_HWDEP
- bool "Build hwdep interface for HD-audio driver"
- select SND_HWDEP
- help
- Say Y here to build a hwdep interface for HD-audio driver.
- This interface can be used for out-of-band communication
- with codecs for debugging purposes.
-
-config SND_HDA_RECONFIG
- bool "Allow dynamic codec reconfiguration"
- help
- Say Y here to enable the HD-audio codec re-configuration feature.
- It allows user to clear the whole codec configuration, change the
- codec setup, add extra verbs, and re-configure the codec dynamically.
-
- Note that this item alone doesn't provide the sysfs interface, but
- enables the feature just for the patch loader below.
- If you need the traditional sysfs entries for the manual interaction,
- turn on CONFIG_SND_HDA_HWDEP as well.
-
-config SND_HDA_INPUT_BEEP
- bool "Support digital beep via input layer"
- depends on INPUT=y || INPUT=SND_HDA
- help
- Say Y here to build a digital beep interface for HD-audio
- driver. This interface is used to generate digital beeps.
-
-config SND_HDA_INPUT_BEEP_MODE
- int "Digital beep registration mode (0=off, 1=on)"
- depends on SND_HDA_INPUT_BEEP=y
- default "1"
- range 0 1
- help
- Set 0 to disable the digital beep interface for HD-audio by default.
- Set 1 to always enable the digital beep interface for HD-audio by
- default.
-
-config SND_HDA_PATCH_LOADER
- bool "Support initialization patch loading for HD-audio"
- select FW_LOADER
- select SND_HDA_RECONFIG
- help
- Say Y here to allow the HD-audio driver to load a pseudo
- firmware file ("patch") for overriding the BIOS setup at
- start up. The "patch" file can be specified via patch module
- option, such as patch=hda-init.
-
-config SND_HDA_SCODEC_CS35L41
- tristate
- select SND_HDA_GENERIC
- select REGMAP_IRQ
-
-config SND_HDA_CS_DSP_CONTROLS
- tristate
- select FW_CS_DSP
-
-config SND_HDA_SCODEC_CS35L41_I2C
- tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
- depends on I2C
- depends on ACPI
- depends on SND_SOC
- select SND_SOC_CS35L41_LIB
- select SND_HDA_SCODEC_CS35L41
- select SND_HDA_CS_DSP_CONTROLS
- help
- Say Y or M here to include CS35L41 I2C HD-audio side codec support
- in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
- depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m
-
-config SND_HDA_SCODEC_CS35L41_SPI
- tristate "Build CS35L41 HD-audio codec support for SPI Bus"
- depends on SPI_MASTER
- depends on ACPI
- depends on SND_SOC
- select SND_SOC_CS35L41_LIB
- select SND_HDA_SCODEC_CS35L41
- select SND_HDA_CS_DSP_CONTROLS
- help
- Say Y or M here to include CS35L41 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_CS35L41_SPI=m
-
-config SND_HDA_CODEC_REALTEK
- tristate "Build Realtek HD-audio codec support"
- select SND_HDA_GENERIC
- select SND_HDA_GENERIC_LEDS
- help
- Say Y or M here to include Realtek HD-audio codec support in
- snd-hda-intel driver, such as ALC880.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
-
-config SND_HDA_CODEC_ANALOG
- tristate "Build Analog Devices HD-audio codec support"
- select SND_HDA_GENERIC
- help
- Say Y or M here to include Analog Devices HD-audio codec support in
- snd-hda-intel driver, such as AD1986A.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m
-
-config SND_HDA_CODEC_SIGMATEL
- tristate "Build IDT/Sigmatel HD-audio codec support"
- select SND_HDA_GENERIC
- select SND_HDA_GENERIC_LEDS
- help
- Say Y or M here to include IDT (Sigmatel) HD-audio codec support in
- snd-hda-intel driver, such as STAC9200.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m
-
-config SND_HDA_CODEC_VIA
- tristate "Build VIA HD-audio codec support"
- select SND_HDA_GENERIC
- help
- Say Y or M here to include VIA HD-audio codec support in
- snd-hda-intel driver, such as VT1708.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
-
-config SND_HDA_CODEC_HDMI
- tristate "Build HDMI/DisplayPort HD-audio codec support"
- select SND_DYNAMIC_MINORS
- 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,
- Intel and Nvidia HDMI/DisplayPort codecs.
-
- Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS
- to assure the multiple streams for DP-MST support.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
-
-config SND_HDA_CODEC_CIRRUS
- tristate "Build Cirrus Logic codec support"
- select SND_HDA_GENERIC
- help
- Say Y or M here to include Cirrus Logic codec support in
- snd-hda-intel driver, such as CS4206.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
-
-config SND_HDA_CODEC_CS8409
- tristate "Build Cirrus Logic HDA bridge support"
- select SND_HDA_GENERIC
- help
- Say Y or M here to include Cirrus Logic HDA bridge support in
- snd-hda-intel driver, such as CS8409.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m
-
-config SND_HDA_CODEC_CONEXANT
- tristate "Build Conexant HD-audio codec support"
- select SND_HDA_GENERIC
- select SND_HDA_GENERIC_LEDS
- help
- Say Y or M here to include Conexant HD-audio codec support in
- snd-hda-intel driver, such as CX20549.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
-
-config SND_HDA_CODEC_CA0110
- tristate "Build Creative CA0110-IBG codec support"
- select SND_HDA_GENERIC
- help
- Say Y or M here to include Creative CA0110-IBG codec support in
- snd-hda-intel driver, found on some Creative X-Fi cards.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m
-
-config SND_HDA_CODEC_CA0132
- tristate "Build Creative CA0132 codec support"
- help
- Say Y or M here to include Creative CA0132 codec support in
- snd-hda-intel driver.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m
-
-config SND_HDA_CODEC_CA0132_DSP
- bool "Support new DSP code for CA0132 codec"
- depends on SND_HDA_CODEC_CA0132
- default y
- select SND_HDA_DSP_LOADER
- select FW_LOADER
- help
- Say Y here to enable the DSP for Creative CA0132 for extended
- features like equalizer or echo cancellation.
-
- Note that this option requires the external firmware file
- (ctefx.bin).
-
-config SND_HDA_CODEC_CMEDIA
- tristate "Build C-Media HD-audio codec support"
- select SND_HDA_GENERIC
- help
- Say Y or M here to include C-Media HD-audio codec support in
- snd-hda-intel driver, such as CMI9880.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
-
-config SND_HDA_CODEC_SI3054
- tristate "Build Silicon Labs 3054 HD-modem codec support"
- help
- Say Y or M here to include Silicon Labs 3054 HD-modem codec
- (and compatibles) support in snd-hda-intel driver.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m
-
-config SND_HDA_GENERIC
- tristate "Enable generic HD-audio codec parser"
- select SND_CTL_LED if SND_HDA_GENERIC_LEDS
- select LEDS_CLASS if SND_HDA_GENERIC_LEDS
- help
- Say Y or M here to enable the generic HD-audio codec parser
- in snd-hda-intel driver.
-
-comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA=y && SND_HDA_GENERIC=m
-
-config SND_HDA_POWER_SAVE_DEFAULT
- int "Default time-out for HD-audio power-save mode"
- depends on PM
- default 0
- help
- The default time-out value in seconds for HD-audio automatic
- power-save mode. 0 means to disable the power-save mode.
-
-config SND_HDA_INTEL_HDMI_SILENT_STREAM
- bool "Enable Silent Stream always for HDMI"
- depends on SND_HDA_INTEL
- help
- Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
- for HDMI on hardware that supports the feature.
-
- When enabled, the HDMI/DisplayPort codec will continue to provide
- a continuous clock and a valid but silent data stream to
- any connected external receiver. This allows to avoid gaps
- at start of playback. Many receivers require multiple seconds
- to start playing audio after the clock has been stopped.
- This feature can impact power consumption as resources
- are kept reserved both at transmitter and receiver.
-
-config SND_HDA_CTL_DEV_ID
- bool "Use the device identifier field for controls"
- depends on SND_HDA_INTEL
- help
- Say Y to use the device identifier field for (mixer)
- controls (old behaviour until this option is available).
-
- When enabled, the multiple HDA codecs may set the device
- field in control (mixer) element identifiers. The use
- of this field is not recommended and defined for mixer controls.
-
- The old behaviour (Y) is obsolete and will be removed. Consider
- to not enable this option.
-
-endif
-
-endmenu
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
deleted file mode 100644
index 00d306104484..000000000000
--- a/sound/pci/hda/Makefile
+++ /dev/null
@@ -1,64 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-snd-hda-intel-objs := hda_intel.o
-snd-hda-tegra-objs := hda_tegra.o
-
-snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
-snd-hda-codec-y += hda_controller.o
-snd-hda-codec-$(CONFIG_SND_PROC_FS) += hda_proc.o
-
-snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
-snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
-
-# for trace-points
-CFLAGS_hda_controller.o := -I$(src)
-CFLAGS_hda_intel.o := -I$(src)
-
-snd-hda-codec-generic-objs := hda_generic.o
-snd-hda-codec-realtek-objs := patch_realtek.o
-snd-hda-codec-cmedia-objs := patch_cmedia.o
-snd-hda-codec-analog-objs := patch_analog.o
-snd-hda-codec-idt-objs := patch_sigmatel.o
-snd-hda-codec-si3054-objs := patch_si3054.o
-snd-hda-codec-cirrus-objs := patch_cirrus.o
-snd-hda-codec-cs8409-objs := patch_cs8409.o patch_cs8409-tables.o
-snd-hda-codec-ca0110-objs := patch_ca0110.o
-snd-hda-codec-ca0132-objs := patch_ca0132.o
-snd-hda-codec-conexant-objs := patch_conexant.o
-snd-hda-codec-via-objs := patch_via.o
-snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
-
-# side codecs
-snd-hda-scodec-cs35l41-objs := cs35l41_hda.o
-snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o
-snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o
-snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o
-
-# common driver
-obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
-
-# codec drivers
-obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
-obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
-obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
-obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
-obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
-obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
-obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
-obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
-obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
-obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
-obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
-obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
-obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
-
-# side codecs
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
-obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
-
-# this must be the last entry after codec drivers;
-# otherwise the codec patches won't be hooked before the PCI probe
-# when built in kernel
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
-obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h
deleted file mode 100644
index 534e845b9cd1..000000000000
--- a/sound/pci/hda/hda_component.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * HD audio Component Binding Interface
- *
- * Copyright (C) 2021 Cirrus Logic, Inc. and
- * Cirrus Logic International Semiconductor Ltd.
- */
-
-#include <linux/component.h>
-
-#define HDA_MAX_COMPONENTS 4
-#define HDA_MAX_NAME_SIZE 50
-
-struct hda_component {
- struct device *dev;
- char name[HDA_MAX_NAME_SIZE];
- struct hda_codec *codec;
- void (*playback_hook)(struct device *dev, int action);
-};
diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c
deleted file mode 100644
index 463ca06036bf..000000000000
--- a/sound/pci/hda/hda_cs_dsp_ctl.c
+++ /dev/null
@@ -1,252 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// HDA DSP ALSA Control Driver
-//
-// Copyright 2022 Cirrus Logic, Inc.
-//
-// Author: Stefan Binding <sbinding@opensource.cirrus.com>
-
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <linux/firmware/cirrus/cs_dsp.h>
-#include <linux/firmware/cirrus/wmfw.h>
-#include "hda_cs_dsp_ctl.h"
-
-#define ADSP_MAX_STD_CTRL_SIZE 512
-
-struct hda_cs_dsp_coeff_ctl {
- struct cs_dsp_coeff_ctl *cs_ctl;
- struct snd_card *card;
- struct snd_kcontrol *kctl;
-};
-
-static const char * const hda_cs_dsp_fw_text[HDA_CS_DSP_NUM_FW] = {
- [HDA_CS_DSP_FW_SPK_PROT] = "Prot",
- [HDA_CS_DSP_FW_SPK_CALI] = "Cali",
- [HDA_CS_DSP_FW_SPK_DIAG] = "Diag",
- [HDA_CS_DSP_FW_MISC] = "Misc",
-};
-
-const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW] = {
- [HDA_CS_DSP_FW_SPK_PROT] = "spk-prot",
- [HDA_CS_DSP_FW_SPK_CALI] = "spk-cali",
- [HDA_CS_DSP_FW_SPK_DIAG] = "spk-diag",
- [HDA_CS_DSP_FW_MISC] = "misc",
-};
-EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_fw_ids, SND_HDA_CS_DSP_CONTROLS);
-
-static int hda_cs_dsp_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
-{
- struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl);
- struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- uinfo->count = cs_ctl->len;
-
- return 0;
-}
-
-static int hda_cs_dsp_coeff_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl);
- struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
- char *p = ucontrol->value.bytes.data;
- int ret = 0;
-
- mutex_lock(&cs_ctl->dsp->pwr_lock);
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len);
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
-
- return ret;
-}
-
-static int hda_cs_dsp_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl);
- struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
- char *p = ucontrol->value.bytes.data;
- int ret;
-
- mutex_lock(&cs_ctl->dsp->pwr_lock);
- ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len);
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
-
- return ret;
-}
-
-static unsigned int wmfw_convert_flags(unsigned int in)
-{
- unsigned int out, rd, wr, vol;
-
- rd = SNDRV_CTL_ELEM_ACCESS_READ;
- wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
- vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
-
- out = 0;
-
- if (in) {
- out |= rd;
- if (in & WMFW_CTL_FLAG_WRITEABLE)
- out |= wr;
- if (in & WMFW_CTL_FLAG_VOLATILE)
- out |= vol;
- } else {
- out |= rd | wr | vol;
- }
-
- return out;
-}
-
-static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name)
-{
- struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
- struct snd_kcontrol_new kcontrol = {0};
- struct snd_kcontrol *kctl;
- int ret = 0;
-
- if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) {
- dev_err(cs_ctl->dsp->dev, "KControl %s: length %zu exceeds maximum %d\n", name,
- cs_ctl->len, ADSP_MAX_STD_CTRL_SIZE);
- return;
- }
-
- kcontrol.name = name;
- kcontrol.info = hda_cs_dsp_coeff_info;
- kcontrol.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kcontrol.access = wmfw_convert_flags(cs_ctl->flags);
- kcontrol.get = hda_cs_dsp_coeff_get;
- kcontrol.put = hda_cs_dsp_coeff_put;
-
- /* Save ctl inside private_data, ctl is owned by cs_dsp,
- * and will be freed when cs_dsp removes the control */
- kctl = snd_ctl_new1(&kcontrol, (void *)ctl);
- if (!kctl)
- return;
-
- ret = snd_ctl_add(ctl->card, kctl);
- if (ret) {
- dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret);
- return;
- }
-
- dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name);
- ctl->kctl = kctl;
-}
-
-static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl,
- const struct hda_cs_dsp_ctl_info *info)
-{
- struct cs_dsp *cs_dsp = cs_ctl->dsp;
- char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
- struct hda_cs_dsp_coeff_ctl *ctl;
- const char *region_name;
- int ret;
-
- region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
- if (!region_name) {
- dev_warn(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type);
- return;
- }
-
- ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %.12s %x", info->device_name,
- cs_dsp->name, hda_cs_dsp_fw_text[info->fw_type], cs_ctl->alg_region.alg);
-
- if (cs_ctl->subname) {
- int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
- int skip = 0;
-
- /* Truncate the subname from the start if it is too long */
- if (cs_ctl->subname_len > avail)
- skip = cs_ctl->subname_len - avail;
-
- snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
- " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip);
- }
-
- ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
- if (!ctl)
- return;
-
- ctl->cs_ctl = cs_ctl;
- ctl->card = info->card;
- cs_ctl->priv = ctl;
-
- hda_cs_dsp_add_kcontrol(ctl, name);
-}
-
-void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info)
-{
- struct cs_dsp_coeff_ctl *cs_ctl;
-
- /*
- * pwr_lock would cause mutex inversion with ALSA control lock compared
- * to the get/put functions.
- * It is safe to walk the list without holding a mutex because entries
- * are persistent and only cs_dsp_power_up() or cs_dsp_remove() can
- * change the list.
- */
- lockdep_assert_not_held(&dsp->pwr_lock);
-
- list_for_each_entry(cs_ctl, &dsp->ctl_list, list) {
- if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
- continue;
-
- if (cs_ctl->priv)
- continue;
-
- hda_cs_dsp_control_add(cs_ctl, info);
- }
-}
-EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_add_controls, SND_HDA_CS_DSP_CONTROLS);
-
-void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
-{
- struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv;
-
- kfree(ctl);
-}
-EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS);
-
-int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
- unsigned int alg, const void *buf, size_t len)
-{
- struct cs_dsp_coeff_ctl *cs_ctl;
- struct hda_cs_dsp_coeff_ctl *ctl;
- int ret;
-
- mutex_lock(&dsp->pwr_lock);
- cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
- mutex_unlock(&dsp->pwr_lock);
- if (ret < 0)
- return ret;
-
- if (ret == 0 || (cs_ctl->flags & WMFW_CTL_FLAG_SYS))
- return 0;
-
- ctl = cs_ctl->priv;
-
- snd_ctl_notify(ctl->card, SNDRV_CTL_EVENT_MASK_VALUE, &ctl->kctl->id);
-
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, SND_HDA_CS_DSP_CONTROLS);
-
-int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type,
- unsigned int alg, void *buf, size_t len)
-{
- int ret;
-
- mutex_lock(&dsp->pwr_lock);
- ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len);
- mutex_unlock(&dsp->pwr_lock);
-
- return ret;
-
-}
-EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS);
-
-MODULE_DESCRIPTION("CS_DSP ALSA Control HDA Library");
-MODULE_AUTHOR("Stefan Binding, <sbinding@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(FW_CS_DSP);
diff --git a/sound/pci/hda/hda_cs_dsp_ctl.h b/sound/pci/hda/hda_cs_dsp_ctl.h
deleted file mode 100644
index 2cf93359c4f2..000000000000
--- a/sound/pci/hda/hda_cs_dsp_ctl.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * HDA DSP ALSA Control Driver
- *
- * Copyright 2022 Cirrus Logic, Inc.
- *
- * Author: Stefan Binding <sbinding@opensource.cirrus.com>
- */
-
-#ifndef __HDA_CS_DSP_CTL_H__
-#define __HDA_CS_DSP_CTL_H__
-
-#include <sound/soc.h>
-#include <linux/firmware/cirrus/cs_dsp.h>
-
-enum hda_cs_dsp_fw_id {
- HDA_CS_DSP_FW_SPK_PROT,
- HDA_CS_DSP_FW_SPK_CALI,
- HDA_CS_DSP_FW_SPK_DIAG,
- HDA_CS_DSP_FW_MISC,
- HDA_CS_DSP_NUM_FW
-};
-
-struct hda_cs_dsp_ctl_info {
- struct snd_card *card;
- enum hda_cs_dsp_fw_id fw_type;
- const char *device_name;
-};
-
-extern const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW];
-
-void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info);
-void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl);
-int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
- unsigned int alg, const void *buf, size_t len);
-int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type,
- unsigned int alg, void *buf, size_t len);
-
-#endif /*__HDA_CS_DSP_CTL_H__*/
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
deleted file mode 100644
index 1d108ed5c6f2..000000000000
--- a/sound/pci/hda/hda_eld.c
+++ /dev/null
@@ -1,771 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Generic routines and proc interface for ELD(EDID Like Data) information
- *
- * Copyright(c) 2008 Intel Corporation.
- * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
- *
- * Authors:
- * Wu Fengguang <wfg@linux.intel.com>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <asm/unaligned.h>
-#include <sound/hda_chmap.h>
-#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,
- CEA_EDID_VER_CEA861A = 2,
- CEA_EDID_VER_CEA861BCD = 3,
- 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)
-{
- unsigned int val;
-
- val = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_HDMI_ELDD, byte_index);
-#ifdef BE_PARANOID
- codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
-#endif
- 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,
- AC_DIPSIZE_ELD_BUF);
-}
-
-int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
- unsigned char *buf, int *eld_size)
-{
- int i;
- int ret = 0;
- int size;
-
- /*
- * ELD size is initialized to zero in caller function. If no errors and
- * ELD is valid, actual eld_size is assigned.
- */
-
- size = snd_hdmi_get_eld_size(codec, nid);
- if (size == 0) {
- /* wfg: workaround for ASUS P5E-VM HDMI board */
- codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
- size = 128;
- }
- if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
- codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
- return -ERANGE;
- }
-
- /* set ELD buffer */
- for (i = 0; i < size; i++) {
- unsigned int val = hdmi_get_eld_data(codec, nid, i);
- /*
- * Graphics driver might be writing to ELD buffer right now.
- * Just abort. The caller will repoll after a while.
- */
- if (!(val & AC_ELDD_ELD_VALID)) {
- codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
- ret = -EINVAL;
- goto error;
- }
- val &= AC_ELDD_ELD_DATA;
- /*
- * The first byte cannot be zero. This can happen on some DVI
- * connections. Some Intel chips may also need some 250ms delay
- * to return non-zero ELD data, even when the graphics driver
- * correctly writes ELD content before setting ELD_valid bit.
- */
- if (!val && !i) {
- codec_dbg(codec, "HDMI: 0 ELD data\n");
- ret = -EINVAL;
- goto error;
- }
- buf[i] = val;
- }
-
- *eld_size = size;
-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);
-}
-
-void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
- struct snd_info_buffer *buffer)
-{
- struct parsed_hdmi_eld *e = &eld->info;
- char line[64];
- char name[64];
- char *sname;
- long long val;
- unsigned int n;
-
- while (!snd_info_get_line(buffer, line, sizeof(line))) {
- if (sscanf(line, "%s %llx", name, &val) != 2)
- continue;
- /*
- * We don't allow modification to these fields:
- * monitor_name manufacture_id product_id
- * eld_version edid_version
- */
- if (!strcmp(name, "monitor_present"))
- eld->monitor_present = val;
- else if (!strcmp(name, "eld_valid"))
- eld->eld_valid = val;
- else if (!strcmp(name, "connection_type"))
- e->conn_type = val;
- else if (!strcmp(name, "port_id"))
- e->port_id = val;
- else if (!strcmp(name, "support_hdcp"))
- e->support_hdcp = val;
- else if (!strcmp(name, "support_ai"))
- e->support_ai = val;
- else if (!strcmp(name, "audio_sync_delay"))
- e->aud_synch_delay = val;
- else if (!strcmp(name, "speakers"))
- e->spk_alloc = val;
- else if (!strcmp(name, "sad_count"))
- e->sad_count = val;
- else if (!strncmp(name, "sad", 3)) {
- sname = name + 4;
- n = name[3] - '0';
- if (name[4] >= '0' && name[4] <= '9') {
- sname++;
- n = 10 * n + name[4] - '0';
- }
- if (n >= ELD_MAX_SAD)
- continue;
- if (!strcmp(sname, "_coding_type"))
- e->sad[n].format = val;
- else if (!strcmp(sname, "_channels"))
- e->sad[n].channels = val;
- else if (!strcmp(sname, "_rates"))
- e->sad[n].rates = val;
- else if (!strcmp(sname, "_bits"))
- e->sad[n].sample_bits = val;
- else if (!strcmp(sname, "_max_bitrate"))
- e->sad[n].max_bitrate = val;
- else if (!strcmp(sname, "_profile"))
- e->sad[n].profile = val;
- if (n >= e->sad_count)
- e->sad_count = n + 1;
- }
- }
-}
-#endif /* CONFIG_SND_PROC_FS */
-
-/* update PCM info based on ELD */
-void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
- struct hda_pcm_stream *hinfo)
-{
- u32 rates;
- u64 formats;
- unsigned int maxbps;
- unsigned int channels_max;
- int i;
-
- /* assume basic audio support (the basic audio flag is not in ELD;
- * however, all audio capable sinks are required to support basic
- * audio) */
- rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000;
- formats = SNDRV_PCM_FMTBIT_S16_LE;
- maxbps = 16;
- channels_max = 2;
- for (i = 0; i < e->sad_count; i++) {
- struct 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) {
- formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (maxbps < 20)
- maxbps = 20;
- }
- if (a->sample_bits & AC_SUPPCM_BITS_24) {
- formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (maxbps < 24)
- maxbps = 24;
- }
- }
- }
-
- /* restrict the parameters by the values the codec provides */
- hinfo->rates &= rates;
- hinfo->formats &= formats;
- hinfo->maxbps = min(hinfo->maxbps, maxbps);
- hinfo->channels_max = min(hinfo->channels_max, channels_max);
-}
-
-
-/* ATI/AMD specific stuff (ELD emulation) */
-
-#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776
-#define ATI_VERB_SET_SINK_INFO_INDEX 0x780
-#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70
-#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76
-#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
-#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80
-#define ATI_VERB_GET_SINK_INFO_DATA 0xf81
-
-#define ATI_SPKALLOC_SPKALLOC 0x007f
-#define ATI_SPKALLOC_TYPE_HDMI 0x0100
-#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200
-
-/* first three bytes are just standard SAD */
-#define ATI_AUDIODESC_CHANNELS 0x00000007
-#define ATI_AUDIODESC_RATES 0x0000ff00
-#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000
-
-/* in standard HDMI VSDB format */
-#define ATI_DELAY_VIDEO_LATENCY 0x000000ff
-#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00
-
-enum ati_sink_info_idx {
- ATI_INFO_IDX_MANUFACTURER_ID = 0,
- ATI_INFO_IDX_PRODUCT_ID = 1,
- ATI_INFO_IDX_SINK_DESC_LEN = 2,
- ATI_INFO_IDX_PORT_ID_LOW = 3,
- ATI_INFO_IDX_PORT_ID_HIGH = 4,
- ATI_INFO_IDX_SINK_DESC_FIRST = 5,
- ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */
-};
-
-int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
- unsigned char *buf, int *eld_size, bool rev3_or_later)
-{
- int spkalloc, ati_sad, aud_synch;
- int sink_desc_len = 0;
- int pos, i;
-
- /* ATI/AMD does not have ELD, emulate it */
-
- spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
-
- if (spkalloc <= 0) {
- codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
- return -EINVAL;
- }
-
- memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
-
- /* version */
- buf[0] = ELD_VER_CEA_861D << 3;
-
- /* speaker allocation from EDID */
- buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
-
- /* is DisplayPort? */
- if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
- buf[5] |= 0x04;
-
- pos = ELD_FIXED_BYTES;
-
- if (rev3_or_later) {
- int sink_info;
-
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
- sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
- put_unaligned_le32(sink_info, buf + 8);
-
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
- sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
- put_unaligned_le32(sink_info, buf + 12);
-
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
- sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
- put_unaligned_le16(sink_info, buf + 16);
-
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
- sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
- put_unaligned_le16(sink_info, buf + 18);
-
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
- sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-
- if (sink_desc_len > ELD_MAX_MNL) {
- codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
- sink_desc_len);
- sink_desc_len = ELD_MAX_MNL;
- }
-
- buf[4] |= sink_desc_len;
-
- for (i = 0; i < sink_desc_len; i++) {
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
- buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
- }
- }
-
- for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
- if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
- continue; /* not handled by ATI/AMD */
-
- snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
- ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
-
- if (ati_sad <= 0)
- continue;
-
- if (ati_sad & ATI_AUDIODESC_RATES) {
- /* format is supported, copy SAD as-is */
- buf[pos++] = (ati_sad & 0x0000ff) >> 0;
- buf[pos++] = (ati_sad & 0x00ff00) >> 8;
- buf[pos++] = (ati_sad & 0xff0000) >> 16;
- }
-
- if (i == AUDIO_CODING_TYPE_LPCM
- && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
- && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
- /* for PCM there is a separate stereo rate mask */
- buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
- /* rates from the extra byte */
- buf[pos++] = (ati_sad & 0xff000000) >> 24;
- buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
- }
- }
-
- if (pos == ELD_FIXED_BYTES + sink_desc_len) {
- codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
- return -EINVAL;
- }
-
- /*
- * HDMI VSDB latency format:
- * separately for both audio and video:
- * 0 field not valid or unknown latency
- * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb)
- * 255 audio/video not supported
- *
- * HDA latency format:
- * single value indicating video latency relative to audio:
- * 0 unknown or 0ms
- * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa)
- * [251..255] reserved
- */
- aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
- if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
- int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
- int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
-
- if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
- video_latency_hdmi > audio_latency_hdmi)
- buf[6] = video_latency_hdmi - audio_latency_hdmi;
- /* else unknown/invalid or 0ms or video ahead of audio, so use zero */
- }
-
- /* SAD count */
- buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
-
- /* Baseline ELD block length is 4-byte aligned */
- pos = round_up(pos, 4);
-
- /* Baseline ELD length (4-byte header is not counted in) */
- buf[2] = (pos - 4) / 4;
-
- *eld_size = pos;
-
- return 0;
-}
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
deleted file mode 100644
index 2ddd33f8dd6c..000000000000
--- a/sound/pci/hda/patch_cmedia.c
+++ /dev/null
@@ -1,127 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for C-Media CMI9880
- *
- * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-struct cmi_spec {
- struct hda_gen_spec gen;
-};
-
-/*
- * stuff for auto-parser
- */
-static const struct hda_codec_ops cmi_auto_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
- .build_pcms = snd_hda_gen_build_pcms,
- .init = snd_hda_gen_init,
- .free = snd_hda_gen_free,
- .unsol_event = snd_hda_jack_unsol_event,
-};
-
-static int patch_cmi9880(struct hda_codec *codec)
-{
- struct cmi_spec *spec;
- struct auto_pin_cfg *cfg;
- int err;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
- codec->patch_ops = cmi_auto_patch_ops;
- cfg = &spec->gen.autocfg;
- snd_hda_gen_spec_init(&spec->gen);
-
- err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
- if (err < 0)
- goto error;
- err = snd_hda_gen_parse_auto_config(codec, cfg);
- if (err < 0)
- goto error;
-
- return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
-}
-
-static int patch_cmi8888(struct hda_codec *codec)
-{
- struct cmi_spec *spec;
- struct auto_pin_cfg *cfg;
- int err;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
-
- codec->spec = spec;
- codec->patch_ops = cmi_auto_patch_ops;
- cfg = &spec->gen.autocfg;
- snd_hda_gen_spec_init(&spec->gen);
-
- /* mask NID 0x10 from the playback volume selection;
- * it's a headphone boost volume handled manually below
- */
- spec->gen.out_vol_mask = (1ULL << 0x10);
-
- err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
- if (err < 0)
- goto error;
- err = snd_hda_gen_parse_auto_config(codec, cfg);
- if (err < 0)
- goto error;
-
- if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
- AC_JACK_HP_OUT) {
- static const struct snd_kcontrol_new amp_kctl =
- HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
- 0x10, 0, HDA_OUTPUT);
- if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
- err = -ENOMEM;
- goto error;
- }
- }
-
- return 0;
-
- error:
- snd_hda_gen_free(codec);
- return err;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_cmedia[] = {
- HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888),
- HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880),
- HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880),
- {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("C-Media HD-audio codec");
-
-static struct hda_codec_driver cmedia_driver = {
- .id = snd_hda_id_cmedia,
-};
-
-module_hda_codec_driver(cmedia_driver);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
deleted file mode 100644
index 5c0b1a09fd57..000000000000
--- a/sound/pci/hda/patch_hdmi.c
+++ /dev/null
@@ -1,4656 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * patch_hdmi.c - routines for HDMI/DisplayPort codecs
- *
- * Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
- * Copyright (c) 2006 ATI Technologies Inc.
- * Copyright (c) 2008 NVIDIA Corp. All rights reserved.
- * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
- * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
- *
- * Authors:
- * Wu Fengguang <wfg@linux.intel.com>
- *
- * Maintained by:
- * Wu Fengguang <wfg@linux.intel.com>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/asoundef.h>
-#include <sound/tlv.h>
-#include <sound/hdaudio.h>
-#include <sound/hda_i915.h>
-#include <sound/hda_chmap.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_jack.h"
-#include "hda_controller.h"
-
-static bool static_hdmi_pcm;
-module_param(static_hdmi_pcm, bool, 0644);
-MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
-
-static bool enable_acomp = true;
-module_param(enable_acomp, bool, 0444);
-MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
-
-static bool enable_silent_stream =
-IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
-module_param(enable_silent_stream, bool, 0644);
-MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
-
-static bool enable_all_pins;
-module_param(enable_all_pins, bool, 0444);
-MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins");
-
-struct hdmi_spec_per_cvt {
- hda_nid_t cvt_nid;
- bool assigned; /* the stream has been assigned */
- bool silent_stream; /* silent stream activated */
- unsigned int channels_min;
- unsigned int channels_max;
- u32 rates;
- u64 formats;
- unsigned int maxbps;
-};
-
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS 32
-
-struct hdmi_spec_per_pin {
- hda_nid_t pin_nid;
- int dev_id;
- /* pin idx, different device entries on the same pin use the same idx */
- int pin_nid_idx;
- int num_mux_nids;
- hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
- int mux_idx;
- hda_nid_t cvt_nid;
-
- struct hda_codec *codec;
- struct hdmi_eld sink_eld;
- struct mutex lock;
- struct delayed_work work;
- struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
- int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
- int prev_pcm_idx; /* previously assigned pcm index */
- int repoll_count;
- bool setup; /* the stream has been set up by prepare callback */
- bool silent_stream;
- int channels; /* current number of channels */
- bool non_pcm;
- bool chmap_set; /* channel-map override by ALSA API? */
- unsigned char chmap[8]; /* ALSA API channel-map */
-#ifdef CONFIG_SND_PROC_FS
- struct snd_info_entry *proc_entry;
-#endif
-};
-
-/* operations used by generic code that can be overridden by patches */
-struct hdmi_ops {
- int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
- int dev_id, unsigned char *buf, int *eld_size);
-
- void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
- int dev_id,
- int ca, int active_channels, int conn_type);
-
- /* enable/disable HBR (HD passthrough) */
- int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
- int dev_id, bool hbr);
-
- int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
- hda_nid_t pin_nid, int dev_id, u32 stream_tag,
- int format);
-
- void (*pin_cvt_fixup)(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- hda_nid_t cvt_nid);
-};
-
-struct hdmi_pcm {
- struct hda_pcm *pcm;
- struct snd_jack *jack;
- struct snd_kcontrol *eld_ctl;
-};
-
-enum {
- SILENT_STREAM_OFF = 0,
- SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */
- SILENT_STREAM_I915, /* Intel i915 extension */
-};
-
-struct hdmi_spec {
- struct hda_codec *codec;
- int num_cvts;
- struct snd_array cvts; /* struct hdmi_spec_per_cvt */
- hda_nid_t cvt_nids[4]; /* only for haswell fix */
-
- /*
- * num_pins is the number of virtual pins
- * for example, there are 3 pins, and each pin
- * has 4 device entries, then the num_pins is 12
- */
- int num_pins;
- /*
- * num_nids is the number of real pins
- * In the above example, num_nids is 3
- */
- int num_nids;
- /*
- * dev_num is the number of device entries
- * on each pin.
- * In the above example, dev_num is 4
- */
- int dev_num;
- struct snd_array pins; /* struct hdmi_spec_per_pin */
- struct hdmi_pcm pcm_rec[8];
- struct mutex pcm_lock;
- struct mutex bind_lock; /* for audio component binding */
- /* pcm_bitmap means which pcms have been assigned to pins*/
- unsigned long pcm_bitmap;
- int pcm_used; /* counter of pcm_rec[] */
- /* bitmap shows whether the pcm is opened in user space
- * bit 0 means the first playback PCM (PCM3);
- * bit 1 means the second playback PCM, and so on.
- */
- unsigned long pcm_in_use;
-
- struct hdmi_eld temp_eld;
- struct hdmi_ops ops;
-
- bool dyn_pin_out;
- bool static_pcm_mapping;
- /* hdmi interrupt trigger control flag for Nvidia codec */
- bool hdmi_intr_trig_ctrl;
- bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
-
- bool intel_hsw_fixup; /* apply Intel platform-specific fixups */
- /*
- * Non-generic VIA/NVIDIA specific
- */
- struct hda_multi_out multiout;
- struct hda_pcm_stream pcm_playback;
-
- bool use_acomp_notifier; /* use eld_notify callback for hotplug */
- bool acomp_registered; /* audio component registered in this driver */
- bool force_connect; /* force connectivity */
- struct drm_audio_component_audio_ops drm_audio_ops;
- int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */
-
- struct hdac_chmap chmap;
- hda_nid_t vendor_nid;
- const int *port_map;
- int port_num;
- int silent_stream_type;
-};
-
-#ifdef CONFIG_SND_HDA_COMPONENT
-static inline bool codec_has_acomp(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- return spec->use_acomp_notifier;
-}
-#else
-#define codec_has_acomp(codec) false
-#endif
-
-struct hdmi_audio_infoframe {
- u8 type; /* 0x84 */
- u8 ver; /* 0x01 */
- u8 len; /* 0x0a */
-
- u8 checksum;
-
- u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
- u8 SS01_SF24;
- u8 CXT04;
- u8 CA;
- u8 LFEPBL01_LSV36_DM_INH7;
-};
-
-struct dp_audio_infoframe {
- u8 type; /* 0x84 */
- u8 len; /* 0x1b */
- u8 ver; /* 0x11 << 2 */
-
- u8 CC02_CT47; /* match with HDMI infoframe from this on */
- u8 SS01_SF24;
- u8 CXT04;
- u8 CA;
- u8 LFEPBL01_LSV36_DM_INH7;
-};
-
-union audio_infoframe {
- struct hdmi_audio_infoframe hdmi;
- struct dp_audio_infoframe dp;
- DECLARE_FLEX_ARRAY(u8, bytes);
-};
-
-/*
- * HDMI routines
- */
-
-#define get_pin(spec, idx) \
- ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
-#define get_cvt(spec, idx) \
- ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx))
-/* obtain hdmi_pcm object assigned to idx */
-#define get_hdmi_pcm(spec, idx) (&(spec)->pcm_rec[idx])
-/* obtain hda_pcm object assigned to idx */
-#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
-
-static int pin_id_to_pin_index(struct hda_codec *codec,
- hda_nid_t pin_nid, int dev_id)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx;
- struct hdmi_spec_per_pin *per_pin;
-
- /*
- * (dev_id == -1) means it is NON-MST pin
- * return the first virtual pin on this port
- */
- if (dev_id == -1)
- dev_id = 0;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- per_pin = get_pin(spec, pin_idx);
- if ((per_pin->pin_nid == pin_nid) &&
- (per_pin->dev_id == dev_id))
- return pin_idx;
- }
-
- codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid);
- return -EINVAL;
-}
-
-static int hinfo_to_pcm_index(struct hda_codec *codec,
- struct hda_pcm_stream *hinfo)
-{
- struct hdmi_spec *spec = codec->spec;
- int pcm_idx;
-
- for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++)
- if (get_pcm_rec(spec, pcm_idx)->stream == hinfo)
- return pcm_idx;
-
- codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo);
- return -EINVAL;
-}
-
-static int hinfo_to_pin_index(struct hda_codec *codec,
- struct hda_pcm_stream *hinfo)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin;
- int pin_idx;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- per_pin = get_pin(spec, pin_idx);
- if (per_pin->pcm &&
- per_pin->pcm->pcm->stream == hinfo)
- return pin_idx;
- }
-
- codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo,
- hinfo_to_pcm_index(codec, hinfo));
- return -EINVAL;
-}
-
-static struct hdmi_spec_per_pin *pcm_idx_to_pin(struct hdmi_spec *spec,
- int pcm_idx)
-{
- int i;
- struct hdmi_spec_per_pin *per_pin;
-
- for (i = 0; i < spec->num_pins; i++) {
- per_pin = get_pin(spec, i);
- if (per_pin->pcm_idx == pcm_idx)
- return per_pin;
- }
- return NULL;
-}
-
-static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
-{
- struct hdmi_spec *spec = codec->spec;
- int cvt_idx;
-
- for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
- if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
- return cvt_idx;
-
- codec_warn(codec, "HDMI: cvt NID 0x%x not registered\n", cvt_nid);
- return -EINVAL;
-}
-
-static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin;
- struct hdmi_eld *eld;
- int pcm_idx;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-
- pcm_idx = kcontrol->private_value;
- mutex_lock(&spec->pcm_lock);
- per_pin = pcm_idx_to_pin(spec, pcm_idx);
- if (!per_pin) {
- /* no pin is bound to the pcm */
- uinfo->count = 0;
- goto unlock;
- }
- eld = &per_pin->sink_eld;
- uinfo->count = eld->eld_valid ? eld->eld_size : 0;
-
- unlock:
- mutex_unlock(&spec->pcm_lock);
- return 0;
-}
-
-static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin;
- struct hdmi_eld *eld;
- int pcm_idx;
- int err = 0;
-
- pcm_idx = kcontrol->private_value;
- mutex_lock(&spec->pcm_lock);
- per_pin = pcm_idx_to_pin(spec, pcm_idx);
- if (!per_pin) {
- /* no pin is bound to the pcm */
- memset(ucontrol->value.bytes.data, 0,
- ARRAY_SIZE(ucontrol->value.bytes.data));
- goto unlock;
- }
-
- eld = &per_pin->sink_eld;
- if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
- eld->eld_size > ELD_MAX_SIZE) {
- snd_BUG();
- err = -EINVAL;
- goto unlock;
- }
-
- memset(ucontrol->value.bytes.data, 0,
- ARRAY_SIZE(ucontrol->value.bytes.data));
- if (eld->eld_valid)
- memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
- eld->eld_size);
-
- unlock:
- mutex_unlock(&spec->pcm_lock);
- return err;
-}
-
-static const struct snd_kcontrol_new eld_bytes_ctl = {
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE |
- SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK,
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "ELD",
- .info = hdmi_eld_ctl_info,
- .get = hdmi_eld_ctl_get,
-};
-
-static int hdmi_create_eld_ctl(struct hda_codec *codec, int pcm_idx,
- int device)
-{
- struct snd_kcontrol *kctl;
- struct hdmi_spec *spec = codec->spec;
- int err;
-
- kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = pcm_idx;
- kctl->id.device = device;
-
- /* no pin nid is associated with the kctl now
- * tbd: associate pin nid to eld ctl later
- */
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
-
- get_hdmi_pcm(spec, pcm_idx)->eld_ctl = kctl;
- return 0;
-}
-
-#ifdef BE_PARANOID
-static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
- int *packet_index, int *byte_index)
-{
- int val;
-
- val = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_HDMI_DIP_INDEX, 0);
-
- *packet_index = val >> 5;
- *byte_index = val & 0x1f;
-}
-#endif
-
-static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
- int packet_index, int byte_index)
-{
- int val;
-
- val = (packet_index << 5) | (byte_index & 0x1f);
-
- snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
-}
-
-static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
- unsigned char val)
-{
- snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
-}
-
-static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_out;
-
- /* Unmute */
- if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-
- if (spec->dyn_pin_out)
- /* Disable pin out until stream is active */
- pin_out = 0;
- else
- /* Enable pin out: some machines with GM965 gets broken output
- * when the pin is disabled or changed while using with HDMI
- */
- pin_out = PIN_OUT;
-
- snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
-}
-
-/*
- * ELD proc files
- */
-
-#ifdef CONFIG_SND_PROC_FS
-static void print_eld_info(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- struct hdmi_spec_per_pin *per_pin = entry->private_data;
-
- mutex_lock(&per_pin->lock);
- snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer, per_pin->pin_nid,
- per_pin->dev_id, per_pin->cvt_nid);
- mutex_unlock(&per_pin->lock);
-}
-
-static void write_eld_info(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- struct hdmi_spec_per_pin *per_pin = entry->private_data;
-
- mutex_lock(&per_pin->lock);
- snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
- mutex_unlock(&per_pin->lock);
-}
-
-static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
-{
- char name[32];
- struct hda_codec *codec = per_pin->codec;
- struct snd_info_entry *entry;
- int err;
-
- snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
- err = snd_card_proc_new(codec->card, name, &entry);
- if (err < 0)
- return err;
-
- snd_info_set_text_ops(entry, per_pin, print_eld_info);
- entry->c.text.write = write_eld_info;
- entry->mode |= 0200;
- per_pin->proc_entry = entry;
-
- return 0;
-}
-
-static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
-{
- if (!per_pin->codec->bus->shutdown) {
- snd_info_free_entry(per_pin->proc_entry);
- per_pin->proc_entry = NULL;
- }
-}
-#else
-static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
- int index)
-{
- return 0;
-}
-static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
-{
-}
-#endif
-
-/*
- * Audio InfoFrame routines
- */
-
-/*
- * Enable Audio InfoFrame Transmission
- */
-static void hdmi_start_infoframe_trans(struct hda_codec *codec,
- hda_nid_t pin_nid)
-{
- hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
- snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
- AC_DIPXMIT_BEST);
-}
-
-/*
- * Disable Audio InfoFrame Transmission
- */
-static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
- hda_nid_t pin_nid)
-{
- hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
- snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
- AC_DIPXMIT_DISABLE);
-}
-
-static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- int i;
- int size;
-
- size = snd_hdmi_get_eld_size(codec, pin_nid);
- codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
-
- for (i = 0; i < 8; i++) {
- size = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_HDMI_DIP_SIZE, i);
- codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
- }
-#endif
-}
-
-static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-#ifdef BE_PARANOID
- int i, j;
- int size;
- int pi, bi;
- for (i = 0; i < 8; i++) {
- size = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_HDMI_DIP_SIZE, i);
- if (size == 0)
- continue;
-
- hdmi_set_dip_index(codec, pin_nid, i, 0x0);
- for (j = 1; j < 1000; j++) {
- hdmi_write_dip_byte(codec, pin_nid, 0x0);
- hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
- if (pi != i)
- codec_dbg(codec, "dip index %d: %d != %d\n",
- bi, pi, i);
- if (bi == 0) /* byte index wrapped around */
- break;
- }
- codec_dbg(codec,
- "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
- i, size, j);
- }
-#endif
-}
-
-static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
-{
- u8 *bytes = (u8 *)hdmi_ai;
- u8 sum = 0;
- int i;
-
- hdmi_ai->checksum = 0;
-
- for (i = 0; i < sizeof(*hdmi_ai); i++)
- sum += bytes[i];
-
- hdmi_ai->checksum = -sum;
-}
-
-static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
- hda_nid_t pin_nid,
- u8 *dip, int size)
-{
- int i;
-
- hdmi_debug_dip_size(codec, pin_nid);
- hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
-
- hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
- for (i = 0; i < size; i++)
- hdmi_write_dip_byte(codec, pin_nid, dip[i]);
-}
-
-static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
- u8 *dip, int size)
-{
- u8 val;
- int i;
-
- hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
- if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
- != AC_DIPXMIT_BEST)
- return false;
-
- for (i = 0; i < size; i++) {
- val = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_HDMI_DIP_DATA, 0);
- if (val != dip[i])
- return false;
- }
-
- return true;
-}
-
-static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
- int dev_id, unsigned char *buf, int *eld_size)
-{
- snd_hda_set_dev_select(codec, nid, dev_id);
-
- return snd_hdmi_get_eld(codec, nid, buf, eld_size);
-}
-
-static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
- hda_nid_t pin_nid, int dev_id,
- int ca, int active_channels,
- int conn_type)
-{
- struct hdmi_spec *spec = codec->spec;
- union audio_infoframe ai;
-
- memset(&ai, 0, sizeof(ai));
- if ((conn_type == 0) || /* HDMI */
- /* Nvidia DisplayPort: Nvidia HW expects same layout as HDMI */
- (conn_type == 1 && spec->nv_dp_workaround)) {
- struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
-
- if (conn_type == 0) { /* HDMI */
- hdmi_ai->type = 0x84;
- hdmi_ai->ver = 0x01;
- hdmi_ai->len = 0x0a;
- } else {/* Nvidia DP */
- hdmi_ai->type = 0x84;
- hdmi_ai->ver = 0x1b;
- hdmi_ai->len = 0x11 << 2;
- }
- hdmi_ai->CC02_CT47 = active_channels - 1;
- hdmi_ai->CA = ca;
- hdmi_checksum_audio_infoframe(hdmi_ai);
- } else if (conn_type == 1) { /* DisplayPort */
- struct dp_audio_infoframe *dp_ai = &ai.dp;
-
- dp_ai->type = 0x84;
- dp_ai->len = 0x1b;
- dp_ai->ver = 0x11 << 2;
- dp_ai->CC02_CT47 = active_channels - 1;
- dp_ai->CA = ca;
- } else {
- codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid);
- return;
- }
-
- snd_hda_set_dev_select(codec, pin_nid, dev_id);
-
- /*
- * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
- * sizeof(*dp_ai) to avoid partial match/update problems when
- * the user switches between HDMI/DP monitors.
- */
- if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
- sizeof(ai))) {
- codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n",
- __func__, pin_nid, active_channels, ca);
- hdmi_stop_infoframe_trans(codec, pin_nid);
- hdmi_fill_audio_infoframe(codec, pin_nid,
- ai.bytes, sizeof(ai));
- hdmi_start_infoframe_trans(codec, pin_nid);
- }
-}
-
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- bool non_pcm)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdac_chmap *chmap = &spec->chmap;
- hda_nid_t pin_nid = per_pin->pin_nid;
- int dev_id = per_pin->dev_id;
- int channels = per_pin->channels;
- int active_channels;
- struct hdmi_eld *eld;
- int ca;
-
- if (!channels)
- return;
-
- snd_hda_set_dev_select(codec, pin_nid, dev_id);
-
- /* some HW (e.g. HSW+) needs reprogramming the amp at each time */
- if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
-
- eld = &per_pin->sink_eld;
-
- ca = snd_hdac_channel_allocation(&codec->core,
- eld->info.spk_alloc, channels,
- per_pin->chmap_set, non_pcm, per_pin->chmap);
-
- active_channels = snd_hdac_get_active_channels(ca);
-
- chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid,
- active_channels);
-
- /*
- * always configure channel mapping, it may have been changed by the
- * user in the meantime
- */
- snd_hdac_setup_channel_mapping(&spec->chmap,
- pin_nid, non_pcm, ca, channels,
- per_pin->chmap, per_pin->chmap_set);
-
- spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
- ca, active_channels, eld->info.conn_type);
-
- per_pin->non_pcm = non_pcm;
-}
-
-/*
- * Unsolicited events
- */
-
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
-
-static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
- int dev_id)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
-
- if (pin_idx < 0)
- return;
- mutex_lock(&spec->pcm_lock);
- hdmi_present_sense(get_pin(spec, pin_idx), 1);
- mutex_unlock(&spec->pcm_lock);
-}
-
-static void jack_callback(struct hda_codec *codec,
- struct hda_jack_callback *jack)
-{
- /* stop polling when notification is enabled */
- if (codec_has_acomp(codec))
- return;
-
- check_presence_and_report(codec, jack->nid, jack->dev_id);
-}
-
-static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
- struct hda_jack_tbl *jack)
-{
- jack->jack_dirty = 1;
-
- codec_dbg(codec,
- "HDMI hot plug event: Codec=%d NID=0x%x Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
- codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA),
- !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
-
- check_presence_and_report(codec, jack->nid, jack->dev_id);
-}
-
-static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
-{
- int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
- int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
- int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
- int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
-
- codec_info(codec,
- "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
- codec->addr,
- tag,
- subtag,
- cp_state,
- cp_ready);
-
- /* TODO */
- if (cp_state) {
- ;
- }
- if (cp_ready) {
- ;
- }
-}
-
-
-static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
-{
- int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
- int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
- struct hda_jack_tbl *jack;
-
- if (codec_has_acomp(codec))
- return;
-
- if (codec->dp_mst) {
- int dev_entry =
- (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
-
- jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry);
- } else {
- jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0);
- }
-
- if (!jack) {
- codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
- return;
- }
-
- if (subtag == 0)
- hdmi_intrinsic_event(codec, res, jack);
- else
- hdmi_non_intrinsic_event(codec, res);
-}
-
-static void haswell_verify_D0(struct hda_codec *codec,
- hda_nid_t cvt_nid, hda_nid_t nid)
-{
- int pwr;
-
- /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
- * thus pins could only choose converter 0 for use. Make sure the
- * converters are in correct power state */
- if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
- snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
- if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
- AC_PWRST_D0);
- msleep(40);
- pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
- pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
- codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
- }
-}
-
-/*
- * Callbacks
- */
-
-/* HBR should be Non-PCM, 8 channels */
-#define is_hbr_format(format) \
- ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
-
-static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
- int dev_id, bool hbr)
-{
- int pinctl, new_pinctl;
-
- if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
- snd_hda_set_dev_select(codec, pin_nid, dev_id);
- pinctl = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-
- if (pinctl < 0)
- return hbr ? -EINVAL : 0;
-
- new_pinctl = pinctl & ~AC_PINCTL_EPT;
- if (hbr)
- new_pinctl |= AC_PINCTL_EPT_HBR;
- else
- new_pinctl |= AC_PINCTL_EPT_NATIVE;
-
- codec_dbg(codec,
- "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
- pin_nid,
- pinctl == new_pinctl ? "" : "new-",
- new_pinctl);
-
- if (pinctl != new_pinctl)
- snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- new_pinctl);
- } else if (hbr)
- return -EINVAL;
-
- return 0;
-}
-
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
- hda_nid_t pin_nid, int dev_id,
- u32 stream_tag, int format)
-{
- struct hdmi_spec *spec = codec->spec;
- unsigned int param;
- int err;
-
- err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id,
- is_hbr_format(format));
-
- if (err) {
- codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
- return err;
- }
-
- if (spec->intel_hsw_fixup) {
-
- /*
- * on recent platforms IEC Coding Type is required for HBR
- * support, read current Digital Converter settings and set
- * ICT bitfield if needed.
- */
- param = snd_hda_codec_read(codec, cvt_nid, 0,
- AC_VERB_GET_DIGI_CONVERT_1, 0);
-
- param = (param >> 16) & ~(AC_DIG3_ICT);
-
- /* on recent platforms ICT mode is required for HBR support */
- if (is_hbr_format(format))
- param |= 0x1;
-
- snd_hda_codec_write(codec, cvt_nid, 0,
- AC_VERB_SET_DIGI_CONVERT_3, param);
- }
-
- snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
- return 0;
-}
-
-/* Try to find an available converter
- * If pin_idx is less then zero, just try to find an available converter.
- * Otherwise, try to find an available converter and get the cvt mux index
- * of the pin.
- */
-static int hdmi_choose_cvt(struct hda_codec *codec,
- int pin_idx, int *cvt_id,
- bool silent)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin;
- struct hdmi_spec_per_cvt *per_cvt = NULL;
- int cvt_idx, mux_idx = 0;
-
- /* pin_idx < 0 means no pin will be bound to the converter */
- if (pin_idx < 0)
- per_pin = NULL;
- else
- per_pin = get_pin(spec, pin_idx);
-
- if (per_pin && per_pin->silent_stream) {
- cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
- per_cvt = get_cvt(spec, cvt_idx);
- if (per_cvt->assigned && !silent)
- return -EBUSY;
- if (cvt_id)
- *cvt_id = cvt_idx;
- return 0;
- }
-
- /* Dynamically assign converter to stream */
- for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
- per_cvt = get_cvt(spec, cvt_idx);
-
- /* Must not already be assigned */
- if (per_cvt->assigned || per_cvt->silent_stream)
- continue;
- if (per_pin == NULL)
- break;
- /* Must be in pin's mux's list of converters */
- for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
- if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
- break;
- /* Not in mux list */
- if (mux_idx == per_pin->num_mux_nids)
- continue;
- break;
- }
-
- /* No free converters */
- if (cvt_idx == spec->num_cvts)
- return -EBUSY;
-
- if (per_pin != NULL)
- per_pin->mux_idx = mux_idx;
-
- if (cvt_id)
- *cvt_id = cvt_idx;
-
- return 0;
-}
-
-/* Assure the pin select the right convetor */
-static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- hda_nid_t pin_nid = per_pin->pin_nid;
- int mux_idx, curr;
-
- mux_idx = per_pin->mux_idx;
- curr = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_CONNECT_SEL, 0);
- if (curr != mux_idx)
- snd_hda_codec_write_cache(codec, pin_nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- mux_idx);
-}
-
-/* get the mux index for the converter of the pins
- * converter's mux index is the same for all pins on Intel platform
- */
-static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
- hda_nid_t cvt_nid)
-{
- int i;
-
- for (i = 0; i < spec->num_cvts; i++)
- if (spec->cvt_nids[i] == cvt_nid)
- return i;
- return -EINVAL;
-}
-
-/* Intel HDMI workaround to fix audio routing issue:
- * For some Intel display codecs, pins share the same connection list.
- * So a conveter can be selected by multiple pins and playback on any of these
- * pins will generate sound on the external display, because audio flows from
- * the same converter to the display pipeline. Also muting one pin may make
- * other pins have no sound output.
- * So this function assures that an assigned converter for a pin is not selected
- * by any other pins.
- */
-static void intel_not_share_assigned_cvt(struct hda_codec *codec,
- hda_nid_t pin_nid,
- int dev_id, int mux_idx)
-{
- struct hdmi_spec *spec = codec->spec;
- hda_nid_t nid;
- int cvt_idx, curr;
- struct hdmi_spec_per_cvt *per_cvt;
- struct hdmi_spec_per_pin *per_pin;
- int pin_idx;
-
- /* configure the pins connections */
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- int dev_id_saved;
- int dev_num;
-
- per_pin = get_pin(spec, pin_idx);
- /*
- * pin not connected to monitor
- * no need to operate on it
- */
- if (!per_pin->pcm)
- continue;
-
- if ((per_pin->pin_nid == pin_nid) &&
- (per_pin->dev_id == dev_id))
- continue;
-
- /*
- * if per_pin->dev_id >= dev_num,
- * snd_hda_get_dev_select() will fail,
- * and the following operation is unpredictable.
- * So skip this situation.
- */
- dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
- if (per_pin->dev_id >= dev_num)
- continue;
-
- nid = per_pin->pin_nid;
-
- /*
- * Calling this function should not impact
- * on the device entry selection
- * So let's save the dev id for each pin,
- * and restore it when return
- */
- dev_id_saved = snd_hda_get_dev_select(codec, nid);
- snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
- curr = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONNECT_SEL, 0);
- if (curr != mux_idx) {
- snd_hda_set_dev_select(codec, nid, dev_id_saved);
- continue;
- }
-
-
- /* choose an unassigned converter. The conveters in the
- * connection list are in the same order as in the codec.
- */
- for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
- per_cvt = get_cvt(spec, cvt_idx);
- if (!per_cvt->assigned) {
- codec_dbg(codec,
- "choose cvt %d for pin NID 0x%x\n",
- cvt_idx, nid);
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- cvt_idx);
- break;
- }
- }
- snd_hda_set_dev_select(codec, nid, dev_id_saved);
- }
-}
-
-/* A wrapper of intel_not_share_asigned_cvt() */
-static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
- hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
-{
- int mux_idx;
- struct hdmi_spec *spec = codec->spec;
-
- /* On Intel platform, the mapping of converter nid to
- * mux index of the pins are always the same.
- * The pin nid may be 0, this means all pins will not
- * share the converter.
- */
- mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
- if (mux_idx >= 0)
- intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
-}
-
-/* skeleton caller of pin_cvt_fixup ops */
-static void pin_cvt_fixup(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- hda_nid_t cvt_nid)
-{
- struct hdmi_spec *spec = codec->spec;
-
- if (spec->ops.pin_cvt_fixup)
- spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
-}
-
-/* called in hdmi_pcm_open when no pin is assigned to the PCM */
-static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int cvt_idx, pcm_idx;
- struct hdmi_spec_per_cvt *per_cvt = NULL;
- int err;
-
- pcm_idx = hinfo_to_pcm_index(codec, hinfo);
- if (pcm_idx < 0)
- return -EINVAL;
-
- err = hdmi_choose_cvt(codec, -1, &cvt_idx, false);
- if (err)
- return err;
-
- per_cvt = get_cvt(spec, cvt_idx);
- per_cvt->assigned = true;
- hinfo->nid = per_cvt->cvt_nid;
-
- pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
-
- set_bit(pcm_idx, &spec->pcm_in_use);
- /* todo: setup spdif ctls assign */
-
- /* Initially set the converter's capabilities */
- hinfo->channels_min = per_cvt->channels_min;
- hinfo->channels_max = per_cvt->channels_max;
- hinfo->rates = per_cvt->rates;
- hinfo->formats = per_cvt->formats;
- hinfo->maxbps = per_cvt->maxbps;
-
- /* Store the updated parameters */
- runtime->hw.channels_min = hinfo->channels_min;
- runtime->hw.channels_max = hinfo->channels_max;
- runtime->hw.formats = hinfo->formats;
- runtime->hw.rates = hinfo->rates;
-
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- return 0;
-}
-
-/*
- * HDA PCM callbacks
- */
-static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int pin_idx, cvt_idx, pcm_idx;
- struct hdmi_spec_per_pin *per_pin;
- struct hdmi_eld *eld;
- struct hdmi_spec_per_cvt *per_cvt = NULL;
- int err;
-
- /* Validate hinfo */
- pcm_idx = hinfo_to_pcm_index(codec, hinfo);
- if (pcm_idx < 0)
- return -EINVAL;
-
- mutex_lock(&spec->pcm_lock);
- pin_idx = hinfo_to_pin_index(codec, hinfo);
- /* no pin is assigned to the PCM
- * PA need pcm open successfully when probe
- */
- if (pin_idx < 0) {
- err = hdmi_pcm_open_no_pin(hinfo, codec, substream);
- goto unlock;
- }
-
- err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false);
- if (err < 0)
- goto unlock;
-
- per_cvt = get_cvt(spec, cvt_idx);
- /* Claim converter */
- per_cvt->assigned = true;
-
- set_bit(pcm_idx, &spec->pcm_in_use);
- per_pin = get_pin(spec, pin_idx);
- per_pin->cvt_nid = per_cvt->cvt_nid;
- hinfo->nid = per_cvt->cvt_nid;
-
- /* flip stripe flag for the assigned stream if supported */
- if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
- azx_stream(get_azx_dev(substream))->stripe = 1;
-
- snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
- snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- per_pin->mux_idx);
-
- /* configure unused pins to choose other converters */
- pin_cvt_fixup(codec, per_pin, 0);
-
- snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
-
- /* Initially set the converter's capabilities */
- hinfo->channels_min = per_cvt->channels_min;
- hinfo->channels_max = per_cvt->channels_max;
- hinfo->rates = per_cvt->rates;
- hinfo->formats = per_cvt->formats;
- hinfo->maxbps = per_cvt->maxbps;
-
- eld = &per_pin->sink_eld;
- /* Restrict capabilities by ELD if this isn't disabled */
- if (!static_hdmi_pcm && eld->eld_valid) {
- snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
- if (hinfo->channels_min > hinfo->channels_max ||
- !hinfo->rates || !hinfo->formats) {
- per_cvt->assigned = false;
- hinfo->nid = 0;
- snd_hda_spdif_ctls_unassign(codec, pcm_idx);
- err = -ENODEV;
- goto unlock;
- }
- }
-
- /* Store the updated parameters */
- runtime->hw.channels_min = hinfo->channels_min;
- runtime->hw.channels_max = hinfo->channels_max;
- runtime->hw.formats = hinfo->formats;
- runtime->hw.rates = hinfo->rates;
-
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- unlock:
- mutex_unlock(&spec->pcm_lock);
- return err;
-}
-
-/*
- * HDA/HDMI auto parsing
- */
-static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- hda_nid_t pin_nid = per_pin->pin_nid;
- int dev_id = per_pin->dev_id;
- int conns;
-
- if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
- codec_warn(codec,
- "HDMI: pin NID 0x%x wcaps %#x does not support connection list\n",
- pin_nid, get_wcaps(codec, pin_nid));
- return -EINVAL;
- }
-
- snd_hda_set_dev_select(codec, pin_nid, dev_id);
-
- if (spec->intel_hsw_fixup) {
- conns = spec->num_cvts;
- memcpy(per_pin->mux_nids, spec->cvt_nids,
- sizeof(hda_nid_t) * conns);
- } else {
- conns = snd_hda_get_raw_connections(codec, pin_nid,
- per_pin->mux_nids,
- HDA_MAX_CONNECTIONS);
- }
-
- /* all the device entries on the same pin have the same conn list */
- per_pin->num_mux_nids = conns;
-
- return 0;
-}
-
-static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
- struct hdmi_spec_per_pin *per_pin)
-{
- int i;
-
- for (i = 0; i < spec->pcm_used; i++) {
- if (!test_bit(i, &spec->pcm_bitmap))
- return i;
- }
- return -EBUSY;
-}
-
-static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
- struct hdmi_spec_per_pin *per_pin)
-{
- int idx;
-
- /* pcm already be attached to the pin */
- if (per_pin->pcm)
- return;
- /* try the previously used slot at first */
- idx = per_pin->prev_pcm_idx;
- if (idx >= 0) {
- if (!test_bit(idx, &spec->pcm_bitmap))
- goto found;
- per_pin->prev_pcm_idx = -1; /* no longer valid, clear it */
- }
- idx = hdmi_find_pcm_slot(spec, per_pin);
- if (idx == -EBUSY)
- return;
- found:
- per_pin->pcm_idx = idx;
- per_pin->pcm = get_hdmi_pcm(spec, idx);
- set_bit(idx, &spec->pcm_bitmap);
-}
-
-static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
- struct hdmi_spec_per_pin *per_pin)
-{
- int idx;
-
- /* pcm already be detached from the pin */
- if (!per_pin->pcm)
- return;
- idx = per_pin->pcm_idx;
- per_pin->pcm_idx = -1;
- per_pin->prev_pcm_idx = idx; /* remember the previous index */
- per_pin->pcm = NULL;
- if (idx >= 0 && idx < spec->pcm_used)
- clear_bit(idx, &spec->pcm_bitmap);
-}
-
-static int hdmi_get_pin_cvt_mux(struct hdmi_spec *spec,
- struct hdmi_spec_per_pin *per_pin, hda_nid_t cvt_nid)
-{
- int mux_idx;
-
- for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
- if (per_pin->mux_nids[mux_idx] == cvt_nid)
- break;
- return mux_idx;
-}
-
-static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid);
-
-static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hda_codec *codec = per_pin->codec;
- struct hda_pcm *pcm;
- struct hda_pcm_stream *hinfo;
- struct snd_pcm_substream *substream;
- int mux_idx;
- bool non_pcm;
-
- if (per_pin->pcm_idx < 0 || per_pin->pcm_idx >= spec->pcm_used)
- return;
- pcm = get_pcm_rec(spec, per_pin->pcm_idx);
- if (!pcm->pcm)
- return;
- if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use))
- return;
-
- /* hdmi audio only uses playback and one substream */
- hinfo = pcm->stream;
- substream = pcm->pcm->streams[0].substream;
-
- per_pin->cvt_nid = hinfo->nid;
-
- mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
- if (mux_idx < per_pin->num_mux_nids) {
- snd_hda_set_dev_select(codec, per_pin->pin_nid,
- per_pin->dev_id);
- snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- mux_idx);
- }
- snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
-
- non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
- if (substream->runtime)
- per_pin->channels = substream->runtime->channels;
- per_pin->setup = true;
- per_pin->mux_idx = mux_idx;
-
- hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
-}
-
-static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
- struct hdmi_spec_per_pin *per_pin)
-{
- if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used)
- snd_hda_spdif_ctls_unassign(per_pin->codec, per_pin->pcm_idx);
-
- per_pin->chmap_set = false;
- memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
-
- per_pin->setup = false;
- per_pin->channels = 0;
-}
-
-static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hdmi_spec *spec = codec->spec;
-
- if (per_pin->pcm_idx >= 0)
- return spec->pcm_rec[per_pin->pcm_idx].jack;
- else
- return NULL;
-}
-
-/* update per_pin ELD from the given new ELD;
- * setup info frame and notification accordingly
- * also notify ELD kctl and report jack status changes
- */
-static void update_eld(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- struct hdmi_eld *eld,
- int repoll)
-{
- struct hdmi_eld *pin_eld = &per_pin->sink_eld;
- struct hdmi_spec *spec = codec->spec;
- struct snd_jack *pcm_jack;
- bool old_eld_valid = pin_eld->eld_valid;
- bool eld_changed;
- int pcm_idx;
-
- if (eld->eld_valid) {
- if (eld->eld_size <= 0 ||
- snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
- eld->eld_size) < 0) {
- eld->eld_valid = false;
- if (repoll) {
- schedule_delayed_work(&per_pin->work,
- msecs_to_jiffies(300));
- return;
- }
- }
- }
-
- if (!eld->eld_valid || eld->eld_size <= 0 || eld->info.sad_count <= 0) {
- eld->eld_valid = false;
- eld->eld_size = 0;
- }
-
- /* for monitor disconnection, save pcm_idx firstly */
- pcm_idx = per_pin->pcm_idx;
-
- /*
- * pcm_idx >=0 before update_eld() means it is in monitor
- * disconnected event. Jack must be fetched before update_eld().
- */
- pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
-
- if (!spec->static_pcm_mapping) {
- if (eld->eld_valid) {
- hdmi_attach_hda_pcm(spec, per_pin);
- hdmi_pcm_setup_pin(spec, per_pin);
- } else {
- hdmi_pcm_reset_pin(spec, per_pin);
- hdmi_detach_hda_pcm(spec, per_pin);
- }
- }
-
- /* if pcm_idx == -1, it means this is in monitor connection event
- * we can get the correct pcm_idx now.
- */
- if (pcm_idx == -1)
- pcm_idx = per_pin->pcm_idx;
- if (!pcm_jack)
- pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
-
- if (eld->eld_valid)
- snd_hdmi_show_eld(codec, &eld->info);
-
- eld_changed = (pin_eld->eld_valid != eld->eld_valid);
- eld_changed |= (pin_eld->monitor_present != eld->monitor_present);
- if (!eld_changed && eld->eld_valid && pin_eld->eld_valid)
- if (pin_eld->eld_size != eld->eld_size ||
- memcmp(pin_eld->eld_buffer, eld->eld_buffer,
- eld->eld_size) != 0)
- eld_changed = true;
-
- if (eld_changed) {
- pin_eld->monitor_present = eld->monitor_present;
- pin_eld->eld_valid = eld->eld_valid;
- pin_eld->eld_size = eld->eld_size;
- if (eld->eld_valid)
- memcpy(pin_eld->eld_buffer, eld->eld_buffer,
- eld->eld_size);
- pin_eld->info = eld->info;
- }
-
- /*
- * Re-setup pin and infoframe. This is needed e.g. when
- * - sink is first plugged-in
- * - transcoder can change during stream playback on Haswell
- * and this can make HW reset converter selection on a pin.
- */
- if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
- pin_cvt_fixup(codec, per_pin, 0);
- hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
- }
-
- if (eld_changed && pcm_idx >= 0)
- snd_ctl_notify(codec->card,
- SNDRV_CTL_EVENT_MASK_VALUE |
- SNDRV_CTL_EVENT_MASK_INFO,
- &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
-
- if (eld_changed && pcm_jack)
- snd_jack_report(pcm_jack,
- (eld->monitor_present && eld->eld_valid) ?
- SND_JACK_AVOUT : 0);
-}
-
-/* update ELD and jack state via HD-audio verbs */
-static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
- int repoll)
-{
- struct hda_codec *codec = per_pin->codec;
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_eld *eld = &spec->temp_eld;
- struct device *dev = hda_codec_dev(codec);
- hda_nid_t pin_nid = per_pin->pin_nid;
- int dev_id = per_pin->dev_id;
- /*
- * Always execute a GetPinSense verb here, even when called from
- * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
- * response's PD bit is not the real PD value, but indicates that
- * the real PD value changed. An older version of the HD-audio
- * specification worked this way. Hence, we just ignore the data in
- * the unsolicited response to avoid custom WARs.
- */
- int present;
- int ret;
-
-#ifdef CONFIG_PM
- if (dev->power.runtime_status == RPM_SUSPENDING)
- return;
-#endif
-
- ret = snd_hda_power_up_pm(codec);
- if (ret < 0 && pm_runtime_suspended(dev))
- goto out;
-
- present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
-
- mutex_lock(&per_pin->lock);
- eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
- if (eld->monitor_present)
- eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
- else
- eld->eld_valid = false;
-
- codec_dbg(codec,
- "HDMI status: Codec=%d NID=0x%x Presence_Detect=%d ELD_Valid=%d\n",
- codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
-
- if (eld->eld_valid) {
- if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
- eld->eld_buffer, &eld->eld_size) < 0)
- eld->eld_valid = false;
- }
-
- update_eld(codec, per_pin, eld, repoll);
- mutex_unlock(&per_pin->lock);
- out:
- snd_hda_power_down_pm(codec);
-}
-
-#define I915_SILENT_RATE 48000
-#define I915_SILENT_CHANNELS 2
-#define I915_SILENT_FORMAT SNDRV_PCM_FORMAT_S16_LE
-#define I915_SILENT_FORMAT_BITS 16
-#define I915_SILENT_FMT_MASK 0xf
-
-static void silent_stream_enable_i915(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- unsigned int format;
-
- snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
- per_pin->dev_id, I915_SILENT_RATE);
-
- /* trigger silent stream generation in hw */
- format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS,
- I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0);
- snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
- I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
- usleep_range(100, 200);
- snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
-
- per_pin->channels = I915_SILENT_CHANNELS;
- hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
-}
-
-static void silent_stream_set_kae(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- bool enable)
-{
- unsigned int param;
-
- codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
-
- param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
- param = (param >> 16) & 0xff;
-
- if (enable)
- param |= AC_DIG3_KAE;
- else
- param &= ~AC_DIG3_KAE;
-
- snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
-}
-
-static void silent_stream_enable(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_cvt *per_cvt;
- int cvt_idx, pin_idx, err;
- int keep_power = 0;
-
- /*
- * Power-up will call hdmi_present_sense, so the PM calls
- * have to be done without mutex held.
- */
-
- err = snd_hda_power_up_pm(codec);
- if (err < 0 && err != -EACCES) {
- codec_err(codec,
- "Failed to power up codec for silent stream enable ret=[%d]\n", err);
- snd_hda_power_down_pm(codec);
- return;
- }
-
- mutex_lock(&per_pin->lock);
-
- if (per_pin->setup) {
- codec_dbg(codec, "hdmi: PCM already open, no silent stream\n");
- err = -EBUSY;
- goto unlock_out;
- }
-
- pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id);
- err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, true);
- if (err) {
- codec_err(codec, "hdmi: no free converter to enable silent mode\n");
- goto unlock_out;
- }
-
- per_cvt = get_cvt(spec, cvt_idx);
- per_cvt->silent_stream = true;
- per_pin->cvt_nid = per_cvt->cvt_nid;
- per_pin->silent_stream = true;
-
- codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n",
- per_pin->pin_nid, per_cvt->cvt_nid);
-
- snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
- snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- per_pin->mux_idx);
-
- /* configure unused pins to choose other converters */
- pin_cvt_fixup(codec, per_pin, 0);
-
- switch (spec->silent_stream_type) {
- case SILENT_STREAM_KAE:
- silent_stream_enable_i915(codec, per_pin);
- silent_stream_set_kae(codec, per_pin, true);
- break;
- case SILENT_STREAM_I915:
- silent_stream_enable_i915(codec, per_pin);
- keep_power = 1;
- break;
- default:
- break;
- }
-
- unlock_out:
- mutex_unlock(&per_pin->lock);
-
- if (err || !keep_power)
- snd_hda_power_down_pm(codec);
-}
-
-static void silent_stream_disable(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_cvt *per_cvt;
- int cvt_idx, err;
-
- err = snd_hda_power_up_pm(codec);
- if (err < 0 && err != -EACCES) {
- codec_err(codec,
- "Failed to power up codec for silent stream disable ret=[%d]\n",
- err);
- snd_hda_power_down_pm(codec);
- return;
- }
-
- mutex_lock(&per_pin->lock);
- if (!per_pin->silent_stream)
- goto unlock_out;
-
- codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n",
- per_pin->pin_nid, per_pin->cvt_nid);
-
- cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
- if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) {
- per_cvt = get_cvt(spec, cvt_idx);
- per_cvt->silent_stream = false;
- }
-
- if (spec->silent_stream_type == SILENT_STREAM_I915) {
- /* release ref taken in silent_stream_enable() */
- snd_hda_power_down_pm(codec);
- } else if (spec->silent_stream_type == SILENT_STREAM_KAE) {
- silent_stream_set_kae(codec, per_pin, false);
- }
-
- per_pin->cvt_nid = 0;
- per_pin->silent_stream = false;
-
- unlock_out:
- mutex_unlock(&per_pin->lock);
-
- snd_hda_power_down_pm(codec);
-}
-
-/* update ELD and jack state via audio component */
-static void sync_eld_via_acomp(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_eld *eld = &spec->temp_eld;
- bool monitor_prev, monitor_next;
-
- mutex_lock(&per_pin->lock);
- eld->monitor_present = false;
- monitor_prev = per_pin->sink_eld.monitor_present;
- eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
- per_pin->dev_id, &eld->monitor_present,
- eld->eld_buffer, ELD_MAX_SIZE);
- eld->eld_valid = (eld->eld_size > 0);
- update_eld(codec, per_pin, eld, 0);
- monitor_next = per_pin->sink_eld.monitor_present;
- mutex_unlock(&per_pin->lock);
-
- if (spec->silent_stream_type) {
- if (!monitor_prev && monitor_next)
- silent_stream_enable(codec, per_pin);
- else if (monitor_prev && !monitor_next)
- silent_stream_disable(codec, per_pin);
- }
-}
-
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
-{
- struct hda_codec *codec = per_pin->codec;
-
- if (!codec_has_acomp(codec))
- hdmi_present_sense_via_verbs(per_pin, repoll);
- else
- sync_eld_via_acomp(codec, per_pin);
-}
-
-static void hdmi_repoll_eld(struct work_struct *work)
-{
- struct hdmi_spec_per_pin *per_pin =
- container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
- struct hda_codec *codec = per_pin->codec;
- struct hdmi_spec *spec = codec->spec;
- struct hda_jack_tbl *jack;
-
- jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
- per_pin->dev_id);
- if (jack)
- jack->jack_dirty = 1;
-
- if (per_pin->repoll_count++ > 6)
- per_pin->repoll_count = 0;
-
- mutex_lock(&spec->pcm_lock);
- hdmi_present_sense(per_pin, per_pin->repoll_count);
- mutex_unlock(&spec->pcm_lock);
-}
-
-static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
-{
- struct hdmi_spec *spec = codec->spec;
- unsigned int caps, config;
- int pin_idx;
- struct hdmi_spec_per_pin *per_pin;
- int err;
- int dev_num, i;
-
- caps = snd_hda_query_pin_caps(codec, pin_nid);
- if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
- return 0;
-
- /*
- * For DP MST audio, Configuration Default is the same for
- * all device entries on the same pin
- */
- config = snd_hda_codec_get_pincfg(codec, pin_nid);
- if (get_defcfg_connect(config) == AC_JACK_PORT_NONE &&
- !spec->force_connect)
- return 0;
-
- /*
- * To simplify the implementation, malloc all
- * the virtual pins in the initialization statically
- */
- if (spec->intel_hsw_fixup) {
- /*
- * On Intel platforms, device entries count returned
- * by AC_PAR_DEVLIST_LEN is dynamic, and depends on
- * the type of receiver that is connected. Allocate pin
- * structures based on worst case.
- */
- dev_num = spec->dev_num;
- } else if (codec->dp_mst) {
- dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
- /*
- * spec->dev_num is the maxinum number of device entries
- * among all the pins
- */
- spec->dev_num = (spec->dev_num > dev_num) ?
- spec->dev_num : dev_num;
- } else {
- /*
- * If the platform doesn't support DP MST,
- * manually set dev_num to 1. This means
- * the pin has only one device entry.
- */
- dev_num = 1;
- spec->dev_num = 1;
- }
-
- for (i = 0; i < dev_num; i++) {
- pin_idx = spec->num_pins;
- per_pin = snd_array_new(&spec->pins);
-
- if (!per_pin)
- return -ENOMEM;
-
- per_pin->pcm = NULL;
- per_pin->pcm_idx = -1;
- per_pin->prev_pcm_idx = -1;
- per_pin->pin_nid = pin_nid;
- per_pin->pin_nid_idx = spec->num_nids;
- per_pin->dev_id = i;
- per_pin->non_pcm = false;
- snd_hda_set_dev_select(codec, pin_nid, i);
- err = hdmi_read_pin_conn(codec, pin_idx);
- if (err < 0)
- return err;
- if (!is_jack_detectable(codec, pin_nid))
- codec_warn(codec, "HDMI: pin NID 0x%x - jack not detectable\n", pin_nid);
- spec->num_pins++;
- }
- spec->num_nids++;
-
- return 0;
-}
-
-static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_cvt *per_cvt;
- unsigned int chans;
- int err;
-
- chans = get_wcaps(codec, cvt_nid);
- chans = get_wcaps_channels(chans);
-
- per_cvt = snd_array_new(&spec->cvts);
- if (!per_cvt)
- return -ENOMEM;
-
- per_cvt->cvt_nid = cvt_nid;
- per_cvt->channels_min = 2;
- if (chans <= 16) {
- per_cvt->channels_max = chans;
- if (chans > spec->chmap.channels_max)
- spec->chmap.channels_max = chans;
- }
-
- err = snd_hda_query_supported_pcm(codec, cvt_nid,
- &per_cvt->rates,
- &per_cvt->formats,
- &per_cvt->maxbps);
- if (err < 0)
- return err;
-
- if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
- spec->cvt_nids[spec->num_cvts] = cvt_nid;
- spec->num_cvts++;
-
- return 0;
-}
-
-static const struct snd_pci_quirk force_connect_list[] = {
- SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
- SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
- SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
- SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
- SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
- SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
- {}
-};
-
-static int hdmi_parse_codec(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- hda_nid_t start_nid;
- unsigned int caps;
- int i, nodes;
- const struct snd_pci_quirk *q;
-
- nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
- if (!start_nid || nodes < 0) {
- codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
- return -EINVAL;
- }
-
- if (enable_all_pins)
- spec->force_connect = true;
-
- q = snd_pci_quirk_lookup(codec->bus->pci, force_connect_list);
-
- if (q && q->value)
- spec->force_connect = true;
-
- /*
- * hdmi_add_pin() assumes total amount of converters to
- * be known, so first discover all converters
- */
- for (i = 0; i < nodes; i++) {
- hda_nid_t nid = start_nid + i;
-
- caps = get_wcaps(codec, nid);
-
- if (!(caps & AC_WCAP_DIGITAL))
- continue;
-
- if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
- hdmi_add_cvt(codec, nid);
- }
-
- /* discover audio pins */
- for (i = 0; i < nodes; i++) {
- hda_nid_t nid = start_nid + i;
-
- caps = get_wcaps(codec, nid);
-
- if (!(caps & AC_WCAP_DIGITAL))
- continue;
-
- if (get_wcaps_type(caps) == AC_WID_PIN)
- hdmi_add_pin(codec, nid);
- }
-
- return 0;
-}
-
-/*
- */
-static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
-{
- struct hda_spdif_out *spdif;
- bool non_pcm;
-
- mutex_lock(&codec->spdif_mutex);
- spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
- /* Add sanity check to pass klockwork check.
- * This should never happen.
- */
- if (WARN_ON(spdif == NULL)) {
- mutex_unlock(&codec->spdif_mutex);
- return true;
- }
- non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
- mutex_unlock(&codec->spdif_mutex);
- return non_pcm;
-}
-
-/*
- * HDMI callbacks
- */
-
-static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- hda_nid_t cvt_nid = hinfo->nid;
- struct hdmi_spec *spec = codec->spec;
- int pin_idx;
- struct hdmi_spec_per_pin *per_pin;
- struct snd_pcm_runtime *runtime = substream->runtime;
- bool non_pcm;
- int pinctl, stripe;
- int err = 0;
-
- mutex_lock(&spec->pcm_lock);
- pin_idx = hinfo_to_pin_index(codec, hinfo);
- if (pin_idx < 0) {
- /* when pcm is not bound to a pin skip pin setup and return 0
- * to make audio playback be ongoing
- */
- pin_cvt_fixup(codec, NULL, cvt_nid);
- snd_hda_codec_setup_stream(codec, cvt_nid,
- stream_tag, 0, format);
- goto unlock;
- }
-
- per_pin = get_pin(spec, pin_idx);
-
- /* Verify pin:cvt selections to avoid silent audio after S3.
- * After S3, the audio driver restores pin:cvt selections
- * but this can happen before gfx is ready and such selection
- * is overlooked by HW. Thus multiple pins can share a same
- * default convertor and mute control will affect each other,
- * which can cause a resumed audio playback become silent
- * after S3.
- */
- pin_cvt_fixup(codec, per_pin, 0);
-
- /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
- /* Todo: add DP1.2 MST audio support later */
- if (codec_has_acomp(codec))
- snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
- per_pin->dev_id, runtime->rate);
-
- non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
- mutex_lock(&per_pin->lock);
- per_pin->channels = substream->runtime->channels;
- per_pin->setup = true;
-
- if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) {
- stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core,
- substream);
- snd_hda_codec_write(codec, cvt_nid, 0,
- AC_VERB_SET_STRIPE_CONTROL,
- stripe);
- }
-
- hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
- mutex_unlock(&per_pin->lock);
- if (spec->dyn_pin_out) {
- snd_hda_set_dev_select(codec, per_pin->pin_nid,
- per_pin->dev_id);
- pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl | PIN_OUT);
- }
-
- /* snd_hda_set_dev_select() has been called before */
- err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid,
- per_pin->dev_id, stream_tag, format);
- unlock:
- mutex_unlock(&spec->pcm_lock);
- return err;
-}
-
-static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- snd_hda_codec_cleanup_stream(codec, hinfo->nid);
- return 0;
-}
-
-static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- int cvt_idx, pin_idx, pcm_idx;
- struct hdmi_spec_per_cvt *per_cvt;
- struct hdmi_spec_per_pin *per_pin;
- int pinctl;
- int err = 0;
-
- mutex_lock(&spec->pcm_lock);
- if (hinfo->nid) {
- pcm_idx = hinfo_to_pcm_index(codec, hinfo);
- if (snd_BUG_ON(pcm_idx < 0)) {
- err = -EINVAL;
- goto unlock;
- }
- cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
- if (snd_BUG_ON(cvt_idx < 0)) {
- err = -EINVAL;
- goto unlock;
- }
- per_cvt = get_cvt(spec, cvt_idx);
- per_cvt->assigned = false;
- hinfo->nid = 0;
-
- azx_stream(get_azx_dev(substream))->stripe = 0;
-
- snd_hda_spdif_ctls_unassign(codec, pcm_idx);
- clear_bit(pcm_idx, &spec->pcm_in_use);
- pin_idx = hinfo_to_pin_index(codec, hinfo);
- /*
- * In such a case, return 0 to match the behavior in
- * hdmi_pcm_open()
- */
- if (pin_idx < 0)
- goto unlock;
-
- per_pin = get_pin(spec, pin_idx);
-
- if (spec->dyn_pin_out) {
- snd_hda_set_dev_select(codec, per_pin->pin_nid,
- per_pin->dev_id);
- pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl & ~PIN_OUT);
- }
-
- mutex_lock(&per_pin->lock);
- per_pin->chmap_set = false;
- memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
-
- per_pin->setup = false;
- per_pin->channels = 0;
- mutex_unlock(&per_pin->lock);
- }
-
-unlock:
- mutex_unlock(&spec->pcm_lock);
-
- return err;
-}
-
-static const struct hda_pcm_ops generic_ops = {
- .open = hdmi_pcm_open,
- .close = hdmi_pcm_close,
- .prepare = generic_hdmi_playback_pcm_prepare,
- .cleanup = generic_hdmi_playback_pcm_cleanup,
-};
-
-static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
-{
- struct hda_codec *codec = hdac_to_hda_codec(hdac);
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
- if (!per_pin)
- return 0;
-
- return per_pin->sink_eld.info.spk_alloc;
-}
-
-static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
- unsigned char *chmap)
-{
- struct hda_codec *codec = hdac_to_hda_codec(hdac);
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
- /* chmap is already set to 0 in caller */
- if (!per_pin)
- return;
-
- memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap));
-}
-
-static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
- unsigned char *chmap, int prepared)
-{
- struct hda_codec *codec = hdac_to_hda_codec(hdac);
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
- if (!per_pin)
- return;
- mutex_lock(&per_pin->lock);
- per_pin->chmap_set = true;
- memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
- if (prepared)
- hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
- mutex_unlock(&per_pin->lock);
-}
-
-static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
-{
- struct hda_codec *codec = hdac_to_hda_codec(hdac);
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
- return per_pin ? true:false;
-}
-
-static int generic_hdmi_build_pcms(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int idx, pcm_num;
-
- /* limit the PCM devices to the codec converters or available PINs */
- pcm_num = min(spec->num_cvts, spec->num_pins);
- codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num);
-
- for (idx = 0; idx < pcm_num; idx++) {
- struct hda_pcm *info;
- struct hda_pcm_stream *pstr;
-
- info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
- if (!info)
- return -ENOMEM;
-
- spec->pcm_rec[idx].pcm = info;
- spec->pcm_used++;
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- info->own_chmap = true;
-
- pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
- pstr->substreams = 1;
- pstr->ops = generic_ops;
- /* pcm number is less than pcm_rec array size */
- if (spec->pcm_used >= ARRAY_SIZE(spec->pcm_rec))
- break;
- /* other pstr fields are set in open */
- }
-
- return 0;
-}
-
-static void free_hdmi_jack_priv(struct snd_jack *jack)
-{
- struct hdmi_pcm *pcm = jack->private_data;
-
- pcm->jack = NULL;
-}
-
-static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
-{
- char hdmi_str[32] = "HDMI/DP";
- struct hdmi_spec *spec = codec->spec;
- struct snd_jack *jack;
- int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
- int err;
-
- if (pcmdev > 0)
- sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
-
- err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
- true, false);
- if (err < 0)
- return err;
-
- spec->pcm_rec[pcm_idx].jack = jack;
- jack->private_data = &spec->pcm_rec[pcm_idx];
- jack->private_free = free_hdmi_jack_priv;
- return 0;
-}
-
-static int generic_hdmi_build_controls(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int dev, err;
- int pin_idx, pcm_idx;
-
- for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
- if (!get_pcm_rec(spec, pcm_idx)->pcm) {
- /* no PCM: mark this for skipping permanently */
- set_bit(pcm_idx, &spec->pcm_bitmap);
- continue;
- }
-
- err = generic_hdmi_build_jack(codec, pcm_idx);
- if (err < 0)
- return err;
-
- /* create the spdif for each pcm
- * pin will be bound when monitor is connected
- */
- err = snd_hda_create_dig_out_ctls(codec,
- 0, spec->cvt_nids[0],
- HDA_PCM_TYPE_HDMI);
- if (err < 0)
- return err;
- snd_hda_spdif_ctls_unassign(codec, pcm_idx);
-
- dev = get_pcm_rec(spec, pcm_idx)->device;
- if (dev != SNDRV_PCM_INVALID_DEVICE) {
- /* add control for ELD Bytes */
- err = hdmi_create_eld_ctl(codec, pcm_idx, dev);
- if (err < 0)
- return err;
- }
- }
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- struct hdmi_eld *pin_eld = &per_pin->sink_eld;
-
- if (spec->static_pcm_mapping) {
- hdmi_attach_hda_pcm(spec, per_pin);
- hdmi_pcm_setup_pin(spec, per_pin);
- }
-
- pin_eld->eld_valid = false;
- hdmi_present_sense(per_pin, 0);
- }
-
- /* add channel maps */
- for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
- struct hda_pcm *pcm;
-
- pcm = get_pcm_rec(spec, pcm_idx);
- if (!pcm || !pcm->pcm)
- break;
- err = snd_hdac_add_chmap_ctls(pcm->pcm, pcm_idx, &spec->chmap);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static int generic_hdmi_init_per_pins(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
- per_pin->codec = codec;
- mutex_init(&per_pin->lock);
- INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
- eld_proc_new(per_pin, pin_idx);
- }
- return 0;
-}
-
-static int generic_hdmi_init(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx;
-
- mutex_lock(&spec->bind_lock);
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- hda_nid_t pin_nid = per_pin->pin_nid;
- int dev_id = per_pin->dev_id;
-
- snd_hda_set_dev_select(codec, pin_nid, dev_id);
- hdmi_init_pin(codec, pin_nid);
- if (codec_has_acomp(codec))
- continue;
- snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id,
- jack_callback);
- }
- mutex_unlock(&spec->bind_lock);
- return 0;
-}
-
-static void hdmi_array_init(struct hdmi_spec *spec, int nums)
-{
- snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
- snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
-}
-
-static void hdmi_array_free(struct hdmi_spec *spec)
-{
- snd_array_free(&spec->pins);
- snd_array_free(&spec->cvts);
-}
-
-static void generic_spec_free(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
-
- if (spec) {
- hdmi_array_free(spec);
- kfree(spec);
- codec->spec = NULL;
- }
- codec->dp_mst = false;
-}
-
-static void generic_hdmi_free(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx, pcm_idx;
-
- if (spec->acomp_registered) {
- snd_hdac_acomp_exit(&codec->bus->core);
- } else if (codec_has_acomp(codec)) {
- snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
- }
- codec->relaxed_resume = 0;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- cancel_delayed_work_sync(&per_pin->work);
- eld_proc_free(per_pin);
- }
-
- for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
- if (spec->pcm_rec[pcm_idx].jack == NULL)
- continue;
- snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack);
- }
-
- generic_spec_free(codec);
-}
-
-#ifdef CONFIG_PM
-static int generic_hdmi_suspend(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- cancel_delayed_work_sync(&per_pin->work);
- }
- return 0;
-}
-
-static int generic_hdmi_resume(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx;
-
- codec->patch_ops.init(codec);
- snd_hda_regmap_sync(codec);
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- hdmi_present_sense(per_pin, 1);
- }
- return 0;
-}
-#endif
-
-static const struct hda_codec_ops generic_hdmi_patch_ops = {
- .init = generic_hdmi_init,
- .free = generic_hdmi_free,
- .build_pcms = generic_hdmi_build_pcms,
- .build_controls = generic_hdmi_build_controls,
- .unsol_event = hdmi_unsol_event,
-#ifdef CONFIG_PM
- .suspend = generic_hdmi_suspend,
- .resume = generic_hdmi_resume,
-#endif
-};
-
-static const struct hdmi_ops generic_standard_hdmi_ops = {
- .pin_get_eld = hdmi_pin_get_eld,
- .pin_setup_infoframe = hdmi_pin_setup_infoframe,
- .pin_hbr_setup = hdmi_pin_hbr_setup,
- .setup_stream = hdmi_setup_stream,
-};
-
-/* allocate codec->spec and assign/initialize generic parser ops */
-static int alloc_generic_hdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
-
- spec->codec = codec;
- spec->ops = generic_standard_hdmi_ops;
- spec->dev_num = 1; /* initialize to 1 */
- mutex_init(&spec->pcm_lock);
- mutex_init(&spec->bind_lock);
- snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
-
- spec->chmap.ops.get_chmap = hdmi_get_chmap;
- spec->chmap.ops.set_chmap = hdmi_set_chmap;
- spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
- spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc;
-
- codec->spec = spec;
- hdmi_array_init(spec, 4);
-
- codec->patch_ops = generic_hdmi_patch_ops;
-
- return 0;
-}
-
-/* generic HDMI parser */
-static int patch_generic_hdmi(struct hda_codec *codec)
-{
- int err;
-
- err = alloc_generic_hdmi(codec);
- if (err < 0)
- return err;
-
- err = hdmi_parse_codec(codec);
- if (err < 0) {
- generic_spec_free(codec);
- return err;
- }
-
- generic_hdmi_init_per_pins(codec);
- return 0;
-}
-
-/*
- * generic audio component binding
- */
-
-/* turn on / off the unsol event jack detection dynamically */
-static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid,
- int dev_id, bool use_acomp)
-{
- struct hda_jack_tbl *tbl;
-
- tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
- if (tbl) {
- /* clear unsol even if component notifier is used, or re-enable
- * if notifier is cleared
- */
- unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag);
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE, val);
- }
-}
-
-/* set up / clear component notifier dynamically */
-static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
- bool use_acomp)
-{
- struct hdmi_spec *spec;
- int i;
-
- spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops);
- mutex_lock(&spec->bind_lock);
- spec->use_acomp_notifier = use_acomp;
- spec->codec->relaxed_resume = use_acomp;
- spec->codec->bus->keep_power = 0;
- /* reprogram each jack detection logic depending on the notifier */
- for (i = 0; i < spec->num_pins; i++)
- reprogram_jack_detect(spec->codec,
- get_pin(spec, i)->pin_nid,
- get_pin(spec, i)->dev_id,
- use_acomp);
- mutex_unlock(&spec->bind_lock);
-}
-
-/* enable / disable the notifier via master bind / unbind */
-static int generic_acomp_master_bind(struct device *dev,
- struct drm_audio_component *acomp)
-{
- generic_acomp_notifier_set(acomp, true);
- return 0;
-}
-
-static void generic_acomp_master_unbind(struct device *dev,
- struct drm_audio_component *acomp)
-{
- generic_acomp_notifier_set(acomp, false);
-}
-
-/* check whether both HD-audio and DRM PCI devices belong to the same bus */
-static int match_bound_vga(struct device *dev, int subtype, void *data)
-{
- struct hdac_bus *bus = data;
- struct pci_dev *pci, *master;
-
- if (!dev_is_pci(dev) || !dev_is_pci(bus->dev))
- return 0;
- master = to_pci_dev(bus->dev);
- pci = to_pci_dev(dev);
- return master->bus == pci->bus;
-}
-
-/* audio component notifier for AMD/Nvidia HDMI codecs */
-static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
-{
- struct hda_codec *codec = audio_ptr;
- struct hdmi_spec *spec = codec->spec;
- hda_nid_t pin_nid = spec->port2pin(codec, port);
-
- if (!pin_nid)
- return;
- if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN)
- return;
- /* skip notification during system suspend (but not in runtime PM);
- * the state will be updated at resume
- */
- if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
- return;
-
- check_presence_and_report(codec, pin_nid, dev_id);
-}
-
-/* set up the private drm_audio_ops from the template */
-static void setup_drm_audio_ops(struct hda_codec *codec,
- const struct drm_audio_component_audio_ops *ops)
-{
- struct hdmi_spec *spec = codec->spec;
-
- spec->drm_audio_ops.audio_ptr = codec;
- /* intel_audio_codec_enable() or intel_audio_codec_disable()
- * will call pin_eld_notify with using audio_ptr pointer
- * We need make sure audio_ptr is really setup
- */
- wmb();
- spec->drm_audio_ops.pin2port = ops->pin2port;
- spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify;
- spec->drm_audio_ops.master_bind = ops->master_bind;
- spec->drm_audio_ops.master_unbind = ops->master_unbind;
-}
-
-/* initialize the generic HDMI audio component */
-static void generic_acomp_init(struct hda_codec *codec,
- const struct drm_audio_component_audio_ops *ops,
- int (*port2pin)(struct hda_codec *, int))
-{
- struct hdmi_spec *spec = codec->spec;
-
- if (!enable_acomp) {
- codec_info(codec, "audio component disabled by module option\n");
- return;
- }
-
- spec->port2pin = port2pin;
- setup_drm_audio_ops(codec, ops);
- if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
- match_bound_vga, 0)) {
- spec->acomp_registered = true;
- }
-}
-
-/*
- * Intel codec parsers and helpers
- */
-
-#define INTEL_GET_VENDOR_VERB 0xf81
-#define INTEL_SET_VENDOR_VERB 0x781
-#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
-#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
-
-static void intel_haswell_enable_all_pins(struct hda_codec *codec,
- bool update_tree)
-{
- unsigned int vendor_param;
- struct hdmi_spec *spec = codec->spec;
-
- vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
- INTEL_GET_VENDOR_VERB, 0);
- if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
- return;
-
- vendor_param |= INTEL_EN_ALL_PIN_CVTS;
- vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
- INTEL_SET_VENDOR_VERB, vendor_param);
- if (vendor_param == -1)
- return;
-
- if (update_tree)
- snd_hda_codec_update_widgets(codec);
-}
-
-static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
-{
- unsigned int vendor_param;
- struct hdmi_spec *spec = codec->spec;
-
- vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
- INTEL_GET_VENDOR_VERB, 0);
- if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
- return;
-
- /* enable DP1.2 mode */
- vendor_param |= INTEL_EN_DP12;
- snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
- snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
- INTEL_SET_VENDOR_VERB, vendor_param);
-}
-
-/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
- * Otherwise you may get severe h/w communication errors.
- */
-static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state)
-{
- if (power_state == AC_PWRST_D0) {
- intel_haswell_enable_all_pins(codec, false);
- intel_haswell_fixup_enable_dp12(codec);
- }
-
- snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
- snd_hda_codec_set_power_to_all(codec, fg, power_state);
-}
-
-/* There is a fixed mapping between audio pin node and display port.
- * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- *
- * on VLV, ILK:
- * Pin Widget 4 - PORT B (port = 1 in i915 driver)
- * Pin Widget 5 - PORT C (port = 2 in i915 driver)
- * Pin Widget 6 - PORT D (port = 3 in i915 driver)
- */
-static int intel_base_nid(struct hda_codec *codec)
-{
- switch (codec->core.vendor_id) {
- case 0x80860054: /* ILK */
- case 0x80862804: /* ILK */
- case 0x80862882: /* VLV */
- return 4;
- default:
- return 5;
- }
-}
-
-static int intel_pin2port(void *audio_ptr, int pin_nid)
-{
- struct hda_codec *codec = audio_ptr;
- struct hdmi_spec *spec = codec->spec;
- int base_nid, i;
-
- if (!spec->port_num) {
- base_nid = intel_base_nid(codec);
- if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
- return -1;
- return pin_nid - base_nid + 1;
- }
-
- /*
- * looking for the pin number in the mapping table and return
- * the index which indicate the port number
- */
- for (i = 0; i < spec->port_num; i++) {
- if (pin_nid == spec->port_map[i])
- return i;
- }
-
- codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
- return -1;
-}
-
-static int intel_port2pin(struct hda_codec *codec, int port)
-{
- struct hdmi_spec *spec = codec->spec;
-
- if (!spec->port_num) {
- /* we assume only from port-B to port-D */
- if (port < 1 || port > 3)
- return 0;
- return port + intel_base_nid(codec) - 1;
- }
-
- if (port < 0 || port >= spec->port_num)
- return 0;
- return spec->port_map[port];
-}
-
-static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
-{
- struct hda_codec *codec = audio_ptr;
- int pin_nid;
- int dev_id = pipe;
-
- pin_nid = intel_port2pin(codec, port);
- if (!pin_nid)
- return;
- /* skip notification during system suspend (but not in runtime PM);
- * the state will be updated at resume
- */
- if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
- return;
-
- snd_hdac_i915_set_bclk(&codec->bus->core);
- check_presence_and_report(codec, pin_nid, dev_id);
-}
-
-static const struct drm_audio_component_audio_ops intel_audio_ops = {
- .pin2port = intel_pin2port,
- .pin_eld_notify = intel_pin_eld_notify,
-};
-
-/* register i915 component pin_eld_notify callback */
-static void register_i915_notifier(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
-
- spec->use_acomp_notifier = true;
- spec->port2pin = intel_port2pin;
- setup_drm_audio_ops(codec, &intel_audio_ops);
- snd_hdac_acomp_register_notifier(&codec->bus->core,
- &spec->drm_audio_ops);
- /* no need for forcible resume for jack check thanks to notifier */
- codec->relaxed_resume = 1;
-}
-
-/* setup_stream ops override for HSW+ */
-static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
- hda_nid_t pin_nid, int dev_id, u32 stream_tag,
- int format)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
- struct hdmi_spec_per_pin *per_pin;
- int res;
-
- if (pin_idx < 0)
- per_pin = NULL;
- else
- per_pin = get_pin(spec, pin_idx);
-
- haswell_verify_D0(codec, cvt_nid, pin_nid);
-
- if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
- silent_stream_set_kae(codec, per_pin, false);
- /* wait for pending transfers in codec to clear */
- usleep_range(100, 200);
- }
-
- res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
- stream_tag, format);
-
- if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
- usleep_range(100, 200);
- silent_stream_set_kae(codec, per_pin, true);
- }
-
- return res;
-}
-
-/* pin_cvt_fixup ops override for HSW+ and VLV+ */
-static void i915_pin_cvt_fixup(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- hda_nid_t cvt_nid)
-{
- if (per_pin) {
- haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
- snd_hda_set_dev_select(codec, per_pin->pin_nid,
- per_pin->dev_id);
- intel_verify_pin_cvt_connect(codec, per_pin);
- intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
- per_pin->dev_id, per_pin->mux_idx);
- } else {
- intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
- }
-}
-
-#ifdef CONFIG_PM
-static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- bool silent_streams = false;
- int pin_idx, res;
-
- res = generic_hdmi_suspend(codec);
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
- if (per_pin->silent_stream) {
- silent_streams = true;
- break;
- }
- }
-
- if (silent_streams && spec->silent_stream_type == SILENT_STREAM_KAE) {
- /*
- * stream-id should remain programmed when codec goes
- * to runtime suspend
- */
- codec->no_stream_clean_at_suspend = 1;
-
- /*
- * the system might go to S3, in which case keep-alive
- * must be reprogrammed upon resume
- */
- codec->forced_resume = 1;
-
- codec_dbg(codec, "HDMI: KAE active at suspend\n");
- } else {
- codec->no_stream_clean_at_suspend = 0;
- codec->forced_resume = 0;
- }
-
- return res;
-}
-
-static int i915_adlp_hdmi_resume(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx, res;
-
- res = generic_hdmi_resume(codec);
-
- /* KAE not programmed at suspend, nothing to do here */
- if (!codec->no_stream_clean_at_suspend)
- return res;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
- /*
- * If system was in suspend with monitor connected,
- * the codec setting may have been lost. Re-enable
- * keep-alive.
- */
- if (per_pin->silent_stream) {
- unsigned int param;
-
- param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
- AC_VERB_GET_CONV, 0);
- if (!param) {
- codec_dbg(codec, "HDMI: KAE: restore stream id\n");
- silent_stream_enable_i915(codec, per_pin);
- }
-
- param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
- AC_VERB_GET_DIGI_CONVERT_1, 0);
- if (!(param & (AC_DIG3_KAE << 16))) {
- codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
- silent_stream_set_kae(codec, per_pin, true);
- }
- }
- }
-
- return res;
-}
-#endif
-
-/* precondition and allocation for Intel codecs */
-static int alloc_intel_hdmi(struct hda_codec *codec)
-{
- int err;
-
- /* requires i915 binding */
- if (!codec->bus->core.audio_component) {
- codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
- /* set probe_id here to prevent generic fallback binding */
- codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
- return -ENODEV;
- }
-
- err = alloc_generic_hdmi(codec);
- if (err < 0)
- return err;
- /* no need to handle unsol events */
- codec->patch_ops.unsol_event = NULL;
- return 0;
-}
-
-/* parse and post-process for Intel codecs */
-static int parse_intel_hdmi(struct hda_codec *codec)
-{
- int err, retries = 3;
-
- do {
- err = hdmi_parse_codec(codec);
- } while (err < 0 && retries--);
-
- if (err < 0) {
- generic_spec_free(codec);
- return err;
- }
-
- generic_hdmi_init_per_pins(codec);
- register_i915_notifier(codec);
- return 0;
-}
-
-/* Intel Haswell and onwards; audio component with eld notifier */
-static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
- const int *port_map, int port_num, int dev_num,
- bool send_silent_stream)
-{
- struct hdmi_spec *spec;
- int err;
-
- err = alloc_intel_hdmi(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
- codec->dp_mst = true;
- spec->vendor_nid = vendor_nid;
- spec->port_map = port_map;
- spec->port_num = port_num;
- spec->intel_hsw_fixup = true;
- spec->dev_num = dev_num;
-
- intel_haswell_enable_all_pins(codec, true);
- intel_haswell_fixup_enable_dp12(codec);
-
- codec->display_power_control = 1;
-
- codec->patch_ops.set_power_state = haswell_set_power_state;
- codec->depop_delay = 0;
- codec->auto_runtime_pm = 1;
-
- spec->ops.setup_stream = i915_hsw_setup_stream;
- spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
-
- /*
- * Enable silent stream feature, if it is enabled via
- * module param or Kconfig option
- */
- if (send_silent_stream)
- spec->silent_stream_type = SILENT_STREAM_I915;
-
- return parse_intel_hdmi(codec);
-}
-
-static int patch_i915_hsw_hdmi(struct hda_codec *codec)
-{
- return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
- enable_silent_stream);
-}
-
-static int patch_i915_glk_hdmi(struct hda_codec *codec)
-{
- /*
- * Silent stream calls audio component .get_power() from
- * .pin_eld_notify(). On GLK this will deadlock in i915 due
- * to the audio vs. CDCLK workaround.
- */
- return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
-}
-
-static int patch_i915_icl_hdmi(struct hda_codec *codec)
-{
- /*
- * pin to port mapping table where the value indicate the pin number and
- * the index indicate the port number.
- */
- static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
-
- return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
- enable_silent_stream);
-}
-
-static int patch_i915_tgl_hdmi(struct hda_codec *codec)
-{
- /*
- * pin to port mapping table where the value indicate the pin number and
- * the index indicate the port number.
- */
- static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
-
- return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
- enable_silent_stream);
-}
-
-static int patch_i915_adlp_hdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int res;
-
- res = patch_i915_tgl_hdmi(codec);
- if (!res) {
- spec = codec->spec;
-
- if (spec->silent_stream_type) {
- spec->silent_stream_type = SILENT_STREAM_KAE;
-
-#ifdef CONFIG_PM
- codec->patch_ops.resume = i915_adlp_hdmi_resume;
- codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
-#endif
- }
- }
-
- return res;
-}
-
-/* Intel Baytrail and Braswell; with eld notifier */
-static int patch_i915_byt_hdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int err;
-
- err = alloc_intel_hdmi(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
-
- /* For Valleyview/Cherryview, only the display codec is in the display
- * power well and can use link_power ops to request/release the power.
- */
- codec->display_power_control = 1;
-
- codec->depop_delay = 0;
- codec->auto_runtime_pm = 1;
-
- spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
-
- return parse_intel_hdmi(codec);
-}
-
-/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
-static int patch_i915_cpt_hdmi(struct hda_codec *codec)
-{
- int err;
-
- err = alloc_intel_hdmi(codec);
- if (err < 0)
- return err;
- return parse_intel_hdmi(codec);
-}
-
-/*
- * Shared non-generic implementations
- */
-
-static int simple_playback_build_pcms(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info;
- unsigned int chans;
- struct hda_pcm_stream *pstr;
- struct hdmi_spec_per_cvt *per_cvt;
-
- per_cvt = get_cvt(spec, 0);
- chans = get_wcaps(codec, per_cvt->cvt_nid);
- chans = get_wcaps_channels(chans);
-
- info = snd_hda_codec_pcm_new(codec, "HDMI 0");
- if (!info)
- return -ENOMEM;
- spec->pcm_rec[0].pcm = info;
- info->pcm_type = HDA_PCM_TYPE_HDMI;
- pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
- *pstr = spec->pcm_playback;
- pstr->nid = per_cvt->cvt_nid;
- if (pstr->channels_max <= 2 && chans && chans <= 16)
- pstr->channels_max = chans;
-
- return 0;
-}
-
-/* unsolicited event for jack sensing */
-static void simple_hdmi_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- snd_hda_jack_set_dirty_all(codec);
- snd_hda_jack_report_sync(codec);
-}
-
-/* generic_hdmi_build_jack can be used for simple_hdmi, too,
- * as long as spec->pins[] is set correctly
- */
-#define simple_hdmi_build_jack generic_hdmi_build_jack
-
-static int simple_playback_build_controls(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_cvt *per_cvt;
- int err;
-
- per_cvt = get_cvt(spec, 0);
- err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
- per_cvt->cvt_nid,
- HDA_PCM_TYPE_HDMI);
- if (err < 0)
- return err;
- return simple_hdmi_build_jack(codec, 0);
-}
-
-static int simple_playback_init(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
- hda_nid_t pin = per_pin->pin_nid;
-
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- /* some codecs require to unmute the pin */
- if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
- snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
- return 0;
-}
-
-static void simple_playback_free(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
-
- hdmi_array_free(spec);
- kfree(spec);
-}
-
-/*
- * Nvidia specific implementations
- */
-
-#define Nv_VERB_SET_Channel_Allocation 0xF79
-#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A
-#define Nv_VERB_SET_Audio_Protection_On 0xF98
-#define Nv_VERB_SET_Audio_Protection_Off 0xF99
-
-#define nvhdmi_master_con_nid_7x 0x04
-#define nvhdmi_master_pin_nid_7x 0x05
-
-static const hda_nid_t nvhdmi_con_nids_7x[4] = {
- /*front, rear, clfe, rear_surr */
- 0x6, 0x8, 0xa, 0xc,
-};
-
-static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
- /* set audio protect on */
- { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
- /* enable digital output on pin widget */
- { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- {} /* terminator */
-};
-
-static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
- /* set audio protect on */
- { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
- /* enable digital output on pin widget */
- { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
- {} /* terminator */
-};
-
-#ifdef LIMITED_RATE_FMT_SUPPORT
-/* support only the safe format and rate */
-#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
-#define SUPPORTED_MAXBPS 16
-#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
-#else
-/* support all rates and formats */
-#define SUPPORTED_RATES \
- (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
- SNDRV_PCM_RATE_192000)
-#define SUPPORTED_MAXBPS 24
-#define SUPPORTED_FORMATS \
- (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#endif
-
-static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
-{
- snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
- return 0;
-}
-
-static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
-{
- snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
- return 0;
-}
-
-static const unsigned int channels_2_6_8[] = {
- 2, 6, 8
-};
-
-static const unsigned int channels_2_8[] = {
- 2, 8
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
- .count = ARRAY_SIZE(channels_2_6_8),
- .list = channels_2_6_8,
- .mask = 0,
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
- .count = ARRAY_SIZE(channels_2_8),
- .list = channels_2_8,
- .mask = 0,
-};
-
-static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
-
- switch (codec->preset->vendor_id) {
- case 0x10de0002:
- case 0x10de0003:
- case 0x10de0005:
- case 0x10de0006:
- hw_constraints_channels = &hw_constraints_2_8_channels;
- break;
- case 0x10de0007:
- hw_constraints_channels = &hw_constraints_2_6_8_channels;
- break;
- default:
- break;
- }
-
- if (hw_constraints_channels != NULL) {
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_constraints_channels);
- } else {
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- }
-
- return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
- stream_tag, format, substream);
-}
-
-static const struct hda_pcm_stream simple_pcm_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- .ops = {
- .open = simple_playback_pcm_open,
- .close = simple_playback_pcm_close,
- .prepare = simple_playback_pcm_prepare
- },
-};
-
-static const struct hda_codec_ops simple_hdmi_patch_ops = {
- .build_controls = simple_playback_build_controls,
- .build_pcms = simple_playback_build_pcms,
- .init = simple_playback_init,
- .free = simple_playback_free,
- .unsol_event = simple_hdmi_unsol_event,
-};
-
-static int patch_simple_hdmi(struct hda_codec *codec,
- hda_nid_t cvt_nid, hda_nid_t pin_nid)
-{
- struct hdmi_spec *spec;
- struct hdmi_spec_per_cvt *per_cvt;
- struct hdmi_spec_per_pin *per_pin;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
-
- spec->codec = codec;
- codec->spec = spec;
- hdmi_array_init(spec, 1);
-
- spec->multiout.num_dacs = 0; /* no analog */
- spec->multiout.max_channels = 2;
- spec->multiout.dig_out_nid = cvt_nid;
- spec->num_cvts = 1;
- spec->num_pins = 1;
- per_pin = snd_array_new(&spec->pins);
- per_cvt = snd_array_new(&spec->cvts);
- if (!per_pin || !per_cvt) {
- simple_playback_free(codec);
- return -ENOMEM;
- }
- per_cvt->cvt_nid = cvt_nid;
- per_pin->pin_nid = pin_nid;
- spec->pcm_playback = simple_pcm_playback;
-
- codec->patch_ops = simple_hdmi_patch_ops;
-
- return 0;
-}
-
-static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
- int channels)
-{
- unsigned int chanmask;
- int chan = channels ? (channels - 1) : 1;
-
- switch (channels) {
- default:
- case 0:
- case 2:
- chanmask = 0x00;
- break;
- case 4:
- chanmask = 0x08;
- break;
- case 6:
- chanmask = 0x0b;
- break;
- case 8:
- chanmask = 0x13;
- break;
- }
-
- /* Set the audio infoframe channel allocation and checksum fields. The
- * channel count is computed implicitly by the hardware. */
- snd_hda_codec_write(codec, 0x1, 0,
- Nv_VERB_SET_Channel_Allocation, chanmask);
-
- snd_hda_codec_write(codec, 0x1, 0,
- Nv_VERB_SET_Info_Frame_Checksum,
- (0x71 - chan - chanmask));
-}
-
-static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct hdmi_spec *spec = codec->spec;
- int i;
-
- snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
- 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
- for (i = 0; i < 4; i++) {
- /* set the stream id */
- snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
- AC_VERB_SET_CHANNEL_STREAMID, 0);
- /* set the stream format */
- snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
- AC_VERB_SET_STREAM_FORMAT, 0);
- }
-
- /* The audio hardware sends a channel count of 0x7 (8ch) when all the
- * streams are disabled. */
- nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
-
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- int chs;
- unsigned int dataDCC2, channel_id;
- int i;
- struct hdmi_spec *spec = codec->spec;
- struct hda_spdif_out *spdif;
- struct hdmi_spec_per_cvt *per_cvt;
-
- mutex_lock(&codec->spdif_mutex);
- per_cvt = get_cvt(spec, 0);
- spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
-
- chs = substream->runtime->channels;
-
- dataDCC2 = 0x2;
-
- /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
- if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
- snd_hda_codec_write(codec,
- nvhdmi_master_con_nid_7x,
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
-
- /* set the stream id */
- snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
- AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
-
- /* set the stream format */
- snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
- AC_VERB_SET_STREAM_FORMAT, format);
-
- /* turn on again (if needed) */
- /* enable and set the channel status audio/data flag */
- if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
- snd_hda_codec_write(codec,
- nvhdmi_master_con_nid_7x,
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- spdif->ctls & 0xff);
- snd_hda_codec_write(codec,
- nvhdmi_master_con_nid_7x,
- 0,
- AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
- }
-
- for (i = 0; i < 4; i++) {
- if (chs == 2)
- channel_id = 0;
- else
- channel_id = i * 2;
-
- /* turn off SPDIF once;
- *otherwise the IEC958 bits won't be updated
- */
- if (codec->spdif_status_reset &&
- (spdif->ctls & AC_DIG1_ENABLE))
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
- /* set the stream id */
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_CHANNEL_STREAMID,
- (stream_tag << 4) | channel_id);
- /* set the stream format */
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_STREAM_FORMAT,
- format);
- /* turn on again (if needed) */
- /* enable and set the channel status audio/data flag */
- if (codec->spdif_status_reset &&
- (spdif->ctls & AC_DIG1_ENABLE)) {
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- spdif->ctls & 0xff);
- snd_hda_codec_write(codec,
- nvhdmi_con_nids_7x[i],
- 0,
- AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
- }
- }
-
- nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
-
- mutex_unlock(&codec->spdif_mutex);
- return 0;
-}
-
-static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 8,
- .nid = nvhdmi_master_con_nid_7x,
- .rates = SUPPORTED_RATES,
- .maxbps = SUPPORTED_MAXBPS,
- .formats = SUPPORTED_FORMATS,
- .ops = {
- .open = simple_playback_pcm_open,
- .close = nvhdmi_8ch_7x_pcm_close,
- .prepare = nvhdmi_8ch_7x_pcm_prepare
- },
-};
-
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
- nvhdmi_master_pin_nid_7x);
- if (err < 0)
- return err;
-
- codec->patch_ops.init = nvhdmi_7x_init_2ch;
- /* override the PCM rates, etc, as the codec doesn't give full list */
- spec = codec->spec;
- spec->pcm_playback.rates = SUPPORTED_RATES;
- spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
- spec->pcm_playback.formats = SUPPORTED_FORMATS;
- spec->nv_dp_workaround = true;
- return 0;
-}
-
-static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int err = simple_playback_build_pcms(codec);
- if (!err) {
- struct hda_pcm *info = get_pcm_rec(spec, 0);
- info->own_chmap = true;
- }
- return err;
-}
-
-static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info;
- struct snd_pcm_chmap *chmap;
- int err;
-
- err = simple_playback_build_controls(codec);
- if (err < 0)
- return err;
-
- /* add channel maps */
- info = get_pcm_rec(spec, 0);
- err = snd_pcm_add_chmap_ctls(info->pcm,
- SNDRV_PCM_STREAM_PLAYBACK,
- snd_pcm_alt_chmaps, 8, 0, &chmap);
- if (err < 0)
- return err;
- switch (codec->preset->vendor_id) {
- case 0x10de0002:
- case 0x10de0003:
- case 0x10de0005:
- case 0x10de0006:
- chmap->channel_mask = (1U << 2) | (1U << 8);
- break;
- case 0x10de0007:
- chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
- }
- return 0;
-}
-
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int err = patch_nvhdmi_2ch(codec);
- if (err < 0)
- return err;
- spec = codec->spec;
- spec->multiout.max_channels = 8;
- spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
- codec->patch_ops.init = nvhdmi_7x_init_8ch;
- codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
- codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
-
- /* Initialize the audio infoframe channel mask and checksum to something
- * valid */
- nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
-
- return 0;
-}
-
-/*
- * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
- * - 0x10de0015
- * - 0x10de0040
- */
-static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
- struct hdac_cea_channel_speaker_allocation *cap, int channels)
-{
- if (cap->ca_index == 0x00 && channels == 2)
- return SNDRV_CTL_TLVT_CHMAP_FIXED;
-
- /* If the speaker allocation matches the channel count, it is OK. */
- if (cap->channels != channels)
- return -1;
-
- /* all channels are remappable freely */
- return SNDRV_CTL_TLVT_CHMAP_VAR;
-}
-
-static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
- int ca, int chs, unsigned char *map)
-{
- if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
- return -EINVAL;
-
- return 0;
-}
-
-/* map from pin NID to port; port is 0-based */
-/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
-static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
-{
- return pin_nid - 4;
-}
-
-/* reverse-map from port to pin NID: see above */
-static int nvhdmi_port2pin(struct hda_codec *codec, int port)
-{
- return port + 4;
-}
-
-static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
- .pin2port = nvhdmi_pin2port,
- .pin_eld_notify = generic_acomp_pin_eld_notify,
- .master_bind = generic_acomp_master_bind,
- .master_unbind = generic_acomp_master_unbind,
-};
-
-static int patch_nvhdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int err;
-
- err = alloc_generic_hdmi(codec);
- if (err < 0)
- return err;
- codec->dp_mst = true;
-
- spec = codec->spec;
-
- err = hdmi_parse_codec(codec);
- if (err < 0) {
- generic_spec_free(codec);
- return err;
- }
-
- generic_hdmi_init_per_pins(codec);
-
- spec->dyn_pin_out = true;
-
- spec->chmap.ops.chmap_cea_alloc_validate_get_type =
- nvhdmi_chmap_cea_alloc_validate_get_type;
- spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
- spec->nv_dp_workaround = true;
-
- codec->link_down_at_suspend = 1;
-
- generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
-
- return 0;
-}
-
-static int patch_nvhdmi_legacy(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int err;
-
- err = patch_generic_hdmi(codec);
- if (err)
- return err;
-
- spec = codec->spec;
- spec->dyn_pin_out = true;
-
- spec->chmap.ops.chmap_cea_alloc_validate_get_type =
- nvhdmi_chmap_cea_alloc_validate_get_type;
- spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
- spec->nv_dp_workaround = true;
-
- codec->link_down_at_suspend = 1;
-
- return 0;
-}
-
-/*
- * The HDA codec on NVIDIA Tegra contains two scratch registers that are
- * accessed using vendor-defined verbs. These registers can be used for
- * interoperability between the HDA and HDMI drivers.
- */
-
-/* Audio Function Group node */
-#define NVIDIA_AFG_NID 0x01
-
-/*
- * The SCRATCH0 register is used to notify the HDMI codec of changes in audio
- * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
- * be raised in the HDMI codec. The remainder of the bits is arbitrary. This
- * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
- * additional bit (at position 30) to signal the validity of the format.
- *
- * | 31 | 30 | 29 16 | 15 0 |
- * +---------+-------+--------+--------+
- * | TRIGGER | VALID | UNUSED | FORMAT |
- * +-----------------------------------|
- *
- * Note that for the trigger bit to take effect it needs to change value
- * (i.e. it needs to be toggled). The trigger bit is not applicable from
- * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
- * trigger to hdmi.
- */
-#define NVIDIA_SET_HOST_INTR 0xf80
-#define NVIDIA_GET_SCRATCH0 0xfa6
-#define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7
-#define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8
-#define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9
-#define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa
-#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
-#define NVIDIA_SCRATCH_VALID (1 << 6)
-
-#define NVIDIA_GET_SCRATCH1 0xfab
-#define NVIDIA_SET_SCRATCH1_BYTE0 0xfac
-#define NVIDIA_SET_SCRATCH1_BYTE1 0xfad
-#define NVIDIA_SET_SCRATCH1_BYTE2 0xfae
-#define NVIDIA_SET_SCRATCH1_BYTE3 0xfaf
-
-/*
- * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
- * the format is invalidated so that the HDMI codec can be disabled.
- */
-static void tegra_hdmi_set_format(struct hda_codec *codec,
- hda_nid_t cvt_nid,
- unsigned int format)
-{
- unsigned int value;
- unsigned int nid = NVIDIA_AFG_NID;
- struct hdmi_spec *spec = codec->spec;
-
- /*
- * Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
- * This resulted in moving scratch registers from audio function
- * group to converter widget context. So CVT NID should be used for
- * scratch register read/write for DP MST supported Tegra HDA codec.
- */
- if (codec->dp_mst)
- nid = cvt_nid;
-
- /* bits [31:30] contain the trigger and valid bits */
- value = snd_hda_codec_read(codec, nid, 0,
- NVIDIA_GET_SCRATCH0, 0);
- value = (value >> 24) & 0xff;
-
- /* bits [15:0] are used to store the HDA format */
- snd_hda_codec_write(codec, nid, 0,
- NVIDIA_SET_SCRATCH0_BYTE0,
- (format >> 0) & 0xff);
- snd_hda_codec_write(codec, nid, 0,
- NVIDIA_SET_SCRATCH0_BYTE1,
- (format >> 8) & 0xff);
-
- /* bits [16:24] are unused */
- snd_hda_codec_write(codec, nid, 0,
- NVIDIA_SET_SCRATCH0_BYTE2, 0);
-
- /*
- * Bit 30 signals that the data is valid and hence that HDMI audio can
- * be enabled.
- */
- if (format == 0)
- value &= ~NVIDIA_SCRATCH_VALID;
- else
- value |= NVIDIA_SCRATCH_VALID;
-
- if (spec->hdmi_intr_trig_ctrl) {
- /*
- * For Tegra HDA Codec design from TEGRA234 onwards, the
- * Interrupt to hdmi driver is triggered by writing
- * non-zero values to verb 0xF80 instead of 31st bit of
- * scratch register.
- */
- snd_hda_codec_write(codec, nid, 0,
- NVIDIA_SET_SCRATCH0_BYTE3, value);
- snd_hda_codec_write(codec, nid, 0,
- NVIDIA_SET_HOST_INTR, 0x1);
- } else {
- /*
- * Whenever the 31st trigger bit is toggled, an interrupt is raised
- * in the HDMI codec. The HDMI driver will use that as trigger
- * to update its configuration.
- */
- value ^= NVIDIA_SCRATCH_TRIGGER;
-
- snd_hda_codec_write(codec, nid, 0,
- NVIDIA_SET_SCRATCH0_BYTE3, value);
- }
-}
-
-static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- int err;
-
- err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag,
- format, substream);
- if (err < 0)
- return err;
-
- /* notify the HDMI codec of the format change */
- tegra_hdmi_set_format(codec, hinfo->nid, format);
-
- return 0;
-}
-
-static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- /* invalidate the format in the HDMI codec */
- tegra_hdmi_set_format(codec, hinfo->nid, 0);
-
- return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream);
-}
-
-static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
-{
- struct hdmi_spec *spec = codec->spec;
- unsigned int i;
-
- for (i = 0; i < spec->num_pins; i++) {
- struct hda_pcm *pcm = get_pcm_rec(spec, i);
-
- if (pcm->pcm_type == type)
- return pcm;
- }
-
- return NULL;
-}
-
-static int tegra_hdmi_build_pcms(struct hda_codec *codec)
-{
- struct hda_pcm_stream *stream;
- struct hda_pcm *pcm;
- int err;
-
- err = generic_hdmi_build_pcms(codec);
- if (err < 0)
- return err;
-
- pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
- if (!pcm)
- return -ENODEV;
-
- /*
- * Override ->prepare() and ->cleanup() operations to notify the HDMI
- * codec about format changes.
- */
- stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
- stream->ops.prepare = tegra_hdmi_pcm_prepare;
- stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
-
- return 0;
-}
-
-static int tegra_hdmi_init(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int i, err;
-
- err = hdmi_parse_codec(codec);
- if (err < 0) {
- generic_spec_free(codec);
- return err;
- }
-
- for (i = 0; i < spec->num_cvts; i++)
- snd_hda_codec_write(codec, spec->cvt_nids[i], 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- AC_DIG1_ENABLE);
-
- generic_hdmi_init_per_pins(codec);
-
- codec->depop_delay = 10;
- codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
- spec->chmap.ops.chmap_cea_alloc_validate_get_type =
- nvhdmi_chmap_cea_alloc_validate_get_type;
- spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-
- spec->chmap.ops.chmap_cea_alloc_validate_get_type =
- nvhdmi_chmap_cea_alloc_validate_get_type;
- spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
- spec->nv_dp_workaround = true;
-
- return 0;
-}
-
-static int patch_tegra_hdmi(struct hda_codec *codec)
-{
- int err;
-
- err = alloc_generic_hdmi(codec);
- if (err < 0)
- return err;
-
- return tegra_hdmi_init(codec);
-}
-
-static int patch_tegra234_hdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- int err;
-
- err = alloc_generic_hdmi(codec);
- if (err < 0)
- return err;
-
- codec->dp_mst = true;
- spec = codec->spec;
- spec->dyn_pin_out = true;
- spec->hdmi_intr_trig_ctrl = true;
-
- return tegra_hdmi_init(codec);
-}
-
-/*
- * ATI/AMD-specific implementations
- */
-
-#define is_amdhdmi_rev3_or_later(codec) \
- ((codec)->core.vendor_id == 0x1002aa01 && \
- ((codec)->core.revision_id & 0xff00) >= 0x0300)
-#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
-
-/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
-#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771
-#define ATI_VERB_SET_DOWNMIX_INFO 0x772
-#define ATI_VERB_SET_MULTICHANNEL_01 0x777
-#define ATI_VERB_SET_MULTICHANNEL_23 0x778
-#define ATI_VERB_SET_MULTICHANNEL_45 0x779
-#define ATI_VERB_SET_MULTICHANNEL_67 0x77a
-#define ATI_VERB_SET_HBR_CONTROL 0x77c
-#define ATI_VERB_SET_MULTICHANNEL_1 0x785
-#define ATI_VERB_SET_MULTICHANNEL_3 0x786
-#define ATI_VERB_SET_MULTICHANNEL_5 0x787
-#define ATI_VERB_SET_MULTICHANNEL_7 0x788
-#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
-#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71
-#define ATI_VERB_GET_DOWNMIX_INFO 0xf72
-#define ATI_VERB_GET_MULTICHANNEL_01 0xf77
-#define ATI_VERB_GET_MULTICHANNEL_23 0xf78
-#define ATI_VERB_GET_MULTICHANNEL_45 0xf79
-#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a
-#define ATI_VERB_GET_HBR_CONTROL 0xf7c
-#define ATI_VERB_GET_MULTICHANNEL_1 0xf85
-#define ATI_VERB_GET_MULTICHANNEL_3 0xf86
-#define ATI_VERB_GET_MULTICHANNEL_5 0xf87
-#define ATI_VERB_GET_MULTICHANNEL_7 0xf88
-#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89
-
-/* AMD specific HDA cvt verbs */
-#define ATI_VERB_SET_RAMP_RATE 0x770
-#define ATI_VERB_GET_RAMP_RATE 0xf70
-
-#define ATI_OUT_ENABLE 0x1
-
-#define ATI_MULTICHANNEL_MODE_PAIRED 0
-#define ATI_MULTICHANNEL_MODE_SINGLE 1
-
-#define ATI_HBR_CAPABLE 0x01
-#define ATI_HBR_ENABLE 0x10
-
-static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
- int dev_id, unsigned char *buf, int *eld_size)
-{
- WARN_ON(dev_id != 0);
- /* call hda_eld.c ATI/AMD-specific function */
- return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
- is_amdhdmi_rev3_or_later(codec));
-}
-
-static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
- hda_nid_t pin_nid, int dev_id, int ca,
- int active_channels, int conn_type)
-{
- WARN_ON(dev_id != 0);
- snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
-}
-
-static int atihdmi_paired_swap_fc_lfe(int pos)
-{
- /*
- * ATI/AMD have automatic FC/LFE swap built-in
- * when in pairwise mapping mode.
- */
-
- switch (pos) {
- /* see channel_allocations[].speakers[] */
- case 2: return 3;
- case 3: return 2;
- default: break;
- }
-
- return pos;
-}
-
-static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
- int ca, int chs, unsigned char *map)
-{
- struct hdac_cea_channel_speaker_allocation *cap;
- int i, j;
-
- /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
-
- cap = snd_hdac_get_ch_alloc_from_ca(ca);
- for (i = 0; i < chs; ++i) {
- int mask = snd_hdac_chmap_to_spk_mask(map[i]);
- bool ok = false;
- bool companion_ok = false;
-
- if (!mask)
- continue;
-
- for (j = 0 + i % 2; j < 8; j += 2) {
- int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
- if (cap->speakers[chan_idx] == mask) {
- /* channel is in a supported position */
- ok = true;
-
- if (i % 2 == 0 && i + 1 < chs) {
- /* even channel, check the odd companion */
- int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
- int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
- int comp_mask_act = cap->speakers[comp_chan_idx];
-
- if (comp_mask_req == comp_mask_act)
- companion_ok = true;
- else
- return -EINVAL;
- }
- break;
- }
- }
-
- if (!ok)
- return -EINVAL;
-
- if (companion_ok)
- i++; /* companion channel already checked */
- }
-
- return 0;
-}
-
-static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
- hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
-{
- struct hda_codec *codec = hdac_to_hda_codec(hdac);
- int verb;
- int ati_channel_setup = 0;
-
- if (hdmi_slot > 7)
- return -EINVAL;
-
- if (!has_amd_full_remap_support(codec)) {
- hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
-
- /* In case this is an odd slot but without stream channel, do not
- * disable the slot since the corresponding even slot could have a
- * channel. In case neither have a channel, the slot pair will be
- * disabled when this function is called for the even slot. */
- if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
- return 0;
-
- hdmi_slot -= hdmi_slot % 2;
-
- if (stream_channel != 0xf)
- stream_channel -= stream_channel % 2;
- }
-
- verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
-
- /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
-
- if (stream_channel != 0xf)
- ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
-
- return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
-}
-
-static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
- hda_nid_t pin_nid, int asp_slot)
-{
- struct hda_codec *codec = hdac_to_hda_codec(hdac);
- bool was_odd = false;
- int ati_asp_slot = asp_slot;
- int verb;
- int ati_channel_setup;
-
- if (asp_slot > 7)
- return -EINVAL;
-
- if (!has_amd_full_remap_support(codec)) {
- ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
- if (ati_asp_slot % 2 != 0) {
- ati_asp_slot -= 1;
- was_odd = true;
- }
- }
-
- verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
-
- ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
-
- if (!(ati_channel_setup & ATI_OUT_ENABLE))
- return 0xf;
-
- return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
-}
-
-static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
- struct hdac_chmap *chmap,
- struct hdac_cea_channel_speaker_allocation *cap,
- int channels)
-{
- int c;
-
- /*
- * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
- * we need to take that into account (a single channel may take 2
- * channel slots if we need to carry a silent channel next to it).
- * On Rev3+ AMD codecs this function is not used.
- */
- int chanpairs = 0;
-
- /* We only produce even-numbered channel count TLVs */
- if ((channels % 2) != 0)
- return -1;
-
- for (c = 0; c < 7; c += 2) {
- if (cap->speakers[c] || cap->speakers[c+1])
- chanpairs++;
- }
-
- if (chanpairs * 2 != channels)
- return -1;
-
- return SNDRV_CTL_TLVT_CHMAP_PAIRED;
-}
-
-static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
- struct hdac_cea_channel_speaker_allocation *cap,
- unsigned int *chmap, int channels)
-{
- /* produce paired maps for pre-rev3 ATI/AMD codecs */
- int count = 0;
- int c;
-
- for (c = 7; c >= 0; c--) {
- int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
- int spk = cap->speakers[chan];
- if (!spk) {
- /* add N/A channel if the companion channel is occupied */
- if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
- chmap[count++] = SNDRV_CHMAP_NA;
-
- continue;
- }
-
- chmap[count++] = snd_hdac_spk_to_chmap(spk);
- }
-
- WARN_ON(count != channels);
-}
-
-static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
- int dev_id, bool hbr)
-{
- int hbr_ctl, hbr_ctl_new;
-
- WARN_ON(dev_id != 0);
-
- hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
- if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
- if (hbr)
- hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
- else
- hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
-
- codec_dbg(codec,
- "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
- pin_nid,
- hbr_ctl == hbr_ctl_new ? "" : "new-",
- hbr_ctl_new);
-
- if (hbr_ctl != hbr_ctl_new)
- snd_hda_codec_write(codec, pin_nid, 0,
- ATI_VERB_SET_HBR_CONTROL,
- hbr_ctl_new);
-
- } else if (hbr)
- return -EINVAL;
-
- return 0;
-}
-
-static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
- hda_nid_t pin_nid, int dev_id,
- u32 stream_tag, int format)
-{
- if (is_amdhdmi_rev3_or_later(codec)) {
- int ramp_rate = 180; /* default as per AMD spec */
- /* disable ramp-up/down for non-pcm as per AMD spec */
- if (format & AC_FMT_TYPE_NON_PCM)
- ramp_rate = 0;
-
- snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
- }
-
- return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
- stream_tag, format);
-}
-
-
-static int atihdmi_init(struct hda_codec *codec)
-{
- struct hdmi_spec *spec = codec->spec;
- int pin_idx, err;
-
- err = generic_hdmi_init(codec);
-
- if (err)
- return err;
-
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
- /* make sure downmix information in infoframe is zero */
- snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
-
- /* enable channel-wise remap mode if supported */
- if (has_amd_full_remap_support(codec))
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
- ATI_VERB_SET_MULTICHANNEL_MODE,
- ATI_MULTICHANNEL_MODE_SINGLE);
- }
- codec->auto_runtime_pm = 1;
-
- return 0;
-}
-
-/* map from pin NID to port; port is 0-based */
-/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
-static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
-{
- return pin_nid / 2 - 1;
-}
-
-/* reverse-map from port to pin NID: see above */
-static int atihdmi_port2pin(struct hda_codec *codec, int port)
-{
- return port * 2 + 3;
-}
-
-static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
- .pin2port = atihdmi_pin2port,
- .pin_eld_notify = generic_acomp_pin_eld_notify,
- .master_bind = generic_acomp_master_bind,
- .master_unbind = generic_acomp_master_unbind,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
- struct hdmi_spec *spec;
- struct hdmi_spec_per_cvt *per_cvt;
- int err, cvt_idx;
-
- err = patch_generic_hdmi(codec);
-
- if (err)
- return err;
-
- codec->patch_ops.init = atihdmi_init;
-
- spec = codec->spec;
-
- spec->static_pcm_mapping = true;
-
- spec->ops.pin_get_eld = atihdmi_pin_get_eld;
- spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
- spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
- spec->ops.setup_stream = atihdmi_setup_stream;
-
- spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
- spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
-
- if (!has_amd_full_remap_support(codec)) {
- /* override to ATI/AMD-specific versions with pairwise mapping */
- spec->chmap.ops.chmap_cea_alloc_validate_get_type =
- atihdmi_paired_chmap_cea_alloc_validate_get_type;
- spec->chmap.ops.cea_alloc_to_tlv_chmap =
- atihdmi_paired_cea_alloc_to_tlv_chmap;
- spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
- }
-
- /* ATI/AMD converters do not advertise all of their capabilities */
- for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
- per_cvt = get_cvt(spec, cvt_idx);
- per_cvt->channels_max = max(per_cvt->channels_max, 8u);
- per_cvt->rates |= SUPPORTED_RATES;
- per_cvt->formats |= SUPPORTED_FORMATS;
- per_cvt->maxbps = max(per_cvt->maxbps, 24u);
- }
-
- spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
-
- /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
- * the link-down as is. Tell the core to allow it.
- */
- codec->link_down_at_suspend = 1;
-
- generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
-
- return 0;
-}
-
-/* VIA HDMI Implementation */
-#define VIAHDMI_CVT_NID 0x02 /* audio converter1 */
-#define VIAHDMI_PIN_NID 0x03 /* HDMI output pin1 */
-
-static int patch_via_hdmi(struct hda_codec *codec)
-{
- return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
-}
-
-static int patch_gf_hdmi(struct hda_codec *codec)
-{
- int err;
-
- err = patch_generic_hdmi(codec);
- if (err)
- return err;
-
- /*
- * Glenfly GPUs have two codecs, stream switches from one codec to
- * another, need to do actual clean-ups in codec_cleanup_stream
- */
- codec->no_sticky_stream = 1;
- return 0;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_hdmi[] = {
-HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI", patch_atihdmi),
-HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI", patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI", patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI", patch_atihdmi),
-HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI", patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI", patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI", patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI", patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy),
-/* 17 is known to be absent */
-HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI", patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi),
-HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi),
-HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281f, "Raptorlake-P HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281d, "Meteorlake HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
-HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
-HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI", patch_generic_hdmi),
-/* special ID for generic HDMI */
-HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
-{} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("HDMI HD-audio codec");
-MODULE_ALIAS("snd-hda-codec-intelhdmi");
-MODULE_ALIAS("snd-hda-codec-nvhdmi");
-MODULE_ALIAS("snd-hda-codec-atihdmi");
-
-static struct hda_codec_driver hdmi_driver = {
- .id = snd_hda_id_hdmi,
-};
-
-module_hda_codec_driver(hdmi_driver);
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index 1196f22a9b45..f406a048374c 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -4,9 +4,9 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ice17xx-ak4xxx-objs := ak4xxx.o
-snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o psc724.o wm8766.o wm8776.o
+snd-ice17xx-ak4xxx-y := ak4xxx.o
+snd-ice1712-y := ice1712.o delta.o hoontech.o ews.o
+snd-ice1724-y := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o psc724.o wm8766.o wm8776.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 24b978234000..b4c9e7d11609 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -358,14 +358,13 @@ static int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned short vol;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
if (kcontrol->private_value & AUREON_AC97_STEREO)
ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -401,12 +400,11 @@ static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_el
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = aureon_ac97_read(ice,
kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -439,11 +437,10 @@ static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ct
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -642,11 +639,10 @@ static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -704,9 +700,8 @@ static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -944,11 +939,10 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned short val;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
val = val > PCM_MIN ? (val - PCM_MIN) : 0;
ucontrol->value.integer.value[0] = val;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -984,12 +978,11 @@ static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
unsigned short val;
int i;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
val = wm_get(ice, WM_ADC_GAIN + i);
ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
}
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -1031,13 +1024,12 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
int i, idx;
unsigned short vol;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
idx = WM_ADC_GAIN + i;
vol = wm_get(ice, idx) & 0x1f;
ucontrol->value.integer.value[i] = vol;
}
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -1097,11 +1089,10 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned short val;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
val = wm_get(ice, WM_ADC_MUX);
ucontrol->value.enumerated.item[0] = val & 7;
ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -1899,11 +1890,12 @@ static int aureon_add_controls(struct snd_ice1712 *ice)
else {
for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
struct snd_kcontrol *kctl;
- err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
- if (err < 0)
- return err;
+ kctl = snd_ctl_new1(&cs8415_controls[i], ice);
if (i > 1)
kctl->id.device = ice->pcm->device;
+ err = snd_ctl_add(ice->card, kctl);
+ if (err < 0)
+ return err;
}
}
}
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 08adf4dd1303..e5a9585cba4c 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -126,13 +126,12 @@ static int ap_cs8427_sendbytes(struct snd_i2c_device *device, unsigned char *byt
int res = count;
unsigned char tmp;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
tmp = ap_cs8427_codec_select(ice);
ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */
while (count-- > 0)
ap_cs8427_write_byte(ice, *bytes++, tmp);
ap_cs8427_codec_deassert(ice, tmp);
- mutex_unlock(&ice->gpio_mutex);
return res;
}
@@ -143,13 +142,12 @@ static int ap_cs8427_readbytes(struct snd_i2c_device *device, unsigned char *byt
int res = count;
unsigned char tmp;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
tmp = ap_cs8427_codec_select(ice);
ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */
while (count-- > 0)
*bytes++ = ap_cs8427_read_byte(ice, tmp);
ap_cs8427_codec_deassert(ice, tmp);
- mutex_unlock(&ice->gpio_mutex);
return res;
}
@@ -176,7 +174,7 @@ static void snd_ice1712_delta_cs8403_spdif_write(struct snd_ice1712 *ice, unsign
/* send byte to transmitter */
mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK;
mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
for (idx = 7; idx >= 0; idx--) {
tmp &= ~(mask1 | mask2);
@@ -190,7 +188,6 @@ static void snd_ice1712_delta_cs8403_spdif_write(struct snd_ice1712 *ice, unsign
}
tmp &= ~mask1;
snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
- mutex_unlock(&ice->gpio_mutex);
}
@@ -205,15 +202,13 @@ static int delta_spdif_default_put(struct snd_ice1712 *ice, struct snd_ctl_elem_
int change;
val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958);
- spin_lock_irq(&ice->reg_lock);
- change = ice->spdif.cs8403_bits != val;
- ice->spdif.cs8403_bits = val;
- if (change && ice->playback_pro_substream == NULL) {
- spin_unlock_irq(&ice->reg_lock);
- snd_ice1712_delta_cs8403_spdif_write(ice, val);
- } else {
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ change = ice->spdif.cs8403_bits != val;
+ ice->spdif.cs8403_bits = val;
+ if (!change || ice->playback_pro_substream)
+ return change;
}
+ snd_ice1712_delta_cs8403_spdif_write(ice, val);
return change;
}
@@ -228,15 +223,13 @@ static int delta_spdif_stream_put(struct snd_ice1712 *ice, struct snd_ctl_elem_v
int change;
val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958);
- spin_lock_irq(&ice->reg_lock);
- change = ice->spdif.cs8403_stream_bits != val;
- ice->spdif.cs8403_stream_bits = val;
- if (change && ice->playback_pro_substream != NULL) {
- spin_unlock_irq(&ice->reg_lock);
- snd_ice1712_delta_cs8403_spdif_write(ice, val);
- } else {
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ change = ice->spdif.cs8403_stream_bits != val;
+ ice->spdif.cs8403_stream_bits = val;
+ if (!change || ice->playback_pro_substream)
+ return change;
}
+ snd_ice1712_delta_cs8403_spdif_write(ice, val);
return change;
}
@@ -306,14 +299,13 @@ static void delta_1010_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
if (rate == 0) /* no hint - S/PDIF input is master, simply return */
return;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
tmp2 = tmp & ~ICE1712_DELTA_DFS;
if (rate > 48000)
tmp2 |= ICE1712_DELTA_DFS;
if (tmp != tmp2)
snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2);
- mutex_unlock(&ice->gpio_mutex);
}
/*
@@ -328,9 +320,9 @@ static void delta_ak4524_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
return;
/* check before reset ak4524 to avoid unnecessary clicks */
- mutex_lock(&ice->gpio_mutex);
- tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
- mutex_unlock(&ice->gpio_mutex);
+ scoped_guard(mutex, &ice->gpio_mutex) {
+ tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+ }
tmp2 = tmp & ~ICE1712_DELTA_DFS;
if (rate > 48000)
tmp2 |= ICE1712_DELTA_DFS;
@@ -339,12 +331,12 @@ static void delta_ak4524_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
/* do it again */
snd_akm4xxx_reset(ak, 1);
- mutex_lock(&ice->gpio_mutex);
- tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
- if (rate > 48000)
- tmp |= ICE1712_DELTA_DFS;
- snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
- mutex_unlock(&ice->gpio_mutex);
+ scoped_guard(mutex, &ice->gpio_mutex) {
+ tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
+ if (rate > 48000)
+ tmp |= ICE1712_DELTA_DFS;
+ snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+ }
snd_akm4xxx_reset(ak, 0);
}
@@ -379,23 +371,22 @@ static void delta_open_spdif(struct snd_ice1712 *ice, struct snd_pcm_substream *
/* set up */
static void delta_setup_spdif(struct snd_ice1712 *ice, int rate)
{
- unsigned long flags;
unsigned int tmp;
int change;
- spin_lock_irqsave(&ice->reg_lock, flags);
- tmp = ice->spdif.cs8403_stream_bits;
- if (tmp & 0x01) /* consumer */
- tmp &= (tmp & 0x01) ? ~0x06 : ~0x18;
- switch (rate) {
- case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break;
- case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break;
- case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break;
- default: tmp |= (tmp & 0x01) ? 0x00 : 0x18; break;
+ scoped_guard(spinlock_irqsave, &ice->reg_lock) {
+ tmp = ice->spdif.cs8403_stream_bits;
+ if (tmp & 0x01) /* consumer */
+ tmp &= (tmp & 0x01) ? ~0x06 : ~0x18;
+ switch (rate) {
+ case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break;
+ case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break;
+ case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break;
+ default: tmp |= (tmp & 0x01) ? 0x00 : 0x18; break;
+ }
+ change = ice->spdif.cs8403_stream_bits != tmp;
+ ice->spdif.cs8403_stream_bits = tmp;
}
- change = ice->spdif.cs8403_stream_bits != tmp;
- ice->spdif.cs8403_stream_bits = tmp;
- spin_unlock_irqrestore(&ice->reg_lock, flags);
if (change)
snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id);
snd_ice1712_delta_cs8403_spdif_write(ice, tmp);
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 8bb86b3c894e..1dffcb011deb 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -260,15 +260,13 @@ static int ews88_spdif_default_put(struct snd_ice1712 *ice, struct snd_ctl_elem_
int change;
val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
- spin_lock_irq(&ice->reg_lock);
- change = ice->spdif.cs8403_bits != val;
- ice->spdif.cs8403_bits = val;
- if (change && ice->playback_pro_substream == NULL) {
- spin_unlock_irq(&ice->reg_lock);
- snd_ice1712_ews_cs8404_spdif_write(ice, val);
- } else {
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ change = ice->spdif.cs8403_bits != val;
+ ice->spdif.cs8403_bits = val;
+ if (!change || ice->playback_pro_substream)
+ return change;
}
+ snd_ice1712_ews_cs8404_spdif_write(ice, val);
return change;
}
@@ -283,15 +281,13 @@ static int ews88_spdif_stream_put(struct snd_ice1712 *ice, struct snd_ctl_elem_v
int change;
val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
- spin_lock_irq(&ice->reg_lock);
- change = ice->spdif.cs8403_stream_bits != val;
- ice->spdif.cs8403_stream_bits = val;
- if (change && ice->playback_pro_substream != NULL) {
- spin_unlock_irq(&ice->reg_lock);
- snd_ice1712_ews_cs8404_spdif_write(ice, val);
- } else {
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ change = ice->spdif.cs8403_stream_bits != val;
+ ice->spdif.cs8403_stream_bits = val;
+ if (!change || ice->playback_pro_substream)
+ return change;
}
+ snd_ice1712_ews_cs8404_spdif_write(ice, val);
return change;
}
@@ -305,23 +301,22 @@ static void ews88_open_spdif(struct snd_ice1712 *ice, struct snd_pcm_substream *
/* set up SPDIF for EWS88MT / EWS88D */
static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate)
{
- unsigned long flags;
unsigned char tmp;
int change;
- spin_lock_irqsave(&ice->reg_lock, flags);
- tmp = ice->spdif.cs8403_stream_bits;
- if (tmp & 0x10) /* consumer */
- tmp &= (tmp & 0x01) ? ~0x06 : ~0x60;
- switch (rate) {
- case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break;
- case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
- case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break;
- default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
+ scoped_guard(spinlock_irqsave, &ice->reg_lock) {
+ tmp = ice->spdif.cs8403_stream_bits;
+ if (tmp & 0x10) /* consumer */
+ tmp &= (tmp & 0x01) ? ~0x06 : ~0x60;
+ switch (rate) {
+ case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break;
+ case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
+ case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break;
+ default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
+ }
+ change = ice->spdif.cs8403_stream_bits != tmp;
+ ice->spdif.cs8403_stream_bits = tmp;
}
- change = ice->spdif.cs8403_stream_bits != tmp;
- ice->spdif.cs8403_stream_bits = tmp;
- spin_unlock_irqrestore(&ice->reg_lock, flags);
if (change)
snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id);
snd_ice1712_ews_cs8404_spdif_write(ice, tmp);
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 46daeea8dc66..071f94dc7390 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -41,35 +41,35 @@ static void snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned cha
static void snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate)
{
struct hoontech_spec *spec = ice->spec;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate);
snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]);
- mutex_unlock(&ice->gpio_mutex);
}
static void snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate)
{
struct hoontech_spec *spec = ice->spec;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
ICE1712_STDSP24_3_MUTE(spec->boxbits, activate);
snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
- mutex_unlock(&ice->gpio_mutex);
}
static void snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate)
{
struct hoontech_spec *spec = ice->spec;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
ICE1712_STDSP24_3_INSEL(spec->boxbits, activate);
snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
- mutex_unlock(&ice->gpio_mutex);
}
static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate)
{
struct hoontech_spec *spec = ice->spec;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
/* select box */
ICE1712_STDSP24_0_BOX(spec->boxbits, box);
@@ -111,15 +111,13 @@ static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, in
ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0);
snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
-
- mutex_unlock(&ice->gpio_mutex);
}
static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master)
{
struct hoontech_spec *spec = ice->spec;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
/* select box */
ICE1712_STDSP24_0_BOX(spec->boxbits, box);
@@ -139,17 +137,15 @@ static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int m
ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1);
snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
-
- mutex_unlock(&ice->gpio_mutex);
}
static void snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate)
{
struct hoontech_spec *spec = ice->spec;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate);
snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
- mutex_unlock(&ice->gpio_mutex);
}
static int hoontech_init(struct snd_ice1712 *ice, bool staudio)
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index a5241a287851..1e39b985bef2 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -249,13 +249,12 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned char val, nval;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
val = inb(ICEMT(ice, MONITOR_ROUTECTRL));
nval = val & ~ICE1712_ROUTE_AC97;
if (ucontrol->value.integer.value[0])
nval |= ICE1712_ROUTE_AC97;
outb(nval, ICEMT(ice, MONITOR_ROUTECTRL));
- spin_unlock_irq(&ice->reg_lock);
return val != nval;
}
@@ -484,7 +483,7 @@ static int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream,
int result = 0;
u32 tmp;
- spin_lock(&ice->reg_lock);
+ guard(spinlock)(&ice->reg_lock);
tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL);
if (cmd == SNDRV_PCM_TRIGGER_START) {
tmp |= 1;
@@ -498,7 +497,6 @@ static int snd_ice1712_playback_trigger(struct snd_pcm_substream *substream,
result = -EINVAL;
}
snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp);
- spin_unlock(&ice->reg_lock);
return result;
}
@@ -509,7 +507,7 @@ static int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream,
int result = 0;
u32 tmp;
- spin_lock(&ice->reg_lock);
+ guard(spinlock)(&ice->reg_lock);
tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL);
if (cmd == SNDRV_PCM_TRIGGER_START) {
tmp |= 1;
@@ -523,7 +521,6 @@ static int snd_ice1712_playback_ds_trigger(struct snd_pcm_substream *substream,
result = -EINVAL;
}
snd_ice1712_ds_write(ice, substream->number * 2, ICE1712_DSC_CONTROL, tmp);
- spin_unlock(&ice->reg_lock);
return result;
}
@@ -534,7 +531,7 @@ static int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream,
int result = 0;
u8 tmp;
- spin_lock(&ice->reg_lock);
+ guard(spinlock)(&ice->reg_lock);
tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL);
if (cmd == SNDRV_PCM_TRIGGER_START) {
tmp |= 1;
@@ -544,7 +541,6 @@ static int snd_ice1712_capture_trigger(struct snd_pcm_substream *substream,
result = -EINVAL;
}
snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
- spin_unlock(&ice->reg_lock);
return result;
}
@@ -564,7 +560,7 @@ static int snd_ice1712_playback_prepare(struct snd_pcm_substream *substream)
rate = (runtime->rate * 8192) / 375;
if (rate > 0x000fffff)
rate = 0x000fffff;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
outb(0, ice->ddma_port + 15);
outb(ICE1712_DMA_MODE_WRITE | ICE1712_DMA_AUTOINIT, ice->ddma_port + 0x0b);
outl(runtime->dma_addr, ice->ddma_port + 0);
@@ -577,7 +573,6 @@ static int snd_ice1712_playback_prepare(struct snd_pcm_substream *substream)
snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_HI, period_size >> 8);
snd_ice1712_write(ice, ICE1712_IREG_PBK_LEFT, 0);
snd_ice1712_write(ice, ICE1712_IREG_PBK_RIGHT, 0);
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -599,7 +594,7 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream)
ice->playback_con_active_buf[substream->number] = 0;
ice->playback_con_virt_addr[substream->number] = runtime->dma_addr;
chn = substream->number * 2;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR0, runtime->dma_addr);
snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT0, period_size);
snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR1, runtime->dma_addr + (runtime->periods > 1 ? period_size + 1 : 0));
@@ -611,7 +606,6 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream)
snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_RATE, rate);
snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_VOLUME, 0);
}
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -629,13 +623,13 @@ static int snd_ice1712_capture_prepare(struct snd_pcm_substream *substream)
tmp &= ~0x04;
if (runtime->channels == 2)
tmp &= ~0x02;
- spin_lock_irq(&ice->reg_lock);
- outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR));
- outw(buf_size, ICEREG(ice, CONCAP_COUNT));
- snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8);
- snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff);
- snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR));
+ outw(buf_size, ICEREG(ice, CONCAP_COUNT));
+ snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8);
+ snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff);
+ snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
+ }
snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
return 0;
}
@@ -763,10 +757,9 @@ static int snd_ice1712_playback_ds_open(struct snd_pcm_substream *substream)
ice->playback_con_substream_ds[substream->number] = substream;
runtime->hw = snd_ice1712_playback_ds;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2));
outw(tmp, ICEDS(ice, INTMASK));
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -796,10 +789,9 @@ static int snd_ice1712_playback_ds_close(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
u32 tmp;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2));
outw(tmp, ICEDS(ice, INTMASK));
- spin_unlock_irq(&ice->reg_lock);
ice->playback_con_substream_ds[substream->number] = NULL;
return 0;
}
@@ -850,7 +842,7 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device)
pcm->private_data = ice;
pcm->info_flags = 0;
- strcpy(pcm->name, "ICE1712 consumer");
+ strscpy(pcm->name, "ICE1712 consumer");
ice->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -875,7 +867,7 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device)
pcm->private_data = ice;
pcm->info_flags = 0;
- strcpy(pcm->name, "ICE1712 consumer (DS)");
+ strscpy(pcm->name, "ICE1712 consumer (DS)");
ice->pcm_ds = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -911,14 +903,13 @@ static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream,
return -EINVAL;
what = ICE1712_PLAYBACK_PAUSE;
snd_pcm_trigger_done(substream, substream);
- spin_lock(&ice->reg_lock);
+ guard(spinlock)(&ice->reg_lock);
old = inl(ICEMT(ice, PLAYBACK_CONTROL));
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
old |= what;
else
old &= ~what;
outl(old, ICEMT(ice, PLAYBACK_CONTROL));
- spin_unlock(&ice->reg_lock);
break;
}
case SNDRV_PCM_TRIGGER_START:
@@ -937,14 +928,13 @@ static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream,
snd_pcm_trigger_done(s, substream);
}
}
- spin_lock(&ice->reg_lock);
+ guard(spinlock)(&ice->reg_lock);
old = inl(ICEMT(ice, PLAYBACK_CONTROL));
if (cmd == SNDRV_PCM_TRIGGER_START)
old |= what;
else
old &= ~what;
outl(old, ICEMT(ice, PLAYBACK_CONTROL));
- spin_unlock(&ice->reg_lock);
break;
}
default:
@@ -957,7 +947,6 @@ static int snd_ice1712_pro_trigger(struct snd_pcm_substream *substream,
*/
static void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force)
{
- unsigned long flags;
unsigned char val, old;
unsigned int i;
@@ -982,24 +971,21 @@ static void snd_ice1712_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
break;
}
- spin_lock_irqsave(&ice->reg_lock, flags);
- if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
- ICE1712_PLAYBACK_PAUSE|
- ICE1712_PLAYBACK_START)) {
-__out:
- spin_unlock_irqrestore(&ice->reg_lock, flags);
- return;
- }
- if (!force && is_pro_rate_locked(ice))
- goto __out;
+ scoped_guard(spinlock_irqsave, &ice->reg_lock) {
+ if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
+ ICE1712_PLAYBACK_PAUSE|
+ ICE1712_PLAYBACK_START))
+ return;
+ if (!force && is_pro_rate_locked(ice))
+ return;
- old = inb(ICEMT(ice, RATE));
- if (!force && old == val)
- goto __out;
+ old = inb(ICEMT(ice, RATE));
+ if (!force && old == val)
+ return;
- ice->cur_rate = rate;
- outb(val, ICEMT(ice, RATE));
- spin_unlock_irqrestore(&ice->reg_lock, flags);
+ ice->cur_rate = rate;
+ outb(val, ICEMT(ice, RATE));
+ }
if (ice->gpio.set_pro_rate)
ice->gpio.set_pro_rate(ice, rate);
@@ -1016,11 +1002,10 @@ static int snd_ice1712_playback_pro_prepare(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream);
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR));
outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));
outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT));
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1039,11 +1024,10 @@ static int snd_ice1712_capture_pro_prepare(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream);
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR));
outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE));
outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, CAPTURE_COUNT));
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1216,7 +1200,7 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device)
pcm->private_data = ice;
pcm->info_flags = 0;
- strcpy(pcm->name, "ICE1712 multi");
+ strscpy(pcm->name, "ICE1712 multi");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&ice->pci->dev, 256*1024, 256*1024);
@@ -1258,12 +1242,11 @@ static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struc
int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
kcontrol->private_value;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
ucontrol->value.integer.value[0] =
!((ice->pro_volumes[priv_idx] >> 15) & 1);
ucontrol->value.integer.value[1] =
!((ice->pro_volumes[priv_idx] >> 31) & 1);
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1276,12 +1259,11 @@ static int snd_ice1712_pro_mixer_switch_put(struct snd_kcontrol *kcontrol, struc
nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) |
(ucontrol->value.integer.value[1] ? 0 : 0x80000000);
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
nval |= ice->pro_volumes[priv_idx] & ~0x80008000;
change = nval != ice->pro_volumes[priv_idx];
ice->pro_volumes[priv_idx] = nval;
snd_ice1712_update_volume(ice, priv_idx);
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -1300,12 +1282,11 @@ static int snd_ice1712_pro_mixer_volume_get(struct snd_kcontrol *kcontrol, struc
int priv_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) +
kcontrol->private_value;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
ucontrol->value.integer.value[0] =
(ice->pro_volumes[priv_idx] >> 0) & 127;
ucontrol->value.integer.value[1] =
(ice->pro_volumes[priv_idx] >> 16) & 127;
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1318,12 +1299,11 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc
nval = (ucontrol->value.integer.value[0] & 127) |
((ucontrol->value.integer.value[1] & 127) << 16);
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
nval |= ice->pro_volumes[priv_idx] & ~0x007f007f;
change = nval != ice->pro_volumes[priv_idx];
ice->pro_volumes[priv_idx] = nval;
snd_ice1712_update_volume(ice, priv_idx);
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -1781,7 +1761,7 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
};
unsigned char val;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
if (is_spdif_master(ice)) {
ucontrol->value.enumerated.item[0] = 13;
} else {
@@ -1792,7 +1772,6 @@ static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
}
ucontrol->value.enumerated.item[0] = val;
}
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1916,10 +1895,9 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
int change = 0, nval;
nval = ucontrol->value.integer.value[0] ? 1 : 0;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
change = PRO_RATE_LOCKED != nval;
PRO_RATE_LOCKED = nval;
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -1947,10 +1925,9 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
int change = 0, nval;
nval = ucontrol->value.integer.value[0] ? 1 : 0;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
change = PRO_RATE_RESET != nval;
PRO_RATE_RESET = nval;
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -1986,10 +1963,10 @@ static int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol,
int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
unsigned int val, cval;
- spin_lock_irq(&ice->reg_lock);
- val = inw(ICEMT(ice, ROUTE_PSDOUT03));
- cval = inl(ICEMT(ice, ROUTE_CAPTURE));
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ val = inw(ICEMT(ice, ROUTE_PSDOUT03));
+ cval = inl(ICEMT(ice, ROUTE_CAPTURE));
+ }
val >>= ((idx % 2) * 8) + ((idx / 2) * 2);
val &= 3;
@@ -2023,35 +2000,35 @@ static int snd_ice1712_pro_route_analog_put(struct snd_kcontrol *kcontrol,
else
nval = 0; /* pcm */
shift = ((idx % 2) * 8) + ((idx / 2) * 2);
- spin_lock_irq(&ice->reg_lock);
- val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03));
- val &= ~(0x03 << shift);
- val |= nval << shift;
- change = val != old_val;
- if (change)
- outw(val, ICEMT(ice, ROUTE_PSDOUT03));
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03));
+ val &= ~(0x03 << shift);
+ val |= nval << shift;
+ change = val != old_val;
+ if (change)
+ outw(val, ICEMT(ice, ROUTE_PSDOUT03));
+ }
if (nval < 2) /* dig mixer of pcm */
return change;
/* update CAPTURE */
- spin_lock_irq(&ice->reg_lock);
- val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE));
- shift = ((idx / 2) * 8) + ((idx % 2) * 4);
- if (nval == 2) { /* analog in */
- nval = ucontrol->value.enumerated.item[0] - 1;
- val &= ~(0x07 << shift);
- val |= nval << shift;
- } else { /* spdif in */
- nval = (ucontrol->value.enumerated.item[0] - 9) << 3;
- val &= ~(0x08 << shift);
- val |= nval << shift;
- }
- if (val != old_val) {
- change = 1;
- outl(val, ICEMT(ice, ROUTE_CAPTURE));
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE));
+ shift = ((idx / 2) * 8) + ((idx % 2) * 4);
+ if (nval == 2) { /* analog in */
+ nval = ucontrol->value.enumerated.item[0] - 1;
+ val &= ~(0x07 << shift);
+ val |= nval << shift;
+ } else { /* spdif in */
+ nval = (ucontrol->value.enumerated.item[0] - 9) << 3;
+ val &= ~(0x08 << shift);
+ val |= nval << shift;
+ }
+ if (val != old_val) {
+ change = 1;
+ outl(val, ICEMT(ice, ROUTE_CAPTURE));
+ }
}
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -2084,7 +2061,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
unsigned int val, old_val, nval;
/* update SPDOUT */
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT));
if (ucontrol->value.enumerated.item[0] >= 11)
nval = 1;
@@ -2110,7 +2087,6 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol,
change = val != old_val;
if (change)
outw(val, ICEMT(ice, ROUTE_SPDOUT));
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -2157,10 +2133,9 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
int change;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
change = inb(ICEMT(ice, MONITOR_RATE)) != ucontrol->value.integer.value[0];
outb(ucontrol->value.integer.value[0], ICEMT(ice, MONITOR_RATE));
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -2188,12 +2163,11 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
int idx;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
for (idx = 0; idx < 22; idx++) {
outb(idx, ICEMT(ice, MONITOR_PEAKINDEX));
ucontrol->value.integer.value[idx] = inb(ICEMT(ice, MONITOR_PEAKDATA));
}
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -2371,22 +2345,26 @@ int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice)
if (snd_BUG_ON(!ice->pcm_pro))
return -EIO;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice));
+ kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice);
+ kctl->id.device = ice->pcm_pro->device;
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
+ kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice);
kctl->id.device = ice->pcm_pro->device;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice));
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
+ kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice);
kctl->id.device = ice->pcm_pro->device;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice));
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
+ kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice);
kctl->id.device = ice->pcm_pro->device;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice));
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
- kctl->id.device = ice->pcm_pro->device;
ice->spdif.stream_ctl = kctl;
return 0;
}
@@ -2498,7 +2476,7 @@ static int snd_ice1712_create(struct snd_card *card,
pci_write_config_word(ice->pci, 0x42, 0x0006);
snd_ice1712_proc_init(ice);
- err = pci_request_regions(pci, "ICE1712");
+ err = pcim_request_all_regions(pci, "ICE1712");
if (err < 0)
return err;
ice->port = pci_resource_start(pci, 0);
@@ -2555,8 +2533,8 @@ static int snd_ice1712_probe(struct pci_dev *pci,
return err;
ice = card->private_data;
- strcpy(card->driver, "ICE1712");
- strcpy(card->shortname, "ICEnsemble ICE1712");
+ strscpy(card->driver, "ICE1712");
+ strscpy(card->shortname, "ICEnsemble ICE1712");
err = snd_ice1712_create(card, pci, model[dev], omni[dev],
cs8427_timeout[dev], dxr_enable[dev]);
@@ -2566,9 +2544,9 @@ static int snd_ice1712_probe(struct pci_dev *pci,
for (tbl = card_tables; *tbl; tbl++) {
for (c = *tbl; c->subvendor; c++) {
if (c->subvendor == ice->eeprom.subvendor) {
- strcpy(card->shortname, c->name);
+ strscpy(card->shortname, c->name);
if (c->driver) /* specific driver? */
- strcpy(card->driver, c->driver);
+ strscpy(card->driver, c->driver);
if (c->chip_init) {
err = c->chip_init(ice);
if (err < 0)
@@ -2671,11 +2649,11 @@ static int snd_ice1712_suspend(struct device *dev)
snd_ac97_suspend(ice->ac97);
- spin_lock_irq(&ice->reg_lock);
- ice->pm_saved_is_spdif_master = is_spdif_master(ice);
- ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT));
- ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03));
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ ice->pm_saved_is_spdif_master = is_spdif_master(ice);
+ ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT));
+ ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03));
+ }
if (ice->pm_suspend)
ice->pm_suspend(ice);
@@ -2708,10 +2686,10 @@ static int snd_ice1712_resume(struct device *dev)
if (ice->pm_saved_is_spdif_master) {
/* switching to external clock via SPDIF */
- spin_lock_irq(&ice->reg_lock);
- outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER,
- ICEMT(ice, RATE));
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER,
+ ICEMT(ice, RATE));
+ }
snd_ice1712_set_input_clock_source(ice, 1);
} else {
/* internal on-card clock */
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 6fab2ad85bbe..e2dbbbfbca9f 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -288,9 +288,8 @@ static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
{
struct snd_ice1712 *ice = substream->rmidi->private_data;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
enable_midi_irq(ice, flag, enable);
- spin_unlock_irq(&ice->reg_lock);
}
static int vt1724_midi_output_open(struct snd_rawmidi_substream *s)
@@ -306,9 +305,8 @@ static int vt1724_midi_output_close(struct snd_rawmidi_substream *s)
static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up)
{
struct snd_ice1712 *ice = s->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&ice->reg_lock, flags);
+ guard(spinlock_irqsave)(&ice->reg_lock);
if (up) {
ice->midi_output = 1;
vt1724_midi_write(ice);
@@ -316,7 +314,6 @@ static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up)
ice->midi_output = 0;
enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
}
- spin_unlock_irqrestore(&ice->reg_lock, flags);
}
static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
@@ -357,16 +354,14 @@ static int vt1724_midi_input_close(struct snd_rawmidi_substream *s)
static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up)
{
struct snd_ice1712 *ice = s->rmidi->private_data;
- unsigned long flags;
- spin_lock_irqsave(&ice->reg_lock, flags);
+ guard(spinlock_irqsave)(&ice->reg_lock);
if (up) {
ice->midi_input = 1;
vt1724_midi_read(ice);
} else {
ice->midi_input = 0;
}
- spin_unlock_irqrestore(&ice->reg_lock, flags);
}
static const struct snd_rawmidi_ops vt1724_midi_input_ops = {
@@ -394,40 +389,39 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
status &= status_mask;
if (status == 0)
break;
- spin_lock(&ice->reg_lock);
- if (++timeout > 10) {
- status = inb(ICEREG1724(ice, IRQSTAT));
- dev_err(ice->card->dev,
- "Too long irq loop, status = 0x%x\n", status);
+ scoped_guard(spinlock, &ice->reg_lock) {
+ if (++timeout > 10) {
+ status = inb(ICEREG1724(ice, IRQSTAT));
+ dev_err(ice->card->dev,
+ "Too long irq loop, status = 0x%x\n", status);
+ if (status & VT1724_IRQ_MPU_TX) {
+ dev_err(ice->card->dev, "Disabling MPU_TX\n");
+ enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
+ }
+ goto out;
+ }
+ handled = 1;
if (status & VT1724_IRQ_MPU_TX) {
- dev_err(ice->card->dev, "Disabling MPU_TX\n");
- enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
+ if (ice->midi_output)
+ vt1724_midi_write(ice);
+ else
+ enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
+ /* Due to mysterical reasons, MPU_TX is always
+ * generated (and can't be cleared) when a PCM
+ * playback is going. So let's ignore at the
+ * next loop.
+ */
+ status_mask &= ~VT1724_IRQ_MPU_TX;
}
- spin_unlock(&ice->reg_lock);
- break;
- }
- handled = 1;
- if (status & VT1724_IRQ_MPU_TX) {
- if (ice->midi_output)
- vt1724_midi_write(ice);
- else
- enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
- /* Due to mysterical reasons, MPU_TX is always
- * generated (and can't be cleared) when a PCM
- * playback is going. So let's ignore at the
- * next loop.
- */
- status_mask &= ~VT1724_IRQ_MPU_TX;
- }
- if (status & VT1724_IRQ_MPU_RX) {
- if (ice->midi_input)
- vt1724_midi_read(ice);
- else
- vt1724_midi_clear_rx(ice);
+ if (status & VT1724_IRQ_MPU_RX) {
+ if (ice->midi_input)
+ vt1724_midi_read(ice);
+ else
+ vt1724_midi_clear_rx(ice);
+ }
+ /* ack MPU irq */
+ outb(status, ICEREG1724(ice, IRQSTAT));
}
- /* ack MPU irq */
- outb(status, ICEREG1724(ice, IRQSTAT));
- spin_unlock(&ice->reg_lock);
if (status & VT1724_IRQ_MTPCM) {
/*
* Multi-track PCM
@@ -481,6 +475,7 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
}
}
+ out:
return IRQ_RETVAL(handled);
}
@@ -539,27 +534,27 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock(&ice->reg_lock);
- old = inb(ICEMT1724(ice, DMA_PAUSE));
- if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
- old |= what;
- else
- old &= ~what;
- outb(old, ICEMT1724(ice, DMA_PAUSE));
- spin_unlock(&ice->reg_lock);
+ scoped_guard(spinlock, &ice->reg_lock) {
+ old = inb(ICEMT1724(ice, DMA_PAUSE));
+ if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+ old |= what;
+ else
+ old &= ~what;
+ outb(old, ICEMT1724(ice, DMA_PAUSE));
+ }
break;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- spin_lock(&ice->reg_lock);
- old = inb(ICEMT1724(ice, DMA_CONTROL));
- if (cmd == SNDRV_PCM_TRIGGER_START)
- old |= what;
- else
- old &= ~what;
- outb(old, ICEMT1724(ice, DMA_CONTROL));
- spin_unlock(&ice->reg_lock);
+ scoped_guard(spinlock, &ice->reg_lock) {
+ old = inb(ICEMT1724(ice, DMA_CONTROL));
+ if (cmd == SNDRV_PCM_TRIGGER_START)
+ old |= what;
+ else
+ old &= ~what;
+ outb(old, ICEMT1724(ice, DMA_CONTROL));
+ }
break;
case SNDRV_PCM_TRIGGER_RESUME:
@@ -625,7 +620,6 @@ static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice,
static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
int force)
{
- unsigned long flags;
unsigned char mclk_change;
unsigned int i, old_rate;
bool call_set_rate = false;
@@ -633,34 +627,31 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
if (rate > ice->hw_rates->list[ice->hw_rates->count - 1])
return -EINVAL;
- spin_lock_irqsave(&ice->reg_lock, flags);
- if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) ||
- (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
- /* running? we cannot change the rate now... */
- spin_unlock_irqrestore(&ice->reg_lock, flags);
- return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY;
- }
- if (!force && is_pro_rate_locked(ice)) {
- /* comparing required and current rate - makes sense for
- * internal clock only */
- spin_unlock_irqrestore(&ice->reg_lock, flags);
- return (rate == ice->cur_rate) ? 0 : -EBUSY;
- }
+ scoped_guard(spinlock_irqsave, &ice->reg_lock) {
+ if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) ||
+ (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
+ /* running? we cannot change the rate now... */
+ return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY;
+ }
+ if (!force && is_pro_rate_locked(ice)) {
+ /* comparing required and current rate - makes sense for
+ * internal clock only */
+ return (rate == ice->cur_rate) ? 0 : -EBUSY;
+ }
- if (force || !ice->is_spdif_master(ice)) {
- /* force means the rate was switched by ucontrol, otherwise
- * setting clock rate for internal clock mode */
- old_rate = ice->get_rate(ice);
- if (force || (old_rate != rate))
- call_set_rate = true;
- else if (rate == ice->cur_rate) {
- spin_unlock_irqrestore(&ice->reg_lock, flags);
- return 0;
+ if (force || !ice->is_spdif_master(ice)) {
+ /* force means the rate was switched by ucontrol, otherwise
+ * setting clock rate for internal clock mode */
+ old_rate = ice->get_rate(ice);
+ if (force || (old_rate != rate))
+ call_set_rate = true;
+ else if (rate == ice->cur_rate) {
+ return 0;
+ }
}
- }
- ice->cur_rate = rate;
- spin_unlock_irqrestore(&ice->reg_lock, flags);
+ ice->cur_rate = rate;
+ }
if (call_set_rate)
ice->set_rate(ice, rate);
@@ -684,24 +675,21 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
return 0;
}
-static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
+static int __snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
int i, chs;
chs = params_channels(hw_params);
- mutex_lock(&ice->open_mutex);
/* mark surround channels */
if (substream == ice->playback_pro_substream) {
/* PDMA0 can be multi-channel up to 8 */
chs = chs / 2 - 1;
for (i = 0; i < chs; i++) {
if (ice->pcm_reserved[i] &&
- ice->pcm_reserved[i] != substream) {
- mutex_unlock(&ice->open_mutex);
+ ice->pcm_reserved[i] != substream)
return -EBUSY;
- }
ice->pcm_reserved[i] = substream;
}
for (; i < 3; i++) {
@@ -713,16 +701,28 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
/* check individual playback stream */
if (ice->playback_con_substream_ds[i] == substream) {
if (ice->pcm_reserved[i] &&
- ice->pcm_reserved[i] != substream) {
- mutex_unlock(&ice->open_mutex);
+ ice->pcm_reserved[i] != substream)
return -EBUSY;
- }
ice->pcm_reserved[i] = substream;
break;
}
}
}
- mutex_unlock(&ice->open_mutex);
+
+ return 0;
+}
+
+static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
+ int err;
+
+ scoped_guard(mutex, &ice->open_mutex) {
+ err = __snd_vt1724_pcm_hw_params(substream, hw_params);
+ if (err < 0)
+ return err;
+ }
return snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
}
@@ -732,12 +732,11 @@ static int snd_vt1724_pcm_hw_free(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
int i;
- mutex_lock(&ice->open_mutex);
+ guard(mutex)(&ice->open_mutex);
/* unmark surround channels */
for (i = 0; i < 3; i++)
if (ice->pcm_reserved[i] == substream)
ice->pcm_reserved[i] = NULL;
- mutex_unlock(&ice->open_mutex);
return 0;
}
@@ -747,7 +746,7 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream)
unsigned char val;
unsigned int size;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
val = (8 - substream->runtime->channels) >> 1;
outb(val, ICEMT1724(ice, BURST));
@@ -762,8 +761,6 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream)
outw(size, ICEMT1724(ice, PLAYBACK_COUNT));
outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2);
- spin_unlock_irq(&ice->reg_lock);
-
/*
dev_dbg(ice->card->dev, "pro prepare: ch = %d, addr = 0x%x, "
"buffer = 0x%x, period = 0x%x\n",
@@ -817,13 +814,12 @@ static int snd_vt1724_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
const struct vt1724_pcm_reg *reg = substream->runtime->private_data;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
outl(substream->runtime->dma_addr, ice->profi_port + reg->addr);
outw((snd_pcm_lib_buffer_bytes(substream) >> 2) - 1,
ice->profi_port + reg->size);
outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1,
ice->profi_port + reg->count);
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1013,18 +1009,18 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
set_rate_constraints(ice, substream);
- mutex_lock(&ice->open_mutex);
- /* calculate the currently available channels */
- num_indeps = ice->num_total_dacs / 2 - 1;
- for (chs = 0; chs < num_indeps; chs++) {
- if (ice->pcm_reserved[chs])
- break;
+ scoped_guard(mutex, &ice->open_mutex) {
+ /* calculate the currently available channels */
+ num_indeps = ice->num_total_dacs / 2 - 1;
+ for (chs = 0; chs < num_indeps; chs++) {
+ if (ice->pcm_reserved[chs])
+ break;
+ }
+ chs = (chs + 1) * 2;
+ runtime->hw.channels_max = chs;
+ if (chs > 2) /* channels must be even */
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
}
- chs = (chs + 1) * 2;
- runtime->hw.channels_max = chs;
- if (chs > 2) /* channels must be even */
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- mutex_unlock(&ice->open_mutex);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
VT1724_BUFFER_ALIGN);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
@@ -1118,7 +1114,7 @@ static int snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device)
pcm->private_data = ice;
pcm->info_flags = 0;
- strcpy(pcm->name, "ICE1724");
+ strscpy(pcm->name, "ICE1724");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&ice->pci->dev, 256*1024, 256*1024);
@@ -1152,9 +1148,8 @@ static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val)
static void update_spdif_rate(struct snd_ice1712 *ice, unsigned int rate)
{
unsigned int val, nval;
- unsigned long flags;
- spin_lock_irqsave(&ice->reg_lock, flags);
+ guard(spinlock_irqsave)(&ice->reg_lock);
nval = val = inw(ICEMT1724(ice, SPDIF_CTRL));
nval &= ~(7 << 12);
switch (rate) {
@@ -1168,7 +1163,6 @@ static void update_spdif_rate(struct snd_ice1712 *ice, unsigned int rate)
}
if (val != nval)
update_spdif_bits(ice, nval);
- spin_unlock_irqrestore(&ice->reg_lock, flags);
}
static int snd_vt1724_playback_spdif_prepare(struct snd_pcm_substream *substream)
@@ -1313,7 +1307,7 @@ static int snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device)
pcm->private_data = ice;
pcm->info_flags = 0;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&ice->pci->dev, 256*1024, 256*1024);
@@ -1354,11 +1348,11 @@ static int snd_vt1724_playback_indep_prepare(struct snd_pcm_substream *substream
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
unsigned char val;
- spin_lock_irq(&ice->reg_lock);
- val = 3 - substream->number;
- if (inb(ICEMT1724(ice, BURST)) < val)
- outb(val, ICEMT1724(ice, BURST));
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ val = 3 - substream->number;
+ if (inb(ICEMT1724(ice, BURST)) < val)
+ outb(val, ICEMT1724(ice, BURST));
+ }
return snd_vt1724_pcm_prepare(substream);
}
@@ -1367,13 +1361,11 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream)
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- mutex_lock(&ice->open_mutex);
- /* already used by PDMA0? */
- if (ice->pcm_reserved[substream->number]) {
- mutex_unlock(&ice->open_mutex);
- return -EBUSY; /* FIXME: should handle blocking mode properly */
+ scoped_guard(mutex, &ice->open_mutex) {
+ /* already used by PDMA0? */
+ if (ice->pcm_reserved[substream->number])
+ return -EBUSY; /* FIXME: should handle blocking mode properly */
}
- mutex_unlock(&ice->open_mutex);
runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number];
ice->playback_con_substream_ds[substream->number] = substream;
runtime->hw = snd_vt1724_2ch_stereo;
@@ -1425,7 +1417,7 @@ static int snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device)
pcm->private_data = ice;
pcm->info_flags = 0;
- strcpy(pcm->name, "ICE1724 Surround PCM");
+ strscpy(pcm->name, "ICE1724 Surround PCM");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&ice->pci->dev, 256*1024, 256*1024);
@@ -1658,11 +1650,10 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol,
unsigned int val, old;
val = encode_spdif_bits(&ucontrol->value.iec958);
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
old = inw(ICEMT1724(ice, SPDIF_CTRL));
if (val != old)
update_spdif_bits(ice, val);
- spin_unlock_irq(&ice->reg_lock);
return val != old;
}
@@ -1733,14 +1724,13 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned char old, val;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
old = val = inb(ICEREG1724(ice, SPDIF_CFG));
val &= ~VT1724_CFG_SPDIF_OUT_EN;
if (ucontrol->value.integer.value[0])
val |= VT1724_CFG_SPDIF_OUT_EN;
if (old != val)
outb(val, ICEREG1724(ice, SPDIF_CFG));
- spin_unlock_irq(&ice->reg_lock);
return old != val;
}
@@ -1820,7 +1810,7 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
if (uinfo->value.enumerated.item >= hw_rates_count)
/* ext_clock items */
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
ice->ext_clock_names[
uinfo->value.enumerated.item - hw_rates_count]);
else
@@ -1836,7 +1826,7 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned int i, rate;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
if (ice->is_spdif_master(ice)) {
ucontrol->value.enumerated.item[0] = ice->hw_rates->count +
ice->get_spdif_master_type(ice);
@@ -1850,7 +1840,6 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
}
}
}
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -1881,29 +1870,31 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
unsigned int old_rate, new_rate;
unsigned int item = ucontrol->value.enumerated.item[0];
unsigned int first_ext_clock = ice->hw_rates->count;
+ bool set_pro_rate = false;
if (item > first_ext_clock + ice->ext_clock_count - 1)
return -EINVAL;
/* if rate = 0 => external clock */
- spin_lock_irq(&ice->reg_lock);
- if (ice->is_spdif_master(ice))
- old_rate = 0;
- else
- old_rate = ice->get_rate(ice);
- if (item >= first_ext_clock) {
- /* switching to external clock */
- ice->set_spdif_clock(ice, item - first_ext_clock);
- new_rate = 0;
- } else {
- /* internal on-card clock */
- new_rate = ice->hw_rates->list[item];
- ice->pro_rate_default = new_rate;
- spin_unlock_irq(&ice->reg_lock);
- snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
- spin_lock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ if (ice->is_spdif_master(ice))
+ old_rate = 0;
+ else
+ old_rate = ice->get_rate(ice);
+ if (item >= first_ext_clock) {
+ /* switching to external clock */
+ ice->set_spdif_clock(ice, item - first_ext_clock);
+ new_rate = 0;
+ } else {
+ /* internal on-card clock */
+ new_rate = ice->hw_rates->list[item];
+ ice->pro_rate_default = new_rate;
+ set_pro_rate = true;
+ }
}
- spin_unlock_irq(&ice->reg_lock);
+
+ if (set_pro_rate)
+ snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
/* the first switch to the ext. clock mode? */
if (old_rate != new_rate && !new_rate) {
@@ -1943,10 +1934,9 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
int change = 0, nval;
nval = ucontrol->value.integer.value[0] ? 1 : 0;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
change = PRO_RATE_LOCKED != nval;
PRO_RATE_LOCKED = nval;
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -1974,10 +1964,9 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
int change = 0, nval;
nval = ucontrol->value.integer.value[0] ? 1 : 0;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
change = PRO_RATE_RESET != nval;
PRO_RATE_RESET = nval;
- spin_unlock_irq(&ice->reg_lock);
return change;
}
@@ -2132,13 +2121,12 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
int idx;
- spin_lock_irq(&ice->reg_lock);
+ guard(spinlock_irq)(&ice->reg_lock);
for (idx = 0; idx < 22; idx++) {
outb(idx, ICEMT1724(ice, MONITOR_PEAKINDEX));
ucontrol->value.integer.value[idx] =
inb(ICEMT1724(ice, MONITOR_PEAKDATA));
}
- spin_unlock_irq(&ice->reg_lock);
return 0;
}
@@ -2220,13 +2208,12 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
{
unsigned char val;
- mutex_lock(&ice->i2c_mutex);
+ guard(mutex)(&ice->i2c_mutex);
wait_i2c_busy(ice);
outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
wait_i2c_busy(ice);
val = inb(ICEREG1724(ice, I2C_DATA));
- mutex_unlock(&ice->i2c_mutex);
/*
dev_dbg(ice->card->dev, "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
*/
@@ -2236,7 +2223,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
unsigned char dev, unsigned char addr, unsigned char data)
{
- mutex_lock(&ice->i2c_mutex);
+ guard(mutex)(&ice->i2c_mutex);
wait_i2c_busy(ice);
/*
dev_dbg(ice->card->dev, "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
@@ -2245,7 +2232,6 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
outb(data, ICEREG1724(ice, I2C_DATA));
outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
wait_i2c_busy(ice);
- mutex_unlock(&ice->i2c_mutex);
}
static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
@@ -2392,23 +2378,27 @@ static int snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice)
if (err < 0)
return err;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice));
+ kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice);
+ kctl->id.device = ice->pcm->device;
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
+ kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice);
kctl->id.device = ice->pcm->device;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice));
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
+ kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice);
kctl->id.device = ice->pcm->device;
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice));
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
- kctl->id.device = ice->pcm->device;
#if 0 /* use default only */
- err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_stream, ice));
+ kctl = snd_ctl_new1(&snd_vt1724_spdif_stream, ice);
+ kctl->id.device = ice->pcm->device;
+ err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
- kctl->id.device = ice->pcm->device;
ice->spdif.stream_ctl = kctl;
#endif
return 0;
@@ -2487,7 +2477,7 @@ static int snd_vt1724_create(struct snd_card *card,
pci_set_master(pci);
snd_vt1724_proc_init(ice);
- err = pci_request_regions(pci, "ICE1724");
+ err = pcim_request_all_regions(pci, "ICE1724");
if (err < 0)
return err;
ice->port = pci_resource_start(pci, 0);
@@ -2541,8 +2531,8 @@ static int __snd_vt1724_probe(struct pci_dev *pci,
return err;
ice = card->private_data;
- strcpy(card->driver, "ICE1724");
- strcpy(card->shortname, "ICEnsemble ICE1724");
+ strscpy(card->driver, "ICE1724");
+ strscpy(card->shortname, "ICEnsemble ICE1724");
err = snd_vt1724_create(card, pci, model[dev]);
if (err < 0)
@@ -2553,9 +2543,9 @@ static int __snd_vt1724_probe(struct pci_dev *pci,
c = ice->card_info;
if (c) {
- strcpy(card->shortname, c->name);
+ strscpy(card->shortname, c->name);
if (c->driver) /* specific driver? */
- strcpy(card->driver, c->driver);
+ strscpy(card->driver, c->driver);
if (c->chip_init) {
err = c->chip_init(ice);
if (err < 0)
@@ -2633,7 +2623,7 @@ static int __snd_vt1724_probe(struct pci_dev *pci,
return err;
ice->rmidi[0] = rmidi;
rmidi->private_data = ice;
- strcpy(rmidi->name, "ICE1724 MIDI");
+ strscpy(rmidi->name, "ICE1724 MIDI");
rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT |
SNDRV_RAWMIDI_INFO_DUPLEX;
@@ -2681,12 +2671,12 @@ static int snd_vt1724_suspend(struct device *dev)
snd_ac97_suspend(ice->ac97);
- spin_lock_irq(&ice->reg_lock);
- ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice);
- ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL));
- ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG));
- ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
- spin_unlock_irq(&ice->reg_lock);
+ scoped_guard(spinlock_irq, &ice->reg_lock) {
+ ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice);
+ ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL));
+ ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG));
+ ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
+ }
if (ice->pm_suspend)
ice->pm_suspend(ice);
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index f0f8324b08b6..d679842ae1bd 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -408,30 +408,6 @@ static const char * const follower_vols[] = {
static
DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1);
-static struct snd_kcontrol *ctl_find(struct snd_card *card,
- const char *name)
-{
- struct snd_ctl_elem_id sid = {0};
-
- strscpy(sid.name, name, sizeof(sid.name));
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- return snd_ctl_find_id(card, &sid);
-}
-
-static void add_followers(struct snd_card *card,
- struct snd_kcontrol *master,
- const char * const *list)
-{
- for (; *list; list++) {
- struct snd_kcontrol *follower = ctl_find(card, *list);
- /* dev_dbg(card->dev, "add_followers - %s\n", *list); */
- if (follower) {
- /* dev_dbg(card->dev, "follower %s found\n", *list); */
- snd_ctl_add_follower(master, follower);
- }
- }
-}
-
static int juli_add_controls(struct snd_ice1712 *ice)
{
struct juli_spec *spec = ice->spec;
@@ -454,10 +430,12 @@ static int juli_add_controls(struct snd_ice1712 *ice)
juli_master_db_scale);
if (!vmaster)
return -ENOMEM;
- add_followers(ice->card, vmaster, follower_vols);
err = snd_ctl_add(ice->card, vmaster);
if (err < 0)
return err;
+ err = snd_ctl_add_followers(ice->card, vmaster, follower_vols);
+ if (err < 0)
+ return err;
/* only capture SPDIF over AK4114 */
return snd_ak4114_build(spec->ak4114, NULL,
diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c
index b46df1821251..551f478c59c4 100644
--- a/sound/pci/ice1712/maya44.c
+++ b/sound/pci/ice1712/maya44.c
@@ -175,10 +175,9 @@ static int maya_vol_get(struct snd_kcontrol *kcontrol,
&chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)];
unsigned int idx = kcontrol->private_value;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
ucontrol->value.integer.value[0] = wm->volumes[idx][0];
ucontrol->value.integer.value[1] = wm->volumes[idx][1];
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -193,7 +192,7 @@ static int maya_vol_put(struct snd_kcontrol *kcontrol,
unsigned int val, data;
int ch, changed = 0;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
for (ch = 0; ch < 2; ch++) {
val = ucontrol->value.integer.value[ch];
if (val > vol->maxval)
@@ -213,7 +212,6 @@ static int maya_vol_put(struct snd_kcontrol *kcontrol,
val ? 0 : vol->mux_bits[ch]);
wm->volumes[idx][ch] = val;
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -250,7 +248,7 @@ static int maya_sw_put(struct snd_kcontrol *kcontrol,
unsigned int mask, val;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
mask = 1 << idx;
wm->switch_bits &= ~mask;
val = ucontrol->value.integer.value[0];
@@ -260,7 +258,6 @@ static int maya_sw_put(struct snd_kcontrol *kcontrol,
changed = wm8776_write_bits(chip->ice, wm,
GET_SW_VAL_REG(kcontrol->private_value),
mask, val ? mask : 0);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -315,14 +312,13 @@ static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol,
unsigned int val, mask;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
mask = 1 << shift;
val = ucontrol->value.integer.value[0];
if (GET_GPIO_VAL_INV(kcontrol->private_value))
val = !val;
val = val ? mask : 0;
changed = maya_set_gpio_bits(chip->ice, mask, val);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -369,11 +365,10 @@ static int maya_rec_src_put(struct snd_kcontrol *kcontrol,
int sel = ucontrol->value.enumerated.item[0];
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY,
sel ? (1 << GPIO_MIC_RELAY) : 0);
wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -635,12 +630,11 @@ static void set_rate(struct snd_ice1712 *ice, unsigned int rate)
val |= 8;
val |= ratio << 4;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
for (i = 0; i < 2; i++)
wm8776_write_bits(ice, &chip->wm[i],
WM8776_REG_MASTER_MODE_CONTROL,
0x180, val);
- mutex_unlock(&chip->mutex);
}
/*
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index 1e47e46ab8ac..151b740ce66d 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -287,10 +287,9 @@ static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?
0 : 1;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -638,11 +637,10 @@ static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned short val;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
val = val > PCM_MIN ? (val - PCM_MIN) : 0;
ucontrol->value.integer.value[0] = val;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 683909ca147c..557473f0d59e 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -112,13 +112,12 @@ static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
unsigned short val;
int i;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff;
val = val > DAC_MIN ? (val - DAC_MIN) : 0;
ucontrol->value.integer.value[i] = val;
}
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -128,7 +127,7 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
unsigned short oval, nval;
int i, idx, change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
nval = ucontrol->value.integer.value[i];
nval = (nval ? (nval + DAC_MIN) : 0) & 0xff;
@@ -140,7 +139,6 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -167,13 +165,12 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
unsigned short val;
int i;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
val = val > ADC_MIN ? (val - ADC_MIN) : 0;
ucontrol->value.integer.value[i] = val;
}
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -183,7 +180,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
unsigned short ovol, nvol;
int i, idx, change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
nvol = ucontrol->value.integer.value[i];
nvol = nvol ? (nvol + ADC_MIN) : 0;
@@ -194,7 +191,6 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -208,9 +204,8 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
int bit = kcontrol->private_value;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -221,7 +216,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
unsigned short oval, nval;
int change;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
nval = oval = wm_get(ice, WM_ADC_MUX);
if (ucontrol->value.integer.value[0])
nval |= (1 << bit);
@@ -231,7 +226,6 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
if (change) {
wm_put(ice, WM_ADC_MUX, nval);
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -244,9 +238,8 @@ static int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -256,7 +249,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
unsigned short val, oval;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
val = oval = wm_get(ice, WM_OUT_MUX);
if (ucontrol->value.integer.value[0])
val |= 0x04;
@@ -266,7 +259,6 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
wm_put(ice, WM_OUT_MUX, val);
change = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -279,9 +271,8 @@ static int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -291,7 +282,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
unsigned short val, oval;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
oval = wm_get(ice, WM_DAC_CTRL1);
val = oval & 0x0f;
if (ucontrol->value.integer.value[0])
@@ -303,7 +294,6 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
wm_put_nocache(ice, WM_DAC_CTRL1, val);
change = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -410,9 +400,8 @@ static int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.enumerated.item[0] = ice->gpio.saved[0];
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -422,14 +411,13 @@ static int cs_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
unsigned char val;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) {
ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3;
val = 0x80 | (ice->gpio.saved[0] << 3);
spi_write(ice, CS_DEV, 0x04, val);
change = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -449,10 +437,10 @@ static int pontis_gpio_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e
static int pontis_gpio_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
/* 4-7 reserved */
ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -461,22 +449,22 @@ static int pontis_gpio_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned int val;
int changed;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
/* 4-7 reserved */
val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0;
changed = val != ice->gpio.write_mask;
ice->gpio.write_mask = val;
- mutex_unlock(&ice->gpio_mutex);
return changed;
}
static int pontis_gpio_dir_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
/* 4-7 reserved */
ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -485,23 +473,23 @@ static int pontis_gpio_dir_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned int val;
int changed;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
/* 4-7 reserved */
val = ucontrol->value.integer.value[0] & 0xff0f;
changed = (val != ice->gpio.direction);
ice->gpio.direction = val;
- mutex_unlock(&ice->gpio_mutex);
return changed;
}
static int pontis_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -510,7 +498,8 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned int val, nval;
int changed = 0;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
val = snd_ice1712_gpio_read(ice) & 0xffff;
@@ -519,7 +508,6 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
snd_ice1712_gpio_write(ice, nval);
changed = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return changed;
}
@@ -620,14 +608,14 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf
struct snd_ice1712 *ice = entry->private_data;
char line[64];
unsigned int reg, val;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
if (reg <= 0x17 && val <= 0xffff)
wm_put(ice, reg, val);
}
- mutex_unlock(&ice->gpio_mutex);
}
static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
@@ -635,12 +623,11 @@ static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff
struct snd_ice1712 *ice = entry->private_data;
int reg, val;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (reg = 0; reg <= 0x17; reg++) {
val = wm_get(ice, reg);
snd_iprintf(buffer, "%02x = %04x\n", reg, val);
}
- mutex_unlock(&ice->gpio_mutex);
}
static void wm_proc_init(struct snd_ice1712 *ice)
@@ -654,14 +641,13 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff
struct snd_ice1712 *ice = entry->private_data;
int reg, val;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (reg = 0; reg <= 0x26; reg++) {
val = spi_read(ice, CS_DEV, reg);
snd_iprintf(buffer, "%02x = %02x\n", reg, val);
}
val = spi_read(ice, CS_DEV, 0x7f);
snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val);
- mutex_unlock(&ice->gpio_mutex);
}
static void cs_proc_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index 096ec76f5304..cd7db2b65b51 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -110,21 +110,19 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
struct prodigy192_spec *spec = ice->spec;
- int idx, change;
+ int idx;
if (kcontrol->private_value)
idx = STAC946X_MASTER_VOLUME;
else
idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
/* due to possible conflicts with stac9460_set_rate_val, mutexing */
- mutex_lock(&spec->mute_mutex);
+ guard(mutex)(&spec->mute_mutex);
/*
dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
ucontrol->value.integer.value[0]);
*/
- change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
- mutex_unlock(&spec->mute_mutex);
- return change;
+ return stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
}
/*
@@ -170,14 +168,9 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
tmp = stac9460_get(ice, idx);
ovol = 0x7f - (tmp & 0x7f);
change = (ovol != nvol);
- if (change) {
- ovol = (0x7f - nvol) | (tmp & 0x80);
- /*
- dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n",
- idx, ovol);
- */
+ if (change)
stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
- }
+
return change;
}
@@ -321,7 +314,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
return;
/* change detected, setting master clock, muting first */
/* due to possible conflicts with mute controls - mutexing */
- mutex_lock(&spec->mute_mutex);
+ guard(mutex)(&spec->mute_mutex);
/* we have to remember current mute status for each DAC */
for (idx = 0; idx < 7 ; ++idx)
changed[idx] = stac9460_dac_mute(ice,
@@ -335,7 +328,6 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
if (changed[idx])
stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1);
}
- mutex_unlock(&spec->mute_mutex);
}
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index 9aa12a67d370..eac233093865 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -268,7 +268,7 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
int i;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
if (ucontrol->value.integer.value[i] != spec->vol[i]) {
spec->vol[i] = ucontrol->value.integer.value[i];
@@ -277,7 +277,6 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -376,7 +375,7 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
struct prodigy_hifi_spec *spec = ice->spec;
int i, idx, change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) {
idx = WM_DAC_ATTEN_L + i;
@@ -386,7 +385,6 @@ static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -428,7 +426,7 @@ static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
voices = kcontrol->private_value >> 8;
ofs = kcontrol->private_value & 0xff;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < voices; i++) {
if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) {
idx = WM8766_LDA1 + ofs + i;
@@ -439,7 +437,6 @@ static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -474,7 +471,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
struct prodigy_hifi_spec *spec = ice->spec;
int ch, change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (ch = 0; ch < 2; ch++) {
if (ucontrol->value.integer.value[ch] != spec->master[ch]) {
spec->master[ch] = ucontrol->value.integer.value[ch];
@@ -494,7 +491,6 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -535,9 +531,8 @@ static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -548,14 +543,13 @@ static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
unsigned short oval, nval;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
oval = wm_get(ice, WM_ADC_MUX);
nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0];
if (nval != oval) {
wm_put(ice, WM_ADC_MUX, nval);
change = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -586,13 +580,12 @@ static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,
unsigned short val;
int i;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
val = val > ADC_MIN ? (val - ADC_MIN) : 0;
ucontrol->value.integer.value[i] = val;
}
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -603,7 +596,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
unsigned short ovol, nvol;
int i, idx, change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (i = 0; i < 2; i++) {
nvol = ucontrol->value.integer.value[i];
nvol = nvol ? (nvol + ADC_MIN) : 0;
@@ -614,7 +607,6 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
change = 1;
}
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -629,10 +621,9 @@ static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
int bit = kcontrol->private_value;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] =
(wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -644,7 +635,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
unsigned short oval, nval;
int change;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
nval = oval = wm_get(ice, WM_ADC_MUX);
if (ucontrol->value.integer.value[0])
nval |= (1 << bit);
@@ -654,7 +645,6 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
if (change) {
wm_put(ice, WM_ADC_MUX, nval);
}
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -668,10 +658,9 @@ static int wm_bypass_get(struct snd_kcontrol *kcontrol,
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] =
(wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -682,7 +671,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol,
unsigned short val, oval;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
val = oval = wm_get(ice, WM_OUT_MUX);
if (ucontrol->value.integer.value[0])
val |= 0x04;
@@ -692,7 +681,6 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol,
wm_put(ice, WM_OUT_MUX, val);
change = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -706,10 +694,9 @@ static int wm_chswap_get(struct snd_kcontrol *kcontrol,
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
ucontrol->value.integer.value[0] =
(wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
@@ -720,7 +707,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol,
unsigned short val, oval;
int change = 0;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
oval = wm_get(ice, WM_DAC_CTRL1);
val = oval & 0x0f;
if (ucontrol->value.integer.value[0])
@@ -732,7 +719,6 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol,
wm_put_nocache(ice, WM_DAC_CTRL1, val);
change = 1;
}
- mutex_unlock(&ice->gpio_mutex);
return change;
}
@@ -864,14 +850,14 @@ static void wm_proc_regs_write(struct snd_info_entry *entry,
struct snd_ice1712 *ice = entry->private_data;
char line[64];
unsigned int reg, val;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%x %x", &reg, &val) != 2)
continue;
if (reg <= 0x17 && val <= 0xffff)
wm_put(ice, reg, val);
}
- mutex_unlock(&ice->gpio_mutex);
}
static void wm_proc_regs_read(struct snd_info_entry *entry,
@@ -880,12 +866,11 @@ static void wm_proc_regs_read(struct snd_info_entry *entry,
struct snd_ice1712 *ice = entry->private_data;
int reg, val;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
for (reg = 0; reg <= 0x17; reg++) {
val = wm_get(ice, reg);
snd_iprintf(buffer, "%02x = %04x\n", reg, val);
}
- mutex_unlock(&ice->gpio_mutex);
}
static void wm_proc_init(struct snd_ice1712 *ice)
@@ -994,7 +979,7 @@ static int prodigy_hifi_resume(struct snd_ice1712 *ice)
struct prodigy_hifi_spec *spec = ice->spec;
int i, ch;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
/* reinitialize WM8776 and re-apply old register values */
wm8776_init(ice);
@@ -1023,7 +1008,6 @@ static int prodigy_hifi_resume(struct snd_ice1712 *ice)
wm_put(ice, WM_DAC_MUTE, 0x00);
wm_put(ice, WM_DAC_CTRL1, 0x90);
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
#endif
@@ -1134,11 +1118,11 @@ static int prodigy_hd2_resume(struct snd_ice1712 *ice)
/* initialize ak4396 codec and restore previous mixer volumes */
struct prodigy_hifi_spec *spec = ice->spec;
int i;
- mutex_lock(&ice->gpio_mutex);
+
+ guard(mutex)(&ice->gpio_mutex);
ak4396_init(ice);
for (i = 0; i < 2; i++)
ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
- mutex_unlock(&ice->gpio_mutex);
return 0;
}
#endif
diff --git a/sound/pci/ice1712/psc724.c b/sound/pci/ice1712/psc724.c
index 82cf365cda10..0818e42c94ca 100644
--- a/sound/pci/ice1712/psc724.c
+++ b/sound/pci/ice1712/psc724.c
@@ -177,7 +177,6 @@ static bool psc724_get_master_switch(struct snd_ice1712 *ice)
static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected)
{
struct psc724_spec *spec = ice->spec;
- struct snd_ctl_elem_id elem_id;
struct snd_kcontrol *kctl;
u16 power = spec->wm8776.regs[WM8776_REG_PWRDOWN] & ~WM8776_PWR_HPPD;
@@ -187,17 +186,15 @@ static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected)
snd_wm8776_set_power(&spec->wm8776, power);
spec->hp_connected = hp_connected;
/* notify about master speaker mute change */
- memset(&elem_id, 0, sizeof(elem_id));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strscpy(elem_id.name, "Master Speakers Playback Switch",
- sizeof(elem_id.name));
- kctl = snd_ctl_find_id(ice->card, &elem_id);
- snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+ kctl = snd_ctl_find_id_mixer(ice->card,
+ "Master Speakers Playback Switch");
+ if (kctl)
+ snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
/* and headphone mute change */
- strscpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name,
- sizeof(elem_id.name));
- kctl = snd_ctl_find_id(ice->card, &elem_id);
- snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+ kctl = snd_ctl_find_id_mixer(ice->card,
+ spec->wm8776.ctl[WM8776_CTL_HP_SW].name);
+ if (kctl)
+ snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
}
static void psc724_update_hp_jack_state(struct work_struct *work)
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
index 20b3e8f94719..099601edf1d0 100644
--- a/sound/pci/ice1712/quartet.c
+++ b/sound/pci/ice1712/quartet.c
@@ -396,7 +396,7 @@ static void reg_write(struct snd_ice1712 *ice, unsigned int reg,
{
unsigned int tmp;
- mutex_lock(&ice->gpio_mutex);
+ guard(mutex)(&ice->gpio_mutex);
/* set direction of used GPIOs*/
/* all outputs */
tmp = 0x00ffff;
@@ -429,7 +429,6 @@ static void reg_write(struct snd_ice1712 *ice, unsigned int reg,
ice->gpio.set_mask(ice, 0xffffff);
/* outputs only 8-15 */
ice->gpio.set_dir(ice, 0x00ff00);
- mutex_unlock(&ice->gpio_mutex);
}
static unsigned int get_scr(struct snd_ice1712 *ice)
@@ -766,26 +765,6 @@ static const char * const follower_vols[] = {
static
DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
-static struct snd_kcontrol *ctl_find(struct snd_card *card,
- const char *name)
-{
- struct snd_ctl_elem_id sid = {0};
-
- strscpy(sid.name, name, sizeof(sid.name));
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- return snd_ctl_find_id(card, &sid);
-}
-
-static void add_followers(struct snd_card *card,
- struct snd_kcontrol *master, const char * const *list)
-{
- for (; *list; list++) {
- struct snd_kcontrol *follower = ctl_find(card, *list);
- if (follower)
- snd_ctl_add_follower(master, follower);
- }
-}
-
static int qtet_add_controls(struct snd_ice1712 *ice)
{
struct qtet_spec *spec = ice->spec;
@@ -806,10 +785,12 @@ static int qtet_add_controls(struct snd_ice1712 *ice)
qtet_master_db_scale);
if (!vmaster)
return -ENOMEM;
- add_followers(ice->card, vmaster, follower_vols);
err = snd_ctl_add(ice->card, vmaster);
if (err < 0)
return err;
+ err = snd_ctl_add_followers(ice->card, vmaster, follower_vols);
+ if (err < 0)
+ return err;
/* only capture SPDIF over AK4113 */
return snd_ak4113_build(spec->ak4113,
ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c
index 6eda86119dff..493425697bb4 100644
--- a/sound/pci/ice1712/wm8776.c
+++ b/sound/pci/ice1712/wm8776.c
@@ -34,13 +34,9 @@ static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm,
struct snd_card *card = wm->card;
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
- struct snd_ctl_elem_id elem_id;
unsigned int index_offset;
- memset(&elem_id, 0, sizeof(elem_id));
- strscpy(elem_id.name, ctl_name, sizeof(elem_id.name));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kctl = snd_ctl_find_id(card, &elem_id);
+ kctl = snd_ctl_find_id_mixer(card, ctl_name);
if (!kctl)
return;
index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c
index f613f0067d8c..57a79536e7ba 100644
--- a/sound/pci/ice1712/wtm.c
+++ b/sound/pci/ice1712/wtm.c
@@ -118,7 +118,7 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
unsigned char val;
int idx, id;
- mutex_lock(&spec->mute_mutex);
+ guard(mutex)(&spec->mute_mutex);
if (kcontrol->private_value) {
idx = STAC946X_MASTER_VOLUME;
@@ -133,7 +133,6 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
val = stac9460_2_get(ice, idx - 6);
ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
- mutex_unlock(&spec->mute_mutex);
return 0;
}
@@ -455,7 +454,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
return;
/* change detected, setting master clock, muting first */
/* due to possible conflicts with mute controls - mutexing */
- mutex_lock(&spec->mute_mutex);
+ guard(mutex)(&spec->mute_mutex);
/* we have to remember current mute status for each DAC */
changed = 0xFFFF;
stac9460_dac_mute_all(ice, 0, &changed);
@@ -466,7 +465,6 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
/* unmuting - only originally unmuted dacs -
* i.e. those changed when muting */
stac9460_dac_mute_all(ice, 1, &changed);
- mutex_unlock(&spec->mute_mutex);
}
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index ae285c0a629c..3b53c5e63c29 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -690,55 +690,51 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ichdev)
{
unsigned long port = ichdev->reg_offset;
- unsigned long flags;
int status, civ, i, step;
int ack = 0;
if (!(ichdev->prepared || chip->in_measurement) || ichdev->suspended)
return;
- spin_lock_irqsave(&chip->reg_lock, flags);
- status = igetbyte(chip, port + ichdev->roff_sr);
- civ = igetbyte(chip, port + ICH_REG_OFF_CIV);
- if (!(status & ICH_BCIS)) {
- step = 0;
- } else if (civ == ichdev->civ) {
- // snd_printd("civ same %d\n", civ);
- step = 1;
- ichdev->civ++;
- ichdev->civ &= ICH_REG_LVI_MASK;
- } else {
- step = civ - ichdev->civ;
- if (step < 0)
- step += ICH_REG_LVI_MASK + 1;
- // if (step != 1)
- // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ);
- ichdev->civ = civ;
- }
-
- ichdev->position += step * ichdev->fragsize1;
- if (! chip->in_measurement)
- ichdev->position %= ichdev->size;
- ichdev->lvi += step;
- ichdev->lvi &= ICH_REG_LVI_MASK;
- iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
- for (i = 0; i < step; i++) {
- ichdev->lvi_frag++;
- ichdev->lvi_frag %= ichdev->frags;
- ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ status = igetbyte(chip, port + ichdev->roff_sr);
+ civ = igetbyte(chip, port + ICH_REG_OFF_CIV);
+ if (!(status & ICH_BCIS)) {
+ step = 0;
+ } else if (civ == ichdev->civ) {
+ step = 1;
+ ichdev->civ++;
+ ichdev->civ &= ICH_REG_LVI_MASK;
+ } else {
+ step = civ - ichdev->civ;
+ if (step < 0)
+ step += ICH_REG_LVI_MASK + 1;
+ ichdev->civ = civ;
+ }
+
+ ichdev->position += step * ichdev->fragsize1;
+ if (! chip->in_measurement)
+ ichdev->position %= ichdev->size;
+ ichdev->lvi += step;
+ ichdev->lvi &= ICH_REG_LVI_MASK;
+ iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
+ for (i = 0; i < step; i++) {
+ ichdev->lvi_frag++;
+ ichdev->lvi_frag %= ichdev->frags;
+ ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
#if 0
- dev_dbg(chip->card->dev,
- "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
- ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
- ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
- inl(port + 4), inb(port + ICH_REG_OFF_CR));
+ dev_dbg(chip->card->dev,
+ "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
+ ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
+ ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
+ inl(port + 4), inb(port + ICH_REG_OFF_CR));
#endif
- if (--ichdev->ack == 0) {
- ichdev->ack = ichdev->ack_reload;
- ack = 1;
+ if (--ichdev->ack == 0) {
+ ichdev->ack = ichdev->ack_reload;
+ ack = 1;
+ }
}
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (ack && ichdev->substream) {
snd_pcm_period_elapsed(ichdev->substream);
}
@@ -920,7 +916,7 @@ static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip,
unsigned int cnt;
int dbl = runtime->rate > 48000;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
switch (chip->device_type) {
case DEVICE_ALI:
cnt = igetdword(chip, ICHREG(ALI_SCR));
@@ -966,7 +962,6 @@ static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip,
iputdword(chip, ICHREG(GLOB_CNT), cnt);
break;
}
- spin_unlock_irq(&chip->reg_lock);
}
static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream)
@@ -996,7 +991,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
int civ, timeout = 10;
unsigned int position;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
do {
civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
@@ -1036,7 +1031,6 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
}
}
ichdev->last_pos = ptr;
- spin_unlock(&chip->reg_lock);
if (ptr >= ichdev->size)
return 0;
return bytes_to_frames(substream->runtime, ptr);
@@ -1238,12 +1232,12 @@ static int snd_intel8x0_ali_ac97spdifout_open(struct snd_pcm_substream *substrea
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
unsigned int val;
- spin_lock_irq(&chip->reg_lock);
- val = igetdword(chip, ICHREG(ALI_INTERFACECR));
- val |= ICH_ALI_IF_AC97SP;
- iputdword(chip, ICHREG(ALI_INTERFACECR), val);
- /* also needs to set ALI_SC_CODEC_SPDF correctly */
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ val = igetdword(chip, ICHREG(ALI_INTERFACECR));
+ val |= ICH_ALI_IF_AC97SP;
+ iputdword(chip, ICHREG(ALI_INTERFACECR), val);
+ /* also needs to set ALI_SC_CODEC_SPDF correctly */
+ }
return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]);
}
@@ -1254,11 +1248,10 @@ static int snd_intel8x0_ali_ac97spdifout_close(struct snd_pcm_substream *substre
unsigned int val;
chip->ichd[ALID_AC97SPDIFOUT].substream = NULL;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
val = igetdword(chip, ICHREG(ALI_INTERFACECR));
val &= ~ICH_ALI_IF_AC97SP;
iputdword(chip, ICHREG(ALI_INTERFACECR), val);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1439,7 +1432,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
if (rec->suffix)
sprintf(name, "Intel ICH - %s", rec->suffix);
else
- strcpy(name, "Intel ICH");
+ strscpy(name, "Intel ICH");
err = snd_pcm_new(chip->card, name, device,
rec->playback_ops ? 1 : 0,
rec->capture_ops ? 1 : 0, &pcm);
@@ -1456,7 +1449,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
if (rec->suffix)
sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix);
else
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm[device] = pcm;
snd_pcm_set_managed_buffer_all(pcm, intel8x0_dma_type(chip),
@@ -2252,7 +2245,7 @@ static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
tmp |= chip->ac97_sdin[0] << ICH_DI1L_SHIFT;
for (i = 1; i < 4; i++) {
if (pcm->r[0].codec[i]) {
- tmp |= chip->ac97_sdin[pcm->r[0].codec[1]->num] << ICH_DI2L_SHIFT;
+ tmp |= chip->ac97_sdin[pcm->r[0].codec[i]->num] << ICH_DI2L_SHIFT;
break;
}
}
@@ -2555,7 +2548,6 @@ static void snd_intel8x0_free(struct snd_card *card)
free_irq(chip->irq, chip);
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -2628,11 +2620,7 @@ static int intel8x0_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
-#define INTEL8X0_PM_OPS &intel8x0_pm
-#else
-#define INTEL8X0_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
#define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */
@@ -2670,53 +2658,53 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
}
snd_intel8x0_setup_periods(chip, ichdev);
port = ichdev->reg_offset;
- spin_lock_irq(&chip->reg_lock);
- chip->in_measurement = 1;
- /* trigger */
- if (chip->device_type != DEVICE_ALI)
- iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM);
- else {
- iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
- iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ chip->in_measurement = 1;
+ /* trigger */
+ if (chip->device_type != DEVICE_ALI)
+ iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM);
+ else {
+ iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
+ iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
+ }
+ start_time = ktime_get();
}
- start_time = ktime_get();
- spin_unlock_irq(&chip->reg_lock);
msleep(50);
- spin_lock_irq(&chip->reg_lock);
- /* check the position */
- do {
- civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
- pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
- if (pos1 == 0) {
- udelay(10);
- continue;
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ /* check the position */
+ do {
+ civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
+ pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
+ if (pos1 == 0) {
+ udelay(10);
+ continue;
+ }
+ if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
+ pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
+ break;
+ } while (timeout--);
+ if (pos1 == 0) { /* oops, this value is not reliable */
+ pos = 0;
+ } else {
+ pos = ichdev->fragsize1;
+ pos -= pos1 << ichdev->pos_shift;
+ pos += ichdev->position;
}
- if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
- pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
- break;
- } while (timeout--);
- if (pos1 == 0) { /* oops, this value is not reliable */
- pos = 0;
- } else {
- pos = ichdev->fragsize1;
- pos -= pos1 << ichdev->pos_shift;
- pos += ichdev->position;
- }
- chip->in_measurement = 0;
- stop_time = ktime_get();
- /* stop */
- if (chip->device_type == DEVICE_ALI) {
- iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
- iputbyte(chip, port + ICH_REG_OFF_CR, 0);
- while (igetbyte(chip, port + ICH_REG_OFF_CR))
- ;
- } else {
- iputbyte(chip, port + ICH_REG_OFF_CR, 0);
- while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
- ;
+ chip->in_measurement = 0;
+ stop_time = ktime_get();
+ /* stop */
+ if (chip->device_type == DEVICE_ALI) {
+ iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
+ iputbyte(chip, port + ICH_REG_OFF_CR, 0);
+ while (igetbyte(chip, port + ICH_REG_OFF_CR))
+ ;
+ } else {
+ iputbyte(chip, port + ICH_REG_OFF_CR, 0);
+ while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
+ ;
+ }
+ iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
}
- iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
- spin_unlock_irq(&chip->reg_lock);
if (pos == 0) {
dev_err(chip->card->dev,
@@ -2934,7 +2922,7 @@ static int snd_intel8x0_init(struct snd_card *card,
pci->device == PCI_DEVICE_ID_INTEL_440MX)
chip->fix_nocache = 1; /* enable workaround */
- err = pci_request_regions(pci, card->shortname);
+ err = pcim_request_all_regions(pci, card->shortname);
if (err < 0)
return err;
@@ -3126,21 +3114,21 @@ static int __snd_intel8x0_probe(struct pci_dev *pci,
if (spdif_aclink < 0)
spdif_aclink = check_default_spdif_aclink(pci);
- strcpy(card->driver, "ICH");
+ strscpy(card->driver, "ICH");
if (!spdif_aclink) {
switch (pci_id->driver_data) {
case DEVICE_NFORCE:
- strcpy(card->driver, "NFORCE");
+ strscpy(card->driver, "NFORCE");
break;
case DEVICE_INTEL_ICH4:
- strcpy(card->driver, "ICH4");
+ strscpy(card->driver, "ICH4");
}
}
- strcpy(card->shortname, "Intel ICH");
+ strscpy(card->shortname, "Intel ICH");
for (name = shortnames; name->id; name++) {
if (pci->device == name->id) {
- strcpy(card->shortname, name->s);
+ strscpy(card->shortname, name->s);
break;
}
}
@@ -3200,7 +3188,7 @@ static struct pci_driver intel8x0_driver = {
.id_table = snd_intel8x0_ids,
.probe = snd_intel8x0_probe,
.driver = {
- .pm = INTEL8X0_PM_OPS,
+ .pm = &intel8x0_pm,
},
};
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 2845cc006d0c..84e1b7ea34e2 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -423,7 +423,6 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i
civ = igetbyte(chip, port + ICH_REG_OFF_CIV);
if (civ == ichdev->civ) {
- // snd_printd("civ same %d\n", civ);
step = 1;
ichdev->civ++;
ichdev->civ &= ICH_REG_LVI_MASK;
@@ -431,8 +430,6 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i
step = civ - ichdev->civ;
if (step < 0)
step += ICH_REG_LVI_MASK + 1;
- // if (step != 1)
- // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ);
ichdev->civ = civ;
}
@@ -474,16 +471,13 @@ static irqreturn_t snd_intel8x0m_interrupt(int irq, void *dev_id)
unsigned int status;
unsigned int i;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
status = igetdword(chip, chip->int_sta_reg);
- if (status == 0xffffffff) { /* we are not yet resumed */
- spin_unlock(&chip->reg_lock);
+ if (status == 0xffffffff) /* we are not yet resumed */
return IRQ_NONE;
- }
if ((status & chip->int_sta_mask) == 0) {
if (status)
iputdword(chip, chip->int_sta_reg, status);
- spin_unlock(&chip->reg_lock);
return IRQ_NONE;
}
@@ -495,7 +489,6 @@ static irqreturn_t snd_intel8x0m_interrupt(int irq, void *dev_id)
/* ack them */
iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask);
- spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -681,7 +674,7 @@ static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device,
if (rec->suffix)
sprintf(name, "Intel ICH - %s", rec->suffix);
else
- strcpy(name, "Intel ICH");
+ strscpy(name, "Intel ICH");
err = snd_pcm_new(chip->card, name, device,
rec->playback_ops ? 1 : 0,
rec->capture_ops ? 1 : 0, &pcm);
@@ -699,7 +692,7 @@ static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device,
if (rec->suffix)
sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix);
else
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm[device] = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -918,7 +911,7 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
}
if (chip->device_type == DEVICE_SIS) {
- /* unmute the output on SIS7012 */
+ /* unmute the output on SIS7013 */
iputword(chip, 0x4c, igetword(chip, 0x4c) | 1);
}
@@ -965,7 +958,6 @@ static void snd_intel8x0m_free(struct snd_card *card)
free_irq(chip->irq, chip);
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1006,11 +998,7 @@ static int intel8x0m_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
-#define INTEL8X0M_PM_OPS &intel8x0m_pm
-#else
-#define INTEL8X0M_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
static void snd_intel8x0m_proc_read(struct snd_info_entry * entry,
struct snd_info_buffer *buffer)
@@ -1068,7 +1056,7 @@ static int snd_intel8x0m_init(struct snd_card *card,
chip->pci = pci;
chip->irq = -1;
- err = pci_request_regions(pci, card->shortname);
+ err = pcim_request_all_regions(pci, card->shortname);
if (err < 0)
return err;
@@ -1192,11 +1180,11 @@ static int __snd_intel8x0m_probe(struct pci_dev *pci,
return err;
chip = card->private_data;
- strcpy(card->driver, "ICH-MODEM");
- strcpy(card->shortname, "Intel ICH");
+ strscpy(card->driver, "ICH-MODEM");
+ strscpy(card->shortname, "Intel ICH");
for (name = shortnames; name->id; name++) {
if (pci->device == name->id) {
- strcpy(card->shortname, name->s);
+ strscpy(card->shortname, name->s);
break;
}
}
@@ -1236,7 +1224,7 @@ static struct pci_driver intel8x0m_driver = {
.id_table = snd_intel8x0m_ids,
.probe = snd_intel8x0m_probe,
.driver = {
- .pm = INTEL8X0M_PM_OPS,
+ .pm = &intel8x0m_pm,
},
};
diff --git a/sound/pci/korg1212/Makefile b/sound/pci/korg1212/Makefile
index 42eb287c77af..ab0186ffbd58 100644
--- a/sound/pci/korg1212/Makefile
+++ b/sound/pci/korg1212/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-korg1212-objs := korg1212.o
+snd-korg1212-y := korg1212.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_KORG1212) += snd-korg1212.o
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 33b4f95d65b3..d16acf83668a 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -28,14 +28,14 @@
// ----------------------------------------------------------------------------
#define K1212_DEBUG_LEVEL 0
#if K1212_DEBUG_LEVEL > 0
-#define K1212_DEBUG_PRINTK(fmt,args...) printk(KERN_DEBUG fmt,##args)
+#define K1212_DEBUG_PRINTK(fmt, args...) pr_debug(fmt, ##args)
#else
-#define K1212_DEBUG_PRINTK(fmt,...) do { } while (0)
+#define K1212_DEBUG_PRINTK(fmt, ...) do { } while (0)
#endif
#if K1212_DEBUG_LEVEL > 1
-#define K1212_DEBUG_PRINTK_VERBOSE(fmt,args...) printk(KERN_DEBUG fmt,##args)
+#define K1212_DEBUG_PRINTK_VERBOSE(fmt, args...) pr_debug(fmt, ##args)
#else
-#define K1212_DEBUG_PRINTK_VERBOSE(fmt,...)
+#define K1212_DEBUG_PRINTK_VERBOSE(fmt, ...)
#endif
// ----------------------------------------------------------------------------
@@ -308,9 +308,6 @@ struct snd_korg1212 {
spinlock_t lock;
struct mutex open_mutex;
- struct timer_list timer; /* timer callback for checking ack of stop request */
- int stop_pending_cnt; /* counter for stop pending check */
-
wait_queue_head_t wait;
unsigned long iomem;
@@ -382,7 +379,7 @@ struct snd_korg1212 {
unsigned long totalerrorcnt; // Total Error Count
int dsp_is_loaded;
- int dsp_stop_is_processed;
+ int dsp_stop_processing;
};
@@ -565,66 +562,25 @@ static int snd_korg1212_Send1212Command(struct snd_korg1212 *korg1212,
/* spinlock already held */
static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212)
{
- if (! korg1212->stop_pending_cnt) {
- korg1212->sharedBufferPtr->cardCommand = 0xffffffff;
- /* program the timer */
- korg1212->stop_pending_cnt = HZ;
- mod_timer(&korg1212->timer, jiffies + 1);
- }
+ korg1212->dsp_stop_processing = 1;
+ korg1212->sharedBufferPtr->cardCommand = 0xffffffff;
}
static void snd_korg1212_SendStopAndWait(struct snd_korg1212 *korg1212)
{
- unsigned long flags;
- spin_lock_irqsave(&korg1212->lock, flags);
- korg1212->dsp_stop_is_processed = 0;
- snd_korg1212_SendStop(korg1212);
- spin_unlock_irqrestore(&korg1212->lock, flags);
- wait_event_timeout(korg1212->wait, korg1212->dsp_stop_is_processed, (HZ * 3) / 2);
-}
-
-/* timer callback for checking the ack of stop request */
-static void snd_korg1212_timer_func(struct timer_list *t)
-{
- struct snd_korg1212 *korg1212 = from_timer(korg1212, t, timer);
- unsigned long flags;
-
- spin_lock_irqsave(&korg1212->lock, flags);
- if (korg1212->sharedBufferPtr->cardCommand == 0) {
- /* ack'ed */
- korg1212->stop_pending_cnt = 0;
- korg1212->dsp_stop_is_processed = 1;
- wake_up(&korg1212->wait);
- K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: Stop ack'ed [%s]\n",
- stateName[korg1212->cardState]);
- } else {
- if (--korg1212->stop_pending_cnt > 0) {
- /* reprogram timer */
- mod_timer(&korg1212->timer, jiffies + 1);
- } else {
- snd_printd("korg1212_timer_func timeout\n");
- korg1212->sharedBufferPtr->cardCommand = 0;
- korg1212->dsp_stop_is_processed = 1;
- wake_up(&korg1212->wait);
- K1212_DEBUG_PRINTK("K1212_DEBUG: Stop timeout [%s]\n",
- stateName[korg1212->cardState]);
- }
+ scoped_guard(spinlock_irqsave, &korg1212->lock) {
+ snd_korg1212_SendStop(korg1212);
}
- spin_unlock_irqrestore(&korg1212->lock, flags);
+ wait_event_timeout(korg1212->wait, !korg1212->dsp_stop_processing, HZ);
}
static int snd_korg1212_TurnOnIdleMonitor(struct snd_korg1212 *korg1212)
{
- unsigned long flags;
- int rc;
-
udelay(INTERCOMMAND_DELAY);
- spin_lock_irqsave(&korg1212->lock, flags);
+ guard(spinlock_irqsave)(&korg1212->lock);
korg1212->idleMonitorOn = 1;
- rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
- K1212_MODE_MonitorOn, 0, 0, 0);
- spin_unlock_irqrestore(&korg1212->lock, flags);
- return rc;
+ return snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
+ K1212_MODE_MonitorOn, 0, 0, 0);
}
static void snd_korg1212_TurnOffIdleMonitor(struct snd_korg1212 *korg1212)
@@ -644,13 +600,12 @@ static int snd_korg1212_OpenCard(struct snd_korg1212 * korg1212)
{
K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n",
stateName[korg1212->cardState], korg1212->opencnt);
- mutex_lock(&korg1212->open_mutex);
+ guard(mutex)(&korg1212->open_mutex);
if (korg1212->opencnt++ == 0) {
snd_korg1212_TurnOffIdleMonitor(korg1212);
snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
}
- mutex_unlock(&korg1212->open_mutex);
return 1;
}
@@ -659,11 +614,9 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212)
K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n",
stateName[korg1212->cardState], korg1212->opencnt);
- mutex_lock(&korg1212->open_mutex);
- if (--(korg1212->opencnt)) {
- mutex_unlock(&korg1212->open_mutex);
+ guard(mutex)(&korg1212->open_mutex);
+ if (--(korg1212->opencnt))
return 0;
- }
if (korg1212->cardState == K1212_STATE_SETUP) {
int rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
@@ -671,10 +624,8 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212)
if (rc)
K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard - RC = %d [%s]\n",
rc, stateName[korg1212->cardState]);
- if (rc != K1212_CMDRET_Success) {
- mutex_unlock(&korg1212->open_mutex);
+ if (rc != K1212_CMDRET_Success)
return 0;
- }
} else if (korg1212->cardState > K1212_STATE_SETUP) {
snd_korg1212_SendStopAndWait(korg1212);
}
@@ -684,7 +635,6 @@ static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212)
snd_korg1212_setCardState(korg1212, K1212_STATE_READY);
}
- mutex_unlock(&korg1212->open_mutex);
return 0;
}
@@ -882,7 +832,6 @@ static int snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212)
u16 controlValue; // this keeps the current value to be written to
// the card's eeprom control register.
u16 count;
- unsigned long flags;
K1212_DEBUG_PRINTK("K1212_DEBUG: WriteADCSensivity [%s]\n",
stateName[korg1212->cardState]);
@@ -903,7 +852,7 @@ static int snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212)
} else
monModeSet = 0;
- spin_lock_irqsave(&korg1212->lock, flags);
+ guard(spinlock_irqsave)(&korg1212->lock);
// ----------------------------------------------------------------------------
// we are about to send new values to the card, so clear the new values queued
@@ -1012,8 +961,6 @@ static int snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212)
rc, stateName[korg1212->cardState]);
}
- spin_unlock_irqrestore(&korg1212->lock, flags);
-
return 1;
}
@@ -1105,7 +1052,7 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id)
if (!doorbellValue)
return IRQ_NONE;
- spin_lock(&korg1212->lock);
+ guard(spinlock)(&korg1212->lock);
writel(doorbellValue, korg1212->inDoorbellPtr);
@@ -1131,11 +1078,13 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id)
K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: IRQ DMAE count - %ld, %x, [%s].\n",
korg1212->irqcount, doorbellValue,
stateName[korg1212->cardState]);
- snd_printk(KERN_ERR "korg1212: DMA Error\n");
+ dev_err(korg1212->card->dev, "korg1212: DMA Error\n");
korg1212->errorcnt++;
korg1212->totalerrorcnt++;
korg1212->sharedBufferPtr->cardCommand = 0;
+ korg1212->dsp_stop_processing = 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_ERRORSTOP);
+ wake_up(&korg1212->wait);
break;
// ------------------------------------------------------------------------
@@ -1147,6 +1096,8 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id)
korg1212->irqcount, doorbellValue,
stateName[korg1212->cardState]);
korg1212->sharedBufferPtr->cardCommand = 0;
+ korg1212->dsp_stop_processing = 0;
+ wake_up(&korg1212->wait);
break;
default:
@@ -1179,8 +1130,6 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id)
korg1212->inIRQ--;
- spin_unlock(&korg1212->lock);
-
return IRQ_HANDLED;
}
@@ -1272,8 +1221,8 @@ static int snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int coun
#if K1212_DEBUG_LEVEL > 0
if ( (void *) dst < (void *) korg1212->playDataBufsPtr ||
(void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) {
- printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_silence KERNEL EFAULT dst=%p iter=%d\n",
- dst, i);
+ pr_debug("K1212_DEBUG: %s KERNEL EFAULT dst=%p iter=%d\n",
+ __func__, dst, i);
return -EFAULT;
}
#endif
@@ -1285,8 +1234,7 @@ static int snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int coun
}
static int snd_korg1212_copy_to(struct snd_pcm_substream *substream,
- void __user *dst, int pos, int count,
- bool in_kernel)
+ struct iov_iter *dst, int pos, int count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
@@ -1306,24 +1254,21 @@ static int snd_korg1212_copy_to(struct snd_pcm_substream *substream,
#if K1212_DEBUG_LEVEL > 0
if ( (void *) src < (void *) korg1212->recordDataBufsPtr ||
(void *) src > (void *) korg1212->recordDataBufsPtr[8].bufferData ) {
- printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_to KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i);
+ pr_debug("K1212_DEBUG: %s KERNEL EFAULT, src=%p dst=%p iter=%d\n",
+ __func__, src, dst->kvec.iov_base, i);
return -EFAULT;
}
#endif
- if (in_kernel)
- memcpy((__force void *)dst, src, size);
- else if (copy_to_user(dst, src, size))
+ if (copy_to_iter(src, size, dst) != size)
return -EFAULT;
src++;
- dst += size;
}
return 0;
}
static int snd_korg1212_copy_from(struct snd_pcm_substream *substream,
- void __user *src, int pos, int count,
- bool in_kernel)
+ struct iov_iter *src, int pos, int count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
@@ -1335,8 +1280,8 @@ static int snd_korg1212_copy_from(struct snd_pcm_substream *substream,
size = korg1212->channels * 2;
dst = korg1212->playDataBufsPtr[0].bufferData + pos;
- K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: snd_korg1212_copy_from pos=%d size=%d count=%d\n",
- pos, size, count);
+ K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: %s pos=%d size=%d count=%d\n",
+ __func__, pos, size, count);
if (snd_BUG_ON(pos + count > K1212_MAX_SAMPLES))
return -EINVAL;
@@ -1345,16 +1290,14 @@ static int snd_korg1212_copy_from(struct snd_pcm_substream *substream,
#if K1212_DEBUG_LEVEL > 0
if ( (void *) dst < (void *) korg1212->playDataBufsPtr ||
(void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) {
- printk(KERN_DEBUG "K1212_DEBUG: snd_korg1212_copy_from KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i);
+ pr_debug("K1212_DEBUG: %s KERNEL EFAULT, src=%p dst=%p iter=%d\n",
+ __func__, src->kvec.iov_base, dst, i);
return -EFAULT;
}
#endif
- if (in_kernel)
- memcpy(dst, (__force void *)src, size);
- else if (copy_from_user(dst, src, size))
+ if (copy_from_iter(dst, size, src) != size)
return -EFAULT;
dst++;
- src += size;
}
return 0;
@@ -1372,7 +1315,6 @@ static void snd_korg1212_free_pcm(struct snd_pcm *pcm)
static int snd_korg1212_playback_open(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1384,15 +1326,13 @@ static int snd_korg1212_playback_open(struct snd_pcm_substream *substream)
runtime->hw = snd_korg1212_playback_info;
snd_pcm_set_runtime_buffer(substream, korg1212->dma_play);
- spin_lock_irqsave(&korg1212->lock, flags);
-
- korg1212->playback_substream = substream;
- korg1212->playback_pid = current->pid;
- korg1212->periodsize = K1212_PERIODS;
- korg1212->channels = K1212_CHANNELS;
- korg1212->errorcnt = 0;
-
- spin_unlock_irqrestore(&korg1212->lock, flags);
+ scoped_guard(spinlock_irqsave, &korg1212->lock) {
+ korg1212->playback_substream = substream;
+ korg1212->playback_pid = current->pid;
+ korg1212->periodsize = K1212_PERIODS;
+ korg1212->channels = K1212_CHANNELS;
+ korg1212->errorcnt = 0;
+ }
snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
kPlayBufferFrames);
@@ -1403,7 +1343,6 @@ static int snd_korg1212_playback_open(struct snd_pcm_substream *substream)
static int snd_korg1212_capture_open(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1415,14 +1354,12 @@ static int snd_korg1212_capture_open(struct snd_pcm_substream *substream)
runtime->hw = snd_korg1212_capture_info;
snd_pcm_set_runtime_buffer(substream, korg1212->dma_rec);
- spin_lock_irqsave(&korg1212->lock, flags);
-
- korg1212->capture_substream = substream;
- korg1212->capture_pid = current->pid;
- korg1212->periodsize = K1212_PERIODS;
- korg1212->channels = K1212_CHANNELS;
-
- spin_unlock_irqrestore(&korg1212->lock, flags);
+ scoped_guard(spinlock_irqsave, &korg1212->lock) {
+ korg1212->capture_substream = substream;
+ korg1212->capture_pid = current->pid;
+ korg1212->periodsize = K1212_PERIODS;
+ korg1212->channels = K1212_CHANNELS;
+ }
snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
kPlayBufferFrames);
@@ -1431,7 +1368,6 @@ static int snd_korg1212_capture_open(struct snd_pcm_substream *substream)
static int snd_korg1212_playback_close(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_close [%s]\n",
@@ -1439,13 +1375,11 @@ static int snd_korg1212_playback_close(struct snd_pcm_substream *substream)
snd_korg1212_silence(korg1212, 0, K1212_MAX_SAMPLES, 0, korg1212->channels * 2);
- spin_lock_irqsave(&korg1212->lock, flags);
-
- korg1212->playback_pid = -1;
- korg1212->playback_substream = NULL;
- korg1212->periodsize = 0;
-
- spin_unlock_irqrestore(&korg1212->lock, flags);
+ scoped_guard(spinlock_irqsave, &korg1212->lock) {
+ korg1212->playback_pid = -1;
+ korg1212->playback_substream = NULL;
+ korg1212->periodsize = 0;
+ }
snd_korg1212_CloseCard(korg1212);
return 0;
@@ -1453,19 +1387,16 @@ static int snd_korg1212_playback_close(struct snd_pcm_substream *substream)
static int snd_korg1212_capture_close(struct snd_pcm_substream *substream)
{
- unsigned long flags;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_close [%s]\n",
stateName[korg1212->cardState]);
- spin_lock_irqsave(&korg1212->lock, flags);
-
- korg1212->capture_pid = -1;
- korg1212->capture_substream = NULL;
- korg1212->periodsize = 0;
-
- spin_unlock_irqrestore(&korg1212->lock, flags);
+ scoped_guard(spinlock_irqsave, &korg1212->lock) {
+ korg1212->capture_pid = -1;
+ korg1212->capture_substream = NULL;
+ korg1212->periodsize = 0;
+ }
snd_korg1212_CloseCard(korg1212);
return 0;
@@ -1491,7 +1422,6 @@ static int snd_korg1212_ioctl(struct snd_pcm_substream *substream,
static int snd_korg1212_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- unsigned long flags;
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
int err;
pid_t this_pid;
@@ -1500,7 +1430,7 @@ static int snd_korg1212_hw_params(struct snd_pcm_substream *substream,
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_hw_params [%s]\n",
stateName[korg1212->cardState]);
- spin_lock_irqsave(&korg1212->lock, flags);
+ guard(spinlock_irqsave)(&korg1212->lock);
if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
this_pid = korg1212->playback_pid;
@@ -1518,29 +1448,31 @@ static int snd_korg1212_hw_params(struct snd_pcm_substream *substream,
*/
if ((int)params_rate(params) != korg1212->clkRate) {
- spin_unlock_irqrestore(&korg1212->lock, flags);
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
return -EBUSY;
}
- spin_unlock_irqrestore(&korg1212->lock, flags);
return 0;
}
err = snd_korg1212_SetRate(korg1212, params_rate(params));
- if (err < 0) {
- spin_unlock_irqrestore(&korg1212->lock, flags);
+ if (err < 0)
return err;
- }
korg1212->channels = params_channels(params);
korg1212->periodsize = K1212_PERIOD_BYTES;
- spin_unlock_irqrestore(&korg1212->lock, flags);
-
return 0;
}
+static int snd_korg1212_sync_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
+
+ wait_event_timeout(korg1212->wait, !korg1212->dsp_stop_processing, HZ);
+ return 0;
+}
+
static int snd_korg1212_prepare(struct snd_pcm_substream *substream)
{
struct snd_korg1212 *korg1212 = snd_pcm_substream_chip(substream);
@@ -1549,27 +1481,13 @@ static int snd_korg1212_prepare(struct snd_pcm_substream *substream)
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare [%s]\n",
stateName[korg1212->cardState]);
- spin_lock_irq(&korg1212->lock);
-
- /* FIXME: we should wait for ack! */
- if (korg1212->stop_pending_cnt > 0) {
- K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare - Stop is pending... [%s]\n",
- stateName[korg1212->cardState]);
- spin_unlock_irq(&korg1212->lock);
- return -EAGAIN;
- /*
- korg1212->sharedBufferPtr->cardCommand = 0;
- del_timer(&korg1212->timer);
- korg1212->stop_pending_cnt = 0;
- */
- }
+ guard(spinlock_irq)(&korg1212->lock);
+ korg1212->dsp_stop_processing = 0;
rc = snd_korg1212_SetupForPlay(korg1212);
korg1212->currentBuffer = 0;
- spin_unlock_irq(&korg1212->lock);
-
return rc ? -EINVAL : 0;
}
@@ -1582,7 +1500,7 @@ static int snd_korg1212_trigger(struct snd_pcm_substream *substream,
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger [%s] cmd=%d\n",
stateName[korg1212->cardState], cmd);
- spin_lock(&korg1212->lock);
+ guard(spinlock)(&korg1212->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/*
@@ -1610,7 +1528,6 @@ static int snd_korg1212_trigger(struct snd_pcm_substream *substream,
rc = 1;
break;
}
- spin_unlock(&korg1212->lock);
return rc ? -EINVAL : 0;
}
@@ -1642,17 +1559,9 @@ static snd_pcm_uframes_t snd_korg1212_capture_pointer(struct snd_pcm_substream *
static int snd_korg1212_playback_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
-{
- return snd_korg1212_copy_from(substream, src, pos, count, false);
-}
-
-static int snd_korg1212_playback_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
- return snd_korg1212_copy_from(substream, (void __user *)src,
- pos, count, true);
+ return snd_korg1212_copy_from(substream, src, pos, count);
}
static int snd_korg1212_playback_silence(struct snd_pcm_substream *substream,
@@ -1670,17 +1579,9 @@ static int snd_korg1212_playback_silence(struct snd_pcm_substream *substream,
static int snd_korg1212_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
-{
- return snd_korg1212_copy_to(substream, dst, pos, count, false);
-}
-
-static int snd_korg1212_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
- return snd_korg1212_copy_to(substream, (void __user *)dst,
- pos, count, true);
+ return snd_korg1212_copy_to(substream, dst, pos, count);
}
static const struct snd_pcm_ops snd_korg1212_playback_ops = {
@@ -1690,9 +1591,9 @@ static const struct snd_pcm_ops snd_korg1212_playback_ops = {
.hw_params = snd_korg1212_hw_params,
.prepare = snd_korg1212_prepare,
.trigger = snd_korg1212_trigger,
+ .sync_stop = snd_korg1212_sync_stop,
.pointer = snd_korg1212_playback_pointer,
- .copy_user = snd_korg1212_playback_copy,
- .copy_kernel = snd_korg1212_playback_copy_kernel,
+ .copy = snd_korg1212_playback_copy,
.fill_silence = snd_korg1212_playback_silence,
};
@@ -1703,9 +1604,9 @@ static const struct snd_pcm_ops snd_korg1212_capture_ops = {
.hw_params = snd_korg1212_hw_params,
.prepare = snd_korg1212_prepare,
.trigger = snd_korg1212_trigger,
+ .sync_stop = snd_korg1212_sync_stop,
.pointer = snd_korg1212_capture_pointer,
- .copy_user = snd_korg1212_capture_copy,
- .copy_kernel = snd_korg1212_capture_copy_kernel,
+ .copy = snd_korg1212_capture_copy,
};
/*
@@ -1726,15 +1627,13 @@ static int snd_korg1212_control_phase_get(struct snd_kcontrol *kcontrol,
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
int i = kcontrol->private_value;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
u->value.integer.value[0] = korg1212->volumePhase[i];
if (i >= 8)
u->value.integer.value[1] = korg1212->volumePhase[i+1];
- spin_unlock_irq(&korg1212->lock);
-
return 0;
}
@@ -1745,7 +1644,7 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol,
int change = 0;
int i, val;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
i = kcontrol->private_value;
@@ -1771,8 +1670,6 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol,
}
}
- spin_unlock_irq(&korg1212->lock);
-
return change;
}
@@ -1792,7 +1689,7 @@ static int snd_korg1212_control_volume_get(struct snd_kcontrol *kcontrol,
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
int i;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
i = kcontrol->private_value;
u->value.integer.value[0] = abs(korg1212->sharedBufferPtr->volumeData[i]);
@@ -1800,8 +1697,6 @@ static int snd_korg1212_control_volume_get(struct snd_kcontrol *kcontrol,
if (i >= 8)
u->value.integer.value[1] = abs(korg1212->sharedBufferPtr->volumeData[i+1]);
- spin_unlock_irq(&korg1212->lock);
-
return 0;
}
@@ -1813,7 +1708,7 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol,
int i;
int val;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
i = kcontrol->private_value;
@@ -1839,8 +1734,6 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol,
}
}
- spin_unlock_irq(&korg1212->lock);
-
return change;
}
@@ -1858,7 +1751,7 @@ static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol,
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
int i;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
i = kcontrol->private_value;
u->value.enumerated.item[0] = korg1212->sharedBufferPtr->routeData[i];
@@ -1866,8 +1759,6 @@ static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol,
if (i >= 8)
u->value.enumerated.item[1] = korg1212->sharedBufferPtr->routeData[i+1];
- spin_unlock_irq(&korg1212->lock);
-
return 0;
}
@@ -1877,7 +1768,7 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol,
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
int change = 0, i;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
i = kcontrol->private_value;
@@ -1897,8 +1788,6 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol,
}
}
- spin_unlock_irq(&korg1212->lock);
-
return change;
}
@@ -1917,13 +1806,11 @@ static int snd_korg1212_control_get(struct snd_kcontrol *kcontrol,
{
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
u->value.integer.value[0] = korg1212->leftADCInSens;
u->value.integer.value[1] = korg1212->rightADCInSens;
- spin_unlock_irq(&korg1212->lock);
-
return 0;
}
@@ -1933,22 +1820,20 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol,
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
int change = 0;
- spin_lock_irq(&korg1212->lock);
-
- if (u->value.integer.value[0] >= k1212MinADCSens &&
- u->value.integer.value[0] <= k1212MaxADCSens &&
- u->value.integer.value[0] != korg1212->leftADCInSens) {
- korg1212->leftADCInSens = u->value.integer.value[0];
- change = 1;
- }
- if (u->value.integer.value[1] >= k1212MinADCSens &&
- u->value.integer.value[1] <= k1212MaxADCSens &&
- u->value.integer.value[1] != korg1212->rightADCInSens) {
- korg1212->rightADCInSens = u->value.integer.value[1];
- change = 1;
- }
-
- spin_unlock_irq(&korg1212->lock);
+ scoped_guard(spinlock_irq, &korg1212->lock) {
+ if (u->value.integer.value[0] >= k1212MinADCSens &&
+ u->value.integer.value[0] <= k1212MaxADCSens &&
+ u->value.integer.value[0] != korg1212->leftADCInSens) {
+ korg1212->leftADCInSens = u->value.integer.value[0];
+ change = 1;
+ }
+ if (u->value.integer.value[1] >= k1212MinADCSens &&
+ u->value.integer.value[1] <= k1212MaxADCSens &&
+ u->value.integer.value[1] != korg1212->rightADCInSens) {
+ korg1212->rightADCInSens = u->value.integer.value[1];
+ change = 1;
+ }
+ }
if (change)
snd_korg1212_WriteADCSensitivity(korg1212);
@@ -1967,11 +1852,9 @@ static int snd_korg1212_control_sync_get(struct snd_kcontrol *kcontrol,
{
struct snd_korg1212 *korg1212 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
ucontrol->value.enumerated.item[0] = korg1212->clkSource;
-
- spin_unlock_irq(&korg1212->lock);
return 0;
}
@@ -1983,10 +1866,9 @@ static int snd_korg1212_control_sync_put(struct snd_kcontrol *kcontrol,
int change;
val = ucontrol->value.enumerated.item[0] % 3;
- spin_lock_irq(&korg1212->lock);
+ guard(spinlock_irq)(&korg1212->lock);
change = val != korg1212->clkSource;
snd_korg1212_SetClockSource(korg1212, val);
- spin_unlock_irq(&korg1212->lock);
return change;
}
@@ -2110,7 +1992,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
init_waitqueue_head(&korg1212->wait);
spin_lock_init(&korg1212->lock);
mutex_init(&korg1212->open_mutex);
- timer_setup(&korg1212->timer, snd_korg1212_timer_func, 0);
korg1212->irq = -1;
korg1212->clkSource = K1212_CLKIDX_Local;
@@ -2132,7 +2013,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
for (i=0; i<kAudioChannels; i++)
korg1212->volumePhase[i] = 0;
- err = pcim_iomap_regions_request_all(pci, 1 << 0, "korg1212");
+ err = pcim_request_all_regions(pci, "korg1212");
if (err < 0)
return err;
@@ -2154,14 +2035,16 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
korg1212->iomem2, iomem2_size,
stateName[korg1212->cardState]);
- korg1212->iobase = pcim_iomap_table(pci)[0];
+ korg1212->iobase = pcim_iomap(pci, 0, 0);
+ if (!korg1212->iobase)
+ return -ENOMEM;
err = devm_request_irq(&pci->dev, pci->irq, snd_korg1212_interrupt,
IRQF_SHARED,
KBUILD_MODNAME, korg1212);
if (err) {
- snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq);
+ dev_err(&pci->dev, "korg1212: unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
@@ -2258,7 +2141,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev);
if (err < 0) {
- snd_printk(KERN_ERR "firmware not available\n");
+ dev_err(&pci->dev, "firmware not available\n");
return err;
}
@@ -2308,7 +2191,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
korg1212->pcm->private_data = korg1212;
korg1212->pcm->private_free = snd_korg1212_free_pcm;
- strcpy(korg1212->pcm->name, "korg1212");
+ strscpy(korg1212->pcm->name, "korg1212");
snd_pcm_set_ops(korg1212->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_korg1212_playback_ops);
@@ -2357,8 +2240,8 @@ snd_korg1212_probe(struct pci_dev *pci,
if (err < 0)
goto error;
- strcpy(card->driver, "korg1212");
- strcpy(card->shortname, "korg1212");
+ strscpy(card->driver, "korg1212");
+ strscpy(card->shortname, "korg1212");
sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname,
korg1212->iomem, korg1212->irq);
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 1aa30e90b86a..34a3ba17deb4 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -74,7 +74,6 @@ static int corb_send_verb(struct lola *chip, unsigned int nid,
unsigned int verb, unsigned int data,
unsigned int extdata)
{
- unsigned long flags;
int ret = -EIO;
chip->last_cmd_nid = nid;
@@ -83,7 +82,7 @@ static int corb_send_verb(struct lola *chip, unsigned int nid,
chip->last_extdata = extdata;
data |= (nid << 20) | (verb << 8);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) {
unsigned int wp = chip->corb.wp + 1;
wp %= LOLA_CORB_ENTRIES;
@@ -95,7 +94,6 @@ static int corb_send_verb(struct lola *chip, unsigned int nid,
smp_wmb();
ret = 0;
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return ret;
}
@@ -541,6 +539,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci, int dev)
struct lola *chip = card->private_data;
int err;
unsigned int dever;
+ void __iomem *iomem;
err = pcim_enable_device(pci);
if (err < 0)
@@ -580,14 +579,19 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci, int dev)
chip->sample_rate_min = 16000;
}
- err = pcim_iomap_regions(pci, (1 << 0) | (1 << 2), DRVNAME);
- if (err < 0)
- return err;
+ iomem = pcim_iomap_region(pci, 0, DRVNAME);
+ if (IS_ERR(iomem))
+ return PTR_ERR(iomem);
+ chip->bar[0].remap_addr = iomem;
chip->bar[0].addr = pci_resource_start(pci, 0);
- chip->bar[0].remap_addr = pcim_iomap_table(pci)[0];
+
+ iomem = pcim_iomap_region(pci, 2, DRVNAME);
+ if (IS_ERR(iomem))
+ return PTR_ERR(iomem);
+
+ chip->bar[1].remap_addr = iomem;
chip->bar[1].addr = pci_resource_start(pci, 2);
- chip->bar[1].remap_addr = pcim_iomap_table(pci)[2];
pci_set_master(pci);
@@ -624,12 +628,12 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci, int dev)
if (err < 0)
return err;
- strcpy(card->driver, "Lola");
+ strscpy(card->driver, "Lola");
strscpy(card->shortname, "Digigram Lola", sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
"%s at 0x%lx irq %i",
card->shortname, chip->bar[0].addr, chip->irq);
- strcpy(card->mixername, card->shortname);
+ strscpy(card->mixername, card->shortname);
lola_irq_enable(chip);
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/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index 32193fae978d..6c046ecd6e08 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -214,11 +214,9 @@ static int lola_pcm_open(struct snd_pcm_substream *substream)
struct lola_stream *str = lola_get_stream(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- mutex_lock(&chip->open_mutex);
- if (str->opened) {
- mutex_unlock(&chip->open_mutex);
+ guard(mutex)(&chip->open_mutex);
+ if (str->opened)
return -EBUSY;
- }
str->substream = substream;
str->master = NULL;
str->opened = 1;
@@ -239,7 +237,6 @@ static int lola_pcm_open(struct snd_pcm_substream *substream)
chip->granularity);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
chip->granularity);
- mutex_unlock(&chip->open_mutex);
return 0;
}
@@ -261,7 +258,7 @@ static int lola_pcm_close(struct snd_pcm_substream *substream)
struct lola *chip = snd_pcm_substream_chip(substream);
struct lola_stream *str = lola_get_stream(substream);
- mutex_lock(&chip->open_mutex);
+ guard(mutex)(&chip->open_mutex);
if (str->substream == substream) {
str->substream = NULL;
str->opened = 0;
@@ -270,7 +267,6 @@ static int lola_pcm_close(struct snd_pcm_substream *substream)
/* release sample rate */
chip->sample_rate = 0;
}
- mutex_unlock(&chip->open_mutex);
return 0;
}
@@ -291,10 +287,9 @@ static int lola_pcm_hw_free(struct snd_pcm_substream *substream)
struct lola_pcm *pcm = lola_get_pcm(substream);
struct lola_stream *str = lola_get_stream(substream);
- mutex_lock(&chip->open_mutex);
+ guard(mutex)(&chip->open_mutex);
lola_stream_reset(chip, str);
lola_cleanup_slave_streams(pcm, str);
- mutex_unlock(&chip->open_mutex);
return 0;
}
@@ -457,18 +452,16 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream)
unsigned int bufsize, period_bytes, format_verb;
int i, err;
- mutex_lock(&chip->open_mutex);
- lola_stream_reset(chip, str);
- lola_cleanup_slave_streams(pcm, str);
- if (str->index + runtime->channels > pcm->num_streams) {
- mutex_unlock(&chip->open_mutex);
- return -EINVAL;
- }
- for (i = 1; i < runtime->channels; i++) {
- str[i].master = str;
- str[i].opened = 1;
+ scoped_guard(mutex, &chip->open_mutex) {
+ lola_stream_reset(chip, str);
+ lola_cleanup_slave_streams(pcm, str);
+ if (str->index + runtime->channels > pcm->num_streams)
+ return -EINVAL;
+ for (i = 1; i < runtime->channels; i++) {
+ str[i].master = str;
+ str[i].opened = 1;
+ }
}
- mutex_unlock(&chip->open_mutex);
bufsize = snd_pcm_lib_buffer_bytes(substream);
period_bytes = snd_pcm_lib_period_bytes(substream);
@@ -530,7 +523,7 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
*/
sync_streams = (start && snd_pcm_stream_linked(substream));
tstamp = lola_get_tstamp(chip, !sync_streams);
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
snd_pcm_group_for_each_entry(s, substream) {
if (s->pcm->card != substream->pcm->card)
continue;
@@ -543,7 +536,6 @@ static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
str->paused = !start;
snd_pcm_trigger_done(s, substream);
}
- spin_unlock(&chip->reg_lock);
return 0;
}
diff --git a/sound/pci/lx6464es/Makefile b/sound/pci/lx6464es/Makefile
index c295f68bac68..2b3047c7a388 100644
--- a/sound/pci/lx6464es/Makefile
+++ b/sound/pci/lx6464es/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-lx6464es-objs := lx6464es.o lx_core.o
+snd-lx6464es-y := lx6464es.o lx_core.o
obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index bd9b6148dd6f..96df00db51d5 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -207,7 +207,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
int board_rate;
dev_dbg(chip->card->dev, "->lx_pcm_open\n");
- mutex_lock(&chip->setup_mutex);
+ guard(mutex)(&chip->setup_mutex);
/* copy the struct snd_pcm_hardware struct */
runtime->hw = lx_caps;
@@ -218,7 +218,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0) {
dev_warn(chip->card->dev, "could not constrain periods\n");
- goto exit;
+ return err;
}
#endif
@@ -229,7 +229,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
if (err < 0) {
dev_warn(chip->card->dev, "could not constrain periods\n");
- goto exit;
+ return err;
}
/* constrain period size */
@@ -240,7 +240,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
if (err < 0) {
dev_warn(chip->card->dev,
"could not constrain period size\n");
- goto exit;
+ return err;
}
snd_pcm_hw_constraint_step(runtime, 0,
@@ -249,10 +249,8 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
err = 0;
-exit:
runtime->private_data = chip;
- mutex_unlock(&chip->setup_mutex);
dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err);
return err;
}
@@ -275,9 +273,8 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n");
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
pos = lx_stream->frame_pos * substream->runtime->period_size;
- mutex_unlock(&chip->lock);
dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos);
return pos;
@@ -291,21 +288,21 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream)
dev_dbg(chip->card->dev, "->lx_pcm_prepare\n");
- mutex_lock(&chip->setup_mutex);
+ guard(mutex)(&chip->setup_mutex);
if (chip->hardware_running[is_capture]) {
err = lx_hardware_stop(chip, substream);
if (err < 0) {
dev_err(chip->card->dev, "failed to stop hardware. "
"Error code %d\n", err);
- goto exit;
+ return err;
}
err = lx_hardware_close(chip, substream);
if (err < 0) {
dev_err(chip->card->dev, "failed to close hardware. "
"Error code %d\n", err);
- goto exit;
+ return err;
}
}
@@ -314,14 +311,14 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream)
if (err < 0) {
dev_err(chip->card->dev, "failed to open hardware. "
"Error code %d\n", err);
- goto exit;
+ return err;
}
err = lx_hardware_start(chip, substream);
if (err < 0) {
dev_err(chip->card->dev, "failed to start hardware. "
"Error code %d\n", err);
- goto exit;
+ return err;
}
chip->hardware_running[is_capture] = 1;
@@ -331,8 +328,6 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream)
chip->board_sample_rate = substream->runtime->rate;
}
-exit:
- mutex_unlock(&chip->setup_mutex);
return err;
}
@@ -343,14 +338,13 @@ static int lx_pcm_hw_params(struct snd_pcm_substream *substream,
dev_dbg(chip->card->dev, "->lx_pcm_hw_params\n");
- mutex_lock(&chip->setup_mutex);
+ guard(mutex)(&chip->setup_mutex);
if (is_capture)
chip->capture_stream.stream = substream;
else
chip->playback_stream.stream = substream;
- mutex_unlock(&chip->setup_mutex);
return 0;
}
@@ -373,21 +367,21 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n");
- mutex_lock(&chip->setup_mutex);
+ guard(mutex)(&chip->setup_mutex);
if (chip->hardware_running[is_capture]) {
err = lx_hardware_stop(chip, substream);
if (err < 0) {
dev_err(chip->card->dev, "failed to stop hardware. "
"Error code %d\n", err);
- goto exit;
+ return err;
}
err = lx_hardware_close(chip, substream);
if (err < 0) {
dev_err(chip->card->dev, "failed to close hardware. "
"Error code %d\n", err);
- goto exit;
+ return err;
}
chip->hardware_running[is_capture] = 0;
@@ -398,9 +392,7 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
else
chip->playback_stream.stream = NULL;
-exit:
- mutex_unlock(&chip->setup_mutex);
- return err;
+ return 0;
}
static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
@@ -486,9 +478,7 @@ static void lx_trigger_dispatch_stream(struct lx6464es *chip,
static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
struct lx_stream *lx_stream, int cmd)
{
- int err = 0;
-
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN;
@@ -499,16 +489,13 @@ static int lx_pcm_trigger_dispatch(struct lx6464es *chip,
break;
default:
- err = -EINVAL;
- goto exit;
+ return -EINVAL;
}
lx_trigger_dispatch_stream(chip, &chip->capture_stream);
lx_trigger_dispatch_stream(chip, &chip->playback_stream);
-exit:
- mutex_unlock(&chip->lock);
- return err;
+ return 0;
}
@@ -814,7 +801,7 @@ static int lx_pcm_create(struct lx6464es *chip)
pcm->info_flags = 0;
pcm->nonatomic = true;
- strcpy(pcm->name, card_name);
+ strscpy(pcm->name, card_name);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pci->dev, size, size);
@@ -944,7 +931,7 @@ static int snd_lx6464es_create(struct snd_card *card,
mutex_init(&chip->setup_mutex);
/* request resources */
- err = pci_request_regions(pci, card_name);
+ err = pcim_request_all_regions(pci, card_name);
if (err < 0)
return err;
@@ -1022,7 +1009,7 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
goto error;
}
- strcpy(card->driver, "LX6464ES");
+ strscpy(card->driver, "LX6464ES");
sprintf(card->id, "LX6464ES_%02X%02X%02X",
chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index b5b0d43bb8dc..6f0843cfb3be 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -231,14 +231,14 @@ static void lx_message_dump(struct lx_rmh *rmh)
u8 idx = rmh->cmd_idx;
int i;
- snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName);
+ pr_debug(LXRMH "command %s\n", dsp_commands[idx].dcOpName);
for (i = 0; i != rmh->cmd_len; ++i)
- snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]);
+ pr_debug(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]);
for (i = 0; i != rmh->stat_len; ++i)
- snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]);
- snd_printk("\n");
+ pr_debug(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]);
+ pr_debug("\n");
}
#else
static inline void lx_message_dump(struct lx_rmh *rmh)
@@ -316,26 +316,25 @@ polling_successful:
/* low-level dsp access */
int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version)
{
- u16 ret;
+ int ret;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
ret = lx_message_send_atomic(chip, &chip->rmh);
*rdsp_version = chip->rmh.stat[1];
- mutex_unlock(&chip->msg_lock);
return ret;
}
int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
{
- u16 ret = 0;
u32 freq_raw = 0;
u32 freq = 0;
u32 frequency = 0;
+ int ret;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG);
ret = lx_message_send_atomic(chip, &chip->rmh);
@@ -353,8 +352,6 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
frequency = 48000;
}
- mutex_unlock(&chip->msg_lock);
-
*rfreq = frequency * chip->freq_ratio;
return ret;
@@ -381,23 +378,19 @@ int lx_dsp_get_mac(struct lx6464es *chip)
int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran)
{
- int ret;
-
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY);
chip->rmh.cmd[0] |= gran;
- ret = lx_message_send_atomic(chip, &chip->rmh);
- mutex_unlock(&chip->msg_lock);
- return ret;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
{
int ret;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_04_GET_EVENT);
chip->rmh.stat_len = 9; /* we don't necessarily need the full length */
@@ -407,7 +400,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
if (!ret)
memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32));
- mutex_unlock(&chip->msg_lock);
return ret;
}
@@ -423,14 +415,13 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE);
chip->rmh.cmd[0] |= pipe_cmd;
chip->rmh.cmd[0] |= channels;
err = lx_message_send_atomic(chip, &chip->rmh);
- mutex_unlock(&chip->msg_lock);
if (err != 0)
dev_err(chip->card->dev, "could not allocate pipe\n");
@@ -440,18 +431,14 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture)
{
- int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE);
chip->rmh.cmd[0] |= pipe_cmd;
- err = lx_message_send_atomic(chip, &chip->rmh);
- mutex_unlock(&chip->msg_lock);
-
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
@@ -468,7 +455,7 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
*r_needed = 0;
*r_freed = 0;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -501,41 +488,32 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
}
}
- mutex_unlock(&chip->msg_lock);
return err;
}
int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture)
{
- int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_09_STOP_PIPE);
chip->rmh.cmd[0] |= pipe_cmd;
- err = lx_message_send_atomic(chip, &chip->rmh);
-
- mutex_unlock(&chip->msg_lock);
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture)
{
- int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE);
chip->rmh.cmd[0] |= pipe_cmd;
- err = lx_message_send_atomic(chip, &chip->rmh);
-
- mutex_unlock(&chip->msg_lock);
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
@@ -572,7 +550,7 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -589,7 +567,6 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
+ chip->rmh.stat[1]; /* lo part */
}
- mutex_unlock(&chip->msg_lock);
return err;
}
@@ -598,7 +575,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -610,7 +587,6 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
else
*rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
- mutex_unlock(&chip->msg_lock);
return err;
}
@@ -651,29 +627,24 @@ int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture)
int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
int is_capture, enum stream_state_t state)
{
- int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE);
chip->rmh.cmd[0] |= pipe_cmd;
chip->rmh.cmd[0] |= state;
- err = lx_message_send_atomic(chip, &chip->rmh);
- mutex_unlock(&chip->msg_lock);
-
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
u32 pipe, int is_capture)
{
- int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
u32 channels = runtime->channels;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -688,10 +659,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
chip->rmh.cmd[0] |= channels-1;
- err = lx_message_send_atomic(chip, &chip->rmh);
- mutex_unlock(&chip->msg_lock);
-
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
@@ -700,7 +668,7 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -709,7 +677,6 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture,
*rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE;
- mutex_unlock(&chip->msg_lock);
return err;
}
@@ -719,7 +686,7 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -730,7 +697,6 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture,
<< 32) /* hi part */
+ chip->rmh.stat[1]; /* lo part */
- mutex_unlock(&chip->msg_lock);
return err;
}
@@ -742,7 +708,7 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -763,7 +729,7 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
if (err == 0) {
*r_buffer_index = chip->rmh.stat[0];
- goto done;
+ return err;
}
if (err == EB_RBUFFERS_TABLE_OVERFLOW)
@@ -778,8 +744,6 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
dev_err(chip->card->dev,
"lx_buffer_give EB_CMD_REFUSED\n");
- done:
- mutex_unlock(&chip->msg_lock);
return err;
}
@@ -789,7 +753,7 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
chip->rmh.cmd[0] |= pipe_cmd;
@@ -801,26 +765,21 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture,
if (err == 0)
*r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE;
- mutex_unlock(&chip->msg_lock);
return err;
}
int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
u32 buffer_index)
{
- int err;
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER);
chip->rmh.cmd[0] |= pipe_cmd;
chip->rmh.cmd[0] |= buffer_index;
- err = lx_message_send_atomic(chip, &chip->rmh);
-
- mutex_unlock(&chip->msg_lock);
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
@@ -831,11 +790,10 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture,
* */
int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
{
- int err;
/* bit set to 1: channel muted */
u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
lx_message_init(&chip->rmh, CMD_0D_SET_MUTE);
chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0);
@@ -847,10 +805,7 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
"mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
chip->rmh.cmd[2]);
- err = lx_message_send_atomic(chip, &chip->rmh);
-
- mutex_unlock(&chip->msg_lock);
- return err;
+ return lx_message_send_atomic(chip, &chip->rmh);
}
static const u32 peak_map[] = {
@@ -878,7 +833,7 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
int err = 0;
int i;
- mutex_lock(&chip->msg_lock);
+ guard(mutex)(&chip->msg_lock);
for (i = 0; i < channels; i += 4) {
u32 s0, s1, s2, s3;
@@ -903,7 +858,6 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels,
r_levels += 4;
}
- mutex_unlock(&chip->msg_lock);
return err;
}
@@ -1033,7 +987,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n");
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
dev_dbg(chip->card->dev,
@@ -1047,7 +1001,6 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
buffer_index, (unsigned long)buf, period_bytes);
lx_stream->frame_pos = next_pos;
- mutex_unlock(&chip->lock);
return err;
}
diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h
index 296013c910b7..c1113439f7c9 100644
--- a/sound/pci/lx6464es/lx_core.h
+++ b/sound/pci/lx6464es/lx_core.h
@@ -129,21 +129,18 @@ int lx_stream_set_state(struct lx6464es *chip, u32 pipe,
static inline int lx_stream_start(struct lx6464es *chip, u32 pipe,
int is_capture)
{
- snd_printdd("->lx_stream_start\n");
return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN);
}
static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe,
int is_capture)
{
- snd_printdd("->lx_stream_pause\n");
return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE);
}
static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe,
int is_capture)
{
- snd_printdd("->lx_stream_stop\n");
return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP);
}
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 261850775c80..3353980d5cd8 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -769,9 +769,7 @@ struct snd_m3 {
unsigned int in_suspend;
-#ifdef CONFIG_PM_SLEEP
u16 *suspend_mem;
-#endif
const struct firmware *assp_kernel_image;
const struct firmware *assp_minisrc_image;
@@ -1098,7 +1096,7 @@ snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
if (snd_BUG_ON(!s))
return -ENXIO;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -1119,7 +1117,6 @@ snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
}
break;
}
- spin_unlock(&chip->reg_lock);
return err;
}
@@ -1414,7 +1411,7 @@ snd_m3_pcm_prepare(struct snd_pcm_substream *subs)
runtime->rate < 8000)
return -EINVAL;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_m3_pcm_setup1(chip, s, subs);
@@ -1425,8 +1422,6 @@ snd_m3_pcm_prepare(struct snd_pcm_substream *subs)
snd_m3_pcm_setup2(chip, s, runtime);
- spin_unlock_irq(&chip->reg_lock);
-
return 0;
}
@@ -1468,9 +1463,8 @@ snd_m3_pcm_pointer(struct snd_pcm_substream *subs)
if (snd_BUG_ON(!s))
return 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
ptr = snd_m3_get_pointer(chip, s, subs);
- spin_unlock(&chip->reg_lock);
return bytes_to_frames(subs->runtime, ptr);
}
@@ -1631,13 +1625,12 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
if (ctl & DSP2HOST_REQ_TIMER) {
outb(DSP2HOST_REQ_TIMER, chip->iobase + ASSP_HOST_INT_STATUS);
/* update adc/dac info if it was a timer int */
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
for (i = 0; i < chip->num_substreams; i++) {
struct m3_dma *s = &chip->substreams[i];
if (s->running)
snd_m3_update_ptr(chip, s);
}
- spin_unlock(&chip->reg_lock);
}
}
}
@@ -1709,18 +1702,16 @@ snd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs)
int i;
struct m3_dma *s;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
for (i = 0; i < chip->num_substreams; i++) {
s = &chip->substreams[i];
if (! s->opened)
goto __found;
}
- spin_unlock_irq(&chip->reg_lock);
return -ENOMEM;
__found:
s->opened = 1;
s->running = 0;
- spin_unlock_irq(&chip->reg_lock);
subs->runtime->private_data = s;
s->substream = subs;
@@ -1744,7 +1735,7 @@ snd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs)
if (s == NULL)
return; /* not opened properly */
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
if (s->substream && s->running)
snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */
if (s->in_lists) {
@@ -1755,7 +1746,6 @@ snd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs)
}
s->running = 0;
s->opened = 0;
- spin_unlock_irq(&chip->reg_lock);
}
static int
@@ -1848,7 +1838,7 @@ snd_m3_pcm(struct snd_m3 * chip, int device)
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, chip->card->driver);
+ strscpy(pcm->name, chip->card->driver);
chip->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -2029,9 +2019,6 @@ static int snd_m3_mixer(struct snd_m3 *chip)
{
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- struct snd_ctl_elem_id elem_id;
-#endif
int err;
static const struct snd_ac97_bus_ops ops = {
.write = snd_m3_ac97_write,
@@ -2054,14 +2041,10 @@ static int snd_m3_mixer(struct snd_m3 *chip)
snd_ac97_write(chip->ac97, AC97_PCM, 0);
#ifndef CONFIG_SND_MAESTRO3_INPUT
- memset(&elem_id, 0, sizeof(elem_id));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(elem_id.name, "Master Playback Switch");
- chip->master_switch = snd_ctl_find_id(chip->card, &elem_id);
- memset(&elem_id, 0, sizeof(elem_id));
- elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(elem_id.name, "Master Playback Volume");
- chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
+ chip->master_switch = snd_ctl_find_id_mixer(chip->card,
+ "Master Playback Switch");
+ chip->master_volume = snd_ctl_find_id_mixer(chip->card,
+ "Master Playback Volume");
#endif
return 0;
@@ -2348,22 +2331,19 @@ static void snd_m3_free(struct snd_card *card)
cancel_work_sync(&chip->hwvol_work);
if (chip->substreams) {
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
for (i = 0; i < chip->num_substreams; i++) {
s = &chip->substreams[i];
/* check surviving pcms; this should not happen though.. */
if (s->substream && s->running)
snd_m3_pcm_stop(chip, s, s->substream);
}
- spin_unlock_irq(&chip->reg_lock);
}
if (chip->iobase) {
outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
}
-#ifdef CONFIG_PM_SLEEP
vfree(chip->suspend_mem);
-#endif
release_firmware(chip->assp_kernel_image);
release_firmware(chip->assp_minisrc_image);
}
@@ -2372,7 +2352,6 @@ static void snd_m3_free(struct snd_card *card)
/*
* APM support
*/
-#ifdef CONFIG_PM_SLEEP
static int m3_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -2446,11 +2425,7 @@ static int m3_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
-#define M3_PM_OPS &m3_pm
-#else
-#define M3_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
#ifdef CONFIG_SND_MAESTRO3_INPUT
static int snd_m3_input_register(struct snd_m3 *chip)
@@ -2568,7 +2543,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
if (err < 0)
return err;
- err = pci_request_regions(pci, card->driver);
+ err = pcim_request_all_regions(pci, card->driver);
if (err < 0)
return err;
@@ -2594,14 +2569,14 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
chip->irq = pci->irq;
card->sync_irq = chip->irq;
-#ifdef CONFIG_PM_SLEEP
- chip->suspend_mem =
- vmalloc(array_size(sizeof(u16),
- REV_B_CODE_MEMORY_LENGTH +
- REV_B_DATA_MEMORY_LENGTH));
- if (chip->suspend_mem == NULL)
- dev_warn(card->dev, "can't allocate apm buffer\n");
-#endif
+ if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+ chip->suspend_mem =
+ vmalloc_array(REV_B_CODE_MEMORY_LENGTH +
+ REV_B_DATA_MEMORY_LENGTH,
+ sizeof(u16));
+ if (!chip->suspend_mem)
+ dev_warn(card->dev, "can't allocate apm buffer\n");
+ }
err = snd_m3_mixer(chip);
if (err < 0)
@@ -2664,14 +2639,14 @@ __snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
switch (pci->device) {
case PCI_DEVICE_ID_ESS_ALLEGRO:
case PCI_DEVICE_ID_ESS_ALLEGRO_1:
- strcpy(card->driver, "Allegro");
+ strscpy(card->driver, "Allegro");
break;
case PCI_DEVICE_ID_ESS_CANYON3D_2LE:
case PCI_DEVICE_ID_ESS_CANYON3D_2:
- strcpy(card->driver, "Canyon3D-2");
+ strscpy(card->driver, "Canyon3D-2");
break;
default:
- strcpy(card->driver, "Maestro3");
+ strscpy(card->driver, "Maestro3");
break;
}
@@ -2713,7 +2688,7 @@ static struct pci_driver m3_driver = {
.id_table = snd_m3_ids,
.probe = snd_m3_probe,
.driver = {
- .pm = M3_PM_OPS,
+ .pm = &m3_pm,
},
};
diff --git a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile
index 16cfeb78a0b6..b803e5e72791 100644
--- a/sound/pci/mixart/Makefile
+++ b/sound/pci/mixart/Makefile
@@ -4,6 +4,6 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
+snd-mixart-y := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
obj-$(CONFIG_SND_MIXART) += snd-mixart.o
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 1b078b789604..c6319e75beab 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -98,7 +98,7 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
memset(&group_state, 0, sizeof(group_state));
group_state.pipe_count = 1;
- group_state.pipe_uid[0] = pipe->group_uid;
+ group_state.pipe_uid = pipe->group_uid;
if(start)
request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET;
@@ -185,7 +185,7 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
clock_properties.clock_mode = CM_STANDALONE;
clock_properties.frequency = rate;
clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
- clock_properties.uid_caller[0] = pipe->group_uid;
+ clock_properties.uid_caller = pipe->group_uid;
dev_dbg(&mgr->pci->dev, "mixart_set_clock to %d kHz\n", rate);
@@ -565,8 +565,8 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form
stream_param.pipe_count = 1; /* set to 1 */
stream_param.stream_count = 1; /* set to 1 */
- stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid;
- stream_param.stream_desc[0].stream_idx = stream->substream->number;
+ stream_param.stream_desc.uid_pipe = stream->pipe->group_uid;
+ stream_param.stream_desc.stream_idx = stream->substream->number;
request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM;
request.uid = (struct mixart_uid){0,0};
@@ -603,7 +603,7 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
/* set up format for the stream */
format = params_format(hw);
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
/* update the stream levels */
if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
@@ -618,10 +618,8 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
/* set the format to the board */
err = mixart_set_format(stream, format);
- if(err < 0) {
- mutex_unlock(&mgr->setup_mutex);
+ if (err < 0)
return err;
- }
if (subs->runtime->buffer_changed) {
struct mixart_bufferinfo *bufferinfo;
@@ -641,7 +639,6 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
bufferinfo[i].available_length,
subs->number);
}
- mutex_unlock(&mgr->setup_mutex);
return 0;
}
@@ -712,7 +709,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
int err = 0;
int pcm_number;
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
if ( pcm == chip->pcm ) {
pcm_number = MIXART_PCM_ANALOG;
@@ -734,25 +731,21 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
dev_err(chip->card->dev,
"snd_mixart_playback_open C%d/P%d/Sub%d in use\n",
chip->chip_idx, pcm_number, subs->number);
- err = -EBUSY;
- goto _exit_open;
+ return -EBUSY;
}
/* get pipe pointer (out pipe) */
pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0);
- if (pipe == NULL) {
- err = -EINVAL;
- goto _exit_open;
- }
+ if (pipe == NULL)
+ return -EINVAL;
/* start the pipe if necessary */
err = mixart_set_pipe_state(chip->mgr, pipe, 1);
if( err < 0 ) {
dev_err(chip->card->dev, "error starting pipe!\n");
snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
- err = -EINVAL;
- goto _exit_open;
+ return -EINVAL;
}
stream->pipe = pipe;
@@ -773,10 +766,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
}
}
- _exit_open:
- mutex_unlock(&mgr->setup_mutex);
-
- return err;
+ return 0;
}
@@ -791,7 +781,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
int err = 0;
int pcm_number;
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
if ( pcm == chip->pcm ) {
pcm_number = MIXART_PCM_ANALOG;
@@ -815,25 +805,21 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
dev_err(chip->card->dev,
"snd_mixart_capture_open C%d/P%d/Sub%d in use\n",
chip->chip_idx, pcm_number, subs->number);
- err = -EBUSY;
- goto _exit_open;
+ return -EBUSY;
}
/* get pipe pointer (in pipe) */
pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0);
- if (pipe == NULL) {
- err = -EINVAL;
- goto _exit_open;
- }
+ if (pipe == NULL)
+ return -EINVAL;
/* start the pipe if necessary */
err = mixart_set_pipe_state(chip->mgr, pipe, 1);
if( err < 0 ) {
dev_err(chip->card->dev, "error starting pipe!\n");
snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
- err = -EINVAL;
- goto _exit_open;
+ return -EINVAL;
}
stream->pipe = pipe;
@@ -854,10 +840,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
}
}
- _exit_open:
- mutex_unlock(&mgr->setup_mutex);
-
- return err;
+ return 0;
}
@@ -868,7 +851,7 @@ static int snd_mixart_close(struct snd_pcm_substream *subs)
struct mixart_mgr *mgr = chip->mgr;
struct mixart_stream *stream = subs->runtime->private_data;
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
dev_dbg(chip->card->dev, "snd_mixart_close C%d/P%d/Sub%d\n",
chip->chip_idx, stream->pcm_number, subs->number);
@@ -890,7 +873,6 @@ static int snd_mixart_close(struct snd_pcm_substream *subs)
stream->status = MIXART_STREAM_STATUS_FREE;
stream->substream = NULL;
- mutex_unlock(&mgr->setup_mutex);
return 0;
}
@@ -970,7 +952,7 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip)
pcm->info_flags = 0;
pcm->nonatomic = true;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name);
preallocate_buffers(chip, pcm);
@@ -1004,7 +986,7 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip)
pcm->info_flags = 0;
pcm->nonatomic = true;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name);
preallocate_buffers(chip, pcm);
@@ -1330,7 +1312,7 @@ static int snd_mixart_probe(struct pci_dev *pci,
return err;
}
- strcpy(card->driver, CARD_NAME);
+ strscpy(card->driver, CARD_NAME);
snprintf(card->shortname, sizeof(card->shortname),
"Digigram miXart [PCM #%d]", i);
snprintf(card->longname, sizeof(card->longname),
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index a047ed0f84e9..f7396ee4f6d7 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -226,17 +226,16 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
init_waitqueue_entry(&wait, current);
- mutex_lock(&mgr->msg_lock);
- /* send the message */
- err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */
- if (err) {
- mutex_unlock(&mgr->msg_lock);
- return err;
+ scoped_guard(mutex, &mgr->msg_lock) {
+ /* send the message */
+ err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */
+ if (err)
+ return err;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&mgr->msg_sleep, &wait);
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&mgr->msg_sleep, &wait);
- mutex_unlock(&mgr->msg_lock);
timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
remove_wait_queue(&mgr->msg_sleep, &wait);
@@ -253,9 +252,9 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
resp.data = resp_data;
resp.size = max_resp_size;
- mutex_lock(&mgr->msg_lock);
- err = get_msg(mgr, &resp, msg_frame);
- mutex_unlock(&mgr->msg_lock);
+ scoped_guard(mutex, &mgr->msg_lock) {
+ err = get_msg(mgr, &resp, msg_frame);
+ }
if( request->message_id != resp.message_id )
dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
@@ -280,17 +279,16 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
init_waitqueue_entry(&wait, current);
- mutex_lock(&mgr->msg_lock);
- /* send the message */
- err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event); /* send and mark the notification event pending */
- if(err) {
- mutex_unlock(&mgr->msg_lock);
- return err;
+ scoped_guard(mutex, &mgr->msg_lock) {
+ /* send the message */
+ err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event); /* send and mark the notification event pending */
+ if (err)
+ return err;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&mgr->msg_sleep, &wait);
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&mgr->msg_sleep, &wait);
- mutex_unlock(&mgr->msg_lock);
timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
remove_wait_queue(&mgr->msg_sleep, &wait);
@@ -311,9 +309,8 @@ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *requ
int err;
/* just send the message (do not mark it as a pending one) */
- mutex_lock(&mgr->msg_lock);
+ guard(mutex)(&mgr->msg_lock);
err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
- mutex_unlock(&mgr->msg_lock);
/* the answer will be handled by snd_struct mixart_msgasklet() */
atomic_inc(&mgr->msg_processed);
@@ -420,7 +417,7 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
struct mixart_msg resp;
u32 msg;
- mutex_lock(&mgr->lock);
+ guard(mutex)(&mgr->lock);
/* process interrupt */
while (retrieve_msg_frame(mgr, &msg)) {
@@ -530,19 +527,19 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
fallthrough;
case MSG_TYPE_ANSWER:
/* answer or notification to a message we are waiting for*/
- mutex_lock(&mgr->msg_lock);
- if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
- wake_up(&mgr->msg_sleep);
- mgr->pending_event = 0;
- }
- /* answer to a message we did't want to wait for */
- else {
- mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
- mgr->msg_fifo_writeptr++;
- mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
- snd_mixart_process_msg(mgr);
+ scoped_guard(mutex, &mgr->msg_lock) {
+ if ((msg & ~MSG_TYPE_MASK) == mgr->pending_event) {
+ wake_up(&mgr->msg_sleep);
+ mgr->pending_event = 0;
+ }
+ /* answer to a message we did't want to wait for */
+ else {
+ mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
+ mgr->msg_fifo_writeptr++;
+ mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
+ snd_mixart_process_msg(mgr);
+ }
}
- mutex_unlock(&mgr->msg_lock);
break;
case MSG_TYPE_REQUEST:
default:
@@ -556,8 +553,6 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
/* allow interrupt again */
writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
- mutex_unlock(&mgr->lock);
-
return IRQ_HANDLED;
}
diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
index 2f0e29ed5d63..7c9a9d82d66e 100644
--- a/sound/pci/mixart/mixart_core.h
+++ b/sound/pci/mixart/mixart_core.h
@@ -68,7 +68,7 @@ struct mixart_enum_connector_resp
u32 uid_count;
u32 current_uid_index;
struct mixart_uid uid[MIXART_MAX_PHYS_CONNECTORS];
-} __attribute__((packed));
+} __packed;
/* used for following struct */
@@ -81,7 +81,7 @@ struct mixart_audio_info_req
u32 line_max_level; /* float */
u32 micro_max_level; /* float */
u32 cd_max_level; /* float */
-} __attribute__((packed));
+} __packed;
struct mixart_analog_hw_info
{
@@ -93,7 +93,7 @@ struct mixart_analog_hw_info
u32 step_var_level; /* float */
u32 fix_gain; /* float */
u32 zero_var; /* float */
-} __attribute__((packed));
+} __packed;
struct mixart_digital_hw_info
{
@@ -101,7 +101,7 @@ struct mixart_digital_hw_info
u32 presence;
u32 clock;
u32 reserved;
-} __attribute__((packed));
+} __packed;
struct mixart_analog_info
{
@@ -110,27 +110,27 @@ struct mixart_analog_info
struct mixart_analog_hw_info line_info;
struct mixart_analog_hw_info cd_info;
u32 analog_level_present;
-} __attribute__((packed));
+} __packed;
struct mixart_digital_info
{
u32 type_mask;
struct mixart_digital_hw_info aes_info;
struct mixart_digital_hw_info adat_info;
-} __attribute__((packed));
+} __packed;
struct mixart_audio_info
{
u32 clock_type_mask;
struct mixart_analog_info analog_info;
struct mixart_digital_info digital_info;
-} __attribute__((packed));
+} __packed;
struct mixart_audio_info_resp
{
u32 txx_status;
struct mixart_audio_info info;
-} __attribute__((packed));
+} __packed;
/* used for nb_bytes_max_per_sample */
@@ -142,7 +142,7 @@ struct mixart_stream_info
u32 size_max_byte_frame;
u32 size_max_sample_frame;
u32 nb_bytes_max_per_sample; /* float */
-} __attribute__((packed));
+} __packed;
/* MSG_STREAM_ADD_INPUT_GROUP */
/* MSG_STREAM_ADD_OUTPUT_GROUP */
@@ -157,13 +157,13 @@ struct mixart_streaming_group_req
struct mixart_stream_info stream_info[32];
struct mixart_uid connector;
u32 flow_entry[32];
-} __attribute__((packed));
+} __packed;
struct mixart_stream_desc
{
struct mixart_uid stream_uid;
u32 stream_desc;
-} __attribute__((packed));
+} __packed;
struct mixart_streaming_group
{
@@ -172,7 +172,7 @@ struct mixart_streaming_group
u32 pipe_desc;
u32 stream_count;
struct mixart_stream_desc stream[32];
-} __attribute__((packed));
+} __packed;
/* MSG_STREAM_DELETE_GROUP */
@@ -182,7 +182,7 @@ struct mixart_delete_group_resp
{
u32 status;
u32 unused[2];
-} __attribute__((packed));
+} __packed;
/* MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130000 + 7,
@@ -195,7 +195,7 @@ struct mixart_fx_couple_uid
{
struct mixart_uid uid_fx_code;
struct mixart_uid uid_fx_data;
-} __attribute__((packed));
+} __packed;
struct mixart_txx_stream_desc
{
@@ -203,14 +203,14 @@ struct mixart_txx_stream_desc
u32 stream_idx;
u32 fx_number;
struct mixart_fx_couple_uid uid_fx[4];
-} __attribute__((packed));
+} __packed;
struct mixart_flow_info
{
struct mixart_txx_stream_desc stream_desc;
u32 flow_entry;
u32 flow_phy_addr;
-} __attribute__((packed));
+} __packed;
struct mixart_stream_state_req
{
@@ -219,7 +219,7 @@ struct mixart_stream_state_req
u32 reserved4np[3];
u32 stream_count; /* set to 1 for instance */
struct mixart_flow_info stream_info; /* could be an array[stream_count] */
-} __attribute__((packed));
+} __packed;
/* MSG_STREAM_START_STREAM_GRP_PACKET = 0x130000 + 6
MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130000 + 9
@@ -231,14 +231,14 @@ struct mixart_group_state_req
u64 scheduler;
u32 reserved4np[2];
u32 pipe_count; /* set to 1 for instance */
- struct mixart_uid pipe_uid[1]; /* could be an array[pipe_count] */
-} __attribute__((packed));
+ struct mixart_uid pipe_uid; /* could be an array[pipe_count], in theory */
+} __packed;
struct mixart_group_state_resp
{
u32 txx_status;
u64 scheduler;
-} __attribute__((packed));
+} __packed;
@@ -250,7 +250,7 @@ struct mixart_sample_pos
u32 validity;
u32 sample_pos_high_part;
u32 sample_pos_low_part;
-} __attribute__((packed));
+} __packed;
/*
* This structure is limited by the size of MSG_DEFAULT_SIZE. Instead of
@@ -263,7 +263,7 @@ struct mixart_timer_notify
{
u32 stream_count;
struct mixart_sample_pos streams[MIXART_MAX_TIMER_NOTIFY_STREAMS];
-} __attribute__((packed));
+} __packed;
/* MSG_CONSOLE_GET_CLOCK_UID = 0x070003,
@@ -275,7 +275,7 @@ struct mixart_return_uid
{
u32 error_code;
struct mixart_uid uid;
-} __attribute__((packed));
+} __packed;
/* MSG_CLOCK_CHECK_PROPERTIES = 0x200001,
MSG_CLOCK_SET_PROPERTIES = 0x200002,
@@ -314,14 +314,14 @@ struct mixart_clock_properties
u32 format;
u32 board_mask;
u32 nb_callers; /* set to 1 (see below) */
- struct mixart_uid uid_caller[1];
-} __attribute__((packed));
+ struct mixart_uid uid_caller;
+} __packed;
struct mixart_clock_properties_resp
{
u32 status;
u32 clock_mode;
-} __attribute__((packed));
+} __packed;
/* MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F */
@@ -401,9 +401,8 @@ struct mixart_stream_param_desc
u32 reserved4np[3];
u32 pipe_count; /* set to 1 (array size !) */
u32 stream_count; /* set to 1 (array size !) */
- struct mixart_txx_stream_desc stream_desc[1]; /* only one stream per command, but this could be an array */
-
-} __attribute__((packed));
+ struct mixart_txx_stream_desc stream_desc; /* only one stream per command, but this could be an array, in theory */
+} __packed;
/* MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009,
@@ -419,7 +418,7 @@ struct mixart_get_out_audio_level
u32 mute;
u32 monitor_mute1;
u32 monitor_mute2;
-} __attribute__((packed));
+} __packed;
/* MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A,
@@ -446,7 +445,7 @@ struct mixart_set_out_audio_level
u32 monitor_mute1;
u32 monitor_mute2;
u32 reserved4np;
-} __attribute__((packed));
+} __packed;
/* MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E,
@@ -461,7 +460,7 @@ struct mixart_uid_enumeration
u32 nb_uid;
u32 current_uid_index;
struct mixart_uid uid[MIXART_MAX_PHYS_IO];
-} __attribute__((packed));
+} __packed;
/* MSG_PHYSICALIO_SET_LEVEL = 0x0F0008,
@@ -472,13 +471,13 @@ struct mixart_io_channel_level
{
u32 analog_level; /* float */
u32 unused[2];
-} __attribute__((packed));
+} __packed;
struct mixart_io_level
{
s32 channel; /* 0=left, 1=right, -1=both, -2=both same */
struct mixart_io_channel_level level[2];
-} __attribute__((packed));
+} __packed;
/* MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015,
@@ -491,7 +490,7 @@ struct mixart_in_audio_level_info
u32 valid_mask2;
u32 digital_level;
u32 analog_level;
-} __attribute__((packed));
+} __packed;
struct mixart_set_in_audio_level_req
{
@@ -500,7 +499,7 @@ struct mixart_set_in_audio_level_req
u32 audio_count; /* set to <= 2 */
u32 reserved4np;
struct mixart_in_audio_level_info level[2];
-} __attribute__((packed));
+} __packed;
/* response is a 32 bit status */
@@ -530,13 +529,13 @@ struct mixart_out_stream_level_info
u32 digital_level2;
u32 mute1;
u32 mute2;
-} __attribute__((packed));
+} __packed;
struct mixart_set_out_stream_level
{
struct mixart_txx_stream_desc desc;
struct mixart_out_stream_level_info out_level;
-} __attribute__((packed));
+} __packed;
struct mixart_set_out_stream_level_req
{
@@ -545,7 +544,7 @@ struct mixart_set_out_stream_level_req
u32 reserved4np[2];
u32 nb_of_stream; /* set to 1 */
struct mixart_set_out_stream_level stream_level; /* could be an array */
-} __attribute__((packed));
+} __packed;
/* response to this request is a u32 status value */
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 2727f3345795..f4081d323340 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -344,7 +344,8 @@ static int mixart_analog_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if(kcontrol->private_value == 0) { /* playback */
ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
@@ -352,7 +353,6 @@ static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -362,7 +362,7 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int changed = 0;
int is_capture, i;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
is_capture = (kcontrol->private_value != 0);
for (i = 0; i < 2; i++) {
int new_volume = ucontrol->value.integer.value[i];
@@ -385,7 +385,6 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
if (changed)
mixart_update_analog_audio_level(chip, is_capture);
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -409,10 +408,9 @@ static int mixart_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
{
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -420,7 +418,8 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
{
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
int i, changed = 0;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
for (i = 0; i < 2; i++) {
if (chip->analog_playback_active[i] !=
ucontrol->value.integer.value[i]) {
@@ -431,7 +430,6 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
}
if (changed) /* update playback levels */
mixart_update_analog_audio_level(chip, 0);
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -825,7 +823,8 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
int *stored_volume;
int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if(is_capture) {
if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */
else stored_volume = chip->digital_capture_volume[0]; /* analog capture */
@@ -836,7 +835,6 @@ static int mixart_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
}
ucontrol->value.integer.value[0] = stored_volume[0];
ucontrol->value.integer.value[1] = stored_volume[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -849,7 +847,8 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
int* stored_volume;
int i;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (is_capture) {
if (is_aes) /* AES capture */
stored_volume = chip->digital_capture_volume[1];
@@ -878,7 +877,6 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
else
mixart_update_playback_stream_level(chip, is_aes, idx);
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -903,12 +901,12 @@ static int mixart_pcm_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if(kcontrol->private_value & MIXART_VOL_AES_MASK) /* AES playback */
idx += MIXART_PLAYBACK_STREAMS;
ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -920,7 +918,8 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
int i, j;
snd_BUG_ON(idx >= MIXART_PLAYBACK_STREAMS);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
j = idx;
if (is_aes)
j += MIXART_PLAYBACK_STREAMS;
@@ -934,7 +933,6 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
}
if (changed)
mixart_update_playback_stream_level(chip, is_aes, idx);
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -985,10 +983,10 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel)
static int mixart_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -997,7 +995,8 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
int i;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
for (i = 0; i < 2; i++) {
if (chip->monitoring_volume[i] !=
ucontrol->value.integer.value[i]) {
@@ -1007,7 +1006,6 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
changed = 1;
}
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -1029,10 +1027,10 @@ static const struct snd_kcontrol_new mixart_control_monitor_vol = {
static int mixart_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->monitoring_active[0];
ucontrol->value.integer.value[1] = chip->monitoring_active[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -1041,7 +1039,8 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
int i;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
for (i = 0; i < 2; i++) {
if (chip->monitoring_active[i] !=
ucontrol->value.integer.value[i]) {
@@ -1074,7 +1073,6 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return (changed != 0);
}
diff --git a/sound/pci/nm256/Makefile b/sound/pci/nm256/Makefile
index 3063766ac56b..7d55fe774d20 100644
--- a/sound/pci/nm256/Makefile
+++ b/sound/pci/nm256/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-nm256-objs := nm256.o
+snd-nm256-y := nm256.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_NM256) += snd-nm256.o
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index f99a1e96e923..da74b923bc88 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -446,27 +446,25 @@ snd_nm256_set_format(struct nm256 *chip, struct nm256_stream *s,
/* acquire interrupt */
static int snd_nm256_acquire_irq(struct nm256 *chip)
{
- mutex_lock(&chip->irq_mutex);
+ guard(mutex)(&chip->irq_mutex);
if (chip->irq < 0) {
if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
dev_err(chip->card->dev,
"unable to grab IRQ %d\n", chip->pci->irq);
- mutex_unlock(&chip->irq_mutex);
return -EBUSY;
}
chip->irq = chip->pci->irq;
chip->card->sync_irq = chip->irq;
}
chip->irq_acks++;
- mutex_unlock(&chip->irq_mutex);
return 0;
}
/* release interrupt */
static void snd_nm256_release_irq(struct nm256 *chip)
{
- mutex_lock(&chip->irq_mutex);
+ guard(mutex)(&chip->irq_mutex);
if (chip->irq_acks > 0)
chip->irq_acks--;
if (chip->irq_acks == 0 && chip->irq >= 0) {
@@ -474,7 +472,6 @@ static void snd_nm256_release_irq(struct nm256 *chip)
chip->irq = -1;
chip->card->sync_irq = -1;
}
- mutex_unlock(&chip->irq_mutex);
}
/*
@@ -547,12 +544,11 @@ snd_nm256_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct nm256 *chip = snd_pcm_substream_chip(substream);
struct nm256_stream *s = substream->runtime->private_data;
- int err = 0;
if (snd_BUG_ON(!s))
return -ENXIO;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
s->suspended = 0;
@@ -573,11 +569,9 @@ snd_nm256_playback_trigger(struct snd_pcm_substream *substream, int cmd)
}
break;
default:
- err = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
- return err;
+ return 0;
}
static int
@@ -585,12 +579,11 @@ snd_nm256_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct nm256 *chip = snd_pcm_substream_chip(substream);
struct nm256_stream *s = substream->runtime->private_data;
- int err = 0;
if (snd_BUG_ON(!s))
return -ENXIO;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -607,11 +600,9 @@ snd_nm256_capture_trigger(struct snd_pcm_substream *substream, int cmd)
}
break;
default:
- err = -EINVAL;
- break;
+ return -EINVAL;
}
- spin_unlock(&chip->reg_lock);
- return err;
+ return 0;
}
@@ -631,10 +622,9 @@ static int snd_nm256_pcm_prepare(struct snd_pcm_substream *substream)
s->periods = substream->runtime->periods;
s->cur_period = 0;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
s->running = 0;
snd_nm256_set_format(chip, s, substream);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -691,56 +681,32 @@ snd_nm256_playback_silence(struct snd_pcm_substream *substream,
static int
snd_nm256_playback_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nm256_stream *s = runtime->private_data;
- if (copy_from_user_toio(s->bufptr + pos, src, count))
+ if (copy_from_iter_toio(s->bufptr + pos, count, src) != count)
return -EFAULT;
return 0;
}
-static int
-snd_nm256_playback_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct nm256_stream *s = runtime->private_data;
-
- memcpy_toio(s->bufptr + pos, src, count);
- return 0;
-}
-
/*
* copy to user
*/
static int
snd_nm256_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nm256_stream *s = runtime->private_data;
- if (copy_to_user_fromio(dst, s->bufptr + pos, count))
+ if (copy_to_iter_fromio(s->bufptr + pos, count, dst) != count)
return -EFAULT;
return 0;
}
-static int
-snd_nm256_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct nm256_stream *s = runtime->private_data;
-
- memcpy_fromio(dst, s->bufptr + pos, count);
- return 0;
-}
-
#endif /* !__i386__ */
@@ -909,8 +875,7 @@ static const struct snd_pcm_ops snd_nm256_playback_ops = {
.trigger = snd_nm256_playback_trigger,
.pointer = snd_nm256_playback_pointer,
#ifndef __i386__
- .copy_user = snd_nm256_playback_copy,
- .copy_kernel = snd_nm256_playback_copy_kernel,
+ .copy = snd_nm256_playback_copy,
.fill_silence = snd_nm256_playback_silence,
#endif
.mmap = snd_pcm_lib_mmap_iomem,
@@ -924,8 +889,7 @@ static const struct snd_pcm_ops snd_nm256_capture_ops = {
.trigger = snd_nm256_capture_trigger,
.pointer = snd_nm256_capture_pointer,
#ifndef __i386__
- .copy_user = snd_nm256_capture_copy,
- .copy_kernel = snd_nm256_capture_copy_kernel,
+ .copy = snd_nm256_capture_copy,
#endif
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1025,7 +989,7 @@ snd_nm256_interrupt(int irq, void *dev_id)
/* Rather boring; check for individual interrupts and process them. */
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
if (status & NM_PLAYBACK_INT) {
status &= ~NM_PLAYBACK_INT;
NM_ACK_INT(chip, NM_PLAYBACK_INT);
@@ -1064,7 +1028,6 @@ snd_nm256_interrupt(int irq, void *dev_id)
NM_ACK_INT(chip, status);
}
- spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -1091,7 +1054,7 @@ snd_nm256_interrupt_zx(int irq, void *dev_id)
/* Rather boring; check for individual interrupts and process them. */
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
if (status & NM2_PLAYBACK_INT) {
status &= ~NM2_PLAYBACK_INT;
NM2_ACK_INT(chip, NM2_PLAYBACK_INT);
@@ -1129,7 +1092,6 @@ snd_nm256_interrupt_zx(int irq, void *dev_id)
NM2_ACK_INT(chip, status);
}
- spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -1386,7 +1348,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
/*
* APM event handler, so the card is properly reinitialized after a power
* event.
@@ -1419,9 +1380,8 @@ static int nm256_resume(struct device *dev)
for (i = 0; i < 2; i++) {
struct nm256_stream *s = &chip->streams[i];
if (s->substream && s->suspended) {
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_nm256_set_format(chip, s, s->substream);
- spin_unlock_irq(&chip->reg_lock);
}
}
@@ -1430,11 +1390,7 @@ static int nm256_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
-#define NM256_PM_OPS &nm256_pm
-#else
-#define NM256_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
static void snd_nm256_free(struct snd_card *card)
{
@@ -1478,7 +1434,7 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci)
chip->buffer_addr = pci_resource_start(pci, 0);
chip->cport_addr = pci_resource_start(pci, 1);
- err = pci_request_regions(pci, card->driver);
+ err = pcim_request_all_regions(pci, card->driver);
if (err < 0)
return err;
@@ -1626,13 +1582,13 @@ static int snd_nm256_probe(struct pci_dev *pci,
switch (pci->device) {
case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO:
- strcpy(card->driver, "NM256AV");
+ strscpy(card->driver, "NM256AV");
break;
case PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO:
- strcpy(card->driver, "NM256ZX");
+ strscpy(card->driver, "NM256ZX");
break;
case PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO:
- strcpy(card->driver, "NM256XL+");
+ strscpy(card->driver, "NM256XL+");
break;
default:
dev_err(&pci->dev, "invalid device id 0x%x\n", pci->device);
@@ -1690,7 +1646,7 @@ static struct pci_driver nm256_driver = {
.id_table = snd_nm256_ids,
.probe = snd_nm256_probe,
.driver = {
- .pm = NM256_PM_OPS,
+ .pm = &nm256_pm,
},
};
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index 0dfc4f840992..cc0c24694750 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
-snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
-snd-se6x-objs := se6x.o
-snd-virtuoso-objs := virtuoso.o xonar_lib.o \
+snd-oxygen-lib-y := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
+snd-oxygen-y := oxygen.o xonar_dg_mixer.o xonar_dg.o
+snd-se6x-y := se6x.o
+snd-virtuoso-y := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index c346f42befc2..e6f869cf8ca2 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -450,7 +450,7 @@ static int rolloff_put(struct snd_kcontrol *ctl,
int changed;
u8 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->ak4396_regs[0][AK4396_CONTROL_2];
if (value->value.enumerated.item[0])
reg |= AK4396_SLOW;
@@ -461,7 +461,6 @@ static int rolloff_put(struct snd_kcontrol *ctl,
for (i = 0; i < data->dacs; ++i)
ak4396_write(chip, i, AK4396_CONTROL_2, reg);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -499,14 +498,13 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
unsigned int reg;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL);
if (value->value.enumerated.item[0])
reg |= WM8785_HPFR | WM8785_HPFL;
changed = reg != data->wm8785_regs[WM8785_R2];
if (changed)
wm8785_write(chip, WM8785_R2, reg);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -563,7 +561,7 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl,
u16 old_reg, new_reg;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK;
if (value->value.enumerated.item[0] == 0)
@@ -573,7 +571,6 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl,
changed = new_reg != old_reg;
if (changed)
oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -584,7 +581,7 @@ static int claro_dig_source_put(struct snd_kcontrol *ctl,
u16 old_reg, new_reg;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
if (value->value.enumerated.item[0])
@@ -592,7 +589,6 @@ static int claro_dig_source_put(struct snd_kcontrol *ctl,
changed = new_reg != old_reg;
if (changed)
oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -854,11 +850,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..6b096d654f9f 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -59,36 +59,34 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
if (!status)
return IRQ_NONE;
- spin_lock(&chip->reg_lock);
-
- clear = status & (OXYGEN_CHANNEL_A |
- OXYGEN_CHANNEL_B |
- OXYGEN_CHANNEL_C |
- OXYGEN_CHANNEL_SPDIF |
- OXYGEN_CHANNEL_MULTICH |
- OXYGEN_CHANNEL_AC97 |
- OXYGEN_INT_SPDIF_IN_DETECT |
- OXYGEN_INT_GPIO |
- OXYGEN_INT_AC97);
- if (clear) {
- if (clear & OXYGEN_INT_SPDIF_IN_DETECT)
- chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT;
- oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
- chip->interrupt_mask & ~clear);
- oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
- chip->interrupt_mask);
- }
-
- elapsed_streams = status & chip->pcm_running;
+ scoped_guard(spinlock, &chip->reg_lock) {
+ clear = status & (OXYGEN_CHANNEL_A |
+ OXYGEN_CHANNEL_B |
+ OXYGEN_CHANNEL_C |
+ OXYGEN_CHANNEL_SPDIF |
+ OXYGEN_CHANNEL_MULTICH |
+ OXYGEN_CHANNEL_AC97 |
+ OXYGEN_INT_SPDIF_IN_DETECT |
+ OXYGEN_INT_GPIO |
+ OXYGEN_INT_AC97);
+ if (clear) {
+ if (clear & OXYGEN_INT_SPDIF_IN_DETECT)
+ chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT;
+ oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
+ chip->interrupt_mask & ~clear);
+ oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
+ chip->interrupt_mask);
+ }
- spin_unlock(&chip->reg_lock);
+ elapsed_streams = status & chip->pcm_running;
+ }
for (i = 0; i < PCM_COUNT; ++i)
if ((elapsed_streams & (1 << i)) && chip->streams[i])
snd_pcm_period_elapsed(chip->streams[i]);
if (status & OXYGEN_INT_SPDIF_IN_DETECT) {
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT |
OXYGEN_SPDIF_RATE_INT)) {
@@ -96,7 +94,6 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i);
schedule_work(&chip->spdif_input_bits_work);
}
- spin_unlock(&chip->reg_lock);
}
if (status & OXYGEN_INT_GPIO)
@@ -127,45 +124,45 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work)
* changes.
*/
msleep(1);
- spin_lock_irq(&chip->reg_lock);
- reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
- if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
- OXYGEN_SPDIF_LOCK_STATUS))
- == OXYGEN_SPDIF_SENSE_STATUS) {
- /*
- * If we detect activity on the SPDIF input but cannot lock to
- * a signal, the clock bit is likely to be wrong.
- */
- reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK;
- oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
- spin_unlock_irq(&chip->reg_lock);
- msleep(1);
- spin_lock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
OXYGEN_SPDIF_LOCK_STATUS))
== OXYGEN_SPDIF_SENSE_STATUS) {
- /* nothing detected with either clock; give up */
- if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK)
- == OXYGEN_SPDIF_IN_CLOCK_192) {
- /*
- * Reset clock to <= 96 kHz because this is
- * more likely to be received next time.
- */
- reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK;
- reg |= OXYGEN_SPDIF_IN_CLOCK_96;
- oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
+ /*
+ * If we detect activity on the SPDIF input but cannot lock to
+ * a signal, the clock bit is likely to be wrong.
+ */
+ reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK;
+ oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
+ spin_unlock_irq(&chip->reg_lock);
+ msleep(1);
+ spin_lock_irq(&chip->reg_lock);
+ reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+ if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
+ OXYGEN_SPDIF_LOCK_STATUS))
+ == OXYGEN_SPDIF_SENSE_STATUS) {
+ /* nothing detected with either clock; give up */
+ if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK)
+ == OXYGEN_SPDIF_IN_CLOCK_192) {
+ /*
+ * Reset clock to <= 96 kHz because this is
+ * more likely to be received next time.
+ */
+ reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK;
+ reg |= OXYGEN_SPDIF_IN_CLOCK_96;
+ oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
+ }
}
}
}
- spin_unlock_irq(&chip->reg_lock);
if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) {
- spin_lock_irq(&chip->reg_lock);
- chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
- oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
- chip->interrupt_mask);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
+ oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
+ chip->interrupt_mask);
+ }
/*
* We don't actually know that any channel status bits have
@@ -557,12 +554,11 @@ static void oxygen_init(struct oxygen *chip)
static void oxygen_shutdown(struct oxygen *chip)
{
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->interrupt_mask = 0;
chip->pcm_running = 0;
oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
- spin_unlock_irq(&chip->reg_lock);
}
static void oxygen_card_free(struct snd_card *card)
@@ -609,7 +605,7 @@ static int __oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
if (err < 0)
return err;
- err = pci_request_regions(pci, DRIVER);
+ err = pcim_request_all_regions(pci, DRIVER);
if (err < 0) {
dev_err(card->dev, "cannot reserve PCI resources\n");
return err;
@@ -655,11 +651,11 @@ static int __oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
chip->irq = pci->irq;
card->sync_irq = chip->irq;
- strcpy(card->driver, chip->model.chip);
- strcpy(card->shortname, chip->model.shortname);
+ strscpy(card->driver, chip->model.chip);
+ strscpy(card->shortname, chip->model.shortname);
sprintf(card->longname, "%s at %#lx, irq %i",
chip->model.longname, chip->addr, chip->irq);
- strcpy(card->mixername, chip->model.chip);
+ strscpy(card->mixername, chip->model.chip);
snd_component_add(card, chip->model.chip);
err = oxygen_pcm_init(chip);
@@ -686,13 +682,13 @@ static int __oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
oxygen_proc_init(chip);
- spin_lock_irq(&chip->reg_lock);
- if (chip->model.device_config & CAPTURE_1_FROM_SPDIF)
- chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
- if (chip->has_ac97_0 | chip->has_ac97_1)
- chip->interrupt_mask |= OXYGEN_INT_AC97;
- oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ if (chip->model.device_config & CAPTURE_1_FROM_SPDIF)
+ chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
+ if (chip->has_ac97_0 | chip->has_ac97_1)
+ chip->interrupt_mask |= OXYGEN_INT_AC97;
+ oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+ }
err = snd_card_register(card);
if (err < 0)
@@ -713,7 +709,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);
@@ -725,12 +720,12 @@ static int oxygen_pci_suspend(struct device *dev)
if (chip->model.suspend)
chip->model.suspend(chip);
- spin_lock_irq(&chip->reg_lock);
- saved_interrupt_mask = chip->interrupt_mask;
- chip->interrupt_mask = 0;
- oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
- oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ saved_interrupt_mask = chip->interrupt_mask;
+ chip->interrupt_mask = 0;
+ oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
+ oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
+ }
flush_work(&chip->spdif_input_bits_work);
flush_work(&chip->gpio_work);
@@ -789,9 +784,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/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 46705ec77b48..256a601d7811 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -31,10 +31,9 @@ static int dac_volume_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
unsigned int i;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
for (i = 0; i < chip->model.dac_channels_mixer; ++i)
value->value.integer.value[i] = chip->dac_volume[i];
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -46,7 +45,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl,
int changed;
changed = 0;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
for (i = 0; i < chip->model.dac_channels_mixer; ++i)
if (value->value.integer.value[i] != chip->dac_volume[i]) {
chip->dac_volume[i] = value->value.integer.value[i];
@@ -54,7 +53,6 @@ static int dac_volume_put(struct snd_kcontrol *ctl,
}
if (changed)
chip->model.update_dac_volume(chip);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -63,9 +61,8 @@ static int dac_mute_get(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.integer.value[0] = !chip->dac_mute;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -75,13 +72,12 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = (!value->value.integer.value[0]) != chip->dac_mute;
if (changed) {
chip->dac_mute = !value->value.integer.value[0];
chip->model.update_dac_mute(chip);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -114,9 +110,8 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.enumerated.item[0] = chip->dac_routing;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -188,13 +183,12 @@ static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
if (value->value.enumerated.item[0] >= count)
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = value->value.enumerated.item[0] != chip->dac_routing;
if (changed) {
chip->dac_routing = value->value.enumerated.item[0];
oxygen_update_dac_routing(chip);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -203,9 +197,8 @@ static int spdif_switch_get(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.integer.value[0] = chip->spdif_playback_enable;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -279,7 +272,7 @@ static int spdif_switch_put(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = value->value.integer.value[0] != chip->spdif_playback_enable;
if (changed) {
chip->spdif_playback_enable = !!value->value.integer.value[0];
@@ -287,7 +280,6 @@ static int spdif_switch_put(struct snd_kcontrol *ctl,
oxygen_update_spdif_source(chip);
spin_unlock_irq(&chip->reg_lock);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -336,9 +328,8 @@ static int spdif_default_get(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
oxygen_to_iec958(chip->spdif_bits, value);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -350,14 +341,13 @@ static int spdif_default_put(struct snd_kcontrol *ctl,
int changed;
new_bits = iec958_to_oxygen(value);
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = new_bits != chip->spdif_bits;
if (changed) {
chip->spdif_bits = new_bits;
if (!(chip->pcm_active & (1 << PCM_SPDIF)))
write_spdif_bits(chip, new_bits);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -376,9 +366,8 @@ static int spdif_pcm_get(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
oxygen_to_iec958(chip->spdif_pcm_bits, value);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -390,14 +379,13 @@ static int spdif_pcm_put(struct snd_kcontrol *ctl,
int changed;
new_bits = iec958_to_oxygen(value);
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = new_bits != chip->spdif_pcm_bits;
if (changed) {
chip->spdif_pcm_bits = new_bits;
if (chip->pcm_active & (1 << PCM_SPDIF))
write_spdif_bits(chip, new_bits);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -444,7 +432,7 @@ static int spdif_bit_switch_put(struct snd_kcontrol *ctl,
u32 oldreg, newreg;
int changed;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
if (value->value.integer.value[0])
newreg = oldreg | bit;
@@ -453,7 +441,6 @@ static int spdif_bit_switch_put(struct snd_kcontrol *ctl,
changed = newreg != oldreg;
if (changed)
oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
- spin_unlock_irq(&chip->reg_lock);
return changed;
}
@@ -488,7 +475,7 @@ static int monitor_put(struct snd_kcontrol *ctl,
u8 oldreg, newreg;
int changed;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR);
if ((!!value->value.integer.value[0] ^ !!invert) != 0)
newreg = oldreg | bit;
@@ -497,7 +484,6 @@ static int monitor_put(struct snd_kcontrol *ctl,
changed = newreg != oldreg;
if (changed)
oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg);
- spin_unlock_irq(&chip->reg_lock);
return changed;
}
@@ -511,9 +497,8 @@ static int ac97_switch_get(struct snd_kcontrol *ctl,
int invert = ctl->private_value & (1 << 16);
u16 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = oxygen_read_ac97(chip, codec, index);
- mutex_unlock(&chip->mutex);
if (!(reg & (1 << bitnr)) ^ !invert)
value->value.integer.value[0] = 1;
else
@@ -550,7 +535,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
u16 oldreg, newreg;
int change;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
oldreg = oxygen_read_ac97(chip, codec, index);
newreg = oldreg;
if (!value->value.integer.value[0] ^ !invert)
@@ -579,7 +564,6 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
CM9780_GPO0, CM9780_GPO0);
}
}
- mutex_unlock(&chip->mutex);
return change;
}
@@ -604,9 +588,8 @@ static int ac97_volume_get(struct snd_kcontrol *ctl,
unsigned int index = ctl->private_value & 0xff;
u16 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = oxygen_read_ac97(chip, codec, index);
- mutex_unlock(&chip->mutex);
if (!stereo) {
value->value.integer.value[0] = 31 - (reg & 0x1f);
} else {
@@ -626,7 +609,7 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
u16 oldreg, newreg;
int change;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
oldreg = oxygen_read_ac97(chip, codec, index);
if (!stereo) {
newreg = oldreg & ~0x1f;
@@ -639,7 +622,6 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
change = newreg != oldreg;
if (change)
oxygen_write_ac97(chip, codec, index, newreg);
- mutex_unlock(&chip->mutex);
return change;
}
@@ -656,10 +638,9 @@ static int mic_fmic_source_get(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.enumerated.item[0] =
!!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -670,7 +651,7 @@ static int mic_fmic_source_put(struct snd_kcontrol *ctl,
u16 oldreg, newreg;
int change;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK);
if (value->value.enumerated.item[0])
newreg = oldreg | CM9780_FMIC2MIC;
@@ -679,7 +660,6 @@ static int mic_fmic_source_put(struct snd_kcontrol *ctl,
change = newreg != oldreg;
if (change)
oxygen_write_ac97(chip, 0, CM9780_JACK, newreg);
- mutex_unlock(&chip->mutex);
return change;
}
@@ -699,9 +679,8 @@ static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
u16 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN);
- mutex_unlock(&chip->mutex);
value->value.integer.value[0] = reg & 7;
value->value.integer.value[1] = (reg >> 8) & 7;
return 0;
@@ -714,15 +693,14 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
u16 oldreg, newreg;
int change;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN);
newreg = oldreg & ~0x0707;
newreg = newreg | (value->value.integer.value[0] & 7);
- newreg = newreg | ((value->value.integer.value[0] & 7) << 8);
+ newreg = newreg | ((value->value.integer.value[1] & 7) << 8);
change = newreg != oldreg;
if (change)
oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg);
- mutex_unlock(&chip->mutex);
return change;
}
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index b2a3fcfe31d4..b716356010b8 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -171,7 +171,7 @@ static int oxygen_open(struct snd_pcm_substream *substream,
snd_pcm_set_sync(substream);
chip->streams[channel] = substream;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
chip->pcm_active |= 1 << channel;
if (channel == PCM_SPDIF) {
chip->spdif_pcm_bits = chip->spdif_bits;
@@ -181,7 +181,6 @@ static int oxygen_open(struct snd_pcm_substream *substream,
SNDRV_CTL_EVENT_MASK_INFO,
&chip->controls[CONTROL_SPDIF_PCM]->id);
}
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -221,7 +220,7 @@ static int oxygen_close(struct snd_pcm_substream *substream)
struct oxygen *chip = snd_pcm_substream_chip(substream);
unsigned int channel = oxygen_substream_channel(substream);
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
chip->pcm_active &= ~(1 << channel);
if (channel == PCM_SPDIF) {
chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |=
@@ -232,7 +231,6 @@ static int oxygen_close(struct snd_pcm_substream *substream)
}
if (channel == PCM_SPDIF || channel == PCM_MULTICH)
oxygen_update_spdif_source(chip);
- mutex_unlock(&chip->mutex);
chip->streams[channel] = NULL;
return 0;
@@ -351,24 +349,23 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
- spin_lock_irq(&chip->reg_lock);
- oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
- oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT,
- OXYGEN_REC_FORMAT_A_MASK);
- oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
- oxygen_rate(hw_params) |
- chip->model.adc_i2s_format |
- get_mclk(chip, PCM_A, hw_params) |
- oxygen_i2s_bits(hw_params),
- OXYGEN_I2S_RATE_MASK |
- OXYGEN_I2S_FORMAT_MASK |
- OXYGEN_I2S_MCLK_MASK |
- OXYGEN_I2S_BITS_MASK);
- spin_unlock_irq(&chip->reg_lock);
-
- mutex_lock(&chip->mutex);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
+ oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT,
+ OXYGEN_REC_FORMAT_A_MASK);
+ oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
+ oxygen_rate(hw_params) |
+ chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_A, hw_params) |
+ oxygen_i2s_bits(hw_params),
+ OXYGEN_I2S_RATE_MASK |
+ OXYGEN_I2S_FORMAT_MASK |
+ OXYGEN_I2S_MCLK_MASK |
+ OXYGEN_I2S_BITS_MASK);
+ }
+
+ guard(mutex)(&chip->mutex);
chip->model.set_adc_params(chip, hw_params);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -386,26 +383,25 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
is_ac97 = chip->has_ac97_1 &&
(chip->model.device_config & CAPTURE_2_FROM_AC97_1);
- spin_lock_irq(&chip->reg_lock);
- oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
- oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT,
- OXYGEN_REC_FORMAT_B_MASK);
- if (!is_ac97)
- oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
- oxygen_rate(hw_params) |
- chip->model.adc_i2s_format |
- get_mclk(chip, PCM_B, hw_params) |
- oxygen_i2s_bits(hw_params),
- OXYGEN_I2S_RATE_MASK |
- OXYGEN_I2S_FORMAT_MASK |
- OXYGEN_I2S_MCLK_MASK |
- OXYGEN_I2S_BITS_MASK);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
+ oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT,
+ OXYGEN_REC_FORMAT_B_MASK);
+ if (!is_ac97)
+ oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
+ oxygen_rate(hw_params) |
+ chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_B, hw_params) |
+ oxygen_i2s_bits(hw_params),
+ OXYGEN_I2S_RATE_MASK |
+ OXYGEN_I2S_FORMAT_MASK |
+ OXYGEN_I2S_MCLK_MASK |
+ OXYGEN_I2S_BITS_MASK);
+ }
if (!is_ac97) {
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
chip->model.set_adc_params(chip, hw_params);
- mutex_unlock(&chip->mutex);
}
return 0;
}
@@ -423,26 +419,25 @@ static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream,
is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF;
- spin_lock_irq(&chip->reg_lock);
- oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
- oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT,
- OXYGEN_REC_FORMAT_C_MASK);
- if (!is_spdif)
- oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT,
- oxygen_rate(hw_params) |
- chip->model.adc_i2s_format |
- get_mclk(chip, PCM_B, hw_params) |
- oxygen_i2s_bits(hw_params),
- OXYGEN_I2S_RATE_MASK |
- OXYGEN_I2S_FORMAT_MASK |
- OXYGEN_I2S_MCLK_MASK |
- OXYGEN_I2S_BITS_MASK);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
+ oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT,
+ OXYGEN_REC_FORMAT_C_MASK);
+ if (!is_spdif)
+ oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT,
+ oxygen_rate(hw_params) |
+ chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_B, hw_params) |
+ oxygen_i2s_bits(hw_params),
+ OXYGEN_I2S_RATE_MASK |
+ OXYGEN_I2S_FORMAT_MASK |
+ OXYGEN_I2S_MCLK_MASK |
+ OXYGEN_I2S_BITS_MASK);
+ }
if (!is_spdif) {
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
chip->model.set_adc_params(chip, hw_params);
- mutex_unlock(&chip->mutex);
}
return 0;
}
@@ -457,8 +452,8 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
- mutex_lock(&chip->mutex);
- spin_lock_irq(&chip->reg_lock);
+ guard(mutex)(&chip->mutex);
+ guard(spinlock_irq)(&chip->reg_lock);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE);
oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT,
@@ -468,8 +463,6 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
oxygen_rate(hw_params) << OXYGEN_SPDIF_OUT_RATE_SHIFT,
OXYGEN_SPDIF_OUT_RATE_MASK);
oxygen_update_spdif_source(chip);
- spin_unlock_irq(&chip->reg_lock);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -483,29 +476,28 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
- mutex_lock(&chip->mutex);
- spin_lock_irq(&chip->reg_lock);
- oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
- oxygen_play_channels(hw_params),
- OXYGEN_PLAY_CHANNELS_MASK);
- oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT,
- oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT,
- OXYGEN_MULTICH_FORMAT_MASK);
- oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
- oxygen_rate(hw_params) |
- chip->model.dac_i2s_format |
- get_mclk(chip, PCM_MULTICH, hw_params) |
- oxygen_i2s_bits(hw_params),
- OXYGEN_I2S_RATE_MASK |
- OXYGEN_I2S_FORMAT_MASK |
- OXYGEN_I2S_MCLK_MASK |
- OXYGEN_I2S_BITS_MASK);
- oxygen_update_spdif_source(chip);
- spin_unlock_irq(&chip->reg_lock);
+ guard(mutex)(&chip->mutex);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
+ oxygen_play_channels(hw_params),
+ OXYGEN_PLAY_CHANNELS_MASK);
+ oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT,
+ oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT,
+ OXYGEN_MULTICH_FORMAT_MASK);
+ oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
+ oxygen_rate(hw_params) |
+ chip->model.dac_i2s_format |
+ get_mclk(chip, PCM_MULTICH, hw_params) |
+ oxygen_i2s_bits(hw_params),
+ OXYGEN_I2S_RATE_MASK |
+ OXYGEN_I2S_FORMAT_MASK |
+ OXYGEN_I2S_MCLK_MASK |
+ OXYGEN_I2S_BITS_MASK);
+ oxygen_update_spdif_source(chip);
+ }
chip->model.set_dac_params(chip, hw_params);
oxygen_update_dac_routing(chip);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -515,13 +507,12 @@ static int oxygen_hw_free(struct snd_pcm_substream *substream)
unsigned int channel = oxygen_substream_channel(substream);
unsigned int channel_mask = 1 << channel;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
chip->interrupt_mask &= ~channel_mask;
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -530,10 +521,10 @@ static int oxygen_spdif_hw_free(struct snd_pcm_substream *substream)
{
struct oxygen *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
- oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
- OXYGEN_SPDIF_OUT_ENABLE);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
+ OXYGEN_SPDIF_OUT_ENABLE);
+ }
return oxygen_hw_free(substream);
}
@@ -543,7 +534,7 @@ static int oxygen_prepare(struct snd_pcm_substream *substream)
unsigned int channel = oxygen_substream_channel(substream);
unsigned int channel_mask = 1 << channel;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
@@ -552,7 +543,6 @@ static int oxygen_prepare(struct snd_pcm_substream *substream)
else
chip->interrupt_mask |= channel_mask;
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -584,7 +574,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd)
}
}
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
if (!pausing) {
if (cmd == SNDRV_PCM_TRIGGER_START)
chip->pcm_running |= mask;
@@ -597,7 +587,6 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd)
else
oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask);
}
- spin_unlock(&chip->reg_lock);
return 0;
}
@@ -697,7 +686,7 @@ int oxygen_pcm_init(struct oxygen *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_b_ops);
pcm->private_data = chip;
- strcpy(pcm->name, "Multichannel");
+ strscpy(pcm->name, "Multichannel");
if (outs)
snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
SNDRV_DMA_TYPE_DEV,
@@ -725,7 +714,7 @@ int oxygen_pcm_init(struct oxygen *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_c_ops);
pcm->private_data = chip;
- strcpy(pcm->name, "Digital");
+ strscpy(pcm->name, "Digital");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pci->dev,
DEFAULT_BUFFER_BYTES,
@@ -755,7 +744,7 @@ int oxygen_pcm_init(struct oxygen *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_b_ops);
pcm->private_data = chip;
- strcpy(pcm->name, outs ? "Front Panel" : "Analog 2");
+ strscpy(pcm->name, outs ? "Front Panel" : "Analog 2");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pci->dev,
DEFAULT_BUFFER_BYTES,
@@ -773,7 +762,7 @@ int oxygen_pcm_init(struct oxygen *chip)
OXYGEN_REC_C_ROUTE_I2S_ADC_3,
OXYGEN_REC_C_ROUTE_MASK);
pcm->private_data = chip;
- strcpy(pcm->name, "Analog 3");
+ strscpy(pcm->name, "Analog 3");
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->pci->dev,
DEFAULT_BUFFER_BYTES,
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/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index 664b7759dd62..47b2758653e4 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -309,7 +309,7 @@ static int rolloff_put(struct snd_kcontrol *ctl,
int changed;
u8 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->cs4398_regs[7];
if (value->value.enumerated.item[0])
reg |= CS4398_FILT_SEL;
@@ -324,7 +324,6 @@ static int rolloff_put(struct snd_kcontrol *ctl,
reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL;
cs4362a_write(chip, 0x04, reg);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -340,11 +339,10 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
unsigned int reg, unsigned int mute)
{
if (reg == AC97_LINE) {
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
mute ? GPIO_D1_INPUT_ROUTE : 0,
GPIO_D1_INPUT_ROUTE);
- spin_unlock_irq(&chip->reg_lock);
}
}
diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c
index 198588562880..2179ff8e4d86 100644
--- a/sound/pci/oxygen/xonar_dg_mixer.c
+++ b/sound/pci/oxygen/xonar_dg_mixer.c
@@ -62,9 +62,8 @@ static int output_select_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.enumerated.item[0] = data->output_sel;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -77,14 +76,13 @@ static int output_select_put(struct snd_kcontrol *ctl,
int changed = 0;
int ret;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
if (data->output_sel != new) {
data->output_sel = new;
ret = output_select_apply(chip);
changed = ret >= 0 ? 1 : ret;
oxygen_update_dac_routing(chip);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -108,12 +106,11 @@ static int hp_stereo_volume_get(struct snd_kcontrol *ctl,
struct dg *data = chip->model_data;
unsigned int tmp;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
val->value.integer.value[0] = tmp;
tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
val->value.integer.value[1] = tmp;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -130,7 +127,7 @@ static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0))
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) ||
(data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) {
data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1;
@@ -140,7 +137,6 @@ static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
changed = ret >= 0 ? 1 : ret;
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -153,10 +149,9 @@ static int hp_mute_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
val->value.integer.value[0] =
!(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC);
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -170,13 +165,12 @@ static int hp_mute_put(struct snd_kcontrol *ctl,
if (val->value.integer.value[0] > 1)
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
(~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
changed = ret >= 0 ? 1 : ret;
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -212,10 +206,9 @@ static int input_vol_get(struct snd_kcontrol *ctl,
struct dg *data = chip->model_data;
unsigned int idx = ctl->private_value;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.integer.value[0] = data->input_vol[idx][0];
value->value.integer.value[1] = data->input_vol[idx][1];
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -233,7 +226,7 @@ static int input_vol_put(struct snd_kcontrol *ctl,
value->value.integer.value[1] < 2 * -12 ||
value->value.integer.value[1] > 2 * 12)
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
data->input_vol[idx][1] != value->value.integer.value[1];
if (changed) {
@@ -246,7 +239,6 @@ static int input_vol_put(struct snd_kcontrol *ctl,
}
changed = ret >= 0 ? 1 : ret;
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -282,9 +274,8 @@ static int input_sel_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.enumerated.item[0] = data->input_sel;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -299,7 +290,7 @@ static int input_sel_put(struct snd_kcontrol *ctl,
if (value->value.enumerated.item[0] > 3)
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = value->value.enumerated.item[0] != data->input_sel;
if (changed) {
data->input_sel = value->value.enumerated.item[0];
@@ -311,7 +302,6 @@ static int input_sel_put(struct snd_kcontrol *ctl,
data->input_vol[data->input_sel][1]);
changed = ret >= 0 ? 1 : ret;
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -341,7 +331,7 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
u8 reg;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
if (value->value.enumerated.item[0])
reg |= CS4245_HPF_FREEZE;
@@ -350,7 +340,6 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
data->cs4245_shadow[CS4245_ADC_CTRL] = reg;
cs4245_write_spi(chip, CS4245_ADC_CTRL);
}
- mutex_unlock(&chip->mutex);
return changed;
}
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c
index e951f5478075..0edf67ce37d1 100644
--- a/sound/pci/oxygen/xonar_lib.c
+++ b/sound/pci/oxygen/xonar_lib.c
@@ -109,7 +109,7 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
u16 old_bits, new_bits;
int changed;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
if (!!value->value.integer.value[0] ^ invert)
new_bits = old_bits | bit;
@@ -118,6 +118,5 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
changed = new_bits != old_bits;
if (changed)
oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
- spin_unlock_irq(&chip->reg_lock);
return changed;
}
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index cf801a235df9..837a9505382a 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -762,7 +762,7 @@ static int rolloff_put(struct snd_kcontrol *ctl,
int changed;
u8 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
reg &= ~PCM1796_FLT_MASK;
if (!value->value.enumerated.item[0])
@@ -774,7 +774,6 @@ static int rolloff_put(struct snd_kcontrol *ctl,
for (i = 0; i < data->dacs; ++i)
pcm1796_write(chip, i, 19, reg);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -806,7 +805,7 @@ static int deemph_put(struct snd_kcontrol *ctl,
int changed;
u8 reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->pcm1796_regs[0][18 - PCM1796_REG_BASE];
if (!value->value.integer.value[0])
reg &= ~PCM1796_DME;
@@ -817,7 +816,6 @@ static int deemph_put(struct snd_kcontrol *ctl,
for (i = 0; i < data->dacs; ++i)
pcm1796_write(chip, i, 18, reg);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -872,7 +870,7 @@ static int st_output_switch_put(struct snd_kcontrol *ctl,
struct xonar_pcm179x *data = chip->model_data;
u16 gpio_old, gpio;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
gpio = gpio_old;
switch (value->value.enumerated.item[0]) {
@@ -889,7 +887,6 @@ static int st_output_switch_put(struct snd_kcontrol *ctl,
oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
data->hp_active = gpio & GPIO_ST_HP;
update_pcm1796_volume(chip);
- mutex_unlock(&chip->mutex);
return gpio != gpio_old;
}
@@ -909,7 +906,7 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
struct xonar_pcm179x *data = chip->model_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
if (data->hp_gain_offset < 2*-12)
value->value.enumerated.item[0] = 0;
else if (data->hp_gain_offset < 2*-6)
@@ -918,7 +915,6 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
value->value.enumerated.item[0] = 2;
else
value->value.enumerated.item[0] = 3;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -935,13 +931,12 @@ static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
if (value->value.enumerated.item[0] > 3)
return -EINVAL;
offset = offsets[value->value.enumerated.item[0]];
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = offset != data->hp_gain_offset;
if (changed) {
data->hp_gain_offset = offset;
update_pcm1796_volume(chip);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -985,7 +980,7 @@ static int xense_output_switch_put(struct snd_kcontrol *ctl,
struct xonar_pcm179x *data = chip->model_data;
u16 gpio_old, gpio;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
gpio = gpio_old;
switch (value->value.enumerated.item[0]) {
@@ -1002,7 +997,6 @@ static int xense_output_switch_put(struct snd_kcontrol *ctl,
oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS);
update_pcm1796_volume(chip);
- mutex_unlock(&chip->mutex);
return gpio != gpio_old;
}
@@ -1027,11 +1021,10 @@ static void xonar_line_mic_ac97_switch(struct oxygen *chip,
unsigned int reg, unsigned int mute)
{
if (reg == AC97_LINE) {
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
mute ? GPIO_INPUT_ROUTE : 0,
GPIO_INPUT_ROUTE);
- spin_unlock_irq(&chip->reg_lock);
}
}
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index 8aa92f3e5ee8..7d92e6e20c39 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -237,7 +237,7 @@ static void xonar_ds_handle_hp_jack(struct oxygen *chip)
bool hp_plugged;
unsigned int reg;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
GPIO_DS_HP_DETECT);
@@ -252,8 +252,6 @@ static void xonar_ds_handle_hp_jack(struct oxygen *chip)
wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
-
- mutex_unlock(&chip->mutex);
}
static void xonar_ds_init(struct oxygen *chip)
@@ -521,14 +519,13 @@ static int wm8776_bit_switch_put(struct snd_kcontrol *ctl,
bool invert = (ctl->private_value >> 24) & 1;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg_value = data->wm8776_regs[reg_index] & ~bit;
if (value->value.integer.value[0] ^ invert)
reg_value |= bit;
changed = reg_value != data->wm8776_regs[reg_index];
if (changed)
wm8776_write(chip, reg_index, reg_value);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -648,13 +645,12 @@ static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value)
max = (ctl->private_value >> 12) & 0xf;
if (value < min || value > max)
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = value != (ctl->private_value & 0xf);
if (changed) {
ctl->private_value = (ctl->private_value & ~0xf) | value;
wm8776_field_set_from_ctl(ctl);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -700,12 +696,11 @@ static int wm8776_hp_vol_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
struct xonar_wm87x6 *data = chip->model_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.integer.value[0] =
data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK;
value->value.integer.value[1] =
data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -716,7 +711,7 @@ static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
struct xonar_wm87x6 *data = chip->model_data;
u8 to_update;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
to_update = (value->value.integer.value[0] !=
(data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK))
<< 0;
@@ -744,7 +739,6 @@ static int wm8776_hp_vol_put(struct snd_kcontrol *ctl,
value->value.integer.value[1] |
WM8776_HPZCEN | WM8776_UPDATE);
}
- mutex_unlock(&chip->mutex);
return to_update != 0;
}
@@ -770,7 +764,7 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
u16 reg;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->wm8776_regs[WM8776_ADCMUX];
if (value->value.integer.value[0]) {
reg |= mux_bit;
@@ -794,7 +788,6 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl,
GPIO_DS_INPUT_ROUTE);
wm8776_write(chip, WM8776_ADCMUX, reg);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -814,12 +807,11 @@ static int wm8776_input_vol_get(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
struct xonar_wm87x6 *data = chip->model_data;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
value->value.integer.value[0] =
data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK;
value->value.integer.value[1] =
data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK;
- mutex_unlock(&chip->mutex);
return 0;
}
@@ -830,7 +822,7 @@ static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
struct xonar_wm87x6 *data = chip->model_data;
int changed = 0;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = (value->value.integer.value[0] !=
(data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) ||
(value->value.integer.value[1] !=
@@ -839,7 +831,6 @@ static int wm8776_input_vol_put(struct snd_kcontrol *ctl,
value->value.integer.value[0] | WM8776_ZCA);
wm8776_write_cached(chip, WM8776_ADCRVOL,
value->value.integer.value[1] | WM8776_ZCA);
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -895,7 +886,7 @@ static int wm8776_level_control_put(struct snd_kcontrol *ctl,
if (value->value.enumerated.item[0] >= 3)
return -EINVAL;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
changed = value->value.enumerated.item[0] != ctl->private_value;
if (changed) {
ctl->private_value = value->value.enumerated.item[0];
@@ -926,7 +917,6 @@ static int wm8776_level_control_put(struct snd_kcontrol *ctl,
for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i)
activate_control(chip, data->lc_controls[i], mode);
}
- mutex_unlock(&chip->mutex);
return changed;
}
@@ -956,14 +946,13 @@ static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
unsigned int reg;
int changed;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD;
if (!value->value.enumerated.item[0])
reg |= WM8776_ADCHPD;
changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL];
if (changed)
wm8776_write(chip, WM8776_ADCIFCTRL, reg);
- mutex_unlock(&chip->mutex);
return changed;
}
diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile
index 5993d86cfb5d..0ea1e5ccb56f 100644
--- a/sound/pci/pcxhr/Makefile
+++ b/sound/pci/pcxhr/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o
+snd-pcxhr-y := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o
obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 242bd7e04b3e..83066d08367e 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -701,7 +701,7 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
start_time = ktime_get();
#endif
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
/* check the pipes concerned and build pipe_array */
for (i = 0; i < mgr->num_cards; i++) {
@@ -720,7 +720,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
}
}
if (capture_mask == 0 && playback_mask == 0) {
- mutex_unlock(&mgr->setup_mutex);
dev_err(&mgr->pci->dev, "%s : no pipes\n", __func__);
return;
}
@@ -731,7 +730,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
/* synchronous stop of all the pipes concerned */
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
if (err) {
- mutex_unlock(&mgr->setup_mutex);
dev_err(&mgr->pci->dev, "%s : "
"error stop pipes (P%x C%x)\n",
__func__, playback_mask, capture_mask);
@@ -776,7 +774,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
/* synchronous start of all the pipes concerned */
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
if (err) {
- mutex_unlock(&mgr->setup_mutex);
dev_err(&mgr->pci->dev, "%s : "
"error start pipes (P%x C%x)\n",
__func__, playback_mask, capture_mask);
@@ -786,7 +783,7 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
/* put the streams into the running state now
* (increment pointer by interrupt)
*/
- mutex_lock(&mgr->lock);
+ guard(mutex)(&mgr->lock);
for ( i =0; i < mgr->num_cards; i++) {
struct pcxhr_stream *stream;
chip = mgr->chip[i];
@@ -804,9 +801,6 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
}
}
}
- mutex_unlock(&mgr->lock);
-
- mutex_unlock(&mgr->setup_mutex);
#ifdef CONFIG_SND_DEBUG_VERBOSE
stop_time = ktime_get();
@@ -907,7 +901,7 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs)
subs->runtime->period_size, subs->runtime->periods,
subs->runtime->buffer_size);
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
do {
/* only the first stream can choose the sample rate */
@@ -923,8 +917,6 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs)
}
} while(0); /* do only once (so we can use break instead of goto) */
- mutex_unlock(&mgr->setup_mutex);
-
return err;
}
@@ -939,15 +931,13 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs,
struct pcxhr_mgr *mgr = chip->mgr;
struct pcxhr_stream *stream = subs->runtime->private_data;
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
/* set up channels */
stream->channels = params_channels(hw);
/* set up format for the stream */
stream->format = params_format(hw);
- mutex_unlock(&mgr->setup_mutex);
-
return 0;
}
@@ -990,7 +980,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
struct pcxhr_stream *stream;
int err;
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
/* copy the struct snd_pcm_hardware struct */
runtime->hw = pcxhr_caps;
@@ -1012,7 +1002,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
/* streams in use */
dev_err(chip->card->dev, "%s chip%d subs%d in use\n",
__func__, chip->chip_idx, subs->number);
- mutex_unlock(&mgr->setup_mutex);
return -EBUSY;
}
@@ -1023,10 +1012,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
/* buffer-size should better be multiple of period-size */
err = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0) {
- mutex_unlock(&mgr->setup_mutex);
+ if (err < 0)
return err;
- }
/* if a sample rate is already used or fixed by external clock,
* the stream cannot change
@@ -1040,7 +1027,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
&external_rate) ||
external_rate == 0) {
/* cannot detect the external clock rate */
- mutex_unlock(&mgr->setup_mutex);
return -EBUSY;
}
runtime->hw.rate_min = external_rate;
@@ -1063,7 +1049,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
mgr->ref_count_rate++;
- mutex_unlock(&mgr->setup_mutex);
return 0;
}
@@ -1074,7 +1059,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
struct pcxhr_mgr *mgr = chip->mgr;
struct pcxhr_stream *stream = subs->runtime->private_data;
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
dev_dbg(chip->card->dev, "%s chip%d subs%d\n", __func__,
chip->chip_idx, subs->number);
@@ -1088,8 +1073,6 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
stream->status = PCXHR_STREAM_STATUS_FREE;
stream->substream = NULL;
- mutex_unlock(&mgr->setup_mutex);
-
return 0;
}
@@ -1102,14 +1085,12 @@ static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs)
struct snd_pcm_runtime *runtime = subs->runtime;
struct pcxhr_stream *stream = runtime->private_data;
- mutex_lock(&chip->mgr->lock);
+ guard(mutex)(&chip->mgr->lock);
/* get the period fragment and the nb of periods in the buffer */
timer_period_frag = stream->timer_period_frag;
timer_buf_periods = stream->timer_buf_periods;
- mutex_unlock(&chip->mgr->lock);
-
return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) +
timer_period_frag);
}
@@ -1149,7 +1130,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip)
pcm->info_flags = 0;
pcm->nonatomic = true;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
&chip->mgr->pci->dev,
@@ -1605,7 +1586,7 @@ static int pcxhr_probe(struct pci_dev *pci,
return err;
}
- strcpy(card->driver, DRIVER_NAME);
+ strscpy(card->driver, DRIVER_NAME);
snprintf(card->shortname, sizeof(card->shortname),
"Digigram [PCM #%d]", i);
snprintf(card->longname, sizeof(card->longname),
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 23f253effb4f..b3b9ab4f303e 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -754,12 +754,8 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
*/
int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
{
- int err;
-
- mutex_lock(&mgr->msg_lock);
- err = pcxhr_send_msg_nolock(mgr, rmh);
- mutex_unlock(&mgr->msg_lock);
- return err;
+ guard(mutex)(&mgr->msg_lock);
+ return pcxhr_send_msg_nolock(mgr, rmh);
}
static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
@@ -962,14 +958,13 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
struct pcxhr_rmh rmh;
int err;
- mutex_lock(&mgr->msg_lock);
+ guard(mutex)(&mgr->msg_lock);
if ((mgr->io_num_reg_cont & mask) == value) {
dev_dbg(&mgr->pci->dev,
"IO_NUM_REG_CONT mask %x already is set to %x\n",
mask, value);
if (changed)
*changed = 0;
- mutex_unlock(&mgr->msg_lock);
return 0; /* already programmed */
}
pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
@@ -984,7 +979,6 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
if (changed)
*changed = 1;
}
- mutex_unlock(&mgr->msg_lock);
return err;
}
@@ -1269,7 +1263,7 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
int i, j;
struct snd_pcxhr *chip;
- mutex_lock(&mgr->lock);
+ guard(mutex)(&mgr->lock);
if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) {
/* is a 24 bit counter */
int dsp_time_new =
@@ -1328,6 +1322,5 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
}
pcxhr_msg_thread(mgr);
- mutex_unlock(&mgr->lock);
return IRQ_HANDLED;
}
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c
index f340458fd2e1..80d22e22ea30 100644
--- a/sound/pci/pcxhr/pcxhr_mix22.c
+++ b/sound/pci/pcxhr/pcxhr_mix22.c
@@ -535,7 +535,7 @@ int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
{
dev_dbg(chip->card->dev,
"hr222_update_analog_audio_level(%s chan=%d)\n",
- is_capture ? "capture" : "playback", channel);
+ snd_pcm_direction_name(is_capture), channel);
if (is_capture) {
int level_l, level_r, level_mic;
/* we have to update all levels */
@@ -710,9 +710,9 @@ static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->mic_volume;
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -721,13 +721,13 @@ static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol,
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (chip->mic_volume != ucontrol->value.integer.value[0]) {
changed = 1;
chip->mic_volume = ucontrol->value.integer.value[0];
hr222_update_analog_audio_level(chip, 1, 0);
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -760,9 +760,9 @@ static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->mic_boost;
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -771,13 +771,13 @@ static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol,
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (chip->mic_boost != ucontrol->value.integer.value[0]) {
changed = 1;
chip->mic_boost = ucontrol->value.integer.value[0];
hr222_micro_boost(chip->mgr, chip->mic_boost);
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -800,9 +800,9 @@ static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->phantom_power;
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -812,14 +812,13 @@ static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol,
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int power, changed = 0;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
power = !!ucontrol->value.integer.value[0];
if (chip->phantom_power != power) {
hr222_phantom_power(chip->mgr, power);
chip->phantom_power = power;
changed = 1;
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index aec509461dd6..03daa2832b1b 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -110,7 +110,8 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (kcontrol->private_value == 0) { /* playback */
ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
@@ -118,7 +119,6 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -129,7 +129,7 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol,
int changed = 0;
int is_capture, i;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
is_capture = (kcontrol->private_value != 0);
for (i = 0; i < 2; i++) {
int new_volume = ucontrol->value.integer.value[i];
@@ -168,7 +168,6 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol,
is_capture, i);
}
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -192,10 +191,9 @@ static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol,
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -204,7 +202,8 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol,
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int i, changed = 0;
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
for(i = 0; i < 2; i++) {
if (chip->analog_playback_active[i] !=
ucontrol->value.integer.value[i]) {
@@ -218,7 +217,6 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol,
pcxhr_update_analog_audio_level(chip, 0, i);
}
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -352,14 +350,13 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol,
int *stored_volume;
int is_capture = kcontrol->private_value;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (is_capture) /* digital capture */
stored_volume = chip->digital_capture_volume;
else /* digital playback */
stored_volume = chip->digital_playback_volume[idx];
ucontrol->value.integer.value[0] = stored_volume[0];
ucontrol->value.integer.value[1] = stored_volume[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -373,7 +370,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol,
int *stored_volume;
int i;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (is_capture) /* digital capture */
stored_volume = chip->digital_capture_volume;
else /* digital playback */
@@ -392,7 +389,6 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol,
}
if (!is_capture && changed) /* update playback volume */
pcxhr_update_playback_stream_level(chip, idx);
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -416,10 +412,9 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol,
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -431,7 +426,7 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol,
int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
int i, j;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
j = idx;
for (i = 0; i < 2; i++) {
if (chip->digital_playback_active[j][i] !=
@@ -443,7 +438,6 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol,
}
if (changed)
pcxhr_update_playback_stream_level(chip, idx);
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -465,10 +459,10 @@ static int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -479,7 +473,7 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol,
int changed = 0;
int i;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
for (i = 0; i < 2; i++) {
if (chip->monitoring_volume[i] !=
ucontrol->value.integer.value[i]) {
@@ -492,7 +486,6 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol,
changed = 1;
}
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
@@ -515,10 +508,10 @@ static int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
- mutex_lock(&chip->mgr->mixer_mutex);
+
+ guard(mutex)(&chip->mgr->mixer_mutex);
ucontrol->value.integer.value[0] = chip->monitoring_active[0];
ucontrol->value.integer.value[1] = chip->monitoring_active[1];
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -529,7 +522,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol,
int changed = 0;
int i;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
for (i = 0; i < 2; i++) {
if (chip->monitoring_active[i] !=
ucontrol->value.integer.value[i]) {
@@ -545,7 +538,6 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol,
/* update right monitoring volume and mute */
pcxhr_update_audio_pipe_level(chip, 0, 1);
- mutex_unlock(&chip->mgr->mixer_mutex);
return (changed != 0);
}
@@ -671,7 +663,7 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol,
}
if (ucontrol->value.enumerated.item[0] >= i)
return -EINVAL;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) {
chip->audio_capture_source = ucontrol->value.enumerated.item[0];
if (chip->mgr->is_hr_stereo)
@@ -680,7 +672,6 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol,
pcxhr_set_audio_source(chip);
ret = 1;
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return ret;
}
@@ -760,9 +751,9 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
}
if (ucontrol->value.enumerated.item[0] >= clock_items)
return -EINVAL;
- mutex_lock(&mgr->mixer_mutex);
+ guard(mutex)(&mgr->mixer_mutex);
if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
- mutex_lock(&mgr->setup_mutex);
+ guard(mutex)(&mgr->setup_mutex);
mgr->use_clock_type = ucontrol->value.enumerated.item[0];
rate = 0;
if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) {
@@ -778,10 +769,8 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
if (mgr->sample_rate)
mgr->sample_rate = rate;
}
- mutex_unlock(&mgr->setup_mutex);
ret = 1; /* return 1 even if the set was not done. ok ? */
}
- mutex_unlock(&mgr->mixer_mutex);
return ret;
}
@@ -814,7 +803,7 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol,
struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
int i, err, rate;
- mutex_lock(&mgr->mixer_mutex);
+ guard(mutex)(&mgr->mixer_mutex);
for(i = 0; i < 3 + mgr->capture_chips; i++) {
if (i == PCXHR_CLOCK_TYPE_INTERNAL)
rate = mgr->sample_rate_real;
@@ -825,7 +814,6 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol,
}
ucontrol->value.integer.value[i] = rate;
}
- mutex_unlock(&mgr->mixer_mutex);
return 0;
}
@@ -918,7 +906,7 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol,
unsigned char aes_bits;
int i, err;
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
for(i = 0; i < 5; i++) {
if (kcontrol->private_value == 0) /* playback */
aes_bits = chip->aes_bits[i];
@@ -934,7 +922,6 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol,
}
ucontrol->value.iec958.status[i] = aes_bits;
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return 0;
}
@@ -988,7 +975,7 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol,
int i, changed = 0;
/* playback */
- mutex_lock(&chip->mgr->mixer_mutex);
+ guard(mutex)(&chip->mgr->mixer_mutex);
for (i = 0; i < 5; i++) {
if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) {
if (chip->mgr->is_hr_stereo)
@@ -1000,7 +987,6 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol,
changed = 1;
}
}
- mutex_unlock(&chip->mgr->mixer_mutex);
return changed;
}
diff --git a/sound/pci/riptide/Makefile b/sound/pci/riptide/Makefile
index 9a505bae243e..9b4e9595859a 100644
--- a/sound/pci/riptide/Makefile
+++ b/sound/pci/riptide/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-riptide-objs := riptide.o
+snd-riptide-y := riptide.o
obj-$(CONFIG_SND_RIPTIDE) += snd-riptide.o
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index b37c877c2c16..e983cd657e28 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -380,6 +380,7 @@ struct riptideport {
};
struct cmdif {
+ struct device *dev;
struct riptideport *hwport;
spinlock_t lock;
unsigned int cmdcnt; /* cmd statistics */
@@ -448,9 +449,7 @@ struct snd_riptide {
unsigned long received_irqs;
unsigned long handled_irqs;
-#ifdef CONFIG_PM_SLEEP
int in_suspend;
-#endif
};
struct sgd { /* scatter gather desriptor */
@@ -729,7 +728,7 @@ static int loadfirmware(struct cmdif *cif, const unsigned char *img,
}
}
}
- snd_printdd("load firmware return %d\n", err);
+ dev_dbg(cif->dev, "load firmware return %d\n", err);
return err;
}
@@ -742,7 +741,7 @@ alloclbuspath(struct cmdif *cif, unsigned char source,
sink = *path & (~SPLIT_PATH);
if (sink != E2SINK_MAX) {
- snd_printdd("alloc path 0x%x->0x%x\n", source, sink);
+ dev_dbg(cif->dev, "alloc path 0x%x->0x%x\n", source, sink);
SEND_PSEL(cif, source, sink);
source = lbusin2out[sink][0];
type = lbusin2out[sink][1];
@@ -780,7 +779,7 @@ freelbuspath(struct cmdif *cif, unsigned char source, const unsigned char *path)
sink = *path & (~SPLIT_PATH);
if (sink != E2SINK_MAX) {
- snd_printdd("free path 0x%x->0x%x\n", source, sink);
+ dev_dbg(cif->dev, "free path 0x%x->0x%x\n", source, sink);
SEND_PCLR(cif, source, sink);
source = lbusin2out[sink][0];
}
@@ -813,8 +812,8 @@ static int writearm(struct cmdif *cif, u32 addr, u32 data, u32 mask)
} else
rptr.retlongs[0] &= ~mask;
}
- snd_printdd("send arm 0x%x 0x%x 0x%x return %d\n", addr, data, mask,
- flag);
+ dev_dbg(cif->dev, "send arm 0x%x 0x%x 0x%x return %d\n", addr, data, mask,
+ flag);
return flag;
}
@@ -834,14 +833,14 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm,
hwport = cif->hwport;
if (cif->errcnt > MAX_ERROR_COUNT) {
if (cif->is_reset) {
- snd_printk(KERN_ERR
- "Riptide: Too many failed cmds, reinitializing\n");
+ dev_err(cif->dev,
+ "Riptide: Too many failed cmds, reinitializing\n");
if (riptide_reset(cif, NULL) == 0) {
cif->errcnt = 0;
return -EIO;
}
}
- snd_printk(KERN_ERR "Riptide: Initialization failed.\n");
+ dev_err(cif->dev, "Riptide: Initialization failed.\n");
return -EINVAL;
}
if (ret) {
@@ -901,21 +900,21 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm,
if (time < cif->cmdtimemin)
cif->cmdtimemin = time;
if ((cif->cmdcnt) % 1000 == 0)
- snd_printdd
- ("send cmd %d time: %d mintime: %d maxtime %d err: %d\n",
- cif->cmdcnt, cif->cmdtime, cif->cmdtimemin,
- cif->cmdtimemax, cif->errcnt);
+ dev_dbg(cif->dev,
+ "send cmd %d time: %d mintime: %d maxtime %d err: %d\n",
+ cif->cmdcnt, cif->cmdtime, cif->cmdtimemin,
+ cif->cmdtimemax, cif->errcnt);
return 0;
errout:
cif->errcnt++;
spin_unlock_irqrestore(&cif->lock, irqflags);
- snd_printdd
- ("send cmd %d hw: 0x%x flag: 0x%x cmd: 0x%x parm: 0x%x ret: 0x%x 0x%x CMDE: %d DATF: %d failed %d\n",
- cif->cmdcnt, (int)((void *)&(cmdport->stat) - (void *)hwport),
- flags, cmd, parm, ret ? ret->retlongs[0] : 0,
- ret ? ret->retlongs[1] : 0, IS_CMDE(cmdport), IS_DATF(cmdport),
- err);
+ dev_dbg(cif->dev,
+ "send cmd %d hw: 0x%x flag: 0x%x cmd: 0x%x parm: 0x%x ret: 0x%x 0x%x CMDE: %d DATF: %d failed %d\n",
+ cif->cmdcnt, (int)((void *)&(cmdport->stat) - (void *)hwport),
+ flags, cmd, parm, ret ? ret->retlongs[0] : 0,
+ ret ? ret->retlongs[1] : 0, IS_CMDE(cmdport), IS_DATF(cmdport),
+ err);
return err;
}
@@ -925,14 +924,14 @@ setmixer(struct cmdif *cif, short num, unsigned short rval, unsigned short lval)
union cmdret rptr = CMDRET_ZERO;
int i = 0;
- snd_printdd("sent mixer %d: 0x%x 0x%x\n", num, rval, lval);
+ dev_dbg(cif->dev, "sent mixer %d: 0x%x 0x%x\n", num, rval, lval);
do {
SEND_SDGV(cif, num, num, rval, lval);
SEND_RDGV(cif, num, num, &rptr);
if (rptr.retwords[0] == lval && rptr.retwords[1] == rval)
return 0;
} while (i++ < MAX_WRITE_RETRY);
- snd_printdd("sent mixer failed\n");
+ dev_dbg(cif->dev, "sent mixer failed\n");
return -EIO;
}
@@ -963,7 +962,7 @@ getsourcesink(struct cmdif *cif, unsigned char source, unsigned char sink,
return -EIO;
*a = rptr.retbytes[0];
*b = rptr.retbytes[1];
- snd_printdd("getsourcesink 0x%x 0x%x\n", *a, *b);
+ dev_dbg(cif->dev, "%s 0x%x 0x%x\n", __func__, *a, *b);
return 0;
}
@@ -990,11 +989,11 @@ getsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int *rate)
}
if (p[0]) {
if (p[1] != p[0])
- snd_printdd("rates differ %d %d\n", p[0], p[1]);
+ dev_dbg(cif->dev, "rates differ %d %d\n", p[0], p[1]);
*rate = (unsigned int)p[0];
} else
*rate = (unsigned int)p[1];
- snd_printdd("getsampleformat %d %d %d\n", intdec[0], intdec[1], *rate);
+ dev_dbg(cif->dev, "getsampleformat %d %d %d\n", intdec[0], intdec[1], *rate);
return 0;
}
@@ -1005,9 +1004,9 @@ setsampleformat(struct cmdif *cif,
{
unsigned char w, ch, sig, order;
- snd_printdd
- ("setsampleformat mixer: %d id: %d channels: %d format: %d\n",
- mixer, id, channels, format);
+ dev_dbg(cif->dev,
+ "%s mixer: %d id: %d channels: %d format: %d\n",
+ __func__, mixer, id, channels, format);
ch = channels == 1;
w = snd_pcm_format_width(format) == 8;
sig = snd_pcm_format_unsigned(format) != 0;
@@ -1015,7 +1014,7 @@ setsampleformat(struct cmdif *cif,
if (SEND_SETF(cif, mixer, w, ch, order, sig, id) &&
SEND_SETF(cif, mixer, w, ch, order, sig, id)) {
- snd_printdd("setsampleformat failed\n");
+ dev_dbg(cif->dev, "%s failed\n", __func__);
return -EIO;
}
return 0;
@@ -1028,8 +1027,8 @@ setsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int rate)
union cmdret rptr = CMDRET_ZERO;
int i;
- snd_printdd("setsamplerate intdec: %d,%d rate: %d\n", intdec[0],
- intdec[1], rate);
+ dev_dbg(cif->dev, "%s intdec: %d,%d rate: %d\n", __func__,
+ intdec[0], intdec[1], rate);
D = 48000;
M = ((rate == 48000) ? 47999 : rate) * 65536;
N = M % D;
@@ -1044,8 +1043,8 @@ setsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int rate)
rptr.retwords[3] != N &&
i++ < MAX_WRITE_RETRY);
if (i > MAX_WRITE_RETRY) {
- snd_printdd("sent samplerate %d: %d failed\n",
- *intdec, rate);
+ dev_dbg(cif->dev, "sent samplerate %d: %d failed\n",
+ *intdec, rate);
return -EIO;
}
}
@@ -1064,7 +1063,7 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval,
return -EIO;
*rval = rptr.retwords[0];
*lval = rptr.retwords[1];
- snd_printdd("got mixer %d: 0x%x 0x%x\n", num, *rval, *lval);
+ dev_dbg(cif->dev, "got mixer %d: 0x%x 0x%x\n", num, *rval, *lval);
return 0;
}
@@ -1107,8 +1106,8 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id)
if ((flag & EOS_STATUS)
&& (data->state == ST_PLAY)) {
data->state = ST_STOP;
- snd_printk(KERN_ERR
- "Riptide: DMA stopped unexpectedly\n");
+ dev_err(cif->dev,
+ "Riptide: DMA stopped unexpectedly\n");
}
c->dwStat_Ctl =
cpu_to_le32(flag &
@@ -1121,11 +1120,11 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id)
period_bytes =
frames_to_bytes(runtime,
runtime->period_size);
- snd_printdd
- ("interrupt 0x%x after 0x%lx of 0x%lx frames in period\n",
- READ_AUDIO_STATUS(cif->hwport),
- bytes_to_frames(runtime, pos),
- runtime->period_size);
+ dev_dbg(cif->dev,
+ "interrupt 0x%x after 0x%lx of 0x%lx frames in period\n",
+ READ_AUDIO_STATUS(cif->hwport),
+ bytes_to_frames(runtime, pos),
+ runtime->period_size);
j = 0;
if (pos >= period_bytes) {
j++;
@@ -1142,7 +1141,6 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-#ifdef CONFIG_PM_SLEEP
static int riptide_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -1166,11 +1164,7 @@ static int riptide_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
-#define RIPTIDE_PM_OPS &riptide_pm
-#else
-#define RIPTIDE_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
{
@@ -1191,23 +1185,23 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
break;
}
if (!timeout) {
- snd_printk(KERN_ERR
- "Riptide: device not ready, audio status: 0x%x "
- "ready: %d gerr: %d\n",
- READ_AUDIO_STATUS(cif->hwport),
- IS_READY(cif->hwport), IS_GERR(cif->hwport));
+ dev_err(cif->dev,
+ "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n",
+ READ_AUDIO_STATUS(cif->hwport),
+ IS_READY(cif->hwport), IS_GERR(cif->hwport));
return -EIO;
} else {
- snd_printdd
- ("Riptide: audio status: 0x%x ready: %d gerr: %d\n",
- READ_AUDIO_STATUS(cif->hwport),
- IS_READY(cif->hwport), IS_GERR(cif->hwport));
+ dev_dbg(cif->dev,
+ "Riptide: audio status: 0x%x ready: %d gerr: %d\n",
+ READ_AUDIO_STATUS(cif->hwport),
+ IS_READY(cif->hwport), IS_GERR(cif->hwport));
}
SEND_GETV(cif, &firmware.ret);
- snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
- firmware.firmware.ASIC, firmware.firmware.CODEC,
- firmware.firmware.AUXDSP, firmware.firmware.PROG);
+ dev_dbg(cif->dev,
+ "Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n",
+ firmware.firmware.ASIC, firmware.firmware.CODEC,
+ firmware.firmware.AUXDSP, firmware.firmware.PROG);
if (!chip)
return 1;
@@ -1218,20 +1212,20 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
}
- snd_printdd("Writing Firmware\n");
+ dev_dbg(cif->dev, "Writing Firmware\n");
if (!chip->fw_entry) {
err = request_firmware(&chip->fw_entry, "riptide.hex",
&chip->pci->dev);
if (err) {
- snd_printk(KERN_ERR
- "Riptide: Firmware not available %d\n", err);
+ dev_err(cif->dev,
+ "Riptide: Firmware not available %d\n", err);
return -EIO;
}
}
err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size);
if (err) {
- snd_printk(KERN_ERR
- "Riptide: Could not load firmware %d\n", err);
+ dev_err(cif->dev,
+ "Riptide: Could not load firmware %d\n", err);
return err;
}
@@ -1264,7 +1258,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip)
SEND_SACR(cif, 0, AC97_RESET);
SEND_RACR(cif, AC97_RESET, &rptr);
- snd_printdd("AC97: 0x%x 0x%x\n", rptr.retlongs[0], rptr.retlongs[1]);
+ dev_dbg(cif->dev, "AC97: 0x%x 0x%x\n", rptr.retlongs[0], rptr.retlongs[1]);
SEND_PLST(cif, 0);
SEND_SLST(cif, 0);
@@ -1357,11 +1351,11 @@ static snd_pcm_uframes_t snd_riptide_pointer(struct snd_pcm_substream
SEND_GPOS(cif, 0, data->id, &rptr);
if (data->size && runtime->period_size) {
- snd_printdd
- ("pointer stream %d position 0x%x(0x%x in buffer) bytes 0x%lx(0x%lx in period) frames\n",
- data->id, rptr.retlongs[1], rptr.retlongs[1] % data->size,
- bytes_to_frames(runtime, rptr.retlongs[1]),
- bytes_to_frames(runtime,
+ dev_dbg(cif->dev,
+ "pointer stream %d position 0x%x(0x%x in buffer) bytes 0x%lx(0x%lx in period) frames\n",
+ data->id, rptr.retlongs[1], rptr.retlongs[1] % data->size,
+ bytes_to_frames(runtime, rptr.retlongs[1]),
+ bytes_to_frames(runtime,
rptr.retlongs[1]) % runtime->period_size);
if (rptr.retlongs[1] > data->pointer)
ret =
@@ -1372,8 +1366,9 @@ static snd_pcm_uframes_t snd_riptide_pointer(struct snd_pcm_substream
bytes_to_frames(runtime,
data->pointer % data->size);
} else {
- snd_printdd("stream not started or strange parms (%d %ld)\n",
- data->size, runtime->period_size);
+ dev_dbg(cif->dev,
+ "stream not started or strange parms (%d %ld)\n",
+ data->size, runtime->period_size);
ret = bytes_to_frames(runtime, 0);
}
return ret;
@@ -1417,7 +1412,7 @@ static int snd_riptide_trigger(struct snd_pcm_substream *substream, int cmd)
udelay(1);
} while (i != rptr.retlongs[1] && j++ < MAX_WRITE_RETRY);
if (j > MAX_WRITE_RETRY)
- snd_printk(KERN_ERR "Riptide: Could not stop stream!");
+ dev_err(cif->dev, "Riptide: Could not stop stream!");
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (!(data->state & ST_PAUSE)) {
@@ -1455,8 +1450,8 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
if (snd_BUG_ON(!cif || !data))
return -EINVAL;
- snd_printdd("prepare id %d ch: %d f:0x%x r:%d\n", data->id,
- runtime->channels, runtime->format, runtime->rate);
+ dev_dbg(cif->dev, "prepare id %d ch: %d f:0x%x r:%d\n", data->id,
+ runtime->channels, runtime->format, runtime->rate);
spin_lock_irq(&chip->lock);
channels = runtime->channels;
@@ -1476,8 +1471,7 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
lbuspath = data->paths.stereo;
break;
}
- snd_printdd("use sgdlist at 0x%p\n",
- data->sgdlist.area);
+ dev_dbg(cif->dev, "use sgdlist at 0x%p\n", data->sgdlist.area);
if (data->sgdlist.area) {
unsigned int i, j, size, pages, f, pt, period;
struct sgd *c, *p = NULL;
@@ -1490,9 +1484,9 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream)
pages = DIV_ROUND_UP(size, f);
data->size = size;
data->pages = pages;
- snd_printdd
- ("create sgd size: 0x%x pages %d of size 0x%x for period 0x%x\n",
- size, pages, f, period);
+ dev_dbg(cif->dev,
+ "create sgd size: 0x%x pages %d of size 0x%x for period 0x%x\n",
+ size, pages, f, period);
pt = 0;
j = 0;
for (i = 0; i < pages; i++) {
@@ -1550,17 +1544,18 @@ snd_riptide_hw_params(struct snd_pcm_substream *substream,
struct snd_dma_buffer *sgdlist = &data->sgdlist;
int err;
- snd_printdd("hw params id %d (sgdlist: 0x%p 0x%lx %d)\n", data->id,
- sgdlist->area, (unsigned long)sgdlist->addr,
- (int)sgdlist->bytes);
+ dev_dbg(chip->card->dev, "hw params id %d (sgdlist: 0x%p 0x%lx %d)\n",
+ data->id, sgdlist->area, (unsigned long)sgdlist->addr,
+ (int)sgdlist->bytes);
if (sgdlist->area)
snd_dma_free_pages(sgdlist);
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev,
sizeof(struct sgd) * (DESC_MAX_MASK + 1),
sgdlist);
if (err < 0) {
- snd_printk(KERN_ERR "Riptide: failed to alloc %d dma bytes\n",
- (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1));
+ dev_err(chip->card->dev,
+ "Riptide: failed to alloc %d dma bytes\n",
+ (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1));
return err;
}
data->sgdbuf = (struct sgd *)sgdlist->area;
@@ -1693,7 +1688,7 @@ static int snd_riptide_pcm(struct snd_riptide *chip, int device)
&snd_riptide_capture_ops);
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, "RIPTIDE");
+ strscpy(pcm->name, "RIPTIDE");
chip->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
&chip->pci->dev, 64 * 1024, 128 * 1024);
@@ -1736,13 +1731,13 @@ snd_riptide_codec_write(struct snd_ac97 *ac97, unsigned short reg,
if (snd_BUG_ON(!cif))
return;
- snd_printdd("Write AC97 reg 0x%x 0x%x\n", reg, val);
+ dev_dbg(cif->dev, "Write AC97 reg 0x%x 0x%x\n", reg, val);
do {
SEND_SACR(cif, val, reg);
SEND_RACR(cif, reg, &rptr);
} while (rptr.retwords[1] != val && i++ < MAX_WRITE_RETRY);
if (i > MAX_WRITE_RETRY)
- snd_printdd("Write AC97 reg failed\n");
+ dev_dbg(cif->dev, "Write AC97 reg failed\n");
}
static unsigned short snd_riptide_codec_read(struct snd_ac97 *ac97,
@@ -1757,7 +1752,7 @@ static unsigned short snd_riptide_codec_read(struct snd_ac97 *ac97,
if (SEND_RACR(cif, reg, &rptr) != 0)
SEND_RACR(cif, reg, &rptr);
- snd_printdd("Read AC97 reg 0x%x got 0x%x\n", reg, rptr.retwords[1]);
+ dev_dbg(cif->dev, "Read AC97 reg 0x%x got 0x%x\n", reg, rptr.retwords[1]);
return rptr.retwords[1];
}
@@ -1775,6 +1770,7 @@ static int snd_riptide_initialize(struct snd_riptide *chip)
cif = kzalloc(sizeof(struct cmdif), GFP_KERNEL);
if (!cif)
return -ENOMEM;
+ cif->dev = chip->card->dev;
cif->hwport = (struct riptideport *)chip->port;
spin_lock_init(&cif->lock);
chip->cif = cif;
@@ -1788,11 +1784,11 @@ static int snd_riptide_initialize(struct snd_riptide *chip)
case 0x4310:
case 0x4320:
case 0x4330:
- snd_printdd("Modem enable?\n");
+ dev_dbg(cif->dev, "Modem enable?\n");
SEND_SETDPLL(cif);
break;
}
- snd_printdd("Enabling MPU IRQs\n");
+ dev_dbg(cif->dev, "Enabling MPU IRQs\n");
if (chip->rmidi)
SET_EMPUIRQ(cif->hwport);
return err;
@@ -1835,7 +1831,7 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci)
chip->cif = NULL;
card->private_free = snd_riptide_free;
- err = pci_request_regions(pci, "RIPTIDE");
+ err = pcim_request_all_regions(pci, "RIPTIDE");
if (err < 0)
return err;
hwport = (struct riptideport *)chip->port;
@@ -1845,8 +1841,8 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci)
snd_riptide_interrupt,
riptide_handleirq, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n",
- pci->irq);
+ dev_err(&pci->dev, "Riptide: unable to grab IRQ %d\n",
+ pci->irq);
return -EBUSY;
}
chip->irq = pci->irq;
@@ -1994,9 +1990,9 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
goto inc_dev;
}
if (!request_region(joystick_port[dev], 8, "Riptide gameport")) {
- snd_printk(KERN_WARNING
- "Riptide: cannot grab gameport 0x%x\n",
- joystick_port[dev]);
+ dev_err(&pci->dev,
+ "Riptide: cannot grab gameport 0x%x\n",
+ joystick_port[dev]);
gameport_free_port(gameport);
ret = -EBUSY;
goto inc_dev;
@@ -2071,9 +2067,9 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
val, MPU401_INFO_IRQ_HOOK, -1,
&chip->rmidi);
if (err < 0)
- snd_printk(KERN_WARNING
- "Riptide: Can't Allocate MPU at 0x%x\n",
- val);
+ dev_warn(&pci->dev,
+ "Riptide: Can't Allocate MPU at 0x%x\n",
+ val);
else
chip->mpuaddr = val;
}
@@ -2083,15 +2079,15 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
err = snd_opl3_create(card, val, val + 2,
OPL3_HW_RIPTIDE, 0, &chip->opl3);
if (err < 0)
- snd_printk(KERN_WARNING
- "Riptide: Can't Allocate OPL3 at 0x%x\n",
- val);
+ dev_warn(&pci->dev,
+ "Riptide: Can't Allocate OPL3 at 0x%x\n",
+ val);
else {
chip->opladdr = val;
err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL);
if (err < 0)
- snd_printk(KERN_WARNING
- "Riptide: Can't Allocate OPL3-HWDEP\n");
+ dev_warn(&pci->dev,
+ "Riptide: Can't Allocate OPL3-HWDEP\n");
}
}
#ifdef SUPPORT_JOYSTICK
@@ -2102,18 +2098,18 @@ __snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
}
#endif
- strcpy(card->driver, "RIPTIDE");
- strcpy(card->shortname, "Riptide");
+ strscpy(card->driver, "RIPTIDE");
+ strscpy(card->shortname, "Riptide");
#ifdef SUPPORT_JOYSTICK
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x gameport 0x%x",
- card->shortname, chip->port, chip->irq, chip->mpuaddr,
- chip->opladdr, chip->gameaddr);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x gameport 0x%x",
+ card->shortname, chip->port, chip->irq, chip->mpuaddr,
+ chip->opladdr, chip->gameaddr);
#else
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x",
- card->shortname, chip->port, chip->irq, chip->mpuaddr,
- chip->opladdr);
+ scnprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, irq %i mpu 0x%x opl3 0x%x",
+ card->shortname, chip->port, chip->irq, chip->mpuaddr,
+ chip->opladdr);
#endif
snd_riptide_proc_init(chip);
err = snd_card_register(card);
@@ -2135,7 +2131,7 @@ static struct pci_driver driver = {
.id_table = snd_riptide_ids,
.probe = snd_card_riptide_probe,
.driver = {
- .pm = RIPTIDE_PM_OPS,
+ .pm = &riptide_pm,
},
};
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 9c0ac025e143..ca9bbf554650 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -252,50 +252,29 @@ static int snd_rme32_playback_silence(struct snd_pcm_substream *substream,
/* copy callback for halfduplex mode */
static int snd_rme32_playback_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- if (copy_from_user_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;
}
-static int snd_rme32_playback_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
-{
- struct rme32 *rme32 = snd_pcm_substream_chip(substream);
-
- memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, src, count);
- return 0;
-}
-
/* copy callback for halfduplex mode */
static int snd_rme32_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- if (copy_to_user_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;
}
-static int snd_rme32_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
-{
- struct rme32 *rme32 = snd_pcm_substream_chip(substream);
-
- memcpy_fromio(dst, rme32->iobase + RME32_IO_DATA_BUFFER + pos, count);
- return 0;
-}
-
/*
* SPDIF I/O capabilities (half-duplex mode)
*/
@@ -667,35 +646,27 @@ snd_rme32_playback_hw_params(struct snd_pcm_substream *substream,
runtime->dma_bytes = RME32_BUFFER_SIZE;
}
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
rate = 0;
if (rme32->rcreg & RME32_RCR_KMODE)
rate = snd_rme32_capture_getrate(rme32, &dummy);
if (rate > 0) {
/* AutoSync */
- if ((int)params_rate(params) != rate) {
- spin_unlock_irq(&rme32->lock);
+ if ((int)params_rate(params) != rate)
return -EIO;
- }
} else {
err = snd_rme32_playback_setrate(rme32, params_rate(params));
- if (err < 0) {
- spin_unlock_irq(&rme32->lock);
+ if (err < 0)
return err;
- }
}
err = snd_rme32_setformat(rme32, params_format(params));
- if (err < 0) {
- spin_unlock_irq(&rme32->lock);
+ if (err < 0)
return err;
- }
snd_rme32_setframelog(rme32, params_channels(params), 1);
if (rme32->capture_periodsize != 0) {
- if (params_period_size(params) << rme32->playback_frlog != rme32->capture_periodsize) {
- spin_unlock_irq(&rme32->lock);
+ if (params_period_size(params) << rme32->playback_frlog != rme32->capture_periodsize)
return -EBUSY;
- }
}
rme32->playback_periodsize = params_period_size(params) << rme32->playback_frlog;
/* S/PDIF setup */
@@ -704,7 +675,6 @@ snd_rme32_playback_hw_params(struct snd_pcm_substream *substream,
rme32->wcreg |= rme32->wcreg_spdif_stream;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
}
- spin_unlock_irq(&rme32->lock);
return 0;
}
@@ -724,32 +694,24 @@ snd_rme32_capture_hw_params(struct snd_pcm_substream *substream,
runtime->dma_bytes = RME32_BUFFER_SIZE;
}
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
/* enable AutoSync for record-preparing */
rme32->wcreg |= RME32_WCR_AUTOSYNC;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
err = snd_rme32_setformat(rme32, params_format(params));
- if (err < 0) {
- spin_unlock_irq(&rme32->lock);
+ if (err < 0)
return err;
- }
err = snd_rme32_playback_setrate(rme32, params_rate(params));
- if (err < 0) {
- spin_unlock_irq(&rme32->lock);
+ if (err < 0)
return err;
- }
rate = snd_rme32_capture_getrate(rme32, &isadat);
if (rate > 0) {
- if ((int)params_rate(params) != rate) {
- spin_unlock_irq(&rme32->lock);
+ if ((int)params_rate(params) != rate)
return -EIO;
- }
if ((isadat && runtime->hw.channels_min == 2) ||
- (!isadat && runtime->hw.channels_min == 8)) {
- spin_unlock_irq(&rme32->lock);
+ (!isadat && runtime->hw.channels_min == 8))
return -EIO;
- }
}
/* AutoSync off for recording */
rme32->wcreg &= ~RME32_WCR_AUTOSYNC;
@@ -758,14 +720,11 @@ snd_rme32_capture_hw_params(struct snd_pcm_substream *substream,
snd_rme32_setframelog(rme32, params_channels(params), 0);
if (rme32->playback_periodsize != 0) {
if (params_period_size(params) << rme32->capture_frlog !=
- rme32->playback_periodsize) {
- spin_unlock_irq(&rme32->lock);
+ rme32->playback_periodsize)
return -EBUSY;
- }
}
rme32->capture_periodsize =
params_period_size(params) << rme32->capture_frlog;
- spin_unlock_irq(&rme32->lock);
return 0;
}
@@ -845,15 +804,13 @@ static int snd_rme32_playback_spdif_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
- spin_lock_irq(&rme32->lock);
- if (rme32->playback_substream != NULL) {
- spin_unlock_irq(&rme32->lock);
- return -EBUSY;
+ scoped_guard(spinlock_irq, &rme32->lock) {
+ if (rme32->playback_substream != NULL)
+ return -EBUSY;
+ rme32->wcreg &= ~RME32_WCR_ADAT;
+ writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
+ rme32->playback_substream = substream;
}
- rme32->wcreg &= ~RME32_WCR_ADAT;
- writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
- rme32->playback_substream = substream;
- spin_unlock_irq(&rme32->lock);
if (rme32->fullduplex_mode)
runtime->hw = snd_rme32_spdif_fd_info;
@@ -890,13 +847,11 @@ static int snd_rme32_capture_spdif_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
- spin_lock_irq(&rme32->lock);
- if (rme32->capture_substream != NULL) {
- spin_unlock_irq(&rme32->lock);
- return -EBUSY;
- }
- rme32->capture_substream = substream;
- spin_unlock_irq(&rme32->lock);
+ scoped_guard(spinlock_irq, &rme32->lock) {
+ if (rme32->capture_substream != NULL)
+ return -EBUSY;
+ rme32->capture_substream = substream;
+ }
if (rme32->fullduplex_mode)
runtime->hw = snd_rme32_spdif_fd_info;
@@ -930,15 +885,13 @@ snd_rme32_playback_adat_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
- spin_lock_irq(&rme32->lock);
- if (rme32->playback_substream != NULL) {
- spin_unlock_irq(&rme32->lock);
- return -EBUSY;
- }
- rme32->wcreg |= RME32_WCR_ADAT;
- writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
- rme32->playback_substream = substream;
- spin_unlock_irq(&rme32->lock);
+ scoped_guard(spinlock_irq, &rme32->lock) {
+ if (rme32->playback_substream != NULL)
+ return -EBUSY;
+ rme32->wcreg |= RME32_WCR_ADAT;
+ writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
+ rme32->playback_substream = substream;
+ }
if (rme32->fullduplex_mode)
runtime->hw = snd_rme32_adat_fd_info;
@@ -981,13 +934,11 @@ snd_rme32_capture_adat_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
- spin_lock_irq(&rme32->lock);
- if (rme32->capture_substream != NULL) {
- spin_unlock_irq(&rme32->lock);
- return -EBUSY;
- }
- rme32->capture_substream = substream;
- spin_unlock_irq(&rme32->lock);
+ scoped_guard(spinlock_irq, &rme32->lock) {
+ if (rme32->capture_substream != NULL)
+ return -EBUSY;
+ rme32->capture_substream = substream;
+ }
snd_rme32_set_buffer_constraint(rme32, runtime);
return 0;
@@ -998,11 +949,11 @@ static int snd_rme32_playback_close(struct snd_pcm_substream *substream)
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
int spdif = 0;
- spin_lock_irq(&rme32->lock);
- rme32->playback_substream = NULL;
- rme32->playback_periodsize = 0;
- spdif = (rme32->wcreg & RME32_WCR_ADAT) == 0;
- spin_unlock_irq(&rme32->lock);
+ scoped_guard(spinlock_irq, &rme32->lock) {
+ rme32->playback_substream = NULL;
+ rme32->playback_periodsize = 0;
+ spdif = (rme32->wcreg & RME32_WCR_ADAT) == 0;
+ }
if (spdif) {
rme32->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(rme32->card, SNDRV_CTL_EVENT_MASK_VALUE |
@@ -1016,10 +967,9 @@ static int snd_rme32_capture_close(struct snd_pcm_substream *substream)
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
rme32->capture_substream = NULL;
rme32->capture_periodsize = 0;
- spin_unlock_irq(&rme32->lock);
return 0;
}
@@ -1027,7 +977,7 @@ static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream)
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
if (rme32->fullduplex_mode) {
memset(&rme32->playback_pcm, 0, sizeof(rme32->playback_pcm));
rme32->playback_pcm.hw_buffer_size = RME32_BUFFER_SIZE;
@@ -1038,7 +988,6 @@ static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream)
if (rme32->wcreg & RME32_WCR_SEL)
rme32->wcreg &= ~RME32_WCR_MUTE;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
- spin_unlock_irq(&rme32->lock);
return 0;
}
@@ -1046,7 +995,7 @@ static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream)
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
if (rme32->fullduplex_mode) {
memset(&rme32->capture_pcm, 0, sizeof(rme32->capture_pcm));
rme32->capture_pcm.hw_buffer_size = RME32_BUFFER_SIZE;
@@ -1055,7 +1004,6 @@ static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream)
} else {
writel(0, rme32->iobase + RME32_IO_RESET_POS);
}
- spin_unlock_irq(&rme32->lock);
return 0;
}
@@ -1065,7 +1013,7 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
struct snd_pcm_substream *s;
- spin_lock(&rme32->lock);
+ guard(spinlock)(&rme32->lock);
snd_pcm_group_for_each_entry(s, substream) {
if (s != rme32->playback_substream &&
s != rme32->capture_substream)
@@ -1109,7 +1057,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_rme32_pcm_start(rme32, 1);
break;
}
- spin_unlock(&rme32->lock);
return 0;
}
@@ -1145,11 +1092,11 @@ static int snd_rme32_playback_fd_ack(struct snd_pcm_substream *substream)
rec = &rme32->playback_pcm;
cprec = &rme32->capture_pcm;
- spin_lock(&rme32->lock);
- rec->hw_queue_size = RME32_BUFFER_SIZE;
- if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE))
- rec->hw_queue_size -= cprec->hw_ready;
- spin_unlock(&rme32->lock);
+ scoped_guard(spinlock, &rme32->lock) {
+ rec->hw_queue_size = RME32_BUFFER_SIZE;
+ if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE))
+ rec->hw_queue_size -= cprec->hw_ready;
+ }
return snd_pcm_indirect_playback_transfer(substream, rec,
snd_rme32_pb_trans_copy);
}
@@ -1194,8 +1141,7 @@ static const struct snd_pcm_ops snd_rme32_playback_spdif_ops = {
.prepare = snd_rme32_playback_prepare,
.trigger = snd_rme32_pcm_trigger,
.pointer = snd_rme32_playback_pointer,
- .copy_user = snd_rme32_playback_copy,
- .copy_kernel = snd_rme32_playback_copy_kernel,
+ .copy = snd_rme32_playback_copy,
.fill_silence = snd_rme32_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1207,8 +1153,7 @@ static const struct snd_pcm_ops snd_rme32_capture_spdif_ops = {
.prepare = snd_rme32_capture_prepare,
.trigger = snd_rme32_pcm_trigger,
.pointer = snd_rme32_capture_pointer,
- .copy_user = snd_rme32_capture_copy,
- .copy_kernel = snd_rme32_capture_copy_kernel,
+ .copy = snd_rme32_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1219,8 +1164,7 @@ static const struct snd_pcm_ops snd_rme32_playback_adat_ops = {
.prepare = snd_rme32_playback_prepare,
.trigger = snd_rme32_pcm_trigger,
.pointer = snd_rme32_playback_pointer,
- .copy_user = snd_rme32_playback_copy,
- .copy_kernel = snd_rme32_playback_copy_kernel,
+ .copy = snd_rme32_playback_copy,
.fill_silence = snd_rme32_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1232,8 +1176,7 @@ static const struct snd_pcm_ops snd_rme32_capture_adat_ops = {
.prepare = snd_rme32_capture_prepare,
.trigger = snd_rme32_pcm_trigger,
.pointer = snd_rme32_capture_pointer,
- .copy_user = snd_rme32_capture_copy,
- .copy_kernel = snd_rme32_capture_copy_kernel,
+ .copy = snd_rme32_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1309,7 +1252,7 @@ static int snd_rme32_create(struct rme32 *rme32)
if (err < 0)
return err;
- err = pci_request_regions(pci, "RME32");
+ err = pcim_request_all_regions(pci, "RME32");
if (err < 0)
return err;
rme32->port = pci_resource_start(rme32->pci, 0);
@@ -1339,7 +1282,7 @@ static int snd_rme32_create(struct rme32 *rme32)
return err;
rme32->spdif_pcm->private_data = rme32;
rme32->spdif_pcm->private_free = snd_rme32_free_spdif_pcm;
- strcpy(rme32->spdif_pcm->name, "Digi32 IEC958");
+ strscpy(rme32->spdif_pcm->name, "Digi32 IEC958");
if (rme32->fullduplex_mode) {
snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_rme32_playback_spdif_fd_ops);
@@ -1369,7 +1312,7 @@ static int snd_rme32_create(struct rme32 *rme32)
return err;
rme32->adat_pcm->private_data = rme32;
rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm;
- strcpy(rme32->adat_pcm->name, "Digi32 ADAT");
+ strscpy(rme32->adat_pcm->name, "Digi32 ADAT");
if (rme32->fullduplex_mode) {
snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_rme32_playback_adat_fd_ops);
@@ -1538,10 +1481,9 @@ snd_rme32_get_loopback_control(struct snd_kcontrol *kcontrol,
{
struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
ucontrol->value.integer.value[0] =
rme32->wcreg & RME32_WCR_SEL ? 0 : 1;
- spin_unlock_irq(&rme32->lock);
return 0;
}
static int
@@ -1553,7 +1495,7 @@ snd_rme32_put_loopback_control(struct snd_kcontrol *kcontrol,
int change;
val = ucontrol->value.integer.value[0] ? 0 : RME32_WCR_SEL;
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
val = (rme32->wcreg & ~RME32_WCR_SEL) | val;
change = val != rme32->wcreg;
if (ucontrol->value.integer.value[0])
@@ -1562,7 +1504,6 @@ snd_rme32_put_loopback_control(struct snd_kcontrol *kcontrol,
val |= RME32_WCR_MUTE;
rme32->wcreg = val;
writel(val, rme32->iobase + RME32_IO_CONTROL_REGISTER);
- spin_unlock_irq(&rme32->lock);
return change;
}
@@ -1597,7 +1538,7 @@ snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol,
struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
unsigned int items = 3;
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
ucontrol->value.enumerated.item[0] = snd_rme32_getinputtype(rme32);
switch (rme32->pci->device) {
@@ -1616,7 +1557,6 @@ snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol,
ucontrol->value.enumerated.item[0] = items - 1;
}
- spin_unlock_irq(&rme32->lock);
return 0;
}
static int
@@ -1641,10 +1581,9 @@ snd_rme32_put_inputtype_control(struct snd_kcontrol *kcontrol,
}
val = ucontrol->value.enumerated.item[0] % items;
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
change = val != (unsigned int)snd_rme32_getinputtype(rme32);
snd_rme32_setinputtype(rme32, val);
- spin_unlock_irq(&rme32->lock);
return change;
}
@@ -1665,9 +1604,8 @@ snd_rme32_get_clockmode_control(struct snd_kcontrol *kcontrol,
{
struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
ucontrol->value.enumerated.item[0] = snd_rme32_getclockmode(rme32);
- spin_unlock_irq(&rme32->lock);
return 0;
}
static int
@@ -1679,10 +1617,9 @@ snd_rme32_put_clockmode_control(struct snd_kcontrol *kcontrol,
int change;
val = ucontrol->value.enumerated.item[0] % 3;
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
change = val != (unsigned int)snd_rme32_getclockmode(rme32);
snd_rme32_setclockmode(rme32, val);
- spin_unlock_irq(&rme32->lock);
return change;
}
@@ -1732,10 +1669,9 @@ static int snd_rme32_control_spdif_put(struct snd_kcontrol *kcontrol,
u32 val;
val = snd_rme32_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
change = val != rme32->wcreg_spdif;
rme32->wcreg_spdif = val;
- spin_unlock_irq(&rme32->lock);
return change;
}
@@ -1767,13 +1703,12 @@ static int snd_rme32_control_spdif_stream_put(struct snd_kcontrol *kcontrol,
u32 val;
val = snd_rme32_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&rme32->lock);
+ guard(spinlock_irq)(&rme32->lock);
change = val != rme32->wcreg_spdif_stream;
rme32->wcreg_spdif_stream = val;
rme32->wcreg &= ~(RME32_WCR_PRO | RME32_WCR_EMP);
rme32->wcreg |= val;
writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
- spin_unlock_irq(&rme32->lock);
return change;
}
@@ -1904,16 +1839,16 @@ __snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (err < 0)
return err;
- strcpy(card->driver, "Digi32");
+ strscpy(card->driver, "Digi32");
switch (rme32->pci->device) {
case PCI_DEVICE_ID_RME_DIGI32:
- strcpy(card->shortname, "RME Digi32");
+ strscpy(card->shortname, "RME Digi32");
break;
case PCI_DEVICE_ID_RME_DIGI32_8:
- strcpy(card->shortname, "RME Digi32/8");
+ strscpy(card->shortname, "RME Digi32/8");
break;
case PCI_DEVICE_ID_RME_DIGI32_PRO:
- strcpy(card->shortname, "RME Digi32 PRO");
+ strscpy(card->shortname, "RME Digi32 PRO");
break;
}
sprintf(card->longname, "%s (Rev. %d) at 0x%lx, irq %d",
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index bccb7e0d3d11..58b8ebf1a24e 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -220,12 +220,10 @@ struct rme96 {
u8 rev; /* card revision number */
-#ifdef CONFIG_PM_SLEEP
u32 playback_pointer;
u32 capture_pointer;
void *playback_suspend_buffer;
void *capture_suspend_buffer;
-#endif
struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream;
@@ -320,45 +318,26 @@ snd_rme96_playback_silence(struct snd_pcm_substream *substream,
static int
snd_rme96_playback_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos,
- src, count);
-}
-
-static int
-snd_rme96_playback_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
-{
- struct rme96 *rme96 = snd_pcm_substream_chip(substream);
-
- memcpy_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
snd_rme96_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- return copy_to_user_fromio(dst,
- rme96->iobase + RME96_IO_REC_BUFFER + pos,
- count);
-}
-
-static int
-snd_rme96_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
-{
- struct rme96 *rme96 = snd_pcm_substream_chip(substream);
-
- memcpy_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;
}
@@ -985,48 +964,45 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
runtime->dma_addr = rme96->port + RME96_IO_PLAY_BUFFER;
runtime->dma_bytes = RME96_BUFFER_SIZE;
- spin_lock_irq(&rme96->lock);
- rate = 0;
- if (!(rme96->wcreg & RME96_WCR_MASTER) &&
- snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG)
- rate = snd_rme96_capture_getrate(rme96, &dummy);
- if (rate > 0) {
- /* slave clock */
- if ((int)params_rate(params) != rate) {
- err = -EIO;
- goto error;
+ scoped_guard(spinlock_irq, &rme96->lock) {
+ rate = 0;
+ if (!(rme96->wcreg & RME96_WCR_MASTER) &&
+ snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG)
+ rate = snd_rme96_capture_getrate(rme96, &dummy);
+ if (rate > 0) {
+ /* slave clock */
+ if ((int)params_rate(params) != rate)
+ return -EIO;
+ } else {
+ err = snd_rme96_playback_setrate(rme96, params_rate(params));
+ if (err < 0)
+ return err;
+ apply_dac_volume = err > 0; /* need to restore volume later? */
}
- } else {
- err = snd_rme96_playback_setrate(rme96, params_rate(params));
- if (err < 0)
- goto error;
- apply_dac_volume = err > 0; /* need to restore volume later? */
- }
- err = snd_rme96_playback_setformat(rme96, params_format(params));
- if (err < 0)
- goto error;
- snd_rme96_setframelog(rme96, params_channels(params), 1);
- if (rme96->capture_periodsize != 0) {
- if (params_period_size(params) << rme96->playback_frlog !=
- rme96->capture_periodsize)
- {
- err = -EBUSY;
+ err = snd_rme96_playback_setformat(rme96, params_format(params));
+ if (err < 0)
goto error;
+ snd_rme96_setframelog(rme96, params_channels(params), 1);
+ if (rme96->capture_periodsize != 0) {
+ if (params_period_size(params) << rme96->playback_frlog !=
+ rme96->capture_periodsize) {
+ err = -EBUSY;
+ goto error;
+ }
+ }
+ rme96->playback_periodsize =
+ params_period_size(params) << rme96->playback_frlog;
+ snd_rme96_set_period_properties(rme96, rme96->playback_periodsize);
+ /* S/PDIF setup */
+ if ((rme96->wcreg & RME96_WCR_ADAT) == 0) {
+ rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP);
+ writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
- }
- rme96->playback_periodsize =
- params_period_size(params) << rme96->playback_frlog;
- snd_rme96_set_period_properties(rme96, rme96->playback_periodsize);
- /* S/PDIF setup */
- if ((rme96->wcreg & RME96_WCR_ADAT) == 0) {
- rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP);
- writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER);
- }
- err = 0;
+ err = 0;
+ }
error:
- spin_unlock_irq(&rme96->lock);
if (apply_dac_volume) {
usleep_range(3000, 10000);
snd_rme96_apply_dac_volume(rme96);
@@ -1048,45 +1024,33 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream,
runtime->dma_addr = rme96->port + RME96_IO_REC_BUFFER;
runtime->dma_bytes = RME96_BUFFER_SIZE;
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
err = snd_rme96_capture_setformat(rme96, params_format(params));
- if (err < 0) {
- spin_unlock_irq(&rme96->lock);
+ if (err < 0)
return err;
- }
if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
err = snd_rme96_capture_analog_setrate(rme96, params_rate(params));
- if (err < 0) {
- spin_unlock_irq(&rme96->lock);
+ if (err < 0)
return err;
- }
} else {
rate = snd_rme96_capture_getrate(rme96, &isadat);
if (rate > 0) {
- if ((int)params_rate(params) != rate) {
- spin_unlock_irq(&rme96->lock);
+ if ((int)params_rate(params) != rate)
return -EIO;
- }
if ((isadat && runtime->hw.channels_min == 2) ||
- (!isadat && runtime->hw.channels_min == 8)) {
- spin_unlock_irq(&rme96->lock);
+ (!isadat && runtime->hw.channels_min == 8))
return -EIO;
- }
}
}
snd_rme96_setframelog(rme96, params_channels(params), 0);
if (rme96->playback_periodsize != 0) {
if (params_period_size(params) << rme96->capture_frlog !=
rme96->playback_periodsize)
- {
- spin_unlock_irq(&rme96->lock);
return -EBUSY;
- }
}
rme96->capture_periodsize =
params_period_size(params) << rme96->capture_frlog;
snd_rme96_set_period_properties(rme96, rme96->capture_periodsize);
- spin_unlock_irq(&rme96->lock);
return 0;
}
@@ -1186,15 +1150,13 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
- spin_lock_irq(&rme96->lock);
- if (rme96->playback_substream) {
- spin_unlock_irq(&rme96->lock);
- return -EBUSY;
- }
- rme96->wcreg &= ~RME96_WCR_ADAT;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
- rme96->playback_substream = substream;
- spin_unlock_irq(&rme96->lock);
+ scoped_guard(spinlock_irq, &rme96->lock) {
+ if (rme96->playback_substream)
+ return -EBUSY;
+ rme96->wcreg &= ~RME96_WCR_ADAT;
+ writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ rme96->playback_substream = substream;
+ }
runtime->hw = snd_rme96_playback_spdif_info;
if (!(rme96->wcreg & RME96_WCR_MASTER) &&
@@ -1236,13 +1198,11 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
}
}
- spin_lock_irq(&rme96->lock);
- if (rme96->capture_substream) {
- spin_unlock_irq(&rme96->lock);
- return -EBUSY;
- }
- rme96->capture_substream = substream;
- spin_unlock_irq(&rme96->lock);
+ scoped_guard(spinlock_irq, &rme96->lock) {
+ if (rme96->capture_substream)
+ return -EBUSY;
+ rme96->capture_substream = substream;
+ }
rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
@@ -1256,15 +1216,13 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
- spin_lock_irq(&rme96->lock);
- if (rme96->playback_substream) {
- spin_unlock_irq(&rme96->lock);
- return -EBUSY;
- }
- rme96->wcreg |= RME96_WCR_ADAT;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
- rme96->playback_substream = substream;
- spin_unlock_irq(&rme96->lock);
+ scoped_guard(spinlock_irq, &rme96->lock) {
+ if (rme96->playback_substream)
+ return -EBUSY;
+ rme96->wcreg |= RME96_WCR_ADAT;
+ writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ rme96->playback_substream = substream;
+ }
runtime->hw = snd_rme96_playback_adat_info;
if (!(rme96->wcreg & RME96_WCR_MASTER) &&
@@ -1306,13 +1264,11 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
runtime->hw.rate_max = rate;
}
- spin_lock_irq(&rme96->lock);
- if (rme96->capture_substream) {
- spin_unlock_irq(&rme96->lock);
- return -EBUSY;
- }
- rme96->capture_substream = substream;
- spin_unlock_irq(&rme96->lock);
+ scoped_guard(spinlock_irq, &rme96->lock) {
+ if (rme96->capture_substream)
+ return -EBUSY;
+ rme96->capture_substream = substream;
+ }
rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
@@ -1324,14 +1280,13 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
int spdif = 0;
- spin_lock_irq(&rme96->lock);
- if (RME96_ISPLAYING(rme96)) {
- snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
+ scoped_guard(spinlock_irq, &rme96->lock) {
+ if (RME96_ISPLAYING(rme96))
+ snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
+ rme96->playback_substream = NULL;
+ rme96->playback_periodsize = 0;
+ spdif = (rme96->wcreg & RME96_WCR_ADAT) == 0;
}
- rme96->playback_substream = NULL;
- rme96->playback_periodsize = 0;
- spdif = (rme96->wcreg & RME96_WCR_ADAT) == 0;
- spin_unlock_irq(&rme96->lock);
if (spdif) {
rme96->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(rme96->card, SNDRV_CTL_EVENT_MASK_VALUE |
@@ -1345,13 +1300,12 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
}
rme96->capture_substream = NULL;
rme96->capture_periodsize = 0;
- spin_unlock_irq(&rme96->lock);
return 0;
}
@@ -1360,12 +1314,11 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
}
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
- spin_unlock_irq(&rme96->lock);
return 0;
}
@@ -1374,12 +1327,11 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
}
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
- spin_unlock_irq(&rme96->lock);
return 0;
}
@@ -1518,8 +1470,7 @@ static const struct snd_pcm_ops snd_rme96_playback_spdif_ops = {
.prepare = snd_rme96_playback_prepare,
.trigger = snd_rme96_playback_trigger,
.pointer = snd_rme96_playback_pointer,
- .copy_user = snd_rme96_playback_copy,
- .copy_kernel = snd_rme96_playback_copy_kernel,
+ .copy = snd_rme96_playback_copy,
.fill_silence = snd_rme96_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1531,8 +1482,7 @@ static const struct snd_pcm_ops snd_rme96_capture_spdif_ops = {
.prepare = snd_rme96_capture_prepare,
.trigger = snd_rme96_capture_trigger,
.pointer = snd_rme96_capture_pointer,
- .copy_user = snd_rme96_capture_copy,
- .copy_kernel = snd_rme96_capture_copy_kernel,
+ .copy = snd_rme96_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1543,8 +1493,7 @@ static const struct snd_pcm_ops snd_rme96_playback_adat_ops = {
.prepare = snd_rme96_playback_prepare,
.trigger = snd_rme96_playback_trigger,
.pointer = snd_rme96_playback_pointer,
- .copy_user = snd_rme96_playback_copy,
- .copy_kernel = snd_rme96_playback_copy_kernel,
+ .copy = snd_rme96_playback_copy,
.fill_silence = snd_rme96_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1556,8 +1505,7 @@ static const struct snd_pcm_ops snd_rme96_capture_adat_ops = {
.prepare = snd_rme96_capture_prepare,
.trigger = snd_rme96_capture_trigger,
.pointer = snd_rme96_capture_pointer,
- .copy_user = snd_rme96_capture_copy,
- .copy_kernel = snd_rme96_capture_copy_kernel,
+ .copy = snd_rme96_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
@@ -1569,10 +1517,8 @@ snd_rme96_free(struct rme96 *rme96)
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
}
-#ifdef CONFIG_PM_SLEEP
vfree(rme96->playback_suspend_buffer);
vfree(rme96->capture_suspend_buffer);
-#endif
}
static void
@@ -1602,7 +1548,7 @@ snd_rme96_create(struct rme96 *rme96)
if (err < 0)
return err;
- err = pci_request_regions(pci, "RME96");
+ err = pcim_request_all_regions(pci, "RME96");
if (err < 0)
return err;
rme96->port = pci_resource_start(rme96->pci, 0);
@@ -1634,7 +1580,7 @@ snd_rme96_create(struct rme96 *rme96)
rme96->spdif_pcm->private_data = rme96;
rme96->spdif_pcm->private_free = snd_rme96_free_spdif_pcm;
- strcpy(rme96->spdif_pcm->name, "Digi96 IEC958");
+ strscpy(rme96->spdif_pcm->name, "Digi96 IEC958");
snd_pcm_set_ops(rme96->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme96_playback_spdif_ops);
snd_pcm_set_ops(rme96->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme96_capture_spdif_ops);
@@ -1651,7 +1597,7 @@ snd_rme96_create(struct rme96 *rme96)
return err;
rme96->adat_pcm->private_data = rme96;
rme96->adat_pcm->private_free = snd_rme96_free_adat_pcm;
- strcpy(rme96->adat_pcm->name, "Digi96 ADAT");
+ strscpy(rme96->adat_pcm->name, "Digi96 ADAT");
snd_pcm_set_ops(rme96->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme96_playback_adat_ops);
snd_pcm_set_ops(rme96->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme96_capture_adat_ops);
@@ -1856,9 +1802,8 @@ snd_rme96_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
{
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
ucontrol->value.integer.value[0] = rme96->wcreg & RME96_WCR_SEL ? 0 : 1;
- spin_unlock_irq(&rme96->lock);
return 0;
}
static int
@@ -1869,12 +1814,11 @@ snd_rme96_put_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
int change;
val = ucontrol->value.integer.value[0] ? 0 : RME96_WCR_SEL;
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
val = (rme96->wcreg & ~RME96_WCR_SEL) | val;
change = val != rme96->wcreg;
rme96->wcreg = val;
writel(val, rme96->iobase + RME96_IO_CONTROL_REGISTER);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -1920,7 +1864,7 @@ snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
unsigned int items = 3;
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
ucontrol->value.enumerated.item[0] = snd_rme96_getinputtype(rme96);
switch (rme96->pci->device) {
@@ -1950,7 +1894,6 @@ snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
ucontrol->value.enumerated.item[0] = items - 1;
}
- spin_unlock_irq(&rme96->lock);
return 0;
}
static int
@@ -1988,10 +1931,9 @@ snd_rme96_put_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
}
}
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
change = (int)val != snd_rme96_getinputtype(rme96);
snd_rme96_setinputtype(rme96, val);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2007,9 +1949,8 @@ snd_rme96_get_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
{
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
ucontrol->value.enumerated.item[0] = snd_rme96_getclockmode(rme96);
- spin_unlock_irq(&rme96->lock);
return 0;
}
static int
@@ -2020,10 +1961,9 @@ snd_rme96_put_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
int change;
val = ucontrol->value.enumerated.item[0] % 3;
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
change = (int)val != snd_rme96_getclockmode(rme96);
snd_rme96_setclockmode(rme96, val);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2041,9 +1981,8 @@ snd_rme96_get_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_
{
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
ucontrol->value.enumerated.item[0] = snd_rme96_getattenuation(rme96);
- spin_unlock_irq(&rme96->lock);
return 0;
}
static int
@@ -2054,11 +1993,10 @@ snd_rme96_put_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_
int change;
val = ucontrol->value.enumerated.item[0] % 4;
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
change = (int)val != snd_rme96_getattenuation(rme96);
snd_rme96_setattenuation(rme96, val);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2074,9 +2012,8 @@ snd_rme96_get_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
{
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
ucontrol->value.enumerated.item[0] = snd_rme96_getmontracks(rme96);
- spin_unlock_irq(&rme96->lock);
return 0;
}
static int
@@ -2087,10 +2024,9 @@ snd_rme96_put_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
int change;
val = ucontrol->value.enumerated.item[0] % 4;
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
change = (int)val != snd_rme96_getmontracks(rme96);
snd_rme96_setmontracks(rme96, val);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2138,10 +2074,9 @@ static int snd_rme96_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd
u32 val;
val = snd_rme96_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
change = val != rme96->wcreg_spdif;
rme96->wcreg_spdif = val;
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2167,13 +2102,12 @@ static int snd_rme96_control_spdif_stream_put(struct snd_kcontrol *kcontrol, str
u32 val;
val = snd_rme96_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
change = val != rme96->wcreg_spdif_stream;
rme96->wcreg_spdif_stream = val;
rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP);
rme96->wcreg |= val;
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2207,10 +2141,9 @@ snd_rme96_dac_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
{
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
u->value.integer.value[0] = rme96->vol[0];
u->value.integer.value[1] = rme96->vol[1];
- spin_unlock_irq(&rme96->lock);
return 0;
}
@@ -2226,7 +2159,7 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
if (!RME96_HAS_ANALOG_OUT(rme96))
return -EINVAL;
maxvol = RME96_185X_MAX_OUT(rme96);
- spin_lock_irq(&rme96->lock);
+ guard(spinlock_irq)(&rme96->lock);
vol = u->value.integer.value[0];
if (vol != rme96->vol[0] && vol <= maxvol) {
rme96->vol[0] = vol;
@@ -2239,7 +2172,6 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
}
if (change)
snd_rme96_apply_dac_volume(rme96);
- spin_unlock_irq(&rme96->lock);
return change;
}
@@ -2355,8 +2287,6 @@ snd_rme96_create_switches(struct snd_card *card,
* Card initialisation
*/
-#ifdef CONFIG_PM_SLEEP
-
static int rme96_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -2418,11 +2348,7 @@ static int rme96_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
-#define RME96_PM_OPS &rme96_pm
-#else
-#define RME96_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
static void snd_rme96_card_free(struct snd_card *card)
{
@@ -2458,32 +2384,32 @@ __snd_rme96_probe(struct pci_dev *pci,
if (err)
return err;
-#ifdef CONFIG_PM_SLEEP
- rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
- if (!rme96->playback_suspend_buffer)
- return -ENOMEM;
- rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
- if (!rme96->capture_suspend_buffer)
- return -ENOMEM;
-#endif
-
- strcpy(card->driver, "Digi96");
+ if (IS_ENABLED(CONFIG_PM_SLEEP)) {
+ rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+ if (!rme96->playback_suspend_buffer)
+ return -ENOMEM;
+ rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+ if (!rme96->capture_suspend_buffer)
+ return -ENOMEM;
+ }
+
+ strscpy(card->driver, "Digi96");
switch (rme96->pci->device) {
case PCI_DEVICE_ID_RME_DIGI96:
- strcpy(card->shortname, "RME Digi96");
+ strscpy(card->shortname, "RME Digi96");
break;
case PCI_DEVICE_ID_RME_DIGI96_8:
- strcpy(card->shortname, "RME Digi96/8");
+ strscpy(card->shortname, "RME Digi96/8");
break;
case PCI_DEVICE_ID_RME_DIGI96_8_PRO:
- strcpy(card->shortname, "RME Digi96/8 PRO");
+ strscpy(card->shortname, "RME Digi96/8 PRO");
break;
case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST:
pci_read_config_byte(rme96->pci, 8, &val);
if (val < 5) {
- strcpy(card->shortname, "RME Digi96/8 PAD");
+ strscpy(card->shortname, "RME Digi96/8 PAD");
} else {
- strcpy(card->shortname, "RME Digi96/8 PST");
+ strscpy(card->shortname, "RME Digi96/8 PST");
}
break;
}
@@ -2509,7 +2435,7 @@ static struct pci_driver rme96_driver = {
.id_table = snd_rme96_ids,
.probe = snd_rme96_probe,
.driver = {
- .pm = RME96_PM_OPS,
+ .pm = &rme96_pm,
},
};
diff --git a/sound/pci/rme9652/Makefile b/sound/pci/rme9652/Makefile
index a3351447ddc0..cc99ae892211 100644
--- a/sound/pci/rme9652/Makefile
+++ b/sound/pci/rme9652/Makefile
@@ -4,9 +4,9 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-rme9652-objs := rme9652.o
-snd-hdsp-objs := hdsp.o
-snd-hdspm-objs := hdspm.o
+snd-rme9652-y := rme9652.o
+snd-hdsp-y := hdsp.o
+snd-hdspm-y := hdspm.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_RME9652) += snd-rme9652.o
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 65add92c88aa..31cc2d91c8d2 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -691,7 +691,6 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
int i;
- unsigned long flags;
const u32 *cache;
if (hdsp->fw_uploaded)
@@ -746,9 +745,8 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
if (hdsp->state & HDSP_InitializationComplete) {
dev_info(hdsp->card->dev,
"firmware loaded from cache, restoring defaults\n");
- spin_lock_irqsave(&hdsp->lock, flags);
+ guard(spinlock_irqsave)(&hdsp->lock);
snd_hdsp_set_defaults(hdsp);
- spin_unlock_irqrestore(&hdsp->lock, flags);
}
hdsp->state |= HDSP_FirmwareLoaded;
@@ -939,14 +937,12 @@ static int hdsp_write_gain(struct hdsp *hdsp, unsigned int addr, unsigned short
static int snd_hdsp_use_is_exclusive(struct hdsp *hdsp)
{
- unsigned long flags;
int ret = 1;
- spin_lock_irqsave(&hdsp->lock, flags);
+ guard(spinlock_irqsave)(&hdsp->lock);
if ((hdsp->playback_pid != hdsp->capture_pid) &&
(hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0))
ret = 0;
- spin_unlock_irqrestore(&hdsp->lock, flags);
return ret;
}
@@ -1063,8 +1059,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
{
int n;
- spin_lock_irq(&s->lock);
-
frames >>= 7;
n = 0;
while (frames) {
@@ -1079,8 +1073,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames)
hdsp_compute_period_size(s);
- spin_unlock_irq(&s->lock);
-
return 0;
}
@@ -1298,13 +1290,14 @@ static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id)
static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id)
{
- while (snd_hdsp_midi_input_available (hdsp, id))
- snd_hdsp_midi_read_byte (hdsp, id);
+ int count = 256;
+
+ while (snd_hdsp_midi_input_available(hdsp, id) && --count)
+ snd_hdsp_midi_read_byte(hdsp, id);
}
static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
{
- unsigned long flags;
int n_pending;
int to_write;
int i;
@@ -1312,7 +1305,7 @@ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
/* Output is not interrupt driven */
- spin_lock_irqsave (&hmidi->lock, flags);
+ guard(spinlock_irqsave)(&hmidi->lock);
if (hmidi->output) {
if (!snd_rawmidi_transmit_empty (hmidi->output)) {
n_pending = snd_hdsp_midi_output_possible(hmidi->hdsp, hmidi->id);
@@ -1328,40 +1321,38 @@ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
}
}
}
- spin_unlock_irqrestore (&hmidi->lock, flags);
return 0;
}
static int snd_hdsp_midi_input_read (struct hdsp_midi *hmidi)
{
unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */
- unsigned long flags;
int n_pending;
int i;
- spin_lock_irqsave (&hmidi->lock, flags);
- n_pending = snd_hdsp_midi_input_available(hmidi->hdsp, hmidi->id);
- if (n_pending > 0) {
- if (hmidi->input) {
- if (n_pending > (int)sizeof (buf))
- n_pending = sizeof (buf);
- for (i = 0; i < n_pending; ++i)
- buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
- if (n_pending)
- snd_rawmidi_receive (hmidi->input, buf, n_pending);
- } else {
- /* flush the MIDI input FIFO */
- while (--n_pending)
- snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id);
+ scoped_guard(spinlock_irqsave, &hmidi->lock) {
+ n_pending = snd_hdsp_midi_input_available(hmidi->hdsp, hmidi->id);
+ if (n_pending > 0) {
+ if (hmidi->input) {
+ if (n_pending > (int)sizeof(buf))
+ n_pending = sizeof(buf);
+ for (i = 0; i < n_pending; ++i)
+ buf[i] = snd_hdsp_midi_read_byte(hmidi->hdsp, hmidi->id);
+ if (n_pending)
+ snd_rawmidi_receive(hmidi->input, buf, n_pending);
+ } else {
+ /* flush the MIDI input FIFO */
+ while (--n_pending)
+ snd_hdsp_midi_read_byte(hmidi->hdsp, hmidi->id);
+ }
}
+ hmidi->pending = 0;
+ if (hmidi->id)
+ hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable;
+ else
+ hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable;
+ hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register);
}
- hmidi->pending = 0;
- if (hmidi->id)
- hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable;
- else
- hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable;
- hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register);
- spin_unlock_irqrestore (&hmidi->lock, flags);
return snd_hdsp_midi_output_write (hmidi);
}
@@ -1369,13 +1360,12 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream,
{
struct hdsp *hdsp;
struct hdsp_midi *hmidi;
- unsigned long flags;
u32 ie;
hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
hdsp = hmidi->hdsp;
ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable;
- spin_lock_irqsave (&hdsp->lock, flags);
+ guard(spinlock_irqsave)(&hdsp->lock);
if (up) {
if (!(hdsp->control_register & ie)) {
snd_hdsp_flush_midi_input (hdsp, hmidi->id);
@@ -1386,16 +1376,14 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream,
}
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
- spin_unlock_irqrestore (&hdsp->lock, flags);
}
static void snd_hdsp_midi_output_timer(struct timer_list *t)
{
- struct hdsp_midi *hmidi = from_timer(hmidi, t, timer);
- unsigned long flags;
+ struct hdsp_midi *hmidi = timer_container_of(hmidi, t, timer);
snd_hdsp_midi_output_write(hmidi);
- spin_lock_irqsave (&hmidi->lock, flags);
+ guard(spinlock_irqsave)(&hmidi->lock);
/* this does not bump hmidi->istimer, because the
kernel automatically removed the timer when it
@@ -1405,29 +1393,26 @@ static void snd_hdsp_midi_output_timer(struct timer_list *t)
if (hmidi->istimer)
mod_timer(&hmidi->timer, 1 + jiffies);
-
- spin_unlock_irqrestore (&hmidi->lock, flags);
}
static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct hdsp_midi *hmidi;
- unsigned long flags;
hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
- spin_lock_irqsave (&hmidi->lock, flags);
- if (up) {
- if (!hmidi->istimer) {
- timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer,
- 0);
- mod_timer(&hmidi->timer, 1 + jiffies);
- hmidi->istimer++;
+ scoped_guard(spinlock_irqsave, &hmidi->lock) {
+ if (up) {
+ if (!hmidi->istimer) {
+ timer_setup(&hmidi->timer, snd_hdsp_midi_output_timer,
+ 0);
+ mod_timer(&hmidi->timer, 1 + jiffies);
+ hmidi->istimer++;
+ }
+ } else {
+ if (hmidi->istimer && --hmidi->istimer <= 0)
+ timer_delete(&hmidi->timer);
}
- } else {
- if (hmidi->istimer && --hmidi->istimer <= 0)
- del_timer (&hmidi->timer);
}
- spin_unlock_irqrestore (&hmidi->lock, flags);
if (up)
snd_hdsp_midi_output_write(hmidi);
}
@@ -1437,10 +1422,9 @@ static int snd_hdsp_midi_input_open(struct snd_rawmidi_substream *substream)
struct hdsp_midi *hmidi;
hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
snd_hdsp_flush_midi_input (hmidi->hdsp, hmidi->id);
hmidi->input = substream;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -1450,9 +1434,8 @@ static int snd_hdsp_midi_output_open(struct snd_rawmidi_substream *substream)
struct hdsp_midi *hmidi;
hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
hmidi->output = substream;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -1464,9 +1447,8 @@ static int snd_hdsp_midi_input_close(struct snd_rawmidi_substream *substream)
snd_hdsp_midi_input_trigger (substream, 0);
hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
hmidi->input = NULL;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -1478,9 +1460,8 @@ static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
snd_hdsp_midi_output_trigger (substream, 0);
hmidi = (struct hdsp_midi *) substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
hmidi->output = NULL;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -1577,10 +1558,9 @@ static int snd_hdsp_control_spdif_put(struct snd_kcontrol *kcontrol, struct snd_
u32 val;
val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = val != hdsp->creg_spdif;
hdsp->creg_spdif = val;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -1606,12 +1586,11 @@ static int snd_hdsp_control_spdif_stream_put(struct snd_kcontrol *kcontrol, stru
u32 val;
val = snd_hdsp_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = val != hdsp->creg_spdif_stream;
hdsp->creg_spdif_stream = val;
hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register |= val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -1677,11 +1656,10 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = val != hdsp_spdif_in(hdsp);
if (change)
hdsp_set_spdif_input(hdsp, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -1718,9 +1696,8 @@ static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol,
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask);
- spin_unlock_irq(&hdsp->lock);
return 0;
}
@@ -1735,11 +1712,10 @@ static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = (int) val != hdsp_toggle_setting(hdsp, regmask);
if (change)
hdsp_set_toggle_setting(hdsp, regmask, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2045,12 +2021,11 @@ static int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_c
if (val > 6)
val = 6;
}
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_clock_source(hdsp))
change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2145,12 +2120,11 @@ static int snd_hdsp_put_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_el
val = ucontrol->value.enumerated.item[0];
if (val < 0) val = 0;
if (val > 2) val = 2;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_da_gain(hdsp))
change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2224,12 +2198,11 @@ static int snd_hdsp_put_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_el
val = ucontrol->value.enumerated.item[0];
if (val < 0) val = 0;
if (val > 2) val = 2;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_ad_gain(hdsp))
change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2303,12 +2276,11 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl
val = ucontrol->value.enumerated.item[0];
if (val < 0) val = 0;
if (val > 2) val = 2;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_phone_gain(hdsp))
change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2434,10 +2406,9 @@ static int snd_hdsp_put_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_
}
val = ucontrol->value.enumerated.item[0] % max;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = (int)val != hdsp_pref_sync_ref(hdsp);
hdsp_set_pref_sync_ref(hdsp, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2517,9 +2488,8 @@ static int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct sn
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
ucontrol->value.integer.value[0] = hdsp->precise_ptr;
- spin_unlock_irq(&hdsp->lock);
return 0;
}
@@ -2532,10 +2502,9 @@ static int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct sn
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = (int)val != hdsp->precise_ptr;
hdsp_set_precise_pointer(hdsp, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2563,9 +2532,8 @@ static int snd_hdsp_get_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
ucontrol->value.integer.value[0] = hdsp->use_midi_work;
- spin_unlock_irq(&hdsp->lock);
return 0;
}
@@ -2578,10 +2546,9 @@ static int snd_hdsp_put_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = (int)val != hdsp->use_midi_work;
hdsp_set_use_midi_work(hdsp, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2622,9 +2589,8 @@ static int snd_hdsp_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
else
addr = hdsp_input_to_output_key(hdsp,source, destination);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr);
- spin_unlock_irq(&hdsp->lock);
return 0;
}
@@ -2650,11 +2616,10 @@ static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
gain = ucontrol->value.integer.value[2];
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = gain != hdsp_read_gain(hdsp, addr);
if (change)
hdsp_write_gain(hdsp, addr, gain);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -2867,12 +2832,11 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0];
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_dds_offset(hdsp))
change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -3016,12 +2980,11 @@ static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ct
val = 0;
if (val > 4)
val = 4;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_rpm_input12(hdsp))
change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -3101,12 +3064,11 @@ static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ct
val = 0;
if (val > 4)
val = 4;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (val != hdsp_rpm_input34(hdsp))
change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -3147,10 +3109,9 @@ static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = (int)val != hdsp_rpm_bypass(hdsp);
hdsp_set_rpm_bypass(hdsp, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -3199,10 +3160,9 @@ static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
change = (int)val != hdsp_rpm_disconnect(hdsp);
hdsp_set_rpm_disconnect(hdsp, val);
- spin_unlock_irq(&hdsp->lock);
return change;
}
@@ -3442,7 +3402,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");
@@ -3450,8 +3410,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);
@@ -3748,8 +3708,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");
@@ -3961,7 +3921,7 @@ static signed char *hdsp_channel_buffer_location(struct hdsp *hdsp,
static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct hdsp *hdsp = snd_pcm_substream_chip(substream);
signed char *channel_buf;
@@ -3972,28 +3932,14 @@ static int snd_hdsp_playback_copy(struct snd_pcm_substream *substream,
channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
- if (copy_from_user(channel_buf + pos, src, count))
+ if (copy_from_iter(channel_buf + pos, count, src) != count)
return -EFAULT;
return 0;
}
-static int snd_hdsp_playback_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
-{
- struct hdsp *hdsp = snd_pcm_substream_chip(substream);
- signed char *channel_buf;
-
- channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel);
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
- memcpy(channel_buf + pos, src, count);
- return 0;
-}
-
static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
struct hdsp *hdsp = snd_pcm_substream_chip(substream);
signed char *channel_buf;
@@ -4004,25 +3950,11 @@ static int snd_hdsp_capture_copy(struct snd_pcm_substream *substream,
channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
- if (copy_to_user(dst, channel_buf + pos, count))
+ if (copy_to_iter(channel_buf + pos, count, dst) != count)
return -EFAULT;
return 0;
}
-static int snd_hdsp_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
-{
- struct hdsp *hdsp = snd_pcm_substream_chip(substream);
- signed char *channel_buf;
-
- channel_buf = hdsp_channel_buffer_location(hdsp, substream->pstr->stream, channel);
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
- memcpy(dst, channel_buf + pos, count);
- return 0;
-}
-
static int snd_hdsp_hw_silence(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
unsigned long count)
@@ -4077,7 +4009,7 @@ static int snd_hdsp_hw_params(struct snd_pcm_substream *substream,
if (hdsp_check_for_firmware(hdsp, 1))
return -EIO;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
hdsp->control_register &= ~(HDSP_SPDIFProfessional | HDSP_SPDIFNonAudio | HDSP_SPDIFEmphasis);
@@ -4097,39 +4029,31 @@ static int snd_hdsp_hw_params(struct snd_pcm_substream *substream,
*/
if (params_rate(params) != hdsp->system_sample_rate) {
- spin_unlock_irq(&hdsp->lock);
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
return -EBUSY;
}
if (params_period_size(params) != hdsp->period_bytes / 4) {
- spin_unlock_irq(&hdsp->lock);
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return -EBUSY;
}
/* We're fine. */
- spin_unlock_irq(&hdsp->lock);
return 0;
- } else {
- spin_unlock_irq(&hdsp->lock);
}
/* how to make sure that the rate matches an externally-set one ?
*/
- spin_lock_irq(&hdsp->lock);
if (! hdsp->clock_source_locked) {
err = hdsp_set_rate(hdsp, params_rate(params), 0);
if (err < 0) {
- spin_unlock_irq(&hdsp->lock);
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
return err;
}
}
- spin_unlock_irq(&hdsp->lock);
err = hdsp_set_interrupt_interval(hdsp, params_period_size(params));
if (err < 0) {
@@ -4186,7 +4110,7 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */
return -EIO;
- spin_lock(&hdsp->lock);
+ guard(spinlock)(&hdsp->lock);
running = hdsp->running;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -4197,7 +4121,6 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
break;
default:
snd_BUG();
- spin_unlock(&hdsp->lock);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -4237,7 +4160,6 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd)
else if (hdsp->running && !running)
hdsp_stop_audio(hdsp);
hdsp->running = running;
- spin_unlock(&hdsp->lock);
return 0;
}
@@ -4253,10 +4175,9 @@ static int snd_hdsp_prepare(struct snd_pcm_substream *substream)
if (hdsp_check_for_firmware(hdsp, 1))
return -EIO;
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
if (!hdsp->running)
hdsp_reset_hw_pointer(hdsp);
- spin_unlock_irq(&hdsp->lock);
return result;
}
@@ -4327,14 +4248,6 @@ static const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_period_sizes
.mask = 0
};
-static const unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 };
-
-static const struct snd_pcm_hw_constraint_list hdsp_hw_constraints_9632_sample_rates = {
- .count = ARRAY_SIZE(hdsp_9632_sample_rates),
- .list = hdsp_9632_sample_rates,
- .mask = 0
-};
-
static int snd_hdsp_hw_rule_in_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -4507,17 +4420,15 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
if (hdsp_check_for_firmware(hdsp, 1))
return -EIO;
- spin_lock_irq(&hdsp->lock);
-
- snd_pcm_set_sync(substream);
+ scoped_guard(spinlock_irq, &hdsp->lock) {
+ snd_pcm_set_sync(substream);
- runtime->hw = snd_hdsp_playback_subinfo;
- snd_pcm_set_runtime_buffer(substream, &hdsp->playback_dma_buf);
+ runtime->hw = snd_hdsp_playback_subinfo;
+ snd_pcm_set_runtime_buffer(substream, &hdsp->playback_dma_buf);
- hdsp->playback_pid = current->pid;
- hdsp->playback_substream = substream;
-
- spin_unlock_irq(&hdsp->lock);
+ hdsp->playback_pid = current->pid;
+ hdsp->playback_substream = substream;
+ }
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
@@ -4525,8 +4436,9 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate;
} else if (hdsp->io_type == H9632) {
runtime->hw.rate_max = 192000;
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
+ runtime->hw.rates |= (SNDRV_PCM_RATE_128000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000);
}
if (hdsp->io_type == H9632) {
runtime->hw.channels_min = hdsp->qs_out_channels;
@@ -4556,12 +4468,10 @@ static int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
{
struct hdsp *hdsp = snd_pcm_substream_chip(substream);
- spin_lock_irq(&hdsp->lock);
-
- hdsp->playback_pid = -1;
- hdsp->playback_substream = NULL;
-
- spin_unlock_irq(&hdsp->lock);
+ scoped_guard(spinlock_irq, &hdsp->lock) {
+ hdsp->playback_pid = -1;
+ hdsp->playback_substream = NULL;
+ }
if (RPM != hdsp->io_type) {
hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
@@ -4583,17 +4493,15 @@ static int snd_hdsp_capture_open(struct snd_pcm_substream *substream)
if (hdsp_check_for_firmware(hdsp, 1))
return -EIO;
- spin_lock_irq(&hdsp->lock);
-
- snd_pcm_set_sync(substream);
-
- runtime->hw = snd_hdsp_capture_subinfo;
- snd_pcm_set_runtime_buffer(substream, &hdsp->capture_dma_buf);
+ scoped_guard(spinlock_irq, &hdsp->lock) {
+ snd_pcm_set_sync(substream);
- hdsp->capture_pid = current->pid;
- hdsp->capture_substream = substream;
+ runtime->hw = snd_hdsp_capture_subinfo;
+ snd_pcm_set_runtime_buffer(substream, &hdsp->capture_dma_buf);
- spin_unlock_irq(&hdsp->lock);
+ hdsp->capture_pid = current->pid;
+ hdsp->capture_substream = substream;
+ }
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
@@ -4601,8 +4509,9 @@ static int snd_hdsp_capture_open(struct snd_pcm_substream *substream)
runtime->hw.channels_min = hdsp->qs_in_channels;
runtime->hw.channels_max = hdsp->ss_in_channels;
runtime->hw.rate_max = 192000;
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
+ runtime->hw.rates |= (SNDRV_PCM_RATE_128000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000);
}
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdsp_hw_rule_in_channels, hdsp,
@@ -4620,12 +4529,11 @@ static int snd_hdsp_capture_release(struct snd_pcm_substream *substream)
{
struct hdsp *hdsp = snd_pcm_substream_chip(substream);
- spin_lock_irq(&hdsp->lock);
+ guard(spinlock_irq)(&hdsp->lock);
hdsp->capture_pid = -1;
hdsp->capture_substream = NULL;
- spin_unlock_irq(&hdsp->lock);
return 0;
}
@@ -4788,7 +4696,6 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
}
case SNDRV_HDSP_IOCTL_GET_CONFIG_INFO: {
struct hdsp_config_info info;
- unsigned long flags;
int i;
err = hdsp_check_for_iobox(hdsp);
@@ -4800,48 +4707,48 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
return err;
memset(&info, 0, sizeof(info));
- spin_lock_irqsave(&hdsp->lock, flags);
- info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
- info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
- if (hdsp->io_type != H9632)
- info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
- info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
- for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
- info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
- info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
- info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp,
- HDSP_SPDIFOpticalOut);
- info.spdif_professional = (unsigned char)
- hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional);
- info.spdif_emphasis = (unsigned char)
- hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis);
- info.spdif_nonaudio = (unsigned char)
- hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio);
- info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
- info.system_sample_rate = hdsp->system_sample_rate;
- info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
- info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
- info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
- info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
- info.line_out = (unsigned char)
- hdsp_toggle_setting(hdsp, HDSP_LineOut);
- if (hdsp->io_type == H9632) {
- info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
- info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
- info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
- info.xlr_breakout_cable =
- (unsigned char)hdsp_toggle_setting(hdsp,
- HDSP_XLRBreakoutCable);
-
- } else if (hdsp->io_type == RPM) {
- info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
- info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
+ scoped_guard(spinlock_irqsave, &hdsp->lock) {
+ info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
+ info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
+ if (hdsp->io_type != H9632)
+ info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
+ info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
+ for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
+ info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
+ info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
+ info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp,
+ HDSP_SPDIFOpticalOut);
+ info.spdif_professional = (unsigned char)
+ hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional);
+ info.spdif_emphasis = (unsigned char)
+ hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis);
+ info.spdif_nonaudio = (unsigned char)
+ hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio);
+ info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
+ info.system_sample_rate = hdsp->system_sample_rate;
+ info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
+ info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
+ info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
+ info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
+ info.line_out = (unsigned char)
+ hdsp_toggle_setting(hdsp, HDSP_LineOut);
+ if (hdsp->io_type == H9632) {
+ info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
+ info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
+ info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
+ info.xlr_breakout_cable =
+ (unsigned char)hdsp_toggle_setting(hdsp,
+ HDSP_XLRBreakoutCable);
+
+ } else if (hdsp->io_type == RPM) {
+ info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
+ info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
+ }
+ if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
+ info.analog_extension_board =
+ (unsigned char)hdsp_toggle_setting(hdsp,
+ HDSP_AnalogExtensionBoard);
}
- if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
- info.analog_extension_board =
- (unsigned char)hdsp_toggle_setting(hdsp,
- HDSP_AnalogExtensionBoard);
- spin_unlock_irqrestore(&hdsp->lock, flags);
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
break;
@@ -4950,8 +4857,7 @@ static const struct snd_pcm_ops snd_hdsp_playback_ops = {
.prepare = snd_hdsp_prepare,
.trigger = snd_hdsp_trigger,
.pointer = snd_hdsp_hw_pointer,
- .copy_user = snd_hdsp_playback_copy,
- .copy_kernel = snd_hdsp_playback_copy_kernel,
+ .copy = snd_hdsp_playback_copy,
.fill_silence = snd_hdsp_hw_silence,
};
@@ -4963,8 +4869,7 @@ static const struct snd_pcm_ops snd_hdsp_capture_ops = {
.prepare = snd_hdsp_prepare,
.trigger = snd_hdsp_trigger,
.pointer = snd_hdsp_hw_pointer,
- .copy_user = snd_hdsp_capture_copy,
- .copy_kernel = snd_hdsp_capture_copy_kernel,
+ .copy = snd_hdsp_capture_copy,
};
static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
@@ -4978,7 +4883,7 @@ static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
hdsp->hwdep = hw;
hw->private_data = hdsp;
- strcpy(hw->name, "HDSP hwdep interface");
+ strscpy(hw->name, "HDSP hwdep interface");
hw->ops.ioctl = snd_hdsp_hwdep_ioctl;
hw->ops.ioctl_compat = snd_hdsp_hwdep_ioctl;
@@ -4997,7 +4902,7 @@ static int snd_hdsp_create_pcm(struct snd_card *card, struct hdsp *hdsp)
hdsp->pcm = pcm;
pcm->private_data = hdsp;
- strcpy(pcm->name, hdsp->card_name);
+ strscpy(pcm->name, hdsp->card_name);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_hdsp_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_hdsp_capture_ops);
@@ -5145,7 +5050,7 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
}
if (!(hdsp->state & HDSP_InitializationComplete)) {
- strcpy(card->shortname, "Hammerfall DSP");
+ strscpy(card->shortname, "Hammerfall DSP");
sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
hdsp->port, hdsp->irq);
@@ -5289,8 +5194,8 @@ static int snd_hdsp_create(struct snd_card *card,
*/
pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF);
- strcpy(card->driver, "H-DSP");
- strcpy(card->mixername, "Xilinx FPGA");
+ strscpy(card->driver, "H-DSP");
+ strscpy(card->mixername, "Xilinx FPGA");
if (hdsp->firmware_rev < 0xa)
return -ENODEV;
@@ -5311,7 +5216,7 @@ static int snd_hdsp_create(struct snd_card *card,
pci_set_master(hdsp->pci);
- err = pci_request_regions(pci, "hdsp");
+ err = pcim_request_all_regions(pci, "hdsp");
if (err < 0)
return err;
hdsp->port = pci_resource_start(pci, 0);
@@ -5446,7 +5351,7 @@ static int snd_hdsp_probe(struct pci_dev *pci,
if (err)
goto error;
- strcpy(card->shortname, "Hammerfall DSP");
+ strscpy(card->shortname, "Hammerfall DSP");
sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name,
hdsp->port, hdsp->irq);
err = snd_card_register(card);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 267c7848974a..3ba5bdc96d9d 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1204,16 +1204,11 @@ static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v)
/* check if same process is writing and reading */
static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
{
- unsigned long flags;
- int ret = 1;
-
- spin_lock_irqsave(&hdspm->lock, flags);
+ guard(spinlock_irqsave)(&hdspm->lock);
if ((hdspm->playback_pid != hdspm->capture_pid) &&
- (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) {
- ret = 0;
- }
- spin_unlock_irqrestore(&hdspm->lock, flags);
- return ret;
+ (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0))
+ return 0;
+ return 1;
}
/* round arbitrary sample rates to commonly known rates */
@@ -1527,7 +1522,7 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames)
{
int n;
- spin_lock_irq(&s->lock);
+ guard(spinlock_irq)(&s->lock);
if (32 == frames) {
/* Special case for new RME cards like RayDAT/AIO which
@@ -1557,8 +1552,6 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames)
hdspm_compute_period_size(s);
- spin_unlock_irq(&s->lock);
-
return 0;
}
@@ -1838,13 +1831,14 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id)
static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id)
{
- while (snd_hdspm_midi_input_available (hdspm, id))
- snd_hdspm_midi_read_byte (hdspm, id);
+ int count = 256;
+
+ while (snd_hdspm_midi_input_available(hdspm, id) && --count)
+ snd_hdspm_midi_read_byte(hdspm, id);
}
static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
{
- unsigned long flags;
int n_pending;
int to_write;
int i;
@@ -1852,7 +1846,7 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
/* Output is not interrupt driven */
- spin_lock_irqsave (&hmidi->lock, flags);
+ guard(spinlock_irqsave)(&hmidi->lock);
if (hmidi->output &&
!snd_rawmidi_transmit_empty (hmidi->output)) {
n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm,
@@ -1871,7 +1865,6 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
}
}
}
- spin_unlock_irqrestore (&hmidi->lock, flags);
return 0;
}
@@ -1880,37 +1873,36 @@ static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi)
unsigned char buf[128]; /* this buffer is designed to match the MIDI
* input FIFO size
*/
- unsigned long flags;
int n_pending;
int i;
- spin_lock_irqsave (&hmidi->lock, flags);
- n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id);
- if (n_pending > 0) {
- if (hmidi->input) {
- if (n_pending > (int)sizeof (buf))
- n_pending = sizeof (buf);
- for (i = 0; i < n_pending; ++i)
- buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm,
- hmidi->id);
- if (n_pending)
- snd_rawmidi_receive (hmidi->input, buf,
- n_pending);
- } else {
- /* flush the MIDI input FIFO */
- while (n_pending--)
- snd_hdspm_midi_read_byte (hmidi->hdspm,
- hmidi->id);
+ scoped_guard(spinlock_irqsave, &hmidi->lock) {
+ n_pending = snd_hdspm_midi_input_available(hmidi->hdspm, hmidi->id);
+ if (n_pending > 0) {
+ if (hmidi->input) {
+ if (n_pending > (int)sizeof(buf))
+ n_pending = sizeof(buf);
+ for (i = 0; i < n_pending; ++i)
+ buf[i] = snd_hdspm_midi_read_byte(hmidi->hdspm,
+ hmidi->id);
+ if (n_pending)
+ snd_rawmidi_receive(hmidi->input, buf,
+ n_pending);
+ } else {
+ /* flush the MIDI input FIFO */
+ while (n_pending--)
+ snd_hdspm_midi_read_byte(hmidi->hdspm,
+ hmidi->id);
+ }
}
+ hmidi->pending = 0;
}
- hmidi->pending = 0;
- spin_unlock_irqrestore(&hmidi->lock, flags);
- spin_lock_irqsave(&hmidi->hdspm->lock, flags);
- hmidi->hdspm->control_register |= hmidi->ie;
- hdspm_write(hmidi->hdspm, HDSPM_controlRegister,
- hmidi->hdspm->control_register);
- spin_unlock_irqrestore(&hmidi->hdspm->lock, flags);
+ scoped_guard(spinlock_irqsave, &hmidi->hdspm->lock) {
+ hmidi->hdspm->control_register |= hmidi->ie;
+ hdspm_write(hmidi->hdspm, HDSPM_controlRegister,
+ hmidi->hdspm->control_register);
+ }
return snd_hdspm_midi_output_write (hmidi);
}
@@ -1920,12 +1912,11 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct hdspm *hdspm;
struct hdspm_midi *hmidi;
- unsigned long flags;
hmidi = substream->rmidi->private_data;
hdspm = hmidi->hdspm;
- spin_lock_irqsave (&hdspm->lock, flags);
+ guard(spinlock_irqsave)(&hdspm->lock);
if (up) {
if (!(hdspm->control_register & hmidi->ie)) {
snd_hdspm_flush_midi_input (hdspm, hmidi->id);
@@ -1936,16 +1927,14 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
}
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
- spin_unlock_irqrestore (&hdspm->lock, flags);
}
static void snd_hdspm_midi_output_timer(struct timer_list *t)
{
- struct hdspm_midi *hmidi = from_timer(hmidi, t, timer);
- unsigned long flags;
+ struct hdspm_midi *hmidi = timer_container_of(hmidi, t, timer);
snd_hdspm_midi_output_write(hmidi);
- spin_lock_irqsave (&hmidi->lock, flags);
+ guard(spinlock_irqsave)(&hmidi->lock);
/* this does not bump hmidi->istimer, because the
kernel automatically removed the timer when it
@@ -1955,30 +1944,27 @@ static void snd_hdspm_midi_output_timer(struct timer_list *t)
if (hmidi->istimer)
mod_timer(&hmidi->timer, 1 + jiffies);
-
- spin_unlock_irqrestore (&hmidi->lock, flags);
}
static void
snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct hdspm_midi *hmidi;
- unsigned long flags;
hmidi = substream->rmidi->private_data;
- spin_lock_irqsave (&hmidi->lock, flags);
- if (up) {
- if (!hmidi->istimer) {
- timer_setup(&hmidi->timer,
- snd_hdspm_midi_output_timer, 0);
- mod_timer(&hmidi->timer, 1 + jiffies);
- hmidi->istimer++;
+ scoped_guard(spinlock_irqsave, &hmidi->lock) {
+ if (up) {
+ if (!hmidi->istimer) {
+ timer_setup(&hmidi->timer,
+ snd_hdspm_midi_output_timer, 0);
+ mod_timer(&hmidi->timer, 1 + jiffies);
+ hmidi->istimer++;
+ }
+ } else {
+ if (hmidi->istimer && --hmidi->istimer <= 0)
+ timer_delete(&hmidi->timer);
}
- } else {
- if (hmidi->istimer && --hmidi->istimer <= 0)
- del_timer (&hmidi->timer);
}
- spin_unlock_irqrestore (&hmidi->lock, flags);
if (up)
snd_hdspm_midi_output_write(hmidi);
}
@@ -1988,10 +1974,9 @@ static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream)
struct hdspm_midi *hmidi;
hmidi = substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id);
hmidi->input = substream;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -2001,9 +1986,8 @@ static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream)
struct hdspm_midi *hmidi;
hmidi = substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
hmidi->output = substream;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -2015,9 +1999,8 @@ static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream)
snd_hdspm_midi_input_trigger (substream, 0);
hmidi = substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
hmidi->input = NULL;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -2029,9 +2012,8 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream)
snd_hdspm_midi_output_trigger (substream, 0);
hmidi = substream->rmidi->private_data;
- spin_lock_irq (&hmidi->lock);
+ guard(spinlock_irq)(&hmidi->lock);
hmidi->output = NULL;
- spin_unlock_irq (&hmidi->lock);
return 0;
}
@@ -2669,12 +2651,11 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol,
val = 0;
if (val > 9)
val = 9;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
if (val != hdspm_clock_source(hdspm))
change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0;
else
change = 0;
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -2997,11 +2978,10 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
else if (val >= hdspm->texts_autosync_items)
val = hdspm->texts_autosync_items-1;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
if (val != hdspm_pref_sync_ref(hdspm))
change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0;
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3081,7 +3061,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
-#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \
+#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_READ |\
@@ -3127,7 +3107,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
-#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \
+#define HDSPM_TCO_LTC_FRAMES(xname) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_READ |\
@@ -3237,9 +3217,8 @@ static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol,
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask);
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3254,10 +3233,9 @@ static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol,
if (!snd_hdspm_use_is_exclusive(hdspm))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change = (int) val != hdspm_toggle_setting(hdspm, regmask);
hdspm_set_toggle_setting(hdspm, regmask, val);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3299,9 +3277,8 @@ static int snd_hdspm_get_input_select(struct snd_kcontrol *kcontrol,
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm);
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3315,10 +3292,9 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol,
if (!snd_hdspm_use_is_exclusive(hdspm))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change = (int) val != hdspm_input_select(hdspm);
hdspm_set_input_select(hdspm, val);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3361,9 +3337,8 @@ static int snd_hdspm_get_ds_wire(struct snd_kcontrol *kcontrol,
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.enumerated.item[0] = hdspm_ds_wire(hdspm);
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3377,10 +3352,9 @@ static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
if (!snd_hdspm_use_is_exclusive(hdspm))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change = (int) val != hdspm_ds_wire(hdspm);
hdspm_set_ds_wire(hdspm, val);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3434,9 +3408,8 @@ static int snd_hdspm_get_qs_wire(struct snd_kcontrol *kcontrol,
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.enumerated.item[0] = hdspm_qs_wire(hdspm);
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3454,10 +3427,9 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
val = 0;
if (val > 2)
val = 2;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change = val != hdspm_qs_wire(hdspm);
hdspm_set_qs_wire(hdspm, val);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3510,9 +3482,8 @@ static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol,
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask);
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3532,10 +3503,9 @@ static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol,
if (val > 2)
val = 2;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change = val != hdspm_tristate(hdspm, regmask);
hdspm_set_tristate(hdspm, val, regmask);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3588,9 +3558,8 @@ static int snd_hdspm_get_madi_speedmode(struct snd_kcontrol *kcontrol,
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.enumerated.item[0] = hdspm_madi_speedmode(hdspm);
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3608,10 +3577,9 @@ static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol,
val = 0;
if (val > 2)
val = 2;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change = val != hdspm_madi_speedmode(hdspm);
hdspm_set_madi_speedmode(hdspm, val);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3657,7 +3625,7 @@ static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol,
else if (destination >= HDSPM_MAX_CHANNELS)
destination = HDSPM_MAX_CHANNELS - 1;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
if (source >= HDSPM_MAX_CHANNELS)
ucontrol->value.integer.value[2] =
hdspm_read_pb_gain(hdspm, destination,
@@ -3666,8 +3634,6 @@ static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[2] =
hdspm_read_in_gain(hdspm, destination, source);
- spin_unlock_irq(&hdspm->lock);
-
return 0;
}
@@ -3693,7 +3659,7 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol,
gain = ucontrol->value.integer.value[2];
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
if (source >= HDSPM_MAX_CHANNELS)
change = gain != hdspm_read_pb_gain(hdspm, destination,
@@ -3712,7 +3678,6 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol,
hdspm_write_in_gain(hdspm, destination, source,
gain);
}
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -3753,10 +3718,9 @@ static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol,
if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
return -EINVAL;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
ucontrol->value.integer.value[0] =
(hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN;
- spin_unlock_irq(&hdspm->lock);
return 0;
}
@@ -3779,14 +3743,13 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64;
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
change =
gain != hdspm_read_pb_gain(hdspm, channel,
channel);
if (change)
hdspm_write_pb_gain(hdspm, channel, channel,
gain);
- spin_unlock_irq(&hdspm->lock);
return change;
}
@@ -4628,8 +4591,8 @@ static const struct snd_kcontrol_new snd_hdspm_controls_tco[] = {
HDSPM_TCO_WORD_TERM("TCO Word Term", 0),
HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11),
HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12),
- HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0),
- HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0)
+ HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate"),
+ HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format")
};
@@ -4925,14 +4888,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))
@@ -5086,12 +5049,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);
@@ -5497,53 +5457,50 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
pid_t this_pid;
pid_t other_pid;
- spin_lock_irq(&hdspm->lock);
+ scoped_guard(spinlock_irq, &hdspm->lock) {
- if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- this_pid = hdspm->playback_pid;
- other_pid = hdspm->capture_pid;
- } else {
- this_pid = hdspm->capture_pid;
- other_pid = hdspm->playback_pid;
- }
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ this_pid = hdspm->playback_pid;
+ other_pid = hdspm->capture_pid;
+ } else {
+ this_pid = hdspm->capture_pid;
+ other_pid = hdspm->playback_pid;
+ }
- if (other_pid > 0 && this_pid != other_pid) {
+ if (other_pid > 0 && this_pid != other_pid) {
- /* The other stream is open, and not by the same
- task as this one. Make sure that the parameters
- that matter are the same.
- */
+ /* The other stream is open, and not by the same
+ task as this one. Make sure that the parameters
+ that matter are the same.
+ */
- if (params_rate(params) != hdspm->system_sample_rate) {
- spin_unlock_irq(&hdspm->lock);
- _snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_RATE);
- return -EBUSY;
- }
+ if (params_rate(params) != hdspm->system_sample_rate) {
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ return -EBUSY;
+ }
- if (params_period_size(params) != hdspm->period_bytes / 4) {
- spin_unlock_irq(&hdspm->lock);
- _snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
- return -EBUSY;
- }
+ if (params_period_size(params) != hdspm->period_bytes / 4) {
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ return -EBUSY;
+ }
+ }
}
/* We're fine. */
- spin_unlock_irq(&hdspm->lock);
/* how to make sure that the rate matches an externally-set one ? */
- spin_lock_irq(&hdspm->lock);
- err = hdspm_set_rate(hdspm, params_rate(params), 0);
- if (err < 0) {
- dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err);
- spin_unlock_irq(&hdspm->lock);
- _snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_RATE);
- return err;
+ scoped_guard(spinlock_irq, &hdspm->lock) {
+ err = hdspm_set_rate(hdspm, params_rate(params), 0);
+ if (err < 0) {
+ dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err);
+ _snd_pcm_hw_param_setempty(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ return err;
+ }
}
- spin_unlock_irq(&hdspm->lock);
err = hdspm_set_interrupt_interval(hdspm,
params_period_size(params));
@@ -5610,15 +5567,13 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
/*
dev_dbg(hdspm->card->dev,
"Allocated sample buffer for %s at 0x%08X\n",
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- "playback" : "capture",
+ snd_pcm_direction_name(substream->stream),
snd_pcm_sgbuf_get_addr(substream, 0));
*/
/*
dev_dbg(hdspm->card->dev,
"set_hwparams: %s %d Hz, %d channels, bs = %d\n",
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- "playback" : "capture",
+ snd_pcm_direction_name(substream->stream),
params_rate(params), params_channels(params),
params_buffer_size(params));
*/
@@ -5753,7 +5708,7 @@ static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_pcm_substream *other;
int running;
- spin_lock(&hdspm->lock);
+ guard(spinlock)(&hdspm->lock);
running = hdspm->running;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -5764,7 +5719,6 @@ static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd)
break;
default:
snd_BUG();
- spin_unlock(&hdspm->lock);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -5805,7 +5759,6 @@ _ok:
else if (hdspm->running && !running)
hdspm_stop_audio(hdspm);
hdspm->running = running;
- spin_unlock(&hdspm->lock);
return 0;
}
@@ -6032,45 +5985,32 @@ static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params,
return snd_interval_list(c, 3, list, 0);
}
-
-static const unsigned int hdspm_aes32_sample_rates[] = {
- 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000
-};
-
-static const struct snd_pcm_hw_constraint_list
-hdspm_hw_constraints_aes32_sample_rates = {
- .count = ARRAY_SIZE(hdspm_aes32_sample_rates),
- .list = hdspm_aes32_sample_rates,
- .mask = 0
-};
-
static int snd_hdspm_open(struct snd_pcm_substream *substream)
{
struct hdspm *hdspm = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- spin_lock_irq(&hdspm->lock);
- snd_pcm_set_sync(substream);
- runtime->hw = (playback) ? snd_hdspm_playback_subinfo :
- snd_hdspm_capture_subinfo;
+ scoped_guard(spinlock_irq, &hdspm->lock) {
+ snd_pcm_set_sync(substream);
+ runtime->hw = (playback) ? snd_hdspm_playback_subinfo :
+ snd_hdspm_capture_subinfo;
- if (playback) {
- if (!hdspm->capture_substream)
- hdspm_stop_audio(hdspm);
+ if (playback) {
+ if (!hdspm->capture_substream)
+ hdspm_stop_audio(hdspm);
- hdspm->playback_pid = current->pid;
- hdspm->playback_substream = substream;
- } else {
- if (!hdspm->playback_substream)
- hdspm_stop_audio(hdspm);
+ hdspm->playback_pid = current->pid;
+ hdspm->playback_substream = substream;
+ } else {
+ if (!hdspm->playback_substream)
+ hdspm_stop_audio(hdspm);
- hdspm->capture_pid = current->pid;
- hdspm->capture_substream = substream;
+ hdspm->capture_pid = current->pid;
+ hdspm->capture_substream = substream;
+ }
}
- spin_unlock_irq(&hdspm->lock);
-
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
@@ -6096,9 +6036,7 @@ static int snd_hdspm_open(struct snd_pcm_substream *substream)
}
if (AES32 == hdspm->io_type) {
- runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- &hdspm_hw_constraints_aes32_sample_rates);
+ runtime->hw.rates |= SNDRV_PCM_RATE_128000;
} else {
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
(playback ?
@@ -6125,7 +6063,7 @@ static int snd_hdspm_release(struct snd_pcm_substream *substream)
struct hdspm *hdspm = snd_pcm_substream_chip(substream);
bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- spin_lock_irq(&hdspm->lock);
+ guard(spinlock_irq)(&hdspm->lock);
if (playback) {
hdspm->playback_pid = -1;
@@ -6135,8 +6073,6 @@ static int snd_hdspm_release(struct snd_pcm_substream *substream)
hdspm->capture_substream = NULL;
}
- spin_unlock_irq(&hdspm->lock);
-
return 0;
}
@@ -6259,19 +6195,19 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
case SNDRV_HDSPM_IOCTL_GET_CONFIG:
memset(&info, 0, sizeof(info));
- spin_lock_irq(&hdspm->lock);
- info.pref_sync_ref = hdspm_pref_sync_ref(hdspm);
- info.wordclock_sync_check = hdspm_wc_sync_check(hdspm);
-
- info.system_sample_rate = hdspm->system_sample_rate;
- info.autosync_sample_rate =
- hdspm_external_sample_rate(hdspm);
- info.system_clock_mode = hdspm_system_clock_mode(hdspm);
- info.clock_source = hdspm_clock_source(hdspm);
- info.autosync_ref = hdspm_autosync_ref(hdspm);
- info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut);
- info.passthru = 0;
- spin_unlock_irq(&hdspm->lock);
+ scoped_guard(spinlock_irq, &hdspm->lock) {
+ info.pref_sync_ref = hdspm_pref_sync_ref(hdspm);
+ info.wordclock_sync_check = hdspm_wc_sync_check(hdspm);
+
+ info.system_sample_rate = hdspm->system_sample_rate;
+ info.autosync_sample_rate =
+ hdspm_external_sample_rate(hdspm);
+ info.system_clock_mode = hdspm_system_clock_mode(hdspm);
+ info.clock_source = hdspm_clock_source(hdspm);
+ info.autosync_ref = hdspm_autosync_ref(hdspm);
+ info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut);
+ info.passthru = 0;
+ }
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
break;
@@ -6372,7 +6308,7 @@ static int snd_hdspm_create_hwdep(struct snd_card *card,
hdspm->hwdep = hw;
hw->private_data = hdspm;
- strcpy(hw->name, "HDSPM hwdep interface");
+ strscpy(hw->name, "HDSPM hwdep interface");
hw->ops.open = snd_hdspm_hwdep_dummy_op;
hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
@@ -6429,7 +6365,7 @@ static int snd_hdspm_create_pcm(struct snd_card *card,
hdspm->pcm = pcm;
pcm->private_data = hdspm;
- strcpy(pcm->name, hdspm->card_name);
+ strscpy(pcm->name, hdspm->card_name);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_hdspm_ops);
@@ -6529,8 +6465,8 @@ static int snd_hdspm_create(struct snd_card *card,
pci_read_config_word(hdspm->pci,
PCI_CLASS_REVISION, &hdspm->firmware_rev);
- strcpy(card->mixername, "Xilinx FPGA");
- strcpy(card->driver, "HDSPM");
+ strscpy(card->mixername, "Xilinx FPGA");
+ strscpy(card->driver, "HDSPM");
switch (hdspm->firmware_rev) {
case HDSPM_RAYDAT_REV:
@@ -6575,13 +6511,12 @@ static int snd_hdspm_create(struct snd_card *card,
pci_set_master(hdspm->pci);
- err = pcim_iomap_regions(pci, 1 << 0, "hdspm");
- if (err < 0)
- return err;
+ hdspm->iobase = pcim_iomap_region(pci, 0, "hdspm");
+ if (IS_ERR(hdspm->iobase))
+ return PTR_ERR(hdspm->iobase);
hdspm->port = pci_resource_start(pci, 0);
io_extent = pci_resource_len(pci, 0);
- hdspm->iobase = pcim_iomap_table(pci)[0];
dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n",
(unsigned long)hdspm->iobase, hdspm->port,
hdspm->port + io_extent - 1);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index e7c320afefe8..3be30cb57a2e 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -308,16 +308,11 @@ static inline unsigned int rme9652_read(struct snd_rme9652 *rme9652, int reg)
static inline int snd_rme9652_use_is_exclusive(struct snd_rme9652 *rme9652)
{
- unsigned long flags;
- int ret = 1;
-
- spin_lock_irqsave(&rme9652->lock, flags);
+ guard(spinlock_irqsave)(&rme9652->lock);
if ((rme9652->playback_pid != rme9652->capture_pid) &&
- (rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0)) {
- ret = 0;
- }
- spin_unlock_irqrestore(&rme9652->lock, flags);
- return ret;
+ (rme9652->playback_pid >= 0) && (rme9652->capture_pid >= 0))
+ return 0;
+ return 1;
}
static inline int rme9652_adat_sample_rate(struct snd_rme9652 *rme9652)
@@ -428,7 +423,7 @@ static int rme9652_set_interrupt_interval(struct snd_rme9652 *s,
int restart = 0;
int n;
- spin_lock_irq(&s->lock);
+ guard(spinlock_irq)(&s->lock);
restart = s->running;
if (restart)
@@ -451,8 +446,6 @@ static int rme9652_set_interrupt_interval(struct snd_rme9652 *s,
if (restart)
rme9652_start(s);
- spin_unlock_irq(&s->lock);
-
return 0;
}
@@ -477,7 +470,7 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate)
is to flag rate changes in the read/write routines.
*/
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
xrate = rme9652_adat_sample_rate(rme9652);
switch (rate) {
@@ -506,14 +499,11 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate)
rate = RME9652_DS | RME9652_freq;
break;
default:
- spin_unlock_irq(&rme9652->lock);
return -EINVAL;
}
- if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0)) {
- spin_unlock_irq(&rme9652->lock);
+ if (reject_if_open && (rme9652->capture_pid >= 0 || rme9652->playback_pid >= 0))
return -EBUSY;
- }
restart = rme9652->running;
if (restart)
@@ -539,7 +529,6 @@ static int rme9652_set_rate(struct snd_rme9652 *rme9652, int rate)
}
}
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -798,10 +787,9 @@ static int snd_rme9652_control_spdif_put(struct snd_kcontrol *kcontrol, struct s
u32 val;
val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = val != rme9652->creg_spdif;
rme9652->creg_spdif = val;
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -827,12 +815,11 @@ static int snd_rme9652_control_spdif_stream_put(struct snd_kcontrol *kcontrol, s
u32 val;
val = snd_rme9652_convert_from_aes(&ucontrol->value.iec958);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = val != rme9652->creg_spdif_stream;
rme9652->creg_spdif_stream = val;
rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= val);
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -897,9 +884,8 @@ static int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ct
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_adat1_in(rme9652);
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -912,11 +898,10 @@ static int snd_rme9652_put_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ct
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.enumerated.item[0] % 2;
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = val != rme9652_adat1_in(rme9652);
if (change)
rme9652_set_adat1_input(rme9652, val);
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -961,9 +946,8 @@ static int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ct
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_spdif_in(rme9652);
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -976,11 +960,10 @@ static int snd_rme9652_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ct
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.enumerated.item[0] % 3;
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = val != rme9652_spdif_in(rme9652);
if (change)
rme9652_set_spdif_input(rme9652, val);
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -1022,9 +1005,8 @@ static int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_c
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.integer.value[0] = rme9652_spdif_out(rme9652);
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -1037,10 +1019,9 @@ static int snd_rme9652_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_c
if (!snd_rme9652_use_is_exclusive(rme9652))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = (int)val != rme9652_spdif_out(rme9652);
rme9652_set_spdif_output(rme9652, val);
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -1104,9 +1085,8 @@ static int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_c
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_sync_mode(rme9652);
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -1117,10 +1097,9 @@ static int snd_rme9652_put_sync_mode(struct snd_kcontrol *kcontrol, struct snd_c
unsigned int val;
val = ucontrol->value.enumerated.item[0] % 3;
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = (int)val != rme9652_sync_mode(rme9652);
rme9652_set_sync_mode(rme9652, val);
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -1193,9 +1172,8 @@ static int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_c
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.enumerated.item[0] = rme9652_sync_pref(rme9652);
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -1209,10 +1187,9 @@ static int snd_rme9652_put_sync_pref(struct snd_kcontrol *kcontrol, struct snd_c
return -EBUSY;
max = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3;
val = ucontrol->value.enumerated.item[0] % max;
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = (int)val != rme9652_sync_pref(rme9652);
rme9652_set_sync_pref(rme9652, val);
- spin_unlock_irq(&rme9652->lock);
return change;
}
@@ -1253,7 +1230,7 @@ static int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_el
thru_bits |= 1 << chn;
}
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = thru_bits ^ rme9652->thru_bits;
if (change) {
for (chn = 0; chn < rme9652->ss_channels; ++chn) {
@@ -1262,7 +1239,6 @@ static int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_el
rme9652_set_thru(rme9652,chn,thru_bits&(1<<chn));
}
}
- spin_unlock_irq(&rme9652->lock);
return !!change;
}
@@ -1278,9 +1254,8 @@ static int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ct
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.integer.value[0] = rme9652->passthru;
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -1295,11 +1270,10 @@ static int snd_rme9652_put_passthru(struct snd_kcontrol *kcontrol, struct snd_ct
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
change = (ucontrol->value.integer.value[0] != rme9652->passthru);
if (change)
err = rme9652_set_passthru(rme9652, val);
- spin_unlock_irq(&rme9652->lock);
return err ? err : change;
}
@@ -1324,9 +1298,8 @@ static int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_
{
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652);
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -1561,8 +1534,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 +1657,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 */
@@ -1844,7 +1816,7 @@ static signed char *rme9652_channel_buffer_location(struct snd_rme9652 *rme9652,
static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
signed char *channel_buf;
@@ -1857,30 +1829,14 @@ static int snd_rme9652_playback_copy(struct snd_pcm_substream *substream,
channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
- if (copy_from_user(channel_buf + pos, src, count))
+ if (copy_from_iter(channel_buf + pos, count, src) != count)
return -EFAULT;
return 0;
}
-static int snd_rme9652_playback_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
-{
- struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
- signed char *channel_buf;
-
- channel_buf = rme9652_channel_buffer_location(rme9652,
- substream->pstr->stream,
- channel);
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
- memcpy(channel_buf + pos, src, count);
- return 0;
-}
-
static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *dst, unsigned long count)
+ struct iov_iter *dst, unsigned long count)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
signed char *channel_buf;
@@ -1893,27 +1849,11 @@ static int snd_rme9652_capture_copy(struct snd_pcm_substream *substream,
channel);
if (snd_BUG_ON(!channel_buf))
return -EIO;
- if (copy_to_user(dst, channel_buf + pos, count))
+ if (copy_to_iter(channel_buf + pos, count, dst) != count)
return -EFAULT;
return 0;
}
-static int snd_rme9652_capture_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *dst, unsigned long count)
-{
- struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
- signed char *channel_buf;
-
- channel_buf = rme9652_channel_buffer_location(rme9652,
- substream->pstr->stream,
- channel);
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
- memcpy(dst, channel_buf + pos, count);
- return 0;
-}
-
static int snd_rme9652_hw_silence(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
unsigned long count)
@@ -1964,45 +1904,39 @@ static int snd_rme9652_hw_params(struct snd_pcm_substream *substream,
pid_t this_pid;
pid_t other_pid;
- spin_lock_irq(&rme9652->lock);
-
- if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
- rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream);
- this_pid = rme9652->playback_pid;
- other_pid = rme9652->capture_pid;
- } else {
- this_pid = rme9652->capture_pid;
- other_pid = rme9652->playback_pid;
- }
+ scoped_guard(spinlock_irq, &rme9652->lock) {
- if ((other_pid > 0) && (this_pid != other_pid)) {
-
- /* The other stream is open, and not by the same
- task as this one. Make sure that the parameters
- that matter are the same.
- */
-
- if ((int)params_rate(params) !=
- rme9652_adat_sample_rate(rme9652)) {
- spin_unlock_irq(&rme9652->lock);
- _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
- return -EBUSY;
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ rme9652->control_register &= ~(RME9652_PRO | RME9652_Dolby | RME9652_EMP);
+ rme9652_write(rme9652, RME9652_control_register, rme9652->control_register |= rme9652->creg_spdif_stream);
+ this_pid = rme9652->playback_pid;
+ other_pid = rme9652->capture_pid;
+ } else {
+ this_pid = rme9652->capture_pid;
+ other_pid = rme9652->playback_pid;
}
- if (params_period_size(params) != rme9652->period_bytes / 4) {
- spin_unlock_irq(&rme9652->lock);
- _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
- return -EBUSY;
- }
+ if ((other_pid > 0) && (this_pid != other_pid)) {
- /* We're fine. */
+ /* The other stream is open, and not by the same
+ task as this one. Make sure that the parameters
+ that matter are the same.
+ */
- spin_unlock_irq(&rme9652->lock);
- return 0;
+ if ((int)params_rate(params) !=
+ rme9652_adat_sample_rate(rme9652)) {
+ _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
+ return -EBUSY;
+ }
- } else {
- spin_unlock_irq(&rme9652->lock);
+ if (params_period_size(params) != rme9652->period_bytes / 4) {
+ _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ return -EBUSY;
+ }
+
+ /* We're fine. */
+ return 0;
+ }
}
/* how to make sure that the rate matches an externally-set one ?
@@ -2074,7 +2008,8 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream,
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_substream *other;
int running;
- spin_lock(&rme9652->lock);
+
+ guard(spinlock)(&rme9652->lock);
running = rme9652->running;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -2085,7 +2020,6 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream,
break;
default:
snd_BUG();
- spin_unlock(&rme9652->lock);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -2125,7 +2059,6 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream,
else if (rme9652->running && !running)
rme9652_stop(rme9652);
rme9652->running = running;
- spin_unlock(&rme9652->lock);
return 0;
}
@@ -2133,12 +2066,10 @@ static int snd_rme9652_trigger(struct snd_pcm_substream *substream,
static int snd_rme9652_prepare(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
- unsigned long flags;
- spin_lock_irqsave(&rme9652->lock, flags);
+ guard(spinlock_irqsave)(&rme9652->lock);
if (!rme9652->running)
rme9652_reset_hw_pointer(rme9652);
- spin_unlock_irqrestore(&rme9652->lock, flags);
return 0;
}
@@ -2259,23 +2190,21 @@ static int snd_rme9652_playback_open(struct snd_pcm_substream *substream)
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- spin_lock_irq(&rme9652->lock);
+ scoped_guard(spinlock_irq, &rme9652->lock) {
+ snd_pcm_set_sync(substream);
- snd_pcm_set_sync(substream);
+ runtime->hw = snd_rme9652_playback_subinfo;
+ snd_pcm_set_runtime_buffer(substream, &rme9652->playback_dma_buf);
- runtime->hw = snd_rme9652_playback_subinfo;
- snd_pcm_set_runtime_buffer(substream, &rme9652->playback_dma_buf);
+ if (rme9652->capture_substream == NULL) {
+ rme9652_stop(rme9652);
+ rme9652_set_thru(rme9652, -1, 0);
+ }
- if (rme9652->capture_substream == NULL) {
- rme9652_stop(rme9652);
- rme9652_set_thru(rme9652, -1, 0);
+ rme9652->playback_pid = current->pid;
+ rme9652->playback_substream = substream;
}
- rme9652->playback_pid = current->pid;
- rme9652->playback_substream = substream;
-
- spin_unlock_irq(&rme9652->lock);
-
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -2299,12 +2228,10 @@ static int snd_rme9652_playback_release(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme9652->lock);
-
- rme9652->playback_pid = -1;
- rme9652->playback_substream = NULL;
-
- spin_unlock_irq(&rme9652->lock);
+ scoped_guard(spinlock_irq, &rme9652->lock) {
+ rme9652->playback_pid = -1;
+ rme9652->playback_substream = NULL;
+ }
rme9652->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(rme9652->card, SNDRV_CTL_EVENT_MASK_VALUE |
@@ -2318,23 +2245,21 @@ static int snd_rme9652_capture_open(struct snd_pcm_substream *substream)
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- spin_lock_irq(&rme9652->lock);
+ scoped_guard(spinlock_irq, &rme9652->lock) {
+ snd_pcm_set_sync(substream);
- snd_pcm_set_sync(substream);
+ runtime->hw = snd_rme9652_capture_subinfo;
+ snd_pcm_set_runtime_buffer(substream, &rme9652->capture_dma_buf);
- runtime->hw = snd_rme9652_capture_subinfo;
- snd_pcm_set_runtime_buffer(substream, &rme9652->capture_dma_buf);
+ if (rme9652->playback_substream == NULL) {
+ rme9652_stop(rme9652);
+ rme9652_set_thru(rme9652, -1, 0);
+ }
- if (rme9652->playback_substream == NULL) {
- rme9652_stop(rme9652);
- rme9652_set_thru(rme9652, -1, 0);
+ rme9652->capture_pid = current->pid;
+ rme9652->capture_substream = substream;
}
- rme9652->capture_pid = current->pid;
- rme9652->capture_substream = substream;
-
- spin_unlock_irq(&rme9652->lock);
-
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -2353,12 +2278,11 @@ static int snd_rme9652_capture_release(struct snd_pcm_substream *substream)
{
struct snd_rme9652 *rme9652 = snd_pcm_substream_chip(substream);
- spin_lock_irq(&rme9652->lock);
+ guard(spinlock_irq)(&rme9652->lock);
rme9652->capture_pid = -1;
rme9652->capture_substream = NULL;
- spin_unlock_irq(&rme9652->lock);
return 0;
}
@@ -2370,8 +2294,7 @@ static const struct snd_pcm_ops snd_rme9652_playback_ops = {
.prepare = snd_rme9652_prepare,
.trigger = snd_rme9652_trigger,
.pointer = snd_rme9652_hw_pointer,
- .copy_user = snd_rme9652_playback_copy,
- .copy_kernel = snd_rme9652_playback_copy_kernel,
+ .copy = snd_rme9652_playback_copy,
.fill_silence = snd_rme9652_hw_silence,
};
@@ -2383,8 +2306,7 @@ static const struct snd_pcm_ops snd_rme9652_capture_ops = {
.prepare = snd_rme9652_prepare,
.trigger = snd_rme9652_trigger,
.pointer = snd_rme9652_hw_pointer,
- .copy_user = snd_rme9652_capture_copy,
- .copy_kernel = snd_rme9652_capture_copy_kernel,
+ .copy = snd_rme9652_capture_copy,
};
static int snd_rme9652_create_pcm(struct snd_card *card,
@@ -2399,7 +2321,7 @@ static int snd_rme9652_create_pcm(struct snd_card *card,
rme9652->pcm = pcm;
pcm->private_data = rme9652;
- strcpy(pcm->name, rme9652->card_name);
+ strscpy(pcm->name, rme9652->card_name);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme9652_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme9652_capture_ops);
@@ -2441,7 +2363,7 @@ static int snd_rme9652_create(struct snd_card *card,
spin_lock_init(&rme9652->lock);
- err = pci_request_regions(pci, "rme9652");
+ err = pcim_request_all_regions(pci, "rme9652");
if (err < 0)
return err;
rme9652->port = pci_resource_start(pci, 0);
@@ -2482,7 +2404,7 @@ static int snd_rme9652_create(struct snd_card *card,
switch (rev) {
case 8: /* original eprom */
- strcpy(card->driver, "RME9636");
+ strscpy(card->driver, "RME9636");
if (rme9652->hw_rev == 15) {
rme9652->card_name = "RME Digi9636 (Rev 1.5)";
} else {
@@ -2491,17 +2413,17 @@ static int snd_rme9652_create(struct snd_card *card,
rme9652->ss_channels = RME9636_NCHANNELS;
break;
case 9: /* W36_G EPROM */
- strcpy(card->driver, "RME9636");
+ strscpy(card->driver, "RME9636");
rme9652->card_name = "RME Digi9636 (Rev G)";
rme9652->ss_channels = RME9636_NCHANNELS;
break;
case 4: /* W52_G EPROM */
- strcpy(card->driver, "RME9652");
+ strscpy(card->driver, "RME9652");
rme9652->card_name = "RME Digi9652 (Rev G)";
rme9652->ss_channels = RME9652_NCHANNELS;
break;
case 3: /* original eprom */
- strcpy(card->driver, "RME9652");
+ strscpy(card->driver, "RME9652");
if (rme9652->hw_rev == 15) {
rme9652->card_name = "RME Digi9652 (Rev 1.5)";
} else {
@@ -2574,7 +2496,7 @@ static int snd_rme9652_probe(struct pci_dev *pci,
if (err)
goto error;
- strcpy(card->shortname, rme9652->card_name);
+ strscpy(card->shortname, rme9652->card_name);
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname, rme9652->port, rme9652->irq);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index fabe393607f8..4be085d27712 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -90,11 +90,7 @@ struct voice {
* we're not doing power management, we still need to allocate a page
* for the silence buffer.
*/
-#ifdef CONFIG_PM_SLEEP
#define SIS_SUSPEND_PAGES 4
-#else
-#define SIS_SUSPEND_PAGES 1
-#endif
struct sis7019 {
unsigned long ioport;
@@ -387,9 +383,7 @@ static void __sis_unmap_silence(struct sis7019 *sis)
static void sis_free_voice(struct sis7019 *sis, struct voice *voice)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sis->voice_lock, flags);
+ guard(spinlock_irqsave)(&sis->voice_lock);
if (voice->timing) {
__sis_unmap_silence(sis);
voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING |
@@ -397,7 +391,6 @@ static void sis_free_voice(struct sis7019 *sis, struct voice *voice)
voice->timing = NULL;
}
voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING);
- spin_unlock_irqrestore(&sis->voice_lock, flags);
}
static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis)
@@ -421,14 +414,8 @@ found_one:
static struct voice *sis_alloc_playback_voice(struct sis7019 *sis)
{
- struct voice *voice;
- unsigned long flags;
-
- spin_lock_irqsave(&sis->voice_lock, flags);
- voice = __sis_alloc_playback_voice(sis);
- spin_unlock_irqrestore(&sis->voice_lock, flags);
-
- return voice;
+ guard(spinlock_irqsave)(&sis->voice_lock);
+ return __sis_alloc_playback_voice(sis);
}
static int sis_alloc_timing_voice(struct snd_pcm_substream *substream,
@@ -438,7 +425,6 @@ static int sis_alloc_timing_voice(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct voice *voice = runtime->private_data;
unsigned int period_size, buffer_size;
- unsigned long flags;
int needed;
/* If there are one or two periods per buffer, we don't need a
@@ -451,11 +437,11 @@ static int sis_alloc_timing_voice(struct snd_pcm_substream *substream,
period_size != (buffer_size / 2));
if (needed && !voice->timing) {
- spin_lock_irqsave(&sis->voice_lock, flags);
- voice->timing = __sis_alloc_playback_voice(sis);
- if (voice->timing)
- __sis_map_silence(sis);
- spin_unlock_irqrestore(&sis->voice_lock, flags);
+ scoped_guard(spinlock_irqsave, &sis->voice_lock) {
+ voice->timing = __sis_alloc_playback_voice(sis);
+ if (voice->timing)
+ __sis_map_silence(sis);
+ }
if (!voice->timing)
return -ENOMEM;
voice->timing->substream = substream;
@@ -649,17 +635,16 @@ static int sis_capture_open(struct snd_pcm_substream *substream)
struct sis7019 *sis = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct voice *voice = &sis->capture_voice;
- unsigned long flags;
/* FIXME: The driver only supports recording from one channel
* at the moment, but it could support more.
*/
- spin_lock_irqsave(&sis->voice_lock, flags);
- if (voice->flags & VOICE_IN_USE)
- voice = NULL;
- else
- voice->flags |= VOICE_IN_USE;
- spin_unlock_irqrestore(&sis->voice_lock, flags);
+ scoped_guard(spinlock_irqsave, &sis->voice_lock) {
+ if (voice->flags & VOICE_IN_USE)
+ voice = NULL;
+ else
+ voice->flags |= VOICE_IN_USE;
+ }
if (!voice)
return -EAGAIN;
@@ -872,7 +857,7 @@ static int sis_pcm_create(struct sis7019 *sis)
return rc;
pcm->private_data = sis;
- strcpy(pcm->name, "SiS7019");
+ strscpy(pcm->name, "SiS7019");
sis->pcm = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sis_playback_ops);
@@ -906,7 +891,7 @@ static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd)
/* Get the AC97 semaphore -- software first, so we don't spin
* pounding out IO reads on the hardware semaphore...
*/
- mutex_lock(&sis->ac97_mutex);
+ guard(mutex)(&sis->ac97_mutex);
count = 0xffff;
while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count)
@@ -945,8 +930,6 @@ static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd)
timeout_sema:
outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
timeout:
- mutex_unlock(&sis->ac97_mutex);
-
if (!count) {
dev_err(&sis->pci->dev, "ac97 codec %d timeout cmd 0x%08x\n",
codec, cmd);
@@ -1152,7 +1135,6 @@ static int sis_chip_init(struct sis7019 *sis)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int sis_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -1231,11 +1213,7 @@ error:
return -EIO;
}
-static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
-#define SIS_PM_OPS &sis_pm
-#else
-#define SIS_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
static int sis_alloc_suspend(struct sis7019 *sis)
{
@@ -1282,7 +1260,7 @@ static int sis_chip_create(struct snd_card *card,
sis->irq = -1;
sis->ioport = pci_resource_start(pci, 0);
- rc = pci_request_regions(pci, "SiS7019");
+ rc = pcim_request_all_regions(pci, "SiS7019");
if (rc) {
dev_err(&pci->dev, "unable request regions\n");
return rc;
@@ -1357,8 +1335,8 @@ static int __snd_sis7019_probe(struct pci_dev *pci,
if (rc < 0)
return rc;
- strcpy(card->driver, "SiS7019");
- strcpy(card->shortname, "SiS7019");
+ strscpy(card->driver, "SiS7019");
+ strscpy(card->shortname, "SiS7019");
rc = sis_chip_create(card, pci);
if (rc)
return rc;
@@ -1397,7 +1375,7 @@ static struct pci_driver sis7019_driver = {
.id_table = snd_sis7019_ids,
.probe = snd_sis7019_probe,
.driver = {
- .pm = SIS_PM_OPS,
+ .pm = &sis_pm,
},
};
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index f91cbf6eeca0..a4c72799d034 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -303,14 +303,11 @@ static void snd_sonicvibes_out(struct sonicvibes * sonic,
unsigned char reg,
unsigned char value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sonic->reg_lock, flags);
+ guard(spinlock_irqsave)(&sonic->reg_lock);
outb(reg, SV_REG(sonic, INDEX));
udelay(10);
outb(value, SV_REG(sonic, DATA));
udelay(10);
- spin_unlock_irqrestore(&sonic->reg_lock, flags);
}
static unsigned char snd_sonicvibes_in1(struct sonicvibes * sonic, unsigned char reg)
@@ -326,15 +323,13 @@ static unsigned char snd_sonicvibes_in1(struct sonicvibes * sonic, unsigned char
static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char reg)
{
- unsigned long flags;
unsigned char value;
- spin_lock_irqsave(&sonic->reg_lock, flags);
+ guard(spinlock_irqsave)(&sonic->reg_lock);
outb(reg, SV_REG(sonic, INDEX));
udelay(10);
value = inb(SV_REG(sonic, DATA));
udelay(10);
- spin_unlock_irqrestore(&sonic->reg_lock, flags);
return value;
}
@@ -448,9 +443,7 @@ static void snd_sonicvibes_setfmt(struct sonicvibes * sonic,
unsigned char mask,
unsigned char value)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sonic->reg_lock, flags);
+ guard(spinlock_irqsave)(&sonic->reg_lock);
outb(SV_MCE | SV_IREG_DMA_DATA_FMT, SV_REG(sonic, INDEX));
if (mask) {
sonic->format = inb(SV_REG(sonic, DATA));
@@ -461,7 +454,6 @@ static void snd_sonicvibes_setfmt(struct sonicvibes * sonic,
udelay(10);
outb(0, SV_REG(sonic, INDEX));
udelay(10);
- spin_unlock_irqrestore(&sonic->reg_lock, flags);
}
static void snd_sonicvibes_pll(unsigned int rate,
@@ -506,21 +498,18 @@ static void snd_sonicvibes_setpll(struct sonicvibes * sonic,
unsigned char reg,
unsigned int rate)
{
- unsigned long flags;
unsigned int r, m, n;
snd_sonicvibes_pll(rate, &r, &m, &n);
if (sonic != NULL) {
- spin_lock_irqsave(&sonic->reg_lock, flags);
+ guard(spinlock_irqsave)(&sonic->reg_lock);
snd_sonicvibes_out1(sonic, reg, m);
snd_sonicvibes_out1(sonic, reg + 1, r | n);
- spin_unlock_irqrestore(&sonic->reg_lock, flags);
}
}
static void snd_sonicvibes_set_adc_rate(struct sonicvibes * sonic, unsigned int rate)
{
- unsigned long flags;
unsigned int div;
unsigned char clock;
@@ -533,10 +522,9 @@ static void snd_sonicvibes_set_adc_rate(struct sonicvibes * sonic, unsigned int
clock = 0x00;
snd_sonicvibes_setpll(sonic, SV_IREG_ADC_PLL, rate);
}
- spin_lock_irqsave(&sonic->reg_lock, flags);
+ guard(spinlock_irqsave)(&sonic->reg_lock);
snd_sonicvibes_out1(sonic, SV_IREG_ADC_ALT_RATE, (div - 1) << 4);
snd_sonicvibes_out1(sonic, SV_IREG_ADC_CLOCK, clock);
- spin_unlock_irqrestore(&sonic->reg_lock, flags);
}
static int snd_sonicvibes_hw_constraint_dac_rate(struct snd_pcm_hw_params *params,
@@ -567,22 +555,18 @@ static int snd_sonicvibes_hw_constraint_dac_rate(struct snd_pcm_hw_params *param
static void snd_sonicvibes_set_dac_rate(struct sonicvibes * sonic, unsigned int rate)
{
unsigned int div;
- unsigned long flags;
div = DIV_ROUND_CLOSEST(rate * 65536, SV_FULLRATE);
if (div > 65535)
div = 65535;
- spin_lock_irqsave(&sonic->reg_lock, flags);
+ guard(spinlock_irqsave)(&sonic->reg_lock);
snd_sonicvibes_out1(sonic, SV_IREG_PCM_RATE_HIGH, div >> 8);
snd_sonicvibes_out1(sonic, SV_IREG_PCM_RATE_LOW, div);
- spin_unlock_irqrestore(&sonic->reg_lock, flags);
}
static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd)
{
- int result = 0;
-
- spin_lock(&sonic->reg_lock);
+ guard(spinlock)(&sonic->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_START) {
if (!(sonic->enable & what)) {
sonic->enable |= what;
@@ -594,10 +578,9 @@ static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd)
snd_sonicvibes_out1(sonic, SV_IREG_PC_ENABLE, sonic->enable);
}
} else {
- result = -EINVAL;
+ return -EINVAL;
}
- spin_unlock(&sonic->reg_lock);
- return result;
+ return 0;
}
static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
@@ -628,34 +611,34 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
unsigned char udreg;
int vol, oleft, oright, mleft, mright;
- spin_lock(&sonic->reg_lock);
- udreg = snd_sonicvibes_in1(sonic, SV_IREG_UD_BUTTON);
- vol = udreg & 0x3f;
- if (!(udreg & 0x40))
- vol = -vol;
- oleft = mleft = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ANALOG);
- oright = mright = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ANALOG);
- oleft &= 0x1f;
- oright &= 0x1f;
- oleft += vol;
- if (oleft < 0)
- oleft = 0;
- if (oleft > 0x1f)
- oleft = 0x1f;
- oright += vol;
- if (oright < 0)
- oright = 0;
- if (oright > 0x1f)
- oright = 0x1f;
- if (udreg & 0x80) {
- mleft ^= 0x80;
- mright ^= 0x80;
+ scoped_guard(spinlock, &sonic->reg_lock) {
+ udreg = snd_sonicvibes_in1(sonic, SV_IREG_UD_BUTTON);
+ vol = udreg & 0x3f;
+ if (!(udreg & 0x40))
+ vol = -vol;
+ oleft = mleft = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ANALOG);
+ oright = mright = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ANALOG);
+ oleft &= 0x1f;
+ oright &= 0x1f;
+ oleft += vol;
+ if (oleft < 0)
+ oleft = 0;
+ if (oleft > 0x1f)
+ oleft = 0x1f;
+ oright += vol;
+ if (oright < 0)
+ oright = 0;
+ if (oright > 0x1f)
+ oright = 0x1f;
+ if (udreg & 0x80) {
+ mleft ^= 0x80;
+ mright ^= 0x80;
+ }
+ oleft |= mleft & 0x80;
+ oright |= mright & 0x80;
+ snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ANALOG, oleft);
+ snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ANALOG, oright);
}
- oleft |= mleft & 0x80;
- oright |= mright & 0x80;
- snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ANALOG, oleft);
- snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ANALOG, oright);
- spin_unlock(&sonic->reg_lock);
snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_mute->id);
snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_volume->id);
}
@@ -696,11 +679,10 @@ static int snd_sonicvibes_playback_prepare(struct snd_pcm_substream *substream)
fmt |= 2;
snd_sonicvibes_setfmt(sonic, ~3, fmt);
snd_sonicvibes_set_dac_rate(sonic, runtime->rate);
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
snd_sonicvibes_setdmaa(sonic, runtime->dma_addr, size);
snd_sonicvibes_out1(sonic, SV_IREG_DMA_A_UPPER, count >> 8);
snd_sonicvibes_out1(sonic, SV_IREG_DMA_A_LOWER, count);
- spin_unlock_irq(&sonic->reg_lock);
return 0;
}
@@ -721,11 +703,10 @@ static int snd_sonicvibes_capture_prepare(struct snd_pcm_substream *substream)
fmt |= 0x20;
snd_sonicvibes_setfmt(sonic, ~0x30, fmt);
snd_sonicvibes_set_adc_rate(sonic, runtime->rate);
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
snd_sonicvibes_setdmac(sonic, runtime->dma_addr, size);
snd_sonicvibes_out1(sonic, SV_IREG_DMA_C_UPPER, count >> 8);
snd_sonicvibes_out1(sonic, SV_IREG_DMA_C_LOWER, count);
- spin_unlock_irq(&sonic->reg_lock);
return 0;
}
@@ -863,7 +844,7 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device)
pcm->private_data = sonic;
pcm->info_flags = 0;
- strcpy(pcm->name, "S3 SonicVibes");
+ strscpy(pcm->name, "S3 SonicVibes");
sonic->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -894,10 +875,9 @@ static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_
{
struct sonicvibes *sonic = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
ucontrol->value.enumerated.item[0] = ((snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC) & SV_RECSRC_OUT) >> 5) - 1;
ucontrol->value.enumerated.item[1] = ((snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC) & SV_RECSRC_OUT) >> 5) - 1;
- spin_unlock_irq(&sonic->reg_lock);
return 0;
}
@@ -912,7 +892,7 @@ static int snd_sonicvibes_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_
return -EINVAL;
left = (ucontrol->value.enumerated.item[0] + 1) << 5;
right = (ucontrol->value.enumerated.item[1] + 1) << 5;
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
oval1 = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC);
oval2 = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC);
left = (oval1 & ~SV_RECSRC_OUT) | left;
@@ -920,7 +900,6 @@ static int snd_sonicvibes_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_
change = left != oval1 || right != oval2;
snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ADC, left);
snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ADC, right);
- spin_unlock_irq(&sonic->reg_lock);
return change;
}
@@ -949,9 +928,8 @@ static int snd_sonicvibes_get_single(struct snd_kcontrol *kcontrol, struct snd_c
int mask = (kcontrol->private_value >> 16) & 0xff;
int invert = (kcontrol->private_value >> 24) & 0xff;
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, reg)>> shift) & mask;
- spin_unlock_irq(&sonic->reg_lock);
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
return 0;
@@ -971,12 +949,11 @@ static int snd_sonicvibes_put_single(struct snd_kcontrol *kcontrol, struct snd_c
if (invert)
val = mask - val;
val <<= shift;
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
oval = snd_sonicvibes_in1(sonic, reg);
val = (oval & ~(mask << shift)) | val;
change = val != oval;
snd_sonicvibes_out1(sonic, reg, val);
- spin_unlock_irq(&sonic->reg_lock);
return change;
}
@@ -1007,10 +984,9 @@ static int snd_sonicvibes_get_double(struct snd_kcontrol *kcontrol, struct snd_c
int mask = (kcontrol->private_value >> 24) & 0xff;
int invert = (kcontrol->private_value >> 22) & 1;
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, left_reg) >> shift_left) & mask;
ucontrol->value.integer.value[1] = (snd_sonicvibes_in1(sonic, right_reg) >> shift_right) & mask;
- spin_unlock_irq(&sonic->reg_lock);
if (invert) {
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
@@ -1038,7 +1014,7 @@ static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_c
}
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irq(&sonic->reg_lock);
+ guard(spinlock_irq)(&sonic->reg_lock);
oval1 = snd_sonicvibes_in1(sonic, left_reg);
oval2 = snd_sonicvibes_in1(sonic, right_reg);
val1 = (oval1 & ~(mask << shift_left)) | val1;
@@ -1046,7 +1022,6 @@ static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_c
change = val1 != oval1 || val2 != oval2;
snd_sonicvibes_out1(sonic, left_reg, val1);
snd_sonicvibes_out1(sonic, right_reg, val2);
- spin_unlock_irq(&sonic->reg_lock);
return change;
}
@@ -1091,7 +1066,7 @@ static int snd_sonicvibes_mixer(struct sonicvibes *sonic)
if (snd_BUG_ON(!sonic || !sonic->card))
return -EINVAL;
card = sonic->card;
- strcpy(card->mixername, "S3 SonicVibes");
+ strscpy(card->mixername, "S3 SonicVibes");
for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_controls); idx++) {
kctl = snd_ctl_new1(&snd_sonicvibes_controls[idx], sonic);
@@ -1118,7 +1093,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 +1110,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)
@@ -1227,7 +1202,7 @@ static int snd_sonicvibes_create(struct snd_card *card,
sonic->pci = pci;
sonic->irq = -1;
- err = pci_request_regions(pci, "S3 SonicVibes");
+ err = pcim_request_all_regions(pci, "S3 SonicVibes");
if (err < 0)
return err;
@@ -1415,8 +1390,8 @@ static int __snd_sonic_probe(struct pci_dev *pci,
if (err < 0)
return err;
- strcpy(card->driver, "SonicVibes");
- strcpy(card->shortname, "S3 SonicVibes");
+ strscpy(card->driver, "SonicVibes");
+ strscpy(card->shortname, "S3 SonicVibes");
sprintf(card->longname, "%s rev %i at 0x%llx, irq %i",
card->shortname,
sonic->revision,
diff --git a/sound/pci/trident/Makefile b/sound/pci/trident/Makefile
index e8975bc37fcb..476d16abcfc9 100644
--- a/sound/pci/trident/Makefile
+++ b/sound/pci/trident/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-trident-objs := trident.o trident_main.o trident_memory.o
+snd-trident-y := trident.o trident_main.o trident_memory.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_TRIDENT) += snd-trident.o
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index 9922ab40798c..ddb6ccc72e44 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -88,11 +88,11 @@ static int snd_trident_probe(struct pci_dev *pci,
default:
str = "Unknown";
}
- strcpy(card->driver, str);
+ strscpy(card->driver, str);
if (trident->device == TRIDENT_DEVICE_ID_SI7018) {
- strcpy(card->shortname, "SiS ");
+ strscpy(card->shortname, "SiS ");
} else {
- strcpy(card->shortname, "Trident ");
+ strscpy(card->shortname, "Trident ");
}
strcat(card->shortname, str);
sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d",
diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h
index 9768a7fc2349..ed2d4eecc704 100644
--- a/sound/pci/trident/trident.h
+++ b/sound/pci/trident/trident.h
@@ -406,7 +406,6 @@ int snd_trident_create_gameport(struct snd_trident *trident);
int snd_trident_pcm(struct snd_trident *trident, int device);
int snd_trident_foldback_pcm(struct snd_trident *trident, int device);
int snd_trident_spdif_pcm(struct snd_trident *trident, int device);
-int snd_trident_attach_synthesizer(struct snd_trident * trident);
struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type,
int client, int port);
void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice);
@@ -419,9 +418,5 @@ extern const struct dev_pm_ops snd_trident_pm;
struct snd_util_memblk *snd_trident_alloc_pages(struct snd_trident *trident,
struct snd_pcm_substream *substream);
int snd_trident_free_pages(struct snd_trident *trident, struct snd_util_memblk *blk);
-struct snd_util_memblk *snd_trident_synth_alloc(struct snd_trident *trident, unsigned int size);
-int snd_trident_synth_free(struct snd_trident *trident, struct snd_util_memblk *blk);
-int snd_trident_synth_copy_from_user(struct snd_trident *trident, struct snd_util_memblk *blk,
- int offset, const char __user *data, int size);
#endif /* __SOUND_TRIDENT_H */
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index e98eea1e6d81..55515c58b8aa 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -107,10 +107,9 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho
{
unsigned int data = 0, treg;
unsigned short count = 0xffff;
- unsigned long flags;
struct snd_trident *trident = ac97->private_data;
- spin_lock_irqsave(&trident->reg_lock, flags);
+ guard(spinlock_irqsave)(&trident->reg_lock);
if (trident->device == TRIDENT_DEVICE_ID_DX) {
data = (DX_AC97_BUSY_READ | (reg & 0x000000ff));
outl(data, TRID_REG(trident, DX_ACR1_AC97_R));
@@ -147,7 +146,6 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho
data = 0;
}
- spin_unlock_irqrestore(&trident->reg_lock, flags);
return ((unsigned short) (data >> 16));
}
@@ -170,12 +168,11 @@ static void snd_trident_codec_write(struct snd_ac97 *ac97, unsigned short reg,
{
unsigned int address, data;
unsigned short count = 0xffff;
- unsigned long flags;
struct snd_trident *trident = ac97->private_data;
data = ((unsigned long) wdata) << 16;
- spin_lock_irqsave(&trident->reg_lock, flags);
+ guard(spinlock_irqsave)(&trident->reg_lock);
if (trident->device == TRIDENT_DEVICE_ID_DX) {
address = DX_ACR0_AC97_W;
@@ -213,12 +210,9 @@ static void snd_trident_codec_write(struct snd_ac97 *ac97, unsigned short reg,
count = 0; /* return */
}
- if (count == 0) {
- spin_unlock_irqrestore(&trident->reg_lock, flags);
+ if (count == 0)
return;
- }
outl(data, TRID_REG(trident, address));
- spin_unlock_irqrestore(&trident->reg_lock, flags);
}
/*---------------------------------------------------------------------------
@@ -911,7 +905,7 @@ static int snd_trident_playback_prepare(struct snd_pcm_substream *substream)
struct snd_trident_voice *evoice = voice->extra;
struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[substream->number];
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
/* set delta (rate) value */
voice->Delta = snd_trident_convert_rate(runtime->rate);
@@ -972,8 +966,6 @@ static int snd_trident_playback_prepare(struct snd_pcm_substream *substream)
evoice->ESO = (runtime->period_size * 2) - 1;
}
- spin_unlock_irq(&trident->reg_lock);
-
return 0;
}
@@ -1013,7 +1005,7 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream)
struct snd_trident_voice *voice = runtime->private_data;
unsigned int val, ESO_bytes;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
// Initialize the channel and set channel Mode
outb(0, TRID_REG(trident, LEGACY_DMAR15));
@@ -1082,7 +1074,6 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream)
snd_trident_write_voice_regs(trident, voice);
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -1147,7 +1138,7 @@ static int snd_trident_si7018_capture_prepare(struct snd_pcm_substream *substrea
struct snd_trident_voice *voice = runtime->private_data;
struct snd_trident_voice *evoice = voice->extra;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
voice->LBA = runtime->dma_addr;
voice->Delta = snd_trident_convert_adc_rate(runtime->rate);
@@ -1196,7 +1187,6 @@ static int snd_trident_si7018_capture_prepare(struct snd_pcm_substream *substrea
evoice->ESO = (runtime->period_size * 2) - 1;
}
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -1218,7 +1208,7 @@ static int snd_trident_foldback_prepare(struct snd_pcm_substream *substream)
struct snd_trident_voice *voice = runtime->private_data;
struct snd_trident_voice *evoice = voice->extra;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
/* Set channel buffer Address */
if (voice->memblk)
@@ -1273,7 +1263,6 @@ static int snd_trident_foldback_prepare(struct snd_pcm_substream *substream)
evoice->ESO = (runtime->period_size * 2) - 1;
}
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -1307,35 +1296,33 @@ static int snd_trident_spdif_hw_params(struct snd_pcm_substream *substream,
}
/* prepare SPDIF channel */
- spin_lock_irq(&trident->reg_lock);
- old_bits = trident->spdif_pcm_bits;
- if (old_bits & IEC958_AES0_PROFESSIONAL)
- trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS;
- else
- trident->spdif_pcm_bits &= ~(IEC958_AES3_CON_FS << 24);
- if (params_rate(hw_params) >= 48000) {
- trident->spdif_pcm_ctrl = 0x3c; // 48000 Hz
- trident->spdif_pcm_bits |=
- trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?
+ scoped_guard(spinlock_irq, &trident->reg_lock) {
+ old_bits = trident->spdif_pcm_bits;
+ if (old_bits & IEC958_AES0_PROFESSIONAL)
+ trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS;
+ else
+ trident->spdif_pcm_bits &= ~(IEC958_AES3_CON_FS << 24);
+ if (params_rate(hw_params) >= 48000) {
+ trident->spdif_pcm_ctrl = 0x3c; // 48000 Hz
+ trident->spdif_pcm_bits |=
+ trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?
IEC958_AES0_PRO_FS_48000 :
(IEC958_AES3_CON_FS_48000 << 24);
- }
- else if (params_rate(hw_params) >= 44100) {
- trident->spdif_pcm_ctrl = 0x3e; // 44100 Hz
- trident->spdif_pcm_bits |=
- trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?
+ } else if (params_rate(hw_params) >= 44100) {
+ trident->spdif_pcm_ctrl = 0x3e; // 44100 Hz
+ trident->spdif_pcm_bits |=
+ trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?
IEC958_AES0_PRO_FS_44100 :
(IEC958_AES3_CON_FS_44100 << 24);
- }
- else {
- trident->spdif_pcm_ctrl = 0x3d; // 32000 Hz
- trident->spdif_pcm_bits |=
- trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?
+ } else {
+ trident->spdif_pcm_ctrl = 0x3d; // 32000 Hz
+ trident->spdif_pcm_bits |=
+ trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?
IEC958_AES0_PRO_FS_32000 :
(IEC958_AES3_CON_FS_32000 << 24);
+ }
+ change = old_bits != trident->spdif_pcm_bits;
}
- change = old_bits != trident->spdif_pcm_bits;
- spin_unlock_irq(&trident->reg_lock);
if (change)
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id);
@@ -1364,7 +1351,7 @@ static int snd_trident_spdif_prepare(struct snd_pcm_substream *substream)
unsigned int RESO, LBAO;
unsigned int temp;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
@@ -1476,8 +1463,6 @@ static int snd_trident_spdif_prepare(struct snd_pcm_substream *substream)
outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
- spin_unlock_irq(&trident->reg_lock);
-
return 0;
}
@@ -1518,7 +1503,7 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream,
return -EINVAL;
}
what = whati = capture_flag = spdif_flag = 0;
- spin_lock(&trident->reg_lock);
+ guard(spinlock)(&trident->reg_lock);
val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff;
snd_pcm_group_for_each_entry(s, substream) {
if ((struct snd_trident *) snd_pcm_substream_chip(s) == trident) {
@@ -1577,7 +1562,6 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream,
if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018)
outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
}
- spin_unlock(&trident->reg_lock);
return 0;
}
@@ -1602,7 +1586,7 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream *
if (!voice->running)
return 0;
- spin_lock(&trident->reg_lock);
+ guard(spinlock)(&trident->reg_lock);
outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
@@ -1612,8 +1596,6 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream *
cso = (unsigned int) inl(TRID_REG(trident, CH_NX_DELTA_CSO)) & 0x00ffffff;
}
- spin_unlock(&trident->reg_lock);
-
if (cso >= runtime->buffer_size)
cso = 0;
@@ -1866,9 +1848,9 @@ static int snd_trident_spdif_open(struct snd_pcm_substream *substream)
return -EAGAIN;
voice->spdif = 1;
voice->substream = substream;
- spin_lock_irq(&trident->reg_lock);
- trident->spdif_pcm_bits = trident->spdif_bits;
- spin_unlock_irq(&trident->reg_lock);
+ scoped_guard(spinlock_irq, &trident->reg_lock) {
+ trident->spdif_pcm_bits = trident->spdif_bits;
+ }
runtime->private_data = voice;
runtime->private_free = snd_trident_pcm_free_substream;
@@ -1901,22 +1883,22 @@ static int snd_trident_spdif_close(struct snd_pcm_substream *substream)
struct snd_trident *trident = snd_pcm_substream_chip(substream);
unsigned int temp;
- spin_lock_irq(&trident->reg_lock);
- // restore default SPDIF setting
- if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
- outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
- outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
- } else {
- outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
- temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL));
- if (trident->spdif_ctrl) {
- temp |= SPDIF_EN;
+ scoped_guard(spinlock_irq, &trident->reg_lock) {
+ // restore default SPDIF setting
+ if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
+ outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
+ outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));
} else {
- temp &= ~SPDIF_EN;
+ outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
+ temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL));
+ if (trident->spdif_ctrl) {
+ temp |= SPDIF_EN;
+ } else {
+ temp &= ~SPDIF_EN;
+ }
+ outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
- outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
- spin_unlock_irq(&trident->reg_lock);
trident->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO, &trident->spdif_pcm_ctl->id);
@@ -2013,9 +1995,8 @@ static int snd_trident_foldback_close(struct snd_pcm_substream *substream)
voice = runtime->private_data;
/* stop capture channel */
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
outb(0x00, TRID_REG(trident, T4D_RCI + voice->foldback_chan));
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -2137,7 +2118,7 @@ int snd_trident_pcm(struct snd_trident *trident, int device)
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
- strcpy(pcm->name, "Trident 4DWave");
+ strscpy(pcm->name, "Trident 4DWave");
trident->pcm = pcm;
if (trident->tlb.entries) {
@@ -2189,16 +2170,16 @@ int snd_trident_foldback_pcm(struct snd_trident *trident, int device)
else
snd_pcm_set_ops(foldback, SNDRV_PCM_STREAM_CAPTURE, &snd_trident_foldback_ops);
foldback->info_flags = 0;
- strcpy(foldback->name, "Trident 4DWave");
+ strscpy(foldback->name, "Trident 4DWave");
substream = foldback->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
- strcpy(substream->name, "Front Mixer");
+ strscpy(substream->name, "Front Mixer");
substream = substream->next;
- strcpy(substream->name, "Reverb Mixer");
+ strscpy(substream->name, "Reverb Mixer");
substream = substream->next;
- strcpy(substream->name, "Chorus Mixer");
+ strscpy(substream->name, "Chorus Mixer");
if (num_chan == 4) {
substream = substream->next;
- strcpy(substream->name, "Second AC'97 ADC");
+ strscpy(substream->name, "Second AC'97 ADC");
}
trident->foldback = foldback;
@@ -2241,7 +2222,7 @@ int snd_trident_spdif_pcm(struct snd_trident *trident, int device)
snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_7018_ops);
}
spdif->info_flags = 0;
- strcpy(spdif->name, "Trident 4DWave IEC958");
+ strscpy(spdif->name, "Trident 4DWave IEC958");
trident->spdif = spdif;
snd_pcm_set_managed_buffer_all(spdif, SNDRV_DMA_TYPE_DEV,
@@ -2269,10 +2250,9 @@ static int snd_trident_spdif_control_get(struct snd_kcontrol *kcontrol,
struct snd_trident *trident = snd_kcontrol_chip(kcontrol);
unsigned char val;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
val = trident->spdif_ctrl;
ucontrol->value.integer.value[0] = val == kcontrol->private_value;
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -2284,7 +2264,7 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol,
int change;
val = ucontrol->value.integer.value[0] ? (unsigned char) kcontrol->private_value : 0x00;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
/* S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled */
change = trident->spdif_ctrl != val;
trident->spdif_ctrl = val;
@@ -2303,7 +2283,6 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol,
outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
}
}
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2336,12 +2315,11 @@ static int snd_trident_spdif_default_get(struct snd_kcontrol *kcontrol,
{
struct snd_trident *trident = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
ucontrol->value.iec958.status[0] = (trident->spdif_bits >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (trident->spdif_bits >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (trident->spdif_bits >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (trident->spdif_bits >> 24) & 0xff;
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -2356,7 +2334,7 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol,
(ucontrol->value.iec958.status[1] << 8) |
(ucontrol->value.iec958.status[2] << 16) |
(ucontrol->value.iec958.status[3] << 24);
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
change = trident->spdif_bits != val;
trident->spdif_bits = val;
if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
@@ -2366,7 +2344,6 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol,
if (trident->spdif == NULL)
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
}
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2431,12 +2408,11 @@ static int snd_trident_spdif_stream_get(struct snd_kcontrol *kcontrol,
{
struct snd_trident *trident = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
ucontrol->value.iec958.status[0] = (trident->spdif_pcm_bits >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (trident->spdif_pcm_bits >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (trident->spdif_pcm_bits >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (trident->spdif_pcm_bits >> 24) & 0xff;
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -2451,7 +2427,7 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol,
(ucontrol->value.iec958.status[1] << 8) |
(ucontrol->value.iec958.status[2] << 16) |
(ucontrol->value.iec958.status[3] << 24);
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
change = trident->spdif_pcm_bits != val;
trident->spdif_pcm_bits = val;
if (trident->spdif != NULL) {
@@ -2461,7 +2437,6 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol,
outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));
}
}
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2489,10 +2464,9 @@ static int snd_trident_ac97_control_get(struct snd_kcontrol *kcontrol,
struct snd_trident *trident = snd_kcontrol_chip(kcontrol);
unsigned char val;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
val = trident->ac97_ctrl = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
ucontrol->value.integer.value[0] = (val & (1 << kcontrol->private_value)) ? 1 : 0;
- spin_unlock_irq(&trident->reg_lock);
return 0;
}
@@ -2503,7 +2477,7 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol,
unsigned char val;
int change = 0;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
val = trident->ac97_ctrl = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
val &= ~(1 << kcontrol->private_value);
if (ucontrol->value.integer.value[0])
@@ -2511,7 +2485,6 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol,
change = val != trident->ac97_ctrl;
trident->ac97_ctrl = val;
outl(trident->ac97_ctrl = val, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2562,14 +2535,13 @@ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
unsigned int val;
int change = 0;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
val = trident->musicvol_wavevol;
val &= ~(0xffff << kcontrol->private_value);
val |= ((255 - (ucontrol->value.integer.value[0] & 0xff)) |
((255 - (ucontrol->value.integer.value[1] & 0xff)) << 8)) << kcontrol->private_value;
change = val != trident->musicvol_wavevol;
outl(trident->musicvol_wavevol = val, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL));
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2642,12 +2614,11 @@ static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol,
} else {
val = (255 - (ucontrol->value.integer.value[0] & 255)) << 2;
}
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
change = val != mix->vol;
mix->vol = val;
if (mix->voice != NULL)
snd_trident_write_vol_reg(trident, mix->voice, val);
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2706,12 +2677,11 @@ static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol,
val = ucontrol->value.integer.value[0] & 0x3f;
else
val = (0x3f - (ucontrol->value.integer.value[0] & 0x3f)) | 0x40;
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
change = val != mix->pan;
mix->pan = val;
if (mix->voice != NULL)
snd_trident_write_pan_reg(trident, mix->voice, val);
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2761,12 +2731,11 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol,
int change = 0;
val = 0x7f - (ucontrol->value.integer.value[0] & 0x7f);
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
change = val != mix->rvol;
mix->rvol = val;
if (mix->voice != NULL)
snd_trident_write_rvol_reg(trident, mix->voice, val);
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -2819,12 +2788,11 @@ static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol,
int change = 0;
val = 0x7f - (ucontrol->value.integer.value[0] & 0x7f);
- spin_lock_irq(&trident->reg_lock);
+ guard(spinlock_irq)(&trident->reg_lock);
change = val != mix->cvol;
mix->cvol = val;
if (mix->voice != NULL)
snd_trident_write_cvol_reg(trident, mix->voice, val);
- spin_unlock_irq(&trident->reg_lock);
return change;
}
@@ -3278,9 +3246,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);
@@ -3533,7 +3501,7 @@ int snd_trident_create(struct snd_card *card,
trident->midi_port = TRID_REG(trident, T4D_MPU401_BASE);
pci_set_master(pci);
- err = pci_request_regions(pci, "Trident Audio");
+ err = pcim_request_all_regions(pci, "Trident Audio");
if (err < 0)
return err;
trident->port = pci_resource_start(pci, 0);
@@ -3659,79 +3627,76 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id)
return IRQ_NONE;
if (audio_int & ADDRESS_IRQ) {
// get interrupt status for all channels
- spin_lock(&trident->reg_lock);
- stimer = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff;
- chn_int = inl(TRID_REG(trident, T4D_AINT_A));
- if (chn_int == 0)
- goto __skip1;
- outl(chn_int, TRID_REG(trident, T4D_AINT_A)); /* ack */
- __skip1:
- chn_int = inl(TRID_REG(trident, T4D_AINT_B));
- if (chn_int == 0)
- goto __skip2;
- for (channel = 63; channel >= 32; channel--) {
- mask = 1 << (channel&0x1f);
- if ((chn_int & mask) == 0)
- continue;
- voice = &trident->synth.voices[channel];
- if (!voice->pcm || voice->substream == NULL) {
- outl(mask, TRID_REG(trident, T4D_STOP_B));
- continue;
- }
- delta = (int)stimer - (int)voice->stimer;
- if (delta < 0)
- delta = -delta;
- if ((unsigned int)delta < voice->spurious_threshold) {
- /* do some statistics here */
- trident->spurious_irq_count++;
- if (trident->spurious_irq_max_delta < (unsigned int)delta)
- trident->spurious_irq_max_delta = delta;
- continue;
- }
- voice->stimer = stimer;
- if (voice->isync) {
- if (!voice->isync3) {
- tmp = inw(TRID_REG(trident, T4D_SBBL_SBCL));
- if (trident->bDMAStart & 0x40)
- tmp >>= 1;
- if (tmp > 0)
- tmp = voice->isync_max - tmp;
- } else {
- tmp = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff;
+ scoped_guard(spinlock, &trident->reg_lock) {
+ stimer = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff;
+ chn_int = inl(TRID_REG(trident, T4D_AINT_A));
+ if (chn_int)
+ outl(chn_int, TRID_REG(trident, T4D_AINT_A)); /* ack */
+ chn_int = inl(TRID_REG(trident, T4D_AINT_B));
+ if (chn_int == 0)
+ break;
+ for (channel = 63; channel >= 32; channel--) {
+ mask = 1 << (channel&0x1f);
+ if ((chn_int & mask) == 0)
+ continue;
+ voice = &trident->synth.voices[channel];
+ if (!voice->pcm || voice->substream == NULL) {
+ outl(mask, TRID_REG(trident, T4D_STOP_B));
+ continue;
+ }
+ delta = (int)stimer - (int)voice->stimer;
+ if (delta < 0)
+ delta = -delta;
+ if ((unsigned int)delta < voice->spurious_threshold) {
+ /* do some statistics here */
+ trident->spurious_irq_count++;
+ if (trident->spurious_irq_max_delta < (unsigned int)delta)
+ trident->spurious_irq_max_delta = delta;
+ continue;
}
- if (tmp < voice->isync_mark) {
- if (tmp > 0x10)
- tmp = voice->isync_ESO - 7;
- else
- tmp = voice->isync_ESO + 2;
- /* update ESO for IRQ voice to preserve sync */
+ voice->stimer = stimer;
+ if (voice->isync) {
+ if (!voice->isync3) {
+ tmp = inw(TRID_REG(trident, T4D_SBBL_SBCL));
+ if (trident->bDMAStart & 0x40)
+ tmp >>= 1;
+ if (tmp > 0)
+ tmp = voice->isync_max - tmp;
+ } else {
+ tmp = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff;
+ }
+ if (tmp < voice->isync_mark) {
+ if (tmp > 0x10)
+ tmp = voice->isync_ESO - 7;
+ else
+ tmp = voice->isync_ESO + 2;
+ /* update ESO for IRQ voice to preserve sync */
+ snd_trident_stop_voice(trident, voice->number);
+ snd_trident_write_eso_reg(trident, voice, tmp);
+ snd_trident_start_voice(trident, voice->number);
+ }
+ } else if (voice->isync2) {
+ voice->isync2 = 0;
+ /* write original ESO and update CSO for IRQ voice to preserve sync */
snd_trident_stop_voice(trident, voice->number);
- snd_trident_write_eso_reg(trident, voice, tmp);
+ snd_trident_write_cso_reg(trident, voice, voice->isync_mark);
+ snd_trident_write_eso_reg(trident, voice, voice->ESO);
snd_trident_start_voice(trident, voice->number);
}
- } else if (voice->isync2) {
- voice->isync2 = 0;
- /* write original ESO and update CSO for IRQ voice to preserve sync */
- snd_trident_stop_voice(trident, voice->number);
- snd_trident_write_cso_reg(trident, voice, voice->isync_mark);
- snd_trident_write_eso_reg(trident, voice, voice->ESO);
- snd_trident_start_voice(trident, voice->number);
- }
#if 0
- if (voice->extra) {
- /* update CSO for extra voice to preserve sync */
- snd_trident_stop_voice(trident, voice->extra->number);
- snd_trident_write_cso_reg(trident, voice->extra, 0);
- snd_trident_start_voice(trident, voice->extra->number);
- }
+ if (voice->extra) {
+ /* update CSO for extra voice to preserve sync */
+ snd_trident_stop_voice(trident, voice->extra->number);
+ snd_trident_write_cso_reg(trident, voice->extra, 0);
+ snd_trident_start_voice(trident, voice->extra->number);
+ }
#endif
- spin_unlock(&trident->reg_lock);
- snd_pcm_period_elapsed(voice->substream);
- spin_lock(&trident->reg_lock);
+ spin_unlock(&trident->reg_lock);
+ snd_pcm_period_elapsed(voice->substream);
+ spin_lock(&trident->reg_lock);
+ }
+ outl(chn_int, TRID_REG(trident, T4D_AINT_B)); /* ack */
}
- outl(chn_int, TRID_REG(trident, T4D_AINT_B)); /* ack */
- __skip2:
- spin_unlock(&trident->reg_lock);
}
if (audio_int & MPU401_IRQ) {
if (trident->rmidi) {
@@ -3747,16 +3712,13 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id)
struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port)
{
struct snd_trident_voice *pvoice;
- unsigned long flags;
int idx;
- spin_lock_irqsave(&trident->voice_alloc, flags);
+ guard(spinlock_irqsave)(&trident->voice_alloc);
if (type == SNDRV_TRIDENT_VOICE_TYPE_PCM) {
idx = snd_trident_allocate_pcm_channel(trident);
- if(idx < 0) {
- spin_unlock_irqrestore(&trident->voice_alloc, flags);
+ if (idx < 0)
return NULL;
- }
pvoice = &trident->synth.voices[idx];
pvoice->use = 1;
pvoice->pcm = 1;
@@ -3764,27 +3726,22 @@ struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident,
pvoice->spdif = 0;
pvoice->memblk = NULL;
pvoice->substream = NULL;
- spin_unlock_irqrestore(&trident->voice_alloc, flags);
return pvoice;
}
if (type == SNDRV_TRIDENT_VOICE_TYPE_SYNTH) {
idx = snd_trident_allocate_synth_channel(trident);
- if(idx < 0) {
- spin_unlock_irqrestore(&trident->voice_alloc, flags);
+ if (idx < 0)
return NULL;
- }
pvoice = &trident->synth.voices[idx];
pvoice->use = 1;
pvoice->synth = 1;
pvoice->client = client;
pvoice->port = port;
pvoice->memblk = NULL;
- spin_unlock_irqrestore(&trident->voice_alloc, flags);
return pvoice;
}
if (type == SNDRV_TRIDENT_VOICE_TYPE_MIDI) {
}
- spin_unlock_irqrestore(&trident->voice_alloc, flags);
return NULL;
}
@@ -3792,26 +3749,25 @@ EXPORT_SYMBOL(snd_trident_alloc_voice);
void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice)
{
- unsigned long flags;
void (*private_free)(struct snd_trident_voice *);
if (voice == NULL || !voice->use)
return;
snd_trident_clear_voices(trident, voice->number, voice->number);
- spin_lock_irqsave(&trident->voice_alloc, flags);
- private_free = voice->private_free;
- voice->private_free = NULL;
- voice->private_data = NULL;
- if (voice->pcm)
- snd_trident_free_pcm_channel(trident, voice->number);
- if (voice->synth)
- snd_trident_free_synth_channel(trident, voice->number);
- voice->use = voice->pcm = voice->synth = voice->midi = 0;
- voice->capture = voice->spdif = 0;
- voice->sample_ops = NULL;
- voice->substream = NULL;
- voice->extra = NULL;
- spin_unlock_irqrestore(&trident->voice_alloc, flags);
+ scoped_guard(spinlock_irqsave, &trident->voice_alloc) {
+ private_free = voice->private_free;
+ voice->private_free = NULL;
+ voice->private_data = NULL;
+ if (voice->pcm)
+ snd_trident_free_pcm_channel(trident, voice->number);
+ if (voice->synth)
+ snd_trident_free_synth_channel(trident, voice->number);
+ voice->use = voice->pcm = voice->synth = voice->midi = 0;
+ voice->capture = voice->spdif = 0;
+ voice->sample_ops = NULL;
+ voice->substream = NULL;
+ voice->extra = NULL;
+ }
if (private_free)
private_free(voice);
}
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index 05de2b9f4ed7..81f6348191dc 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -137,14 +137,14 @@ __found_pages:
/*
* check if the given pointer is valid for pages
*/
-static int is_valid_page(unsigned long ptr)
+static int is_valid_page(struct snd_trident *trident, unsigned long ptr)
{
if (ptr & ~0x3fffffffUL) {
- snd_printk(KERN_ERR "max memory size is 1GB!!\n");
+ dev_err(trident->card->dev, "max memory size is 1GB!!\n");
return 0;
}
if (ptr & (SNDRV_TRIDENT_PAGE_SIZE-1)) {
- snd_printk(KERN_ERR "page is not aligned\n");
+ dev_err(trident->card->dev, "page is not aligned\n");
return 0;
}
return 1;
@@ -172,26 +172,22 @@ snd_trident_alloc_sg_pages(struct snd_trident *trident,
- mutex_lock(&hdr->block_mutex);
+ guard(mutex)(&hdr->block_mutex);
blk = search_empty(hdr, runtime->dma_bytes);
- if (blk == NULL) {
- mutex_unlock(&hdr->block_mutex);
+ if (blk == NULL)
return NULL;
- }
/* set TLB entries */
idx = 0;
for (page = firstpg(blk); page <= lastpg(blk); page++, idx++) {
unsigned long ofs = idx << PAGE_SHIFT;
dma_addr_t addr = snd_pcm_sgbuf_get_addr(substream, ofs);
- if (! is_valid_page(addr)) {
+ if (!is_valid_page(trident, addr)) {
__snd_util_mem_free(hdr, blk);
- mutex_unlock(&hdr->block_mutex);
return NULL;
}
set_tlb_bus(trident, page, addr);
}
- mutex_unlock(&hdr->block_mutex);
return blk;
}
@@ -216,25 +212,21 @@ snd_trident_alloc_cont_pages(struct snd_trident *trident,
if (snd_BUG_ON(!hdr))
return NULL;
- mutex_lock(&hdr->block_mutex);
+ guard(mutex)(&hdr->block_mutex);
blk = search_empty(hdr, runtime->dma_bytes);
- if (blk == NULL) {
- mutex_unlock(&hdr->block_mutex);
+ if (blk == NULL)
return NULL;
- }
/* set TLB entries */
addr = runtime->dma_addr;
for (page = firstpg(blk); page <= lastpg(blk); page++,
addr += SNDRV_TRIDENT_PAGE_SIZE) {
- if (! is_valid_page(addr)) {
+ if (!is_valid_page(trident, addr)) {
__snd_util_mem_free(hdr, blk);
- mutex_unlock(&hdr->block_mutex);
return NULL;
}
set_tlb_bus(trident, page, addr);
}
- mutex_unlock(&hdr->block_mutex);
return blk;
}
@@ -267,12 +259,11 @@ int snd_trident_free_pages(struct snd_trident *trident,
return -EINVAL;
hdr = trident->tlb.memhdr;
- mutex_lock(&hdr->block_mutex);
+ guard(mutex)(&hdr->block_mutex);
/* reset TLB entries */
for (page = firstpg(blk); page <= lastpg(blk); page++)
set_silent_tlb(trident, page);
/* free memory block */
__snd_util_mem_free(hdr, blk);
- mutex_unlock(&hdr->block_mutex);
return 0;
}
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 361b83fd721e..2b0f9e38863e 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -347,13 +347,11 @@ struct via82xx {
unsigned char old_legacy;
unsigned char old_legacy_cfg;
-#ifdef CONFIG_PM_SLEEP
unsigned char legacy_saved;
unsigned char legacy_cfg_saved;
unsigned char spdif_ctrl_saved;
unsigned char capture_src_saved[2];
unsigned int mpu_port_saved;
-#endif
unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */
unsigned char playback_volume_c[2]; /* for VIA8233/C/8235; default = 0 */
@@ -630,7 +628,7 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id)
}
/* check status for each stream */
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
for (i = 0; i < chip->num_devs; i++) {
struct viadev *viadev = &chip->devs[i];
unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS));
@@ -654,7 +652,6 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id)
}
outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */
}
- spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -669,7 +666,7 @@ static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id)
int irqreturn = 0;
/* check status for each stream */
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
status = inl(VIAREG(chip, SGD_SHADOW));
for (i = 0; i < chip->num_devs; i++) {
@@ -708,7 +705,6 @@ static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id)
outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */
irqreturn = 1;
}
- spin_unlock(&chip->reg_lock);
return IRQ_RETVAL(irqreturn);
}
@@ -835,7 +831,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
return 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff;
/* The via686a does not have the current index register,
* so we need to calculate the index from CURR_PTR.
@@ -847,7 +843,6 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries;
res = calc_linear_pos(chip, viadev, idx, count);
viadev->lastpos = res; /* remember the last position */
- spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, res);
}
@@ -865,7 +860,7 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst
if (snd_BUG_ON(!viadev->tbl_entries))
return 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT));
status = viadev->in_interrupt;
if (!status)
@@ -906,7 +901,6 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst
}
unlock:
viadev->lastpos = res;
- spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, res);
}
@@ -999,7 +993,7 @@ static int via_lock_rate(struct via_rate_lock *rec, int rate)
{
int changed = 0;
- spin_lock_irq(&rec->lock);
+ guard(spinlock_irq)(&rec->lock);
if (rec->rate != rate) {
if (rec->rate && rec->used > 1) /* already set */
changed = -EINVAL;
@@ -1008,7 +1002,6 @@ static int via_lock_rate(struct via_rate_lock *rec, int rate)
changed = 1;
}
}
- spin_unlock_irq(&rec->lock);
return changed;
}
@@ -1169,33 +1162,33 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
/* set the hw rate condition */
ratep = &chip->rates[viadev->direction];
- spin_lock_irq(&ratep->lock);
- ratep->used++;
- if (chip->spdif_on && viadev->reg_offset == 0x30) {
- /* DXS#3 and spdif is on */
- runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF];
- snd_pcm_limit_hw_rates(runtime);
- } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) {
- /* fixed DXS playback rate */
- runtime->hw.rates = SNDRV_PCM_RATE_48000;
- runtime->hw.rate_min = runtime->hw.rate_max = 48000;
- } else if (chip->dxs_src && viadev->reg_offset < 0x40) {
- /* use full SRC capabilities of DXS */
- runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS |
- SNDRV_PCM_RATE_8000_48000);
- runtime->hw.rate_min = 8000;
- runtime->hw.rate_max = 48000;
- use_src = true;
- } else if (! ratep->rate) {
- int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
- runtime->hw.rates = chip->ac97->rates[idx];
- snd_pcm_limit_hw_rates(runtime);
- } else {
- /* a fixed rate */
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
- runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate;
+ scoped_guard(spinlock_irq, &ratep->lock) {
+ ratep->used++;
+ if (chip->spdif_on && viadev->reg_offset == 0x30) {
+ /* DXS#3 and spdif is on */
+ runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF];
+ snd_pcm_limit_hw_rates(runtime);
+ } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) {
+ /* fixed DXS playback rate */
+ runtime->hw.rates = SNDRV_PCM_RATE_48000;
+ runtime->hw.rate_min = runtime->hw.rate_max = 48000;
+ } else if (chip->dxs_src && viadev->reg_offset < 0x40) {
+ /* use full SRC capabilities of DXS */
+ runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS |
+ SNDRV_PCM_RATE_8000_48000);
+ runtime->hw.rate_min = 8000;
+ runtime->hw.rate_max = 48000;
+ use_src = true;
+ } else if (!ratep->rate) {
+ int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
+ runtime->hw.rates = chip->ac97->rates[idx];
+ snd_pcm_limit_hw_rates(runtime);
+ } else {
+ /* a fixed rate */
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+ runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate;
+ }
}
- spin_unlock_irq(&ratep->lock);
/* we may remove following constaint when we modify table entries
in interrupt */
@@ -1313,11 +1306,11 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream)
/* release the rate lock */
ratep = &chip->rates[viadev->direction];
- spin_lock_irq(&ratep->lock);
- ratep->used--;
- if (! ratep->used)
- ratep->rate = 0;
- spin_unlock_irq(&ratep->lock);
+ scoped_guard(spinlock_irq, &ratep->lock) {
+ ratep->used--;
+ if (!ratep->used)
+ ratep->rate = 0;
+ }
if (! ratep->rate) {
if (! viadev->direction) {
snd_ac97_update_power(chip->ac97,
@@ -1438,7 +1431,7 @@ static int snd_via8233_pcm_new(struct via82xx *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcms[0] = pcm;
/* set up playbacks */
for (i = 0; i < 4; i++)
@@ -1463,7 +1456,7 @@ static int snd_via8233_pcm_new(struct via82xx *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_multi_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcms[1] = pcm;
/* set up playback */
init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 4, 0);
@@ -1506,7 +1499,7 @@ static int snd_via8233a_pcm_new(struct via82xx *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_multi_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcms[0] = pcm;
/* set up playback */
init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 4, 0);
@@ -1534,7 +1527,7 @@ static int snd_via8233a_pcm_new(struct via82xx *chip)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
pcm->private_data = chip;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcms[1] = pcm;
/* set up playback */
init_viadev(chip, chip->playback_devno, 0x30, 3, 0);
@@ -1564,7 +1557,7 @@ static int snd_via686_pcm_new(struct via82xx *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops);
pcm->private_data = chip;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcms[0] = pcm;
init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0, 0);
init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 0, 1);
@@ -1608,14 +1601,13 @@ static int snd_via8233_capture_source_put(struct snd_kcontrol *kcontrol,
unsigned long port = chip->port + (kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL);
u8 val, oval;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oval = inb(port);
val = oval & ~VIA_REG_CAPTURE_CHANNEL_MIC;
if (ucontrol->value.enumerated.item[0])
val |= VIA_REG_CAPTURE_CHANNEL_MIC;
if (val != oval)
outb(val, port);
- spin_unlock_irq(&chip->reg_lock);
return val != oval;
}
@@ -1984,11 +1976,7 @@ static int snd_via8233_init_misc(struct via82xx *chip)
/* when no h/w PCM volume control is found, use DXS volume control
* as the PCM vol control
*/
- struct snd_ctl_elem_id sid;
- memset(&sid, 0, sizeof(sid));
- strcpy(sid.name, "PCM Playback Volume");
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- if (! snd_ctl_find_id(chip->card, &sid)) {
+ if (!snd_ctl_find_id_mixer(chip->card, "PCM Playback Volume")) {
dev_info(chip->card->dev,
"Using DXS as PCM Playback\n");
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip));
@@ -2035,9 +2023,7 @@ static int snd_via686_init_misc(struct via82xx *chip)
if (mpu_port >= 0x200) { /* force MIDI */
mpu_port &= 0xfffc;
pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);
-#ifdef CONFIG_PM_SLEEP
chip->mpu_port_saved = mpu_port;
-#endif
} else {
mpu_port = pci_resource_start(chip->pci, 2);
}
@@ -2089,10 +2075,8 @@ static int snd_via686_init_misc(struct via82xx *chip)
snd_via686_create_gameport(chip, &legacy);
-#ifdef CONFIG_PM_SLEEP
chip->legacy_saved = legacy;
chip->legacy_cfg_saved = legacy_cfg;
-#endif
return 0;
}
@@ -2238,7 +2222,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -2291,11 +2274,7 @@ static int snd_via82xx_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
-#define SND_VIA82XX_PM_OPS &snd_via82xx_pm
-#else
-#define SND_VIA82XX_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
static void snd_via82xx_free(struct snd_card *card)
{
@@ -2341,7 +2320,7 @@ static int snd_via82xx_create(struct snd_card *card,
pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE,
chip->old_legacy & ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM));
- err = pci_request_regions(pci, card->driver);
+ err = pcim_request_all_regions(pci, card->driver);
if (err < 0)
return err;
chip->port = pci_resource_start(pci, 0);
@@ -2476,7 +2455,7 @@ static int __snd_via82xx_probe(struct pci_dev *pci,
card_type = pci_id->driver_data;
switch (card_type) {
case TYPE_CARD_VIA686:
- strcpy(card->driver, "VIA686A");
+ strscpy(card->driver, "VIA686A");
sprintf(card->shortname, "VIA 82C686A/B rev%x", pci->revision);
chip_type = TYPE_VIA686;
break;
@@ -2486,7 +2465,7 @@ static int __snd_via82xx_probe(struct pci_dev *pci,
for (i = 0; i < ARRAY_SIZE(via823x_cards); i++) {
if (pci->revision == via823x_cards[i].revision) {
chip_type = via823x_cards[i].type;
- strcpy(card->shortname, via823x_cards[i].name);
+ strscpy(card->shortname, via823x_cards[i].name);
break;
}
}
@@ -2502,11 +2481,11 @@ static int __snd_via82xx_probe(struct pci_dev *pci,
chip_type = TYPE_VIA8233;
}
if (chip_type == TYPE_VIA8233A)
- strcpy(card->driver, "VIA8233A");
+ strscpy(card->driver, "VIA8233A");
else if (pci->revision >= VIA_REV_8237)
- strcpy(card->driver, "VIA8237"); /* no slog assignment */
+ strscpy(card->driver, "VIA8237"); /* no slog assignment */
else
- strcpy(card->driver, "VIA8233");
+ strscpy(card->driver, "VIA8233");
break;
default:
dev_err(card->dev, "invalid card type %d\n", card_type);
@@ -2580,7 +2559,7 @@ static struct pci_driver via82xx_driver = {
.id_table = snd_via82xx_ids,
.probe = snd_via82xx_probe,
.driver = {
- .pm = SND_VIA82XX_PM_OPS,
+ .pm = &snd_via82xx_pm,
},
};
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index ca7f024bf8ec..6ce2cd88cda6 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -483,7 +483,7 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id)
// _skip_sgd:
/* check status for each stream */
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
for (i = 0; i < chip->num_devs; i++) {
struct viadev *viadev = &chip->devs[i];
unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS));
@@ -497,7 +497,6 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id)
}
outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */
}
- spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -616,7 +615,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
return 0;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff;
/* The via686a does not have the current index register,
* so we need to calculate the index from CURR_PTR.
@@ -628,7 +627,6 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) %
viadev->tbl_entries;
res = calc_linear_pos(chip, viadev, idx, count);
- spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, res);
}
@@ -842,7 +840,7 @@ static int snd_via686_pcm_new(struct via82xx_modem *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops);
pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
pcm->private_data = chip;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcms[0] = pcm;
init_viadev(chip, 0, VIA_REG_MO_STATUS, 0);
init_viadev(chip, 1, VIA_REG_MI_STATUS, 1);
@@ -1008,7 +1006,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
@@ -1042,11 +1039,7 @@ static int snd_via82xx_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
-#define SND_VIA82XX_PM_OPS &snd_via82xx_pm
-#else
-#define SND_VIA82XX_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume);
static void snd_via82xx_free(struct snd_card *card)
{
@@ -1076,7 +1069,7 @@ static int snd_via82xx_create(struct snd_card *card,
chip->pci = pci;
chip->irq = -1;
- err = pci_request_regions(pci, card->driver);
+ err = pcim_request_all_regions(pci, card->driver);
if (err < 0)
return err;
chip->port = pci_resource_start(pci, 0);
@@ -1121,7 +1114,7 @@ static int __snd_via82xx_probe(struct pci_dev *pci,
card_type = pci_id->driver_data;
switch (card_type) {
case TYPE_CARD_VIA82XX_MODEM:
- strcpy(card->driver, "VIA82XX-MODEM");
+ strscpy(card->driver, "VIA82XX-MODEM");
sprintf(card->shortname, "VIA 82XX modem");
break;
default:
@@ -1168,7 +1161,7 @@ static struct pci_driver via82xx_modem_driver = {
.id_table = snd_via82xx_modem_ids,
.probe = snd_via82xx_probe,
.driver = {
- .pm = SND_VIA82XX_PM_OPS,
+ .pm = &snd_via82xx_pm,
},
};
diff --git a/sound/pci/vx222/Makefile b/sound/pci/vx222/Makefile
index dda900e45385..6889137eb438 100644
--- a/sound/pci/vx222/Makefile
+++ b/sound/pci/vx222/Makefile
@@ -4,6 +4,6 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-vx222-objs := vx222.o vx222_ops.o
+snd-vx222-y := vx222.o vx222_ops.o
obj-$(CONFIG_SND_VX222) += snd-vx222.o
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 468a6a20dc1e..693a4e471cf7 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -123,7 +123,7 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci,
vx = to_vx222(chip);
vx->pci = pci;
- err = pci_request_regions(pci, CARD_NAME);
+ err = pcim_request_all_regions(pci, KBUILD_MODNAME);
if (err < 0)
return err;
for (i = 0; i < 2; i++)
@@ -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/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 3e7e928b24f8..b6459dbdb1b0 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -868,10 +868,10 @@ static int vx_input_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
{
struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
struct snd_vx222 *chip = to_vx222(_chip);
- mutex_lock(&_chip->mixer_mutex);
+
+ guard(mutex)(&_chip->mixer_mutex);
ucontrol->value.integer.value[0] = chip->input_level[0];
ucontrol->value.integer.value[1] = chip->input_level[1];
- mutex_unlock(&_chip->mixer_mutex);
return 0;
}
@@ -885,16 +885,14 @@ static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
if (ucontrol->value.integer.value[1] < 0 ||
ucontrol->value.integer.value[1] > MIC_LEVEL_MAX)
return -EINVAL;
- mutex_lock(&_chip->mixer_mutex);
+ guard(mutex)(&_chip->mixer_mutex);
if (chip->input_level[0] != ucontrol->value.integer.value[0] ||
chip->input_level[1] != ucontrol->value.integer.value[1]) {
chip->input_level[0] = ucontrol->value.integer.value[0];
chip->input_level[1] = ucontrol->value.integer.value[1];
vx2_set_input_level(chip);
- mutex_unlock(&_chip->mixer_mutex);
return 1;
}
- mutex_unlock(&_chip->mixer_mutex);
return 0;
}
@@ -923,14 +921,12 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
if (ucontrol->value.integer.value[0] < 0 ||
ucontrol->value.integer.value[0] > MIC_LEVEL_MAX)
return -EINVAL;
- mutex_lock(&_chip->mixer_mutex);
+ guard(mutex)(&_chip->mixer_mutex);
if (chip->mic_level != ucontrol->value.integer.value[0]) {
chip->mic_level = ucontrol->value.integer.value[0];
vx2_set_input_level(chip);
- mutex_unlock(&_chip->mixer_mutex);
return 1;
}
- mutex_unlock(&_chip->mixer_mutex);
return 0;
}
diff --git a/sound/pci/ymfpci/Makefile b/sound/pci/ymfpci/Makefile
index 40a1d83e1a9e..2d7856403371 100644
--- a/sound/pci/ymfpci/Makefile
+++ b/sound/pci/ymfpci/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-ymfpci-objs := ymfpci.o ymfpci_main.o
+snd-ymfpci-y := ymfpci.o ymfpci_main.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_YMFPCI) += snd-ymfpci.o
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index b033bd290940..764ca59e98d1 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -152,8 +152,8 @@ static inline int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, i
void snd_ymfpci_free_gameport(struct snd_ymfpci *chip) { }
#endif /* SUPPORT_JOYSTICK */
-static int snd_card_ymfpci_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
+static int __snd_card_ymfpci_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
{
static int dev;
struct snd_card *card;
@@ -188,7 +188,7 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
default: model = str = "???"; break;
}
- strcpy(card->driver, str);
+ strscpy(card->driver, str);
sprintf(card->shortname, "Yamaha %s (%s)", model, str);
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname,
@@ -348,6 +348,12 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
return 0;
}
+static int snd_card_ymfpci_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ return snd_card_free_on_error(&pci->dev, __snd_card_ymfpci_probe(pci, pci_id));
+}
+
static struct pci_driver ymfpci_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_ymfpci_ids,
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 6971eec45a4d..eb373d9395e3 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -159,26 +159,21 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate)
static void snd_ymfpci_hw_start(struct snd_ymfpci *chip)
{
- unsigned long flags;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (chip->start_count++ > 0)
- goto __end;
+ return;
snd_ymfpci_writel(chip, YDSXGR_MODE,
snd_ymfpci_readl(chip, YDSXGR_MODE) | 3);
chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;
- __end:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
static void snd_ymfpci_hw_stop(struct snd_ymfpci *chip)
{
- unsigned long flags;
long timeout = 1000;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (--chip->start_count > 0)
- goto __end;
+ return;
snd_ymfpci_writel(chip, YDSXGR_MODE,
snd_ymfpci_readl(chip, YDSXGR_MODE) & ~3);
while (timeout-- > 0) {
@@ -189,8 +184,6 @@ static void snd_ymfpci_hw_stop(struct snd_ymfpci *chip)
atomic_set(&chip->interrupt_sleep_count, 0);
wake_up(&chip->interrupt_sleep);
}
- __end:
- spin_unlock_irqrestore(&chip->reg_lock, flags);
}
/*
@@ -239,7 +232,6 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip,
enum snd_ymfpci_voice_type type, int pair,
struct snd_ymfpci_voice **rvoice)
{
- unsigned long flags;
int result;
if (snd_BUG_ON(!rvoice))
@@ -247,7 +239,7 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip,
if (snd_BUG_ON(pair && type != YMFPCI_PCM))
return -EINVAL;
- spin_lock_irqsave(&chip->voice_lock, flags);
+ guard(spinlock_irqsave)(&chip->voice_lock);
for (;;) {
result = voice_alloc(chip, type, pair, rvoice);
if (result == 0 || type != YMFPCI_PCM)
@@ -255,18 +247,15 @@ static int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip,
/* TODO: synth/midi voice deallocation */
break;
}
- spin_unlock_irqrestore(&chip->voice_lock, flags);
return result;
}
static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voice *pvoice)
{
- unsigned long flags;
-
if (snd_BUG_ON(!pvoice))
return -EINVAL;
snd_ymfpci_hw_stop(chip);
- spin_lock_irqsave(&chip->voice_lock, flags);
+ guard(spinlock_irqsave)(&chip->voice_lock);
if (pvoice->number == chip->src441_used) {
chip->src441_used = -1;
pvoice->ypcm->use_441_slot = 0;
@@ -274,7 +263,6 @@ static int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voic
pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
pvoice->ypcm = NULL;
pvoice->interrupt = NULL;
- spin_unlock_irqrestore(&chip->voice_lock, flags);
return 0;
}
@@ -292,7 +280,7 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
return;
if (ypcm->substream == NULL)
return;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
if (ypcm->running) {
pos = le32_to_cpu(voice->bank[chip->active_bank].start);
if (pos < ypcm->last_pos)
@@ -334,7 +322,6 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
ypcm->update_pcm_vol--;
}
}
- spin_unlock(&chip->reg_lock);
}
static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream)
@@ -344,7 +331,7 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream
struct snd_ymfpci *chip = ypcm->chip;
u32 pos, delta;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
if (ypcm->running) {
pos = le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;
if (pos < ypcm->last_pos)
@@ -366,7 +353,6 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream
spin_lock(&chip->reg_lock);
}
}
- spin_unlock(&chip->reg_lock);
}
static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
@@ -377,11 +363,9 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
struct snd_kcontrol *kctl = NULL;
int result = 0;
- spin_lock(&chip->reg_lock);
- if (ypcm->voices[0] == NULL) {
- result = -EINVAL;
- goto __unlock;
- }
+ guard(spinlock)(&chip->reg_lock);
+ if (ypcm->voices[0] == NULL)
+ return -EINVAL;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -405,11 +389,8 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream,
ypcm->running = 0;
break;
default:
- result = -EINVAL;
- break;
+ return -EINVAL;
}
- __unlock:
- spin_unlock(&chip->reg_lock);
if (kctl)
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return result;
@@ -422,7 +403,7 @@ static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream,
int result = 0;
u32 tmp;
- spin_lock(&chip->reg_lock);
+ guard(spinlock)(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -442,7 +423,6 @@ static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream,
result = -EINVAL;
break;
}
- spin_unlock(&chip->reg_lock);
return result;
}
@@ -489,7 +469,6 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
unsigned int nbank;
__le32 vol_left, vol_right;
u8 use_left, use_right;
- unsigned long flags;
if (snd_BUG_ON(!voice))
return;
@@ -509,26 +488,26 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
vol_left = cpu_to_le32(0x40000000);
vol_right = cpu_to_le32(0x40000000);
}
- spin_lock_irqsave(&ypcm->chip->voice_lock, flags);
- format = runtime->channels == 2 ? 0x00010000 : 0;
- if (snd_pcm_format_width(runtime->format) == 8)
- format |= 0x80000000;
- else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
- runtime->rate == 44100 && runtime->channels == 2 &&
- voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
- ypcm->chip->src441_used == voice->number)) {
- ypcm->chip->src441_used = voice->number;
- ypcm->use_441_slot = 1;
- format |= 0x10000000;
- }
- if (ypcm->chip->src441_used == voice->number &&
- (format & 0x10000000) == 0) {
- ypcm->chip->src441_used = -1;
- ypcm->use_441_slot = 0;
+ scoped_guard(spinlock_irqsave, &ypcm->chip->voice_lock) {
+ format = runtime->channels == 2 ? 0x00010000 : 0;
+ if (snd_pcm_format_width(runtime->format) == 8)
+ format |= 0x80000000;
+ else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 &&
+ runtime->rate == 44100 && runtime->channels == 2 &&
+ voiceidx == 0 && (ypcm->chip->src441_used == -1 ||
+ ypcm->chip->src441_used == voice->number)) {
+ ypcm->chip->src441_used = voice->number;
+ ypcm->use_441_slot = 1;
+ format |= 0x10000000;
+ }
+ if (ypcm->chip->src441_used == voice->number &&
+ (format & 0x10000000) == 0) {
+ ypcm->chip->src441_used = -1;
+ ypcm->use_441_slot = 0;
+ }
+ if (runtime->channels == 2 && (voiceidx & 1) != 0)
+ format |= 1;
}
- if (runtime->channels == 2 && (voiceidx & 1) != 0)
- format |= 1;
- spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags);
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
memset(bank, 0, sizeof(*bank));
@@ -596,19 +575,18 @@ static int snd_ymfpci_ac3_init(struct snd_ymfpci *chip)
chip->bank_effect[4][0]->loop_end =
chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
static int snd_ymfpci_ac3_done(struct snd_ymfpci *chip)
{
- spin_lock_irq(&chip->reg_lock);
- snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
- snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3));
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT,
+ snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3));
+ }
// snd_ymfpci_irq_wait(chip);
if (chip->ac3_tmp_base.area) {
snd_dma_free_pages(&chip->ac3_tmp_base);
@@ -778,28 +756,28 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id)
status = snd_ymfpci_readl(chip, YDSXGR_STATUS);
if (status & 0x80000000) {
chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1;
- spin_lock(&chip->voice_lock);
- for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
- voice = &chip->voices[nvoice];
- if (voice->interrupt)
- voice->interrupt(chip, voice);
- }
- for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
- if (chip->capture_substream[nvoice])
- snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]);
- }
+ scoped_guard(spinlock, &chip->voice_lock) {
+ for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
+ voice = &chip->voices[nvoice];
+ if (voice->interrupt)
+ voice->interrupt(chip, voice);
+ }
+ for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
+ if (chip->capture_substream[nvoice])
+ snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]);
+ }
#if 0
- for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) {
- if (chip->effect_substream[nvoice])
- snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]);
- }
+ for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) {
+ if (chip->effect_substream[nvoice])
+ snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]);
+ }
#endif
- spin_unlock(&chip->voice_lock);
- spin_lock(&chip->reg_lock);
- snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000);
- mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2;
- snd_ymfpci_writel(chip, YDSXGR_MODE, mode);
- spin_unlock(&chip->reg_lock);
+ }
+ scoped_guard(spinlock, &chip->reg_lock) {
+ snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000);
+ mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2;
+ snd_ymfpci_writel(chip, YDSXGR_MODE, mode);
+ }
if (atomic_read(&chip->interrupt_sleep_count)) {
atomic_set(&chip->interrupt_sleep_count, 0);
@@ -936,12 +914,11 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream)
ypcm->output_front = 1;
ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
ypcm->swap_rear = 0;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
if (ypcm->output_rear) {
ymfpci_open_extension(chip);
chip->rear_opened++;
}
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -959,14 +936,14 @@ static int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream)
ypcm->output_front = 0;
ypcm->output_rear = 1;
ypcm->swap_rear = 1;
- spin_lock_irq(&chip->reg_lock);
- snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
- snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2);
- ymfpci_open_extension(chip);
- chip->spdif_pcm_bits = chip->spdif_bits;
- snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
- chip->spdif_opened++;
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
+ snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2);
+ ymfpci_open_extension(chip);
+ chip->spdif_pcm_bits = chip->spdif_bits;
+ snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
+ chip->spdif_opened++;
+ }
chip->spdif_pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
@@ -988,10 +965,9 @@ static int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream)
ypcm->output_front = 0;
ypcm->output_rear = 1;
ypcm->swap_rear = 0;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
ymfpci_open_extension(chip);
chip->rear_opened++;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1048,12 +1024,12 @@ static int snd_ymfpci_playback_close(struct snd_pcm_substream *substream)
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
- spin_lock_irq(&chip->reg_lock);
- if (ypcm->output_rear && chip->rear_opened > 0) {
- chip->rear_opened--;
- ymfpci_close_extension(chip);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ if (ypcm->output_rear && chip->rear_opened > 0) {
+ chip->rear_opened--;
+ ymfpci_close_extension(chip);
+ }
}
- spin_unlock_irq(&chip->reg_lock);
return snd_ymfpci_playback_close_1(substream);
}
@@ -1061,13 +1037,13 @@ static int snd_ymfpci_playback_spdif_close(struct snd_pcm_substream *substream)
{
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
- chip->spdif_opened = 0;
- ymfpci_close_extension(chip);
- snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
- snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2);
- snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
- spin_unlock_irq(&chip->reg_lock);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ chip->spdif_opened = 0;
+ ymfpci_close_extension(chip);
+ snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL,
+ snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2);
+ snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
+ }
chip->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id);
@@ -1078,12 +1054,12 @@ static int snd_ymfpci_playback_4ch_close(struct snd_pcm_substream *substream)
{
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
- spin_lock_irq(&chip->reg_lock);
- if (chip->rear_opened > 0) {
- chip->rear_opened--;
- ymfpci_close_extension(chip);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ if (chip->rear_opened > 0) {
+ chip->rear_opened--;
+ ymfpci_close_extension(chip);
+ }
}
- spin_unlock_irq(&chip->reg_lock);
return snd_ymfpci_playback_close_1(substream);
}
@@ -1134,7 +1110,7 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "YMFPCI");
+ strscpy(pcm->name, "YMFPCI");
chip->pcm = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1201,7 +1177,7 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "YMFPCI - IEC958");
+ strscpy(pcm->name, "YMFPCI - IEC958");
chip->pcm_spdif = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1242,7 +1218,7 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device)
/* global setup */
pcm->info_flags = 0;
- strcpy(pcm->name, "YMFPCI - Rear PCM");
+ strscpy(pcm->name, "YMFPCI - Rear PCM");
chip->pcm_4ch = pcm;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
@@ -1264,11 +1240,10 @@ static int snd_ymfpci_spdif_default_get(struct snd_kcontrol *kcontrol,
{
struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
ucontrol->value.iec958.status[0] = (chip->spdif_bits >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (chip->spdif_bits >> 8) & 0xff;
ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1281,12 +1256,11 @@ static int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol,
val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) |
(ucontrol->value.iec958.status[1] << 8);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
change = chip->spdif_bits != val;
chip->spdif_bits = val;
if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 1) && chip->pcm_spdif == NULL)
snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits);
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1311,10 +1285,9 @@ static int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol,
{
struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
ucontrol->value.iec958.status[0] = 0x3e;
ucontrol->value.iec958.status[1] = 0xff;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1339,11 +1312,10 @@ static int snd_ymfpci_spdif_stream_get(struct snd_kcontrol *kcontrol,
{
struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
ucontrol->value.iec958.status[0] = (chip->spdif_pcm_bits >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (chip->spdif_pcm_bits >> 8) & 0xff;
ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000;
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1356,12 +1328,11 @@ static int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol,
val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) |
(ucontrol->value.iec958.status[1] << 8);
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
change = chip->spdif_pcm_bits != val;
chip->spdif_pcm_bits = val;
if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 2))
snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits);
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1387,9 +1358,8 @@ static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_
struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
u16 reg;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
- spin_unlock_irq(&chip->reg_lock);
if (!(reg & 0x100))
value->value.enumerated.item[0] = 0;
else
@@ -1402,14 +1372,13 @@ static int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_
struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
u16 reg, old_reg;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL);
if (value->value.enumerated.item[0] == 0)
reg = old_reg & ~0x100;
else
reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9);
snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg);
- spin_unlock_irq(&chip->reg_lock);
return reg != old_reg;
}
@@ -1469,12 +1438,11 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol,
}
val = (ucontrol->value.integer.value[0] & mask);
val <<= shift;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oval = snd_ymfpci_readl(chip, reg);
val = (oval & ~(mask << shift)) | val;
change = val != oval;
snd_ymfpci_writel(chip, reg, val);
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1510,9 +1478,8 @@ static int snd_ymfpci_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
if (reg < 0x80 || reg >= 0xc0)
return -EINVAL;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
val = snd_ymfpci_readl(chip, reg);
- spin_unlock_irq(&chip->reg_lock);
ucontrol->value.integer.value[0] = (val >> shift_left) & mask;
ucontrol->value.integer.value[1] = (val >> shift_right) & mask;
return 0;
@@ -1532,12 +1499,11 @@ static int snd_ymfpci_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e
val2 = ucontrol->value.integer.value[1] & mask;
val1 <<= shift_left;
val2 <<= shift_right;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oval = snd_ymfpci_readl(chip, reg);
val1 = (oval & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
change = val1 != oval;
snd_ymfpci_writel(chip, reg, val1);
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1552,12 +1518,11 @@ static int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol,
value = ucontrol->value.integer.value[0] & 0x3fff;
value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16;
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
oval = snd_ymfpci_readl(chip, reg);
change = value != oval;
snd_ymfpci_writel(chip, reg, value);
snd_ymfpci_writel(chip, reg2, value);
- spin_unlock_irq(&chip->reg_lock);
return change;
}
@@ -1629,9 +1594,8 @@ YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4)
static int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin)
{
u16 reg, mode;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
reg &= ~(1 << (pin + 8));
reg |= (1 << pin);
@@ -1642,23 +1606,20 @@ static int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin)
snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode);
snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return (mode >> pin) & 1;
}
static int snd_ymfpci_set_gpio_out(struct snd_ymfpci *chip, int pin, int enable)
{
u16 reg;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
reg &= ~(1 << pin);
reg &= ~(1 << (pin + 8));
snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin);
snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -1726,7 +1687,6 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
unsigned int subs = kcontrol->id.subdevice;
struct snd_pcm_substream *substream;
- unsigned long flags;
if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
@@ -1738,13 +1698,12 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
chip->pcm_mixer[subs].right = 0x8000;
substream = (struct snd_pcm_substream *)kcontrol->private_value;
- spin_lock_irqsave(&chip->voice_lock, flags);
+ guard(spinlock_irqsave)(&chip->voice_lock);
if (substream->runtime && substream->runtime->private_data) {
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
if (!ypcm->use_441_slot)
ypcm->update_pcm_vol = 2;
}
- spin_unlock_irqrestore(&chip->voice_lock, flags);
return 1;
}
return 0;
@@ -1822,20 +1781,20 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
if (snd_BUG_ON(!chip->pcm_spdif))
return -ENXIO;
kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip);
+ kctl->id.device = chip->pcm_spdif->device;
err = snd_ctl_add(chip->card, kctl);
if (err < 0)
return err;
- kctl->id.device = chip->pcm_spdif->device;
kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip);
+ kctl->id.device = chip->pcm_spdif->device;
err = snd_ctl_add(chip->card, kctl);
if (err < 0)
return err;
- kctl->id.device = chip->pcm_spdif->device;
kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip);
+ kctl->id.device = chip->pcm_spdif->device;
err = snd_ctl_add(chip->card, kctl);
if (err < 0)
return err;
- kctl->id.device = chip->pcm_spdif->device;
chip->spdif_pcm_ctl = kctl;
/* direct recording source */
@@ -1884,11 +1843,10 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
static int snd_ymfpci_timer_start(struct snd_timer *timer)
{
struct snd_ymfpci *chip;
- unsigned long flags;
unsigned int count;
chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (timer->sticks > 1) {
chip->timer_ticks = timer->sticks;
count = timer->sticks - 1;
@@ -1902,19 +1860,16 @@ static int snd_ymfpci_timer_start(struct snd_timer *timer)
}
snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count);
snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
static int snd_ymfpci_timer_stop(struct snd_timer *timer)
{
struct snd_ymfpci *chip;
- unsigned long flags;
chip = snd_timer_chip(timer);
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -1948,7 +1903,7 @@ int snd_ymfpci_timer(struct snd_ymfpci *chip, int device)
tid.subdevice = 0;
err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer);
if (err >= 0) {
- strcpy(timer->name, "YMFPCI timer");
+ strscpy(timer->name, "YMFPCI timer");
timer->private_data = chip;
timer->hw = snd_ymfpci_timer_hw;
}
@@ -2273,10 +2228,9 @@ static int snd_ymfpci_resume(struct device *dev)
/* start hw again */
if (chip->start_count > 0) {
- spin_lock_irq(&chip->reg_lock);
+ guard(spinlock_irq)(&chip->reg_lock);
snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode);
chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT);
- spin_unlock_irq(&chip->reg_lock);
}
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
@@ -2307,7 +2261,7 @@ int snd_ymfpci_create(struct snd_card *card,
chip->device_id = pci->device;
chip->rev = pci->revision;
- err = pci_request_regions(pci, "YMFPCI");
+ err = pcim_request_all_regions(pci, "YMFPCI");
if (err < 0)
return err;
diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig
index 10291c43cb18..2e3dfc1ff540 100644
--- a/sound/pcmcia/Kconfig
+++ b/sound/pcmcia/Kconfig
@@ -4,6 +4,7 @@
menuconfig SND_PCMCIA
bool "PCMCIA sound devices"
depends on PCMCIA
+ depends on HAS_IOPORT
default y
help
Support for sound devices connected via the PCMCIA bus.
diff --git a/sound/pcmcia/pdaudiocf/Makefile b/sound/pcmcia/pdaudiocf/Makefile
index ea0d67576df9..34a288c1eebd 100644
--- a/sound/pcmcia/pdaudiocf/Makefile
+++ b/sound/pcmcia/pdaudiocf/Makefile
@@ -4,6 +4,6 @@
# Copyright (c) 2004 by Jaroslav Kysela <perex@perex.cz>
#
-snd-pdaudiocf-objs := pdaudiocf.o pdaudiocf_core.o pdaudiocf_irq.o pdaudiocf_pcm.o
+snd-pdaudiocf-y := pdaudiocf.o pdaudiocf_core.o pdaudiocf_irq.o pdaudiocf_pcm.o
obj-$(CONFIG_SND_PDAUDIOCF) += snd-pdaudiocf.o
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 8363ec08df5d..13419837dfb7 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -85,14 +85,13 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
.dev_free = snd_pdacf_dev_free,
};
- snd_printdd(KERN_DEBUG "pdacf_attach called\n");
/* find an empty slot from the card list */
for (i = 0; i < SNDRV_CARDS; i++) {
if (! card_list[i])
break;
}
if (i >= SNDRV_CARDS) {
- snd_printk(KERN_ERR "pdacf: too many cards found\n");
+ dev_err(&link->dev, "pdacf: too many cards found\n");
return -EINVAL;
}
if (! enable[i])
@@ -102,7 +101,7 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
err = snd_card_new(&link->dev, index[i], id[i], THIS_MODULE,
0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "pdacf: cannot create a card instance\n");
+ dev_err(&link->dev, "pdacf: cannot create a card instance\n");
return err;
}
@@ -152,7 +151,7 @@ static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq
int err;
struct snd_card *card = pdacf->card;
- snd_printdd(KERN_DEBUG "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq);
+ dev_dbg(card->dev, "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq);
pdacf->port = port;
pdacf->irq = irq;
pdacf->chip_status |= PDAUDIOCF_STAT_IS_CONFIGURED;
@@ -161,7 +160,7 @@ static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq
if (err < 0)
return err;
- strcpy(card->driver, "PDAudio-CF");
+ strscpy(card->driver, "PDAudio-CF");
sprintf(card->shortname, "Core Sound %s", card->driver);
sprintf(card->longname, "%s at 0x%x, irq %i",
card->shortname, port, irq);
@@ -185,8 +184,6 @@ static void snd_pdacf_detach(struct pcmcia_device *link)
{
struct snd_pdacf *chip = link->priv;
- snd_printdd(KERN_DEBUG "pdacf_detach called\n");
-
if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED)
snd_pdacf_powerdown(chip);
chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */
@@ -203,7 +200,6 @@ static int pdacf_config(struct pcmcia_device *link)
struct snd_pdacf *pdacf = link->priv;
int ret;
- snd_printdd(KERN_DEBUG "pdacf_config called\n");
link->config_index = 0x5;
link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
@@ -241,11 +237,8 @@ static int pdacf_suspend(struct pcmcia_device *link)
{
struct snd_pdacf *chip = link->priv;
- snd_printdd(KERN_DEBUG "SUSPEND\n");
- if (chip) {
- snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n");
+ if (chip)
snd_pdacf_suspend(chip);
- }
return 0;
}
@@ -254,14 +247,10 @@ static int pdacf_resume(struct pcmcia_device *link)
{
struct snd_pdacf *chip = link->priv;
- snd_printdd(KERN_DEBUG "RESUME\n");
if (pcmcia_dev_present(link)) {
- if (chip) {
- snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n");
+ if (chip)
snd_pdacf_resume(chip);
- }
}
- snd_printdd(KERN_DEBUG "resume done!\n");
return 0;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
index 5537c0882aa5..a104baac3a94 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -28,7 +28,7 @@ static unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg)
udelay(5);
if (--timeout == 0) {
spin_unlock_irqrestore(&chip->ak4117_lock, flags);
- snd_printk(KERN_ERR "AK4117 ready timeout (read)\n");
+ dev_err(chip->card->dev, "AK4117 ready timeout (read)\n");
return 0;
}
}
@@ -38,7 +38,7 @@ static unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg)
udelay(5);
if (--timeout == 0) {
spin_unlock_irqrestore(&chip->ak4117_lock, flags);
- snd_printk(KERN_ERR "AK4117 read timeout (read2)\n");
+ dev_err(chip->card->dev, "AK4117 read timeout (read2)\n");
return 0;
}
}
@@ -59,7 +59,7 @@ static void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned c
udelay(5);
if (--timeout == 0) {
spin_unlock_irqrestore(&chip->ak4117_lock, flags);
- snd_printk(KERN_ERR "AK4117 ready timeout (write)\n");
+ dev_err(chip->card->dev, "AK4117 ready timeout (write)\n");
return;
}
}
@@ -70,21 +70,21 @@ static void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned c
#if 0
void pdacf_dump(struct snd_pdacf *chip)
{
- printk(KERN_DEBUG "PDAUDIOCF DUMP (0x%lx):\n", chip->port);
- printk(KERN_DEBUG "WPD : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_WDP));
- printk(KERN_DEBUG "RDP : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_RDP));
- printk(KERN_DEBUG "TCR : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_TCR));
- printk(KERN_DEBUG "SCR : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_SCR));
- printk(KERN_DEBUG "ISR : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_ISR));
- printk(KERN_DEBUG "IER : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_IER));
- printk(KERN_DEBUG "AK_IFR : 0x%x\n",
- inw(chip->port + PDAUDIOCF_REG_AK_IFR));
+ dev_dbg(chip->card->dev, "PDAUDIOCF DUMP (0x%lx):\n", chip->port);
+ dev_dbg(chip->card->dev, "WPD : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_WDP));
+ dev_dbg(chip->card->dev, "RDP : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_RDP));
+ dev_dbg(chip->card->dev, "TCR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_TCR));
+ dev_dbg(chip->card->dev, "SCR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_SCR));
+ dev_dbg(chip->card->dev, "ISR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_ISR));
+ dev_dbg(chip->card->dev, "IER : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_IER));
+ dev_dbg(chip->card->dev, "AK_IFR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_AK_IFR));
}
#endif
@@ -161,14 +161,13 @@ static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, uns
if (!(c0 & AK4117_UNLCK))
return;
- mutex_lock(&chip->reg_lock);
+ guard(mutex)(&chip->reg_lock);
val = chip->regmap[PDAUDIOCF_REG_SCR>>1];
if (ak4117->rcs0 & AK4117_UNLCK)
val |= PDAUDIOCF_BLUE_LED_OFF;
else
val &= ~PDAUDIOCF_BLUE_LED_OFF;
pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
- mutex_unlock(&chip->reg_lock);
}
int snd_pdacf_ak4117_create(struct snd_pdacf *chip)
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index f134b4a4622f..af40a2c8789a 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -27,7 +27,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev)
stat = inw(chip->port + PDAUDIOCF_REG_ISR);
if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
if (stat & PDAUDIOCF_IRQOVR) /* should never happen */
- snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
+ dev_err(chip->card->dev, "PDAUDIOCF SRAM buffer overrun detected!\n");
if (chip->pcm_substream)
wake_thread = true;
if (!(stat & PDAUDIOCF_IRQAKM))
@@ -257,7 +257,6 @@ irqreturn_t pdacf_threaded_irq(int irq, void *dev)
rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
- /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
size = wdp - rdp;
if (size < 0)
size += 0x10000;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
index aaa82ec36540..228822996ef7 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
@@ -64,21 +64,20 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
default:
return -EINVAL;
}
- mutex_lock(&chip->reg_lock);
- chip->pcm_running += inc;
- tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
- if (chip->pcm_running) {
- if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
- chip->pcm_running -= inc;
- ret = -EIO;
- goto __end;
+ scoped_guard(mutex, &chip->reg_lock) {
+ chip->pcm_running += inc;
+ tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
+ if (chip->pcm_running) {
+ if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
+ chip->pcm_running -= inc;
+ ret = -EIO;
+ break;
+ }
}
+ tmp &= ~mask;
+ tmp |= val;
+ pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
}
- tmp &= ~mask;
- tmp |= val;
- pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
- __end:
- mutex_unlock(&chip->reg_lock);
snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
return ret;
}
@@ -263,7 +262,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip)
pcm->private_data = chip;
pcm->info_flags = 0;
pcm->nonatomic = true;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
diff --git a/sound/pcmcia/vx/Makefile b/sound/pcmcia/vx/Makefile
index b25006e4d25a..abd187544946 100644
--- a/sound/pcmcia/vx/Makefile
+++ b/sound/pcmcia/vx/Makefile
@@ -4,6 +4,6 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-vxpocket-objs := vxpocket.o vxp_ops.o vxp_mixer.o
+snd-vxpocket-y := vxpocket.o vxp_ops.o vxp_mixer.o
obj-$(CONFIG_SND_VXPOCKET) += snd-vxpocket.o
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c
index bc2114475810..998cea2d0318 100644
--- a/sound/pcmcia/vx/vxp_mixer.c
+++ b/sound/pcmcia/vx/vxp_mixer.c
@@ -43,14 +43,12 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
if (val > MIC_LEVEL_MAX)
return -EINVAL;
- mutex_lock(&_chip->mixer_mutex);
+ guard(mutex)(&_chip->mixer_mutex);
if (chip->mic_level != ucontrol->value.integer.value[0]) {
vx_set_mic_level(_chip, ucontrol->value.integer.value[0]);
chip->mic_level = ucontrol->value.integer.value[0];
- mutex_unlock(&_chip->mixer_mutex);
return 1;
}
- mutex_unlock(&_chip->mixer_mutex);
return 0;
}
@@ -85,14 +83,13 @@ static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
struct snd_vxpocket *chip = to_vxpocket(_chip);
int val = !!ucontrol->value.integer.value[0];
- mutex_lock(&_chip->mixer_mutex);
+
+ guard(mutex)(&_chip->mixer_mutex);
if (chip->mic_level != val) {
vx_set_mic_boost(_chip, val);
chip->mic_level = val;
- mutex_unlock(&_chip->mixer_mutex);
return 1;
}
- mutex_unlock(&_chip->mixer_mutex);
return 0;
}
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 4176abd73799..4211e7239138 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -84,7 +84,7 @@ static int vx_check_magic(struct vx_core *chip)
return 0;
msleep(10);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "cannot find xilinx magic word (%x)\n", c);
+ dev_err(chip->card->dev, "cannot find xilinx magic word (%x)\n", c);
return -EIO;
}
@@ -153,7 +153,6 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
vx_outb(chip, ICR, 0);
/* Wait for answer HF2 equal to 1 */
- snd_printdd(KERN_DEBUG "check ISR_HF2\n");
if (vx_check_isr(_chip, ISR_HF2, ISR_HF2, 20) < 0)
goto _error;
@@ -170,7 +169,9 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
goto _error;
c = vx_inb(chip, RXL);
if (c != (int)data)
- snd_printk(KERN_ERR "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n", i, c, (int)data);
+ dev_err(_chip->card->dev,
+ "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n",
+ i, c, (int)data);
}
/* reset HF1 */
@@ -188,7 +189,8 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
c |= (int)vx_inb(chip, RXM) << 8;
c |= vx_inb(chip, RXL);
- snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%zx\n", c, fw->size);
+ dev_dbg(_chip->card->dev,
+ "xilinx: dsp size received 0x%x, orig 0x%zx\n", c, fw->size);
vx_outb(chip, ICR, ICR_HF0);
@@ -461,7 +463,7 @@ void vx_set_mic_boost(struct vx_core *chip, int boost)
if (chip->chip_status & VX_STAT_IS_STALE)
return;
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) {
if (boost) {
/* boost: 38 dB */
@@ -474,7 +476,6 @@ void vx_set_mic_boost(struct vx_core *chip, int boost)
}
vx_outb(chip, CDSP, pchip->regCDSP);
}
- mutex_unlock(&chip->lock);
}
/*
@@ -503,12 +504,11 @@ void vx_set_mic_level(struct vx_core *chip, int level)
if (chip->chip_status & VX_STAT_IS_STALE)
return;
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) {
level = vx_compute_mic_level(level);
vx_outb(chip, MICRO, level);
}
- mutex_unlock(&chip->lock);
}
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 7a0f0e73ceb2..2e09f2a513a6 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -151,7 +151,8 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq
struct snd_card *card = chip->card;
struct snd_vxpocket *vxp = to_vxpocket(chip);
- snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
+ dev_dbg(chip->card->dev,
+ "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
vxp->port = port;
sprintf(card->shortname, "Digigram %s", card->driver);
@@ -178,17 +179,15 @@ static int vxpocket_config(struct pcmcia_device *link)
struct vx_core *chip = link->priv;
int ret;
- snd_printdd(KERN_DEBUG "vxpocket_config called\n");
-
/* redefine hardware record according to the VERSION1 string */
if (!strcmp(link->prod_id[1], "VX-POCKET")) {
- snd_printdd("VX-pocket is detected\n");
+ dev_dbg(chip->card->dev, "VX-pocket is detected\n");
} else {
- snd_printdd("VX-pocket 440 is detected\n");
+ dev_dbg(chip->card->dev, "VX-pocket 440 is detected\n");
/* overwrite the hardware information */
chip->hw = &vxp440_hw;
chip->type = vxp440_hw.type;
- strcpy(chip->card->driver, vxp440_hw.name);
+ strscpy(chip->card->driver, vxp440_hw.name);
}
ret = pcmcia_request_io(link);
@@ -205,8 +204,6 @@ static int vxpocket_config(struct pcmcia_device *link)
if (ret)
goto failed;
- chip->dev = &link->dev;
-
if (snd_vxpocket_assign_resources(chip, link->resource[0]->start,
link->irq) < 0)
goto failed;
@@ -226,11 +223,8 @@ static int vxp_suspend(struct pcmcia_device *link)
{
struct vx_core *chip = link->priv;
- snd_printdd(KERN_DEBUG "SUSPEND\n");
- if (chip) {
- snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
+ if (chip)
snd_vx_suspend(chip);
- }
return 0;
}
@@ -239,15 +233,10 @@ static int vxp_resume(struct pcmcia_device *link)
{
struct vx_core *chip = link->priv;
- snd_printdd(KERN_DEBUG "RESUME\n");
if (pcmcia_dev_present(link)) {
- //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
- if (chip) {
- snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
+ if (chip)
snd_vx_resume(chip);
- }
}
- snd_printdd(KERN_DEBUG "resume done!\n");
return 0;
}
@@ -269,7 +258,7 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
break;
}
if (i >= SNDRV_CARDS) {
- snd_printk(KERN_ERR "vxpocket: too many cards found\n");
+ dev_err(&p_dev->dev, "vxpocket: too many cards found\n");
return -EINVAL;
}
if (! enable[i])
@@ -279,7 +268,7 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
err = snd_card_new(&p_dev->dev, index[i], id[i], THIS_MODULE,
0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
+ dev_err(&p_dev->dev, "vxpocket: cannot create a card instance\n");
return err;
}
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
index 0188ce3e30b8..655bcffba843 100644
--- a/sound/ppc/Makefile
+++ b/sound/ppc/Makefile
@@ -4,7 +4,7 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
+snd-powermac-y := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 53d558b2806c..c231a9d6d1de 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -11,6 +11,7 @@
#include <asm/nvram.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <sound/core.h>
#include "pmac.h"
@@ -38,7 +39,7 @@ static void snd_pmac_screamer_wait(struct snd_pmac *chip)
while (!(in_le32(&chip->awacs->codec_stat) & MASK_VALID)) {
mdelay(1);
if (! --timeout) {
- snd_printd("snd_pmac_screamer_wait timeout\n");
+ dev_dbg(chip->card->dev, "%s timeout\n", __func__);
break;
}
}
@@ -57,7 +58,7 @@ snd_pmac_awacs_write(struct snd_pmac *chip, int val)
out_le32(&chip->awacs->codec_ctrl, val | (chip->subframe << 22));
while (in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) {
if (! --timeout) {
- snd_printd("snd_pmac_awacs_write timeout\n");
+ dev_dbg(chip->card->dev, "%s timeout\n", __func__);
break;
}
}
@@ -136,13 +137,11 @@ static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol,
int reg = kcontrol->private_value & 0xff;
int lshift = (kcontrol->private_value >> 8) & 0xff;
int inverted = (kcontrol->private_value >> 16) & 1;
- unsigned long flags;
int vol[2];
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
vol[0] = (chip->awacs_reg[reg] >> lshift) & 0xf;
vol[1] = chip->awacs_reg[reg] & 0xf;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (inverted) {
vol[0] = 0x0f - vol[0];
vol[1] = 0x0f - vol[1];
@@ -160,7 +159,6 @@ static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol,
int lshift = (kcontrol->private_value >> 8) & 0xff;
int inverted = (kcontrol->private_value >> 16) & 1;
int val, oldval;
- unsigned long flags;
unsigned int vol[2];
vol[0] = ucontrol->value.integer.value[0];
@@ -173,14 +171,13 @@ static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol,
}
vol[0] &= 0x0f;
vol[1] &= 0x0f;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
oldval = chip->awacs_reg[reg];
val = oldval & ~(0xf | (0xf << lshift));
val |= vol[0] << lshift;
val |= vol[1];
if (oldval != val)
snd_pmac_awacs_write_reg(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return oldval != reg;
}
@@ -203,11 +200,9 @@ static int snd_pmac_awacs_get_switch(struct snd_kcontrol *kcontrol,
int shift = (kcontrol->private_value >> 8) & 0xff;
int invert = (kcontrol->private_value >> 16) & 1;
int val;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val = (chip->awacs_reg[reg] >> shift) & 1;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (invert)
val = 1 - val;
ucontrol->value.integer.value[0] = val;
@@ -223,16 +218,14 @@ static int snd_pmac_awacs_put_switch(struct snd_kcontrol *kcontrol,
int invert = (kcontrol->private_value >> 16) & 1;
int mask = 1 << shift;
int val, changed;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val = chip->awacs_reg[reg] & ~mask;
if (ucontrol->value.integer.value[0] != invert)
val |= mask;
changed = chip->awacs_reg[reg] != val;
if (changed)
snd_pmac_awacs_write_reg(chip, reg, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return changed;
}
@@ -540,14 +533,12 @@ static int snd_pmac_screamer_mic_boost_get(struct snd_kcontrol *kcontrol,
{
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
int val = 0;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (chip->awacs_reg[6] & MASK_MIC_BOOST)
val |= 2;
if (chip->awacs_reg[0] & MASK_GAINLINE)
val |= 1;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
ucontrol->value.integer.value[0] = val;
return 0;
}
@@ -558,9 +549,8 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,
struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
int changed = 0;
int val0, val6;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
val0 = chip->awacs_reg[0] & ~MASK_GAINLINE;
val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST;
if (ucontrol->value.integer.value[0] & 1)
@@ -575,7 +565,6 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,
snd_pmac_awacs_write_reg(chip, 6, val6);
changed = 1;
}
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return changed;
}
@@ -955,7 +944,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip)
/*
* build mixers
*/
- strcpy(chip->card->mixername, "PowerMac AWACS");
+ strscpy(chip->card->mixername, "PowerMac AWACS");
err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
snd_pmac_awacs_mixers);
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
index bf289783eafd..ab2468790b0c 100644
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -88,7 +88,6 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
{
struct snd_pmac *chip;
struct pmac_beep *beep;
- unsigned long flags;
int beep_speed = 0;
int srate;
int period, ncycles, nsamples;
@@ -112,10 +111,9 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
return -1;
if (! hz) {
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
if (beep->running)
snd_pmac_beep_stop(chip);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
@@ -125,13 +123,11 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
hz = 1000;
- spin_lock_irqsave(&chip->reg_lock, flags);
- if (chip->playback.running || chip->capture.running || beep->running) {
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- return 0;
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ if (chip->playback.running || chip->capture.running || beep->running)
+ return 0;
+ beep->running = 1;
}
- beep->running = 1;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
if (hz == beep->hz && beep->volume == beep->volume_play) {
nsamples = beep->nsamples;
@@ -151,9 +147,8 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type,
beep->nsamples = nsamples;
}
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
return 0;
}
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index 4fb990ab2ceb..5d6accce3a72 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -9,6 +9,7 @@
#include <linux/io.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/of.h>
#include <sound/core.h>
#include "pmac.h"
#include "burgundy.h"
@@ -58,9 +59,8 @@ static unsigned
snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
{
unsigned val = 0;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
snd_pmac_burgundy_busy_wait(chip);
@@ -82,8 +82,6 @@ snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
snd_pmac_burgundy_extend_wait(chip);
val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
return val;
}
@@ -99,17 +97,14 @@ static unsigned
snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr)
{
unsigned val = 0;
- unsigned long flags;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ guard(spinlock_irqsave)(&chip->reg_lock);
out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
snd_pmac_burgundy_busy_wait(chip);
snd_pmac_burgundy_extend_wait(chip);
val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
return val;
}
@@ -664,7 +659,7 @@ int snd_pmac_burgundy_init(struct snd_pmac *chip)
/*
* build burgundy mixers
*/
- strcpy(chip->card->mixername, "PowerMac Burgundy");
+ strscpy(chip->card->mixername, "PowerMac Burgundy");
for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
err = snd_ctl_add(chip->card,
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c
index 4da9278dd58a..a74114225b67 100644
--- a/sound/ppc/daca.c
+++ b/sound/ppc/daca.c
@@ -69,7 +69,7 @@ static int daca_set_volume(struct pmac_daca *mix)
data[1] |= mix->deemphasis ? 0x40 : 0;
if (i2c_smbus_write_block_data(mix->i2c.client, DACA_REG_AVOL,
2, data) < 0) {
- snd_printk(KERN_ERR "failed to set volume \n");
+ dev_err(&mix->i2c.client->dev, "failed to set volume\n");
return -EINVAL;
}
return 0;
@@ -261,7 +261,7 @@ int snd_pmac_daca_init(struct snd_pmac *chip)
/*
* build mixers
*/
- strcpy(chip->card->mixername, "PowerMac DACA");
+ strscpy(chip->card->mixername, "PowerMac DACA");
for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip));
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 0c4f43963c75..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;
}
@@ -80,8 +74,8 @@ static void keywest_remove(struct i2c_client *client)
static const struct i2c_device_id keywest_i2c_id[] = {
- { "MAC,tas3004", 0 }, /* instantiated by i2c-powermac */
- { "keywest", 0 }, /* instantiated by us if needed */
+ { "MAC,tas3004" }, /* instantiated by i2c-powermac */
+ { "keywest" }, /* instantiated by us if needed */
{ }
};
MODULE_DEVICE_TABLE(i2c, keywest_i2c_id);
@@ -90,7 +84,7 @@ static struct i2c_driver keywest_driver = {
.driver = {
.name = "PMac Keywest Audio",
},
- .probe_new = keywest_probe,
+ .probe = keywest_probe,
.remove = keywest_remove,
.id_table = keywest_i2c_id,
};
@@ -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;
}
@@ -113,7 +108,8 @@ int snd_pmac_tumbler_post_init(void)
err = keywest_ctx->init_client(keywest_ctx);
if (err < 0) {
- snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err);
+ dev_err(&keywest_ctx->client->dev,
+ "tumbler: %i :cannot initialize the MCS\n", err);
return err;
}
return 0;
@@ -136,7 +132,7 @@ int snd_pmac_keywest_init(struct pmac_keywest *i2c)
err = i2c_add_driver(&keywest_driver);
if (err) {
- snd_printk(KERN_ERR "cannot register keywest i2c driver\n");
+ dev_err(&i2c->client->dev, "cannot register keywest i2c driver\n");
i2c_put_adapter(adap);
return err;
}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 84058bbf9d12..6d7dab26ddf2 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -206,32 +206,32 @@ static int snd_pmac_pcm_prepare(struct snd_pmac *chip, struct pmac_stream *rec,
* common to many PowerBook G3 systems and random noise otherwise
* captured on iBook2's about every third time. -ReneR
*/
- spin_lock_irq(&chip->reg_lock);
- snd_pmac_dma_stop(rec);
- chip->extra_dma.cmds->command = cpu_to_le16(DBDMA_STOP);
- snd_pmac_dma_set_command(rec, &chip->extra_dma);
- snd_pmac_dma_run(rec, RUN);
- spin_unlock_irq(&chip->reg_lock);
- mdelay(5);
- spin_lock_irq(&chip->reg_lock);
- /* continuous DMA memory type doesn't provide the physical address,
- * so we need to resolve the address here...
- */
- offset = runtime->dma_addr;
- for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) {
- cp->phy_addr = cpu_to_le32(offset);
- cp->req_count = cpu_to_le16(rec->period_size);
- /*cp->res_count = cpu_to_le16(0);*/
- cp->xfer_status = cpu_to_le16(0);
- offset += rec->period_size;
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ snd_pmac_dma_stop(rec);
+ chip->extra_dma.cmds->command = cpu_to_le16(DBDMA_STOP);
+ snd_pmac_dma_set_command(rec, &chip->extra_dma);
+ snd_pmac_dma_run(rec, RUN);
}
- /* make loop */
- cp->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
- cp->cmd_dep = cpu_to_le32(rec->cmd.addr);
+ mdelay(5);
+ scoped_guard(spinlock_irq, &chip->reg_lock) {
+ /* continuous DMA memory type doesn't provide the physical address,
+ * so we need to resolve the address here...
+ */
+ offset = runtime->dma_addr;
+ for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) {
+ cp->phy_addr = cpu_to_le32(offset);
+ cp->req_count = cpu_to_le16(rec->period_size);
+ /*cp->res_count = cpu_to_le16(0);*/
+ cp->xfer_status = cpu_to_le16(0);
+ offset += rec->period_size;
+ }
+ /* make loop */
+ cp->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
+ cp->cmd_dep = cpu_to_le32(rec->cmd.addr);
- snd_pmac_dma_stop(rec);
- snd_pmac_dma_set_command(rec, &rec->cmd);
- spin_unlock_irq(&chip->reg_lock);
+ snd_pmac_dma_stop(rec);
+ snd_pmac_dma_set_command(rec, &rec->cmd);
+ }
return 0;
}
@@ -253,27 +253,26 @@ static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec,
return -EBUSY;
command = (subs->stream == SNDRV_PCM_STREAM_PLAYBACK ?
OUTPUT_MORE : INPUT_MORE) + INTR_ALWAYS;
- spin_lock(&chip->reg_lock);
- snd_pmac_beep_stop(chip);
- snd_pmac_pcm_set_format(chip);
- for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
- out_le16(&cp->command, command);
- snd_pmac_dma_set_command(rec, &rec->cmd);
- (void)in_le32(&rec->dma->status);
- snd_pmac_dma_run(rec, RUN|WAKE);
- rec->running = 1;
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ snd_pmac_beep_stop(chip);
+ snd_pmac_pcm_set_format(chip);
+ for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
+ out_le16(&cp->command, command);
+ snd_pmac_dma_set_command(rec, &rec->cmd);
+ (void)in_le32(&rec->dma->status);
+ snd_pmac_dma_run(rec, RUN|WAKE);
+ rec->running = 1;
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- spin_lock(&chip->reg_lock);
- rec->running = 0;
- /*printk(KERN_DEBUG "stopped!!\n");*/
- snd_pmac_dma_stop(rec);
- for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
- out_le16(&cp->command, DBDMA_STOP);
- spin_unlock(&chip->reg_lock);
+ scoped_guard(spinlock, &chip->reg_lock) {
+ rec->running = 0;
+ snd_pmac_dma_stop(rec);
+ for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
+ out_le16(&cp->command, DBDMA_STOP);
+ }
break;
default:
@@ -304,7 +303,6 @@ static snd_pcm_uframes_t snd_pmac_pcm_pointer(struct snd_pmac *chip,
}
#endif
count += rec->cur_period * rec->period_size;
- /*printk(KERN_DEBUG "pointer=%d\n", count);*/
return bytes_to_frames(subs->runtime, count);
}
@@ -384,8 +382,6 @@ static inline void snd_pmac_pcm_dead_xfer(struct pmac_stream *rec,
unsigned short req, res ;
unsigned int phy ;
- /* printk(KERN_WARNING "snd-powermac: DMA died - patching it up!\n"); */
-
/* to clear DEAD status we must first clear RUN
set it to quiescent to be on the safe side */
(void)in_le32(&rec->dma->status);
@@ -456,7 +452,6 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
if (! (stat & ACTIVE))
break;
- /*printk(KERN_DEBUG "update frag %d\n", rec->cur_period);*/
cp->xfer_status = cpu_to_le16(0);
cp->req_count = cpu_to_le16(rec->period_size);
/*cp->res_count = cpu_to_le16(0);*/
@@ -684,7 +679,7 @@ int snd_pmac_pcm_new(struct snd_pmac *chip)
pcm->private_data = chip;
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
- strcpy(pcm->name, chip->card->shortname);
+ strscpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
chip->formats_ok = SNDRV_PCM_FMTBIT_S16_BE;
@@ -770,7 +765,6 @@ snd_pmac_ctrl_intr(int irq, void *devid)
struct snd_pmac *chip = devid;
int ctrl = in_le32(&chip->awacs->control);
- /*printk(KERN_DEBUG "pmac: control interrupt.. 0x%x\n", ctrl);*/
if (ctrl & MASK_PORTCHG) {
/* do something when headphone is plugged/unplugged? */
if (chip->update_automute)
@@ -779,7 +773,7 @@ snd_pmac_ctrl_intr(int irq, void *devid)
if (ctrl & MASK_CNTLERR) {
int err = (in_le32(&chip->awacs->codec_stat) & MASK_ERRCODE) >> 16;
if (err && chip->model <= PMAC_SCREAMER)
- snd_printk(KERN_DEBUG "error %x\n", err);
+ dev_dbg(chip->card->dev, "%s: error %x\n", __func__, err);
}
/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
out_le32(&chip->awacs->control, ctrl);
@@ -964,9 +958,8 @@ static int snd_pmac_detect(struct snd_pmac *chip)
if (prop) {
/* partly deprecate snd-powermac, for those machines
* that have a layout-id property for now */
- printk(KERN_INFO "snd-powermac no longer handles any "
- "machines with a layout-id property "
- "in the device-tree, use snd-aoa.\n");
+ dev_info(chip->card->dev,
+ "snd-powermac no longer handles any machines with a layout-id property in the device-tree, use snd-aoa.\n");
of_node_put(sound);
of_node_put(chip->node);
chip->node = NULL;
@@ -1021,7 +1014,7 @@ static int snd_pmac_detect(struct snd_pmac *chip)
*/
macio = macio_find(chip->node, macio_unknown);
if (macio == NULL)
- printk(KERN_WARNING "snd-powermac: can't locate macio !\n");
+ dev_warn(chip->card->dev, "snd-powermac: can't locate macio !\n");
else {
struct pci_dev *pdev = NULL;
@@ -1034,8 +1027,8 @@ static int snd_pmac_detect(struct snd_pmac *chip)
}
}
if (chip->pdev == NULL)
- printk(KERN_WARNING "snd-powermac: can't locate macio PCI"
- " device !\n");
+ dev_warn(chip->card->dev,
+ "snd-powermac: can't locate macio PCI device !\n");
detect_byte_swap(chip);
@@ -1125,7 +1118,8 @@ int snd_pmac_add_automute(struct snd_pmac *chip)
chip->auto_mute = 1;
err = snd_ctl_add(chip->card, snd_ctl_new1(&auto_mute_controls[0], chip));
if (err < 0) {
- printk(KERN_ERR "snd-powermac: Failed to add automute control\n");
+ dev_err(chip->card->dev,
+ "snd-powermac: Failed to add automute control\n");
return err;
}
chip->hp_detect_ctl = snd_ctl_new1(&auto_mute_controls[1], chip);
@@ -1180,17 +1174,18 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
for (i = 0; i < 2; i ++) {
if (of_address_to_resource(np->parent, i,
&chip->rsrc[i])) {
- printk(KERN_ERR "snd: can't translate rsrc "
- " %d (%s)\n", i, rnames[i]);
+ dev_err(chip->card->dev,
+ "snd: can't translate rsrc %d (%s)\n",
+ i, rnames[i]);
err = -ENODEV;
goto __error;
}
if (request_mem_region(chip->rsrc[i].start,
resource_size(&chip->rsrc[i]),
rnames[i]) == NULL) {
- printk(KERN_ERR "snd: can't request rsrc "
- " %d (%s: %pR)\n",
- i, rnames[i], &chip->rsrc[i]);
+ dev_err(chip->card->dev,
+ "snd: can't request rsrc %d (%s: %pR)\n",
+ i, rnames[i], &chip->rsrc[i]);
err = -ENODEV;
goto __error;
}
@@ -1205,17 +1200,18 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
for (i = 0; i < 3; i ++) {
if (of_address_to_resource(np, i,
&chip->rsrc[i])) {
- printk(KERN_ERR "snd: can't translate rsrc "
- " %d (%s)\n", i, rnames[i]);
+ dev_err(chip->card->dev,
+ "snd: can't translate rsrc %d (%s)\n",
+ i, rnames[i]);
err = -ENODEV;
goto __error;
}
if (request_mem_region(chip->rsrc[i].start,
resource_size(&chip->rsrc[i]),
rnames[i]) == NULL) {
- printk(KERN_ERR "snd: can't request rsrc "
- " %d (%s: %pR)\n",
- i, rnames[i], &chip->rsrc[i]);
+ dev_err(chip->card->dev,
+ "snd: can't request rsrc %d (%s: %pR)\n",
+ i, rnames[i], &chip->rsrc[i]);
err = -ENODEV;
goto __error;
}
@@ -1233,8 +1229,8 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
irq = irq_of_parse_and_map(np, 0);
if (request_irq(irq, snd_pmac_ctrl_intr, 0,
"PMac", (void*)chip)) {
- snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n",
- irq);
+ dev_err(chip->card->dev,
+ "pmac: unable to grab IRQ %d\n", irq);
err = -EBUSY;
goto __error;
}
@@ -1242,14 +1238,14 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
}
irq = irq_of_parse_and_map(np, 1);
if (request_irq(irq, snd_pmac_tx_intr, 0, "PMac Output", (void*)chip)){
- snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", irq);
+ dev_err(chip->card->dev, "pmac: unable to grab IRQ %d\n", irq);
err = -EBUSY;
goto __error;
}
chip->tx_irq = irq;
irq = irq_of_parse_and_map(np, 2);
if (request_irq(irq, snd_pmac_rx_intr, 0, "PMac Input", (void*)chip)) {
- snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", irq);
+ dev_err(chip->card->dev, "pmac: unable to grab IRQ %d\n", irq);
err = -EBUSY;
goto __error;
}
@@ -1325,14 +1321,12 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
void snd_pmac_suspend(struct snd_pmac *chip)
{
- unsigned long flags;
-
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
if (chip->suspend)
chip->suspend(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_pmac_beep_stop(chip);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ scoped_guard(spinlock_irqsave, &chip->reg_lock) {
+ snd_pmac_beep_stop(chip);
+ }
if (chip->irq >= 0)
disable_irq(chip->irq);
if (chip->tx_irq >= 0)
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index e17af46abddd..e685d245883e 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -55,8 +55,8 @@ static int snd_pmac_probe(struct platform_device *devptr)
switch (chip->model) {
case PMAC_BURGUNDY:
- strcpy(card->driver, "PMac Burgundy");
- strcpy(card->shortname, "PowerMac Burgundy");
+ strscpy(card->driver, "PMac Burgundy");
+ strscpy(card->shortname, "PowerMac Burgundy");
sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
card->shortname, chip->device_id, chip->subframe);
err = snd_pmac_burgundy_init(chip);
@@ -64,8 +64,8 @@ static int snd_pmac_probe(struct platform_device *devptr)
goto __error;
break;
case PMAC_DACA:
- strcpy(card->driver, "PMac DACA");
- strcpy(card->shortname, "PowerMac DACA");
+ strscpy(card->driver, "PMac DACA");
+ strscpy(card->shortname, "PowerMac DACA");
sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
card->shortname, chip->device_id, chip->subframe);
err = snd_pmac_daca_init(chip);
@@ -104,7 +104,7 @@ static int snd_pmac_probe(struct platform_device *devptr)
goto __error;
break;
default:
- snd_printk(KERN_ERR "unsupported hardware %d\n", chip->model);
+ dev_err(&devptr->dev, "unsupported hardware %d\n", chip->model);
err = -EINVAL;
goto __error;
}
@@ -160,7 +160,7 @@ static SIMPLE_DEV_PM_OPS(snd_pmac_pm, snd_pmac_driver_suspend, snd_pmac_driver_r
static struct platform_driver snd_pmac_driver = {
.probe = snd_pmac_probe,
- .remove_new = snd_pmac_remove,
+ .remove = snd_pmac_remove,
.driver = {
.name = SND_PMAC_DRIVER,
.pm = SND_PMAC_PM_OPS,
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index a6cff2c46ac7..225b20f0b71a 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -221,7 +221,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
int fill_stages, dma_ch, stage;
enum snd_ps3_ch ch;
uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
- unsigned long irqsave;
int silent = 0;
switch (filltype) {
@@ -242,7 +241,7 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
snd_ps3_verify_dma_stop(card, 700, 0);
fill_stages = 4;
- spin_lock_irqsave(&card->dma_lock, irqsave);
+ guard(spinlock_irqsave)(&card->dma_lock);
for (ch = 0; ch < 2; ch++) {
for (stage = 0; stage < fill_stages; stage++) {
dma_ch = stage * 2 + ch;
@@ -289,7 +288,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
}
/* ensure the hardware sees the change */
wmb();
- spin_unlock_irqrestore(&card->dma_lock, irqsave);
return 0;
}
@@ -561,7 +559,6 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
- unsigned long irqsave;
if (!snd_ps3_set_avsetting(substream)) {
/* some parameter changed */
@@ -578,8 +575,7 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
}
/* restart ring buffer pointer */
- spin_lock_irqsave(&card->dma_lock, irqsave);
- {
+ scoped_guard(spinlock_irqsave, &card->dma_lock) {
card->dma_buffer_size = runtime->dma_bytes;
card->dma_last_transfer_vaddr[SND_PS3_CH_L] =
@@ -600,7 +596,6 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
card->dma_start_bus_addr[SND_PS3_CH_L]);
}
- spin_unlock_irqrestore(&card->dma_lock, irqsave);
/* ensure the hardware sees the change */
mb();
@@ -618,11 +613,9 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
/* clear outstanding interrupts */
update_reg(PS3_AUDIO_AX_IS, 0);
- spin_lock(&card->dma_lock);
- {
+ scoped_guard(spinlock, &card->dma_lock) {
card->running = 1;
}
- spin_unlock(&card->dma_lock);
snd_ps3_program_dma(card,
SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
@@ -636,11 +629,9 @@ static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_STOP:
- spin_lock(&card->dma_lock);
- {
+ scoped_guard(spinlock, &card->dma_lock) {
card->running = 0;
}
- spin_unlock(&card->dma_lock);
snd_ps3_wait_for_dma_stop(card);
break;
default:
@@ -661,12 +652,10 @@ static snd_pcm_uframes_t snd_ps3_pcm_pointer(
size_t bytes;
snd_pcm_uframes_t ret;
- spin_lock(&card->dma_lock);
- {
+ scoped_guard(spinlock, &card->dma_lock) {
bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
card->dma_start_vaddr[SND_PS3_CH_L]);
}
- spin_unlock(&card->dma_lock);
ret = bytes_to_frames(substream->runtime, bytes * 2);
@@ -951,9 +940,9 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
if (ret < 0)
goto clean_irq;
- strcpy(the_card.card->driver, "PS3");
- strcpy(the_card.card->shortname, "PS3");
- strcpy(the_card.card->longname, "PS3 sound");
+ strscpy(the_card.card->driver, "PS3");
+ strscpy(the_card.card->shortname, "PS3");
+ strscpy(the_card.card->longname, "PS3 sound");
/* create control elements */
for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) {
@@ -975,7 +964,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
goto clean_card;
the_card.pcm->private_data = &the_card;
- strcpy(the_card.pcm->name, "SPDIF");
+ strscpy(the_card.pcm->name, "SPDIF");
/* set pcm ops */
snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK,
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 12f1e10db1c4..3c09660e1522 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -29,7 +29,7 @@
#undef DEBUG
#ifdef DEBUG
-#define DBG(fmt...) printk(KERN_DEBUG fmt)
+#define DBG(fmt...) pr_debug(fmt)
#else
#define DBG(fmt...)
#endif
@@ -230,7 +230,7 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix)
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_VOL, 6,
block) < 0) {
- snd_printk(KERN_ERR "failed to set volume \n");
+ dev_err(&mix->i2c.client->dev, "failed to set volume\n");
return -EINVAL;
}
DBG("(I) succeeded to set volume (%u, %u)\n", left_vol, right_vol);
@@ -341,7 +341,7 @@ static int tumbler_set_drc(struct pmac_tumbler *mix)
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_DRC,
2, val) < 0) {
- snd_printk(KERN_ERR "failed to set DRC\n");
+ dev_err(&mix->i2c.client->dev, "failed to set DRC\n");
return -EINVAL;
}
DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
@@ -378,7 +378,7 @@ static int snapper_set_drc(struct pmac_tumbler *mix)
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, TAS_REG_DRC,
6, val) < 0) {
- snd_printk(KERN_ERR "failed to set DRC\n");
+ dev_err(&mix->i2c.client->dev, "failed to set DRC\n");
return -EINVAL;
}
DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
@@ -503,8 +503,8 @@ static int tumbler_set_mono_volume(struct pmac_tumbler *mix,
block[i] = (vol >> ((info->bytes - i - 1) * 8)) & 0xff;
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, info->reg,
info->bytes, block) < 0) {
- snd_printk(KERN_ERR "failed to set mono volume %d\n",
- info->index);
+ dev_err(&mix->i2c.client->dev, "failed to set mono volume %d\n",
+ info->index);
return -EINVAL;
}
return 0;
@@ -643,7 +643,8 @@ static int snapper_set_mix_vol1(struct pmac_tumbler *mix, int idx, int ch, int r
}
if (i2c_smbus_write_i2c_block_data(mix->i2c.client, reg,
9, block) < 0) {
- snd_printk(KERN_ERR "failed to set mono volume %d\n", reg);
+ dev_err(&mix->i2c.client->dev,
+ "failed to set mono volume %d\n", reg);
return -EINVAL;
}
return 0;
@@ -1102,7 +1103,6 @@ static long tumbler_find_device(const char *device, const char *platform,
node = find_audio_device(device);
if (! node) {
DBG("(W) cannot find audio device %s !\n", device);
- snd_printdd("cannot find device %s\n", device);
return -ENODEV;
}
@@ -1111,7 +1111,6 @@ static long tumbler_find_device(const char *device, const char *platform,
base = of_get_property(node, "reg", NULL);
if (!base) {
DBG("(E) cannot find address for device %s !\n", device);
- snd_printd("cannot find address for device %s\n", device);
of_node_put(node);
return -ENODEV;
}
@@ -1232,9 +1231,9 @@ static void tumbler_resume(struct snd_pmac *chip)
tumbler_reset_audio(chip);
if (mix->i2c.client && mix->i2c.init_client) {
if (mix->i2c.init_client(&mix->i2c) < 0)
- printk(KERN_ERR "tumbler_init_client error\n");
+ dev_err(chip->card->dev, "tumbler_init_client error\n");
} else
- printk(KERN_ERR "tumbler: i2c is not initialized\n");
+ dev_err(chip->card->dev, "tumbler: i2c is not initialized\n");
if (chip->model == PMAC_TUMBLER) {
tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info);
tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig
index b75fbb3236a7..f5fa09d740b4 100644
--- a/sound/sh/Kconfig
+++ b/sound/sh/Kconfig
@@ -14,7 +14,7 @@ if SND_SUPERH
config SND_AICA
tristate "Dreamcast Yamaha AICA sound"
- depends on SH_DREAMCAST
+ depends on SH_DREAMCAST && SH_DMA_API
select SND_PCM
select G2_DMA
help
diff --git a/sound/sh/Makefile b/sound/sh/Makefile
index c0bbc500c17c..6871dece28a5 100644
--- a/sound/sh/Makefile
+++ b/sound/sh/Makefile
@@ -3,8 +3,8 @@
# Makefile for ALSA
#
-snd-aica-objs := aica.o
-snd-sh_dac_audio-objs := sh_dac_audio.o
+snd-aica-y := aica.o
+snd-sh_dac_audio-y := sh_dac_audio.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AICA) += snd-aica.o
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 320ac792c7fe..fa81bfba59c1 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -75,8 +75,7 @@ static void spu_write_wait(void)
/* To ensure hardware failure doesn't wedge kernel */
time_count++;
if (time_count > 0x10000) {
- snd_printk
- ("WARNING: G2 FIFO appears to be blocked.\n");
+ pr_warn("WARNING: G2 FIFO appears to be blocked.\n");
break;
}
}
@@ -278,18 +277,21 @@ static void run_spu_dma(struct work_struct *work)
dreamcastcard->clicks++;
if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
- mod_timer(&dreamcastcard->timer, jiffies + 1);
+ if (snd_pcm_running(dreamcastcard->substream))
+ mod_timer(&dreamcastcard->timer, jiffies + 1);
}
}
static void aica_period_elapsed(struct timer_list *t)
{
- struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard,
- t, timer);
+ struct snd_card_aica *dreamcastcard = timer_container_of(dreamcastcard,
+ t, timer);
struct snd_pcm_substream *substream = dreamcastcard->substream;
/*timer function - so cannot sleep */
int play_period;
struct snd_pcm_runtime *runtime;
+ if (!snd_pcm_running(substream))
+ return;
runtime = substream->runtime;
dreamcastcard = substream->pcm->private_data;
/* Have we played out an additional period? */
@@ -313,8 +315,6 @@ static void aica_period_elapsed(struct timer_list *t)
static void spu_begin_dma(struct snd_pcm_substream *substream)
{
struct snd_card_aica *dreamcastcard;
- struct snd_pcm_runtime *runtime;
- runtime = substream->runtime;
dreamcastcard = substream->pcm->private_data;
/*get the queue to do the work */
schedule_work(&(dreamcastcard->spu_dma_work));
@@ -350,12 +350,19 @@ static int snd_aicapcm_pcm_open(struct snd_pcm_substream
return 0;
}
+static int snd_aicapcm_pcm_sync_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+
+ timer_delete_sync(&dreamcastcard->timer);
+ cancel_work_sync(&dreamcastcard->spu_dma_work);
+ return 0;
+}
+
static int snd_aicapcm_pcm_close(struct snd_pcm_substream
*substream)
{
struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
- flush_work(&(dreamcastcard->spu_dma_work));
- del_timer(&dreamcastcard->timer);
dreamcastcard->substream = NULL;
kfree(dreamcastcard->channel);
spu_disable();
@@ -401,6 +408,7 @@ static const struct snd_pcm_ops snd_aicapcm_playback_ops = {
.prepare = snd_aicapcm_pcm_prepare,
.trigger = snd_aicapcm_pcm_trigger,
.pointer = snd_aicapcm_pcm_pointer,
+ .sync_stop = snd_aicapcm_pcm_sync_stop,
};
/* TO DO: set up to handle more than one pcm instance */
@@ -416,7 +424,7 @@ static int __init snd_aicapcmchip(struct snd_card_aica
if (unlikely(err < 0))
return err;
pcm->private_data = dreamcastcard;
- strcpy(pcm->name, "AICA PCM");
+ strscpy(pcm->name, "AICA PCM");
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_aicapcm_playback_ops);
/* Allocate the DMA buffers */
@@ -461,8 +469,8 @@ static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_card_aica *dreamcastcard;
- dreamcastcard = kcontrol->private_data;
+ struct snd_card_aica *dreamcastcard = snd_kcontrol_chip(kcontrol);
+
if (unlikely(!dreamcastcard->channel))
return -ETXTBSY; /* we've not yet been set up */
ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
@@ -472,9 +480,9 @@ static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_card_aica *dreamcastcard;
+ struct snd_card_aica *dreamcastcard = snd_kcontrol_chip(kcontrol);
unsigned int vol;
- dreamcastcard = kcontrol->private_data;
+
if (unlikely(!dreamcastcard->channel))
return -ETXTBSY;
vol = ucontrol->value.integer.value[0];
@@ -560,9 +568,9 @@ static int snd_aica_probe(struct platform_device *devptr)
kfree(dreamcastcard);
return err;
}
- strcpy(dreamcastcard->card->driver, "snd_aica");
- strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
- strcpy(dreamcastcard->card->longname,
+ strscpy(dreamcastcard->card->driver, "snd_aica");
+ strscpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
+ strscpy(dreamcastcard->card->longname,
"Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
/* Prepare to use the queue */
INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
@@ -580,8 +588,8 @@ static int snd_aica_probe(struct platform_device *devptr)
if (unlikely(err < 0))
goto freedreamcast;
platform_set_drvdata(devptr, dreamcastcard);
- snd_printk
- ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
+ dev_info(&devptr->dev,
+ "ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
return 0;
freedreamcast:
snd_card_free(dreamcastcard->card);
@@ -591,7 +599,7 @@ static int snd_aica_probe(struct platform_device *devptr)
static struct platform_driver snd_aica_driver = {
.probe = snd_aica_probe,
- .remove_new = snd_aica_remove,
+ .remove = snd_aica_remove,
.driver = {
.name = SND_AICA_DRIVER,
},
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index 8cf571955c9d..164f91240d02 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -158,12 +158,12 @@ static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *src, unsigned long count)
+ struct iov_iter *src, unsigned long count)
{
/* channel is not used (interleaved data) */
struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
- if (copy_from_user_toio(chip->data_buffer + pos, src, count))
+ if (copy_from_iter(chip->data_buffer + pos, count, src) != count)
return -EFAULT;
chip->buffer_end = chip->data_buffer + pos + count;
@@ -175,24 +175,6 @@ static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream,
return 0;
}
-static int snd_sh_dac_pcm_copy_kernel(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void *src, unsigned long count)
-{
- /* channel is not used (interleaved data) */
- struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
-
- memcpy_toio(chip->data_buffer + pos, src, count);
- chip->buffer_end = chip->data_buffer + pos + count;
-
- if (chip->empty) {
- chip->empty = 0;
- dac_audio_start_timer(chip);
- }
-
- return 0;
-}
-
static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
unsigned long count)
@@ -200,7 +182,7 @@ static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream,
/* channel is not used (interleaved data) */
struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
- memset_io(chip->data_buffer + pos, 0, count);
+ memset(chip->data_buffer + pos, 0, count);
chip->buffer_end = chip->data_buffer + pos + count;
if (chip->empty) {
@@ -227,10 +209,8 @@ static const struct snd_pcm_ops snd_sh_dac_pcm_ops = {
.prepare = snd_sh_dac_pcm_prepare,
.trigger = snd_sh_dac_pcm_trigger,
.pointer = snd_sh_dac_pcm_pointer,
- .copy_user = snd_sh_dac_pcm_copy,
- .copy_kernel = snd_sh_dac_pcm_copy_kernel,
+ .copy = snd_sh_dac_pcm_copy,
.fill_silence = snd_sh_dac_pcm_silence,
- .mmap = snd_pcm_lib_mmap_iomem,
};
static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
@@ -244,7 +224,7 @@ static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, "SH_DAC PCM");
+ strscpy(pcm->name, "SH_DAC PCM");
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops);
/* buffer size=48K */
@@ -332,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;
@@ -367,8 +346,8 @@ static int snd_sh_dac_probe(struct platform_device *devptr)
err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "cannot allocate the card\n");
- return err;
+ dev_err(&devptr->dev, "cannot allocate the card\n");
+ return err;
}
err = snd_sh_dac_create(card, devptr, &chip);
@@ -379,15 +358,15 @@ static int snd_sh_dac_probe(struct platform_device *devptr)
if (err < 0)
goto probe_error;
- strcpy(card->driver, "snd_sh_dac");
- strcpy(card->shortname, "SuperH DAC audio driver");
- printk(KERN_INFO "%s %s", card->longname, card->shortname);
+ strscpy(card->driver, "snd_sh_dac");
+ strscpy(card->shortname, "SuperH DAC audio driver");
+ dev_info(&devptr->dev, "%s %s\n", card->longname, card->shortname);
err = snd_card_register(card);
if (err < 0)
goto probe_error;
- snd_printk(KERN_INFO "ALSA driver for SuperH DAC audio");
+ dev_info(&devptr->dev, "ALSA driver for SuperH DAC audio\n");
platform_set_drvdata(devptr, card);
return 0;
@@ -402,7 +381,7 @@ probe_error:
*/
static struct platform_driver sh_dac_driver = {
.probe = snd_sh_dac_probe,
- .remove_new = snd_sh_dac_remove,
+ .remove = snd_sh_dac_remove,
.driver = {
.name = "dac_audio",
},
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index bfa9622e1ab1..36e0d443ba0e 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -38,6 +38,17 @@ config SND_SOC_TOPOLOGY
bool
select SND_DYNAMIC_MINORS
+config SND_SOC_TOPOLOGY_BUILD
+ bool "Build topology core"
+ select SND_SOC_TOPOLOGY
+ depends on KUNIT
+ help
+ This option exists to facilitate running the KUnit tests for
+ the topology core, KUnit is frequently tested in virtual
+ environments with minimal drivers enabled but the topology
+ core is usually selected by drivers. There is little reason
+ to enable it if not doing a KUnit build.
+
config SND_SOC_TOPOLOGY_KUNIT_TEST
tristate "KUnit tests for SoC topology"
depends on KUNIT
@@ -55,6 +66,14 @@ config SND_SOC_TOPOLOGY_KUNIT_TEST
userspace applications such as pulseaudio, to prevent unnecessary
problems.
+config SND_SOC_CARD_KUNIT_TEST
+ tristate "KUnit tests for SoC card"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ If you want to perform tests on ALSA SoC card functions say Y here.
+ If unsure, say N.
+
config SND_SOC_UTILS_KUNIT_TEST
tristate "KUnit tests for SoC utils"
depends on KUNIT
@@ -62,9 +81,26 @@ 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
+config SND_SOC_USB
+ tristate "SoC based USB audio offloading"
+ depends on SND_USB_AUDIO
+ help
+ Enable this option if an ASoC platform card has support to handle
+ USB audio offloading. This enables the SoC USB layer, which will
+ notify the ASoC USB DPCM backend DAI link about available USB audio
+ devices. Based on the notifications, sequences to enable the audio
+ stream can be taken based on the design.
+
# All the supported SoCs
source "sound/soc/adi/Kconfig"
source "sound/soc/amd/Kconfig"
@@ -87,10 +123,11 @@ source "sound/soc/meson/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
+source "sound/soc/renesas/Kconfig"
source "sound/soc/rockchip/Kconfig"
source "sound/soc/samsung/Kconfig"
-source "sound/soc/sh/Kconfig"
-source "sound/soc/sof/Kconfig"
+source "sound/soc/sdca/Kconfig"
+source "sound/soc/spacemit/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/sprd/Kconfig"
source "sound/soc/starfive/Kconfig"
@@ -104,9 +141,14 @@ source "sound/soc/ux500/Kconfig"
source "sound/soc/xilinx/Kconfig"
source "sound/soc/xtensa/Kconfig"
+# SOF
+source "sound/soc/sof/Kconfig"
+
# Supported codecs
source "sound/soc/codecs/Kconfig"
+source "sound/soc/sdw_utils/Kconfig"
+
# generic frame-work
source "sound/soc/generic/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 8376fdb217ed..8c0480e6484e 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,36 +1,46 @@
# SPDX-License-Identifier: GPL-2.0
-snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o soc-component.o
-snd-soc-core-objs += soc-pcm.o soc-devres.o soc-ops.o soc-link.o soc-card.o
+snd-soc-core-y := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o soc-component.o
+snd-soc-core-y += soc-pcm.o soc-devres.o soc-ops.o soc-link.o soc-card.o
snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o
ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
-snd-soc-core-objs += soc-topology.o
+snd-soc-core-y += soc-topology.o
endif
ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
-# snd-soc-test-objs := soc-topology-test.o
+# snd-soc-test-y := soc-topology-test.o
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) += soc-topology-test.o
endif
+ifneq ($(CONFIG_SND_SOC_CARD_KUNIT_TEST),)
+obj-$(CONFIG_SND_SOC_CARD_KUNIT_TEST) += soc-card-test.o
+endif
+
ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
-# snd-soc-test-objs := soc-utils-test.o
+# snd-soc-test-y := soc-utils-test.o
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-objs += soc-generic-dmaengine-pcm.o
+snd-soc-core-y += soc-generic-dmaengine-pcm.o
endif
ifneq ($(CONFIG_SND_SOC_AC97_BUS),)
-snd-soc-core-objs += soc-ac97.o
+snd-soc-core-y += soc-ac97.o
endif
ifneq ($(CONFIG_SND_SOC_ACPI),)
-snd-soc-acpi-objs := soc-acpi.o
+snd-soc-acpi-y := soc-acpi.o
endif
obj-$(CONFIG_SND_SOC_ACPI) += snd-soc-acpi.o
+obj-$(CONFIG_SND_SOC_USB) += soc-usb.o
+
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
@@ -55,10 +65,12 @@ obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
+obj-$(CONFIG_SND_SOC) += renesas/
obj-$(CONFIG_SND_SOC) += rockchip/
obj-$(CONFIG_SND_SOC) += samsung/
-obj-$(CONFIG_SND_SOC) += sh/
+obj-$(CONFIG_SND_SOC) += sdca/
obj-$(CONFIG_SND_SOC) += sof/
+obj-$(CONFIG_SND_SOC) += spacemit/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += sprd/
obj-$(CONFIG_SND_SOC) += starfive/
@@ -71,3 +83,4 @@ obj-$(CONFIG_SND_SOC) += uniphier/
obj-$(CONFIG_SND_SOC) += ux500/
obj-$(CONFIG_SND_SOC) += xilinx/
obj-$(CONFIG_SND_SOC) += xtensa/
+obj-$(CONFIG_SND_SOC) += sdw_utils/
diff --git a/sound/soc/adi/Kconfig b/sound/soc/adi/Kconfig
index 0236dc5b4e9f..d47dffbf40d0 100644
--- a/sound/soc/adi/Kconfig
+++ b/sound/soc/adi/Kconfig
@@ -1,12 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
-config SND_SOC_ADI
- tristate "Audio support for Analog Devices reference designs"
- help
- Audio support for various reference designs by Analog Devices.
+menu "Analog Devices"
config SND_SOC_ADI_AXI_I2S
tristate "AXI-I2S support"
- depends on SND_SOC_ADI
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
@@ -14,8 +10,9 @@ config SND_SOC_ADI_AXI_I2S
config SND_SOC_ADI_AXI_SPDIF
tristate "AXI-SPDIF support"
- depends on SND_SOC_ADI
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
ASoC driver for the Analog Devices AXI-SPDIF softcore peripheral.
+
+endmenu
diff --git a/sound/soc/adi/Makefile b/sound/soc/adi/Makefile
index 125f667b0e08..0d2db8d05806 100644
--- a/sound/soc/adi/Makefile
+++ b/sound/soc/adi/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-adi-axi-i2s-objs := axi-i2s.o
-snd-soc-adi-axi-spdif-objs := axi-spdif.o
+snd-soc-adi-axi-i2s-y := axi-i2s.o
+snd-soc-adi-axi-spdif-y := axi-spdif.o
obj-$(CONFIG_SND_SOC_ADI_AXI_I2S) += snd-soc-adi-axi-i2s.o
obj-$(CONFIG_SND_SOC_ADI_AXI_SPDIF) += snd-soc-adi-axi-spdif.o
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c
index d5b6f5187f8e..41f89384f8fd 100644
--- a/sound/soc/adi/axi-i2s.c
+++ b/sound/soc/adi/axi-i2s.c
@@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
+ .probe = axi_i2s_dai_probe,
.startup = axi_i2s_startup,
.shutdown = axi_i2s_shutdown,
.trigger = axi_i2s_trigger,
@@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
};
static struct snd_soc_dai_driver axi_i2s_dai = {
- .probe = axi_i2s_dai_probe,
.ops = &axi_i2s_dai_ops,
.symmetric_rate = 1,
};
@@ -264,8 +264,8 @@ static int axi_i2s_probe(struct platform_device *pdev)
goto err_clk_disable;
dev_info(&pdev->dev, "probed, capture %s, playback %s\n",
- i2s->has_capture ? "enabled" : "disabled",
- i2s->has_playback ? "enabled" : "disabled");
+ str_enabled_disabled(i2s->has_capture),
+ str_enabled_disabled(i2s->has_playback));
return 0;
@@ -293,7 +293,7 @@ static struct platform_driver axi_i2s_driver = {
.of_match_table = axi_i2s_of_match,
},
.probe = axi_i2s_probe,
- .remove_new = axi_i2s_dev_remove,
+ .remove = axi_i2s_dev_remove,
};
module_platform_driver(axi_i2s_driver);
diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c
index e4c99bbc9cdd..5581134201a3 100644
--- a/sound/soc/adi/axi-spdif.c
+++ b/sound/soc/adi/axi-spdif.c
@@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
+ .probe = axi_spdif_dai_probe,
.startup = axi_spdif_startup,
.shutdown = axi_spdif_shutdown,
.trigger = axi_spdif_trigger,
@@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
};
static struct snd_soc_dai_driver axi_spdif_dai = {
- .probe = axi_spdif_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -258,7 +258,7 @@ static struct platform_driver axi_spdif_driver = {
.of_match_table = axi_spdif_of_match,
},
.probe = axi_spdif_probe,
- .remove_new = axi_spdif_dev_remove,
+ .remove = axi_spdif_dev_remove,
};
module_platform_driver(axi_spdif_driver);
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 57d5e342a8eb..fd35a03aadcb 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "AMD"
+
config SND_SOC_AMD_ACP
tristate "AMD Audio Coprocessor support"
help
@@ -79,14 +81,15 @@ config SND_SOC_AMD_ACP5x
ACP DMA driver, CPU DAI driver.
config SND_SOC_AMD_VANGOGH_MACH
- tristate "AMD Vangogh support for NAU8821 CS35L41"
+ tristate "AMD Vangogh support for NAU8821/CS35L41/MAX98388"
select SND_SOC_NAU8821
select SND_SOC_CS35L41_SPI
+ select SND_SOC_MAX98388
select SND_AMD_ACP_CONFIG
depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER
help
This option enables machine driver for Vangogh platform
- using NAU8821 and CS35L41 codecs.
+ using NAU8821 and either CS35L41 or MAX98388 codecs.
Say m if you have such a device.
If unsure select "N".
@@ -104,7 +107,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.
@@ -131,14 +134,44 @@ config SND_SOC_AMD_RPL_ACP6x
Say m if you have such a device.
If unsure select "N".
+config SND_SOC_AMD_ACP63_TOPLEVEL
+ tristate "support for AMD platforms with ACP version >= 6.3"
+ default SND_AMD_ACP_CONFIG
+ depends on SND_AMD_ACP_CONFIG
+ depends on SOUNDWIRE_AMD || !SOUNDWIRE_AMD
+ depends on X86 || COMPILE_TEST
+ help
+ This adds support for AMD platforms with ACP version >= 6.3.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+if SND_SOC_AMD_ACP63_TOPLEVEL
+
+config SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
+ tristate
+ select SND_AMD_SOUNDWIRE_ACPI if ACPI
+
+config SND_SOC_AMD_SOUNDWIRE
+ tristate "Support for SoundWire based AMD platforms"
+ default SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
+ depends on SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
+ depends on ACPI
+ depends on SOUNDWIRE_AMD
+ help
+ This adds support for SoundWire for AMD platforms.
+ Say Y if you want to enable SoundWire links with SOF.
+ If unsure select "N".
+
config SND_SOC_AMD_PS
- tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support"
- select SND_AMD_ACP_CONFIG
+ 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.
+ 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".
@@ -152,3 +185,6 @@ config SND_SOC_AMD_PS_MACH
DMIC can be connected directly to ACP IP.
Say m if you have such a device.
If unsure select "N".
+
+endif
+endmenu
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 82e1cf864a40..4f89d962cce2 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
-acp_audio_dma-objs := acp-pcm-dma.o
-snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
-snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
-snd-soc-acp-es8336-mach-objs := acp-es8336.o
-snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o
-snd-acp-config-objs := acp-config.o
+acp_audio_dma-y := acp-pcm-dma.o
+snd-soc-acp-da7219mx98357-mach-y := acp-da7219-max98357a.o
+snd-soc-acp-rt5645-mach-y := acp-rt5645.o
+snd-soc-acp-es8336-mach-y := acp-es8336.o
+snd-soc-acp-rt5682-mach-y := acp3x-rt5682-max9836.o
+snd-acp-config-y := acp-config.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
@@ -15,7 +15,7 @@ obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/
obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
-obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
+obj-$(CONFIG_SND_AMD_ACP_CONFIG) += acp/
obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/
obj-$(CONFIG_SND_SOC_AMD_PS) += ps/
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
index 0932473b6394..365209ea53f3 100644
--- a/sound/soc/amd/acp-config.c
+++ b/sound/soc/amd/acp-config.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
//
@@ -19,6 +19,8 @@
#include "../sof/amd/acp.h"
#include "mach-config.h"
+#define ACP_7_0_REV 0x70
+
static int acp_quirk_data;
static const struct config_entry config_table[] = {
@@ -47,17 +49,145 @@ static const struct config_entry config_table[] = {
{}
},
},
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_SOF,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1020"),
+ },
+ },
+ {}
+ },
+ },
+ {
+ .flags = FLAG_AMD_LEGACY,
+ .device = ACP_PCI_DEV_ID,
+ .dmi_table = (const struct dmi_system_id []) {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"),
+ },
+ },
+ {}
+ },
+ },
};
+static int snd_amd_acp_acpi_find_config(struct pci_dev *pci)
+{
+ const union acpi_object *obj;
+ int acp_flag = FLAG_AMD_LEGACY_ONLY_DMIC;
+
+ if (!acpi_dev_get_property(ACPI_COMPANION(&pci->dev), "acp-audio-config-flag",
+ ACPI_TYPE_INTEGER, &obj))
+ acp_flag = obj->integer.value;
+
+ return acp_flag;
+}
+
int snd_amd_acp_find_config(struct pci_dev *pci)
{
const struct config_entry *table = config_table;
u16 device = pci->device;
int i;
- /* Do not enable FLAGS on older platforms with Rev id zero */
+ /* Do not enable FLAGS on older platforms with Rev Id zero
+ * For platforms which has ACP 7.0 or higher, read the acp
+ * config flag from BIOS ACPI table and for older platforms
+ * read it from DMI tables.
+ */
if (!pci->revision)
return 0;
+ else if (pci->revision >= ACP_7_0_REV)
+ return snd_amd_acp_acpi_find_config(pci);
for (i = 0; i < ARRAY_SIZE(config_table); i++, table++) {
if (table->device != device)
@@ -82,6 +212,11 @@ static struct snd_soc_acpi_codecs amp_max = {
.codecs = {"MX98360A"}
};
+static struct snd_soc_acpi_codecs amp_max98388 = {
+ .num_codecs = 1,
+ .codecs = {"ADS8388"}
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = {
{
.id = "10EC5682",
@@ -130,6 +265,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = {
};
EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines);
+struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[] = {
+ {
+ .id = "NVTN2020",
+ .drv_name = "nau8821-max",
+ .pdata = &acp_quirk_data,
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_max98388,
+ .fw_filename = "sof-vangogh.ri",
+ .sof_tplg_filename = "sof-vangogh-nau8821-max.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_vangogh_sof_machines);
+
struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = {
{
.id = "AMDI1019",
@@ -160,4 +309,29 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = {
};
EXPORT_SYMBOL(snd_soc_acpi_amd_rmb_sof_machines);
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[] = {
+ {
+ .id = "AMDI1019",
+ .drv_name = "acp63-dsp",
+ .pdata = &acp_quirk_data,
+ .fw_filename = "sof-acp_6_3.ri",
+ .sof_tplg_filename = "sof-acp_6_3.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_machines);
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = {
+ {
+ .id = "AMDI1010",
+ .drv_name = "acp70-dsp",
+ .pdata = &acp_quirk_data,
+ .fw_filename = "sof-acp_7_0.ri",
+ .sof_tplg_filename = "sof-acp_7_0.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines);
+
+MODULE_DESCRIPTION("AMD ACP Machine Configuration Module");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index 7464ca2b596c..42aa009c4e13 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -28,6 +28,21 @@
#define RT5682_PLL_FREQ (48000 * 512)
static struct snd_soc_jack cz_jack;
+static struct snd_soc_jack_pin cz_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
static struct clk *da7219_dai_wclk;
static struct clk *da7219_dai_bclk;
static struct clk *rt5682_dai_wclk;
@@ -39,7 +54,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
@@ -66,11 +81,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
if (IS_ERR(da7219_dai_bclk))
return PTR_ERR(da7219_dai_bclk);
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack,
+ cz_jack_pins,
+ ARRAY_SIZE(cz_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -89,7 +106,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
static int da7219_clk_enable(struct snd_pcm_substream *substream)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
/*
* Set wclk to 48000 because the rate constraint of this driver is
@@ -117,7 +134,7 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
dev_info(codec_dai->dev, "codec dai name = %s\n", codec_dai->name);
@@ -146,11 +163,13 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
if (IS_ERR(rt5682_dai_bclk))
return PTR_ERR(rt5682_dai_bclk);
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack,
+ cz_jack_pins,
+ ARRAY_SIZE(cz_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -172,7 +191,7 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
static int rt5682_clk_enable(struct snd_pcm_substream *substream)
{
int ret;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
/*
* Set wclk to 48000 because the rate constraint of this driver is
@@ -226,7 +245,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -247,7 +266,7 @@ static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -269,7 +288,7 @@ static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
static int cz_max_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -290,7 +309,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream)
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -311,7 +330,7 @@ static int cz_dmic0_startup(struct snd_pcm_substream *substream)
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -338,7 +357,7 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
static int cz_rt5682_play_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -359,7 +378,7 @@ static int cz_rt5682_play_startup(struct snd_pcm_substream *substream)
static int cz_rt5682_cap_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -381,7 +400,7 @@ static int cz_rt5682_cap_startup(struct snd_pcm_substream *substream)
static int cz_rt5682_max_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -402,7 +421,7 @@ static int cz_rt5682_max_startup(struct snd_pcm_substream *substream)
static int cz_rt5682_dmic0_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -423,7 +442,7 @@ static int cz_rt5682_dmic0_startup(struct snd_pcm_substream *substream)
static int cz_rt5682_dmic1_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -498,11 +517,11 @@ static const struct snd_soc_ops cz_rt5682_dmic1_cap_ops = {
};
SND_SOC_DAILINK_DEF(designware1,
- DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto")));
+ DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1")));
SND_SOC_DAILINK_DEF(designware2,
- DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto")));
+ DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2")));
SND_SOC_DAILINK_DEF(designware3,
- DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.3.auto")));
+ DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.3")));
SND_SOC_DAILINK_DEF(dlgs,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", "da7219-hifi")));
@@ -514,7 +533,7 @@ SND_SOC_DAILINK_DEF(adau,
DAILINK_COMP_ARRAY(COMP_CODEC("ADAU7002:00", "adau7002-hifi")));
SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0.auto")));
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0")));
static struct snd_soc_dai_link cz_dai_7219_98357[] = {
{
@@ -523,7 +542,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
.init = cz_da7219_init,
- .dpcm_playback = 1,
+ .playback_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_da7219_play_ops,
SND_SOC_DAILINK_REG(designware1, dlgs, platform),
@@ -533,7 +552,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.stream_name = "Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_da7219_cap_ops,
SND_SOC_DAILINK_REG(designware2, dlgs, platform),
@@ -543,7 +562,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_playback = 1,
+ .playback_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_max_play_ops,
SND_SOC_DAILINK_REG(designware3, mx, platform),
@@ -554,7 +573,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.stream_name = "DMIC0 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_dmic0_cap_ops,
SND_SOC_DAILINK_REG(designware3, adau, platform),
@@ -565,7 +584,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.stream_name = "DMIC1 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_dmic1_cap_ops,
SND_SOC_DAILINK_REG(designware2, adau, platform),
@@ -579,7 +598,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
.init = cz_rt5682_init,
- .dpcm_playback = 1,
+ .playback_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_rt5682_play_ops,
SND_SOC_DAILINK_REG(designware1, rt5682, platform),
@@ -589,7 +608,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.stream_name = "Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_rt5682_cap_ops,
SND_SOC_DAILINK_REG(designware2, rt5682, platform),
@@ -599,7 +618,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_playback = 1,
+ .playback_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_rt5682_max_play_ops,
SND_SOC_DAILINK_REG(designware3, mx, platform),
@@ -610,7 +629,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.stream_name = "DMIC0 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_rt5682_dmic0_cap_ops,
SND_SOC_DAILINK_REG(designware3, adau, platform),
@@ -621,7 +640,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.stream_name = "DMIC1 Capture",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
.ops = &cz_rt5682_dmic1_cap_ops,
SND_SOC_DAILINK_REG(designware2, adau, platform),
@@ -631,6 +650,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
static const struct snd_soc_dapm_widget cz_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
};
@@ -654,6 +674,7 @@ static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = {
static const struct snd_kcontrol_new cz_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
};
@@ -712,7 +733,7 @@ static struct regulator_config acp_da7219_cfg = {
.init_data = &acp_da7219_data,
};
-static struct regulator_ops acp_da7219_ops = {
+static const struct regulator_ops acp_da7219_ops = {
};
static const struct regulator_desc acp_da7219_desc = {
diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c
index 5e56d3a53be7..b16dde0e2987 100644
--- a/sound/soc/amd/acp-es8336.c
+++ b/sound/soc/amd/acp-es8336.c
@@ -62,7 +62,7 @@ static int st_es8336_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_card *card;
struct snd_soc_component *codec;
- codec = asoc_rtd_to_codec(rtd, 0)->component;
+ codec = snd_soc_rtd_to_codec(rtd, 0)->component;
card = rtd->card;
ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
@@ -111,10 +111,10 @@ static int st_es8336_codec_startup(struct snd_pcm_substream *substream)
int ret;
runtime = substream->runtime;
- rtd = asoc_substream_to_rtd(substream);
+ rtd = snd_soc_substream_to_rtd(substream);
card = rtd->card;
machine = snd_soc_card_get_drvdata(card);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
ret = snd_soc_dai_set_sysclk(codec_dai, 0, ES8336_PLL_FREQ, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
@@ -137,11 +137,11 @@ static const struct snd_soc_ops st_es8336_ops = {
};
SND_SOC_DAILINK_DEF(designware1,
- DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto")));
+ DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1")));
SND_SOC_DAILINK_DEF(codec,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.1.auto")));
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0")));
static struct snd_soc_dai_link st_dai_es8336[] = {
{
@@ -150,8 +150,6 @@ static struct snd_soc_dai_link st_dai_es8336[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
.trigger_stop = SND_SOC_TRIGGER_ORDER_LDC,
- .dpcm_capture = 1,
- .dpcm_playback = 1,
.init = st_es8336_init,
.ops = &st_es8336_ops,
SND_SOC_DAILINK_REG(designware1, codec, platform),
@@ -203,8 +201,10 @@ static int st_es8336_late_probe(struct snd_soc_card *card)
codec_dev = acpi_get_first_physical_node(adev);
acpi_dev_put(adev);
- if (!codec_dev)
+ if (!codec_dev) {
dev_err(card->dev, "can not find codec dev\n");
+ return -ENODEV;
+ }
ret = devm_acpi_dev_add_driver_gpios(codec_dev, acpi_es8336_gpios);
if (ret)
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index d41df316da58..897dde630022 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -849,7 +849,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
u32 val = 0;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
- struct snd_soc_pcm_runtime *prtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *prtd = snd_soc_substream_to_rtd(substream);
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
struct snd_soc_card *card = prtd->card;
struct acp_platform_info *pinfo = snd_soc_card_get_drvdata(card);
@@ -1426,7 +1426,7 @@ static const struct dev_pm_ops acp_pm_ops = {
static struct platform_driver acp_dma_driver = {
.probe = acp_audio_probe,
- .remove_new = acp_audio_remove,
+ .remove = acp_audio_remove,
.driver = {
.name = DRV_NAME,
.pm = &acp_pm_ops,
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
index 532aa98a2241..11d373169380 100644
--- a/sound/soc/amd/acp-rt5645.c
+++ b/sound/soc/amd/acp-rt5645.c
@@ -42,13 +42,23 @@
#define CZ_PLAT_CLK 24000000
static struct snd_soc_jack cz_jack;
+static struct snd_soc_jack_pin cz_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
CZ_PLAT_CLK, params_rate(params) * 512);
@@ -73,14 +83,16 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_card *card;
struct snd_soc_component *codec;
- codec = asoc_rtd_to_codec(rtd, 0)->component;
+ codec = snd_soc_rtd_to_codec(rtd, 0)->component;
card = rtd->card;
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack,
+ cz_jack_pins,
+ ARRAY_SIZE(cz_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -96,15 +108,15 @@ static const struct snd_soc_ops cz_aif1_ops = {
};
SND_SOC_DAILINK_DEF(designware1,
- DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto")));
+ DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1")));
SND_SOC_DAILINK_DEF(designware2,
- DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto")));
+ DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2")));
SND_SOC_DAILINK_DEF(codec,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1")));
SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0.auto")));
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0")));
static struct snd_soc_dai_link cz_dai_rt5650[] = {
{
diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig
index ce0037810743..c2a60bc80ee6 100644
--- a/sound/soc/amd/acp/Kconfig
+++ b/sound/soc/amd/acp/Kconfig
@@ -13,14 +13,24 @@ config SND_SOC_AMD_ACP_COMMON
This option enables common modules for Audio-Coprocessor i.e. ACP
IP block on AMD platforms.
+config SND_SOC_ACPI_AMD_MATCH
+ tristate
+ select SND_SOC_ACPI if ACPI
+
if SND_SOC_AMD_ACP_COMMON
config SND_SOC_AMD_ACP_PDM
tristate
+config SND_SOC_AMD_ACP_LEGACY_COMMON
+ tristate
+
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
@@ -28,29 +38,69 @@ config SND_SOC_AMD_ACP_PCM
config SND_SOC_AMD_ACP_PCI
tristate "AMD ACP PCI Driver Support"
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.
config SND_AMD_ASOC_RENOIR
tristate "AMD ACP ASOC Renoir Support"
+ depends on ACPI
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
depends on X86 && PCI
help
This option enables Renoir I2S support on AMD platform.
config SND_AMD_ASOC_REMBRANDT
tristate "AMD ACP ASOC Rembrandt Support"
+ depends on ACPI
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
+ depends on AMD_NODE
depends on X86 && PCI
help
This option enables Rembrandt I2S support on AMD platform.
Say Y if you want to enable AUDIO on Rembrandt
If unsure select "N".
+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
+ If unsure select "N".
+
+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
+ If unsure select "N".
+
config SND_SOC_AMD_MACH_COMMON
tristate
depends on X86 && PCI && I2C
@@ -61,6 +111,8 @@ config SND_SOC_AMD_MACH_COMMON
select SND_SOC_MAX98357A
select SND_SOC_RT5682S
select SND_SOC_NAU8825
+ select SND_SOC_NAU8821
+ select SND_SOC_MAX98388
help
This option enables common Machine driver module for ACP.
@@ -78,4 +130,60 @@ config SND_SOC_AMD_SOF_MACH
help
This option enables SOF sound card support for ACP audio.
+config SND_SOC_AMD_SDW_MACH_COMMON
+ tristate
+ help
+ This option enables common SoundWire Machine driver module for
+ AMD platforms.
+
+config SND_SOC_AMD_SOF_SDW_MACH
+ tristate "AMD SOF Soundwire Machine Driver Support"
+ depends on X86 && PCI && ACPI
+ depends on SOUNDWIRE
+ select SND_SOC_AMD_SDW_MACH_COMMON
+ select SND_SOC_SDW_UTILS
+ select SND_SOC_DMIC
+ select SND_SOC_RT711_SDW
+ select SND_SOC_RT711_SDCA_SDW
+ select SND_SOC_RT1316_SDW
+ select SND_SOC_RT715_SDW
+ select SND_SOC_RT715_SDCA_SDW
+ select SND_SOC_RT722_SDCA_SDW
+ help
+ This option enables SOF sound card support for SoundWire enabled
+ AMD platforms along with ACP PDM controller.
+ Say Y if you want to enable SoundWire based machine driver support
+ on AMD platform.
+ If unsure select "N".
+
+config SND_SOC_AMD_LEGACY_SDW_MACH
+ tristate "AMD Legacy(No DSP) Soundwire Machine Driver Support"
+ depends on X86 && PCI && ACPI
+ depends on SOUNDWIRE
+ select SND_SOC_AMD_SDW_MACH_COMMON
+ select SND_SOC_SDW_UTILS
+ select SND_SOC_DMIC
+ select SND_SOC_RT711_SDW
+ select SND_SOC_RT711_SDCA_SDW
+ 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
+ help
+ This option enables Legacy(No DSP) sound card support for SoundWire
+ enabled AMD platforms along with ACP PDM controller.
+ Say Y if you want to enable SoundWire based machine driver support
+ on AMD platform.
+ If unsure select "N".
+
endif # SND_SOC_AMD_ACP_COMMON
+
+config SND_AMD_SOUNDWIRE_ACPI
+ tristate
+ depends on ACPI
+ help
+ This options enables ACPI helper functions for SoundWire
+ interface for AMD platforms.
diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile
index d9abb0ee5218..08220b9a3802 100644
--- a/sound/soc/amd/acp/Makefile
+++ b/sound/soc/amd/acp/Makefile
@@ -5,28 +5,46 @@
# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
#common acp driver
-snd-acp-pcm-objs := acp-platform.o
-snd-acp-i2s-objs := acp-i2s.o
-snd-acp-pdm-objs := acp-pdm.o
-snd-acp-pci-objs := acp-pci.o
+snd-acp-pcm-y := acp-platform.o
+snd-acp-i2s-y := acp-i2s.o
+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-objs := acp-renoir.o
-snd-acp-rembrandt-objs := acp-rembrandt.o
+snd-acp-renoir-y := acp-renoir.o
+snd-acp-rembrandt-y := acp-rembrandt.o
+snd-acp63-y := acp63.o
+snd-acp70-y := acp70.o
#machine specific driver
-snd-acp-mach-objs := acp-mach-common.o
-snd-acp-legacy-mach-objs := acp-legacy-mach.o
-snd-acp-sof-mach-objs := acp-sof-mach.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 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
obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o
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
+obj-$(CONFIG_SND_AMD_ASOC_ACP63) += snd-acp63.o
+obj-$(CONFIG_SND_AMD_ASOC_ACP70) += snd-acp70.o
+obj-$(CONFIG_SND_AMD_SOUNDWIRE_ACPI) += snd-amd-sdw-acpi.o
obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o
+obj-$(CONFIG_SND_SOC_ACPI_AMD_MATCH) += snd-soc-acpi-amd-match.o
+obj-$(CONFIG_SND_SOC_AMD_SDW_MACH_COMMON) += snd-acp-sdw-mach.o
+obj-$(CONFIG_SND_SOC_AMD_SOF_SDW_MACH) += snd-acp-sdw-sof-mach.o
+obj-$(CONFIG_SND_SOC_AMD_LEGACY_SDW_MACH) += snd-acp-sdw-legacy-mach.o
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 09b6511c0a26..4ba0a66981ea 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -20,24 +20,69 @@
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <linux/dma-mapping.h>
+#include <linux/bitfield.h>
#include "amd.h"
#define DRV_NAME "acp_i2s_playcap"
+#define I2S_MASTER_MODE_ENABLE 1
+#define LRCLK_DIV_FIELD GENMASK(10, 2)
+#define BCLK_DIV_FIELD GENMASK(23, 11)
+#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_chip_info *chip, int dai_id)
+{
+ u32 i2s_clk_reg, val;
+
+ switch (dai_id) {
+ case I2S_SP_INSTANCE:
+ i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
+ break;
+ case I2S_BT_INSTANCE:
+ i2s_clk_reg = ACP_I2STDM1_MSTRCLKGEN;
+ break;
+ case I2S_HS_INSTANCE:
+ i2s_clk_reg = ACP_I2STDM2_MSTRCLKGEN;
+ break;
+ default:
+ i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
+ break;
+ }
+
+ val = I2S_MASTER_MODE_ENABLE;
+ if (chip->tdm_mode)
+ val |= BIT(1);
+
+ switch (chip->acp_rev) {
+ case ACP63_PCI_ID:
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ 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, chip->lrclk_div);
+ val |= FIELD_PREP(BCLK_DIV_FIELD, chip->bclk_div);
+ }
+ 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_drvdata(dev->parent);
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;
@@ -49,10 +94,11 @@ 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;
+ chip = dev_get_drvdata(dev->parent);
switch (slot_width) {
case SLOT_WIDTH_8:
slot_len = 8;
@@ -71,30 +117,74 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
return -EINVAL;
}
- switch (slots) {
- case 1 ... 7:
- no_of_slots = slots;
+ switch (chip->acp_rev) {
+ case ACP_RN_PCI_ID:
+ case ACP_RMB_PCI_ID:
+ switch (slots) {
+ case 1 ... 7:
+ no_of_slots = slots;
+ break;
+ case 8:
+ no_of_slots = 0;
+ break;
+ default:
+ dev_err(dev, "Unsupported slots %d\n", slots);
+ return -EINVAL;
+ }
break;
- case 8:
- no_of_slots = 0;
+ case ACP63_PCI_ID:
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ switch (slots) {
+ case 1 ... 31:
+ no_of_slots = slots;
+ break;
+ case 32:
+ no_of_slots = 0;
+ break;
+ default:
+ dev_err(dev, "Unsupported slots %d\n", slots);
+ return -EINVAL;
+ }
break;
default:
- dev_err(dev, "Unsupported slots %d\n", slots);
+ dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
return -EINVAL;
}
slots = no_of_slots;
- spin_lock_irq(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
- if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
- adata->tdm_tx_fmt[stream->dai_id - 1] =
+ 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)
+ 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] =
+ else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
+ 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:
+ case ACP72_PCI_ID:
+ if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
+ 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)
+ 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;
}
@@ -102,15 +192,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_drvdata(dev->parent);
+ rsrc = chip->rsrc;
/* These values are as per Hardware Spec */
switch (params_format(params)) {
@@ -149,6 +239,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;
}
+ chip->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
} else {
switch (dai->driver->id) {
case I2S_BT_INSTANCE:
@@ -167,21 +258,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;
}
+ 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) {
@@ -249,8 +341,43 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
default:
return -EINVAL;
}
- adata->lrclk_div = lrclk_div_val;
- adata->bclk_div = bclk_div_val;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 48000:
+ case 96000:
+ case 192000:
+ switch (params_channels(params)) {
+ case 2:
+ break;
+ case 4:
+ bclk_div_val = bclk_div_val >> 1;
+ lrclk_div_val = lrclk_div_val << 1;
+ break;
+ case 8:
+ bclk_div_val = bclk_div_val >> 2;
+ lrclk_div_val = lrclk_div_val << 2;
+ break;
+ case 16:
+ bclk_div_val = bclk_div_val >> 3;
+ lrclk_div_val = lrclk_div_val << 3;
+ break;
+ case 32:
+ bclk_div_val = bclk_div_val >> 4;
+ lrclk_div_val = lrclk_div_val << 4;
+ break;
+ default:
+ dev_err(dev, "Unsupported channels %#x\n",
+ params_channels(params));
+ }
+ break;
+ default:
+ break;
+ }
+ chip->lrclk_div = lrclk_div_val;
+ chip->bclk_div = bclk_div_val;
}
return 0;
}
@@ -259,8 +386,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_drvdata(dev->parent);
+ 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);
@@ -270,20 +397,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;
+ 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;
+ buf_reg = ACP_BT_TX_RINGBUFSIZE(chip);
break;
case I2S_SP_INSTANCE:
- water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE;
+ 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;
+ buf_reg = ACP_I2S_TX_RINGBUFSIZE(chip);
break;
case I2S_HS_INSTANCE:
water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
@@ -298,16 +425,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;
+ 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;
+ buf_reg = ACP_BT_RX_RINGBUFSIZE(chip);
break;
case I2S_SP_INSTANCE:
- water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE;
+ 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;
+ buf_reg = ACP_I2S_RX_RINGBUFSIZE(chip);
break;
case I2S_HS_INSTANCE:
water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
@@ -320,14 +447,15 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
return -EINVAL;
}
}
- writel(period_bytes, adata->acp_base + water_val);
- writel(buf_size, adata->acp_base + buf_reg);
- val = readl(adata->acp_base + reg_val);
- val = val | BIT(0);
- writel(val, adata->acp_base + reg_val);
- writel(1, adata->acp_base + ier_val);
+
+ 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);
+ acp_set_i2s_clk(chip, dai->driver->id);
+ val = readl(chip->base + reg_val);
+ val = val | BIT(0);
+ writel(val, chip->base + reg_val);
+ writel(1, chip->base + ier_val);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -364,19 +492,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;
@@ -388,8 +516,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_resource *rsrc = adata->rsrc;
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
+ 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;
@@ -398,43 +526,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;
+ 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;
- reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
-
- phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
+ 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, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
} else {
- reg_dma_size = ACP_I2S_RX_DMA_SIZE;
+ 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;
- reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
- phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
+ 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, 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;
+ 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;
- reg_fifo_size = ACP_BT_TX_FIFOSIZE;
-
- phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
+ 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, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
} else {
- reg_dma_size = ACP_BT_RX_DMA_SIZE;
+ 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;
- reg_fifo_size = ACP_BT_RX_FIFOSIZE;
-
- phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
+ 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, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
}
break;
case I2S_HS_INSTANCE:
@@ -445,8 +586,11 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
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);
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
+ 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 +
@@ -454,8 +598,11 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
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);
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
+ writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR);
}
break;
default:
@@ -463,11 +610,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)) |
@@ -475,7 +622,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;
}
@@ -484,8 +631,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_drvdata(dev->parent);
+ struct acp_resource *rsrc = chip->rsrc;
unsigned int dir = substream->stream;
unsigned int irq_bit = 0;
@@ -538,36 +685,15 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
}
const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
- .startup = acp_i2s_startup,
- .hw_params = acp_i2s_hwparams,
- .prepare = acp_i2s_prepare,
- .trigger = acp_i2s_trigger,
- .set_fmt = acp_i2s_set_fmt,
- .set_tdm_slot = acp_i2s_set_tdm_slot,
+ .startup = acp_i2s_startup,
+ .hw_params = acp_i2s_hwparams,
+ .prepare = acp_i2s_prepare,
+ .trigger = acp_i2s_trigger,
+ .set_fmt = acp_i2s_set_fmt,
+ .set_tdm_slot = acp_i2s_set_tdm_slot,
};
-EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
-
-int asoc_acp_i2s_probe(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;
- unsigned int val;
-
- if (!adata->acp_base) {
- dev_err(dev, "I2S base is NULL\n");
- return -EINVAL;
- }
-
- val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset);
- if (val != rsrc->i2s_mode) {
- dev_err(dev, "I2S Mode not supported val %x\n", val);
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON);
+EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");
+MODULE_DESCRIPTION("AMD ACP Audio I2S controller");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
new file mode 100644
index 000000000000..3078f459e005
--- /dev/null
+++ b/sound/soc/amd/acp/acp-legacy-common.c
@@ -0,0 +1,647 @@
+// 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) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Syed Saba Kareem <Syed.SabaKareem@amd.com>
+//
+
+/*
+ * Common file to be used by amd platforms
+ */
+
+#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
+
+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_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;
+
+ 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(chip, rsrc->irqp_used));
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, "SND_SOC_ACP_COMMON");
+
+int acp_disable_interrupts(struct acp_chip_info *chip)
+{
+ 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));
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, "SND_SOC_ACP_COMMON");
+
+static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct acp_stream *stream = runtime->private_data;
+ struct device *dev = dai->component->dev;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+
+ u32 physical_addr, pdm_size, period_bytes;
+
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
+ pdm_size = frames_to_bytes(runtime, runtime->buffer_size);
+ physical_addr = stream->reg_offset + MEM_WINDOW_START;
+
+ /* Init ACP PDM Ring buffer */
+ 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_chip_info *chip = dev_get_platdata(dev);
+ unsigned int pdm_ctrl;
+
+ /* Enable default ACP PDM clk */
+ 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, 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_chip_info *chip)
+{
+ struct snd_soc_dai *dai;
+ struct snd_soc_pcm_runtime *soc_runtime;
+ u32 ext_int_ctrl;
+
+ soc_runtime = snd_soc_substream_to_rtd(substream);
+ dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+
+ /* Programming channel mask and sampling rate */
+ 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(chip, 0));
+ ext_int_ctrl |= PDM_DMA_INTR_MASK;
+ 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");
+
+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_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;
+ unsigned int dir = substream->stream;
+
+ switch (dai->driver->id) {
+ case I2S_SP_INSTANCE:
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ 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(chip);
+ reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip);
+ phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
+ writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
+ } else {
+ 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(chip);
+ reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip);
+ phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
+ 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(chip);
+ acp_fifo_addr = rsrc->sram_pte_offset +
+ BT_PB_FIFO_ADDR_OFFSET;
+ 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, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
+ } else {
+ 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(chip);
+ reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip);
+ phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
+ writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
+ }
+ break;
+ case I2S_HS_INSTANCE:
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ reg_dma_size = ACP_HS_TX_DMA_SIZE;
+ acp_fifo_addr = rsrc->sram_pte_offset +
+ HS_PB_FIFO_ADDR_OFFSET;
+ 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, chip->base + ACP_HS_TX_RINGBUFADDR);
+ } else {
+ reg_dma_size = ACP_HS_RX_DMA_SIZE;
+ acp_fifo_addr = rsrc->sram_pte_offset +
+ HS_CAPT_FIFO_ADDR_OFFSET;
+ 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, chip->base + ACP_HS_RX_RINGBUFADDR);
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
+ return -EINVAL;
+ }
+
+ 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(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)) |
+ BIT(BT_TX_THRESHOLD(rsrc->offset)) |
+ BIT(HS_RX_THRESHOLD(rsrc->offset)) |
+ BIT(HS_TX_THRESHOLD(rsrc->offset));
+
+ 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_chip_info *chip,
+ struct acp_stream *stream)
+{
+ struct snd_soc_dai *dai;
+ struct snd_soc_pcm_runtime *soc_runtime;
+ u32 tdm_fmt, reg_val, fmt_reg, val;
+
+ 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 = chip->tdm_tx_fmt[stream->dai_id - 1];
+ switch (stream->dai_id) {
+ case I2S_BT_INSTANCE:
+ reg_val = ACP_BTTDM_ITER;
+ fmt_reg = ACP_BTTDM_TXFRMT;
+ break;
+ case I2S_SP_INSTANCE:
+ reg_val = ACP_I2STDM_ITER;
+ fmt_reg = ACP_I2STDM_TXFRMT;
+ break;
+ case I2S_HS_INSTANCE:
+ reg_val = ACP_HSTDM_ITER;
+ fmt_reg = ACP_HSTDM_TXFRMT;
+ break;
+ default:
+ pr_err("Invalid dai id %x\n", stream->dai_id);
+ return -EINVAL;
+ }
+ val = chip->xfer_tx_resolution[stream->dai_id - 1] << 3;
+ } else {
+ tdm_fmt = chip->tdm_rx_fmt[stream->dai_id - 1];
+ switch (stream->dai_id) {
+ case I2S_BT_INSTANCE:
+ reg_val = ACP_BTTDM_IRER;
+ fmt_reg = ACP_BTTDM_RXFRMT;
+ break;
+ case I2S_SP_INSTANCE:
+ reg_val = ACP_I2STDM_IRER;
+ fmt_reg = ACP_I2STDM_RXFRMT;
+ break;
+ case I2S_HS_INSTANCE:
+ reg_val = ACP_HSTDM_IRER;
+ fmt_reg = ACP_HSTDM_RXFRMT;
+ break;
+ default:
+ pr_err("Invalid dai id %x\n", stream->dai_id);
+ return -EINVAL;
+ }
+ val = chip->xfer_rx_resolution[stream->dai_id - 1] << 3;
+ }
+ 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);
+}
+EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, "SND_SOC_ACP_COMMON");
+
+static int acp_power_on(struct acp_chip_info *chip)
+{
+ u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg;
+ void __iomem *base;
+
+ base = chip->base;
+ switch (chip->acp_rev) {
+ case ACP_RN_PCI_ID:
+ acp_pgfsm_stat_reg = ACP_PGFSM_STATUS;
+ acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL;
+ break;
+ case ACP_RMB_PCI_ID:
+ acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS;
+ acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL;
+ break;
+ case ACP63_PCI_ID:
+ acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS;
+ acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL;
+ break;
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS;
+ acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = readl(base + acp_pgfsm_stat_reg);
+ if (val == ACP_POWERED_ON)
+ return 0;
+
+ if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
+ writel(ACP_PGFSM_CNTL_POWER_ON_MASK, base + acp_pgfsm_ctrl_reg);
+
+ return readl_poll_timeout(base + acp_pgfsm_stat_reg, val,
+ !val, DELAY_US, ACP_TIMEOUT);
+}
+
+static int acp_reset(void __iomem *base)
+{
+ u32 val;
+ int ret;
+
+ writel(1, base + ACP_SOFT_RESET);
+ ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
+ DELAY_US, ACP_TIMEOUT);
+ if (ret)
+ return ret;
+
+ writel(0, base + ACP_SOFT_RESET);
+ return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
+}
+
+int acp_init(struct acp_chip_info *chip)
+{
+ int ret;
+
+ /* power on */
+ ret = acp_power_on(chip);
+ if (ret) {
+ pr_err("ACP power on failed\n");
+ return ret;
+ }
+ writel(0x01, chip->base + ACP_CONTROL);
+
+ /* Reset */
+ ret = acp_reset(chip->base);
+ if (ret) {
+ pr_err("ACP reset failed\n");
+ return ret;
+ }
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ writel(0, chip->base + ACP_ZSC_DSP_CTRL);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp_init, "SND_SOC_ACP_COMMON");
+
+int acp_deinit(struct acp_chip_info *chip)
+{
+ int ret;
+
+ /* Reset */
+ ret = acp_reset(chip->base);
+ if (ret)
+ return ret;
+
+ if (chip->acp_rev < ACP70_PCI_ID)
+ writel(0, chip->base + ACP_CONTROL);
+ else
+ writel(0x01, chip->base + ACP_ZSC_DSP_CTRL);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp_deinit, "SND_SOC_ACP_COMMON");
+int acp_machine_select(struct acp_chip_info *chip)
+{
+ struct snd_soc_acpi_mach *mach;
+ int size, platform;
+
+ if (chip->flag == FLAG_AMD_LEGACY_ONLY_DMIC && chip->is_pdm_dev) {
+ 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(acp_machine_select, "SND_SOC_ACP_COMMON");
+
+static void check_acp3x_config(struct acp_chip_info *chip)
+{
+ u32 val;
+
+ val = readl(chip->base + ACP3X_PIN_CONFIG);
+ switch (val) {
+ case ACP_CONFIG_4:
+ chip->is_i2s_config = true;
+ chip->is_pdm_config = true;
+ break;
+ default:
+ chip->is_pdm_config = true;
+ break;
+ }
+}
+
+static void check_acp6x_config(struct acp_chip_info *chip)
+{
+ u32 val;
+
+ val = readl(chip->base + ACP_PIN_CONFIG);
+ switch (val) {
+ case ACP_CONFIG_4:
+ case ACP_CONFIG_5:
+ case ACP_CONFIG_6:
+ case ACP_CONFIG_7:
+ case ACP_CONFIG_8:
+ case ACP_CONFIG_11:
+ case ACP_CONFIG_14:
+ chip->is_pdm_config = true;
+ break;
+ case ACP_CONFIG_9:
+ chip->is_i2s_config = true;
+ break;
+ case ACP_CONFIG_10:
+ case ACP_CONFIG_12:
+ case ACP_CONFIG_13:
+ chip->is_i2s_config = true;
+ chip->is_pdm_config = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static void check_acp70_config(struct acp_chip_info *chip)
+{
+ u32 val;
+
+ val = readl(chip->base + ACP_PIN_CONFIG);
+ switch (val) {
+ case ACP_CONFIG_4:
+ case ACP_CONFIG_5:
+ case ACP_CONFIG_6:
+ case ACP_CONFIG_7:
+ case ACP_CONFIG_8:
+ case ACP_CONFIG_11:
+ case ACP_CONFIG_14:
+ case ACP_CONFIG_17:
+ case ACP_CONFIG_18:
+ chip->is_pdm_config = true;
+ break;
+ case ACP_CONFIG_9:
+ chip->is_i2s_config = true;
+ break;
+ case ACP_CONFIG_10:
+ case ACP_CONFIG_12:
+ case ACP_CONFIG_13:
+ case ACP_CONFIG_19:
+ case ACP_CONFIG_20:
+ chip->is_i2s_config = true;
+ chip->is_pdm_config = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
+{
+ struct acpi_device *pdm_dev;
+ const union acpi_object *obj;
+ acpi_handle handle;
+ acpi_integer dmic_status;
+ u32 pdm_addr, ret;
+
+ switch (chip->acp_rev) {
+ case ACP_RN_PCI_ID:
+ pdm_addr = ACP_RENOIR_PDM_ADDR;
+ check_acp3x_config(chip);
+ break;
+ case ACP_RMB_PCI_ID:
+ pdm_addr = ACP_REMBRANDT_PDM_ADDR;
+ check_acp6x_config(chip);
+ break;
+ case ACP63_PCI_ID:
+ pdm_addr = ACP63_PDM_ADDR;
+ check_acp6x_config(chip);
+ break;
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ pdm_addr = ACP70_PDM_ADDR;
+ check_acp70_config(chip);
+ break;
+ default:
+ break;
+ }
+
+ if (chip->is_pdm_config) {
+ pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), pdm_addr, 0);
+ if (pdm_dev) {
+ if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
+ ACPI_TYPE_INTEGER, &obj) &&
+ 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-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index 676ad50638d0..a7a551366a40 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include "acp-mach.h"
+#include "acp3x-es83xx/acp3x-es83xx.h"
static struct acp_card_drvdata rt5682_rt1019_data = {
.hs_cpu_id = I2S_SP,
@@ -51,6 +52,13 @@ static struct acp_card_drvdata rt5682s_rt1019_data = {
.tdm_mode = false,
};
+static struct acp_card_drvdata es83xx_rn_data = {
+ .hs_cpu_id = I2S_SP,
+ .dmic_cpu_id = DMIC,
+ .hs_codec_id = ES83XX,
+ .dmic_codec_id = DMIC,
+};
+
static struct acp_card_drvdata max_nau8825_data = {
.hs_cpu_id = I2S_HS,
.amp_cpu_id = I2S_HS,
@@ -59,7 +67,6 @@ static struct acp_card_drvdata max_nau8825_data = {
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
.soc_mclk = true,
- .platform = REMBRANDT,
.tdm_mode = false,
};
@@ -71,67 +78,122 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
.soc_mclk = true,
- .platform = REMBRANDT,
.tdm_mode = false,
};
-static const struct snd_kcontrol_new acp_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-
+static struct acp_card_drvdata acp_dmic_data = {
+ .dmic_cpu_id = DMIC,
+ .dmic_codec_id = DMIC,
};
-static const struct snd_soc_dapm_widget acp_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
+static bool acp_asoc_init_ops(struct acp_card_drvdata *priv)
+{
+ bool has_ops = false;
+
+ if (priv->hs_codec_id == ES83XX) {
+ has_ops = true;
+ acp3x_es83xx_init_ops(&priv->ops);
+ }
+ return has_ops;
+}
+
+static int acp_asoc_suspend_pre(struct snd_soc_card *card)
+{
+ int ret;
+
+ ret = acp_ops_suspend_pre(card);
+ if (ret == 1)
+ return 0;
+ else
+ return ret;
+}
+
+static int acp_asoc_resume_post(struct snd_soc_card *card)
+{
+ int ret;
+
+ ret = acp_ops_resume_post(card);
+ if (ret == 1)
+ return 0;
+ else
+ return ret;
+}
static int acp_asoc_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = NULL;
struct device *dev = &pdev->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
const struct dmi_system_id *dmi_id;
struct acp_card_drvdata *acp_card_drvdata;
int ret;
- if (!pdev->id_entry)
- return -EINVAL;
+ if (!pdev->id_entry) {
+ ret = -EINVAL;
+ goto out;
+ }
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
- if (!card)
- return -ENOMEM;
+ if (!card) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+ acp_card_drvdata = card->drvdata;
+ acp_card_drvdata->acpi_mach = (struct snd_soc_acpi_mach *)pdev->dev.platform_data;
card->dev = dev;
card->owner = THIS_MODULE;
card->name = pdev->id_entry->name;
- card->dapm_widgets = acp_widgets;
- card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
- card->controls = acp_controls;
- card->num_controls = ARRAY_SIZE(acp_controls);
- card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
- acp_card_drvdata = card->drvdata;
+ acp_asoc_init_ops(card->drvdata);
+
+ /* If widgets and controls are not set in specific callback,
+ * they will be added per-codec in acp-mach-common.c
+ */
+ ret = acp_ops_configure_widgets(card);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Cannot configure widgets for card (%s): %d\n",
+ card->name, ret);
+ goto out;
+ }
+ card->suspend_pre = acp_asoc_suspend_pre;
+ card->resume_post = acp_asoc_resume_post;
+
+ ret = acp_ops_probe(card);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Cannot probe card (%s): %d\n",
+ card->name, ret);
+ goto out;
+ }
+ if (!strcmp(pdev->name, "acp-pdm-mach"))
+ acp_card_drvdata->acp_rev = *((int *)dev->platform_data);
+ else
+ acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
+
dmi_id = dmi_first_match(acp_quirk_table);
if (dmi_id && dmi_id->driver_data)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
- acp_legacy_dai_links_create(card);
+ ret = acp_legacy_dai_links_create(card);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Cannot create dai links for card (%s): %d\n",
+ card->name, ret);
+ goto out;
+ }
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
dev_err(&pdev->dev,
"devm_snd_soc_register_card(%s) failed: %d\n",
card->name, ret);
- return ret;
+ goto out;
}
-
- return 0;
+out:
+ return ret;
}
static const struct platform_device_id board_ids[] = {
@@ -148,6 +210,10 @@ static const struct platform_device_id board_ids[] = {
.driver_data = (kernel_ulong_t)&rt5682s_rt1019_data,
},
{
+ .name = "acp3x-es83xx",
+ .driver_data = (kernel_ulong_t)&es83xx_rn_data,
+ },
+ {
.name = "rmb-nau8825-max",
.driver_data = (kernel_ulong_t)&max_nau8825_data,
},
@@ -155,8 +221,14 @@ static const struct platform_device_id board_ids[] = {
.name = "rmb-rt5682s-rt1019",
.driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data,
},
+ {
+ .name = "acp-pdm-mach",
+ .driver_data = (kernel_ulong_t)&acp_dmic_data,
+ },
{ }
};
+MODULE_DEVICE_TABLE(platform, board_ids);
+
static struct platform_driver acp_asoc_audio = {
.driver = {
.pm = &snd_soc_pm_ops,
@@ -168,11 +240,6 @@ static struct platform_driver acp_asoc_audio = {
module_platform_driver(acp_asoc_audio);
-MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
+MODULE_IMPORT_NS("SND_SOC_AMD_MACH");
MODULE_DESCRIPTION("ACP chrome audio support");
-MODULE_ALIAS("platform:acp3xalc56821019");
-MODULE_ALIAS("platform:acp3xalc5682sm98360");
-MODULE_ALIAS("platform:acp3xalc5682s1019");
-MODULE_ALIAS("platform:rmb-nau8825-max");
-MODULE_ALIAS("platform:rmb-rt5682s-rt1019");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 6da17140beea..4d99472c75ba 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
// Vijendar Mukunda <Vijendar.Mukunda@amd.com>
@@ -25,12 +25,17 @@
#include "../../codecs/rt1019.h"
#include "../../codecs/rt5682s.h"
#include "../../codecs/nau8825.h"
+#include "../../codecs/nau8821.h"
#include "acp-mach.h"
#define PCO_PLAT_CLK 48000000
#define RT5682_PLL_FREQ (48000 * 512)
#define DUAL_CHANNEL 2
#define FOUR_CHANNEL 4
+#define NAU8821_CODEC_DAI "nau8821-hifi"
+#define NAU8821_BCLK 1536000
+#define NAU8821_FREQ_OUT 12288000
+#define MAX98388_CODEC_DAI "max98388-aif1"
#define TDM_MODE_ENABLE 1
@@ -46,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = {
};
EXPORT_SYMBOL_GPL(acp_quirk_table);
-static struct snd_soc_jack pco_jack;
-
static const unsigned int channels[] = {
DUAL_CHANNEL,
};
@@ -81,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata,
SND_SOC_DAILINK_DEF(rt5682,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
+static struct snd_soc_jack rt5682_jack;
+static struct snd_soc_jack_pin rt5682_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new rt5682_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget rt5682_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
static const struct snd_soc_dapm_route rt5682_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
@@ -91,8 +116,9 @@ static const struct snd_soc_dapm_route rt5682_map[] = {
static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
int ret;
@@ -104,37 +130,53 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ ret = snd_soc_dapm_new_controls(dapm, rt5682_widgets,
+ ARRAY_SIZE(rt5682_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, rt5682_controls,
+ ARRAY_SIZE(rt5682_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &rt5682_jack,
+ rt5682_jack_pins,
+ ARRAY_SIZE(rt5682_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
}
- return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
+ return snd_soc_dapm_add_routes(dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
}
static int acp_card_hs_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
unsigned int fmt;
@@ -165,7 +207,7 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
static void acp_card_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
@@ -176,11 +218,11 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream)
static int acp_card_rt5682_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
unsigned int fmt, srate, ch, format;
@@ -241,6 +283,22 @@ static int acp_card_rt5682_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (drvdata->tdm_mode) {
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1,
+ 6144000, 49152000);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL1,
+ 49152000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
+ return ret;
+ }
+ }
+
/* Set tdm/i2s1 master bclk ratio */
ret = snd_soc_dai_set_bclk_ratio(codec_dai, ch * format);
if (ret < 0) {
@@ -269,6 +327,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = {
SND_SOC_DAILINK_DEF(rt5682s,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
+static struct snd_soc_jack rt5682s_jack;
+static struct snd_soc_jack_pin rt5682s_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new rt5682s_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget rt5682s_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
static const struct snd_soc_dapm_route rt5682s_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
@@ -278,8 +358,9 @@ static const struct snd_soc_dapm_route rt5682s_map[] = {
static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
int ret;
@@ -293,28 +374,44 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
}
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ ret = snd_soc_dapm_new_controls(dapm, rt5682s_widgets,
+ ARRAY_SIZE(rt5682s_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, rt5682s_controls,
+ ARRAY_SIZE(rt5682s_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &rt5682s_jack,
+ rt5682s_jack_pins,
+ ARRAY_SIZE(rt5682s_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
}
- return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
+ return snd_soc_dapm_add_routes(dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
}
static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,
@@ -323,8 +420,8 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
unsigned int fmt, srate, ch, format;
@@ -385,6 +482,22 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (drvdata->tdm_mode) {
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1,
+ 6144000, 49152000);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL1,
+ 49152000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
+ return ret;
+ }
+ }
+
/* Set tdm/i2s1 master bclk ratio */
ret = snd_soc_dai_set_bclk_ratio(codec_dai, ch * format);
if (ret < 0) {
@@ -394,6 +507,13 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,
clk_set_rate(drvdata->wclk, srate);
clk_set_rate(drvdata->bclk, srate * ch * format);
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata, srate, ch * format);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+ return ret;
+ }
+ }
return 0;
}
@@ -434,6 +554,16 @@ SND_SOC_DAILINK_DEF(rt1019,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
+static const struct snd_kcontrol_new rt1019_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget rt1019_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
static const struct snd_soc_dapm_route rt1019_map_lr[] = {
{ "Left Spk", NULL, "Left SPO" },
{ "Right Spk", NULL, "Right SPO" },
@@ -453,12 +583,28 @@ static struct snd_soc_codec_conf rt1019_conf[] = {
static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret;
if (drvdata->amp_codec_id != RT1019)
return -EINVAL;
- return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
+ ret = snd_soc_dapm_new_controls(dapm, rt1019_widgets,
+ ARRAY_SIZE(rt1019_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, rt1019_controls,
+ ARRAY_SIZE(rt1019_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_dapm_add_routes(dapm, rt1019_map_lr,
ARRAY_SIZE(rt1019_map_lr));
}
@@ -469,7 +615,7 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int i, ret = 0;
unsigned int fmt, srate, ch, format;
@@ -588,6 +734,14 @@ static const struct snd_soc_ops acp_card_rt1019_ops = {
SND_SOC_DAILINK_DEF(max98360a,
DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
+static const struct snd_kcontrol_new max98360a_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget max98360a_widgets[] = {
+ SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
static const struct snd_soc_dapm_route max98360a_map[] = {
{"Spk", NULL, "Speaker"},
};
@@ -595,12 +749,28 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret;
if (drvdata->amp_codec_id != MAX98360A)
return -EINVAL;
- return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
+ ret = snd_soc_dapm_new_controls(dapm, max98360a_widgets,
+ ARRAY_SIZE(max98360a_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, max98360a_controls,
+ ARRAY_SIZE(max98360a_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_dapm_add_routes(dapm, max98360a_map,
ARRAY_SIZE(max98360a_map));
}
@@ -610,7 +780,7 @@ static int acp_card_maxim_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned int fmt, srate, ch, format;
int ret;
@@ -661,10 +831,138 @@ static const struct snd_soc_ops acp_card_maxim_ops = {
.hw_params = acp_card_maxim_hw_params,
};
+SND_SOC_DAILINK_DEF(max98388,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", MAX98388_CODEC_DAI),
+ COMP_CODEC("i2c-ADS8388:01", MAX98388_CODEC_DAI)));
+
+static const struct snd_kcontrol_new max98388_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget max98388_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route max98388_map[] = {
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static struct snd_soc_codec_conf max98388_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF("i2c-ADS8388:00"),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF("i2c-ADS8388:01"),
+ .name_prefix = "Right",
+ },
+};
+
+static const unsigned int max98388_format[] = {16};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_bits_max = {
+ .list = max98388_format,
+ .count = ARRAY_SIZE(max98388_format),
+};
+
+static int acp_card_max98388_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ &constraints_sample_bits_max);
+
+ return 0;
+}
+
+static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret;
+
+ if (drvdata->amp_codec_id != MAX98388)
+ return -EINVAL;
+
+ ret = snd_soc_dapm_new_controls(dapm, max98388_widgets,
+ ARRAY_SIZE(max98388_widgets));
+
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ /* Don't need to add routes if widget addition failed */
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, max98388_controls,
+ ARRAY_SIZE(max98388_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_dapm_add_routes(dapm, max98388_map,
+ ARRAY_SIZE(max98388_map));
+}
+
+static int acp_max98388_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai =
+ snd_soc_card_get_codec_dai(card,
+ MAX98388_CODEC_DAI);
+ int ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static const struct snd_soc_ops acp_max98388_ops = {
+ .startup = acp_card_max98388_startup,
+ .hw_params = acp_max98388_hw_params,
+};
+
/* Declare nau8825 codec components */
SND_SOC_DAILINK_DEF(nau8825,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi")));
+static struct snd_soc_jack nau8825_jack;
+static struct snd_soc_jack_pin nau8825_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new nau8825_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget nau8825_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
static const struct snd_soc_dapm_route nau8825_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
@@ -673,8 +971,9 @@ static const struct snd_soc_dapm_route nau8825_map[] = {
static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
int ret;
@@ -683,38 +982,54 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != NAU8825)
return -EINVAL;
- ret = snd_soc_card_jack_new(card, "Headset Jack",
+ ret = snd_soc_dapm_new_controls(dapm, nau8825_widgets,
+ ARRAY_SIZE(nau8825_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, nau8825_controls,
+ ARRAY_SIZE(nau8825_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ &nau8825_jack,
+ nau8825_jack_pins,
+ ARRAY_SIZE(nau8825_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
}
- return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map));
+ return snd_soc_dapm_add_routes(dapm, nau8825_map, ARRAY_SIZE(nau8825_map));
}
static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
unsigned int fmt;
@@ -790,6 +1105,189 @@ static const struct snd_soc_ops acp_card_nau8825_ops = {
.hw_params = acp_nau8825_hw_params,
};
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, NAU8821_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_INTERNAL,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "set sysclk err = %d\n", ret);
+ return -EIO;
+ }
+ } else {
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, NAU8821_BCLK,
+ NAU8821_FREQ_OUT);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+ }
+ return ret;
+}
+
+static struct snd_soc_jack nau8821_jack;
+static struct snd_soc_jack_pin nau8821_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new nau8821_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget nau8821_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route nau8821_audio_route[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+ { "MICL", NULL, "Headset Mic" },
+ { "MICR", NULL, "Headset Mic" },
+ { "DMIC", NULL, "Int Mic" },
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+ { "Int Mic", NULL, "Platform Clock" },
+};
+
+static const unsigned int nau8821_format[] = {16};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
+ .list = nau8821_format,
+ .count = ARRAY_SIZE(nau8821_format),
+};
+
+static int acp_8821_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ int ret;
+
+ dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+ ret = snd_soc_dapm_new_controls(dapm, nau8821_widgets,
+ ARRAY_SIZE(nau8821_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ // Don't need to add routes if widget addition failed
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, nau8821_controls,
+ ARRAY_SIZE(nau8821_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &nau8821_jack,
+ nau8821_jack_pins,
+ ARRAY_SIZE(nau8821_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ nau8821_enable_jack_detect(component, &nau8821_jack);
+
+ return snd_soc_dapm_add_routes(dapm, nau8821_audio_route,
+ ARRAY_SIZE(nau8821_audio_route));
+}
+
+static int acp_8821_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ &constraints_sample_bits);
+ return 0;
+}
+
+static int acp_nau8821_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_card *card = rtd->card;
+ struct acp_card_drvdata *drvdata = card->drvdata;
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ int ret;
+ unsigned int fmt;
+
+ if (drvdata->soc_mclk)
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(card->dev, "can't set FS clock %d\n", ret);
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, snd_soc_params_to_bclk(params),
+ params_rate(params) * 256);
+ if (ret < 0)
+ dev_err(card->dev, "can't set FLL: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops acp_8821_ops = {
+ .startup = acp_8821_startup,
+ .hw_params = acp_nau8821_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(nau8821,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00",
+ NAU8821_CODEC_DAI)));
+
/* Declare DMIC codec components */
SND_SOC_DAILINK_DEF(dmic_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
@@ -807,6 +1305,18 @@ static struct snd_soc_dai_link_component platform_rmb_component[] = {
}
};
+static struct snd_soc_dai_link_component platform_acp63_component[] = {
+ {
+ .name = "acp_asoc_acp63.0",
+ }
+};
+
+static struct snd_soc_dai_link_component platform_acp70_component[] = {
+ {
+ .name = "acp_asoc_acp70.0",
+ }
+};
+
static struct snd_soc_dai_link_component sof_component[] = {
{
.name = "0000:04:00.5",
@@ -825,6 +1335,8 @@ SND_SOC_DAILINK_DEF(sof_hs,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs")));
SND_SOC_DAILINK_DEF(sof_hs_virtual,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs-virtual")));
+SND_SOC_DAILINK_DEF(sof_bt,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-bt")));
SND_SOC_DAILINK_DEF(sof_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
SND_SOC_DAILINK_DEF(pdm_dmic,
@@ -834,7 +1346,7 @@ static int acp_rtk_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_component *component = dapm->component;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct acp_card_drvdata *drvdata = card->drvdata;
int ret = 0;
@@ -883,6 +1395,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
if (drv_data->hs_cpu_id)
num_links++;
+ if (drv_data->bt_cpu_id)
+ num_links++;
if (drv_data->amp_cpu_id)
num_links++;
if (drv_data->dmic_cpu_id)
@@ -899,13 +1413,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].num_cpus = ARRAY_SIZE(sof_sp);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
- links[i].dpcm_playback = 1;
- links[i].dpcm_capture = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
if (!drv_data->hs_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->hs_codec_id == RT5682) {
@@ -920,6 +1432,12 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].init = acp_card_rt5682s_init;
links[i].ops = &acp_card_rt5682s_ops;
}
+ if (drv_data->hs_codec_id == NAU8821) {
+ links[i].codecs = nau8821;
+ links[i].num_codecs = ARRAY_SIZE(nau8821);
+ links[i].init = acp_8821_init;
+ links[i].ops = &acp_8821_ops;
+ }
i++;
}
@@ -930,13 +1448,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].num_cpus = ARRAY_SIZE(sof_hs);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
- links[i].dpcm_playback = 1;
- links[i].dpcm_capture = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
if (!drv_data->hs_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->hs_codec_id == NAU8825) {
@@ -957,16 +1473,21 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
if (drv_data->amp_cpu_id == I2S_SP) {
links[i].name = "acp-amp-codec";
links[i].id = AMP_BE_ID;
- links[i].cpus = sof_sp_virtual;
- links[i].num_cpus = ARRAY_SIZE(sof_sp_virtual);
+ if (drv_data->acp_rev == ACP_RN_PCI_ID) {
+ links[i].cpus = sof_sp;
+ links[i].num_cpus = ARRAY_SIZE(sof_sp);
+ } else {
+ links[i].cpus = sof_sp_virtual;
+ links[i].num_cpus = ARRAY_SIZE(sof_sp_virtual);
+ }
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
- links[i].dpcm_playback = 1;
+ links[i].playback_only = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
if (!drv_data->amp_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->amp_codec_id == RT1019) {
@@ -993,12 +1514,12 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].num_cpus = ARRAY_SIZE(sof_hs_virtual);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
- links[i].dpcm_playback = 1;
+ links[i].playback_only = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
if (!drv_data->amp_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->amp_codec_id == MAX98360A) {
@@ -1007,6 +1528,15 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].ops = &acp_card_maxim_ops;
links[i].init = acp_card_maxim_init;
}
+ if (drv_data->amp_codec_id == MAX98388) {
+ links[i].playback_only = 0;
+ links[i].codecs = max98388;
+ links[i].num_codecs = ARRAY_SIZE(max98388);
+ links[i].ops = &acp_max98388_ops;
+ links[i].init = acp_card_max98388_init;
+ card->codec_conf = max98388_conf;
+ card->num_configs = ARRAY_SIZE(max98388_conf);
+ }
if (drv_data->amp_codec_id == RT1019) {
links[i].codecs = rt1019;
links[i].num_codecs = ARRAY_SIZE(rt1019);
@@ -1018,6 +1548,23 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
i++;
}
+ if (drv_data->bt_cpu_id == I2S_BT) {
+ links[i].name = "acp-bt-codec";
+ links[i].id = BT_BE_ID;
+ links[i].cpus = sof_bt;
+ links[i].num_cpus = ARRAY_SIZE(sof_bt);
+ links[i].platforms = sof_component;
+ links[i].num_platforms = ARRAY_SIZE(sof_component);
+ links[i].nonatomic = true;
+ links[i].no_pcm = 1;
+ if (!drv_data->bt_codec_id) {
+ /* Use dummy codec if codec id not specified */
+ links[i].codecs = &snd_soc_dummy_dlc;
+ links[i].num_codecs = 1;
+ }
+ i++;
+ }
+
if (drv_data->dmic_cpu_id == DMIC) {
links[i].name = "acp-dmic-codec";
links[i].id = DMIC_BE_ID;
@@ -1027,7 +1574,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
links[i].num_cpus = ARRAY_SIZE(sof_dmic);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
- links[i].dpcm_capture = 1;
+ links[i].capture_only = 1;
links[i].nonatomic = true;
links[i].no_pcm = 1;
}
@@ -1038,7 +1585,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH);
+EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, "SND_SOC_AMD_MACH");
int acp_legacy_dai_links_create(struct snd_soc_card *card)
{
@@ -1046,6 +1593,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
struct device *dev = card->dev;
struct acp_card_drvdata *drv_data = card->drvdata;
int i = 0, num_links = 0;
+ int rc;
if (drv_data->hs_cpu_id)
num_links++;
@@ -1065,11 +1613,9 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
links[i].num_cpus = ARRAY_SIZE(i2s_sp);
links[i].platforms = platform_component;
links[i].num_platforms = ARRAY_SIZE(platform_component);
- links[i].dpcm_playback = 1;
- links[i].dpcm_capture = 1;
if (!drv_data->hs_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->hs_codec_id == RT5682) {
@@ -1084,6 +1630,13 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
links[i].init = acp_card_rt5682s_init;
links[i].ops = &acp_card_rt5682s_ops;
}
+ if (drv_data->hs_codec_id == ES83XX) {
+ rc = acp_ops_configure_link(card, &links[i]);
+ if (rc != 0) {
+ dev_err(dev, "Failed to configure link for ES83XX: %d\n", rc);
+ return rc;
+ }
+ }
i++;
}
@@ -1092,18 +1645,24 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
links[i].id = HEADSET_BE_ID;
links[i].cpus = i2s_hs;
links[i].num_cpus = ARRAY_SIZE(i2s_hs);
- if (drv_data->platform == REMBRANDT) {
+ switch (drv_data->acp_rev) {
+ case ACP_RMB_PCI_ID:
links[i].platforms = platform_rmb_component;
links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
- } else {
+ break;
+ case ACP63_PCI_ID:
+ links[i].platforms = platform_acp63_component;
+ links[i].num_platforms = ARRAY_SIZE(platform_acp63_component);
+ break;
+ default:
links[i].platforms = platform_component;
links[i].num_platforms = ARRAY_SIZE(platform_component);
+ break;
}
- links[i].dpcm_playback = 1;
- links[i].dpcm_capture = 1;
+
if (!drv_data->hs_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->hs_codec_id == NAU8825) {
@@ -1128,10 +1687,10 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
links[i].num_cpus = ARRAY_SIZE(i2s_sp);
links[i].platforms = platform_component;
links[i].num_platforms = ARRAY_SIZE(platform_component);
- links[i].dpcm_playback = 1;
+ links[i].playback_only = 1;
if (!drv_data->amp_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->amp_codec_id == RT1019) {
@@ -1156,17 +1715,25 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
links[i].id = AMP_BE_ID;
links[i].cpus = i2s_hs;
links[i].num_cpus = ARRAY_SIZE(i2s_hs);
- if (drv_data->platform == REMBRANDT) {
+ switch (drv_data->acp_rev) {
+ case ACP_RMB_PCI_ID:
links[i].platforms = platform_rmb_component;
links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
- } else {
+ break;
+ case ACP63_PCI_ID:
+ links[i].platforms = platform_acp63_component;
+ links[i].num_platforms = ARRAY_SIZE(platform_acp63_component);
+ break;
+ default:
links[i].platforms = platform_component;
links[i].num_platforms = ARRAY_SIZE(platform_component);
+ break;
}
- links[i].dpcm_playback = 1;
+
+ links[i].playback_only = 1;
if (!drv_data->amp_codec_id) {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
if (drv_data->amp_codec_id == MAX98360A) {
@@ -1188,26 +1755,40 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
if (drv_data->dmic_cpu_id == DMIC) {
links[i].name = "acp-dmic-codec";
+ links[i].stream_name = "DMIC capture";
links[i].id = DMIC_BE_ID;
if (drv_data->dmic_codec_id == DMIC) {
links[i].codecs = dmic_codec;
links[i].num_codecs = ARRAY_SIZE(dmic_codec);
} else {
/* Use dummy codec if codec id not specified */
- links[i].codecs = &asoc_dummy_dlc;
+ links[i].codecs = &snd_soc_dummy_dlc;
links[i].num_codecs = 1;
}
links[i].cpus = pdm_dmic;
links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
- if (drv_data->platform == REMBRANDT) {
+ switch (drv_data->acp_rev) {
+ case ACP_RMB_PCI_ID:
links[i].platforms = platform_rmb_component;
links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
- } else {
+ break;
+ case ACP63_PCI_ID:
+ links[i].platforms = platform_acp63_component;
+ links[i].num_platforms = ARRAY_SIZE(platform_acp63_component);
+ break;
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ links[i].platforms = platform_acp70_component;
+ links[i].num_platforms = ARRAY_SIZE(platform_acp70_component);
+ break;
+ default:
links[i].platforms = platform_component;
links[i].num_platforms = ARRAY_SIZE(platform_component);
+ break;
}
links[i].ops = &acp_card_dmic_ops;
- links[i].dpcm_capture = 1;
+ links[i].capture_only = 1;
}
card->dai_link = links;
@@ -1216,6 +1797,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH);
+EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, "SND_SOC_AMD_MACH");
+MODULE_DESCRIPTION("AMD ACP Common Machine driver");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h
index 165f407697c0..f94c30c20f20 100644
--- a/sound/soc/amd/acp/acp-mach.h
+++ b/sound/soc/amd/acp/acp-mach.h
@@ -18,12 +18,19 @@
#include <linux/module.h>
#include <sound/soc.h>
+#include "acp_common.h"
+
#define TDM_CHANNELS 8
+#define ACP_OPS(priv, cb) ((priv)->ops.cb)
+
+#define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata)
+
enum be_id {
HEADSET_BE_ID = 0,
AMP_BE_ID,
DMIC_BE_ID,
+ BT_BE_ID,
};
enum cpu_endpoints {
@@ -41,24 +48,35 @@ enum codec_endpoints {
MAX98360A,
RT5682S,
NAU8825,
+ NAU8821,
+ MAX98388,
+ ES83XX,
};
-enum platform_end_point {
- RENOIR = 0,
- REMBRANDT,
+struct acp_mach_ops {
+ int (*probe)(struct snd_soc_card *card);
+ int (*configure_link)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
+ int (*configure_widgets)(struct snd_soc_card *card);
+ int (*suspend_pre)(struct snd_soc_card *card);
+ int (*resume_post)(struct snd_soc_card *card);
};
struct acp_card_drvdata {
unsigned int hs_cpu_id;
unsigned int amp_cpu_id;
+ unsigned int bt_cpu_id;
unsigned int dmic_cpu_id;
unsigned int hs_codec_id;
unsigned int amp_codec_id;
+ unsigned int bt_codec_id;
unsigned int dmic_codec_id;
unsigned int dai_fmt;
- unsigned int platform;
+ unsigned int acp_rev;
struct clk *wclk;
struct clk *bclk;
+ struct acp_mach_ops ops;
+ struct snd_soc_acpi_mach *acpi_mach;
+ void *mach_priv;
bool soc_mclk;
bool tdm_mode;
};
@@ -67,4 +85,55 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card);
int acp_legacy_dai_links_create(struct snd_soc_card *card);
extern const struct dmi_system_id acp_quirk_table[];
+static inline int acp_ops_probe(struct snd_soc_card *card)
+{
+ int ret = 1;
+ struct acp_card_drvdata *priv = acp_get_drvdata(card);
+
+ if (ACP_OPS(priv, probe))
+ ret = ACP_OPS(priv, probe)(card);
+ return ret;
+}
+
+static inline int acp_ops_configure_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ int ret = 1;
+ struct acp_card_drvdata *priv = acp_get_drvdata(card);
+
+ if (ACP_OPS(priv, configure_link))
+ ret = ACP_OPS(priv, configure_link)(card, dai_link);
+ return ret;
+}
+
+static inline int acp_ops_configure_widgets(struct snd_soc_card *card)
+{
+ int ret = 1;
+ struct acp_card_drvdata *priv = acp_get_drvdata(card);
+
+ if (ACP_OPS(priv, configure_widgets))
+ ret = ACP_OPS(priv, configure_widgets)(card);
+ return ret;
+}
+
+static inline int acp_ops_suspend_pre(struct snd_soc_card *card)
+{
+ int ret = 1;
+ struct acp_card_drvdata *priv = acp_get_drvdata(card);
+
+ if (ACP_OPS(priv, suspend_pre))
+ ret = ACP_OPS(priv, suspend_pre)(card);
+ return ret;
+}
+
+static inline int acp_ops_resume_post(struct snd_soc_card *card)
+{
+ int ret = 1;
+ struct acp_card_drvdata *priv = acp_get_drvdata(card);
+
+ if (ACP_OPS(priv, resume_post))
+ ret = ACP_OPS(priv, resume_post)(card);
+ return ret;
+}
+
#endif
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index 8154fbfd1229..f83708755ed1 100644
--- a/sound/soc/amd/acp/acp-pci.c
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -16,6 +16,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include "amd.h"
#include "../mach-config.h"
@@ -25,36 +26,92 @@
#define ACP3x_REG_START 0x1240000
#define ACP3x_REG_END 0x125C000
-static struct platform_device *dmic_dev;
-static struct platform_device *pdev;
+static irqreturn_t irq_handler(int irq, void *data)
+{
+ struct acp_chip_info *chip = data;
-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,
- },
-};
+ if (chip && chip->acp_hw_ops && chip->acp_hw_ops->irq)
+ return chip->acp_hw_ops->irq(irq, chip);
-static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+ 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);
- if (flag != FLAG_AMD_LEGACY)
+ if (flag != FLAG_AMD_LEGACY && flag != FLAG_AMD_LEGACY_ONLY_DMIC)
return -ENODEV;
chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
@@ -74,76 +131,89 @@ 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->acp_rev = ACP3X_DEV;
+ 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->acp_rev = ACP6X_DEV;
+ 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:
+ case 0x71:
+ case 0x72:
+ 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);
ret = -EINVAL;
goto release_regions;
}
-
- 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;
- }
+ chip->flag = flag;
addr = pci_resource_start(pci, 0);
chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
if (!chip->base) {
ret = -ENOMEM;
- goto unregister_dmic_dev;
+ goto release_regions;
}
- res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL);
- if (!res) {
- ret = -ENOMEM;
- goto unregister_dmic_dev;
- }
+ chip->addr = addr;
- 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->acp_hw_ops_init(chip);
+ ret = acp_hw_init(chip);
+ if (ret)
+ 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;
}
- memset(&pdevinfo, 0, sizeof(pdevinfo));
+ check_acp_config(pci, chip);
+ if (!chip->is_pdm_dev && !chip->is_i2s_config)
+ goto skip_pdev_creation;
- 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;
+ ret = create_acp_platform_devs(pci, chip, addr);
+ if (ret < 0) {
+ dev_err(&pci->dev, "ACP platform devices creation failed\n");
+ goto de_init;
}
+ chip->chip_pdev = chip->acp_plat_dev;
+ chip->dev = &chip->acp_plat_dev->dev;
+
+ acp_machine_select(chip);
+
+ INIT_LIST_HEAD(&chip->stream_list);
+ spin_lock_init(&chip->acp_lock);
+skip_pdev_creation:
+ dev_set_drvdata(&pci->dev, chip);
+ pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
+ pm_runtime_use_autosuspend(&pci->dev);
+ pm_runtime_put_noidle(&pci->dev);
+ 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:
@@ -152,12 +222,58 @@ disable_pci:
return ret;
};
+static int snd_acp_suspend(struct device *dev)
+{
+ struct acp_chip_info *chip;
+ int ret;
+
+ chip = dev_get_drvdata(dev);
+ ret = acp_hw_deinit(chip);
+ if (ret)
+ dev_err(dev, "ACP de-init failed\n");
+ return ret;
+}
+
+static int snd_acp_resume(struct device *dev)
+{
+ struct acp_chip_info *chip;
+ int ret;
+
+ chip = dev_get_drvdata(dev);
+ ret = acp_hw_init(chip);
+ if (ret)
+ dev_err(dev, "ACP init failed\n");
+
+ 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 = {
+ 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)
{
- if (dmic_dev)
- platform_device_unregister(dmic_dev);
- if (pdev)
- platform_device_unregister(pdev);
+ struct acp_chip_info *chip;
+ int ret;
+
+ chip = pci_get_drvdata(pci);
+ pm_runtime_forbid(&pci->dev);
+ pm_runtime_get_noresume(&pci->dev);
+ 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");
}
/* PCI IDs */
@@ -173,8 +289,13 @@ static struct pci_driver snd_amd_acp_pci_driver = {
.id_table = acp_pci_ids,
.probe = acp_pci_probe,
.remove = acp_pci_remove,
+ .driver = {
+ .pm = pm_ptr(&acp_pm_ops),
+ },
};
module_pci_driver(snd_amd_acp_pci_driver);
+MODULE_DESCRIPTION("AMD ACP common PCI support");
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c
index 66ec6b6a5972..1bfc34c2aa53 100644
--- a/sound/soc/amd/acp/acp-pdm.c
+++ b/sound/soc/amd/acp/acp-pdm.c
@@ -25,45 +25,37 @@
#define DRV_NAME "acp-pdm"
-#define PDM_DMA_STAT 0x10
-#define PDM_DMA_INTR_MASK 0x10000
-#define PDM_DEC_64 0x2
-#define PDM_CLK_FREQ_MASK 0x07
-#define PDM_MISC_CTRL_MASK 0x10
-#define PDM_ENABLE 0x01
-#define PDM_DISABLE 0x00
-#define DMA_EN_MASK 0x02
-#define DELAY_US 5
-#define PDM_TIMEOUT 1000
-#define ACP_REGION2_OFFSET 0x02000000
-
static int acp_dmic_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
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);
size_dmic = frames_to_bytes(substream->runtime,
substream->runtime->buffer_size);
- physical_addr = stream->reg_offset + MEM_WINDOW_START;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ physical_addr = ACP7x_DMIC_MEM_WINDOW_START;
+ else
+ 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;
}
@@ -72,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;
@@ -80,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;
@@ -116,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);
@@ -135,13 +127,14 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ 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;
}
@@ -151,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;
@@ -160,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;
}
@@ -171,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 |= ~PDM_DMA_INTR_MASK;
- writel(ext_int_ctrl, 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(chip, 0));
}
const struct snd_soc_dai_ops acp_dmic_dai_ops = {
@@ -187,7 +180,8 @@ const struct snd_soc_dai_ops acp_dmic_dai_ops = {
.startup = acp_dmic_dai_startup,
.shutdown = acp_dmic_dai_shutdown,
};
-EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, SND_SOC_ACP_COMMON);
+EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, "SND_SOC_ACP_COMMON");
+MODULE_DESCRIPTION("AMD ACP Audio PDM controller");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c
index f220378ec20e..b25ac5612808 100644
--- a/sound/soc/amd/acp/acp-platform.c
+++ b/sound/soc/amd/acp/acp-platform.c
@@ -21,6 +21,7 @@
#include <linux/dma-mapping.h>
#include "amd.h"
+#include "acp-mach.h"
#define DRV_NAME "acp_i2s_dma"
@@ -66,114 +67,132 @@ static const struct snd_pcm_hardware acp_pcm_hardware_capture = {
.periods_max = CAPTURE_MAX_NUM_PERIODS,
};
-int acp_machine_select(struct acp_dev_data *adata)
-{
- struct snd_soc_acpi_mach *mach;
- int size;
-
- 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;
- }
-
- 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");
+static const struct snd_pcm_hardware acp6x_pcm_hardware_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(acp_machine_select, SND_SOC_ACP_COMMON);
+static const struct snd_pcm_hardware acp6x_pcm_hardware_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
-static irqreturn_t i2s_irq_handler(int irq, void *data)
+void config_pte_for_stream(struct acp_chip_info *chip, struct acp_stream *stream)
{
- 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;
+ struct acp_resource *rsrc = chip->rsrc;
+ u32 reg_val;
- if (!adata)
- return IRQ_NONE;
-
- 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;
+ reg_val = rsrc->sram_pte_offset;
+ stream->reg_offset = 0x02000000;
- return IRQ_NONE;
-}
+ 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);
-static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream)
-{
- struct acp_resource *rsrc = adata->rsrc;
- u32 pte_reg, pte_size, reg_val;
+ 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);
- /* Use ATU base Group5 */
- pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5;
- pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5;
- stream->reg_offset = 0x02000000;
+ 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);
- /* Group Enable */
- reg_val = rsrc->sram_pte_offset;
- writel(reg_val | BIT(31), adata->acp_base + pte_reg);
- writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size);
- 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");
-static 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;
- val = stream->pte_offset;
+ switch (chip->acp_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ switch (stream->dai_id) {
+ case I2S_SP_INSTANCE:
+ if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
+ val = 0x0;
+ else
+ val = 0x1000;
+ break;
+ case I2S_BT_INSTANCE:
+ if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
+ val = 0x2000;
+ else
+ val = 0x3000;
+ break;
+ case I2S_HS_INSTANCE:
+ if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
+ val = 0x4000;
+ else
+ val = 0x5000;
+ break;
+ case DMIC_INSTANCE:
+ val = 0x6000;
+ break;
+ default:
+ dev_err(chip->dev, "Invalid dai id %x\n", stream->dai_id);
+ return;
+ }
+ break;
+ default:
+ val = stream->pte_offset;
+ break;
+ }
for (page_idx = 0; page_idx < num_pages; page_idx++) {
/* 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;
addr += PAGE_SIZE;
}
}
+EXPORT_SYMBOL_NS_GPL(config_acp_dma, "SND_SOC_ACP_COMMON");
static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream)
{
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;
@@ -182,11 +201,38 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
return -ENOMEM;
stream->substream = substream;
+ chip = dev_get_drvdata(dev->parent);
+ switch (chip->acp_rev) {
+ case ACP63_PCI_ID:
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = acp6x_pcm_hardware_playback;
+ else
+ runtime->hw = acp6x_pcm_hardware_capture;
+ break;
+ default:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = acp_pcm_hardware_playback;
+ else
+ runtime->hw = acp_pcm_hardware_capture;
+ break;
+ }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- runtime->hw = acp_pcm_hardware_playback;
- else
- runtime->hw = acp_pcm_hardware_capture;
+ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE);
+ if (ret) {
+ dev_err(component->dev, "set hw constraint HW_PARAM_PERIOD_BYTES failed\n");
+ kfree(stream);
+ return ret;
+ }
+
+ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, DMA_SIZE);
+ if (ret) {
+ dev_err(component->dev, "set hw constraint HW_PARAM_BUFFER_BYTES failed\n");
+ kfree(stream);
+ return ret;
+ }
ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
@@ -196,11 +242,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;
}
@@ -209,13 +255,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;
}
@@ -224,7 +271,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;
@@ -232,7 +279,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;
@@ -256,13 +303,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;
@@ -280,41 +327,33 @@ 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);
+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);
+EXPORT_SYMBOL_NS_GPL(acp_platform_unregister, "SND_SOC_ACP_COMMON");
MODULE_DESCRIPTION("AMD ACP PCM Driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c
index 5c455cc04113..7e9c07488dcc 100644
--- a/sound/soc/amd/acp/acp-rembrandt.c
+++ b/sound/soc/amd/acp/acp-rembrandt.c
@@ -19,72 +19,20 @@
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <linux/dma-mapping.h>
+#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"
#define DRV_NAME "acp_asoc_rembrandt"
-#define ACP6X_PGFSM_CONTROL 0x1024
-#define ACP6X_PGFSM_STATUS 0x1028
-
-#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
-
-#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01
-#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00
-#define ACP_PGFSM_STATUS_MASK 0x03
-#define ACP_POWERED_ON 0x00
-#define ACP_POWER_ON_IN_PROGRESS 0x01
-#define ACP_POWERED_OFF 0x02
-#define ACP_POWER_OFF_IN_PROGRESS 0x03
-
-#define ACP_ERROR_MASK 0x20000000
-#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
-
-
-static int rmb_acp_init(void __iomem *base);
-static int rmb_acp_deinit(void __iomem *base);
-
-static struct acp_resource rsrc = {
- .offset = 0,
- .no_of_ctrls = 2,
- .irqp_used = 1,
- .soc_mclk = true,
- .irq_reg_offset = 0x1a00,
- .i2s_pin_cfg_offset = 0x1440,
- .i2s_mode = 0x0a,
- .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,
- },
- {},
-};
+#define MP1_C2PMSG_69 0x3B10A14
+#define MP1_C2PMSG_85 0x3B10A54
+#define MP1_C2PMSG_93 0x3B10A74
static struct snd_soc_dai_driver acp_rmb_dai[] = {
{
@@ -111,7 +59,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-i2s-bt",
@@ -137,7 +84,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-i2s-hs",
@@ -163,7 +109,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-pdm-dmic",
@@ -180,142 +125,29 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
},
};
-static int acp6x_power_on(void __iomem *base)
-{
- u32 val;
- int timeout;
-
- val = readl(base + ACP6X_PGFSM_STATUS);
-
- if (val == ACP_POWERED_ON)
- return 0;
-
- if ((val & ACP_PGFSM_STATUS_MASK) !=
- ACP_POWER_ON_IN_PROGRESS)
- writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
- base + ACP6X_PGFSM_CONTROL);
- timeout = 0;
- while (++timeout < 500) {
- val = readl(base + ACP6X_PGFSM_STATUS);
- if (!val)
- return 0;
- udelay(1);
- }
- return -ETIMEDOUT;
-}
-
-static int acp6x_power_off(void __iomem *base)
-{
- u32 val;
- int timeout;
-
- writel(ACP_PGFSM_CNTL_POWER_OFF_MASK,
- base + ACP6X_PGFSM_CONTROL);
- timeout = 0;
- while (++timeout < 500) {
- val = readl(base + ACP6X_PGFSM_STATUS);
- if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF)
- return 0;
- udelay(1);
- }
- return -ETIMEDOUT;
-}
-
-static int acp6x_reset(void __iomem *base)
-{
- u32 val;
- int timeout;
-
- writel(1, base + ACP_SOFT_RESET);
- timeout = 0;
- while (++timeout < 500) {
- val = readl(base + ACP_SOFT_RESET);
- if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
- break;
- cpu_relax();
- }
- writel(0, base + ACP_SOFT_RESET);
- timeout = 0;
- while (++timeout < 500) {
- val = readl(base + ACP_SOFT_RESET);
- if (!val)
- return 0;
- cpu_relax();
- }
- return -ETIMEDOUT;
-}
-
-static void acp6x_enable_interrupts(struct acp_dev_data *adata)
-{
- struct acp_resource *rsrc = adata->rsrc;
- u32 ext_intr_ctrl;
-
- writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));
- ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
- ext_intr_ctrl |= ACP_ERROR_MASK;
- writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
-}
-
-static void acp6x_disable_interrupts(struct acp_dev_data *adata)
-{
- struct acp_resource *rsrc = adata->rsrc;
-
- writel(ACP_EXT_INTR_STAT_CLEAR_MASK,
- ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
- writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));
-}
-
-static int rmb_acp_init(void __iomem *base)
-{
- int ret;
-
- /* power on */
- ret = acp6x_power_on(base);
- if (ret) {
- pr_err("ACP power on failed\n");
- return ret;
- }
- writel(0x01, base + ACP_CONTROL);
-
- /* Reset */
- ret = acp6x_reset(base);
- if (ret) {
- pr_err("ACP reset failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static int rmb_acp_deinit(void __iomem *base)
+static int acp6x_master_clock_generate(struct device *dev)
{
- int ret = 0;
-
- /* Reset */
- ret = acp6x_reset(base);
- if (ret) {
- pr_err("ACP reset failed\n");
- return ret;
- }
-
- writel(0x00, base + ACP_CONTROL);
-
- /* power off */
- ret = acp6x_power_off(base);
- if (ret) {
- pr_err("ACP power off failed\n");
- return ret;
- }
-
- 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;
+ int ret;
chip = dev_get_platdata(&pdev->dev);
if (!chip || !chip->base) {
@@ -323,72 +155,93 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (chip->acp_rev != ACP6X_DEV) {
+ if (chip->acp_rev != ACP_RMB_PCI_ID) {
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
return -ENODEV;
}
- rmb_acp_init(chip->base);
+ chip->dev = dev;
+ chip->dai_driver = acp_rmb_dai;
+ chip->num_dai = ARRAY_SIZE(acp_rmb_dai);
- 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;
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk) {
+ ret = acp6x_master_clock_generate(dev);
+ if (ret)
+ return ret;
}
-
- 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;
+ ret = acp_hw_en_interrupts(chip);
+ if (ret) {
+ dev_err(dev, "ACP en-interrupts failed\n");
+ return ret;
}
-
- 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->machines = snd_soc_acpi_amd_rmb_acp_machines;
- acp_machine_select(adata);
-
- dev_set_drvdata(dev, adata);
- acp6x_enable_interrupts(adata);
acp_platform_register(dev);
-
+ pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
return 0;
}
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;
- rmb_acp_deinit(chip->base);
+ ret = acp_hw_dis_interrupts(chip);
+ if (ret)
+ dev_err(dev, "ACP dis-interrupts failed\n");
- acp6x_disable_interrupts(adata);
acp_platform_unregister(dev);
+ pm_runtime_disable(&pdev->dev);
}
+static int rmb_pcm_resume(struct device *dev)
+{
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
+ struct acp_stream *stream;
+ struct snd_pcm_substream *substream;
+ snd_pcm_uframes_t buf_in_frames;
+ u64 buf_size;
+
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk)
+ acp6x_master_clock_generate(dev);
+
+ 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(&chip->acp_lock);
+ return 0;
+}
+
+static const struct dev_pm_ops rmb_dma_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume)
+};
+
static struct platform_driver rembrandt_driver = {
.probe = rembrandt_audio_probe,
- .remove_new = rembrandt_audio_remove,
+ .remove = rembrandt_audio_remove,
.driver = {
.name = "acp_asoc_rembrandt",
+ .pm = pm_ptr(&rmb_dma_pm_ops),
},
};
module_platform_driver(rembrandt_driver);
MODULE_DESCRIPTION("AMD ACP Rembrandt Driver");
-MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
+MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c
index b3cbc7f19ec5..04f6d70b6a92 100644
--- a/sound/soc/amd/acp/acp-renoir.c
+++ b/sound/soc/amd/acp/acp-renoir.c
@@ -20,72 +20,13 @@
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
#include "amd.h"
+#include "acp-mach.h"
#define DRV_NAME "acp_asoc_renoir"
-#define ACP_SOFT_RST_DONE_MASK 0x00010001
-
-#define ACP_PWR_ON_MASK 0x01
-#define ACP_PWR_OFF_MASK 0x00
-#define ACP_PGFSM_STAT_MASK 0x03
-#define ACP_POWERED_ON 0x00
-#define ACP_PWR_ON_IN_PROGRESS 0x01
-#define ACP_POWERED_OFF 0x02
-#define DELAY_US 5
-#define ACP_TIMEOUT 500
-
-#define ACP_ERROR_MASK 0x20000000
-#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
-
-static struct acp_resource rsrc = {
- .offset = 20,
- .no_of_ctrls = 1,
- .irqp_used = 0,
- .irq_reg_offset = 0x1800,
- .i2s_pin_cfg_offset = 0x1400,
- .i2s_mode = 0x04,
- .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",
- },
- {},
-};
-
static struct snd_soc_dai_driver acp_renoir_dai[] = {
{
.name = "acp-i2s-sp",
@@ -111,7 +52,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-i2s-bt",
@@ -137,7 +77,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-pdm-dmic",
@@ -154,112 +93,11 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
},
};
-static int acp3x_power_on(void __iomem *base)
-{
- u32 val;
-
- val = readl(base + ACP_PGFSM_STATUS);
-
- if (val == ACP_POWERED_ON)
- return 0;
-
- if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS)
- writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL);
-
- return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT);
-}
-
-static int acp3x_power_off(void __iomem *base)
-{
- u32 val;
-
- writel(ACP_PWR_OFF_MASK, base + ACP_PGFSM_CONTROL);
-
- return readl_poll_timeout(base + ACP_PGFSM_STATUS, val,
- (val & ACP_PGFSM_STAT_MASK) == ACP_POWERED_OFF,
- DELAY_US, ACP_TIMEOUT);
-}
-
-static int acp3x_reset(void __iomem *base)
-{
- u32 val;
- int ret;
-
- writel(1, base + ACP_SOFT_RESET);
-
- ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
- DELAY_US, ACP_TIMEOUT);
- if (ret)
- return ret;
-
- writel(0, base + ACP_SOFT_RESET);
-
- return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
-}
-
-static void acp3x_enable_interrupts(struct acp_dev_data *adata)
-{
- struct acp_resource *rsrc = adata->rsrc;
- u32 ext_intr_ctrl;
-
- writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));
- ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
- ext_intr_ctrl |= ACP_ERROR_MASK;
- writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
-}
-
-static void acp3x_disable_interrupts(struct acp_dev_data *adata)
-{
- struct acp_resource *rsrc = adata->rsrc;
-
- writel(ACP_EXT_INTR_STAT_CLEAR_MASK,
- ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
- writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));
-}
-
-static int rn_acp_init(void __iomem *base)
-{
- int ret;
-
- /* power on */
- ret = acp3x_power_on(base);
- if (ret)
- return ret;
-
- writel(0x01, base + ACP_CONTROL);
-
- /* Reset */
- ret = acp3x_reset(base);
- if (ret)
- return ret;
-
- return 0;
-}
-static int rn_acp_deinit(void __iomem *base)
-{
- int ret = 0;
-
- /* Reset */
- ret = acp3x_reset(base);
- if (ret)
- return ret;
-
- writel(0x00, base + ACP_CONTROL);
-
- /* power off */
- ret = acp3x_power_off(base);
- if (ret)
- return ret;
-
- return 0;
-}
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);
@@ -268,80 +106,86 @@ static int renoir_audio_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (chip->acp_rev != ACP3X_DEV) {
+ if (chip->acp_rev != ACP_RN_PCI_ID) {
dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
return -ENODEV;
}
- ret = rn_acp_init(chip->base);
- if (ret) {
- dev_err(&pdev->dev, "ACP Init failed\n");
- return -EINVAL;
- }
-
- 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;
- }
+ chip->dev = dev;
+ chip->dai_driver = acp_renoir_dai;
+ chip->num_dai = ARRAY_SIZE(acp_renoir_dai);
- adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!adata->acp_base)
- return -ENOMEM;
-
- 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->machines = snd_soc_acpi_amd_acp_machines;
- acp_machine_select(adata);
+ }
- dev_set_drvdata(dev, adata);
- acp3x_enable_interrupts(adata);
acp_platform_register(dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
return 0;
}
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;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
int ret;
- chip = dev_get_platdata(&pdev->dev);
-
- acp3x_disable_interrupts(adata);
-
- ret = rn_acp_deinit(chip->base);
+ ret = acp_hw_dis_interrupts(chip);
if (ret)
- dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret));
+ dev_err(dev, "ACP dis-interrupts failed\n");
acp_platform_unregister(dev);
}
+static int rn_pcm_resume(struct device *dev)
+{
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
+ struct acp_stream *stream;
+ struct snd_pcm_substream *substream;
+ snd_pcm_uframes_t buf_in_frames;
+ u64 buf_size;
+
+ 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(&chip->acp_lock);
+ return 0;
+}
+
+static const struct dev_pm_ops rn_dma_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(NULL, rn_pcm_resume)
+};
+
static struct platform_driver renoir_driver = {
.probe = renoir_audio_probe,
- .remove_new = renoir_audio_remove,
+ .remove = renoir_audio_remove,
.driver = {
.name = "acp_asoc_renoir",
+ .pm = pm_ptr(&rn_dma_pm_ops),
},
};
module_platform_driver(renoir_driver);
MODULE_DESCRIPTION("AMD ACP Renoir Driver");
-MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
+MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
new file mode 100644
index 000000000000..fae94b9edd5a
--- /dev/null
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * acp-sdw-legacy-mach - ASoC legacy Machine driver for AMD SoundWire platforms
+ */
+
+#include <linux/bitmap.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "soc_amd_sdw_common.h"
+#include "../../codecs/rt711.h"
+
+static unsigned long soc_sdw_quirk = RT711_JD1;
+static int quirk_override = -1;
+module_param_named(quirk, quirk_override, int, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
+static void log_quirks(struct device *dev)
+{
+ if (SOC_JACK_JDSRC(soc_sdw_quirk))
+ dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
+ 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)
+{
+ soc_sdw_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id soc_sdw_quirk_table[] = {
+ {
+ .callback = soc_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AMD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"),
+ },
+ .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),
+ },
+ {
+ .callback = soc_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0DD3"),
+ },
+ .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, "0DD4"),
+ },
+ .driver_data = (void *)(ASOC_SDW_CODEC_SPKR),
+ },
+ {}
+};
+
+static const struct snd_soc_ops sdw_ops = {
+ .startup = asoc_sdw_startup,
+ .prepare = asoc_sdw_prepare,
+ .trigger = asoc_sdw_trigger,
+ .hw_params = asoc_sdw_hw_params,
+ .hw_free = asoc_sdw_hw_free,
+ .shutdown = asoc_sdw_shutdown,
+};
+
+static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
+
+static int create_sdw_dailink(struct snd_soc_card *card,
+ struct asoc_sdw_dailink *soc_dai,
+ struct snd_soc_dai_link **dai_links,
+ int *be_id, struct snd_soc_codec_conf **codec_conf,
+ struct snd_soc_dai_link_component *sdw_platform_component)
+{
+ struct device *dev = card->dev;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
+ struct asoc_sdw_endpoint *soc_end;
+ int cpu_pin_id;
+ int stream;
+ int ret;
+
+ list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
+ if (soc_end->name_prefix) {
+ (*codec_conf)->dlc.name = soc_end->codec_name;
+ (*codec_conf)->name_prefix = soc_end->name_prefix;
+ (*codec_conf)++;
+ }
+
+ if (soc_end->include_sidecar) {
+ ret = soc_end->codec_info->add_sidecar(card, dai_links, codec_conf);
+ if (ret)
+ return ret;
+ }
+ }
+
+ for_each_pcm_streams(stream) {
+ static const char * const sdw_stream_name[] = {
+ "SDW%d-PIN%d-PLAYBACK",
+ "SDW%d-PIN%d-CAPTURE",
+ "SDW%d-PIN%d-PLAYBACK-%s",
+ "SDW%d-PIN%d-CAPTURE-%s",
+ };
+ struct snd_soc_dai_link_ch_map *codec_maps;
+ struct snd_soc_dai_link_component *codecs;
+ struct snd_soc_dai_link_component *cpus;
+ int num_cpus = hweight32(soc_dai->link_mask[stream]);
+ int num_codecs = soc_dai->num_devs[stream];
+ int playback, capture;
+ int j = 0;
+ char *name;
+
+ if (!soc_dai->num_devs[stream])
+ continue;
+
+ soc_end = list_first_entry(&soc_dai->endpoints,
+ struct asoc_sdw_endpoint, list);
+
+ *be_id = soc_end->dai_info->dailink[stream];
+ if (*be_id < 0) {
+ dev_err(dev, "Invalid dailink id %d\n", *be_id);
+ return -EINVAL;
+ }
+
+ switch (amd_ctx->acp_rev) {
+ case ACP63_PCI_REV:
+ ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask - 1),
+ *be_id, &cpu_pin_id, dev);
+ if (ret)
+ return ret;
+ break;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_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;
+ }
+ /* create stream name according to first link id */
+ if (ctx->append_dai_type) {
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ sdw_stream_name[stream + 2],
+ ffs(soc_end->link_mask) - 1,
+ cpu_pin_id,
+ type_strings[soc_end->dai_info->dai_type]);
+ } else {
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ sdw_stream_name[stream],
+ ffs(soc_end->link_mask) - 1,
+ cpu_pin_id);
+ }
+ if (!name)
+ return -ENOMEM;
+
+ cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
+ if (!codecs)
+ return -ENOMEM;
+
+ codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
+ if (!codec_maps)
+ return -ENOMEM;
+
+ list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
+ if (!soc_end->dai_info->direction[stream])
+ continue;
+
+ int link_num = ffs(soc_end->link_mask) - 1;
+
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SDW%d Pin%d",
+ link_num, cpu_pin_id);
+ dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name);
+ if (!cpus->dai_name)
+ return -ENOMEM;
+
+ codec_maps[j].cpu = 0;
+ codec_maps[j].codec = j;
+
+ codecs[j].name = soc_end->codec_name;
+ codecs[j].dai_name = soc_end->dai_info->dai_name;
+ j++;
+ }
+
+ WARN_ON(j != num_codecs);
+
+ playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
+
+ asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
+ cpus, num_cpus, sdw_platform_component,
+ 1, codecs, num_codecs,
+ 0, asoc_sdw_rtd_init, &sdw_ops);
+ /*
+ * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
+ * based on wait_for_completion(), tag them as 'nonatomic'.
+ */
+ (*dai_links)->nonatomic = true;
+ (*dai_links)->ch_maps = codec_maps;
+
+ list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
+ if (soc_end->dai_info->init)
+ soc_end->dai_info->init(card, *dai_links,
+ soc_end->codec_info,
+ playback);
+ }
+
+ (*dai_links)++;
+ }
+
+ return 0;
+}
+
+static int create_sdw_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ struct asoc_sdw_dailink *soc_dais,
+ struct snd_soc_codec_conf **codec_conf)
+{
+ struct device *dev = card->dev;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
+ struct snd_soc_dai_link_component *sdw_platform_component;
+ int ret;
+
+ sdw_platform_component = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!sdw_platform_component)
+ return -ENOMEM;
+
+ switch (amd_ctx->acp_rev) {
+ case ACP63_PCI_REV:
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_PCI_REV:
+ sdw_platform_component->name = "amd_ps_sdw_dma.0";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* generate DAI links by each sdw link */
+ while (soc_dais->initialised) {
+ int current_be_id = 0;
+
+ ret = create_sdw_dailink(card, soc_dais, dai_links,
+ &current_be_id, codec_conf, sdw_platform_component);
+ if (ret)
+ return ret;
+
+ /* Update the be_id to match the highest ID used for SDW link */
+ if (*be_id < current_be_id)
+ *be_id = current_be_id;
+
+ soc_dais++;
+ }
+
+ return 0;
+}
+
+static int create_dmic_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm)
+{
+ struct device *dev = card->dev;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
+ struct snd_soc_dai_link_component *pdm_cpu;
+ struct snd_soc_dai_link_component *pdm_platform;
+ int ret;
+
+ pdm_cpu = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
+ if (!pdm_cpu)
+ return -ENOMEM;
+
+ pdm_platform = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
+ if (!pdm_platform)
+ return -ENOMEM;
+
+ switch (amd_ctx->acp_rev) {
+ case ACP63_PCI_REV:
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_PCI_REV:
+ pdm_cpu->name = "acp_ps_pdm_dma.0";
+ pdm_platform->name = "acp_ps_pdm_dma.0";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *be_id = ACP_DMIC_BE_ID;
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec",
+ 0, 1, // DMIC only supports capture
+ pdm_cpu->name, pdm_platform->name,
+ "dmic-codec.0", "dmic-hifi", no_pcm,
+ asoc_sdw_dmic_init, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
+
+ return 0;
+}
+
+static int soc_card_dai_links_create(struct snd_soc_card *card)
+{
+ struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+ int sdw_be_num = 0, dmic_num = 0;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL;
+ struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL;
+ struct snd_soc_aux_dev *soc_aux;
+ struct snd_soc_codec_conf *codec_conf;
+ struct snd_soc_dai_link *dai_links;
+ int num_devs = 0;
+ int num_ends = 0;
+ int num_aux = 0;
+ int num_confs;
+ int num_links;
+ int be_id = 0;
+ int ret;
+
+ ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
+ if (ret < 0) {
+ dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
+ return ret;
+ }
+
+ num_confs = num_ends;
+
+ /* One per DAI link, worst case is a DAI link for every endpoint */
+ soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL);
+ if (!soc_dais)
+ return -ENOMEM;
+
+ /* One per endpoint, ie. each DAI on each codec/amp */
+ soc_ends = kcalloc(num_ends, sizeof(*soc_ends), GFP_KERNEL);
+ if (!soc_ends)
+ return -ENOMEM;
+
+ soc_aux = devm_kcalloc(dev, num_aux, sizeof(*soc_aux), GFP_KERNEL);
+ if (!soc_aux)
+ return -ENOMEM;
+
+ ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs);
+ if (ret < 0)
+ return ret;
+
+ sdw_be_num = ret;
+
+ /* enable dmic */
+ if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num)
+ dmic_num = 1;
+
+ dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num);
+
+ codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL);
+ if (!codec_conf)
+ return -ENOMEM;
+
+ /* allocate BE dailinks */
+ num_links = sdw_be_num + dmic_num;
+ dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
+ if (!dai_links)
+ return -ENOMEM;
+
+ card->codec_conf = codec_conf;
+ card->num_configs = num_confs;
+ card->dai_link = dai_links;
+ card->num_links = num_links;
+ card->aux_dev = soc_aux;
+ card->num_aux_devs = num_aux;
+
+ /* SDW */
+ if (sdw_be_num) {
+ ret = create_sdw_dailinks(card, &dai_links, &be_id,
+ soc_dais, &codec_conf);
+ if (ret)
+ return ret;
+ }
+
+ /* dmic */
+ if (dmic_num > 0) {
+ if (ctx->ignore_internal_dmic) {
+ dev_warn(dev, "Ignoring ACP DMIC\n");
+ } else {
+ ret = create_dmic_dailinks(card, &dai_links, &be_id, 0);
+ if (ret)
+ return ret;
+ }
+ }
+
+ WARN_ON(codec_conf != card->codec_conf + card->num_configs);
+ WARN_ON(dai_links != card->dai_link + card->num_links);
+
+ return ret;
+}
+
+static int mc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
+ struct snd_soc_card *card;
+ struct amd_mc_ctx *amd_ctx;
+ struct asoc_sdw_mc_private *ctx;
+ int amp_num = 0, i;
+ int ret;
+
+ amd_ctx = devm_kzalloc(&pdev->dev, sizeof(*amd_ctx), GFP_KERNEL);
+ if (!amd_ctx)
+ return -ENOMEM;
+
+ amd_ctx->acp_rev = mach->mach_params.subsystem_rev;
+ amd_ctx->max_sdw_links = ACP63_SDW_MAX_LINKS;
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
+ ctx->private = amd_ctx;
+ card = &ctx->card;
+ card->dev = &pdev->dev;
+ card->name = "amd-soundwire";
+ card->owner = THIS_MODULE;
+ card->late_probe = asoc_sdw_card_late_probe;
+
+ 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);
+
+ dmi_check_system(soc_sdw_quirk_table);
+
+ if (quirk_override != -1) {
+ dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ soc_sdw_quirk, quirk_override);
+ soc_sdw_quirk = quirk_override;
+ }
+
+ log_quirks(card->dev);
+
+ ctx->mc_quirk = soc_sdw_quirk;
+ dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk);
+ /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
+ for (i = 0; i < ctx->codec_info_list_count; i++)
+ codec_info_list[i].amp_num = 0;
+
+ ret = soc_card_dai_links_create(card);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * the default amp_num is zero for each codec and
+ * amp_num will only be increased for active amp
+ * codecs on used platform
+ */
+ for (i = 0; i < ctx->codec_info_list_count; i++)
+ amp_num += codec_info_list[i].amp_num;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ " cfg-amp:%d", amp_num);
+ if (!card->components)
+ return -ENOMEM;
+ if (mach->mach_params.dmic_num) {
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s mic:dmic cfg-mics:%d",
+ card->components,
+ mach->mach_params.dmic_num);
+ if (!card->components)
+ return -ENOMEM;
+ }
+
+ /* Register the card */
+ ret = devm_snd_soc_register_card(card->dev, card);
+ if (ret) {
+ dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ asoc_sdw_mc_dailink_exit_loop(card);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, card);
+
+ return ret;
+}
+
+static void mc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ asoc_sdw_mc_dailink_exit_loop(card);
+}
+
+static const struct platform_device_id mc_id_table[] = {
+ { "amd_sdw", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, mc_id_table);
+
+static struct platform_driver soc_sdw_driver = {
+ .driver = {
+ .name = "amd_sdw",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mc_probe,
+ .remove = mc_remove,
+ .id_table = mc_id_table,
+};
+
+module_platform_driver(soc_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC AMD SoundWire Legacy Generic Machine driver");
+MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
+MODULE_IMPORT_NS("SND_SOC_AMD_SDW_MACH");
diff --git a/sound/soc/amd/acp/acp-sdw-mach-common.c b/sound/soc/amd/acp/acp-sdw-mach-common.c
new file mode 100644
index 000000000000..e5f394dc2f4c
--- /dev/null
+++ b/sound/soc/amd/acp/acp-sdw-mach-common.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * acp-sdw-mach-common - Common machine driver helper functions for
+ * legacy(No DSP) stack and SOF stack.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include "soc_amd_sdw_common.h"
+
+int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev)
+{
+ switch (sdw_link_id) {
+ case AMD_SDW0:
+ switch (be_id) {
+ case SOC_SDW_JACK_OUT_DAI_ID:
+ *cpu_pin_id = ACP63_SW0_AUDIO0_TX;
+ break;
+ case SOC_SDW_JACK_IN_DAI_ID:
+ *cpu_pin_id = ACP63_SW0_AUDIO0_RX;
+ break;
+ case SOC_SDW_AMP_OUT_DAI_ID:
+ *cpu_pin_id = ACP63_SW0_AUDIO1_TX;
+ break;
+ case SOC_SDW_AMP_IN_DAI_ID:
+ *cpu_pin_id = ACP63_SW0_AUDIO1_RX;
+ break;
+ case SOC_SDW_DMIC_DAI_ID:
+ *cpu_pin_id = ACP63_SW0_AUDIO2_RX;
+ break;
+ default:
+ dev_err(dev, "Invalid be id:%d\n", be_id);
+ return -EINVAL;
+ }
+ break;
+ case AMD_SDW1:
+ switch (be_id) {
+ case SOC_SDW_JACK_OUT_DAI_ID:
+ case SOC_SDW_AMP_OUT_DAI_ID:
+ *cpu_pin_id = ACP63_SW1_AUDIO0_TX;
+ break;
+ case SOC_SDW_JACK_IN_DAI_ID:
+ case SOC_SDW_AMP_IN_DAI_ID:
+ case SOC_SDW_DMIC_DAI_ID:
+ *cpu_pin_id = ACP63_SW1_AUDIO0_RX;
+ break;
+ default:
+ dev_err(dev, "invalid be_id:%d\n", be_id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid link id:%d\n", sdw_link_id);
+ return -EINVAL;
+ }
+ return 0;
+}
+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/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
new file mode 100644
index 000000000000..5677ae63fca9
--- /dev/null
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * acp-sdw-sof-mach - ASoC Machine driver for AMD SoundWire platforms
+ */
+
+#include <linux/bitmap.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "soc_amd_sdw_common.h"
+#include "../../codecs/rt711.h"
+
+static unsigned long sof_sdw_quirk = RT711_JD1;
+static int quirk_override = -1;
+module_param_named(quirk, quirk_override, int, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
+static void log_quirks(struct device *dev)
+{
+ if (SOC_JACK_JDSRC(sof_sdw_quirk))
+ dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
+ SOC_JACK_JDSRC(sof_sdw_quirk));
+ if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC)
+ dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n");
+}
+
+static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
+{
+ sof_sdw_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id sof_sdw_quirk_table[] = {
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AMD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"),
+ },
+ .driver_data = (void *)RT711_JD2,
+ },
+ {}
+};
+
+static struct snd_soc_dai_link_component platform_component[] = {
+ {
+ /* name might be overridden during probe */
+ .name = "0000:04:00.5",
+ }
+};
+
+static const struct snd_soc_ops sdw_ops = {
+ .startup = asoc_sdw_startup,
+ .prepare = asoc_sdw_prepare,
+ .trigger = asoc_sdw_trigger,
+ .hw_params = asoc_sdw_hw_params,
+ .hw_free = asoc_sdw_hw_free,
+ .shutdown = asoc_sdw_shutdown,
+};
+
+static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
+
+static int create_sdw_dailink(struct snd_soc_card *card,
+ struct asoc_sdw_dailink *sof_dai,
+ struct snd_soc_dai_link **dai_links,
+ int *be_id, struct snd_soc_codec_conf **codec_conf)
+{
+ struct device *dev = card->dev;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private;
+ struct asoc_sdw_endpoint *sof_end;
+ int cpu_pin_id;
+ int stream;
+ int ret;
+
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (sof_end->name_prefix) {
+ (*codec_conf)->dlc.name = sof_end->codec_name;
+ (*codec_conf)->name_prefix = sof_end->name_prefix;
+ (*codec_conf)++;
+ }
+
+ if (sof_end->include_sidecar) {
+ ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
+ if (ret)
+ return ret;
+ }
+ }
+
+ for_each_pcm_streams(stream) {
+ static const char * const sdw_stream_name[] = {
+ "SDW%d-PIN%d-PLAYBACK",
+ "SDW%d-PIN%d-CAPTURE",
+ "SDW%d-PIN%d-PLAYBACK-%s",
+ "SDW%d-PIN%d-CAPTURE-%s",
+ };
+ struct snd_soc_dai_link_ch_map *codec_maps;
+ struct snd_soc_dai_link_component *codecs;
+ struct snd_soc_dai_link_component *cpus;
+ int num_cpus = hweight32(sof_dai->link_mask[stream]);
+ int num_codecs = sof_dai->num_devs[stream];
+ int playback, capture;
+ int j = 0;
+ char *name;
+
+ if (!sof_dai->num_devs[stream])
+ continue;
+
+ sof_end = list_first_entry(&sof_dai->endpoints,
+ struct asoc_sdw_endpoint, list);
+
+ *be_id = sof_end->dai_info->dailink[stream];
+ if (*be_id < 0) {
+ dev_err(dev, "Invalid dailink id %d\n", *be_id);
+ return -EINVAL;
+ }
+
+ switch (amd_ctx->acp_rev) {
+ case ACP63_PCI_REV:
+ ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask - 1),
+ *be_id, &cpu_pin_id, dev);
+ if (ret)
+ return ret;
+ break;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_PCI_REV:
+ ret = get_acp70_cpu_pin_id(ffs(sof_end->link_mask - 1),
+ *be_id, &cpu_pin_id, dev);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* create stream name according to first link id */
+ if (ctx->append_dai_type) {
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ sdw_stream_name[stream + 2],
+ ffs(sof_end->link_mask) - 1,
+ cpu_pin_id,
+ type_strings[sof_end->dai_info->dai_type]);
+ } else {
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ sdw_stream_name[stream],
+ ffs(sof_end->link_mask) - 1,
+ cpu_pin_id);
+ }
+ if (!name)
+ return -ENOMEM;
+
+ cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
+ if (!codecs)
+ return -ENOMEM;
+
+ codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
+ if (!codec_maps)
+ return -ENOMEM;
+
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (!sof_end->dai_info->direction[stream])
+ continue;
+
+ int link_num = ffs(sof_end->link_mask) - 1;
+
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SDW%d Pin%d",
+ link_num, cpu_pin_id);
+ if (!cpus->dai_name)
+ return -ENOMEM;
+ dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name);
+
+ codec_maps[j].cpu = 0;
+ codec_maps[j].codec = j;
+
+ codecs[j].name = sof_end->codec_name;
+ codecs[j].dai_name = sof_end->dai_info->dai_name;
+ j++;
+ }
+
+ WARN_ON(j != num_codecs);
+
+ playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
+
+ asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
+ cpus, num_cpus, platform_component,
+ ARRAY_SIZE(platform_component), codecs, num_codecs,
+ 1, asoc_sdw_rtd_init, &sdw_ops);
+
+ /*
+ * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
+ * based on wait_for_completion(), tag them as 'nonatomic'.
+ */
+ (*dai_links)->nonatomic = true;
+ (*dai_links)->ch_maps = codec_maps;
+
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (sof_end->dai_info->init)
+ sof_end->dai_info->init(card, *dai_links,
+ sof_end->codec_info,
+ playback);
+ }
+
+ (*dai_links)++;
+ }
+
+ return 0;
+}
+
+static int create_sdw_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ struct asoc_sdw_dailink *sof_dais,
+ struct snd_soc_codec_conf **codec_conf)
+{
+ int ret;
+
+ /* generate DAI links by each sdw link */
+ while (sof_dais->initialised) {
+ int current_be_id = 0;
+
+ ret = create_sdw_dailink(card, sof_dais, dai_links,
+ &current_be_id, codec_conf);
+ if (ret)
+ return ret;
+
+ /* Update the be_id to match the highest ID used for SDW link */
+ if (*be_id < current_be_id)
+ *be_id = current_be_id;
+
+ sof_dais++;
+ }
+
+ return 0;
+}
+
+static int create_dmic_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm)
+{
+ struct device *dev = card->dev;
+ int ret;
+
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec",
+ 0, 1, // DMIC only supports capture
+ "acp-sof-dmic", platform_component->name,
+ "dmic-codec", "dmic-hifi", no_pcm,
+ asoc_sdw_dmic_init, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
+
+ return 0;
+}
+
+static int sof_card_dai_links_create(struct snd_soc_card *card)
+{
+ struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+ int sdw_be_num = 0, dmic_num = 0;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ struct asoc_sdw_endpoint *sof_ends __free(kfree) = NULL;
+ struct asoc_sdw_dailink *sof_dais __free(kfree) = NULL;
+ struct snd_soc_aux_dev *sof_aux;
+ struct snd_soc_codec_conf *codec_conf;
+ struct snd_soc_dai_link *dai_links;
+ int num_devs = 0;
+ int num_ends = 0;
+ int num_aux = 0;
+ int num_links;
+ int be_id = 0;
+ int ret;
+
+ ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
+ if (ret < 0) {
+ dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
+ return ret;
+ }
+
+ /* One per DAI link, worst case is a DAI link for every endpoint */
+ sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL);
+ if (!sof_dais)
+ return -ENOMEM;
+
+ /* One per endpoint, ie. each DAI on each codec/amp */
+ sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
+ if (!sof_ends)
+ return -ENOMEM;
+
+ sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL);
+ if (!sof_aux)
+ return -ENOMEM;
+
+ ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs);
+ if (ret < 0)
+ return ret;
+
+ sdw_be_num = ret;
+
+ /* enable dmic */
+ if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num)
+ dmic_num = 1;
+
+ dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num);
+
+ codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
+ if (!codec_conf)
+ return -ENOMEM;
+
+ /* allocate BE dailinks */
+ num_links = sdw_be_num + dmic_num;
+ dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
+ if (!dai_links)
+ return -ENOMEM;
+
+ card->codec_conf = codec_conf;
+ card->num_configs = num_devs;
+ card->dai_link = dai_links;
+ card->num_links = num_links;
+ card->aux_dev = sof_aux;
+ card->num_aux_devs = num_aux;
+
+ /* SDW */
+ if (sdw_be_num) {
+ ret = create_sdw_dailinks(card, &dai_links, &be_id,
+ sof_dais, &codec_conf);
+ if (ret)
+ return ret;
+ }
+
+ /* dmic */
+ if (dmic_num > 0) {
+ if (ctx->ignore_internal_dmic) {
+ dev_warn(dev, "Ignoring ACP DMIC\n");
+ } else {
+ ret = create_dmic_dailinks(card, &dai_links, &be_id, 1);
+ if (ret)
+ return ret;
+ }
+ }
+
+ WARN_ON(codec_conf != card->codec_conf + card->num_configs);
+ WARN_ON(dai_links != card->dai_link + card->num_links);
+
+ return ret;
+}
+
+static int mc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
+ struct snd_soc_card *card;
+ struct amd_mc_ctx *amd_ctx;
+ struct asoc_sdw_mc_private *ctx;
+ int amp_num = 0, i;
+ int ret;
+
+ amd_ctx = devm_kzalloc(&pdev->dev, sizeof(*amd_ctx), GFP_KERNEL);
+ if (!amd_ctx)
+ return -ENOMEM;
+
+ amd_ctx->acp_rev = mach->mach_params.subsystem_rev;
+ amd_ctx->max_sdw_links = ACP63_SDW_MAX_LINKS;
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
+ ctx->private = amd_ctx;
+ card = &ctx->card;
+ card->dev = &pdev->dev;
+ card->name = "amd-soundwire";
+ card->owner = THIS_MODULE;
+ card->late_probe = asoc_sdw_card_late_probe;
+
+ snd_soc_card_set_drvdata(card, ctx);
+
+ dmi_check_system(sof_sdw_quirk_table);
+
+ if (quirk_override != -1) {
+ dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ sof_sdw_quirk, quirk_override);
+ sof_sdw_quirk = quirk_override;
+ }
+
+ log_quirks(card->dev);
+
+ ctx->mc_quirk = sof_sdw_quirk;
+ /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
+ for (i = 0; i < ctx->codec_info_list_count; i++)
+ codec_info_list[i].amp_num = 0;
+
+ ret = sof_card_dai_links_create(card);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * the default amp_num is zero for each codec and
+ * amp_num will only be increased for active amp
+ * codecs on used platform
+ */
+ for (i = 0; i < ctx->codec_info_list_count; i++)
+ amp_num += codec_info_list[i].amp_num;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ " cfg-amp:%d", amp_num);
+ if (!card->components)
+ return -ENOMEM;
+
+ /* Register the card */
+ ret = devm_snd_soc_register_card(card->dev, card);
+ if (ret) {
+ dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ asoc_sdw_mc_dailink_exit_loop(card);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, card);
+
+ return ret;
+}
+
+static void mc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ asoc_sdw_mc_dailink_exit_loop(card);
+}
+
+static const struct platform_device_id mc_id_table[] = {
+ { "amd_sof_sdw", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, mc_id_table);
+
+static struct platform_driver sof_sdw_driver = {
+ .driver = {
+ .name = "amd_sof_sdw",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mc_probe,
+ .remove = mc_remove,
+ .id_table = mc_id_table,
+};
+
+module_platform_driver(sof_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC AMD SoundWire Generic Machine driver");
+MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
+MODULE_IMPORT_NS("SND_SOC_AMD_SDW_MACH");
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 99a7d3879340..6215e31ecedd 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
//
@@ -28,7 +28,6 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = {
.hs_codec_id = RT5682,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682_max_data = {
@@ -38,7 +37,6 @@ static struct acp_card_drvdata sof_rt5682_max_data = {
.hs_codec_id = RT5682,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
@@ -48,7 +46,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
.hs_codec_id = RT5682S,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_max_data = {
@@ -58,7 +55,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
.hs_codec_id = RT5682S,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_nau8825_data = {
@@ -69,7 +65,6 @@ static struct acp_card_drvdata sof_nau8825_data = {
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
.soc_mclk = true,
- .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
@@ -80,29 +75,22 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
.soc_mclk = true,
- .tdm_mode = false,
};
-static const struct snd_kcontrol_new acp_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_soc_dapm_widget acp_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
+static struct acp_card_drvdata sof_nau8821_max98388_data = {
+ .hs_cpu_id = I2S_SP,
+ .amp_cpu_id = I2S_HS,
+ .bt_cpu_id = I2S_BT,
+ .hs_codec_id = NAU8821,
+ .amp_codec_id = MAX98388,
+ .soc_mclk = true,
};
static int acp_sof_probe(struct platform_device *pdev)
{
- struct snd_soc_card *card = NULL;
+ struct snd_soc_card *card;
struct device *dev = &pdev->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
const struct dmi_system_id *dmi_id;
struct acp_card_drvdata *acp_card_drvdata;
int ret;
@@ -117,27 +105,23 @@ static int acp_sof_probe(struct platform_device *pdev)
card->dev = dev;
card->owner = THIS_MODULE;
card->name = pdev->id_entry->name;
- card->dapm_widgets = acp_widgets;
- card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
- card->controls = acp_controls;
- card->num_controls = ARRAY_SIZE(acp_controls);
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+ /* Widgets and controls added per-codec in acp-mach-common.c */
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
if (dmi_id && dmi_id->driver_data)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
- acp_sofdsp_dai_links_create(card);
+ acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
+ ret = acp_sofdsp_dai_links_create(card);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n");
ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret) {
- dev_err(&pdev->dev,
- "devm_snd_soc_register_card(%s) failed: %d\n",
- card->name, ret);
- return ret;
- }
-
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to register card(%s)\n", card->name);
return 0;
}
@@ -166,8 +150,14 @@ static const struct platform_device_id board_ids[] = {
.name = "rt5682s-hs-rt1019",
.driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
},
+ {
+ .name = "nau8821-max",
+ .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data
+ },
{ }
};
+MODULE_DEVICE_TABLE(platform, board_ids);
+
static struct platform_driver acp_asoc_audio = {
.driver = {
.name = "sof_mach",
@@ -179,12 +169,6 @@ static struct platform_driver acp_asoc_audio = {
module_platform_driver(acp_asoc_audio);
-MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
-MODULE_DESCRIPTION("ACP chrome SOF audio support");
-MODULE_ALIAS("platform:rt5682-rt1019");
-MODULE_ALIAS("platform:rt5682-max");
-MODULE_ALIAS("platform:rt5682s-max");
-MODULE_ALIAS("platform:rt5682s-rt1019");
-MODULE_ALIAS("platform:nau8825-max");
-MODULE_ALIAS("platform:rt5682s-hs-rt1019");
+MODULE_IMPORT_NS("SND_SOC_AMD_MACH");
+MODULE_DESCRIPTION("ACP SOF Machine Driver");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
new file mode 100644
index 000000000000..141ea4787d99
--- /dev/null
+++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Machine driver for AMD ACP Audio engine using ES8336 codec.
+//
+// Copyright 2023 Marian Postevca <posteuca@mutex.one>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <sound/soc-acpi.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#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"
+
+#define get_mach_priv(card) ((struct acp3x_es83xx_private *)((acp_get_drvdata(card))->mach_priv))
+
+#define DUAL_CHANNEL 2
+
+#define ES83XX_ENABLE_DMIC BIT(4)
+#define ES83XX_48_MHZ_MCLK BIT(5)
+
+struct acp3x_es83xx_private {
+ bool speaker_on;
+ bool headphone_on;
+ unsigned long quirk;
+ struct snd_soc_component *codec;
+ struct device *codec_dev;
+ struct gpio_desc *gpio_speakers, *gpio_headphone;
+ struct acpi_gpio_params enable_spk_gpio, enable_hp_gpio;
+ struct acpi_gpio_mapping gpio_mapping[3];
+ struct snd_soc_dapm_route mic_map[2];
+};
+
+static const unsigned int channels[] = {
+ DUAL_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+#define ES83xx_12288_KHZ_MCLK_FREQ (48000 * 256)
+#define ES83xx_48_MHZ_MCLK_FREQ (48000 * 1000)
+
+static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static int acp3x_es83xx_codec_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *codec_dai;
+ struct acp3x_es83xx_private *priv;
+ unsigned int freq;
+ int ret;
+
+ runtime = substream->runtime;
+ rtd = snd_soc_substream_to_rtd(substream);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ priv = get_mach_priv(rtd->card);
+
+ if (priv->quirk & ES83XX_48_MHZ_MCLK) {
+ dev_dbg(priv->codec_dev, "using a 48Mhz MCLK\n");
+ freq = ES83xx_48_MHZ_MCLK_FREQ;
+ } else {
+ dev_dbg(priv->codec_dev, "using a 12.288Mhz MCLK\n");
+ freq = ES83xx_12288_KHZ_MCLK_FREQ;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ return 0;
+}
+
+static struct snd_soc_jack es83xx_jack;
+
+static struct snd_soc_jack_pin es83xx_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_soc_dapm_widget acp3x_es83xx_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+
+ SND_SOC_DAPM_SUPPLY("Headphone Power", SND_SOC_NOPM, 0, 0,
+ acp3x_es83xx_headphone_power_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
+ acp3x_es83xx_speaker_power_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route acp3x_es83xx_audio_map[] = {
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Headphone", NULL, "Headphone Power"},
+
+ /*
+ * There is no separate speaker output instead the speakers are muxed to
+ * the HP outputs. The mux is controlled Speaker and/or headphone switch.
+ */
+ {"Speaker", NULL, "HPOL"},
+ {"Speaker", NULL, "HPOR"},
+ {"Speaker", NULL, "Speaker Power"},
+};
+
+
+static const struct snd_kcontrol_new acp3x_es83xx_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static int acp3x_es83xx_configure_widgets(struct snd_soc_card *card)
+{
+ card->dapm_widgets = acp3x_es83xx_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(acp3x_es83xx_widgets);
+ card->controls = acp3x_es83xx_controls;
+ card->num_controls = ARRAY_SIZE(acp3x_es83xx_controls);
+ card->dapm_routes = acp3x_es83xx_audio_map;
+ card->num_dapm_routes = ARRAY_SIZE(acp3x_es83xx_audio_map);
+
+ return 0;
+}
+
+static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct acp3x_es83xx_private *priv = get_mach_priv(card);
+
+ dev_dbg(priv->codec_dev, "headphone power event = %d\n", event);
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ priv->headphone_on = true;
+ else
+ priv->headphone_on = false;
+
+ gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_on);
+ gpiod_set_value_cansleep(priv->gpio_headphone, priv->headphone_on);
+
+ return 0;
+}
+
+static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct acp3x_es83xx_private *priv = get_mach_priv(card);
+
+ dev_dbg(priv->codec_dev, "speaker power event: %d\n", event);
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ priv->speaker_on = true;
+ else
+ priv->speaker_on = false;
+
+ gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_on);
+ gpiod_set_value_cansleep(priv->gpio_headphone, priv->headphone_on);
+
+ return 0;
+}
+
+static int acp3x_es83xx_suspend_pre(struct snd_soc_card *card)
+{
+ struct acp3x_es83xx_private *priv = get_mach_priv(card);
+
+ /* We need to disable the jack in the machine driver suspend
+ * callback so that the CODEC suspend callback actually gets
+ * called. Without doing it, the CODEC suspend/resume
+ * callbacks do not get called if headphones are plugged in.
+ * This is because plugging in headphones keeps some supplies
+ * active, this in turn means that the lowest bias level
+ * that the CODEC can go to is SND_SOC_BIAS_STANDBY.
+ * If components do not set idle_bias_on to true then
+ * their suspend/resume callbacks do not get called.
+ */
+ dev_dbg(priv->codec_dev, "card suspend\n");
+ snd_soc_component_set_jack(priv->codec, NULL, NULL);
+ return 0;
+}
+
+static int acp3x_es83xx_resume_post(struct snd_soc_card *card)
+{
+ struct acp3x_es83xx_private *priv = get_mach_priv(card);
+
+ /* We disabled jack detection in suspend callback,
+ * enable it back.
+ */
+ dev_dbg(priv->codec_dev, "card resume\n");
+ snd_soc_component_set_jack(priv->codec, &es83xx_jack, NULL);
+ return 0;
+}
+
+static int acp3x_es83xx_configure_gpios(struct acp3x_es83xx_private *priv)
+{
+
+ priv->enable_spk_gpio.crs_entry_index = 0;
+ priv->enable_hp_gpio.crs_entry_index = 1;
+
+ priv->enable_spk_gpio.active_low = false;
+ priv->enable_hp_gpio.active_low = false;
+
+ priv->gpio_mapping[0].name = "speakers-enable-gpios";
+ priv->gpio_mapping[0].data = &priv->enable_spk_gpio;
+ priv->gpio_mapping[0].size = 1;
+ priv->gpio_mapping[0].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO;
+
+ priv->gpio_mapping[1].name = "headphone-enable-gpios";
+ priv->gpio_mapping[1].data = &priv->enable_hp_gpio;
+ priv->gpio_mapping[1].size = 1;
+ priv->gpio_mapping[1].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO;
+
+ dev_info(priv->codec_dev, "speaker gpio %d active %s, headphone gpio %d active %s\n",
+ priv->enable_spk_gpio.crs_entry_index,
+ str_low_high(priv->enable_spk_gpio.active_low),
+ priv->enable_hp_gpio.crs_entry_index,
+ str_low_high(priv->enable_hp_gpio.active_low));
+ return 0;
+}
+
+static int acp3x_es83xx_configure_mics(struct acp3x_es83xx_private *priv)
+{
+ int num_routes = 0;
+ int i;
+
+ if (!(priv->quirk & ES83XX_ENABLE_DMIC)) {
+ priv->mic_map[num_routes].sink = "MIC1";
+ priv->mic_map[num_routes].source = "Internal Mic";
+ num_routes++;
+ }
+
+ priv->mic_map[num_routes].sink = "MIC2";
+ priv->mic_map[num_routes].source = "Headset Mic";
+ num_routes++;
+
+ for (i = 0; i < num_routes; i++)
+ dev_info(priv->codec_dev, "%s is %s\n",
+ priv->mic_map[i].source, priv->mic_map[i].sink);
+
+ return num_routes;
+}
+
+static int acp3x_es83xx_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_card *card = runtime->card;
+ struct acp3x_es83xx_private *priv = get_mach_priv(card);
+ int ret = 0;
+ int num_routes;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &es83xx_jack, es83xx_jack_pins,
+ ARRAY_SIZE(es83xx_jack_pins));
+ if (ret) {
+ dev_err(card->dev, "jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(es83xx_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+
+ snd_soc_component_set_jack(codec, &es83xx_jack, NULL);
+
+ priv->codec = codec;
+ acp3x_es83xx_configure_gpios(priv);
+
+ ret = devm_acpi_dev_add_driver_gpios(priv->codec_dev, priv->gpio_mapping);
+ if (ret)
+ dev_warn(priv->codec_dev, "failed to add speaker gpio\n");
+
+ priv->gpio_speakers = gpiod_get_optional(priv->codec_dev, "speakers-enable",
+ priv->enable_spk_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpio_speakers)) {
+ dev_err(priv->codec_dev, "could not get speakers-enable GPIO\n");
+ return PTR_ERR(priv->gpio_speakers);
+ }
+
+ priv->gpio_headphone = gpiod_get_optional(priv->codec_dev, "headphone-enable",
+ priv->enable_hp_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpio_headphone)) {
+ dev_err(priv->codec_dev, "could not get headphone-enable GPIO\n");
+ return PTR_ERR(priv->gpio_headphone);
+ }
+
+ num_routes = acp3x_es83xx_configure_mics(priv);
+ if (num_routes > 0) {
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+
+ ret = snd_soc_dapm_add_routes(dapm, priv->mic_map, num_routes);
+ if (ret != 0)
+ device_remove_software_node(priv->codec_dev);
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_ops acp3x_es83xx_ops = {
+ .startup = acp3x_es83xx_codec_startup,
+};
+
+
+SND_SOC_DAILINK_DEF(codec,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
+
+static const struct dmi_system_id acp3x_es83xx_dmi_table[] = {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = (void *)(ES83XX_ENABLE_DMIC),
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = (void *)(ES83XX_ENABLE_DMIC),
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = (void *)(ES83XX_ENABLE_DMIC|ES83XX_48_MHZ_MCLK),
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+ },
+ .driver_data = (void *)(ES83XX_ENABLE_DMIC),
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1020"),
+ },
+ .driver_data = (void *)(ES83XX_ENABLE_DMIC),
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"),
+ },
+ .driver_data = (void *)(ES83XX_ENABLE_DMIC),
+ },
+ {}
+};
+
+static int acp3x_es83xx_configure_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
+{
+ link->codecs = codec;
+ link->num_codecs = ARRAY_SIZE(codec);
+ link->init = acp3x_es83xx_init;
+ link->ops = &acp3x_es83xx_ops;
+ link->dai_fmt = SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ return 0;
+}
+
+static int acp3x_es83xx_probe(struct snd_soc_card *card)
+{
+ int ret = 0;
+ struct device *dev = card->dev;
+ const struct dmi_system_id *dmi_id;
+
+ dmi_id = dmi_first_match(acp3x_es83xx_dmi_table);
+ if (dmi_id && dmi_id->driver_data) {
+ struct acp3x_es83xx_private *priv;
+ struct acp_card_drvdata *acp_drvdata;
+ struct acpi_device *adev;
+ struct device *codec_dev;
+
+ acp_drvdata = (struct acp_card_drvdata *)card->drvdata;
+
+ dev_info(dev, "matched DMI table with this system, trying to register sound card\n");
+
+ adev = acpi_dev_get_first_match_dev(acp_drvdata->acpi_mach->id, NULL, -1);
+ if (!adev) {
+ dev_err(dev, "Error cannot find '%s' dev\n", acp_drvdata->acpi_mach->id);
+ return -ENXIO;
+ }
+
+ codec_dev = acpi_get_first_physical_node(adev);
+ acpi_dev_put(adev);
+ if (!codec_dev) {
+ dev_warn(dev, "Error cannot find codec device, will defer probe\n");
+ return -EPROBE_DEFER;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ put_device(codec_dev);
+ return -ENOMEM;
+ }
+
+ priv->codec_dev = codec_dev;
+ priv->quirk = (unsigned long)dmi_id->driver_data;
+ acp_drvdata->mach_priv = priv;
+ dev_info(dev, "successfully probed the sound card\n");
+ } else {
+ ret = -ENODEV;
+ dev_warn(dev, "this system has a ES83xx codec defined in ACPI, but the driver doesn't have this system registered in DMI table\n");
+ }
+ return ret;
+}
+
+
+void acp3x_es83xx_init_ops(struct acp_mach_ops *ops)
+{
+ ops->probe = acp3x_es83xx_probe;
+ ops->configure_widgets = acp3x_es83xx_configure_widgets;
+ ops->configure_link = acp3x_es83xx_configure_link;
+ ops->suspend_pre = acp3x_es83xx_suspend_pre;
+ ops->resume_post = acp3x_es83xx_resume_post;
+}
diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.h b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.h
new file mode 100644
index 000000000000..03551ffdd9da
--- /dev/null
+++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2023 Marian Postevca <posteuca@mutex.one>
+ */
+
+#ifndef __ACP3X_ES83XX_H
+#define __ACP3X_ES83XX_H
+
+void acp3x_es83xx_init_ops(struct acp_mach_ops *ops);
+
+#endif
+
diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c
new file mode 100644
index 000000000000..10fb416b959d
--- /dev/null
+++ b/sound/soc/amd/acp/acp63.c
@@ -0,0 +1,298 @@
+// 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) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Syed Saba kareem <syed.sabakareem@amd.com>
+/*
+ * Hardware interface for ACP6.3 block
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#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"
+
+#define DRV_NAME "acp_asoc_acp63"
+
+#define CLK_PLL_PWR_REQ_N0 0X0006C2C0
+#define CLK_SPLL_FIELD_2_N0 0X0006C114
+#define CLK_PLL_REQ_N0 0X0006C0DC
+#define CLK_DFSBYPASS_CONTR 0X0006C2C8
+#define CLK_DFS_CNTL_N0 0X0006C1A4
+
+#define PLL_AUTO_STOP_REQ BIT(4)
+#define PLL_AUTO_START_REQ BIT(0)
+#define PLL_FRANCE_EN BIT(4)
+#define EXIT_DPF_BYPASS_0 BIT(16)
+#define EXIT_DPF_BYPASS_1 BIT(17)
+#define CLK0_DIVIDER 0X30
+
+union clk_pll_req_no {
+ struct {
+ u32 fb_mult_int : 9;
+ u32 reserved : 3;
+ u32 pll_spine_div : 4;
+ u32 gb_mult_frac : 16;
+ } bitfields, bits;
+ u32 clk_pll_req_no_reg;
+};
+
+static struct snd_soc_dai_driver acp63_dai[] = {
+{
+ .name = "acp-i2s-sp",
+ .id = I2S_SP_INSTANCE,
+ .playback = {
+ .stream_name = "I2S SP Playback",
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .stream_name = "I2S SP Capture",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &asoc_acp_cpu_dai_ops,
+},
+{
+ .name = "acp-i2s-bt",
+ .id = I2S_BT_INSTANCE,
+ .playback = {
+ .stream_name = "I2S BT Playback",
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .stream_name = "I2S BT Capture",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &asoc_acp_cpu_dai_ops,
+},
+{
+ .name = "acp-i2s-hs",
+ .id = I2S_HS_INSTANCE,
+ .playback = {
+ .stream_name = "I2S HS Playback",
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .stream_name = "I2S HS Capture",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &asoc_acp_cpu_dai_ops,
+},
+{
+ .name = "acp-pdm-dmic",
+ .id = DMIC_INSTANCE,
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &acp_dmic_dai_ops,
+},
+};
+
+static int acp63_i2s_master_clock_generate(struct acp_chip_info *chip)
+{
+ int rc;
+ u32 data;
+ union clk_pll_req_no clk_pll;
+
+ /* 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;
+
+ 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;
+ }
+
+ 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;
+ int ret;
+
+ chip = dev_get_platdata(&pdev->dev);
+ if (!chip || !chip->base) {
+ dev_err(&pdev->dev, "ACP chip data is NULL\n");
+ return -ENODEV;
+ }
+
+ if (chip->acp_rev != ACP63_PCI_ID) {
+ dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
+ return -ENODEV;
+ }
+
+ chip->dev = dev;
+ chip->dai_driver = acp63_dai;
+ chip->num_dai = ARRAY_SIZE(acp63_dai);
+
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk) {
+ ret = acp63_i2s_master_clock_generate(chip);
+ if (ret)
+ return ret;
+ }
+ 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);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ return 0;
+}
+
+static void acp63_audio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->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_platform_unregister(dev);
+ pm_runtime_disable(&pdev->dev);
+}
+
+static int acp63_pcm_resume(struct device *dev)
+{
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
+ struct acp_stream *stream;
+ struct snd_pcm_substream *substream;
+ snd_pcm_uframes_t buf_in_frames;
+ u64 buf_size;
+
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk)
+ acp63_i2s_master_clock_generate(chip);
+
+ 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(&chip->acp_lock);
+ return 0;
+}
+
+static const struct dev_pm_ops acp63_dma_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume)
+};
+
+static struct platform_driver acp63_driver = {
+ .probe = acp63_audio_probe,
+ .remove = acp63_audio_remove,
+ .driver = {
+ .name = "acp_asoc_acp63",
+ .pm = pm_ptr(&acp63_dma_pm_ops),
+ },
+};
+
+module_platform_driver(acp63_driver);
+
+MODULE_DESCRIPTION("AMD ACP acp63 Driver");
+MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c
new file mode 100644
index 000000000000..bca311c88139
--- /dev/null
+++ b/sound/soc/amd/acp/acp70.c
@@ -0,0 +1,228 @@
+// 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) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Syed Saba kareem <syed.sabakareem@amd.com>
+/*
+ * Hardware interface for ACP7.0 block
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/pci.h>
+#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 snd_soc_dai_driver acp70_dai[] = {
+{
+ .name = "acp-i2s-sp",
+ .id = I2S_SP_INSTANCE,
+ .playback = {
+ .stream_name = "I2S SP Playback",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "I2S SP Capture",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &asoc_acp_cpu_dai_ops,
+},
+{
+ .name = "acp-i2s-bt",
+ .id = I2S_BT_INSTANCE,
+ .playback = {
+ .stream_name = "I2S BT Playback",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "I2S BT Capture",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &asoc_acp_cpu_dai_ops,
+},
+{
+ .name = "acp-i2s-hs",
+ .id = I2S_HS_INSTANCE,
+ .playback = {
+ .stream_name = "I2S HS Playback",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .capture = {
+ .stream_name = "I2S HS Capture",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .ops = &asoc_acp_cpu_dai_ops,
+},
+{
+ .name = "acp-pdm-dmic",
+ .id = DMIC_INSTANCE,
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &acp_dmic_dai_ops,
+},
+};
+
+static int acp_acp70_audio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct acp_chip_info *chip;
+ int ret;
+
+ chip = dev_get_platdata(&pdev->dev);
+ if (!chip || !chip->base) {
+ dev_err(&pdev->dev, "ACP chip data is NULL\n");
+ return -ENODEV;
+ }
+
+ switch (chip->acp_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ break;
+ default:
+ dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
+ return -ENODEV;
+ }
+
+ chip->dev = dev;
+ chip->dai_driver = acp70_dai;
+ chip->num_dai = ARRAY_SIZE(acp70_dai);
+
+ /* 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;
+ }
+ 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);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ return 0;
+}
+
+static void acp_acp70_audio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->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_platform_unregister(dev);
+ pm_runtime_disable(&pdev->dev);
+}
+
+static int acp70_pcm_resume(struct device *dev)
+{
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
+ struct acp_stream *stream;
+ struct snd_pcm_substream *substream;
+ snd_pcm_uframes_t buf_in_frames;
+ u64 buf_size;
+
+ 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(&chip->acp_lock);
+ return 0;
+}
+
+static const struct dev_pm_ops acp70_dma_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(NULL, acp70_pcm_resume)
+};
+
+static struct platform_driver acp70_driver = {
+ .probe = acp_acp70_audio_probe,
+ .remove = acp_acp70_audio_remove,
+ .driver = {
+ .name = "acp_asoc_acp70",
+ .pm = pm_ptr(&acp70_dma_pm_ops),
+ },
+};
+
+module_platform_driver(acp70_driver);
+
+MODULE_DESCRIPTION("AMD ACP ACP70 Driver");
+MODULE_IMPORT_NS("SND_SOC_ACP_COMMON");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/acp/acp_common.h b/sound/soc/amd/acp/acp_common.h
new file mode 100644
index 000000000000..984685602e3d
--- /dev/null
+++ b/sound/soc/amd/acp/acp_common.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved
+ */
+
+/*
+ * acp_common.h - acp common header file
+ */
+
+#ifndef __ACP_COMMON_H
+#define __ACP_COMMON_H
+
+#define ACP_RN_PCI_ID 0x01
+#define ACP_VANGOGH_PCI_ID 0x50
+#define ACP_RMB_PCI_ID 0x6F
+#define ACP63_PCI_ID 0x63
+#define ACP70_PCI_ID 0x70
+#define ACP71_PCI_ID 0x71
+#define ACP72_PCI_ID 0x72
+
+#endif
diff --git a/sound/soc/amd/acp/amd-acp63-acpi-match.c b/sound/soc/amd/acp/amd-acp63-acpi-match.c
new file mode 100644
index 000000000000..9b6a49c051cd
--- /dev/null
+++ b/sound/soc/amd/acp/amd-acp63-acpi-match.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * amd-acp63-acpi-match.c - tables and support for ACP 6.3 platform
+ * ACPI enumeration.
+ *
+ * Copyright 2024 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 acp63_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_link_adr acp63_rt722_only[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt722_0_single_adr),
+ .adr_d = rt722_0_single_adr,
+ },
+ {}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = {
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_4_in_1_sdca,
+ .drv_name = "amd_sof_sdw",
+ .sof_tplg_filename = "sof-acp_6_3-rt711-l0-rt1316-l0-rt714-l1.tplg",
+ .fw_filename = "sof-acp_6_3.ri",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_sdw_machines);
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[] = {
+ {
+ .link_mask = BIT(0),
+ .links = acp63_rt722_only,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_4_in_1_sdca,
+ .drv_name = "amd_sdw",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sdw_machines);
+
+MODULE_DESCRIPTION("AMD ACP6.3 tables and support for ACPI enumeration");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
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..871b4f054a84
--- /dev/null
+++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c
@@ -0,0 +1,329 @@
+// 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_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_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_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_0_adr[] = {
+ {
+ .adr = 0x00003001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_1_cs35l56x4_1_adr[] = {
+ {
+ .adr = 0x00013001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ },
+ {
+ .adr = 0x00013001FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00013201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00013301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56x4_1_adr[] = {
+ {
+ .adr = 0x00013301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00013101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00013001FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_link_adr acp70_cs42l43_l1_cs35l56x4_l1[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs42l43_1_cs35l56x4_1_adr),
+ .adr_d = cs42l43_1_cs35l56x4_1_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp70_cs42l43_l0_cs35l56x4_l1[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56x4_1_adr),
+ .adr_d = cs35l56x4_1_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp70_cs35l56x4_l1[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56x4_1_adr),
+ .adr_d = cs35l56x4_1_adr,
+ },
+ {}
+};
+
+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",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp70_cs42l43_l0_cs35l56x4_l1,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(1),
+ .links = acp70_cs42l43_l1_cs35l56x4_l1,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(1),
+ .links = acp70_cs35l56x4_l1,
+ .drv_name = "amd_sdw",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sdw_machines);
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[] = {
+ {
+ .link_mask = BIT(0),
+ .links = acp70_rt722_only,
+ .drv_name = "amd_sof_sdw",
+ .sof_tplg_filename = "sof-acp_7_0-rt722-l0.tplg",
+ .fw_filename = "sof-acp_7_0.ri",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_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..27da2a862f1c
--- /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>
+
+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"}
+};
+
+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-sdw-acpi.c b/sound/soc/amd/acp/amd-sdw-acpi.c
new file mode 100644
index 000000000000..0160b0df26a0
--- /dev/null
+++ b/sound/soc/amd/acp/amd-sdw-acpi.c
@@ -0,0 +1,62 @@
+// 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) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * SDW AMD ACPI scan helper function
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/soundwire/sdw_amd.h>
+#include <linux/string.h>
+
+int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info)
+{
+ struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
+ u32 sdw_bitmap = 0;
+ u8 count = 0;
+ int ret;
+
+ if (!adev)
+ return -EINVAL;
+
+ /* Found controller, find links supported */
+ ret = fwnode_property_read_u32_array(acpi_fwnode_handle(adev),
+ "mipi-sdw-manager-list", &sdw_bitmap, 1);
+ if (ret) {
+ dev_err(&adev->dev,
+ "Failed to read mipi-sdw-manager-list: %d\n", ret);
+ return -EINVAL;
+ }
+ count = hweight32(sdw_bitmap);
+ /* Check count is within bounds */
+ if (count > info->count) {
+ dev_err(&adev->dev, "Manager count %d exceeds max %d\n",
+ count, info->count);
+ return -EINVAL;
+ }
+
+ if (!count) {
+ dev_dbg(&adev->dev, "No SoundWire Managers detected\n");
+ return -EINVAL;
+ }
+ dev_dbg(&adev->dev, "ACPI reports %d SoundWire Manager devices\n", count);
+ info->link_mask = sdw_bitmap;
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sdw_scan_controller, "SND_AMD_SOUNDWIRE_ACPI");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("AMD SoundWire ACPI helpers");
diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h
index 5f2119f42271..73a028e67246 100644
--- a/sound/soc/amd/acp/amd.h
+++ b/sound/soc/amd/acp/amd.h
@@ -16,11 +16,9 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dai.h>
+#include "acp_common.h"
#include "chip_offset_byte.h"
-#define ACP3X_DEV 3
-#define ACP6X_DEV 6
-
#define DMIC_INSTANCE 0x00
#define I2S_SP_INSTANCE 0x01
#define I2S_BT_INSTANCE 0x02
@@ -59,6 +57,14 @@
#define I2S_HS_TX_MEM_WINDOW_START 0x40A0000
#define I2S_HS_RX_MEM_WINDOW_START 0x40C0000
+#define ACP7x_I2S_SP_TX_MEM_WINDOW_START 0x4000000
+#define ACP7x_I2S_SP_RX_MEM_WINDOW_START 0x4200000
+#define ACP7x_I2S_BT_TX_MEM_WINDOW_START 0x4400000
+#define ACP7x_I2S_BT_RX_MEM_WINDOW_START 0x4600000
+#define ACP7x_I2S_HS_TX_MEM_WINDOW_START 0x4800000
+#define ACP7x_I2S_HS_RX_MEM_WINDOW_START 0x4A00000
+#define ACP7x_DMIC_MEM_WINDOW_START 0x4C00000
+
#define SP_PB_FIFO_ADDR_OFFSET 0x500
#define SP_CAPT_FIFO_ADDR_OFFSET 0x700
#define BT_PB_FIFO_ADDR_OFFSET 0x900
@@ -92,10 +98,78 @@
#define SLOT_WIDTH_24 0x18
#define SLOT_WIDTH_32 0x20
+#define ACP6X_PGFSM_CONTROL 0x1024
+#define ACP6X_PGFSM_STATUS 0x1028
+
+#define ACP63_PGFSM_CONTROL ACP6X_PGFSM_CONTROL
+#define ACP63_PGFSM_STATUS ACP6X_PGFSM_STATUS
+
+#define ACP70_PGFSM_CONTROL ACP6X_PGFSM_CONTROL
+#define ACP70_PGFSM_STATUS ACP6X_PGFSM_STATUS
+
+#define ACP_ZSC_DSP_CTRL 0x0001014
+#define ACP_ZSC_STS 0x0001018
+#define ACP_SOFT_RST_DONE_MASK 0x00010001
+
+#define ACP_PGFSM_CNTL_POWER_ON_MASK 0xffffffff
+#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00
+#define ACP_PGFSM_STATUS_MASK 0x03
+#define ACP_POWERED_ON 0x00
+#define ACP_POWER_ON_IN_PROGRESS 0x01
+#define ACP_POWERED_OFF 0x02
+#define ACP_POWER_OFF_IN_PROGRESS 0x03
+
+#define ACP_ERROR_MASK 0x20000000
+#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xffffffff
+
+#define ACP_TIMEOUT 500
+#define DELAY_US 5
+#define ACP_SUSPEND_DELAY_MS 2000
+
+#define PDM_DMA_STAT 0x10
+#define PDM_DMA_INTR_MASK 0x10000
+#define PDM_DEC_64 0x2
+#define PDM_CLK_FREQ_MASK 0x07
+#define PDM_MISC_CTRL_MASK 0x18
+#define PDM_ENABLE 0x01
+#define PDM_DISABLE 0x00
+#define DMA_EN_MASK 0x02
+#define DELAY_US 5
+#define PDM_TIMEOUT 1000
+#define ACP_REGION2_OFFSET 0x02000000
+
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 {
@@ -117,136 +191,175 @@ struct acp_resource {
int irqp_used;
bool soc_mclk;
u32 irq_reg_offset;
- u32 i2s_pin_cfg_offset;
- int i2s_mode;
u64 scratch_reg_offset;
u64 sram_pte_offset;
};
-struct acp_dev_data {
- char *name;
- struct device *dev;
- void __iomem *acp_base;
- unsigned int i2s_irq;
-
- bool tdm_mode;
- /* 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 tdm_tx_fmt[3];
- u32 tdm_rx_fmt[3];
+/**
+ * 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);
};
-union acp_i2stdm_mstrclkgen {
- struct {
- u32 i2stdm_master_mode : 1;
- u32 i2stdm_format_mode : 1;
- u32 i2stdm_lrclk_div_val : 9;
- u32 i2stdm_bclk_div_val : 11;
- u32:10;
- } bitfields, bits;
- u32 u32_all;
+enum acp_config {
+ ACP_CONFIG_0 = 0,
+ ACP_CONFIG_1,
+ ACP_CONFIG_2,
+ ACP_CONFIG_3,
+ ACP_CONFIG_4,
+ ACP_CONFIG_5,
+ ACP_CONFIG_6,
+ ACP_CONFIG_7,
+ ACP_CONFIG_8,
+ ACP_CONFIG_9,
+ ACP_CONFIG_10,
+ ACP_CONFIG_11,
+ ACP_CONFIG_12,
+ ACP_CONFIG_13,
+ ACP_CONFIG_14,
+ ACP_CONFIG_15,
+ ACP_CONFIG_16,
+ ACP_CONFIG_17,
+ ACP_CONFIG_18,
+ ACP_CONFIG_19,
+ 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 asoc_acp_i2s_probe(struct snd_soc_dai *dai);
int acp_platform_register(struct device *dev);
int acp_platform_unregister(struct device *dev);
-int acp_machine_select(struct acp_dev_data *adata);
-
+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);
+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);
-static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
+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_chip_info *chip);
+
+int restore_acp_i2s_params(struct snd_pcm_substream *substream,
+ struct acp_chip_info *chip, struct acp_stream *stream);
+
+void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip);
+
+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, low = 0, high = 0;
+ 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);
- low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW);
+ 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);
- low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
+ 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);
- return -EINVAL;
+ 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);
- low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW);
+ 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);
- low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
+ 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);
- return -EINVAL;
+ dev_err(chip->dev, "Invalid dai id %x\n", dai_id);
+ goto POINTER_RETURN_BYTES;
}
}
/* Get 64 bit value from two 32 bit registers */
byte_count = (high << 32) | low;
+POINTER_RETURN_BYTES:
return byte_count;
}
-
-static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
-{
- union acp_i2stdm_mstrclkgen mclkgen;
- u32 master_reg;
-
- switch (dai_id) {
- case I2S_SP_INSTANCE:
- master_reg = ACP_I2STDM0_MSTRCLKGEN;
- break;
- case I2S_BT_INSTANCE:
- master_reg = ACP_I2STDM1_MSTRCLKGEN;
- break;
- case I2S_HS_INSTANCE:
- master_reg = ACP_I2STDM2_MSTRCLKGEN;
- break;
- default:
- master_reg = ACP_I2STDM0_MSTRCLKGEN;
- break;
- }
-
- mclkgen.bits.i2stdm_master_mode = 0x1;
- mclkgen.bits.i2stdm_format_mode = 0x00;
-
- mclkgen.bits.i2stdm_bclk_div_val = adata->bclk_div;
- mclkgen.bits.i2stdm_lrclk_div_val = adata->lrclk_div;
- writel(mclkgen.u32_all, adata->acp_base + master_reg);
-}
#endif
diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h
index ce3948e0679c..82275c9de53a 100644
--- a/sound/soc/amd/acp/chip_offset_byte.h
+++ b/sound/soc/amd/acp/chip_offset_byte.h
@@ -12,60 +12,74 @@
#define _ACP_IP_OFFSET_HEADER
#define ACPAXI2AXI_ATU_CTRL 0xC40
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0xC00
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0xC04
+#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0xC08
+#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0xC0C
#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20
#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24
+#define GRP1_OFFSET 0x0
+#define GRP2_OFFSET 0x4000
+
#define ACP_PGFSM_CONTROL 0x141C
#define ACP_PGFSM_STATUS 0x1420
#define ACP_SOFT_RESET 0x1000
#define ACP_CONTROL 0x1004
+#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 */
-#define ACP_I2S_RX_RINGBUFADDR 0x2000
-#define ACP_I2S_RX_RINGBUFSIZE 0x2004
-#define ACP_I2S_RX_LINKPOSITIONCNTR 0x2008
-#define ACP_I2S_RX_FIFOADDR 0x200C
-#define ACP_I2S_RX_FIFOSIZE 0x2010
-#define ACP_I2S_RX_DMA_SIZE 0x2014
-#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x2018
-#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x201C
-#define ACP_I2S_RX_INTR_WATERMARK_SIZE 0x2020
-#define ACP_I2S_TX_RINGBUFADDR 0x2024
-#define ACP_I2S_TX_RINGBUFSIZE 0x2028
-#define ACP_I2S_TX_LINKPOSITIONCNTR 0x202C
-#define ACP_I2S_TX_FIFOADDR 0x2030
-#define ACP_I2S_TX_FIFOSIZE 0x2034
-#define ACP_I2S_TX_DMA_SIZE 0x2038
-#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x203C
-#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x2040
-#define ACP_I2S_TX_INTR_WATERMARK_SIZE 0x2044
-#define ACP_BT_RX_RINGBUFADDR 0x2048
-#define ACP_BT_RX_RINGBUFSIZE 0x204C
-#define ACP_BT_RX_LINKPOSITIONCNTR 0x2050
-#define ACP_BT_RX_FIFOADDR 0x2054
-#define ACP_BT_RX_FIFOSIZE 0x2058
-#define ACP_BT_RX_DMA_SIZE 0x205C
-#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x2060
-#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x2064
-#define ACP_BT_RX_INTR_WATERMARK_SIZE 0x2068
-#define ACP_BT_TX_RINGBUFADDR 0x206C
-#define ACP_BT_TX_RINGBUFSIZE 0x2070
-#define ACP_BT_TX_LINKPOSITIONCNTR 0x2074
-#define ACP_BT_TX_FIFOADDR 0x2078
-#define ACP_BT_TX_FIFOSIZE 0x207C
-#define ACP_BT_TX_DMA_SIZE 0x2080
-#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x2084
-#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x2088
-#define ACP_BT_TX_INTR_WATERMARK_SIZE 0x208C
+#define ACP_I2S_REG_ADDR(acp_adata, addr) \
+ ((addr) + (acp_adata->rsrc->irqp_used * \
+ acp_adata->rsrc->irq_reg_offset))
+
+#define ACP_I2S_RX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2000)
+#define ACP_I2S_RX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2004)
+#define ACP_I2S_RX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x2008)
+#define ACP_I2S_RX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x200C)
+#define ACP_I2S_RX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2010)
+#define ACP_I2S_RX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2014)
+#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x2018)
+#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x201C)
+#define ACP_I2S_RX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2020)
+#define ACP_I2S_TX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2024)
+#define ACP_I2S_TX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2028)
+#define ACP_I2S_TX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x202C)
+#define ACP_I2S_TX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2030)
+#define ACP_I2S_TX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2034)
+#define ACP_I2S_TX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2038)
+#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x203C)
+#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x2040)
+#define ACP_I2S_TX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2044)
+#define ACP_BT_RX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2048)
+#define ACP_BT_RX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x204C)
+#define ACP_BT_RX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x2050)
+#define ACP_BT_RX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2054)
+#define ACP_BT_RX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2058)
+#define ACP_BT_RX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x205C)
+#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x2060)
+#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x2064)
+#define ACP_BT_RX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2068)
+#define ACP_BT_TX_RINGBUFADDR(adata) ACP_I2S_REG_ADDR(adata, 0x206C)
+#define ACP_BT_TX_RINGBUFSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2070)
+#define ACP_BT_TX_LINKPOSITIONCNTR(adata) ACP_I2S_REG_ADDR(adata, 0x2074)
+#define ACP_BT_TX_FIFOADDR(adata) ACP_I2S_REG_ADDR(adata, 0x2078)
+#define ACP_BT_TX_FIFOSIZE(adata) ACP_I2S_REG_ADDR(adata, 0x207C)
+#define ACP_BT_TX_DMA_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x2080)
+#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(adata) ACP_I2S_REG_ADDR(adata, 0x2084)
+#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW(adata) ACP_I2S_REG_ADDR(adata, 0x2088)
+#define ACP_BT_TX_INTR_WATERMARK_SIZE(adata) ACP_I2S_REG_ADDR(adata, 0x208C)
+
#define ACP_HS_RX_RINGBUFADDR 0x3A90
#define ACP_HS_RX_RINGBUFSIZE 0x3A94
#define ACP_HS_RX_LINKPOSITIONCNTR 0x3A98
diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h
new file mode 100644
index 000000000000..3930cc46fa58
--- /dev/null
+++ b/sound/soc/amd/acp/soc_amd_sdw_common.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved
+ */
+
+/*
+ * soc_amd_sdw_common.h - prototypes for common helpers
+ */
+
+#ifndef SOC_AMD_SDW_COMMON_H
+#define SOC_AMD_SDW_COMMON_H
+
+#include <linux/bits.h>
+#include <linux/types.h>
+#include <sound/soc.h>
+#include <sound/soc_sdw_utils.h>
+
+#define ACP63_SDW_MAX_CPU_DAIS 8
+#define ACP63_SDW_MAX_LINKS 2
+
+#define AMD_SDW_MAX_GROUPS 9
+#define ACP63_PCI_REV 0x63
+#define ACP70_PCI_REV 0x70
+#define ACP71_PCI_REV 0x71
+#define ACP72_PCI_REV 0x72
+
+#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
+#define ACP63_SW0_AUDIO0_TX 0
+#define ACP63_SW0_AUDIO1_TX 1
+#define ACP63_SW0_AUDIO2_TX 2
+
+#define ACP63_SW0_AUDIO0_RX 3
+#define ACP63_SW0_AUDIO1_RX 4
+#define ACP63_SW0_AUDIO2_RX 5
+
+#define ACP63_SW1_AUDIO0_TX 0
+#define ACP63_SW1_AUDIO0_RX 1
+
+#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/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c
index 0543dda75b99..4ca1978020a9 100644
--- a/sound/soc/amd/acp3x-rt5682-max9836.c
+++ b/sound/soc/amd/acp3x-rt5682-max9836.c
@@ -28,6 +28,17 @@
#define DUAL_CHANNEL 2
static struct snd_soc_jack pco_jack;
+static struct snd_soc_jack_pin pco_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static struct clk *rt5682_dai_wclk;
static struct clk *rt5682_dai_bclk;
static struct gpio_desc *dmic_sel;
@@ -43,7 +54,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
@@ -86,11 +97,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk");
rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pco_jack,
+ pco_jack_pins,
+ ARRAY_SIZE(pco_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -113,7 +126,7 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
static int rt5682_clk_enable(struct snd_pcm_substream *substream)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
/* RT5682 will support only 48K output with 48M mclk */
clk_set_rate(rt5682_dai_wclk, 48000);
@@ -130,7 +143,7 @@ static int rt5682_clk_enable(struct snd_pcm_substream *substream)
static int acp3x_1015_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int srate, i, ret;
@@ -181,7 +194,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
static int acp3x_5682_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -199,7 +212,7 @@ static int acp3x_5682_startup(struct snd_pcm_substream *substream)
static int acp3x_max_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
@@ -215,9 +228,9 @@ static int acp3x_max_startup(struct snd_pcm_substream *substream)
static int acp3x_ec_dmic0_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->cap_i2s_instance = I2S_BT_INSTANCE;
@@ -304,8 +317,6 @@ static struct snd_soc_dai_link acp3x_dai[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP,
.init = acp3x_5682_init,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &acp3x_5682_ops,
SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform),
},
@@ -314,7 +325,7 @@ static struct snd_soc_dai_link acp3x_dai[] = {
.stream_name = "HiFi Playback",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &acp3x_max_play_ops,
.cpus = acp3x_bt,
.num_cpus = ARRAY_SIZE(acp3x_bt),
@@ -326,7 +337,7 @@ static struct snd_soc_dai_link acp3x_dai[] = {
.stream_name = "Capture DMIC0",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &acp3x_ec_cap0_ops,
SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform),
},
diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h
index 7b4c625da40d..5b6362103ca0 100644
--- a/sound/soc/amd/mach-config.h
+++ b/sound/soc/amd/mach-config.h
@@ -15,11 +15,19 @@
#define FLAG_AMD_SOF BIT(1)
#define FLAG_AMD_SOF_ONLY_DMIC BIT(2)
#define FLAG_AMD_LEGACY BIT(3)
+#define FLAG_AMD_LEGACY_ONLY_DMIC BIT(4)
#define ACP_PCI_DEV_ID 0x15E2
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[];
+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[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[];
struct config_entry {
u32 flags;
diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile
index 383973a12f6a..778ee4726389 100644
--- a/sound/soc/amd/ps/Makefile
+++ b/sound/soc/amd/ps/Makefile
@@ -1,9 +1,11 @@
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-only
# Pink Sardine platform Support
-snd-pci-ps-objs := pci-ps.o
-snd-ps-pdm-dma-objs := ps-pdm-dma.o
-snd-soc-ps-mach-objs := ps-mach.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
obj-$(CONFIG_SND_SOC_AMD_PS) += snd-pci-ps.o
obj-$(CONFIG_SND_SOC_AMD_PS) += snd-ps-pdm-dma.o
+obj-$(CONFIG_SND_SOC_AMD_PS) += snd-ps-sdw-dma.o
obj-$(CONFIG_SND_SOC_AMD_PS_MACH) += snd-soc-ps-mach.o
diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h
index 2f94448102d0..62cb6bef17ab 100644
--- a/sound/soc/amd/ps/acp63.h
+++ b/sound/soc/amd/ps/acp63.h
@@ -1,25 +1,29 @@
/* 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>
#include <sound/acp63_chip_offset_byte.h>
#define ACP_DEVICE_ID 0x15E2
#define ACP63_REG_START 0x1240000
-#define ACP63_REG_END 0x1250200
-#define ACP63_DEVS 3
+#define ACP63_REG_END 0x125C000
+#define ACP63_PCI_REV 0x63
+#define ACP70_PCI_REV 0x70
+#define ACP71_PCI_REV 0x71
+#define ACP72_PCI_REV 0x72
#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
@@ -53,13 +57,136 @@
/* time in ms for runtime suspend delay */
#define ACP_SUSPEND_DELAY_MS 2000
-#define ACP63_DMIC_ADDR 2
-#define ACP63_PDM_MODE_DEVS 3
-#define ACP63_PDM_DEV_MASK 1
#define ACP_DMIC_DEV 2
+#define ACP63_DMIC_ADDR 2
+#define ACP63_SDW_ADDR 5
+#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)
+#define ACP_ERROR_IRQ BIT(29)
+
+#define ACP_AUDIO0_TX_THRESHOLD 0x1c
+#define ACP_AUDIO1_TX_THRESHOLD 0x1a
+#define ACP_AUDIO2_TX_THRESHOLD 0x18
+#define ACP_AUDIO0_RX_THRESHOLD 0x1b
+#define ACP_AUDIO1_RX_THRESHOLD 0x19
+#define ACP_AUDIO2_RX_THRESHOLD 0x17
+#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 ACP63_P1_AUDIO_TX_THRESHOLD 6
+
+/*
+ * Below entries describes SDW0 instance DMA stream id and DMA irq bit mapping
+ * in ACP_EXTENAL_INTR_CNTL register.
+ * Stream id IRQ Bit
+ * 0 (SDW0_AUDIO0_TX) 28
+ * 1 (SDW0_AUDIO1_TX) 26
+ * 2 (SDW0_AUDIO2_TX) 24
+ * 3 (SDW0_AUDIO0_RX) 27
+ * 4 (SDW0_AUDIO1_RX) 25
+ * 5 (SDW0_AUDIO2_RX) 23
+ */
+#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
+ * in ACP_EXTENAL_INTR_CNTL1 register.
+ * Stream id IRQ Bit
+ * 0 (SDW1_AUDIO1_TX) 6
+ * 1 (SDW1_AUDIO1_RX) 5
+ */
+#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)
+#define SDW0_MEM_WINDOW_START 0x4800000
+#define ACP_SDW_SRAM_PTE_OFFSET 0x03800400
+#define SDW0_PTE_OFFSET 0x400
+#define SDW_FIFO_SIZE 0x100
+#define SDW_DMA_SIZE 0x40
+#define ACP_SDW0_FIFO_OFFSET 0x100
+#define ACP_SDW_PTE_OFFSET 0x100
+#define SDW_FIFO_OFFSET 0x100
+#define SDW_PTE_OFFSET(i) (SDW0_PTE_OFFSET + ((i) * 0x600))
+#define ACP_SDW_FIFO_OFFSET(i) (ACP_SDW0_FIFO_OFFSET + ((i) * 0x500))
+#define SDW_MEM_WINDOW_START(i) (SDW0_MEM_WINDOW_START + ((i) * 0xC0000))
+
+#define SDW_PLAYBACK_MIN_NUM_PERIODS 2
+#define SDW_PLAYBACK_MAX_NUM_PERIODS 8
+#define SDW_PLAYBACK_MAX_PERIOD_SIZE 8192
+#define SDW_PLAYBACK_MIN_PERIOD_SIZE 1024
+#define SDW_CAPTURE_MIN_NUM_PERIODS 2
+#define SDW_CAPTURE_MAX_NUM_PERIODS 8
+#define SDW_CAPTURE_MAX_PERIOD_SIZE 8192
+#define SDW_CAPTURE_MIN_PERIOD_SIZE 1024
+
+#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,
@@ -78,6 +205,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_acp63_sdw1_channel {
+ ACP63_SDW1_AUDIO1_TX,
+ ACP63_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 {
@@ -95,14 +250,199 @@ struct pdm_dev_data {
struct snd_pcm_substream *capture_stream;
};
+struct sdw_dma_dev_data {
+ void __iomem *acp_base;
+ struct mutex *acp_lock; /* used to protect acp common register access */
+ 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 {
+ u16 num_pages;
+ u16 channels;
+ u32 stream_id;
+ u32 instance;
+ dma_addr_t dma_addr;
+ u64 bytescount;
+};
+
+union acp_sdw_dma_count {
+ struct {
+ u32 low;
+ u32 high;
+ } bcount;
+ u64 bytescount;
+};
+
+struct sdw_dma_ring_buf_reg {
+ u32 reg_dma_size;
+ u32 reg_fifo_addr;
+ u32 reg_fifo_size;
+ u32 reg_ring_buf_size;
+ u32 reg_ring_buf_addr;
+ u32 water_mark_size_reg;
+ u32 pos_low_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
+ * @mach_dev: platform device for machine driver to support ACP PDM/SoundWire configuration
+ * @acp_lock: used to protect acp common registers
+ * @info: SoundWire AMD information found in ACPI tables
+ * @sdw: SoundWire context for all SoundWire manager instances
+ * @machine: ACPI machines for SoundWire interface
+ * @is_sdw_dev: flag set to true when any SoundWire manager instances are available
+ * @is_pdm_dev: flag set to true when ACP PDM controller exists
+ * @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
+ * @acp_sw_pad_keeper_en: store acp SoundWire pad keeper enable register value
+ * @acp_pad_pulldown_ctrl: store acp pad pulldown control register value
+ * @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 platform_device *pdev[ACP63_DEVS];
+ struct acp_hw_ops *hw_ops;
+ struct platform_device *pdm_dev;
+ struct platform_device *dmic_codec_dev;
+ struct platform_device *sdw_dma_dev;
+ struct platform_device *mach_dev;
struct mutex acp_lock; /* protect shared registers */
- u16 pdev_mask;
- u16 pdev_count;
- u16 pdm_dev_index;
+ struct sdw_amd_acpi_info info;
+ /* sdw context allocated by SoundWire driver */
+ struct sdw_amd_ctx *sdw;
+ struct snd_soc_acpi_mach *machines;
+ bool is_sdw_dev;
+ bool is_pdm_dev;
+ 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;
+ u32 subsystem_vendor;
+ u32 subsystem_device;
+ u32 acp_sw_pad_keeper_en;
+ u32 acp_pad_pulldown_ctrl;
+ 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 c957718abefc..3a20cc10d61f 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -1,11 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0+
+// 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>
+#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -15,141 +16,439 @@
#include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
#include <linux/iopoll.h>
+#include <linux/soundwire/sdw_amd.h>
+#include "../mach-config.h"
#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;
+ struct amd_sdw_manager *amd_manager;
- val = readl(acp_base + ACP_PGFSM_STATUS);
-
- if (!val)
- return val;
-
- 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;
-
- 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;
+ u32 ext_intr_stat1;
+ int irq_flag = 0;
+ bool sdw_wake_irq = false;
+
+ 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;
+ }
- writel(0, acp_base + ACP_SOFT_RESET);
+ 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;
+ }
- return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
-}
+ 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;
+ }
-static void acp63_enable_interrupts(void __iomem *acp_base)
-{
- writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
-}
+ 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;
+ }
-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 (sdw_wake_irq) {
+ handle_acp70_sdw_wake_event(adata);
+ irq_flag = 1;
+ }
+ return irq_flag;
}
-static int acp63_init(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;
-
- ret = acp63_power_on(acp_base);
- if (ret) {
- dev_err(dev, "ACP power on failed\n");
- return ret;
+ u32 stream_id = 0;
+ u16 sdw_dma_irq_flag = 0;
+ u16 index;
+
+ 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:
+ case ACP72_PCI_REV:
+ adata->acp70_sdw0_dma_intr_stat[stream_id] = 1;
+ break;
+ }
+ sdw_dma_irq_flag = 1;
+ }
+ }
}
- writel(0x01, acp_base + ACP_CONTROL);
- ret = acp63_reset(acp_base);
- if (ret) {
- dev_err(dev, "ACP reset failed\n");
- return ret;
+ 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:
+ case ACP72_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;
}
- acp63_enable_interrupts(acp_base);
- return 0;
+ return sdw_dma_irq_flag;
}
-static int acp63_deinit(void __iomem *acp_base, struct device *dev)
+static irqreturn_t acp63_irq_thread(int irq, void *context)
{
- int ret;
+ struct acp63_dev_data *adata = context;
- 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);
- return 0;
+ acp_hw_sdw_dma_irq_thread(adata);
+ return IRQ_HANDLED;
}
static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
{
struct acp63_dev_data *adata;
struct pdm_dev_data *ps_pdm_data;
- u32 val;
- u16 pdev_index;
+ struct amd_sdw_manager *amd_manager;
+ u32 ext_intr_stat, ext_intr_stat1;
+ u16 irq_flag = 0;
+ u16 wake_irq_flag = 0;
+ u16 sdw_dma_irq_flag = 0;
adata = dev_id;
if (!adata)
return IRQ_NONE;
+ /* ACP interrupts will be cleared by reading particular bit and writing
+ * same value to the status register. writing zero's doesn't have any
+ * effect.
+ * Bit by bit checking of IRQ field is implemented.
+ */
+ ext_intr_stat = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+ if (ext_intr_stat & ACP_SDW0_STAT) {
+ writel(ACP_SDW0_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
+ if (amd_manager)
+ schedule_work(&amd_manager->amd_sdw_irq_thread);
+ irq_flag = 1;
+ }
+
+ ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ if (ext_intr_stat1 & ACP_SDW1_STAT) {
+ writel(ACP_SDW1_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
+ if (amd_manager)
+ schedule_work(&amd_manager->amd_sdw_irq_thread);
+ irq_flag = 1;
+ }
+
+ if (ext_intr_stat & ACP_ERROR_IRQ) {
+ writel(ACP_ERROR_IRQ, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+ /* TODO: Report SoundWire Manager instance errors */
+ writel(0, adata->acp63_base + ACP_SW0_I2S_ERROR_REASON);
+ writel(0, adata->acp63_base + ACP_SW1_I2S_ERROR_REASON);
+ writel(0, adata->acp63_base + ACP_ERROR_STATUS);
+ irq_flag = 1;
+ }
+
+ if (adata->acp_rev >= ACP70_PCI_REV)
+ wake_irq_flag = check_and_handle_acp70_sdw_wake_irq(adata);
- val = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
- if (val & BIT(PDM_DMA_STAT)) {
- pdev_index = adata->pdm_dev_index;
- ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+ 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);
if (ps_pdm_data->capture_stream)
snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
+ 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;
+
+ if (irq_flag | wake_irq_flag)
return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+#if IS_ENABLED(CONFIG_SND_SOC_AMD_SOUNDWIRE)
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+ struct acpi_device *sdw_dev;
+ struct acp63_dev_data *acp_data;
+
+ acp_data = dev_get_drvdata(dev);
+ if (!addr)
+ return -ENODEV;
+
+ sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), addr, 0);
+ if (!sdw_dev)
+ return -ENODEV;
+
+ acp_data->info.handle = sdw_dev->handle;
+ acp_data->info.count = AMD_SDW_MAX_MANAGERS;
+ return amd_sdw_scan_controller(&acp_data->info);
+}
+
+static int amd_sdw_probe(struct device *dev)
+{
+ struct acp63_dev_data *acp_data;
+ struct sdw_amd_res sdw_res;
+ int ret;
+
+ acp_data = dev_get_drvdata(dev);
+ memset(&sdw_res, 0, sizeof(sdw_res));
+ sdw_res.addr = acp_data->addr;
+ sdw_res.reg_range = acp_data->reg_range;
+ sdw_res.handle = acp_data->info.handle;
+ sdw_res.parent = dev;
+ sdw_res.dev = dev;
+ sdw_res.acp_lock = &acp_data->acp_lock;
+ sdw_res.count = acp_data->info.count;
+ sdw_res.mmio_base = acp_data->acp63_base;
+ sdw_res.acp_rev = acp_data->acp_rev;
+ sdw_res.link_mask = acp_data->info.link_mask;
+ ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
+ if (ret)
+ dev_err(dev, "error: SoundWire probe failed\n");
+ return ret;
+}
+
+static int amd_sdw_exit(struct acp63_dev_data *acp_data)
+{
+ if (acp_data->sdw)
+ sdw_amd_exit(acp_data->sdw);
+ acp_data->sdw = NULL;
+
+ return 0;
+}
+
+static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
+{
+ struct snd_soc_acpi_mach *mach;
+ const struct snd_soc_acpi_link_adr *link;
+ struct acp63_dev_data *acp_data = dev_get_drvdata(dev);
+ int ret, i;
+
+ if (acp_data->info.count) {
+ ret = sdw_amd_get_slave_info(acp_data->sdw);
+ if (ret) {
+ dev_dbg(dev, "failed to read slave information\n");
+ return NULL;
+ }
+ for (mach = acp_data->machines; mach; mach++) {
+ if (!mach->links)
+ break;
+ link = mach->links;
+ for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
+ if (!snd_soc_acpi_sdw_link_slaves_found(dev, link,
+ acp_data->sdw->peripherals))
+ break;
+ }
+ if (i == acp_data->info.count || !link->num_adr)
+ break;
+ }
+ 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;
+ mach->mach_params.subsystem_vendor = acp_data->subsystem_vendor;
+ mach->mach_params.subsystem_device = acp_data->subsystem_device;
+ mach->mach_params.subsystem_id_set = true;
+
+ dev_dbg(dev, "SSID %x%x\n", mach->mach_params.subsystem_vendor,
+ mach->mach_params.subsystem_device);
+ return mach;
+ }
}
- return IRQ_NONE;
+ dev_dbg(dev, "No SoundWire machine driver found\n");
+ return NULL;
+}
+#else
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+ return 0;
}
-static void get_acp63_device_config(u32 config, struct pci_dev *pci,
- struct acp63_dev_data *acp_data)
+static int amd_sdw_probe(struct device *dev)
{
- struct acpi_device *dmic_dev;
+ return 0;
+}
+
+static int amd_sdw_exit(struct acp63_dev_data *acp_data)
+{
+ return 0;
+}
+
+static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
+static int acp63_machine_register(struct device *dev)
+{
+ struct snd_soc_acpi_mach *mach;
+ struct acp63_dev_data *adata = dev_get_drvdata(dev);
+ int size;
+
+ if (adata->is_sdw_dev && adata->is_sdw_config) {
+ size = sizeof(*adata->machines);
+ mach = acp63_sdw_machine_select(dev);
+ if (mach) {
+ adata->mach_dev = platform_device_register_data(dev, mach->drv_name,
+ PLATFORM_DEVID_NONE, mach,
+ size);
+ if (IS_ERR(adata->mach_dev)) {
+ dev_err(dev,
+ "cannot register Machine device for SoundWire Interface\n");
+ return PTR_ERR(adata->mach_dev);
+ }
+ }
+
+ } else if (adata->is_pdm_dev && !adata->is_sdw_dev && adata->is_pdm_config) {
+ adata->mach_dev = platform_device_register_data(dev, "acp_ps_mach",
+ PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(adata->mach_dev)) {
+ dev_err(dev, "cannot register amd_ps_mach device\n");
+ return PTR_ERR(adata->mach_dev);
+ }
+ }
+ return 0;
+}
+
+static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *acp_data)
+{
+ struct acpi_device *pdm_dev;
const union acpi_object *obj;
+ acpi_handle handle;
+ acpi_integer dmic_status;
bool is_dmic_dev = false;
+ bool is_sdw_dev = false;
+ bool wov_en, dmic_en;
+ int ret;
- dmic_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0);
- if (dmic_dev) {
- if (!acpi_dev_get_property(dmic_dev, "acp-audio-device-type",
- ACPI_TYPE_INTEGER, &obj) &&
- obj->integer.value == ACP_DMIC_DEV)
- is_dmic_dev = true;
- }
-
- switch (config) {
- case ACP_CONFIG_0:
- case ACP_CONFIG_1:
- case ACP_CONFIG_2:
- case ACP_CONFIG_3:
- case ACP_CONFIG_9:
- case ACP_CONFIG_15:
- dev_dbg(&pci->dev, "Audio Mode %d\n", config);
- break;
- default:
- if (is_dmic_dev) {
- acp_data->pdev_mask = ACP63_PDM_DEV_MASK;
- acp_data->pdev_count = ACP63_PDM_MODE_DEVS;
+ /* IF WOV entry not found, enable dmic based on acp-audio-device-type entry*/
+ wov_en = true;
+ dmic_en = false;
+
+ 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);
+ if (pdm_dev) {
+ /* is_dmic_dev flag will be set when ACP PDM controller device exists */
+ if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
+ ACPI_TYPE_INTEGER, &obj) &&
+ obj->integer.value == ACP_DMIC_DEV)
+ dmic_en = true;
}
- break;
+
+ handle = ACPI_HANDLE(&pci->dev);
+ ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
+ if (!ACPI_FAILURE(ret))
+ wov_en = dmic_status;
+ }
+
+ if (dmic_en && wov_en)
+ is_dmic_dev = true;
+
+ if (acp_data->is_sdw_config) {
+ ret = acp_scan_sdw_devices(&pci->dev, ACP63_SDW_ADDR);
+ if (!ret && acp_data->info.link_mask)
+ is_sdw_dev = true;
}
+
+ acp_data->is_pdm_dev = is_dmic_dev;
+ acp_data->is_sdw_dev = is_sdw_dev;
+ if (!is_dmic_dev && !is_sdw_dev) {
+ dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n");
+ return -ENODEV;
+ }
+ return 0;
}
static void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo,
@@ -173,16 +472,13 @@ static void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo,
static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data *adata, u32 addr)
{
- struct platform_device_info pdevinfo[ACP63_DEVS];
+ struct platform_device_info pdevinfo;
struct device *parent;
- int index;
int ret;
parent = &pci->dev;
- dev_dbg(&pci->dev,
- "%s pdev_mask:0x%x pdev_count:0x%x\n", __func__, adata->pdev_mask,
- adata->pdev_count);
- if (adata->pdev_mask) {
+
+ if (adata->is_sdw_dev || adata->is_pdm_dev) {
adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
if (!adata->res) {
ret = -ENOMEM;
@@ -194,48 +490,92 @@ static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data
memset(&pdevinfo, 0, sizeof(pdevinfo));
}
- switch (adata->pdev_mask) {
- case ACP63_PDM_DEV_MASK:
- adata->pdm_dev_index = 0;
- acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
- 0, adata->res, 1, &adata->acp_lock,
- sizeof(adata->acp_lock));
- acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "dmic-codec",
- 0, NULL, 0, NULL, 0);
- acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "acp_ps_mach",
+ if (adata->is_pdm_dev && adata->is_pdm_config) {
+ acp63_fill_platform_dev_info(&pdevinfo, parent, NULL, "acp_ps_pdm_dma",
+ 0, adata->res, 1, NULL, 0);
+
+ adata->pdm_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->pdm_dev)) {
+ dev_err(&pci->dev,
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(adata->pdm_dev);
+ goto de_init;
+ }
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ acp63_fill_platform_dev_info(&pdevinfo, parent, NULL, "dmic-codec",
0, NULL, 0, NULL, 0);
- break;
- default:
- dev_dbg(&pci->dev, "No PDM devices found\n");
- return 0;
+ adata->dmic_codec_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->dmic_codec_dev)) {
+ dev_err(&pci->dev,
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(adata->dmic_codec_dev);
+ goto unregister_pdm_dev;
+ }
}
+ if (adata->is_sdw_dev && adata->is_sdw_config) {
+ ret = amd_sdw_probe(&pci->dev);
+ if (ret) {
+ if (adata->is_pdm_dev)
+ goto unregister_dmic_codec_dev;
+ else
+ goto de_init;
+ }
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ acp63_fill_platform_dev_info(&pdevinfo, parent, NULL, "amd_ps_sdw_dma",
+ 0, adata->res, 1, NULL, 0);
- for (index = 0; index < adata->pdev_count; index++) {
- adata->pdev[index] = platform_device_register_full(&pdevinfo[index]);
- if (IS_ERR(adata->pdev[index])) {
+ adata->sdw_dma_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->sdw_dma_dev)) {
dev_err(&pci->dev,
- "cannot register %s device\n", pdevinfo[index].name);
- ret = PTR_ERR(adata->pdev[index]);
- goto unregister_devs;
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(adata->sdw_dma_dev);
+ if (adata->is_pdm_dev)
+ goto unregister_dmic_codec_dev;
+ else
+ goto de_init;
}
}
+
return 0;
-unregister_devs:
- for (--index; index >= 0; index--)
- platform_device_unregister(adata->pdev[index]);
+unregister_dmic_codec_dev:
+ platform_device_unregister(adata->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:
+ case ACP72_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)
{
struct acp63_dev_data *adata;
u32 addr;
u32 irqflags, flag;
- int val;
int ret;
irqflags = IRQF_SHARED;
@@ -245,12 +585,15 @@ 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:
+ case ACP72_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)) {
@@ -277,32 +620,59 @@ static int snd_acp63_probe(struct pci_dev *pci,
ret = -ENOMEM;
goto release_regions;
}
+ adata->addr = addr;
+ adata->reg_range = ACP63_REG_END - ACP63_REG_START;
+ adata->acp_rev = pci->revision;
+ adata->subsystem_vendor = pci->subsystem_vendor;
+ adata->subsystem_device = pci->subsystem_device;
+
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_irq(&pci->dev, pci->irq, acp63_irq_handler,
- irqflags, "ACP_PCI_IRQ", adata);
+ ret = devm_request_threaded_irq(&pci->dev, pci->irq, acp63_irq_handler,
+ acp63_irq_thread, irqflags, "ACP_PCI_IRQ", adata);
if (ret) {
dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
goto de_init;
}
- val = readl(adata->acp63_base + ACP_PIN_CONFIG);
- get_acp63_device_config(val, pci, adata);
+ ret = get_acp63_device_config(pci, adata);
+ /* ACP PCI driver probe should be continued even PDM or SoundWire Devices are not found */
+ if (ret) {
+ dev_dbg(&pci->dev, "get acp device config failed:%d\n", ret);
+ goto skip_pdev_creation;
+ }
ret = create_acp63_platform_devs(pci, adata, addr);
if (ret < 0) {
dev_err(&pci->dev, "ACP platform devices creation failed\n");
goto de_init;
}
+ 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");
+ goto de_init;
+ }
+skip_pdev_creation:
+ device_set_wakeup_enable(&pci->dev, true);
pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pci->dev);
pm_runtime_put_noidle(&pci->dev);
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);
@@ -312,44 +682,43 @@ disable_pci:
return ret;
}
-static int __maybe_unused snd_acp63_suspend(struct device *dev)
+static int snd_acp_suspend(struct device *dev)
{
- struct acp63_dev_data *adata;
- int ret;
-
- adata = dev_get_drvdata(dev);
- 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_resume(struct device *dev)
+static int snd_acp_runtime_resume(struct device *dev)
{
- struct acp63_dev_data *adata;
- int ret;
+ return acp_hw_runtime_resume(dev);
+}
- adata = dev_get_drvdata(dev);
- ret = acp63_init(adata->acp63_base, dev);
- if (ret)
- dev_err(dev, "ACP init failed\n");
- return ret;
+static int snd_acp_resume(struct device *dev)
+{
+ return acp_hw_resume(dev);
}
static const struct dev_pm_ops acp63_pm_ops = {
- SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_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)
{
struct acp63_dev_data *adata;
- int ret, index;
+ int ret;
adata = pci_get_drvdata(pci);
- for (index = 0; index < adata->pdev_count; index++)
- platform_device_unregister(adata->pdev[index]);
- ret = acp63_deinit(adata->acp63_base, &pci->dev);
+ if (adata->sdw) {
+ amd_sdw_exit(adata);
+ platform_device_unregister(adata->sdw_dma_dev);
+ }
+ if (adata->is_pdm_dev) {
+ platform_device_unregister(adata->pdm_dev);
+ platform_device_unregister(adata->dmic_codec_dev);
+ }
+ if (adata->mach_dev)
+ platform_device_unregister(adata->mach_dev);
+ ret = acp_hw_deinit(adata, &pci->dev);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
pm_runtime_forbid(&pci->dev);
@@ -372,7 +741,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),
}
};
@@ -380,5 +749,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..7b4966b75dc6
--- /dev/null
+++ b/sound/soc/amd/ps/ps-common.c
@@ -0,0 +1,493 @@
+// 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->acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+ adata->acp_pad_pulldown_ctrl = readl(adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
+ 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;
+ u32 acp_sw_pad_keeper_en;
+ 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");
+
+ acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+ dev_dbg(dev, "ACP_SW0_PAD_KEEPER_EN:0x%x\n", acp_sw_pad_keeper_en);
+ if (!acp_sw_pad_keeper_en) {
+ writel(adata->acp_sw_pad_keeper_en, adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+ writel(adata->acp_pad_pulldown_ctrl, adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
+ }
+ 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->acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+ adata->acp_pad_pulldown_ctrl = readl(adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
+ 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;
+ u32 acp_sw_pad_keeper_en;
+ 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");
+
+ acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+ dev_dbg(dev, "ACP_SW0_PAD_KEEPER_EN:0x%x\n", acp_sw_pad_keeper_en);
+ if (!acp_sw_pad_keeper_en) {
+ writel(adata->acp_sw_pad_keeper_en, adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+ writel(adata->acp_pad_pulldown_ctrl, adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
+ }
+ 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-mach.c b/sound/soc/amd/ps/ps-mach.c
index 3ffbe4fdafdf..ff8ad036b077 100644
--- a/sound/soc/amd/ps/ps-mach.c
+++ b/sound/soc/amd/ps/ps-mach.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Machine driver for AMD Pink Sardine platform using DMIC
*
@@ -75,5 +75,6 @@ static struct platform_driver acp63_mach_driver = {
module_platform_driver(acp63_mach_driver);
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
+MODULE_DESCRIPTION("AMD Pink Sardine support for DMIC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index 3ecc6cf3fd34..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+
+// 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>
@@ -358,12 +358,12 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
{
struct resource *res;
struct pdm_dev_data *adata;
+ struct acp63_dev_data *acp_data;
+ struct device *parent;
int status;
- if (!pdev->dev.platform_data) {
- dev_err(&pdev->dev, "platform_data not retrieved\n");
- return -ENODEV;
- }
+ parent = pdev->dev.parent;
+ acp_data = dev_get_drvdata(parent);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
@@ -379,7 +379,7 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
return -ENOMEM;
adata->capture_stream = NULL;
- adata->acp_lock = pdev->dev.platform_data;
+ adata->acp_lock = &acp_data->acp_lock;
dev_set_drvdata(&pdev->dev, adata);
status = devm_snd_soc_register_component(&pdev->dev,
&acp63_pdm_component,
@@ -391,8 +391,9 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
}
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
return 0;
}
@@ -401,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;
@@ -422,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;
@@ -431,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;
@@ -441,22 +442,22 @@ 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 = {
.probe = acp63_pdm_audio_probe,
- .remove_new = acp63_pdm_audio_remove,
+ .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
new file mode 100644
index 000000000000..5449323e2728
--- /dev/null
+++ b/sound/soc/amd/ps/ps-sdw-dma.c
@@ -0,0 +1,804 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD ALSA SoC common SoundWire DMA Driver for ACP6.3, ACP7.0 and ACP7.1
+ * platforms.
+ *
+ * Copyright 2023, 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_amd.h>
+#include "acp63.h"
+
+#define DRV_NAME "amd_ps_sdw_dma"
+
+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},
+ {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}
+};
+
+/*
+ * SDW1 instance supports one TX stream and one RX stream.
+ * 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 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,
+ ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_TX_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},
+};
+
+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,
+ ACP_SW0_AUDIO0_RX_EN,
+ ACP_SW0_AUDIO1_RX_EN,
+ ACP_SW0_AUDIO2_RX_EN,
+};
+
+/*
+ * SDW1 instance supports one TX stream and one RX stream.
+ * For TX/RX streams DMA enable register programming for SDW1 instance,
+ * it uses ACP_SW1_AUDIO1_TX_EN and ACP_SW1_AUDIO1_RX_EN registers
+ * as per hardware register documentation.
+ */
+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 |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .buffer_bytes_max = SDW_PLAYBACK_MAX_NUM_PERIODS * SDW_PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = SDW_PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = SDW_PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = SDW_PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = SDW_PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp63_sdw_hardware_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .buffer_bytes_max = SDW_CAPTURE_MAX_NUM_PERIODS * SDW_CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = SDW_CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = SDW_CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = SDW_CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = SDW_CAPTURE_MAX_NUM_PERIODS,
+};
+
+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;
+
+ if (enable) {
+ ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_intr_cntl |= irq_mask;
+ writel(ext_intr_cntl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1);
+ ext_intr_cntl1 |= irq_mask1;
+ writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1);
+ } else {
+ ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_intr_cntl &= ~irq_mask;
+ writel(ext_intr_cntl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1);
+ ext_intr_cntl1 &= ~irq_mask1;
+ writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1);
+ }
+}
+
+static void acp63_config_dma(struct acp_sdw_dma_stream *stream, void __iomem *acp_base,
+ u32 stream_id)
+{
+ u16 page_idx;
+ u32 low, high, val;
+ u32 sdw_dma_pte_offset;
+ dma_addr_t addr;
+
+ addr = stream->dma_addr;
+ sdw_dma_pte_offset = SDW_PTE_OFFSET(stream->instance);
+ val = sdw_dma_pte_offset + (stream_id * ACP_SDW_PTE_OFFSET);
+
+ /* Group Enable */
+ writel(ACP_SDW_SRAM_PTE_OFFSET | BIT(31), acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2);
+ writel(PAGE_SIZE_4K_ENABLE, acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2);
+ for (page_idx = 0; page_idx < stream->num_pages; page_idx++) {
+ /* Load the low address of page int ACP SRAM through SRBM */
+ low = lower_32_bits(addr);
+ high = upper_32_bits(addr);
+
+ writel(low, acp_base + ACP_SCRATCH_REG_0 + val);
+ high |= BIT(31);
+ writel(high, acp_base + ACP_SCRATCH_REG_0 + val + 4);
+ val += 8;
+ addr += PAGE_SIZE;
+ }
+ writel(0x1, acp_base + ACPAXI2AXI_ATU_CTRL);
+}
+
+static int acp63_configure_sdw_ringbuffer(void __iomem *acp_base, u32 stream_id, u32 size,
+ u32 manager_instance, u32 acp_rev)
+{
+ u32 reg_dma_size;
+ u32 reg_fifo_addr;
+ u32 reg_fifo_size;
+ u32 reg_ring_buf_size;
+ u32 reg_ring_buf_addr;
+ u32 sdw_fifo_addr;
+ u32 sdw_fifo_offset;
+ u32 sdw_ring_buf_addr;
+ u32 sdw_ring_buf_size;
+ u32 sdw_mem_window_offset;
+
+ 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 ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_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;
+ }
+ sdw_fifo_offset = ACP_SDW_FIFO_OFFSET(manager_instance);
+ sdw_mem_window_offset = SDW_MEM_WINDOW_START(manager_instance);
+ sdw_fifo_addr = sdw_fifo_offset + (stream_id * SDW_FIFO_OFFSET);
+ sdw_ring_buf_addr = sdw_mem_window_offset + (stream_id * ACP_SDW_RING_BUFF_ADDR_OFFSET);
+ sdw_ring_buf_size = size;
+ writel(sdw_ring_buf_size, acp_base + reg_ring_buf_size);
+ writel(sdw_ring_buf_addr, acp_base + reg_ring_buf_addr);
+ writel(sdw_fifo_addr, acp_base + reg_fifo_addr);
+ writel(SDW_DMA_SIZE, acp_base + reg_dma_size);
+ writel(SDW_FIFO_SIZE, acp_base + reg_fifo_size);
+ return 0;
+}
+
+static int acp63_sdw_dma_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct acp_sdw_dma_stream *stream;
+ struct snd_soc_dai *cpu_dai;
+ struct amd_sdw_manager *amd_manager;
+ struct snd_soc_pcm_runtime *prtd = snd_soc_substream_to_rtd(substream);
+ int ret;
+
+ runtime = substream->runtime;
+ cpu_dai = snd_soc_rtd_to_cpu(prtd, 0);
+ amd_manager = snd_soc_dai_get_drvdata(cpu_dai);
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = acp63_sdw_hardware_playback;
+ else
+ runtime->hw = acp63_sdw_hardware_capture;
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ dev_err(component->dev, "set integer constraint failed\n");
+ kfree(stream);
+ return ret;
+ }
+
+ stream->stream_id = cpu_dai->id;
+ stream->instance = amd_manager->instance;
+ runtime->private_data = stream;
+ return ret;
+}
+
+static int acp63_sdw_dma_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct acp_sdw_dma_stream *stream;
+ struct sdw_dma_dev_data *sdw_data;
+ u32 period_bytes;
+ u32 water_mark_size_reg;
+ u32 irq_mask, ext_intr_ctrl;
+ u64 size;
+ u32 stream_id;
+ u32 acp_ext_intr_cntl_reg;
+ int ret;
+
+ sdw_data = dev_get_drvdata(component->dev);
+ stream = substream->runtime->private_data;
+ if (!stream)
+ return -EINVAL;
+ stream_id = stream->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 ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_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;
+ }
+ size = params_buffer_bytes(params);
+ period_bytes = params_period_bytes(params);
+ stream->dma_addr = substream->runtime->dma_addr;
+ 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, sdw_data->acp_rev);
+ if (ret) {
+ dev_err(component->dev, "Invalid DMA channel\n");
+ return -EINVAL;
+ }
+ ext_intr_ctrl = readl(sdw_data->acp_base + acp_ext_intr_cntl_reg);
+ ext_intr_ctrl |= irq_mask;
+ writel(ext_intr_ctrl, sdw_data->acp_base + acp_ext_intr_cntl_reg);
+ writel(period_bytes, sdw_data->acp_base + water_mark_size_reg);
+ return 0;
+}
+
+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 (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 ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_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;
+ }
+ if (pos_low_reg) {
+ byte_count.bcount.high = readl(acp_base + pos_high_reg);
+ byte_count.bcount.low = readl(acp_base + pos_low_reg);
+ }
+POINTER_RETURN_BYTES:
+ return byte_count.bytescount;
+}
+
+static snd_pcm_uframes_t acp63_sdw_dma_pointer(struct snd_soc_component *comp,
+ struct snd_pcm_substream *substream)
+{
+ struct sdw_dma_dev_data *sdw_data;
+ struct acp_sdw_dma_stream *stream;
+ u32 pos, buffersize;
+ u64 bytescount;
+
+ sdw_data = dev_get_drvdata(comp->dev);
+ 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, sdw_data->acp_rev);
+ if (bytescount > stream->bytescount)
+ bytescount -= stream->bytescount;
+ pos = do_div(bytescount, buffersize);
+ return bytes_to_frames(substream->runtime, pos);
+}
+
+static int acp63_sdw_dma_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct device *parent = component->dev->parent;
+
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+ parent, SDW_MIN_BUFFER, SDW_MAX_BUFFER);
+ return 0;
+}
+
+static int acp63_sdw_dma_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct sdw_dma_dev_data *sdw_data;
+ struct acp_sdw_dma_stream *stream;
+
+ sdw_data = dev_get_drvdata(component->dev);
+ stream = substream->runtime->private_data;
+ if (!stream)
+ return -EINVAL;
+ 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 ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_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;
+ }
+ kfree(stream);
+ return 0;
+}
+
+static int acp63_sdw_dma_enable(struct snd_pcm_substream *substream,
+ void __iomem *acp_base, u32 acp_rev, bool sdw_dma_enable)
+{
+ struct acp_sdw_dma_stream *stream;
+ u32 stream_id;
+ u32 sdw_dma_en_reg;
+ u32 sdw_dma_en_stat_reg;
+ u32 sdw_dma_stat;
+ u32 dma_enable;
+
+ stream = substream->runtime->private_data;
+ stream_id = stream->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 ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ case ACP72_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;
+ }
+ sdw_dma_en_stat_reg = sdw_dma_en_reg + 4;
+ dma_enable = sdw_dma_enable;
+ writel(dma_enable, acp_base + sdw_dma_en_reg);
+ return readl_poll_timeout(acp_base + sdw_dma_en_stat_reg, sdw_dma_stat,
+ (sdw_dma_stat == dma_enable), ACP_DELAY_US, ACP_COUNTER);
+}
+
+static int acp63_sdw_dma_trigger(struct snd_soc_component *comp,
+ struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct sdw_dma_dev_data *sdw_data;
+ int ret;
+
+ sdw_data = dev_get_drvdata(comp->dev);
+ switch (cmd) {
+ 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, 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, sdw_data->acp_rev, false);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret)
+ dev_err(comp->dev, "trigger %d failed: %d", cmd, ret);
+ return ret;
+}
+
+static const struct snd_soc_component_driver acp63_sdw_component = {
+ .name = DRV_NAME,
+ .open = acp63_sdw_dma_open,
+ .close = acp63_sdw_dma_close,
+ .hw_params = acp63_sdw_dma_hw_params,
+ .trigger = acp63_sdw_dma_trigger,
+ .pointer = acp63_sdw_dma_pointer,
+ .pcm_construct = acp63_sdw_dma_new,
+ .use_dai_pcm_id = true,
+
+};
+
+static int acp63_sdw_platform_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct sdw_dma_dev_data *sdw_data;
+ struct acp63_dev_data *acp_data;
+ struct device *parent;
+ int status;
+
+ parent = pdev->dev.parent;
+ acp_data = dev_get_drvdata(parent);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
+ return -ENODEV;
+ }
+
+ sdw_data = devm_kzalloc(&pdev->dev, sizeof(*sdw_data), GFP_KERNEL);
+ if (!sdw_data)
+ return -ENOMEM;
+
+ sdw_data->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!sdw_data->acp_base)
+ 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,
+ NULL, 0);
+ if (status) {
+ dev_err(&pdev->dev, "Fail to register sdw dma component\n");
+ return status;
+ }
+ pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ return 0;
+}
+
+static void acp63_sdw_platform_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+}
+
+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, 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;
+ else
+ stream_count = ACP63_SDW1_DMA_MAX_STREAMS;
+
+ for (index = 0; index < stream_count; index++) {
+ if (instance == ACP_SDW0) {
+ 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->acp63_sdw1_dma_stream[index];
+ water_mark_size_reg = acp63_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,
+ 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, irq_mask, irq_mask1, true);
+ return 0;
+}
+
+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);
+ 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 = {
+ SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume)
+};
+
+static struct platform_driver acp63_sdw_dma_driver = {
+ .probe = acp63_sdw_platform_probe,
+ .remove = acp63_sdw_platform_remove,
+ .driver = {
+ .name = "amd_ps_sdw_dma",
+ .pm = pm_ptr(&acp63_pm_ops),
+ },
+};
+
+module_platform_driver(acp63_sdw_dma_driver);
+
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+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/raven/Makefile b/sound/soc/amd/raven/Makefile
index 62c22b6ed95a..b2ea030cbf25 100644
--- a/sound/soc/amd/raven/Makefile
+++ b/sound/soc/amd/raven/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
# Raven Ridge platform Support
-snd-pci-acp3x-objs := pci-acp3x.o
-snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o
-snd-acp3x-i2s-objs := acp3x-i2s.o
+snd-pci-acp3x-y := pci-acp3x.o
+snd-acp3x-pcm-dma-y := acp3x-pcm-dma.o
+snd-acp3x-i2s-y := acp3x-i2s.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-i2s.o
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
index 4ba83689482a..352485dd98b1 100644
--- a/sound/soc/amd/raven/acp3x-i2s.c
+++ b/sound/soc/amd/raven/acp3x-i2s.c
@@ -80,7 +80,7 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
u32 val;
u32 reg_val, frmt_reg;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
rtd = substream->runtime->private_data;
card = prtd->card;
adata = snd_soc_dai_get_drvdata(dai);
@@ -149,8 +149,9 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct i2s_stream_instance *rtd;
- u32 ret, val, period_bytes, reg_val, ier_val, water_val;
+ u32 val, period_bytes, reg_val, ier_val, water_val;
u32 buf_size, buf_reg;
+ int ret;
rtd = substream->runtime->private_data;
period_bytes = frames_to_bytes(substream->runtime,
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
index 7362dd15ad30..bb9ed52d744d 100644
--- a/sound/soc/amd/raven/acp3x-pcm-dma.c
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -215,7 +215,7 @@ static int acp3x_dma_open(struct snd_soc_component *component,
int ret;
runtime = substream->runtime;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
adata = dev_get_drvdata(component->dev);
i2s_data = kzalloc(sizeof(*i2s_data), GFP_KERNEL);
@@ -252,7 +252,7 @@ static int acp3x_dma_hw_params(struct snd_soc_component *component,
struct i2s_dev_data *adata;
u64 size;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
card = prtd->card;
pinfo = snd_soc_card_get_drvdata(card);
adata = dev_get_drvdata(component->dev);
@@ -327,7 +327,7 @@ static int acp3x_dma_close(struct snd_soc_component *component,
struct i2s_dev_data *adata;
struct i2s_stream_instance *ins;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
adata = dev_get_drvdata(component->dev);
ins = substream->runtime->private_data;
@@ -416,8 +416,9 @@ static int acp3x_audio_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
return 0;
}
@@ -508,7 +509,7 @@ static const struct dev_pm_ops acp3x_pm_ops = {
static struct platform_driver acp3x_dma_driver = {
.probe = acp3x_audio_probe,
- .remove_new = acp3x_audio_remove,
+ .remove = acp3x_audio_remove,
.driver = {
.name = "acp3x_rv_i2s_dma",
.pm = &acp3x_pm_ops,
diff --git a/sound/soc/amd/renoir/Makefile b/sound/soc/amd/renoir/Makefile
index 4a82690aec16..76b4a9c3e24f 100644
--- a/sound/soc/amd/renoir/Makefile
+++ b/sound/soc/amd/renoir/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
# Renoir platform Support
-snd-rn-pci-acp3x-objs := rn-pci-acp3x.o
-snd-acp3x-pdm-dma-objs := acp3x-pdm-dma.o
-snd-acp3x-rn-objs := acp3x-rn.o
+snd-rn-pci-acp3x-y := rn-pci-acp3x.o
+snd-acp3x-pdm-dma-y := acp3x-pdm-dma.o
+snd-acp3x-rn-y := acp3x-rn.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-rn-pci-acp3x.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-acp3x-pdm-dma.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR_MACH) += snd-acp3x-rn.o
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index 4e299f96521f..95ac8c680037 100644
--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c
+++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c
@@ -430,8 +430,9 @@ static int acp_pdm_audio_probe(struct platform_device *pdev)
}
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
return 0;
}
@@ -488,7 +489,7 @@ static const struct dev_pm_ops acp_pdm_pm_ops = {
static struct platform_driver acp_pdm_dma_driver = {
.probe = acp_pdm_audio_probe,
- .remove_new = acp_pdm_audio_remove,
+ .remove = acp_pdm_audio_remove,
.driver = {
.name = "acp_rn_pdm_dma",
.pm = &acp_pdm_pm_ops,
diff --git a/sound/soc/amd/renoir/acp3x-rn.c b/sound/soc/amd/renoir/acp3x-rn.c
index 5d979a7b77fb..3249f74a0197 100644
--- a/sound/soc/amd/renoir/acp3x-rn.c
+++ b/sound/soc/amd/renoir/acp3x-rn.c
@@ -72,5 +72,6 @@ static struct platform_driver acp_mach_driver = {
module_platform_driver(acp_mach_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD Renoir support for DMIC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/rpl/Makefile b/sound/soc/amd/rpl/Makefile
index 11a33a05e94b..a3825c5be4e7 100644
--- a/sound/soc/amd/rpl/Makefile
+++ b/sound/soc/amd/rpl/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
# RPL platform Support
-snd-rpl-pci-acp6x-objs := rpl-pci-acp6x.o
+snd-rpl-pci-acp6x-y := rpl-pci-acp6x.o
obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += snd-rpl-pci-acp6x.o
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/Makefile b/sound/soc/amd/vangogh/Makefile
index c9e53e04e247..7eae82faa392 100644
--- a/sound/soc/amd/vangogh/Makefile
+++ b/sound/soc/amd/vangogh/Makefile
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: GPL-2.0+
# Vangogh platform Support
-snd-pci-acp5x-objs := pci-acp5x.o
-snd-acp5x-i2s-objs := acp5x-i2s.o
-snd-acp5x-pcm-dma-objs := acp5x-pcm-dma.o
-snd-soc-acp5x-mach-objs := acp5x-mach.o
+snd-pci-acp5x-y := pci-acp5x.o
+snd-acp5x-i2s-y := acp5x-i2s.o
+snd-acp5x-pcm-dma-y := acp5x-pcm-dma.o
+snd-soc-acp5x-mach-y := acp5x-mach.o
obj-$(CONFIG_SND_SOC_AMD_ACP5x) += snd-pci-acp5x.o
obj-$(CONFIG_SND_SOC_AMD_ACP5x) += snd-acp5x-i2s.o
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index 773e96f1b4dd..bf719f628617 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -95,7 +95,7 @@ static int acp5x_i2s_hwparams(struct snd_pcm_substream *substream,
lrclk_div_val = 0;
bclk_div_val = 0;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
rtd = substream->runtime->private_data;
card = prtd->card;
adata = snd_soc_dai_get_drvdata(dai);
@@ -234,8 +234,9 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
{
struct i2s_stream_instance *rtd;
struct i2s_dev_data *adata;
- u32 ret, val, period_bytes, reg_val, ier_val, water_val;
+ u32 val, period_bytes, reg_val, ier_val, water_val;
u32 buf_size, buf_reg;
+ int ret;
adata = snd_soc_dai_get_drvdata(dai);
rtd = substream->runtime->private_data;
diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c
index e5bcd1e6eb73..5454de24fbcc 100644
--- a/sound/soc/amd/vangogh/acp5x-mach.c
+++ b/sound/soc/amd/vangogh/acp5x-mach.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Machine driver for AMD Vangogh platform using NAU8821 & CS35L41
- * codecs.
+ * Machine driver for AMD Vangogh platform using either
+ * NAU8821 & CS35L41 or NAU8821 & MAX98388 codecs.
*
* Copyright 2021 Advanced Micro Devices, Inc.
*/
@@ -22,7 +22,6 @@
#define DRV_NAME "acp5x_mach"
#define DUAL_CHANNEL 2
-#define VG_JUPITER 1
#define ACP5X_NAU8821_BCLK 3072000
#define ACP5X_NAU8821_FREQ_OUT 12288000
#define ACP5X_NAU8821_COMP_NAME "i2c-NVTN2020:00"
@@ -30,8 +29,10 @@
#define ACP5X_CS35L41_COMP_LNAME "spi-VLV1776:00"
#define ACP5X_CS35L41_COMP_RNAME "spi-VLV1776:01"
#define ACP5X_CS35L41_DAI_NAME "cs35l41-pcm"
+#define ACP5X_MAX98388_COMP_LNAME "i2c-ADS8388:00"
+#define ACP5X_MAX98388_COMP_RNAME "i2c-ADS8388:01"
+#define ACP5X_MAX98388_DAI_NAME "max98388-aif1"
-static unsigned long acp5x_machine_id;
static struct snd_soc_jack vg_headset;
SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0")));
@@ -60,8 +61,7 @@ static const struct snd_kcontrol_new acp5x_8821_controls[] = {
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *dai;
int ret = 0;
@@ -91,7 +91,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
static int acp5x_8821_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
/*
@@ -143,7 +143,7 @@ static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
static int acp5x_8821_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card);
machine->play_i2s_instance = I2S_SP_INSTANCE;
@@ -164,11 +164,14 @@ static int acp5x_8821_startup(struct snd_pcm_substream *substream)
static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME);
int ret, bclk;
+ if (!dai)
+ return -EINVAL;
+
ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(card->dev, "can't set FS clock %d\n", ret);
@@ -193,7 +196,7 @@ static const struct snd_soc_ops acp5x_8821_ops = {
static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card);
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -211,7 +214,7 @@ static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream)
static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int bclk, rate = params_rate(params);
struct snd_soc_component *comp;
int ret, i;
@@ -242,7 +245,6 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
}
return 0;
-
}
static const struct snd_soc_ops acp5x_cs35l41_play_ops = {
@@ -273,8 +275,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &acp5x_8821_ops,
.init = acp5x_8821_init,
SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform),
@@ -285,15 +285,12 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
.playback_only = 1,
.ops = &acp5x_cs35l41_play_ops,
SND_SOC_DAILINK_REG(acp5x_bt, cs35l41, platform),
},
};
-
-
static const struct snd_soc_dapm_widget acp5x_8821_35l41_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -331,43 +328,140 @@ static struct snd_soc_card acp5x_8821_35l41_card = {
.num_controls = ARRAY_SIZE(acp5x_8821_controls),
};
-static int acp5x_vg_quirk_cb(const struct dmi_system_id *id)
+static int acp5x_max98388_startup(struct snd_pcm_substream *substream)
{
- acp5x_machine_id = VG_JUPITER;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ machine->play_i2s_instance = I2S_HS_INSTANCE;
- return 1;
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+ return 0;
}
+static const struct snd_soc_ops acp5x_max98388_play_ops = {
+ .startup = acp5x_max98388_startup,
+};
+
+static struct snd_soc_codec_conf acp5x_max98388_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_LNAME),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_RNAME),
+ .name_prefix = "Right",
+ },
+};
+
+SND_SOC_DAILINK_DEF(max98388, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_MAX98388_COMP_LNAME,
+ ACP5X_MAX98388_DAI_NAME),
+ COMP_CODEC(ACP5X_MAX98388_COMP_RNAME,
+ ACP5X_MAX98388_DAI_NAME)));
+
+static struct snd_soc_dai_link acp5x_8821_98388_dai[] = {
+ {
+ .name = "acp5x-8821-play",
+ .stream_name = "Playback/Capture",
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC,
+ .ops = &acp5x_8821_ops,
+ .init = acp5x_8821_init,
+ SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform),
+ },
+ {
+ .name = "acp5x-max98388-play",
+ .stream_name = "MAX98388 Playback",
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC,
+ .playback_only = 1,
+ .ops = &acp5x_max98388_play_ops,
+ SND_SOC_DAILINK_REG(acp5x_bt, max98388, platform),
+ },
+};
+
+static const struct snd_soc_dapm_widget acp5x_8821_98388_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SPK("SPK", NULL),
+};
+
+static const struct snd_soc_dapm_route acp5x_8821_98388_route[] = {
+ { "Headphone", NULL, "HPOL" },
+ { "Headphone", NULL, "HPOR" },
+ { "MICL", NULL, "Headset Mic" },
+ { "MICR", NULL, "Headset Mic" },
+ { "DMIC", NULL, "Int Mic" },
+
+ { "Headphone", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+ { "Int Mic", NULL, "Platform Clock" },
+
+ { "SPK", NULL, "Left BE_OUT" },
+ { "SPK", NULL, "Right BE_OUT" },
+};
+
+static struct snd_soc_card acp5x_8821_98388_card = {
+ .name = "acp5x-max98388",
+ .owner = THIS_MODULE,
+ .dai_link = acp5x_8821_98388_dai,
+ .num_links = ARRAY_SIZE(acp5x_8821_98388_dai),
+ .dapm_widgets = acp5x_8821_98388_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_98388_widgets),
+ .dapm_routes = acp5x_8821_98388_route,
+ .num_dapm_routes = ARRAY_SIZE(acp5x_8821_98388_route),
+ .codec_conf = acp5x_max98388_conf,
+ .num_configs = ARRAY_SIZE(acp5x_max98388_conf),
+ .controls = acp5x_8821_controls,
+ .num_controls = ARRAY_SIZE(acp5x_8821_controls),
+};
+
static const struct dmi_system_id acp5x_vg_quirk_table[] = {
{
- .callback = acp5x_vg_quirk_cb,
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
- }
+ },
+ .driver_data = (void *)&acp5x_8821_35l41_card,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ .driver_data = (void *)&acp5x_8821_98388_card,
},
{}
};
static int acp5x_probe(struct platform_device *pdev)
{
+ const struct dmi_system_id *dmi_id;
struct acp5x_platform_info *machine;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int ret;
+ dmi_id = dmi_first_match(acp5x_vg_quirk_table);
+ if (!dmi_id || !dmi_id->driver_data)
+ return -ENODEV;
+
machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL);
if (!machine)
return -ENOMEM;
- dmi_check_system(acp5x_vg_quirk_table);
- switch (acp5x_machine_id) {
- case VG_JUPITER:
- card = &acp5x_8821_35l41_card;
- break;
- default:
- return -ENODEV;
- }
+ card = dmi_id->driver_data;
card->dev = dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
@@ -381,7 +475,7 @@ static int acp5x_probe(struct platform_device *pdev)
static struct platform_driver acp5x_mach_driver = {
.driver = {
- .name = "acp5x_mach",
+ .name = DRV_NAME,
.pm = &snd_soc_pm_ops,
},
.probe = acp5x_probe,
@@ -390,6 +484,6 @@ static struct platform_driver acp5x_mach_driver = {
module_platform_driver(acp5x_mach_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
-MODULE_DESCRIPTION("NAU8821 & CS35L41 audio support");
+MODULE_DESCRIPTION("NAU8821/CS35L41 & NAU8821/MAX98388 audio support");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
index 29901ee4bfe3..aa4726899434 100644
--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c
+++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
@@ -209,7 +209,7 @@ static int acp5x_dma_open(struct snd_soc_component *component,
int ret;
runtime = substream->runtime;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
adata = dev_get_drvdata(component->dev);
@@ -245,7 +245,7 @@ static int acp5x_dma_hw_params(struct snd_soc_component *component,
struct i2s_dev_data *adata;
u64 size;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
card = prtd->card;
pinfo = snd_soc_card_get_drvdata(card);
adata = dev_get_drvdata(component->dev);
@@ -322,7 +322,7 @@ static int acp5x_dma_close(struct snd_soc_component *component,
struct i2s_dev_data *adata;
struct i2s_stream_instance *ins;
- prtd = asoc_substream_to_rtd(substream);
+ prtd = snd_soc_substream_to_rtd(substream);
component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
adata = dev_get_drvdata(component->dev);
ins = substream->runtime->private_data;
@@ -409,9 +409,9 @@ static int acp5x_audio_probe(struct platform_device *pdev)
}
pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
-
return 0;
}
@@ -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,14 +492,13 @@ 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 = {
.probe = acp5x_audio_probe,
- .remove_new = acp5x_audio_remove,
+ .remove = acp5x_audio_remove,
.driver = {
.name = "acp5x_i2s_dma",
.pm = &acp5x_pm_ops,
diff --git a/sound/soc/amd/vangogh/pci-acp5x.c b/sound/soc/amd/vangogh/pci-acp5x.c
index c4634a8a17cd..af56ff09f02a 100644
--- a/sound/soc/amd/vangogh/pci-acp5x.c
+++ b/sound/soc/amd/vangogh/pci-acp5x.c
@@ -2,7 +2,7 @@
//
// AMD Vangogh ACP PCI Driver
//
-// Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
+// Copyright (C) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
#include <linux/pci.h>
#include <linux/module.h>
@@ -13,6 +13,7 @@
#include <linux/pm_runtime.h>
#include "acp5x.h"
+#include "../mach-config.h"
struct acp5x_dev_data {
void __iomem *acp5x_base;
@@ -129,9 +130,13 @@ static int snd_acp5x_probe(struct pci_dev *pci,
int ret, i;
u32 addr, val;
- /* Return if acp config flag is defined */
+ /*
+ * Return if ACP config flag is defined, except when board
+ * supports SOF while it is not being enabled in kernel config.
+ */
flag = snd_amd_acp_find_config(pci);
- if (flag)
+ if (flag != FLAG_AMD_LEGACY &&
+ (flag != FLAG_AMD_SOF || IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_VANGOGH)))
return -ENODEV;
irqflags = IRQF_SHARED;
@@ -259,7 +264,7 @@ disable_pci:
return ret;
}
-static int __maybe_unused snd_acp5x_suspend(struct device *dev)
+static int snd_acp5x_suspend(struct device *dev)
{
int ret;
struct acp5x_dev_data *adata;
@@ -274,7 +279,7 @@ static int __maybe_unused snd_acp5x_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused snd_acp5x_resume(struct device *dev)
+static int snd_acp5x_resume(struct device *dev)
{
int ret;
struct acp5x_dev_data *adata;
@@ -289,9 +294,8 @@ static int __maybe_unused snd_acp5x_resume(struct device *dev)
}
static const struct dev_pm_ops acp5x_pm = {
- SET_RUNTIME_PM_OPS(snd_acp5x_suspend,
- snd_acp5x_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(snd_acp5x_suspend, snd_acp5x_resume)
+ RUNTIME_PM_OPS(snd_acp5x_suspend, snd_acp5x_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(snd_acp5x_suspend, snd_acp5x_resume)
};
static void snd_acp5x_remove(struct pci_dev *pci)
@@ -327,7 +331,7 @@ static struct pci_driver acp5x_driver = {
.probe = snd_acp5x_probe,
.remove = snd_acp5x_remove,
.driver = {
- .pm = &acp5x_pm,
+ .pm = pm_ptr(&acp5x_pm),
}
};
diff --git a/sound/soc/amd/yc/Makefile b/sound/soc/amd/yc/Makefile
index dc2974440388..7a0a3a410b2d 100644
--- a/sound/soc/amd/yc/Makefile
+++ b/sound/soc/amd/yc/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
# Yellow Carp platform Support
-snd-pci-acp6x-objs := pci-acp6x.o
-snd-acp6x-pdm-dma-objs := acp6x-pdm-dma.o
-snd-soc-acp6x-mach-objs := acp6x-mach.o
+snd-pci-acp6x-y := pci-acp6x.o
+snd-acp6x-pdm-dma-y := acp6x-pdm-dma.o
+snd-soc-acp6x-mach-y := acp6x-mach.o
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += snd-pci-acp6x.o
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += snd-acp6x-pdm-dma.o
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 31e466917c3d..f210a253da9f 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -175,6 +175,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, "21EF"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21EM"),
}
},
@@ -196,6 +203,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, "21J0"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21J5"),
}
},
@@ -210,7 +224,154 @@ 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, "82"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M1"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M3"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M4"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M5"),
+ }
+ },
+ {
+ .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"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82TL"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82UG"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82UU"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82V2"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82YM"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83AS"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83BS"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83HN"),
+ }
+ },
+ {
+ .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, "RB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"),
+ }
+ },
+ {
+ .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, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83J3"),
}
},
{
@@ -231,6 +392,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M5602RA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "M6400RC"),
}
},
@@ -244,6 +412,76 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M6500RC"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M6501RM"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "E1404FA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "E1504FA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M7600RE"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M3502RA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 B7ED"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7VF"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VEK"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
}
@@ -265,6 +503,20 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "TIMI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14 2022"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "TIMI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Redmi G 2022"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Razer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Blade 14 (2022) - RZ09-0427"),
}
@@ -294,6 +546,20 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Victus by HP Gaming Laptop 15-fb1xxx"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Victus by HP Gaming Laptop 15-fb2xxx"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8A42"),
}
},
@@ -308,12 +574,61 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8A44"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8A22"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8A3E"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8A7F"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8A81"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8B27"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8B2F"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8BD6"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "MECHREVO"),
DMI_MATCH(DMI_BOARD_NAME, "MRID6"),
}
@@ -321,10 +636,31 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "MDC"),
+ DMI_MATCH(DMI_BOARD_NAME, "Herbag_MDU"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "System76"),
DMI_MATCH(DMI_PRODUCT_VERSION, "pang12"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "System76"),
+ 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"),
+ }
+ },
{}
};
@@ -334,8 +670,14 @@ static int acp6x_probe(struct platform_device *pdev)
struct acp6x_pdm *machine = NULL;
struct snd_soc_card *card;
struct acpi_device *adev;
+ acpi_handle handle;
+ acpi_integer dmic_status;
int ret;
+ bool is_dmic_enable, wov_en;
+ /* IF WOV entry not found, enable dmic based on AcpDmicConnected entry*/
+ is_dmic_enable = false;
+ wov_en = true;
/* check the parent device's firmware node has _DSD or not */
adev = ACPI_COMPANION(pdev->dev.parent);
if (adev) {
@@ -343,9 +685,24 @@ static int acp6x_probe(struct platform_device *pdev)
if (!acpi_dev_get_property(adev, "AcpDmicConnected", ACPI_TYPE_INTEGER, &obj) &&
obj->integer.value == 1)
- platform_set_drvdata(pdev, &acp6x_card);
+ is_dmic_enable = true;
+ }
+
+ handle = ACPI_HANDLE(pdev->dev.parent);
+ ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
+ if (!ACPI_FAILURE(ret)) {
+ wov_en = dmic_status;
+ if (!wov_en)
+ return -ENODEV;
+ } else {
+ /* Incase of ACPI method read failure then jump to check_dmi_entry */
+ goto check_dmi_entry;
}
+ if (is_dmic_enable)
+ platform_set_drvdata(pdev, &acp6x_card);
+
+check_dmi_entry:
/* check for any DMI overrides */
dmi_id = dmi_first_match(yc_acp_quirk_table);
if (dmi_id)
@@ -378,5 +735,6 @@ static struct platform_driver acp6x_mach_driver = {
module_platform_driver(acp6x_mach_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD Yellow Carp support for DMIC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index d818eba48546..ac758b90f441 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -383,8 +383,9 @@ static int acp6x_pdm_audio_probe(struct platform_device *pdev)
}
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
return 0;
}
@@ -393,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;
@@ -414,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;
@@ -423,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;
@@ -433,16 +434,16 @@ 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 = {
.probe = acp6x_pdm_audio_probe,
- .remove_new = acp6x_pdm_audio_remove,
+ .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/apple/Kconfig b/sound/soc/apple/Kconfig
index 793f7782e0d7..d8dc2f1ccc83 100644
--- a/sound/soc/apple/Kconfig
+++ b/sound/soc/apple/Kconfig
@@ -1,8 +1,11 @@
+menu "Apple"
+
config SND_SOC_APPLE_MCA
tristate "Apple Silicon MCA driver"
depends on ARCH_APPLE || COMPILE_TEST
select SND_DMAENGINE_PCM
- default ARCH_APPLE
help
This option enables an ASoC platform driver for MCA peripherals found
on Apple Silicon SoCs.
+
+endmenu
diff --git a/sound/soc/apple/Makefile b/sound/soc/apple/Makefile
index 7a30bf452817..1eb8fbef60c6 100644
--- a/sound/soc/apple/Makefile
+++ b/sound/soc/apple/Makefile
@@ -1,3 +1,3 @@
-snd-soc-apple-mca-objs := mca.o
+snd-soc-apple-mca-y := mca.o
obj-$(CONFIG_SND_SOC_APPLE_MCA) += snd-soc-apple-mca.o
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index ce77934f3eef..c4dcb2b54591 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -161,7 +161,7 @@ struct mca_data {
struct mutex port_mutex;
int nclusters;
- struct mca_cluster clusters[];
+ struct mca_cluster clusters[] __counted_by(nclusters);
};
static void mca_modify(struct mca_cluster *cl, int regoffset, u32 mask, u32 val)
@@ -464,6 +464,28 @@ err:
return -EINVAL;
}
+static int mca_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ unsigned int mask, nchannels;
+
+ if (cl->tdm_slots) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mask = cl->tdm_tx_mask;
+ else
+ mask = cl->tdm_rx_mask;
+
+ nchannels = hweight32(mask);
+ } else {
+ nchannels = 2;
+ }
+
+ return snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, nchannels);
+}
+
static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
@@ -546,7 +568,7 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
static int mca_fe_get_port(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
struct snd_soc_pcm_runtime *be;
struct snd_soc_dpcm *dpcm;
@@ -559,7 +581,7 @@ static int mca_fe_get_port(struct snd_pcm_substream *substream)
if (!be)
return -EINVAL;
- return mca_dai_to_cluster(asoc_rtd_to_cpu(be, 0))->no;
+ return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
}
static int mca_fe_hw_params(struct snd_pcm_substream *substream,
@@ -616,7 +638,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
tdm_slot_width = 32;
if (tdm_slot_width < params_width(params)) {
- dev_err(dev, "TDM slots too narrow (tdm=%d params=%d)\n",
+ dev_err(dev, "TDM slots too narrow (tdm=%u params=%d)\n",
tdm_slot_width, params_width(params));
return -EINVAL;
}
@@ -680,6 +702,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops mca_fe_ops = {
+ .startup = mca_fe_startup,
.set_fmt = mca_fe_set_fmt,
.set_bclk_ratio = mca_set_bclk_ratio,
.set_tdm_slot = mca_fe_set_tdm_slot,
@@ -700,7 +723,7 @@ static bool mca_be_started(struct mca_cluster *cl)
static int mca_be_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *be = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
struct snd_soc_pcm_runtime *fe;
struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_cluster *fe_cl;
@@ -721,7 +744,7 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
if (!fe)
return -EINVAL;
- fe_cl = mca_dai_to_cluster(asoc_rtd_to_cpu(fe, 0));
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
if (mca_be_started(cl)) {
/*
@@ -811,8 +834,8 @@ static int mca_set_runtime_hwparams(struct snd_soc_component *component,
static int mca_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));
struct dma_chan *chan = cl->dma_chans[substream->stream];
int ret;
@@ -830,7 +853,7 @@ static int mca_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct dma_slave_config slave_config;
int ret;
@@ -857,7 +880,7 @@ static int mca_hw_params(struct snd_soc_component *component,
static int mca_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rtd->dai_link->no_pcm)
return 0;
@@ -868,7 +891,7 @@ static int mca_close(struct snd_soc_component *component,
static int mca_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rtd->dai_link->no_pcm)
return 0;
@@ -877,7 +900,7 @@ static int mca_trigger(struct snd_soc_component *component,
* Before we do the PCM trigger proper, insert an opportunity
* to reset the frontend's SERDES.
*/
- mca_fe_early_trigger(substream, cmd, asoc_rtd_to_cpu(rtd, 0));
+ mca_fe_early_trigger(substream, cmd, snd_soc_rtd_to_cpu(rtd, 0));
return snd_dmaengine_pcm_trigger(substream, cmd);
}
@@ -885,7 +908,7 @@ static int mca_trigger(struct snd_soc_component *component,
static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rtd->dai_link->no_pcm)
return -ENOTSUPP;
@@ -911,7 +934,7 @@ static void mca_pcm_free(struct snd_soc_component *component,
struct snd_pcm *pcm)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_chip(pcm);
- struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));
unsigned int i;
if (rtd->dai_link->no_pcm)
@@ -933,7 +956,7 @@ static void mca_pcm_free(struct snd_soc_component *component,
static int mca_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));
unsigned int i;
if (rtd->dai_link->no_pcm)
@@ -1168,6 +1191,7 @@ static void apple_mca_remove(struct platform_device *pdev)
}
static const struct of_device_id apple_mca_of_match[] = {
+ { .compatible = "apple,t8103-mca", },
{ .compatible = "apple,mca", },
{}
};
@@ -1179,7 +1203,7 @@ static struct platform_driver apple_mca_driver = {
.of_match_table = apple_mca_of_match,
},
.probe = apple_mca_probe,
- .remove_new = apple_mca_remove,
+ .remove = apple_mca_remove,
};
module_platform_driver(apple_mca_driver);
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 5d59e00be823..4f51612f3dd2 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -1,13 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-config SND_ATMEL_SOC
- tristate "SoC Audio for the Atmel System-on-Chip"
+menu "Atmel"
depends on HAS_IOMEM
- help
- Say Y or M if you want to add support for codecs attached to
- the ATMEL SSC interface. You will also need
- to select the audio interfaces to support below.
-
-if SND_ATMEL_SOC
config SND_ATMEL_SOC_PDC
bool
@@ -176,4 +169,4 @@ config SND_MCHP_SOC_PDMC
2 data lines. The signal path includes an audio grade programmable
decimation filter and outputs 24-bit audio words.
-endif
+endmenu
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 043097a08ea8..03d9c419c93f 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
# AT91 Platform Support
-snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
-snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
-snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
-snd-soc-atmel-i2s-objs := atmel-i2s.o
-snd-soc-mchp-i2s-mcc-objs := mchp-i2s-mcc.o
-snd-soc-mchp-spdiftx-objs := mchp-spdiftx.o
-snd-soc-mchp-spdifrx-objs := mchp-spdifrx.o
-snd-soc-mchp-pdmc-objs := mchp-pdmc.o
+snd-soc-atmel-pcm-pdc-y := atmel-pcm-pdc.o
+snd-soc-atmel-pcm-dma-y := atmel-pcm-dma.o
+snd-soc-atmel_ssc_dai-y := atmel_ssc_dai.o
+snd-soc-atmel-i2s-y := atmel-i2s.o
+snd-soc-mchp-i2s-mcc-y := mchp-i2s-mcc.o
+snd-soc-mchp-spdiftx-y := mchp-spdiftx.o
+snd-soc-mchp-spdifrx-y := mchp-spdifrx.o
+snd-soc-mchp-pdmc-y := mchp-pdmc.o
# pdc and dma need to both be built-in if any user of
# ssc is built-in.
@@ -25,13 +25,13 @@ obj-$(CONFIG_SND_MCHP_SOC_SPDIFRX) += snd-soc-mchp-spdifrx.o
obj-$(CONFIG_SND_MCHP_SOC_PDMC) += snd-soc-mchp-pdmc.o
# AT91 Machine Support
-snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
-snd-atmel-soc-wm8904-objs := atmel_wm8904.o
-snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
-snd-atmel-soc-classd-objs := atmel-classd.o
-snd-atmel-soc-pdmic-objs := atmel-pdmic.o
-snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
-snd-soc-mikroe-proto-objs := mikroe-proto.o
+snd-soc-sam9g20-wm8731-y := sam9g20_wm8731.o
+snd-atmel-soc-wm8904-y := atmel_wm8904.o
+snd-soc-sam9x5-wm8731-y := sam9x5_wm8731.o
+snd-atmel-soc-classd-y := atmel-classd.o
+snd-atmel-soc-pdmic-y := atmel-pdmic.o
+snd-atmel-soc-tse850-pcm5142-y := tse850-pcm5142.o
+snd-soc-mikroe-proto-y := mikroe-proto.o
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 4c1985711218..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>
@@ -118,7 +119,7 @@ static const struct snd_pcm_hardware atmel_classd_hw = {
static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
int err;
@@ -141,7 +142,7 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct dma_slave_config *slave_config)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
if (params_physical_width(params) != 16) {
@@ -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;
}
@@ -338,7 +339,7 @@ atmel_classd_cpu_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_component *component = cpu_dai->component;
int fs;
@@ -381,7 +382,7 @@ static void
atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
clk_disable_unprepare(dd->gclk);
@@ -473,19 +474,22 @@ static int atmel_classd_asoc_card_init(struct device *dev,
if (!dai_link)
return -ENOMEM;
- comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+ comp = devm_kzalloc(dev, 2 * sizeof(*comp), GFP_KERNEL);
if (!comp)
return -ENOMEM;
- dai_link->cpus = comp;
- dai_link->codecs = &asoc_dummy_dlc;
+ dai_link->cpus = &comp[0];
+ dai_link->codecs = &snd_soc_dummy_dlc;
+ dai_link->platforms = &comp[1];
dai_link->num_cpus = 1;
dai_link->num_codecs = 1;
+ dai_link->num_platforms = 1;
dai_link->name = "CLASSD";
dai_link->stream_name = "CLASSD PCM";
dai_link->cpus->dai_name = dev_name(dev);
+ dai_link->platforms->name = dev_name(dev);
card->dai_link = dai_link;
card->num_links = 1;
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 49930baf5e4d..762199faf872 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -163,11 +163,14 @@ struct atmel_i2s_gck_param {
#define I2S_MCK_12M288 12288000UL
#define I2S_MCK_11M2896 11289600UL
+#define I2S_MCK_6M144 6144000UL
/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */
static const struct atmel_i2s_gck_param gck_params[] = {
+ /* mck = 6.144Mhz */
+ { 8000, I2S_MCK_6M144, 1, 47}, /* mck = 768 fs */
+
/* mck = 12.288MHz */
- { 8000, I2S_MCK_12M288, 0, 47}, /* mck = 1536 fs */
{ 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */
{ 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */
{ 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */
@@ -529,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return err;
}
-static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
- .prepare = atmel_i2s_prepare,
- .trigger = atmel_i2s_trigger,
- .hw_params = atmel_i2s_hw_params,
- .set_fmt = atmel_i2s_set_dai_fmt,
-};
-
static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -544,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
+ .probe = atmel_i2s_dai_probe,
+ .prepare = atmel_i2s_prepare,
+ .trigger = atmel_i2s_trigger,
+ .hw_params = atmel_i2s_hw_params,
+ .set_fmt = atmel_i2s_set_dai_fmt,
+};
+
static struct snd_soc_dai_driver atmel_i2s_dai = {
- .probe = atmel_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -727,10 +730,10 @@ static void atmel_i2s_remove(struct platform_device *pdev)
static struct platform_driver atmel_i2s_driver = {
.driver = {
.name = "atmel_i2s",
- .of_match_table = of_match_ptr(atmel_i2s_dt_ids),
+ .of_match_table = atmel_i2s_dt_ids,
},
.probe = atmel_i2s_probe,
- .remove_new = atmel_i2s_remove,
+ .remove = atmel_i2s_remove,
};
module_platform_driver(atmel_i2s_driver);
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index 96a8c7dba98f..7306e04da513 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -52,10 +52,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
static void atmel_pcm_dma_irq(u32 ssc_sr,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pcm_dma_params *prtd;
- prtd = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ prtd = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if (ssc_sr & prtd->mask->ssc_error) {
if (snd_pcm_running(substream))
@@ -77,12 +77,12 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pcm_dma_params *prtd;
struct ssc_device *ssc;
int ret;
- prtd = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ prtd = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
ssc = prtd->ssc;
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 3e7ea2021b46..7db8df85c54f 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -140,12 +140,12 @@ static int atmel_pcm_hw_params(struct snd_soc_component *component,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct atmel_runtime_data *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
/* this may get called several times by oss emulation
* with different params */
- prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ prtd->params = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
prtd->dma_buffer = runtime->dma_addr;
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index efcbdd1a629f..4dfc7e5ca8ff 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -104,7 +104,7 @@ static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev)
static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
int ret;
@@ -132,7 +132,7 @@ static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream,
static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
/* Disable the overrun error interrupt */
@@ -145,7 +145,7 @@ static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream,
static int atmel_pdmic_cpu_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_component *component = cpu_dai->component;
u32 val;
@@ -191,7 +191,7 @@ atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct dma_slave_config *slave_config)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
int ret;
@@ -280,7 +280,7 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
static int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int dgain_val, scale_val;
int i;
@@ -304,7 +304,7 @@ static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int max = mc->max;
unsigned int val;
int ret;
@@ -356,7 +356,7 @@ atmel_pdmic_cpu_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_component *component = cpu_dai->component;
unsigned int rate_min = substream->runtime->hw.rate_min;
@@ -501,7 +501,7 @@ static int atmel_pdmic_asoc_card_init(struct device *dev,
return -ENOMEM;
dai_link->cpus = comp;
- dai_link->codecs = &asoc_dummy_dlc;
+ dai_link->codecs = &snd_soc_dummy_dlc;
dai_link->num_cpus = 1;
dai_link->num_codecs = 1;
@@ -690,7 +690,7 @@ unregister_codec:
static struct platform_driver atmel_pdmic_driver = {
.driver = {
.name = "atmel-pdmic",
- .of_match_table = of_match_ptr(atmel_pdmic_of_match),
+ .of_match_table = atmel_pdmic_of_match,
.pm = &snd_soc_pm_ops,
},
.probe = atmel_pdmic_probe,
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 3763454436c1..89098f41679c 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -821,8 +821,9 @@ static int atmel_ssc_resume(struct snd_soc_component *component)
return 0;
}
+/* S24_LE is not supported if more than 2 channels (of TDM slots) are used. */
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+ SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.startup = atmel_ssc_startup,
@@ -836,6 +837,7 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
static struct snd_soc_dai_driver atmel_ssc_dai = {
.playback = {
+ .stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
@@ -843,6 +845,7 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
.rate_max = 384000,
.formats = ATMEL_SSC_FORMATS,},
.capture = {
+ .stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index 00e98136bec2..0f4021c6c588 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -10,7 +10,6 @@
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <sound/soc.h>
@@ -26,8 +25,8 @@ static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = {
static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK,
@@ -188,7 +187,7 @@ static struct platform_driver atmel_asoc_wm8904_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = atmel_asoc_wm8904_probe,
- .remove_new = atmel_asoc_wm8904_remove,
+ .remove = atmel_asoc_wm8904_remove,
};
module_platform_driver(atmel_asoc_wm8904_driver);
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 7c83d48ca1a0..17d138bb9064 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -16,7 +16,7 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/lcm.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -221,6 +221,15 @@
#define MCHP_I2SMCC_MAX_CHANNELS 8
#define MCHP_I2MCC_TDM_SLOT_WIDTH 32
+/*
+ * ---- DMA chunk size allowed ----
+ */
+#define MCHP_I2SMCC_DMA_8_WORD_CHUNK 8
+#define MCHP_I2SMCC_DMA_4_WORD_CHUNK 4
+#define MCHP_I2SMCC_DMA_2_WORD_CHUNK 2
+#define MCHP_I2SMCC_DMA_1_WORD_CHUNK 1
+#define DMA_BURST_ALIGNED(_p, _s, _w) !(_p % (_s * _w))
+
static const struct regmap_config mchp_i2s_mcc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -504,12 +513,30 @@ static int mchp_i2s_mcc_is_running(struct mchp_i2s_mcc_dev *dev)
return !!(sr & (MCHP_I2SMCC_SR_TXEN | MCHP_I2SMCC_SR_RXEN));
}
+static inline int mchp_i2s_mcc_period_to_maxburst(int period_size, int sample_size)
+{
+ int p_size = period_size;
+ int s_size = sample_size;
+
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_8_WORD_CHUNK))
+ return MCHP_I2SMCC_DMA_8_WORD_CHUNK;
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_4_WORD_CHUNK))
+ return MCHP_I2SMCC_DMA_4_WORD_CHUNK;
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_2_WORD_CHUNK))
+ return MCHP_I2SMCC_DMA_2_WORD_CHUNK;
+ return MCHP_I2SMCC_DMA_1_WORD_CHUNK;
+}
+
static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
unsigned long rate = 0;
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
+ int sample_bytes = params_physical_width(params) / 8;
+ int period_bytes = params_period_size(params) *
+ params_channels(params) * sample_bytes;
+ int maxburst;
u32 mra = 0;
u32 mrb = 0;
unsigned int channels = params_channels(params);
@@ -519,9 +546,9 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
int ret;
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
+ dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u period_bytes=%d\n",
__func__, params_rate(params), params_format(params),
- params_width(params), params_channels(params));
+ params_width(params), params_channels(params), period_bytes);
switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -630,11 +657,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
* We must have the same burst size configured
* in the DMA transfer and in out IP
*/
- mrb |= MCHP_I2SMCC_MRB_DMACHUNK(channels);
+ maxburst = mchp_i2s_mcc_period_to_maxburst(period_bytes, sample_bytes);
+ mrb |= MCHP_I2SMCC_MRB_DMACHUNK(maxburst);
if (is_playback)
- dev->playback.maxburst = 1 << (fls(channels) - 1);
+ dev->playback.maxburst = maxburst;
else
- dev->capture.maxburst = 1 << (fls(channels) - 1);
+ dev->capture.maxburst = maxburst;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
@@ -870,17 +898,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
- .set_sysclk = mchp_i2s_mcc_set_sysclk,
- .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
- .startup = mchp_i2s_mcc_startup,
- .trigger = mchp_i2s_mcc_trigger,
- .hw_params = mchp_i2s_mcc_hw_params,
- .hw_free = mchp_i2s_mcc_hw_free,
- .set_fmt = mchp_i2s_mcc_set_dai_fmt,
- .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
-};
-
static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
{
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -895,6 +912,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
+ .probe = mchp_i2s_mcc_dai_probe,
+ .set_sysclk = mchp_i2s_mcc_set_sysclk,
+ .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
+ .startup = mchp_i2s_mcc_startup,
+ .trigger = mchp_i2s_mcc_trigger,
+ .hw_params = mchp_i2s_mcc_hw_params,
+ .hw_free = mchp_i2s_mcc_hw_free,
+ .set_fmt = mchp_i2s_mcc_set_dai_fmt,
+ .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
+};
+
#define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -906,16 +935,15 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
- .probe = mchp_i2s_mcc_dai_probe,
.playback = {
- .stream_name = "I2SMCC-Playback",
+ .stream_name = "Playback",
.channels_min = 1,
.channels_max = 8,
.rates = MCHP_I2SMCC_RATES,
.formats = MCHP_I2SMCC_FORMATS,
},
.capture = {
- .stream_name = "I2SMCC-Capture",
+ .stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,
.rates = MCHP_I2SMCC_RATES,
@@ -1098,10 +1126,10 @@ static void mchp_i2s_mcc_remove(struct platform_device *pdev)
static struct platform_driver mchp_i2s_mcc_driver = {
.driver = {
.name = "mchp_i2s_mcc",
- .of_match_table = of_match_ptr(mchp_i2s_mcc_dt_ids),
+ .of_match_table = mchp_i2s_mcc_dt_ids,
},
.probe = mchp_i2s_mcc_probe,
- .remove_new = mchp_i2s_mcc_remove,
+ .remove = mchp_i2s_mcc_remove,
};
module_platform_driver(mchp_i2s_mcc_driver);
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
index c79c73e6791e..06dc3c48e7e8 100644
--- a/sound/soc/atmel/mchp-pdmc.c
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -90,6 +90,15 @@
#define MCHP_PDMC_DS_NO 2
#define MCHP_PDMC_EDGE_NO 2
+/*
+ * ---- DMA chunk size allowed ----
+ */
+#define MCHP_PDMC_DMA_8_WORD_CHUNK 8
+#define MCHP_PDMC_DMA_4_WORD_CHUNK 4
+#define MCHP_PDMC_DMA_2_WORD_CHUNK 2
+#define MCHP_PDMC_DMA_1_WORD_CHUNK 1
+#define DMA_BURST_ALIGNED(_p, _s, _w) !(_p % (_s * _w))
+
struct mic_map {
int ds_pos;
int clk_edge;
@@ -115,6 +124,7 @@ struct mchp_pdmc {
int mic_no;
int sinc_order;
bool audio_filter_en;
+ atomic_t busy_stream;
};
static const char *const mchp_pdmc_sinc_filter_order_text[] = {
@@ -158,6 +168,10 @@ static int mchp_pdmc_sinc_order_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ if (atomic_read(&dd->busy_stream))
+ return -EBUSY;
+
if (val == dd->sinc_order)
return 0;
@@ -184,6 +198,9 @@ static int mchp_pdmc_af_put(struct snd_kcontrol *kcontrol,
struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component);
bool af = uvalue->value.integer.value[0] ? true : false;
+ if (atomic_read(&dd->busy_stream))
+ return -EBUSY;
+
if (dd->audio_filter_en == af)
return 0;
@@ -285,6 +302,9 @@ static int mchp_pdmc_chmap_ctl_put(struct snd_kcontrol *kcontrol,
if (!substream)
return -ENODEV;
+ if (!substream->runtime)
+ return 0; /* just for avoiding error from alsactl restore */
+
map = mchp_pdmc_chmap_get(substream, info);
if (!map)
return -EINVAL;
@@ -370,60 +390,10 @@ static const struct snd_kcontrol_new mchp_pdmc_snd_controls[] = {
},
};
-static int mchp_pdmc_close(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- return snd_soc_add_component_controls(component, mchp_pdmc_snd_controls,
- ARRAY_SIZE(mchp_pdmc_snd_controls));
-}
-
-static int mchp_pdmc_open(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- int i;
-
- /* remove controls that can't be changed at runtime */
- for (i = 0; i < ARRAY_SIZE(mchp_pdmc_snd_controls); i++) {
- const struct snd_kcontrol_new *control = &mchp_pdmc_snd_controls[i];
- struct snd_ctl_elem_id id;
- struct snd_kcontrol *kctl;
- int err;
-
- if (component->name_prefix)
- snprintf(id.name, sizeof(id.name), "%s %s", component->name_prefix,
- control->name);
- else
- strscpy(id.name, control->name, sizeof(id.name));
-
- id.numid = 0;
- id.iface = control->iface;
- id.device = control->device;
- id.subdevice = control->subdevice;
- id.index = control->index;
- kctl = snd_ctl_find_id(component->card->snd_card, &id);
- if (!kctl) {
- dev_err(component->dev, "Failed to find %s\n", control->name);
- continue;
- }
- err = snd_ctl_remove(component->card->snd_card, kctl);
- if (err < 0) {
- dev_err(component->dev, "%d: Failed to remove %s\n", err,
- control->name);
- continue;
- }
- }
-
- return 0;
-}
-
static const struct snd_soc_component_driver mchp_pdmc_dai_component = {
.name = "mchp-pdmc",
.controls = mchp_pdmc_snd_controls,
.num_controls = ARRAY_SIZE(mchp_pdmc_snd_controls),
- .open = &mchp_pdmc_open,
- .close = &mchp_pdmc_close,
- .legacy_dai_naming = 1,
- .trigger_start = SND_SOC_TRIGGER_ORDER_LDC,
};
static const unsigned int mchp_pdmc_1mic[] = {1};
@@ -519,15 +489,18 @@ static u32 mchp_pdmc_mr_set_osr(int audio_filter_en, unsigned int osr)
return 0;
}
-static inline int mchp_pdmc_period_to_maxburst(int period_size)
+static inline int mchp_pdmc_period_to_maxburst(int period_size, int sample_size)
{
- if (!(period_size % 8))
- return 8;
- if (!(period_size % 4))
- return 4;
- if (!(period_size % 2))
- return 2;
- return 1;
+ int p_size = period_size;
+ int s_size = sample_size;
+
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_PDMC_DMA_8_WORD_CHUNK))
+ return MCHP_PDMC_DMA_8_WORD_CHUNK;
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_PDMC_DMA_4_WORD_CHUNK))
+ return MCHP_PDMC_DMA_4_WORD_CHUNK;
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_PDMC_DMA_2_WORD_CHUNK))
+ return MCHP_PDMC_DMA_2_WORD_CHUNK;
+ return MCHP_PDMC_DMA_1_WORD_CHUNK;
}
static struct snd_pcm_chmap_elem mchp_pdmc_std_chmaps[] = {
@@ -555,14 +528,18 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
unsigned int channels = params_channels(params);
unsigned int osr = 0, osr_start;
unsigned int fs = params_rate(params);
+ int sample_bytes = params_physical_width(params) / 8;
+ int period_bytes = params_period_size(params) *
+ params_channels(params) * sample_bytes;
+ int maxburst;
u32 mr_val = 0;
u32 cfgr_val = 0;
int i;
int ret;
- dev_dbg(comp->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
+ dev_dbg(comp->dev, "%s() rate=%u format=%#x width=%u channels=%u period_bytes=%d\n",
__func__, params_rate(params), params_format(params),
- params_width(params), params_channels(params));
+ params_width(params), params_channels(params), period_bytes);
if (channels > dd->mic_no) {
dev_err(comp->dev, "more channels %u than microphones %d\n",
@@ -579,6 +556,11 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i);
}
+ /*
+ * from these point forward, we consider the controller busy, so the
+ * audio filter and SINC order can't be changed
+ */
+ atomic_set(&dd->busy_stream, 1);
for (osr_start = dd->audio_filter_en ? 64 : 8;
osr_start <= 256 && best_diff_rate; osr_start *= 2) {
long round_rate;
@@ -616,7 +598,8 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
mr_val |= FIELD_PREP(MCHP_PDMC_MR_SINCORDER_MASK, dd->sinc_order);
- dd->addr.maxburst = mchp_pdmc_period_to_maxburst(snd_pcm_lib_period_bytes(substream));
+ maxburst = mchp_pdmc_period_to_maxburst(period_bytes, sample_bytes);
+ dd->addr.maxburst = maxburst;
mr_val |= FIELD_PREP(MCHP_PDMC_MR_CHUNK_MASK, dd->addr.maxburst);
dev_dbg(comp->dev, "maxburst set to %d\n", dd->addr.maxburst);
@@ -706,13 +689,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
- .set_fmt = mchp_pdmc_set_fmt,
- .startup = mchp_pdmc_startup,
- .hw_params = mchp_pdmc_hw_params,
- .trigger = mchp_pdmc_trigger,
-};
-
static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd)
{
struct mchp_pdmc_chmap *info;
@@ -765,8 +741,17 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd,
return ret;
}
+static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
+ .probe = mchp_pdmc_dai_probe,
+ .set_fmt = mchp_pdmc_set_fmt,
+ .startup = mchp_pdmc_startup,
+ .hw_params = mchp_pdmc_hw_params,
+ .trigger = mchp_pdmc_trigger,
+ .pcm_new = &mchp_pdmc_pcm_new,
+};
+
static struct snd_soc_dai_driver mchp_pdmc_dai = {
- .probe = mchp_pdmc_dai_probe,
+ .name = "mchp-pdmc",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -777,7 +762,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = {
.formats = SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &mchp_pdmc_dai_ops,
- .pcm_new = &mchp_pdmc_pcm_new,
};
/* PDMC interrupt handler */
@@ -962,7 +946,7 @@ static int mchp_pdmc_dt_init(struct mchp_pdmc *dd)
/* used to clean the channel index found on RHR's MSB */
static int mchp_pdmc_process(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
- void *buf, unsigned long bytes)
+ unsigned long bytes)
{
struct snd_pcm_runtime *runtime = substream->runtime;
u8 *dma_ptr = runtime->dma_area + hwoff +
@@ -1133,6 +1117,8 @@ static void mchp_pdmc_remove(struct platform_device *pdev)
{
struct mchp_pdmc *dd = platform_get_drvdata(pdev);
+ atomic_set(&dd->busy_stream, 0);
+
if (!pm_runtime_status_suspended(dd->dev))
mchp_pdmc_runtime_suspend(dd->dev);
@@ -1161,7 +1147,7 @@ static struct platform_driver mchp_pdmc_driver = {
.pm = pm_ptr(&mchp_pdmc_pm_ops),
},
.probe = mchp_pdmc_probe,
- .remove_new = mchp_pdmc_remove,
+ .remove = mchp_pdmc_remove,
};
module_platform_driver(mchp_pdmc_driver);
diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c
index ff6aba143aee..521bee4998f8 100644
--- a/sound/soc/atmel/mchp-spdifrx.c
+++ b/sound/soc/atmel/mchp-spdifrx.c
@@ -503,11 +503,6 @@ unlock:
return ret;
}
-static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = {
- .trigger = mchp_spdifrx_trigger,
- .hw_params = mchp_spdifrx_hw_params,
-};
-
#define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -582,7 +577,6 @@ static int mchp_spdifrx_cs_get(struct mchp_spdifrx_dev *dev,
sizeof(ch_stat->data));
pm_runtime_put:
- pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
unlock:
mutex_unlock(&dev->mlock);
@@ -665,7 +659,6 @@ static int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev,
sizeof(user_data->data));
pm_runtime_put:
- pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
unlock:
mutex_unlock(&dev->mlock);
@@ -731,7 +724,6 @@ static int mchp_spdifrx_ulock_get(struct snd_kcontrol *kcontrol,
uvalue->value.integer.value[0] = ctrl->ulock;
- pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
unlock:
mutex_unlock(&dev->mlock);
@@ -767,7 +759,6 @@ static int mchp_spdifrx_badf_get(struct snd_kcontrol *kcontrol,
ctrl->badf = 0;
}
- pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
unlock:
mutex_unlock(&dev->mlock);
@@ -816,7 +807,6 @@ static int mchp_spdifrx_signal_get(struct snd_kcontrol *kcontrol,
regmap_read(dev->regmap, SPDIFRX_RSR, &val);
}
- pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
unlock:
@@ -880,7 +870,6 @@ static int mchp_spdifrx_rate_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = rate / (32 * SPDIFRX_RSR_IFS(val));
pm_runtime_put:
- pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
unlock:
mutex_unlock(&dev->mlock);
@@ -1009,12 +998,17 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = {
+ .probe = mchp_spdifrx_dai_probe,
+ .remove = mchp_spdifrx_dai_remove,
+ .trigger = mchp_spdifrx_trigger,
+ .hw_params = mchp_spdifrx_hw_params,
+};
+
static struct snd_soc_dai_driver mchp_spdifrx_dai = {
.name = "mchp-spdifrx",
- .probe = mchp_spdifrx_dai_probe,
- .remove = mchp_spdifrx_dai_remove,
.capture = {
- .stream_name = "S/PDIF Capture",
+ .stream_name = "Capture",
.channels_min = SPDIFRX_CHANNELS,
.channels_max = SPDIFRX_CHANNELS,
.rates = MCHP_SPDIF_RATES,
@@ -1194,10 +1188,10 @@ static void mchp_spdifrx_remove(struct platform_device *pdev)
static struct platform_driver mchp_spdifrx_driver = {
.probe = mchp_spdifrx_probe,
- .remove_new = mchp_spdifrx_remove,
+ .remove = mchp_spdifrx_remove,
.driver = {
.name = "mchp_spdifrx",
- .of_match_table = of_match_ptr(mchp_spdifrx_dt_ids),
+ .of_match_table = mchp_spdifrx_dt_ids,
.pm = pm_ptr(&mchp_spdifrx_pm_ops),
},
};
diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c
index 1d3e17119888..245c0352c141 100644
--- a/sound/soc/atmel/mchp-spdiftx.c
+++ b/sound/soc/atmel/mchp-spdiftx.c
@@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream,
SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR);
}
-static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = {
- .startup = mchp_spdiftx_dai_startup,
- .shutdown = mchp_spdiftx_dai_shutdown,
- .trigger = mchp_spdiftx_trigger,
- .hw_params = mchp_spdiftx_hw_params,
- .hw_free = mchp_spdiftx_hw_free,
-};
-
#define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -703,11 +695,19 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = {
+ .probe = mchp_spdiftx_dai_probe,
+ .startup = mchp_spdiftx_dai_startup,
+ .shutdown = mchp_spdiftx_dai_shutdown,
+ .trigger = mchp_spdiftx_trigger,
+ .hw_params = mchp_spdiftx_hw_params,
+ .hw_free = mchp_spdiftx_hw_free,
+};
+
static struct snd_soc_dai_driver mchp_spdiftx_dai = {
.name = "mchp-spdiftx",
- .probe = mchp_spdiftx_dai_probe,
.playback = {
- .stream_name = "S/PDIF Playback",
+ .stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = MCHP_SPDIFTX_RATES,
@@ -888,10 +888,10 @@ static void mchp_spdiftx_remove(struct platform_device *pdev)
static struct platform_driver mchp_spdiftx_driver = {
.probe = mchp_spdiftx_probe,
- .remove_new = mchp_spdiftx_remove,
+ .remove = mchp_spdiftx_remove,
.driver = {
.name = "mchp_spdiftx",
- .of_match_table = of_match_ptr(mchp_spdiftx_dt_ids),
+ .of_match_table = mchp_spdiftx_dt_ids,
.pm = pm_ptr(&mchp_spdiftx_pm_ops)
},
};
diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c
index 30c87c2c1b0b..8341a6e06493 100644
--- a/sound/soc/atmel/mikroe-proto.c
+++ b/sound/soc/atmel/mikroe-proto.c
@@ -21,7 +21,7 @@
static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
/* Set proto sysclk */
int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
@@ -140,7 +140,7 @@ static int snd_proto_probe(struct platform_device *pdev)
dai->dai_fmt = dai_fmt;
- ret = snd_soc_register_card(&snd_proto);
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_proto);
if (ret)
dev_err_probe(&pdev->dev, ret,
"snd_soc_register_card() failed\n");
@@ -155,11 +155,6 @@ put_codec_node:
return ret;
}
-static void snd_proto_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&snd_proto);
-}
-
static const struct of_device_id snd_proto_of_match[] = {
{ .compatible = "mikroe,mikroe-proto", },
{},
@@ -172,7 +167,6 @@ static struct platform_driver snd_proto_driver = {
.of_match_table = snd_proto_of_match,
},
.probe = snd_proto_probe,
- .remove_new = snd_proto_remove,
};
module_platform_driver(snd_proto_driver);
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 0405e9e49140..be54a63f43d5 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -66,7 +66,7 @@ static const struct snd_soc_dapm_route intercon[] = {
*/
static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct device *dev = rtd->dev;
int ret;
@@ -80,7 +80,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
}
#ifndef ENABLE_MIC_INPUT
- snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
+ snd_soc_dapm_disable_pin(snd_soc_card_to_dapm(rtd->card), "Int Mic");
#endif
return 0;
@@ -207,7 +207,7 @@ static struct platform_driver at91sam9g20ek_audio_driver = {
.of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids),
},
.probe = at91sam9g20ek_audio_probe,
- .remove_new = at91sam9g20ek_audio_remove,
+ .remove = at91sam9g20ek_audio_remove,
};
module_platform_driver(at91sam9g20ek_audio_driver);
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
index cd1d59a90e02..1b5ef4e9d2b8 100644
--- a/sound/soc/atmel/sam9x5_wm8731.c
+++ b/sound/soc/atmel/sam9x5_wm8731.c
@@ -40,7 +40,7 @@ struct sam9x5_drvdata {
*/
static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct device *dev = rtd->dev;
int ret;
@@ -196,7 +196,7 @@ static struct platform_driver sam9x5_wm8731_driver = {
.of_match_table = of_match_ptr(sam9x5_wm8731_of_match),
},
.probe = sam9x5_wm8731_driver_probe,
- .remove_new = sam9x5_wm8731_driver_remove,
+ .remove = sam9x5_wm8731_driver_remove,
};
module_platform_driver(sam9x5_wm8731_driver);
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index efead272d92b..0b4927d07f25 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -35,11 +35,9 @@
// of the (filtered) output from the PCM5142 codec.
#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
@@ -60,8 +58,8 @@ struct tse850_priv {
static int tse850_get_mux1(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
ucontrol->value.enumerated.item[0] = tse850->loop1_cache;
@@ -72,8 +70,8 @@ static int tse850_get_mux1(struct snd_kcontrol *kctrl,
static int tse850_put_mux1(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
unsigned int val = ucontrol->value.enumerated.item[0];
@@ -90,8 +88,8 @@ static int tse850_put_mux1(struct snd_kcontrol *kctrl,
static int tse850_get_mux2(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
ucontrol->value.enumerated.item[0] = tse850->loop2_cache;
@@ -102,8 +100,8 @@ static int tse850_get_mux2(struct snd_kcontrol *kctrl,
static int tse850_put_mux2(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
unsigned int val = ucontrol->value.enumerated.item[0];
@@ -120,8 +118,8 @@ static int tse850_put_mux2(struct snd_kcontrol *kctrl,
static int tse850_get_mix(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
ucontrol->value.enumerated.item[0] = tse850->add_cache;
@@ -132,8 +130,8 @@ static int tse850_get_mix(struct snd_kcontrol *kctrl,
static int tse850_put_mix(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
int connect = !!ucontrol->value.integer.value[0];
@@ -154,8 +152,8 @@ static int tse850_put_mix(struct snd_kcontrol *kctrl,
static int tse850_get_ana(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
int ret;
@@ -187,8 +185,8 @@ static int tse850_get_ana(struct snd_kcontrol *kctrl,
static int tse850_put_ana(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kctrl);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
unsigned int uV = ucontrol->value.enumerated.item[0];
@@ -229,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[] = {
@@ -430,10 +421,10 @@ MODULE_DEVICE_TABLE(of, tse850_dt_ids);
static struct platform_driver tse850_driver = {
.driver = {
.name = "axentia-tse850-pcm5142",
- .of_match_table = of_match_ptr(tse850_dt_ids),
+ .of_match_table = tse850_dt_ids,
},
.probe = tse850_probe,
- .remove_new = tse850_remove,
+ .remove = tse850_remove,
};
module_platform_driver(tse850_driver);
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 8a78809e8754..a7630897bc0b 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -2,6 +2,8 @@
##
## Au1200/Au1550/Au1300 PSC + DBDMA
##
+menu "Au1x"
+
config SND_SOC_AU1XPSC
tristate "SoC Audio for Au12xx/Au13xx/Au1550"
depends on MIPS_ALCHEMY
@@ -63,3 +65,5 @@ config SND_SOC_DB1200
Select this option to enable audio (AC97 and I2S) on the
Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards.
If you need Db1300 touchscreen support, you definitely want to say Y.
+
+endmenu
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile
index 33183d7fe057..9c6f5c38f92d 100644
--- a/sound/soc/au1x/Makefile
+++ b/sound/soc/au1x/Makefile
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
# Au1200/Au1550 PSC audio
-snd-soc-au1xpsc-dbdma-objs := dbdma2.o
-snd-soc-au1xpsc-i2s-objs := psc-i2s.o
-snd-soc-au1xpsc-ac97-objs := psc-ac97.o
+snd-soc-au1xpsc-dbdma-y := dbdma2.o
+snd-soc-au1xpsc-i2s-y := psc-i2s.o
+snd-soc-au1xpsc-ac97-y := psc-ac97.o
# Au1000/1500/1100 Audio units
-snd-soc-au1x-dma-objs := dma.o
-snd-soc-au1x-ac97c-objs := ac97c.o
-snd-soc-au1x-i2sc-objs := i2sc.o
+snd-soc-au1x-dma-y := dma.o
+snd-soc-au1x-ac97c-y := ac97c.o
+snd-soc-au1x-i2sc-y := i2sc.o
obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o
obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o
@@ -17,8 +17,8 @@ obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o
obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o
# Boards
-snd-soc-db1000-objs := db1000.o
-snd-soc-db1200-objs := db1200.o
+snd-soc-db1000-y := db1000.o
+snd-soc-db1200-y := db1200.o
obj-$(CONFIG_SND_SOC_DB1000) += snd-soc-db1000.o
obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
index a11d6841afc2..f8ab936250dc 100644
--- a/sound/soc/au1x/ac97c.c
+++ b/sound/soc/au1x/ac97c.c
@@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
- .startup = alchemy_ac97c_startup,
-};
-
static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
{
return ac97c_workdata ? 0 : -ENODEV;
}
+static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
+ .probe = au1xac97c_dai_probe,
+ .startup = alchemy_ac97c_startup,
+};
+
static struct snd_soc_dai_driver au1xac97c_dai_driver = {
.name = "alchemy-ac97c",
- .probe = au1xac97c_dai_probe,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
@@ -336,7 +336,7 @@ static struct platform_driver au1xac97c_driver = {
.pm = AU1XPSCAC97_PMOPS,
},
.probe = au1xac97c_drvprobe,
- .remove_new = au1xac97c_drvremove,
+ .remove = au1xac97c_drvremove,
};
module_platform_driver(au1xac97c_driver);
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 400eaf9f8b14..81abe2e18402 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -44,6 +44,7 @@ static const struct platform_device_id db1200_pids[] = {
},
{},
};
+MODULE_DEVICE_TABLE(platform, db1200_pids);
/*------------------------- AC97 PART ---------------------------*/
@@ -94,8 +95,8 @@ static struct snd_soc_card db1550_ac97_machine = {
static int db1200_i2s_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
/* WM8731 has its own 12MHz crystal */
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 3d67e27fada9..3392693faeb9 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -278,10 +278,10 @@ static int au1xpsc_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int stype = substream->stream, *dmaids;
- dmaids = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dmaids = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if (!dmaids)
return -ENODEV; /* whoa, has ordering changed? */
@@ -311,7 +311,7 @@ static int au1xpsc_pcm_new(struct snd_soc_component *component,
}
/* au1xpsc audio platform */
-static struct snd_soc_component_driver au1xpsc_soc_component = {
+static const struct snd_soc_component_driver au1xpsc_soc_component = {
.name = DRV_NAME,
.open = au1xpsc_pcm_open,
.close = au1xpsc_pcm_close,
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index 7f5be90c9ed1..c9c2b1e71d55 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -191,11 +191,11 @@ static int alchemy_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream, component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int *dmaids, s = substream->stream;
char *name;
- dmaids = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dmaids = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if (!dmaids)
return -ENODEV; /* whoa, has ordering changed? */
@@ -289,7 +289,7 @@ static int alchemy_pcm_new(struct snd_soc_component *component,
return 0;
}
-static struct snd_soc_component_driver alchemy_pcm_soc_component = {
+static const struct snd_soc_component_driver alchemy_pcm_soc_component = {
.name = DRV_NAME,
.open = alchemy_pcm_open,
.close = alchemy_pcm_close,
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 064406080d72..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,26 +293,16 @@ 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_new = au1xi2s_drvremove,
+ .remove = au1xi2s_drvremove,
};
module_platform_driver(au1xi2s_driver);
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 9fd91aea7d1a..94698e08a513 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -58,7 +58,7 @@ static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
{
struct snd_soc_card *c = x->bus->card->private_data;
- return snd_soc_dai_get_drvdata(c->asoc_rtd_to_cpu(rtd, 0));
+ return snd_soc_dai_get_drvdata(c->snd_soc_rtd_to_cpu(rtd, 0));
}
#else
@@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+ .probe = au1xpsc_ac97_probe,
.startup = au1xpsc_ac97_startup,
.trigger = au1xpsc_ac97_trigger,
.hw_params = au1xpsc_ac97_hw_params,
};
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
- .probe = au1xpsc_ac97_probe,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
@@ -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,26 +466,16 @@ 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_new = au1xpsc_ac97_drvremove,
+ .remove = au1xpsc_ac97_drvremove,
};
module_platform_driver(au1xpsc_ac97_driver);
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 52734dec8247..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,26 +384,16 @@ 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_new = au1xpsc_i2s_drvremove,
+ .remove = au1xpsc_i2s_drvremove,
};
module_platform_driver(au1xpsc_i2s_driver);
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
index 4218057b0874..de4e8a0daf1c 100644
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Broadcom"
+
config SND_BCM2835_SOC_I2S
tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
depends on ARCH_BCM2835 || COMPILE_TEST
@@ -26,3 +28,5 @@ config SND_BCM63XX_I2S_WHISTLER
DSL/PON chips (bcm63158, bcm63178)
If you don't know what to do here, say N
+
+endmenu
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile
index 7c2d7899603b..0c1325a97b70 100644
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -1,15 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
# BCM2835 Platform Support
-snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o
+snd-soc-bcm2835-i2s-y := bcm2835-i2s.o
obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
# CYGNUS Platform Support
-snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o
+snd-soc-cygnus-y := cygnus-pcm.o cygnus-ssp.o
obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o
# BCM63XX Platform Support
-snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
+snd-soc-63xx-y := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o \ No newline at end of file
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 85f705afcdbb..87d2f06c2f53 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
bcm2835_i2s_stop_clock(dev);
}
+static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai,
+ &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+ &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
+ .probe = bcm2835_i2s_dai_probe,
.startup = bcm2835_i2s_startup,
.shutdown = bcm2835_i2s_shutdown,
.prepare = bcm2835_i2s_prepare,
@@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot,
};
-static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
-{
- struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
-
- snd_soc_dai_init_dma_data(dai,
- &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
- &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
-
- return 0;
-}
-
static struct snd_soc_dai_driver bcm2835_i2s_dai = {
.name = "bcm2835-i2s",
- .probe = bcm2835_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -817,7 +817,7 @@ static const struct regmap_config bcm2835_regmap_config = {
.max_register = BCM2835_I2S_GRAY_REG,
.precious_reg = bcm2835_i2s_precious_reg,
.volatile_reg = bcm2835_i2s_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const struct snd_soc_component_driver bcm2835_i2s_component = {
diff --git a/sound/soc/bcm/bcm63xx-i2s-whistler.c b/sound/soc/bcm/bcm63xx-i2s-whistler.c
index 18c51dbbc8dc..c47ed1e6ea2b 100644
--- a/sound/soc/bcm/bcm63xx-i2s-whistler.c
+++ b/sound/soc/bcm/bcm63xx-i2s-whistler.c
@@ -225,7 +225,6 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev)
{
int ret = 0;
void __iomem *regs;
- struct resource *r_mem, *region;
struct bcm_i2s_priv *i2s_priv;
struct regmap *regmap_i2s;
struct clk *i2s_clk;
@@ -241,20 +240,7 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev)
return PTR_ERR(i2s_clk);
}
- r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r_mem) {
- dev_err(&pdev->dev, "Unable to get register resource.\n");
- return -ENODEV;
- }
-
- region = devm_request_mem_region(&pdev->dev, r_mem->start,
- resource_size(r_mem), DRV_NAME);
- if (!region) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- return -EBUSY;
- }
-
- regs = devm_ioremap_resource(&pdev->dev, r_mem);
+ regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs)) {
ret = PTR_ERR(regs);
return ret;
@@ -307,7 +293,7 @@ static struct platform_driver bcm63xx_i2s_driver = {
.of_match_table = of_match_ptr(snd_soc_bcm_audio_match),
},
.probe = bcm63xx_i2s_dev_probe,
- .remove_new = bcm63xx_i2s_dev_remove,
+ .remove = bcm63xx_i2s_dev_remove,
};
module_platform_driver(bcm63xx_i2s_driver);
diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c
index 2c600b017524..e3a4fcc63a56 100644
--- a/sound/soc/bcm/bcm63xx-pcm-whistler.c
+++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c
@@ -46,13 +46,13 @@ static int bcm63xx_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_hw_params *params)
{
struct i2s_dma_desc *dma_desc;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
dma_desc = kzalloc(sizeof(*dma_desc), GFP_NOWAIT);
if (!dma_desc)
return -ENOMEM;
- snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_desc);
+ snd_soc_dai_set_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream, dma_desc);
return 0;
}
@@ -61,9 +61,9 @@ static int bcm63xx_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct i2s_dma_desc *dma_desc;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_desc = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
kfree(dma_desc);
return 0;
@@ -77,8 +77,8 @@ static int bcm63xx_pcm_trigger(struct snd_soc_component *component,
struct bcm_i2s_priv *i2s_priv;
struct regmap *regmap_i2s;
- rtd = asoc_substream_to_rtd(substream);
- i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
+ rtd = snd_soc_substream_to_rtd(substream);
+ i2s_priv = dev_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)->dev);
regmap_i2s = i2s_priv->regmap_i2s;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -144,11 +144,11 @@ static int bcm63xx_pcm_prepare(struct snd_soc_component *component,
struct i2s_dma_desc *dma_desc;
struct regmap *regmap_i2s;
struct bcm_i2s_priv *i2s_priv;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
uint32_t regaddr_desclen, regaddr_descaddr;
- dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_desc = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
dma_desc->dma_len = snd_pcm_lib_period_bytes(substream);
dma_desc->dma_addr = runtime->dma_addr;
dma_desc->dma_area = runtime->dma_area;
@@ -161,7 +161,7 @@ static int bcm63xx_pcm_prepare(struct snd_soc_component *component,
regaddr_descaddr = I2S_RX_DESC_IFF_ADDR;
}
- i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
+ i2s_priv = dev_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)->dev);
regmap_i2s = i2s_priv->regmap_i2s;
regmap_write(regmap_i2s, regaddr_desclen, dma_desc->dma_len);
@@ -250,18 +250,22 @@ static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv)
if (int_status & I2S_RX_DESC_OFF_INTR_EN_MSK) {
substream = i2s_priv->capture_substream;
runtime = substream->runtime;
- rtd = asoc_substream_to_rtd(substream);
+ rtd = snd_soc_substream_to_rtd(substream);
prtd = runtime->private_data;
- dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_desc = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >>
I2S_RX_DESC_OFF_LEVEL_SHIFT;
+ bool val_read = false;
while (offlevel) {
regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1);
regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2);
+ val_read = true;
offlevel--;
}
- prtd->dma_addr_next = val_1 + val_2;
+ if (val_read)
+ prtd->dma_addr_next = val_1 + val_2;
+
ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >>
I2S_RX_DESC_IFF_LEVEL_SHIFT;
@@ -298,9 +302,9 @@ static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv)
if (int_status & I2S_TX_DESC_OFF_INTR_EN_MSK) {
substream = i2s_priv->play_substream;
runtime = substream->runtime;
- rtd = asoc_substream_to_rtd(substream);
+ rtd = snd_soc_substream_to_rtd(substream);
prtd = runtime->private_data;
- dma_desc = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_desc = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
offlevel = (int_status & I2S_TX_DESC_OFF_LEVEL_MASK) >>
I2S_TX_DESC_OFF_LEVEL_SHIFT;
@@ -352,7 +356,7 @@ static int bcm63xx_soc_pcm_new(struct snd_soc_component *component,
struct bcm_i2s_priv *i2s_priv;
int ret;
- i2s_priv = dev_get_drvdata(asoc_rtd_to_cpu(rtd, 0)->dev);
+ i2s_priv = dev_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)->dev);
of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1);
diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c
index 8f488f92936b..4cb2fe10bcdc 100644
--- a/sound/soc/bcm/cygnus-pcm.c
+++ b/sound/soc/bcm/cygnus-pcm.c
@@ -197,9 +197,9 @@ static u64 cygnus_dma_dmamask = DMA_BIT_MASK(32);
static struct cygnus_aio_port *cygnus_dai_get_dma_data(
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
- return snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(soc_runtime, 0), substream);
+ return snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(soc_runtime, 0), substream);
}
static void ringbuf_set_initial(void __iomem *audio_io,
@@ -343,13 +343,13 @@ static void enable_intr(struct snd_pcm_substream *substream)
static void disable_intr(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct cygnus_aio_port *aio;
u32 set_mask;
aio = cygnus_dai_get_dma_data(substream);
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s on port %d\n", __func__, aio->portnum);
+ dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "%s on port %d\n", __func__, aio->portnum);
/* The port number maps to the bit position to be set */
set_mask = BIT(aio->portnum);
@@ -571,7 +571,7 @@ static irqreturn_t cygnus_dma_irq(int irq, void *data)
static int cygnus_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct cygnus_aio_port *aio;
int ret;
@@ -580,7 +580,7 @@ static int cygnus_pcm_open(struct snd_soc_component *component,
if (!aio)
return -ENODEV;
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
+ dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
snd_soc_set_runtime_hwparams(substream, &cygnus_pcm_hw);
@@ -608,12 +608,12 @@ static int cygnus_pcm_open(struct snd_soc_component *component,
static int cygnus_pcm_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct cygnus_aio_port *aio;
aio = cygnus_dai_get_dma_data(substream);
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
+ dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
aio->play_stream = NULL;
@@ -621,7 +621,7 @@ static int cygnus_pcm_close(struct snd_soc_component *component,
aio->capture_stream = NULL;
if (!aio->play_stream && !aio->capture_stream)
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "freed port %d\n", aio->portnum);
+ dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "freed port %d\n", aio->portnum);
return 0;
}
@@ -629,7 +629,7 @@ static int cygnus_pcm_close(struct snd_soc_component *component,
static int cygnus_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct cygnus_aio_port *aio;
unsigned long bufsize, periodsize;
@@ -638,12 +638,12 @@ static int cygnus_pcm_prepare(struct snd_soc_component *component,
struct ringbuf_regs *p_rbuf = NULL;
aio = cygnus_dai_get_dma_data(substream);
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
+ dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "%s port %d\n", __func__, aio->portnum);
bufsize = snd_pcm_lib_buffer_bytes(substream);
periodsize = snd_pcm_lib_period_bytes(substream);
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "%s (buf_size %lu) (period_size %lu)\n",
+ dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "%s (buf_size %lu) (period_size %lu)\n",
__func__, bufsize, periodsize);
configure_ringbuf_regs(substream);
@@ -707,7 +707,7 @@ static int cygnus_dma_new(struct snd_soc_component *component,
return 0;
}
-static struct snd_soc_component_driver cygnus_soc_platform = {
+static const struct snd_soc_component_driver cygnus_soc_platform = {
.open = cygnus_pcm_open,
.close = cygnus_pcm_close,
.prepare = cygnus_pcm_prepare,
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 8638bf22ef5c..e0ce0232eb1e 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -5,7 +5,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -1390,7 +1390,7 @@ MODULE_DEVICE_TABLE(of, cygnus_ssp_of_match);
static struct platform_driver cygnus_ssp_driver = {
.probe = cygnus_ssp_probe,
- .remove_new = cygnus_ssp_remove,
+ .remove = cygnus_ssp_remove,
.driver = {
.name = "cygnus-ssp",
.of_match_table = cygnus_ssp_of_match,
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 74152b2d770d..4925e03c3c30 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -117,8 +117,6 @@ struct cygnus_audio {
unsigned long vco_rate;
};
-extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd);
extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
int len);
extern int cygnus_soc_platform_register(struct device *dev,
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
index 38a83c4dcc2d..31475e64e7dd 100644
--- a/sound/soc/cirrus/Kconfig
+++ b/sound/soc/cirrus/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Cirrus Logic"
+
config SND_EP93XX_SOC
tristate "SoC Audio support for the Cirrus Logic EP93xx series"
depends on ARCH_EP93XX || COMPILE_TEST
@@ -31,12 +33,4 @@ config SND_EP93XX_SOC_I2S_WATCHDOG
endif # if SND_EP93XX_SOC_I2S
-config SND_EP93XX_SOC_EDB93XX
- tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
- depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
- select SND_EP93XX_SOC_I2S
- select SND_SOC_CS4271_I2C if I2C
- select SND_SOC_CS4271_SPI if SPI_MASTER
- help
- Say Y or M here if you want to add support for I2S audio on the
- Cirrus Logic EDB93xx boards.
+endmenu
diff --git a/sound/soc/cirrus/Makefile b/sound/soc/cirrus/Makefile
index 19a86daad660..61d8cf64e859 100644
--- a/sound/soc/cirrus/Makefile
+++ b/sound/soc/cirrus/Makefile
@@ -1,12 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# EP93xx Platform Support
-snd-soc-ep93xx-objs := ep93xx-pcm.o
-snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
+snd-soc-ep93xx-y := ep93xx-pcm.o
+snd-soc-ep93xx-i2s-y := ep93xx-i2s.o
obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
-# EP93XX Machine Support
-snd-soc-edb93xx-objs := edb93xx.o
-
-obj-$(CONFIG_SND_EP93XX_SOC_EDB93XX) += snd-soc-edb93xx.o
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
deleted file mode 100644
index f49caab21a25..000000000000
--- a/sound/soc/cirrus/edb93xx.c
+++ /dev/null
@@ -1,117 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * SoC audio for EDB93xx
- *
- * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
- *
- * This driver support CS4271 codec being master or slave, working
- * in control port mode, connected either via SPI or I2C.
- * The data format accepted is I2S or left-justified.
- * DAPM support not implemented.
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/soc/cirrus/ep93xx.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-
-static int edb93xx_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- int err;
- unsigned int mclk_rate;
- unsigned int rate = params_rate(params);
-
- /*
- * According to CS4271 datasheet we use MCLK/LRCK=256 for
- * rates below 50kHz and 128 for higher sample rates
- */
- if (rate < 50000)
- mclk_rate = rate * 64 * 4;
- else
- mclk_rate = rate * 64 * 2;
-
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
- SND_SOC_CLOCK_IN);
- if (err)
- return err;
-
- return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate,
- SND_SOC_CLOCK_OUT);
-}
-
-static const struct snd_soc_ops edb93xx_ops = {
- .hw_params = edb93xx_hw_params,
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
- DAILINK_COMP_ARRAY(COMP_CPU("ep93xx-i2s")),
- DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "cs4271-hifi")),
- DAILINK_COMP_ARRAY(COMP_PLATFORM("ep93xx-i2s")));
-
-static struct snd_soc_dai_link edb93xx_dai = {
- .name = "CS4271",
- .stream_name = "CS4271 HiFi",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ops = &edb93xx_ops,
- SND_SOC_DAILINK_REG(hifi),
-};
-
-static struct snd_soc_card snd_soc_edb93xx = {
- .name = "EDB93XX",
- .owner = THIS_MODULE,
- .dai_link = &edb93xx_dai,
- .num_links = 1,
-};
-
-static int edb93xx_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &snd_soc_edb93xx;
- int ret;
-
- ret = ep93xx_i2s_acquire();
- if (ret)
- return ret;
-
- card->dev = &pdev->dev;
-
- ret = snd_soc_register_card(card);
- if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
- ret);
- ep93xx_i2s_release();
- }
-
- return ret;
-}
-
-static void edb93xx_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- snd_soc_unregister_card(card);
- ep93xx_i2s_release();
-}
-
-static struct platform_driver edb93xx_driver = {
- .driver = {
- .name = "edb93xx-audio",
- },
- .probe = edb93xx_probe,
- .remove_new = edb93xx_remove,
-};
-
-module_platform_driver(edb93xx_driver);
-
-MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
-MODULE_DESCRIPTION("ALSA SoC EDB93xx");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:edb93xx-audio");
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index afc6b5b570ea..cca01c03f048 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -24,7 +24,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <linux/platform_data/dma-ep93xx.h>
#include <linux/soc/cirrus/ep93xx.h>
#include "ep93xx-pcm.h"
@@ -80,19 +79,6 @@ struct ep93xx_i2s_info {
struct snd_dmaengine_dai_dma_data dma_params_tx;
};
-static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
- [SNDRV_PCM_STREAM_PLAYBACK] = {
- .name = "i2s-pcm-out",
- .port = EP93XX_DMA_I2S1,
- .direction = DMA_MEM_TO_DEV,
- },
- [SNDRV_PCM_STREAM_CAPTURE] = {
- .name = "i2s-pcm-in",
- .port = EP93XX_DMA_I2S1,
- .direction = DMA_DEV_TO_MEM,
- },
-};
-
static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
unsigned reg, unsigned val)
{
@@ -198,11 +184,6 @@ static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
- info->dma_params_tx.filter_data =
- &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
- info->dma_params_rx.filter_data =
- &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
-
snd_soc_dai_init_dma_data(dai, &info->dma_params_tx,
&info->dma_params_rx);
@@ -407,6 +388,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component)
#endif
static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+ .probe = ep93xx_i2s_dai_probe,
.startup = ep93xx_i2s_startup,
.shutdown = ep93xx_i2s_shutdown,
.hw_params = ep93xx_i2s_hw_params,
@@ -418,7 +400,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
static struct snd_soc_dai_driver ep93xx_i2s_dai = {
.symmetric_rate = 1,
- .probe = ep93xx_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -523,7 +504,7 @@ MODULE_DEVICE_TABLE(of, ep93xx_i2s_of_ids);
static struct platform_driver ep93xx_i2s_driver = {
.probe = ep93xx_i2s_probe,
- .remove_new = ep93xx_i2s_remove,
+ .remove = ep93xx_i2s_remove,
.driver = {
.name = "ep93xx-i2s",
.of_match_table = ep93xx_i2s_of_ids,
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
index fa72acd8d334..5ecb4671cbba 100644
--- a/sound/soc/cirrus/ep93xx-pcm.c
+++ b/sound/soc/cirrus/ep93xx-pcm.c
@@ -18,8 +18,6 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include <linux/platform_data/dma-ep93xx.h>
-
#include "ep93xx-pcm.h"
static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
@@ -35,30 +33,15 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
.fifo_size = 32,
};
-static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
-{
- struct ep93xx_dma_data *data = filter_param;
-
- if (data->direction == ep93xx_dma_chan_direction(chan)) {
- chan->private = data;
- return true;
- }
-
- return false;
-}
-
static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
.pcm_hardware = &ep93xx_pcm_hardware,
- .compat_filter_fn = ep93xx_pcm_dma_filter,
.prealloc_buffer_size = 131072,
};
int devm_ep93xx_pcm_platform_register(struct device *dev)
{
return devm_snd_dmaengine_pcm_register(dev,
- &ep93xx_dmaengine_pcm_config,
- SND_DMAENGINE_PCM_FLAG_NO_DT |
- SND_DMAENGINE_PCM_FLAG_COMPAT);
+ &ep93xx_dmaengine_pcm_config, 0);
}
EXPORT_SYMBOL_GPL(devm_ep93xx_pcm_platform_register);
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 3574c68e0dda..b4f5b24cde45 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -143,7 +143,7 @@ struct pm860x_priv {
struct pm860x_det det;
int irq[4];
- unsigned char name[4][MAX_NAME_LEN+1];
+ unsigned char name[4][MAX_NAME_LEN];
};
/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@@ -269,7 +269,7 @@ static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
int val[2], val2[2], i;
@@ -293,7 +293,7 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
int err;
@@ -326,7 +326,7 @@ static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -346,7 +346,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -400,9 +400,9 @@ static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
unsigned int dac = 0;
int data;
- if (!strcmp(w->name, "Left DAC"))
+ if (!snd_soc_dapm_widget_name_cmp(w, "Left DAC"))
dac = DAC_LEFT;
- if (!strcmp(w->name, "Right DAC"))
+ if (!snd_soc_dapm_widget_name_cmp(w, "Right DAC"))
dac = DAC_RIGHT;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1106,6 +1106,7 @@ static int pm860x_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int data;
switch (level) {
@@ -1116,7 +1117,7 @@ static int pm860x_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Enable Audio PLL & Audio section */
data = AUDIO_PLL | AUDIO_SECTION_ON;
pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
@@ -1373,7 +1374,7 @@ static int pm860x_codec_probe(struct platform_device *pdev)
return -EINVAL;
}
pm860x->irq[i] = res->start + chip->irq_base;
- strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+ strscpy(pm860x->name[i], res->name, MAX_NAME_LEN);
}
ret = devm_snd_soc_register_component(&pdev->dev,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7422cd10c1da..6087ebde9523 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -15,7 +15,6 @@ config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
depends on COMPILE_TEST
imply SND_SOC_88PM860X
- imply SND_SOC_L3
imply SND_SOC_AB8500_CODEC
imply SND_SOC_AC97_CODEC
imply SND_SOC_AD1836
@@ -46,6 +45,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AK4535
imply SND_SOC_AK4554
imply SND_SOC_AK4613
+ imply SND_SOC_AK4619
imply SND_SOC_AK4641
imply SND_SOC_AK4642
imply SND_SOC_AK4671
@@ -53,8 +53,14 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AK5558
imply SND_SOC_ALC5623
imply SND_SOC_ALC5632
+ imply SND_SOC_AUDIO_IIO_AUX
imply SND_SOC_AW8738
+ 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
imply SND_SOC_BD28623
imply SND_SOC_CHV3_CODEC
@@ -72,12 +78,16 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS35L56_I2C
imply SND_SOC_CS35L56_SPI
imply SND_SOC_CS35L56_SDW
+ imply SND_SOC_CS40L50
imply SND_SOC_CS42L42
imply SND_SOC_CS42L42_SDW
+ imply SND_SOC_CS42L43
+ imply SND_SOC_CS42L43_SDW
imply SND_SOC_CS42L51_I2C
imply SND_SOC_CS42L52
imply SND_SOC_CS42L56
imply SND_SOC_CS42L73
+ imply SND_SOC_CS42L84
imply SND_SOC_CS4234
imply SND_SOC_CS4265
imply SND_SOC_CS4270
@@ -93,7 +103,10 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS47L85
imply SND_SOC_CS47L90
imply SND_SOC_CS47L92
+ imply SND_SOC_CS48L32
imply SND_SOC_CS53L30
+ imply SND_SOC_CS530X_I2C
+ imply SND_SOC_CS530X_SPI
imply SND_SOC_CX20442
imply SND_SOC_CX2072X
imply SND_SOC_DA7210
@@ -104,11 +117,16 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_DA9055
imply SND_SOC_DMIC
imply SND_SOC_ES8316
+ imply SND_SOC_ES8323
imply SND_SOC_ES8326
imply SND_SOC_ES8328_SPI
imply SND_SOC_ES8328_I2C
+ imply SND_SOC_ES8375
+ imply SND_SOC_ES8389
imply SND_SOC_ES7134
imply SND_SOC_ES7241
+ imply SND_SOC_FRAMER
+ imply SND_SOC_FS210X
imply SND_SOC_GTM601
imply SND_SOC_HDAC_HDMI
imply SND_SOC_HDAC_HDA
@@ -148,10 +166,12 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_MC13783
imply SND_SOC_ML26124
imply SND_SOC_MT6351
+ imply SND_SOC_MT6357
imply SND_SOC_MT6358
imply SND_SOC_MT6359
imply SND_SOC_MT6660
imply SND_SOC_NAU8315
+ imply SND_SOC_NAU8325
imply SND_SOC_NAU8540
imply SND_SOC_NAU8810
imply SND_SOC_NAU8821
@@ -160,6 +180,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_NAU8825
imply SND_SOC_HDMI_CODEC
imply SND_SOC_PCM1681
+ imply SND_SOC_PCM1754
imply SND_SOC_PCM1789_I2C
imply SND_SOC_PCM179X_I2C
imply SND_SOC_PCM179X_SPI
@@ -173,7 +194,10 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_PCM5102A
imply SND_SOC_PCM512x_I2C
imply SND_SOC_PCM512x_SPI
+ imply SND_SOC_PCM6240
imply SND_SOC_PEB2466
+ imply SND_SOC_PM4125_SDW
+ imply SND_SOC_RK3308
imply SND_SOC_RK3328
imply SND_SOC_RK817
imply SND_SOC_RT274
@@ -183,6 +207,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT1015
imply SND_SOC_RT1015P
imply SND_SOC_RT1016
+ imply SND_SOC_RT1017_SDCA_SDW
imply SND_SOC_RT1019
imply SND_SOC_RT1305
imply SND_SOC_RT1308
@@ -209,17 +234,24 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT712_SDCA_DMIC_SDW
imply SND_SOC_RT715_SDW
imply SND_SOC_RT715_SDCA_SDW
+ imply SND_SOC_RT721_SDCA_SDW
imply SND_SOC_RT722_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
+ imply SND_SOC_RT1318
imply SND_SOC_RT1318_SDW
+ imply SND_SOC_RT1320_SDW
imply SND_SOC_RT9120
+ imply SND_SOC_RT9123
+ imply SND_SOC_RTQ9124
+ imply SND_SOC_RTQ9128
imply SND_SOC_SDW_MOCKUP
imply SND_SOC_SGTL5000
imply SND_SOC_SI476X
imply SND_SOC_SIMPLE_AMPLIFIER
imply SND_SOC_SIMPLE_MUX
imply SND_SOC_SMA1303
+ imply SND_SOC_SMA1307
imply SND_SOC_SPDIF
imply SND_SOC_SRC4XXX_I2C
imply SND_SOC_SSM2305
@@ -237,6 +269,8 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TAS2764
imply SND_SOC_TAS2770
imply SND_SOC_TAS2780
+ imply SND_SOC_TAS2781_I2C
+ imply SND_SOC_TAS2783_SDW
imply SND_SOC_TAS5086
imply SND_SOC_TAS571X
imply SND_SOC_TAS5720
@@ -262,15 +296,16 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TWL4030
imply SND_SOC_TWL6040
imply SND_SOC_UDA1334
- imply SND_SOC_UDA134X
+ imply SND_SOC_UDA1342
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
+ imply SND_SOC_WCD937X_SDW
imply SND_SOC_WCD938X_SDW
+ imply SND_SOC_WCD939X_SDW
imply SND_SOC_LPASS_MACRO_COMMON
imply SND_SOC_LPASS_RX_MACRO
imply SND_SOC_LPASS_TX_MACRO
- imply SND_SOC_WL1273
imply SND_SOC_WM0010
imply SND_SOC_WM1250_EV1
imply SND_SOC_WM2000
@@ -327,6 +362,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_WM9713
imply SND_SOC_WSA881X
imply SND_SOC_WSA883X
+ imply SND_SOC_WSA884X
imply SND_SOC_ZL38060
help
Normally ASoC codec drivers are only built if a machine driver which
@@ -375,6 +411,7 @@ config SND_SOC_WM_ADSP
default y if SND_SOC_CS35L45_SPI=y
default y if SND_SOC_CS35L45_I2C=y
default y if SND_SOC_CS35L56=y
+ default y if SND_SOC_CS48L32=y
default m if SND_SOC_MADERA=m
default m if SND_SOC_CS47L24=m
default m if SND_SOC_WM5102=m
@@ -385,6 +422,7 @@ config SND_SOC_WM_ADSP
default m if SND_SOC_CS35L45_SPI=m
default m if SND_SOC_CS35L45_I2C=m
default m if SND_SOC_CS35L56=m
+ default m if SND_SOC_CS48L32=m
config SND_SOC_AB8500_CODEC
tristate
@@ -440,7 +478,7 @@ config SND_SOC_ADAU1372_SPI
select REGMAP_SPI
config SND_SOC_ADAU1373
- tristate
+ tristate "Analog Devices ADAU1373 CODEC"
depends on I2C
select SND_SOC_ADAU_UTILS
@@ -582,9 +620,14 @@ config SND_SOC_AK4613
tristate "AKM AK4613 CODEC"
depends on I2C
+config SND_SOC_AK4619
+ tristate "AKM AK4619 CODEC"
+ depends on I2C
+
config SND_SOC_AK4641
tristate
depends on I2C
+ depends on GPIOLIB_LEGACY
config SND_SOC_AK4642
tristate "AKM AK4642 CODEC"
@@ -610,6 +653,17 @@ config SND_SOC_ALC5632
tristate
depends on I2C
+config SND_SOC_AUDIO_IIO_AUX
+ tristate "Audio IIO Auxiliary device"
+ depends on IIO
+ help
+ Enable support for Industrial I/O devices as audio auxiliary devices.
+ This allows to have an IIO device present in the audio path and
+ controlled using mixer controls.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-audio-iio-aux.
+
config SND_SOC_AW8738
tristate "Awinic AW8738 Audio Amplifier"
select GPIOLIB
@@ -620,12 +674,12 @@ config SND_SOC_AW8738
operation mode using the Awinic-specific one-wire pulse control.
config SND_SOC_AW88395_LIB
+ select CRC8
tristate
config SND_SOC_AW88395
tristate "Soc Audio for awinic aw88395"
depends on I2C
- select CRC8
select CRC32
select REGMAP_I2C
select GPIOLIB
@@ -636,6 +690,66 @@ 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
+ select REGMAP_I2C
+ select GPIOLIB
+ select SND_SOC_AW88395_LIB
+ help
+ This option enables support for aw88261 Smart PA.
+ The awinic AW88261 is an I2S/TDM input, high efficiency
+ digital Smart K audio amplifier. The output voltage of
+ boost converter can be adjusted smartly according to
+ the input amplitude.
+
+config SND_SOC_AW88081
+ tristate "Soc Audio for awinic aw88081/aw88083"
+ depends on I2C
+ select REGMAP_I2C
+ select SND_SOC_AW88395_LIB
+ help
+ This option enables support for aw88081 Smart PA.
+ The awinic AW88081 is an I2S/TDM input, high efficiency
+ digital Smart K audio amplifier. Due to its 9uV noise
+ floor and ultra-low distortion, clean listening is guaranteed.
+
+config SND_SOC_AW87390
+ tristate "Soc Audio for awinic aw87390"
+ depends on I2C
+ select REGMAP_I2C
+ select SND_SOC_AW88395_LIB
+ help
+ The awinic aw87390 is specifically designed to improve
+ the musical output dynamic range, enhance the overall
+ sound quality, which is a new high efficiency, low
+ noise, constant large volume, 6th Smart K audio amplifier.
+
+config SND_SOC_AW88399
+ tristate "Soc Audio for awinic aw88399"
+ depends on I2C
+ select CRC8
+ select REGMAP_I2C
+ select GPIOLIB
+ select SND_SOC_AW88395_LIB
+ help
+ This option enables support for aw88399 Smart PA.
+ The awinic AW88399 is an I2S/TDM input, high efficiency
+ digital Smart K audio amplifier and SKTune speaker
+ protection algorithms.
+
config SND_SOC_BD28623
tristate "ROHM BD28623 CODEC"
help
@@ -669,6 +783,21 @@ config SND_SOC_CROS_EC_CODEC
If you say yes here you will get support for the
ChromeOS Embedded Controller's Audio Codec.
+config SND_SOC_CS_AMP_LIB
+ tristate
+
+config SND_SOC_CS_AMP_LIB_TEST
+ tristate "KUnit test for Cirrus Logic cs-amp-lib" if !KUNIT_ALL_TESTS
+ depends on SND_SOC_CS_AMP_LIB && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This builds KUnit tests for the Cirrus Logic common
+ amplifier library.
+ For more information on KUnit and unit tests in general,
+ please refer to the KUnit documentation in
+ Documentation/dev-tools/kunit/.
+ If in doubt, say "N".
+
config SND_SOC_CS35L32
tristate "Cirrus Logic CS35L32 CODEC"
depends on I2C
@@ -711,6 +840,7 @@ config SND_SOC_CS35L41_I2C
config SND_SOC_CS35L45
tristate
+ select REGMAP_IRQ
config SND_SOC_CS35L45_SPI
tristate "Cirrus Logic CS35L45 CODEC (SPI)"
@@ -736,6 +866,7 @@ config SND_SOC_CS35L56
tristate
config SND_SOC_CS35L56_SHARED
+ select SND_SOC_CS_AMP_LIB
tristate
config SND_SOC_CS35L56_I2C
@@ -767,6 +898,48 @@ config SND_SOC_CS35L56_SDW
help
Enable support for Cirrus Logic CS35L56 boosted amplifier with SoundWire control
+config SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
+ bool
+
+menu "CS35L56 driver options"
+ depends on SND_SOC_CS35L56
+
+config SND_SOC_CS35L56_CAL_DEBUGFS
+ bool "CS35L56 create debugfs for factory calibration"
+ default N
+ depends on DEBUG_FS
+ select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
+ help
+ Create debugfs entries used during factory-line manufacture
+ for factory calibration.
+
+ If unsure select "N".
+
+config SND_SOC_CS35L56_CAL_SET_CTRL
+ bool "CS35L56 ALSA control to restore factory calibration"
+ default N
+ select SND_SOC_CS35L56_CAL_SYSFS_COMMON
+ help
+ Allow restoring factory calibration data through an ALSA
+ control. This is only needed on platforms without UEFI or
+ some other method of non-volatile storage that the driver
+ can access directly.
+
+ On most platforms this is not needed.
+
+ If unsure select "N".
+endmenu
+
+config SND_SOC_CS40L50
+ tristate "Cirrus Logic CS40L50 CODEC"
+ depends on MFD_CS40L50_CORE
+ help
+ This option enables support for I2S streaming to Cirrus Logic CS40L50.
+
+ CS40L50 is a haptic driver with waveform memory, an integrated
+ DSP, and closed-loop algorithms. If built as a module, it will be
+ called snd-soc-cs40l50.
+
config SND_SOC_CS42L42_CORE
tristate
@@ -784,6 +957,20 @@ config SND_SOC_CS42L42_SDW
help
Enable support for Cirrus Logic CS42L42 codec with Soundwire control
+config SND_SOC_CS42L43
+ tristate "Cirrus Logic CS42L43 CODEC"
+ depends on MFD_CS42L43
+ help
+ Select this to support the audio functions of the Cirrus Logic
+ CS42L43 PC CODEC.
+
+config SND_SOC_CS42L43_SDW
+ tristate "Cirrus Logic CS42L43 CODEC (SoundWire)"
+ depends on SND_SOC_CS42L43 && MFD_CS42L43_SDW
+ help
+ Select this to support the audio functions of the Cirrus Logic
+ CS42L43 PC CODEC over SoundWire.
+
config SND_SOC_CS42L51
tristate
@@ -811,6 +998,12 @@ config SND_SOC_CS42L83
select REGMAP_I2C
select SND_SOC_CS42L42_CORE
+config SND_SOC_CS42L84
+ tristate "Cirrus Logic CS42L84 CODEC"
+ depends on I2C
+ select REGMAP
+ select REGMAP_I2C
+
config SND_SOC_CS4234
tristate "Cirrus Logic CS4234 CODEC"
depends on I2C
@@ -898,11 +1091,40 @@ config SND_SOC_CS47L92
tristate
depends on MFD_CS47L92
+config SND_SOC_CS48L32
+ tristate "Cirrus Logic CS48L32 audio DSP"
+ depends on SPI_MASTER
+ select REGMAP_SPI
+ help
+ Build the codec driver for the Cirrus Logic CS48L32 audio DSP.
+
# Cirrus Logic Quad-Channel ADC
config SND_SOC_CS53L30
tristate "Cirrus Logic CS53L30 CODEC"
depends on I2C
+config SND_SOC_CS530X
+ tristate
+
+config SND_SOC_CS530X_I2C
+ tristate "Cirrus Logic CS530x ADCs (I2C)"
+ depends on I2C
+ select REGMAP
+ select REGMAP_I2C
+ select SND_SOC_CS530X
+ help
+ Enable support for Cirrus Logic CS530X ADCs
+ with I2C control.
+
+config SND_SOC_CS530X_SPI
+ tristate "Cirrus Logic CS530x ADCs (SPI)"
+ depends on SPI_MASTER
+ select REGMAP_SPI
+ select SND_SOC_CS530X
+ help
+ Enable support for Cirrus Logic CS530X ADCs
+ with SPI control.
+
config SND_SOC_CX20442
tristate
depends on TTY
@@ -961,9 +1183,6 @@ config SND_SOC_JZ4770_CODEC
This driver can also be built as a module. If so, the module
will be called snd-soc-jz4770-codec.
-config SND_SOC_L3
- tristate
-
config SND_SOC_DA7210
tristate
depends on SND_SOC_I2C_AND_SPI
@@ -1006,10 +1225,22 @@ config SND_SOC_ES7134
config SND_SOC_ES7241
tristate "Everest Semi ES7241 CODEC"
+config SND_SOC_ES83XX_DSM_COMMON
+ depends on ACPI
+ tristate
+
+config SND_SOC_ES8311
+ tristate "Everest Semi ES8311 CODEC"
+ depends on I2C
+
config SND_SOC_ES8316
tristate "Everest Semi ES8316 CODEC"
depends on I2C
+config SND_SOC_ES8323
+ tristate "Everest Semi ES8323 CODEC"
+ depends on I2C
+
config SND_SOC_ES8326
tristate "Everest Semi ES8326 CODEC"
depends on I2C
@@ -1027,6 +1258,43 @@ config SND_SOC_ES8328_SPI
depends on SPI_MASTER
select SND_SOC_ES8328
+config SND_SOC_ES8375
+ tristate "Everest Semi ES8375 CODEC"
+ depends on I2C
+
+config SND_SOC_ES8389
+ tristate "Everest Semi ES8389 CODEC"
+ depends on I2C
+
+config SND_SOC_FRAMER
+ tristate "Framer codec"
+ depends on GENERIC_FRAMER
+ help
+ Enable support for the framer codec.
+ The framer codec uses the generic framer infrastructure to transport
+ some audio data over an analog E1/T1/J1 line.
+ This codec allows to use some of the time slots available on the TDM
+ bus on which the framer is connected to transport the audio data.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-framer.
+
+config SND_SOC_FS_AMP_LIB
+ select CRC16
+ tristate
+
+config SND_SOC_FS210X
+ tristate 'FourSemi FS2104/5S digital audio amplifier'
+ depends on I2C
+ select GPIOLIB
+ select REGMAP_I2C
+ select SND_SOC_FS_AMP_LIB
+ help
+ Enable support for FourSemi FS2104/5S digital audio amplifier.
+ The FS2104/5S are Inductor-Less, Stereo, Closed-Loop,
+ Digital Input Class-D Power Amplifiers with Enhanced Signal Processing.
+ The amplifiers support I2C and I2S/TDM.
+
config SND_SOC_GTM601
tristate 'GTM601 UMTS modem audio codec'
@@ -1065,6 +1333,7 @@ config SND_SOC_IDT821034
config SND_SOC_INNO_RK3036
tristate "Inno codec driver for RK3036 SoC"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
select REGMAP_MMIO
config SND_SOC_ISABELLE
@@ -1219,6 +1488,10 @@ config SND_SOC_PCM1681
tristate "Texas Instruments PCM1681 CODEC"
depends on I2C
+config SND_SOC_PCM1754
+ tristate "Texas Instruments PCM1754 CODEC"
+ depends on GPIOLIB
+
config SND_SOC_PCM1789
tristate
@@ -1315,6 +1588,15 @@ config SND_SOC_PCM512x_SPI
select SND_SOC_PCM512x
select REGMAP_SPI
+config SND_SOC_PCM6240
+ tristate "Texas Instruments PCM6240 Family Audio chips based on I2C"
+ depends on I2C
+ help
+ Enable support for Texas Instruments PCM6240 Family Audio chips.
+ Note the PCM6240 driver implements a flexible and configurable
+ setting for register and filter coefficients, to one, two or
+ even multiple PCM6240 Family Audio chips.
+
config SND_SOC_PEB2466
tristate "Infineon PEB2466 quad PCM codec"
depends on SPI
@@ -1326,13 +1608,45 @@ config SND_SOC_PEB2466
To compile this driver as a module, choose M here: the module
will be called snd-soc-peb2466.
+config SND_SOC_PM4125
+ depends on SND_SOC_PM4125_SDW
+ select SND_SOC_WCD_COMMON
+ tristate
+ depends on SOUNDWIRE || !SOUNDWIRE
+
+config SND_SOC_PM4125_SDW
+ tristate "PM4125 audio codec - SDW"
+ select SND_SOC_PM4125
+ select SND_SOC_WCD_MBHC
+ select REGMAP_IRQ
+ select SND_SOC_WCD_COMMON
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ help
+ The PMIC PM4125 has an in-built audio codec IC used with SoCs
+ like QCM2290, and it is connected via soundwire and SPMI.
+ To compile this codec driver say Y or m.
+
+config SND_SOC_RK3308
+ tristate "Rockchip RK3308 audio CODEC"
+ depends on ARM64 || COMPILE_TEST
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This is a device driver for the audio codec embedded in the
+ Rockchip RK3308 SoC.
+
+ It has 8 24-bit ADCs and 2 24-bit DACs. The maximum supported
+ sampling rate is 192 kHz.
+
config SND_SOC_RK3328
tristate "Rockchip RK3328 audio CODEC"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
select REGMAP_MMIO
config SND_SOC_RK817
tristate "Rockchip RK817 audio CODEC"
- depends on MFD_RK808 || COMPILE_TEST
+ depends on MFD_RK8XX || COMPILE_TEST
config SND_SOC_RL6231
tristate
@@ -1375,6 +1689,11 @@ config SND_SOC_RL6231
default m if SND_SOC_RT1305=m
default m if SND_SOC_RT1308=m
+config SND_SOC_RT_SDW_COMMON
+ tristate
+ default y if SND_SOC_RT721_SDCA_SDW=y
+ default m if SND_SOC_RT721_SDCA_SDW=m
+
config SND_SOC_RL6347A
tristate
default y if SND_SOC_RT274=y
@@ -1411,6 +1730,11 @@ config SND_SOC_RT1016
tristate
depends on I2C
+config SND_SOC_RT1017_SDCA_SDW
+ tristate "Realtek RT1017 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+
config SND_SOC_RT1019
tristate
depends on I2C
@@ -1433,11 +1757,21 @@ config SND_SOC_RT1316_SDW
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1318
+ tristate
+ depends on I2C
+
config SND_SOC_RT1318_SDW
tristate "Realtek RT1318 Codec - SDW"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+config SND_SOC_RT1320_SDW
+ tristate "Realtek RT1320 Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT5514
tristate
depends on I2C
@@ -1558,6 +1892,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
+config SND_SOC_RT721_SDCA_SDW
+ tristate "Realtek RT721 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT722_SDCA_SDW
tristate "Realtek RT722 SDCA Codec - SDW"
depends on SOUNDWIRE
@@ -1587,6 +1927,42 @@ config SND_SOC_RT9120
Enable support for Richtek RT9120 20W, stereo, inductor-less,
high-efficiency Class-D audio amplifier.
+config SND_SOC_RT9123
+ tristate "Richtek RT9123 Mono Class-D Amplifier"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Enable support for the I2C control mode of Richtek RT9123 3.2W mono
+ Class-D audio amplifier.
+
+config SND_SOC_RT9123P
+ tristate "Richtek RT9123P Mono Class-D Amplifier"
+ help
+ Enable support for the HW control mode of Richtek RT9123P 3.2W mono
+ Class-D audio amplifier.
+
+config SND_SOC_RTQ9124
+ tristate "Richtek RTQ9124 Mono Class-D Amplifier"
+ depends on I2C
+ select REGMAP
+ help
+ Enable support for Richtek RTQ9124 1x30W digital input automotive
+ audio amplifier with current sense and real-time load diagnostics.
+
+config SND_SOC_RTQ9128
+ tristate "Richtek RTQ9128 45W Digital Input Amplifier"
+ depends on I2C
+ select REGMAP
+ help
+ Enable support for Richtek RTQ9128 digital input 4-channel
+ automotive audio amplifier. It is a ultra-low output noise,
+ high-efficiency, four-channel class-D audio power amplifier
+ that can deliver over 87% power efficienty at 4x75W into 4Ohm,
+ 25V supply in automotive applications.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-rtq9128.
+
config SND_SOC_SDW_MOCKUP
tristate "SoundWire mockup codec"
depends on EXPERT
@@ -1611,6 +1987,7 @@ config SND_SOC_SGTL5000
config SND_SOC_SI476X
tristate
+ depends on MFD_SI476X_CORE
config SND_SOC_SIGMADSP
tristate
@@ -1637,6 +2014,15 @@ config SND_SOC_SMA1303
help
Enable support for Iron Device SMA1303 Boosted Class-D amplifier
+config SND_SOC_SMA1307
+ tristate "Iron Device SMA1307 Audio Amplifier"
+ depends on I2C
+ help
+ Enable support for Iron Device SMA1307 boosted digital speaker
+ amplifier with feedback-loop.
+ If you are using a system with an SMA1307 amplifier connected
+ via I2C, enable this option.
+
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
@@ -1703,6 +2089,7 @@ config SND_SOC_STA529
config SND_SOC_STAC9766
tristate
depends on SND_SOC_AC97_BUS
+ select REGMAP_AC97
config SND_SOC_STI_SAS
tristate "codec Audio support for STI SAS codec"
@@ -1730,6 +2117,46 @@ config SND_SOC_TAS2780
Enable support for Texas Instruments TAS2780 high-efficiency
digital input mono Class-D audio power amplifiers.
+config SND_SOC_TAS2781_COMLIB
+ tristate
+
+config SND_SOC_TAS2781_COMLIB_I2C
+ depends on I2C
+ select CRC8
+ select REGMAP_I2C
+ tristate
+
+config SND_SOC_TAS2781_FMWLIB
+ select SND_SOC_TAS2781_COMLIB
+ select CRC8
+ tristate
+ default n
+
+config SND_SOC_TAS2781_I2C
+ tristate "Texas Instruments TAS2781 speaker amplifier based on I2C"
+ depends on I2C
+ select SND_SOC_TAS2781_COMLIB_I2C
+ select SND_SOC_TAS2781_FMWLIB
+ help
+ Enable support for Texas Instruments TAS2781 Smart Amplifier
+ Digital input mono Class-D and DSP-inside audio power amplifiers.
+ Note the TAS2781 driver implements a flexible and configurable
+ algo coefficient setting, for one, two or even multiple TAS2781
+ chips.
+
+config SND_SOC_TAS2783_SDW
+ tristate "Texas Instruments TAS2783 speaker amplifier (sdw)"
+ depends on SOUNDWIRE
+ depends on EFI
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+ select CRC32
+ help
+ Enable support for Texas Instruments TAS2783A Digital input
+ mono Class-D and DSP-inside audio power amplifiers. TAS2783
+ driver implements a flexible and configurable algorithm
+ cofficient setting, for one, two or multiple TAS2783 chips.
+
config SND_SOC_TAS5086
tristate "Texas Instruments TAS5086 speaker amplifier"
depends on I2C
@@ -1847,6 +2274,7 @@ config SND_SOC_TLV320AIC3X_SPI
config SND_SOC_TLV320DAC33
tristate
depends on I2C
+ depends on GPIOLIB_LEGACY
config SND_SOC_TLV320ADCX140
tristate "Texas Instruments TLV320ADCX140 CODEC family"
@@ -1891,18 +2319,30 @@ config SND_SOC_UDA1334
and has basic features such as de-emphasis (at 44.1 kHz sampling
rate) and mute.
-config SND_SOC_UDA134X
- tristate
+config SND_SOC_UDA1342
+ tristate "NXP UDA1342 CODEC"
+ depends on I2C
+ help
+ The UDA1342 is an NXP audio codec, support 2x Stereo audio ADC (4x PGA
+ mic inputs), stereo audio DAC, with basic audio processing.
config SND_SOC_UDA1380
tristate
depends on I2C
+ depends on GPIOLIB_LEGACY
+
+config SND_SOC_WCD_CLASSH
+ tristate
+
+config SND_SOC_WCD_COMMON
+ tristate
config SND_SOC_WCD9335
tristate "WCD9335 Codec"
depends on SLIMBUS
select REGMAP_SLIMBUS
select REGMAP_IRQ
+ select SND_SOC_WCD_CLASSH
help
The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports
Qualcomm Technologies, Inc. (QTI) multimedia solutions,
@@ -1915,17 +2355,44 @@ config SND_SOC_WCD934X
tristate "WCD9340/WCD9341 Codec"
depends on COMMON_CLK
depends on SLIMBUS
+ depends on SOUNDWIRE || !SOUNDWIRE
+ select REGMAP_IRQ
select REGMAP_SLIMBUS
+ select SND_SOC_WCD_CLASSH
+ select SND_SOC_WCD_COMMON
select SND_SOC_WCD_MBHC
depends on MFD_WCD934X || COMPILE_TEST
help
The WCD9340/9341 is a audio codec IC Integrated in
Qualcomm SoCs like SDM845.
+config SND_SOC_WCD937X
+ depends on SND_SOC_WCD937X_SDW
+ tristate
+ depends on SOUNDWIRE || !SOUNDWIRE
+ select SND_SOC_WCD_CLASSH
+ select SND_SOC_WCD_COMMON
+
+config SND_SOC_WCD937X_SDW
+ tristate "WCD9370/WCD9375 Codec - SDW"
+ select SND_SOC_WCD937X
+ select SND_SOC_WCD_MBHC
+ select REGMAP_IRQ
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ help
+ The WCD9370/9375 is an audio codec IC used with SoCs
+ like SC7280 or QCM6490 chipsets, and it connected
+ via soundwire.
+ To compile this codec driver say Y or m.
+
config SND_SOC_WCD938X
depends on SND_SOC_WCD938X_SDW
tristate
depends on SOUNDWIRE || !SOUNDWIRE
+ select SND_SOC_WCD_CLASSH
+ select SND_SOC_WCD_COMMON
+ select MULTIPLEXER
config SND_SOC_WCD938X_SDW
tristate "WCD9380/WCD9385 Codec - SDW"
@@ -1938,8 +2405,25 @@ config SND_SOC_WCD938X_SDW
The WCD9380/9385 is a audio codec IC Integrated in
Qualcomm SoCs like SM8250.
-config SND_SOC_WL1273
+config SND_SOC_WCD939X
+ depends on SND_SOC_WCD939X_SDW
tristate
+ depends on SOUNDWIRE || !SOUNDWIRE
+ depends on TYPEC || !TYPEC
+ select SND_SOC_WCD_CLASSH
+ select SND_SOC_WCD_COMMON
+
+config SND_SOC_WCD939X_SDW
+ tristate "WCD9390/WCD9395 Codec - SDW"
+ depends on TYPEC || !TYPEC
+ select SND_SOC_WCD939X
+ select SND_SOC_WCD_MBHC
+ select REGMAP_IRQ
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ help
+ The WCD9390/9395 is a audio codec IC Integrated in
+ Qualcomm SoCs like SM8650.
config SND_SOC_WM0010
tristate
@@ -2132,6 +2616,7 @@ config SND_SOC_WM8993
config SND_SOC_WM8994
tristate
+ depends on MFD_WM8994
config SND_SOC_WM8995
tristate
@@ -2146,7 +2631,7 @@ config SND_SOC_WM8997
depends on MFD_WM8997 && MFD_ARIZONA
config SND_SOC_WM8998
- tristate
+ tristate "Wolfson Microelectronics WM8998 codec driver"
depends on MFD_WM8998 && MFD_ARIZONA
config SND_SOC_WM9081
@@ -2179,7 +2664,6 @@ config SND_SOC_WSA881X
tristate "WSA881X Codec"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
- tristate
help
This enables support for Qualcomm WSA8810/WSA8815 Class-D
Smart Speaker Amplifier.
@@ -2188,11 +2672,18 @@ config SND_SOC_WSA883X
tristate "WSA883X Codec"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
- tristate
help
This enables support for Qualcomm WSA8830/WSA8835 Class-D
Smart Speaker Amplifier.
+config SND_SOC_WSA884X
+ tristate "WSA884X Codec"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ help
+ This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D
+ Smart Speaker Amplifier.
+
config SND_SOC_ZL38060
tristate "Microsemi ZL38060 Connected Home Audio Processor"
depends on SPI_MASTER
@@ -2231,6 +2722,12 @@ config SND_SOC_ML26124
config SND_SOC_MT6351
tristate "MediaTek MT6351 Codec"
+config SND_SOC_MT6357
+ tristate "MediaTek MT6357 Codec"
+ help
+ Enable support for the platform which uses MT6357 as
+ external codec device.
+
config SND_SOC_MT6358
tristate "MediaTek MT6358 Codec"
help
@@ -2264,6 +2761,10 @@ config SND_SOC_MT6660
config SND_SOC_NAU8315
tristate "Nuvoton Technology Corporation NAU8315 CODEC"
+config SND_SOC_NAU8325
+ tristate "Nuvoton Technology Corporation NAU8325 CODEC"
+ depends on I2C
+
config SND_SOC_NAU8540
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
depends on I2C
@@ -2288,6 +2789,19 @@ config SND_SOC_NAU8825
tristate
depends on I2C
+config SND_SOC_NTPFW
+ tristate
+
+config SND_SOC_NTP8918
+ select SND_SOC_NTPFW
+ tristate "NeoFidelity NTP8918 amplifier"
+ depends on I2C
+
+config SND_SOC_NTP8835
+ select SND_SOC_NTPFW
+ tristate "NeoFidelity NTP8835 and NTP8835C amplifiers"
+ depends on I2C
+
config SND_SOC_TPA6130A2
tristate "Texas Instruments TPA6130A2 headphone amplifier"
depends on I2C
@@ -2298,6 +2812,7 @@ config SND_SOC_LPASS_MACRO_COMMON
config SND_SOC_LPASS_WSA_MACRO
depends on COMMON_CLK
select REGMAP_MMIO
+ select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_VA_MACRO
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0fd003d432e5..d687d4f74363 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,380 +1,435 @@
# SPDX-License-Identifier: GPL-2.0
-snd-soc-88pm860x-objs := 88pm860x-codec.o
-snd-soc-ab8500-codec-objs := ab8500-codec.o
-snd-soc-ac97-objs := ac97.o
-snd-soc-ad1836-objs := ad1836.o
-snd-soc-ad193x-objs := ad193x.o
-snd-soc-ad193x-spi-objs := ad193x-spi.o
-snd-soc-ad193x-i2c-objs := ad193x-i2c.o
-snd-soc-ad1980-objs := ad1980.o
-snd-soc-ad73311-objs := ad73311.o
-snd-soc-adau-utils-objs := adau-utils.o
-snd-soc-adau1372-objs := adau1372.o
-snd-soc-adau1372-i2c-objs := adau1372-i2c.o
-snd-soc-adau1372-spi-objs := adau1372-spi.o
-snd-soc-adau1373-objs := adau1373.o
-snd-soc-adau1701-objs := adau1701.o
-snd-soc-adau17x1-objs := adau17x1.o
-snd-soc-adau1761-objs := adau1761.o
-snd-soc-adau1761-i2c-objs := adau1761-i2c.o
-snd-soc-adau1761-spi-objs := adau1761-spi.o
-snd-soc-adau1781-objs := adau1781.o
-snd-soc-adau1781-i2c-objs := adau1781-i2c.o
-snd-soc-adau1781-spi-objs := adau1781-spi.o
-snd-soc-adau1977-objs := adau1977.o
-snd-soc-adau1977-spi-objs := adau1977-spi.o
-snd-soc-adau1977-i2c-objs := adau1977-i2c.o
-snd-soc-adau7002-objs := adau7002.o
-snd-soc-adau7118-objs := adau7118.o
-snd-soc-adau7118-i2c-objs := adau7118-i2c.o
-snd-soc-adau7118-hw-objs := adau7118-hw.o
-snd-soc-adav80x-objs := adav80x.o
-snd-soc-adav801-objs := adav801.o
-snd-soc-adav803-objs := adav803.o
-snd-soc-ads117x-objs := ads117x.o
-snd-soc-ak4104-objs := ak4104.o
-snd-soc-ak4118-objs := ak4118.o
-snd-soc-ak4375-objs := ak4375.o
-snd-soc-ak4458-objs := ak4458.o
-snd-soc-ak4535-objs := ak4535.o
-snd-soc-ak4554-objs := ak4554.o
-snd-soc-ak4613-objs := ak4613.o
-snd-soc-ak4641-objs := ak4641.o
-snd-soc-ak4642-objs := ak4642.o
-snd-soc-ak4671-objs := ak4671.o
-snd-soc-ak5386-objs := ak5386.o
-snd-soc-ak5558-objs := ak5558.o
-snd-soc-arizona-objs := arizona.o arizona-jack.o
-snd-soc-aw8738-objs := aw8738.o
-snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o
-snd-soc-aw88395-objs := aw88395/aw88395.o \
+snd-soc-88pm860x-y := 88pm860x-codec.o
+snd-soc-ab8500-codec-y := ab8500-codec.o
+snd-soc-ac97-y := ac97.o
+snd-soc-ad1836-y := ad1836.o
+snd-soc-ad193x-y := ad193x.o
+snd-soc-ad193x-spi-y := ad193x-spi.o
+snd-soc-ad193x-i2c-y := ad193x-i2c.o
+snd-soc-ad1980-y := ad1980.o
+snd-soc-ad73311-y := ad73311.o
+snd-soc-adau-utils-y := adau-utils.o
+snd-soc-adau1372-y := adau1372.o
+snd-soc-adau1372-i2c-y := adau1372-i2c.o
+snd-soc-adau1372-spi-y := adau1372-spi.o
+snd-soc-adau1373-y := adau1373.o
+snd-soc-adau1701-y := adau1701.o
+snd-soc-adau17x1-y := adau17x1.o
+snd-soc-adau1761-y := adau1761.o
+snd-soc-adau1761-i2c-y := adau1761-i2c.o
+snd-soc-adau1761-spi-y := adau1761-spi.o
+snd-soc-adau1781-y := adau1781.o
+snd-soc-adau1781-i2c-y := adau1781-i2c.o
+snd-soc-adau1781-spi-y := adau1781-spi.o
+snd-soc-adau1977-y := adau1977.o
+snd-soc-adau1977-spi-y := adau1977-spi.o
+snd-soc-adau1977-i2c-y := adau1977-i2c.o
+snd-soc-adau7002-y := adau7002.o
+snd-soc-adau7118-y := adau7118.o
+snd-soc-adau7118-i2c-y := adau7118-i2c.o
+snd-soc-adau7118-hw-y := adau7118-hw.o
+snd-soc-adav80x-y := adav80x.o
+snd-soc-adav801-y := adav801.o
+snd-soc-adav803-y := adav803.o
+snd-soc-ads117x-y := ads117x.o
+snd-soc-ak4104-y := ak4104.o
+snd-soc-ak4118-y := ak4118.o
+snd-soc-ak4375-y := ak4375.o
+snd-soc-ak4458-y := ak4458.o
+snd-soc-ak4535-y := ak4535.o
+snd-soc-ak4554-y := ak4554.o
+snd-soc-ak4613-y := ak4613.o
+snd-soc-ak4619-y := ak4619.o
+snd-soc-ak4641-y := ak4641.o
+snd-soc-ak4642-y := ak4642.o
+snd-soc-ak4671-y := ak4671.o
+snd-soc-ak5386-y := ak5386.o
+snd-soc-ak5558-y := ak5558.o
+snd-soc-arizona-y := arizona.o arizona-jack.o
+snd-soc-audio-iio-aux-y := audio-iio-aux.o
+snd-soc-aw8738-y := aw8738.o
+snd-soc-aw87390-y := aw87390.o
+snd-soc-aw88081-y := aw88081.o
+snd-soc-aw88395-lib-y := aw88395/aw88395_lib.o \
aw88395/aw88395_device.o
-snd-soc-bd28623-objs := bd28623.o
-snd-soc-bt-sco-objs := bt-sco.o
-snd-soc-chv3-codec-objs := chv3-codec.o
-snd-soc-cpcap-objs := cpcap.o
-snd-soc-cq93vc-objs := cq93vc.o
-snd-soc-cros-ec-codec-objs := cros_ec_codec.o
-snd-soc-cs35l32-objs := cs35l32.o
-snd-soc-cs35l33-objs := cs35l33.o
-snd-soc-cs35l34-objs := cs35l34.o
-snd-soc-cs35l35-objs := cs35l35.o
-snd-soc-cs35l36-objs := cs35l36.o
-snd-soc-cs35l41-lib-objs := cs35l41-lib.o
-snd-soc-cs35l41-objs := cs35l41.o
-snd-soc-cs35l41-spi-objs := cs35l41-spi.o
-snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o
-snd-soc-cs35l45-objs := cs35l45.o cs35l45-tables.o
-snd-soc-cs35l45-spi-objs := cs35l45-spi.o
-snd-soc-cs35l45-i2c-objs := cs35l45-i2c.o
-snd-soc-cs35l56-objs := cs35l56.o
-snd-soc-cs35l56-shared-objs := cs35l56-shared.o
-snd-soc-cs35l56-i2c-objs := cs35l56-i2c.o
-snd-soc-cs35l56-spi-objs := cs35l56-spi.o
-snd-soc-cs35l56-sdw-objs := cs35l56-sdw.o
-snd-soc-cs42l42-objs := cs42l42.o
-snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o
-snd-soc-cs42l42-sdw-objs := cs42l42-sdw.o
-snd-soc-cs42l51-objs := cs42l51.o
-snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
-snd-soc-cs42l52-objs := cs42l52.o
-snd-soc-cs42l56-objs := cs42l56.o
-snd-soc-cs42l73-objs := cs42l73.o
-snd-soc-cs42l83-i2c-objs := cs42l83-i2c.o
-snd-soc-cs4234-objs := cs4234.o
-snd-soc-cs4265-objs := cs4265.o
-snd-soc-cs4270-objs := cs4270.o
-snd-soc-cs4271-objs := cs4271.o
-snd-soc-cs4271-i2c-objs := cs4271-i2c.o
-snd-soc-cs4271-spi-objs := cs4271-spi.o
-snd-soc-cs42xx8-objs := cs42xx8.o
-snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
-snd-soc-cs43130-objs := cs43130.o
-snd-soc-cs4341-objs := cs4341.o
-snd-soc-cs4349-objs := cs4349.o
-snd-soc-cs47l15-objs := cs47l15.o
-snd-soc-cs47l24-objs := cs47l24.o
-snd-soc-cs47l35-objs := cs47l35.o
-snd-soc-cs47l85-objs := cs47l85.o
-snd-soc-cs47l90-objs := cs47l90.o
-snd-soc-cs47l92-objs := cs47l92.o
-snd-soc-cs53l30-objs := cs53l30.o
-snd-soc-cx20442-objs := cx20442.o
-snd-soc-cx2072x-objs := cx2072x.o
-snd-soc-da7210-objs := da7210.o
-snd-soc-da7213-objs := da7213.o
-snd-soc-da7218-objs := da7218.o
-snd-soc-da7219-objs := da7219.o da7219-aad.o
-snd-soc-da732x-objs := da732x.o
-snd-soc-da9055-objs := da9055.o
-snd-soc-dmic-objs := dmic.o
-snd-soc-es7134-objs := es7134.o
-snd-soc-es7241-objs := es7241.o
-snd-soc-es8316-objs := es8316.o
-snd-soc-es8326-objs := es8326.o
-snd-soc-es8328-objs := es8328.o
-snd-soc-es8328-i2c-objs := es8328-i2c.o
-snd-soc-es8328-spi-objs := es8328-spi.o
-snd-soc-gtm601-objs := gtm601.o
-snd-soc-hdac-hdmi-objs := hdac_hdmi.o
-snd-soc-hdac-hda-objs := hdac_hda.o
-snd-soc-hda-codec-objs := hda.o hda-dai.o
-snd-soc-ics43432-objs := ics43432.o
-snd-soc-idt821034-objs := idt821034.o
-snd-soc-inno-rk3036-objs := inno_rk3036.o
-snd-soc-isabelle-objs := isabelle.o
-snd-soc-jz4740-codec-objs := jz4740.o
-snd-soc-jz4725b-codec-objs := jz4725b.o
-snd-soc-jz4760-codec-objs := jz4760.o
-snd-soc-jz4770-codec-objs := jz4770.o
-snd-soc-l3-objs := l3.o
-snd-soc-lm4857-objs := lm4857.o
-snd-soc-lm49453-objs := lm49453.o
-snd-soc-lochnagar-sc-objs := lochnagar-sc.o
-snd-soc-lpass-macro-common-objs := lpass-macro-common.o
-snd-soc-lpass-rx-macro-objs := lpass-rx-macro.o
-snd-soc-lpass-tx-macro-objs := lpass-tx-macro.o
-snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o
-snd-soc-lpass-va-macro-objs := lpass-va-macro.o
-snd-soc-madera-objs := madera.o
-snd-soc-max9759-objs := max9759.o
-snd-soc-max9768-objs := max9768.o
-snd-soc-max98088-objs := max98088.o
-snd-soc-max98090-objs := max98090.o
-snd-soc-max98095-objs := max98095.o
-snd-soc-max98357a-objs := max98357a.o
-snd-soc-max98371-objs := max98371.o
-snd-soc-max9867-objs := max9867.o
-snd-soc-max98925-objs := max98925.o
-snd-soc-max98926-objs := max98926.o
-snd-soc-max98927-objs := max98927.o
-snd-soc-max98520-objs := max98520.o
-snd-soc-max98363-objs := max98363.o
-snd-soc-max98373-objs := max98373.o
-snd-soc-max98373-i2c-objs := max98373-i2c.o
-snd-soc-max98373-sdw-objs := max98373-sdw.o
-snd-soc-max98388-objs := max98388.o
-snd-soc-max98390-objs := max98390.o
-snd-soc-max98396-objs := max98396.o
-snd-soc-max9850-objs := max9850.o
-snd-soc-max9860-objs := max9860.o
-snd-soc-mc13783-objs := mc13783.o
-snd-soc-ml26124-objs := ml26124.o
-snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
-snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
-snd-soc-mt6351-objs := mt6351.o
-snd-soc-mt6358-objs := mt6358.o
-snd-soc-mt6359-objs := mt6359.o
-snd-soc-mt6359-accdet-objs := mt6359-accdet.o
-snd-soc-mt6660-objs := mt6660.o
-snd-soc-nau8315-objs := nau8315.o
-snd-soc-nau8540-objs := nau8540.o
-snd-soc-nau8810-objs := nau8810.o
-snd-soc-nau8821-objs := nau8821.o
-snd-soc-nau8822-objs := nau8822.o
-snd-soc-nau8824-objs := nau8824.o
-snd-soc-nau8825-objs := nau8825.o
-snd-soc-hdmi-codec-objs := hdmi-codec.o
-snd-soc-pcm1681-objs := pcm1681.o
-snd-soc-pcm1789-codec-objs := pcm1789.o
-snd-soc-pcm1789-i2c-objs := pcm1789-i2c.o
-snd-soc-pcm179x-codec-objs := pcm179x.o
-snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o
-snd-soc-pcm179x-spi-objs := pcm179x-spi.o
-snd-soc-pcm186x-objs := pcm186x.o
-snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
-snd-soc-pcm186x-spi-objs := pcm186x-spi.o
-snd-soc-pcm3008-objs := pcm3008.o
-snd-soc-pcm3060-objs := pcm3060.o
-snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o
-snd-soc-pcm3060-spi-objs := pcm3060-spi.o
-snd-soc-pcm3168a-objs := pcm3168a.o
-snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
-snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
-snd-soc-pcm5102a-objs := pcm5102a.o
-snd-soc-pcm512x-objs := pcm512x.o
-snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
-snd-soc-pcm512x-spi-objs := pcm512x-spi.o
-snd-soc-peb2466-objs := peb2466.o
-snd-soc-rk3328-objs := rk3328_codec.o
-snd-soc-rk817-objs := rk817_codec.o
-snd-soc-rl6231-objs := rl6231.o
-snd-soc-rl6347a-objs := rl6347a.o
-snd-soc-rt1011-objs := rt1011.o
-snd-soc-rt1015-objs := rt1015.o
-snd-soc-rt1015p-objs := rt1015p.o
-snd-soc-rt1016-objs := rt1016.o
-snd-soc-rt1019-objs := rt1019.o
-snd-soc-rt1305-objs := rt1305.o
-snd-soc-rt1308-objs := rt1308.o
-snd-soc-rt1308-sdw-objs := rt1308-sdw.o
-snd-soc-rt1316-sdw-objs := rt1316-sdw.o
-snd-soc-rt1318-sdw-objs := rt1318-sdw.o
-snd-soc-rt274-objs := rt274.o
-snd-soc-rt286-objs := rt286.o
-snd-soc-rt298-objs := rt298.o
-snd-soc-rt5514-objs := rt5514.o
-snd-soc-rt5514-spi-objs := rt5514-spi.o
-snd-soc-rt5616-objs := rt5616.o
-snd-soc-rt5631-objs := rt5631.o
-snd-soc-rt5640-objs := rt5640.o
-snd-soc-rt5645-objs := rt5645.o
-snd-soc-rt5651-objs := rt5651.o
-snd-soc-rt5659-objs := rt5659.o
-snd-soc-rt5660-objs := rt5660.o
-snd-soc-rt5663-objs := rt5663.o
-snd-soc-rt5665-objs := rt5665.o
-snd-soc-rt5668-objs := rt5668.o
-snd-soc-rt5670-objs := rt5670.o
-snd-soc-rt5677-objs := rt5677.o
-snd-soc-rt5677-spi-objs := rt5677-spi.o
-snd-soc-rt5682-objs := rt5682.o
-snd-soc-rt5682-sdw-objs := rt5682-sdw.o
-snd-soc-rt5682-i2c-objs := rt5682-i2c.o
-snd-soc-rt5682s-objs := rt5682s.o
-snd-soc-rt700-objs := rt700.o rt700-sdw.o
-snd-soc-rt711-objs := rt711.o rt711-sdw.o
-snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o
-snd-soc-rt712-sdca-objs := rt712-sdca.o rt712-sdca-sdw.o
-snd-soc-rt712-sdca-dmic-objs := rt712-sdca-dmic.o
-snd-soc-rt715-objs := rt715.o rt715-sdw.o
-snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o
-snd-soc-rt722-sdca-objs := rt722-sdca.o rt722-sdca-sdw.o
-snd-soc-rt9120-objs := rt9120.o
-snd-soc-sdw-mockup-objs := sdw-mockup.o
-snd-soc-sgtl5000-objs := sgtl5000.o
-snd-soc-alc5623-objs := alc5623.o
-snd-soc-alc5632-objs := alc5632.o
-snd-soc-sigmadsp-objs := sigmadsp.o
-snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
-snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
-snd-soc-si476x-objs := si476x.o
-snd-soc-sma1303-objs := sma1303.o
-snd-soc-spdif-tx-objs := spdif_transmitter.o
-snd-soc-spdif-rx-objs := spdif_receiver.o
-snd-soc-src4xxx-objs := src4xxx.o
-snd-soc-src4xxx-i2c-objs := src4xxx-i2c.o
-snd-soc-ssm2305-objs := ssm2305.o
-snd-soc-ssm2518-objs := ssm2518.o
-snd-soc-ssm2602-objs := ssm2602.o
-snd-soc-ssm2602-spi-objs := ssm2602-spi.o
-snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
-snd-soc-ssm3515-objs := ssm3515.o
-snd-soc-ssm4567-objs := ssm4567.o
-snd-soc-sta32x-objs := sta32x.o
-snd-soc-sta350-objs := sta350.o
-snd-soc-sta529-objs := sta529.o
-snd-soc-stac9766-objs := stac9766.o
-snd-soc-sti-sas-objs := sti-sas.o
-snd-soc-tas5086-objs := tas5086.o
-snd-soc-tas571x-objs := tas571x.o
-snd-soc-tas5720-objs := tas5720.o
-snd-soc-tas5805m-objs := tas5805m.o
-snd-soc-tas6424-objs := tas6424.o
-snd-soc-tda7419-objs := tda7419.o
-snd-soc-tas2770-objs := tas2770.o
-snd-soc-tfa9879-objs := tfa9879.o
-snd-soc-tfa989x-objs := tfa989x.o
-snd-soc-tlv320adc3xxx-objs := tlv320adc3xxx.o
-snd-soc-tlv320aic23-objs := tlv320aic23.o
-snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
-snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
-snd-soc-tlv320aic26-objs := tlv320aic26.o
-snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
-snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
-snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
-snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
-snd-soc-tlv320aic3x-i2c-objs := tlv320aic3x-i2c.o
-snd-soc-tlv320aic3x-spi-objs := tlv320aic3x-spi.o
-snd-soc-tlv320dac33-objs := tlv320dac33.o
-snd-soc-tlv320adcx140-objs := tlv320adcx140.o
-snd-soc-tscs42xx-objs := tscs42xx.o
-snd-soc-tscs454-objs := tscs454.o
-snd-soc-ts3a227e-objs := ts3a227e.o
-snd-soc-twl4030-objs := twl4030.o
-snd-soc-twl6040-objs := twl6040.o
-snd-soc-uda1334-objs := uda1334.o
-snd-soc-uda134x-objs := uda134x.o
-snd-soc-uda1380-objs := uda1380.o
-snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o
-snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
-snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
-snd-soc-wcd938x-objs := wcd938x.o wcd-clsh-v2.o
-snd-soc-wcd938x-sdw-objs := wcd938x-sdw.o
-snd-soc-wl1273-objs := wl1273.o
-snd-soc-wm-adsp-objs := wm_adsp.o
-snd-soc-wm0010-objs := wm0010.o
-snd-soc-wm1250-ev1-objs := wm1250-ev1.o
-snd-soc-wm2000-objs := wm2000.o
-snd-soc-wm2200-objs := wm2200.o
-snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
-snd-soc-wm5102-objs := wm5102.o
-snd-soc-wm5110-objs := wm5110.o
-snd-soc-wm8350-objs := wm8350.o
-snd-soc-wm8400-objs := wm8400.o
-snd-soc-wm8510-objs := wm8510.o
-snd-soc-wm8523-objs := wm8523.o
-snd-soc-wm8524-objs := wm8524.o
-snd-soc-wm8580-objs := wm8580.o
-snd-soc-wm8711-objs := wm8711.o
-snd-soc-wm8727-objs := wm8727.o
-snd-soc-wm8728-objs := wm8728.o
-snd-soc-wm8731-objs := wm8731.o
-snd-soc-wm8731-i2c-objs := wm8731-i2c.o
-snd-soc-wm8731-spi-objs := wm8731-spi.o
-snd-soc-wm8737-objs := wm8737.o
-snd-soc-wm8741-objs := wm8741.o
-snd-soc-wm8750-objs := wm8750.o
-snd-soc-wm8753-objs := wm8753.o
-snd-soc-wm8770-objs := wm8770.o
-snd-soc-wm8776-objs := wm8776.o
-snd-soc-wm8782-objs := wm8782.o
-snd-soc-wm8804-objs := wm8804.o
-snd-soc-wm8804-i2c-objs := wm8804-i2c.o
-snd-soc-wm8804-spi-objs := wm8804-spi.o
-snd-soc-wm8900-objs := wm8900.o
-snd-soc-wm8903-objs := wm8903.o
-snd-soc-wm8904-objs := wm8904.o
-snd-soc-wm8996-objs := wm8996.o
-snd-soc-wm8940-objs := wm8940.o
-snd-soc-wm8955-objs := wm8955.o
-snd-soc-wm8960-objs := wm8960.o
-snd-soc-wm8961-objs := wm8961.o
-snd-soc-wm8962-objs := wm8962.o
-snd-soc-wm8971-objs := wm8971.o
-snd-soc-wm8974-objs := wm8974.o
-snd-soc-wm8978-objs := wm8978.o
-snd-soc-wm8983-objs := wm8983.o
-snd-soc-wm8985-objs := wm8985.o
-snd-soc-wm8988-objs := wm8988.o
-snd-soc-wm8990-objs := wm8990.o
-snd-soc-wm8991-objs := wm8991.o
-snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
-snd-soc-wm8995-objs := wm8995.o
-snd-soc-wm8997-objs := wm8997.o
-snd-soc-wm8998-objs := wm8998.o
-snd-soc-wm9081-objs := wm9081.o
-snd-soc-wm9090-objs := wm9090.o
-snd-soc-wm9705-objs := wm9705.o
-snd-soc-wm9712-objs := wm9712.o
-snd-soc-wm9713-objs := wm9713.o
-snd-soc-wm-hubs-objs := wm_hubs.o
-snd-soc-wsa881x-objs := wsa881x.o
-snd-soc-wsa883x-objs := wsa883x.o
-snd-soc-zl38060-objs := zl38060.o
+snd-soc-aw88395-y := aw88395/aw88395.o
+snd-soc-aw88166-y := aw88166.o
+snd-soc-aw88261-y := aw88261.o
+snd-soc-aw88399-y := aw88399.o
+snd-soc-bd28623-y := bd28623.o
+snd-soc-bt-sco-y := bt-sco.o
+snd-soc-chv3-codec-y := chv3-codec.o
+snd-soc-cpcap-y := cpcap.o
+snd-soc-cq93vc-y := cq93vc.o
+snd-soc-cros-ec-codec-y := cros_ec_codec.o
+snd-soc-cs-amp-lib-y := cs-amp-lib.o
+snd-soc-cs-amp-lib-test-y := cs-amp-lib-test.o
+snd-soc-cs35l32-y := cs35l32.o
+snd-soc-cs35l33-y := cs35l33.o
+snd-soc-cs35l34-y := cs35l34.o
+snd-soc-cs35l35-y := cs35l35.o
+snd-soc-cs35l36-y := cs35l36.o
+snd-soc-cs35l41-lib-y := cs35l41-lib.o
+snd-soc-cs35l41-y := cs35l41.o
+snd-soc-cs35l41-spi-y := cs35l41-spi.o
+snd-soc-cs35l41-i2c-y := cs35l41-i2c.o
+snd-soc-cs35l45-y := cs35l45.o cs35l45-tables.o
+snd-soc-cs35l45-spi-y := cs35l45-spi.o
+snd-soc-cs35l45-i2c-y := cs35l45-i2c.o
+snd-soc-cs35l56-y := cs35l56.o
+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-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
+snd-soc-cs42l43-y := cs42l43.o cs42l43-jack.o
+snd-soc-cs42l43-sdw-y := cs42l43-sdw.o
+snd-soc-cs42l51-y := cs42l51.o
+snd-soc-cs42l51-i2c-y := cs42l51-i2c.o
+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-y := cs42l84.o
+snd-soc-cs4234-y := cs4234.o
+snd-soc-cs4265-y := cs4265.o
+snd-soc-cs4270-y := cs4270.o
+snd-soc-cs4271-y := cs4271.o
+snd-soc-cs4271-i2c-y := cs4271-i2c.o
+snd-soc-cs4271-spi-y := cs4271-spi.o
+snd-soc-cs42xx8-y := cs42xx8.o
+snd-soc-cs42xx8-i2c-y := cs42xx8-i2c.o
+snd-soc-cs43130-y := cs43130.o
+snd-soc-cs4341-y := cs4341.o
+snd-soc-cs4349-y := cs4349.o
+snd-soc-cs47l15-y := cs47l15.o
+snd-soc-cs47l24-y := cs47l24.o
+snd-soc-cs47l35-y := cs47l35.o
+snd-soc-cs47l85-y := cs47l85.o
+snd-soc-cs47l90-y := cs47l90.o
+snd-soc-cs47l92-y := cs47l92.o
+snd-soc-cs48l32-y := cs48l32.o cs48l32-tables.o
+snd-soc-cs53l30-y := cs53l30.o
+snd-soc-cs530x-y := cs530x.o
+snd-soc-cs530x-i2c-y := cs530x-i2c.o
+snd-soc-cs530x-spi-y := cs530x-spi.o
+snd-soc-cx20442-y := cx20442.o
+snd-soc-cx2072x-y := cx2072x.o
+snd-soc-da7210-y := da7210.o
+snd-soc-da7213-y := da7213.o
+snd-soc-da7218-y := da7218.o
+snd-soc-da7219-y := da7219.o da7219-aad.o
+snd-soc-da732x-y := da732x.o
+snd-soc-da9055-y := da9055.o
+snd-soc-dmic-y := dmic.o
+snd-soc-es7134-y := es7134.o
+snd-soc-es7241-y := es7241.o
+snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o
+snd-soc-es8311-y := es8311.o
+snd-soc-es8316-y := es8316.o
+snd-soc-es8323-y := es8323.o
+snd-soc-es8326-y := es8326.o
+snd-soc-es8328-y := es8328.o
+snd-soc-es8328-i2c-y := es8328-i2c.o
+snd-soc-es8328-spi-y := es8328-spi.o
+snd-soc-es8375-y := es8375.o
+snd-soc-es8389-y := es8389.o
+snd-soc-framer-y := framer-codec.o
+snd-soc-fs-amp-lib-y := fs-amp-lib.o
+snd-soc-fs210x-y := fs210x.o
+snd-soc-gtm601-y := gtm601.o
+snd-soc-hdac-hdmi-y := hdac_hdmi.o
+snd-soc-hdac-hda-y := hdac_hda.o
+snd-soc-hda-codec-y := hda.o hda-dai.o
+snd-soc-ics43432-y := ics43432.o
+snd-soc-idt821034-y := idt821034.o
+snd-soc-inno-rk3036-y := inno_rk3036.o
+snd-soc-isabelle-y := isabelle.o
+snd-soc-jz4740-codec-y := jz4740.o
+snd-soc-jz4725b-codec-y := jz4725b.o
+snd-soc-jz4760-codec-y := jz4760.o
+snd-soc-jz4770-codec-y := jz4770.o
+snd-soc-lm4857-y := lm4857.o
+snd-soc-lm49453-y := lm49453.o
+snd-soc-lochnagar-sc-y := lochnagar-sc.o
+snd-soc-lpass-macro-common-y := lpass-macro-common.o
+snd-soc-lpass-rx-macro-y := lpass-rx-macro.o
+snd-soc-lpass-tx-macro-y := lpass-tx-macro.o
+snd-soc-lpass-wsa-macro-y := lpass-wsa-macro.o
+snd-soc-lpass-va-macro-y := lpass-va-macro.o
+snd-soc-madera-y := madera.o
+snd-soc-max9759-y := max9759.o
+snd-soc-max9768-y := max9768.o
+snd-soc-max98088-y := max98088.o
+snd-soc-max98090-y := max98090.o
+snd-soc-max98095-y := max98095.o
+snd-soc-max98357a-y := max98357a.o
+snd-soc-max98371-y := max98371.o
+snd-soc-max9867-y := max9867.o
+snd-soc-max98925-y := max98925.o
+snd-soc-max98926-y := max98926.o
+snd-soc-max98927-y := max98927.o
+snd-soc-max98520-y := max98520.o
+snd-soc-max98363-y := max98363.o
+snd-soc-max98373-y := max98373.o
+snd-soc-max98373-i2c-y := max98373-i2c.o
+snd-soc-max98373-sdw-y := max98373-sdw.o
+snd-soc-max98388-y := max98388.o
+snd-soc-max98390-y := max98390.o
+snd-soc-max98396-y := max98396.o
+snd-soc-max9850-y := max9850.o
+snd-soc-max9860-y := max9860.o
+snd-soc-mc13783-y := mc13783.o
+snd-soc-ml26124-y := ml26124.o
+snd-soc-msm8916-analog-y := msm8916-wcd-analog.o
+snd-soc-msm8916-digital-y := msm8916-wcd-digital.o
+snd-soc-mt6351-y := mt6351.o
+snd-soc-mt6357-y := mt6357.o
+snd-soc-mt6358-y := mt6358.o
+snd-soc-mt6359-y := mt6359.o
+snd-soc-mt6359-accdet-y := mt6359-accdet.o
+snd-soc-mt6660-y := mt6660.o
+snd-soc-nau8315-y := nau8315.o
+snd-soc-nau8325-y := nau8325.o
+snd-soc-nau8540-y := nau8540.o
+snd-soc-nau8810-y := nau8810.o
+snd-soc-nau8821-y := nau8821.o
+snd-soc-nau8822-y := nau8822.o
+snd-soc-nau8824-y := nau8824.o
+snd-soc-nau8825-y := nau8825.o
+snd-soc-ntp8835-y := ntp8835.o
+snd-soc-ntp8918-y := ntp8918.o
+snd-soc-ntpfw-y := ntpfw.o
+snd-soc-hdmi-codec-y := hdmi-codec.o
+snd-soc-pcm1681-y := pcm1681.o
+snd-soc-pcm1754-y := pcm1754.o
+snd-soc-pcm1789-codec-y := pcm1789.o
+snd-soc-pcm1789-i2c-y := pcm1789-i2c.o
+snd-soc-pcm179x-codec-y := pcm179x.o
+snd-soc-pcm179x-i2c-y := pcm179x-i2c.o
+snd-soc-pcm179x-spi-y := pcm179x-spi.o
+snd-soc-pcm186x-y := pcm186x.o
+snd-soc-pcm186x-i2c-y := pcm186x-i2c.o
+snd-soc-pcm186x-spi-y := pcm186x-spi.o
+snd-soc-pcm3008-y := pcm3008.o
+snd-soc-pcm3060-y := pcm3060.o
+snd-soc-pcm3060-i2c-y := pcm3060-i2c.o
+snd-soc-pcm3060-spi-y := pcm3060-spi.o
+snd-soc-pcm3168a-y := pcm3168a.o
+snd-soc-pcm3168a-i2c-y := pcm3168a-i2c.o
+snd-soc-pcm3168a-spi-y := pcm3168a-spi.o
+snd-soc-pcm5102a-y := pcm5102a.o
+snd-soc-pcm512x-y := pcm512x.o
+snd-soc-pcm512x-i2c-y := pcm512x-i2c.o
+snd-soc-pcm512x-spi-y := pcm512x-spi.o
+snd-soc-pcm6240-y := pcm6240.o
+snd-soc-peb2466-y := peb2466.o
+snd-soc-pm4125-y := pm4125.o
+snd-soc-pm4125-sdw-y := pm4125-sdw.o
+snd-soc-rk3308-y := rk3308_codec.o
+snd-soc-rk3328-y := rk3328_codec.o
+snd-soc-rk817-y := rk817_codec.o
+snd-soc-rl6231-y := rl6231.o
+snd-soc-rt-sdw-common-y := rt-sdw-common.o
+snd-soc-rl6347a-y := rl6347a.o
+snd-soc-rt1011-y := rt1011.o
+snd-soc-rt1015-y := rt1015.o
+snd-soc-rt1015p-y := rt1015p.o
+snd-soc-rt1016-y := rt1016.o
+snd-soc-rt1017-sdca-y := rt1017-sdca-sdw.o
+snd-soc-rt1019-y := rt1019.o
+snd-soc-rt1305-y := rt1305.o
+snd-soc-rt1308-y := rt1308.o
+snd-soc-rt1308-sdw-y := rt1308-sdw.o
+snd-soc-rt1316-sdw-y := rt1316-sdw.o
+snd-soc-rt1318-y := rt1318.o
+snd-soc-rt1318-sdw-y := rt1318-sdw.o
+snd-soc-rt1320-sdw-y := rt1320-sdw.o
+snd-soc-rt274-y := rt274.o
+snd-soc-rt286-y := rt286.o
+snd-soc-rt298-y := rt298.o
+snd-soc-rt5514-y := rt5514.o
+snd-soc-rt5514-spi-y := rt5514-spi.o
+snd-soc-rt5616-y := rt5616.o
+snd-soc-rt5631-y := rt5631.o
+snd-soc-rt5640-y := rt5640.o
+snd-soc-rt5645-y := rt5645.o
+snd-soc-rt5651-y := rt5651.o
+snd-soc-rt5659-y := rt5659.o
+snd-soc-rt5660-y := rt5660.o
+snd-soc-rt5663-y := rt5663.o
+snd-soc-rt5665-y := rt5665.o
+snd-soc-rt5668-y := rt5668.o
+snd-soc-rt5670-y := rt5670.o
+snd-soc-rt5677-y := rt5677.o
+snd-soc-rt5677-spi-y := rt5677-spi.o
+snd-soc-rt5682-y := rt5682.o
+snd-soc-rt5682-sdw-y := rt5682-sdw.o
+snd-soc-rt5682-i2c-y := rt5682-i2c.o
+snd-soc-rt5682s-y := rt5682s.o
+snd-soc-rt700-y := rt700.o rt700-sdw.o
+snd-soc-rt711-y := rt711.o rt711-sdw.o
+snd-soc-rt711-sdca-y := rt711-sdca.o rt711-sdca-sdw.o
+snd-soc-rt712-sdca-y := rt712-sdca.o rt712-sdca-sdw.o
+snd-soc-rt712-sdca-dmic-y := rt712-sdca-dmic.o
+snd-soc-rt715-y := rt715.o rt715-sdw.o
+snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o
+snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o
+snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o
+snd-soc-rt9120-y := rt9120.o
+snd-soc-rt9123-y := rt9123.o
+snd-soc-rt9123p-y := rt9123p.o
+snd-soc-rtq9124-y := rtq9124.o
+snd-soc-rtq9128-y := rtq9128.o
+snd-soc-sdw-mockup-y := sdw-mockup.o
+snd-soc-sgtl5000-y := sgtl5000.o
+snd-soc-alc5623-y := alc5623.o
+snd-soc-alc5632-y := alc5632.o
+snd-soc-sigmadsp-y := sigmadsp.o
+snd-soc-sigmadsp-i2c-y := sigmadsp-i2c.o
+snd-soc-sigmadsp-regmap-y := sigmadsp-regmap.o
+snd-soc-si476x-y := si476x.o
+snd-soc-sma1303-y := sma1303.o
+snd-soc-sma1307-y := sma1307.o
+snd-soc-spdif-tx-y := spdif_transmitter.o
+snd-soc-spdif-rx-y := spdif_receiver.o
+snd-soc-src4xxx-y := src4xxx.o
+snd-soc-src4xxx-i2c-y := src4xxx-i2c.o
+snd-soc-ssm2305-y := ssm2305.o
+snd-soc-ssm2518-y := ssm2518.o
+snd-soc-ssm2602-y := ssm2602.o
+snd-soc-ssm2602-spi-y := ssm2602-spi.o
+snd-soc-ssm2602-i2c-y := ssm2602-i2c.o
+snd-soc-ssm3515-y := ssm3515.o
+snd-soc-ssm4567-y := ssm4567.o
+snd-soc-sta32x-y := sta32x.o
+snd-soc-sta350-y := sta350.o
+snd-soc-sta529-y := sta529.o
+snd-soc-stac9766-y := stac9766.o
+snd-soc-sti-sas-y := sti-sas.o
+snd-soc-tas5086-y := tas5086.o
+snd-soc-tas571x-y := tas571x.o
+snd-soc-tas5720-y := tas5720.o
+snd-soc-tas5805m-y := tas5805m.o
+snd-soc-tas6424-y := tas6424.o
+snd-soc-tda7419-y := tda7419.o
+snd-soc-tas2770-y := tas2770.o
+snd-soc-tas2781-comlib-y := tas2781-comlib.o
+snd-soc-tas2781-comlib-i2c-y := tas2781-comlib-i2c.o
+snd-soc-tas2781-fmwlib-y := tas2781-fmwlib.o
+snd-soc-tas2781-i2c-y := tas2781-i2c.o
+snd-soc-tas2783-sdw-y := tas2783-sdw.o
+snd-soc-tfa9879-y := tfa9879.o
+snd-soc-tfa989x-y := tfa989x.o
+snd-soc-tlv320adc3xxx-y := tlv320adc3xxx.o
+snd-soc-tlv320aic23-y := tlv320aic23.o
+snd-soc-tlv320aic23-i2c-y := tlv320aic23-i2c.o
+snd-soc-tlv320aic23-spi-y := tlv320aic23-spi.o
+snd-soc-tlv320aic26-y := tlv320aic26.o
+snd-soc-tlv320aic31xx-y := tlv320aic31xx.o
+snd-soc-tlv320aic32x4-y := tlv320aic32x4.o tlv320aic32x4-clk.o
+snd-soc-tlv320aic32x4-i2c-y := tlv320aic32x4-i2c.o
+snd-soc-tlv320aic32x4-spi-y := tlv320aic32x4-spi.o
+snd-soc-tlv320aic3x-y := tlv320aic3x.o
+snd-soc-tlv320aic3x-i2c-y := tlv320aic3x-i2c.o
+snd-soc-tlv320aic3x-spi-y := tlv320aic3x-spi.o
+snd-soc-tlv320dac33-y := tlv320dac33.o
+snd-soc-tlv320adcx140-y := tlv320adcx140.o
+snd-soc-tscs42xx-y := tscs42xx.o
+snd-soc-tscs454-y := tscs454.o
+snd-soc-ts3a227e-y := ts3a227e.o
+snd-soc-twl4030-y := twl4030.o
+snd-soc-twl6040-y := twl6040.o
+snd-soc-uda1334-y := uda1334.o
+snd-soc-uda1342-y := uda1342.o
+snd-soc-uda1380-y := uda1380.o
+snd-soc-wcd-classh-y := wcd-clsh-v2.o
+snd-soc-wcd-common-y := wcd-common.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-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
+snd-soc-wcd939x-sdw-y := wcd939x-sdw.o
+snd-soc-wm-adsp-y := wm_adsp.o
+snd-soc-wm0010-y := wm0010.o
+snd-soc-wm1250-ev1-y := wm1250-ev1.o
+snd-soc-wm2000-y := wm2000.o
+snd-soc-wm2200-y := wm2200.o
+snd-soc-wm5100-y := wm5100.o wm5100-tables.o
+snd-soc-wm5102-y := wm5102.o
+snd-soc-wm5110-y := wm5110.o
+snd-soc-wm8350-y := wm8350.o
+snd-soc-wm8400-y := wm8400.o
+snd-soc-wm8510-y := wm8510.o
+snd-soc-wm8523-y := wm8523.o
+snd-soc-wm8524-y := wm8524.o
+snd-soc-wm8580-y := wm8580.o
+snd-soc-wm8711-y := wm8711.o
+snd-soc-wm8727-y := wm8727.o
+snd-soc-wm8728-y := wm8728.o
+snd-soc-wm8731-y := wm8731.o
+snd-soc-wm8731-i2c-y := wm8731-i2c.o
+snd-soc-wm8731-spi-y := wm8731-spi.o
+snd-soc-wm8737-y := wm8737.o
+snd-soc-wm8741-y := wm8741.o
+snd-soc-wm8750-y := wm8750.o
+snd-soc-wm8753-y := wm8753.o
+snd-soc-wm8770-y := wm8770.o
+snd-soc-wm8776-y := wm8776.o
+snd-soc-wm8782-y := wm8782.o
+snd-soc-wm8804-y := wm8804.o
+snd-soc-wm8804-i2c-y := wm8804-i2c.o
+snd-soc-wm8804-spi-y := wm8804-spi.o
+snd-soc-wm8900-y := wm8900.o
+snd-soc-wm8903-y := wm8903.o
+snd-soc-wm8904-y := wm8904.o
+snd-soc-wm8996-y := wm8996.o
+snd-soc-wm8940-y := wm8940.o
+snd-soc-wm8955-y := wm8955.o
+snd-soc-wm8960-y := wm8960.o
+snd-soc-wm8961-y := wm8961.o
+snd-soc-wm8962-y := wm8962.o
+snd-soc-wm8971-y := wm8971.o
+snd-soc-wm8974-y := wm8974.o
+snd-soc-wm8978-y := wm8978.o
+snd-soc-wm8983-y := wm8983.o
+snd-soc-wm8985-y := wm8985.o
+snd-soc-wm8988-y := wm8988.o
+snd-soc-wm8990-y := wm8990.o
+snd-soc-wm8991-y := wm8991.o
+snd-soc-wm8993-y := wm8993.o
+snd-soc-wm8994-y := wm8994.o wm8958-dsp2.o
+snd-soc-wm8995-y := wm8995.o
+snd-soc-wm8997-y := wm8997.o
+snd-soc-wm8998-y := wm8998.o
+snd-soc-wm9081-y := wm9081.o
+snd-soc-wm9090-y := wm9090.o
+snd-soc-wm9705-y := wm9705.o
+snd-soc-wm9712-y := wm9712.o
+snd-soc-wm9713-y := wm9713.o
+snd-soc-wm-hubs-y := wm_hubs.o
+snd-soc-wsa881x-y := wsa881x.o
+snd-soc-wsa883x-y := wsa883x.o
+snd-soc-wsa884x-y := wsa884x.o
+snd-soc-zl38060-y := zl38060.o
# Amp
-snd-soc-max9877-objs := max9877.o
-snd-soc-max98504-objs := max98504.o
-snd-soc-simple-amplifier-objs := simple-amplifier.o
-snd-soc-tpa6130a2-objs := tpa6130a2.o
-snd-soc-tas2552-objs := tas2552.o
-snd-soc-tas2562-objs := tas2562.o
-snd-soc-tas2764-objs := tas2764.o
-snd-soc-tas2780-objs := tas2780.o
+snd-soc-max9877-y := max9877.o
+snd-soc-max98504-y := max98504.o
+snd-soc-simple-amplifier-y := simple-amplifier.o
+snd-soc-tpa6130a2-y := tpa6130a2.o
+snd-soc-tas2552-y := tas2552.o
+snd-soc-tas2562-y := tas2562.o
+snd-soc-tas2764-y := tas2764.o
+snd-soc-tas2780-y := tas2780.o
# Mux
-snd-soc-simple-mux-objs := simple-mux.o
+snd-soc-simple-mux-y := simple-mux.o
obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
@@ -416,6 +471,7 @@ obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o
obj-$(CONFIG_SND_SOC_AK4613) += snd-soc-ak4613.o
+obj-$(CONFIG_SND_SOC_AK4619) += snd-soc-ak4619.o
obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
@@ -424,15 +480,23 @@ obj-$(CONFIG_SND_SOC_AK5558) += snd-soc-ak5558.o
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
+obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o
obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o
+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
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o
obj-$(CONFIG_SND_SOC_CROS_EC_CODEC) += snd-soc-cros-ec-codec.o
+obj-$(CONFIG_SND_SOC_CS_AMP_LIB) += snd-soc-cs-amp-lib.o
+obj-$(CONFIG_SND_SOC_CS_AMP_LIB_TEST) += snd-soc-cs-amp-lib-test.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o
@@ -450,15 +514,19 @@ obj-$(CONFIG_SND_SOC_CS35L56_SHARED) += snd-soc-cs35l56-shared.o
obj-$(CONFIG_SND_SOC_CS35L56_I2C) += snd-soc-cs35l56-i2c.o
obj-$(CONFIG_SND_SOC_CS35L56_SPI) += snd-soc-cs35l56-spi.o
obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o
+obj-$(CONFIG_SND_SOC_CS40L50) += snd-soc-cs40l50.o
obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o
obj-$(CONFIG_SND_SOC_CS42L42_SDW) += snd-soc-cs42l42-sdw.o
+obj-$(CONFIG_SND_SOC_CS42L43) += snd-soc-cs42l43.o
+obj-$(CONFIG_SND_SOC_CS42L43_SDW) += snd-soc-cs42l43-sdw.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o
+obj-$(CONFIG_SND_SOC_CS42L84) += snd-soc-cs42l84.o
obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
@@ -476,7 +544,11 @@ obj-$(CONFIG_SND_SOC_CS47L35) += snd-soc-cs47l35.o
obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o
obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o
obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o
+obj-$(CONFIG_SND_SOC_CS48L32) += snd-soc-cs48l32.o
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
+obj-$(CONFIG_SND_SOC_CS530X) += snd-soc-cs530x.o
+obj-$(CONFIG_SND_SOC_CS530X_I2C) += snd-soc-cs530x-i2c.o
+obj-$(CONFIG_SND_SOC_CS530X_SPI) += snd-soc-cs530x-spi.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
@@ -488,11 +560,19 @@ obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o
obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o
+obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o
+obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.o
obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o
obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
+obj-$(CONFIG_SND_SOC_ES8375) += snd-soc-es8375.o
+obj-$(CONFIG_SND_SOC_ES8389) += snd-soc-es8389.o
+obj-$(CONFIG_SND_SOC_FRAMER) += snd-soc-framer.o
+obj-$(CONFIG_SND_SOC_FS_AMP_LIB)+= snd-soc-fs-amp-lib.o
+obj-$(CONFIG_SND_SOC_FS210X) += snd-soc-fs210x.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
@@ -505,7 +585,6 @@ obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o
obj-$(CONFIG_SND_SOC_JZ4760_CODEC) += snd-soc-jz4760-codec.o
obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o
-obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o
@@ -536,19 +615,25 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
+obj-$(CONFIG_SND_SOC_MT6357) += snd-soc-mt6357.o
obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o
obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o
obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o
obj-$(CONFIG_SND_SOC_NAU8315) += snd-soc-nau8315.o
+obj-$(CONFIG_SND_SOC_NAU8325) += snd-soc-nau8325.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8821) += snd-soc-nau8821.o
obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o
obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
+obj-$(CONFIG_SND_SOC_NTP8835) += snd-soc-ntp8835.o
+obj-$(CONFIG_SND_SOC_NTP8918) += snd-soc-ntp8918.o
+obj-$(CONFIG_SND_SOC_NTPFW) += snd-soc-ntpfw.o
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
+obj-$(CONFIG_SND_SOC_PCM1754) += snd-soc-pcm1754.o
obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
obj-$(CONFIG_SND_SOC_PCM1789_I2C) += snd-soc-pcm1789-i2c.o
obj-$(CONFIG_SND_SOC_PCM1789) += snd-soc-pcm1789-codec.o
@@ -568,21 +653,33 @@ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
+obj-$(CONFIG_SND_SOC_PCM6240) += snd-soc-pcm6240.o
obj-$(CONFIG_SND_SOC_PEB2466) += snd-soc-peb2466.o
+obj-$(CONFIG_SND_SOC_PM4125_SDW) += snd-soc-pm4125-sdw.o
+obj-$(CONFIG_SND_SOC_PM4125) += snd-soc-pm4125.o
+ifdef CONFIG_SND_SOC_PM4125_SDW
+# avoid link failure by forcing sdw code built-in when needed
+obj-$(CONFIG_SND_SOC_PM4125) += snd-soc-pm4125-sdw.o
+endif
+obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
+obj-$(CONFIG_SND_SOC_RT_SDW_COMMON) += snd-soc-rt-sdw-common.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o
obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o
obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o
+obj-$(CONFIG_SND_SOC_RT1017_SDCA_SDW) += snd-soc-rt1017-sdca.o
obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o
obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o
+obj-$(CONFIG_SND_SOC_RT1318) += snd-soc-rt1318.o
obj-$(CONFIG_SND_SOC_RT1318_SDW) += snd-soc-rt1318-sdw.o
+obj-$(CONFIG_SND_SOC_RT1320_SDW) += snd-soc-rt1320-sdw.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
@@ -613,8 +710,13 @@ obj-$(CONFIG_SND_SOC_RT712_SDCA_SDW) += snd-soc-rt712-sdca.o
obj-$(CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW) += snd-soc-rt712-sdca-dmic.o
obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o
+obj-$(CONFIG_SND_SOC_RT721_SDCA_SDW) += snd-soc-rt721-sdca.o
obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o
obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o
+obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o
+obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o
+obj-$(CONFIG_SND_SOC_RTQ9124) += snd-soc-rtq9124.o
+obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o
obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
@@ -622,6 +724,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o
+obj-$(CONFIG_SND_SOC_SMA1307) += snd-soc-sma1307.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o
obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o
@@ -641,6 +744,11 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o
obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o
obj-$(CONFIG_SND_SOC_TAS2780) += snd-soc-tas2780.o
+obj-$(CONFIG_SND_SOC_TAS2781_COMLIB) += snd-soc-tas2781-comlib.o
+obj-$(CONFIG_SND_SOC_TAS2781_COMLIB_I2C) += snd-soc-tas2781-comlib-i2c.o
+obj-$(CONFIG_SND_SOC_TAS2781_FMWLIB) += snd-soc-tas2781-fmwlib.o
+obj-$(CONFIG_SND_SOC_TAS2781_I2C) += snd-soc-tas2781-i2c.o
+obj-$(CONFIG_SND_SOC_TAS2783_SDW) += snd-soc-tas2783-sdw.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
@@ -670,17 +778,28 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o
-obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
+obj-$(CONFIG_SND_SOC_UDA1342) += snd-soc-uda1342.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WCD_CLASSH) += snd-soc-wcd-classh.o
+obj-$(CONFIG_SND_SOC_WCD_COMMON) += snd-soc-wcd-common.o
obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o
obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o
obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o
+obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x.o
+ifdef CONFIG_SND_SOC_WCD937X_SDW
+# avoid link failure by forcing sdw code built-in when needed
+obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x-sdw.o
+endif
obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o
ifdef CONFIG_SND_SOC_WCD938X_SDW
# avoid link failure by forcing sdw code built-in when needed
obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x-sdw.o
endif
-obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WCD939X) += snd-soc-wcd939x.o
+ifdef CONFIG_SND_SOC_WCD939X_SDW
+# avoid link failure by forcing sdw code built-in when needed
+obj-$(CONFIG_SND_SOC_WCD939X) += snd-soc-wcd939x-sdw.o
+endif
obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
@@ -741,6 +860,7 @@ obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o
+obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o
obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o
# Amp
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 68342917419e..fdda1b747bf7 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1114,7 +1114,7 @@ static void anc_configure(struct snd_soc_component *component,
static int sid_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
mutex_lock(&drvdata->ctrl_lock);
@@ -1128,7 +1128,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
static int sid_status_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
unsigned int param, sidconf, val;
int status = 1;
@@ -1183,7 +1183,7 @@ out:
static int anc_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
mutex_lock(&drvdata->ctrl_lock);
@@ -1196,8 +1196,8 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
static int anc_status_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
struct device *dev = component->dev;
bool apply_fir, apply_iir;
@@ -1279,7 +1279,7 @@ static int filter_control_info(struct snd_kcontrol *kcontrol,
static int filter_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
struct filter_control *fc =
(struct filter_control *)kcontrol->private_value;
@@ -1296,7 +1296,7 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
static int filter_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
struct filter_control *fc =
(struct filter_control *)kcontrol->private_value;
@@ -1934,7 +1934,7 @@ static int ab8500_audio_init_audioblock(struct snd_soc_component *component)
static int ab8500_audio_setup_mics(struct snd_soc_component *component,
struct amic_settings *amics)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u8 value8;
unsigned int value;
int status;
@@ -2449,7 +2449,7 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
static int ab8500_codec_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct device *dev = component->dev;
struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
@@ -2571,4 +2571,5 @@ static struct platform_driver ab8500_codec_platform_driver = {
};
module_platform_driver(ab8500_codec_platform_driver);
+MODULE_DESCRIPTION("ASoC AB8500 codec driver");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 0e013edfe63d..d8444a083af2 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
@@ -127,9 +128,18 @@ static int ac97_probe(struct platform_device *pdev)
&soc_component_dev_ac97, &ac97_dai, 1);
}
+#ifdef CONFIG_OF
+static const struct of_device_id ac97_codec_of_match[] = {
+ { .compatible = "realtek,alc203", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ac97_codec_of_match);
+#endif
+
static struct platform_driver ac97_codec_driver = {
.driver = {
.name = "ac97-codec",
+ .of_match_table = of_match_ptr(ac97_codec_of_match),
},
.probe = ac97_probe,
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 2c64df96b5ce..8afeadcaf8b0 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -250,7 +250,7 @@ static int ad1836_resume(struct snd_soc_component *component)
static int ad1836_probe(struct snd_soc_component *component)
{
struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int num_dacs, num_adcs;
int ret = 0;
int i;
@@ -358,7 +358,7 @@ static const struct regmap_config ad1836_regmap_config = {
.max_register = AD1836_ADC_CTRL3,
.reg_defaults = ad1836_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int ad1836_spi_probe(struct spi_device *spi)
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/ad193x.c b/sound/soc/codecs/ad193x.c
index 1d3c4d94b4ae..b93531c3a9a4 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -282,7 +282,7 @@ static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = codec_dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
if (clk_id == AD193X_SYSCLK_MCLK) {
@@ -476,7 +476,7 @@ static void ad193x_reg_default_init(struct ad193x_priv *ad193x)
static int ad193x_component_probe(struct snd_soc_component *component)
{
struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int num, ret;
/* default setting for ad193x */
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 5e777d7fd5d9..3c1ae13c1aae 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -92,7 +92,7 @@ static const struct regmap_config ad1980_regmap_config = {
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = regmap_ac97_default_volatile,
.readable_reg = ad1980_readable_reg,
diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c
index 132b9e2cca59..73f83be38f74 100644
--- a/sound/soc/codecs/adau1372-i2c.c
+++ b/sound/soc/codecs/adau1372-i2c.c
@@ -21,7 +21,7 @@ static int adau1372_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adau1372_i2c_ids[] = {
- { "adau1372", 0 },
+ { "adau1372" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids);
@@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids);
static struct i2c_driver adau1372_i2c_driver = {
.driver = {
.name = "adau1372",
+ .of_match_table = adau1372_of_match,
},
.probe = adau1372_i2c_probe,
.id_table = adau1372_i2c_ids,
diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c
index 51298e00fbd6..656bd1fabeb3 100644
--- a/sound/soc/codecs/adau1372-spi.c
+++ b/sound/soc/codecs/adau1372-spi.c
@@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(spi, adau1372_spi_id);
static struct spi_driver adau1372_spi_driver = {
.driver = {
.name = "adau1372",
+ .of_match_table = adau1372_of_match,
},
.probe = adau1372_spi_probe,
.id_table = adau1372_spi_id,
diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c
index d9bde7eb043a..fdee689cae53 100644
--- a/sound/soc/codecs/adau1372.c
+++ b/sound/soc/codecs/adau1372.c
@@ -11,6 +11,7 @@
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -1056,10 +1057,17 @@ const struct regmap_config adau1372_regmap_config = {
.reg_defaults = adau1372_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults),
.volatile_reg = adau1372_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(adau1372_regmap_config);
+const struct of_device_id adau1372_of_match[] = {
+ { .compatible = "adi,adau1372" },
+ { }
+};
+EXPORT_SYMBOL_GPL(adau1372_of_match);
+MODULE_DEVICE_TABLE(of, adau1372_of_match);
+
MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h
index a9d2c59b73a9..c55b1c24fe39 100644
--- a/sound/soc/codecs/adau1372.h
+++ b/sound/soc/codecs/adau1372.h
@@ -13,6 +13,7 @@
struct device;
+extern const struct of_device_id adau1372_of_match[];
int adau1372_probe(struct device *dev, struct regmap *regmap,
void (*switch_mode)(struct device *dev));
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index c5b087b8fffc..16b9b2658341 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -8,8 +8,10 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -18,7 +20,6 @@
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
-#include <sound/adau1373.h>
#include "adau1373.h"
#include "adau-utils.h"
@@ -30,9 +31,28 @@ struct adau1373_dai {
bool clock_provider;
};
+enum adau1373_micbias_voltage {
+ ADAU1373_MICBIAS_2_9V,
+ ADAU1373_MICBIAS_2_2V,
+ ADAU1373_MICBIAS_2_6V,
+ ADAU1373_MICBIAS_1_8V,
+};
+
+#define ADAU1373_DRC_SIZE 13
+
struct adau1373 {
struct regmap *regmap;
struct adau1373_dai dais[3];
+
+ bool input_differential[4];
+ bool lineout_differential;
+ bool lineout_ground_sense;
+
+ unsigned int num_drc;
+ u8 drc_setting[3][ADAU1373_DRC_SIZE];
+
+ enum adau1373_micbias_voltage micbias1;
+ enum adau1373_micbias_voltage micbias2;
};
#define ADAU1373_INPUT_MODE 0x00
@@ -834,7 +854,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
else
clk = "SYSCLK2";
- return strcmp(source->name, clk) == 0;
+ return snd_soc_dapm_widget_name_cmp(source, clk) == 0;
}
static int adau1373_check_src(struct snd_soc_dapm_widget *source,
@@ -1332,66 +1352,61 @@ static void adau1373_load_drc_settings(struct adau1373 *adau1373,
regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);
}
-static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
+static int adau1373_get_micbias(unsigned int val,
+ enum adau1373_micbias_voltage *micbias)
{
- switch (micbias) {
- case ADAU1373_MICBIAS_2_9V:
- case ADAU1373_MICBIAS_2_2V:
- case ADAU1373_MICBIAS_2_6V:
- case ADAU1373_MICBIAS_1_8V:
- return true;
+ switch (val) {
+ case 2900000:
+ *micbias = ADAU1373_MICBIAS_2_9V;
+ return 0;
+ case 2200000:
+ *micbias = ADAU1373_MICBIAS_2_2V;
+ return 0;
+ case 2600000:
+ *micbias = ADAU1373_MICBIAS_2_6V;
+ return 0;
+ case 1800000:
+ *micbias = ADAU1373_MICBIAS_1_8V;
+ return 0;
default:
- break;
+ return -EINVAL;
}
- return false;
}
static int adau1373_probe(struct snd_soc_component *component)
{
struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
- struct adau1373_platform_data *pdata = component->dev->platform_data;
- bool lineout_differential = false;
unsigned int val;
int i;
- if (pdata) {
- if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
- return -EINVAL;
-
- if (!adau1373_valid_micbias(pdata->micbias1) ||
- !adau1373_valid_micbias(pdata->micbias2))
- return -EINVAL;
-
- for (i = 0; i < pdata->num_drc; ++i) {
- adau1373_load_drc_settings(adau1373, i,
- pdata->drc_setting[i]);
- }
+ for (i = 0; i < adau1373->num_drc; ++i) {
+ adau1373_load_drc_settings(adau1373, i,
+ adau1373->drc_setting[i]);
+ }
- snd_soc_add_component_controls(component, adau1373_drc_controls,
- pdata->num_drc);
+ snd_soc_add_component_controls(component, adau1373_drc_controls,
+ adau1373->num_drc);
- val = 0;
- for (i = 0; i < 4; ++i) {
- if (pdata->input_differential[i])
- val |= BIT(i);
- }
- regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
+ val = 0;
+ for (i = 0; i < ARRAY_SIZE(adau1373->input_differential); ++i) {
+ if (adau1373->input_differential[i])
+ val |= BIT(i);
+ }
+ regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
- val = 0;
- if (pdata->lineout_differential)
- val |= ADAU1373_OUTPUT_CTRL_LDIFF;
- if (pdata->lineout_ground_sense)
- val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
- regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
+ val = 0;
+ if (adau1373->lineout_differential)
+ val |= ADAU1373_OUTPUT_CTRL_LDIFF;
+ if (adau1373->lineout_ground_sense)
+ val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
- lineout_differential = pdata->lineout_differential;
+ regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
- regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
- (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
- (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
- }
+ regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
+ (adau1373->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
+ (adau1373->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
- if (!lineout_differential) {
+ if (!adau1373->lineout_differential) {
snd_soc_add_component_controls(component, adau1373_lineout2_controls,
ARRAY_SIZE(adau1373_lineout2_controls));
}
@@ -1451,7 +1466,7 @@ static const struct regmap_config adau1373_regmap_config = {
.volatile_reg = adau1373_register_volatile,
.max_register = ADAU1373_SOFT_RESET,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = adau1373_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
};
@@ -1471,9 +1486,74 @@ static const struct snd_soc_component_driver adau1373_component_driver = {
.endianness = 1,
};
+static void adau1373_reset(void *reset_gpio)
+{
+ gpiod_set_value_cansleep(reset_gpio, 1);
+}
+
+static int adau1373_parse_fw(struct device *dev, struct adau1373 *adau1373)
+{
+ int ret, drc_count;
+ unsigned int val;
+
+ if (device_property_present(dev, "adi,input1-differential"))
+ adau1373->input_differential[0] = true;
+ if (device_property_present(dev, "adi,input2-differential"))
+ adau1373->input_differential[1] = true;
+ if (device_property_present(dev, "adi,input3-differential"))
+ adau1373->input_differential[2] = true;
+ if (device_property_present(dev, "adi,input4-differential"))
+ adau1373->input_differential[3] = true;
+
+ if (device_property_present(dev, "adi,lineout-differential"))
+ adau1373->lineout_differential = true;
+ if (device_property_present(dev, "adi,lineout-gnd-sense"))
+ adau1373->lineout_ground_sense = true;
+
+ ret = device_property_read_u32(dev, "adi,micbias1-microvolt", &val);
+ if (!ret) {
+ ret = adau1373_get_micbias(val, &adau1373->micbias1);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get micbias1(%u)\n", val);
+ }
+
+ ret = device_property_read_u32(dev, "adi,micbias2-microvolt", &val);
+ if (!ret) {
+ ret = adau1373_get_micbias(val, &adau1373->micbias2);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get micbias2(%u)\n", val);
+ }
+
+ drc_count = device_property_count_u8(dev, "adi,drc-settings");
+ if (drc_count < 0)
+ return 0;
+ if (drc_count % ADAU1373_DRC_SIZE != 0)
+ return dev_err_probe(dev, -EINVAL,
+ "DRC count(%u) not multiple of %u\n",
+ drc_count, ADAU1373_DRC_SIZE);
+
+ adau1373->num_drc = drc_count / ADAU1373_DRC_SIZE;
+ if (adau1373->num_drc > ARRAY_SIZE(adau1373->drc_setting))
+ return dev_err_probe(dev, -EINVAL,
+ "Too many DRC settings(%u)\n",
+ adau1373->num_drc);
+
+ ret = device_property_read_u8_array(dev, "adi,drc-settings",
+ (u8 *)&adau1373->drc_setting[0],
+ drc_count);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read DRC settings\n");
+
+ return 0;
+}
+
static int adau1373_i2c_probe(struct i2c_client *client)
{
struct adau1373 *adau1373;
+ struct gpio_desc *gpiod;
int ret;
adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL);
@@ -1485,10 +1565,33 @@ static int adau1373_i2c_probe(struct i2c_client *client)
if (IS_ERR(adau1373->regmap))
return PTR_ERR(adau1373->regmap);
- regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
+ /*
+ * If the powerdown GPIO is specified, we use it for reset. Otherwise
+ * a software reset is done.
+ */
+ gpiod = devm_gpiod_get_optional(&client->dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
+
+ if (gpiod) {
+ gpiod_set_value_cansleep(gpiod, 0);
+ fsleep(10);
+
+ ret = devm_add_action_or_reset(&client->dev, adau1373_reset,
+ gpiod);
+ if (ret)
+ return ret;
+ } else {
+ regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
+ }
dev_set_drvdata(&client->dev, adau1373);
+ ret = adau1373_parse_fw(&client->dev, adau1373);
+ if (ret)
+ return ret;
+
ret = devm_snd_soc_register_component(&client->dev,
&adau1373_component_driver,
adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
@@ -1496,14 +1599,21 @@ static int adau1373_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adau1373_i2c_id[] = {
- { "adau1373", 0 },
+ { "adau1373" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id);
+static const struct of_device_id adau1373_of_match[] = {
+ { .compatible = "adi,adau1373", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adau1373_of_match);
+
static struct i2c_driver adau1373_i2c_driver = {
.driver = {
.name = "adau1373",
+ .of_match_table = adau1373_of_match,
},
.probe = adau1373_i2c_probe,
.id_table = adau1373_i2c_id,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 8c8de3b3c901..6876462d8bdb 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -13,7 +13,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
@@ -22,7 +21,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "sigmadsp.h"
#include "adau1701.h"
@@ -326,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;
@@ -778,7 +775,7 @@ static const struct regmap_config adau1701_regmap = {
.reg_bits = 16,
.val_bits = 32,
.max_register = ADAU1701_MAX_REGISTER,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = adau1701_volatile_reg,
.reg_write = adau1701_reg_write,
.reg_read = adau1701_reg_read,
@@ -863,10 +860,10 @@ exit_regulators_disable:
}
static const struct i2c_device_id adau1701_i2c_id[] = {
- { "adau1401", 0 },
- { "adau1401a", 0 },
- { "adau1701", 0 },
- { "adau1702", 0 },
+ { "adau1401" },
+ { "adau1401a" },
+ { "adau1701" },
+ { "adau1702" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
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/adau1761.c b/sound/soc/codecs/adau1761.c
index 3ccc7acac205..a70c46dd5d76 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -621,6 +621,7 @@ static int adau1761_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct adau *adau = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -632,7 +633,7 @@ static int adau1761_set_bias_level(struct snd_soc_component *component,
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
regcache_sync(adau->regmap);
break;
case SND_SOC_BIAS_OFF:
@@ -658,7 +659,7 @@ static enum adau1761_output_mode adau1761_get_lineout_mode(
static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau1761_platform_data *pdata = component->dev->platform_data;
struct adau *adau = snd_soc_component_get_drvdata(component);
enum adau1761_digmic_jackdet_pin_mode mode;
@@ -721,7 +722,7 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component)
static int adau1761_setup_headphone_mode(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau *adau = snd_soc_component_get_drvdata(component);
struct adau1761_platform_data *pdata = component->dev->platform_data;
enum adau1761_output_mode mode;
@@ -819,7 +820,7 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg)
static int adau1761_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau1761_platform_data *pdata = component->dev->platform_data;
struct adau *adau = snd_soc_component_get_drvdata(component);
int ret;
@@ -1014,7 +1015,7 @@ const struct regmap_config adau1761_regmap_config = {
.readable_reg = adau1761_readable_register,
.volatile_reg = adau17x1_volatile_register,
.precious_reg = adau17x1_precious_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(adau1761_regmap_config);
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/adau1781.c b/sound/soc/codecs/adau1781.c
index ff6be24863bf..38cc0b6e4122 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -381,7 +381,7 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
static int adau1781_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau1781_platform_data *pdata = dev_get_platdata(component->dev);
struct adau *adau = snd_soc_component_get_drvdata(component);
int ret;
@@ -472,7 +472,7 @@ const struct regmap_config adau1781_regmap_config = {
.readable_reg = adau1781_readable_register,
.volatile_reg = adau17x1_volatile_register,
.precious_reg = adau17x1_precious_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(adau1781_regmap_config);
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index f2932713b4de..26d7eb437ad1 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -19,7 +19,7 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "sigmadsp.h"
#include "adau17x1.h"
@@ -185,8 +185,8 @@ static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
static int adau17x1_dsp_mux_enum_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_component_get_dapm(component);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau *adau = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update update = {};
@@ -230,7 +230,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct adau *adau = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int stream = e->shift_l;
@@ -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)
@@ -383,7 +383,7 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dai->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(dai->component);
struct adau *adau = snd_soc_component_get_drvdata(dai->component);
bool is_pll;
bool was_pll;
@@ -881,7 +881,7 @@ static int adau17x1_setup_firmware(struct snd_soc_component *component,
int ret;
int dspsr, dsp_run;
struct adau *adau = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
/* Check if sample rate is the same as before. If it is there is no
* point in performing the below steps as the call to
@@ -922,7 +922,7 @@ err:
int adau17x1_add_widgets(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau *adau = snd_soc_component_get_drvdata(component);
int ret;
@@ -958,7 +958,7 @@ EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
int adau17x1_add_routes(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau *adau = snd_soc_component_get_drvdata(component);
int ret;
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/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c
index 207c5c95f35a..e7e95e5d1911 100644
--- a/sound/soc/codecs/adau1977-spi.c
+++ b/sound/soc/codecs/adau1977-spi.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <sound/soc.h>
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 7a9672f94fc6..b42f35b1a603 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -473,6 +473,7 @@ static int adau1977_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret = 0;
switch (level) {
@@ -481,7 +482,7 @@ static int adau1977_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
ret = adau1977_power_enable(adau1977);
break;
case SND_SOC_BIAS_OFF:
@@ -795,7 +796,7 @@ static int adau1977_set_sysclk(struct snd_soc_component *component,
struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
unsigned int mask = 0;
unsigned int clk_src;
- unsigned int ret;
+ int ret;
if (dir != SND_SOC_CLOCK_IN)
return -EINVAL;
@@ -845,7 +846,7 @@ static int adau1977_set_sysclk(struct snd_soc_component *component,
static int adau1977_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
int ret;
@@ -991,7 +992,7 @@ const struct regmap_config adau1977_regmap_config = {
.max_register = ADAU1977_REG_DC_HPF_CAL,
.volatile_reg = adau1977_register_volatile,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = adau1977_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
};
diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c
index 73f181f7757e..f9dc8f4ef9a4 100644
--- a/sound/soc/codecs/adau7118-i2c.c
+++ b/sound/soc/codecs/adau7118-i2c.c
@@ -43,7 +43,7 @@ static const struct regmap_config adau7118_regmap_config = {
.val_bits = 8,
.reg_defaults = adau7118_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = ADAU7118_REG_RESET,
.volatile_reg = adau7118_volatile,
};
@@ -68,7 +68,7 @@ static const struct of_device_id adau7118_of_match[] = {
MODULE_DEVICE_TABLE(of, adau7118_of_match);
static const struct i2c_device_id adau7118_id[] = {
- {"adau7118", 0},
+ {"adau7118"},
{}
};
MODULE_DEVICE_TABLE(i2c, adau7118_id);
diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c
index a663d37e5776..5ddea63a6612 100644
--- a/sound/soc/codecs/adau7118.c
+++ b/sound/soc/codecs/adau7118.c
@@ -121,8 +121,10 @@ static const struct snd_soc_dapm_widget adau7118_widgets[] = {
};
static int adau7118_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct adau7118_data *st =
snd_soc_component_get_drvdata(dai->component);
@@ -167,6 +169,12 @@ static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_RIGHT_J:
st->right_j = true;
break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ ADAU7118_DATA_FMT(1));
+ break;
default:
dev_err(st->dev, "Invalid format %d",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
@@ -327,6 +335,7 @@ static int adau7118_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct adau7118_data *st = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret = 0;
dev_dbg(st->dev, "Set bias level %d\n", level);
@@ -337,8 +346,7 @@ static int adau7118_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) ==
- SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* power on */
ret = regulator_enable(st->iovdd);
if (ret)
@@ -385,8 +393,7 @@ static int adau7118_set_bias_level(struct snd_soc_component *component,
static int adau7118_component_probe(struct snd_soc_component *component)
{
struct adau7118_data *st = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret = 0;
if (st->hw_mode) {
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
index 78a317947df9..8b96c41f0354 100644
--- a/sound/soc/codecs/adav803.c
+++ b/sound/soc/codecs/adav803.c
@@ -14,7 +14,7 @@
#include "adav80x.h"
static const struct i2c_device_id adav803_id[] = {
- { "adav803", 0 },
+ { "adav803" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adav803_id);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index fcff35f26cec..8a89187f9c78 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -229,7 +229,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
return 0;
}
- return strcmp(source->name, clk) == 0;
+ return snd_soc_dapm_widget_name_cmp(source, clk) == 0;
}
static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
@@ -314,7 +314,7 @@ static int adav80x_set_deemph(struct snd_soc_component *component)
static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
@@ -329,7 +329,7 @@ static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = adav80x->deemph;
@@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_component *component,
unsigned int freq, int dir)
{
struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (dir == SND_SOC_CLOCK_IN) {
switch (clk_id) {
@@ -622,7 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_component *component,
static int adav80x_set_pll(struct snd_soc_component *component, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
unsigned int pll_ctrl1 = 0;
unsigned int pll_ctrl2 = 0;
@@ -802,7 +802,7 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
static int adav80x_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
/* Force PLLs on for SYSCLK output */
@@ -870,7 +870,7 @@ const struct regmap_config adav80x_regmap_config = {
.max_register = ADAV80X_PLL_OUTE,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = adav80x_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
};
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index ce99f30b4613..a33cb329865c 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -5,10 +5,10 @@
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/asoundef.h>
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
index e34e5533765c..23e868e4e3fb 100644
--- a/sound/soc/codecs/ak4118.c
+++ b/sound/soc/codecs/ak4118.c
@@ -8,8 +8,7 @@
#include <linux/i2c.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -396,7 +395,7 @@ MODULE_DEVICE_TABLE(of, ak4118_of_match);
#endif
static const struct i2c_device_id ak4118_id_table[] = {
- { "ak4118", 0 },
+ { "ak4118" },
{}
};
MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c
index f287acb98646..452559d8c97b 100644
--- a/sound/soc/codecs/ak4375.c
+++ b/sound/soc/codecs/ak4375.c
@@ -9,7 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
@@ -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 77678f85ad94..f0b465f9ded5 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -9,8 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -46,7 +45,6 @@ struct ak4458_priv {
const struct ak4458_drvdata *drvdata;
struct device *dev;
struct regmap *regmap;
- struct gpio_desc *reset_gpiod;
struct reset_control *reset;
struct gpio_desc *mute_gpiod;
int digfil; /* SSLOW, SD, SLOW bits */
@@ -189,7 +187,7 @@ static const struct soc_enum ak4458_dif_enum =
static int get_digfil(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = ak4458->digfil;
@@ -200,7 +198,7 @@ static int get_digfil(struct snd_kcontrol *kcontrol,
static int set_digfil(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
int num;
@@ -588,13 +586,9 @@ static const struct snd_pcm_hw_constraint_list ak4458_rate_constraints = {
static int ak4458_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- int ret;
-
- ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &ak4458_rate_constraints);
-
- return ret;
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &ak4458_rate_constraints);
}
static const struct snd_soc_dai_ops ak4458_dai_ops = {
@@ -632,10 +626,7 @@ static struct snd_soc_dai_driver ak4497_dai = {
static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
{
- if (ak4458->reset_gpiod) {
- gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
- usleep_range(1000, 2000);
- } else if (!IS_ERR_OR_NULL(ak4458->reset)) {
+ if (!IS_ERR_OR_NULL(ak4458->reset)) {
if (active)
reset_control_assert(ak4458->reset);
else
@@ -644,8 +635,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);
@@ -661,7 +651,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;
@@ -683,7 +673,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,
@@ -732,9 +721,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)
@@ -759,11 +747,6 @@ static int ak4458_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(ak4458->reset))
return PTR_ERR(ak4458->reset);
- ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(ak4458->reset_gpiod))
- return PTR_ERR(ak4458->reset_gpiod);
-
ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute",
GPIOD_OUT_LOW);
if (IS_ERR(ak4458->mute_gpiod))
@@ -815,7 +798,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/ak4535.c b/sound/soc/codecs/ak4535.c
index 904bf91090aa..aadc46a47280 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -430,7 +430,7 @@ static int ak4535_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ak4535_i2c_id[] = {
- { "ak4535", 0 },
+ { "ak4535" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index ad56caec9dac..de9e43185555 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -99,7 +99,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -753,7 +753,7 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
-static u64 ak4613_dai_formats =
+static const u64 ak4613_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
@@ -840,14 +840,14 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
/* Input 1 - 2 */
for (i = 0; i < 2; i++) {
snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
- if (!of_get_property(np, prop, NULL))
+ if (!of_property_read_bool(np, prop))
priv->ic |= 1 << i;
}
/* Output 1 - 6 */
for (i = 0; i < 6; i++) {
snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
- if (!of_get_property(np, prop, NULL))
+ if (!of_property_read_bool(np, prop))
priv->oc |= 1 << i;
}
@@ -880,20 +880,11 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
static int ak4613_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
- struct device_node *np = dev->of_node;
const struct regmap_config *regmap_cfg;
struct regmap *regmap;
struct ak4613_priv *priv;
- regmap_cfg = NULL;
- if (np)
- regmap_cfg = of_device_get_match_data(dev);
- else {
- const struct i2c_device_id *id =
- i2c_match_id(ak4613_i2c_id, i2c);
- regmap_cfg = (const struct regmap_config *)id->driver_data;
- }
-
+ regmap_cfg = i2c_get_match_data(i2c);
if (!regmap_cfg)
return -EINVAL;
diff --git a/sound/soc/codecs/ak4619.c b/sound/soc/codecs/ak4619.c
new file mode 100644
index 000000000000..daf6e15b7077
--- /dev/null
+++ b/sound/soc/codecs/ak4619.c
@@ -0,0 +1,912 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ak4619.c -- Asahi Kasei ALSA SoC Audio driver
+ *
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ * Khanh Le <khanh.le.xr@renesas.com>
+ *
+ * Based on ak4613.c by Kuninori Morimoto
+ * Based on da7213.c by Adam Thomson
+ * Based on ak4641.c by Harald Welte
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+/*
+ * Registers
+ */
+
+#define PWR_MGMT 0x00 /* Power Management */
+#define AU_IFF1 0x01 /* Audio I/F Format */
+#define AU_IFF2 0x02 /* Audio I/F Format (Extended) */
+#define SYS_CLK 0x03 /* System Clock Setting */
+#define MIC_AMP1 0x04 /* MIC AMP Gain 1 */
+#define MIC_AMP2 0x05 /* MIC AMP Gain 2 */
+#define LADC1 0x06 /* ADC1 Lch Digital Volume */
+#define RADC1 0x07 /* ADC1 Rch Digital Volume */
+#define LADC2 0x08 /* ADC2 Lch Digital Volume */
+#define RADC2 0x09 /* ADC2 Rch Digital Volume */
+#define ADC_DF 0x0a /* ADC Digital Filter Setting */
+#define ADC_AI 0x0b /* ADC Analog Input Setting */
+#define ADC_MHPF 0x0D /* ADC Mute & HPF Control */
+#define LDAC1 0x0E /* DAC1 Lch Digital Volume */
+#define RDAC1 0x0F /* DAC1 Rch Digital Volume */
+#define LDAC2 0x10 /* DAC2 Lch Digital Volume */
+#define RDAC2 0x11 /* DAC2 Rch Digital Volume */
+#define DAC_IS 0x12 /* DAC Input Select Setting */
+#define DAC_DEMP 0x13 /* DAC De-Emphasis Setting */
+#define DAC_MF 0x14 /* DAC Mute & Filter Setting */
+
+/*
+ * Bit fields
+ */
+
+/* Power Management */
+#define PMAD2 BIT(5)
+#define PMAD1 BIT(4)
+#define PMDA2 BIT(2)
+#define PMDA1 BIT(1)
+#define RSTN BIT(0)
+
+/* Audio_I/F Format */
+#define DCF_STEREO_I2S (0x0 << 4)
+#define DCF_STEREO_MSB (0x5 << 4)
+#define DCF_PCM_SF (0x6 << 4)
+#define DCF_PCM_LF (0x7 << 4)
+#define DSL_32 (0x3 << 2)
+#define DCF_MASK (0x7 << 4)
+#define DSL_MASK (0x3 << 2)
+#define BCKP BIT(1)
+
+/* Audio_I/F Format (Extended) */
+#define DIDL_24 (0x0 << 2)
+#define DIDL_20 (0x1 << 2)
+#define DIDL_16 (0x2 << 2)
+#define DIDL_32 (0x3 << 2)
+#define DODL_24 (0x0 << 0)
+#define DODL_20 (0x1 << 0)
+#define DODL_16 (0x2 << 0)
+#define DIDL_MASK (0x3 << 2)
+#define DODL_MASK (0x3 << 0)
+#define SLOT BIT(4)
+
+/* System Clock Setting */
+#define FS_MASK 0x7
+
+/* MIC AMP Gain */
+#define MGNL_SHIFT 4
+#define MGNR_SHIFT 0
+#define MGN_MAX 0xB
+
+/* ADC Digital Volume */
+#define VOLAD_SHIFT 0
+#define VOLAD_MAX 0xFF
+
+/* ADC Digital Filter Setting */
+#define AD1SL_SHIFT 0
+#define AD2SL_SHIFT 4
+
+/* Analog Input Select */
+#define AD1LSEL_SHIFT 6
+#define AD1RSEL_SHIFT 4
+#define AD2LSEL_SHIFT 2
+#define AD2RSEL_SHIFT 0
+
+/* ADC Mute & HPF Control */
+#define ATSPAD_SHIFT 7
+#define AD1MUTE_SHIFT 5
+#define AD2MUTE_SHIFT 6
+#define AD1MUTE_MAX 1
+#define AD2MUTE_MAX 1
+#define AD1MUTE_EN BIT(5)
+#define AD2MUTE_EN BIT(6)
+#define AD1HPFN_SHIFT 1
+#define AD1HPFN_MAX 1
+#define AD2HPFN_SHIFT 2
+#define AD2HPFN_MAX 1
+
+/* DAC Digital Volume */
+#define VOLDA_SHIFT 0
+#define VOLDA_MAX 0xFF
+
+/* DAC Input Select Setting */
+#define DAC1SEL_SHIFT 0
+#define DAC2SEL_SHIFT 2
+
+/* DAC De-Emphasis Setting */
+#define DEM1_32000 (0x3 << 0)
+#define DEM1_44100 (0x0 << 0)
+#define DEM1_48000 (0x2 << 0)
+#define DEM1_OFF (0x1 << 0)
+#define DEM2_32000 (0x3 << 2)
+#define DEM2_44100 (0x0 << 2)
+#define DEM2_48000 (0x2 << 2)
+#define DEM2_OFF (0x1 << 2)
+#define DEM1_MASK (0x3 << 0)
+#define DEM2_MASK (0x3 << 2)
+#define DEM1_SHIFT 0
+#define DEM2_SHIFT 2
+
+/* DAC Mute & Filter Setting */
+#define DA1MUTE_SHIFT 4
+#define DA1MUTE_MAX 1
+#define DA2MUTE_SHIFT 5
+#define DA2MUTE_MAX 1
+#define DA1MUTE_EN BIT(4)
+#define DA2MUTE_EN BIT(5)
+#define ATSPDA_SHIFT 7
+#define DA1SL_SHIFT 0
+#define DA2SL_SHIFT 2
+
+/* Codec private data */
+struct ak4619_priv {
+ struct regmap *regmap;
+ struct snd_pcm_hw_constraint_list constraint;
+ int deemph_en;
+ unsigned int playback_rate;
+ unsigned int sysclk;
+};
+
+/*
+ * DAC Volume
+ *
+ * max : 0x00 : +12.0 dB
+ * ( 0.5 dB step )
+ * min : 0xFE : -115.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -11550, 50, 1);
+
+/*
+ * MIC Volume
+ *
+ * max : 0x0B : +27.0 dB
+ * ( 3 dB step )
+ * min: 0x00 : -6.0 dB
+ */
+static const DECLARE_TLV_DB_SCALE(mic_tlv, -600, 300, 0);
+
+/*
+ * ADC Volume
+ *
+ * max : 0x00 : +24.0 dB
+ * ( 0.5 dB step )
+ * min : 0xFE : -103.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1);
+
+/* ADC & DAC Volume Level Transition Time select */
+static const char * const ak4619_vol_trans_txt[] = {
+ "4/fs", "16/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_vol_trans, ADC_MHPF, ATSPAD_SHIFT, ak4619_vol_trans_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_vol_trans, DAC_MF, ATSPDA_SHIFT, ak4619_vol_trans_txt);
+
+/* ADC Digital Filter select */
+static const char * const ak4619_adc_digi_fil_txt[] = {
+ "Sharp Roll-Off Filter",
+ "Slow Roll-Off Filter",
+ "Short Delay Sharp Roll-Off Filter",
+ "Short Delay Slow Roll-Off Filter",
+ "Voice Filter"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_1_digi_fil, ADC_DF, AD1SL_SHIFT, ak4619_adc_digi_fil_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_adc_2_digi_fil, ADC_DF, AD2SL_SHIFT, ak4619_adc_digi_fil_txt);
+
+/* DAC De-Emphasis Filter select */
+static const char * const ak4619_dac_de_emp_txt[] = {
+ "44.1kHz", "OFF", "48kHz", "32kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_de_emp, DAC_DEMP, DEM1_SHIFT, ak4619_dac_de_emp_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_de_emp, DAC_DEMP, DEM2_SHIFT, ak4619_dac_de_emp_txt);
+
+/* DAC Digital Filter select */
+static const char * const ak4619_dac_digi_fil_txt[] = {
+ "Sharp Roll-Off Filter",
+ "Slow Roll-Off Filter",
+ "Short Delay Sharp Roll-Off Filter",
+ "Short Delay Slow Roll-Off Filter"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_digi_fil, DAC_MF, DA1SL_SHIFT, ak4619_dac_digi_fil_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_digi_fil, DAC_MF, DA2SL_SHIFT, ak4619_dac_digi_fil_txt);
+
+/*
+ * Control functions
+ */
+
+static void ak4619_set_deemph(struct snd_soc_component *component)
+{
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+ u8 dem = 0;
+
+ if (!ak4619->deemph_en)
+ return;
+
+ switch (ak4619->playback_rate) {
+ case 32000:
+ dem |= DEM1_32000 | DEM2_32000;
+ break;
+ case 44100:
+ dem |= DEM1_44100 | DEM2_44100;
+ break;
+ case 48000:
+ dem |= DEM1_48000 | DEM2_48000;
+ break;
+ default:
+ dem |= DEM1_OFF | DEM2_OFF;
+ break;
+ }
+ snd_soc_component_update_bits(component, DAC_DEMP, DEM1_MASK | DEM2_MASK, dem);
+}
+
+static int ak4619_put_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+ int deemph_en = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ switch (deemph_en) {
+ case 0:
+ case 1:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ak4619->deemph_en != deemph_en)
+ ret = 1; /* The value changed */
+
+ ak4619->deemph_en = deemph_en;
+ ak4619_set_deemph(component);
+
+ return ret;
+}
+
+static int ak4619_get_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = ak4619->deemph_en;
+
+ return 0;
+};
+
+/*
+ * KControls
+ */
+static const struct snd_kcontrol_new ak4619_snd_controls[] = {
+
+ /* Volume controls */
+ SOC_DOUBLE_R_TLV("DAC 1 Volume", LDAC1, RDAC1, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC 2 Volume", LDAC2, RDAC2, VOLDA_SHIFT, VOLDA_MAX, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("ADC 1 Volume", LADC1, RADC1, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv),
+ SOC_DOUBLE_R_TLV("ADC 2 Volume", LADC2, RADC2, VOLAD_SHIFT, VOLAD_MAX, 1, adc_tlv),
+
+ SOC_DOUBLE_TLV("Mic 1 Volume", MIC_AMP1, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv),
+ SOC_DOUBLE_TLV("Mic 2 Volume", MIC_AMP2, MGNL_SHIFT, MGNR_SHIFT, MGN_MAX, 0, mic_tlv),
+
+ /* Volume Level Transition Time controls */
+ SOC_ENUM("ADC Volume Level Transition Time", ak4619_adc_vol_trans),
+ SOC_ENUM("DAC Volume Level Transition Time", ak4619_dac_vol_trans),
+
+ /* Mute controls */
+ SOC_SINGLE("DAC 1 Switch", DAC_MF, DA1MUTE_SHIFT, DA1MUTE_MAX, 1),
+ SOC_SINGLE("DAC 2 Switch", DAC_MF, DA2MUTE_SHIFT, DA2MUTE_MAX, 1),
+
+ SOC_SINGLE("ADC 1 Switch", ADC_MHPF, AD1MUTE_SHIFT, AD1MUTE_MAX, 1),
+ SOC_SINGLE("ADC 2 Switch", ADC_MHPF, AD2MUTE_SHIFT, AD2MUTE_MAX, 1),
+
+ /* Filter controls */
+ SOC_ENUM("ADC 1 Digital Filter", ak4619_adc_1_digi_fil),
+ SOC_ENUM("ADC 2 Digital Filter", ak4619_adc_2_digi_fil),
+
+ SOC_SINGLE("ADC 1 HPF", ADC_MHPF, AD1HPFN_SHIFT, AD1HPFN_MAX, 1),
+ SOC_SINGLE("ADC 2 HPF", ADC_MHPF, AD2HPFN_SHIFT, AD2HPFN_MAX, 1),
+
+ SOC_ENUM("DAC 1 De-Emphasis Filter", ak4619_dac_1_de_emp),
+ SOC_ENUM("DAC 2 De-Emphasis Filter", ak4619_dac_2_de_emp),
+
+ SOC_ENUM("DAC 1 Digital Filter", ak4619_dac_1_digi_fil),
+ SOC_ENUM("DAC 2 Digital Filter", ak4619_dac_2_digi_fil),
+
+ SOC_SINGLE_BOOL_EXT("Playback De-Emphasis Switch", 0, ak4619_get_deemph, ak4619_put_deemph),
+};
+
+/*
+ * DAPM
+ */
+
+/* Analog input mode */
+static const char * const ak4619_analog_in_txt[] = {
+ "Differential", "Single-Ended1", "Single-Ended2", "Pseudo Differential"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_left_in, ADC_AI, AD1LSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_1_right_in, ADC_AI, AD1RSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_left_in, ADC_AI, AD2LSEL_SHIFT, ak4619_analog_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_ad_2_right_in, ADC_AI, AD2RSEL_SHIFT, ak4619_analog_in_txt);
+
+static const struct snd_kcontrol_new ak4619_ad_1_left_in_mux =
+ SOC_DAPM_ENUM("Analog Input 1 Left MUX", ak4619_ad_1_left_in);
+static const struct snd_kcontrol_new ak4619_ad_1_right_in_mux =
+ SOC_DAPM_ENUM("Analog Input 1 Right MUX", ak4619_ad_1_right_in);
+static const struct snd_kcontrol_new ak4619_ad_2_left_in_mux =
+ SOC_DAPM_ENUM("Analog Input 2 Left MUX", ak4619_ad_2_left_in);
+static const struct snd_kcontrol_new ak4619_ad_2_right_in_mux =
+ SOC_DAPM_ENUM("Analog Input 2 Right MUX", ak4619_ad_2_right_in);
+
+/* DAC source mux */
+static const char * const ak4619_dac_in_txt[] = {
+ "SDIN1", "SDIN2", "SDOUT1", "SDOUT2"
+};
+
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_1_in, DAC_IS, DAC1SEL_SHIFT, ak4619_dac_in_txt);
+static SOC_ENUM_SINGLE_DECL(ak4619_dac_2_in, DAC_IS, DAC2SEL_SHIFT, ak4619_dac_in_txt);
+
+static const struct snd_kcontrol_new ak4619_dac_1_in_mux =
+ SOC_DAPM_ENUM("DAC 1 Source MUX", ak4619_dac_1_in);
+static const struct snd_kcontrol_new ak4619_dac_2_in_mux =
+ SOC_DAPM_ENUM("DAC 2 Source MUX", ak4619_dac_2_in);
+
+static const struct snd_soc_dapm_widget ak4619_dapm_widgets[] = {
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC1", NULL, PWR_MGMT, 1, 0),
+ SND_SOC_DAPM_DAC("DAC2", NULL, PWR_MGMT, 2, 0),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC1", NULL, PWR_MGMT, 4, 0),
+ SND_SOC_DAPM_ADC("ADC2", NULL, PWR_MGMT, 5, 0),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("AOUT1L"),
+ SND_SOC_DAPM_OUTPUT("AOUT2L"),
+
+ SND_SOC_DAPM_OUTPUT("AOUT1R"),
+ SND_SOC_DAPM_OUTPUT("AOUT2R"),
+
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN4L"),
+ SND_SOC_DAPM_INPUT("AIN5L"),
+
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("AIN4R"),
+ SND_SOC_DAPM_INPUT("AIN5R"),
+
+ SND_SOC_DAPM_INPUT("MIC1L"),
+ SND_SOC_DAPM_INPUT("MIC1R"),
+ SND_SOC_DAPM_INPUT("MIC2L"),
+ SND_SOC_DAPM_INPUT("MIC2R"),
+
+ /* DAI */
+ SND_SOC_DAPM_AIF_IN("SDIN1", "Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SDIN2", "Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SDOUT1", "Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SDOUT2", "Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* MUXs for Mic PGA source selection */
+ SND_SOC_DAPM_MUX("Analog Input 1 Left MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_left_in_mux),
+ SND_SOC_DAPM_MUX("Analog Input 1 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_1_right_in_mux),
+ SND_SOC_DAPM_MUX("Analog Input 2 Left MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_left_in_mux),
+ SND_SOC_DAPM_MUX("Analog Input 2 Right MUX", SND_SOC_NOPM, 0, 0, &ak4619_ad_2_right_in_mux),
+
+ /* MUXs for DAC source selection */
+ SND_SOC_DAPM_MUX("DAC 1 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_1_in_mux),
+ SND_SOC_DAPM_MUX("DAC 2 Source MUX", SND_SOC_NOPM, 0, 0, &ak4619_dac_2_in_mux),
+};
+
+static const struct snd_soc_dapm_route ak4619_intercon[] = {
+ /* Dest Connecting Widget Source */
+
+ /* Output path */
+ {"AOUT1L", NULL, "DAC1"},
+ {"AOUT2L", NULL, "DAC2"},
+
+ {"AOUT1R", NULL, "DAC1"},
+ {"AOUT2R", NULL, "DAC2"},
+
+ {"DAC1", NULL, "DAC 1 Source MUX"},
+ {"DAC2", NULL, "DAC 2 Source MUX"},
+
+ {"DAC 1 Source MUX", "SDIN1", "SDIN1"},
+ {"DAC 1 Source MUX", "SDIN2", "SDIN2"},
+ {"DAC 1 Source MUX", "SDOUT1", "SDOUT1"},
+ {"DAC 1 Source MUX", "SDOUT2", "SDOUT2"},
+
+ {"DAC 2 Source MUX", "SDIN1", "SDIN1"},
+ {"DAC 2 Source MUX", "SDIN2", "SDIN2"},
+ {"DAC 2 Source MUX", "SDOUT1", "SDOUT1"},
+ {"DAC 2 Source MUX", "SDOUT2", "SDOUT2"},
+
+ /* Input path */
+ {"SDOUT1", NULL, "ADC1"},
+ {"SDOUT2", NULL, "ADC2"},
+
+ {"ADC1", NULL, "Analog Input 1 Left MUX"},
+ {"ADC1", NULL, "Analog Input 1 Right MUX"},
+
+ {"ADC2", NULL, "Analog Input 2 Left MUX"},
+ {"ADC2", NULL, "Analog Input 2 Right MUX"},
+
+ {"Analog Input 1 Left MUX", "Differential", "MIC1L"},
+ {"Analog Input 1 Left MUX", "Single-Ended1", "MIC1L"},
+ {"Analog Input 1 Left MUX", "Single-Ended2", "MIC1L"},
+ {"Analog Input 1 Left MUX", "Pseudo Differential", "MIC1L"},
+
+ {"Analog Input 1 Right MUX", "Differential", "MIC1R"},
+ {"Analog Input 1 Right MUX", "Single-Ended1", "MIC1R"},
+ {"Analog Input 1 Right MUX", "Single-Ended2", "MIC1R"},
+ {"Analog Input 1 Right MUX", "Pseudo Differential", "MIC1R"},
+
+ {"Analog Input 2 Left MUX", "Differential", "MIC2L"},
+ {"Analog Input 2 Left MUX", "Single-Ended1", "MIC2L"},
+ {"Analog Input 2 Left MUX", "Single-Ended2", "MIC2L"},
+ {"Analog Input 2 Left MUX", "Pseudo Differential", "MIC2L"},
+
+ {"Analog Input 2 Right MUX", "Differential", "MIC2R"},
+ {"Analog Input 2 Right MUX", "Single-Ended1", "MIC2R"},
+ {"Analog Input 2 Right MUX", "Single-Ended2", "MIC2R"},
+ {"Analog Input 2 Right MUX", "Pseudo Differential", "MIC2R"},
+
+ {"MIC1L", NULL, "AIN1L"},
+ {"MIC1L", NULL, "AIN2L"},
+
+ {"MIC1R", NULL, "AIN1R"},
+ {"MIC1R", NULL, "AIN2R"},
+
+ {"MIC2L", NULL, "AIN4L"},
+ {"MIC2L", NULL, "AIN5L"},
+
+ {"MIC2R", NULL, "AIN4R"},
+ {"MIC2R", NULL, "AIN5R"},
+};
+
+static const struct reg_default ak4619_reg_defaults[] = {
+ { PWR_MGMT, 0x00 },
+ { AU_IFF1, 0x0C },
+ { AU_IFF2, 0x0C },
+ { SYS_CLK, 0x00 },
+ { MIC_AMP1, 0x22 },
+ { MIC_AMP2, 0x22 },
+ { LADC1, 0x30 },
+ { RADC1, 0x30 },
+ { LADC2, 0x30 },
+ { RADC2, 0x30 },
+ { ADC_DF, 0x00 },
+ { ADC_AI, 0x00 },
+ { ADC_MHPF, 0x00 },
+ { LDAC1, 0x18 },
+ { RDAC1, 0x18 },
+ { LDAC2, 0x18 },
+ { RDAC2, 0x18 },
+ { DAC_IS, 0x04 },
+ { DAC_DEMP, 0x05 },
+ { DAC_MF, 0x0A },
+};
+
+static int ak4619_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ u8 pwr_ctrl = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ pwr_ctrl |= RSTN;
+ fallthrough;
+ case SND_SOC_BIAS_PREPARE:
+ pwr_ctrl |= PMAD1 | PMAD2 | PMDA1 | PMDA2;
+ fallthrough;
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_OFF:
+ default:
+ break;
+ }
+
+ snd_soc_component_write(component, PWR_MGMT, pwr_ctrl);
+
+ return 0;
+}
+
+static int ak4619_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+ unsigned int width;
+ unsigned int rate;
+ unsigned int fs;
+ bool is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u8 dai_ctrl = 0;
+ u8 clk_mode = 0;
+
+ width = params_width(params);
+ switch (width) {
+ case 16:
+ dai_ctrl |= is_play ? DIDL_16 : DODL_16;
+ break;
+ case 20:
+ dai_ctrl |= is_play ? DIDL_20 : DODL_20;
+ break;
+ case 24:
+ dai_ctrl |= is_play ? DIDL_24 : DODL_24;
+ break;
+ case 32:
+ if (is_play)
+ dai_ctrl |= DIDL_32;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rate = params_rate(params);
+ if (rate)
+ fs = ak4619->sysclk / rate;
+ else
+ return -EINVAL;
+
+ switch (rate) {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ switch (fs) {
+ case 256:
+ clk_mode |= (0x0 << 0);
+ break;
+ case 384:
+ clk_mode |= (0x2 << 0);
+ break;
+ case 512:
+ clk_mode |= (0x3 << 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 64000:
+ case 88200:
+ case 96000:
+ if (fs == 256)
+ clk_mode |= (0x1 << 0);
+ else
+ return -EINVAL;
+ break;
+ case 176400:
+ case 192000:
+ if (fs == 128)
+ clk_mode |= (0x4 << 0);
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, SYS_CLK, FS_MASK, clk_mode);
+ snd_soc_component_update_bits(component, AU_IFF2,
+ is_play ? DIDL_MASK : DODL_MASK, dai_ctrl);
+
+ if (is_play) {
+ ak4619->playback_rate = rate;
+ ak4619_set_deemph(component);
+ }
+
+ return 0;
+}
+
+static int ak4619_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ u8 dai_fmt1 = 0;
+ u8 dai_fmt2 = 0;
+
+ /* Set clock normal/inverted */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ dai_fmt1 |= BCKP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ case SND_SOC_DAIFMT_IB_IF:
+ default:
+ return -EINVAL;
+ }
+
+ /* Only Stereo modes are supported */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dai_fmt1 |= DCF_STEREO_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dai_fmt1 |= DCF_STEREO_MSB;
+ break;
+ case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
+ dai_fmt1 |= DCF_PCM_SF;
+ dai_fmt2 |= SLOT;
+ break;
+ case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+ dai_fmt1 |= DCF_PCM_LF;
+ dai_fmt2 |= SLOT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Only slave mode is support */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* By default only 64 BICK per LRCLK is supported */
+ dai_fmt1 |= DSL_32;
+
+ snd_soc_component_update_bits(component, AU_IFF1, DCF_MASK |
+ DSL_MASK | BCKP, dai_fmt1);
+ snd_soc_component_update_bits(component, AU_IFF2, SLOT, dai_fmt2);
+
+ return 0;
+}
+
+static int ak4619_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+ ak4619->sysclk = freq;
+
+ return 0;
+}
+
+static int ak4619_dai_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+
+ snd_soc_component_update_bits(component, DAC_MF, DA1MUTE_EN, mute ? DA1MUTE_EN : 0);
+ snd_soc_component_update_bits(component, DAC_MF, DA2MUTE_EN, mute ? DA2MUTE_EN : 0);
+
+ return 0;
+}
+
+static void ak4619_hw_constraints(struct ak4619_priv *ak4619,
+ struct snd_pcm_runtime *runtime)
+{
+ struct snd_pcm_hw_constraint_list *constraint = &ak4619->constraint;
+ int ak4619_rate_mask = 0;
+ unsigned int fs;
+ int i;
+ static const unsigned int ak4619_sr[] = {
+ 8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 64000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+ };
+
+ /*
+ * [8kHz - 48kHz] : 256fs, 384fs or 512fs
+ * [64kHz - 96kHz] : 256fs
+ * [176.4kHz, 192kHz] : 128fs
+ */
+
+ for (i = 0; i < ARRAY_SIZE(ak4619_sr); i++) {
+ fs = ak4619->sysclk / ak4619_sr[i];
+
+ switch (fs) {
+ case 512:
+ case 384:
+ case 256:
+ ak4619_rate_mask |= (1 << i);
+ break;
+ case 128:
+ switch (i) {
+ case (ARRAY_SIZE(ak4619_sr) - 1):
+ case (ARRAY_SIZE(ak4619_sr) - 2):
+ ak4619_rate_mask |= (1 << i);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ constraint->list = ak4619_sr;
+ constraint->mask = ak4619_rate_mask;
+ constraint->count = ARRAY_SIZE(ak4619_sr);
+
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, constraint);
+};
+
+#define PLAYBACK_MODE 0
+#define CAPTURE_MODE 1
+
+static int ak4619_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ak4619_priv *ak4619 = snd_soc_component_get_drvdata(component);
+
+ ak4619_hw_constraints(ak4619, substream->runtime);
+
+ return 0;
+}
+
+static u64 ak4619_dai_formats[] = {
+ /*
+ * Select below from Sound Card, not here
+ * SND_SOC_DAIFMT_CBC_CFC
+ * SND_SOC_DAIFMT_CBP_CFP
+ */
+
+ /* First Priority */
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J,
+
+ /* Second Priority */
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
+static const struct snd_soc_dai_ops ak4619_dai_ops = {
+ .startup = ak4619_dai_startup,
+ .set_sysclk = ak4619_dai_set_sysclk,
+ .set_fmt = ak4619_dai_set_fmt,
+ .hw_params = ak4619_dai_hw_params,
+ .mute_stream = ak4619_dai_mute,
+ .auto_selectable_formats = ak4619_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(ak4619_dai_formats),
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4619 = {
+ .set_bias_level = ak4619_set_bias_level,
+ .controls = ak4619_snd_controls,
+ .num_controls = ARRAY_SIZE(ak4619_snd_controls),
+ .dapm_widgets = ak4619_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ak4619_dapm_widgets),
+ .dapm_routes = ak4619_intercon,
+ .num_dapm_routes = ARRAY_SIZE(ak4619_intercon),
+ .idle_bias_on = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config ak4619_regmap_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x14,
+ .reg_defaults = ak4619_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ak4619_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct of_device_id ak4619_of_match[] = {
+ { .compatible = "asahi-kasei,ak4619", .data = &ak4619_regmap_cfg },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ak4619_of_match);
+
+static const struct i2c_device_id ak4619_i2c_id[] = {
+ { "ak4619", (kernel_ulong_t)&ak4619_regmap_cfg },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4619_i2c_id);
+
+#define AK4619_RATES SNDRV_PCM_RATE_8000_192000
+
+#define AK4619_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AK4619_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver ak4619_dai = {
+ .name = "ak4619-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AK4619_RATES,
+ .formats = AK4619_DAC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AK4619_RATES,
+ .formats = AK4619_ADC_FORMATS,
+ },
+ .ops = &ak4619_dai_ops,
+ .symmetric_rate = 1,
+};
+
+static int ak4619_i2c_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct ak4619_priv *ak4619;
+ int ret;
+
+ ak4619 = devm_kzalloc(dev, sizeof(*ak4619), GFP_KERNEL);
+ if (!ak4619)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, ak4619);
+
+ ak4619->regmap = devm_regmap_init_i2c(i2c, &ak4619_regmap_cfg);
+ if (IS_ERR(ak4619->regmap)) {
+ ret = PTR_ERR(ak4619->regmap);
+ dev_err(dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(dev, &soc_component_dev_ak4619,
+ &ak4619_dai, 1);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register ak4619 component: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct i2c_driver ak4619_i2c_driver = {
+ .driver = {
+ .name = "ak4619-codec",
+ .of_match_table = ak4619_of_match,
+ },
+ .probe = ak4619_i2c_probe,
+ .id_table = ak4619_i2c_id,
+};
+module_i2c_driver(ak4619_i2c_driver);
+
+MODULE_DESCRIPTION("SoC AK4619 driver");
+MODULE_AUTHOR("Khanh Le <khanh.le.xr@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 5b7df2f0dd6a..9db8cdb26d33 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -91,7 +91,7 @@ static int ak4641_set_deemph(struct snd_soc_component *component)
static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
int deemph = ucontrol->value.integer.value[0];
@@ -106,7 +106,7 @@ static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = ak4641->deemph;
@@ -415,6 +415,7 @@ static int ak4641_mute(struct snd_soc_dai *dai, int mute, int direction)
static int ak4641_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
struct ak4641_platform_data *pdata = component->dev->platform_data;
int ret;
@@ -429,7 +430,7 @@ static int ak4641_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, AK4641_DAC, 0x20, 0x20);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
if (pdata && gpio_is_valid(pdata->gpio_power))
gpio_set_value(pdata->gpio_power, 1);
mdelay(1);
@@ -619,7 +620,7 @@ static void ak4641_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id ak4641_i2c_id[] = {
- { "ak4641", 0 },
+ { "ak4641" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 2a8984c1fa9c..fe035d2fc913 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -24,7 +24,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <sound/soc.h>
@@ -628,37 +628,23 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev)
#define ak4642_of_parse_mcko(d) 0
#endif
-static const struct of_device_id ak4642_of_match[];
-static const struct i2c_device_id ak4642_i2c_id[];
static int ak4642_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
- struct device_node *np = dev->of_node;
- const struct ak4642_drvdata *drvdata = NULL;
+ const struct ak4642_drvdata *drvdata;
struct regmap *regmap;
struct ak4642_priv *priv;
struct clk *mcko = NULL;
- if (np) {
- const struct of_device_id *of_id;
-
+ if (dev_fwnode(dev)) {
mcko = ak4642_of_parse_mcko(dev);
if (IS_ERR(mcko))
mcko = NULL;
-
- of_id = of_match_device(ak4642_of_match, dev);
- if (of_id)
- drvdata = of_id->data;
- } else {
- const struct i2c_device_id *id =
- i2c_match_id(ak4642_i2c_id, i2c);
- drvdata = (const struct ak4642_drvdata *)id->driver_data;
}
- if (!drvdata) {
- dev_err(dev, "Unknown device type\n");
- return -EINVAL;
- }
+ drvdata = i2c_get_match_data(i2c);
+ if (!drvdata)
+ return dev_err_probe(dev, -EINVAL, "Unknown device type\n");
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -681,7 +667,7 @@ static const struct of_device_id ak4642_of_match[] = {
{ .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata},
{ .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata},
{ .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata},
- {},
+ {}
};
MODULE_DEVICE_TABLE(of, ak4642_of_match);
@@ -689,7 +675,7 @@ static const struct i2c_device_id ak4642_i2c_id[] = {
{ "ak4642", (kernel_ulong_t)&ak4642_drvdata },
{ "ak4643", (kernel_ulong_t)&ak4643_drvdata },
{ "ak4648", (kernel_ulong_t)&ak4648_drvdata },
- { }
+ {}
};
MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 5b849b390c2a..d545aa2e0a39 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -646,7 +646,7 @@ static int ak4671_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ak4671_i2c_id[] = {
- { "ak4671", 0 },
+ { "ak4671" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index 0c5e00679c7d..6525d50b7ab2 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -6,12 +6,13 @@
* (c) 2013 Daniel Mack <zonque@gmail.com>
*/
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/initval.h>
@@ -21,7 +22,7 @@ static const char * const supply_names[] = {
};
struct ak5386_priv {
- int reset_gpio;
+ struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
@@ -111,8 +112,7 @@ static int ak5386_hw_params(struct snd_pcm_substream *substream,
* the AK5386 in power-down mode (PDN pin = “L”).
*/
- if (gpio_is_valid(priv->reset_gpio))
- gpio_set_value(priv->reset_gpio, 1);
+ gpiod_set_value(priv->reset_gpio, 1);
return 0;
}
@@ -123,8 +123,7 @@ static int ak5386_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(priv->reset_gpio))
- gpio_set_value(priv->reset_gpio, 0);
+ gpiod_set_value(priv->reset_gpio, 0);
return 0;
}
@@ -168,7 +167,6 @@ static int ak5386_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->reset_gpio = -EINVAL;
dev_set_drvdata(dev, priv);
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
@@ -179,15 +177,12 @@ static int ak5386_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
- priv->reset_gpio = of_get_named_gpio(dev->of_node,
- "reset-gpio", 0);
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get AK5386 reset GPIO\n");
- if (gpio_is_valid(priv->reset_gpio))
- if (devm_gpio_request_one(dev, priv->reset_gpio,
- GPIOF_OUT_INIT_LOW,
- "AK5386 Reset"))
- priv->reset_gpio = -EINVAL;
+ gpiod_set_consumer_name(priv->reset_gpio, "AK5386 Reset");
return devm_snd_soc_register_component(dev, &soc_component_ak5386,
&ak5386_dai, 1);
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 442e2cb42df4..683f3e472f50 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -9,7 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -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..a9946dcdc9f6 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -888,7 +888,7 @@ static int alc5623_resume(struct snd_soc_component *component)
static int alc5623_probe(struct snd_soc_component *component)
{
struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
alc5623_reset(component);
@@ -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-jack.c b/sound/soc/codecs/arizona-jack.c
index 9c15ddba6008..303c1d44ebd8 100644
--- a/sound/soc/codecs/arizona-jack.c
+++ b/sound/soc/codecs/arizona-jack.c
@@ -212,17 +212,16 @@ static void arizona_extcon_pulse_micbias(struct arizona_priv *info)
struct arizona *arizona = info->arizona;
const char *widget = arizona_extcon_get_micbias(info);
struct snd_soc_dapm_context *dapm = arizona->dapm;
- struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
int ret;
- ret = snd_soc_component_force_enable_pin(component, widget);
+ ret = snd_soc_dapm_force_enable_pin(dapm, widget);
if (ret)
dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret);
snd_soc_dapm_sync(dapm);
if (!arizona->pdata.micd_force_micbias) {
- ret = snd_soc_component_disable_pin(component, widget);
+ ret = snd_soc_dapm_disable_pin(dapm, widget);
if (ret)
dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret);
@@ -287,7 +286,6 @@ static void arizona_stop_mic(struct arizona_priv *info)
struct arizona *arizona = info->arizona;
const char *widget = arizona_extcon_get_micbias(info);
struct snd_soc_dapm_context *dapm = arizona->dapm;
- struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
bool change = false;
int ret;
@@ -297,7 +295,7 @@ static void arizona_stop_mic(struct arizona_priv *info)
if (ret < 0)
dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
- ret = snd_soc_component_disable_pin(component, widget);
+ ret = snd_soc_dapm_disable_pin(dapm, widget);
if (ret)
dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret);
@@ -319,7 +317,6 @@ static void arizona_stop_mic(struct arizona_priv *info)
if (change) {
regulator_disable(info->micvdd);
- pm_runtime_mark_last_busy(arizona->dev);
pm_runtime_put_autosuspend(arizona->dev);
}
}
@@ -462,7 +459,11 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
bool *mic)
{
struct arizona *arizona = info->arizona;
+#ifdef CONFIG_GPIOLIB_LEGACY
int id_gpio = arizona->pdata.hpdet_id_gpio;
+#else
+ int id_gpio = 0;
+#endif
if (!arizona->pdata.hpdet_acc_id)
return 0;
@@ -473,6 +474,7 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
*/
info->hpdet_res[info->num_hpdet_res++] = *reading;
+#ifdef CONFIG_GPIOLIB_LEGACY
/* Only check the mic directly if we didn't already ID it */
if (id_gpio && info->num_hpdet_res == 1) {
dev_dbg(arizona->dev, "Measuring mic\n");
@@ -490,6 +492,7 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading,
ARIZONA_HP_POLL, ARIZONA_HP_POLL);
return -EAGAIN;
}
+#endif
/* OK, got both. Now, compare... */
dev_dbg(arizona->dev, "HPDET measured %d %d\n",
@@ -530,7 +533,9 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
{
struct arizona_priv *info = data;
struct arizona *arizona = info->arizona;
+#ifdef CONFIG_GPIOLIB_LEGACY
int id_gpio = arizona->pdata.hpdet_id_gpio;
+#endif
int ret, reading, state, report;
bool mic = false;
@@ -586,8 +591,10 @@ done:
arizona_extcon_hp_clamp(info, false);
+#ifdef CONFIG_GPIOLIB_LEGACY
if (id_gpio)
gpio_set_value_cansleep(id_gpio, 0);
+#endif
/* If we have a mic then reenable MICDET */
if (state && (mic || info->mic))
@@ -1127,7 +1134,6 @@ out:
mutex_unlock(&info->lock);
- pm_runtime_mark_last_busy(arizona->dev);
pm_runtime_put_autosuspend(arizona->dev);
return IRQ_HANDLED;
@@ -1319,6 +1325,7 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
+#ifdef CONFIG_GPIOLIB_LEGACY
if (pdata->micd_pol_gpio > 0) {
if (info->micd_modes[0].gpio)
mode = GPIOF_OUT_INIT_HIGH;
@@ -1334,7 +1341,9 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
}
info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
- } else {
+ } else
+#endif
+ {
if (info->micd_modes[0].gpio)
mode = GPIOD_OUT_HIGH;
else
@@ -1355,6 +1364,7 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
}
}
+#ifdef CONFIG_GPIOLIB_LEGACY
if (arizona->pdata.hpdet_id_gpio > 0) {
ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio,
GPIOF_OUT_INIT_LOW,
@@ -1366,6 +1376,7 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev)
return ret;
}
}
+#endif
return 0;
}
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 7434aeeda292..8c683b0bb74c 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -169,7 +169,7 @@ static const struct snd_soc_dapm_widget arizona_spkr =
int arizona_init_spk(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int ret;
@@ -238,7 +238,7 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = {
int arizona_init_mono(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int i;
@@ -255,6 +255,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono);
int arizona_init_gpio(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->arizona;
int i;
@@ -262,24 +263,21 @@ int arizona_init_gpio(struct snd_soc_component *component)
switch (arizona->type) {
case WM5110:
case WM8280:
- snd_soc_component_disable_pin(component,
- "DRC2 Signal Activity");
+ snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
break;
default:
break;
}
- snd_soc_component_disable_pin(component, "DRC1 Signal Activity");
+ snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
- snd_soc_component_enable_pin(component,
- "DRC1 Signal Activity");
+ snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
break;
case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
- snd_soc_component_enable_pin(component,
- "DRC2 Signal Activity");
+ snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
break;
default:
break;
@@ -967,7 +965,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 +975,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 +997,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 +1015,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 +1026,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 +1051,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 +1455,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 +1466,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 +1479,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;
@@ -1911,7 +1909,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct snd_soc_dapm_route routes[2];
@@ -2724,7 +2722,7 @@ static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_bytes *params = (void *)kcontrol->private_value;
unsigned int val;
@@ -2768,7 +2766,7 @@ EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
__be16 *data = (__be16 *)ucontrol->value.bytes.data;
s16 val = be16_to_cpu(*data);
@@ -2786,15 +2784,13 @@ int arizona_of_get_audio_pdata(struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct device_node *np = arizona->dev->of_node;
- struct property *prop;
- const __be32 *cur;
u32 val;
u32 pdm_val[ARIZONA_MAX_PDM_SPK];
int ret;
int count = 0;
count = 0;
- of_property_for_each_u32(np, "wlf,inmode", prop, cur, val) {
+ of_property_for_each_u32(np, "wlf,inmode", val) {
if (count == ARRAY_SIZE(pdata->inmode))
break;
@@ -2803,7 +2799,7 @@ int arizona_of_get_audio_pdata(struct arizona *arizona)
}
count = 0;
- of_property_for_each_u32(np, "wlf,dmic-ref", prop, cur, val) {
+ of_property_for_each_u32(np, "wlf,dmic-ref", val) {
if (count == ARRAY_SIZE(pdata->dmic_ref))
break;
@@ -2812,7 +2808,7 @@ int arizona_of_get_audio_pdata(struct arizona *arizona)
}
count = 0;
- of_property_for_each_u32(np, "wlf,out-mono", prop, cur, val) {
+ of_property_for_each_u32(np, "wlf,out-mono", val) {
if (count == ARRAY_SIZE(pdata->out_mono))
break;
@@ -2821,7 +2817,7 @@ int arizona_of_get_audio_pdata(struct arizona *arizona)
}
count = 0;
- of_property_for_each_u32(np, "wlf,max-channels-clocked", prop, cur, val) {
+ of_property_for_each_u32(np, "wlf,max-channels-clocked", val) {
if (count == ARRAY_SIZE(pdata->max_channels_clocked))
break;
@@ -2830,7 +2826,7 @@ int arizona_of_get_audio_pdata(struct arizona *arizona)
}
count = 0;
- of_property_for_each_u32(np, "wlf,out-volume-limit", prop, cur, val) {
+ of_property_for_each_u32(np, "wlf,out-volume-limit", val) {
if (count == ARRAY_SIZE(pdata->out_vol_limit))
break;
diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c
new file mode 100644
index 000000000000..066e401912b0
--- /dev/null
+++ b/sound/soc/codecs/audio-iio-aux.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// ALSA SoC glue to use IIO devices as audio components
+//
+// Copyright 2023 CS GROUP France
+//
+// Author: Herve Codina <herve.codina@bootlin.com>
+
+#include <linux/cleanup.h>
+#include <linux/iio/consumer.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+struct audio_iio_aux_chan {
+ struct iio_channel *iio_chan;
+ const char *name;
+ int max;
+ int min;
+ bool is_invert_range;
+};
+
+struct audio_iio_aux {
+ struct device *dev;
+ unsigned int num_chans;
+ struct audio_iio_aux_chan chans[] __counted_by(num_chans);
+};
+
+static int audio_iio_aux_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = chan->max - chan->min;
+ uinfo->type = (uinfo->value.integer.max == 1) ?
+ SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ return 0;
+}
+
+static int audio_iio_aux_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+ int max = chan->max;
+ int min = chan->min;
+ bool invert_range = chan->is_invert_range;
+ int ret;
+ int val;
+
+ ret = iio_read_channel_raw(chan->iio_chan, &val);
+ if (ret < 0)
+ return ret;
+
+ ucontrol->value.integer.value[0] = val - min;
+ if (invert_range)
+ ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static int audio_iio_aux_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+ int max = chan->max;
+ int min = chan->min;
+ bool invert_range = chan->is_invert_range;
+ int val;
+ int ret;
+ int tmp;
+
+ val = ucontrol->value.integer.value[0];
+ if (val < 0)
+ return -EINVAL;
+ if (val > max - min)
+ return -EINVAL;
+
+ val = val + min;
+ if (invert_range)
+ val = max - val;
+
+ ret = iio_read_channel_raw(chan->iio_chan, &tmp);
+ if (ret < 0)
+ return ret;
+
+ if (tmp == val)
+ return 0;
+
+ ret = iio_write_channel_raw(chan->iio_chan, val);
+ if (ret)
+ return ret;
+
+ return 1; /* The value changed */
+}
+
+static int audio_iio_aux_add_controls(struct snd_soc_component *component,
+ struct audio_iio_aux_chan *chan)
+{
+ struct snd_kcontrol_new control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = chan->name,
+ .info = audio_iio_aux_info_volsw,
+ .get = audio_iio_aux_get_volsw,
+ .put = audio_iio_aux_put_volsw,
+ .private_value = (unsigned long)chan,
+ };
+
+ return snd_soc_add_component_controls(component, &control, 1);
+}
+
+/*
+ * These data could be on stack but they are pretty big.
+ * As ASoC internally copy them and protect them against concurrent accesses
+ * (snd_soc_bind_card() protects using client_mutex), keep them in the global
+ * data area.
+ */
+static struct snd_soc_dapm_widget widgets[3];
+static struct snd_soc_dapm_route routes[2];
+
+/* Be sure sizes are correct (need 3 widgets and 2 routes) */
+static_assert(ARRAY_SIZE(widgets) >= 3, "3 widgets are needed");
+static_assert(ARRAY_SIZE(routes) >= 2, "2 routes are needed");
+
+static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
+ struct audio_iio_aux_chan *chan)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
+
+ /* Allocated names are not needed afterwards (duplicated in ASoC internals) */
+ char *input_name __free(kfree) = kasprintf(GFP_KERNEL, "%s IN", chan->name);
+ if (!input_name)
+ return -ENOMEM;
+
+ char *output_name __free(kfree) = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
+ if (!output_name)
+ return -ENOMEM;
+
+ char *pga_name __free(kfree) = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
+ if (!pga_name)
+ return -ENOMEM;
+
+ widgets[0] = SND_SOC_DAPM_INPUT(input_name);
+ widgets[1] = SND_SOC_DAPM_OUTPUT(output_name);
+ widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0);
+ ret = snd_soc_dapm_new_controls(dapm, widgets, 3);
+ if (ret)
+ return ret;
+
+ routes[0].sink = pga_name;
+ routes[0].control = NULL;
+ routes[0].source = input_name;
+ routes[1].sink = output_name;
+ routes[1].control = NULL;
+ routes[1].source = pga_name;
+
+ return snd_soc_dapm_add_routes(dapm, routes, 2);
+}
+
+static int audio_iio_aux_component_probe(struct snd_soc_component *component)
+{
+ struct audio_iio_aux *iio_aux = snd_soc_component_get_drvdata(component);
+ struct audio_iio_aux_chan *chan;
+ int ret;
+ int i;
+
+ for (i = 0; i < iio_aux->num_chans; i++) {
+ chan = iio_aux->chans + i;
+
+ ret = iio_read_max_channel_raw(chan->iio_chan, &chan->max);
+ if (ret)
+ return dev_err_probe(component->dev, ret,
+ "chan[%d] %s: Cannot get max raw value\n",
+ i, chan->name);
+
+ ret = iio_read_min_channel_raw(chan->iio_chan, &chan->min);
+ if (ret)
+ return dev_err_probe(component->dev, ret,
+ "chan[%d] %s: Cannot get min raw value\n",
+ i, chan->name);
+
+ if (chan->min > chan->max) {
+ /*
+ * This should never happen but to avoid any check
+ * later, just swap values here to ensure that the
+ * minimum value is lower than the maximum value.
+ */
+ dev_dbg(component->dev, "chan[%d] %s: Swap min and max\n",
+ i, chan->name);
+ swap(chan->min, chan->max);
+ }
+
+ /* Set initial value */
+ ret = iio_write_channel_raw(chan->iio_chan,
+ chan->is_invert_range ? chan->max : chan->min);
+ if (ret)
+ return dev_err_probe(component->dev, ret,
+ "chan[%d] %s: Cannot set initial value\n",
+ i, chan->name);
+
+ ret = audio_iio_aux_add_controls(component, chan);
+ if (ret)
+ return ret;
+
+ ret = audio_iio_aux_add_dapms(component, chan);
+ if (ret)
+ return ret;
+
+ dev_dbg(component->dev, "chan[%d]: Added %s (min=%d, max=%d, invert=%s)\n",
+ i, chan->name, chan->min, chan->max,
+ str_on_off(chan->is_invert_range));
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver audio_iio_aux_component_driver = {
+ .probe = audio_iio_aux_component_probe,
+};
+
+static int audio_iio_aux_probe(struct platform_device *pdev)
+{
+ struct audio_iio_aux_chan *iio_aux_chan;
+ struct device *dev = &pdev->dev;
+ struct audio_iio_aux *iio_aux;
+ int count;
+ int ret;
+ int i;
+
+ count = device_property_string_array_count(dev, "io-channel-names");
+ if (count < 0)
+ return dev_err_probe(dev, count, "failed to count io-channel-names\n");
+
+ iio_aux = devm_kzalloc(dev, struct_size(iio_aux, chans, count), GFP_KERNEL);
+ if (!iio_aux)
+ return -ENOMEM;
+
+ iio_aux->dev = dev;
+
+ iio_aux->num_chans = count;
+
+ const char **names __free(kfree) = kcalloc(iio_aux->num_chans,
+ sizeof(*names),
+ GFP_KERNEL);
+ if (!names)
+ return -ENOMEM;
+
+ u32 *invert_ranges __free(kfree) = kcalloc(iio_aux->num_chans,
+ sizeof(*invert_ranges),
+ GFP_KERNEL);
+ if (!invert_ranges)
+ return -ENOMEM;
+
+ ret = device_property_read_string_array(dev, "io-channel-names",
+ names, iio_aux->num_chans);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read io-channel-names\n");
+
+ /*
+ * snd-control-invert-range is optional and can contain fewer items
+ * than the number of channels. Unset values default to 0.
+ */
+ count = device_property_count_u32(dev, "snd-control-invert-range");
+ if (count > 0) {
+ count = min_t(unsigned int, count, iio_aux->num_chans);
+ ret = device_property_read_u32_array(dev, "snd-control-invert-range",
+ invert_ranges, count);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
+ }
+
+ for (i = 0; i < iio_aux->num_chans; i++) {
+ iio_aux_chan = iio_aux->chans + i;
+ iio_aux_chan->name = names[i];
+ iio_aux_chan->is_invert_range = invert_ranges[i];
+
+ iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name);
+ if (IS_ERR(iio_aux_chan->iio_chan))
+ return dev_err_probe(dev, PTR_ERR(iio_aux_chan->iio_chan),
+ "get IIO channel '%s' failed\n",
+ iio_aux_chan->name);
+ }
+
+ platform_set_drvdata(pdev, iio_aux);
+
+ return devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
+ NULL, 0);
+}
+
+static const struct of_device_id audio_iio_aux_ids[] = {
+ { .compatible = "audio-iio-aux" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, audio_iio_aux_ids);
+
+static struct platform_driver audio_iio_aux_driver = {
+ .driver = {
+ .name = "audio-iio-aux",
+ .of_match_table = audio_iio_aux_ids,
+ },
+ .probe = audio_iio_aux_probe,
+};
+module_platform_driver(audio_iio_aux_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("IIO ALSA SoC aux driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c
new file mode 100644
index 000000000000..d7fd865c349f
--- /dev/null
+++ b/sound/soc/codecs/aw87390.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw87390.c -- AW87390 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "aw87390.h"
+#include "aw88395/aw88395_data_type.h"
+#include "aw88395/aw88395_device.h"
+
+static const struct regmap_config aw87390_remap_config = {
+ .val_bits = 8,
+ .reg_bits = 8,
+ .max_register = AW87390_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int aw87390_dev_reg_update(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int i, ret;
+
+ if (!data) {
+ dev_err(aw_dev->dev, "data is NULL\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len-1; i += 2) {
+ if (data[i] == AW87390_DELAY_REG_ADDR) {
+ usleep_range(data[i + 1] * AW87390_REG_DELAY_TIME,
+ data[i + 1] * AW87390_REG_DELAY_TIME + 10);
+ continue;
+ }
+ ret = regmap_write(aw_dev->regmap, data[i], data[i + 1]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw87390_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 aw87390_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 aw87390_dev_fw_update(struct aw_device *aw_dev)
+{
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ ret = aw87390_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret) {
+ dev_err(aw_dev->dev, "get prof name failed\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw87390_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw87390_dev_get_prof_data failed\n");
+ return ret;
+ }
+
+ /* update reg */
+ sec_desc = prof_index_desc->sec_desc;
+ ret = aw87390_dev_reg_update(aw_dev, 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;
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+}
+
+static int aw87390_power_off(struct aw_device *aw_dev)
+{
+ int ret;
+
+ if (aw_dev->status == AW87390_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off\n");
+ return 0;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE);
+ if (ret)
+ return ret;
+ aw_dev->status = AW87390_DEV_PW_OFF;
+
+ return 0;
+}
+
+static int aw87390_power_on(struct aw_device *aw_dev)
+{
+ int ret;
+
+ if (aw_dev->status == AW87390_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on\n");
+ return 0;
+ }
+
+ if (!aw_dev->fw_status) {
+ dev_err(aw_dev->dev, "fw not load\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw87390_dev_fw_update(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s load profile failed\n", __func__);
+ return ret;
+ }
+ aw_dev->status = AW87390_DEV_PW_ON;
+
+ return 0;
+}
+
+static int aw87390_dev_set_profile_index(struct aw_device *aw_dev, int index)
+{
+ if ((index >= aw_dev->prof_info.count) || (index < 0))
+ return -EINVAL;
+
+ if (aw_dev->prof_index == index)
+ return -EPERM;
+
+ aw_dev->prof_index = index;
+
+ return 0;
+}
+
+static int aw87390_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
+ char *prof_name;
+ int count, ret;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw87390->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;
+
+ count = uinfo->value.enumerated.item;
+
+ ret = aw87390_dev_get_prof_name(aw87390->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null");
+ return 0;
+ }
+
+ strscpy(uinfo->value.enumerated.name, prof_name);
+
+ return 0;
+}
+
+static int aw87390_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw87390->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw87390_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ mutex_lock(&aw87390->lock);
+ ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]);
+ if (ret) {
+ dev_dbg(codec->dev, "profile index does not change\n");
+ mutex_unlock(&aw87390->lock);
+ return 0;
+ }
+
+ if (aw87390->aw_pa->status == AW87390_DEV_PW_ON) {
+ aw87390_power_off(aw87390->aw_pa);
+ aw87390_power_on(aw87390->aw_pa);
+ }
+
+ mutex_unlock(&aw87390->lock);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new aw87390_controls[] = {
+ AW87390_PROFILE_EXT("AW87390 Profile Set", aw87390_profile_info,
+ aw87390_profile_get, aw87390_profile_set),
+};
+
+static int aw87390_request_firmware_file(struct aw87390 *aw87390)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW87390_ACF_FILE, aw87390->aw_pa->dev);
+ if (ret)
+ return dev_err_probe(aw87390->aw_pa->dev, ret,
+ "load [%s] failed!\n", AW87390_ACF_FILE);
+
+ dev_dbg(aw87390->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW87390_ACF_FILE, cont ? cont->size : 0);
+
+ aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev,
+ struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL);
+ if (!aw87390->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+
+ aw87390->aw_cfg->len = cont->size;
+ memcpy(aw87390->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg);
+ if (ret) {
+ dev_err(aw87390->aw_pa->dev, "load [%s] failed!\n", AW87390_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw87390->lock);
+
+ ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg);
+ if (ret)
+ dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n");
+
+ mutex_unlock(&aw87390->lock);
+
+ return ret;
+}
+
+static int aw87390_drv_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 aw87390 *aw87390 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw87390->aw_pa;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = aw87390_power_on(aw_dev);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = aw87390_power_off(aw_dev);
+ break;
+ default:
+ dev_err(aw_dev->dev, "%s: invalid event %d\n", __func__, event);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget aw87390_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("IN"),
+ SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0, NULL, 0, aw87390_drv_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route aw87390_dapm_routes[] = {
+ { "SPK PA", NULL, "IN" },
+ { "OUT", NULL, "SPK PA" },
+};
+
+static int aw87390_codec_probe(struct snd_soc_component *component)
+{
+ struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = aw87390_request_firmware_file(aw87390);
+ if (ret)
+ return dev_err_probe(aw87390->aw_pa->dev, ret,
+ "aw87390_request_firmware_file failed\n");
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw87390 = {
+ .probe = aw87390_codec_probe,
+ .dapm_widgets = aw87390_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aw87390_dapm_widgets),
+ .dapm_routes = aw87390_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(aw87390_dapm_routes),
+ .controls = aw87390_controls,
+ .num_controls = ARRAY_SIZE(aw87390_controls),
+};
+
+static void aw87390_parse_channel_dt(struct aw87390 *aw87390)
+{
+ struct aw_device *aw_dev = aw87390->aw_pa;
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value = AW87390_DEV_DEFAULT_CH;
+
+ of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+
+ aw_dev->channel = channel_value;
+}
+
+static int aw87390_init(struct aw87390 *aw87390, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ /* read chip id */
+ ret = regmap_read(regmap, AW87390_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (chip_id != AW87390_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device\n");
+ return -ENXIO;
+ }
+
+ dev_dbg(&i2c->dev, "chip id = 0x%x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+
+ aw87390->aw_pa = aw_dev;
+ aw_dev->i2c = i2c;
+ aw_dev->regmap = regmap;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->chip_id = AW87390_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 = AW87390_DEV_DEFAULT_CH;
+ aw_dev->fw_status = AW87390_DEV_FW_FAILED;
+ aw_dev->prof_index = AW87390_INIT_PROFILE;
+ aw_dev->status = AW87390_DEV_PW_OFF;
+
+ aw87390_parse_channel_dt(aw87390);
+
+ return 0;
+}
+
+static int aw87390_i2c_probe(struct i2c_client *i2c)
+{
+ struct aw87390 *aw87390;
+ int ret;
+
+ ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
+ if (!ret)
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n");
+
+ aw87390 = devm_kzalloc(&i2c->dev, sizeof(*aw87390), GFP_KERNEL);
+ if (!aw87390)
+ return -ENOMEM;
+
+ mutex_init(&aw87390->lock);
+
+ i2c_set_clientdata(i2c, aw87390);
+
+ aw87390->regmap = devm_regmap_init_i2c(i2c, &aw87390_remap_config);
+ if (IS_ERR(aw87390->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw87390->regmap),
+ "failed to init regmap\n");
+
+ /* aw pa init */
+ ret = aw87390_init(aw87390, i2c, aw87390->regmap);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(aw87390->regmap, AW87390_ID_REG, AW87390_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw87390, NULL, 0);
+ if (ret)
+ dev_err(&i2c->dev, "failed to register aw87390: %d\n", ret);
+
+ return ret;
+}
+
+static const struct i2c_device_id aw87390_i2c_id[] = {
+ { AW87390_I2C_NAME },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id);
+
+static struct i2c_driver aw87390_i2c_driver = {
+ .driver = {
+ .name = AW87390_I2C_NAME,
+ },
+ .probe = aw87390_i2c_probe,
+ .id_table = aw87390_i2c_id,
+};
+module_i2c_driver(aw87390_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW87390 PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw87390.h b/sound/soc/codecs/aw87390.h
new file mode 100644
index 000000000000..d0d049e65991
--- /dev/null
+++ b/sound/soc/codecs/aw87390.h
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw87390.h -- aw87390 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW87390_H__
+#define __AW87390_H__
+
+#define AW87390_ID_REG (0x00)
+#define AW87390_SYSCTRL_REG (0x01)
+#define AW87390_MDCTRL_REG (0x02)
+#define AW87390_CPOVP_REG (0x03)
+#define AW87390_CPP_REG (0x04)
+#define AW87390_PAG_REG (0x05)
+#define AW87390_AGC3P_REG (0x06)
+#define AW87390_AGC3PA_REG (0x07)
+#define AW87390_AGC2P_REG (0x08)
+#define AW87390_AGC2PA_REG (0x09)
+#define AW87390_AGC1PA_REG (0x0A)
+#define AW87390_SYSST_REG (0x59)
+#define AW87390_SYSINT_REG (0x60)
+#define AW87390_DFT_SYSCTRL_REG (0x61)
+#define AW87390_DFT_MDCTRL_REG (0x62)
+#define AW87390_DFT_CPADP_REG (0x63)
+#define AW87390_DFT_AGCPA_REG (0x64)
+#define AW87390_DFT_POFR_REG (0x65)
+#define AW87390_DFT_OC_REG (0x66)
+#define AW87390_DFT_ADP1_REG (0x67)
+#define AW87390_DFT_REF_REG (0x68)
+#define AW87390_DFT_LDO_REG (0x69)
+#define AW87390_ADP1_REG (0x70)
+#define AW87390_ADP2_REG (0x71)
+#define AW87390_NG1_REG (0x72)
+#define AW87390_NG2_REG (0x73)
+#define AW87390_NG3_REG (0x74)
+#define AW87390_CP_REG (0x75)
+#define AW87390_AB_REG (0x76)
+#define AW87390_TEST_REG (0x77)
+#define AW87390_ENCR_REG (0x78)
+#define AW87390_DELAY_REG_ADDR (0xFE)
+
+#define AW87390_SOFT_RESET_VALUE (0xAA)
+#define AW87390_POWER_DOWN_VALUE (0x00)
+#define AW87390_REG_MAX (0xFF)
+#define AW87390_DEV_DEFAULT_CH (0)
+#define AW87390_INIT_PROFILE (0)
+#define AW87390_REG_DELAY_TIME (1000)
+#define AW87390_I2C_NAME "aw87390"
+#define AW87390_ACF_FILE "aw87390_acf.bin"
+
+#define AW87390_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 aw87390_id {
+ AW87390_CHIP_ID = 0x76,
+};
+
+enum {
+ AW87390_DEV_FW_FAILED = 0,
+ AW87390_DEV_FW_OK,
+};
+
+enum {
+ AW87390_DEV_PW_OFF = 0,
+ AW87390_DEV_PW_ON,
+};
+
+struct aw87390 {
+ struct aw_device *aw_pa;
+ struct mutex lock;
+ struct regmap *regmap;
+ struct aw_container *aw_cfg;
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
new file mode 100644
index 000000000000..fbd1fd12381a
--- /dev/null
+++ b/sound/soc/codecs/aw88081.c
@@ -0,0 +1,1317 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88081.c -- AW88081 ALSA SoC Audio driver
+//
+// Copyright (c) 2024 awinic Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#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;
+};
+
+static const struct regmap_config aw88081_regmap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88081_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .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;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88081_BIT_PLL_CHECK) != AW88081_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw88081_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88081_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw88081_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88081_PLLCTRL1_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88081_CCO_MUX_MASK);
+ if (reg_val == AW88081_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, AW88081_PLLCTRL1_REG,
+ ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88081_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis check error");
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG,
+ ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88081_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis check error");
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int aw88081_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw88081_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw88081_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int aw88081_dev_check_sysst(struct aw_device *aw_dev)
+{
+ unsigned int check_val;
+ unsigned int reg_val;
+ unsigned int value;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88081_PWMCTRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88081_NOISE_GATE_EN_MASK))
+ check_val = AW88081_NO_SWS_SYSST_CHECK;
+ else
+ check_val = AW88081_SWS_SYSST_CHECK;
+
+ for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ value = reg_val & (~AW88081_BIT_SYSST_CHECK_MASK) & check_val;
+ if (value != check_val) {
+ dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
+ reg_val, check_val);
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw88081_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ if (flag)
+ regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG,
+ ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG,
+ ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_DISABLE_VALUE);
+}
+
+static void aw88081_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ if (pwd)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_PWDN_MASK, AW88081_PWDN_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_PWDN_MASK, AW88081_PWDN_WORKING_VALUE);
+}
+
+static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ if (amppd)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_EN_PA_MASK, AW88081_EN_PA_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~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;
+
+ /* read int status and clear */
+ regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status);
+ /* make sure int status is clear */
+ regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status);
+
+ dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status);
+}
+
+static void aw88081_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int volume;
+
+ volume = min((value + vol_desc->init_volume), (unsigned int)AW88081_MUTE_VOL);
+
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL2_REG, ~AW88081_VOL_MASK, volume);
+}
+
+static void aw88081_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int 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) {
+ aw88081_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88081_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw88081_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw88081_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw88081_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) {
+ aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88081_MUTE_VOL; i += fade_step) {
+ aw88081_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88081_MUTE_VOL)
+ aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL);
+}
+
+static void aw88081_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw88081_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_HMUTE_MASK, AW88081_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_HMUTE_MASK, AW88081_HMUTE_DISABLE_VALUE);
+ aw88081_dev_fade_in(aw_dev);
+ }
+}
+
+static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
+{
+ if (uls_hmute)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_ULS_HMUTE_MASK,
+ AW88081_ULS_HMUTE_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88081_ULS_HMUTE_MASK,
+ 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;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u16 reg_val;
+ u8 reg_addr;
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ 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)
+ return ret;
+ }
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+
+ /* keep min volume */
+ aw88081_dev_set_volume(aw_dev, vol_desc->mute_volume);
+
+ return 0;
+}
+
+static int aw88081_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
+}
+
+static int aw88081_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 aw88081_dev_fw_update(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ ret = aw88081_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret) {
+ dev_err(aw_dev->dev, "get prof name failed");
+ return -EINVAL;
+ }
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88081_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 = aw88081_dev_reg_update(aw88081, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+}
+
+static int aw88081_dev_start(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88081_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ /* power on */
+ aw88081_dev_pwd(aw_dev, false);
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+
+ ret = aw88081_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw88081_dev_amppd(aw_dev, false);
+ usleep_range(AW88081_1000_US, AW88081_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw88081_dev_check_sysst(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ /* enable tx feedback */
+ aw88081_dev_i2s_tx_enable(aw_dev, true);
+
+ /* close uls mute */
+ aw88081_dev_uls_hmute(aw_dev, false);
+
+ /* close mute */
+ aw88081_dev_mute(aw_dev, false);
+
+ /* clear inturrupt */
+ aw88081_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88081_DEV_PW_ON;
+
+ return 0;
+
+sysst_check_fail:
+ aw88081_dev_i2s_tx_enable(aw_dev, false);
+ aw88081_dev_clear_int_status(aw_dev);
+ aw88081_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw88081_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88081_DEV_PW_OFF;
+
+ return ret;
+}
+
+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;
+ }
+
+ aw_dev->status = AW88081_DEV_PW_OFF;
+
+ /* clear inturrupt */
+ aw88081_dev_clear_int_status(aw_dev);
+
+ aw88081_dev_uls_hmute(aw_dev, true);
+ /* set mute */
+ aw88081_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw88081_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88081_1000_US, AW88081_1000_US + 100);
+
+ /* enable amppd */
+ aw88081_dev_amppd(aw_dev, true);
+
+ /* set power down */
+ aw88081_dev_pwd(aw_dev, true);
+
+ 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;
+ int ret;
+
+ if (force) {
+ ret = regmap_write(aw_dev->regmap,
+ AW88081_ID_REG, AW88081_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw88081_dev_fw_update(aw88081);
+ if (ret)
+ return ret;
+ } else {
+ if (aw_dev->prof_cur != aw_dev->prof_index) {
+ ret = aw88081_dev_fw_update(aw88081);
+ if (ret)
+ return ret;
+ }
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+}
+
+static void aw88081_start_pa(struct aw88081 *aw88081)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88081_START_RETRIES; i++) {
+ ret = aw88081_reg_update(aw88081, aw88081->phase_sync);
+ if (ret) {
+ dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i);
+ continue;
+ }
+ ret = aw88081_device_start(aw88081);
+ if (ret) {
+ dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i);
+ continue;
+ } else {
+ dev_dbg(aw88081->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+static void aw88081_startup_work(struct work_struct *work)
+{
+ struct aw88081 *aw88081 =
+ container_of(work, struct aw88081, start_work.work);
+
+ mutex_lock(&aw88081->lock);
+ aw88081_start_pa(aw88081);
+ mutex_unlock(&aw88081->lock);
+}
+
+static void aw88081_start(struct aw88081 *aw88081, bool sync_start)
+{
+ if (aw88081->aw_pa->fw_status != AW88081_DEV_FW_OK)
+ return;
+
+ if (aw88081->aw_pa->status == AW88081_DEV_PW_ON)
+ return;
+
+ if (sync_start == AW88081_SYNC_START)
+ aw88081_start_pa(aw88081);
+ else
+ queue_delayed_work(system_dfl_wq,
+ &aw88081->start_work,
+ AW88081_START_WORK_DELAY_MS);
+}
+
+static struct snd_soc_dai_driver aw88081_dai[] = {
+ {
+ .name = "aw88081-aif",
+ .id = 1,
+ .playback = {
+ .stream_name = "Speaker_Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88081_RATES,
+ .formats = AW88081_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Speaker_Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88081_RATES,
+ .formats = AW88081_FORMATS,
+ },
+ },
+};
+
+static int aw88081_get_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+ return 0;
+}
+
+static int aw88081_set_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88081->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 aw88081_get_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+ return 0;
+}
+
+static int aw88081_set_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88081->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 aw88081_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 -EPERM;
+
+ aw_dev->prof_index = index;
+
+ return 0;
+}
+
+static int aw88081_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ char *prof_name;
+ int count, ret;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw88081->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;
+
+ count = uinfo->value.enumerated.item;
+
+ ret = aw88081_dev_get_prof_name(aw88081->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null");
+ return 0;
+ }
+
+ strscpy(uinfo->value.enumerated.name, prof_name);
+
+ return 0;
+}
+
+static int aw88081_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88081->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ /* pa stop or stopping just set profile */
+ mutex_lock(&aw88081->lock);
+ ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]);
+ if (ret) {
+ dev_dbg(codec->dev, "profile index does not change");
+ mutex_unlock(&aw88081->lock);
+ return 0;
+ }
+
+ if (aw88081->aw_pa->status) {
+ aw88081_stop(aw88081);
+ aw88081_start(aw88081, AW88081_SYNC_START);
+ }
+
+ mutex_unlock(&aw88081->lock);
+
+ return 1;
+}
+
+static int aw88081_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc;
+
+ ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+ return 0;
+}
+
+static int aw88081_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88081->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;
+
+ 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;
+}
+
+static int aw88081_get_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88081->aw_pa->fade_step;
+
+ return 0;
+}
+
+static int aw88081_set_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88081 *aw88081 = 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 (aw88081->aw_pa->fade_step != value) {
+ aw88081->aw_pa->fade_step = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new aw88081_controls[] = {
+ SOC_SINGLE_EXT("PCM Playback Volume", AW88081_SYSCTRL2_REG,
+ 0, AW88081_MUTE_VOL, 0, aw88081_volume_get,
+ aw88081_volume_set),
+ SOC_SINGLE_EXT("Fade Step", 0, 0, AW88081_MUTE_VOL, 0,
+ aw88081_get_fade_step, aw88081_set_fade_step),
+ SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, 0,
+ aw88081_get_fade_in_time, aw88081_set_fade_in_time),
+ SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, 0,
+ aw88081_get_fade_out_time, aw88081_set_fade_out_time),
+ AW88081_PROFILE_EXT("Profile Set", aw88081_profile_info,
+ aw88081_profile_get, aw88081_profile_set),
+};
+
+static void aw88081_parse_channel_dt(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value = AW88081_DEV_DEFAULT_CH;
+
+ of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ aw88081->phase_sync = of_property_read_bool(np, "awinic,sync-flag");
+
+ aw_dev->channel = channel_value;
+}
+
+static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ /* read chip id */
+ ret = regmap_read(regmap, AW88081_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+
+ 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;
+ }
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+
+ aw88081->aw_pa = aw_dev;
+ aw_dev->i2c = i2c;
+ aw_dev->regmap = regmap;
+ aw_dev->dev = &i2c->dev;
+ 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;
+ aw_dev->fade_step = AW88081_VOLUME_STEP_DB;
+ aw_dev->volume_desc.mute_volume = AW88081_MUTE_VOL;
+ aw88081_parse_channel_dt(aw88081);
+
+ return 0;
+}
+
+static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88081_ID_REG, AW88081_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ aw_dev->fade_in_time = AW88081_500_US;
+ aw_dev->fade_out_time = AW88081_500_US;
+ aw_dev->prof_cur = AW88081_INIT_PROFILE;
+ aw_dev->prof_index = AW88081_INIT_PROFILE;
+
+ ret = aw88081_dev_fw_update(aw88081);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw_dev->status = AW88081_DEV_PW_ON;
+ aw88081_stop(aw88081);
+
+ return 0;
+}
+
+static int aw88081_request_firmware_file(struct aw88081 *aw88081)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88081->aw_pa->fw_status = AW88081_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88081_ACF_FILE, aw88081->aw_pa->dev);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw88081->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88081_ACF_FILE, cont ? cont->size : 0);
+
+ aw88081->aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
+ if (!aw88081->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+ aw88081->aw_cfg->len = (int)cont->size;
+ memcpy(aw88081->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg);
+ if (ret)
+ return ret;
+
+ mutex_lock(&aw88081->lock);
+ ret = aw88081_dev_init(aw88081, aw88081->aw_cfg);
+ mutex_unlock(&aw88081->lock);
+
+ return ret;
+}
+
+static int aw88081_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 aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&aw88081->lock);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ aw88081_start(aw88081, AW88081_ASYNC_START);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ aw88081_stop(aw88081);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&aw88081->lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88081_dapm_widgets[] = {
+ /* playback */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0,
+ aw88081_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 aw88081_audio_map[] = {
+ {"DAC Output", NULL, "AIF_RX"},
+ {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88081_codec_probe(struct snd_soc_component *component)
+{
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ INIT_DELAYED_WORK(&aw88081->start_work, aw88081_startup_work);
+
+ ret = aw88081_request_firmware_file(aw88081);
+ if (ret)
+ dev_err(aw88081->aw_pa->dev, "%s: request firmware failed\n", __func__);
+
+ return ret;
+}
+
+static void aw88081_codec_remove(struct snd_soc_component *aw_codec)
+{
+ struct aw88081 *aw88081 = snd_soc_component_get_drvdata(aw_codec);
+
+ cancel_delayed_work_sync(&aw88081->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88081 = {
+ .probe = aw88081_codec_probe,
+ .remove = aw88081_codec_remove,
+ .dapm_widgets = aw88081_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aw88081_dapm_widgets),
+ .dapm_routes = aw88081_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(aw88081_audio_map),
+ .controls = aw88081_controls,
+ .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;
+
+ ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
+ if (!ret)
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
+
+ aw88081 = devm_kzalloc(&i2c->dev, sizeof(*aw88081), GFP_KERNEL);
+ 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);
+
+ 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");
+
+ /* aw pa init */
+ ret = aw88081_init(aw88081, i2c, aw88081->regmap);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw88081,
+ aw88081_dai, ARRAY_SIZE(aw88081_dai));
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id aw88081_of_match[] = {
+ { .compatible = "awinic,aw88081" },
+ { .compatible = "awinic,aw88083" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, aw88081_of_match);
+#endif
+
+static struct i2c_driver aw88081_i2c_driver = {
+ .driver = {
+ .name = AW88081_I2C_NAME,
+ .of_match_table = of_match_ptr(aw88081_of_match),
+ },
+ .probe = aw88081_i2c_probe,
+ .id_table = aw88081_i2c_id,
+};
+module_i2c_driver(aw88081_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88081 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88081.h b/sound/soc/codecs/aw88081.h
new file mode 100644
index 000000000000..7a4564270ab3
--- /dev/null
+++ b/sound/soc/codecs/aw88081.h
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88081.h -- AW88081 ALSA SoC Audio driver
+//
+// Copyright (c) 2024 awinic Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88081_H__
+#define __AW88081_H__
+
+#define AW88081_ID_REG (0x00)
+#define AW88081_SYSST_REG (0x01)
+#define AW88081_SYSINT_REG (0x02)
+#define AW88081_SYSINTM_REG (0x03)
+#define AW88081_SYSCTRL_REG (0x04)
+#define AW88081_SYSCTRL2_REG (0x05)
+#define AW88081_I2SCTRL1_REG (0x06)
+#define AW88081_I2SCTRL2_REG (0x07)
+#define AW88081_I2SCTRL3_REG (0x08)
+#define AW88081_DACCFG1_REG (0x09)
+#define AW88081_DACCFG2_REG (0x0A)
+#define AW88081_DACCFG3_REG (0x0B)
+#define AW88081_DACCFG4_REG (0x0C)
+#define AW88081_DACCFG5_REG (0x0D)
+#define AW88081_DACCFG6_REG (0x0E)
+#define AW88081_DACCFG7_REG (0x11)
+#define AW88081_PWMCTRL1_REG (0x13)
+#define AW88081_PWMCTRL2_REG (0x14)
+#define AW88081_PWMCTRL3_REG (0x15)
+#define AW88081_PWMCTRL4_REG (0x16)
+#define AW88081_I2SCFG1_REG (0x17)
+#define AW88081_DBGCTRL_REG (0x18)
+#define AW88081_PDMCTRL_REG (0x19)
+#define AW88081_DACST_REG (0x20)
+#define AW88081_PATTERNST_REG (0x21)
+#define AW88081_I2SINT_REG (0x26)
+#define AW88081_I2SCAPCNT_REG (0x27)
+#define AW88081_ANASTA1_REG (0x28)
+#define AW88081_ANASTA2_REG (0x29)
+#define AW88081_ANASTA3_REG (0x2A)
+#define AW88081_VBAT_REG (0x21)
+#define AW88081_TEMP_REG (0x22)
+#define AW88081_PVDD_REG (0x23)
+#define AW88081_ISNDAT_REG (0x24)
+#define AW88081_VSNDAT_REG (0x25)
+#define AW88081_DSMCFG1_REG (0x30)
+#define AW88081_DSMCFG2_REG (0x31)
+#define AW88081_DSMCFG3_REG (0x32)
+#define AW88081_DSMCFG4_REG (0x33)
+#define AW88081_DSMCFG5_REG (0x34)
+#define AW88081_DSMCFG6_REG (0x35)
+#define AW88081_DSMCFG7_REG (0x36)
+#define AW88081_DSMCFG8_REG (0x37)
+#define AW88081_TESTIN_REG (0x38)
+#define AW88081_TESTOUT_REG (0x39)
+#define AW88081_BOPCTRL1_REG (0x40)
+#define AW88081_BOPCTRL2_REG (0x41)
+#define AW88081_BOPCTRL3_REG (0x42)
+#define AW88081_BOPSTA_REG (0x43)
+#define AW88081_PLLCTRL1_REG (0x54)
+#define AW88081_PLLCTRL2_REG (0x55)
+#define AW88081_PLLCTRL3_REG (0x56)
+#define AW88081_CDACTRL1_REG (0x57)
+#define AW88081_CDACTRL2_REG (0x58)
+#define AW88081_CDACTRL3_REG (0x59)
+#define AW88081_DITHERCFG1_REG (0x5A)
+#define AW88081_DITHERCFG2_REG (0x5B)
+#define AW88081_DITHERCFG3_REG (0x5C)
+#define AW88081_TM_REG (0x6E)
+#define AW88081_TM2_REG (0x6F)
+#define AW88081_TESTCTRL1_REG (0x70)
+#define AW88081_TESTCTRL2_REG (0x71)
+
+#define AW88081_REG_MAX (0x72)
+
+#define AW88081_UVLS_START_BIT (14)
+#define AW88081_UVLS_UVLO (1)
+#define AW88081_UVLS_UVLO_VALUE \
+ (AW88081_UVLS_UVLO << AW88081_UVLS_START_BIT)
+
+#define AW88081_SWS_START_BIT (8)
+#define AW88081_SWS_SWITCHING (1)
+#define AW88081_SWS_SWITCHING_VALUE \
+ (AW88081_SWS_SWITCHING << AW88081_SWS_START_BIT)
+
+#define AW88081_NOCLKS_START_BIT (5)
+#define AW88081_NOCLKS_NO_CLOCK (1)
+#define AW88081_NOCLKS_NO_CLOCK_VALUE \
+ (AW88081_NOCLKS_NO_CLOCK << AW88081_NOCLKS_START_BIT)
+
+#define AW88081_CLKS_START_BIT (4)
+#define AW88081_CLKS_STABLE (1)
+#define AW88081_CLKS_STABLE_VALUE \
+ (AW88081_CLKS_STABLE << AW88081_CLKS_START_BIT)
+
+#define AW88081_OCDS_START_BIT (3)
+#define AW88081_OCDS_OC (1)
+#define AW88081_OCDS_OC_VALUE \
+ (AW88081_OCDS_OC << AW88081_OCDS_START_BIT)
+
+#define AW88081_OTHS_START_BIT (1)
+#define AW88081_OTHS_OT (1)
+#define AW88081_OTHS_OT_VALUE \
+ (AW88081_OTHS_OT << AW88081_OTHS_START_BIT)
+
+#define AW88081_PLLS_START_BIT (0)
+#define AW88081_PLLS_LOCKED (1)
+#define AW88081_PLLS_LOCKED_VALUE \
+ (AW88081_PLLS_LOCKED << AW88081_PLLS_START_BIT)
+
+#define AW88081_BIT_PLL_CHECK \
+ (AW88081_CLKS_STABLE_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE)
+
+#define AW88081_BIT_SYSST_CHECK_MASK \
+ (~(AW88081_UVLS_UVLO_VALUE | \
+ AW88081_SWS_SWITCHING_VALUE | \
+ AW88081_NOCLKS_NO_CLOCK_VALUE | \
+ AW88081_CLKS_STABLE_VALUE | \
+ AW88081_OCDS_OC_VALUE | \
+ AW88081_OTHS_OT_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE))
+
+#define AW88081_NO_SWS_SYSST_CHECK \
+ (AW88081_CLKS_STABLE_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE)
+
+#define AW88081_SWS_SYSST_CHECK \
+ (AW88081_SWS_SWITCHING_VALUE | \
+ AW88081_CLKS_STABLE_VALUE | \
+ AW88081_PLLS_LOCKED_VALUE)
+
+#define AW88081_ULS_HMUTE_START_BIT (14)
+#define AW88081_ULS_HMUTE_BITS_LEN (1)
+#define AW88081_ULS_HMUTE_MASK \
+ (~(((1<<AW88081_ULS_HMUTE_BITS_LEN)-1) << AW88081_ULS_HMUTE_START_BIT))
+
+#define AW88081_ULS_HMUTE_DISABLE (0)
+#define AW88081_ULS_HMUTE_DISABLE_VALUE \
+ (AW88081_ULS_HMUTE_DISABLE << AW88081_ULS_HMUTE_START_BIT)
+
+#define AW88081_ULS_HMUTE_ENABLE (1)
+#define AW88081_ULS_HMUTE_ENABLE_VALUE \
+ (AW88081_ULS_HMUTE_ENABLE << AW88081_ULS_HMUTE_START_BIT)
+
+#define AW88081_HMUTE_START_BIT (8)
+#define AW88081_HMUTE_BITS_LEN (1)
+#define AW88081_HMUTE_MASK \
+ (~(((1<<AW88081_HMUTE_BITS_LEN)-1) << AW88081_HMUTE_START_BIT))
+
+#define AW88081_HMUTE_DISABLE (0)
+#define AW88081_HMUTE_DISABLE_VALUE \
+ (AW88081_HMUTE_DISABLE << AW88081_HMUTE_START_BIT)
+
+#define AW88081_HMUTE_ENABLE (1)
+#define AW88081_HMUTE_ENABLE_VALUE \
+ (AW88081_HMUTE_ENABLE << AW88081_HMUTE_START_BIT)
+
+#define AW88081_EN_PA_START_BIT (1)
+#define AW88081_EN_PA_BITS_LEN (1)
+#define AW88081_EN_PA_MASK \
+ (~(((1<<AW88081_EN_PA_BITS_LEN)-1) << AW88081_EN_PA_START_BIT))
+
+#define AW88081_EN_PA_WORKING (1)
+#define AW88081_EN_PA_WORKING_VALUE \
+ (AW88081_EN_PA_WORKING << AW88081_EN_PA_START_BIT)
+
+#define AW88081_EN_PA_POWER_DOWN (0)
+#define AW88081_EN_PA_POWER_DOWN_VALUE \
+ (AW88081_EN_PA_POWER_DOWN << AW88081_EN_PA_START_BIT)
+
+#define AW88081_PWDN_START_BIT (0)
+#define AW88081_PWDN_BITS_LEN (1)
+#define AW88081_PWDN_MASK \
+ (~(((1<<AW88081_PWDN_BITS_LEN)-1) << AW88081_PWDN_START_BIT))
+
+#define AW88081_PWDN_WORKING (0)
+#define AW88081_PWDN_WORKING_VALUE \
+ (AW88081_PWDN_WORKING << AW88081_PWDN_START_BIT)
+
+#define AW88081_PWDN_POWER_DOWN (1)
+#define AW88081_PWDN_POWER_DOWN_VALUE \
+ (AW88081_PWDN_POWER_DOWN << AW88081_PWDN_START_BIT)
+
+#define AW88081_VOL_START_BIT (0)
+#define AW88081_VOL_BITS_LEN (10)
+#define AW88081_VOL_MASK \
+ (~(((1<<AW88081_VOL_BITS_LEN)-1) << AW88081_VOL_START_BIT))
+
+#define AW88081_VOLUME_STEP_DB (64)
+#define AW88081_MUTE_VOL (1023)
+
+#define AW88081_I2STXEN_START_BIT (6)
+#define AW88081_I2STXEN_BITS_LEN (1)
+#define AW88081_I2STXEN_MASK \
+ (~(((1<<AW88081_I2STXEN_BITS_LEN)-1) << AW88081_I2STXEN_START_BIT))
+
+#define AW88081_I2STXEN_DISABLE (0)
+#define AW88081_I2STXEN_DISABLE_VALUE \
+ (AW88081_I2STXEN_DISABLE << AW88081_I2STXEN_START_BIT)
+
+#define AW88081_I2STXEN_ENABLE (1)
+#define AW88081_I2STXEN_ENABLE_VALUE \
+ (AW88081_I2STXEN_ENABLE << AW88081_I2STXEN_START_BIT)
+
+#define AW88081_NOISE_GATE_EN_START_BIT (13)
+#define AW88081_NOISE_GATE_EN_BITS_LEN (1)
+#define AW88081_NOISE_GATE_EN_MASK \
+ (~(((1<<AW88081_NOISE_GATE_EN_BITS_LEN)-1) << AW88081_NOISE_GATE_EN_START_BIT))
+
+#define AW88081_NOISE_GATE_EN_DISABLE (0)
+#define AW88081_NOISE_GATE_EN_DISABLE_VALUE \
+ (AW88081_NOISE_GATE_EN_DISABLE << AW88081_NOISE_GATE_EN_START_BIT)
+
+#define AW88081_NOISE_GATE_EN_ENABLE (1)
+#define AW88081_NOISE_GATE_EN_ENABLE_VALUE \
+ (AW88081_NOISE_GATE_EN_ENABLE << AW88081_NOISE_GATE_EN_START_BIT)
+
+#define AW88081_CCO_MUX_START_BIT (13)
+#define AW88081_CCO_MUX_BITS_LEN (1)
+#define AW88081_CCO_MUX_MASK \
+ (~(((1<<AW88081_CCO_MUX_BITS_LEN)-1) << AW88081_CCO_MUX_START_BIT))
+
+#define AW88081_CCO_MUX_DIVIDED (0)
+#define AW88081_CCO_MUX_DIVIDED_VALUE \
+ (AW88081_CCO_MUX_DIVIDED << AW88081_CCO_MUX_START_BIT)
+
+#define AW88081_CCO_MUX_BYPASS (1)
+#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)
+
+#define AW88081_I2C_NAME "aw88081"
+#define AW88081_CHIP_ID 0x2116
+
+#define AW88081_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_96000)
+#define AW88081_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define FADE_TIME_MAX 100000
+
+#define AW88081_DEV_DEFAULT_CH (0)
+#define AW88081_ACF_FILE "aw88081_acf.bin"
+#define AW88081_DEV_SYSST_CHECK_MAX (10)
+#define AW88081_SOFT_RESET_VALUE (0x55aa)
+
+#define AW88081_INIT_PROFILE (0)
+
+#define AW88081_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 {
+ AW88081_SYNC_START = 0,
+ AW88081_ASYNC_START,
+};
+
+enum {
+ AW88081_500_US = 500,
+ AW88081_1000_US = 1000,
+ AW88081_2000_US = 2000,
+ AW88081_5000_US = 5000,
+};
+
+enum {
+ AW88081_DEV_PW_OFF = 0,
+ AW88081_DEV_PW_ON,
+};
+
+enum {
+ AW88081_DEV_FW_FAILED = 0,
+ AW88081_DEV_FW_OK,
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c
new file mode 100644
index 000000000000..daee4de9e3b0
--- /dev/null
+++ b/sound/soc/codecs/aw88166.c
@@ -0,0 +1,1815 @@
+// 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/minmax.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 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;
+
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, base);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i += AW88166_MAX_RAM_WRITE_BYTE_SIZE) {
+ tmp_len = min(len - i, AW88166_MAX_RAM_WRITE_BYTE_SIZE);
+ ret = regmap_raw_write(aw_dev->regmap, AW88166_DSPMDAT_REG,
+ &data[i], tmp_len);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ u32 dsp_ra;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88166_DSP_REG_CFG_ADPZ_RA,
+ &dsp_ra, AW_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;
+
+ /* read dsp_rom_check_reg */
+ aw_dev_dsp_read(aw_dev, AW88166_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
+ 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);
+ return -EPERM;
+ }
+
+ /* check dsp_cfg_base_addr */
+ aw_dev_dsp_write(aw_dev, AW88166_DSP_CFG_ADDR,
+ AW88166_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
+ aw_dev_dsp_read(aw_dev, AW88166_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
+ 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);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+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_dfl_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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ char *prof_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;
+
+ 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");
+ return 0;
+ }
+
+ strscpy(uinfo->value.enumerated.name, prof_name);
+
+ return 0;
+}
+
+static int aw88166_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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_kcontrol_chip(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..9f3f47a7003e
--- /dev/null
+++ b/sound/soc/codecs/aw88166.h
@@ -0,0 +1,529 @@
+// 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_SYNC_START = 0,
+ AW88166_ASYNC_START,
+};
+
+enum {
+ AW88166_RECORD_SEC_DATA = 0,
+ AW88166_RECOVERY_SEC_DATA = 1,
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
new file mode 100644
index 000000000000..8f37bfb974ae
--- /dev/null
+++ b/sound/soc/codecs/aw88261.c
@@ -0,0 +1,1282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88261.c -- AW88261 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "aw88261.h"
+#include "aw88395/aw88395_data_type.h"
+#include "aw88395/aw88395_device.h"
+
+static const struct regmap_config aw88261_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88261_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int real_value, volume;
+ unsigned int reg_value;
+
+ volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL);
+ real_value = DB_TO_REG_VAL(volume);
+
+ regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, &reg_value);
+
+ real_value = (real_value | (reg_value & AW88261_VOL_START_MASK));
+
+ dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value);
+
+ regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value);
+}
+
+static void aw88261_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int 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) {
+ aw88261_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw88261_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time,
+ aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw88261_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw88261_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) {
+ aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) {
+ aw88261_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88261_MUTE_VOL) {
+ aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ if (flag)
+ regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG,
+ ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG,
+ ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_DISABLE_VALUE);
+}
+
+static void aw88261_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ if (pwd)
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_PWDN_MASK, AW88261_PWDN_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_PWDN_MASK, AW88261_PWDN_WORKING_VALUE);
+}
+
+static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ if (amppd)
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_AMPPD_MASK, AW88261_AMPPD_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_AMPPD_MASK, AW88261_AMPPD_WORKING_VALUE);
+}
+
+static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw88261_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE);
+ aw88261_dev_fade_in(aw_dev);
+ }
+}
+
+static void aw88261_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ unsigned int int_status;
+
+ /* read int status and clear */
+ regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status);
+ /* make sure int status is clear */
+ regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status);
+
+ dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status);
+}
+
+static int aw88261_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88261_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ return ret;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88261_CCO_MUX_MASK);
+ if (reg_val == AW88261_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, AW88261_PLLCTRL1_REG,
+ ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88261_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis signal check error");
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
+ ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88261_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int aw88261_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw88261_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw88261_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int aw88261_dev_check_sysst(struct aw_device *aw_dev)
+{
+ unsigned int check_val;
+ unsigned int reg_val;
+ int ret, i;
+
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK)
+ & AW88261_BIT_SYSST_CHECK;
+ if (check_val != AW88261_BIT_SYSST_CHECK) {
+ dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
+ reg_val, AW88261_BIT_SYSST_CHECK);
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
+{
+ if (uls_hmute)
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_ULS_HMUTE_MASK,
+ AW88261_ULS_HMUTE_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_ULS_HMUTE_MASK,
+ AW88261_ULS_HMUTE_DISABLE_VALUE);
+}
+
+static void aw88261_reg_force_set(struct aw88261 *aw88261)
+{
+ if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) {
+ /* set FORCE_PWM */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG,
+ AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE);
+ /* set BOOST_OS_WIDTH */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG,
+ AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE);
+ /* set BURST_LOOPR */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG,
+ AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE);
+ /* set RSQN_DLY */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG,
+ AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE);
+ /* set BURST_SSMODE */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG,
+ AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE);
+ /* set BST_BURST */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG,
+ AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE);
+ } else {
+ dev_dbg(aw88261->aw_pa->dev, "needn't set reg value");
+ }
+}
+
+static int aw88261_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk)
+{
+ u16 reg_icalk, reg_icalkl;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRH4_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_icalk = reg_val & (~AW88261_EF_ISN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_icalkl = reg_val & (~AW88261_EF_ISN_GESLP_L_MASK);
+
+ reg_icalk = (reg_icalk >> AW88261_ICALK_SHIFT) & (reg_icalkl >> AW88261_ICALKL_SHIFT);
+
+ if (reg_icalk & (~AW88261_EF_ISN_GESLP_SIGN_MASK))
+ reg_icalk = reg_icalk | ~AW88261_EF_ISN_GESLP_NEG;
+
+ *icalk = (int16_t)reg_icalk;
+
+ return ret;
+}
+
+static int aw88261_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk)
+{
+ u16 reg_vcalk, reg_vcalkl;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_vcalk = (u16)reg_val & (~AW88261_EF_VSN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_vcalkl = (u16)reg_val & (~AW88261_EF_VSN_GESLP_L_MASK);
+
+ reg_vcalk = (reg_vcalk >> AW88261_VCALK_SHIFT) & (reg_vcalkl >> AW88261_VCALKL_SHIFT);
+
+ if (reg_vcalk & AW88261_EF_VSN_GESLP_SIGN_MASK)
+ reg_vcalk = reg_vcalk | (~AW88261_EF_VSN_GESLP_NEG);
+ *vcalk = (int16_t)reg_vcalk;
+
+ return ret;
+}
+
+static int aw88261_dev_set_vcalb(struct aw_device *aw_dev)
+{
+ int16_t icalk_val, vcalk_val;
+ int icalk, vcalk, vcalb;
+ u32 reg_val;
+ int ret;
+
+ ret = aw88261_dev_get_icalk(aw_dev, &icalk_val);
+ if (ret)
+ return ret;
+
+ ret = aw88261_dev_get_vcalk(aw_dev, &vcalk_val);
+ if (ret)
+ return ret;
+
+ icalk = AW88261_CABL_BASE_VALUE + AW88261_ICABLK_FACTOR * icalk_val;
+ vcalk = AW88261_CABL_BASE_VALUE + AW88261_VCABLK_FACTOR * vcalk_val;
+ if (!vcalk)
+ return -EINVAL;
+
+ vcalb = AW88261_VCAL_FACTOR * icalk / vcalk;
+ reg_val = (unsigned int)vcalb;
+
+ dev_dbg(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x",
+ icalk, vcalk, vcalb, reg_val);
+ ret = regmap_write(aw_dev->regmap, AW88261_VSNTM1_REG, reg_val);
+
+ return ret;
+}
+
+static int aw88261_dev_reg_update(struct aw88261 *aw88261,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int read_val, efcheck_val, read_vol;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u16 reg_val;
+ u8 reg_addr;
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ if (reg_addr == AW88261_SYSCTRL_REG) {
+ aw88261->amppd_st = reg_val & (~AW88261_AMPPD_MASK);
+ ret = regmap_read(aw_dev->regmap, reg_addr, &read_val);
+ if (ret)
+ break;
+
+ read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) |
+ (~AW88261_HMUTE_MASK);
+ reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK);
+ reg_val |= read_val;
+
+ /* enable uls hmute */
+ reg_val &= AW88261_ULS_HMUTE_MASK;
+ reg_val |= AW88261_ULS_HMUTE_ENABLE_VALUE;
+ }
+
+ if (reg_addr == AW88261_DBGCTRL_REG) {
+ efcheck_val = reg_val & (~AW88261_EF_DBMD_MASK);
+ if (efcheck_val == AW88261_OR_VALUE)
+ aw88261->efuse_check = AW88261_EF_OR_CHECK;
+ else
+ aw88261->efuse_check = AW88261_EF_AND_CHECK;
+ }
+
+ /* i2stxen */
+ if (reg_addr == AW88261_I2SCTRL3_REG) {
+ /* close tx */
+ reg_val &= AW88261_I2STXEN_MASK;
+ reg_val |= AW88261_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88261_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88261_VOL_MASK)) >>
+ AW88261_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume =
+ REG_VAL_TO_DB(read_vol);
+ }
+
+ if (reg_addr == AW88261_VSNTM1_REG)
+ continue;
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ break;
+ }
+
+ ret = aw88261_dev_set_vcalb(aw_dev);
+ if (ret)
+ return ret;
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+
+ /* keep min volume */
+ aw88261_dev_set_volume(aw_dev, vol_desc->mute_volume);
+
+ return ret;
+}
+
+static int aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
+}
+
+static int aw88261_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 aw88261_dev_fw_update(struct aw88261 *aw88261)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ ret = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret) {
+ dev_err(aw_dev->dev, "get prof name failed");
+ return -EINVAL;
+ }
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88261_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 = aw88261_dev_reg_update(aw88261, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return ret;
+}
+
+static int aw88261_dev_start(struct aw88261 *aw88261)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88261_DEV_PW_ON) {
+ dev_info(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ /* power on */
+ aw88261_dev_pwd(aw_dev, false);
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+
+ ret = aw88261_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw88261_dev_amppd(aw_dev, false);
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw88261_dev_check_sysst(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ /* enable tx feedback */
+ aw88261_dev_i2s_tx_enable(aw_dev, true);
+
+ if (aw88261->amppd_st)
+ aw88261_dev_amppd(aw_dev, true);
+
+ aw88261_reg_force_set(aw88261);
+
+ /* close uls mute */
+ aw88261_dev_uls_hmute(aw_dev, false);
+
+ /* close mute */
+ if (!aw88261->mute_st)
+ aw88261_dev_mute(aw_dev, false);
+
+ /* clear inturrupt */
+ aw88261_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88261_DEV_PW_ON;
+
+ return 0;
+
+sysst_check_fail:
+ aw88261_dev_i2s_tx_enable(aw_dev, false);
+ aw88261_dev_clear_int_status(aw_dev);
+ aw88261_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw88261_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88261_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw88261_dev_stop(struct aw_device *aw_dev)
+{
+ if (aw_dev->status == AW88261_DEV_PW_OFF) {
+ dev_info(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88261_DEV_PW_OFF;
+
+ /* clear inturrupt */
+ aw88261_dev_clear_int_status(aw_dev);
+
+ aw88261_dev_uls_hmute(aw_dev, true);
+ /* set mute */
+ aw88261_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw88261_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 100);
+
+ /* enable amppd */
+ aw88261_dev_amppd(aw_dev, true);
+
+ /* set power down */
+ aw88261_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88261_reg_update(struct aw88261 *aw88261, bool force)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int ret;
+
+ if (force) {
+ ret = regmap_write(aw_dev->regmap,
+ AW88261_ID_REG, AW88261_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw88261_dev_fw_update(aw88261);
+ if (ret)
+ return ret;
+ } else {
+ if (aw_dev->prof_cur != aw_dev->prof_index) {
+ ret = aw88261_dev_fw_update(aw88261);
+ if (ret)
+ return ret;
+ } else {
+ ret = 0;
+ }
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return ret;
+}
+
+static void aw88261_start_pa(struct aw88261 *aw88261)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88261_START_RETRIES; i++) {
+ ret = aw88261_reg_update(aw88261, aw88261->phase_sync);
+ if (ret) {
+ dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i);
+ continue;
+ }
+ ret = aw88261_dev_start(aw88261);
+ if (ret) {
+ dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i);
+ continue;
+ } else {
+ dev_info(aw88261->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+static void aw88261_startup_work(struct work_struct *work)
+{
+ struct aw88261 *aw88261 =
+ container_of(work, struct aw88261, start_work.work);
+
+ mutex_lock(&aw88261->lock);
+ aw88261_start_pa(aw88261);
+ mutex_unlock(&aw88261->lock);
+}
+
+static void aw88261_start(struct aw88261 *aw88261, bool sync_start)
+{
+ if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK)
+ return;
+
+ if (aw88261->aw_pa->status == AW88261_DEV_PW_ON)
+ return;
+
+ if (sync_start == AW88261_SYNC_START)
+ aw88261_start_pa(aw88261);
+ else
+ queue_delayed_work(system_dfl_wq,
+ &aw88261->start_work,
+ AW88261_START_WORK_DELAY_MS);
+}
+
+static struct snd_soc_dai_driver aw88261_dai[] = {
+ {
+ .name = "aw88261-aif",
+ .id = 1,
+ .playback = {
+ .stream_name = "Speaker_Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88261_RATES,
+ .formats = AW88261_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Speaker_Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88261_RATES,
+ .formats = AW88261_FORMATS,
+ },
+ },
+};
+
+static int aw88261_get_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88261->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+ return 0;
+}
+
+static int aw88261_set_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88261->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 aw88261_get_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88261->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+ return 0;
+}
+
+static int aw88261_set_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88261->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 aw88261_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 -EPERM;
+
+ aw_dev->prof_index = index;
+
+ return 0;
+}
+
+static int aw88261_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ char *prof_name;
+ int count, ret;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw88261->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;
+
+ count = uinfo->value.enumerated.item;
+
+ ret = aw88261_dev_get_prof_name(aw88261->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null");
+ return 0;
+ }
+
+ strscpy(uinfo->value.enumerated.name, prof_name);
+
+ return 0;
+}
+
+static int aw88261_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88261->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ /* pa stop or stopping just set profile */
+ mutex_lock(&aw88261->lock);
+ ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]);
+ if (ret) {
+ dev_dbg(codec->dev, "profile index does not change");
+ mutex_unlock(&aw88261->lock);
+ return 0;
+ }
+
+ if (aw88261->aw_pa->status) {
+ aw88261_dev_stop(aw88261->aw_pa);
+ aw88261_start(aw88261, AW88261_SYNC_START);
+ }
+
+ mutex_unlock(&aw88261->lock);
+
+ return 1;
+}
+
+static int aw88261_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc;
+
+ ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+ return 0;
+}
+
+static int aw88261_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88261->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;
+ aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step;
+
+ return 0;
+}
+
+static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88261 *aw88261 = 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 (aw88261->aw_pa->fade_step != value) {
+ aw88261->aw_pa->fade_step = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new aw88261_controls[] = {
+ SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG,
+ 6, AW88261_MUTE_VOL, 0, aw88261_volume_get,
+ aw88261_volume_set),
+ SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0,
+ aw88261_get_fade_step, aw88261_set_fade_step),
+ SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88261_get_fade_in_time, aw88261_set_fade_in_time),
+ SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88261_get_fade_out_time, aw88261_set_fade_out_time),
+ AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info,
+ aw88261_profile_get, aw88261_profile_set),
+};
+
+static int aw88261_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 aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&aw88261->lock);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ aw88261_start(aw88261, AW88261_ASYNC_START);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ aw88261_dev_stop(aw88261->aw_pa);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&aw88261->lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88261_dapm_widgets[] = {
+ /* playback */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0,
+ aw88261_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 aw88261_audio_map[] = {
+ {"DAC Output", NULL, "AIF_RX"},
+ {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88261_frcset_check(struct aw88261 *aw88261)
+{
+ unsigned int reg_val;
+ u16 temh, teml, tem;
+ int ret;
+
+ ret = regmap_read(aw88261->regmap, AW88261_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+ temh = ((u16)reg_val & (~AW88261_TEMH_MASK));
+
+ ret = regmap_read(aw88261->regmap, AW88261_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+ teml = ((u16)reg_val & (~AW88261_TEML_MASK));
+
+ if (aw88261->efuse_check == AW88261_EF_OR_CHECK)
+ tem = (temh | teml);
+ else
+ tem = (temh & teml);
+
+ if (tem == AW88261_DEFAULT_CFG)
+ aw88261->frcset_en = AW88261_FRCSET_ENABLE;
+ else
+ aw88261->frcset_en = AW88261_FRCSET_DISABLE;
+
+ dev_dbg(aw88261->aw_pa->dev, "tem is 0x%04x, frcset_en is %d",
+ tem, aw88261->frcset_en);
+
+ return ret;
+}
+
+static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88261_ID_REG, AW88261_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ aw_dev->fade_in_time = AW88261_500_US;
+ aw_dev->fade_out_time = AW88261_500_US;
+ aw_dev->prof_cur = AW88261_INIT_PROFILE;
+ aw_dev->prof_index = AW88261_INIT_PROFILE;
+
+ ret = aw88261_dev_fw_update(aw88261);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = aw88261_frcset_check(aw88261);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw88261_frcset_check ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88261_dev_clear_int_status(aw_dev);
+
+ aw88261_dev_uls_hmute(aw_dev, true);
+
+ aw88261_dev_mute(aw_dev, true);
+
+ aw88261_dev_i2s_tx_enable(aw_dev, false);
+
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 100);
+
+ aw88261_dev_amppd(aw_dev, true);
+
+ aw88261_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88261_request_firmware_file(struct aw88261 *aw88261)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev);
+ if (ret)
+ return dev_err_probe(aw88261->aw_pa->dev, ret,
+ "load [%s] failed!", AW88261_ACF_FILE);
+
+ dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88261_ACF_FILE, cont ? cont->size : 0);
+
+ aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
+ if (!aw88261->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+ aw88261->aw_cfg->len = (int)cont->size;
+ memcpy(aw88261->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg);
+ if (ret) {
+ dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw88261->lock);
+ /* aw device init */
+ ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
+ if (ret)
+ dev_err(aw88261->aw_pa->dev, "dev init failed");
+ mutex_unlock(&aw88261->lock);
+
+ return ret;
+}
+
+static int aw88261_codec_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work);
+
+ ret = aw88261_request_firmware_file(aw88261);
+ if (ret)
+ return dev_err_probe(aw88261->aw_pa->dev, ret,
+ "aw88261_request_firmware_file failed\n");
+
+ /* add widgets */
+ ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets,
+ ARRAY_SIZE(aw88261_dapm_widgets));
+ if (ret)
+ return ret;
+
+ /* add route */
+ ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map,
+ ARRAY_SIZE(aw88261_audio_map));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_add_component_controls(component, aw88261_controls,
+ ARRAY_SIZE(aw88261_controls));
+
+ return ret;
+}
+
+static void aw88261_codec_remove(struct snd_soc_component *aw_codec)
+{
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec);
+
+ cancel_delayed_work_sync(&aw88261->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88261 = {
+ .probe = aw88261_codec_probe,
+ .remove = aw88261_codec_remove,
+};
+
+static void aw88261_parse_channel_dt(struct aw88261 *aw88261)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value = AW88261_DEV_DEFAULT_CH;
+
+ of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ aw88261->phase_sync = of_property_read_bool(np, "awinic,sync-flag");
+
+ aw_dev->channel = channel_value;
+}
+
+static int aw88261_init(struct aw88261 *aw88261, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ /* read chip id */
+ ret = regmap_read(regmap, AW88261_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88261_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device");
+ return -ENXIO;
+ }
+
+ dev_info(&i2c->dev, "chip id = %x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+
+ aw88261->aw_pa = aw_dev;
+ aw_dev->i2c = i2c;
+ aw_dev->regmap = regmap;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->chip_id = AW88261_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 = 0;
+ aw_dev->fw_status = AW88261_DEV_FW_FAILED;
+ aw_dev->fade_step = AW88261_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE;
+ aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL;
+ aw88261_parse_channel_dt(aw88261);
+
+ return ret;
+}
+
+static int aw88261_i2c_probe(struct i2c_client *i2c)
+{
+ struct aw88261 *aw88261;
+ int ret;
+
+ ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
+ if (!ret)
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
+
+ aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL);
+ if (!aw88261)
+ return -ENOMEM;
+
+ mutex_init(&aw88261->lock);
+
+ i2c_set_clientdata(i2c, aw88261);
+
+ aw88261->regmap = devm_regmap_init_i2c(i2c, &aw88261_remap_config);
+ if (IS_ERR(aw88261->regmap)) {
+ ret = PTR_ERR(aw88261->regmap);
+ return dev_err_probe(&i2c->dev, ret, "failed to init regmap: %d\n", ret);
+ }
+
+ /* aw pa init */
+ ret = aw88261_init(aw88261, i2c, aw88261->regmap);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw88261,
+ aw88261_dai, ARRAY_SIZE(aw88261_dai));
+ if (ret)
+ dev_err(&i2c->dev, "failed to register aw88261: %d", ret);
+
+ return ret;
+}
+
+static const struct i2c_device_id aw88261_i2c_id[] = {
+ { AW88261_I2C_NAME },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id);
+
+static struct i2c_driver aw88261_i2c_driver = {
+ .driver = {
+ .name = AW88261_I2C_NAME,
+ },
+ .probe = aw88261_i2c_probe,
+ .id_table = aw88261_i2c_id,
+};
+module_i2c_driver(aw88261_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88261 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h
new file mode 100644
index 000000000000..734d0f93ced9
--- /dev/null
+++ b/sound/soc/codecs/aw88261.h
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88261.h -- AW88261 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88261_H__
+#define __AW88261_H__
+
+#define AW88261_ID_REG (0x00)
+#define AW88261_SYSST_REG (0x01)
+#define AW88261_SYSINT_REG (0x02)
+#define AW88261_SYSINTM_REG (0x03)
+#define AW88261_SYSCTRL_REG (0x04)
+#define AW88261_SYSCTRL2_REG (0x05)
+#define AW88261_I2SCTRL1_REG (0x06)
+#define AW88261_I2SCTRL2_REG (0x07)
+#define AW88261_I2SCTRL3_REG (0x08)
+#define AW88261_DACCFG1_REG (0x09)
+#define AW88261_DACCFG2_REG (0x0A)
+#define AW88261_DACCFG3_REG (0x0B)
+#define AW88261_DACCFG4_REG (0x0C)
+#define AW88261_DACCFG5_REG (0x0D)
+#define AW88261_DACCFG6_REG (0x0E)
+#define AW88261_DACCFG7_REG (0x0F)
+#define AW88261_DACCFG8_REG (0x10)
+#define AW88261_PWMCTRL1_REG (0x11)
+#define AW88261_PWMCTRL2_REG (0x12)
+#define AW88261_I2SCFG1_REG (0x13)
+#define AW88261_DBGCTRL_REG (0x14)
+#define AW88261_DACCFG9_REG (0x15)
+#define AW88261_DACCFG10_REG (0x16)
+#define AW88261_DACST_REG (0x20)
+#define AW88261_VBAT_REG (0x21)
+#define AW88261_TEMP_REG (0x22)
+#define AW88261_PVDD_REG (0x23)
+#define AW88261_ISNDAT_REG (0x24)
+#define AW88261_VSNDAT_REG (0x25)
+#define AW88261_I2SINT_REG (0x26)
+#define AW88261_I2SCAPCNT_REG (0x27)
+#define AW88261_ANASTA1_REG (0x28)
+#define AW88261_ANASTA2_REG (0x29)
+#define AW88261_ANASTA3_REG (0x2A)
+#define AW88261_TESTDET_REG (0x2B)
+#define AW88261_DSMCFG1_REG (0x30)
+#define AW88261_DSMCFG2_REG (0x31)
+#define AW88261_DSMCFG3_REG (0x32)
+#define AW88261_DSMCFG4_REG (0x33)
+#define AW88261_DSMCFG5_REG (0x34)
+#define AW88261_DSMCFG6_REG (0x35)
+#define AW88261_DSMCFG7_REG (0x36)
+#define AW88261_DSMCFG8_REG (0x37)
+#define AW88261_TESTIN_REG (0x38)
+#define AW88261_TESTOUT_REG (0x39)
+#define AW88261_SADCCTRL1_REG (0x3A)
+#define AW88261_SADCCTRL2_REG (0x3B)
+#define AW88261_SADCCTRL3_REG (0x3C)
+#define AW88261_SADCCTRL4_REG (0x3D)
+#define AW88261_SADCCTRL5_REG (0x3E)
+#define AW88261_SADCCTRL6_REG (0x3F)
+#define AW88261_SADCCTRL7_REG (0x40)
+#define AW88261_VSNTM1_REG (0x50)
+#define AW88261_VSNTM2_REG (0x51)
+#define AW88261_ISNCTRL1_REG (0x52)
+#define AW88261_ISNCTRL2_REG (0x53)
+#define AW88261_PLLCTRL1_REG (0x54)
+#define AW88261_PLLCTRL2_REG (0x55)
+#define AW88261_PLLCTRL3_REG (0x56)
+#define AW88261_CDACTRL1_REG (0x57)
+#define AW88261_CDACTRL2_REG (0x58)
+#define AW88261_DITHERCFG1_REG (0x59)
+#define AW88261_DITHERCFG2_REG (0x5A)
+#define AW88261_DITHERCFG3_REG (0x5B)
+#define AW88261_CPCTRL_REG (0x5C)
+#define AW88261_BSTCTRL1_REG (0x60)
+#define AW88261_BSTCTRL2_REG (0x61)
+#define AW88261_BSTCTRL3_REG (0x62)
+#define AW88261_BSTCTRL4_REG (0x63)
+#define AW88261_BSTCTRL5_REG (0x64)
+#define AW88261_BSTCTRL6_REG (0x65)
+#define AW88261_BSTCTRL7_REG (0x66)
+#define AW88261_BSTCTRL8_REG (0x67)
+#define AW88261_BSTCTRL9_REG (0x68)
+#define AW88261_TM_REG (0x6F)
+#define AW88261_TESTCTRL1_REG (0x70)
+#define AW88261_TESTCTRL2_REG (0x71)
+#define AW88261_EFCTRL1_REG (0x72)
+#define AW88261_EFCTRL2_REG (0x73)
+#define AW88261_EFWH_REG (0x74)
+#define AW88261_EFWM2_REG (0x75)
+#define AW88261_EFWM1_REG (0x76)
+#define AW88261_EFWL_REG (0x77)
+#define AW88261_EFRH4_REG (0x78)
+#define AW88261_EFRH3_REG (0x79)
+#define AW88261_EFRH2_REG (0x7A)
+#define AW88261_EFRH1_REG (0x7B)
+#define AW88261_EFRL4_REG (0x7C)
+#define AW88261_EFRL3_REG (0x7D)
+#define AW88261_EFRL2_REG (0x7E)
+#define AW88261_EFRL1_REG (0x7F)
+
+#define AW88261_REG_MAX (0x80)
+#define AW88261_EF_DBMD_MASK (0xfff7)
+#define AW88261_OR_VALUE (0x0008)
+
+#define AW88261_TEMH_MASK (0x83ff)
+#define AW88261_TEML_MASK (0x83ff)
+#define AW88261_DEFAULT_CFG (0x0000)
+
+#define AW88261_ICALK_SHIFT (0)
+#define AW88261_ICALKL_SHIFT (0)
+#define AW88261_VCALK_SHIFT (0)
+#define AW88261_VCALKL_SHIFT (0)
+
+#define AW88261_AMPPD_START_BIT (1)
+#define AW88261_AMPPD_BITS_LEN (1)
+#define AW88261_AMPPD_MASK \
+ (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT))
+
+#define AW88261_UVLS_START_BIT (14)
+#define AW88261_UVLS_NORMAL (0)
+#define AW88261_UVLS_NORMAL_VALUE \
+ (AW88261_UVLS_NORMAL << AW88261_UVLS_START_BIT)
+
+#define AW88261_BSTOCS_START_BIT (11)
+#define AW88261_BSTOCS_OVER_CURRENT (1)
+#define AW88261_BSTOCS_OVER_CURRENT_VALUE \
+ (AW88261_BSTOCS_OVER_CURRENT << AW88261_BSTOCS_START_BIT)
+
+#define AW88261_BSTS_START_BIT (9)
+#define AW88261_BSTS_FINISHED (1)
+#define AW88261_BSTS_FINISHED_VALUE \
+ (AW88261_BSTS_FINISHED << AW88261_BSTS_START_BIT)
+
+#define AW88261_SWS_START_BIT (8)
+#define AW88261_SWS_SWITCHING (1)
+#define AW88261_SWS_SWITCHING_VALUE \
+ (AW88261_SWS_SWITCHING << AW88261_SWS_START_BIT)
+
+#define AW88261_NOCLKS_START_BIT (5)
+#define AW88261_NOCLKS_NO_CLOCK (1)
+#define AW88261_NOCLKS_NO_CLOCK_VALUE \
+ (AW88261_NOCLKS_NO_CLOCK << AW88261_NOCLKS_START_BIT)
+
+#define AW88261_CLKS_START_BIT (4)
+#define AW88261_CLKS_STABLE (1)
+#define AW88261_CLKS_STABLE_VALUE \
+ (AW88261_CLKS_STABLE << AW88261_CLKS_START_BIT)
+
+#define AW88261_OCDS_START_BIT (3)
+#define AW88261_OCDS_OC (1)
+#define AW88261_OCDS_OC_VALUE \
+ (AW88261_OCDS_OC << AW88261_OCDS_START_BIT)
+
+#define AW88261_OTHS_START_BIT (1)
+#define AW88261_OTHS_OT (1)
+#define AW88261_OTHS_OT_VALUE \
+ (AW88261_OTHS_OT << AW88261_OTHS_START_BIT)
+
+#define AW88261_PLLS_START_BIT (0)
+#define AW88261_PLLS_LOCKED (1)
+#define AW88261_PLLS_LOCKED_VALUE \
+ (AW88261_PLLS_LOCKED << AW88261_PLLS_START_BIT)
+
+#define AW88261_BIT_PLL_CHECK \
+ (AW88261_CLKS_STABLE_VALUE | \
+ AW88261_PLLS_LOCKED_VALUE)
+
+#define AW88261_BIT_SYSST_CHECK_MASK \
+ (~(AW88261_UVLS_NORMAL_VALUE | \
+ AW88261_BSTOCS_OVER_CURRENT_VALUE | \
+ AW88261_BSTS_FINISHED_VALUE | \
+ AW88261_SWS_SWITCHING_VALUE | \
+ AW88261_NOCLKS_NO_CLOCK_VALUE | \
+ AW88261_CLKS_STABLE_VALUE | \
+ AW88261_OCDS_OC_VALUE | \
+ AW88261_OTHS_OT_VALUE | \
+ AW88261_PLLS_LOCKED_VALUE))
+
+#define AW88261_BIT_SYSST_CHECK \
+ (AW88261_BSTS_FINISHED_VALUE | \
+ AW88261_SWS_SWITCHING_VALUE | \
+ AW88261_CLKS_STABLE_VALUE | \
+ AW88261_PLLS_LOCKED_VALUE)
+
+#define AW88261_ULS_HMUTE_START_BIT (14)
+#define AW88261_ULS_HMUTE_BITS_LEN (1)
+#define AW88261_ULS_HMUTE_MASK \
+ (~(((1<<AW88261_ULS_HMUTE_BITS_LEN)-1) << AW88261_ULS_HMUTE_START_BIT))
+
+#define AW88261_ULS_HMUTE_DISABLE (0)
+#define AW88261_ULS_HMUTE_DISABLE_VALUE \
+ (AW88261_ULS_HMUTE_DISABLE << AW88261_ULS_HMUTE_START_BIT)
+
+#define AW88261_ULS_HMUTE_ENABLE (1)
+#define AW88261_ULS_HMUTE_ENABLE_VALUE \
+ (AW88261_ULS_HMUTE_ENABLE << AW88261_ULS_HMUTE_START_BIT)
+
+#define AW88261_HMUTE_START_BIT (8)
+#define AW88261_HMUTE_BITS_LEN (1)
+#define AW88261_HMUTE_MASK \
+ (~(((1<<AW88261_HMUTE_BITS_LEN)-1) << AW88261_HMUTE_START_BIT))
+
+#define AW88261_HMUTE_DISABLE (0)
+#define AW88261_HMUTE_DISABLE_VALUE \
+ (AW88261_HMUTE_DISABLE << AW88261_HMUTE_START_BIT)
+
+#define AW88261_HMUTE_ENABLE (1)
+#define AW88261_HMUTE_ENABLE_VALUE \
+ (AW88261_HMUTE_ENABLE << AW88261_HMUTE_START_BIT)
+
+#define AW88261_AMPPD_START_BIT (1)
+#define AW88261_AMPPD_BITS_LEN (1)
+#define AW88261_AMPPD_MASK \
+ (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT))
+
+#define AW88261_AMPPD_WORKING (0)
+#define AW88261_AMPPD_WORKING_VALUE \
+ (AW88261_AMPPD_WORKING << AW88261_AMPPD_START_BIT)
+
+#define AW88261_AMPPD_POWER_DOWN (1)
+#define AW88261_AMPPD_POWER_DOWN_VALUE \
+ (AW88261_AMPPD_POWER_DOWN << AW88261_AMPPD_START_BIT)
+
+#define AW88261_PWDN_START_BIT (0)
+#define AW88261_PWDN_BITS_LEN (1)
+#define AW88261_PWDN_MASK \
+ (~(((1<<AW88261_PWDN_BITS_LEN)-1) << AW88261_PWDN_START_BIT))
+
+#define AW88261_PWDN_WORKING (0)
+#define AW88261_PWDN_WORKING_VALUE \
+ (AW88261_PWDN_WORKING << AW88261_PWDN_START_BIT)
+
+#define AW88261_PWDN_POWER_DOWN (1)
+#define AW88261_PWDN_POWER_DOWN_VALUE \
+ (AW88261_PWDN_POWER_DOWN << AW88261_PWDN_START_BIT)
+
+#define AW88261_MUTE_VOL (90 * 8)
+#define AW88261_VOLUME_STEP_DB (6 * 8)
+
+#define AW88261_VOL_6DB_START (6)
+
+#define AW88261_VOL_START_BIT (0)
+#define AW88261_VOL_BITS_LEN (10)
+#define AW88261_VOL_MASK \
+ (~(((1<<AW88261_VOL_BITS_LEN)-1) << AW88261_VOL_START_BIT))
+
+#define AW88261_VOL_DEFAULT_VALUE (0)
+
+#define AW88261_I2STXEN_START_BIT (6)
+#define AW88261_I2STXEN_BITS_LEN (1)
+#define AW88261_I2STXEN_MASK \
+ (~(((1<<AW88261_I2STXEN_BITS_LEN)-1) << AW88261_I2STXEN_START_BIT))
+
+#define AW88261_I2STXEN_DISABLE (0)
+#define AW88261_I2STXEN_DISABLE_VALUE \
+ (AW88261_I2STXEN_DISABLE << AW88261_I2STXEN_START_BIT)
+
+#define AW88261_I2STXEN_ENABLE (1)
+#define AW88261_I2STXEN_ENABLE_VALUE \
+ (AW88261_I2STXEN_ENABLE << AW88261_I2STXEN_START_BIT)
+
+#define AW88261_CCO_MUX_START_BIT (14)
+#define AW88261_CCO_MUX_BITS_LEN (1)
+#define AW88261_CCO_MUX_MASK \
+ (~(((1<<AW88261_CCO_MUX_BITS_LEN)-1) << AW88261_CCO_MUX_START_BIT))
+
+#define AW88261_CCO_MUX_DIVIDED (0)
+#define AW88261_CCO_MUX_DIVIDED_VALUE \
+ (AW88261_CCO_MUX_DIVIDED << AW88261_CCO_MUX_START_BIT)
+
+#define AW88261_CCO_MUX_BYPASS (1)
+#define AW88261_CCO_MUX_BYPASS_VALUE \
+ (AW88261_CCO_MUX_BYPASS << AW88261_CCO_MUX_START_BIT)
+
+#define AW88261_EF_VSN_GESLP_H_START_BIT (0)
+#define AW88261_EF_VSN_GESLP_H_BITS_LEN (10)
+#define AW88261_EF_VSN_GESLP_H_MASK \
+ (~(((1<<AW88261_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_H_START_BIT))
+
+#define AW88261_EF_VSN_GESLP_L_START_BIT (0)
+#define AW88261_EF_VSN_GESLP_L_BITS_LEN (10)
+#define AW88261_EF_VSN_GESLP_L_MASK \
+ (~(((1<<AW88261_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_L_START_BIT))
+
+#define AW88261_FORCE_PWM_START_BIT (12)
+#define AW88261_FORCE_PWM_BITS_LEN (1)
+#define AW88261_FORCE_PWM_MASK \
+ (~(((1<<AW88261_FORCE_PWM_BITS_LEN)-1) << AW88261_FORCE_PWM_START_BIT))
+
+#define AW88261_FORCE_PWM_FORCEMINUS_PWM (1)
+#define AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE \
+ (AW88261_FORCE_PWM_FORCEMINUS_PWM << AW88261_FORCE_PWM_START_BIT)
+
+#define AW88261_BST_OS_WIDTH_START_BIT (0)
+#define AW88261_BST_OS_WIDTH_BITS_LEN (3)
+#define AW88261_BST_OS_WIDTH_MASK \
+ (~(((1<<AW88261_BST_OS_WIDTH_BITS_LEN)-1) << AW88261_BST_OS_WIDTH_START_BIT))
+
+#define AW88261_BST_OS_WIDTH_50NS (4)
+#define AW88261_BST_OS_WIDTH_50NS_VALUE \
+ (AW88261_BST_OS_WIDTH_50NS << AW88261_BST_OS_WIDTH_START_BIT)
+
+/* BST_LOOPR bit 1:0 (BSTCTRL6 0x65) */
+#define AW88261_BST_LOOPR_START_BIT (0)
+#define AW88261_BST_LOOPR_BITS_LEN (2)
+#define AW88261_BST_LOOPR_MASK \
+ (~(((1<<AW88261_BST_LOOPR_BITS_LEN)-1) << AW88261_BST_LOOPR_START_BIT))
+
+#define AW88261_BST_LOOPR_340K (2)
+#define AW88261_BST_LOOPR_340K_VALUE \
+ (AW88261_BST_LOOPR_340K << AW88261_BST_LOOPR_START_BIT)
+
+/* RSQN_DLY bit 15:14 (BSTCTRL7 0x66) */
+#define AW88261_RSQN_DLY_START_BIT (14)
+#define AW88261_RSQN_DLY_BITS_LEN (2)
+#define AW88261_RSQN_DLY_MASK \
+ (~(((1<<AW88261_RSQN_DLY_BITS_LEN)-1) << AW88261_RSQN_DLY_START_BIT))
+
+#define AW88261_RSQN_DLY_35NS (2)
+#define AW88261_RSQN_DLY_35NS_VALUE \
+ (AW88261_RSQN_DLY_35NS << AW88261_RSQN_DLY_START_BIT)
+
+/* BURST_SSMODE bit 3 (BSTCTRL8 0x67) */
+#define AW88261_BURST_SSMODE_START_BIT (3)
+#define AW88261_BURST_SSMODE_BITS_LEN (1)
+#define AW88261_BURST_SSMODE_MASK \
+ (~(((1<<AW88261_BURST_SSMODE_BITS_LEN)-1) << AW88261_BURST_SSMODE_START_BIT))
+
+#define AW88261_BURST_SSMODE_FAST (0)
+#define AW88261_BURST_SSMODE_FAST_VALUE \
+ (AW88261_BURST_SSMODE_FAST << AW88261_BURST_SSMODE_START_BIT)
+
+/* BST_BURST bit 9:7 (BSTCTRL9 0x68) */
+#define AW88261_BST_BURST_START_BIT (7)
+#define AW88261_BST_BURST_BITS_LEN (3)
+#define AW88261_BST_BURST_MASK \
+ (~(((1<<AW88261_BST_BURST_BITS_LEN)-1) << AW88261_BST_BURST_START_BIT))
+
+#define AW88261_BST_BURST_30MA (2)
+#define AW88261_BST_BURST_30MA_VALUE \
+ (AW88261_BST_BURST_30MA << AW88261_BST_BURST_START_BIT)
+
+#define AW88261_EF_VSN_GESLP_SIGN_MASK (~0x0200)
+#define AW88261_EF_VSN_GESLP_NEG (~0xfc00)
+
+#define AW88261_EF_ISN_GESLP_SIGN_MASK (~0x0200)
+#define AW88261_EF_ISN_GESLP_NEG (~0xfc00)
+
+#define AW88261_EF_ISN_GESLP_H_START_BIT (0)
+#define AW88261_EF_ISN_GESLP_H_BITS_LEN (10)
+#define AW88261_EF_ISN_GESLP_H_MASK \
+ (~(((1<<AW88261_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_H_START_BIT))
+
+#define AW88261_EF_ISN_GESLP_L_START_BIT (0)
+#define AW88261_EF_ISN_GESLP_L_BITS_LEN (10)
+#define AW88261_EF_ISN_GESLP_L_MASK \
+ (~(((1<<AW88261_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_L_START_BIT))
+
+#define AW88261_CABL_BASE_VALUE (1000)
+#define AW88261_ICABLK_FACTOR (1)
+#define AW88261_VCABLK_FACTOR (1)
+
+#define AW88261_VCAL_FACTOR (1<<13)
+
+#define AW88261_START_RETRIES (5)
+#define AW88261_START_WORK_DELAY_MS (0)
+
+#define AW88261_I2C_NAME "aw88261"
+
+#define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_96000)
+#define AW88261_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define FADE_TIME_MAX 100000
+#define FADE_TIME_MIN 0
+
+#define AW88261_DEV_DEFAULT_CH (0)
+#define AW88261_ACF_FILE "aw88261_acf.bin"
+#define AW88261_DEV_SYSST_CHECK_MAX (10)
+#define AW88261_SOFT_RESET_VALUE (0x55aa)
+#define AW88261_REG_TO_DB (0x3f)
+#define AW88261_VOL_START_MASK (0xfc00)
+#define AW88261_INIT_PROFILE (0)
+
+#define REG_VAL_TO_DB(value) ((((value) >> AW88261_VOL_6DB_START) * \
+ AW88261_VOLUME_STEP_DB) + \
+ ((value) & AW88261_REG_TO_DB))
+#define DB_TO_REG_VAL(value) ((((value) / AW88261_VOLUME_STEP_DB) << \
+ AW88261_VOL_6DB_START) + \
+ ((value) % AW88261_VOLUME_STEP_DB))
+
+#define AW88261_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 {
+ AW88261_SYNC_START = 0,
+ AW88261_ASYNC_START,
+};
+
+enum aw88261_id {
+ AW88261_CHIP_ID = 0x2113,
+};
+
+enum {
+ AW88261_500_US = 500,
+ AW88261_1000_US = 1000,
+ AW88261_2000_US = 2000,
+};
+
+enum {
+ AW88261_DEV_PW_OFF = 0,
+ AW88261_DEV_PW_ON,
+};
+
+enum {
+ AW88261_DEV_FW_FAILED = 0,
+ AW88261_DEV_FW_OK,
+};
+
+enum {
+ AW88261_EF_AND_CHECK = 0,
+ AW88261_EF_OR_CHECK,
+};
+
+enum {
+ AW88261_FRCSET_DISABLE = 0,
+ AW88261_FRCSET_ENABLE,
+};
+
+struct aw88261 {
+ 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;
+
+ int efuse_check;
+ int frcset_en;
+ unsigned int mute_st;
+ unsigned int amppd_st;
+
+ bool phase_sync;
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index 9dcd75dd799a..3602b5b9f7d7 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -8,9 +8,9 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "aw88395.h"
@@ -75,7 +75,7 @@ static void aw88395_start(struct aw88395 *aw88395, bool sync_start)
if (sync_start == AW88395_SYNC_START)
aw88395_start_pa(aw88395);
else
- queue_delayed_work(system_wq,
+ queue_delayed_work(system_dfl_wq,
&aw88395->start_work,
AW88395_START_WORK_DELAY_MS);
}
@@ -104,7 +104,7 @@ static struct snd_soc_dai_driver aw88395_dai[] = {
static int aw88395_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 snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
struct aw_device *aw_dev = aw88395->aw_pa;
@@ -116,7 +116,7 @@ static int aw88395_get_fade_in_time(struct snd_kcontrol *kcontrol,
static int aw88395_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 snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -139,7 +139,7 @@ static int aw88395_set_fade_in_time(struct snd_kcontrol *kcontrol,
static int aw88395_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 snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
struct aw_device *aw_dev = aw88395->aw_pa;
@@ -151,7 +151,7 @@ static int aw88395_get_fade_out_time(struct snd_kcontrol *kcontrol,
static int aw88395_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 snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -173,11 +173,10 @@ static int aw88395_set_fade_out_time(struct snd_kcontrol *kcontrol,
static int aw88395_profile_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
- const char *prof_name;
- char *name;
- int count;
+ char *prof_name;
+ int count, ret;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
@@ -193,17 +192,15 @@ static int aw88395_profile_info(struct snd_kcontrol *kcontrol,
if (uinfo->value.enumerated.item >= count)
uinfo->value.enumerated.item = count - 1;
- name = uinfo->value.enumerated.name;
count = uinfo->value.enumerated.item;
- prof_name = aw88395_dev_get_prof_name(aw88395->aw_pa, count);
- if (!prof_name) {
- strscpy(uinfo->value.enumerated.name, "null",
- strlen("null") + 1);
+ ret = aw88395_dev_get_prof_name(aw88395->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null");
return 0;
}
- strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));
+ strscpy(uinfo->value.enumerated.name, prof_name);
return 0;
}
@@ -211,7 +208,7 @@ static int aw88395_profile_info(struct snd_kcontrol *kcontrol,
static int aw88395_profile_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
ucontrol->value.integer.value[0] = aw88395_dev_get_profile_index(aw88395->aw_pa);
@@ -222,7 +219,7 @@ static int aw88395_profile_get(struct snd_kcontrol *kcontrol,
static int aw88395_profile_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
int ret;
@@ -248,7 +245,7 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol,
static int aw88395_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
struct aw_volume_desc *vol_desc = &aw88395->aw_pa->volume_desc;
@@ -260,7 +257,7 @@ static int aw88395_volume_get(struct snd_kcontrol *kcontrol,
static int aw88395_volume_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
struct aw_volume_desc *vol_desc = &aw88395->aw_pa->volume_desc;
struct soc_mixer_control *mc =
@@ -284,7 +281,7 @@ static int aw88395_volume_set(struct snd_kcontrol *kcontrol,
static int aw88395_get_fade_step(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
ucontrol->value.integer.value[0] = aw88395->aw_pa->fade_step;
@@ -295,7 +292,7 @@ static int aw88395_get_fade_step(struct snd_kcontrol *kcontrol,
static int aw88395_set_fade_step(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -316,7 +313,7 @@ static int aw88395_set_fade_step(struct snd_kcontrol *kcontrol,
static int aw88395_re_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
struct aw_device *aw_dev = aw88395->aw_pa;
@@ -328,7 +325,7 @@ static int aw88395_re_get(struct snd_kcontrol *kcontrol,
static int aw88395_re_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -357,7 +354,7 @@ static const struct snd_kcontrol_new aw88395_controls[] = {
aw88395_get_fade_in_time, aw88395_set_fade_in_time),
SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
aw88395_get_fade_out_time, aw88395_set_fade_out_time),
- SOC_SINGLE_EXT("Calib", 0, 0, 100, 0,
+ SOC_SINGLE_EXT("Calib", 0, 0, AW88395_CALI_RE_MAX, 0,
aw88395_re_get, aw88395_re_set),
AW88395_PROFILE_EXT("Profile Set", aw88395_profile_info,
aw88395_profile_get, aw88395_profile_set),
@@ -404,7 +401,7 @@ static const struct snd_soc_dapm_route aw88395_audio_map[] = {
static int aw88395_codec_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
int ret;
@@ -561,7 +558,7 @@ static int aw88395_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id aw88395_i2c_id[] = {
- { AW88395_I2C_NAME, 0 },
+ { AW88395_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw88395_i2c_id);
diff --git a/sound/soc/codecs/aw88395/aw88395.h b/sound/soc/codecs/aw88395/aw88395.h
index 8036ba27f68d..c2a4f0cb8cd5 100644
--- a/sound/soc/codecs/aw88395/aw88395.h
+++ b/sound/soc/codecs/aw88395/aw88395.h
@@ -16,7 +16,7 @@
#define AW88395_DSP_16_DATA_MASK (0x0000ffff)
-#define AW88395_I2C_NAME "aw88395_smartpa"
+#define AW88395_I2C_NAME "aw88395"
#define AW88395_RATES (SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_96000)
diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c
index 33eda3741464..79c3135a4110 100644
--- a/sound/soc/codecs/aw88395/aw88395_device.c
+++ b/sound/soc/codecs/aw88395/aw88395_device.c
@@ -10,6 +10,7 @@
#include <linux/crc32.h>
#include <linux/i2c.h>
+#include <linux/minmax.h>
#include <linux/regmap.h>
#include "aw88395_device.h"
#include "aw88395_reg.h"
@@ -63,7 +64,7 @@ static int aw_dev_dsp_write_32bit(struct aw_device *aw_dev,
return 0;
}
-static int aw_dev_dsp_write(struct aw_device *aw_dev,
+int aw_dev_dsp_write(struct aw_device *aw_dev,
unsigned short dsp_addr, unsigned int dsp_data, unsigned char data_type)
{
u32 reg_value;
@@ -71,13 +72,13 @@ static int aw_dev_dsp_write(struct aw_device *aw_dev,
mutex_lock(&aw_dev->dsp_lock);
switch (data_type) {
- case AW88395_DSP_16_DATA:
+ case AW_DSP_16_DATA:
ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data);
if (ret)
dev_err(aw_dev->dev, "write dsp_addr[0x%x] 16-bit dsp_data[0x%x] failed",
(u32)dsp_addr, dsp_data);
break;
- case AW88395_DSP_32_DATA:
+ case AW_DSP_32_DATA:
ret = aw_dev_dsp_write_32bit(aw_dev, dsp_addr, dsp_data);
if (ret)
dev_err(aw_dev->dev, "write dsp_addr[0x%x] 32-bit dsp_data[0x%x] failed",
@@ -96,6 +97,7 @@ static int aw_dev_dsp_write(struct aw_device *aw_dev,
return ret;
}
+EXPORT_SYMBOL_GPL(aw_dev_dsp_write);
static int aw_dev_dsp_read_16bit(struct aw_device *aw_dev,
unsigned short dsp_addr, unsigned int *dsp_data)
@@ -148,7 +150,7 @@ static int aw_dev_dsp_read_32bit(struct aw_device *aw_dev,
return 0;
}
-static int aw_dev_dsp_read(struct aw_device *aw_dev,
+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;
@@ -156,13 +158,13 @@ static int aw_dev_dsp_read(struct aw_device *aw_dev,
mutex_lock(&aw_dev->dsp_lock);
switch (data_type) {
- case AW88395_DSP_16_DATA:
+ case AW_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 dsp_data[0x%x] failed",
(u32)dsp_addr, *dsp_data);
break;
- case AW88395_DSP_32_DATA:
+ case AW_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] 32r-bit dsp_data[0x%x] failed",
@@ -181,7 +183,7 @@ static int aw_dev_dsp_read(struct aw_device *aw_dev,
return ret;
}
-
+EXPORT_SYMBOL_GPL(aw_dev_dsp_read);
static int aw_dev_read_chipid(struct aw_device *aw_dev, u16 *chip_id)
{
@@ -230,7 +232,7 @@ static int aw_dev_dsp_fw_check(struct aw_device *aw_dev)
dsp_fw_desc = &set_prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_FW];
for (i = 0; i < AW88395_FW_CHECK_PART; i++) {
- ret = aw_dev_dsp_read(aw_dev, addr, &dsp_val, AW88395_DSP_16_DATA);
+ ret = aw_dev_dsp_read(aw_dev, addr, &dsp_val, AW_DSP_16_DATA);
if (ret) {
dev_err(aw_dev->dev, "dsp read failed");
return ret;
@@ -297,9 +299,6 @@ static void aw_dev_fade_in(struct aw_device *aw_dev)
int fade_step = aw_dev->fade_step;
int i;
- if (!aw_dev->fade_en)
- return;
-
if (fade_step == 0 || aw_dev->fade_in_time == 0) {
aw_dev_set_volume(aw_dev, fade_in_vol);
return;
@@ -320,9 +319,6 @@ static void aw_dev_fade_out(struct aw_device *aw_dev)
int fade_step = aw_dev->fade_step;
int i;
- if (!aw_dev->fade_en)
- return;
-
if (fade_step == 0 || aw_dev->fade_out_time == 0) {
aw_dev_set_volume(aw_dev, AW88395_MUTE_VOL);
return;
@@ -356,11 +352,11 @@ static int aw_dev_modify_dsp_cfg(struct aw_device *aw_dev,
return -EINVAL;
}
switch (data_type) {
- case AW88395_DSP_16_DATA:
+ case AW_DSP_16_DATA:
data1 = cpu_to_le16((u16)dsp_data);
memcpy(crc_dsp_cfg->data + addr_offset, (u8 *)&data1, 2);
break;
- case AW88395_DSP_32_DATA:
+ case AW_DSP_32_DATA:
data2 = cpu_to_le32(dsp_data);
memcpy(crc_dsp_cfg->data + addr_offset, (u8 *)&data2, 4);
break;
@@ -382,14 +378,14 @@ static int aw_dev_dsp_set_cali_re(struct aw_device *aw_dev)
/* set cali re to device */
ret = aw_dev_dsp_write(aw_dev,
- AW88395_DSP_REG_CFG_ADPZ_RE, cali_re, AW88395_DSP_32_DATA);
+ AW88395_DSP_REG_CFG_ADPZ_RE, cali_re, AW_DSP_32_DATA);
if (ret) {
dev_err(aw_dev->dev, "set cali re error");
return ret;
}
ret = aw_dev_modify_dsp_cfg(aw_dev, AW88395_DSP_REG_CFG_ADPZ_RE,
- cali_re, AW88395_DSP_32_DATA);
+ cali_re, AW_DSP_32_DATA);
if (ret)
dev_err(aw_dev->dev, "modify dsp cfg failed");
@@ -430,10 +426,10 @@ 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);
+ AW_DSP_32_DATA);
}
static void aw_dev_dsp_check_crc_enable(struct aw_device *aw_dev, bool flag)
@@ -668,7 +664,7 @@ static int aw_dev_set_vcalb(struct aw_device *aw_dev)
int vcalb, vcalk;
int ret;
- ret = aw_dev_dsp_read(aw_dev, AW88395_DSP_REG_VCALB, &vcalb_adj, AW88395_DSP_16_DATA);
+ ret = aw_dev_dsp_read(aw_dev, AW88395_DSP_REG_VCALB, &vcalb_adj, AW_DSP_16_DATA);
if (ret) {
dev_err(aw_dev->dev, "read vcalb_adj failed");
return ret;
@@ -709,7 +705,7 @@ static int aw_dev_set_vcalb(struct aw_device *aw_dev)
AW88395_VSCAL_FACTOR_DAC, icalk, vcalk);
break;
default:
- dev_err(aw_dev->dev, "unsupport vsense status");
+ dev_err(aw_dev->dev, "unsupported vsense status");
return -EINVAL;
}
@@ -725,14 +721,14 @@ static int aw_dev_set_vcalb(struct aw_device *aw_dev)
dev_dbg(aw_dev->dev, "vcalb=%d, reg_val=0x%x, vcalb_adj =0x%x",
vcalb, reg_val, vcalb_adj);
- ret = aw_dev_dsp_write(aw_dev, AW88395_DSP_REG_VCALB, reg_val, AW88395_DSP_16_DATA);
+ ret = aw_dev_dsp_write(aw_dev, AW88395_DSP_REG_VCALB, reg_val, AW_DSP_16_DATA);
if (ret) {
dev_err(aw_dev->dev, "write vcalb failed");
return ret;
}
ret = aw_dev_modify_dsp_cfg(aw_dev, AW88395_DSP_REG_VCALB,
- (u32)reg_val, AW88395_DSP_16_DATA);
+ (u32)reg_val, AW_DSP_16_DATA);
if (ret)
dev_err(aw_dev->dev, "modify dsp cfg failed");
@@ -746,7 +742,7 @@ static int aw_dev_get_cali_f0_delay(struct aw_device *aw_dev)
int ret;
ret = aw_dev_dsp_read(aw_dev,
- AW88395_DSP_CALI_F0_DELAY, &cali_delay, AW88395_DSP_16_DATA);
+ AW88395_DSP_CALI_F0_DELAY, &cali_delay, AW_DSP_16_DATA);
if (ret)
dev_err(aw_dev->dev, "read cali delay failed, ret=%d", ret);
else
@@ -996,7 +992,7 @@ static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
static int aw_dev_get_vmax(struct aw_device *aw_dev, unsigned int *vmax)
{
- return aw_dev_dsp_read(aw_dev, AW88395_DSP_REG_VMAX, vmax, AW88395_DSP_16_DATA);
+ return aw_dev_dsp_read(aw_dev, AW88395_DSP_REG_VMAX, vmax, AW_DSP_16_DATA);
}
static int aw_dev_update_reg_container(struct aw_device *aw_dev,
@@ -1062,10 +1058,6 @@ static int aw_dev_update_reg_container(struct aw_device *aw_dev,
aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
}
- /* keep min volume */
- if (aw_dev->fade_en)
- aw_dev_set_volume(aw_dev, AW88395_MUTE_VOL);
-
aw_dev_get_dsp_config(aw_dev, &aw_dev->dsp_cfg);
return ret;
@@ -1098,7 +1090,7 @@ static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
int ret;
ret = aw_dev_dsp_read(aw_dev, AW88395_DSP_REG_CFG_ADPZ_RA,
- &dsp_ra, AW88395_DSP_32_DATA);
+ &dsp_ra, AW_DSP_32_DATA);
if (ret) {
dev_err(aw_dev->dev, "read ra error");
return ret;
@@ -1124,11 +1116,7 @@ static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
goto error_operation;
for (i = 0; i < len; i += AW88395_MAX_RAM_WRITE_BYTE_SIZE) {
- if ((len - i) < AW88395_MAX_RAM_WRITE_BYTE_SIZE)
- tmp_len = len - i;
- else
- tmp_len = AW88395_MAX_RAM_WRITE_BYTE_SIZE;
-
+ tmp_len = min(len - i, AW88395_MAX_RAM_WRITE_BYTE_SIZE);
ret = regmap_raw_write(aw_dev->regmap, AW88395_DSPMDAT_REG,
&data[i], tmp_len);
if (ret)
@@ -1306,7 +1294,9 @@ int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool forc
return -EPERM;
}
- prof_name = aw88395_dev_get_prof_name(aw_dev, aw_dev->prof_index);
+ ret = aw88395_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);
@@ -1594,37 +1584,19 @@ static void aw88395_parse_channel_dt(struct aw_device *aw_dev)
u32 channel_value;
int ret;
- ret = of_property_read_u32(np, "sound-channel", &channel_value);
+ ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value);
if (ret) {
dev_dbg(aw_dev->dev,
- "read sound-channel failed,use default 0");
+ "read audio-channel failed,use default 0");
aw_dev->channel = AW88395_DEV_DEFAULT_CH;
return;
}
- dev_dbg(aw_dev->dev, "read sound-channel value is: %d",
+ dev_dbg(aw_dev->dev, "read audio-channel value is: %d",
channel_value);
aw_dev->channel = channel_value;
}
-static void aw88395_parse_fade_enable_dt(struct aw_device *aw_dev)
-{
- struct device_node *np = aw_dev->dev->of_node;
- u32 fade_en;
- int ret;
-
- ret = of_property_read_u32(np, "fade-enable", &fade_en);
- if (ret) {
- dev_dbg(aw_dev->dev,
- "read fade-enable failed, close fade_in_out");
- fade_en = AW88395_FADE_IN_OUT_DEFAULT;
- }
-
- dev_dbg(aw_dev->dev, "read fade-enable value is: %d", fade_en);
-
- aw_dev->fade_en = fade_en;
-}
-
static int aw_dev_init(struct aw_device *aw_dev)
{
aw_dev->chip_id = AW88395_CHIP_ID;
@@ -1639,7 +1611,6 @@ static int aw_dev_init(struct aw_device *aw_dev)
aw_dev->fade_step = AW88395_VOLUME_STEP_DB;
aw_dev->volume_desc.ctl_volume = AW88395_VOL_DEFAULT_VALUE;
aw88395_parse_channel_dt(aw_dev);
- aw88395_parse_fade_enable_dt(aw_dev);
return 0;
}
@@ -1673,7 +1644,7 @@ int aw88395_dev_set_profile_index(struct aw_device *aw_dev, int index)
}
EXPORT_SYMBOL_GPL(aw88395_dev_set_profile_index);
-char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index)
+int aw88395_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;
@@ -1681,12 +1652,14 @@ char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index)
if ((index >= aw_dev->prof_info.count) || (index < 0)) {
dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
index, aw_dev->prof_info.count);
- return NULL;
+ return -EINVAL;
}
prof_desc = &aw_dev->prof_info.prof_desc[index];
- return prof_info->prof_name_list[prof_desc->id];
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
}
EXPORT_SYMBOL_GPL(aw88395_dev_get_prof_name);
diff --git a/sound/soc/codecs/aw88395/aw88395_device.h b/sound/soc/codecs/aw88395/aw88395_device.h
index caf730753167..3626f222899d 100644
--- a/sound/soc/codecs/aw88395/aw88395_device.h
+++ b/sound/soc/codecs/aw88395/aw88395_device.h
@@ -89,8 +89,8 @@ enum AW88395_DEV_DSP_CFG {
};
enum {
- AW88395_DSP_16_DATA = 0,
- AW88395_DSP_32_DATA = 1,
+ AW_DSP_16_DATA = 0,
+ AW_DSP_32_DATA = 1,
};
enum {
@@ -102,6 +102,11 @@ struct aw_profctrl_desc {
unsigned int cur_mode;
};
+enum {
+ CALI_RESULT_NORMAL,
+ CALI_RESULT_ERROR,
+};
+
struct aw_volume_desc {
unsigned int init_volume;
unsigned int mute_volume;
@@ -124,9 +129,25 @@ struct aw_cali_delay_desc {
unsigned int delay;
};
+#define AW_CALI_CFG_NUM (4)
+struct cali_cfg {
+ uint32_t data[AW_CALI_CFG_NUM];
+};
+
+struct aw_cali_backup_desc {
+ unsigned int dsp_ng_cfg;
+ unsigned int dsp_lp_cfg;
+};
+
struct aw_cali_desc {
u32 cali_re;
u32 ra;
+ bool cali_switch;
+ bool cali_running;
+ uint16_t cali_result;
+ uint16_t store_vol;
+ struct cali_cfg cali_cfg;
+ struct aw_cali_backup_desc backup_info;
};
struct aw_container {
@@ -141,19 +162,18 @@ struct aw_device {
unsigned char prof_cur;
unsigned char prof_index;
unsigned char dsp_crc_st;
+ unsigned char dsp_cfg;
u16 chip_id;
unsigned int channel;
unsigned int fade_step;
+ unsigned int prof_data_type;
struct i2c_client *i2c;
struct device *dev;
struct regmap *regmap;
char *acf;
- u32 fade_en;
- unsigned char dsp_cfg;
-
u32 dsp_fw_len;
u32 dsp_cfg_len;
u8 platform;
@@ -183,12 +203,16 @@ int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool forc
void aw88395_dev_set_volume(struct aw_device *aw_dev, unsigned short set_vol);
int aw88395_dev_get_prof_data(struct aw_device *aw_dev, int index,
struct aw_prof_desc **prof_desc);
-char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index);
+int aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name);
int aw88395_dev_set_profile_index(struct aw_device *aw_dev, int index);
int aw88395_dev_get_profile_index(struct aw_device *aw_dev);
int aw88395_dev_get_profile_count(struct aw_device *aw_dev);
int aw88395_dev_load_acf_check(struct aw_device *aw_dev, struct aw_container *aw_cfg);
int aw88395_dev_cfg_load(struct aw_device *aw_dev, struct aw_container *aw_cfg);
void aw88395_dev_mute(struct aw_device *aw_dev, bool is_mute);
+int aw_dev_dsp_write(struct aw_device *aw_dev,
+ unsigned short dsp_addr, unsigned int dsp_data, unsigned char data_type);
+int aw_dev_dsp_read(struct aw_device *aw_dev,
+ unsigned short dsp_addr, unsigned int *dsp_data, unsigned char data_type);
#endif
diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c
index 05bcf49da857..ceb7fc43d018 100644
--- a/sound/soc/codecs/aw88395/aw88395_lib.c
+++ b/sound/soc/codecs/aw88395/aw88395_lib.c
@@ -7,6 +7,7 @@
// Author: Bruce zhao <zhaolei@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/i2c.h>
#include "aw88395_lib.h"
@@ -361,11 +362,11 @@ static int aw_dev_parse_raw_dsp_fw(unsigned char *data, unsigned int data_len,
static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *data,
unsigned int data_len, struct aw_prof_desc *prof_desc)
{
- struct aw_bin *aw_bin;
int ret;
int i;
- aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(struct aw_bin), GFP_KERNEL);
+ struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(struct aw_bin),
+ GFP_KERNEL);
if (!aw_bin)
return -ENOMEM;
@@ -375,7 +376,7 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
ret = aw_parsing_bin_file(aw_dev, aw_bin);
if (ret < 0) {
dev_err(aw_dev->dev, "parse bin failed");
- goto parse_bin_failed;
+ return ret;
}
for (i = 0; i < aw_bin->all_bin_parse_num; i++) {
@@ -387,10 +388,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
data + aw_bin->header_info[i].valid_data_addr;
break;
case DATA_TYPE_DSP_REG:
- if (aw_bin->header_info[i].valid_data_len & 0x01) {
- ret = -EINVAL;
- goto parse_bin_failed;
- }
+ if (aw_bin->header_info[i].valid_data_len & 0x01)
+ return -EINVAL;
swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),
aw_bin->header_info[i].valid_data_len >> 1);
@@ -402,10 +401,8 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
break;
case DATA_TYPE_DSP_FW:
case DATA_TYPE_SOC_APP:
- if (aw_bin->header_info[i].valid_data_len & 0x01) {
- ret = -EINVAL;
- goto parse_bin_failed;
- }
+ if (aw_bin->header_info[i].valid_data_len & 0x01)
+ return -EINVAL;
swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),
aw_bin->header_info[i].valid_data_len >> 1);
@@ -422,11 +419,42 @@ static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *
}
}
prof_desc->prof_st = AW88395_PROFILE_OK;
- ret = 0;
-parse_bin_failed:
- devm_kfree(aw_dev->dev, aw_bin);
- return ret;
+ return 0;
+}
+
+static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
+ uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc)
+{
+ int ret;
+
+ struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(*aw_bin),
+ GFP_KERNEL);
+ if (!aw_bin)
+ return -ENOMEM;
+
+ aw_bin->info.len = data_len;
+ memcpy(aw_bin->info.data, data, data_len);
+
+ ret = aw_parsing_bin_file(aw_dev, aw_bin);
+ if (ret < 0) {
+ dev_err(aw_dev->dev, "parse bin failed");
+ return ret;
+ }
+
+ if ((aw_bin->all_bin_parse_num != 1) ||
+ (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
+ dev_err(aw_dev->dev, "bin num or type error");
+ return -EINVAL;
+ }
+
+ prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =
+ data + aw_bin->header_info[0].valid_data_addr;
+ prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len =
+ aw_bin->header_info[0].valid_data_len;
+ prof_desc->prof_st = AW88395_PROFILE_OK;
+
+ return 0;
}
static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr,
@@ -447,6 +475,9 @@ static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg
return aw_dev_prof_parse_multi_bin(
aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,
cfg_dde->data_size, scene_prof_desc);
+ case ACF_SEC_TYPE_HDR_REG:
+ return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,
+ cfg_dde->data_size, scene_prof_desc);
default:
dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type);
break;
@@ -473,7 +504,7 @@ static int aw_dev_parse_dev_type(struct aw_device *aw_dev,
cfg_dde[i].dev_profile);
return -EINVAL;
}
-
+ aw_dev->prof_data_type = cfg_dde[i].data_type;
ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i],
&all_prof_info->prof_desc[cfg_dde[i].dev_profile]);
if (ret < 0) {
@@ -509,6 +540,7 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev,
cfg_dde[i].dev_profile);
return -EINVAL;
}
+ aw_dev->prof_data_type = cfg_dde[i].data_type;
ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i],
&all_prof_info->prof_desc[cfg_dde[i].dev_profile]);
if (ret < 0) {
@@ -527,10 +559,52 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev,
return 0;
}
-static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
- struct aw_all_prof_info all_prof_info)
+static int aw_dev_cfg_get_reg_valid_prof(struct aw_device *aw_dev,
+ struct aw_all_prof_info *all_prof_info)
+{
+ struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ int num = 0;
+ int i;
+
+ for (i = 0; i < AW88395_PROFILE_MAX; i++) {
+ if (prof_desc[i].prof_st == AW88395_PROFILE_OK)
+ prof_info->count++;
+ }
+
+ dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count);
+
+ if (!prof_info->count) {
+ dev_err(aw_dev->dev, "no profile data");
+ return -EPERM;
+ }
+
+ prof_info->prof_desc = devm_kcalloc(aw_dev->dev,
+ prof_info->count, sizeof(struct aw_prof_desc),
+ GFP_KERNEL);
+ if (!prof_info->prof_desc)
+ return -ENOMEM;
+
+ for (i = 0; i < AW88395_PROFILE_MAX; i++) {
+ if (prof_desc[i].prof_st == AW88395_PROFILE_OK) {
+ if (num >= prof_info->count) {
+ dev_err(aw_dev->dev, "overflow count[%d]",
+ prof_info->count);
+ return -EINVAL;
+ }
+ prof_info->prof_desc[num] = prof_desc[i];
+ prof_info->prof_desc[num].id = i;
+ num++;
+ }
+ }
+
+ return 0;
+}
+
+static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev,
+ struct aw_all_prof_info *all_prof_info)
{
- struct aw_prof_desc *prof_desc = all_prof_info.prof_desc;
+ struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;
struct aw_prof_info *prof_info = &aw_dev->prof_info;
struct aw_sec_data_desc *sec_desc;
int num = 0;
@@ -589,31 +663,38 @@ static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
struct aw_cfg_hdr *prof_hdr)
{
- struct aw_all_prof_info *all_prof_info;
int ret;
- all_prof_info = devm_kzalloc(aw_dev->dev, sizeof(struct aw_all_prof_info), GFP_KERNEL);
+ struct aw_all_prof_info *all_prof_info __free(kfree) = kzalloc(sizeof(*all_prof_info),
+ GFP_KERNEL);
if (!all_prof_info)
return -ENOMEM;
ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, all_prof_info);
if (ret < 0) {
- goto exit;
+ return ret;
} else if (ret == AW88395_DEV_TYPE_NONE) {
dev_dbg(aw_dev->dev, "get dev type num is 0, parse default dev");
ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, all_prof_info);
if (ret < 0)
- goto exit;
+ return ret;
}
- ret = aw_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
- if (ret < 0)
- goto exit;
-
- aw_dev->prof_info.prof_name_list = profile_name;
+ switch (aw_dev->prof_data_type) {
+ case ACF_SEC_TYPE_MULTIPLE_BIN:
+ ret = aw_dev_cfg_get_multiple_valid_prof(aw_dev, all_prof_info);
+ break;
+ case ACF_SEC_TYPE_HDR_REG:
+ ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info);
+ break;
+ default:
+ dev_err(aw_dev->dev, "unsupported data type\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (!ret)
+ aw_dev->prof_info.prof_name_list = profile_name;
-exit:
- devm_kfree(aw_dev->dev, all_prof_info);
return ret;
}
@@ -681,13 +762,20 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain
unsigned int i;
for (i = 0; i < cfg_hdr->ddt_num; ++i) {
- if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
+ if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||
+ (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG) ||
+ (cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN)) &&
(aw_dev->chip_id == cfg_dde[i].chip_id) &&
(aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
(aw_dev->i2c->addr == cfg_dde[i].dev_addr))
(*scene_num)++;
}
+ if ((*scene_num) == 0) {
+ dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num));
+ return -EINVAL;
+ }
+
return 0;
}
@@ -700,13 +788,21 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev,
(struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);
unsigned int i;
+
for (i = 0; i < cfg_hdr->ddt_num; ++i) {
- if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
+ if (((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) ||
+ (cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||
+ (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&
(aw_dev->chip_id == cfg_dde[i].chip_id) &&
(aw_dev->channel == cfg_dde[i].dev_index))
(*scene_num)++;
}
+ if ((*scene_num) == 0) {
+ dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num));
+ return -EINVAL;
+ }
+
return 0;
}
@@ -756,6 +852,18 @@ static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev,
prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;
(*cur_scene_id)++;
break;
+ case ACF_SEC_TYPE_HDR_REG:
+ ret = aw_dev_parse_reg_bin_with_hdr(aw_dev,
+ (uint8_t *)prof_hdr + cfg_dde->data_offset,
+ cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]);
+ if (ret < 0) {
+ dev_err(aw_dev->dev, "parse reg bin with hdr failed");
+ return ret;
+ }
+ prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str;
+ prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;
+ (*cur_scene_id)++;
+ break;
default:
dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type);
return -EINVAL;
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
new file mode 100644
index 000000000000..b588c27909b5
--- /dev/null
+++ b/sound/soc/codecs/aw88399.c
@@ -0,0 +1,2173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88399.c -- ALSA SoC AW88399 codec support
+//
+// Copyright (c) 2023 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/crc32.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/minmax.h>
+#include <linux/regmap.h>
+#include <linux/sort.h>
+#include <sound/soc.h>
+#include "aw88399.h"
+#include "aw88395/aw88395_device.h"
+
+static const struct regmap_config aw88399_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88399_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ int ret;
+
+ if (pwd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
+ if (ret)
+ dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
+ else
+ *int_status = reg_val;
+
+ dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
+}
+
+static void aw_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ u16 int_status;
+
+ /* read int status and clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ /* make sure int status is clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ if (int_status)
+ dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
+}
+
+static int aw_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88399_CCO_MUX_MASK);
+ if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) {
+ dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
+ return -EPERM;
+ }
+
+ /* change mode2 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int aw_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int aw_dev_check_sysst(struct aw_device *aw_dev)
+{
+ unsigned int check_val;
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
+ check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
+ else
+ check_val = AW88399_BIT_SYSST_SWS_CHECK;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
+ dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
+ i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ int ret;
+
+ if (amppd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
+{
+ int ret;
+
+ if (is_enable)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed\n", __func__);
+}
+
+static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
+{
+ uint16_t icalkh_val, icalkl_val, icalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ icalk_val = icalkh_val & icalkl_val;
+ else
+ icalk_val = icalkh_val | icalkl_val;
+
+ if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
+ icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
+ *icalk = (int16_t)icalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = vcalkh_val & vcalkl_val;
+ else
+ vcalk_val = vcalkh_val | vcalkl_val;
+
+ if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
+ vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+ else
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+
+ if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
+ vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
+
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw_dev_set_vcalb(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int vsense_select, vsense_value;
+ int32_t ical_k, vcal_k, vcalb;
+ int16_t icalk, vcalk;
+ uint16_t reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
+ if (ret)
+ return ret;
+
+ vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
+
+ ret = aw88399_dev_get_icalk(aw88399, &icalk);
+ if (ret) {
+ dev_err(aw_dev->dev, "get icalk failed\n");
+ return ret;
+ }
+
+ ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+
+ switch (vsense_select) {
+ case AW88399_DEV_VDSEL_VSENSE:
+ ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
+ ical_k / vcal_k * aw88399->vcalb_init_val;
+ break;
+ case AW88399_DEV_VDSEL_DAC:
+ ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
+ AW88399_ISCAL_DAC_FACTOR * ical_k /
+ vcal_k * aw88399->vcalb_init_val;
+ break;
+ default:
+ dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ return ret;
+
+ vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
+ reg_val = (uint32_t)vcalb;
+
+ regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
+
+ return 0;
+}
+
+static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ uint16_t re_lbits, re_hbits;
+ u32 cali_re;
+ int ret;
+
+ if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
+ (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
+ return -EINVAL;
+
+ cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
+ aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
+
+ re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
+ re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
+ if (ret) {
+ dev_err(aw_dev->dev, "set cali re error");
+ return ret;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
+ if (ret)
+ dev_err(aw_dev->dev, "set cali re error");
+
+ return ret;
+}
+
+static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, fw_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate fw_end_addr */
+ fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
+
+ /* write fw_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
+ if (ret)
+ return ret;
+ /* enable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
+
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ /* read crc check result */
+ regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
+ __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, cfg_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate cfg end addr */
+ cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
+
+ /* write cfg_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
+ if (ret)
+ return ret;
+
+ /* enable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
+ if (ret)
+ return ret;
+
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ /* read crc check result */
+ ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
+ check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_fw_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = aw_dev_cfg_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "cfg_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+
+ return ret;
+
+crc_check_failed:
+ regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+ return ret;
+}
+
+static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ int ret;
+
+ if (flag)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
+ if (ret)
+ return ret;
+ if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
+ return -EPERM;
+
+ return 0;
+}
+
+static int aw_dev_dsp_check(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ switch (aw_dev->dsp_cfg) {
+ case AW88399_DEV_DSP_BYPASS:
+ dev_dbg(aw_dev->dev, "dsp bypass");
+ ret = 0;
+ break;
+ case AW88399_DEV_DSP_WORK:
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_dsp_enable(aw_dev, true);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
+ ret = aw_dev_get_dsp_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ }
+ }
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int reg_value;
+ u16 real_value;
+ int ret;
+
+ real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
+
+ real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
+
+ ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
+
+ return ret;
+}
+
+static void aw_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ u16 fade_in_vol = desc->ctl_volume;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_in_time == 0) {
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw_dev_fade_out(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_out_time == 0) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88399_MUTE_VOL) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
+ aw_dev_fade_in(aw_dev);
+ }
+}
+
+static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ if (dither)
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
+}
+
+static int aw88399_dev_start(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88399_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ aw88399_dev_set_dither(aw88399, false);
+
+ /* power on */
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ ret = aw_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw_dev_amppd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw_dev_check_sysst(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
+ ret = aw_dev_hw_crc_check(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp crc check failed");
+ goto crc_check_fail;
+ }
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_set_vcalb(aw88399);
+ aw_dev_update_cali_re(&aw_dev->cali_desc);
+
+ ret = aw_dev_dsp_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp status check failed");
+ goto dsp_check_fail;
+ }
+ } else {
+ dev_dbg(aw_dev->dev, "start pa with dsp bypass");
+ }
+
+ /* enable tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, true);
+
+ if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
+ aw88399_dev_set_dither(aw88399, true);
+
+ /* close mute */
+ aw88399_dev_mute(aw_dev, false);
+ /* clear inturrupt */
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88399_DEV_PW_ON;
+
+ return 0;
+
+dsp_check_fail:
+crc_check_fail:
+ aw_dev_dsp_enable(aw_dev, false);
+sysst_check_fail:
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len, unsigned short base)
+{
+ u32 tmp_len;
+ int i, ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
+ tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
+ ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
+ &data[i], tmp_len);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ u32 dsp_ra;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
+ &dsp_ra, AW_DSP_32_DATA);
+ if (ret) {
+ dev_err(aw_dev->dev, "read ra error");
+ return ret;
+ }
+
+ cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
+ AW88399_DSP_RE_SHIFT);
+
+ return 0;
+}
+
+static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp config len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp config data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
+ if (ret)
+ return ret;
+
+ aw_dev->dsp_cfg_len = len;
+
+ ret = aw_dev_get_ra(&aw_dev->cali_desc);
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
+ return -EINVAL;
+ }
+
+ aw_dev->dsp_fw_len = len;
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
+
+ return ret;
+}
+
+static int aw_dev_check_sram(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+
+ /* read dsp_rom_check_reg */
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
+ dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
+ reg_val, AW88399_DSP_ROM_CHECK_DATA);
+ return -EPERM;
+ }
+
+ /* check dsp_cfg_base_addr */
+ aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
+ AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
+ dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
+ reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
+{
+ int ret;
+
+ switch (flag) {
+ case AW88399_DEV_MEMCLK_PLL:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select pll failed");
+ break;
+ case AW88399_DEV_MEMCLK_OSC:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_OSCCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select OSC failed");
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
+ break;
+ }
+}
+
+static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
+{
+ struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+ return;
+ }
+ if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
+ profctrl_desc->cur_mode = AW88399_RCV_MODE;
+ else
+ profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
+}
+
+static int aw_dev_update_reg_container(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ u16 read_vol, reg_val;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u8 reg_addr;
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ if (reg_addr == AW88399_DSPVCALB_REG) {
+ aw88399->vcalb_init_val = reg_val;
+ continue;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL_REG) {
+ if (reg_val & (~AW88399_DSPBY_MASK))
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
+ else
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
+
+ reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
+ AW88399_DSPBY_MASK);
+ reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
+ AW88399_DSPBY_BYPASS_VALUE);
+ }
+
+ if (reg_addr == AW88399_I2SCTRL3_REG) {
+ reg_val &= AW88399_I2STXEN_MASK;
+ reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
+ AW88399_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ if (reg_addr == AW88399_DBGCTRL_REG) {
+ if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
+ aw88399->check_val = AW_EF_OR_CHECK;
+ else
+ aw88399->check_val = AW_EF_AND_CHECK;
+
+ aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
+ }
+
+ if (reg_addr == AW88399_CRCCTRL_REG)
+ aw88399->crc_init_val = reg_val;
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ return ret;
+ }
+
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ aw_dev_get_cur_mode_st(aw_dev);
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+ else
+ aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
+
+ return 0;
+}
+
+static int aw_dev_reg_update(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ if (!len || !data) {
+ dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_update_reg_container(aw88399, data, len);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "reg update failed");
+
+ return ret;
+}
+
+static int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
+}
+
+static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index,
+ struct aw_prof_desc **prof_desc)
+{
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
+ __func__, index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ *prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ return 0;
+}
+
+static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ if ((aw_dev->prof_cur == aw_dev->prof_index) &&
+ (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
+ dev_dbg(aw_dev->dev, "scene no change, not update");
+ return 0;
+ }
+
+ if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
+ dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
+ return -EPERM;
+ }
+
+ ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+ if (ret)
+ return ret;
+
+ /* update reg */
+ sec_desc = prof_index_desc->sec_desc;
+ ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+
+ ret = aw_dev_check_sram(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "check sram failed");
+ goto error;
+ }
+
+ if (up_dsp_fw_en) {
+ dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
+ ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp fw failed");
+ goto error;
+ }
+ }
+
+ /* update dsp config */
+ ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp cfg failed");
+ goto error;
+ }
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+
+error:
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ return ret;
+}
+
+static void aw88399_start_pa(struct aw88399 *aw88399)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_START_RETRIES; i++) {
+ ret = aw88399_dev_start(aw88399);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
+ ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed");
+ continue;
+ }
+ } else {
+ dev_dbg(aw88399->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+static void aw88399_startup_work(struct work_struct *work)
+{
+ struct aw88399 *aw88399 =
+ container_of(work, struct aw88399, start_work.work);
+
+ mutex_lock(&aw88399->lock);
+ aw88399_start_pa(aw88399);
+ mutex_unlock(&aw88399->lock);
+}
+
+static void aw88399_start(struct aw88399 *aw88399, bool sync_start)
+{
+ int ret;
+
+ if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
+ return;
+
+ if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
+ return;
+
+ ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed.");
+ return;
+ }
+
+ if (sync_start == AW88399_SYNC_START)
+ aw88399_start_pa(aw88399);
+ else
+ queue_delayed_work(system_dfl_wq,
+ &aw88399->start_work,
+ AW88399_START_WORK_DELAY_MS);
+}
+
+static int aw_dev_check_sysint(struct aw_device *aw_dev)
+{
+ u16 reg_val;
+
+ aw_dev_get_int_status(aw_dev, &reg_val);
+ if (reg_val & AW88399_BIT_SYSINT_CHECK) {
+ dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw88399_stop(struct aw_device *aw_dev)
+{
+ struct aw_sec_data_desc *dsp_cfg =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
+ struct aw_sec_data_desc *dsp_fw =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
+ int int_st;
+
+ if (aw_dev->status == AW88399_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ aw88399_dev_mute(aw_dev, true);
+ usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
+
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ int_st = aw_dev_check_sysint(aw_dev);
+
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_amppd(aw_dev, true);
+
+ if (int_st) {
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+ aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
+ aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ }
+
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver aw88399_dai[] = {
+ {
+ .name = "aw88399-aif",
+ .id = 1,
+ .playback = {
+ .stream_name = "Speaker_Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88399_RATES,
+ .formats = AW88399_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Speaker_Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88399_RATES,
+ .formats = AW88399_FORMATS,
+ },
+ },
+};
+
+static void aw_cali_svc_run_mute(struct aw_device *aw_dev, uint16_t cali_result)
+{
+ if (cali_result == CALI_RESULT_ERROR)
+ aw88399_dev_mute(aw_dev, true);
+ else if (cali_result == CALI_RESULT_NORMAL)
+ aw88399_dev_mute(aw_dev, false);
+}
+
+static int aw_cali_svc_get_cali_cfg(struct aw_device *aw_dev)
+{
+ struct cali_cfg *cali_cfg = &aw_dev->cali_desc.cali_cfg;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_MBMEC_ACTAMPTH,
+ &cali_cfg->data[0], AW_DSP_32_DATA);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_MBMEC_NOISEAMPTH,
+ &cali_cfg->data[1], AW_DSP_32_DATA);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_USTEPN,
+ &cali_cfg->data[2], AW_DSP_16_DATA);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_RE_ALPHA,
+ &cali_cfg->data[3], AW_DSP_16_DATA);
+
+ return ret;
+}
+
+static int aw_cali_svc_set_cali_cfg(struct aw_device *aw_dev,
+ struct cali_cfg cali_cfg)
+{
+ int ret;
+
+ ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_MBMEC_ACTAMPTH,
+ cali_cfg.data[0], AW_DSP_32_DATA);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_MBMEC_NOISEAMPTH,
+ cali_cfg.data[1], AW_DSP_32_DATA);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_ADPZ_USTEPN,
+ cali_cfg.data[2], AW_DSP_16_DATA);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_dsp_write(aw_dev, AW88399_DSP_REG_CFG_RE_ALPHA,
+ cali_cfg.data[3], AW_DSP_16_DATA);
+
+ return ret;
+}
+
+static int aw_cali_svc_cali_en(struct aw_device *aw_dev, bool cali_en)
+{
+ struct cali_cfg set_cfg;
+ int ret;
+
+ aw_dev_dsp_enable(aw_dev, false);
+ if (cali_en) {
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW883XX_DSP_NG_EN_MASK, AW883XX_DSP_NG_EN_DISABLE_VALUE);
+ aw_dev_dsp_write(aw_dev, AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR,
+ AW88399_DSP_LOW_POWER_SWITCH_DISABLE, AW_DSP_16_DATA);
+
+ ret = aw_cali_svc_get_cali_cfg(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "get cali cfg failed\n");
+ aw_dev_dsp_enable(aw_dev, true);
+ return ret;
+ }
+ set_cfg.data[0] = 0;
+ set_cfg.data[1] = 0;
+ set_cfg.data[2] = -1;
+ set_cfg.data[3] = 1;
+
+ ret = aw_cali_svc_set_cali_cfg(aw_dev, set_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "set cali cfg failed\n");
+ aw_cali_svc_set_cali_cfg(aw_dev, aw_dev->cali_desc.cali_cfg);
+ aw_dev_dsp_enable(aw_dev, true);
+ return ret;
+ }
+ } else {
+ aw_cali_svc_set_cali_cfg(aw_dev, aw_dev->cali_desc.cali_cfg);
+ }
+
+ aw_dev_dsp_enable(aw_dev, true);
+
+ return 0;
+}
+
+static int aw_cali_svc_cali_run_dsp_vol(struct aw_device *aw_dev, bool enable)
+{
+ unsigned int reg_val;
+ int ret;
+
+ if (enable) {
+ ret = regmap_read(aw_dev->regmap, AW88399_DSPCFG_REG, &reg_val);
+ if (ret) {
+ dev_err(aw_dev->dev, "read reg 0x%x failed\n", AW88399_DSPCFG_REG);
+ return ret;
+ }
+
+ aw_dev->cali_desc.store_vol = reg_val & (~AW88399_DSP_VOL_MASK);
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DSPCFG_REG,
+ ~AW88399_DSP_VOL_MASK, AW88399_DSP_VOL_MUTE);
+ } else {
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DSPCFG_REG,
+ ~AW88399_DSP_VOL_MASK, aw_dev->cali_desc.store_vol);
+ }
+
+ return ret;
+}
+
+static void aw_cali_svc_backup_info(struct aw_device *aw_dev)
+{
+ struct aw_cali_backup_desc *backup_desc = &aw_dev->cali_desc.backup_info;
+ unsigned int reg_val, dsp_val;
+
+ regmap_read(aw_dev->regmap, AW88399_DBGCTRL_REG, &reg_val);
+ backup_desc->dsp_ng_cfg = reg_val & (~AW883XX_DSP_NG_EN_MASK);
+
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR, &dsp_val, AW_DSP_16_DATA);
+
+ backup_desc->dsp_lp_cfg = dsp_val;
+}
+
+static void aw_cali_svc_recover_info(struct aw_device *aw_dev)
+{
+ struct aw_cali_backup_desc *backup_desc = &aw_dev->cali_desc.backup_info;
+
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW883XX_DSP_NG_EN_MASK, backup_desc->dsp_ng_cfg);
+
+ aw_dev_dsp_write(aw_dev, AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR,
+ backup_desc->dsp_lp_cfg, AW_DSP_16_DATA);
+}
+
+static int aw_cali_svc_cali_re_mode_enable(struct aw_device *aw_dev, bool is_enable)
+{
+ int ret;
+
+ if (is_enable) {
+ ret = aw_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start\n");
+ return ret;
+ }
+
+ ret = aw_dev_get_dsp_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp status error\n");
+ return ret;
+ }
+
+ aw_cali_svc_backup_info(aw_dev);
+ ret = aw_cali_svc_cali_en(aw_dev, true);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_cali_svc_cali_en failed\n");
+ return ret;
+ }
+
+ ret = aw_cali_svc_cali_run_dsp_vol(aw_dev, true);
+ if (ret) {
+ aw_cali_svc_cali_en(aw_dev, false);
+ return ret;
+ }
+
+ } else {
+ aw_cali_svc_cali_run_dsp_vol(aw_dev, false);
+ aw_cali_svc_recover_info(aw_dev);
+ aw_cali_svc_cali_en(aw_dev, false);
+ }
+
+ return 0;
+}
+
+static int aw_cali_svc_get_dev_re(struct aw_device *aw_dev, uint32_t *re)
+{
+ uint32_t dsp_re, show_re;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CALRE, &dsp_re, AW_DSP_16_DATA);
+ if (ret)
+ return ret;
+
+ show_re = AW88399_DSP_RE_TO_SHOW_RE(dsp_re, AW88399_DSP_REG_CALRE_SHIFT);
+
+ *re = (uint32_t)(show_re - aw_dev->cali_desc.ra);
+
+ return 0;
+}
+
+static void aw_cali_svc_del_max_min_ave_algo(uint32_t *data, int data_size, uint32_t *dsp_re)
+{
+ int sum = 0, i;
+
+ for (i = 1; i < data_size - 1; i++)
+ sum += data[i];
+
+ *dsp_re = sum / (data_size - AW_CALI_DATA_SUM_RM);
+}
+
+static int aw_cali_svc_get_iv_st(struct aw_device *aw_dev)
+{
+ unsigned int reg_data;
+ int ret, i;
+
+ for (i = 0; i < AW_GET_IV_CNT_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88399_ASR1_REG, &reg_data);
+ if (ret) {
+ dev_err(aw_dev->dev, "read 0x%x failed\n", AW88399_ASR1_REG);
+ return ret;
+ }
+
+ reg_data &= (~AW88399_REABS_MASK);
+ if (!reg_data)
+ return 0;
+ msleep(30);
+ }
+
+ dev_err(aw_dev->dev, "IV data abnormal, please check\n");
+
+ return -EINVAL;
+}
+
+static int compare_ints(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+static int aw_cali_svc_get_smooth_cali_re(struct aw_device *aw_dev)
+{
+ uint32_t re_temp[AW_CALI_READ_CNT_MAX];
+ uint32_t dsp_re;
+ int ret, i;
+
+ for (i = 0; i < AW_CALI_READ_CNT_MAX; i++) {
+ ret = aw_cali_svc_get_dev_re(aw_dev, &re_temp[i]);
+ if (ret)
+ goto cali_re_fail;
+ msleep(30);
+ }
+
+ sort(re_temp, AW_CALI_READ_CNT_MAX, sizeof(uint32_t), compare_ints, NULL);
+
+ aw_cali_svc_del_max_min_ave_algo(re_temp, AW_CALI_READ_CNT_MAX, &dsp_re);
+
+ ret = aw_cali_svc_get_iv_st(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "get iv data failed");
+ goto cali_re_fail;
+ }
+
+ if (dsp_re < AW88399_CALI_RE_MIN || dsp_re > AW88399_CALI_RE_MAX) {
+ dev_err(aw_dev->dev, "out range re value: [%d]mohm\n", dsp_re);
+ aw_dev->cali_desc.cali_re = dsp_re;
+ aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR;
+ aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result);
+
+ return 0;
+ }
+
+ aw_dev->cali_desc.cali_result = CALI_RESULT_NORMAL;
+
+ aw_dev->cali_desc.cali_re = dsp_re;
+ dev_dbg(aw_dev->dev, "re[%d]mohm\n", aw_dev->cali_desc.cali_re);
+
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_update_cali_re(&aw_dev->cali_desc);
+ aw_dev_dsp_enable(aw_dev, true);
+
+ return 0;
+
+cali_re_fail:
+ aw_dev->cali_desc.cali_result = CALI_RESULT_ERROR;
+ aw_cali_svc_run_mute(aw_dev, aw_dev->cali_desc.cali_result);
+ return -EINVAL;
+}
+
+static int aw_cali_svc_dev_cali_re(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_cali_desc *cali_desc = &aw_dev->cali_desc;
+ int ret;
+
+ if (cali_desc->cali_running) {
+ dev_err(aw_dev->dev, "calibration in progress\n");
+ return -EINVAL;
+ }
+
+ cali_desc->cali_running = true;
+ aw_cali_svc_run_mute(aw_dev, CALI_RESULT_NORMAL);
+
+ ret = aw_cali_svc_cali_re_mode_enable(aw_dev, true);
+ if (ret) {
+ dev_err(aw_dev->dev, "start cali re failed\n");
+ goto re_mode_err;
+ }
+
+ msleep(1000);
+
+ ret = aw_cali_svc_get_smooth_cali_re(aw_dev);
+ if (ret)
+ dev_err(aw_dev->dev, "get cali re failed\n");
+
+ aw_cali_svc_cali_re_mode_enable(aw_dev, false);
+
+re_mode_err:
+ cali_desc->cali_running = false;
+
+ return ret;
+}
+
+static int aw88399_get_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+ return 0;
+}
+
+static int aw88399_set_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88399->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 aw88399_get_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+ return 0;
+}
+
+static int aw88399_set_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88399->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 aw88399_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 aw88399_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ char *prof_name;
+ int count, ret;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw88399->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;
+
+ count = uinfo->value.enumerated.item;
+
+ ret = aw88399_dev_get_prof_name(aw88399->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null");
+ return 0;
+ }
+
+ strscpy(uinfo->value.enumerated.name, prof_name);
+
+ return 0;
+}
+
+static int aw88399_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88399->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw88399_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ mutex_lock(&aw88399->lock);
+ ret = aw88399_dev_set_profile_index(aw88399->aw_pa, ucontrol->value.integer.value[0]);
+ if (ret) {
+ dev_dbg(codec->dev, "profile index does not change");
+ mutex_unlock(&aw88399->lock);
+ return 0;
+ }
+
+ if (aw88399->aw_pa->status) {
+ aw88399_stop(aw88399->aw_pa);
+ aw88399_start(aw88399, AW88399_SYNC_START);
+ }
+
+ mutex_unlock(&aw88399->lock);
+
+ return 1;
+}
+
+static int aw88399_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88399->aw_pa->volume_desc;
+
+ ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+ return 0;
+}
+
+static int aw88399_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88399->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(aw88399->aw_pa, vol_desc->ctl_volume);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88399_get_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88399->aw_pa->fade_step;
+
+ return 0;
+}
+
+static int aw88399_set_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = 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 (aw88399->aw_pa->fade_step != value) {
+ aw88399->aw_pa->fade_step = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88399_re_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_re;
+
+ return 0;
+}
+
+static int aw88399_re_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88399->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 aw88399_calib_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_switch;
+
+ return 0;
+}
+
+static int aw88399_calib_switch_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ if (aw_dev->cali_desc.cali_switch == ucontrol->value.integer.value[0])
+ return 0;
+
+ aw_dev->cali_desc.cali_switch = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+static int aw88399_calib_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* do nothing */
+ return 0;
+}
+
+static int aw88399_calib_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ if (aw_dev->status && aw_dev->cali_desc.cali_switch)
+ aw_cali_svc_dev_cali_re(aw88399);
+
+ return 0;
+}
+
+static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+ aw_dev->fade_in_time = AW88399_1000_US / 10;
+ aw_dev->fade_out_time = AW88399_1000_US >> 1;
+ aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
+ aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
+
+ ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ /* enable amppd */
+ aw_dev_amppd(aw_dev, true);
+
+ /* close dsp */
+ aw_dev_dsp_enable(aw_dev, false);
+ /* set power down */
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88399_request_firmware_file(struct aw88399 *aw88399)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88399_ACF_FILE, cont ? cont->size : 0);
+
+ aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
+ struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
+ if (!aw88399->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+ aw88399->aw_cfg->len = (int)cont->size;
+ memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw88399->lock);
+ /* aw device init */
+ ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "dev init failed");
+ mutex_unlock(&aw88399->lock);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new aw88399_controls[] = {
+ SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG,
+ 6, AW88399_MUTE_VOL, 0, aw88399_volume_get,
+ aw88399_volume_set),
+ SOC_SINGLE_EXT("Fade Step", 0, 0, AW88399_MUTE_VOL, 0,
+ aw88399_get_fade_step, aw88399_set_fade_step),
+ SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88399_get_fade_in_time, aw88399_set_fade_in_time),
+ SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88399_get_fade_out_time, aw88399_set_fade_out_time),
+ SOC_SINGLE_EXT("Calib", 0, 0, AW88399_CALI_RE_MAX, 0,
+ aw88399_re_get, aw88399_re_set),
+ SOC_SINGLE_BOOL_EXT("Calib Switch", 0,
+ aw88399_calib_switch_get, aw88399_calib_switch_set),
+ SOC_SINGLE_EXT("Trigger Calib", SND_SOC_NOPM, 0, 1, 0,
+ aw88399_calib_get, aw88399_calib_set),
+ AW88399_PROFILE_EXT("AW88399 Profile Set", aw88399_profile_info,
+ aw88399_profile_get, aw88399_profile_set),
+};
+
+static int aw88399_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 aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&aw88399->lock);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ aw88399_start(aw88399, AW88399_ASYNC_START);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ aw88399_stop(aw88399->aw_pa);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&aw88399->lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88399_dapm_widgets[] = {
+ /* playback */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0,
+ aw88399_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 aw88399_audio_map[] = {
+ {"DAC Output", NULL, "AIF_RX"},
+ {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88399_codec_probe(struct snd_soc_component *component)
+{
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ INIT_DELAYED_WORK(&aw88399->start_work, aw88399_startup_work);
+
+ ret = aw88399_request_firmware_file(aw88399);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "%s failed\n", __func__);
+
+ return ret;
+}
+
+static void aw88399_codec_remove(struct snd_soc_component *aw_codec)
+{
+ struct aw88399 *aw88399 = snd_soc_component_get_drvdata(aw_codec);
+
+ cancel_delayed_work_sync(&aw88399->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88399 = {
+ .probe = aw88399_codec_probe,
+ .remove = aw88399_codec_remove,
+ .dapm_widgets = aw88399_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aw88399_dapm_widgets),
+ .dapm_routes = aw88399_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(aw88399_audio_map),
+ .controls = aw88399_controls,
+ .num_controls = ARRAY_SIZE(aw88399_controls),
+};
+
+static void aw88399_hw_reset(struct aw88399 *aw88399)
+{
+ if (aw88399->reset_gpio) {
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ }
+}
+
+static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
+{
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value;
+
+ of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ aw_dev->channel = channel_value;
+}
+
+static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88399_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device");
+ return -ENXIO;
+ }
+ dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+ aw88399->aw_pa = aw_dev;
+
+ aw_dev->i2c = i2c;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->regmap = regmap;
+ mutex_init(&aw_dev->dsp_lock);
+
+ aw_dev->chip_id = chip_id;
+ aw_dev->acf = NULL;
+ aw_dev->prof_info.prof_desc = NULL;
+ aw_dev->prof_info.count = 0;
+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+ aw_dev->channel = AW88399_DEV_DEFAULT_CH;
+ aw_dev->fw_status = AW88399_DEV_FW_FAILED;
+
+ aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
+
+ aw88399_parse_channel_dt(aw_dev);
+
+ return 0;
+}
+
+static int aw88399_i2c_probe(struct i2c_client *i2c)
+{
+ struct aw88399 *aw88399;
+ int ret;
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
+
+ aw88399 = devm_kzalloc(&i2c->dev, sizeof(*aw88399), GFP_KERNEL);
+ if (!aw88399)
+ return -ENOMEM;
+
+ mutex_init(&aw88399->lock);
+
+ i2c_set_clientdata(i2c, aw88399);
+
+ aw88399->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(aw88399->reset_gpio))
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88399->reset_gpio),
+ "reset gpio not defined\n");
+ aw88399_hw_reset(aw88399);
+
+ aw88399->regmap = devm_regmap_init_i2c(i2c, &aw88399_remap_config);
+ if (IS_ERR(aw88399->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88399->regmap),
+ "failed to init regmap\n");
+
+ /* aw pa init */
+ ret = aw88399_init(aw88399, i2c, aw88399->regmap);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw88399,
+ aw88399_dai, ARRAY_SIZE(aw88399_dai));
+ if (ret)
+ dev_err(&i2c->dev, "failed to register aw88399: %d", ret);
+
+ return ret;
+}
+
+static const struct i2c_device_id aw88399_i2c_id[] = {
+ { AW88399_I2C_NAME },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88399_i2c_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id aw88399_acpi_match[] = {
+ { "AWDZ8399", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, aw88399_acpi_match);
+#endif
+
+static struct i2c_driver aw88399_i2c_driver = {
+ .driver = {
+ .name = AW88399_I2C_NAME,
+ .acpi_match_table = ACPI_PTR(aw88399_acpi_match),
+ },
+ .probe = aw88399_i2c_probe,
+ .id_table = aw88399_i2c_id,
+};
+module_i2c_driver(aw88399_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88399 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h
new file mode 100644
index 000000000000..b386f4836748
--- /dev/null
+++ b/sound/soc/codecs/aw88399.h
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88399.h -- ALSA SoC AW88399 codec support
+//
+// Copyright (c) 2023 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88399_H__
+#define __AW88399_H__
+
+/* registers list */
+#define AW88399_ID_REG (0x00)
+#define AW88399_SYSST_REG (0x01)
+#define AW88399_SYSINT_REG (0x02)
+#define AW88399_SYSINTM_REG (0x03)
+#define AW88399_SYSCTRL_REG (0x04)
+#define AW88399_SYSCTRL2_REG (0x05)
+#define AW88399_I2SCTRL1_REG (0x06)
+#define AW88399_I2SCTRL2_REG (0x07)
+#define AW88399_I2SCTRL3_REG (0x08)
+#define AW88399_DACCFG1_REG (0x09)
+#define AW88399_DACCFG2_REG (0x0A)
+#define AW88399_DACCFG3_REG (0x0B)
+#define AW88399_DACCFG4_REG (0x0C)
+#define AW88399_DACCFG5_REG (0x0D)
+#define AW88399_DACCFG6_REG (0x0E)
+#define AW88399_DACCFG7_REG (0x0F)
+#define AW88399_MPDCFG1_REG (0x10)
+#define AW88399_MPDCFG2_REG (0x11)
+#define AW88399_MPDCFG3_REG (0x12)
+#define AW88399_MPDCFG4_REG (0x13)
+#define AW88399_PWMCTRL1_REG (0x14)
+#define AW88399_PWMCTRL2_REG (0x15)
+#define AW88399_PWMCTRL3_REG (0x16)
+#define AW88399_I2SCFG1_REG (0x17)
+#define AW88399_DBGCTRL_REG (0x18)
+#define AW88399_HAGCST_REG (0x20)
+#define AW88399_VBAT_REG (0x21)
+#define AW88399_TEMP_REG (0x22)
+#define AW88399_PVDD_REG (0x23)
+#define AW88399_ISNDAT_REG (0x24)
+#define AW88399_VSNDAT_REG (0x25)
+#define AW88399_I2SINT_REG (0x26)
+#define AW88399_I2SCAPCNT_REG (0x27)
+#define AW88399_ANASTA1_REG (0x28)
+#define AW88399_ANASTA2_REG (0x29)
+#define AW88399_ANASTA3_REG (0x2A)
+#define AW88399_TESTDET_REG (0x2B)
+#define AW88399_DSMCFG1_REG (0x30)
+#define AW88399_DSMCFG2_REG (0x31)
+#define AW88399_DSMCFG3_REG (0x32)
+#define AW88399_DSMCFG4_REG (0x33)
+#define AW88399_DSMCFG5_REG (0x34)
+#define AW88399_DSMCFG6_REG (0x35)
+#define AW88399_DSMCFG7_REG (0x36)
+#define AW88399_DSMCFG8_REG (0x37)
+#define AW88399_TESTIN_REG (0x38)
+#define AW88399_TESTOUT_REG (0x39)
+#define AW88399_MEMTEST_REG (0x3A)
+#define AW88399_VSNCTRL1_REG (0x3B)
+#define AW88399_ISNCTRL1_REG (0x3C)
+#define AW88399_ISNCTRL2_REG (0x3D)
+#define AW88399_DSPMADD_REG (0x40)
+#define AW88399_DSPMDAT_REG (0x41)
+#define AW88399_WDT_REG (0x42)
+#define AW88399_ACR1_REG (0x43)
+#define AW88399_ACR2_REG (0x44)
+#define AW88399_ASR1_REG (0x45)
+#define AW88399_ASR2_REG (0x46)
+#define AW88399_DSPCFG_REG (0x47)
+#define AW88399_ASR3_REG (0x48)
+#define AW88399_ASR4_REG (0x49)
+#define AW88399_DSPVCALB_REG (0x4A)
+#define AW88399_CRCCTRL_REG (0x4B)
+#define AW88399_DSPDBG1_REG (0x4C)
+#define AW88399_DSPDBG2_REG (0x4D)
+#define AW88399_DSPDBG3_REG (0x4E)
+#define AW88399_PLLCTRL1_REG (0x50)
+#define AW88399_PLLCTRL2_REG (0x51)
+#define AW88399_PLLCTRL3_REG (0x52)
+#define AW88399_CDACTRL1_REG (0x53)
+#define AW88399_CDACTRL2_REG (0x54)
+#define AW88399_CDACTRL3_REG (0x55)
+#define AW88399_SADCCTRL1_REG (0x56)
+#define AW88399_SADCCTRL2_REG (0x57)
+#define AW88399_BOPCTRL1_REG (0x58)
+#define AW88399_BOPCTRL2_REG (0x5A)
+#define AW88399_BOPCTRL3_REG (0x5B)
+#define AW88399_BOPCTRL4_REG (0x5C)
+#define AW88399_BOPCTRL5_REG (0x5D)
+#define AW88399_BOPCTRL6_REG (0x5E)
+#define AW88399_BOPCTRL7_REG (0x5F)
+#define AW88399_BSTCTRL1_REG (0x60)
+#define AW88399_BSTCTRL2_REG (0x61)
+#define AW88399_BSTCTRL3_REG (0x62)
+#define AW88399_BSTCTRL4_REG (0x63)
+#define AW88399_BSTCTRL5_REG (0x64)
+#define AW88399_BSTCTRL6_REG (0x65)
+#define AW88399_BSTCTRL7_REG (0x66)
+#define AW88399_BSTCTRL8_REG (0x67)
+#define AW88399_BSTCTRL9_REG (0x68)
+#define AW88399_BSTCTRL10_REG (0x69)
+#define AW88399_CPCTRL_REG (0x6A)
+#define AW88399_EFWH_REG (0x6C)
+#define AW88399_EFWM2_REG (0x6D)
+#define AW88399_EFWM1_REG (0x6E)
+#define AW88399_EFWL_REG (0x6F)
+#define AW88399_TESTCTRL1_REG (0x70)
+#define AW88399_TESTCTRL2_REG (0x71)
+#define AW88399_EFCTRL1_REG (0x72)
+#define AW88399_EFCTRL2_REG (0x73)
+#define AW88399_EFRH4_REG (0x74)
+#define AW88399_EFRH3_REG (0x75)
+#define AW88399_EFRH2_REG (0x76)
+#define AW88399_EFRH1_REG (0x77)
+#define AW88399_EFRL4_REG (0x78)
+#define AW88399_EFRL3_REG (0x79)
+#define AW88399_EFRL2_REG (0x7A)
+#define AW88399_EFRL1_REG (0x7B)
+#define AW88399_TM_REG (0x7C)
+#define AW88399_TM2_REG (0x7D)
+
+#define AW88399_REG_MAX (0x7E)
+#define AW88399_MUTE_VOL (1023)
+
+#define AW88399_DSP_CFG_ADDR (0x9B00)
+#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68)
+#define AW88399_DSP_FW_ADDR (0x8980)
+#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40)
+#define AW88399_DSP_ROM_CHECK_DATA (0x4638)
+
+#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000))
+#define AW88399_CALI_RE_HBITS_SHIFT (16)
+
+#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF))
+#define AW88399_CALI_RE_LBITS_SHIFT (0)
+
+#define AW88399_I2STXEN_START_BIT (9)
+#define AW88399_I2STXEN_BITS_LEN (1)
+#define AW88399_I2STXEN_MASK \
+ (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT))
+
+#define AW88399_I2STXEN_DISABLE (0)
+#define AW88399_I2STXEN_DISABLE_VALUE \
+ (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT)
+
+#define AW88399_I2STXEN_ENABLE (1)
+#define AW88399_I2STXEN_ENABLE_VALUE \
+ (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT)
+
+#define AW88399_VOL_START_BIT (0)
+#define AW88399_VOL_BITS_LEN (10)
+#define AW88399_VOL_MASK \
+ (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT))
+
+#define AW88399_PWDN_START_BIT (0)
+#define AW88399_PWDN_BITS_LEN (1)
+#define AW88399_PWDN_MASK \
+ (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT))
+
+#define AW88399_PWDN_POWER_DOWN (1)
+#define AW88399_PWDN_POWER_DOWN_VALUE \
+ (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT)
+
+#define AW88399_PWDN_WORKING (0)
+#define AW88399_PWDN_WORKING_VALUE \
+ (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT)
+
+#define AW88399_DSPBY_START_BIT (2)
+#define AW88399_DSPBY_BITS_LEN (1)
+#define AW88399_DSPBY_MASK \
+ (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT))
+
+#define AW88399_DSPBY_WORKING (0)
+#define AW88399_DSPBY_WORKING_VALUE \
+ (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT)
+
+#define AW88399_DSPBY_BYPASS (1)
+#define AW88399_DSPBY_BYPASS_VALUE \
+ (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT)
+
+#define AW88399_MEM_CLKSEL_START_BIT (3)
+#define AW88399_MEM_CLKSEL_BITS_LEN (1)
+#define AW88399_MEM_CLKSEL_MASK \
+ (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT))
+
+#define AW88399_MEM_CLKSEL_OSCCLK (0)
+#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \
+ (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT)
+
+#define AW88399_MEM_CLKSEL_DAPHCLK (1)
+#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \
+ (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT)
+
+#define AW88399_DITHER_EN_START_BIT (15)
+#define AW88399_DITHER_EN_BITS_LEN (1)
+#define AW88399_DITHER_EN_MASK \
+ (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT))
+
+#define AW88399_DITHER_EN_DISABLE (0)
+#define AW88399_DITHER_EN_DISABLE_VALUE \
+ (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT)
+
+#define AW88399_DITHER_EN_ENABLE (1)
+#define AW88399_DITHER_EN_ENABLE_VALUE \
+ (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT)
+
+#define AW88399_HMUTE_START_BIT (8)
+#define AW88399_HMUTE_BITS_LEN (1)
+#define AW88399_HMUTE_MASK \
+ (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT))
+
+#define AW88399_HMUTE_DISABLE (0)
+#define AW88399_HMUTE_DISABLE_VALUE \
+ (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT)
+
+#define AW88399_HMUTE_ENABLE (1)
+#define AW88399_HMUTE_ENABLE_VALUE \
+ (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT)
+
+#define AW88399_EF_DBMD_START_BIT (2)
+#define AW88399_EF_DBMD_BITS_LEN (1)
+#define AW88399_EF_DBMD_MASK \
+ (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT))
+
+#define AW88399_EF_DBMD_OR (1)
+#define AW88399_EF_DBMD_OR_VALUE \
+ (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT)
+
+#define AW88399_VDSEL_START_BIT (5)
+#define AW88399_VDSEL_BITS_LEN (1)
+#define AW88399_VDSEL_MASK \
+ (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT))
+
+#define AW88399_EF_ISN_GESLP_H_START_BIT (0)
+#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10)
+#define AW88399_EF_ISN_GESLP_H_MASK \
+ (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT))
+
+/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */
+#define AW88399_EF_VSN_GESLP_H_START_BIT (0)
+#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10)
+#define AW88399_EF_VSN_GESLP_H_MASK \
+ (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT))
+
+#define AW88399_EF_ISN_GESLP_L_START_BIT (0)
+#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10)
+#define AW88399_EF_ISN_GESLP_L_MASK \
+ (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT))
+
+/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */
+#define AW88399_EF_VSN_GESLP_L_START_BIT (0)
+#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10)
+#define AW88399_EF_VSN_GESLP_L_MASK \
+ (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT))
+
+#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9)
+#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6)
+#define AW88399_INTERNAL_VSN_TRIM_H_MASK \
+ (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT))
+
+#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9)
+#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6)
+#define AW88399_INTERNAL_VSN_TRIM_L_MASK \
+ (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT))
+
+#define AW88399_RCV_MODE_START_BIT (7)
+#define AW88399_RCV_MODE_BITS_LEN (1)
+#define AW88399_RCV_MODE_MASK \
+ (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT))
+
+#define AW88399_CLKI_START_BIT (4)
+#define AW88399_NOCLKI_START_BIT (5)
+#define AW88399_PLLI_START_BIT (0)
+#define AW88399_PLLI_INT_VALUE (1)
+#define AW88399_PLLI_INT_INTERRUPT \
+ (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT)
+
+#define AW88399_CLKI_INT_VALUE (1)
+#define AW88399_CLKI_INT_INTERRUPT \
+ (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT)
+
+#define AW88399_NOCLKI_INT_VALUE (1)
+#define AW88399_NOCLKI_INT_INTERRUPT \
+ (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT)
+
+#define AW88399_BIT_SYSINT_CHECK \
+ (AW88399_PLLI_INT_INTERRUPT | \
+ AW88399_CLKI_INT_INTERRUPT | \
+ AW88399_NOCLKI_INT_INTERRUPT)
+
+#define AW88399_CRC_CHECK_START_BIT (12)
+#define AW88399_CRC_CHECK_BITS_LEN (3)
+#define AW88399_CRC_CHECK_BITS_MASK \
+ (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT))
+
+#define AW88399_RCV_MODE_RECEIVER (1)
+#define AW88399_RCV_MODE_RECEIVER_VALUE \
+ (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT)
+
+#define AW88399_AMPPD_START_BIT (1)
+#define AW88399_AMPPD_BITS_LEN (1)
+#define AW88399_AMPPD_MASK \
+ (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT))
+
+#define AW88399_AMPPD_WORKING (0)
+#define AW88399_AMPPD_WORKING_VALUE \
+ (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT)
+
+#define AW88399_AMPPD_POWER_DOWN (1)
+#define AW88399_AMPPD_POWER_DOWN_VALUE \
+ (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT)
+
+#define AW88399_RAM_CG_BYP_START_BIT (0)
+#define AW88399_RAM_CG_BYP_BITS_LEN (1)
+#define AW88399_RAM_CG_BYP_MASK \
+ (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT))
+
+#define AW88399_RAM_CG_BYP_WORK (0)
+#define AW88399_RAM_CG_BYP_WORK_VALUE \
+ (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT)
+
+#define AW88399_RAM_CG_BYP_BYPASS (1)
+#define AW88399_RAM_CG_BYP_BYPASS_VALUE \
+ (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT)
+
+#define AW88399_CRC_END_ADDR_START_BIT (0)
+#define AW88399_CRC_END_ADDR_BITS_LEN (12)
+#define AW88399_CRC_END_ADDR_MASK \
+ (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT))
+
+#define AW88399_CRC_CODE_EN_START_BIT (13)
+#define AW88399_CRC_CODE_EN_BITS_LEN (1)
+#define AW88399_CRC_CODE_EN_MASK \
+ (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT))
+
+#define AW88399_CRC_CODE_EN_DISABLE (0)
+#define AW88399_CRC_CODE_EN_DISABLE_VALUE \
+ (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT)
+
+#define AW88399_CRC_CODE_EN_ENABLE (1)
+#define AW88399_CRC_CODE_EN_ENABLE_VALUE \
+ (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT)
+
+#define AW88399_CRC_CFG_EN_START_BIT (12)
+#define AW88399_CRC_CFG_EN_BITS_LEN (1)
+#define AW88399_CRC_CFG_EN_MASK \
+ (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT))
+
+#define AW88399_CRC_CFG_EN_DISABLE (0)
+#define AW88399_CRC_CFG_EN_DISABLE_VALUE \
+ (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT)
+
+#define AW88399_CRC_CFG_EN_ENABLE (1)
+#define AW88399_CRC_CFG_EN_ENABLE_VALUE \
+ (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT)
+
+#define AW88399_OCDS_START_BIT (3)
+#define AW88399_OCDS_OC (1)
+#define AW88399_OCDS_OC_VALUE \
+ (AW88399_OCDS_OC << AW88399_OCDS_START_BIT)
+
+#define AW88399_NOCLKS_START_BIT (5)
+#define AW88399_NOCLKS_NO_CLOCK (1)
+#define AW88399_NOCLKS_NO_CLOCK_VALUE \
+ (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT)
+
+#define AW88399_SWS_START_BIT (8)
+#define AW88399_SWS_SWITCHING (1)
+#define AW88399_SWS_SWITCHING_VALUE \
+ (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT)
+
+#define AW88399_BSTS_START_BIT (9)
+#define AW88399_BSTS_FINISHED (1)
+#define AW88399_BSTS_FINISHED_VALUE \
+ (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT)
+
+#define AW88399_UVLS_START_BIT (14)
+#define AW88399_UVLS_NORMAL (0)
+#define AW88399_UVLS_NORMAL_VALUE \
+ (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT)
+
+#define AW88399_BSTOCS_START_BIT (11)
+#define AW88399_BSTOCS_OVER_CURRENT (1)
+#define AW88399_BSTOCS_OVER_CURRENT_VALUE \
+ (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT)
+
+#define AW88399_OTHS_START_BIT (1)
+#define AW88399_OTHS_OT (1)
+#define AW88399_OTHS_OT_VALUE \
+ (AW88399_OTHS_OT << AW88399_OTHS_START_BIT)
+
+#define AW88399_PLLS_START_BIT (0)
+#define AW88399_PLLS_LOCKED (1)
+#define AW88399_PLLS_LOCKED_VALUE \
+ (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT)
+
+#define AW88399_CLKS_START_BIT (4)
+#define AW88399_CLKS_STABLE (1)
+#define AW88399_CLKS_STABLE_VALUE \
+ (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT)
+
+#define AW88399_BIT_PLL_CHECK \
+ (AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE)
+
+#define AW88399_BIT_SYSST_CHECK_MASK \
+ (~(AW88399_UVLS_NORMAL_VALUE | \
+ AW88399_BSTOCS_OVER_CURRENT_VALUE | \
+ AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_SWS_SWITCHING_VALUE | \
+ AW88399_NOCLKS_NO_CLOCK_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_OCDS_OC_VALUE | \
+ AW88399_OTHS_OT_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE))
+
+#define AW88399_BIT_SYSST_NOSWS_CHECK \
+ (AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE)
+
+#define AW88399_BIT_SYSST_SWS_CHECK \
+ (AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE | \
+ AW88399_SWS_SWITCHING_VALUE)
+
+#define AW88399_CCO_MUX_START_BIT (14)
+#define AW88399_CCO_MUX_BITS_LEN (1)
+#define AW88399_CCO_MUX_MASK \
+ (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT))
+
+#define AW88399_CCO_MUX_DIVIDED (0)
+#define AW88399_CCO_MUX_DIVIDED_VALUE \
+ (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT)
+
+#define AW88399_CCO_MUX_BYPASS (1)
+#define AW88399_CCO_MUX_BYPASS_VALUE \
+ (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT)
+
+#define AW88399_NOISE_GATE_EN_START_BIT (13)
+#define AW88399_NOISE_GATE_EN_BITS_LEN (1)
+#define AW88399_NOISE_GATE_EN_MASK \
+ (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
+
+#define AW88399_WDT_CNT_START_BIT (0)
+#define AW88399_WDT_CNT_BITS_LEN (8)
+#define AW88399_WDT_CNT_MASK \
+ (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT))
+
+#define AW88399_REABS_START_BIT (3)
+#define AW88399_REABS_BITS_LEN (1)
+#define AW88399_REABS_MASK \
+ (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT))
+
+#define AW88399_DSP_VOL_START_BIT (8)
+#define AW88399_DSP_VOL_BITS_LEN (8)
+#define AW88399_DSP_VOL_MASK \
+ (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT))
+
+#define AW883XX_DSP_NG_EN_START (13)
+#define AW883XX_DSP_NG_EN_LEN (1)
+#define AW883XX_DSP_NG_EN_MASK \
+ (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START))
+#define AW883XX_DSP_NG_EN_DISABLE (0)
+#define AW883XX_DSP_NG_EN_DISABLE_VALUE \
+ (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START)
+
+#define AW88399_VOLUME_STEP_DB (64)
+#define AW88399_VOL_DEFAULT_VALUE (0)
+#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555)
+#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9))
+#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00)
+
+#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9))
+#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00)
+
+#define AW88399_TEM4_SIGN_MASK (~(1 << 5))
+#define AW88399_TEM4_SIGN_NEG (0xffc0)
+
+#define AW88399_ICABLK_FACTOR (1)
+#define AW88399_VCABLK_FACTOR (1)
+#define AW88399_VCABLK_DAC_FACTOR (2)
+
+#define AW88399_VCALB_ADJ_FACTOR (12)
+#define AW88399_VCALB_ACCURACY (1 << 12)
+
+#define AW88399_ISCAL_FACTOR (3125)
+#define AW88399_VSCAL_FACTOR (18875)
+#define AW88399_ISCAL_DAC_FACTOR (3125)
+#define AW88399_VSCAL_DAC_FACTOR (12600)
+#define AW88399_CABL_BASE_VALUE (1000)
+
+#define AW88399_DEV_DEFAULT_CH (0)
+#define AW88399_DEV_DSP_CHECK_MAX (5)
+#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128)
+#define AW88399_DSP_RE_SHIFT (12)
+#define AW88399_CALI_RE_MAX (15000)
+#define AW88399_CALI_RE_MIN (4000)
+#define AW_FW_ADDR_LEN (4)
+#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
+#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
+#define AW88399_CRC_CHECK_PASS_VAL (0x4)
+
+#define AW88399_CRC_CFG_BASE_ADDR (0xD80)
+#define AW88399_CRC_FW_BASE_ADDR (0x4C0)
+#define AW88399_ACF_FILE "aw88399_acf.bin"
+#define AW88399_DEV_SYSST_CHECK_MAX (10)
+#define AW88399_CHIP_ID 0x2183
+
+#define AW88399_I2C_NAME "aw88399"
+
+#define AW88399_START_RETRIES (5)
+#define AW88399_START_WORK_DELAY_MS (0)
+
+#define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_96000)
+#define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define FADE_TIME_MAX 100000
+#define FADE_TIME_MIN 0
+
+#define AW_CALI_READ_CNT_MAX (8)
+#define AW88399_DSP_REG_CALRE (0x8141)
+#define AW88399_DSP_REG_CALRE_SHIFT (10)
+#define AW_CALI_DATA_SUM_RM (2)
+
+#define AW88399_DSP_REG_CFG_MBMEC_ACTAMPTH (0x9B4C)
+#define AW88399_DSP_REG_CFG_MBMEC_NOISEAMPTH (0x9B4E)
+#define AW88399_DSP_REG_CFG_ADPZ_USTEPN (0x9B6E)
+#define AW88399_DSP_REG_CFG_RE_ALPHA (0x9BD4)
+#define AW_GET_IV_CNT_MAX (6)
+
+#define AW88399_DSP_VOL_MUTE (0XFF00)
+
+#define AW88399_DSP_LOW_POWER_SWITCH_CFG_ADDR (0x9BEC)
+#define AW88399_DSP_LOW_POWER_SWITCH_DISABLE (0x110b)
+
+#define AW88399_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 {
+ AW88399_DEV_VDSEL_DAC = 0,
+ AW88399_DEV_VDSEL_VSENSE = 32,
+};
+
+enum {
+ AW88399_DSP_CRC_NA = 0,
+ AW88399_DSP_CRC_OK = 1,
+};
+
+enum {
+ AW88399_DSP_FW_UPDATE_OFF = 0,
+ AW88399_DSP_FW_UPDATE_ON = 1,
+};
+
+enum {
+ AW88399_FORCE_UPDATE_OFF = 0,
+ AW88399_FORCE_UPDATE_ON = 1,
+};
+
+enum {
+ AW88399_1000_US = 1000,
+ AW88399_2000_US = 2000,
+ AW88399_3000_US = 3000,
+ AW88399_4000_US = 4000,
+};
+
+enum AW88399_DEV_STATUS {
+ AW88399_DEV_PW_OFF = 0,
+ AW88399_DEV_PW_ON,
+};
+
+enum AW88399_DEV_FW_STATUS {
+ AW88399_DEV_FW_FAILED = 0,
+ AW88399_DEV_FW_OK,
+};
+
+enum AW88399_DEV_MEMCLK {
+ AW88399_DEV_MEMCLK_OSC = 0,
+ AW88399_DEV_MEMCLK_PLL = 1,
+};
+
+enum AW88399_DEV_DSP_CFG {
+ AW88399_DEV_DSP_WORK = 0,
+ AW88399_DEV_DSP_BYPASS = 1,
+};
+
+enum {
+ AW88399_NOT_RCV_MODE = 0,
+ AW88399_RCV_MODE = 1,
+};
+
+enum {
+ AW88399_SYNC_START = 0,
+ AW88399_ASYNC_START,
+};
+
+struct aw88399 {
+ struct aw_device *aw_pa;
+ struct mutex lock;
+ struct gpio_desc *reset_gpio;
+ struct delayed_work start_work;
+ struct regmap *regmap;
+ struct aw_container *aw_cfg;
+
+ unsigned int check_val;
+ unsigned int crc_init_val;
+ unsigned int vcalb_init_val;
+ unsigned int dither_st;
+};
+
+#endif
diff --git a/sound/soc/codecs/bd28623.c b/sound/soc/codecs/bd28623.c
index 82a94211d012..07e7bd79c8b0 100644
--- a/sound/soc/codecs/bd28623.c
+++ b/sound/soc/codecs/bd28623.c
@@ -70,8 +70,7 @@ static void bd28623_power_off(struct bd28623_priv *bd)
static int bd28623_get_switch_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = bd->switch_spk;
@@ -82,8 +81,7 @@ static int bd28623_get_switch_spk(struct snd_kcontrol *kcontrol,
static int bd28623_set_switch_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
if (bd->switch_spk == ucontrol->value.integer.value[0])
diff --git a/sound/soc/codecs/chv3-codec.c b/sound/soc/codecs/chv3-codec.c
index ab99effa6874..40020500b1fe 100644
--- a/sound/soc/codecs/chv3-codec.c
+++ b/sound/soc/codecs/chv3-codec.c
@@ -26,6 +26,7 @@ static const struct of_device_id chv3_codec_of_match[] = {
{ .compatible = "google,chv3-codec", },
{ }
};
+MODULE_DEVICE_TABLE(of, chv3_codec_of_match);
static struct platform_driver chv3_codec_platform_driver = {
.driver = {
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 4f9dabd9d78a..6b80c455b074 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,
@@ -366,7 +380,7 @@ static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);
static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int shift = e->shift_l;
@@ -409,10 +423,9 @@ static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int muxval = ucontrol->value.enumerated.item[0];
unsigned int mask = BIT(e->shift_l);
@@ -454,7 +467,7 @@ static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
int regval, mask;
int err;
@@ -493,10 +506,9 @@ static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
static int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int muxval = ucontrol->value.enumerated.item[0];
int regval = 0, mask;
@@ -538,7 +550,7 @@ static int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol,
static int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
int regval, mask;
int err;
@@ -569,10 +581,9 @@ static int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol,
static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int muxval = ucontrol->value.enumerated.item[0];
int regval = 0, mask;
@@ -1626,17 +1637,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 +1763,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 struct snd_soc_component_driver soc_codec_dev_cpcap = {
+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..f78a85b89d95 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -18,9 +18,11 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
#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>
@@ -106,8 +108,7 @@ error:
static int dmic_get_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
struct ec_param_ec_codec_dmic p;
@@ -138,8 +139,7 @@ static int dmic_get_gain(struct snd_kcontrol *kcontrol,
static int dmic_put_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
struct soc_mixer_control *control =
@@ -631,7 +631,7 @@ leave:
static int wov_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c);
ucontrol->value.integer.value[0] = priv->wov_enabled;
@@ -641,7 +641,7 @@ static int wov_enable_get(struct snd_kcontrol *kcontrol,
static int wov_enable_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c);
int enabled = ucontrol->value.integer.value[0];
struct ec_param_ec_codec_wov p;
@@ -657,7 +657,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;
}
@@ -960,7 +960,6 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev)
struct ec_response_ec_codec_get_capabilities r;
int ret;
#ifdef CONFIG_OF
- struct device_node *node;
struct resource res;
u64 ec_shm_size;
const __be32 *regaddr_p;
@@ -980,22 +979,18 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev)
priv->ec_shm_addr, priv->ec_shm_len);
}
- node = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (node) {
- ret = of_address_to_resource(node, 0, &res);
- if (!ret) {
- priv->ap_shm_phys_addr = res.start;
- priv->ap_shm_len = resource_size(&res);
- priv->ap_shm_addr =
- (uint64_t)(uintptr_t)devm_ioremap_wc(
- dev, priv->ap_shm_phys_addr,
- priv->ap_shm_len);
- priv->ap_shm_last_alloc = priv->ap_shm_phys_addr;
-
- dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n",
- priv->ap_shm_phys_addr, priv->ap_shm_len);
- }
- of_node_put(node);
+ ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
+ if (!ret) {
+ priv->ap_shm_phys_addr = res.start;
+ priv->ap_shm_len = resource_size(&res);
+ priv->ap_shm_addr =
+ (uint64_t)(uintptr_t)devm_ioremap_wc(
+ dev, priv->ap_shm_phys_addr,
+ priv->ap_shm_len);
+ priv->ap_shm_last_alloc = priv->ap_shm_phys_addr;
+
+ dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n",
+ priv->ap_shm_phys_addr, priv->ap_shm_len);
}
#endif
diff --git a/sound/soc/codecs/cs-amp-lib-test.c b/sound/soc/codecs/cs-amp-lib-test.c
new file mode 100644
index 000000000000..923f1857e45b
--- /dev/null
+++ b/sound/soc/codecs/cs-amp-lib-test.c
@@ -0,0 +1,2451 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// KUnit test for the Cirrus common amplifier library.
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/resource.h>
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include <kunit/static_stub.h>
+#include <linux/device/faux.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/gpio/driver.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <sound/cs-amp-lib.h>
+
+#define CIRRUS_LOGIC_CALIBRATION_EFI_NAME L"CirrusSmartAmpCalibrationData"
+#define CIRRUS_LOGIC_CALIBRATION_EFI_GUID \
+ EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3)
+
+#define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker"
+#define LENOVO_SPEAKER_ID_EFI_GUID \
+ EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82)
+
+#define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID"
+#define HP_SPEAKER_ID_EFI_GUID \
+ EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e)
+
+#define HP_CALIBRATION_EFI_NAME L"SmartAmpCalibrationData"
+#define HP_CALIBRATION_EFI_GUID \
+ EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93)
+
+KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
+ struct faux_device *)
+
+struct cs_amp_lib_test_priv {
+ struct faux_device *amp_dev;
+
+ struct cirrus_amp_efi_data *cal_blob;
+ struct list_head ctl_write_list;
+ u32 efi_attr;
+};
+
+struct cs_amp_lib_test_ctl_write_entry {
+ struct list_head list;
+ unsigned int value;
+ char name[16];
+};
+
+struct cs_amp_lib_test_param {
+ int num_amps;
+ int amp_index;
+};
+
+static struct cirrus_amp_efi_data *cs_amp_lib_test_cal_blob_dup(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_efi_data *temp;
+
+ KUNIT_ASSERT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ temp = kunit_kmalloc(test, priv->cal_blob->size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, temp);
+ memcpy(temp, priv->cal_blob, priv->cal_blob->size);
+
+ return temp;
+}
+
+static void cs_amp_lib_test_init_dummy_cal_blob(struct kunit *test, int num_amps)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ unsigned int blob_size;
+ int i;
+
+ blob_size = struct_size(priv->cal_blob, data, num_amps);
+
+ priv->cal_blob = kunit_kzalloc(test, blob_size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+
+ priv->cal_blob->size = blob_size;
+ priv->cal_blob->count = num_amps;
+
+ get_random_bytes(priv->cal_blob->data, flex_array_size(priv->cal_blob, data, num_amps));
+
+ /* Ensure all timestamps are non-zero to mark the entry valid. */
+ for (i = 0; i < num_amps; i++)
+ priv->cal_blob->data[i].calTime[0] |= 1;
+
+ /*
+ * Ensure that all UIDs are non-zero and unique.
+ * Make both words non-zero and not equal values, so that
+ * tests can verify that both words were checked or changed.
+ */
+ for (i = 0; i < num_amps; i++) {
+ *(u8 *)&priv->cal_blob->data[i].calTarget[0] = i + 1;
+ *(u8 *)&priv->cal_blob->data[i].calTarget[1] = i;
+ }
+}
+
+static u64 cs_amp_lib_test_get_target_uid(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ const struct cs_amp_lib_test_param *param = test->param_value;
+ u64 uid;
+
+ uid = priv->cal_blob->data[param->amp_index].calTarget[1];
+ uid <<= 32;
+ uid |= priv->cal_blob->data[param->amp_index].calTarget[0];
+
+ return uid;
+}
+
+/* Redirected get_efi_variable to simulate that the file is too short */
+static efi_status_t cs_amp_lib_test_get_efi_variable_nohead(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ if (!buf) {
+ *size = offsetof(struct cirrus_amp_efi_data, data) - 1;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/* Should return -EOVERFLOW if the header is larger than the EFI data */
+static void cs_amp_lib_test_cal_data_too_short_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_nohead);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
+}
+
+/* Redirected get_efi_variable to simulate that the count is larger than the file */
+static efi_status_t cs_amp_lib_test_get_efi_variable_bad_count(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+
+ if (!buf) {
+ /*
+ * Return a size that is shorter than required for the
+ * declared number of entries.
+ */
+ *size = priv->cal_blob->size - 1;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ memcpy(buf, priv->cal_blob, priv->cal_blob->size - 1);
+
+ return EFI_SUCCESS;
+}
+
+/* Should return -EOVERFLOW if the entry count is larger than the EFI data */
+static void cs_amp_lib_test_cal_count_too_big_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_bad_count);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -EOVERFLOW);
+}
+
+/* Redirected get_efi_variable to simulate that the variable not found */
+static efi_status_t cs_amp_lib_test_get_efi_variable_none(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ return EFI_NOT_FOUND;
+}
+
+/* If EFI doesn't contain a cal data variable the result should be -ENOENT */
+static void cs_amp_lib_test_no_cal_data_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_none);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/* Redirected get_efi_variable to simulate reading a cal data blob */
+static efi_status_t cs_amp_lib_test_get_efi_variable(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ static const efi_char16_t expected_name[] = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+ static const efi_guid_t expected_guid = CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
+
+ if (memcmp(name, expected_name, sizeof(expected_name)) ||
+ efi_guidcmp(*guid, expected_guid))
+ return -EFI_NOT_FOUND;
+
+ if (!buf) {
+ *size = priv->cal_blob->size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
+
+ memcpy(buf, priv->cal_blob, priv->cal_blob->size);
+
+ if (returned_attr) {
+ if (priv->efi_attr)
+ *returned_attr = priv->efi_attr;
+ else
+ *returned_attr = EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+#define CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE \
+ struct_size_t(struct cirrus_amp_efi_data, data, 8)
+
+/* Redirected get_efi_variable to simulate reading a prealloced zero-filled blob */
+static efi_status_t cs_amp_lib_test_get_efi_variable_all_zeros(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ static const efi_char16_t expected_name[] = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+ static const efi_guid_t expected_guid = CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
+
+ if (memcmp(name, expected_name, sizeof(expected_name)) ||
+ efi_guidcmp(*guid, expected_guid))
+ return -EFI_NOT_FOUND;
+
+ if (!buf) {
+ *size = CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ KUNIT_ASSERT_EQ(test, *size, struct_size(priv->cal_blob, data, 8));
+ priv->cal_blob = kunit_kzalloc(test, CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+ memset(buf, 0, CS_AMP_LIB_ZERO_FILLED_BLOB_SIZE);
+
+ if (returned_attr) {
+ if (priv->efi_attr)
+ *returned_attr = priv->efi_attr;
+ else
+ *returned_attr = EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t cs_amp_lib_test_get_hp_cal_efi_variable(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ static const efi_char16_t expected_name[] = L"SmartAmpCalibrationData";
+ static const efi_guid_t expected_guid =
+ EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93);
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, name);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, guid);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, size);
+
+ if (memcmp(name, expected_name, sizeof(expected_name)) ||
+ efi_guidcmp(*guid, expected_guid))
+ return -EFI_NOT_FOUND;
+
+ if (!buf) {
+ *size = priv->cal_blob->size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ KUNIT_ASSERT_GE_MSG(test, ksize(buf), priv->cal_blob->size, "Buffer to small");
+
+ memcpy(buf, priv->cal_blob, priv->cal_blob->size);
+
+ if (returned_attr) {
+ *returned_attr = EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* Get cal data block from HP variable. */
+static void cs_amp_lib_test_get_hp_efi_cal(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_hp_cal_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 0, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_MEMEQ(test, &result_data, &priv->cal_blob->data[0], sizeof(result_data));
+}
+
+/* Get cal data block for a given amp, matched by target UID. */
+static void cs_amp_lib_test_get_efi_cal_by_uid_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ const struct cs_amp_lib_test_param *param = test->param_value;
+ struct cirrus_amp_cal_data result_data;
+ u64 target_uid;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ target_uid = cs_amp_lib_test_get_target_uid(test);
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid, -1, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, result_data.calTarget[0], target_uid & 0xFFFFFFFFULL);
+ KUNIT_EXPECT_EQ(test, result_data.calTarget[1], target_uid >> 32);
+ KUNIT_EXPECT_EQ(test, result_data.calTime[0],
+ priv->cal_blob->data[param->amp_index].calTime[0]);
+ KUNIT_EXPECT_EQ(test, result_data.calTime[1],
+ priv->cal_blob->data[param->amp_index].calTime[1]);
+ KUNIT_EXPECT_EQ(test, result_data.calAmbient,
+ priv->cal_blob->data[param->amp_index].calAmbient);
+ KUNIT_EXPECT_EQ(test, result_data.calStatus,
+ priv->cal_blob->data[param->amp_index].calStatus);
+ KUNIT_EXPECT_EQ(test, result_data.calR,
+ priv->cal_blob->data[param->amp_index].calR);
+}
+
+/* Get cal data block for a given amp index without checking target UID. */
+static void cs_amp_lib_test_get_efi_cal_by_index_unchecked_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ const struct cs_amp_lib_test_param *param = test->param_value;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0,
+ param->amp_index, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, result_data.calTime[0],
+ priv->cal_blob->data[param->amp_index].calTime[0]);
+ KUNIT_EXPECT_EQ(test, result_data.calTime[1],
+ priv->cal_blob->data[param->amp_index].calTime[1]);
+ KUNIT_EXPECT_EQ(test, result_data.calAmbient,
+ priv->cal_blob->data[param->amp_index].calAmbient);
+ KUNIT_EXPECT_EQ(test, result_data.calStatus,
+ priv->cal_blob->data[param->amp_index].calStatus);
+ KUNIT_EXPECT_EQ(test, result_data.calR,
+ priv->cal_blob->data[param->amp_index].calR);
+}
+
+/* Get cal data block for a given amp index with checked target UID. */
+static void cs_amp_lib_test_get_efi_cal_by_index_checked_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ const struct cs_amp_lib_test_param *param = test->param_value;
+ struct cirrus_amp_cal_data result_data;
+ u64 target_uid;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ target_uid = cs_amp_lib_test_get_target_uid(test);
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid,
+ param->amp_index, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, result_data.calTime[0],
+ priv->cal_blob->data[param->amp_index].calTime[0]);
+ KUNIT_EXPECT_EQ(test, result_data.calTime[1],
+ priv->cal_blob->data[param->amp_index].calTime[1]);
+ KUNIT_EXPECT_EQ(test, result_data.calAmbient,
+ priv->cal_blob->data[param->amp_index].calAmbient);
+ KUNIT_EXPECT_EQ(test, result_data.calStatus,
+ priv->cal_blob->data[param->amp_index].calStatus);
+ KUNIT_EXPECT_EQ(test, result_data.calR,
+ priv->cal_blob->data[param->amp_index].calR);
+}
+
+/*
+ * Get cal data block for a given amp index with checked target UID.
+ * The UID does not match so the result should be -ENOENT.
+ */
+static void cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ const struct cs_amp_lib_test_param *param = test->param_value;
+ struct cirrus_amp_cal_data result_data;
+ u64 target_uid;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ /* Get a target UID that won't match the entry */
+ target_uid = ~cs_amp_lib_test_get_target_uid(test);
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, target_uid,
+ param->amp_index, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/*
+ * Get cal data block for a given amp, where the cal data does not
+ * specify calTarget so the lookup falls back to using the index
+ */
+static void cs_amp_lib_test_get_efi_cal_by_index_fallback_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ const struct cs_amp_lib_test_param *param = test->param_value;
+ struct cirrus_amp_cal_data result_data;
+ static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
+ int i, ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, param->num_amps);
+
+ /* Make all the target values zero so they are ignored */
+ for (i = 0; i < priv->cal_blob->count; ++i) {
+ priv->cal_blob->data[i].calTarget[0] = 0;
+ priv->cal_blob->data[i].calTarget[1] = 0;
+ }
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid,
+ param->amp_index, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, result_data.calTime[0],
+ priv->cal_blob->data[param->amp_index].calTime[0]);
+ KUNIT_EXPECT_EQ(test, result_data.calTime[1],
+ priv->cal_blob->data[param->amp_index].calTime[1]);
+ KUNIT_EXPECT_EQ(test, result_data.calAmbient,
+ priv->cal_blob->data[param->amp_index].calAmbient);
+ KUNIT_EXPECT_EQ(test, result_data.calStatus,
+ priv->cal_blob->data[param->amp_index].calStatus);
+ KUNIT_EXPECT_EQ(test, result_data.calR,
+ priv->cal_blob->data[param->amp_index].calR);
+}
+
+/*
+ * If the target UID isn't present in the cal data, and there isn't an
+ * index to fall back do, the result should be -ENOENT.
+ */
+static void cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
+ int i, ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Make all the target values != bad_target_uid */
+ for (i = 0; i < priv->cal_blob->count; ++i) {
+ priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
+ priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
+ }
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, -1,
+ &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/*
+ * If the target UID isn't present in the cal data, and the index is
+ * out of range, the result should be -ENOENT.
+ */
+static void cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ static const u64 bad_target_uid = 0xBADCA100BABABABAULL;
+ int i, ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Make all the target values != bad_target_uid */
+ for (i = 0; i < priv->cal_blob->count; ++i) {
+ priv->cal_blob->data[i].calTarget[0] &= ~(bad_target_uid & 0xFFFFFFFFULL);
+ priv->cal_blob->data[i].calTarget[1] &= ~(bad_target_uid >> 32);
+ }
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, bad_target_uid, 99,
+ &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/*
+ * If the target UID isn't given, and the index is out of range, the
+ * result should be -ENOENT.
+ */
+static void cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, 99, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/* If neither the target UID or the index is given the result should be -ENOENT. */
+static void cs_amp_lib_test_get_efi_cal_no_uid_no_index_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/*
+ * If the UID is passed as 0 this must not match an entry with an
+ * unpopulated calTarget
+ */
+static void cs_amp_lib_test_get_efi_cal_zero_not_matched_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ int i, ret;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Make all the target values zero so they are ignored */
+ for (i = 0; i < priv->cal_blob->count; ++i) {
+ priv->cal_blob->data[i].calTarget[0] = 0;
+ priv->cal_blob->data[i].calTarget[1] = 0;
+ }
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ ret = cs_amp_get_efi_calibration_data(&priv->amp_dev->dev, 0, -1, &result_data);
+ KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+/*
+ * If an entry has a timestamp of 0 it should be ignored even if it has
+ * a matching target UID.
+ */
+static void cs_amp_lib_test_get_efi_cal_empty_entry_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data result_data;
+ u64 uid;
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 8);
+
+ /* Mark the 3rd entry invalid by zeroing calTime */
+ priv->cal_blob->data[2].calTime[0] = 0;
+ priv->cal_blob->data[2].calTime[1] = 0;
+
+ /* Get the UID value of the 3rd entry */
+ uid = priv->cal_blob->data[2].calTarget[1];
+ uid <<= 32;
+ uid |= priv->cal_blob->data[2].calTarget[0];
+
+ /* Redirect calls to get EFI data */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+
+ /* Lookup by UID should not find it */
+ KUNIT_EXPECT_EQ(test,
+ cs_amp_get_efi_calibration_data(&priv->amp_dev->dev,
+ uid, -1,
+ &result_data),
+ -ENOENT);
+
+ /* Get by index should ignore it */
+ KUNIT_EXPECT_EQ(test,
+ cs_amp_get_efi_calibration_data(&priv->amp_dev->dev,
+ 0, 2,
+ &result_data),
+ -ENOENT);
+}
+
+static const struct cirrus_amp_cal_controls cs_amp_lib_test_calibration_controls = {
+ .alg_id = 0x9f210,
+ .mem_region = WMFW_ADSP2_YM,
+ .ambient = "CAL_AMBIENT",
+ .calr = "CAL_R",
+ .status = "CAL_STATUS",
+ .checksum = "CAL_CHECKSUM",
+};
+
+static int cs_amp_lib_test_write_cal_coeff(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ const char *ctl_name, u32 val)
+{
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cs_amp_lib_test_ctl_write_entry *entry;
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name);
+ KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls);
+
+ entry = kunit_kzalloc(test, sizeof(*entry), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, entry);
+
+ INIT_LIST_HEAD(&entry->list);
+ strscpy(entry->name, ctl_name, sizeof(entry->name));
+ entry->value = val;
+
+ list_add_tail(&entry->list, &priv->ctl_write_list);
+
+ return 0;
+}
+
+static void cs_amp_lib_test_write_cal_data_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cs_amp_lib_test_ctl_write_entry *entry;
+ struct cirrus_amp_cal_data data;
+ struct cs_dsp *dsp;
+ int ret;
+
+ dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
+ dsp->dev = &priv->amp_dev->dev;
+
+ get_random_bytes(&data, sizeof(data));
+
+ /* Redirect calls to write firmware controls */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->write_cal_coeff,
+ cs_amp_lib_test_write_cal_coeff);
+
+ ret = cs_amp_write_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 4);
+
+ /* Checksum control must be written last */
+ entry = list_last_entry(&priv->ctl_write_list, typeof(*entry), list);
+ KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.checksum);
+ KUNIT_EXPECT_EQ(test, entry->value, data.calR + 1);
+ list_del(&entry->list);
+
+ entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
+ KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient);
+ KUNIT_EXPECT_EQ(test, entry->value, data.calAmbient);
+ list_del(&entry->list);
+
+ entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
+ KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.calr);
+ KUNIT_EXPECT_EQ(test, entry->value, data.calR);
+ list_del(&entry->list);
+
+ entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
+ KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.status);
+ KUNIT_EXPECT_EQ(test, entry->value, data.calStatus);
+}
+
+static int cs_amp_lib_test_read_cal_coeff(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ const char *ctl_name, u32 *val)
+{
+ struct kunit *test = kunit_get_current_test();
+
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctl_name);
+ KUNIT_EXPECT_PTR_EQ(test, controls, &cs_amp_lib_test_calibration_controls);
+
+ if (strcmp(ctl_name, controls->ambient) == 0)
+ *val = 19;
+ else if (strcmp(ctl_name, controls->calr) == 0)
+ *val = 1077;
+ else if (strcmp(ctl_name, controls->status) == 0)
+ *val = 2;
+ else
+ kunit_fail_current_test("Bad control '%s'\n", ctl_name);
+
+ return 0;
+}
+
+static void cs_amp_lib_test_read_cal_data_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cirrus_amp_cal_data data = { 0 };
+ struct cs_dsp *dsp;
+ int ret;
+
+ dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
+ dsp->dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->read_cal_coeff,
+ cs_amp_lib_test_read_cal_coeff);
+
+ ret = cs_amp_read_cal_coeffs(dsp, &cs_amp_lib_test_calibration_controls, &data);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, 19, data.calAmbient);
+ KUNIT_EXPECT_EQ(test, 1077, data.calR);
+ KUNIT_EXPECT_EQ(test, 2, data.calStatus);
+ KUNIT_EXPECT_NE(test, 0, data.calTime[0] | data.calTime[1]);
+}
+
+static void cs_amp_lib_test_write_ambient_test(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct cs_amp_lib_test_ctl_write_entry *entry;
+ struct cs_dsp *dsp;
+ int ret;
+
+ dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp);
+ dsp->dev = &priv->amp_dev->dev;
+
+ /* Redirect calls to write firmware controls */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->write_cal_coeff,
+ cs_amp_lib_test_write_cal_coeff);
+
+ ret = cs_amp_write_ambient_temp(dsp, &cs_amp_lib_test_calibration_controls, 18);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, list_count_nodes(&priv->ctl_write_list), 1);
+
+ entry = list_first_entry(&priv->ctl_write_list, typeof(*entry), list);
+ KUNIT_EXPECT_STREQ(test, entry->name, cs_amp_lib_test_calibration_controls.ambient);
+ KUNIT_EXPECT_EQ(test, entry->value, 18);
+}
+
+static efi_status_t cs_amp_lib_test_set_efi_variable(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 attr,
+ unsigned long size,
+ void *buf)
+{
+ static const efi_char16_t expected_name[] = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+ static const efi_guid_t expected_guid = CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+
+ KUNIT_ASSERT_NOT_NULL(test, name);
+ KUNIT_ASSERT_NOT_NULL(test, guid);
+
+ if (memcmp(name, expected_name, sizeof(expected_name)) ||
+ efi_guidcmp(*guid, expected_guid))
+ return -EFI_NOT_FOUND;
+
+ KUNIT_ASSERT_NOT_NULL(test, buf);
+ KUNIT_ASSERT_NE(test, 0, size);
+
+ kunit_kfree(test, priv->cal_blob);
+ priv->cal_blob = kunit_kmalloc(test, size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+ memcpy(priv->cal_blob, buf, size);
+ priv->efi_attr = attr;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t cs_amp_lib_test_set_efi_variable_denied(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 attr,
+ unsigned long size,
+ void *buf)
+{
+ return EFI_WRITE_PROTECTED;
+}
+
+#define CS_AMP_CAL_DEFAULT_EFI_ATTR \
+ (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS)
+
+static void cs_amp_lib_test_create_new_cal_efi(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_none);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* For unspecified number of amps */
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, CS_AMP_CAL_DEFAULT_EFI_ATTR, priv->efi_attr);
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+ KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ for (i = 1; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* For 2 amps */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 2, &data));
+ KUNIT_EXPECT_EQ(test, CS_AMP_CAL_DEFAULT_EFI_ATTR, priv->efi_attr);
+ KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+
+ /* For 4 amps */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+ KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+ /* For 6 amps */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+}
+
+static void cs_amp_lib_test_create_new_cal_efi_indexed(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_none);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* In slot 0 */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* In slot 1 */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[0], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* In slot 5 */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 5, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[0], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+}
+
+static void cs_amp_lib_test_create_new_cal_efi_indexed_no_max(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_none);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* In slot 0 with unspecified number of amps */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+ KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ for (i = 1; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* In slot 1 with unspecified number of amps */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 2);
+ KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[0], sizeof(data)));
+ for (i = 2; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* In slot 5 with unspecified number of amps */
+ priv->cal_blob = NULL;
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 5, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 6);
+ KUNIT_EXPECT_LE(test, priv->cal_blob->count, 8);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ for (i = 0; (i < 5) && (i < priv->cal_blob->count); i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+ for (i = 6; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_append_cal_efi(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* Initially 1 used entry grown to 2 entries */
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 2, &data));
+ KUNIT_EXPECT_EQ(test, CS_AMP_CAL_DEFAULT_EFI_ATTR, priv->efi_attr);
+ KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+
+ /* Initially 1 entry grown to 4 entries */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+ KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+ /* Initially 2 entries grown to 4 entries */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+ KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+ KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+ /* Initially 1 entry grown to 6 entries */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 4 entries grown to 6 entries */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_append_cal_efi_indexed(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* Initially 1 entry grown to 2 entries using slot 1 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 2, &data));
+ KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+
+ /* Initially 1 entry grown to 6 entries using slot 1 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 2 entries grown to 6 entries using slot 2 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+ KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 2 entries grown to 6 entries using slot 4 */
+ kunit_kfree(test, original_blob);
+ kunit_kfree(test, priv->cal_blob);
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+ KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_all_zeros);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /*
+ * Add an entry. The header should be filled in to match the
+ * original EFI variable size.
+ */
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+ KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ for (i = 1; i < priv->cal_blob->count; i++) {
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+ }
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first_no_shrink(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_all_zeros);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /*
+ * Add an entry. The header should be filled in to match the
+ * original EFI variable size. A number of amps less than the
+ * available preallocated space does not shrink the EFI variable.
+ */
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+ KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ for (i = 1; i < priv->cal_blob->count; i++) {
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+ }
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_all_zeros);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /*
+ * Write entry to slot 2. The header should be filled in to match
+ * the original EFI variable size.
+ */
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, -1, &data));
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+ KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+ for (i = 3; i < priv->cal_blob->count; i++) {
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+ }
+}
+
+static void cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed_no_shrink(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ /* Simulate a BIOS reserving EFI space that is entirely zero-filled. */
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_all_zeros);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /*
+ * Write entry to slot 2. The header should be filled in to match
+ * the original EFI variable size. A number of amps less than the
+ * available preallocated space does not shrink the EFI variable.
+ */
+ get_random_bytes(&data, sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, 4, &data));
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+ KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+ for (i = 3; i < priv->cal_blob->count; i++) {
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[i].calTime[1]);
+ }
+}
+
+static void cs_amp_lib_test_grow_append_cal_efi_indexed_no_max(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* Initially 1 entry adding slot 1 */
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 2);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ for (i = 2; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* Initially 1 entry adding slot 3 */
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 4);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ for (i = 4; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* Initially 2 entries adding slot 3 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+ KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ for (i = 4; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* Initially 4 entries adding slot 4 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ for (i = 5; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+
+ /* Initially 4 entries adding slot 6 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 6, -1, &data));
+ KUNIT_EXPECT_GE(test, priv->cal_blob->count, 1);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, priv->cal_blob->count),
+ priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[6], sizeof(data));
+ for (i = 7; i < priv->cal_blob->count; i++)
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[i], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_cal_efi_replace_indexed(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* Initially 1 entry grown to 2 entries overwriting slot 0 */
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, 2, &data));
+ KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+
+ /* Initially 2 entries grown to 4 entries overwriting slot 1 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+ KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 4, &data));
+ KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+ /* Initially 4 entries grown to 6 entries overwriting slot 1 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 4 entries grown to 6 entries overwriting slot 3 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 6 entries grown to 8 entries overwriting slot 4 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa; /* won't match */
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, 8, &data));
+ KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[6], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[7], sizeof(data)));
+}
+
+static void cs_amp_lib_test_grow_cal_efi_replace_by_uid(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /* Initially 1 entry grown to 2 entries overwriting slot 0 */
+ cs_amp_lib_test_init_dummy_cal_blob(test, 1);
+ KUNIT_ASSERT_EQ(test, 1, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[0].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 2, &data));
+ KUNIT_EXPECT_EQ(test, 2, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 2), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[1], sizeof(data)));
+
+ /* Initially 2 entries grown to 4 entries overwriting slot 1 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 2);
+ KUNIT_ASSERT_EQ(test, 2, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[1].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 4, &data));
+ KUNIT_EXPECT_EQ(test, 4, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 4), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[2], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[3], sizeof(data)));
+
+ /* Initially 4 entries grown to 6 entries overwriting slot 1 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[1].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 4 entries grown to 6 entries overwriting slot 3 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[3].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 6, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[4], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[5], sizeof(data)));
+
+ /* Initially 6 entries grown to 8 entries overwriting slot 4 */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[4].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, 8, &data));
+ KUNIT_EXPECT_EQ(test, 8, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 8), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[6], sizeof(data)));
+ KUNIT_EXPECT_TRUE(test, mem_is_zero(&priv->cal_blob->data[7], sizeof(data)));
+}
+
+static void cs_amp_lib_test_cal_efi_replace_by_uid(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+ /* Replace entry matching slot 0 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[0].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 4 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[4].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 3 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[3].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 5 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[5].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_cal_efi_replace_by_index(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+ /*
+ * Replace entry matching slot 0.
+ * data.calTarget is deliberately set different to current calTarget
+ * of the slot to check that the index forces that slot to be used.
+ */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = ~priv->cal_blob->data[0].calTarget[0];
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 4 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = ~priv->cal_blob->data[4].calTarget[0];
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 3 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = ~priv->cal_blob->data[3].calTarget[0];
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 3, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 5 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = ~priv->cal_blob->data[5].calTarget[0];
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 5, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_cal_efi_deduplicate(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+ int i;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ /*
+ * Replace entry matching slot 0.
+ * An active entry in slot 1 for the same UID should be marked empty.
+ * Other entries are unaltered.
+ */
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[1].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 0, -1, &data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+
+ /*
+ * Replace entry matching slot 1.
+ * An active entry in slot 0 for the same UID should be marked empty.
+ * Other entries are unaltered.
+ */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[0].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+
+ /*
+ * Replace entry matching slot 1.
+ * An active entry in slot 3 for the same UID should be marked empty.
+ * Other entries are unaltered.
+ */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ memcpy(data.calTarget, priv->cal_blob->data[3].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 1, -1, &data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[1]);
+
+ /*
+ * Worst case, all entries have the same UID
+ */
+ priv->cal_blob = NULL;
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ for (i = 0; i < priv->cal_blob->count; i++) {
+ priv->cal_blob->data[i].calTarget[0] = 0xe5e5e5e5;
+ priv->cal_blob->data[i].calTarget[1] = 0xa7a7a7a7;
+ }
+ memcpy(data.calTarget, priv->cal_blob->data[2].calTarget, sizeof(data.calTarget));
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 2, -1, &data));
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[0].calTime[1]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[1].calTime[1]);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[0]);
+ KUNIT_EXPECT_EQ(test, 0, priv->cal_blob->data[3].calTime[1]);
+}
+
+static void cs_amp_lib_test_cal_efi_find_free(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+ /*
+ * Slot 0 is empty.
+ * data.calTarget is set to a value that won't match any existing entry.
+ */
+ memset(&priv->cal_blob->data[0].calTime, 0, sizeof(priv->cal_blob->data[0].calTime));
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa;
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Slot 4 is empty */
+ memset(&priv->cal_blob->data[4].calTime, 0, sizeof(priv->cal_blob->data[4].calTime));
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa;
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Slot 3 is empty */
+ memset(&priv->cal_blob->data[3].calTime, 0, sizeof(priv->cal_blob->data[3].calTime));
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa;
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+
+ /* Replace entry matching slot 5 */
+ memset(&priv->cal_blob->data[5].calTime, 0, sizeof(priv->cal_blob->data[5].calTime));
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = 0xaaaaaaaa;
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[4], &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_cal_efi_bad_cal_target(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+
+ /* Zero calTarget is illegal */
+ get_random_bytes(&data, sizeof(data));
+ memset(data.calTarget, 0, sizeof(data.calTarget));
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, -1, -1, &data), 0);
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 0, -1, &data), 0);
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 0, 2, &data), 0);
+}
+
+static void cs_amp_lib_test_cal_efi_write_denied(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable_denied);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 4);
+ KUNIT_ASSERT_EQ(test, 4, priv->cal_blob->count);
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+
+ /* Unspecified slot */
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, -1, -1, &data), 0);
+ KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+
+ /* Unspecified slot with size */
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, -1, 6, &data), 0);
+ KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+
+ /* Specified slot */
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 1, -1, &data), 0);
+ KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+
+ /* Specified slot with size */
+ KUNIT_EXPECT_LT(test, cs_amp_set_efi_calibration_data(dev, 1, 6, &data), 0);
+ KUNIT_EXPECT_MEMEQ(test, original_blob, priv->cal_blob, original_blob->size);
+}
+
+static void cs_amp_lib_test_cal_efi_attr_preserved(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_efi_variable);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+ memset(&priv->cal_blob->data[0], 0, sizeof(priv->cal_blob->data[0]));
+ get_random_bytes(&data, sizeof(data));
+
+ /* Set a non-standard attr to return from get_efi_variable() */
+ priv->efi_attr = EFI_VARIABLE_HARDWARE_ERROR_RECORD;
+
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, -1, -1, &data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_EQ(test, priv->efi_attr, EFI_VARIABLE_HARDWARE_ERROR_RECORD);
+}
+
+static efi_status_t cs_amp_lib_test_set_hp_efi_cal_variable(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 attr,
+ unsigned long size,
+ void *buf)
+{
+ static const efi_char16_t expected_name[] = HP_CALIBRATION_EFI_NAME;
+ static const efi_guid_t expected_guid = HP_CALIBRATION_EFI_GUID;
+ struct kunit *test = kunit_get_current_test();
+ struct cs_amp_lib_test_priv *priv = test->priv;
+
+ KUNIT_ASSERT_NOT_NULL(test, name);
+ KUNIT_ASSERT_NOT_NULL(test, guid);
+
+ if (memcmp(name, expected_name, sizeof(expected_name)) ||
+ efi_guidcmp(*guid, expected_guid))
+ return -EFI_ACCESS_DENIED;
+
+ KUNIT_ASSERT_NOT_NULL(test, buf);
+ KUNIT_ASSERT_NE(test, 0, size);
+
+ kunit_kfree(test, priv->cal_blob);
+ priv->cal_blob = kunit_kmalloc(test, size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv->cal_blob);
+ memcpy(priv->cal_blob, buf, size);
+ priv->efi_attr = attr;
+
+ return EFI_SUCCESS;
+}
+
+/*
+ * If the HP EFI exists it should be the one that is updated.
+ */
+static void cs_amp_lib_test_cal_efi_update_hp(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+ const struct cirrus_amp_efi_data *original_blob;
+ struct cirrus_amp_cal_data data;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_hp_cal_efi_variable);
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->set_efi_variable,
+ cs_amp_lib_test_set_hp_efi_cal_variable);
+
+ cs_amp_lib_test_init_dummy_cal_blob(test, 6);
+ KUNIT_ASSERT_EQ(test, 6, priv->cal_blob->count);
+
+ /* Replace entry matching slot 4 */
+ original_blob = cs_amp_lib_test_cal_blob_dup(test);
+ get_random_bytes(&data, sizeof(data));
+ data.calTarget[0] = ~priv->cal_blob->data[4].calTarget[0];
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_set_efi_calibration_data(dev, 4, -1, &data));
+ KUNIT_EXPECT_EQ(test, 6, priv->cal_blob->count);
+ KUNIT_EXPECT_EQ(test, struct_size(priv->cal_blob, data, 6), priv->cal_blob->size);
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[0], &priv->cal_blob->data[0], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[1], &priv->cal_blob->data[1], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[2], &priv->cal_blob->data[2], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[3], &priv->cal_blob->data[3], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &data, &priv->cal_blob->data[4], sizeof(data));
+ KUNIT_EXPECT_MEMEQ(test, &original_blob->data[5], &priv->cal_blob->data[5], sizeof(data));
+}
+
+static void cs_amp_lib_test_spkid_lenovo_not_present(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_none);
+
+ KUNIT_EXPECT_EQ(test, -ENOENT, cs_amp_get_vendor_spkid(dev));
+}
+
+static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_d0(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ struct kunit *test = kunit_get_current_test();
+
+ if (efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID) ||
+ memcmp(name, LENOVO_SPEAKER_ID_EFI_NAME, sizeof(LENOVO_SPEAKER_ID_EFI_NAME)))
+ return EFI_NOT_FOUND;
+
+ KUNIT_ASSERT_EQ(test, *size, 1);
+ *size = 1;
+ *(u8 *)buf = 0xd0;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_d1(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ struct kunit *test = kunit_get_current_test();
+
+ if (efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID) ||
+ memcmp(name, LENOVO_SPEAKER_ID_EFI_NAME, sizeof(LENOVO_SPEAKER_ID_EFI_NAME)))
+ return EFI_NOT_FOUND;
+
+ KUNIT_ASSERT_EQ(test, *size, 1);
+ *size = 1;
+ *(u8 *)buf = 0xd1;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t cs_amp_lib_test_get_efi_variable_lenovo_00(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ struct kunit *test = kunit_get_current_test();
+
+ KUNIT_ASSERT_EQ(test, 0, efi_guidcmp(*guid, LENOVO_SPEAKER_ID_EFI_GUID));
+ KUNIT_ASSERT_EQ(test, *size, 1);
+ *size = 1;
+ *(u8 *)buf = 0;
+
+ return EFI_SUCCESS;
+}
+
+static void cs_amp_lib_test_spkid_lenovo_d0(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_lenovo_d0);
+
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_get_vendor_spkid(dev));
+}
+
+static void cs_amp_lib_test_spkid_lenovo_d1(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_lenovo_d1);
+
+ KUNIT_EXPECT_EQ(test, 1, cs_amp_get_vendor_spkid(dev));
+}
+
+static void cs_amp_lib_test_spkid_lenovo_illegal(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_lenovo_00);
+
+ KUNIT_EXPECT_LT(test, cs_amp_get_vendor_spkid(dev), 0);
+}
+
+static efi_status_t cs_amp_lib_test_get_efi_variable_buf_too_small(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ return EFI_BUFFER_TOO_SMALL;
+}
+
+static void cs_amp_lib_test_spkid_lenovo_oversize(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_buf_too_small);
+
+ KUNIT_EXPECT_LT(test, cs_amp_get_vendor_spkid(dev), 0);
+}
+
+static efi_status_t cs_amp_lib_test_get_efi_variable_hp_30(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ struct kunit *test = kunit_get_current_test();
+
+ if (efi_guidcmp(*guid, HP_SPEAKER_ID_EFI_GUID) ||
+ memcmp(name, HP_SPEAKER_ID_EFI_NAME, sizeof(HP_SPEAKER_ID_EFI_NAME)))
+ return EFI_NOT_FOUND;
+
+ KUNIT_ASSERT_EQ(test, *size, 1);
+ *size = 1;
+ *(u8 *)buf = 0x30;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t cs_amp_lib_test_get_efi_variable_hp_31(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ struct kunit *test = kunit_get_current_test();
+
+ if (efi_guidcmp(*guid, HP_SPEAKER_ID_EFI_GUID) ||
+ memcmp(name, HP_SPEAKER_ID_EFI_NAME, sizeof(HP_SPEAKER_ID_EFI_NAME)))
+ return EFI_NOT_FOUND;
+
+ KUNIT_ASSERT_EQ(test, *size, 1);
+ *size = 1;
+ *(u8 *)buf = 0x31;
+
+ return EFI_SUCCESS;
+}
+
+static void cs_amp_lib_test_spkid_hp_30(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_hp_30);
+
+ KUNIT_EXPECT_EQ(test, 0, cs_amp_get_vendor_spkid(dev));
+}
+
+static void cs_amp_lib_test_spkid_hp_31(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv = test->priv;
+ struct device *dev = &priv->amp_dev->dev;
+
+ kunit_activate_static_stub(test,
+ cs_amp_test_hooks->get_efi_variable,
+ cs_amp_lib_test_get_efi_variable_hp_31);
+
+ KUNIT_EXPECT_EQ(test, 1, cs_amp_get_vendor_spkid(dev));
+}
+
+static int cs_amp_lib_test_case_init(struct kunit *test)
+{
+ struct cs_amp_lib_test_priv *priv;
+
+ KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks);
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ test->priv = priv;
+ INIT_LIST_HEAD(&priv->ctl_write_list);
+
+ /* Create dummy amp driver dev */
+ priv->amp_dev = faux_device_create("cs_amp_lib_test_drv", NULL, NULL);
+ KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
+ KUNIT_ASSERT_EQ(test, 0,
+ kunit_add_action_or_reset(test,
+ faux_device_destroy_wrapper,
+ priv->amp_dev));
+
+ return 0;
+}
+
+static const struct cs_amp_lib_test_param cs_amp_lib_test_get_cal_param_cases[] = {
+ { .num_amps = 2, .amp_index = 0 },
+ { .num_amps = 2, .amp_index = 1 },
+
+ { .num_amps = 3, .amp_index = 0 },
+ { .num_amps = 3, .amp_index = 1 },
+ { .num_amps = 3, .amp_index = 2 },
+
+ { .num_amps = 4, .amp_index = 0 },
+ { .num_amps = 4, .amp_index = 1 },
+ { .num_amps = 4, .amp_index = 2 },
+ { .num_amps = 4, .amp_index = 3 },
+
+ { .num_amps = 5, .amp_index = 0 },
+ { .num_amps = 5, .amp_index = 1 },
+ { .num_amps = 5, .amp_index = 2 },
+ { .num_amps = 5, .amp_index = 3 },
+ { .num_amps = 5, .amp_index = 4 },
+
+ { .num_amps = 6, .amp_index = 0 },
+ { .num_amps = 6, .amp_index = 1 },
+ { .num_amps = 6, .amp_index = 2 },
+ { .num_amps = 6, .amp_index = 3 },
+ { .num_amps = 6, .amp_index = 4 },
+ { .num_amps = 6, .amp_index = 5 },
+
+ { .num_amps = 8, .amp_index = 0 },
+ { .num_amps = 8, .amp_index = 1 },
+ { .num_amps = 8, .amp_index = 2 },
+ { .num_amps = 8, .amp_index = 3 },
+ { .num_amps = 8, .amp_index = 4 },
+ { .num_amps = 8, .amp_index = 5 },
+ { .num_amps = 8, .amp_index = 6 },
+ { .num_amps = 8, .amp_index = 7 },
+};
+
+static void cs_amp_lib_test_get_cal_param_desc(const struct cs_amp_lib_test_param *param,
+ char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE, "num_amps:%d amp_index:%d",
+ param->num_amps, param->amp_index);
+}
+
+KUNIT_ARRAY_PARAM(cs_amp_lib_test_get_cal, cs_amp_lib_test_get_cal_param_cases,
+ cs_amp_lib_test_get_cal_param_desc);
+
+static struct kunit_case cs_amp_lib_test_cases[] = {
+ /* Tests for getting calibration data from EFI */
+ KUNIT_CASE(cs_amp_lib_test_cal_data_too_short_test),
+ KUNIT_CASE(cs_amp_lib_test_cal_count_too_big_test),
+ KUNIT_CASE(cs_amp_lib_test_no_cal_data_test),
+ KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_noindex_test),
+ KUNIT_CASE(cs_amp_lib_test_get_efi_cal_uid_not_found_index_not_found_test),
+ KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_index_not_found_test),
+ KUNIT_CASE(cs_amp_lib_test_get_efi_cal_no_uid_no_index_test),
+ KUNIT_CASE(cs_amp_lib_test_get_efi_cal_zero_not_matched_test),
+ KUNIT_CASE(cs_amp_lib_test_get_hp_efi_cal),
+ KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_uid_test,
+ cs_amp_lib_test_get_cal_gen_params),
+ KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_unchecked_test,
+ cs_amp_lib_test_get_cal_gen_params),
+ KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_checked_test,
+ cs_amp_lib_test_get_cal_gen_params),
+ KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_uid_mismatch_test,
+ cs_amp_lib_test_get_cal_gen_params),
+ KUNIT_CASE_PARAM(cs_amp_lib_test_get_efi_cal_by_index_fallback_test,
+ cs_amp_lib_test_get_cal_gen_params),
+ KUNIT_CASE(cs_amp_lib_test_get_efi_cal_empty_entry_test),
+
+ /* Tests for writing and reading calibration data */
+ KUNIT_CASE(cs_amp_lib_test_write_cal_data_test),
+ KUNIT_CASE(cs_amp_lib_test_read_cal_data_test),
+ KUNIT_CASE(cs_amp_lib_test_write_ambient_test),
+
+ /* Test cases for writing cal data to UEFI */
+ KUNIT_CASE(cs_amp_lib_test_create_new_cal_efi),
+ KUNIT_CASE(cs_amp_lib_test_create_new_cal_efi_indexed),
+ KUNIT_CASE(cs_amp_lib_test_create_new_cal_efi_indexed_no_max),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first_no_shrink),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_all_zeros_add_first_indexed_no_shrink),
+ KUNIT_CASE(cs_amp_lib_test_grow_append_cal_efi),
+ KUNIT_CASE(cs_amp_lib_test_grow_append_cal_efi_indexed),
+ KUNIT_CASE(cs_amp_lib_test_grow_append_cal_efi_indexed_no_max),
+ KUNIT_CASE(cs_amp_lib_test_grow_cal_efi_replace_indexed),
+ KUNIT_CASE(cs_amp_lib_test_grow_cal_efi_replace_by_uid),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_replace_by_uid),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_replace_by_index),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_deduplicate),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_find_free),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_bad_cal_target),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_write_denied),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_attr_preserved),
+ KUNIT_CASE(cs_amp_lib_test_cal_efi_update_hp),
+
+ /* Test cases for speaker ID */
+ KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_not_present),
+ KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d0),
+ KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_d1),
+ KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_illegal),
+ KUNIT_CASE(cs_amp_lib_test_spkid_lenovo_oversize),
+ KUNIT_CASE(cs_amp_lib_test_spkid_hp_30),
+ KUNIT_CASE(cs_amp_lib_test_spkid_hp_31),
+
+ { } /* terminator */
+};
+
+static struct kunit_suite cs_amp_lib_test_suite = {
+ .name = "snd-soc-cs-amp-lib-test",
+ .init = cs_amp_lib_test_case_init,
+ .test_cases = cs_amp_lib_test_cases,
+};
+
+kunit_test_suite(cs_amp_lib_test_suite);
+
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
+MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
new file mode 100644
index 000000000000..8c9fd9980a7d
--- /dev/null
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -0,0 +1,737 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Common code for Cirrus Logic Smart Amplifiers
+//
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <asm/byteorder.h>
+#include <kunit/static_stub.h>
+#include <linux/cleanup.h>
+#include <linux/debugfs.h>
+#include <linux/dev_printk.h>
+#include <linux/efi.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/slab.h>
+#include <linux/timekeeping.h>
+#include <linux/types.h>
+#include <sound/cs-amp-lib.h>
+
+#define CIRRUS_LOGIC_CALIBRATION_EFI_NAME L"CirrusSmartAmpCalibrationData"
+#define CIRRUS_LOGIC_CALIBRATION_EFI_GUID \
+ EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3)
+
+#define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker"
+#define LENOVO_SPEAKER_ID_EFI_GUID \
+ EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82)
+
+#define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID"
+#define HP_SPEAKER_ID_EFI_GUID \
+ EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e)
+
+#define HP_CALIBRATION_EFI_NAME L"SmartAmpCalibrationData"
+#define HP_CALIBRATION_EFI_GUID \
+ EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93)
+
+static const struct cs_amp_lib_cal_efivar {
+ efi_char16_t *name;
+ efi_guid_t *guid;
+} cs_amp_lib_cal_efivars[] = {
+ {
+ .name = HP_CALIBRATION_EFI_NAME,
+ .guid = &HP_CALIBRATION_EFI_GUID,
+ },
+ {
+ .name = CIRRUS_LOGIC_CALIBRATION_EFI_NAME,
+ .guid = &CIRRUS_LOGIC_CALIBRATION_EFI_GUID,
+ },
+};
+
+#define CS_AMP_CAL_DEFAULT_EFI_ATTR \
+ (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS)
+
+/* Offset from Unix time to Windows time (100ns since 1 Jan 1601) */
+#define UNIX_TIME_TO_WINDOWS_TIME_OFFSET 116444736000000000ULL
+
+static DEFINE_MUTEX(cs_amp_efi_cal_write_lock);
+
+static u64 cs_amp_time_now_in_windows_time(void)
+{
+ u64 time_in_100ns = div_u64(ktime_get_real_ns(), 100);
+
+ return time_in_100ns + UNIX_TIME_TO_WINDOWS_TIME_OFFSET;
+}
+
+static int cs_amp_write_cal_coeff(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ const char *ctl_name, u32 val)
+{
+ struct cs_dsp_coeff_ctl *cs_ctl;
+ __be32 beval = cpu_to_be32(val);
+ int ret;
+
+ KUNIT_STATIC_STUB_REDIRECT(cs_amp_write_cal_coeff, dsp, controls, ctl_name, val);
+
+ if (IS_REACHABLE(CONFIG_FW_CS_DSP)) {
+ mutex_lock(&dsp->pwr_lock);
+ cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id);
+ ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval));
+ mutex_unlock(&dsp->pwr_lock);
+
+ if (ret < 0) {
+ dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int cs_amp_read_cal_coeff(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ const char *ctl_name, u32 *val)
+{
+ struct cs_dsp_coeff_ctl *cs_ctl;
+ __be32 beval;
+ int ret;
+
+ KUNIT_STATIC_STUB_REDIRECT(cs_amp_read_cal_coeff, dsp, controls, ctl_name, val);
+
+ if (!IS_REACHABLE(CONFIG_FW_CS_DSP))
+ return -ENODEV;
+
+ scoped_guard(mutex, &dsp->pwr_lock) {
+ cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id);
+ ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &beval, sizeof(beval));
+ }
+
+ if (ret < 0) {
+ dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret);
+ return ret;
+ }
+
+ *val = be32_to_cpu(beval);
+
+ return 0;
+}
+
+static int _cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ const struct cirrus_amp_cal_data *data)
+{
+ int ret;
+
+ dev_dbg(dsp->dev, "Calibration: Ambient=%#x, Status=%#x, CalR=%d\n",
+ data->calAmbient, data->calStatus, data->calR);
+
+ if (list_empty(&dsp->ctl_list)) {
+ dev_info(dsp->dev, "Calibration disabled due to missing firmware controls\n");
+ return -ENOENT;
+ }
+
+ ret = cs_amp_write_cal_coeff(dsp, controls, controls->ambient, data->calAmbient);
+ if (ret)
+ return ret;
+
+ ret = cs_amp_write_cal_coeff(dsp, controls, controls->calr, data->calR);
+ if (ret)
+ return ret;
+
+ ret = cs_amp_write_cal_coeff(dsp, controls, controls->status, data->calStatus);
+ if (ret)
+ return ret;
+
+ ret = cs_amp_write_cal_coeff(dsp, controls, controls->checksum, data->calR + 1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int _cs_amp_read_cal_coeffs(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ struct cirrus_amp_cal_data *data)
+{
+ u64 time;
+ u32 val;
+ int ret;
+
+ if (list_empty(&dsp->ctl_list)) {
+ dev_info(dsp->dev, "Calibration disabled due to missing firmware controls\n");
+ return -ENOENT;
+ }
+
+ ret = cs_amp_read_cal_coeff(dsp, controls, controls->ambient, &val);
+ if (ret)
+ return ret;
+
+ data->calAmbient = (s8)val;
+
+ ret = cs_amp_read_cal_coeff(dsp, controls, controls->calr, &val);
+ if (ret)
+ return ret;
+
+ data->calR = (u16)val;
+
+ ret = cs_amp_read_cal_coeff(dsp, controls, controls->status, &val);
+ if (ret)
+ return ret;
+
+ data->calStatus = (u8)val;
+
+ /* Fill in timestamp */
+ time = cs_amp_time_now_in_windows_time();
+ data->calTime[0] = (u32)time;
+ data->calTime[1] = (u32)(time >> 32);
+
+ return 0;
+}
+
+/**
+ * cs_amp_write_cal_coeffs - Write calibration data to firmware controls.
+ * @dsp: Pointer to struct cs_dsp.
+ * @controls: Pointer to definition of firmware controls to be written.
+ * @data: Pointer to calibration data.
+ *
+ * Returns: 0 on success, else negative error value.
+ */
+int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ const struct cirrus_amp_cal_data *data)
+{
+ if (IS_REACHABLE(CONFIG_FW_CS_DSP) || IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+ return _cs_amp_write_cal_coeffs(dsp, controls, data);
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_write_cal_coeffs, "SND_SOC_CS_AMP_LIB");
+
+/**
+ * cs_amp_read_cal_coeffs - Read calibration data from firmware controls.
+ * @dsp: Pointer to struct cs_dsp.
+ * @controls: Pointer to definition of firmware controls to be read.
+ * @data: Pointer to calibration data where results will be written.
+ *
+ * Returns: 0 on success, else negative error value.
+ */
+int cs_amp_read_cal_coeffs(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ struct cirrus_amp_cal_data *data)
+{
+ if (IS_REACHABLE(CONFIG_FW_CS_DSP) || IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+ return _cs_amp_read_cal_coeffs(dsp, controls, data);
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_read_cal_coeffs, "SND_SOC_CS_AMP_LIB");
+
+/**
+ * cs_amp_write_ambient_temp - write value to calibration ambient temperature
+ * @dsp: Pointer to struct cs_dsp.
+ * @controls: Pointer to definition of firmware controls to be read.
+ * @temp: Temperature in degrees celcius.
+ *
+ * Returns: 0 on success, else negative error value.
+ */
+int cs_amp_write_ambient_temp(struct cs_dsp *dsp,
+ const struct cirrus_amp_cal_controls *controls,
+ u32 temp)
+{
+ if (IS_REACHABLE(CONFIG_FW_CS_DSP) || IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+ return cs_amp_write_cal_coeff(dsp, controls, controls->ambient, temp);
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_write_ambient_temp, "SND_SOC_CS_AMP_LIB");
+
+static efi_status_t cs_amp_get_efi_variable(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 *returned_attr,
+ unsigned long *size,
+ void *buf)
+{
+ u32 attr;
+
+ if (!returned_attr)
+ returned_attr = &attr;
+
+ KUNIT_STATIC_STUB_REDIRECT(cs_amp_get_efi_variable, name, guid,
+ returned_attr, size, buf);
+
+ if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+ return efi.get_variable(name, guid, returned_attr, size, buf);
+
+ return EFI_NOT_FOUND;
+}
+
+static efi_status_t cs_amp_set_efi_variable(efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 attr,
+ unsigned long size,
+ void *buf)
+{
+ KUNIT_STATIC_STUB_REDIRECT(cs_amp_set_efi_variable, name, guid, attr, size, buf);
+
+ if (!efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
+ return EFI_NOT_FOUND;
+
+ return efi.set_variable(name, guid, attr, size, buf);
+}
+
+static int cs_amp_convert_efi_status(efi_status_t status)
+{
+ switch (status) {
+ case EFI_SUCCESS:
+ return 0;
+ case EFI_NOT_FOUND:
+ return -ENOENT;
+ case EFI_BUFFER_TOO_SMALL:
+ return -EFBIG;
+ case EFI_WRITE_PROTECTED:
+ case EFI_UNSUPPORTED:
+ case EFI_ACCESS_DENIED:
+ case EFI_SECURITY_VIOLATION:
+ return -EACCES;
+ default:
+ return -EIO;
+ }
+}
+
+static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev,
+ efi_char16_t **name,
+ efi_guid_t **guid,
+ u32 *attr)
+{
+ struct cirrus_amp_efi_data *efi_data __free(kfree) = NULL;
+ unsigned long data_size = 0;
+ efi_status_t status;
+ int i, ret;
+
+ /* Find EFI variable and get size */
+ for (i = 0; i < ARRAY_SIZE(cs_amp_lib_cal_efivars); i++) {
+ status = cs_amp_get_efi_variable(cs_amp_lib_cal_efivars[i].name,
+ cs_amp_lib_cal_efivars[i].guid,
+ attr, &data_size, NULL);
+ if (status == EFI_BUFFER_TOO_SMALL)
+ break;
+ }
+
+ if (status != EFI_BUFFER_TOO_SMALL)
+ return ERR_PTR(-ENOENT);
+
+ if (name)
+ *name = cs_amp_lib_cal_efivars[i].name;
+
+ if (guid)
+ *guid = cs_amp_lib_cal_efivars[i].guid;
+
+ if (data_size < sizeof(*efi_data)) {
+ dev_err(dev, "EFI cal variable truncated\n");
+ return ERR_PTR(-EOVERFLOW);
+ }
+
+ /* Get variable contents into buffer */
+ efi_data = kmalloc(data_size, GFP_KERNEL);
+ if (!efi_data)
+ return ERR_PTR(-ENOMEM);
+
+ status = cs_amp_get_efi_variable(cs_amp_lib_cal_efivars[i].name,
+ cs_amp_lib_cal_efivars[i].guid,
+ attr, &data_size, efi_data);
+ if (status != EFI_SUCCESS) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dev_dbg(dev, "Calibration: Size=%d, Amp Count=%d\n", efi_data->size, efi_data->count);
+
+ if ((efi_data->count > 128) ||
+ struct_size(efi_data, data, efi_data->count) > data_size) {
+ dev_err(dev, "EFI cal variable truncated\n");
+ ret = -EOVERFLOW;
+ goto err;
+ }
+
+ /* This could be zero-filled space pre-allocated by the BIOS */
+ if (efi_data->size == 0)
+ efi_data->size = data_size;
+
+ return_ptr(efi_data);
+
+err:
+ dev_err(dev, "Failed to read calibration data from EFI: %d\n", ret);
+
+ return ERR_PTR(ret);
+}
+
+static int cs_amp_set_cal_efi_buffer(struct device *dev,
+ efi_char16_t *name,
+ efi_guid_t *guid,
+ u32 attr,
+ struct cirrus_amp_efi_data *data)
+{
+ efi_status_t status;
+
+ status = cs_amp_set_efi_variable(name, guid, attr,
+ struct_size(data, data, data->count), data);
+
+ return cs_amp_convert_efi_status(status);
+}
+
+static int _cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
+ struct cirrus_amp_cal_data *out_data)
+{
+ struct cirrus_amp_efi_data *efi_data __free(kfree) = NULL;
+ struct cirrus_amp_cal_data *cal = NULL;
+ int i;
+
+ efi_data = cs_amp_get_cal_efi_buffer(dev, NULL, NULL, NULL);
+ if (IS_ERR(efi_data))
+ return PTR_ERR(efi_data);
+
+ if (target_uid) {
+ for (i = 0; i < efi_data->count; ++i) {
+ u64 cal_target = cs_amp_cal_target_u64(&efi_data->data[i]);
+
+ /* Skip empty entries */
+ if (!efi_data->data[i].calTime[0] && !efi_data->data[i].calTime[1])
+ continue;
+
+ /* Skip entries with unpopulated silicon ID */
+ if (cal_target == 0)
+ continue;
+
+ if (cal_target == target_uid) {
+ cal = &efi_data->data[i];
+ break;
+ }
+ }
+ }
+
+ if (!cal && (amp_index >= 0) && (amp_index < efi_data->count) &&
+ (efi_data->data[amp_index].calTime[0] || efi_data->data[amp_index].calTime[1])) {
+ u64 cal_target = cs_amp_cal_target_u64(&efi_data->data[amp_index]);
+
+ /*
+ * Treat unpopulated cal_target as a wildcard.
+ * If target_uid != 0 we can only get here if cal_target == 0
+ * or it didn't match any cal_target value.
+ * If target_uid == 0 it is a wildcard.
+ */
+ if ((cal_target == 0) || (target_uid == 0))
+ cal = &efi_data->data[amp_index];
+ else
+ dev_warn(dev, "Calibration entry %d does not match silicon ID", amp_index);
+ }
+
+ if (!cal) {
+ dev_warn(dev, "No calibration for silicon ID %#llx\n", target_uid);
+ return -ENOENT;
+ }
+
+ memcpy(out_data, cal, sizeof(*out_data));
+
+ return 0;
+}
+
+static int _cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, int num_amps,
+ const struct cirrus_amp_cal_data *in_data)
+{
+ u64 cal_target = cs_amp_cal_target_u64(in_data);
+ unsigned long num_entries;
+ struct cirrus_amp_efi_data *data __free(kfree) = NULL;
+ efi_char16_t *name = CIRRUS_LOGIC_CALIBRATION_EFI_NAME;
+ efi_guid_t *guid = &CIRRUS_LOGIC_CALIBRATION_EFI_GUID;
+ u32 attr = CS_AMP_CAL_DEFAULT_EFI_ATTR;
+ int i, ret;
+
+ if (cal_target == 0)
+ return -EINVAL;
+
+ data = cs_amp_get_cal_efi_buffer(dev, &name, &guid, &attr);
+ ret = PTR_ERR_OR_ZERO(data);
+ if (ret == -ENOENT) {
+ data = NULL;
+ goto alloc_new;
+ } else if (ret) {
+ return ret;
+ }
+
+ /*
+ * If the EFI variable is just zero-filled reserved space the count
+ * must be set.
+ */
+ if (data->count == 0)
+ data->count = (data->size - sizeof(data)) / sizeof(data->data[0]);
+
+ if (amp_index < 0) {
+ /* Is there already a slot for this target? */
+ for (amp_index = 0; amp_index < data->count; amp_index++) {
+ if (cs_amp_cal_target_u64(&data->data[amp_index]) == cal_target)
+ break;
+ }
+
+ /* Else find an empty slot */
+ if (amp_index >= data->count) {
+ for (amp_index = 0; amp_index < data->count; amp_index++) {
+ if ((data->data[amp_index].calTime[0] == 0) &&
+ (data->data[amp_index].calTime[1] == 0))
+ break;
+ }
+ }
+ } else {
+ /*
+ * If the index is forced there could be another active
+ * slot with the same calTarget. So deduplicate.
+ */
+ for (i = 0; i < data->count; i++) {
+ if (i == amp_index)
+ continue;
+
+ if ((data->data[i].calTime[0] == 0) && (data->data[i].calTime[1] == 0))
+ continue;
+
+ if (cs_amp_cal_target_u64(&data->data[i]) == cal_target)
+ memset(data->data[i].calTime, 0, sizeof(data->data[i].calTime));
+ }
+ }
+
+alloc_new:
+ if (amp_index < 0)
+ amp_index = 0;
+
+ num_entries = max(num_amps, amp_index + 1);
+ if (!data || (data->count < num_entries)) {
+ struct cirrus_amp_efi_data *old_data __free(kfree) = no_free_ptr(data);
+ unsigned int new_data_size = struct_size(data, data, num_entries);
+
+ data = kzalloc(new_data_size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (old_data)
+ memcpy(data, old_data, struct_size(old_data, data, old_data->count));
+
+ data->count = num_entries;
+ data->size = new_data_size;
+ }
+
+ data->data[amp_index] = *in_data;
+ ret = cs_amp_set_cal_efi_buffer(dev, name, guid, attr, data);
+ if (ret) {
+ dev_err(dev, "Failed writing calibration to EFI: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * cs_amp_get_efi_calibration_data - get an entry from calibration data in EFI.
+ * @dev: struct device of the caller.
+ * @target_uid: UID to match, or zero to ignore UID matching.
+ * @amp_index: Entry index to use, or -1 to prevent lookup by index.
+ * @out_data: struct cirrus_amp_cal_data where the entry will be copied.
+ *
+ * This function can perform 3 types of lookup:
+ *
+ * (target_uid > 0, amp_index >= 0)
+ * UID search with fallback to using the array index.
+ * Search the calibration data for a non-zero calTarget that matches
+ * target_uid, and if found return that entry. Else, if the entry at
+ * [amp_index] has calTarget == 0, return that entry. Else fail.
+ *
+ * (target_uid > 0, amp_index < 0)
+ * UID search only.
+ * Search the calibration data for a non-zero calTarget that matches
+ * target_uid, and if found return that entry. Else fail.
+ *
+ * (target_uid == 0, amp_index >= 0)
+ * Array index fetch only.
+ * Return the entry at [amp_index].
+ *
+ * An array lookup will be skipped if amp_index exceeds the number of
+ * entries in the calibration array, and in this case the return will
+ * be -ENOENT. An out-of-range amp_index does not prevent matching by
+ * target_uid - it has the same effect as passing amp_index < 0.
+ *
+ * If the EFI data is too short to be a valid entry, or the entry count
+ * in the EFI data overflows the actual length of the data, this function
+ * returns -EOVERFLOW.
+ *
+ * Return: 0 if the entry was found, -ENOENT if no entry was found,
+ * -EOVERFLOW if the EFI file is corrupt, else other error value.
+ */
+int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
+ struct cirrus_amp_cal_data *out_data)
+{
+ if (IS_ENABLED(CONFIG_EFI) || IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+ return _cs_amp_get_efi_calibration_data(dev, target_uid, amp_index, out_data);
+ else
+ return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, "SND_SOC_CS_AMP_LIB");
+
+/**
+ * cs_amp_set_efi_calibration_data - write a calibration data entry to EFI.
+ * @dev: struct device of the caller.
+ * @amp_index: Entry index to use, or -1 to use any available slot.
+ * @num_amps: Maximum number of amps to reserve slots for, or -1 to ignore.
+ * @in_data: struct cirrus_amp_cal_data entry to be written to EFI.
+ *
+ * If a Vendor-specific variable exists it will be updated,
+ * else if the Cirrus variable exists it will be updated
+ * else the Cirrus variable will be created.
+ *
+ * If amp_index >= 0 the data will be placed in this entry of the calibration
+ * data array, overwriting what was in that entry. Any other entries with the
+ * same calTarget will be marked empty.
+ *
+ * If amp_index < 0 and in_data->calTarget matches any existing entry, that
+ * entry will be overwritten. Else the first available free entry will be used,
+ * extending the size of the EFI variable if there are no free entries.
+ *
+ * If num_amps > 0 the EFI variable will be sized to contain at least this
+ * many calibration entries, with any new entries marked empty.
+ *
+ * Return: 0 if the write was successful, -EFBIG if space could not be made in
+ * the EFI file to add the entry, -EACCES if it was not possible to
+ * read or write the EFI variable.
+ */
+int cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, int num_amps,
+ const struct cirrus_amp_cal_data *in_data)
+{
+ if (IS_ENABLED(CONFIG_EFI) || IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST)) {
+ scoped_guard(mutex, &cs_amp_efi_cal_write_lock) {
+ return _cs_amp_set_efi_calibration_data(dev, amp_index,
+ num_amps, in_data);
+ }
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_set_efi_calibration_data, "SND_SOC_CS_AMP_LIB");
+
+struct cs_amp_spkid_efi {
+ efi_char16_t *name;
+ efi_guid_t *guid;
+ u8 values[2];
+};
+
+static int cs_amp_get_efi_byte_spkid(struct device *dev, const struct cs_amp_spkid_efi *info)
+{
+ efi_status_t status;
+ unsigned long size;
+ u8 spkid;
+ int i, ret;
+
+ size = sizeof(spkid);
+ status = cs_amp_get_efi_variable(info->name, info->guid, NULL, &size, &spkid);
+ ret = cs_amp_convert_efi_status(status);
+ if (ret < 0)
+ return ret;
+
+ if (size == 0)
+ return -ENOENT;
+
+ for (i = 0; i < ARRAY_SIZE(info->values); i++) {
+ if (info->values[i] == spkid)
+ return i;
+ }
+
+ dev_err(dev, "EFI speaker ID bad value %#x\n", spkid);
+
+ return -EINVAL;
+}
+
+static const struct cs_amp_spkid_efi cs_amp_spkid_byte_types[] = {
+ {
+ .name = LENOVO_SPEAKER_ID_EFI_NAME,
+ .guid = &LENOVO_SPEAKER_ID_EFI_GUID,
+ .values = { 0xd0, 0xd1 },
+ },
+ {
+ .name = HP_SPEAKER_ID_EFI_NAME,
+ .guid = &HP_SPEAKER_ID_EFI_GUID,
+ .values = { 0x30, 0x31 },
+ },
+};
+
+/**
+ * cs_amp_get_vendor_spkid - get a speaker ID from vendor-specific storage
+ * @dev: pointer to struct device
+ *
+ * Known vendor-specific methods of speaker ID are checked and if one is
+ * found its speaker ID value is returned.
+ *
+ * Return: >=0 is a valid speaker ID. -ENOENT if a vendor-specific method
+ * was not found. -EACCES if the vendor-specific storage could not
+ * be read. Other error values indicate that the data from the
+ * vendor-specific storage was found but could not be understood.
+ */
+int cs_amp_get_vendor_spkid(struct device *dev)
+{
+ int i, ret;
+
+ if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE) &&
+ !IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+ return -ENOENT;
+
+ for (i = 0; i < ARRAY_SIZE(cs_amp_spkid_byte_types); i++) {
+ ret = cs_amp_get_efi_byte_spkid(dev, &cs_amp_spkid_byte_types[i]);
+ if (ret != -ENOENT)
+ return ret;
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_get_vendor_spkid, "SND_SOC_CS_AMP_LIB");
+
+/**
+ * cs_amp_create_debugfs - create a debugfs directory for a device
+ *
+ * @dev: pointer to struct device
+ *
+ * Creates a node under "cirrus_logic" in the root of the debugfs filesystem.
+ * This is for Cirrus-specific debugfs functionality to be grouped in a
+ * defined way, independently of the debugfs provided by ALSA/ASoC.
+ * The general ALSA/ASoC debugfs may not be enabled, and does not necessarily
+ * have a stable layout or naming convention.
+ *
+ * Return: Pointer to the dentry for the created directory, or -ENODEV.
+ */
+struct dentry *cs_amp_create_debugfs(struct device *dev)
+{
+ struct dentry *dir;
+
+ dir = debugfs_lookup("cirrus_logic", NULL);
+ if (!dir)
+ dir = debugfs_create_dir("cirrus_logic", NULL);
+
+ return debugfs_create_dir(dev_name(dev), dir);
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_create_debugfs, "SND_SOC_CS_AMP_LIB");
+
+static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = {
+ .get_efi_variable = cs_amp_get_efi_variable,
+ .set_efi_variable = cs_amp_set_efi_variable,
+ .write_cal_coeff = cs_amp_write_cal_coeff,
+ .read_cal_coeff = cs_amp_read_cal_coeff,
+};
+
+const struct cs_amp_test_hooks * const cs_amp_test_hooks =
+ PTR_IF(IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST), &cs_amp_test_hook_ptrs);
+EXPORT_SYMBOL_NS_GPL(cs_amp_test_hooks, "SND_SOC_CS_AMP_LIB");
+
+MODULE_DESCRIPTION("Cirrus Logic amplifier library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("FW_CS_DSP");
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 6e658bb16fb0..0bb4bdb3deec 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -13,13 +13,12 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -154,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;
@@ -505,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);
@@ -544,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[] = {
@@ -559,7 +555,7 @@ MODULE_DEVICE_TABLE(of, cs35l32_of_match);
static const struct i2c_device_id cs35l32_id[] = {
- {"cs35l32", 0},
+ {"cs35l32"},
{}
};
@@ -568,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 9968c2e189e6..98b4d371d931 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -22,16 +22,12 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <sound/cs35l33.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
-#include <linux/of_gpio.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include "cs35l33.h"
#include "cirrus_legacy.h"
@@ -442,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");
@@ -551,7 +547,7 @@ static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
unsigned int reg, bit_pos, i;
int slot, slot_num;
@@ -699,7 +695,7 @@ static int cs35l33_set_hg_data(struct snd_soc_component *component,
struct cs35l33_pdata *pdata)
{
struct cs35l33_hg *hg_config = &pdata->hg_config;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
if (hg_config->enable_hg_algo) {
@@ -857,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;
@@ -895,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);
@@ -913,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,
@@ -1167,7 +1161,7 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client)
/* We could issue !RST or skip it based on AMP topology */
cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
- "reset-gpios", GPIOD_OUT_HIGH);
+ "reset", GPIOD_OUT_HIGH);
if (IS_ERR(cs35l33->reset_gpio)) {
dev_err(&i2c_client->dev, "%s ERROR: Can't get reset GPIO\n",
__func__);
@@ -1268,7 +1262,7 @@ static const struct of_device_id cs35l33_of_match[] = {
MODULE_DEVICE_TABLE(of, cs35l33_of_match);
static const struct i2c_device_id cs35l33_id[] = {
- {"cs35l33", 0},
+ {"cs35l33"},
{}
};
@@ -1277,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 6974dd461410..a5a8075598ff 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -19,15 +19,13 @@
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -525,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;
@@ -564,26 +562,6 @@ static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static const unsigned int cs35l34_src_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-};
-
-
-static const struct snd_pcm_hw_constraint_list cs35l34_constraints = {
- .count = ARRAY_SIZE(cs35l34_src_rates),
- .list = cs35l34_src_rates,
-};
-
-static int cs35l34_pcm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
-
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints);
- return 0;
-}
-
-
static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate)
{
@@ -641,7 +619,6 @@ static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai,
}
static const struct snd_soc_dai_ops cs35l34_ops = {
- .startup = cs35l34_pcm_startup,
.set_tristate = cs35l34_set_tristate,
.set_fmt = cs35l34_set_dai_fmt,
.hw_params = cs35l34_pcm_hw_params,
@@ -789,7 +766,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = {
.endianness = 1,
};
-static struct regmap_config cs35l34_regmap = {
+static const struct regmap_config cs35l34_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -1061,7 +1038,7 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client)
dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
- "reset-gpios", GPIOD_OUT_LOW);
+ "reset", GPIOD_OUT_LOW);
if (IS_ERR(cs35l34->reset_gpio)) {
ret = PTR_ERR(cs35l34->reset_gpio);
goto err_regulator;
@@ -1139,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;
@@ -1172,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);
@@ -1188,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[] = {
@@ -1200,7 +1175,7 @@ static const struct of_device_id cs35l34_of_match[] = {
MODULE_DEVICE_TABLE(of, cs35l34_of_match);
static const struct i2c_device_id cs35l34_id[] = {
- {"cs35l34", 0},
+ {"cs35l34"},
{}
};
MODULE_DEVICE_TABLE(i2c, cs35l34_id);
@@ -1208,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/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 0a4b5aa78185..7a01b1d9fc9d 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -17,19 +17,16 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <linux/gpio.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/cs35l35.h>
-#include <linux/of_irq.h>
#include <linux/completion.h>
#include "cs35l35.h"
@@ -1089,7 +1086,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = {
.endianness = 1,
};
-static struct regmap_config cs35l35_regmap = {
+static const struct regmap_config cs35l35_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -1642,7 +1639,7 @@ static const struct of_device_id cs35l35_of_match[] = {
MODULE_DEVICE_TABLE(of, cs35l35_of_match);
static const struct i2c_device_id cs35l35_id[] = {
- {"cs35l35", 0},
+ {"cs35l35"},
{}
};
diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c
index 04ba7f25012e..93818d7ec1a7 100644
--- a/sound/soc/codecs/cs35l36.c
+++ b/sound/soc/codecs/cs35l36.c
@@ -17,19 +17,17 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <linux/gpio.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/cs35l36.h>
-#include <linux/of_irq.h>
#include <linux/completion.h>
#include "cs35l36.h"
@@ -131,7 +129,7 @@ static const struct cs35l36_pll_config cs35l36_pll_sysclk[] = {
{27000000, 0x3F, 0x0A},
};
-static struct reg_default cs35l36_reg[] = {
+static const struct reg_default cs35l36_reg[] = {
{CS35L36_TESTKEY_CTRL, 0x00000000},
{CS35L36_USERKEY_CTL, 0x00000000},
{CS35L36_OTP_CTRL1, 0x00002460},
@@ -457,8 +455,7 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, CS35L36_AMP_DIG_VOL_CTRL, 0,
static int cs35l36_ldm_sel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs35l36_private *cs35l36 =
snd_soc_component_get_drvdata(component);
@@ -470,8 +467,7 @@ static int cs35l36_ldm_sel_get(struct snd_kcontrol *kcontrol,
static int cs35l36_ldm_sel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs35l36_private *cs35l36 =
snd_soc_component_get_drvdata(component);
int val = (ucontrol->value.integer.value[0]) ? CS35L36_NG_AMP_EN_MASK :
@@ -951,32 +947,22 @@ static const struct cs35l36_pll_config *cs35l36_get_clk_config(
return NULL;
}
-static const unsigned int cs35l36_src_rates[] = {
- 8000, 12000, 11025, 16000, 22050, 24000, 32000,
- 44100, 48000, 88200, 96000, 176400, 192000, 384000
-};
-
-static const struct snd_pcm_hw_constraint_list cs35l36_constraints = {
- .count = ARRAY_SIZE(cs35l36_src_rates),
- .list = cs35l36_src_rates,
-};
-
-static int cs35l36_pcm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &cs35l36_constraints);
-
- return 0;
-}
-
static const struct snd_soc_dai_ops cs35l36_ops = {
- .startup = cs35l36_pcm_startup,
.set_fmt = cs35l36_set_dai_fmt,
.hw_params = cs35l36_pcm_hw_params,
.set_sysclk = cs35l36_dai_set_sysclk,
};
+#define CS35L36_RATES ( \
+ SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_12000 | \
+ SNDRV_PCM_RATE_24000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000 | \
+ SNDRV_PCM_RATE_384000)
+
static struct snd_soc_dai_driver cs35l36_dai[] = {
{
.name = "cs35l36-pcm",
@@ -985,14 +971,14 @@ static struct snd_soc_dai_driver cs35l36_dai[] = {
.stream_name = "AMP Playback",
.channels_min = 1,
.channels_max = 8,
- .rates = SNDRV_PCM_RATE_KNOT,
+ .rates = CS35L36_RATES,
.formats = CS35L36_RX_FORMATS,
},
.capture = {
.stream_name = "AMP Capture",
.channels_min = 1,
.channels_max = 8,
- .rates = SNDRV_PCM_RATE_KNOT,
+ .rates = CS35L36_RATES,
.formats = CS35L36_TX_FORMATS,
},
.ops = &cs35l36_ops,
@@ -1302,7 +1288,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = {
.endianness = 1,
};
-static struct regmap_config cs35l36_regmap = {
+static const struct regmap_config cs35l36_regmap = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -1312,7 +1298,7 @@ static struct regmap_config cs35l36_regmap = {
.precious_reg = cs35l36_precious_reg,
.volatile_reg = cs35l36_volatile_reg,
.readable_reg = cs35l36_readable_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static irqreturn_t cs35l36_irq(int irq, void *data)
@@ -1932,7 +1918,7 @@ static const struct of_device_id cs35l36_of_match[] = {
MODULE_DEVICE_TABLE(of, cs35l36_of_match);
static const struct i2c_device_id cs35l36_id[] = {
- {"cs35l36", 0},
+ {"cs35l36"},
{}
};
diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c
index 7ea890d7d387..34097996b784 100644
--- a/sound/soc/codecs/cs35l41-i2c.c
+++ b/sound/soc/codecs/cs35l41-i2c.c
@@ -13,17 +13,17 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "cs35l41.h"
static const struct i2c_device_id cs35l41_id_i2c[] = {
- { "cs35l40", 0 },
- { "cs35l41", 0 },
- { "cs35l51", 0 },
- { "cs35l53", 0 },
+ { "cs35l40" },
+ { "cs35l41" },
+ { "cs35l51" },
+ { "cs35l53" },
{}
};
@@ -35,7 +35,6 @@ static int cs35l41_i2c_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(dev);
const struct regmap_config *regmap_config = &cs35l41_regmap_i2c;
- int ret;
cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL);
@@ -47,11 +46,9 @@ static int cs35l41_i2c_probe(struct i2c_client *client)
i2c_set_clientdata(client, cs35l41);
cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config);
- if (IS_ERR(cs35l41->regmap)) {
- ret = PTR_ERR(cs35l41->regmap);
- dev_err(cs35l41->dev, "Failed to allocate register map: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(cs35l41->regmap))
+ return dev_err_probe(cs35l41->dev, PTR_ERR(cs35l41->regmap),
+ "Failed to allocate register map\n");
return cs35l41_probe(cs35l41, hw_cfg);
}
@@ -83,7 +80,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
static struct i2c_driver cs35l41_i2c_driver = {
.driver = {
.name = "cs35l41",
- .pm = &cs35l41_pm_ops,
+ .pm = pm_ptr(&cs35l41_pm_ops),
.of_match_table = of_match_ptr(cs35l41_of_match),
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
},
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index 8538e2871c5f..1702f26049d3 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -16,6 +16,8 @@
#include <sound/cs35l41.h>
+#define CS35L41_FIRMWARE_OLD_VERSION 0x001C00 /* v0.28.0 */
+
static const struct reg_default cs35l41_reg[] = {
{ CS35L41_PWR_CTRL1, 0x00000000 },
{ CS35L41_PWR_CTRL2, 0x00000000 },
@@ -46,7 +48,7 @@ static const struct reg_default cs35l41_reg[] = {
{ CS35L41_DSP1_RX5_SRC, 0x00000020 },
{ CS35L41_DSP1_RX6_SRC, 0x00000021 },
{ CS35L41_DSP1_RX7_SRC, 0x0000003A },
- { CS35L41_DSP1_RX8_SRC, 0x00000001 },
+ { CS35L41_DSP1_RX8_SRC, 0x0000003B },
{ CS35L41_NGATE1_SRC, 0x00000008 },
{ CS35L41_NGATE2_SRC, 0x00000009 },
{ CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 },
@@ -58,8 +60,8 @@ static const struct reg_default cs35l41_reg[] = {
{ CS35L41_IRQ1_MASK2, 0xFFFFFFFF },
{ CS35L41_IRQ1_MASK3, 0xFFFF87FF },
{ CS35L41_IRQ1_MASK4, 0xFEFFFFFF },
- { CS35L41_GPIO1_CTRL1, 0xE1000001 },
- { CS35L41_GPIO2_CTRL1, 0xE1000001 },
+ { CS35L41_GPIO1_CTRL1, 0x81000001 },
+ { CS35L41_GPIO2_CTRL1, 0x81000001 },
{ CS35L41_MIXER_NGATE_CFG, 0x00000000 },
{ CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 },
{ CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 },
@@ -74,6 +76,7 @@ static bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
case CS35L41_FABID:
case CS35L41_RELID:
case CS35L41_OTPID:
+ case CS35L41_SFT_RESET:
case CS35L41_TEST_KEY_CTL:
case CS35L41_USER_KEY_CTL:
case CS35L41_OTP_CTRL0:
@@ -743,7 +746,7 @@ struct regmap_config cs35l41_regmap_i2c = {
.volatile_reg = cs35l41_volatile_reg,
.readable_reg = cs35l41_readable_reg,
.precious_reg = cs35l41_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c);
@@ -760,7 +763,7 @@ struct regmap_config cs35l41_regmap_spi = {
.volatile_reg = cs35l41_volatile_reg,
.readable_reg = cs35l41_readable_reg,
.precious_reg = cs35l41_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(cs35l41_regmap_spi);
@@ -933,8 +936,8 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign
EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch);
int cs35l41_set_channels(struct device *dev, struct regmap *reg,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num, const unsigned int *tx_slot,
+ unsigned int rx_num, const unsigned int *rx_slot)
{
unsigned int val, mask;
int i;
@@ -1080,28 +1083,32 @@ static const struct reg_sequence cs35l41_safe_to_reset[] = {
{ 0x00000040, 0x00000033 },
};
-static const struct reg_sequence cs35l41_active_to_safe[] = {
+static const struct reg_sequence cs35l41_active_to_safe_start[] = {
{ 0x00000040, 0x00000055 },
{ 0x00000040, 0x000000AA },
{ 0x00007438, 0x00585941 },
{ CS35L41_PWR_CTRL1, 0x00000000 },
- { 0x0000742C, 0x00000009, 3000 },
+ { 0x0000742C, 0x00000009 },
+};
+
+static const struct reg_sequence cs35l41_active_to_safe_end[] = {
{ 0x00007438, 0x00580941 },
{ 0x00000040, 0x000000CC },
{ 0x00000040, 0x00000033 },
};
-static const struct reg_sequence cs35l41_safe_to_active[] = {
+static const struct reg_sequence cs35l41_safe_to_active_start[] = {
{ 0x00000040, 0x00000055 },
{ 0x00000040, 0x000000AA },
{ 0x0000742C, 0x0000000F },
{ 0x0000742C, 0x00000079 },
{ 0x00007438, 0x00585941 },
- { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1
+ { CS35L41_PWR_CTRL1, 0x00000001 }, // GLOBAL_EN = 1
+};
+
+static const struct reg_sequence cs35l41_safe_to_active_en_spk[] = {
{ 0x0000742C, 0x000000F9 },
{ 0x00007438, 0x00580941 },
- { 0x00000040, 0x000000CC },
- { 0x00000040, 0x00000033 },
};
static const struct reg_sequence cs35l41_reset_to_safe[] = {
@@ -1188,21 +1195,51 @@ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type)
}
EXPORT_SYMBOL_GPL(cs35l41_safe_reset);
-int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable,
- struct completion *pll_lock)
+/*
+ * Enabling the CS35L41_SHD_BOOST_ACTV and CS35L41_SHD_BOOST_PASS shared boosts
+ * does also require a call to cs35l41_mdsync_up(), but not before getting the
+ * PLL Lock signal.
+ *
+ * PLL Lock seems to be triggered soon after snd_pcm_start() is executed and
+ * SNDRV_PCM_TRIGGER_START command is processed, which happens (long) after the
+ * SND_SOC_DAPM_PRE_PMU event handler is invoked as part of snd_pcm_prepare().
+ *
+ * This event handler is where cs35l41_global_enable() is normally called from,
+ * but waiting for PLL Lock here will time out. Increasing the wait duration
+ * will not help, as the only consequence of it would be to add an unnecessary
+ * delay in the invocation of snd_pcm_start().
+ *
+ * Trying to move the wait in the SNDRV_PCM_TRIGGER_START callback is not a
+ * solution either, as the trigger is executed in an IRQ-off atomic context.
+ *
+ * The current approach is to invoke cs35l41_mdsync_up() right after receiving
+ * the PLL Lock interrupt, in the IRQ handler.
+ */
+int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type,
+ int enable, struct cs_dsp *dsp)
{
int ret;
- unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3;
+ unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status, pup_pdn_mask;
+ unsigned int pwr_ctl1_val;
struct reg_sequence cs35l41_mdsync_down_seq[] = {
{CS35L41_PWR_CTRL3, 0},
{CS35L41_GPIO_PAD_CONTROL, 0},
{CS35L41_PWR_CTRL1, 0, 3000},
};
- struct reg_sequence cs35l41_mdsync_up_seq[] = {
- {CS35L41_PWR_CTRL3, 0},
- {CS35L41_PWR_CTRL1, 0x00000000, 3000},
- {CS35L41_PWR_CTRL1, 0x00000001, 3000},
- };
+
+ pup_pdn_mask = enable ? CS35L41_PUP_DONE_MASK : CS35L41_PDN_DONE_MASK;
+
+ ret = regmap_read(regmap, CS35L41_PWR_CTRL1, &pwr_ctl1_val);
+ if (ret)
+ return ret;
+
+ if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) {
+ dev_dbg(dev, "Cannot set Global Enable - already set.\n");
+ return 0;
+ } else if (!(pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && !enable) {
+ dev_dbg(dev, "Cannot unset Global Enable - not set.\n");
+ return 0;
+ }
switch (b_type) {
case CS35L41_SHD_BOOST_ACTV:
@@ -1222,38 +1259,91 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type,
cs35l41_mdsync_down_seq[0].def = pwr_ctrl3;
cs35l41_mdsync_down_seq[1].def = pad_control;
cs35l41_mdsync_down_seq[2].def = pwr_ctrl1;
+
ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_down_seq,
ARRAY_SIZE(cs35l41_mdsync_down_seq));
- if (!enable)
- break;
+ /* Activation to be completed later via cs35l41_mdsync_up() */
+ if (ret || enable)
+ return ret;
- if (!pll_lock)
- return -EINVAL;
+ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1,
+ int_status, int_status & pup_pdn_mask,
+ 1000, 100000);
+ if (ret)
+ dev_err(dev, "Enable(%d) failed: %d\n", enable, ret);
- ret = wait_for_completion_timeout(pll_lock, msecs_to_jiffies(1000));
- if (ret == 0) {
- ret = -ETIMEDOUT;
- } else {
- regmap_read(regmap, CS35L41_PWR_CTRL3, &pwr_ctrl3);
- pwr_ctrl3 |= CS35L41_SYNC_EN_MASK;
- cs35l41_mdsync_up_seq[0].def = pwr_ctrl3;
- ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_up_seq,
- ARRAY_SIZE(cs35l41_mdsync_up_seq));
- }
+ /* Clear PUP/PDN status */
+ regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask);
break;
case CS35L41_INT_BOOST:
ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK,
enable << CS35L41_GLOBAL_EN_SHIFT);
- usleep_range(3000, 3100);
+ if (ret) {
+ dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1,
+ int_status, int_status & pup_pdn_mask,
+ 1000, 100000);
+ if (ret)
+ dev_err(dev, "Enable(%d) failed: %d\n", enable, ret);
+
+ /* Clear PUP/PDN status */
+ regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask);
break;
case CS35L41_EXT_BOOST:
case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
- if (enable)
- ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active,
- ARRAY_SIZE(cs35l41_safe_to_active));
- else
- ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe,
- ARRAY_SIZE(cs35l41_active_to_safe));
+ if (enable) {
+ /* Test Key is unlocked here */
+ ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_start,
+ ARRAY_SIZE(cs35l41_safe_to_active_start));
+ if (ret)
+ return ret;
+
+ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status,
+ int_status & CS35L41_PUP_DONE_MASK, 1000, 100000);
+ if (ret) {
+ dev_err(dev, "Failed waiting for CS35L41_PUP_DONE_MASK: %d\n", ret);
+ /* Lock the test key, it was unlocked during the multi_reg_write */
+ cs35l41_test_key_lock(dev, regmap);
+ return ret;
+ }
+ regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PUP_DONE_MASK);
+
+ if (dsp->running && dsp->fw_id_version > CS35L41_FIRMWARE_OLD_VERSION)
+ ret = cs35l41_set_cspl_mbox_cmd(dev, regmap,
+ CSPL_MBOX_CMD_SPK_OUT_ENABLE);
+ else
+ ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_en_spk,
+ ARRAY_SIZE(cs35l41_safe_to_active_en_spk));
+
+ /* Lock the test key, it was unlocked during the multi_reg_write */
+ cs35l41_test_key_lock(dev, regmap);
+ } else {
+ /* Test Key is unlocked here */
+ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_start,
+ ARRAY_SIZE(cs35l41_active_to_safe_start));
+ if (ret) {
+ /* Lock the test key, it was unlocked during the multi_reg_write */
+ cs35l41_test_key_lock(dev, regmap);
+ return ret;
+ }
+
+ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status,
+ int_status & CS35L41_PDN_DONE_MASK, 1000, 100000);
+ if (ret) {
+ dev_err(dev, "Failed waiting for CS35L41_PDN_DONE_MASK: %d\n", ret);
+ /* Lock the test key, it was unlocked during the multi_reg_write */
+ cs35l41_test_key_lock(dev, regmap);
+ return ret;
+ }
+ regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PDN_DONE_MASK);
+
+ /* Test Key is locked here */
+ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end,
+ ARRAY_SIZE(cs35l41_active_to_safe_end));
+ }
break;
default:
ret = -EINVAL;
@@ -1264,6 +1354,17 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type,
}
EXPORT_SYMBOL_GPL(cs35l41_global_enable);
+/*
+ * To be called after receiving the IRQ Lock interrupt, in order to complete
+ * any shared boost activation initiated by cs35l41_global_enable().
+ */
+int cs35l41_mdsync_up(struct regmap *regmap)
+{
+ return regmap_update_bits(regmap, CS35L41_PWR_CTRL3,
+ CS35L41_SYNC_EN_MASK, CS35L41_SYNC_EN_MASK);
+}
+EXPORT_SYMBOL_GPL(cs35l41_mdsync_up);
+
int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg)
{
struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1;
@@ -1344,6 +1445,8 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
return (sts == CSPL_MBOX_STS_RUNNING);
case CSPL_MBOX_CMD_STOP_PRE_REINIT:
return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
+ case CSPL_MBOX_CMD_SPK_OUT_ENABLE:
+ return (sts == CSPL_MBOX_STS_RUNNING);
default:
return false;
}
@@ -1373,6 +1476,11 @@ int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
continue;
}
+ if (sts == CSPL_MBOX_STS_ERROR || sts == CSPL_MBOX_STS_ERROR2) {
+ dev_err(dev, "CSPL Error Detected\n");
+ return -EINVAL;
+ }
+
if (!cs35l41_check_cspl_mbox_sts(cmd, sts))
dev_dbg(dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts);
else
diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c
index 5c8bb24909eb..f9b6bf7bea9c 100644
--- a/sound/soc/codecs/cs35l41-spi.c
+++ b/sound/soc/codecs/cs35l41-spi.c
@@ -39,15 +39,15 @@ static int cs35l41_spi_probe(struct spi_device *spi)
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);
- if (IS_ERR(cs35l41->regmap)) {
- ret = PTR_ERR(cs35l41->regmap);
- dev_err(&spi->dev, "Failed to allocate register map: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(cs35l41->regmap))
+ return dev_err_probe(cs35l41->dev, PTR_ERR(cs35l41->regmap),
+ "Failed to allocate register map\n");
cs35l41->dev = &spi->dev;
cs35l41->irq = spi->irq;
@@ -83,7 +83,7 @@ MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
static struct spi_driver cs35l41_spi_driver = {
.driver = {
.name = "cs35l41",
- .pm = &cs35l41_pm_ops,
+ .pm = pm_ptr(&cs35l41_pm_ops),
.of_match_table = of_match_ptr(cs35l41_of_match),
.acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
},
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 6ac501f008ec..3a8a8dd065b7 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -7,13 +7,13 @@
// Author: David Rhodes <david.rhodes@cirrus.com>
#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <sound/initval.h>
@@ -168,7 +168,7 @@ static int cs35l41_get_fs_mon_config_index(int freq)
static const DECLARE_TLV_DB_RANGE(dig_vol_tlv,
0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
1, 913, TLV_DB_MINMAX_ITEM(-10200, 1200));
-static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1);
+static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 50, 100, 0);
static const struct snd_kcontrol_new dre_ctrl =
SOC_DAPM_SINGLE("Switch", CS35L41_PWR_CTRL3, 20, 1, 0);
@@ -386,10 +386,18 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
struct cs35l41_private *cs35l41 = data;
unsigned int status[4] = { 0, 0, 0, 0 };
unsigned int masks[4] = { 0, 0, 0, 0 };
- int ret = IRQ_NONE;
unsigned int i;
+ int ret;
- pm_runtime_get_sync(cs35l41->dev);
+ ret = pm_runtime_resume_and_get(cs35l41->dev);
+ if (ret < 0) {
+ dev_err(cs35l41->dev,
+ "pm_runtime_resume_and_get failed in %s: %d\n",
+ __func__, ret);
+ return IRQ_NONE;
+ }
+
+ ret = IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(status); i++) {
regmap_read(cs35l41->regmap,
@@ -459,12 +467,23 @@ static irqreturn_t cs35l41_irq(int irq, void *data)
if (status[2] & CS35L41_PLL_LOCK) {
regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS3, CS35L41_PLL_LOCK);
- complete(&cs35l41->pll_lock);
+
+ if (cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_ACTV ||
+ cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_PASS) {
+ ret = cs35l41_mdsync_up(cs35l41->regmap);
+ if (ret)
+ dev_err(cs35l41->dev, "MDSYNC-up failed: %d\n", ret);
+ else
+ dev_dbg(cs35l41->dev, "MDSYNC-up done\n");
+
+ dev_dbg(cs35l41->dev, "PUP-done status: %d\n",
+ !!(status[0] & CS35L41_PUP_DONE_MASK));
+ }
+
ret = IRQ_HANDLED;
}
done:
- pm_runtime_mark_last_busy(cs35l41->dev);
pm_runtime_put_autosuspend(cs35l41->dev);
return ret;
@@ -491,7 +510,6 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
- unsigned int val;
int ret = 0;
switch (event) {
@@ -500,21 +518,12 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
cs35l41_pup_patch,
ARRAY_SIZE(cs35l41_pup_patch));
- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1,
- &cs35l41->pll_lock);
+ ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type,
+ 1, &cs35l41->dsp.cs_dsp);
break;
case SND_SOC_DAPM_POST_PMD:
- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0,
- &cs35l41->pll_lock);
-
- ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1,
- val, val & CS35L41_PDN_DONE_MASK,
- 1000, 100000);
- if (ret)
- dev_warn(cs35l41->dev, "PDN failed: %d\n", ret);
-
- regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1,
- CS35L41_PDN_DONE_MASK);
+ ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type,
+ 0, &cs35l41->dsp.cs_dsp);
regmap_multi_reg_write_bypassed(cs35l41->regmap,
cs35l41_pdn_patch,
@@ -664,7 +673,8 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
};
static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n,
- unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot)
+ const unsigned int *tx_slot,
+ unsigned int rx_n, const unsigned int *rx_slot)
{
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component);
@@ -763,10 +773,9 @@ static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream,
asp_wl = params_width(params);
- if (i < ARRAY_SIZE(cs35l41_fs_rates))
- regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL,
- CS35L41_GLOBAL_FS_MASK,
- cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT);
+ regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL,
+ CS35L41_GLOBAL_FS_MASK,
+ cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT,
@@ -799,30 +808,6 @@ static int cs35l41_get_clk_config(int freq)
return -EINVAL;
}
-static const unsigned int cs35l41_src_rates[] = {
- 8000, 12000, 11025, 16000, 22050, 24000, 32000,
- 44100, 48000, 88200, 96000, 176400, 192000
-};
-
-static const struct snd_pcm_hw_constraint_list cs35l41_constraints = {
- .count = ARRAY_SIZE(cs35l41_src_rates),
- .list = cs35l41_src_rates,
-};
-
-static int cs35l41_pcm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component);
-
- reinit_completion(&cs35l41->pll_lock);
-
- if (substream->runtime)
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &cs35l41_constraints);
- return 0;
-}
-
static int cs35l41_component_set_sysclk(struct snd_soc_component *component,
int clk_id, int source,
unsigned int freq, int dir)
@@ -943,7 +928,7 @@ static const struct snd_soc_dapm_widget cs35l41_ext_bst_widget[] = {
static int cs35l41_component_probe(struct snd_soc_component *component)
{
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) {
@@ -969,13 +954,21 @@ static void cs35l41_component_remove(struct snd_soc_component *component)
}
static const struct snd_soc_dai_ops cs35l41_ops = {
- .startup = cs35l41_pcm_startup,
.set_fmt = cs35l41_set_dai_fmt,
.hw_params = cs35l41_pcm_hw_params,
.set_sysclk = cs35l41_dai_set_sysclk,
.set_channel_map = cs35l41_set_channel_map,
};
+#define CS35L41_RATES ( \
+ SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_12000 | \
+ SNDRV_PCM_RATE_24000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000)
+
static struct snd_soc_dai_driver cs35l41_dai[] = {
{
.name = "cs35l41-pcm",
@@ -984,14 +977,14 @@ static struct snd_soc_dai_driver cs35l41_dai[] = {
.stream_name = "AMP Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_KNOT,
+ .rates = CS35L41_RATES,
.formats = CS35L41_RX_FORMATS,
},
.capture = {
.stream_name = "AMP Capture",
.channels_min = 1,
.channels_max = 4,
- .rates = SNDRV_PCM_RATE_KNOT,
+ .rates = CS35L41_RATES,
.formats = CS35L41_TX_FORMATS,
},
.ops = &cs35l41_ops,
@@ -1089,6 +1082,7 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf
static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
{
struct wm_adsp *dsp;
+ uint32_t dsp1rx5_src;
int ret;
dsp = &cs35l41->dsp;
@@ -1108,16 +1102,29 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
return ret;
}
- ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC,
- CS35L41_INPUT_SRC_VPMON);
+ switch (cs35l41->hw_cfg.bst_type) {
+ case CS35L41_INT_BOOST:
+ case CS35L41_SHD_BOOST_ACTV:
+ dsp1rx5_src = CS35L41_INPUT_SRC_VPMON;
+ break;
+ case CS35L41_EXT_BOOST:
+ case CS35L41_SHD_BOOST_PASS:
+ dsp1rx5_src = CS35L41_INPUT_SRC_VBSTMON;
+ break;
+ default:
+ dev_err(cs35l41->dev, "wm_halo_init failed - Invalid Boost Type: %d\n",
+ cs35l41->hw_cfg.bst_type);
+ goto err_dsp;
+ }
+
+ ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, dsp1rx5_src);
if (ret < 0) {
- dev_err(cs35l41->dev, "Write INPUT_SRC_VPMON failed: %d\n", ret);
+ dev_err(cs35l41->dev, "Write DSP1RX5_SRC: %d failed: %d\n", dsp1rx5_src, ret);
goto err_dsp;
}
- ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC,
- CS35L41_INPUT_SRC_CLASSH);
+ ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, CS35L41_INPUT_SRC_VBSTMON);
if (ret < 0) {
- dev_err(cs35l41->dev, "Write INPUT_SRC_CLASSH failed: %d\n", ret);
+ dev_err(cs35l41->dev, "Write CS35L41_INPUT_SRC_VBSTMON failed: %d\n", ret);
goto err_dsp;
}
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC,
@@ -1141,28 +1148,54 @@ err_dsp:
return ret;
}
-static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41)
+static int cs35l41_get_system_name(struct cs35l41_private *cs35l41)
{
- acpi_handle handle = ACPI_HANDLE(cs35l41->dev);
- const char *sub;
-
- /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
- if (!handle)
- return 0;
+ struct acpi_device *adev = ACPI_COMPANION(cs35l41->dev);
+ const char *sub = NULL;
+ const char *tmp;
+ int ret = 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
- return PTR_ERR(sub);
+ /* If there is no acpi_device, there is no ACPI for this system, skip checking ACPI */
+ if (adev) {
+ acpi_handle handle = acpi_device_handle(adev);
+
+ sub = acpi_get_subsystem_id(handle);
+ ret = PTR_ERR_OR_ZERO(sub);
+ if (ret) {
+ sub = NULL;
+ /* If no _SUB, fallback to _HID, otherwise fail */
+ if (ret == -ENODATA) {
+ tmp = acpi_device_hid(adev);
+ /* If dummy hid, return 0 and fallback to legacy firmware path */
+ if (!strcmp(tmp, "device")) {
+ ret = 0;
+ goto err;
+ }
+ sub = kstrdup(tmp, GFP_KERNEL);
+ if (!sub) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+ }
+ } else {
+ if (!device_property_read_string(cs35l41->dev, "cirrus,subsystem-id", &tmp)) {
+ sub = kstrdup(tmp, GFP_KERNEL);
+ if (!sub) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
}
- cs35l41->dsp.system_name = sub;
- dev_dbg(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name);
+err:
+ if (sub) {
+ cs35l41->dsp.system_name = sub;
+ dev_info(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name);
+ } else
+ dev_warn(cs35l41->dev, "Subsystem ID not found\n");
- return 0;
+ return ret;
}
int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg)
@@ -1184,16 +1217,14 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
ret = devm_regulator_bulk_get(cs35l41->dev, CS35L41_NUM_SUPPLIES,
cs35l41->supplies);
- if (ret != 0) {
- dev_err(cs35l41->dev, "Failed to request core supplies: %d\n", ret);
- return ret;
- }
+ if (ret != 0)
+ return dev_err_probe(cs35l41->dev, ret,
+ "Failed to request core supplies\n");
ret = regulator_bulk_enable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
- if (ret != 0) {
- dev_err(cs35l41->dev, "Failed to enable core supplies: %d\n", ret);
- return ret;
- }
+ if (ret != 0)
+ return dev_err_probe(cs35l41->dev, ret,
+ "Failed to enable core supplies\n");
/* returning NULL can be an option if in stereo mode */
cs35l41->reset_gpio = devm_gpiod_get_optional(cs35l41->dev, "reset",
@@ -1205,8 +1236,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
dev_info(cs35l41->dev,
"Reset line busy, assuming shared reset\n");
} else {
- dev_err(cs35l41->dev,
- "Failed to get reset GPIO: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret,
+ "Failed to get reset GPIO\n");
goto err;
}
}
@@ -1222,8 +1253,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
int_status, int_status & CS35L41_OTP_BOOT_DONE,
1000, 100000);
if (ret) {
- dev_err(cs35l41->dev,
- "Failed waiting for OTP_BOOT_DONE: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret,
+ "Failed waiting for OTP_BOOT_DONE\n");
goto err;
}
@@ -1236,13 +1267,13 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, &regid);
if (ret < 0) {
- dev_err(cs35l41->dev, "Get Device ID failed: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "Get Device ID failed\n");
goto err;
}
ret = regmap_read(cs35l41->regmap, CS35L41_REVID, &reg_revid);
if (ret < 0) {
- dev_err(cs35l41->dev, "Get Revision ID failed: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "Get Revision ID failed\n");
goto err;
}
@@ -1267,7 +1298,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
if (ret < 0) {
- dev_err(cs35l41->dev, "OTP Unpack failed: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "OTP Unpack failed\n");
goto err;
}
@@ -1287,17 +1318,17 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
IRQF_ONESHOT | IRQF_SHARED | irq_pol,
"cs35l41", cs35l41);
if (ret != 0) {
- dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "Failed to request IRQ\n");
goto err;
}
ret = cs35l41_set_pdata(cs35l41);
if (ret < 0) {
- dev_err(cs35l41->dev, "Set pdata failed: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "Set pdata failed\n");
goto err;
}
- ret = cs35l41_acpi_get_name(cs35l41);
+ ret = cs35l41_get_system_name(cs35l41);
if (ret < 0)
goto err;
@@ -1305,11 +1336,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
if (ret < 0)
goto err;
- init_completion(&cs35l41->pll_lock);
-
pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
pm_runtime_use_autosuspend(cs35l41->dev);
- pm_runtime_mark_last_busy(cs35l41->dev);
pm_runtime_set_active(cs35l41->dev);
pm_runtime_get_noresume(cs35l41->dev);
pm_runtime_enable(cs35l41->dev);
@@ -1318,7 +1346,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
&soc_component_dev_cs35l41,
cs35l41_dai, ARRAY_SIZE(cs35l41_dai));
if (ret < 0) {
- dev_err(cs35l41->dev, "Register codec failed: %d\n", ret);
+ dev_err_probe(cs35l41->dev, ret, "Register codec failed\n");
goto err_pm;
}
@@ -1330,6 +1358,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
return 0;
err_pm:
+ pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev);
pm_runtime_put_noidle(cs35l41->dev);
@@ -1346,6 +1375,7 @@ EXPORT_SYMBOL_GPL(cs35l41_probe);
void cs35l41_remove(struct cs35l41_private *cs35l41)
{
pm_runtime_get_sync(cs35l41->dev);
+ pm_runtime_dont_use_autosuspend(cs35l41->dev);
pm_runtime_disable(cs35l41->dev);
regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
@@ -1364,7 +1394,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41)
}
EXPORT_SYMBOL_GPL(cs35l41_remove);
-static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
+static int cs35l41_runtime_suspend(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1381,7 +1411,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
+static int cs35l41_runtime_resume(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
int ret;
@@ -1410,7 +1440,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused cs35l41_sys_suspend(struct device *dev)
+static int cs35l41_sys_suspend(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1420,7 +1450,7 @@ static int __maybe_unused cs35l41_sys_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev)
+static int cs35l41_sys_suspend_noirq(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1430,7 +1460,7 @@ static int __maybe_unused cs35l41_sys_suspend_noirq(struct device *dev)
return 0;
}
-static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev)
+static int cs35l41_sys_resume_noirq(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1440,7 +1470,7 @@ static int __maybe_unused cs35l41_sys_resume_noirq(struct device *dev)
return 0;
}
-static int __maybe_unused cs35l41_sys_resume(struct device *dev)
+static int cs35l41_sys_resume(struct device *dev)
{
struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1450,13 +1480,12 @@ static int __maybe_unused cs35l41_sys_resume(struct device *dev)
return 0;
}
-const struct dev_pm_ops cs35l41_pm_ops = {
- SET_RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
+EXPORT_GPL_DEV_PM_OPS(cs35l41_pm_ops) = {
+ RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend, cs35l41_sys_resume)
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend_noirq, cs35l41_sys_resume_noirq)
+ SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend, cs35l41_sys_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l41_sys_suspend_noirq, cs35l41_sys_resume_noirq)
};
-EXPORT_SYMBOL_GPL(cs35l41_pm_ops);
MODULE_DESCRIPTION("ASoC CS35L41 driver");
MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h
index 34d967d4372b..c85cbc1dd333 100644
--- a/sound/soc/codecs/cs35l41.h
+++ b/sound/soc/codecs/cs35l41.h
@@ -33,7 +33,6 @@ struct cs35l41_private {
int irq;
/* GPIO for /RST */
struct gpio_desc *reset_gpio;
- struct completion pll_lock;
};
int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg);
diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c
index 77e0f8750f37..a09aa3b92ae1 100644
--- a/sound/soc/codecs/cs35l45-i2c.c
+++ b/sound/soc/codecs/cs35l45-i2c.c
@@ -53,7 +53,7 @@ static const struct of_device_id cs35l45_of_match[] = {
MODULE_DEVICE_TABLE(of, cs35l45_of_match);
static const struct i2c_device_id cs35l45_id_i2c[] = {
- { "cs35l45", 0 },
+ { "cs35l45" },
{}
};
MODULE_DEVICE_TABLE(i2c, cs35l45_id_i2c);
@@ -62,7 +62,7 @@ static struct i2c_driver cs35l45_i2c_driver = {
.driver = {
.name = "cs35l45",
.of_match_table = cs35l45_of_match,
- .pm = &cs35l45_pm_ops,
+ .pm = pm_ptr(&cs35l45_pm_ops),
},
.id_table = cs35l45_id_i2c,
.probe = cs35l45_i2c_probe,
@@ -73,4 +73,4 @@ module_i2c_driver(cs35l45_i2c_driver);
MODULE_DESCRIPTION("I2C CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS35L45);
+MODULE_IMPORT_NS("SND_SOC_CS35L45");
diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c
index 5efb77530cc3..5f91472c3fd2 100644
--- a/sound/soc/codecs/cs35l45-spi.c
+++ b/sound/soc/codecs/cs35l45-spi.c
@@ -64,7 +64,7 @@ static struct spi_driver cs35l45_spi_driver = {
.driver = {
.name = "cs35l45",
.of_match_table = cs35l45_of_match,
- .pm = &cs35l45_pm_ops,
+ .pm = pm_ptr(&cs35l45_pm_ops),
},
.id_table = cs35l45_id_spi,
.probe = cs35l45_spi_probe,
@@ -75,4 +75,4 @@ module_spi_driver(cs35l45_spi_driver);
MODULE_DESCRIPTION("SPI CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS35L45);
+MODULE_IMPORT_NS("SND_SOC_CS35L45");
diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c
index 066f83c0c7ac..d2ecc7b3f619 100644
--- a/sound/soc/codecs/cs35l45-tables.c
+++ b/sound/soc/codecs/cs35l45-tables.c
@@ -38,7 +38,7 @@ int cs35l45_apply_patch(struct cs35l45_private *cs35l45)
return regmap_register_patch(cs35l45->regmap, cs35l45_patch,
ARRAY_SIZE(cs35l45_patch));
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, "SND_SOC_CS35L45");
static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_BLOCK_ENABLES, 0x00003323 },
@@ -91,6 +91,7 @@ static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_DSP1RX7_INPUT, 0x0000003A },
{ CS35L45_DSP1RX8_INPUT, 0x00000028 },
{ CS35L45_AMP_PCM_CONTROL, 0x00100000 },
+ { CS35L45_AMP_GAIN, 0x00002300 },
{ CS35L45_IRQ1_CFG, 0x00000000 },
{ CS35L45_IRQ1_MASK_1, 0xBFEFFFBF },
{ CS35L45_IRQ1_MASK_2, 0xFFFFFFFF },
@@ -156,7 +157,9 @@ static bool cs35l45_readable_reg(struct device *dev, unsigned int reg)
case CS35L45_DSP1RX6_INPUT:
case CS35L45_DSP1RX7_INPUT:
case CS35L45_DSP1RX8_INPUT:
+ case CS35L45_HVLV_CONFIG:
case CS35L45_AMP_PCM_CONTROL:
+ case CS35L45_AMP_GAIN:
case CS35L45_AMP_PCM_HPF_TST:
case CS35L45_IRQ1_CFG:
case CS35L45_IRQ1_STATUS:
@@ -255,9 +258,9 @@ const struct regmap_config cs35l45_i2c_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs35l45_defaults),
.volatile_reg = cs35l45_volatile_reg,
.readable_reg = cs35l45_readable_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, "SND_SOC_CS35L45");
const struct regmap_config cs35l45_spi_regmap = {
.reg_bits = 32,
@@ -271,9 +274,9 @@ const struct regmap_config cs35l45_spi_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs35l45_defaults),
.volatile_reg = cs35l45_volatile_reg,
.readable_reg = cs35l45_readable_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, "SND_SOC_CS35L45");
static const struct {
u8 cfg_id;
@@ -312,7 +315,7 @@ static const struct {
{ 0x3B, 24576000 },
};
-unsigned int cs35l45_get_clk_freq_id(unsigned int freq)
+int cs35l45_get_clk_freq_id(unsigned int freq)
{
int i;
@@ -326,4 +329,4 @@ unsigned int cs35l45_get_clk_freq_id(unsigned int freq)
return -EINVAL;
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, "SND_SOC_CS35L45");
diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c
index d1edb9876c10..e33f11435980 100644
--- a/sound/soc/codecs/cs35l45.c
+++ b/sound/soc/codecs/cs35l45.c
@@ -169,6 +169,133 @@ static int cs35l45_dsp_audio_ev(struct snd_soc_dapm_widget *w,
return 0;
}
+static int cs35l45_activate_ctl(struct snd_soc_component *component,
+ const char *ctl_name, bool active)
+{
+ struct snd_card *card = component->card->snd_card;
+ struct snd_kcontrol *kcontrol;
+ struct snd_kcontrol_volatile *vd;
+ unsigned int index_offset;
+
+ kcontrol = snd_soc_component_get_kcontrol(component, ctl_name);
+ if (!kcontrol) {
+ dev_err(component->dev, "Can't find kcontrol %s\n", ctl_name);
+ return -EINVAL;
+ }
+
+ index_offset = snd_ctl_get_ioff(kcontrol, &kcontrol->id);
+ vd = &kcontrol->vd[index_offset];
+ if (active)
+ vd->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ else
+ vd->access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
+
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &kcontrol->id);
+
+ return 0;
+}
+
+static int cs35l45_amplifier_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l45_private *cs35l45 =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = cs35l45->amplifier_mode;
+
+ return 0;
+}
+
+static int cs35l45_amplifier_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l45_private *cs35l45 =
+ snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_to_dapm(component);
+ unsigned int amp_state;
+ int ret;
+
+ if ((ucontrol->value.integer.value[0] == cs35l45->amplifier_mode) ||
+ (ucontrol->value.integer.value[0] > AMP_MODE_RCV))
+ return 0;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ ret = regmap_read(cs35l45->regmap, CS35L45_BLOCK_ENABLES, &amp_state);
+ if (ret < 0) {
+ dev_err(cs35l45->dev, "Failed to read AMP state: %d\n", ret);
+ snd_soc_dapm_mutex_unlock(dapm);
+ return ret;
+ }
+
+ regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,
+ CS35L45_AMP_EN_MASK);
+ snd_soc_dapm_disable_pin_unlocked(dapm, "SPK");
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ if (ucontrol->value.integer.value[0] == AMP_MODE_SPK) {
+ regmap_clear_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,
+ CS35L45_RCV_EN_MASK);
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,
+ CS35L45_BST_EN_MASK,
+ CS35L45_BST_ENABLE << CS35L45_BST_EN_SHIFT);
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_HVLV_CONFIG,
+ CS35L45_HVLV_MODE_MASK,
+ CS35L45_HVLV_OPERATION <<
+ CS35L45_HVLV_MODE_SHIFT);
+
+ ret = cs35l45_activate_ctl(component, "Analog PCM Volume", true);
+ if (ret < 0)
+ dev_err(cs35l45->dev,
+ "Unable to deactivate ctl (%d)\n", ret);
+
+ } else /* AMP_MODE_RCV */ {
+ regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,
+ CS35L45_RCV_EN_MASK);
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,
+ CS35L45_BST_EN_MASK,
+ CS35L45_BST_DISABLE_FET_OFF <<
+ CS35L45_BST_EN_SHIFT);
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_HVLV_CONFIG,
+ CS35L45_HVLV_MODE_MASK,
+ CS35L45_FORCE_LV_OPERATION <<
+ CS35L45_HVLV_MODE_SHIFT);
+
+ regmap_clear_bits(cs35l45->regmap,
+ CS35L45_BLOCK_ENABLES2,
+ CS35L45_AMP_DRE_EN_MASK);
+
+ regmap_update_bits(cs35l45->regmap, CS35L45_AMP_GAIN,
+ CS35L45_AMP_GAIN_PCM_MASK,
+ CS35L45_AMP_GAIN_PCM_13DBV <<
+ CS35L45_AMP_GAIN_PCM_SHIFT);
+
+ ret = cs35l45_activate_ctl(component, "Analog PCM Volume", false);
+ if (ret < 0)
+ dev_err(cs35l45->dev,
+ "Unable to deactivate ctl (%d)\n", ret);
+ }
+
+ if (amp_state & CS35L45_AMP_EN_MASK)
+ regmap_set_bits(cs35l45->regmap, CS35L45_BLOCK_ENABLES,
+ CS35L45_AMP_EN_MASK);
+
+ snd_soc_dapm_enable_pin_unlocked(dapm, "SPK");
+ snd_soc_dapm_sync_unlocked(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs35l45->amplifier_mode = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
static const char * const cs35l45_asp_tx_txt[] = {
"Zero", "ASP_RX1", "ASP_RX2",
"VMON", "IMON", "ERR_VOL",
@@ -279,8 +406,10 @@ static const struct snd_kcontrol_new cs35l45_dsp_muxes[] = {
};
static const struct snd_kcontrol_new cs35l45_dac_muxes[] = {
- SOC_DAPM_ENUM("DACPCM1 Source", cs35l45_dacpcm_enums[0]),
+ SOC_DAPM_ENUM("DACPCM Source", cs35l45_dacpcm_enums[0]),
};
+static const struct snd_kcontrol_new amp_en_ctl =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {
SND_SOC_DAPM_SPK("DSP1 Preload", NULL),
@@ -297,17 +426,25 @@ static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {
SND_SOC_DAPM_SIGGEN("VMON_SRC"),
SND_SOC_DAPM_SIGGEN("IMON_SRC"),
+ SND_SOC_DAPM_SIGGEN("TEMPMON_SRC"),
SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"),
SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"),
SND_SOC_DAPM_SIGGEN("ERR_VOL"),
SND_SOC_DAPM_SIGGEN("AMP_INTP"),
SND_SOC_DAPM_SIGGEN("IL_TARGET"),
- SND_SOC_DAPM_ADC("VMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0),
- SND_SOC_DAPM_ADC("IMON", NULL, CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0),
- SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, CS35L45_BLOCK_ENABLES,
- CS35L45_VDD_BATTMON_EN_SHIFT, 0),
- SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, CS35L45_BLOCK_ENABLES,
- CS35L45_VDD_BSTMON_EN_SHIFT, 0),
+
+ SND_SOC_DAPM_SUPPLY("VMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_VMON_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("IMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_IMON_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("TEMPMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_TEMPMON_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VDD_BATTMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_VDD_BATTMON_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VDD_BSTMON_EN", CS35L45_BLOCK_ENABLES, CS35L45_VDD_BSTMON_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_ADC("VMON", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("IMON", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("TEMPMON", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("VDD_BATTMON", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("VDD_BSTMON", NULL, SND_SOC_NOPM, 0, 0),
+
SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL, 0, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX1_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL, 1, CS35L45_ASP_ENABLES1, CS35L45_ASP_RX2_EN_SHIFT, 0),
@@ -333,7 +470,9 @@ static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {
SND_SOC_DAPM_MUX("DSP_RX7 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[6]),
SND_SOC_DAPM_MUX("DSP_RX8 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[7]),
- SND_SOC_DAPM_MUX("DACPCM1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]),
+ SND_SOC_DAPM_MUX("DACPCM Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]),
+
+ SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 0, &amp_en_ctl),
SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -367,9 +506,16 @@ static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
/* Feedback */
{ "VMON", NULL, "VMON_SRC" },
{ "IMON", NULL, "IMON_SRC" },
+ { "TEMPMON", NULL, "TEMPMON_SRC" },
{ "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" },
{ "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" },
+ { "VMON", NULL, "VMON_EN" },
+ { "IMON", NULL, "IMON_EN" },
+ { "TEMPMON", NULL, "TEMPMON_EN" },
+ { "VDD_BATTMON", NULL, "VDD_BATTMON_EN" },
+ { "VDD_BSTMON", NULL, "VDD_BSTMON_EN" },
+
{ "Capture", NULL, "ASP_TX1"},
{ "Capture", NULL, "ASP_TX2"},
{ "Capture", NULL, "ASP_TX3"},
@@ -403,7 +549,7 @@ static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
{ "ASP_RX1", NULL, "ASP_EN" },
{ "ASP_RX2", NULL, "ASP_EN" },
- { "AMP", NULL, "DACPCM1 Source"},
+ { "AMP", NULL, "DACPCM Source"},
{ "AMP", NULL, "GLOBAL_EN"},
CS35L45_DSP_MUX_ROUTE("DSP_RX1"),
@@ -424,17 +570,34 @@ static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
{"DSP1", NULL, "DSP_RX7 Source"},
{"DSP1", NULL, "DSP_RX8 Source"},
+ {"DSP1", NULL, "VMON_EN"},
+ {"DSP1", NULL, "IMON_EN"},
+ {"DSP1", NULL, "VDD_BATTMON_EN"},
+ {"DSP1", NULL, "VDD_BSTMON_EN"},
+ {"DSP1", NULL, "TEMPMON_EN"},
+
{"DSP1 Preload", NULL, "DSP1 Preloader"},
{"DSP1", NULL, "DSP1 Preloader"},
- CS35L45_DAC_MUX_ROUTE("DACPCM1"),
+ CS35L45_DAC_MUX_ROUTE("DACPCM"),
- { "SPK", NULL, "AMP"},
+ { "AMP Enable", "Switch", "AMP" },
+ { "SPK", NULL, "AMP Enable"},
};
+static const char * const amplifier_mode_texts[] = {"SPK", "RCV"};
+static SOC_ENUM_SINGLE_DECL(amplifier_mode_enum, SND_SOC_NOPM, 0,
+ amplifier_mode_texts);
+static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 1000, 300, 0);
static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true);
static const struct snd_kcontrol_new cs35l45_controls[] = {
+ SOC_ENUM_EXT("Amplifier Mode", amplifier_mode_enum,
+ cs35l45_amplifier_mode_get, cs35l45_amplifier_mode_put),
+ SOC_SINGLE_TLV("Analog PCM Volume", CS35L45_AMP_GAIN,
+ CS35L45_AMP_GAIN_PCM_SHIFT,
+ CS35L45_AMP_GAIN_PCM_MASK >> CS35L45_AMP_GAIN_PCM_SHIFT,
+ 0, amp_gain_tlv),
/* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */
SOC_SINGLE_S_TLV("Digital PCM Volume",
CS35L45_AMP_PCM_CONTROL,
@@ -775,6 +938,8 @@ static int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45)
cs35l45_setup_hibernate(cs35l45);
+ regmap_set_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, CS35L45_DSP_VIRT2_MBOX_MASK);
+
// Don't wait for ACK since bus activity would wake the device
regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);
@@ -795,6 +960,8 @@ static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)
CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
if (!ret) {
dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j);
+ regmap_clear_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2,
+ CS35L45_DSP_VIRT2_MBOX_MASK);
return 0;
}
usleep_range(100, 200);
@@ -810,7 +977,7 @@ static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)
return -ETIMEDOUT;
}
-static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
+static int cs35l45_runtime_suspend(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
@@ -827,7 +994,7 @@ static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
+static int cs35l45_runtime_resume(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
int ret;
@@ -854,6 +1021,46 @@ static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
return ret;
}
+static int cs35l45_sys_suspend(struct device *dev)
+{
+ struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
+
+ dev_dbg(cs35l45->dev, "System suspend, disabling IRQ\n");
+ disable_irq(cs35l45->irq);
+
+ return 0;
+}
+
+static int cs35l45_sys_suspend_noirq(struct device *dev)
+{
+ struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
+
+ dev_dbg(cs35l45->dev, "Late system suspend, reenabling IRQ\n");
+ enable_irq(cs35l45->irq);
+
+ return 0;
+}
+
+static int cs35l45_sys_resume_noirq(struct device *dev)
+{
+ struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
+
+ dev_dbg(cs35l45->dev, "Early system resume, disabling IRQ\n");
+ disable_irq(cs35l45->irq);
+
+ return 0;
+}
+
+static int cs35l45_sys_resume(struct device *dev)
+{
+ struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
+
+ dev_dbg(cs35l45->dev, "System resume, reenabling IRQ\n");
+ enable_irq(cs35l45->irq);
+
+ return 0;
+}
+
static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
{
struct device_node *node = cs35l45->dev->of_node;
@@ -969,7 +1176,7 @@ static irqreturn_t cs35l45_dsp_virt2_mbox_cb(int irq, void *data)
ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_3, &mbox_val);
if (!ret && mbox_val)
- ret = cs35l45_dsp_virt2_mbox3_irq_handle(cs35l45, mbox_val & CS35L45_MBOX3_CMD_MASK,
+ cs35l45_dsp_virt2_mbox3_irq_handle(cs35l45, mbox_val & CS35L45_MBOX3_CMD_MASK,
(mbox_val & CS35L45_MBOX3_DATA_MASK) >> CS35L45_MBOX3_DATA_SHIFT);
/* Handle DSP trace log IRQ */
@@ -1023,7 +1230,10 @@ static irqreturn_t cs35l45_spk_safe_err(int irq, void *data)
i = irq - regmap_irq_get_virq(cs35l45->irq_data, 0);
- dev_err(cs35l45->dev, "%s condition detected!\n", cs35l45_irqs[i].name);
+ if (i < 0 || i >= ARRAY_SIZE(cs35l45_irqs))
+ dev_err(cs35l45->dev, "Unspecified global error condition (%d) detected!\n", irq);
+ else
+ dev_err(cs35l45->dev, "%s condition detected!\n", cs35l45_irqs[i].name);
return IRQ_HANDLED;
}
@@ -1078,6 +1288,7 @@ static int cs35l45_initialize(struct cs35l45_private *cs35l45)
switch (dev_id[0]) {
case 0x35A450:
+ case 0x35A460:
break;
default:
dev_err(cs35l45->dev, "Bad DEVID 0x%x\n", dev_id[0]);
@@ -1100,6 +1311,8 @@ static int cs35l45_initialize(struct cs35l45_private *cs35l45)
if (ret < 0)
return ret;
+ cs35l45->amplifier_mode = AMP_MODE_SPK;
+
return 0;
}
@@ -1212,7 +1425,6 @@ int cs35l45_probe(struct cs35l45_private *cs35l45)
pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000);
pm_runtime_use_autosuspend(cs35l45->dev);
- pm_runtime_mark_last_busy(cs35l45->dev);
pm_runtime_set_active(cs35l45->dev);
pm_runtime_get_noresume(cs35l45->dev);
pm_runtime_enable(cs35l45->dev);
@@ -1271,7 +1483,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_probe, "SND_SOC_CS35L45");
void cs35l45_remove(struct cs35l45_private *cs35l45)
{
@@ -1286,12 +1498,14 @@ void cs35l45_remove(struct cs35l45_private *cs35l45)
/* VDD_BATT must be the last to power-off */
regulator_disable(cs35l45->vdd_batt);
}
-EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
+EXPORT_SYMBOL_NS_GPL(cs35l45_remove, "SND_SOC_CS35L45");
+
+EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = {
+ RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
-const struct dev_pm_ops cs35l45_pm_ops = {
- SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend, cs35l45_sys_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend_noirq, cs35l45_sys_resume_noirq)
};
-EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45);
MODULE_DESCRIPTION("ASoC CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
diff --git a/sound/soc/codecs/cs35l45.h b/sound/soc/codecs/cs35l45.h
index 61135a316df3..7a790d2acac7 100644
--- a/sound/soc/codecs/cs35l45.h
+++ b/sound/soc/codecs/cs35l45.h
@@ -61,9 +61,11 @@
#define CS35L45_DSP1RX6_INPUT 0x00004C54
#define CS35L45_DSP1RX7_INPUT 0x00004C58
#define CS35L45_DSP1RX8_INPUT 0x00004C5C
+#define CS35L45_HVLV_CONFIG 0x00006400
#define CS35L45_LDPM_CONFIG 0x00006404
#define CS35L45_AMP_PCM_CONTROL 0x00007000
#define CS35L45_AMP_PCM_HPF_TST 0x00007004
+#define CS35L45_AMP_GAIN 0x00007800
#define CS35L45_IRQ1_CFG 0x0000E000
#define CS35L45_IRQ1_STATUS 0x0000E004
#define CS35L45_IRQ1_EINT_1 0x0000E010
@@ -163,16 +165,24 @@
/* BLOCK_ENABLES */
#define CS35L45_IMON_EN_SHIFT 13
#define CS35L45_VMON_EN_SHIFT 12
+#define CS35L45_TEMPMON_EN_SHIFT 10
#define CS35L45_VDD_BSTMON_EN_SHIFT 9
#define CS35L45_VDD_BATTMON_EN_SHIFT 8
#define CS35L45_BST_EN_SHIFT 4
#define CS35L45_BST_EN_MASK GENMASK(5, 4)
+#define CS35L45_RCV_EN_SHIFT 2
+#define CS35L45_RCV_EN_MASK BIT(2)
+#define CS35L45_AMP_EN_SHIFT 0
+#define CS35L45_AMP_EN_MASK BIT(0)
-#define CS35L45_BST_DISABLE_FET_ON 0x01
+#define CS35L45_BST_DISABLE_FET_OFF 0x00
+#define CS35L45_BST_DISABLE_FET_ON 0x01
+#define CS35L45_BST_ENABLE 0x02
/* BLOCK_ENABLES2 */
#define CS35L45_ASP_EN_SHIFT 27
-
+#define CS35L45_AMP_DRE_EN_SHIFT 20
+#define CS35L45_AMP_DRE_EN_MASK BIT(20)
#define CS35L45_MEM_RDY_SHIFT 1
#define CS35L45_MEM_RDY_MASK BIT(1)
@@ -266,6 +276,13 @@
#define CS35L45_ASP_WL_SHIFT 0
#define CS35L45_ASP_WL_MASK GENMASK(5, 0)
+/* HVLV_CONFIG */
+#define CS35L45_FORCE_LV_OPERATION 0x01
+#define CS35L45_FORCE_HV_OPERATION 0x02
+#define CS35L45_HVLV_OPERATION 0x03
+#define CS35L45_HVLV_MODE_SHIFT 0
+#define CS35L45_HVLV_MODE_MASK GENMASK(1, 0)
+
/* AMP_PCM_CONTROL */
#define CS35L45_AMP_VOL_PCM_SHIFT 0
#define CS35L45_AMP_VOL_PCM_WIDTH 11
@@ -275,6 +292,15 @@
#define CS35L45_HPF_44P1 0x000108BD
#define CS35L45_HPF_88P2 0x0001045F
+/* AMP_GAIN_PCM */
+#define CS35L45_AMP_GAIN_PCM_10DBV 0x00
+#define CS35L45_AMP_GAIN_PCM_13DBV 0x01
+#define CS35L45_AMP_GAIN_PCM_16DBV 0x02
+#define CS35L45_AMP_GAIN_PCM_19DBV 0x03
+
+#define CS35L45_AMP_GAIN_PCM_SHIFT 8
+#define CS35L45_AMP_GAIN_PCM_MASK GENMASK(9, 8)
+
/* IRQ1_EINT_4 */
#define CS35L45_OTP_BOOT_DONE_STS_MASK BIT(1)
#define CS35L45_OTP_BUSY_MASK BIT(0)
@@ -396,6 +422,11 @@ enum control_bus_type {
CONTROL_BUS_SPI = 1,
};
+enum amp_mode {
+ AMP_MODE_SPK = 0,
+ AMP_MODE_RCV = 1,
+};
+
#define CS35L45_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_3LE| \
SNDRV_PCM_FMTBIT_S24_LE)
@@ -464,6 +495,7 @@ struct cs35l45_private {
bool sysclk_set;
u8 slot_width;
u8 slot_count;
+ int amplifier_mode;
int irq_invert;
int irq;
unsigned int i2c_addr;
@@ -475,7 +507,7 @@ extern const struct dev_pm_ops cs35l45_pm_ops;
extern const struct regmap_config cs35l45_i2c_regmap;
extern const struct regmap_config cs35l45_spi_regmap;
int cs35l45_apply_patch(struct cs35l45_private *cs35l45);
-unsigned int cs35l45_get_clk_freq_id(unsigned int freq);
+int cs35l45_get_clk_freq_id(unsigned int freq);
int cs35l45_probe(struct cs35l45_private *cs35l45);
void cs35l45_remove(struct cs35l45_private *cs35l45);
diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
index ed2a41943d97..0492ddc4102d 100644
--- a/sound/soc/codecs/cs35l56-i2c.c
+++ b/sound/soc/codecs/cs35l56-i2c.c
@@ -17,23 +17,38 @@
static int cs35l56_i2c_probe(struct i2c_client *client)
{
+ unsigned int id = (u32)(uintptr_t)i2c_get_match_data(client);
struct cs35l56_private *cs35l56;
struct device *dev = &client->dev;
- const struct regmap_config *regmap_config = &cs35l56_regmap_i2c;
+ const struct regmap_config *regmap_config;
int ret;
cs35l56 = devm_kzalloc(dev, sizeof(struct cs35l56_private), GFP_KERNEL);
if (!cs35l56)
return -ENOMEM;
- cs35l56->dev = dev;
- cs35l56->can_hibernate = true;
+ cs35l56->base.dev = dev;
+ cs35l56->base.can_hibernate = true;
i2c_set_clientdata(client, cs35l56);
- cs35l56->regmap = devm_regmap_init_i2c(client, regmap_config);
- if (IS_ERR(cs35l56->regmap)) {
- ret = PTR_ERR(cs35l56->regmap);
- return dev_err_probe(cs35l56->dev, ret, "Failed to allocate register map\n");
+
+ switch (id) {
+ case 0x3556:
+ regmap_config = &cs35l56_regmap_i2c;
+ cs35l56->base.type = 0x56;
+ break;
+ case 0x3563:
+ regmap_config = &cs35l63_regmap_i2c;
+ cs35l56->base.type = 0x63;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n");
}
ret = cs35l56_common_probe(cs35l56);
@@ -42,7 +57,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
ret = cs35l56_init(cs35l56);
if (ret == 0)
- ret = cs35l56_irq_request(cs35l56, client->irq);
+ ret = cs35l56_irq_request(&cs35l56->base, client->irq);
if (ret < 0)
cs35l56_remove(cs35l56);
@@ -57,15 +72,26 @@ static void cs35l56_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id cs35l56_id_i2c[] = {
- { "cs35l56", 0 },
+ { "cs35l56", 0x3556 },
+ { "cs35l63", 0x3563 },
{}
};
MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
+ { "CSC355C", 0x3556 },
+ { "CSC356C", 0x3563 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);
+#endif
+
static struct i2c_driver cs35l56_i2c_driver = {
.driver = {
.name = "cs35l56",
- .pm = &cs35l56_pm_ops_i2c_spi,
+ .pm = pm_ptr(&cs35l56_pm_ops_i2c_spi),
+ .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match),
},
.id_table = cs35l56_id_i2c,
.probe = cs35l56_i2c_probe,
@@ -75,8 +101,8 @@ static struct i2c_driver cs35l56_i2c_driver = {
module_i2c_driver(cs35l56_i2c_driver);
MODULE_DESCRIPTION("ASoC CS35L56 I2C driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE);
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 2cde78605ba9..42d24ac2977f 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -23,6 +23,79 @@
/* Register addresses are offset when sent over SoundWire */
#define CS35L56_SDW_ADDR_OFFSET 0x8000
+/* Cirrus bus bridge registers */
+#define CS35L56_SDW_MEM_ACCESS_STATUS 0xd0
+#define CS35L56_SDW_MEM_READ_DATA 0xd8
+
+#define CS35L56_SDW_LAST_LATE BIT(3)
+#define CS35L56_SDW_CMD_IN_PROGRESS BIT(2)
+#define CS35L56_SDW_RDATA_RDY BIT(0)
+
+#define CS35L56_LATE_READ_POLL_US 10
+#define CS35L56_LATE_READ_TIMEOUT_US 1000
+
+static int cs35l56_sdw_poll_mem_status(struct sdw_slave *peripheral,
+ unsigned int mask,
+ unsigned int match)
+{
+ int ret, val;
+
+ ret = read_poll_timeout(sdw_read_no_pm, val,
+ (val < 0) || ((val & mask) == match),
+ CS35L56_LATE_READ_POLL_US, CS35L56_LATE_READ_TIMEOUT_US,
+ false, peripheral, CS35L56_SDW_MEM_ACCESS_STATUS);
+ if (ret < 0)
+ return ret;
+
+ if (val < 0)
+ return val;
+
+ return 0;
+}
+
+static int cs35l56_sdw_slow_read(struct sdw_slave *peripheral, unsigned int reg,
+ u8 *buf, size_t val_size)
+{
+ int ret, i;
+
+ reg += CS35L56_SDW_ADDR_OFFSET;
+
+ for (i = 0; i < val_size; i += sizeof(u32)) {
+ /* Poll for bus bridge idle */
+ ret = cs35l56_sdw_poll_mem_status(peripheral,
+ CS35L56_SDW_CMD_IN_PROGRESS,
+ 0);
+ if (ret < 0) {
+ dev_err(&peripheral->dev, "!CMD_IN_PROGRESS fail: %d\n", ret);
+ return ret;
+ }
+
+ /* Reading LSByte triggers read of register to holding buffer */
+ sdw_read_no_pm(peripheral, reg + i);
+
+ /* Wait for data available */
+ ret = cs35l56_sdw_poll_mem_status(peripheral,
+ CS35L56_SDW_RDATA_RDY,
+ CS35L56_SDW_RDATA_RDY);
+ if (ret < 0) {
+ dev_err(&peripheral->dev, "RDATA_RDY fail: %d\n", ret);
+ return ret;
+ }
+
+ /* Read data from buffer */
+ ret = sdw_nread_no_pm(peripheral, CS35L56_SDW_MEM_READ_DATA,
+ sizeof(u32), &buf[i]);
+ if (ret) {
+ dev_err(&peripheral->dev, "Late read @%#x failed: %d\n", reg + i, ret);
+ return ret;
+ }
+
+ swab32s((u32 *)&buf[i]);
+ }
+
+ return 0;
+}
+
static int cs35l56_sdw_read_one(struct sdw_slave *peripheral, unsigned int reg, void *buf)
{
int ret;
@@ -48,6 +121,10 @@ static int cs35l56_sdw_read(void *context, const void *reg_buf,
int ret;
reg = le32_to_cpu(*(const __le32 *)reg_buf);
+
+ if (cs35l56_is_otp_register(reg))
+ return cs35l56_sdw_slow_read(peripheral, reg, buf8, val_size);
+
reg += CS35L56_SDW_ADDR_OFFSET;
if (val_size == 4)
@@ -161,18 +238,37 @@ static const struct regmap_bus cs35l56_regmap_bus_sdw = {
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};
+static int cs35l56_sdw_get_unique_id(struct cs35l56_private *cs35l56)
+{
+ int ret;
+
+ ret = sdw_read_no_pm(cs35l56->sdw_peripheral, SDW_SCP_DEVID_0);
+ if (ret < 0)
+ return ret;
+
+ cs35l56->sdw_unique_id = ret & 0xf;
+
+ return 0;
+}
+
static void cs35l56_sdw_init(struct sdw_slave *peripheral)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
int ret;
- pm_runtime_get_noresume(cs35l56->dev);
+ pm_runtime_get_noresume(cs35l56->base.dev);
+
+ ret = cs35l56_sdw_get_unique_id(cs35l56);
+ if (ret)
+ goto out;
- regcache_cache_only(cs35l56->regmap, false);
+ /* SoundWire UniqueId is used to index the calibration array */
+ if (cs35l56->base.cal_index < 0)
+ cs35l56->base.cal_index = cs35l56->sdw_unique_id;
ret = cs35l56_init(cs35l56);
if (ret < 0) {
- regcache_cache_only(cs35l56->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);
goto out;
}
@@ -180,15 +276,14 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
* cs35l56_init can return with !init_done if it triggered
* a soft reset.
*/
- if (cs35l56->init_done) {
+ if (cs35l56->base.init_done) {
/* Enable SoundWire interrupts */
sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1,
CS35L56_SDW_INT_MASK_CODEC_IRQ);
}
out:
- pm_runtime_mark_last_busy(cs35l56->dev);
- pm_runtime_put_autosuspend(cs35l56->dev);
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
}
static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
@@ -198,7 +293,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
/* SoundWire core holds our pm_runtime when calling this function. */
- dev_dbg(cs35l56->dev, "int control_port=%#x\n", status->control_port);
+ dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port);
if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0)
return 0;
@@ -207,7 +302,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
* Prevent bus manager suspending and possibly issuing a
* bus-reset before the queued work has run.
*/
- pm_runtime_get_noresume(cs35l56->dev);
+ pm_runtime_get_noresume(cs35l56->base.dev);
/*
* Mask and clear until it has been handled. The read of GEN_INT_STAT_1
@@ -230,14 +325,14 @@ static void cs35l56_sdw_irq_work(struct work_struct *work)
struct cs35l56_private,
sdw_irq_work);
- cs35l56_irq(-1, cs35l56);
+ cs35l56_irq(-1, &cs35l56->base);
/* unmask interrupts */
if (!cs35l56->sdw_irq_no_unmask)
sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1,
CS35L56_SDW_INT_MASK_CODEC_IRQ);
- pm_runtime_put_autosuspend(cs35l56->dev);
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
}
static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
@@ -246,14 +341,13 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
struct sdw_slave_prop *prop = &peripheral->prop;
struct sdw_dpn_prop *ports;
- ports = devm_kcalloc(cs35l56->dev, 2, sizeof(*ports), GFP_KERNEL);
+ ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL);
if (!ports)
return -ENOMEM;
prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT);
prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT);
prop->paging_support = true;
- prop->clk_stop_mode1 = false;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF;
@@ -279,17 +373,17 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
switch (status) {
case SDW_SLAVE_ATTACHED:
- dev_dbg(cs35l56->dev, "%s: ATTACHED\n", __func__);
+ dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__);
if (cs35l56->sdw_attached)
break;
- if (!cs35l56->init_done || cs35l56->soft_resetting)
+ if (!cs35l56->base.init_done || cs35l56->soft_resetting)
cs35l56_sdw_init(peripheral);
cs35l56->sdw_attached = true;
break;
case SDW_SLAVE_UNATTACHED:
- dev_dbg(cs35l56->dev, "%s: UNATTACHED\n", __func__);
+ dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__);
cs35l56->sdw_attached = false;
break;
default:
@@ -299,84 +393,13 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
return 0;
}
-static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
- struct sdw_slave *peripheral)
-{
- unsigned int curr_scale_reg, next_scale_reg;
- int curr_scale, next_scale, ret;
-
- if (!cs35l56->init_done)
- return 0;
-
- if (peripheral->bus->params.curr_bank) {
- curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
- next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
- } else {
- curr_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B0;
- next_scale_reg = SDW_SCP_BUSCLOCK_SCALE_B1;
- }
-
- /*
- * Current clock scale value must be different to new value.
- * Modify current to guarantee this. If next still has the dummy
- * value we wrote when it was current, the core code has not set
- * a new scale so restore its original good value
- */
- curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg);
- if (curr_scale < 0) {
- dev_err(cs35l56->dev, "Failed to read current clock scale: %d\n", curr_scale);
- return curr_scale;
- }
-
- next_scale = sdw_read_no_pm(peripheral, next_scale_reg);
- if (next_scale < 0) {
- dev_err(cs35l56->dev, "Failed to read next clock scale: %d\n", next_scale);
- return next_scale;
- }
-
- if (next_scale == CS35L56_SDW_INVALID_BUS_SCALE) {
- next_scale = cs35l56->old_sdw_clock_scale;
- ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale);
- if (ret < 0) {
- dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret);
- return ret;
- }
- }
-
- cs35l56->old_sdw_clock_scale = curr_scale;
- ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE);
- if (ret < 0) {
- dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret);
- return ret;
- }
-
- dev_dbg(cs35l56->dev, "Next bus scale: %#x\n", next_scale);
-
- return 0;
-}
-
-static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
- struct sdw_bus_params *params)
-{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
- int sclk;
-
- sclk = params->curr_dr_freq / 2;
- dev_dbg(cs35l56->dev, "%s: sclk=%u c=%u r=%u\n", __func__, sclk, params->col, params->row);
-
- if (cs35l56->rev < 0xb0)
- return cs35l56_a1_kick_divider(cs35l56, peripheral);
-
- return 0;
-}
-
static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
- dev_dbg(cs35l56->dev, "%s: mode:%d type:%d\n", __func__, mode, type);
+ dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type);
return 0;
}
@@ -385,7 +408,6 @@ static const struct sdw_slave_ops cs35l56_sdw_ops = {
.read_prop = cs35l56_sdw_read_prop,
.interrupt_callback = cs35l56_sdw_interrupt,
.update_status = cs35l56_sdw_update_status,
- .bus_config = cs35l56_sdw_bus_config,
#ifdef DEBUG
.clk_stop = cs35l56_sdw_clk_stop,
#endif
@@ -397,10 +419,10 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs
if (peripheral->unattach_request) {
/* Cannot access registers until bus is re-initialized. */
- dev_dbg(cs35l56->dev, "Wait for initialization_complete\n");
+ dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n");
if (!wait_for_completion_timeout(&peripheral->initialization_complete,
msecs_to_jiffies(5000))) {
- dev_err(cs35l56->dev, "initialization_complete timed out\n");
+ dev_err(cs35l56->base.dev, "initialization_complete timed out\n");
return -ETIMEDOUT;
}
@@ -419,10 +441,10 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;
- return cs35l56_runtime_suspend(dev);
+ return cs35l56_runtime_suspend_common(&cs35l56->base);
}
static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
@@ -432,14 +454,14 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
dev_dbg(dev, "Runtime resume\n");
- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;
ret = cs35l56_sdw_handle_unattach(cs35l56);
if (ret < 0)
return ret;
- ret = cs35l56_runtime_resume_common(cs35l56);
+ ret = cs35l56_runtime_resume_common(&cs35l56->base, true);
if (ret)
return ret;
@@ -454,7 +476,7 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return 0;
/*
@@ -487,27 +509,43 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
{
struct device *dev = &peripheral->dev;
struct cs35l56_private *cs35l56;
+ const struct regmap_config *regmap_config;
int ret;
cs35l56 = devm_kzalloc(dev, sizeof(*cs35l56), GFP_KERNEL);
if (!cs35l56)
return -ENOMEM;
- cs35l56->dev = dev;
+ cs35l56->base.dev = dev;
cs35l56->sdw_peripheral = peripheral;
+ cs35l56->sdw_link_num = peripheral->bus->link_id;
INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work);
dev_set_drvdata(dev, cs35l56);
- cs35l56->regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw,
- peripheral, &cs35l56_regmap_sdw);
- if (IS_ERR(cs35l56->regmap)) {
- ret = PTR_ERR(cs35l56->regmap);
+ switch ((unsigned int)id->driver_data) {
+ case 0x3556:
+ case 0x3557:
+ regmap_config = &cs35l56_regmap_sdw;
+ break;
+ case 0x3563:
+ regmap_config = &cs35l63_regmap_sdw;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ cs35l56->base.type = ((unsigned int)id->driver_data) & 0xff;
+
+ cs35l56->base.regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw,
+ peripheral, regmap_config);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
return dev_err_probe(dev, ret, "Failed to allocate register map\n");
}
/* Start in cache-only until device is enumerated */
- regcache_cache_only(cs35l56->regmap, true);
+ regcache_cache_only(cs35l56->base.regmap, true);
ret = cs35l56_common_probe(cs35l56);
if (ret != 0)
@@ -540,7 +578,9 @@ static const struct dev_pm_ops cs35l56_sdw_pm = {
};
static const struct sdw_device_id cs35l56_sdw_id[] = {
- SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0),
+ SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556),
+ SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557),
+ SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563),
{},
};
MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id);
@@ -548,7 +588,7 @@ MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id);
static struct sdw_driver cs35l56_sdw_driver = {
.driver = {
.name = "cs35l56",
- .pm = &cs35l56_sdw_pm,
+ .pm = pm_ptr(&cs35l56_sdw_pm),
},
.probe = cs35l56_sdw_probe,
.remove = cs35l56_sdw_remove,
@@ -559,8 +599,8 @@ static struct sdw_driver cs35l56_sdw_driver = {
module_sdw_driver(cs35l56_sdw_driver);
MODULE_DESCRIPTION("ASoC CS35L56 SoundWire driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE);
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 60da8c75b7b9..60100c8f8c95 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -5,13 +5,94 @@
// Copyright (C) 2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
+#include <linux/array_size.h>
+#include <linux/cleanup.h>
+#include <linux/debugfs.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/fs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kstrtox.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/string_choices.h>
#include <linux/types.h>
+#include <sound/cs-amp-lib.h>
#include "cs35l56.h"
+static const struct reg_sequence cs35l56_patch[] = {
+ /*
+ * Firmware can change these to non-defaults to satisfy SDCA.
+ * Ensure that they are at known defaults.
+ */
+ { CS35L56_ASP1_ENABLES1, 0x00000000 },
+ { CS35L56_ASP1_CONTROL1, 0x00000028 },
+ { CS35L56_ASP1_CONTROL2, 0x18180200 },
+ { CS35L56_ASP1_CONTROL3, 0x00000002 },
+ { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
+ { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
+ { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
+ { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
+ { CS35L56_ASP1TX1_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX2_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX3_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX4_INPUT, 0x00000000 },
+ { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
+ { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
+ { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
+ { CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 },
+ { CS35L56_IRQ1_MASK_18, 0x1f7df0ff },
+};
+
+static const struct reg_sequence cs35l56_patch_fw[] = {
+ /* These are not reset by a soft-reset, so patch to defaults. */
+ { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 },
+ { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 },
+ { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 },
+};
+
+static const struct reg_sequence cs35l63_patch_fw[] = {
+ /* These are not reset by a soft-reset, so patch to defaults. */
+ { CS35L63_MAIN_RENDER_USER_MUTE, 0x00000000 },
+ { CS35L63_MAIN_RENDER_USER_VOLUME, 0x00000000 },
+ { CS35L63_MAIN_POSTURE_NUMBER, 0x00000000 },
+};
+
+int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
+{
+ int ret;
+
+ ret = regmap_register_patch(cs35l56_base->regmap, cs35l56_patch,
+ ARRAY_SIZE(cs35l56_patch));
+ if (ret)
+ return ret;
+
+
+ switch (cs35l56_base->type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ ret = regmap_register_patch(cs35l56_base->regmap, cs35l56_patch_fw,
+ ARRAY_SIZE(cs35l56_patch_fw));
+ break;
+ case 0x63:
+ ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw,
+ ARRAY_SIZE(cs35l63_patch_fw));
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED");
+
static const struct reg_default cs35l56_reg_defaults[] = {
+ /* no defaults for OTP_MEM - first read populates cache */
+
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
@@ -20,24 +101,53 @@ static const struct reg_default cs35l56_reg_defaults[] = {
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
- { CS35L56_ASP1TX1_INPUT, 0x00000018 },
- { CS35L56_ASP1TX2_INPUT, 0x00000019 },
- { CS35L56_ASP1TX3_INPUT, 0x00000020 },
- { CS35L56_ASP1TX4_INPUT, 0x00000028 },
+ { CS35L56_ASP1TX1_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX2_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX3_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX4_INPUT, 0x00000000 },
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
{ CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 },
- { CS35L56_IRQ1_CFG, 0x00000000 },
{ CS35L56_IRQ1_MASK_1, 0x83ffffff },
{ CS35L56_IRQ1_MASK_2, 0xffff7fff },
{ CS35L56_IRQ1_MASK_4, 0xe0ffffff },
{ CS35L56_IRQ1_MASK_8, 0xfc000fff },
{ CS35L56_IRQ1_MASK_18, 0x1f7df0ff },
{ CS35L56_IRQ1_MASK_20, 0x15c00000 },
- /* CS35L56_MAIN_RENDER_USER_MUTE - soft register, no default */
- /* CS35L56_MAIN_RENDER_USER_VOLUME - soft register, no default */
- /* CS35L56_MAIN_POSTURE_NUMBER - soft register, no default */
+ { CS35L56_MAIN_RENDER_USER_MUTE, 0x00000000 },
+ { CS35L56_MAIN_RENDER_USER_VOLUME, 0x00000000 },
+ { CS35L56_MAIN_POSTURE_NUMBER, 0x00000000 },
+};
+
+static const struct reg_default cs35l63_reg_defaults[] = {
+ /* no defaults for OTP_MEM - first read populates cache */
+
+ { CS35L56_ASP1_ENABLES1, 0x00000000 },
+ { CS35L56_ASP1_CONTROL1, 0x00000028 },
+ { CS35L56_ASP1_CONTROL2, 0x18180200 },
+ { CS35L56_ASP1_CONTROL3, 0x00000002 },
+ { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
+ { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
+ { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
+ { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
+ { CS35L56_ASP1TX1_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX2_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX3_INPUT, 0x00000000 },
+ { CS35L56_ASP1TX4_INPUT, 0x00000000 },
+ { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
+ { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
+ { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
+ { CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 },
+ { CS35L56_IRQ1_MASK_1, 0x8003ffff },
+ { CS35L56_IRQ1_MASK_2, 0xffff7fff },
+ { CS35L56_IRQ1_MASK_4, 0xe0ffffff },
+ { CS35L56_IRQ1_MASK_8, 0x8c000fff },
+ { CS35L56_IRQ1_MASK_18, 0x0760f000 },
+ { CS35L56_IRQ1_MASK_20, 0x15c00000 },
+ { CS35L63_MAIN_RENDER_USER_MUTE, 0x00000000 },
+ { CS35L63_MAIN_RENDER_USER_VOLUME, 0x00000000 },
+ { CS35L63_MAIN_POSTURE_NUMBER, 0x00000000 },
};
static bool cs35l56_is_dsp_memory(unsigned int reg)
@@ -69,6 +179,9 @@ static bool cs35l56_readable_reg(struct device *dev, unsigned int reg)
case CS35L56_BLOCK_ENABLES2:
case CS35L56_REFCLK_INPUT:
case CS35L56_GLOBAL_SAMPLE_RATE:
+ case CS35L56_OTP_MEM_53:
+ case CS35L56_OTP_MEM_54:
+ case CS35L56_OTP_MEM_55:
case CS35L56_ASP1_ENABLES1:
case CS35L56_ASP1_CONTROL1:
case CS35L56_ASP1_CONTROL2:
@@ -100,6 +213,8 @@ static bool cs35l56_readable_reg(struct device *dev, unsigned int reg)
case CS35L56_IRQ1_MASK_8:
case CS35L56_IRQ1_MASK_18:
case CS35L56_IRQ1_MASK_20:
+ case CS35L56_MIXER_NGATE_CH1_CFG:
+ case CS35L56_MIXER_NGATE_CH2_CFG:
case CS35L56_DSP_VIRTUAL1_MBOX_1:
case CS35L56_DSP_VIRTUAL1_MBOX_2:
case CS35L56_DSP_VIRTUAL1_MBOX_3:
@@ -108,6 +223,8 @@ static bool cs35l56_readable_reg(struct device *dev, unsigned int reg)
case CS35L56_DSP_VIRTUAL1_MBOX_6:
case CS35L56_DSP_VIRTUAL1_MBOX_7:
case CS35L56_DSP_VIRTUAL1_MBOX_8:
+ case CS35L56_DIE_STS1:
+ case CS35L56_DIE_STS2:
case CS35L56_DSP_RESTRICT_STS1:
case CS35L56_DSP1_SYS_INFO_ID ... CS35L56_DSP1_SYS_INFO_END:
case CS35L56_DSP1_AHBM_WINDOW_DEBUG_0:
@@ -134,7 +251,7 @@ static bool cs35l56_precious_reg(struct device *dev, unsigned int reg)
}
}
-static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
+static bool cs35l56_common_volatile_reg(unsigned int reg)
{
switch (reg) {
case CS35L56_DEVID:
@@ -155,6 +272,8 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8:
case CS35L56_IRQ1_EINT_18:
case CS35L56_IRQ1_EINT_20:
+ case CS35L56_MIXER_NGATE_CH1_CFG:
+ case CS35L56_MIXER_NGATE_CH2_CFG:
case CS35L56_DSP_VIRTUAL1_MBOX_1:
case CS35L56_DSP_VIRTUAL1_MBOX_2:
case CS35L56_DSP_VIRTUAL1_MBOX_3:
@@ -172,42 +291,1266 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
case CS35L56_DSP1_SCRATCH3:
case CS35L56_DSP1_SCRATCH4:
return true;
+ default:
+ return cs35l56_is_dsp_memory(reg);
+ }
+}
+
+static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
case CS35L56_MAIN_RENDER_USER_MUTE:
case CS35L56_MAIN_RENDER_USER_VOLUME:
case CS35L56_MAIN_POSTURE_NUMBER:
return false;
default:
- return cs35l56_is_dsp_memory(reg);
+ return cs35l56_common_volatile_reg(reg);
+ }
+}
+
+static bool cs35l63_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L63_MAIN_RENDER_USER_MUTE:
+ case CS35L63_MAIN_RENDER_USER_VOLUME:
+ case CS35L63_MAIN_POSTURE_NUMBER:
+ return false;
+ default:
+ return cs35l56_common_volatile_reg(reg);
}
}
-static const u32 cs35l56_firmware_registers[] = {
- CS35L56_MAIN_RENDER_USER_MUTE,
- CS35L56_MAIN_RENDER_USER_VOLUME,
- CS35L56_MAIN_POSTURE_NUMBER,
+static const struct cs35l56_fw_reg cs35l56_fw_reg = {
+ .fw_ver = CS35L56_DSP1_FW_VER,
+ .halo_state = CS35L56_DSP1_HALO_STATE,
+ .pm_cur_stat = CS35L56_DSP1_PM_CUR_STATE,
+ .prot_sts = CS35L56_PROTECTION_STATUS,
+ .transducer_actual_ps = CS35L56_TRANSDUCER_ACTUAL_PS,
+ .user_mute = CS35L56_MAIN_RENDER_USER_MUTE,
+ .user_volume = CS35L56_MAIN_RENDER_USER_VOLUME,
+ .posture_number = CS35L56_MAIN_POSTURE_NUMBER,
+};
+
+static const struct cs35l56_fw_reg cs35l56_b2_fw_reg = {
+ .fw_ver = CS35L56_DSP1_FW_VER,
+ .halo_state = CS35L56_B2_DSP1_HALO_STATE,
+ .pm_cur_stat = CS35L56_B2_DSP1_PM_CUR_STATE,
+ .prot_sts = CS35L56_PROTECTION_STATUS,
+ .transducer_actual_ps = CS35L56_TRANSDUCER_ACTUAL_PS,
+ .user_mute = CS35L56_MAIN_RENDER_USER_MUTE,
+ .user_volume = CS35L56_MAIN_RENDER_USER_VOLUME,
+ .posture_number = CS35L56_MAIN_POSTURE_NUMBER,
+};
+
+static const struct cs35l56_fw_reg cs35l63_fw_reg = {
+ .fw_ver = CS35L63_DSP1_FW_VER,
+ .halo_state = CS35L63_DSP1_HALO_STATE,
+ .pm_cur_stat = CS35L63_DSP1_PM_CUR_STATE,
+ .prot_sts = CS35L63_PROTECTION_STATUS,
+ .transducer_actual_ps = CS35L63_TRANSDUCER_ACTUAL_PS,
+ .user_mute = CS35L63_MAIN_RENDER_USER_MUTE,
+ .user_volume = CS35L63_MAIN_RENDER_USER_VOLUME,
+ .posture_number = CS35L63_MAIN_POSTURE_NUMBER,
};
-void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap)
+static void cs35l56_set_fw_reg_table(struct cs35l56_base *cs35l56_base)
+{
+ switch (cs35l56_base->type) {
+ default:
+ switch (cs35l56_base->rev) {
+ case 0xb0:
+ cs35l56_base->fw_reg = &cs35l56_fw_reg;
+ break;
+ default:
+ cs35l56_base->fw_reg = &cs35l56_b2_fw_reg;
+ break;
+ }
+ break;
+ case 0x63:
+ cs35l56_base->fw_reg = &cs35l63_fw_reg;
+ break;
+ }
+}
+
+int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
{
- int i;
unsigned int val;
+ int ret;
- for (i = 0; i < ARRAY_SIZE(cs35l56_firmware_registers); i++) {
- regmap_read(regmap, cs35l56_firmware_registers[i], &val);
- dev_dbg(dev, "%s: %d: %#x: %#x\n", __func__,
- i, cs35l56_firmware_registers[i], val);
+ regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ val, (val == 0),
+ CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
+ if (ret) {
+ dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret);
+ return ret;
}
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
+{
+ int ret;
+ unsigned int val;
+
+ ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN);
+ if (ret)
+ return ret;
+
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap,
+ cs35l56_base->fw_reg->pm_cur_stat,
+ val, (val == CS35L56_HALO_STATE_SHUTDOWN),
+ CS35L56_HALO_STATE_POLL_US,
+ CS35L56_HALO_STATE_TIMEOUT_US);
+ if (ret < 0)
+ dev_err(cs35l56_base->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
+ val, ret);
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int val = 0;
+ int read_ret, poll_ret;
+
+ /*
+ * The regmap must remain in cache-only until the chip has
+ * booted, so use a bypassed read of the status register.
+ */
+ poll_ret = read_poll_timeout(regmap_read_bypassed, read_ret,
+ (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
+ CS35L56_HALO_STATE_POLL_US,
+ CS35L56_HALO_STATE_TIMEOUT_US,
+ false,
+ cs35l56_base->regmap,
+ cs35l56_base->fw_reg->halo_state,
+ &val);
+
+ if (poll_ret) {
+ dev_err(cs35l56_base->dev, "Firmware boot timed out(%d): HALO_STATE=%#x\n",
+ read_ret, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, "SND_SOC_CS35L56_SHARED");
+
+void cs35l56_wait_control_port_ready(void)
+{
+ /* Wait for control port to be ready (datasheet tIRS). */
+ usleep_range(CS35L56_CONTROL_PORT_READY_US, 2 * CS35L56_CONTROL_PORT_READY_US);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, "SND_SOC_CS35L56_SHARED");
+
+void cs35l56_wait_min_reset_pulse(void)
+{
+ /* Satisfy minimum reset pulse width spec */
+ usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
+}
+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),
+};
+
+static const struct reg_sequence cs35l56_b2_system_reset_seq[] = {
+ REG_SEQ0(CS35L56_B2_DSP1_HALO_STATE, 0),
+ REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
+};
+
+static const struct reg_sequence cs35l63_system_reset_seq[] = {
+ REG_SEQ0(CS35L63_DSP1_HALO_STATE, 0),
+ REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
+};
+
+void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
+{
+ /*
+ * Must enter cache-only first so there can't be any more register
+ * 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;
+ }
+
+ switch (cs35l56_base->type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ switch (cs35l56_base->rev) {
+ case 0xb0:
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_system_reset_seq,
+ ARRAY_SIZE(cs35l56_system_reset_seq));
+ break;
+ default:
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_b2_system_reset_seq,
+ ARRAY_SIZE(cs35l56_b2_system_reset_seq));
+ break;
+ }
+ break;
+ case 0x63:
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l63_system_reset_seq,
+ ARRAY_SIZE(cs35l63_system_reset_seq));
+ break;
+ default:
+ break;
+ }
+
+ /* On SoundWire the registers won't be accessible until it re-enumerates. */
+ if (is_soundwire)
+ return;
+
+ cs35l56_wait_control_port_ready();
+
+ /* Leave in cache-only. This will be revoked when the chip has rebooted. */
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
+{
+ int ret;
+
+ if (irq < 1)
+ return 0;
+
+ ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "cs35l56", cs35l56_base);
+ if (!ret)
+ cs35l56_base->irq = irq;
+ else
+ dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED");
+
+irqreturn_t cs35l56_irq(int irq, void *data)
+{
+ struct cs35l56_base *cs35l56_base = data;
+ unsigned int status1 = 0, status8 = 0, status20 = 0;
+ unsigned int mask1, mask8, mask20;
+ unsigned int val;
+ int rv;
+
+ irqreturn_t ret = IRQ_NONE;
+
+ if (!cs35l56_base->init_done)
+ return IRQ_NONE;
+
+ mutex_lock(&cs35l56_base->irq_lock);
+
+ rv = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (rv < 0) {
+ dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
+ goto err_unlock;
+ }
+
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
+ if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
+ dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
+ goto err;
+ }
+
+ /* Ack interrupts */
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1);
+ status1 &= ~mask1;
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1);
+
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8);
+ status8 &= ~mask8;
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8);
+
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20);
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20);
+ status20 &= ~mask20;
+ /* We don't want EINT20 but they default to unmasked: force mask */
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+
+ dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8);
+
+ /* Check to see if unmasked bits are active */
+ if (!status1 && !status8 && !status20)
+ goto err;
+
+ if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
+ dev_crit(cs35l56_base->dev, "Amp short error\n");
+
+ if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
+ dev_crit(cs35l56_base->dev, "Overtemp error\n");
+
+ ret = IRQ_HANDLED;
+
+err:
+ pm_runtime_put(cs35l56_base->dev);
+err_unlock:
+ mutex_unlock(&cs35l56_base->irq_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int val;
+ int ret;
+
+ /*
+ * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
+ * can't be used here to test for memory retention.
+ * Assume that tuning must be re-loaded.
+ */
+ if (cs35l56_base->secured)
+ return true;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(cs35l56_base->regmap,
+ cs35l56_base->fw_reg->prot_sts,
+ &val);
+ if (ret)
+ dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+ else
+ ret = !!(val & CS35L56_FIRMWARE_MISSING);
+
+ pm_runtime_put_autosuspend(cs35l56_base->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, "SND_SOC_CS35L56_SHARED");
+
+static const struct reg_sequence cs35l56_hibernate_seq[] = {
+ /* This must be the last register access */
+ REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE),
+};
+
+static void cs35l56_issue_wake_event(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int val;
+
+ /*
+ * Dummy transactions to trigger I2C/SPI auto-wake. Issue two
+ * transactions to meet the minimum required time from the rising edge
+ * to the last falling edge of wake.
+ *
+ * It uses bypassed read because we must wake the chip before
+ * disabling regmap cache-only.
+ */
+ regmap_read_bypassed(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
+
+ usleep_range(CS35L56_WAKE_HOLD_TIME_US, 2 * CS35L56_WAKE_HOLD_TIME_US);
+
+ regmap_read_bypassed(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
+
+ cs35l56_wait_control_port_ready();
+}
+
+static int cs35l56_wait_for_ps3(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read_poll_timeout(cs35l56_base->regmap,
+ cs35l56_base->fw_reg->transducer_actual_ps,
+ val, (val >= CS35L56_PS3),
+ CS35L56_PS3_POLL_US,
+ CS35L56_PS3_TIMEOUT_US);
+ if (ret)
+ dev_warn(cs35l56_base->dev, "PS3 wait failed: %d\n", ret);
+
+ return ret;
+}
+
+int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base)
+{
+ if (!cs35l56_base->init_done)
+ return 0;
+
+ /* Firmware must have entered a power-save state */
+ cs35l56_wait_for_ps3(cs35l56_base);
+
+ /* Clear BOOT_DONE so it can be used to detect a reboot */
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
+
+ if (!cs35l56_base->can_hibernate) {
+ regcache_cache_only(cs35l56_base->regmap, true);
+ dev_dbg(cs35l56_base->dev, "Suspended: no hibernate");
+
+ return 0;
+ }
+
+ /*
+ * Must enter cache-only first so there can't be any more register
+ * accesses other than the controlled hibernate sequence below.
+ */
+ regcache_cache_only(cs35l56_base->regmap, true);
+
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_hibernate_seq,
+ ARRAY_SIZE(cs35l56_hibernate_seq));
+
+ dev_dbg(cs35l56_base->dev, "Suspended: hibernate");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire)
+{
+ unsigned int val;
+ int ret;
+
+ if (!cs35l56_base->init_done)
+ return 0;
+
+ if (!cs35l56_base->can_hibernate)
+ goto out_sync;
+
+ /* Must be done before releasing cache-only */
+ if (!is_soundwire)
+ cs35l56_issue_wake_event(cs35l56_base);
+
+out_sync:
+ ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret);
+ goto err;
+ }
+
+ regcache_cache_only(cs35l56_base->regmap, false);
+
+ ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ if (ret)
+ goto err;
+
+ /* BOOT_DONE will be 1 if the amp reset */
+ regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, &val);
+ if (val & CS35L56_OTP_BOOT_DONE_MASK) {
+ dev_dbg(cs35l56_base->dev, "Registers reset in suspend\n");
+ regcache_mark_dirty(cs35l56_base->regmap);
+ }
+
+ regcache_sync(cs35l56_base->regmap);
+
+ dev_dbg(cs35l56_base->dev, "Resumed");
+
+ return 0;
+
+err:
+ regcache_cache_only(cs35l56_base->regmap, true);
+
+ regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+ cs35l56_hibernate_seq,
+ ARRAY_SIZE(cs35l56_hibernate_seq));
+
+ return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_reread_firmware_registers, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, "SND_SOC_CS35L56_SHARED");
-const struct cs_dsp_region cs35l56_dsp1_regions[] = {
+static const struct cs_dsp_region cs35l56_dsp1_regions[] = {
{ .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 },
{ .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 },
{ .type = WMFW_HALO_YM_PACKED, .base = CS35L56_DSP1_YMEM_PACKED_0 },
{ .type = WMFW_ADSP2_XM, .base = CS35L56_DSP1_XMEM_UNPACKED24_0 },
{ .type = WMFW_ADSP2_YM, .base = CS35L56_DSP1_YMEM_UNPACKED24_0 },
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_dsp1_regions, SND_SOC_CS35L56_SHARED);
+
+void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp)
+{
+ cs_dsp->num = 1;
+ cs_dsp->type = WMFW_HALO;
+ cs_dsp->rev = 0;
+ cs_dsp->dev = cs35l56_base->dev;
+ cs_dsp->regmap = cs35l56_base->regmap;
+ cs_dsp->base = CS35L56_DSP1_CORE_BASE;
+ cs_dsp->base_sysinfo = CS35L56_DSP1_SYS_INFO_ID;
+ cs_dsp->mem = cs35l56_dsp1_regions;
+ cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions);
+ cs_dsp->no_core_startstop = true;
+
+ cs35l56_base->dsp = cs_dsp;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, "SND_SOC_CS35L56_SHARED");
+
+struct cs35l56_pte {
+ u8 x;
+ u8 wafer_id;
+ u8 pte[2];
+ u8 lot[3];
+ u8 y;
+ u8 unused[3];
+ u8 dvs;
+} __packed;
+static_assert((sizeof(struct cs35l56_pte) % sizeof(u32)) == 0);
+
+static int cs35l56_read_silicon_uid(struct cs35l56_base *cs35l56_base)
+{
+ struct cs35l56_pte pte;
+ u64 unique_id;
+ int ret;
+
+ ret = regmap_raw_read(cs35l56_base->regmap, CS35L56_OTP_MEM_53, &pte, sizeof(pte));
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Failed to read OTP: %d\n", ret);
+ return ret;
+ }
+
+ unique_id = (u32)pte.lot[2] | ((u32)pte.lot[1] << 8) | ((u32)pte.lot[0] << 16);
+ unique_id <<= 32;
+ unique_id |= (u32)pte.x | ((u32)pte.y << 8) | ((u32)pte.wafer_id << 16) |
+ ((u32)pte.dvs << 24);
+
+ cs35l56_base->silicon_uid = unique_id;
+
+ return 0;
+}
+
+static int cs35l63_read_silicon_uid(struct cs35l56_base *cs35l56_base)
+{
+ u32 tmp[2];
+ u64 unique_id;
+ int ret;
+
+ ret = regmap_bulk_read(cs35l56_base->regmap, CS35L56_DIE_STS1, tmp, ARRAY_SIZE(tmp));
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Cannot obtain CS35L56_DIE_STS: %d\n", ret);
+ return ret;
+ }
+
+ unique_id = tmp[1];
+ unique_id <<= 32;
+ unique_id |= tmp[0];
+
+ cs35l56_base->silicon_uid = unique_id;
+
+ return 0;
+}
+
+/* Firmware calibration controls */
+const struct cirrus_amp_cal_controls cs35l56_calibration_controls = {
+ .alg_id = 0x9f210,
+ .mem_region = WMFW_ADSP2_YM,
+ .ambient = "CAL_AMBIENT",
+ .calr = "CAL_R",
+ .status = "CAL_STATUS",
+ .checksum = "CAL_CHECKSUM",
+};
+EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, "SND_SOC_CS35L56_SHARED");
+
+static const struct cirrus_amp_cal_controls cs35l63_calibration_controls = {
+ .alg_id = 0xbf210,
+ .mem_region = WMFW_ADSP2_YM,
+ .ambient = "CAL_AMBIENT",
+ .calr = "CAL_R",
+ .status = "CAL_STATUS",
+ .checksum = "CAL_CHECKSUM",
+};
+
+int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base)
+{
+ int ret;
+
+ /* Driver can't apply calibration to a secured part, so skip */
+ if (cs35l56_base->secured)
+ return 0;
+
+ ret = cs_amp_get_efi_calibration_data(cs35l56_base->dev,
+ cs35l56_base->silicon_uid,
+ cs35l56_base->cal_index,
+ &cs35l56_base->cal_data);
+
+ /* Only return an error status if probe should be aborted */
+ if ((ret == -ENOENT) || (ret == -EOVERFLOW))
+ return 0;
+
+ if (ret < 0)
+ return ret;
+
+ cs35l56_base->cal_data_valid = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_stash_calibration(struct cs35l56_base *cs35l56_base,
+ const struct cirrus_amp_cal_data *data)
+{
+
+ /* Ignore if it is empty */
+ if (!data->calTime[0] && !data->calTime[1])
+ return -ENODATA;
+
+ if (cs_amp_cal_target_u64(data) != cs35l56_base->silicon_uid) {
+ dev_err(cs35l56_base->dev, "cal_data not for this silicon ID\n");
+ return -EINVAL;
+ }
+
+ cs35l56_base->cal_data = *data;
+ cs35l56_base->cal_data_valid = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_stash_calibration, "SND_SOC_CS35L56_SHARED");
+
+static int cs35l56_perform_calibration(struct cs35l56_base *cs35l56_base)
+{
+ const struct cirrus_amp_cal_controls *calibration_controls =
+ cs35l56_base->calibration_controls;
+ struct cs_dsp *dsp = cs35l56_base->dsp;
+ struct cirrus_amp_cal_data cal_data;
+ struct cs_dsp_coeff_ctl *ctl;
+ bool ngate_ch1_was_enabled = false;
+ bool ngate_ch2_was_enabled = false;
+ int cali_norm_en_alg_id, cali_norm_en_mem;
+ int ret;
+ __be32 val;
+
+ if (cs35l56_base->silicon_uid == 0) {
+ dev_err(cs35l56_base->dev, "Cannot calibrate: no silicon UID\n");
+ return -ENXIO;
+ }
+
+ switch (cs35l56_base->type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ if (cs35l56_base->rev < 0xb2) {
+ cali_norm_en_alg_id = 0x9f22f;
+ cali_norm_en_mem = WMFW_ADSP2_YM;
+ } else {
+ cali_norm_en_alg_id = 0x9f210;
+ cali_norm_en_mem = WMFW_ADSP2_XM;
+ }
+ break;
+ default:
+ cali_norm_en_alg_id = 0xbf210;
+ cali_norm_en_mem = WMFW_ADSP2_XM;
+ break;
+ }
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_wait_for_ps3(cs35l56_base);
+ if (ret) {
+ ret = -EBUSY;
+ goto err_pm_put;
+ }
+
+ regmap_update_bits_check(cs35l56_base->regmap, CS35L56_MIXER_NGATE_CH1_CFG,
+ CS35L56_AUX_NGATE_CHn_EN, 0, &ngate_ch1_was_enabled);
+ regmap_update_bits_check(cs35l56_base->regmap, CS35L56_MIXER_NGATE_CH2_CFG,
+ CS35L56_AUX_NGATE_CHn_EN, 0, &ngate_ch2_was_enabled);
+
+ scoped_guard(mutex, &dsp->pwr_lock) {
+ ctl = cs_dsp_get_ctl(dsp,
+ calibration_controls->status,
+ calibration_controls->mem_region,
+ calibration_controls->alg_id);
+ if (!ctl) {
+ dev_err(cs35l56_base->dev, "Could not get %s control\n",
+ calibration_controls->status);
+ ret = -EIO;
+ goto err;
+ }
+
+ val = cpu_to_be32(0);
+ ret = cs_dsp_coeff_write_ctrl(cs_dsp_get_ctl(dsp,
+ "CALI_NORM_EN",
+ cali_norm_en_mem,
+ cali_norm_en_alg_id),
+ 0, &val, sizeof(val));
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Could not write %s: %d\n", "CALI_NORM_EN", ret);
+ ret = -EIO;
+ goto err;
+ }
+
+ ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_AUDIO_CALIBRATION);
+ if (ret) {
+ ret = -EIO;
+ goto err;
+ }
+
+ if (read_poll_timeout(cs_dsp_coeff_read_ctrl, ret,
+ (val == cpu_to_be32(1)),
+ CS35L56_CALIBRATION_POLL_US,
+ CS35L56_CALIBRATION_TIMEOUT_US,
+ true,
+ ctl, 0, &val, sizeof(val))) {
+ dev_err(cs35l56_base->dev, "Calibration timed out (CAL_STATUS: %u)\n",
+ be32_to_cpu(val));
+ switch (be32_to_cpu(val)) {
+ case CS35L56_CAL_STATUS_OUT_OF_RANGE:
+ ret = -ERANGE;
+ goto err;
+ default:
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+ }
+ }
+
+ cs35l56_base->cal_data_valid = false;
+ memset(&cal_data, 0, sizeof(cal_data));
+ ret = cs_amp_read_cal_coeffs(dsp, calibration_controls, &cal_data);
+ if (ret) {
+ ret = -EIO;
+ goto err;
+ }
+
+ dev_info(cs35l56_base->dev, "Cal status:%d calR:%d ambient:%d\n",
+ cal_data.calStatus, cal_data.calR, cal_data.calAmbient);
+
+ cal_data.calTarget[0] = (u32)cs35l56_base->silicon_uid;
+ cal_data.calTarget[1] = (u32)(cs35l56_base->silicon_uid >> 32);
+ cs35l56_base->cal_data = cal_data;
+ cs35l56_base->cal_data_valid = true;
+
+ ret = 0;
+
+err:
+ if (ngate_ch1_was_enabled) {
+ regmap_set_bits(cs35l56_base->regmap, CS35L56_MIXER_NGATE_CH1_CFG,
+ CS35L56_AUX_NGATE_CHn_EN);
+ }
+ if (ngate_ch2_was_enabled) {
+ regmap_set_bits(cs35l56_base->regmap, CS35L56_MIXER_NGATE_CH2_CFG,
+ CS35L56_AUX_NGATE_CHn_EN);
+ }
+err_pm_put:
+ pm_runtime_put(cs35l56_base->dev);
+
+ return ret;
+}
+
+ssize_t cs35l56_calibrate_debugfs_write(struct cs35l56_base *cs35l56_base,
+ const char __user *from, size_t count,
+ loff_t *ppos)
+{
+ static const char * const options[] = { "factory", "store_uefi" };
+ char buf[11] = { 0 };
+ int num_amps, ret;
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS_COMMON))
+ return -ENXIO;
+
+ if (*ppos)
+ return -EINVAL;
+
+ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count);
+ if (ret < 0)
+ return ret;
+
+ switch (sysfs_match_string(options, buf)) {
+ case 0:
+ ret = cs35l56_perform_calibration(cs35l56_base);
+ if (ret < 0)
+ return ret;
+ break;
+ case 1:
+ if (!cs35l56_base->cal_data_valid)
+ return -ENODATA;
+
+ num_amps = cs35l56_base->num_amps;
+ if (num_amps == 0)
+ num_amps = -1;
+
+ ret = cs_amp_set_efi_calibration_data(cs35l56_base->dev,
+ cs35l56_base->cal_index,
+ num_amps,
+ &cs35l56_base->cal_data);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return count;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_calibrate_debugfs_write, "SND_SOC_CS35L56_SHARED");
+
+ssize_t cs35l56_cal_ambient_debugfs_write(struct cs35l56_base *cs35l56_base,
+ const char __user *from, size_t count,
+ loff_t *ppos)
+{
+ unsigned long val;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS_COMMON))
+ return -ENXIO;
+
+ if (*ppos)
+ return -EINVAL;
+
+ ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+ if (ret)
+ return ret;
+
+ ret = kstrtoul_from_user(from, count, 10, &val);
+ if (ret < 0)
+ goto out;
+
+ ret = cs_amp_write_ambient_temp(cs35l56_base->dsp, cs35l56_base->calibration_controls, val);
+ if (ret)
+ ret = -EIO;
+out:
+ pm_runtime_put(cs35l56_base->dev);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_cal_ambient_debugfs_write, "SND_SOC_CS35L56_SHARED");
+
+ssize_t cs35l56_cal_data_debugfs_read(struct cs35l56_base *cs35l56_base,
+ char __user *to, size_t count,
+ loff_t *ppos)
+{
+ if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS_COMMON))
+ return -ENXIO;
+
+ if (!cs35l56_base->cal_data_valid)
+ return 0;
+
+ return simple_read_from_buffer(to, count, ppos, &cs35l56_base->cal_data,
+ sizeof(cs35l56_base->cal_data));
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_cal_data_debugfs_read, "SND_SOC_CS35L56_SHARED");
+
+ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base,
+ const char __user *from, size_t count,
+ loff_t *ppos)
+{
+ struct cirrus_amp_cal_data cal_data;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS_COMMON))
+ return -ENXIO;
+
+ /* Only allow a full blob to be written */
+ if (*ppos || (count != sizeof(cal_data)))
+ return -EMSGSIZE;
+
+ ret = simple_write_to_buffer(&cal_data, sizeof(cal_data), ppos, from, count);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_stash_calibration(cs35l56_base, &cal_data);
+ if (ret)
+ return ret;
+
+ return count;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_cal_data_debugfs_write, "SND_SOC_CS35L56_SHARED");
+
+void cs35l56_create_cal_debugfs(struct cs35l56_base *cs35l56_base,
+ const struct cs35l56_cal_debugfs_fops *fops)
+{
+ if (!IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS_COMMON))
+ return;
+
+ cs35l56_base->debugfs = cs_amp_create_debugfs(cs35l56_base->dev);
+
+ debugfs_create_file("calibrate",
+ 0200, cs35l56_base->debugfs, cs35l56_base,
+ &fops->calibrate);
+ debugfs_create_file("cal_temperature",
+ 0200, cs35l56_base->debugfs, cs35l56_base,
+ &fops->cal_temperature);
+ debugfs_create_file("cal_data",
+ 0644, cs35l56_base->debugfs, cs35l56_base,
+ &fops->cal_data);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_create_cal_debugfs, "SND_SOC_CS35L56_SHARED");
+
+void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base)
+{
+ debugfs_remove_recursive(cs35l56_base->debugfs);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_remove_cal_debugfs, "SND_SOC_CS35L56_SHARED");
+
+const char * const cs35l56_cal_set_status_text[] = {
+ "Unknown", "Default", "Set",
+};
+EXPORT_SYMBOL_NS_GPL(cs35l56_cal_set_status_text, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct cs_dsp *dsp = cs35l56_base->dsp;
+ __be32 cal_set_status_be;
+ int alg_id;
+ int ret;
+
+ switch (cs35l56_base->type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ alg_id = 0x9f210;
+ break;
+ default:
+ alg_id = 0xbf210;
+ break;
+ }
+
+ scoped_guard(mutex, &dsp->pwr_lock) {
+ ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp,
+ "CAL_SET_STATUS",
+ WMFW_ADSP2_YM, alg_id),
+ 0, &cal_set_status_be,
+ sizeof(cal_set_status_be));
+ }
+ if (ret) {
+ uvalue->value.enumerated.item[0] = CS35L56_CAL_SET_STATUS_UNKNOWN;
+ return 0;
+ }
+
+ switch (be32_to_cpu(cal_set_status_be)) {
+ case CS35L56_CAL_SET_STATUS_DEFAULT:
+ case CS35L56_CAL_SET_STATUS_SET:
+ uvalue->value.enumerated.item[0] = be32_to_cpu(cal_set_status_be);
+ return 0;
+ default:
+ uvalue->value.enumerated.item[0] = CS35L56_CAL_SET_STATUS_UNKNOWN;
+ return 0;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_cal_set_status_get, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
+ bool *fw_missing, unsigned int *fw_version)
+{
+ unsigned int prot_status;
+ int ret;
+
+ ret = regmap_read(cs35l56_base->regmap,
+ cs35l56_base->fw_reg->prot_sts, &prot_status);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Get PROTECTION_STATUS failed: %d\n", ret);
+ return ret;
+ }
+
+ *fw_missing = !!(prot_status & CS35L56_FIRMWARE_MISSING);
+
+ ret = regmap_read(cs35l56_base->regmap,
+ cs35l56_base->fw_reg->fw_ver, fw_version);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Get FW VER failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, "SND_SOC_CS35L56_SHARED");
+
+void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base)
+{
+ unsigned int firmware_version;
+ bool firmware_missing;
+ int ret;
+
+ ret = cs35l56_read_prot_status(cs35l56_base, &firmware_missing, &firmware_version);
+ if (ret)
+ return;
+
+ if (!firmware_missing)
+ return;
+
+ dev_warn(cs35l56_base->dev, "FIRMWARE_MISSING\n");
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_warn_if_firmware_missing, "SND_SOC_CS35L56_SHARED");
+
+void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp)
+{
+ __be32 pid, sid, tid;
+ unsigned int alg_id;
+ int ret;
+
+ switch (cs35l56_base->type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ alg_id = 0x9f212;
+ break;
+ default:
+ alg_id = 0xbf212;
+ break;
+ }
+
+ scoped_guard(mutex, &cs_dsp->pwr_lock) {
+ ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(cs_dsp, "AS_PRJCT_ID",
+ WMFW_ADSP2_XM, alg_id),
+ 0, &pid, sizeof(pid));
+ if (!ret)
+ ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(cs_dsp, "AS_CHNNL_ID",
+ WMFW_ADSP2_XM, alg_id),
+ 0, &sid, sizeof(sid));
+ if (!ret)
+ ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(cs_dsp, "AS_SNPSHT_ID",
+ WMFW_ADSP2_XM, alg_id),
+ 0, &tid, sizeof(tid));
+ }
+
+ if (ret)
+ dev_warn(cs35l56_base->dev, "Can't read tuning IDs");
+ else
+ dev_info(cs35l56_base->dev, "Tuning PID: %#x, SID: %#x, TID: %#x\n",
+ be32_to_cpu(pid), be32_to_cpu(sid), be32_to_cpu(tid));
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_log_tuning, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
+{
+ int ret;
+ unsigned int devid, revid, otpid, secured, fw_ver;
+ bool fw_missing;
+
+ /*
+ * When the system is not using a reset_gpio ensure the device is
+ * awake, otherwise the device has just been released from reset and
+ * the driver must wait for the control port to become usable.
+ */
+ if (!cs35l56_base->reset_gpio)
+ cs35l56_issue_wake_event(cs35l56_base);
+ else
+ cs35l56_wait_control_port_ready();
+
+ ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_REVID, &revid);
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Get Revision ID failed\n");
+ return ret;
+ }
+ cs35l56_base->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
+ cs35l56_set_fw_reg_table(cs35l56_base);
+
+ ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
+ if (ret)
+ return ret;
+
+ ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_DEVID, &devid);
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Get Device ID failed\n");
+ return ret;
+ }
+ devid &= CS35L56_DEVID_MASK;
+
+ switch (devid) {
+ case 0x35A54:
+ case 0x35A56:
+ case 0x35A57:
+ cs35l56_base->calibration_controls = &cs35l56_calibration_controls;
+ break;
+ case 0x35A630:
+ cs35l56_base->calibration_controls = &cs35l63_calibration_controls;
+ devid = devid >> 4;
+ break;
+ default:
+ dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
+ return -ENODEV;
+ }
+
+ cs35l56_base->type = devid & 0xFF;
+
+ /* Silicon is now identified and booted so exit cache-only */
+ regcache_cache_only(cs35l56_base->regmap, false);
+
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "Get Secure status failed\n");
+ return ret;
+ }
+
+ /* When any bus is restricted treat the device as secured */
+ if (secured & CS35L56_RESTRICTED_MASK)
+ cs35l56_base->secured = true;
+
+ ret = regmap_read(cs35l56_base->regmap, CS35L56_OTPID, &otpid);
+ if (ret < 0) {
+ dev_err(cs35l56_base->dev, "Get OTP ID failed\n");
+ return ret;
+ }
+
+ ret = cs35l56_read_prot_status(cs35l56_base, &fw_missing, &fw_ver);
+ if (ret)
+ return ret;
+
+ dev_info(cs35l56_base->dev, "Cirrus Logic CS35L%02X%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n",
+ cs35l56_base->type, cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid,
+ fw_ver >> 16, (fw_ver >> 8) & 0xff, fw_ver & 0xff, !fw_missing);
+
+ /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
+ regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+ regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1,
+ CS35L56_AMP_SHORT_ERR_EINT1_MASK,
+ 0);
+ regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8,
+ CS35L56_TEMP_ERR_EINT1_MASK,
+ 0);
+
+ switch (cs35l56_base->type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ ret = cs35l56_read_silicon_uid(cs35l56_base);
+ break;
+ default:
+ ret = cs35l63_read_silicon_uid(cs35l56_base);
+ break;
+ }
+ if (ret)
+ return ret;
+
+ dev_dbg(cs35l56_base->dev, "SiliconID = %#llx\n", cs35l56_base->silicon_uid);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, "SND_SOC_CS35L56_SHARED");
+
+int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base)
+{
+ struct gpio_descs *descs;
+ u32 speaker_id;
+ int i, ret;
+
+ /* Check for vendor-specific speaker ID method */
+ ret = cs_amp_get_vendor_spkid(cs35l56_base->dev);
+ if (ret >= 0) {
+ dev_dbg(cs35l56_base->dev, "Vendor Speaker ID = %d\n", ret);
+ return ret;
+ } else if (ret != -ENOENT) {
+ dev_err(cs35l56_base->dev, "Error getting vendor Speaker ID: %d\n", ret);
+ return ret;
+ }
+
+ /* Attempt to read the speaker type from a device property */
+ ret = device_property_read_u32(cs35l56_base->dev, "cirrus,speaker-id", &speaker_id);
+ if (!ret) {
+ dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id);
+ return speaker_id;
+ }
+
+ /* Read the speaker type qualifier from the motherboard GPIOs */
+ descs = gpiod_get_array_optional(cs35l56_base->dev, "spk-id", GPIOD_IN);
+ if (!descs) {
+ return -ENOENT;
+ } else if (IS_ERR(descs)) {
+ ret = PTR_ERR(descs);
+ return dev_err_probe(cs35l56_base->dev, ret, "Failed to get spk-id-gpios\n");
+ }
+
+ speaker_id = 0;
+ for (i = 0; i < descs->ndescs; i++) {
+ ret = gpiod_get_value_cansleep(descs->desc[i]);
+ if (ret < 0) {
+ dev_err_probe(cs35l56_base->dev, ret, "Failed to read spk-id[%d]\n", i);
+ goto err;
+ }
+
+ speaker_id |= (ret << i);
+ }
+
+ dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id);
+ ret = speaker_id;
+err:
+ gpiod_put_array(descs);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, "SND_SOC_CS35L56_SHARED");
static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = {
[0x0C] = 128000,
@@ -256,7 +1599,7 @@ int cs35l56_get_bclk_freq_id(unsigned int freq)
return -EINVAL;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, "SND_SOC_CS35L56_SHARED");
static const char * const cs35l56_supplies[/* auto-sized */] = {
"VDD_P",
@@ -272,7 +1615,7 @@ void cs35l56_fill_supply_names(struct regulator_bulk_data *data)
for (i = 0; i < ARRAY_SIZE(cs35l56_supplies); i++)
data[i].supply = cs35l56_supplies[i];
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, "SND_SOC_CS35L56_SHARED");
const char * const cs35l56_tx_input_texts[] = {
"None", "ASP1RX1", "ASP1RX2", "VMON", "IMON", "ERRVOL", "CLASSH",
@@ -280,7 +1623,7 @@ const char * const cs35l56_tx_input_texts[] = {
"DSP1TX5", "DSP1TX6", "DSP1TX7", "DSP1TX8", "TEMPMON",
"INTERPOLATOR", "SDW1RX1", "SDW1RX2",
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, "SND_SOC_CS35L56_SHARED");
const unsigned int cs35l56_tx_input_values[] = {
CS35L56_INPUT_SRC_NONE,
@@ -305,9 +1648,9 @@ const unsigned int cs35l56_tx_input_values[] = {
CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL1,
CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL2,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, "SND_SOC_CS35L56_SHARED");
-struct regmap_config cs35l56_regmap_i2c = {
+const struct regmap_config cs35l56_regmap_i2c = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -319,11 +1662,11 @@ struct regmap_config cs35l56_regmap_i2c = {
.volatile_reg = cs35l56_volatile_reg,
.readable_reg = cs35l56_readable_reg,
.precious_reg = cs35l56_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, "SND_SOC_CS35L56_SHARED");
-struct regmap_config cs35l56_regmap_spi = {
+const struct regmap_config cs35l56_regmap_spi = {
.reg_bits = 32,
.val_bits = 32,
.pad_bits = 16,
@@ -336,11 +1679,11 @@ struct regmap_config cs35l56_regmap_spi = {
.volatile_reg = cs35l56_volatile_reg,
.readable_reg = cs35l56_readable_reg,
.precious_reg = cs35l56_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, "SND_SOC_CS35L56_SHARED");
-struct regmap_config cs35l56_regmap_sdw = {
+const struct regmap_config cs35l56_regmap_sdw = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -352,11 +1695,46 @@ struct regmap_config cs35l56_regmap_sdw = {
.volatile_reg = cs35l56_volatile_reg,
.readable_reg = cs35l56_readable_reg,
.precious_reg = cs35l56_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, "SND_SOC_CS35L56_SHARED");
+
+const struct regmap_config cs35l63_regmap_i2c = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .reg_base = 0x8000,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .max_register = CS35L56_DSP1_PMEM_5114,
+ .reg_defaults = cs35l63_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs35l63_reg_defaults),
+ .volatile_reg = cs35l63_volatile_reg,
+ .readable_reg = cs35l56_readable_reg,
+ .precious_reg = cs35l56_precious_reg,
+ .cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(cs35l63_regmap_i2c, "SND_SOC_CS35L56_SHARED");
+
+const struct regmap_config cs35l63_regmap_sdw = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .max_register = CS35L56_DSP1_PMEM_5114,
+ .reg_defaults = cs35l63_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs35l63_reg_defaults),
+ .volatile_reg = cs35l63_volatile_reg,
+ .readable_reg = cs35l56_readable_reg,
+ .precious_reg = cs35l56_precious_reg,
+ .cache_type = REGCACHE_MAPLE,
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l63_regmap_sdw, "SND_SOC_CS35L56_SHARED");
MODULE_DESCRIPTION("ASoC CS35L56 Shared");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
+MODULE_IMPORT_NS("FW_CS_DSP");
diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
index 996aab10500e..9bc9b7c98390 100644
--- a/sound/soc/codecs/cs35l56-spi.c
+++ b/sound/soc/codecs/cs35l56-spi.c
@@ -25,13 +25,20 @@ static int cs35l56_spi_probe(struct spi_device *spi)
return -ENOMEM;
spi_set_drvdata(spi, cs35l56);
- cs35l56->regmap = devm_regmap_init_spi(spi, regmap_config);
- if (IS_ERR(cs35l56->regmap)) {
- ret = PTR_ERR(cs35l56->regmap);
+
+ cs35l56->base.type = 0x56;
+
+ cs35l56->base.regmap = devm_regmap_init_spi(spi, regmap_config);
+ if (IS_ERR(cs35l56->base.regmap)) {
+ ret = PTR_ERR(cs35l56->base.regmap);
return dev_err_probe(&spi->dev, ret, "Failed to allocate register map\n");
}
- cs35l56->dev = &spi->dev;
+ 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)
@@ -39,7 +46,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)
ret = cs35l56_init(cs35l56);
if (ret == 0)
- ret = cs35l56_irq_request(cs35l56, spi->irq);
+ ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
if (ret < 0)
cs35l56_remove(cs35l56);
@@ -59,10 +66,19 @@ static const struct spi_device_id cs35l56_id_spi[] = {
};
MODULE_DEVICE_TABLE(spi, cs35l56_id_spi);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
+ { "CSC355C", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);
+#endif
+
static struct spi_driver cs35l56_spi_driver = {
.driver = {
.name = "cs35l56",
- .pm = &cs35l56_pm_ops_i2c_spi,
+ .pm = pm_ptr(&cs35l56_pm_ops_i2c_spi),
+ .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match),
},
.id_table = cs35l56_id_spi,
.probe = cs35l56_spi_probe,
@@ -72,8 +88,8 @@ static struct spi_driver cs35l56_spi_driver = {
module_spi_driver(cs35l56_spi_driver);
MODULE_DESCRIPTION("ASoC CS35L56 SPI driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE);
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 3c07bd1e959e..55b4d0d55712 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -6,9 +6,11 @@
// Cirrus Logic International Semiconductor Ltd.
#include <linux/acpi.h>
+#include <linux/array_size.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
@@ -16,12 +18,14 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/soundwire/sdw.h>
#include <linux/types.h>
#include <linux/workqueue.h>
+#include <sound/cs-amp-lib.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -34,23 +38,6 @@
static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
-static int cs35l56_mbox_send(struct cs35l56_private *cs35l56, unsigned int command)
-{
- unsigned int val;
- int ret;
-
- regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
- ret = regmap_read_poll_timeout(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
- val, (val == 0),
- CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
- if (ret) {
- dev_warn(cs35l56->dev, "MBOX command %#x failed: %d\n", command, ret);
- return ret;
- }
-
- return 0;
-}
-
static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56)
{
/* Wait for patching to complete */
@@ -79,19 +66,60 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol,
static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
+static SOC_ENUM_SINGLE_DECL(cs35l56_cal_set_status_enum, SND_SOC_NOPM, 0,
+ cs35l56_cal_set_status_text);
+
+static int cs35l56_cal_set_status_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+ return cs35l56_cal_set_status_get(&cs35l56->base, ucontrol);
+}
+
static const struct snd_kcontrol_new cs35l56_controls[] = {
SOC_SINGLE_EXT("Speaker Switch",
CS35L56_MAIN_RENDER_USER_MUTE, 0, 1, 1,
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
SOC_SINGLE_S_EXT_TLV("Speaker Volume",
CS35L56_MAIN_RENDER_USER_VOLUME,
- 6, -400, 400, 9, 0,
+ CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
+ CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
+ 0,
cs35l56_dspwait_get_volsw,
cs35l56_dspwait_put_volsw,
vol_tlv),
SOC_SINGLE_EXT("Posture Number", CS35L56_MAIN_POSTURE_NUMBER,
0, 255, 0,
cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
+ SOC_ENUM_EXT_ACC("CAL_SET_STATUS", cs35l56_cal_set_status_enum,
+ cs35l56_cal_set_status_ctl_get, NULL,
+ SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+};
+
+static const struct snd_kcontrol_new cs35l63_controls[] = {
+ SOC_SINGLE_EXT("Speaker Switch",
+ CS35L63_MAIN_RENDER_USER_MUTE, 0, 1, 1,
+ cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
+ SOC_SINGLE_S_EXT_TLV("Speaker Volume",
+ CS35L63_MAIN_RENDER_USER_VOLUME,
+ CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MIN,
+ CS35L56_MAIN_RENDER_USER_VOLUME_MAX,
+ CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT,
+ 0,
+ cs35l56_dspwait_get_volsw,
+ cs35l56_dspwait_put_volsw,
+ vol_tlv),
+ SOC_SINGLE_EXT("Posture Number", CS35L63_MAIN_POSTURE_NUMBER,
+ 0, 255, 0,
+ cs35l56_dspwait_get_volsw, cs35l56_dspwait_put_volsw),
+ SOC_ENUM_EXT_ACC("CAL_SET_STATUS", cs35l56_cal_set_status_enum,
+ cs35l56_cal_set_status_ctl_get, NULL,
+ SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
};
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
@@ -174,25 +202,25 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
unsigned int val;
int ret;
- dev_dbg(cs35l56->dev, "play: %d\n", event);
+ dev_dbg(cs35l56->base.dev, "play: %d\n", event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Don't wait for ACK, we check in POST_PMU that it completed */
- return regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+ return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
CS35L56_MBOX_CMD_AUDIO_PLAY);
case SND_SOC_DAPM_POST_PMU:
/* Wait for firmware to enter PS0 power state */
- ret = regmap_read_poll_timeout(cs35l56->regmap,
- CS35L56_TRANSDUCER_ACTUAL_PS,
+ ret = regmap_read_poll_timeout(cs35l56->base.regmap,
+ cs35l56->base.fw_reg->transducer_actual_ps,
val, (val == CS35L56_PS0),
CS35L56_PS0_POLL_US,
CS35L56_PS0_TIMEOUT_US);
if (ret)
- dev_err(cs35l56->dev, "PS0 wait failed: %d\n", ret);
+ dev_err(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
return ret;
case SND_SOC_DAPM_POST_PMD:
- return cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_PAUSE);
+ return cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
default:
return 0;
}
@@ -241,6 +269,8 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
SND_SOC_DAPM_SIGGEN("VDDBMON ADC"),
SND_SOC_DAPM_SIGGEN("VBSTMON ADC"),
SND_SOC_DAPM_SIGGEN("TEMPMON ADC"),
+
+ SND_SOC_DAPM_INPUT("Calibrate"),
};
#define CS35L56_SRC_ROUTE(name) \
@@ -277,6 +307,7 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = {
{ "DSP1", NULL, "ASP1RX1" },
{ "DSP1", NULL, "ASP1RX2" },
{ "DSP1", NULL, "SDW1 Playback" },
+ { "DSP1", NULL, "Calibrate" },
{ "AMP", NULL, "DSP1" },
{ "SPK", NULL, "AMP" },
@@ -310,109 +341,23 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
- dev_dbg(cs35l56->dev, "%s: %d\n", __func__, event);
+ dev_dbg(cs35l56->base.dev, "%s: %d\n", __func__, event);
return wm_adsp_event(w, kcontrol, event);
}
-irqreturn_t cs35l56_irq(int irq, void *data)
-{
- struct cs35l56_private *cs35l56 = data;
- unsigned int status1 = 0, status8 = 0, status20 = 0;
- unsigned int mask1, mask8, mask20;
- unsigned int val;
- int rv;
-
- irqreturn_t ret = IRQ_NONE;
-
- if (!cs35l56->init_done)
- return IRQ_NONE;
-
- mutex_lock(&cs35l56->irq_lock);
-
- rv = pm_runtime_resume_and_get(cs35l56->dev);
- if (rv < 0) {
- dev_err(cs35l56->dev, "irq: failed to get pm_runtime: %d\n", rv);
- goto err_unlock;
- }
-
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_STATUS, &val);
- if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
- dev_dbg(cs35l56->dev, "Spurious IRQ: no pending interrupt\n");
- goto err;
- }
-
- /* Ack interrupts */
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_1, &status1);
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_1, &mask1);
- status1 &= ~mask1;
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_1, status1);
-
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_8, &status8);
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_8, &mask8);
- status8 &= ~mask8;
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_8, status8);
-
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_20, &status20);
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_20, &mask20);
- status20 &= ~mask20;
- /* We don't want EINT20 but they default to unmasked: force mask */
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
-
- dev_dbg(cs35l56->dev, "%s: %#x %#x\n", __func__, status1, status8);
-
- /* Check to see if unmasked bits are active */
- if (!status1 && !status8 && !status20)
- goto err;
-
- if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
- dev_crit(cs35l56->dev, "Amp short error\n");
-
- if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
- dev_crit(cs35l56->dev, "Overtemp error\n");
-
- ret = IRQ_HANDLED;
-
-err:
- pm_runtime_put(cs35l56->dev);
-err_unlock:
- mutex_unlock(&cs35l56->irq_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE);
-
-int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq)
-{
- int ret;
-
- if (!irq)
- return 0;
-
- ret = devm_request_threaded_irq(cs35l56->dev, irq, NULL, cs35l56_irq,
- IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
- "cs35l56", cs35l56);
- if (!ret)
- cs35l56->irq = irq;
- else
- dev_err(cs35l56->dev, "Failed to get IRQ: %d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_CORE);
-
static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
unsigned int val;
- dev_dbg(cs35l56->dev, "%s: %#x\n", __func__, fmt);
+ dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- dev_err(cs35l56->dev, "Unsupported clock source mode\n");
+ dev_err(cs35l56->base.dev, "Unsupported clock source mode\n");
return -EINVAL;
}
@@ -426,7 +371,7 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
cs35l56->tdm_mode = false;
break;
default:
- dev_err(cs35l56->dev, "Unsupported DAI format\n");
+ dev_err(cs35l56->base.dev, "Unsupported DAI format\n");
return -EINVAL;
}
@@ -443,40 +388,29 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
case SND_SOC_DAIFMT_NB_NF:
break;
default:
- dev_err(cs35l56->dev, "Invalid clock invert\n");
+ dev_err(cs35l56->base.dev, "Invalid clock invert\n");
return -EINVAL;
}
- regmap_update_bits(cs35l56->regmap,
+ regmap_update_bits(cs35l56->base.regmap,
CS35L56_ASP1_CONTROL2,
CS35L56_ASP_FMT_MASK |
CS35L56_ASP_BCLK_INV_MASK | CS35L56_ASP_FSYNC_INV_MASK,
val);
/* Hi-Z DOUT in unused slots and when all TX are disabled */
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL3,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
CS35L56_ASP1_DOUT_HIZ_CTRL_MASK,
CS35L56_ASP_UNUSED_HIZ_OFF_HIZ);
return 0;
}
-static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
- unsigned int reg, unsigned long mask)
+static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask)
{
- unsigned int reg_val, channel_shift;
+ unsigned int channel_shift;
int bit_num;
- /* Init all slots to 63 */
- switch (reg) {
- case CS35L56_ASP1_FRAME_CONTROL1:
- reg_val = 0x3f3f3f3f;
- break;
- case CS35L56_ASP1_FRAME_CONTROL5:
- reg_val = 0x3f3f3f;
- break;
- }
-
/* Enable consecutive TX1..TXn for each of the slots set in mask */
channel_shift = 0;
for_each_set_bit(bit_num, &mask, 32) {
@@ -485,7 +419,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
channel_shift += 8;
}
- regmap_write(cs35l56->regmap, reg, reg_val);
+ return reg_val;
}
static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -494,20 +428,20 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
if ((slots == 0) || (slot_width == 0)) {
- dev_dbg(cs35l56->dev, "tdm config cleared\n");
+ dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
cs35l56->asp_slot_width = 0;
cs35l56->asp_slot_count = 0;
return 0;
}
if (slot_width > (CS35L56_ASP_RX_WIDTH_MASK >> CS35L56_ASP_RX_WIDTH_SHIFT)) {
- dev_err(cs35l56->dev, "tdm invalid slot width %d\n", slot_width);
+ dev_err(cs35l56->base.dev, "tdm invalid slot width %d\n", slot_width);
return -EINVAL;
}
/* More than 32 slots would give an unsupportable BCLK frequency */
if (slots > 32) {
- dev_err(cs35l56->dev, "tdm invalid slot count %d\n", slots);
+ dev_err(cs35l56->base.dev, "tdm invalid slot count %d\n", slots);
return -EINVAL;
}
@@ -521,10 +455,13 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
if (rx_mask == 0)
rx_mask = 0xf; // ASPTX1..TX4 in slots 0..3
- cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask);
- cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask);
+ /* Default unused slots to 63 */
+ regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1,
+ cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask));
+ regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5,
+ cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask));
- dev_dbg(cs35l56->dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
+ dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask);
return 0;
@@ -544,7 +481,8 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
else
asp_width = asp_wl;
- dev_dbg(cs35l56->dev, "%s: wl=%d, width=%d, rate=%d", __func__, asp_wl, asp_width, rate);
+ dev_dbg(cs35l56->base.dev, "%s: wl=%d, width=%d, rate=%d",
+ __func__, asp_wl, asp_width, rate);
if (!cs35l56->sysclk_set) {
unsigned int slots = cs35l56->asp_slot_count;
@@ -562,26 +500,26 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
bclk_freq = asp_width * slots * rate;
freq_id = cs35l56_get_bclk_freq_id(bclk_freq);
if (freq_id < 0) {
- dev_err(cs35l56->dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
+ dev_err(cs35l56->base.dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
return -EINVAL;
}
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
CS35L56_ASP_BCLK_FREQ_MASK,
freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
CS35L56_ASP_RX_WIDTH_MASK, asp_width <<
CS35L56_ASP_RX_WIDTH_SHIFT);
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL5,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL5,
CS35L56_ASP_RX_WL_MASK, asp_wl);
} else {
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
CS35L56_ASP_TX_WIDTH_MASK, asp_width <<
CS35L56_ASP_TX_WIDTH_SHIFT);
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL1,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL1,
CS35L56_ASP_TX_WL_MASK, asp_wl);
}
@@ -603,7 +541,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
if (freq_id < 0)
return freq_id;
- regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
+ regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
CS35L56_ASP_BCLK_FREQ_MASK,
freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
cs35l56->sysclk_set = true;
@@ -646,9 +584,9 @@ static int cs35l56_sdw_dai_hw_params(struct snd_pcm_substream *substream,
struct sdw_port_config pconfig;
int ret;
- dev_dbg(cs35l56->dev, "%s: rate %d\n", __func__, params_rate(params));
+ dev_dbg(cs35l56->base.dev, "%s: rate %d\n", __func__, params_rate(params));
- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return -ENODEV;
if (!sdw_stream)
@@ -704,9 +642,6 @@ static int cs35l56_sdw_dai_hw_free(struct snd_pcm_substream *substream,
static int cs35l56_sdw_dai_set_stream(struct snd_soc_dai *dai,
void *sdw_stream, int direction)
{
- if (!sdw_stream)
- return 0;
-
snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
return 0;
@@ -752,6 +687,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,
@@ -761,86 +702,75 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
},
.symmetric_rate = 1,
.ops = &cs35l56_sdw_dai_ops,
- }
+ },
};
-static int cs35l56_wait_for_firmware_boot(struct cs35l56_private *cs35l56)
+static int cs35l56_write_cal(struct cs35l56_private *cs35l56)
{
- unsigned int reg;
- unsigned int val;
int ret;
- if (cs35l56->rev < CS35L56_REVID_B0)
- reg = CS35L56_DSP1_HALO_STATE_A1;
- else
- reg = CS35L56_DSP1_HALO_STATE;
-
- ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
- val,
- (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
- CS35L56_HALO_STATE_POLL_US,
- CS35L56_HALO_STATE_TIMEOUT_US);
+ if (cs35l56->base.secured || !cs35l56->base.cal_data_valid)
+ return -ENODATA;
- if ((ret < 0) && (ret != -ETIMEDOUT)) {
- dev_err(cs35l56->dev, "Failed to read HALO_STATE: %d\n", ret);
+ ret = wm_adsp_run(&cs35l56->dsp);
+ if (ret)
return ret;
- }
- if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
- dev_err(cs35l56->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
- return -EIO;
- }
+ ret = cs_amp_write_cal_coeffs(&cs35l56->dsp.cs_dsp,
+ cs35l56->base.calibration_controls,
+ &cs35l56->base.cal_data);
- return 0;
-}
+ wm_adsp_stop(&cs35l56->dsp);
-static inline void cs35l56_wait_min_reset_pulse(void)
-{
- /* Satisfy minimum reset pulse width spec */
- usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
-}
+ if (ret == 0)
+ dev_info(cs35l56->base.dev, "Calibration applied\n");
-static const struct reg_sequence cs35l56_system_reset_seq[] = {
- REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
-};
+ return ret;
+}
-static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
+static int cs35l56_dsp_download_and_power_up(struct cs35l56_private *cs35l56,
+ bool load_firmware)
{
- cs35l56->soft_resetting = true;
+ int ret;
/*
- * Must enter cache-only first so there can't be any more register
- * accesses other than the controlled system reset sequence below.
+ * Abort the first load if it didn't find the suffixed bins and
+ * we have an alternate fallback suffix.
*/
- regcache_cache_only(cs35l56->regmap, true);
- regmap_multi_reg_write_bypassed(cs35l56->regmap,
- cs35l56_system_reset_seq,
- ARRAY_SIZE(cs35l56_system_reset_seq));
+ cs35l56->dsp.bin_mandatory = (load_firmware && cs35l56->fallback_fw_suffix);
+
+ ret = wm_adsp_power_up(&cs35l56->dsp, load_firmware);
+ if ((ret == -ENOENT) && cs35l56->dsp.bin_mandatory) {
+ cs35l56->dsp.fwf_suffix = cs35l56->fallback_fw_suffix;
+ cs35l56->fallback_fw_suffix = NULL;
+ cs35l56->dsp.bin_mandatory = false;
+ ret = wm_adsp_power_up(&cs35l56->dsp, load_firmware);
+ }
- /* On SoundWire the registers won't be accessible until it re-enumerates. */
- if (cs35l56->sdw_peripheral)
- return;
+ if (ret) {
+ dev_dbg(cs35l56->base.dev, "wm_adsp_power_up ret %d\n", ret);
+ return ret;
+ }
- usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
- regcache_cache_only(cs35l56->regmap, false);
+ return 0;
}
-static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
+static void cs35l56_reinit_patch(struct cs35l56_private *cs35l56)
{
int ret;
- /* Use wm_adsp to load and apply the firmware patch and coefficient files */
- ret = wm_adsp_power_up(&cs35l56->dsp);
+ ret = cs35l56_dsp_download_and_power_up(cs35l56, true);
if (ret)
- dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
- else
- cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT);
+ return;
+
+ cs35l56_write_cal(cs35l56);
+
+ /* Always REINIT after applying patch or coefficients */
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
}
-static void cs35l56_patch(struct cs35l56_private *cs35l56)
+static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing)
{
- unsigned int reg;
- unsigned int val;
int ret;
/*
@@ -857,35 +787,25 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
flush_work(&cs35l56->sdw_irq_work);
}
- ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_SHUTDOWN);
+ ret = cs35l56_firmware_shutdown(&cs35l56->base);
if (ret)
goto err;
- if (cs35l56->rev < CS35L56_REVID_B0)
- reg = CS35L56_DSP1_PM_CUR_STATE_A1;
- else
- reg = CS35L56_DSP1_PM_CUR_STATE;
-
- ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
- val, (val == CS35L56_HALO_STATE_SHUTDOWN),
- CS35L56_HALO_STATE_POLL_US,
- CS35L56_HALO_STATE_TIMEOUT_US);
- if (ret < 0)
- dev_err(cs35l56->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
- val, ret);
-
- /* Use wm_adsp to load and apply the firmware patch and coefficient files */
- ret = wm_adsp_power_up(&cs35l56->dsp);
- if (ret) {
- dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
+ /*
+ * Use wm_adsp to load and apply the firmware patch and coefficient files,
+ * but only if firmware is missing. If firmware is already patched just
+ * power-up wm_adsp without downloading firmware.
+ */
+ ret = cs35l56_dsp_download_and_power_up(cs35l56, firmware_missing);
+ if (ret)
goto err;
- }
- mutex_lock(&cs35l56->irq_lock);
+ mutex_lock(&cs35l56->base.irq_lock);
- init_completion(&cs35l56->init_completion);
+ reinit_completion(&cs35l56->init_completion);
- cs35l56_system_reset(cs35l56);
+ cs35l56->soft_resetting = true;
+ cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
if (cs35l56->sdw_peripheral) {
/*
@@ -895,18 +815,27 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
*/
if (!wait_for_completion_timeout(&cs35l56->init_completion,
msecs_to_jiffies(5000))) {
- dev_err(cs35l56->dev, "%s: init_completion timed out (SDW)\n", __func__);
+ dev_err(cs35l56->base.dev, "%s: init_completion timed out (SDW)\n",
+ __func__);
goto err_unlock;
}
} else if (cs35l56_init(cs35l56)) {
goto err_unlock;
}
- regmap_clear_bits(cs35l56->regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING);
- cs35l56->fw_patched = true;
+ /* Check if the firmware is still reported missing */
+ cs35l56_warn_if_firmware_missing(&cs35l56->base);
+
+ regmap_clear_bits(cs35l56->base.regmap,
+ cs35l56->base.fw_reg->prot_sts,
+ CS35L56_FIRMWARE_MISSING);
+ cs35l56->base.fw_patched = true;
+
+ if (cs35l56_write_cal(cs35l56) == 0)
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
err_unlock:
- mutex_unlock(&cs35l56->irq_lock);
+ mutex_unlock(&cs35l56->base.irq_lock);
err:
/* Re-enable SoundWire interrupts */
if (cs35l56->sdw_peripheral) {
@@ -921,262 +850,450 @@ static void cs35l56_dsp_work(struct work_struct *work)
struct cs35l56_private *cs35l56 = container_of(work,
struct cs35l56_private,
dsp_work);
+ unsigned int firmware_version;
+ bool firmware_missing;
+ int ret;
- if (!cs35l56->init_done)
+ if (!cs35l56->base.init_done)
return;
- pm_runtime_get_sync(cs35l56->dev);
+ pm_runtime_get_sync(cs35l56->base.dev);
+
+ ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &firmware_version);
+ if (ret)
+ goto err;
+
+ /* Populate fw file qualifier with the revision and security state */
+ kfree(cs35l56->dsp.fwf_name);
+ if (firmware_missing) {
+ cs35l56->dsp.fwf_name = kasprintf(GFP_KERNEL, "%02x-dsp1", cs35l56->base.rev);
+ } else {
+ /* Firmware files must match the running firmware version */
+ cs35l56->dsp.fwf_name = kasprintf(GFP_KERNEL,
+ "%02x%s-%06x-dsp1",
+ cs35l56->base.rev,
+ cs35l56->base.secured ? "-s" : "",
+ firmware_version);
+ }
+
+ if (!cs35l56->dsp.fwf_name)
+ goto err;
+
+ dev_dbg(cs35l56->base.dev, "DSP fwf name: '%s' system name: '%s'\n",
+ cs35l56->dsp.fwf_name, cs35l56->dsp.system_name);
/*
- * When the device is running in secure mode the firmware files can
- * only contain insecure tunings and therefore we do not need to
- * shutdown the firmware to apply them and can use the lower cost
- * reinit sequence instead.
+ * The firmware cannot be patched if it is already running from
+ * patch RAM. In this case the firmware files are versioned to
+ * match the running firmware version and will only contain
+ * tunings. We do not need to shutdown the firmware to apply
+ * tunings so can use the lower cost reinit sequence instead.
*/
- if (cs35l56->secured)
- cs35l56_secure_patch(cs35l56);
+ if (!firmware_missing)
+ cs35l56_reinit_patch(cs35l56);
else
- cs35l56_patch(cs35l56);
+ cs35l56_patch(cs35l56, firmware_missing);
- pm_runtime_mark_last_busy(cs35l56->dev);
- pm_runtime_put_autosuspend(cs35l56->dev);
+ cs35l56_log_tuning(&cs35l56->base, &cs35l56->dsp.cs_dsp);
+err:
+ pm_runtime_put_autosuspend(cs35l56->base.dev);
}
-static int cs35l56_component_probe(struct snd_soc_component *component)
+static struct snd_soc_dapm_context *cs35l56_power_up_for_cal(struct cs35l56_private *cs35l56)
{
- struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
- struct dentry *debugfs_root = component->debugfs_root;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cs35l56->component);
+ int ret;
- BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values));
+ ret = snd_soc_dapm_enable_pin(dapm, "Calibrate");
+ if (ret)
+ return ERR_PTR(ret);
- if (!wait_for_completion_timeout(&cs35l56->init_completion,
- msecs_to_jiffies(5000))) {
- dev_err(cs35l56->dev, "%s: init_completion timed out\n", __func__);
- return -ENODEV;
- }
+ snd_soc_dapm_sync(dapm);
- cs35l56->component = component;
- wm_adsp2_component_probe(&cs35l56->dsp, component);
+ return dapm;
+}
+
+static void cs35l56_power_down_after_cal(struct cs35l56_private *cs35l56)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cs35l56->component);
- debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->init_done);
- debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->can_hibernate);
- debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->fw_patched);
+ snd_soc_dapm_disable_pin(dapm, "Calibrate");
+ snd_soc_dapm_sync(dapm);
+}
- queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
+static ssize_t cs35l56_debugfs_calibrate_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
+{
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ struct snd_soc_dapm_context *dapm;
+ ssize_t ret;
- return 0;
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = cs35l56_calibrate_debugfs_write(&cs35l56->base, from, count, ppos);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
}
-static void cs35l56_component_remove(struct snd_soc_component *component)
+static ssize_t cs35l56_debugfs_cal_temperature_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
{
- struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ struct snd_soc_dapm_context *dapm;
+ ssize_t ret;
- cancel_work_sync(&cs35l56->dsp_work);
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
+
+ ret = cs35l56_cal_ambient_debugfs_write(&cs35l56->base, from, count, ppos);
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
}
-static int cs35l56_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
+static ssize_t cs35l56_debugfs_cal_data_read(struct file *file,
+ char __user *to,
+ size_t count, loff_t *ppos)
{
- struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
+ struct snd_soc_dapm_context *dapm;
+ ssize_t ret;
- switch (level) {
- case SND_SOC_BIAS_STANDBY:
- /*
- * Wait for patching to complete when transitioning from
- * BIAS_OFF to BIAS_STANDBY
- */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
- cs35l56_wait_dsp_ready(cs35l56);
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
- break;
- default:
- break;
- }
+ ret = cs35l56_cal_data_debugfs_read(&cs35l56->base, to, count, ppos);
+ cs35l56_power_down_after_cal(cs35l56);
- return 0;
+ return ret;
}
-static const struct snd_soc_component_driver soc_component_dev_cs35l56 = {
- .probe = cs35l56_component_probe,
- .remove = cs35l56_component_remove,
+static int cs35l56_new_cal_data_apply(struct cs35l56_private *cs35l56)
+{
+ struct snd_soc_dapm_context *dapm;
+ int ret;
- .dapm_widgets = cs35l56_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(cs35l56_dapm_widgets),
- .dapm_routes = cs35l56_audio_map,
- .num_dapm_routes = ARRAY_SIZE(cs35l56_audio_map),
- .controls = cs35l56_controls,
- .num_controls = ARRAY_SIZE(cs35l56_controls),
+ if (!cs35l56->base.cal_data_valid)
+ return -ENXIO;
- .set_bias_level = cs35l56_set_bias_level,
+ if (cs35l56->base.secured)
+ return -EACCES;
- .suspend_bias_off = 1, /* see cs35l56_system_resume() */
-};
+ dapm = cs35l56_power_up_for_cal(cs35l56);
+ if (IS_ERR(dapm))
+ return PTR_ERR(dapm);
-static const struct reg_sequence cs35l56_hibernate_seq[] = {
- /* This must be the last register access */
- REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW),
-};
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = cs_amp_write_cal_coeffs(&cs35l56->dsp.cs_dsp,
+ cs35l56->base.calibration_controls,
+ &cs35l56->base.cal_data);
+ if (ret == 0)
+ cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
+ else
+ ret = -EIO;
-static const struct reg_sequence cs35l56_hibernate_wake_seq[] = {
- REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP),
-};
+ snd_soc_dapm_mutex_unlock(dapm);
+ cs35l56_power_down_after_cal(cs35l56);
+
+ return ret;
+}
-int cs35l56_runtime_suspend(struct device *dev)
+static ssize_t cs35l56_debugfs_cal_data_write(struct file *file,
+ const char __user *from,
+ size_t count, loff_t *ppos)
{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
- unsigned int val;
+ struct cs35l56_base *cs35l56_base = file->private_data;
+ struct cs35l56_private *cs35l56 = cs35l56_private_from_base(cs35l56_base);
int ret;
- if (!cs35l56->init_done)
- return 0;
+ ret = cs35l56_cal_data_debugfs_write(&cs35l56->base, from, count, ppos);
+ if (ret == -ENODATA)
+ return count; /* Ignore writes of empty cal blobs */
+ else if (ret < 0)
+ return -EIO;
- /* Firmware must have entered a power-save state */
- ret = regmap_read_poll_timeout(cs35l56->regmap,
- CS35L56_TRANSDUCER_ACTUAL_PS,
- val, (val >= CS35L56_PS3),
- CS35L56_PS3_POLL_US,
- CS35L56_PS3_TIMEOUT_US);
+ ret = cs35l56_new_cal_data_apply(cs35l56);
if (ret)
- dev_warn(cs35l56->dev, "PS3 wait failed: %d\n", ret);
+ return ret;
- /* Clear BOOT_DONE so it can be used to detect a reboot */
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
+ return count;
+}
- if (!cs35l56->can_hibernate) {
- regcache_cache_only(cs35l56->regmap, true);
- dev_dbg(dev, "Suspended: no hibernate");
+static const struct cs35l56_cal_debugfs_fops cs35l56_cal_debugfs_fops = {
+ .calibrate = {
+ .write = cs35l56_debugfs_calibrate_write,
+ },
+ .cal_temperature = {
+ .write = cs35l56_debugfs_cal_temperature_write,
+ },
+ .cal_data = {
+ .read = cs35l56_debugfs_cal_data_read,
+ .write = cs35l56_debugfs_cal_data_write,
+ },
+};
- return 0;
- }
+static int cs35l56_cal_data_rb_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
- /*
- * Enable auto-hibernate. If it is woken by some other wake source
- * it will automatically return to hibernate.
- */
- cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
+ if (!cs35l56->base.cal_data_valid)
+ return -ENODATA;
+
+ memcpy(ucontrol->value.bytes.data, &cs35l56->base.cal_data,
+ sizeof(cs35l56->base.cal_data));
+
+ return 0;
+}
+
+static int cs35l56_cal_data_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
/*
- * Must enter cache-only first so there can't be any more register
- * accesses other than the controlled hibernate sequence below.
+ * This control is write-only but mixer libraries often try to read
+ * a control before writing it. So we have to implement read.
+ * Return zeros so a write of valid data will always be a change
+ * from its "current value".
*/
- regcache_cache_only(cs35l56->regmap, true);
+ memset(ucontrol->value.bytes.data, 0, sizeof(cs35l56->base.cal_data));
- regmap_multi_reg_write_bypassed(cs35l56->regmap,
- cs35l56_hibernate_seq,
- ARRAY_SIZE(cs35l56_hibernate_seq));
+ return 0;
+}
- dev_dbg(dev, "Suspended: hibernate");
+static int cs35l56_cal_data_ctl_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ const struct cirrus_amp_cal_data *cal_data = (const void *)ucontrol->value.bytes.data;
+ int ret;
- return 0;
+ if (cs35l56->base.cal_data_valid)
+ return -EACCES;
+
+ ret = cs35l56_stash_calibration(&cs35l56->base, cal_data);
+ if (ret)
+ return ret;
+
+ ret = cs35l56_new_cal_data_apply(cs35l56);
+ if (ret < 0)
+ return ret;
+
+ return 1;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend, SND_SOC_CS35L56_CORE);
-static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev)
+static const struct snd_kcontrol_new cs35l56_cal_data_restore_controls[] = {
+ SND_SOC_BYTES_E("CAL_DATA", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32),
+ cs35l56_cal_data_ctl_get, cs35l56_cal_data_ctl_set),
+ SND_SOC_BYTES_E_ACC("CAL_DATA_RB", 0, sizeof(struct cirrus_amp_cal_data) / sizeof(u32),
+ cs35l56_cal_data_rb_ctl_get, NULL,
+ SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+};
+
+static int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56)
{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
+ if (cs35l56->dsp.fwf_suffix)
+ return 0;
- if (!cs35l56->init_done)
+ if (!cs35l56->sdw_peripheral)
return 0;
- return cs35l56_runtime_resume_common(cs35l56);
+ cs35l56->dsp.fwf_suffix = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL,
+ "l%uu%u",
+ cs35l56->sdw_link_num,
+ cs35l56->sdw_unique_id);
+ if (!cs35l56->dsp.fwf_suffix)
+ return -ENOMEM;
+
+ /*
+ * There are published firmware files for L56 B0 silicon using
+ * the ALSA prefix as the filename suffix. Default to trying these
+ * first, with the new name as an alternate.
+ */
+ if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev == 0xb0)) {
+ cs35l56->fallback_fw_suffix = cs35l56->dsp.fwf_suffix;
+ cs35l56->dsp.fwf_suffix = cs35l56->component->name_prefix;
+ }
+
+ return 0;
}
-int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
+static int cs35l56_component_probe(struct snd_soc_component *component)
{
- unsigned int val;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct dentry *debugfs_root = component->debugfs_root;
+ unsigned short vendor, device;
int ret;
- if (!cs35l56->can_hibernate)
- goto out_sync;
+ BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values));
- if (!cs35l56->sdw_peripheral) {
- /*
- * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C.
- * Must be done before releasing cache-only.
- */
- regmap_multi_reg_write_bypassed(cs35l56->regmap,
- cs35l56_hibernate_wake_seq,
- ARRAY_SIZE(cs35l56_hibernate_wake_seq));
+ if (!cs35l56->dsp.system_name &&
+ (snd_soc_card_get_pci_ssid(component->card, &vendor, &device) == 0)) {
+ /* Append a speaker qualifier if there is a speaker ID */
+ if (cs35l56->speaker_id >= 0) {
+ cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
+ GFP_KERNEL,
+ "%04x%04x-spkid%d",
+ vendor, device,
+ cs35l56->speaker_id);
+ } else {
+ cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
+ GFP_KERNEL,
+ "%04x%04x",
+ vendor, device);
+ }
+ if (!cs35l56->dsp.system_name)
+ return -ENOMEM;
+ }
- usleep_range(CS35L56_CONTROL_PORT_READY_US,
- CS35L56_CONTROL_PORT_READY_US + 400);
+ if (!wait_for_completion_timeout(&cs35l56->init_completion,
+ msecs_to_jiffies(5000))) {
+ dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__);
+ return -ENODEV;
}
-out_sync:
- regcache_cache_only(cs35l56->regmap, false);
+ cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type);
+ if (!cs35l56->dsp.part)
+ return -ENOMEM;
- ret = cs35l56_wait_for_firmware_boot(cs35l56);
- if (ret) {
- dev_err(cs35l56->dev, "Hibernate wake failed: %d\n", ret);
- goto err;
+ cs35l56->component = component;
+ ret = cs35l56_set_fw_suffix(cs35l56);
+ if (ret)
+ return ret;
+
+ wm_adsp2_component_probe(&cs35l56->dsp, component);
+
+ debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done);
+ debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
+ debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
+
+
+ switch (cs35l56->base.type) {
+ case 0x54:
+ case 0x56:
+ case 0x57:
+ ret = snd_soc_add_component_controls(component, cs35l56_controls,
+ ARRAY_SIZE(cs35l56_controls));
+ break;
+ case 0x63:
+ ret = snd_soc_add_component_controls(component, cs35l63_controls,
+ ARRAY_SIZE(cs35l63_controls));
+ break;
+ default:
+ ret = -ENODEV;
+ break;
+ }
+
+ if (!ret && IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_SET_CTRL)) {
+ ret = snd_soc_add_component_controls(component,
+ cs35l56_cal_data_restore_controls,
+ ARRAY_SIZE(cs35l56_cal_data_restore_controls));
}
- ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
if (ret)
- goto err;
+ return dev_err_probe(cs35l56->base.dev, ret, "unable to add controls\n");
- /* BOOT_DONE will be 1 if the amp reset */
- regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_4, &val);
- if (val & CS35L56_OTP_BOOT_DONE_MASK) {
- dev_dbg(cs35l56->dev, "Registers reset in suspend\n");
- regcache_mark_dirty(cs35l56->regmap);
- }
+ ret = snd_soc_dapm_disable_pin(dapm, "Calibrate");
+ if (ret)
+ return ret;
- regcache_sync(cs35l56->regmap);
+ if (IS_ENABLED(CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS))
+ cs35l56_create_cal_debugfs(&cs35l56->base, &cs35l56_cal_debugfs_fops);
- dev_dbg(cs35l56->dev, "Resumed");
+ queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
return 0;
+}
-err:
- regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
- CS35L56_MBOX_CMD_HIBERNATE_NOW);
+static void cs35l56_component_remove(struct snd_soc_component *component)
+{
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
- regcache_cache_only(cs35l56->regmap, true);
+ cancel_work_sync(&cs35l56->dsp_work);
- return ret;
+ cs35l56_remove_cal_debugfs(&cs35l56->base);
+
+ if (cs35l56->dsp.cs_dsp.booted)
+ wm_adsp_power_down(&cs35l56->dsp);
+
+ wm_adsp2_component_remove(&cs35l56->dsp, component);
+
+ kfree(cs35l56->dsp.part);
+ cs35l56->dsp.part = NULL;
+
+ kfree(cs35l56->dsp.fwf_name);
+ cs35l56->dsp.fwf_name = NULL;
+
+ cs35l56->component = NULL;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE);
-static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56)
+static int cs35l56_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
{
- unsigned int val;
- int ret;
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ /*
+ * Wait for patching to complete when transitioning from
+ * BIAS_OFF to BIAS_STANDBY
+ */
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
+ cs35l56_wait_dsp_ready(cs35l56);
- /* Nothing to re-patch if we haven't done any patching yet. */
- if (!cs35l56->fw_patched)
- return false;
+ break;
+ default:
+ break;
+ }
- /*
- * If we have control of RESET we will have asserted it so the firmware
- * will need re-patching.
- */
- if (cs35l56->reset_gpio)
- return true;
+ return 0;
+}
- /*
- * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
- * can't be used here to test for memory retention.
- * Assume that tuning must be re-loaded.
- */
- if (cs35l56->secured)
- return true;
+static const struct snd_soc_component_driver soc_component_dev_cs35l56 = {
+ .probe = cs35l56_component_probe,
+ .remove = cs35l56_component_remove,
- ret = pm_runtime_resume_and_get(cs35l56->dev);
- if (ret) {
- dev_err(cs35l56->dev, "Failed to runtime_get: %d\n", ret);
- return ret;
- }
+ .dapm_widgets = cs35l56_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs35l56_dapm_widgets),
+ .dapm_routes = cs35l56_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs35l56_audio_map),
- ret = regmap_read(cs35l56->regmap, CS35L56_PROTECTION_STATUS, &val);
- if (ret)
- dev_err(cs35l56->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
- else
- ret = !!(val & CS35L56_FIRMWARE_MISSING);
+ .set_bias_level = cs35l56_set_bias_level,
- pm_runtime_put_autosuspend(cs35l56->dev);
+ .suspend_bias_off = 1, /* see cs35l56_system_resume() */
+};
- return ret;
+static int __maybe_unused cs35l56_runtime_suspend_i2c_spi(struct device *dev)
+{
+ struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
+
+ return cs35l56_runtime_suspend_common(&cs35l56->base);
+}
+
+static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev)
+{
+ struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
+
+ return cs35l56_runtime_resume_common(&cs35l56->base, false);
}
int cs35l56_system_suspend(struct device *dev)
@@ -1194,8 +1311,8 @@ int cs35l56_system_suspend(struct device *dev)
* clear it. Prevent this race by temporarily disabling the parent irq
* until we reach _no_irq.
*/
- if (cs35l56->irq)
- disable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);
return pm_runtime_force_suspend(dev);
}
@@ -1212,8 +1329,8 @@ int cs35l56_system_suspend_late(struct device *dev)
* RESET is usually shared by all amps so it must not be asserted until
* all driver instances have done their suspend() stage.
*/
- if (cs35l56->reset_gpio) {
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ if (cs35l56->base.reset_gpio) {
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
cs35l56_wait_min_reset_pulse();
}
@@ -1230,8 +1347,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev)
dev_dbg(dev, "system_suspend_no_irq\n");
/* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
- if (cs35l56->irq)
- enable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ enable_irq(cs35l56->base.irq);
return 0;
}
@@ -1250,8 +1367,8 @@ int cs35l56_system_resume_no_irq(struct device *dev)
* clear it, until it has fully resumed. Prevent this race by temporarily
* disabling the parent irq until we complete resume().
*/
- if (cs35l56->irq)
- disable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);
return 0;
}
@@ -1265,8 +1382,8 @@ int cs35l56_system_resume_early(struct device *dev)
dev_dbg(dev, "system_resume_early\n");
/* Ensure a spec-compliant RESET pulse. */
- if (cs35l56->reset_gpio) {
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ if (cs35l56->base.reset_gpio) {
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
cs35l56_wait_min_reset_pulse();
}
@@ -1278,7 +1395,7 @@ int cs35l56_system_resume_early(struct device *dev)
}
/* Release shared RESET before drivers start resume(). */
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
return 0;
}
@@ -1291,10 +1408,16 @@ int cs35l56_system_resume(struct device *dev)
dev_dbg(dev, "system_resume\n");
+ /*
+ * We might have done a hard reset or the CS35L56 was power-cycled
+ * so wait for control port to be ready.
+ */
+ cs35l56_wait_control_port_ready();
+
/* Undo pm_runtime_force_suspend() before re-enabling the irq */
ret = pm_runtime_force_resume(dev);
- if (cs35l56->irq)
- enable_irq(cs35l56->irq);
+ if (cs35l56->base.irq)
+ enable_irq(cs35l56->base.irq);
if (ret)
return ret;
@@ -1303,12 +1426,13 @@ int cs35l56_system_resume(struct device *dev)
if (!cs35l56->component)
return 0;
- ret = cs35l56_is_fw_reload_needed(cs35l56);
- dev_dbg(cs35l56->dev, "fw_reload_needed: %d\n", ret);
+ ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
+ dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
if (ret < 1)
return ret;
- cs35l56->fw_patched = false;
+ cs35l56->base.fw_patched = false;
+ wm_adsp_power_down(&cs35l56->dsp);
queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
/*
@@ -1320,6 +1444,11 @@ int cs35l56_system_resume(struct device *dev)
}
EXPORT_SYMBOL_GPL(cs35l56_system_resume);
+static int cs35l56_control_add_nop(struct wm_adsp *dsp, struct cs_dsp_coeff_ctl *cs_ctl)
+{
+ return 0;
+}
+
static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
{
struct wm_adsp *dsp;
@@ -1332,126 +1461,240 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work);
dsp = &cs35l56->dsp;
- dsp->part = "cs35l56";
- dsp->cs_dsp.num = 1;
- dsp->cs_dsp.type = WMFW_HALO;
- dsp->cs_dsp.rev = 0;
+ cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
+
+ /*
+ * dsp->part is filled in later as it is based on the DEVID. In a
+ * SoundWire system that cannot be read until enumeration has occurred
+ * and the device has attached.
+ */
dsp->fw = 12;
- dsp->cs_dsp.dev = cs35l56->dev;
- dsp->cs_dsp.regmap = cs35l56->regmap;
- dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE;
- dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID;
- dsp->cs_dsp.mem = cs35l56_dsp1_regions;
- dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l56_dsp1_regions);
- dsp->cs_dsp.no_core_startstop = true;
dsp->wmfw_optional = true;
- dev_dbg(cs35l56->dev, "DSP system name: '%s'\n", dsp->system_name);
+ /*
+ * None of the firmware controls need to be exported so add a no-op
+ * callback that suppresses creating an ALSA control.
+ */
+ dsp->control_add = &cs35l56_control_add_nop;
+
+ dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name);
ret = wm_halo_init(dsp);
if (ret != 0) {
- dev_err(cs35l56->dev, "wm_halo_init failed\n");
+ dev_err(cs35l56->base.dev, "wm_halo_init failed\n");
return ret;
}
return 0;
}
-static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56)
+static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
{
- acpi_handle handle = ACPI_HANDLE(cs35l56->dev);
- const char *sub;
+ struct device *dev = cs35l56->base.dev;
+ const char *prop;
+ int ret;
- /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
- if (!handle)
+ ret = device_property_read_string(dev, "cirrus,firmware-uid", &prop);
+ /* If bad sw node property, return 0 and fallback to legacy firmware path */
+ if (ret < 0)
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
- return PTR_ERR(sub);
- }
+ /* Append a speaker qualifier if there is a speaker ID */
+ if (cs35l56->speaker_id >= 0)
+ cs35l56->dsp.system_name = devm_kasprintf(dev, GFP_KERNEL, "%s-spkid%d",
+ prop, cs35l56->speaker_id);
+ else
+ cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
- cs35l56->dsp.system_name = sub;
- dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name);
+ if (cs35l56->dsp.system_name == NULL)
+ return -ENOMEM;
+
+ dev_dbg(dev, "Firmware UID: %s\n", cs35l56->dsp.system_name);
return 0;
}
+/*
+ * Some SoundWire laptops have a spk-id-gpios property but it points to
+ * the wrong ACPI Device node so can't be used to get the GPIO. Try to
+ * find the SDCA node containing the GpioIo resource and add a GPIO
+ * mapping to it.
+ */
+static const struct acpi_gpio_params cs35l56_af01_first_gpio = { 0, 0, false };
+static const struct acpi_gpio_mapping cs35l56_af01_spkid_gpios_mapping[] = {
+ { "spk-id-gpios", &cs35l56_af01_first_gpio, 1 },
+ { }
+};
+
+static void cs35l56_acpi_dev_release_driver_gpios(void *adev)
+{
+ acpi_dev_remove_driver_gpios(adev);
+}
+
+static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l56)
+{
+ struct fwnode_handle *af01_fwnode;
+ const union acpi_object *obj;
+ struct gpio_desc *desc;
+ int ret;
+
+ /* Find the SDCA node containing the GpioIo */
+ af01_fwnode = device_get_named_child_node(cs35l56->base.dev, "AF01");
+ if (!af01_fwnode) {
+ dev_dbg(cs35l56->base.dev, "No AF01 node\n");
+ return -ENOENT;
+ }
+
+ ret = acpi_dev_get_property(ACPI_COMPANION(cs35l56->base.dev),
+ "spk-id-gpios", ACPI_TYPE_PACKAGE, &obj);
+ if (ret) {
+ dev_dbg(cs35l56->base.dev, "Could not get spk-id-gpios package: %d\n", ret);
+ fwnode_handle_put(af01_fwnode);
+ return -ENOENT;
+ }
+
+ /* The broken properties we can handle are a 4-element package (one GPIO) */
+ if (obj->package.count != 4) {
+ dev_warn(cs35l56->base.dev, "Unexpected spk-id element count %d\n",
+ obj->package.count);
+ fwnode_handle_put(af01_fwnode);
+ return -ENOENT;
+ }
+
+ /* Add a GPIO mapping if it doesn't already have one */
+ if (!fwnode_property_present(af01_fwnode, "spk-id-gpios")) {
+ struct acpi_device *adev = to_acpi_device_node(af01_fwnode);
+
+ /*
+ * Can't use devm_acpi_dev_add_driver_gpios() because the
+ * mapping isn't being added to the node pointed to by
+ * ACPI_COMPANION().
+ */
+ ret = acpi_dev_add_driver_gpios(adev, cs35l56_af01_spkid_gpios_mapping);
+ if (ret) {
+ fwnode_handle_put(af01_fwnode);
+ return dev_err_probe(cs35l56->base.dev, ret,
+ "Failed to add gpio mapping to AF01\n");
+ }
+
+ ret = devm_add_action_or_reset(cs35l56->base.dev,
+ cs35l56_acpi_dev_release_driver_gpios,
+ adev);
+ if (ret) {
+ fwnode_handle_put(af01_fwnode);
+ return ret;
+ }
+
+ dev_dbg(cs35l56->base.dev, "Added spk-id-gpios mapping to AF01\n");
+ }
+
+ desc = fwnode_gpiod_get_index(af01_fwnode, "spk-id", 0, GPIOD_IN, NULL);
+ if (IS_ERR(desc)) {
+ fwnode_handle_put(af01_fwnode);
+ ret = PTR_ERR(desc);
+ return dev_err_probe(cs35l56->base.dev, ret, "Get GPIO from AF01 failed\n");
+ }
+
+ ret = gpiod_get_value_cansleep(desc);
+ gpiod_put(desc);
+
+ if (ret < 0) {
+ fwnode_handle_put(af01_fwnode);
+ dev_err_probe(cs35l56->base.dev, ret, "Error reading spk-id GPIO\n");
+ return ret;
+ }
+
+ fwnode_handle_put(af01_fwnode);
+
+ dev_info(cs35l56->base.dev, "Got spk-id from AF01\n");
+
+ return ret;
+}
+
int cs35l56_common_probe(struct cs35l56_private *cs35l56)
{
int ret;
init_completion(&cs35l56->init_completion);
- mutex_init(&cs35l56->irq_lock);
+ mutex_init(&cs35l56->base.irq_lock);
+ cs35l56->base.cal_index = -1;
+ cs35l56->speaker_id = -ENOENT;
- dev_set_drvdata(cs35l56->dev, cs35l56);
+ dev_set_drvdata(cs35l56->base.dev, cs35l56);
cs35l56_fill_supply_names(cs35l56->supplies);
- ret = devm_regulator_bulk_get(cs35l56->dev, ARRAY_SIZE(cs35l56->supplies),
+ ret = devm_regulator_bulk_get(cs35l56->base.dev, ARRAY_SIZE(cs35l56->supplies),
cs35l56->supplies);
if (ret != 0)
- return dev_err_probe(cs35l56->dev, ret, "Failed to request supplies\n");
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to request supplies\n");
/* Reset could be controlled by the BIOS or shared by multiple amps */
- cs35l56->reset_gpio = devm_gpiod_get_optional(cs35l56->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(cs35l56->reset_gpio)) {
- ret = PTR_ERR(cs35l56->reset_gpio);
+ cs35l56->base.reset_gpio = devm_gpiod_get_optional(cs35l56->base.dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cs35l56->base.reset_gpio)) {
+ ret = PTR_ERR(cs35l56->base.reset_gpio);
/*
* If RESET is shared the first amp to probe will grab the reset
* line and reset all the amps
*/
if (ret != -EBUSY)
- return dev_err_probe(cs35l56->dev, ret, "Failed to get reset GPIO\n");
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
- dev_info(cs35l56->dev, "Reset GPIO busy, assume shared reset\n");
- cs35l56->reset_gpio = NULL;
+ dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
+ cs35l56->base.reset_gpio = NULL;
}
ret = regulator_bulk_enable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
if (ret != 0)
- return dev_err_probe(cs35l56->dev, ret, "Failed to enable supplies\n");
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n");
- if (cs35l56->reset_gpio) {
+ if (cs35l56->base.reset_gpio) {
+ /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
cs35l56_wait_min_reset_pulse();
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
}
- ret = cs35l56_acpi_get_name(cs35l56);
+ ret = cs35l56_get_speaker_id(&cs35l56->base);
+ if (ACPI_COMPANION(cs35l56->base.dev) && cs35l56->sdw_peripheral && (ret == -ENOENT))
+ ret = cs35l56_try_get_broken_sdca_spkid_gpio(cs35l56);
+
+ if ((ret < 0) && (ret != -ENOENT))
+ goto err;
+
+ cs35l56->speaker_id = ret;
+
+ ret = cs35l56_get_firmware_uid(cs35l56);
if (ret != 0)
goto err;
ret = cs35l56_dsp_init(cs35l56);
if (ret < 0) {
- dev_err_probe(cs35l56->dev, ret, "DSP init failed\n");
+ dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n");
goto err;
}
- ret = devm_snd_soc_register_component(cs35l56->dev,
+ ret = devm_snd_soc_register_component(cs35l56->base.dev,
&soc_component_dev_cs35l56,
cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
- dev_err_probe(cs35l56->dev, ret, "Register codec failed\n");
+ dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
goto err;
}
return 0;
err:
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE);
+EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, "SND_SOC_CS35L56_CORE");
int cs35l56_init(struct cs35l56_private *cs35l56)
{
int ret;
- unsigned int devid, revid, otpid, secured;
/*
* Check whether the actions associated with soft reset or one time
@@ -1460,96 +1703,33 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
if (cs35l56->soft_resetting)
goto post_soft_reset;
- if (cs35l56->init_done)
+ if (cs35l56->base.init_done)
return 0;
- pm_runtime_set_autosuspend_delay(cs35l56->dev, 100);
- pm_runtime_use_autosuspend(cs35l56->dev);
- pm_runtime_set_active(cs35l56->dev);
- pm_runtime_enable(cs35l56->dev);
+ pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 100);
+ pm_runtime_use_autosuspend(cs35l56->base.dev);
+ pm_runtime_set_active(cs35l56->base.dev);
+ pm_runtime_enable(cs35l56->base.dev);
- /*
- * If the system is not using a reset_gpio then issue a
- * dummy read to force a wakeup.
- */
- if (!cs35l56->reset_gpio)
- regmap_read(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
-
- /* Wait for control port to be ready (datasheet tIRS). */
- usleep_range(CS35L56_CONTROL_PORT_READY_US,
- CS35L56_CONTROL_PORT_READY_US + 400);
-
- /*
- * The HALO_STATE register is in different locations on Ax and B0
- * devices so the REVID needs to be determined before waiting for the
- * firmware to boot.
- */
- ret = regmap_read(cs35l56->regmap, CS35L56_REVID, &revid);
- if (ret < 0) {
- dev_err(cs35l56->dev, "Get Revision ID failed\n");
+ ret = cs35l56_hw_init(&cs35l56->base);
+ if (ret < 0)
return ret;
- }
- cs35l56->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
- ret = cs35l56_wait_for_firmware_boot(cs35l56);
+ ret = cs35l56_set_patch(&cs35l56->base);
if (ret)
return ret;
- ret = regmap_read(cs35l56->regmap, CS35L56_DEVID, &devid);
- if (ret < 0) {
- dev_err(cs35l56->dev, "Get Device ID failed\n");
- return ret;
- }
- devid &= CS35L56_DEVID_MASK;
-
- switch (devid) {
- case 0x35A56:
- break;
- default:
- dev_err(cs35l56->dev, "Unknown device %x\n", devid);
- return ret;
- }
-
- ret = regmap_read(cs35l56->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
- if (ret) {
- dev_err(cs35l56->dev, "Get Secure status failed\n");
- return ret;
- }
-
- /* When any bus is restricted treat the device as secured */
- if (secured & CS35L56_RESTRICTED_MASK)
- cs35l56->secured = true;
-
- ret = regmap_read(cs35l56->regmap, CS35L56_OTPID, &otpid);
- if (ret < 0) {
- dev_err(cs35l56->dev, "Get OTP ID failed\n");
+ ret = cs35l56_get_calibration(&cs35l56->base);
+ if (ret)
return ret;
- }
- dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
- cs35l56->secured ? "s" : "", cs35l56->rev, otpid);
-
- /* Populate the DSP information with the revision and security state */
- cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x",
- cs35l56->secured ? "s" : "", cs35l56->rev);
- if (!cs35l56->dsp.part)
- return -ENOMEM;
-
- /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
- regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
- regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1,
- CS35L56_AMP_SHORT_ERR_EINT1_MASK,
- 0);
- regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_8,
- CS35L56_TEMP_ERR_EINT1_MASK,
- 0);
-
- if (!cs35l56->reset_gpio) {
- dev_dbg(cs35l56->dev, "No reset gpio: using soft reset\n");
- cs35l56_system_reset(cs35l56);
+ if (!cs35l56->base.reset_gpio) {
+ dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
+ cs35l56->soft_resetting = true;
+ cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
if (cs35l56->sdw_peripheral) {
/* Keep alive while we wait for re-enumeration */
- pm_runtime_get_noresume(cs35l56->dev);
+ pm_runtime_get_noresume(cs35l56->base.dev);
return 0;
}
}
@@ -1559,71 +1739,76 @@ post_soft_reset:
cs35l56->soft_resetting = false;
/* Done re-enumerating after one-time init so release the keep-alive */
- if (cs35l56->sdw_peripheral && !cs35l56->init_done)
- pm_runtime_put_noidle(cs35l56->dev);
+ if (cs35l56->sdw_peripheral && !cs35l56->base.init_done)
+ pm_runtime_put_noidle(cs35l56->base.dev);
- regcache_mark_dirty(cs35l56->regmap);
- ret = cs35l56_wait_for_firmware_boot(cs35l56);
+ regcache_mark_dirty(cs35l56->base.regmap);
+ ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
if (ret)
return ret;
- dev_dbg(cs35l56->dev, "Firmware rebooted after soft reset\n");
+ dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n");
+
+ regcache_cache_only(cs35l56->base.regmap, false);
}
/* Disable auto-hibernate so that runtime_pm has control */
- ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+ ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
if (ret)
return ret;
- /* Populate soft registers in the regmap cache */
- cs35l56_reread_firmware_registers(cs35l56->dev, cs35l56->regmap);
-
/* Registers could be dirty after soft reset or SoundWire enumeration */
- regcache_sync(cs35l56->regmap);
+ regcache_sync(cs35l56->base.regmap);
- cs35l56->init_done = true;
+ /* Set ASP1 DOUT to high-impedance when it is not transmitting audio data. */
+ ret = regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
+ CS35L56_ASP1_DOUT_HIZ_CTRL_MASK);
+ if (ret)
+ return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
+
+ cs35l56->base.init_done = true;
complete(&cs35l56->init_completion);
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE);
+EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE");
void cs35l56_remove(struct cs35l56_private *cs35l56)
{
- cs35l56->init_done = false;
+ cs35l56->base.init_done = false;
/*
* WAKE IRQs unmask if CS35L56 hibernates so free the handler to
* prevent it racing with remove().
*/
- if (cs35l56->irq)
- devm_free_irq(cs35l56->dev, cs35l56->irq, 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_suspend(cs35l56->dev);
- pm_runtime_disable(cs35l56->dev);
-
- regcache_cache_only(cs35l56->regmap, true);
+ pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
+ pm_runtime_suspend(cs35l56->base.dev);
+ pm_runtime_disable(cs35l56->base.dev);
- kfree(cs35l56->dsp.system_name);
+ regcache_cache_only(cs35l56->base.regmap, true);
- gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE);
+EXPORT_SYMBOL_NS_GPL(cs35l56_remove, "SND_SOC_CS35L56_CORE");
-const struct dev_pm_ops cs35l56_pm_ops_i2c_spi = {
- SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend, cs35l56_runtime_resume_i2c_spi, NULL)
+#if IS_ENABLED(CONFIG_SND_SOC_CS35L56_I2C) || IS_ENABLED(CONFIG_SND_SOC_CS35L56_SPI)
+EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = {
+ SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend_i2c_spi, cs35l56_runtime_resume_i2c_spi, NULL)
SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend, cs35l56_system_resume)
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_no_irq, cs35l56_system_resume_no_irq)
};
-EXPORT_SYMBOL_NS_GPL(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE);
+#endif
MODULE_DESCRIPTION("ASoC CS35L56 driver");
-MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index 1f7894662fcb..4c59f92f3206 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -10,6 +10,7 @@
#define CS35L56_H
#include <linux/completion.h>
+#include <linux/container_of.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/workqueue.h>
@@ -20,8 +21,6 @@
#define CS35L56_SDW_GEN_INT_MASK_1 0xc1
#define CS35L56_SDW_INT_MASK_CODEC_IRQ BIT(0)
-#define CS35L56_SDW_INVALID_BUS_SCALE 0xf
-
#define CS35L56_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
#define CS35L56_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE \
| SNDRV_PCM_FMTBIT_S32_LE)
@@ -32,40 +31,37 @@ struct sdw_slave;
struct cs35l56_private {
struct wm_adsp dsp; /* must be first member */
+ struct cs35l56_base base;
struct work_struct dsp_work;
struct workqueue_struct *dsp_wq;
- struct mutex irq_lock;
struct snd_soc_component *component;
- struct device *dev;
- struct regmap *regmap;
struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
- int irq;
struct sdw_slave *sdw_peripheral;
- u8 rev;
+ const char *fallback_fw_suffix;
struct work_struct sdw_irq_work;
- bool secured;
bool sdw_irq_no_unmask;
bool soft_resetting;
- bool init_done;
bool sdw_attached;
- bool fw_patched;
- bool can_hibernate;
struct completion init_completion;
- struct gpio_desc *reset_gpio;
+ int speaker_id;
u32 rx_mask;
u32 tx_mask;
u8 asp_slot_width;
u8 asp_slot_count;
bool tdm_mode;
bool sysclk_set;
- u8 old_sdw_clock_scale;
+ u8 sdw_link_num;
+ u8 sdw_unique_id;
};
+static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_base *cs35l56_base)
+{
+ return container_of(cs35l56_base, struct cs35l56_private, base);
+}
+
extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
-int cs35l56_runtime_suspend(struct device *dev);
-int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56);
int cs35l56_system_suspend(struct device *dev);
int cs35l56_system_suspend_late(struct device *dev);
int cs35l56_system_suspend_no_irq(struct device *dev);
@@ -73,7 +69,7 @@ int cs35l56_system_resume_no_irq(struct device *dev);
int cs35l56_system_resume_early(struct device *dev);
int cs35l56_system_resume(struct device *dev);
irqreturn_t cs35l56_irq(int irq, void *data);
-int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq);
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
int cs35l56_common_probe(struct cs35l56_private *cs35l56);
int cs35l56_init(struct cs35l56_private *cs35l56);
void cs35l56_remove(struct cs35l56_private *cs35l56);
diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c
new file mode 100644
index 000000000000..aa629ef53db4
--- /dev/null
+++ b/sound/soc/codecs/cs40l50-codec.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS40L50 Advanced Haptic Driver with waveform memory,
+// integrated DSP, and closed-loop algorithms
+//
+// Copyright 2024 Cirrus Logic, Inc.
+//
+// Author: James Ogletree <james.ogletree@cirrus.com>
+
+#include <linux/bitfield.h>
+#include <linux/mfd/cs40l50.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define CS40L50_REFCLK_INPUT 0x2C04
+#define CS40L50_ASP_CONTROL2 0x4808
+#define CS40L50_ASP_DATA_CONTROL5 0x4840
+
+/* PLL Config */
+#define CS40L50_PLL_REFCLK_BCLK 0x0
+#define CS40L50_PLL_REFCLK_MCLK 0x5
+#define CS40L50_PLL_REEFCLK_MCLK_CFG 0x00
+#define CS40L50_PLL_REFCLK_LOOP_MASK BIT(11)
+#define CS40L50_PLL_REFCLK_OPEN_LOOP 1
+#define CS40L50_PLL_REFCLK_CLOSED_LOOP 0
+#define CS40L50_PLL_REFCLK_LOOP_SHIFT 11
+#define CS40L50_PLL_REFCLK_FREQ_MASK GENMASK(10, 5)
+#define CS40L50_PLL_REFCLK_FREQ_SHIFT 5
+#define CS40L50_PLL_REFCLK_SEL_MASK GENMASK(2, 0)
+#define CS40L50_BCLK_RATIO_DEFAULT 32
+
+/* ASP Config */
+#define CS40L50_ASP_RX_WIDTH_SHIFT 24
+#define CS40L50_ASP_RX_WIDTH_MASK GENMASK(31, 24)
+#define CS40L50_ASP_RX_WL_MASK GENMASK(5, 0)
+#define CS40L50_ASP_FSYNC_INV_MASK BIT(2)
+#define CS40L50_ASP_BCLK_INV_MASK BIT(6)
+#define CS40L50_ASP_FMT_MASK GENMASK(10, 8)
+#define CS40L50_ASP_FMT_I2S 0x2
+
+struct cs40l50_pll_config {
+ unsigned int freq;
+ unsigned int cfg;
+};
+
+struct cs40l50_codec {
+ struct device *dev;
+ struct regmap *regmap;
+ unsigned int daifmt;
+ unsigned int bclk_ratio;
+ unsigned int rate;
+};
+
+static const struct cs40l50_pll_config cs40l50_pll_cfg[] = {
+ { 32768, 0x00 },
+ { 1536000, 0x1B },
+ { 3072000, 0x21 },
+ { 6144000, 0x28 },
+ { 9600000, 0x30 },
+ { 12288000, 0x33 },
+};
+
+static int cs40l50_get_clk_config(const unsigned int freq, unsigned int *cfg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs40l50_pll_cfg); i++) {
+ if (cs40l50_pll_cfg[i].freq == freq) {
+ *cfg = cs40l50_pll_cfg[i].cfg;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int cs40l50_swap_ext_clk(struct cs40l50_codec *codec, const unsigned int clk_src)
+{
+ unsigned int cfg;
+ int ret;
+
+ switch (clk_src) {
+ case CS40L50_PLL_REFCLK_BCLK:
+ ret = cs40l50_get_clk_config(codec->bclk_ratio * codec->rate, &cfg);
+ if (ret)
+ return ret;
+ break;
+ case CS40L50_PLL_REFCLK_MCLK:
+ cfg = CS40L50_PLL_REEFCLK_MCLK_CFG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
+ CS40L50_PLL_REFCLK_LOOP_MASK,
+ CS40L50_PLL_REFCLK_OPEN_LOOP <<
+ CS40L50_PLL_REFCLK_LOOP_SHIFT);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
+ CS40L50_PLL_REFCLK_FREQ_MASK |
+ CS40L50_PLL_REFCLK_SEL_MASK,
+ (cfg << CS40L50_PLL_REFCLK_FREQ_SHIFT) | clk_src);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT,
+ CS40L50_PLL_REFCLK_LOOP_MASK,
+ CS40L50_PLL_REFCLK_CLOSED_LOOP <<
+ CS40L50_PLL_REFCLK_LOOP_SHIFT);
+}
+
+static int cs40l50_clk_en(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(comp);
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_STOP_PLAYBACK);
+ if (ret)
+ return ret;
+
+ ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_START_I2S);
+ if (ret)
+ return ret;
+
+ ret = cs40l50_swap_ext_clk(codec, CS40L50_PLL_REFCLK_BCLK);
+ if (ret)
+ return ret;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ ret = cs40l50_swap_ext_clk(codec, CS40L50_PLL_REFCLK_MCLK);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget cs40l50_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("ASP PLL", 0, SND_SOC_NOPM, 0, 0, cs40l50_clk_en,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route cs40l50_dapm_routes[] = {
+ { "ASP Playback", NULL, "ASP PLL" },
+ { "ASPRX1", NULL, "ASP Playback" },
+ { "ASPRX2", NULL, "ASP Playback" },
+
+ { "OUT", NULL, "ASPRX1" },
+ { "OUT", NULL, "ASPRX2" },
+};
+
+static int cs40l50_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(codec_dai->component);
+
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBC_CFC)
+ return -EINVAL;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ codec->daifmt = 0;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ codec->daifmt = CS40L50_ASP_FSYNC_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ codec->daifmt = CS40L50_ASP_BCLK_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ codec->daifmt = CS40L50_ASP_FSYNC_INV_MASK | CS40L50_ASP_BCLK_INV_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock invert\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ codec->daifmt |= FIELD_PREP(CS40L50_ASP_FMT_MASK, CS40L50_ASP_FMT_I2S);
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported DAI format\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs40l50_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(dai->component);
+ unsigned int asp_rx_wl = params_width(params);
+ int ret;
+
+ codec->rate = params_rate(params);
+
+ ret = regmap_update_bits(codec->regmap, CS40L50_ASP_DATA_CONTROL5,
+ CS40L50_ASP_RX_WL_MASK, asp_rx_wl);
+ if (ret)
+ return ret;
+
+ codec->daifmt |= (asp_rx_wl << CS40L50_ASP_RX_WIDTH_SHIFT);
+
+ return regmap_update_bits(codec->regmap, CS40L50_ASP_CONTROL2,
+ CS40L50_ASP_FSYNC_INV_MASK |
+ CS40L50_ASP_BCLK_INV_MASK |
+ CS40L50_ASP_FMT_MASK |
+ CS40L50_ASP_RX_WIDTH_MASK, codec->daifmt);
+}
+
+static int cs40l50_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(dai->component);
+
+ codec->bclk_ratio = ratio;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs40l50_dai_ops = {
+ .set_fmt = cs40l50_set_dai_fmt,
+ .set_bclk_ratio = cs40l50_set_dai_bclk_ratio,
+ .hw_params = cs40l50_hw_params,
+};
+
+static struct snd_soc_dai_driver cs40l50_dai[] = {
+ {
+ .name = "cs40l50-pcm",
+ .id = 0,
+ .playback = {
+ .stream_name = "ASP Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &cs40l50_dai_ops,
+ },
+};
+
+static int cs40l50_codec_probe(struct snd_soc_component *component)
+{
+ struct cs40l50_codec *codec = snd_soc_component_get_drvdata(component);
+
+ codec->bclk_ratio = CS40L50_BCLK_RATIO_DEFAULT;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_cs40l50 = {
+ .probe = cs40l50_codec_probe,
+ .dapm_widgets = cs40l50_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs40l50_dapm_widgets),
+ .dapm_routes = cs40l50_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs40l50_dapm_routes),
+};
+
+static int cs40l50_codec_driver_probe(struct platform_device *pdev)
+{
+ struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent);
+ struct cs40l50_codec *codec;
+
+ codec = devm_kzalloc(&pdev->dev, sizeof(*codec), GFP_KERNEL);
+ if (!codec)
+ return -ENOMEM;
+
+ codec->regmap = cs40l50->regmap;
+ codec->dev = &pdev->dev;
+
+ return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cs40l50,
+ cs40l50_dai, ARRAY_SIZE(cs40l50_dai));
+}
+
+static const struct platform_device_id cs40l50_id[] = {
+ { "cs40l50-codec", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs40l50_id);
+
+static struct platform_driver cs40l50_codec_driver = {
+ .probe = cs40l50_codec_driver_probe,
+ .id_table = cs40l50_id,
+ .driver = {
+ .name = "cs40l50-codec",
+ },
+};
+module_platform_driver(cs40l50_codec_driver);
+
+MODULE_DESCRIPTION("ASoC CS40L50 driver");
+MODULE_AUTHOR("James Ogletree <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c
index 69287ba7e955..89c424dd838b 100644
--- a/sound/soc/codecs/cs4234.c
+++ b/sound/soc/codecs/cs4234.c
@@ -85,9 +85,9 @@ static SOC_ENUM_SINGLE_DECL(cs4234_max_delay, CS4234_VOLUME_MODE,
static int cs4234_dac14_grp_delay_put(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *uctrl)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kctrl);
+ struct snd_soc_component *component = snd_kcontrol_chip(kctrl);
struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int val = 0;
int ret = 0;
@@ -126,10 +126,11 @@ static int cs4234_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct cs4234 *cs4234 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_STANDBY:
wait_for_completion(&cs4234->vq_ramp_complete);
break;
@@ -307,9 +308,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 +861,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 +882,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 +892,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 +904,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 0cfc5ab36a13..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);
@@ -564,7 +564,7 @@ static const struct regmap_config cs4265_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
.readable_reg = cs4265_readable_register,
.volatile_reg = cs4265_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int cs4265_i2c_probe(struct i2c_client *i2c_client)
@@ -638,7 +638,7 @@ static const struct of_device_id cs4265_of_match[] = {
MODULE_DEVICE_TABLE(of, cs4265_of_match);
static const struct i2c_device_id cs4265_id[] = {
- { "cs4265", 0 },
+ { "cs4265" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs4265_id);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index ab32f15e3b44..3139f03cd42b 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -21,6 +21,7 @@
* - Power management is supported
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -30,7 +31,6 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -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:
@@ -433,7 +433,7 @@ static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute, int direction)
static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
int left = !ucontrol->value.integer.value[0];
int right = !ucontrol->value.integer.value[1];
@@ -636,7 +636,7 @@ static const struct regmap_config cs4270_regmap = {
.max_register = CS4270_LASTREG,
.reg_defaults = cs4270_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs4270_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.write_flag_mask = CS4270_I2C_INCR,
.readable_reg = cs4270_reg_is_readable,
@@ -734,7 +734,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client)
* cs4270_id - I2C device IDs supported by this driver
*/
static const struct i2c_device_id cs4270_id[] = {
- {"cs4270", 0},
+ {"cs4270"},
{}
};
MODULE_DEVICE_TABLE(i2c, cs4270_id);
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c
index 89fe7d1665df..1d210b969173 100644
--- a/sound/soc/codecs/cs4271-i2c.c
+++ b/sound/soc/codecs/cs4271-i2c.c
@@ -23,7 +23,7 @@ static int cs4271_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id cs4271_i2c_id[] = {
- { "cs4271", 0 },
+ { "cs4271" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 188b8b43c524..77dfc83a3c01 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -10,13 +10,12 @@
* DAPM support not implemented.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -161,12 +160,11 @@ struct cs4271_private {
/* Current sample rate for de-emphasis control */
int rate;
/* GPIO driving Reset pin, if any */
- int gpio_nreset;
- /* GPIO that disable serial bus, if any */
- int gpio_disable;
+ struct gpio_desc *reset;
/* enable soft reset workaround */
bool enable_soft_reset;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+ struct clk *clk;
};
static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
@@ -213,10 +211,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;
@@ -280,7 +278,7 @@ static int cs4271_set_deemph(struct snd_soc_component *component)
static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = cs4271->deemph;
@@ -290,7 +288,7 @@ static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
cs4271->deemph = ucontrol->value.integer.value[0];
@@ -488,12 +486,10 @@ static int cs4271_reset(struct snd_soc_component *component)
{
struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(cs4271->gpio_nreset)) {
- gpio_direction_output(cs4271->gpio_nreset, 0);
- mdelay(1);
- gpio_set_value(cs4271->gpio_nreset, 1);
- mdelay(1);
- }
+ gpiod_direction_output(cs4271->reset, 1);
+ mdelay(1);
+ gpiod_set_value(cs4271->reset, 0);
+ mdelay(1);
return 0;
}
@@ -511,6 +507,7 @@ static int cs4271_soc_suspend(struct snd_soc_component *component)
return ret;
regcache_mark_dirty(cs4271->regmap);
+ clk_disable_unprepare(cs4271->clk);
regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
return 0;
@@ -528,6 +525,12 @@ static int cs4271_soc_resume(struct snd_soc_component *component)
return ret;
}
+ ret = clk_prepare_enable(cs4271->clk);
+ if (ret) {
+ dev_err(component->dev, "Failed to enable clk: %d\n", ret);
+ return ret;
+ }
+
/* Do a proper reset after power up */
cs4271_reset(component);
@@ -563,19 +566,12 @@ static int cs4271_component_probe(struct snd_soc_component *component)
struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
struct cs4271_platform_data *cs4271plat = component->dev->platform_data;
int ret;
- bool amutec_eq_bmutec = false;
+ bool amutec_eq_bmutec;
-#ifdef CONFIG_OF
- if (of_match_device(cs4271_dt_ids, component->dev)) {
- if (of_get_property(component->dev->of_node,
- "cirrus,amutec-eq-bmutec", NULL))
- amutec_eq_bmutec = true;
-
- if (of_get_property(component->dev->of_node,
- "cirrus,enable-soft-reset", NULL))
- cs4271->enable_soft_reset = true;
- }
-#endif
+ amutec_eq_bmutec = of_property_read_bool(component->dev->of_node,
+ "cirrus,amutec-eq-bmutec");
+ cs4271->enable_soft_reset = of_property_read_bool(component->dev->of_node,
+ "cirrus,enable-soft-reset");
ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
cs4271->supplies);
@@ -589,22 +585,30 @@ static int cs4271_component_probe(struct snd_soc_component *component)
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}
+ ret = clk_prepare_enable(cs4271->clk);
+ if (ret) {
+ dev_err(component->dev, "Failed to enable clk: %d\n", ret);
+ goto err_disable_regulators;
+ }
+
/* Reset codec */
cs4271_reset(component);
ret = regcache_sync(cs4271->regmap);
if (ret < 0)
- return ret;
+ goto err_disable_clk;
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
if (ret < 0)
- return ret;
+ goto err_disable_clk;
+
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN, 0);
if (ret < 0)
- return ret;
+ goto err_disable_clk;
+
/* Power-up sequence requires 85 uS */
udelay(85);
@@ -614,18 +618,24 @@ static int cs4271_component_probe(struct snd_soc_component *component)
CS4271_MODE2_MUTECAEQUB);
return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(cs4271->clk);
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+ return ret;
}
static void cs4271_component_remove(struct snd_soc_component *component)
{
struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(cs4271->gpio_nreset))
- /* Set codec to the reset state */
- gpio_set_value(cs4271->gpio_nreset, 0);
+ /* Set codec to the reset state */
+ gpiod_set_value(cs4271->reset, 1);
regcache_mark_dirty(cs4271->regmap);
regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+ clk_disable_unprepare(cs4271->clk);
};
static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
@@ -647,7 +657,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
static int cs4271_common_probe(struct device *dev,
struct cs4271_private **c)
{
- struct cs4271_platform_data *cs4271plat = dev->platform_data;
struct cs4271_private *cs4271;
int i, ret;
@@ -655,19 +664,15 @@ static int cs4271_common_probe(struct device *dev,
if (!cs4271)
return -ENOMEM;
- if (of_match_device(cs4271_dt_ids, dev))
- cs4271->gpio_nreset =
- of_get_named_gpio(dev->of_node, "reset-gpio", 0);
-
- if (cs4271plat)
- cs4271->gpio_nreset = cs4271plat->gpio_nreset;
+ cs4271->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
+ if (IS_ERR(cs4271->reset))
+ return dev_err_probe(dev, PTR_ERR(cs4271->reset),
+ "error retrieving RESET GPIO\n");
+ gpiod_set_consumer_name(cs4271->reset, "CS4271 Reset");
- if (gpio_is_valid(cs4271->gpio_nreset)) {
- ret = devm_gpio_request(dev, cs4271->gpio_nreset,
- "CS4271 Reset");
- if (ret < 0)
- return ret;
- }
+ cs4271->clk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(cs4271->clk))
+ return dev_err_probe(dev, PTR_ERR(cs4271->clk), "Failed to get mclk\n");
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
cs4271->supplies[i].supply = supply_names[i];
diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c
index 2552a1e6b82f..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[] = {
@@ -78,7 +78,7 @@ static const struct acpi_device_id __maybe_unused cs42l42_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, cs42l42_acpi_match);
static const struct i2c_device_id cs42l42_id[] = {
- {"cs42l42", 0},
+ {"cs42l42"},
{}
};
@@ -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),
},
@@ -101,4 +101,4 @@ module_i2c_driver(cs42l42_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L42 I2C driver");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
+MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE");
diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c
index eeab07c850f9..f837c7eff10b 100644
--- a/sound/soc/codecs/cs42l42-sdw.c
+++ b/sound/soc/codecs/cs42l42-sdw.c
@@ -6,6 +6,7 @@
#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/gpio/consumer.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -322,15 +323,15 @@ static int cs42l42_sdw_read_prop(struct sdw_slave *peripheral)
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
/* DP1 - capture */
- ports[0].num = CS42L42_SDW_CAPTURE_PORT,
- ports[0].type = SDW_DPN_FULL,
- ports[0].ch_prep_timeout = 10,
+ ports[0].num = CS42L42_SDW_CAPTURE_PORT;
+ ports[0].type = SDW_DPN_FULL;
+ ports[0].ch_prep_timeout = 10;
prop->src_dpn_prop = &ports[0];
/* DP2 - playback */
- ports[1].num = CS42L42_SDW_PLAYBACK_PORT,
- ports[1].type = SDW_DPN_FULL,
- ports[1].ch_prep_timeout = 10,
+ ports[1].num = CS42L42_SDW_PLAYBACK_PORT;
+ ports[1].type = SDW_DPN_FULL;
+ ports[1].ch_prep_timeout = 10;
prop->sink_dpn_prop = &ports[1];
return 0;
@@ -344,6 +345,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
switch (status) {
case SDW_SLAVE_ATTACHED:
dev_dbg(cs42l42->dev, "ATTACHED\n");
+
+ /*
+ * The SoundWire core can report stale ATTACH notifications
+ * if we hard-reset CS42L42 in probe() but it had already been
+ * enumerated. Reject the ATTACH if we haven't yet seen an
+ * UNATTACH report for the device being in reset.
+ */
+ if (cs42l42->sdw_waiting_first_unattach)
+ break;
+
/*
* Initialise codec, this only needs to be done once.
* When resuming from suspend, resume callback will handle re-init of codec,
@@ -354,6 +365,16 @@ static int cs42l42_sdw_update_status(struct sdw_slave *peripheral,
break;
case SDW_SLAVE_UNATTACHED:
dev_dbg(cs42l42->dev, "UNATTACHED\n");
+
+ if (cs42l42->sdw_waiting_first_unattach) {
+ /*
+ * SoundWire core has seen that CS42L42 is not on
+ * the bus so release RESET and wait for ATTACH.
+ */
+ cs42l42->sdw_waiting_first_unattach = false;
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+ }
+
break;
default:
break;
@@ -390,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);
@@ -405,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;
@@ -439,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);
@@ -470,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;
@@ -575,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[] = {
@@ -588,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,
@@ -601,4 +622,4 @@ module_sdw_driver(cs42l42_sdw_driver);
MODULE_DESCRIPTION("ASoC CS42L42 SoundWire driver");
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
+MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE");
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index a0de0329406a..2652a639a79a 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -11,11 +11,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/acpi.h>
@@ -24,7 +22,6 @@
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -332,7 +329,7 @@ bool cs42l42_readable_register(struct device *dev, unsigned int reg)
return false;
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, "SND_SOC_CS42L42_CORE");
bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
{
@@ -366,7 +363,7 @@ bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
return false;
}
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, "SND_SOC_CS42L42_CORE");
const struct regmap_range_cfg cs42l42_page_range = {
.name = "Pages",
@@ -378,7 +375,7 @@ const struct regmap_range_cfg cs42l42_page_range = {
.window_start = 0,
.window_len = 256,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, "SND_SOC_CS42L42_CORE");
const struct regmap_config cs42l42_regmap = {
.reg_bits = 8,
@@ -398,7 +395,7 @@ const struct regmap_config cs42l42_regmap = {
.use_single_read = true,
.use_single_write = true,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, "SND_SOC_CS42L42_CORE");
static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true);
static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
@@ -406,7 +403,7 @@ static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
static int cs42l42_slow_start_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
/* all bits of SLOW_START_EN must change together */
@@ -599,7 +596,7 @@ const struct snd_soc_component_driver cs42l42_soc_component = {
.num_controls = ARRAY_SIZE(cs42l42_snd_controls),
.endianness = 1,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, "SND_SOC_CS42L42_CORE");
/* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */
static const struct reg_sequence cs42l42_to_sclk_seq[] = {
@@ -751,7 +748,7 @@ int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk,
return -EINVAL;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, "SND_SOC_CS42L42_CORE");
void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate)
{
@@ -785,7 +782,7 @@ void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample
CS42L42_CLK_OASRC_SEL_MASK,
fs << CS42L42_CLK_OASRC_SEL_SHIFT);
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, "SND_SOC_CS42L42_CORE");
static int cs42l42_asp_config(struct snd_soc_component *component,
unsigned int sclk, unsigned int sample_rate)
@@ -833,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;
@@ -1119,7 +1116,7 @@ int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, "SND_SOC_CS42L42_CORE");
#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
@@ -1154,7 +1151,7 @@ struct snd_soc_dai_driver cs42l42_dai = {
.symmetric_sample_bits = 1,
.ops = &cs42l42_ops,
};
-EXPORT_SYMBOL_NS_GPL(cs42l42_dai, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_dai, "SND_SOC_CS42L42_CORE");
static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42)
{
@@ -1778,12 +1775,11 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
}
mutex_unlock(&cs42l42->irq_lock);
- pm_runtime_mark_last_busy(cs42l42->dev);
pm_runtime_put_autosuspend(cs42l42->dev);
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE");
static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42)
{
@@ -2197,7 +2193,6 @@ int cs42l42_suspend(struct device *dev)
/* Discharge FILT+ */
regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL2,
CS42L42_DISCHARGE_FILT_MASK, CS42L42_DISCHARGE_FILT_MASK);
- msleep(CS42L42_FILT_DISCHARGE_TIME_MS);
regcache_cache_only(cs42l42->regmap, true);
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
@@ -2215,7 +2210,7 @@ int cs42l42_suspend(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, "SND_SOC_CS42L42_CORE");
int cs42l42_resume(struct device *dev)
{
@@ -2246,7 +2241,7 @@ int cs42l42_resume(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_resume, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_resume, "SND_SOC_CS42L42_CORE");
void cs42l42_resume_restore(struct device *dev)
{
@@ -2265,7 +2260,7 @@ void cs42l42_resume_restore(struct device *dev)
dev_dbg(dev, "System resumed\n");
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, "SND_SOC_CS42L42_CORE");
static int __maybe_unused cs42l42_i2c_resume(struct device *dev)
{
@@ -2320,7 +2315,26 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42,
if (cs42l42->reset_gpio) {
dev_dbg(cs42l42->dev, "Found reset GPIO\n");
- gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+
+ /*
+ * ACPI can override the default GPIO state we requested
+ * so ensure that we start with RESET low.
+ */
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+ /* Ensure minimum reset pulse width */
+ usleep_range(10, 500);
+
+ /*
+ * On SoundWire keep the chip in reset until we get an UNATTACH
+ * notification from the SoundWire core. This acts as a
+ * synchronization point to reject stale ATTACH notifications
+ * if the chip was already enumerated before we reset it.
+ */
+ if (cs42l42->sdw_peripheral)
+ cs42l42->sdw_waiting_first_unattach = true;
+ else
+ gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
}
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
@@ -2355,7 +2369,7 @@ err_disable_noreset:
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, "SND_SOC_CS42L42_CORE");
int cs42l42_init(struct cs42l42_private *cs42l42)
{
@@ -2449,7 +2463,7 @@ err_disable:
cs42l42->supplies);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_init, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_init, "SND_SOC_CS42L42_CORE");
void cs42l42_common_remove(struct cs42l42_private *cs42l42)
{
@@ -2469,7 +2483,7 @@ void cs42l42_common_remove(struct cs42l42_private *cs42l42)
gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
}
-EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, SND_SOC_CS42L42_CORE);
+EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, "SND_SOC_CS42L42_CORE");
MODULE_DESCRIPTION("ASoC CS42L42 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index 4bd7b85a5747..3d85ebc59489 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -14,7 +14,7 @@
#include <dt-bindings/sound/cs42l42.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -53,6 +53,7 @@ struct cs42l42_private {
u8 stream_use;
bool hp_adc_up_pending;
bool suspended;
+ bool sdw_waiting_first_unattach;
bool init_done;
};
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
new file mode 100644
index 000000000000..b719d62635a0
--- /dev/null
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -0,0 +1,962 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 CODEC driver jack handling
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/build_bug.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/time.h>
+#include <linux/workqueue.h>
+#include <sound/control.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-component.h>
+#include <sound/soc-jack.h>
+#include <sound/soc.h>
+
+#include "cs42l43.h"
+
+static const unsigned int cs42l43_accdet_us[] = {
+ 20, 100, 1000, 10000, 50000, 75000, 100000, 200000,
+};
+
+static const unsigned int cs42l43_accdet_db_ms[] = {
+ 0, 125, 250, 500, 750, 1000, 1250, 1500,
+};
+
+static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 };
+
+static const unsigned int cs42l43_accdet_bias_sense[] = {
+ 14, 24, 43, 52, 61, 71, 90, 99, 0,
+};
+
+static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const prop,
+ unsigned int defval, unsigned int *val,
+ const unsigned int *values, const int nvalues)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ int i, ret;
+
+ ret = device_property_read_u32(cs42l43->dev, prop, &defval);
+ if (ret != -EINVAL && ret < 0) {
+ dev_err(priv->dev, "Property %s malformed: %d\n", prop, ret);
+ return ret;
+ }
+
+ if (val)
+ *val = defval;
+
+ for (i = 0; i < nvalues; i++)
+ if (defval == values[i])
+ return i;
+
+ dev_err(priv->dev, "Invalid value for property %s: %d\n", prop, defval);
+ return -EINVAL;
+}
+
+int cs42l43_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *d)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ /* This tip sense invert is always set, HW wants an inverted signal */
+ unsigned int tip_deb = CS42L43_TIPSENSE_INV_MASK;
+ unsigned int hs2 = 0x2 << CS42L43_HSDET_MODE_SHIFT;
+ unsigned int autocontrol = 0, pdncntl = 0;
+ int ret;
+
+ dev_dbg(priv->dev, "Configure accessory detect\n");
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret);
+ return ret;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ priv->jack_hp = jack;
+
+ if (!jack)
+ goto done;
+
+ ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms");
+ if (ret != -EINVAL) {
+ if (ret < 0) {
+ dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n",
+ ret);
+ goto error;
+ }
+
+ if (ret > CS42L43_N_BUTTONS) {
+ ret = -EINVAL;
+ dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n");
+ goto error;
+ }
+
+ ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms",
+ priv->buttons, ret);
+ if (ret < 0) {
+ dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n",
+ ret);
+ goto error;
+ }
+ } else {
+ priv->buttons[0] = 70;
+ priv->buttons[1] = 185;
+ priv->buttons[2] = 355;
+ priv->buttons[3] = 735;
+ }
+
+ ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us,
+ cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us));
+ if (ret < 0)
+ goto error;
+
+ hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT;
+
+ priv->bias_low = device_property_read_bool(cs42l43->dev, "cirrus,bias-low");
+
+ ret = cs42l43_find_index(priv, "cirrus,bias-ramp-ms", 170,
+ &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms,
+ ARRAY_SIZE(cs42l43_accdet_ramp_ms));
+ if (ret < 0)
+ goto error;
+
+ hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,bias-sense-microamp", 14,
+ &priv->bias_sense_ua, cs42l43_accdet_bias_sense,
+ ARRAY_SIZE(cs42l43_accdet_bias_sense));
+ if (ret < 0)
+ goto error;
+
+ if (priv->bias_sense_ua)
+ autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT;
+
+ if (!device_property_read_bool(cs42l43->dev, "cirrus,button-automute"))
+ autocontrol |= CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK;
+
+ ret = device_property_read_u32(cs42l43->dev, "cirrus,tip-debounce-ms",
+ &priv->tip_debounce_ms);
+ if (ret < 0 && ret != -EINVAL) {
+ dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret);
+ goto error;
+ }
+
+ /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */
+ if (device_property_read_bool(cs42l43->dev, "cirrus,tip-invert"))
+ autocontrol |= 0x1 << CS42L43_JACKDET_INV_SHIFT;
+
+ if (device_property_read_bool(cs42l43->dev, "cirrus,tip-disable-pullup"))
+ autocontrol |= 0x1 << CS42L43_JACKDET_MODE_SHIFT;
+ else
+ autocontrol |= 0x3 << CS42L43_JACKDET_MODE_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,tip-fall-db-ms", 500,
+ &priv->tip_fall_db_ms, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,tip-rise-db-ms", 500,
+ &priv->tip_rise_db_ms, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT;
+
+ if (device_property_read_bool(cs42l43->dev, "cirrus,use-ring-sense")) {
+ unsigned int ring_deb = 0;
+
+ priv->use_ring_sense = true;
+
+ /* HW wants an inverted signal, so invert the invert */
+ if (!device_property_read_bool(cs42l43->dev, "cirrus,ring-invert"))
+ ring_deb |= CS42L43_RINGSENSE_INV_MASK;
+
+ if (!device_property_read_bool(cs42l43->dev,
+ "cirrus,ring-disable-pullup"))
+ ring_deb |= CS42L43_RINGSENSE_PULLUP_PDNB_MASK;
+
+ ret = cs42l43_find_index(priv, "cirrus,ring-fall-db-ms", 500,
+ NULL, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,ring-rise-db-ms", 500,
+ NULL, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT;
+ pdncntl |= CS42L43_RING_SENSE_EN_MASK;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_RINGSENSE_DEB_CTRL,
+ CS42L43_RINGSENSE_INV_MASK |
+ CS42L43_RINGSENSE_PULLUP_PDNB_MASK |
+ CS42L43_RINGSENSE_FALLING_DB_TIME_MASK |
+ CS42L43_RINGSENSE_RISING_DB_TIME_MASK,
+ ring_deb);
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_TIPSENSE_DEB_CTRL,
+ CS42L43_TIPSENSE_INV_MASK |
+ CS42L43_TIPSENSE_FALLING_DB_TIME_MASK |
+ CS42L43_TIPSENSE_RISING_DB_TIME_MASK, tip_deb);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK |
+ CS42L43_AUTO_HSDET_TIME_MASK, hs2);
+
+done:
+ ret = 0;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |
+ CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,
+ CS42L43_RING_SENSE_EN_MASK, pdncntl);
+
+ dev_dbg(priv->dev, "Successfully configured accessory detect\n");
+
+error:
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return ret;
+}
+
+static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT;
+
+ dev_dbg(priv->dev, "Start headset bias\n");
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);
+
+ if (!type_detect) {
+ if (priv->bias_low)
+ val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT;
+
+ if (priv->bias_sense_ua)
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_HSBIAS_SENSE_EN_MASK |
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
+ CS42L43_HSBIAS_SENSE_EN_MASK |
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, val);
+
+ msleep(priv->bias_ramp_ms);
+}
+
+static void cs42l43_stop_hs_bias(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Stop headset bias\n");
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, 0);
+
+ if (priv->bias_sense_ua) {
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_HSBIAS_SENSE_EN_MASK |
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0);
+ }
+}
+
+irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+
+ queue_delayed_work(system_dfl_wq, &priv->bias_sense_timeout,
+ msecs_to_jiffies(1000));
+
+ return IRQ_HANDLED;
+}
+
+#define CS42L43_JACK_PRESENT 0x3
+#define CS42L43_JACK_ABSENT 0x0
+
+#define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT)
+#define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE)
+#define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET)
+#define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
+#define CS42L43_JACK_LINEIN (SND_JACK_MECHANICAL | SND_JACK_LINEIN)
+#define CS42L43_JACK_EXTENSION (SND_JACK_MECHANICAL)
+#define CS42L43_JACK_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | \
+ SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5)
+
+static inline bool cs42l43_jack_present(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int sts = 0;
+
+ regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts);
+
+ sts = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;
+
+ return sts == CS42L43_JACK_PRESENT;
+}
+
+static void cs42l43_start_button_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val = 0x3 << CS42L43_BUTTON_DETECT_MODE_SHIFT;
+
+ dev_dbg(priv->dev, "Start button detect\n");
+
+ priv->button_detect_running = true;
+
+ if (priv->bias_low)
+ val = 0x1 << CS42L43_BUTTON_DETECT_MODE_SHIFT;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_BUTTON_DETECT_MODE_MASK |
+ CS42L43_MIC_LVL_DET_DISABLE_MASK, val);
+}
+
+static void cs42l43_stop_button_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Stop button detect\n");
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_BUTTON_DETECT_MODE_MASK |
+ CS42L43_MIC_LVL_DET_DISABLE_MASK,
+ CS42L43_MIC_LVL_DET_DISABLE_MASK);
+
+ priv->button_detect_running = false;
+}
+
+#define CS42L43_BUTTON_COMB_US 11000
+#define CS42L43_BUTTON_COMB_MAX 512
+#define CS42L43_BUTTON_ROUT 2210
+
+irqreturn_t cs42l43_button_press(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ struct cs42l43 *cs42l43 = priv->core;
+ irqreturn_t iret = IRQ_NONE;
+ unsigned int buttons = 0;
+ unsigned int val = 0;
+ int i, ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for button press: %d\n", ret);
+ return iret;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ if (!priv->button_detect_running) {
+ dev_dbg(priv->dev, "Spurious button press IRQ\n");
+ goto error;
+ }
+
+ // Wait for 2 full cycles of comb filter to ensure good reading
+ usleep_range(2 * CS42L43_BUTTON_COMB_US, 2 * CS42L43_BUTTON_COMB_US + 50);
+
+ regmap_read(cs42l43->regmap, CS42L43_DETECT_STATUS_1, &val);
+
+ /* Bail if jack removed, the button is irrelevant and likely invalid */
+ if (!cs42l43_jack_present(priv)) {
+ dev_dbg(priv->dev, "Button ignored due to removal\n");
+ goto error;
+ }
+
+ if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) {
+ dev_dbg(priv->dev, "Button ignored due to bias sense\n");
+ goto error;
+ }
+
+ val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT;
+ val = ((CS42L43_BUTTON_COMB_MAX << 20) / (val + 1)) - (1 << 20);
+ if (val)
+ val = (CS42L43_BUTTON_ROUT << 20) / val;
+ else
+ val = UINT_MAX;
+
+ for (i = 0; i < CS42L43_N_BUTTONS; i++) {
+ if (val < priv->buttons[i]) {
+ buttons = SND_JACK_BTN_0 >> i;
+ dev_dbg(priv->dev, "Detected button %d at %d Ohms\n", i, val);
+ break;
+ }
+ }
+
+ if (!buttons)
+ dev_dbg(priv->dev, "Unrecognised button: %d Ohms\n", val);
+
+ snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS);
+
+ iret = IRQ_HANDLED;
+
+error:
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return iret;
+}
+
+irqreturn_t cs42l43_button_release(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ irqreturn_t iret = IRQ_NONE;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for button release: %d\n", ret);
+ return iret;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ if (priv->button_detect_running) {
+ dev_dbg(priv->dev, "Button release IRQ\n");
+
+ snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);
+
+ iret = IRQ_HANDLED;
+ } else {
+ dev_dbg(priv->dev, "Spurious button release IRQ\n");
+ }
+
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return iret;
+}
+
+void cs42l43_bias_sense_timeout(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ bias_sense_timeout.work);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret);
+ return;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ if (cs42l43_jack_present(priv) && priv->button_detect_running) {
+ dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n");
+
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
+ }
+
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_put_autosuspend(priv->dev);
+}
+
+static void cs42l43_start_load_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Start load detect\n");
+
+ snd_soc_dapm_mutex_lock(snd_soc_component_to_dapm(priv->component));
+
+ priv->load_detect_running = true;
+
+ if (priv->hp_ena && !priv->hp_ilimited) {
+ unsigned long time_left;
+
+ reinit_completion(&priv->hp_shutdown);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, 0);
+
+ time_left = wait_for_completion_timeout(&priv->hp_shutdown,
+ msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
+ if (!time_left)
+ dev_err(priv->dev, "Load detect HP power down timed out\n");
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
+ CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL,
+ CS42L43_ADPTPWR_MODE_MASK, 0x4 << CS42L43_ADPTPWR_MODE_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL,
+ CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, 0x6);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1,
+ CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, 0);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA,
+ CS42L43_HPLOAD_DET_EN_MASK,
+ CS42L43_HPLOAD_DET_EN_MASK);
+
+ snd_soc_dapm_mutex_unlock(snd_soc_component_to_dapm(priv->component));
+}
+
+static void cs42l43_stop_load_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Stop load detect\n");
+
+ snd_soc_dapm_mutex_lock(snd_soc_component_to_dapm(priv->component));
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA,
+ CS42L43_HPLOAD_DET_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1,
+ CS42L43_HP_MSTR_VOL_CTRL_EN_MASK,
+ CS42L43_HP_MSTR_VOL_CTRL_EN_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL,
+ CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK,
+ 0x4 << CS42L43_HP_DIG_VOL_RAMP_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL,
+ CS42L43_ADPTPWR_MODE_MASK, 0x7 << CS42L43_ADPTPWR_MODE_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2,
+ CS42L43_HP_HPF_EN_MASK, CS42L43_HP_HPF_EN_MASK);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
+ CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK,
+ priv->adc_ena);
+
+ if (priv->hp_ena && !priv->hp_ilimited) {
+ unsigned long time_left;
+
+ reinit_completion(&priv->hp_startup);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, priv->hp_ena);
+
+ time_left = wait_for_completion_timeout(&priv->hp_startup,
+ msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
+ if (!time_left)
+ dev_err(priv->dev, "Load detect HP restore timed out\n");
+ }
+
+ priv->load_detect_running = false;
+
+ snd_soc_dapm_mutex_unlock(snd_soc_component_to_dapm(priv->component));
+}
+
+static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val = 0;
+ unsigned long time_left;
+
+ reinit_completion(&priv->load_detect);
+
+ cs42l43_start_load_detect(priv);
+ time_left = wait_for_completion_timeout(&priv->load_detect,
+ msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS));
+ cs42l43_stop_load_detect(priv);
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ regmap_read(cs42l43->regmap, CS42L43_LOADDETRESULTS, &val);
+
+ dev_dbg(priv->dev, "Headphone load detect: 0x%x\n", val);
+
+ /* Bail if jack removed, the load is irrelevant and likely invalid */
+ if (!cs42l43_jack_present(priv))
+ return -ENODEV;
+
+ if (mic) {
+ cs42l43_start_hs_bias(priv, false);
+ cs42l43_start_button_detect(priv);
+
+ return CS42L43_JACK_HEADSET;
+ }
+
+ switch (val & CS42L43_AMP3_RES_DET_MASK) {
+ case 0x0: // low impedance
+ case 0x1: // high impedance
+ return CS42L43_JACK_HEADPHONE;
+ case 0x2: // lineout
+ case 0x3: // Open circuit
+ return CS42L43_JACK_LINEOUT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cs42l43_run_type_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ int timeout_ms = ((2 * priv->detect_us) / USEC_PER_MSEC) + 200;
+ unsigned int type = 0xff;
+ unsigned long time_left;
+
+ reinit_completion(&priv->type_detect);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK);
+
+ cs42l43_start_hs_bias(priv, true);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT);
+
+ time_left = wait_for_completion_timeout(&priv->type_detect,
+ msecs_to_jiffies(timeout_ms));
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT);
+ cs42l43_stop_hs_bias(priv);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, 0);
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ regmap_read(cs42l43->regmap, CS42L43_HS_STAT, &type);
+
+ dev_dbg(priv->dev, "Type detect: 0x%x\n", type);
+
+ /* Bail if jack removed, the type is irrelevant and likely invalid */
+ if (!cs42l43_jack_present(priv))
+ return -ENODEV;
+
+ switch (type & CS42L43_HSDET_TYPE_STS_MASK) {
+ case 0x0: // CTIA
+ case 0x1: // OMTP
+ return cs42l43_run_load_detect(priv, true);
+ case 0x2: // 3-pole
+ return cs42l43_run_load_detect(priv, false);
+ case 0x3: // Open-circuit
+ return CS42L43_JACK_EXTENSION;
+ default:
+ return -EINVAL;
+ }
+}
+
+void cs42l43_clear_jack(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ cs42l43_stop_button_detect(priv);
+ cs42l43_stop_hs_bias(priv);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,
+ CS42L43_JACK_STEREO_CONFIG_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK,
+ 0x2 << CS42L43_HSDET_MODE_SHIFT);
+}
+
+void cs42l43_tip_sense_work(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ tip_sense_work.work);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int sts = 0;
+ unsigned int tip, ring;
+ int ret, report;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for tip work: %d\n", ret);
+ return;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts);
+
+ dev_dbg(priv->dev, "Tip sense: 0x%x\n", sts);
+
+ tip = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;
+ ring = (sts >> CS42L43_RINGSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;
+
+ if (tip == CS42L43_JACK_PRESENT) {
+ if (cs42l43->sdw && !priv->jack_present) {
+ priv->jack_present = true;
+ pm_runtime_get(priv->dev);
+ }
+
+ if (priv->use_ring_sense && ring == CS42L43_JACK_ABSENT) {
+ report = CS42L43_JACK_OPTICAL;
+ } else {
+ report = cs42l43_run_type_detect(priv);
+ if (report < 0) {
+ dev_err(priv->dev, "Jack detect failed: %d\n", report);
+ goto error;
+ }
+ }
+
+ snd_soc_jack_report(priv->jack_hp, report, report);
+ } else {
+ priv->jack_override = 0;
+
+ cs42l43_clear_jack(priv);
+
+ snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF);
+
+ if (cs42l43->sdw && priv->jack_present) {
+ pm_runtime_put(priv->dev);
+ priv->jack_present = false;
+ }
+ }
+
+error:
+ mutex_unlock(&priv->jack_lock);
+
+ priv->suspend_jack_debounce = false;
+
+ pm_runtime_put_autosuspend(priv->dev);
+}
+
+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);
+
+ // 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(db_delay));
+
+ return IRQ_HANDLED;
+}
+
+enum cs42l43_raw_jack {
+ CS42L43_JACK_RAW_CTIA = 0,
+ CS42L43_JACK_RAW_OMTP,
+ CS42L43_JACK_RAW_HEADPHONE,
+ CS42L43_JACK_RAW_LINE_OUT,
+ CS42L43_JACK_RAW_LINE_IN,
+ CS42L43_JACK_RAW_MICROPHONE,
+ CS42L43_JACK_RAW_OPTICAL,
+};
+
+#define CS42L43_JACK_3_POLE_SWITCHES ((0x2 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | \
+ CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | \
+ CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | \
+ CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | \
+ CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | \
+ CS42L43_HSGND_HS3_SEL_MASK | \
+ CS42L43_HSGND_HS4_SEL_MASK)
+
+static const struct cs42l43_jack_override_mode {
+ unsigned int hsdet_mode;
+ unsigned int mic_ctrl;
+ unsigned int clamp_ctrl;
+ int report;
+} cs42l43_jack_override_modes[] = {
+ [CS42L43_JACK_RAW_CTIA] = {
+ .hsdet_mode = CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS4_SEL_MASK |
+ CS42L43_HSGND_HS3_SEL_MASK,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_HEADSET,
+ },
+ [CS42L43_JACK_RAW_OMTP] = {
+ .hsdet_mode = (0x1 << CS42L43_HSDET_MANUAL_MODE_SHIFT) |
+ CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS3_SEL_MASK |
+ CS42L43_HSGND_HS4_SEL_MASK,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_HEADSET,
+ },
+ [CS42L43_JACK_RAW_HEADPHONE] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_HEADPHONE,
+ },
+ [CS42L43_JACK_RAW_LINE_OUT] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_LINEOUT,
+ },
+ [CS42L43_JACK_RAW_LINE_IN] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .mic_ctrl = 0x2 << CS42L43_JACK_STEREO_CONFIG_SHIFT,
+ .report = CS42L43_JACK_LINEIN,
+ },
+ [CS42L43_JACK_RAW_MICROPHONE] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) |
+ CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK,
+ .report = CS42L43_JACK_LINEIN,
+ },
+ [CS42L43_JACK_RAW_OPTICAL] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_OPTICAL,
+ },
+};
+
+static const char * const cs42l43_jack_text[] = {
+ "None", "CTIA", "OMTP", "Headphone", "Line-Out",
+ "Line-In", "Microphone", "Optical",
+};
+
+static_assert(ARRAY_SIZE(cs42l43_jack_override_modes) ==
+ ARRAY_SIZE(cs42l43_jack_text) - 1);
+
+SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_jack_enum, cs42l43_jack_text);
+
+int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&priv->jack_lock);
+ ucontrol->value.integer.value[0] = priv->jack_override;
+ mutex_unlock(&priv->jack_lock);
+
+ return 0;
+}
+
+int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int override = ucontrol->value.integer.value[0];
+
+ if (override >= e->items)
+ return -EINVAL;
+
+ mutex_lock(&priv->jack_lock);
+
+ if (!cs42l43_jack_present(priv)) {
+ mutex_unlock(&priv->jack_lock);
+ return -EBUSY;
+ }
+
+ if (override == priv->jack_override) {
+ mutex_unlock(&priv->jack_lock);
+ return 0;
+ }
+
+ priv->jack_override = override;
+
+ cs42l43_clear_jack(priv);
+
+ snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF);
+
+ if (!override) {
+ queue_delayed_work(system_long_wq, &priv->tip_sense_work, 0);
+ } else {
+ override--;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK |
+ CS42L43_HSDET_MANUAL_MODE_MASK |
+ CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK |
+ CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS3_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS4_SEL_MASK |
+ CS42L43_HSGND_HS3_SEL_MASK |
+ CS42L43_HSGND_HS4_SEL_MASK,
+ cs42l43_jack_override_modes[override].hsdet_mode);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,
+ CS42L43_HS2_BIAS_EN_MASK | CS42L43_HS1_BIAS_EN_MASK |
+ CS42L43_JACK_STEREO_CONFIG_MASK,
+ cs42l43_jack_override_modes[override].mic_ctrl);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ cs42l43_jack_override_modes[override].clamp_ctrl);
+
+ switch (override) {
+ case CS42L43_JACK_RAW_CTIA:
+ case CS42L43_JACK_RAW_OMTP:
+ cs42l43_start_hs_bias(priv, false);
+ cs42l43_start_button_detect(priv);
+ break;
+ case CS42L43_JACK_RAW_LINE_IN:
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK);
+ break;
+ case CS42L43_JACK_RAW_MICROPHONE:
+ cs42l43_start_hs_bias(priv, false);
+ break;
+ default:
+ break;
+ }
+
+ snd_soc_jack_report(priv->jack_hp,
+ cs42l43_jack_override_modes[override].report,
+ cs42l43_jack_override_modes[override].report);
+ }
+
+ mutex_unlock(&priv->jack_lock);
+
+ return 1;
+}
diff --git a/sound/soc/codecs/cs42l43-sdw.c b/sound/soc/codecs/cs42l43-sdw.c
new file mode 100644
index 000000000000..336e88a7a987
--- /dev/null
+++ b/sound/soc/codecs/cs42l43-sdw.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 CODEC driver SoundWire handling
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/errno.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/pcm.h>
+#include <sound/sdw.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+
+#include "cs42l43.h"
+
+int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent);
+ struct sdw_stream_config sconfig = {0};
+ struct sdw_port_config pconfig = {0};
+ int ret;
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ snd_sdw_params_to_config(substream, params, &sconfig, &pconfig);
+ pconfig.num = dai->id;
+
+ ret = sdw_stream_add_slave(sdw, &sconfig, &pconfig, 1, sdw_stream);
+ if (ret) {
+ dev_err(priv->dev, "Failed to add sdw stream: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, "SND_SOC_CS42L43");
+
+int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ return sdw_stream_remove_slave(sdw, sdw_stream);
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, "SND_SOC_CS42L43");
+
+int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, "SND_SOC_CS42L43");
+
+MODULE_DESCRIPTION("CS42L43 CODEC SoundWire Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
new file mode 100644
index 000000000000..fd02d8a57e0f
--- /dev/null
+++ b/sound/soc/codecs/cs42l43.c
@@ -0,0 +1,2476 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 CODEC driver
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/build_bug.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/bitmap.h>
+#include <linux/gcd.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <sound/control.h>
+#include <sound/cs42l43.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42l43.h"
+
+#define CS42L43_DECL_MUX(name, reg) \
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_##name##_enum, reg, \
+ 0, CS42L43_MIXER_SRC_MASK, \
+ cs42l43_mixer_texts, cs42l43_mixer_values); \
+static const struct snd_kcontrol_new cs42l43_##name##_mux = \
+ SOC_DAPM_ENUM("Route", cs42l43_##name##_enum)
+
+#define CS42L43_DECL_MIXER(name, reg) \
+ CS42L43_DECL_MUX(name##_in1, reg); \
+ CS42L43_DECL_MUX(name##_in2, reg + 0x4); \
+ CS42L43_DECL_MUX(name##_in3, reg + 0x8); \
+ CS42L43_DECL_MUX(name##_in4, reg + 0xC)
+
+#define CS42L43_DAPM_MUX(name_str, name) \
+ SND_SOC_DAPM_MUX(name_str " Input", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_mux)
+
+#define CS42L43_DAPM_MIXER(name_str, name) \
+ SND_SOC_DAPM_MUX(name_str " Input 1", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in1_mux), \
+ SND_SOC_DAPM_MUX(name_str " Input 2", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in2_mux), \
+ SND_SOC_DAPM_MUX(name_str " Input 3", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in3_mux), \
+ SND_SOC_DAPM_MUX(name_str " Input 4", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in4_mux), \
+ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define CS42L43_BASE_ROUTES(name_str) \
+ { name_str, "Tone Generator 1", "Tone 1" }, \
+ { name_str, "Tone Generator 2", "Tone 2" }, \
+ { name_str, "Decimator 1", "Decimator 1" }, \
+ { name_str, "Decimator 2", "Decimator 2" }, \
+ { name_str, "Decimator 3", "Decimator 3" }, \
+ { name_str, "Decimator 4", "Decimator 4" }, \
+ { name_str, "ASPRX1", "ASPRX1" }, \
+ { name_str, "ASPRX2", "ASPRX2" }, \
+ { name_str, "ASPRX3", "ASPRX3" }, \
+ { name_str, "ASPRX4", "ASPRX4" }, \
+ { name_str, "ASPRX5", "ASPRX5" }, \
+ { name_str, "ASPRX6", "ASPRX6" }, \
+ { name_str, "DP5RX1", "DP5RX1" }, \
+ { name_str, "DP5RX2", "DP5RX2" }, \
+ { name_str, "DP6RX1", "DP6RX1" }, \
+ { name_str, "DP6RX2", "DP6RX2" }, \
+ { name_str, "DP7RX1", "DP7RX1" }, \
+ { name_str, "DP7RX2", "DP7RX2" }, \
+ { name_str, "ASRC INT1", "ASRC_INT1" }, \
+ { name_str, "ASRC INT2", "ASRC_INT2" }, \
+ { name_str, "ASRC INT3", "ASRC_INT3" }, \
+ { name_str, "ASRC INT4", "ASRC_INT4" }, \
+ { name_str, "ASRC DEC1", "ASRC_DEC1" }, \
+ { name_str, "ASRC DEC2", "ASRC_DEC2" }, \
+ { name_str, "ASRC DEC3", "ASRC_DEC3" }, \
+ { name_str, "ASRC DEC4", "ASRC_DEC4" }, \
+ { name_str, "ISRC1 INT1", "ISRC1INT1" }, \
+ { name_str, "ISRC1 INT2", "ISRC1INT2" }, \
+ { name_str, "ISRC1 DEC1", "ISRC1DEC1" }, \
+ { name_str, "ISRC1 DEC2", "ISRC1DEC2" }, \
+ { name_str, "ISRC2 INT1", "ISRC2INT1" }, \
+ { name_str, "ISRC2 INT2", "ISRC2INT2" }, \
+ { name_str, "ISRC2 DEC1", "ISRC2DEC1" }, \
+ { name_str, "ISRC2 DEC2", "ISRC2DEC2" }, \
+ { name_str, "EQ1", "EQ" }, \
+ { name_str, "EQ2", "EQ" }
+
+#define CS42L43_MUX_ROUTES(name_str, widget) \
+ { widget, NULL, name_str " Input" }, \
+ { name_str " Input", NULL, "Mixer Core" }, \
+ CS42L43_BASE_ROUTES(name_str " Input")
+
+#define CS42L43_MIXER_ROUTES(name_str, widget) \
+ { name_str " Mixer", NULL, name_str " Input 1" }, \
+ { name_str " Mixer", NULL, name_str " Input 2" }, \
+ { name_str " Mixer", NULL, name_str " Input 3" }, \
+ { name_str " Mixer", NULL, name_str " Input 4" }, \
+ { widget, NULL, name_str " Mixer" }, \
+ { name_str " Mixer", NULL, "Mixer Core" }, \
+ CS42L43_BASE_ROUTES(name_str " Input 1"), \
+ CS42L43_BASE_ROUTES(name_str " Input 2"), \
+ CS42L43_BASE_ROUTES(name_str " Input 3"), \
+ CS42L43_BASE_ROUTES(name_str " Input 4")
+
+#define CS42L43_MIXER_VOLUMES(name_str, base) \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 1 Volume", base, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 2 Volume", base + 4, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 3 Volume", base + 8, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 4 Volume", base + 12, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv)
+
+#define CS42L43_IRQ_ERROR(name) \
+static irqreturn_t cs42l43_##name(int irq, void *data) \
+{ \
+ struct cs42l43_codec *priv = data; \
+ dev_err(priv->dev, "Error " #name " IRQ\n"); \
+ return IRQ_HANDLED; \
+}
+
+CS42L43_IRQ_ERROR(pll_lost_lock)
+CS42L43_IRQ_ERROR(spkr_clock_stop)
+CS42L43_IRQ_ERROR(spkl_clock_stop)
+CS42L43_IRQ_ERROR(spkr_brown_out)
+CS42L43_IRQ_ERROR(spkl_brown_out)
+CS42L43_IRQ_ERROR(spkr_therm_shutdown)
+CS42L43_IRQ_ERROR(spkl_therm_shutdown)
+CS42L43_IRQ_ERROR(spkr_therm_warm)
+CS42L43_IRQ_ERROR(spkl_therm_warm)
+CS42L43_IRQ_ERROR(spkr_sc_detect)
+CS42L43_IRQ_ERROR(spkl_sc_detect)
+
+static void cs42l43_hp_ilimit_clear_work(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ hp_ilimit_clear_work.work);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(priv->component);
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ priv->hp_ilimit_count--;
+
+ if (priv->hp_ilimit_count)
+ queue_delayed_work(system_dfl_wq, &priv->hp_ilimit_clear_work,
+ msecs_to_jiffies(CS42L43_HP_ILIMIT_DECAY_MS));
+
+ snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static irqreturn_t cs42l43_hp_ilimit(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(priv->component);
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "headphone ilimit IRQ\n");
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ if (priv->hp_ilimit_count < CS42L43_HP_ILIMIT_MAX_COUNT) {
+ if (!priv->hp_ilimit_count)
+ queue_delayed_work(system_dfl_wq, &priv->hp_ilimit_clear_work,
+ msecs_to_jiffies(CS42L43_HP_ILIMIT_DECAY_MS));
+
+ priv->hp_ilimit_count++;
+ snd_soc_dapm_mutex_unlock(dapm);
+ return IRQ_HANDLED;
+ }
+
+ dev_err(priv->dev, "Disabling headphone for %dmS, due to frequent current limit\n",
+ CS42L43_HP_ILIMIT_BACKOFF_MS);
+
+ priv->hp_ilimited = true;
+
+ // No need to wait for disable, as just disabling for a period of time
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, 0);
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ msleep(CS42L43_HP_ILIMIT_BACKOFF_MS);
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ if (priv->hp_ena && !priv->load_detect_running) {
+ unsigned long time_left;
+
+ reinit_completion(&priv->hp_startup);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, priv->hp_ena);
+
+ time_left = wait_for_completion_timeout(&priv->hp_startup,
+ msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
+ if (!time_left)
+ dev_err(priv->dev, "ilimit HP restore timed out\n");
+ }
+
+ priv->hp_ilimited = false;
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return IRQ_HANDLED;
+}
+
+#define CS42L43_IRQ_COMPLETE(name) \
+static irqreturn_t cs42l43_##name(int irq, void *data) \
+{ \
+ struct cs42l43_codec *priv = data; \
+ dev_dbg(priv->dev, #name " completed\n"); \
+ complete(&priv->name); \
+ return IRQ_HANDLED; \
+}
+
+CS42L43_IRQ_COMPLETE(pll_ready)
+CS42L43_IRQ_COMPLETE(hp_startup)
+CS42L43_IRQ_COMPLETE(hp_shutdown)
+CS42L43_IRQ_COMPLETE(type_detect)
+CS42L43_IRQ_COMPLETE(spkr_shutdown)
+CS42L43_IRQ_COMPLETE(spkl_shutdown)
+CS42L43_IRQ_COMPLETE(spkr_startup)
+CS42L43_IRQ_COMPLETE(spkl_startup)
+CS42L43_IRQ_COMPLETE(load_detect)
+
+static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ struct snd_soc_component *component = priv->component;
+ int i;
+
+ dev_dbg(priv->dev, "Microphone shutter changed\n");
+
+ if (!component)
+ return IRQ_NONE;
+
+ for (i = 1; i < ARRAY_SIZE(priv->kctl); i++) {
+ if (!priv->kctl[i])
+ return IRQ_NONE;
+
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[i]->id);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs42l43_spk_shutter(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ struct snd_soc_component *component = priv->component;
+
+ dev_dbg(priv->dev, "Speaker shutter changed\n");
+
+ if (!component)
+ return IRQ_NONE;
+
+ if (!priv->kctl[0])
+ return IRQ_NONE;
+
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[0]->id);
+
+ return IRQ_HANDLED;
+}
+
+static const unsigned int cs42l43_sample_rates[] = {
+ 8000, 16000, 24000, 32000, 44100, 48000, 96000, 192000,
+};
+
+#define CS42L43_CONSUMER_RATE_MASK 0xFF
+#define CS42L43_PROVIDER_RATE_MASK 0xEF // 44.1k only supported as consumer
+
+static const struct snd_pcm_hw_constraint_list cs42l43_constraint = {
+ .count = ARRAY_SIZE(cs42l43_sample_rates),
+ .list = cs42l43_sample_rates,
+};
+
+static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int provider = !dai->id || !!regmap_test_bits(cs42l43->regmap,
+ CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
+
+ if (provider)
+ priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK;
+ else
+ priv->constraint.mask = CS42L43_CONSUMER_RATE_MASK;
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &priv->constraint);
+}
+
+static int cs42l43_convert_sample_rate(unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return 0x11;
+ case 16000:
+ return 0x12;
+ case 24000:
+ return 0x02;
+ case 32000:
+ return 0x13;
+ case 44100:
+ return 0x0B;
+ case 48000:
+ return 0x03;
+ case 96000:
+ return 0x04;
+ case 192000:
+ return 0x05;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cs42l43_set_sample_rate(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ ret = cs42l43_convert_sample_rate(params_rate(params));
+ if (ret < 0) {
+ dev_err(priv->dev, "Failed to convert sample rate: %d\n", ret);
+ return ret;
+ }
+
+ //FIXME: For now lets just set sample rate 1, this needs expanded in the future
+ regmap_update_bits(cs42l43->regmap, CS42L43_SAMPLE_RATE1,
+ CS42L43_SAMPLE_RATE_MASK, ret);
+
+ return 0;
+}
+
+static int cs42l43_asp_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int dsp_mode = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CTRL,
+ CS42L43_ASP_FSYNC_MODE_MASK);
+ int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
+ int n_chans = params_channels(params);
+ int data_width = params_width(params);
+ int n_slots = n_chans;
+ int slot_width = data_width;
+ int frame, bclk_target, i;
+ unsigned int reg;
+ int *slots;
+
+ if (priv->n_slots) {
+ n_slots = priv->n_slots;
+ slot_width = priv->slot_width;
+ }
+
+ if (!dsp_mode && (n_slots & 0x1)) {
+ dev_dbg(priv->dev, "Forcing balanced channels on ASP\n");
+ n_slots++;
+ }
+
+ frame = n_slots * slot_width;
+ bclk_target = params_rate(params) * frame;
+
+ if (provider) {
+ unsigned int gcd_nm = gcd(bclk_target, CS42L43_INTERNAL_SYSCLK);
+ int n = bclk_target / gcd_nm;
+ int m = CS42L43_INTERNAL_SYSCLK / gcd_nm;
+
+ if (n > (CS42L43_ASP_BCLK_N_MASK >> CS42L43_ASP_BCLK_N_SHIFT) ||
+ m > CS42L43_ASP_BCLK_M_MASK) {
+ dev_err(priv->dev, "Can't produce %dHz bclk\n", bclk_target);
+ return -EINVAL;
+ }
+
+ dev_dbg(priv->dev, "bclk %d/%d = %dHz, with %dx%d frame\n",
+ n, m, bclk_target, n_slots, slot_width);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG1,
+ CS42L43_ASP_BCLK_N_MASK | CS42L43_ASP_BCLK_M_MASK,
+ n << CS42L43_ASP_BCLK_N_SHIFT |
+ m << CS42L43_ASP_BCLK_M_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL1,
+ CS42L43_ASP_FSYNC_M_MASK, frame);
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL4,
+ CS42L43_ASP_NUM_BCLKS_PER_FSYNC_MASK,
+ frame << CS42L43_ASP_NUM_BCLKS_PER_FSYNC_SHIFT);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ reg = CS42L43_ASP_TX_CH1_CTRL;
+ slots = priv->tx_slots;
+ } else {
+ reg = CS42L43_ASP_RX_CH1_CTRL;
+ slots = priv->rx_slots;
+ }
+
+ for (i = 0; i < n_chans; i++, reg += 4) {
+ int slot_phase = dsp_mode | (i & CS42L43_ASP_CH_SLOT_PHASE_MASK);
+ int slot_pos;
+
+ if (dsp_mode)
+ slot_pos = slots[i] * slot_width;
+ else
+ slot_pos = (slots[i] / 2) * slot_width;
+
+ dev_dbg(priv->dev, "Configure channel %d at slot %d (%d,%d)\n",
+ i, slots[i], slot_pos, slot_phase);
+
+ regmap_update_bits(cs42l43->regmap, reg,
+ CS42L43_ASP_CH_WIDTH_MASK |
+ CS42L43_ASP_CH_SLOT_MASK |
+ CS42L43_ASP_CH_SLOT_PHASE_MASK,
+ ((data_width - 1) << CS42L43_ASP_CH_WIDTH_SHIFT) |
+ (slot_pos << CS42L43_ASP_CH_SLOT_SHIFT) |
+ slot_phase);
+ }
+
+ return cs42l43_set_sample_rate(substream, params, dai);
+}
+
+static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int provider = regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
+ struct snd_soc_dapm_route routes[] = {
+ { "BCLK", NULL, "FSYNC" },
+ };
+ unsigned int asp_ctrl = 0;
+ unsigned int data_ctrl = 0;
+ unsigned int fsync_ctrl = 0;
+ unsigned int clk_config = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT;
+ fallthrough;
+ case SND_SOC_DAIFMT_DSP_B:
+ asp_ctrl |= CS42L43_ASP_FSYNC_MODE_MASK;
+ data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK;
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported DAI format 0x%x\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ if (provider)
+ snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
+ break;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ if (!provider)
+ snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
+ clk_config |= CS42L43_ASP_MASTER_MODE_MASK;
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported ASP mode 0x%x\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ clk_config |= CS42L43_ASP_BCLK_INV_MASK; /* Yes BCLK_INV = NB */
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ clk_config |= CS42L43_ASP_BCLK_INV_MASK;
+ fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK |
+ CS42L43_ASP_FSYNC_OUT_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK |
+ CS42L43_ASP_FSYNC_OUT_INV_MASK;
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported invert mode 0x%x\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CTRL,
+ CS42L43_ASP_FSYNC_MODE_MASK,
+ asp_ctrl);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_DATA_CTRL,
+ CS42L43_ASP_FSYNC_FRAME_START_DLY_MASK |
+ CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK,
+ data_ctrl);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK |
+ CS42L43_ASP_BCLK_INV_MASK,
+ clk_config);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL3,
+ CS42L43_ASP_FSYNC_IN_INV_MASK |
+ CS42L43_ASP_FSYNC_OUT_INV_MASK,
+ fsync_ctrl);
+
+ return 0;
+}
+
+static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned long mask,
+ int *slots, unsigned int nslots)
+{
+ int i = 0;
+ int slot;
+
+ for_each_set_bit(slot, &mask, BITS_PER_TYPE(mask)) {
+ if (i == nslots) {
+ dev_warn(priv->dev, "Too many channels in TDM mask: %lx\n",
+ mask);
+ return;
+ }
+
+ slots[i++] = slot;
+ }
+
+}
+
+static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ priv->n_slots = slots;
+ priv->slot_width = slot_width;
+
+ if (!slots) {
+ tx_mask = CS42L43_DEFAULT_SLOTS;
+ rx_mask = CS42L43_DEFAULT_SLOTS;
+ }
+
+ cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots,
+ ARRAY_SIZE(priv->tx_slots));
+ cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots,
+ ARRAY_SIZE(priv->rx_slots));
+
+ return 0;
+}
+
+static int cs42l43_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ static const char * const controls[] = {
+ "Speaker Digital Switch",
+ "Decimator 1 Switch",
+ "Decimator 2 Switch",
+ "Decimator 3 Switch",
+ "Decimator 4 Switch",
+ };
+ int i;
+
+ static_assert(ARRAY_SIZE(controls) == ARRAY_SIZE(priv->kctl));
+
+ for (i = 0; i < ARRAY_SIZE(controls); i++) {
+ if (priv->kctl[i])
+ continue;
+
+ priv->kctl[i] = snd_soc_component_get_kcontrol(component, controls[i]);
+ }
+
+ return 0;
+}
+
+static int cs42l43_dai_remove(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->kctl); i++)
+ priv->kctl[i] = NULL;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs42l43_asp_ops = {
+ .probe = cs42l43_dai_probe,
+ .remove = cs42l43_dai_remove,
+ .startup = cs42l43_startup,
+ .hw_params = cs42l43_asp_hw_params,
+ .set_fmt = cs42l43_asp_set_fmt,
+ .set_tdm_slot = cs42l43_asp_set_tdm_slot,
+};
+
+static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = cs42l43_sdw_add_peripheral(substream, params, dai);
+ if (ret)
+ return ret;
+
+ return cs42l43_set_sample_rate(substream, params, dai);
+}
+
+static const struct snd_soc_dai_ops cs42l43_sdw_ops = {
+ .probe = cs42l43_dai_probe,
+ .remove = cs42l43_dai_remove,
+ .startup = cs42l43_startup,
+ .set_stream = cs42l43_sdw_set_stream,
+ .hw_params = cs42l43_sdw_hw_params,
+ .hw_free = cs42l43_sdw_remove_peripheral,
+};
+
+#define CS42L43_ASP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+#define CS42L43_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver cs42l43_dais[] = {
+ {
+ .name = "cs42l43-asp",
+ .ops = &cs42l43_asp_ops,
+ .symmetric_rate = 1,
+ .capture = {
+ .stream_name = "ASP Capture",
+ .channels_min = 1,
+ .channels_max = CS42L43_ASP_MAX_CHANNELS,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_ASP_FORMATS,
+ },
+ .playback = {
+ .stream_name = "ASP Playback",
+ .channels_min = 1,
+ .channels_max = CS42L43_ASP_MAX_CHANNELS,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_ASP_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp1",
+ .id = 1,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP1 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp2",
+ .id = 2,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp3",
+ .id = 3,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP3 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp4",
+ .id = 4,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP4 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp5",
+ .id = 5,
+ .ops = &cs42l43_sdw_ops,
+ .playback = {
+ .stream_name = "DP5 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp6",
+ .id = 6,
+ .ops = &cs42l43_sdw_ops,
+ .playback = {
+ .stream_name = "DP6 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp7",
+ .id = 7,
+ .ops = &cs42l43_sdw_ops,
+ .playback = {
+ .stream_name = "DP7 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+};
+
+static const DECLARE_TLV_DB_SCALE(cs42l43_mixer_tlv, -3200, 100, 0);
+
+static const char * const cs42l43_ramp_text[] = {
+ "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+ "15ms/6dB", "30ms/6dB",
+};
+
+static const char * const cs42l43_adc1_input_text[] = { "IN1", "IN2" };
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_adc1_input, CS42L43_ADC_B_CTRL1,
+ CS42L43_ADC_AIN_SEL_SHIFT,
+ cs42l43_adc1_input_text);
+
+static const struct snd_kcontrol_new cs42l43_adc1_input_ctl =
+ SOC_DAPM_ENUM("ADC1 Input", cs42l43_adc1_input);
+
+static const char * const cs42l43_dec_mode_text[] = { "ADC", "PDM" };
+
+static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec1_mode, cs42l43_dec_mode_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec2_mode, cs42l43_dec_mode_text);
+
+static const struct snd_kcontrol_new cs42l43_dec_mode_ctl[] = {
+ SOC_DAPM_ENUM("Decimator 1 Mode", cs42l43_dec1_mode),
+ SOC_DAPM_ENUM("Decimator 2 Mode", cs42l43_dec2_mode),
+};
+
+static const char * const cs42l43_pdm_clk_text[] = {
+ "3.072MHz", "1.536MHz", "768kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_pdm1_clk, CS42L43_PDM_CONTROL,
+ CS42L43_PDM1_CLK_DIV_SHIFT, cs42l43_pdm_clk_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_pdm2_clk, CS42L43_PDM_CONTROL,
+ CS42L43_PDM2_CLK_DIV_SHIFT, cs42l43_pdm_clk_text);
+
+static DECLARE_TLV_DB_SCALE(cs42l43_adc_tlv, -600, 600, 0);
+static DECLARE_TLV_DB_SCALE(cs42l43_dec_tlv, -6400, 50, 0);
+
+static const char * const cs42l43_wnf_corner_text[] = {
+ "160Hz", "180Hz", "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+
+static const char * const cs42l43_hpf_corner_text[] = {
+ "3Hz", "12Hz", "48Hz", "96Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text);
+
+static DECLARE_TLV_DB_SCALE(cs42l43_speaker_tlv, -6400, 50, 0);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_up, CS42L43_AMP1_2_VOL_RAMP,
+ CS42L43_AMP1_2_VI_RAMP_SHIFT, cs42l43_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_down, CS42L43_AMP1_2_VOL_RAMP,
+ CS42L43_AMP1_2_VD_RAMP_SHIFT, cs42l43_ramp_text);
+
+static DECLARE_TLV_DB_SCALE(cs42l43_headphone_tlv, -11450, 50, 1);
+
+static const char * const cs42l43_headphone_ramp_text[] = {
+ "1", "2", "4", "6", "8", "11", "12", "16", "22", "24", "33", "36", "44",
+ "48", "66", "72",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_headphone_ramp, CS42L43_PGAVOL,
+ CS42L43_HP_PATH_VOL_RAMP_SHIFT,
+ cs42l43_headphone_ramp_text);
+
+static const char * const cs42l43_tone_freq_text[] = {
+ "1kHz", "2kHz", "4kHz", "6kHz", "8kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_tone1_freq, CS42L43_TONE_CH1_CTRL,
+ CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_tone2_freq, CS42L43_TONE_CH2_CTRL,
+ CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text);
+
+static const char * const cs42l43_mixer_texts[] = {
+ "None",
+ "Tone Generator 1", "Tone Generator 2",
+ "Decimator 1", "Decimator 2", "Decimator 3", "Decimator 4",
+ "ASPRX1", "ASPRX2", "ASPRX3", "ASPRX4", "ASPRX5", "ASPRX6",
+ "DP5RX1", "DP5RX2", "DP6RX1", "DP6RX2", "DP7RX1", "DP7RX2",
+ "ASRC INT1", "ASRC INT2", "ASRC INT3", "ASRC INT4",
+ "ASRC DEC1", "ASRC DEC2", "ASRC DEC3", "ASRC DEC4",
+ "ISRC1 INT1", "ISRC1 INT2",
+ "ISRC1 DEC1", "ISRC1 DEC2",
+ "ISRC2 INT1", "ISRC2 INT2",
+ "ISRC2 DEC1", "ISRC2 DEC2",
+ "EQ1", "EQ2",
+};
+
+static const unsigned int cs42l43_mixer_values[] = {
+ 0x00, // None
+ 0x04, 0x05, // Tone Generator 1, 2
+ 0x10, 0x11, 0x12, 0x13, // Decimator 1, 2, 3, 4
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, // ASPRX1,2,3,4,5,6
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // DP5, 6, 7RX1, 2
+ 0x40, 0x41, 0x42, 0x43, // ASRC INT1, 2, 3, 4
+ 0x44, 0x45, 0x46, 0x47, // ASRC DEC1, 2, 3, 4
+ 0x50, 0x51, // ISRC1 INT1, 2
+ 0x52, 0x53, // ISRC1 DEC1, 2
+ 0x54, 0x55, // ISRC2 INT1, 2
+ 0x56, 0x57, // ISRC2 DEC1, 2
+ 0x58, 0x59, // EQ1, 2
+};
+
+CS42L43_DECL_MUX(asptx1, CS42L43_ASPTX1_INPUT);
+CS42L43_DECL_MUX(asptx2, CS42L43_ASPTX2_INPUT);
+CS42L43_DECL_MUX(asptx3, CS42L43_ASPTX3_INPUT);
+CS42L43_DECL_MUX(asptx4, CS42L43_ASPTX4_INPUT);
+CS42L43_DECL_MUX(asptx5, CS42L43_ASPTX5_INPUT);
+CS42L43_DECL_MUX(asptx6, CS42L43_ASPTX6_INPUT);
+
+CS42L43_DECL_MUX(dp1tx1, CS42L43_SWIRE_DP1_CH1_INPUT);
+CS42L43_DECL_MUX(dp1tx2, CS42L43_SWIRE_DP1_CH2_INPUT);
+CS42L43_DECL_MUX(dp1tx3, CS42L43_SWIRE_DP1_CH3_INPUT);
+CS42L43_DECL_MUX(dp1tx4, CS42L43_SWIRE_DP1_CH4_INPUT);
+CS42L43_DECL_MUX(dp2tx1, CS42L43_SWIRE_DP2_CH1_INPUT);
+CS42L43_DECL_MUX(dp2tx2, CS42L43_SWIRE_DP2_CH2_INPUT);
+CS42L43_DECL_MUX(dp3tx1, CS42L43_SWIRE_DP3_CH1_INPUT);
+CS42L43_DECL_MUX(dp3tx2, CS42L43_SWIRE_DP3_CH2_INPUT);
+CS42L43_DECL_MUX(dp4tx1, CS42L43_SWIRE_DP4_CH1_INPUT);
+CS42L43_DECL_MUX(dp4tx2, CS42L43_SWIRE_DP4_CH2_INPUT);
+
+CS42L43_DECL_MUX(asrcint1, CS42L43_ASRC_INT1_INPUT1);
+CS42L43_DECL_MUX(asrcint2, CS42L43_ASRC_INT2_INPUT1);
+CS42L43_DECL_MUX(asrcint3, CS42L43_ASRC_INT3_INPUT1);
+CS42L43_DECL_MUX(asrcint4, CS42L43_ASRC_INT4_INPUT1);
+CS42L43_DECL_MUX(asrcdec1, CS42L43_ASRC_DEC1_INPUT1);
+CS42L43_DECL_MUX(asrcdec2, CS42L43_ASRC_DEC2_INPUT1);
+CS42L43_DECL_MUX(asrcdec3, CS42L43_ASRC_DEC3_INPUT1);
+CS42L43_DECL_MUX(asrcdec4, CS42L43_ASRC_DEC4_INPUT1);
+
+CS42L43_DECL_MUX(isrc1int1, CS42L43_ISRC1INT1_INPUT1);
+CS42L43_DECL_MUX(isrc1int2, CS42L43_ISRC1INT2_INPUT1);
+CS42L43_DECL_MUX(isrc1dec1, CS42L43_ISRC1DEC1_INPUT1);
+CS42L43_DECL_MUX(isrc1dec2, CS42L43_ISRC1DEC2_INPUT1);
+CS42L43_DECL_MUX(isrc2int1, CS42L43_ISRC2INT1_INPUT1);
+CS42L43_DECL_MUX(isrc2int2, CS42L43_ISRC2INT2_INPUT1);
+CS42L43_DECL_MUX(isrc2dec1, CS42L43_ISRC2DEC1_INPUT1);
+CS42L43_DECL_MUX(isrc2dec2, CS42L43_ISRC2DEC2_INPUT1);
+
+CS42L43_DECL_MUX(spdif1, CS42L43_SPDIF1_INPUT1);
+CS42L43_DECL_MUX(spdif2, CS42L43_SPDIF2_INPUT1);
+
+CS42L43_DECL_MIXER(eq1, CS42L43_EQ1MIX_INPUT1);
+CS42L43_DECL_MIXER(eq2, CS42L43_EQ2MIX_INPUT1);
+
+CS42L43_DECL_MIXER(amp1, CS42L43_AMP1MIX_INPUT1);
+CS42L43_DECL_MIXER(amp2, CS42L43_AMP2MIX_INPUT1);
+
+CS42L43_DECL_MIXER(amp3, CS42L43_AMP3MIX_INPUT1);
+CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1);
+
+static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_eq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ memcpy(ucontrol->value.integer.value, priv->eq_coeffs, sizeof(priv->eq_coeffs));
+
+ return 0;
+}
+
+static int cs42l43_eq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ memcpy(priv->eq_coeffs, ucontrol->value.integer.value, sizeof(priv->eq_coeffs));
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return 0;
+}
+
+static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ mutex_lock(&priv->spk_vu_lock);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
+ CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
+ CS42L43_AMP1_2_VU_MASK, 0);
+
+ mutex_unlock(&priv->spk_vu_lock);
+}
+
+static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for shutters: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * SHUTTER_CONTROL is a mix of volatile and non-volatile bits, so must
+ * be cached for the non-volatiles, so drop it from the cache here so
+ * we force a read.
+ */
+ ret = regcache_drop_region(cs42l43->regmap, CS42L43_SHUTTER_CONTROL,
+ CS42L43_SHUTTER_CONTROL);
+ if (ret) {
+ dev_err(priv->dev, "Failed to drop shutter from cache: %d\n", ret);
+ goto error;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to check shutter status: %d\n", ret);
+ goto error;
+ }
+
+ ret = !(val & BIT(shift));
+
+ dev_dbg(priv->dev, "%s shutter is %s\n",
+ BIT(shift) == CS42L43_STATUS_MIC_SHUTTER_MUTE_MASK ? "Mic" : "Speaker",
+ ret ? "open" : "closed");
+
+error:
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return ret;
+}
+
+static int cs42l43_decim_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = cs42l43_shutter_get(priv, CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT);
+ if (ret > 0)
+ ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol);
+ else if (!ret)
+ ucontrol->value.integer.value[0] = ret;
+
+ return ret;
+}
+
+static int cs42l43_spk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = cs42l43_shutter_get(priv, CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT);
+ if (ret > 0)
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+ else if (!ret)
+ ucontrol->value.integer.value[0] = ret;
+
+ return ret;
+}
+
+static int cs42l43_spk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret > 0)
+ cs42l43_spk_vu_sync(priv);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new cs42l43_controls[] = {
+ SOC_ENUM_EXT("Jack Override", cs42l43_jack_enum,
+ cs42l43_jack_get, cs42l43_jack_put),
+
+ SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2,
+ CS42L43_ADC_PGA_GAIN_SHIFT,
+ 0xF, 4, cs42l43_adc_tlv),
+
+ SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL,
+ CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0),
+ SOC_DOUBLE("PDM2 Invert Switch", CS42L43_DMIC_PDM_CTRL,
+ CS42L43_PDM2L_INV_SHIFT, CS42L43_PDM2R_INV_SHIFT, 1, 0),
+ SOC_ENUM("PDM1 Clock", cs42l43_pdm1_clk),
+ SOC_ENUM("PDM2 Clock", cs42l43_pdm2_clk),
+
+ SOC_SINGLE("Decimator 1 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 2 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 3 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 4 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+
+ SOC_ENUM("Decimator 1 WNF Corner Frequency", cs42l43_dec1_wnf_corner),
+ SOC_ENUM("Decimator 2 WNF Corner Frequency", cs42l43_dec2_wnf_corner),
+ SOC_ENUM("Decimator 3 WNF Corner Frequency", cs42l43_dec3_wnf_corner),
+ SOC_ENUM("Decimator 4 WNF Corner Frequency", cs42l43_dec4_wnf_corner),
+
+ SOC_SINGLE("Decimator 1 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 2 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 3 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 4 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+
+ SOC_ENUM("Decimator 1 HPF Corner Frequency", cs42l43_dec1_hpf_corner),
+ SOC_ENUM("Decimator 2 HPF Corner Frequency", cs42l43_dec2_hpf_corner),
+ SOC_ENUM("Decimator 3 HPF Corner Frequency", cs42l43_dec3_hpf_corner),
+ SOC_ENUM("Decimator 4 HPF Corner Frequency", cs42l43_dec4_hpf_corner),
+
+ SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+
+ SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43_dec1_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43_dec1_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43_dec2_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43_dec2_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43_dec3_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43_dec3_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43_dec4_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43_dec4_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+
+ SOC_DOUBLE_R_EXT("Speaker Digital Switch",
+ CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
+ CS42L43_AMP_MUTE_SHIFT, 1, 1,
+ cs42l43_spk_get, cs42l43_spk_put),
+
+ SOC_DOUBLE_R_EXT_TLV("Speaker Digital Volume",
+ CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
+ CS42L43_AMP_VOL_SHIFT,
+ 0xBF, 0, snd_soc_get_volsw, cs42l43_spk_put,
+ cs42l43_speaker_tlv),
+
+ SOC_ENUM("Speaker Ramp Up", cs42l43_speaker_ramp_up),
+ SOC_ENUM("Speaker Ramp Down", cs42l43_speaker_ramp_down),
+
+ CS42L43_MIXER_VOLUMES("Speaker L", CS42L43_AMP1MIX_INPUT1),
+ CS42L43_MIXER_VOLUMES("Speaker R", CS42L43_AMP2MIX_INPUT1),
+
+ SOC_DOUBLE_SX_TLV("Headphone Digital Volume", CS42L43_HPPATHVOL,
+ CS42L43_AMP3_PATH_VOL_SHIFT, CS42L43_AMP4_PATH_VOL_SHIFT,
+ 0x11B, 229, cs42l43_headphone_tlv),
+
+ SOC_DOUBLE("Headphone Invert Switch", CS42L43_DACCNFG1,
+ CS42L43_AMP3_INV_SHIFT, CS42L43_AMP4_INV_SHIFT, 1, 0),
+
+ SOC_SINGLE("Headphone Zero Cross Switch", CS42L43_PGAVOL,
+ CS42L43_HP_PATH_VOL_ZC_SHIFT, 1, 0),
+ SOC_SINGLE("Headphone Ramp Switch", CS42L43_PGAVOL,
+ CS42L43_HP_PATH_VOL_SFT_SHIFT, 1, 0),
+ SOC_ENUM("Headphone Ramp Rate", cs42l43_headphone_ramp),
+
+ CS42L43_MIXER_VOLUMES("Headphone L", CS42L43_AMP3MIX_INPUT1),
+ CS42L43_MIXER_VOLUMES("Headphone R", CS42L43_AMP4MIX_INPUT1),
+
+ SOC_ENUM("Tone 1 Frequency", cs42l43_tone1_freq),
+ SOC_ENUM("Tone 2 Frequency", cs42l43_tone2_freq),
+
+ SOC_DOUBLE_EXT("EQ Switch",
+ CS42L43_MUTE_EQ_IN0, CS42L43_MUTE_EQ_CH1_SHIFT,
+ CS42L43_MUTE_EQ_CH2_SHIFT, 1, 1,
+ cs42l43_dapm_get_volsw, cs42l43_dapm_put_volsw),
+
+ SND_SOC_BYTES_E("EQ Coefficients", 0, CS42L43_N_EQ_COEFFS,
+ cs42l43_eq_get, cs42l43_eq_put),
+
+ CS42L43_MIXER_VOLUMES("EQ1", CS42L43_EQ1MIX_INPUT1),
+ CS42L43_MIXER_VOLUMES("EQ2", CS42L43_EQ2MIX_INPUT1),
+};
+
+static int cs42l43_eq_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val;
+ int i, ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0,
+ CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK,
+ CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0,
+ CS42L43_WRITE_MODE_MASK, CS42L43_WRITE_MODE_MASK);
+
+ for (i = 0; i < CS42L43_N_EQ_COEFFS; i++)
+ regmap_write(cs42l43->regmap, CS42L43_COEFF_DATA_IN0,
+ priv->eq_coeffs[i]);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0,
+ CS42L43_WRITE_MODE_MASK, 0);
+
+ return 0;
+ case SND_SOC_DAPM_POST_PMU:
+ ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_INIT_DONE0,
+ val, (val & CS42L43_INITIALIZE_DONE_MASK),
+ 2000, 10000);
+ if (ret)
+ dev_err(priv->dev, "Failed to start EQs: %d\n", ret);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0,
+ CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, 0);
+ return ret;
+ default:
+ return 0;
+ }
+}
+
+struct cs42l43_pll_config {
+ unsigned int freq;
+
+ unsigned int div;
+ unsigned int mode;
+ unsigned int cal;
+};
+
+static const struct cs42l43_pll_config cs42l43_pll_configs[] = {
+ { 2400000, 0x50000000, 0x1, 0xA4 },
+ { 3000000, 0x40000000, 0x1, 0x83 },
+ { 3072000, 0x40000000, 0x3, 0x80 },
+};
+
+static int cs42l43_set_pll(struct cs42l43_codec *priv, unsigned int src,
+ unsigned int freq)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ lockdep_assert_held(&cs42l43->pll_lock);
+
+ if (priv->refclk_src == src && priv->refclk_freq == freq)
+ return 0;
+
+ if (regmap_test_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK)) {
+ dev_err(priv->dev, "PLL active, can't change configuration\n");
+ return -EBUSY;
+ }
+
+ switch (src) {
+ case CS42L43_SYSCLK_MCLK:
+ case CS42L43_SYSCLK_SDW:
+ dev_dbg(priv->dev, "Source PLL from %s at %uHz\n",
+ src ? "SoundWire" : "MCLK", freq);
+
+ priv->refclk_src = src;
+ priv->refclk_freq = freq;
+
+ return 0;
+ default:
+ dev_err(priv->dev, "Invalid PLL source: 0x%x\n", src);
+ return -EINVAL;
+ }
+}
+
+static int cs42l43_enable_pll(struct cs42l43_codec *priv)
+{
+ static const struct reg_sequence enable_seq[] = {
+ { CS42L43_OSC_DIV_SEL, 0x0, },
+ { CS42L43_MCLK_SRC_SEL, CS42L43_OSC_PLL_MCLK_SEL_MASK, 5, },
+ };
+ struct cs42l43 *cs42l43 = priv->core;
+ const struct cs42l43_pll_config *config = NULL;
+ unsigned int div = 0;
+ unsigned int freq = priv->refclk_freq;
+ unsigned long time_left;
+
+ lockdep_assert_held(&cs42l43->pll_lock);
+
+ if (priv->refclk_src == CS42L43_SYSCLK_SDW) {
+ if (!freq)
+ freq = cs42l43->sdw_freq;
+ else if (!cs42l43->sdw_freq)
+ cs42l43->sdw_freq = freq;
+ }
+
+ dev_dbg(priv->dev, "Enabling PLL at %uHz\n", freq);
+
+ div = fls(freq) -
+ fls(cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq);
+ freq >>= div;
+
+ if (div <= CS42L43_PLL_REFCLK_DIV_MASK) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_pll_configs); i++) {
+ if (freq == cs42l43_pll_configs[i].freq) {
+ config = &cs42l43_pll_configs[i];
+ break;
+ }
+ }
+ }
+
+ if (!config) {
+ dev_err(priv->dev, "No suitable PLL config: 0x%x, %uHz\n", div, freq);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_DIV_MASK | CS42L43_PLL_REFCLK_SRC_MASK,
+ div << CS42L43_PLL_REFCLK_DIV_SHIFT |
+ priv->refclk_src << CS42L43_PLL_REFCLK_SRC_SHIFT);
+ regmap_write(cs42l43->regmap, CS42L43_FDIV_FRAC, config->div);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
+ CS42L43_PLL_MODE_BYPASS_500_MASK |
+ CS42L43_PLL_MODE_BYPASS_1029_MASK,
+ config->mode << CS42L43_PLL_MODE_BYPASS_1029_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CAL_RATIO,
+ CS42L43_PLL_CAL_RATIO_MASK, config->cal);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_EN_MASK, CS42L43_PLL_REFCLK_EN_MASK);
+
+ reinit_completion(&priv->pll_ready);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
+ CS42L43_PLL_EN_MASK, CS42L43_PLL_EN_MASK);
+
+ time_left = wait_for_completion_timeout(&priv->pll_ready,
+ msecs_to_jiffies(CS42L43_PLL_TIMEOUT_MS));
+ if (!time_left) {
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
+ CS42L43_PLL_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_EN_MASK, 0);
+
+ dev_err(priv->dev, "Timeout out waiting for PLL\n");
+ return -ETIMEDOUT;
+ }
+
+ if (priv->refclk_src == CS42L43_SYSCLK_SDW)
+ cs42l43->sdw_pll_active = true;
+
+ dev_dbg(priv->dev, "PLL locked in %ums\n", 200 - jiffies_to_msecs(time_left));
+
+ /*
+ * Reads are not allowed over Soundwire without OSC_DIV2_EN or the PLL,
+ * but you can not change to PLL with OSC_DIV2_EN set. So ensure the whole
+ * change over happens under the regmap lock to prevent any reads.
+ */
+ regmap_multi_reg_write(cs42l43->regmap, enable_seq, ARRAY_SIZE(enable_seq));
+
+ return 0;
+}
+
+static int cs42l43_disable_pll(struct cs42l43_codec *priv)
+{
+ static const struct reg_sequence disable_seq[] = {
+ { CS42L43_MCLK_SRC_SEL, 0x0, 5, },
+ { CS42L43_OSC_DIV_SEL, CS42L43_OSC_DIV2_EN_MASK, },
+ };
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Disabling PLL\n");
+
+ lockdep_assert_held(&cs42l43->pll_lock);
+
+ regmap_multi_reg_write(cs42l43->regmap, disable_seq, ARRAY_SIZE(disable_seq));
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_EN_MASK, 0);
+
+ cs42l43->sdw_pll_active = false;
+
+ return 0;
+}
+
+static int cs42l43_pll_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ mutex_lock(&cs42l43->pll_lock);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (priv->refclk_src == CS42L43_SYSCLK_MCLK) {
+ ret = clk_prepare_enable(priv->mclk);
+ if (ret) {
+ dev_err(priv->dev, "Failed to enable MCLK: %d\n", ret);
+ break;
+ }
+ }
+
+ ret = cs42l43_enable_pll(priv);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = cs42l43_disable_pll(priv);
+
+ if (priv->refclk_src == CS42L43_SYSCLK_MCLK)
+ clk_disable_unprepare(priv->mclk);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ mutex_unlock(&cs42l43->pll_lock);
+
+ return ret;
+}
+
+static int cs42l43_dapm_wait_completion(struct completion *pmu, struct completion *pmd,
+ int event, int timeout_ms)
+{
+ unsigned long time_left;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ reinit_completion(pmu);
+ return 0;
+ case SND_SOC_DAPM_PRE_PMD:
+ reinit_completion(pmd);
+ return 0;
+ case SND_SOC_DAPM_POST_PMU:
+ time_left = wait_for_completion_timeout(pmu, msecs_to_jiffies(timeout_ms));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ time_left = wait_for_completion_timeout(pmd, msecs_to_jiffies(timeout_ms));
+ break;
+ default:
+ return 0;
+ }
+
+ if (!time_left)
+ return -ETIMEDOUT;
+ else
+ return 0;
+}
+
+static int cs42l43_spkr_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ return cs42l43_dapm_wait_completion(&priv->spkr_startup,
+ &priv->spkr_shutdown, event,
+ CS42L43_SPK_TIMEOUT_MS);
+}
+
+static int cs42l43_spkl_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ return cs42l43_dapm_wait_completion(&priv->spkl_startup,
+ &priv->spkl_shutdown, event,
+ CS42L43_SPK_TIMEOUT_MS);
+}
+
+static int cs42l43_hp_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int mask = 1 << w->shift;
+ unsigned int val = 0;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ val = mask;
+ fallthrough;
+ case SND_SOC_DAPM_PRE_PMD:
+ priv->hp_ena &= ~mask;
+ priv->hp_ena |= val;
+
+ ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
+ &priv->hp_shutdown, event,
+ CS42L43_HP_TIMEOUT_MS);
+ if (ret)
+ return ret;
+
+ if (!priv->load_detect_running && !priv->hp_ilimited)
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ mask, val);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ if (priv->load_detect_running || priv->hp_ilimited)
+ break;
+
+ ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
+ &priv->hp_shutdown, event,
+ CS42L43_HP_TIMEOUT_MS);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l43_mic_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int reg, ramp, mute;
+ unsigned int *val;
+ int ret;
+
+ switch (w->shift) {
+ case CS42L43_ADC1_EN_SHIFT:
+ case CS42L43_PDM1_DIN_L_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM1_VD_RAMP_MASK;
+ mute = CS42L43_DECIM1_MUTE_MASK;
+ val = &priv->decim_cache[0];
+ break;
+ case CS42L43_ADC2_EN_SHIFT:
+ case CS42L43_PDM1_DIN_R_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM2_VD_RAMP_MASK;
+ mute = CS42L43_DECIM2_MUTE_MASK;
+ val = &priv->decim_cache[1];
+ break;
+ case CS42L43_PDM2_DIN_L_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM3_VD_RAMP_MASK;
+ mute = CS42L43_DECIM3_MUTE_MASK;
+ val = &priv->decim_cache[2];
+ break;
+ case CS42L43_PDM2_DIN_R_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM4_VD_RAMP_MASK;
+ mute = CS42L43_DECIM4_MUTE_MASK;
+ val = &priv->decim_cache[3];
+ break;
+ default:
+ dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regmap_read(cs42l43->regmap, reg, val);
+ if (ret) {
+ dev_err(priv->dev,
+ "Failed to cache decimator settings: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_update_bits(cs42l43->regmap, reg, mute | ramp, mute);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(cs42l43->regmap, reg, mute | ramp, *val);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l43_adc_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 cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int mask = 1 << w->shift;
+ unsigned int val = 0;
+ int ret;
+
+ ret = cs42l43_mic_ev(w, kcontrol, event);
+ if (ret)
+ return ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ val = mask;
+ fallthrough;
+ case SND_SOC_DAPM_PRE_PMD:
+ priv->adc_ena &= ~mask;
+ priv->adc_ena |= val;
+
+ if (!priv->load_detect_running)
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
+ mask, val);
+ fallthrough;
+ default:
+ return 0;
+ }
+}
+
+static const struct snd_soc_dapm_widget cs42l43_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, cs42l43_pll_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("ADC1_IN1_P"),
+ SND_SOC_DAPM_INPUT("ADC1_IN1_N"),
+ SND_SOC_DAPM_INPUT("ADC1_IN2_P"),
+ SND_SOC_DAPM_INPUT("ADC1_IN2_N"),
+ SND_SOC_DAPM_INPUT("ADC2_IN_P"),
+ SND_SOC_DAPM_INPUT("ADC2_IN_N"),
+
+ SND_SOC_DAPM_INPUT("PDM1_DIN"),
+ SND_SOC_DAPM_INPUT("PDM2_DIN"),
+
+ SND_SOC_DAPM_MUX("ADC1 Input", SND_SOC_NOPM, 0, 0, &cs42l43_adc1_input_ctl),
+
+ SND_SOC_DAPM_PGA_E("ADC1", SND_SOC_NOPM, CS42L43_ADC1_EN_SHIFT, 0, NULL, 0,
+ cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("ADC2", SND_SOC_NOPM, CS42L43_ADC2_EN_SHIFT, 0, NULL, 0,
+ cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA_E("PDM1L", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_L_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("PDM1R", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_R_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("PDM2L", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_L_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("PDM2R", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_R_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MUX("Decimator 1 Mode", SND_SOC_NOPM, 0, 0,
+ &cs42l43_dec_mode_ctl[0]),
+ SND_SOC_DAPM_MUX("Decimator 2 Mode", SND_SOC_NOPM, 0, 0,
+ &cs42l43_dec_mode_ctl[1]),
+
+ SND_SOC_DAPM_PGA("Decimator 1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("FSYNC", 0, CS42L43_ASP_CTRL, CS42L43_ASP_FSYNC_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("BCLK", 1, CS42L43_ASP_CTRL, CS42L43_ASP_BCLK_EN_SHIFT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH1_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 1,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH2_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 2,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH3_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 3,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH4_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX5", NULL, 4,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH5_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX6", NULL, 5,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH6_EN_SHIFT, 0),
+
+ SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH1_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 1,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH2_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX3", NULL, 2,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH3_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX4", NULL, 3,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH4_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX5", NULL, 4,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH5_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX6", NULL, 5,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH6_EN_SHIFT, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP1TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP1TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP1TX3", NULL, 2, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP1TX4", NULL, 3, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP2TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP3TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP3TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP4TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("DP5RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP5RX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("DP6RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP6RX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("DP7RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP7RX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-amp", 0, 0),
+
+ SND_SOC_DAPM_PGA_E("AMP1", CS42L43_BLOCK_EN10, CS42L43_AMP1_EN_SHIFT, 0, NULL, 0,
+ cs42l43_spkl_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("AMP2", CS42L43_BLOCK_EN10, CS42L43_AMP2_EN_SHIFT, 0, NULL, 0,
+ cs42l43_spkr_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_OUTPUT("AMP1_OUT_P"),
+ SND_SOC_DAPM_OUTPUT("AMP1_OUT_N"),
+ SND_SOC_DAPM_OUTPUT("AMP2_OUT_P"),
+ SND_SOC_DAPM_OUTPUT("AMP2_OUT_N"),
+
+ SND_SOC_DAPM_PGA("SPDIF", CS42L43_BLOCK_EN11, CS42L43_SPDIF_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("SPDIF_TX"),
+
+ SND_SOC_DAPM_PGA_E("HP", SND_SOC_NOPM, CS42L43_HP_EN_SHIFT, 0, NULL, 0,
+ cs42l43_hp_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("AMP3_OUT"),
+ SND_SOC_DAPM_OUTPUT("AMP4_OUT"),
+
+ SND_SOC_DAPM_SIGGEN("Tone"),
+ SND_SOC_DAPM_SUPPLY("Tone Generator", CS42L43_BLOCK_EN9, CS42L43_TONE_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 1", CS42L43_TONE_CH1_CTRL,
+ CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 2", CS42L43_TONE_CH2_CTRL,
+ CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0),
+
+ SND_SOC_DAPM_SUPPLY("ISRC1", CS42L43_BLOCK_EN5, CS42L43_ISRC1_BANK_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ISRC2", CS42L43_BLOCK_EN5, CS42L43_ISRC2_BANK_EN_SHIFT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ISRC1INT2", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1INT1", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1DEC2", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1DEC1", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ISRC2INT2", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2INT1", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2DEC2", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2DEC1", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("ASRC_INT", CS42L43_BLOCK_EN4,
+ CS42L43_ASRC_INT_BANK_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASRC_DEC", CS42L43_BLOCK_EN4,
+ CS42L43_ASRC_DEC_BANK_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ASRC_INT1", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_INT2", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_INT3", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT3_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_INT4", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT4_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC1", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC2", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC3", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC3_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC4", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC4_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("EQ Clock", CS42L43_BLOCK_EN7, CS42L43_EQ_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("EQ", CS42L43_START_EQZ0, CS42L43_START_FILTER_SHIFT,
+ 0, NULL, 0, cs42l43_eq_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY("Mixer Core", CS42L43_BLOCK_EN6, CS42L43_MIXER_EN_SHIFT,
+ 0, NULL, 0),
+ CS42L43_DAPM_MUX("ASPTX1", asptx1),
+ CS42L43_DAPM_MUX("ASPTX2", asptx2),
+ CS42L43_DAPM_MUX("ASPTX3", asptx3),
+ CS42L43_DAPM_MUX("ASPTX4", asptx4),
+ CS42L43_DAPM_MUX("ASPTX5", asptx5),
+ CS42L43_DAPM_MUX("ASPTX6", asptx6),
+
+ CS42L43_DAPM_MUX("DP1TX1", dp1tx1),
+ CS42L43_DAPM_MUX("DP1TX2", dp1tx2),
+ CS42L43_DAPM_MUX("DP1TX3", dp1tx3),
+ CS42L43_DAPM_MUX("DP1TX4", dp1tx4),
+ CS42L43_DAPM_MUX("DP2TX1", dp2tx1),
+ CS42L43_DAPM_MUX("DP2TX2", dp2tx2),
+ CS42L43_DAPM_MUX("DP3TX1", dp3tx1),
+ CS42L43_DAPM_MUX("DP3TX2", dp3tx2),
+ CS42L43_DAPM_MUX("DP4TX1", dp4tx1),
+ CS42L43_DAPM_MUX("DP4TX2", dp4tx2),
+
+ CS42L43_DAPM_MUX("ASRC INT1", asrcint1),
+ CS42L43_DAPM_MUX("ASRC INT2", asrcint2),
+ CS42L43_DAPM_MUX("ASRC INT3", asrcint3),
+ CS42L43_DAPM_MUX("ASRC INT4", asrcint4),
+ CS42L43_DAPM_MUX("ASRC DEC1", asrcdec1),
+ CS42L43_DAPM_MUX("ASRC DEC2", asrcdec2),
+ CS42L43_DAPM_MUX("ASRC DEC3", asrcdec3),
+ CS42L43_DAPM_MUX("ASRC DEC4", asrcdec4),
+
+ CS42L43_DAPM_MUX("ISRC1INT1", isrc1int1),
+ CS42L43_DAPM_MUX("ISRC1INT2", isrc1int2),
+ CS42L43_DAPM_MUX("ISRC1DEC1", isrc1dec1),
+ CS42L43_DAPM_MUX("ISRC1DEC2", isrc1dec2),
+ CS42L43_DAPM_MUX("ISRC2INT1", isrc2int1),
+ CS42L43_DAPM_MUX("ISRC2INT2", isrc2int2),
+ CS42L43_DAPM_MUX("ISRC2DEC1", isrc2dec1),
+ CS42L43_DAPM_MUX("ISRC2DEC2", isrc2dec2),
+
+ CS42L43_DAPM_MUX("SPDIF1", spdif1),
+ CS42L43_DAPM_MUX("SPDIF2", spdif2),
+
+ CS42L43_DAPM_MIXER("EQ1", eq1),
+ CS42L43_DAPM_MIXER("EQ2", eq2),
+
+ CS42L43_DAPM_MIXER("Speaker L", amp1),
+ CS42L43_DAPM_MIXER("Speaker R", amp2),
+
+ CS42L43_DAPM_MIXER("Headphone L", amp3),
+ CS42L43_DAPM_MIXER("Headphone R", amp4),
+};
+
+static const struct snd_soc_dapm_route cs42l43_routes[] = {
+ { "ADC1_IN1_P", NULL, "PLL" },
+ { "ADC1_IN1_N", NULL, "PLL" },
+ { "ADC1_IN2_P", NULL, "PLL" },
+ { "ADC1_IN2_N", NULL, "PLL" },
+ { "ADC2_IN_P", NULL, "PLL" },
+ { "ADC2_IN_N", NULL, "PLL" },
+ { "PDM1_DIN", NULL, "PLL" },
+ { "PDM2_DIN", NULL, "PLL" },
+ { "AMP1_OUT_P", NULL, "PLL" },
+ { "AMP1_OUT_N", NULL, "PLL" },
+ { "AMP2_OUT_P", NULL, "PLL" },
+ { "AMP2_OUT_N", NULL, "PLL" },
+ { "SPDIF_TX", NULL, "PLL" },
+ { "HP", NULL, "PLL" },
+ { "AMP3_OUT", NULL, "PLL" },
+ { "AMP4_OUT", NULL, "PLL" },
+ { "Tone 1", NULL, "PLL" },
+ { "Tone 2", NULL, "PLL" },
+ { "ASP Playback", NULL, "PLL" },
+ { "ASP Capture", NULL, "PLL" },
+ { "DP1 Capture", NULL, "PLL" },
+ { "DP2 Capture", NULL, "PLL" },
+ { "DP3 Capture", NULL, "PLL" },
+ { "DP4 Capture", NULL, "PLL" },
+ { "DP5 Playback", NULL, "PLL" },
+ { "DP6 Playback", NULL, "PLL" },
+ { "DP7 Playback", NULL, "PLL" },
+
+ { "ADC1 Input", "IN1", "ADC1_IN1_P" },
+ { "ADC1 Input", "IN1", "ADC1_IN1_N" },
+ { "ADC1 Input", "IN2", "ADC1_IN2_P" },
+ { "ADC1 Input", "IN2", "ADC1_IN2_N" },
+
+ { "ADC1", NULL, "ADC1 Input" },
+ { "ADC2", NULL, "ADC2_IN_P" },
+ { "ADC2", NULL, "ADC2_IN_N" },
+
+ { "PDM1L", NULL, "PDM1_DIN" },
+ { "PDM1R", NULL, "PDM1_DIN" },
+ { "PDM2L", NULL, "PDM2_DIN" },
+ { "PDM2R", NULL, "PDM2_DIN" },
+
+ { "Decimator 1 Mode", "PDM", "PDM1L" },
+ { "Decimator 1 Mode", "ADC", "ADC1" },
+ { "Decimator 2 Mode", "PDM", "PDM1R" },
+ { "Decimator 2 Mode", "ADC", "ADC2" },
+
+ { "Decimator 1", NULL, "Decimator 1 Mode" },
+ { "Decimator 2", NULL, "Decimator 2 Mode" },
+ { "Decimator 3", NULL, "PDM2L" },
+ { "Decimator 4", NULL, "PDM2R" },
+
+ { "ASP Capture", NULL, "ASPTX1" },
+ { "ASP Capture", NULL, "ASPTX2" },
+ { "ASP Capture", NULL, "ASPTX3" },
+ { "ASP Capture", NULL, "ASPTX4" },
+ { "ASP Capture", NULL, "ASPTX5" },
+ { "ASP Capture", NULL, "ASPTX6" },
+ { "ASPTX1", NULL, "BCLK" },
+ { "ASPTX2", NULL, "BCLK" },
+ { "ASPTX3", NULL, "BCLK" },
+ { "ASPTX4", NULL, "BCLK" },
+ { "ASPTX5", NULL, "BCLK" },
+ { "ASPTX6", NULL, "BCLK" },
+
+ { "ASPRX1", NULL, "ASP Playback" },
+ { "ASPRX2", NULL, "ASP Playback" },
+ { "ASPRX3", NULL, "ASP Playback" },
+ { "ASPRX4", NULL, "ASP Playback" },
+ { "ASPRX5", NULL, "ASP Playback" },
+ { "ASPRX6", NULL, "ASP Playback" },
+ { "ASPRX1", NULL, "BCLK" },
+ { "ASPRX2", NULL, "BCLK" },
+ { "ASPRX3", NULL, "BCLK" },
+ { "ASPRX4", NULL, "BCLK" },
+ { "ASPRX5", NULL, "BCLK" },
+ { "ASPRX6", NULL, "BCLK" },
+
+ { "DP1 Capture", NULL, "DP1TX1" },
+ { "DP1 Capture", NULL, "DP1TX2" },
+ { "DP1 Capture", NULL, "DP1TX3" },
+ { "DP1 Capture", NULL, "DP1TX4" },
+
+ { "DP2 Capture", NULL, "DP2TX1" },
+ { "DP2 Capture", NULL, "DP2TX2" },
+
+ { "DP3 Capture", NULL, "DP3TX1" },
+ { "DP3 Capture", NULL, "DP3TX2" },
+
+ { "DP4 Capture", NULL, "DP4TX1" },
+ { "DP4 Capture", NULL, "DP4TX2" },
+
+ { "DP5RX1", NULL, "DP5 Playback" },
+ { "DP5RX2", NULL, "DP5 Playback" },
+
+ { "DP6RX1", NULL, "DP6 Playback" },
+ { "DP6RX2", NULL, "DP6 Playback" },
+
+ { "DP7RX1", NULL, "DP7 Playback" },
+ { "DP7RX2", NULL, "DP7 Playback" },
+
+ { "AMP1", NULL, "vdd-amp" },
+ { "AMP2", NULL, "vdd-amp" },
+
+ { "AMP1_OUT_P", NULL, "AMP1" },
+ { "AMP1_OUT_N", NULL, "AMP1" },
+ { "AMP2_OUT_P", NULL, "AMP2" },
+ { "AMP2_OUT_N", NULL, "AMP2" },
+
+ { "SPDIF_TX", NULL, "SPDIF" },
+
+ { "AMP3_OUT", NULL, "HP" },
+ { "AMP4_OUT", NULL, "HP" },
+
+ { "Tone 1", NULL, "Tone" },
+ { "Tone 1", NULL, "Tone Generator" },
+ { "Tone 2", NULL, "Tone" },
+ { "Tone 2", NULL, "Tone Generator" },
+
+ { "ISRC1INT2", NULL, "ISRC1" },
+ { "ISRC1INT1", NULL, "ISRC1" },
+ { "ISRC1DEC2", NULL, "ISRC1" },
+ { "ISRC1DEC1", NULL, "ISRC1" },
+
+ { "ISRC2INT2", NULL, "ISRC2" },
+ { "ISRC2INT1", NULL, "ISRC2" },
+ { "ISRC2DEC2", NULL, "ISRC2" },
+ { "ISRC2DEC1", NULL, "ISRC2" },
+
+ { "ASRC_INT1", NULL, "ASRC_INT" },
+ { "ASRC_INT2", NULL, "ASRC_INT" },
+ { "ASRC_INT3", NULL, "ASRC_INT" },
+ { "ASRC_INT4", NULL, "ASRC_INT" },
+ { "ASRC_DEC1", NULL, "ASRC_DEC" },
+ { "ASRC_DEC2", NULL, "ASRC_DEC" },
+ { "ASRC_DEC3", NULL, "ASRC_DEC" },
+ { "ASRC_DEC4", NULL, "ASRC_DEC" },
+
+ { "EQ", NULL, "EQ Clock" },
+
+ CS42L43_MUX_ROUTES("ASPTX1", "ASPTX1"),
+ CS42L43_MUX_ROUTES("ASPTX2", "ASPTX2"),
+ CS42L43_MUX_ROUTES("ASPTX3", "ASPTX3"),
+ CS42L43_MUX_ROUTES("ASPTX4", "ASPTX4"),
+ CS42L43_MUX_ROUTES("ASPTX5", "ASPTX5"),
+ CS42L43_MUX_ROUTES("ASPTX6", "ASPTX6"),
+
+ CS42L43_MUX_ROUTES("DP1TX1", "DP1TX1"),
+ CS42L43_MUX_ROUTES("DP1TX2", "DP1TX2"),
+ CS42L43_MUX_ROUTES("DP1TX3", "DP1TX3"),
+ CS42L43_MUX_ROUTES("DP1TX4", "DP1TX4"),
+ CS42L43_MUX_ROUTES("DP2TX1", "DP2TX1"),
+ CS42L43_MUX_ROUTES("DP2TX2", "DP2TX2"),
+ CS42L43_MUX_ROUTES("DP3TX1", "DP3TX1"),
+ CS42L43_MUX_ROUTES("DP3TX2", "DP3TX2"),
+ CS42L43_MUX_ROUTES("DP4TX1", "DP4TX1"),
+ CS42L43_MUX_ROUTES("DP4TX2", "DP4TX2"),
+
+ CS42L43_MUX_ROUTES("ASRC INT1", "ASRC_INT1"),
+ CS42L43_MUX_ROUTES("ASRC INT2", "ASRC_INT2"),
+ CS42L43_MUX_ROUTES("ASRC INT3", "ASRC_INT3"),
+ CS42L43_MUX_ROUTES("ASRC INT4", "ASRC_INT4"),
+ CS42L43_MUX_ROUTES("ASRC DEC1", "ASRC_DEC1"),
+ CS42L43_MUX_ROUTES("ASRC DEC2", "ASRC_DEC2"),
+ CS42L43_MUX_ROUTES("ASRC DEC3", "ASRC_DEC3"),
+ CS42L43_MUX_ROUTES("ASRC DEC4", "ASRC_DEC4"),
+
+ CS42L43_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+ CS42L43_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+ CS42L43_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+ CS42L43_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+ CS42L43_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+ CS42L43_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+ CS42L43_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+ CS42L43_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+ CS42L43_MUX_ROUTES("SPDIF1", "SPDIF"),
+ CS42L43_MUX_ROUTES("SPDIF2", "SPDIF"),
+
+ CS42L43_MIXER_ROUTES("EQ1", "EQ"),
+ CS42L43_MIXER_ROUTES("EQ2", "EQ"),
+
+ CS42L43_MIXER_ROUTES("Speaker L", "AMP1"),
+ CS42L43_MIXER_ROUTES("Speaker R", "AMP2"),
+
+ CS42L43_MIXER_ROUTES("Headphone L", "HP"),
+ CS42L43_MIXER_ROUTES("Headphone R", "HP"),
+};
+
+static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int src, unsigned int freq, int dir)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ mutex_lock(&cs42l43->pll_lock);
+ ret = cs42l43_set_pll(priv, src, freq);
+ mutex_unlock(&cs42l43->pll_lock);
+
+ return ret;
+}
+
+static int cs42l43_component_probe(struct snd_soc_component *component)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+
+ snd_soc_component_init_regmap(component, cs42l43->regmap);
+
+ cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->tx_slots,
+ ARRAY_SIZE(priv->tx_slots));
+ cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->rx_slots,
+ ARRAY_SIZE(priv->rx_slots));
+
+ priv->component = component;
+ priv->constraint = cs42l43_constraint;
+
+ return 0;
+}
+
+static void cs42l43_component_remove(struct snd_soc_component *component)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ cs42l43_set_jack(priv->component, NULL, NULL);
+
+ cancel_delayed_work_sync(&priv->bias_sense_timeout);
+ cancel_delayed_work_sync(&priv->tip_sense_work);
+
+ cancel_delayed_work_sync(&priv->hp_ilimit_clear_work);
+
+ priv->component = NULL;
+}
+
+static const struct snd_soc_component_driver cs42l43_component_drv = {
+ .name = "cs42l43-codec",
+
+ .probe = cs42l43_component_probe,
+ .remove = cs42l43_component_remove,
+ .set_sysclk = cs42l43_set_sysclk,
+ .set_jack = cs42l43_set_jack,
+
+ .endianness = 1,
+
+ .controls = cs42l43_controls,
+ .num_controls = ARRAY_SIZE(cs42l43_controls),
+ .dapm_widgets = cs42l43_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l43_widgets),
+ .dapm_routes = cs42l43_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs42l43_routes),
+};
+
+struct cs42l43_irq {
+ unsigned int irq;
+ const char *name;
+ irq_handler_t handler;
+};
+
+static const struct cs42l43_irq cs42l43_irqs[] = {
+ { CS42L43_PLL_LOST_LOCK, "pll lost lock", cs42l43_pll_lost_lock },
+ { CS42L43_PLL_READY, "pll ready", cs42l43_pll_ready },
+ { CS42L43_HP_STARTUP_DONE, "hp startup", cs42l43_hp_startup },
+ { CS42L43_HP_SHUTDOWN_DONE, "hp shutdown", cs42l43_hp_shutdown },
+ { CS42L43_HSDET_DONE, "type detect", cs42l43_type_detect },
+ { CS42L43_TIPSENSE_UNPLUG_PDET, "tip sense unplug", cs42l43_tip_sense },
+ { CS42L43_TIPSENSE_PLUG_PDET, "tip sense plug", cs42l43_tip_sense },
+ { CS42L43_DC_DETECT1_TRUE, "button press", cs42l43_button_press },
+ { CS42L43_DC_DETECT1_FALSE, "button release", cs42l43_button_release },
+ { CS42L43_HSBIAS_CLAMPED, "hsbias detect clamp", cs42l43_bias_detect_clamp },
+ { CS42L43_AMP2_CLK_STOP_FAULT, "spkr clock stop", cs42l43_spkr_clock_stop },
+ { CS42L43_AMP1_CLK_STOP_FAULT, "spkl clock stop", cs42l43_spkl_clock_stop },
+ { CS42L43_AMP2_VDDSPK_FAULT, "spkr brown out", cs42l43_spkr_brown_out },
+ { CS42L43_AMP1_VDDSPK_FAULT, "spkl brown out", cs42l43_spkl_brown_out },
+ { CS42L43_AMP2_SHUTDOWN_DONE, "spkr shutdown", cs42l43_spkr_shutdown },
+ { CS42L43_AMP1_SHUTDOWN_DONE, "spkl shutdown", cs42l43_spkl_shutdown },
+ { CS42L43_AMP2_STARTUP_DONE, "spkr startup", cs42l43_spkr_startup },
+ { CS42L43_AMP1_STARTUP_DONE, "spkl startup", cs42l43_spkl_startup },
+ { CS42L43_AMP2_THERM_SHDN, "spkr thermal shutdown", cs42l43_spkr_therm_shutdown },
+ { CS42L43_AMP1_THERM_SHDN, "spkl thermal shutdown", cs42l43_spkl_therm_shutdown },
+ { CS42L43_AMP2_THERM_WARN, "spkr thermal warning", cs42l43_spkr_therm_warm },
+ { CS42L43_AMP1_THERM_WARN, "spkl thermal warning", cs42l43_spkl_therm_warm },
+ { CS42L43_AMP2_SCDET, "spkr short circuit", cs42l43_spkr_sc_detect },
+ { CS42L43_AMP1_SCDET, "spkl short circuit", cs42l43_spkl_sc_detect },
+ { CS42L43_HP_ILIMIT, "hp ilimit", cs42l43_hp_ilimit },
+ { CS42L43_HP_LOADDET_DONE, "load detect done", cs42l43_load_detect },
+};
+
+static int cs42l43_request_irq(struct cs42l43_codec *priv,
+ const char * const name, unsigned int irq,
+ irq_handler_t handler, unsigned long flags)
+{
+ int ret;
+
+ ret = irq_create_mapping(priv->dom, irq);
+ if (ret < 0)
+ return dev_err_probe(priv->dev, ret, "Failed to map IRQ %s\n", name);
+
+ dev_dbg(priv->dev, "Request IRQ %d for %s\n", ret, name);
+
+ ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler,
+ IRQF_ONESHOT | flags, name, priv);
+ if (ret)
+ return dev_err_probe(priv->dev, ret, "Failed to request IRQ %s\n", name);
+
+ return 0;
+}
+
+static void cs42l43_disable_irq(struct cs42l43_codec *priv, unsigned int irq)
+{
+ int ret;
+
+ ret = irq_find_mapping(priv->dom, irq);
+ if (ret > 0)
+ disable_irq(ret);
+}
+
+static void cs42l43_enable_irq(struct cs42l43_codec *priv, unsigned int irq)
+{
+ int ret;
+
+ ret = irq_find_mapping(priv->dom, irq);
+ if (ret > 0)
+ enable_irq(ret);
+}
+
+static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter,
+ const char * const open_name, unsigned int *open_irq,
+ const char * const close_name, unsigned int *close_irq,
+ irq_handler_t handler)
+{
+ int ret;
+
+ switch (shutter) {
+ case 0x1:
+ dev_warn(priv->dev, "Manual shutters, notifications not available\n");
+ return 0;
+ case 0x2:
+ *open_irq = CS42L43_GPIO1_RISE;
+ *close_irq = CS42L43_GPIO1_FALL;
+ break;
+ case 0x4:
+ *open_irq = CS42L43_GPIO2_RISE;
+ *close_irq = CS42L43_GPIO2_FALL;
+ break;
+ case 0x8:
+ *open_irq = CS42L43_GPIO3_RISE;
+ *close_irq = CS42L43_GPIO3_FALL;
+ break;
+ default:
+ return 0;
+ }
+
+ ret = cs42l43_request_irq(priv, close_name, *close_irq, handler, IRQF_SHARED);
+ if (ret)
+ return ret;
+
+ return cs42l43_request_irq(priv, open_name, *open_irq, handler, IRQF_SHARED);
+}
+
+static int cs42l43_codec_probe(struct platform_device *pdev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
+ struct cs42l43_codec *priv;
+ unsigned int val;
+ int i, ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->core = cs42l43;
+
+ priv->dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY);
+ if (!priv->dom)
+ return -EPROBE_DEFER;
+
+ platform_set_drvdata(pdev, priv);
+
+ mutex_init(&priv->jack_lock);
+ mutex_init(&priv->spk_vu_lock);
+
+ init_completion(&priv->hp_startup);
+ init_completion(&priv->hp_shutdown);
+ init_completion(&priv->spkr_shutdown);
+ init_completion(&priv->spkl_shutdown);
+ init_completion(&priv->spkr_startup);
+ init_completion(&priv->spkl_startup);
+ init_completion(&priv->pll_ready);
+ init_completion(&priv->type_detect);
+ init_completion(&priv->load_detect);
+
+ INIT_DELAYED_WORK(&priv->tip_sense_work, cs42l43_tip_sense_work);
+ INIT_DELAYED_WORK(&priv->bias_sense_timeout, cs42l43_bias_sense_timeout);
+ INIT_DELAYED_WORK(&priv->hp_ilimit_clear_work, cs42l43_hp_ilimit_clear_work);
+
+ pm_runtime_set_autosuspend_delay(priv->dev, 100);
+ pm_runtime_use_autosuspend(priv->dev);
+ pm_runtime_set_active(priv->dev);
+ pm_runtime_get_noresume(priv->dev);
+
+ ret = devm_pm_runtime_enable(priv->dev);
+ if (ret)
+ goto err_pm;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) {
+ ret = cs42l43_request_irq(priv, cs42l43_irqs[i].name,
+ cs42l43_irqs[i].irq,
+ cs42l43_irqs[i].handler, 0);
+ if (ret)
+ goto err_pm;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to check shutter source: %d\n", ret);
+ goto err_pm;
+ }
+
+ ret = cs42l43_shutter_irq(priv, val & CS42L43_MIC_SHUTTER_CFG_MASK,
+ "mic shutter open", &priv->shutter_irqs[0],
+ "mic shutter close", &priv->shutter_irqs[1],
+ cs42l43_mic_shutter);
+ if (ret)
+ goto err_pm;
+
+ ret = cs42l43_shutter_irq(priv, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >>
+ CS42L43_SPK_SHUTTER_CFG_SHIFT,
+ "spk shutter open", &priv->shutter_irqs[2],
+ "spk shutter close", &priv->shutter_irqs[3],
+ cs42l43_spk_shutter);
+ if (ret)
+ goto err_pm;
+
+ // Don't use devm as we need to get against the MFD device
+ priv->mclk = clk_get_optional(cs42l43->dev, "mclk");
+ if (IS_ERR(priv->mclk)) {
+ ret = PTR_ERR(priv->mclk);
+ dev_err_probe(priv->dev, ret, "Failed to get mclk\n");
+ goto err_pm;
+ }
+
+ ret = devm_snd_soc_register_component(priv->dev, &cs42l43_component_drv,
+ cs42l43_dais, ARRAY_SIZE(cs42l43_dais));
+ if (ret) {
+ dev_err_probe(priv->dev, ret, "Failed to register component\n");
+ goto err_clk;
+ }
+
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return 0;
+
+err_clk:
+ clk_put(priv->mclk);
+err_pm:
+ pm_runtime_put_sync(priv->dev);
+
+ return ret;
+}
+
+static void cs42l43_codec_remove(struct platform_device *pdev)
+{
+ struct cs42l43_codec *priv = platform_get_drvdata(pdev);
+
+ clk_put(priv->mclk);
+}
+
+static int cs42l43_codec_runtime_resume(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "Runtime resume\n");
+
+ // Toggle the speaker volume update incase the speaker volume was synced
+ cs42l43_spk_vu_sync(priv);
+
+ return 0;
+}
+
+static int cs42l43_codec_suspend(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+ int i;
+
+ dev_dbg(priv->dev, "System suspend\n");
+
+ priv->suspend_jack_debounce = true;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++)
+ cs42l43_disable_irq(priv, cs42l43_irqs[i].irq);
+
+ for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++)
+ if (priv->shutter_irqs[i])
+ cs42l43_disable_irq(priv, priv->shutter_irqs[i]);
+
+ cancel_delayed_work_sync(&priv->bias_sense_timeout);
+ cancel_delayed_work_sync(&priv->tip_sense_work);
+ cancel_delayed_work_sync(&priv->hp_ilimit_clear_work);
+
+ cs42l43_clear_jack(priv);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int cs42l43_codec_resume(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+ int ret, i;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++)
+ cs42l43_enable_irq(priv, cs42l43_irqs[i].irq);
+
+ for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++)
+ if (priv->shutter_irqs[i])
+ cs42l43_enable_irq(priv, priv->shutter_irqs[i]);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cs42l43_codec_pm_ops = {
+ RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume)
+};
+
+static const struct platform_device_id cs42l43_codec_id_table[] = {
+ { "cs42l43-codec", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table);
+
+static struct platform_driver cs42l43_codec_driver = {
+ .driver = {
+ .name = "cs42l43-codec",
+ .pm = pm_ptr(&cs42l43_codec_pm_ops),
+ },
+
+ .probe = cs42l43_codec_probe,
+ .remove = cs42l43_codec_remove,
+ .id_table = cs42l43_codec_id_table,
+};
+module_platform_driver(cs42l43_codec_driver);
+
+MODULE_IMPORT_NS("SND_SOC_CS42L43");
+
+MODULE_DESCRIPTION("CS42L43 CODEC Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h
new file mode 100644
index 000000000000..b2fa2cd1d99f
--- /dev/null
+++ b/sound/soc/codecs/cs42l43.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS42L43 CODEC driver internal data
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef CS42L43_ASOC_INT_H
+#define CS42L43_ASOC_INT_H
+
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <sound/pcm.h>
+
+#define CS42L43_INTERNAL_SYSCLK 24576000
+#define CS42L43_DEFAULT_SLOTS 0x3F
+
+#define CS42L43_PLL_TIMEOUT_MS 200
+#define CS42L43_SPK_TIMEOUT_MS 100
+#define CS42L43_HP_TIMEOUT_MS 2000
+#define CS42L43_LOAD_TIMEOUT_MS 1000
+
+#define CS42L43_HP_ILIMIT_BACKOFF_MS 1000
+#define CS42L43_HP_ILIMIT_DECAY_MS 300
+#define CS42L43_HP_ILIMIT_MAX_COUNT 4
+
+#define CS42L43_ASP_MAX_CHANNELS 6
+#define CS42L43_N_EQ_COEFFS 15
+
+#define CS42L43_N_BUTTONS 6
+
+struct clk;
+struct device;
+
+struct snd_soc_component;
+struct snd_soc_jack;
+
+struct cs42l43;
+
+struct cs42l43_codec {
+ struct device *dev;
+ struct cs42l43 *core;
+ struct snd_soc_component *component;
+ struct irq_domain *dom;
+ unsigned int shutter_irqs[4];
+
+ struct clk *mclk;
+
+ int n_slots;
+ int slot_width;
+ int tx_slots[CS42L43_ASP_MAX_CHANNELS];
+ int rx_slots[CS42L43_ASP_MAX_CHANNELS];
+ struct snd_pcm_hw_constraint_list constraint;
+
+ u32 eq_coeffs[CS42L43_N_EQ_COEFFS];
+
+ unsigned int refclk_src;
+ unsigned int refclk_freq;
+ struct completion pll_ready;
+
+ unsigned int decim_cache[4];
+ unsigned int adc_ena;
+ unsigned int hp_ena;
+
+ struct completion hp_startup;
+ struct completion hp_shutdown;
+ struct completion spkr_shutdown;
+ struct completion spkl_shutdown;
+ struct completion spkr_startup;
+ struct completion spkl_startup;
+ // Lock to ensure speaker VU updates don't clash
+ struct mutex spk_vu_lock;
+
+ // Lock for all jack detect operations
+ struct mutex jack_lock;
+ struct snd_soc_jack *jack_hp;
+
+ 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;
+ unsigned int detect_us;
+ unsigned int buttons[CS42L43_N_BUTTONS];
+
+ struct delayed_work tip_sense_work;
+ struct delayed_work bias_sense_timeout;
+ struct completion type_detect;
+ struct completion load_detect;
+
+ bool load_detect_running;
+ bool button_detect_running;
+ bool jack_present;
+ int jack_override;
+ bool suspend_jack_debounce;
+
+ struct delayed_work hp_ilimit_clear_work;
+ bool hp_ilimited;
+ int hp_ilimit_count;
+
+ struct snd_kcontrol *kctl[5];
+};
+
+#if IS_REACHABLE(CONFIG_SND_SOC_CS42L43_SDW)
+
+int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction);
+
+#else
+
+static inline int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return -EINVAL;
+}
+
+#define cs42l43_sdw_remove_peripheral NULL
+#define cs42l43_sdw_set_stream NULL
+
+#endif
+
+int cs42l43_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *d);
+void cs42l43_bias_sense_timeout(struct work_struct *work);
+void cs42l43_clear_jack(struct cs42l43_codec *priv);
+void cs42l43_tip_sense_work(struct work_struct *work);
+irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data);
+irqreturn_t cs42l43_button_press(int irq, void *data);
+irqreturn_t cs42l43_button_release(int irq, void *data);
+irqreturn_t cs42l43_tip_sense(int irq, void *data);
+int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+
+extern const struct soc_enum cs42l43_jack_enum;
+
+#endif /* CS42L43_ASOC_INT_H */
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index b2106ff6a7cb..ba7e237619f2 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -13,12 +13,18 @@
#include "cs42l51.h"
-static struct i2c_device_id cs42l51_i2c_id[] = {
- {"cs42l51", 0},
- {}
+static const struct i2c_device_id cs42l51_i2c_id[] = {
+ { "cs42l51" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
+static const struct of_device_id cs42l51_of_match[] = {
+ { .compatible = "cirrus,cs42l51", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+
static int cs42l51_i2c_probe(struct i2c_client *i2c)
{
struct regmap_config config;
@@ -34,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 a67cd3ee84e0..0519affe0ed8 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -57,7 +57,7 @@ struct cs42l51_private {
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned long value = snd_soc_component_read(component, CS42L51_PCM_MIXER)&3;
switch (value) {
@@ -85,7 +85,7 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned char val;
switch (ucontrol->value.enumerated.item[0]) {
@@ -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:
@@ -567,7 +567,7 @@ static int cs42l51_component_probe(struct snd_soc_component *component)
struct cs42l51_private *cs42l51;
cs42l51 = snd_soc_component_get_drvdata(component);
- dapm = snd_soc_component_get_dapm(component);
+ dapm = snd_soc_component_to_dapm(component);
if (cs42l51->mclk_handle)
snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1);
@@ -703,7 +703,7 @@ const struct regmap_config cs42l51_regmap = {
.volatile_reg = cs42l51_volatile_reg,
.writeable_reg = cs42l51_writeable_reg,
.max_register = CS42L51_CHARGE_FREQ,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(cs42l51_regmap);
@@ -747,8 +747,10 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);
- if (IS_ERR(cs42l51->reset_gpio))
- return PTR_ERR(cs42l51->reset_gpio);
+ if (IS_ERR(cs42l51->reset_gpio)) {
+ ret = PTR_ERR(cs42l51->reset_gpio);
+ goto error;
+ }
if (cs42l51->reset_gpio) {
dev_dbg(dev, "Release reset gpio\n");
@@ -780,6 +782,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
return 0;
error:
+ gpiod_set_value_cansleep(cs42l51->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
cs42l51->supplies);
return ret;
@@ -802,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);
@@ -813,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);
@@ -823,13 +826,6 @@ int __maybe_unused cs42l51_resume(struct device *dev)
}
EXPORT_SYMBOL_GPL(cs42l51_resume);
-const struct of_device_id cs42l51_of_match[] = {
- { .compatible = "cirrus,cs42l51", },
- { }
-};
-MODULE_DEVICE_TABLE(of, cs42l51_of_match);
-EXPORT_SYMBOL_GPL(cs42l51_of_match);
-
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
index a79343e8a54e..125703ede113 100644
--- a/sound/soc/codecs/cs42l51.h
+++ b/sound/soc/codecs/cs42l51.h
@@ -16,7 +16,6 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap);
void cs42l51_remove(struct device *dev);
int __maybe_unused cs42l51_suspend(struct device *dev);
int __maybe_unused cs42l51_resume(struct device *dev);
-extern const struct of_device_id cs42l51_of_match[];
#define CS42L51_CHIP_ID 0x1B
#define CS42L51_CHIP_REV_A 0x00
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 1f1ded0ff0ac..662dc1a4835b 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -8,27 +8,26 @@
* Author: Brian Austin <brian.austin@cirrus.com>
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/of_gpio.h>
-#include <linux/pm.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/init.h>
#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
-#include <linux/platform_device.h>
#include <sound/core.h>
+#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
-#include <sound/cs42l52.h>
#include "cs42l52.h"
struct sp_config {
@@ -36,6 +35,24 @@ struct sp_config {
u32 srate;
};
+struct cs42l52_platform_data {
+
+ /* MICBIAS Level. Check datasheet Pg48 */
+ unsigned int micbias_lvl;
+
+ /* MICA mode selection Differential or Single-ended */
+ bool mica_diff_cfg;
+
+ /* MICB mode selection Differential or Single-ended */
+ bool micb_diff_cfg;
+
+ /* Charge Pump Freq. Check datasheet Pg73 */
+ unsigned int chgfreq;
+
+ /* Reset GPIO */
+ struct gpio_desc *reset_gpio;
+};
+
struct cs42l52_private {
struct regmap *regmap;
struct snd_soc_component *component;
@@ -733,10 +750,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:
@@ -834,6 +851,7 @@ static int cs42l52_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -843,7 +861,7 @@ static int cs42l52_set_bias_level(struct snd_soc_component *component,
CS42L52_PWRCTL1_PDN_CODEC, 0);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l52->regmap, false);
regcache_sync(cs42l52->regmap);
}
@@ -902,7 +920,7 @@ static void cs42l52_beep_work(struct work_struct *work)
struct cs42l52_private *cs42l52 =
container_of(work, struct cs42l52_private, beep_work);
struct snd_soc_component *component = cs42l52->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i;
int val = 0;
int best = 0;
@@ -1084,13 +1102,13 @@ static const struct regmap_config cs42l52_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
.readable_reg = cs42l52_readable_register,
.volatile_reg = cs42l52_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int cs42l52_i2c_probe(struct i2c_client *i2c_client)
{
struct cs42l52_private *cs42l52;
- struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
+ struct cs42l52_platform_data *pdata;
int ret;
unsigned int devid;
unsigned int reg;
@@ -1107,50 +1125,43 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client)
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
- if (pdata) {
- cs42l52->pdata = *pdata;
- } else {
- pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
- GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- if (i2c_client->dev.of_node) {
- if (of_property_read_bool(i2c_client->dev.of_node,
- "cirrus,mica-differential-cfg"))
- pdata->mica_diff_cfg = true;
-
- if (of_property_read_bool(i2c_client->dev.of_node,
- "cirrus,micb-differential-cfg"))
- pdata->micb_diff_cfg = true;
-
- if (of_property_read_u32(i2c_client->dev.of_node,
- "cirrus,micbias-lvl", &val32) >= 0)
- pdata->micbias_lvl = val32;
-
- if (of_property_read_u32(i2c_client->dev.of_node,
- "cirrus,chgfreq-divisor", &val32) >= 0)
- pdata->chgfreq = val32;
-
- pdata->reset_gpio =
- of_get_named_gpio(i2c_client->dev.of_node,
- "cirrus,reset-gpio", 0);
- }
- cs42l52->pdata = *pdata;
+
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (i2c_client->dev.of_node) {
+ if (of_property_read_bool(i2c_client->dev.of_node,
+ "cirrus,mica-differential-cfg"))
+ pdata->mica_diff_cfg = true;
+
+ if (of_property_read_bool(i2c_client->dev.of_node,
+ "cirrus,micb-differential-cfg"))
+ pdata->micb_diff_cfg = true;
+
+ if (of_property_read_u32(i2c_client->dev.of_node,
+ "cirrus,micbias-lvl", &val32) >= 0)
+ pdata->micbias_lvl = val32;
+
+ if (of_property_read_u32(i2c_client->dev.of_node,
+ "cirrus,chgfreq-divisor", &val32) >= 0)
+ pdata->chgfreq = val32;
+
+ pdata->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ "cirrus,reset",
+ GPIOD_OUT_LOW);
+
+ if (IS_ERR(pdata->reset_gpio))
+ return PTR_ERR(pdata->reset_gpio);
+
+ gpiod_set_consumer_name(pdata->reset_gpio, "CS42L52 /RST");
}
+ cs42l52->pdata = *pdata;
+
if (cs42l52->pdata.reset_gpio) {
- ret = devm_gpio_request_one(&i2c_client->dev,
- cs42l52->pdata.reset_gpio,
- GPIOF_OUT_INIT_HIGH,
- "CS42L52 /RST");
- if (ret < 0) {
- dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
- cs42l52->pdata.reset_gpio, ret);
- return ret;
- }
- gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 0);
- gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 1);
+ gpiod_set_value_cansleep(cs42l52->pdata.reset_gpio, 1);
+ gpiod_set_value_cansleep(cs42l52->pdata.reset_gpio, 0);
}
i2c_set_clientdata(i2c_client, cs42l52);
@@ -1215,7 +1226,7 @@ MODULE_DEVICE_TABLE(of, cs42l52_of_match);
static const struct i2c_device_id cs42l52_id[] = {
- { "cs42l52", 0 },
+ { "cs42l52" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs42l52_id);
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index 4c646e8d72aa..aabb74f1f43c 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -7,32 +7,64 @@
* Author: Brian Austin <brian.austin@cirrus.com>
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/pm.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/init.h>
#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <sound/core.h>
+#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
-#include <sound/cs42l56.h>
#include "cs42l56.h"
#define CS42L56_NUM_SUPPLIES 3
+
+struct cs42l56_platform_data {
+ /* GPIO for Reset */
+ struct gpio_desc *gpio_nreset;
+
+ /* MICBIAS Level. Check datasheet Pg48 */
+ unsigned int micbias_lvl;
+
+ /* Analog Input 1A Reference 0=Single 1=Pseudo-Differential */
+ unsigned int ain1a_ref_cfg;
+
+ /* Analog Input 2A Reference 0=Single 1=Pseudo-Differential */
+ unsigned int ain2a_ref_cfg;
+
+ /* Analog Input 1B Reference 0=Single 1=Pseudo-Differential */
+ unsigned int ain1b_ref_cfg;
+
+ /* Analog Input 2B Reference 0=Single 1=Pseudo-Differential */
+ unsigned int ain2b_ref_cfg;
+
+ /* Charge Pump Freq. Check datasheet Pg62 */
+ unsigned int chgfreq;
+
+ /* HighPass Filter Right Channel Corner Frequency */
+ unsigned int hpfb_freq;
+
+ /* HighPass Filter Left Channel Corner Frequency */
+ unsigned int hpfa_freq;
+
+ /* Adaptive Power Control for LO/HP */
+ unsigned int adaptive_pwr;
+};
+
static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
"VA",
"VCP",
@@ -757,10 +789,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:
@@ -879,6 +911,7 @@ static int cs42l56_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -891,7 +924,7 @@ static int cs42l56_set_bias_level(struct snd_soc_component *component,
CS42L56_PDN_ALL_MASK, 0);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l56->regmap, false);
regcache_sync(cs42l56->regmap);
ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
@@ -964,7 +997,7 @@ static void cs42l56_beep_work(struct work_struct *work)
struct cs42l56_private *cs42l56 =
container_of(work, struct cs42l56_private, beep_work);
struct snd_soc_component *component = cs42l56->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i;
int val = 0;
int best = 0;
@@ -1125,7 +1158,7 @@ static const struct regmap_config cs42l56_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
.readable_reg = cs42l56_readable_register,
.volatile_reg = cs42l56_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
@@ -1161,7 +1194,13 @@ static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
pdata->hpfb_freq = val32;
- pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
+ pdata->gpio_nreset = devm_gpiod_get_optional(&i2c_client->dev, "cirrus,gpio-nreset",
+ GPIOD_OUT_LOW);
+
+ if (IS_ERR(pdata->gpio_nreset))
+ return PTR_ERR(pdata->gpio_nreset);
+
+ gpiod_set_consumer_name(pdata->gpio_nreset, "CS42L56 /RST");
return 0;
}
@@ -1169,8 +1208,6 @@ static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
static int cs42l56_i2c_probe(struct i2c_client *i2c_client)
{
struct cs42l56_private *cs42l56;
- struct cs42l56_platform_data *pdata =
- dev_get_platdata(&i2c_client->dev);
int ret, i;
unsigned int devid;
unsigned int alpha_rev, metal_rev;
@@ -1188,31 +1225,17 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client)
return ret;
}
- if (pdata) {
- cs42l56->pdata = *pdata;
- } else {
- if (i2c_client->dev.of_node) {
- ret = cs42l56_handle_of_data(i2c_client,
- &cs42l56->pdata);
- if (ret != 0)
- return ret;
- }
+ if (i2c_client->dev.of_node) {
+ ret = cs42l56_handle_of_data(i2c_client, &cs42l56->pdata);
+ if (ret != 0)
+ return ret;
}
if (cs42l56->pdata.gpio_nreset) {
- ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
- GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
- if (ret < 0) {
- dev_err(&i2c_client->dev,
- "Failed to request /RST %d: %d\n",
- cs42l56->pdata.gpio_nreset, ret);
- return ret;
- }
- gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
- gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
+ gpiod_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
+ gpiod_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
}
-
i2c_set_clientdata(i2c_client, cs42l56);
for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
@@ -1330,7 +1353,7 @@ MODULE_DEVICE_TABLE(of, cs42l56_of_match);
static const struct i2c_device_id cs42l56_id[] = {
- { "cs42l56", 0 },
+ { "cs42l56" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs42l56_id);
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 6ab67d196d10..bda8442c1d66 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -8,26 +8,33 @@
* Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>
*/
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/of_gpio.h>
#include <linux/pm.h>
-#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
+#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
-#include <sound/cs42l73.h>
-#include "cs42l73.h"
#include "cirrus_legacy.h"
+#include "cs42l73.h"
+
+struct cs42l73_platform_data {
+ /* RST GPIO */
+ struct gpio_desc *reset_gpio;
+ unsigned int chgfreq;
+ int jack_detection;
+ unsigned int mclk_freq;
+};
struct sp_config {
u8 spc, mmcc, spfs;
@@ -943,11 +950,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;
@@ -1094,6 +1101,7 @@ static int cs42l73_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1105,7 +1113,7 @@ static int cs42l73_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l73->regmap, false);
regcache_sync(cs42l73->regmap);
}
@@ -1276,7 +1284,7 @@ static const struct regmap_config cs42l73_regmap = {
static int cs42l73_i2c_probe(struct i2c_client *i2c_client)
{
struct cs42l73_private *cs42l73;
- struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
+ struct cs42l73_platform_data *pdata;
int ret, devid;
unsigned int reg;
u32 val32;
@@ -1292,38 +1300,27 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client)
return ret;
}
- if (pdata) {
- cs42l73->pdata = *pdata;
- } else {
- pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
- GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- if (i2c_client->dev.of_node) {
- if (of_property_read_u32(i2c_client->dev.of_node,
- "chgfreq", &val32) >= 0)
- pdata->chgfreq = val32;
- }
- pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
- "reset-gpio", 0);
- cs42l73->pdata = *pdata;
+ pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (i2c_client->dev.of_node) {
+ if (of_property_read_u32(i2c_client->dev.of_node, "chgfreq", &val32) >= 0)
+ pdata->chgfreq = val32;
}
+ pdata->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW);
+
+ if (IS_ERR(pdata->reset_gpio))
+ return PTR_ERR(pdata->reset_gpio);
+
+ gpiod_set_consumer_name(pdata->reset_gpio, "CS42L73 /RST");
+ cs42l73->pdata = *pdata;
i2c_set_clientdata(i2c_client, cs42l73);
if (cs42l73->pdata.reset_gpio) {
- ret = devm_gpio_request_one(&i2c_client->dev,
- cs42l73->pdata.reset_gpio,
- GPIOF_OUT_INIT_HIGH,
- "CS42L73 /RST");
- if (ret < 0) {
- dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
- cs42l73->pdata.reset_gpio, ret);
- return ret;
- }
- gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
- gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
+ gpiod_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
+ gpiod_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
}
/* initialize codec */
@@ -1360,7 +1357,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client)
return 0;
err_reset:
- gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
+ gpiod_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
return ret;
}
@@ -1372,7 +1369,7 @@ static const struct of_device_id cs42l73_of_match[] = {
MODULE_DEVICE_TABLE(of, cs42l73_of_match);
static const struct i2c_device_id cs42l73_id[] = {
- {"cs42l73", 0},
+ {"cs42l73"},
{}
};
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index f482b6a4f5c3..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,
@@ -237,4 +237,4 @@ module_i2c_driver(cs42l83_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L83 I2C driver");
MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE);
+MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE");
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
new file mode 100644
index 000000000000..1e1307a16f81
--- /dev/null
+++ b/sound/soc/codecs/cs42l84.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cs42l84.c -- CS42L84 ALSA SoC audio driver
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ *
+ * Based on sound/soc/codecs/cs42l42{.c,.h}
+ * Copyright 2016 Cirrus Logic, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "cs42l84.h"
+#include "cirrus_legacy.h"
+
+struct cs42l84_private {
+ struct regmap *regmap;
+ struct device *dev;
+ struct gpio_desc *reset_gpio;
+ struct snd_soc_jack *jack;
+ struct mutex irq_lock;
+ u8 tip_state;
+ u8 ring_state;
+ int pll_config;
+ int bclk;
+ u8 pll_mclk_f;
+ u32 srate;
+ u8 stream_use;
+ int hs_type;
+};
+
+static bool cs42l84_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L84_DEVID ... CS42L84_DEVID+5:
+ case CS42L84_TSRS_PLUG_INT_STATUS:
+ case CS42L84_PLL_LOCK_STATUS:
+ case CS42L84_TSRS_PLUG_STATUS:
+ case CS42L84_HS_DET_STATUS2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config cs42l84_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+
+ .volatile_reg = cs42l84_volatile_register,
+
+ .max_register = 0x73fe,
+
+ .cache_type = REGCACHE_MAPLE,
+
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int cs42l84_put_dac_vol(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kctl);
+ struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value;
+ int vola, volb;
+ int ret, ret2, updated = 0;
+
+ vola = val->value.integer.value[0] + mc->min;
+ volb = val->value.integer.value[1] + mc->min;
+
+ if (vola < mc->min || vola > mc->max || volb < mc->min || volb > mc->max)
+ return -EINVAL;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL,
+ CS42L84_FRZ_CTL_ENGAGE,
+ CS42L84_FRZ_CTL_ENGAGE);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_LSB,
+ 0xff, vola & 0xff);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_MSB,
+ 0xff, (vola >> 8) & 0x01);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_LSB,
+ 0xff, volb & 0xff);
+ if (ret < 0)
+ goto bail;
+ updated |= ret;
+
+ ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_MSB,
+ 0xff, (volb >> 8) & 0x01);
+ if (ret < 0)
+ goto bail;
+ ret |= updated;
+
+bail:
+ ret2 = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL,
+ CS42L84_FRZ_CTL_ENGAGE, 0);
+ if (ret2 < 0 && ret >= 0)
+ ret = ret2;
+
+ return ret;
+}
+
+static int cs42l84_get_dac_vol(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kctl);
+ struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value;
+ int vola, volb;
+ int ret;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_LSB);
+ if (ret < 0)
+ return ret;
+ vola = ret;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_MSB);
+ if (ret < 0)
+ return ret;
+ vola |= (ret & 1) << 8;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_LSB);
+ if (ret < 0)
+ return ret;
+ volb = ret;
+
+ ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_MSB);
+ if (ret < 0)
+ return ret;
+ volb |= (ret & 1) << 8;
+
+ if (vola & BIT(8))
+ vola |= ~((int)(BIT(8) - 1));
+ if (volb & BIT(8))
+ volb |= ~((int)(BIT(8) - 1));
+
+ val->value.integer.value[0] = vola - mc->min;
+ val->value.integer.value[1] = volb - mc->min;
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(cs42l84_dac_tlv, -12800, 50, true);
+static const DECLARE_TLV_DB_SCALE(cs42l84_adc_tlv, -1200, 50, false);
+static const DECLARE_TLV_DB_SCALE(cs42l84_pre_tlv, 0, 1000, false);
+
+static const struct snd_kcontrol_new cs42l84_snd_controls[] = {
+ SOC_DOUBLE_R_S_EXT_TLV("DAC Playback Volume", CS42L84_DAC_CHA_VOL_LSB,
+ CS42L84_DAC_CHB_VOL_LSB, 0, -256, 24, 8, 0,
+ cs42l84_get_dac_vol, cs42l84_put_dac_vol, cs42l84_dac_tlv),
+ SOC_SINGLE_TLV("ADC Preamp Capture Volume", CS42L84_ADC_CTL1,
+ CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT, 2, 0, cs42l84_pre_tlv),
+ SOC_SINGLE_TLV("ADC PGA Capture Volume", CS42L84_ADC_CTL1,
+ CS42L84_ADC_CTL1_PGA_GAIN_SHIFT, 24, 0, cs42l84_adc_tlv),
+ SOC_SINGLE("ADC WNF Switch", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("WNF Corner Frequency", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_WNF_CF_SHIFT, 3, 0),
+ SOC_SINGLE("ADC HPF Switch", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("HPF Corner Frequency", CS42L84_ADC_CTL4,
+ CS42L84_ADC_CTL4_HPF_CF_SHIFT, 3, 0),
+};
+
+static const char * const cs42l84_mux_text[] = {
+ "Blank", "ADC", "ASP RX CH1", "ASP RX CH2",
+};
+
+static const unsigned int cs42l84_mux_values[] = {
+ 0b0000, 0b0111, 0b1101, 0b1110,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_daca_mux_enum,
+ CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACA_SHIFT,
+ 0b1111, cs42l84_mux_text, cs42l84_mux_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_dacb_mux_enum,
+ CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACB_SHIFT,
+ 0b1111, cs42l84_mux_text, cs42l84_mux_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_sdout1_mux_enum,
+ CS42L84_BUS_ASP_TX_SRC, CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT,
+ 0b1111, cs42l84_mux_text, cs42l84_mux_values);
+
+static const struct snd_kcontrol_new cs42l84_daca_mux_ctrl =
+ SOC_DAPM_ENUM("DACA Select", cs42l84_daca_mux_enum);
+
+static const struct snd_kcontrol_new cs42l84_dacb_mux_ctrl =
+ SOC_DAPM_ENUM("DACB Select", cs42l84_dacb_mux_enum);
+
+static const struct snd_kcontrol_new cs42l84_sdout1_mux_ctrl =
+ SOC_DAPM_ENUM("SDOUT1 Select", cs42l84_sdout1_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l84_dapm_widgets[] = {
+ /* Playback Path */
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_DAC("DAC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_DAC_SHIFT, 0),
+ SND_SOC_DAPM_MUX("DACA Select", SND_SOC_NOPM, 0, 0, &cs42l84_daca_mux_ctrl),
+ SND_SOC_DAPM_MUX("DACB Select", SND_SOC_NOPM, 0, 0, &cs42l84_dacb_mux_ctrl),
+ SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH1_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH2_SHIFT, 0),
+
+ /* Capture Path */
+ SND_SOC_DAPM_INPUT("HS"),
+ SND_SOC_DAPM_ADC("ADC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ADC_SHIFT, 0),
+ SND_SOC_DAPM_MUX("SDOUT1 Select", SND_SOC_NOPM, 0, 0, &cs42l84_sdout1_mux_ctrl),
+ SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L84_ASP_TX_EN, CS42L84_ASP_TX_EN_CH1_SHIFT, 0),
+
+ /* Playback/Capture Requirements */
+ SND_SOC_DAPM_SUPPLY("BUS", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_BUS_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASP", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ASP_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("BCLK", CS42L84_ASP_CTL, CS42L84_ASP_CTL_BCLK_EN_SHIFT, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route cs42l84_audio_map[] = {
+ /* Playback Path */
+ {"HP", NULL, "DAC"},
+ {"DAC", NULL, "DACA Select"},
+ {"DAC", NULL, "DACB Select"},
+ {"DACA Select", "ASP RX CH1", "SDIN1"},
+ {"DACA Select", "ASP RX CH2", "SDIN2"},
+ {"DACB Select", "ASP RX CH1", "SDIN1"},
+ {"DACB Select", "ASP RX CH2", "SDIN2"},
+ {"SDIN1", NULL, "Playback"},
+ {"SDIN2", NULL, "Playback"},
+
+ {"ADC", NULL, "HS"},
+ {"SDOUT1 Select", "ADC", "ADC"},
+ {"SDOUT1", NULL, "SDOUT1 Select"},
+ {"Capture", NULL, "SDOUT1"},
+
+ /* Playback Requirements */
+ {"DAC", NULL, "BUS"},
+ {"SDIN1", NULL, "ASP"},
+ {"SDIN2", NULL, "ASP"},
+ {"SDIN1", NULL, "BCLK"},
+ {"SDIN2", NULL, "BCLK"},
+
+ /* Capture Requirements */
+ {"SDOUT1", NULL, "BUS"},
+ {"SDOUT1", NULL, "ASP"},
+ {"SDOUT1", NULL, "BCLK"},
+};
+
+static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jk, void *d)
+{
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+
+ /* Prevent race with interrupt handler */
+ mutex_lock(&cs42l84->irq_lock);
+ cs42l84->jack = jk;
+ snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET);
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return 0;
+}
+
+static int cs42l84_component_probe(struct snd_soc_component *component)
+{
+ snd_soc_component_update_bits(component, CS42L84_ASP_CTL,
+ CS42L84_ASP_CTL_TDM_MODE, 0);
+ snd_soc_component_update_bits(component, CS42L84_HP_VOL_CTL,
+ CS42L84_HP_VOL_CTL_SOFT | CS42L84_HP_VOL_CTL_ZERO_CROSS,
+ CS42L84_HP_VOL_CTL_ZERO_CROSS);
+
+ /* TDM settings */
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE |
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE |
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE);
+ snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE | \
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL1,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE | \
+ CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB,
+ CS42L84_ASP_RX_CHx_CTL1_EDGE);
+ snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL2,
+ CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0);
+ /* Routing defaults */
+ snd_soc_component_write(component, CS42L84_BUS_DAC_SRC,
+ 0b1101 << CS42L84_BUS_DAC_SRC_DACA_SHIFT |
+ 0b1110 << CS42L84_BUS_DAC_SRC_DACB_SHIFT);
+ snd_soc_component_write(component, CS42L84_BUS_ASP_TX_SRC,
+ 0b0111 << CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs42l84 = {
+ .set_jack = cs42l84_set_jack,
+ .probe = cs42l84_component_probe,
+ .controls = cs42l84_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42l84_snd_controls),
+ .dapm_widgets = cs42l84_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l84_dapm_widgets),
+ .dapm_routes = cs42l84_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs42l84_audio_map),
+ .endianness = 1,
+};
+
+struct cs42l84_pll_params {
+ u32 bclk;
+ u8 mclk_src_sel;
+ u8 bclk_prediv;
+ u8 pll_div_int;
+ u32 pll_div_frac;
+ u8 pll_mode;
+ u8 pll_divout;
+ u32 mclk_int;
+};
+
+/*
+ * Common PLL Settings for given BCLK
+ */
+static const struct cs42l84_pll_params pll_ratio_table[] = {
+ { 3072000, 1, 0, 0x40, 0x000000, 0x03, 0x10, 12288000},
+ { 6144000, 1, 1, 0x40, 0x000000, 0x03, 0x10, 12288000},
+ { 12288000, 0, 0, 0, 0, 0, 0, 12288000},
+ { 24576000, 1, 3, 0x40, 0x000000, 0x03, 0x10, 12288000},
+};
+
+static int cs42l84_pll_config(struct snd_soc_component *component)
+{
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ int i;
+ u32 clk;
+ u32 fsync;
+
+ clk = cs42l84->bclk;
+
+ /* Don't reconfigure if there is an audio stream running */
+ if (cs42l84->stream_use) {
+ if (pll_ratio_table[cs42l84->pll_config].bclk == clk)
+ return 0;
+ else
+ return -EBUSY;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].bclk == clk) {
+ cs42l84->pll_config = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(pll_ratio_table))
+ return -EINVAL;
+
+ /* Set up the LRCLK */
+ fsync = clk / cs42l84->srate;
+ if (((fsync * cs42l84->srate) != clk)
+ || ((fsync % 2) != 0)) {
+ dev_err(component->dev,
+ "Unsupported bclk %d/sample rate %d\n",
+ clk, cs42l84->srate);
+ return -EINVAL;
+ }
+
+ /* Set the LRCLK period */
+ snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL2,
+ CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO,
+ FIELD_PREP(CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, fsync & 0x7f));
+ snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL3,
+ CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI,
+ FIELD_PREP(CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, fsync >> 7));
+
+ /* Save what the MCLK will be */
+ switch (pll_ratio_table[i].mclk_int) {
+ case 12000000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12MHZ;
+ break;
+ case 12288000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12_288KHZ;
+ break;
+ case 24000000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24MHZ;
+ break;
+ case 24576000:
+ cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24_576KHZ;
+ break;
+ }
+
+ snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_EN, 0);
+
+ if (pll_ratio_table[i].mclk_src_sel) {
+ /* Configure PLL */
+ snd_soc_component_update_bits(component,
+ CS42L84_CCM_CTL3, CS42L84_CCM_CTL3_REFCLK_DIV,
+ FIELD_PREP(CS42L84_CCM_CTL3_REFCLK_DIV, pll_ratio_table[i].bclk_prediv));
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_INT,
+ pll_ratio_table[i].pll_div_int);
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_FRAC0,
+ pll_ratio_table[i].pll_div_frac);
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_FRAC1,
+ pll_ratio_table[i].pll_div_frac >> 8);
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIV_FRAC2,
+ pll_ratio_table[i].pll_div_frac >> 16);
+ snd_soc_component_update_bits(component,
+ CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_MODE,
+ FIELD_PREP(CS42L84_PLL_CTL1_MODE, pll_ratio_table[i].pll_mode));
+ snd_soc_component_write(component,
+ CS42L84_PLL_DIVOUT,
+ pll_ratio_table[i].pll_divout);
+ }
+
+ return 0;
+}
+
+static int cs42l84_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Bitclock/frame inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs42l84_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ int ret;
+ u32 ccm_samp_rate;
+
+ cs42l84->srate = params_rate(params);
+
+ ret = cs42l84_pll_config(component);
+ if (ret)
+ return ret;
+
+ switch (params_rate(params)) {
+ case 44100:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_44K1HZ;
+ break;
+ case 48000:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_48KHZ;
+ break;
+ case 88200:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_88K2HZ;
+ break;
+ case 96000:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_96KHZ;
+ break;
+ case 176400:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_176K4HZ;
+ break;
+ case 192000:
+ ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_192KHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_write(component, CS42L84_CCM_SAMP_RATE, ccm_samp_rate);
+
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ snd_soc_component_write(component, CS42L84_ASP_RX_CH1_WIDTH,
+ params_width(params) - 1);
+ snd_soc_component_write(component, CS42L84_ASP_RX_CH2_WIDTH,
+ params_width(params) - 1);
+ break;
+
+ case SNDRV_PCM_STREAM_CAPTURE:
+ snd_soc_component_write(component, CS42L84_ASP_TX_CH1_WIDTH,
+ params_width(params) - 1);
+ snd_soc_component_write(component, CS42L84_ASP_TX_CH2_WIDTH,
+ params_width(params) - 1);
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l84_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ int i;
+
+ if (freq == 0) {
+ cs42l84->bclk = 0;
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+ if (pll_ratio_table[i].bclk == freq) {
+ cs42l84->bclk = freq;
+ return 0;
+ }
+ }
+
+ dev_err(component->dev, "BCLK %u not supported\n", freq);
+
+ return -EINVAL;
+}
+
+static int cs42l84_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
+ unsigned int regval;
+ int ret;
+
+ if (mute) {
+ /* Mute the headphone */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_component_update_bits(component, CS42L84_DAC_CTL1,
+ CS42L84_DAC_CTL1_UNMUTE, 0);
+ cs42l84->stream_use &= ~(1 << stream);
+ if (!cs42l84->stream_use) {
+ /* Must disconnect PLL before stopping it */
+ snd_soc_component_write(component, CS42L84_CCM_CTL1,
+ CS42L84_CCM_CTL1_RCO);
+
+ usleep_range(150, 300);
+
+ snd_soc_component_update_bits(component, CS42L84_PLL_CTL1,
+ CS42L84_PLL_CTL1_EN, 0);
+
+ snd_soc_component_update_bits(component, CS42L84_CCM_CTL4,
+ CS42L84_CCM_CTL4_REFCLK_EN, 0);
+ }
+ } else {
+ if (!cs42l84->stream_use) {
+ /* SCLK must be running before codec unmute.
+ *
+ * Note carried over from CS42L42:
+ *
+ * PLL must not be started with ADC and HP both off
+ * otherwise the FILT+ supply will not charge properly.
+ * DAPM widgets power-up before stream unmute so at least
+ * one of the "DAC" or "ADC" widgets will already have
+ * powered-up.
+ */
+
+ snd_soc_component_update_bits(component, CS42L84_CCM_CTL4,
+ CS42L84_CCM_CTL4_REFCLK_EN,
+ CS42L84_CCM_CTL4_REFCLK_EN);
+
+ if (pll_ratio_table[cs42l84->pll_config].mclk_src_sel) {
+ snd_soc_component_update_bits(component, CS42L84_PLL_CTL1,
+ CS42L84_PLL_CTL1_EN,
+ CS42L84_PLL_CTL1_EN);
+ /* TODO: should we be doing something with divout here? */
+
+ ret = regmap_read_poll_timeout(cs42l84->regmap,
+ CS42L84_PLL_LOCK_STATUS,
+ regval,
+ (regval & CS42L84_PLL_LOCK_STATUS_LOCKED),
+ CS42L84_PLL_LOCK_POLL_US,
+ CS42L84_PLL_LOCK_TIMEOUT_US);
+ if (ret < 0)
+ dev_warn(component->dev, "PLL failed to lock: %d\n", ret);
+
+ if (regval & CS42L84_PLL_LOCK_STATUS_ERROR)
+ dev_warn(component->dev, "PLL lock error\n");
+
+ /* PLL must be running to drive glitchless switch logic */
+ snd_soc_component_update_bits(component,
+ CS42L84_CCM_CTL1,
+ CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ,
+ FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_PLL)
+ | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f));
+ usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2);
+ } else {
+ snd_soc_component_update_bits(component,
+ CS42L84_CCM_CTL1,
+ CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ,
+ FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_BCLK)
+ | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f));
+ usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2);
+ }
+ }
+ cs42l84->stream_use |= 1 << stream;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* Un-mute the headphone */
+ snd_soc_component_update_bits(component, CS42L84_DAC_CTL1,
+ CS42L84_DAC_CTL1_UNMUTE,
+ CS42L84_DAC_CTL1_UNMUTE);
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs42l84_ops = {
+ .hw_params = cs42l84_pcm_hw_params,
+ .set_fmt = cs42l84_set_dai_fmt,
+ .set_sysclk = cs42l84_set_sysclk,
+ .mute_stream = cs42l84_mute_stream,
+};
+
+#define CS42L84_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver cs42l84_dai = {
+ .name = "cs42l84",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = CS42L84_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = CS42L84_FORMATS,
+ },
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ .ops = &cs42l84_ops,
+};
+
+struct cs42l84_irq_params {
+ u16 status_addr;
+ u16 mask_addr;
+ u8 mask;
+};
+
+static const struct cs42l84_irq_params irq_params_table[] = {
+ {CS42L84_TSRS_PLUG_INT_STATUS, CS42L84_TSRS_PLUG_INT_MASK,
+ CS42L84_TSRS_PLUG_VAL_MASK}
+};
+
+static void cs42l84_detect_hs(struct cs42l84_private *cs42l84)
+{
+ unsigned int reg;
+
+ /* Power up HSBIAS */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 3) | /* 2.7 V */
+ FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0));
+
+ /* Power up level detection circuitry */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, 0);
+
+ /* TODO: Optimize */
+ msleep(50);
+
+ /* Connect HSBIAS in CTIA wiring */
+ /* TODO: Should likely be subject of detection */
+ regmap_write(cs42l84->regmap,
+ CS42L84_HS_SWITCH_CTL,
+ CS42L84_HS_SWITCH_CTL_REF_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_HS4);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_DET_CTL2,
+ CS42L84_HS_DET_CTL2_SET,
+ FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 0));
+
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_DETECT_MODE,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 3));
+
+ /* TODO: Optimize */
+ msleep(50);
+
+ regmap_read(cs42l84->regmap, CS42L84_HS_DET_STATUS2, &reg);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET,
+ CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET);
+
+ switch (reg & 0b11) {
+ case 0b11: /* shorted */
+ case 0b00: /* open */
+ /* Power down HSBIAS */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_HSBIAS_CTL,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1)); /* 0.0 V */
+ break;
+ }
+
+ switch (reg & 0b11) {
+ case 0b10: /* load */
+ dev_dbg(cs42l84->dev, "Detected mic\n");
+ cs42l84->hs_type = SND_JACK_HEADSET;
+ snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADSET,
+ SND_JACK_HEADSET);
+ break;
+
+ case 0b00: /* open */
+ dev_dbg(cs42l84->dev, "Detected open circuit on HS4\n");
+ fallthrough;
+ case 0b11: /* shorted */
+ default:
+ snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADSET);
+ cs42l84->hs_type = SND_JACK_HEADPHONE;
+ dev_dbg(cs42l84->dev, "Detected bare headphone (no mic)\n");
+ break;
+ }
+}
+
+static void cs42l84_revert_hs(struct cs42l84_private *cs42l84)
+{
+ /* Power down HSBIAS */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MISC_DET_CTL,
+ CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE,
+ FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1) | /* 0.0 V */
+ FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0));
+
+ /* Disconnect HSBIAS */
+ regmap_write(cs42l84->regmap,
+ CS42L84_HS_SWITCH_CTL,
+ CS42L84_HS_SWITCH_CTL_REF_HS3 | \
+ CS42L84_HS_SWITCH_CTL_REF_HS4 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS4);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_DET_CTL2,
+ CS42L84_HS_DET_CTL2_SET,
+ FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2));
+}
+
+static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84,
+ unsigned int val)
+{
+ regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK,
+ CS42L84_RS_PLUG | CS42L84_RS_UNPLUG |
+ CS42L84_TS_PLUG | CS42L84_TS_UNPLUG,
+ val);
+}
+
+static irqreturn_t cs42l84_irq_thread(int irq, void *data)
+{
+ struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data;
+ unsigned int stickies[1];
+ unsigned int masks[1];
+ unsigned int reg;
+ u8 current_tip_state;
+ u8 current_ring_state;
+ int i;
+
+ mutex_lock(&cs42l84->irq_lock);
+ /* Read sticky registers to clear interrupt */
+ for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+ regmap_read(cs42l84->regmap, irq_params_table[i].status_addr,
+ &(stickies[i]));
+ regmap_read(cs42l84->regmap, irq_params_table[i].mask_addr,
+ &(masks[i]));
+ stickies[i] = stickies[i] & (~masks[i]) &
+ irq_params_table[i].mask;
+ }
+
+ /* When handling plug sene IRQs, we only care about EITHER tip OR ring.
+ * Ring is useless on remove, and is only useful on insert for
+ * detecting if the plug state has changed AFTER we have handled the
+ * tip sense IRQ, e.g. if the plug was not fully seated within the tip
+ * sense debounce time.
+ */
+
+ if ((~masks[0]) & irq_params_table[0].mask) {
+ regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg);
+
+ current_tip_state = (((char) reg) &
+ (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
+ CS42L84_TS_PLUG_SHIFT;
+
+ if (current_tip_state != cs42l84->tip_state) {
+ cs42l84->tip_state = current_tip_state;
+ switch (current_tip_state) {
+ case CS42L84_PLUG:
+ dev_dbg(cs42l84->dev, "Plug event\n");
+
+ cs42l84_detect_hs(cs42l84);
+
+ /*
+ * Check the tip sense status again, and possibly invalidate
+ * the detection result
+ *
+ * Thanks to debounce, this should reliably indicate if the tip
+ * was disconnected at any point during the detection procedure.
+ */
+ regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg);
+ current_tip_state = (((char) reg) &
+ (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
+ CS42L84_TS_PLUG_SHIFT;
+ if (current_tip_state != CS42L84_PLUG) {
+ dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n");
+ cs42l84->tip_state = CS42L84_UNPLUG;
+ cs42l84_revert_hs(cs42l84);
+ }
+
+ /* Unmask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84, 0);
+ break;
+ case CS42L84_UNPLUG:
+ cs42l84->ring_state = CS42L84_UNPLUG;
+ dev_dbg(cs42l84->dev, "Unplug event\n");
+
+ cs42l84_revert_hs(cs42l84);
+ cs42l84->hs_type = 0;
+ snd_soc_jack_report(cs42l84->jack, 0,
+ SND_JACK_HEADSET);
+
+ /* Mask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84,
+ CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
+ break;
+ default:
+ cs42l84->ring_state = CS42L84_TRANS;
+ break;
+ }
+
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Tip state didn't change, we must've got a ring sense IRQ */
+ current_ring_state = (((char) reg) &
+ (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >>
+ CS42L84_RS_PLUG_SHIFT;
+
+ if (current_ring_state != cs42l84->ring_state) {
+ cs42l84->ring_state = current_ring_state;
+ if (current_ring_state == CS42L84_PLUG)
+ cs42l84_detect_hs(cs42l84);
+ }
+ }
+
+ mutex_unlock(&cs42l84->irq_lock);
+
+ return IRQ_HANDLED;
+}
+
+static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84)
+{
+ unsigned int reg;
+
+ /* Set up plug detection */
+ regmap_update_bits(cs42l84->regmap, CS42L84_MIC_DET_CTL4,
+ CS42L84_MIC_DET_CTL4_LATCH_TO_VP,
+ CS42L84_MIC_DET_CTL4_LATCH_TO_VP);
+ regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL2,
+ CS42L84_TIP_SENSE_CTL2_MODE,
+ FIELD_PREP(CS42L84_TIP_SENSE_CTL2_MODE, CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET));
+ regmap_update_bits(cs42l84->regmap, CS42L84_RING_SENSE_CTL,
+ CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 |
+ CS42L84_RING_SENSE_CTL_RISETIME | CS42L84_RING_SENSE_CTL_FALLTIME,
+ CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 |
+ FIELD_PREP(CS42L84_RING_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_125MS) |
+ FIELD_PREP(CS42L84_RING_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS));
+ regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL,
+ CS42L84_TIP_SENSE_CTL_INV |
+ CS42L84_TIP_SENSE_CTL_RISETIME | CS42L84_TIP_SENSE_CTL_FALLTIME,
+ CS42L84_TIP_SENSE_CTL_INV |
+ FIELD_PREP(CS42L84_TIP_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_500MS) |
+ FIELD_PREP(CS42L84_TIP_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS));
+ regmap_update_bits(cs42l84->regmap, CS42L84_MSM_BLOCK_EN3,
+ CS42L84_MSM_BLOCK_EN3_TR_SENSE,
+ CS42L84_MSM_BLOCK_EN3_TR_SENSE);
+
+ /* Save the initial status of the tip sense */
+ regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, &reg);
+ cs42l84->tip_state = (((char) reg) &
+ (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >>
+ CS42L84_TS_PLUG_SHIFT;
+
+ /* Set mic-detection threshold */
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_MIC_DET_CTL1, CS42L84_MIC_DET_CTL1_HS_DET_LEVEL,
+ FIELD_PREP(CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, 0x2c)); /* ~1.9 V */
+
+ /* Disconnect HSBIAS (initially) */
+ regmap_write(cs42l84->regmap,
+ CS42L84_HS_SWITCH_CTL,
+ CS42L84_HS_SWITCH_CTL_REF_HS3 | \
+ CS42L84_HS_SWITCH_CTL_REF_HS4 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \
+ CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \
+ CS42L84_HS_SWITCH_CTL_GNDHS_HS4);
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_DET_CTL2,
+ CS42L84_HS_DET_CTL2_SET | CS42L84_HS_DET_CTL2_CTL,
+ FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2) |
+ FIELD_PREP(CS42L84_HS_DET_CTL2_CTL, 0));
+ regmap_update_bits(cs42l84->regmap,
+ CS42L84_HS_CLAMP_DISABLE, 1, 1);
+
+}
+
+static int cs42l84_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct cs42l84_private *cs42l84;
+ int ret, devid;
+ unsigned int reg;
+
+ cs42l84 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l84_private),
+ GFP_KERNEL);
+ if (!cs42l84)
+ return -ENOMEM;
+
+ cs42l84->dev = &i2c_client->dev;
+ i2c_set_clientdata(i2c_client, cs42l84);
+ mutex_init(&cs42l84->irq_lock);
+
+ cs42l84->regmap = devm_regmap_init_i2c(i2c_client, &cs42l84_regmap);
+ if (IS_ERR(cs42l84->regmap)) {
+ ret = PTR_ERR(cs42l84->regmap);
+ dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset the Device */
+ cs42l84->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs42l84->reset_gpio)) {
+ ret = PTR_ERR(cs42l84->reset_gpio);
+ goto err_disable_noreset;
+ }
+
+ if (cs42l84->reset_gpio) {
+ dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+ gpiod_set_value_cansleep(cs42l84->reset_gpio, 1);
+ }
+ usleep_range(CS42L84_BOOT_TIME_US, CS42L84_BOOT_TIME_US * 2);
+
+ /* Request IRQ if one was specified */
+ if (i2c_client->irq) {
+ ret = request_threaded_irq(i2c_client->irq,
+ NULL, cs42l84_irq_thread,
+ IRQF_ONESHOT,
+ "cs42l84", cs42l84);
+ if (ret == -EPROBE_DEFER) {
+ goto err_disable_noirq;
+ } else if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to request IRQ: %d\n", ret);
+ goto err_disable_noirq;
+ }
+ }
+
+ /* initialize codec */
+ devid = cirrus_read_device_id(cs42l84->regmap, CS42L84_DEVID);
+ if (devid < 0) {
+ ret = devid;
+ dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret);
+ goto err_disable;
+ }
+
+ if (devid != CS42L84_CHIP_ID) {
+ dev_err(&i2c_client->dev,
+ "CS42L84 Device ID (%X). Expected %X\n",
+ devid, CS42L84_CHIP_ID);
+ ret = -EINVAL;
+ goto err_disable;
+ }
+
+ ret = regmap_read(cs42l84->regmap, CS42L84_REVID, &reg);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+ goto err_shutdown;
+ }
+
+ dev_info(&i2c_client->dev,
+ "Cirrus Logic CS42L84, Revision: %02X\n", reg & 0xFF);
+
+ /* Setup plug detection */
+ cs42l84_setup_plug_detect(cs42l84);
+
+ /* Mask ring sense interrupts */
+ cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG);
+
+ /* Register codec for machine driver */
+ ret = devm_snd_soc_register_component(&i2c_client->dev,
+ &soc_component_dev_cs42l84, &cs42l84_dai, 1);
+ if (ret < 0)
+ goto err_shutdown;
+
+ return 0;
+
+err_shutdown:
+ /* Nothing to do */
+
+err_disable:
+ if (i2c_client->irq)
+ free_irq(i2c_client->irq, cs42l84);
+
+err_disable_noirq:
+ gpiod_set_value_cansleep(cs42l84->reset_gpio, 0);
+err_disable_noreset:
+ return ret;
+}
+
+static void cs42l84_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cs42l84_private *cs42l84 = i2c_get_clientdata(i2c_client);
+
+ if (i2c_client->irq)
+ free_irq(i2c_client->irq, cs42l84);
+
+ gpiod_set_value_cansleep(cs42l84->reset_gpio, 0);
+}
+
+static const struct of_device_id cs42l84_of_match[] = {
+ { .compatible = "cirrus,cs42l84", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs42l84_of_match);
+
+static const struct i2c_device_id cs42l84_id[] = {
+ { "cs42l84" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l84_id);
+
+static struct i2c_driver cs42l84_i2c_driver = {
+ .driver = {
+ .name = "cs42l84",
+ .of_match_table = cs42l84_of_match,
+ },
+ .id_table = cs42l84_id,
+ .probe = cs42l84_i2c_probe,
+ .remove = cs42l84_i2c_remove,
+};
+
+module_i2c_driver(cs42l84_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L84 driver");
+MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
+MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l84.h b/sound/soc/codecs/cs42l84.h
new file mode 100644
index 000000000000..dbf778a902b9
--- /dev/null
+++ b/sound/soc/codecs/cs42l84.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) The Asahi Linux Contributors
+ *
+ * Based on sound/soc/codecs/cs42l42.h
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ */
+
+
+#ifndef __CS42L84_H__
+#define __CS42L84_H__
+
+#include <linux/bits.h>
+
+#define CS42L84_CHIP_ID 0x42a84
+
+#define CS42L84_DEVID 0x0000
+#define CS42L84_REVID 0x73fe
+#define CS42L84_FRZ_CTL 0x0006
+#define CS42L84_FRZ_CTL_ENGAGE BIT(0)
+
+#define CS42L84_TSRS_PLUG_INT_STATUS 0x0400
+#define CS42L84_TSRS_PLUG_INT_MASK 0x0418
+#define CS42L84_RS_PLUG_SHIFT 0
+#define CS42L84_RS_PLUG BIT(0)
+#define CS42L84_RS_UNPLUG BIT(1)
+#define CS42L84_TS_PLUG_SHIFT 2
+#define CS42L84_TS_PLUG BIT(2)
+#define CS42L84_TS_UNPLUG BIT(3)
+#define CS42L84_TSRS_PLUG_VAL_MASK GENMASK(3, 0)
+#define CS42L84_PLL_LOCK_STATUS 0x040e // probably bit 0x10
+#define CS42L84_PLL_LOCK_STATUS_LOCKED BIT(4)
+#define CS42L84_PLL_LOCK_STATUS_ERROR BIT(5)
+
+#define CS42L84_PLUG 3
+#define CS42L84_UNPLUG 0
+#define CS42L84_TRANS 1
+
+#define CS42L84_CCM_CTL1 0x0600
+#define CS42L84_CCM_CTL1_MCLK_SRC GENMASK(1, 0)
+#define CS42L84_CCM_CTL1_MCLK_SRC_RCO 0
+#define CS42L84_CCM_CTL1_MCLK_SRC_MCLK 1
+#define CS42L84_CCM_CTL1_MCLK_SRC_BCLK 2
+#define CS42L84_CCM_CTL1_MCLK_SRC_PLL 3
+#define CS42L84_CCM_CTL1_MCLK_FREQ GENMASK(3, 2)
+#define CS42L84_CCM_CTL1_MCLK_F_12MHZ 0b00
+#define CS42L84_CCM_CTL1_MCLK_F_24MHZ 0b01
+#define CS42L84_CCM_CTL1_MCLK_F_12_288KHZ 0b10
+#define CS42L84_CCM_CTL1_MCLK_F_24_576KHZ 0b11
+#define CS42L84_CCM_CTL1_RCO \
+ (FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_RCO) \
+ | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, CS42L84_CCM_CTL1_MCLK_F_12MHZ))
+
+#define CS42L84_CCM_SAMP_RATE 0x0601
+#define CS42L84_CCM_SAMP_RATE_RATE_48KHZ 4
+#define CS42L84_CCM_SAMP_RATE_RATE_96KHZ 5
+#define CS42L84_CCM_SAMP_RATE_RATE_192KHZ 6
+#define CS42L84_CCM_SAMP_RATE_RATE_44K1HZ 12
+#define CS42L84_CCM_SAMP_RATE_RATE_88K2HZ 13
+#define CS42L84_CCM_SAMP_RATE_RATE_176K4HZ 14
+#define CS42L84_CCM_CTL3 0x0602
+#define CS42L84_CCM_CTL3_REFCLK_DIV GENMASK(2, 1)
+#define CS42L84_CCM_CTL4 0x0603
+#define CS42L84_CCM_CTL4_REFCLK_EN BIT(0)
+
+#define CS42L84_CCM_ASP_CLK_CTRL 0x0608
+
+#define CS42L84_PLL_CTL1 0x0800
+#define CS42L84_PLL_CTL1_EN BIT(0)
+#define CS42L84_PLL_CTL1_MODE GENMASK(2, 1)
+#define CS42L84_PLL_DIV_FRAC0 0x0804
+#define CS42L84_PLL_DIV_FRAC1 0x0805
+#define CS42L84_PLL_DIV_FRAC2 0x0806
+#define CS42L84_PLL_DIV_INT 0x0807
+#define CS42L84_PLL_DIVOUT 0x0808
+
+#define CS42L84_RING_SENSE_CTL 0x1282
+#define CS42L84_RING_SENSE_CTL_INV BIT(7)
+#define CS42L84_RING_SENSE_CTL_UNK1 BIT(6)
+#define CS42L84_RING_SENSE_CTL_FALLTIME GENMASK(5, 3)
+#define CS42L84_RING_SENSE_CTL_RISETIME GENMASK(2, 0)
+#define CS42L84_TIP_SENSE_CTL 0x1283
+#define CS42L84_TIP_SENSE_CTL_INV BIT(7)
+#define CS42L84_TIP_SENSE_CTL_FALLTIME GENMASK(5, 3)
+#define CS42L84_TIP_SENSE_CTL_RISETIME GENMASK(2, 0)
+
+#define CS42L84_TSRS_PLUG_STATUS 0x1288
+
+#define CS42L84_TIP_SENSE_CTL2 0x1473
+#define CS42L84_TIP_SENSE_CTL2_MODE GENMASK(7, 6)
+#define CS42L84_TIP_SENSE_CTL2_MODE_DISABLED 0b00
+#define CS42L84_TIP_SENSE_CTL2_MODE_DIG_INPUT 0b01
+#define CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET 0b11
+#define CS42L84_TIP_SENSE_CTL2_INV BIT(5)
+
+#define CS42L84_MISC_DET_CTL 0x1474
+#define CS42L84_MISC_DET_CTL_DETECT_MODE GENMASK(4, 3)
+#define CS42L84_MISC_DET_CTL_HSBIAS_CTL GENMASK(2, 1)
+#define CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET BIT(0)
+
+#define CS42L84_MIC_DET_CTL1 0x1475
+#define CS42L84_MIC_DET_CTL1_HS_DET_LEVEL GENMASK(5, 0)
+
+#define CS42L84_MIC_DET_CTL4 0x1477
+#define CS42L84_MIC_DET_CTL4_LATCH_TO_VP BIT(1)
+
+#define CS42L84_HS_DET_STATUS2 0x147d
+
+#define CS42L84_MSM_BLOCK_EN1 0x1800
+#define CS42L84_MSM_BLOCK_EN2 0x1801
+#define CS42L84_MSM_BLOCK_EN2_ASP_SHIFT 6
+#define CS42L84_MSM_BLOCK_EN2_BUS_SHIFT 5
+#define CS42L84_MSM_BLOCK_EN2_DAC_SHIFT 4
+#define CS42L84_MSM_BLOCK_EN2_ADC_SHIFT 3
+#define CS42L84_MSM_BLOCK_EN3 0x1802
+#define CS42L84_MSM_BLOCK_EN3_TR_SENSE BIT(3)
+
+#define CS42L84_HS_DET_CTL2 0x1811
+#define CS42L84_HS_DET_CTL2_CTL GENMASK(7, 6)
+#define CS42L84_HS_DET_CTL2_SET GENMASK(5, 4)
+#define CS42L84_HS_DET_CTL2_REF BIT(3)
+#define CS42L84_HS_DET_CTL2_AUTO_TIME GENMASK(1, 0)
+
+#define CS42L84_HS_SWITCH_CTL 0x1812
+#define CS42L84_HS_SWITCH_CTL_REF_HS3 BIT(7)
+#define CS42L84_HS_SWITCH_CTL_REF_HS4 BIT(6)
+#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 BIT(5)
+#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 BIT(4)
+#define CS42L84_HS_SWITCH_CTL_HSB_HS3 BIT(3)
+#define CS42L84_HS_SWITCH_CTL_HSB_HS4 BIT(2)
+#define CS42L84_HS_SWITCH_CTL_GNDHS_HS3 BIT(1)
+#define CS42L84_HS_SWITCH_CTL_GNDHS_HS4 BIT(0)
+
+#define CS42L84_HS_CLAMP_DISABLE 0x1813
+
+#define CS42L84_ADC_CTL1 0x2000
+#define CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT 6
+#define CS42L84_ADC_CTL1_PGA_GAIN_SHIFT 0
+#define CS42L84_ADC_CTL4 0x2003
+#define CS42L84_ADC_CTL4_WNF_CF_SHIFT 4
+#define CS42L84_ADC_CTL4_WNF_EN_SHIFT 3
+#define CS42L84_ADC_CTL4_HPF_CF_SHIFT 1
+#define CS42L84_ADC_CTL4_HPF_EN_SHIFT 0
+
+#define CS42L84_DAC_CTL1 0x3000
+#define CS42L84_DAC_CTL1_UNMUTE BIT(0)
+//#define CS42L84_DAC_CTL1_DACB_INV_SHIFT 1
+//#define CS42L84_DAC_CTL1_DACA_INV_SHIFT 0
+#define CS42L84_DAC_CTL2 0x3001
+
+#define CS42L84_DAC_CHA_VOL_LSB 0x3004
+#define CS42L84_DAC_CHA_VOL_MSB 0x3005
+#define CS42L84_DAC_CHB_VOL_LSB 0x3006
+#define CS42L84_DAC_CHB_VOL_MSB 0x3007
+#define CS42L84_HP_VOL_CTL 0x3020
+#define CS42L84_HP_VOL_CTL_ZERO_CROSS BIT(1)
+#define CS42L84_HP_VOL_CTL_SOFT BIT(0)
+
+#define CS42L84_SRC_ASP_RX_CH1 0b1101
+#define CS42L84_SRC_ASP_RX_CH2 0b1110
+
+#define CS42L84_BUS_ASP_TX_SRC 0x4000
+#define CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT 0
+#define CS42L84_BUS_DAC_SRC 0x4001
+#define CS42L84_BUS_DAC_SRC_DACA_SHIFT 0
+#define CS42L84_BUS_DAC_SRC_DACB_SHIFT 4
+
+#define CS42L84_ASP_CTL 0x5000
+#define CS42L84_ASP_CTL_BCLK_EN_SHIFT 1
+#define CS42L84_ASP_CTL_TDM_MODE BIT(2)
+#define CS42L84_ASP_FSYNC_CTL2 0x5010
+#define CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO GENMASK(7, 1)
+#define CS42L84_ASP_FSYNC_CTL3 0x5011
+#define CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI GENMASK(4, 0)
+#define CS42L84_ASP_DATA_CTL 0x5018
+
+#define CS42L84_ASP_RX_EN 0x5020
+#define CS42L84_ASP_RX_EN_CH1_SHIFT 0
+#define CS42L84_ASP_RX_EN_CH2_SHIFT 1
+#define CS42L84_ASP_TX_EN 0x5024
+#define CS42L84_ASP_TX_EN_CH1_SHIFT 0
+
+#define CS42L84_ASP_RX_CH1_CTL1 0x5028
+#define CS42L84_ASP_RX_CH1_CTL2 0x5029
+#define CS42L84_ASP_RX_CH1_WIDTH 0x502a
+#define CS42L84_ASP_RX_CH2_CTL1 0x502c
+#define CS42L84_ASP_RX_CH2_CTL2 0x502d
+#define CS42L84_ASP_RX_CH2_WIDTH 0x502e
+
+#define CS42L84_ASP_RX_CHx_CTL1_EDGE BIT(0)
+#define CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB GENMASK(7, 1)
+#define CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB GENMASK(2, 0)
+
+#define CS42L84_ASP_TX_CH1_CTL1 0x5068
+#define CS42L84_ASP_TX_CH1_CTL2 0x5069
+#define CS42L84_ASP_TX_CH1_WIDTH 0x506a
+#define CS42L84_ASP_TX_CH2_CTL1 0x506c
+#define CS42L84_ASP_TX_CH2_CTL2 0x506d
+#define CS42L84_ASP_TX_CH2_WIDTH 0x506e
+
+#define CS42L84_DEBOUNCE_TIME_125MS 0b001
+#define CS42L84_DEBOUNCE_TIME_500MS 0b011
+
+#define CS42L84_BOOT_TIME_US 3000
+#define CS42L84_CLOCK_SWITCH_DELAY_US 150
+#define CS42L84_PLL_LOCK_POLL_US 250
+#define CS42L84_PLL_LOCK_TIMEOUT_US 1250
+
+#endif /* __CS42L84_H__ */
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index a422472820fb..039b3ecb3b9b 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -12,27 +12,21 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include "cs42xx8.h"
-static const struct of_device_id cs42xx8_of_match[];
-
static int cs42xx8_i2c_probe(struct i2c_client *i2c)
{
int ret;
struct cs42xx8_driver_data *drvdata;
- const struct of_device_id *of_id;
-
- of_id = of_match_device(cs42xx8_of_match, &i2c->dev);
- if (!of_id) {
- dev_err(&i2c->dev, "failed to find driver data\n");
- return -EINVAL;
- }
- drvdata = (struct cs42xx8_driver_data *)of_id->data;
+ drvdata = (struct cs42xx8_driver_data *)i2c_get_match_data(i2c);
+ if (!drvdata)
+ return dev_err_probe(&i2c->dev, -EINVAL,
+ "failed to find driver data\n");
ret = cs42xx8_probe(&i2c->dev,
devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config), drvdata);
@@ -67,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 4558ec38a7ac..d14538c49b97 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:
@@ -458,14 +458,14 @@ const struct regmap_config cs42xx8_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
.volatile_reg = cs42xx8_volatile_register,
.writeable_reg = cs42xx8_writeable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
static int cs42xx8_component_probe(struct snd_soc_component *component)
{
struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (cs42xx8->drvdata->num_adcs) {
case 3:
@@ -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 3292405024bc..a3bdaac9c059 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -11,12 +11,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -26,10 +25,8 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
-#include <linux/of_irq.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
@@ -239,7 +236,7 @@ static int cs43130_pll_config(struct snd_soc_component *component)
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
const struct cs43130_pll_params *pll_entry;
- dev_dbg(component->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
+ dev_dbg(cs43130->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
cs43130->mclk, cs43130->mclk_int);
pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int);
@@ -304,7 +301,7 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int
cs43130->mclk = freq_in;
break;
default:
- dev_err(component->dev,
+ dev_err(cs43130->dev,
"unsupported pll input reference clock:%d\n", freq_in);
return -EINVAL;
}
@@ -317,16 +314,44 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int
cs43130->mclk_int = freq_out;
break;
default:
- dev_err(component->dev,
+ dev_err(cs43130->dev,
"unsupported pll output ref clock: %u\n", freq_out);
return -EINVAL;
}
ret = cs43130_pll_config(component);
- dev_dbg(component->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
+ dev_dbg(cs43130->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
return ret;
}
+static int cs43130_wait_for_completion(struct cs43130_private *cs43130, struct completion *to_poll,
+ int time)
+{
+ int stickies, offset, flag, ret;
+
+ if (cs43130->has_irq_line) {
+ ret = wait_for_completion_timeout(to_poll, msecs_to_jiffies(time));
+ if (ret == 0)
+ return -ETIMEDOUT;
+ else
+ return 0; // Discard number of jiffies left till timeout and return success
+ }
+
+ if (to_poll == &cs43130->xtal_rdy) {
+ offset = 0;
+ flag = CS43130_XTAL_RDY_INT;
+ } else if (to_poll == &cs43130->pll_rdy) {
+ offset = 0;
+ flag = CS43130_PLL_RDY_INT;
+ } else {
+ return -EINVAL;
+ }
+
+ return regmap_read_poll_timeout(cs43130->regmap, CS43130_INT_STATUS_1 + offset,
+ stickies, (stickies & flag),
+ 1000, time * 1000);
+}
+
static int cs43130_change_clksrc(struct snd_soc_component *component,
enum cs43130_mclk_src_sel src)
{
@@ -347,7 +372,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
mclk_int_decoded = CS43130_MCLK_24P5;
break;
default:
- dev_err(component->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
+ dev_err(cs43130->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
return -EINVAL;
}
@@ -365,14 +390,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
CS43130_XTAL_RDY_INT_MASK, 0);
regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
CS43130_PDN_XTAL_MASK, 0);
- ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
- msecs_to_jiffies(100));
+ ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100);
regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
CS43130_XTAL_RDY_INT_MASK,
1 << CS43130_XTAL_RDY_INT_SHIFT);
- if (ret == 0) {
- dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
- return -ETIMEDOUT;
+ if (ret) {
+ dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret);
+ return ret;
}
}
@@ -401,14 +425,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
CS43130_XTAL_RDY_INT_MASK, 0);
regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
CS43130_PDN_XTAL_MASK, 0);
- ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
- msecs_to_jiffies(100));
+ ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100);
regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
CS43130_XTAL_RDY_INT_MASK,
1 << CS43130_XTAL_RDY_INT_SHIFT);
- if (ret == 0) {
- dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
- return -ETIMEDOUT;
+ if (ret) {
+ dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret);
+ return ret;
}
}
@@ -417,14 +440,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
CS43130_PLL_RDY_INT_MASK, 0);
regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
CS43130_PDN_PLL_MASK, 0);
- ret = wait_for_completion_timeout(&cs43130->pll_rdy,
- msecs_to_jiffies(100));
+ ret = cs43130_wait_for_completion(cs43130, &cs43130->pll_rdy, 100);
regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
CS43130_PLL_RDY_INT_MASK,
1 << CS43130_PLL_RDY_INT_SHIFT);
- if (ret == 0) {
- dev_err(component->dev, "Timeout waiting for PLL_READY interrupt\n");
- return -ETIMEDOUT;
+ if (ret) {
+ dev_err(cs43130->dev, "Error waiting for PLL_READY interrupt: %d\n", ret);
+ return ret;
}
regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
@@ -454,7 +476,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component,
1 << CS43130_PDN_PLL_SHIFT);
break;
default:
- dev_err(component->dev, "Invalid MCLK source value\n");
+ dev_err(cs43130->dev, "Invalid MCLK source value\n");
return -EINVAL;
}
@@ -579,7 +601,7 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
break;
case SND_SOC_DAIFMT_LEFT_J:
hi_size = bitwidth_sclk;
- frm_delay = 2;
+ frm_delay = 0;
frm_phase = 1;
break;
case SND_SOC_DAIFMT_DSP_A:
@@ -596,11 +618,32 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
return -EINVAL;
}
+ switch (cs43130->dais[dai_id].dai_invert) {
+ case SND_SOC_DAIFMT_NB_NF:
+ sclk_edge = 1;
+ lrck_edge = 0;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ sclk_edge = 0;
+ lrck_edge = 0;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ sclk_edge = 1;
+ lrck_edge = 1;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ sclk_edge = 0;
+ lrck_edge = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
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:
@@ -608,8 +651,6 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
}
frm_size = bitwidth_sclk * params_channels(params);
- sclk_edge = 1;
- lrck_edge = 0;
loc_ch1 = 0;
loc_ch2 = bitwidth_sclk * (params_channels(params) - 1);
@@ -805,12 +846,12 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
dsd_speed = 1;
break;
default:
- dev_err(component->dev, "Rate(%u) not supported\n",
+ dev_err(cs43130->dev, "Rate(%u) not supported\n",
params_rate(params));
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
@@ -876,7 +917,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
dsd_speed = 1;
break;
default:
- dev_err(component->dev, "Rate(%u) not supported\n",
+ dev_err(cs43130->dev, "Rate(%u) not supported\n",
params_rate(params));
return -EINVAL;
}
@@ -893,7 +934,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val);
break;
default:
- dev_err(component->dev, "Invalid DAI (%d)\n", dai->id);
+ dev_err(cs43130->dev, "Invalid DAI (%d)\n", dai->id);
return -EINVAL;
}
@@ -910,28 +951,28 @@ 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);
if (!sclk) {
/* at this point, SCLK must be set */
- dev_err(component->dev, "SCLK freq is not set\n");
+ dev_err(cs43130->dev, "SCLK freq is not set\n");
return -EINVAL;
}
bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params);
if (bitwidth_sclk < bitwidth_dai) {
- dev_err(component->dev, "Format not supported: SCLK freq is too low\n");
+ dev_err(cs43130->dev, "Format not supported: SCLK freq is too low\n");
return -EINVAL;
}
- dev_dbg(component->dev,
+ dev_dbg(cs43130->dev,
"sclk = %u, fs = %d, bitwidth_dai = %u\n",
sclk, params_rate(params), bitwidth_dai);
- dev_dbg(component->dev,
+ dev_dbg(cs43130->dev,
"bitwidth_sclk = %u, num_ch = %u\n",
bitwidth_sclk, params_channels(params));
@@ -1021,7 +1062,7 @@ static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol,
{
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
unsigned int val;
@@ -1190,7 +1231,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
}
break;
default:
- dev_err(component->dev, "Invalid event = 0x%x\n", event);
+ dev_err(cs43130->dev, "Invalid event = 0x%x\n", event);
return -EINVAL;
}
return 0;
@@ -1247,7 +1288,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
}
break;
default:
- dev_err(component->dev, "Invalid event = 0x%x\n", event);
+ dev_err(cs43130->dev, "Invalid event = 0x%x\n", event);
return -EINVAL;
}
return 0;
@@ -1323,7 +1364,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
}
break;
default:
- dev_err(component->dev, "Invalid DAC event = 0x%x\n", event);
+ dev_err(cs43130->dev, "Invalid DAC event = 0x%x\n", event);
return -EINVAL;
}
return 0;
@@ -1361,13 +1402,21 @@ static int cs43130_hpin_event(struct snd_soc_dapm_widget *w,
ARRAY_SIZE(hpin_postpmu_seq));
break;
default:
- dev_err(component->dev, "Invalid HPIN event = 0x%x\n", event);
+ dev_err(cs43130->dev, "Invalid HPIN event = 0x%x\n", event);
return -EINVAL;
}
return 0;
}
-static const struct snd_soc_dapm_widget digital_hp_widgets[] = {
+static const char * const bypass_mux_text[] = {
+ "Internal",
+ "Alternative",
+};
+static SOC_ENUM_SINGLE_DECL(bypass_enum, SND_SOC_NOPM, 0, bypass_mux_text);
+static const struct snd_kcontrol_new bypass_ctrl = SOC_DAPM_ENUM("Switch", bypass_enum);
+
+static const struct snd_soc_dapm_widget hp_widgets[] = {
+ SND_SOC_DAPM_MUX("Bypass Switch", SND_SOC_NOPM, 0, 0, &bypass_ctrl),
SND_SOC_DAPM_OUTPUT("HPOUTA"),
SND_SOC_DAPM_OUTPUT("HPOUTB"),
@@ -1398,19 +1447,16 @@ static const struct snd_soc_dapm_widget digital_hp_widgets[] = {
CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event,
(SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_POST_PMD)),
-};
-static const struct snd_soc_dapm_widget analog_hp_widgets[] = {
+/* Some devices have some extra analog widgets */
+#define NUM_ANALOG_WIDGETS 1
+
SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1,
CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event,
(SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
};
-static struct snd_soc_dapm_widget all_hp_widgets[
- ARRAY_SIZE(digital_hp_widgets) +
- ARRAY_SIZE(analog_hp_widgets)];
-
-static const struct snd_soc_dapm_route digital_hp_routes[] = {
+static const struct snd_soc_dapm_route hp_routes[] = {
{"ASPIN PCM", NULL, "ASP PCM Playback"},
{"ASPIN DoP", NULL, "ASP DoP Playback"},
{"XSPIN DoP", NULL, "XSP DoP Playback"},
@@ -1420,18 +1466,15 @@ static const struct snd_soc_dapm_route digital_hp_routes[] = {
{"DSD", NULL, "XSPIN DSD"},
{"HiFi DAC", NULL, "ASPIN PCM"},
{"HiFi DAC", NULL, "DSD"},
- {"HPOUTA", NULL, "HiFi DAC"},
- {"HPOUTB", NULL, "HiFi DAC"},
-};
+ {"Bypass Switch", "Internal", "HiFi DAC"},
+ {"HPOUTA", NULL, "Bypass Switch"},
+ {"HPOUTB", NULL, "Bypass Switch"},
-static const struct snd_soc_dapm_route analog_hp_routes[] = {
- {"HPOUTA", NULL, "Analog Playback"},
- {"HPOUTB", NULL, "Analog Playback"},
+/* Some devices have some extra analog routes */
+#define NUM_ANALOG_ROUTES 1
+ {"Bypass Switch", "Alternative", "Analog Playback"},
};
-static struct snd_soc_dapm_route all_hp_routes[
- ARRAY_SIZE(digital_hp_routes) +
- ARRAY_SIZE(analog_hp_routes)];
static const unsigned int cs43130_asp_src_rates[] = {
32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
@@ -1473,14 +1516,33 @@ 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(component->dev, "unsupported mode\n");
+ dev_err(cs43130->dev, "unsupported mode\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_NB_NF;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_IB_NF;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_NB_IF;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_IB_IF;
+ break;
+ default:
+ dev_err(cs43130->dev, "Unsupported invert mode 0x%x\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
return -EINVAL;
}
@@ -1498,12 +1560,12 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B;
break;
default:
- dev_err(component->dev,
+ dev_err(cs43130->dev,
"unsupported audio format\n");
return -EINVAL;
}
- dev_dbg(component->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n",
+ dev_dbg(cs43130->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n",
codec_dai->id,
cs43130->dais[codec_dai->id].dai_mode,
cs43130->dais[codec_dai->id].dai_format);
@@ -1517,18 +1579,18 @@ 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(component->dev, "Unsupported DAI format.\n");
+ dev_err(cs43130->dev, "Unsupported DAI format.\n");
return -EINVAL;
}
- dev_dbg(component->dev, "dai_mode = 0x%x\n",
+ dev_dbg(cs43130->dev, "dai_mode = 0x%x\n",
cs43130->dais[codec_dai->id].dai_mode);
return 0;
@@ -1541,7 +1603,7 @@ static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
cs43130->dais[codec_dai->id].sclk = freq;
- dev_dbg(component->dev, "dai_id = %d, sclk = %u\n", codec_dai->id,
+ dev_dbg(cs43130->dev, "dai_id = %d, sclk = %u\n", codec_dai->id,
cs43130->dais[codec_dai->id].sclk);
return 0;
@@ -1631,7 +1693,7 @@ static int cs43130_component_set_sysclk(struct snd_soc_component *component,
{
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
- dev_dbg(component->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
+ dev_dbg(cs43130->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
clk_id, source, freq, dir);
switch (freq) {
@@ -1640,14 +1702,14 @@ static int cs43130_component_set_sysclk(struct snd_soc_component *component,
cs43130->mclk = freq;
break;
default:
- dev_err(component->dev, "Invalid MCLK INT freq: %u\n", freq);
+ dev_err(cs43130->dev, "Invalid MCLK INT freq: %u\n", freq);
return -EINVAL;
}
if (source == CS43130_MCLK_SRC_EXT) {
cs43130->pll_bypass = true;
} else {
- dev_err(component->dev, "Invalid MCLK source\n");
+ dev_err(cs43130->dev, "Invalid MCLK source\n");
return -EINVAL;
}
@@ -1683,7 +1745,7 @@ static ssize_t hpload_dc_r_show(struct device *dev,
return cs43130_show_dc(dev, buf, HP_RIGHT);
}
-static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = {
+static const u16 cs43130_ac_freq[CS43130_AC_FREQ] = {
24,
43,
93,
@@ -1743,7 +1805,7 @@ static struct attribute *hpload_attrs[] = {
};
ATTRIBUTE_GROUPS(hpload);
-static struct reg_sequence hp_en_cal_seq[] = {
+static const struct reg_sequence hp_en_cal_seq[] = {
{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
{CS43130_HP_MEAS_LOAD_1, 0},
{CS43130_HP_MEAS_LOAD_2, 0},
@@ -1758,7 +1820,7 @@ static struct reg_sequence hp_en_cal_seq[] = {
{CS43130_HP_LOAD_1, 0x80},
};
-static struct reg_sequence hp_en_cal_seq2[] = {
+static const struct reg_sequence hp_en_cal_seq2[] = {
{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
{CS43130_HP_MEAS_LOAD_1, 0},
{CS43130_HP_MEAS_LOAD_2, 0},
@@ -1766,7 +1828,7 @@ static struct reg_sequence hp_en_cal_seq2[] = {
{CS43130_HP_LOAD_1, 0x80},
};
-static struct reg_sequence hp_dis_cal_seq[] = {
+static const struct reg_sequence hp_dis_cal_seq[] = {
{CS43130_HP_LOAD_1, 0x80},
{CS43130_DXD1, 0x99},
{CS43130_DXD12, 0},
@@ -1774,12 +1836,12 @@ static struct reg_sequence hp_dis_cal_seq[] = {
{CS43130_HP_LOAD_1, 0},
};
-static struct reg_sequence hp_dis_cal_seq2[] = {
+static const struct reg_sequence hp_dis_cal_seq2[] = {
{CS43130_HP_LOAD_1, 0x80},
{CS43130_HP_LOAD_1, 0},
};
-static struct reg_sequence hp_dc_ch_l_seq[] = {
+static const struct reg_sequence hp_dc_ch_l_seq[] = {
{CS43130_DXD1, 0x99},
{CS43130_DXD19, 0x0A},
{CS43130_DXD17, 0x93},
@@ -1789,12 +1851,12 @@ static struct reg_sequence hp_dc_ch_l_seq[] = {
{CS43130_HP_LOAD_1, 0x81},
};
-static struct reg_sequence hp_dc_ch_l_seq2[] = {
+static const struct reg_sequence hp_dc_ch_l_seq2[] = {
{CS43130_HP_LOAD_1, 0x80},
{CS43130_HP_LOAD_1, 0x81},
};
-static struct reg_sequence hp_dc_ch_r_seq[] = {
+static const struct reg_sequence hp_dc_ch_r_seq[] = {
{CS43130_DXD1, 0x99},
{CS43130_DXD19, 0x8A},
{CS43130_DXD17, 0x15},
@@ -1804,12 +1866,12 @@ static struct reg_sequence hp_dc_ch_r_seq[] = {
{CS43130_HP_LOAD_1, 0x91},
};
-static struct reg_sequence hp_dc_ch_r_seq2[] = {
+static const struct reg_sequence hp_dc_ch_r_seq2[] = {
{CS43130_HP_LOAD_1, 0x90},
{CS43130_HP_LOAD_1, 0x91},
};
-static struct reg_sequence hp_ac_ch_l_seq[] = {
+static const struct reg_sequence hp_ac_ch_l_seq[] = {
{CS43130_DXD1, 0x99},
{CS43130_DXD19, 0x0A},
{CS43130_DXD17, 0x93},
@@ -1819,12 +1881,12 @@ static struct reg_sequence hp_ac_ch_l_seq[] = {
{CS43130_HP_LOAD_1, 0x82},
};
-static struct reg_sequence hp_ac_ch_l_seq2[] = {
+static const struct reg_sequence hp_ac_ch_l_seq2[] = {
{CS43130_HP_LOAD_1, 0x80},
{CS43130_HP_LOAD_1, 0x82},
};
-static struct reg_sequence hp_ac_ch_r_seq[] = {
+static const struct reg_sequence hp_ac_ch_r_seq[] = {
{CS43130_DXD1, 0x99},
{CS43130_DXD19, 0x8A},
{CS43130_DXD17, 0x15},
@@ -1834,24 +1896,24 @@ static struct reg_sequence hp_ac_ch_r_seq[] = {
{CS43130_HP_LOAD_1, 0x92},
};
-static struct reg_sequence hp_ac_ch_r_seq2[] = {
+static const struct reg_sequence hp_ac_ch_r_seq2[] = {
{CS43130_HP_LOAD_1, 0x90},
{CS43130_HP_LOAD_1, 0x92},
};
-static struct reg_sequence hp_cln_seq[] = {
+static const struct reg_sequence hp_cln_seq[] = {
{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
{CS43130_HP_MEAS_LOAD_1, 0},
{CS43130_HP_MEAS_LOAD_2, 0},
};
struct reg_sequences {
- struct reg_sequence *seq;
- int size;
- unsigned int msk;
+ const struct reg_sequence *seq;
+ int size;
+ unsigned int msk;
};
-static struct reg_sequences hpload_seq1[] = {
+static const struct reg_sequences hpload_seq1[] = {
{
.seq = hp_en_cal_seq,
.size = ARRAY_SIZE(hp_en_cal_seq),
@@ -1889,7 +1951,7 @@ static struct reg_sequences hpload_seq1[] = {
},
};
-static struct reg_sequences hpload_seq2[] = {
+static const struct reg_sequences hpload_seq2[] = {
{
.seq = hp_en_cal_seq2,
.size = ARRAY_SIZE(hp_en_cal_seq2),
@@ -1934,7 +1996,6 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
unsigned int reg;
u32 addr;
u16 impedance;
- struct snd_soc_component *component = cs43130->component;
switch (msk) {
case CS43130_HPLOAD_DC_INT:
@@ -1964,7 +2025,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
else
cs43130->hpload_dc[HP_RIGHT] = impedance;
- dev_dbg(component->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
+ dev_dbg(cs43130->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
impedance);
} else {
if (left_ch)
@@ -1972,7 +2033,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
else
cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance;
- dev_dbg(component->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
+ dev_dbg(cs43130->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
cs43130->ac_freq[ac_idx], !left_ch, impedance);
}
@@ -1980,13 +2041,12 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx,
}
static int cs43130_hpload_proc(struct cs43130_private *cs43130,
- struct reg_sequence *seq, int seq_size,
+ const struct reg_sequence *seq, int seq_size,
unsigned int rslt_msk, int ac_idx)
{
int ret;
unsigned int msk;
u16 ac_reg_val;
- struct snd_soc_component *component = cs43130->component;
reinit_completion(&cs43130->hpload_evt);
@@ -2009,17 +2069,17 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130,
msecs_to_jiffies(1000));
regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk);
if (!ret) {
- dev_err(component->dev, "Timeout waiting for HPLOAD interrupt\n");
- return -1;
+ dev_err(cs43130->dev, "Timeout waiting for HPLOAD interrupt\n");
+ return -ETIMEDOUT;
}
- dev_dbg(component->dev, "HP load stat: %x, INT_MASK_4: %x\n",
+ dev_dbg(cs43130->dev, "HP load stat: %x, INT_MASK_4: %x\n",
cs43130->hpload_stat, msk);
if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT |
CS43130_HPLOAD_UNPLUG_INT |
CS43130_HPLOAD_OOR_INT)) ||
!(cs43130->hpload_stat & rslt_msk)) {
- dev_dbg(component->dev, "HP load measure failed\n");
+ dev_dbg(cs43130->dev, "HP load measure failed\n");
return -1;
}
@@ -2062,7 +2122,7 @@ static void cs43130_imp_meas(struct work_struct *wk)
int i, ret, ac_idx;
struct cs43130_private *cs43130;
struct snd_soc_component *component;
- struct reg_sequences *hpload_seq;
+ const struct reg_sequences *hpload_seq;
cs43130 = container_of(wk, struct cs43130_private, work);
component = cs43130->component;
@@ -2130,9 +2190,9 @@ static void cs43130_imp_meas(struct work_struct *wk)
snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE,
CS43130_JACK_MASK);
- dev_dbg(component->dev, "Set HP output control. DC threshold\n");
+ dev_dbg(cs43130->dev, "Set HP output control. DC threshold\n");
for (i = 0; i < CS43130_DC_THRESHOLD; i++)
- dev_dbg(component->dev, "DC threshold[%d]: %u.\n", i,
+ dev_dbg(cs43130->dev, "DC threshold[%d]: %u.\n", i,
cs43130->dc_threshold[i]);
cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT],
@@ -2166,7 +2226,6 @@ exit:
static irqreturn_t cs43130_irq_thread(int irq, void *data)
{
struct cs43130_private *cs43130 = (struct cs43130_private *)data;
- struct snd_soc_component *component = cs43130->component;
unsigned int stickies[CS43130_NUM_INT];
unsigned int irq_occurrence = 0;
unsigned int masks[CS43130_NUM_INT];
@@ -2184,8 +2243,6 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
for (j = 0; j < 8; j++)
irq_occurrence += (stickies[i] >> j) & 1;
}
- dev_dbg(component->dev, "number of interrupts occurred (%u)\n",
- irq_occurrence);
if (!irq_occurrence)
return IRQ_NONE;
@@ -2202,7 +2259,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) {
cs43130->hpload_stat = stickies[3];
- dev_err(component->dev,
+ dev_err(cs43130->dev,
"DC load has not completed before AC load (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
@@ -2211,7 +2268,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) {
cs43130->hpload_stat = stickies[3];
- dev_err(component->dev, "HP unplugged during measurement (%x)\n",
+ dev_err(cs43130->dev, "HP unplugged during measurement (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
return IRQ_HANDLED;
@@ -2219,7 +2276,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_OOR_INT) {
cs43130->hpload_stat = stickies[3];
- dev_err(component->dev, "HP load out of range (%x)\n",
+ dev_err(cs43130->dev, "HP load out of range (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
return IRQ_HANDLED;
@@ -2227,7 +2284,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_AC_INT) {
cs43130->hpload_stat = stickies[3];
- dev_dbg(component->dev, "HP AC load measurement done (%x)\n",
+ dev_dbg(cs43130->dev, "HP AC load measurement done (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
return IRQ_HANDLED;
@@ -2235,7 +2292,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_DC_INT) {
cs43130->hpload_stat = stickies[3];
- dev_dbg(component->dev, "HP DC load measurement done (%x)\n",
+ dev_dbg(cs43130->dev, "HP DC load measurement done (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
return IRQ_HANDLED;
@@ -2243,7 +2300,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_ON_INT) {
cs43130->hpload_stat = stickies[3];
- dev_dbg(component->dev, "HP load state machine on done (%x)\n",
+ dev_dbg(cs43130->dev, "HP load state machine on done (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
return IRQ_HANDLED;
@@ -2251,19 +2308,19 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[3] & CS43130_HPLOAD_OFF_INT) {
cs43130->hpload_stat = stickies[3];
- dev_dbg(component->dev, "HP load state machine off done (%x)\n",
+ dev_dbg(cs43130->dev, "HP load state machine off done (%x)\n",
cs43130->hpload_stat);
complete(&cs43130->hpload_evt);
return IRQ_HANDLED;
}
if (stickies[0] & CS43130_XTAL_ERR_INT) {
- dev_err(component->dev, "Crystal err: clock is not running\n");
+ dev_err(cs43130->dev, "Crystal err: clock is not running\n");
return IRQ_HANDLED;
}
if (stickies[0] & CS43130_HP_UNPLUG_INT) {
- dev_dbg(component->dev, "HP unplugged\n");
+ dev_dbg(cs43130->dev, "HP unplugged\n");
cs43130->hpload_done = false;
snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK);
return IRQ_HANDLED;
@@ -2272,7 +2329,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data)
if (stickies[0] & CS43130_HP_PLUG_INT) {
if (cs43130->dc_meas && !cs43130->hpload_done &&
!work_busy(&cs43130->work)) {
- dev_dbg(component->dev, "HP load queue work\n");
+ dev_dbg(cs43130->dev, "HP load queue work\n");
queue_work(cs43130->wq, &cs43130->work);
}
@@ -2304,19 +2361,19 @@ static int cs43130_probe(struct snd_soc_component *component)
ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK,
&cs43130->jack);
if (ret < 0) {
- dev_err(component->dev, "Cannot create jack\n");
+ dev_err(cs43130->dev, "Cannot create jack\n");
return ret;
}
cs43130->hpload_done = false;
if (cs43130->dc_meas) {
- ret = sysfs_create_groups(&component->dev->kobj, hpload_groups);
+ ret = sysfs_create_groups(&cs43130->dev->kobj, hpload_groups);
if (ret)
return ret;
cs43130->wq = create_singlethread_workqueue("cs43130_hp");
if (!cs43130->wq) {
- sysfs_remove_groups(&component->dev->kobj, hpload_groups);
+ sysfs_remove_groups(&cs43130->dev->kobj, hpload_groups);
return -ENOMEM;
}
INIT_WORK(&cs43130->work, cs43130_imp_meas);
@@ -2335,7 +2392,23 @@ static int cs43130_probe(struct snd_soc_component *component)
return 0;
}
-static struct snd_soc_component_driver soc_component_dev_cs43130 = {
+static const struct snd_soc_component_driver soc_component_dev_cs43130_digital = {
+ .probe = cs43130_probe,
+ .controls = cs43130_snd_controls,
+ .num_controls = ARRAY_SIZE(cs43130_snd_controls),
+ .set_sysclk = cs43130_component_set_sysclk,
+ .set_pll = cs43130_set_pll,
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ /* Don't take into account the ending analog widgets and routes */
+ .dapm_widgets = hp_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(hp_widgets) - NUM_ANALOG_WIDGETS,
+ .dapm_routes = hp_routes,
+ .num_dapm_routes = ARRAY_SIZE(hp_routes) - NUM_ANALOG_ROUTES,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_cs43130_analog = {
.probe = cs43130_probe,
.controls = cs43130_snd_controls,
.num_controls = ARRAY_SIZE(cs43130_snd_controls),
@@ -2344,6 +2417,10 @@ static struct snd_soc_component_driver soc_component_dev_cs43130 = {
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
+ .dapm_widgets = hp_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(hp_widgets),
+ .dapm_routes = hp_routes,
+ .num_dapm_routes = ARRAY_SIZE(hp_routes),
};
static const struct regmap_config cs43130_regmap = {
@@ -2363,19 +2440,17 @@ static const struct regmap_config cs43130_regmap = {
.use_single_write = true,
};
-static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
+static const u16 cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
50,
120,
};
-static int cs43130_handle_device_data(struct i2c_client *i2c_client,
- struct cs43130_private *cs43130)
+static int cs43130_handle_device_data(struct cs43130_private *cs43130)
{
- struct device_node *np = i2c_client->dev.of_node;
unsigned int val;
int i;
- if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) {
+ if (device_property_read_u32(cs43130->dev, "cirrus,xtal-ibias", &val) < 0) {
/* Crystal is unused. System clock is used for external MCLK */
cs43130->xtal_ibias = CS43130_XTAL_UNUSED;
return 0;
@@ -2392,23 +2467,23 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client,
cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA;
break;
default:
- dev_err(&i2c_client->dev,
+ dev_err(cs43130->dev,
"Invalid cirrus,xtal-ibias value: %d\n", val);
return -EINVAL;
}
- cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure");
- cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure");
+ cs43130->dc_meas = device_property_read_bool(cs43130->dev, "cirrus,dc-measure");
+ cs43130->ac_meas = device_property_read_bool(cs43130->dev, "cirrus,ac-measure");
- if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq,
- CS43130_AC_FREQ) < 0) {
+ if (!device_property_read_u16_array(cs43130->dev, "cirrus,ac-freq", cs43130->ac_freq,
+ CS43130_AC_FREQ)) {
for (i = 0; i < CS43130_AC_FREQ; i++)
cs43130->ac_freq[i] = cs43130_ac_freq[i];
}
- if (of_property_read_u16_array(np, "cirrus,dc-threshold",
+ if (!device_property_read_u16_array(cs43130->dev, "cirrus,dc-threshold",
cs43130->dc_threshold,
- CS43130_DC_THRESHOLD) < 0) {
+ CS43130_DC_THRESHOLD)) {
for (i = 0; i < CS43130_DC_THRESHOLD; i++)
cs43130->dc_threshold[i] = cs43130_dc_threshold[i];
}
@@ -2418,6 +2493,7 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client,
static int cs43130_i2c_probe(struct i2c_client *client)
{
+ const struct snd_soc_component_driver *component_driver;
struct cs43130_private *cs43130;
int ret;
unsigned int reg;
@@ -2427,6 +2503,8 @@ static int cs43130_i2c_probe(struct i2c_client *client)
if (!cs43130)
return -ENOMEM;
+ cs43130->dev = &client->dev;
+
i2c_set_clientdata(client, cs43130);
cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap);
@@ -2435,29 +2513,30 @@ static int cs43130_i2c_probe(struct i2c_client *client)
return ret;
}
- if (client->dev.of_node) {
- ret = cs43130_handle_device_data(client, cs43130);
+ if (dev_fwnode(cs43130->dev)) {
+ ret = cs43130_handle_device_data(cs43130);
if (ret != 0)
return ret;
}
+
for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++)
cs43130->supplies[i].supply = cs43130_supply_names[i];
- ret = devm_regulator_bulk_get(&client->dev,
+ ret = devm_regulator_bulk_get(cs43130->dev,
ARRAY_SIZE(cs43130->supplies),
cs43130->supplies);
if (ret != 0) {
- dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
+ dev_err(cs43130->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies),
cs43130->supplies);
if (ret != 0) {
- dev_err(&client->dev, "Failed to enable supplies: %d\n", ret);
+ dev_err(cs43130->dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
- cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev,
+ cs43130->reset_gpio = devm_gpiod_get_optional(cs43130->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(cs43130->reset_gpio)) {
ret = PTR_ERR(cs43130->reset_gpio);
@@ -2471,7 +2550,7 @@ static int cs43130_i2c_probe(struct i2c_client *client)
devid = cirrus_read_device_id(cs43130->regmap, CS43130_DEVID_AB);
if (devid < 0) {
ret = devid;
- dev_err(&client->dev, "Failed to read device ID: %d\n", ret);
+ dev_err(cs43130->dev, "Failed to read device ID: %d\n", ret);
goto err;
}
@@ -2482,7 +2561,7 @@ static int cs43130_i2c_probe(struct i2c_client *client)
case CS43198_CHIP_ID:
break;
default:
- dev_err(&client->dev,
+ dev_err(cs43130->dev,
"CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n",
devid, CS43130_CHIP_ID, CS4399_CHIP_ID,
CS43131_CHIP_ID, CS43198_CHIP_ID);
@@ -2493,11 +2572,11 @@ static int cs43130_i2c_probe(struct i2c_client *client)
cs43130->dev_id = devid;
ret = regmap_read(cs43130->regmap, CS43130_REV_ID, &reg);
if (ret < 0) {
- dev_err(&client->dev, "Get Revision ID failed\n");
+ dev_err(cs43130->dev, "Get Revision ID failed\n");
goto err;
}
- dev_info(&client->dev,
+ dev_info(cs43130->dev,
"Cirrus Logic CS43130 (%x), Revision: %02X\n", devid,
reg & 0xFF);
@@ -2507,61 +2586,43 @@ static int cs43130_i2c_probe(struct i2c_client *client)
init_completion(&cs43130->pll_rdy);
init_completion(&cs43130->hpload_evt);
- ret = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, cs43130_irq_thread,
- IRQF_ONESHOT | IRQF_TRIGGER_LOW,
- "cs43130", cs43130);
- if (ret != 0) {
- dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);
- goto err;
+ if (!client->irq) {
+ dev_dbg(cs43130->dev, "IRQ not found, will poll instead\n");
+ cs43130->has_irq_line = 0;
+ } else {
+ ret = devm_request_threaded_irq(cs43130->dev, client->irq,
+ NULL, cs43130_irq_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs43130", cs43130);
+ if (ret != 0) {
+ dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret);
+ goto err;
+ }
+ cs43130->has_irq_line = 1;
}
cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
- pm_runtime_set_autosuspend_delay(&client->dev, 100);
- pm_runtime_use_autosuspend(&client->dev);
- pm_runtime_set_active(&client->dev);
- pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(cs43130->dev, 100);
+ pm_runtime_use_autosuspend(cs43130->dev);
+ pm_runtime_set_active(cs43130->dev);
+ pm_runtime_enable(cs43130->dev);
switch (cs43130->dev_id) {
case CS43130_CHIP_ID:
case CS43131_CHIP_ID:
- memcpy(all_hp_widgets, digital_hp_widgets,
- sizeof(digital_hp_widgets));
- memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets),
- analog_hp_widgets, sizeof(analog_hp_widgets));
- memcpy(all_hp_routes, digital_hp_routes,
- sizeof(digital_hp_routes));
- memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes),
- analog_hp_routes, sizeof(analog_hp_routes));
-
- soc_component_dev_cs43130.dapm_widgets =
- all_hp_widgets;
- soc_component_dev_cs43130.num_dapm_widgets =
- ARRAY_SIZE(all_hp_widgets);
- soc_component_dev_cs43130.dapm_routes =
- all_hp_routes;
- soc_component_dev_cs43130.num_dapm_routes =
- ARRAY_SIZE(all_hp_routes);
+ component_driver = &soc_component_dev_cs43130_analog;
break;
case CS43198_CHIP_ID:
case CS4399_CHIP_ID:
- soc_component_dev_cs43130.dapm_widgets =
- digital_hp_widgets;
- soc_component_dev_cs43130.num_dapm_widgets =
- ARRAY_SIZE(digital_hp_widgets);
- soc_component_dev_cs43130.dapm_routes =
- digital_hp_routes;
- soc_component_dev_cs43130.num_dapm_routes =
- ARRAY_SIZE(digital_hp_routes);
+ component_driver = &soc_component_dev_cs43130_digital;
break;
}
- ret = devm_snd_soc_register_component(&client->dev,
- &soc_component_dev_cs43130,
+ ret = devm_snd_soc_register_component(cs43130->dev, component_driver,
cs43130_dai, ARRAY_SIZE(cs43130_dai));
if (ret < 0) {
- dev_err(&client->dev,
+ dev_err(cs43130->dev,
"snd_soc_register_component failed with ret = %d\n", ret);
goto err;
}
@@ -2599,19 +2660,19 @@ static void cs43130_i2c_remove(struct i2c_client *client)
cancel_work_sync(&cs43130->work);
flush_workqueue(cs43130->wq);
- device_remove_file(&client->dev, &dev_attr_hpload_dc_l);
- device_remove_file(&client->dev, &dev_attr_hpload_dc_r);
- device_remove_file(&client->dev, &dev_attr_hpload_ac_l);
- device_remove_file(&client->dev, &dev_attr_hpload_ac_r);
+ device_remove_file(cs43130->dev, &dev_attr_hpload_dc_l);
+ device_remove_file(cs43130->dev, &dev_attr_hpload_dc_r);
+ device_remove_file(cs43130->dev, &dev_attr_hpload_ac_l);
+ device_remove_file(cs43130->dev, &dev_attr_hpload_ac_r);
}
gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
- pm_runtime_disable(&client->dev);
+ pm_runtime_disable(cs43130->dev);
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);
@@ -2630,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;
@@ -2666,10 +2727,10 @@ 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)
static const struct of_device_id cs43130_of_match[] = {
{.compatible = "cirrus,cs43130",},
{.compatible = "cirrus,cs4399",},
@@ -2679,12 +2740,23 @@ static const struct of_device_id cs43130_of_match[] = {
};
MODULE_DEVICE_TABLE(of, cs43130_of_match);
+#endif
+
+#if IS_ENABLED(CONFIG_ACPI)
+static const struct acpi_device_id cs43130_acpi_match[] = {
+ { "CSC4399", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, cs43130_acpi_match);
+#endif
+
static const struct i2c_device_id cs43130_i2c_id[] = {
- {"cs43130", 0},
- {"cs4399", 0},
- {"cs43131", 0},
- {"cs43198", 0},
+ {"cs43130"},
+ {"cs4399"},
+ {"cs43131"},
+ {"cs43198"},
{}
};
@@ -2692,9 +2764,10 @@ MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id);
static struct i2c_driver cs43130_i2c_driver = {
.driver = {
- .name = "cs43130",
- .of_match_table = cs43130_of_match,
- .pm = &cs43130_runtime_pm,
+ .name = "cs43130",
+ .of_match_table = of_match_ptr(cs43130_of_match),
+ .acpi_match_table = ACPI_PTR(cs43130_acpi_match),
+ .pm = pm_ptr(&cs43130_runtime_pm),
},
.id_table = cs43130_i2c_id,
.probe = cs43130_i2c_probe,
diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h
index 1dd893674313..dbdb5b262f1b 100644
--- a/sound/soc/codecs/cs43130.h
+++ b/sound/soc/codecs/cs43130.h
@@ -381,88 +381,88 @@ struct cs43130_clk_gen {
/* frm_size = 16 */
static const struct cs43130_clk_gen cs43130_16_clk_gen[] = {
- { 22579200, 32000, .v = { 441, 10, }, },
- { 22579200, 44100, .v = { 32, 1, }, },
- { 22579200, 48000, .v = { 147, 5, }, },
- { 22579200, 88200, .v = { 16, 1, }, },
- { 22579200, 96000, .v = { 147, 10, }, },
- { 22579200, 176400, .v = { 8, 1, }, },
- { 22579200, 192000, .v = { 147, 20, }, },
- { 22579200, 352800, .v = { 4, 1, }, },
- { 22579200, 384000, .v = { 147, 40, }, },
- { 24576000, 32000, .v = { 48, 1, }, },
- { 24576000, 44100, .v = { 5120, 147, }, },
- { 24576000, 48000, .v = { 32, 1, }, },
- { 24576000, 88200, .v = { 2560, 147, }, },
- { 24576000, 96000, .v = { 16, 1, }, },
- { 24576000, 176400, .v = { 1280, 147, }, },
- { 24576000, 192000, .v = { 8, 1, }, },
- { 24576000, 352800, .v = { 640, 147, }, },
- { 24576000, 384000, .v = { 4, 1, }, },
+ { 22579200, 32000, .v = { 10, 441, }, },
+ { 22579200, 44100, .v = { 1, 32, }, },
+ { 22579200, 48000, .v = { 5, 147, }, },
+ { 22579200, 88200, .v = { 1, 16, }, },
+ { 22579200, 96000, .v = { 10, 147, }, },
+ { 22579200, 176400, .v = { 1, 8, }, },
+ { 22579200, 192000, .v = { 20, 147, }, },
+ { 22579200, 352800, .v = { 1, 4, }, },
+ { 22579200, 384000, .v = { 40, 147, }, },
+ { 24576000, 32000, .v = { 1, 48, }, },
+ { 24576000, 44100, .v = { 147, 5120, }, },
+ { 24576000, 48000, .v = { 1, 32, }, },
+ { 24576000, 88200, .v = { 147, 2560, }, },
+ { 24576000, 96000, .v = { 1, 16, }, },
+ { 24576000, 176400, .v = { 147, 1280, }, },
+ { 24576000, 192000, .v = { 1, 8, }, },
+ { 24576000, 352800, .v = { 147, 640, }, },
+ { 24576000, 384000, .v = { 1, 4, }, },
};
/* frm_size = 32 */
static const struct cs43130_clk_gen cs43130_32_clk_gen[] = {
- { 22579200, 32000, .v = { 441, 20, }, },
- { 22579200, 44100, .v = { 16, 1, }, },
- { 22579200, 48000, .v = { 147, 10, }, },
- { 22579200, 88200, .v = { 8, 1, }, },
- { 22579200, 96000, .v = { 147, 20, }, },
- { 22579200, 176400, .v = { 4, 1, }, },
- { 22579200, 192000, .v = { 147, 40, }, },
- { 22579200, 352800, .v = { 2, 1, }, },
- { 22579200, 384000, .v = { 147, 80, }, },
- { 24576000, 32000, .v = { 24, 1, }, },
- { 24576000, 44100, .v = { 2560, 147, }, },
- { 24576000, 48000, .v = { 16, 1, }, },
- { 24576000, 88200, .v = { 1280, 147, }, },
- { 24576000, 96000, .v = { 8, 1, }, },
- { 24576000, 176400, .v = { 640, 147, }, },
- { 24576000, 192000, .v = { 4, 1, }, },
- { 24576000, 352800, .v = { 320, 147, }, },
- { 24576000, 384000, .v = { 2, 1, }, },
+ { 22579200, 32000, .v = { 20, 441, }, },
+ { 22579200, 44100, .v = { 1, 16, }, },
+ { 22579200, 48000, .v = { 10, 147, }, },
+ { 22579200, 88200, .v = { 1, 8, }, },
+ { 22579200, 96000, .v = { 20, 147, }, },
+ { 22579200, 176400, .v = { 1, 4, }, },
+ { 22579200, 192000, .v = { 40, 147, }, },
+ { 22579200, 352800, .v = { 1, 2, }, },
+ { 22579200, 384000, .v = { 80, 147, }, },
+ { 24576000, 32000, .v = { 1, 24, }, },
+ { 24576000, 44100, .v = { 147, 2560, }, },
+ { 24576000, 48000, .v = { 1, 16, }, },
+ { 24576000, 88200, .v = { 147, 1280, }, },
+ { 24576000, 96000, .v = { 1, 8, }, },
+ { 24576000, 176400, .v = { 147, 640, }, },
+ { 24576000, 192000, .v = { 1, 4, }, },
+ { 24576000, 352800, .v = { 147, 320, }, },
+ { 24576000, 384000, .v = { 1, 2, }, },
};
/* frm_size = 48 */
static const struct cs43130_clk_gen cs43130_48_clk_gen[] = {
- { 22579200, 32000, .v = { 147, 100, }, },
- { 22579200, 44100, .v = { 32, 3, }, },
- { 22579200, 48000, .v = { 49, 5, }, },
- { 22579200, 88200, .v = { 16, 3, }, },
- { 22579200, 96000, .v = { 49, 10, }, },
- { 22579200, 176400, .v = { 8, 3, }, },
- { 22579200, 192000, .v = { 49, 20, }, },
- { 22579200, 352800, .v = { 4, 3, }, },
- { 22579200, 384000, .v = { 49, 40, }, },
- { 24576000, 32000, .v = { 16, 1, }, },
- { 24576000, 44100, .v = { 5120, 441, }, },
- { 24576000, 48000, .v = { 32, 3, }, },
- { 24576000, 88200, .v = { 2560, 441, }, },
- { 24576000, 96000, .v = { 16, 3, }, },
- { 24576000, 176400, .v = { 1280, 441, }, },
- { 24576000, 192000, .v = { 8, 3, }, },
- { 24576000, 352800, .v = { 640, 441, }, },
- { 24576000, 384000, .v = { 4, 3, }, },
+ { 22579200, 32000, .v = { 100, 147, }, },
+ { 22579200, 44100, .v = { 3, 32, }, },
+ { 22579200, 48000, .v = { 5, 49, }, },
+ { 22579200, 88200, .v = { 3, 16, }, },
+ { 22579200, 96000, .v = { 10, 49, }, },
+ { 22579200, 176400, .v = { 3, 8, }, },
+ { 22579200, 192000, .v = { 20, 49, }, },
+ { 22579200, 352800, .v = { 3, 4, }, },
+ { 22579200, 384000, .v = { 40, 49, }, },
+ { 24576000, 32000, .v = { 1, 16, }, },
+ { 24576000, 44100, .v = { 441, 5120, }, },
+ { 24576000, 48000, .v = { 3, 32, }, },
+ { 24576000, 88200, .v = { 441, 2560, }, },
+ { 24576000, 96000, .v = { 3, 16, }, },
+ { 24576000, 176400, .v = { 441, 1280, }, },
+ { 24576000, 192000, .v = { 3, 8, }, },
+ { 24576000, 352800, .v = { 441, 640, }, },
+ { 24576000, 384000, .v = { 3, 4, }, },
};
/* frm_size = 64 */
static const struct cs43130_clk_gen cs43130_64_clk_gen[] = {
- { 22579200, 32000, .v = { 441, 40, }, },
- { 22579200, 44100, .v = { 8, 1, }, },
- { 22579200, 48000, .v = { 147, 20, }, },
- { 22579200, 88200, .v = { 4, 1, }, },
- { 22579200, 96000, .v = { 147, 40, }, },
- { 22579200, 176400, .v = { 2, 1, }, },
- { 22579200, 192000, .v = { 147, 80, }, },
+ { 22579200, 32000, .v = { 40, 441, }, },
+ { 22579200, 44100, .v = { 1, 8, }, },
+ { 22579200, 48000, .v = { 20, 147, }, },
+ { 22579200, 88200, .v = { 1, 4, }, },
+ { 22579200, 96000, .v = { 40, 147, }, },
+ { 22579200, 176400, .v = { 1, 2, }, },
+ { 22579200, 192000, .v = { 80, 147, }, },
{ 22579200, 352800, .v = { 1, 1, }, },
- { 24576000, 32000, .v = { 12, 1, }, },
- { 24576000, 44100, .v = { 1280, 147, }, },
- { 24576000, 48000, .v = { 8, 1, }, },
- { 24576000, 88200, .v = { 640, 147, }, },
- { 24576000, 96000, .v = { 4, 1, }, },
- { 24576000, 176400, .v = { 320, 147, }, },
- { 24576000, 192000, .v = { 2, 1, }, },
- { 24576000, 352800, .v = { 160, 147, }, },
+ { 24576000, 32000, .v = { 1, 12, }, },
+ { 24576000, 44100, .v = { 147, 1280, }, },
+ { 24576000, 48000, .v = { 1, 8, }, },
+ { 24576000, 88200, .v = { 147, 640, }, },
+ { 24576000, 96000, .v = { 1, 4, }, },
+ { 24576000, 176400, .v = { 147, 320, }, },
+ { 24576000, 192000, .v = { 1, 2, }, },
+ { 24576000, 352800, .v = { 147, 160, }, },
{ 24576000, 384000, .v = { 1, 1, }, },
};
@@ -497,15 +497,18 @@ struct cs43130_dai {
unsigned int sclk;
unsigned int dai_format;
unsigned int dai_mode;
+ unsigned int dai_invert;
};
struct cs43130_private {
+ struct device *dev;
struct snd_soc_component *component;
struct regmap *regmap;
struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES];
struct gpio_desc *reset_gpio;
unsigned int dev_id; /* codec device ID */
int xtal_ibias;
+ bool has_irq_line;
/* shared by both DAIs */
struct mutex clk_mutex;
diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c
index 2ceca5d0e5bf..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;
@@ -248,7 +248,7 @@ static int cs4341_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id cs4341_i2c_id[] = {
- { "cs4341", 0 },
+ { "cs4341" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs4341_i2c_id);
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 8365dd0ebe2a..d9a9c34fffe3 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -7,17 +7,16 @@
* Authors: Tim Howe <Tim.Howe@cirrus.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -271,7 +270,7 @@ static const struct regmap_config cs4349_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults),
.readable_reg = cs4349_readable_register,
.writeable_reg = cs4349_writeable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int cs4349_i2c_probe(struct i2c_client *client)
@@ -313,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);
@@ -347,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[] = {
@@ -362,7 +358,7 @@ static const struct of_device_id cs4349_of_match[] = {
MODULE_DEVICE_TABLE(of, cs4349_of_match);
static const struct i2c_device_id cs4349_i2c_id[] = {
- {"cs4349", 0},
+ {"cs4349"},
{}
};
@@ -372,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/cs47l15.c b/sound/soc/codecs/cs47l15.c
index a6538dab6639..da64e0a1db28 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -106,8 +106,7 @@ static int cs47l15_adsp_power_ev(struct snd_soc_dapm_widget *w,
static int cs47l15_in1_adc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = !!cs47l15->in1_lp_mode;
@@ -118,8 +117,7 @@ static int cs47l15_in1_adc_get(struct snd_kcontrol *kcontrol,
static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
if (!!ucontrol->value.integer.value[0] == cs47l15->in1_lp_mode)
@@ -1143,6 +1141,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l15_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l15_dai[] = {
{
.name = "cs47l15-aif1",
@@ -1219,7 +1221,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l15_dai_ops,
},
{
.name = "cs47l15-dsp-trace",
@@ -1242,12 +1244,12 @@ static int cs47l15_open(struct snd_soc_component *component,
struct madera *madera = priv->madera;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l15-dsp-trace") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l15-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(madera->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -1276,6 +1278,7 @@ static const struct snd_soc_dapm_route cs47l15_mono_routes[] = {
static int cs47l15_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l15->core.madera;
int ret;
@@ -1283,7 +1286,7 @@ static int cs47l15_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_get_dapm(component);
+ madera->dapm = snd_soc_component_to_dapm(component);
mutex_unlock(&madera->dapm_ptr_lock);
ret = madera_init_inputs(component);
@@ -1296,7 +1299,7 @@ static int cs47l15_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
ret = snd_soc_add_component_controls(component,
madera_adsp_rate_controls,
@@ -1489,7 +1492,7 @@ static struct platform_driver cs47l15_codec_driver = {
.name = "cs47l15-codec",
},
.probe = &cs47l15_probe,
- .remove_new = cs47l15_remove,
+ .remove = cs47l15_remove,
};
module_platform_driver(cs47l15_codec_driver);
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index a07b621d463e..5100b1aac902 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id,
#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static const struct snd_soc_dai_ops cs47l24_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l24_dai[] = {
{
.name = "cs47l24-aif1",
@@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l24_dai_ops,
},
{
.name = "cs47l24-dsp-voicectrl",
@@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l24_dai_ops,
},
{
.name = "cs47l24-dsp-trace",
@@ -1076,14 +1080,14 @@ static int cs47l24_open(struct snd_soc_component *component,
struct arizona *arizona = priv->core.arizona;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l24-dsp-voicectrl") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l24-dsp-voicectrl") == 0) {
n_adsp = 2;
- } else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l24-dsp-trace") == 0) {
+ } else if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l24-dsp-trace") == 0) {
n_adsp = 1;
} else {
dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -1120,7 +1124,7 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
static int cs47l24_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int ret;
@@ -1149,7 +1153,7 @@ static int cs47l24_component_probe(struct snd_soc_component *component)
if (ret)
goto err_adsp2_codec_probe;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
return 0;
@@ -1340,7 +1344,7 @@ static struct platform_driver cs47l24_codec_driver = {
.name = "cs47l24-codec",
},
.probe = cs47l24_probe,
- .remove_new = cs47l24_remove,
+ .remove = cs47l24_remove,
};
module_platform_driver(cs47l24_codec_driver);
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index c05c80c16c84..a8fe5a99a8bb 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l35_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l35_dai[] = {
{
.name = "cs47l35-aif1",
@@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l35_dai_ops,
},
{
.name = "cs47l35-dsp-voicectrl",
@@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l35_dai_ops,
},
{
.name = "cs47l35-dsp-trace",
@@ -1506,14 +1510,14 @@ static int cs47l35_open(struct snd_soc_component *component,
struct madera *madera = priv->madera;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l35-dsp-voicectrl") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l35-dsp-voicectrl") == 0) {
n_adsp = 2;
- } else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l35-dsp-trace") == 0) {
+ } else if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l35-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(madera->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -1555,6 +1559,7 @@ static const struct snd_soc_dapm_route cs47l35_mono_routes[] = {
static int cs47l35_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l35 *cs47l35 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l35->core.madera;
int i, ret;
@@ -1562,7 +1567,7 @@ static int cs47l35_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_get_dapm(component);
+ madera->dapm = snd_soc_component_to_dapm(component);
mutex_unlock(&madera->dapm_ptr_lock);
ret = madera_init_inputs(component);
@@ -1575,7 +1580,7 @@ static int cs47l35_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
ret = snd_soc_add_component_controls(component,
madera_adsp_rate_controls,
@@ -1765,7 +1770,7 @@ static struct platform_driver cs47l35_codec_driver = {
.name = "cs47l35-codec",
},
.probe = &cs47l35_probe,
- .remove_new = cs47l35_remove,
+ .remove = cs47l35_remove,
};
module_platform_driver(cs47l35_codec_driver);
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index dd7997a53e70..42fafb0b392c 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l85_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l85_dai[] = {
{
.name = "cs47l85-aif1",
@@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l85_dai_ops,
},
{
.name = "cs47l85-dsp-voicectrl",
@@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l85_dai_ops,
},
{
.name = "cs47l85-dsp-trace",
@@ -2448,14 +2452,14 @@ static int cs47l85_open(struct snd_soc_component *component,
struct madera *madera = priv->madera;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l85-dsp-voicectrl") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l85-dsp-voicectrl") == 0) {
n_adsp = 5;
- } else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l85-dsp-trace") == 0) {
+ } else if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l85-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(madera->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -2493,6 +2497,7 @@ static irqreturn_t cs47l85_adsp2_irq(int irq, void *data)
static int cs47l85_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l85 *cs47l85 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l85->core.madera;
int i, ret;
@@ -2500,7 +2505,7 @@ static int cs47l85_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_get_dapm(component);
+ madera->dapm = snd_soc_component_to_dapm(component);
mutex_unlock(&madera->dapm_ptr_lock);
ret = madera_init_inputs(component);
@@ -2512,7 +2517,7 @@ static int cs47l85_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
ret = snd_soc_add_component_controls(component,
madera_adsp_rate_controls,
@@ -2716,7 +2721,7 @@ static struct platform_driver cs47l85_codec_driver = {
.name = "cs47l85-codec",
},
.probe = &cs47l85_probe,
- .remove_new = cs47l85_remove,
+ .remove = cs47l85_remove,
};
module_platform_driver(cs47l85_codec_driver);
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index cdd5e7e20b5d..77e8aabb241a 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l90_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l90_dai[] = {
{
.name = "cs47l90-aif1",
@@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l90_dai_ops,
},
{
.name = "cs47l90-dsp-voicectrl",
@@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l90_dai_ops,
},
{
.name = "cs47l90-dsp-trace",
@@ -2367,14 +2371,14 @@ static int cs47l90_open(struct snd_soc_component *component,
struct madera *madera = priv->madera;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l90-dsp-voicectrl") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l90-dsp-voicectrl") == 0) {
n_adsp = 5;
- } else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l90-dsp-trace") == 0) {
+ } else if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l90-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(madera->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -2412,6 +2416,7 @@ static irqreturn_t cs47l90_adsp2_irq(int irq, void *data)
static int cs47l90_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l90 *cs47l90 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l90->core.madera;
int ret, i;
@@ -2419,7 +2424,7 @@ static int cs47l90_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_get_dapm(component);
+ madera->dapm = snd_soc_component_to_dapm(component);
mutex_unlock(&madera->dapm_ptr_lock);
ret = madera_init_inputs(component);
@@ -2431,7 +2436,7 @@ static int cs47l90_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
ret = snd_soc_add_component_controls(component,
madera_adsp_rate_controls,
@@ -2640,7 +2645,7 @@ static struct platform_driver cs47l90_codec_driver = {
.name = "cs47l90-codec",
},
.probe = &cs47l90_probe,
- .remove_new = cs47l90_remove,
+ .remove = cs47l90_remove,
};
module_platform_driver(cs47l90_codec_driver);
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index bc4d311d4778..868237bd6d91 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -52,10 +52,8 @@ static const char * const cs47l92_outdemux_texts[] = {
static int cs47l92_put_demux(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_component_get_dapm(component);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component);
struct madera_priv *priv = &cs47l92->core;
struct madera *madera = priv->madera;
@@ -1690,6 +1688,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l92_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l92_dai[] = {
{
.name = "cs47l92-aif1",
@@ -1823,7 +1825,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l92_dai_ops,
},
{
.name = "cs47l92-dsp-trace",
@@ -1846,12 +1848,12 @@ static int cs47l92_open(struct snd_soc_component *component,
struct madera *madera = priv->madera;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "cs47l92-dsp-trace") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs47l92-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(madera->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -1883,6 +1885,7 @@ static const struct snd_soc_dapm_route cs47l92_mono_routes[] = {
static int cs47l92_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l92->core.madera;
int ret;
@@ -1890,7 +1893,7 @@ static int cs47l92_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_get_dapm(component);
+ madera->dapm = snd_soc_component_to_dapm(component);
mutex_unlock(&madera->dapm_ptr_lock);
ret = madera_init_inputs(component);
@@ -1903,7 +1906,7 @@ static int cs47l92_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
ret = snd_soc_add_component_controls(component,
madera_adsp_rate_controls,
@@ -2088,7 +2091,7 @@ static struct platform_driver cs47l92_codec_driver = {
.name = "cs47l92-codec",
},
.probe = &cs47l92_probe,
- .remove_new = cs47l92_remove,
+ .remove = cs47l92_remove,
};
module_platform_driver(cs47l92_codec_driver);
diff --git a/sound/soc/codecs/cs48l32-tables.c b/sound/soc/codecs/cs48l32-tables.c
new file mode 100644
index 000000000000..8ff3652a010e
--- /dev/null
+++ b/sound/soc/codecs/cs48l32-tables.c
@@ -0,0 +1,538 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Regmap tables and other data for Cirrus Logic CS48L32 audio DSP.
+//
+// Copyright (C) 2018, 2020, 2022, 2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/array_size.h>
+#include <linux/build_bug.h>
+#include <linux/device.h>
+#include <linux/linear_range.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/cs48l32.h>
+#include <sound/cs48l32_registers.h>
+
+#include "cs48l32.h"
+
+static const struct reg_sequence cs48l32_reva_patch[] = {
+ { 0x00001044, 0x0005000f },
+ { 0x00001c34, 0x000037e8 },
+ { 0x000046d8, 0x00000fe0 },
+};
+
+int cs48l32_apply_patch(struct cs48l32 *cs48l32)
+{
+ int ret;
+
+ ret = regmap_register_patch(cs48l32->regmap, cs48l32_reva_patch,
+ ARRAY_SIZE(cs48l32_reva_patch));
+ if (ret < 0)
+ return dev_err_probe(cs48l32->dev, ret, "Failed to apply patch\n");
+
+ return 0;
+}
+
+static const struct reg_default cs48l32_reg_default[] = {
+ { 0x00000c08, 0xe1000001 }, /* GPIO1_CTRL1 */
+ { 0x00000c0c, 0xe1000001 }, /* GPIO2_CTRL1 */
+ { 0x00000c10, 0xe1000001 }, /* GPIO3_CTRL1 */
+ { 0x00000c14, 0xe1000001 }, /* GPIO4_CTRL1 */
+ { 0x00000c18, 0xe1000001 }, /* GPIO5_CTRL1 */
+ { 0x00000c1c, 0xe1000001 }, /* GPIO6_CTRL1 */
+ { 0x00000c20, 0xe1000001 }, /* GPIO7_CTRL1 */
+ { 0x00000c24, 0xe1000001 }, /* GPIO8_CTRL1 */
+ { 0x00000c28, 0xe1000001 }, /* GPIO9_CTRL1 */
+ { 0x00000c2c, 0xe1000001 }, /* GPIO10_CTRL1 */
+ { 0x00000c30, 0xe1000001 }, /* GPIO11_CTRL1 */
+ { 0x00000c34, 0xe1000001 }, /* GPIO12_CTRL1 */
+ { 0x00000c38, 0xe1000001 }, /* GPIO13_CTRL1 */
+ { 0x00000c3c, 0xe1000001 }, /* GPIO14_CTRL1 */
+ { 0x00000c40, 0xe1000001 }, /* GPIO15_CTRL1 */
+ { 0x00000c44, 0xe1000001 }, /* GPIO16_CTRL1 */
+ { 0x00001020, 0x00000000 }, /* OUTPUT_SYS_CLK */
+ { 0x00001044, 0x0005000f }, /* AUXPDM_CTRL */
+ { 0x0000105c, 0x00000000 }, /* AUXPDM_CTRL2 */
+ { 0x00001400, 0x00000002 }, /* CLOCK32K */
+ { 0x00001404, 0x00000404 }, /* SYSTEM_CLOCK1 */
+ { 0x00001420, 0x00000003 }, /* SAMPLE_RATE1 */
+ { 0x00001424, 0x00000003 }, /* SAMPLE_RATE2 */
+ { 0x00001428, 0x00000003 }, /* SAMPLE_RATE3 */
+ { 0x0000142c, 0x00000003 }, /* SAMPLE_RATE4 */
+ { 0x00001c00, 0x00000002 }, /* FLL1_CONTROL1 */
+ { 0x00001c04, 0x88203004 }, /* FLL1_CONTROL2 */
+ { 0x00001c08, 0x00000000 }, /* FLL1_CONTROL3 */
+ { 0x00001c0c, 0x21f05001 }, /* FLL1_CONTROL4 */
+ { 0x00001ca0, 0x00000c04 }, /* FLL1_GPIO_CLOCK */
+ { 0x00002000, 0x00000006 }, /* CHARGE_PUMP1 */
+ { 0x00002408, 0x000003e4 }, /* LDO2_CTRL1 */
+ { 0x00002410, 0x000000e6 }, /* MICBIAS_CTRL1 */
+ { 0x00002418, 0x00000222 }, /* MICBIAS_CTRL5 */
+ { 0x00002710, 0x00004600 }, /* IRQ1_CTRL_AOD */
+ { 0x00004000, 0x00000000 }, /* INPUT_CONTROL */
+ { 0x00004008, 0x00000400 }, /* INPUT_RATE_CONTROL */
+ { 0x0000400c, 0x00000000 }, /* INPUT_CONTROL2 */
+ { 0x00004020, 0x00050020 }, /* INPUT1_CONTROL1 */
+ { 0x00004024, 0x00000000 }, /* IN1L_CONTROL1 */
+ { 0x00004028, 0x10800080 }, /* IN1L_CONTROL2 */
+ { 0x00004044, 0x00000000 }, /* IN1R_CONTROL1 */
+ { 0x00004048, 0x10800080 }, /* IN1R_CONTROL2 */
+ { 0x00004060, 0x00050020 }, /* INPUT2_CONTROL1 */
+ { 0x00004064, 0x00000000 }, /* IN2L_CONTROL1 */
+ { 0x00004068, 0x10800000 }, /* IN2L_CONTROL2 */
+ { 0x00004084, 0x00000000 }, /* IN2R_CONTROL1 */
+ { 0x00004088, 0x10800000 }, /* IN2R_CONTROL2 */
+ { 0x00004244, 0x00000002 }, /* INPUT_HPF_CONTROL */
+ { 0x00004248, 0x00000022 }, /* INPUT_VOL_CONTROL */
+ { 0x00004300, 0x00000000 }, /* AUXPDM_CONTROL1 */
+ { 0x00004304, 0x00000000 }, /* AUXPDM_CONTROL2 */
+ { 0x00004308, 0x00010008 }, /* AUXPDM1_CONTROL1 */
+ { 0x00004310, 0x00010008 }, /* AUXPDM2_CONTROL1 */
+ { 0x00004688, 0x00000000 }, /* ADC1L_ANA_CONTROL1 */
+ { 0x0000468c, 0x00000000 }, /* ADC1R_ANA_CONTROL1 */
+ { 0x00006000, 0x00000000 }, /* ASP1_ENABLES1 */
+ { 0x00006004, 0x00000028 }, /* ASP1_CONTROL1 */
+ { 0x00006008, 0x18180200 }, /* ASP1_CONTROL2 */
+ { 0x0000600c, 0x00000002 }, /* ASP1_CONTROL3 */
+ { 0x00006010, 0x03020100 }, /* ASP1_FRAME_CONTROL1 */
+ { 0x00006014, 0x07060504 }, /* ASP1_FRAME_CONTROL2 */
+ { 0x00006020, 0x03020100 }, /* ASP1_FRAME_CONTROL5 */
+ { 0x00006024, 0x07060504 }, /* ASP1_FRAME_CONTROL6 */
+ { 0x00006030, 0x00000020 }, /* ASP1_DATA_CONTROL1 */
+ { 0x00006040, 0x00000020 }, /* ASP1_DATA_CONTROL5 */
+ { 0x00006080, 0x00000000 }, /* ASP2_ENABLES1 */
+ { 0x00006084, 0x00000028 }, /* ASP2_CONTROL1 */
+ { 0x00006088, 0x18180200 }, /* ASP2_CONTROL2 */
+ { 0x0000608c, 0x00000002 }, /* ASP2_CONTROL3 */
+ { 0x00006090, 0x03020100 }, /* ASP2_FRAME_CONTROL1 */
+ { 0x000060a0, 0x03020100 }, /* ASP2_FRAME_CONTROL5 */
+ { 0x000060b0, 0x00000020 }, /* ASP2_DATA_CONTROL1 */
+ { 0x000060c0, 0x00000020 }, /* ASP2_DATA_CONTROL5 */
+ { 0x00008200, 0x00800000 }, /* ASP1TX1_INPUT1 */
+ { 0x00008204, 0x00800000 }, /* ASP1TX1_INPUT2 */
+ { 0x00008208, 0x00800000 }, /* ASP1TX1_INPUT3 */
+ { 0x0000820c, 0x00800000 }, /* ASP1TX1_INPUT4 */
+ { 0x00008210, 0x00800000 }, /* ASP1TX2_INPUT1 */
+ { 0x00008214, 0x00800000 }, /* ASP1TX2_INPUT2 */
+ { 0x00008218, 0x00800000 }, /* ASP1TX2_INPUT3 */
+ { 0x0000821c, 0x00800000 }, /* ASP1TX2_INPUT4 */
+ { 0x00008220, 0x00800000 }, /* ASP1TX3_INPUT1 */
+ { 0x00008224, 0x00800000 }, /* ASP1TX3_INPUT2 */
+ { 0x00008228, 0x00800000 }, /* ASP1TX3_INPUT3 */
+ { 0x0000822c, 0x00800000 }, /* ASP1TX3_INPUT4 */
+ { 0x00008230, 0x00800000 }, /* ASP1TX4_INPUT1 */
+ { 0x00008234, 0x00800000 }, /* ASP1TX4_INPUT2 */
+ { 0x00008238, 0x00800000 }, /* ASP1TX4_INPUT3 */
+ { 0x0000823c, 0x00800000 }, /* ASP1TX4_INPUT4 */
+ { 0x00008240, 0x00800000 }, /* ASP1TX5_INPUT1 */
+ { 0x00008244, 0x00800000 }, /* ASP1TX5_INPUT2 */
+ { 0x00008248, 0x00800000 }, /* ASP1TX5_INPUT3 */
+ { 0x0000824c, 0x00800000 }, /* ASP1TX5_INPUT4 */
+ { 0x00008250, 0x00800000 }, /* ASP1TX6_INPUT1 */
+ { 0x00008254, 0x00800000 }, /* ASP1TX6_INPUT2 */
+ { 0x00008258, 0x00800000 }, /* ASP1TX6_INPUT3 */
+ { 0x0000825c, 0x00800000 }, /* ASP1TX6_INPUT4 */
+ { 0x00008260, 0x00800000 }, /* ASP1TX7_INPUT1 */
+ { 0x00008264, 0x00800000 }, /* ASP1TX7_INPUT2 */
+ { 0x00008268, 0x00800000 }, /* ASP1TX7_INPUT3 */
+ { 0x0000826c, 0x00800000 }, /* ASP1TX7_INPUT4 */
+ { 0x00008270, 0x00800000 }, /* ASP1TX8_INPUT1 */
+ { 0x00008274, 0x00800000 }, /* ASP1TX8_INPUT2 */
+ { 0x00008278, 0x00800000 }, /* ASP1TX8_INPUT3 */
+ { 0x0000827c, 0x00800000 }, /* ASP1TX8_INPUT4 */
+ { 0x00008300, 0x00800000 }, /* ASP2TX1_INPUT1 */
+ { 0x00008304, 0x00800000 }, /* ASP2TX1_INPUT2 */
+ { 0x00008308, 0x00800000 }, /* ASP2TX1_INPUT3 */
+ { 0x0000830c, 0x00800000 }, /* ASP2TX1_INPUT4 */
+ { 0x00008310, 0x00800000 }, /* ASP2TX2_INPUT1 */
+ { 0x00008314, 0x00800000 }, /* ASP2TX2_INPUT2 */
+ { 0x00008318, 0x00800000 }, /* ASP2TX2_INPUT3 */
+ { 0x0000831c, 0x00800000 }, /* ASP2TX2_INPUT4 */
+ { 0x00008320, 0x00800000 }, /* ASP2TX3_INPUT1 */
+ { 0x00008324, 0x00800000 }, /* ASP2TX3_INPUT2 */
+ { 0x00008328, 0x00800000 }, /* ASP2TX3_INPUT3 */
+ { 0x0000832c, 0x00800000 }, /* ASP2TX3_INPUT4 */
+ { 0x00008330, 0x00800000 }, /* ASP2TX4_INPUT1 */
+ { 0x00008334, 0x00800000 }, /* ASP2TX4_INPUT2 */
+ { 0x00008338, 0x00800000 }, /* ASP2TX4_INPUT3 */
+ { 0x0000833c, 0x00800000 }, /* ASP2TX4_INPUT4 */
+ { 0x00008980, 0x00000000 }, /* ISRC1INT1_INPUT1 */
+ { 0x00008990, 0x00000000 }, /* ISRC1INT2_INPUT1 */
+ { 0x000089a0, 0x00000000 }, /* ISRC1INT3_INPUT1 */
+ { 0x000089b0, 0x00000000 }, /* ISRC1INT4_INPUT1 */
+ { 0x000089c0, 0x00000000 }, /* ISRC1DEC1_INPUT1 */
+ { 0x000089d0, 0x00000000 }, /* ISRC1DEC2_INPUT1 */
+ { 0x000089e0, 0x00000000 }, /* ISRC1DEC3_INPUT1 */
+ { 0x000089f0, 0x00000000 }, /* ISRC1DEC4_INPUT1 */
+ { 0x00008a00, 0x00000000 }, /* ISRC2INT1_INPUT1 */
+ { 0x00008a10, 0x00000000 }, /* ISRC2INT2_INPUT1 */
+ { 0x00008a40, 0x00000000 }, /* ISRC2DEC1_INPUT1 */
+ { 0x00008a50, 0x00000000 }, /* ISRC2DEC2_INPUT1 */
+ { 0x00008a80, 0x00000000 }, /* ISRC3INT1_INPUT1 */
+ { 0x00008a90, 0x00000000 }, /* ISRC3INT2_INPUT1 */
+ { 0x00008ac0, 0x00000000 }, /* ISRC3DEC1_INPUT1 */
+ { 0x00008ad0, 0x00000000 }, /* ISRC3DEC2_INPUT1 */
+ { 0x00008b80, 0x00800000 }, /* EQ1_INPUT1 */
+ { 0x00008b84, 0x00800000 }, /* EQ1_INPUT2 */
+ { 0x00008b88, 0x00800000 }, /* EQ1_INPUT3 */
+ { 0x00008b8c, 0x00800000 }, /* EQ1_INPUT4 */
+ { 0x00008b90, 0x00800000 }, /* EQ2_INPUT1 */
+ { 0x00008b94, 0x00800000 }, /* EQ2_INPUT2 */
+ { 0x00008b98, 0x00800000 }, /* EQ2_INPUT3 */
+ { 0x00008b9c, 0x00800000 }, /* EQ2_INPUT4 */
+ { 0x00008ba0, 0x00800000 }, /* EQ3_INPUT1 */
+ { 0x00008ba4, 0x00800000 }, /* EQ3_INPUT2 */
+ { 0x00008ba8, 0x00800000 }, /* EQ3_INPUT3 */
+ { 0x00008bac, 0x00800000 }, /* EQ3_INPUT4 */
+ { 0x00008bb0, 0x00800000 }, /* EQ4_INPUT1 */
+ { 0x00008bb4, 0x00800000 }, /* EQ4_INPUT2 */
+ { 0x00008bb8, 0x00800000 }, /* EQ4_INPUT3 */
+ { 0x00008bbc, 0x00800000 }, /* EQ4_INPUT4 */
+ { 0x00008c00, 0x00800000 }, /* DRC1L_INPUT1 */
+ { 0x00008c04, 0x00800000 }, /* DRC1L_INPUT2 */
+ { 0x00008c08, 0x00800000 }, /* DRC1L_INPUT3 */
+ { 0x00008c0c, 0x00800000 }, /* DRC1L_INPUT4 */
+ { 0x00008c10, 0x00800000 }, /* DRC1R_INPUT1 */
+ { 0x00008c14, 0x00800000 }, /* DRC1R_INPUT2 */
+ { 0x00008c18, 0x00800000 }, /* DRC1R_INPUT3 */
+ { 0x00008c1c, 0x00800000 }, /* DRC1R_INPUT4 */
+ { 0x00008c20, 0x00800000 }, /* DRC2L_INPUT1 */
+ { 0x00008c24, 0x00800000 }, /* DRC2L_INPUT2 */
+ { 0x00008c28, 0x00800000 }, /* DRC2L_INPUT3 */
+ { 0x00008c2c, 0x00800000 }, /* DRC2L_INPUT4 */
+ { 0x00008c30, 0x00800000 }, /* DRC2R_INPUT1 */
+ { 0x00008c34, 0x00800000 }, /* DRC2R_INPUT2 */
+ { 0x00008c38, 0x00800000 }, /* DRC2R_INPUT3 */
+ { 0x00008c3c, 0x00800000 }, /* DRC2R_INPUT4 */
+ { 0x00008c80, 0x00800000 }, /* LHPF1_INPUT1 */
+ { 0x00008c84, 0x00800000 }, /* LHPF1_INPUT2 */
+ { 0x00008c88, 0x00800000 }, /* LHPF1_INPUT3 */
+ { 0x00008c8c, 0x00800000 }, /* LHPF1_INPUT4 */
+ { 0x00008c90, 0x00800000 }, /* LHPF2_INPUT1 */
+ { 0x00008c94, 0x00800000 }, /* LHPF2_INPUT2 */
+ { 0x00008c98, 0x00800000 }, /* LHPF2_INPUT3 */
+ { 0x00008c9c, 0x00800000 }, /* LHPF2_INPUT4 */
+ { 0x00008ca0, 0x00800000 }, /* LHPF3_INPUT1 */
+ { 0x00008ca4, 0x00800000 }, /* LHPF3_INPUT2 */
+ { 0x00008ca8, 0x00800000 }, /* LHPF3_INPUT3 */
+ { 0x00008cac, 0x00800000 }, /* LHPF3_INPUT4 */
+ { 0x00008cb0, 0x00800000 }, /* LHPF4_INPUT1 */
+ { 0x00008cb4, 0x00800000 }, /* LHPF4_INPUT2 */
+ { 0x00008cb8, 0x00800000 }, /* LHPF4_INPUT3 */
+ { 0x00008cbc, 0x00800000 }, /* LHPF4_INPUT4 */
+ { 0x00009000, 0x00800000 }, /* DSP1RX1_INPUT1 */
+ { 0x00009004, 0x00800000 }, /* DSP1RX1_INPUT2 */
+ { 0x00009008, 0x00800000 }, /* DSP1RX1_INPUT3 */
+ { 0x0000900c, 0x00800000 }, /* DSP1RX1_INPUT4 */
+ { 0x00009010, 0x00800000 }, /* DSP1RX2_INPUT1 */
+ { 0x00009014, 0x00800000 }, /* DSP1RX2_INPUT2 */
+ { 0x00009018, 0x00800000 }, /* DSP1RX2_INPUT3 */
+ { 0x0000901c, 0x00800000 }, /* DSP1RX2_INPUT4 */
+ { 0x00009020, 0x00800000 }, /* DSP1RX3_INPUT1 */
+ { 0x00009024, 0x00800000 }, /* DSP1RX3_INPUT2 */
+ { 0x00009028, 0x00800000 }, /* DSP1RX3_INPUT3 */
+ { 0x0000902c, 0x00800000 }, /* DSP1RX3_INPUT4 */
+ { 0x00009030, 0x00800000 }, /* DSP1RX4_INPUT1 */
+ { 0x00009034, 0x00800000 }, /* DSP1RX4_INPUT2 */
+ { 0x00009038, 0x00800000 }, /* DSP1RX4_INPUT3 */
+ { 0x0000903c, 0x00800000 }, /* DSP1RX4_INPUT4 */
+ { 0x00009040, 0x00800000 }, /* DSP1RX5_INPUT1 */
+ { 0x00009044, 0x00800000 }, /* DSP1RX5_INPUT2 */
+ { 0x00009048, 0x00800000 }, /* DSP1RX5_INPUT3 */
+ { 0x0000904c, 0x00800000 }, /* DSP1RX5_INPUT4 */
+ { 0x00009050, 0x00800000 }, /* DSP1RX6_INPUT1 */
+ { 0x00009054, 0x00800000 }, /* DSP1RX6_INPUT2 */
+ { 0x00009058, 0x00800000 }, /* DSP1RX6_INPUT3 */
+ { 0x0000905c, 0x00800000 }, /* DSP1RX6_INPUT4 */
+ { 0x00009060, 0x00800000 }, /* DSP1RX7_INPUT1 */
+ { 0x00009064, 0x00800000 }, /* DSP1RX7_INPUT2 */
+ { 0x00009068, 0x00800000 }, /* DSP1RX7_INPUT3 */
+ { 0x0000906c, 0x00800000 }, /* DSP1RX7_INPUT4 */
+ { 0x00009070, 0x00800000 }, /* DSP1RX8_INPUT1 */
+ { 0x00009074, 0x00800000 }, /* DSP1RX8_INPUT2 */
+ { 0x00009078, 0x00800000 }, /* DSP1RX8_INPUT3 */
+ { 0x0000907c, 0x00800000 }, /* DSP1RX8_INPUT4 */
+ { 0x0000a400, 0x00000000 }, /* ISRC1_CONTROL1 */
+ { 0x0000a404, 0x00000000 }, /* ISRC1_CONTROL2 */
+ { 0x0000a510, 0x00000000 }, /* ISRC2_CONTROL1 */
+ { 0x0000a514, 0x00000000 }, /* ISRC2_CONTROL2 */
+ { 0x0000a620, 0x00000000 }, /* ISRC3_CONTROL1 */
+ { 0x0000a624, 0x00000000 }, /* ISRC3_CONTROL2 */
+ { 0x0000a800, 0x00000000 }, /* FX_SAMPLE_RATE */
+ { 0x0000a808, 0x00000000 }, /* EQ_CONTROL1 */
+ { 0x0000a80c, 0x00000000 }, /* EQ_CONTROL2 */
+ { 0x0000a810, 0x0c0c0c0c }, /* EQ1_GAIN1 */
+ { 0x0000a814, 0x0000000c }, /* EQ1_GAIN2 */
+ { 0x0000a818, 0x03fe0fc8 }, /* EQ1_BAND1_COEFF1 */
+ { 0x0000a81c, 0x00000b75 }, /* EQ1_BAND1_COEFF2 */
+ { 0x0000a820, 0x000000e0 }, /* EQ1_BAND1_PG */
+ { 0x0000a824, 0xf1361ec4 }, /* EQ1_BAND2_COEFF1 */
+ { 0x0000a828, 0x00000409 }, /* EQ1_BAND2_COEFF2 */
+ { 0x0000a82c, 0x000004cc }, /* EQ1_BAND2_PG */
+ { 0x0000a830, 0xf3371c9b }, /* EQ1_BAND3_COEFF1 */
+ { 0x0000a834, 0x0000040b }, /* EQ1_BAND3_COEFF2 */
+ { 0x0000a838, 0x00000cbb }, /* EQ1_BAND3_PG */
+ { 0x0000a83c, 0xf7d916f8 }, /* EQ1_BAND4_COEFF1 */
+ { 0x0000a840, 0x0000040a }, /* EQ1_BAND4_COEFF2 */
+ { 0x0000a844, 0x00001f14 }, /* EQ1_BAND4_PG */
+ { 0x0000a848, 0x0563058c }, /* EQ1_BAND5_COEFF1 */
+ { 0x0000a84c, 0x00000000 }, /* EQ1_BAND5_COEFF1 + 4 */
+ { 0x0000a850, 0x00004000 }, /* EQ1_BAND5_PG */
+ { 0x0000a854, 0x0c0c0c0c }, /* EQ2_GAIN1 */
+ { 0x0000a858, 0x0000000c }, /* EQ2_GAIN2 */
+ { 0x0000a85c, 0x03fe0fc8 }, /* EQ2_BAND1_COEFF1 */
+ { 0x0000a860, 0x00000b75 }, /* EQ2_BAND1_COEFF2 */
+ { 0x0000a864, 0x000000e0 }, /* EQ2_BAND1_PG */
+ { 0x0000a868, 0xf1361ec4 }, /* EQ2_BAND2_COEFF1 */
+ { 0x0000a86c, 0x00000409 }, /* EQ2_BAND2_COEFF2 */
+ { 0x0000a870, 0x000004cc }, /* EQ2_BAND2_PG */
+ { 0x0000a874, 0xf3371c9b }, /* EQ2_BAND3_COEFF1 */
+ { 0x0000a878, 0x0000040b }, /* EQ2_BAND3_COEFF2 */
+ { 0x0000a87c, 0x00000cbb }, /* EQ2_BAND3_PG */
+ { 0x0000a880, 0xf7d916f8 }, /* EQ2_BAND4_COEFF1 */
+ { 0x0000a884, 0x0000040a }, /* EQ2_BAND4_COEFF2 */
+ { 0x0000a888, 0x00001f14 }, /* EQ2_BAND4_PG */
+ { 0x0000a88c, 0x0563058c }, /* EQ2_BAND5_COEFF1 */
+ { 0x0000a890, 0x00000000 }, /* EQ2_BAND5_COEFF1 + 4 */
+ { 0x0000a894, 0x00004000 }, /* EQ2_BAND5_PG */
+ { 0x0000a898, 0x0c0c0c0c }, /* EQ3_GAIN1 */
+ { 0x0000a89c, 0x0000000c }, /* EQ3_GAIN2 */
+ { 0x0000a8a0, 0x03fe0fc8 }, /* EQ3_BAND1_COEFF1 */
+ { 0x0000a8a4, 0x00000b75 }, /* EQ3_BAND1_COEFF2 */
+ { 0x0000a8a8, 0x000000e0 }, /* EQ3_BAND1_PG */
+ { 0x0000a8ac, 0xf1361ec4 }, /* EQ3_BAND2_COEFF1 */
+ { 0x0000a8b0, 0x00000409 }, /* EQ3_BAND2_COEFF2 */
+ { 0x0000a8b4, 0x000004cc }, /* EQ3_BAND2_PG */
+ { 0x0000a8b8, 0xf3371c9b }, /* EQ3_BAND3_COEFF1 */
+ { 0x0000a8bc, 0x0000040b }, /* EQ3_BAND3_COEFF2 */
+ { 0x0000a8c0, 0x00000cbb }, /* EQ3_BAND3_PG */
+ { 0x0000a8c4, 0xf7d916f8 }, /* EQ3_BAND4_COEFF1 */
+ { 0x0000a8c8, 0x0000040a }, /* EQ3_BAND4_COEFF2 */
+ { 0x0000a8cc, 0x00001f14 }, /* EQ3_BAND4_PG */
+ { 0x0000a8d0, 0x0563058c }, /* EQ3_BAND5_COEFF1 */
+ { 0x0000a8d4, 0x00000000 }, /* EQ3_BAND5_COEFF1 + 4 */
+ { 0x0000a8d8, 0x00004000 }, /* EQ3_BAND5_PG */
+ { 0x0000a8dc, 0x0c0c0c0c }, /* EQ4_GAIN1 */
+ { 0x0000a8e0, 0x0000000c }, /* EQ4_GAIN2 */
+ { 0x0000a8e4, 0x03fe0fc8 }, /* EQ4_BAND1_COEFF1 */
+ { 0x0000a8e8, 0x00000b75 }, /* EQ4_BAND1_COEFF2 */
+ { 0x0000a8ec, 0x000000e0 }, /* EQ4_BAND1_PG */
+ { 0x0000a8f0, 0xf1361ec4 }, /* EQ4_BAND2_COEFF1 */
+ { 0x0000a8f4, 0x00000409 }, /* EQ4_BAND2_COEFF2 */
+ { 0x0000a8f8, 0x000004cc }, /* EQ4_BAND2_PG */
+ { 0x0000a8fc, 0xf3371c9b }, /* EQ4_BAND3_COEFF1 */
+ { 0x0000a900, 0x0000040b }, /* EQ4_BAND3_COEFF2 */
+ { 0x0000a904, 0x00000cbb }, /* EQ4_BAND3_PG */
+ { 0x0000a908, 0xf7d916f8 }, /* EQ4_BAND4_COEFF1 */
+ { 0x0000a90c, 0x0000040a }, /* EQ4_BAND4_COEFF2 */
+ { 0x0000a910, 0x00001f14 }, /* EQ4_BAND4_PG */
+ { 0x0000a914, 0x0563058c }, /* EQ4_BAND5_COEFF1 */
+ { 0x0000a918, 0x00000000 }, /* EQ4_BAND5_COEFF1 + 4 */
+ { 0x0000a91c, 0x00004000 }, /* EQ4_BAND5_PG */
+ { 0x0000aa30, 0x00000000 }, /* LHPF_CONTROL1 */
+ { 0x0000aa34, 0x00000000 }, /* LHPF_CONTROL2 */
+ { 0x0000aa38, 0x00000000 }, /* LHPF1_COEFF */
+ { 0x0000aa3c, 0x00000000 }, /* LHPF2_COEFF */
+ { 0x0000aa40, 0x00000000 }, /* LHPF3_COEFF */
+ { 0x0000aa44, 0x00000000 }, /* LHPF4_COEFF */
+ { 0x0000ab00, 0x00000000 }, /* DRC1_CONTROL1 */
+ { 0x0000ab04, 0x49130018 }, /* DRC1_CONTROL2 */
+ { 0x0000ab08, 0x00000018 }, /* DRC1_CONTROL3 */
+ { 0x0000ab0c, 0x00000000 }, /* DRC1_CONTROL4 */
+ { 0x0000ab14, 0x00000000 }, /* DRC2_CONTROL1 */
+ { 0x0000ab18, 0x49130018 }, /* DRC2_CONTROL2 */
+ { 0x0000ab1c, 0x00000018 }, /* DRC2_CONTROL3 */
+ { 0x0000ab20, 0x00000000 }, /* DRC2_CONTROL4 */
+ { 0x0000b000, 0x00000000 }, /* TONE_GENERATOR1 */
+ { 0x0000b004, 0x00100000 }, /* TONE_GENERATOR2 */
+ { 0x0000b400, 0x00000000 }, /* COMFORT_NOISE_GENERATOR */
+ { 0x0000b800, 0x00000000 }, /* US_CONTROL */
+ { 0x0000b804, 0x00002020 }, /* US1_CONTROL */
+ { 0x0000b808, 0x00000000 }, /* US1_DET_CONTROL */
+ { 0x0000b814, 0x00002020 }, /* US2_CONTROL */
+ { 0x0000b818, 0x00000000 }, /* US2_DET_CONTROL */
+ { 0x00018110, 0x00000700 }, /* IRQ1_MASK_1 */
+ { 0x00018114, 0x00000004 }, /* IRQ1_MASK_2 */
+ { 0x00018120, 0x03ff0000 }, /* IRQ1_MASK_5 */
+ { 0x00018124, 0x00000103 }, /* IRQ1_MASK_6 */
+ { 0x00018128, 0x003f0000 }, /* IRQ1_MASK_7 */
+ { 0x00018130, 0xff00000f }, /* IRQ1_MASK_9 */
+ { 0x00018138, 0xffff0000 }, /* IRQ1_MASK_11 */
+};
+
+static bool cs48l32_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS48L32_DEVID:
+ case CS48L32_REVID:
+ case CS48L32_OTPID:
+ case CS48L32_SFT_RESET:
+ case CS48L32_CTRL_IF_DEBUG3:
+ case CS48L32_MCU_CTRL1:
+ case CS48L32_GPIO1_CTRL1 ... CS48L32_GPIO16_CTRL1:
+ case CS48L32_OUTPUT_SYS_CLK:
+ case CS48L32_AUXPDM_CTRL:
+ case CS48L32_AUXPDM_CTRL2:
+ case CS48L32_CLOCK32K:
+ case CS48L32_SYSTEM_CLOCK1 ... CS48L32_SYSTEM_CLOCK2:
+ case CS48L32_SAMPLE_RATE1 ... CS48L32_SAMPLE_RATE4:
+ case CS48L32_FLL1_CONTROL1 ... CS48L32_FLL1_GPIO_CLOCK:
+ case CS48L32_CHARGE_PUMP1:
+ case CS48L32_LDO2_CTRL1:
+ case CS48L32_MICBIAS_CTRL1:
+ case CS48L32_MICBIAS_CTRL5:
+ case CS48L32_IRQ1_CTRL_AOD:
+ case CS48L32_INPUT_CONTROL:
+ case CS48L32_INPUT_STATUS:
+ case CS48L32_INPUT_RATE_CONTROL:
+ case CS48L32_INPUT_CONTROL2:
+ case CS48L32_INPUT_CONTROL3:
+ case CS48L32_INPUT1_CONTROL1:
+ case CS48L32_IN1L_CONTROL1 ... CS48L32_IN1L_CONTROL2:
+ case CS48L32_IN1R_CONTROL1 ... CS48L32_IN1R_CONTROL2:
+ case CS48L32_INPUT2_CONTROL1:
+ case CS48L32_IN2L_CONTROL1 ... CS48L32_IN2L_CONTROL2:
+ case CS48L32_IN2R_CONTROL1 ... CS48L32_IN2R_CONTROL2:
+ case CS48L32_INPUT_HPF_CONTROL:
+ case CS48L32_INPUT_VOL_CONTROL:
+ case CS48L32_AUXPDM_CONTROL1:
+ case CS48L32_AUXPDM_CONTROL2:
+ case CS48L32_AUXPDM1_CONTROL1:
+ case CS48L32_AUXPDM2_CONTROL1:
+ case CS48L32_ADC1L_ANA_CONTROL1:
+ case CS48L32_ADC1R_ANA_CONTROL1:
+ case CS48L32_ASP1_ENABLES1 ... CS48L32_ASP1_DATA_CONTROL5:
+ case CS48L32_ASP2_ENABLES1 ... CS48L32_ASP2_DATA_CONTROL5:
+ case CS48L32_ASP1TX1_INPUT1 ... CS48L32_ASP1TX8_INPUT4:
+ case CS48L32_ASP2TX1_INPUT1 ... CS48L32_ASP2TX4_INPUT4:
+ case CS48L32_ISRC1INT1_INPUT1 ... CS48L32_ISRC1DEC4_INPUT1:
+ case CS48L32_ISRC2INT1_INPUT1 ... CS48L32_ISRC2DEC2_INPUT1:
+ case CS48L32_ISRC3INT1_INPUT1 ... CS48L32_ISRC3DEC2_INPUT1:
+ case CS48L32_EQ1_INPUT1 ... CS48L32_EQ4_INPUT4:
+ case CS48L32_DRC1L_INPUT1 ... CS48L32_DRC1R_INPUT4:
+ case CS48L32_DRC2L_INPUT1 ... CS48L32_DRC2R_INPUT4:
+ case CS48L32_LHPF1_INPUT1 ... CS48L32_LHPF1_INPUT4:
+ case CS48L32_LHPF2_INPUT1 ... CS48L32_LHPF2_INPUT4:
+ case CS48L32_LHPF3_INPUT1 ... CS48L32_LHPF3_INPUT4:
+ case CS48L32_LHPF4_INPUT1 ... CS48L32_LHPF4_INPUT4:
+ case CS48L32_DSP1RX1_INPUT1 ... CS48L32_DSP1RX8_INPUT4:
+ case CS48L32_ISRC1_CONTROL1 ... CS48L32_ISRC1_CONTROL2:
+ case CS48L32_ISRC2_CONTROL1 ... CS48L32_ISRC2_CONTROL2:
+ case CS48L32_ISRC3_CONTROL1 ... CS48L32_ISRC3_CONTROL2:
+ case CS48L32_FX_SAMPLE_RATE:
+ case CS48L32_EQ_CONTROL1 ... CS48L32_EQ_CONTROL2:
+ case CS48L32_EQ1_GAIN1 ... CS48L32_EQ1_BAND5_PG:
+ case CS48L32_EQ2_GAIN1 ... CS48L32_EQ2_BAND5_PG:
+ case CS48L32_EQ3_GAIN1 ... CS48L32_EQ3_BAND5_PG:
+ case CS48L32_EQ4_GAIN1 ... CS48L32_EQ4_BAND5_PG:
+ case CS48L32_LHPF_CONTROL1 ... CS48L32_LHPF_CONTROL2:
+ case CS48L32_LHPF1_COEFF ... CS48L32_LHPF4_COEFF:
+ case CS48L32_DRC1_CONTROL1 ... CS48L32_DRC1_CONTROL4:
+ case CS48L32_DRC2_CONTROL1 ... CS48L32_DRC2_CONTROL4:
+ case CS48L32_TONE_GENERATOR1 ... CS48L32_TONE_GENERATOR2:
+ case CS48L32_COMFORT_NOISE_GENERATOR:
+ case CS48L32_US_CONTROL:
+ case CS48L32_US1_CONTROL:
+ case CS48L32_US1_DET_CONTROL:
+ case CS48L32_US2_CONTROL:
+ case CS48L32_US2_DET_CONTROL:
+ case CS48L32_DSP1_XM_SRAM_IBUS_SETUP_0 ... CS48L32_DSP1_XM_SRAM_IBUS_SETUP_24:
+ case CS48L32_DSP1_YM_SRAM_IBUS_SETUP_0 ... CS48L32_DSP1_YM_SRAM_IBUS_SETUP_8:
+ case CS48L32_DSP1_PM_SRAM_IBUS_SETUP_0 ... CS48L32_DSP1_PM_SRAM_IBUS_SETUP_7:
+ case CS48L32_IRQ1_STATUS:
+ case CS48L32_IRQ1_EINT_1 ... CS48L32_IRQ1_EINT_11:
+ case CS48L32_IRQ1_STS_1 ... CS48L32_IRQ1_STS_11:
+ case CS48L32_IRQ1_MASK_1 ... CS48L32_IRQ1_MASK_11:
+ case CS48L32_DSP1_XMEM_PACKED_0 ... CS48L32_DSP1_XMEM_PACKED_LAST:
+ case CS48L32_DSP1_SYS_INFO_ID ... CS48L32_DSP1_AHBM_WINDOW_DEBUG_1:
+ case CS48L32_DSP1_XMEM_UNPACKED24_0 ... CS48L32_DSP1_XMEM_UNPACKED24_LAST:
+ case CS48L32_DSP1_CLOCK_FREQ ... CS48L32_DSP1_SAMPLE_RATE_TX8:
+ case CS48L32_DSP1_SCRATCH1 ... CS48L32_DSP1_SCRATCH4:
+ case CS48L32_DSP1_CCM_CORE_CONTROL ... CS48L32_DSP1_STREAM_ARB_RESYNC_MSK1:
+ case CS48L32_DSP1_YMEM_PACKED_0 ... CS48L32_DSP1_YMEM_PACKED_LAST:
+ case CS48L32_DSP1_YMEM_UNPACKED24_0 ... CS48L32_DSP1_YMEM_UNPACKED24_LAST:
+ case CS48L32_DSP1_PMEM_0 ... CS48L32_DSP1_PMEM_LAST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs48l32_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS48L32_DEVID:
+ case CS48L32_REVID:
+ case CS48L32_OTPID:
+ case CS48L32_SFT_RESET:
+ case CS48L32_CTRL_IF_DEBUG3:
+ case CS48L32_MCU_CTRL1:
+ case CS48L32_SYSTEM_CLOCK2:
+ case CS48L32_FLL1_CONTROL5:
+ case CS48L32_FLL1_CONTROL6:
+ case CS48L32_INPUT_STATUS:
+ case CS48L32_INPUT_CONTROL3:
+ case CS48L32_DSP1_XM_SRAM_IBUS_SETUP_0 ... CS48L32_DSP1_XM_SRAM_IBUS_SETUP_24:
+ case CS48L32_DSP1_YM_SRAM_IBUS_SETUP_0 ... CS48L32_DSP1_YM_SRAM_IBUS_SETUP_8:
+ case CS48L32_DSP1_PM_SRAM_IBUS_SETUP_0 ... CS48L32_DSP1_PM_SRAM_IBUS_SETUP_7:
+ case CS48L32_IRQ1_STATUS:
+ case CS48L32_IRQ1_EINT_1 ... CS48L32_IRQ1_EINT_11:
+ case CS48L32_IRQ1_STS_1 ... CS48L32_IRQ1_STS_11:
+ case CS48L32_DSP1_XMEM_PACKED_0 ... CS48L32_DSP1_XMEM_PACKED_LAST:
+ case CS48L32_DSP1_SYS_INFO_ID ... CS48L32_DSP1_AHBM_WINDOW_DEBUG_1:
+ case CS48L32_DSP1_XMEM_UNPACKED24_0 ... CS48L32_DSP1_XMEM_UNPACKED24_LAST:
+ case CS48L32_DSP1_CLOCK_FREQ ... CS48L32_DSP1_SAMPLE_RATE_TX8:
+ case CS48L32_DSP1_SCRATCH1 ... CS48L32_DSP1_SCRATCH4:
+ case CS48L32_DSP1_CCM_CORE_CONTROL ... CS48L32_DSP1_STREAM_ARB_RESYNC_MSK1:
+ case CS48L32_DSP1_YMEM_PACKED_0 ... CS48L32_DSP1_YMEM_PACKED_LAST:
+ case CS48L32_DSP1_YMEM_UNPACKED24_0 ... CS48L32_DSP1_YMEM_UNPACKED24_LAST:
+ case CS48L32_DSP1_PMEM_0 ... CS48L32_DSP1_PMEM_LAST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * The bus bridge requires DSP packed memory registers to be accessed in
+ * aligned block multiples.
+ * Mark precious to prevent regmap debugfs causing an illegal bus transaction.
+ */
+static bool cs48l32_precious_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS48L32_DSP1_XMEM_PACKED_0 ... CS48L32_DSP1_XMEM_PACKED_LAST:
+ case CS48L32_DSP1_YMEM_PACKED_0 ... CS48L32_DSP1_YMEM_PACKED_LAST:
+ case CS48L32_DSP1_PMEM_0 ... CS48L32_DSP1_PMEM_LAST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config cs48l32_regmap = {
+ .name = "cs48l32",
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .pad_bits = 32,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = CS48L32_DSP1_PMEM_LAST,
+ .readable_reg = &cs48l32_readable_register,
+ .volatile_reg = &cs48l32_volatile_register,
+ .precious_reg = &cs48l32_precious_register,
+
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = cs48l32_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs48l32_reg_default),
+};
+
+int cs48l32_create_regmap(struct spi_device *spi, struct cs48l32 *cs48l32)
+{
+ cs48l32->regmap = devm_regmap_init_spi(spi, &cs48l32_regmap);
+
+ return PTR_ERR_OR_ZERO(cs48l32->regmap);
+}
diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c
new file mode 100644
index 000000000000..086ed0f57a85
--- /dev/null
+++ b/sound/soc/codecs/cs48l32.c
@@ -0,0 +1,4076 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Cirrus Logic CS48L32 audio DSP.
+//
+// Copyright (C) 2016-2018, 2020, 2022, 2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <dt-bindings/sound/cs48l32.h>
+#include <linux/array_size.h>
+#include <linux/build_bug.h>
+#include <linux/clk.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gcd.h>
+#include <linux/gpio/consumer.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/string_choices.h>
+#include <sound/cs48l32.h>
+#include <sound/cs48l32_registers.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "cs48l32.h"
+
+static const char * const cs48l32_core_supplies[] = { "vdd-a", "vdd-io" };
+
+static const struct cs_dsp_region cs48l32_dsp1_regions[] = {
+ { .type = WMFW_HALO_PM_PACKED, .base = 0x3800000 },
+ { .type = WMFW_HALO_XM_PACKED, .base = 0x2000000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x2800000 },
+ { .type = WMFW_HALO_YM_PACKED, .base = 0x2C00000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x3400000 },
+};
+
+static const struct cs48l32_dsp_power_reg_block cs48l32_dsp1_sram_ext_regs[] = {
+ { CS48L32_DSP1_XM_SRAM_IBUS_SETUP_1, CS48L32_DSP1_XM_SRAM_IBUS_SETUP_24 },
+ { CS48L32_DSP1_YM_SRAM_IBUS_SETUP_1, CS48L32_DSP1_YM_SRAM_IBUS_SETUP_8 },
+ { CS48L32_DSP1_PM_SRAM_IBUS_SETUP_1, CS48L32_DSP1_PM_SRAM_IBUS_SETUP_7 },
+};
+
+static const unsigned int cs48l32_dsp1_sram_pwd_regs[] = {
+ CS48L32_DSP1_XM_SRAM_IBUS_SETUP_0,
+ CS48L32_DSP1_YM_SRAM_IBUS_SETUP_0,
+ CS48L32_DSP1_PM_SRAM_IBUS_SETUP_0,
+};
+
+static const struct cs48l32_dsp_power_regs cs48l32_dsp_sram_regs = {
+ .ext = cs48l32_dsp1_sram_ext_regs,
+ .n_ext = ARRAY_SIZE(cs48l32_dsp1_sram_ext_regs),
+ .pwd = cs48l32_dsp1_sram_pwd_regs,
+ .n_pwd = ARRAY_SIZE(cs48l32_dsp1_sram_pwd_regs),
+};
+
+static const char * const cs48l32_mixer_texts[] = {
+ "None",
+ "Tone Generator 1",
+ "Tone Generator 2",
+ "Noise Generator",
+ "IN1L",
+ "IN1R",
+ "IN2L",
+ "IN2R",
+ "ASP1RX1",
+ "ASP1RX2",
+ "ASP1RX3",
+ "ASP1RX4",
+ "ASP1RX5",
+ "ASP1RX6",
+ "ASP1RX7",
+ "ASP1RX8",
+ "ASP2RX1",
+ "ASP2RX2",
+ "ASP2RX3",
+ "ASP2RX4",
+ "ISRC1INT1",
+ "ISRC1INT2",
+ "ISRC1INT3",
+ "ISRC1INT4",
+ "ISRC1DEC1",
+ "ISRC1DEC2",
+ "ISRC1DEC3",
+ "ISRC1DEC4",
+ "ISRC2INT1",
+ "ISRC2INT2",
+ "ISRC2DEC1",
+ "ISRC2DEC2",
+ "ISRC3INT1",
+ "ISRC3INT2",
+ "ISRC3DEC1",
+ "ISRC3DEC2",
+ "EQ1",
+ "EQ2",
+ "EQ3",
+ "EQ4",
+ "DRC1L",
+ "DRC1R",
+ "DRC2L",
+ "DRC2R",
+ "LHPF1",
+ "LHPF2",
+ "LHPF3",
+ "LHPF4",
+ "Ultrasonic 1",
+ "Ultrasonic 2",
+ "DSP1.1",
+ "DSP1.2",
+ "DSP1.3",
+ "DSP1.4",
+ "DSP1.5",
+ "DSP1.6",
+ "DSP1.7",
+ "DSP1.8",
+};
+
+static unsigned int cs48l32_mixer_values[] = {
+ 0x000, /* Silence (mute) */
+ 0x004, /* Tone generator 1 */
+ 0x005, /* Tone generator 2 */
+ 0x00C, /* Noise Generator */
+ 0x010, /* IN1L signal path */
+ 0x011, /* IN1R signal path */
+ 0x012, /* IN2L signal path */
+ 0x013, /* IN2R signal path */
+ 0x020, /* ASP1 RX1 */
+ 0x021, /* ASP1 RX2 */
+ 0x022, /* ASP1 RX3 */
+ 0x023, /* ASP1 RX4 */
+ 0x024, /* ASP1 RX5 */
+ 0x025, /* ASP1 RX6 */
+ 0x026, /* ASP1 RX7 */
+ 0x027, /* ASP1 RX8 */
+ 0x030, /* ASP2 RX1 */
+ 0x031, /* ASP2 RX2 */
+ 0x032, /* ASP2 RX3 */
+ 0x033, /* ASP2 RX4 */
+ 0x098, /* ISRC1 INT1 */
+ 0x099, /* ISRC1 INT2 */
+ 0x09a, /* ISRC1 INT3 */
+ 0x09b, /* ISRC1 INT4 */
+ 0x09C, /* ISRC1 DEC1 */
+ 0x09D, /* ISRC1 DEC2 */
+ 0x09e, /* ISRC1 DEC3 */
+ 0x09f, /* ISRC1 DEC4 */
+ 0x0A0, /* ISRC2 INT1 */
+ 0x0A1, /* ISRC2 INT2 */
+ 0x0A4, /* ISRC2 DEC1 */
+ 0x0A5, /* ISRC2 DEC2 */
+ 0x0A8, /* ISRC3 INT1 */
+ 0x0A9, /* ISRC3 INT2 */
+ 0x0AC, /* ISRC3 DEC1 */
+ 0x0AD, /* ISRC3 DEC2 */
+ 0x0B8, /* EQ1 */
+ 0x0B9, /* EQ2 */
+ 0x0BA, /* EQ3 */
+ 0x0BB, /* EQ4 */
+ 0x0C0, /* DRC1 Left */
+ 0x0C1, /* DRC1 Right */
+ 0x0C2, /* DRC2 Left */
+ 0x0C3, /* DRC2 Right */
+ 0x0C8, /* LHPF1 */
+ 0x0C9, /* LHPF2 */
+ 0x0CA, /* LHPF3 */
+ 0x0CB, /* LHPF4 */
+ 0x0D8, /* Ultrasonic 1 */
+ 0x0D9, /* Ultrasonic 2 */
+ 0x100, /* DSP1 channel 1 */
+ 0x101, /* DSP1 channel 2 */
+ 0x102, /* DSP1 channel 3 */
+ 0x103, /* DSP1 channel 4 */
+ 0x104, /* DSP1 channel 5 */
+ 0x105, /* DSP1 channel 6 */
+ 0x106, /* DSP1 channel 7 */
+ 0x107, /* DSP1 channel 8 */
+};
+static_assert(ARRAY_SIZE(cs48l32_mixer_texts) == ARRAY_SIZE(cs48l32_mixer_values));
+#define CS48L32_NUM_MIXER_INPUTS ARRAY_SIZE(cs48l32_mixer_values)
+
+static const DECLARE_TLV_DB_SCALE(cs48l32_ana_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(cs48l32_eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(cs48l32_digital_tlv, -6400, 50, 0);
+static const DECLARE_TLV_DB_SCALE(cs48l32_noise_tlv, -10800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(cs48l32_mixer_tlv, -3200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(cs48l32_us_tlv, 0, 600, 0);
+
+static void cs48l32_spin_sysclk(struct cs48l32_codec *cs48l32_codec)
+{
+ struct cs48l32 *cs48l32 = &cs48l32_codec->core;
+ unsigned int val;
+ int ret, i;
+
+ /* Skip this if the chip is down */
+ if (pm_runtime_suspended(cs48l32->dev))
+ return;
+
+ /*
+ * Just read a register a few times to ensure the internal
+ * oscillator sends out some clocks.
+ */
+ for (i = 0; i < 4; i++) {
+ ret = regmap_read(cs48l32->regmap, CS48L32_DEVID, &val);
+ if (ret)
+ dev_err(cs48l32_codec->core.dev, "%s Failed to read register: %d (%d)\n",
+ __func__, ret, i);
+ }
+
+ udelay(300);
+}
+
+static const char * const cs48l32_rate_text[] = {
+ "Sample Rate 1", "Sample Rate 2", "Sample Rate 3", "Sample Rate 4",
+};
+
+static const unsigned int cs48l32_rate_val[] = {
+ 0x0, 0x1, 0x2, 0x3,
+};
+static_assert(ARRAY_SIZE(cs48l32_rate_val) == ARRAY_SIZE(cs48l32_rate_text));
+
+static int cs48l32_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ /* Prevent any mixer mux changes while we do this */
+ mutex_lock(&cs48l32_codec->rate_lock);
+
+ /* The write must be guarded by a number of SYSCLK cycles */
+ cs48l32_spin_sysclk(cs48l32_codec);
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+ cs48l32_spin_sysclk(cs48l32_codec);
+
+ mutex_unlock(&cs48l32_codec->rate_lock);
+
+ return ret;
+}
+
+static const char * const cs48l32_sample_rate_text[] = {
+ "12kHz",
+ "24kHz",
+ "48kHz",
+ "96kHz",
+ "192kHz",
+ "384kHz",
+ "768kHz",
+ "11.025kHz",
+ "22.05kHz",
+ "44.1kHz",
+ "88.2kHz",
+ "176.4kHz",
+ "352.8kHz",
+ "705.6kHz",
+ "8kHz",
+ "16kHz",
+ "32kHz",
+};
+
+static const unsigned int cs48l32_sample_rate_val[] = {
+ 0x01, /* 12kHz */
+ 0x02, /* 24kHz */
+ 0x03, /* 48kHz */
+ 0x04, /* 96kHz */
+ 0x05, /* 192kHz */
+ 0x06, /* 384kHz */
+ 0x07, /* 768kHz */
+ 0x09, /* 11.025kHz */
+ 0x0a, /* 22.05kHz */
+ 0x0b, /* 44.1kHz */
+ 0x0c, /* 88.2kHz */
+ 0x0d, /* 176.4kHz */
+ 0x0e, /* 352.8kHz */
+ 0x0f, /* 705.6kHz */
+ 0x11, /* 8kHz */
+ 0x12, /* 16kHz */
+ 0x13, /* 32kHz */
+};
+static_assert(ARRAY_SIZE(cs48l32_sample_rate_val) == ARRAY_SIZE(cs48l32_sample_rate_text));
+#define CS48L32_SAMPLE_RATE_ENUM_SIZE ARRAY_SIZE(cs48l32_sample_rate_val)
+
+static const struct soc_enum cs48l32_sample_rate[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_SAMPLE_RATE1,
+ CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_1_MASK >> CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_ENUM_SIZE,
+ cs48l32_sample_rate_text,
+ cs48l32_sample_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_SAMPLE_RATE2,
+ CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_1_MASK >> CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_ENUM_SIZE,
+ cs48l32_sample_rate_text,
+ cs48l32_sample_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_SAMPLE_RATE3,
+ CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_1_MASK >> CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_ENUM_SIZE,
+ cs48l32_sample_rate_text,
+ cs48l32_sample_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_SAMPLE_RATE4,
+ CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_1_MASK >> CS48L32_SAMPLE_RATE_1_SHIFT,
+ CS48L32_SAMPLE_RATE_ENUM_SIZE,
+ cs48l32_sample_rate_text,
+ cs48l32_sample_rate_val),
+};
+
+static int cs48l32_inmux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *) kcontrol->private_value;
+ unsigned int mux, src_val, in_type;
+ int ret;
+
+ mux = ucontrol->value.enumerated.item[0];
+ if (mux > 1)
+ return -EINVAL;
+
+ switch (e->reg) {
+ case CS48L32_IN1L_CONTROL1:
+ in_type = cs48l32_codec->in_type[0][mux];
+ break;
+ case CS48L32_IN1R_CONTROL1:
+ in_type = cs48l32_codec->in_type[1][mux];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ src_val = mux << e->shift_l;
+
+ if (in_type == CS48L32_IN_TYPE_SE)
+ src_val |= 1 << CS48L32_INx_SRC_SHIFT;
+
+ ret = snd_soc_component_update_bits(component,
+ e->reg,
+ CS48L32_INx_SRC_MASK,
+ src_val);
+ if (ret > 0)
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+
+ return ret;
+}
+
+static const char * const cs48l32_inmux_texts[] = {
+ "Analog 1", "Analog 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_in1muxl_enum,
+ CS48L32_IN1L_CONTROL1,
+ CS48L32_INx_SRC_SHIFT + 1,
+ cs48l32_inmux_texts);
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_in1muxr_enum,
+ CS48L32_IN1R_CONTROL1,
+ CS48L32_INx_SRC_SHIFT + 1,
+ cs48l32_inmux_texts);
+
+static const struct snd_kcontrol_new cs48l32_inmux[] = {
+ SOC_DAPM_ENUM_EXT("IN1L Mux", cs48l32_in1muxl_enum,
+ snd_soc_dapm_get_enum_double, cs48l32_inmux_put),
+ SOC_DAPM_ENUM_EXT("IN1R Mux", cs48l32_in1muxr_enum,
+ snd_soc_dapm_get_enum_double, cs48l32_inmux_put),
+};
+
+static const char * const cs48l32_dmode_texts[] = {
+ "Analog", "Digital",
+};
+
+static int cs48l32_dmode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct soc_enum *e = (struct soc_enum *) kcontrol->private_value;
+ unsigned int mode;
+ int ret, result;
+
+ mode = ucontrol->value.enumerated.item[0];
+ switch (mode) {
+ case 0:
+ ret = snd_soc_component_update_bits(component,
+ CS48L32_ADC1L_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "Failed to set ADC1L_INT_ENA_FRC: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_update_bits(component,
+ CS48L32_ADC1R_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "Failed to set ADC1R_INT_ENA_FRC: %d\n", ret);
+ return ret;
+ }
+
+ result = snd_soc_component_update_bits(component,
+ e->reg,
+ BIT(CS48L32_IN1_MODE_SHIFT),
+ 0);
+ if (result < 0) {
+ dev_err(component->dev, "Failed to set input mode: %d\n", result);
+ return result;
+ }
+
+ usleep_range(200, 300);
+
+ ret = snd_soc_component_update_bits(component,
+ CS48L32_ADC1L_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ 0);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "Failed to clear ADC1L_INT_ENA_FRC: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_update_bits(component,
+ CS48L32_ADC1R_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ 0);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "Failed to clear ADC1R_INT_ENA_FRC: %d\n", ret);
+ return ret;
+ }
+
+ if (result > 0)
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mode, e, NULL);
+
+ return result;
+ case 1:
+ return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+ default:
+ return -EINVAL;
+ }
+}
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_in1dmode_enum,
+ CS48L32_INPUT1_CONTROL1,
+ CS48L32_IN1_MODE_SHIFT,
+ cs48l32_dmode_texts);
+
+static const struct snd_kcontrol_new cs48l32_dmode_mux[] = {
+ SOC_DAPM_ENUM_EXT("IN1 Mode", cs48l32_in1dmode_enum,
+ snd_soc_dapm_get_enum_double, cs48l32_dmode_put),
+};
+
+static const char * const cs48l32_in_texts[] = {
+ "IN1L", "IN1R", "IN2L", "IN2R",
+};
+static_assert(ARRAY_SIZE(cs48l32_in_texts) == CS48L32_MAX_INPUT);
+
+static const char * const cs48l32_us_freq_texts[] = {
+ "16-24kHz", "20-28kHz",
+};
+
+static const unsigned int cs48l32_us_freq_val[] = {
+ 0x2, 0x3,
+};
+
+static const struct soc_enum cs48l32_us_freq[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_US1_CONTROL,
+ CS48L32_US1_FREQ_SHIFT,
+ CS48L32_US1_FREQ_MASK >> CS48L32_US1_FREQ_SHIFT,
+ ARRAY_SIZE(cs48l32_us_freq_val),
+ cs48l32_us_freq_texts,
+ cs48l32_us_freq_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_US2_CONTROL,
+ CS48L32_US1_FREQ_SHIFT,
+ CS48L32_US1_FREQ_MASK >> CS48L32_US1_FREQ_SHIFT,
+ ARRAY_SIZE(cs48l32_us_freq_val),
+ cs48l32_us_freq_texts,
+ cs48l32_us_freq_val),
+};
+
+static const unsigned int cs48l32_us_in_val[] = {
+ 0x0, 0x1, 0x2, 0x3,
+};
+
+static const struct soc_enum cs48l32_us_inmux_enum[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_US1_CONTROL,
+ CS48L32_US1_SRC_SHIFT,
+ CS48L32_US1_SRC_MASK >> CS48L32_US1_SRC_SHIFT,
+ ARRAY_SIZE(cs48l32_us_in_val),
+ cs48l32_in_texts,
+ cs48l32_us_in_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_US2_CONTROL,
+ CS48L32_US1_SRC_SHIFT,
+ CS48L32_US1_SRC_MASK >> CS48L32_US1_SRC_SHIFT,
+ ARRAY_SIZE(cs48l32_us_in_val),
+ cs48l32_in_texts,
+ cs48l32_us_in_val),
+};
+
+static const struct snd_kcontrol_new cs48l32_us_inmux[] = {
+ SOC_DAPM_ENUM("Ultrasonic 1 Input", cs48l32_us_inmux_enum[0]),
+ SOC_DAPM_ENUM("Ultrasonic 2 Input", cs48l32_us_inmux_enum[1]),
+};
+
+static const char * const cs48l32_us_det_thr_texts[] = {
+ "-6dB", "-9dB", "-12dB", "-15dB", "-18dB", "-21dB", "-24dB", "-27dB",
+};
+
+static const struct soc_enum cs48l32_us_det_thr[] = {
+ SOC_ENUM_SINGLE(CS48L32_US1_DET_CONTROL,
+ CS48L32_US1_DET_THR_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_thr_texts),
+ cs48l32_us_det_thr_texts),
+ SOC_ENUM_SINGLE(CS48L32_US2_DET_CONTROL,
+ CS48L32_US1_DET_THR_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_thr_texts),
+ cs48l32_us_det_thr_texts),
+};
+
+static const char * const cs48l32_us_det_num_texts[] = {
+ "1 Sample",
+ "2 Samples",
+ "4 Samples",
+ "8 Samples",
+ "16 Samples",
+ "32 Samples",
+ "64 Samples",
+ "128 Samples",
+ "256 Samples",
+ "512 Samples",
+ "1024 Samples",
+ "2048 Samples",
+ "4096 Samples",
+ "8192 Samples",
+ "16384 Samples",
+ "32768 Samples",
+};
+
+static const struct soc_enum cs48l32_us_det_num[] = {
+ SOC_ENUM_SINGLE(CS48L32_US1_DET_CONTROL,
+ CS48L32_US1_DET_NUM_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_num_texts),
+ cs48l32_us_det_num_texts),
+ SOC_ENUM_SINGLE(CS48L32_US2_DET_CONTROL,
+ CS48L32_US1_DET_NUM_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_num_texts),
+ cs48l32_us_det_num_texts),
+};
+
+static const char * const cs48l32_us_det_hold_texts[] = {
+ "0 Samples",
+ "31 Samples",
+ "63 Samples",
+ "127 Samples",
+ "255 Samples",
+ "511 Samples",
+ "1023 Samples",
+ "2047 Samples",
+ "4095 Samples",
+ "8191 Samples",
+ "16383 Samples",
+ "32767 Samples",
+ "65535 Samples",
+ "131071 Samples",
+ "262143 Samples",
+ "524287 Samples",
+};
+
+static const struct soc_enum cs48l32_us_det_hold[] = {
+ SOC_ENUM_SINGLE(CS48L32_US1_DET_CONTROL,
+ CS48L32_US1_DET_HOLD_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_hold_texts),
+ cs48l32_us_det_hold_texts),
+ SOC_ENUM_SINGLE(CS48L32_US2_DET_CONTROL,
+ CS48L32_US1_DET_HOLD_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_hold_texts),
+ cs48l32_us_det_hold_texts),
+};
+
+static const struct soc_enum cs48l32_us_output_rate[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_US1_CONTROL,
+ CS48L32_US1_RATE_SHIFT,
+ CS48L32_US1_RATE_MASK >> CS48L32_US1_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_US2_CONTROL,
+ CS48L32_US1_RATE_SHIFT,
+ CS48L32_US1_RATE_MASK >> CS48L32_US1_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+};
+
+static const char * const cs48l32_us_det_lpf_cut_texts[] = {
+ "1722Hz", "833Hz", "408Hz", "203Hz",
+};
+
+static const struct soc_enum cs48l32_us_det_lpf_cut[] = {
+ SOC_ENUM_SINGLE(CS48L32_US1_DET_CONTROL,
+ CS48L32_US1_DET_LPF_CUT_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_lpf_cut_texts),
+ cs48l32_us_det_lpf_cut_texts),
+ SOC_ENUM_SINGLE(CS48L32_US2_DET_CONTROL,
+ CS48L32_US1_DET_LPF_CUT_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_lpf_cut_texts),
+ cs48l32_us_det_lpf_cut_texts),
+};
+
+static const char * const cs48l32_us_det_dcy_texts[] = {
+ "0 ms", "0.79 ms", "1.58 ms", "3.16 ms", "6.33 ms", "12.67 ms", "25.34 ms", "50.69 ms",
+};
+
+static const struct soc_enum cs48l32_us_det_dcy[] = {
+ SOC_ENUM_SINGLE(CS48L32_US1_DET_CONTROL,
+ CS48L32_US1_DET_DCY_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_dcy_texts),
+ cs48l32_us_det_dcy_texts),
+ SOC_ENUM_SINGLE(CS48L32_US2_DET_CONTROL,
+ CS48L32_US1_DET_DCY_SHIFT,
+ ARRAY_SIZE(cs48l32_us_det_dcy_texts),
+ cs48l32_us_det_dcy_texts),
+};
+
+static const struct snd_kcontrol_new cs48l32_us_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const char * const cs48l32_vol_ramp_text[] = {
+ "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", "16ms/6dB", "32ms/6dB",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_in_vd_ramp,
+ CS48L32_INPUT_VOL_CONTROL,
+ CS48L32_IN_VD_RAMP_SHIFT,
+ cs48l32_vol_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_in_vi_ramp,
+ CS48L32_INPUT_VOL_CONTROL,
+ CS48L32_IN_VI_RAMP_SHIFT,
+ cs48l32_vol_ramp_text);
+
+static const char * const cs48l32_in_hpf_cut_text[] = {
+ "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_in_hpf_cut_enum,
+ CS48L32_INPUT_HPF_CONTROL,
+ CS48L32_IN_HPF_CUT_SHIFT,
+ cs48l32_in_hpf_cut_text);
+
+static const char * const cs48l32_in_dmic_osr_text[] = {
+ "384kHz", "768kHz", "1.536MHz", "2.048MHz", "2.4576MHz", "3.072MHz", "6.144MHz",
+};
+
+static const struct soc_enum cs48l32_in_dmic_osr[] = {
+ SOC_ENUM_SINGLE(CS48L32_INPUT1_CONTROL1,
+ CS48L32_IN1_OSR_SHIFT,
+ ARRAY_SIZE(cs48l32_in_dmic_osr_text),
+ cs48l32_in_dmic_osr_text),
+ SOC_ENUM_SINGLE(CS48L32_INPUT2_CONTROL1,
+ CS48L32_IN1_OSR_SHIFT,
+ ARRAY_SIZE(cs48l32_in_dmic_osr_text),
+ cs48l32_in_dmic_osr_text),
+};
+
+static bool cs48l32_is_input_enabled(struct snd_soc_component *component,
+ unsigned int reg)
+{
+ unsigned int input_active;
+
+ input_active = snd_soc_component_read(component, CS48L32_INPUT_CONTROL);
+ switch (reg) {
+ case CS48L32_IN1L_CONTROL1:
+ return input_active & BIT(CS48L32_IN1L_EN_SHIFT);
+ case CS48L32_IN1R_CONTROL1:
+ return input_active & BIT(CS48L32_IN1R_EN_SHIFT);
+ case CS48L32_IN2L_CONTROL1:
+ return input_active & BIT(CS48L32_IN2L_EN_SHIFT);
+ case CS48L32_IN2R_CONTROL1:
+ return input_active & BIT(CS48L32_IN2R_EN_SHIFT);
+ default:
+ return false;
+ }
+}
+
+static int cs48l32_in_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ /* Cannot change rate on an active input */
+ if (cs48l32_is_input_enabled(component, e->reg)) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+exit:
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static const struct soc_enum cs48l32_input_rate[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_IN1L_CONTROL1,
+ CS48L32_INx_RATE_SHIFT,
+ CS48L32_INx_RATE_MASK >> CS48L32_INx_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_IN1R_CONTROL1,
+ CS48L32_INx_RATE_SHIFT,
+ CS48L32_INx_RATE_MASK >> CS48L32_INx_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_IN2L_CONTROL1,
+ CS48L32_INx_RATE_SHIFT,
+ CS48L32_INx_RATE_MASK >> CS48L32_INx_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_IN2R_CONTROL1,
+ CS48L32_INx_RATE_SHIFT,
+ CS48L32_INx_RATE_MASK >> CS48L32_INx_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+};
+
+static int cs48l32_low_power_mode_put(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);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ /* Cannot change rate on an active input */
+ if (cs48l32_is_input_enabled(component, mc->reg)) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+exit:
+ snd_soc_dapm_mutex_unlock(dapm);
+ return ret;
+}
+
+static const struct soc_enum noise_gen_rate =
+ SOC_VALUE_ENUM_SINGLE(CS48L32_COMFORT_NOISE_GENERATOR,
+ CS48L32_NOISE_GEN_RATE_SHIFT,
+ CS48L32_NOISE_GEN_RATE_MASK >> CS48L32_NOISE_GEN_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val);
+
+static const char * const cs48l32_auxpdm_freq_texts[] = {
+ "3.072MHz", "2.048MHz", "1.536MHz", "768kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_auxpdm1_freq,
+ CS48L32_AUXPDM1_CONTROL1,
+ CS48L32_AUXPDM1_FREQ_SHIFT,
+ cs48l32_auxpdm_freq_texts);
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_auxpdm2_freq,
+ CS48L32_AUXPDM2_CONTROL1,
+ CS48L32_AUXPDM1_FREQ_SHIFT,
+ cs48l32_auxpdm_freq_texts);
+
+static const char * const cs48l32_auxpdm_src_texts[] = {
+ "Analog", "IN1 Digital", "IN2 Digital",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_auxpdm1_in,
+ CS48L32_AUXPDM_CTRL2,
+ CS48L32_AUXPDMDAT1_SRC_SHIFT,
+ cs48l32_auxpdm_src_texts);
+
+static SOC_ENUM_SINGLE_DECL(cs48l32_auxpdm2_in,
+ CS48L32_AUXPDM_CTRL2,
+ CS48L32_AUXPDMDAT2_SRC_SHIFT,
+ cs48l32_auxpdm_src_texts);
+
+static const struct snd_kcontrol_new cs48l32_auxpdm_inmux[] = {
+ SOC_DAPM_ENUM("AUXPDM1 Input", cs48l32_auxpdm1_in),
+ SOC_DAPM_ENUM("AUXPDM2 Input", cs48l32_auxpdm2_in),
+};
+
+static const unsigned int cs48l32_auxpdm_analog_in_val[] = {
+ 0x0, 0x1,
+};
+
+static const struct soc_enum cs48l32_auxpdm_analog_inmux_enum[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_AUXPDM1_CONTROL1,
+ CS48L32_AUXPDM1_SRC_SHIFT,
+ CS48L32_AUXPDM1_SRC_MASK >> CS48L32_AUXPDM1_SRC_SHIFT,
+ ARRAY_SIZE(cs48l32_auxpdm_analog_in_val),
+ cs48l32_in_texts,
+ cs48l32_auxpdm_analog_in_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_AUXPDM2_CONTROL1,
+ CS48L32_AUXPDM1_SRC_SHIFT,
+ CS48L32_AUXPDM1_SRC_MASK >> CS48L32_AUXPDM1_SRC_SHIFT,
+ ARRAY_SIZE(cs48l32_auxpdm_analog_in_val),
+ cs48l32_in_texts,
+ cs48l32_auxpdm_analog_in_val),
+};
+
+static const struct snd_kcontrol_new cs48l32_auxpdm_analog_inmux[] = {
+ SOC_DAPM_ENUM("AUXPDM1 Analog Input", cs48l32_auxpdm_analog_inmux_enum[0]),
+ SOC_DAPM_ENUM("AUXPDM2 Analog Input", cs48l32_auxpdm_analog_inmux_enum[1]),
+};
+
+static const struct snd_kcontrol_new cs48l32_auxpdm_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct soc_enum cs48l32_isrc_fsh[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_ISRC1_CONTROL1,
+ CS48L32_ISRC1_FSH_SHIFT,
+ CS48L32_ISRC1_FSH_MASK >> CS48L32_ISRC1_FSH_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_ISRC2_CONTROL1,
+ CS48L32_ISRC1_FSH_SHIFT,
+ CS48L32_ISRC1_FSH_MASK >> CS48L32_ISRC1_FSH_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_ISRC3_CONTROL1,
+ CS48L32_ISRC1_FSH_SHIFT,
+ CS48L32_ISRC1_FSH_MASK >> CS48L32_ISRC1_FSH_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+};
+
+static const struct soc_enum cs48l32_isrc_fsl[] = {
+ SOC_VALUE_ENUM_SINGLE(CS48L32_ISRC1_CONTROL1,
+ CS48L32_ISRC1_FSL_SHIFT,
+ CS48L32_ISRC1_FSL_MASK >> CS48L32_ISRC1_FSL_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_ISRC2_CONTROL1,
+ CS48L32_ISRC1_FSL_SHIFT,
+ CS48L32_ISRC1_FSL_MASK >> CS48L32_ISRC1_FSL_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(CS48L32_ISRC3_CONTROL1,
+ CS48L32_ISRC1_FSL_SHIFT,
+ CS48L32_ISRC1_FSL_MASK >> CS48L32_ISRC1_FSL_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val),
+};
+
+static const struct soc_enum cs48l32_fx_rate =
+ SOC_VALUE_ENUM_SINGLE(CS48L32_FX_SAMPLE_RATE,
+ CS48L32_FX_RATE_SHIFT,
+ CS48L32_FX_RATE_MASK >> CS48L32_FX_RATE_SHIFT,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text,
+ cs48l32_rate_val);
+
+static const char * const cs48l32_lhpf_mode_text[] = {
+ "Low-pass", "High-pass"
+};
+
+static const struct soc_enum cs48l32_lhpf_mode[] = {
+ SOC_ENUM_SINGLE(CS48L32_LHPF_CONTROL2, 0,
+ ARRAY_SIZE(cs48l32_lhpf_mode_text), cs48l32_lhpf_mode_text),
+ SOC_ENUM_SINGLE(CS48L32_LHPF_CONTROL2, 1,
+ ARRAY_SIZE(cs48l32_lhpf_mode_text), cs48l32_lhpf_mode_text),
+ SOC_ENUM_SINGLE(CS48L32_LHPF_CONTROL2, 2,
+ ARRAY_SIZE(cs48l32_lhpf_mode_text), cs48l32_lhpf_mode_text),
+ SOC_ENUM_SINGLE(CS48L32_LHPF_CONTROL2, 3,
+ ARRAY_SIZE(cs48l32_lhpf_mode_text), cs48l32_lhpf_mode_text),
+};
+
+static int cs48l32_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ __be32 *data = (__be32 *)ucontrol->value.bytes.data;
+ s16 val = (s16)be32_to_cpu(*data);
+
+ if (abs(val) > CS48L32_LHPF_MAX_COEFF) {
+ dev_err(cs48l32_codec->core.dev, "Rejecting unstable LHPF coefficients\n");
+ return -EINVAL;
+ }
+
+ return snd_soc_bytes_put(kcontrol, ucontrol);
+}
+
+static const char * const cs48l32_eq_mode_text[] = {
+ "Low-pass", "High-pass",
+};
+
+static const struct soc_enum cs48l32_eq_mode[] = {
+ SOC_ENUM_SINGLE(CS48L32_EQ_CONTROL2, 0,
+ ARRAY_SIZE(cs48l32_eq_mode_text),
+ cs48l32_eq_mode_text),
+ SOC_ENUM_SINGLE(CS48L32_EQ_CONTROL2, 1,
+ ARRAY_SIZE(cs48l32_eq_mode_text),
+ cs48l32_eq_mode_text),
+ SOC_ENUM_SINGLE(CS48L32_EQ_CONTROL2, 2,
+ ARRAY_SIZE(cs48l32_eq_mode_text),
+ cs48l32_eq_mode_text),
+ SOC_ENUM_SINGLE(CS48L32_EQ_CONTROL2, 3,
+ ARRAY_SIZE(cs48l32_eq_mode_text),
+ cs48l32_eq_mode_text),
+};
+
+static int cs48l32_eq_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *) kcontrol->private_value;
+ unsigned int item;
+
+ item = snd_soc_enum_val_to_item(e, cs48l32_codec->eq_mode[e->shift_l]);
+ ucontrol->value.enumerated.item[0] = item;
+
+ return 0;
+}
+
+static int cs48l32_eq_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs48l32_codec *cs48l32_codec = 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;
+ bool changed = false;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ if (cs48l32_codec->eq_mode[e->shift_l] != val) {
+ cs48l32_codec->eq_mode[e->shift_l] = val;
+ changed = true;
+ }
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return changed;
+}
+
+static int cs48l32_eq_coeff_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct cs48l32_eq_control *ctl = (void *) kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = ctl->max;
+
+ return 0;
+}
+
+static int cs48l32_eq_coeff_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct cs48l32_eq_control *params = (void *)kcontrol->private_value;
+ __be16 *coeffs;
+ unsigned int coeff_idx;
+ int block_idx;
+
+ block_idx = ((int) params->block_base - (int) CS48L32_EQ1_BAND1_COEFF1);
+ block_idx /= (CS48L32_EQ2_BAND1_COEFF1 - CS48L32_EQ1_BAND1_COEFF1);
+
+ coeffs = &cs48l32_codec->eq_coefficients[block_idx][0];
+ coeff_idx = (params->reg - params->block_base) / 2;
+
+ /* High __be16 is in [coeff_idx] and low __be16 in [coeff_idx + 1] */
+ if (params->shift == 0)
+ coeff_idx++;
+
+ ucontrol->value.integer.value[0] = be16_to_cpu(coeffs[coeff_idx]);
+
+ return 0;
+}
+
+static int cs48l32_eq_coeff_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct cs48l32_eq_control *params = (void *)kcontrol->private_value;
+ __be16 *coeffs;
+ unsigned int coeff_idx;
+ int block_idx;
+
+ block_idx = ((int) params->block_base - (int) CS48L32_EQ1_BAND1_COEFF1);
+ block_idx /= (CS48L32_EQ2_BAND1_COEFF1 - CS48L32_EQ1_BAND1_COEFF1);
+
+ coeffs = &cs48l32_codec->eq_coefficients[block_idx][0];
+ coeff_idx = (params->reg - params->block_base) / 2;
+
+ /* Put high __be16 in [coeff_idx] and low __be16 in [coeff_idx + 1] */
+ if (params->shift == 0)
+ coeff_idx++;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ coeffs[coeff_idx] = cpu_to_be16(ucontrol->value.integer.value[0]);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new cs48l32_drc_activity_output_mux[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs48l32_dsp_trigger_output_mux[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+};
+
+static int cs48l32_dsp_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *) kcontrol->private_value;
+ unsigned int cached_rate;
+ const unsigned int rate_num = e->mask;
+ int item;
+
+ if (rate_num >= ARRAY_SIZE(cs48l32_codec->dsp_dma_rates))
+ return -EINVAL;
+
+ cached_rate = cs48l32_codec->dsp_dma_rates[rate_num];
+ item = snd_soc_enum_val_to_item(e, cached_rate);
+ ucontrol->value.enumerated.item[0] = item;
+
+ return 0;
+}
+
+static int cs48l32_dsp_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *) kcontrol->private_value;
+ const unsigned int rate_num = e->mask;
+ const unsigned int item = ucontrol->value.enumerated.item[0];
+ unsigned int val;
+ bool changed = false;
+
+ if (item >= e->items)
+ return -EINVAL;
+
+ if (rate_num >= ARRAY_SIZE(cs48l32_codec->dsp_dma_rates))
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item);
+
+ snd_soc_dapm_mutex_lock(dapm);
+ if (cs48l32_codec->dsp_dma_rates[rate_num] != val) {
+ cs48l32_codec->dsp_dma_rates[rate_num] = val;
+ changed = true;
+ }
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return changed;
+}
+
+static const struct soc_enum cs48l32_dsp_rate_enum[] = {
+ /* RX rates */
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 0,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 1,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 2,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 3,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 4,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 5,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 6,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 7,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ /* TX rates */
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 8,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 9,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 10,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 11,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 12,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 13,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 14,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+ SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ 15,
+ ARRAY_SIZE(cs48l32_rate_text),
+ cs48l32_rate_text, cs48l32_rate_val),
+};
+
+static int cs48l32_dsp_pre_run(struct wm_adsp *dsp)
+{
+ struct cs48l32_codec *cs48l32_codec = container_of(dsp, struct cs48l32_codec, dsp);
+ unsigned int reg;
+ const u8 *rate = cs48l32_codec->dsp_dma_rates;
+ int i;
+
+ reg = dsp->cs_dsp.base + CS48L32_HALO_SAMPLE_RATE_RX1;
+ for (i = 0; i < CS48L32_DSP_N_RX_CHANNELS; ++i) {
+ regmap_update_bits(dsp->cs_dsp.regmap, reg, CS48L32_HALO_DSP_RATE_MASK, *rate);
+ reg += 8;
+ rate++;
+ }
+
+ reg = dsp->cs_dsp.base + CS48L32_HALO_SAMPLE_RATE_TX1;
+ for (i = 0; i < CS48L32_DSP_N_TX_CHANNELS; ++i) {
+ regmap_update_bits(dsp->cs_dsp.regmap, reg, CS48L32_HALO_DSP_RATE_MASK, *rate);
+ reg += 8;
+ rate++;
+ }
+
+ usleep_range(300, 600);
+
+ return 0;
+}
+
+static void cs48l32_dsp_memory_disable(struct cs48l32_codec *cs48l32_codec,
+ const struct cs48l32_dsp_power_regs *regs)
+{
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ int i, j, ret;
+
+ for (i = 0; i < regs->n_pwd; ++i) {
+ ret = regmap_write(regmap, regs->pwd[i], 0);
+ if (ret)
+ goto err;
+ }
+
+ for (i = 0; i < regs->n_ext; ++i) {
+ for (j = regs->ext[i].start; j <= regs->ext[i].end; j += 4) {
+ ret = regmap_write(regmap, j, 0);
+ if (ret)
+ goto err;
+ }
+ }
+
+ return;
+
+err:
+ dev_warn(cs48l32_codec->core.dev, "Failed to write SRAM enables (%d)\n", ret);
+}
+
+static int cs48l32_dsp_memory_enable(struct cs48l32_codec *cs48l32_codec,
+ const struct cs48l32_dsp_power_regs *regs)
+{
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ int i, j, ret;
+
+ /* disable power-off */
+ for (i = 0; i < regs->n_ext; ++i) {
+ for (j = regs->ext[i].start; j <= regs->ext[i].end; j += 4) {
+ ret = regmap_write(regmap, j, 0x3);
+ if (ret)
+ goto err;
+ }
+ }
+
+ /* power-up the banks in sequence */
+ for (i = 0; i < regs->n_pwd; ++i) {
+ ret = regmap_write(regmap, regs->pwd[i], 0x1);
+ if (ret)
+ goto err;
+
+ udelay(1); /* allow bank to power-up */
+
+ ret = regmap_write(regmap, regs->pwd[i], 0x3);
+ if (ret)
+ goto err;
+
+ udelay(1); /* allow bank to power-up */
+ }
+
+ return 0;
+
+err:
+ dev_err(cs48l32_codec->core.dev, "Failed to write SRAM enables (%d)\n", ret);
+ cs48l32_dsp_memory_disable(cs48l32_codec, regs);
+
+ return ret;
+}
+
+static int cs48l32_dsp_freq_update(struct snd_soc_dapm_widget *w, unsigned int freq_reg,
+ unsigned int freqsel_reg)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ struct wm_adsp *dsp = &cs48l32_codec->dsp;
+ int ret;
+ unsigned int freq, freq_sel, freq_sts;
+
+ if (!freq_reg)
+ return -EINVAL;
+
+ ret = regmap_read(regmap, freq_reg, &freq);
+ if (ret) {
+ dev_err(component->dev, "Failed to read #%x: %d\n", freq_reg, ret);
+ return ret;
+ }
+
+ if (freqsel_reg) {
+ freq_sts = (freq & CS48L32_SYSCLK_FREQ_STS_MASK) >> CS48L32_SYSCLK_FREQ_STS_SHIFT;
+
+ ret = regmap_read(regmap, freqsel_reg, &freq_sel);
+ if (ret) {
+ dev_err(component->dev, "Failed to read #%x: %d\n", freqsel_reg, ret);
+ return ret;
+ }
+ freq_sel = (freq_sel & CS48L32_SYSCLK_FREQ_MASK) >> CS48L32_SYSCLK_FREQ_SHIFT;
+
+ if (freq_sts != freq_sel) {
+ dev_err(component->dev, "SYSCLK FREQ (#%x) != FREQ STS (#%x)\n",
+ freq_sel, freq_sts);
+ return -ETIMEDOUT;
+ }
+ }
+
+ freq &= CS48L32_DSP_CLK_FREQ_MASK;
+ freq >>= CS48L32_DSP_CLK_FREQ_SHIFT;
+
+ ret = regmap_write(dsp->cs_dsp.regmap,
+ dsp->cs_dsp.base + CS48L32_DSP_CLOCK_FREQ_OFFS, freq);
+ if (ret) {
+ dev_err(component->dev, "Failed to set HALO clock freq: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cs48l32_dsp_freq_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ return cs48l32_dsp_freq_update(w, CS48L32_SYSTEM_CLOCK2, CS48L32_SYSTEM_CLOCK1);
+ default:
+ return 0;
+ }
+}
+
+static irqreturn_t cs48l32_irq(int irq, void *data)
+{
+ static const unsigned int eint1_regs[] = {
+ CS48L32_IRQ1_EINT_9, CS48L32_IRQ1_MASK_9,
+ CS48L32_IRQ1_EINT_7, CS48L32_IRQ1_MASK_7
+ };
+ u32 reg_vals[4];
+ struct cs48l32_codec *cs48l32_codec = data;
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ irqreturn_t result = IRQ_NONE;
+ unsigned int eint_pending;
+ int i, ret;
+
+ static_assert(ARRAY_SIZE(eint1_regs) == ARRAY_SIZE(reg_vals));
+
+ ret = pm_runtime_resume_and_get(cs48l32_codec->core.dev);
+ if (ret) {
+ dev_warn(cs48l32_codec->core.dev, "irq could not get pm runtime: %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ ret = regmap_read(regmap, CS48L32_IRQ1_STATUS, &eint_pending);
+ if (ret) {
+ dev_warn(cs48l32_codec->core.dev, "Read IRQ1_STATUS failed: %d\n", ret);
+ return IRQ_NONE;
+ }
+ if ((eint_pending & CS48L32_IRQ1_STS_MASK) == 0)
+ goto out;
+
+ ret = regmap_multi_reg_read(regmap, eint1_regs, reg_vals, ARRAY_SIZE(reg_vals));
+ if (ret) {
+ dev_warn(cs48l32_codec->core.dev, "Read IRQ regs failed: %d\n", ret);
+ return IRQ_NONE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(reg_vals); i += 2) {
+ reg_vals[i] &= ~reg_vals[i + 1];
+ regmap_write(regmap, eint1_regs[i], reg_vals[i]);
+ }
+
+ if (reg_vals[0] & CS48L32_DSP1_IRQ0_EINT1_MASK)
+ wm_adsp_compr_handle_irq(&cs48l32_codec->dsp);
+
+ if (reg_vals[2] & CS48L32_DSP1_MPU_ERR_EINT1_MASK) {
+ dev_warn(cs48l32_codec->core.dev, "MPU err IRQ\n");
+ wm_halo_bus_error(irq, &cs48l32_codec->dsp);
+ }
+
+ if (reg_vals[2] & CS48L32_DSP1_WDT_EXPIRE_EINT1_MASK) {
+ dev_warn(cs48l32_codec->core.dev, "WDT expire IRQ\n");
+ wm_halo_wdt_expire(irq, &cs48l32_codec->dsp);
+ }
+
+ result = IRQ_HANDLED;
+
+out:
+ pm_runtime_put_autosuspend(cs48l32_codec->core.dev);
+
+ return result;
+}
+
+static int cs48l32_get_dspclk_setting(struct cs48l32_codec *cs48l32_codec, unsigned int freq,
+ int src, unsigned int *val)
+{
+ freq /= 15625; /* convert to 1/64ths of 1MHz */
+ *val |= freq << CS48L32_DSP_CLK_FREQ_SHIFT;
+
+ return 0;
+}
+
+static int cs48l32_get_sysclk_setting(unsigned int freq)
+{
+ switch (freq) {
+ case 0:
+ case 5644800:
+ case 6144000:
+ return CS48L32_SYSCLK_RATE_6MHZ;
+ case 11289600:
+ case 12288000:
+ return CS48L32_SYSCLK_RATE_12MHZ << CS48L32_SYSCLK_FREQ_SHIFT;
+ case 22579200:
+ case 24576000:
+ return CS48L32_SYSCLK_RATE_24MHZ << CS48L32_SYSCLK_FREQ_SHIFT;
+ case 45158400:
+ case 49152000:
+ return CS48L32_SYSCLK_RATE_49MHZ << CS48L32_SYSCLK_FREQ_SHIFT;
+ case 90316800:
+ case 98304000:
+ return CS48L32_SYSCLK_RATE_98MHZ << CS48L32_SYSCLK_FREQ_SHIFT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cs48l32_set_pdm_fllclk(struct snd_soc_component *component, int source)
+{
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ unsigned int val;
+
+ switch (source) {
+ case CS48L32_PDMCLK_SRC_IN1_PDMCLK:
+ case CS48L32_PDMCLK_SRC_IN2_PDMCLK:
+ case CS48L32_PDMCLK_SRC_IN3_PDMCLK:
+ case CS48L32_PDMCLK_SRC_IN4_PDMCLK:
+ case CS48L32_PDMCLK_SRC_AUXPDM1_CLK:
+ case CS48L32_PDMCLK_SRC_AUXPDM2_CLK:
+ val = source << CS48L32_PDM_FLLCLK_SRC_SHIFT;
+ break;
+ default:
+ dev_err(cs48l32_codec->core.dev, "Invalid PDM FLLCLK src %d\n", source);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS48L32_INPUT_CONTROL2,
+ CS48L32_PDM_FLLCLK_SRC_MASK, val);
+}
+
+static int cs48l32_set_sysclk(struct snd_soc_component *component, int clk_id, int source,
+ unsigned int freq, int dir)
+{
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ char *name;
+ unsigned int reg;
+ unsigned int mask = CS48L32_SYSCLK_SRC_MASK;
+ unsigned int val = source << CS48L32_SYSCLK_SRC_SHIFT;
+ int clk_freq_sel, *clk;
+
+ switch (clk_id) {
+ case CS48L32_CLK_SYSCLK_1:
+ name = "SYSCLK";
+ reg = CS48L32_SYSTEM_CLOCK1;
+ clk = &cs48l32_codec->sysclk;
+ clk_freq_sel = cs48l32_get_sysclk_setting(freq);
+ mask |= CS48L32_SYSCLK_FREQ_MASK | CS48L32_SYSCLK_FRAC_MASK;
+ break;
+ case CS48L32_CLK_DSPCLK:
+ name = "DSPCLK";
+ reg = CS48L32_DSP_CLOCK1;
+ clk = &cs48l32_codec->dspclk;
+ clk_freq_sel = cs48l32_get_dspclk_setting(cs48l32_codec, freq, source, &val);
+ mask |= CS48L32_DSP_CLK_FREQ_MASK;
+ break;
+ case CS48L32_CLK_PDM_FLLCLK:
+ return cs48l32_set_pdm_fllclk(component, source);
+ default:
+ return -EINVAL;
+ }
+
+ if (clk_freq_sel < 0) {
+ dev_err(cs48l32_codec->core.dev, "Failed to get %s setting for %dHZ\n", name, freq);
+ return clk_freq_sel;
+ }
+
+ *clk = freq;
+
+ if (freq == 0) {
+ dev_dbg(cs48l32_codec->core.dev, "%s cleared\n", name);
+ return 0;
+ }
+
+ val |= clk_freq_sel;
+
+ if (freq % 6144000)
+ val |= CS48L32_SYSCLK_FRAC_MASK;
+
+ dev_dbg(cs48l32_codec->core.dev, "%s set to %uHz", name, freq);
+
+ return regmap_update_bits(regmap, reg, mask, val);
+}
+
+static int cs48l32_is_enabled_fll(struct cs48l32_fll *fll, int base)
+{
+ struct regmap *regmap = fll->codec->core.regmap;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(regmap, base + CS48L32_FLL_CONTROL1_OFFS, &reg);
+ if (ret != 0) {
+ cs48l32_fll_err(fll, "Failed to read current state: %d\n", ret);
+ return ret;
+ }
+
+ return reg & CS48L32_FLL_EN_MASK;
+}
+
+static int cs48l32_wait_for_fll(struct cs48l32_fll *fll, bool requested)
+{
+ struct regmap *regmap = fll->codec->core.regmap;
+ unsigned int val = 0;
+ int i;
+
+ cs48l32_fll_dbg(fll, "Waiting for FLL...\n");
+
+ for (i = 0; i < 30; i++) {
+ regmap_read(regmap, fll->sts_addr, &val);
+ if (!!(val & fll->sts_mask) == requested)
+ return 0;
+
+ switch (i) {
+ case 0 ... 5:
+ usleep_range(75, 125);
+ break;
+ case 6 ... 20:
+ usleep_range(750, 1250);
+ break;
+ default:
+ fsleep(20000);
+ break;
+ }
+ }
+
+ cs48l32_fll_warn(fll, "Timed out waiting for %s\n", requested ? "lock" : "unlock");
+
+ return -ETIMEDOUT;
+}
+
+static int cs48l32_fllhj_disable(struct cs48l32_fll *fll)
+{
+ struct cs48l32 *cs48l32 = &fll->codec->core;
+ bool change;
+
+ cs48l32_fll_dbg(fll, "Disabling FLL\n");
+
+ /*
+ * Disable lockdet, but don't set ctrl_upd update bit. This allows the
+ * lock status bit to clear as normal, but should the FLL be enabled
+ * again due to a control clock being required, the lock won't re-assert
+ * as the FLL config registers are automatically applied when the FLL
+ * enables.
+ */
+ regmap_set_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_HOLD_MASK);
+ regmap_clear_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL2_OFFS,
+ CS48L32_FLL_LOCKDET_MASK);
+ regmap_set_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL5_OFFS,
+ CS48L32_FLL_FRC_INTEG_UPD_MASK);
+ regmap_update_bits_check(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_EN_MASK,
+ 0,
+ &change);
+
+ cs48l32_wait_for_fll(fll, false);
+
+ /*
+ * ctrl_up gates the writes to all the fll's registers, setting it to 0
+ * here ensures that after a runtime suspend/resume cycle when one
+ * enables the fll then ctrl_up is the last bit that is configured
+ * by the fll enable code rather than the cache sync operation which
+ * would have updated it much earlier before writing out all fll
+ * registers
+ */
+ regmap_clear_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_CTRL_UPD_MASK);
+
+ if (change)
+ pm_runtime_put_autosuspend(cs48l32->dev);
+
+ return 0;
+}
+
+static int cs48l32_fllhj_apply(struct cs48l32_fll *fll, int fin)
+{
+ struct regmap *regmap = fll->codec->core.regmap;
+ int refdiv, fref, fout, lockdet_thr, fbdiv, fllgcd;
+ bool frac = false;
+ unsigned int fll_n, min_n, max_n, ratio, theta, lambda, hp;
+ unsigned int gains, num;
+
+ cs48l32_fll_dbg(fll, "fin=%d, fout=%d\n", fin, fll->fout);
+
+ for (refdiv = 0; refdiv < 4; refdiv++) {
+ if ((fin / (1 << refdiv)) <= CS48L32_FLLHJ_MAX_THRESH)
+ break;
+ }
+
+ fref = fin / (1 << refdiv);
+ fout = fll->fout;
+ frac = fout % fref;
+
+ /*
+ * Use simple heuristic approach to find a configuration that
+ * should work for most input clocks.
+ */
+ if (fref < CS48L32_FLLHJ_LOW_THRESH) {
+ lockdet_thr = 2;
+ gains = CS48L32_FLLHJ_LOW_GAINS;
+
+ if (frac)
+ fbdiv = 256;
+ else
+ fbdiv = 4;
+ } else if (fref < CS48L32_FLLHJ_MID_THRESH) {
+ lockdet_thr = 8;
+ gains = CS48L32_FLLHJ_MID_GAINS;
+ fbdiv = (frac) ? 16 : 2;
+ } else {
+ lockdet_thr = 8;
+ gains = CS48L32_FLLHJ_HIGH_GAINS;
+ fbdiv = 1;
+ }
+ /* Use high performance mode for fractional configurations. */
+ if (frac) {
+ hp = 3;
+ min_n = CS48L32_FLLHJ_FRAC_MIN_N;
+ max_n = CS48L32_FLLHJ_FRAC_MAX_N;
+ } else {
+ if (fref < CS48L32_FLLHJ_LP_INT_MODE_THRESH)
+ hp = 0;
+ else
+ hp = 1;
+
+ min_n = CS48L32_FLLHJ_INT_MIN_N;
+ max_n = CS48L32_FLLHJ_INT_MAX_N;
+ }
+
+ ratio = fout / fref;
+
+ cs48l32_fll_dbg(fll, "refdiv=%d, fref=%d, frac:%d\n", refdiv, fref, frac);
+
+ while (ratio / fbdiv < min_n) {
+ fbdiv /= 2;
+ if (fbdiv < min_n) {
+ cs48l32_fll_err(fll, "FBDIV (%u) < minimum N (%u)\n", fbdiv, min_n);
+ return -EINVAL;
+ }
+ }
+ while (frac && (ratio / fbdiv > max_n)) {
+ fbdiv *= 2;
+ if (fbdiv >= 1024) {
+ cs48l32_fll_err(fll, "FBDIV (%u) >= 1024\n", fbdiv);
+ return -EINVAL;
+ }
+ }
+
+ cs48l32_fll_dbg(fll, "lockdet=%d, hp=#%x, fbdiv:%d\n", lockdet_thr, hp, fbdiv);
+
+ /* Calculate N.K values */
+ fllgcd = gcd(fout, fbdiv * fref);
+ num = fout / fllgcd;
+ lambda = (fref * fbdiv) / fllgcd;
+ fll_n = num / lambda;
+ theta = num % lambda;
+
+ cs48l32_fll_dbg(fll, "fll_n=%d, gcd=%d, theta=%d, lambda=%d\n",
+ fll_n, fllgcd, theta, lambda);
+
+ /* Some sanity checks before any registers are written. */
+ if (fll_n < min_n || fll_n > max_n) {
+ cs48l32_fll_err(fll, "N not in valid %s mode range %d-%d: %d\n",
+ frac ? "fractional" : "integer", min_n, max_n, fll_n);
+ return -EINVAL;
+ }
+ if (fbdiv < 1 || (frac && fbdiv >= 1024) || (!frac && fbdiv >= 256)) {
+ cs48l32_fll_err(fll, "Invalid fbdiv for %s mode (%u)\n",
+ frac ? "fractional" : "integer", fbdiv);
+ return -EINVAL;
+ }
+
+ /* clear the ctrl_upd bit to guarantee we write to it later. */
+ regmap_update_bits(regmap,
+ fll->base + CS48L32_FLL_CONTROL2_OFFS,
+ CS48L32_FLL_LOCKDET_THR_MASK |
+ CS48L32_FLL_PHASEDET_MASK |
+ CS48L32_FLL_REFCLK_DIV_MASK |
+ CS48L32_FLL_N_MASK |
+ CS48L32_FLL_CTRL_UPD_MASK,
+ (lockdet_thr << CS48L32_FLL_LOCKDET_THR_SHIFT) |
+ (1 << CS48L32_FLL_PHASEDET_SHIFT) |
+ (refdiv << CS48L32_FLL_REFCLK_DIV_SHIFT) |
+ (fll_n << CS48L32_FLL_N_SHIFT));
+
+ regmap_update_bits(regmap,
+ fll->base + CS48L32_FLL_CONTROL3_OFFS,
+ CS48L32_FLL_LAMBDA_MASK |
+ CS48L32_FLL_THETA_MASK,
+ (lambda << CS48L32_FLL_LAMBDA_SHIFT) |
+ (theta << CS48L32_FLL_THETA_SHIFT));
+
+ regmap_update_bits(regmap,
+ fll->base + CS48L32_FLL_CONTROL4_OFFS,
+ (0xffff << CS48L32_FLL_FD_GAIN_COARSE_SHIFT) |
+ CS48L32_FLL_HP_MASK |
+ CS48L32_FLL_FB_DIV_MASK,
+ (gains << CS48L32_FLL_FD_GAIN_COARSE_SHIFT) |
+ (hp << CS48L32_FLL_HP_SHIFT) |
+ (fbdiv << CS48L32_FLL_FB_DIV_SHIFT));
+
+ return 0;
+}
+
+static int cs48l32_fllhj_enable(struct cs48l32_fll *fll)
+{
+ struct cs48l32 *cs48l32 = &fll->codec->core;
+ int already_enabled = cs48l32_is_enabled_fll(fll, fll->base);
+ int ret;
+
+ if (already_enabled < 0)
+ return already_enabled;
+
+ if (!already_enabled)
+ pm_runtime_get_sync(cs48l32->dev);
+
+ cs48l32_fll_dbg(fll, "Enabling FLL, initially %s\n",
+ str_enabled_disabled(already_enabled));
+
+ /* FLLn_HOLD must be set before configuring any registers */
+ regmap_set_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_HOLD_MASK);
+
+ /* Apply refclk */
+ ret = cs48l32_fllhj_apply(fll, fll->ref_freq);
+ if (ret) {
+ cs48l32_fll_err(fll, "Failed to set FLL: %d\n", ret);
+ goto out;
+ }
+ regmap_update_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL2_OFFS,
+ CS48L32_FLL_REFCLK_SRC_MASK,
+ fll->ref_src << CS48L32_FLL_REFCLK_SRC_SHIFT);
+
+ regmap_set_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_EN_MASK);
+
+out:
+ regmap_set_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL2_OFFS,
+ CS48L32_FLL_LOCKDET_MASK);
+
+ regmap_set_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_CTRL_UPD_MASK);
+
+ /* Release the hold so that flln locks to external frequency */
+ regmap_clear_bits(cs48l32->regmap,
+ fll->base + CS48L32_FLL_CONTROL1_OFFS,
+ CS48L32_FLL_HOLD_MASK);
+
+ if (!already_enabled)
+ cs48l32_wait_for_fll(fll, true);
+
+ return 0;
+}
+
+static int cs48l32_fllhj_validate(struct cs48l32_fll *fll,
+ unsigned int ref_in,
+ unsigned int fout)
+{
+ if (fout && !ref_in) {
+ cs48l32_fll_err(fll, "fllout set without valid input clk\n");
+ return -EINVAL;
+ }
+
+ if (fll->fout && fout != fll->fout) {
+ cs48l32_fll_err(fll, "Can't change output on active FLL\n");
+ return -EINVAL;
+ }
+
+ if (ref_in / CS48L32_FLL_MAX_REFDIV > CS48L32_FLLHJ_MAX_THRESH) {
+ cs48l32_fll_err(fll, "Can't scale %dMHz to <=13MHz\n", ref_in);
+ return -EINVAL;
+ }
+
+ if (fout > CS48L32_FLL_MAX_FOUT) {
+ cs48l32_fll_err(fll, "Fout=%dMHz exceeds maximum %dMHz\n",
+ fout, CS48L32_FLL_MAX_FOUT);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs48l32_fllhj_set_refclk(struct cs48l32_fll *fll, int source,
+ unsigned int fin, unsigned int fout)
+{
+ int ret = 0;
+
+ if (fll->ref_src == source && fll->ref_freq == fin && fll->fout == fout)
+ return 0;
+
+ if (fin && fout && cs48l32_fllhj_validate(fll, fin, fout))
+ return -EINVAL;
+
+ fll->ref_src = source;
+ fll->ref_freq = fin;
+ fll->fout = fout;
+
+ if (fout)
+ ret = cs48l32_fllhj_enable(fll);
+ else
+ cs48l32_fllhj_disable(fll);
+
+ return ret;
+}
+
+static int cs48l32_init_fll(struct cs48l32_fll *fll)
+{
+ fll->ref_src = CS48L32_FLL_SRC_NONE;
+
+ return 0;
+}
+
+static int cs48l32_set_fll(struct snd_soc_component *component, int fll_id,
+ int source, unsigned int fref, unsigned int fout)
+{
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+
+ switch (fll_id) {
+ case CS48L32_FLL1_REFCLK:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return cs48l32_fllhj_set_refclk(&cs48l32_codec->fll, source, fref, fout);
+}
+
+static int cs48l32_asp_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ unsigned int pin_reg, last_pin_reg, hiz_reg;
+
+ switch (dai->id) {
+ case 1:
+ pin_reg = CS48L32_GPIO3_CTRL1;
+ hiz_reg = CS48L32_ASP1_CONTROL3;
+ break;
+ case 2:
+ pin_reg = CS48L32_GPIO7_CTRL1;
+ hiz_reg = CS48L32_ASP2_CONTROL3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (last_pin_reg = pin_reg + 12; pin_reg <= last_pin_reg; ++pin_reg)
+ regmap_clear_bits(regmap, pin_reg, CS48L32_GPIOX_CTRL1_FN_MASK);
+
+ /* DOUT high-impendance when not transmitting */
+ regmap_set_bits(regmap, hiz_reg, CS48L32_ASP_DOUT_HIZ_MASK);
+
+ return 0;
+}
+
+static int cs48l32_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ unsigned int val = 0U;
+ unsigned int base = dai->driver->base;
+ unsigned int mask = CS48L32_ASP_FMT_MASK | CS48L32_ASP_BCLK_INV_MASK |
+ CS48L32_ASP_BCLK_MSTR_MASK |
+ CS48L32_ASP_FSYNC_INV_MASK |
+ CS48L32_ASP_FSYNC_MSTR_MASK;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ val |= (CS48L32_ASP_FMT_DSP_MODE_A << CS48L32_ASP_FMT_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) {
+ cs48l32_asp_err(dai, "DSP_B cannot be clock consumer\n");
+ return -EINVAL;
+ }
+ val |= (CS48L32_ASP_FMT_DSP_MODE_B << CS48L32_ASP_FMT_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ val |= (CS48L32_ASP_FMT_I2S_MODE << CS48L32_ASP_FMT_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) {
+ cs48l32_asp_err(dai, "LEFT_J cannot be clock consumer\n");
+ return -EINVAL;
+ }
+ val |= (CS48L32_ASP_FMT_LEFT_JUSTIFIED_MODE << CS48L32_ASP_FMT_SHIFT);
+ break;
+ default:
+ cs48l32_asp_err(dai, "Unsupported DAI format %d\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BC_FC:
+ break;
+ case SND_SOC_DAIFMT_BC_FP:
+ val |= CS48L32_ASP_FSYNC_MSTR_MASK;
+ break;
+ case SND_SOC_DAIFMT_BP_FC:
+ val |= CS48L32_ASP_BCLK_MSTR_MASK;
+ break;
+ case SND_SOC_DAIFMT_BP_FP:
+ val |= CS48L32_ASP_BCLK_MSTR_MASK;
+ val |= CS48L32_ASP_FSYNC_MSTR_MASK;
+ break;
+ default:
+ cs48l32_asp_err(dai, "Unsupported clock direction %d\n",
+ fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ val |= CS48L32_ASP_BCLK_INV_MASK;
+ val |= CS48L32_ASP_FSYNC_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val |= CS48L32_ASP_BCLK_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val |= CS48L32_ASP_FSYNC_INV_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(regmap, base + CS48L32_ASP_CONTROL2, mask, val);
+
+ return 0;
+}
+
+static const struct {
+ u32 freq;
+ u32 id;
+} cs48l32_sclk_rates[] = {
+ { 128000, 12 },
+ { 176400, 13 },
+ { 192000, 14 },
+ { 256000, 15 },
+ { 352800, 16 },
+ { 384000, 17 },
+ { 512000, 18 },
+ { 705600, 19 },
+ { 768000, 21 },
+ { 1024000, 23 },
+ { 1411200, 25 },
+ { 1536000, 27 },
+ { 2048000, 29 },
+ { 2822400, 31 },
+ { 3072000, 33 },
+ { 4096000, 36 },
+ { 5644800, 38 },
+ { 6144000, 40 },
+ { 8192000, 47 },
+ { 11289600, 49 },
+ { 12288000, 51 },
+ { 22579200, 57 },
+ { 24576000, 59 },
+};
+
+#define CS48L32_48K_RATE_MASK 0x0e00fe
+#define CS48L32_44K1_RATE_MASK 0x00fe00
+#define CS48L32_RATE_MASK (CS48L32_48K_RATE_MASK | CS48L32_44K1_RATE_MASK)
+
+static const unsigned int cs48l32_sr_vals[] = {
+ 0,
+ 12000, /* CS48L32_48K_RATE_MASK */
+ 24000, /* CS48L32_48K_RATE_MASK */
+ 48000, /* CS48L32_48K_RATE_MASK */
+ 96000, /* CS48L32_48K_RATE_MASK */
+ 192000, /* CS48L32_48K_RATE_MASK */
+ 384000, /* CS48L32_48K_RATE_MASK */
+ 768000, /* CS48L32_48K_RATE_MASK */
+ 0,
+ 11025, /* CS48L32_44K1_RATE_MASK */
+ 22050, /* CS48L32_44K1_RATE_MASK */
+ 44100, /* CS48L32_44K1_RATE_MASK */
+ 88200, /* CS48L32_44K1_RATE_MASK */
+ 176400, /* CS48L32_44K1_RATE_MASK */
+ 352800, /* CS48L32_44K1_RATE_MASK */
+ 705600, /* CS48L32_44K1_RATE_MASK */
+ 0,
+ 8000, /* CS48L32_48K_RATE_MASK */
+ 16000, /* CS48L32_48K_RATE_MASK */
+ 32000, /* CS48L32_48K_RATE_MASK */
+};
+
+static const struct snd_pcm_hw_constraint_list cs48l32_constraint = {
+ .count = ARRAY_SIZE(cs48l32_sr_vals),
+ .list = cs48l32_sr_vals,
+};
+
+static int cs48l32_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1];
+ unsigned int base_rate;
+
+ if (!substream->runtime)
+ return 0;
+
+ switch (dai_priv->clk) {
+ case CS48L32_CLK_SYSCLK_1:
+ case CS48L32_CLK_SYSCLK_2:
+ case CS48L32_CLK_SYSCLK_3:
+ case CS48L32_CLK_SYSCLK_4:
+ base_rate = cs48l32_codec->sysclk;
+ break;
+ default:
+ return 0;
+ }
+
+ if (base_rate == 0)
+ dai_priv->constraint.mask = CS48L32_RATE_MASK;
+ else if (base_rate % 4000)
+ dai_priv->constraint.mask = CS48L32_44K1_RATE_MASK;
+ else
+ dai_priv->constraint.mask = CS48L32_48K_RATE_MASK;
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &dai_priv->constraint);
+}
+
+static int cs48l32_hw_params_rate(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1];
+ unsigned int sr_val, sr_reg, rate;
+
+ rate = params_rate(params);
+ for (sr_val = 0; sr_val < ARRAY_SIZE(cs48l32_sr_vals); sr_val++)
+ if (cs48l32_sr_vals[sr_val] == rate)
+ break;
+
+ if (sr_val == ARRAY_SIZE(cs48l32_sr_vals)) {
+ cs48l32_asp_err(dai, "Unsupported sample rate %dHz\n", rate);
+ return -EINVAL;
+ }
+
+ switch (dai_priv->clk) {
+ case CS48L32_CLK_SYSCLK_1:
+ sr_reg = CS48L32_SAMPLE_RATE1;
+ break;
+ case CS48L32_CLK_SYSCLK_2:
+ sr_reg = CS48L32_SAMPLE_RATE2;
+ break;
+ case CS48L32_CLK_SYSCLK_3:
+ sr_reg = CS48L32_SAMPLE_RATE3;
+ break;
+ case CS48L32_CLK_SYSCLK_4:
+ sr_reg = CS48L32_SAMPLE_RATE4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, sr_reg, CS48L32_SAMPLE_RATE_1_MASK, sr_val);
+
+ return 0;
+}
+
+static bool cs48l32_asp_cfg_changed(struct snd_soc_component *component,
+ unsigned int base, unsigned int sclk,
+ unsigned int slotws, unsigned int dataw)
+{
+ unsigned int val;
+
+ val = snd_soc_component_read(component, base + CS48L32_ASP_CONTROL1);
+ if (sclk != (val & CS48L32_ASP_BCLK_FREQ_MASK))
+ return true;
+
+ val = snd_soc_component_read(component, base + CS48L32_ASP_CONTROL2);
+ if (slotws != (val & (CS48L32_ASP_RX_WIDTH_MASK | CS48L32_ASP_TX_WIDTH_MASK)))
+ return true;
+
+ val = snd_soc_component_read(component, base + CS48L32_ASP_DATA_CONTROL1);
+ if (dataw != (val & (CS48L32_ASP_TX_WL_MASK)))
+ return true;
+
+ val = snd_soc_component_read(component, base + CS48L32_ASP_DATA_CONTROL5);
+ if (dataw != (val & (CS48L32_ASP_RX_WL_MASK)))
+ return true;
+
+ return false;
+}
+
+static int cs48l32_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ int base = dai->driver->base;
+ int dai_id = dai->id - 1;
+ unsigned int rate = params_rate(params);
+ unsigned int dataw = snd_pcm_format_width(params_format(params));
+ unsigned int asp_state = 0;
+ int sclk, sclk_target;
+ unsigned int slotw, n_slots, n_slots_multiple, val;
+ int i, ret;
+
+ cs48l32_asp_dbg(dai, "hwparams in: ch:%u dataw:%u rate:%u\n",
+ params_channels(params), dataw, rate);
+ /*
+ * The following calculations hold only under the assumption that
+ * symmetric_[rates|channels|samplebits] are set to 1
+ */
+ if (cs48l32_codec->tdm_slots[dai_id]) {
+ n_slots = cs48l32_codec->tdm_slots[dai_id];
+ slotw = cs48l32_codec->tdm_width[dai_id];
+ } else {
+ n_slots = params_channels(params);
+ slotw = dataw;
+ }
+
+ val = snd_soc_component_read(component, base + CS48L32_ASP_CONTROL2);
+ val = (val & CS48L32_ASP_FMT_MASK) >> CS48L32_ASP_FMT_SHIFT;
+ if (val == CS48L32_ASP_FMT_I2S_MODE)
+ n_slots_multiple = 2;
+ else
+ n_slots_multiple = 1;
+
+ sclk_target = snd_soc_tdm_params_to_bclk(params, slotw, n_slots, n_slots_multiple);
+ if (sclk_target < 0) {
+ cs48l32_asp_err(dai, "Invalid parameters\n");
+ return sclk_target;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs48l32_sclk_rates); i++) {
+ if ((cs48l32_sclk_rates[i].freq >= sclk_target) &&
+ (cs48l32_sclk_rates[i].freq % rate == 0)) {
+ sclk = cs48l32_sclk_rates[i].id;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(cs48l32_sclk_rates)) {
+ cs48l32_asp_err(dai, "Unsupported sample rate %dHz\n", rate);
+ return -EINVAL;
+ }
+
+ cs48l32_asp_dbg(dai, "hwparams out: n_slots:%u dataw:%u slotw:%u bclk:%u bclkid:%u\n",
+ n_slots, dataw, slotw, sclk_target, sclk);
+
+ slotw = (slotw << CS48L32_ASP_TX_WIDTH_SHIFT) |
+ (slotw << CS48L32_ASP_RX_WIDTH_SHIFT);
+
+ if (!cs48l32_asp_cfg_changed(component, base, sclk, slotw, dataw))
+ return cs48l32_hw_params_rate(substream, params, dai);
+
+ /* ASP must be disabled while changing configuration */
+ asp_state = snd_soc_component_read(component, base + CS48L32_ASP_ENABLES1);
+ regmap_clear_bits(regmap, base + CS48L32_ASP_ENABLES1, 0xff00ff);
+
+ ret = cs48l32_hw_params_rate(substream, params, dai);
+ if (ret != 0)
+ goto restore_asp;
+
+ regmap_update_bits_async(regmap,
+ base + CS48L32_ASP_CONTROL1,
+ CS48L32_ASP_BCLK_FREQ_MASK,
+ sclk);
+ regmap_update_bits_async(regmap,
+ base + CS48L32_ASP_CONTROL2,
+ CS48L32_ASP_RX_WIDTH_MASK | CS48L32_ASP_TX_WIDTH_MASK,
+ slotw);
+ regmap_update_bits_async(regmap,
+ base + CS48L32_ASP_DATA_CONTROL1,
+ CS48L32_ASP_TX_WL_MASK,
+ dataw);
+ regmap_update_bits(regmap,
+ base + CS48L32_ASP_DATA_CONTROL5,
+ CS48L32_ASP_RX_WL_MASK,
+ dataw);
+
+restore_asp:
+ /* Restore ASP TX/RX enable state */
+ regmap_update_bits(regmap,
+ base + CS48L32_ASP_ENABLES1,
+ 0xff00ff,
+ asp_state);
+ return ret;
+}
+
+static const char *cs48l32_dai_clk_str(int clk_id)
+{
+ switch (clk_id) {
+ case CS48L32_CLK_SYSCLK_1:
+ case CS48L32_CLK_SYSCLK_2:
+ case CS48L32_CLK_SYSCLK_3:
+ case CS48L32_CLK_SYSCLK_4:
+ return "SYSCLK";
+ default:
+ return "Unknown clock";
+ }
+}
+
+static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1];
+ unsigned int base = dai->driver->base;
+ unsigned int current_asp_rate, target_asp_rate;
+ bool change_rate_domain = false;
+ int ret;
+
+ if (clk_id == dai_priv->clk)
+ return 0;
+
+ if (snd_soc_dai_active(dai)) {
+ cs48l32_asp_err(dai, "Can't change clock on active DAI\n");
+ return -EBUSY;
+ }
+
+ switch (clk_id) {
+ case CS48L32_CLK_SYSCLK_1:
+ target_asp_rate = 0U << CS48L32_ASP_RATE_SHIFT;
+ break;
+ case CS48L32_CLK_SYSCLK_2:
+ target_asp_rate = 1U << CS48L32_ASP_RATE_SHIFT;
+ break;
+ case CS48L32_CLK_SYSCLK_3:
+ target_asp_rate = 2U << CS48L32_ASP_RATE_SHIFT;
+ break;
+ case CS48L32_CLK_SYSCLK_4:
+ target_asp_rate = 3U << CS48L32_ASP_RATE_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dai_priv->clk = clk_id;
+ cs48l32_asp_dbg(dai, "Setting to %s\n", cs48l32_dai_clk_str(clk_id));
+
+ if (base) {
+ ret = regmap_read(cs48l32_codec->core.regmap,
+ base + CS48L32_ASP_CONTROL1,
+ &current_asp_rate);
+ if (ret != 0) {
+ cs48l32_asp_err(dai, "Failed to check rate: %d\n", ret);
+ return ret;
+ }
+
+ if ((current_asp_rate & CS48L32_ASP_RATE_MASK) !=
+ (target_asp_rate & CS48L32_ASP_RATE_MASK)) {
+ change_rate_domain = true;
+
+ mutex_lock(&cs48l32_codec->rate_lock);
+ /* Guard the rate change with SYSCLK cycles */
+ cs48l32_spin_sysclk(cs48l32_codec);
+ }
+
+ snd_soc_component_update_bits(component, base + CS48L32_ASP_CONTROL1,
+ CS48L32_ASP_RATE_MASK, target_asp_rate);
+
+ if (change_rate_domain) {
+ cs48l32_spin_sysclk(cs48l32_codec);
+ mutex_unlock(&cs48l32_codec->rate_lock);
+ }
+ }
+
+ return 0;
+}
+
+static void cs48l32_set_channels_to_mask(struct snd_soc_dai *dai,
+ unsigned int base,
+ int channels, unsigned int mask)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ int slot, i, j = 0, shift;
+ unsigned int frame_ctls[2] = {0, 0};
+
+ for (i = 0; i < channels; ++i) {
+ slot = ffs(mask) - 1;
+ if (slot < 0)
+ return;
+
+ if (i - (j * 4) >= 4) {
+ ++j;
+ if (j >= 2)
+ break;
+ }
+
+ shift = (8 * (i - j * 4));
+
+ frame_ctls[j] |= slot << shift;
+
+ mask &= ~(1 << slot); /* ? mask ^= 1 << slot ? */
+ }
+
+ regmap_write(regmap, base, frame_ctls[0]);
+ regmap_write(regmap, base + 0x4, frame_ctls[1]);
+
+ if (mask)
+ cs48l32_asp_warn(dai, "Too many channels in TDM mask\n");
+}
+
+static int cs48l32_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ int base = dai->driver->base;
+ int rx_max_chan = dai->driver->playback.channels_max;
+ int tx_max_chan = dai->driver->capture.channels_max;
+
+ /* Only support TDM for the physical ASPs */
+ if (dai->id > CS48L32_MAX_ASP)
+ return -EINVAL;
+
+ if (slots == 0) {
+ tx_mask = (1 << tx_max_chan) - 1;
+ rx_mask = (1 << rx_max_chan) - 1;
+ }
+
+ cs48l32_set_channels_to_mask(dai, base + CS48L32_ASP_FRAME_CONTROL1,
+ tx_max_chan, tx_mask);
+ cs48l32_set_channels_to_mask(dai, base + CS48L32_ASP_FRAME_CONTROL5,
+ rx_max_chan, rx_mask);
+
+ cs48l32_codec->tdm_width[dai->id - 1] = slot_width;
+ cs48l32_codec->tdm_slots[dai->id - 1] = slots;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs48l32_dai_ops = {
+ .probe = &cs48l32_asp_dai_probe,
+ .startup = &cs48l32_startup,
+ .set_fmt = &cs48l32_set_fmt,
+ .set_tdm_slot = &cs48l32_set_tdm_slot,
+ .hw_params = &cs48l32_hw_params,
+ .set_sysclk = &cs48l32_dai_set_sysclk,
+};
+
+static int cs48l32_sysclk_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 cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+
+ cs48l32_spin_sysclk(cs48l32_codec);
+
+ return 0;
+}
+
+static int cs48l32_in_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 cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ unsigned int reg;
+
+ if (w->shift % 2)
+ reg = CS48L32_IN1L_CONTROL2;
+ else
+ reg = CS48L32_IN1R_CONTROL2;
+
+ reg += (w->shift / 2) * (CS48L32_IN2L_CONTROL2 - CS48L32_IN1L_CONTROL2);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (w->shift) {
+ case CS48L32_IN1L_EN_SHIFT:
+ snd_soc_component_update_bits(component,
+ CS48L32_ADC1L_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK);
+ break;
+ case CS48L32_IN1R_EN_SHIFT:
+ snd_soc_component_update_bits(component,
+ CS48L32_ADC1R_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK);
+ break;
+ default:
+ break;
+ }
+ cs48l32_codec->in_up_pending++;
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(200, 300);
+
+ switch (w->shift) {
+ case CS48L32_IN1L_EN_SHIFT:
+ snd_soc_component_update_bits(component,
+ CS48L32_ADC1L_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ 0);
+ break;
+ case CS48L32_IN1R_EN_SHIFT:
+ snd_soc_component_update_bits(component,
+ CS48L32_ADC1R_ANA_CONTROL1,
+ CS48L32_ADC1x_INT_ENA_FRC_MASK,
+ 0);
+ break;
+
+ default:
+ break;
+ }
+ cs48l32_codec->in_up_pending--;
+ snd_soc_component_update_bits(component, reg, CS48L32_INx_MUTE_MASK, 0);
+
+ /* Uncached write-only register, no need for update_bits */
+ if (!cs48l32_codec->in_up_pending) {
+ snd_soc_component_write(component, cs48l32_codec->in_vu_reg,
+ CS48L32_IN_VU_MASK);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_component_update_bits(component, reg,
+ CS48L32_INx_MUTE_MASK, CS48L32_INx_MUTE_MASK);
+ snd_soc_component_write(component, cs48l32_codec->in_vu_reg,
+ CS48L32_IN_VU_MASK);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cs48l32_in_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Uncached write-only register, no need for update_bits.
+ * Will fail if codec is off but that will be handled by cs48l32_in_ev
+ */
+ snd_soc_component_write(component, cs48l32_codec->in_vu_reg, CS48L32_IN_VU);
+
+ return ret;
+}
+
+static bool cs48l32_eq_filter_unstable(bool mode, __be16 in_a, __be16 in_b)
+{
+ s16 a = be16_to_cpu(in_a);
+ s16 b = be16_to_cpu(in_b);
+
+ if (!mode)
+ return abs(a) > CS48L32_EQ_MAX_COEFF;
+
+ if (abs(b) > CS48L32_EQ_MAX_COEFF)
+ return true;
+
+ if (abs((a << 16) / (CS48L32_EQ_MAX_COEFF + 1 - b)) >= ((CS48L32_EQ_MAX_COEFF + 1) << 4))
+ return true;
+
+ return false;
+}
+
+static int cs48l32_eq_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 cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ unsigned int mode = cs48l32_codec->eq_mode[w->shift];
+ unsigned int reg;
+ __be16 *data = &cs48l32_codec->eq_coefficients[w->shift][0];
+ int ret = 0;
+
+ reg = CS48L32_EQ1_BAND1_COEFF1;
+ reg += w->shift * (CS48L32_EQ2_BAND1_COEFF1 - CS48L32_EQ1_BAND1_COEFF1);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (cs48l32_eq_filter_unstable(!!mode, data[1], data[0]) ||
+ cs48l32_eq_filter_unstable(true, data[7], data[6]) ||
+ cs48l32_eq_filter_unstable(true, data[13], data[12]) ||
+ cs48l32_eq_filter_unstable(true, data[19], data[18]) ||
+ cs48l32_eq_filter_unstable(false, data[25], data[24])) {
+ dev_err(cs48l32_codec->core.dev, "Rejecting unstable EQ coefficients.\n");
+ ret = -EINVAL;
+ } else {
+ ret = regmap_raw_write(regmap, reg, data, CS48L32_EQ_BLOCK_SZ);
+ if (ret < 0) {
+ dev_err(cs48l32_codec->core.dev,
+ "Error writing EQ coefficients: %d\n", ret);
+ goto out;
+ }
+
+ ret = snd_soc_component_update_bits(component,
+ CS48L32_EQ_CONTROL2,
+ w->mask,
+ mode << w->shift);
+ if (ret < 0) {
+ dev_err(cs48l32_codec->core.dev,
+ "Error writing EQ mode: %d\n", ret);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+out:
+ return ret;
+}
+
+static const struct snd_kcontrol_new cs48l32_snd_controls[] = {
+SOC_ENUM("IN1 OSR", cs48l32_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", cs48l32_in_dmic_osr[1]),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", CS48L32_IN1L_CONTROL2,
+ CS48L32_INx_PGA_VOL_SHIFT, 0x40, 0x5f, 0, cs48l32_ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", CS48L32_IN1R_CONTROL2,
+ CS48L32_INx_PGA_VOL_SHIFT, 0x40, 0x5f, 0, cs48l32_ana_tlv),
+
+SOC_ENUM("IN HPF Cutoff Frequency", cs48l32_in_hpf_cut_enum),
+
+SOC_SINGLE_EXT("IN1L LP Switch", CS48L32_IN1L_CONTROL1, CS48L32_INx_LP_MODE_SHIFT,
+ 1, 0, snd_soc_get_volsw, cs48l32_low_power_mode_put),
+SOC_SINGLE_EXT("IN1R LP Switch", CS48L32_IN1R_CONTROL1, CS48L32_INx_LP_MODE_SHIFT,
+ 1, 0, snd_soc_get_volsw, cs48l32_low_power_mode_put),
+
+SOC_SINGLE("IN1L HPF Switch", CS48L32_IN1L_CONTROL1, CS48L32_INx_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", CS48L32_IN1R_CONTROL1, CS48L32_INx_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", CS48L32_IN2L_CONTROL1, CS48L32_INx_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", CS48L32_IN2R_CONTROL1, CS48L32_INx_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_EXT_TLV("IN1L Digital Volume", CS48L32_IN1L_CONTROL2,
+ CS48L32_INx_VOL_SHIFT, 0xbf, 0, snd_soc_get_volsw,
+ cs48l32_in_put_volsw, cs48l32_digital_tlv),
+SOC_SINGLE_EXT_TLV("IN1R Digital Volume", CS48L32_IN1R_CONTROL2,
+ CS48L32_INx_VOL_SHIFT, 0xbf, 0, snd_soc_get_volsw,
+ cs48l32_in_put_volsw, cs48l32_digital_tlv),
+SOC_SINGLE_EXT_TLV("IN2L Digital Volume", CS48L32_IN2L_CONTROL2,
+ CS48L32_INx_VOL_SHIFT, 0xbf, 0, snd_soc_get_volsw,
+ cs48l32_in_put_volsw, cs48l32_digital_tlv),
+SOC_SINGLE_EXT_TLV("IN2R Digital Volume", CS48L32_IN2R_CONTROL2,
+ CS48L32_INx_VOL_SHIFT, 0xbf, 0, snd_soc_get_volsw,
+ cs48l32_in_put_volsw, cs48l32_digital_tlv),
+
+SOC_ENUM("Input Ramp Up", cs48l32_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", cs48l32_in_vd_ramp),
+
+CS48L32_RATE_ENUM("Ultrasonic 1 Rate", cs48l32_us_output_rate[0]),
+CS48L32_RATE_ENUM("Ultrasonic 2 Rate", cs48l32_us_output_rate[1]),
+
+SOC_ENUM("Ultrasonic 1 Freq", cs48l32_us_freq[0]),
+SOC_ENUM("Ultrasonic 2 Freq", cs48l32_us_freq[1]),
+
+SOC_SINGLE_TLV("Ultrasonic 1 Volume", CS48L32_US1_CONTROL, CS48L32_US1_GAIN_SHIFT,
+ 3, 0, cs48l32_us_tlv),
+SOC_SINGLE_TLV("Ultrasonic 2 Volume", CS48L32_US2_CONTROL, CS48L32_US1_GAIN_SHIFT,
+ 3, 0, cs48l32_us_tlv),
+
+SOC_ENUM("Ultrasonic 1 Detect Threshold", cs48l32_us_det_thr[0]),
+SOC_ENUM("Ultrasonic 2 Detect Threshold", cs48l32_us_det_thr[1]),
+
+SOC_ENUM("Ultrasonic 1 Detect Pulse Length", cs48l32_us_det_num[0]),
+SOC_ENUM("Ultrasonic 2 Detect Pulse Length", cs48l32_us_det_num[1]),
+
+SOC_ENUM("Ultrasonic 1 Detect Hold", cs48l32_us_det_hold[0]),
+SOC_ENUM("Ultrasonic 2 Detect Hold", cs48l32_us_det_hold[1]),
+
+SOC_ENUM("Ultrasonic 1 Detect Decay", cs48l32_us_det_dcy[0]),
+SOC_ENUM("Ultrasonic 2 Detect Decay", cs48l32_us_det_dcy[1]),
+
+SOC_SINGLE("Ultrasonic 1 Detect LPF Switch",
+ CS48L32_US1_DET_CONTROL, CS48L32_US1_DET_LPF_SHIFT, 1, 0),
+SOC_SINGLE("Ultrasonic 2 Detect LPF Switch",
+ CS48L32_US2_DET_CONTROL, CS48L32_US1_DET_LPF_SHIFT, 1, 0),
+
+SOC_ENUM("Ultrasonic 1 Detect LPF Cut-off", cs48l32_us_det_lpf_cut[0]),
+SOC_ENUM("Ultrasonic 2 Detect LPF Cut-off", cs48l32_us_det_lpf_cut[1]),
+
+CS48L32_MIXER_CONTROLS("EQ1", CS48L32_EQ1_INPUT1),
+CS48L32_MIXER_CONTROLS("EQ2", CS48L32_EQ2_INPUT1),
+CS48L32_MIXER_CONTROLS("EQ3", CS48L32_EQ3_INPUT1),
+CS48L32_MIXER_CONTROLS("EQ4", CS48L32_EQ4_INPUT1),
+
+SOC_ENUM_EXT("EQ1 Mode", cs48l32_eq_mode[0], cs48l32_eq_mode_get, cs48l32_eq_mode_put),
+
+CS48L32_EQ_COEFF_CONTROLS(EQ1),
+
+SOC_SINGLE_TLV("EQ1 B1 Volume", CS48L32_EQ1_GAIN1, 0, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", CS48L32_EQ1_GAIN1, 8, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", CS48L32_EQ1_GAIN1, 16, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", CS48L32_EQ1_GAIN1, 24, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", CS48L32_EQ1_GAIN2, 0, 24, 0, cs48l32_eq_tlv),
+
+SOC_ENUM_EXT("EQ2 Mode", cs48l32_eq_mode[1], cs48l32_eq_mode_get, cs48l32_eq_mode_put),
+CS48L32_EQ_COEFF_CONTROLS(EQ2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", CS48L32_EQ2_GAIN1, 0, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", CS48L32_EQ2_GAIN1, 8, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", CS48L32_EQ2_GAIN1, 16, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", CS48L32_EQ2_GAIN1, 24, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", CS48L32_EQ2_GAIN2, 0, 24, 0, cs48l32_eq_tlv),
+
+SOC_ENUM_EXT("EQ3 Mode", cs48l32_eq_mode[2], cs48l32_eq_mode_get, cs48l32_eq_mode_put),
+CS48L32_EQ_COEFF_CONTROLS(EQ3),
+SOC_SINGLE_TLV("EQ3 B1 Volume", CS48L32_EQ3_GAIN1, 0, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", CS48L32_EQ3_GAIN1, 8, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", CS48L32_EQ3_GAIN1, 16, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", CS48L32_EQ3_GAIN1, 24, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", CS48L32_EQ3_GAIN2, 0, 24, 0, cs48l32_eq_tlv),
+
+SOC_ENUM_EXT("EQ4 Mode", cs48l32_eq_mode[3], cs48l32_eq_mode_get, cs48l32_eq_mode_put),
+CS48L32_EQ_COEFF_CONTROLS(EQ4),
+SOC_SINGLE_TLV("EQ4 B1 Volume", CS48L32_EQ4_GAIN1, 0, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", CS48L32_EQ4_GAIN1, 8, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", CS48L32_EQ4_GAIN1, 16, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", CS48L32_EQ4_GAIN1, 24, 24, 0, cs48l32_eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", CS48L32_EQ4_GAIN2, 0, 24, 0, cs48l32_eq_tlv),
+
+CS48L32_MIXER_CONTROLS("DRC1L", CS48L32_DRC1L_INPUT1),
+CS48L32_MIXER_CONTROLS("DRC1R", CS48L32_DRC1R_INPUT1),
+CS48L32_MIXER_CONTROLS("DRC2L", CS48L32_DRC2L_INPUT1),
+CS48L32_MIXER_CONTROLS("DRC2R", CS48L32_DRC2R_INPUT1),
+
+SND_SOC_BYTES_MASK("DRC1 Coefficients", CS48L32_DRC1_CONTROL1, 4,
+ BIT(CS48L32_DRC1R_EN_SHIFT) | BIT(CS48L32_DRC1L_EN_SHIFT)),
+SND_SOC_BYTES_MASK("DRC2 Coefficients", CS48L32_DRC2_CONTROL1, 4,
+ BIT(CS48L32_DRC1R_EN_SHIFT) | BIT(CS48L32_DRC1L_EN_SHIFT)),
+
+CS48L32_MIXER_CONTROLS("LHPF1", CS48L32_LHPF1_INPUT1),
+CS48L32_MIXER_CONTROLS("LHPF2", CS48L32_LHPF2_INPUT1),
+CS48L32_MIXER_CONTROLS("LHPF3", CS48L32_LHPF3_INPUT1),
+CS48L32_MIXER_CONTROLS("LHPF4", CS48L32_LHPF4_INPUT1),
+
+CS48L32_LHPF_CONTROL("LHPF1 Coefficients", CS48L32_LHPF1_COEFF),
+CS48L32_LHPF_CONTROL("LHPF2 Coefficients", CS48L32_LHPF2_COEFF),
+CS48L32_LHPF_CONTROL("LHPF3 Coefficients", CS48L32_LHPF3_COEFF),
+CS48L32_LHPF_CONTROL("LHPF4 Coefficients", CS48L32_LHPF4_COEFF),
+
+SOC_ENUM("LHPF1 Mode", cs48l32_lhpf_mode[0]),
+SOC_ENUM("LHPF2 Mode", cs48l32_lhpf_mode[1]),
+SOC_ENUM("LHPF3 Mode", cs48l32_lhpf_mode[2]),
+SOC_ENUM("LHPF4 Mode", cs48l32_lhpf_mode[3]),
+
+CS48L32_RATE_CONTROL("Sample Rate 1", 1),
+CS48L32_RATE_CONTROL("Sample Rate 2", 2),
+CS48L32_RATE_CONTROL("Sample Rate 3", 3),
+CS48L32_RATE_CONTROL("Sample Rate 4", 4),
+
+CS48L32_RATE_ENUM("FX Rate", cs48l32_fx_rate),
+
+CS48L32_RATE_ENUM("ISRC1 FSL", cs48l32_isrc_fsl[0]),
+CS48L32_RATE_ENUM("ISRC2 FSL", cs48l32_isrc_fsl[1]),
+CS48L32_RATE_ENUM("ISRC3 FSL", cs48l32_isrc_fsl[2]),
+CS48L32_RATE_ENUM("ISRC1 FSH", cs48l32_isrc_fsh[0]),
+CS48L32_RATE_ENUM("ISRC2 FSH", cs48l32_isrc_fsh[1]),
+CS48L32_RATE_ENUM("ISRC3 FSH", cs48l32_isrc_fsh[2]),
+
+SOC_ENUM("AUXPDM1 Rate", cs48l32_auxpdm1_freq),
+SOC_ENUM("AUXPDM2 Rate", cs48l32_auxpdm2_freq),
+
+SOC_ENUM_EXT("IN1L Rate", cs48l32_input_rate[0], snd_soc_get_enum_double, cs48l32_in_rate_put),
+SOC_ENUM_EXT("IN1R Rate", cs48l32_input_rate[1], snd_soc_get_enum_double, cs48l32_in_rate_put),
+SOC_ENUM_EXT("IN2L Rate", cs48l32_input_rate[2], snd_soc_get_enum_double, cs48l32_in_rate_put),
+SOC_ENUM_EXT("IN2R Rate", cs48l32_input_rate[3], snd_soc_get_enum_double, cs48l32_in_rate_put),
+
+CS48L32_RATE_ENUM("Noise Generator Rate", noise_gen_rate),
+
+SOC_SINGLE_TLV("Noise Generator Volume", CS48L32_COMFORT_NOISE_GENERATOR,
+ CS48L32_NOISE_GEN_GAIN_SHIFT, 0x12, 0, cs48l32_noise_tlv),
+
+CS48L32_MIXER_CONTROLS("ASP1TX1", CS48L32_ASP1TX1_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX2", CS48L32_ASP1TX2_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX3", CS48L32_ASP1TX3_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX4", CS48L32_ASP1TX4_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX5", CS48L32_ASP1TX5_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX6", CS48L32_ASP1TX6_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX7", CS48L32_ASP1TX7_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP1TX8", CS48L32_ASP1TX8_INPUT1),
+
+CS48L32_MIXER_CONTROLS("ASP2TX1", CS48L32_ASP2TX1_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP2TX2", CS48L32_ASP2TX2_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP2TX3", CS48L32_ASP2TX3_INPUT1),
+CS48L32_MIXER_CONTROLS("ASP2TX4", CS48L32_ASP2TX4_INPUT1),
+
+WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
+
+CS48L32_MIXER_CONTROLS("DSP1RX1", CS48L32_DSP1RX1_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX2", CS48L32_DSP1RX2_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX3", CS48L32_DSP1RX3_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX4", CS48L32_DSP1RX4_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX5", CS48L32_DSP1RX5_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX6", CS48L32_DSP1RX6_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX7", CS48L32_DSP1RX7_INPUT1),
+CS48L32_MIXER_CONTROLS("DSP1RX8", CS48L32_DSP1RX8_INPUT1),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+
+CS48L32_DSP_RATE_CONTROL("DSP1RX1", 0),
+CS48L32_DSP_RATE_CONTROL("DSP1RX2", 1),
+CS48L32_DSP_RATE_CONTROL("DSP1RX3", 2),
+CS48L32_DSP_RATE_CONTROL("DSP1RX4", 3),
+CS48L32_DSP_RATE_CONTROL("DSP1RX5", 4),
+CS48L32_DSP_RATE_CONTROL("DSP1RX6", 5),
+CS48L32_DSP_RATE_CONTROL("DSP1RX7", 6),
+CS48L32_DSP_RATE_CONTROL("DSP1RX8", 7),
+CS48L32_DSP_RATE_CONTROL("DSP1TX1", 8),
+CS48L32_DSP_RATE_CONTROL("DSP1TX2", 9),
+CS48L32_DSP_RATE_CONTROL("DSP1TX3", 10),
+CS48L32_DSP_RATE_CONTROL("DSP1TX4", 11),
+CS48L32_DSP_RATE_CONTROL("DSP1TX5", 12),
+CS48L32_DSP_RATE_CONTROL("DSP1TX6", 13),
+CS48L32_DSP_RATE_CONTROL("DSP1TX7", 14),
+CS48L32_DSP_RATE_CONTROL("DSP1TX8", 15),
+};
+
+CS48L32_MIXER_ENUMS(EQ1, CS48L32_EQ1_INPUT1);
+CS48L32_MIXER_ENUMS(EQ2, CS48L32_EQ2_INPUT1);
+CS48L32_MIXER_ENUMS(EQ3, CS48L32_EQ3_INPUT1);
+CS48L32_MIXER_ENUMS(EQ4, CS48L32_EQ4_INPUT1);
+
+CS48L32_MIXER_ENUMS(DRC1L, CS48L32_DRC1L_INPUT1);
+CS48L32_MIXER_ENUMS(DRC1R, CS48L32_DRC1R_INPUT1);
+CS48L32_MIXER_ENUMS(DRC2L, CS48L32_DRC2L_INPUT1);
+CS48L32_MIXER_ENUMS(DRC2R, CS48L32_DRC2R_INPUT1);
+
+CS48L32_MIXER_ENUMS(LHPF1, CS48L32_LHPF1_INPUT1);
+CS48L32_MIXER_ENUMS(LHPF2, CS48L32_LHPF2_INPUT1);
+CS48L32_MIXER_ENUMS(LHPF3, CS48L32_LHPF3_INPUT1);
+CS48L32_MIXER_ENUMS(LHPF4, CS48L32_LHPF4_INPUT1);
+
+CS48L32_MIXER_ENUMS(ASP1TX1, CS48L32_ASP1TX1_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX2, CS48L32_ASP1TX2_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX3, CS48L32_ASP1TX3_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX4, CS48L32_ASP1TX4_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX5, CS48L32_ASP1TX5_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX6, CS48L32_ASP1TX6_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX7, CS48L32_ASP1TX7_INPUT1);
+CS48L32_MIXER_ENUMS(ASP1TX8, CS48L32_ASP1TX8_INPUT1);
+
+CS48L32_MIXER_ENUMS(ASP2TX1, CS48L32_ASP2TX1_INPUT1);
+CS48L32_MIXER_ENUMS(ASP2TX2, CS48L32_ASP2TX2_INPUT1);
+CS48L32_MIXER_ENUMS(ASP2TX3, CS48L32_ASP2TX3_INPUT1);
+CS48L32_MIXER_ENUMS(ASP2TX4, CS48L32_ASP2TX4_INPUT1);
+
+CS48L32_MUX_ENUMS(ISRC1INT1, CS48L32_ISRC1INT1_INPUT1);
+CS48L32_MUX_ENUMS(ISRC1INT2, CS48L32_ISRC1INT2_INPUT1);
+CS48L32_MUX_ENUMS(ISRC1INT3, CS48L32_ISRC1INT3_INPUT1);
+CS48L32_MUX_ENUMS(ISRC1INT4, CS48L32_ISRC1INT4_INPUT1);
+
+CS48L32_MUX_ENUMS(ISRC1DEC1, CS48L32_ISRC1DEC1_INPUT1);
+CS48L32_MUX_ENUMS(ISRC1DEC2, CS48L32_ISRC1DEC2_INPUT1);
+CS48L32_MUX_ENUMS(ISRC1DEC3, CS48L32_ISRC1DEC3_INPUT1);
+CS48L32_MUX_ENUMS(ISRC1DEC4, CS48L32_ISRC1DEC4_INPUT1);
+
+CS48L32_MUX_ENUMS(ISRC2INT1, CS48L32_ISRC2INT1_INPUT1);
+CS48L32_MUX_ENUMS(ISRC2INT2, CS48L32_ISRC2INT2_INPUT1);
+
+CS48L32_MUX_ENUMS(ISRC2DEC1, CS48L32_ISRC2DEC1_INPUT1);
+CS48L32_MUX_ENUMS(ISRC2DEC2, CS48L32_ISRC2DEC2_INPUT1);
+
+CS48L32_MUX_ENUMS(ISRC3INT1, CS48L32_ISRC3INT1_INPUT1);
+CS48L32_MUX_ENUMS(ISRC3INT2, CS48L32_ISRC3INT2_INPUT1);
+
+CS48L32_MUX_ENUMS(ISRC3DEC1, CS48L32_ISRC3DEC1_INPUT1);
+CS48L32_MUX_ENUMS(ISRC3DEC2, CS48L32_ISRC3DEC2_INPUT1);
+
+CS48L32_MIXER_ENUMS(DSP1RX1, CS48L32_DSP1RX1_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX2, CS48L32_DSP1RX2_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX3, CS48L32_DSP1RX3_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX4, CS48L32_DSP1RX4_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX5, CS48L32_DSP1RX5_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX6, CS48L32_DSP1RX6_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX7, CS48L32_DSP1RX7_INPUT1);
+CS48L32_MIXER_ENUMS(DSP1RX8, CS48L32_DSP1RX8_INPUT1);
+
+static int cs48l32_dsp_mem_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 cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ return cs48l32_dsp_memory_enable(cs48l32_codec, &cs48l32_dsp_sram_regs);
+ case SND_SOC_DAPM_PRE_PMD:
+ cs48l32_dsp_memory_disable(cs48l32_codec, &cs48l32_dsp_sram_regs);
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static const struct snd_soc_dapm_widget cs48l32_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", CS48L32_SYSTEM_CLOCK1, CS48L32_SYSCLK_EN_SHIFT, 0,
+ cs48l32_sysclk_ev, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-cp", 20, 0),
+
+SND_SOC_DAPM_SUPPLY("VOUT_MIC", CS48L32_CHARGE_PUMP1, CS48L32_CP2_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("VOUT_MIC_REGULATED", CS48L32_CHARGE_PUMP1, CS48L32_CP2_BYPASS_SHIFT,
+ 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", CS48L32_MICBIAS_CTRL1, CS48L32_MICB1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1A", CS48L32_MICBIAS_CTRL5, CS48L32_MICB1A_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1B", CS48L32_MICBIAS_CTRL5, CS48L32_MICB1B_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1C", CS48L32_MICBIAS_CTRL5, CS48L32_MICB1C_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DSP1MEM", SND_SOC_NOPM, 0, 0, cs48l32_dsp_mem_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+CS48L32_DSP_FREQ_WIDGET_EV("DSP1", 0, cs48l32_dsp_freq_ev),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+
+SND_SOC_DAPM_INPUT("IN1LN_1"),
+SND_SOC_DAPM_INPUT("IN1LN_2"),
+SND_SOC_DAPM_INPUT("IN1LP_1"),
+SND_SOC_DAPM_INPUT("IN1LP_2"),
+SND_SOC_DAPM_INPUT("IN1RN_1"),
+SND_SOC_DAPM_INPUT("IN1RN_2"),
+SND_SOC_DAPM_INPUT("IN1RP_1"),
+SND_SOC_DAPM_INPUT("IN1RP_2"),
+SND_SOC_DAPM_INPUT("IN1_PDMCLK"),
+SND_SOC_DAPM_INPUT("IN1_PDMDATA"),
+
+SND_SOC_DAPM_INPUT("IN2_PDMCLK"),
+SND_SOC_DAPM_INPUT("IN2_PDMDATA"),
+
+SND_SOC_DAPM_MUX("Ultrasonic 1 Input", SND_SOC_NOPM, 0, 0, &cs48l32_us_inmux[0]),
+SND_SOC_DAPM_MUX("Ultrasonic 2 Input", SND_SOC_NOPM, 0, 0, &cs48l32_us_inmux[1]),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
+SND_SOC_DAPM_OUTPUT("DSP Trigger Out"),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &cs48l32_inmux[0]),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &cs48l32_inmux[1]),
+
+SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &cs48l32_dmode_mux[0]),
+SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &cs48l32_dmode_mux[0]),
+
+SND_SOC_DAPM_AIF_OUT("ASP1TX1", NULL, 0, CS48L32_ASP1_ENABLES1, 0, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX2", NULL, 1, CS48L32_ASP1_ENABLES1, 1, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX3", NULL, 2, CS48L32_ASP1_ENABLES1, 2, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX4", NULL, 3, CS48L32_ASP1_ENABLES1, 3, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX5", NULL, 4, CS48L32_ASP1_ENABLES1, 4, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX6", NULL, 5, CS48L32_ASP1_ENABLES1, 5, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX7", NULL, 6, CS48L32_ASP1_ENABLES1, 6, 0),
+SND_SOC_DAPM_AIF_OUT("ASP1TX8", NULL, 7, CS48L32_ASP1_ENABLES1, 7, 0),
+
+SND_SOC_DAPM_AIF_OUT("ASP2TX1", NULL, 0, CS48L32_ASP2_ENABLES1, 0, 0),
+SND_SOC_DAPM_AIF_OUT("ASP2TX2", NULL, 1, CS48L32_ASP2_ENABLES1, 1, 0),
+SND_SOC_DAPM_AIF_OUT("ASP2TX3", NULL, 2, CS48L32_ASP2_ENABLES1, 2, 0),
+SND_SOC_DAPM_AIF_OUT("ASP2TX4", NULL, 3, CS48L32_ASP2_ENABLES1, 3, 0),
+
+SND_SOC_DAPM_SWITCH("AUXPDM1 Output", CS48L32_AUXPDM_CONTROL1, 0, 0, &cs48l32_auxpdm_switch[0]),
+SND_SOC_DAPM_SWITCH("AUXPDM2 Output", CS48L32_AUXPDM_CONTROL1, 1, 0, &cs48l32_auxpdm_switch[1]),
+
+SND_SOC_DAPM_MUX("AUXPDM1 Input", SND_SOC_NOPM, 0, 0, &cs48l32_auxpdm_inmux[0]),
+SND_SOC_DAPM_MUX("AUXPDM2 Input", SND_SOC_NOPM, 0, 0, &cs48l32_auxpdm_inmux[1]),
+
+SND_SOC_DAPM_MUX("AUXPDM1 Analog Input", SND_SOC_NOPM, 0, 0,
+ &cs48l32_auxpdm_analog_inmux[0]),
+SND_SOC_DAPM_MUX("AUXPDM2 Analog Input", SND_SOC_NOPM, 0, 0,
+ &cs48l32_auxpdm_analog_inmux[1]),
+
+SND_SOC_DAPM_SWITCH("Ultrasonic 1 Detect", CS48L32_US_CONTROL,
+ CS48L32_US1_DET_EN_SHIFT, 0, &cs48l32_us_switch[0]),
+SND_SOC_DAPM_SWITCH("Ultrasonic 2 Detect", CS48L32_US_CONTROL,
+ CS48L32_US1_DET_EN_SHIFT, 0, &cs48l32_us_switch[1]),
+
+/*
+ * mux_in widgets : arranged in the order of sources
+ * specified in CS48L32_MIXER_INPUT_ROUTES
+ */
+SND_SOC_DAPM_PGA("Tone Generator 1", CS48L32_TONE_GENERATOR1, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", CS48L32_TONE_GENERATOR1, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", CS48L32_COMFORT_NOISE_GENERATOR,
+ CS48L32_NOISE_GEN_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", CS48L32_INPUT_CONTROL, CS48L32_IN1L_EN_SHIFT,
+ 0, NULL, 0, cs48l32_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", CS48L32_INPUT_CONTROL, CS48L32_IN1R_EN_SHIFT,
+ 0, NULL, 0, cs48l32_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", CS48L32_INPUT_CONTROL, CS48L32_IN2L_EN_SHIFT,
+ 0, NULL, 0, cs48l32_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", CS48L32_INPUT_CONTROL, CS48L32_IN2R_EN_SHIFT,
+ 0, NULL, 0, cs48l32_in_ev,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_AIF_IN("ASP1RX1", NULL, 0, CS48L32_ASP1_ENABLES1, 16, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX2", NULL, 1, CS48L32_ASP1_ENABLES1, 17, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX3", NULL, 2, CS48L32_ASP1_ENABLES1, 18, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX4", NULL, 3, CS48L32_ASP1_ENABLES1, 19, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX5", NULL, 4, CS48L32_ASP1_ENABLES1, 20, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX6", NULL, 5, CS48L32_ASP1_ENABLES1, 21, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX7", NULL, 6, CS48L32_ASP1_ENABLES1, 22, 0),
+SND_SOC_DAPM_AIF_IN("ASP1RX8", NULL, 7, CS48L32_ASP1_ENABLES1, 23, 0),
+
+SND_SOC_DAPM_AIF_IN("ASP2RX1", NULL, 0, CS48L32_ASP2_ENABLES1, 16, 0),
+SND_SOC_DAPM_AIF_IN("ASP2RX2", NULL, 1, CS48L32_ASP2_ENABLES1, 17, 0),
+SND_SOC_DAPM_AIF_IN("ASP2RX3", NULL, 2, CS48L32_ASP2_ENABLES1, 18, 0),
+SND_SOC_DAPM_AIF_IN("ASP2RX4", NULL, 3, CS48L32_ASP2_ENABLES1, 19, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_DEC1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_DEC2_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_DEC3_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_DEC4_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_INT1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_INT2_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_INT3_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", CS48L32_ISRC1_CONTROL2, CS48L32_ISRC1_INT4_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", CS48L32_ISRC2_CONTROL2, CS48L32_ISRC1_DEC1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", CS48L32_ISRC2_CONTROL2, CS48L32_ISRC1_DEC2_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", CS48L32_ISRC2_CONTROL2, CS48L32_ISRC1_INT1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", CS48L32_ISRC2_CONTROL2, CS48L32_ISRC1_INT2_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", CS48L32_ISRC3_CONTROL2, CS48L32_ISRC1_DEC1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", CS48L32_ISRC3_CONTROL2, CS48L32_ISRC1_DEC2_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", CS48L32_ISRC3_CONTROL2, CS48L32_ISRC1_INT1_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", CS48L32_ISRC3_CONTROL2, CS48L32_ISRC1_INT2_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("EQ1", CS48L32_EQ_CONTROL1, 0, 0, NULL, 0, cs48l32_eq_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("EQ2", CS48L32_EQ_CONTROL1, 1, 0, NULL, 0, cs48l32_eq_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("EQ3", CS48L32_EQ_CONTROL1, 2, 0, NULL, 0, cs48l32_eq_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("EQ4", CS48L32_EQ_CONTROL1, 3, 0, NULL, 0, cs48l32_eq_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_PGA("DRC1L", CS48L32_DRC1_CONTROL1, CS48L32_DRC1L_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", CS48L32_DRC1_CONTROL1, CS48L32_DRC1R_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", CS48L32_DRC2_CONTROL1, CS48L32_DRC1L_EN_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", CS48L32_DRC2_CONTROL1, CS48L32_DRC1R_EN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", CS48L32_LHPF_CONTROL1, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", CS48L32_LHPF_CONTROL1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", CS48L32_LHPF_CONTROL1, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", CS48L32_LHPF_CONTROL1, 3, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Ultrasonic 1", CS48L32_US_CONTROL, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Ultrasonic 2", CS48L32_US_CONTROL, 1, 0, NULL, 0),
+
+WM_ADSP2("DSP1", 0, wm_adsp_early_event),
+
+/* end of ordered widget list */
+
+CS48L32_MIXER_WIDGETS(EQ1, "EQ1"),
+CS48L32_MIXER_WIDGETS(EQ2, "EQ2"),
+CS48L32_MIXER_WIDGETS(EQ3, "EQ3"),
+CS48L32_MIXER_WIDGETS(EQ4, "EQ4"),
+
+CS48L32_MIXER_WIDGETS(DRC1L, "DRC1L"),
+CS48L32_MIXER_WIDGETS(DRC1R, "DRC1R"),
+CS48L32_MIXER_WIDGETS(DRC2L, "DRC2L"),
+CS48L32_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+SND_SOC_DAPM_SWITCH("DRC1 Activity Output", SND_SOC_NOPM, 0, 0,
+ &cs48l32_drc_activity_output_mux[0]),
+SND_SOC_DAPM_SWITCH("DRC2 Activity Output", SND_SOC_NOPM, 0, 0,
+ &cs48l32_drc_activity_output_mux[1]),
+
+CS48L32_MIXER_WIDGETS(LHPF1, "LHPF1"),
+CS48L32_MIXER_WIDGETS(LHPF2, "LHPF2"),
+CS48L32_MIXER_WIDGETS(LHPF3, "LHPF3"),
+CS48L32_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+CS48L32_MIXER_WIDGETS(ASP1TX1, "ASP1TX1"),
+CS48L32_MIXER_WIDGETS(ASP1TX2, "ASP1TX2"),
+CS48L32_MIXER_WIDGETS(ASP1TX3, "ASP1TX3"),
+CS48L32_MIXER_WIDGETS(ASP1TX4, "ASP1TX4"),
+CS48L32_MIXER_WIDGETS(ASP1TX5, "ASP1TX5"),
+CS48L32_MIXER_WIDGETS(ASP1TX6, "ASP1TX6"),
+CS48L32_MIXER_WIDGETS(ASP1TX7, "ASP1TX7"),
+CS48L32_MIXER_WIDGETS(ASP1TX8, "ASP1TX8"),
+
+CS48L32_MIXER_WIDGETS(ASP2TX1, "ASP2TX1"),
+CS48L32_MIXER_WIDGETS(ASP2TX2, "ASP2TX2"),
+CS48L32_MIXER_WIDGETS(ASP2TX3, "ASP2TX3"),
+CS48L32_MIXER_WIDGETS(ASP2TX4, "ASP2TX4"),
+
+CS48L32_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+CS48L32_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+CS48L32_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+CS48L32_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+CS48L32_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+CS48L32_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+CS48L32_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+CS48L32_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+CS48L32_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+CS48L32_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+CS48L32_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+CS48L32_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+CS48L32_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+CS48L32_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+
+CS48L32_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+CS48L32_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+
+CS48L32_MIXER_WIDGETS(DSP1RX1, "DSP1RX1"),
+CS48L32_MIXER_WIDGETS(DSP1RX2, "DSP1RX2"),
+CS48L32_MIXER_WIDGETS(DSP1RX3, "DSP1RX3"),
+CS48L32_MIXER_WIDGETS(DSP1RX4, "DSP1RX4"),
+CS48L32_MIXER_WIDGETS(DSP1RX5, "DSP1RX5"),
+CS48L32_MIXER_WIDGETS(DSP1RX6, "DSP1RX6"),
+CS48L32_MIXER_WIDGETS(DSP1RX7, "DSP1RX7"),
+CS48L32_MIXER_WIDGETS(DSP1RX8, "DSP1RX8"),
+
+SND_SOC_DAPM_SWITCH("DSP1 Trigger Output", SND_SOC_NOPM, 0, 0,
+ &cs48l32_dsp_trigger_output_mux[0]),
+
+SND_SOC_DAPM_OUTPUT("AUXPDM1_CLK"),
+SND_SOC_DAPM_OUTPUT("AUXPDM1_DOUT"),
+SND_SOC_DAPM_OUTPUT("AUXPDM2_CLK"),
+SND_SOC_DAPM_OUTPUT("AUXPDM2_DOUT"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+
+SND_SOC_DAPM_OUTPUT("Ultrasonic Dummy Output"),
+};
+
+static const struct snd_soc_dapm_route cs48l32_dapm_routes[] = {
+ { "IN1LN_1", NULL, "SYSCLK" },
+ { "IN1LN_2", NULL, "SYSCLK" },
+ { "IN1LP_1", NULL, "SYSCLK" },
+ { "IN1LP_2", NULL, "SYSCLK" },
+ { "IN1RN_1", NULL, "SYSCLK" },
+ { "IN1RN_2", NULL, "SYSCLK" },
+ { "IN1RP_1", NULL, "SYSCLK" },
+ { "IN1RP_2", NULL, "SYSCLK" },
+
+ { "IN1_PDMCLK", NULL, "SYSCLK" },
+ { "IN1_PDMDATA", NULL, "SYSCLK" },
+ { "IN2_PDMCLK", NULL, "SYSCLK" },
+ { "IN2_PDMDATA", NULL, "SYSCLK" },
+
+ { "DSP1 Preloader", NULL, "DSP1MEM" },
+ { "DSP1", NULL, "DSP1FREQ" },
+
+ { "Audio Trace DSP", NULL, "DSP1" },
+ { "Voice Ctrl DSP", NULL, "DSP1" },
+
+ { "VOUT_MIC_REGULATED", NULL, "VOUT_MIC" },
+ { "MICBIAS1", NULL, "VOUT_MIC_REGULATED" },
+ { "MICBIAS1A", NULL, "MICBIAS1" },
+ { "MICBIAS1B", NULL, "MICBIAS1" },
+ { "MICBIAS1C", NULL, "MICBIAS1" },
+
+ { "Tone Generator 1", NULL, "SYSCLK" },
+ { "Tone Generator 2", NULL, "SYSCLK" },
+ { "Noise Generator", NULL, "SYSCLK" },
+
+ { "Tone Generator 1", NULL, "TONE" },
+ { "Tone Generator 2", NULL, "TONE" },
+ { "Noise Generator", NULL, "NOISE" },
+
+ { "ASP1 Capture", NULL, "ASP1TX1" },
+ { "ASP1 Capture", NULL, "ASP1TX2" },
+ { "ASP1 Capture", NULL, "ASP1TX3" },
+ { "ASP1 Capture", NULL, "ASP1TX4" },
+ { "ASP1 Capture", NULL, "ASP1TX5" },
+ { "ASP1 Capture", NULL, "ASP1TX6" },
+ { "ASP1 Capture", NULL, "ASP1TX7" },
+ { "ASP1 Capture", NULL, "ASP1TX8" },
+
+ { "ASP1RX1", NULL, "ASP1 Playback" },
+ { "ASP1RX2", NULL, "ASP1 Playback" },
+ { "ASP1RX3", NULL, "ASP1 Playback" },
+ { "ASP1RX4", NULL, "ASP1 Playback" },
+ { "ASP1RX5", NULL, "ASP1 Playback" },
+ { "ASP1RX6", NULL, "ASP1 Playback" },
+ { "ASP1RX7", NULL, "ASP1 Playback" },
+ { "ASP1RX8", NULL, "ASP1 Playback" },
+
+ { "ASP2 Capture", NULL, "ASP2TX1" },
+ { "ASP2 Capture", NULL, "ASP2TX2" },
+ { "ASP2 Capture", NULL, "ASP2TX3" },
+ { "ASP2 Capture", NULL, "ASP2TX4" },
+
+ { "ASP2RX1", NULL, "ASP2 Playback" },
+ { "ASP2RX2", NULL, "ASP2 Playback" },
+ { "ASP2RX3", NULL, "ASP2 Playback" },
+ { "ASP2RX4", NULL, "ASP2 Playback" },
+
+ { "ASP1 Playback", NULL, "SYSCLK" },
+ { "ASP2 Playback", NULL, "SYSCLK" },
+
+ { "ASP1 Capture", NULL, "SYSCLK" },
+ { "ASP2 Capture", NULL, "SYSCLK" },
+
+ { "IN1L Mux", "Analog 1", "IN1LN_1" },
+ { "IN1L Mux", "Analog 2", "IN1LN_2" },
+ { "IN1L Mux", "Analog 1", "IN1LP_1" },
+ { "IN1L Mux", "Analog 2", "IN1LP_2" },
+ { "IN1R Mux", "Analog 1", "IN1RN_1" },
+ { "IN1R Mux", "Analog 2", "IN1RN_2" },
+ { "IN1R Mux", "Analog 1", "IN1RP_1" },
+ { "IN1R Mux", "Analog 2", "IN1RP_2" },
+
+ { "IN1L PGA", NULL, "IN1L Mode" },
+ { "IN1R PGA", NULL, "IN1R Mode" },
+
+ { "IN1L Mode", "Analog", "IN1L Mux" },
+ { "IN1R Mode", "Analog", "IN1R Mux" },
+
+ { "IN1L Mode", "Digital", "IN1_PDMCLK" },
+ { "IN1L Mode", "Digital", "IN1_PDMDATA" },
+ { "IN1R Mode", "Digital", "IN1_PDMCLK" },
+ { "IN1R Mode", "Digital", "IN1_PDMDATA" },
+
+ { "IN1L PGA", NULL, "VOUT_MIC" },
+ { "IN1R PGA", NULL, "VOUT_MIC" },
+
+ { "IN2L PGA", NULL, "VOUT_MIC" },
+ { "IN2R PGA", NULL, "VOUT_MIC" },
+
+ { "IN2L PGA", NULL, "IN2_PDMCLK" },
+ { "IN2R PGA", NULL, "IN2_PDMCLK" },
+ { "IN2L PGA", NULL, "IN2_PDMDATA" },
+ { "IN2R PGA", NULL, "IN2_PDMDATA" },
+
+ { "Ultrasonic 1", NULL, "Ultrasonic 1 Input" },
+ { "Ultrasonic 2", NULL, "Ultrasonic 2 Input" },
+
+ { "Ultrasonic 1 Input", "IN1L", "IN1L PGA" },
+ { "Ultrasonic 1 Input", "IN1R", "IN1R PGA" },
+ { "Ultrasonic 1 Input", "IN2L", "IN2L PGA" },
+ { "Ultrasonic 1 Input", "IN2R", "IN2R PGA" },
+
+ { "Ultrasonic 2 Input", "IN1L", "IN1L PGA" },
+ { "Ultrasonic 2 Input", "IN1R", "IN1R PGA" },
+ { "Ultrasonic 2 Input", "IN2L", "IN2L PGA" },
+ { "Ultrasonic 2 Input", "IN2R", "IN2R PGA" },
+
+ { "Ultrasonic 1 Detect", "Switch", "Ultrasonic 1 Input" },
+ { "Ultrasonic 2 Detect", "Switch", "Ultrasonic 2 Input" },
+
+ { "Ultrasonic Dummy Output", NULL, "Ultrasonic 1 Detect" },
+ { "Ultrasonic Dummy Output", NULL, "Ultrasonic 2 Detect" },
+
+ CS48L32_MIXER_ROUTES("ASP1TX1", "ASP1TX1"),
+ CS48L32_MIXER_ROUTES("ASP1TX2", "ASP1TX2"),
+ CS48L32_MIXER_ROUTES("ASP1TX3", "ASP1TX3"),
+ CS48L32_MIXER_ROUTES("ASP1TX4", "ASP1TX4"),
+ CS48L32_MIXER_ROUTES("ASP1TX5", "ASP1TX5"),
+ CS48L32_MIXER_ROUTES("ASP1TX6", "ASP1TX6"),
+ CS48L32_MIXER_ROUTES("ASP1TX7", "ASP1TX7"),
+ CS48L32_MIXER_ROUTES("ASP1TX8", "ASP1TX8"),
+
+ CS48L32_MIXER_ROUTES("ASP2TX1", "ASP2TX1"),
+ CS48L32_MIXER_ROUTES("ASP2TX2", "ASP2TX2"),
+ CS48L32_MIXER_ROUTES("ASP2TX3", "ASP2TX3"),
+ CS48L32_MIXER_ROUTES("ASP2TX4", "ASP2TX4"),
+
+ CS48L32_MIXER_ROUTES("EQ1", "EQ1"),
+ CS48L32_MIXER_ROUTES("EQ2", "EQ2"),
+ CS48L32_MIXER_ROUTES("EQ3", "EQ3"),
+ CS48L32_MIXER_ROUTES("EQ4", "EQ4"),
+
+ CS48L32_MIXER_ROUTES("DRC1L", "DRC1L"),
+ CS48L32_MIXER_ROUTES("DRC1R", "DRC1R"),
+ CS48L32_MIXER_ROUTES("DRC2L", "DRC2L"),
+ CS48L32_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+ CS48L32_MIXER_ROUTES("LHPF1", "LHPF1"),
+ CS48L32_MIXER_ROUTES("LHPF2", "LHPF2"),
+ CS48L32_MIXER_ROUTES("LHPF3", "LHPF3"),
+ CS48L32_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+ CS48L32_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+ CS48L32_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+ CS48L32_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+ CS48L32_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+ CS48L32_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+ CS48L32_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+ CS48L32_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+ CS48L32_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+ CS48L32_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+ CS48L32_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+ CS48L32_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+ CS48L32_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+ CS48L32_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+ CS48L32_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+
+ CS48L32_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+ CS48L32_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+
+ CS48L32_DSP_ROUTES_1_8_SYSCLK("DSP1"),
+
+ { "DSP Trigger Out", NULL, "DSP1 Trigger Output" },
+
+ { "DSP1 Trigger Output", "Switch", "DSP1" },
+
+ { "AUXPDM1 Analog Input", "IN1L", "IN1L PGA" },
+ { "AUXPDM1 Analog Input", "IN1R", "IN1R PGA" },
+
+ { "AUXPDM2 Analog Input", "IN1L", "IN1L PGA" },
+ { "AUXPDM2 Analog Input", "IN1R", "IN1R PGA" },
+
+ { "AUXPDM1 Input", "Analog", "AUXPDM1 Analog Input" },
+ { "AUXPDM1 Input", "IN1 Digital", "IN1L PGA" },
+ { "AUXPDM1 Input", "IN1 Digital", "IN1R PGA" },
+ { "AUXPDM1 Input", "IN2 Digital", "IN2L PGA" },
+ { "AUXPDM1 Input", "IN2 Digital", "IN2R PGA" },
+
+ { "AUXPDM2 Input", "Analog", "AUXPDM2 Analog Input" },
+ { "AUXPDM2 Input", "IN1 Digital", "IN1L PGA" },
+ { "AUXPDM2 Input", "IN1 Digital", "IN1R PGA" },
+ { "AUXPDM2 Input", "IN2 Digital", "IN2L PGA" },
+ { "AUXPDM2 Input", "IN2 Digital", "IN2R PGA" },
+
+ { "AUXPDM1 Output", "Switch", "AUXPDM1 Input" },
+ { "AUXPDM1_CLK", NULL, "AUXPDM1 Output" },
+ { "AUXPDM1_DOUT", NULL, "AUXPDM1 Output" },
+
+ { "AUXPDM2 Output", "Switch", "AUXPDM2 Input" },
+ { "AUXPDM2_CLK", NULL, "AUXPDM2 Output" },
+ { "AUXPDM2_DOUT", NULL, "AUXPDM2 Output" },
+
+ { "MICSUPP", NULL, "SYSCLK" },
+
+ { "DRC1 Signal Activity", NULL, "DRC1 Activity Output" },
+ { "DRC2 Signal Activity", NULL, "DRC2 Activity Output" },
+ { "DRC1 Activity Output", "Switch", "DRC1L" },
+ { "DRC1 Activity Output", "Switch", "DRC1R" },
+ { "DRC2 Activity Output", "Switch", "DRC2L" },
+ { "DRC2 Activity Output", "Switch", "DRC2R" },
+};
+
+static int cs48l32_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs48l32-dsp-trace") &&
+ strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "cs48l32-dsp-voicectrl")) {
+ dev_err(cs48l32_codec->core.dev, "No suitable compressed stream for DAI '%s'\n",
+ snd_soc_rtd_to_codec(rtd, 0)->name);
+ return -EINVAL;
+ }
+
+ return wm_adsp_compr_open(&cs48l32_codec->dsp, stream);
+}
+
+static const struct snd_compress_ops cs48l32_compress_ops = {
+ .open = &cs48l32_compr_open,
+ .free = &wm_adsp_compr_free,
+ .set_params = &wm_adsp_compr_set_params,
+ .get_caps = &wm_adsp_compr_get_caps,
+ .trigger = &wm_adsp_compr_trigger,
+ .pointer = &wm_adsp_compr_pointer,
+ .copy = &wm_adsp_compr_copy,
+};
+
+static const struct snd_soc_dai_ops cs48l32_compress_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
+static struct snd_soc_dai_driver cs48l32_dai[] = {
+ {
+ .name = "cs48l32-asp1",
+ .id = 1,
+ .base = CS48L32_ASP1_ENABLES1,
+ .playback = {
+ .stream_name = "ASP1 Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASP1 Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ .ops = &cs48l32_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+ {
+ .name = "cs48l32-asp2",
+ .id = 2,
+ .base = CS48L32_ASP2_ENABLES1,
+ .playback = {
+ .stream_name = "ASP2 Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASP2 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ .ops = &cs48l32_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+ {
+ .name = "cs48l32-cpu-trace",
+ .id = 3,
+ .capture = {
+ .stream_name = "Audio Trace CPU",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ .ops = &cs48l32_compress_dai_ops,
+ },
+ {
+ .name = "cs48l32-dsp-trace",
+ .id = 4,
+ .capture = {
+ .stream_name = "Audio Trace DSP",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ },
+ {
+ .name = "cs48l32-cpu-voicectrl",
+ .id = 5,
+ .capture = {
+ .stream_name = "Voice Ctrl CPU",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ .ops = &cs48l32_compress_dai_ops,
+ },
+ {
+ .name = "cs48l32-dsp-voicectrl",
+ .id = 6,
+ .capture = {
+ .stream_name = "Voice Ctrl DSP",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = CS48L32_RATES,
+ .formats = CS48L32_FORMATS,
+ },
+ },
+};
+
+static int cs48l32_init_inputs(struct snd_soc_component *component)
+{
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ unsigned int ana_mode_l, ana_mode_r, dig_mode;
+ int i;
+
+ /*
+ * Initialize input modes from the A settings. For muxed inputs the
+ * B settings will be applied if the mux is changed
+ */
+ switch (cs48l32_codec->in_type[0][0]) {
+ default:
+ case CS48L32_IN_TYPE_DIFF:
+ ana_mode_l = 0;
+ break;
+ case CS48L32_IN_TYPE_SE:
+ ana_mode_l = 1 << CS48L32_INx_SRC_SHIFT;
+ break;
+ }
+
+ switch (cs48l32_codec->in_type[1][0]) {
+ default:
+ case CS48L32_IN_TYPE_DIFF:
+ ana_mode_r = 0;
+ break;
+ case CS48L32_IN_TYPE_SE:
+ ana_mode_r = 1 << CS48L32_INx_SRC_SHIFT;
+ break;
+ }
+
+ dev_dbg(cs48l32_codec->core.dev, "IN1_1 Analogue mode=#%x,#%x\n",
+ ana_mode_l, ana_mode_r);
+
+ regmap_update_bits(regmap,
+ CS48L32_IN1L_CONTROL1,
+ CS48L32_INx_SRC_MASK,
+ ana_mode_l);
+
+ regmap_update_bits(regmap,
+ CS48L32_IN1R_CONTROL1,
+ CS48L32_INx_SRC_MASK,
+ ana_mode_r);
+
+ for (i = 0; i < ARRAY_SIZE(cs48l32_codec->pdm_sup); i++) {
+ dig_mode = cs48l32_codec->pdm_sup[i] << CS48L32_IN1_PDM_SUP_SHIFT;
+
+ dev_dbg(cs48l32_codec->core.dev, "IN%d PDM_SUP=#%x\n", i + 1, dig_mode);
+
+ regmap_update_bits(regmap,
+ CS48L32_INPUT1_CONTROL1 + (i * 0x40),
+ CS48L32_IN1_PDM_SUP_MASK, dig_mode);
+ }
+
+ return 0;
+}
+
+static int cs48l32_init_dai(struct cs48l32_codec *cs48l32_codec, int id)
+{
+ struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[id];
+
+ dai_priv->clk = CS48L32_CLK_SYSCLK_1;
+ dai_priv->constraint = cs48l32_constraint;
+
+ return 0;
+}
+
+static int cs48l32_init_eq(struct cs48l32_codec *cs48l32_codec)
+{
+ struct regmap *regmap = cs48l32_codec->core.regmap;
+ unsigned int reg = CS48L32_EQ1_BAND1_COEFF1, mode;
+ __be16 *data;
+ int i, ret;
+
+ ret = regmap_read(regmap, CS48L32_EQ_CONTROL2, &mode);
+ if (ret < 0) {
+ dev_err(cs48l32_codec->core.dev, "Error reading EQ mode: %d\n", ret);
+ goto out;
+ }
+
+ for (i = 0; i < 4; ++i) {
+ cs48l32_codec->eq_mode[i] = (mode >> i) & 0x1;
+
+ data = &cs48l32_codec->eq_coefficients[i][0];
+ ret = regmap_raw_read(regmap, reg + (i * 68), data,
+ CS48L32_EQ_BLOCK_SZ);
+ if (ret < 0) {
+ dev_err(cs48l32_codec->core.dev,
+ "Error reading EQ coefficients: %d\n", ret);
+ goto out;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static int cs48l32_component_probe(struct snd_soc_component *component)
+{
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+ int i, ret;
+
+ snd_soc_component_init_regmap(component, cs48l32_codec->core.regmap);
+
+ ret = cs48l32_init_inputs(component);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cs48l32_dai); i++)
+ cs48l32_init_dai(cs48l32_codec, i);
+
+ ret = cs48l32_init_eq(cs48l32_codec);
+ if (ret)
+ return ret;
+
+ wm_adsp2_component_probe(&cs48l32_codec->dsp, component);
+
+ /* Unmask DSP IRQs */
+ regmap_clear_bits(cs48l32_codec->core.regmap, CS48L32_IRQ1_MASK_7,
+ CS48L32_DSP1_MPU_ERR_EINT1_MASK | CS48L32_DSP1_WDT_EXPIRE_EINT1_MASK);
+ regmap_clear_bits(cs48l32_codec->core.regmap, CS48L32_IRQ1_MASK_9,
+ CS48L32_DSP1_IRQ0_EINT1_MASK);
+
+ return 0;
+}
+
+static void cs48l32_component_remove(struct snd_soc_component *component)
+{
+ struct cs48l32_codec *cs48l32_codec = snd_soc_component_get_drvdata(component);
+
+ /* Mask DSP IRQs */
+ regmap_set_bits(cs48l32_codec->core.regmap, CS48L32_IRQ1_MASK_7,
+ CS48L32_DSP1_MPU_ERR_EINT1_MASK | CS48L32_DSP1_WDT_EXPIRE_EINT1_MASK);
+ regmap_set_bits(cs48l32_codec->core.regmap, CS48L32_IRQ1_MASK_9,
+ CS48L32_DSP1_IRQ0_EINT1_MASK);
+
+ wm_adsp2_component_remove(&cs48l32_codec->dsp, component);
+}
+
+static const struct snd_soc_component_driver cs48l32_soc_component_drv = {
+ .probe = &cs48l32_component_probe,
+ .remove = &cs48l32_component_remove,
+ .set_sysclk = &cs48l32_set_sysclk,
+ .set_pll = &cs48l32_set_fll,
+ .name = "cs48l32-codec",
+ .compress_ops = &cs48l32_compress_ops,
+ .controls = cs48l32_snd_controls,
+ .num_controls = ARRAY_SIZE(cs48l32_snd_controls),
+ .dapm_widgets = cs48l32_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs48l32_dapm_widgets),
+ .dapm_routes = cs48l32_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs48l32_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int cs48l32_prop_read_u32_array(struct cs48l32_codec *cs48l32_codec,
+ const char *propname,
+ u32 *dest,
+ int n_max)
+{
+ struct cs48l32 *cs48l32 = &cs48l32_codec->core;
+ int ret;
+
+ ret = device_property_read_u32_array(cs48l32->dev, propname, dest, n_max);
+ if (ret == -EINVAL)
+ return -ENOENT;
+
+ if (ret < 0)
+ return dev_err_probe(cs48l32->dev, ret, "%s malformed\n", propname);
+
+ return 0;
+}
+
+static void cs48l32_prop_get_in_type(struct cs48l32_codec *cs48l32_codec)
+{
+ const char *propname = "cirrus,in-type";
+ u32 tmp[CS48L32_MAX_ANALOG_INPUT * CS48L32_MAX_IN_MUX_WAYS];
+ int i, in_idx, mux_way_idx, ret;
+
+ static_assert(ARRAY_SIZE(tmp) ==
+ ARRAY_SIZE(cs48l32_codec->in_type) * ARRAY_SIZE(cs48l32_codec->in_type[0]));
+
+ ret = cs48l32_prop_read_u32_array(cs48l32_codec, propname, tmp, ARRAY_SIZE(tmp));
+ if (ret < 0)
+ return;
+
+ in_idx = 0;
+ mux_way_idx = 0;
+ for (i = 0; i < ARRAY_SIZE(tmp); ++i) {
+ switch (tmp[i]) {
+ case CS48L32_IN_TYPE_DIFF:
+ case CS48L32_IN_TYPE_SE:
+ cs48l32_codec->in_type[in_idx][mux_way_idx] = tmp[i];
+ break;
+ default:
+ dev_warn(cs48l32_codec->core.dev, "Illegal %s value %d ignored\n",
+ propname, tmp[i]);
+ break;
+ }
+
+ /*
+ * Property array is [mux_way][in_channel]. Swap to
+ * [in_channel][mux_way] for convenience.
+ */
+ if (++in_idx == ARRAY_SIZE(cs48l32_codec->in_type)) {
+ in_idx = 0;
+ ++mux_way_idx;
+ }
+ }
+}
+
+static void cs48l32_prop_get_pdm_sup(struct cs48l32_codec *cs48l32_codec)
+{
+ const char *propname = "cirrus,pdm-sup";
+ u32 tmp[CS48L32_MAX_ANALOG_INPUT];
+ int i;
+
+ static_assert(ARRAY_SIZE(tmp) == ARRAY_SIZE(cs48l32_codec->pdm_sup));
+
+ cs48l32_prop_read_u32_array(cs48l32_codec, propname, tmp, ARRAY_SIZE(tmp));
+
+ for (i = 0; i < ARRAY_SIZE(cs48l32_codec->pdm_sup); i++) {
+ switch (tmp[i]) {
+ case CS48L32_PDM_SUP_VOUT_MIC:
+ case CS48L32_PDM_SUP_MICBIAS1:
+ cs48l32_codec->pdm_sup[i] = tmp[i];
+ break;
+ default:
+ dev_warn(cs48l32_codec->core.dev, "Illegal %s value %d ignored\n",
+ propname, cs48l32_codec->pdm_sup[i]);
+ break;
+ }
+ }
+}
+
+static void cs48l32_handle_properties(struct cs48l32_codec *cs48l32_codec)
+{
+ cs48l32_prop_get_in_type(cs48l32_codec);
+ cs48l32_prop_get_pdm_sup(cs48l32_codec);
+}
+
+static int cs48l32_request_interrupt(struct cs48l32_codec *cs48l32_codec)
+{
+ int irq = cs48l32_codec->core.irq;
+ int ret;
+
+ if (irq < 1)
+ return 0;
+
+ /*
+ * Don't use devm because this must be freed before destroying the
+ * rest of the driver
+ */
+ ret = request_threaded_irq(irq, NULL, cs48l32_irq,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "cs48l32", cs48l32_codec);
+ if (ret)
+ return dev_err_probe(cs48l32_codec->core.dev, ret, "Failed to get IRQ\n");
+
+ return 0;
+}
+
+static int cs48l32_create_codec_component(struct cs48l32_codec *cs48l32_codec)
+{
+ struct wm_adsp *dsp;
+ int ret;
+
+ ASSERT_STRUCT_OFFSET(struct cs48l32_codec, dsp, 0);
+ static_assert(ARRAY_SIZE(cs48l32_dai) == ARRAY_SIZE(cs48l32_codec->dai));
+
+ cs48l32_handle_properties(cs48l32_codec);
+
+ dsp = &cs48l32_codec->dsp;
+ dsp->part = "cs48l32";
+ dsp->cs_dsp.num = 1;
+ dsp->cs_dsp.type = WMFW_HALO;
+ dsp->cs_dsp.rev = 0;
+ dsp->cs_dsp.dev = cs48l32_codec->core.dev;
+ dsp->cs_dsp.regmap = cs48l32_codec->core.regmap;
+ dsp->cs_dsp.base = CS48L32_DSP1_CLOCK_FREQ;
+ dsp->cs_dsp.base_sysinfo = CS48L32_DSP1_SYS_INFO_ID;
+ dsp->cs_dsp.mem = cs48l32_dsp1_regions;
+ dsp->cs_dsp.num_mems = ARRAY_SIZE(cs48l32_dsp1_regions);
+ dsp->pre_run = cs48l32_dsp_pre_run;
+
+ ret = wm_halo_init(dsp);
+ if (ret != 0)
+ return ret;
+
+ cs48l32_codec->fll.codec = cs48l32_codec;
+ cs48l32_codec->fll.id = 1;
+ cs48l32_codec->fll.base = CS48L32_FLL1_CONTROL1;
+ cs48l32_codec->fll.sts_addr = CS48L32_IRQ1_STS_6;
+ cs48l32_codec->fll.sts_mask = CS48L32_FLL1_LOCK_STS1_MASK;
+ cs48l32_init_fll(&cs48l32_codec->fll);
+
+ ret = cs48l32_request_interrupt(cs48l32_codec);
+ if (ret)
+ goto err_dsp;
+
+ ret = devm_snd_soc_register_component(cs48l32_codec->core.dev,
+ &cs48l32_soc_component_drv,
+ cs48l32_dai,
+ ARRAY_SIZE(cs48l32_dai));
+ if (ret < 0) {
+ dev_err_probe(cs48l32_codec->core.dev, ret, "Failed to register component\n");
+ goto err_dsp;
+ }
+
+ return 0;
+
+err_dsp:
+ wm_adsp2_remove(&cs48l32_codec->dsp);
+
+ return ret;
+}
+
+static int cs48l32_wait_for_boot(struct cs48l32 *cs48l32)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read_poll_timeout(cs48l32->regmap, CS48L32_IRQ1_EINT_2, val,
+ ((val < 0xffffffff) && (val & CS48L32_BOOT_DONE_EINT1_MASK)),
+ 1000, CS48L32_BOOT_TIMEOUT_US);
+ if (ret) {
+ dev_err(cs48l32->dev, "BOOT_DONE timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ ret = regmap_read(cs48l32->regmap, CS48L32_MCU_CTRL1, &val);
+ if (ret) {
+ dev_err(cs48l32->dev, "Failed to read MCU_CTRL1: %d\n", ret);
+ return ret;
+ }
+
+ if (val & BIT(CS48L32_MCU_STS_SHIFT)) {
+ dev_err(cs48l32->dev, "MCU boot failed\n");
+ return -EIO;
+ }
+
+ pm_runtime_mark_last_busy(cs48l32->dev);
+
+ return 0;
+}
+
+static int cs48l32_soft_reset(struct cs48l32 *cs48l32)
+{
+ int ret;
+
+ ret = regmap_write(cs48l32->regmap, CS48L32_SFT_RESET, CS48L32_SFT_RESET_MAGIC);
+ if (ret != 0) {
+ dev_err(cs48l32->dev, "Failed to write soft reset: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(CS48L32_SOFT_RESET_US, CS48L32_SOFT_RESET_US + 1000);
+
+ return 0;
+}
+
+static void cs48l32_enable_hard_reset(struct cs48l32 *cs48l32)
+{
+ if (cs48l32->reset_gpio)
+ gpiod_set_raw_value_cansleep(cs48l32->reset_gpio, 0);
+}
+
+static void cs48l32_disable_hard_reset(struct cs48l32 *cs48l32)
+{
+ if (cs48l32->reset_gpio) {
+ gpiod_set_raw_value_cansleep(cs48l32->reset_gpio, 1);
+ usleep_range(CS48L32_HARD_RESET_MIN_US, CS48L32_HARD_RESET_MIN_US + 1000);
+ }
+}
+
+static int cs48l32_runtime_resume(struct device *dev)
+{
+ struct cs48l32_codec *cs48l32_codec = dev_get_drvdata(dev);
+ struct cs48l32 *cs48l32 = &cs48l32_codec->core;
+ unsigned int val;
+ int ret;
+
+ ret = regulator_enable(cs48l32->vdd_d);
+ if (ret) {
+ dev_err(cs48l32->dev, "Failed to enable VDD_D: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(CS48L32_SOFT_RESET_US, CS48L32_SOFT_RESET_US + 1000);
+
+ regcache_cache_only(cs48l32->regmap, false);
+
+ ret = cs48l32_wait_for_boot(cs48l32);
+ if (ret)
+ goto err;
+
+ /* Check whether registers reset during suspend */
+ regmap_read(cs48l32->regmap, CS48L32_CTRL_IF_DEBUG3, &val);
+ if (!val)
+ regcache_mark_dirty(cs48l32->regmap);
+ else
+ dev_dbg(cs48l32->dev, "Did not reset during suspend\n");
+
+ ret = regcache_sync(cs48l32->regmap);
+ if (ret) {
+ dev_err(cs48l32->dev, "Failed to restore register cache\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regcache_cache_only(cs48l32->regmap, true);
+ regulator_disable(cs48l32->vdd_d);
+
+ return ret;
+}
+
+static int cs48l32_runtime_suspend(struct device *dev)
+{
+ struct cs48l32_codec *cs48l32_codec = dev_get_drvdata(dev);
+ struct cs48l32 *cs48l32 = &cs48l32_codec->core;
+
+ /* Flag to detect if the registers reset during suspend */
+ regmap_write(cs48l32->regmap, CS48L32_CTRL_IF_DEBUG3, 1);
+
+ regcache_cache_only(cs48l32->regmap, true);
+ regulator_disable(cs48l32->vdd_d);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cs48l32_pm_ops = {
+ RUNTIME_PM_OPS(cs48l32_runtime_suspend, cs48l32_runtime_resume, NULL)
+};
+
+static int cs48l32_configure_clk32k(struct cs48l32 *cs48l32)
+{
+ int ret = 0;
+
+ ret = clk_prepare_enable(cs48l32->mclk1);
+ if (ret)
+ return dev_err_probe(cs48l32->dev, ret, "Failed to enable 32k clock\n");
+
+ ret = regmap_update_bits(cs48l32->regmap, CS48L32_CLOCK32K,
+ CS48L32_CLK_32K_EN_MASK | CS48L32_CLK_32K_SRC_MASK,
+ CS48L32_CLK_32K_EN_MASK | CS48L32_32K_MCLK1);
+ if (ret) {
+ clk_disable_unprepare(cs48l32->mclk1);
+ return dev_err_probe(cs48l32->dev, ret, "Failed to init 32k clock\n");
+ }
+
+ return 0;
+}
+
+static int cs48l32_get_clocks(struct cs48l32 *cs48l32)
+{
+ cs48l32->mclk1 = devm_clk_get_optional(cs48l32->dev, "mclk1");
+ if (IS_ERR(cs48l32->mclk1))
+ return dev_err_probe(cs48l32->dev, PTR_ERR(cs48l32->mclk1),
+ "Failed to get mclk1\n");
+
+ return 0;
+}
+
+static int cs48l32_get_reset_gpio(struct cs48l32 *cs48l32)
+{
+ struct gpio_desc *reset;
+
+ reset = devm_gpiod_get_optional(cs48l32->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset))
+ return dev_err_probe(cs48l32->dev, PTR_ERR(reset), "Failed to request /RESET\n");
+
+ /* ACPI can override the GPIOD_OUT_LOW so ensure it starts low */
+ gpiod_set_raw_value_cansleep(reset, 0);
+
+ cs48l32->reset_gpio = reset;
+
+ return 0;
+}
+
+static int cs48l32_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct cs48l32_codec *cs48l32_codec;
+ struct cs48l32 *cs48l32;
+ unsigned int hwid, rev, otp_rev;
+ int i, ret;
+
+ cs48l32_codec = devm_kzalloc(&spi->dev, sizeof(*cs48l32_codec), GFP_KERNEL);
+ if (!cs48l32_codec)
+ return -ENOMEM;
+
+ cs48l32 = &cs48l32_codec->core;
+ cs48l32->dev = dev;
+ cs48l32->irq = spi->irq;
+ mutex_init(&cs48l32_codec->rate_lock);
+ cs48l32_codec->in_vu_reg = CS48L32_INPUT_CONTROL3;
+
+ dev_set_drvdata(cs48l32->dev, cs48l32_codec);
+
+ ret = cs48l32_create_regmap(spi, cs48l32);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "Failed to allocate regmap\n");
+
+ regcache_cache_only(cs48l32->regmap, true);
+
+ ret = cs48l32_get_reset_gpio(cs48l32);
+ if (ret)
+ return ret;
+
+ ret = cs48l32_get_clocks(cs48l32);
+ if (ret)
+ return ret;
+
+ static_assert(ARRAY_SIZE(cs48l32_core_supplies) == ARRAY_SIZE(cs48l32->core_supplies));
+ for (i = 0; i < ARRAY_SIZE(cs48l32->core_supplies); i++)
+ cs48l32->core_supplies[i].supply = cs48l32_core_supplies[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs48l32->core_supplies),
+ cs48l32->core_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request core supplies\n");
+
+ cs48l32->vdd_d = devm_regulator_get(cs48l32->dev, "vdd-d");
+ if (IS_ERR(cs48l32->vdd_d))
+ return dev_err_probe(dev, PTR_ERR(cs48l32->vdd_d), "Failed to request vdd-d\n");
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs48l32->core_supplies), cs48l32->core_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable core supplies\n");
+
+ ret = regulator_enable(cs48l32->vdd_d);
+ if (ret) {
+ dev_err(dev, "Failed to enable vdd-d: %d\n", ret);
+ goto err_enable;
+ }
+
+ cs48l32_disable_hard_reset(cs48l32);
+
+ regcache_cache_only(cs48l32->regmap, false);
+
+ /* If we don't have a reset GPIO use a soft reset */
+ if (!cs48l32->reset_gpio) {
+ ret = cs48l32_soft_reset(cs48l32);
+ if (ret)
+ goto err_reset;
+ }
+
+ ret = cs48l32_wait_for_boot(cs48l32);
+ if (ret) {
+ dev_err(cs48l32->dev, "Device failed initial boot: %d\n", ret);
+ goto err_reset;
+ }
+
+ ret = regmap_read(cs48l32->regmap, CS48L32_DEVID, &hwid);
+ if (ret) {
+ dev_err(dev, "Failed to read ID register: %d\n", ret);
+ goto err_reset;
+ }
+ hwid &= CS48L32_DEVID_MASK;
+
+ switch (hwid) {
+ case CS48L32_SILICON_ID:
+ break;
+ default:
+ ret = -ENODEV;
+ dev_err_probe(cs48l32->dev, ret, "Unknown device ID: %#x\n", hwid);
+ goto err_reset;
+ }
+
+ ret = regmap_read(cs48l32->regmap, CS48L32_REVID, &rev);
+ if (ret) {
+ dev_err(dev, "Failed to read revision register: %d\n", ret);
+ goto err_reset;
+ }
+ rev &= CS48L32_AREVID_MASK | CS48L32_MTLREVID_MASK;
+
+ ret = regmap_read(cs48l32->regmap, CS48L32_OTPID, &otp_rev);
+ if (ret) {
+ dev_err(dev, "Failed to read OTP revision register: %d\n", ret);
+ goto err_reset;
+ }
+ otp_rev &= CS48L32_OTPID_MASK;
+
+ dev_info(dev, "CS48L%x revision %X%u OTP%u\n", hwid & 0xff,
+ rev >> CS48L32_AREVID_SHIFT, rev & CS48L32_MTLREVID_MASK, otp_rev);
+
+ /* Apply hardware patch */
+ ret = cs48l32_apply_patch(cs48l32);
+ if (ret) {
+ dev_err(cs48l32->dev, "Failed to apply patch %d\n", ret);
+ goto err_reset;
+ }
+
+ /* BOOT_DONE interrupt is unmasked by default, so mask it */
+ ret = regmap_set_bits(cs48l32->regmap, CS48L32_IRQ1_MASK_2, CS48L32_BOOT_DONE_EINT1_MASK);
+
+ ret = cs48l32_configure_clk32k(cs48l32);
+ if (ret)
+ goto err_reset;
+
+ pm_runtime_set_active(cs48l32->dev);
+ pm_runtime_set_autosuspend_delay(cs48l32->dev, 100);
+ pm_runtime_use_autosuspend(cs48l32->dev);
+ pm_runtime_enable(cs48l32->dev);
+
+ ret = cs48l32_create_codec_component(cs48l32_codec);
+ if (ret)
+ goto err_clk32k;
+
+ return 0;
+
+err_clk32k:
+ clk_disable_unprepare(cs48l32->mclk1);
+err_reset:
+ cs48l32_enable_hard_reset(cs48l32);
+ regulator_disable(cs48l32->vdd_d);
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(cs48l32->core_supplies), cs48l32->core_supplies);
+
+ return ret;
+}
+
+static void cs48l32_spi_remove(struct spi_device *spi)
+{
+ struct cs48l32_codec *cs48l32_codec = spi_get_drvdata(spi);
+ struct cs48l32 *cs48l32 = &cs48l32_codec->core;
+
+ /* Remove IRQ handler before destroying anything else */
+ if (cs48l32->irq >= 1)
+ free_irq(cs48l32->irq, cs48l32_codec);
+
+ pm_runtime_disable(cs48l32->dev);
+ regulator_disable(cs48l32->vdd_d);
+ clk_disable_unprepare(cs48l32->mclk1);
+ cs48l32_enable_hard_reset(cs48l32);
+ regulator_bulk_disable(ARRAY_SIZE(cs48l32->core_supplies), cs48l32->core_supplies);
+
+ mutex_destroy(&cs48l32_codec->rate_lock);
+}
+
+static const struct of_device_id cs48l32_of_match[] = {
+ { .compatible = "cirrus,cs48l32", },
+ {},
+};
+
+static const struct spi_device_id cs48l32_spi_ids[] = {
+ { "cs48l32", },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, cs48l32_spi_ids);
+
+static struct spi_driver cs48l32_spi_driver = {
+ .driver = {
+ .name = "cs48l32",
+ .pm = pm_ptr(&cs48l32_pm_ops),
+ .of_match_table = cs48l32_of_match,
+ },
+ .probe = &cs48l32_spi_probe,
+ .remove = &cs48l32_spi_remove,
+ .id_table = cs48l32_spi_ids,
+};
+module_spi_driver(cs48l32_spi_driver);
+
+MODULE_DESCRIPTION("CS48L32 ASoC codec driver");
+MODULE_AUTHOR("Stuart Henderson <stuarth@opensource.cirrus.com>");
+MODULE_AUTHOR("Piotr Stankiewicz <piotrs@opensource.cirrus.com>");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs48l32.h b/sound/soc/codecs/cs48l32.h
new file mode 100644
index 000000000000..c1b4e13feae4
--- /dev/null
+++ b/sound/soc/codecs/cs48l32.h
@@ -0,0 +1,403 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Cirrus Logic CS48L32 audio DSP.
+ *
+ * Copyright (C) 2016-2018, 2020, 2022, 2025 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+#ifndef SND_SOC_CS48L32_H
+#define SND_SOC_CS48L32_H
+
+#include <linux/bits.h>
+#include <sound/soc.h>
+#include "wm_adsp.h"
+
+#define CS48L32_SILICON_ID 0x48a32
+
+#define CS48L32_32K_MCLK1 0
+
+#define CS48L32_SFT_RESET_MAGIC 0x5a000000
+#define CS48L32_SOFT_RESET_US 2000
+#define CS48L32_HARD_RESET_MIN_US 1000
+
+#define CS48L32_SEEN_BOOT_DONE BIT(0)
+#define CS48L32_BOOT_TIMEOUT_US 25000
+
+#define CS48L32_ASP_ENABLES1 0x00
+#define CS48L32_ASP_CONTROL1 0x04
+#define CS48L32_ASP_CONTROL2 0x08
+#define CS48L32_ASP_CONTROL3 0x0c
+#define CS48L32_ASP_FRAME_CONTROL1 0x10
+#define CS48L32_ASP_FRAME_CONTROL2 0x14
+#define CS48L32_ASP_FRAME_CONTROL5 0x20
+#define CS48L32_ASP_FRAME_CONTROL6 0x24
+#define CS48L32_ASP_DATA_CONTROL1 0x30
+#define CS48L32_ASP_DATA_CONTROL5 0x40
+#define CS48L32_SYSCLK_RATE_6MHZ 0
+#define CS48L32_SYSCLK_RATE_12MHZ 1
+#define CS48L32_SYSCLK_RATE_24MHZ 2
+#define CS48L32_SYSCLK_RATE_49MHZ 3
+#define CS48L32_SYSCLK_RATE_98MHZ 4
+#define CS48L32_FLLHJ_INT_MAX_N 1023
+#define CS48L32_FLLHJ_INT_MIN_N 1
+#define CS48L32_FLLHJ_FRAC_MAX_N 255
+#define CS48L32_FLLHJ_FRAC_MIN_N 2
+#define CS48L32_FLLHJ_LP_INT_MODE_THRESH 100000
+#define CS48L32_FLLHJ_LOW_THRESH 192000
+#define CS48L32_FLLHJ_MID_THRESH 1152000
+#define CS48L32_FLLHJ_MAX_THRESH 13000000
+#define CS48L32_FLLHJ_LOW_GAINS 0x23f0
+#define CS48L32_FLLHJ_MID_GAINS 0x22f2
+#define CS48L32_FLLHJ_HIGH_GAINS 0x21f0
+#define CS48L32_FLL_MAX_FOUT 50000000
+#define CS48L32_FLL_MAX_REFDIV 8
+#define CS48L32_FLL_CONTROL1_OFFS 0x00
+#define CS48L32_FLL_CONTROL2_OFFS 0x04
+#define CS48L32_FLL_CONTROL3_OFFS 0x08
+#define CS48L32_FLL_CONTROL4_OFFS 0x0c
+#define CS48L32_FLL_CONTROL5_OFFS 0x10
+#define CS48L32_FLL_CONTROL6_OFFS 0x14
+#define CS48L32_FLL_DIGITAL_TEST2_OFFS 0x34
+#define CS48L32_FLL_GPIO_CLOCK_OFFS 0xa0
+#define CS48L32_DSP_CLOCK_FREQ_OFFS 0x00000
+#define CS48L32_ASP_FMT_DSP_MODE_A 0
+#define CS48L32_ASP_FMT_DSP_MODE_B 1
+#define CS48L32_ASP_FMT_I2S_MODE 2
+#define CS48L32_ASP_FMT_LEFT_JUSTIFIED_MODE 3
+#define CS48L32_HALO_SAMPLE_RATE_RX1 0x00080
+#define CS48L32_HALO_SAMPLE_RATE_TX1 0x00280
+#define CS48L32_HALO_DSP_RATE_MASK 0x1f
+
+#define CS48L32_PDMCLK_SRC_IN1_PDMCLK 0x0
+#define CS48L32_PDMCLK_SRC_IN2_PDMCLK 0x1
+#define CS48L32_PDMCLK_SRC_IN3_PDMCLK 0x2
+#define CS48L32_PDMCLK_SRC_IN4_PDMCLK 0x3
+#define CS48L32_PDMCLK_SRC_AUXPDM1_CLK 0x8
+#define CS48L32_PDMCLK_SRC_AUXPDM2_CLK 0x9
+
+#define CS48L32_MAX_DAI 6
+#define CS48L32_MAX_INPUT 4
+#define CS48L32_MAX_ANALOG_INPUT 2
+#define CS48L32_MAX_IN_MUX_WAYS 2
+#define CS48L32_MAX_ASP 2
+
+#define CS48L32_EQ_BLOCK_SZ 60
+#define CS48L32_N_EQ_BLOCKS 4
+
+#define CS48L32_DSP_N_RX_CHANNELS 8
+#define CS48L32_DSP_N_TX_CHANNELS 8
+
+#define CS48L32_LHPF_MAX_COEFF 4095
+#define CS48L32_EQ_MAX_COEFF 4095
+
+#define CS48L32_MIXER_CONTROLS(name, base) \
+ SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base, \
+ CS48L32_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs48l32_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name " Input 2 Volume", base + 4, \
+ CS48L32_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs48l32_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name " Input 3 Volume", base + 8, \
+ CS48L32_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs48l32_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name " Input 4 Volume", base + 12, \
+ CS48L32_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs48l32_mixer_tlv)
+
+#define CS48L32_MUX_ENUM_DECL(name, reg) \
+ SOC_VALUE_ENUM_SINGLE_DECL( \
+ name, reg, 0, CS48L32_MIXER_SRC_MASK, \
+ cs48l32_mixer_texts, cs48l32_mixer_values)
+
+#define CS48L32_MUX_CTL_DECL(name) \
+ const struct snd_kcontrol_new name##_mux = SOC_DAPM_ENUM("Route", name##_enum)
+
+#define CS48L32_MUX_ENUMS(name, base_reg) \
+ static CS48L32_MUX_ENUM_DECL(name##_enum, base_reg); \
+ static CS48L32_MUX_CTL_DECL(name)
+
+#define CS48L32_MIXER_ENUMS(name, base_reg) \
+ CS48L32_MUX_ENUMS(name##_in1, base_reg); \
+ CS48L32_MUX_ENUMS(name##_in2, base_reg + 4); \
+ CS48L32_MUX_ENUMS(name##_in3, base_reg + 8); \
+ CS48L32_MUX_ENUMS(name##_in4, base_reg + 12)
+
+#define CS48L32_MUX(name, ctrl) SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define CS48L32_MUX_WIDGETS(name, name_str) CS48L32_MUX(name_str " Input 1", &name##_mux)
+
+#define CS48L32_MIXER_WIDGETS(name, name_str) \
+ CS48L32_MUX(name_str " Input 1", &name##_in1_mux), \
+ CS48L32_MUX(name_str " Input 2", &name##_in2_mux), \
+ CS48L32_MUX(name_str " Input 3", &name##_in3_mux), \
+ CS48L32_MUX(name_str " Input 4", &name##_in4_mux), \
+ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define CS48L32_MUX_ROUTES(widget, name) \
+ { widget, NULL, name " Input 1" }, \
+ CS48L32_MIXER_INPUT_ROUTES(name " Input 1")
+
+#define CS48L32_MIXER_ROUTES(widget, name) \
+ { widget, NULL, name " Mixer" }, \
+ { name " Mixer", NULL, name " Input 1" }, \
+ { name " Mixer", NULL, name " Input 2" }, \
+ { name " Mixer", NULL, name " Input 3" }, \
+ { name " Mixer", NULL, name " Input 4" }, \
+ CS48L32_MIXER_INPUT_ROUTES(name " Input 1"), \
+ CS48L32_MIXER_INPUT_ROUTES(name " Input 2"), \
+ CS48L32_MIXER_INPUT_ROUTES(name " Input 3"), \
+ CS48L32_MIXER_INPUT_ROUTES(name " Input 4")
+
+#define CS48L32_DSP_ROUTES_1_8_SYSCLK(name) \
+ { name, NULL, name " Preloader" }, \
+ { name, NULL, "SYSCLK" }, \
+ { name " Preload", NULL, name " Preloader" }, \
+ CS48L32_MIXER_ROUTES(name, name "RX1"), \
+ CS48L32_MIXER_ROUTES(name, name "RX2"), \
+ CS48L32_MIXER_ROUTES(name, name "RX3"), \
+ CS48L32_MIXER_ROUTES(name, name "RX4"), \
+ CS48L32_MIXER_ROUTES(name, name "RX5"), \
+ CS48L32_MIXER_ROUTES(name, name "RX6"), \
+ CS48L32_MIXER_ROUTES(name, name "RX7"), \
+ CS48L32_MIXER_ROUTES(name, name "RX8") \
+
+#define CS48L32_DSP_ROUTES_1_8(name) \
+ { name, NULL, "DSPCLK" }, \
+ CS48L32_DSP_ROUTES_1_8_SYSCLK(name) \
+
+#define CS48L32_RATE_CONTROL(name, domain) SOC_ENUM(name, cs48l32_sample_rate[(domain) - 1])
+
+#define CS48L32_RATE_ENUM(name, enum) \
+ SOC_ENUM_EXT(name, enum, snd_soc_get_enum_double, cs48l32_rate_put)
+
+#define CS48L32_DSP_RATE_CONTROL(name, num) \
+ SOC_ENUM_EXT(name " Rate", cs48l32_dsp_rate_enum[num], \
+ cs48l32_dsp_rate_get, cs48l32_dsp_rate_put)
+
+#define CS48L32_EQ_COEFF_CONTROL(xname, xreg, xbase, xshift) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = cs48l32_eq_coeff_info, .get = cs48l32_eq_coeff_get, \
+ .put = cs48l32_eq_coeff_put, .private_value = \
+ (unsigned long)&(struct cs48l32_eq_control) { .reg = xreg,\
+ .shift = xshift, .block_base = xbase, .max = 65535 } }
+
+#define CS48L32_EQ_REG_NAME_PASTER(eq, band, type) \
+ CS48L32_ ## eq ## _ ## band ## _ ## type
+
+#define CS48L32_EQ_BAND_COEFF_CONTROLS(name, band) \
+ CS48L32_EQ_COEFF_CONTROL(#name " " #band " A", \
+ CS48L32_EQ_REG_NAME_PASTER(name, band, COEFF1), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 0), \
+ CS48L32_EQ_COEFF_CONTROL(#name " " #band " B", \
+ CS48L32_EQ_REG_NAME_PASTER(name, band, COEFF1), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 16), \
+ CS48L32_EQ_COEFF_CONTROL(#name " " #band " C", \
+ CS48L32_EQ_REG_NAME_PASTER(name, band, COEFF2), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 0), \
+ CS48L32_EQ_COEFF_CONTROL(#name " " #band " PG", \
+ CS48L32_EQ_REG_NAME_PASTER(name, band, PG), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 0)
+
+#define CS48L32_EQ_COEFF_CONTROLS(name) \
+ CS48L32_EQ_BAND_COEFF_CONTROLS(name, BAND1), \
+ CS48L32_EQ_BAND_COEFF_CONTROLS(name, BAND2), \
+ CS48L32_EQ_BAND_COEFF_CONTROLS(name, BAND3), \
+ CS48L32_EQ_BAND_COEFF_CONTROLS(name, BAND4), \
+ CS48L32_EQ_COEFF_CONTROL(#name " BAND5 A", \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND5, COEFF1), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 0), \
+ CS48L32_EQ_COEFF_CONTROL(#name " BAND5 B", \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND5, COEFF1), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 16), \
+ CS48L32_EQ_COEFF_CONTROL(#name " BAND5 PG", \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND5, PG), \
+ CS48L32_EQ_REG_NAME_PASTER(name, BAND1, COEFF1), \
+ 0)
+
+#define CS48L32_LHPF_CONTROL(xname, xbase) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+ .put = cs48l32_lhpf_coeff_put, .private_value = \
+ ((unsigned long)&(struct soc_bytes) { .base = xbase, \
+ .num_regs = 1 }) }
+
+/* these have a subseq number so they run after SYSCLK and DSPCLK widgets */
+#define CS48L32_DSP_FREQ_WIDGET_EV(name, num, event) \
+ SND_SOC_DAPM_SUPPLY_S(name "FREQ", 100, SND_SOC_NOPM, num, 0, \
+ event, SND_SOC_DAPM_POST_PMU)
+
+#define CS48L32_RATES SNDRV_PCM_RATE_KNOT
+
+#define CS48L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CS48L32_MIXER_INPUT_ROUTES(name) \
+ { name, "Tone Generator 1", "Tone Generator 1" }, \
+ { name, "Tone Generator 2", "Tone Generator 2" }, \
+ { name, "Noise Generator", "Noise Generator" }, \
+ { name, "IN1L", "IN1L PGA" }, \
+ { name, "IN1R", "IN1R PGA" }, \
+ { name, "IN2L", "IN2L PGA" }, \
+ { name, "IN2R", "IN2R PGA" }, \
+ { name, "ASP1RX1", "ASP1RX1" }, \
+ { name, "ASP1RX2", "ASP1RX2" }, \
+ { name, "ASP1RX3", "ASP1RX3" }, \
+ { name, "ASP1RX4", "ASP1RX4" }, \
+ { name, "ASP1RX5", "ASP1RX5" }, \
+ { name, "ASP1RX6", "ASP1RX6" }, \
+ { name, "ASP1RX7", "ASP1RX7" }, \
+ { name, "ASP1RX8", "ASP1RX8" }, \
+ { name, "ASP2RX1", "ASP2RX1" }, \
+ { name, "ASP2RX2", "ASP2RX2" }, \
+ { name, "ASP2RX3", "ASP2RX3" }, \
+ { name, "ASP2RX4", "ASP2RX4" }, \
+ { name, "ISRC1DEC1", "ISRC1DEC1" }, \
+ { name, "ISRC1DEC2", "ISRC1DEC2" }, \
+ { name, "ISRC1DEC3", "ISRC1DEC3" }, \
+ { name, "ISRC1DEC4", "ISRC1DEC4" }, \
+ { name, "ISRC1INT1", "ISRC1INT1" }, \
+ { name, "ISRC1INT2", "ISRC1INT2" }, \
+ { name, "ISRC1INT3", "ISRC1INT3" }, \
+ { name, "ISRC1INT4", "ISRC1INT4" }, \
+ { name, "ISRC2DEC1", "ISRC2DEC1" }, \
+ { name, "ISRC2DEC2", "ISRC2DEC2" }, \
+ { name, "ISRC2INT1", "ISRC2INT1" }, \
+ { name, "ISRC2INT2", "ISRC2INT2" }, \
+ { name, "ISRC3DEC1", "ISRC3DEC1" }, \
+ { name, "ISRC3DEC2", "ISRC3DEC2" }, \
+ { name, "ISRC3INT1", "ISRC3INT1" }, \
+ { name, "ISRC3INT2", "ISRC3INT2" }, \
+ { name, "EQ1", "EQ1" }, \
+ { name, "EQ2", "EQ2" }, \
+ { name, "EQ3", "EQ3" }, \
+ { name, "EQ4", "EQ4" }, \
+ { name, "DRC1L", "DRC1L" }, \
+ { name, "DRC1R", "DRC1R" }, \
+ { name, "DRC2L", "DRC2L" }, \
+ { name, "DRC2R", "DRC2R" }, \
+ { name, "LHPF1", "LHPF1" }, \
+ { name, "LHPF2", "LHPF2" }, \
+ { name, "LHPF3", "LHPF3" }, \
+ { name, "LHPF4", "LHPF4" }, \
+ { name, "Ultrasonic 1", "Ultrasonic 1" }, \
+ { name, "Ultrasonic 2", "Ultrasonic 2" }, \
+ { name, "DSP1.1", "DSP1" }, \
+ { name, "DSP1.2", "DSP1" }, \
+ { name, "DSP1.3", "DSP1" }, \
+ { name, "DSP1.4", "DSP1" }, \
+ { name, "DSP1.5", "DSP1" }, \
+ { name, "DSP1.6", "DSP1" }, \
+ { name, "DSP1.7", "DSP1" }, \
+ { name, "DSP1.8", "DSP1" }
+
+struct cs48l32_enum {
+ struct soc_enum mixer_enum;
+ int val;
+};
+
+struct cs48l32_eq_control {
+ unsigned int reg;
+ unsigned int shift;
+ unsigned int block_base;
+ unsigned int max;
+};
+
+struct cs48l32_dai_priv {
+ int clk;
+ struct snd_pcm_hw_constraint_list constraint;
+};
+
+struct cs48l32_dsp_power_reg_block {
+ unsigned int start;
+ unsigned int end;
+};
+
+struct cs48l32_dsp_power_regs {
+ const unsigned int *pwd;
+ unsigned int n_pwd;
+ const struct cs48l32_dsp_power_reg_block *ext;
+ unsigned int n_ext;
+};
+
+struct cs48l32;
+struct cs48l32_codec;
+struct spi_device;
+
+struct cs48l32_fll_cfg {
+ int n;
+ unsigned int theta;
+ unsigned int lambda;
+ int refdiv;
+ int fratio;
+ int gain;
+ int alt_gain;
+};
+
+struct cs48l32_fll {
+ struct cs48l32_codec *codec;
+ int id;
+ unsigned int base;
+
+ unsigned int sts_addr;
+ unsigned int sts_mask;
+ unsigned int fout;
+ int ref_src;
+ unsigned int ref_freq;
+
+ struct cs48l32_fll_cfg ref_cfg;
+};
+
+struct cs48l32_codec {
+ struct wm_adsp dsp; /* must be first */
+ struct cs48l32 core;
+ int sysclk;
+ int dspclk;
+ struct cs48l32_dai_priv dai[CS48L32_MAX_DAI];
+ struct cs48l32_fll fll;
+
+ unsigned int in_up_pending;
+ unsigned int in_vu_reg;
+
+ struct mutex rate_lock;
+
+ u8 dsp_dma_rates[CS48L32_DSP_N_RX_CHANNELS + CS48L32_DSP_N_TX_CHANNELS];
+
+ u8 in_type[CS48L32_MAX_ANALOG_INPUT][CS48L32_MAX_IN_MUX_WAYS];
+ u8 pdm_sup[CS48L32_MAX_ANALOG_INPUT];
+ u8 tdm_width[CS48L32_MAX_ASP];
+ u8 tdm_slots[CS48L32_MAX_ASP];
+
+ unsigned int eq_mode[CS48L32_N_EQ_BLOCKS];
+ __be16 eq_coefficients[CS48L32_N_EQ_BLOCKS][CS48L32_EQ_BLOCK_SZ / 2];
+
+ const struct cs48l32_dsp_power_regs *dsp_power_regs;
+};
+
+#define cs48l32_fll_err(_fll, fmt, ...) \
+ dev_err(_fll->codec->core.dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+#define cs48l32_fll_warn(_fll, fmt, ...) \
+ dev_warn(_fll->codec->core.dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+#define cs48l32_fll_dbg(_fll, fmt, ...) \
+ dev_dbg(_fll->codec->core.dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+
+#define cs48l32_asp_err(_dai, fmt, ...) \
+ dev_err(_dai->component->dev, "ASP%d: " fmt, _dai->id, ##__VA_ARGS__)
+#define cs48l32_asp_warn(_dai, fmt, ...) \
+ dev_warn(_dai->component->dev, "ASP%d: " fmt, _dai->id, ##__VA_ARGS__)
+#define cs48l32_asp_dbg(_dai, fmt, ...) \
+ dev_dbg(_dai->component->dev, "ASP%d: " fmt, _dai->id, ##__VA_ARGS__)
+
+int cs48l32_apply_patch(struct cs48l32 *cs48l32);
+int cs48l32_create_regmap(struct spi_device *spi, struct cs48l32 *cs48l32);
+int cs48l32_enable_asp1_pins(struct cs48l32_codec *cs48l32_codec);
+int cs48l32_enable_asp2_pins(struct cs48l32_codec *cs48l32_codec);
+int cs48l32_micvdd_voltage_index(u32 voltage);
+int cs48l32_micbias1_voltage_index(u32 voltage);
+
+#endif
diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c
new file mode 100644
index 000000000000..52b02ceaa7e3
--- /dev/null
+++ b/sound/soc/codecs/cs530x-i2c.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2024-2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include "cs530x.h"
+
+static const struct of_device_id cs530x_of_match[] = {
+ {
+ .compatible = "cirrus,cs4282",
+ .data = (void *)CS4282,
+ }, {
+ .compatible = "cirrus,cs4302",
+ .data = (void *)CS4302,
+ }, {
+ .compatible = "cirrus,cs4304",
+ .data = (void *)CS4304,
+ }, {
+ .compatible = "cirrus,cs4308",
+ .data = (void *)CS4308,
+ }, {
+ .compatible = "cirrus,cs5302",
+ .data = (void *)CS5302,
+ }, {
+ .compatible = "cirrus,cs5304",
+ .data = (void *)CS5304,
+ }, {
+ .compatible = "cirrus,cs5308",
+ .data = (void *)CS5308,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs530x_of_match);
+
+static const struct i2c_device_id cs530x_i2c_id[] = {
+ { "cs4282", CS4282 },
+ { "cs4302", CS4302 },
+ { "cs4304", CS4304 },
+ { "cs4308", CS4308 },
+ { "cs5302", CS5302 },
+ { "cs5304", CS5304 },
+ { "cs5308", CS5308 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs530x_i2c_id);
+
+static int cs530x_i2c_probe(struct i2c_client *client)
+{
+ struct cs530x_priv *cs530x;
+
+ cs530x = devm_kzalloc(&client->dev, sizeof(*cs530x), GFP_KERNEL);
+ if (!cs530x)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, cs530x);
+
+ cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap_i2c);
+ if (IS_ERR(cs530x->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap),
+ "Failed to allocate register map\n");
+
+ cs530x->devtype = (uintptr_t)i2c_get_match_data(client);
+ cs530x->dev = &client->dev;
+
+ return cs530x_probe(cs530x);
+}
+
+static struct i2c_driver cs530x_i2c_driver = {
+ .driver = {
+ .name = "cs530x",
+ .of_match_table = cs530x_of_match,
+ },
+ .probe = cs530x_i2c_probe,
+ .id_table = cs530x_i2c_id,
+};
+module_i2c_driver(cs530x_i2c_driver);
+
+MODULE_DESCRIPTION("I2C CS530X driver");
+MODULE_IMPORT_NS("SND_SOC_CS530X");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paulha@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x-spi.c b/sound/soc/codecs/cs530x-spi.c
new file mode 100644
index 000000000000..dbf1e7bbec19
--- /dev/null
+++ b/sound/soc/codecs/cs530x-spi.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include "cs530x.h"
+
+static const struct of_device_id cs530x_of_match[] = {
+ {
+ .compatible = "cirrus,cs4282",
+ .data = (void *)CS4282,
+ }, {
+ .compatible = "cirrus,cs4302",
+ .data = (void *)CS4302,
+ }, {
+ .compatible = "cirrus,cs4304",
+ .data = (void *)CS4304,
+ }, {
+ .compatible = "cirrus,cs4308",
+ .data = (void *)CS4308,
+ }, {
+ .compatible = "cirrus,cs5302",
+ .data = (void *)CS5302,
+ }, {
+ .compatible = "cirrus,cs5304",
+ .data = (void *)CS5304,
+ }, {
+ .compatible = "cirrus,cs5304",
+ .data = (void *)CS5308,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs530x_of_match);
+
+static const struct spi_device_id cs530x_spi_id[] = {
+ { "cs4282", CS4282 },
+ { "cs4302", CS4302 },
+ { "cs4304", CS4304 },
+ { "cs4308", CS4308 },
+ { "cs5302", CS5302 },
+ { "cs5304", CS5304 },
+ { "cs5308", CS5308 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, cs530x_spi_id);
+
+static int cs530x_spi_probe(struct spi_device *spi)
+{
+ struct cs530x_priv *cs530x;
+ struct device *dev = &spi->dev;
+ int ret;
+
+ cs530x = devm_kzalloc(dev, sizeof(struct cs530x_priv), GFP_KERNEL);
+ if (cs530x == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, cs530x);
+
+ cs530x->regmap = devm_regmap_init_spi(spi, &cs530x_regmap_spi);
+ if (IS_ERR(cs530x->regmap)) {
+ ret = PTR_ERR(cs530x->regmap);
+ dev_err(dev, "Failed to allocate register map: %d\n", ret);
+ return ret;
+ }
+
+ cs530x->devtype = (unsigned long)spi_get_device_match_data(spi);
+ cs530x->dev = &spi->dev;
+
+ return cs530x_probe(cs530x);
+}
+
+static struct spi_driver cs530x_spi_driver = {
+ .driver = {
+ .name = "cs530x",
+ .of_match_table = cs530x_of_match,
+ },
+ .id_table = cs530x_spi_id,
+ .probe = cs530x_spi_probe,
+};
+
+module_spi_driver(cs530x_spi_driver);
+
+MODULE_DESCRIPTION("SPI CS530X driver");
+MODULE_IMPORT_NS("SND_SOC_CS530X");
+MODULE_AUTHOR("Vitaly Rodionov <vitalyr@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
new file mode 100644
index 000000000000..18b5ff75feec
--- /dev/null
+++ b/sound/soc/codecs/cs530x.c
@@ -0,0 +1,1343 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS530x CODEC driver
+//
+// Copyright (C) 2024-2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs530x.h"
+
+static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = {
+ "vdd-a",
+ "vdd-io",
+};
+
+static const struct reg_default cs530x_reg_defaults[] = {
+ { CS530X_CLK_CFG_0, 0x30 },
+ { CS530X_CLK_CFG_1, 0x0001 },
+ { CS530X_CHIP_ENABLE, 0 },
+ { CS530X_ASP_CFG, 0 },
+ { CS530X_SIGNAL_PATH_CFG, 0 },
+ { CS530X_IN_ENABLES, 0 },
+ { CS530X_IN_RAMP_SUM, 0x0022 },
+ { CS530X_IN_FILTER, 0 },
+ { CS530X_IN_HIZ, 0 },
+ { CS530X_IN_INV, 0 },
+ { CS530X_IN_VOL_CTRL1_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL1_1, 0x8000 },
+ { CS530X_IN_VOL_CTRL2_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL2_1, 0x8000 },
+ { CS530X_IN_VOL_CTRL3_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL3_1, 0x8000 },
+ { CS530X_IN_VOL_CTRL4_0, 0x8000 },
+ { CS530X_IN_VOL_CTRL4_1, 0x8000 },
+ { CS530X_OUT_ENABLES, 0 },
+ { CS530X_OUT_RAMP_SUM, 0x0022 },
+ { CS530X_OUT_FILTER, 0 },
+ { CS530X_OUT_INV, 0 },
+ { CS530X_OUT_VOL_CTRL1_0, 0x8000 },
+ { CS530X_OUT_VOL_CTRL1_1, 0x8000 },
+ { CS530X_OUT_VOL_CTRL2_0, 0x8000 },
+ { CS530X_OUT_VOL_CTRL2_1, 0x8000 },
+ { CS530X_OUT_VOL_CTRL3_0, 0x8000 },
+ { CS530X_OUT_VOL_CTRL3_1, 0x8000 },
+ { CS530X_OUT_VOL_CTRL4_0, 0x8000 },
+ { CS530X_OUT_VOL_CTRL4_1, 0x8000 },
+ { CS530X_PAD_FN, 0 },
+ { CS530X_PAD_LVL, 0 },
+};
+
+static bool cs530x_read_and_write_regs(unsigned int reg)
+{
+ switch (reg) {
+ case CS530X_CLK_CFG_0:
+ case CS530X_CLK_CFG_1:
+ case CS530X_CHIP_ENABLE:
+ case CS530X_ASP_CFG:
+ case CS530X_SIGNAL_PATH_CFG:
+ case CS530X_IN_ENABLES:
+ case CS530X_IN_RAMP_SUM:
+ case CS530X_IN_FILTER:
+ case CS530X_IN_HIZ:
+ case CS530X_IN_INV:
+ case CS530X_IN_VOL_CTRL1_0:
+ case CS530X_IN_VOL_CTRL1_1:
+ case CS530X_IN_VOL_CTRL2_0:
+ case CS530X_IN_VOL_CTRL2_1:
+ case CS530X_IN_VOL_CTRL3_0:
+ case CS530X_IN_VOL_CTRL3_1:
+ case CS530X_IN_VOL_CTRL4_0:
+ case CS530X_IN_VOL_CTRL4_1:
+ case CS530X_OUT_ENABLES:
+ case CS530X_OUT_RAMP_SUM:
+ case CS530X_OUT_DEEMPH:
+ case CS530X_OUT_FILTER:
+ case CS530X_OUT_INV:
+ case CS530X_OUT_VOL_CTRL1_0:
+ case CS530X_OUT_VOL_CTRL1_1:
+ case CS530X_OUT_VOL_CTRL2_0:
+ case CS530X_OUT_VOL_CTRL2_1:
+ case CS530X_OUT_VOL_CTRL3_0:
+ case CS530X_OUT_VOL_CTRL3_1:
+ case CS530X_OUT_VOL_CTRL4_0:
+ case CS530X_OUT_VOL_CTRL4_1:
+ case CS530X_PAD_FN:
+ case CS530X_PAD_LVL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs530x_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS530X_DEVID:
+ case CS530X_REVID:
+ return true;
+ default:
+ return cs530x_read_and_write_regs(reg);
+ }
+}
+
+static bool cs530x_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS530X_SW_RESET:
+ case CS530X_IN_VOL_CTRL5:
+ case CS530X_OUT_VOL_CTRL5:
+ return true;
+ default:
+ return cs530x_read_and_write_regs(reg);
+ }
+}
+
+static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret)
+ goto volsw_err;
+
+ /* Write INOUT_VU bit for the volume change to take effect */
+ regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_INOUT_VU);
+
+volsw_err:
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0);
+
+static const char * const cs530x_inout_filter_text[] = {
+ "Min Phase Slow Roll-off",
+ "Min Phase Fast Roll-off",
+ "Linear Phase Slow Roll-off",
+ "Linear Phase Fast Roll-off",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_filter_enum, CS530X_IN_FILTER,
+ CS530X_INOUT_FILTER_SHIFT,
+ cs530x_inout_filter_text);
+
+static SOC_ENUM_SINGLE_DECL(cs530x_out_filter_enum, CS530X_OUT_FILTER,
+ CS530X_INOUT_FILTER_SHIFT,
+ cs530x_inout_filter_text);
+
+static const char * const cs530x_4ch_sum_text[] = {
+ "None",
+ "Groups of 2",
+ "Groups of 4",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM,
+ CS530X_INOUT_SUM_MODE_SHIFT,
+ cs530x_4ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = {
+SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum),
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch4_enum, CS530X_OUT_RAMP_SUM,
+ CS530X_INOUT_SUM_MODE_SHIFT,
+ cs530x_4ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_out_sum_4ch_controls[] = {
+SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch4_enum),
+};
+
+static const char * const cs530x_8ch_sum_text[] = {
+ "None",
+ "Groups of 2",
+ "Groups of 4",
+ "Groups of 8",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM,
+ CS530X_INOUT_SUM_MODE_SHIFT,
+ cs530x_8ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = {
+SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum),
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_out_sum_ch8_enum, CS530X_OUT_RAMP_SUM,
+ CS530X_INOUT_SUM_MODE_SHIFT,
+ cs530x_8ch_sum_text);
+
+static const struct snd_kcontrol_new cs530x_out_sum_8ch_controls[] = {
+SOC_ENUM("OUT Sum Select", cs530x_out_sum_ch8_enum),
+};
+
+static const char * const cs530x_vol_ramp_text[] = {
+ "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+ "15ms/6dB", "30ms/6dB",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM,
+ CS530X_RAMP_RATE_INC_SHIFT,
+ cs530x_vol_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM,
+ CS530X_RAMP_RATE_DEC_SHIFT,
+ cs530x_vol_ramp_text);
+
+static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = {
+SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_ENUM("IN DEC Filter Select", cs530x_in_filter_enum),
+SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum),
+SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum),
+
+SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_INOUT1_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_INOUT2_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = {
+SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_INOUT3_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_INOUT4_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = {
+SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_INOUT5_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_INOUT6_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_INOUT7_INV_SHIFT, 1, 0),
+SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_INOUT8_INV_SHIFT, 1, 0),
+};
+
+static int cs530x_adc_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ cs530x->adc_pairs_count++;
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ (w->shift * 2), CS530X_INOUT_MUTE);
+ regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
+
+ cs530x->adc_pairs_count--;
+ if (!cs530x->adc_pairs_count) {
+ usleep_range(1000, 1100);
+ return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
+ CS530X_INOUT_VU);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ (w->shift * 2), CS530X_INOUT_MUTE);
+ regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
+ ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
+ return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
+ CS530X_INOUT_VU);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_inc_enum, CS530X_OUT_RAMP_SUM,
+ CS530X_RAMP_RATE_INC_SHIFT,
+ cs530x_vol_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs530x_ramp_out_dec_enum, CS530X_OUT_RAMP_SUM,
+ CS530X_RAMP_RATE_DEC_SHIFT,
+ cs530x_vol_ramp_text);
+
+static const struct snd_kcontrol_new cs530x_out_1_to_2_controls[] = {
+SOC_SINGLE_EXT_TLV("OUT1 Volume", CS530X_OUT_VOL_CTRL1_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("OUT2 Volume", CS530X_OUT_VOL_CTRL1_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_ENUM("OUT DEC Filter Select", cs530x_out_filter_enum),
+SOC_ENUM("Output Ramp Up", cs530x_ramp_out_inc_enum),
+SOC_ENUM("Output Ramp Down", cs530x_ramp_out_dec_enum),
+
+SOC_SINGLE("DAC1 Invert Switch", CS530X_OUT_INV, CS530X_INOUT1_INV_SHIFT, 1, 0),
+SOC_SINGLE("DAC2 Invert Switch", CS530X_OUT_INV, CS530X_INOUT2_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_out_3_to_4_controls[] = {
+SOC_SINGLE_EXT_TLV("OUT3 Volume", CS530X_OUT_VOL_CTRL2_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("OUT4 Volume", CS530X_OUT_VOL_CTRL2_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("DAC3 Invert Switch", CS530X_OUT_INV, CS530X_INOUT3_INV_SHIFT, 1, 0),
+SOC_SINGLE("DAC4 Invert Switch", CS530X_OUT_INV, CS530X_INOUT4_INV_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new cs530x_out_5_to_8_controls[] = {
+SOC_SINGLE_EXT_TLV("OUT5 Volume", CS530X_OUT_VOL_CTRL3_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("OUT6 Volume", CS530X_OUT_VOL_CTRL3_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("OUT7 Volume", CS530X_OUT_VOL_CTRL4_0, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+SOC_SINGLE_EXT_TLV("OUT8 Volume", CS530X_OUT_VOL_CTRL4_1, 0, 255, 1,
+ snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
+
+SOC_SINGLE("DAC5 Invert Switch", CS530X_OUT_INV, CS530X_INOUT5_INV_SHIFT, 1, 0),
+SOC_SINGLE("DAC6 Invert Switch", CS530X_OUT_INV, CS530X_INOUT6_INV_SHIFT, 1, 0),
+SOC_SINGLE("DAC7 Invert Switch", CS530X_OUT_INV, CS530X_INOUT7_INV_SHIFT, 1, 0),
+SOC_SINGLE("DAC8 Invert Switch", CS530X_OUT_INV, CS530X_INOUT8_INV_SHIFT, 1, 0),
+};
+
+static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ cs530x->dac_pairs_count++;
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
+ (w->shift * 2), CS530X_INOUT_MUTE);
+ regmap_clear_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
+ ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
+
+ cs530x->dac_pairs_count--;
+ if (!cs530x->dac_pairs_count) {
+ usleep_range(1000, 1100);
+ return regmap_write(regmap, CS530X_OUT_VOL_CTRL5,
+ CS530X_INOUT_VU);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
+ (w->shift * 2), CS530X_INOUT_MUTE);
+ regmap_set_bits(regmap, CS530X_OUT_VOL_CTRL1_0 +
+ ((w->shift + 1) * 2), CS530X_INOUT_MUTE);
+ return regmap_write(regmap, CS530X_OUT_VOL_CTRL5,
+ CS530X_INOUT_VU);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new adc12_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new adc34_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new adc56_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new adc78_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new dac12_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new dac34_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new dac56_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new dac78_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new in_hpf_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+static const struct snd_kcontrol_new out_hpf_ctrl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* General DAPM widgets for all devices */
+static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0),
+};
+
+/* ADC's Channels 1 and 2 plus generic ADC DAPM events */
+static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1"),
+SND_SOC_DAPM_INPUT("IN2"),
+SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0),
+SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl),
+SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_INOUT_HPF_EN_SHIFT,
+ 0, &in_hpf_ctrl),
+};
+
+/* ADC's Channels 3 and 4 */
+static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN3"),
+SND_SOC_DAPM_INPUT("IN4"),
+SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0),
+SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl),
+};
+
+/* ADC's Channels 5 to 8 */
+static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN5"),
+SND_SOC_DAPM_INPUT("IN6"),
+SND_SOC_DAPM_INPUT("IN7"),
+SND_SOC_DAPM_INPUT("IN8"),
+SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0),
+SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl),
+SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0,
+ cs530x_adc_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0),
+SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl),
+};
+
+static const struct snd_soc_dapm_route adc_ch1_2_routes[] = {
+ { "ADC1", NULL, "Global Enable" },
+ { "ADC2", NULL, "Global Enable" },
+
+ { "ADC12 Enable", "Switch", "IN1" },
+ { "ADC12 Enable", "Switch", "IN2" },
+ { "ADC1", NULL, "ADC12 Enable" },
+ { "ADC2", NULL, "ADC12 Enable" },
+ { "IN HPF", "Switch", "ADC1" },
+ { "IN HPF", "Switch", "ADC2" },
+
+ { "AIF Capture", NULL, "IN HPF" },
+ { "AIF Capture", NULL, "ADC1" },
+ { "AIF Capture", NULL, "ADC2" },
+};
+
+static const struct snd_soc_dapm_route adc_ch3_4_routes[] = {
+ { "ADC3", NULL, "Global Enable" },
+ { "ADC4", NULL, "Global Enable" },
+
+ { "ADC34 Enable", "Switch", "IN3" },
+ { "ADC34 Enable", "Switch", "IN4" },
+ { "ADC3", NULL, "ADC34 Enable" },
+ { "ADC4", NULL, "ADC34 Enable" },
+ { "IN HPF", "Switch", "ADC3" },
+ { "IN HPF", "Switch", "ADC4" },
+
+ { "AIF Capture", NULL, "ADC3" },
+ { "AIF Capture", NULL, "ADC4" },
+};
+
+static const struct snd_soc_dapm_route adc_ch5_8_routes[] = {
+ { "ADC5", NULL, "Global Enable" },
+ { "ADC6", NULL, "Global Enable" },
+ { "ADC7", NULL, "Global Enable" },
+ { "ADC8", NULL, "Global Enable" },
+
+ { "ADC56 Enable", "Switch", "IN5" },
+ { "ADC56 Enable", "Switch", "IN6" },
+ { "ADC5", NULL, "ADC56 Enable" },
+ { "ADC6", NULL, "ADC56 Enable" },
+ { "IN HPF", "Switch", "ADC5" },
+ { "IN HPF", "Switch", "ADC6" },
+
+ { "AIF Capture", NULL, "ADC5" },
+ { "AIF Capture", NULL, "ADC6" },
+
+ { "ADC78 Enable", "Switch", "IN7" },
+ { "ADC78 Enable", "Switch", "IN8" },
+ { "ADC7", NULL, "ADC78 Enable" },
+ { "ADC8", NULL, "ADC78 Enable" },
+ { "IN HPF", "Switch", "ADC7" },
+ { "IN HPF", "Switch", "ADC8" },
+
+ { "AIF Capture", NULL, "ADC7" },
+ { "AIF Capture", NULL, "ADC8" },
+};
+
+static void cs530x_add_12_adc_widgets(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_add_component_controls(component,
+ cs530x_in_1_to_2_controls,
+ ARRAY_SIZE(cs530x_in_1_to_2_controls));
+
+ snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets,
+ ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes,
+ ARRAY_SIZE(adc_ch1_2_routes));
+}
+
+static void cs530x_add_34_adc_widgets(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_add_component_controls(component,
+ cs530x_in_3_to_4_controls,
+ ARRAY_SIZE(cs530x_in_3_to_4_controls));
+
+ snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets,
+ ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes,
+ ARRAY_SIZE(adc_ch3_4_routes));
+}
+
+/* DAC's Channels 1 and 2 plus generic DAC DAPM events */
+static const struct snd_soc_dapm_widget cs530x_dac_ch12_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("OUT1"),
+SND_SOC_DAPM_OUTPUT("OUT2"),
+SND_SOC_DAPM_DAC_E("DAC1", NULL, CS530X_OUT_ENABLES, 0, 0,
+ cs530x_dac_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC("DAC2", NULL, CS530X_OUT_ENABLES, 1, 0),
+SND_SOC_DAPM_SWITCH("DAC12 Enable", SND_SOC_NOPM, 0, 0, &dac12_ctrl),
+SND_SOC_DAPM_SWITCH("OUT HPF", CS530X_OUT_FILTER, CS530X_INOUT_HPF_EN_SHIFT,
+ 0, &out_hpf_ctrl),
+};
+
+/* DAC's Channels 3 and 4 */
+static const struct snd_soc_dapm_widget cs530x_dac_ch34_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_DAC_E("DAC3", NULL, CS530X_OUT_ENABLES, 2, 0,
+ cs530x_dac_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC("DAC4", NULL, CS530X_OUT_ENABLES, 3, 0),
+SND_SOC_DAPM_SWITCH("DAC34 Enable", SND_SOC_NOPM, 0, 0, &dac34_ctrl),
+};
+
+/* DAC's Channels 5 to 8 */
+static const struct snd_soc_dapm_widget cs530x_dac_ch58_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("OUT5"),
+SND_SOC_DAPM_OUTPUT("OUT6"),
+SND_SOC_DAPM_OUTPUT("OUT7"),
+SND_SOC_DAPM_OUTPUT("OUT8"),
+SND_SOC_DAPM_DAC_E("DAC5", NULL, CS530X_OUT_ENABLES, 4, 0,
+ cs530x_dac_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC("DAC6", NULL, CS530X_OUT_ENABLES, 5, 0),
+SND_SOC_DAPM_SWITCH("DAC56 Enable", SND_SOC_NOPM, 0, 0, &dac56_ctrl),
+SND_SOC_DAPM_DAC_E("DAC7", NULL, CS530X_OUT_ENABLES, 6, 0,
+ cs530x_dac_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC("DAC8", NULL, CS530X_OUT_ENABLES, 7, 0),
+SND_SOC_DAPM_SWITCH("DAC78 Enable", SND_SOC_NOPM, 0, 0, &dac78_ctrl),
+};
+
+static const struct snd_soc_dapm_route dac_ch1_2_routes[] = {
+ { "DAC1", NULL, "Global Enable" },
+ { "DAC2", NULL, "Global Enable" },
+
+ { "DAC12 Enable", "Switch", "OUT1" },
+ { "DAC12 Enable", "Switch", "OUT2" },
+ { "DAC1", NULL, "DAC12 Enable" },
+ { "DAC2", NULL, "DAC12 Enable" },
+ { "OUT HPF", "Switch", "DAC1" },
+ { "OUT HPF", "Switch", "DAC2" },
+
+ { "OUT HPF", NULL, "AIF Playback" },
+ { "DAC1", NULL, "AIF Playback" },
+ { "DAC2", NULL, "AIF Playback" },
+
+ { "OUT1", NULL, "DAC1" },
+ { "OUT2", NULL, "DAC2" },
+};
+
+static const struct snd_soc_dapm_route dac_ch3_4_routes[] = {
+ { "DAC3", NULL, "Global Enable" },
+ { "DAC4", NULL, "Global Enable" },
+
+ { "DAC34 Enable", "Switch", "OUT3" },
+ { "DAC34 Enable", "Switch", "OUT4" },
+ { "DAC3", NULL, "DAC34 Enable" },
+ { "DAC4", NULL, "DAC34 Enable" },
+ { "OUT HPF", "Switch", "DAC3" },
+ { "OUT HPF", "Switch", "DAC4" },
+
+ { "DAC3", NULL, "AIF Playback" },
+ { "DAC4", NULL, "AIF Playback" },
+
+ { "OUT3", NULL, "DAC3" },
+ { "OUT4", NULL, "DAC4" },
+};
+
+static const struct snd_soc_dapm_route dac_ch5_8_routes[] = {
+ { "DAC5", NULL, "Global Enable" },
+ { "DAC6", NULL, "Global Enable" },
+
+ { "DAC56 Enable", "Switch", "OUT5" },
+ { "DAC56 Enable", "Switch", "OUT6" },
+ { "DAC5", NULL, "DAC56 Enable" },
+ { "DAC6", NULL, "DAC56 Enable" },
+ { "OUT HPF", "Switch", "DAC5" },
+ { "OUT HPF", "Switch", "DAC6" },
+
+ { "DAC5", NULL, "AIF Playback" },
+ { "DAC6", NULL, "AIF Playback" },
+
+ { "OUT5", NULL, "DAC5" },
+ { "OUT6", NULL, "DAC6" },
+
+ { "DAC7", NULL, "Global Enable" },
+ { "DAC8", NULL, "Global Enable" },
+
+ { "DAC78 Enable", "Switch", "OUT7" },
+ { "DAC78 Enable", "Switch", "OUT8" },
+ { "DAC7", NULL, "DAC78 Enable" },
+ { "DAC8", NULL, "DAC78 Enable" },
+ { "OUT HPF", "Switch", "DAC7" },
+ { "OUT HPF", "Switch", "DAC8" },
+
+ { "DAC7", NULL, "AIF Playback" },
+ { "DAC8", NULL, "AIF Playback" },
+
+ { "OUT7", NULL, "DAC7" },
+ { "OUT8", NULL, "DAC8" },
+};
+
+static void cs530x_add_12_dac_widgets(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_add_component_controls(component,
+ cs530x_out_1_to_2_controls,
+ ARRAY_SIZE(cs530x_out_1_to_2_controls));
+
+ snd_soc_dapm_new_controls(dapm, cs530x_dac_ch12_dapm_widgets,
+ ARRAY_SIZE(cs530x_dac_ch12_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, dac_ch1_2_routes,
+ ARRAY_SIZE(dac_ch1_2_routes));
+}
+
+static void cs530x_add_34_dac_widgets(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_add_component_controls(component,
+ cs530x_out_3_to_4_controls,
+ ARRAY_SIZE(cs530x_out_3_to_4_controls));
+
+ snd_soc_dapm_new_controls(dapm, cs530x_dac_ch34_dapm_widgets,
+ ARRAY_SIZE(cs530x_dac_ch34_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, dac_ch3_4_routes,
+ ARRAY_SIZE(dac_ch3_4_routes));
+}
+
+static int cs530x_set_bclk(struct snd_soc_component *component, const int freq)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ unsigned int bclk_val;
+
+ switch (freq) {
+ case 2822400:
+ case 3072000:
+ bclk_val = CS530X_BCLK_2P822_3P072;
+ break;
+ case 5644800:
+ case 6144000:
+ bclk_val = CS530X_BCLK_5P6448_6P144;
+ break;
+ case 11289600:
+ case 12288000:
+ bclk_val = CS530X_BCLK_11P2896_12P288;
+ break;
+ case 22579200:
+ case 24576000:
+ bclk_val = CS530X_BCLK_24P5792_24P576;
+ break;
+ default:
+ dev_err(component->dev, "Invalid BCLK frequency %d\n", freq);
+ return -EINVAL;
+ }
+
+ dev_dbg(component->dev, "BCLK frequency is %d\n", freq);
+
+ return regmap_update_bits(regmap, CS530X_ASP_CFG,
+ CS530X_ASP_BCLK_FREQ_MASK, bclk_val);
+}
+
+static int cs530x_set_pll_refclk(struct snd_soc_component *component,
+ const unsigned int freq)
+{
+ struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = priv->regmap;
+ unsigned int refclk;
+
+ switch (freq) {
+ case 2822400:
+ case 3072000:
+ refclk = CS530X_REFCLK_2P822_3P072;
+ break;
+ case 5644800:
+ case 6144000:
+ refclk = CS530X_REFCLK_5P6448_6P144;
+ break;
+ case 11289600:
+ case 12288000:
+ refclk = CS530X_REFCLK_11P2896_12P288;
+ break;
+ case 22579200:
+ case 24576000:
+ refclk = CS530X_REFCLK_24P5792_24P576;
+ break;
+ default:
+ dev_err(component->dev, "Invalid PLL refclk %d\n", freq);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_PLL_REFCLK_FREQ_MASK, refclk);
+}
+
+static int cs530x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ int ret = 0, fs = params_rate(params), bclk;
+ unsigned int fs_val;
+
+ switch (fs) {
+ case 32000:
+ fs_val = CS530X_FS_32K;
+ break;
+ case 44100:
+ case 48000:
+ fs_val = CS530X_FS_44P1K_48K;
+ break;
+ case 88200:
+ case 96000:
+ fs_val = CS530X_FS_88P2K_96K;
+ break;
+ case 176400:
+ case 192000:
+ fs_val = CS530X_FS_176P4K_192K;
+ break;
+ case 356800:
+ case 384000:
+ fs_val = CS530X_FS_356P8K_384K;
+ break;
+ case 705600:
+ case 768000:
+ fs_val = CS530X_FS_705P6K_768K;
+ break;
+ default:
+ dev_err(component->dev, "Invalid sample rate %d\n", fs);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(regmap, CS530X_CLK_CFG_1,
+ CS530X_SAMPLE_RATE_MASK, fs_val);
+
+
+ if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+ CS530X_TDM_EN_MASK)) {
+ dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
+ cs530x->tdm_slots, cs530x->tdm_width);
+ bclk = snd_soc_tdm_params_to_bclk(params,
+ cs530x->tdm_width,
+ cs530x->tdm_slots,
+ 1);
+ } else {
+ bclk = snd_soc_params_to_bclk(params);
+ }
+
+ if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_PLL_REFCLK_SRC_MASK)) {
+ ret = cs530x_set_pll_refclk(component, bclk);
+ if (ret)
+ return ret;
+ }
+
+ return cs530x_set_bclk(component, bclk);
+}
+
+static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = priv->regmap;
+ unsigned int asp_fmt, asp_cfg = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ asp_cfg = CS530X_ASP_PRIMARY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ asp_fmt = CS530X_ASP_FMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ asp_fmt = CS530X_ASP_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ asp_fmt = CS530X_ASP_FMT_LJ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ asp_cfg |= CS530X_ASP_BCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(regmap, CS530X_ASP_CFG,
+ CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV,
+ asp_cfg);
+
+ return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+ CS530X_ASP_FMT_MASK, asp_fmt);
+}
+
+static bool cs530x_check_mclk_freq(struct snd_soc_component *component,
+ const unsigned int freq)
+{
+ switch (freq) {
+ case 24576000:
+ case 22579200:
+ case 12288000:
+ case 11289600:
+ return true;
+ default:
+ dev_err(component->dev, "Invalid MCLK %d\n", freq);
+ return false;
+ }
+}
+
+static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ unsigned int val;
+
+ switch (tx_mask) {
+ case CS530X_0_1_TDM_SLOT_MASK:
+ case CS530X_0_3_TDM_SLOT_MASK:
+ case CS530X_0_7_TDM_SLOT_MASK:
+ val = CS530X_0_7_TDM_SLOT_VAL;
+ break;
+ case CS530X_2_3_TDM_SLOT_MASK:
+ val = CS530X_2_3_TDM_SLOT_VAL;
+ break;
+ case CS530X_4_5_TDM_SLOT_MASK:
+ case CS530X_4_7_TDM_SLOT_MASK:
+ val = CS530X_4_7_TDM_SLOT_VAL;
+ break;
+ case CS530X_6_7_TDM_SLOT_MASK:
+ val = CS530X_6_7_TDM_SLOT_VAL;
+ break;
+ case CS530X_8_9_TDM_SLOT_MASK:
+ case CS530X_8_11_TDM_SLOT_MASK:
+ case CS530X_8_15_TDM_SLOT_MASK:
+ val = CS530X_8_15_TDM_SLOT_VAL;
+ break;
+ case CS530X_10_11_TDM_SLOT_MASK:
+ val = CS530X_10_11_TDM_SLOT_VAL;
+ break;
+ case CS530X_12_13_TDM_SLOT_MASK:
+ case CS530X_12_15_TDM_SLOT_MASK:
+ val = CS530X_12_15_TDM_SLOT_VAL;
+ break;
+ case CS530X_14_15_TDM_SLOT_MASK:
+ val = CS530X_14_15_TDM_SLOT_VAL;
+ break;
+ default:
+ dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask);
+ return -EINVAL;
+ }
+
+ cs530x->tdm_width = slot_width;
+ cs530x->tdm_slots = slots;
+
+ return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
+ CS530X_ASP_TDM_SLOT_MASK,
+ val << CS530X_ASP_TDM_SLOT_SHIFT);
+}
+
+static const struct snd_soc_dai_ops cs530x_dai_ops = {
+ .set_fmt = cs530x_set_fmt,
+ .hw_params = cs530x_hw_params,
+ .set_tdm_slot = cs530x_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_driver cs530x_dai = {
+ .name = "cs530x-dai",
+ .capture = {
+ .stream_name = "AIF Capture",
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .playback = {
+ .stream_name = "AIF Playback",
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &cs530x_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static int cs530x_set_pll(struct snd_soc_component *component, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+ unsigned int sysclk_src;
+ int ret;
+
+ regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src);
+
+ /* Check if the source is the PLL */
+ if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0)
+ return 0;
+
+ switch (source) {
+ case CS530X_PLL_SRC_MCLK:
+ if (!cs530x_check_mclk_freq(component, freq_in))
+ return -EINVAL;
+
+ ret = cs530x_set_pll_refclk(component, freq_in);
+ if (ret)
+ return ret;
+
+ break;
+ case CS530X_PLL_SRC_BCLK:
+ break;
+ default:
+ dev_err(component->dev, "Invalid PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_PLL_REFCLK_SRC_MASK, source);
+}
+
+static int cs530x_component_probe(struct snd_soc_component *component)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int num_widgets;
+
+ snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets,
+ ARRAY_SIZE(cs530x_gen_dapm_widgets));
+
+ switch (cs530x->devtype) {
+ case CS4282:
+ cs530x_add_12_adc_widgets(component);
+ cs530x_add_12_dac_widgets(component);
+ break;
+ case CS4302:
+ cs530x_add_12_dac_widgets(component);
+ break;
+ case CS4304:
+ cs530x_add_12_dac_widgets(component);
+ cs530x_add_34_dac_widgets(component);
+
+ num_widgets = ARRAY_SIZE(cs530x_out_sum_4ch_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_out_sum_4ch_controls,
+ num_widgets);
+ break;
+ case CS4308:
+ cs530x_add_12_dac_widgets(component);
+ cs530x_add_34_dac_widgets(component);
+
+ num_widgets = ARRAY_SIZE(cs530x_out_5_to_8_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_out_5_to_8_controls,
+ num_widgets);
+
+ num_widgets = ARRAY_SIZE(cs530x_out_sum_8ch_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_out_sum_8ch_controls,
+ num_widgets);
+
+ num_widgets = ARRAY_SIZE(cs530x_dac_ch58_dapm_widgets);
+ snd_soc_dapm_new_controls(dapm, cs530x_dac_ch58_dapm_widgets,
+ num_widgets);
+
+ snd_soc_dapm_add_routes(dapm, dac_ch5_8_routes,
+ ARRAY_SIZE(dac_ch5_8_routes));
+ break;
+ case CS5302:
+ cs530x_add_12_adc_widgets(component);
+ break;
+ case CS5304:
+ cs530x_add_12_adc_widgets(component);
+ cs530x_add_34_adc_widgets(component);
+
+ num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_in_sum_4ch_controls,
+ num_widgets);
+ break;
+ case CS5308:
+ cs530x_add_12_adc_widgets(component);
+ cs530x_add_34_adc_widgets(component);
+
+ num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_in_5_to_8_controls,
+ num_widgets);
+
+ num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls);
+ snd_soc_add_component_controls(component,
+ cs530x_in_sum_8ch_controls,
+ num_widgets);
+
+ num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets);
+ snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets,
+ num_widgets);
+
+ snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes,
+ ARRAY_SIZE(adc_ch5_8_routes));
+ break;
+ default:
+ dev_err(component->dev, "Invalid device type %d\n",
+ cs530x->devtype);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int source, unsigned int freq, int dir)
+{
+ struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cs530x->regmap;
+
+ switch (source) {
+ case CS530X_SYSCLK_SRC_MCLK:
+ switch (freq) {
+ case CS530X_SYSCLK_REF_45_1MHZ:
+ case CS530X_SYSCLK_REF_49_1MHZ:
+ break;
+ default:
+ dev_err(component->dev, "Invalid MCLK source rate %d\n", freq);
+ return -EINVAL;
+ }
+ break;
+ case CS530X_SYSCLK_SRC_PLL:
+ break;
+ default:
+ dev_err(component->dev, "Invalid sysclk source: %d\n", source);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
+ CS530X_SYSCLK_SRC_MASK,
+ source << CS530X_SYSCLK_SRC_SHIFT);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs530x = {
+ .probe = cs530x_component_probe,
+ .set_sysclk = cs530x_set_sysclk,
+ .set_pll = cs530x_set_pll,
+ .endianness = 1,
+};
+
+const struct regmap_config cs530x_regmap_i2c = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .max_register = CS530X_MAX_REGISTER,
+ .readable_reg = cs530x_readable_register,
+ .writeable_reg = cs530x_writeable_register,
+
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = cs530x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
+};
+EXPORT_SYMBOL_NS_GPL(cs530x_regmap_i2c, "SND_SOC_CS530X");
+
+const struct regmap_config cs530x_regmap_spi = {
+ .reg_bits = 16,
+ .pad_bits = 16,
+ .val_bits = 16,
+
+ .reg_stride = 2,
+
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = CS530X_MAX_REGISTER,
+ .writeable_reg = cs530x_writeable_register,
+ .readable_reg = cs530x_readable_register,
+
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = cs530x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
+};
+EXPORT_SYMBOL_NS_GPL(cs530x_regmap_spi, "SND_SOC_CS530X");
+
+static int cs530x_check_device_id(struct cs530x_priv *cs530x)
+{
+ struct device *dev = cs530x->dev;
+ unsigned int dev_id, rev;
+ int ret;
+
+ ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't read device ID\n");
+
+ ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't read REV ID\n");
+
+ switch (dev_id) {
+ case CS530X_2CH_CODEC_DEV_ID:
+ cs530x->num_dacs = 2;
+ cs530x->num_adcs = 2;
+ break;
+ case CS530X_2CH_DAC_DEV_ID:
+ cs530x->num_dacs = 2;
+ break;
+ case CS530X_4CH_DAC_DEV_ID:
+ cs530x->num_dacs = 4;
+ break;
+ case CS530X_8CH_DAC_DEV_ID:
+ cs530x->num_dacs = 8;
+ break;
+ case CS530X_2CH_ADC_DEV_ID:
+ cs530x->num_adcs = 2;
+ break;
+ case CS530X_4CH_ADC_DEV_ID:
+ cs530x->num_adcs = 4;
+ break;
+ case CS530X_8CH_ADC_DEV_ID:
+ cs530x->num_adcs = 8;
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n",
+ dev_id);
+ }
+
+ if (cs530x->devtype != dev_id) {
+ dev_err(dev, "Read device ID 0x%x is not the expected devtype 0x%x\n",
+ dev_id, cs530x->devtype);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x (%d in %d out)\n", dev_id, rev,
+ cs530x->num_adcs, cs530x->num_dacs);
+
+ return 0;
+}
+
+static int cs530x_parse_device_properties(struct cs530x_priv *cs530x)
+{
+ struct regmap *regmap = cs530x->regmap;
+ struct device *dev = cs530x->dev;
+ unsigned int val = 0;
+
+ switch (cs530x->num_adcs) {
+ case 8:
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin78"))
+ val = CS530X_IN78_HIZ;
+
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin56"))
+ val |= CS530X_IN56_HIZ;
+
+ fallthrough;
+ case 4:
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin34"))
+ val |= CS530X_IN34_HIZ;
+
+ fallthrough;
+ case 2:
+ if (device_property_read_bool(dev, "cirrus,in-hiz-pin12"))
+ val |= CS530X_IN12_HIZ;
+
+ return regmap_set_bits(regmap, CS530X_IN_HIZ, val);
+ case 0:
+ /* No ADCs */
+ return 0;
+ default:
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid number of adcs %d\n",
+ cs530x->num_adcs);
+ }
+}
+
+int cs530x_probe(struct cs530x_priv *cs530x)
+{
+ struct device *dev = cs530x->dev;
+ int ret, i;
+
+ cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai,
+ sizeof(*(cs530x->dev_dai)),
+ GFP_KERNEL);
+ if (!cs530x->dev_dai)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++)
+ cs530x->supplies[i].supply = cs530x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies),
+ cs530x->supplies);
+ if (ret != 0)
+ return dev_err_probe(dev, ret, "Failed to request supplies");
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies),
+ cs530x->supplies);
+ if (ret != 0)
+ return dev_err_probe(dev, ret, "Failed to enable supplies");
+
+ cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(cs530x->reset_gpio)) {
+ ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio),
+ "Reset gpio not available\n");
+ goto err_regulator;
+ }
+
+ if (cs530x->reset_gpio) {
+ usleep_range(2000, 2100);
+ gpiod_set_value_cansleep(cs530x->reset_gpio, 0);
+ }
+
+ usleep_range(5000, 5100);
+ ret = cs530x_check_device_id(cs530x);
+ if (ret)
+ goto err_reset;
+
+ if (!cs530x->reset_gpio) {
+ ret = regmap_write(cs530x->regmap, CS530X_SW_RESET,
+ CS530X_SW_RST_VAL);
+ if (ret) {
+ dev_err_probe(dev, ret, "Soft Reset Failed\n");
+ goto err_reset;
+ }
+ }
+
+ ret = cs530x_parse_device_properties(cs530x);
+ if (ret)
+ goto err_reset;
+
+ if (cs530x->num_adcs) {
+ cs530x->dev_dai->capture.channels_min = 2;
+ cs530x->dev_dai->capture.channels_max = cs530x->num_adcs;
+ }
+
+ if (cs530x->num_dacs) {
+ cs530x->dev_dai->playback.channels_min = 2;
+ cs530x->dev_dai->playback.channels_max = cs530x->num_dacs;
+ }
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_dev_cs530x,
+ cs530x->dev_dai, 1);
+ if (ret) {
+ dev_err_probe(dev, ret, "Can't register cs530x component\n");
+ goto err_reset;
+ }
+
+ return 0;
+
+err_reset:
+ gpiod_set_value_cansleep(cs530x->reset_gpio, 1);
+
+err_regulator:
+ regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies),
+ cs530x->supplies);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs530x_probe, "SND_SOC_CS530X");
+
+MODULE_DESCRIPTION("CS530X CODEC Driver");
+MODULE_AUTHOR("Paul Handrigan <paulha@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h
new file mode 100644
index 000000000000..1e2f6a7a589c
--- /dev/null
+++ b/sound/soc/codecs/cs530x.h
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS530x CODEC driver internal data
+ *
+ * Copyright (C) 2023-2025 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef _CS530X_H
+#define _CS530X_H
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+/* Devices */
+#define CS530X_2CH_CODEC_DEV_ID 0x4282
+#define CS530X_2CH_DAC_DEV_ID 0x4302
+#define CS530X_4CH_DAC_DEV_ID 0x4304
+#define CS530X_8CH_DAC_DEV_ID 0x4308
+#define CS530X_2CH_ADC_DEV_ID 0x5302
+#define CS530X_4CH_ADC_DEV_ID 0x5304
+#define CS530X_8CH_ADC_DEV_ID 0x5308
+
+/* Registers */
+
+#define CS530X_DEVID 0x0000000
+#define CS530X_REVID 0x0000004
+#define CS530X_SW_RESET 0x0000022
+
+#define CS530X_CLK_CFG_0 0x0000040
+#define CS530X_CLK_CFG_1 0x0000042
+#define CS530X_CHIP_ENABLE 0x0000044
+#define CS530X_ASP_CFG 0x0000048
+#define CS530X_SIGNAL_PATH_CFG 0x0000050
+#define CS530X_IN_ENABLES 0x0000080
+#define CS530X_IN_RAMP_SUM 0x0000082
+#define CS530X_IN_FILTER 0x0000086
+#define CS530X_IN_HIZ 0x0000088
+#define CS530X_IN_INV 0x000008A
+#define CS530X_IN_VOL_CTRL1_0 0x0000090
+#define CS530X_IN_VOL_CTRL1_1 0x0000092
+#define CS530X_IN_VOL_CTRL2_0 0x0000094
+#define CS530X_IN_VOL_CTRL2_1 0x0000096
+#define CS530X_IN_VOL_CTRL3_0 0x0000098
+#define CS530X_IN_VOL_CTRL3_1 0x000009A
+#define CS530X_IN_VOL_CTRL4_0 0x000009C
+#define CS530X_IN_VOL_CTRL4_1 0x000009E
+#define CS530X_IN_VOL_CTRL5 0x00000A0
+
+#define CS530X_OUT_ENABLES 0x00000C0
+#define CS530X_OUT_RAMP_SUM 0x00000C2
+#define CS530X_OUT_DEEMPH 0x00000C4
+#define CS530X_OUT_FILTER 0x00000C6
+#define CS530X_OUT_INV 0x00000CA
+#define CS530X_OUT_VOL_CTRL1_0 0x00000D0
+#define CS530X_OUT_VOL_CTRL1_1 0x00000D2
+#define CS530X_OUT_VOL_CTRL2_0 0x00000D4
+#define CS530X_OUT_VOL_CTRL2_1 0x00000D6
+#define CS530X_OUT_VOL_CTRL3_0 0x00000D8
+#define CS530X_OUT_VOL_CTRL3_1 0x00000DA
+#define CS530X_OUT_VOL_CTRL4_0 0x00000DC
+#define CS530X_OUT_VOL_CTRL4_1 0x00000DE
+#define CS530X_OUT_VOL_CTRL5 0x00000E0
+
+#define CS530X_PAD_FN 0x0003D24
+#define CS530X_PAD_LVL 0x0003D28
+
+#define CS530X_MAX_REGISTER CS530X_PAD_LVL
+
+/* Register Fields */
+
+/* REVID */
+#define CS530X_MTLREVID GENMASK(3, 0)
+#define CS530X_AREVID GENMASK(7, 4)
+
+/* SW_RESET */
+#define CS530X_SW_RST_SHIFT 8
+#define CS530X_SW_RST_VAL (0x5A << CS530X_SW_RST_SHIFT)
+
+/* CLK_CFG_0 */
+#define CS530X_PLL_REFCLK_SRC_MASK BIT(0)
+#define CS530X_PLL_REFCLK_FREQ_MASK GENMASK(5, 4)
+#define CS530X_SYSCLK_SRC_MASK BIT(12)
+#define CS530X_SYSCLK_SRC_SHIFT 12
+#define CS530X_REFCLK_2P822_3P072 0
+#define CS530X_REFCLK_5P6448_6P144 0x10
+#define CS530X_REFCLK_11P2896_12P288 0x20
+#define CS530X_REFCLK_24P5792_24P576 0x30
+
+/* CLK_CFG_1 */
+#define CS530X_SAMPLE_RATE_MASK GENMASK(2, 0)
+#define CS530X_FS_32K 0
+#define CS530X_FS_44P1K_48K 1
+#define CS530X_FS_88P2K_96K 2
+#define CS530X_FS_176P4K_192K 3
+#define CS530X_FS_356P8K_384K 4
+#define CS530X_FS_705P6K_768K 5
+
+/* CHIP_ENABLE */
+#define CS530X_GLOBAL_EN BIT(0)
+
+/* ASP_CFG */
+#define CS530X_ASP_BCLK_FREQ_MASK GENMASK(1, 0)
+#define CS530X_ASP_PRIMARY BIT(5)
+#define CS530X_ASP_BCLK_INV BIT(6)
+#define CS530X_BCLK_2P822_3P072 0
+#define CS530X_BCLK_5P6448_6P144 1
+#define CS530X_BCLK_11P2896_12P288 2
+#define CS530X_BCLK_24P5792_24P576 3
+
+/* SIGNAL_PATH_CFG */
+#define CS530X_ASP_FMT_MASK GENMASK(2, 0)
+#define CS530X_ASP_TDM_SLOT_MASK GENMASK(5, 3)
+#define CS530X_ASP_TDM_SLOT_SHIFT 3
+#define CS530X_ASP_CH_REVERSE BIT(9)
+#define CS530X_TDM_EN_MASK BIT(2)
+#define CS530X_ASP_FMT_I2S 0
+#define CS530X_ASP_FMT_LJ 1
+#define CS530X_ASP_FMT_DSP_A 6
+
+/* TDM Slots */
+#define CS530X_0_1_TDM_SLOT_MASK GENMASK(1, 0)
+#define CS530X_0_3_TDM_SLOT_MASK GENMASK(3, 0)
+#define CS530X_0_7_TDM_SLOT_MASK GENMASK(7, 0)
+#define CS530X_0_7_TDM_SLOT_VAL 0
+
+#define CS530X_2_3_TDM_SLOT_MASK GENMASK(3, 2)
+#define CS530X_2_3_TDM_SLOT_VAL 1
+
+#define CS530X_4_5_TDM_SLOT_MASK GENMASK(5, 4)
+#define CS530X_4_7_TDM_SLOT_MASK GENMASK(7, 4)
+#define CS530X_4_7_TDM_SLOT_VAL 2
+
+#define CS530X_6_7_TDM_SLOT_MASK GENMASK(7, 6)
+#define CS530X_6_7_TDM_SLOT_VAL 3
+
+#define CS530X_8_9_TDM_SLOT_MASK GENMASK(9, 8)
+#define CS530X_8_11_TDM_SLOT_MASK GENMASK(11, 8)
+#define CS530X_8_15_TDM_SLOT_MASK GENMASK(15, 8)
+#define CS530X_8_15_TDM_SLOT_VAL 4
+
+#define CS530X_10_11_TDM_SLOT_MASK GENMASK(11, 10)
+#define CS530X_10_11_TDM_SLOT_VAL 5
+
+#define CS530X_12_13_TDM_SLOT_MASK GENMASK(13, 12)
+#define CS530X_12_15_TDM_SLOT_MASK GENMASK(15, 12)
+#define CS530X_12_15_TDM_SLOT_VAL 6
+
+#define CS530X_14_15_TDM_SLOT_MASK GENMASK(15, 14)
+#define CS530X_14_15_TDM_SLOT_VAL 7
+
+/* IN_RAMP_SUM and OUT_RAMP_SUM */
+#define CS530X_RAMP_RATE_INC_SHIFT 0
+#define CS530X_RAMP_RATE_DEC_SHIFT 4
+#define CS530X_INOUT_SUM_MODE_SHIFT 13
+
+/* IN_FILTER and OUT_FILTER */
+#define CS530X_INOUT_FILTER_SHIFT 8
+#define CS530X_INOUT_HPF_EN_SHIFT 12
+
+/* IN_HIZ */
+#define CS530X_IN12_HIZ BIT(0)
+#define CS530X_IN34_HIZ BIT(1)
+#define CS530X_IN56_HIZ BIT(2)
+#define CS530X_IN78_HIZ BIT(3)
+
+/* IN_INV and OUT_INV */
+#define CS530X_INOUT1_INV_SHIFT 0
+#define CS530X_INOUT2_INV_SHIFT 1
+#define CS530X_INOUT3_INV_SHIFT 2
+#define CS530X_INOUT4_INV_SHIFT 3
+#define CS530X_INOUT5_INV_SHIFT 4
+#define CS530X_INOUT6_INV_SHIFT 5
+#define CS530X_INOUT7_INV_SHIFT 6
+#define CS530X_INOUT8_INV_SHIFT 7
+
+/* IN_VOL_CTLy_z and OUT_VOL_CTLy_z */
+#define CS530X_INOUT_MUTE BIT(15)
+
+/* IN_VOL_CTL5 */
+#define CS530X_IN_VU BIT(0)
+
+/* PAD_FN */
+#define CS530X_DOUT2_FN BIT(0)
+#define CS530X_DOUT3_FN BIT(1)
+#define CS530X_DOUT4_FN BIT(2)
+#define CS530X_SPI_CS_FN BIT(3)
+#define CS530X_CONFIG2_FN BIT(6)
+#define CS530X_CONFIG3_FN BIT(7)
+#define CS530X_CONFIG4_FN BIT(8)
+#define CS530X_CONFIG5_FN BIT(9)
+
+/* PAD_LVL */
+#define CS530X_CONFIG2_LVL BIT(6)
+#define CS530X_CONFIG3_LVL BIT(7)
+#define CS530X_CONFIG4_LVL BIT(8)
+#define CS530X_CONFIG5_LVL BIT(9)
+/* IN_VOL_CTL5 and OUT_VOL_CTL5 */
+#define CS530X_INOUT_VU BIT(0)
+
+/* MCLK Reference Source Frequency */
+/* 41KHz related */
+#define CS530X_SYSCLK_REF_45_1MHZ 45158400
+/* 48KHz related */
+#define CS530X_SYSCLK_REF_49_1MHZ 49152000
+
+/* System Clock Source */
+#define CS530X_SYSCLK_SRC_MCLK 0
+#define CS530X_SYSCLK_SRC_PLL 1
+
+/* PLL Reference Clock Source */
+#define CS530X_PLL_SRC_BCLK 0
+#define CS530X_PLL_SRC_MCLK 1
+
+#define CS530X_NUM_SUPPLIES 2
+
+enum cs530x_type {
+ CS4282 = CS530X_2CH_CODEC_DEV_ID,
+ CS4302 = CS530X_2CH_DAC_DEV_ID,
+ CS4304 = CS530X_4CH_DAC_DEV_ID,
+ CS4308 = CS530X_8CH_DAC_DEV_ID,
+ CS5302 = CS530X_2CH_ADC_DEV_ID,
+ CS5304 = CS530X_4CH_ADC_DEV_ID,
+ CS5308 = CS530X_8CH_ADC_DEV_ID,
+};
+
+/* codec private data */
+struct cs530x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct snd_soc_dai_driver *dev_dai;
+
+ enum cs530x_type devtype;
+ int num_adcs;
+ int num_dacs;
+
+ struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES];
+
+ int tdm_width;
+ int tdm_slots;
+ int adc_pairs_count;
+ int dac_pairs_count;
+
+ struct gpio_desc *reset_gpio;
+};
+
+extern const struct regmap_config cs530x_regmap_i2c;
+extern const struct regmap_config cs530x_regmap_spi;
+int cs530x_probe(struct cs530x_priv *cs530x);
+
+#endif
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index f4065555c36e..93ea2fb4dae9 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/pcm_params.h>
@@ -573,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;
@@ -650,8 +649,9 @@ static int cs53l30_pcm_hw_params(struct snd_pcm_substream *substream,
static int cs53l30_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct cs53l30_private *priv = snd_soc_component_get_drvdata(component);
+ enum snd_soc_bias_level bias_level = snd_soc_dapm_get_bias_level(dapm);
unsigned int reg;
int i, inter_max_check, ret;
@@ -659,12 +659,12 @@ static int cs53l30_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
+ if (bias_level == SND_SOC_BIAS_STANDBY)
regmap_update_bits(priv->regmap, CS53L30_PWRCTL,
CS53L30_PDN_LP_MASK, 0);
break;
case SND_SOC_BIAS_STANDBY:
- if (dapm->bias_level == SND_SOC_BIAS_OFF) {
+ if (bias_level == SND_SOC_BIAS_OFF) {
ret = clk_prepare_enable(priv->mclk);
if (ret) {
dev_err(component->dev,
@@ -740,24 +740,6 @@ static int cs53l30_set_tristate(struct snd_soc_dai *dai, int tristate)
CS53L30_ASP_3ST_MASK, val);
}
-static unsigned int const cs53l30_src_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-};
-
-static const struct snd_pcm_hw_constraint_list src_constraints = {
- .count = ARRAY_SIZE(cs53l30_src_rates),
- .list = cs53l30_src_rates,
-};
-
-static int cs53l30_pcm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &src_constraints);
-
- return 0;
-}
-
/*
* Note: CS53L30 counts the slot number per byte while ASoC counts the slot
* number per slot_width. So there is a difference between the slots of ASoC
@@ -844,14 +826,14 @@ static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
-/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
-#define CS53L30_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+#define CS53L30_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_12000 | \
+ SNDRV_PCM_RATE_24000)
#define CS53L30_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
static const struct snd_soc_dai_ops cs53l30_ops = {
- .startup = cs53l30_pcm_startup,
.hw_params = cs53l30_pcm_hw_params,
.set_fmt = cs53l30_set_dai_fmt,
.set_sysclk = cs53l30_set_sysclk,
@@ -876,7 +858,7 @@ static struct snd_soc_dai_driver cs53l30_dai = {
static int cs53l30_component_probe(struct snd_soc_component *component)
{
struct cs53l30_private *priv = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (priv->use_sdout2)
snd_soc_dapm_add_routes(dapm, cs53l30_dapm_routes_sdout2,
@@ -901,7 +883,7 @@ static const struct snd_soc_component_driver cs53l30_driver = {
.endianness = 1,
};
-static struct regmap_config cs53l30_regmap = {
+static const struct regmap_config cs53l30_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -1050,7 +1032,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);
@@ -1089,11 +1070,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[] = {
@@ -1104,7 +1083,7 @@ static const struct of_device_id cs53l30_of_match[] = {
MODULE_DEVICE_TABLE(of, cs53l30_of_match);
static const struct i2c_device_id cs53l30_id[] = {
- { "cs53l30", 0 },
+ { "cs53l30" },
{}
};
@@ -1114,7 +1093,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/cx20442.c b/sound/soc/codecs/cx20442.c
index 43c0cac0ec9e..d6121c0a2616 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -258,8 +258,8 @@ static void v253_hangup(struct tty_struct *tty)
}
/* Line discipline .receive_buf() */
-static void v253_receive(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+static void v253_receive(struct tty_struct *tty, const u8 *cp, const u8 *fp,
+ size_t count)
{
struct snd_soc_component *component = tty->disc_data;
struct cx20442_priv *cx20442;
@@ -315,11 +315,12 @@ static int cx20442_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int err = 0;
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_STANDBY)
break;
if (IS_ERR(cx20442->por))
err = PTR_ERR(cx20442->por);
@@ -327,7 +328,7 @@ static int cx20442_set_bias_level(struct snd_soc_component *component,
err = regulator_enable(cx20442->por);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_PREPARE)
break;
if (IS_ERR(cx20442->por))
err = PTR_ERR(cx20442->por);
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 082231088a26..b0033bf9be3a 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -63,11 +63,6 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7400, 100, 0);
static const DECLARE_TLV_DB_SCALE(dac_tlv, -7400, 100, 0);
static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 1200, 0);
-struct cx2072x_eq_ctrl {
- u8 ch;
- u8 band;
-};
-
static const DECLARE_TLV_DB_RANGE(hpf_tlv,
0, 0, TLV_DB_SCALE_ITEM(120, 0, 0),
1, 63, TLV_DB_SCALE_ITEM(30, 30, 0)
@@ -1346,8 +1341,8 @@ static int cx2072x_set_bias_level(struct snd_soc_component *codec,
enum snd_soc_bias_level level)
{
struct cx2072x_priv *cx2072x = snd_soc_component_get_drvdata(codec);
- const enum snd_soc_bias_level old_level =
- snd_soc_component_get_bias_level(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
+ const enum snd_soc_bias_level old_level = snd_soc_dapm_get_bias_level(dapm);
if (level == SND_SOC_BIAS_STANDBY && old_level == SND_SOC_BIAS_OFF)
regmap_write(cx2072x->regmap, CX2072X_AFG_POWER_STATE, 0);
@@ -1368,7 +1363,7 @@ static int cx2072x_set_bias_level(struct snd_soc_component *codec,
static void cx2072x_enable_jack_detect(struct snd_soc_component *codec)
{
struct cx2072x_priv *cx2072x = snd_soc_component_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
/* No-sticky input type */
regmap_write(cx2072x->regmap, CX2072X_GPIO_STICKY_MASK, 0x1f);
@@ -1546,6 +1541,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops cx2072x_dai_ops2 = {
+ .probe = cx2072x_dsp_dai_probe,
+ .set_sysclk = cx2072x_set_dai_sysclk,
+ .set_fmt = cx2072x_set_dai_fmt,
+ .hw_params = cx2072x_hw_params,
+ .set_bclk_ratio = cx2072x_set_dai_bclk_ratio,
+};
+
#define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
@@ -1572,7 +1575,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
{ /* plabayck only, return echo reference to Conexant DSP chip */
.name = "cx2072x-dsp",
.id = CX2072X_DAI_DSP,
- .probe = cx2072x_dsp_dai_probe,
.playback = {
.stream_name = "DSP Playback",
.channels_min = 2,
@@ -1580,7 +1582,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
.rates = CX2072X_RATES_DSP,
.formats = CX2072X_FORMATS,
},
- .ops = &cx2072x_dai_ops,
+ .ops = &cx2072x_dai_ops2,
},
{ /* plabayck only, return echo reference through I2S TX */
.name = "cx2072x-aec",
@@ -1609,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);
@@ -1617,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);
@@ -1679,8 +1681,8 @@ static void cx2072x_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id cx2072x_i2c_id[] = {
- { "cx20721", 0 },
- { "cx20723", 0 },
+ { "cx20721" },
+ { "cx20723" },
{}
};
MODULE_DEVICE_TABLE(i2c, cx2072x_i2c_id);
@@ -1694,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 1e232d01809c..94e59546c2fe 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -326,7 +326,7 @@ static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
if (ucontrol->value.integer.value[0]) {
/* Check if noise suppression is enabled */
@@ -349,7 +349,7 @@ static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
if (ucontrol->value.integer.value[0]) {
@@ -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;
@@ -1238,7 +1238,7 @@ static int da7210_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id da7210_i2c_id[] = {
- { "da7210", 0 },
+ { "da7210" },
{ }
};
MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 3a6449c44b23..0a2b50cdea95 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -9,7 +9,7 @@
*/
#include <linux/acpi.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/property.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -20,6 +20,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
+#include <linux/units.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -55,6 +56,7 @@ static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0);
static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0);
static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0);
static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7213_tonegen_gain_tlv, -4500, 300, 0);
/* ADC and DAC voice mode (8kHz) high pass cutoff value */
static const char * const da7213_voice_hpf_corner_txt[] = {
@@ -86,6 +88,23 @@ static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner,
DA7213_AUDIO_HPF_CORNER_SHIFT,
da7213_audio_hpf_corner_txt);
+static const char * const da7213_tonegen_dtmf_key_txt[] = {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+ "*", "#"
+};
+
+static const struct soc_enum da7213_tonegen_dtmf_key =
+ SOC_ENUM_SINGLE(DA7213_TONE_GEN_CFG1, DA7213_DTMF_REG_SHIFT,
+ DA7213_DTMF_REG_MAX, da7213_tonegen_dtmf_key_txt);
+
+static const char * const da7213_tonegen_swg_sel_txt[] = {
+ "Sum", "SWG1", "SWG2", "Sum"
+};
+
+static const struct soc_enum da7213_tonegen_swg_sel =
+ SOC_ENUM_SINGLE(DA7213_TONE_GEN_CFG2, DA7213_SWG_SEL_SHIFT,
+ DA7213_SWG_SEL_MAX, da7213_tonegen_swg_sel_txt);
+
/* Gain ramping rate value */
static const char * const da7213_gain_ramp_rate_txt[] = {
"nominal rate * 8", "nominal rate * 16", "nominal rate / 16",
@@ -191,6 +210,64 @@ static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate,
* Control Functions
*/
+/* Locked Kcontrol calls */
+static int da7213_volsw_locked_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ mutex_lock(&da7213->ctrl_lock);
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+ mutex_unlock(&da7213->ctrl_lock);
+
+ return ret;
+}
+
+static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ mutex_lock(&da7213->ctrl_lock);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ mutex_unlock(&da7213->ctrl_lock);
+
+ return ret;
+}
+
+static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ mutex_lock(&da7213->ctrl_lock);
+ ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+ mutex_unlock(&da7213->ctrl_lock);
+
+ return ret;
+}
+
+static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ mutex_lock(&da7213->ctrl_lock);
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+ mutex_unlock(&da7213->ctrl_lock);
+
+ return ret;
+}
+
+/* ALC */
static int da7213_get_alc_data(struct snd_soc_component *component, u8 reg_val)
{
int mid_data, top_data;
@@ -343,7 +420,7 @@ static void da7213_alc_calib(struct snd_soc_component *component)
static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
int ret;
@@ -359,7 +436,7 @@ static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
/* Force ALC offset calibration if enabling ALC */
@@ -376,6 +453,64 @@ static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,
return snd_soc_put_volsw(kcontrol, ucontrol);
}
+/* ToneGen */
+static int da7213_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mixer_ctrl =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ unsigned int reg = mixer_ctrl->reg;
+ __le16 val;
+ int ret;
+
+ mutex_lock(&da7213->ctrl_lock);
+ ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val));
+ mutex_unlock(&da7213->ctrl_lock);
+
+ if (ret)
+ return ret;
+
+ /*
+ * Frequency value spans two 8-bit registers, lower then upper byte.
+ * Therefore we need to convert to host endianness here.
+ */
+ ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+ return 0;
+}
+
+static int da7213_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mixer_ctrl =
+ (struct soc_mixer_control *) kcontrol->private_value;
+ unsigned int reg = mixer_ctrl->reg;
+ __le16 val_new, val_old;
+ int ret;
+
+ /*
+ * Frequency value spans two 8-bit registers, lower then upper byte.
+ * Therefore we need to convert to little endian here to align with
+ * HW registers.
+ */
+ val_new = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+ mutex_lock(&da7213->ctrl_lock);
+ ret = regmap_raw_read(da7213->regmap, reg, &val_old, sizeof(val_old));
+ if (ret == 0 && (val_old != val_new))
+ ret = regmap_raw_write(da7213->regmap, reg,
+ &val_new, sizeof(val_new));
+ mutex_unlock(&da7213->ctrl_lock);
+
+ if (ret < 0)
+ return ret;
+
+ return val_old != val_new;
+}
/*
* KControls
@@ -477,6 +612,37 @@ static const struct snd_kcontrol_new da7213_snd_controls[] = {
SOC_DOUBLE_R("Headphone ZC Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL,
DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT),
+ /* Tone Generator */
+ SOC_SINGLE_EXT_TLV("ToneGen Volume", DA7213_TONE_GEN_CFG2,
+ DA7213_TONE_GEN_GAIN_SHIFT, DA7213_TONE_GEN_GAIN_MAX,
+ DA7213_NO_INVERT, da7213_volsw_locked_get,
+ da7213_volsw_locked_put, da7213_tonegen_gain_tlv),
+ SOC_ENUM_EXT("ToneGen DTMF Key", da7213_tonegen_dtmf_key,
+ da7213_enum_locked_get, da7213_enum_locked_put),
+ SOC_SINGLE_EXT("ToneGen DTMF Switch", DA7213_TONE_GEN_CFG1,
+ DA7213_DTMF_EN_SHIFT, DA7213_SWITCH_EN_MAX,
+ DA7213_NO_INVERT, da7213_volsw_locked_get,
+ da7213_volsw_locked_put),
+ SOC_SINGLE_EXT("ToneGen Start", DA7213_TONE_GEN_CFG1,
+ DA7213_START_STOPN_SHIFT, DA7213_SWITCH_EN_MAX,
+ DA7213_NO_INVERT, da7213_volsw_locked_get,
+ da7213_volsw_locked_put),
+ SOC_ENUM_EXT("ToneGen Sinewave Gen Type", da7213_tonegen_swg_sel,
+ da7213_enum_locked_get, da7213_enum_locked_put),
+ SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7213_TONE_GEN_FREQ1_L,
+ DA7213_FREQ1_L_SHIFT, DA7213_FREQ_MAX, DA7213_NO_INVERT,
+ da7213_tonegen_freq_get, da7213_tonegen_freq_put),
+ SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7213_TONE_GEN_FREQ2_L,
+ DA7213_FREQ2_L_SHIFT, DA7213_FREQ_MAX, DA7213_NO_INVERT,
+ da7213_tonegen_freq_get, da7213_tonegen_freq_put),
+ SOC_SINGLE_EXT("ToneGen On Time", DA7213_TONE_GEN_ON_PER,
+ DA7213_BEEP_ON_PER_SHIFT, DA7213_BEEP_ON_OFF_MAX,
+ DA7213_NO_INVERT, da7213_volsw_locked_get,
+ da7213_volsw_locked_put),
+ SOC_SINGLE("ToneGen Off Time", DA7213_TONE_GEN_OFF_PER,
+ DA7213_BEEP_OFF_PER_SHIFT, DA7213_BEEP_ON_OFF_MAX,
+ DA7213_NO_INVERT),
+
/* Gain Ramping controls */
SOC_DOUBLE_R("Aux Gain Ramping Switch", DA7213_AUX_L_CTRL,
DA7213_AUX_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT,
@@ -765,7 +931,7 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w,
/* Check SRM has locked */
do {
pll_status = snd_soc_component_read(component, DA7213_PLL_STATUS);
- if (pll_status & DA7219_PLL_SRM_LOCK) {
+ if (pll_status & DA7213_PLL_SRM_LOCK) {
srm_lock = true;
} else {
++i;
@@ -1261,10 +1427,10 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
/* Set master/slave mode */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
da7213->master = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
da7213->master = false;
break;
default:
@@ -1293,8 +1459,8 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
break;
- case SND_SOC_DAI_FORMAT_DSP_A:
- case SND_SOC_DAI_FORMAT_DSP_B:
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
/* The bclk is inverted wrt ASoC conventions */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -1331,12 +1497,12 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
dai_ctrl |= DA7213_DAI_FORMAT_RIGHT_J;
da7213->fmt = DA7213_DAI_FORMAT_RIGHT_J;
break;
- case SND_SOC_DAI_FORMAT_DSP_A: /* L data MSB after FRM LRC */
+ case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
dai_ctrl |= DA7213_DAI_FORMAT_DSP;
dai_offset = 1;
da7213->fmt = DA7213_DAI_FORMAT_DSP;
break;
- case SND_SOC_DAI_FORMAT_DSP_B: /* L data MSB during FRM LRC */
+ case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
dai_ctrl |= DA7213_DAI_FORMAT_DSP;
da7213->fmt = DA7213_DAI_FORMAT_DSP;
break;
@@ -1390,7 +1556,11 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component,
if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq))
return 0;
- if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) {
+ /* Maybe audio stream is closing. */
+ if (freq == 0)
+ return 0;
+
+ if (((freq < da7213->fin_min_rate) && (freq != 32768)) || (freq > 54000000)) {
dev_err(component->dev, "Unsupported MCLK value %d\n",
freq);
return -EINVAL;
@@ -1550,12 +1720,30 @@ static int da7213_set_component_pll(struct snd_soc_component *component,
return _da7213_set_component_pll(component, pll_id, source, fref, fout);
}
+/*
+ * Select below from Sound Card, not Auto
+ * SND_SOC_DAIFMT_CBC_CFC
+ * SND_SOC_DAIFMT_CBP_CFP
+ */
+static const u64 da7213_dai_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
/* DAI operations */
static const struct snd_soc_dai_ops da7213_dai_ops = {
.hw_params = da7213_hw_params,
.set_fmt = da7213_set_dai_fmt,
.mute_stream = da7213_mute,
.no_capture_mute = 1,
+ .auto_selectable_formats = &da7213_dai_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver da7213_dai = {
@@ -1628,6 +1816,7 @@ static int da7213_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1635,7 +1824,7 @@ static int da7213_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
/* Enable MCLK for transition to ON state */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
if (da7213->mclk) {
ret = clk_prepare_enable(da7213->mclk);
if (ret) {
@@ -1649,7 +1838,7 @@ static int da7213_set_bias_level(struct snd_soc_component *component,
}
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Enable VMID reference & master bias */
snd_soc_component_update_bits(component, DA7213_REFERENCES,
DA7213_VMID_EN | DA7213_BIAS_EN,
@@ -1671,11 +1860,14 @@ static int da7213_set_bias_level(struct snd_soc_component *component,
return 0;
}
+#define DA7213_FIN_MIN_RATE (5 * MEGA)
+#define DA7212_FIN_MIN_RATE (2 * MEGA)
+
#if defined(CONFIG_OF)
/* DT */
static const struct of_device_id da7213_of_match[] = {
- { .compatible = "dlg,da7212", },
- { .compatible = "dlg,da7213", },
+ { .compatible = "dlg,da7212", .data = (void *)DA7212_FIN_MIN_RATE },
+ { .compatible = "dlg,da7213", .data = (void *)DA7213_FIN_MIN_RATE },
{ }
};
MODULE_DEVICE_TABLE(of, da7213_of_match);
@@ -1683,8 +1875,8 @@ MODULE_DEVICE_TABLE(of, da7213_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id da7213_acpi_match[] = {
- { "DLGS7212", 0},
- { "DLGS7213", 0},
+ { "DLGS7212", DA7212_FIN_MIN_RATE },
+ { "DLGS7213", DA7213_FIN_MIN_RATE },
{ },
};
MODULE_DEVICE_TABLE(acpi, da7213_acpi_match);
@@ -1918,27 +2110,65 @@ static int da7213_probe(struct snd_soc_component *component)
pm_runtime_put_sync(component->dev);
/* Check if MCLK provided */
- da7213->mclk = devm_clk_get(component->dev, "mclk");
- if (IS_ERR(da7213->mclk)) {
- if (PTR_ERR(da7213->mclk) != -ENOENT)
- return PTR_ERR(da7213->mclk);
- else
- da7213->mclk = NULL;
- } else {
+ da7213->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(da7213->mclk))
+ return PTR_ERR(da7213->mclk);
+ if (da7213->mclk)
/* Do automatic PLL handling assuming fixed clock until
* set_pll() has been called. This makes the codec usable
* with the simple-audio-card driver. */
da7213->fixed_clk_auto_pll = true;
- }
+
+ /* Default infinite tone gen, start/stop by Kcontrol */
+ snd_soc_component_write(component, DA7213_TONE_GEN_CYCLES, DA7213_BEEP_CYCLES_MASK);
return 0;
}
+static int da7213_runtime_suspend(struct device *dev)
+{
+ struct da7213_priv *da7213 = dev_get_drvdata(dev);
+
+ regcache_cache_only(da7213->regmap, true);
+ regcache_mark_dirty(da7213->regmap);
+ regulator_bulk_disable(DA7213_NUM_SUPPLIES, da7213->supplies);
+
+ return 0;
+}
+
+static int da7213_runtime_resume(struct device *dev)
+{
+ struct da7213_priv *da7213 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_bulk_enable(DA7213_NUM_SUPPLIES, da7213->supplies);
+ if (ret < 0)
+ return ret;
+ regcache_cache_only(da7213->regmap, false);
+ return regcache_sync(da7213->regmap);
+}
+
+static int da7213_suspend(struct snd_soc_component *component)
+{
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+
+ return da7213_runtime_suspend(da7213->dev);
+}
+
+static int da7213_resume(struct snd_soc_component *component)
+{
+ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+
+ return da7213_runtime_resume(da7213->dev);
+}
+
static const struct snd_soc_component_driver soc_component_dev_da7213 = {
.probe = da7213_probe,
.set_bias_level = da7213_set_bias_level,
.controls = da7213_snd_controls,
.num_controls = ARRAY_SIZE(da7213_snd_controls),
+ .suspend = da7213_suspend,
+ .resume = da7213_resume,
.dapm_widgets = da7213_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets),
.dapm_routes = da7213_audio_map,
@@ -1954,6 +2184,7 @@ static const struct regmap_config da7213_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+ .max_register = DA7213_TONE_GEN_OFF_PER,
.reg_defaults = da7213_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults),
.volatile_reg = da7213_volatile_register,
@@ -1980,6 +2211,12 @@ static int da7213_i2c_probe(struct i2c_client *i2c)
if (!da7213)
return -ENOMEM;
+ da7213->fin_min_rate = (uintptr_t)i2c_get_match_data(i2c);
+ if (!da7213->fin_min_rate)
+ return -EINVAL;
+
+ da7213->dev = &i2c->dev;
+
i2c_set_clientdata(i2c, da7213);
/* Get required supplies */
@@ -2008,6 +2245,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);
@@ -2027,36 +2266,12 @@ static void da7213_i2c_remove(struct i2c_client *i2c)
pm_runtime_disable(&i2c->dev);
}
-static int __maybe_unused da7213_runtime_suspend(struct device *dev)
-{
- struct da7213_priv *da7213 = dev_get_drvdata(dev);
-
- regcache_cache_only(da7213->regmap, true);
- regcache_mark_dirty(da7213->regmap);
- regulator_bulk_disable(DA7213_NUM_SUPPLIES, da7213->supplies);
-
- return 0;
-}
-
-static int __maybe_unused da7213_runtime_resume(struct device *dev)
-{
- struct da7213_priv *da7213 = dev_get_drvdata(dev);
- int ret;
-
- ret = regulator_bulk_enable(DA7213_NUM_SUPPLIES, da7213->supplies);
- if (ret < 0)
- return ret;
- regcache_cache_only(da7213->regmap, false);
- regcache_sync(da7213->regmap);
- return 0;
-}
-
static const struct dev_pm_ops da7213_pm = {
- SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL)
+ RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL)
};
static const struct i2c_device_id da7213_i2c_id[] = {
- { "da7213", 0 },
+ { "da7213" },
{ }
};
MODULE_DEVICE_TABLE(i2c, da7213_i2c_id);
@@ -2067,7 +2282,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,
@@ -2078,4 +2293,5 @@ module_i2c_driver(da7213_i2c_driver);
MODULE_DESCRIPTION("ASoC DA7213 Codec driver");
MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_AUTHOR("David Rau <David.Rau.opensource@dm.renesas.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
index 4ca9cfdea06d..29cbf0eb6124 100644
--- a/sound/soc/codecs/da7213.h
+++ b/sound/soc/codecs/da7213.h
@@ -5,6 +5,7 @@
* Copyright (c) 2013 Dialog Semiconductor
*
* Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ * Author: David Rau <David.Rau.opensource@dm.renesas.com>
*/
#ifndef _DA7213_H
@@ -135,13 +136,24 @@
#define DA7213_DAC_NG_ON_THRESHOLD 0xB1
#define DA7213_DAC_NG_CTRL 0xB2
+#define DA7213_TONE_GEN_CFG1 0xB4
+#define DA7213_TONE_GEN_CFG2 0xB5
+#define DA7213_TONE_GEN_CYCLES 0xB6
+#define DA7213_TONE_GEN_FREQ1_L 0xB7
+#define DA7213_TONE_GEN_FREQ1_U 0xB8
+#define DA7213_TONE_GEN_FREQ2_L 0xB9
+#define DA7213_TONE_GEN_FREQ2_U 0xBA
+#define DA7213_TONE_GEN_ON_PER 0xBB
+#define DA7213_TONE_GEN_OFF_PER 0xBC
/*
* Bit fields
*/
+#define DA7213_SWITCH_EN_MAX 0x1
+
/* DA7213_PLL_STATUS = 0x03 */
-#define DA7219_PLL_SRM_LOCK (0x1 << 1)
+#define DA7213_PLL_SRM_LOCK (0x1 << 1)
/* DA7213_SR = 0x22 */
#define DA7213_SR_8000 (0x1 << 0)
@@ -484,6 +496,55 @@
#define DA7213_DAC_NG_EN_SHIFT 7
#define DA7213_DAC_NG_EN_MAX 0x1
+/* DA7213_TONE_GEN_CFG1 = 0xB4 */
+#define DA7213_DTMF_REG_SHIFT 0
+#define DA7213_DTMF_REG_MASK (0xF << 0)
+#define DA7213_DTMF_REG_MAX 16
+#define DA7213_DTMF_EN_SHIFT 4
+#define DA7213_DTMF_EN_MASK (0x1 << 4)
+#define DA7213_START_STOPN_SHIFT 7
+#define DA7213_START_STOPN_MASK (0x1 << 7)
+
+/* DA7213_TONE_GEN_CFG2 = 0xB5 */
+#define DA7213_SWG_SEL_SHIFT 0
+#define DA7213_SWG_SEL_MASK (0x3 << 0)
+#define DA7213_SWG_SEL_MAX 4
+#define DA7213_SWG_SEL_SRAMP (0x3 << 0)
+#define DA7213_TONE_GEN_GAIN_SHIFT 4
+#define DA7213_TONE_GEN_GAIN_MASK (0xF << 4)
+#define DA7213_TONE_GEN_GAIN_MAX 0xF
+#define DA7213_TONE_GEN_GAIN_MINUS_9DB (0x3 << 4)
+#define DA7213_TONE_GEN_GAIN_MINUS_15DB (0x5 << 4)
+
+/* DA7213_TONE_GEN_CYCLES = 0xB6 */
+#define DA7213_BEEP_CYCLES_SHIFT 0
+#define DA7213_BEEP_CYCLES_MASK (0x7 << 0)
+
+/* DA7213_TONE_GEN_FREQ1_L = 0xB7 */
+#define DA7213_FREQ1_L_SHIFT 0
+#define DA7213_FREQ1_L_MASK (0xFF << 0)
+#define DA7213_FREQ_MAX 0xFFFF
+
+/* DA7213_TONE_GEN_FREQ1_U = 0xB8 */
+#define DA7213_FREQ1_U_SHIFT 0
+#define DA7213_FREQ1_U_MASK (0xFF << 0)
+
+/* DA7213_TONE_GEN_FREQ2_L = 0xB9 */
+#define DA7213_FREQ2_L_SHIFT 0
+#define DA7213_FREQ2_L_MASK (0xFF << 0)
+
+/* DA7213_TONE_GEN_FREQ2_U = 0xBA */
+#define DA7213_FREQ2_U_SHIFT 0
+#define DA7213_FREQ2_U_MASK (0xFF << 0)
+
+/* DA7213_TONE_GEN_ON_PER = 0xBB */
+#define DA7213_BEEP_ON_PER_SHIFT 0
+#define DA7213_BEEP_ON_PER_MASK (0x3F << 0)
+#define DA7213_BEEP_ON_OFF_MAX 0x3F
+
+/* DA7213_TONE_GEN_OFF_PER = 0xBC */
+#define DA7213_BEEP_OFF_PER_SHIFT 0
+#define DA7213_BEEP_OFF_PER_MASK (0x3F << 0)
/*
* General defines
@@ -534,10 +595,13 @@ enum da7213_supplies {
/* Codec private data */
struct da7213_priv {
struct regmap *regmap;
+ struct device *dev;
+ struct mutex ctrl_lock;
struct regulator_bulk_data supplies[DA7213_NUM_SUPPLIES];
struct clk *mclk;
unsigned int mclk_rate;
unsigned int out_rate;
+ unsigned int fin_min_rate;
int clk_src;
bool master;
bool alc_calib_auto;
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 3f456b08b809..5c80839704c7 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -9,7 +9,7 @@
#include <linux/clk.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/pm.h>
@@ -425,7 +425,7 @@ static void da7218_alc_calib(struct snd_soc_component *component)
static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
int ret;
@@ -446,7 +446,7 @@ static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *) kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
unsigned int lvalue = ucontrol->value.integer.value[0];
unsigned int rvalue = ucontrol->value.integer.value[1];
@@ -469,7 +469,7 @@ static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mixer_ctrl =
(struct soc_mixer_control *) kcontrol->private_value;
@@ -493,7 +493,7 @@ static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mixer_ctrl =
(struct soc_mixer_control *) kcontrol->private_value;
@@ -513,7 +513,7 @@ static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mixer_ctrl =
(struct soc_mixer_control *) kcontrol->private_value;
@@ -540,7 +540,7 @@ static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mixer_ctrl =
(struct soc_mixer_control *) kcontrol->private_value;
@@ -560,7 +560,7 @@ static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
@@ -585,7 +585,7 @@ static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
@@ -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:
@@ -2285,16 +2285,6 @@ static const struct of_device_id da7218_of_match[] = {
};
MODULE_DEVICE_TABLE(of, da7218_of_match);
-static inline int da7218_of_get_id(struct device *dev)
-{
- const struct of_device_id *id = of_match_device(da7218_of_match, dev);
-
- if (id)
- return (uintptr_t)id->data;
- else
- return -EINVAL;
-}
-
static enum da7218_micbias_voltage
da7218_of_micbias_lvl(struct snd_soc_component *component, u32 val)
{
@@ -2572,6 +2562,7 @@ static int da7218_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -2579,7 +2570,7 @@ static int da7218_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
/* Enable MCLK for transition to ON state */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
if (da7218->mclk) {
ret = clk_prepare_enable(da7218->mclk);
if (ret) {
@@ -2591,7 +2582,7 @@ static int da7218_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Master bias */
snd_soc_component_update_bits(component, DA7218_REFERENCES,
DA7218_BIAS_EN_MASK,
@@ -3043,7 +3034,7 @@ static const struct snd_soc_component_driver soc_component_dev_da7218 = {
* Regmap configs
*/
-static struct reg_default da7218_reg_defaults[] = {
+static const struct reg_default da7218_reg_defaults[] = {
{ DA7218_SYSTEM_ACTIVE, 0x00 },
{ DA7218_CIF_CTRL, 0x00 },
{ DA7218_SPARE1, 0x00 },
@@ -3253,18 +3244,6 @@ static const struct regmap_config da7218_regmap_config = {
* I2C layer
*/
-static const struct i2c_device_id da7218_i2c_id[];
-
-static inline int da7218_i2c_get_id(struct i2c_client *i2c)
-{
- const struct i2c_device_id *id = i2c_match_id(da7218_i2c_id, i2c);
-
- if (id)
- return (uintptr_t)id->driver_data;
- else
- return -EINVAL;
-}
-
static int da7218_i2c_probe(struct i2c_client *i2c)
{
struct da7218_priv *da7218;
@@ -3276,10 +3255,7 @@ static int da7218_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, da7218);
- if (i2c->dev.of_node)
- da7218->dev_id = da7218_of_get_id(&i2c->dev);
- else
- da7218->dev_id = da7218_i2c_get_id(i2c);
+ da7218->dev_id = (uintptr_t)i2c_get_match_data(i2c);
if ((da7218->dev_id != DA7217_DEV_ID) &&
(da7218->dev_id != DA7218_DEV_ID)) {
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
index 9ac2892092b5..7f6a4aea2c7a 100644
--- a/sound/soc/codecs/da7218.h
+++ b/sound/soc/codecs/da7218.h
@@ -1369,7 +1369,7 @@ enum da7218_sys_clk {
};
enum da7218_dev_id {
- DA7217_DEV_ID = 0,
+ DA7217_DEV_ID = 1,
DA7218_DEV_ID,
};
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index c65256bd526d..d9d932a78b71 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -53,15 +53,12 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
struct da7219_aad_priv *da7219_aad =
container_of(work, struct da7219_aad_priv, btn_det_work);
struct snd_soc_component *component = da7219_aad->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
u8 statusa, micbias_ctrl;
bool micbias_up = false;
int retries = 0;
- /* Disable ground switch */
- snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
-
/* Drive headphones/lineout */
snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
DA7219_HP_L_AMP_OE_MASK,
@@ -112,7 +109,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
struct da7219_aad_priv *da7219_aad =
container_of(work, struct da7219_aad_priv, hptest_work);
struct snd_soc_component *component = da7219_aad->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
__le16 tonegen_freq_hptest;
@@ -155,9 +152,6 @@ static void da7219_aad_hptest_work(struct work_struct *work)
tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
}
- /* Disable ground switch */
- snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
-
/* Ensure gain ramping at fastest rate */
gain_ramp_ctrl = snd_soc_component_read(component, DA7219_GAIN_RAMP_CTRL);
snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
@@ -357,15 +351,19 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
{
struct da7219_aad_priv *da7219_aad = data;
struct snd_soc_component *component = da7219_aad->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
u8 events[DA7219_AAD_IRQ_REG_MAX];
u8 statusa;
- int i, report = 0, mask = 0;
+ int i, ret, report = 0, mask = 0;
/* Read current IRQ events */
- regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
- events, DA7219_AAD_IRQ_REG_MAX);
+ ret = regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
+ events, DA7219_AAD_IRQ_REG_MAX);
+ if (ret) {
+ dev_warn_ratelimited(component->dev, "Failed to read IRQ events: %d\n", ret);
+ return IRQ_NONE;
+ }
if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
return IRQ_NONE;
@@ -417,6 +415,11 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
* handle a removal, and we can check at the end of
* hptest if we have a valid result or not.
*/
+
+ cancel_delayed_work_sync(&da7219_aad->jack_det_work);
+ /* Disable ground switch */
+ snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
+
if (statusa & DA7219_JACK_TYPE_STS_MASK) {
report |= SND_JACK_HEADSET;
mask |= SND_JACK_HEADSET | SND_JACK_LINEOUT;
@@ -668,8 +671,10 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
return NULL;
aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);
- if (!aad_pdata)
+ if (!aad_pdata) {
+ fwnode_handle_put(aad_np);
return NULL;
+ }
aad_pdata->irq = i2c->irq;
@@ -693,7 +698,7 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
aad_pdata->mic_det_thr =
da7219_aad_fw_mic_det_thr(dev, fw_val32);
else
- aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
+ aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_200_OHMS;
if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
aad_pdata->jack_ins_deb =
@@ -750,6 +755,8 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
else
aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
+ fwnode_handle_put(aad_np);
+
return aad_pdata;
}
@@ -921,13 +928,18 @@ void da7219_aad_suspend(struct snd_soc_component *component)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct da7219_aad_priv *da7219_aad = da7219->aad;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u8 micbias_ctrl;
+ disable_irq(da7219_aad->irq);
+
if (da7219_aad->jack) {
/* Disable jack detection during suspend */
snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
DA7219_ACCDET_EN_MASK, 0);
+ cancel_delayed_work_sync(&da7219_aad->jack_det_work);
+ /* Disable ground switch */
+ snd_soc_component_update_bits(component, 0xFB, 0x01, 0x00);
/*
* If we have a 4-pole jack inserted, then micbias will be
@@ -950,7 +962,7 @@ void da7219_aad_resume(struct snd_soc_component *component)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct da7219_aad_priv *da7219_aad = da7219->aad;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (da7219_aad->jack) {
/* Re-enable micbias if previously enabled for 4-pole jack */
@@ -966,6 +978,8 @@ void da7219_aad_resume(struct snd_soc_component *component)
DA7219_ACCDET_EN_MASK,
DA7219_ACCDET_EN_MASK);
}
+
+ enable_irq(da7219_aad->irq);
}
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 600c2db58756..298a626df3ad 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -12,7 +12,7 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -254,7 +254,7 @@ static const struct soc_enum da7219_cp_track_mode =
static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret;
@@ -268,7 +268,7 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret;
@@ -282,7 +282,7 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret;
@@ -296,7 +296,7 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret;
@@ -376,7 +376,7 @@ static void da7219_alc_calib(struct snd_soc_component *component)
static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret;
@@ -395,7 +395,7 @@ static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
@@ -414,7 +414,7 @@ static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol,
static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mixer_ctrl =
(struct soc_mixer_control *) kcontrol->private_value;
@@ -441,7 +441,7 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mixer_ctrl =
(struct soc_mixer_control *) kcontrol->private_value;
@@ -1167,17 +1167,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret = 0;
- if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq))
+ mutex_lock(&da7219->pll_lock);
+
+ if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) {
+ mutex_unlock(&da7219->pll_lock);
return 0;
+ }
if ((freq < 2000000) || (freq > 54000000)) {
+ mutex_unlock(&da7219->pll_lock);
dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
freq);
return -EINVAL;
}
- mutex_lock(&da7219->pll_lock);
-
switch (clk_id) {
case DA7219_CLKSRC_MCLK_SQR:
snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
@@ -1309,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:
@@ -1804,6 +1807,7 @@ static int da7219_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1811,7 +1815,7 @@ static int da7219_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
/* Enable MCLK for transition to ON state */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
if (da7219->mclk) {
ret = clk_prepare_enable(da7219->mclk);
if (ret) {
@@ -1824,13 +1828,13 @@ static int da7219_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
/* Master bias */
snd_soc_component_update_bits(component, DA7219_REFERENCES,
DA7219_BIAS_EN_MASK,
DA7219_BIAS_EN_MASK);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) {
/* Remove MCLK */
if (da7219->mclk)
clk_disable_unprepare(da7219->mclk);
@@ -1979,8 +1983,8 @@ static unsigned long da7219_wclk_recalc_rate(struct clk_hw *hw,
}
}
-static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int da7219_wclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
@@ -1989,28 +1993,30 @@ static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
if (!da7219->master)
return -EINVAL;
- if (rate < 11025)
- return 8000;
- else if (rate < 12000)
- return 11025;
- else if (rate < 16000)
- return 12000;
- else if (rate < 22050)
- return 16000;
- else if (rate < 24000)
- return 22050;
- else if (rate < 32000)
- return 24000;
- else if (rate < 44100)
- return 32000;
- else if (rate < 48000)
- return 44100;
- else if (rate < 88200)
- return 48000;
- else if (rate < 96000)
- return 88200;
+ if (req->rate < 11025)
+ req->rate = 8000;
+ else if (req->rate < 12000)
+ req->rate = 11025;
+ else if (req->rate < 16000)
+ req->rate = 12000;
+ else if (req->rate < 22050)
+ req->rate = 16000;
+ else if (req->rate < 24000)
+ req->rate = 22050;
+ else if (req->rate < 32000)
+ req->rate = 24000;
+ else if (req->rate < 44100)
+ req->rate = 32000;
+ else if (req->rate < 48000)
+ req->rate = 44100;
+ else if (req->rate < 88200)
+ req->rate = 48000;
+ else if (req->rate < 96000)
+ req->rate = 88200;
else
- return 96000;
+ req->rate = 96000;
+
+ return 0;
}
static int da7219_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -2067,15 +2073,15 @@ static unsigned long da7219_bclk_get_factor(unsigned long rate,
return 256;
}
-static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int da7219_bclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_BCLK_IDX]);
unsigned long factor;
- if (!*parent_rate || !da7219->master)
+ if (!req->best_parent_rate || !da7219->master)
return -EINVAL;
/*
@@ -2085,9 +2091,11 @@ static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
* parent WCLK rate set and find the appropriate multiplier of BCLK to
* get the rounded down BCLK value.
*/
- factor = da7219_bclk_get_factor(rate, *parent_rate);
+ factor = da7219_bclk_get_factor(req->rate, req->best_parent_rate);
- return *parent_rate * factor;
+ req->rate = req->best_parent_rate * factor;
+
+ return 0;
}
static int da7219_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -2113,12 +2121,12 @@ static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = {
.unprepare = da7219_wclk_unprepare,
.is_prepared = da7219_wclk_is_prepared,
.recalc_rate = da7219_wclk_recalc_rate,
- .round_rate = da7219_wclk_round_rate,
+ .determine_rate = da7219_wclk_determine_rate,
.set_rate = da7219_wclk_set_rate,
},
[DA7219_DAI_BCLK_IDX] = {
.recalc_rate = da7219_bclk_recalc_rate,
- .round_rate = da7219_bclk_round_rate,
+ .determine_rate = da7219_bclk_determine_rate,
.set_rate = da7219_bclk_set_rate,
},
};
@@ -2309,7 +2317,7 @@ static void da7219_handle_pdata(struct snd_soc_component *component)
* Regmap configs
*/
-static struct reg_default da7219_reg_defaults[] = {
+static const struct reg_default da7219_reg_defaults[] = {
{ DA7219_MIC_1_SELECT, 0x00 },
{ DA7219_CIF_TIMEOUT_CTRL, 0x01 },
{ DA7219_SR_24_48, 0x00 },
@@ -2440,7 +2448,7 @@ static const struct regmap_config da7219_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
-static struct reg_sequence da7219_rev_aa_patch[] = {
+static const struct reg_sequence da7219_rev_aa_patch[] = {
{ DA7219_REFERENCES, 0x08 },
};
@@ -2606,12 +2614,13 @@ static void da7219_remove(struct snd_soc_component *component)
static int da7219_suspend(struct snd_soc_component *component)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
/* Suspend AAD if we're not a wake-up source */
if (!da7219->wakeup_source)
da7219_aad_suspend(component);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
return 0;
}
@@ -2619,8 +2628,9 @@ static int da7219_suspend(struct snd_soc_component *component)
static int da7219_resume(struct snd_soc_component *component)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Resume AAD if previously suspended */
if (!da7219->wakeup_source)
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index f8ca1afa8af5..140e449d3ef4 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -323,7 +323,7 @@ static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = enum_ctrl->reg;
unsigned int sel = ucontrol->value.enumerated.item[0];
@@ -351,7 +351,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = enum_ctrl->reg;
int val;
@@ -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;
@@ -1408,6 +1408,7 @@ static int da732x_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1418,7 +1419,7 @@ static int da732x_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Init Codec */
snd_soc_component_write(component, DA732X_REG_REF1,
DA732X_VMID_FASTCHG);
@@ -1546,7 +1547,7 @@ err:
}
static const struct i2c_device_id da732x_i2c_id[] = {
- { "da7320", 0},
+ { "da7320"},
{ }
};
MODULE_DEVICE_TABLE(i2c, da732x_i2c_id);
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index ae20086777b5..a52276e32f2f 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -15,7 +15,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -477,7 +476,7 @@ static int da9055_get_alc_data(struct snd_soc_component *component, u8 reg_val)
static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 reg_val, adc_left, adc_right, mic_left, mic_right;
int avg_left_data, avg_right_data, offset_l, offset_r;
@@ -1161,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;
@@ -1353,12 +1352,14 @@ static struct snd_soc_dai_driver da9055_dai = {
static int da9055_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Enable VMID reference & master bias */
snd_soc_component_update_bits(component, DA9055_REFERENCES,
DA9055_VMID_EN | DA9055_BIAS_EN,
@@ -1512,7 +1513,7 @@ static int da9055_i2c_probe(struct i2c_client *i2c)
* and PMIC, which must be different to operate together.
*/
static const struct i2c_device_id da9055_i2c_id[] = {
- { "da9055-codec", 0 },
+ { "da9055-codec" },
{ }
};
MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
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/es7134.c b/sound/soc/codecs/es7134.c
index f5150d2f95da..441df1523f1c 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -104,7 +104,7 @@ static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
static int es7134_component_probe(struct snd_soc_component *c)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(c);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(c);
struct es7134_data *priv = snd_soc_component_get_drvdata(c);
const struct es7134_chip *chip = priv->chip;
int ret;
diff --git a/sound/soc/codecs/es8311.c b/sound/soc/codecs/es8311.c
new file mode 100644
index 000000000000..0b07a53cc792
--- /dev/null
+++ b/sound/soc/codecs/es8311.c
@@ -0,0 +1,974 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * es8311.c -- es8311 ALSA SoC audio driver
+ *
+ * Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
+ *
+ * Author: Matteo Martelli <matteomartelli3@gmail.com>
+ */
+
+#include "linux/array_size.h"
+#include "sound/pcm.h"
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "es8311.h"
+
+#define ES8311_NUM_RATES 10
+#define ES8311_RATES (SNDRV_PCM_RATE_8000_96000)
+#define ES8311_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct es8311_priv {
+ struct regmap *regmap;
+ struct clk *mclk;
+ unsigned long mclk_freq;
+ bool provider;
+ unsigned int rates[ES8311_NUM_RATES];
+ struct snd_pcm_hw_constraint_list constraints;
+};
+
+static const DECLARE_TLV_DB_SCALE(es8311_adc_vol_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(es8311_pga_gain_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(es8311_adc_scale_tlv, 0, 600, 0);
+
+#define ES8311_DB_LRCK_STEPS \
+ "0.25db/4LRCK", \
+ "0.25db/8LRCK", \
+ "0.25db/16LRCK", \
+ "0.25db/32LRCK", \
+ "0.25db/64LRCK", \
+ "0.25db/128LRCK", \
+ "0.25db/256LRCK", \
+ "0.25db/512LRCK", \
+ "0.25db/1024LRCK", \
+ "0.25db/2048LRCK", \
+ "0.25db/4096LRCK", \
+ "0.25db/8192LRCK", \
+ "0.25db/16384LRCK", \
+ "0.25db/32768LRCK", \
+ "0.25db/65536LRCK",
+
+static const char *const es8311_level_winsize_txt[] = {
+ "0.25db/2LRCK",
+ ES8311_DB_LRCK_STEPS
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ es8311_alc_winsize, ES8311_ADC4,
+ ES8311_ADC4_ALC_WINSIZE_SHIFT, es8311_level_winsize_txt);
+static const DECLARE_TLV_DB_RANGE(es8311_level_tlv,
+ 0, 1, TLV_DB_SCALE_ITEM(-3010, 600, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(-2060, 250, 0),
+ 4, 5, TLV_DB_SCALE_ITEM(-1610, 160, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-1320, 120, 0),
+ 8, 9, TLV_DB_SCALE_ITEM(-1100, 90, 0),
+ 10, 11, TLV_DB_SCALE_ITEM(-930, 80, 0),
+ 12, 15, TLV_DB_SCALE_ITEM(-780, 60, 0),
+);
+
+static const char *const es8311_ramprate_txt[] = {
+ "Disabled",
+ ES8311_DB_LRCK_STEPS
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_adc_ramprate, ES8311_ADC1,
+ ES8311_ADC1_RAMPRATE_SHIFT, es8311_ramprate_txt);
+
+static const char *const es8311_automute_winsize_txt[] = {
+ "2048 samples",
+ "4096 samples",
+ "6144 samples",
+ "8192 samples",
+ "10240 samples",
+ "12288 samples",
+ "14336 samples",
+ "16384 samples",
+ "18432 samples",
+ "20480 samples",
+ "22528 samples",
+ "24576 samples",
+ "26624 samples",
+ "28672 samples",
+ "30720 samples",
+ "32768 samples",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_automute_winsize, ES8311_ADC6,
+ ES8311_ADC6_AUTOMUTE_WS_SHIFT, es8311_automute_winsize_txt);
+static const DECLARE_TLV_DB_RANGE(es8311_automute_ng_tlv,
+ 0, 7, TLV_DB_SCALE_ITEM(-9600, 600, 0),
+ 8, 15, TLV_DB_SCALE_ITEM(-5100, 300, 0),
+);
+static const DECLARE_TLV_DB_SCALE(es8311_automute_vol_tlv, -2800, 400, 0);
+
+static const DECLARE_TLV_DB_SCALE(es8311_dac_vol_tlv, -9550, 50, 0);
+static SOC_ENUM_SINGLE_DECL(
+ es8311_drc_winsize, ES8311_DAC4,
+ ES8311_DAC4_DRC_WINSIZE_SHIFT, es8311_level_winsize_txt);
+static SOC_ENUM_SINGLE_DECL(
+ es8311_dac_ramprate, ES8311_DAC6,
+ ES8311_DAC6_RAMPRATE_SHIFT, es8311_ramprate_txt);
+
+static const char *const es8311_out_mode_txt[] = {
+ "Lineout",
+ "Headphones"
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_out_mode, ES8311_SYS9,
+ ES8311_SYS9_HPSW_SHIFT, es8311_out_mode_txt);
+
+static const struct snd_kcontrol_new es8311_snd_controls[] = {
+ /* Capture path */
+ SOC_SINGLE_TLV("PGA Capture Volume", ES8311_SYS10,
+ ES8311_SYS10_PGAGAIN_SHIFT, ES8311_SYS10_PGAGAIN_MAX, 0,
+ es8311_pga_gain_tlv),
+ SOC_SINGLE("ADC Polarity Invert Capture Switch", ES8311_ADC2,
+ ES8311_ADC2_INV_SHIFT, 1, 0),
+ SOC_SINGLE_TLV("ADC Scale Capture Volume", ES8311_ADC2,
+ ES8311_ADC2_SCALE_SHIFT, ES8311_ADC2_SCALE_MAX, 0,
+ es8311_adc_scale_tlv),
+ SOC_SINGLE_TLV("ADC Capture Volume", ES8311_ADC3,
+ ES8311_ADC3_VOLUME_SHIFT, ES8311_ADC3_VOLUME_MAX, 0,
+ es8311_adc_vol_tlv),
+ SOC_ENUM("ADC Capture Ramp Rate", es8311_adc_ramprate),
+ SOC_SINGLE("ADC Automute Capture Switch", ES8311_ADC4,
+ ES8311_ADC4_AUTOMUTE_EN_SHIFT, 1, 0),
+ SOC_ENUM("ADC Automute Capture Winsize", es8311_automute_winsize),
+ SOC_SINGLE_TLV("ADC Automute Noise Gate Capture Volume", ES8311_ADC6,
+ ES8311_ADC6_AUTOMUTE_NG_SHIFT,
+ ES8311_ADC6_AUTOMUTE_NG_MAX, 0, es8311_automute_ng_tlv),
+ SOC_SINGLE_TLV("ADC Automute Capture Volume", ES8311_ADC7,
+ ES8311_ADC7_AUTOMUTE_VOL_SHIFT,
+ ES8311_ADC7_AUTOMUTE_VOL_MAX, 0,
+ es8311_automute_vol_tlv),
+ SOC_SINGLE("ADC HPF Capture Switch", ES8311_ADC8, ES8311_ADC8_HPF_SHIFT,
+ 1, 0),
+ SOC_SINGLE("ADC EQ Capture Switch", ES8311_ADC8,
+ ES8311_ADC8_EQBYPASS_SHIFT, 1, 1),
+ SOC_SINGLE("ALC Capture Switch", ES8311_ADC4, ES8311_ADC4_ALC_EN_SHIFT,
+ 1, 0),
+ SOC_SINGLE_TLV("ALC Capture Max Volume", ES8311_ADC5,
+ ES8311_ADC5_ALC_MAXLEVEL_SHIFT,
+ ES8311_ADC5_ALC_MAXLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_SINGLE_TLV("ALC Capture Min Volume", ES8311_ADC5,
+ ES8311_ADC5_ALC_MINLEVEL_SHIFT,
+ ES8311_ADC5_ALC_MINLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_ENUM("ALC Capture Winsize", es8311_alc_winsize),
+
+ /* Playback path */
+ SOC_SINGLE_TLV("DAC Playback Volume", ES8311_DAC2, 0,
+ ES8311_DAC2_VOLUME_MAX, 0, es8311_dac_vol_tlv),
+ SOC_SINGLE("DRC Playback Switch", ES8311_DAC4, ES8311_DAC4_DRC_EN_SHIFT,
+ 1, 0),
+ SOC_SINGLE_TLV("DRC Playback Max Volume", ES8311_DAC5,
+ ES8311_DAC5_DRC_MAXLEVEL_SHIFT,
+ ES8311_DAC5_DRC_MAXLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_SINGLE_TLV("DRC Playback Min Volume", ES8311_DAC5,
+ ES8311_DAC5_DRC_MINLEVEL_SHIFT,
+ ES8311_DAC5_DRC_MINLEVEL_MAX, 0, es8311_level_tlv),
+ SOC_ENUM("DRC Playback Winsize", es8311_drc_winsize),
+ SOC_ENUM("DAC Playback Ramp Rate", es8311_dac_ramprate),
+ SOC_SINGLE("DAC EQ Playback Switch", ES8311_DAC6,
+ ES8311_DAC6_EQBYPASS_SHIFT, 1, 1),
+
+ SOC_ENUM("Output Mode", es8311_out_mode),
+};
+
+static const char *const es8311_diff_src_txt[] = {
+ "Disabled",
+ "MIC1P-MIC1N",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_diff_src_enum, ES8311_SYS10,
+ ES8311_SYS10_LINESEL_SHIFT, es8311_diff_src_txt);
+static const struct snd_kcontrol_new es8311_diff_src_mux =
+ SOC_DAPM_ENUM("Differential Source", es8311_diff_src_enum);
+
+static const char *const es8311_dmic_src_txt[] = {
+ "Disabled",
+ "DMIC from MIC1P",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_dmic_src_enum, ES8311_SYS10,
+ ES8311_SYS10_DMIC_ON_SHIFT, es8311_dmic_src_txt);
+static const struct snd_kcontrol_new es8311_dmic_src_mux =
+ SOC_DAPM_ENUM("Digital Mic Source", es8311_dmic_src_enum);
+
+static const char * const es8311_aif1tx_src_txt[] = {
+ "ADC + ADC",
+ "ADC + 0",
+ "0 + ADC",
+ "0 + 0",
+ "DACL + ADC",
+ "ADC + DACR",
+ "DACL + DACR",
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_aif1tx_src_enum, ES8311_GPIO,
+ ES8311_GPIO_ADCDAT_SEL_SHIFT, es8311_aif1tx_src_txt);
+static const struct snd_kcontrol_new es8311_aif1tx_src_mux =
+ SOC_DAPM_ENUM("AIF1TX Source", es8311_aif1tx_src_enum);
+
+static const char * const es8311_dac_src_txt[] = {
+ "Left",
+ "Right"
+};
+static SOC_ENUM_SINGLE_DECL(
+ es8311_dac_src_enum, ES8311_SDP_IN,
+ ES8311_SDP_IN_SEL_SHIFT, es8311_dac_src_txt);
+static const struct snd_kcontrol_new es8311_dac_src_mux =
+ SOC_DAPM_ENUM("Mono DAC Source", es8311_dac_src_enum);
+
+static const struct snd_soc_dapm_widget es8311_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("Bias", ES8311_SYS3, ES8311_SYS3_PDN_IBIASGEN_SHIFT,
+ 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Analog power", ES8311_SYS3,
+ ES8311_SYS3_PDN_ANA_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Vref", ES8311_SYS3, ES8311_SYS3_PDN_VREF_SHIFT, 1,
+ NULL, 0),
+
+ /* Capture path */
+ SND_SOC_DAPM_INPUT("DMIC"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_diff_src_mux),
+ SND_SOC_DAPM_SUPPLY("ADC Bias Gen", ES8311_SYS3,
+ ES8311_SYS3_PDN_ADCBIASGEN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Vref Gen", ES8311_SYS3,
+ ES8311_SYS3_PDN_ADCVREFGEN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_CLKADC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC Analog Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_ANACLKADC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA", ES8311_SYS4, ES8311_SYS4_PDN_PGA_SHIFT, 1, NULL,
+ 0),
+ SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8311_SYS4,
+ ES8311_SYS4_PDN_MOD_SHIFT, 1),
+ SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_dmic_src_mux),
+ SND_SOC_DAPM_MUX("AIF1TX Source Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_aif1tx_src_mux),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, ES8311_SDP_OUT,
+ ES8311_SDP_MUTE_SHIFT, 1),
+
+ /* Playback path */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, ES8311_SDP_IN,
+ ES8311_SDP_MUTE_SHIFT, 1),
+ SND_SOC_DAPM_MUX("Mono DAC Source Mux", SND_SOC_NOPM, 0, 0,
+ &es8311_dac_src_mux),
+ SND_SOC_DAPM_DAC("Mono DAC", NULL, ES8311_SYS8,
+ ES8311_SYS8_PDN_DAC_SHIFT, 1),
+ SND_SOC_DAPM_SUPPLY("DAC Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_CLKDAC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Analog Clock", ES8311_CLKMGR1,
+ ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC Vref Gen", ES8311_SYS3,
+ ES8311_SYS3_PDN_DACVREFGEN_SHIFT, 1, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route es8311_dapm_routes[] = {
+ /* Capture Path */
+ { "MIC1", NULL, "Bias" },
+ { "MIC1", NULL, "Analog power" },
+ { "MIC1", NULL, "Vref" },
+ { "Differential Mux", "MIC1P-MIC1N", "MIC1" },
+ { "PGA", NULL, "Differential Mux" },
+ { "Mono ADC", NULL, "PGA" },
+ { "Mono ADC", NULL, "ADC Bias Gen" },
+ { "Mono ADC", NULL, "ADC Vref Gen" },
+ { "Mono ADC", NULL, "ADC Clock" },
+ { "Mono ADC", NULL, "ADC Analog Clock" },
+ { "Digital Mic Mux", "Disabled", "Mono ADC" },
+ { "Digital Mic Mux", "DMIC from MIC1P", "DMIC" },
+
+ { "AIF1TX Source Mux", "ADC + ADC", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "ADC + 0", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "0 + ADC", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "DACL + ADC", "Digital Mic Mux" },
+ { "AIF1TX Source Mux", "ADC + DACR", "Digital Mic Mux" },
+
+ { "AIF1TX", NULL, "AIF1TX Source Mux" },
+
+ /* Playback Path */
+ { "Mono DAC Source Mux", "Left", "AIF1RX" },
+ { "Mono DAC Source Mux", "Right", "AIF1RX" },
+ { "Mono DAC", NULL, "Mono DAC Source Mux" },
+ { "Mono DAC", NULL, "DAC Clock" },
+ { "Mono DAC", NULL, "DAC Analog Clock" },
+ { "OUT", NULL, "Mono DAC" },
+ { "OUT", NULL, "Bias" },
+ { "OUT", NULL, "Analog power" },
+ { "OUT", NULL, "Vref" },
+ { "OUT", NULL, "DAC Vref Gen" },
+};
+
+/* Bit clock divider values:
+ * from 1 to 20: the register takes the div value - 1
+ * above 20: the register takes the corresponding idx of the div value
+ * in the following table + 20
+ */
+#define ES8311_BCLK_DIV_IDX_OFFSET 20
+static const unsigned int es8311_bclk_divs[] = {
+ 22, 24, 25, 30, 32, 33, 34, 36, 44, 48, 66, 72
+};
+
+struct es8311_mclk_coeff {
+ unsigned int rate;
+ unsigned int mclk;
+ unsigned int div;
+ unsigned int mult;
+ unsigned int div_adc_dac;
+};
+
+#define ES8311_MCLK_MAX_FREQ 49200000
+
+/* Coefficients for common master clock frequencies based on clock table from
+ * documentation. Limited to have a ratio of adc (or dac) clock to lrclk equal
+ * to 256. This to keep the default adc and dac oversampling and adc scale
+ * settings. Internal mclk dividers and multipliers are dynamically adjusted to
+ * support, respectively, multiples (up to x8) and factors (/2,4,8) of listed
+ * mclks frequencies (see es8311_cmp_adj_mclk_coeff).
+ * All rates are supported when mclk/rate ratio is 32, 64, 128, 256, 384 or 512
+ * (upper limit due to max mclk freq of 49.2MHz).
+ */
+static const struct es8311_mclk_coeff es8311_mclk_coeffs[] = {
+ { 8000, 2048000, 1, 1, 1 },
+ { 8000, 6144000, 3, 1, 1 },
+ { 8000, 18432000, 3, 1, 3 },
+ { 11025, 2822400, 1, 1, 1 },
+ { 11025, 8467200, 3, 1, 1 },
+ { 16000, 4096000, 1, 1, 1 },
+ { 16000, 12288000, 3, 1, 1 },
+ { 16000, 18432000, 3, 2, 3 },
+ { 22050, 5644800, 1, 1, 1 },
+ { 22050, 16934400, 3, 1, 1 },
+ { 32000, 8192000, 1, 1, 1 },
+ { 32000, 12288000, 3, 2, 1 },
+ { 32000, 18432000, 3, 4, 3 },
+ { 44100, 11289600, 1, 1, 1 },
+ { 44100, 33868800, 3, 1, 1 },
+ { 48000, 12288000, 1, 1, 1 },
+ { 48000, 18432000, 3, 2, 1 },
+ { 64000, 8192000, 1, 2, 1 },
+ { 64000, 12288000, 3, 4, 1 },
+ { 88200, 11289600, 1, 2, 1 },
+ { 88200, 33868800, 3, 2, 1 },
+ { 96000, 12288000, 1, 2, 1 },
+ { 96000, 18432000, 3, 4, 1 },
+};
+
+/* Compare coeff with provided mclk_freq and adjust it if needed.
+ * If frequencies match, return 0 and the unaltered coeff copy into out_coeff.
+ * If mclk_freq is a valid multiple or factor of coeff mclk freq, return 0 and
+ * the adjusted coeff copy into out_coeff.
+ * Return -EINVAL otherwise.
+ */
+static int es8311_cmp_adj_mclk_coeff(unsigned int mclk_freq,
+ const struct es8311_mclk_coeff *coeff,
+ struct es8311_mclk_coeff *out_coeff)
+{
+ if (WARN_ON_ONCE(!coeff))
+ return -EINVAL;
+
+ unsigned int div = coeff->div;
+ unsigned int mult = coeff->mult;
+ bool match = false;
+
+ if (coeff->mclk == mclk_freq) {
+ match = true;
+ } else if (mclk_freq % coeff->mclk == 0) {
+ div = mclk_freq / coeff->mclk;
+ div *= coeff->div;
+ if (div <= 8)
+ match = true;
+ } else if (coeff->mclk % mclk_freq == 0) {
+ mult = coeff->mclk / mclk_freq;
+ if (mult == 2 || mult == 4 || mult == 8) {
+ mult *= coeff->mult;
+ if (mult <= 8)
+ match = true;
+ }
+ }
+ if (!match)
+ return -EINVAL;
+ if (out_coeff) {
+ *out_coeff = *coeff;
+ out_coeff->div = div;
+ out_coeff->mult = mult;
+ }
+ return 0;
+}
+
+static int es8311_get_mclk_coeff(unsigned int mclk_freq, unsigned int rate,
+ struct es8311_mclk_coeff *out_coeff)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs); i++) {
+ const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i];
+
+ if (coeff->rate != rate)
+ continue;
+
+ int ret =
+ es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, out_coeff);
+ if (ret == 0)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void es8311_set_sysclk_constraints(unsigned int mclk_freq,
+ struct es8311_priv *es8311)
+{
+ unsigned int count = 0;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(es8311_mclk_coeffs) &&
+ count < ARRAY_SIZE(es8311->rates); i++) {
+ const struct es8311_mclk_coeff *coeff = &es8311_mclk_coeffs[i];
+
+ if (count > 0 && coeff->rate == es8311->rates[count - 1])
+ continue;
+
+ int ret = es8311_cmp_adj_mclk_coeff(mclk_freq, coeff, NULL);
+ if (ret == 0)
+ es8311->rates[count++] = coeff->rate;
+ }
+ if (count) {
+ es8311->constraints.list = es8311->rates;
+ es8311->constraints.count = count;
+ }
+}
+
+static int es8311_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ unsigned int mask = ES8311_DAC1_DAC_DSMMUTE |
+ ES8311_DAC1_DAC_DEMMUTE;
+ unsigned int val = mute ? mask : 0;
+
+ regmap_update_bits(es8311->regmap, ES8311_DAC1, mask, val);
+ }
+
+ return 0;
+}
+
+static int es8311_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ if (es8311->constraints.list) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &es8311->constraints);
+ }
+
+ return 0;
+}
+
+static int es8311_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+ unsigned int wl;
+ int par_width = params_width(params);
+
+ switch (par_width) {
+ case 16:
+ wl = ES8311_SDP_WL_16;
+ break;
+ case 18:
+ wl = ES8311_SDP_WL_18;
+ break;
+ case 20:
+ wl = ES8311_SDP_WL_20;
+ break;
+ case 24:
+ wl = ES8311_SDP_WL_24;
+ break;
+ case 32:
+ wl = ES8311_SDP_WL_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ unsigned int width = (unsigned int)par_width;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ snd_soc_component_update_bits(component, ES8311_SDP_IN,
+ ES8311_SDP_WL_MASK,
+ wl << ES8311_SDP_WL_SHIFT);
+ } else {
+ snd_soc_component_update_bits(component, ES8311_SDP_OUT,
+ ES8311_SDP_WL_MASK,
+ wl << ES8311_SDP_WL_SHIFT);
+ }
+
+ if (es8311->mclk_freq > ES8311_MCLK_MAX_FREQ) {
+ dev_err(component->dev, "mclk frequency %lu too high\n",
+ es8311->mclk_freq);
+ return -EINVAL;
+ }
+
+ unsigned int mclk_freq = es8311->mclk_freq;
+ unsigned int rate = params_rate(params);
+ unsigned int clkmgr = ES8311_CLKMGR1_MCLK_ON;
+
+ if (!mclk_freq) {
+ if (es8311->provider) {
+ dev_err(component->dev,
+ "mclk not configured, cannot run as master\n");
+ return -EINVAL;
+ }
+ dev_dbg(component->dev,
+ "mclk not configured, use bclk as internal mclk\n");
+
+ clkmgr = ES8311_CLKMGR1_MCLK_SEL;
+
+ mclk_freq = rate * width * 2;
+ }
+
+ struct es8311_mclk_coeff coeff;
+ int ret = es8311_get_mclk_coeff(mclk_freq, rate, &coeff);
+ if (ret) {
+ dev_err(component->dev, "unable to find mclk coefficient\n");
+ return ret;
+ }
+
+ unsigned int mask = ES8311_CLKMGR1_MCLK_SEL | ES8311_CLKMGR1_MCLK_ON |
+ ES8311_CLKMGR1_BCLK_ON;
+
+ clkmgr |= ES8311_CLKMGR1_BCLK_ON;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR1, mask, clkmgr);
+
+ if (WARN_ON_ONCE(coeff.div == 0 || coeff.div > 8 ||
+ coeff.div_adc_dac == 0 || coeff.div_adc_dac > 8))
+ return -EINVAL;
+
+ unsigned int mult;
+
+ switch (coeff.mult) {
+ case 1:
+ mult = 0;
+ break;
+ case 2:
+ mult = 1;
+ break;
+ case 4:
+ mult = 2;
+ break;
+ case 8:
+ mult = 3;
+ break;
+ default:
+ WARN_ON_ONCE(true);
+ return -EINVAL;
+ }
+
+ mask = ES8311_CLKMGR2_DIV_PRE_MASK | ES8311_CLKMGR2_MULT_PRE_MASK;
+ clkmgr = (coeff.div - 1) << ES8311_CLKMGR2_DIV_PRE_SHIFT |
+ mult << ES8311_CLKMGR2_MULT_PRE_SHIFT;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR2, mask, clkmgr);
+
+ mask = ES8311_CLKMGR5_ADC_DIV_MASK | ES8311_CLKMGR5_DAC_DIV_MASK;
+ clkmgr = (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_ADC_DIV_SHIFT |
+ (coeff.div_adc_dac - 1) << ES8311_CLKMGR5_DAC_DIV_SHIFT;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR5, mask, clkmgr);
+
+ if (es8311->provider) {
+ unsigned int div_lrclk = mclk_freq / rate;
+
+ if (WARN_ON_ONCE(div_lrclk == 0 ||
+ div_lrclk > ES8311_CLKMGR_LRCLK_DIV_MAX + 1))
+ return -EINVAL;
+
+ mask = ES8311_CLKMGR7_LRCLK_DIV_H_MASK;
+ clkmgr = (div_lrclk - 1) >> 8;
+ snd_soc_component_update_bits(component, ES8311_CLKMGR7, mask,
+ clkmgr);
+ clkmgr = (div_lrclk - 1) & 0xFF;
+ snd_soc_component_write(component, ES8311_CLKMGR8, clkmgr);
+
+ if (div_lrclk % (2 * width) != 0) {
+ dev_err(component->dev,
+ "unable to divide mclk %u to generate bclk\n",
+ mclk_freq);
+ return -EINVAL;
+ }
+
+ unsigned int div_bclk = div_lrclk / (2 * width);
+
+ mask = ES8311_CLKMGR6_DIV_BCLK_MASK;
+ if (div_bclk <= ES8311_BCLK_DIV_IDX_OFFSET) {
+ clkmgr = div_bclk - 1;
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(es8311_bclk_divs); i++) {
+ if (es8311_bclk_divs[i] == div_bclk)
+ break;
+ }
+ if (i == ARRAY_SIZE(es8311_bclk_divs)) {
+ dev_err(component->dev,
+ "bclk divider %u not supported\n",
+ div_bclk);
+ return -EINVAL;
+ }
+
+ clkmgr = i + ES8311_BCLK_DIV_IDX_OFFSET;
+ }
+ snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask,
+ clkmgr);
+ }
+
+ return 0;
+}
+
+static int es8311_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ if (freq > ES8311_MCLK_MAX_FREQ) {
+ dev_err(component->dev, "invalid frequency %u: too high\n",
+ freq);
+ return -EINVAL;
+ }
+
+ if (es8311->mclk_freq == freq)
+ return 0;
+
+ es8311->mclk_freq = freq;
+ es8311->constraints.list = NULL;
+ es8311->constraints.count = 0;
+
+ if (freq == 0)
+ return 0;
+
+ int ret = clk_set_rate(es8311->mclk, freq);
+ if (ret) {
+ dev_err(component->dev, "unable to set mclk rate\n");
+ return ret;
+ }
+
+ es8311_set_sysclk_constraints(freq, es8311);
+
+ return ret;
+}
+
+static int es8311_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ /* Master mode */
+ es8311->provider = true;
+
+ snd_soc_component_update_bits(component, ES8311_RESET,
+ ES8311_RESET_MSC,
+ ES8311_RESET_MSC);
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ /* Slave mode */
+ es8311->provider = false;
+ snd_soc_component_update_bits(component, ES8311_RESET,
+ ES8311_RESET_MSC, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ unsigned int sdp = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ sdp |= ES8311_SDP_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ sdp |= ES8311_SDP_FMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dev_err(component->dev, "right justified mode not supported\n");
+ return -EINVAL;
+ case SND_SOC_DAIFMT_DSP_B:
+ sdp |= ES8311_SDP_LRP;
+ fallthrough;
+ case SND_SOC_DAIFMT_DSP_A:
+ sdp |= ES8311_SDP_FMT_DSP;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ default:
+ dev_err(component->dev,
+ "inverted fsync not supported in dsp mode\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ unsigned int clkmgr = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ sdp |= ES8311_SDP_LRP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ clkmgr |= ES8311_CLKMGR6_BCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ clkmgr |= ES8311_CLKMGR6_BCLK_INV;
+ sdp |= ES8311_SDP_LRP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ unsigned int mask = ES8311_CLKMGR6_BCLK_INV;
+
+ snd_soc_component_update_bits(component, ES8311_CLKMGR6, mask, clkmgr);
+
+ mask = ES8311_SDP_FMT_MASK | ES8311_SDP_LRP;
+ snd_soc_component_update_bits(component, ES8311_SDP_IN, mask, sdp);
+ snd_soc_component_update_bits(component, ES8311_SDP_OUT, mask, sdp);
+
+ return 0;
+}
+
+static int es8311_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct es8311_priv *es8311 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
+ int ret = clk_prepare_enable(es8311->mclk);
+ if (ret) {
+ dev_err(component->dev,
+ "unable to prepare mclk\n");
+ return ret;
+ }
+
+ snd_soc_component_update_bits(
+ component, ES8311_SYS3,
+ ES8311_SYS3_PDN_VMIDSEL_MASK,
+ ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED);
+ }
+
+ break;
+ case SND_SOC_BIAS_OFF:
+ clk_disable_unprepare(es8311->mclk);
+ snd_soc_component_update_bits(
+ component, ES8311_SYS3, ES8311_SYS3_PDN_VMIDSEL_MASK,
+ ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops es8311_dai_ops = {
+ .startup = es8311_startup,
+ .hw_params = es8311_hw_params,
+ .mute_stream = es8311_mute,
+ .set_sysclk = es8311_set_sysclk,
+ .set_fmt = es8311_set_dai_fmt,
+ .no_capture_mute = 1,
+};
+
+static struct snd_soc_dai_driver es8311_dai = {
+ .name = "es8311",
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8311_RATES,
+ .formats = ES8311_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ES8311_RATES,
+ .formats = ES8311_FORMATS,
+ },
+ .ops = &es8311_dai_ops,
+ .symmetric_rate = 1,
+};
+
+static void es8311_reset(struct snd_soc_component *component, bool reset)
+{
+ /* Reset procedure:
+ * (1) power down state machine and reset codec blocks then,
+ * (2) after a short delay, power up state machine and leave reset mode.
+ * Specific delay is not documented, using the same as es8316.
+ */
+ unsigned int mask = ES8311_RESET_CSM_ON | ES8311_RESET_RST_MASK;
+
+ if (reset) {
+ /* Enter reset mode */
+ snd_soc_component_update_bits(component, ES8311_RESET, mask,
+ ES8311_RESET_RST_MASK);
+ } else {
+ /* Leave reset mode */
+ usleep_range(5000, 5500);
+ snd_soc_component_update_bits(component, ES8311_RESET, mask,
+ ES8311_RESET_CSM_ON);
+ }
+}
+
+static int es8311_suspend(struct snd_soc_component *component)
+{
+ struct es8311_priv *es8311;
+
+ es8311 = snd_soc_component_get_drvdata(component);
+
+ es8311_reset(component, true);
+
+ regcache_cache_only(es8311->regmap, true);
+ regcache_mark_dirty(es8311->regmap);
+
+ return 0;
+}
+
+static int es8311_resume(struct snd_soc_component *component)
+{
+ struct es8311_priv *es8311;
+
+ es8311 = snd_soc_component_get_drvdata(component);
+
+ es8311_reset(component, false);
+
+ regcache_cache_only(es8311->regmap, false);
+ regcache_sync(es8311->regmap);
+
+ return 0;
+}
+
+static int es8311_component_probe(struct snd_soc_component *component)
+{
+ struct es8311_priv *es8311;
+
+ es8311 = snd_soc_component_get_drvdata(component);
+
+ es8311->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(es8311->mclk)) {
+ dev_err(component->dev, "invalid mclk\n");
+ return PTR_ERR(es8311->mclk);
+ }
+
+ es8311->mclk_freq = clk_get_rate(es8311->mclk);
+ if (es8311->mclk_freq > 0 && es8311->mclk_freq < ES8311_MCLK_MAX_FREQ)
+ es8311_set_sysclk_constraints(es8311->mclk_freq, es8311);
+
+ es8311_reset(component, true);
+ es8311_reset(component, false);
+
+ /* Set minimal power up time */
+ snd_soc_component_write(component, ES8311_SYS1, 0);
+ snd_soc_component_write(component, ES8311_SYS2, 0);
+
+ return 0;
+}
+
+static const struct regmap_config es8311_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ES8311_REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct snd_soc_component_driver es8311_component_driver = {
+ .probe = es8311_component_probe,
+ .suspend = es8311_suspend,
+ .resume = es8311_resume,
+ .set_bias_level = es8311_set_bias_level,
+ .controls = es8311_snd_controls,
+ .num_controls = ARRAY_SIZE(es8311_snd_controls),
+ .dapm_widgets = es8311_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8311_dapm_widgets),
+ .dapm_routes = es8311_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8311_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int es8311_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct es8311_priv *es8311;
+
+ struct device *dev = &i2c_client->dev;
+
+ es8311 = devm_kzalloc(dev, sizeof(*es8311), GFP_KERNEL);
+ if (es8311 == NULL)
+ return -ENOMEM;
+
+ es8311->regmap =
+ devm_regmap_init_i2c(i2c_client, &es8311_regmap_config);
+ if (IS_ERR(es8311->regmap))
+ return PTR_ERR(es8311->regmap);
+
+ i2c_set_clientdata(i2c_client, es8311);
+
+ return devm_snd_soc_register_component(dev, &es8311_component_driver,
+ &es8311_dai, 1);
+}
+
+static const struct i2c_device_id es8311_id[] = {
+ { "es8311" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, es8311_id);
+
+static const struct of_device_id es8311_of_match[] = {
+ {
+ .compatible = "everest,es8311",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, es8311_of_match);
+
+static struct i2c_driver es8311_i2c_driver = {
+ .driver = {
+ .name = "es8311",
+ .of_match_table = es8311_of_match,
+ },
+ .probe = es8311_i2c_probe,
+ .id_table = es8311_id,
+};
+
+module_i2c_driver(es8311_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8311 driver");
+MODULE_AUTHOR("Matteo Martelli <matteomartelli3@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8311.h b/sound/soc/codecs/es8311.h
new file mode 100644
index 000000000000..8a3105bb8443
--- /dev/null
+++ b/sound/soc/codecs/es8311.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * es8311.c -- es8311 ALSA SoC audio driver
+ *
+ * Copyright (C) 2024 Matteo Martelli <matteomartelli3@gmail.com>
+ *
+ * Author: Matteo Martelli <matteomartelli3@gmail.com>
+ */
+
+#ifndef _ES8311_H
+#define _ES8311_H
+
+#include <linux/bitops.h>
+
+#define ES8311_RESET 0x00
+#define ES8311_RESET_CSM_ON BIT(7)
+#define ES8311_RESET_MSC BIT(6)
+#define ES8311_RESET_RST_MASK GENMASK(4, 0)
+
+/* Clock Manager Registers */
+#define ES8311_CLKMGR1 0x01
+#define ES8311_CLKMGR1_MCLK_SEL BIT(7)
+#define ES8311_CLKMGR1_MCLK_ON BIT(5)
+#define ES8311_CLKMGR1_BCLK_ON BIT(4)
+#define ES8311_CLKMGR1_CLKADC_ON_SHIFT 3
+#define ES8311_CLKMGR1_CLKDAC_ON_SHIFT 2
+#define ES8311_CLKMGR1_ANACLKADC_ON_SHIFT 1
+#define ES8311_CLKMGR1_ANACLKDAC_ON_SHIFT 0
+#define ES8311_CLKMGR2 0x02
+#define ES8311_CLKMGR2_DIV_PRE_MASK GENMASK(7, 5)
+#define ES8311_CLKMGR2_DIV_PRE_SHIFT 5
+#define ES8311_CLKMGR2_DIV_PRE_MAX 0x07
+#define ES8311_CLKMGR2_MULT_PRE_MASK GENMASK(4, 3)
+#define ES8311_CLKMGR2_MULT_PRE_SHIFT 3
+#define ES8311_CLKMGR3 0x03
+#define ES8311_CLKMGR4 0x04
+#define ES8311_CLKMGR5 0x05
+#define ES8311_CLKMGR5_ADC_DIV_MASK GENMASK(7, 4)
+#define ES8311_CLKMGR5_ADC_DIV_SHIFT 4
+#define ES8311_CLKMGR5_DAC_DIV_MASK GENMASK(3, 0)
+#define ES8311_CLKMGR5_DAC_DIV_SHIFT 0
+#define ES8311_CLKMGR6 0x06
+#define ES8311_CLKMGR6_BCLK_INV BIT(5)
+#define ES8311_CLKMGR6_DIV_BCLK_MASK GENMASK(4, 0)
+#define ES8311_CLKMGR7 0x07
+#define ES8311_CLKMGR7_LRCLK_DIV_H_MASK GENMASK(3, 0)
+#define ES8311_CLKMGR8 0x08
+#define ES8311_CLKMGR_LRCLK_DIV_MAX 0x0FFF
+
+/* SDP Mode Registers */
+#define ES8311_SDP_IN 0x09
+#define ES8311_SDP_IN_SEL_SHIFT 7
+#define ES8311_SDP_OUT 0x0A
+/* Following values are the same for both SPD_IN and SDP_OUT */
+#define ES8311_SDP_MUTE_SHIFT 6
+#define ES8311_SDP_LRP BIT(5)
+#define ES8311_SDP_WL_MASK GENMASK(4, 2)
+#define ES8311_SDP_WL_SHIFT 2
+#define ES8311_SDP_WL_24 0x00
+#define ES8311_SDP_WL_20 0x01
+#define ES8311_SDP_WL_18 0x02
+#define ES8311_SDP_WL_16 0x03
+#define ES8311_SDP_WL_32 0x04
+#define ES8311_SDP_FMT_MASK GENMASK(1, 0)
+#define ES8311_SDP_FMT_I2S 0x00
+#define ES8311_SDP_FMT_LEFT_J 0x01
+#define ES8311_SDP_FMT_DSP 0x03
+
+/* System registers */
+#define ES8311_SYS1 0x0B
+#define ES8311_SYS2 0x0C
+#define ES8311_SYS3 0x0D
+#define ES8311_SYS3_PDN_ANA_SHIFT 7
+#define ES8311_SYS3_PDN_IBIASGEN_SHIFT 6
+#define ES8311_SYS3_PDN_ADCBIASGEN_SHIFT 5
+#define ES8311_SYS3_PDN_ADCVREFGEN_SHIFT 4
+#define ES8311_SYS3_PDN_DACVREFGEN_SHIFT 3
+#define ES8311_SYS3_PDN_VREF_SHIFT 2
+#define ES8311_SYS3_PDN_VMIDSEL_MASK GENMASK(1, 0)
+#define ES8311_SYS3_PDN_VMIDSEL_POWER_DOWN 0
+#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_NORMAL_SPEED 1
+#define ES8311_SYS3_PDN_VMIDSEL_NORMAL_OPERATION 2
+#define ES8311_SYS3_PDN_VMIDSEL_STARTUP_FAST_SPEED 3
+#define ES8311_SYS4 0x0E
+#define ES8311_SYS4_PDN_PGA_SHIFT 6
+#define ES8311_SYS4_PDN_MOD_SHIFT 5
+#define ES8311_SYS5 0x0F
+#define ES8311_SYS6 0x10
+#define ES8311_SYS7 0x11
+#define ES8311_SYS8 0x12
+#define ES8311_SYS8_PDN_DAC_SHIFT 1
+#define ES8311_SYS9 0x13
+#define ES8311_SYS9_HPSW_SHIFT 4
+#define ES8311_SYS10 0x14
+#define ES8311_SYS10_DMIC_ON_SHIFT 6
+#define ES8311_SYS10_LINESEL_SHIFT 4
+#define ES8311_SYS10_PGAGAIN_SHIFT 0
+#define ES8311_SYS10_PGAGAIN_MAX 0x0A
+
+/* ADC Registers*/
+#define ES8311_ADC1 0x15
+#define ES8311_ADC1_RAMPRATE_SHIFT 4
+#define ES8311_ADC2 0x16
+#define ES8311_ADC2_INV_SHIFT 4
+#define ES8311_ADC2_SCALE_SHIFT 0
+#define ES8311_ADC2_SCALE_MAX 0x07
+#define ES8311_ADC3 0x17
+#define ES8311_ADC3_VOLUME_SHIFT 0
+#define ES8311_ADC3_VOLUME_MAX 0xFF
+#define ES8311_ADC4 0x18
+#define ES8311_ADC4_ALC_EN_SHIFT 7
+#define ES8311_ADC4_AUTOMUTE_EN_SHIFT 6
+#define ES8311_ADC4_ALC_WINSIZE_SHIFT 0
+#define ES8311_ADC5 0x19
+#define ES8311_ADC5_ALC_MAXLEVEL_SHIFT 4
+#define ES8311_ADC5_ALC_MAXLEVEL_MAX 0x0F
+#define ES8311_ADC5_ALC_MINLEVEL_SHIFT 0
+#define ES8311_ADC5_ALC_MINLEVEL_MAX 0x0F
+#define ES8311_ADC6 0x1A
+#define ES8311_ADC6_AUTOMUTE_WS_SHIFT 4
+#define ES8311_ADC6_AUTOMUTE_NG_SHIFT 0
+#define ES8311_ADC6_AUTOMUTE_NG_MAX 0x0F
+
+#define ES8311_ADC7 0x1B
+#define ES8311_ADC7_AUTOMUTE_VOL_SHIFT 5
+#define ES8311_ADC7_AUTOMUTE_VOL_MAX 0x07
+#define ES8311_ADC8 0x1C
+#define ES8311_ADC8_EQBYPASS_SHIFT 6
+#define ES8311_ADC8_HPF_SHIFT 5
+
+/* DAC Registers */
+#define ES8311_DAC1 0x31
+#define ES8311_DAC1_DAC_DSMMUTE BIT(6)
+#define ES8311_DAC1_DAC_DEMMUTE BIT(5)
+#define ES8311_DAC2 0x32
+#define ES8311_DAC2_VOLUME_MAX 0xFF
+#define ES8311_DAC3 0x33
+#define ES8311_DAC4 0x34
+#define ES8311_DAC4_DRC_EN_SHIFT 7
+#define ES8311_DAC4_DRC_WINSIZE_SHIFT 0
+#define ES8311_DAC5 0x35
+#define ES8311_DAC5_DRC_MAXLEVEL_SHIFT 4
+#define ES8311_DAC5_DRC_MAXLEVEL_MAX 0x0F
+#define ES8311_DAC5_DRC_MINLEVEL_SHIFT 0
+#define ES8311_DAC5_DRC_MINLEVEL_MAX 0x0F
+#define ES8311_DAC6 0x37
+#define ES8311_DAC6_RAMPRATE_SHIFT 4
+#define ES8311_DAC6_EQBYPASS_SHIFT 3
+
+/* GPIO Registers */
+#define ES8311_GPIO 0x44
+#define ES8311_GPIO_ADC2DAC_SEL_SHIFT 7
+#define ES8311_GPIO_ADCDAT_SEL_SHIFT 4
+
+/* Chip Info Registers */
+#define ES8311_CHIPID1 0xFD /* 0x83 */
+#define ES8311_CHIPID2 0xFE /* 0x11 */
+#define ES8311_CHIPVER 0xFF
+
+#define ES8311_REG_MAX 0xFF
+
+#endif
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 069f1ce1cd50..9245c33700de 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -27,9 +27,8 @@
* MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
* Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
*/
-#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
static const unsigned int supported_mclk_lrck_ratios[] = {
- 256, 384, 400, 512, 768, 1024
+ 256, 384, 400, 500, 512, 768, 1024
};
struct es8316_priv {
@@ -40,7 +39,9 @@ struct es8316_priv {
struct snd_soc_jack *jack;
int irq;
unsigned int sysclk;
- unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
+ /* ES83xx supports halving the MCLK so it supports twice as many rates
+ */
+ unsigned int allowed_rates[ARRAY_SIZE(supported_mclk_lrck_ratios) * 2];
struct snd_pcm_hw_constraint_list sysclk_constraints;
bool jd_inverted;
};
@@ -100,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),
@@ -153,7 +154,7 @@ static const char * const es8316_dmic_txt[] = {
"dmic data at high level",
"dmic data at low level",
};
-static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
+static const unsigned int es8316_dmic_values[] = { 0, 2, 3 };
static const struct soc_enum es8316_dmic_src_enum =
SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3,
ARRAY_SIZE(es8316_dmic_txt),
@@ -382,11 +383,17 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/* Limit supported sample rates to ones that can be autodetected
* by the codec running in slave mode.
*/
- for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
+ for (i = 0; i < ARRAY_SIZE(supported_mclk_lrck_ratios); i++) {
const unsigned int ratio = supported_mclk_lrck_ratios[i];
if (freq % ratio == 0)
es8316->allowed_rates[count++] = freq / ratio;
+
+ /* We also check if the halved MCLK produces a valid rate
+ * since the codec supports halving the MCLK.
+ */
+ if ((freq / ratio) % 2 == 0)
+ es8316->allowed_rates[count++] = freq / ratio / 2;
}
if (count) {
@@ -470,19 +477,42 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
u8 bclk_divider;
u16 lrck_divider;
int i;
+ unsigned int clk = es8316->sysclk / 2;
+ bool clk_valid = false;
+
+ /* We will start with halved sysclk and see if we can use it
+ * for proper clocking. This is to minimise the risk of running
+ * the CODEC with a too high frequency. We have an SKU where
+ * the sysclk frequency is 48Mhz and this causes the sound to be
+ * sped up. If we can run with a halved sysclk, we will use it,
+ * if we can't use it, then full sysclk will be used.
+ */
+ do {
+ /* Validate supported sample rates that are autodetected from MCLK */
+ for (i = 0; i < ARRAY_SIZE(supported_mclk_lrck_ratios); i++) {
+ const unsigned int ratio = supported_mclk_lrck_ratios[i];
+
+ if (clk % ratio != 0)
+ continue;
+ if (clk / ratio == params_rate(params))
+ break;
+ }
+ if (i == ARRAY_SIZE(supported_mclk_lrck_ratios)) {
+ if (clk == es8316->sysclk)
+ return -EINVAL;
+ clk = es8316->sysclk;
+ } else {
+ clk_valid = true;
+ }
+ } while (!clk_valid);
- /* Validate supported sample rates that are autodetected from MCLK */
- for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
- const unsigned int ratio = supported_mclk_lrck_ratios[i];
-
- if (es8316->sysclk % ratio != 0)
- continue;
- if (es8316->sysclk / ratio == params_rate(params))
- break;
+ if (clk != es8316->sysclk) {
+ snd_soc_component_update_bits(component, ES8316_CLKMGR_CLKSW,
+ ES8316_CLKMGR_CLKSW_MCLK_DIV,
+ ES8316_CLKMGR_CLKSW_MCLK_DIV);
}
- if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS)
- return -EINVAL;
- lrck_divider = es8316->sysclk / params_rate(params);
+
+ lrck_divider = clk / params_rate(params);
bclk_divider = lrck_divider / 4;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -494,6 +524,7 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
bclk_divider /= 20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
wordlen = ES8316_SERDATA2_LEN_24;
bclk_divider /= 24;
break;
@@ -525,7 +556,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute, int direction)
}
#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops es8316_ops = {
.startup = es8316_pcm_startup,
@@ -559,7 +590,7 @@ static struct snd_soc_dai_driver es8316_dai = {
static void es8316_enable_micbias_for_mic_gnd_short_detect(
struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias");
@@ -574,7 +605,7 @@ static void es8316_enable_micbias_for_mic_gnd_short_detect(
static void es8316_disable_micbias_for_mic_gnd_short_detect(
struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias");
@@ -825,7 +856,7 @@ static const struct regmap_config es8316_regmap = {
.use_single_write = true,
.max_register = 0x53,
.volatile_reg = es8316_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int es8316_i2c_probe(struct i2c_client *i2c_client)
@@ -864,7 +895,7 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client)
}
static const struct i2c_device_id es8316_i2c_id[] = {
- {"es8316", 0 },
+ {"es8316" },
{}
};
MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h
index c335138e2837..0ff16f948690 100644
--- a/sound/soc/codecs/es8316.h
+++ b/sound/soc/codecs/es8316.h
@@ -129,4 +129,7 @@
#define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02
#define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04
+/* ES8316_CLKMGR_CLKSW */
+#define ES8316_CLKMGR_CLKSW_MCLK_DIV 0x80
+
#endif
diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c
new file mode 100644
index 000000000000..eb85b71e87f3
--- /dev/null
+++ b/sound/soc/codecs/es8323.c
@@ -0,0 +1,791 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// es8323.c -- es8323 ALSA SoC audio driver
+//
+// Copyright 2024 Rockchip Electronics Co. Ltd.
+// Copyright 2024 Everest Semiconductor Co.,Ltd.
+// Copyright 2024 Loongson Technology Co.,Ltd.
+//
+// Author: Mark Brown <broonie@kernel.org>
+// Jianqun Xu <jay.xu@rock-chips.com>
+// Nickey Yang <nickey.yang@rock-chips.com>
+// Further cleanup and restructuring by:
+// Binbin Zhou <zhoubinbin@loongson.cn>
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "es8323.h"
+
+struct es8323_priv {
+ unsigned int sysclk;
+ struct clk *mclk;
+ struct regmap *regmap;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ struct snd_soc_component *component;
+};
+
+/* es8323 register cache */
+static const struct reg_default es8323_reg_defaults[] = {
+ { ES8323_CONTROL1, 0x06 },
+ { ES8323_CONTROL2, 0x1c },
+ { ES8323_CHIPPOWER, 0xc3 },
+ { ES8323_ADCPOWER, 0xfc },
+ { ES8323_DACPOWER, 0xc0 },
+ { ES8323_CHIPLOPOW1, 0x00 },
+ { ES8323_CHIPLOPOW2, 0x00 },
+ { ES8323_ANAVOLMANAG, 0x7c },
+ { ES8323_MASTERMODE, 0x80 },
+ { ES8323_ADCCONTROL1, 0x00 },
+ { ES8323_ADCCONTROL2, 0x00 },
+ { ES8323_ADCCONTROL3, 0x06 },
+ { ES8323_ADCCONTROL4, 0x00 },
+ { ES8323_ADCCONTROL5, 0x06 },
+ { ES8323_ADCCONTROL6, 0x30 },
+ { ES8323_ADC_MUTE, 0x30 },
+ { ES8323_LADC_VOL, 0xc0 },
+ { ES8323_RADC_VOL, 0xc0 },
+ { ES8323_ADCCONTROL10, 0x38 },
+ { ES8323_ADCCONTROL11, 0xb0 },
+ { ES8323_ADCCONTROL12, 0x32 },
+ { ES8323_ADCCONTROL13, 0x06 },
+ { ES8323_ADCCONTROL14, 0x00 },
+ { ES8323_DACCONTROL1, 0x00 },
+ { ES8323_DACCONTROL2, 0x06 },
+ { ES8323_DAC_MUTE, 0x30 },
+ { ES8323_LDAC_VOL, 0xc0 },
+ { ES8323_RDAC_VOL, 0xc0 },
+ { ES8323_DACCONTROL6, 0x08 },
+ { ES8323_DACCONTROL7, 0x06 },
+ { ES8323_DACCONTROL8, 0x1f },
+ { ES8323_DACCONTROL9, 0xf7 },
+ { ES8323_DACCONTROL10, 0xfd },
+ { ES8323_DACCONTROL11, 0xff },
+ { ES8323_DACCONTROL12, 0x1f },
+ { ES8323_DACCONTROL13, 0xf7 },
+ { ES8323_DACCONTROL14, 0xfd },
+ { ES8323_DACCONTROL15, 0xff },
+ { ES8323_DACCONTROL16, 0x00 },
+ { ES8323_DACCONTROL17, 0x38 },
+ { ES8323_DACCONTROL18, 0x38 },
+ { ES8323_DACCONTROL19, 0x38 },
+ { ES8323_DACCONTROL20, 0x38 },
+ { ES8323_DACCONTROL21, 0x38 },
+ { ES8323_DACCONTROL22, 0x38 },
+ { ES8323_DACCONTROL23, 0x00 },
+ { ES8323_LOUT1_VOL, 0x00 },
+ { ES8323_ROUT1_VOL, 0x00 },
+};
+
+static const char *const es8323_stereo_3d_texts[] = { "No 3D ", "Level 1", "Level 2", "Level 3",
+ "Level 4", "Level 5", "Level 6", "Level 7" };
+static SOC_ENUM_SINGLE_DECL(es8323_stereo_3d_enum, ES8323_DACCONTROL7, 2, es8323_stereo_3d_texts);
+
+static const char *const es8323_alc_func_texts[] = { "Off", "Right", "Left", "Stereo" };
+static SOC_ENUM_SINGLE_DECL(es8323_alc_function_enum,
+ ES8323_ADCCONTROL10, 6, es8323_alc_func_texts);
+
+static const char *const es8323_ng_type_texts[] = { "Constant PGA Gain", "Mute ADC Output" };
+static SOC_ENUM_SINGLE_DECL(es8323_alc_ng_type_enum, ES8323_ADCCONTROL14, 1, es8323_ng_type_texts);
+
+static const char *const es8323_deemph_texts[] = { "None", "32Khz", "44.1Khz", "48Khz" };
+static SOC_ENUM_SINGLE_DECL(es8323_playback_deemphasis_enum,
+ ES8323_DACCONTROL6, 6, es8323_deemph_texts);
+
+static const char *const es8323_adcpol_texts[] = { "Normal", "L Invert",
+ "R Invert", "L + R Invert" };
+static SOC_ENUM_SINGLE_DECL(es8323_capture_polarity_enum,
+ ES8323_ADCCONTROL6, 6, es8323_adcpol_texts);
+
+static const DECLARE_TLV_DB_SCALE(es8323_adc_tlv, -9600, 50, 1);
+static const DECLARE_TLV_DB_SCALE(es8323_dac_tlv, -9600, 50, 1);
+static const DECLARE_TLV_DB_SCALE(es8323_out_tlv, -4500, 150, 0);
+static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv2, -15, 300, 0);
+
+static const struct snd_kcontrol_new es8323_snd_controls[] = {
+ SOC_ENUM("3D Mode", es8323_stereo_3d_enum),
+ SOC_ENUM("ALC Capture Function", es8323_alc_function_enum),
+ SOC_ENUM("ALC Capture NG Type", es8323_alc_ng_type_enum),
+ SOC_ENUM("Playback De-emphasis", es8323_playback_deemphasis_enum),
+ SOC_ENUM("Capture Polarity", es8323_capture_polarity_enum),
+ SOC_SINGLE("ALC Capture ZC Switch", ES8323_ADCCONTROL13, 6, 1, 0),
+ SOC_SINGLE("ALC Capture Decay Time", ES8323_ADCCONTROL12, 4, 15, 0),
+ SOC_SINGLE("ALC Capture Attack Time", ES8323_ADCCONTROL12, 0, 15, 0),
+ SOC_SINGLE("ALC Capture NG Threshold", ES8323_ADCCONTROL14, 3, 31, 0),
+ SOC_SINGLE("ALC Capture NG Switch", ES8323_ADCCONTROL14, 0, 1, 0),
+ SOC_SINGLE("ZC Timeout Switch", ES8323_ADCCONTROL13, 6, 1, 0),
+ SOC_SINGLE("Capture Mute Switch", ES8323_ADC_MUTE, 2, 1, 0),
+ SOC_SINGLE_TLV("Left Channel Capture Volume", ES8323_ADCCONTROL1, 4, 8,
+ 0, es8323_bypass_tlv),
+ SOC_SINGLE_TLV("Right Channel Capture Volume", ES8323_ADCCONTROL1, 0,
+ 8, 0, es8323_bypass_tlv),
+ SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", ES8323_DACCONTROL17, 3,
+ 7, 1, es8323_bypass_tlv2),
+ SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", ES8323_DACCONTROL20,
+ 3, 7, 1, es8323_bypass_tlv2),
+ SOC_DOUBLE_R_TLV("PCM Volume", ES8323_LDAC_VOL, ES8323_RDAC_VOL,
+ 0, 192, 1, es8323_dac_tlv),
+ SOC_DOUBLE_R_TLV("Capture Digital Volume", ES8323_LADC_VOL,
+ ES8323_RADC_VOL, 0, 192, 1, es8323_adc_tlv),
+ SOC_DOUBLE_R_TLV("Output 1 Playback Volume", ES8323_LOUT1_VOL,
+ ES8323_ROUT1_VOL, 0, 33, 0, es8323_out_tlv),
+ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", ES8323_LOUT2_VOL,
+ ES8323_ROUT2_VOL, 0, 33, 0, es8323_out_tlv),
+};
+
+/* Left DAC Route */
+static const char *const es8323_pga_sell[] = { "Line 1L", "Line 2L", "NC", "DifferentialL" };
+static SOC_ENUM_SINGLE_DECL(es8323_left_dac_enum, ES8323_ADCCONTROL2, 6, es8323_pga_sell);
+static const struct snd_kcontrol_new es8323_left_dac_mux_controls =
+ SOC_DAPM_ENUM("Left DAC Route", es8323_left_dac_enum);
+
+/* Right DAC Route */
+static const char *const es8323_pga_selr[] = { "Line 1R", "Line 2R", "NC", "DifferentialR" };
+static SOC_ENUM_SINGLE_DECL(es8323_right_dac_enum, ES8323_ADCCONTROL2, 4, es8323_pga_selr);
+static const struct snd_kcontrol_new es8323_right_dac_mux_controls =
+ SOC_DAPM_ENUM("Right DAC Route", es8323_right_dac_enum);
+
+/* Left Line Mux */
+static const char *const es8323_lin_sell[] = { "Line 1L", "Line 2L", "NC", "MicL" };
+static SOC_ENUM_SINGLE_DECL(es8323_llin_enum, ES8323_DACCONTROL16, 3, es8323_lin_sell);
+static const struct snd_kcontrol_new es8323_left_line_controls =
+ SOC_DAPM_ENUM("LLIN Mux", es8323_llin_enum);
+
+/* Right Line Mux */
+static const char *const es8323_lin_selr[] = { "Line 1R", "Line 2R", "NC", "MicR" };
+static SOC_ENUM_SINGLE_DECL(es8323_rlin_enum, ES8323_DACCONTROL16, 0, es8323_lin_selr);
+static const struct snd_kcontrol_new es8323_right_line_controls =
+ SOC_DAPM_ENUM("RLIN Mux", es8323_rlin_enum);
+
+/* Differential Mux */
+static const char *const es8323_diffmux_sel[] = { "Line 1", "Line 2" };
+static SOC_ENUM_SINGLE_DECL(es8323_diffmux_enum, ES8323_ADCCONTROL3, 7, es8323_diffmux_sel);
+static const struct snd_kcontrol_new es8323_diffmux_controls =
+ SOC_DAPM_ENUM("Route2", es8323_diffmux_enum);
+
+/* Mono ADC Mux */
+static const char *const es8323_mono_adc_mux[] = { "Stereo", "Mono (Left)", "Mono (Right)" };
+static SOC_ENUM_SINGLE_DECL(es8323_mono_adc_mux_enum, ES8323_ADCCONTROL3, 3, es8323_mono_adc_mux);
+static const struct snd_kcontrol_new es8323_mono_adc_mux_controls =
+ SOC_DAPM_ENUM("Mono Mux", es8323_mono_adc_mux_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new es8323_left_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Left Playback Switch", ES8323_DACCONTROL17, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left Bypass Switch", ES8323_DACCONTROL17, 6, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new es8323_right_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Right Playback Switch", ES8323_DACCONTROL20, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right Bypass Switch", ES8323_DACCONTROL20, 6, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("LINPUT1"),
+ SND_SOC_DAPM_INPUT("LINPUT2"),
+ SND_SOC_DAPM_INPUT("RINPUT1"),
+ SND_SOC_DAPM_INPUT("RINPUT2"),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias", SND_SOC_NOPM, 3, 1),
+
+ /* Muxes */
+ SND_SOC_DAPM_MUX("Left PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_left_dac_mux_controls),
+ SND_SOC_DAPM_MUX("Right PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_right_dac_mux_controls),
+ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, &es8323_diffmux_controls),
+ SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls),
+ SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls),
+ SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, &es8323_left_line_controls),
+ SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, &es8323_right_line_controls),
+
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 4, 1),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 5, 1),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8323_DACPOWER, 6, 1),
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8323_DACPOWER, 7, 1),
+
+ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+ &es8323_left_mixer_controls[0],
+ ARRAY_SIZE(es8323_left_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+ &es8323_right_mixer_controls[0],
+ ARRAY_SIZE(es8323_right_mixer_controls)),
+
+ SND_SOC_DAPM_PGA("Right ADC Power", SND_SOC_NOPM, 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Left ADC Power", SND_SOC_NOPM, 7, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Out 2", ES8323_DACPOWER, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 2", ES8323_DACPOWER, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Out 1", ES8323_DACPOWER, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Left Out 1", ES8323_DACPOWER, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LAMP", ES8323_ADCCONTROL1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RAMP", ES8323_ADCCONTROL1, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("LOUT1"),
+ SND_SOC_DAPM_OUTPUT("ROUT1"),
+ SND_SOC_DAPM_OUTPUT("LOUT2"),
+ SND_SOC_DAPM_OUTPUT("ROUT2"),
+ SND_SOC_DAPM_OUTPUT("VREF"),
+};
+
+static const struct snd_soc_dapm_route es8323_dapm_routes[] = {
+ /*12.22*/
+ {"Left PGA Mux", "Line 1L", "LINPUT1"},
+ {"Left PGA Mux", "Line 2L", "LINPUT2"},
+ {"Left PGA Mux", "DifferentialL", "Differential Mux"},
+
+ {"Right PGA Mux", "Line 1R", "RINPUT1"},
+ {"Right PGA Mux", "Line 2R", "RINPUT2"},
+ {"Right PGA Mux", "DifferentialR", "Differential Mux"},
+
+ {"Differential Mux", "Line 1", "LINPUT1"},
+ {"Differential Mux", "Line 1", "RINPUT1"},
+ {"Differential Mux", "Line 2", "LINPUT2"},
+ {"Differential Mux", "Line 2", "RINPUT2"},
+
+ {"Left ADC Mux", "Stereo", "Right PGA Mux"},
+ {"Left ADC Mux", "Stereo", "Left PGA Mux"},
+ {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+
+ {"Right ADC Mux", "Stereo", "Left PGA Mux"},
+ {"Right ADC Mux", "Stereo", "Right PGA Mux"},
+ {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+
+ {"Left ADC Power", NULL, "Left ADC Mux"},
+ {"Right ADC Power", NULL, "Right ADC Mux"},
+ {"Left ADC", NULL, "Left ADC Power"},
+ {"Right ADC", NULL, "Right ADC Power"},
+
+ {"Left Line Mux", "Line 1L", "LINPUT1"},
+ {"Left Line Mux", "Line 2L", "LINPUT2"},
+ {"Left Line Mux", "MicL", "Left PGA Mux"},
+
+ {"Right Line Mux", "Line 1R", "RINPUT1"},
+ {"Right Line Mux", "Line 2R", "RINPUT2"},
+ {"Right Line Mux", "MicR", "Right PGA Mux"},
+
+ {"Left Mixer", "Left Playback Switch", "Left DAC"},
+ {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+
+ {"Right Mixer", "Right Playback Switch", "Right DAC"},
+ {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+ {"Left Out 1", NULL, "Left Mixer"},
+ {"LOUT1", NULL, "Left Out 1"},
+ {"Right Out 1", NULL, "Right Mixer"},
+ {"ROUT1", NULL, "Right Out 1"},
+
+ {"Left Out 2", NULL, "Left Mixer"},
+ {"LOUT2", NULL, "Left Out 2"},
+ {"Right Out 2", NULL, "Right Mixer"},
+ {"ROUT2", NULL, "Right Out 2"},
+};
+
+struct coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u8 sr:4;
+ u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct coeff_div es8323_coeff_div[] = {
+ /* 8k */
+ {12288000, 8000, 1536, 0xa, 0x0},
+ {11289600, 8000, 1408, 0x9, 0x0},
+ {18432000, 8000, 2304, 0xc, 0x0},
+ {16934400, 8000, 2112, 0xb, 0x0},
+ {12000000, 8000, 1500, 0xb, 0x1},
+
+ /* 11.025k */
+ {11289600, 11025, 1024, 0x7, 0x0},
+ {16934400, 11025, 1536, 0xa, 0x0},
+ {12000000, 11025, 1088, 0x9, 0x1},
+
+ /* 16k */
+ {12288000, 16000, 768, 0x6, 0x0},
+ {18432000, 16000, 1152, 0x8, 0x0},
+ {12000000, 16000, 750, 0x7, 0x1},
+
+ /* 22.05k */
+ {11289600, 22050, 512, 0x4, 0x0},
+ {16934400, 22050, 768, 0x6, 0x0},
+ {12000000, 22050, 544, 0x6, 0x1},
+
+ /* 32k */
+ {12288000, 32000, 384, 0x3, 0x0},
+ {18432000, 32000, 576, 0x5, 0x0},
+ {12000000, 32000, 375, 0x4, 0x1},
+
+ /* 44.1k */
+ {11289600, 44100, 256, 0x2, 0x0},
+ {16934400, 44100, 384, 0x3, 0x0},
+ {12000000, 44100, 272, 0x3, 0x1},
+
+ /* 48k */
+ {12288000, 48000, 256, 0x2, 0x0},
+ {18432000, 48000, 384, 0x3, 0x0},
+ {12000000, 48000, 250, 0x2, 0x1},
+
+ /* 88.2k */
+ {11289600, 88200, 128, 0x0, 0x0},
+ {16934400, 88200, 192, 0x1, 0x0},
+ {12000000, 88200, 136, 0x1, 0x1},
+
+ /* 96k */
+ {12288000, 96000, 128, 0x0, 0x0},
+ {18432000, 96000, 192, 0x1, 0x0},
+ {12000000, 96000, 125, 0x0, 0x1},
+};
+
+static unsigned int rates_12288[] = {
+ 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+ .count = ARRAY_SIZE(rates_12288),
+ .list = rates_12288,
+};
+
+static unsigned int rates_112896[] = {
+ 8000, 11025, 22050, 44100,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_112896 = {
+ .count = ARRAY_SIZE(rates_112896),
+ .list = rates_112896,
+};
+
+static unsigned int rates_12[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 48000, 88235, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12 = {
+ .count = ARRAY_SIZE(rates_12),
+ .list = rates_12,
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(es8323_coeff_div); i++) {
+ if (es8323_coeff_div[i].rate == rate &&
+ es8323_coeff_div[i].mclk == mclk)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int es8323_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ switch (freq) {
+ case 11289600:
+ case 18432000:
+ case 22579200:
+ case 36864000:
+ es8323->sysclk_constraints = &constraints_112896;
+ break;
+ case 12288000:
+ case 16934400:
+ case 24576000:
+ case 33868800:
+ es8323->sysclk_constraints = &constraints_12288;
+ break;
+ case 12000000:
+ case 24000000:
+ es8323->sysclk_constraints = &constraints_12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ es8323->sysclk = freq;
+ return 0;
+}
+
+static int es8323_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ u8 iface = snd_soc_component_read(component, ES8323_MASTERMODE);
+ u8 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE);
+ u8 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_BC_FP:
+ iface |= 0x80;
+ break;
+ case SND_SOC_DAIFMT_BC_FC:
+ iface &= 0x7f;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ adciface &= 0xfc;
+ daciface &= 0xf8;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ adciface &= 0xfd;
+ daciface &= 0xf9;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ adciface &= 0xfe;
+ daciface &= 0xfa;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ adciface &= 0xff;
+ daciface &= 0xfb;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ iface &= 0xdf;
+ adciface &= 0xdf;
+ daciface &= 0xbf;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x20;
+ adciface |= 0x20;
+ daciface |= 0x40;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x20;
+ adciface &= 0xdf;
+ daciface &= 0xbf;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface &= 0xdf;
+ adciface |= 0x20;
+ daciface |= 0x40;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_write(component, ES8323_MASTERMODE, iface);
+ snd_soc_component_write(component, ES8323_ADC_IFACE, adciface);
+ snd_soc_component_write(component, ES8323_DAC_IFACE, daciface);
+
+ return 0;
+}
+
+static int es8323_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ if (es8323->sysclk) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ es8323->sysclk_constraints);
+ }
+
+ return 0;
+}
+
+static int es8323_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+ u16 srate = snd_soc_component_read(component, ES8323_MASTERMODE) & 0x80;
+ u16 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE) & 0xe3;
+ u16 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE) & 0xc7;
+ int coeff;
+
+ coeff = get_coeff(es8323->sysclk, params_rate(params));
+ if (coeff < 0) {
+ coeff = get_coeff(es8323->sysclk / 2, params_rate(params));
+ srate |= 0x40;
+ }
+
+ if (coeff < 0) {
+ dev_err(component->dev,
+ "Unable to configure sample rate %dHz with %dHz MCLK\n",
+ params_rate(params), es8323->sysclk);
+ return coeff;
+ }
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ adciface |= 0xc;
+ daciface |= 0x18;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ adciface |= 0x4;
+ daciface |= 0x8;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ adciface |= 0x10;
+ daciface |= 0x20;
+ break;
+ }
+
+ snd_soc_component_write(component, ES8323_DAC_IFACE, daciface);
+ snd_soc_component_write(component, ES8323_ADC_IFACE, adciface);
+
+ snd_soc_component_write(component, ES8323_MASTERMODE, srate);
+ snd_soc_component_write(component, ES8323_ADCCONTROL5,
+ es8323_coeff_div[coeff].sr |
+ (es8323_coeff_div[coeff].usb) << 4);
+ snd_soc_component_write(component, ES8323_DACCONTROL2,
+ es8323_coeff_div[coeff].sr |
+ (es8323_coeff_div[coeff].usb) << 4);
+
+ snd_soc_component_write(component, ES8323_DACPOWER, 0x3c);
+
+ return 0;
+}
+
+static int es8323_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ u32 val = mute ? 0x6 : 0x2;
+
+ snd_soc_component_write(component, ES8323_DAC_MUTE, val);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops es8323_ops = {
+ .startup = es8323_pcm_startup,
+ .hw_params = es8323_pcm_hw_params,
+ .set_fmt = es8323_set_dai_fmt,
+ .set_sysclk = es8323_set_dai_sysclk,
+ .mute_stream = es8323_mute_stream,
+};
+
+#define ES8323_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver es8323_dai = {
+ .name = "ES8323 HiFi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ES8323_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = ES8323_FORMATS,
+ },
+ .ops = &es8323_ops,
+ .symmetric_rate = 1,
+};
+
+static int es8323_probe(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ es8323->component = component;
+
+ es8323->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(es8323->mclk)) {
+ dev_err(component->dev, "unable to get mclk\n");
+ return PTR_ERR(es8323->mclk);
+ }
+
+ if (!es8323->mclk)
+ dev_warn(component->dev, "assuming static mclk\n");
+
+ ret = clk_prepare_enable(es8323->mclk);
+ if (ret) {
+ dev_err(component->dev, "unable to enable mclk\n");
+ return ret;
+ }
+
+ snd_soc_component_write(component, ES8323_CONTROL2, 0x60);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00);
+
+ return 0;
+}
+
+static int es8323_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ ret = clk_prepare_enable(es8323->mclk);
+ if (ret)
+ return ret;
+
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0xf0);
+ usleep_range(18000, 20000);
+ snd_soc_component_write(component, ES8323_DACPOWER, 0x3c);
+ snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00);
+ snd_soc_component_write(component, ES8323_ADCPOWER, 0x09);
+ snd_soc_component_write(component, ES8323_ADCCONTROL14, 0x00);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00);
+ snd_soc_component_write(component, ES8323_ADCPOWER, 0x59);
+ break;
+ case SND_SOC_BIAS_OFF:
+ clk_disable_unprepare(es8323->mclk);
+ snd_soc_component_write(component, ES8323_ADCPOWER, 0xff);
+ snd_soc_component_write(component, ES8323_DACPOWER, 0xC0);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0xff);
+ snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0xff);
+ snd_soc_component_write(component, ES8323_CHIPPOWER, 0xff);
+ snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7b);
+ break;
+ }
+
+ return 0;
+}
+
+static void es8323_remove(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ clk_disable_unprepare(es8323->mclk);
+ es8323_set_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static int es8323_suspend(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8323->regmap, true);
+ regcache_mark_dirty(es8323->regmap);
+
+ return 0;
+}
+
+static int es8323_resume(struct snd_soc_component *component)
+{
+ struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(es8323->regmap, false);
+ regcache_sync(es8323->regmap);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8323 = {
+ .probe = es8323_probe,
+ .remove = es8323_remove,
+ .suspend = es8323_suspend,
+ .resume = es8323_resume,
+ .set_bias_level = es8323_set_bias_level,
+ .controls = es8323_snd_controls,
+ .num_controls = ARRAY_SIZE(es8323_snd_controls),
+ .dapm_widgets = es8323_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8323_dapm_widgets),
+ .dapm_routes = es8323_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8323_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config es8323_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .use_single_read = true,
+ .use_single_write = true,
+ .max_register = 0x53,
+ .reg_defaults = es8323_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(es8323_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int es8323_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct es8323_priv *es8323;
+ struct device *dev = &i2c_client->dev;
+
+ es8323 = devm_kzalloc(dev, sizeof(*es8323), GFP_KERNEL);
+ if (!es8323)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c_client, es8323);
+
+ es8323->regmap = devm_regmap_init_i2c(i2c_client, &es8323_regmap);
+ if (IS_ERR(es8323->regmap))
+ return PTR_ERR(es8323->regmap);
+
+ return devm_snd_soc_register_component(dev,
+ &soc_component_dev_es8323,
+ &es8323_dai, 1);
+}
+
+static const struct i2c_device_id es8323_i2c_id[] = {
+ { "es8323" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, es8323_i2c_id);
+
+static const struct acpi_device_id es8323_acpi_match[] = {
+ { "ESSX8323", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, es8323_acpi_match);
+
+static const struct of_device_id es8323_of_match[] = {
+ { .compatible = "everest,es8323" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, es8323_of_match);
+
+static struct i2c_driver es8323_i2c_driver = {
+ .driver = {
+ .name = "ES8323",
+ .acpi_match_table = es8323_acpi_match,
+ .of_match_table = es8323_of_match,
+ },
+ .probe = es8323_i2c_probe,
+ .id_table = es8323_i2c_id,
+};
+module_i2c_driver(es8323_i2c_driver);
+
+MODULE_DESCRIPTION("Everest Semi ES8323 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8323.h b/sound/soc/codecs/es8323.h
new file mode 100644
index 000000000000..f986c9301dc6
--- /dev/null
+++ b/sound/soc/codecs/es8323.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ * Binbin Zhou <zhoubinbin@loongson.cn>
+ *
+ */
+
+#ifndef _ES8323_H
+#define _ES8323_H
+
+/* ES8323 register space */
+
+/* Chip Control and Power Management */
+#define ES8323_CONTROL1 0x00
+#define ES8323_CONTROL2 0x01
+#define ES8323_CHIPPOWER 0x02
+#define ES8323_ADCPOWER 0x03
+#define ES8323_DACPOWER 0x04
+#define ES8323_CHIPLOPOW1 0x05
+#define ES8323_CHIPLOPOW2 0x06
+#define ES8323_ANAVOLMANAG 0x07
+#define ES8323_MASTERMODE 0x08
+
+/* ADC Control */
+#define ES8323_ADCCONTROL1 0x09
+#define ES8323_ADCCONTROL2 0x0a
+#define ES8323_ADCCONTROL3 0x0b
+#define ES8323_ADCCONTROL4 0x0c
+#define ES8323_ADCCONTROL5 0x0d
+#define ES8323_ADCCONTROL6 0x0e
+#define ES8323_ADC_MUTE 0x0f
+#define ES8323_LADC_VOL 0x10
+#define ES8323_RADC_VOL 0x11
+#define ES8323_ADCCONTROL10 0x12
+#define ES8323_ADCCONTROL11 0x13
+#define ES8323_ADCCONTROL12 0x14
+#define ES8323_ADCCONTROL13 0x15
+#define ES8323_ADCCONTROL14 0x16
+
+/* DAC Control */
+#define ES8323_DACCONTROL1 0x17
+#define ES8323_DACCONTROL2 0x18
+#define ES8323_DAC_MUTE 0x19
+#define ES8323_LDAC_VOL 0x1a
+#define ES8323_RDAC_VOL 0x1b
+#define ES8323_DACCONTROL6 0x1c
+#define ES8323_DACCONTROL7 0x1d
+#define ES8323_DACCONTROL8 0x1e
+#define ES8323_DACCONTROL9 0x1f
+#define ES8323_DACCONTROL10 0x20
+#define ES8323_DACCONTROL11 0x21
+#define ES8323_DACCONTROL12 0x22
+#define ES8323_DACCONTROL13 0x23
+#define ES8323_DACCONTROL14 0x24
+#define ES8323_DACCONTROL15 0x25
+#define ES8323_DACCONTROL16 0x26
+#define ES8323_DACCONTROL17 0x27
+#define ES8323_DACCONTROL18 0x28
+#define ES8323_DACCONTROL19 0x29
+#define ES8323_DACCONTROL20 0x2a
+#define ES8323_DACCONTROL21 0x2b
+#define ES8323_DACCONTROL22 0x2c
+#define ES8323_DACCONTROL23 0x2d
+#define ES8323_LOUT1_VOL 0x2e
+#define ES8323_ROUT1_VOL 0x2f
+#define ES8323_LOUT2_VOL 0x30
+#define ES8323_ROUT2_VOL 0x31
+#define ES8323_DACCONTROL28 0x32
+#define ES8323_DACCONTROL29 0x33
+#define ES8323_DACCONTROL30 0x34
+
+#define ES8323_ADC_IFACE ES8323_ADCCONTROL4
+#define ES8323_ADC_SRATE ES8323_ADCCONTROL5
+#define ES8323_DAC_IFACE ES8323_DACCONTROL1
+#define ES8323_DAC_SRATE ES8323_DACCONTROL2
+#endif
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index 7cb5b57ae655..05b13661c38c 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -31,15 +31,162 @@ struct es8326_priv {
* while enabling or disabling or during an irq.
*/
struct mutex lock;
- u8 mic1_src;
- u8 mic2_src;
u8 jack_pol;
u8 interrupt_src;
u8 interrupt_clk;
+ u8 hpl_vol;
+ u8 hpr_vol;
bool jd_inverted;
unsigned int sysclk;
+
+ bool calibrated;
+ int version;
+ int hp;
+ int jack_remove_retry;
};
+static int es8326_crosstalk1_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int crosstalk_h, crosstalk_l;
+ unsigned int crosstalk;
+
+ regmap_read(es8326->regmap, ES8326_DAC_RAMPRATE, &crosstalk_h);
+ regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+ crosstalk_h &= 0x20;
+ crosstalk_l &= 0xf0;
+ crosstalk = crosstalk_h >> 1 | crosstalk_l >> 4;
+ ucontrol->value.integer.value[0] = crosstalk;
+
+ return 0;
+}
+
+static int es8326_crosstalk1_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int crosstalk_h, crosstalk_l;
+ unsigned int crosstalk;
+
+ crosstalk = ucontrol->value.integer.value[0];
+ regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+ crosstalk_h = (crosstalk & 0x10) << 1;
+ crosstalk_l &= 0x0f;
+ crosstalk_l |= (crosstalk & 0x0f) << 4;
+ regmap_update_bits(es8326->regmap, ES8326_DAC_RAMPRATE,
+ 0x20, crosstalk_h);
+ regmap_write(es8326->regmap, ES8326_DAC_CROSSTALK, crosstalk_l);
+
+ return 0;
+}
+
+static int es8326_crosstalk2_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int crosstalk_h, crosstalk_l;
+ unsigned int crosstalk;
+
+ regmap_read(es8326->regmap, ES8326_DAC_RAMPRATE, &crosstalk_h);
+ regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+ crosstalk_h &= 0x10;
+ crosstalk_l &= 0x0f;
+ crosstalk = crosstalk_h | crosstalk_l;
+ ucontrol->value.integer.value[0] = crosstalk;
+
+ return 0;
+}
+
+static int es8326_crosstalk2_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int crosstalk_h, crosstalk_l;
+ unsigned int crosstalk;
+
+ crosstalk = ucontrol->value.integer.value[0];
+ regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+ crosstalk_h = crosstalk & 0x10;
+ crosstalk_l &= 0xf0;
+ crosstalk_l |= crosstalk & 0x0f;
+ regmap_update_bits(es8326->regmap, ES8326_DAC_RAMPRATE,
+ 0x10, crosstalk_h);
+ regmap_write(es8326->regmap, ES8326_DAC_CROSSTALK, crosstalk_l);
+
+ return 0;
+}
+
+static int es8326_hplvol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = es8326->hpl_vol;
+
+ return 0;
+}
+
+static int es8326_hplvol_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int hp_vol;
+
+ hp_vol = ucontrol->value.integer.value[0];
+ if (hp_vol > 5)
+ return -EINVAL;
+ if (es8326->hpl_vol != hp_vol) {
+ es8326->hpl_vol = hp_vol;
+ if (hp_vol >= 3)
+ hp_vol++;
+ regmap_update_bits(es8326->regmap, ES8326_HP_VOL,
+ 0x70, (hp_vol << 4));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int es8326_hprvol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = es8326->hpr_vol;
+
+ return 0;
+}
+
+static int es8326_hprvol_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int hp_vol;
+
+ hp_vol = ucontrol->value.integer.value[0];
+ if (hp_vol > 5)
+ return -EINVAL;
+ if (es8326->hpr_vol != hp_vol) {
+ es8326->hpr_vol = hp_vol;
+ if (hp_vol >= 3)
+ hp_vol++;
+ regmap_update_bits(es8326->regmap, ES8326_HP_VOL,
+ 0x07, hp_vol);
+ return 1;
+ }
+
+ return 0;
+}
+
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
@@ -70,15 +217,24 @@ static const char *const winsize[] = {
static const char *const dacpol_txt[] = {
"Normal", "R Invert", "L Invert", "L + R Invert" };
+static const char *const hp_spkvol_switch[] = {
+ "HPVOL: HPL+HPL, SPKVOL: HPL+HPL",
+ "HPVOL: HPL+HPR, SPKVOL: HPL+HPR",
+ "HPVOL: HPL+HPL, SPKVOL: SPKL+SPKR",
+ "HPVOL: HPL+HPR, SPKVOL: SPKL+SPKR",
+};
+
static const struct soc_enum dacpol =
SOC_ENUM_SINGLE(ES8326_DAC_DSM, 4, 4, dacpol_txt);
static const struct soc_enum alc_winsize =
SOC_ENUM_SINGLE(ES8326_ADC_RAMPRATE, 4, 16, winsize);
static const struct soc_enum drc_winsize =
SOC_ENUM_SINGLE(ES8326_DRC_WINSIZE, 4, 16, winsize);
+static const struct soc_enum hpvol_spkvol_switch =
+ SOC_ENUM_SINGLE(ES8326_HP_MISC, 6, 4, hp_spkvol_switch);
static const struct snd_kcontrol_new es8326_snd_controls[] = {
- SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DAC_VOL, 0, 0xbf, 0, dac_vol_tlv),
+ SOC_SINGLE_TLV("DAC Playback Volume", ES8326_DACL_VOL, 0, 0xbf, 0, dac_vol_tlv),
SOC_ENUM("Playback Polarity", dacpol),
SOC_SINGLE_TLV("DAC Ramp Rate", ES8326_DAC_RAMPRATE, 0, 0x0f, 0, softramp_rate),
SOC_SINGLE_TLV("DRC Recovery Level", ES8326_DRC_RECOVERY, 0, 4, 0, drc_recovery_tlv),
@@ -97,6 +253,21 @@ static const struct snd_kcontrol_new es8326_snd_controls[] = {
SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
0, 0x0f, 0, drc_target_tlv),
+ SOC_SINGLE_EXT("CROSSTALK1", SND_SOC_NOPM, 0, 31, 0,
+ es8326_crosstalk1_get, es8326_crosstalk1_set),
+ SOC_SINGLE_EXT("CROSSTALK2", SND_SOC_NOPM, 0, 31, 0,
+ es8326_crosstalk2_get, es8326_crosstalk2_set),
+ SOC_SINGLE_EXT("HPL Volume", SND_SOC_NOPM, 0, 5, 0,
+ es8326_hplvol_get, es8326_hplvol_set),
+ SOC_SINGLE_EXT("HPR Volume", SND_SOC_NOPM, 0, 5, 0,
+ es8326_hprvol_get, es8326_hprvol_set),
+
+ SOC_SINGLE_TLV("HPL Playback Volume", ES8326_DACL_VOL, 0, 0xbf, 0, dac_vol_tlv),
+ SOC_SINGLE_TLV("HPR Playback Volume", ES8326_DACR_VOL, 0, 0xbf, 0, dac_vol_tlv),
+ SOC_SINGLE_TLV("SPKL Playback Volume", ES8326_SPKL_VOL, 0, 0xbf, 0, dac_vol_tlv),
+ SOC_SINGLE_TLV("SPKR Playback Volume", ES8326_SPKR_VOL, 0, 0xbf, 0, dac_vol_tlv),
+
+ SOC_ENUM("HPVol SPKVol Switch", hpvol_spkvol_switch),
};
static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
@@ -112,106 +283,75 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
- /* ADC Digital Mute */
- SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE, 0, 1, NULL, 0),
- SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0),
- SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0),
- SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0),
-
/* Analog Power Supply*/
SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1),
SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1),
- SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0),
SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0),
- /* Headphone Charge Pump and Output */
- SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER,
- 3, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER,
- 2, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER,
- 1, 1, NULL, 0),
- SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER,
- 0, 1, NULL, 0),
- SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL,
- ES8326_HPOR_SHIFT, 7, 7, 0),
- SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL,
- 0, 7, 7, 0),
-
SND_SOC_DAPM_OUTPUT("HPOL"),
SND_SOC_DAPM_OUTPUT("HPOR"),
};
static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
- {"ADC L1", NULL, "MIC1"},
- {"ADC R1", NULL, "MIC2"},
- {"ADC L2", NULL, "MIC3"},
- {"ADC R2", NULL, "MIC4"},
-
- {"ADC L", NULL, "ADC L1"},
- {"ADC R", NULL, "ADC R1"},
- {"ADC L", NULL, "ADC L2"},
- {"ADC R", NULL, "ADC R2"},
+ {"ADC L", NULL, "MIC1"},
+ {"ADC R", NULL, "MIC2"},
+ {"ADC L", NULL, "MIC3"},
+ {"ADC R", NULL, "MIC4"},
{"I2S OUT", NULL, "ADC L"},
{"I2S OUT", NULL, "ADC R"},
- {"I2S OUT", NULL, "Analog Power"},
- {"I2S OUT", NULL, "ADC Vref"},
- {"I2S OUT", NULL, "Vref Power"},
- {"I2S OUT", NULL, "IBias Power"},
- {"I2S IN", NULL, "Analog Power"},
- {"I2S IN", NULL, "DAC Vref"},
- {"I2S IN", NULL, "Vref Power"},
- {"I2S IN", NULL, "IBias Power"},
-
{"Right DAC", NULL, "I2S IN"},
{"Left DAC", NULL, "I2S IN"},
{"LHPMIX", NULL, "Left DAC"},
{"RHPMIX", NULL, "Right DAC"},
- {"HPOR", NULL, "HPOR Cal"},
- {"HPOL", NULL, "HPOL Cal"},
- {"HPOR", NULL, "HPOR Supply"},
- {"HPOL", NULL, "HPOL Supply"},
- {"HPOL", NULL, "Headphone Charge Pump"},
- {"HPOR", NULL, "Headphone Charge Pump"},
- {"HPOL", NULL, "Headphone Driver Bias"},
- {"HPOR", NULL, "Headphone Driver Bias"},
- {"HPOL", NULL, "Headphone LDO"},
- {"HPOR", NULL, "Headphone LDO"},
- {"HPOL", NULL, "Headphone Reference"},
- {"HPOR", NULL, "Headphone Reference"},
-
{"HPOL", NULL, "LHPMIX"},
{"HPOR", NULL, "RHPMIX"},
};
-static const struct regmap_range es8326_volatile_ranges[] = {
- regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT),
-};
+static bool es8326_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ES8326_HPL_OFFSET_INI:
+ case ES8326_HPR_OFFSET_INI:
+ case ES8326_HPDET_STA:
+ case ES8326_CTIA_OMTP_STA:
+ case ES8326_CSM_MUTE_STA:
+ return true;
+ default:
+ return false;
+ }
+}
-static const struct regmap_access_table es8326_volatile_table = {
- .yes_ranges = es8326_volatile_ranges,
- .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
-};
+static bool es8326_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ES8326_BIAS_SW1:
+ case ES8326_BIAS_SW2:
+ case ES8326_BIAS_SW3:
+ case ES8326_BIAS_SW4:
+ case ES8326_ADC_HPFS1:
+ case ES8326_ADC_HPFS2:
+ return false;
+ default:
+ return true;
+ }
+}
static const struct regmap_config es8326_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xff,
- .volatile_table = &es8326_volatile_table,
+ .use_single_read = true,
+ .use_single_write = true,
+ .volatile_reg = es8326_volatile_register,
+ .writeable_reg = es8326_writeable_register,
.cache_type = REGCACHE_RBTREE,
};
@@ -231,77 +371,108 @@ struct _coeff_div {
/* codec hifi mclk clock divider coefficients */
/* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */
-static const struct _coeff_div coeff_div[] = {
- {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
- {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
- {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
- {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47},
- {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
- {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
- {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
- {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
-
- {64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47},
- {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47},
- {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
- {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
- {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f},
- {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
- {128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
- {128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
-
- {128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47},
- {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47},
- {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
- {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F},
- {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
- {256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
- {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
-
- {256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47},
- {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
- {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
- {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F},
- {500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
- {512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
-
- {512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
- {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
- {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F},
- {1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+static const struct _coeff_div coeff_div_v0[] = {
+ {64, 8000, 512000, 0x60, 0x01, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F},
+ {64, 16000, 1024000, 0x20, 0x00, 0x33, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {64, 44100, 2822400, 0xE0, 0x00, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {64, 48000, 3072000, 0xE0, 0x00, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {128, 8000, 1024000, 0x60, 0x00, 0x33, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {128, 16000, 2048000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {128, 44100, 5644800, 0xE0, 0x01, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {128, 48000, 6144000, 0xE0, 0x01, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+
+ {192, 32000, 6144000, 0xE0, 0x02, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {256, 8000, 2048000, 0x60, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {256, 16000, 4096000, 0x20, 0x01, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {256, 44100, 11289600, 0xE0, 0x00, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {256, 48000, 12288000, 0xE0, 0x00, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {384, 32000, 12288000, 0xE0, 0x05, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {400, 48000, 19200000, 0xE9, 0x04, 0x0F, 0x6d, 0x4A, 0x0A, 0x1F, 0x1F},
+
+ {500, 48000, 24000000, 0xF8, 0x04, 0x3F, 0x6D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {512, 8000, 4096000, 0x60, 0x01, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
+ {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
+ {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {768, 32000, 24576000, 0xE0, 0x02, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F},
+ {1024, 8000, 8192000, 0x60, 0x00, 0x30, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
{1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
- {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
- {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
-
- {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F},
- {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
- {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
- {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
- {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F},
- {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F},
- {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27},
+};
+static const struct _coeff_div coeff_div_v3[] = {
+ {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x3F},
+ {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F},
+ {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F},
+ {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x23, 0x47},
+ {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x23, 0x47},
+ {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x8A, 0x1B, 0x1F, 0x3F},
+ {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F},
+
+ {64, 8000, 512000, 0x60, 0x00, 0x35, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x3F},
+ {64, 44100, 2822400, 0xE0, 0x00, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {64, 48000, 3072000, 0xE0, 0x00, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x8A, 0x1B, 0x23, 0x47},
+ {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x23, 0x47},
+ {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x3F},
+ {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0xB8, 0x08, 0x4f, 0x1f},
+ {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27},
+
+ {128, 8000, 1024000, 0x60, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {128, 16000, 2048000, 0x20, 0x00, 0x31, 0x35, 0x08, 0x19, 0x1F, 0x3F},
+ {128, 44100, 5644800, 0xE0, 0x00, 0x01, 0x2D, 0x48, 0x08, 0x1F, 0x1F},
+ {128, 48000, 6144000, 0xE0, 0x00, 0x01, 0x2D, 0x48, 0x08, 0x1F, 0x1F},
+ {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x8A, 0x1B, 0x23, 0x47},
+ {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x8A, 0x1B, 0x23, 0x47},
+ {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {192, 32000, 6144000, 0xE0, 0x02, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0xCA, 0x1B, 0x1F, 0x3F},
+
+ {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0xCA, 0x0A, 0x27, 0x27},
+ {256, 8000, 2048000, 0x60, 0x00, 0x31, 0x35, 0x08, 0x19, 0x1F, 0x7F},
+ {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x08, 0x19, 0x1F, 0x3F},
+ {256, 44100, 11289600, 0xE0, 0x01, 0x01, 0x2D, 0x48, 0x08, 0x1F, 0x1F},
+ {256, 48000, 12288000, 0xE0, 0x01, 0x01, 0x2D, 0x48, 0x08, 0x1F, 0x1F},
+ {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x23, 0x47},
+ {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x7F},
+ {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x8A, 0x1B, 0x1F, 0x3F},
+ {384, 32000, 12288000, 0xE0, 0x02, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F},
+
+ {400, 48000, 19200000, 0xE4, 0x04, 0x35, 0x6d, 0xCA, 0x0A, 0x1F, 0x1F},
+ {500, 48000, 24000000, 0xF8, 0x04, 0x3F, 0x6D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x08, 0x19, 0x1B, 0x1F, 0x7F},
+ {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x08, 0x19, 0x1F, 0x3F},
+ {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0x48, 0x08, 0x1F, 0x1F},
+ {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 0x48, 0x08, 0x1F, 0x1F},
+ {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x8A, 0x1B, 0x1F, 0x7F},
+ {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x3F},
+ {768, 32000, 24576000, 0xE0, 0x02, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F},
+ {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F},
+
+ {1024, 8000, 8192000, 0x60, 0x00, 0x30, 0x35, 0x8A, 0x1B, 0x1F, 0x7F},
+ {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x8A, 0x1B, 0x1F, 0x3F},
+ {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x8A, 0x1B, 0x1F, 0x3F},
+ {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x7F},
+ {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x3F},
+ {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27},
+ {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27},
+ {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x8A, 0x1B, 0x1F, 0x7F},
+ {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x5F},
+ {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x7F},
+ {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x8A, 0x0A, 0x27, 0x27},
};
-static inline int get_coeff(int mclk, int rate)
+static inline int get_coeff(int mclk, int rate, int array,
+ const struct _coeff_div *coeff_div)
{
int i;
- for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ for (i = 0; i < array; i++) {
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
return i;
}
@@ -366,11 +537,19 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
+ const struct _coeff_div *coeff_div;
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
u8 srate = 0;
- int coeff;
+ int coeff, array;
- coeff = get_coeff(es8326->sysclk, params_rate(params));
+ if (es8326->version == 0) {
+ coeff_div = coeff_div_v0;
+ array = ARRAY_SIZE(coeff_div_v0);
+ } else {
+ coeff_div = coeff_div_v3;
+ array = ARRAY_SIZE(coeff_div_v3);
+ }
+ coeff = get_coeff(es8326->sysclk, params_rate(params), array, coeff_div);
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -419,6 +598,65 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int offset_l, offset_r;
+
+ if (mute) {
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+ regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
+ ES8326_MUTE_MASK, ES8326_MUTE);
+ regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF,
+ 0x30, 0x00);
+ } else {
+ regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
+ 0x0F, 0x0F);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x30);
+ }
+ }
+ } else {
+ if (!es8326->calibrated) {
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL);
+ msleep(30);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+ regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l);
+ regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r);
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+ regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l);
+ regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
+ es8326->calibrated = true;
+ }
+ regmap_update_bits(es8326->regmap, ES8326_CLK_INV, 0xc0, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_CLK_MUX, 0x80, 0x00);
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x01);
+ usleep_range(1000, 5000);
+ regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00);
+ usleep_range(1000, 5000);
+ regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x30, 0x20);
+ regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x30, 0x30);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON);
+ regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
+ ES8326_MUTE_MASK, ~(ES8326_MUTE));
+ } else {
+ msleep(300);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x70);
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00);
+ }
+ regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
+ 0x0F, 0x00);
+ }
+ }
+ return 0;
+}
+
static int es8326_set_bias_level(struct snd_soc_component *codec,
enum snd_soc_bias_level level)
{
@@ -430,32 +668,36 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
ret = clk_prepare_enable(es8326->mclk);
if (ret)
return ret;
- regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN);
- regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45);
+
+ regmap_update_bits(es8326->regmap, ES8326_RESET, 0x02, 0x02);
+ usleep_range(5000, 10000);
+ regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
(ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
- regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
- regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
- regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02);
regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
- regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA);
- regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20);
+ regmap_update_bits(es8326->regmap, ES8326_RESET, 0x02, 0x00);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x30);
+ }
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
+ regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00);
+ regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x10);
+ }
+ regmap_update_bits(es8326->regmap, ES8326_CLK_INV, 0xc0, 0xc0);
+ regmap_update_bits(es8326->regmap, ES8326_CLK_MUX, 0x80, 0x80);
break;
case SND_SOC_BIAS_OFF:
clk_disable_unprepare(es8326->mclk);
- regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11);
- regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF);
- regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8);
- regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
- regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08);
- regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
- regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
- regmap_write(es8326->regmap, ES8326_RESET,
- ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
break;
}
@@ -469,6 +711,8 @@ static const struct snd_soc_dai_ops es8326_ops = {
.hw_params = es8326_pcm_hw_params,
.set_fmt = es8326_set_dai_fmt,
.set_sysclk = es8326_set_dai_sysclk,
+ .mute_stream = es8326_mute,
+ .no_capture_mute = 0,
};
static struct snd_soc_dai_driver es8326_dai = {
@@ -493,7 +737,7 @@ static struct snd_soc_dai_driver es8326_dai = {
static void es8326_enable_micbias(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
@@ -504,7 +748,7 @@ static void es8326_enable_micbias(struct snd_soc_component *component)
static void es8326_disable_micbias(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
@@ -532,21 +776,26 @@ static void es8326_jack_button_handler(struct work_struct *work)
return;
mutex_lock(&es8326->lock);
- iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+ iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
switch (iface) {
case 0x93:
/* pause button detected */
cur_button = SND_JACK_BTN_0;
break;
case 0x6f:
+ case 0x4b:
/* button volume up */
- cur_button = SND_JACK_BTN_1;
+ if ((iface == 0x6f) && (es8326->version > ES8326_VERSION_B))
+ cur_button = SND_JACK_BTN_0;
+ else
+ cur_button = SND_JACK_BTN_1;
break;
case 0x27:
/* button volume down */
cur_button = SND_JACK_BTN_2;
break;
case 0x1e:
+ case 0xe2:
/* button released or not pressed */
cur_button = 0;
break;
@@ -556,20 +805,20 @@ static void es8326_jack_button_handler(struct work_struct *work)
if ((prev_button == cur_button) && (cur_button != 0)) {
press_count++;
- if (press_count > 10) {
- /* report a press every 500ms */
+ if (press_count > 3) {
+ /* report a press every 120ms */
snd_soc_jack_report(es8326->jack, cur_button,
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
press_count = 0;
}
button_to_report = cur_button;
- queue_delayed_work(system_wq, &es8326->button_press_work,
- msecs_to_jiffies(50));
+ queue_delayed_work(system_dfl_wq, &es8326->button_press_work,
+ msecs_to_jiffies(35));
} else if (prev_button != cur_button) {
/* mismatch, detect again */
prev_button = cur_button;
- queue_delayed_work(system_wq, &es8326->button_press_work,
- msecs_to_jiffies(50));
+ queue_delayed_work(system_dfl_wq, &es8326->button_press_work,
+ msecs_to_jiffies(35));
} else {
/* released or no pressed */
if (button_to_report != 0) {
@@ -579,6 +828,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
button_to_report = 0;
}
+ es8326_disable_micbias(es8326->component);
}
mutex_unlock(&es8326->lock);
}
@@ -591,96 +841,286 @@ static void es8326_jack_detect_handler(struct work_struct *work)
unsigned int iface;
mutex_lock(&es8326->lock);
- iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+ iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
dev_dbg(comp->dev, "gpio flag %#04x", iface);
+
+ if ((es8326->jack_remove_retry == 1) && (es8326->version < ES8326_VERSION_B)) {
+ if (iface & ES8326_HPINSERT_FLAG)
+ es8326->jack_remove_retry = 2;
+ else
+ es8326->jack_remove_retry = 0;
+
+ dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n",
+ es8326->jack_remove_retry);
+ /*
+ * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
+ */
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
+ ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
+ ~es8326->jack_pol : es8326->jack_pol));
+ goto exit;
+ }
+
if ((iface & ES8326_HPINSERT_FLAG) == 0) {
/* Jack unplugged or spurious IRQ */
- dev_dbg(comp->dev, "No headset detected");
+ dev_dbg(comp->dev, "No headset detected\n");
+ es8326_disable_micbias(es8326->component);
if (es8326->jack->status & SND_JACK_HEADPHONE) {
+ dev_dbg(comp->dev, "Report hp remove event\n");
+ snd_soc_jack_report(es8326->jack, 0,
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
- snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
- es8326_disable_micbias(comp);
+ /* mute adc when mic path switch */
+ regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44);
+ regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66);
+ }
+ es8326->hp = 0;
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+ regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x0a);
+ regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x0f, 0x03);
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
+ /*
+ * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
+ */
+ if ((es8326->jack_remove_retry == 0) && (es8326->version < ES8326_VERSION_B)) {
+ es8326->jack_remove_retry = 1;
+ dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n",
+ es8326->jack_remove_retry);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
+ ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
+ es8326->jack_pol : ~es8326->jack_pol));
+
+ } else {
+ es8326->jack_remove_retry = 0;
}
} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+ es8326->jack_remove_retry = 0;
+ if (es8326->hp == 0) {
+ dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n");
+ /*
+ * set auto-check mode, then restart jack_detect_work after 400ms.
+ * Don't report jack status.
+ */
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x00);
+ usleep_range(50000, 70000);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x10);
+ usleep_range(50000, 70000);
+ 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, 0x0d);
+ queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work,
+ msecs_to_jiffies(400));
+ es8326->hp = 1;
+ goto exit;
+ }
if (es8326->jack->status & SND_JACK_HEADSET) {
/* detect button */
- queue_delayed_work(system_wq, &es8326->button_press_work, 10);
+ dev_dbg(comp->dev, "button pressed\n");
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE,
+ (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
+ es8326_enable_micbias(es8326->component);
+ queue_delayed_work(system_dfl_wq, &es8326->button_press_work, 10);
+ goto exit;
+ }
+ if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
+ dev_dbg(comp->dev, "Headphone detected\n");
+ snd_soc_jack_report(es8326->jack,
+ SND_JACK_HEADPHONE, SND_JACK_HEADSET);
} else {
- if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
- dev_dbg(comp->dev, "Headset detected");
- snd_soc_jack_report(es8326->jack,
- SND_JACK_HEADSET, SND_JACK_HEADSET);
- snd_soc_component_write(comp,
- ES8326_ADC1_SRC, es8326->mic1_src);
- } else {
- dev_dbg(comp->dev, "Headphone detected");
- snd_soc_jack_report(es8326->jack,
- SND_JACK_HEADPHONE, SND_JACK_HEADSET);
- }
+ dev_dbg(comp->dev, "Headset detected\n");
+ snd_soc_jack_report(es8326->jack,
+ SND_JACK_HEADSET, SND_JACK_HEADSET);
+
+ regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+ 0x08, 0x08);
+ regmap_update_bits(es8326->regmap, ES8326_PGAGAIN,
+ 0x80, 0x80);
+ regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
+ regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+ 0x08, 0x00);
+ usleep_range(10000, 15000);
}
}
+exit:
mutex_unlock(&es8326->lock);
}
static irqreturn_t es8326_irq(int irq, void *dev_id)
{
struct es8326_priv *es8326 = dev_id;
- struct snd_soc_component *comp = es8326->component;
if (!es8326->jack)
goto out;
- es8326_enable_micbias(comp);
-
if (es8326->jack->status & SND_JACK_HEADSET)
- queue_delayed_work(system_wq, &es8326->jack_detect_work,
+ queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work,
msecs_to_jiffies(10));
else
- queue_delayed_work(system_wq, &es8326->jack_detect_work,
+ queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work,
msecs_to_jiffies(300));
out:
return IRQ_HANDLED;
}
-static int es8326_resume(struct snd_soc_component *component)
+static int es8326_calibrate(struct snd_soc_component *component)
{
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
unsigned int reg;
+ unsigned int offset_l, offset_r;
- regcache_cache_only(es8326->regmap, false);
- regcache_sync(es8326->regmap);
+ regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
+ es8326->version = reg;
+
+ if ((es8326->version >= ES8326_VERSION_B) && (es8326->calibrated == false)) {
+ dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n");
+ regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0);
+ regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x03);
+ regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30);
+ regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed);
+ regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL, 0x08);
+ regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1);
+ regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03);
+ regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f);
+ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23);
+ regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88);
+ usleep_range(15000, 20000);
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+ usleep_range(15000, 20000);
+ regmap_write(es8326->regmap, ES8326_RESET, 0xc0);
+ usleep_range(15000, 20000);
+
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF);
+ regmap_read(es8326->regmap, ES8326_CSM_MUTE_STA, &reg);
+ if ((reg & 0xf0) != 0x40)
+ msleep(50);
+
+ regmap_write(es8326->regmap, ES8326_HP_CAL, 0xd4);
+ msleep(200);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, 0x4d);
+ msleep(200);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+ regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l);
+ regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r);
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+ regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l);
+ regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
+ regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
+
+ es8326->calibrated = true;
+ }
+
+ return 0;
+}
+
+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, 0x3E);
+ regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
+ usleep_range(10000, 15000);
+ regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xd9);
+ regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xd8);
+ /* set headphone default type and detect pin */
+ regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x83);
+ regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
+
+ /* set internal oscillator as clock source of headpone cp */
+ regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x89);
regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
- /* Two channel ADC */
- regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02);
+ /* clock manager reset release */
+ regmap_write(es8326->regmap, ES8326_RESET, 0x17);
+ /* set headphone detection as half scan mode */
+ regmap_write(es8326->regmap, ES8326_HP_MISC, 0x3d);
+ regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00);
+
+ /* enable headphone driver */
+ regmap_write(es8326->regmap, ES8326_HP_VOL, 0xc4);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7);
+ usleep_range(2000, 5000);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0x23);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0x33);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
+
regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
- regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F);
- regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8);
- regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88);
- regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20);
- regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08);
- regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22);
- regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src);
- regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src);
- regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
- regmap_write(es8326->regmap, ES8326_HP_DET,
- ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
- regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src);
- regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
+ regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4);
+ regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81);
+ regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00);
+ /* calibrate for B version */
+ es8326_calibrate(component);
+ regmap_write(es8326->regmap, ES8326_DAC_CROSSTALK, 0xaa);
+ regmap_write(es8326->regmap, ES8326_DAC_RAMPRATE, 0x00);
+ /* turn off headphone out */
+ regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00);
+ /* set ADC and DAC in low power mode */
+ regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
+
+ regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
+ /* select vdda as micbias source */
+ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x03);
+ /* set dac dsmclip = 1 */
+ regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08);
+ regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15);
+
+ regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 |
+ ((es8326->version >= ES8326_VERSION_B) ?
+ (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
+ (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
+ usleep_range(5000, 10000);
+ es8326_enable_micbias(es8326->component);
+ usleep_range(50000, 70000);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
+ regmap_write(es8326->regmap, ES8326_INTOUT_IO,
+ es8326->interrupt_clk);
+ regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
+ regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00);
regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
- snd_soc_component_update_bits(component, ES8326_PGAGAIN,
- ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
-
- regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
- if ((reg & ES8326_VERSION_B) == 1) {
- regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD);
- regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
- regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F);
- /* enable button detect */
- regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0);
+ regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK,
+ ES8326_MIC1_SEL);
+
+ regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK,
+ ES8326_MUTE);
+
+ regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f);
+ regmap_write(es8326->regmap, ES8326_CLK_DIV_LRCK, 0xff);
+ regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44);
+ regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66);
+ es8326_disable_micbias(es8326->component);
+ if (es8326->version > ES8326_VERSION_B) {
+ regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x73, 0x10);
+ regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40);
}
+ msleep(200);
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9);
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int reg;
+
+ regcache_cache_only(es8326->regmap, false);
+ regcache_cache_bypass(es8326->regmap, true);
+ regmap_read(es8326->regmap, ES8326_CLK_RESAMPLE, &reg);
+ regcache_cache_bypass(es8326->regmap, false);
+ /* reset internal clock state */
+ if (reg == 0x05)
+ regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
+ else
+ es8326_init(component);
+
+ regcache_sync(es8326->regmap);
+
es8326_irq(es8326->irq, es8326);
return 0;
}
@@ -691,11 +1131,19 @@ static int es8326_suspend(struct snd_soc_component *component)
cancel_delayed_work_sync(&es8326->jack_detect_work);
es8326_disable_micbias(component);
-
+ es8326->calibrated = false;
+ regmap_write(es8326->regmap, ES8326_CLK_MUX, 0x2d);
+ regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x00);
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF);
regcache_cache_only(es8326->regmap, true);
- regcache_mark_dirty(es8326->regmap);
+ /* reset register value to default */
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+ usleep_range(1000, 3000);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
+
+ regcache_mark_dirty(es8326->regmap);
return 0;
}
@@ -708,24 +1156,10 @@ static int es8326_probe(struct snd_soc_component *component)
es8326->jd_inverted = device_property_read_bool(component->dev,
"everest,jack-detect-inverted");
- ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src);
- if (ret != 0) {
- dev_dbg(component->dev, "mic1-src return %d", ret);
- es8326->mic1_src = ES8326_ADC_AMIC;
- }
- dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src);
-
- ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src);
- if (ret != 0) {
- dev_dbg(component->dev, "mic2-src return %d", ret);
- es8326->mic2_src = ES8326_ADC_DMIC;
- }
- dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src);
-
ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
if (ret != 0) {
dev_dbg(component->dev, "jack-pol return %d", ret);
- es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+ es8326->jack_pol = ES8326_HP_TYPE_AUTO;
}
dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
@@ -741,11 +1175,11 @@ static int es8326_probe(struct snd_soc_component *component)
&es8326->interrupt_clk);
if (ret != 0) {
dev_dbg(component->dev, "interrupt-clk return %d", ret);
- es8326->interrupt_clk = 0x45;
+ es8326->interrupt_clk = 0x00;
}
dev_dbg(component->dev, "interrupt-clk %x", es8326->interrupt_clk);
- es8326_resume(component);
+ es8326_init(component);
return 0;
}
@@ -756,7 +1190,7 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component,
mutex_lock(&es8326->lock);
if (es8326->jd_inverted)
- snd_soc_component_update_bits(component, ES8326_HP_DET,
+ snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
es8326->jack = jack;
@@ -795,8 +1229,13 @@ static int es8326_set_jack(struct snd_soc_component *component,
static void es8326_remove(struct snd_soc_component *component)
{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+
es8326_disable_jack_detect(component);
es8326_set_bias_level(component, SND_SOC_BIAS_OFF);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+ usleep_range(1000, 3000);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
}
static const struct snd_soc_component_driver soc_component_dev_es8326 = {
@@ -836,6 +1275,10 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
}
es8326->irq = i2c->irq;
+ es8326->jack_remove_retry = 0;
+ es8326->hp = 0;
+ es8326->hpl_vol = 0x03;
+ es8326->hpr_vol = 0x03;
INIT_DELAYED_WORK(&es8326->jack_detect_work,
es8326_jack_detect_handler);
INIT_DELAYED_WORK(&es8326->button_press_work,
@@ -868,8 +1311,31 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
&es8326_dai, 1);
}
+
+static void es8326_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct snd_soc_component *component;
+ struct es8326_priv *es8326;
+
+ es8326 = i2c_get_clientdata(i2c);
+ component = es8326->component;
+ dev_dbg(component->dev, "Enter into %s\n", __func__);
+ cancel_delayed_work_sync(&es8326->jack_detect_work);
+ cancel_delayed_work_sync(&es8326->button_press_work);
+
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+ usleep_range(1000, 3000);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
+
+}
+
+static void es8326_i2c_remove(struct i2c_client *i2c)
+{
+ es8326_i2c_shutdown(i2c);
+}
+
static const struct i2c_device_id es8326_i2c_id[] = {
- {"es8326", 0 },
+ {"es8326" },
{}
};
MODULE_DEVICE_TABLE(i2c, es8326_i2c_id);
@@ -897,6 +1363,8 @@ static struct i2c_driver es8326_i2c_driver = {
.of_match_table = of_match_ptr(es8326_of_match),
},
.probe = es8326_i2c_probe,
+ .shutdown = es8326_i2c_shutdown,
+ .remove = es8326_i2c_remove,
.id_table = es8326_i2c_id,
};
module_i2c_driver(es8326_i2c_driver);
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
index 8e5ffe5ee10d..c3e52e7bdef5 100644
--- a/sound/soc/codecs/es8326.h
+++ b/sound/soc/codecs/es8326.h
@@ -9,8 +9,6 @@
#ifndef _ES8326_H
#define _ES8326_H
-#define CONFIG_HHTECH_MINIPMP 1
-
/* ES8326 register space */
#define ES8326_RESET 0x00
#define ES8326_CLK_CTL 0x01
@@ -71,19 +69,27 @@
#define ES8326_DAC_DSM 0x4D
#define ES8326_DAC_RAMPRATE 0x4E
#define ES8326_DAC_VPPSCALE 0x4F
-#define ES8326_DAC_VOL 0x50
+#define ES8326_DACL_VOL 0x50
#define ES8326_DRC_RECOVERY 0x53
#define ES8326_DRC_WINSIZE 0x54
+#define ES8326_DAC_CROSSTALK 0x55
#define ES8326_HPJACK_TIMER 0x56
-#define ES8326_HP_DET 0x57
+#define ES8326_HPDET_TYPE 0x57
#define ES8326_INT_SOURCE 0x58
#define ES8326_INTOUT_IO 0x59
#define ES8326_SDINOUT1_IO 0x5A
#define ES8326_SDINOUT23_IO 0x5B
#define ES8326_JACK_PULSE 0x5C
+#define ES8326_DACR_VOL 0xF4
+#define ES8326_SPKL_VOL 0xF5
+#define ES8326_SPKR_VOL 0xF6
+#define ES8326_HP_MISC 0xF7
+#define ES8326_CTIA_OMTP_STA 0xF8
#define ES8326_PULLUP_CTL 0xF9
-#define ES8326_HP_DETECT 0xFB
+#define ES8326_CSM_I2C_STA 0xFA
+#define ES8326_HPDET_STA 0xFB
+#define ES8326_CSM_MUTE_STA 0xFC
#define ES8326_CHIP_ID1 0xFD
#define ES8326_CHIP_ID2 0xFE
#define ES8326_CHIP_VERSION 0xFF
@@ -94,6 +100,8 @@
#define ES8326_PWRUP_SEQ_EN (1 << 5)
#define ES8326_CODEC_RESET (0x0f << 0)
#define ES8326_CSM_OFF (0 << 7)
+#define ES8326_MUTE_MASK (3 << 0)
+#define ES8326_MUTE (3 << 0)
/* ES8326_CLK_CTL */
#define ES8326_CLK_ON (0x7f << 0)
@@ -122,7 +130,9 @@
#define ES8326_MIC2_SEL (1 << 5)
/* ES8326_HP_CAL */
-#define ES8326_HPOR_SHIFT 4
+#define ES8326_HP_OFF 0
+#define ES8326_HP_FORCE_CAL ((1 << 7) | (1 << 3))
+#define ES8326_HP_ON ((7 << 4) | (7 << 0))
/* ES8326_ADC1_SRC */
#define ES8326_ADC1_SHIFT 0
@@ -144,7 +154,7 @@
#define ES8326_ADC3_SHIFT 0
#define ES8326_ADC4_SHIFT 3
-/* ES8326_HP_DET */
+/* ES8326_HPDET_TYPE */
#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
#define ES8326_HP_DET_JACK_POL (1 << 3)
@@ -154,6 +164,13 @@
#define ES8326_HP_TYPE_AUTO (1 << 0)
#define ES8326_HP_TYPE_AUTO_INV (0 << 0)
+/* ES8326_INT_SOURCE */
+#define ES8326_INT_SRC_DAC_MOZ (1 << 0)
+#define ES8326_INT_SRC_ADC_MOZ (1 << 1)
+#define ES8326_INT_SRC_BUTTON (1 << 2)
+#define ES8326_INT_SRC_PIN9 (1 << 3)
+#define ES8326_INT_SRC_PIN27 (1 << 4)
+
/* ES8326_SDINOUT1_IO */
#define ES8326_IO_INPUT (0 << 0)
#define ES8326_IO_SDIN_SLOT0 (1 << 0)
@@ -172,11 +189,12 @@
#define ES8326_SDINOUT2_SHIFT 4
#define ES8326_SDINOUT3_SHIFT 0
-/* ES8326_HP_DETECT */
+/* ES8326_HPDET_STA */
#define ES8326_HPINSERT_FLAG (1 << 1)
#define ES8326_HPBUTTON_FLAG (1 << 0)
/* ES8326_CHIP_VERSION 0xFF */
-#define ES8326_VERSION_B (1 << 0)
+#define ES8326_VERSION (1 << 0)
+#define ES8326_VERSION_B (3 << 0)
#endif
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
index 3c4aaa0032a0..56bfbe9261ce 100644
--- a/sound/soc/codecs/es8328-i2c.c
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -16,8 +16,8 @@
#include "es8328.h"
static const struct i2c_device_id es8328_id[] = {
- { "es8328", 0 },
- { "es8388", 0 },
+ { "es8328" },
+ { "es8388" },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8328_id);
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 160adc706cc6..1e11175cfbbb 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -9,7 +9,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -143,7 +142,7 @@ static int es8328_set_deemph(struct snd_soc_component *component)
static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = es8328->deemph;
@@ -153,7 +152,7 @@ static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
int ret;
@@ -234,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),
@@ -244,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),
};
@@ -337,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)),
@@ -419,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" },
@@ -557,8 +549,15 @@ static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
struct snd_soc_component *component = codec_dai->component;
struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
int mclkdiv2 = 0;
+ unsigned int round_freq;
- switch (freq) {
+ /*
+ * Allow a small tolerance for frequencies within 100hz. Note
+ * this value is chosen arbitrarily.
+ */
+ round_freq = DIV_ROUND_CLOSEST(freq, 100) * 100;
+
+ switch (round_freq) {
case 0:
es8328->sysclk_constraints = NULL;
es8328->mclk_ratios = NULL;
@@ -644,6 +643,8 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int es8328_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
break;
@@ -659,7 +660,7 @@ static int es8328_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component, ES8328_CONTROL1,
ES8328_CONTROL1_VMIDSEL_MASK |
ES8328_CONTROL1_ENREF,
@@ -822,7 +823,7 @@ const struct regmap_config es8328_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ES8328_REG_MAX,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
diff --git a/sound/soc/codecs/es8375.c b/sound/soc/codecs/es8375.c
new file mode 100644
index 000000000000..36b0ebdce514
--- /dev/null
+++ b/sound/soc/codecs/es8375.c
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * es8375.c -- ES8375 ALSA SoC Audio Codec
+ *
+ * Copyright Everest Semiconductor Co., Ltd
+ *
+ * Authors: Michael Zhang (zhangyi@everest-semi.com)
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <linux/acpi.h>
+#include "es8375.h"
+
+struct es8375_priv {
+ struct regmap *regmap;
+ struct clk *mclk;
+ struct regulator_bulk_data core_supply[2];
+ unsigned int mclk_freq;
+ int mastermode;
+ u8 mclk_src;
+ u8 vddd;
+ enum snd_soc_bias_level bias_level;
+};
+
+static const char * const es8375_core_supplies[] = {
+ "vddd",
+ "vdda",
+};
+
+static const DECLARE_TLV_DB_SCALE(es8375_adc_osr_gain_tlv, -3100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_adc_volume_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_adc_automute_attn_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_adc_dmic_volume_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_dac_volume_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_dac_vppscale_tlv, -388, 12, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_dac_automute_attn_tlv, 0, 400, 0);
+static const DECLARE_TLV_DB_SCALE(es8375_automute_ng_tlv, -9600, 600, 0);
+
+static const char *const es8375_ramprate_txt[] = {
+ "0.125dB/LRCK",
+ "0.125dB/2LRCK",
+ "0.125dB/4LRCK",
+ "0.125dB/8LRCK",
+ "0.125dB/16LRCK",
+ "0.125dB/32LRCK",
+ "0.125dB/64LRCK",
+ "0.125dB/128LRCK",
+ "disable softramp",
+};
+static SOC_ENUM_SINGLE_DECL(es8375_adc_ramprate, ES8375_ADC2,
+ ADC_RAMPRATE_SHIFT_0, es8375_ramprate_txt);
+static SOC_ENUM_SINGLE_DECL(es8375_dac_ramprate, ES8375_DAC2,
+ DAC_RAMPRATE_SHIFT_0, es8375_ramprate_txt);
+
+static const char *const es8375_automute_ws_txt[] = {
+ "256 samples",
+ "512 samples",
+ "1024 samples",
+ "2048 samples",
+ "4096 samples",
+ "8192 samples",
+ "16384 samples",
+ "32768 samples",
+};
+static SOC_ENUM_SINGLE_DECL(es8375_adc_automute_ws, ES8375_ADC_AUTOMUTE,
+ ADC_AUTOMUTE_WS_SHIFT_3, es8375_automute_ws_txt);
+static SOC_ENUM_SINGLE_DECL(es8375_dac_automute_ws, ES8375_DAC_AUTOMUTE,
+ DAC_AUTOMUTE_WS_SHIFT_5, es8375_automute_ws_txt);
+
+static const char *const es8375_dmic_pol_txt[] = {
+ "Low",
+ "High",
+};
+
+static SOC_ENUM_SINGLE_DECL(es8375_dmic_pol, ES8375_ADC1,
+ DMIC_POL_SHIFT_4, es8375_dmic_pol_txt);
+
+static const char *const es8375_adc_hpf_txt[] = {
+ "Freeze Offset",
+ "Dynamic HPF",
+};
+
+static SOC_ENUM_SINGLE_DECL(es8375_adc_hpf, ES8375_HPF1,
+ ADC_HPF_SHIFT_5, es8375_adc_hpf_txt);
+
+static const char *const es8375_dmic_mux_txt[] = {
+ "AMIC",
+ "DMIC",
+};
+static const struct soc_enum es8375_dmic_mux_enum =
+ SOC_ENUM_SINGLE(ES8375_ADC1, ADC_SRC_SHIFT_7,
+ ARRAY_SIZE(es8375_dmic_mux_txt), es8375_dmic_mux_txt);
+
+static const struct snd_kcontrol_new es8375_dmic_mux_controls =
+ SOC_DAPM_ENUM("ADC MUX", es8375_dmic_mux_enum);
+
+static const struct snd_kcontrol_new es8375_snd_controls[] = {
+ SOC_SINGLE_TLV("ADC OSR Volume", ES8375_ADC_OSR_GAIN,
+ ADC_OSR_GAIN_SHIFT_0, ES8375_ADC_OSR_GAIN_MAX, 0,
+ es8375_adc_osr_gain_tlv),
+ SOC_SINGLE("ADC Invert Switch", ES8375_ADC1, ADC_INV_SHIFT_6, 1, 0),
+ SOC_SINGLE("ADC RAM Clear", ES8375_ADC1, ADC_RAMCLR_SHIFT_5, 1, 0),
+ SOC_ENUM("DMIC Polarity", es8375_dmic_pol),
+ SOC_SINGLE_TLV("DMIC Volume", ES8375_ADC1,
+ DMIC_GAIN_SHIFT_2, ES8375_DMIC_GAIN_MAX,
+ 0, es8375_adc_dmic_volume_tlv),
+ SOC_ENUM("ADC Ramp Rate", es8375_adc_ramprate),
+ SOC_SINGLE_TLV("ADC Volume", ES8375_ADC_VOLUME,
+ ADC_VOLUME_SHIFT_0, ES8375_ADC_VOLUME_MAX,
+ 0, es8375_adc_volume_tlv),
+ SOC_SINGLE("ADC Automute Switch", ES8375_ADC_AUTOMUTE,
+ ADC_AUTOMUTE_SHIFT_7, 1, 0),
+ SOC_ENUM("ADC Automute Winsize", es8375_adc_automute_ws),
+ SOC_SINGLE_TLV("ADC Automute Noise Gate", ES8375_ADC_AUTOMUTE,
+ ADC_AUTOMUTE_NG_SHIFT_0, ES8375_AUTOMUTE_NG_MAX,
+ 0, es8375_automute_ng_tlv),
+ SOC_SINGLE_TLV("ADC Automute Volume", ES8375_ADC_AUTOMUTE_ATTN,
+ ADC_AUTOMUTE_ATTN_SHIFT_0, ES8375_ADC_AUTOMUTE_ATTN_MAX,
+ 0, es8375_adc_automute_attn_tlv),
+ SOC_ENUM("ADC HPF", es8375_adc_hpf),
+
+ SOC_SINGLE("DAC DSM Mute Switch", ES8375_DAC1, DAC_DSMMUTE_SHIFT_7, 1, 0),
+ SOC_SINGLE("DAC DEM Mute Switch", ES8375_DAC1, DAC_DEMMUTE_SHIFT_6, 1, 0),
+ SOC_SINGLE("DAC Invert Switch", ES8375_DAC1, DAC_INV_SHIFT_5, 1, 0),
+ SOC_SINGLE("DAC RAM Clear", ES8375_DAC1, DAC_RAMCLR_SHIFT_4, 1, 0),
+ SOC_ENUM("DAC Ramp Rate", es8375_dac_ramprate),
+ SOC_SINGLE_TLV("DAC Volume", ES8375_DAC_VOLUME,
+ DAC_VOLUME_SHIFT_0, ES8375_DAC_VOLUME_MAX,
+ 0, es8375_dac_volume_tlv),
+ SOC_SINGLE_TLV("DAC VPP Scale", ES8375_DAC_VPPSCALE,
+ DAC_VPPSCALE_SHIFT_0, ES8375_DAC_VPPSCALE_MAX,
+ 0, es8375_dac_vppscale_tlv),
+ SOC_SINGLE("DAC Automute Switch", ES8375_DAC_AUTOMUTE1,
+ DAC_AUTOMUTE_EN_SHIFT_7, 1, 0),
+ SOC_SINGLE_TLV("DAC Automute Noise Gate", ES8375_DAC_AUTOMUTE1,
+ DAC_AUTOMUTE_NG_SHIFT_0, ES8375_AUTOMUTE_NG_MAX,
+ 0, es8375_automute_ng_tlv),
+ SOC_ENUM("DAC Automute Winsize", es8375_dac_automute_ws),
+ SOC_SINGLE_TLV("DAC Automute Volume", ES8375_DAC_AUTOMUTE,
+ DAC_AUTOMUTE_ATTN_SHIFT_0, ES8375_DAC_AUTOMUTE_ATTN_MAX,
+ 0, es8375_dac_automute_attn_tlv),
+};
+
+static const struct snd_soc_dapm_widget es8375_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("DMIC"),
+ SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_ADC("Mono ADC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, ES8375_SDP2,
+ ES8375_ADC_P2S_MUTE_SHIFT_5, 1),
+
+ SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8375_dmic_mux_controls),
+
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, ES8375_SDP,
+ SND_SOC_NOPM, 0),
+ SND_SOC_DAPM_DAC("Mono DAC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route es8375_dapm_routes[] = {
+ {"ADC MUX", "AMIC", "MIC1"},
+ {"ADC MUX", "DMIC", "DMIC"},
+ {"PGA", NULL, "ADC MUX"},
+ {"Mono ADC", NULL, "PGA"},
+ {"AIF1TX", NULL, "Mono ADC"},
+
+ {"Mono DAC", NULL, "AIF1RX"},
+ {"OUT", NULL, "Mono DAC"},
+};
+
+struct _coeff_div {
+ u16 mclk_lrck_ratio;
+ u32 mclk;
+ u32 rate;
+ u8 Reg0x04;
+ u8 Reg0x05;
+ u8 Reg0x06;
+ u8 Reg0x07;
+ u8 Reg0x08;
+ u8 Reg0x09;
+ u8 Reg0x0A;
+ u8 Reg0x0B;
+ u8 Reg0x19;
+ u8 dvdd_vol;
+ u8 dmic_sel;
+};
+
+static const struct _coeff_div coeff_div[] = {
+ {32, 256000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
+ {32, 512000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
+ {32, 1536000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
+ {36, 288000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
+ {36, 576000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
+ {36, 1728000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
+ {48, 384000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
+ {48, 768000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
+ {48, 2304000, 48000, 0x05, 0x11, 0x53, 0x55, 0x17, 0x20, 0x92, 0x00, 0x28, 2, 2},
+ {50, 400000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
+ {50, 800000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
+ {50, 2400000, 48000, 0x05, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
+ {64, 512000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
+ {64, 1024000, 16000, 0x05, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
+ {64, 3072000, 48000, 0x05, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
+ {72, 576000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
+ {72, 1152000, 16000, 0x05, 0x13, 0x55, 0x33, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
+ {72, 3456000, 48000, 0x05, 0x11, 0x53, 0x33, 0x23, 0x08, 0x92, 0x00, 0x1F, 2, 2},
+ {96, 768000, 8000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
+ {96, 1536000, 16000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
+ {96, 4608000, 48000, 0x15, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
+ {100, 800000, 8000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
+ {100, 1600000, 16000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x93, 0x00, 0x27, 2, 2},
+ {100, 4800000, 48000, 0x03, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
+ {128, 1024000, 8000, 0x05, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x93, 0x01, 0x1F, 2, 2},
+ {128, 2048000, 16000, 0x03, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
+ {128, 6144000, 48000, 0x03, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
+ {144, 1152000, 8000, 0x05, 0x03, 0x35, 0x11, 0x23, 0x08, 0x93, 0x01, 0x1F, 2, 2},
+ {144, 2304000, 16000, 0x03, 0x01, 0x33, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
+ {144, 6912000, 48000, 0x03, 0x00, 0x31, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
+ {192, 1536000, 8000, 0x15, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x93, 0x02, 0x1F, 2, 2},
+ {192, 3072000, 16000, 0x15, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
+ {192, 9216000, 48000, 0x15, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
+ {250, 12000000, 48000, 0x25, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
+ {256, 2048000, 8000, 0x0D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
+ {256, 4096000, 16000, 0x0B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
+ {256, 12288000, 48000, 0x0B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
+ {384, 3072000, 8000, 0x15, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
+ {384, 6144000, 16000, 0x13, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
+ {384, 18432000, 48000, 0x13, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
+ {400, 19200000, 48000, 0x1B, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
+ {500, 24000000, 48000, 0x23, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
+ {512, 4096000, 8000, 0x1D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
+ {512, 8192000, 16000, 0x1B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
+ {512, 24576000, 48000, 0x1B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
+ {768, 6144000, 8000, 0x2D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
+ {768, 12288000, 16000, 0x2B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
+ {1024, 8192000, 8000, 0x3D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
+ {1024, 16384000, 16000, 0x3B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
+ {1152, 9216000, 8000, 0x45, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
+ {1152, 18432000, 16000, 0x43, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
+ {1200, 9600000, 8000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
+ {1200, 19200000, 16000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
+ {1536, 12288000, 8000, 0x5D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
+ {1536, 24576000, 16000, 0x5B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
+ {2048, 16384000, 8000, 0x7D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x1F, 0x1F, 2, 2},
+ {2304, 18432000, 8000, 0x8D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x23, 0x1F, 2, 2},
+ {2400, 19200000, 8000, 0xBD, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x25, 0x27, 2, 2},
+ {3072, 24576000, 8000, 0xBD, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x2F, 0x1F, 2, 2},
+ {32, 3072000, 96000, 0x05, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
+ {64, 6144000, 96000, 0x03, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
+ {96, 9216000, 96000, 0x15, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
+ {128, 12288000, 96000, 0x0B, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x01, 0x37, 2, 2},
+};
+
+static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
+{
+ int i;
+ u8 dmic_det, vddd_det;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) {
+ vddd_det = ~(coeff_div[i].dvdd_vol ^ vddd) & 0x01;
+ dmic_det = ~(coeff_div[i].dmic_sel ^ dmic) & 0x01;
+ vddd_det |= ~(coeff_div[i].dvdd_vol % 2) & 0x01;
+ dmic_det |= ~(coeff_div[i].dmic_sel % 2) & 0x01;
+
+ if (vddd_det && dmic_det)
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int es8375_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+ int par_width = params_width(params);
+ u8 dmic_enable, iface = 0;
+ unsigned int regv;
+ int coeff, ret;
+
+ if (es8375->mclk_src == ES8375_BCLK_PIN) {
+ regmap_update_bits(es8375->regmap,
+ ES8375_MCLK_SEL, 0x80, 0x80);
+
+ es8375->mclk_freq = 2 * (unsigned int)par_width * params_rate(params);
+ }
+
+ regmap_read(es8375->regmap, ES8375_ADC1, &regv);
+ dmic_enable = regv >> 7 & 0x01;
+
+ ret = regulator_get_voltage(es8375->core_supply[ES8375_SUPPLY_VD].consumer);
+ switch (ret) {
+ case 1800000 ... 2000000:
+ es8375->vddd = ES8375_1V8;
+ break;
+ case 2500000 ... 3300000:
+ es8375->vddd = ES8375_3V3;
+ break;
+ default:
+ es8375->vddd = ES8375_3V3;
+ break;
+ }
+
+ coeff = get_coeff(es8375->vddd, dmic_enable, es8375->mclk_freq, params_rate(params));
+ if (coeff < 0) {
+ dev_warn(component->dev, "Clock coefficients do not match");
+ return coeff;
+ }
+ regmap_write(es8375->regmap, ES8375_CLK_MGR4,
+ coeff_div[coeff].Reg0x04);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR5,
+ coeff_div[coeff].Reg0x05);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR6,
+ coeff_div[coeff].Reg0x06);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR7,
+ coeff_div[coeff].Reg0x07);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR8,
+ coeff_div[coeff].Reg0x08);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR9,
+ coeff_div[coeff].Reg0x09);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR10,
+ coeff_div[coeff].Reg0x0A);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR11,
+ coeff_div[coeff].Reg0x0B);
+ regmap_write(es8375->regmap, ES8375_ADC_OSR_GAIN,
+ coeff_div[coeff].Reg0x19);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ iface |= 0x0c;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x04;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ iface |= 0x10;
+ break;
+ }
+
+ regmap_update_bits(es8375->regmap, ES8375_SDP, 0x1c, iface);
+
+ return 0;
+}
+
+static int es8375_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+
+ es8375->mclk_freq = freq;
+
+ return 0;
+}
+
+static int es8375_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+ unsigned int iface, codeciface;
+
+ regmap_read(es8375->regmap, ES8375_SDP, &codeciface);
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFP:
+ es8375->mastermode = 1;
+ regmap_update_bits(es8375->regmap, ES8375_RESET1,
+ 0x80, 0x80);
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ es8375->mastermode = 0;
+ regmap_update_bits(es8375->regmap, ES8375_RESET1,
+ 0x80, 0x00);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ codeciface &= 0xFC;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ return -EINVAL;
+ case SND_SOC_DAIFMT_LEFT_J:
+ codeciface &= 0xFC;
+ codeciface |= 0x01;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ codeciface &= 0xDC;
+ codeciface |= 0x03;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ codeciface &= 0xDC;
+ codeciface |= 0x23;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_read(es8375->regmap, ES8375_CLK_MGR3, &iface);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ iface &= 0xFE;
+ codeciface &= 0xDF;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x01;
+ codeciface |= 0x20;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x01;
+ codeciface &= 0xDF;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface &= 0xFE;
+ codeciface |= 0x20;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_write(es8375->regmap, ES8375_CLK_MGR3, iface);
+ regmap_write(es8375->regmap, ES8375_SDP, codeciface);
+
+ return 0;
+}
+
+static int es8375_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ ret = clk_prepare_enable(es8375->mclk);
+ if (ret) {
+ dev_err(component->dev, "unable to prepare mclk\n");
+ return ret;
+ }
+ regmap_write(es8375->regmap, ES8375_CSM1, 0xA6);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ regmap_write(es8375->regmap, ES8375_CSM1, 0x96);
+ clk_disable_unprepare(es8375->mclk);
+ break;
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+ return 0;
+}
+
+static int es8375_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+
+ if (mute) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(es8375->regmap, ES8375_SDP, 0x40, 0x40);
+ else
+ regmap_update_bits(es8375->regmap, ES8375_SDP2, 0x20, 0x20);
+ } else {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(es8375->regmap, ES8375_SDP, 0x40, 0x00);
+ else
+ regmap_update_bits(es8375->regmap, ES8375_SDP2, 0x20, 0x00);
+ }
+
+ return 0;
+}
+
+#define es8375_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8375_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops es8375_ops = {
+ .hw_params = es8375_hw_params,
+ .mute_stream = es8375_mute,
+ .set_sysclk = es8375_set_sysclk,
+ .set_fmt = es8375_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver es8375_dai = {
+ .name = "ES8375 HiFi",
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = es8375_RATES,
+ .formats = es8375_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = es8375_RATES,
+ .formats = es8375_FORMATS,
+ },
+ .ops = &es8375_ops,
+ .symmetric_rate = 1,
+};
+
+static void es8375_init(struct snd_soc_component *component)
+{
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+
+ regmap_write(es8375->regmap, ES8375_CLK_MGR10, 0x95);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x48);
+ regmap_write(es8375->regmap, ES8375_DIV_SPKCLK, 0x18);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x02);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x05);
+ regmap_write(es8375->regmap, ES8375_CSM1, 0x82);
+ regmap_write(es8375->regmap, ES8375_VMID_CHARGE2, 0x20);
+ regmap_write(es8375->regmap, ES8375_VMID_CHARGE3, 0x20);
+ regmap_write(es8375->regmap, ES8375_DAC_CAL, 0x28);
+ regmap_write(es8375->regmap, ES8375_ANALOG_SPK1, 0xFC);
+ regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE0);
+ regmap_write(es8375->regmap, ES8375_VMID_SEL, 0xFE);
+ regmap_write(es8375->regmap, ES8375_ANALOG1, 0xB8);
+ regmap_write(es8375->regmap, ES8375_SYS_CTRL2, 0x03);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0x16);
+ regmap_write(es8375->regmap, ES8375_RESET1, 0x00);
+ msleep(80);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x00);
+ regmap_write(es8375->regmap, ES8375_CSM1, 0x86);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x0B);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x00);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR6, 0x31);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR7, 0x11);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR8, 0x1F);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR9, 0x00);
+ regmap_write(es8375->regmap, ES8375_ADC_OSR_GAIN, 0x1F);
+ regmap_write(es8375->regmap, ES8375_ADC2, 0x00);
+ regmap_write(es8375->regmap, ES8375_DAC2, 0x00);
+ regmap_write(es8375->regmap, ES8375_DAC_OTP, 0x88);
+ regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE7);
+ regmap_write(es8375->regmap, ES8375_ANALOG2, 0xF0);
+ regmap_write(es8375->regmap, ES8375_ANALOG3, 0x40);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0xFE);
+
+ regmap_update_bits(es8375->regmap, ES8375_SDP, 0x40, 0x40);
+ regmap_update_bits(es8375->regmap, ES8375_SDP2, 0x20, 0x20);
+}
+
+static int es8375_suspend(struct snd_soc_component *component)
+{
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+
+ regmap_write(es8375->regmap, ES8375_CSM1, 0x96);
+ regcache_cache_only(es8375->regmap, true);
+ regcache_mark_dirty(es8375->regmap);
+ return 0;
+}
+
+static int es8375_resume(struct snd_soc_component *component)
+{
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+ unsigned int reg;
+
+ regcache_cache_only(es8375->regmap, false);
+ regcache_cache_bypass(es8375->regmap, true);
+ regmap_read(es8375->regmap, ES8375_CLK_MGR2, &reg);
+ regcache_cache_bypass(es8375->regmap, false);
+
+ if (reg == 0x00)
+ es8375_init(component);
+ else
+ es8375_set_bias_level(component, SND_SOC_BIAS_ON);
+
+ regcache_sync(es8375->regmap);
+
+ return 0;
+}
+
+static int es8375_codec_probe(struct snd_soc_component *component)
+{
+ struct es8375_priv *es8375 = snd_soc_component_get_drvdata(component);
+
+ es8375->mastermode = 0;
+
+ es8375_init(component);
+
+ return 0;
+}
+
+static bool es8375_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ES8375_CHIP_VERSION:
+ case ES8375_CHIP_ID0:
+ case ES8375_CHIP_ID1:
+ case ES8375_SPK_OFFSET:
+ case ES8375_FLAGS2:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config es8375_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ES8375_REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+ .writeable_reg = es8375_writeable_register,
+};
+
+static struct snd_soc_component_driver es8375_codec_driver = {
+ .probe = es8375_codec_probe,
+ .suspend = es8375_suspend,
+ .resume = es8375_resume,
+ .set_bias_level = es8375_set_bias_level,
+ .controls = es8375_snd_controls,
+ .num_controls = ARRAY_SIZE(es8375_snd_controls),
+ .dapm_widgets = es8375_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8375_dapm_widgets),
+ .dapm_routes = es8375_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8375_dapm_routes),
+
+ .idle_bias_on = 1,
+ .suspend_bias_off = 1,
+};
+
+static int es8375_read_device_properities(struct device *dev, struct es8375_priv *es8375)
+{
+ int ret, i;
+
+ ret = device_property_read_u8(dev, "everest,mclk-src", &es8375->mclk_src);
+ if (ret != 0)
+ es8375->mclk_src = ES8375_MCLK_SOURCE;
+ dev_dbg(dev, "mclk-src %x", es8375->mclk_src);
+
+ for (i = 0; i < ARRAY_SIZE(es8375_core_supplies); i++)
+ es8375->core_supply[i].supply = es8375_core_supplies[i];
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8375_core_supplies), es8375->core_supply);
+ if (ret) {
+ dev_err(dev, "Failed to request core supplies %d\n", ret);
+ return ret;
+ }
+
+ es8375->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(es8375->mclk))
+ return dev_err_probe(dev, PTR_ERR(es8375->mclk), "unable to get mclk\n");
+
+ if (!es8375->mclk)
+ dev_warn(dev, "assuming static mclk\n");
+
+ ret = clk_prepare_enable(es8375->mclk);
+ if (ret) {
+ dev_err(dev, "unable to enable mclk\n");
+ return ret;
+ }
+ ret = regulator_bulk_enable(ARRAY_SIZE(es8375_core_supplies), es8375->core_supply);
+ if (ret) {
+ dev_err(dev, "Failed to enable core supplies: %d\n", ret);
+ clk_disable_unprepare(es8375->mclk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int es8375_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct es8375_priv *es8375;
+ struct device *dev = &i2c_client->dev;
+ int ret;
+ unsigned int val;
+
+ es8375 = devm_kzalloc(&i2c_client->dev, sizeof(*es8375), GFP_KERNEL);
+ if (!es8375)
+ return -ENOMEM;
+
+ es8375->regmap = devm_regmap_init_i2c(i2c_client,
+ &es8375_regmap_config);
+ if (IS_ERR(es8375->regmap))
+ return dev_err_probe(&i2c_client->dev, PTR_ERR(es8375->regmap),
+ "regmap_init() failed\n");
+
+ i2c_set_clientdata(i2c_client, es8375);
+
+ ret = regmap_read(es8375->regmap, ES8375_CHIP_ID1, &val);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+ i2c_client->addr);
+ return ret;
+ }
+
+ if (val != 0x83) {
+ dev_err(&i2c_client->dev, "device at addr %X is not an es8375\n",
+ i2c_client->addr);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(es8375->regmap, ES8375_CHIP_ID0, &val);
+ if (val != 0x75) {
+ dev_err(&i2c_client->dev, "device at addr %X is not an es8375\n",
+ i2c_client->addr);
+ return -ENODEV;
+ }
+
+ ret = es8375_read_device_properities(dev, es8375);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev, "get an error from dts info %X\n", ret);
+ return ret;
+ }
+
+ return devm_snd_soc_register_component(&i2c_client->dev, &es8375_codec_driver,
+ &es8375_dai, 1);
+}
+
+static void es8375_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct es8375_priv *es8375;
+
+ es8375 = i2c_get_clientdata(i2c);
+
+ regmap_write(es8375->regmap, ES8375_CSM1, 0x3C);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x48);
+ regmap_write(es8375->regmap, ES8375_CSM2, 0x80);
+ regmap_write(es8375->regmap, ES8375_CSM1, 0x3E);
+ regmap_write(es8375->regmap, ES8375_CLK_MGR10, 0x15);
+ regmap_write(es8375->regmap, ES8375_SYS_CTRL2, 0x0C);
+ regmap_write(es8375->regmap, ES8375_RESET1, 0x00);
+ regmap_write(es8375->regmap, ES8375_CSM2, 0x00);
+
+ regulator_bulk_disable(ARRAY_SIZE(es8375_core_supplies), es8375->core_supply);
+ clk_disable_unprepare(es8375->mclk);
+}
+
+static const struct i2c_device_id es8375_id[] = {
+ {"es8375"},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, es8375_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id es8375_acpi_match[] = {
+ {"ESSX8375", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, es8375_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id es8375_of_match[] = {
+ {.compatible = "everest,es8375",},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, es8375_of_match);
+#endif
+
+static struct i2c_driver es8375_i2c_driver = {
+ .driver = {
+ .name = "es8375",
+ .of_match_table = of_match_ptr(es8375_of_match),
+ .acpi_match_table = ACPI_PTR(es8375_acpi_match),
+ },
+ .shutdown = es8375_i2c_shutdown,
+ .probe = es8375_i2c_probe,
+ .id_table = es8375_id,
+};
+module_i2c_driver(es8375_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8375 driver");
+MODULE_AUTHOR("Michael Zhang <zhangyi@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8375.h b/sound/soc/codecs/es8375.h
new file mode 100644
index 000000000000..11e3ceec9b68
--- /dev/null
+++ b/sound/soc/codecs/es8375.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+* ES8375.h -- ES8375 ALSA SoC Audio Codec
+*
+* Authors:
+*
+* Based on ES8375.h by Michael Zhang
+*/
+#ifndef _ES8375_H
+#define _ES8375_H
+
+// Registors
+#define ES8375_RESET1 0x00
+#define ES8375_MCLK_SEL 0x01
+#define ES8375_CLK_MGR2 0x02
+#define ES8375_CLK_MGR3 0x03
+#define ES8375_CLK_MGR4 0x04
+#define ES8375_CLK_MGR5 0x05
+#define ES8375_CLK_MGR6 0x06
+#define ES8375_CLK_MGR7 0x07
+#define ES8375_CLK_MGR8 0x08
+#define ES8375_CLK_MGR9 0x09
+#define ES8375_CLK_MGR10 0x0A
+#define ES8375_CLK_MGR11 0x0B
+#define ES8375_CLK_MGR12 0x0C
+#define ES8375_DIV_SPKCLK 0x0E
+#define ES8375_CSM1 0x0F
+#define ES8375_CSM2 0x10
+#define ES8375_VMID_CHARGE2 0x11
+#define ES8375_VMID_CHARGE3 0x12
+#define ES8375_SDP 0x15
+#define ES8375_SDP2 0x16
+#define ES8375_ADC1 0x17
+#define ES8375_ADC2 0x18
+#define ES8375_ADC_OSR_GAIN 0x19
+#define ES8375_ADC_VOLUME 0x1A
+#define ES8375_ADC_AUTOMUTE 0x1B
+#define ES8375_ADC_AUTOMUTE_ATTN 0x1C
+#define ES8375_HPF1 0x1D
+#define ES8375_DAC1 0x1F
+#define ES8375_DAC2 0x20
+#define ES8375_DAC_VOLUME 0x21
+#define ES8375_DAC_VPPSCALE 0x22
+#define ES8375_DAC_AUTOMUTE1 0x23
+#define ES8375_DAC_AUTOMUTE 0x24
+#define ES8375_DAC_CAL 0x25
+#define ES8375_DAC_OTP 0x27
+#define ES8375_ANALOG_SPK1 0x28
+#define ES8375_ANALOG_SPK2 0x29
+#define ES8375_VMID_SEL 0x2D
+#define ES8375_ANALOG1 0x2E
+#define ES8375_ANALOG2 0x32
+#define ES8375_ANALOG3 0x37
+#define ES8375_ADC2DAC_CLKTRI 0xF8
+#define ES8375_SYS_CTRL2 0xF9
+#define ES8375_FLAGS2 0xFB
+#define ES8375_SPK_OFFSET 0xFC
+#define ES8375_CHIP_ID1 0xFD
+#define ES8375_CHIP_ID0 0xFE
+#define ES8375_CHIP_VERSION 0xFF
+
+// Bit Shifts
+#define ADC_OSR_GAIN_SHIFT_0 0
+#define ADC_RAMPRATE_SHIFT_0 0
+#define ADC_VOLUME_SHIFT_0 0
+#define ADC_AUTOMUTE_NG_SHIFT_0 0
+#define ADC_AUTOMUTE_ATTN_SHIFT_0 0
+#define DAC_RAMPRATE_SHIFT_0 0
+#define DAC_VOLUME_SHIFT_0 0
+#define DAC_VPPSCALE_SHIFT_0 0
+#define DAC_AUTOMUTE_NG_SHIFT_0 0
+#define DAC_AUTOMUTE_ATTN_SHIFT_0 0
+#define DMIC_GAIN_SHIFT_2 2
+#define ADC_AUTOMUTE_WS_SHIFT_3 3
+#define DMIC_POL_SHIFT_4 4
+#define DAC_RAMCLR_SHIFT_4 4
+#define ES8375_EN_MODL_SHIFT_4 4
+#define ADC_RAMCLR_SHIFT_5 5
+#define ADC_HPF_SHIFT_5 5
+#define DAC_INV_SHIFT_5 5
+#define DAC_AUTOMUTE_WS_SHIFT_5 5
+#define ES8375_EN_PGAL_SHIFT_5 5
+#define ES8375_ADC_P2S_MUTE_SHIFT_5 5
+#define ADC_INV_SHIFT_6 6
+#define DAC_DEMMUTE_SHIFT_6 6
+#define ES8375_DAC_S2P_MUTE_SHIFT_6 6
+#define ADC_SRC_SHIFT_7 7
+#define ADC_AUTOMUTE_SHIFT_7 7
+#define DAC_DSMMUTE_SHIFT_7 7
+#define DAC_AUTOMUTE_EN_SHIFT_7 7
+
+// Function values
+#define ES8375_ADC_OSR_GAIN_MAX 0x3F
+#define ES8375_DMIC_GAIN_MAX 0x04
+#define ES8375_ADC_AUTOMUTE_ATTN_MAX 0x1F
+#define ES8375_AUTOMUTE_NG_MAX 0x07
+#define ES8375_ADC_VOLUME_MAX 0xFF
+#define ES8375_DAC_VOLUME_MAX 0xFF
+#define ES8375_DAC_VPPSCALE_MAX 0x3F
+#define ES8375_DAC_AUTOMUTE_ATTN_MAX 0x17
+#define ES8375_REG_MAX 0xFF
+
+enum ES8375_supplies {
+ ES8375_SUPPLY_VD = 0,
+ ES8375_SUPPLY_VA,
+};
+
+// Properties
+#define ES8375_3V3 1
+#define ES8375_1V8 0
+
+#define ES8375_MCLK_PIN 0
+#define ES8375_BCLK_PIN 1
+#define ES8375_MCLK_SOURCE ES8375_MCLK_PIN
+
+#define DMIC_POSITIVE_EDGE 0
+#define DMIC_NEGATIVE_EDGE 1
+#define DMIC_POL DMIC_POSITIVE_EDGE
+
+#define PA_SHUTDOWN 0
+#define PA_ENABLE 1
+
+#endif
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
new file mode 100644
index 000000000000..a84d79f9d3d1
--- /dev/null
+++ b/sound/soc/codecs/es8389.c
@@ -0,0 +1,962 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * es8389.c -- ES8389 ALSA SoC Audio Codec
+ *
+ * Copyright Everest Semiconductor Co., Ltd
+ *
+ * Authors: Michael Zhang (zhangyi@everest-semi.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+
+#include "es8389.h"
+
+
+/* codec private data */
+
+struct es8389_private {
+ struct regmap *regmap;
+ struct clk *mclk;
+ unsigned int sysclk;
+ int mastermode;
+
+ u8 mclk_src;
+ enum snd_soc_bias_level bias_level;
+};
+
+static bool es8389_volatile_register(struct device *dev,
+ unsigned int reg)
+{
+ if ((reg <= 0xff))
+ return true;
+ else
+ return false;
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0);
+
+static int es8389_dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val;
+ bool changed1, changed2;
+
+ val = ucontrol->value.integer.value[0];
+ if (val > 1)
+ return -EINVAL;
+
+ if (val) {
+ regmap_update_bits_check(es8389->regmap, ES8389_DMIC_EN, 0xC0, 0xC0, &changed1);
+ regmap_update_bits_check(es8389->regmap, ES8389_ADC_MODE, 0x03, 0x03, &changed2);
+ } else {
+ regmap_update_bits_check(es8389->regmap, ES8389_DMIC_EN, 0xC0, 0x00, &changed1);
+ regmap_update_bits_check(es8389->regmap, ES8389_ADC_MODE, 0x03, 0x00, &changed2);
+ }
+
+ if (changed1 & changed2)
+ return snd_soc_dapm_mux_update_power(dapm, kcontrol, val, e, NULL);
+ else
+ return 0;
+}
+
+static const char *const alc[] = {
+ "ALC OFF",
+ "ADCR ALC ON",
+ "ADCL ALC ON",
+ "ADCL & ADCL ALC ON",
+};
+
+static const char *const ramprate[] = {
+ "0.125db/1 LRCK",
+ "0.125db/4 LRCK",
+ "0.125db/8 LRCK",
+ "0.125db/16 LRCK",
+ "0.125db/32 LRCK",
+ "0.125db/64 LRCK",
+ "0.125db/128 LRCK",
+ "0.125db/256 LRCK",
+ "0.125db/512 LRCK",
+ "0.125db/1024 LRCK",
+ "0.125db/2048 LRCK",
+ "0.125db/4096 LRCK",
+ "0.125db/8192 LRCK",
+ "0.125db/16384 LRCK",
+ "0.125db/32768 LRCK",
+ "0.125db/65536 LRCK",
+};
+
+static const char *const winsize[] = {
+ "2 LRCK",
+ "4 LRCK",
+ "8 LRCK",
+ "16 LRCK",
+ "32 LRCK",
+ "64 LRCK",
+ "128 LRCK",
+ "256 LRCK",
+ "512 LRCK",
+ "1024 LRCK",
+ "2048 LRCK",
+ "4096 LRCK",
+ "8192 LRCK",
+ "16384 LRCK",
+ "32768 LRCK",
+ "65536 LRCK",
+};
+
+static const struct soc_enum alc_enable =
+ SOC_ENUM_SINGLE(ES8389_ALC_ON, 5, 4, alc);
+static const struct soc_enum alc_ramprate =
+ SOC_ENUM_SINGLE(ES8389_ALC_CTL, 4, 16, ramprate);
+static const struct soc_enum alc_winsize =
+ SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize);
+
+static const char *const es8389_outl_mux_txt[] = {
+ "Normal",
+ "DAC2 channel to DAC1 channel",
+};
+
+static const char *const es8389_outr_mux_txt[] = {
+ "Normal",
+ "DAC1 channel to DAC2 channel",
+};
+
+static const char *const es8389_dmic_mux_txt[] = {
+ "AMIC",
+ "DMIC",
+};
+
+static const char *const es8389_pga1_texts[] = {
+ "DifferentialL", "Line 1P", "Line 2P"
+};
+
+static const char *const es8389_pga2_texts[] = {
+ "DifferentialR", "Line 2N", "Line 1N"
+};
+
+static const unsigned int es8389_pga_values[] = {
+ 1, 5, 6
+};
+
+static const struct soc_enum es8389_outl_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5,
+ ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt);
+
+static const struct snd_kcontrol_new es8389_outl_mux_controls =
+ SOC_DAPM_ENUM("OUTL MUX", es8389_outl_mux_enum);
+
+static const struct soc_enum es8389_outr_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_DAC_MIX, 4,
+ ARRAY_SIZE(es8389_outr_mux_txt), es8389_outr_mux_txt);
+
+static const struct snd_kcontrol_new es8389_outr_mux_controls =
+ SOC_DAPM_ENUM("OUTR MUX", es8389_outr_mux_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ es8389_dmic_mux_enum, ES8389_DMIC_EN, 6, es8389_dmic_mux_txt);
+
+static const struct soc_enum es8389_pgal_enum =
+ SOC_VALUE_ENUM_SINGLE(ES8389_MIC1_GAIN, 4, 7,
+ ARRAY_SIZE(es8389_pga1_texts), es8389_pga1_texts,
+ es8389_pga_values);
+
+static const struct soc_enum es8389_pgar_enum =
+ SOC_VALUE_ENUM_SINGLE(ES8389_MIC2_GAIN, 4, 7,
+ ARRAY_SIZE(es8389_pga2_texts), es8389_pga2_texts,
+ es8389_pga_values);
+
+static const struct snd_kcontrol_new es8389_dmic_mux_controls =
+ SOC_DAPM_ENUM_EXT("ADC MUX", es8389_dmic_mux_enum,
+ snd_soc_dapm_get_enum_double, es8389_dmic_set);
+
+static const struct snd_kcontrol_new es8389_left_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACR DACL Mixer", ES8389_DAC_MIX, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8389_right_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACL DACR Mixer", ES8389_DAC_MIX, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8389_leftadc_mixer_controls[] = {
+ SOC_DAPM_SINGLE("ADCL DACL Mixer", ES8389_DAC_MIX, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8389_rightadc_mixer_controls[] = {
+ SOC_DAPM_SINGLE("ADCR DACR Mixer", ES8389_DAC_MIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8389_adc_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACL ADCL Mixer", ES8389_ADC_RESET, 7, 1, 0),
+ SOC_DAPM_SINGLE("DACR ADCR Mixer", ES8389_ADC_RESET, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new es8389_snd_controls[] = {
+ SOC_SINGLE_TLV("ADCL Capture Volume", ES8389_ADCL_VOL, 0, 0xFF, 0, adc_vol_tlv),
+ SOC_SINGLE_TLV("ADCR Capture Volume", ES8389_ADCR_VOL, 0, 0xFF, 0, adc_vol_tlv),
+ SOC_SINGLE_TLV("ADCL PGA Volume", ES8389_MIC1_GAIN, 0, 0x0E, 0, pga_vol_tlv),
+ SOC_SINGLE_TLV("ADCR PGA Volume", ES8389_MIC2_GAIN, 0, 0x0E, 0, pga_vol_tlv),
+
+ SOC_ENUM("PGAL Select", es8389_pgal_enum),
+ SOC_ENUM("PGAR Select", es8389_pgar_enum),
+ SOC_ENUM("ALC Capture Switch", alc_enable),
+ SOC_SINGLE_TLV("ALC Capture Target Level", ES8389_ALC_TARGET,
+ 0, 0x0f, 0, alc_target_tlv),
+ SOC_SINGLE_TLV("ALC Capture Max Gain", ES8389_ALC_GAIN,
+ 0, 0x0f, 0, alc_max_level),
+ SOC_ENUM("ADC Ramp Rate", alc_ramprate),
+ SOC_ENUM("ALC Capture Winsize", alc_winsize),
+ SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0),
+ SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv),
+ SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0),
+
+ SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv),
+ SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv),
+ SOC_DOUBLE("DAC OUTPUT Invert Switch", ES8389_DAC_INV, 5, 6, 1, 0),
+ SOC_SINGLE_TLV("ADC2DAC Mixer Volume", ES8389_MIX_VOL, 0, 0x7F, 0, mix_vol_tlv),
+};
+
+static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = {
+ /*Input Side*/
+ SND_SOC_DAPM_INPUT("INPUT1"),
+ SND_SOC_DAPM_INPUT("INPUT2"),
+ SND_SOC_DAPM_INPUT("DMIC"),
+ SND_SOC_DAPM_PGA("PGAL", SND_SOC_NOPM, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGAR", SND_SOC_NOPM, 4, 0, NULL, 0),
+
+ /*ADCs*/
+ SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("I2S IN", "I2S Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /*DACs*/
+ SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+ /*Output Side*/
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF DACL1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF DACR1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF DACL2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF DACR2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF DACL3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF DACR3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Interface Select */
+ SND_SOC_DAPM_MIXER("IF DACL Mixer", SND_SOC_NOPM, 0, 0,
+ &es8389_left_mixer_controls[0],
+ ARRAY_SIZE(es8389_left_mixer_controls)),
+ SND_SOC_DAPM_MIXER("IF DACR Mixer", SND_SOC_NOPM, 0, 0,
+ &es8389_right_mixer_controls[0],
+ ARRAY_SIZE(es8389_right_mixer_controls)),
+ SND_SOC_DAPM_MIXER("IF ADCDACL Mixer", SND_SOC_NOPM, 0, 0,
+ &es8389_leftadc_mixer_controls[0],
+ ARRAY_SIZE(es8389_leftadc_mixer_controls)),
+ SND_SOC_DAPM_MIXER("IF ADCDACR Mixer", SND_SOC_NOPM, 0, 0,
+ &es8389_rightadc_mixer_controls[0],
+ ARRAY_SIZE(es8389_rightadc_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("ADC Mixer", SND_SOC_NOPM, 0, 0,
+ &es8389_adc_mixer_controls[0],
+ ARRAY_SIZE(es8389_adc_mixer_controls)),
+ SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls),
+
+ SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls),
+ SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls),
+};
+
+
+static const struct snd_soc_dapm_route es8389_dapm_routes[] = {
+ {"PGAL", NULL, "INPUT1"},
+ {"PGAR", NULL, "INPUT2"},
+
+ {"ADCL", NULL, "PGAL"},
+ {"ADCR", NULL, "PGAR"},
+
+ {"ADC Mixer", "DACL ADCL Mixer", "DACL"},
+ {"ADC Mixer", "DACR ADCR Mixer", "DACR"},
+ {"ADC Mixer", NULL, "ADCL"},
+ {"ADC Mixer", NULL, "ADCR"},
+
+ {"ADC MUX", "AMIC", "ADC Mixer"},
+ {"ADC MUX", "DMIC", "DMIC"},
+
+ {"I2S OUT", NULL, "ADC MUX"},
+
+ {"DACL", NULL, "I2S IN"},
+ {"DACR", NULL, "I2S IN"},
+
+ {"IF DACL1", NULL, "DACL"},
+ {"IF DACR1", NULL, "DACR"},
+ {"IF DACL2", NULL, "DACL"},
+ {"IF DACR2", NULL, "DACR"},
+ {"IF DACL3", NULL, "DACL"},
+ {"IF DACR3", NULL, "DACR"},
+
+ {"IF DACL Mixer", NULL, "IF DACL2"},
+ {"IF DACL Mixer", "DACR DACL Mixer", "IF DACR1"},
+ {"IF DACR Mixer", NULL, "IF DACR2"},
+ {"IF DACR Mixer", "DACL DACR Mixer", "IF DACL1"},
+
+ {"IF ADCDACL Mixer", NULL, "IF DACL Mixer"},
+ {"IF ADCDACL Mixer", "ADCL DACL Mixer", "IF DACL3"},
+ {"IF ADCDACR Mixer", NULL, "IF DACR Mixer"},
+ {"IF ADCDACR Mixer", "ADCR DACR Mixer", "IF DACR3"},
+
+ {"OUTL MUX", "Normal", "IF ADCDACL Mixer"},
+ {"OUTL MUX", "DAC2 channel to DAC1 channel", "IF ADCDACR Mixer"},
+ {"OUTR MUX", "Normal", "IF ADCDACR Mixer"},
+ {"OUTR MUX", "DAC1 channel to DAC2 channel", "IF ADCDACL Mixer"},
+
+ {"HPOL", NULL, "OUTL MUX"},
+ {"HPOR", NULL, "OUTR MUX"},
+
+};
+
+struct _coeff_div {
+ u16 fs;
+ u32 mclk;
+ u32 rate;
+ u8 Reg0x04;
+ u8 Reg0x05;
+ u8 Reg0x06;
+ u8 Reg0x07;
+ u8 Reg0x08;
+ u8 Reg0x09;
+ u8 Reg0x0A;
+ u8 Reg0x0F;
+ u8 Reg0x11;
+ u8 Reg0x21;
+ u8 Reg0x22;
+ u8 Reg0x26;
+ u8 Reg0x30;
+ u8 Reg0x41;
+ u8 Reg0x42;
+ u8 Reg0x43;
+ u8 Reg0xF0;
+ u8 Reg0xF1;
+ u8 Reg0x16;
+ u8 Reg0x18;
+ u8 Reg0x19;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+ {32, 256000, 8000, 0x00, 0x57, 0x84, 0xD0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {36, 288000, 8000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xB7, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {48, 384000, 8000, 0x02, 0x5F, 0x04, 0xC0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {64, 512000, 8000, 0x00, 0x4D, 0x24, 0xC0, 0x03, 0xD1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {72, 576000, 8000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xB7, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {96, 768000, 8000, 0x02, 0x57, 0x84, 0xD0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {128, 1024000, 8000, 0x00, 0x45, 0x04, 0xD0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {192, 1536000, 8000, 0x02, 0x4D, 0x24, 0xC0, 0x03, 0xD1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {256, 2048000, 8000, 0x01, 0x45, 0x04, 0xD0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {288, 2304000, 8000, 0x01, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xB7, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {384, 3072000, 8000, 0x02, 0x45, 0x04, 0xD0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {512, 4096000, 8000, 0x00, 0x41, 0x04, 0xE0, 0x00, 0xD1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {768, 6144000, 8000, 0x05, 0x45, 0x04, 0xD0, 0x03, 0xC1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {1024, 8192000, 8000, 0x01, 0x41, 0x06, 0xE0, 0x00, 0xD1, 0xB0, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {1536, 12288000, 8000, 0x02, 0x41, 0x04, 0xE0, 0x00, 0xD1, 0xB0, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {1625, 13000000, 8000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {2048, 16384000, 8000, 0x03, 0x44, 0x01, 0xC0, 0x00, 0xD2, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {2304, 18432000, 8000, 0x11, 0x45, 0x25, 0xF0, 0x00, 0xD1, 0xB0, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {3072, 24576000, 8000, 0x05, 0x44, 0x01, 0xC0, 0x00, 0xD2, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {32, 512000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xB7, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xB7, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xB7, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E},
+ {800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14},
+ {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B},
+ {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28},
+ {128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25},
+ {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28},
+ {128, 12288000, 96000, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28},
+ {256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28},
+ {128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F},
+
+ {50, 400000, 8000, 0x00, 0x75, 0x05, 0xC8, 0x01, 0xC1, 0x90, 0x10, 0x00, 0x18, 0xC7, 0xD0, 0xC0, 0x8F, 0xC7, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {600, 4800000, 8000, 0x05, 0x65, 0x25, 0xF9, 0x00, 0xD1, 0x90, 0x10, 0x00, 0x18, 0xC7, 0xD0, 0xC0, 0x8F, 0xC7, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {1500, 12000000, 8000, 0x0E, 0x25, 0x25, 0xE8, 0x00, 0xD1, 0x90, 0x40, 0x00, 0x31, 0xC7, 0xC5, 0x00, 0x8F, 0xC7, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {2400, 19200000, 8000, 0x0B, 0x01, 0x00, 0xD0, 0x00, 0xD1, 0x80, 0x90, 0x00, 0x31, 0xC7, 0xC5, 0x00, 0xC7, 0xC7, 0x00, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {3000, 24000000, 8000, 0x0E, 0x24, 0x05, 0xD0, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x31, 0xC7, 0xC5, 0x00, 0x8F, 0xC7, 0x01, 0x12, 0x00, 0x09, 0x19, 0x07},
+ {3250, 26000000, 8000, 0x40, 0x05, 0xA4, 0xC0, 0x00, 0xD1, 0x80, 0xD0, 0x00, 0x31, 0xC7, 0xC5, 0x00, 0xC7, 0xC7, 0x00, 0x12, 0x00, 0x09, 0x19, 0x07},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+ return -EINVAL;
+}
+
+/*
+ * if PLL not be used, use internal clk1 for mclk,otherwise, use internal clk2 for PLL source.
+ */
+static int es8389_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ es8389->sysclk = freq;
+
+ return 0;
+}
+
+static int es8389_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ regmap_update_bits(es8389->regmap, ES8389_PTDM_SLOT,
+ ES8389_TDM_SLOT, (slots << ES8389_TDM_SHIFT));
+ regmap_update_bits(es8389->regmap, ES8389_DAC_RAMP,
+ ES8389_TDM_SLOT, (slots << ES8389_TDM_SHIFT));
+
+ return 0;
+}
+
+static int es8389_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ u8 state = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFP:
+ regmap_update_bits(es8389->regmap, ES8389_MASTER_MODE,
+ ES8389_MASTER_MODE_EN, ES8389_MASTER_MODE_EN);
+ es8389->mastermode = 1;
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ es8389->mastermode = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ state |= ES8389_DAIFMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dev_err(component->dev, "component driver does not support right justified\n");
+ return -EINVAL;
+ case SND_SOC_DAIFMT_LEFT_J:
+ state |= ES8389_DAIFMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ state |= ES8389_DAIFMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ state |= ES8389_DAIFMT_DSP_B;
+ break;
+ default:
+ break;
+ }
+ regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE, ES8389_DAIFMT_MASK, state);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE, ES8389_DAIFMT_MASK, state);
+
+ return 0;
+}
+
+static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ int coeff;
+ u8 state = 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ state |= ES8389_S16_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ state |= ES8389_S20_3_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ state |= ES8389_S18_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ state |= ES8389_S24_LE;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ state |= ES8389_S32_LE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE, ES8389_DATA_LEN_MASK, state);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE, ES8389_DATA_LEN_MASK, state);
+
+ if (es8389->mclk_src == ES8389_SCLK_PIN) {
+ regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK,
+ ES8389_MCLK_SOURCE, es8389->mclk_src);
+ es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params);
+ }
+
+ coeff = get_coeff(es8389->sysclk, params_rate(params));
+ if (coeff >= 0) {
+ regmap_write(es8389->regmap, ES8389_CLK_DIV1, coeff_div[coeff].Reg0x04);
+ regmap_write(es8389->regmap, ES8389_CLK_MUL, coeff_div[coeff].Reg0x05);
+ regmap_write(es8389->regmap, ES8389_CLK_MUX1, coeff_div[coeff].Reg0x06);
+ regmap_write(es8389->regmap, ES8389_CLK_MUX2, coeff_div[coeff].Reg0x07);
+ regmap_write(es8389->regmap, ES8389_CLK_CTL1, coeff_div[coeff].Reg0x08);
+ regmap_write(es8389->regmap, ES8389_CLK_CTL2, coeff_div[coeff].Reg0x09);
+ regmap_write(es8389->regmap, ES8389_CLK_CTL3, coeff_div[coeff].Reg0x0A);
+ regmap_update_bits(es8389->regmap, ES8389_OSC_CLK,
+ 0xC0, coeff_div[coeff].Reg0x0F);
+ regmap_write(es8389->regmap, ES8389_CLK_DIV2, coeff_div[coeff].Reg0x11);
+ regmap_write(es8389->regmap, ES8389_ADC_OSR, coeff_div[coeff].Reg0x21);
+ regmap_write(es8389->regmap, ES8389_ADC_DSP, coeff_div[coeff].Reg0x22);
+ regmap_write(es8389->regmap, ES8389_OSR_VOL, coeff_div[coeff].Reg0x26);
+ regmap_update_bits(es8389->regmap, ES8389_SYSTEM30,
+ 0xC0, coeff_div[coeff].Reg0x30);
+ regmap_write(es8389->regmap, ES8389_DAC_DSM_OSR, coeff_div[coeff].Reg0x41);
+ regmap_write(es8389->regmap, ES8389_DAC_DSP_OSR, coeff_div[coeff].Reg0x42);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_MISC,
+ 0x81, coeff_div[coeff].Reg0x43);
+ regmap_update_bits(es8389->regmap, ES8389_CHIP_MISC,
+ 0x72, coeff_div[coeff].Reg0xF0);
+ regmap_write(es8389->regmap, ES8389_CSM_STATE1, coeff_div[coeff].Reg0xF1);
+ regmap_write(es8389->regmap, ES8389_SYSTEM16, coeff_div[coeff].Reg0x16);
+ regmap_write(es8389->regmap, ES8389_SYSTEM18, coeff_div[coeff].Reg0x18);
+ regmap_write(es8389->regmap, ES8389_SYSTEM19, coeff_div[coeff].Reg0x19);
+ } else {
+ dev_warn(component->dev, "Clock coefficients do not match");
+ }
+
+ return 0;
+}
+
+static int es8389_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ ret = clk_prepare_enable(es8389->mclk);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(es8389->regmap, ES8389_HPSW, 0x20, 0x20);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0xD9);
+ regmap_write(es8389->regmap, ES8389_ADC_EN, 0x8F);
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xE4);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x01);
+ regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0xC3);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a);
+ usleep_range(70000, 72000);
+ regmap_write(es8389->regmap, ES8389_DAC_RESET, 0X00);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04);
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4);
+ usleep_range(70000, 72000);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59);
+ regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x3E);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80);
+ usleep_range(8000, 8500);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00);
+
+ clk_disable_unprepare(es8389->mclk);
+ break;
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+ return 0;
+}
+
+
+
+static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ if (mute) {
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE,
+ 0x03, 0x03);
+ } else {
+ regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE,
+ 0x03, 0x03);
+ }
+ } else {
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE,
+ 0x03, 0x00);
+ } else {
+ regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE,
+ 0x03, 0x00);
+ }
+ }
+
+ return 0;
+}
+
+#define es8389_RATES SNDRV_PCM_RATE_8000_96000
+
+#define es8389_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops es8389_ops = {
+ .hw_params = es8389_pcm_hw_params,
+ .set_fmt = es8389_set_dai_fmt,
+ .set_sysclk = es8389_set_dai_sysclk,
+ .set_tdm_slot = es8389_set_tdm_slot,
+ .mute_stream = es8389_mute,
+};
+
+static struct snd_soc_dai_driver es8389_dai = {
+ .name = "ES8389 HiFi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = es8389_RATES,
+ .formats = es8389_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = es8389_RATES,
+ .formats = es8389_FORMATS,
+ },
+ .ops = &es8389_ops,
+ .symmetric_rate = 1,
+};
+
+static void es8389_init(struct snd_soc_component *component)
+{
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x7E);
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38);
+ regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64);
+ regmap_write(es8389->regmap, ES8389_ADC_HPF2, 0x04);
+ regmap_write(es8389->regmap, ES8389_DAC_INV, 0x03);
+
+ regmap_write(es8389->regmap, ES8389_VMID, 0x2A);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0xC9);
+ regmap_write(es8389->regmap, ES8389_ANA_VSEL, 0x4F);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL2, 0x06);
+ regmap_write(es8389->regmap, ES8389_LOW_POWER1, 0x00);
+ regmap_write(es8389->regmap, ES8389_DMIC_EN, 0x16);
+
+ regmap_write(es8389->regmap, ES8389_PGA_SW, 0xAA);
+ regmap_write(es8389->regmap, ES8389_MOD_SW1, 0x66);
+ regmap_write(es8389->regmap, ES8389_MOD_SW2, 0x99);
+ regmap_write(es8389->regmap, ES8389_ADC_MODE, (0x00 | ES8389_TDM_MODE));
+ regmap_update_bits(es8389->regmap, ES8389_DMIC_EN, 0xC0, 0x00);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_MODE, 0x03, 0x00);
+
+ regmap_update_bits(es8389->regmap, ES8389_MIC1_GAIN,
+ ES8389_MIC_SEL_MASK, ES8389_MIC_DEFAULT);
+ regmap_update_bits(es8389->regmap, ES8389_MIC2_GAIN,
+ ES8389_MIC_SEL_MASK, ES8389_MIC_DEFAULT);
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xC4);
+ regmap_write(es8389->regmap, ES8389_MASTER_MODE, 0x08);
+ regmap_write(es8389->regmap, ES8389_CSM_STATE1, 0x00);
+ regmap_write(es8389->regmap, ES8389_SYSTEM12, 0x01);
+ regmap_write(es8389->regmap, ES8389_SYSTEM13, 0x01);
+ regmap_write(es8389->regmap, ES8389_SYSTEM14, 0x01);
+ regmap_write(es8389->regmap, ES8389_SYSTEM15, 0x01);
+ regmap_write(es8389->regmap, ES8389_SYSTEM16, 0x35);
+ regmap_write(es8389->regmap, ES8389_SYSTEM17, 0x09);
+ regmap_write(es8389->regmap, ES8389_SYSTEM18, 0x91);
+ regmap_write(es8389->regmap, ES8389_SYSTEM19, 0x28);
+ regmap_write(es8389->regmap, ES8389_SYSTEM1A, 0x01);
+ regmap_write(es8389->regmap, ES8389_SYSTEM1B, 0x01);
+ regmap_write(es8389->regmap, ES8389_SYSTEM1C, 0x11);
+
+ regmap_write(es8389->regmap, ES8389_CHIP_MISC, 0x13);
+ regmap_write(es8389->regmap, ES8389_MASTER_CLK, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_DIV1, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_MUL, 0x10);
+ regmap_write(es8389->regmap, ES8389_CLK_MUX1, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_MUX2, 0xC0);
+ regmap_write(es8389->regmap, ES8389_CLK_CTL1, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_CTL2, 0xC0);
+ regmap_write(es8389->regmap, ES8389_CLK_CTL3, 0x80);
+ regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04);
+ regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01);
+ regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00);
+ regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00);
+ regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F);
+ regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F);
+ regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0);
+ regmap_write(es8389->regmap, ES8389_SYSTEM30, 0xF4);
+ regmap_write(es8389->regmap, ES8389_DAC_DSM_OSR, 0x7F);
+ regmap_write(es8389->regmap, ES8389_DAC_DSP_OSR, 0x7F);
+ regmap_write(es8389->regmap, ES8389_DAC_MISC, 0x10);
+ regmap_write(es8389->regmap, ES8389_DAC_RAMP, 0x0F);
+ regmap_write(es8389->regmap, ES8389_SYSTEM4C, 0xC0);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0xC1);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x01);
+ regmap_write(es8389->regmap, ES8389_DAC_RESET, 0x02);
+
+ regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE, 0x03, 0x03);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE, 0x03, 0x03);
+}
+
+static int es8389_suspend(struct snd_soc_component *component)
+{
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
+ regcache_cache_only(es8389->regmap, true);
+ regcache_mark_dirty(es8389->regmap);
+
+ return 0;
+}
+
+static int es8389_resume(struct snd_soc_component *component)
+{
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ unsigned int regv;
+
+ regcache_cache_only(es8389->regmap, false);
+ regcache_cache_bypass(es8389->regmap, true);
+ regmap_read(es8389->regmap, ES8389_RESET, &regv);
+ regcache_cache_bypass(es8389->regmap, false);
+
+ if (regv == 0xff)
+ es8389_init(component);
+ else
+ es8389_set_bias_level(component, SND_SOC_BIAS_ON);
+
+ regcache_sync(es8389->regmap);
+
+ return 0;
+}
+
+static int es8389_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ ret = device_property_read_u8(component->dev, "everest,mclk-src", &es8389->mclk_src);
+ if (ret != 0) {
+ dev_dbg(component->dev, "mclk-src return %d", ret);
+ es8389->mclk_src = ES8389_MCLK_SOURCE;
+ }
+
+ es8389->mclk = devm_clk_get(component->dev, "mclk");
+ if (IS_ERR(es8389->mclk))
+ return dev_err_probe(component->dev, PTR_ERR(es8389->mclk),
+ "ES8389 is unable to get mclk\n");
+
+ if (!es8389->mclk)
+ dev_err(component->dev, "%s, assuming static mclk\n", __func__);
+
+ ret = clk_prepare_enable(es8389->mclk);
+ if (ret) {
+ dev_err(component->dev, "%s, unable to enable mclk\n", __func__);
+ return ret;
+ }
+
+ es8389_init(component);
+ es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+static void es8389_remove(struct snd_soc_component *component)
+{
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ regmap_write(es8389->regmap, ES8389_MASTER_MODE, 0x28);
+ regmap_write(es8389->regmap, ES8389_HPSW, 0x00);
+ regmap_write(es8389->regmap, ES8389_VMID, 0x00);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x00);
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xCC);
+ usleep_range(500000, 550000);//500MS
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0x00);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x08);
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0xC1);
+ regmap_write(es8389->regmap, ES8389_PULL_DOWN, 0x00);
+
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_es8389 = {
+ .probe = es8389_probe,
+ .remove = es8389_remove,
+ .suspend = es8389_suspend,
+ .resume = es8389_resume,
+ .set_bias_level = es8389_set_bias_level,
+
+ .controls = es8389_snd_controls,
+ .num_controls = ARRAY_SIZE(es8389_snd_controls),
+ .dapm_widgets = es8389_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es8389_dapm_widgets),
+ .dapm_routes = es8389_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es8389_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+};
+
+static const struct regmap_config es8389_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = ES8389_MAX_REGISTER,
+
+ .volatile_reg = es8389_volatile_register,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static void es8389_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct es8389_private *es8389;
+
+ es8389 = i2c_get_clientdata(i2c);
+
+ regmap_write(es8389->regmap, ES8389_MASTER_MODE, 0x28);
+ regmap_write(es8389->regmap, ES8389_HPSW, 0x00);
+ regmap_write(es8389->regmap, ES8389_VMID, 0x00);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x00);
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xCC);
+ usleep_range(500000, 550000);//500MS
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0x00);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x08);
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0xC1);
+ regmap_write(es8389->regmap, ES8389_PULL_DOWN, 0x00);
+}
+
+static int es8389_i2c_probe(struct i2c_client *i2c_client)
+{
+ struct es8389_private *es8389;
+ int ret;
+
+ es8389 = devm_kzalloc(&i2c_client->dev, sizeof(*es8389), GFP_KERNEL);
+ if (es8389 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c_client, es8389);
+ es8389->regmap = devm_regmap_init_i2c(i2c_client, &es8389_regmap);
+ if (IS_ERR(es8389->regmap))
+ return dev_err_probe(&i2c_client->dev, PTR_ERR(es8389->regmap),
+ "regmap_init() failed\n");
+
+ ret = devm_snd_soc_register_component(&i2c_client->dev,
+ &soc_codec_dev_es8389,
+ &es8389_dai,
+ 1);
+
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es8389_if_dt_ids[] = {
+ { .compatible = "everest,es8389", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, es8389_if_dt_ids);
+#endif
+
+static const struct i2c_device_id es8389_i2c_id[] = {
+ {"es8389"},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, es8389_i2c_id);
+
+static struct i2c_driver es8389_i2c_driver = {
+ .driver = {
+ .name = "es8389",
+ .of_match_table = of_match_ptr(es8389_if_dt_ids),
+ },
+ .shutdown = es8389_i2c_shutdown,
+ .probe = es8389_i2c_probe,
+ .id_table = es8389_i2c_id,
+};
+module_i2c_driver(es8389_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC es8389 driver");
+MODULE_AUTHOR("Michael Zhang <zhangyi@everest-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h
new file mode 100644
index 000000000000..123d1e4b2d53
--- /dev/null
+++ b/sound/soc/codecs/es8389.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+* ES8389.h -- ES8389 ALSA SoC Audio Codec
+*
+* Authors:
+*
+* Based on ES8374.h by Michael Zhang
+*/
+
+#ifndef _ES8389_H
+#define _ES8389_H
+
+/*
+* ES8389_REGISTER NAME_REG_REGISTER ADDRESS
+*/
+#define ES8389_RESET 0x00 /*reset digital,csm,clock manager etc.*/
+
+/*
+* Clock Scheme Register definition
+*/
+#define ES8389_MASTER_MODE 0x01
+#define ES8389_MASTER_CLK 0x02
+#define ES8389_CLK_OFF1 0x03
+#define ES8389_CLK_DIV1 0x04
+#define ES8389_CLK_MUL 0x05
+#define ES8389_CLK_MUX1 0x06
+#define ES8389_CLK_MUX2 0x07
+#define ES8389_CLK_CTL1 0x08
+#define ES8389_CLK_CTL2 0x09
+#define ES8389_CLK_CTL3 0x0A
+#define ES8389_SCLK_DIV 0x0B
+#define ES8389_LRCK_DIV1 0x0C
+#define ES8389_LRCK_DIV2 0x0D
+#define ES8389_CLK_OFF2 0x0E
+#define ES8389_OSC_CLK 0x0F
+#define ES8389_CSM_JUMP 0x10
+#define ES8389_CLK_DIV2 0x11
+#define ES8389_SYSTEM12 0x12
+#define ES8389_SYSTEM13 0x13
+#define ES8389_SYSTEM14 0x14
+#define ES8389_SYSTEM15 0x15
+#define ES8389_SYSTEM16 0x16
+#define ES8389_SYSTEM17 0x17
+#define ES8389_SYSTEM18 0x18
+#define ES8389_SYSTEM19 0x19
+#define ES8389_SYSTEM1A 0x1A
+#define ES8389_SYSTEM1B 0x1B
+#define ES8389_SYSTEM1C 0x1C
+#define ES8389_ADC_FORMAT_MUTE 0x20
+#define ES8389_ADC_OSR 0x21
+#define ES8389_ADC_DSP 0x22
+#define ES8389_ADC_MODE 0x23
+#define ES8389_ADC_HPF1 0x24
+#define ES8389_ADC_HPF2 0x25
+#define ES8389_OSR_VOL 0x26
+#define ES8389_ADCL_VOL 0x27
+#define ES8389_ADCR_VOL 0x28
+#define ES8389_ALC_CTL 0x29
+#define ES8389_PTDM_SLOT 0x2A
+#define ES8389_ALC_ON 0x2B
+#define ES8389_ALC_TARGET 0x2C
+#define ES8389_ALC_GAIN 0x2D
+#define ES8389_SYSTEM2E 0x2E
+#define ES8389_ADC_MUTE 0x2F
+#define ES8389_SYSTEM30 0x30
+#define ES8389_ADC_RESET 0x31
+#define ES8389_DAC_FORMAT_MUTE 0x40
+#define ES8389_DAC_DSM_OSR 0x41
+#define ES8389_DAC_DSP_OSR 0x42
+#define ES8389_DAC_MISC 0x43
+#define ES8389_DAC_MIX 0x44
+#define ES8389_DAC_INV 0x45
+#define ES8389_DACL_VOL 0x46
+#define ES8389_DACR_VOL 0x47
+#define ES8389_MIX_VOL 0x48
+#define ES8389_DAC_RAMP 0x49
+#define ES8389_SYSTEM4C 0x4C
+#define ES8389_DAC_RESET 0x4D
+#define ES8389_VMID 0x60
+#define ES8389_ANA_CTL1 0x61
+#define ES8389_ANA_VSEL 0x62
+#define ES8389_ANA_CTL2 0x63
+#define ES8389_ADC_EN 0x64
+#define ES8389_HPSW 0x69
+#define ES8389_LOW_POWER1 0x6B
+#define ES8389_LOW_POWER2 0x6C
+#define ES8389_DMIC_EN 0x6D
+#define ES8389_PGA_SW 0x6E
+#define ES8389_MOD_SW1 0x6F
+#define ES8389_MOD_SW2 0x70
+#define ES8389_MOD_SW3 0x71
+#define ES8389_MIC1_GAIN 0x72
+#define ES8389_MIC2_GAIN 0x73
+
+#define ES8389_CHIP_MISC 0xF0
+#define ES8389_CSM_STATE1 0xF1
+#define ES8389_PULL_DOWN 0xF2
+#define ES8389_ISO_CTL 0xF3
+#define ES8389_CSM_STATE2 0xF4
+
+#define ES8389_CHIP_ID0 0xFD
+#define ES8389_CHIP_ID1 0xFE
+
+#define ES8389_MAX_REGISTER 0xFF
+
+#define ES8389_MIC_SEL_MASK (7 << 4)
+#define ES8389_MIC_DEFAULT (1 << 4)
+
+#define ES8389_MASTER_MODE_EN (1 << 0)
+
+#define ES8389_TDM_OFF (0 << 0)
+#define ES8389_STDM_ON (1 << 7)
+#define ES8389_PTDM_ON (1 << 6)
+
+#define ES8389_TDM_MODE ES8389_TDM_OFF
+#define ES8389_TDM_SLOT (0x70 << 0)
+#define ES8389_TDM_SHIFT 4
+
+#define ES8389_MCLK_SOURCE (1 << 6)
+#define ES8389_MCLK_PIN (1 << 6)
+#define ES8389_SCLK_PIN (0 << 6)
+
+/* ES8389_FMT */
+#define ES8389_S24_LE (0 << 5)
+#define ES8389_S20_3_LE (1 << 5)
+#define ES8389_S18_LE (2 << 5)
+#define ES8389_S16_LE (3 << 5)
+#define ES8389_S32_LE (4 << 5)
+#define ES8389_DATA_LEN_MASK (7 << 5)
+
+#define ES8389_DAIFMT_MASK (7 << 2)
+#define ES8389_DAIFMT_I2S 0
+#define ES8389_DAIFMT_LEFT_J (1 << 2)
+#define ES8389_DAIFMT_DSP_A (1 << 3)
+#define ES8389_DAIFMT_DSP_B (3 << 3)
+
+#define ES8389_STATE_ON (13 << 0)
+#define ES8389_STATE_STANDBY (7 << 0)
+
+#endif
diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c
new file mode 100644
index 000000000000..94fd7d54c53b
--- /dev/null
+++ b/sound/soc/codecs/es83xx-dsm-common.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright (c) Intel Corporation, 2022
+// Copyright Everest Semiconductor Co.,Ltd
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include "es83xx-dsm-common.h"
+
+/* UUID ("a9800c04-e016-343e-41f4-6bcce70f4332") */
+static const guid_t es83xx_dsm_guid =
+ GUID_INIT(0xa9800c04, 0xe016, 0x343e,
+ 0x41, 0xf4, 0x6b, 0xcc, 0xe7, 0x0f, 0x43, 0x32);
+
+#define ES83xx_DSM_REVID 1
+
+int es83xx_dsm(struct device *dev, int arg, int *value)
+{
+ acpi_handle dhandle;
+ union acpi_object *obj;
+ int ret = 0;
+
+ dhandle = ACPI_HANDLE(dev);
+ if (!dhandle)
+ return -ENOENT;
+
+ obj = acpi_evaluate_dsm(dhandle, &es83xx_dsm_guid, ES83xx_DSM_REVID,
+ arg, NULL);
+ if (!obj) {
+ dev_err(dev, "%s: acpi_evaluate_dsm() failed\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ dev_err(dev, "%s: object is not ACPI_TYPE_INTEGER\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ *value = obj->integer.value;
+err:
+ ACPI_FREE(obj);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(es83xx_dsm);
+
+int es83xx_dsm_dump(struct device *dev)
+{
+ int value;
+ int ret;
+
+ ret = es83xx_dsm(dev, PLATFORM_MAINMIC_TYPE_ARG, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "PLATFORM_MAINMIC_TYPE %#x\n", value);
+
+ ret = es83xx_dsm(dev, PLATFORM_HPMIC_TYPE_ARG, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "PLATFORM_HPMIC_TYPE %#x\n", value);
+
+ ret = es83xx_dsm(dev, PLATFORM_SPK_TYPE_ARG, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "PLATFORM_SPK_TYPE %#x\n", value);
+
+ ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "PLATFORM_HPDET_INV %#x\n", value);
+
+ ret = es83xx_dsm(dev, PLATFORM_PCM_TYPE_ARG, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "PLATFORM_PCM_TYPE %#x\n", value);
+
+ ret = es83xx_dsm(dev, PLATFORM_MIC_DE_POP_ARG, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "PLATFORM_MIC_DE_POP %#x\n", value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(es83xx_dsm_dump);
+
+MODULE_DESCRIPTION("Everest Semi ES83xx DSM helpers");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h
new file mode 100644
index 000000000000..91c9a89e75e9
--- /dev/null
+++ b/sound/soc/codecs/es83xx-dsm-common.h
@@ -0,0 +1,393 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Intel Corporation, 2022
+ * Copyright Everest Semiconductor Co.,Ltd
+ */
+
+/* Definitions extracted from ASL file provided at
+ * https://github.com/thesofproject/linux/files/9398723/ESSX8326.zip
+ */
+
+#ifndef _ES83XX_DSM_COMMON_H
+#define _ES83XX_DSM_COMMON_H
+
+/***************************************************
+ * DSM arguments *
+ ***************************************************/
+
+#define PLATFORM_MAINMIC_TYPE_ARG 0x00
+#define PLATFORM_HPMIC_TYPE_ARG 0x01
+#define PLATFORM_SPK_TYPE_ARG 0x02
+#define PLATFORM_HPDET_INV_ARG 0x03
+#define PLATFORM_PCM_TYPE_ARG 0x04
+
+#define PLATFORM_MIC_DE_POP_ARG 0x06
+#define PLATFORM_CODEC_TYPE_ARG 0x0E
+#define PLATFORM_BUS_SLOT_ARG 0x0F
+
+#define HP_CODEC_LINEIN_PGA_GAIN_ARG 0x10
+#define MAIN_CODEC_LINEIN_PGA_GAIN_ARG 0x20
+
+#define HP_CODEC_D2SEPGA_GAIN_ARG 0x11
+#define MAIN_CODEC_D2SEPGA_GAIN_ARG 0x21
+
+#define HP_CODEC_ADC_VOLUME_ARG 0x12
+#define MAIN_CODEC_ADC_VOLUME_ARG 0x22
+
+#define HP_CODEC_ADC_ALC_ENABLE_ARG 0x13
+#define MAIN_CODEC_ADC_ALC_ENABLE_ARG 0x23
+
+#define HP_CODEC_ADC_ALC_TARGET_LEVEL_ARG 0x14
+#define MAIN_CODEC_ADC_ALC_TARGET_LEVEL_ARG 0x24
+
+#define HP_CODEC_ADC_ALC_MAXGAIN_ARG 0x15
+#define MAIN_CODEC_ADC_ALC_MAXGAIN_ARG 0x25
+
+#define HP_CODEC_ADC_ALC_MINGAIN_ARG 0x16
+#define MAIN_CODEC_ADC_ALC_MINGAIN_ARG 0x26
+
+#define HP_CODEC_ADC_ALC_HLDTIME_ARG 0x17
+#define MAIN_CODEC_ADC_ALC_HLDTIME_ARG 0x27
+
+#define HP_CODEC_ADC_ALC_DCYTIME_ARG 0x18
+#define MAIN_CODEC_ADC_ALC_DCYTIME_ARG 0x28
+
+#define HP_CODEC_ADC_ALC_ATKTIME_ARG 0x19
+#define MAIN_CODEC_ADC_ALC_ATKTIME_ARG 0x29
+
+#define HP_CODEC_ADC_ALC_NGTYPE_ARG 0x1a
+#define MAIN_CODEC_ADC_ALC_NGTYPE_ARG 0x2a
+
+#define HP_CODEC_ADC_ALC_NGTHLD_ARG 0x1b
+#define MAIN_CODEC_ADC_ALC_NGTHLD_ARG 0x2b
+
+#define MAIN_CODEC_ADC_GUI_STEP_ARG 0x2c
+#define MAIN_CODEC_ADC_GUI_GAIN_RANGE_ARG 0x2c
+
+#define HEADPHONE_DUMMY_REMOVE_ENABLE_ARG 0x2e
+
+#define HP_CODEC_DAC_HPMIX_HIGAIN_ARG 0x40
+#define SPK_CODEC_DAC_HPMIX_HIGAIN_ARG 0x50
+
+#define HP_CODEC_DAC_HPMIX_VOLUME_ARG 0x41
+#define SPK_CODEC_DAC_HPMIX_VOLUME_ARG 0x51
+
+#define HP_CODEC_DAC_HPOUT_VOLUME_ARG 0x42
+#define SPK_CODEC_DAC_HPOUT_VOLUME_ARG 0x52
+
+#define HP_CODEC_LDAC_VOLUME_ARG 0x44
+#define HP_CODEC_RDAC_VOLUME_ARG 0x54
+
+#define SPK_CODEC_LDAC_VOLUME_ARG 0x45
+#define SPK_CODEC_RDAC_VOLUME_ARG 0x55
+
+#define HP_CODEC_DAC_AUTOMUTE_ARG 0x46
+#define SPK_CODEC_DAC_AUTOMUTE_ARG 0x56
+
+#define HP_CODEC_DAC_MONO_ARG 0x4A
+#define SPK_CODEC_DAC_MONO_ARG 0x5A
+
+#define HP_CTL_IO_LEVEL_ARG 0x4B
+#define SPK_CTL_IO_LEVEL_ARG 0x5B
+
+#define CODEC_GPIO0_FUNC_ARG 0x80
+#define CODEC_GPIO1_FUNC_ARG 0x81
+#define CODEC_GPIO2_FUNC_ARG 0x82
+#define CODEC_GPIO3_FUNC_ARG 0x83
+#define CODEC_GPIO4_FUNC_ARG 0x84
+
+#define PLATFORM_MCLK_LRCK_FREQ_ARG 0x85
+
+/***************************************************
+ * Values for arguments *
+ ***************************************************/
+
+/* Main and HP Mic */
+#define PLATFORM_MIC_DMIC_HIGH_LEVEL 0xAA
+#define PLATFORM_MIC_DMIC_LOW_LEVEL 0x55
+#define PLATFORM_MIC_AMIC_LIN1RIN1 0xBB
+#define PLATFORM_MIC_AMIC_LIN2RIN2 0xCC
+
+/* Speaker */
+#define PLATFORM_SPK_NONE 0x00
+#define PLATFORM_SPK_MONO 0x01
+#define PLATFORM_SPK_STEREO 0x02
+
+/* Jack Detection */
+#define PLATFORM_HPDET_NORMAL 0x00
+#define PLATFORM_HPDET_INVERTED 0x01
+
+/* PCM type (Port number + protocol) */
+/*
+ * RETURNED VALUE = 0x00, PCM PORT0, I2S
+ * 0x01, PCM PORT0, LJ
+ * 0x02, PCM PORT0, RJ
+ * 0x03, PCM PORT0, DSP-A
+ * 0x04, PCM PORT0, DSP-B
+ * 0x10, PCM PORT1, I2S
+ * 0x11, PCM PORT1, LJ
+ * 0x12, PCM PORT1, RJ
+ * 0x13, PCM PORT1, DSP-A
+ * 0x14, PCM PORT1, DSP-B
+ * 0xFF, Use default
+ *
+ * This is not used in Linux (defined by topology) and in
+ * Windows it's always DSP-A
+ */
+
+/* Depop */
+#define PLATFORM_MIC_DE_POP_OFF 0x00
+#define PLATFORM_MIC_DE_POP_ON 0x01
+
+/* Codec type */
+#define PLATFORM_CODEC_8316 16
+#define PLATFORM_CODEC_8326 26
+#define PLATFORM_CODEC_8336 36
+#define PLATFORM_CODEC_8395 95
+#define PLATFORM_CODEC_8396 96
+
+/* Bus slot (on the host) */
+/* BIT[3:0] FOR BUS NUMBER, BIT[7:4] FOR SLOT NUMBER
+ * BIT[3:0] 0 for I2S0, 1 for IS21, 2 for I2S2.
+ *
+ * On Intel platforms this refers to SSP0..2. This information
+ * is not really useful for Linux, the information is already
+ * inferred from NHLT but can be used to double-check NHLT
+ */
+
+/* Volume - Gain */
+#define LINEIN_GAIN_0db 0x00 /* gain = 0db */
+#define LINEIN_GAIN_3db 0x01 /* gain = +3db */
+#define LINEIN_GAIN_6db 0x02 /* gain = +6db */
+#define LINEIN_GAIN_9db 0x03 /* gain = +9db */
+#define LINEIN_GAIN_12db 0x04 /* gain = +12db */
+#define LINEIN_GAIN_15db 0x05 /* gain = +15db */
+#define LINEIN_GAIN_18db 0x06 /* gain = +18db */
+#define LINEIN_GAIN_21db 0x07 /* gain = +21db */
+#define LINEIN_GAIN_24db 0x08 /* gain = +24db */
+#define LINEIN_GAIN_27db 0x09 /* gain = +27db */
+#define LINEIN_GAIN_30db 0x0a /* gain = +30db */
+
+#define ADC_GUI_STEP_3db 0x03 /* gain = +3db */
+#define ADC_GUI_STEP_6db 0x06 /* gain = +6db */
+#define ADC_GUI_STEP_10db 0x0a /* gain = +10db */
+
+#define D2SEPGA_GAIN_0db 0x00 /* gain = 0db */
+#define D2SEPGA_GAIN_15db 0x01 /* gain = +15db */
+
+/* ADC volume: base = 0db, -0.5db/setp, 0xc0 <-> -96db */
+
+#define ADC_ALC_DISABLE 0x00
+#define ADC_ALC_ENABLE 0x01
+
+#define ADC_ALC_TARGET_LEVEL_m16_5db 0x00 /* gain = -16.5db */
+#define ADC_ALC_TARGET_LEVEL_m15db 0x01 /* gain = -15db */
+#define ADC_ALC_TARGET_LEVEL_m13_5db 0x02 /* gain = -13.5db */
+#define ADC_ALC_TARGET_LEVEL_m12db 0x03 /* gain = -12db */
+#define ADC_ALC_TARGET_LEVEL_m10_5db 0x04 /* gain = -10.5db */
+#define ADC_ALC_TARGET_LEVEL_m9db 0x05 /* gain = -9db */
+#define ADC_ALC_TARGET_LEVEL_m7_5db 0x06 /* gain = -7.5db */
+#define ADC_ALC_TARGET_LEVEL_m6db 0x07 /* gain = -6db */
+#define ADC_ALC_TARGET_LEVEL_m4_5db 0x08 /* gain = -4.5db */
+#define ADC_ALC_TARGET_LEVEL_m_3db 0x09 /* gain = -3db */
+#define ADC_ALC_TARGET_LEVEL_m1_5db 0x0a /* gain = -1.5db */
+
+#define ADC_ALC_MAXGAIN_m6_5db 0x00 /* gain = -6.5db */
+#define ADC_ALC_MAXGAIN_m5db 0x01 /* gain = -5db */
+#define ADC_ALC_MAXGAIN_m3_5db 0x02 /* gain = -3.5db */
+#define ADC_ALC_MAXGAIN_m2db 0x03 /* gain = -2db */
+#define ADC_ALC_MAXGAIN_m0_5db 0x04 /* gain = -0.5db */
+#define ADC_ALC_MAXGAIN_1db 0x05 /* gain = +1db */
+#define ADC_ALC_MAXGAIN_2_5db 0x06 /* gain = +2.5db */
+#define ADC_ALC_MAXGAIN_4db 0x07 /* gain = +4db */
+#define ADC_ALC_MAXGAIN_5_5db 0x08 /* gain = +5.5db */
+#define ADC_ALC_MAXGAIN_7db 0x09 /* gain = +7db */
+#define ADC_ALC_MAXGAIN_8_5db 0x0a /* gain = +8.5db */
+#define ADC_ALC_MAXGAIN_10db 0x0b /* gain = +10db */
+#define ADC_ALC_MAXGAIN_11_5db 0x0c /* gain = +11.5db */
+#define ADC_ALC_MAXGAIN_13db 0x0d /* gain = +13db */
+#define ADC_ALC_MAXGAIN_14_5db 0x0e /* gain = +14.5db */
+#define ADC_ALC_MAXGAIN_16db 0x0f /* gain = +16db */
+#define ADC_ALC_MAXGAIN_17_5db 0x10 /* gain = +17.5db */
+#define ADC_ALC_MAXGAIN_19db 0x11 /* gain = +19db */
+#define ADC_ALC_MAXGAIN_20_5db 0x12 /* gain = +20.5db */
+#define ADC_ALC_MAXGAIN_22db 0x13 /* gain = +22db */
+#define ADC_ALC_MAXGAIN_23_5db 0x14 /* gain = +23.5db */
+#define ADC_ALC_MAXGAIN_25db 0x15 /* gain = +25db */
+#define ADC_ALC_MAXGAIN_26_5db 0x16 /* gain = +26.5db */
+#define ADC_ALC_MAXGAIN_28db 0x17 /* gain = +28db */
+#define ADC_ALC_MAXGAIN_29_5db 0x18 /* gain = +29.5db */
+#define ADC_ALC_MAXGAIN_31db 0x19 /* gain = +31db */
+#define ADC_ALC_MAXGAIN_32_5db 0x1a /* gain = +32.5db */
+#define ADC_ALC_MAXGAIN_34db 0x1b /* gain = +34db */
+#define ADC_ALC_MAXGAIN_35_5db 0x1c /* gain = +35.5db */
+
+#define ADC_ALC_MINGAIN_m12db 0x00 /* gain = -12db */
+#define ADC_ALC_MINGAIN_m10_5db 0x01 /* gain = -10.5db */
+#define ADC_ALC_MINGAIN_m9db 0x02 /* gain = -9db */
+#define ADC_ALC_MINGAIN_m7_5db 0x03 /* gain = -7.5db */
+#define ADC_ALC_MINGAIN_m6db 0x04 /* gain = -6db */
+#define ADC_ALC_MINGAIN_m4_51db 0x05 /* gain = -4.51db */
+#define ADC_ALC_MINGAIN_m3db 0x06 /* gain = -3db */
+#define ADC_ALC_MINGAIN_m1_5db 0x07 /* gain = -1.5db */
+#define ADC_ALC_MINGAIN_0db 0x08 /* gain = 0db */
+#define ADC_ALC_MINGAIN_1_5db 0x09 /* gain = +1.5db */
+#define ADC_ALC_MINGAIN_3db 0x0a /* gain = +3db */
+#define ADC_ALC_MINGAIN_4_5db 0x0b /* gain = +4.5db */
+#define ADC_ALC_MINGAIN_6db 0x0c /* gain = +6db */
+#define ADC_ALC_MINGAIN_7_5db 0x0d /* gain = +7.5db */
+#define ADC_ALC_MINGAIN_9db 0x0e /* gain = +9db */
+#define ADC_ALC_MINGAIN_10_5db 0x0f /* gain = +10.5db */
+#define ADC_ALC_MINGAIN_12db 0x10 /* gain = +12db */
+#define ADC_ALC_MINGAIN_13_5db 0x11 /* gain = +13.5db */
+#define ADC_ALC_MINGAIN_15db 0x12 /* gain = +15db */
+#define ADC_ALC_MINGAIN_16_5db 0x13 /* gain = +16.5db */
+#define ADC_ALC_MINGAIN_18db 0x14 /* gain = +18db */
+#define ADC_ALC_MINGAIN_19_5db 0x15 /* gain = +19.5db */
+#define ADC_ALC_MINGAIN_21db 0x16 /* gain = +21db */
+#define ADC_ALC_MINGAIN_22_5db 0x17 /* gain = +22.5db */
+#define ADC_ALC_MINGAIN_24db 0x18 /* gain = +24db */
+#define ADC_ALC_MINGAIN_25_5db 0x19 /* gain = +25.5db */
+#define ADC_ALC_MINGAIN_27db 0x1a /* gain = +27db */
+#define ADC_ALC_MINGAIN_28_5db 0x1b /* gain = +28.5db */
+#define ADC_ALC_MINGAIN_30db 0x1c /* gain = +30db */
+
+/* ADC volume: step 1dB */
+
+/* ALC Hold, Decay, Attack */
+#define ADC_ALC_HLDTIME_0_US 0x00
+#define ADC_ALC_HLDTIME_0000266_US 0x01 //time = 2.67ms
+#define ADC_ALC_HLDTIME_0000533_US 0x02 //time = 5.33ms
+#define ADC_ALC_HLDTIME_0001066_US 0x03 //time = 10.66ms
+#define ADC_ALC_HLDTIME_0002132_US 0x04 //time = 21.32ms
+#define ADC_ALC_HLDTIME_0004264_US 0x05 //time = 42.64ms
+#define ADC_ALC_HLDTIME_0008538_US 0x06 //time = 85.38ms
+#define ADC_ALC_HLDTIME_0017076_US 0x07 //time = 170.76ms
+#define ADC_ALC_HLDTIME_0034152_US 0x08 //time = 341.52ms
+#define ADC_ALC_HLDTIME_0680000_US 0x09 //time = 0.68s
+#define ADC_ALC_HLDTIME_1360000_US 0x0a //time = 1.36s
+
+#define ADC_ALC_DCYTIME_000410_US 0x00 //time = 410us
+#define ADC_ALC_DCYTIME_000820_US 0x01 //time = 820us
+#define ADC_ALC_DCYTIME_001640_US 0x02 //time = 1.64ms
+#define ADC_ALC_DCYTIME_003280_US 0x03 //time = 3.28ms
+#define ADC_ALC_DCYTIME_006560_US 0x04 //time = 6.56ms
+#define ADC_ALC_DCYTIME_013120_US 0x05 //time = 13.12ms
+#define ADC_ALC_DCYTIME_026240_US 0x06 //time = 26.24ms
+#define ADC_ALC_DCYTIME_058480_US 0x07 //time = 52.48ms
+#define ADC_ALC_DCYTIME_104960_US 0x08 //time = 104.96ms
+#define ADC_ALC_DCYTIME_209920_US 0x09 //time = 209.92ms
+#define ADC_ALC_DCYTIME_420000_US 0x0a //time = 420ms
+
+#define ADC_ALC_ATKTIME_000104_US 0x00 //time = 104us
+#define ADC_ALC_ATKTIME_000208_US 0x01 //time = 208us
+#define ADC_ALC_ATKTIME_000416_US 0x02 //time = 416ms
+#define ADC_ALC_ATKTIME_003832_US 0x03 //time = 832ms
+#define ADC_ALC_ATKTIME_001664_US 0x04 //time = 1.664ms
+#define ADC_ALC_ATKTIME_003328_US 0x05 //time = 3.328ms
+#define ADC_ALC_ATKTIME_006656_US 0x06 //time = 6.656ms
+#define ADC_ALC_ATKTIME_013312_US 0x07 //time = 13.312ms
+#define ADC_ALC_ATKTIME_026624_US 0x08 //time = 26.624ms
+#define ADC_ALC_ATKTIME_053248_US 0x09 //time = 53.248ms
+#define ADC_ALC_ATKTIME_106496_US 0x0a //time = 106.496ms
+
+/* ALC Noise Gate */
+#define ADC_ALC_NGTYPE_DISABLE 0x00 //noise gate disable
+#define ADC_ALC_NGTYPE_ENABLE_HOLD 0x01 //noise gate enable, hold gain type
+#define ADC_ALC_NGTYPE_ENABLE_MUTE 0x03 //noise gate enable, mute type
+
+#define ADC_ALC_NGTHLD_m76_5db 0x00 /* Threshold = -76.5db */
+#define ADC_ALC_NGTHLD_m75db 0x01 /* Threshold = -75db */
+#define ADC_ALC_NGTHLD_m73_5db 0x02 /* Threshold = -73.5db */
+#define ADC_ALC_NGTHLD_m72db 0x03 /* Threshold = -72db */
+#define ADC_ALC_NGTHLD_m70_5db 0x04 /* Threshold = -70.5db */
+#define ADC_ALC_NGTHLD_m69db 0x05 /* Threshold = -69db */
+#define ADC_ALC_NGTHLD_m67_5db 0x06 /* Threshold = -67.5db */
+#define ADC_ALC_NGTHLD_m66db 0x07 /* Threshold = -66db */
+#define ADC_ALC_NGTHLD_m64_5db 0x08 /* Threshold = -64.5db */
+#define ADC_ALC_NGTHLD_m63db 0x09 /* Threshold = -63db */
+#define ADC_ALC_NGTHLD_m61_5db 0x0a /* Threshold = -61.5db */
+#define ADC_ALC_NGTHLD_m60db 0x0b /* Threshold = -60db */
+#define ADC_ALC_NGTHLD_m58_5db 0x0c /* Threshold = -58.5db */
+#define ADC_ALC_NGTHLD_m57db 0x0d /* Threshold = -57db */
+#define ADC_ALC_NGTHLD_m55_5db 0x0e /* Threshold = -55.5db */
+#define ADC_ALC_NGTHLD_m54db 0x0f /* Threshold = -54db */
+#define ADC_ALC_NGTHLD_m52_5db 0x10 /* Threshold = -52.5db */
+#define ADC_ALC_NGTHLD_m51db 0x11 /* Threshold = -51db */
+#define ADC_ALC_NGTHLD_m49_5db 0x12 /* Threshold = -49.5db */
+#define ADC_ALC_NGTHLD_m48db 0x13 /* Threshold = -48db */
+#define ADC_ALC_NGTHLD_m46_5db 0x14 /* Threshold = -46.5db */
+#define ADC_ALC_NGTHLD_m45db 0x15 /* Threshold = -45db */
+#define ADC_ALC_NGTHLD_m43_5db 0x16 /* Threshold = -43.5db */
+#define ADC_ALC_NGTHLD_m42db 0x17 /* Threshold = -42db */
+#define ADC_ALC_NGTHLD_m40_5db 0x18 /* Threshold = -40.5db */
+#define ADC_ALC_NGTHLD_m39db 0x19 /* Threshold = -39db */
+#define ADC_ALC_NGTHLD_m37_5db 0x1a /* Threshold = -37.5db */
+#define ADC_ALC_NGTHLD_m36db 0x1b /* Threshold = -36db */
+#define ADC_ALC_NGTHLD_m34_5db 0x1c /* Threshold = -34.5db */
+#define ADC_ALC_NGTHLD_m33db 0x1d /* Threshold = -33db */
+#define ADC_ALC_NGTHLD_m31_5db 0x1e /* Threshold = -31.5db */
+#define ADC_ALC_NGTHLD_m30db 0x1f /* Threshold = -30db */
+
+/* Headphone dummy - Windows Specific flag, not needed for Linux */
+
+/* HPMIX HIGAIN and VOLUME */
+#define DAC_HPMIX_HIGAIN_0db 0x00 /* gain = 0db */
+#define DAC_HPMIX_HIGAIN_m6db 0x88 /* gain = -6db */
+
+#define DAC_HPMIX_VOLUME_m12db 0x00 /* volume = -12db */
+#define DAC_HPMIX_VOLUME_m10_5db 0x11 /* volume = -10.5db */
+#define DAC_HPMIX_VOLUME_m9db 0x22 /* volume = -9db */
+#define DAC_HPMIX_VOLUME_m7_5db 0x33 /* volume = -7.5db */
+#define DAC_HPMIX_VOLUME_m6db 0x44 /* volume = -6db */
+#define DAC_HPMIX_VOLUME_m4_5db 0x88 /* volume = -4.5db */
+#define DAC_HPMIX_VOLUME_m3db 0x99 /* volume = -3db */
+#define DAC_HPMIX_VOLUME_m1_5db 0xaa /* volume = -1.5db */
+#define DAC_HPMIX_VOLUME_0db 0xbb /* volume = 0db */
+
+/* HPOUT VOLUME */
+#define DAC_HPOUT_VOLUME_0db 0x00 /* volume = 0db */
+#define DAC_HPOUT_VOLUME_m12db 0x11 /* volume = -12db */
+#define DAC_HPOUT_VOLUME_m24db 0x22 /* volume = -24db */
+#define DAC_HPOUT_VOLUME_m48db 0x33 /* volume = -48db */
+
+/* LDAC/RDAC volume = 0db, -0.5db/setp, 0xc0 <-> -96db */
+
+/* Automute */
+#define DAC_AUTOMUTE_NONE 0x00 /* no automute */
+#define DAC_AUTOMUTE_DIGITAL 0x01 /* digital mute */
+#define DAC_AUTOMUTE_ANALOG 0x02 /* analog mute */
+
+/* Mono - Windows specific, on Linux the information comes from DAI/topology */
+#define HEADPHONE_MONO 0x01 /* on channel */
+#define HEADPHONE_STEREO 0x00 /* stereo */
+
+/* Speaker and headphone GPIO control */
+#define GPIO_CTL_IO_LEVEL_LOW 0x00 /* low level enable */
+#define GPIO_CTL_IO_LEVEL_HIGH 0x01 /* high level enable */
+
+/* GPIO */
+/* FIXME: for ES8396, no need to use */
+
+/* Platform clocks */
+/*
+ * BCLK AND MCLK FREQ
+ * BIT[7:4] MCLK FREQ
+ * 0 - 19.2MHz
+ * 1 - 24MHz
+ * 2 - 12.288MHz
+ * F - Default for 19.2MHz
+ *
+ * BIT[3:0] BCLK FREQ
+ * 0 - 4.8MHz
+ * 1 - 2.4MHz
+ * 2 - 2.304MHz
+ * 3 - 3.072MHz
+ * 4 - 4.096MHz
+ * F - Default for 4.8MHz
+ */
+
+int es83xx_dsm(struct device *dev, int arg, int *value);
+int es83xx_dsm_dump(struct device *dev);
+
+#endif
diff --git a/sound/soc/codecs/framer-codec.c b/sound/soc/codecs/framer-codec.c
new file mode 100644
index 000000000000..6f57a3aeecc8
--- /dev/null
+++ b/sound/soc/codecs/framer-codec.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Framer ALSA SoC driver
+//
+// Copyright 2023 CS GROUP France
+//
+// Author: Herve Codina <herve.codina@bootlin.com>
+
+#include <linux/clk.h>
+#include <linux/framer/framer.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define FRAMER_NB_CHANNEL 32
+#define FRAMER_JACK_MASK (SND_JACK_LINEIN | SND_JACK_LINEOUT)
+
+struct framer_codec {
+ struct framer *framer;
+ struct device *dev;
+ struct snd_soc_jack jack;
+ struct notifier_block nb;
+ struct work_struct carrier_work;
+ int max_chan_playback;
+ int max_chan_capture;
+};
+
+static int framer_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int width)
+{
+ struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component);
+
+ switch (width) {
+ case 0:
+ /* Not set -> default 8 */
+ case 8:
+ break;
+ default:
+ dev_err(dai->dev, "tdm slot width %d not supported\n", width);
+ return -EINVAL;
+ }
+
+ framer->max_chan_playback = hweight32(tx_mask);
+ if (framer->max_chan_playback > FRAMER_NB_CHANNEL) {
+ dev_err(dai->dev, "too many tx slots defined (mask = 0x%x) supported max %d\n",
+ tx_mask, FRAMER_NB_CHANNEL);
+ return -EINVAL;
+ }
+
+ framer->max_chan_capture = hweight32(rx_mask);
+ if (framer->max_chan_capture > FRAMER_NB_CHANNEL) {
+ dev_err(dai->dev, "too many rx slots defined (mask = 0x%x) supported max %d\n",
+ rx_mask, FRAMER_NB_CHANNEL);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * The constraints for format/channel is to match with the number of 8bit
+ * time-slots available.
+ */
+static int framer_dai_hw_rule_channels_by_format(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params,
+ unsigned int nb_ts)
+{
+ struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ snd_pcm_format_t format = params_format(params);
+ struct snd_interval ch = {0};
+ int width;
+
+ width = snd_pcm_format_physical_width(format);
+ if (width == 8 || width == 16 || width == 32 || width == 64) {
+ ch.max = nb_ts * 8 / width;
+ } else {
+ dev_err(dai->dev, "format physical width %d not supported\n", width);
+ return -EINVAL;
+ }
+
+ ch.min = ch.max ? 1 : 0;
+
+ return snd_interval_refine(c, &ch);
+}
+
+static int framer_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_soc_dai *dai = rule->private;
+ struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component);
+
+ return framer_dai_hw_rule_channels_by_format(dai, params, framer->max_chan_playback);
+}
+
+static int framer_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_soc_dai *dai = rule->private;
+ struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component);
+
+ return framer_dai_hw_rule_channels_by_format(dai, params, framer->max_chan_capture);
+}
+
+static int framer_dai_hw_rule_format_by_channels(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params,
+ unsigned int nb_ts)
+{
+ struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ unsigned int channels = params_channels(params);
+ unsigned int slot_width;
+ snd_pcm_format_t format;
+ struct snd_mask f_new;
+
+ if (!channels || channels > nb_ts) {
+ dev_err(dai->dev, "channels %u not supported\n", nb_ts);
+ return -EINVAL;
+ }
+
+ slot_width = (nb_ts / channels) * 8;
+
+ snd_mask_none(&f_new);
+ pcm_for_each_format(format) {
+ if (snd_mask_test_format(f_old, format)) {
+ if (snd_pcm_format_physical_width(format) <= slot_width)
+ snd_mask_set_format(&f_new, format);
+ }
+ }
+
+ return snd_mask_refine(f_old, &f_new);
+}
+
+static int framer_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_soc_dai *dai = rule->private;
+ struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component);
+
+ return framer_dai_hw_rule_format_by_channels(dai, params, framer->max_chan_playback);
+}
+
+static int framer_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_soc_dai *dai = rule->private;
+ struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component);
+
+ return framer_dai_hw_rule_format_by_channels(dai, params, framer->max_chan_capture);
+}
+
+static u64 framer_formats(u8 nb_ts)
+{
+ unsigned int format_width;
+ unsigned int chan_width;
+ snd_pcm_format_t format;
+ u64 formats_mask;
+
+ if (!nb_ts)
+ return 0;
+
+ formats_mask = 0;
+ chan_width = nb_ts * 8;
+ pcm_for_each_format(format) {
+ /* Support physical width multiple of 8bit */
+ format_width = snd_pcm_format_physical_width(format);
+ if (format_width == 0 || format_width % 8)
+ continue;
+
+ /*
+ * And support physical width that can fit N times in the
+ * channel
+ */
+ if (format_width > chan_width || chan_width % format_width)
+ continue;
+
+ formats_mask |= pcm_format_to_bits(format);
+ }
+ return formats_mask;
+}
+
+static int framer_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component);
+ snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
+ snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
+ unsigned int frame_bits;
+ u64 format;
+ int ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ format = framer_formats(framer->max_chan_capture);
+ hw_rule_channels_by_format = framer_dai_hw_rule_capture_channels_by_format;
+ hw_rule_format_by_channels = framer_dai_hw_rule_capture_format_by_channels;
+ frame_bits = framer->max_chan_capture * 8;
+ } else {
+ format = framer_formats(framer->max_chan_playback);
+ hw_rule_channels_by_format = framer_dai_hw_rule_playback_channels_by_format;
+ hw_rule_format_by_channels = framer_dai_hw_rule_playback_format_by_channels;
+ frame_bits = framer->max_chan_playback * 8;
+ }
+
+ ret = snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT, format);
+ if (ret) {
+ dev_err(dai->dev, "Failed to add format constraint (%d)\n", ret);
+ return ret;
+ }
+
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_channels_by_format, dai,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (ret) {
+ dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret);
+ return ret;
+ }
+
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
+ hw_rule_format_by_channels, dai,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (ret) {
+ dev_err(dai->dev, "Failed to add format rule (%d)\n", ret);
+ return ret;
+ }
+
+ ret = snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ frame_bits);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const u64 framer_dai_formats[] = {
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
+static const struct snd_soc_dai_ops framer_dai_ops = {
+ .startup = framer_dai_startup,
+ .set_tdm_slot = framer_dai_set_tdm_slot,
+ .auto_selectable_formats = framer_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(framer_dai_formats),
+};
+
+static struct snd_soc_dai_driver framer_dai_driver = {
+ .name = "framer",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = FRAMER_NB_CHANNEL,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = U64_MAX, /* Will be refined on DAI .startup() */
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = FRAMER_NB_CHANNEL,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = U64_MAX, /* Will be refined on DAI .startup() */
+ },
+ .ops = &framer_dai_ops,
+};
+
+static void framer_carrier_work(struct work_struct *work)
+{
+ struct framer_codec *framer = container_of(work, struct framer_codec, carrier_work);
+ struct framer_status framer_status;
+ int jack_status;
+ int ret;
+
+ ret = framer_get_status(framer->framer, &framer_status);
+ if (ret) {
+ dev_err(framer->dev, "get framer status failed (%d)\n", ret);
+ return;
+ }
+
+ jack_status = framer_status.link_is_on ? FRAMER_JACK_MASK : 0;
+ snd_soc_jack_report(&framer->jack, jack_status, FRAMER_JACK_MASK);
+}
+
+static int framer_carrier_notifier(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct framer_codec *framer = container_of(nb, struct framer_codec, nb);
+
+ switch (action) {
+ case FRAMER_EVENT_STATUS:
+ queue_work(system_power_efficient_wq, &framer->carrier_work);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int framer_component_probe(struct snd_soc_component *component)
+{
+ struct framer_codec *framer = snd_soc_component_get_drvdata(component);
+ struct framer_status status;
+ char *name;
+ int ret;
+
+ INIT_WORK(&framer->carrier_work, framer_carrier_work);
+
+ name = "carrier";
+ if (component->name_prefix) {
+ name = kasprintf(GFP_KERNEL, "%s carrier", component->name_prefix);
+ if (!name)
+ return -ENOMEM;
+ }
+
+ ret = snd_soc_card_jack_new(component->card, name, FRAMER_JACK_MASK, &framer->jack);
+ if (component->name_prefix)
+ kfree(name); /* A copy is done by snd_soc_card_jack_new */
+ if (ret) {
+ dev_err(component->dev, "Cannot create jack\n");
+ return ret;
+ }
+
+ ret = framer_init(framer->framer);
+ if (ret) {
+ dev_err(component->dev, "framer init failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = framer_power_on(framer->framer);
+ if (ret) {
+ dev_err(component->dev, "framer power-on failed (%d)\n", ret);
+ goto framer_exit;
+ }
+
+ /* Be sure that get_status is supported */
+ ret = framer_get_status(framer->framer, &status);
+ if (ret) {
+ dev_err(component->dev, "get framer status failed (%d)\n", ret);
+ goto framer_power_off;
+ }
+
+ framer->nb.notifier_call = framer_carrier_notifier;
+ ret = framer_notifier_register(framer->framer, &framer->nb);
+ if (ret) {
+ dev_err(component->dev, "Cannot register event notifier\n");
+ goto framer_power_off;
+ }
+
+ /* Queue work to set the initial value */
+ queue_work(system_power_efficient_wq, &framer->carrier_work);
+
+ return 0;
+
+framer_power_off:
+ framer_power_off(framer->framer);
+framer_exit:
+ framer_exit(framer->framer);
+ return ret;
+}
+
+static void framer_component_remove(struct snd_soc_component *component)
+{
+ struct framer_codec *framer = snd_soc_component_get_drvdata(component);
+
+ framer_notifier_unregister(framer->framer, &framer->nb);
+ cancel_work_sync(&framer->carrier_work);
+ framer_power_off(framer->framer);
+ framer_exit(framer->framer);
+}
+
+static const struct snd_soc_component_driver framer_component_driver = {
+ .probe = framer_component_probe,
+ .remove = framer_component_remove,
+ .endianness = 1,
+};
+
+static int framer_codec_probe(struct platform_device *pdev)
+{
+ struct framer_codec *framer;
+
+ framer = devm_kzalloc(&pdev->dev, sizeof(*framer), GFP_KERNEL);
+ if (!framer)
+ return -ENOMEM;
+
+ framer->dev = &pdev->dev;
+
+ /* Get framer from parents node */
+ framer->framer = devm_framer_get(&pdev->dev, NULL);
+ if (IS_ERR(framer->framer))
+ return dev_err_probe(&pdev->dev, PTR_ERR(framer->framer), "get framer failed\n");
+
+ platform_set_drvdata(pdev, framer);
+
+ return devm_snd_soc_register_component(&pdev->dev, &framer_component_driver,
+ &framer_dai_driver, 1);
+}
+
+static struct platform_driver framer_codec_driver = {
+ .driver = {
+ .name = "framer-codec",
+ },
+ .probe = framer_codec_probe,
+};
+module_platform_driver(framer_codec_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("FRAMER ALSA SoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c
new file mode 100644
index 000000000000..c8f56617e370
--- /dev/null
+++ b/sound/soc/codecs/fs-amp-lib.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// fs-amp-lib.c --- Common library for FourSemi Audio Amplifiers
+//
+// Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd.
+
+#include <linux/crc16.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "fs-amp-lib.h"
+
+static int fs_get_scene_count(struct fs_amp_lib *amp_lib)
+{
+ const struct fs_fwm_table *table;
+ int count;
+
+ if (!amp_lib || !amp_lib->dev)
+ return -EINVAL;
+
+ table = amp_lib->table[FS_INDEX_SCENE];
+ if (!table)
+ return -EFAULT;
+
+ count = table->size / sizeof(struct fs_scene_index);
+ if (count < 1 || count > FS_SCENE_COUNT_MAX) {
+ dev_err(amp_lib->dev, "Invalid scene count: %d\n", count);
+ return -ERANGE;
+ }
+
+ return count;
+}
+
+static void fs_get_fwm_string(struct fs_amp_lib *amp_lib,
+ int offset, const char **pstr)
+{
+ const struct fs_fwm_table *table;
+
+ if (!amp_lib || !amp_lib->dev || !pstr)
+ return;
+
+ table = amp_lib->table[FS_INDEX_STRING];
+ if (table && offset > 0 && offset < table->size + sizeof(*table))
+ *pstr = (char *)table + offset;
+ else
+ *pstr = NULL;
+}
+
+static void fs_get_scene_reg(struct fs_amp_lib *amp_lib,
+ int offset, struct fs_amp_scene *scene)
+{
+ const struct fs_fwm_table *table;
+
+ if (!amp_lib || !amp_lib->dev || !scene)
+ return;
+
+ table = amp_lib->table[FS_INDEX_REG];
+ if (table && offset > 0 && offset < table->size + sizeof(*table))
+ scene->reg = (struct fs_reg_table *)((char *)table + offset);
+ else
+ scene->reg = NULL;
+}
+
+static void fs_get_scene_model(struct fs_amp_lib *amp_lib,
+ int offset, struct fs_amp_scene *scene)
+{
+ const struct fs_fwm_table *table;
+ const char *ptr;
+
+ if (!amp_lib || !amp_lib->dev || !scene)
+ return;
+
+ table = amp_lib->table[FS_INDEX_MODEL];
+ ptr = (char *)table;
+ if (table && offset > 0 && offset < table->size + sizeof(*table))
+ scene->model = (struct fs_file_table *)(ptr + offset);
+ else
+ scene->model = NULL;
+}
+
+static void fs_get_scene_effect(struct fs_amp_lib *amp_lib,
+ int offset, struct fs_amp_scene *scene)
+{
+ const struct fs_fwm_table *table;
+ const char *ptr;
+
+ if (!amp_lib || !amp_lib->dev || !scene)
+ return;
+
+ table = amp_lib->table[FS_INDEX_EFFECT];
+ ptr = (char *)table;
+ if (table && offset > 0 && offset < table->size + sizeof(*table))
+ scene->effect = (struct fs_file_table *)(ptr + offset);
+ else
+ scene->effect = NULL;
+}
+
+static int fs_parse_scene_tables(struct fs_amp_lib *amp_lib)
+{
+ const struct fs_scene_index *scene_index;
+ const struct fs_fwm_table *table;
+ struct fs_amp_scene *scene;
+ int idx, count;
+
+ if (!amp_lib || !amp_lib->dev)
+ return -EINVAL;
+
+ count = fs_get_scene_count(amp_lib);
+ if (count <= 0)
+ return -EFAULT;
+
+ scene = devm_kcalloc(amp_lib->dev, count, sizeof(*scene), GFP_KERNEL);
+ if (!scene)
+ return -ENOMEM;
+
+ amp_lib->scene_count = count;
+ amp_lib->scene = scene;
+
+ table = amp_lib->table[FS_INDEX_SCENE];
+ scene_index = (struct fs_scene_index *)table->buf;
+
+ for (idx = 0; idx < count; idx++) {
+ fs_get_fwm_string(amp_lib, scene_index->name, &scene->name);
+ if (!scene->name)
+ scene->name = devm_kasprintf(amp_lib->dev,
+ GFP_KERNEL, "S%d", idx);
+ dev_dbg(amp_lib->dev, "scene.%d name: %s\n", idx, scene->name);
+ fs_get_scene_reg(amp_lib, scene_index->reg, scene);
+ fs_get_scene_model(amp_lib, scene_index->model, scene);
+ fs_get_scene_effect(amp_lib, scene_index->effect, scene);
+ scene++;
+ scene_index++;
+ }
+
+ return 0;
+}
+
+static int fs_parse_all_tables(struct fs_amp_lib *amp_lib)
+{
+ const struct fs_fwm_table *table;
+ const struct fs_fwm_index *index;
+ const char *ptr;
+ int idx, count;
+ int ret;
+
+ if (!amp_lib || !amp_lib->dev || !amp_lib->hdr)
+ return -EINVAL;
+
+ /* Parse all fwm tables */
+ table = (struct fs_fwm_table *)amp_lib->hdr->params;
+ index = (struct fs_fwm_index *)table->buf;
+ count = table->size / sizeof(*index);
+
+ for (idx = 0; idx < count; idx++, index++) {
+ if (index->type >= FS_INDEX_MAX)
+ return -ERANGE;
+ ptr = (char *)table + (int)index->offset;
+ amp_lib->table[index->type] = (struct fs_fwm_table *)ptr;
+ }
+
+ /* Parse all scene tables */
+ ret = fs_parse_scene_tables(amp_lib);
+ if (ret)
+ dev_err(amp_lib->dev, "Failed to parse scene: %d\n", ret);
+
+ return ret;
+}
+
+static int fs_verify_firmware(struct fs_amp_lib *amp_lib)
+{
+ const struct fs_fwm_header *hdr;
+ int crcsum;
+
+ if (!amp_lib || !amp_lib->dev || !amp_lib->hdr)
+ return -EINVAL;
+
+ hdr = amp_lib->hdr;
+
+ /* Verify the crcsum code */
+ crcsum = crc16(0x0000, (const char *)&hdr->crc_size, hdr->crc_size);
+ if (crcsum != hdr->crc16) {
+ dev_err(amp_lib->dev, "Failed to checksum: %x-%x\n",
+ crcsum, hdr->crc16);
+ return -EFAULT;
+ }
+
+ /* Verify the devid(chip_type) */
+ if (amp_lib->devid != LO_U16(hdr->chip_type)) {
+ dev_err(amp_lib->dev, "DEVID dismatch: %04X#%04X\n",
+ amp_lib->devid, hdr->chip_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void fs_print_firmware_info(struct fs_amp_lib *amp_lib)
+{
+ const struct fs_fwm_header *hdr;
+ const char *pro_name = NULL;
+ const char *dev_name = NULL;
+
+ if (!amp_lib || !amp_lib->dev || !amp_lib->hdr)
+ return;
+
+ hdr = amp_lib->hdr;
+
+ fs_get_fwm_string(amp_lib, hdr->project, &pro_name);
+ fs_get_fwm_string(amp_lib, hdr->device, &dev_name);
+
+ dev_info(amp_lib->dev, "Project: %s Device: %s\n",
+ pro_name ? pro_name : "null",
+ dev_name ? dev_name : "null");
+
+ dev_info(amp_lib->dev, "Date: %04d%02d%02d-%02d%02d\n",
+ hdr->date.year, hdr->date.month, hdr->date.day,
+ hdr->date.hour, hdr->date.minute);
+}
+
+int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name)
+{
+ const struct firmware *cont;
+ struct fs_fwm_header *hdr;
+ int ret;
+
+ if (!amp_lib || !amp_lib->dev || !name)
+ return -EINVAL;
+
+ ret = request_firmware(&cont, name, amp_lib->dev);
+ if (ret) {
+ dev_err(amp_lib->dev, "Failed to request %s: %d\n", name, ret);
+ return ret;
+ }
+
+ dev_info(amp_lib->dev, "Loading %s - size: %zu\n", name, cont->size);
+
+ hdr = devm_kmemdup(amp_lib->dev, cont->data, cont->size, GFP_KERNEL);
+ release_firmware(cont);
+ if (!hdr)
+ return -ENOMEM;
+
+ amp_lib->hdr = hdr;
+ ret = fs_verify_firmware(amp_lib);
+ if (ret) {
+ amp_lib->hdr = NULL;
+ return ret;
+ }
+
+ ret = fs_parse_all_tables(amp_lib);
+ if (ret) {
+ amp_lib->hdr = NULL;
+ return ret;
+ }
+
+ fs_print_firmware_info(amp_lib);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fs_amp_load_firmware);
+
+MODULE_AUTHOR("Nick Li <nick.li@foursemi.com>");
+MODULE_DESCRIPTION("FourSemi audio amplifier library");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/fs-amp-lib.h b/sound/soc/codecs/fs-amp-lib.h
new file mode 100644
index 000000000000..4a77c7b383cd
--- /dev/null
+++ b/sound/soc/codecs/fs-amp-lib.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * fs-amp-lib.h --- Common library for FourSemi Audio Amplifiers
+ *
+ * Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd.
+ */
+
+#ifndef __FS_AMP_LIB_H__
+#define __FS_AMP_LIB_H__
+
+#define HI_U16(a) (((a) >> 8) & 0xFF)
+#define LO_U16(a) ((a) & 0xFF)
+#define FS_TABLE_NAME_LEN (4)
+#define FS_SCENE_COUNT_MAX (16)
+#define FS_CMD_DELAY_MS_MAX (100) /* 100ms */
+
+#define FS_CMD_DELAY (0xFF)
+#define FS_CMD_BURST (0xFE)
+#define FS_CMD_UPDATE (0xFD)
+
+#define FS_SOC_ENUM_EXT(xname, xhandler_info, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = xhandler_info, \
+ .get = xhandler_get, .put = xhandler_put \
+}
+
+enum fs_index_type {
+ FS_INDEX_INFO = 0,
+ FS_INDEX_STCOEF,
+ FS_INDEX_SCENE,
+ FS_INDEX_MODEL,
+ FS_INDEX_REG,
+ FS_INDEX_EFFECT,
+ FS_INDEX_STRING,
+ FS_INDEX_WOOFER,
+ FS_INDEX_MAX,
+};
+
+#pragma pack(push, 1)
+
+struct fs_reg_val {
+ u8 reg;
+ u16 val;
+};
+
+struct fs_reg_bits {
+ u8 cmd; /* FS_CMD_UPDATE */
+ u8 reg;
+ u16 val;
+ u16 mask;
+};
+
+struct fs_cmd_pkg {
+ union {
+ u8 cmd;
+ struct fs_reg_val regv;
+ struct fs_reg_bits regb;
+ };
+};
+
+struct fs_fwm_index {
+ /* Index type */
+ u16 type;
+ /* Offset address starting from the end of header */
+ u16 offset;
+};
+
+struct fs_fwm_table {
+ char name[FS_TABLE_NAME_LEN];
+ u16 size; /* size of buf */
+ u8 buf[];
+};
+
+struct fs_scene_index {
+ /* Offset address(scene name) in string table */
+ u16 name;
+ /* Offset address(scene reg) in register table */
+ u16 reg;
+ /* Offset address(scene model) in model table */
+ u16 model;
+ /* Offset address(scene effect) in effect table */
+ u16 effect;
+};
+
+struct fs_reg_table {
+ u16 size; /* size of buf */
+ u8 buf[];
+};
+
+struct fs_file_table {
+ u16 name;
+ u16 size; /* size of buf */
+ u8 buf[];
+};
+
+struct fs_fwm_date {
+ u32 year:12;
+ u32 month:4;
+ u32 day:5;
+ u32 hour:5;
+ u32 minute:6;
+};
+
+struct fs_fwm_header {
+ u16 version;
+ u16 project; /* Offset address(project name) in string table */
+ u16 device; /* Offset address(device name) in string table */
+ struct fs_fwm_date date;
+ u16 crc16;
+ u16 crc_size; /* Starting position for CRC checking */
+ u16 chip_type;
+ u16 addr; /* 7-bit i2c address */
+ u16 spkid;
+ u16 rsvd[6];
+ u8 params[];
+};
+
+#pragma pack(pop)
+
+struct fs_i2s_srate {
+ u32 srate; /* Sample rate */
+ u16 i2ssr; /* Value of Bit field[I2SSR] */
+};
+
+struct fs_pll_div {
+ unsigned int bclk; /* Rate of bit clock */
+ u16 pll1;
+ u16 pll2;
+ u16 pll3;
+};
+
+struct fs_amp_scene {
+ const char *name;
+ const struct fs_reg_table *reg;
+ const struct fs_file_table *model;
+ const struct fs_file_table *effect;
+};
+
+struct fs_amp_lib {
+ const struct fs_fwm_header *hdr;
+ const struct fs_fwm_table *table[FS_INDEX_MAX];
+ struct fs_amp_scene *scene;
+ struct device *dev;
+ int scene_count;
+ u16 devid;
+};
+
+int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name);
+
+#endif // __FS_AMP_LIB_H__
diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c
new file mode 100644
index 000000000000..e6195b71adad
--- /dev/null
+++ b/sound/soc/codecs/fs210x.c
@@ -0,0 +1,1586 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// fs210x.c -- Driver for the FS2104/5S Audio Amplifier
+//
+// Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd.
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "fs210x.h"
+#include "fs-amp-lib.h"
+
+#define FS210X_DEFAULT_FWM_NAME "fs210x_fwm.bin"
+#define FS210X_DEFAULT_DAI_NAME "fs210x-aif"
+#define FS2105S_DEVICE_ID 0x20 /* FS2105S */
+#define FS210X_DEVICE_ID 0x45 /* FS2104 */
+#define FS210X_REG_MAX 0xF8
+#define FS210X_INIT_SCENE 0
+#define FS210X_DEFAULT_SCENE 1
+#define FS210X_START_DELAY_MS 5
+#define FS210X_FAULT_CHECK_INTERVAL_MS 2000
+#define FS2105S_RATES (SNDRV_PCM_RATE_32000 | \
+ SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000)
+#define FS210X_RATES (SNDRV_PCM_RATE_16000 | FS2105S_RATES)
+#define FS210X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+#define FS210X_NUM_SUPPLIES ARRAY_SIZE(fs210x_supply_names)
+
+static const char *const fs210x_supply_names[] = {
+ "pvdd",
+ "dvdd",
+};
+
+struct fs210x_platform_data {
+ const char *fwm_name;
+};
+
+struct fs210x_priv {
+ struct i2c_client *i2c;
+ struct device *dev;
+ struct regmap *regmap;
+ struct fs210x_platform_data pdata;
+ struct regulator_bulk_data supplies[FS210X_NUM_SUPPLIES];
+ struct gpio_desc *gpio_sdz;
+ struct delayed_work start_work;
+ struct delayed_work fault_check_work;
+ struct fs_amp_lib amp_lib;
+ const struct fs_amp_scene *cur_scene;
+ struct clk *clk_bclk;
+ /*
+ * @lock: Mutex ensuring exclusive access for critical device operations
+ *
+ * This lock serializes access between the following actions:
+ * - Device initialization procedures(probe)
+ * - Enable/disable device(DAPM event)
+ * - Suspend/resume device(PM)
+ * - Runtime scene switching(control)
+ * - Scheduling/execution of delayed works items(delayed works)
+ */
+ struct mutex lock;
+ unsigned int check_interval_ms;
+ unsigned int bclk;
+ unsigned int srate;
+ int scene_id;
+ u16 devid;
+ bool is_inited;
+ bool is_suspended;
+ bool is_bclk_on;
+ bool is_playing;
+};
+
+static const unsigned int fs2105s_rates[] = {
+ 32000, 44100, 48000, 88200, 96000
+};
+
+static const struct snd_pcm_hw_constraint_list fs2105s_constraints = {
+ .count = ARRAY_SIZE(fs2105s_rates),
+ .list = fs2105s_rates,
+};
+
+static const unsigned int fs210x_rates[] = {
+ 16000, 32000, 44100, 48000, 88200, 96000
+};
+
+static const struct snd_pcm_hw_constraint_list fs210x_constraints = {
+ .count = ARRAY_SIZE(fs210x_rates),
+ .list = fs210x_rates,
+};
+
+static const struct fs_pll_div fs210x_pll_div[] = {
+ /* bclk, pll1, pll2, pll3 */
+ { 512000, 0x006C, 0x0120, 0x0001 },
+ { 768000, 0x016C, 0x00C0, 0x0001 },
+ { 1024000, 0x016C, 0x0090, 0x0001 },
+ { 1536000, 0x016C, 0x0060, 0x0001 },
+ { 2048000, 0x016C, 0x0090, 0x0002 },
+ { 2304000, 0x016C, 0x0080, 0x0002 },
+ { 3072000, 0x016C, 0x0090, 0x0003 },
+ { 4096000, 0x016C, 0x0090, 0x0004 },
+ { 4608000, 0x016C, 0x0080, 0x0004 },
+ { 6144000, 0x016C, 0x0090, 0x0006 },
+ { 8192000, 0x016C, 0x0090, 0x0008 },
+ { 9216000, 0x016C, 0x0090, 0x0009 },
+ { 12288000, 0x016C, 0x0090, 0x000C },
+ { 16384000, 0x016C, 0x0090, 0x0010 },
+ { 18432000, 0x016C, 0x0090, 0x0012 },
+ { 24576000, 0x016C, 0x0090, 0x0018 },
+ { 1411200, 0x016C, 0x0060, 0x0001 },
+ { 2116800, 0x016C, 0x0080, 0x0002 },
+ { 2822400, 0x016C, 0x0090, 0x0003 },
+ { 4233600, 0x016C, 0x0080, 0x0004 },
+ { 5644800, 0x016C, 0x0090, 0x0006 },
+ { 8467200, 0x016C, 0x0090, 0x0009 },
+ { 11289600, 0x016C, 0x0090, 0x000C },
+ { 16934400, 0x016C, 0x0090, 0x0012 },
+ { 22579200, 0x016C, 0x0090, 0x0018 },
+ { 2000000, 0x017C, 0x0093, 0x0002 },
+};
+
+static int fs210x_bclk_set(struct fs210x_priv *fs210x, bool on)
+{
+ int ret = 0;
+
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ if ((fs210x->is_bclk_on ^ on) == 0)
+ return 0;
+
+ if (on) {
+ clk_set_rate(fs210x->clk_bclk, fs210x->bclk);
+ ret = clk_prepare_enable(fs210x->clk_bclk);
+ fs210x->is_bclk_on = true;
+ fsleep(2000); /* >= 2ms */
+ } else {
+ clk_disable_unprepare(fs210x->clk_bclk);
+ fs210x->is_bclk_on = false;
+ }
+
+ return ret;
+}
+
+static int fs210x_reg_write(struct fs210x_priv *fs210x,
+ u8 reg, u16 val)
+{
+ int ret;
+
+ ret = regmap_write(fs210x->regmap, reg, val);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to write %02Xh: %d\n", reg, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fs210x_reg_read(struct fs210x_priv *fs210x,
+ u8 reg, u16 *pval)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(fs210x->regmap, reg, &val);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to read %02Xh: %d\n", reg, ret);
+ return ret;
+ }
+
+ *pval = (u16)val;
+
+ return 0;
+}
+
+static int fs210x_reg_update_bits(struct fs210x_priv *fs210x,
+ u8 reg, u16 mask, u16 val)
+{
+ int ret;
+
+ ret = regmap_update_bits(fs210x->regmap, reg, mask, val);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to update %02Xh: %d\n", reg, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fs210x_reg_bulk_write(struct fs210x_priv *fs210x,
+ u8 reg, const void *val, u32 size)
+{
+ int ret;
+
+ ret = regmap_bulk_write(fs210x->regmap, reg, val, size / 2);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to bulk write %02Xh: %d\n",
+ reg, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline int fs210x_write_reg_val(struct fs210x_priv *fs210x,
+ const struct fs_reg_val *regv)
+{
+ return fs210x_reg_write(fs210x, regv->reg, regv->val);
+}
+
+static inline int fs210x_write_reg_bits(struct fs210x_priv *fs210x,
+ const struct fs_reg_bits *regu)
+{
+ return fs210x_reg_update_bits(fs210x,
+ regu->reg,
+ regu->mask,
+ regu->val);
+}
+
+static inline int fs210x_set_cmd_pkg(struct fs210x_priv *fs210x,
+ const struct fs_cmd_pkg *pkg,
+ unsigned int *offset)
+{
+ int delay_us;
+
+ if (pkg->cmd >= 0x00 && pkg->cmd <= FS210X_REG_MAX) {
+ *offset = sizeof(pkg->regv);
+ return fs210x_write_reg_val(fs210x, &pkg->regv);
+ } else if (pkg->cmd == FS_CMD_UPDATE) {
+ *offset = sizeof(pkg->regb);
+ return fs210x_write_reg_bits(fs210x, &pkg->regb);
+ } else if (pkg->cmd == FS_CMD_DELAY) {
+ if (pkg->regv.val > FS_CMD_DELAY_MS_MAX)
+ return -EOPNOTSUPP;
+ delay_us = pkg->regv.val * 1000; /* ms -> us */
+ fsleep(delay_us);
+ *offset = sizeof(pkg->regv);
+ return 0;
+ }
+
+ dev_err(fs210x->dev, "Invalid pkg cmd: %d\n", pkg->cmd);
+
+ return -EOPNOTSUPP;
+}
+
+static int fs210x_reg_write_table(struct fs210x_priv *fs210x,
+ const struct fs_reg_table *reg)
+{
+ const struct fs_cmd_pkg *pkg;
+ unsigned int index, offset;
+ int ret;
+
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ if (!reg || reg->size == 0)
+ return -EFAULT;
+
+ for (index = 0; index < reg->size; index += offset) {
+ pkg = (struct fs_cmd_pkg *)(reg->buf + index);
+ ret = fs210x_set_cmd_pkg(fs210x, pkg, &offset);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to set cmd pkg: %02X-%d\n",
+ pkg->cmd, ret);
+ return ret;
+ }
+ }
+
+ if (index != reg->size) {
+ dev_err(fs210x->dev, "Invalid reg table size: %d-%d\n",
+ index, reg->size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int fs210x_dev_play(struct fs210x_priv *fs210x)
+{
+ int ret;
+
+ if (!fs210x->is_inited)
+ return -EFAULT;
+
+ if (fs210x->is_playing)
+ return 0;
+
+ ret = fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL,
+ FS210X_11H_DPS_PLAY);
+ if (!ret)
+ fs210x->is_playing = true;
+
+ fsleep(10000); /* >= 10ms */
+
+ return ret;
+}
+
+static int fs210x_dev_stop(struct fs210x_priv *fs210x)
+{
+ int ret;
+
+ if (!fs210x->is_inited)
+ return -EFAULT;
+
+ if (!fs210x->is_playing)
+ return 0;
+
+ ret = fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL,
+ FS210X_11H_DPS_PWDN);
+ fs210x->is_playing = false;
+
+ fsleep(30000); /* >= 30ms */
+
+ return ret;
+}
+
+static int fs210x_set_reg_table(struct fs210x_priv *fs210x,
+ const struct fs_amp_scene *scene)
+{
+ const struct fs_amp_scene *cur_scene;
+ const struct fs_reg_table *reg;
+
+ if (!fs210x || !fs210x->dev || !scene)
+ return -EINVAL;
+
+ cur_scene = fs210x->cur_scene;
+ if (!scene->reg || cur_scene == scene) {
+ dev_dbg(fs210x->dev, "Skip writing reg table\n");
+ return 0;
+ }
+
+ reg = scene->reg;
+ dev_dbg(fs210x->dev, "reg table size: %d\n", reg->size);
+
+ return fs210x_reg_write_table(fs210x, reg);
+}
+
+static int fs210x_set_woofer_table(struct fs210x_priv *fs210x)
+{
+ const struct fs_file_table *woofer;
+ const struct fs_fwm_table *table;
+ int ret;
+
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ /* NOTE: fs2105s has woofer ram only */
+ if (fs210x->devid != FS2105S_DEVICE_ID)
+ return 0;
+
+ table = fs210x->amp_lib.table[FS_INDEX_WOOFER];
+ if (!table) {
+ dev_dbg(fs210x->dev, "Skip writing woofer table\n");
+ return 0;
+ }
+
+ woofer = (struct fs_file_table *)table->buf;
+ dev_dbg(fs210x->dev, "woofer table size: %d\n", woofer->size);
+ /* Unit of woofer data is u32(4 bytes) */
+ if (woofer->size == 0 || (woofer->size & 0x3)) {
+ dev_err(fs210x->dev, "Invalid woofer size: %d\n",
+ woofer->size);
+ return -EINVAL;
+ }
+
+ ret = fs210x_reg_write(fs210x, FS210X_46H_DACEQA,
+ FS2105S_46H_CAM_BURST_W);
+ ret |= fs210x_reg_bulk_write(fs210x, FS210X_42H_DACEQWL,
+ woofer->buf, woofer->size);
+
+ return ret;
+}
+
+static int fs210x_set_effect_table(struct fs210x_priv *fs210x,
+ const struct fs_amp_scene *scene)
+{
+ const struct fs_amp_scene *cur_scene;
+ const struct fs_file_table *effect;
+ int half_size;
+ int ret;
+
+ if (!fs210x || !fs210x->dev || !scene)
+ return -EINVAL;
+
+ cur_scene = fs210x->cur_scene;
+ if (!scene->effect || cur_scene == scene) {
+ dev_dbg(fs210x->dev, "Skip writing effect table\n");
+ return 0;
+ }
+
+ effect = scene->effect;
+ dev_dbg(fs210x->dev, "effect table size: %d\n", effect->size);
+
+ /* Unit of effect data is u32(4 bytes), 2 channels */
+ if (effect->size == 0 || (effect->size & 0x7)) {
+ dev_err(fs210x->dev, "Invalid effect size: %d\n",
+ effect->size);
+ return -EINVAL;
+ }
+
+ half_size = effect->size / 2;
+
+ /* Left channel */
+ ret = fs210x_reg_write(fs210x, FS210X_46H_DACEQA,
+ FS210X_46H_CAM_BURST_L);
+ ret |= fs210x_reg_bulk_write(fs210x, FS210X_42H_DACEQWL,
+ effect->buf, half_size);
+ if (ret)
+ return ret;
+
+ /* Right channel */
+ ret = fs210x_reg_write(fs210x, FS210X_46H_DACEQA,
+ FS210X_46H_CAM_BURST_R);
+ ret |= fs210x_reg_bulk_write(fs210x, FS210X_42H_DACEQWL,
+ effect->buf + half_size, half_size);
+
+ return ret;
+}
+
+static int fs210x_access_dsp_ram(struct fs210x_priv *fs210x, bool enable)
+{
+ int ret;
+
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ if (enable) {
+ ret = fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL,
+ FS210X_11H_DPS_HIZ);
+ ret |= fs210x_reg_write(fs210x, FS210X_0BH_ACCKEY,
+ FS210X_0BH_ACCKEY_ON);
+ } else {
+ ret = fs210x_reg_write(fs210x, FS210X_0BH_ACCKEY,
+ FS210X_0BH_ACCKEY_OFF);
+ ret |= fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL,
+ FS210X_11H_DPS_PWDN);
+ }
+
+ fsleep(10000); /* >= 10ms */
+
+ return ret;
+}
+
+static int fs210x_write_dsp_effect(struct fs210x_priv *fs210x,
+ const struct fs_amp_scene *scene,
+ int scene_id)
+{
+ int ret;
+
+ if (!fs210x || !scene)
+ return -EINVAL;
+
+ ret = fs210x_access_dsp_ram(fs210x, true);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to access dsp: %d\n", ret);
+ goto tag_exit;
+ }
+
+ ret = fs210x_set_effect_table(fs210x, scene);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to set effect: %d\n", ret);
+ goto tag_exit;
+ }
+
+ if (scene_id == FS210X_INIT_SCENE)
+ ret = fs210x_set_woofer_table(fs210x);
+
+tag_exit:
+ fs210x_reg_write(fs210x, FS210X_46H_DACEQA,
+ FS210X_46H_CAM_CLEAR);
+ fs210x_access_dsp_ram(fs210x, false);
+
+ return ret;
+}
+
+static int fs210x_check_scene(struct fs210x_priv *fs210x,
+ int scene_id, bool *skip_set)
+{
+ struct fs_amp_lib *amp_lib;
+
+ if (!fs210x || !skip_set)
+ return -EINVAL;
+
+ amp_lib = &fs210x->amp_lib;
+ if (amp_lib->scene_count == 0 || !amp_lib->scene) {
+ dev_err(fs210x->dev, "There's no scene data\n");
+ return -EINVAL;
+ }
+
+ if (scene_id < 0 || scene_id >= amp_lib->scene_count) {
+ dev_err(fs210x->dev, "Invalid scene_id: %d\n", scene_id);
+ return -EINVAL;
+ }
+
+ if (fs210x->scene_id == scene_id) {
+ dev_dbg(fs210x->dev, "Skip to set same scene\n");
+ return 0;
+ }
+
+ *skip_set = false;
+
+ return 0;
+}
+
+static int fs210x_set_scene(struct fs210x_priv *fs210x, int scene_id)
+{
+ const struct fs_amp_scene *scene;
+ bool skip_set = true;
+ bool is_playing;
+ int ret;
+
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ ret = fs210x_check_scene(fs210x, scene_id, &skip_set);
+ if (ret || skip_set)
+ return ret;
+
+ scene = fs210x->amp_lib.scene + scene_id;
+ dev_info(fs210x->dev, "Switch scene.%d: %s\n",
+ scene_id, scene->name);
+
+ is_playing = fs210x->is_playing;
+ if (is_playing)
+ fs210x_dev_stop(fs210x);
+
+ ret = fs210x_set_reg_table(fs210x, scene);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to set reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = fs210x_write_dsp_effect(fs210x, scene, scene_id);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to write ram: %d\n", ret);
+ return ret;
+ }
+
+ fs210x->cur_scene = scene;
+ fs210x->scene_id = scene_id;
+
+ if (is_playing)
+ fs210x_dev_play(fs210x);
+
+ return 0;
+}
+
+static int fs210x_init_chip(struct fs210x_priv *fs210x)
+{
+ int scene_id;
+ int ret;
+
+ regcache_cache_bypass(fs210x->regmap, true);
+
+ if (!fs210x->gpio_sdz) {
+ /* Gpio is not found, i2c reset */
+ ret = fs210x_reg_write(fs210x, FS210X_10H_PWRCTRL,
+ FS210X_10H_I2C_RESET);
+ if (ret)
+ goto tag_power_down;
+ } else {
+ /* gpio reset, deactivate */
+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 0);
+ }
+
+ fsleep(10000); /* >= 10ms */
+
+ /* Backup scene id */
+ scene_id = fs210x->scene_id;
+ fs210x->scene_id = -1;
+
+ /* Init registers/RAM by init scene */
+ ret = fs210x_set_scene(fs210x, FS210X_INIT_SCENE);
+ if (ret)
+ goto tag_power_down;
+
+ /*
+ * If the firmware has effect scene(s),
+ * we load effect scene by default scene or scene_id
+ */
+ if (fs210x->amp_lib.scene_count > 1) {
+ if (scene_id < FS210X_DEFAULT_SCENE)
+ scene_id = FS210X_DEFAULT_SCENE;
+ ret = fs210x_set_scene(fs210x, scene_id);
+ if (ret)
+ goto tag_power_down;
+ }
+
+tag_power_down:
+ /* Power down the device */
+ ret |= fs210x_reg_write(fs210x, FS210X_11H_SYSCTRL,
+ FS210X_11H_DPS_PWDN);
+ fsleep(10000); /* >= 10ms */
+
+ regcache_cache_bypass(fs210x->regmap, false);
+ if (!ret) {
+ regcache_mark_dirty(fs210x->regmap);
+ regcache_sync(fs210x->regmap);
+ fs210x->is_inited = true;
+ }
+
+ return ret;
+}
+
+static int fs210x_set_i2s_params(struct fs210x_priv *fs210x)
+{
+ const struct fs_i2s_srate params[] = {
+ { 16000, 0x3 },
+ { 32000, 0x7 },
+ { 44100, 0x8 },
+ { 48000, 0x9 },
+ { 88200, 0xA },
+ { 96000, 0xB },
+ };
+ u16 val;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(params); i++) {
+ if (params[i].srate != fs210x->srate)
+ continue;
+ val = params[i].i2ssr << FS210X_17H_I2SSR_SHIFT;
+ ret = fs210x_reg_update_bits(fs210x,
+ FS210X_17H_I2SCTRL,
+ FS210X_17H_I2SSR_MASK,
+ val);
+ return ret;
+ }
+
+ dev_err(fs210x->dev, "Invalid sample rate: %d\n", fs210x->srate);
+
+ return -EINVAL;
+}
+
+static int fs210x_get_pll_div(struct fs210x_priv *fs210x,
+ const struct fs_pll_div **pll_div)
+{
+ int i;
+
+ if (!fs210x || !pll_div)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(fs210x_pll_div); i++) {
+ if (fs210x_pll_div[i].bclk != fs210x->bclk)
+ continue;
+ *pll_div = fs210x_pll_div + i;
+ return 0;
+ }
+
+ dev_err(fs210x->dev, "No PLL table for bclk: %d\n", fs210x->bclk);
+
+ return -EFAULT;
+}
+
+static int fs210x_set_hw_params(struct fs210x_priv *fs210x)
+{
+ const struct fs_pll_div *pll_div;
+ int ret;
+
+ ret = fs210x_set_i2s_params(fs210x);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to set i2s params: %d\n", ret);
+ return ret;
+ }
+
+ /* Set pll params */
+ ret = fs210x_get_pll_div(fs210x, &pll_div);
+ if (ret)
+ return ret;
+
+ ret = fs210x_reg_write(fs210x, FS210X_A1H_PLLCTRL1, pll_div->pll1);
+ ret |= fs210x_reg_write(fs210x, FS210X_A2H_PLLCTRL2, pll_div->pll2);
+ ret |= fs210x_reg_write(fs210x, FS210X_A3H_PLLCTRL3, pll_div->pll3);
+
+ return ret;
+}
+
+static int fs210x_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ const struct snd_pcm_hw_constraint_list *list;
+ struct fs210x_priv *fs210x;
+ int ret;
+
+ fs210x = snd_soc_component_get_drvdata(dai->component);
+ if (!fs210x) {
+ pr_err("dai_startup: fs210x is null\n");
+ return -EINVAL;
+ }
+
+ if (!substream->runtime)
+ return 0;
+
+ ret = snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT,
+ FS210X_FORMATS);
+ if (ret < 0) {
+ dev_err(fs210x->dev,
+ "Failed to set hw param format: %d\n", ret);
+ return ret;
+ }
+
+ if (fs210x->devid == FS2105S_DEVICE_ID)
+ list = &fs2105s_constraints;
+ else
+ list = &fs210x_constraints;
+
+ ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ list);
+ if (ret < 0) {
+ dev_err(fs210x->dev,
+ "Failed to set hw param rate: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fs210x_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct fs210x_priv *fs210x;
+
+ fs210x = snd_soc_component_get_drvdata(dai->component);
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ /* Only supports consumer mode */
+ break;
+ default:
+ dev_err(fs210x->dev, "Only supports consumer mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fs210x_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct fs210x_priv *fs210x;
+ int chn_num;
+ int ret;
+
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ fs210x = snd_soc_component_get_drvdata(dai->component);
+
+ fs210x->srate = params_rate(params);
+ fs210x->bclk = snd_soc_params_to_bclk(params);
+ chn_num = params_channels(params);
+ if (chn_num == 1) /* mono */
+ fs210x->bclk *= 2; /* I2S bus has 2 channels */
+
+ /* The FS2105S can't support 16kHz sample rate. */
+ if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&fs210x->lock);
+ ret = fs210x_set_hw_params(fs210x);
+ mutex_unlock(&fs210x->lock);
+ if (ret)
+ dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret);
+
+ return ret;
+}
+
+static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct fs210x_priv *fs210x;
+ unsigned long delay;
+
+ if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ fs210x = snd_soc_component_get_drvdata(dai->component);
+
+ mutex_lock(&fs210x->lock);
+
+ if (!fs210x->is_inited || fs210x->is_suspended) {
+ mutex_unlock(&fs210x->lock);
+ return 0;
+ }
+
+ mutex_unlock(&fs210x->lock);
+
+ if (mute) {
+ cancel_delayed_work_sync(&fs210x->fault_check_work);
+ cancel_delayed_work_sync(&fs210x->start_work);
+ } else {
+ delay = msecs_to_jiffies(fs210x->check_interval_ms);
+ schedule_delayed_work(&fs210x->fault_check_work, delay);
+ }
+
+ return 0;
+}
+
+static int fs210x_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct fs210x_priv *fs210x;
+
+ fs210x = snd_soc_component_get_drvdata(dai->component);
+
+ mutex_lock(&fs210x->lock);
+
+ if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) {
+ mutex_unlock(&fs210x->lock);
+ return 0;
+ }
+
+ mutex_unlock(&fs210x->lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /*
+ * According to the power up/down sequence of FS210x,
+ * it requests the I2S clock has been present
+ * and stable(>= 2ms) before playing.
+ */
+ schedule_delayed_work(&fs210x->start_work,
+ msecs_to_jiffies(FS210X_START_DELAY_MS));
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void fs210x_start_work(struct work_struct *work)
+{
+ struct fs210x_priv *fs210x;
+ int ret;
+
+ fs210x = container_of(work, struct fs210x_priv, start_work.work);
+
+ mutex_lock(&fs210x->lock);
+
+ ret = fs210x_dev_play(fs210x);
+ if (ret)
+ dev_err(fs210x->dev, "Failed to start playing: %d\n", ret);
+
+ mutex_unlock(&fs210x->lock);
+}
+
+static void fs210x_fault_check_work(struct work_struct *work)
+{
+ struct fs210x_priv *fs210x;
+ u16 status;
+ int ret;
+
+ fs210x = container_of(work, struct fs210x_priv, fault_check_work.work);
+
+ mutex_lock(&fs210x->lock);
+
+ if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) {
+ mutex_unlock(&fs210x->lock);
+ return;
+ }
+
+ ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status);
+ mutex_unlock(&fs210x->lock);
+ if (ret)
+ return;
+
+ if (!(status & FS210X_05H_PVDD_MASK))
+ dev_err(fs210x->dev, "PVDD fault\n");
+ if (status & FS210X_05H_OCDL_MASK)
+ dev_err(fs210x->dev, "OC detected\n");
+ if (status & FS210X_05H_UVDL_MASK)
+ dev_err(fs210x->dev, "UV detected\n");
+ if (status & FS210X_05H_OVDL_MASK)
+ dev_err(fs210x->dev, "OV detected\n");
+ if (status & FS210X_05H_OTPDL_MASK)
+ dev_err(fs210x->dev, "OT detected\n");
+ if (status & FS210X_05H_OCRDL_MASK)
+ dev_err(fs210x->dev, "OCR detected\n");
+ if (status & FS210X_05H_OCLDL_MASK)
+ dev_err(fs210x->dev, "OCL detected\n");
+ if (status & FS210X_05H_DCRDL_MASK)
+ dev_err(fs210x->dev, "DCR detected\n");
+ if (status & FS210X_05H_DCLDL_MASK)
+ dev_err(fs210x->dev, "DCL detected\n");
+ if (status & FS210X_05H_SRDL_MASK)
+ dev_err(fs210x->dev, "SR detected\n");
+ if (status & FS210X_05H_OTWDL_MASK)
+ dev_err(fs210x->dev, "OTW detected\n");
+ if (!(status & FS210X_05H_AMPS_MASK))
+ dev_dbg(fs210x->dev, "Amplifier unready\n");
+ if (!(status & FS210X_05H_PLLS_MASK))
+ dev_err(fs210x->dev, "PLL unlock\n");
+ if (!(status & FS210X_05H_ANAS_MASK))
+ dev_err(fs210x->dev, "Analog power fault\n");
+
+ schedule_delayed_work(&fs210x->fault_check_work,
+ msecs_to_jiffies(fs210x->check_interval_ms));
+}
+
+static int fs210x_get_drvdata_from_kctrl(struct snd_kcontrol *kctrl,
+ struct fs210x_priv **fs210x)
+{
+ struct snd_soc_component *cmpnt;
+
+ if (!kctrl) {
+ pr_err("fs210x: kcontrol is null\n");
+ return -EINVAL;
+ }
+
+ cmpnt = snd_kcontrol_chip(kctrl);
+ if (!cmpnt) {
+ pr_err("fs210x: component is null\n");
+ return -EINVAL;
+ }
+
+ *fs210x = snd_soc_component_get_drvdata(cmpnt);
+
+ return 0;
+}
+
+static int fs210x_effect_scene_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ const struct fs_amp_scene *scene;
+ struct fs210x_priv *fs210x;
+ const char *name = "N/A";
+ int idx, count;
+ int ret;
+
+ ret = fs210x_get_drvdata_from_kctrl(kcontrol, &fs210x);
+ if (ret || !fs210x->dev) {
+ pr_err("scene_effect_info: fs210x is null\n");
+ return -EINVAL;
+ }
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */
+ if (count < 1) {
+ uinfo->value.enumerated.items = 0;
+ return 0;
+ }
+
+ uinfo->value.enumerated.items = count;
+ if (uinfo->value.enumerated.item >= count)
+ uinfo->value.enumerated.item = count - 1;
+
+ idx = uinfo->value.enumerated.item;
+ scene = fs210x->amp_lib.scene + idx + 1;
+ if (scene->name)
+ name = scene->name;
+
+ strscpy(uinfo->value.enumerated.name, name, strlen(name) + 1);
+
+ return 0;
+}
+
+static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct fs210x_priv *fs210x;
+ int index;
+ int ret;
+
+ ret = fs210x_get_drvdata_from_kctrl(kcontrol, &fs210x);
+ if (ret || !fs210x->dev) {
+ pr_err("scene_effect_get: fs210x is null\n");
+ return -EINVAL;
+ }
+
+ /* The id of effect scene is from 1 to N. */
+ if (fs210x->scene_id < 1)
+ return -EINVAL;
+
+ mutex_lock(&fs210x->lock);
+ /*
+ * FS210x has scene(s) as below:
+ * init scene: id = 0
+ * effect scene(s): id = 1~N (optional)
+ * effect_index = scene_id - 1
+ */
+ index = fs210x->scene_id - 1;
+ ucontrol->value.integer.value[0] = index;
+ mutex_unlock(&fs210x->lock);
+
+ return 0;
+}
+
+static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct fs210x_priv *fs210x;
+ int scene_id, scene_count;
+ bool is_changed = false;
+ int ret;
+
+ ret = fs210x_get_drvdata_from_kctrl(kcontrol, &fs210x);
+ if (ret || !fs210x->dev) {
+ pr_err("scene_effect_put: fs210x is null\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&fs210x->lock);
+
+ /*
+ * FS210x has scene(s) as below:
+ * init scene: id = 0 (It's set in fs210x_init_chip() only)
+ * effect scene(s): id = 1~N (optional)
+ * scene_id = effect_index + 1.
+ */
+ scene_id = ucontrol->value.integer.value[0] + 1;
+ scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */
+ if (scene_id < 1 || scene_id > scene_count) {
+ mutex_unlock(&fs210x->lock);
+ return -ERANGE;
+ }
+
+ if (scene_id != fs210x->scene_id)
+ is_changed = true;
+
+ if (fs210x->is_suspended) {
+ fs210x->scene_id = scene_id;
+ mutex_unlock(&fs210x->lock);
+ return is_changed;
+ }
+
+ ret = fs210x_set_scene(fs210x, scene_id);
+ if (ret)
+ dev_err(fs210x->dev, "Failed to set scene: %d\n", ret);
+
+ mutex_unlock(&fs210x->lock);
+
+ if (!ret && is_changed)
+ return 1;
+
+ return ret;
+}
+
+static int fs210x_playback_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt);
+ int ret = 0;
+
+ mutex_lock(&fs210x->lock);
+
+ if (fs210x->is_suspended) {
+ mutex_unlock(&fs210x->lock);
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /*
+ * If there is no bclk for us to set the clock output,
+ * we will enable the device(start_work) in dai trigger.
+ */
+ if (!fs210x->clk_bclk)
+ break;
+ fs210x_bclk_set(fs210x, true);
+ ret = fs210x_dev_play(fs210x);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = fs210x_dev_stop(fs210x);
+ fs210x_bclk_set(fs210x, false);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&fs210x->lock);
+
+ return ret;
+}
+
+static const struct snd_soc_dai_ops fs210x_dai_ops = {
+ .startup = fs210x_dai_startup,
+ .set_fmt = fs210x_dai_set_fmt,
+ .hw_params = fs210x_dai_hw_params,
+ .mute_stream = fs210x_dai_mute,
+ .trigger = fs210x_dai_trigger,
+};
+
+static const struct snd_soc_dai_driver fs210x_dai = {
+ .name = FS210X_DEFAULT_DAI_NAME,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = FS210X_RATES,
+ .formats = FS210X_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = FS210X_RATES,
+ .formats = FS210X_FORMATS,
+ },
+ .ops = &fs210x_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static const DECLARE_TLV_DB_SCALE(fs2105s_vol_tlv, -9709, 19, 1);
+static const DECLARE_TLV_DB_SCALE(fs210x_vol_tlv, -13357, 19, 1);
+
+static const struct snd_kcontrol_new fs2105s_vol_control[] = {
+ SOC_DOUBLE_R_TLV("PCM Playback Volume",
+ FS210X_39H_LVOLCTRL, FS210X_3AH_RVOLCTRL,
+ 7, 0x1FF, 0, fs2105s_vol_tlv),
+};
+
+static const struct snd_kcontrol_new fs210x_vol_control[] = {
+ SOC_DOUBLE_R_TLV("PCM Playback Volume",
+ FS210X_39H_LVOLCTRL, FS210X_3AH_RVOLCTRL,
+ 6, 0x2BF, 0, fs210x_vol_tlv),
+};
+
+static const struct snd_kcontrol_new fs210x_controls[] = {
+ SOC_DOUBLE("DAC Mute Switch", FS210X_30H_DACCTRL, 4, 8, 1, 0),
+ SOC_DOUBLE("DAC Fade Switch", FS210X_30H_DACCTRL, 5, 9, 1, 0),
+};
+
+static const struct snd_kcontrol_new fs210x_scene_control[] = {
+ FS_SOC_ENUM_EXT("Effect Scene",
+ fs210x_effect_scene_info,
+ fs210x_effect_scene_get,
+ fs210x_effect_scene_put),
+};
+
+static const struct snd_soc_dapm_widget fs210x_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN_E("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0,
+ fs210x_playback_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUTL"),
+ SND_SOC_DAPM_OUTPUT("OUTR"),
+ SND_SOC_DAPM_INPUT("SDO"),
+};
+
+static const struct snd_soc_dapm_route fs210x_dapm_routes[] = {
+ { "OUTL", NULL, "AIF IN" },
+ { "OUTR", NULL, "AIF IN" },
+ { "AIF OUT", NULL, "SDO" },
+};
+
+static int fs210x_add_mixer_controls(struct fs210x_priv *fs210x,
+ struct snd_soc_component *cmpnt)
+{
+ const struct snd_kcontrol_new *kctrl;
+ int count;
+ int ret;
+
+ if (!fs210x || !cmpnt)
+ return -EINVAL;
+
+ if (fs210x->devid == FS2105S_DEVICE_ID) {
+ kctrl = fs2105s_vol_control;
+ count = ARRAY_SIZE(fs2105s_vol_control);
+ } else {
+ kctrl = fs210x_vol_control;
+ count = ARRAY_SIZE(fs210x_vol_control);
+ }
+
+ ret = snd_soc_add_component_controls(cmpnt, kctrl, count);
+ if (ret)
+ return ret;
+
+ /*
+ * If the firmware has no scene or only init scene,
+ * we skip adding this mixer control.
+ */
+ if (fs210x->amp_lib.scene_count < 2)
+ return 0;
+
+ kctrl = fs210x_scene_control;
+ count = ARRAY_SIZE(fs210x_scene_control);
+
+ return snd_soc_add_component_controls(cmpnt, kctrl, count);
+}
+
+static int fs210x_probe(struct snd_soc_component *cmpnt)
+{
+ struct fs210x_priv *fs210x;
+ int ret;
+
+ fs210x = snd_soc_component_get_drvdata(cmpnt);
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ fs210x->amp_lib.dev = fs210x->dev;
+ fs210x->amp_lib.devid = fs210x->devid;
+
+ ret = fs_amp_load_firmware(&fs210x->amp_lib, fs210x->pdata.fwm_name);
+ if (ret)
+ return ret;
+
+ ret = fs210x_add_mixer_controls(fs210x, cmpnt);
+ if (ret)
+ return ret;
+
+ mutex_lock(&fs210x->lock);
+ ret = fs210x_init_chip(fs210x);
+ mutex_unlock(&fs210x->lock);
+
+ return ret;
+}
+
+static void fs210x_remove(struct snd_soc_component *cmpnt)
+{
+ struct fs210x_priv *fs210x;
+
+ fs210x = snd_soc_component_get_drvdata(cmpnt);
+ if (!fs210x || !fs210x->dev)
+ return;
+
+ cancel_delayed_work_sync(&fs210x->start_work);
+ cancel_delayed_work_sync(&fs210x->fault_check_work);
+}
+
+#ifdef CONFIG_PM
+static int fs210x_suspend(struct snd_soc_component *cmpnt)
+{
+ struct fs210x_priv *fs210x;
+ int ret;
+
+ fs210x = snd_soc_component_get_drvdata(cmpnt);
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ regcache_cache_only(fs210x->regmap, true);
+
+ mutex_lock(&fs210x->lock);
+ fs210x->cur_scene = NULL;
+ fs210x->is_inited = false;
+ fs210x->is_playing = false;
+ fs210x->is_suspended = true;
+
+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */
+ fsleep(30000); /* >= 30ms */
+ mutex_unlock(&fs210x->lock);
+
+ cancel_delayed_work_sync(&fs210x->start_work);
+ cancel_delayed_work_sync(&fs210x->fault_check_work);
+
+ ret = regulator_bulk_disable(FS210X_NUM_SUPPLIES, fs210x->supplies);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to suspend: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fs210x_resume(struct snd_soc_component *cmpnt)
+{
+ struct fs210x_priv *fs210x;
+ int ret;
+
+ fs210x = snd_soc_component_get_drvdata(cmpnt);
+ if (!fs210x || !fs210x->dev)
+ return -EINVAL;
+
+ ret = regulator_bulk_enable(FS210X_NUM_SUPPLIES, fs210x->supplies);
+ if (ret) {
+ dev_err(fs210x->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ mutex_lock(&fs210x->lock);
+
+ fs210x->is_suspended = false;
+ ret = fs210x_init_chip(fs210x);
+
+ mutex_unlock(&fs210x->lock);
+
+ return ret;
+}
+#else
+#define fs210x_suspend NULL
+#define fs210x_resume NULL
+#endif // CONFIG_PM
+
+static bool fs210x_volatile_registers(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FS210X_00H_STATUS ... FS210X_0FH_I2CADDR:
+ case FS210X_ABH_INTSTAT:
+ case FS210X_ACH_INTSTATR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct snd_soc_component_driver fs210x_soc_component_dev = {
+ .probe = fs210x_probe,
+ .remove = fs210x_remove,
+ .suspend = fs210x_suspend,
+ .resume = fs210x_resume,
+ .controls = fs210x_controls,
+ .num_controls = ARRAY_SIZE(fs210x_controls),
+ .dapm_widgets = fs210x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(fs210x_dapm_widgets),
+ .dapm_routes = fs210x_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(fs210x_dapm_routes),
+};
+
+static const struct regmap_config fs210x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = FS210X_REG_MAX,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = fs210x_volatile_registers,
+};
+
+static int fs210x_detect_device(struct fs210x_priv *fs210x)
+{
+ u16 devid;
+ int ret;
+
+ ret = fs210x_reg_read(fs210x, FS210X_03H_DEVID, &devid);
+ if (ret)
+ return ret;
+
+ fs210x->devid = HI_U16(devid);
+
+ switch (fs210x->devid) {
+ case FS210X_DEVICE_ID:
+ dev_info(fs210x->dev, "FS2104 detected\n");
+ break;
+ case FS2105S_DEVICE_ID:
+ dev_info(fs210x->dev, "FS2105S detected\n");
+ break;
+ default:
+ dev_err(fs210x->dev, "DEVID: 0x%04X dismatch\n", devid);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int fs210x_parse_dts(struct fs210x_priv *fs210x,
+ struct fs210x_platform_data *pdata)
+{
+ struct device_node *node = fs210x->dev->of_node;
+ int i, ret;
+
+ if (!node)
+ return 0;
+
+ ret = of_property_read_string(node, "firmware-name", &pdata->fwm_name);
+ if (ret)
+ pdata->fwm_name = FS210X_DEFAULT_FWM_NAME;
+
+ fs210x->gpio_sdz = devm_gpiod_get_optional(fs210x->dev,
+ "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(fs210x->gpio_sdz))
+ return dev_err_probe(fs210x->dev, PTR_ERR(fs210x->gpio_sdz),
+ "Failed to get reset-gpios\n");
+
+ for (i = 0; i < FS210X_NUM_SUPPLIES; i++)
+ fs210x->supplies[i].supply = fs210x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(fs210x->dev,
+ ARRAY_SIZE(fs210x->supplies),
+ fs210x->supplies);
+ if (ret)
+ return dev_err_probe(fs210x->dev, ret,
+ "Failed to get supplies\n");
+
+ return 0;
+}
+
+static void fs210x_deinit(struct fs210x_priv *fs210x)
+{
+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */
+ fsleep(10000); /* >= 10ms */
+
+ regulator_bulk_disable(FS210X_NUM_SUPPLIES, fs210x->supplies);
+}
+
+static int fs210x_init(struct fs210x_priv *fs210x)
+{
+ int ret;
+
+ ret = fs210x_parse_dts(fs210x, &fs210x->pdata);
+ if (ret)
+ return ret;
+
+ fs210x->clk_bclk = devm_clk_get_optional(fs210x->dev, "bclk");
+ if (IS_ERR(fs210x->clk_bclk))
+ return dev_err_probe(fs210x->dev, PTR_ERR(fs210x->clk_bclk),
+ "Failed to get bclk\n");
+
+ ret = regulator_bulk_enable(FS210X_NUM_SUPPLIES, fs210x->supplies);
+ if (ret)
+ return dev_err_probe(fs210x->dev, ret,
+ "Failed to enable supplies\n");
+
+ /* Make sure the SDZ pin is pulled down enough time. */
+ fsleep(10000); /* >= 10ms */
+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 0); /* Deactivate */
+ fsleep(10000); /* >= 10ms */
+
+ ret = fs210x_detect_device(fs210x);
+ if (ret) {
+ fs210x_deinit(fs210x);
+ return ret;
+ }
+
+ fs210x->scene_id = -1; /* Invalid scene */
+ fs210x->cur_scene = NULL;
+ fs210x->is_playing = false;
+ fs210x->is_inited = false;
+ fs210x->is_suspended = false;
+ fs210x->check_interval_ms = FS210X_FAULT_CHECK_INTERVAL_MS;
+
+ INIT_DELAYED_WORK(&fs210x->fault_check_work, fs210x_fault_check_work);
+ INIT_DELAYED_WORK(&fs210x->start_work, fs210x_start_work);
+ mutex_init(&fs210x->lock);
+
+ return 0;
+}
+
+static int fs210x_register_snd_component(struct fs210x_priv *fs210x)
+{
+ struct snd_soc_dai_driver *dai_drv;
+ static int instance_id;
+ int ret;
+
+ dai_drv = devm_kmemdup(fs210x->dev, &fs210x_dai,
+ sizeof(fs210x_dai), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+
+ dai_drv->name = devm_kasprintf(fs210x->dev,
+ GFP_KERNEL, "%s-%d",
+ dai_drv->name, instance_id);
+ if (!dai_drv->name)
+ return -ENOMEM;
+
+ instance_id++;
+
+ if (fs210x->devid == FS2105S_DEVICE_ID) {
+ dai_drv->playback.rates = FS2105S_RATES;
+ dai_drv->capture.rates = FS2105S_RATES;
+ }
+
+ ret = snd_soc_register_component(fs210x->dev,
+ &fs210x_soc_component_dev,
+ dai_drv, 1);
+ return ret;
+}
+
+static ssize_t check_interval_ms_show(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct fs210x_priv *fs210x = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", fs210x->check_interval_ms);
+}
+
+static ssize_t check_interval_ms_store(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct fs210x_priv *fs210x = dev_get_drvdata(dev);
+ int ret;
+
+ ret = kstrtouint(buf, 10, &fs210x->check_interval_ms);
+ if (ret)
+ return -EINVAL;
+
+ return (ssize_t)count;
+}
+
+static DEVICE_ATTR_RW(check_interval_ms);
+
+static struct attribute *fs210x_attrs[] = {
+ &dev_attr_check_interval_ms.attr,
+ NULL,
+};
+
+static struct attribute_group fs210x_attr_group = {
+ .attrs = fs210x_attrs,
+};
+
+static int fs210x_i2c_probe(struct i2c_client *client)
+{
+ struct fs210x_priv *fs210x;
+ int ret;
+
+ fs210x = devm_kzalloc(&client->dev, sizeof(*fs210x), GFP_KERNEL);
+ if (!fs210x)
+ return -ENOMEM;
+
+ fs210x->i2c = client;
+ fs210x->dev = &client->dev;
+ i2c_set_clientdata(client, fs210x);
+
+ fs210x->regmap = devm_regmap_init_i2c(client, &fs210x_regmap);
+ if (IS_ERR(fs210x->regmap))
+ return dev_err_probe(fs210x->dev, PTR_ERR(fs210x->regmap),
+ "Failed to get regmap\n");
+
+ ret = fs210x_init(fs210x);
+ if (ret)
+ return ret;
+
+ ret = devm_device_add_group(fs210x->dev, &fs210x_attr_group);
+ if (ret) {
+ fs210x_deinit(fs210x);
+ return dev_err_probe(fs210x->dev, ret,
+ "Failed to create sysfs group\n");
+ }
+
+ ret = fs210x_register_snd_component(fs210x);
+ if (ret) {
+ fs210x_deinit(fs210x);
+ return dev_err_probe(fs210x->dev, ret,
+ "Failed to register component\n");
+ }
+
+ return 0;
+}
+
+static void fs210x_i2c_remove(struct i2c_client *client)
+{
+ struct fs210x_priv *fs210x = i2c_get_clientdata(client);
+
+ snd_soc_unregister_component(fs210x->dev);
+ fs210x_deinit(fs210x);
+}
+
+static const struct i2c_device_id fs210x_i2c_id[] = {
+ { "fs2104" },
+ { "fs2105s" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, fs210x_i2c_id);
+
+static const struct of_device_id fs210x_of_match[] = {
+ { .compatible = "foursemi,fs2105s", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fs210x_of_match);
+
+static struct i2c_driver fs210x_i2c_driver = {
+ .driver = {
+ .name = "fs210x",
+ .of_match_table = fs210x_of_match,
+ },
+ .id_table = fs210x_i2c_id,
+ .probe = fs210x_i2c_probe,
+ .remove = fs210x_i2c_remove,
+};
+
+module_i2c_driver(fs210x_i2c_driver);
+
+MODULE_AUTHOR("Nick Li <nick.li@foursemi.com>");
+MODULE_DESCRIPTION("FS2104/5S Audio Amplifier Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/fs210x.h b/sound/soc/codecs/fs210x.h
new file mode 100644
index 000000000000..78e1760332ca
--- /dev/null
+++ b/sound/soc/codecs/fs210x.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * fs210x.h -- Driver for the FS2104/5S Audio Amplifier
+ *
+ * Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd.
+ */
+
+#ifndef __FS210X_H__
+#define __FS210X_H__
+
+#define FS210X_00H_STATUS 0x00
+#define FS210X_03H_DEVID 0x03
+#define FS210X_05H_ANASTAT 0x05
+#define FS210X_06H_DIGSTAT 0x06
+#define FS210X_0BH_ACCKEY 0x0B
+#define FS210X_0FH_I2CADDR 0x0F
+#define FS210X_10H_PWRCTRL 0x10
+#define FS210X_11H_SYSCTRL 0x11
+#define FS210X_17H_I2SCTRL 0x17
+#define FS210X_30H_DACCTRL 0x30
+#define FS210X_39H_LVOLCTRL 0x39
+#define FS210X_3AH_RVOLCTRL 0x3A
+#define FS210X_42H_DACEQWL 0x42
+#define FS210X_46H_DACEQA 0x46
+#define FS210X_A1H_PLLCTRL1 0xA1
+#define FS210X_A2H_PLLCTRL2 0xA2
+#define FS210X_A3H_PLLCTRL3 0xA3
+#define FS210X_ABH_INTSTAT 0xAB
+#define FS210X_ACH_INTSTATR 0xAC
+
+#define FS210X_05H_PVDD_SHIFT 14
+#define FS210X_05H_PVDD_MASK BIT(14)
+#define FS210X_05H_OCDL_SHIFT 13
+#define FS210X_05H_OCDL_MASK BIT(13)
+#define FS210X_05H_UVDL_SHIFT 12
+#define FS210X_05H_UVDL_MASK BIT(12)
+#define FS210X_05H_OVDL_SHIFT 11
+#define FS210X_05H_OVDL_MASK BIT(11)
+#define FS210X_05H_OTPDL_SHIFT 10
+#define FS210X_05H_OTPDL_MASK BIT(10)
+#define FS210X_05H_OCRDL_SHIFT 9
+#define FS210X_05H_OCRDL_MASK BIT(9)
+#define FS210X_05H_OCLDL_SHIFT 8
+#define FS210X_05H_OCLDL_MASK BIT(8)
+#define FS210X_05H_DCRDL_SHIFT 7
+#define FS210X_05H_DCRDL_MASK BIT(7)
+#define FS210X_05H_DCLDL_SHIFT 6
+#define FS210X_05H_DCLDL_MASK BIT(6)
+#define FS210X_05H_SRDL_SHIFT 5
+#define FS210X_05H_SRDL_MASK BIT(5)
+#define FS210X_05H_OTWDL_SHIFT 4
+#define FS210X_05H_OTWDL_MASK BIT(4)
+#define FS210X_05H_AMPS_SHIFT 3
+#define FS210X_05H_AMPS_MASK BIT(3)
+#define FS210X_05H_PLLS_SHIFT 1
+#define FS210X_05H_PLLS_MASK BIT(1)
+#define FS210X_05H_ANAS_SHIFT 0
+#define FS210X_05H_ANAS_MASK BIT(0)
+#define FS210X_17H_I2SSR_SHIFT 12
+#define FS210X_17H_I2SSR_MASK GENMASK(15, 12)
+#define FS210X_30H_RMUTE_SHIFT 8
+#define FS210X_30H_LMUTE_SHIFT 4
+
+#define FS210X_0BH_ACCKEY_ON 0x0091
+#define FS210X_0BH_ACCKEY_OFF 0x0000
+#define FS210X_10H_I2C_RESET 0x0002
+#define FS210X_11H_DPS_HIZ 0x0100
+#define FS210X_11H_DPS_PWDN 0x0000
+#define FS210X_11H_DPS_PLAY 0x0300
+#define FS210X_46H_CAM_BURST_L 0x8000
+#define FS210X_46H_CAM_BURST_R 0x8200
+#define FS2105S_46H_CAM_BURST_W 0x8400
+#define FS210X_46H_CAM_CLEAR 0x0000
+
+#endif /* __FS210X_H__ */
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
index c6b1e77ffccd..1f165e46701f 100644
--- a/sound/soc/codecs/gtm601.c
+++ b/sound/soc/codecs/gtm601.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c
index 5371ff086261..b9caae7e4817 100644
--- a/sound/soc/codecs/hda-dai.c
+++ b/sound/soc/codecs/hda-dai.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -76,13 +76,16 @@ static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd
struct hdac_stream *stream;
struct hda_codec *codec;
unsigned int format;
+ unsigned int bits;
int ret;
codec = dev_to_hda_codec(dai->dev);
stream = substream->runtime->private_data;
stream_info = snd_soc_dai_get_dma_data(dai, substream);
- format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
- runtime->sample_bits, 0);
+
+ bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat,
+ stream_info->maxbps);
+ format = snd_hdac_stream_format(runtime->channels, bits, runtime->rate);
ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream);
if (ret < 0) {
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index d57b043d6bfe..237b0b060457 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -52,6 +52,7 @@ static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count,
stream->channels_max = pcm->stream[dir].channels_max;
stream->rates = pcm->stream[dir].rates;
stream->formats = pcm->stream[dir].formats;
+ stream->subformats = pcm->stream[dir].subformats;
stream->sig_bits = pcm->stream[dir].maxbps;
capture_dais:
@@ -71,6 +72,7 @@ capture_dais:
stream->channels_max = pcm->stream[dir].channels_max;
stream->rates = pcm->stream[dir].rates;
stream->formats = pcm->stream[dir].formats;
+ stream->subformats = pcm->stream[dir].subformats;
stream->sig_bits = pcm->stream[dir].maxbps;
}
@@ -94,7 +96,7 @@ static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_compo
if (ret < 0)
return ret;
- dapm = snd_soc_component_get_dapm(component);
+ dapm = snd_soc_component_to_dapm(component);
list_for_each_entry(pcm, &codec->pcm_list_head, list) {
struct snd_soc_dai *dai;
@@ -150,7 +152,7 @@ int hda_codec_probe_complete(struct hda_codec *codec)
ret = snd_hda_codec_build_controls(codec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to create controls %d\n", ret);
- goto out;
+ return ret;
}
/* Bus suspended codecs as it does not manage their pm */
@@ -158,9 +160,8 @@ int hda_codec_probe_complete(struct hda_codec *codec)
/* rpm was forbidden in snd_hda_codec_device_new() */
snd_hda_codec_set_power_save(codec, 2000);
snd_hda_codec_register(codec);
-out:
+
/* Complement pm_runtime_get_sync(bus) in probe */
- pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
return ret;
@@ -171,10 +172,10 @@ EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
static int hda_codec_probe(struct snd_soc_component *component)
{
struct hda_codec *codec = dev_to_hda_codec(component->dev);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hdac_device *hdev = &codec->core;
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink;
- hda_codec_patch_t patch;
int ret;
#ifdef CONFIG_PM
@@ -196,38 +197,36 @@ static int hda_codec_probe(struct snd_soc_component *component)
ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec,
false);
if (ret < 0) {
- dev_err(&hdev->dev, "create hda codec failed: %d\n", ret);
+ dev_err(&hdev->dev, "codec create failed: %d\n", ret);
goto device_new_err;
}
ret = snd_hda_codec_set_name(codec, codec->preset->name);
if (ret < 0) {
- dev_err(&hdev->dev, "name failed %s\n", codec->preset->name);
+ dev_err(&hdev->dev, "set name: %s failed: %d\n", codec->preset->name, ret);
goto err;
}
ret = snd_hdac_regmap_init(&codec->core);
if (ret < 0) {
- dev_err(&hdev->dev, "regmap init failed\n");
+ dev_err(&hdev->dev, "regmap init failed: %d\n", ret);
goto err;
}
- patch = (hda_codec_patch_t)codec->preset->driver_data;
- if (!patch) {
- dev_err(&hdev->dev, "no patch specified\n");
+ if (WARN_ON(!(driver->ops && driver->ops->probe))) {
ret = -EINVAL;
goto err;
}
- ret = patch(codec);
+ ret = driver->ops->probe(codec, codec->preset);
if (ret < 0) {
- dev_err(&hdev->dev, "patch failed %d\n", ret);
+ dev_err(&hdev->dev, "codec init failed: %d\n", ret);
goto err;
}
ret = snd_hda_codec_parse_pcms(codec);
if (ret < 0) {
- dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+ dev_err(&hdev->dev, "unable to map pcms to dai: %d\n", ret);
goto parse_pcms_err;
}
@@ -250,8 +249,8 @@ static int hda_codec_probe(struct snd_soc_component *component)
complete_err:
hda_codec_unregister_dais(codec, component);
parse_pcms_err:
- if (codec->patch_ops.free)
- codec->patch_ops.free(codec);
+ if (driver->ops->remove)
+ driver->ops->remove(codec);
err:
snd_hda_codec_cleanup_for_unbind(codec);
device_new_err:
@@ -260,7 +259,6 @@ device_new_err:
snd_hdac_ext_bus_link_put(bus, hlink);
- pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
return ret;
}
@@ -269,6 +267,7 @@ device_new_err:
static void hda_codec_remove(struct snd_soc_component *component)
{
struct hda_codec *codec = dev_to_hda_codec(component->dev);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hdac_device *hdev = &codec->core;
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink;
@@ -279,8 +278,8 @@ static void hda_codec_remove(struct snd_soc_component *component)
hda_codec_unregister_dais(codec, component);
- if (codec->patch_ops.free)
- codec->patch_ops.free(codec);
+ if (driver->ops->remove)
+ driver->ops->remove(codec);
snd_hda_codec_cleanup_for_unbind(codec);
pm_runtime_put_noidle(&hdev->dev);
@@ -298,7 +297,6 @@ static void hda_codec_remove(struct snd_soc_component *component)
* not be called due to early error, leaving bus uc unbalanced
*/
if (!was_registered) {
- pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
}
@@ -348,6 +346,11 @@ static int hda_hdev_attach(struct hdac_device *hdev)
struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
struct snd_soc_component_driver *comp_drv;
+ if (hda_codec_is_display(codec) && !hdev->bus->audio_component) {
+ dev_dbg(&hdev->dev, "no i915, skip registration for 0x%08x\n", hdev->vendor_id);
+ return -ENODEV;
+ }
+
comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL);
if (!comp_drv)
return -ENOMEM;
diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h
index 78a2be4945b1..59308cc6afef 100644
--- a/sound/soc/codecs/hda.h
+++ b/sound/soc/codecs/hda.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021-2022 Intel Corporation
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index be66853afbe2..680e341aa7f1 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -7,6 +7,7 @@
* codec drivers using hdac_ext_bus_ops ops.
*/
+#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -35,6 +36,13 @@
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
SNDRV_PCM_RATE_192000)
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+static char *loadable_patch[HDA_MAX_CODECS];
+
+module_param_array_named(patch, loadable_patch, charp, NULL, 0444);
+MODULE_PARM_DESC(patch, "Patch file array for Intel HD audio interface. The array index is the codec address.");
+#endif
+
static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
@@ -124,6 +132,9 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = {
.sig_bits = 24,
},
},
+};
+
+static struct snd_soc_dai_driver hdac_hda_hdmi_dais[] = {
{
.id = HDAC_HDMI_0_DAI_ID,
.name = "intel-hdmi-hifi1",
@@ -207,21 +218,20 @@ static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct hdac_hda_priv *hda_pvt;
unsigned int format_val;
unsigned int maxbps;
+ unsigned int bits;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
maxbps = dai->driver->playback.sig_bits;
else
maxbps = dai->driver->capture.sig_bits;
+ bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD, maxbps);
hda_pvt = snd_soc_component_get_drvdata(component);
- format_val = snd_hdac_calc_stream_format(params_rate(params),
- params_channels(params),
- params_format(params),
- maxbps,
- 0);
+ format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
if (!format_val) {
dev_err(dai->dev,
- "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n",
+ "%s: invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n",
+ __func__,
params_rate(params), params_channels(params),
params_format(params), maxbps);
@@ -257,14 +267,12 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct hda_pcm_stream *hda_stream;
struct hdac_hda_priv *hda_pvt;
- struct hdac_device *hdev;
unsigned int format_val;
struct hda_pcm *pcm;
unsigned int stream;
int ret = 0;
hda_pvt = snd_soc_component_get_drvdata(component);
- hdev = &hda_pvt->codec->core;
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
if (!pcm)
return -EINVAL;
@@ -277,7 +285,7 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
ret = snd_hda_codec_prepare(hda_pvt->codec, hda_stream,
stream, format_val, substream);
if (ret < 0)
- dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
+ dev_err(dai->dev, "%s: failed %d\n", __func__, ret);
return ret;
}
@@ -289,6 +297,7 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
struct hdac_hda_priv *hda_pvt;
struct hda_pcm_stream *hda_stream;
struct hda_pcm *pcm;
+ int ret;
hda_pvt = snd_soc_component_get_drvdata(component);
pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
@@ -299,7 +308,11 @@ static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
hda_stream = &pcm->stream[substream->stream];
- return hda_stream->ops.open(hda_stream, hda_pvt->codec, substream);
+ ret = hda_stream->ops.open(hda_stream, hda_pvt->codec, substream);
+ if (ret < 0)
+ dev_err(dai->dev, "%s: failed %d\n", __func__, ret);
+
+ return ret;
}
static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
@@ -358,7 +371,7 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
pcm_name = "HDMI 3";
break;
default:
- dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
+ dev_err(dai->dev, "%s: invalid dai id %d\n", __func__, dai->id);
return NULL;
}
@@ -372,7 +385,7 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
}
}
- dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
+ dev_err(dai->dev, "%s: didn't find PCM for DAI %s\n", __func__, dai->name);
return NULL;
}
@@ -392,17 +405,15 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
{
struct hdac_hda_priv *hda_pvt =
snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
struct hdac_device *hdev = &hda_pvt->codec->core;
struct hda_codec *hcodec = hda_pvt->codec;
+ struct hda_codec_driver *driver = hda_codec_to_driver(hcodec);
struct hdac_ext_link *hlink;
- hda_codec_patch_t patch;
int ret;
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&hdev->dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "%s: hdac link not found\n", __func__);
return -EIO;
}
@@ -420,9 +431,30 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
hdev->addr, hcodec, true);
if (ret < 0) {
- dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
+ dev_err(&hdev->dev, "%s: failed to create hda codec %d\n", __func__, ret);
goto error_no_pm;
}
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) {
+ const struct firmware *fw;
+
+ dev_info(&hdev->dev, "Applying patch firmware '%s'\n",
+ loadable_patch[hda_pvt->dev_index]);
+ ret = request_firmware(&fw, loadable_patch[hda_pvt->dev_index],
+ &hdev->dev);
+ if (ret < 0)
+ goto error_no_pm;
+ if (fw) {
+ ret = snd_hda_load_patch(hcodec->bus, fw->size, fw->data);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret);
+ goto error_no_pm;
+ }
+ release_firmware(fw);
+ }
+ }
+#endif
/*
* Overwrite type to HDA_DEV_ASOC since it is a ASoC driver
* hda_codec.c will check this flag to determine if unregister
@@ -436,34 +468,34 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
*/
pm_runtime_get_noresume(&hdev->dev);
- hcodec->bus->card = dapm->card->snd_card;
+ hcodec->bus->card = component->card->snd_card;
ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
if (ret < 0) {
- dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
+ dev_err(&hdev->dev, "%s: name failed %s\n", __func__, hcodec->preset->name);
goto error_pm;
}
ret = snd_hdac_regmap_init(&hcodec->core);
if (ret < 0) {
- dev_err(&hdev->dev, "regmap init failed\n");
+ dev_err(&hdev->dev, "%s: regmap init failed\n", __func__);
goto error_pm;
}
- patch = (hda_codec_patch_t)hcodec->preset->driver_data;
- if (patch) {
- ret = patch(hcodec);
- if (ret < 0) {
- dev_err(&hdev->dev, "patch failed %d\n", ret);
- goto error_regmap;
- }
- } else {
- dev_dbg(&hdev->dev, "no patch file found\n");
+ if (WARN_ON(!(driver->ops && driver->ops->probe))) {
+ ret = -EINVAL;
+ goto error_regmap;
+ }
+
+ ret = driver->ops->probe(hcodec, hcodec->preset);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret);
+ goto error_regmap;
}
ret = snd_hda_codec_parse_pcms(hcodec);
if (ret < 0) {
- dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+ dev_err(&hdev->dev, "%s: unable to map pcms to dai %d\n", __func__, ret);
goto error_patch;
}
@@ -471,8 +503,8 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
if (!is_hdmi_codec(hcodec)) {
ret = snd_hda_codec_build_controls(hcodec);
if (ret < 0) {
- dev_err(&hdev->dev, "unable to create controls %d\n",
- ret);
+ dev_err(&hdev->dev, "%s: unable to create controls %d\n",
+ __func__, ret);
goto error_patch;
}
}
@@ -497,8 +529,8 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
return 0;
error_patch:
- if (hcodec->patch_ops.free)
- hcodec->patch_ops.free(hcodec);
+ if (driver->ops->remove)
+ driver->ops->remove(hcodec);
error_regmap:
snd_hdac_regmap_exit(hdev);
error_pm:
@@ -514,19 +546,20 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
snd_soc_component_get_drvdata(component);
struct hdac_device *hdev = &hda_pvt->codec->core;
struct hda_codec *codec = hda_pvt->codec;
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hdac_ext_link *hlink = NULL;
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&hdev->dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "%s: hdac link not found\n", __func__);
return;
}
pm_runtime_disable(&hdev->dev);
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
- if (codec->patch_ops.free)
- codec->patch_ops.free(codec);
+ if (driver->ops->remove)
+ driver->ops->remove(codec);
snd_hda_codec_cleanup_for_unbind(codec);
}
@@ -578,25 +611,39 @@ static const struct snd_soc_component_driver hdac_hda_codec = {
.endianness = 1,
};
+static const struct snd_soc_component_driver hdac_hda_hdmi_codec = {
+ .probe = hdac_hda_codec_probe,
+ .remove = hdac_hda_codec_remove,
+ .idle_bias_on = false,
+ .endianness = 1,
+};
+
static int hdac_hda_dev_probe(struct hdac_device *hdev)
{
+ struct hdac_hda_priv *hda_pvt = dev_get_drvdata(&hdev->dev);
struct hdac_ext_link *hlink;
int ret;
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&hdev->dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "%s: hdac link not found\n", __func__);
return -EIO;
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
/* ASoC specific initialization */
- ret = devm_snd_soc_register_component(&hdev->dev,
- &hdac_hda_codec, hdac_hda_dais,
- ARRAY_SIZE(hdac_hda_dais));
+ if (hda_pvt->need_display_power)
+ ret = devm_snd_soc_register_component(&hdev->dev,
+ &hdac_hda_hdmi_codec, hdac_hda_hdmi_dais,
+ ARRAY_SIZE(hdac_hda_hdmi_dais));
+ else
+ ret = devm_snd_soc_register_component(&hdev->dev,
+ &hdac_hda_codec, hdac_hda_dais,
+ ARRAY_SIZE(hdac_hda_dais));
+
if (ret < 0) {
- dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
+ dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret);
return ret;
}
diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h
index b65560981abb..d03a5d4e7288 100644
--- a/sound/soc/codecs/hdac_hda.h
+++ b/sound/soc/codecs/hdac_hda.h
@@ -26,6 +26,7 @@ struct hdac_hda_priv {
struct hda_codec *codec;
struct hdac_hda_pcm pcm[HDAC_DAI_ID_NUM];
bool need_display_power;
+ int dev_index;
};
struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void);
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 8b6b76029694..2652fcf2a3a3 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/hdmi.h>
#include <drm/drm_edid.h>
+#include <drm/drm_eld.h>
#include <sound/pcm_params.h>
#include <sound/jack.h>
#include <sound/soc.h>
@@ -23,8 +24,6 @@
#include <sound/hda_i915.h>
#include <sound/pcm_drm_eld.h>
#include <sound/hda_chmap.h>
-#include "../../hda/local.h"
-#include "hdac_hdmi.h"
#define NAME_SIZE 32
@@ -220,8 +219,8 @@ static int hdac_hdmi_get_port_len(struct hdac_device *hdev, hda_nid_t nid)
unsigned int caps;
unsigned int type, param;
- caps = get_wcaps(hdev, nid);
- type = get_wcaps_type(caps);
+ caps = snd_hdac_get_wcaps(hdev, nid);
+ type = snd_hdac_get_wcaps_type(caps);
if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
return 0;
@@ -468,13 +467,14 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_pcm *pcm;
+ unsigned int bits;
int format;
dai_map = &hdmi->dai_map[dai->id];
- format = snd_hdac_calc_stream_format(params_rate(hparams),
- params_channels(hparams), params_format(hparams),
- dai->driver->playback.sig_bits, 0);
+ bits = snd_hdac_stream_format_bits(params_format(hparams), SNDRV_PCM_SUBFORMAT_STD,
+ dai->driver->playback.sig_bits);
+ format = snd_hdac_stream_format(params_channels(hparams), bits, params_rate(hparams));
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
if (!pcm)
@@ -490,10 +490,10 @@ static int hdac_hdmi_query_port_connlist(struct hdac_device *hdev,
struct hdac_hdmi_pin *pin,
struct hdac_hdmi_port *port)
{
- if (!(get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
+ if (!(snd_hdac_get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
dev_warn(&hdev->dev,
"HDMI: pin %d wcaps %#x does not support connection list\n",
- pin->nid, get_wcaps(hdev, pin->nid));
+ pin->nid, snd_hdac_get_wcaps(hdev, pin->nid));
return -EINVAL;
}
@@ -658,8 +658,8 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
int err;
- chans = get_wcaps(hdev, cvt->nid);
- chans = get_wcaps_channels(chans);
+ chans = snd_hdac_get_wcaps(hdev, cvt->nid);
+ chans = snd_hdac_get_wcaps_channels(chans);
cvt->params.channels_min = 2;
@@ -670,6 +670,7 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
err = snd_hdac_query_supported_pcm(hdev, cvt->nid,
&cvt->params.rates,
&cvt->params.formats,
+ NULL,
&cvt->params.maxbps);
if (err < 0)
dev_err(&hdev->dev,
@@ -740,7 +741,7 @@ static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
int count;
unsigned int state;
- if (get_wcaps(hdev, nid) & AC_WCAP_POWER) {
+ if (snd_hdac_get_wcaps(hdev, nid) & AC_WCAP_POWER) {
if (!snd_hdac_check_power_state(hdev, nid, pwr_state)) {
for (count = 0; count < 10; count++) {
snd_hdac_codec_read(hdev, nid, 0,
@@ -758,7 +759,7 @@ static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
static void hdac_hdmi_set_amp(struct hdac_device *hdev,
hda_nid_t nid, int val)
{
- if (get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
+ if (snd_hdac_get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
snd_hdac_codec_write(hdev, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, val);
}
@@ -768,7 +769,8 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kc, int event)
{
struct hdac_hdmi_port *port = w->priv;
- struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_hdmi_pcm *pcm;
dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
@@ -813,7 +815,8 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kc, int event)
{
struct hdac_hdmi_cvt *cvt = w->priv;
- struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm;
@@ -868,7 +871,8 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kc, int event)
{
struct hdac_hdmi_port *port = w->priv;
- struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
int mux_idx;
dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
@@ -877,7 +881,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
if (!kc)
kc = w->kcontrols[0];
- mux_idx = dapm_kcontrol_get_value(kc);
+ mux_idx = snd_soc_dapm_kcontrol_get_value(kc);
/* set the device if pin is mst_capable */
if (hdac_hdmi_port_select_set(hdev, port) < 0)
@@ -900,10 +904,11 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
int ret;
struct hdac_hdmi_port *p, *p_next;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_dapm_context *dapm = w->dapm;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct hdac_hdmi_port *port = w->priv;
- struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm;
const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
@@ -1014,8 +1019,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;
@@ -1070,9 +1074,11 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_device *hdev,
*/
static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct snd_soc_dapm_widget *widgets;
struct snd_soc_dapm_route *route;
- struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct snd_soc_dai_driver *dai_drv = hdmi->dai_drv;
char widget_name[NAME_SIZE];
@@ -1083,7 +1089,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
return -EINVAL;
- widgets = devm_kzalloc(dapm->dev, (sizeof(*widgets) *
+ widgets = devm_kzalloc(dev, (sizeof(*widgets) *
((2 * hdmi->num_ports) + hdmi->num_cvt)),
GFP_KERNEL);
@@ -1093,7 +1099,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
/* DAPM widgets to represent each converter widget */
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
sprintf(widget_name, "Converter %d", cvt->nid);
- ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+ ret = hdac_hdmi_fill_widget_info(dev, &widgets[i],
snd_soc_dapm_aif_in, cvt,
widget_name, dai_drv[i].playback.stream_name, NULL, 0,
hdac_hdmi_cvt_output_widget_event,
@@ -1107,7 +1113,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
for (j = 0; j < pin->num_ports; j++) {
sprintf(widget_name, "hif%d-%d Output",
pin->nid, pin->ports[j].id);
- ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+ ret = hdac_hdmi_fill_widget_info(dev, &widgets[i],
snd_soc_dapm_output, &pin->ports[j],
widget_name, NULL, NULL, 0,
hdac_hdmi_pin_output_widget_event,
@@ -1140,7 +1146,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
}
}
- route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
+ route = devm_kzalloc(dev, (sizeof(*route) * num_routes),
GFP_KERNEL);
if (!route)
return -ENOMEM;
@@ -1166,7 +1172,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
((2 * hdmi->num_ports) + hdmi->num_cvt));
snd_soc_dapm_add_routes(dapm, route, num_routes);
- snd_soc_dapm_new_widgets(dapm->card);
+ snd_soc_dapm_new_widgets(card);
return 0;
@@ -1230,7 +1236,8 @@ static int hdac_hdmi_parse_eld(struct hdac_device *hdev,
>> DRM_ELD_VER_SHIFT;
if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
- dev_err(&hdev->dev, "HDMI: Unknown ELD version %d\n", ver);
+ dev_err_ratelimited(&hdev->dev,
+ "HDMI: Unknown ELD version %d\n", ver);
return -EINVAL;
}
@@ -1238,7 +1245,8 @@ static int hdac_hdmi_parse_eld(struct hdac_device *hdev,
DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
if (mnl > ELD_MAX_MNL) {
- dev_err(&hdev->dev, "HDMI: MNL Invalid %d\n", mnl);
+ dev_err_ratelimited(&hdev->dev,
+ "HDMI: MNL Invalid %d\n", mnl);
return -EINVAL;
}
@@ -1297,8 +1305,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_err(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
- __func__, pin->nid, port->id);
+ dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
+ __func__, pin->nid, port->id);
/*
* PCMs are not registered during device probe, so don't
@@ -1429,122 +1437,6 @@ static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev)
}
-static int hdac_hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
- struct hdac_hdmi_pcm *pcm;
- struct hdac_hdmi_port *port;
- struct hdac_hdmi_eld *eld;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- uinfo->count = 0;
-
- pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device);
- if (!pcm) {
- dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__,
- kcontrol->id.device);
- return 0;
- }
-
- if (list_empty(&pcm->port_list)) {
- dev_dbg(component->dev, "%s: empty port list, device %d\n",
- __func__, kcontrol->id.device);
- return 0;
- }
-
- mutex_lock(&hdmi->pin_mutex);
-
- list_for_each_entry(port, &pcm->port_list, head) {
- eld = &port->eld;
-
- if (eld->eld_valid) {
- uinfo->count = eld->eld_size;
- break;
- }
- }
-
- mutex_unlock(&hdmi->pin_mutex);
-
- return 0;
-}
-
-static int hdac_hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
- struct hdac_hdmi_pcm *pcm;
- struct hdac_hdmi_port *port;
- struct hdac_hdmi_eld *eld;
-
- memset(ucontrol->value.bytes.data, 0, sizeof(ucontrol->value.bytes.data));
-
- pcm = get_hdmi_pcm_from_id(hdmi, kcontrol->id.device);
- if (!pcm) {
- dev_dbg(component->dev, "%s: no pcm, device %d\n", __func__,
- kcontrol->id.device);
- return 0;
- }
-
- if (list_empty(&pcm->port_list)) {
- dev_dbg(component->dev, "%s: empty port list, device %d\n",
- __func__, kcontrol->id.device);
- return 0;
- }
-
- mutex_lock(&hdmi->pin_mutex);
-
- list_for_each_entry(port, &pcm->port_list, head) {
- eld = &port->eld;
-
- if (!eld->eld_valid)
- continue;
-
- if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
- eld->eld_size > ELD_MAX_SIZE) {
- mutex_unlock(&hdmi->pin_mutex);
-
- dev_err(component->dev, "%s: buffer too small, device %d eld_size %d\n",
- __func__, kcontrol->id.device, eld->eld_size);
- snd_BUG();
- return -EINVAL;
- }
-
- memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
- eld->eld_size);
- break;
- }
-
- mutex_unlock(&hdmi->pin_mutex);
-
- return 0;
-}
-
-static int hdac_hdmi_create_eld_ctl(struct snd_soc_component *component, struct hdac_hdmi_pcm *pcm)
-{
- struct snd_kcontrol *kctl;
- struct snd_kcontrol_new hdmi_eld_ctl = {
- .access = SNDRV_CTL_ELEM_ACCESS_READ |
- SNDRV_CTL_ELEM_ACCESS_VOLATILE,
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "ELD",
- .info = hdac_hdmi_eld_ctl_info,
- .get = hdac_hdmi_eld_ctl_get,
- .device = pcm->pcm_id,
- };
-
- /* add ELD ctl with the device number corresponding to the PCM stream */
- kctl = snd_ctl_new1(&hdmi_eld_ctl, component);
- if (!kctl)
- return -ENOMEM;
-
- pcm->eld_ctl = kctl;
-
- return snd_ctl_add(component->card->snd_card, kctl);
-}
-
static const struct snd_soc_dai_ops hdmi_dai_ops = {
.startup = hdac_hdmi_pcm_open,
.shutdown = hdac_hdmi_pcm_close,
@@ -1577,7 +1469,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
ret = snd_hdac_query_supported_pcm(hdev, cvt->nid,
- &rates, &formats, &bps);
+ &rates, &formats, NULL, &bps);
if (ret)
return ret;
@@ -1646,8 +1538,8 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
unsigned int caps;
unsigned int type;
- caps = get_wcaps(hdev, nid);
- type = get_wcaps_type(caps);
+ caps = snd_hdac_get_wcaps(hdev, nid);
+ type = snd_hdac_get_wcaps_type(caps);
if (!(caps & AC_WCAP_DIGITAL))
continue;
@@ -1752,187 +1644,6 @@ static struct drm_audio_component_audio_ops aops = {
.pin_eld_notify = hdac_hdmi_eld_notify_cb,
};
-static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
- int device)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- for_each_card_rtds(card, rtd) {
- if (rtd->pcm && (rtd->pcm->device == device))
- return rtd->pcm;
- }
-
- return NULL;
-}
-
-/* create jack pin kcontrols */
-static int create_fill_jack_kcontrols(struct snd_soc_card *card,
- struct hdac_device *hdev)
-{
- struct hdac_hdmi_pin *pin;
- struct snd_kcontrol_new *kc;
- char kc_name[NAME_SIZE], xname[NAME_SIZE];
- char *name;
- int i = 0, j;
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
- struct snd_soc_component *component = hdmi->component;
-
- kc = devm_kcalloc(component->dev, hdmi->num_ports,
- sizeof(*kc), GFP_KERNEL);
-
- if (!kc)
- return -ENOMEM;
-
- list_for_each_entry(pin, &hdmi->pin_list, head) {
- for (j = 0; j < pin->num_ports; j++) {
- snprintf(xname, sizeof(xname), "hif%d-%d Jack",
- pin->nid, pin->ports[j].id);
- name = devm_kstrdup(component->dev, xname, GFP_KERNEL);
- if (!name)
- return -ENOMEM;
- snprintf(kc_name, sizeof(kc_name), "%s Switch", xname);
- kc[i].name = devm_kstrdup(component->dev, kc_name,
- GFP_KERNEL);
- if (!kc[i].name)
- return -ENOMEM;
-
- kc[i].private_value = (unsigned long)name;
- kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc[i].access = 0;
- kc[i].info = snd_soc_dapm_info_pin_switch;
- kc[i].put = snd_soc_dapm_put_pin_switch;
- kc[i].get = snd_soc_dapm_get_pin_switch;
- i++;
- }
- }
-
- return snd_soc_add_card_controls(card, kc, i);
-}
-
-int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
- struct snd_soc_dapm_context *dapm)
-{
- struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
- struct hdac_device *hdev = hdmi->hdev;
- struct hdac_hdmi_pin *pin;
- struct snd_soc_dapm_widget *widgets;
- struct snd_soc_dapm_route *route;
- char w_name[NAME_SIZE];
- int i = 0, j, ret;
-
- widgets = devm_kcalloc(dapm->dev, hdmi->num_ports,
- sizeof(*widgets), GFP_KERNEL);
-
- if (!widgets)
- return -ENOMEM;
-
- route = devm_kcalloc(dapm->dev, hdmi->num_ports,
- sizeof(*route), GFP_KERNEL);
- if (!route)
- return -ENOMEM;
-
- /* create Jack DAPM widget */
- list_for_each_entry(pin, &hdmi->pin_list, head) {
- for (j = 0; j < pin->num_ports; j++) {
- snprintf(w_name, sizeof(w_name), "hif%d-%d Jack",
- pin->nid, pin->ports[j].id);
-
- ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
- snd_soc_dapm_spk, NULL,
- w_name, NULL, NULL, 0, NULL, 0);
- if (ret < 0)
- return ret;
-
- pin->ports[j].jack_pin = widgets[i].name;
- pin->ports[j].dapm = dapm;
-
- /* add to route from Jack widget to output */
- hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin,
- NULL, pin->ports[j].output_pin, NULL);
-
- i++;
- }
- }
-
- /* Add Route from Jack widget to the output widget */
- ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dapm_new_widgets(dapm->card);
- if (ret < 0)
- return ret;
-
- /* Add Jack Pin switch Kcontrol */
- ret = create_fill_jack_kcontrols(dapm->card, hdev);
-
- if (ret < 0)
- return ret;
-
- /* default set the Jack Pin switch to OFF */
- list_for_each_entry(pin, &hdmi->pin_list, head) {
- for (j = 0; j < pin->num_ports; j++)
- snd_soc_dapm_disable_pin(pin->ports[j].dapm,
- pin->ports[j].jack_pin);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init);
-
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
- struct snd_soc_jack *jack)
-{
- struct snd_soc_component *component = dai->component;
- struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
- struct hdac_device *hdev = hdmi->hdev;
- struct hdac_hdmi_pcm *pcm;
- struct snd_pcm *snd_pcm;
- int err;
-
- /*
- * this is a new PCM device, create new pcm and
- * add to the pcm list
- */
- pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
- pcm->pcm_id = device;
- pcm->cvt = hdmi->dai_map[dai->id].cvt;
- pcm->jack_event = 0;
- pcm->jack = jack;
- mutex_init(&pcm->lock);
- INIT_LIST_HEAD(&pcm->port_list);
- snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
- if (snd_pcm) {
- err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
- if (err < 0) {
- dev_err(&hdev->dev,
- "chmap control add failed with err: %d for pcm: %d\n",
- err, device);
- return err;
- }
- }
-
- /* add control for ELD Bytes */
- err = hdac_hdmi_create_eld_ctl(component, pcm);
- if (err < 0) {
- dev_err(&hdev->dev,
- "eld control add failed with err: %d for pcm: %d\n",
- err, device);
- return err;
- }
-
- list_add_tail(&pcm->head, &hdmi->pcm_list);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
-
static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev,
struct hdac_hdmi_priv *hdmi, bool detect_pin_caps)
{
@@ -1961,8 +1672,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
{
struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
struct hdac_device *hdev = hdmi->hdev;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct hdac_ext_link *hlink;
int ret;
@@ -1993,7 +1703,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
hdac_hdmi_present_sense_all_pins(hdev, hdmi, true);
/* Imp: Store the card pointer in hda_codec */
- hdmi->card = dapm->card->snd_card;
+ hdmi->card = component->card->snd_card;
/*
* Setup a device_link between card device and HDMI codec device.
@@ -2031,7 +1741,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);
@@ -2054,9 +1763,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,
@@ -2226,7 +1932,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);
@@ -2295,14 +2000,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[] = {
@@ -2321,7 +2022,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/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
deleted file mode 100644
index 493fa3b4ef75..000000000000
--- a/sound/soc/codecs/hdac_hdmi.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __HDAC_HDMI_H__
-#define __HDAC_HDMI_H__
-
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
- struct snd_soc_jack *jack);
-
-int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
- struct snd_soc_dapm_context *dapm);
-#endif /* __HDAC_HDMI_H__ */
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 6d980fbc4207..13ae9e83bc21 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -17,6 +17,7 @@
#include <sound/pcm_iec958.h>
#include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
+#include <drm/drm_eld.h>
#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1
@@ -184,89 +185,103 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
/*
* hdmi_codec_channel_alloc: speaker configuration available for CEA
*
- * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct
+ * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps
* The preceding ones have better chances to be selected by
* hdmi_codec_get_ch_alloc_table_idx().
*/
static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
{ .ca_id = 0x00, .n_ch = 2,
- .mask = FL | FR},
- /* 2.1 */
- { .ca_id = 0x01, .n_ch = 4,
- .mask = FL | FR | LFE},
- /* Dolby Surround */
+ .mask = FL | FR },
+ { .ca_id = 0x03, .n_ch = 4,
+ .mask = FL | FR | LFE | FC },
{ .ca_id = 0x02, .n_ch = 4,
.mask = FL | FR | FC },
- /* surround51 */
+ { .ca_id = 0x01, .n_ch = 4,
+ .mask = FL | FR | LFE },
{ .ca_id = 0x0b, .n_ch = 6,
- .mask = FL | FR | LFE | FC | RL | RR},
- /* surround40 */
- { .ca_id = 0x08, .n_ch = 6,
- .mask = FL | FR | RL | RR },
- /* surround41 */
- { .ca_id = 0x09, .n_ch = 6,
- .mask = FL | FR | LFE | RL | RR },
- /* surround50 */
+ .mask = FL | FR | LFE | FC | RL | RR },
{ .ca_id = 0x0a, .n_ch = 6,
.mask = FL | FR | FC | RL | RR },
- /* 6.1 */
- { .ca_id = 0x0f, .n_ch = 8,
- .mask = FL | FR | LFE | FC | RL | RR | RC },
- /* surround71 */
+ { .ca_id = 0x09, .n_ch = 6,
+ .mask = FL | FR | LFE | RL | RR },
+ { .ca_id = 0x08, .n_ch = 6,
+ .mask = FL | FR | RL | RR },
+ { .ca_id = 0x07, .n_ch = 6,
+ .mask = FL | FR | LFE | FC | RC },
+ { .ca_id = 0x06, .n_ch = 6,
+ .mask = FL | FR | FC | RC },
+ { .ca_id = 0x05, .n_ch = 6,
+ .mask = FL | FR | LFE | RC },
+ { .ca_id = 0x04, .n_ch = 6,
+ .mask = FL | FR | RC },
{ .ca_id = 0x13, .n_ch = 8,
.mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
- /* others */
- { .ca_id = 0x03, .n_ch = 8,
- .mask = FL | FR | LFE | FC },
- { .ca_id = 0x04, .n_ch = 8,
- .mask = FL | FR | RC},
- { .ca_id = 0x05, .n_ch = 8,
- .mask = FL | FR | LFE | RC },
- { .ca_id = 0x06, .n_ch = 8,
- .mask = FL | FR | FC | RC },
- { .ca_id = 0x07, .n_ch = 8,
- .mask = FL | FR | LFE | FC | RC },
- { .ca_id = 0x0c, .n_ch = 8,
- .mask = FL | FR | RC | RL | RR },
- { .ca_id = 0x0d, .n_ch = 8,
- .mask = FL | FR | LFE | RL | RR | RC },
- { .ca_id = 0x0e, .n_ch = 8,
- .mask = FL | FR | FC | RL | RR | RC },
- { .ca_id = 0x10, .n_ch = 8,
- .mask = FL | FR | RL | RR | RLC | RRC },
- { .ca_id = 0x11, .n_ch = 8,
- .mask = FL | FR | LFE | RL | RR | RLC | RRC },
+ { .ca_id = 0x1f, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
{ .ca_id = 0x12, .n_ch = 8,
.mask = FL | FR | FC | RL | RR | RLC | RRC },
- { .ca_id = 0x14, .n_ch = 8,
- .mask = FL | FR | FLC | FRC },
- { .ca_id = 0x15, .n_ch = 8,
- .mask = FL | FR | LFE | FLC | FRC },
- { .ca_id = 0x16, .n_ch = 8,
- .mask = FL | FR | FC | FLC | FRC },
- { .ca_id = 0x17, .n_ch = 8,
- .mask = FL | FR | LFE | FC | FLC | FRC },
- { .ca_id = 0x18, .n_ch = 8,
- .mask = FL | FR | RC | FLC | FRC },
- { .ca_id = 0x19, .n_ch = 8,
- .mask = FL | FR | LFE | RC | FLC | FRC },
- { .ca_id = 0x1a, .n_ch = 8,
- .mask = FL | FR | RC | FC | FLC | FRC },
- { .ca_id = 0x1b, .n_ch = 8,
- .mask = FL | FR | LFE | RC | FC | FLC | FRC },
- { .ca_id = 0x1c, .n_ch = 8,
- .mask = FL | FR | RL | RR | FLC | FRC },
- { .ca_id = 0x1d, .n_ch = 8,
- .mask = FL | FR | LFE | RL | RR | FLC | FRC },
{ .ca_id = 0x1e, .n_ch = 8,
.mask = FL | FR | FC | RL | RR | FLC | FRC },
- { .ca_id = 0x1f, .n_ch = 8,
- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
+ { .ca_id = 0x11, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | RLC | RRC },
+ { .ca_id = 0x1d, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | FLC | FRC },
+ { .ca_id = 0x10, .n_ch = 8,
+ .mask = FL | FR | RL | RR | RLC | RRC },
+ { .ca_id = 0x1c, .n_ch = 8,
+ .mask = FL | FR | RL | RR | FLC | FRC },
+ { .ca_id = 0x0f, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | RC },
+ { .ca_id = 0x1b, .n_ch = 8,
+ .mask = FL | FR | LFE | RC | FC | FLC | FRC },
+ { .ca_id = 0x0e, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR | RC },
+ { .ca_id = 0x1a, .n_ch = 8,
+ .mask = FL | FR | RC | FC | FLC | FRC },
+ { .ca_id = 0x0d, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | RC },
+ { .ca_id = 0x19, .n_ch = 8,
+ .mask = FL | FR | LFE | RC | FLC | FRC },
+ { .ca_id = 0x0c, .n_ch = 8,
+ .mask = FL | FR | RC | RL | RR },
+ { .ca_id = 0x18, .n_ch = 8,
+ .mask = FL | FR | RC | FLC | FRC },
+ { .ca_id = 0x17, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | FLC | FRC },
+ { .ca_id = 0x16, .n_ch = 8,
+ .mask = FL | FR | FC | FLC | FRC },
+ { .ca_id = 0x15, .n_ch = 8,
+ .mask = FL | FR | LFE | FLC | FRC },
+ { .ca_id = 0x14, .n_ch = 8,
+ .mask = FL | FR | FLC | FRC },
+ { .ca_id = 0x0b, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR },
+ { .ca_id = 0x0a, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR },
+ { .ca_id = 0x09, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR },
+ { .ca_id = 0x08, .n_ch = 8,
+ .mask = FL | FR | RL | RR },
+ { .ca_id = 0x07, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RC },
+ { .ca_id = 0x06, .n_ch = 8,
+ .mask = FL | FR | FC | RC },
+ { .ca_id = 0x05, .n_ch = 8,
+ .mask = FL | FR | LFE | RC },
+ { .ca_id = 0x04, .n_ch = 8,
+ .mask = FL | FR | RC },
+ { .ca_id = 0x03, .n_ch = 8,
+ .mask = FL | FR | LFE | FC },
+ { .ca_id = 0x02, .n_ch = 8,
+ .mask = FL | FR | FC },
+ { .ca_id = 0x01, .n_ch = 8,
+ .mask = FL | FR | LFE },
};
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;
@@ -274,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[] = {
@@ -370,7 +386,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
struct hdmi_codec_priv *hcp = info->private_data;
- map = info->chmap[hcp->chmap_idx].map;
+ if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN)
+ map = info->chmap[hcp->chmap_idx].map;
for (i = 0; i < info->max_channels; i++) {
if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN)
@@ -454,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;
@@ -495,31 +515,46 @@ static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
struct hdmi_codec_params *hp)
{
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
- int idx;
+ int idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+ u8 ca_id = 0;
+ bool pcm_audio = !(hcp->iec_status[0] & IEC958_AES0_NONAUDIO);
+
+ if (pcm_audio) {
+ /* Select a channel allocation that matches with ELD and pcm channels */
+ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
+
+ if (idx < 0) {
+ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
+ idx);
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+ return idx;
+ }
- /* Select a channel allocation that matches with ELD and pcm channels */
- idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
- if (idx < 0) {
- dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
- idx);
- hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
- return idx;
+ ca_id = hdmi_codec_channel_alloc[idx].ca_id;
}
memset(hp, 0, sizeof(*hp));
hdmi_audio_infoframe_init(&hp->cea);
- hp->cea.channels = channels;
+
+ if (pcm_audio)
+ hp->cea.channels = channels;
+ else
+ hp->cea.channels = 0;
+
hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
- hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
+ hp->cea.channel_allocation = ca_id;
hp->sample_width = sample_width;
hp->sample_rate = sample_rate;
hp->channels = channels;
- hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
+ if (pcm_audio)
+ hcp->chmap_idx = ca_id;
+ else
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
return 0;
}
@@ -684,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);
@@ -699,7 +734,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction)
* For example,
* ${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
*/
-static u64 hdmi_codec_formats =
+static const u64 hdmi_codec_formats =
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
SND_SOC_POSSIBLE_DAIFMT_NB_IF |
SND_SOC_POSSIBLE_DAIFMT_IB_NF |
@@ -711,24 +746,6 @@ static u64 hdmi_codec_formats =
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_AC97;
-static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
- .startup = hdmi_codec_startup,
- .shutdown = hdmi_codec_shutdown,
- .hw_params = hdmi_codec_hw_params,
- .prepare = hdmi_codec_prepare,
- .set_fmt = hdmi_codec_i2s_set_fmt,
- .mute_stream = hdmi_codec_mute,
- .auto_selectable_formats = &hdmi_codec_formats,
- .num_auto_selectable_formats = 1,
-};
-
-static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
- .startup = hdmi_codec_startup,
- .shutdown = hdmi_codec_shutdown,
- .hw_params = hdmi_codec_hw_params,
- .mute_stream = hdmi_codec_mute,
-};
-
#define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
@@ -813,8 +830,70 @@ 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_soc_component *component = dai->component;
+ struct snd_soc_card *card = component->card;
+ struct snd_soc_dai *d;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_info_entry *entry;
+ char name[32];
+ int err, i, id = 0;
+
+ /*
+ * To avoid duplicate proc entry, find its rtd and use rtd->id
+ * instead of dai->id
+ */
+ for_each_card_rtds(card, rtd) {
+ for_each_rtd_dais(rtd, i, d)
+ if (d == dai) {
+ id = rtd->id;
+ goto found;
+ }
+ }
+found:
+ snprintf(name, sizeof(name), "eld#%d", id);
+ err = snd_card_proc_new(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[] = {
@@ -829,7 +908,7 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
};
int ret, i;
- dapm = snd_soc_component_get_dapm(dai->component);
+ dapm = snd_soc_component_to_dapm(dai->component);
/* One of the directions might be omitted for unidirectional DAIs */
for (i = 0; i < ARRAY_SIZE(route); i++) {
@@ -847,14 +926,24 @@ 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;
}
static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp,
unsigned int jack_status)
{
- if (hcp->jack && jack_status != hcp->jack_status) {
- snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT);
+ if (jack_status != hcp->jack_status) {
+ if (hcp->jack)
+ snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_AVOUT);
hcp->jack_status = jack_status;
}
}
@@ -862,13 +951,20 @@ 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);
+ hdmi_codec_jack_report(hcp, SND_JACK_AVOUT);
} else {
hdmi_codec_jack_report(hcp, 0);
memset(hcp->eld, 0, sizeof(hcp->eld));
@@ -880,18 +976,20 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
void *data)
{
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
- int ret = -ENOTSUPP;
if (hcp->hcd.ops->hook_plugged_cb) {
hcp->jack = jack;
- ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent,
- hcp->hcd.data,
- plugged_cb,
- component->dev);
- if (ret)
- hcp->jack = NULL;
+
+ /*
+ * Report the initial jack status which may have been provided
+ * by the parent hdmi driver while the hpd hook was registered.
+ */
+ snd_soc_jack_report(jack, hcp->jack_status, SND_JACK_AVOUT);
+
+ return 0;
}
- return ret;
+
+ return -ENOTSUPP;
}
static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
@@ -909,10 +1007,33 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
return 0;
}
+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,
+ .prepare = hdmi_codec_prepare,
+ .set_fmt = hdmi_codec_i2s_set_fmt,
+ .mute_stream = hdmi_codec_mute,
+ .pcm_new = hdmi_codec_pcm_new,
+ .auto_selectable_formats = &hdmi_codec_formats,
+ .num_auto_selectable_formats = 1,
+};
+
+static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
+ .probe = hdmi_dai_spdif_probe,
+ .startup = hdmi_codec_startup,
+ .shutdown = hdmi_codec_shutdown,
+ .hw_params = hdmi_codec_hw_params,
+ .prepare = hdmi_codec_prepare,
+ .mute_stream = hdmi_codec_mute,
+ .pcm_new = hdmi_codec_pcm_new,
+};
+
static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.name = "i2s-hifi",
.id = DAI_ID_I2S,
- .probe = hdmi_dai_probe,
.playback = {
.stream_name = "I2S Playback",
.channels_min = 2,
@@ -930,13 +1051,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.sig_bits = 24,
},
.ops = &hdmi_codec_i2s_dai_ops,
- .pcm_new = hdmi_codec_pcm_new,
};
static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.name = "spdif-hifi",
.id = DAI_ID_SPDIF,
- .probe = hdmi_dai_spdif_probe,
.playback = {
.stream_name = "SPDIF Playback",
.channels_min = 2,
@@ -952,7 +1071,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.formats = SPDIF_FORMATS,
},
.ops = &hdmi_codec_spdif_dai_ops,
- .pcm_new = hdmi_codec_pcm_new,
};
static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
@@ -962,7 +1080,22 @@ 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;
+}
+
+static int hdmi_probe(struct snd_soc_component *component)
+{
+ struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ if (hcp->hcd.ops->hook_plugged_cb) {
+ ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent,
+ hcp->hcd.data,
+ plugged_cb,
+ component->dev);
+ }
return ret;
}
@@ -977,6 +1110,7 @@ static void hdmi_remove(struct snd_soc_component *component)
}
static const struct snd_soc_component_driver hdmi_driver = {
+ .probe = hdmi_probe,
.remove = hdmi_remove,
.dapm_widgets = hdmi_widgets,
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
@@ -1028,6 +1162,10 @@ static int hdmi_codec_probe(struct platform_device *pdev)
if (hcd->i2s) {
daidrv[i] = hdmi_i2s_dai;
daidrv[i].playback.channels_max = hcd->max_i2s_channels;
+ if (hcd->i2s_formats) {
+ daidrv[i].playback.formats = hcd->i2s_formats;
+ daidrv[i].capture.formats = hcd->i2s_formats;
+ }
if (hcd->no_i2s_playback)
memset(&daidrv[i].playback, 0,
sizeof(daidrv[i].playback));
diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c
index 2cc7b9166e69..39bafefa6a18 100644
--- a/sound/soc/codecs/idt821034.c
+++ b/sound/soc/codecs/idt821034.c
@@ -402,7 +402,7 @@ static int idt821034_kctrl_gain_get(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_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component);
int min = mc->min;
int max = mc->max;
@@ -433,7 +433,7 @@ static int idt821034_kctrl_gain_put(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_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component);
struct idt821034_amp *amp;
int min = mc->min;
@@ -487,7 +487,7 @@ end:
static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component);
int id = kcontrol->private_value;
bool is_muted;
@@ -509,7 +509,7 @@ static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol,
static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component);
int id = kcontrol->private_value;
struct idt821034_amp *amp;
@@ -548,14 +548,14 @@ end:
return ret;
}
-static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -6520, 1306);
-#define IDT821034_GAIN_IN_MIN_RAW 1 /* -65.20 dB -> 10^(-65.2/20.0) * 1820 = 1 */
-#define IDT821034_GAIN_IN_MAX_RAW 8191 /* 13.06 dB -> 10^(13.06/20.0) * 1820 = 8191 */
+static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -300, 1300);
+#define IDT821034_GAIN_IN_MIN_RAW 1288 /* -3.0 dB -> 10^(-3.0/20.0) * 1820 = 1288 */
+#define IDT821034_GAIN_IN_MAX_RAW 8130 /* 13.0 dB -> 10^(13.0/20.0) * 1820 = 8130 */
#define IDT821034_GAIN_IN_INIT_RAW 1820 /* 0dB -> 10^(0/20) * 1820 = 1820 */
-static const DECLARE_TLV_DB_LINEAR(idt821034_gain_out, -6798, 1029);
-#define IDT821034_GAIN_OUT_MIN_RAW 1 /* -67.98 dB -> 10^(-67.98/20.0) * 2506 = 1*/
-#define IDT821034_GAIN_OUT_MAX_RAW 8191 /* 10.29 dB -> 10^(10.29/20.0) * 2506 = 8191 */
+static const DECLARE_TLV_DB_LINEAR(idt821034_gain_out, -1300, 300);
+#define IDT821034_GAIN_OUT_MIN_RAW 561 /* -13.0 dB -> 10^(-13.0/20.0) * 2506 = 561 */
+#define IDT821034_GAIN_OUT_MAX_RAW 3540 /* 3.0 dB -> 10^(3.0/20.0) * 2506 = 3540 */
#define IDT821034_GAIN_OUT_INIT_RAW 2506 /* 0dB -> 10^(0/20) * 2506 = 2506 */
static const struct snd_kcontrol_new idt821034_controls[] = {
@@ -860,7 +860,7 @@ static int idt821034_dai_startup(struct snd_pcm_substream *substream,
return 0;
}
-static u64 idt821034_dai_formats[] = {
+static const u64 idt821034_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
@@ -957,7 +957,8 @@ static const struct snd_soc_component_driver idt821034_component_driver = {
#define IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(_offset) (((_offset) / 5) % 4)
#define IDT821034_GPIO_OFFSET_TO_SLIC_MASK(_offset) BIT((_offset) % 5)
-static void idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
+static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
+ int val)
{
u8 ch = IDT821034_GPIO_OFFSET_TO_SLIC_CHANNEL(offset);
u8 mask = IDT821034_GPIO_OFFSET_TO_SLIC_MASK(offset);
@@ -973,12 +974,14 @@ static void idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, in
else
slic_raw &= ~mask;
ret = idt821034_write_slic_raw(idt821034, ch, slic_raw);
- if (ret) {
+
+ mutex_unlock(&idt821034->mutex);
+
+ if (ret)
dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n",
offset, ch, mask, ret);
- }
- mutex_unlock(&idt821034->mutex);
+ return ret;
}
static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset)
@@ -1054,7 +1057,9 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off
u8 slic_conf;
int ret;
- idt821034_chip_gpio_set(c, offset, val);
+ ret = idt821034_chip_gpio_set(c, offset, val);
+ if (ret)
+ return ret;
mutex_lock(&idt821034->mutex);
@@ -1062,7 +1067,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off
ret = idt821034_set_slic_conf(idt821034, ch, slic_conf);
if (ret) {
- dev_err(&idt821034->spi->dev, "dir in gpio %d (%u, 0x%x) failed (%d)\n",
+ dev_err(&idt821034->spi->dev, "dir out gpio %d (%u, 0x%x) failed (%d)\n",
offset, ch, mask, ret);
}
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
index 11320423c69c..fdd19f8e8864 100644
--- a/sound/soc/codecs/inno_rk3036.c
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -476,7 +476,7 @@ static struct platform_driver rk3036_codec_platform_driver = {
.of_match_table = of_match_ptr(rk3036_codec_of_match),
},
.probe = rk3036_codec_platform_probe,
- .remove_new = rk3036_codec_platform_remove,
+ .remove = rk3036_codec_platform_remove,
};
module_platform_driver(rk3036_codec_platform_driver);
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index f9456133a89a..b7a94631d77d 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -1133,7 +1133,7 @@ static int isabelle_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id isabelle_i2c_id[] = {
- { "isabelle", 0 },
+ { "isabelle" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id);
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 7c25acf6ff0d..d3d801d850a1 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -231,6 +231,7 @@ static void jz4740_codec_wakeup(struct regmap *regmap)
static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
struct regmap *regmap = jz4740_codec->regmap;
unsigned int mask;
@@ -247,7 +248,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
/* The only way to clear the suspend flag is to reset the codec */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
jz4740_codec_wakeup(regmap);
mask = JZ4740_CODEC_1_VREF_DISABLE |
@@ -301,7 +302,7 @@ static const struct regmap_config jz4740_codec_regmap_config = {
.reg_defaults = jz4740_codec_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int jz4740_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
index 9df58e23d360..344c251be397 100644
--- a/sound/soc/codecs/jz4760.c
+++ b/sound/soc/codecs/jz4760.c
@@ -197,7 +197,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *codec = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
int ret = 0;
/*
@@ -214,7 +214,7 @@ static void jz4760_codec_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *codec = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dapm_disable_pin(dapm, "SYSCLK");
@@ -225,6 +225,7 @@ static int jz4760_codec_pcm_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_component *codec = dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
int ret = 0;
switch (cmd) {
@@ -232,7 +233,7 @@ static int jz4760_codec_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_component_force_bias_level(codec, SND_SOC_BIAS_ON);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_ON);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -314,37 +315,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,
@@ -821,7 +798,7 @@ static const u8 jz4760_codec_reg_defaults[] = {
0x1F, 0x00, 0x00, 0x00
};
-static struct regmap_config jz4760_codec_regmap_config = {
+static const struct regmap_config jz4760_codec_regmap_config = {
.reg_bits = 7,
.val_bits = 8,
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index 1d0c467ab57b..6b86d47028d7 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -217,7 +217,7 @@ static int jz4770_codec_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *codec = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
/*
* SYSCLK output from the codec to the AIC is required to keep the
@@ -234,7 +234,7 @@ static void jz4770_codec_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *codec = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dapm_disable_pin(dapm, "SYSCLK");
@@ -245,6 +245,7 @@ static int jz4770_codec_pcm_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_component *codec = dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
int ret = 0;
switch (cmd) {
@@ -252,8 +253,7 @@ static int jz4770_codec_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_component_force_bias_level(codec,
- SND_SOC_BIAS_ON);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_ON);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -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,
@@ -872,7 +844,7 @@ static const u8 jz4770_codec_reg_defaults[] = {
0x07, 0x44, 0x1F, 0x00
};
-static struct regmap_config jz4770_codec_regmap_config = {
+static const struct regmap_config jz4770_codec_regmap_config = {
.reg_bits = 7,
.val_bits = 8,
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
deleted file mode 100644
index b84f6f1f6800..000000000000
--- a/sound/soc/codecs/l3.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * L3 code
- *
- * Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org>
- *
- * based on:
- *
- * L3 bus algorithm module.
- *
- * Copyright (C) 2001 Russell King, All Rights Reserved.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-
-#include <sound/l3.h>
-
-/*
- * Send one byte of data to the chip. Data is latched into the chip on
- * the rising edge of the clock.
- */
-static void sendbyte(struct l3_pins *adap, unsigned int byte)
-{
- int i;
-
- for (i = 0; i < 8; i++) {
- adap->setclk(adap, 0);
- udelay(adap->data_hold);
- adap->setdat(adap, byte & 1);
- udelay(adap->data_setup);
- adap->setclk(adap, 1);
- udelay(adap->clock_high);
- byte >>= 1;
- }
-}
-
-/*
- * Send a set of bytes to the chip. We need to pulse the MODE line
- * between each byte, but never at the start nor at the end of the
- * transfer.
- */
-static void sendbytes(struct l3_pins *adap, const u8 *buf,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- if (i) {
- udelay(adap->mode_hold);
- adap->setmode(adap, 0);
- udelay(adap->mode);
- }
- adap->setmode(adap, 1);
- udelay(adap->mode_setup);
- sendbyte(adap, buf[i]);
- }
-}
-
-int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
-{
- adap->setclk(adap, 1);
- adap->setdat(adap, 1);
- adap->setmode(adap, 1);
- udelay(adap->mode);
-
- adap->setmode(adap, 0);
- udelay(adap->mode_setup);
- sendbyte(adap, addr);
- udelay(adap->mode_hold);
-
- sendbytes(adap, data, len);
-
- adap->setclk(adap, 1);
- adap->setdat(adap, 1);
- adap->setmode(adap, 0);
-
- return len;
-}
-EXPORT_SYMBOL_GPL(l3_write);
-
-
-static void l3_set_clk(struct l3_pins *adap, int val)
-{
- gpio_set_value(adap->gpio_clk, val);
-}
-
-static void l3_set_data(struct l3_pins *adap, int val)
-{
- gpio_set_value(adap->gpio_data, val);
-}
-
-static void l3_set_mode(struct l3_pins *adap, int val)
-{
- gpio_set_value(adap->gpio_mode, val);
-}
-
-int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap)
-{
- int ret;
-
- if (!adap->use_gpios)
- return -EINVAL;
-
- ret = devm_gpio_request_one(dev, adap->gpio_data,
- GPIOF_OUT_INIT_LOW, "l3_data");
- if (ret < 0)
- return ret;
- adap->setdat = l3_set_data;
-
- ret = devm_gpio_request_one(dev, adap->gpio_clk,
- GPIOF_OUT_INIT_LOW, "l3_clk");
- if (ret < 0)
- return ret;
- adap->setclk = l3_set_clk;
-
- ret = devm_gpio_request_one(dev, adap->gpio_mode,
- GPIOF_OUT_INIT_LOW, "l3_mode");
- if (ret < 0)
- return ret;
- adap->setmode = l3_set_mode;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(l3_set_gpio_ops);
-
-MODULE_DESCRIPTION("L3 bit-banging driver");
-MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index e7542f71323d..26cdb750cbca 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -128,7 +128,7 @@ static int lm4857_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id lm4857_i2c_id[] = {
- { "lm4857", 0 },
+ { "lm4857" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id);
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index a4094689b3dd..043030509795 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1255,6 +1255,7 @@ static int lm49453_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct lm49453_priv *lm49453 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1262,7 +1263,7 @@ static int lm49453_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
regcache_sync(lm49453->regmap);
snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG,
@@ -1442,7 +1443,7 @@ static int lm49453_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id lm49453_i2c_id[] = {
- { "lm49453", 0 },
+ { "lm49453" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
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-macro-common.c b/sound/soc/codecs/lpass-macro-common.c
index f54baaad54d4..6e3b8d0897dd 100644
--- a/sound/soc/codecs/lpass-macro-common.c
+++ b/sound/soc/codecs/lpass-macro-common.c
@@ -4,13 +4,16 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include "lpass-macro-common.h"
+static DEFINE_MUTEX(lpass_codec_mutex);
+static enum lpass_codec_version lpass_codec_version;
+
struct lpass_macro *lpass_macro_pds_init(struct device *dev)
{
struct lpass_macro *l_pds;
@@ -66,5 +69,25 @@ void lpass_macro_pds_exit(struct lpass_macro *pds)
}
EXPORT_SYMBOL_GPL(lpass_macro_pds_exit);
+void lpass_macro_set_codec_version(enum lpass_codec_version version)
+{
+ mutex_lock(&lpass_codec_mutex);
+ lpass_codec_version = version;
+ mutex_unlock(&lpass_codec_mutex);
+}
+EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version);
+
+enum lpass_codec_version lpass_macro_get_codec_version(void)
+{
+ enum lpass_codec_version ver;
+
+ mutex_lock(&lpass_codec_mutex);
+ ver = lpass_codec_version;
+ mutex_unlock(&lpass_codec_mutex);
+
+ return ver;
+}
+EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version);
+
MODULE_DESCRIPTION("Common macro driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h
index 4eb886565ea3..10ad682019fa 100644
--- a/sound/soc/codecs/lpass-macro-common.h
+++ b/sound/soc/codecs/lpass-macro-common.h
@@ -8,6 +8,29 @@
/* NPL clock is expected */
#define LPASS_MACRO_FLAG_HAS_NPL_CLOCK BIT(0)
+/* The soundwire block should be internally reset at probe */
+#define LPASS_MACRO_FLAG_RESET_SWR BIT(1)
+
+enum lpass_version {
+ LPASS_VER_9_0_0,
+ LPASS_VER_9_2_0,
+ LPASS_VER_10_0_0,
+ LPASS_VER_11_0_0,
+};
+
+enum lpass_codec_version {
+ LPASS_CODEC_VERSION_UNKNOWN,
+ LPASS_CODEC_VERSION_1_0,
+ LPASS_CODEC_VERSION_1_1,
+ LPASS_CODEC_VERSION_1_2,
+ LPASS_CODEC_VERSION_2_0,
+ LPASS_CODEC_VERSION_2_1,
+ LPASS_CODEC_VERSION_2_5,
+ LPASS_CODEC_VERSION_2_6,
+ LPASS_CODEC_VERSION_2_7,
+ LPASS_CODEC_VERSION_2_8,
+ LPASS_CODEC_VERSION_2_9,
+};
struct lpass_macro {
struct device *macro_pd;
@@ -16,5 +39,39 @@ struct lpass_macro {
struct lpass_macro *lpass_macro_pds_init(struct device *dev);
void lpass_macro_pds_exit(struct lpass_macro *pds);
+void lpass_macro_set_codec_version(enum lpass_codec_version version);
+enum lpass_codec_version lpass_macro_get_codec_version(void);
+
+static inline void lpass_macro_pds_exit_action(void *pds)
+{
+ lpass_macro_pds_exit(pds);
+}
+
+static inline const char *lpass_macro_get_codec_version_string(int version)
+{
+ switch (version) {
+ case LPASS_CODEC_VERSION_1_0:
+ return "v1.0";
+ case LPASS_CODEC_VERSION_1_1:
+ return "v1.1";
+ case LPASS_CODEC_VERSION_1_2:
+ return "v1.2";
+ case LPASS_CODEC_VERSION_2_0:
+ return "v2.0";
+ case LPASS_CODEC_VERSION_2_1:
+ return "v2.1";
+ case LPASS_CODEC_VERSION_2_5:
+ return "v2.5";
+ case LPASS_CODEC_VERSION_2_6:
+ return "v2.6";
+ case LPASS_CODEC_VERSION_2_7:
+ return "v2.7";
+ case LPASS_CODEC_VERSION_2_8:
+ return "v2.8";
+ default:
+ break;
+ }
+ return "NA";
+}
#endif /* __LPASS_MACRO_COMMON_H__ */
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 685ca95ef4a9..0a8de5620e72 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -158,7 +159,7 @@
#define CDC_RX_INTR_CTRL_LEVEL0 (0x03C0)
#define CDC_RX_INTR_CTRL_BYPASS0 (0x03C8)
#define CDC_RX_INTR_CTRL_SET0 (0x03D0)
-#define CDC_RX_RXn_RX_PATH_CTL(n) (0x0400 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CTL(rx, n) (0x0400 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_CTL (0x0400)
#define CDC_RX_PATH_RESET_EN_MASK BIT(6)
#define CDC_RX_PATH_CLK_EN_MASK BIT(5)
@@ -166,45 +167,49 @@
#define CDC_RX_PATH_PGA_MUTE_MASK BIT(4)
#define CDC_RX_PATH_PGA_MUTE_ENABLE BIT(4)
#define CDC_RX_PATH_PCM_RATE_MASK GENMASK(3, 0)
-#define CDC_RX_RXn_RX_PATH_CFG0(n) (0x0404 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG0(rx, n) (0x0404 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_COMP_EN_MASK BIT(1)
#define CDC_RX_RX0_RX_PATH_CFG0 (0x0404)
#define CDC_RX_RXn_CLSH_EN_MASK BIT(6)
#define CDC_RX_DLY_ZN_EN_MASK BIT(3)
#define CDC_RX_DLY_ZN_ENABLE BIT(3)
#define CDC_RX_RXn_HD2_EN_MASK BIT(2)
-#define CDC_RX_RXn_RX_PATH_CFG1(n) (0x0408 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG1(rx, n) (0x0408 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_SIDETONE_EN_MASK BIT(4)
#define CDC_RX_RX0_RX_PATH_CFG1 (0x0408)
#define CDC_RX_RX0_HPH_L_EAR_SEL_MASK BIT(1)
-#define CDC_RX_RXn_RX_PATH_CFG2(n) (0x040C + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG2(rx, n) (0x040C + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_HPF_CUT_FREQ_MASK GENMASK(1, 0)
#define CDC_RX_RX0_RX_PATH_CFG2 (0x040C)
-#define CDC_RX_RXn_RX_PATH_CFG3(n) (0x0410 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_CFG3(rx, n) (0x0410 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_CFG3 (0x0410)
#define CDC_RX_DC_COEFF_SEL_MASK GENMASK(1, 0)
#define CDC_RX_DC_COEFF_SEL_TWO 0x2
-#define CDC_RX_RXn_RX_VOL_CTL(n) (0x0414 + 0x80 * n)
+#define CDC_RX_RXn_RX_VOL_CTL(rx, n) (0x0414 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_VOL_CTL (0x0414)
-#define CDC_RX_RXn_RX_PATH_MIX_CTL(n) (0x0418 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_MIX_CTL(rx, n) (0x0418 + rx->rxn_reg_stride * n)
#define CDC_RX_RXn_MIX_PCM_RATE_MASK GENMASK(3, 0)
#define CDC_RX_RXn_MIX_RESET_MASK BIT(6)
#define CDC_RX_RXn_MIX_RESET BIT(6)
#define CDC_RX_RXn_MIX_CLK_EN_MASK BIT(5)
#define CDC_RX_RX0_RX_PATH_MIX_CTL (0x0418)
#define CDC_RX_RX0_RX_PATH_MIX_CFG (0x041C)
-#define CDC_RX_RXn_RX_VOL_MIX_CTL(n) (0x0420 + 0x80 * n)
+#define CDC_RX_RXn_RX_VOL_MIX_CTL(rx, n) (0x0420 + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_VOL_MIX_CTL (0x0420)
#define CDC_RX_RX0_RX_PATH_SEC1 (0x0424)
#define CDC_RX_RX0_RX_PATH_SEC2 (0x0428)
#define CDC_RX_RX0_RX_PATH_SEC3 (0x042C)
+#define CDC_RX_RXn_RX_PATH_SEC3(rx, n) (0x042c + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_SEC4 (0x0430)
#define CDC_RX_RX0_RX_PATH_SEC7 (0x0434)
+#define CDC_RX_RXn_RX_PATH_SEC7(rx, n) \
+ (0x0434 + (rx->rxn_reg_stride * n) + ((n > 1) ? rx->rxn_reg_stride2 : 0))
#define CDC_RX_DSM_OUT_DELAY_SEL_MASK GENMASK(2, 0)
#define CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE 0x2
#define CDC_RX_RX0_RX_PATH_MIX_SEC0 (0x0438)
#define CDC_RX_RX0_RX_PATH_MIX_SEC1 (0x043C)
-#define CDC_RX_RXn_RX_PATH_DSM_CTL(n) (0x0440 + 0x80 * n)
+#define CDC_RX_RXn_RX_PATH_DSM_CTL(rx, n) \
+ (0x0440 + (rx->rxn_reg_stride * n) + ((n > 1) ? rx->rxn_reg_stride2 : 0))
#define CDC_RX_RXn_DSM_CLK_EN_MASK BIT(0)
#define CDC_RX_RX0_RX_PATH_DSM_CTL (0x0440)
#define CDC_RX_RX0_RX_PATH_DSM_DATA1 (0x0444)
@@ -213,6 +218,7 @@
#define CDC_RX_RX0_RX_PATH_DSM_DATA4 (0x0450)
#define CDC_RX_RX0_RX_PATH_DSM_DATA5 (0x0454)
#define CDC_RX_RX0_RX_PATH_DSM_DATA6 (0x0458)
+/* RX offsets prior to 2.5 codec version */
#define CDC_RX_RX1_RX_PATH_CTL (0x0480)
#define CDC_RX_RX1_RX_PATH_CFG0 (0x0484)
#define CDC_RX_RX1_RX_PATH_CFG1 (0x0488)
@@ -259,6 +265,53 @@
#define CDC_RX_RX2_RX_PATH_MIX_SEC0 (0x0544)
#define CDC_RX_RX2_RX_PATH_MIX_SEC1 (0x0548)
#define CDC_RX_RX2_RX_PATH_DSM_CTL (0x054C)
+
+/* LPASS CODEC version 2.5 rx reg offsets */
+#define CDC_2_5_RX_RX1_RX_PATH_CTL (0x04c0)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG0 (0x04c4)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG1 (0x04c8)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG2 (0x04cC)
+#define CDC_2_5_RX_RX1_RX_PATH_CFG3 (0x04d0)
+#define CDC_2_5_RX_RX1_RX_VOL_CTL (0x04d4)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_CTL (0x04d8)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_CFG (0x04dC)
+#define CDC_2_5_RX_RX1_RX_VOL_MIX_CTL (0x04e0)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC1 (0x04e4)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC2 (0x04e8)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC3 (0x04eC)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC4 (0x04f0)
+#define CDC_2_5_RX_RX1_RX_PATH_SEC7 (0x04f4)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0 (0x04f8)
+#define CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1 (0x04fC)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_CTL (0x0500)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1 (0x0504)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2 (0x0508)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3 (0x050C)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4 (0x0510)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5 (0x0514)
+#define CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6 (0x0518)
+
+#define CDC_2_5_RX_RX2_RX_PATH_CTL (0x0580)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG0 (0x0584)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG1 (0x0588)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG2 (0x058C)
+#define CDC_2_5_RX_RX2_RX_PATH_CFG3 (0x0590)
+#define CDC_2_5_RX_RX2_RX_VOL_CTL (0x0594)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_CTL (0x0598)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_CFG (0x059C)
+#define CDC_2_5_RX_RX2_RX_VOL_MIX_CTL (0x05a0)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC0 (0x05a4)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC1 (0x05a8)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC2 (0x05aC)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC3 (0x05b0)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC4 (0x05b4)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC5 (0x05b8)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC6 (0x05bC)
+#define CDC_2_5_RX_RX2_RX_PATH_SEC7 (0x05c0)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0 (0x05c4)
+#define CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1 (0x05c8)
+#define CDC_2_5_RX_RX2_RX_PATH_DSM_CTL (0x05cC)
+
#define CDC_RX_IDLE_DETECT_PATH_CTL (0x0780)
#define CDC_RX_IDLE_DETECT_CFG0 (0x0784)
#define CDC_RX_IDLE_DETECT_CFG1 (0x0788)
@@ -463,12 +516,6 @@ static const struct comp_coeff_val comp_coeff_table[HPH_MODE_MAX][COMP_MAX_COEFF
},
};
-struct rx_macro_reg_mask_val {
- u16 reg;
- u8 mask;
- u8 val;
-};
-
enum {
INTERP_HPHL,
INTERP_HPHR,
@@ -571,8 +618,8 @@ static struct interp_sample_rate sr_val_tbl[] = {
{176400, 0xB}, {352800, 0xC},
};
+/* Matches also rx_macro_mux_text */
enum {
- RX_MACRO_AIF_INVALID = 0,
RX_MACRO_AIF1_PB,
RX_MACRO_AIF2_PB,
RX_MACRO_AIF3_PB,
@@ -598,6 +645,9 @@ struct rx_macro {
int rx_mclk_users;
int clsh_users;
int rx_mclk_cnt;
+ enum lpass_codec_version codec_version;
+ int rxn_reg_stride;
+ int rxn_reg_stride2;
bool is_ear_mode_on;
bool hph_pwr_mode;
bool hph_hd2_mode;
@@ -673,6 +723,7 @@ static const char * const rx_int2_2_interp_mux_text[] = {
"ZERO", "RX INT2_2 MUX",
};
+/* Order must match RX_MACRO_MAX_DAIS enum (offset by 1) */
static const char *const rx_macro_mux_text[] = {
"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB"
};
@@ -759,6 +810,8 @@ static SOC_ENUM_SINGLE_DECL(rx_int0_dem_inp_enum, CDC_RX_RX0_RX_PATH_CFG1, 0,
rx_int_dem_inp_mux_text);
static SOC_ENUM_SINGLE_DECL(rx_int1_dem_inp_enum, CDC_RX_RX1_RX_PATH_CFG1, 0,
rx_int_dem_inp_mux_text);
+static SOC_ENUM_SINGLE_DECL(rx_2_5_int1_dem_inp_enum, CDC_2_5_RX_RX1_RX_PATH_CFG1, 0,
+ rx_int_dem_inp_mux_text);
static SOC_ENUM_SINGLE_DECL(rx_macro_rx0_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
static SOC_ENUM_SINGLE_DECL(rx_macro_rx1_enum, SND_SOC_NOPM, 0, rx_macro_mux_text);
@@ -909,7 +962,7 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_BCL_VBAT_PK_EST2, 0x01 },
{ CDC_RX_BCL_VBAT_PK_EST3, 0x40 },
{ CDC_RX_BCL_VBAT_RF_PROC1, 0x2A },
- { CDC_RX_BCL_VBAT_RF_PROC1, 0x00 },
+ { CDC_RX_BCL_VBAT_RF_PROC2, 0x00 },
{ CDC_RX_BCL_VBAT_TAC1, 0x00 },
{ CDC_RX_BCL_VBAT_TAC2, 0x18 },
{ CDC_RX_BCL_VBAT_TAC3, 0x18 },
@@ -976,49 +1029,6 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_RX0_RX_PATH_DSM_DATA4, 0x55 },
{ CDC_RX_RX0_RX_PATH_DSM_DATA5, 0x55 },
{ CDC_RX_RX0_RX_PATH_DSM_DATA6, 0x55 },
- { CDC_RX_RX1_RX_PATH_CTL, 0x04 },
- { CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
- { CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
- { CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
- { CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
- { CDC_RX_RX1_RX_VOL_CTL, 0x00 },
- { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
- { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
- { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
- { CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
- { CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
- { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
- { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
- { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
- { CDC_RX_RX2_RX_PATH_CTL, 0x04 },
- { CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
- { CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
- { CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
- { CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
- { CDC_RX_RX2_RX_VOL_CTL, 0x00 },
- { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
- { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
- { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
- { CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
- { CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
- { CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
- { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
- { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
- { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
{ CDC_RX_IDLE_DETECT_PATH_CTL, 0x00 },
{ CDC_RX_IDLE_DETECT_CFG0, 0x07 },
{ CDC_RX_IDLE_DETECT_CFG1, 0x3C },
@@ -1121,6 +1131,99 @@ static const struct reg_default rx_defaults[] = {
{ CDC_RX_DSD1_CFG2, 0x96 },
};
+static const struct reg_default rx_2_5_defaults[] = {
+ { CDC_2_5_RX_RX1_RX_PATH_CTL, 0x04 },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG0, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG1, 0x64 },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG2, 0x8F },
+ { CDC_2_5_RX_RX1_RX_PATH_CFG3, 0x00 },
+ { CDC_2_5_RX_RX1_RX_VOL_CTL, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_2_5_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC1, 0x08 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC2, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC3, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC4, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_SEC7, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+ { CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+ { CDC_2_5_RX_RX2_RX_PATH_CTL, 0x04 },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG0, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG1, 0x64 },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG2, 0x8F },
+ { CDC_2_5_RX_RX2_RX_PATH_CFG3, 0x00 },
+ { CDC_2_5_RX_RX2_RX_VOL_CTL, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_2_5_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC0, 0x04 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC1, 0x08 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC2, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC3, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC4, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC5, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC6, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_SEC7, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_2_5_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+};
+
+static const struct reg_default rx_pre_2_5_defaults[] = {
+ { CDC_RX_RX1_RX_PATH_CTL, 0x04 },
+ { CDC_RX_RX1_RX_PATH_CFG0, 0x00 },
+ { CDC_RX_RX1_RX_PATH_CFG1, 0x64 },
+ { CDC_RX_RX1_RX_PATH_CFG2, 0x8F },
+ { CDC_RX_RX1_RX_PATH_CFG3, 0x00 },
+ { CDC_RX_RX1_RX_VOL_CTL, 0x00 },
+ { CDC_RX_RX1_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_RX_RX1_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_RX_RX1_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC1, 0x08 },
+ { CDC_RX_RX1_RX_PATH_SEC2, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC3, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC4, 0x00 },
+ { CDC_RX_RX1_RX_PATH_SEC7, 0x00 },
+ { CDC_RX_RX1_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_RX_RX1_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_CTL, 0x08 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA1, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA2, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA3, 0x00 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA4, 0x55 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA5, 0x55 },
+ { CDC_RX_RX1_RX_PATH_DSM_DATA6, 0x55 },
+ { CDC_RX_RX2_RX_PATH_CTL, 0x04 },
+ { CDC_RX_RX2_RX_PATH_CFG0, 0x00 },
+ { CDC_RX_RX2_RX_PATH_CFG1, 0x64 },
+ { CDC_RX_RX2_RX_PATH_CFG2, 0x8F },
+ { CDC_RX_RX2_RX_PATH_CFG3, 0x00 },
+ { CDC_RX_RX2_RX_VOL_CTL, 0x00 },
+ { CDC_RX_RX2_RX_PATH_MIX_CTL, 0x04 },
+ { CDC_RX_RX2_RX_PATH_MIX_CFG, 0x7E },
+ { CDC_RX_RX2_RX_VOL_MIX_CTL, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC0, 0x04 },
+ { CDC_RX_RX2_RX_PATH_SEC1, 0x08 },
+ { CDC_RX_RX2_RX_PATH_SEC2, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC3, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC4, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC5, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC6, 0x00 },
+ { CDC_RX_RX2_RX_PATH_SEC7, 0x00 },
+ { CDC_RX_RX2_RX_PATH_MIX_SEC0, 0x08 },
+ { CDC_RX_RX2_RX_PATH_MIX_SEC1, 0x00 },
+ { CDC_RX_RX2_RX_PATH_DSM_CTL, 0x00 },
+
+};
+
static bool rx_is_wronly_register(struct device *dev,
unsigned int reg)
{
@@ -1175,8 +1278,114 @@ static bool rx_is_volatile_register(struct device *dev, unsigned int reg)
return false;
}
+static bool rx_pre_2_5_is_rw_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_RX_RX1_RX_PATH_CTL:
+ case CDC_RX_RX1_RX_PATH_CFG0:
+ case CDC_RX_RX1_RX_PATH_CFG1:
+ case CDC_RX_RX1_RX_PATH_CFG2:
+ case CDC_RX_RX1_RX_PATH_CFG3:
+ case CDC_RX_RX1_RX_VOL_CTL:
+ case CDC_RX_RX1_RX_PATH_MIX_CTL:
+ case CDC_RX_RX1_RX_PATH_MIX_CFG:
+ case CDC_RX_RX1_RX_VOL_MIX_CTL:
+ case CDC_RX_RX1_RX_PATH_SEC1:
+ case CDC_RX_RX1_RX_PATH_SEC2:
+ case CDC_RX_RX1_RX_PATH_SEC3:
+ case CDC_RX_RX1_RX_PATH_SEC4:
+ case CDC_RX_RX1_RX_PATH_SEC7:
+ case CDC_RX_RX1_RX_PATH_MIX_SEC0:
+ case CDC_RX_RX1_RX_PATH_MIX_SEC1:
+ case CDC_RX_RX1_RX_PATH_DSM_CTL:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA1:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA2:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA3:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA4:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA5:
+ case CDC_RX_RX1_RX_PATH_DSM_DATA6:
+ case CDC_RX_RX2_RX_PATH_CTL:
+ case CDC_RX_RX2_RX_PATH_CFG0:
+ case CDC_RX_RX2_RX_PATH_CFG1:
+ case CDC_RX_RX2_RX_PATH_CFG2:
+ case CDC_RX_RX2_RX_PATH_CFG3:
+ case CDC_RX_RX2_RX_VOL_CTL:
+ case CDC_RX_RX2_RX_PATH_MIX_CTL:
+ case CDC_RX_RX2_RX_PATH_MIX_CFG:
+ case CDC_RX_RX2_RX_VOL_MIX_CTL:
+ case CDC_RX_RX2_RX_PATH_SEC0:
+ case CDC_RX_RX2_RX_PATH_SEC1:
+ case CDC_RX_RX2_RX_PATH_SEC2:
+ case CDC_RX_RX2_RX_PATH_SEC3:
+ case CDC_RX_RX2_RX_PATH_SEC4:
+ case CDC_RX_RX2_RX_PATH_SEC5:
+ case CDC_RX_RX2_RX_PATH_SEC6:
+ case CDC_RX_RX2_RX_PATH_SEC7:
+ case CDC_RX_RX2_RX_PATH_MIX_SEC0:
+ case CDC_RX_RX2_RX_PATH_MIX_SEC1:
+ case CDC_RX_RX2_RX_PATH_DSM_CTL:
+ return true;
+ }
+
+ return false;
+}
+
+static bool rx_2_5_is_rw_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_2_5_RX_RX1_RX_PATH_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG0:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG1:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG2:
+ case CDC_2_5_RX_RX1_RX_PATH_CFG3:
+ case CDC_2_5_RX_RX1_RX_VOL_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_CFG:
+ case CDC_2_5_RX_RX1_RX_VOL_MIX_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC1:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC2:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC3:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC4:
+ case CDC_2_5_RX_RX1_RX_PATH_SEC7:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC0:
+ case CDC_2_5_RX_RX1_RX_PATH_MIX_SEC1:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_CTL:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA1:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA2:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA3:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA4:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA5:
+ case CDC_2_5_RX_RX1_RX_PATH_DSM_DATA6:
+ case CDC_2_5_RX_RX2_RX_PATH_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG0:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG1:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG2:
+ case CDC_2_5_RX_RX2_RX_PATH_CFG3:
+ case CDC_2_5_RX_RX2_RX_VOL_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_CFG:
+ case CDC_2_5_RX_RX2_RX_VOL_MIX_CTL:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC0:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC1:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC2:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC3:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC4:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC5:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC6:
+ case CDC_2_5_RX_RX2_RX_PATH_SEC7:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC0:
+ case CDC_2_5_RX_RX2_RX_PATH_MIX_SEC1:
+ case CDC_2_5_RX_RX2_RX_PATH_DSM_CTL:
+ return true;
+ }
+
+ return false;
+}
+
static bool rx_is_rw_register(struct device *dev, unsigned int reg)
{
+ struct rx_macro *rx = dev_get_drvdata(dev);
+
switch (reg) {
case CDC_RX_TOP_TOP_CFG0:
case CDC_RX_TOP_SWR_CTRL:
@@ -1306,49 +1515,6 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
case CDC_RX_RX0_RX_PATH_DSM_DATA4:
case CDC_RX_RX0_RX_PATH_DSM_DATA5:
case CDC_RX_RX0_RX_PATH_DSM_DATA6:
- case CDC_RX_RX1_RX_PATH_CTL:
- case CDC_RX_RX1_RX_PATH_CFG0:
- case CDC_RX_RX1_RX_PATH_CFG1:
- case CDC_RX_RX1_RX_PATH_CFG2:
- case CDC_RX_RX1_RX_PATH_CFG3:
- case CDC_RX_RX1_RX_VOL_CTL:
- case CDC_RX_RX1_RX_PATH_MIX_CTL:
- case CDC_RX_RX1_RX_PATH_MIX_CFG:
- case CDC_RX_RX1_RX_VOL_MIX_CTL:
- case CDC_RX_RX1_RX_PATH_SEC1:
- case CDC_RX_RX1_RX_PATH_SEC2:
- case CDC_RX_RX1_RX_PATH_SEC3:
- case CDC_RX_RX1_RX_PATH_SEC4:
- case CDC_RX_RX1_RX_PATH_SEC7:
- case CDC_RX_RX1_RX_PATH_MIX_SEC0:
- case CDC_RX_RX1_RX_PATH_MIX_SEC1:
- case CDC_RX_RX1_RX_PATH_DSM_CTL:
- case CDC_RX_RX1_RX_PATH_DSM_DATA1:
- case CDC_RX_RX1_RX_PATH_DSM_DATA2:
- case CDC_RX_RX1_RX_PATH_DSM_DATA3:
- case CDC_RX_RX1_RX_PATH_DSM_DATA4:
- case CDC_RX_RX1_RX_PATH_DSM_DATA5:
- case CDC_RX_RX1_RX_PATH_DSM_DATA6:
- case CDC_RX_RX2_RX_PATH_CTL:
- case CDC_RX_RX2_RX_PATH_CFG0:
- case CDC_RX_RX2_RX_PATH_CFG1:
- case CDC_RX_RX2_RX_PATH_CFG2:
- case CDC_RX_RX2_RX_PATH_CFG3:
- case CDC_RX_RX2_RX_VOL_CTL:
- case CDC_RX_RX2_RX_PATH_MIX_CTL:
- case CDC_RX_RX2_RX_PATH_MIX_CFG:
- case CDC_RX_RX2_RX_VOL_MIX_CTL:
- case CDC_RX_RX2_RX_PATH_SEC0:
- case CDC_RX_RX2_RX_PATH_SEC1:
- case CDC_RX_RX2_RX_PATH_SEC2:
- case CDC_RX_RX2_RX_PATH_SEC3:
- case CDC_RX_RX2_RX_PATH_SEC4:
- case CDC_RX_RX2_RX_PATH_SEC5:
- case CDC_RX_RX2_RX_PATH_SEC6:
- case CDC_RX_RX2_RX_PATH_SEC7:
- case CDC_RX_RX2_RX_PATH_MIX_SEC0:
- case CDC_RX_RX2_RX_PATH_MIX_SEC1:
- case CDC_RX_RX2_RX_PATH_DSM_CTL:
case CDC_RX_IDLE_DETECT_PATH_CTL:
case CDC_RX_IDLE_DETECT_CFG0:
case CDC_RX_IDLE_DETECT_CFG1:
@@ -1435,6 +1601,22 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
return true;
}
+ switch (rx->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ return rx_pre_2_5_is_rw_register(dev, reg);
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ return rx_2_5_is_rw_register(dev, reg);
+ default:
+ break;
+ }
+
return false;
}
@@ -1491,8 +1673,6 @@ static const struct regmap_config rx_regmap_config = {
.val_bits = 32, /* 8 but with 32 bit read/write */
.reg_stride = 4,
.cache_type = REGCACHE_FLAT,
- .reg_defaults = rx_defaults,
- .num_reg_defaults = ARRAY_SIZE(rx_defaults),
.max_register = RX_MAX_OFFSET,
.writeable_reg = rx_is_writeable_register,
.volatile_reg = rx_is_volatile_register,
@@ -1502,18 +1682,19 @@ static const struct regmap_config rx_regmap_config = {
static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short look_ahead_dly_reg;
unsigned int val;
val = ucontrol->value.enumerated.item[0];
- if (e->reg == CDC_RX_RX0_RX_PATH_CFG1)
- look_ahead_dly_reg = CDC_RX_RX0_RX_PATH_CFG0;
- else if (e->reg == CDC_RX_RX1_RX_PATH_CFG1)
- look_ahead_dly_reg = CDC_RX_RX1_RX_PATH_CFG0;
+ if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 0))
+ look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0);
+ else if (e->reg == CDC_RX_RXn_RX_PATH_CFG1(rx, 1))
+ look_ahead_dly_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1);
/* Set Look Ahead Delay */
if (val)
@@ -1534,6 +1715,10 @@ static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_int1_dem_inp_enum,
snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+static const struct snd_kcontrol_new rx_2_5_int1_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("rx_int1_dem_inp", rx_2_5_int1_dem_inp_enum,
+ snd_soc_dapm_get_enum_double, rx_macro_int_dem_inp_mux_put);
+
static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
int rate_reg_val, u32 sample_rate)
{
@@ -1567,7 +1752,7 @@ static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) {
- int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(j);
+ int_fs_reg = CDC_RX_RXn_RX_PATH_CTL(rx, j);
/* sample_rate is in Hz */
snd_soc_component_update_bits(component, int_fs_reg,
CDC_RX_PATH_PCM_RATE_MASK,
@@ -1600,7 +1785,7 @@ static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
CDC_RX_INTX_2_SEL_MASK);
if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
- int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
+ int_fs_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j);
snd_soc_component_update_bits(component, int_fs_reg,
CDC_RX_RXn_MIX_PCM_RATE_MASK,
rate_reg_val);
@@ -1654,7 +1839,7 @@ static int rx_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
+static int rx_macro_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)
{
@@ -1719,55 +1904,49 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai,
static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
- uint16_t j, reg, mix_reg, dsm_reg;
- u16 int_mux_cfg0, int_mux_cfg1;
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+ u32 port, j, reg, mix_reg, int_mux_cfg0, int_mux_cfg1;
+ u32 mask, val;
u8 int_mux_cfg0_val, int_mux_cfg1_val;
- switch (dai->id) {
- case RX_MACRO_AIF1_PB:
- case RX_MACRO_AIF2_PB:
- case RX_MACRO_AIF3_PB:
- case RX_MACRO_AIF4_PB:
- for (j = 0; j < INTERP_MAX; j++) {
- reg = CDC_RX_RXn_RX_PATH_CTL(j);
- mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(j);
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(j);
-
- if (mute) {
- snd_soc_component_update_bits(component, reg,
- CDC_RX_PATH_PGA_MUTE_MASK,
- CDC_RX_PATH_PGA_MUTE_ENABLE);
- snd_soc_component_update_bits(component, mix_reg,
- CDC_RX_PATH_PGA_MUTE_MASK,
- CDC_RX_PATH_PGA_MUTE_ENABLE);
- } else {
- snd_soc_component_update_bits(component, reg,
- CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
- snd_soc_component_update_bits(component, mix_reg,
- CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
- }
+ if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
- if (j == INTERP_AUX)
- dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
+ for (j = 0; j < INTERP_MAX; j++) {
+ reg = CDC_RX_RXn_RX_PATH_CTL(rx, j);
+ mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, j);
+
+ mask = CDC_RX_PATH_PGA_MUTE_MASK;
+ val = 0;
+ if (mute)
+ val |= CDC_RX_PATH_PGA_MUTE_ENABLE;
+ if (rx->main_clk_users[j] > 0) {
+ mask |= CDC_RX_PATH_CLK_EN_MASK;
+ val |= CDC_RX_PATH_CLK_ENABLE;
+ }
- int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
- int_mux_cfg1 = int_mux_cfg0 + 4;
- int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
- int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
-
- if (snd_soc_component_read(component, dsm_reg) & 0x01) {
- if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0))
- snd_soc_component_update_bits(component, reg, 0x20, 0x20);
- if (int_mux_cfg1_val & 0x0F) {
- snd_soc_component_update_bits(component, reg, 0x20, 0x20);
- snd_soc_component_update_bits(component, mix_reg, 0x20,
- 0x20);
+ int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
+ int_mux_cfg1 = int_mux_cfg0 + 4;
+ int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
+ int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
+
+ for_each_set_bit(port, &rx->active_ch_mask[dai->id], RX_MACRO_PORTS_MAX) {
+ if (((int_mux_cfg0_val & 0x0f) == port + INTn_1_INP_SEL_RX0) ||
+ ((int_mux_cfg0_val >> 4) == port + INTn_1_INP_SEL_RX0) ||
+ ((int_mux_cfg1_val >> 4) == port + INTn_1_INP_SEL_RX0)) {
+ snd_soc_component_update_bits(component, reg, mask, val);
+ }
+
+ if ((int_mux_cfg1_val & 0x0f) == port + INTn_2_INP_SEL_RX0) {
+ snd_soc_component_update_bits(component, mix_reg, mask, val);
+ /* main clock needs to be enabled for mix to be useful: */
+ if (rx->main_clk_users[j] > 0) {
+ snd_soc_component_update_bits(component, reg,
+ CDC_RX_PATH_CLK_EN_MASK,
+ CDC_RX_PATH_CLK_ENABLE);
}
}
}
- break;
- default:
- break;
}
return 0;
}
@@ -1956,10 +2135,11 @@ static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w,
int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
u16 gain_reg, reg;
- reg = CDC_RX_RXn_RX_PATH_CTL(w->shift);
- gain_reg = CDC_RX_RXn_RX_VOL_CTL(w->shift);
+ reg = CDC_RX_RXn_RX_PATH_CTL(rx, w->shift);
+ gain_reg = CDC_RX_RXn_RX_VOL_CTL(rx, w->shift);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1991,7 +2171,7 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
if (comp == INTERP_AUX)
return 0;
- pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(comp)) & 0x0F;
+ pcm_rate = snd_soc_component_read(component, CDC_RX_RXn_RX_PATH_CTL(rx, comp)) & 0x0F;
if (pcm_rate < 0x06)
val = 0x03;
else if (pcm_rate < 0x08)
@@ -2002,11 +2182,11 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
val = 0x00;
if (SND_SOC_DAPM_EVENT_ON(event))
- snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp),
CDC_RX_DC_COEFF_SEL_MASK, val);
if (SND_SOC_DAPM_EVENT_OFF(event))
- snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(comp),
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, comp),
CDC_RX_DC_COEFF_SEL_MASK, 0x3);
if (!rx->comp_enabled[comp])
return 0;
@@ -2019,14 +2199,14 @@ static int rx_macro_config_compander(struct snd_soc_component *component,
CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x1);
snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
CDC_RX_COMPANDERn_SOFT_RST_MASK, 0x0);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp),
CDC_RX_RXn_COMP_EN_MASK, 0x1);
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
CDC_RX_COMPANDERn_HALT_MASK, 0x1);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(comp),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG0(rx, comp),
CDC_RX_RXn_COMP_EN_MASK, 0x0);
snd_soc_component_write_field(component, CDC_RX_COMPANDERn_CTL0(comp),
CDC_RX_COMPANDERn_CLK_EN_MASK, 0x0);
@@ -2125,13 +2305,13 @@ static int rx_macro_config_aux_hpf(struct snd_soc_component *component,
/* Update Aux HPF control */
if (!rx->is_aux_hpf_on)
snd_soc_component_update_bits(component,
- CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x00);
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x00);
}
if (SND_SOC_DAPM_EVENT_OFF(event)) {
/* Reset to default (HPF=ON) */
snd_soc_component_update_bits(component,
- CDC_RX_RX2_RX_PATH_CFG1, 0x04, 0x04);
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 2), 0x04, 0x04);
}
return 0;
@@ -2183,7 +2363,7 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
CDC_RX_CLSH_DECAY_CTRL,
CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
snd_soc_component_write_field(component,
- CDC_RX_RX0_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 0),
CDC_RX_RXn_CLSH_EN_MASK, 0x1);
break;
case INTERP_HPHR:
@@ -2199,15 +2379,15 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
CDC_RX_CLSH_DECAY_CTRL,
CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
snd_soc_component_write_field(component,
- CDC_RX_RX1_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 1),
CDC_RX_RXn_CLSH_EN_MASK, 0x1);
break;
case INTERP_AUX:
snd_soc_component_update_bits(component,
- CDC_RX_RX2_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 2),
CDC_RX_RX2_DLY_Z_EN_MASK, 1);
snd_soc_component_write_field(component,
- CDC_RX_RX2_RX_PATH_CFG0,
+ CDC_RX_RXn_RX_PATH_CFG0(rx, 2),
CDC_RX_RX2_CLSH_EN_MASK, 1);
break;
}
@@ -2218,16 +2398,17 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
static void rx_macro_hd2_control(struct snd_soc_component *component,
u16 interp_idx, int event)
{
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
u16 hd2_scale_reg, hd2_enable_reg;
switch (interp_idx) {
case INTERP_HPHL:
- hd2_scale_reg = CDC_RX_RX0_RX_PATH_SEC3;
- hd2_enable_reg = CDC_RX_RX0_RX_PATH_CFG0;
+ hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 0);
+ hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 0);
break;
case INTERP_HPHR:
- hd2_scale_reg = CDC_RX_RX1_RX_PATH_SEC3;
- hd2_enable_reg = CDC_RX_RX1_RX_PATH_CFG0;
+ hd2_scale_reg = CDC_RX_RXn_RX_PATH_SEC3(rx, 1);
+ hd2_enable_reg = CDC_RX_RXn_RX_PATH_CFG0(rx, 1);
break;
}
@@ -2249,8 +2430,7 @@ static void rx_macro_hd2_control(struct snd_soc_component *component,
static int rx_macro_get_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
@@ -2261,7 +2441,7 @@ static int rx_macro_get_compander(struct snd_kcontrol *kcontrol,
static int rx_macro_set_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
int value = ucontrol->value.integer.value[0];
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
@@ -2274,7 +2454,7 @@ static int rx_macro_set_compander(struct snd_kcontrol *kcontrol,
static int rx_macro_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
@@ -2286,11 +2466,12 @@ static int rx_macro_mux_get(struct snd_kcontrol *kcontrol,
static int rx_macro_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
u32 rx_port_value = ucontrol->value.enumerated.item[0];
+ unsigned int dai_id;
u32 aif_rst;
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
@@ -2307,19 +2488,24 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcontrol,
switch (rx_port_value) {
case 0:
- if (rx->active_ch_cnt[aif_rst]) {
- clear_bit(widget->shift,
- &rx->active_ch_mask[aif_rst]);
- rx->active_ch_cnt[aif_rst]--;
+ /*
+ * active_ch_cnt and active_ch_mask use DAI IDs (RX_MACRO_MAX_DAIS).
+ * active_ch_cnt == 0 was tested in if() above.
+ */
+ dai_id = aif_rst - 1;
+ if (rx->active_ch_cnt[dai_id]) {
+ clear_bit(widget->shift, &rx->active_ch_mask[dai_id]);
+ rx->active_ch_cnt[dai_id]--;
}
break;
case 1:
case 2:
case 3:
case 4:
- set_bit(widget->shift,
- &rx->active_ch_mask[rx_port_value]);
- rx->active_ch_cnt[rx_port_value]++;
+ /* active_ch_cnt and active_ch_mask use DAI IDs (WSA_MACRO_MAX_DAIS). */
+ dai_id = rx_port_value - 1;
+ set_bit(widget->shift, &rx->active_ch_mask[dai_id]);
+ rx->active_ch_cnt[dai_id]++;
break;
default:
dev_err(component->dev,
@@ -2357,7 +2543,7 @@ static const struct snd_kcontrol_new rx_macro_rx5_mux =
static int rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rx->is_ear_mode_on;
@@ -2367,7 +2553,7 @@ static int rx_macro_get_ear_mode(struct snd_kcontrol *kcontrol,
static int rx_macro_put_ear_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
rx->is_ear_mode_on = (!ucontrol->value.integer.value[0] ? false : true);
@@ -2377,7 +2563,7 @@ static int rx_macro_put_ear_mode(struct snd_kcontrol *kcontrol,
static int rx_macro_get_hph_hd2_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rx->hph_hd2_mode;
@@ -2387,7 +2573,7 @@ static int rx_macro_get_hph_hd2_mode(struct snd_kcontrol *kcontrol,
static int rx_macro_put_hph_hd2_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
rx->hph_hd2_mode = ucontrol->value.integer.value[0];
@@ -2397,7 +2583,7 @@ static int rx_macro_put_hph_hd2_mode(struct snd_kcontrol *kcontrol,
static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = rx->hph_pwr_mode;
@@ -2407,7 +2593,7 @@ static int rx_macro_get_hph_pwr_mode(struct snd_kcontrol *kcontrol,
static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
rx->hph_pwr_mode = ucontrol->value.enumerated.item[0];
@@ -2417,7 +2603,7 @@ static int rx_macro_put_hph_pwr_mode(struct snd_kcontrol *kcontrol,
static int rx_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rx->is_softclip_on;
@@ -2428,7 +2614,7 @@ static int rx_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
static int rx_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
rx->is_softclip_on = ucontrol->value.integer.value[0];
@@ -2439,7 +2625,7 @@ static int rx_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
static int rx_macro_aux_hpf_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rx->is_aux_hpf_on;
@@ -2450,7 +2636,7 @@ static int rx_macro_aux_hpf_mode_get(struct snd_kcontrol *kcontrol,
static int rx_macro_aux_hpf_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
rx->is_aux_hpf_on = ucontrol->value.integer.value[0];
@@ -2482,7 +2668,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
if (interp_idx == INTERP_HPHL) {
if (rx->is_ear_mode_on)
snd_soc_component_write_field(component,
- CDC_RX_RX0_RX_PATH_CFG1,
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 0),
CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x1);
else
snd_soc_component_write_field(component,
@@ -2499,7 +2685,7 @@ static int rx_macro_hphdelay_lutbypass(struct snd_soc_component *component,
if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
snd_soc_component_write_field(component,
- CDC_RX_RX0_RX_PATH_CFG1,
+ CDC_RX_RXn_RX_PATH_CFG1(rx, 0),
CDC_RX_RX0_HPH_L_EAR_SEL_MASK, 0x0);
snd_soc_component_update_bits(component, hph_lut_bypass_reg,
CDC_RX_TOP_HPH_LUT_BYPASS_MASK, 0);
@@ -2516,11 +2702,9 @@ static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
u16 main_reg, dsm_reg, rx_cfg2_reg;
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
- main_reg = CDC_RX_RXn_RX_PATH_CTL(interp_idx);
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(interp_idx);
- if (interp_idx == INTERP_AUX)
- dsm_reg = CDC_RX_RX2_RX_PATH_DSM_CTL;
- rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(interp_idx);
+ main_reg = CDC_RX_RXn_RX_PATH_CTL(rx, interp_idx);
+ dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, interp_idx);
+ rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(rx, interp_idx);
if (SND_SOC_DAPM_EVENT_ON(event)) {
if (rx->main_clk_users[interp_idx] == 0) {
@@ -2587,10 +2771,11 @@ static int rx_macro_enable_mix_path(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 rx_macro *rx = snd_soc_component_get_drvdata(component);
u16 gain_reg, mix_reg;
- gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(w->shift);
- mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(w->shift);
+ gain_reg = CDC_RX_RXn_RX_VOL_MIX_CTL(rx, w->shift);
+ mix_reg = CDC_RX_RXn_RX_PATH_MIX_CTL(rx, w->shift);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -2621,17 +2806,18 @@ static int rx_macro_enable_rx_path_clk(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rx_macro *rx = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
rx_macro_enable_interp_clk(component, event, w->shift);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift),
CDC_RX_RXn_SIDETONE_EN_MASK, 1);
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(w->shift),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CTL(rx, w->shift),
CDC_RX_PATH_CLK_EN_MASK, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(w->shift),
+ snd_soc_component_write_field(component, CDC_RX_RXn_RX_PATH_CFG1(rx, w->shift),
CDC_RX_RXn_SIDETONE_EN_MASK, 0);
rx_macro_enable_interp_clk(component, event, w->shift);
break;
@@ -2739,8 +2925,7 @@ static int rx_macro_put_iir_band_audio_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd_iir_filter_ctl *ctl =
(struct wcd_iir_filter_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -2768,8 +2953,7 @@ static int rx_macro_put_iir_band_audio_mixer(
static int rx_macro_get_iir_band_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd_iir_filter_ctl *ctl =
(struct wcd_iir_filter_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -2801,20 +2985,34 @@ static int rx_macro_iir_filter_info(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
- SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
- -84, 40, digital_gain),
+static const struct snd_kcontrol_new rx_macro_def_snd_controls[] = {
SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_RX_RX1_RX_VOL_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_RX_RX2_RX_VOL_CTL,
-84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
- -84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_RX_RX1_RX_VOL_MIX_CTL,
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_RX_RX2_RX_VOL_MIX_CTL,
-84, 40, digital_gain),
+};
+
+static const struct snd_kcontrol_new rx_macro_2_5_snd_controls[] = {
+
+ SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", CDC_2_5_RX_RX1_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", CDC_2_5_RX_RX2_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", CDC_2_5_RX_RX1_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", CDC_2_5_RX_RX2_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+};
+static const struct snd_kcontrol_new rx_macro_snd_controls[] = {
+ SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", CDC_RX_RX0_RX_VOL_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", CDC_RX_RX0_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0,
rx_macro_get_compander, rx_macro_set_compander),
SOC_SINGLE_EXT("RX_COMP2 Switch", SND_SOC_NOPM, RX_MACRO_COMP2, 1, 0,
@@ -2906,14 +3104,14 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
val = snd_soc_component_read(component,
CDC_RX_INP_MUX_RX_MIX_CFG4);
- if (!(strcmp(w->name, "RX MIX TX0 MUX")))
+ if (!(snd_soc_dapm_widget_name_cmp(w, "RX MIX TX0 MUX")))
ec_tx = ((val & 0xf0) >> 0x4) - 1;
- else if (!(strcmp(w->name, "RX MIX TX1 MUX")))
+ else if (!(snd_soc_dapm_widget_name_cmp(w, "RX MIX TX1 MUX")))
ec_tx = (val & 0x0f) - 1;
val = snd_soc_component_read(component,
CDC_RX_INP_MUX_RX_MIX_CFG5);
- if (!(strcmp(w->name, "RX MIX TX2 MUX")))
+ if (!(snd_soc_dapm_widget_name_cmp(w, "RX MIX TX2 MUX")))
ec_tx = (val & 0x0f) - 1;
if (ec_tx < 0 || (ec_tx >= RX_MACRO_EC_MUX_MAX)) {
@@ -2932,6 +3130,16 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
return 0;
}
+static const struct snd_soc_dapm_widget rx_macro_2_5_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_2_5_int1_dem_inp_mux),
+};
+
+static const struct snd_soc_dapm_widget rx_macro_def_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int1_dem_inp_mux),
+};
+
static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("RX AIF1 PB", "RX_MACRO_AIF1 Playback", 0,
SND_SOC_NOPM, 0, 0),
@@ -3003,8 +3211,6 @@ static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = {
SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
&rx_int0_dem_inp_mux),
- SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
- &rx_int1_dem_inp_mux),
SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", SND_SOC_NOPM, INTERP_HPHL, 0,
&rx_int0_2_mux, rx_macro_enable_mix_path,
@@ -3399,32 +3605,65 @@ static const struct snd_soc_dapm_route rx_audio_map[] = {
static int rx_macro_component_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rx_macro *rx = snd_soc_component_get_drvdata(component);
+ const struct snd_soc_dapm_widget *widgets;
+ const struct snd_kcontrol_new *controls;
+ unsigned int num_controls, num_widgets;
+ int ret;
snd_soc_component_init_regmap(component, rx->regmap);
- snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_SEC7,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 0),
CDC_RX_DSM_OUT_DELAY_SEL_MASK,
CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
- snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_SEC7,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 1),
CDC_RX_DSM_OUT_DELAY_SEL_MASK,
CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
- snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_SEC7,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_SEC7(rx, 2),
CDC_RX_DSM_OUT_DELAY_SEL_MASK,
CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE);
- snd_soc_component_update_bits(component, CDC_RX_RX0_RX_PATH_CFG3,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 0),
CDC_RX_DC_COEFF_SEL_MASK,
CDC_RX_DC_COEFF_SEL_TWO);
- snd_soc_component_update_bits(component, CDC_RX_RX1_RX_PATH_CFG3,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 1),
CDC_RX_DC_COEFF_SEL_MASK,
CDC_RX_DC_COEFF_SEL_TWO);
- snd_soc_component_update_bits(component, CDC_RX_RX2_RX_PATH_CFG3,
+ snd_soc_component_update_bits(component, CDC_RX_RXn_RX_PATH_CFG3(rx, 2),
CDC_RX_DC_COEFF_SEL_MASK,
CDC_RX_DC_COEFF_SEL_TWO);
+ switch (rx->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ controls = rx_macro_def_snd_controls;
+ num_controls = ARRAY_SIZE(rx_macro_def_snd_controls);
+ widgets = rx_macro_def_dapm_widgets;
+ num_widgets = ARRAY_SIZE(rx_macro_def_dapm_widgets);
+ break;
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ controls = rx_macro_2_5_snd_controls;
+ num_controls = ARRAY_SIZE(rx_macro_2_5_snd_controls);
+ widgets = rx_macro_2_5_dapm_widgets;
+ num_widgets = ARRAY_SIZE(rx_macro_2_5_dapm_widgets);
+ break;
+ default:
+ return -EINVAL;
+ }
+
rx->component = component;
- return 0;
+ ret = snd_soc_add_component_controls(component, controls, num_controls);
+ if (ret)
+ return ret;
+
+ return snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
}
static int swclk_gate_enable(struct clk_hw *hw)
@@ -3527,7 +3766,7 @@ static int rx_macro_probe(struct platform_device *pdev)
kernel_ulong_t flags;
struct rx_macro *rx;
void __iomem *base;
- int ret;
+ int ret, def_count;
flags = (kernel_ulong_t)device_get_match_data(dev);
@@ -3537,41 +3776,88 @@ static int rx_macro_probe(struct platform_device *pdev)
rx->macro = devm_clk_get_optional(dev, "macro");
if (IS_ERR(rx->macro))
- return PTR_ERR(rx->macro);
+ return dev_err_probe(dev, PTR_ERR(rx->macro), "unable to get macro clock\n");
rx->dcodec = devm_clk_get_optional(dev, "dcodec");
if (IS_ERR(rx->dcodec))
- return PTR_ERR(rx->dcodec);
+ return dev_err_probe(dev, PTR_ERR(rx->dcodec), "unable to get dcodec clock\n");
rx->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(rx->mclk))
- return PTR_ERR(rx->mclk);
+ return dev_err_probe(dev, PTR_ERR(rx->mclk), "unable to get mclk clock\n");
if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
rx->npl = devm_clk_get(dev, "npl");
if (IS_ERR(rx->npl))
- return PTR_ERR(rx->npl);
+ return dev_err_probe(dev, PTR_ERR(rx->npl), "unable to get npl clock\n");
}
rx->fsgen = devm_clk_get(dev, "fsgen");
if (IS_ERR(rx->fsgen))
- return PTR_ERR(rx->fsgen);
+ return dev_err_probe(dev, PTR_ERR(rx->fsgen), "unable to get fsgen clock\n");
rx->pds = lpass_macro_pds_init(dev);
if (IS_ERR(rx->pds))
return PTR_ERR(rx->pds);
+ ret = devm_add_action_or_reset(dev, lpass_macro_pds_exit_action, rx->pds);
+ if (ret)
+ return ret;
+
base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- ret = PTR_ERR(base);
- goto err;
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rx->codec_version = lpass_macro_get_codec_version();
+ struct reg_default *reg_defaults __free(kfree) = NULL;
+
+ switch (rx->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ rx->rxn_reg_stride = 0x80;
+ rx->rxn_reg_stride2 = 0xc;
+ def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults);
+ reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], rx_defaults, sizeof(rx_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(rx_defaults)],
+ rx_pre_2_5_defaults, sizeof(rx_pre_2_5_defaults));
+ break;
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ rx->rxn_reg_stride = 0xc0;
+ rx->rxn_reg_stride2 = 0x0;
+ def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults);
+ reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], rx_defaults, sizeof(rx_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(rx_defaults)],
+ rx_2_5_defaults, sizeof(rx_2_5_defaults));
+ break;
+ default:
+ dev_err(dev, "Unsupported Codec version (%d)\n", rx->codec_version);
+ return -EINVAL;
}
- rx->regmap = devm_regmap_init_mmio(dev, base, &rx_regmap_config);
- if (IS_ERR(rx->regmap)) {
- ret = PTR_ERR(rx->regmap);
- goto err;
- }
+ struct regmap_config *reg_config __free(kfree) = kmemdup(&rx_regmap_config,
+ sizeof(*reg_config),
+ GFP_KERNEL);
+ if (!reg_config)
+ return -ENOMEM;
+
+ reg_config->reg_defaults = reg_defaults;
+ reg_config->num_reg_defaults = def_count;
+
+ rx->regmap = devm_regmap_init_mmio(dev, base, reg_config);
+ if (IS_ERR(rx->regmap))
+ return PTR_ERR(rx->regmap);
dev_set_drvdata(dev, rx);
@@ -3583,7 +3869,7 @@ static int rx_macro_probe(struct platform_device *pdev)
ret = clk_prepare_enable(rx->macro);
if (ret)
- goto err;
+ return ret;
ret = clk_prepare_enable(rx->dcodec);
if (ret)
@@ -3641,8 +3927,6 @@ err_mclk:
clk_disable_unprepare(rx->dcodec);
err_dcodec:
clk_disable_unprepare(rx->macro);
-err:
- lpass_macro_pds_exit(rx->pds);
return ret;
}
@@ -3656,8 +3940,6 @@ static void rx_macro_remove(struct platform_device *pdev)
clk_disable_unprepare(rx->fsgen);
clk_disable_unprepare(rx->macro);
clk_disable_unprepare(rx->dcodec);
-
- lpass_macro_pds_exit(rx->pds);
}
static const struct of_device_id rx_macro_dt_match[] = {
@@ -3666,6 +3948,9 @@ static const struct of_device_id rx_macro_dt_match[] = {
.data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
}, {
+ .compatible = "qcom,sm6115-lpass-rx-macro",
+ .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
+ }, {
.compatible = "qcom,sm8250-lpass-rx-macro",
.data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
}, {
@@ -3681,7 +3966,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);
@@ -3695,7 +3980,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;
@@ -3730,7 +4015,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 = {
@@ -3738,10 +4023,10 @@ 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_new = rx_macro_remove,
+ .remove = rx_macro_remove,
};
module_platform_driver(rx_macro_driver);
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index da6fcf7f0991..f7d168f557dd 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -38,6 +38,8 @@
#define CDC_TX_TOP_CSR_I2S_RESET (0x00AC)
#define CDC_TX_TOP_CSR_SWR_DMICn_CTL(n) (0x00C0 + n * 0x4)
#define CDC_TX_TOP_CSR_SWR_DMIC0_CTL (0x00C0)
+/* Default divider for AMIC and DMIC clock: DIV2 */
+#define CDC_TX_SWR_MIC_CLK_DEFAULT 0
#define CDC_TX_SWR_DMIC_CLK_SEL_MASK GENMASK(3, 1)
#define CDC_TX_TOP_CSR_SWR_DMIC1_CTL (0x00C4)
#define CDC_TX_TOP_CSR_SWR_DMIC2_CTL (0x00C8)
@@ -206,7 +208,6 @@
#define MCLK_FREQ 19200000
enum {
- TX_MACRO_AIF_INVALID = 0,
TX_MACRO_AIF1_CAP,
TX_MACRO_AIF2_CAP,
TX_MACRO_AIF3_CAP,
@@ -253,8 +254,18 @@ struct hpf_work {
struct delayed_work dwork;
};
+struct tx_macro_data {
+ unsigned int flags;
+ unsigned int ver;
+ const struct snd_soc_dapm_widget *extra_widgets;
+ size_t extra_widgets_num;
+ const struct snd_soc_dapm_route *extra_routes;
+ size_t extra_routes_num;
+};
+
struct tx_macro {
struct device *dev;
+ const struct tx_macro_data *data;
struct snd_soc_component *component;
struct hpf_work tx_hpf_work[NUM_DECIMATORS];
struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
@@ -270,7 +281,6 @@ struct tx_macro {
struct clk_hw hw;
bool dec_active[NUM_DECIMATORS];
int tx_mclk_users;
- u16 dmic_clk_div;
bool bcs_enable;
int dec_mode[NUM_DECIMATORS];
struct lpass_macro *pds;
@@ -431,6 +441,8 @@ static bool tx_is_volatile_register(struct device *dev, unsigned int reg)
case CDC_TX_TOP_CSR_SWR_DMIC1_CTL:
case CDC_TX_TOP_CSR_SWR_DMIC2_CTL:
case CDC_TX_TOP_CSR_SWR_DMIC3_CTL:
+ case CDC_TX_TOP_CSR_SWR_AMIC0_CTL:
+ case CDC_TX_TOP_CSR_SWR_AMIC1_CTL:
return true;
}
return false;
@@ -635,13 +647,18 @@ exit:
return 0;
}
-static bool is_amic_enabled(struct snd_soc_component *component, u8 decimator)
+static bool is_amic_enabled(struct snd_soc_component *component,
+ struct tx_macro *tx, u8 decimator)
{
u16 adc_mux_reg, adc_reg, adc_n;
adc_mux_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG1(decimator);
if (snd_soc_component_read(component, adc_mux_reg) & SWR_MIC) {
+ if (tx->data->ver > LPASS_VER_9_0_0)
+ return true;
+
+ /* else: LPASS <= v9.0.0 */
adc_reg = CDC_TX_INP_MUX_ADC_MUXn_CFG0(decimator);
adc_n = snd_soc_component_read_field(component, adc_reg,
CDC_TX_MACRO_SWR_MIC_MUX_SEL_MASK);
@@ -670,7 +687,7 @@ static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work)
dec_cfg_reg = CDC_TXn_TX_PATH_CFG0(hpf_work->decimator);
hpf_gate_reg = CDC_TXn_TX_PATH_SEC2(hpf_work->decimator);
- if (is_amic_enabled(component, hpf_work->decimator)) {
+ if (is_amic_enabled(component, tx, hpf_work->decimator)) {
snd_soc_component_write_field(component,
dec_cfg_reg,
CDC_TXn_HPF_CUT_FREQ_MASK,
@@ -734,18 +751,65 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static void tx_macro_update_smic_sel_v9(struct snd_soc_component *component,
+ struct snd_soc_dapm_widget *widget,
+ struct tx_macro *tx, u16 mic_sel_reg,
+ unsigned int val)
+{
+ unsigned int dmic;
+ u16 dmic_clk_reg;
+
+ if (val < 5) {
+ snd_soc_component_write_field(component, mic_sel_reg,
+ CDC_TXn_ADC_DMIC_SEL_MASK, 0);
+ } else {
+ snd_soc_component_write_field(component, mic_sel_reg,
+ CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+ dmic = TX_ADC_TO_DMIC(val);
+ dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+ snd_soc_component_write_field(component, dmic_clk_reg,
+ CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+ CDC_TX_SWR_MIC_CLK_DEFAULT);
+ }
+}
+
+static void tx_macro_update_smic_sel_v9_2(struct snd_soc_component *component,
+ struct snd_soc_dapm_widget *widget,
+ struct tx_macro *tx, u16 mic_sel_reg,
+ unsigned int val)
+{
+ unsigned int dmic;
+ u16 dmic_clk_reg;
+
+ if (widget->shift) {
+ /* MSM DMIC */
+ snd_soc_component_write_field(component, mic_sel_reg,
+ CDC_TXn_ADC_DMIC_SEL_MASK, 1);
+
+ dmic = TX_ADC_TO_DMIC(val);
+ dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
+ snd_soc_component_write_field(component, dmic_clk_reg,
+ CDC_TX_SWR_DMIC_CLK_SEL_MASK,
+ CDC_TX_SWR_MIC_CLK_DEFAULT);
+ } else {
+ snd_soc_component_write_field(component, mic_sel_reg,
+ CDC_TXn_ADC_DMIC_SEL_MASK, 0);
+ }
+}
+
static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val, dmic;
- u16 mic_sel_reg;
- u16 dmic_clk_reg;
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+ unsigned int val;
+ u16 mic_sel_reg;
val = ucontrol->value.enumerated.item[0];
+ if (val >= e->items)
+ return -EINVAL;
switch (e->reg) {
case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
@@ -772,24 +836,21 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
mic_sel_reg = CDC_TX7_TX_PATH_CFG0;
break;
+ default:
+ dev_err(component->dev, "Error in configuration!!\n");
+ return -EINVAL;
}
if (val != 0) {
- if (widget->shift) { /* MSM DMIC */
+ if (widget->shift) /* MSM DMIC */
snd_soc_component_write_field(component, mic_sel_reg,
CDC_TXn_ADC_DMIC_SEL_MASK, 1);
- } else if (val < 5) {
- snd_soc_component_write_field(component, mic_sel_reg,
- CDC_TXn_ADC_DMIC_SEL_MASK, 0);
- } else {
- snd_soc_component_write_field(component, mic_sel_reg,
- CDC_TXn_ADC_DMIC_SEL_MASK, 1);
- dmic = TX_ADC_TO_DMIC(val);
- dmic_clk_reg = CDC_TX_TOP_CSR_SWR_DMICn_CTL(dmic);
- snd_soc_component_write_field(component, dmic_clk_reg,
- CDC_TX_SWR_DMIC_CLK_SEL_MASK,
- tx->dmic_clk_div);
- }
+ else if (tx->data->ver <= LPASS_VER_9_0_0)
+ tx_macro_update_smic_sel_v9(component, widget, tx,
+ mic_sel_reg, val);
+ else
+ tx_macro_update_smic_sel_v9_2(component, widget, tx,
+ mic_sel_reg, val);
}
return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
@@ -798,7 +859,7 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
static int tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
u32 dai_id = widget->shift;
@@ -816,7 +877,7 @@ static int tx_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
static int tx_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct snd_soc_dapm_update *update = NULL;
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
@@ -877,7 +938,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
snd_soc_component_write_field(component, dmic_clk_reg,
CDC_TX_SWR_DMIC_CLK_SEL_MASK,
- tx->dmic_clk_div);
+ CDC_TX_SWR_MIC_CLK_DEFAULT);
}
}
snd_soc_component_write_field(component, dec_cfg_reg,
@@ -890,7 +951,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
snd_soc_component_write_field(component, tx_vol_ctl_reg,
CDC_TXn_CLK_EN_MASK, 0x1);
- if (!is_amic_enabled(component, decimator)) {
+ if (!is_amic_enabled(component, tx, decimator)) {
snd_soc_component_update_bits(component, hpf_gate_reg, 0x01, 0x00);
/* Minimum 1 clk cycle delay is required as per HW spec */
usleep_range(1000, 1010);
@@ -906,7 +967,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
CDC_TXn_HPF_CUT_FREQ_MASK,
CF_MIN_3DB_150HZ);
- if (is_amic_enabled(component, decimator)) {
+ if (is_amic_enabled(component, tx, decimator)) {
hpf_delay = TX_MACRO_AMIC_HPF_DELAY_MS;
unmute_delay = TX_MACRO_AMIC_UNMUTE_DELAY_MS;
}
@@ -922,7 +983,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
CDC_TXn_HPF_F_CHANGE_MASK |
CDC_TXn_HPF_ZERO_GATE_MASK,
0x02);
- if (!is_amic_enabled(component, decimator))
+ if (!is_amic_enabled(component, tx, decimator))
snd_soc_component_update_bits(component, hpf_gate_reg,
CDC_TXn_HPF_F_CHANGE_MASK |
CDC_TXn_HPF_ZERO_GATE_MASK,
@@ -959,7 +1020,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
component, dec_cfg_reg,
CDC_TXn_HPF_CUT_FREQ_MASK,
hpf_cut_off_freq);
- if (is_amic_enabled(component, decimator))
+ if (is_amic_enabled(component, tx, decimator))
snd_soc_component_update_bits(component,
hpf_gate_reg,
CDC_TXn_HPF_F_CHANGE_MASK |
@@ -1009,7 +1070,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
static int tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -1022,7 +1083,7 @@ static int tx_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int value = ucontrol->value.integer.value[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -1039,7 +1100,7 @@ static int tx_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = tx->bcs_enable;
@@ -1050,7 +1111,7 @@ static int tx_macro_get_bcs(struct snd_kcontrol *kcontrol,
static int tx_macro_set_bcs(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int value = ucontrol->value.integer.value[0];
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
@@ -1105,7 +1166,7 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int tx_macro_get_channel_map(struct snd_soc_dai *dai,
+static int tx_macro_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)
{
@@ -1230,53 +1291,6 @@ static const struct snd_kcontrol_new tx_dec5_mux = SOC_DAPM_ENUM("tx_dec5", tx_d
static const struct snd_kcontrol_new tx_dec6_mux = SOC_DAPM_ENUM("tx_dec6", tx_dec6_enum);
static const struct snd_kcontrol_new tx_dec7_mux = SOC_DAPM_ENUM("tx_dec7", tx_dec7_enum);
-static const char * const smic_mux_text[] = {
- "ZERO", "ADC0", "ADC1", "ADC2", "ADC3", "SWR_DMIC0",
- "SWR_DMIC1", "SWR_DMIC2", "SWR_DMIC3", "SWR_DMIC4",
- "SWR_DMIC5", "SWR_DMIC6", "SWR_DMIC7"
-};
-
-static SOC_ENUM_SINGLE_DECL(tx_smic0_enum, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic1_enum, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic2_enum, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic3_enum, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic4_enum, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic5_enum, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic6_enum, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
- 0, smic_mux_text);
-
-static SOC_ENUM_SINGLE_DECL(tx_smic7_enum, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
- 0, smic_mux_text);
-
-static const struct snd_kcontrol_new tx_smic0_mux = SOC_DAPM_ENUM_EXT("tx_smic0", tx_smic0_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic1_mux = SOC_DAPM_ENUM_EXT("tx_smic1", tx_smic1_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic2_mux = SOC_DAPM_ENUM_EXT("tx_smic2", tx_smic2_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic3_mux = SOC_DAPM_ENUM_EXT("tx_smic3", tx_smic3_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic4_mux = SOC_DAPM_ENUM_EXT("tx_smic4", tx_smic4_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic5_mux = SOC_DAPM_ENUM_EXT("tx_smic5", tx_smic5_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic6_mux = SOC_DAPM_ENUM_EXT("tx_smic6", tx_smic6_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-static const struct snd_kcontrol_new tx_smic7_mux = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum,
- snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
-
static const char * const dmic_mux_text[] = {
"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3",
"DMIC4", "DMIC5", "DMIC6", "DMIC7"
@@ -1422,15 +1436,6 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("TX_AIF3_CAP Mixer", SND_SOC_NOPM, TX_MACRO_AIF3_CAP, 0,
tx_aif3_cap_mixer, ARRAY_SIZE(tx_aif3_cap_mixer)),
- SND_SOC_DAPM_MUX("TX SMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_smic0_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_smic1_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_smic2_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_smic3_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_smic4_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_smic5_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux),
- SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux),
-
SND_SOC_DAPM_MUX("TX DMIC MUX0", SND_SOC_NOPM, 4, 0, &tx_dmic0_mux),
SND_SOC_DAPM_MUX("TX DMIC MUX1", SND_SOC_NOPM, 4, 0, &tx_dmic1_mux),
SND_SOC_DAPM_MUX("TX DMIC MUX2", SND_SOC_NOPM, 4, 0, &tx_dmic2_mux),
@@ -1440,18 +1445,6 @@ static const struct snd_soc_dapm_widget tx_macro_dapm_widgets[] = {
SND_SOC_DAPM_MUX("TX DMIC MUX6", SND_SOC_NOPM, 4, 0, &tx_dmic6_mux),
SND_SOC_DAPM_MUX("TX DMIC MUX7", SND_SOC_NOPM, 4, 0, &tx_dmic7_mux),
- SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
- SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
- SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
- SND_SOC_DAPM_INPUT("TX SWR_ADC3"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC0"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC1"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC2"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC3"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC4"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
- SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
SND_SOC_DAPM_INPUT("TX DMIC0"),
SND_SOC_DAPM_INPUT("TX DMIC1"),
SND_SOC_DAPM_INPUT("TX DMIC2"),
@@ -1573,6 +1566,150 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX DMIC MUX0", "DMIC6", "TX DMIC6"},
{"TX DMIC MUX0", "DMIC7", "TX DMIC7"},
+ {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
+ {"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX1", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX1", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX1", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX1", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX1", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX1", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
+ {"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX2", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX2", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX2", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX2", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX2", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX2", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
+ {"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX3", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX3", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX3", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX3", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX3", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX3", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"},
+ {"TX DMIC MUX4", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX4", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX4", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX4", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX4", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX4", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX4", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"},
+ {"TX DMIC MUX5", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX5", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX5", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX5", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX5", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX5", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX5", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"},
+ {"TX DMIC MUX6", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX6", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX6", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX6", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX6", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX6", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX6", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
+
+ {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"},
+ {"TX DMIC MUX7", "DMIC0", "TX DMIC0"},
+ {"TX DMIC MUX7", "DMIC1", "TX DMIC1"},
+ {"TX DMIC MUX7", "DMIC2", "TX DMIC2"},
+ {"TX DMIC MUX7", "DMIC3", "TX DMIC3"},
+ {"TX DMIC MUX7", "DMIC4", "TX DMIC4"},
+ {"TX DMIC MUX7", "DMIC5", "TX DMIC5"},
+ {"TX DMIC MUX7", "DMIC6", "TX DMIC6"},
+ {"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
+};
+
+/* Controls and routes specific to LPASS <= v9.0.0 */
+static const char * const smic_mux_text_v9[] = {
+ "ZERO", "ADC0", "ADC1", "ADC2", "ADC3", "SWR_DMIC0",
+ "SWR_DMIC1", "SWR_DMIC2", "SWR_DMIC3", "SWR_DMIC4",
+ "SWR_DMIC5", "SWR_DMIC6", "SWR_DMIC7"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_smic0_enum_v9, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic1_enum_v9, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic2_enum_v9, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic3_enum_v9, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic4_enum_v9, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic5_enum_v9, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic6_enum_v9, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+ 0, smic_mux_text_v9);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic7_enum_v9, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+ 0, smic_mux_text_v9);
+
+static const struct snd_kcontrol_new tx_smic0_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic0", tx_smic0_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic1_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic1", tx_smic1_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic2_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic2", tx_smic2_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic3_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic3", tx_smic3_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic4_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic4", tx_smic4_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic5_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic5", tx_smic5_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic6_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic6", tx_smic6_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic7_mux_v9 = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum_v9,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v9[] = {
+ SND_SOC_DAPM_MUX("TX SMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_smic0_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_smic1_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_smic2_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_smic3_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_smic4_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_smic5_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux_v9),
+ SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux_v9),
+
+ SND_SOC_DAPM_INPUT("TX SWR_ADC0"),
+ SND_SOC_DAPM_INPUT("TX SWR_ADC1"),
+ SND_SOC_DAPM_INPUT("TX SWR_ADC2"),
+ SND_SOC_DAPM_INPUT("TX SWR_ADC3"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC0"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC1"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC2"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC3"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC4"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC5"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC6"),
+ SND_SOC_DAPM_INPUT("TX SWR_DMIC7"),
+};
+
+static const struct snd_soc_dapm_route tx_audio_map_v9[] = {
{"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
{"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX0", "ADC0", "TX SWR_ADC0"},
@@ -1588,16 +1725,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX0", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX0", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC1 MUX", "MSM_DMIC", "TX DMIC MUX1"},
- {"TX DMIC MUX1", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX1", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX1", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX1", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX1", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX1", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX1", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX1", "DMIC7", "TX DMIC7"},
-
{"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
{"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX1", "ADC0", "TX SWR_ADC0"},
@@ -1613,16 +1740,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX1", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX1", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC2 MUX", "MSM_DMIC", "TX DMIC MUX2"},
- {"TX DMIC MUX2", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX2", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX2", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX2", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX2", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX2", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX2", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX2", "DMIC7", "TX DMIC7"},
-
{"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
{"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX2", "ADC0", "TX SWR_ADC0"},
@@ -1638,16 +1755,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX2", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX2", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC3 MUX", "MSM_DMIC", "TX DMIC MUX3"},
- {"TX DMIC MUX3", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX3", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX3", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX3", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX3", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX3", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX3", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX3", "DMIC7", "TX DMIC7"},
-
{"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
{"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX3", "ADC0", "TX SWR_ADC0"},
@@ -1663,16 +1770,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX3", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX3", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC4 MUX", "MSM_DMIC", "TX DMIC MUX4"},
- {"TX DMIC MUX4", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX4", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX4", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX4", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX4", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX4", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX4", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX4", "DMIC7", "TX DMIC7"},
-
{"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
{"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX4", "ADC0", "TX SWR_ADC0"},
@@ -1688,16 +1785,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX4", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX4", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC5 MUX", "MSM_DMIC", "TX DMIC MUX5"},
- {"TX DMIC MUX5", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX5", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX5", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX5", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX5", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX5", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX5", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX5", "DMIC7", "TX DMIC7"},
-
{"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
{"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX5", "ADC0", "TX SWR_ADC0"},
@@ -1713,16 +1800,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX5", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX5", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC6 MUX", "MSM_DMIC", "TX DMIC MUX6"},
- {"TX DMIC MUX6", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX6", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX6", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX6", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX6", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX6", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX6", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX6", "DMIC7", "TX DMIC7"},
-
{"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
{"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX6", "ADC0", "TX SWR_ADC0"},
@@ -1738,16 +1815,6 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX6", "SWR_DMIC6", "TX SWR_DMIC6"},
{"TX SMIC MUX6", "SWR_DMIC7", "TX SWR_DMIC7"},
- {"TX DEC7 MUX", "MSM_DMIC", "TX DMIC MUX7"},
- {"TX DMIC MUX7", "DMIC0", "TX DMIC0"},
- {"TX DMIC MUX7", "DMIC1", "TX DMIC1"},
- {"TX DMIC MUX7", "DMIC2", "TX DMIC2"},
- {"TX DMIC MUX7", "DMIC3", "TX DMIC3"},
- {"TX DMIC MUX7", "DMIC4", "TX DMIC4"},
- {"TX DMIC MUX7", "DMIC5", "TX DMIC5"},
- {"TX DMIC MUX7", "DMIC6", "TX DMIC6"},
- {"TX DMIC MUX7", "DMIC7", "TX DMIC7"},
-
{"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
{"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
{"TX SMIC MUX7", "ADC0", "TX SWR_ADC0"},
@@ -1764,6 +1831,200 @@ static const struct snd_soc_dapm_route tx_audio_map[] = {
{"TX SMIC MUX7", "SWR_DMIC7", "TX SWR_DMIC7"},
};
+/* Controls and routes specific to LPASS >= v9.2.0 */
+static const char * const smic_mux_text_v9_2[] = {
+ "ZERO", "SWR_MIC0", "SWR_MIC1", "SWR_MIC2", "SWR_MIC3",
+ "SWR_MIC4", "SWR_MIC5", "SWR_MIC6", "SWR_MIC7",
+ "SWR_MIC8", "SWR_MIC9", "SWR_MIC10", "SWR_MIC11"
+};
+
+static SOC_ENUM_SINGLE_DECL(tx_smic0_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX0_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic1_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX1_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic2_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX2_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic3_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX3_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic4_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX4_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic5_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX5_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic6_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX6_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static SOC_ENUM_SINGLE_DECL(tx_smic7_enum_v9_2, CDC_TX_INP_MUX_ADC_MUX7_CFG0,
+ 0, smic_mux_text_v9_2);
+
+static const struct snd_kcontrol_new tx_smic0_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic0", tx_smic0_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic1_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic1", tx_smic1_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic2_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic2", tx_smic2_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic3_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic3", tx_smic3_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic4_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic4", tx_smic4_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic5_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic5", tx_smic5_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic6_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic6", tx_smic6_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+static const struct snd_kcontrol_new tx_smic7_mux_v9_2 = SOC_DAPM_ENUM_EXT("tx_smic7", tx_smic7_enum_v9_2,
+ snd_soc_dapm_get_enum_double, tx_macro_put_dec_enum);
+
+static const struct snd_soc_dapm_widget tx_macro_dapm_widgets_v9_2[] = {
+ SND_SOC_DAPM_MUX("TX SMIC MUX0", SND_SOC_NOPM, 0, 0, &tx_smic0_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX1", SND_SOC_NOPM, 0, 0, &tx_smic1_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX2", SND_SOC_NOPM, 0, 0, &tx_smic2_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX3", SND_SOC_NOPM, 0, 0, &tx_smic3_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX4", SND_SOC_NOPM, 0, 0, &tx_smic4_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX5", SND_SOC_NOPM, 0, 0, &tx_smic5_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX6", SND_SOC_NOPM, 0, 0, &tx_smic6_mux_v9_2),
+ SND_SOC_DAPM_MUX("TX SMIC MUX7", SND_SOC_NOPM, 0, 0, &tx_smic7_mux_v9_2),
+
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT0"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT1"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT2"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT3"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT4"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT5"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT6"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT7"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT8"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT9"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT10"),
+ SND_SOC_DAPM_INPUT("TX SWR_INPUT11"),
+};
+
+static const struct snd_soc_dapm_route tx_audio_map_v9_2[] = {
+ {"TX DEC0 MUX", "SWR_MIC", "TX SMIC MUX0"},
+ {"TX SMIC MUX0", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX0", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX0", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX0", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX0", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX0", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX0", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX0", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX0", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX0", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX0", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX0", "SWR_MIC10", "TX SWR_INPUT11"},
+ {"TX SMIC MUX0", "SWR_MIC11", "TX SWR_INPUT10"},
+
+ {"TX DEC1 MUX", "SWR_MIC", "TX SMIC MUX1"},
+ {"TX SMIC MUX1", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX1", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX1", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX1", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX1", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX1", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX1", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX1", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX1", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX1", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX1", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX1", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX1", "SWR_MIC11", "TX SWR_INPUT11"},
+
+ {"TX DEC2 MUX", "SWR_MIC", "TX SMIC MUX2"},
+ {"TX SMIC MUX2", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX2", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX2", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX2", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX2", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX2", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX2", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX2", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX2", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX2", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX2", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX2", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX2", "SWR_MIC11", "TX SWR_INPUT11"},
+
+ {"TX DEC3 MUX", "SWR_MIC", "TX SMIC MUX3"},
+ {"TX SMIC MUX3", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX3", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX3", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX3", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX3", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX3", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX3", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX3", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX3", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX3", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX3", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX3", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX3", "SWR_MIC11", "TX SWR_INPUT11"},
+
+ {"TX DEC4 MUX", "SWR_MIC", "TX SMIC MUX4"},
+ {"TX SMIC MUX4", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX4", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX4", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX4", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX4", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX4", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX4", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX4", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX4", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX4", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX4", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX4", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX4", "SWR_MIC11", "TX SWR_INPUT11"},
+
+ {"TX DEC5 MUX", "SWR_MIC", "TX SMIC MUX5"},
+ {"TX SMIC MUX5", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX5", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX5", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX5", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX5", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX5", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX5", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX5", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX5", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX5", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX5", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX5", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX5", "SWR_MIC11", "TX SWR_INPUT11"},
+
+ {"TX DEC6 MUX", "SWR_MIC", "TX SMIC MUX6"},
+ {"TX SMIC MUX6", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX6", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX6", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX6", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX6", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX6", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX6", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX6", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX6", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX6", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX6", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX6", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX6", "SWR_MIC11", "TX SWR_INPUT11"},
+
+ {"TX DEC7 MUX", "SWR_MIC", "TX SMIC MUX7"},
+ {"TX SMIC MUX7", NULL, "TX_SWR_CLK"},
+ {"TX SMIC MUX7", "SWR_MIC0", "TX SWR_INPUT0"},
+ {"TX SMIC MUX7", "SWR_MIC1", "TX SWR_INPUT1"},
+ {"TX SMIC MUX7", "SWR_MIC2", "TX SWR_INPUT2"},
+ {"TX SMIC MUX7", "SWR_MIC3", "TX SWR_INPUT3"},
+ {"TX SMIC MUX7", "SWR_MIC4", "TX SWR_INPUT4"},
+ {"TX SMIC MUX7", "SWR_MIC5", "TX SWR_INPUT5"},
+ {"TX SMIC MUX7", "SWR_MIC6", "TX SWR_INPUT6"},
+ {"TX SMIC MUX7", "SWR_MIC7", "TX SWR_INPUT7"},
+ {"TX SMIC MUX7", "SWR_MIC8", "TX SWR_INPUT8"},
+ {"TX SMIC MUX7", "SWR_MIC9", "TX SWR_INPUT9"},
+ {"TX SMIC MUX7", "SWR_MIC10", "TX SWR_INPUT10"},
+ {"TX SMIC MUX7", "SWR_MIC11", "TX SWR_INPUT11"},
+};
+
static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
SOC_SINGLE_S8_TLV("TX_DEC0 Volume",
CDC_TX0_TX_VOL_CTL,
@@ -1818,10 +2079,41 @@ static const struct snd_kcontrol_new tx_macro_snd_controls[] = {
tx_macro_get_bcs, tx_macro_set_bcs),
};
+static int tx_macro_component_extend(struct snd_soc_component *comp)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp);
+ struct tx_macro *tx = snd_soc_component_get_drvdata(comp);
+ int ret;
+
+ if (tx->data->extra_widgets_num) {
+ ret = snd_soc_dapm_new_controls(dapm, tx->data->extra_widgets,
+ tx->data->extra_widgets_num);
+ if (ret) {
+ dev_err(tx->dev, "failed to add extra widgets: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (tx->data->extra_routes_num) {
+ ret = snd_soc_dapm_add_routes(dapm, tx->data->extra_routes,
+ tx->data->extra_routes_num);
+ if (ret) {
+ dev_err(tx->dev, "failed to add extra routes: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int tx_macro_component_probe(struct snd_soc_component *comp)
{
struct tx_macro *tx = snd_soc_component_get_drvdata(comp);
- int i;
+ int i, ret;
+
+ ret = tx_macro_component_extend(comp);
+ if (ret)
+ return ret;
snd_soc_component_init_regmap(comp, tx->regmap);
@@ -1843,8 +2135,10 @@ static int tx_macro_component_probe(struct snd_soc_component *comp)
snd_soc_component_update_bits(comp, CDC_TX0_TX_PATH_SEC7, 0x3F,
0x0A);
/* Enable swr mic0 and mic1 clock */
- snd_soc_component_update_bits(comp, CDC_TX_TOP_CSR_SWR_AMIC0_CTL, 0xFF, 0x00);
- snd_soc_component_update_bits(comp, CDC_TX_TOP_CSR_SWR_AMIC1_CTL, 0xFF, 0x00);
+ snd_soc_component_write(comp, CDC_TX_TOP_CSR_SWR_AMIC0_CTL,
+ CDC_TX_SWR_MIC_CLK_DEFAULT);
+ snd_soc_component_write(comp, CDC_TX_TOP_CSR_SWR_AMIC1_CTL,
+ CDC_TX_SWR_MIC_CLK_DEFAULT);
return 0;
}
@@ -1935,7 +2229,7 @@ static int tx_macro_register_mclk_output(struct tx_macro *tx)
}
static const struct snd_soc_component_driver tx_macro_component_drv = {
- .name = "RX-MACRO",
+ .name = "TX-MACRO",
.probe = tx_macro_component_probe,
.controls = tx_macro_snd_controls,
.num_controls = ARRAY_SIZE(tx_macro_snd_controls),
@@ -1949,38 +2243,37 @@ static int tx_macro_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- kernel_ulong_t flags;
struct tx_macro *tx;
void __iomem *base;
int ret, reg;
- flags = (kernel_ulong_t)device_get_match_data(dev);
-
tx = devm_kzalloc(dev, sizeof(*tx), GFP_KERNEL);
if (!tx)
return -ENOMEM;
+ tx->data = device_get_match_data(dev);
+
tx->macro = devm_clk_get_optional(dev, "macro");
if (IS_ERR(tx->macro))
- return PTR_ERR(tx->macro);
+ return dev_err_probe(dev, PTR_ERR(tx->macro), "unable to get macro clock\n");
tx->dcodec = devm_clk_get_optional(dev, "dcodec");
if (IS_ERR(tx->dcodec))
- return PTR_ERR(tx->dcodec);
+ return dev_err_probe(dev, PTR_ERR(tx->dcodec), "unable to get dcodec clock\n");
tx->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(tx->mclk))
- return PTR_ERR(tx->mclk);
+ return dev_err_probe(dev, PTR_ERR(tx->mclk), "unable to get mclk clock\n");
- if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
+ if (tx->data->flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
tx->npl = devm_clk_get(dev, "npl");
if (IS_ERR(tx->npl))
- return PTR_ERR(tx->npl);
+ return dev_err_probe(dev, PTR_ERR(tx->npl), "unable to get npl clock\n");
}
tx->fsgen = devm_clk_get(dev, "fsgen");
if (IS_ERR(tx->fsgen))
- return PTR_ERR(tx->fsgen);
+ return dev_err_probe(dev, PTR_ERR(tx->fsgen), "unable to get fsgen clock\n");
tx->pds = lpass_macro_pds_init(dev);
if (IS_ERR(tx->pds))
@@ -2016,6 +2309,11 @@ static int tx_macro_probe(struct platform_device *pdev)
tx->dev = dev;
+ /* Set active_decimator default value */
+ tx->active_decimator[TX_MACRO_AIF1_CAP] = -1;
+ tx->active_decimator[TX_MACRO_AIF2_CAP] = -1;
+ tx->active_decimator[TX_MACRO_AIF3_CAP] = -1;
+
/* set MCLK and NPL rates */
clk_set_rate(tx->mclk, MCLK_FREQ);
clk_set_rate(tx->npl, MCLK_FREQ);
@@ -2040,15 +2338,19 @@ static int tx_macro_probe(struct platform_device *pdev)
if (ret)
goto err_fsgen;
+
/* reset soundwire block */
- regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
- CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE);
+ if (tx->data->flags & LPASS_MACRO_FLAG_RESET_SWR)
+ regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE);
regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
CDC_TX_SWR_CLK_EN_MASK,
CDC_TX_SWR_CLK_ENABLE);
- regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
- CDC_TX_SWR_RESET_MASK, 0x0);
+
+ if (tx->data->flags & LPASS_MACRO_FLAG_RESET_SWR)
+ regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
+ CDC_TX_SWR_RESET_MASK, 0x0);
ret = devm_snd_soc_register_component(dev, &tx_macro_component_drv,
tx_macro_dai,
@@ -2097,7 +2399,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);
@@ -2111,7 +2413,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;
@@ -2147,24 +2449,79 @@ 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 = {
+ .flags = LPASS_MACRO_FLAG_HAS_NPL_CLOCK |
+ LPASS_MACRO_FLAG_RESET_SWR,
+ .ver = LPASS_VER_9_0_0,
+ .extra_widgets = tx_macro_dapm_widgets_v9,
+ .extra_widgets_num = ARRAY_SIZE(tx_macro_dapm_widgets_v9),
+ .extra_routes = tx_audio_map_v9,
+ .extra_routes_num = ARRAY_SIZE(tx_audio_map_v9),
+};
+
+static const struct tx_macro_data lpass_ver_9_2 = {
+ .flags = LPASS_MACRO_FLAG_HAS_NPL_CLOCK |
+ LPASS_MACRO_FLAG_RESET_SWR,
+ .ver = LPASS_VER_9_2_0,
+ .extra_widgets = tx_macro_dapm_widgets_v9_2,
+ .extra_widgets_num = ARRAY_SIZE(tx_macro_dapm_widgets_v9_2),
+ .extra_routes = tx_audio_map_v9_2,
+ .extra_routes_num = ARRAY_SIZE(tx_audio_map_v9_2),
+};
+
+static const struct tx_macro_data lpass_ver_10_sm6115 = {
+ .flags = LPASS_MACRO_FLAG_HAS_NPL_CLOCK |
+ LPASS_MACRO_FLAG_RESET_SWR,
+ .ver = LPASS_VER_10_0_0,
+ .extra_widgets = tx_macro_dapm_widgets_v9_2,
+ .extra_widgets_num = ARRAY_SIZE(tx_macro_dapm_widgets_v9_2),
+ .extra_routes = tx_audio_map_v9_2,
+ .extra_routes_num = ARRAY_SIZE(tx_audio_map_v9_2),
+};
+
+static const struct tx_macro_data lpass_ver_11 = {
+ .flags = LPASS_MACRO_FLAG_RESET_SWR,
+ .ver = LPASS_VER_11_0_0,
+ .extra_widgets = tx_macro_dapm_widgets_v9_2,
+ .extra_widgets_num = ARRAY_SIZE(tx_macro_dapm_widgets_v9_2),
+ .extra_routes = tx_audio_map_v9_2,
+ .extra_routes_num = ARRAY_SIZE(tx_audio_map_v9_2),
};
static const struct of_device_id tx_macro_dt_match[] = {
{
+ /*
+ * The block is actually LPASS v9.4, but keep LPASS v9 match
+ * data and audio widgets, due to compatibility reasons.
+ * Microphones are working on SC7280 fine, so apparently the fix
+ * is not necessary.
+ */
.compatible = "qcom,sc7280-lpass-tx-macro",
- .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
+ .data = &lpass_ver_9,
+ }, {
+ .compatible = "qcom,sm6115-lpass-tx-macro",
+ .data = &lpass_ver_10_sm6115,
}, {
.compatible = "qcom,sm8250-lpass-tx-macro",
- .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
+ .data = &lpass_ver_9,
}, {
.compatible = "qcom,sm8450-lpass-tx-macro",
- .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
+ .data = &lpass_ver_9_2,
}, {
.compatible = "qcom,sm8550-lpass-tx-macro",
+ .data = &lpass_ver_11,
}, {
.compatible = "qcom,sc8280xp-lpass-tx-macro",
- .data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
+ /*
+ * The block is actually LPASS v9.3, but keep LPASS v9 match
+ * data and audio widgets, due to compatibility reasons.
+ * Microphones are working on SC8280xp fine, so apparently the
+ * fix is not necessary.
+ */
+ .data = &lpass_ver_9,
},
{ }
};
@@ -2174,10 +2531,10 @@ 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_new = tx_macro_remove,
+ .remove = tx_macro_remove,
};
module_platform_driver(tx_macro_driver);
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 74724448da50..528d5b167ecf 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
@@ -64,8 +65,15 @@
#define CDC_VA_TOP_CSR_I2S_CLK (0x00A8)
#define CDC_VA_TOP_CSR_I2S_RESET (0x00AC)
#define CDC_VA_TOP_CSR_CORE_ID_0 (0x00C0)
+ #define CORE_ID_0_REV_MAJ GENMASK(7, 0)
#define CDC_VA_TOP_CSR_CORE_ID_1 (0x00C4)
+#define CORE_ID_1_HAS_WSAMACRO BIT(0)
+#define CORE_ID_1_HAS_RXMACRO BIT(1)
+#define CORE_ID_1_HAS_TXMACRO BIT(2)
+#define CORE_ID_1_HAS_VAMACRO BIT(3)
#define CDC_VA_TOP_CSR_CORE_ID_2 (0x00C8)
+ #define CORE_ID_2_REV_MIN GENMASK(7, 4)
+ #define CORE_ID_2_REV_STEP GENMASK(3, 0)
#define CDC_VA_TOP_CSR_CORE_ID_3 (0x00CC)
#define CDC_VA_TOP_CSR_SWR_MIC_CTL0 (0x00D0)
#define CDC_VA_TOP_CSR_SWR_MIC_CTL1 (0x00D4)
@@ -165,7 +173,6 @@
static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
enum {
- VA_MACRO_AIF_INVALID = 0,
VA_MACRO_AIF1_CAP,
VA_MACRO_AIF2_CAP,
VA_MACRO_AIF3_CAP,
@@ -201,10 +208,12 @@ struct va_macro {
unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
u16 dmic_clk_div;
bool has_swr_master;
+ bool has_npl_clk;
int dec_mode[VA_MACRO_NUM_DECIMATORS];
struct regmap *regmap;
struct clk *mclk;
+ struct clk *npl;
struct clk *macro;
struct clk *dcodec;
struct clk *fsgen;
@@ -225,14 +234,24 @@ struct va_macro {
struct va_macro_data {
bool has_swr_master;
+ bool has_npl_clk;
+ int version;
};
static const struct va_macro_data sm8250_va_data = {
.has_swr_master = false,
+ .has_npl_clk = false,
+ .version = LPASS_CODEC_VERSION_1_0,
};
static const struct va_macro_data sm8450_va_data = {
.has_swr_master = true,
+ .has_npl_clk = true,
+};
+
+static const struct va_macro_data sm8550_va_data = {
+ .has_swr_master = true,
+ .has_npl_clk = false,
};
static bool va_is_volatile_register(struct device *dev, unsigned int reg)
@@ -505,8 +524,7 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -545,8 +563,7 @@ static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct soc_mixer_control *mc =
@@ -566,8 +583,7 @@ static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol,
static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct snd_soc_dapm_update *update = NULL;
@@ -808,7 +824,7 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w,
static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct va_macro *va = snd_soc_component_get_drvdata(comp);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -821,7 +837,7 @@ static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol,
static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
int value = ucontrol->value.enumerated.item[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -882,7 +898,7 @@ static int va_macro_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int va_macro_get_channel_map(struct snd_soc_dai *dai,
+static int va_macro_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)
{
@@ -1332,6 +1348,12 @@ static int fsgen_gate_enable(struct clk_hw *hw)
struct regmap *regmap = va->regmap;
int ret;
+ if (va->has_swr_master) {
+ ret = clk_prepare_enable(va->mclk);
+ if (ret)
+ return ret;
+ }
+
ret = va_macro_mclk_enable(va, true);
if (va->has_swr_master)
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
@@ -1350,6 +1372,8 @@ static void fsgen_gate_disable(struct clk_hw *hw)
CDC_VA_SWR_CLK_EN_MASK, 0x0);
va_macro_mclk_enable(va, false);
+ if (va->has_swr_master)
+ clk_disable_unprepare(va->mclk);
}
static int fsgen_gate_is_enabled(struct clk_hw *hw)
@@ -1378,6 +1402,9 @@ static int va_macro_register_fsgen_output(struct va_macro *va)
struct clk_init_data init;
int ret;
+ if (va->has_npl_clk)
+ parent = va->npl;
+
parent_clk_name = __clk_get_name(parent);
of_property_read_string(np, "clock-output-names", &clk_name);
@@ -1440,6 +1467,65 @@ undefined_rate:
return dmic_sample_rate;
}
+static int va_macro_set_lpass_codec_version(struct va_macro *va)
+{
+ int version = LPASS_CODEC_VERSION_UNKNOWN;
+ u32 maj, min, step;
+ u32 val;
+
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &val);
+ maj = FIELD_GET(CORE_ID_0_REV_MAJ, val);
+
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &val);
+ if (!FIELD_GET(CORE_ID_1_HAS_VAMACRO, val)) {
+ dev_err(va->dev, "This is not a VA macro instance\n");
+ return -ENODEV;
+ }
+
+ regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_2, &val);
+ min = FIELD_GET(CORE_ID_2_REV_MIN, val);
+ step = FIELD_GET(CORE_ID_2_REV_STEP, val);
+
+ if (maj == 1) {
+ version = LPASS_CODEC_VERSION_2_0;
+ } else if (maj == 2) {
+ switch (min) {
+ case 0:
+ version = LPASS_CODEC_VERSION_2_0;
+ break;
+ case 5:
+ version = LPASS_CODEC_VERSION_2_5;
+ break;
+ case 6:
+ version = LPASS_CODEC_VERSION_2_6;
+ break;
+ case 7:
+ version = LPASS_CODEC_VERSION_2_7;
+ break;
+ case 8:
+ version = LPASS_CODEC_VERSION_2_8;
+ break;
+ case 9:
+ version = LPASS_CODEC_VERSION_2_9;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (version == LPASS_CODEC_VERSION_UNKNOWN) {
+ dev_err(va->dev, "VA Macro v%u.%u.%u is not supported\n",
+ maj, min, step);
+ return -EOPNOTSUPP;
+ }
+
+ lpass_macro_set_codec_version(version);
+
+ dev_dbg(va->dev, "LPASS Codec Version %s\n", lpass_macro_get_codec_version_string(version));
+
+ return 0;
+}
+
static int va_macro_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1457,15 +1543,15 @@ static int va_macro_probe(struct platform_device *pdev)
va->macro = devm_clk_get_optional(dev, "macro");
if (IS_ERR(va->macro))
- return PTR_ERR(va->macro);
+ return dev_err_probe(dev, PTR_ERR(va->macro), "unable to get macro clock\n");
va->dcodec = devm_clk_get_optional(dev, "dcodec");
if (IS_ERR(va->dcodec))
- return PTR_ERR(va->dcodec);
+ return dev_err_probe(dev, PTR_ERR(va->dcodec), "unable to get dcodec clock\n");
va->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(va->mclk))
- return PTR_ERR(va->mclk);
+ return dev_err_probe(dev, PTR_ERR(va->mclk), "unable to get mclk clock\n");
va->pds = lpass_macro_pds_init(dev);
if (IS_ERR(va->pds))
@@ -1500,10 +1586,21 @@ static int va_macro_probe(struct platform_device *pdev)
data = of_device_get_match_data(dev);
va->has_swr_master = data->has_swr_master;
+ va->has_npl_clk = data->has_npl_clk;
/* mclk rate */
clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ);
+ if (va->has_npl_clk) {
+ va->npl = devm_clk_get(dev, "npl");
+ if (IS_ERR(va->npl)) {
+ ret = PTR_ERR(va->npl);
+ goto err;
+ }
+
+ clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ);
+ }
+
ret = clk_prepare_enable(va->macro);
if (ret)
goto err;
@@ -1516,6 +1613,25 @@ static int va_macro_probe(struct platform_device *pdev)
if (ret)
goto err_mclk;
+ if (va->has_npl_clk) {
+ ret = clk_prepare_enable(va->npl);
+ if (ret)
+ goto err_npl;
+ }
+
+ /**
+ * old version of codecs do not have a reliable way to determine the
+ * version from registers, get them from soc specific data
+ */
+ if (data->version) {
+ lpass_macro_set_codec_version(data->version);
+ } else {
+ /* read version from register */
+ ret = va_macro_set_lpass_codec_version(va);
+ if (ret)
+ goto err_clkout;
+ }
+
if (va->has_swr_master) {
/* Set default CLK div to 1 */
regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0,
@@ -1555,7 +1671,7 @@ static int va_macro_probe(struct platform_device *pdev)
if (ret)
goto err_clkout;
- va->fsgen = clk_hw_get_clk(&va->hw, "fsgen");
+ va->fsgen = devm_clk_hw_get_clk(dev, &va->hw, "fsgen");
if (IS_ERR(va->fsgen)) {
ret = PTR_ERR(va->fsgen);
goto err_clkout;
@@ -1564,6 +1680,9 @@ static int va_macro_probe(struct platform_device *pdev)
return 0;
err_clkout:
+ if (va->has_npl_clk)
+ clk_disable_unprepare(va->npl);
+err_npl:
clk_disable_unprepare(va->mclk);
err_mclk:
clk_disable_unprepare(va->dcodec);
@@ -1579,6 +1698,9 @@ static void va_macro_remove(struct platform_device *pdev)
{
struct va_macro *va = dev_get_drvdata(&pdev->dev);
+ if (va->has_npl_clk)
+ clk_disable_unprepare(va->npl);
+
clk_disable_unprepare(va->mclk);
clk_disable_unprepare(va->dcodec);
clk_disable_unprepare(va->macro);
@@ -1586,19 +1708,22 @@ 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);
regcache_cache_only(va->regmap, true);
regcache_mark_dirty(va->regmap);
+ if (va->has_npl_clk)
+ clk_disable_unprepare(va->npl);
+
clk_disable_unprepare(va->mclk);
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;
@@ -1609,6 +1734,15 @@ static int __maybe_unused va_macro_runtime_resume(struct device *dev)
return ret;
}
+ if (va->has_npl_clk) {
+ ret = clk_prepare_enable(va->npl);
+ if (ret) {
+ clk_disable_unprepare(va->mclk);
+ dev_err(va->dev, "unable to prepare npl\n");
+ return ret;
+ }
+ }
+
regcache_cache_only(va->regmap, false);
regcache_sync(va->regmap);
@@ -1617,13 +1751,15 @@ 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[] = {
{ .compatible = "qcom,sc7280-lpass-va-macro", .data = &sm8250_va_data },
+ { .compatible = "qcom,sm6115-lpass-va-macro", .data = &sm8450_va_data },
{ .compatible = "qcom,sm8250-lpass-va-macro", .data = &sm8250_va_data },
{ .compatible = "qcom,sm8450-lpass-va-macro", .data = &sm8450_va_data },
+ { .compatible = "qcom,sm8550-lpass-va-macro", .data = &sm8550_va_data },
{ .compatible = "qcom,sc8280xp-lpass-va-macro", .data = &sm8450_va_data },
{}
};
@@ -1634,10 +1770,10 @@ 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_new = va_macro_remove,
+ .remove = va_macro_remove,
};
module_platform_driver(va_macro_driver);
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 8ba7dc89daaa..b695c77c18ac 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -44,11 +45,7 @@
#define CDC_WSA_TOP_I2S_CLK (0x00A4)
#define CDC_WSA_TOP_I2S_RESET (0x00A8)
#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (0x0100)
-#define CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK GENMASK(2, 0)
-#define CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK GENMASK(5, 3)
#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (0x0104)
-#define CDC_WSA_RX_INTX_2_SEL_MASK GENMASK(2, 0)
-#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK GENMASK(5, 3)
#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (0x0108)
#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (0x010C)
#define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (0x0110)
@@ -66,6 +63,10 @@
#define CDC_WSA_TX_SPKR_PROT_CLK_DISABLE 0
#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK GENMASK(3, 0)
#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K 0
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_16K 1
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_24K 2
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_32K 3
+#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_48K 4
#define CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (0x0248)
#define CDC_WSA_TX1_SPKR_PROT_PATH_CTL (0x0264)
#define CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (0x0268)
@@ -173,22 +174,7 @@
#define CDC_WSA_COMPANDER0_CTL5 (0x0594)
#define CDC_WSA_COMPANDER0_CTL6 (0x0598)
#define CDC_WSA_COMPANDER0_CTL7 (0x059C)
-#define CDC_WSA_COMPANDER1_CTL0 (0x05C0)
-#define CDC_WSA_COMPANDER1_CTL1 (0x05C4)
-#define CDC_WSA_COMPANDER1_CTL2 (0x05C8)
-#define CDC_WSA_COMPANDER1_CTL3 (0x05CC)
-#define CDC_WSA_COMPANDER1_CTL4 (0x05D0)
-#define CDC_WSA_COMPANDER1_CTL5 (0x05D4)
-#define CDC_WSA_COMPANDER1_CTL6 (0x05D8)
-#define CDC_WSA_COMPANDER1_CTL7 (0x05DC)
-#define CDC_WSA_SOFTCLIP0_CRC (0x0600)
-#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0)
-#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0)
-#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604)
-#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0)
-#define CDC_WSA_SOFTCLIP_ENABLE BIT(0)
-#define CDC_WSA_SOFTCLIP1_CRC (0x0640)
-#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644)
+/* CDC_WSA_COMPANDER1_CTLx and CDC_WSA_SOFTCLIPx differ per LPASS codec versions */
#define CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL (0x0680)
#define CDC_WSA_EC_HQ_EC_CLK_EN_MASK BIT(0)
#define CDC_WSA_EC_HQ_EC_CLK_ENABLE BIT(0)
@@ -217,6 +203,65 @@
#define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO (0x0760)
#define WSA_MAX_OFFSET (0x0760)
+/* LPASS codec version <=2.4 register offsets */
+#define CDC_WSA_COMPANDER1_CTL0 (0x05C0)
+#define CDC_WSA_COMPANDER1_CTL1 (0x05C4)
+#define CDC_WSA_COMPANDER1_CTL2 (0x05C8)
+#define CDC_WSA_COMPANDER1_CTL3 (0x05CC)
+#define CDC_WSA_COMPANDER1_CTL4 (0x05D0)
+#define CDC_WSA_COMPANDER1_CTL5 (0x05D4)
+#define CDC_WSA_COMPANDER1_CTL6 (0x05D8)
+#define CDC_WSA_COMPANDER1_CTL7 (0x05DC)
+#define CDC_WSA_SOFTCLIP0_CRC (0x0600)
+#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0)
+#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0)
+#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604)
+#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0)
+#define CDC_WSA_SOFTCLIP_ENABLE BIT(0)
+#define CDC_WSA_SOFTCLIP1_CRC (0x0640)
+#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644)
+
+/* LPASS codec version >=2.5 register offsets */
+#define CDC_WSA_TOP_FS_UNGATE (0x00AC)
+#define CDC_WSA_TOP_GRP_SEL (0x00B0)
+#define CDC_WSA_TOP_FS_UNGATE2 (0x00DC)
+#define CDC_2_5_WSA_COMPANDER0_CTL8 (0x05A0)
+#define CDC_2_5_WSA_COMPANDER0_CTL9 (0x05A4)
+#define CDC_2_5_WSA_COMPANDER0_CTL10 (0x05A8)
+#define CDC_2_5_WSA_COMPANDER0_CTL11 (0x05AC)
+#define CDC_2_5_WSA_COMPANDER0_CTL12 (0x05B0)
+#define CDC_2_5_WSA_COMPANDER0_CTL13 (0x05B4)
+#define CDC_2_5_WSA_COMPANDER0_CTL14 (0x05B8)
+#define CDC_2_5_WSA_COMPANDER0_CTL15 (0x05BC)
+#define CDC_2_5_WSA_COMPANDER0_CTL16 (0x05C0)
+#define CDC_2_5_WSA_COMPANDER0_CTL17 (0x05C4)
+#define CDC_2_5_WSA_COMPANDER0_CTL18 (0x05C8)
+#define CDC_2_5_WSA_COMPANDER0_CTL19 (0x05CC)
+#define CDC_2_5_WSA_COMPANDER1_CTL0 (0x05E0)
+#define CDC_2_5_WSA_COMPANDER1_CTL1 (0x05E4)
+#define CDC_2_5_WSA_COMPANDER1_CTL2 (0x05E8)
+#define CDC_2_5_WSA_COMPANDER1_CTL3 (0x05EC)
+#define CDC_2_5_WSA_COMPANDER1_CTL4 (0x05F0)
+#define CDC_2_5_WSA_COMPANDER1_CTL5 (0x05F4)
+#define CDC_2_5_WSA_COMPANDER1_CTL6 (0x05F8)
+#define CDC_2_5_WSA_COMPANDER1_CTL7 (0x05FC)
+#define CDC_2_5_WSA_COMPANDER1_CTL8 (0x0600)
+#define CDC_2_5_WSA_COMPANDER1_CTL9 (0x0604)
+#define CDC_2_5_WSA_COMPANDER1_CTL10 (0x0608)
+#define CDC_2_5_WSA_COMPANDER1_CTL11 (0x060C)
+#define CDC_2_5_WSA_COMPANDER1_CTL12 (0x0610)
+#define CDC_2_5_WSA_COMPANDER1_CTL13 (0x0614)
+#define CDC_2_5_WSA_COMPANDER1_CTL14 (0x0618)
+#define CDC_2_5_WSA_COMPANDER1_CTL15 (0x061C)
+#define CDC_2_5_WSA_COMPANDER1_CTL16 (0x0620)
+#define CDC_2_5_WSA_COMPANDER1_CTL17 (0x0624)
+#define CDC_2_5_WSA_COMPANDER1_CTL18 (0x0628)
+#define CDC_2_5_WSA_COMPANDER1_CTL19 (0x062C)
+#define CDC_2_5_WSA_SOFTCLIP0_CRC (0x0640)
+#define CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0644)
+#define CDC_2_5_WSA_SOFTCLIP1_CRC (0x0660)
+#define CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0664)
+
#define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
@@ -235,11 +280,8 @@
#define NUM_INTERPOLATORS 2
#define WSA_NUM_CLKS_MAX 5
#define WSA_MACRO_MCLK_FREQ 19200000
-#define WSA_MACRO_MUX_INP_MASK2 0x38
#define WSA_MACRO_MUX_CFG_OFFSET 0x8
#define WSA_MACRO_MUX_CFG1_OFFSET 0x4
-#define WSA_MACRO_RX_COMP_OFFSET 0x40
-#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40
#define WSA_MACRO_RX_PATH_OFFSET 0x80
#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10
#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C
@@ -255,8 +297,7 @@ enum {
enum {
WSA_MACRO_RX0 = 0,
WSA_MACRO_RX1,
- WSA_MACRO_RX_MIX,
- WSA_MACRO_RX_MIX0 = WSA_MACRO_RX_MIX,
+ WSA_MACRO_RX_MIX0,
WSA_MACRO_RX_MIX1,
WSA_MACRO_RX_MAX,
};
@@ -326,8 +367,8 @@ static struct interp_sample_rate int_mix_sample_rate_val[] = {
{192000, 0x6}, /* 192K */
};
+/* Matches also rx_mux_text */
enum {
- WSA_MACRO_AIF_INVALID = 0,
WSA_MACRO_AIF1_PB,
WSA_MACRO_AIF_MIX1_PB,
WSA_MACRO_AIF_VI,
@@ -335,18 +376,41 @@ enum {
WSA_MACRO_MAX_DAIS,
};
+/**
+ * struct wsa_reg_layout - Register layout differences
+ * @rx_intx_1_mix_inp0_sel_mask: register mask for RX_INTX_1_MIX_INP0_SEL_MASK
+ * @rx_intx_1_mix_inp1_sel_mask: register mask for RX_INTX_1_MIX_INP1_SEL_MASK
+ * @rx_intx_1_mix_inp2_sel_mask: register mask for RX_INTX_1_MIX_INP2_SEL_MASK
+ * @rx_intx_2_sel_mask: register mask for RX_INTX_2_SEL_MASK
+ * @compander1_reg_offset: offset between compander registers (compander1 - compander0)
+ * @softclip0_reg_base: base address of softclip0 register
+ * @softclip1_reg_offset: offset between compander registers (softclip1 - softclip0)
+ */
+struct wsa_reg_layout {
+ unsigned int rx_intx_1_mix_inp0_sel_mask;
+ unsigned int rx_intx_1_mix_inp1_sel_mask;
+ unsigned int rx_intx_1_mix_inp2_sel_mask;
+ unsigned int rx_intx_2_sel_mask;
+ unsigned int compander1_reg_offset;
+ unsigned int softclip0_reg_base;
+ unsigned int softclip1_reg_offset;
+};
+
struct wsa_macro {
struct device *dev;
int comp_enabled[WSA_MACRO_COMP_MAX];
int ec_hq[WSA_MACRO_RX1 + 1];
u16 prim_int_users[WSA_MACRO_RX1 + 1];
u16 wsa_mclk_users;
+ enum lpass_codec_version codec_version;
+ const struct wsa_reg_layout *reg_layout;
unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS];
unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS];
int rx_port_value[WSA_MACRO_RX_MAX];
int ear_spkr_gain;
int spkr_gain_offset;
int spkr_mode;
+ u32 pcm_rate_vi;
int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX];
int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX];
struct regmap *regmap;
@@ -359,20 +423,49 @@ struct wsa_macro {
};
#define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw)
+static const struct wsa_reg_layout wsa_codec_v2_1 = {
+ .rx_intx_1_mix_inp0_sel_mask = GENMASK(2, 0),
+ .rx_intx_1_mix_inp1_sel_mask = GENMASK(5, 3),
+ .rx_intx_1_mix_inp2_sel_mask = GENMASK(5, 3),
+ .rx_intx_2_sel_mask = GENMASK(2, 0),
+ .compander1_reg_offset = 0x40,
+ .softclip0_reg_base = 0x600,
+ .softclip1_reg_offset = 0x40,
+};
+
+static const struct wsa_reg_layout wsa_codec_v2_5 = {
+ .rx_intx_1_mix_inp0_sel_mask = GENMASK(3, 0),
+ .rx_intx_1_mix_inp1_sel_mask = GENMASK(7, 4),
+ .rx_intx_1_mix_inp2_sel_mask = GENMASK(7, 4),
+ .rx_intx_2_sel_mask = GENMASK(3, 0),
+ .compander1_reg_offset = 0x60,
+ .softclip0_reg_base = 0x640,
+ .softclip1_reg_offset = 0x20,
+};
+
static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
-static const char *const rx_text[] = {
+static const char *const rx_text_v2_1[] = {
"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1"
};
-static const char *const rx_mix_text[] = {
+static const char *const rx_text_v2_5[] = {
+ "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1"
+};
+
+static const char *const rx_mix_text_v2_1[] = {
"ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1"
};
+static const char *const rx_mix_text_v2_5[] = {
+ "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8"
+};
+
static const char *const rx_mix_ec_text[] = {
"ZERO", "RX_MIX_TX0", "RX_MIX_TX1"
};
+/* Order must match WSA_MACRO_MAX_DAIS enum (offset by 1) */
static const char *const rx_mux_text[] = {
"ZERO", "AIF1_PB", "AIF_MIX1_PB"
};
@@ -390,68 +483,124 @@ static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum,
wsa_macro_ear_spkr_pa_gain_text);
/* RX INT0 */
-static const struct soc_enum rx0_prim_inp0_chain_enum =
+static const struct soc_enum rx0_prim_inp0_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+ 0, 7, rx_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp1_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
+ 3, 7, rx_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp2_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+ 3, 7, rx_text_v2_1);
+
+static const struct soc_enum rx0_mix_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
+ 0, 5, rx_mix_text_v2_1);
+
+static const struct soc_enum rx0_prim_inp0_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
- 0, 7, rx_text);
+ 0, 12, rx_text_v2_5);
-static const struct soc_enum rx0_prim_inp1_chain_enum =
+static const struct soc_enum rx0_prim_inp1_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0,
- 3, 7, rx_text);
+ 4, 12, rx_text_v2_5);
-static const struct soc_enum rx0_prim_inp2_chain_enum =
+static const struct soc_enum rx0_prim_inp2_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
- 3, 7, rx_text);
+ 4, 12, rx_text_v2_5);
-static const struct soc_enum rx0_mix_chain_enum =
+static const struct soc_enum rx0_mix_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1,
- 0, 5, rx_mix_text);
+ 0, 10, rx_mix_text_v2_5);
static const struct soc_enum rx0_sidetone_mix_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text);
-static const struct snd_kcontrol_new rx0_prim_inp0_mux =
- SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_1);
-static const struct snd_kcontrol_new rx0_prim_inp1_mux =
- SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_1);
-static const struct snd_kcontrol_new rx0_prim_inp2_mux =
- SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum);
+static const struct snd_kcontrol_new rx0_mix_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_1);
-static const struct snd_kcontrol_new rx0_mix_mux =
- SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum);
+static const struct snd_kcontrol_new rx0_prim_inp0_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx0_prim_inp1_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx0_prim_inp2_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum_v2_5);
+
+static const struct snd_kcontrol_new rx0_mix_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum_v2_5);
static const struct snd_kcontrol_new rx0_sidetone_mix_mux =
SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum);
/* RX INT1 */
-static const struct soc_enum rx1_prim_inp0_chain_enum =
+static const struct soc_enum rx1_prim_inp0_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+ 0, 7, rx_text_v2_1);
+
+static const struct soc_enum rx1_prim_inp1_chain_enum_v2_1 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
- 0, 7, rx_text);
+ 3, 7, rx_text_v2_1);
-static const struct soc_enum rx1_prim_inp1_chain_enum =
+static const struct soc_enum rx1_prim_inp2_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+ 3, 7, rx_text_v2_1);
+
+static const struct soc_enum rx1_mix_chain_enum_v2_1 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
+ 0, 5, rx_mix_text_v2_1);
+
+static const struct soc_enum rx1_prim_inp0_chain_enum_v2_5 =
+ SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
+ 0, 12, rx_text_v2_5);
+
+static const struct soc_enum rx1_prim_inp1_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0,
- 3, 7, rx_text);
+ 4, 12, rx_text_v2_5);
-static const struct soc_enum rx1_prim_inp2_chain_enum =
+static const struct soc_enum rx1_prim_inp2_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
- 3, 7, rx_text);
+ 4, 12, rx_text_v2_5);
-static const struct soc_enum rx1_mix_chain_enum =
+static const struct soc_enum rx1_mix_chain_enum_v2_5 =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1,
- 0, 5, rx_mix_text);
+ 0, 10, rx_mix_text_v2_5);
+
+static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_1);
+
+static const struct snd_kcontrol_new rx1_mix_mux_v2_1 =
+ SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_1);
-static const struct snd_kcontrol_new rx1_prim_inp0_mux =
- SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum);
+static const struct snd_kcontrol_new rx1_prim_inp0_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum_v2_5);
-static const struct snd_kcontrol_new rx1_prim_inp1_mux =
- SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum);
+static const struct snd_kcontrol_new rx1_prim_inp1_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum_v2_5);
-static const struct snd_kcontrol_new rx1_prim_inp2_mux =
- SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum);
+static const struct snd_kcontrol_new rx1_prim_inp2_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum_v2_5);
-static const struct snd_kcontrol_new rx1_mix_mux =
- SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum);
+static const struct snd_kcontrol_new rx1_mix_mux_v2_5 =
+ SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum_v2_5);
static const struct soc_enum rx_mix_ec0_enum =
SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0,
@@ -490,14 +639,6 @@ static const struct reg_default wsa_defaults[] = {
{ CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00},
{ CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00},
{ CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00},
- { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
- { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
- { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
- { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
- { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
{ CDC_WSA_INTR_CTRL_CFG, 0x00},
{ CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00},
{ CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF},
@@ -562,18 +703,6 @@ static const struct reg_default wsa_defaults[] = {
{ CDC_WSA_COMPANDER0_CTL5, 0x00},
{ CDC_WSA_COMPANDER0_CTL6, 0x01},
{ CDC_WSA_COMPANDER0_CTL7, 0x28},
- { CDC_WSA_COMPANDER1_CTL0, 0x60},
- { CDC_WSA_COMPANDER1_CTL1, 0xDB},
- { CDC_WSA_COMPANDER1_CTL2, 0xFF},
- { CDC_WSA_COMPANDER1_CTL3, 0x35},
- { CDC_WSA_COMPANDER1_CTL4, 0xFF},
- { CDC_WSA_COMPANDER1_CTL5, 0x00},
- { CDC_WSA_COMPANDER1_CTL6, 0x01},
- { CDC_WSA_COMPANDER1_CTL7, 0x28},
- { CDC_WSA_SOFTCLIP0_CRC, 0x00},
- { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
- { CDC_WSA_SOFTCLIP1_CRC, 0x00},
- { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
{ CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00},
{ CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01},
{ CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00},
@@ -598,6 +727,79 @@ static const struct reg_default wsa_defaults[] = {
{ CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00},
};
+static const struct reg_default wsa_defaults_v2_1[] = {
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00},
+ { CDC_WSA_COMPANDER1_CTL0, 0x60},
+ { CDC_WSA_COMPANDER1_CTL1, 0xDB},
+ { CDC_WSA_COMPANDER1_CTL2, 0xFF},
+ { CDC_WSA_COMPANDER1_CTL3, 0x35},
+ { CDC_WSA_COMPANDER1_CTL4, 0xFF},
+ { CDC_WSA_COMPANDER1_CTL5, 0x00},
+ { CDC_WSA_COMPANDER1_CTL6, 0x01},
+ { CDC_WSA_COMPANDER1_CTL7, 0x28},
+ { CDC_WSA_SOFTCLIP0_CRC, 0x00},
+ { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+ { CDC_WSA_SOFTCLIP1_CRC, 0x00},
+ { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+};
+
+static const struct reg_default wsa_defaults_v2_5[] = {
+ { CDC_WSA_TOP_FS_UNGATE, 0xFF},
+ { CDC_WSA_TOP_GRP_SEL, 0x08},
+ { CDC_WSA_TOP_FS_UNGATE2, 0x1F},
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x04},
+ { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x02},
+ { CDC_2_5_WSA_COMPANDER0_CTL8, 0x00},
+ { CDC_2_5_WSA_COMPANDER0_CTL9, 0x00},
+ { CDC_2_5_WSA_COMPANDER0_CTL10, 0x06},
+ { CDC_2_5_WSA_COMPANDER0_CTL11, 0x12},
+ { CDC_2_5_WSA_COMPANDER0_CTL12, 0x1E},
+ { CDC_2_5_WSA_COMPANDER0_CTL13, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL14, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL15, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL16, 0x00},
+ { CDC_2_5_WSA_COMPANDER0_CTL17, 0x24},
+ { CDC_2_5_WSA_COMPANDER0_CTL18, 0x2A},
+ { CDC_2_5_WSA_COMPANDER0_CTL19, 0x16},
+ { CDC_2_5_WSA_COMPANDER1_CTL0, 0x60},
+ { CDC_2_5_WSA_COMPANDER1_CTL1, 0xDB},
+ { CDC_2_5_WSA_COMPANDER1_CTL2, 0xFF},
+ { CDC_2_5_WSA_COMPANDER1_CTL3, 0x35},
+ { CDC_2_5_WSA_COMPANDER1_CTL4, 0xFF},
+ { CDC_2_5_WSA_COMPANDER1_CTL5, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL6, 0x01},
+ { CDC_2_5_WSA_COMPANDER1_CTL7, 0x28},
+ { CDC_2_5_WSA_COMPANDER1_CTL8, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL9, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL10, 0x06},
+ { CDC_2_5_WSA_COMPANDER1_CTL11, 0x12},
+ { CDC_2_5_WSA_COMPANDER1_CTL12, 0x1E},
+ { CDC_2_5_WSA_COMPANDER1_CTL13, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL14, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL15, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL16, 0x00},
+ { CDC_2_5_WSA_COMPANDER1_CTL17, 0x24},
+ { CDC_2_5_WSA_COMPANDER1_CTL18, 0x2A},
+ { CDC_2_5_WSA_COMPANDER1_CTL19, 0x16},
+ { CDC_2_5_WSA_SOFTCLIP0_CRC, 0x00},
+ { CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38},
+ { CDC_2_5_WSA_SOFTCLIP1_CRC, 0x00},
+ { CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38},
+};
+
static bool wsa_is_wronly_register(struct device *dev,
unsigned int reg)
{
@@ -611,8 +813,77 @@ static bool wsa_is_wronly_register(struct device *dev,
return false;
}
+static bool wsa_is_rw_register_v2_1(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_COMPANDER1_CTL0:
+ case CDC_WSA_COMPANDER1_CTL1:
+ case CDC_WSA_COMPANDER1_CTL2:
+ case CDC_WSA_COMPANDER1_CTL3:
+ case CDC_WSA_COMPANDER1_CTL4:
+ case CDC_WSA_COMPANDER1_CTL5:
+ case CDC_WSA_COMPANDER1_CTL7:
+ case CDC_WSA_SOFTCLIP0_CRC:
+ case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+ case CDC_WSA_SOFTCLIP1_CRC:
+ case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wsa_is_rw_register_v2_5(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_TOP_FS_UNGATE:
+ case CDC_WSA_TOP_GRP_SEL:
+ case CDC_WSA_TOP_FS_UNGATE2:
+ case CDC_2_5_WSA_COMPANDER0_CTL8:
+ case CDC_2_5_WSA_COMPANDER0_CTL9:
+ case CDC_2_5_WSA_COMPANDER0_CTL10:
+ case CDC_2_5_WSA_COMPANDER0_CTL11:
+ case CDC_2_5_WSA_COMPANDER0_CTL12:
+ case CDC_2_5_WSA_COMPANDER0_CTL13:
+ case CDC_2_5_WSA_COMPANDER0_CTL14:
+ case CDC_2_5_WSA_COMPANDER0_CTL15:
+ case CDC_2_5_WSA_COMPANDER0_CTL16:
+ case CDC_2_5_WSA_COMPANDER0_CTL17:
+ case CDC_2_5_WSA_COMPANDER0_CTL18:
+ case CDC_2_5_WSA_COMPANDER0_CTL19:
+ case CDC_2_5_WSA_COMPANDER1_CTL0:
+ case CDC_2_5_WSA_COMPANDER1_CTL1:
+ case CDC_2_5_WSA_COMPANDER1_CTL2:
+ case CDC_2_5_WSA_COMPANDER1_CTL3:
+ case CDC_2_5_WSA_COMPANDER1_CTL4:
+ case CDC_2_5_WSA_COMPANDER1_CTL5:
+ case CDC_2_5_WSA_COMPANDER1_CTL7:
+ case CDC_2_5_WSA_COMPANDER1_CTL8:
+ case CDC_2_5_WSA_COMPANDER1_CTL9:
+ case CDC_2_5_WSA_COMPANDER1_CTL10:
+ case CDC_2_5_WSA_COMPANDER1_CTL11:
+ case CDC_2_5_WSA_COMPANDER1_CTL12:
+ case CDC_2_5_WSA_COMPANDER1_CTL13:
+ case CDC_2_5_WSA_COMPANDER1_CTL14:
+ case CDC_2_5_WSA_COMPANDER1_CTL15:
+ case CDC_2_5_WSA_COMPANDER1_CTL16:
+ case CDC_2_5_WSA_COMPANDER1_CTL17:
+ case CDC_2_5_WSA_COMPANDER1_CTL18:
+ case CDC_2_5_WSA_COMPANDER1_CTL19:
+ case CDC_2_5_WSA_SOFTCLIP0_CRC:
+ case CDC_2_5_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
+ case CDC_2_5_WSA_SOFTCLIP1_CRC:
+ case CDC_2_5_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
+ return true;
+ }
+
+ return false;
+}
+
static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
{
+ struct wsa_macro *wsa = dev_get_drvdata(dev);
+
switch (reg) {
case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL:
case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL:
@@ -702,17 +973,6 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
case CDC_WSA_COMPANDER0_CTL4:
case CDC_WSA_COMPANDER0_CTL5:
case CDC_WSA_COMPANDER0_CTL7:
- case CDC_WSA_COMPANDER1_CTL0:
- case CDC_WSA_COMPANDER1_CTL1:
- case CDC_WSA_COMPANDER1_CTL2:
- case CDC_WSA_COMPANDER1_CTL3:
- case CDC_WSA_COMPANDER1_CTL4:
- case CDC_WSA_COMPANDER1_CTL5:
- case CDC_WSA_COMPANDER1_CTL7:
- case CDC_WSA_SOFTCLIP0_CRC:
- case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL:
- case CDC_WSA_SOFTCLIP1_CRC:
- case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL:
case CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL:
case CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0:
case CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL:
@@ -728,7 +988,10 @@ static bool wsa_is_rw_register(struct device *dev, unsigned int reg)
return true;
}
- return false;
+ if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+ return wsa_is_rw_register_v2_5(dev, reg);
+
+ return wsa_is_rw_register_v2_1(dev, reg);
}
static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
@@ -742,8 +1005,30 @@ static bool wsa_is_writeable_register(struct device *dev, unsigned int reg)
return ret;
}
+static bool wsa_is_readable_register_v2_1(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return wsa_is_rw_register(dev, reg);
+}
+
+static bool wsa_is_readable_register_v2_5(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_2_5_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return wsa_is_rw_register(dev, reg);
+}
+
static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
{
+ struct wsa_macro *wsa = dev_get_drvdata(dev);
+
switch (reg) {
case CDC_WSA_INTR_CTRL_CLR_COMMIT:
case CDC_WSA_INTR_CTRL_PIN1_CLEAR0:
@@ -751,7 +1036,6 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
case CDC_WSA_COMPANDER0_CTL6:
- case CDC_WSA_COMPANDER1_CTL6:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
@@ -765,17 +1049,41 @@ static bool wsa_is_readable_register(struct device *dev, unsigned int reg)
return true;
}
- return wsa_is_rw_register(dev, reg);
+ if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+ return wsa_is_readable_register_v2_5(dev, reg);
+
+ return wsa_is_readable_register_v2_1(dev, reg);
+}
+
+static bool wsa_is_volatile_register_v2_1(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wsa_is_volatile_register_v2_5(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CDC_2_5_WSA_COMPANDER1_CTL6:
+ return true;
+ }
+
+ return false;
}
static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
{
+ struct wsa_macro *wsa = dev_get_drvdata(dev);
+
/* Update volatile list for rx/tx macros */
switch (reg) {
case CDC_WSA_INTR_CTRL_PIN1_STATUS0:
case CDC_WSA_INTR_CTRL_PIN2_STATUS0:
case CDC_WSA_COMPANDER0_CTL6:
- case CDC_WSA_COMPANDER1_CTL6:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB:
case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB:
@@ -788,7 +1096,11 @@ static bool wsa_is_volatile_register(struct device *dev, unsigned int reg)
case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO:
return true;
}
- return false;
+
+ if (wsa->codec_version >= LPASS_CODEC_VERSION_2_5)
+ return wsa_is_volatile_register_v2_5(dev, reg);
+
+ return wsa_is_volatile_register_v2_1(dev, reg);
}
static const struct regmap_config wsa_regmap_config = {
@@ -797,8 +1109,7 @@ static const struct regmap_config wsa_regmap_config = {
.val_bits = 32, /* 8 but with 32 bit read/write */
.reg_stride = 4,
.cache_type = REGCACHE_FLAT,
- .reg_defaults = wsa_defaults,
- .num_reg_defaults = ARRAY_SIZE(wsa_defaults),
+ /* .reg_defaults and .num_reg_defaults set in probe() */
.max_register = WSA_MAX_OFFSET,
.writeable_reg = wsa_is_writeable_register,
.volatile_reg = wsa_is_volatile_register,
@@ -856,12 +1167,6 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) {
int_1_mix1_inp = port;
- if ((int_1_mix1_inp < WSA_MACRO_RX0) || (int_1_mix1_inp > WSA_MACRO_RX_MIX1)) {
- dev_err(component->dev, "%s: Invalid RX port, Dai ID is %d\n",
- __func__, dai->id);
- return -EINVAL;
- }
-
int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0;
/*
@@ -872,11 +1177,11 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai,
for (j = 0; j < NUM_INTERPOLATORS; j++) {
int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET;
inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
- inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp0_sel_mask);
+ inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0,
+ wsa->reg_layout->rx_intx_1_mix_inp1_sel_mask);
inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1,
- CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
+ wsa->reg_layout->rx_intx_1_mix_inp2_sel_mask);
if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
(inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) ||
@@ -908,16 +1213,11 @@ static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) {
int_2_inp = port;
- if ((int_2_inp < WSA_MACRO_RX0) || (int_2_inp > WSA_MACRO_RX_MIX1)) {
- dev_err(component->dev, "%s: Invalid RX port, Dai ID is %d\n",
- __func__, dai->id);
- return -EINVAL;
- }
int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1;
for (j = 0; j < NUM_INTERPOLATORS; j++) {
int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1,
- CDC_WSA_RX_INTX_2_SEL_MASK);
+ wsa->reg_layout->rx_intx_2_sel_mask);
if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) {
int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL +
@@ -974,6 +1274,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
int ret;
switch (substream->stream) {
@@ -986,13 +1287,18 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream,
return ret;
}
break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ if (dai->id == WSA_MACRO_AIF_VI)
+ wsa->pcm_rate_vi = params_rate(params);
+
+ break;
default:
break;
}
return 0;
}
-static int wsa_macro_get_channel_map(struct snd_soc_dai *dai,
+static int wsa_macro_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)
{
@@ -1142,35 +1448,11 @@ static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable)
}
}
-static int wsa_macro_mclk_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 wsa_macro *wsa = snd_soc_component_get_drvdata(component);
-
- wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU);
- return 0;
-}
-
-static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol,
- int event)
+static void wsa_macro_enable_disable_vi_sense(struct snd_soc_component *component, bool enable,
+ u32 tx_reg0, u32 tx_reg1, u32 val)
{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
- u32 tx_reg0, tx_reg1;
-
- if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
- tx_reg0 = CDC_WSA_TX0_SPKR_PROT_PATH_CTL;
- tx_reg1 = CDC_WSA_TX1_SPKR_PROT_PATH_CTL;
- } else if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
- tx_reg0 = CDC_WSA_TX2_SPKR_PROT_PATH_CTL;
- tx_reg1 = CDC_WSA_TX3_SPKR_PROT_PATH_CTL;
- }
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- /* Enable V&I sensing */
+ if (enable) {
+ /* Enable V&I sensing */
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_RESET_MASK,
CDC_WSA_TX_SPKR_PROT_RESET);
@@ -1179,10 +1461,10 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
CDC_WSA_TX_SPKR_PROT_RESET);
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
- CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+ val);
snd_soc_component_update_bits(component, tx_reg1,
CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK,
- CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K);
+ val);
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
CDC_WSA_TX_SPKR_PROT_CLK_ENABLE);
@@ -1195,9 +1477,7 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, tx_reg1,
CDC_WSA_TX_SPKR_PROT_RESET_MASK,
CDC_WSA_TX_SPKR_PROT_NO_RESET);
- break;
- case SND_SOC_DAPM_POST_PMD:
- /* Disable V&I sensing */
+ } else {
snd_soc_component_update_bits(component, tx_reg0,
CDC_WSA_TX_SPKR_PROT_RESET_MASK,
CDC_WSA_TX_SPKR_PROT_RESET);
@@ -1210,41 +1490,72 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, tx_reg1,
CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK,
CDC_WSA_TX_SPKR_PROT_CLK_DISABLE);
- break;
}
+}
+
+static void wsa_macro_enable_disable_vi_feedback(struct snd_soc_component *component,
+ bool enable, u32 rate)
+{
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+ if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI]))
+ wsa_macro_enable_disable_vi_sense(component, enable,
+ CDC_WSA_TX0_SPKR_PROT_PATH_CTL,
+ CDC_WSA_TX1_SPKR_PROT_PATH_CTL, rate);
+
+ if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI]))
+ wsa_macro_enable_disable_vi_sense(component, enable,
+ CDC_WSA_TX2_SPKR_PROT_PATH_CTL,
+ CDC_WSA_TX3_SPKR_PROT_PATH_CTL, rate);
+}
+static int wsa_macro_mclk_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 wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+
+ wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU);
return 0;
}
-static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- u16 path_reg, gain_reg;
- int val;
+ struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
+ u32 rate_val;
- switch (w->shift) {
- case WSA_MACRO_RX_MIX0:
- path_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL;
- gain_reg = CDC_WSA_RX0_RX_VOL_MIX_CTL;
+ switch (wsa->pcm_rate_vi) {
+ case 8000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K;
+ break;
+ case 16000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_16K;
+ break;
+ case 24000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_24K;
+ break;
+ case 32000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_32K;
break;
- case WSA_MACRO_RX_MIX1:
- path_reg = CDC_WSA_RX1_RX_PATH_MIX_CTL;
- gain_reg = CDC_WSA_RX1_RX_VOL_MIX_CTL;
+ case 48000:
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_48K;
break;
default:
- return 0;
+ rate_val = CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K;
+ break;
}
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- val = snd_soc_component_read(component, gain_reg);
- snd_soc_component_write(component, gain_reg, val);
+ /* Enable V&I sensing */
+ wsa_macro_enable_disable_vi_feedback(component, true, rate_val);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_soc_component_update_bits(component, path_reg,
- CDC_WSA_RX_PATH_MIX_CLK_EN_MASK,
- CDC_WSA_RX_PATH_MIX_CLK_DISABLE);
+ /* Disable V&I sensing */
+ wsa_macro_enable_disable_vi_feedback(component, false, rate_val);
break;
}
@@ -1300,7 +1611,7 @@ static int wsa_macro_config_compander(struct snd_soc_component *component,
return 0;
comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 +
- (comp * WSA_MACRO_RX_COMP_OFFSET);
+ (comp * wsa->reg_layout->compander1_reg_offset);
rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 +
(comp * WSA_MACRO_RX_PATH_OFFSET);
@@ -1346,8 +1657,8 @@ static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component,
int path,
bool enable)
{
- u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC +
- (path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+ u16 softclip_clk_reg = wsa->reg_layout->softclip0_reg_base +
+ (path * wsa->reg_layout->softclip1_reg_offset);
u8 softclip_mux_mask = (1 << path);
u8 softclip_mux_value = (1 << path);
@@ -1392,7 +1703,7 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component,
return 0;
softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL +
- (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET);
+ (softclip_path * wsa->reg_layout->softclip1_reg_offset);
if (SND_SOC_DAPM_EVENT_ON(event)) {
/* Enable Softclip clock and mux */
@@ -1414,58 +1725,6 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component,
return 0;
}
-static bool wsa_macro_adie_lb(struct snd_soc_component *component,
- int interp_idx)
-{
- u16 int_mux_cfg0, int_mux_cfg1;
- u8 int_n_inp0, int_n_inp1, int_n_inp2;
-
- int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8;
- int_mux_cfg1 = int_mux_cfg0 + 4;
-
- int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK);
- if (int_n_inp0 == INTn_1_INP_SEL_DEC0 ||
- int_n_inp0 == INTn_1_INP_SEL_DEC1)
- return true;
-
- int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0,
- CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK);
- if (int_n_inp1 == INTn_1_INP_SEL_DEC0 ||
- int_n_inp1 == INTn_1_INP_SEL_DEC1)
- return true;
-
- int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1,
- CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK);
- if (int_n_inp2 == INTn_1_INP_SEL_DEC0 ||
- int_n_inp2 == INTn_1_INP_SEL_DEC1)
- return true;
-
- return false;
-}
-
-static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol,
- int event)
-{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- u16 reg;
-
- reg = CDC_WSA_RX0_RX_PATH_CTL + WSA_MACRO_RX_PATH_OFFSET * w->shift;
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- if (wsa_macro_adie_lb(component, w->shift)) {
- snd_soc_component_update_bits(component, reg,
- CDC_WSA_RX_PATH_CLK_EN_MASK,
- CDC_WSA_RX_PATH_CLK_ENABLE);
- }
- break;
- default:
- break;
- }
- return 0;
-}
-
static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind)
{
u16 prim_int_reg = 0;
@@ -1583,8 +1842,6 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
u16 gain_reg;
u16 reg;
- int val;
- int offset_val = 0;
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
if (w->shift == WSA_MACRO_COMP1) {
@@ -1623,11 +1880,7 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
CDC_WSA_RX1_RX_PATH_MIX_SEC0,
CDC_WSA_RX_PGA_HALF_DB_MASK,
CDC_WSA_RX_PGA_HALF_DB_ENABLE);
- offset_val = -2;
}
- val = snd_soc_component_read(component, gain_reg);
- val += offset_val;
- snd_soc_component_write(component, gain_reg, val);
wsa_macro_config_ear_spkr_gain(component, wsa,
event, gain_reg);
break;
@@ -1654,10 +1907,6 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
CDC_WSA_RX1_RX_PATH_MIX_SEC0,
CDC_WSA_RX_PGA_HALF_DB_MASK,
CDC_WSA_RX_PGA_HALF_DB_DISABLE);
- offset_val = 2;
- val = snd_soc_component_read(component, gain_reg);
- val += offset_val;
- snd_soc_component_write(component, gain_reg, val);
}
wsa_macro_config_ear_spkr_gain(component, wsa,
event, gain_reg);
@@ -1675,16 +1924,19 @@ static int wsa_macro_spk_boost_event(struct snd_soc_dapm_widget *w,
u16 boost_path_ctl, boost_path_cfg1;
u16 reg, reg_mix;
- if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) {
+ if (!snd_soc_dapm_widget_name_cmp(w, "WSA_RX INT0 CHAIN")) {
boost_path_ctl = CDC_WSA_BOOST0_BOOST_PATH_CTL;
boost_path_cfg1 = CDC_WSA_RX0_RX_PATH_CFG1;
reg = CDC_WSA_RX0_RX_PATH_CTL;
reg_mix = CDC_WSA_RX0_RX_PATH_MIX_CTL;
- } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) {
+ } else if (!snd_soc_dapm_widget_name_cmp(w, "WSA_RX INT1 CHAIN")) {
boost_path_ctl = CDC_WSA_BOOST1_BOOST_PATH_CTL;
boost_path_cfg1 = CDC_WSA_RX1_RX_PATH_CFG1;
reg = CDC_WSA_RX1_RX_PATH_CTL;
reg_mix = CDC_WSA_RX1_RX_PATH_MIX_CTL;
+ } else {
+ dev_warn(component->dev, "Incorrect widget name in the driver\n");
+ return -EINVAL;
}
switch (event) {
@@ -1759,7 +2011,7 @@ static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -1771,7 +2023,7 @@ static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol,
static int wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
int value = ucontrol->value.integer.value[0];
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -1785,7 +2037,7 @@ static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -1796,7 +2048,7 @@ static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
int value = ucontrol->value.integer.value[0];
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -1809,7 +2061,7 @@ static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol,
static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wsa->ear_spkr_gain;
@@ -1820,7 +2072,7 @@ static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
wsa->ear_spkr_gain = ucontrol->value.integer.value[0];
@@ -1831,8 +2083,7 @@ static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -1845,8 +2096,7 @@ static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol,
static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget =
- snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component =
snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -1854,6 +2104,7 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
u32 rx_port_value = ucontrol->value.integer.value[0];
u32 bit_input;
u32 aif_rst;
+ unsigned int dai_id;
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
aif_rst = wsa->rx_port_value[widget->shift];
@@ -1871,17 +2122,22 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
switch (rx_port_value) {
case 0:
- if (wsa->active_ch_cnt[aif_rst]) {
- clear_bit(bit_input,
- &wsa->active_ch_mask[aif_rst]);
- wsa->active_ch_cnt[aif_rst]--;
+ /*
+ * active_ch_cnt and active_ch_mask use DAI IDs (WSA_MACRO_MAX_DAIS).
+ * active_ch_cnt == 0 was tested in if() above.
+ */
+ dai_id = aif_rst - 1;
+ if (wsa->active_ch_cnt[dai_id]) {
+ clear_bit(bit_input, &wsa->active_ch_mask[dai_id]);
+ wsa->active_ch_cnt[dai_id]--;
}
break;
case 1:
case 2:
- set_bit(bit_input,
- &wsa->active_ch_mask[rx_port_value]);
- wsa->active_ch_cnt[rx_port_value]++;
+ /* active_ch_cnt and active_ch_mask use DAI IDs (WSA_MACRO_MAX_DAIS). */
+ dai_id = rx_port_value - 1;
+ set_bit(bit_input, &wsa->active_ch_mask[dai_id]);
+ wsa->active_ch_cnt[dai_id]++;
break;
default:
dev_err(component->dev,
@@ -1898,7 +2154,7 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
int path = ((struct soc_mixer_control *)kcontrol->private_value)->shift;
@@ -1910,7 +2166,7 @@ static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol,
static int wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
int path = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
@@ -1936,6 +2192,10 @@ static const struct snd_kcontrol_new wsa_macro_snd_controls[] = {
-84, 40, digital_gain),
SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume", CDC_WSA_RX1_RX_VOL_CTL,
-84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("WSA_RX0_MIX Digital Volume", CDC_WSA_RX0_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("WSA_RX1_MIX Digital Volume", CDC_WSA_RX1_RX_VOL_MIX_CTL,
+ -84, 40, digital_gain),
SOC_SINGLE("WSA_RX0 Digital Mute", CDC_WSA_RX0_RX_PATH_CTL, 4, 1, 0),
SOC_SINGLE("WSA_RX1 Digital Mute", CDC_WSA_RX1_RX_PATH_CTL, 4, 1, 0),
@@ -1970,7 +2230,7 @@ static const struct snd_kcontrol_new rx_mux[WSA_MACRO_RX_MAX] = {
static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
@@ -1988,42 +2248,43 @@ static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol,
static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
u32 enable = ucontrol->value.integer.value[0];
u32 spk_tx_id = mixer->shift;
+ u32 dai_id = widget->shift;
if (enable) {
if (spk_tx_id == WSA_MACRO_TX0 &&
!test_bit(WSA_MACRO_TX0,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ &wsa->active_ch_mask[dai_id])) {
set_bit(WSA_MACRO_TX0,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
- wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+ &wsa->active_ch_mask[dai_id]);
+ wsa->active_ch_cnt[dai_id]++;
}
if (spk_tx_id == WSA_MACRO_TX1 &&
!test_bit(WSA_MACRO_TX1,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ &wsa->active_ch_mask[dai_id])) {
set_bit(WSA_MACRO_TX1,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
- wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++;
+ &wsa->active_ch_mask[dai_id]);
+ wsa->active_ch_cnt[dai_id]++;
}
} else {
if (spk_tx_id == WSA_MACRO_TX0 &&
test_bit(WSA_MACRO_TX0,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ &wsa->active_ch_mask[dai_id])) {
clear_bit(WSA_MACRO_TX0,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
- wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+ &wsa->active_ch_mask[dai_id]);
+ wsa->active_ch_cnt[dai_id]--;
}
if (spk_tx_id == WSA_MACRO_TX1 &&
test_bit(WSA_MACRO_TX1,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) {
+ &wsa->active_ch_mask[dai_id])) {
clear_bit(WSA_MACRO_TX1,
- &wsa->active_ch_mask[WSA_MACRO_AIF_VI]);
- wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--;
+ &wsa->active_ch_mask[dai_id]);
+ wsa->active_ch_cnt[dai_id]--;
}
}
snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL);
@@ -2078,23 +2339,8 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux),
- SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux),
- SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux),
- SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
- 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux),
- SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux),
- SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux),
- SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
- 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0,
- wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0,
- wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("WSA_RX INT1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -2141,6 +2387,28 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_1[] = {
+ SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX0 MIX INP", SND_SOC_NOPM, 0, 0, &rx0_mix_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_1),
+ SND_SOC_DAPM_MUX("WSA_RX1 MIX INP", SND_SOC_NOPM, 0, 0, &rx1_mix_mux_v2_1),
+};
+
+static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets_v2_5[] = {
+ SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX0 MIX INP", SND_SOC_NOPM, 0, 0, &rx0_mix_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux_v2_5),
+ SND_SOC_DAPM_MUX("WSA_RX1 MIX INP", SND_SOC_NOPM, 0, 0, &rx1_mix_mux_v2_5),
+};
+
static const struct snd_soc_dapm_route wsa_audio_map[] = {
/* VI Feedback */
{"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"},
@@ -2174,10 +2442,8 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = {
{"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"},
{"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"},
- {"WSA RX0", NULL, "WSA_RX0_CLK"},
- {"WSA RX1", NULL, "WSA_RX1_CLK"},
- {"WSA RX_MIX0", NULL, "WSA_RX_MIX0_CLK"},
- {"WSA RX_MIX1", NULL, "WSA_RX_MIX1_CLK"},
+ {"WSA_RX INT0 MIX", NULL, "WSA_RX0_CLK"},
+ {"WSA_RX INT1 MIX", NULL, "WSA_RX1_CLK"},
{"WSA_RX0 INP0", "RX0", "WSA RX0"},
{"WSA_RX0 INP0", "RX1", "WSA RX1"},
@@ -2207,6 +2473,8 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = {
{"WSA_RX0 MIX INP", "RX1", "WSA RX1"},
{"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
{"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX0 MIX INP", NULL, "WSA_RX0_CLK"},
+ {"WSA_RX0 MIX INP", NULL, "WSA_RX_MIX0_CLK"},
{"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"},
{"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"},
@@ -2246,6 +2514,8 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = {
{"WSA_RX1 MIX INP", "RX1", "WSA RX1"},
{"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"},
{"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"},
+ {"WSA_RX1 MIX INP", NULL, "WSA_RX1_CLK"},
+ {"WSA_RX1 MIX INP", NULL, "WSA_RX_MIX1_CLK"},
{"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"},
{"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"},
@@ -2286,7 +2556,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
static int wsa_macro_component_probe(struct snd_soc_component *comp)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp);
+ const struct snd_soc_dapm_widget *widgets;
+ unsigned int num_widgets;
snd_soc_component_init_regmap(comp, wsa->regmap);
@@ -2303,7 +2576,28 @@ static int wsa_macro_component_probe(struct snd_soc_component *comp)
wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1);
- return 0;
+ switch (wsa->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ widgets = wsa_macro_dapm_widgets_v2_1;
+ num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_1);
+ break;
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ case LPASS_CODEC_VERSION_2_9:
+ widgets = wsa_macro_dapm_widgets_v2_5;
+ num_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets_v2_5);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
}
static int swclk_gate_enable(struct clk_hw *hw)
@@ -2386,7 +2680,7 @@ static int wsa_macro_probe(struct platform_device *pdev)
struct wsa_macro *wsa;
kernel_ulong_t flags;
void __iomem *base;
- int ret;
+ int ret, def_count;
flags = (kernel_ulong_t)device_get_match_data(dev);
@@ -2396,31 +2690,81 @@ static int wsa_macro_probe(struct platform_device *pdev)
wsa->macro = devm_clk_get_optional(dev, "macro");
if (IS_ERR(wsa->macro))
- return PTR_ERR(wsa->macro);
+ return dev_err_probe(dev, PTR_ERR(wsa->macro), "unable to get macro clock\n");
wsa->dcodec = devm_clk_get_optional(dev, "dcodec");
if (IS_ERR(wsa->dcodec))
- return PTR_ERR(wsa->dcodec);
+ return dev_err_probe(dev, PTR_ERR(wsa->dcodec), "unable to get dcodec clock\n");
wsa->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(wsa->mclk))
- return PTR_ERR(wsa->mclk);
+ return dev_err_probe(dev, PTR_ERR(wsa->mclk), "unable to get mclk clock\n");
if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
wsa->npl = devm_clk_get(dev, "npl");
if (IS_ERR(wsa->npl))
- return PTR_ERR(wsa->npl);
+ return dev_err_probe(dev, PTR_ERR(wsa->npl), "unable to get npl clock\n");
}
wsa->fsgen = devm_clk_get(dev, "fsgen");
if (IS_ERR(wsa->fsgen))
- return PTR_ERR(wsa->fsgen);
+ return dev_err_probe(dev, PTR_ERR(wsa->fsgen), "unable to get fsgen clock\n");
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config);
+ wsa->codec_version = lpass_macro_get_codec_version();
+ struct reg_default *reg_defaults __free(kfree) = NULL;
+
+ switch (wsa->codec_version) {
+ case LPASS_CODEC_VERSION_1_0:
+ case LPASS_CODEC_VERSION_1_1:
+ case LPASS_CODEC_VERSION_1_2:
+ case LPASS_CODEC_VERSION_2_0:
+ case LPASS_CODEC_VERSION_2_1:
+ wsa->reg_layout = &wsa_codec_v2_1;
+ def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_1);
+ reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults),
+ GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], wsa_defaults, sizeof(wsa_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(wsa_defaults)],
+ wsa_defaults_v2_1, sizeof(wsa_defaults_v2_1));
+ break;
+
+ case LPASS_CODEC_VERSION_2_5:
+ case LPASS_CODEC_VERSION_2_6:
+ case LPASS_CODEC_VERSION_2_7:
+ case LPASS_CODEC_VERSION_2_8:
+ case LPASS_CODEC_VERSION_2_9:
+ wsa->reg_layout = &wsa_codec_v2_5;
+ def_count = ARRAY_SIZE(wsa_defaults) + ARRAY_SIZE(wsa_defaults_v2_5);
+ reg_defaults = kmalloc_array(def_count, sizeof(*reg_defaults),
+ GFP_KERNEL);
+ if (!reg_defaults)
+ return -ENOMEM;
+ memcpy(&reg_defaults[0], wsa_defaults, sizeof(wsa_defaults));
+ memcpy(&reg_defaults[ARRAY_SIZE(wsa_defaults)],
+ wsa_defaults_v2_5, sizeof(wsa_defaults_v2_5));
+ break;
+
+ default:
+ dev_err(dev, "Unsupported Codec version (%d)\n", wsa->codec_version);
+ return -EINVAL;
+ }
+
+ struct regmap_config *reg_config __free(kfree) = kmemdup(&wsa_regmap_config,
+ sizeof(*reg_config),
+ GFP_KERNEL);
+ if (!reg_config)
+ return -ENOMEM;
+
+ reg_config->reg_defaults = reg_defaults;
+ reg_config->num_reg_defaults = def_count;
+
+ wsa->regmap = devm_regmap_init_mmio(dev, base, reg_config);
if (IS_ERR(wsa->regmap))
return PTR_ERR(wsa->regmap);
@@ -2507,7 +2851,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);
@@ -2521,7 +2865,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;
@@ -2557,7 +2901,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[] = {
@@ -2584,10 +2928,10 @@ 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_new = wsa_macro_remove,
+ .remove = wsa_macro_remove,
};
module_platform_driver(wsa_macro_driver);
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index b9f19fbd2911..98d72db599d8 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>
@@ -540,10 +541,8 @@ EXPORT_SYMBOL_GPL(madera_domain_clk_ev);
int madera_out1_demux_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct madera *madera = priv->madera;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -631,8 +630,7 @@ EXPORT_SYMBOL_GPL(madera_out1_demux_put);
int madera_out1_demux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
unsigned int val;
val = snd_soc_component_read(component, MADERA_OUTPUT_ENABLES_1);
@@ -647,10 +645,8 @@ EXPORT_SYMBOL_GPL(madera_out1_demux_get);
static int madera_inmux_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct madera *madera = priv->madera;
struct regmap *regmap = madera->regmap;
@@ -872,8 +868,7 @@ static bool madera_can_change_grp_rate(const struct madera_priv *priv,
static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int cached_rate;
@@ -893,8 +888,7 @@ static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,
static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
const int adsp_num = e->shift_l;
@@ -1053,8 +1047,7 @@ EXPORT_SYMBOL_GPL(madera_set_adsp_clk);
int madera_rate_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int item = ucontrol->value.enumerated.item[0];
@@ -1213,8 +1206,7 @@ int madera_init_outputs(struct snd_soc_component *component,
const struct snd_soc_dapm_route *routes,
int n_mono_routes, int n_real)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct madera *madera = priv->madera;
const struct madera_codec_pdata *pdata = &madera->pdata.codec;
@@ -2162,10 +2154,8 @@ EXPORT_SYMBOL_GPL(madera_output_anc_src);
int madera_dfc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = e->reg;
unsigned int val;
@@ -2195,10 +2185,8 @@ int madera_lp_mode_put(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int val, mask;
int ret;
@@ -2322,10 +2310,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 +2344,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 +2363,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 +2380,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 +2763,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 +2774,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 +2787,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;
@@ -3240,8 +3228,7 @@ static int madera_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct snd_soc_dapm_route routes[2];
@@ -3884,7 +3871,7 @@ static inline int madera_set_fll_clks(struct madera_fll *fll, int base, bool ena
return madera_set_fll_clks_reg(fll, ena,
base + MADERA_FLL_CONTROL_6_OFFS,
MADERA_FLL1_REFCLK_SRC_MASK,
- MADERA_FLL1_REFCLK_DIV_SHIFT);
+ MADERA_FLL1_REFCLK_SRC_SHIFT);
}
static inline int madera_set_fllao_clks(struct madera_fll *fll, int base, bool ena)
@@ -3965,7 +3952,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 +4239,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 +4563,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,
@@ -4741,8 +4728,7 @@ static bool madera_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
int madera_eq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct madera *madera = priv->madera;
struct soc_bytes *params = (void *)kcontrol->private_value;
@@ -4788,8 +4774,7 @@ EXPORT_SYMBOL_GPL(madera_eq_coeff_put);
int madera_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
struct madera *madera = priv->madera;
__be16 *data = (__be16 *)ucontrol->value.bytes.data;
diff --git a/sound/soc/codecs/max9759.c b/sound/soc/codecs/max9759.c
index bc57d7687f16..9760543f2922 100644
--- a/sound/soc/codecs/max9759.c
+++ b/sound/soc/codecs/max9759.c
@@ -42,7 +42,7 @@ static const DECLARE_TLV_DB_SCALE(speaker_gain_tlv, 600, 600, 0);
static int speaker_gain_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct max9759 *priv = snd_soc_component_get_drvdata(c);
ucontrol->value.integer.value[0] = priv->gain;
@@ -61,7 +61,7 @@ static const bool speaker_gain_table[4][2] = {
static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct max9759 *priv = snd_soc_component_get_drvdata(c);
if (ucontrol->value.integer.value[0] < 0 ||
@@ -83,7 +83,7 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
static int speaker_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct max9759 *priv = snd_soc_component_get_drvdata(c);
ucontrol->value.integer.value[0] = !priv->is_mute;
@@ -94,7 +94,7 @@ static int speaker_mute_get(struct snd_kcontrol *kcontrol,
static int speaker_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct max9759 *priv = snd_soc_component_get_drvdata(c);
priv->is_mute = !ucontrol->value.integer.value[0];
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index d22b4ba51ed8..7ad7a9fb7255 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -9,7 +9,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <sound/core.h>
@@ -27,8 +27,8 @@
struct max9768 {
struct regmap *regmap;
- int mute_gpio;
- int shdn_gpio;
+ struct gpio_desc *mute;
+ struct gpio_desc *shdn;
u32 flags;
};
@@ -40,9 +40,9 @@ static const struct reg_default max9768_default_regs[] = {
static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
- int val = gpio_get_value_cansleep(max9768->mute_gpio);
+ int val = gpiod_get_value_cansleep(max9768->mute);
ucontrol->value.integer.value[0] = !val;
@@ -52,12 +52,19 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
+ bool val = !ucontrol->value.integer.value[0];
+ int ret;
- gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
+ if (val != gpiod_get_value_cansleep(max9768->mute))
+ ret = 1;
+ else
+ ret = 0;
- return 0;
+ gpiod_set_value_cansleep(max9768->mute, val);
+
+ return ret;
}
static const DECLARE_TLV_DB_RANGE(volume_tlv,
@@ -138,7 +145,7 @@ static int max9768_probe(struct snd_soc_component *component)
return ret;
}
- if (gpio_is_valid(max9768->mute_gpio)) {
+ if (max9768->mute) {
ret = snd_soc_add_component_controls(component, max9768_mute,
ARRAY_SIZE(max9768_mute));
if (ret)
@@ -171,28 +178,29 @@ static int max9768_i2c_probe(struct i2c_client *client)
{
struct max9768 *max9768;
struct max9768_pdata *pdata = client->dev.platform_data;
- int err;
max9768 = devm_kzalloc(&client->dev, sizeof(*max9768), GFP_KERNEL);
if (!max9768)
return -ENOMEM;
- if (pdata) {
- /* Mute on powerup to avoid clicks */
- err = devm_gpio_request_one(&client->dev, pdata->mute_gpio,
- GPIOF_INIT_HIGH, "MAX9768 Mute");
- max9768->mute_gpio = err ?: pdata->mute_gpio;
-
- /* Activate chip by releasing shutdown, enables I2C */
- err = devm_gpio_request_one(&client->dev, pdata->shdn_gpio,
- GPIOF_INIT_HIGH, "MAX9768 Shutdown");
- max9768->shdn_gpio = err ?: pdata->shdn_gpio;
-
+ /* Mute on powerup to avoid clicks */
+ max9768->mute = devm_gpiod_get_optional(&client->dev,
+ "mute",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(max9768->mute))
+ return PTR_ERR(max9768->mute);
+ gpiod_set_consumer_name(max9768->mute, "MAX9768 Mute");
+
+ /* Activate chip by releasing shutdown, enables I2C */
+ max9768->shdn = devm_gpiod_get_optional(&client->dev,
+ "shutdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(max9768->shdn))
+ return PTR_ERR(max9768->shdn);
+ gpiod_set_consumer_name(max9768->shdn, "MAX9768 Shutdown");
+
+ if (pdata)
max9768->flags = pdata->flags;
- } else {
- max9768->shdn_gpio = -EINVAL;
- max9768->mute_gpio = -EINVAL;
- }
i2c_set_clientdata(client, max9768);
@@ -205,7 +213,7 @@ static int max9768_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id max9768_i2c_id[] = {
- { "max9768", 0 },
+ { "max9768" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max9768_i2c_id);
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 8b56ee550c09..9f40ca4b60d5 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -380,7 +380,7 @@ static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -394,7 +394,7 @@ static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = max98088->mic1pre;
@@ -404,7 +404,7 @@ static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -418,7 +418,7 @@ static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = max98088->mic2pre;
@@ -480,12 +480,18 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+ SOC_SINGLE("DACL Volume", M98088_REG_2F_LVL_DAI1_PLAY, 0, 15, 1),
+ SOC_SINGLE("DACR Volume", M98088_REG_31_LVL_DAI2_PLAY, 0, 15, 1),
+
SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+ SOC_SINGLE("Left HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 4, 1, 0),
+ SOC_SINGLE("Right HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 5, 1, 0),
+
SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
@@ -515,10 +521,8 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
/* Left speaker mixer switch */
static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
@@ -529,10 +533,8 @@ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
/* Right speaker mixer switch */
static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
@@ -543,10 +545,8 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
/* Left headphone mixer switch */
static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
@@ -557,10 +557,8 @@ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
/* Right headphone mixer switch */
static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
@@ -571,10 +569,8 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
/* Left earpiece/receiver mixer switch */
static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
@@ -585,10 +581,8 @@ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
/* Right earpiece/receiver mixer switch */
static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
- SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
- SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
@@ -717,13 +711,9 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
- SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+ SND_SOC_DAPM_DAC("DACL", "HiFi Playback",
M98088_REG_4D_PWR_EN_OUT, 1, 0),
- SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
- M98088_REG_4D_PWR_EN_OUT, 0, 0),
- SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
- M98088_REG_4D_PWR_EN_OUT, 1, 0),
- SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+ SND_SOC_DAPM_DAC("DACR", "HiFi Playback",
M98088_REG_4D_PWR_EN_OUT, 0, 0),
SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
@@ -819,10 +809,8 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
static const struct snd_soc_dapm_route max98088_audio_map[] = {
/* Left headphone output mixer */
- {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
- {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
- {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
- {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left HP Mixer", "Left DAC Switch", "DACL"},
+ {"Left HP Mixer", "Right DAC Switch", "DACR"},
{"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
{"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
{"Left HP Mixer", "INA1 Switch", "INA1 Input"},
@@ -831,10 +819,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Left HP Mixer", "INB2 Switch", "INB2 Input"},
/* Right headphone output mixer */
- {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
- {"Right HP Mixer", "Left DAC2 Switch", "DACL2" },
- {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
- {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right HP Mixer", "Left DAC Switch", "DACL"},
+ {"Right HP Mixer", "Right DAC Switch", "DACR"},
{"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
{"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
{"Right HP Mixer", "INA1 Switch", "INA1 Input"},
@@ -843,10 +829,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Right HP Mixer", "INB2 Switch", "INB2 Input"},
/* Left speaker output mixer */
- {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
- {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
- {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
- {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left SPK Mixer", "Left DAC Switch", "DACL"},
+ {"Left SPK Mixer", "Right DAC Switch", "DACR"},
{"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
{"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
{"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
@@ -855,10 +839,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
/* Right speaker output mixer */
- {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
- {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
- {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
- {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right SPK Mixer", "Left DAC Switch", "DACL"},
+ {"Right SPK Mixer", "Right DAC Switch", "DACR"},
{"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
{"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
{"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
@@ -867,10 +849,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
/* Earpiece/Receiver output mixer */
- {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
- {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
- {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
- {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Left REC Mixer", "Left DAC Switch", "DACL"},
+ {"Left REC Mixer", "Right DAC Switch", "DACR"},
{"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
{"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
{"Left REC Mixer", "INA1 Switch", "INA1 Input"},
@@ -879,10 +859,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = {
{"Left REC Mixer", "INB2 Switch", "INB2 Input"},
/* Earpiece/Receiver output mixer */
- {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
- {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
- {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
- {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+ {"Right REC Mixer", "Left DAC Switch", "DACL"},
+ {"Right REC Mixer", "Right DAC Switch", "DACR"},
{"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
{"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
{"Right REC Mixer", "INA1 Switch", "INA1 Input"},
@@ -1318,6 +1296,8 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1332,16 +1312,18 @@ static int max98088_set_bias_level(struct snd_soc_component *component,
* enable it.
*/
if (!IS_ERR(max98088->mclk)) {
- if (snd_soc_component_get_bias_level(component) ==
- SND_SOC_BIAS_ON)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(max98088->mclk);
- else
- clk_prepare_enable(max98088->mclk);
+ } else {
+ ret = clk_prepare_enable(max98088->mclk);
+ if (ret)
+ return ret;
+ }
}
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
regcache_sync(max98088->regmap);
snd_soc_component_update_bits(component, M98088_REG_4C_PWR_EN_IN,
@@ -1518,7 +1500,7 @@ static void max98088_setup_eq2(struct snd_soc_component *component)
static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
struct max98088_pdata *pdata = max98088->pdata;
int channel = max98088_get_channel(component, kcontrol->id.name);
@@ -1550,7 +1532,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
int channel = max98088_get_channel(component, kcontrol->id.name);
struct max98088_cdata *cdata;
@@ -1749,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);
@@ -1765,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 7bc463910d4f..13a15459040f 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -347,7 +347,7 @@ static const DECLARE_TLV_DB_RANGE(max98090_rcv_lout_tlv,
static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -387,7 +387,7 @@ static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -817,6 +817,16 @@ static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);
static const struct snd_kcontrol_new max98090_dmic_mux =
SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum);
+static const char * const dmic_mX_mux_text[] = { "Enable", "Disable" };
+
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_m1_enum, dmic_mX_mux_text);
+static const struct snd_kcontrol_new max98090_dmic_m1_mux =
+ SOC_DAPM_ENUM("DMIC M1 Mux", dmic_m1_enum);
+
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_m2_enum, dmic_mX_mux_text);
+static const struct snd_kcontrol_new max98090_dmic_m2_mux =
+ SOC_DAPM_ENUM("DMIC M2 Mux", dmic_m2_enum);
+
/* LINEA mixer switch */
static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = {
SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG,
@@ -1106,6 +1116,9 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux),
+ SND_SOC_DAPM_MUX("DMIC M1 Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_dmic_m1_mux),
+
SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1144,7 +1157,7 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0,
SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_OUT("AIFOUTR", "HiFi Capture", 1,
+ SND_SOC_DAPM_AIF_OUT("AIFOUTR", "HiFi Capture", 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("LBENL Mux", SND_SOC_NOPM,
@@ -1234,9 +1247,21 @@ static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("DMIC4"),
SND_SOC_DAPM_SUPPLY("DMIC3_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMIC3_SHIFT, 0, NULL, 0),
+ M98090_DIGMIC3_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("DMIC4_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_DIGMIC4_SHIFT, 0, NULL, 0),
+ M98090_DIGMIC4_SHIFT, 0, max98090_shdn_event,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC34_HPF", M98090_REG_FILTER_CONFIG,
+ M98090_FLT_DMIC34HPF_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("DMIC M2 Mux", SND_SOC_NOPM, 0, 0,
+ &max98090_dmic_m2_mux),
+
+ SND_SOC_DAPM_AIF_OUT("AIFOUT2L", "HiFi Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIFOUT2R", "HiFi Capture", 0,
+ SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
@@ -1300,10 +1325,12 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"ADCL", NULL, "SHDN"},
{"ADCR", NULL, "SHDN"},
+ {"DMIC M1 Mux", "Enable", "DMICL"},
+ {"DMIC M1 Mux", "Enable", "DMICR"},
+
{"DMIC Mux", "ADC", "ADCL"},
{"DMIC Mux", "ADC", "ADCR"},
- {"DMIC Mux", "DMIC", "DMICL"},
- {"DMIC Mux", "DMIC", "DMICR"},
+ {"DMIC Mux", "DMIC", "DMIC M1 Mux"},
{"LBENL Mux", "Normal", "DMIC Mux"},
{"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1425,14 +1452,24 @@ static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
/* DMIC inputs */
{"DMIC3", NULL, "DMIC3_ENA"},
{"DMIC4", NULL, "DMIC4_ENA"},
- {"DMIC3", NULL, "AHPF"},
- {"DMIC4", NULL, "AHPF"},
+ {"DMIC3", NULL, "DMIC34_HPF"},
+ {"DMIC4", NULL, "DMIC34_HPF"},
+
+ {"DMIC M2 Mux", "Enable", "DMIC3"},
+ {"DMIC M2 Mux", "Enable", "DMIC4"},
+
+ {"AIFOUT2L", NULL, "DMIC M2 Mux"},
+ {"AIFOUT2R", NULL, "DMIC M2 Mux"},
+ {"AIFOUT2L", NULL, "SHDN"},
+ {"AIFOUT2R", NULL, "SHDN"},
+ {"AIFOUT2L", NULL, "SDOEN"},
+ {"AIFOUT2R", NULL, "SDOEN"},
};
static int max98090_add_widgets(struct snd_soc_component *component)
{
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_add_component_controls(component, max98090_snd_controls,
ARRAY_SIZE(max98090_snd_controls));
@@ -1581,7 +1618,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_component *component = codec_dai->component;
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
struct max98090_cdata *cdata;
- u8 regval;
+ u8 regval, tdm_regval;
max98090->dai_fmt = fmt;
cdata = &max98090->dai[0];
@@ -1590,6 +1627,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
cdata->fmt = fmt;
regval = 0;
+ tdm_regval = 0;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
/* Set to consumer mode PLL - MAS mode off */
@@ -1635,7 +1673,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
regval |= M98090_RJ_MASK;
break;
case SND_SOC_DAIFMT_DSP_A:
- /* Not supported mode */
+ tdm_regval |= M98090_TDM_MASK;
+ break;
default:
dev_err(component->dev, "DAI format unsupported");
return -EINVAL;
@@ -1664,11 +1703,20 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
* seen for the case of TDM mode. The remaining cases have
* normal logic.
*/
- if (max98090->tdm_slots > 1)
+ if (tdm_regval)
regval ^= M98090_BCI_MASK;
snd_soc_component_write(component,
M98090_REG_INTERFACE_FORMAT, regval);
+
+ regval = 0;
+ if (tdm_regval)
+ regval = max98090->tdm_lslot << M98090_TDM_SLOTL_SHIFT |
+ max98090->tdm_rslot << M98090_TDM_SLOTR_SHIFT |
+ 0 << M98090_TDM_SLOTDLY_SHIFT;
+
+ snd_soc_component_write(component, M98090_REG_TDM_FORMAT, regval);
+ snd_soc_component_write(component, M98090_REG_TDM_CONTROL, tdm_regval);
}
return 0;
@@ -1679,33 +1727,22 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
{
struct snd_soc_component *component = codec_dai->component;
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
- struct max98090_cdata *cdata;
- cdata = &max98090->dai[0];
if (slots < 0 || slots > 4)
return -EINVAL;
- max98090->tdm_slots = slots;
- max98090->tdm_width = slot_width;
-
- if (max98090->tdm_slots > 1) {
- /* SLOTL SLOTR SLOTDLY */
- snd_soc_component_write(component, M98090_REG_TDM_FORMAT,
- 0 << M98090_TDM_SLOTL_SHIFT |
- 1 << M98090_TDM_SLOTR_SHIFT |
- 0 << M98090_TDM_SLOTDLY_SHIFT);
-
- /* FSW TDM */
- snd_soc_component_update_bits(component, M98090_REG_TDM_CONTROL,
- M98090_TDM_MASK,
- M98090_TDM_MASK);
- }
+ if (slot_width != 16)
+ return -EINVAL;
- /*
- * Normally advisable to set TDM first, but this permits either order
- */
- cdata->fmt = 0;
- max98090_dai_set_fmt(codec_dai, max98090->dai_fmt);
+ if (rx_mask != tx_mask)
+ return -EINVAL;
+
+ if (!rx_mask)
+ return -EINVAL;
+
+ max98090->tdm_slots = slots;
+ max98090->tdm_lslot = ffs(rx_mask) - 1;
+ max98090->tdm_rslot = fls(rx_mask) - 1;
return 0;
}
@@ -1714,6 +1751,7 @@ static int max98090_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1731,7 +1769,7 @@ static int max98090_set_bias_level(struct snd_soc_component *component,
if (IS_ERR(max98090->mclk))
break;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(max98090->mclk);
} else {
ret = clk_prepare_enable(max98090->mclk);
@@ -1741,7 +1779,7 @@ static int max98090_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(max98090->regmap);
if (ret != 0) {
dev_err(component->dev,
@@ -2367,11 +2405,11 @@ static struct snd_soc_dai_driver max98090_dai = {
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rates = MAX98090_RATES,
.formats = MAX98090_FORMATS,
},
- .ops = &max98090_dai_ops,
+ .ops = &max98090_dai_ops,
};
static int max98090_probe(struct snd_soc_component *component)
@@ -2408,6 +2446,9 @@ static int max98090_probe(struct snd_soc_component *component)
max98090->pa1en = 0;
max98090->pa2en = 0;
+ max98090->tdm_lslot = 0;
+ max98090->tdm_rslot = 1;
+
ret = snd_soc_component_read(component, M98090_REG_REVISION_ID);
if (ret < 0) {
dev_err(component->dev, "Failed to read device revision: %d\n",
@@ -2540,8 +2581,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");
@@ -2551,21 +2590,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;
@@ -2617,7 +2642,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);
@@ -2639,9 +2663,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);
@@ -2658,12 +2680,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
@@ -2686,7 +2706,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/max98090.h b/sound/soc/codecs/max98090.h
index a197114b0dad..6ce8dd176e48 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1533,7 +1533,8 @@ struct max98090_priv {
struct snd_soc_jack *jack;
unsigned int dai_fmt;
int tdm_slots;
- int tdm_width;
+ int tdm_lslot;
+ int tdm_rslot;
u8 lin_state;
unsigned int pa1en;
unsigned int pa2en;
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 7e525d49328d..aae6423156e1 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -350,7 +350,7 @@ static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -364,7 +364,7 @@ static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = max98095->mic1pre;
@@ -374,7 +374,7 @@ static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
unsigned int sel = ucontrol->value.integer.value[0];
@@ -388,7 +388,7 @@ static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = max98095->mic2pre;
@@ -1359,6 +1359,7 @@ static int max98095_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1376,7 +1377,7 @@ static int max98095_set_bias_level(struct snd_soc_component *component,
if (IS_ERR(max98095->mclk))
break;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(max98095->mclk);
} else {
ret = clk_prepare_enable(max98095->mclk);
@@ -1386,7 +1387,7 @@ static int max98095_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(max98095->regmap);
if (ret != 0) {
@@ -1485,7 +1486,7 @@ static int max98095_get_eq_channel(const char *name)
static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_eq_channel(kcontrol->id.name);
@@ -1549,7 +1550,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
int channel = max98095_get_eq_channel(kcontrol->id.name);
struct max98095_cdata *cdata;
@@ -1636,7 +1637,7 @@ static int max98095_get_bq_channel(struct snd_soc_component *component,
static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_bq_channel(component, kcontrol->id.name);
@@ -1697,7 +1698,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
int channel = max98095_get_bq_channel(component, kcontrol->id.name);
struct max98095_cdata *cdata;
@@ -1917,11 +1918,12 @@ EXPORT_SYMBOL_GPL(max98095_jack_detect);
static int max98095_suspend(struct snd_soc_component *component)
{
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (max98095->headphone_jack || max98095->mic_jack)
max98095_jack_detect_disable(component);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1930,8 +1932,9 @@ static int max98095_resume(struct snd_soc_component *component)
{
struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
struct i2c_client *client = to_i2c_client(component->dev);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
if (max98095->headphone_jack || max98095->mic_jack) {
max98095_jack_detect_enable(component);
@@ -2115,7 +2118,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 +2133,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/max98357a.c b/sound/soc/codecs/max98357a.c
index 2a2b286f1747..cc811f58c9d2 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -8,7 +8,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c
index dcce06bff756..25af78ab30d5 100644
--- a/sound/soc/codecs/max98363.c
+++ b/sound/soc/codecs/max98363.c
@@ -14,12 +14,7 @@
#include "max98363.h"
-static struct reg_default max98363_reg[] = {
- {MAX98363_R2001_INTR_RAW, 0x0},
- {MAX98363_R2003_INTR_STATE, 0x0},
- {MAX98363_R2005_INTR_FALG, 0x0},
- {MAX98363_R2007_INTR_EN, 0x0},
- {MAX98363_R2009_INTR_CLR, 0x0},
+static const struct reg_default max98363_reg[] = {
{MAX98363_R2021_ERR_MON_CTRL, 0x0},
{MAX98363_R2022_SPK_MON_THRESH, 0x0},
{MAX98363_R2023_SPK_MON_DURATION, 0x0},
@@ -28,7 +23,6 @@ static struct reg_default max98363_reg[] = {
{MAX98363_R2040_AMP_VOL, 0x0},
{MAX98363_R2041_AMP_GAIN, 0x5},
{MAX98363_R2042_DSP_CFG, 0x0},
- {MAX98363_R21FF_REV_ID, 0x0},
};
static bool max98363_readable_register(struct device *dev, unsigned int reg)
@@ -166,35 +160,24 @@ static int max98363_io_init(struct sdw_slave *slave)
struct max98363_priv *max98363 = dev_get_drvdata(dev);
int ret, reg;
- if (max98363->first_hw_init) {
- regcache_cache_only(max98363->regmap, false);
+ regcache_cache_only(max98363->regmap, false);
+ if (max98363->first_hw_init)
regcache_cache_bypass(max98363->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!max98363->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
-
+ if (!max98363->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(dev);
-
- pm_runtime_enable(dev);
- }
-
pm_runtime_get_noresume(dev);
ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, &reg);
- if (!ret) {
+ if (!ret)
dev_info(dev, "Revision ID: %X\n", reg);
- return ret;
- }
+ else
+ goto out;
if (max98363->first_hw_init) {
regcache_cache_bypass(max98363->regmap, false);
@@ -204,14 +187,14 @@ static int max98363_io_init(struct sdw_slave *slave)
max98363->first_hw_init = true;
max98363->hw_init = true;
- pm_runtime_mark_last_busy(dev);
+out:
pm_runtime_put_autosuspend(dev);
- return 0;
+ return ret;
}
#define MAX98363_RATES SNDRV_PCM_RATE_8000_192000
-#define MAX98363_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+#define MAX98363_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
static int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -246,7 +229,7 @@ static int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream,
stream_config.frame_rate = params_rate(params);
stream_config.bps = snd_pcm_format_width(params_format(params));
stream_config.direction = direction;
- stream_config.ch_count = params_channels(params);
+ stream_config.ch_count = 1;
if (stream_config.ch_count > runtime->hw.channels_max) {
stream_config.ch_count = runtime->hw.channels_max;
@@ -330,7 +313,7 @@ static int max98363_update_status(struct sdw_slave *slave,
return max98363_io_init(slave);
}
-static struct sdw_slave_ops max98363_slave_ops = {
+static const struct sdw_slave_ops max98363_slave_ops = {
.read_prop = max98363_read_prop,
.update_status = max98363_update_status,
};
@@ -415,6 +398,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
max98363->regmap = regmap;
max98363->slave = slave;
+ regcache_cache_only(max98363->regmap, true);
+
max98363->hw_init = false;
max98363->first_hw_init = false;
@@ -422,10 +407,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363,
max98363_dai,
ARRAY_SIZE(max98363_dai));
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+ return 0;
}
static int max98363_sdw_probe(struct sdw_slave *slave,
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
index f0e49179c38f..852db211ba1e 100644
--- a/sound/soc/codecs/max98371.c
+++ b/sound/soc/codecs/max98371.c
@@ -400,7 +400,7 @@ static int max98371_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max98371_i2c_id[] = {
- { "max98371", 0 },
+ { "max98371" },
{ }
};
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 0fa5ceca62a2..f58b8c8625a7 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -3,12 +3,10 @@
#include <linux/acpi.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -25,7 +23,7 @@ static const u32 max98373_i2c_cache_reg[] = {
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
};
-static struct reg_default max98373_reg[] = {
+static const struct reg_default max98373_reg[] = {
{MAX98373_R2000_SW_RESET, 0x00},
{MAX98373_R2001_INT_RAW1, 0x00},
{MAX98373_R2002_INT_RAW2, 0x00},
@@ -474,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);
@@ -498,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 = {
@@ -560,21 +556,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c)
/* voltage/current slot & gpio configuration */
max98373_slot_config(&i2c->dev, max98373);
- /* Power on device */
- if (gpio_is_valid(max98373->reset_gpio)) {
- ret = devm_gpio_request(&i2c->dev, max98373->reset_gpio,
- "MAX98373_RESET");
- if (ret) {
- dev_err(&i2c->dev, "%s: Failed to request gpio %d\n",
- __func__, max98373->reset_gpio);
- return -EINVAL;
- }
- gpio_direction_output(max98373->reset_gpio, 0);
- msleep(50);
- gpio_direction_output(max98373->reset_gpio, 1);
- msleep(20);
- }
-
/* Check Revision ID */
ret = regmap_read(max98373->regmap,
MAX98373_R21FF_REV_ID, &reg);
@@ -595,7 +576,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max98373_i2c_id[] = {
- { "max98373", 0},
+ { "max98373"},
{ },
};
@@ -622,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 df92242af960..88ff215f52b3 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -26,7 +26,7 @@ static const u32 max98373_sdw_cache_reg[] = {
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
};
-static struct reg_default max98373_reg[] = {
+static const struct reg_default max98373_reg[] = {
{MAX98373_R0040_SCP_INIT_STAT_1, 0x00},
{MAX98373_R0041_SCP_INIT_MASK_1, 0x00},
{MAX98373_R0042_SCP_INIT_STAT_2, 0x00},
@@ -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)
@@ -361,28 +361,17 @@ static int max98373_io_init(struct sdw_slave *slave)
struct device *dev = &slave->dev;
struct max98373_priv *max98373 = dev_get_drvdata(dev);
- if (max98373->first_hw_init) {
- regcache_cache_only(max98373->regmap, false);
+ regcache_cache_only(max98373->regmap, false);
+ if (max98373->first_hw_init)
regcache_cache_bypass(max98373->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!max98373->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
-
+ if (!max98373->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(dev);
-
- pm_runtime_enable(dev);
- }
-
pm_runtime_get_noresume(dev);
/* Software Reset */
@@ -469,7 +458,6 @@ static int max98373_io_init(struct sdw_slave *slave)
max98373->first_hw_init = true;
max98373->hw_init = true;
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -753,6 +741,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
max98373->regmap = regmap;
max98373->slave = slave;
+ regcache_cache_only(max98373->regmap, true);
+
max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
max98373->cache = devm_kcalloc(dev, max98373->cache_num,
sizeof(*max98373->cache),
@@ -773,10 +763,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw,
max98373_sdw_dai,
ARRAY_SIZE(max98373_sdw_dai));
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ return 0;
}
static int max98373_update_status(struct sdw_slave *slave,
@@ -813,7 +820,7 @@ static int max98373_bus_config(struct sdw_slave *slave,
* slave_ops: callbacks for get_clock_stop_mode, clock_stop and
* port_prep are not defined for now
*/
-static struct sdw_slave_ops max98373_slave_ops = {
+static const struct sdw_slave_ops max98373_slave_ops = {
.read_prop = max98373_read_prop,
.update_status = max98373_update_status,
.bus_config = max98373_bus_config,
@@ -834,10 +841,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
static int max98373_sdw_remove(struct sdw_slave *slave)
{
- struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
-
- if (max98373->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -867,10 +871,9 @@ MODULE_DEVICE_TABLE(sdw, max98373_id);
static struct sdw_driver max98373_sdw_driver = {
.driver = {
.name = "max98373",
- .owner = THIS_MODULE,
.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/max98373.c b/sound/soc/codecs/max98373.c
index fde055c6c894..cfb95fd4f85e 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -12,9 +12,8 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <sound/tlv.h>
#include "max98373.h"
@@ -175,12 +174,13 @@ static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
int i;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/*
* Register values will be cached before suspend. The cached value
* will be a valid value and userspace will happy with that.
@@ -478,20 +478,24 @@ void max98373_slot_config(struct device *dev,
max98373->i_slot = value & 0xF;
else
max98373->i_slot = 1;
- if (dev->of_node) {
- max98373->reset_gpio = of_get_named_gpio(dev->of_node,
- "maxim,reset-gpio", 0);
- if (!gpio_is_valid(max98373->reset_gpio)) {
- dev_err(dev, "Looking up %s property in node %s failed %d\n",
- "maxim,reset-gpio", dev->of_node->full_name,
- max98373->reset_gpio);
- } else {
- dev_dbg(dev, "maxim,reset-gpio=%d",
- max98373->reset_gpio);
- }
- } else {
- /* this makes reset_gpio as invalid */
- max98373->reset_gpio = -1;
+
+ /* This will assert RESET */
+ max98373->reset = devm_gpiod_get_optional(dev,
+ "maxim,reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(max98373->reset)) {
+ dev_err(dev, "error %ld looking up RESET GPIO line\n",
+ PTR_ERR(max98373->reset));
+ return;
+ }
+
+ /* Cycle reset */
+ if (max98373->reset) {
+ gpiod_set_consumer_name(max98373->reset ,"MAX98373_RESET");
+ gpiod_direction_output(max98373->reset, 1);
+ msleep(50);
+ gpiod_direction_output(max98373->reset, 0);
+ msleep(20);
}
if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h
index e1810b3b1620..af3b62217497 100644
--- a/sound/soc/codecs/max98373.h
+++ b/sound/soc/codecs/max98373.h
@@ -213,7 +213,7 @@ struct max98373_cache {
struct max98373_priv {
struct regmap *regmap;
- int reset_gpio;
+ struct gpio_desc *reset;
unsigned int v_slot;
unsigned int i_slot;
unsigned int spkfb_slot;
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
index 3d03c4bac6c5..076f15a9867e 100644
--- a/sound/soc/codecs/max98388.c
+++ b/sound/soc/codecs/max98388.c
@@ -3,12 +3,11 @@
#include <linux/acpi.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -19,7 +18,7 @@
#include <sound/tlv.h>
#include "max98388.h"
-static struct reg_default max98388_reg[] = {
+static const struct reg_default max98388_reg[] = {
{MAX98388_R2000_SW_RESET, 0x00},
{MAX98388_R2001_INT_RAW1, 0x00},
{MAX98388_R2002_INT_RAW2, 0x00},
@@ -764,6 +763,7 @@ static int max98388_dai_tdm_slot(struct snd_soc_dai *dai,
addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8);
bits = cnt % 8;
regmap_update_bits(max98388->regmap, addr, bits, bits);
+ slot_found++;
if (slot_found >= MAX_NUM_CH)
break;
}
@@ -887,7 +887,7 @@ static const struct regmap_config max98388_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-const struct snd_soc_component_driver soc_codec_dev_max98388 = {
+static const struct snd_soc_component_driver soc_codec_dev_max98388 = {
.probe = max98388_probe,
.controls = max98388_snd_controls,
.num_controls = ARRAY_SIZE(max98388_snd_controls),
@@ -960,7 +960,7 @@ static int max98388_i2c_probe(struct i2c_client *i2c)
ret = regmap_read(max98388->regmap,
MAX98388_R22FF_REV_ID, &reg);
if (ret < 0)
- return dev_err_probe(&i2c->dev, PTR_ERR(max98388->regmap),
+ return dev_err_probe(&i2c->dev, ret,
"Failed to read the revision ID\n");
dev_info(&i2c->dev, "MAX98388 revisionID: 0x%02X\n", reg);
@@ -977,7 +977,7 @@ static int max98388_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max98388_i2c_id[] = {
- { "max98388", 0},
+ { "max98388"},
{ },
};
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 5b8e78e51630..3dd4dd94bc37 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -13,7 +13,6 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/time.h>
@@ -24,7 +23,7 @@
#include "max98390.h"
-static struct reg_default max98390_reg_defaults[] = {
+static const struct reg_default max98390_reg_defaults[] = {
{MAX98390_INT_EN1, 0xf0},
{MAX98390_INT_EN2, 0x00},
{MAX98390_INT_EN3, 0x00},
@@ -535,8 +534,7 @@ static SOC_ENUM_SINGLE_DECL(max98390_current_limit,
static int max98390_ref_rdc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
@@ -555,8 +553,7 @@ static int max98390_ref_rdc_put(struct snd_kcontrol *kcontrol,
static int max98390_ref_rdc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
@@ -568,8 +565,7 @@ static int max98390_ref_rdc_get(struct snd_kcontrol *kcontrol,
static int max98390_ambient_temp_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
@@ -586,8 +582,7 @@ static int max98390_ambient_temp_put(struct snd_kcontrol *kcontrol,
static int max98390_ambient_temp_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
@@ -599,8 +594,7 @@ static int max98390_ambient_temp_get(struct snd_kcontrol *kcontrol,
static int max98390_adaptive_rdc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
dev_warn(component->dev, "Put adaptive rdc not supported\n");
@@ -611,8 +605,7 @@ static int max98390_adaptive_rdc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int rdc, rdc0;
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
@@ -633,9 +626,9 @@ static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol,
static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val;
snd_soc_dapm_mutex_lock(dapm);
@@ -944,7 +937,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);
@@ -968,10 +960,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 = {
@@ -1104,7 +1095,7 @@ static int max98390_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max98390_i2c_id[] = {
- { "max98390", 0},
+ { "max98390"},
{},
};
@@ -1131,7 +1122,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 3a1d8c211f3c..18fd90227187 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -7,7 +7,6 @@
#include <sound/pcm_params.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
#include <sound/tlv.h>
#include "max98396.h"
@@ -17,7 +16,7 @@ static const char * const max98396_core_supplies[MAX98396_NUM_CORE_SUPPLIES] = {
"dvddio",
};
-static struct reg_default max98396_reg[] = {
+static const struct reg_default max98396_reg[] = {
{MAX98396_R2000_SW_RESET, 0x00},
{MAX98396_R2001_INT_RAW1, 0x00},
{MAX98396_R2002_INT_RAW2, 0x00},
@@ -175,7 +174,7 @@ static struct reg_default max98396_reg[] = {
{MAX98396_R21FF_REVISION_ID, 0x00},
};
-static struct reg_default max98397_reg[] = {
+static const struct reg_default max98397_reg[] = {
{MAX98396_R2000_SW_RESET, 0x00},
{MAX98396_R2001_INT_RAW1, 0x00},
{MAX98396_R2002_INT_RAW2, 0x00},
@@ -954,8 +953,7 @@ static const DECLARE_TLV_DB_RANGE(max98397_spk_tlv,
static int max98396_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
int reg, val;
@@ -974,9 +972,8 @@ static int max98396_mux_get(struct snd_kcontrol *kcontrol,
static int max98396_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -1108,6 +1105,7 @@ static int max98396_adc_value_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
@@ -1116,7 +1114,7 @@ static int max98396_adc_value_get(struct snd_kcontrol *kcontrol,
int reg = mc->reg;
/* ADC value is not available if the device is powered down */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
goto exit;
if (max98396->device_id == CODEC_TYPE_MAX98397) {
@@ -1572,7 +1570,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);
@@ -1617,10 +1614,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 = {
@@ -1905,7 +1901,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/max9850.c b/sound/soc/codecs/max9850.c
index 8b012a85360a..1fcbc64a2771 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -225,6 +225,7 @@ static int max9850_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -233,7 +234,7 @@ static int max9850_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(max9850->regmap);
if (ret) {
dev_err(component->dev,
@@ -320,7 +321,7 @@ static int max9850_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max9850_i2c_id[] = {
- { "max9850", 0 },
+ { "max9850" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max9850_i2c_id);
diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c
index 93412b966b33..c94142768c81 100644
--- a/sound/soc/codecs/max98504.c
+++ b/sound/soc/codecs/max98504.c
@@ -35,7 +35,7 @@ struct max98504_priv {
unsigned int brownout_release_rate;
};
-static struct reg_default max98504_reg_defaults[] = {
+static const struct reg_default max98504_reg_defaults[] = {
{ 0x01, 0},
{ 0x02, 0},
{ 0x03, 0},
@@ -220,8 +220,10 @@ static int max98504_set_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
static int max98504_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
struct regmap *map = max98504->regmap;
diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c
index 8637fff307ad..2bf8976c1828 100644
--- a/sound/soc/codecs/max98520.c
+++ b/sound/soc/codecs/max98520.c
@@ -11,14 +11,12 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <sound/tlv.h>
#include "max98520.h"
-static struct reg_default max98520_reg[] = {
+static const struct reg_default max98520_reg[] = {
{MAX98520_R2000_SW_RESET, 0x00},
{MAX98520_R2001_STATUS_1, 0x00},
{MAX98520_R2002_STATUS_2, 0x00},
@@ -623,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);
@@ -632,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);
@@ -643,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 = {
@@ -736,7 +734,7 @@ static int max98520_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max98520_i2c_id[] = {
- { "max98520", 0},
+ { "max98520"},
{ },
};
@@ -754,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/max9867.c b/sound/soc/codecs/max9867.c
index b616ad39858c..9cad9b698cf2 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -56,13 +56,13 @@ static int max9867_adc_dac_event(struct snd_soc_dapm_widget *w,
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
enum max9867_adc_dac adc_dac;
- if (!strcmp(w->name, "ADCL"))
+ if (!snd_soc_dapm_widget_name_cmp(w, "ADCL"))
adc_dac = MAX9867_ADC_LEFT;
- else if (!strcmp(w->name, "ADCR"))
+ else if (!snd_soc_dapm_widget_name_cmp(w, "ADCR"))
adc_dac = MAX9867_ADC_RIGHT;
- else if (!strcmp(w->name, "DACL"))
+ else if (!snd_soc_dapm_widget_name_cmp(w, "DACL"))
adc_dac = MAX9867_DAC_LEFT;
- else if (!strcmp(w->name, "DACR"))
+ else if (!snd_soc_dapm_widget_name_cmp(w, "DACR"))
adc_dac = MAX9867_DAC_RIGHT;
else
return 0;
@@ -78,7 +78,7 @@ static int max9867_adc_dac_event(struct snd_soc_dapm_widget *w,
static int max9867_filter_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
unsigned int reg;
int ret;
@@ -98,7 +98,7 @@ static int max9867_filter_get(struct snd_kcontrol *kcontrol,
static int max9867_filter_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
unsigned int reg, mode = ucontrol->value.enumerated.item[0];
int ret;
@@ -556,14 +556,18 @@ static struct snd_soc_dai_driver max9867_dai[] = {
#ifdef CONFIG_PM
static int max9867_suspend(struct snd_soc_component *component)
{
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
return 0;
}
static int max9867_resume(struct snd_soc_component *component)
{
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -577,6 +581,7 @@ static int max9867_set_bias_level(struct snd_soc_component *component,
{
int err;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -585,7 +590,7 @@ static int max9867_set_bias_level(struct snd_soc_component *component,
return err;
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
err = regcache_sync(max9867->regmap);
if (err)
return err;
@@ -684,7 +689,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max9867_i2c_id[] = {
- { "max9867", 0 },
+ { "max9867" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max9867_i2c_id);
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
index 2ae64fcf29c7..1bd0d4761ca6 100644
--- a/sound/soc/codecs/max9877.c
+++ b/sound/soc/codecs/max9877.c
@@ -151,7 +151,7 @@ static int max9877_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id max9877_i2c_id[] = {
- { "max9877", 0 },
+ { "max9877" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index a9c1d85cd0d5..124af6408d96 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -97,7 +97,7 @@ static const struct snd_kcontrol_new max98925_dai_sel_mux =
static int max98925_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
switch (event) {
@@ -617,7 +617,7 @@ static int max98925_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id max98925_i2c_id[] = {
- { "max98925", 0 },
+ { "max98925" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index bdc508e23e59..ae962bda163e 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -528,7 +528,8 @@ static int max98926_i2c_probe(struct i2c_client *i2c)
"Failed to allocate regmap: %d\n", ret);
goto err_out;
}
- if (of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
+ if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") ||
+ of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
max98926->interleave_mode = true;
if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
@@ -564,7 +565,7 @@ err_out:
}
static const struct i2c_device_id max98926_i2c_id[] = {
- { "max98926", 0 },
+ { "max98926" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max98926_i2c_id);
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 0aaf2e6ae78d..0e9b8970997c 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -15,13 +15,11 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_gpio.h>
#include <sound/tlv.h>
#include "max98927.h"
-static struct reg_default max98927_reg[] = {
+static const struct reg_default max98927_reg[] = {
{MAX98927_R0001_INT_RAW1, 0x00},
{MAX98927_R0002_INT_RAW2, 0x00},
{MAX98927_R0003_INT_RAW3, 0x00},
@@ -162,10 +160,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0021_PCM_MASTER_MODE,
- MAX98927_PCM_MASTER_MODE_MASK,
- mode);
+ regmap_update_bits(max98927->regmap, MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MASK, mode);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -178,10 +174,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
- invert);
+ regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, invert);
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -207,36 +201,31 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
if (!use_pdm) {
/* pcm channel configuration */
- regmap_update_bits(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
+ regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_FORMAT_MASK,
- format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_FORMAT_MASK,
+ format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
- regmap_update_bits(max98927->regmap,
- MAX98927_R003B_SPK_SRC_SEL,
- MAX98927_SPK_SRC_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R0035_PDM_RX_CTRL,
- MAX98927_PDM_RX_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 0);
} else {
/* pdm channel configuration */
- regmap_update_bits(max98927->regmap,
- MAX98927_R0035_PDM_RX_CTRL,
- MAX98927_PDM_RX_EN_MASK, 1);
+ regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 1);
- regmap_update_bits(max98927->regmap,
- MAX98927_R003B_SPK_SRC_SEL,
- MAX98927_SPK_SRC_MASK, 3);
+ regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 3);
- regmap_update_bits(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+ 0);
}
return 0;
}
@@ -283,9 +272,9 @@ static int max98927_set_clock(struct max98927_priv *max98927,
return -EINVAL;
}
regmap_update_bits(max98927->regmap,
- MAX98927_R0021_PCM_MASTER_MODE,
- MAX98927_PCM_MASTER_MODE_MCLK_MASK,
- i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+ i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
}
if (!max98927->tdm_mode) {
@@ -298,9 +287,8 @@ static int max98927_set_clock(struct max98927_priv *max98927,
}
regmap_update_bits(max98927->regmap,
- MAX98927_R0022_PCM_CLK_SETUP,
- MAX98927_PCM_CLK_SETUP_BSEL_MASK,
- value);
+ MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK, value);
}
return 0;
}
@@ -333,9 +321,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
max98927->ch_size = snd_pcm_format_width(params_format(params));
- regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+ regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
dev_dbg(component->dev, "format supported %d",
params_format(params));
@@ -375,27 +362,24 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
goto err;
}
/* set DAI_SR to correct LRCLK frequency */
- regmap_update_bits(max98927->regmap,
- MAX98927_R0023_PCM_SR_SETUP1,
- MAX98927_PCM_SR_SET1_SR_MASK,
- sampling_rate);
- regmap_update_bits(max98927->regmap,
- MAX98927_R0024_PCM_SR_SETUP2,
- MAX98927_PCM_SR_SET2_SR_MASK,
- sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+ regmap_update_bits(max98927->regmap, MAX98927_R0023_PCM_SR_SETUP1,
+ MAX98927_PCM_SR_SET1_SR_MASK, sampling_rate);
+ regmap_update_bits(max98927->regmap, MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_SR_MASK,
+ sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
/* set sampling rate of IV */
if (max98927->interleave_mode &&
sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
regmap_update_bits(max98927->regmap,
- MAX98927_R0024_PCM_SR_SETUP2,
- MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
- sampling_rate - 3);
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate - 3);
else
regmap_update_bits(max98927->regmap,
- MAX98927_R0024_PCM_SR_SETUP2,
- MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
- sampling_rate);
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate);
return max98927_set_clock(max98927, params);
err:
return -EINVAL;
@@ -420,10 +404,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0022_PCM_CLK_SETUP,
- MAX98927_PCM_CLK_SETUP_BSEL_MASK,
- bsel);
+ regmap_update_bits(max98927->regmap, MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK, bsel);
/* Channel size configuration */
switch (slot_width) {
@@ -442,33 +424,26 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+ regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
/* Rx slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- rx_mask & 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R0019_PCM_RX_EN_B,
- (rx_mask & 0xFF00) >> 8);
+ regmap_write(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+ rx_mask & 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R0019_PCM_RX_EN_B,
+ (rx_mask & 0xFF00) >> 8);
/* Tx slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001A_PCM_TX_EN_A,
- tx_mask & 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R001B_PCM_TX_EN_B,
- (tx_mask & 0xFF00) >> 8);
+ regmap_write(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+ tx_mask & 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+ (tx_mask & 0xFF00) >> 8);
/* Tx slot Hi-Z configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- ~tx_mask & 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- (~tx_mask & 0xFF00) >> 8);
+ regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ ~tx_mask & 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ (~tx_mask & 0xFF00) >> 8);
return 0;
}
@@ -506,20 +481,16 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
max98927->tdm_mode = false;
break;
case SND_SOC_DAPM_POST_PMU:
- regmap_update_bits(max98927->regmap,
- MAX98927_R003A_AMP_EN,
- MAX98927_AMP_EN_MASK, 1);
- regmap_update_bits(max98927->regmap,
- MAX98927_R00FF_GLOBAL_SHDN,
- MAX98927_GLOBAL_EN_MASK, 1);
+ regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 1);
+ regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- regmap_update_bits(max98927->regmap,
- MAX98927_R00FF_GLOBAL_SHDN,
- MAX98927_GLOBAL_EN_MASK, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R003A_AMP_EN,
- MAX98927_AMP_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 0);
break;
default:
return 0;
@@ -532,8 +503,8 @@ static const char * const max98927_switch_text[] = {
static const struct soc_enum dai_sel_enum =
SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
- MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
- 3, max98927_switch_text);
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 3,
+ max98927_switch_text);
static const struct snd_kcontrol_new max98927_dai_controls =
SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
@@ -543,17 +514,17 @@ static const struct snd_kcontrol_new max98927_vi_control =
static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
- 0, 0, max98927_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ 0, 0, max98927_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
- &max98927_dai_controls),
+ &max98927_dai_controls),
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
- MAX98927_R003E_MEAS_EN, 0, 0),
+ MAX98927_R003E_MEAS_EN, 0, 0),
SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
- MAX98927_R003E_MEAS_EN, 1, 0),
+ MAX98927_R003E_MEAS_EN, 1, 0),
SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
- &max98927_vi_control),
+ &max98927_vi_control),
SND_SOC_DAPM_SIGGEN("VMON"),
SND_SOC_DAPM_SIGGEN("IMON"),
};
@@ -623,20 +594,19 @@ static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
max98927_current_limit_text);
static const struct snd_kcontrol_new max98927_snd_controls[] = {
- SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
- 0, 6, 0,
- max98927_spk_tlv),
+ SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, 0, 6, 0,
+ max98927_spk_tlv),
SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
- 0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
- max98927_digital_tlv),
+ 0, (1 << MAX98927_AMP_VOL_WIDTH) - 1, 0,
+ max98927_digital_tlv),
SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
- MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
+ MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
- MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
- SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
- MAX98927_DRE_EN_SHIFT, 1, 0),
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
+ SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL, MAX98927_DRE_EN_SHIFT,
+ 1, 0),
SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
- MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+ MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
SOC_ENUM("Current Limit", max98927_current_limit),
};
@@ -682,121 +652,85 @@ static int max98927_probe(struct snd_soc_component *component)
max98927->component = component;
/* Software Reset */
- regmap_write(max98927->regmap,
- MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+ regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
+ MAX98927_SOFT_RESET);
/* IV default slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
- 0x80);
- regmap_write(max98927->regmap,
- MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
- 0x1);
+ regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ 0x80);
+ regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+ 0x1);
/* Set inital volume (+13dB) */
- regmap_write(max98927->regmap,
- MAX98927_R0036_AMP_VOL_CTRL,
- 0x38);
- regmap_write(max98927->regmap,
- MAX98927_R003C_SPK_GAIN,
- 0x05);
+ regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38);
+ regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05);
/* Enable DC blocker */
- regmap_write(max98927->regmap,
- MAX98927_R0037_AMP_DSP_CFG,
- 0x03);
+ regmap_write(max98927->regmap, MAX98927_R0037_AMP_DSP_CFG, 0x03);
/* Enable IMON VMON DC blocker */
- regmap_write(max98927->regmap,
- MAX98927_R003F_MEAS_DSP_CFG,
- 0xF7);
+ regmap_write(max98927->regmap, MAX98927_R003F_MEAS_DSP_CFG, 0xF7);
/* Boost Output Voltage & Current limit */
- regmap_write(max98927->regmap,
- MAX98927_R0040_BOOST_CTRL0,
- 0x1C);
- regmap_write(max98927->regmap,
- MAX98927_R0042_BOOST_CTRL1,
- 0x3E);
+ regmap_write(max98927->regmap, MAX98927_R0040_BOOST_CTRL0, 0x1C);
+ regmap_write(max98927->regmap, MAX98927_R0042_BOOST_CTRL1, 0x3E);
/* Measurement ADC config */
- regmap_write(max98927->regmap,
- MAX98927_R0043_MEAS_ADC_CFG,
- 0x04);
- regmap_write(max98927->regmap,
- MAX98927_R0044_MEAS_ADC_BASE_MSB,
- 0x00);
- regmap_write(max98927->regmap,
- MAX98927_R0045_MEAS_ADC_BASE_LSB,
- 0x24);
+ regmap_write(max98927->regmap, MAX98927_R0043_MEAS_ADC_CFG, 0x04);
+ regmap_write(max98927->regmap, MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00);
+ regmap_write(max98927->regmap, MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x24);
/* Brownout Level */
- regmap_write(max98927->regmap,
- MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
- 0x06);
+ regmap_write(max98927->regmap, MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+ 0x06);
/* Envelope Tracking configuration */
- regmap_write(max98927->regmap,
- MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
- 0x08);
- regmap_write(max98927->regmap,
- MAX98927_R0086_ENV_TRACK_CTRL,
- 0x01);
- regmap_write(max98927->regmap,
- MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
- 0x10);
+ regmap_write(max98927->regmap, MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+ 0x08);
+ regmap_write(max98927->regmap, MAX98927_R0086_ENV_TRACK_CTRL, 0x01);
+ regmap_write(max98927->regmap, MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+ 0x10);
/* voltage, current slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001E_PCM_TX_CH_SRC_A,
- (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
- max98927->v_l_slot)&0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001E_PCM_TX_CH_SRC_A,
+ (max98927->i_l_slot << MAX98927_PCM_TX_CH_SRC_A_I_SHIFT | max98927->v_l_slot) & 0xFF);
if (max98927->v_l_slot < 8) {
regmap_update_bits(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- 1 << max98927->v_l_slot, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001A_PCM_TX_EN_A,
- 1 << max98927->v_l_slot,
- 1 << max98927->v_l_slot);
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->v_l_slot, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->v_l_slot,
+ 1 << max98927->v_l_slot);
} else {
regmap_update_bits(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- 1 << (max98927->v_l_slot - 8), 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001B_PCM_TX_EN_B,
- 1 << (max98927->v_l_slot - 8),
- 1 << (max98927->v_l_slot - 8));
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->v_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->v_l_slot - 8),
+ 1 << (max98927->v_l_slot - 8));
}
if (max98927->i_l_slot < 8) {
regmap_update_bits(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- 1 << max98927->i_l_slot, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001A_PCM_TX_EN_A,
- 1 << max98927->i_l_slot,
- 1 << max98927->i_l_slot);
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->i_l_slot, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->i_l_slot,
+ 1 << max98927->i_l_slot);
} else {
regmap_update_bits(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- 1 << (max98927->i_l_slot - 8), 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001B_PCM_TX_EN_B,
- 1 << (max98927->i_l_slot - 8),
- 1 << (max98927->i_l_slot - 8));
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->i_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->i_l_slot - 8),
+ 1 << (max98927->i_l_slot - 8));
}
/* Set interleave mode */
if (max98927->interleave_mode)
regmap_update_bits(max98927->regmap,
- MAX98927_R001F_PCM_TX_CH_SRC_B,
- MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
- MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
+ MAX98927_R001F_PCM_TX_CH_SRC_B,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int max98927_suspend(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
@@ -809,16 +743,15 @@ static int max98927_resume(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
- regmap_write(max98927->regmap,
- MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+ regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
+ MAX98927_SOFT_RESET);
regcache_cache_only(max98927->regmap, false);
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 = {
@@ -869,9 +802,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
int reg = 0;
struct max98927_priv *max98927 = NULL;
- max98927 = devm_kzalloc(&i2c->dev,
- sizeof(*max98927), GFP_KERNEL);
-
+ max98927 = devm_kzalloc(&i2c->dev, sizeof(*max98927), GFP_KERNEL);
if (!max98927) {
ret = -ENOMEM;
return ret;
@@ -879,14 +810,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, max98927);
/* update interleave mode info */
- if (!of_property_read_u32(i2c->dev.of_node,
- "interleave_mode", &value)) {
- if (value > 0)
- max98927->interleave_mode = true;
- else
- max98927->interleave_mode = false;
- } else
- max98927->interleave_mode = false;
+ if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode")) {
+ max98927->interleave_mode = true;
+ } else {
+ if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode",
+ &value))
+ if (value > 0)
+ max98927->interleave_mode = true;
+ }
/* regmap initialization */
max98927->regmap
@@ -897,9 +828,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
"Failed to allocate regmap: %d\n", ret);
return ret;
}
-
- max98927->reset_gpio
- = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH);
+
+ max98927->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset",
+ GPIOD_OUT_HIGH);
if (IS_ERR(max98927->reset_gpio)) {
ret = PTR_ERR(max98927->reset_gpio);
return dev_err_probe(&i2c->dev, ret, "failed to request GPIO reset pin");
@@ -912,8 +843,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
}
/* Check Revision ID */
- ret = regmap_read(max98927->regmap,
- MAX98927_R01FF_REV_ID, &reg);
+ ret = regmap_read(max98927->regmap, MAX98927_R01FF_REV_ID, &reg);
if (ret < 0) {
dev_err(&i2c->dev,
"Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
@@ -938,13 +868,12 @@ static void max98927_i2c_remove(struct i2c_client *i2c)
{
struct max98927_priv *max98927 = i2c_get_clientdata(i2c);
- if (max98927->reset_gpio) {
+ if (max98927->reset_gpio)
gpiod_set_value_cansleep(max98927->reset_gpio, 1);
- }
}
static const struct i2c_device_id max98927_i2c_id[] = {
- { "max98927", 0},
+ { "max98927"},
{ },
};
@@ -971,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/ml26124.c b/sound/soc/codecs/ml26124.c
index a45ef9d65703..fad0cc902346 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -459,6 +459,7 @@ static int ml26124_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -473,7 +474,7 @@ static int ml26124_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
/* VMID ON */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component, ML26124_PW_REF_PW_MNG,
ML26124_VMID, ML26124_VMID);
msleep(500);
@@ -572,7 +573,7 @@ static int ml26124_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ml26124_i2c_id[] = {
- { "ml26124", 0 },
+ { "ml26124" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index cec90cf920ff..9ca381812975 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -7,7 +7,6 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
-#include <linux/clk.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -1198,12 +1197,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- priv->mclk = devm_clk_get(dev, "mclk");
- if (IS_ERR(priv->mclk)) {
- dev_err(dev, "failed to get mclk\n");
- return PTR_ERR(priv->mclk);
- }
-
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
priv->supplies[i].supply = supply_names[i];
@@ -1214,55 +1207,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
return ret;
}
- ret = clk_prepare_enable(priv->mclk);
- if (ret < 0) {
- dev_err(dev, "failed to enable mclk %d\n", ret);
- return ret;
- }
-
irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
- if (irq < 0) {
- ret = irq;
- goto err_disable_clk;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_threaded_irq(dev, irq, NULL,
pm8916_mbhc_switch_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"mbhc switch irq", priv);
- if (ret)
+ if (ret) {
dev_err(dev, "cannot request mbhc switch irq\n");
+ return ret;
+ }
if (priv->mbhc_btn_enabled) {
irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
- if (irq < 0) {
- ret = irq;
- goto err_disable_clk;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_threaded_irq(dev, irq, NULL,
mbhc_btn_press_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"mbhc btn press irq", priv);
- if (ret)
+ if (ret) {
dev_err(dev, "cannot request mbhc button press irq\n");
+ return ret;
+ }
irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
- if (irq < 0) {
- ret = irq;
- goto err_disable_clk;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_threaded_irq(dev, irq, NULL,
mbhc_btn_release_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"mbhc btn release irq", priv);
- if (ret)
+ if (ret) {
dev_err(dev, "cannot request mbhc button release irq\n");
-
+ return ret;
+ }
}
dev_set_drvdata(dev, priv);
@@ -1270,17 +1256,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
return devm_snd_soc_register_component(dev, &pm8916_wcd_analog,
pm8916_wcd_analog_dai,
ARRAY_SIZE(pm8916_wcd_analog_dai));
-
-err_disable_clk:
- clk_disable_unprepare(priv->mclk);
- return ret;
-}
-
-static void pm8916_wcd_analog_spmi_remove(struct platform_device *pdev)
-{
- struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(priv->mclk);
}
static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
@@ -1296,7 +1271,6 @@ static struct platform_driver pm8916_wcd_analog_spmi_driver = {
.of_match_table = pm8916_wcd_analog_spmi_match_table,
},
.probe = pm8916_wcd_analog_spmi_probe,
- .remove_new = pm8916_wcd_analog_spmi_remove,
};
module_platform_driver(pm8916_wcd_analog_spmi_driver);
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index 978c4d056e81..cfadea2aa1f7 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -423,8 +423,7 @@ static int msm8x16_wcd_get_iir_band_audio_mixer(
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd_iir_filter_ctl *ctl =
(struct wcd_iir_filter_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -469,8 +468,7 @@ static int msm8x16_wcd_put_iir_band_audio_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd_iir_filter_ctl *ctl =
(struct wcd_iir_filter_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -1241,7 +1239,7 @@ static struct platform_driver msm8916_wcd_digital_driver = {
.of_match_table = msm8916_wcd_digital_match_table,
},
.probe = msm8916_wcd_digital_probe,
- .remove_new = msm8916_wcd_digital_remove,
+ .remove = msm8916_wcd_digital_remove,
};
module_platform_driver(msm8916_wcd_digital_driver);
diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c
index d2cf4847eead..2a5e963fb2b5 100644
--- a/sound/soc/codecs/mt6351.c
+++ b/sound/soc/codecs/mt6351.c
@@ -8,8 +8,8 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/delay.h>
#include <sound/core.h>
diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c
new file mode 100644
index 000000000000..674cf7df9df4
--- /dev/null
+++ b/sound/soc/codecs/mt6357.c
@@ -0,0 +1,1855 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MT6357 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2024 Baylibre
+ * Author: Nicolas Belin <nbelin@baylibre.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/regulator/consumer.h>
+
+#include "mt6357.h"
+
+static void set_playback_gpio(struct mt6357_priv *priv, bool enable)
+{
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, MT6357_GPIO_MODE2_CLEAR_ALL);
+ if (enable) {
+ /* set gpio mosi mode */
+ regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET,
+ MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI |
+ MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0 |
+ MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1 |
+ MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI);
+ } else {
+ /* pad_aud_*_mosi are GPIO mode after clear and set them to dir input
+ * reason:
+ * pad_aud_dat_mosi*, because the pin is used as boot strap
+ */
+ regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0,
+ MT6357_GPIO8_DIR_MASK |
+ MT6357_GPIO9_DIR_MASK |
+ MT6357_GPIO10_DIR_MASK |
+ MT6357_GPIO11_DIR_MASK,
+ MT6357_GPIO8_DIR_INPUT |
+ MT6357_GPIO9_DIR_INPUT |
+ MT6357_GPIO10_DIR_INPUT |
+ MT6357_GPIO11_DIR_INPUT);
+ }
+}
+
+static void set_capture_gpio(struct mt6357_priv *priv, bool enable)
+{
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, MT6357_GPIO_MODE3_CLEAR_ALL);
+ if (enable) {
+ /* set gpio miso mode */
+ regmap_write(priv->regmap, MT6357_GPIO_MODE3_SET,
+ MT6357_GPIO12_MODE_SET_AUD_CLK_MISO |
+ MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0 |
+ MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1 |
+ MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO);
+ } else {
+ /* pad_aud_*_mosi are GPIO mode after clear and set them to dir input
+ * reason:
+ * pad_aud_clk_miso, because when playback only the miso_clk
+ * will also have 26m, so will have power leak
+ * pad_aud_dat_miso*, because the pin is used as boot strap
+ */
+ regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0,
+ MT6357_GPIO12_DIR_MASK |
+ MT6357_GPIO13_DIR_MASK |
+ MT6357_GPIO14_DIR_MASK |
+ MT6357_GPIO15_DIR_MASK,
+ MT6357_GPIO12_DIR_INPUT |
+ MT6357_GPIO13_DIR_INPUT |
+ MT6357_GPIO14_DIR_INPUT |
+ MT6357_GPIO15_DIR_INPUT);
+ }
+}
+
+static void hp_main_output_ramp(struct mt6357_priv *priv, bool up)
+{
+ int i, stage;
+
+ /* Enable/Reduce HPL/R main output stage step by step */
+ for (i = 0; i <= MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX; i++) {
+ stage = up ? i : MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX - i;
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK,
+ stage << MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT);
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_STG_CTRL_VAUDP15_MASK,
+ stage << MT6357_HPROUT_STG_CTRL_VAUDP15_SFT);
+ usleep_range(600, 700);
+ }
+}
+
+static void hp_aux_feedback_loop_gain_ramp(struct mt6357_priv *priv, bool up)
+{
+ int i, stage;
+
+ /* Reduce HP aux feedback loop gain step by step */
+ for (i = 0; i <= MT6357_HP_AUX_LOOP_GAIN_MAX; i++) {
+ stage = up ? i : MT6357_HP_AUX_LOOP_GAIN_MAX - i;
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HP_AUX_LOOP_GAIN_MASK,
+ stage << MT6357_HP_AUX_LOOP_GAIN_SFT);
+ usleep_range(600, 700);
+ }
+}
+
+static void hp_pull_down(struct mt6357_priv *priv, bool enable)
+{
+ if (enable)
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ MT6357_HPP_SHORT_2VCM_VAUDP15_MASK,
+ MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE);
+ else
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ MT6357_HPP_SHORT_2VCM_VAUDP15_MASK,
+ MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE);
+}
+
+static bool is_valid_hp_pga_idx(int reg_idx)
+{
+ return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) || reg_idx == DL_GAIN_N_40DB;
+}
+
+static void volume_ramp(struct mt6357_priv *priv, int lfrom, int lto,
+ int rfrom, int rto, unsigned int reg_addr)
+{
+ int lcount, rcount, sleep = 0;
+
+ if (!is_valid_hp_pga_idx(lfrom) || !is_valid_hp_pga_idx(lto))
+ pr_debug("%s(), invalid left volume index, from %d, to %d\n",
+ __func__, lfrom, lto);
+
+ if (!is_valid_hp_pga_idx(rfrom) || !is_valid_hp_pga_idx(rto))
+ pr_debug("%s(), invalid right volume index, from %d, to %d\n",
+ __func__, rfrom, rto);
+
+ if (lto > lfrom)
+ lcount = 1;
+ else
+ lcount = -1;
+
+ if (rto > rfrom)
+ rcount = 1;
+ else
+ rcount = -1;
+
+ while ((lto != lfrom) || (rto != rfrom)) {
+ if (lto != lfrom) {
+ lfrom += lcount;
+ if (is_valid_hp_pga_idx(lfrom)) {
+ regmap_update_bits(priv->regmap, reg_addr,
+ MT6357_DL_GAIN_REG_LEFT_MASK,
+ lfrom << MT6357_DL_GAIN_REG_LEFT_SHIFT);
+ sleep = 1;
+ }
+ }
+ if (rto != rfrom) {
+ rfrom += rcount;
+ if (is_valid_hp_pga_idx(rfrom)) {
+ regmap_update_bits(priv->regmap, reg_addr,
+ MT6357_DL_GAIN_REG_RIGHT_MASK,
+ rfrom << MT6357_DL_GAIN_REG_RIGHT_SHIFT);
+ sleep = 1;
+ }
+ }
+ if (sleep)
+ usleep_range(200, 300);
+ }
+}
+
+static void lo_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
+{
+ volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON1);
+}
+
+static void hp_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
+{
+ volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON2);
+}
+
+static void hs_volume_ramp(struct mt6357_priv *priv, int from, int to)
+{
+ volume_ramp(priv, from, to, 0, 0, MT6357_ZCD_CON3);
+}
+
+/* Volume and channel swap controls */
+static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_degain_tlv, -1200, 1200, 0);
+
+static const struct snd_kcontrol_new mt6357_controls[] = {
+ /* dl pga gain */
+ SOC_DOUBLE_TLV("Headphone Volume",
+ MT6357_ZCD_CON2, MT6357_AUD_HPL_GAIN_SFT,
+ MT6357_AUD_HPR_GAIN_SFT, MT6357_AUD_HP_GAIN_MAX,
+ 1, playback_tlv),
+ SOC_SINGLE_TLV("Headphone Vin Volume",
+ MT6357_AUDDEC_ANA_CON7, MT6357_HP_IVBUF_DEGAIN_SFT,
+ MT6357_HP_IVBUF_DEGAIN_MAX, 1, hp_degain_tlv),
+ SOC_DOUBLE_TLV("Lineout Volume",
+ MT6357_ZCD_CON1, MT6357_AUD_LOL_GAIN_SFT,
+ MT6357_AUD_LOR_GAIN_SFT, MT6357_AUD_LO_GAIN_MAX,
+ 1, playback_tlv),
+ SOC_SINGLE_TLV("Handset Volume",
+ MT6357_ZCD_CON3, MT6357_AUD_HS_GAIN_SFT,
+ MT6357_AUD_HS_GAIN_MAX, 1, playback_tlv),
+ /* ul pga gain */
+ SOC_DOUBLE_R_TLV("Mic Volume",
+ MT6357_AUDENC_ANA_CON0, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPLGAIN_SFT, MT6357_AUDPREAMPLGAIN_MAX,
+ 0, capture_tlv),
+};
+
+/* Uplink controls */
+
+enum {
+ MIC_TYPE_MUX_IDLE,
+ MIC_TYPE_MUX_ACC,
+ MIC_TYPE_MUX_DMIC,
+ MIC_TYPE_MUX_DCC,
+ MIC_TYPE_MUX_DCC_ECM_DIFF,
+ MIC_TYPE_MUX_DCC_ECM_SINGLE,
+ MIC_TYPE_MUX_LPBK,
+ MIC_TYPE_MUX_SGEN,
+};
+
+#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \
+ (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \
+ (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE)
+
+static const char * const mic_type_mux_map[] = {
+ "Idle",
+ "ACC",
+ "DMIC",
+ "DCC",
+ "DCC_ECM_DIFF",
+ "DCC_ECM_SINGLE",
+ "Loopback",
+ "Sine Generator",
+};
+
+static SOC_ENUM_SINGLE_DECL(mic_type_mux_map_enum, SND_SOC_NOPM,
+ 0, mic_type_mux_map);
+
+static const struct snd_kcontrol_new mic_type_mux_control =
+ SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum);
+
+static const char * const pga_mux_map[] = {
+ "None", "AIN0", "AIN1", "AIN2"
+};
+
+static SOC_ENUM_SINGLE_DECL(pga_left_mux_map_enum,
+ MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLINPUTSEL_SFT,
+ pga_mux_map);
+
+static const struct snd_kcontrol_new pga_left_mux_control =
+ SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum);
+
+static SOC_ENUM_SINGLE_DECL(pga_right_mux_map_enum,
+ MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRINPUTSEL_SFT,
+ pga_mux_map);
+
+static const struct snd_kcontrol_new pga_right_mux_control =
+ SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum);
+
+/* Downlink controls */
+static const char * const hslo_mux_map[] = {
+ "Open", "DACR", "Playback", "Test mode"
+};
+
+static SOC_ENUM_SINGLE_DECL(lo_mux_map_enum,
+ MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT,
+ hslo_mux_map);
+
+static const struct snd_kcontrol_new lo_mux_control =
+ SOC_DAPM_ENUM("Line out source", lo_mux_map_enum);
+
+static SOC_ENUM_SINGLE_DECL(hs_mux_map_enum,
+ MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT,
+ hslo_mux_map);
+
+static const struct snd_kcontrol_new hs_mux_control =
+ SOC_DAPM_ENUM("Handset source", hs_mux_map_enum);
+
+static const char * const hplr_mux_map[] = {
+ "Open", "Line Out", "DAC", "Handset"
+};
+
+static SOC_ENUM_SINGLE_DECL(hpr_mux_map_enum,
+ MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT,
+ hplr_mux_map);
+
+static const struct snd_kcontrol_new hpr_mux_control =
+ SOC_DAPM_ENUM("Headphone Right source", hpr_mux_map_enum);
+
+static SOC_ENUM_SINGLE_DECL(hpl_mux_map_enum,
+ MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT,
+ hplr_mux_map);
+
+static const struct snd_kcontrol_new hpl_mux_control =
+ SOC_DAPM_ENUM("Headphone Left source", hpl_mux_map_enum);
+
+static const char * const dac_mux_map[] = {
+ "Normal Path", "Sine Generator"
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_mux_map_enum,
+ MT6357_AFE_TOP_CON0,
+ MT6357_DL_SINE_ON_SFT,
+ dac_mux_map);
+
+static const struct snd_kcontrol_new dac_mux_control =
+ SOC_DAPM_ENUM("DAC Select", dac_mux_map_enum);
+
+static int mt6357_set_dmic(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* DMIC enable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7,
+ MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK,
+ MT6357_AUDDIGMICBIAS_DEFAULT_VALUE | MT6357_AUDDIGMICEN_ENABLE);
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* UL dmic setting: dual mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H,
+ MT6357_C_TWO_DIGITAL_MIC_CTL_MASK,
+ MT6357_C_TWO_DIGITAL_MIC_ENABLE);
+ /* UL turn on SDM 3 level mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SDM_3_LEVEL_CTL_MASK,
+ MT6357_UL_SDM_3_LEVEL_SELECT);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK,
+ MT6357_UL_SRC_ENABLE);
+ /* Wait to avoid any pop noises */
+ msleep(100);
+ } else {
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK,
+ MT6357_UL_SRC_DISABLE);
+ /* UL turn on SDM 3 level mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SDM_3_LEVEL_CTL_MASK,
+ MT6357_UL_SDM_3_LEVEL_DESELECT);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ /* UL dmic setting: dual mode */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H,
+ MT6357_C_TWO_DIGITAL_MIC_CTL_MASK,
+ MT6357_C_TWO_DIGITAL_MIC_DISABLE);
+ /* DMIC disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7,
+ MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK,
+ MT6357_AUDDIGMICBIAS_OFF | MT6357_AUDDIGMICEN_DISABLE);
+ }
+ return 0;
+}
+
+static int mt6357_set_amic(struct mt6357_priv *priv, bool enable, unsigned int mic_type)
+{
+ if (enable) {
+ if (IS_DCC_BASE(mic_type)) {
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_RUN_VALUE);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_OUTPUT);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_ON);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG1,
+ MT6357_DCCLK_RESYNC_BYPASS_MASK,
+ MT6357_DCCLK_RESYNC_BYPASS);
+
+ /* mic bias 0: set the correct DC couple*/
+ switch (mic_type) {
+ case MIC_TYPE_MUX_DCC_ECM_DIFF:
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ MT6357_AUD_MICBIAS0_DC_MASK,
+ MT6357_AUD_MICBIAS0_DC_ENABLE_ALL);
+ break;
+ case MIC_TYPE_MUX_DCC_ECM_SINGLE:
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ MT6357_AUD_MICBIAS0_DC_MASK,
+ MT6357_AUD_MICBIAS0_DC_ENABLE_P1);
+ break;
+ default:
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ MT6357_AUD_MICBIAS0_DC_MASK,
+ MT6357_AUD_MICBIAS0_DC_DISABLE_ALL);
+ break;
+ }
+
+ /* mic bias 1: set the correct DC couple */
+ if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE)
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+ MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK,
+ MT6357_AUD_MICBIAS1_DCSW1P_ENABLE);
+
+ /* Audio L/R preamplifier DCC precharge */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPLDCPRECHARGE_ENABLE);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPRDCPRECHARGE_ENABLE);
+ /* L preamplifier DCCEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCCEN_MASK,
+ MT6357_AUDPREAMPLDCCEN_DC);
+ /* R preamplifier DCCEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCCEN_MASK,
+ MT6357_AUDPREAMPRDCCEN_DC);
+ } else {
+ /* Audio L preamplifier DCC precharge disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPLDCPRECHARGE_DISABLE);
+ /* L preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCCEN_MASK,
+ MT6357_AUDPREAMPLDCCEN_AC);
+ /* Audio R preamplifier DCC precharge disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPRDCPRECHARGE_DISABLE);
+ /* R preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCCEN_MASK,
+ MT6357_AUDPREAMPRDCCEN_AC);
+ }
+ } else {
+ /* disable any Mic Bias 0 DC couple */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ MT6357_AUD_MICBIAS0_DC_MASK,
+ MT6357_AUD_MICBIAS0_DC_DISABLE_ALL);
+ /* disable any Mic Bias 1 DC couple */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+ MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK,
+ MT6357_AUD_MICBIAS1_DCSW1P_DISABLE);
+ if (IS_DCC_BASE(mic_type)) {
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_OFF);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_PDN);
+ regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+ MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_STOP_VALUE);
+ }
+ }
+
+ return 0;
+}
+
+static int mt6357_set_loopback(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* enable aud_pad lpk TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_LPBK_MASK,
+ MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE);
+ /* Set UL Part: enable new lpbk 2 */
+ regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0,
+ MT6357_ADDA_MTKAIF_LPBK_CTL_MASK,
+ MT6357_ADDA_MTKAIF_LPBK_ENABLE);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK,
+ MT6357_UL_SRC_ENABLE);
+ } else {
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK,
+ MT6357_UL_SRC_DISABLE);
+ /* disable new lpbk 2 */
+ regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0,
+ MT6357_ADDA_MTKAIF_LPBK_CTL_MASK,
+ MT6357_ADDA_MTKAIF_LPBK_DISABLE);
+ /* disable aud_pad lpbk TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_LPBK_MASK,
+ MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ }
+
+ return 0;
+}
+
+static int mt6357_set_ul_sine_gen(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK,
+ MT6357_UL_SRC_ENABLE);
+ } else {
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK,
+ MT6357_UL_SRC_DISABLE);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ }
+
+ return 0;
+}
+
+static int mt_aif_out_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ set_capture_gpio(priv, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ set_capture_gpio(priv, false);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_adc_supply_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable audio ADC CLKGEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ MT6357_RSTB_ENCODER_VA28_MASK, MT6357_RSTB_ENCODER_VA28_ENABLE);
+ /* Enable LCLDO_ENC 2P8V */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ MT6357_LCLDO_ENC_EN_VA28_MASK, MT6357_LCLDO_ENC_EN_VA28_ENABLE);
+ /* LCLDO_ENC remote sense */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ MT6357_VA28REFGEN_EN_VA28_MASK |
+ MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK,
+ MT6357_VA28REFGEN_EN_VA28_ENABLE |
+ MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* LCLDO_ENC remote sense off */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ MT6357_VA28REFGEN_EN_VA28_MASK |
+ MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK,
+ MT6357_VA28REFGEN_EN_VA28_DISABLE |
+ MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE);
+ /* disable LCLDO_ENC 2P8V */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ MT6357_LCLDO_ENC_EN_VA28_MASK,
+ MT6357_LCLDO_ENC_EN_VA28_DISABLE);
+ /* disable audio ADC CLKGEN */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ MT6357_RSTB_ENCODER_VA28_MASK,
+ MT6357_RSTB_ENCODER_VA28_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_mic_type_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ unsigned int mic_type = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (mic_type) {
+ case MIC_TYPE_MUX_DMIC:
+ mt6357_set_dmic(priv, true);
+ break;
+ case MIC_TYPE_MUX_LPBK:
+ mt6357_set_loopback(priv, true);
+ break;
+ case MIC_TYPE_MUX_SGEN:
+ mt6357_set_ul_sine_gen(priv, true);
+ break;
+ default:
+ mt6357_set_amic(priv, true, mic_type);
+ break;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ switch (mic_type) {
+ case MIC_TYPE_MUX_DMIC:
+ mt6357_set_dmic(priv, false);
+ break;
+ case MIC_TYPE_MUX_LPBK:
+ mt6357_set_loopback(priv, false);
+ break;
+ case MIC_TYPE_MUX_SGEN:
+ mt6357_set_ul_sine_gen(priv, false);
+ break;
+ default:
+ mt6357_set_amic(priv, false, mic_type);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_pga_left_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* L preamplifier enable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLON_MASK,
+ MT6357_AUDPREAMPLON_ENABLE);
+ /* L ADC input sel : L PGA. Enable audio L ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDADCLINPUTSEL_MASK,
+ MT6357_AUDADCLINPUTSEL_PREAMPLIFIER);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDADCLPWRUP_MASK,
+ MT6357_AUDADCLPWRUP);
+ /* Audio L preamplifier DCC precharge off */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPLDCPRECHARGE_DISABLE);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Audio L ADC input sel : off, disable audio L ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDADCLPWRUP_MASK,
+ MT6357_AUDADCLPWRDOWN);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDADCLINPUTSEL_MASK,
+ MT6357_AUDADCLINPUTSEL_IDLE);
+ /* L preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCCEN_MASK,
+ MT6357_AUDPREAMPLDCCEN_AC);
+ /* L preamplifier disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLON_MASK,
+ MT6357_AUDPREAMPLON_DISABLE);
+ /* disable Audio L preamplifier DCC precharge */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPLDCPRECHARGE_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_pga_right_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* R preamplifier enable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_ENABLE);
+ /* R ADC input sel : R PGA. Enable audio R ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDADCRINPUTSEL_MASK,
+ MT6357_AUDADCRINPUTSEL_PREAMPLIFIER);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRUP);
+ /* Audio R preamplifier DCC precharge off */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPRDCPRECHARGE_DISABLE);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Audio R ADC input sel : off, disable audio R ADC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRDOWN);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDADCRINPUTSEL_MASK, MT6357_AUDADCRINPUTSEL_IDLE);
+ /* R preamplifier ACC */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCCEN_MASK, MT6357_AUDPREAMPRDCCEN_AC);
+ /* R preamplifier disable */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_DISABLE);
+ /* disable Audio R preamplifier DCC precharge */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+ MT6357_AUDPREAMPRDCPRECHARGE_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int adc_enable_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ int lgain, rgain;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON0, &lgain);
+ regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON1, &rgain);
+ /* L PGA 0 dB gain */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLGAIN_MASK,
+ UL_GAIN_0DB << MT6357_AUDPREAMPLGAIN_SFT);
+ /* R PGA 0 dB gain */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRGAIN_MASK,
+ UL_GAIN_0DB << MT6357_AUDPREAMPRGAIN_SFT);
+ /* enable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+ /* UL turn on */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE);
+ /* Wait to avoid any pop noises */
+ msleep(100);
+ /* set the mic gains to the stored values */
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+ MT6357_AUDPREAMPLGAIN_MASK, lgain);
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+ MT6357_AUDPREAMPRGAIN_MASK, rgain);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* UL turn off */
+ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+ MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE);
+ /* disable aud_pad TX fifos */
+ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+ MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void configure_downlinks(struct mt6357_priv *priv, bool enable)
+{
+ if (enable) {
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ELR_0,
+ MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK,
+ MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE);
+ /* Disable headphone short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_SC_VAUDP15_MASK | MT6357_AUD_HPL_SC_VAUDP15_MASK,
+ MT6357_AUD_HPR_SC_VAUDP15_DISABLE |
+ MT6357_AUD_HPL_SC_VAUDP15_DISABLE);
+ /* Disable handset short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_SC_VAUDP15_MASK,
+ MT6357_AUD_HS_SC_VAUDP15_DISABLE);
+ /* Disable lineout short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_SC_VAUDP15_MASK,
+ MT6357_AUD_LOL_SC_VAUDP15_DISABLE);
+ /* Reduce ESD resistance of AU_REFN */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ MT6357_AUD_REFN_DERES_VAUDP15_MASK,
+ MT6357_AUD_REFN_DERES_VAUDP15_ENABLE);
+ /* Turn on DA_600K_NCP_VA18 */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON1, MT6357_DIVCKS_ON);
+ /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON2, 0x002c);
+ /* Toggle DIVCKS_CHG */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON0, MT6357_DIVCKS_CHG);
+ /* Set NCP soft start mode as default mode: 150us */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON4,
+ MT6357_DIVCKS_PWD_NCP_ST_150US);
+ /* Enable NCP */
+ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3,
+ MT6357_DIVCKS_PWD_NCP_ENABLE);
+ usleep_range(250, 270);
+ /* Enable cap-less LDOs (1.5V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ MT6357_VA33REFGEN_EN_VA18_MASK |
+ MT6357_LCLDO_REMOTE_SENSE_VA18_MASK |
+ MT6357_LCLDO_EN_VA18_MASK |
+ MT6357_HCLDO_REMOTE_SENSE_VA18_MASK |
+ MT6357_HCLDO_EN_VA18_MASK,
+ MT6357_VA33REFGEN_EN_VA18_ENABLE |
+ MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE |
+ MT6357_LCLDO_EN_VA18_ENABLE |
+ MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE |
+ MT6357_HCLDO_EN_VA18_ENABLE);
+ /* Enable NV regulator (-1.2V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13,
+ MT6357_NVREG_EN_VAUDP15_MASK, MT6357_NVREG_EN_VAUDP15_ENABLE);
+ usleep_range(100, 120);
+ /* Enable IBIST */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10,
+ MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK,
+ MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE);
+ /* Enable AUD_CLK */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ MT6357_RSTB_DECODER_VA28_MASK,
+ MT6357_RSTB_DECODER_VA28_ENABLE);
+ /* Enable low-noise mode of DAC */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_DAC_LOW_NOISE_MODE_MASK,
+ MT6357_DAC_LOW_NOISE_MODE_ENABLE);
+ usleep_range(100, 120);
+ } else {
+ /* Disable low-noise mode of DAC */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_DAC_LOW_NOISE_MODE_MASK,
+ MT6357_DAC_LOW_NOISE_MODE_DISABLE);
+ /* Disable AUD_CLK */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+ MT6357_RSTB_DECODER_VA28_MASK,
+ MT6357_RSTB_DECODER_VA28_DISABLE);
+ /* Enable linout short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_SC_VAUDP15_MASK,
+ MT6357_AUD_LOL_SC_VAUDP15_ENABLE);
+ /* Enable handset short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_SC_VAUDP15_MASK,
+ MT6357_AUD_HS_SC_VAUDP15_ENABLE);
+ /* Enable headphone short-circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_SC_VAUDP15_MASK |
+ MT6357_AUD_HPL_SC_VAUDP15_MASK,
+ MT6357_AUD_HPR_SC_VAUDP15_ENABLE |
+ MT6357_AUD_HPL_SC_VAUDP15_ENABLE);
+ /* Disable IBIST */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10,
+ MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK,
+ MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE);
+ /* Disable NV regulator (-1.2V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13,
+ MT6357_NVREG_EN_VAUDP15_MASK,
+ MT6357_NVREG_EN_VAUDP15_DISABLE);
+ /* Disable cap-less LDOs (1.5V) */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+ MT6357_VA33REFGEN_EN_VA18_MASK |
+ MT6357_LCLDO_REMOTE_SENSE_VA18_MASK |
+ MT6357_LCLDO_EN_VA18_MASK |
+ MT6357_HCLDO_REMOTE_SENSE_VA18_MASK |
+ MT6357_HCLDO_EN_VA18_MASK,
+ MT6357_VA33REFGEN_EN_VA18_DISABLE |
+ MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE |
+ MT6357_LCLDO_EN_VA18_DISABLE |
+ MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE |
+ MT6357_HCLDO_EN_VA18_DISABLE);
+ /* Disable NCP */
+ regmap_update_bits(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3,
+ MT6357_DIVCKS_PWD_NCP_MASK, MT6357_DIVCKS_PWD_NCP_DISABLE);
+ }
+}
+
+static int mt_audio_in_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ set_playback_gpio(priv, true);
+
+ /* Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, true);
+
+ /* Disable HP main CMFB Switch */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HPRL_MAIN_CMFB_LOOP_MASK,
+ MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE);
+ /* Audio system digital clock power down release */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+ MT6357_CCI_AUDIO_FIFO_DISABLE |
+ MT6357_CCI_ACD_MODE_NORMAL_PATH |
+ MT6357_CCI_AFIFO_CLK_PWDB_ON |
+ MT6357_CCI_ACD_FUNC_RSTB_RESET);
+ /* sdm audio fifo clock power on */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0,
+ MT6357_CCI_AUD_ANACK_INVERT |
+ (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) |
+ MT6357_CCI_SCRAMBLER_CG_ENABLE |
+ MT6357_CCI_RAND_ENABLE |
+ MT6357_CCI_SPLT_SCRMB_CLK_ON |
+ MT6357_CCI_SPLT_SCRMB_ON |
+ MT6357_CCI_ZERO_PADDING_DISABLE |
+ MT6357_CCI_SCRAMBLER_ENABLE);
+ /* scrambler clock on enable */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+ MT6357_CCI_AUDIO_FIFO_DISABLE |
+ MT6357_CCI_ACD_MODE_TEST_PATH |
+ MT6357_CCI_AFIFO_CLK_PWDB_ON |
+ MT6357_CCI_ACD_FUNC_RSTB_RELEASE);
+ /* sdm power on */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+ MT6357_CCI_AUDIO_FIFO_ENABLE |
+ MT6357_CCI_ACD_MODE_TEST_PATH |
+ MT6357_CCI_AFIFO_CLK_PWDB_ON |
+ MT6357_CCI_ACD_FUNC_RSTB_RELEASE);
+
+ configure_downlinks(priv, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ configure_downlinks(priv, false);
+ /* DL scrambler disabling sequence */
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+ MT6357_CCI_AUDIO_FIFO_DISABLE |
+ MT6357_CCI_ACD_MODE_TEST_PATH |
+ MT6357_CCI_AFIFO_CLK_PWDB_DOWN |
+ MT6357_CCI_ACD_FUNC_RSTB_RESET);
+ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0,
+ MT6357_CCI_AUD_ANACK_INVERT |
+ (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) |
+ MT6357_CCI_SCRAMBLER_CG_ENABLE |
+ MT6357_CCI_RAND_ENABLE |
+ MT6357_CCI_SPLT_SCRMB_CLK_ON |
+ MT6357_CCI_SPLT_SCRMB_ON |
+ MT6357_CCI_ZERO_PADDING_DISABLE |
+ MT6357_CCI_SCRAMBLER_DISABLE);
+
+ set_playback_gpio(priv, false);
+
+ /* disable Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, false);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_delay_250_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(250, 270);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ usleep_range(250, 270);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int lo_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ int lgain, rgain;
+
+ /* Get current gain value */
+ regmap_read(priv->regmap, MT6357_ZCD_CON1, &lgain);
+ rgain = (lgain & MT6357_AUD_LOR_GAIN_MASK) >> MT6357_AUD_LOR_GAIN_SFT;
+ lgain = lgain & MT6357_AUD_LOL_GAIN_MASK;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Set -40dB before enable HS to avoid POP noise */
+ regmap_update_bits(priv->regmap, MT6357_ZCD_CON1,
+ MT6357_AUD_LOL_GAIN_MASK |
+ MT6357_AUD_LOR_GAIN_MASK,
+ MT6357_DL_GAIN_N_40DB_REG);
+ /* Set LO STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
+ MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE);
+ /* Enable LO driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
+ MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE);
+ /* Enable LO driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE);
+ /* Set LOL gain to normal gain step by step */
+ lo_volume_ramp(priv, DL_GAIN_N_40DB, lgain,
+ DL_GAIN_N_40DB, rgain);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* decrease LOL gain to minimum gain step by step */
+
+ lo_volume_ramp(priv, lgain, DL_GAIN_N_40DB,
+ rgain, DL_GAIN_N_40DB);
+ /* Disable LO driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE);
+ /* Disable LO driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
+ MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE);
+ /* Clear LO STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
+ MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE);
+ /* Save the gain value into the register*/
+ regmap_update_bits(priv->regmap, MT6357_ZCD_CON1,
+ MT6357_AUD_LOL_GAIN_MASK |
+ MT6357_AUD_LOR_GAIN_MASK,
+ lgain << MT6357_AUD_LOL_GAIN_SFT |
+ rgain << MT6357_AUD_LOR_GAIN_SFT);
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int hs_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ int gain; /* HS register has only one gain slot */
+
+ /* Get current gain value */
+ regmap_read(priv->regmap, MT6357_ZCD_CON3, &gain);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Set -40dB before enable HS to avoid POP noise */
+ regmap_update_bits(priv->regmap, MT6357_ZCD_CON3,
+ MT6357_AUD_HS_GAIN_MASK,
+ DL_GAIN_N_40DB);
+
+ /* Set HS STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK,
+ MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE);
+ /* Enable HS driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
+ MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
+ /* Enable HS driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE);
+ /* Set HS gain to normal gain step by step */
+ hs_volume_ramp(priv, DL_GAIN_N_40DB, gain);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* decrease HS gain to minimum gain step by step */
+ hs_volume_ramp(priv, gain, DL_GAIN_N_40DB);
+ /* Disable HS driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE);
+ /* Disable HS driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
+ MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
+ /* Clear HS STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK,
+ MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE);
+ /* Save the gain value into the register*/
+ regmap_update_bits(priv->regmap, MT6357_ZCD_CON3,
+ MT6357_AUD_HS_GAIN_MASK, gain);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int hp_main_mux_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+ int lgain, rgain;
+
+ /* Get current gain value */
+ regmap_read(priv->regmap, MT6357_ZCD_CON2, &lgain);
+ rgain = (lgain & MT6357_AUD_HPR_GAIN_MASK) >> MT6357_AUD_HPR_GAIN_SFT;
+ lgain = lgain & MT6357_AUD_HPL_GAIN_MASK;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ priv->hp_channel_number++;
+ if (priv->hp_channel_number > 1)
+ break;
+ /* Set -40dB before enable HS to avoid POP noise */
+ regmap_update_bits(priv->regmap, MT6357_ZCD_CON2,
+ MT6357_AUD_HPL_GAIN_MASK |
+ MT6357_AUD_HPR_GAIN_MASK,
+ MT6357_DL_GAIN_N_40DB_REG);
+ /* Set HPP/N STB enhance circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+ MT6357_HPROUT_STB_ENH_VAUDP15_MASK |
+ MT6357_HPLOUT_STB_ENH_VAUDP15_MASK,
+ MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250 |
+ MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250);
+ /* Enable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE);
+ /* Enable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE);
+ /* Enable HP aux CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HP_CMFB_RST_MASK |
+ MT6357_HPL_AUX_CMFB_LOOP_MASK |
+ MT6357_HPR_AUX_CMFB_LOOP_MASK,
+ MT6357_HP_CMFB_RST_NORMAL |
+ MT6357_HPL_AUX_CMFB_LOOP_ENABLE |
+ MT6357_HPR_AUX_CMFB_LOOP_ENABLE);
+ /* Enable HP driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_BIAS_VAUDP15_MASK |
+ MT6357_AUD_HPL_BIAS_VAUDP15_MASK,
+ MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE |
+ MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE);
+ /* Enable HP driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_PWRUP_VAUDP15_MASK |
+ MT6357_AUD_HPL_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE |
+ MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE);
+ /* Short HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE);
+ /* Enable HP main CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HPRL_MAIN_CMFB_LOOP_MASK,
+ MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE);
+ /* Disable HP aux CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HPR_AUX_CMFB_LOOP_MASK |
+ MT6357_HPL_AUX_CMFB_LOOP_MASK,
+ MT6357_HPR_AUX_CMFB_LOOP_DISABLE |
+ MT6357_HPL_AUX_CMFB_LOOP_DISABLE);
+ /* Enable HP main output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_PWRUP_VAUDP15_MASK |
+ MT6357_HPLOUT_PWRUP_VAUDP15_MASK,
+ MT6357_HPROUT_PWRUP_VAUDP15_ENABLE |
+ MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE);
+ /* Enable HPR/L main output stage step by step */
+ hp_main_output_ramp(priv, true);
+ usleep_range(1000, 1200);
+ /* Reduce HP aux feedback loop gain */
+ hp_aux_feedback_loop_gain_ramp(priv, true);
+ /* Disable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE);
+ /* apply volume setting */
+ hp_volume_ramp(priv, DL_GAIN_N_40DB, lgain,
+ DL_GAIN_N_40DB, rgain);
+ /* Disable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE);
+ /* Unshort HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE);
+ usleep_range(100, 120);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ priv->hp_channel_number--;
+ if (priv->hp_channel_number > 0)
+ break;
+ /* Short HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE);
+ /* Enable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE);
+ /* decrease HPL/R gain to normal gain step by step */
+ hp_volume_ramp(priv, lgain, DL_GAIN_N_40DB,
+ rgain, DL_GAIN_N_40DB);
+ /* Enable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE);
+ /* Reduce HP aux feedback loop gain */
+ hp_aux_feedback_loop_gain_ramp(priv, false);
+ /* decrease HPR/L main output stage step by step */
+ hp_main_output_ramp(priv, false);
+ /* Disable HP main output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_PWRUP_VAUDP15_MASK |
+ MT6357_HPLOUT_PWRUP_VAUDP15_MASK,
+ MT6357_HPROUT_PWRUP_VAUDP15_DISABLE |
+ MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE);
+ /* Enable HP aux CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HP_CMFB_RST_MASK |
+ MT6357_HPL_AUX_CMFB_LOOP_MASK |
+ MT6357_HPR_AUX_CMFB_LOOP_MASK,
+ MT6357_HP_CMFB_RST_RESET |
+ MT6357_HPL_AUX_CMFB_LOOP_ENABLE |
+ MT6357_HPR_AUX_CMFB_LOOP_ENABLE);
+ /* Disable HP main CMFB loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HPRL_MAIN_CMFB_LOOP_MASK,
+ MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE);
+ /* Unshort HP main output to HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+ MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE |
+ MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE);
+ /* Disable HP driver core circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_PWRUP_VAUDP15_MASK |
+ MT6357_AUD_HPL_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE |
+ MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE);
+ /* Disable HP driver bias circuits */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_BIAS_VAUDP15_MASK |
+ MT6357_AUD_HPL_BIAS_VAUDP15_MASK,
+ MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE |
+ MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE);
+ /* Disable HP aux CMFB loop,
+ * Enable HP main CMFB for HP off state
+ */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+ MT6357_HPRL_MAIN_CMFB_LOOP_MASK |
+ MT6357_HPR_AUX_CMFB_LOOP_MASK |
+ MT6357_HPL_AUX_CMFB_LOOP_MASK,
+ MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE |
+ MT6357_HPR_AUX_CMFB_LOOP_DISABLE |
+ MT6357_HPL_AUX_CMFB_LOOP_DISABLE);
+ /* Disable HP aux feedback loop */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+ MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE |
+ MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE);
+ /* Disable HP aux output stage */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+ MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE |
+ MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE);
+ /* Save the gain value into the register*/
+ regmap_update_bits(priv->regmap, MT6357_ZCD_CON2,
+ MT6357_AUD_HPL_GAIN_MASK |
+ MT6357_AUD_HPR_GAIN_MASK,
+ lgain << MT6357_AUD_HPL_GAIN_SFT |
+ rgain << MT6357_AUD_HPR_GAIN_SFT);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int right_dac_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_DACR_PWRUP_VA28_MASK |
+ MT6357_AUD_DACR_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_DACR_PWRUP_VA28_ENABLE |
+ MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* disable Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, false);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, true);
+ /* Disable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_DACR_PWRUP_VA28_MASK |
+ MT6357_AUD_DACR_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_DACR_PWRUP_VA28_DISABLE |
+ MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int left_dac_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 mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_DACL_PWRUP_VA28_MASK |
+ MT6357_AUD_DACL_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_DACL_PWRUP_VA28_ENABLE |
+ MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* disable Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, false);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Pull-down HPL/R to AVSS28_AUD */
+ if (priv->pull_down_needed)
+ hp_pull_down(priv, true);
+ /* Disable Audio DAC and control audio bias gen */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_DACL_PWRUP_VA28_MASK |
+ MT6357_AUD_DACL_PWRUP_VAUDP15_MASK,
+ MT6357_AUD_DACL_PWRUP_VA28_DISABLE |
+ MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Supply widgets subsequence */
+enum {
+ /* common */
+ SUPPLY_SEQ_CLK_BUF,
+ SUPPLY_SEQ_AUD_GLB,
+ SUPPLY_SEQ_CLKSQ,
+ SUPPLY_SEQ_VOW_AUD_LPW,
+ SUPPLY_SEQ_AUD_VOW,
+ SUPPLY_SEQ_VOW_CLK,
+ SUPPLY_SEQ_VOW_LDO,
+ SUPPLY_SEQ_TOP_CK,
+ SUPPLY_SEQ_TOP_CK_LAST,
+ SUPPLY_SEQ_AUD_TOP,
+ SUPPLY_SEQ_AUD_TOP_LAST,
+ SUPPLY_SEQ_AFE,
+ /* capture */
+ SUPPLY_SEQ_ADC_SUPPLY,
+};
+
+/* DAPM Widgets */
+static const struct snd_soc_dapm_widget mt6357_dapm_widgets[] = {
+ /* Analog Clocks */
+ SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF,
+ MT6357_DCXO_CW14,
+ MT6357_XO_AUDIO_EN_M_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB,
+ MT6357_AUDDEC_ANA_CON11,
+ MT6357_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ,
+ MT6357_AUDENC_ANA_CON6,
+ MT6357_CLKSQ_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ MT6357_AUDNCP_CK_PDN_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ MT6357_ZCD13M_CK_PDN_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ MT6357_AUD_CK_PDN_SFT, 1,
+ mt_delay_250_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK,
+ MT6357_AUD_TOP_CKPDN_CON0,
+ MT6357_AUDIF_CK_PDN_SFT, 1, NULL, 0),
+
+ /* Digital Clocks */
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_AFE_CTL_SFT, 1,
+ mt_delay_250_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_DAC_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_ADC_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_I2S_DL_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PWR_CLK_DIS_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_RESERVED_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_LPBK", SUPPLY_SEQ_AUD_TOP,
+ MT6357_AUDIO_TOP_CON0,
+ MT6357_PDN_LPBK_CTL_SFT, 1, NULL, 0),
+
+ /* General */
+ SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE,
+ MT6357_AFE_UL_DL_CON0,
+ MT6357_AFE_ON_SFT, 0, NULL, 0),
+
+ /* Uplinks */
+ SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "MT6357 Capture", 0,
+ SND_SOC_NOPM, 0, 0,
+ mt_aif_out_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY,
+ SND_SOC_NOPM, 0, 0,
+ mt_adc_supply_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, adc_enable_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0,
+ &pga_left_mux_control,
+ mt_pga_left_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0,
+ &pga_right_mux_control,
+ mt_pga_right_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0,
+ &mic_type_mux_control,
+ mt_mic_type_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MICBIAS0", MT6357_AUDENC_ANA_CON8,
+ MT6357_AUD_MICBIAS0_PWD_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", MT6357_AUDENC_ANA_CON9,
+ MT6357_AUD_MICBIAS1_PWD_SFT, 0, NULL, 0),
+
+ /* UL inputs */
+ SND_SOC_DAPM_INPUT("AIN0"),
+ SND_SOC_DAPM_INPUT("AIN1"),
+ SND_SOC_DAPM_INPUT("AIN2"),
+ SND_SOC_DAPM_INPUT("LPBK"),
+ SND_SOC_DAPM_INPUT("SGEN UL"),
+
+ /* Downlinks */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "MT6357 Playback", 0,
+ SND_SOC_NOPM, 0, 0,
+ mt_audio_in_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_INPUT("SGEN DL"),
+ SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &dac_mux_control),
+
+ SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM, 0, 0, right_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM, 0, 0, left_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("DL Digital Supply", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DL Analog Supply", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DL SRC", MT6357_AFE_DL_SRC2_CON0_L,
+ MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("Line Out Source", SND_SOC_NOPM, 0, 0, &lo_mux_control,
+ lo_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX_E("Handset Source", SND_SOC_NOPM, 0, 0, &hs_mux_control,
+ hs_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX_E("Headphone Right Source", SND_SOC_NOPM, 0, 0, &hpr_mux_control,
+ hp_main_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX_E("Headphone Left Source", SND_SOC_NOPM, 0, 0, &hpl_mux_control,
+ hp_main_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ /* DL outputs */
+ SND_SOC_DAPM_OUTPUT("Headphones"),
+ SND_SOC_DAPM_OUTPUT("Hansdet"),
+ SND_SOC_DAPM_OUTPUT("Line out"),
+
+ /* Sine generator */
+ SND_SOC_DAPM_SUPPLY("SGEN UL Enable",
+ MT6357_AFE_TOP_CON0, MT6357_UL_SINE_ON_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SGEN Enable",
+ MT6357_AFE_SGEN_CFG0,
+ MT6357_SGEN_DAC_EN_CTL_SFT, 0, mt_audio_in_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("SGEN MUTE",
+ MT6357_AFE_SGEN_CFG0,
+ MT6357_SGEN_MUTE_SW_CTL_SFT, 1, NULL, 0)
+};
+
+static const struct snd_soc_dapm_route mt6357_dapm_routes[] = {
+ /* Capture */
+ {"AIF1TX", NULL, "Mic Type Mux"},
+ {"AIF1TX", NULL, "CLK_BUF"},
+ {"AIF1TX", NULL, "AUDGLB"},
+ {"AIF1TX", NULL, "CLKSQ Audio"},
+ {"AIF1TX", NULL, "AUD_CK"},
+ {"AIF1TX", NULL, "AUDIF_CK"},
+
+ {"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"},
+ {"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"},
+ {"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"},
+ {"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"},
+ {"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"},
+ {"AIF1TX", NULL, "AFE_ON"},
+
+ {"Mic Type Mux", "ACC", "ADC"},
+ {"Mic Type Mux", "DCC", "ADC"},
+ {"Mic Type Mux", "DCC_ECM_DIFF", "ADC"},
+ {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC"},
+ {"Mic Type Mux", "DMIC", "AIN0"},
+ {"Mic Type Mux", "DMIC", "AIN2"},
+ {"Mic Type Mux", "Loopback", "LPBK"},
+ {"Mic Type Mux", "Sine Generator", "SGEN UL"},
+
+ {"SGEN UL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
+ {"SGEN UL", NULL, "SGEN UL Enable"},
+ {"SGEN UL", NULL, "SGEN MUTE"},
+ {"SGEN UL", NULL, "SGEN Enable"},
+
+ {"ADC", NULL, "PGA L Mux"},
+ {"ADC", NULL, "PGA R Mux"},
+ {"ADC", NULL, "ADC Supply"},
+
+ {"PGA L Mux", "AIN0", "AIN0"},
+ {"PGA L Mux", "AIN1", "AIN1"},
+ {"PGA L Mux", "AIN2", "AIN2"},
+
+ {"PGA R Mux", "AIN0", "AIN0"},
+ {"PGA R Mux", "AIN1", "AIN1"},
+ {"PGA R Mux", "AIN2", "AIN2"},
+
+ {"AIN0", NULL, "MICBIAS0"},
+ {"AIN1", NULL, "MICBIAS1"},
+ {"AIN2", NULL, "MICBIAS0"},
+ {"LPBK", NULL, "AUDIO_TOP_LPBK"},
+
+ /* Playback */
+ {"DAC Mux", "Normal Path", "AIF_RX"},
+ {"DAC Mux", "Sine Generator", "SGEN DL"},
+
+ {"AIF_RX", NULL, "DL SRC"},
+
+ {"SGEN DL", NULL, "DL SRC"},
+ {"SGEN DL", NULL, "SGEN MUTE"},
+ {"SGEN DL", NULL, "SGEN Enable"},
+ {"SGEN DL", NULL, "DL Digital Supply"},
+ {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
+
+ {"DACL", NULL, "DAC Mux"},
+ {"DACR", NULL, "DAC Mux"},
+
+ {"DL Analog Supply", NULL, "CLK_BUF"},
+ {"DL Analog Supply", NULL, "AUDGLB"},
+ {"DL Analog Supply", NULL, "CLKSQ Audio"},
+ {"DL Analog Supply", NULL, "AUDNCP_CK"},
+ {"DL Analog Supply", NULL, "ZCD13M_CK"},
+ {"DL Analog Supply", NULL, "AUD_CK"},
+ {"DL Analog Supply", NULL, "AUDIF_CK"},
+
+ {"DL Digital Supply", NULL, "AUDIO_TOP_AFE_CTL"},
+ {"DL Digital Supply", NULL, "AUDIO_TOP_DAC_CTL"},
+ {"DL Digital Supply", NULL, "AUDIO_TOP_PWR_CLK"},
+ {"DL Digital Supply", NULL, "AFE_ON"},
+
+ {"DACR", NULL, "DL Digital Supply"},
+ {"DACR", NULL, "DL Analog Supply"},
+ {"DACL", NULL, "DL Digital Supply"},
+ {"DACL", NULL, "DL Analog Supply"},
+
+ {"Line Out Source", "DACR", "DACR"},
+ {"Line Out Source", "Playback", "DACL"},
+ {"Line Out Source", "Test mode", "DACL"},
+
+ {"Handset Source", "DACR", "DACR"},
+ {"Handset Source", "Playback", "DACL"},
+ {"Handset Source", "Test mode", "DACL"},
+
+ {"Headphone Right Source", "DAC", "DACR"},
+ {"Headphone Right Source", "Line Out", "Line Out Source"},
+ {"Headphone Right Source", "Handset", "Handset Source"},
+
+ {"Headphone Left Source", "DAC", "DACL"},
+ {"Headphone Left Source", "Line Out", "Line Out Source"},
+ {"Headphone Left Source", "Handset", "Handset Source"},
+
+ {"Line out", NULL, "Line Out Source"},
+ {"Hansdet", NULL, "Handset Source"},
+
+ {"Headphones", NULL, "Headphone Right Source"},
+ {"Headphones", NULL, "Headphone Left Source"},
+};
+
+static struct snd_soc_dai_driver mtk_6357_dai_codecs[] = {
+ {
+ .name = "mt6357-snd-codec-aif1",
+ .playback = {
+ .stream_name = "MT6357 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = MT6357_SND_SOC_ADV_MT_FMTS,
+ },
+ .capture = {
+ .stream_name = "MT6357 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MT6357_SOC_HIGH_USE_RATE,
+ .formats = MT6357_SND_SOC_ADV_MT_FMTS,
+ },
+ },
+};
+
+static int mt6357_codec_probe(struct snd_soc_component *codec)
+{
+ struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+
+ snd_soc_component_init_regmap(codec, priv->regmap);
+
+ /* Enable audio part */
+ regmap_update_bits(priv->regmap, MT6357_DCXO_CW14,
+ MT6357_XO_AUDIO_EN_M_MASK, MT6357_XO_AUDIO_EN_M_ENABLE);
+ /* Disable HeadphoneL/HeadphoneR short circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+ MT6357_AUD_HPR_SC_VAUDP15_MASK |
+ MT6357_AUD_HPL_SC_VAUDP15_MASK,
+ MT6357_AUD_HPR_SC_VAUDP15_DISABLE |
+ MT6357_AUD_HPL_SC_VAUDP15_DISABLE);
+ /* Disable voice short circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+ MT6357_AUD_HS_SC_VAUDP15_MASK,
+ MT6357_AUD_HS_SC_VAUDP15_DISABLE);
+ /* disable LO buffer left short circuit protection */
+ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+ MT6357_AUD_LOL_SC_VAUDP15_MASK,
+ MT6357_AUD_LOL_SC_VAUDP15_DISABLE);
+ /* set gpio */
+ set_playback_gpio(priv, false);
+ set_capture_gpio(priv, false);
+ /* Disable audio part */
+ regmap_update_bits(priv->regmap, MT6357_DCXO_CW14,
+ MT6357_XO_AUDIO_EN_M_MASK,
+ MT6357_XO_AUDIO_EN_M_DISABLE);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver mt6357_soc_component_driver = {
+ .probe = mt6357_codec_probe,
+ .read = snd_soc_component_read,
+ .write = snd_soc_component_write,
+ .controls = mt6357_controls,
+ .num_controls = ARRAY_SIZE(mt6357_controls),
+ .dapm_widgets = mt6357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt6357_dapm_widgets),
+ .dapm_routes = mt6357_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt6357_dapm_routes),
+};
+
+static const u32 micbias_values[] = {
+ 1700000, 1800000, 1900000, 2000000,
+ 2100000, 2500000, 2600000, 2700000
+};
+
+static u32 mt6357_get_micbias_idx(struct device_node *np, const char *micbias)
+{
+ int err;
+ u32 idx, val;
+
+ err = of_property_read_u32(np, micbias, &val);
+ if (err)
+ return 0;
+
+ for (idx = 0; idx < ARRAY_SIZE(micbias_values); idx++) {
+ if (val == micbias_values[idx])
+ return idx;
+ }
+ return 0;
+}
+
+static int mt6357_parse_dt(struct mt6357_priv *priv)
+{
+ u32 micbias_voltage_index = 0;
+ struct device_node *np = priv->dev->parent->of_node;
+
+ if (!np)
+ return -EINVAL;
+
+ priv->pull_down_needed = false;
+ if (of_property_read_bool(np, "mediatek,hp-pull-down"))
+ priv->pull_down_needed = true;
+
+ micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias0-microvolt");
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+ MT6357_AUD_MICBIAS0_VREF_MASK,
+ micbias_voltage_index << MT6357_AUD_MICBIAS0_VREF_SFT);
+
+ micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias1-microvolt");
+ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+ MT6357_AUD_MICBIAS1_VREF_MASK,
+ micbias_voltage_index << MT6357_AUD_MICBIAS1_VREF_SFT);
+
+ return 0;
+}
+
+static int mt6357_platform_driver_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+ struct mt6357_priv *priv;
+ int ret;
+
+ ret = devm_regulator_get_enable(&pdev->dev, "vaud28");
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to enable vaud28 regulator\n");
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, priv);
+ priv->dev = &pdev->dev;
+
+ priv->regmap = mt6397->regmap;
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ ret = mt6357_parse_dt(priv);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to parse dts\n");
+
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ return devm_snd_soc_register_component(&pdev->dev,
+ &mt6357_soc_component_driver,
+ mtk_6357_dai_codecs,
+ ARRAY_SIZE(mtk_6357_dai_codecs));
+}
+
+static const struct platform_device_id mt6357_platform_ids[] = {
+ {"mt6357-sound", 0},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6357_platform_ids);
+
+static struct platform_driver mt6357_platform_driver = {
+ .driver = {
+ .name = "mt6357-sound",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = mt6357_platform_driver_probe,
+ .id_table = mt6357_platform_ids,
+};
+
+module_platform_driver(mt6357_platform_driver)
+
+MODULE_DESCRIPTION("MT6357 ALSA SoC codec driver");
+MODULE_AUTHOR("Nicolas Belin <nbelin@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mt6357.h b/sound/soc/codecs/mt6357.h
new file mode 100644
index 000000000000..7f6fccada6a2
--- /dev/null
+++ b/sound/soc/codecs/mt6357.h
@@ -0,0 +1,660 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6357.h -- mt6357 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2024 Baylibre
+ * Author: Nicolas Belin <nbelin@baylibre.com>
+ */
+
+#ifndef __MT6357_H__
+#define __MT6357_H__
+
+#include <linux/types.h>
+
+/* Reg bit defines */
+/* MT6357_GPIO_DIR0 */
+#define MT6357_GPIO8_DIR_MASK BIT(8)
+#define MT6357_GPIO8_DIR_INPUT 0
+#define MT6357_GPIO8_DIR_OUTPUT BIT(8)
+#define MT6357_GPIO9_DIR_MASK BIT(9)
+#define MT6357_GPIO9_DIR_INPUT 0
+#define MT6357_GPIO9_DIR_OUTPUT BIT(9)
+#define MT6357_GPIO10_DIR_MASK BIT(10)
+#define MT6357_GPIO10_DIR_INPUT 0
+#define MT6357_GPIO10_DIR_OUTPUT BIT(10)
+#define MT6357_GPIO11_DIR_MASK BIT(11)
+#define MT6357_GPIO11_DIR_INPUT 0
+#define MT6357_GPIO11_DIR_OUTPUT BIT(11)
+#define MT6357_GPIO12_DIR_MASK BIT(12)
+#define MT6357_GPIO12_DIR_INPUT 0
+#define MT6357_GPIO12_DIR_OUTPUT BIT(12)
+#define MT6357_GPIO13_DIR_MASK BIT(13)
+#define MT6357_GPIO13_DIR_INPUT 0
+#define MT6357_GPIO13_DIR_OUTPUT BIT(13)
+#define MT6357_GPIO14_DIR_MASK BIT(14)
+#define MT6357_GPIO14_DIR_INPUT 0
+#define MT6357_GPIO14_DIR_OUTPUT BIT(14)
+#define MT6357_GPIO15_DIR_MASK BIT(15)
+#define MT6357_GPIO15_DIR_INPUT 0
+#define MT6357_GPIO15_DIR_OUTPUT BIT(15)
+
+/* MT6357_GPIO_MODE2 */
+#define MT6357_GPIO8_MODE_MASK GENMASK(2, 0)
+#define MT6357_GPIO8_MODE_AUD_CLK_MOSI BIT(0)
+#define MT6357_GPIO8_MODE_GPIO 0
+#define MT6357_GPIO9_MODE_MASK GENMASK(5, 3)
+#define MT6357_GPIO9_MODE_AUD_DAT_MOSI0 BIT(3)
+#define MT6357_GPIO9_MODE_GPIO 0
+#define MT6357_GPIO10_MODE_MASK GENMASK(8, 6)
+#define MT6357_GPIO10_MODE_AUD_DAT_MOSI1 BIT(6)
+#define MT6357_GPIO10_MODE_GPIO 0
+#define MT6357_GPIO11_MODE_MASK GENMASK(11, 9)
+#define MT6357_GPIO11_MODE_AUD_SYNC_MOSI BIT(9)
+#define MT6357_GPIO11_MODE_GPIO 0
+
+/* MT6357_GPIO_MODE2_SET */
+#define MT6357_GPIO8_MODE_SET_MASK GENMASK(2, 0)
+#define MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI BIT(0)
+#define MT6357_GPIO9_MODE_SET_MASK GENMASK(5, 3)
+#define MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0 BIT(3)
+#define MT6357_GPIO10_MODE_SET_MASK GENMASK(8, 6)
+#define MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1 BIT(6)
+#define MT6357_GPIO11_MODE_SET_MASK GENMASK(11, 9)
+#define MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI BIT(9)
+
+/* MT6357_GPIO_MODE2_CLR */
+#define MT6357_GPIO_MODE2_CLEAR_ALL GENMASK(15, 0)
+
+/* MT6357_GPIO_MODE3 */
+#define MT6357_GPIO12_MODE_MASK GENMASK(2, 0)
+#define MT6357_GPIO12_MODE_AUD_CLK_MISO BIT(0)
+#define MT6357_GPIO12_MODE_GPIO 0
+#define MT6357_GPIO13_MODE_MASK GENMASK(5, 3)
+#define MT6357_GPIO13_MODE_AUD_DAT_MISO0 BIT(3)
+#define MT6357_GPIO13_MODE_GPIO 0
+#define MT6357_GPIO14_MODE_MASK GENMASK(8, 6)
+#define MT6357_GPIO14_MODE_AUD_DAT_MISO1 BIT(6)
+#define MT6357_GPIO14_MODE_GPIO 0
+#define MT6357_GPIO15_MODE_MASK GENMASK(11, 9)
+#define MT6357_GPIO15_MODE_AUD_SYNC_MISO BIT(9)
+#define MT6357_GPIO15_MODE_GPIO 0
+
+/* MT6357_GPIO_MODE3_SET */
+#define MT6357_GPIO12_MODE_SET_MASK GENMASK(2, 0)
+#define MT6357_GPIO12_MODE_SET_AUD_CLK_MISO BIT(0)
+#define MT6357_GPIO13_MODE_SET_MASK GENMASK(5, 3)
+#define MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0 BIT(3)
+#define MT6357_GPIO14_MODE_SET_MASK GENMASK(8, 6)
+#define MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1 BIT(6)
+#define MT6357_GPIO15_MODE_SET_MASK GENMASK(11, 9)
+#define MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO BIT(9)
+
+/* MT6357_GPIO_MODE3_CLR */
+#define MT6357_GPIO_MODE3_CLEAR_ALL GENMASK(15, 0)
+
+/* MT6357_DCXO_CW14 */
+#define MT6357_XO_AUDIO_EN_M_SFT 13
+#define MT6357_XO_AUDIO_EN_M_MASK BIT(13)
+#define MT6357_XO_AUDIO_EN_M_ENABLE BIT(13)
+#define MT6357_XO_AUDIO_EN_M_DISABLE 0
+
+/* MT6357_AUD_TOP_CKPDN_CON0 */
+#define MT6357_AUDNCP_CK_PDN_SFT 6
+#define MT6357_ZCD13M_CK_PDN_SFT 5
+#define MT6357_AUDIF_CK_PDN_SFT 2
+#define MT6357_AUD_CK_PDN_SFT 1
+
+/* MT6357_AUDNCP_CLKDIV_CON0 */
+#define MT6357_DIVCKS_CHG BIT(0)
+
+/* MT6357_AUDNCP_CLKDIV_CON1 */
+#define MT6357_DIVCKS_ON BIT(0)
+
+/* MT6357_AUDNCP_CLKDIV_CON3 */
+#define MT6357_DIVCKS_PWD_NCP_MASK BIT(0)
+#define MT6357_DIVCKS_PWD_NCP_DISABLE BIT(0)
+#define MT6357_DIVCKS_PWD_NCP_ENABLE 0
+
+/* MT6357_AUDNCP_CLKDIV_CON4 */
+#define MT6357_DIVCKS_PWD_NCP_ST_SEL_MASK GENMASK(1, 0)
+#define MT6357_DIVCKS_PWD_NCP_ST_50US 0
+#define MT6357_DIVCKS_PWD_NCP_ST_100US 1
+#define MT6357_DIVCKS_PWD_NCP_ST_150US 2
+#define MT6357_DIVCKS_PWD_NCP_ST_200US 3
+
+/* MT6357_AFE_UL_DL_CON0 */
+#define MT6357_AFE_UL_LR_SWAP_SFT 15
+#define MT6357_AFE_ON_SFT 0
+
+/* MT6357_AFE_DL_SRC2_CON0_L */
+#define MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT 0
+
+/* MT6357_AFE_UL_SRC_CON0_H */
+#define MT6357_C_TWO_DIGITAL_MIC_CTL_MASK BIT(7)
+#define MT6357_C_TWO_DIGITAL_MIC_ENABLE BIT(7)
+#define MT6357_C_TWO_DIGITAL_MIC_DISABLE 0
+
+/* MT6357_AFE_UL_SRC_CON0_L */
+#define MT6357_UL_SDM_3_LEVEL_CTL_MASK BIT(1)
+#define MT6357_UL_SDM_3_LEVEL_SELECT BIT(1)
+#define MT6357_UL_SDM_3_LEVEL_DESELECT 0
+#define MT6357_UL_SRC_ON_TMP_CTL_MASK BIT(0)
+#define MT6357_UL_SRC_ENABLE BIT(0)
+#define MT6357_UL_SRC_DISABLE 0
+
+/* MT6357_AFE_TOP_CON0 */
+#define MT6357_UL_SINE_ON_SFT 1
+#define MT6357_UL_SINE_ON_MASK BIT(1)
+#define MT6357_DL_SINE_ON_SFT 0
+#define MT6357_DL_SINE_ON_MASK BIT(0)
+
+/* MT6357_AUDIO_TOP_CON0 */
+#define MT6357_PDN_LPBK_CTL_SFT 15
+#define MT6357_PDN_AFE_CTL_SFT 7
+#define MT6357_PDN_DAC_CTL_SFT 6
+#define MT6357_PDN_ADC_CTL_SFT 5
+#define MT6357_PDN_I2S_DL_CTL_SFT 3
+#define MT6357_PWR_CLK_DIS_CTL_SFT 2
+#define MT6357_PDN_AFE_TESTMODEL_CTL_SFT 1
+#define MT6357_PDN_RESERVED_SFT 0
+
+/* MT6357_AFUNC_AUD_CON0 */
+#define MT6357_CCI_AUD_ANACK_INVERT BIT(15)
+#define MT6357_CCI_AUD_ANACK_NORMAL 0
+#define MT6357_CCI_AUDIO_FIFO_WPTR_SFT 12
+#define MT6357_CCI_SCRAMBLER_CG_ENABLE BIT(11)
+#define MT6357_CCI_SCRAMBLER_CG_DISABLE 0
+#define MT6357_CCI_LCK_INV_OUT_OF_PHASE BIT(10)
+#define MT6357_CCI_LCK_INV_IN_PHASE 0
+#define MT6357_CCI_RAND_ENABLE BIT(9)
+#define MT6357_CCI_RAND_DISABLE 0
+#define MT6357_CCI_SPLT_SCRMB_CLK_ON BIT(8)
+#define MT6357_CCI_SPLT_SCRMB_CLK_OFF 0
+#define MT6357_CCI_SPLT_SCRMB_ON BIT(7)
+#define MT6357_CCI_SPLT_SCRMB_OFF 0
+#define MT6357_CCI_AUD_IDAC_TEST_EN_FROM_TEST_IN BIT(6)
+#define MT6357_CCI_AUD_IDAC_TEST_EN_NORMAL_PATH 0
+#define MT6357_CCI_ZERO_PADDING_DISABLE BIT(5)
+#define MT6357_CCI_ZERO_PADDING_ENABLE 0
+#define MT6357_CCI_AUD_SPLIT_TEST_EN_FROM_TEST_IN BIT(4)
+#define MT6357_CCI_AUD_SPLIT_TEST_EN_NORMAL_PATH 0
+#define MT6357_CCI_AUD_SDM_MUTE_L_REG_CTL BIT(3)
+#define MT6357_CCI_AUD_SDM_MUTE_L_NO_CTL 0
+#define MT6357_CCI_AUD_SDM_MUTE_R_REG_CTL BIT(2)
+#define MT6357_CCI_AUD_SDM_MUTE_R_NO_CTL 0
+#define MT6357_CCI_AUD_SDM_7BIT_FROM_SPLITTER3 BIT(1)
+#define MT6357_CCI_AUD_SDM_7BIT_FROM_SPLITTER1 0
+#define MT6357_CCI_SCRAMBLER_ENABLE BIT(0)
+#define MT6357_CCI_SCRAMBLER_DISABLE 0
+
+/* MT6357_AFUNC_AUD_CON2 */
+#define MT6357_CCI_AUDIO_FIFO_ENABLE BIT(3)
+#define MT6357_CCI_AUDIO_FIFO_DISABLE 0
+#define MT6357_CCI_ACD_MODE_NORMAL_PATH BIT(2)
+#define MT6357_CCI_ACD_MODE_TEST_PATH 0
+#define MT6357_CCI_AFIFO_CLK_PWDB_ON BIT(1)
+#define MT6357_CCI_AFIFO_CLK_PWDB_DOWN 0
+#define MT6357_CCI_ACD_FUNC_RSTB_RELEASE BIT(0)
+#define MT6357_CCI_ACD_FUNC_RSTB_RESET 0
+
+/* MT6357_AFE_ADDA_MTKAIF_CFG0 */
+#define MT6357_ADDA_MTKAIF_LPBK_CTL_MASK BIT(1)
+#define MT6357_ADDA_MTKAIF_LPBK_ENABLE BIT(1)
+#define MT6357_ADDA_MTKAIF_LPBK_DISABLE 0
+
+/* MT6357_AFE_SGEN_CFG0 */
+#define MT6357_SGEN_DAC_EN_CTL_SFT 7
+#define MT6357_SGEN_DAC_ENABLE BIT(7)
+#define MT6357_SGEN_MUTE_SW_CTL_SFT 6
+#define MT6357_SGEN_MUTE_SW_DISABLE 0
+
+/* MT6357_AFE_DCCLK_CFG0 */
+#define MT6357_DCCLK_DIV_MASK GENMASK(15, 5)
+#define MT6357_DCCLK_DIV_SFT 5
+#define MT6357_DCCLK_DIV_RUN_VALUE (32 << MT6357_DCCLK_DIV_SFT)
+#define MT6357_DCCLK_DIV_STOP_VALUE (259 << MT6357_DCCLK_DIV_SFT)
+#define MT6357_DCCLK_PDN_MASK BIT(1)
+#define MT6357_DCCLK_PDN BIT(1)
+#define MT6357_DCCLK_OUTPUT 0
+#define MT6357_DCCLK_GEN_ON_MASK BIT(0)
+#define MT6357_DCCLK_GEN_ON BIT(0)
+#define MT6357_DCCLK_GEN_OFF 0
+
+/* MT6357_AFE_DCCLK_CFG1 */
+#define MT6357_DCCLK_RESYNC_BYPASS_MASK BIT(8)
+#define MT6357_DCCLK_RESYNC_BYPASS BIT(8)
+
+/* MT6357_AFE_AUD_PAD_TOP */
+#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK GENMASK(15, 8)
+#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE (BIT(13) | BIT(12) | BIT(8))
+#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE (BIT(13) | BIT(12))
+#define MT6357_AUD_PAD_TX_FIFO_LPBK_MASK GENMASK(7, 0)
+#define MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE (BIT(5) | BIT(4) | BIT(0))
+#define MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON0 */
+#define MT6357_AUDADCLINPUTSEL_MASK GENMASK(14, 13)
+#define MT6357_AUDADCLINPUTSEL_PREAMPLIFIER BIT(14)
+#define MT6357_AUDADCLINPUTSEL_IDLE 0
+#define MT6357_AUDADCLPWRUP_SFT 12
+#define MT6357_AUDADCLPWRUP_MASK BIT(12)
+#define MT6357_AUDADCLPWRUP BIT(12)
+#define MT6357_AUDADCLPWRDOWN 0
+#define MT6357_AUDPREAMPLGAIN_SFT 8
+#define MT6357_AUDPREAMPLGAIN_MASK GENMASK(10, 8)
+#define MT6357_AUDPREAMPLGAIN_MAX 4
+#define MT6357_AUDPREAMPLINPUTSEL_SFT 6
+#define MT6357_AUDPREAMPLINPUTSEL_MASK_NOSFT GENMASK(1, 0)
+#define MT6357_AUDPREAMPLDCPRECHARGE_MASK BIT(2)
+#define MT6357_AUDPREAMPLDCPRECHARGE_ENABLE BIT(2)
+#define MT6357_AUDPREAMPLDCPRECHARGE_DISABLE 0
+#define MT6357_AUDPREAMPLDCCEN_MASK BIT(1)
+#define MT6357_AUDPREAMPLDCCEN_DC BIT(1)
+#define MT6357_AUDPREAMPLDCCEN_AC 0
+#define MT6357_AUDPREAMPLON_MASK BIT(0)
+#define MT6357_AUDPREAMPLON_ENABLE BIT(0)
+#define MT6357_AUDPREAMPLON_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON1 */
+#define MT6357_AUDADCRINPUTSEL_MASK GENMASK(14, 13)
+#define MT6357_AUDADCRINPUTSEL_PREAMPLIFIER BIT(14)
+#define MT6357_AUDADCRINPUTSEL_IDLE 0
+#define MT6357_AUDADCRPWRUP_SFT 12
+#define MT6357_AUDADCRPWRUP_MASK BIT(12)
+#define MT6357_AUDADCRPWRUP BIT(12)
+#define MT6357_AUDADCRPWRDOWN 0
+#define MT6357_AUDPREAMPRGAIN_SFT 8
+#define MT6357_AUDPREAMPRGAIN_MASK GENMASK(10, 8)
+#define MT6357_AUDPREAMPRGAIN_MAX 4
+#define MT6357_AUDPREAMPRINPUTSEL_SFT 6
+#define MT6357_AUDPREAMPRINPUTSEL_MASK_NOSFT GENMASK(1, 0)
+#define MT6357_AUDPREAMPRDCPRECHARGE_MASK BIT(2)
+#define MT6357_AUDPREAMPRDCPRECHARGE_ENABLE BIT(2)
+#define MT6357_AUDPREAMPRDCPRECHARGE_DISABLE 0
+#define MT6357_AUDPREAMPRDCCEN_MASK BIT(1)
+#define MT6357_AUDPREAMPRDCCEN_DC BIT(1)
+#define MT6357_AUDPREAMPRDCCEN_AC 0
+#define MT6357_AUDPREAMPRON_MASK BIT(0)
+#define MT6357_AUDPREAMPRON_ENABLE BIT(0)
+#define MT6357_AUDPREAMPRON_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON6 */
+#define MT6357_CLKSQ_EN_SFT 0
+
+/* MT6357_AUDENC_ANA_CON7 */
+#define MT6357_AUDDIGMICBIAS_MASK GENMASK(2, 1)
+#define MT6357_AUDDIGMICBIAS_DEFAULT_VALUE BIT(2)
+#define MT6357_AUDDIGMICBIAS_OFF 0
+#define MT6357_AUDDIGMICEN_MASK BIT(0)
+#define MT6357_AUDDIGMICEN_ENABLE BIT(0)
+#define MT6357_AUDDIGMICEN_DISABLE 0
+
+/* MT6357_AUDENC_ANA_CON8 */
+#define MT6357_AUD_MICBIAS0_DCSW2N_EN_MASK BIT(14)
+#define MT6357_AUD_MICBIAS0_DCSW2N_ENABLE BIT(14)
+#define MT6357_AUD_MICBIAS0_DCSW2N_DISABLE 0
+#define MT6357_AUD_MICBIAS0_DCSW2P2_EN_MASK BIT(13)
+#define MT6357_AUD_MICBIAS0_DCSW2P2_ENABLE BIT(13)
+#define MT6357_AUD_MICBIAS0_DCSW2P2_DISABLE 0
+#define MT6357_AUD_MICBIAS0_DCSW2P1_EN_MASK BIT(12)
+#define MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE BIT(12)
+#define MT6357_AUD_MICBIAS0_DCSW2P1_DISABLE 0
+#define MT6357_AUD_MICBIAS0_DCSW0N_EN_MASK BIT(10)
+#define MT6357_AUD_MICBIAS0_DCSW0N_ENABLE BIT(10)
+#define MT6357_AUD_MICBIAS0_DCSWN_DISABLE 0
+#define MT6357_AUD_MICBIAS0_DCSW0P2_EN_MASK BIT(9)
+#define MT6357_AUD_MICBIAS0_DCSW0P2_ENABLE BIT(9)
+#define MT6357_AUD_MICBIAS0_DCSW0P2_DISABLE 0
+#define MT6357_AUD_MICBIAS0_DCSW0P1_EN_MASK BIT(8)
+#define MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE BIT(8)
+#define MT6357_AUD_MICBIAS0_DCSW0P1_DISABLE 0
+#define MT6357_AUD_MICBIAS0_VREF_MASK GENMASK(6, 4)
+#define MT6357_AUD_MICBIAS0_VREF_SFT 4
+#define MT6357_AUD_MICBIAS0_PWD_SFT 0
+
+#define MT6357_AUD_MICBIAS0_DC_MASK (MT6357_AUD_MICBIAS0_DCSW2N_EN_MASK | \
+ MT6357_AUD_MICBIAS0_DCSW2P2_EN_MASK | \
+ MT6357_AUD_MICBIAS0_DCSW2P1_EN_MASK | \
+ MT6357_AUD_MICBIAS0_DCSW0N_EN_MASK | \
+ MT6357_AUD_MICBIAS0_DCSW0P2_EN_MASK | \
+ MT6357_AUD_MICBIAS0_DCSW0P1_EN_MASK)
+
+#define MT6357_AUD_MICBIAS0_DC_ENABLE_ALL (MT6357_AUD_MICBIAS0_DCSW2N_ENABLE | \
+ MT6357_AUD_MICBIAS0_DCSW2P2_ENABLE | \
+ MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE | \
+ MT6357_AUD_MICBIAS0_DCSW0N_ENABLE | \
+ MT6357_AUD_MICBIAS0_DCSW0P2_ENABLE | \
+ MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE)
+
+#define MT6357_AUD_MICBIAS0_DC_ENABLE_P1 (MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE | \
+ MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE)
+
+#define MT6357_AUD_MICBIAS0_DC_DISABLE_ALL 0
+
+/* MT6357_AUDENC_ANA_CON9 */
+#define MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK BIT(8)
+#define MT6357_AUD_MICBIAS1_DCSW1P_ENABLE BIT(8)
+#define MT6357_AUD_MICBIAS1_DCSW1P_DISABLE 0
+#define MT6357_AUD_MICBIAS1_VREF_MASK GENMASK(6, 4)
+#define MT6357_AUD_MICBIAS1_VREF_SFT 4
+#define MT6357_AUD_MICBIAS1_PWD_SFT 0
+
+/* MT6357_AUDDEC_ANA_CON0 */
+#define MT6357_AUD_HPR_SC_VAUDP15_MASK BIT(13)
+#define MT6357_AUD_HPR_SC_VAUDP15_DISABLE BIT(13)
+#define MT6357_AUD_HPR_SC_VAUDP15_ENABLE 0
+#define MT6357_AUD_HPL_SC_VAUDP15_MASK BIT(12)
+#define MT6357_AUD_HPL_SC_VAUDP15_DISABLE BIT(12)
+#define MT6357_AUD_HPL_SC_VAUDP15_ENABLE 0
+#define MT6357_AUD_HPR_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT 10
+#define MT6357_AUD_HPL_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT 8
+#define MT6357_AUD_HPR_BIAS_VAUDP15_MASK BIT(7)
+#define MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE BIT(7)
+#define MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE 0
+#define MT6357_AUD_HPL_BIAS_VAUDP15_MASK BIT(6)
+#define MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE BIT(6)
+#define MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE 0
+#define MT6357_AUD_HPR_PWRUP_VAUDP15_MASK BIT(5)
+#define MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE BIT(5)
+#define MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE 0
+#define MT6357_AUD_HPL_PWRUP_VAUDP15_MASK BIT(4)
+#define MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE BIT(4)
+#define MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE 0
+#define MT6357_AUD_DACL_PWRUP_VA28_MASK BIT(3)
+#define MT6357_AUD_DACL_PWRUP_VA28_ENABLE BIT(3)
+#define MT6357_AUD_DACL_PWRUP_VA28_DISABLE 0
+#define MT6357_AUD_DACR_PWRUP_VA28_MASK BIT(2)
+#define MT6357_AUD_DACR_PWRUP_VA28_ENABLE BIT(2)
+#define MT6357_AUD_DACR_PWRUP_VA28_DISABLE 0
+#define MT6357_AUD_DACR_PWRUP_VAUDP15_MASK BIT(1)
+#define MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE BIT(1)
+#define MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE 0
+#define MT6357_AUD_DACL_PWRUP_VAUDP15_MASK BIT(0)
+#define MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE BIT(0)
+#define MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON1 */
+#define MT6357_HPROUT_STG_CTRL_VAUDP15_MASK GENMASK(14, 12)
+#define MT6357_HPROUT_STG_CTRL_VAUDP15_SFT 12
+#define MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK GENMASK(10, 8)
+#define MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT 8
+#define MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX 7
+#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK BIT(7)
+#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE BIT(7)
+#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE 0
+#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK BIT(6)
+#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE BIT(6)
+#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE 0
+#define MT6357_HPR_AUX_FBRSW_VAUDP15_MASK BIT(5)
+#define MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE BIT(5)
+#define MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE 0
+#define MT6357_HPL_AUX_FBRSW_VAUDP15_MASK BIT(4)
+#define MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE BIT(4)
+#define MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE 0
+#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK BIT(3)
+#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE BIT(3)
+#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE 0
+#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK BIT(2)
+#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE BIT(2)
+#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE 0
+#define MT6357_HPROUT_PWRUP_VAUDP15_MASK BIT(1)
+#define MT6357_HPROUT_PWRUP_VAUDP15_ENABLE BIT(1)
+#define MT6357_HPROUT_PWRUP_VAUDP15_DISABLE 0
+#define MT6357_HPLOUT_PWRUP_VAUDP15_MASK BIT(0)
+#define MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE BIT(0)
+#define MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON2 */
+#define MT6357_HPP_SHORT_2VCM_VAUDP15_MASK BIT(10)
+#define MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE BIT(10)
+#define MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE 0
+#define MT6357_AUD_REFN_DERES_VAUDP15_MASK BIT(9)
+#define MT6357_AUD_REFN_DERES_VAUDP15_ENABLE BIT(9)
+#define MT6357_AUD_REFN_DERES_VAUDP15_DISABLE 0
+#define MT6357_HPROUT_STB_ENH_VAUDP15_MASK GENMASK(6, 4)
+#define MT6357_HPROUT_STB_ENH_VAUDP15_OPEN 0
+#define MT6357_HPROUT_STB_ENH_VAUDP15_NOPEN_P250 BIT(4)
+#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_POPEN BIT(5)
+#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250 (BIT(4) | BIT(5))
+#define MT6357_HPROUT_STB_ENH_VAUDP15_NOPEN_P470 (BIT(4) | BIT(6))
+#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_P470 (BIT(4) | BIT(5) | BIT(6))
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_MASK GENMASK(2, 0)
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_OPEN 0
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_NOPEN_P250 BIT(0)
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_POPEN BIT(1)
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250 (BIT(0) | BIT(1))
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_NOPEN_P470 (BIT(0) | BIT(2))
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P470 (BIT(0) | BIT(1) | BIT(2))
+
+/* MT6357_AUDDEC_ANA_CON3 */
+#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK BIT(7)
+#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE BIT(7)
+#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE 0
+#define MT6357_AUD_HS_SC_VAUDP15_MASK BIT(4)
+#define MT6357_AUD_HS_SC_VAUDP15_DISABLE BIT(4)
+#define MT6357_AUD_HS_SC_VAUDP15_ENABLE 0
+#define MT6357_AUD_HS_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT 2
+#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK BIT(1)
+#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE BIT(1)
+#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_DISABLE 0
+#define MT6357_AUD_HS_PWRUP_VAUDP15_MASK BIT(0)
+#define MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE BIT(0)
+#define MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON4 */
+#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK BIT(8)
+#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE BIT(8)
+#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE 0
+#define MT6357_AUD_LOL_SC_VAUDP15_MASK BIT(4)
+#define MT6357_AUD_LOL_SC_VAUDP15_DISABLE BIT(4)
+#define MT6357_AUD_LOL_SC_VAUDP15_ENABLE 0
+#define MT6357_AUD_LOL_MUX_INPUT_VAUDP15_MASK_NOSFT GENMASK(1, 0)
+#define MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT 2
+#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK BIT(1)
+#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE BIT(1)
+#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE 0
+#define MT6357_AUD_LOL_PWRUP_VAUDP15_MASK BIT(0)
+#define MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE BIT(0)
+#define MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON6 */
+#define MT6357_HP_AUX_LOOP_GAIN_MASK GENMASK(15, 12)
+#define MT6357_HP_AUX_LOOP_GAIN_SFT 12
+#define MT6357_HP_AUX_LOOP_GAIN_MAX 0x0f
+#define MT6357_HPR_AUX_CMFB_LOOP_MASK BIT(11)
+#define MT6357_HPR_AUX_CMFB_LOOP_ENABLE BIT(11)
+#define MT6357_HPR_AUX_CMFB_LOOP_DISABLE 0
+#define MT6357_HPL_AUX_CMFB_LOOP_MASK BIT(10)
+#define MT6357_HPL_AUX_CMFB_LOOP_ENABLE BIT(10)
+#define MT6357_HPL_AUX_CMFB_LOOP_DISABLE 0
+#define MT6357_HPRL_MAIN_CMFB_LOOP_MASK BIT(9)
+#define MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE BIT(9)
+#define MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE 0
+#define MT6357_HP_CMFB_RST_MASK BIT(7)
+#define MT6357_HP_CMFB_RST_NORMAL BIT(7)
+#define MT6357_HP_CMFB_RST_RESET 0
+#define MT6357_DAC_LOW_NOISE_MODE_MASK BIT(0)
+#define MT6357_DAC_LOW_NOISE_MODE_ENABLE BIT(0)
+#define MT6357_DAC_LOW_NOISE_MODE_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON7 */
+#define MT6357_HP_IVBUF_DEGAIN_SFT 2
+#define MT6357_HP_IVBUF_DEGAIN_MAX 1
+
+/* MT6357_AUDDEC_ANA_CON10 */
+#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK BIT(8)
+#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE BIT(8)
+#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE 0
+
+/* MT6357_AUDDEC_ANA_CON11 */
+#define MT6357_RSTB_ENCODER_VA28_MASK BIT(5)
+#define MT6357_RSTB_ENCODER_VA28_ENABLE BIT(5)
+#define MT6357_RSTB_ENCODER_VA28_DISABLE 0
+#define MT6357_AUDGLB_PWRDN_VA28_SFT 4
+#define MT6357_RSTB_DECODER_VA28_MASK BIT(0)
+#define MT6357_RSTB_DECODER_VA28_ENABLE BIT(0)
+#define MT6357_RSTB_DECODER_VA28_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON12 */
+#define MT6357_VA28REFGEN_EN_VA28_MASK BIT(13)
+#define MT6357_VA28REFGEN_EN_VA28_ENABLE BIT(13)
+#define MT6357_VA28REFGEN_EN_VA28_DISABLE 0
+#define MT6357_VA33REFGEN_EN_VA18_MASK BIT(12)
+#define MT6357_VA33REFGEN_EN_VA18_ENABLE BIT(12)
+#define MT6357_VA33REFGEN_EN_VA18_DISABLE 0
+#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK BIT(10)
+#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE BIT(10)
+#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE 0
+#define MT6357_LCLDO_ENC_EN_VA28_MASK BIT(8)
+#define MT6357_LCLDO_ENC_EN_VA28_ENABLE BIT(8)
+#define MT6357_LCLDO_ENC_EN_VA28_DISABLE 0
+#define MT6357_LCLDO_REMOTE_SENSE_VA18_MASK BIT(6)
+#define MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE BIT(6)
+#define MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE 0
+#define MT6357_LCLDO_EN_VA18_MASK BIT(4)
+#define MT6357_LCLDO_EN_VA18_ENABLE BIT(4)
+#define MT6357_LCLDO_EN_VA18_DISABLE 0
+#define MT6357_HCLDO_REMOTE_SENSE_VA18_MASK BIT(2)
+#define MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE BIT(2)
+#define MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE 0
+#define MT6357_HCLDO_EN_VA18_MASK BIT(0)
+#define MT6357_HCLDO_EN_VA18_ENABLE BIT(0)
+#define MT6357_HCLDO_EN_VA18_DISABLE 0
+
+/* MT6357_AUDDEC_ANA_CON13 */
+#define MT6357_NVREG_EN_VAUDP15_MASK BIT(0)
+#define MT6357_NVREG_EN_VAUDP15_ENABLE BIT(0)
+#define MT6357_NVREG_EN_VAUDP15_DISABLE 0
+
+/* MT6357_AUDDEC_ELR_0 */
+#define MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK BIT(12)
+#define MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE BIT(12)
+#define MT6357_AUD_HP_TRIM_EN_VAUDP15_DISABLE 0
+
+/* MT6357_ZCD_CON1 */
+#define MT6357_AUD_LOL_GAIN_MASK GENMASK(4, 0)
+#define MT6357_AUD_LOL_GAIN_SFT 0
+#define MT6357_AUD_LOR_GAIN_MASK GENMASK(11, 7)
+#define MT6357_AUD_LOR_GAIN_SFT 7
+#define MT6357_AUD_LO_GAIN_MAX 0x12
+
+/* MT6357_ZCD_CON2 */
+#define MT6357_AUD_HPL_GAIN_MASK GENMASK(4, 0)
+#define MT6357_AUD_HPL_GAIN_SFT 0
+#define MT6357_AUD_HPR_GAIN_MASK GENMASK(11, 7)
+#define MT6357_AUD_HPR_GAIN_SFT 7
+#define MT6357_AUD_HP_GAIN_MAX 0x12
+
+/* MT6357_ZCD_CON3 */
+#define MT6357_AUD_HS_GAIN_MASK GENMASK(4, 0)
+#define MT6357_AUD_HS_GAIN_SFT 0
+#define MT6357_AUD_HS_GAIN_MAX 0x12
+
+/* Registers list */
+/* gpio direction */
+#define MT6357_GPIO_DIR0 0x0088
+/* mosi */
+#define MT6357_GPIO_MODE2 0x00B6
+#define MT6357_GPIO_MODE2_SET 0x00B8
+#define MT6357_GPIO_MODE2_CLR 0x00BA
+/* miso */
+#define MT6357_GPIO_MODE3 0x00BC
+#define MT6357_GPIO_MODE3_SET 0x00BE
+#define MT6357_GPIO_MODE3_CLR 0x00C0
+
+#define MT6357_DCXO_CW14 0x07AC
+
+#define MT6357_AUD_TOP_CKPDN_CON0 0x208C
+#define MT6357_AUDNCP_CLKDIV_CON0 0x20B4
+#define MT6357_AUDNCP_CLKDIV_CON1 0x20B6
+#define MT6357_AUDNCP_CLKDIV_CON2 0x20B8
+#define MT6357_AUDNCP_CLKDIV_CON3 0x20BA
+#define MT6357_AUDNCP_CLKDIV_CON4 0x20BC
+#define MT6357_AFE_UL_DL_CON0 0x2108
+#define MT6357_AFE_DL_SRC2_CON0_L 0x210A
+#define MT6357_AFE_UL_SRC_CON0_H 0x210C
+#define MT6357_AFE_UL_SRC_CON0_L 0x210E
+#define MT6357_AFE_TOP_CON0 0x2110
+#define MT6357_AUDIO_TOP_CON0 0x2112
+#define MT6357_AFUNC_AUD_CON0 0x2116
+#define MT6357_AFUNC_AUD_CON2 0x211A
+#define MT6357_AFE_ADDA_MTKAIF_CFG0 0x2134
+#define MT6357_AFE_SGEN_CFG0 0x2140
+#define MT6357_AFE_DCCLK_CFG0 0x2146
+#define MT6357_AFE_DCCLK_CFG1 0x2148
+#define MT6357_AFE_AUD_PAD_TOP 0x214C
+#define MT6357_AUDENC_ANA_CON0 0x2188
+#define MT6357_AUDENC_ANA_CON1 0x218A
+#define MT6357_AUDENC_ANA_CON6 0x2194
+#define MT6357_AUDENC_ANA_CON7 0x2196
+#define MT6357_AUDENC_ANA_CON8 0x2198
+#define MT6357_AUDENC_ANA_CON9 0x219A
+#define MT6357_AUDDEC_ANA_CON0 0x2208
+#define MT6357_AUDDEC_ANA_CON1 0x220A
+#define MT6357_AUDDEC_ANA_CON2 0x220C
+#define MT6357_AUDDEC_ANA_CON3 0x220E
+#define MT6357_AUDDEC_ANA_CON4 0x2210
+#define MT6357_AUDDEC_ANA_CON6 0x2214
+#define MT6357_AUDDEC_ANA_CON7 0x2216
+#define MT6357_AUDDEC_ANA_CON10 0x221C
+#define MT6357_AUDDEC_ANA_CON11 0x221E
+#define MT6357_AUDDEC_ANA_CON12 0x2220
+#define MT6357_AUDDEC_ANA_CON13 0x2222
+#define MT6357_AUDDEC_ELR_0 0x2226
+#define MT6357_ZCD_CON1 0x228A
+#define MT6357_ZCD_CON2 0x228C
+#define MT6357_ZCD_CON3 0x228E
+
+enum {
+ DL_GAIN_8DB = 0,
+ DL_GAIN_0DB = 8,
+ DL_GAIN_N_1DB = 9,
+ DL_GAIN_N_10DB = 18,
+ DL_GAIN_N_12DB = 20,
+ DL_GAIN_N_40DB = 0x1f,
+};
+
+enum {
+ UL_GAIN_0DB = 0,
+ UL_GAIN_6DB,
+ UL_GAIN_12DB,
+ UL_GAIN_18DB,
+ UL_GAIN_24DB,
+};
+
+#define MT6357_DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB)
+#define MT6357_DL_GAIN_REG_LEFT_MASK 0x001f
+#define MT6357_DL_GAIN_REG_LEFT_SHIFT 0
+#define MT6357_DL_GAIN_REG_RIGHT_MASK 0x0f80
+#define MT6357_DL_GAIN_REG_RIGHT_SHIFT 7
+#define MT6357_DL_GAIN_REG_MASK 0x0f9f
+
+#define MT6357_SND_SOC_ADV_MT_FMTS (\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S16_BE |\
+ SNDRV_PCM_FMTBIT_U16_LE |\
+ SNDRV_PCM_FMTBIT_U16_BE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_BE |\
+ SNDRV_PCM_FMTBIT_U24_LE |\
+ SNDRV_PCM_FMTBIT_U24_BE |\
+ SNDRV_PCM_FMTBIT_S32_LE |\
+ SNDRV_PCM_FMTBIT_S32_BE |\
+ SNDRV_PCM_FMTBIT_U32_LE |\
+ SNDRV_PCM_FMTBIT_U32_BE)
+
+#define MT6357_SOC_HIGH_USE_RATE (\
+ SNDRV_PCM_RATE_CONTINUOUS |\
+ SNDRV_PCM_RATE_8000_192000)
+
+/* codec private structure */
+struct mt6357_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ bool pull_down_needed;
+ int hp_channel_number;
+};
+#endif
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index d7b157ddc9a8..a787accb88e8 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -6,8 +6,8 @@
// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/sched.h>
@@ -96,7 +96,7 @@ struct mt6358_priv {
int wov_enabled;
- unsigned int dmic_one_wire_mode;
+ int dmic_one_wire_mode;
};
int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
@@ -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,
@@ -424,8 +320,7 @@ static void headset_volume_ramp(struct mt6358_priv *priv, int from, int to)
static int mt6358_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -546,7 +441,7 @@ static int mt6358_disable_wov_phase2(struct mt6358_priv *priv)
static int mt6358_get_wov(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
ucontrol->value.integer.value[0] = priv->wov_enabled;
@@ -556,7 +451,7 @@ static int mt6358_get_wov(struct snd_kcontrol *kcontrol,
static int mt6358_put_wov(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
int enabled = ucontrol->value.integer.value[0];
@@ -577,6 +472,39 @@ static int mt6358_put_wov(struct snd_kcontrol *kcontrol,
return 0;
}
+static int mt6358_dmic_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
+
+ ucontrol->value.integer.value[0] = priv->dmic_one_wire_mode;
+ dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+ return 0;
+}
+
+static int mt6358_dmic_mode_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct mt6358_priv *priv = snd_soc_component_get_drvdata(c);
+ int enabled = ucontrol->value.integer.value[0];
+
+ if (enabled < 0 || enabled > 1)
+ return -EINVAL;
+
+ if (priv->dmic_one_wire_mode != enabled) {
+ priv->dmic_one_wire_mode = enabled;
+ dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+ return 1;
+ }
+ dev_dbg(priv->dev, "%s() dmic_mode = %d", __func__, priv->dmic_one_wire_mode);
+
+ return 0;
+}
+
static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
@@ -599,6 +527,9 @@ static const struct snd_kcontrol_new mt6358_snd_controls[] = {
SOC_SINGLE_BOOL_EXT("Wake-on-Voice Phase2 Switch", 0,
mt6358_get_wov, mt6358_put_wov),
+
+ SOC_SINGLE_BOOL_EXT("Dmic Mode Switch", 0,
+ mt6358_dmic_mode_get, mt6358_dmic_mode_set),
};
/* MUX */
@@ -1356,7 +1287,7 @@ static int mt_hp_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
int device = DEVICE_HP;
dev_info(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
@@ -1418,7 +1349,7 @@ static int mt_rcv_event(struct snd_soc_dapm_widget *w,
dev_info(priv->dev, "%s(), event 0x%x, mux %u\n",
__func__,
event,
- dapm_kcontrol_get_value(w->kcontrols[0]));
+ snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]));
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1897,7 +1828,7 @@ static int mt_mic_type_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n",
__func__, event, mux);
@@ -1943,7 +1874,7 @@ static int mt_adc_l_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
__func__, event, mux);
@@ -1959,7 +1890,7 @@ static int mt_adc_r_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
__func__, event, mux);
@@ -1975,7 +1906,7 @@ static int mt_pga_left_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
__func__, event, mux);
@@ -1991,7 +1922,7 @@ static int mt_pga_right_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n",
__func__, event, mux);
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.c b/sound/soc/codecs/mt6359-accdet.c
index 7f624854948c..ed34cc15b80e 100644
--- a/sound/soc/codecs/mt6359-accdet.c
+++ b/sound/soc/codecs/mt6359-accdet.c
@@ -6,11 +6,7 @@
// Author: Argus Lin <argus.lin@mediatek.com>
//
-#include <linux/of_gpio.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
#include <linux/input.h>
#include <linux/kthread.h>
#include <linux/io.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 30690479ec17..b15bdb15dbb0 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -9,7 +9,7 @@
#include <linux/kthread.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
@@ -367,8 +367,7 @@ static void headset_volume_ramp(struct mt6359_priv *priv,
static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -468,8 +467,7 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
static int mt6359_get_playback_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -1045,7 +1043,7 @@ static int mt_hp_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
int device = DEVICE_HP;
dev_dbg(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n",
@@ -1077,7 +1075,7 @@ static int mt_rcv_event(struct snd_soc_dapm_widget *w,
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n",
- __func__, event, dapm_kcontrol_get_value(w->kcontrols[0]));
+ __func__, event, snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]));
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1159,7 +1157,7 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n",
__func__, event, mux);
@@ -1639,7 +1637,7 @@ static int mt_pga_l_mux_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), mux %d\n", __func__, mux);
priv->mux_select[MUX_PGA_L] = mux >> RG_AUDPREAMPLINPUTSEL_SFT;
@@ -1652,7 +1650,7 @@ static int mt_pga_r_mux_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), mux %d\n", __func__, mux);
priv->mux_select[MUX_PGA_R] = mux >> RG_AUDPREAMPRINPUTSEL_SFT;
@@ -1665,7 +1663,7 @@ static int mt_pga_3_mux_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
dev_dbg(priv->dev, "%s(), mux %d\n", __func__, mux);
priv->mux_select[MUX_PGA_3] = mux >> RG_AUDPREAMP3INPUTSEL_SFT;
@@ -2867,9 +2865,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 5c50c7de26cd..ef63fd113cb7 100644
--- a/sound/soc/codecs/mt6660.c
+++ b/sound/soc/codecs/mt6660.c
@@ -187,8 +187,7 @@ static const struct snd_soc_dapm_route mt6660_component_dapm_routes[] = {
static int mt6660_component_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mt6660_chip *chip = (struct mt6660_chip *)
snd_soc_component_get_drvdata(component);
@@ -529,7 +528,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 +537,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 +547,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[] = {
@@ -559,7 +557,7 @@ static const struct of_device_id __maybe_unused mt6660_of_id[] = {
MODULE_DEVICE_TABLE(of, mt6660_of_id);
static const struct i2c_device_id mt6660_i2c_id[] = {
- {"mt6660", 0 },
+ {"mt6660" },
{},
};
MODULE_DEVICE_TABLE(i2c, mt6660_i2c_id);
@@ -568,7 +566,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/nau8325.c b/sound/soc/codecs/nau8325.c
new file mode 100644
index 000000000000..3bfdb448f8bd
--- /dev/null
+++ b/sound/soc/codecs/nau8325.c
@@ -0,0 +1,899 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// nau8325.c -- Nuvoton NAU8325 audio codec driver
+//
+// Copyright 2023 Nuvoton Technology Crop.
+// Author: Seven Lee <WTLI@nuvoton.com>
+// David Lin <CTLIN0@nuvoton.com>
+//
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "nau8325.h"
+
+/* Range of Master Clock MCLK (Hz) */
+#define MASTER_CLK_MAX 49152000
+#define MASTER_CLK_MIN 2048000
+
+/* scaling for MCLK source */
+#define CLK_PROC_BYPASS (-1)
+
+/* the maximum CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
+
+/* from MCLK input */
+#define MCLK_SRC 4
+
+static const struct nau8325_src_attr mclk_n1_div[] = {
+ { 1, 0x0 },
+ { 2, 0x1 },
+ { 3, 0x2 },
+};
+
+/* over sampling rate */
+static const struct nau8325_osr_attr osr_dac_sel[] = {
+ { 64, 2 }, /* OSR 64, SRC 1/4 */
+ { 256, 0 }, /* OSR 256, SRC 1 */
+ { 128, 1 }, /* OSR 128, SRC 1/2 */
+ { 0, 0 },
+ { 32, 3 }, /* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8325_src_attr mclk_n2_div[] = {
+ { 0, 0x0 },
+ { 1, 0x1 },
+ { 2, 0x2 },
+ { 3, 0x3 },
+ { 4, 0x4 },
+};
+
+static const struct nau8325_src_attr mclk_n3_mult[] = {
+ { 0, 0x1 },
+ { 1, 0x2 },
+ { 2, 0x3 },
+ { 3, 0x4 },
+};
+
+/* Sample Rate and MCLK_SRC selections */
+static const struct nau8325_srate_attr target_srate_table[] = {
+ /* { FS, range, max, { MCLK source }} */
+ { 48000, 2, true, { 12288000, 19200000, 24000000 } },
+ { 16000, 1, false, { 4096000, 6400000, 8000000 } },
+ { 8000, 0, false, { 2048000, 3200000, 4000000 }},
+ { 44100, 2, true, { 11289600, 17640000, 22050000 }},
+ { 64000, 3, false, { 16384000, 25600000, 32000000 } },
+ { 96000, 3, true, { 24576000, 38400000, 48000000 } },
+ { 12000, 0, true, { 3072000, 4800000, 6000000 } },
+ { 24000, 1, true, { 6144000, 9600000, 12000000 } },
+ { 32000, 2, false, { 8192000, 12800000, 16000000 } },
+};
+
+static const struct reg_default nau8325_reg_defaults[] = {
+ { NAU8325_R00_HARDWARE_RST, 0x0000 },
+ { NAU8325_R01_SOFTWARE_RST, 0x0000 },
+ { NAU8325_R03_CLK_CTRL, 0x0000 },
+ { NAU8325_R04_ENA_CTRL, 0x0000 },
+ { NAU8325_R05_INTERRUPT_CTRL, 0x007f },
+ { NAU8325_R09_IRQOUT, 0x0000 },
+ { NAU8325_R0A_IO_CTRL, 0x0000 },
+ { NAU8325_R0B_PDM_CTRL, 0x0000 },
+ { NAU8325_R0C_TDM_CTRL, 0x0000 },
+ { NAU8325_R0D_I2S_PCM_CTRL1, 0x000a },
+ { NAU8325_R0E_I2S_PCM_CTRL2, 0x0000 },
+ { NAU8325_R0F_L_TIME_SLOT, 0x0000 },
+ { NAU8325_R10_R_TIME_SLOT, 0x0000 },
+ { NAU8325_R11_HPF_CTRL, 0x0000 },
+ { NAU8325_R12_MUTE_CTRL, 0x0000 },
+ { NAU8325_R13_DAC_VOLUME, 0xf3f3 },
+ { NAU8325_R29_DAC_CTRL1, 0x0081 },
+ { NAU8325_R2A_DAC_CTRL2, 0x0000 },
+ { NAU8325_R2C_ALC_CTRL1, 0x000e },
+ { NAU8325_R2D_ALC_CTRL2, 0x8400 },
+ { NAU8325_R2E_ALC_CTRL3, 0x0000 },
+ { NAU8325_R2F_ALC_CTRL4, 0x003f },
+ { NAU8325_R40_CLK_DET_CTRL, 0xa801 },
+ { NAU8325_R50_MIXER_CTRL, 0x0000 },
+ { NAU8325_R55_MISC_CTRL, 0x0000 },
+ { NAU8325_R60_BIAS_ADJ, 0x0000 },
+ { NAU8325_R61_ANALOG_CONTROL_1, 0x0000 },
+ { NAU8325_R62_ANALOG_CONTROL_2, 0x0000 },
+ { NAU8325_R63_ANALOG_CONTROL_3, 0x0000 },
+ { NAU8325_R64_ANALOG_CONTROL_4, 0x0000 },
+ { NAU8325_R65_ANALOG_CONTROL_5, 0x0000 },
+ { NAU8325_R66_ANALOG_CONTROL_6, 0x0000 },
+ { NAU8325_R69_CLIP_CTRL, 0x0000 },
+ { NAU8325_R73_RDAC, 0x0008 },
+};
+
+static bool nau8325_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8325_R02_DEVICE_ID ... NAU8325_R06_INT_CLR_STATUS:
+ case NAU8325_R09_IRQOUT ... NAU8325_R13_DAC_VOLUME:
+ case NAU8325_R1D_DEBUG_READ1:
+ case NAU8325_R1F_DEBUG_READ2:
+ case NAU8325_R22_DEBUG_READ3:
+ case NAU8325_R29_DAC_CTRL1 ... NAU8325_R2A_DAC_CTRL2:
+ case NAU8325_R2C_ALC_CTRL1 ... NAU8325_R2F_ALC_CTRL4:
+ case NAU8325_R40_CLK_DET_CTRL:
+ case NAU8325_R49_TEST_STATUS ... NAU8325_R4A_ANALOG_READ:
+ case NAU8325_R50_MIXER_CTRL:
+ case NAU8325_R55_MISC_CTRL:
+ case NAU8325_R60_BIAS_ADJ ... NAU8325_R66_ANALOG_CONTROL_6:
+ case NAU8325_R69_CLIP_CTRL:
+ case NAU8325_R73_RDAC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool nau8325_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8325_R00_HARDWARE_RST:
+ case NAU8325_R03_CLK_CTRL ... NAU8325_R06_INT_CLR_STATUS:
+ case NAU8325_R09_IRQOUT ... NAU8325_R13_DAC_VOLUME:
+ case NAU8325_R29_DAC_CTRL1 ... NAU8325_R2A_DAC_CTRL2:
+ case NAU8325_R2C_ALC_CTRL1 ... NAU8325_R2F_ALC_CTRL4:
+ case NAU8325_R40_CLK_DET_CTRL:
+ case NAU8325_R50_MIXER_CTRL:
+ case NAU8325_R55_MISC_CTRL:
+ case NAU8325_R60_BIAS_ADJ ... NAU8325_R66_ANALOG_CONTROL_6:
+ case NAU8325_R69_CLIP_CTRL:
+ case NAU8325_R73_RDAC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool nau8325_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8325_R00_HARDWARE_RST ... NAU8325_R02_DEVICE_ID:
+ case NAU8325_R06_INT_CLR_STATUS:
+ case NAU8325_R1D_DEBUG_READ1:
+ case NAU8325_R1F_DEBUG_READ2:
+ case NAU8325_R22_DEBUG_READ3:
+ case NAU8325_R4A_ANALOG_READ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char * const nau8325_dac_oversampl_texts[] = {
+ "64", "256", "128", "32",
+};
+
+static const unsigned int nau8325_dac_oversampl_values[] = {
+ 0, 1, 2, 4,
+};
+
+static const struct soc_enum nau8325_dac_oversampl_enum =
+ SOC_VALUE_ENUM_SINGLE(NAU8325_R29_DAC_CTRL1,
+ NAU8325_DAC_OVERSAMPLE_SFT, 0x7,
+ ARRAY_SIZE(nau8325_dac_oversampl_texts),
+ nau8325_dac_oversampl_texts,
+ nau8325_dac_oversampl_values);
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(dac_vol_tlv, -8000, 600);
+
+static const struct snd_kcontrol_new nau8325_snd_controls[] = {
+ SOC_ENUM("DAC Oversampling Rate", nau8325_dac_oversampl_enum),
+ SOC_DOUBLE_TLV("Speaker Volume", NAU8325_R13_DAC_VOLUME,
+ NAU8325_DAC_VOLUME_L_SFT, NAU8325_DAC_VOLUME_R_SFT,
+ NAU8325_DAC_VOLUME_R_EN, 0, dac_vol_tlv),
+ SOC_SINGLE("ALC Max Gain", NAU8325_R2C_ALC_CTRL1,
+ NAU8325_ALC_MAXGAIN_SFT, NAU8325_ALC_MAXGAIN_MAX, 0),
+ SOC_SINGLE("ALC Min Gain", NAU8325_R2C_ALC_CTRL1,
+ NAU8325_ALC_MINGAIN_SFT, NAU8325_ALC_MINGAIN_MAX, 0),
+ SOC_SINGLE("ALC Decay Timer", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_DCY_SFT, NAU8325_ALC_DCY_MAX, 0),
+ SOC_SINGLE("ALC Attack Timer", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_ATK_SFT, NAU8325_ALC_ATK_MAX, 0),
+ SOC_SINGLE("ALC Hold Time", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_HLD_SFT, NAU8325_ALC_HLD_MAX, 0),
+ SOC_SINGLE("ALC Target Level", NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_LVL_SFT, NAU8325_ALC_LVL_MAX, 0),
+ SOC_SINGLE("ALC Enable Switch", NAU8325_R2E_ALC_CTRL3,
+ NAU8325_ALC_EN_SFT, 1, 0),
+};
+
+static int nau8325_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 nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8325->regmap, NAU8325_R12_MUTE_CTRL,
+ NAU8325_SOFT_MUTE, 0);
+ msleep(30);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Soft mute the output to prevent the pop noise. */
+ regmap_update_bits(nau8325->regmap, NAU8325_R12_MUTE_CTRL,
+ NAU8325_SOFT_MUTE, NAU8325_SOFT_MUTE);
+ msleep(30);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nau8325_powerup_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 nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+
+ if (nau8325->clock_detection)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8325->regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_PWRUP_DFT, NAU8325_PWRUP_DFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(nau8325->regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_PWRUP_DFT, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget nau8325_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("Power Up", SND_SOC_NOPM, 0, 0,
+ nau8325_powerup_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("DACL", NULL, NAU8325_R04_ENA_CTRL,
+ NAU8325_DAC_LEFT_CH_EN_SFT, 0, nau8325_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("DACR", NULL, NAU8325_R04_ENA_CTRL,
+ NAU8325_DAC_RIGHT_CH_EN_SFT, 0, nau8325_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("AIFRX", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+};
+
+static const struct snd_soc_dapm_route nau8325_dapm_routes[] = {
+ { "DACL", NULL, "Power Up" },
+ { "DACR", NULL, "Power Up" },
+
+ { "DACL", NULL, "AIFRX" },
+ { "DACR", NULL, "AIFRX" },
+ { "SPKL", NULL, "DACL" },
+ { "SPKR", NULL, "DACR" },
+};
+
+static int nau8325_srate_clk_apply(struct nau8325 *nau8325,
+ const struct nau8325_srate_attr *srate_table,
+ int n1_sel, int mclk_mult_sel, int n2_sel)
+{
+ if (!srate_table || n2_sel < 0 || n2_sel >= ARRAY_SIZE(mclk_n2_div) ||
+ n1_sel < 0 || n1_sel >= ARRAY_SIZE(mclk_n1_div)) {
+ dev_dbg(nau8325->dev, "The CLK isn't supported.");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8325->regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_REG_SRATE_MASK | NAU8325_REG_DIV_MAX,
+ (srate_table->range << NAU8325_REG_SRATE_SFT) |
+ (srate_table->max ? NAU8325_REG_DIV_MAX : 0));
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_MCLK_SRC_MASK, mclk_n2_div[n2_sel].val);
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_CLK_MUL_SRC_MASK,
+ mclk_n1_div[n1_sel].val << NAU8325_CLK_MUL_SRC_SFT);
+
+ if (mclk_mult_sel != CLK_PROC_BYPASS) {
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_MCLK_SEL_MASK,
+ mclk_n3_mult[mclk_mult_sel].val <<
+ NAU8325_MCLK_SEL_SFT);
+ } else {
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_MCLK_SEL_MASK, 0);
+ }
+
+ switch (mclk_mult_sel) {
+ case 2:
+ regmap_update_bits(nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5,
+ NAU8325_MCLK4XEN_EN, NAU8325_MCLK4XEN_EN);
+ break;
+ case 3:
+ regmap_update_bits(nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5,
+ NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN,
+ NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN);
+ break;
+ default:
+ regmap_update_bits(nau8325->regmap, NAU8325_R65_ANALOG_CONTROL_5,
+ NAU8325_MCLK4XEN_EN | NAU8325_MCLK8XEN_EN, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static int nau8325_clksrc_n2(struct nau8325 *nau8325,
+ const struct nau8325_srate_attr *srate_table,
+ int mclk, int *n2_sel)
+{
+ int i, mclk_src, ratio;
+
+ ratio = NAU8325_MCLK_FS_RATIO_NUM;
+ for (i = 0; i < ARRAY_SIZE(mclk_n2_div); i++) {
+ mclk_src = mclk >> mclk_n2_div[i].param;
+ if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_256] == mclk_src) {
+ ratio = NAU8325_MCLK_FS_RATIO_256;
+ break;
+ } else if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_400] == mclk_src) {
+ ratio = NAU8325_MCLK_FS_RATIO_400;
+ break;
+ } else if (srate_table->mclk_src[NAU8325_MCLK_FS_RATIO_500] == mclk_src) {
+ ratio = NAU8325_MCLK_FS_RATIO_500;
+ break;
+ }
+ }
+ if (ratio != NAU8325_MCLK_FS_RATIO_NUM)
+ *n2_sel = i;
+
+ return ratio;
+}
+
+static const struct nau8325_srate_attr *target_srate_attribute(int srate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(target_srate_table); i++)
+ if (target_srate_table[i].fs == srate)
+ break;
+
+ if (i == ARRAY_SIZE(target_srate_table))
+ goto proc_err;
+
+ return &target_srate_table[i];
+
+proc_err:
+ return NULL;
+}
+
+static int nau8325_clksrc_choose(struct nau8325 *nau8325,
+ const struct nau8325_srate_attr **srate_table,
+ int *n1_sel, int *mult_sel, int *n2_sel)
+{
+ int i, j, mclk, mclk_max, ratio, ratio_sel, n2_max;
+
+ if (!nau8325->mclk || !nau8325->fs)
+ goto proc_err;
+
+ /* select sampling rate and MCLK_SRC */
+ *srate_table = target_srate_attribute(nau8325->fs);
+ if (!*srate_table)
+ goto proc_err;
+
+ /* First check clock from MCLK directly, decide N2 for MCLK_SRC.
+ * If not good, consider 1/N1 and Multiplier.
+ */
+ ratio = nau8325_clksrc_n2(nau8325, *srate_table, nau8325->mclk, n2_sel);
+ if (ratio != NAU8325_MCLK_FS_RATIO_NUM) {
+ *n1_sel = 0;
+ *mult_sel = CLK_PROC_BYPASS;
+ *n2_sel = MCLK_SRC;
+ goto proc_done;
+ }
+
+ /* Get MCLK_SRC through 1/N, Multiplier, and then 1/N2. */
+ mclk_max = 0;
+ for (i = 0; i < ARRAY_SIZE(mclk_n1_div); i++) {
+ for (j = 0; j < ARRAY_SIZE(mclk_n3_mult); j++) {
+ mclk = nau8325->mclk << mclk_n3_mult[j].param;
+ mclk = mclk / mclk_n1_div[i].param;
+ ratio = nau8325_clksrc_n2(nau8325,
+ *srate_table, mclk, n2_sel);
+ if (ratio != NAU8325_MCLK_FS_RATIO_NUM &&
+ (mclk_max < mclk || i > *n1_sel)) {
+ mclk_max = mclk;
+ n2_max = *n2_sel;
+ *n1_sel = i;
+ *mult_sel = j;
+ ratio_sel = ratio;
+ goto proc_done;
+ }
+ }
+ }
+ if (mclk_max) {
+ *n2_sel = n2_max;
+ ratio = ratio_sel;
+ goto proc_done;
+ }
+
+proc_err:
+ dev_dbg(nau8325->dev, "The MCLK %d is invalid. It can't get MCLK_SRC of 256/400/500 FS (%d)",
+ nau8325->mclk, nau8325->fs);
+ return -EINVAL;
+proc_done:
+ dev_dbg(nau8325->dev, "nau8325->fs=%d,range=0x%x, %s, (n1,mu,n2,dmu):(%d,%d,%d), MCLK_SRC=%uHz (%d)",
+ nau8325->fs, (*srate_table)->range,
+ (*srate_table)->max ? "MAX" : "MIN",
+ *n1_sel == CLK_PROC_BYPASS ?
+ CLK_PROC_BYPASS : mclk_n1_div[*n1_sel].param,
+ *mult_sel == CLK_PROC_BYPASS ?
+ CLK_PROC_BYPASS : 1 << mclk_n3_mult[*mult_sel].param,
+ 1 << mclk_n2_div[*n2_sel].param,
+ (*srate_table)->mclk_src[ratio],
+ (*srate_table)->mclk_src[ratio] / nau8325->fs);
+
+ return 0;
+}
+
+static int nau8325_clock_config(struct nau8325 *nau8325)
+{
+ const struct nau8325_srate_attr *srate_table;
+ int ret, n1_sel, mult_sel, n2_sel;
+
+ ret = nau8325_clksrc_choose(nau8325, &srate_table,
+ &n1_sel, &mult_sel, &n2_sel);
+ if (ret)
+ goto err;
+
+ ret = nau8325_srate_clk_apply(nau8325, srate_table,
+ n1_sel, mult_sel, n2_sel);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct nau8325_osr_attr *nau8325_get_osr(struct nau8325 *nau8325)
+{
+ unsigned int osr;
+
+ regmap_read(nau8325->regmap, NAU8325_R29_DAC_CTRL1, &osr);
+ osr &= NAU8325_DAC_OVERSAMPLE_MASK;
+ if (osr >= ARRAY_SIZE(osr_dac_sel))
+ return NULL;
+
+ return &osr_dac_sel[osr];
+}
+
+static int nau8325_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+ const struct nau8325_osr_attr *osr;
+
+ osr = nau8325_get_osr(nau8325);
+ if (!osr || !osr->osr)
+ return -EINVAL;
+
+ return snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ 0, CLK_DA_AD_MAX / osr->osr);
+}
+
+static int nau8325_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+ unsigned int val_len = 0;
+ const struct nau8325_osr_attr *osr;
+ int ret;
+
+ nau8325->fs = params_rate(params);
+ osr = nau8325_get_osr(nau8325);
+ if (!osr || !osr->osr || nau8325->fs * osr->osr > CLK_DA_AD_MAX) {
+ ret = -EINVAL;
+ goto err;
+ }
+ regmap_update_bits(nau8325->regmap, NAU8325_R03_CLK_CTRL,
+ NAU8325_CLK_DAC_SRC_MASK,
+ osr->clk_src << NAU8325_CLK_DAC_SRC_SFT);
+
+ ret = nau8325_clock_config(nau8325);
+ if (ret)
+ goto err;
+
+ switch (params_width(params)) {
+ case 16:
+ val_len |= NAU8325_I2S_DL_16;
+ break;
+ case 20:
+ val_len |= NAU8325_I2S_DL_20;
+ break;
+ case 24:
+ val_len |= NAU8325_I2S_DL_24;
+ break;
+ case 32:
+ val_len |= NAU8325_I2S_DL_32;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ regmap_update_bits(nau8325->regmap, NAU8325_R0D_I2S_PCM_CTRL1,
+ NAU8325_I2S_DL_MASK, val_len);
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static int nau8325_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+ unsigned int ctrl1_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl1_val |= NAU8325_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl1_val |= NAU8325_I2S_DF_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl1_val |= NAU8325_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl1_val |= NAU8325_I2S_DF_RIGTH;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ctrl1_val |= NAU8325_I2S_DF_PCM_AB;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl1_val |= NAU8325_I2S_DF_PCM_AB;
+ ctrl1_val |= NAU8325_I2S_PCMB_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8325->regmap, NAU8325_R0D_I2S_PCM_CTRL1,
+ NAU8325_I2S_DF_MASK | NAU8325_I2S_BP_MASK |
+ NAU8325_I2S_PCMB_EN, ctrl1_val);
+
+ return 0;
+}
+
+static int nau8325_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int source, unsigned int freq, int dir)
+{
+ struct nau8325 *nau8325 = snd_soc_component_get_drvdata(component);
+
+ if (freq < MASTER_CLK_MIN || freq > MASTER_CLK_MAX) {
+ dev_dbg(nau8325->dev, "MCLK exceeds the range, MCLK:%d", freq);
+ return -EINVAL;
+ }
+
+ nau8325->mclk = freq;
+ dev_dbg(nau8325->dev, "MCLK %dHz", nau8325->mclk);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver nau8325_component_driver = {
+ .set_sysclk = nau8325_set_sysclk,
+ .suspend_bias_off = true,
+ .controls = nau8325_snd_controls,
+ .num_controls = ARRAY_SIZE(nau8325_snd_controls),
+ .dapm_widgets = nau8325_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(nau8325_dapm_widgets),
+ .dapm_routes = nau8325_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(nau8325_dapm_routes),
+};
+
+static const struct snd_soc_dai_ops nau8325_dai_ops = {
+ .startup = nau8325_dai_startup,
+ .hw_params = nau8325_hw_params,
+ .set_fmt = nau8325_set_fmt,
+};
+
+#define NAU8325_RATES SNDRV_PCM_RATE_8000_96000
+#define NAU8325_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE)
+
+static struct snd_soc_dai_driver nau8325_dai = {
+ .name = NAU8325_CODEC_DAI,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = NAU8325_RATES,
+ .formats = NAU8325_FORMATS,
+ },
+ .ops = &nau8325_dai_ops,
+};
+
+static const struct regmap_config nau8325_regmap_config = {
+ .reg_bits = NAU8325_REG_ADDR_LEN,
+ .val_bits = NAU8325_REG_DATA_LEN,
+
+ .max_register = NAU8325_REG_MAX,
+ .readable_reg = nau8325_readable_reg,
+ .writeable_reg = nau8325_writeable_reg,
+ .volatile_reg = nau8325_volatile_reg,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = nau8325_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(nau8325_reg_defaults),
+};
+
+static void nau8325_reset_chip(struct regmap *regmap)
+{
+ regmap_write(regmap, NAU8325_R00_HARDWARE_RST, 0x0001);
+ regmap_write(regmap, NAU8325_R00_HARDWARE_RST, 0x0000);
+}
+
+static void nau8325_init_regs(struct nau8325 *nau8325)
+{
+ struct regmap *regmap = nau8325->regmap;
+ struct device *dev = nau8325->dev;
+
+ /* set ALC parameters */
+ regmap_update_bits(regmap, NAU8325_R2C_ALC_CTRL1,
+ NAU8325_ALC_MAXGAIN_MASK,
+ 0x7 << NAU8325_ALC_MAXGAIN_SFT);
+ regmap_update_bits(regmap, NAU8325_R2D_ALC_CTRL2,
+ NAU8325_ALC_DCY_MASK | NAU8325_ALC_ATK_MASK |
+ NAU8325_ALC_HLD_MASK, (0x5 << NAU8325_ALC_DCY_SFT) |
+ (0x3 << NAU8325_ALC_ATK_SFT) |
+ (0x5 << NAU8325_ALC_HLD_SFT));
+ /* Enable ALC to avoid signal distortion when battery low. */
+ if (nau8325->alc_enable)
+ regmap_update_bits(regmap, NAU8325_R2E_ALC_CTRL3,
+ NAU8325_ALC_EN, NAU8325_ALC_EN);
+ if (nau8325->clock_detection)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS |
+ NAU8325_PWRUP_DFT, 0);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS | NAU8325_PWRUP_DFT,
+ NAU8325_CLKPWRUP_DIS);
+ if (nau8325->clock_det_data)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, NAU8325_APWRUP_EN);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, 0);
+
+ /* DAC Reference Voltage Setting */
+ switch (nau8325->dac_vref_microvolt) {
+ case 1800000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 0 << NAU8325_DACVREFSEL_SFT);
+ break;
+ case 2700000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 1 << NAU8325_DACVREFSEL_SFT);
+ break;
+ case 2880000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 2 << NAU8325_DACVREFSEL_SFT);
+ break;
+ case 3060000:
+ regmap_update_bits(regmap, NAU8325_R73_RDAC,
+ NAU8325_DACVREFSEL_MASK, 3 << NAU8325_DACVREFSEL_SFT);
+ break;
+ default:
+ dev_dbg(dev, "Invalid dac-vref-microvolt %d", nau8325->dac_vref_microvolt);
+
+ }
+
+ /* DAC Reference Voltage Decoupling Capacitors. */
+ regmap_update_bits(regmap, NAU8325_R63_ANALOG_CONTROL_3,
+ NAU8325_CLASSD_COARSE_GAIN_MASK, 0x4);
+ /* Auto-Att Min Gain 0dB, Class-D N Driver Slew Rate -25%. */
+ regmap_update_bits(regmap, NAU8325_R64_ANALOG_CONTROL_4,
+ NAU8325_CLASSD_SLEWN_MASK, 0x7);
+
+ /* VMID Tieoff (VMID Resistor Selection) */
+ switch (nau8325->vref_impedance_ohms) {
+ case 0:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 0 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ case 25000:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 1 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ case 125000:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 2 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ case 2500:
+ regmap_update_bits(regmap, NAU8325_R60_BIAS_ADJ,
+ NAU8325_BIAS_VMID_SEL_MASK, 3 << NAU8325_BIAS_VMID_SEL_SFT);
+ break;
+ default:
+ dev_dbg(dev, "Invalid vref-impedance-ohms %d", nau8325->vref_impedance_ohms);
+ }
+
+
+ /* enable VMID, BIAS, DAC, DCA CLOCK, Voltage/Current Amps
+ */
+ regmap_update_bits(regmap, NAU8325_R61_ANALOG_CONTROL_1,
+ NAU8325_DACEN_MASK | NAU8325_DACCLKEN_MASK |
+ NAU8325_DACEN_R_MASK | NAU8325_DACCLKEN_R_MASK |
+ NAU8325_CLASSDEN_MASK | NAU8325_VMDFSTENB_MASK |
+ NAU8325_BIASEN_MASK | NAU8325_VMIDEN_MASK,
+ (0x1 << NAU8325_DACEN_SFT) |
+ (0x1 << NAU8325_DACCLKEN_SFT) |
+ (0x1 << NAU8325_DACEN_R_SFT) |
+ (0x1 << NAU8325_DACCLKEN_R_SFT) |
+ (0x1 << NAU8325_CLASSDEN_SFT) |
+ (0x1 << NAU8325_VMDFSTENB_SFT) |
+ (0x1 << NAU8325_BIASEN_SFT) | 0x3);
+
+ /* Enable ALC to avoid signal distortion when battery low. */
+ if (nau8325->alc_enable)
+ regmap_update_bits(regmap, NAU8325_R2E_ALC_CTRL3,
+ NAU8325_ALC_EN, NAU8325_ALC_EN);
+ if (nau8325->clock_det_data)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, NAU8325_APWRUP_EN);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_APWRUP_EN, 0);
+ if (nau8325->clock_detection)
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS |
+ NAU8325_PWRUP_DFT, 0);
+ else
+ regmap_update_bits(regmap, NAU8325_R40_CLK_DET_CTRL,
+ NAU8325_CLKPWRUP_DIS | NAU8325_PWRUP_DFT,
+ NAU8325_CLKPWRUP_DIS);
+ regmap_update_bits(regmap, NAU8325_R29_DAC_CTRL1,
+ NAU8325_DAC_OVERSAMPLE_MASK,
+ NAU8325_DAC_OVERSAMPLE_128);
+}
+
+static void nau8325_print_device_properties(struct nau8325 *nau8325)
+{
+ struct device *dev = nau8325->dev;
+
+ dev_dbg(dev, "vref-impedance-ohms: %d", nau8325->vref_impedance_ohms);
+ dev_dbg(dev, "dac-vref-microvolt: %d", nau8325->dac_vref_microvolt);
+ dev_dbg(dev, "alc-enable: %d", nau8325->alc_enable);
+ dev_dbg(dev, "clock-det-data: %d", nau8325->clock_det_data);
+ dev_dbg(dev, "clock-detection-disable: %d", nau8325->clock_detection);
+}
+
+static int nau8325_read_device_properties(struct device *dev,
+ struct nau8325 *nau8325)
+{
+ int ret;
+
+ nau8325->alc_enable =
+ device_property_read_bool(dev, "nuvoton,alc-enable");
+ nau8325->clock_det_data =
+ device_property_read_bool(dev, "nuvoton,clock-det-data");
+ nau8325->clock_detection =
+ !device_property_read_bool(dev, "nuvoton,clock-detection-disable");
+
+ ret = device_property_read_u32(dev, "nuvoton,vref-impedance-ohms",
+ &nau8325->vref_impedance_ohms);
+ if (ret)
+ nau8325->vref_impedance_ohms = 125000;
+ ret = device_property_read_u32(dev, "nuvoton,dac-vref-microvolt",
+ &nau8325->dac_vref_microvolt);
+ if (ret)
+ nau8325->dac_vref_microvolt = 2880000;
+
+ return 0;
+}
+
+static int nau8325_i2c_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct nau8325 *nau8325 = dev_get_platdata(dev);
+ int ret, value;
+
+ if (!nau8325) {
+ nau8325 = devm_kzalloc(dev, sizeof(*nau8325), GFP_KERNEL);
+ if (!nau8325) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = nau8325_read_device_properties(dev, nau8325);
+ if (ret)
+ goto err;
+ }
+ i2c_set_clientdata(i2c, nau8325);
+
+ nau8325->regmap = devm_regmap_init_i2c(i2c, &nau8325_regmap_config);
+ if (IS_ERR(nau8325->regmap)) {
+ ret = PTR_ERR(nau8325->regmap);
+ goto err;
+ }
+ nau8325->dev = dev;
+ nau8325_print_device_properties(nau8325);
+
+ nau8325_reset_chip(nau8325->regmap);
+ ret = regmap_read(nau8325->regmap, NAU8325_R02_DEVICE_ID, &value);
+ if (ret) {
+ dev_dbg(dev, "Failed to read device id (%d)", ret);
+ goto err;
+ }
+ nau8325_init_regs(nau8325);
+
+ ret = devm_snd_soc_register_component(dev, &nau8325_component_driver,
+ &nau8325_dai, 1);
+err:
+ return ret;
+}
+
+static const struct i2c_device_id nau8325_i2c_ids[] = {
+ { "nau8325" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nau8325_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8325_of_ids[] = {
+ { .compatible = "nuvoton,nau8325", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, nau8325_of_ids);
+#endif
+
+static struct i2c_driver nau8325_i2c_driver = {
+ .driver = {
+ .name = "nau8325",
+ .of_match_table = of_match_ptr(nau8325_of_ids),
+ },
+ .probe = nau8325_i2c_probe,
+ .id_table = nau8325_i2c_ids,
+};
+module_i2c_driver(nau8325_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8325 driver");
+MODULE_AUTHOR("Seven Lee <WTLI@nuvoton.com>");
+MODULE_AUTHOR("David Lin <CTLIN0@nuvoton.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/nau8325.h b/sound/soc/codecs/nau8325.h
new file mode 100644
index 000000000000..0d173b66a4d4
--- /dev/null
+++ b/sound/soc/codecs/nau8325.h
@@ -0,0 +1,391 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * nau8325.h -- Nuvoton NAU8325 audio codec driver
+ *
+ * Copyright 2023 Nuvoton Technology Crop.
+ * Author: Seven Lee <WTLI@nuvoton.com>
+ * David Lin <CTLIN0@nuvoton.com>
+ */
+
+#ifndef __NAU8325_H__
+#define __NAU8325_H__
+
+#define NAU8325_R00_HARDWARE_RST 0x00
+#define NAU8325_R01_SOFTWARE_RST 0x01
+#define NAU8325_R02_DEVICE_ID 0x02
+#define NAU8325_R03_CLK_CTRL 0x03
+#define NAU8325_R04_ENA_CTRL 0x04
+#define NAU8325_R05_INTERRUPT_CTRL 0x05
+#define NAU8325_R06_INT_CLR_STATUS 0x06
+#define NAU8325_R09_IRQOUT 0x09
+#define NAU8325_R0A_IO_CTRL 0x0a
+#define NAU8325_R0B_PDM_CTRL 0x0b
+#define NAU8325_R0C_TDM_CTRL 0x0c
+#define NAU8325_R0D_I2S_PCM_CTRL1 0x0d
+#define NAU8325_R0E_I2S_PCM_CTRL2 0x0e
+#define NAU8325_R0F_L_TIME_SLOT 0x0f
+#define NAU8325_R10_R_TIME_SLOT 0x10
+#define NAU8325_R11_HPF_CTRL 0x11
+#define NAU8325_R12_MUTE_CTRL 0x12
+#define NAU8325_R13_DAC_VOLUME 0x13
+#define NAU8325_R1D_DEBUG_READ1 0x1d
+#define NAU8325_R1F_DEBUG_READ2 0x1f
+#define NAU8325_R22_DEBUG_READ3 0x22
+#define NAU8325_R29_DAC_CTRL1 0x29
+#define NAU8325_R2A_DAC_CTRL2 0x2a
+#define NAU8325_R2C_ALC_CTRL1 0x2c
+#define NAU8325_R2D_ALC_CTRL2 0x2d
+#define NAU8325_R2E_ALC_CTRL3 0x2e
+#define NAU8325_R2F_ALC_CTRL4 0x2f
+#define NAU8325_R40_CLK_DET_CTRL 0x40
+#define NAU8325_R49_TEST_STATUS 0x49
+#define NAU8325_R4A_ANALOG_READ 0x4a
+#define NAU8325_R50_MIXER_CTRL 0x50
+#define NAU8325_R55_MISC_CTRL 0x55
+#define NAU8325_R60_BIAS_ADJ 0x60
+#define NAU8325_R61_ANALOG_CONTROL_1 0x61
+#define NAU8325_R62_ANALOG_CONTROL_2 0x62
+#define NAU8325_R63_ANALOG_CONTROL_3 0x63
+#define NAU8325_R64_ANALOG_CONTROL_4 0x64
+#define NAU8325_R65_ANALOG_CONTROL_5 0x65
+#define NAU8325_R66_ANALOG_CONTROL_6 0x66
+#define NAU8325_R69_CLIP_CTRL 0x69
+#define NAU8325_R73_RDAC 0x73
+#define NAU8325_REG_MAX NAU8325_R73_RDAC
+
+/* 16-bit control register address, and 16-bits control register data */
+#define NAU8325_REG_ADDR_LEN 16
+#define NAU8325_REG_DATA_LEN 16
+
+/* CLK_CTRL (0x03) */
+#define NAU8325_CLK_DAC_SRC_SFT 12
+#define NAU8325_CLK_DAC_SRC_MASK (0x3 << NAU8325_CLK_DAC_SRC_SFT)
+#define NAU8325_CLK_MUL_SRC_SFT 6
+#define NAU8325_CLK_MUL_SRC_MASK (0x3 << NAU8325_CLK_MUL_SRC_SFT)
+#define NAU8325_MCLK_SEL_SFT 3
+#define NAU8325_MCLK_SEL_MASK (0x7 << NAU8325_MCLK_SEL_SFT)
+#define NAU8325_MCLK_SRC_MASK 0x7
+
+/* ENA_CTRL (0x04) */
+#define NAU8325_DAC_LEFT_CH_EN_SFT 3
+#define NAU8325_DAC_LEFT_CH_EN (0x1 << NAU8325_DAC_LEFT_CH_EN_SFT)
+#define NAU8325_DAC_RIGHT_CH_EN_SFT 2
+#define NAU8325_DAC_RIGHT_CH_EN (0x1 << NAU8325_DAC_RIGHT_CH_EN_SFT)
+
+/* INTERRUPT_CTRL (0x05) */
+#define NAU8325_ARP_DWN_INT_SFT 12
+#define NAU8325_ARP_DWN_INT_MASK (0x1 << NAU8325_ARP_DWN_INT_SFT)
+#define NAU8325_CLIP_INT_SFT 11
+#define NAU8325_CLIP_INT_MASK (0x1 << NAU8325_CLIP_INT_SFT)
+#define NAU8325_LVD_INT_SFT 10
+#define NAU8325_LVD_INT_MASK (0x1 << NAU8325_LVD_INT_SFT)
+#define NAU8325_PWR_INT_DIS_SFT 8
+#define NAU8325_PWR_INT_DIS (0x1 << NAU8325_PWR_INT_DIS_SFT)
+#define NAU8325_OCP_OTP_SHTDWN_INT_SFT 4
+#define NAU8325_OCP_OTP_SHTDWN_INT_MASK (0x1 << NAU8325_OCP_OTP_SHTDWN_INT_SFT)
+#define NAU8325_CLIP_INT_DIS_SFT 3
+#define NAU8325_CLIP_INT_DIS (0x1 << NAU8325_CLIP_INT_DIS_SFT)
+#define NAU8325_LVD_INT_DIS_SFT 2
+#define NAU8325_LVD_INT_DIS (0x1 << NAU8325_LVD_INT_DIS_SFT)
+#define NAU8325_PWR_INT_MASK 0x1
+
+/* INT_CLR_STATUS (0x06) */
+#define NAU8325_INT_STATUS_MASK 0x7f
+
+/* IRQOUT (0x9) */
+#define NAU8325_IRQOUT_SEL_SEF 12
+#define NAU8325_IRQOUT_SEL_MASK (0xf << NAU8325_IRQOUT_SEL_SEF)
+#define NAU8325_DEM_DITH_SFT 7
+#define NAU8325_DEM_DITH_EN (0x1 << NAU8325_DEM_DITH_SFT)
+#define NAU8325_GAINZI3_SFT 5
+#define NAU8325_GAINZI3_MASK (0x1 << NAU8325_GAINZI3_SFT)
+#define NAU8325_GAINZI2_MASK 0x1f
+
+/* IO_CTRL (0x0a) */
+#define NAU8325_IRQ_PL_SFT 15
+#define NAU8325_IRQ_PL_ACT_HIGH (0x1 << NAU8325_IRQ_PL_SFT)
+#define NAU8325_IRQ_PS_SFT 14
+#define NAU8325_IRQ_PS_UP (0x1 << NAU8325_IRQ_PS_SFT)
+#define NAU8325_IRQ_PE_SFT 13
+#define NAU8325_IRQ_PE_EN (0x1 << NAU8325_IRQ_PE_SFT)
+#define NAU8325_IRQ_DS_SFT 12
+#define NAU8325_IRQ_DS_HIGH (0x1 << NAU8325_IRQ_DS_SFT)
+#define NAU8325_IRQ_OUTPUT_SFT 11
+#define NAU8325_IRQ_OUTPUT_EN (0x1 << NAU8325_IRQ_OUTPUT_SFT)
+#define NAU8325_IRQ_PIN_DEBUG_SFT 10
+#define NAU8325_IRQ_PIN_DEBUG_EN (0x1 << NAU8325_IRQ_PIN_DEBUG_SFT)
+
+/* PDM_CTRL (0x0b) */
+#define NAU8325_PDM_LCH_EDGE_SFT 1
+#define NAU8325_PDM_LCH_EDGE__MASK (0x1 << NAU8325_PDM_LCH_EDGE_SFT)
+#define NAU8325_PDM_MODE_EN 0x1
+
+/* TDM_CTRL (0x0c) */
+#define NAU8325_TDM_SFT 15
+#define NAU8325_TDM_EN (0x1 << NAU8325_TDM_SFT)
+#define NAU8325_PCM_OFFSET_CTRL_SFT 14
+#define NAU8325_PCM_OFFSET_CTRL_EN (0x1 << NAU8325_PCM_OFFSET_CTRL_SFT)
+#define NAU8325_DAC_LEFT_SFT 6
+#define NAU8325_NAU8325_DAC_LEFT_MASK (0x7 << NAU8325_DAC_LEFT_SFT)
+#define NAU8325_DAC_RIGHT_SFT 3
+#define NAU8325_DAC_RIGHT_MASK (0x7 << NAU8325_DAC_RIGHT_SFT)
+
+/* I2S_PCM_CTRL1 (0x0d) */
+#define NAU8325_DACCM_CTL_SFT 14
+#define NAU8325_DACCM_CTL_MASK (0x3 << NAU8325_DACCM_CTL_SFT)
+#define NAU8325_CMB8_0_SFT 10
+#define NAU8325_CMB8_0_MASK (0x1 << NAU8325_CMB8_0_SFT)
+#define NAU8325_UA_OFFSET_SFT 9
+#define NAU8325_UA_OFFSET_MASK (0x1 << NAU8325_UA_OFFSET_SFT)
+#define NAU8325_I2S_BP_SFT 7
+#define NAU8325_I2S_BP_MASK (0x1 << NAU8325_I2S_BP_SFT)
+#define NAU8325_I2S_BP_INV (0x1 << NAU8325_I2S_BP_SFT)
+#define NAU8325_I2S_PCMB_SFT 6
+#define NAU8325_I2S_PCMB_EN (0x1 << NAU8325_I2S_PCMB_SFT)
+#define NAU8325_I2S_DACPSHS0_SFT 5
+#define NAU8325_I2S_DACPSHS0_MASK (0x1 << NAU8325_I2S_DACPSHS0_SFT)
+#define NAU8325_I2S_DL_SFT 2
+#define NAU8325_I2S_DL_MASK (0x3 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_32 (0x3 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_24 (0x2 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_20 (0x1 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DL_16 (0x0 << NAU8325_I2S_DL_SFT)
+#define NAU8325_I2S_DF_MASK 0x3
+#define NAU8325_I2S_DF_RIGTH 0x0
+#define NAU8325_I2S_DF_LEFT 0x1
+#define NAU8325_I2S_DF_I2S 0x2
+#define NAU8325_I2S_DF_PCM_AB 0x3
+
+/* I2S_PCM_CTRL2 (0x0e) */
+#define NAU8325_PCM_TS_SFT 10
+#define NAU8325_PCM_TS_EN (0x1 << NAU8325_PCM_TS_SFT)
+#define NAU8325_PCM8BIT0_SFT 8
+#define NAU8325_PCM8BIT0_MASK (0x1 << NAU8325_PCM8BIT0_SFT)
+
+/* L_TIME_SLOT (0x0f)*/
+#define NAU8325_SHORT_FS_DET_SFT 13
+#define NAU8325_SHORT_FS_DET_DIS (0x1 << NAU8325_SHORT_FS_DET_SFT)
+#define NAU8325_TSLOT_L0_MASK 0x3ff
+
+/* R_TIME_SLOT (0x10)*/
+#define NAU8325_TSLOT_R0_MASK 0x3ff
+
+/* HPF_CTRL (0x11)*/
+#define NAU8325_DAC_HPF_SFT 15
+#define NAU8325_DAC_HPF_EN (0x1 << NAU8325_DAC_HPF_SFT)
+#define NAU8325_DAC_HPF_APP_SFT 14
+#define NAU8325_DAC_HPF_APP_MASK (0x1 << NAU8325_DAC_HPF_APP_SFT)
+#define NAU8325_DAC_HPF_FCUT_SFT 11
+#define NAU8325_DAC_HPF_FCUT_MASK (0x7 << NAU8325_DAC_HPF_FCUT_SFT)
+
+/* MUTE_CTRL (0x12)*/
+#define NAU8325_SOFT_MUTE_SFT 15
+#define NAU8325_SOFT_MUTE (0x1 << NAU8325_SOFT_MUTE_SFT)
+#define NAU8325_DAC_ZC_SFT 8
+#define NAU8325_DAC_ZC_EN (0x1 << NAU8325_DAC_ZC_SFT)
+#define NAU8325_UNMUTE_CTL_SFT 6
+#define NAU8325_UNMUTE_CTL_MASK (0x3 << NAU8325_UNMUTE_CTL_SFT)
+#define NAU8325_ANA_MUTE_SFT 4
+#define NAU8325_ANA_MUTE_MASK (0x3 << NAU8325_ANA_MUTE_SFT)
+#define NAU8325_AUTO_MUTE_SFT 3
+#define NAU8325_AUTO_MUTE_DIS (0x1 << NAU8325_AUTO_MUTE_SFT)
+
+/* DAC_VOLUME (0x13) */
+#define NAU8325_DAC_VOLUME_L_SFT 8
+#define NAU8325_DAC_VOLUME_L_EN (0xff << NAU8325_DAC_VOLUME_L_SFT)
+#define NAU8325_DAC_VOLUME_R_SFT 0
+#define NAU8325_DAC_VOLUME_R_EN (0xff << NAU8325_DAC_VOLUME_R_SFT)
+#define NAU8325_DAC_VOL_MAX 0xff
+
+/* DEBUG_READ1 (0x1d)*/
+#define NAU8325_OSR100_MASK (0x1 << 6)
+#define NAU8325_MIPS500_MASK (0x1 << 5)
+#define NAU8325_SHUTDWNDRVR_R_MASK (0x1 << 4)
+#define NAU8325_SHUTDWNDRVR_L_MASK (0x1 << 3)
+#define NAU8325_MUTEB_MASK (0x1 << 2)
+#define NAU8325_PDOSCB_MASK (0x1 << 1)
+#define NAU8325_POWERDOWN1B_D_MASK 0x1
+
+/* DEBUG_READ2 (0x1f)*/
+#define NAU8325_R_CHANNEL_Vol_SFT 8
+#define NAU8325_R_CHANNEL_Vol_MASK (0xff << NAU8325_R_CHANNEL_Vol_SFT)
+#define NAU8325_L_CHANNEL_Vol_MASK 0xff
+
+/* DEBUG_READ3(0x22)*/
+#define NAU8325_PGAL_GAIN_MASK (0x3f << 7)
+#define NAU8325_CLIP_MASK (0x1 << 6)
+#define NAU8325_SCAN_MODE_MASK (0x1 << 5)
+#define NAU8325_SDB_MASK (0x1 << 4)
+#define NAU8325_TALARM_MASK (0x1 << 3)
+#define NAU8325_SHORTR_MASK (0x1 << 2)
+#define NAU8325_SHORTL_MASK (0x1 << 1)
+#define NAU8325_TMDET_MASK 0x1
+
+/* DAC_CTRL1 (0x29) */
+#define NAU8325_DAC_OVERSAMPLE_SFT 0
+#define NAU8325_DAC_OVERSAMPLE_MASK 0x7
+#define NAU8325_DAC_OVERSAMPLE_256 1
+#define NAU8325_DAC_OVERSAMPLE_128 2
+#define NAU8325_DAC_OVERSAMPLE_64 0
+#define NAU8325_DAC_OVERSAMPLE_32 4
+
+/* ALC_CTRL1 (0x2c) */
+#define NAU8325_ALC_MAXGAIN_SFT 5
+#define NAU8325_ALC_MAXGAIN_MAX 0x7
+#define NAU8325_ALC_MAXGAIN_MASK (0x7 << NAU8325_ALC_MAXGAIN_SFT)
+#define NAU8325_ALC_MINGAIN_MAX 4
+#define NAU8325_ALC_MINGAIN_SFT 1
+#define NAU8325_ALC_MINGAIN_MASK (0x7 << NAU8325_ALC_MINGAIN_SFT)
+
+/* ALC_CTRL2 (0x2d) */
+#define NAU8325_ALC_DCY_SFT 12
+#define NAU8325_ALC_DCY_MAX 0xb
+#define NAU8325_ALC_DCY_MASK (0xf << NAU8325_ALC_DCY_SFT)
+#define NAU8325_ALC_ATK_SFT 8
+#define NAU8325_ALC_ATK_MAX 0xb
+#define NAU8325_ALC_ATK_MASK (0xf << NAU8325_ALC_ATK_SFT)
+#define NAU8325_ALC_HLD_SFT 4
+#define NAU8325_ALC_HLD_MAX 0xa
+#define NAU8325_ALC_HLD_MASK (0xf << NAU8325_ALC_HLD_SFT)
+#define NAU8325_ALC_LVL_SFT 0
+#define NAU8325_ALC_LVL_MAX 0xf
+#define NAU8325_ALC_LVL_MASK 0xf
+
+/* ALC_CTRL3 (0x2e) */
+#define NAU8325_ALC_EN_SFT 15
+#define NAU8325_ALC_EN (0x1 << NAU8325_ALC_EN_SFT)
+
+/* TEMP_COMP_CTRL (0x30) */
+#define NAU8325_TEMP_COMP_ACT2_MASK 0xff
+
+/* LPF_CTRL (0x33) */
+#define NAU8325_LPF_IN1_EN_SFT 15
+#define NAU8325_LPF_IN1_EN (0x1 << NAU8325_LPF_IN1_EN_SFT)
+#define NAU8325_LPF_IN1_TC_SFT 11
+#define NAU8325_LPF_IN1_TC_MASK (0xf << NAU8325_LPF_IN1_TC_SFT)
+#define NAU8325_LPF_IN2_EN_SFT 10
+#define NAU8325_LPF_IN2_EN (0x1 << NAU8325_LPF_IN2_EN_SFT)
+#define NAU8325_LPF_IN2_TC_SFT 6
+#define NAU8325_LPF_IN2_TC_MASK (0xf << NAU8325_LPF_IN2_TC_SFT)
+
+/* CLK_DET_CTRL (0x40) */
+#define NAU8325_APWRUP_SFT 15
+#define NAU8325_APWRUP_EN (0x1 << NAU8325_APWRUP_SFT)
+#define NAU8325_CLKPWRUP_SFT 14
+#define NAU8325_CLKPWRUP_DIS (0x1 << NAU8325_CLKPWRUP_SFT)
+#define NAU8325_PWRUP_DFT_SFT 13
+#define NAU8325_PWRUP_DFT (0x1 << NAU8325_PWRUP_DFT_SFT)
+#define NAU8325_REG_SRATE_SFT 10
+#define NAU8325_REG_SRATE_MASK (0x7 << NAU8325_REG_SRATE_SFT)
+#define NAU8325_REG_ALT_SRATE_SFT 9
+#define NAU8325_REG_ALT_SRATE_EN (0x1 << NAU8325_REG_ALT_SRATE_SFT)
+#define NAU8325_REG_DIV_MAX 0x1
+
+/* BIAS_ADJ (0x60) */
+#define NAU8325_BIAS_VMID_SEL_SFT 4
+#define NAU8325_BIAS_VMID_SEL_MASK (0x3 << NAU8325_BIAS_VMID_SEL_SFT)
+
+/* ANALOG_CONTROL_1 (0x61) */
+#define NAU8325_VMDFSTENB_SFT 14
+#define NAU8325_VMDFSTENB_MASK (0x3 << NAU8325_VMDFSTENB_SFT)
+#define NAU8325_CLASSDEN_SFT 12
+#define NAU8325_CLASSDEN_MASK (0x3 << NAU8325_CLASSDEN_SFT)
+#define NAU8325_DACCLKEN_R_SFT 10
+#define NAU8325_DACCLKEN_R_MASK (0x3 << NAU8325_DACCLKEN_R_SFT)
+#define NAU8325_DACEN_R_SFT 8
+#define NAU8325_DACEN_R_MASK (0x3 << NAU8325_DACEN_R_SFT)
+#define NAU8325_DACCLKEN_SFT 6
+#define NAU8325_DACCLKEN_MASK (0x3 << NAU8325_DACCLKEN_SFT)
+#define NAU8325_DACEN_SFT 4
+#define NAU8325_DACEN_MASK (0x3 << NAU8325_DACEN_SFT)
+#define NAU8325_BIASEN_SFT 2
+#define NAU8325_BIASEN_MASK (0x3 << NAU8325_BIASEN_SFT)
+#define NAU8325_VMIDEN_MASK 0x3
+
+/* ANALOG_CONTROL_2 (0x62) */
+#define NAU8325_PWMMOD_SFT 14
+#define NAU8325_PWMMOD_MASK (0x1 << NAU8325_PWMMOD_SFT)
+#define NAU8325_DACTEST_SFT 6
+#define NAU8325_DACTEST_MASK (0x3 << NAU8325_DACTEST_SFT)
+#define NAU8325_DACREFCAP_SFT 4
+#define NAU8325_DACREFCAP_MASK (0x3 << NAU8325_DACREFCAP_SFT)
+
+/* ANALOG_CONTROL_3 (0x63) */
+#define NAU8325_POWER_DOWN_L_SFT 12
+#define NAU8325_POWER_DOWN_L_MASK (0x3 << NAU8325_POWER_DOWN_L_SFT)
+#define NAU8325_POWER_DOWN_R_SFT 11
+#define NAU8325_POWER_DOWN_R_MASK (0x3 << NAU8325_DACREFCAP_SFT)
+#define NAU8325_CLASSD_FINE_SFT 5
+#define NAU8325_CLASSD_FINE_MASK (0x3 << NAU8325_CLASSD_FINE_SFT)
+#define NAU8325_CLASSD_COARSE_GAIN_MASK 0xf
+
+/* ANALOG_CONTROL_4 (0x64) */
+#define NAU8325_CLASSD_OCPN_SFT 12
+#define NAU8325_CLASSD_OCPN_MASK (0xf << NAU8325_CLASSD_OCPN_SFT)
+#define NAU8325_CLASSD_OCPP_SFT 8
+#define NAU8325_CLASSD_OCPP_MASK (0xf << NAU8325_CLASSD_OCPP_SFT)
+#define NAU8325_CLASSD_SLEWN_MASK 0xff
+
+/* ANALOG_CONTROL_5 (0x65) */
+#define NAU8325_MCLK_RANGE_SFT 2
+#define NAU8325_MCLK_RANGE_EN (0x1 << NAU8325_MCLK_RANGE_SFT)
+#define NAU8325_MCLK8XEN_SFT 1
+#define NAU8325_MCLK8XEN_EN (0x1 << NAU8325_MCLK8XEN_SFT)
+#define NAU8325_MCLK4XEN_EN 0x1
+
+/* ANALOG_CONTROL_6 (0x66) */
+#define NAU8325_VBATLOW_SFT 4
+#define NAU8325_VBATLOW_MASK (0x1 << NAU8325_VBATLOW_SFT)
+#define NAU8325_VDDSPK_LIM_SFT 3
+#define NAU8325_VDDSPK_LIM_EN (0x1 << NAU8325_VDDSPK_LIM_SFT)
+#define NAU8325_VDDSPK_LIM_MASK 0x7
+
+/* CLIP_CTRL (0x69)*/
+#define NAU8325_ANTI_CLIP_SFT 4
+#define NAU8325_ANTI_CLIP_EN (0x1 << NAU8325_ANTI_CLIP_SFT)
+
+/* RDAC (0x73) */
+#define NAU8325_CLK_DAC_DELAY_SFT 4
+#define NAU8325_CLK_DAC_DELAY_EN (0x7 << NAU8325_CLK_DAC_DELAY_SFT)
+#define NAU8325_DACVREFSEL_SFT 2
+#define NAU8325_DACVREFSEL_MASK (0x3 << NAU8325_DACVREFSEL_SFT)
+
+#define NAU8325_CODEC_DAI "nau8325-hifi"
+
+struct nau8325 {
+ struct device *dev;
+ struct regmap *regmap;
+ int mclk;
+ int fs;
+ int vref_impedance_ohms;
+ int dac_vref_microvolt;
+ int clock_detection;
+ int clock_det_data;
+ int alc_enable;
+};
+
+struct nau8325_src_attr {
+ int param;
+ unsigned int val;
+};
+
+enum {
+ NAU8325_MCLK_FS_RATIO_256,
+ NAU8325_MCLK_FS_RATIO_400,
+ NAU8325_MCLK_FS_RATIO_500,
+ NAU8325_MCLK_FS_RATIO_NUM,
+};
+
+struct nau8325_srate_attr {
+ int fs;
+ int range;
+ bool max;
+ unsigned int mclk_src[NAU8325_MCLK_FS_RATIO_NUM];
+};
+
+struct nau8325_osr_attr {
+ unsigned int osr;
+ unsigned int clk_src;
+};
+
+#endif /* __NAU8325_H__ */
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index 2174a89772fc..caf2edb23088 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -16,7 +16,7 @@
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -26,7 +26,6 @@
#include <sound/tlv.h>
#include "nau8540.h"
-
#define NAU_FREF_MAX 13500000
#define NAU_FVCO_MAX 100000000
#define NAU_FVCO_MIN 90000000
@@ -230,6 +229,49 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new digital_ch1_mux =
SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
+static int nau8540_fepga_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 nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FEPGA2,
+ NAU8540_ACDC_CTL_MASK, NAU8540_ACDC_CTL_MIC1P_VREF |
+ NAU8540_ACDC_CTL_MIC1N_VREF | NAU8540_ACDC_CTL_MIC2P_VREF |
+ NAU8540_ACDC_CTL_MIC2N_VREF | NAU8540_ACDC_CTL_MIC3P_VREF |
+ NAU8540_ACDC_CTL_MIC3N_VREF | NAU8540_ACDC_CTL_MIC4P_VREF |
+ NAU8540_ACDC_CTL_MIC4N_VREF);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int nau8540_precharge_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 nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_REFERENCE,
+ NAU8540_DISCHRG_EN, NAU8540_DISCHRG_EN);
+ msleep(40);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_REFERENCE,
+ NAU8540_DISCHRG_EN, 0);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FEPGA2,
+ NAU8540_ACDC_CTL_MASK, 0);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static int adc_power_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -237,8 +279,10 @@ static int adc_power_control(struct snd_soc_dapm_widget *w,
struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
if (SND_SOC_DAPM_EVENT_ON(event)) {
- msleep(300);
+ msleep(160);
/* DO12 and DO34 pad output enable */
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_POWER_MANAGEMENT,
+ NAU8540_ADC_ALL_EN, NAU8540_ADC_ALL_EN);
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
NAU8540_I2S_DO12_TRI, 0);
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
@@ -248,6 +292,8 @@ static int adc_power_control(struct snd_soc_dapm_widget *w,
NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_POWER_MANAGEMENT,
+ NAU8540_ADC_ALL_EN, 0);
}
return 0;
}
@@ -274,28 +320,26 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("MIC3"),
SND_SOC_DAPM_INPUT("MIC4"),
- SND_SOC_DAPM_PGA("Frontend PGA1", NAU8540_REG_PWR, 12, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Frontend PGA2", NAU8540_REG_PWR, 13, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0),
-
- SND_SOC_DAPM_ADC_E("ADC1", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_ADC_E("ADC2", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_ADC_E("ADC3", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_ADC_E("ADC4", NULL,
- NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
- SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ADC CH3", NAU8540_REG_ANALOG_PWR, 2, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ADC CH4", NAU8540_REG_ANALOG_PWR, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_S("Frontend PGA1", 0, NAU8540_REG_PWR, 12, 0,
+ nau8540_fepga_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("Frontend PGA2", 0, NAU8540_REG_PWR, 13, 0,
+ nau8540_fepga_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("Frontend PGA3", 0, NAU8540_REG_PWR, 14, 0,
+ nau8540_fepga_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("Frontend PGA4", 0, NAU8540_REG_PWR, 15, 0,
+ nau8540_fepga_event, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_PGA_S("Precharge", 1, SND_SOC_NOPM, 0, 0,
+ nau8540_precharge_event, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_PGA_S("ADC CH1", 2, NAU8540_REG_ANALOG_PWR, 0, 0,
+ adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_S("ADC CH2", 2, NAU8540_REG_ANALOG_PWR, 1, 0,
+ adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_S("ADC CH3", 2, NAU8540_REG_ANALOG_PWR, 2, 0,
+ adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_S("ADC CH4", 2, NAU8540_REG_ANALOG_PWR, 3, 0,
+ adc_power_control, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_MUX("Digital CH4 Mux",
SND_SOC_NOPM, 0, 0, &digital_ch4_mux),
@@ -316,20 +360,20 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
{"Frontend PGA3", NULL, "MIC3"},
{"Frontend PGA4", NULL, "MIC4"},
- {"ADC1", NULL, "Frontend PGA1"},
- {"ADC2", NULL, "Frontend PGA2"},
- {"ADC3", NULL, "Frontend PGA3"},
- {"ADC4", NULL, "Frontend PGA4"},
+ {"Precharge", NULL, "Frontend PGA1"},
+ {"Precharge", NULL, "Frontend PGA2"},
+ {"Precharge", NULL, "Frontend PGA3"},
+ {"Precharge", NULL, "Frontend PGA4"},
- {"ADC CH1", NULL, "ADC1"},
- {"ADC CH2", NULL, "ADC2"},
- {"ADC CH3", NULL, "ADC3"},
- {"ADC CH4", NULL, "ADC4"},
+ {"ADC CH1", NULL, "Precharge"},
+ {"ADC CH2", NULL, "Precharge"},
+ {"ADC CH3", NULL, "Precharge"},
+ {"ADC CH4", NULL, "Precharge"},
- {"ADC1", NULL, "MICBIAS1"},
- {"ADC2", NULL, "MICBIAS1"},
- {"ADC3", NULL, "MICBIAS2"},
- {"ADC4", NULL, "MICBIAS2"},
+ {"ADC CH1", NULL, "MICBIAS1"},
+ {"ADC CH2", NULL, "MICBIAS1"},
+ {"ADC CH3", NULL, "MICBIAS2"},
+ {"ADC CH4", NULL, "MICBIAS2"},
{"Digital CH1 Mux", "ADC channel 1", "ADC CH1"},
{"Digital CH1 Mux", "ADC channel 2", "ADC CH2"},
@@ -438,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;
@@ -530,12 +574,61 @@ static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
+static int nau8540_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = nau8540->regmap;
+ unsigned int val;
+ int ret = 0;
+
+ /* Reading the peak data to detect abnormal data in the ADC channel.
+ * If abnormal data happens, the driver takes recovery actions to
+ * refresh the ADC channel.
+ */
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
+ NAU8540_CLK_AGC_EN, NAU8540_CLK_AGC_EN);
+ regmap_update_bits(regmap, NAU8540_REG_ALC_CONTROL_3,
+ NAU8540_ALC_CH_ALL_EN, NAU8540_ALC_CH_ALL_EN);
+
+ regmap_read(regmap, NAU8540_REG_PEAK_CH1, &val);
+ dev_dbg(nau8540->dev, "1.ADC CH1 peak data %x", val);
+ if (!val) {
+ regmap_update_bits(regmap, NAU8540_REG_MUTE,
+ NAU8540_PGA_CH_ALL_MUTE, NAU8540_PGA_CH_ALL_MUTE);
+ regmap_update_bits(regmap, NAU8540_REG_MUTE,
+ NAU8540_PGA_CH_ALL_MUTE, 0);
+ regmap_write(regmap, NAU8540_REG_RST, 0x1);
+ regmap_write(regmap, NAU8540_REG_RST, 0);
+ regmap_read(regmap, NAU8540_REG_PEAK_CH1, &val);
+ dev_dbg(nau8540->dev, "2.ADC CH1 peak data %x", val);
+ if (!val) {
+ dev_err(nau8540->dev, "Channel recovery failed!!");
+ ret = -EIO;
+ }
+ }
+ regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
+ NAU8540_CLK_AGC_EN, 0);
+ regmap_update_bits(regmap, NAU8540_REG_ALC_CONTROL_3,
+ NAU8540_ALC_CH_ALL_EN, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
static const struct snd_soc_dai_ops nau8540_dai_ops = {
.startup = nau8540_dai_startup,
.hw_params = nau8540_hw_params,
.set_fmt = nau8540_set_fmt,
.set_tdm_slot = nau8540_set_tdm_slot,
+ .trigger = nau8540_dai_trigger,
};
#define NAU8540_RATES SNDRV_PCM_RATE_8000_48000
@@ -872,7 +965,7 @@ static int nau8540_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id nau8540_i2c_ids[] = {
- { "nau8540", 0 },
+ { "nau8540" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau8540_i2c_ids);
diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h
index 305ea9207cf0..762bb93b06fd 100644
--- a/sound/soc/codecs/nau8540.h
+++ b/sound/soc/codecs/nau8540.h
@@ -78,6 +78,7 @@
/* POWER_MANAGEMENT (0x01) */
+#define NAU8540_ADC_ALL_EN 0xf
#define NAU8540_ADC4_EN (0x1 << 3)
#define NAU8540_ADC3_EN (0x1 << 2)
#define NAU8540_ADC2_EN (0x1 << 1)
@@ -85,6 +86,7 @@
/* CLOCK_CTRL (0x02) */
#define NAU8540_CLK_ADC_EN (0x1 << 15)
+#define NAU8540_CLK_AGC_EN (0x1 << 3)
#define NAU8540_CLK_I2S_EN (0x1 << 1)
/* CLOCK_SRC (0x03) */
@@ -168,6 +170,13 @@
#define NAU8540_TDM_OFFSET_EN (0x1 << 14)
#define NAU8540_TDM_TX_MASK 0xf
+/* ALC_CONTROL_3 (0x22) */
+#define NAU8540_ALC_CH1_EN (0x1 << 12)
+#define NAU8540_ALC_CH2_EN (0x1 << 13)
+#define NAU8540_ALC_CH3_EN (0x1 << 14)
+#define NAU8540_ALC_CH4_EN (0x1 << 15)
+#define NAU8540_ALC_CH_ALL_EN (0xf << 12)
+
/* ADC_SAMPLE_RATE (0x3A) */
#define NAU8540_CH_SYNC (0x1 << 14)
#define NAU8540_ADC_OSR_MASK 0x3
@@ -181,12 +190,20 @@
#define NAU8540_VMID_SEL_SFT 4
#define NAU8540_VMID_SEL_MASK (0x3 << NAU8540_VMID_SEL_SFT)
+/* MUTE (0x61) */
+#define NAU8540_PGA_CH1_MUTE 0x1
+#define NAU8540_PGA_CH2_MUTE 0x2
+#define NAU8540_PGA_CH3_MUTE 0x4
+#define NAU8540_PGA_CH4_MUTE 0x8
+#define NAU8540_PGA_CH_ALL_MUTE 0xf
+
/* MIC_BIAS (0x67) */
#define NAU8540_PU_PRE (0x1 << 8)
/* REFERENCE (0x68) */
#define NAU8540_PRECHARGE_DIS (0x1 << 13)
#define NAU8540_GLOBAL_BIAS_EN (0x1 << 12)
+#define NAU8540_DISCHRG_EN (0x1 << 11)
/* FEPGA1 (0x69) */
#define NAU8540_FEPGA1_MODCH2_SHT_SFT 7
@@ -199,7 +216,16 @@
#define NAU8540_FEPGA2_MODCH4_SHT (0x1 << NAU8540_FEPGA2_MODCH4_SHT_SFT)
#define NAU8540_FEPGA2_MODCH3_SHT_SFT 3
#define NAU8540_FEPGA2_MODCH3_SHT (0x1 << NAU8540_FEPGA2_MODCH3_SHT_SFT)
-
+#define NAU8540_ACDC_CTL_SFT 8
+#define NAU8540_ACDC_CTL_MASK (0xff << NAU8540_ACDC_CTL_SFT)
+#define NAU8540_ACDC_CTL_MIC4N_VREF (0x1 << 15)
+#define NAU8540_ACDC_CTL_MIC4P_VREF (0x1 << 14)
+#define NAU8540_ACDC_CTL_MIC3N_VREF (0x1 << 13)
+#define NAU8540_ACDC_CTL_MIC3P_VREF (0x1 << 12)
+#define NAU8540_ACDC_CTL_MIC2N_VREF (0x1 << 11)
+#define NAU8540_ACDC_CTL_MIC2P_VREF (0x1 << 10)
+#define NAU8540_ACDC_CTL_MIC1N_VREF (0x1 << 9)
+#define NAU8540_ACDC_CTL_MIC1P_VREF (0x1 << 8)
/* System Clock Source */
enum {
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index 47f000cd4d99..9870e62d372e 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -164,11 +164,12 @@ static bool nau8810_volatile_reg(struct device *dev, unsigned int reg)
static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
int i, reg, reg_val;
u16 *val;
+ __be16 tmp;
val = (u16 *)ucontrol->value.bytes.data;
reg = NAU8810_REG_EQ1;
@@ -177,8 +178,8 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
/* conversion of 16-bit integers between native CPU format
* and big endian format
*/
- reg_val = cpu_to_be16(reg_val);
- memcpy(val + i, &reg_val, sizeof(reg_val));
+ tmp = cpu_to_be16(reg_val);
+ memcpy(val + i, &tmp, sizeof(tmp));
}
return 0;
@@ -195,12 +196,13 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
void *data;
u16 *val, value;
int i, reg, ret;
+ __be16 *tmp;
data = kmemdup(ucontrol->value.bytes.data,
params->max, GFP_KERNEL | GFP_DMA);
@@ -213,7 +215,8 @@ static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
/* conversion of 16-bit integers between native CPU format
* and big endian format
*/
- value = be16_to_cpu(*(val + i));
+ tmp = (__be16 *)(val + i);
+ value = be16_to_cpup(tmp);
ret = regmap_write(nau8810->regmap, reg + i, value);
if (ret) {
dev_err(component->dev, "EQ configuration fail, register: %x ret: %d\n",
@@ -610,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;
@@ -772,6 +775,7 @@ static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream,
static int nau8810_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
struct regmap *map = nau8810->regmap;
@@ -787,7 +791,7 @@ static int nau8810_set_bias_level(struct snd_soc_component *component,
NAU8810_IOBUF_EN | NAU8810_ABIAS_EN,
NAU8810_IOBUF_EN | NAU8810_ABIAS_EN);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_sync(map);
regmap_update_bits(map, NAU8810_REG_POWER1,
NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K);
@@ -892,9 +896,9 @@ static int nau8810_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id nau8810_i2c_id[] = {
- { "nau8810", 0 },
- { "nau8812", 0 },
- { "nau8814", 0 },
+ { "nau8810" },
+ { "nau8812" },
+ { "nau8814" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau8810_i2c_id);
diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
index 96d75882b33a..3beb3c44dc2c 100644
--- a/sound/soc/codecs/nau8821.c
+++ b/sound/soc/codecs/nau8821.c
@@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
@@ -25,6 +26,14 @@
#include <sound/tlv.h>
#include "nau8821.h"
+#define NAU8821_QUIRK_JD_ACTIVE_HIGH BIT(0)
+#define NAU8821_QUIRK_JD_DB_BYPASS BIT(1)
+
+static int nau8821_quirk;
+static int quirk_override = -1;
+module_param_named(quirk, quirk_override, uint, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
#define NAU_FREF_MAX 13500000
#define NAU_FVCO_MAX 100000000
#define NAU_FVCO_MIN 90000000
@@ -279,10 +288,8 @@ static int nau8821_biq_coeff_get(struct snd_kcontrol *kcontrol,
if (!component->regmap)
return -EINVAL;
- regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1,
+ return regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1,
ucontrol->value.bytes.data, params->max);
-
- return 0;
}
static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol,
@@ -291,6 +298,7 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
void *data;
+ int ret;
if (!component->regmap)
return -EINVAL;
@@ -300,12 +308,12 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol,
if (!data)
return -ENOMEM;
- regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1,
+ ret = regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1,
data, params->max);
kfree(data);
- return 0;
+ return ret;
}
static const char * const nau8821_adc_decimation[] = {
@@ -503,13 +511,9 @@ static int nau8821_left_adc_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- msleep(125);
- regmap_update_bits(nau8821->regmap, NAU8821_R01_ENA_CTRL,
- NAU8821_EN_ADCL, NAU8821_EN_ADCL);
+ msleep(nau8821->adc_delay);
break;
case SND_SOC_DAPM_POST_PMD:
- regmap_update_bits(nau8821->regmap,
- NAU8821_R01_ENA_CTRL, NAU8821_EN_ADCL, 0);
break;
default:
return -EINVAL;
@@ -527,13 +531,9 @@ static int nau8821_right_adc_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- msleep(125);
- regmap_update_bits(nau8821->regmap, NAU8821_R01_ENA_CTRL,
- NAU8821_EN_ADCR, NAU8821_EN_ADCR);
+ msleep(nau8821->adc_delay);
break;
case SND_SOC_DAPM_POST_PMD:
- regmap_update_bits(nau8821->regmap,
- NAU8821_R01_ENA_CTRL, NAU8821_EN_ADCR, 0);
break;
default:
return -EINVAL;
@@ -616,6 +616,36 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
return 0;
}
+static int nau8821_left_fepga_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 nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
+
+ if (!nau8821->left_input_single_end)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA,
+ NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK,
+ NAU8821_ACDC_VREF_MICN | NAU8821_FEPGA_MODEL_AAF);
+ regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST,
+ NAU8821_HP_BOOST_DISCHRG_EN, NAU8821_HP_BOOST_DISCHRG_EN);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA,
+ NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK, 0);
+ regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST,
+ NAU8821_HP_BOOST_DISCHRG_EN, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0,
system_clock_control, SND_SOC_DAPM_POST_PMD),
@@ -627,8 +657,10 @@ static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = {
NAU8821_POWERUP_ADCL_SFT, 0),
SND_SOC_DAPM_ADC("ADCR Power", NULL, NAU8821_R72_ANALOG_ADC_2,
NAU8821_POWERUP_ADCR_SFT, 0),
+ /* single-ended design only on the left */
SND_SOC_DAPM_PGA_S("Frontend PGA L", 1, NAU8821_R7F_POWER_UP_CONTROL,
- NAU8821_PUP_PGA_L_SFT, 0, NULL, 0),
+ NAU8821_PUP_PGA_L_SFT, 0, nau8821_left_fepga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_S("Frontend PGA R", 1, NAU8821_R7F_POWER_UP_CONTROL,
NAU8821_PUP_PGA_R_SFT, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("ADCL Digital path", 0, NAU8821_R01_ENA_CTRL,
@@ -990,12 +1022,17 @@ static bool nau8821_is_jack_inserted(struct regmap *regmap)
return active_high == is_high;
}
-static void nau8821_int_status_clear_all(struct regmap *regmap)
+static void nau8821_irq_status_clear(struct regmap *regmap, int active_irq)
{
- int active_irq, clear_irq, i;
+ int clear_irq, i;
+
+ if (active_irq) {
+ regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, active_irq);
+ return;
+ }
- /* Reset the intrruption status from rightmost bit if the corres-
- * ponding irq event occurs.
+ /* Reset the interruption status from rightmost bit if the
+ * corresponding irq event occurs.
*/
regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq);
for (i = 0; i < NAU8821_REG_DATA_LEN; i++) {
@@ -1010,7 +1047,6 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
{
struct snd_soc_dapm_context *dapm = nau8821->dapm;
struct regmap *regmap = nau8821->regmap;
- struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
/* Detach 2kOhm Resistors from MICBIAS to MICGND */
regmap_update_bits(regmap, NAU8821_R74_MIC_BIAS,
@@ -1018,28 +1054,32 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
/* HPL/HPR short to ground */
regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
NAU8821_SPKR_DWN1R | NAU8821_SPKR_DWN1L, 0);
- snd_soc_component_disable_pin(component, "MICBIAS");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
snd_soc_dapm_sync(dapm);
+ /* Disable & mask both insertion & ejection IRQs */
+ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
+ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS,
+ NAU8821_IRQ_INSERT_DIS | NAU8821_IRQ_EJECT_DIS);
+ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
+ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN,
+ NAU8821_IRQ_INSERT_EN | NAU8821_IRQ_EJECT_EN);
+
/* Clear all interruption status */
- nau8821_int_status_clear_all(regmap);
+ nau8821_irq_status_clear(regmap, 0);
- /* Enable the insertion interruption, disable the ejection inter-
- * ruption, and then bypass de-bounce circuit.
- */
+ /* Enable & unmask the insertion IRQ */
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
- NAU8821_IRQ_EJECT_DIS | NAU8821_IRQ_INSERT_DIS,
- NAU8821_IRQ_EJECT_DIS);
- /* Mask unneeded IRQs: 1 - disable, 0 - enable */
+ NAU8821_IRQ_INSERT_DIS, 0);
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
- NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN,
- NAU8821_IRQ_EJECT_EN);
+ NAU8821_IRQ_INSERT_EN, 0);
+ /* Bypass de-bounce circuit */
regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
NAU8821_JACK_DET_DB_BYPASS, NAU8821_JACK_DET_DB_BYPASS);
/* Close clock for jack type detection at manual mode */
- if (dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(dapm) < SND_SOC_BIAS_PREPARE)
nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0);
/* Recover to normal channel input */
@@ -1058,22 +1098,16 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
NAU8821_IRQ_KEY_RELEASE_DIS |
NAU8821_IRQ_KEY_PRESS_DIS);
}
-
}
static void nau8821_jdet_work(struct work_struct *work)
{
struct nau8821 *nau8821 =
- container_of(work, struct nau8821, jdet_work);
+ container_of(work, struct nau8821, jdet_work.work);
struct snd_soc_dapm_context *dapm = nau8821->dapm;
- struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct regmap *regmap = nau8821->regmap;
int jack_status_reg, mic_detected, event = 0, event_mask = 0;
- snd_soc_component_force_enable_pin(component, "MICBIAS");
- snd_soc_dapm_sync(dapm);
- msleep(20);
-
regmap_read(regmap, NAU8821_R58_I2C_DEVICE_ID, &jack_status_reg);
mic_detected = !(jack_status_reg & NAU8821_KEYDET);
if (mic_detected) {
@@ -1096,13 +1130,17 @@ static void nau8821_jdet_work(struct work_struct *work)
NAU8821_R12_INTERRUPT_DIS_CTRL,
NAU8821_IRQ_KEY_RELEASE_DIS |
NAU8821_IRQ_KEY_PRESS_DIS, 0);
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_sync(dapm);
}
} else {
dev_dbg(nau8821->dev, "Headphone connected\n");
event |= SND_JACK_HEADPHONE;
- snd_soc_component_disable_pin(component, "MICBIAS");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
snd_soc_dapm_sync(dapm);
}
+
event_mask |= SND_JACK_HEADSET;
snd_soc_jack_report(nau8821->jack, event, event_mask);
}
@@ -1112,8 +1150,17 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821)
{
struct regmap *regmap = nau8821->regmap;
+ /* Disable & mask insertion IRQ */
+ regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
+ NAU8821_IRQ_INSERT_DIS, NAU8821_IRQ_INSERT_DIS);
+ regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
+ NAU8821_IRQ_INSERT_EN, NAU8821_IRQ_INSERT_EN);
+
+ /* Clear insert IRQ status */
+ nau8821_irq_status_clear(regmap, NAU8821_JACK_INSERT_DETECTED);
+
/* Enable internal VCO needed for interruptions */
- if (nau8821->dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(nau8821->dapm) < SND_SOC_BIAS_PREPARE)
nau8821_configure_sysclk(nau8821, NAU8821_CLK_INTERNAL, 0);
/* Chip needs one FSCLK cycle in order to generate interruptions,
@@ -1126,21 +1173,23 @@ static void nau8821_setup_inserted_irq(struct nau8821 *nau8821)
regmap_update_bits(regmap, NAU8821_R1D_I2S_PCM_CTRL2,
NAU8821_I2S_MS_MASK, NAU8821_I2S_MS_SLAVE);
- /* Not bypass de-bounce circuit */
- regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
- NAU8821_JACK_DET_DB_BYPASS, 0);
+ /* Do not bypass de-bounce circuit */
+ if (!(nau8821_quirk & NAU8821_QUIRK_JD_DB_BYPASS))
+ regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL,
+ NAU8821_JACK_DET_DB_BYPASS, 0);
+ /* Unmask & enable the ejection IRQs */
regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
- NAU8821_IRQ_EJECT_EN, 0);
+ NAU8821_IRQ_EJECT_EN, 0);
regmap_update_bits(regmap, NAU8821_R12_INTERRUPT_DIS_CTRL,
- NAU8821_IRQ_EJECT_DIS, 0);
+ NAU8821_IRQ_EJECT_DIS, 0);
}
static irqreturn_t nau8821_interrupt(int irq, void *data)
{
struct nau8821 *nau8821 = (struct nau8821 *)data;
struct regmap *regmap = nau8821->regmap;
- int active_irq, clear_irq = 0, event = 0, event_mask = 0;
+ int active_irq, event = 0, event_mask = 0;
if (regmap_read(regmap, NAU8821_R10_IRQ_STATUS, &active_irq)) {
dev_err(nau8821->dev, "failed to read irq status\n");
@@ -1151,48 +1200,40 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
if ((active_irq & NAU8821_JACK_EJECT_IRQ_MASK) ==
NAU8821_JACK_EJECT_DETECTED) {
+ cancel_delayed_work_sync(&nau8821->jdet_work);
regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
NAU8821_MICDET_MASK, NAU8821_MICDET_DIS);
nau8821_eject_jack(nau8821);
event_mask |= SND_JACK_HEADSET;
- clear_irq = NAU8821_JACK_EJECT_IRQ_MASK;
} else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) {
event |= NAU8821_BUTTON;
event_mask |= NAU8821_BUTTON;
- clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ;
+ nau8821_irq_status_clear(regmap, NAU8821_KEY_SHORT_PRESS_IRQ);
} else if (active_irq & NAU8821_KEY_RELEASE_IRQ) {
event_mask = NAU8821_BUTTON;
- clear_irq = NAU8821_KEY_RELEASE_IRQ;
+ nau8821_irq_status_clear(regmap, NAU8821_KEY_RELEASE_IRQ);
} else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) ==
NAU8821_JACK_INSERT_DETECTED) {
+ cancel_delayed_work_sync(&nau8821->jdet_work);
regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
NAU8821_MICDET_MASK, NAU8821_MICDET_EN);
if (nau8821_is_jack_inserted(regmap)) {
- /* detect microphone and jack type */
- cancel_work_sync(&nau8821->jdet_work);
- schedule_work(&nau8821->jdet_work);
+ /* Detect microphone and jack type */
+ snd_soc_dapm_force_enable_pin(nau8821->dapm, "MICBIAS");
+ snd_soc_dapm_sync(nau8821->dapm);
+ schedule_delayed_work(&nau8821->jdet_work, msecs_to_jiffies(20));
/* Turn off insertion interruption at manual mode */
- regmap_update_bits(regmap,
- NAU8821_R12_INTERRUPT_DIS_CTRL,
- NAU8821_IRQ_INSERT_DIS,
- NAU8821_IRQ_INSERT_DIS);
- regmap_update_bits(regmap,
- NAU8821_R0F_INTERRUPT_MASK,
- NAU8821_IRQ_INSERT_EN,
- NAU8821_IRQ_INSERT_EN);
nau8821_setup_inserted_irq(nau8821);
} else {
dev_warn(nau8821->dev,
"Inserted IRQ fired but not connected\n");
nau8821_eject_jack(nau8821);
}
+ } else {
+ /* Clear the rightmost interrupt */
+ nau8821_irq_status_clear(regmap, active_irq);
}
- if (!clear_irq)
- clear_irq = active_irq;
- /* clears the rightmost interruption */
- regmap_write(regmap, NAU8821_R11_INT_CLR_KEY_STATUS, clear_irq);
-
if (event_mask)
snd_soc_jack_report(nau8821->jack, event, event_mask);
@@ -1216,8 +1257,7 @@ static const struct regmap_config nau8821_regmap_config = {
static int nau8821_component_probe(struct snd_soc_component *component)
{
struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
nau8821->dapm = dapm;
@@ -1487,7 +1527,7 @@ static int nau8821_resume_setup(struct nau8821 *nau8821)
nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0);
if (nau8821->irq) {
/* Clear all interruption status */
- nau8821_int_status_clear_all(regmap);
+ nau8821_irq_status_clear(regmap, 0);
/* Enable both insertion and ejection interruptions, and then
* bypass de-bounce circuit.
@@ -1519,8 +1559,7 @@ static int nau8821_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_STANDBY:
/* Setup codec configuration after resume */
- if (snd_soc_component_get_bias_level(component) ==
- SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(nau8821->dapm) == SND_SOC_BIAS_OFF)
nau8821_resume_setup(nau8821);
break;
@@ -1558,9 +1597,9 @@ static int __maybe_unused nau8821_suspend(struct snd_soc_component *component)
if (nau8821->irq)
disable_irq(nau8821->irq);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(nau8821->dapm, SND_SOC_BIAS_OFF);
/* Power down codec power; don't support button wakeup */
- snd_soc_component_disable_pin(component, "MICBIAS");
+ snd_soc_dapm_disable_pin(nau8821->dapm, "MICBIAS");
snd_soc_dapm_sync(nau8821->dapm);
regcache_cache_only(nau8821->regmap, true);
regcache_mark_dirty(nau8821->regmap);
@@ -1617,7 +1656,8 @@ int nau8821_enable_jack_detect(struct snd_soc_component *component,
nau8821->jack = jack;
/* Initiate jack detection work queue */
- INIT_WORK(&nau8821->jdet_work, nau8821_jdet_work);
+ INIT_DELAYED_WORK(&nau8821->jdet_work, nau8821_jdet_work);
+
ret = devm_request_threaded_irq(nau8821->dev, nau8821->irq, NULL,
nau8821_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"nau8821", nau8821);
@@ -1654,6 +1694,7 @@ static void nau8821_print_device_properties(struct nau8821 *nau8821)
dev_dbg(dev, "dmic-clk-threshold: %d\n",
nau8821->dmic_clk_threshold);
dev_dbg(dev, "key_enable: %d\n", nau8821->key_enable);
+ dev_dbg(dev, "adc-delay-ms: %d\n", nau8821->adc_delay);
}
static int nau8821_read_device_properties(struct device *dev,
@@ -1669,6 +1710,8 @@ static int nau8821_read_device_properties(struct device *dev,
"nuvoton,jkdet-pull-up");
nau8821->key_enable = device_property_read_bool(dev,
"nuvoton,key-enable");
+ nau8821->left_input_single_end = device_property_read_bool(dev,
+ "nuvoton,left-input-single-end");
ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
&nau8821->jkdet_polarity);
if (ret)
@@ -1693,6 +1736,16 @@ static int nau8821_read_device_properties(struct device *dev,
&nau8821->dmic_clk_threshold);
if (ret)
nau8821->dmic_clk_threshold = 3072000;
+ ret = device_property_read_u32(dev, "nuvoton,dmic-slew-rate",
+ &nau8821->dmic_slew_rate);
+ if (ret)
+ nau8821->dmic_slew_rate = 0;
+ ret = device_property_read_u32(dev, "nuvoton,adc-delay-ms",
+ &nau8821->adc_delay);
+ if (ret)
+ nau8821->adc_delay = 125;
+ if (nau8821->adc_delay < 125 || nau8821->adc_delay > 500)
+ dev_warn(dev, "Please set the suitable delay time!\n");
return 0;
}
@@ -1752,6 +1805,15 @@ static void nau8821_init_regs(struct nau8821 *nau8821)
NAU8821_ADC_SYNC_DOWN_MASK, NAU8821_ADC_SYNC_DOWN_64);
regmap_update_bits(regmap, NAU8821_R2C_DAC_CTRL1,
NAU8821_DAC_OVERSAMPLE_MASK, NAU8821_DAC_OVERSAMPLE_64);
+ regmap_update_bits(regmap, NAU8821_R13_DMIC_CTRL,
+ NAU8821_DMIC_SLEW_MASK, nau8821->dmic_slew_rate <<
+ NAU8821_DMIC_SLEW_SFT);
+ if (nau8821->left_input_single_end) {
+ regmap_update_bits(regmap, NAU8821_R6B_PGA_MUTE,
+ NAU8821_MUTE_MICNL_EN, NAU8821_MUTE_MICNL_EN);
+ regmap_update_bits(regmap, NAU8821_R74_MIC_BIAS,
+ NAU8821_MICBIAS_LOWNOISE_EN, NAU8821_MICBIAS_LOWNOISE_EN);
+ }
}
static int nau8821_setup_irq(struct nau8821 *nau8821)
@@ -1792,6 +1854,49 @@ static int nau8821_setup_irq(struct nau8821 *nau8821)
return 0;
}
+/* Please keep this list alphabetically sorted */
+static const struct dmi_system_id nau8821_quirk_table[] = {
+ {
+ /* Positivo CW14Q01P-V2 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+ DMI_MATCH(DMI_BOARD_NAME, "CW14Q01P-V2"),
+ },
+ .driver_data = (void *)(NAU8821_QUIRK_JD_ACTIVE_HIGH),
+ },
+ {
+ /* Valve Steam Deck LCD */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
+ },
+ .driver_data = (void *)(NAU8821_QUIRK_JD_DB_BYPASS),
+ },
+ {
+ /* Valve Steam Deck OLED */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ .driver_data = (void *)(NAU8821_QUIRK_JD_DB_BYPASS),
+ },
+ {}
+};
+
+static void nau8821_check_quirks(void)
+{
+ const struct dmi_system_id *dmi_id;
+
+ if (quirk_override != -1) {
+ nau8821_quirk = quirk_override;
+ return;
+ }
+
+ dmi_id = dmi_first_match(nau8821_quirk_table);
+ if (dmi_id)
+ nau8821_quirk = (unsigned long)dmi_id->driver_data;
+}
+
static int nau8821_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
@@ -1812,6 +1917,15 @@ static int nau8821_i2c_probe(struct i2c_client *i2c)
nau8821->dev = dev;
nau8821->irq = i2c->irq;
+
+ nau8821_check_quirks();
+
+ if (nau8821_quirk & NAU8821_QUIRK_JD_ACTIVE_HIGH)
+ nau8821->jkdet_polarity = 0;
+
+ if (nau8821_quirk & NAU8821_QUIRK_JD_DB_BYPASS)
+ dev_dbg(dev, "Force bypassing jack detection debounce circuit\n");
+
nau8821_print_device_properties(nau8821);
nau8821_reset_chip(nau8821->regmap);
@@ -1832,7 +1946,7 @@ static int nau8821_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id nau8821_i2c_ids[] = {
- { "nau8821", 0 },
+ { "nau8821" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau8821_i2c_ids);
diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h
index d962293c218e..88602923780d 100644
--- a/sound/soc/codecs/nau8821.h
+++ b/sound/soc/codecs/nau8821.h
@@ -236,6 +236,8 @@
#define NAU8821_DMIC_SRC_MASK (0x3 << NAU8821_DMIC_SRC_SFT)
#define NAU8821_CLK_DMIC_SRC (0x2 << NAU8821_DMIC_SRC_SFT)
#define NAU8821_DMIC_EN_SFT 0
+#define NAU8821_DMIC_SLEW_SFT 8
+#define NAU8821_DMIC_SLEW_MASK (0x7 << NAU8821_DMIC_SLEW_SFT)
/* GPIO12_CTRL (0x1a) */
#define NAU8821_JKDET_PULL_UP (0x1 << 11) /* 0 - pull down, 1 - pull up */
@@ -433,6 +435,14 @@
#define NAU8821_DAC_CAPACITOR_MSB (0x1 << 1)
#define NAU8821_DAC_CAPACITOR_LSB 0x1
+/* MUTE_MIC_L_N (0x6b) */
+#define NAU8821_MUTE_MICNL_SFT 5
+#define NAU8821_MUTE_MICNL_EN (0x1 << NAU8821_MUTE_MICNL_SFT)
+#define NAU8821_MUTE_MICNR_SFT 4
+#define NAU8821_MUTE_MICNR_EN (0x1 << NAU8821_MUTE_MICNR_SFT)
+#define NAU8821_MUTE_MICRP_SFT 2
+#define NAU8821_MUTE_MICRP_EN (0x1 << NAU8821_MUTE_MICRP_SFT)
+
/* ANALOG_ADC_1 (0x71) */
#define NAU8821_MICDET_EN_SFT 0
#define NAU8821_MICDET_MASK 0x1
@@ -463,23 +473,39 @@
/* MIC_BIAS (0x74) */
#define NAU8821_MICBIAS_JKR2 (0x1 << 12)
+#define NAU8821_MICBIAS_LOWNOISE_SFT 10
+#define NAU8821_MICBIAS_LOWNOISE_EN (0x1 << NAU8821_MICBIAS_LOWNOISE_SFT)
#define NAU8821_MICBIAS_POWERUP_SFT 8
+#define NAU8821_MICBIAS_POWERUP_EN (0x1 << NAU8821_MICBIAS_POWERUP_SFT)
#define NAU8821_MICBIAS_VOLTAGE_SFT 0
#define NAU8821_MICBIAS_VOLTAGE_MASK 0x7
/* BOOST (0x76) */
#define NAU8821_PRECHARGE_DIS (0x1 << 13)
#define NAU8821_GLOBAL_BIAS_EN (0x1 << 12)
+#define NAU8821_HP_BOOST_DISCHRG_SFT 11
+#define NAU8821_HP_BOOST_DISCHRG_EN (0x1 << NAU8821_HP_BOOST_DISCHRG_SFT)
#define NAU8821_HP_BOOST_DIS_SFT 9
#define NAU8821_HP_BOOST_DIS (0x1 << NAU8821_HP_BOOST_DIS_SFT)
#define NAU8821_HP_BOOST_G_DIS (0x1 << 8)
#define NAU8821_SHORT_SHUTDOWN_EN (0x1 << 6)
/* FEPGA (0x77) */
+#define NAU8821_ACDC_CTRL_SFT 14
+#define NAU8821_ACDC_CTRL_MASK (0x3 << NAU8821_ACDC_CTRL_SFT)
+#define NAU8821_ACDC_VREF_MICP (0x1 << NAU8821_ACDC_CTRL_SFT)
+#define NAU8821_ACDC_VREF_MICN (0x2 << NAU8821_ACDC_CTRL_SFT)
#define NAU8821_FEPGA_MODEL_SFT 4
#define NAU8821_FEPGA_MODEL_MASK (0xf << NAU8821_FEPGA_MODEL_SFT)
+#define NAU8821_FEPGA_MODEL_AAF (0x1 << NAU8821_FEPGA_MODEL_SFT)
+#define NAU8821_FEPGA_MODEL_DIS (0x2 << NAU8821_FEPGA_MODEL_SFT)
+#define NAU8821_FEPGA_MODEL_IMP12K (0x8 << NAU8821_FEPGA_MODEL_SFT)
#define NAU8821_FEPGA_MODER_SFT 0
#define NAU8821_FEPGA_MODER_MASK 0xf
+#define NAU8821_FEPGA_MODER_AAF 0x1
+#define NAU8821_FEPGA_MODER_DIS 0x2
+#define NAU8821_FEPGA_MODER_IMP12K 0x8
+
/* PGA_GAIN (0x7e) */
#define NAU8821_PGA_GAIN_L_SFT 8
@@ -535,7 +561,7 @@ struct nau8821 {
struct regmap *regmap;
struct snd_soc_dapm_context *dapm;
struct snd_soc_jack *jack;
- struct work_struct jdet_work;
+ struct delayed_work jdet_work;
int irq;
int clk_id;
int micbias_voltage;
@@ -543,12 +569,15 @@ struct nau8821 {
bool jkdet_enable;
bool jkdet_pull_enable;
bool jkdet_pull_up;
+ bool left_input_single_end;
int jkdet_polarity;
int jack_insert_debounce;
int jack_eject_debounce;
int fs;
int dmic_clk_threshold;
+ int dmic_slew_rate;
int key_enable;
+ int adc_delay;
};
int nau8821_enable_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index ff3024899f45..a11759f85eac 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -14,6 +14,7 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
@@ -179,11 +180,11 @@ static bool nau8822_volatile(struct device *dev, unsigned int reg)
static int nau8822_eq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
int i, reg;
u16 reg_val, *val;
+ __be16 tmp;
val = (u16 *)ucontrol->value.bytes.data;
reg = NAU8822_REG_EQ1;
@@ -192,8 +193,8 @@ static int nau8822_eq_get(struct snd_kcontrol *kcontrol,
/* conversion of 16-bit integers between native CPU format
* and big endian format
*/
- reg_val = cpu_to_be16(reg_val);
- memcpy(val + i, &reg_val, sizeof(reg_val));
+ tmp = cpu_to_be16(reg_val);
+ memcpy(val + i, &tmp, sizeof(tmp));
}
return 0;
@@ -210,12 +211,12 @@ static int nau8822_eq_get(struct snd_kcontrol *kcontrol,
static int nau8822_eq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
void *data;
u16 *val, value;
int i, reg, ret;
+ __be16 *tmp;
data = kmemdup(ucontrol->value.bytes.data,
params->max, GFP_KERNEL | GFP_DMA);
@@ -228,7 +229,8 @@ static int nau8822_eq_put(struct snd_kcontrol *kcontrol,
/* conversion of 16-bit integers between native CPU format
* and big endian format
*/
- value = be16_to_cpu(*(val + i));
+ tmp = (__be16 *)(val + i);
+ value = be16_to_cpup(tmp);
ret = snd_soc_component_write(component, reg + i, value);
if (ret) {
dev_err(component->dev,
@@ -609,20 +611,6 @@ static const struct snd_soc_dapm_route nau8822_dapm_routes[] = {
{"Right DAC", NULL, "Digital Loopback"},
};
-static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
- unsigned int freq, int dir)
-{
- struct snd_soc_component *component = dai->component;
- struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
-
- nau8822->div_id = clk_id;
- nau8822->sysclk = freq;
- dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq,
- clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK");
-
- return 0;
-}
-
static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs,
struct nau8822_pll *pll_param)
{
@@ -746,7 +734,7 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
return ret;
}
- dev_info(component->dev,
+ dev_dbg(component->dev,
"pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n",
pll_param->pll_int, pll_param->pll_frac,
pll_param->mclk_scaler, pll_param->pre_factor);
@@ -779,6 +767,35 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
return 0;
}
+static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+ unsigned long mclk_freq;
+
+ nau8822->div_id = clk_id;
+ nau8822->sysclk = freq;
+
+ if (nau8822->mclk) {
+ mclk_freq = clk_get_rate(nau8822->mclk);
+ if (mclk_freq != freq) {
+ int ret = nau8822_set_pll(dai, NAU8822_CLK_MCLK,
+ NAU8822_CLK_MCLK, mclk_freq, freq);
+ if (ret) {
+ dev_err(component->dev, "Failed to set PLL\n");
+ return ret;
+ }
+ nau8822->div_id = NAU8822_CLK_PLL;
+ }
+ }
+
+ dev_dbg(component->dev, "master sysclk %dHz, source %s\n", freq,
+ nau8822->div_id == NAU8822_CLK_PLL ? "PLL" : "MCLK");
+
+ return 0;
+}
+
static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
@@ -787,10 +804,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:
@@ -845,7 +862,7 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
- int val_len = 0, val_rate = 0;
+ int div = 0, val_len = 0, val_rate = 0;
unsigned int ctrl_val, bclk_fs, bclk_div;
/* make BCLK and LRC divide configuration if the codec as master. */
@@ -912,8 +929,10 @@ static int nau8822_hw_params(struct snd_pcm_substream *substream,
/* If the master clock is from MCLK, provide the runtime FS for driver
* to get the master clock prescaler configuration.
*/
- if (nau8822->div_id == NAU8822_CLK_MCLK)
- nau8822_config_clkdiv(dai, 0, params_rate(params));
+ if (nau8822->div_id != NAU8822_CLK_MCLK)
+ div = nau8822->pll.mclk_scaler;
+
+ nau8822_config_clkdiv(dai, div, params_rate(params));
return 0;
}
@@ -937,22 +956,41 @@ static int nau8822_mute(struct snd_soc_dai *dai, int mute, int direction)
static int nau8822_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
+ break;
+
case SND_SOC_BIAS_PREPARE:
+ if (nau8822->mclk &&
+ snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON) {
+ int ret = clk_prepare_enable(nau8822->mclk);
+
+ if (ret) {
+ dev_err(component->dev,
+ "Failed to enable MCLK: %d\n", ret);
+ return ret;
+ }
+ }
+
snd_soc_component_update_bits(component,
NAU8822_REG_POWER_MANAGEMENT_1,
NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K);
break;
case SND_SOC_BIAS_STANDBY:
+ if (nau8822->mclk &&
+ snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_OFF)
+ clk_disable_unprepare(nau8822->mclk);
+
snd_soc_component_update_bits(component,
NAU8822_REG_POWER_MANAGEMENT_1,
NAU8822_IOBUF_EN | NAU8822_ABIAS_EN,
NAU8822_IOBUF_EN | NAU8822_ABIAS_EN);
- if (snd_soc_component_get_bias_level(component) ==
- SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component,
NAU8822_REG_POWER_MANAGEMENT_1,
NAU8822_REFIMP_MASK, NAU8822_REFIMP_3K);
@@ -1015,8 +1053,9 @@ static struct snd_soc_dai_driver nau8822_dai = {
static int nau8822_suspend(struct snd_soc_component *component)
{
struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
regcache_mark_dirty(nau8822->regmap);
@@ -1026,10 +1065,11 @@ static int nau8822_suspend(struct snd_soc_component *component)
static int nau8822_resume(struct snd_soc_component *component)
{
struct nau8822 *nau8822 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
regcache_sync(nau8822->regmap);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -1122,6 +1162,11 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
}
i2c_set_clientdata(i2c, nau8822);
+ nau8822->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(nau8822->mclk))
+ return dev_err_probe(&i2c->dev, PTR_ERR(nau8822->mclk),
+ "Error getting mclk\n");
+
nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config);
if (IS_ERR(nau8822->regmap)) {
ret = PTR_ERR(nau8822->regmap);
@@ -1148,7 +1193,7 @@ static int nau8822_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id nau8822_i2c_id[] = {
- { "nau8822", 0 },
+ { "nau8822" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau8822_i2c_id);
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index 646f6bb64bc5..13fe0a091e9e 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -215,7 +215,7 @@ struct nau8822_pll {
struct nau8822 {
struct device *dev;
struct regmap *regmap;
- int mclk_idx;
+ struct clk *mclk;
struct nau8822_pll pll;
int sysclk;
int div_id;
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 8ee47d4d750a..6ce763762443 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),
@@ -506,6 +506,7 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
struct regmap *regmap = nau8824->regmap;
unsigned int value;
bool clk_fll, error;
+ int ret;
if (SND_SOC_DAPM_EVENT_OFF(event)) {
dev_dbg(nau8824->dev, "system clock control : POWER OFF\n");
@@ -520,8 +521,15 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
} else {
nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
}
+
+ clk_disable_unprepare(nau8824->mclk);
} else {
dev_dbg(nau8824->dev, "system clock control : POWER ON\n");
+
+ ret = clk_prepare_enable(nau8824->mclk);
+ if (ret)
+ return ret;
+
/* Check the clock source setting is proper or not
* no matter the source is from FLL or MCLK.
*/
@@ -563,16 +571,21 @@ static int dmic_clock_control(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
int src;
+ unsigned int freq;
+
+ freq = clk_get_rate(nau8824->mclk);
+ if (!freq)
+ freq = nau8824->fs * 256;
/* The DMIC clock is gotten from system clock (256fs) divided by
* DMIC_SRC (1, 2, 4, 8, 16, 32). The clock has to be equal or
* less than 3.072 MHz.
*/
for (src = 0; src < 5; src++) {
- if ((0x1 << (8 - src)) * nau8824->fs <= DMIC_CLK)
+ if (freq / (0x1 << src) <= DMIC_CLK)
break;
}
- dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, nau8824->fs * 256);
+ dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, freq);
regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
NAU8824_CLK_DMIC_SRC_MASK, (src << NAU8824_CLK_DMIC_SRC_SFT));
@@ -863,7 +876,7 @@ static void nau8824_eject_jack(struct nau8824 *nau8824)
NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
/* Close clock for jack type detection at manual mode */
- if (dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(dapm) < SND_SOC_BIAS_PREPARE)
nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
}
@@ -918,7 +931,7 @@ static void nau8824_setup_auto_irq(struct nau8824 *nau8824)
regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
NAU8824_IRQ_EJECT_DIS, 0);
/* Enable internal VCO needed for interruptions */
- if (nau8824->dapm->bias_level < SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(nau8824->dapm) < SND_SOC_BIAS_PREPARE)
nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
NAU8824_JD_SLEEP_MODE, 0);
@@ -1146,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;
@@ -1485,7 +1498,7 @@ static int nau8824_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(nau8824->dapm) == SND_SOC_BIAS_OFF) {
/* Setup codec configuration after resume */
nau8824_resume_setup(nau8824);
}
@@ -1506,7 +1519,7 @@ static int nau8824_set_bias_level(struct snd_soc_component *component,
static int nau8824_component_probe(struct snd_soc_component *component)
{
struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
nau8824->dapm = dapm;
@@ -1519,7 +1532,7 @@ static int __maybe_unused nau8824_suspend(struct snd_soc_component *component)
if (nau8824->irq) {
disable_irq(nau8824->irq);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(nau8824->dapm, SND_SOC_BIAS_OFF);
}
regcache_cache_only(nau8824->regmap, true);
regcache_mark_dirty(nau8824->regmap);
@@ -1871,6 +1884,10 @@ static int nau8824_read_device_properties(struct device *dev,
if (ret)
nau8824->jack_eject_debounce = 1;
+ nau8824->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(nau8824->mclk))
+ return PTR_ERR(nau8824->mclk);
+
return 0;
}
@@ -1903,6 +1920,30 @@ static const struct dmi_system_id nau8824_quirk_table[] = {
},
.driver_data = (void *)(NAU8824_MONO_SPEAKER),
},
+ {
+ /* Positivo CW14Q01P */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+ DMI_MATCH(DMI_BOARD_NAME, "CW14Q01P"),
+ },
+ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+ },
+ {
+ /* Positivo K1424G */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+ DMI_MATCH(DMI_BOARD_NAME, "K1424G"),
+ },
+ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+ },
+ {
+ /* Positivo N14ZP74G */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+ DMI_MATCH(DMI_BOARD_NAME, "N14ZP74G"),
+ },
+ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+ },
{}
};
@@ -1979,7 +2020,7 @@ static int nau8824_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id nau8824_i2c_ids[] = {
- { "nau8824", 0 },
+ { "nau8824" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau8824_i2c_ids);
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
index 5fcfc43dfc85..d8e19515133c 100644
--- a/sound/soc/codecs/nau8824.h
+++ b/sound/soc/codecs/nau8824.h
@@ -434,6 +434,7 @@ struct nau8824 {
struct snd_soc_jack *jack;
struct work_struct jdet_work;
struct semaphore jd_sem;
+ struct clk *mclk;
int fs;
int irq;
int resume_lock;
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 9e0e4ddf128e..dd3528537ae4 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/int_log.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -38,7 +39,6 @@
#define NAU_FVCO_MIN 90000000
/* cross talk suppression detection */
-#define LOG10_MAGIC 646456993
#define GAIN_AUGMENT 22500
#define SIDETONE_BASE 207000
@@ -219,42 +219,6 @@ static const struct reg_sequence nau8825_regmap_patch[] = {
{ NAU8825_REG_MIC_BIAS, 0x0046 },
};
-
-static const unsigned short logtable[256] = {
- 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
- 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
- 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
- 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
- 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
- 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
- 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
- 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
- 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
- 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
- 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
- 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
- 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
- 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
- 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
- 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
- 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
- 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
- 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
- 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
- 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
- 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
- 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
- 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
- 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
- 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
- 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
- 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
- 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
- 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
- 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
- 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
/**
* nau8825_sema_acquire - acquire the semaphore of nau88l25
* @nau8825: component to register the codec private data with
@@ -368,65 +332,14 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
}
/**
- * nau8825_intlog10_dec3 - Computes log10 of a value
- * the result is round off to 3 decimal. This function takes reference to
- * dvb-math. The source code locates as the following.
- * Linux/drivers/media/dvb-core/dvb_math.c
+ * nau8825_intlog10_dec3 - Computes log10 of a value, rounding the result to 3 decimal places.
* @value: input for log10
*
* return log10(value) * 1000
*/
static u32 nau8825_intlog10_dec3(u32 value)
{
- u32 msb, logentry, significand, interpolation, log10val;
- u64 log2val;
-
- /* first detect the msb (count begins at 0) */
- msb = fls(value) - 1;
- /**
- * now we use a logtable after the following method:
- *
- * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
- * where x = msb and therefore 1 <= y < 2
- * first y is determined by shifting the value left
- * so that msb is bit 31
- * 0x00231f56 -> 0x8C7D5800
- * the result is y * 2^31 -> "significand"
- * then the highest 9 bits are used for a table lookup
- * the highest bit is discarded because it's always set
- * the highest nine bits in our example are 100011000
- * so we would use the entry 0x18
- */
- significand = value << (31 - msb);
- logentry = (significand >> 23) & 0xff;
- /**
- * last step we do is interpolation because of the
- * limitations of the log table the error is that part of
- * the significand which isn't used for lookup then we
- * compute the ratio between the error and the next table entry
- * and interpolate it between the log table entry used and the
- * next one the biggest error possible is 0x7fffff
- * (in our example it's 0x7D5800)
- * needed value for next table entry is 0x800000
- * so the interpolation is
- * (error / 0x800000) * (logtable_next - logtable_current)
- * in the implementation the division is moved to the end for
- * better accuracy there is also an overflow correction if
- * logtable_next is 256
- */
- interpolation = ((significand & 0x7fffff) *
- ((logtable[(logentry + 1) & 0xff] -
- logtable[logentry]) & 0xffff)) >> 15;
-
- log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation);
- /**
- * log10(x) = log2(x) * log10(2)
- */
- log10val = (log2val * LOG10_MAGIC) >> 31;
- /**
- * the result is round off to 3 decimal
- */
- return log10val / ((1 << 24) / 1000);
+ return intlog10(value) / ((1 << 24) / 1000);
}
/**
@@ -1443,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;
@@ -2313,7 +2226,7 @@ static const struct regmap_config nau8825_regmap_config = {
static int nau8825_component_probe(struct snd_soc_component *component)
{
struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
nau8825->dapm = dapm;
@@ -2717,7 +2630,7 @@ static int nau8825_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(nau8825->dapm) == SND_SOC_BIAS_OFF) {
if (nau8825->mclk_freq) {
ret = clk_prepare_enable(nau8825->mclk);
if (ret) {
@@ -2760,7 +2673,7 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_component *component)
struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
disable_irq(nau8825->irq);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(nau8825->dapm, SND_SOC_BIAS_OFF);
/* Power down codec power; don't suppoet button wakeup */
snd_soc_dapm_disable_pin(nau8825->dapm, "SAR");
snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS");
@@ -2923,16 +2836,12 @@ static int nau8825_read_device_properties(struct device *dev,
if (nau8825->adc_delay < 125 || nau8825->adc_delay > 500)
dev_warn(dev, "Please set the suitable delay time!\n");
- nau8825->mclk = devm_clk_get(dev, "mclk");
- if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
- return -EPROBE_DEFER;
- } else if (PTR_ERR(nau8825->mclk) == -ENOENT) {
+ nau8825->mclk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(nau8825->mclk))
+ return PTR_ERR(nau8825->mclk);
+ if (!nau8825->mclk)
/* The MCLK is managed externally or not used at all */
- nau8825->mclk = NULL;
dev_info(dev, "No 'mclk' clock found, assume MCLK is managed externally");
- } else if (IS_ERR(nau8825->mclk)) {
- return -EINVAL;
- }
return 0;
}
@@ -3025,7 +2934,7 @@ static void nau8825_i2c_remove(struct i2c_client *client)
{}
static const struct i2c_device_id nau8825_i2c_ids[] = {
- { "nau8825", 0 },
+ { "nau8825" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau8825_i2c_ids);
diff --git a/sound/soc/codecs/ntp8835.c b/sound/soc/codecs/ntp8835.c
new file mode 100644
index 000000000000..2b93bea11752
--- /dev/null
+++ b/sound/soc/codecs/ntp8835.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the NTP8835/NTP8835C Audio Amplifiers
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Igor Prusov <ivprusov@salutedevices.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/bits.h>
+#include <linux/reset.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/initval.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+#include <sound/tlv.h>
+
+#include "ntpfw.h"
+
+#define NTP8835_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define NTP8835_INPUT_FMT 0x0
+#define NTP8835_INPUT_FMT_MASTER_MODE BIT(0)
+#define NTP8835_INPUT_FMT_GSA_MODE BIT(1)
+#define NTP8835_GSA_FMT 0x1
+#define NTP8835_GSA_BS_MASK GENMASK(3, 2)
+#define NTP8835_GSA_BS(x) ((x) << 2)
+#define NTP8835_GSA_RIGHT_J BIT(0)
+#define NTP8835_GSA_LSB BIT(1)
+#define NTP8835_MCLK_FREQ_CTRL 0x2
+#define NTP8835_MCLK_FREQ_MCF GENMASK(1, 0)
+#define NTP8835_SOFT_MUTE 0x26
+#define NTP8835_SOFT_MUTE_SM1 BIT(0)
+#define NTP8835_SOFT_MUTE_SM2 BIT(1)
+#define NTP8835_SOFT_MUTE_SM3 BIT(2)
+#define NTP8835_PWM_SWITCH 0x27
+#define NTP8835_PWM_SWITCH_POF1 BIT(0)
+#define NTP8835_PWM_SWITCH_POF2 BIT(1)
+#define NTP8835_PWM_SWITCH_POF3 BIT(2)
+#define NTP8835_PWM_MASK_CTRL0 0x28
+#define NTP8835_PWM_MASK_CTRL0_OUT_LOW BIT(1)
+#define NTP8835_PWM_MASK_CTRL0_FPMLD BIT(2)
+#define NTP8835_MASTER_VOL 0x2e
+#define NTP8835_CHNL_A_VOL 0x2f
+#define NTP8835_CHNL_B_VOL 0x30
+#define NTP8835_CHNL_C_VOL 0x31
+#define REG_MAX NTP8835_CHNL_C_VOL
+
+#define NTP8835_FW_NAME "eq_8835.bin"
+#define NTP8835_FW_MAGIC 0x38383335 /* "8835" */
+
+struct ntp8835_priv {
+ struct i2c_client *i2c;
+ struct reset_control *reset;
+ unsigned int format;
+ struct clk *mclk;
+ unsigned int mclk_rate;
+};
+
+static const DECLARE_TLV_DB_RANGE(ntp8835_vol_scale,
+ 0, 1, TLV_DB_SCALE_ITEM(-15000, 0, 0),
+ 2, 6, TLV_DB_SCALE_ITEM(-15000, 1000, 0),
+ 7, 0xff, TLV_DB_SCALE_ITEM(-10000, 50, 0),
+);
+
+static int ntp8835_mute_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->access =
+ (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE);
+ uinfo->count = 1;
+
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ uinfo->value.integer.step = 1;
+
+ return 0;
+}
+
+static int ntp8835_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+
+ val = snd_soc_component_read(component, NTP8835_SOFT_MUTE);
+
+ ucontrol->value.integer.value[0] = val ? 0 : 1;
+ return 0;
+}
+
+static int ntp8835_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+
+ val = ucontrol->value.integer.value[0] ? 0 : 7;
+
+ snd_soc_component_write(component, NTP8835_SOFT_MUTE, val);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new ntp8835_vol_control[] = {
+ SOC_SINGLE_TLV("Playback Volume", NTP8835_MASTER_VOL, 0,
+ 0xff, 0, ntp8835_vol_scale),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Playback Switch",
+ .info = ntp8835_mute_info,
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .get = ntp8835_mute_get,
+ .put = ntp8835_mute_put,
+ },
+};
+
+static void ntp8835_reset_gpio(struct ntp8835_priv *ntp8835)
+{
+ /*
+ * Proper initialization sequence for NTP835 amplifier requires driving
+ * /RESET signal low during power up for at least 0.1us. The sequence is,
+ * according to NTP8835 datasheet, 6.2 Timing Sequence (recommended):
+ * Deassert for T2 >= 1ms...
+ */
+ reset_control_deassert(ntp8835->reset);
+ fsleep(1000);
+
+ /* ...Assert for T3 >= 0.1us... */
+ reset_control_assert(ntp8835->reset);
+ fsleep(1);
+
+ /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */
+ reset_control_deassert(ntp8835->reset);
+ fsleep(500);
+}
+
+static const struct reg_sequence ntp8835_sound_on[] = {
+ { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_FPMLD },
+ { NTP8835_PWM_SWITCH, 0x00 },
+ { NTP8835_SOFT_MUTE, 0x00 },
+};
+
+static const struct reg_sequence ntp8835_sound_off[] = {
+ { NTP8835_SOFT_MUTE, NTP8835_SOFT_MUTE_SM1 |
+ NTP8835_SOFT_MUTE_SM2 |
+ NTP8835_SOFT_MUTE_SM3 },
+
+ { NTP8835_PWM_SWITCH, NTP8835_PWM_SWITCH_POF1 |
+ NTP8835_PWM_SWITCH_POF2 |
+ NTP8835_PWM_SWITCH_POF3 },
+
+ { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_OUT_LOW |
+ NTP8835_PWM_MASK_CTRL0_FPMLD },
+};
+
+static int ntp8835_load_firmware(struct ntp8835_priv *ntp8835)
+{
+ int ret;
+
+ ret = ntpfw_load(ntp8835->i2c, NTP8835_FW_NAME, NTP8835_FW_MAGIC);
+ if (ret == -ENOENT) {
+ dev_warn_once(&ntp8835->i2c->dev,
+ "Could not find firmware %s\n", NTP8835_FW_NAME);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int ntp8835_snd_suspend(struct snd_soc_component *component)
+{
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(component->regmap, true);
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8835_sound_off,
+ ARRAY_SIZE(ntp8835_sound_off));
+
+ /*
+ * According to NTP8835 datasheet, 6.2 Timing Sequence (recommended):
+ * wait after sound off for T6 >= 0.5ms
+ */
+ fsleep(500);
+ reset_control_assert(ntp8835->reset);
+
+ regcache_mark_dirty(component->regmap);
+ clk_disable_unprepare(ntp8835->mclk);
+
+ return 0;
+}
+
+static int ntp8835_snd_resume(struct snd_soc_component *component)
+{
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ntp8835_reset_gpio(ntp8835);
+ ret = clk_prepare_enable(ntp8835->mclk);
+ if (ret)
+ return ret;
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8835_sound_on,
+ ARRAY_SIZE(ntp8835_sound_on));
+
+ ret = ntp8835_load_firmware(ntp8835);
+ if (ret) {
+ dev_err(&ntp8835->i2c->dev, "Failed to load firmware\n");
+ return ret;
+ }
+
+ regcache_cache_only(component->regmap, false);
+ snd_soc_component_cache_sync(component);
+
+ return 0;
+}
+
+static int ntp8835_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+
+ ret = snd_soc_add_component_controls(component, ntp8835_vol_control,
+ ARRAY_SIZE(ntp8835_vol_control));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add controls\n");
+
+ ret = ntp8835_load_firmware(ntp8835);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to load firmware\n");
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget ntp8835_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("OUT1"),
+ SND_SOC_DAPM_OUTPUT("OUT2"),
+ SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_route ntp8835_dapm_routes[] = {
+ { "OUT1", NULL, "AIFIN" },
+ { "OUT2", NULL, "AIFIN" },
+ { "OUT3", NULL, "AIFIN" },
+};
+
+static int ntp8835_set_component_sysclk(struct snd_soc_component *component,
+ int clk_id, int source,
+ unsigned int freq, int dir)
+{
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+
+ switch (freq) {
+ case 12288000:
+ case 24576000:
+ case 18432000:
+ ntp8835->mclk_rate = freq;
+ break;
+ default:
+ ntp8835->mclk_rate = 0;
+ dev_err(component->dev, "Unsupported MCLK value: %u", freq);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_ntp8835 = {
+ .probe = ntp8835_probe,
+ .suspend = ntp8835_snd_suspend,
+ .resume = ntp8835_snd_resume,
+ .dapm_widgets = ntp8835_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ntp8835_dapm_widgets),
+ .dapm_routes = ntp8835_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ntp8835_dapm_routes),
+ .set_sysclk = ntp8835_set_component_sysclk,
+};
+
+static int ntp8835_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+ unsigned int input_fmt = 0;
+ unsigned int gsa_fmt = 0;
+ unsigned int gsa_fmt_mask;
+ unsigned int mcf;
+ int ret;
+
+ switch (ntp8835->mclk_rate) {
+ case 12288000:
+ mcf = 0;
+ break;
+ case 24576000:
+ mcf = 1;
+ break;
+ case 18432000:
+ mcf = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8835_MCLK_FREQ_CTRL,
+ NTP8835_MCLK_FREQ_MCF, mcf);
+ if (ret)
+ return ret;
+
+ switch (ntp8835->format) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ input_fmt |= NTP8835_INPUT_FMT_GSA_MODE;
+ gsa_fmt |= NTP8835_GSA_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ input_fmt |= NTP8835_INPUT_FMT_GSA_MODE;
+ break;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8835_INPUT_FMT,
+ NTP8835_INPUT_FMT_MASTER_MODE |
+ NTP8835_INPUT_FMT_GSA_MODE,
+ input_fmt);
+
+ if (!(input_fmt & NTP8835_INPUT_FMT_GSA_MODE) || ret < 0)
+ return ret;
+
+ switch (params_width(params)) {
+ case 24:
+ gsa_fmt |= NTP8835_GSA_BS(0);
+ break;
+ case 20:
+ gsa_fmt |= NTP8835_GSA_BS(1);
+ break;
+ case 18:
+ gsa_fmt |= NTP8835_GSA_BS(2);
+ break;
+ case 16:
+ gsa_fmt |= NTP8835_GSA_BS(3);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ gsa_fmt_mask = NTP8835_GSA_BS_MASK |
+ NTP8835_GSA_RIGHT_J |
+ NTP8835_GSA_LSB;
+ return snd_soc_component_update_bits(component, NTP8835_GSA_FMT,
+ gsa_fmt_mask, gsa_fmt);
+}
+
+static int ntp8835_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ ntp8835->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+};
+
+static const struct snd_soc_dai_ops ntp8835_dai_ops = {
+ .hw_params = ntp8835_hw_params,
+ .set_fmt = ntp8835_set_fmt,
+};
+
+static struct snd_soc_dai_driver ntp8835_dai = {
+ .name = "ntp8835-amplifier",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 3,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = NTP8835_FORMATS,
+ },
+ .ops = &ntp8835_dai_ops,
+};
+
+static const struct regmap_config ntp8835_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ntp8835_i2c_probe(struct i2c_client *i2c)
+{
+ struct ntp8835_priv *ntp8835;
+ struct regmap *regmap;
+ int ret;
+
+ ntp8835 = devm_kzalloc(&i2c->dev, sizeof(*ntp8835), GFP_KERNEL);
+ if (!ntp8835)
+ return -ENOMEM;
+
+ ntp8835->i2c = i2c;
+
+ ntp8835->reset = devm_reset_control_get_shared(&i2c->dev, NULL);
+ if (IS_ERR(ntp8835->reset))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->reset),
+ "Failed to get reset\n");
+
+ ret = reset_control_deassert(ntp8835->reset);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to deassert reset\n");
+
+ dev_set_drvdata(&i2c->dev, ntp8835);
+
+ ntp8835_reset_gpio(ntp8835);
+
+ regmap = devm_regmap_init_i2c(i2c, &ntp8835_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+ "Failed to allocate regmap\n");
+
+ ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8835,
+ &ntp8835_dai, 1);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to register component\n");
+
+ ntp8835->mclk = devm_clk_get_enabled(&i2c->dev, "mclk");
+ if (IS_ERR(ntp8835->mclk))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->mclk), "failed to get mclk\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id ntp8835_i2c_id[] = {
+ { "ntp8835" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ntp8835_i2c_id);
+
+static const struct of_device_id ntp8835_of_match[] = {
+ {.compatible = "neofidelity,ntp8835",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, ntp8835_of_match);
+
+static struct i2c_driver ntp8835_i2c_driver = {
+ .probe = ntp8835_i2c_probe,
+ .id_table = ntp8835_i2c_id,
+ .driver = {
+ .name = "ntp8835",
+ .of_match_table = ntp8835_of_match,
+ },
+};
+module_i2c_driver(ntp8835_i2c_driver);
+
+MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>");
+MODULE_DESCRIPTION("NTP8835 Audio Amplifier Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c
new file mode 100644
index 000000000000..5593d48ef696
--- /dev/null
+++ b/sound/soc/codecs/ntp8918.c
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the NTP8918 Audio Amplifier
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Igor Prusov <ivprusov@salutedevices.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/reset.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include <sound/initval.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+#include <sound/tlv.h>
+
+#include "ntpfw.h"
+
+#define NTP8918_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+#define NTP8918_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define NTP8918_INPUT_FMT 0x0
+#define NTP8918_INPUT_FMT_MASTER_MODE BIT(0)
+#define NTP8918_INPUT_FMT_GSA_MODE BIT(1)
+#define NTP8918_GSA_FMT 0x1
+#define NTP8918_GSA_BS_MASK GENMASK(3, 2)
+#define NTP8918_GSA_BS(x) ((x) << 2)
+#define NTP8918_GSA_RIGHT_J BIT(0)
+#define NTP8918_GSA_LSB BIT(1)
+#define NTP8918_MCLK_FREQ_CTRL 0x2
+#define NTP8918_MCLK_FREQ_MCF GENMASK(1, 0)
+#define NTP8918_MASTER_VOL 0x0C
+#define NTP8918_CHNL_A_VOL 0x17
+#define NTP8918_CHNL_B_VOL 0x18
+#define NTP8918_SOFT_MUTE 0x33
+#define NTP8918_SOFT_MUTE_SM1 BIT(0)
+#define NTP8918_SOFT_MUTE_SM2 BIT(1)
+#define NTP8918_PWM_SWITCH 0x34
+#define NTP8918_PWM_MASK_CTRL0 0x35
+#define REG_MAX NTP8918_PWM_MASK_CTRL0
+
+#define NTP8918_FW_NAME "eq_8918.bin"
+#define NTP8918_FW_MAGIC 0x38393138 /* "8918" */
+
+struct ntp8918_priv {
+ struct i2c_client *i2c;
+ struct clk *bck;
+ struct reset_control *reset;
+ unsigned int format;
+};
+
+static const DECLARE_TLV_DB_SCALE(ntp8918_master_vol_scale, -12550, 50, 0);
+
+static const struct snd_kcontrol_new ntp8918_vol_control[] = {
+ SOC_SINGLE_RANGE_TLV("Playback Volume", NTP8918_MASTER_VOL, 0,
+ 0x04, 0xff, 0, ntp8918_master_vol_scale),
+ SOC_SINGLE("Playback Switch", NTP8918_PWM_MASK_CTRL0, 1, 1, 1),
+};
+
+static void ntp8918_reset_gpio(struct ntp8918_priv *ntp8918)
+{
+ /*
+ * Proper initialization sequence for NTP8918 amplifier requires driving
+ * /RESET signal low during power up for at least 0.1us. The sequence is,
+ * according to NTP8918 datasheet, 6.2 Timing Sequence 1:
+ * Deassert for T2 >= 1ms...
+ */
+ reset_control_deassert(ntp8918->reset);
+ fsleep(1000);
+
+ /* ...Assert for T3 >= 0.1us... */
+ reset_control_assert(ntp8918->reset);
+ fsleep(1);
+
+ /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */
+ reset_control_deassert(ntp8918->reset);
+ fsleep(500);
+}
+
+static const struct reg_sequence ntp8918_sound_off[] = {
+ { NTP8918_MASTER_VOL, 0 },
+};
+
+static const struct reg_sequence ntp8918_sound_on[] = {
+ { NTP8918_MASTER_VOL, 0b11 },
+};
+
+static int ntp8918_load_firmware(struct ntp8918_priv *ntp8918)
+{
+ int ret;
+
+ ret = ntpfw_load(ntp8918->i2c, NTP8918_FW_NAME, NTP8918_FW_MAGIC);
+ if (ret == -ENOENT) {
+ dev_warn_once(&ntp8918->i2c->dev, "Could not find firmware %s\n",
+ NTP8918_FW_NAME);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int ntp8918_snd_suspend(struct snd_soc_component *component)
+{
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(component->regmap, true);
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8918_sound_off,
+ ARRAY_SIZE(ntp8918_sound_off));
+
+ /*
+ * According to NTP8918 datasheet, 6.2 Timing Sequence 1:
+ * wait after sound off for T6 >= 0.5ms
+ */
+ fsleep(500);
+ reset_control_assert(ntp8918->reset);
+
+ regcache_mark_dirty(component->regmap);
+ clk_disable_unprepare(ntp8918->bck);
+
+ return 0;
+}
+
+static int ntp8918_snd_resume(struct snd_soc_component *component)
+{
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = clk_prepare_enable(ntp8918->bck);
+ if (ret)
+ return ret;
+
+ ntp8918_reset_gpio(ntp8918);
+
+ regmap_multi_reg_write_bypassed(component->regmap,
+ ntp8918_sound_on,
+ ARRAY_SIZE(ntp8918_sound_on));
+
+ ret = ntp8918_load_firmware(ntp8918);
+ if (ret) {
+ dev_err(&ntp8918->i2c->dev, "Failed to load firmware\n");
+ return ret;
+ }
+
+ regcache_cache_only(component->regmap, false);
+ snd_soc_component_cache_sync(component);
+
+ return 0;
+}
+
+static int ntp8918_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+
+ ret = snd_soc_add_component_controls(component, ntp8918_vol_control,
+ ARRAY_SIZE(ntp8918_vol_control));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add controls\n");
+
+ ret = ntp8918_load_firmware(ntp8918);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to load firmware\n");
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget ntp8918_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("OUT1"),
+ SND_SOC_DAPM_OUTPUT("OUT2"),
+};
+
+static const struct snd_soc_dapm_route ntp8918_dapm_routes[] = {
+ { "OUT1", NULL, "AIFIN" },
+ { "OUT2", NULL, "AIFIN" },
+};
+
+static const struct snd_soc_component_driver soc_component_ntp8918 = {
+ .probe = ntp8918_probe,
+ .suspend = ntp8918_snd_suspend,
+ .resume = ntp8918_snd_resume,
+ .dapm_widgets = ntp8918_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ntp8918_dapm_widgets),
+ .dapm_routes = ntp8918_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ntp8918_dapm_routes),
+};
+
+static int ntp8918_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+ unsigned int input_fmt = 0;
+ unsigned int gsa_fmt = 0;
+ unsigned int gsa_fmt_mask;
+ unsigned int mcf;
+ int bclk;
+ int ret;
+
+ bclk = snd_soc_params_to_bclk(params);
+ switch (bclk) {
+ case 3072000:
+ case 2822400:
+ mcf = 0;
+ break;
+ case 6144000:
+ mcf = 1;
+ break;
+ case 2048000:
+ mcf = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8918_MCLK_FREQ_CTRL,
+ NTP8918_MCLK_FREQ_MCF, mcf);
+ if (ret)
+ return ret;
+
+ switch (ntp8918->format) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ input_fmt |= NTP8918_INPUT_FMT_GSA_MODE;
+ gsa_fmt |= NTP8918_GSA_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ input_fmt |= NTP8918_INPUT_FMT_GSA_MODE;
+ break;
+ }
+
+ ret = snd_soc_component_update_bits(component, NTP8918_INPUT_FMT,
+ NTP8918_INPUT_FMT_MASTER_MODE |
+ NTP8918_INPUT_FMT_GSA_MODE,
+ input_fmt);
+
+ if (!(input_fmt & NTP8918_INPUT_FMT_GSA_MODE) || ret < 0)
+ return ret;
+
+ switch (params_width(params)) {
+ case 24:
+ gsa_fmt |= NTP8918_GSA_BS(0);
+ break;
+ case 20:
+ gsa_fmt |= NTP8918_GSA_BS(1);
+ break;
+ case 18:
+ gsa_fmt |= NTP8918_GSA_BS(2);
+ break;
+ case 16:
+ gsa_fmt |= NTP8918_GSA_BS(3);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ gsa_fmt_mask = NTP8918_GSA_BS_MASK |
+ NTP8918_GSA_RIGHT_J |
+ NTP8918_GSA_LSB;
+ return snd_soc_component_update_bits(component, NTP8918_GSA_FMT,
+ gsa_fmt_mask, gsa_fmt);
+}
+
+static int ntp8918_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ ntp8918->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ntp8918_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ unsigned int mute_mask = NTP8918_SOFT_MUTE_SM1 |
+ NTP8918_SOFT_MUTE_SM2;
+
+ return snd_soc_component_update_bits(dai->component, NTP8918_SOFT_MUTE,
+ mute_mask, mute ? mute_mask : 0);
+}
+
+static const struct snd_soc_dai_ops ntp8918_dai_ops = {
+ .hw_params = ntp8918_hw_params,
+ .set_fmt = ntp8918_set_fmt,
+ .mute_stream = ntp8918_digital_mute,
+};
+
+static struct snd_soc_dai_driver ntp8918_dai = {
+ .name = "ntp8918-amplifier",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = NTP8918_RATES,
+ .formats = NTP8918_FORMATS,
+ },
+ .ops = &ntp8918_dai_ops,
+};
+
+static const struct regmap_config ntp8918_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int ntp8918_i2c_probe(struct i2c_client *i2c)
+{
+ struct ntp8918_priv *ntp8918;
+ int ret;
+ struct regmap *regmap;
+
+ ntp8918 = devm_kzalloc(&i2c->dev, sizeof(*ntp8918), GFP_KERNEL);
+ if (!ntp8918)
+ return -ENOMEM;
+
+ ntp8918->i2c = i2c;
+
+ ntp8918->reset = devm_reset_control_get_shared(&i2c->dev, NULL);
+ if (IS_ERR(ntp8918->reset))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->reset), "Failed to get reset\n");
+
+ dev_set_drvdata(&i2c->dev, ntp8918);
+
+ ntp8918_reset_gpio(ntp8918);
+
+ regmap = devm_regmap_init_i2c(i2c, &ntp8918_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+ "Failed to allocate regmap\n");
+
+ ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8918,
+ &ntp8918_dai, 1);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to register component\n");
+
+ ntp8918->bck = devm_clk_get_enabled(&i2c->dev, "bck");
+ if (IS_ERR(ntp8918->bck))
+ return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->bck), "failed to get bck clock\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id ntp8918_i2c_id[] = {
+ { "ntp8918" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ntp8918_i2c_id);
+
+static const struct of_device_id ntp8918_of_match[] = {
+ {.compatible = "neofidelity,ntp8918"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, ntp8918_of_match);
+
+static struct i2c_driver ntp8918_i2c_driver = {
+ .probe = ntp8918_i2c_probe,
+ .id_table = ntp8918_i2c_id,
+ .driver = {
+ .name = "ntp8918",
+ .of_match_table = ntp8918_of_match,
+ },
+};
+module_i2c_driver(ntp8918_i2c_driver);
+
+MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>");
+MODULE_DESCRIPTION("NTP8918 Audio Amplifier Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c
new file mode 100644
index 000000000000..5ced2e966ab7
--- /dev/null
+++ b/sound/soc/codecs/ntpfw.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ntpfw.c - Firmware helper functions for Neofidelity codecs
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ */
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "ntpfw.h"
+
+struct ntpfw_chunk {
+ __be16 length;
+ u8 step;
+ u8 data[];
+} __packed;
+
+struct ntpfw_header {
+ __be32 magic;
+} __packed;
+
+static bool ntpfw_verify(struct device *dev, const u8 *buf, size_t buf_size, u32 magic)
+{
+ const struct ntpfw_header *header = (struct ntpfw_header *)buf;
+ u32 buf_magic;
+
+ if (buf_size <= sizeof(*header)) {
+ dev_err(dev, "Failed to load firmware: image too small\n");
+ return false;
+ }
+
+ buf_magic = be32_to_cpu(header->magic);
+ if (buf_magic != magic) {
+ dev_err(dev, "Failed to load firmware: invalid magic 0x%x:\n", buf_magic);
+ return false;
+ }
+
+ return true;
+}
+
+static bool ntpfw_verify_chunk(struct device *dev, const struct ntpfw_chunk *chunk, size_t buf_size)
+{
+ size_t chunk_size;
+
+ if (buf_size <= sizeof(*chunk)) {
+ dev_err(dev, "Failed to load firmware: chunk size too big\n");
+ return false;
+ }
+
+ if (chunk->step != 2 && chunk->step != 5) {
+ dev_err(dev, "Failed to load firmware: invalid chunk step: %d\n", chunk->step);
+ return false;
+ }
+
+ chunk_size = be16_to_cpu(chunk->length);
+ if (chunk_size > buf_size) {
+ dev_err(dev, "Failed to load firmware: invalid chunk length\n");
+ return false;
+ }
+
+ if (chunk_size % chunk->step) {
+ dev_err(dev, "Failed to load firmware: chunk length and step mismatch\n");
+ return false;
+ }
+
+ return true;
+}
+
+static int ntpfw_send_chunk(struct i2c_client *i2c, const struct ntpfw_chunk *chunk)
+{
+ int ret;
+ size_t i;
+ size_t length = be16_to_cpu(chunk->length);
+
+ for (i = 0; i < length; i += chunk->step) {
+ ret = i2c_master_send(i2c, &chunk->data[i], chunk->step);
+ if (ret != chunk->step) {
+ dev_err(&i2c->dev, "I2C send failed: %d\n", ret);
+ return ret < 0 ? ret : -EIO;
+ }
+ }
+
+ return 0;
+}
+
+int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
+{
+ struct device *dev = &i2c->dev;
+ const struct ntpfw_chunk *chunk;
+ const struct firmware *fw;
+ const u8 *data;
+ size_t leftover;
+ int ret;
+
+ ret = request_firmware(&fw, name, dev);
+ if (ret) {
+ dev_warn(dev, "request_firmware '%s' failed with %d\n",
+ name, ret);
+ return ret;
+ }
+
+ if (!ntpfw_verify(dev, fw->data, fw->size, magic)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ data = fw->data + sizeof(struct ntpfw_header);
+ leftover = fw->size - sizeof(struct ntpfw_header);
+
+ while (leftover) {
+ chunk = (struct ntpfw_chunk *)data;
+
+ if (!ntpfw_verify_chunk(dev, chunk, leftover)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = ntpfw_send_chunk(i2c, chunk);
+ if (ret)
+ goto done;
+
+ data += be16_to_cpu(chunk->length) + sizeof(*chunk);
+ leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk);
+ }
+
+done:
+ release_firmware(fw);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ntpfw_load);
+
+MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>");
+MODULE_DESCRIPTION("Helper for loading Neofidelity amplifiers firmware");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h
new file mode 100644
index 000000000000..1cf10d5480ee
--- /dev/null
+++ b/sound/soc/codecs/ntpfw.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/**
+ * ntpfw.h - Firmware helper functions for Neofidelity codecs
+ *
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ */
+
+#ifndef __NTPFW_H__
+#define __NTPFW_H__
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+
+/**
+ * ntpfw_load - load firmware to amplifier over i2c interface.
+ *
+ * @i2c Pointer to amplifier's I2C client.
+ * @name Firmware file name.
+ * @magic Magic number to validate firmware.
+ * @return 0 or error code upon error.
+ */
+int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic);
+
+#endif /* __NTPFW_H__ */
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 735e1942b530..f4e5f3133f2b 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -9,12 +9,9 @@
#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>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -111,7 +108,7 @@ static int pcm1681_set_deemph(struct snd_soc_component *component)
static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = priv->deemph;
@@ -122,7 +119,7 @@ static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
priv->deemph = ucontrol->value.integer.value[0];
@@ -293,7 +290,7 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1681 = {
};
static const struct i2c_device_id pcm1681_i2c_id[] = {
- {"pcm1681", 0},
+ {"pcm1681"},
{}
};
MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id);
diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c
new file mode 100644
index 000000000000..b68a528000be
--- /dev/null
+++ b/sound/soc/codecs/pcm1754.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PCM1754 DAC ASoC codec driver
+ *
+ * Copyright (c) 2022 Alvin Šipraga <alsi@bang-olufsen.dk>
+ * Copyright (c) 2025 Stefan Kerkmann <s.kerkmann@pengutronix.de>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+struct pcm1754_priv {
+ unsigned int format;
+ struct gpio_desc *gpiod_mute;
+ struct gpio_desc *gpiod_format;
+};
+
+static int pcm1754_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct pcm1754_priv *priv = snd_soc_component_get_drvdata(component);
+
+ priv->format = format;
+
+ return 0;
+}
+
+static int pcm1754_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct pcm1754_priv *priv = snd_soc_component_get_drvdata(component);
+ int format;
+
+ switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 16:
+ format = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ switch (params_width(params)) {
+ case 16:
+ fallthrough;
+ case 24:
+ format = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(component->dev, "Invalid DAI format\n");
+ return -EINVAL;
+ }
+
+ gpiod_set_value_cansleep(priv->gpiod_format, format);
+
+ return 0;
+}
+
+static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct pcm1754_priv *priv = snd_soc_component_get_drvdata(dai->component);
+
+ gpiod_set_value_cansleep(priv->gpiod_mute, mute);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops pcm1754_dai_ops = {
+ .set_fmt = pcm1754_set_dai_fmt,
+ .hw_params = pcm1754_hw_params,
+ .mute_stream = pcm1754_mute_stream,
+};
+
+static const struct snd_soc_dai_driver pcm1754_dai = {
+ .name = "pcm1754",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5000,
+ .rate_max = 200000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE
+ },
+ .ops = &pcm1754_dai_ops,
+};
+
+static const struct snd_soc_dapm_widget pcm1754_dapm_widgets[] = {
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 0, 0),
+
+ SND_SOC_DAPM_DAC("DAC1", "Channel 1 Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC2", "Channel 2 Playback", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("VOUTL"),
+ SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm1754_dapm_routes[] = {
+ { "DAC1", NULL, "Playback" },
+ { "DAC2", NULL, "Playback" },
+
+ { "DAC1", NULL, "VCC" },
+ { "DAC2", NULL, "VCC" },
+
+ { "VOUTL", NULL, "DAC1" },
+ { "VOUTR", NULL, "DAC2" },
+};
+
+static const struct snd_soc_component_driver soc_component_dev_pcm1754 = {
+ .dapm_widgets = pcm1754_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm1754_dapm_widgets),
+ .dapm_routes = pcm1754_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm1754_dapm_routes),
+};
+
+static int pcm1754_probe(struct platform_device *pdev)
+{
+ struct pcm1754_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_dai_driver *dai_drv;
+ int ret;
+
+ dai_drv = devm_kmemdup(dev, &pcm1754_dai, sizeof(*dai_drv), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->gpiod_mute = devm_gpiod_get_optional(dev, "mute", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_mute))
+ return dev_err_probe(dev, PTR_ERR(priv->gpiod_mute),
+ "failed to get mute gpio");
+
+ priv->gpiod_format = devm_gpiod_get_optional(dev, "format", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_format))
+ return dev_err_probe(dev, PTR_ERR(priv->gpiod_format),
+ "failed to get format gpio");
+
+ dev_set_drvdata(dev, priv);
+
+ ret = devm_snd_soc_register_component(
+ &pdev->dev, &soc_component_dev_pcm1754, dai_drv, 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register");
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm1754_of_match[] = {
+ { .compatible = "ti,pcm1754" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm1754_of_match);
+#endif
+
+static struct platform_driver pcm1754_codec_driver = {
+ .driver = {
+ .name = "pcm1754-codec",
+ .of_match_table = of_match_ptr(pcm1754_of_match),
+ },
+ .probe = pcm1754_probe,
+};
+
+module_platform_driver(pcm1754_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM1754 driver");
+MODULE_AUTHOR("Alvin Šipraga <alsi@bang-olufsen.dk>");
+MODULE_AUTHOR("Stefan Kerkmann <s.kerkmann@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c
index f2d0b4d21e41..abadf4f8ed5e 100644
--- a/sound/soc/codecs/pcm1789-i2c.c
+++ b/sound/soc/codecs/pcm1789-i2c.c
@@ -41,7 +41,7 @@ MODULE_DEVICE_TABLE(of, pcm1789_of_match);
#endif
static const struct i2c_device_id pcm1789_i2c_ids[] = {
- { "pcm1789", 0 },
+ { "pcm1789" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcm1789_i2c_ids);
diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c
index 10579681f44b..effc1dd6df22 100644
--- a/sound/soc/codecs/pcm179x-i2c.c
+++ b/sound/soc/codecs/pcm179x-i2c.c
@@ -38,7 +38,7 @@ MODULE_DEVICE_TABLE(of, pcm179x_of_match);
#endif
static const struct i2c_device_id pcm179x_i2c_ids[] = {
- { "pcm179x", 0 },
+ { "pcm179x" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcm179x_i2c_ids);
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/pcm186x.c b/sound/soc/codecs/pcm186x.c
index 451a8fd8fac5..0d1103fe4e04 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -546,8 +546,10 @@ static int pcm186x_power_off(struct snd_soc_component *component)
static int pcm186x_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
- snd_soc_component_get_bias_level(component), level);
+ snd_soc_dapm_get_bias_level(dapm), level);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -555,7 +557,7 @@ static int pcm186x_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
pcm186x_power_on(component);
break;
case SND_SOC_BIAS_OFF:
@@ -566,7 +568,7 @@ static int pcm186x_set_bias_level(struct snd_soc_component *component,
return 0;
}
-static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
+static const struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
.set_bias_level = pcm186x_set_bias_level,
.controls = pcm1863_snd_controls,
.num_controls = ARRAY_SIZE(pcm1863_snd_controls),
@@ -579,7 +581,7 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
.endianness = 1,
};
-static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
+static const struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
.set_bias_level = pcm186x_set_bias_level,
.controls = pcm1865_snd_controls,
.num_controls = ARRAY_SIZE(pcm1865_snd_controls),
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/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c
index 5330cf46b127..3816b25a8ead 100644
--- a/sound/soc/codecs/pcm3060-i2c.c
+++ b/sound/soc/codecs/pcm3060-i2c.c
@@ -2,7 +2,7 @@
//
// PCM3060 I2C driver
//
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+// Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
#include <linux/i2c.h>
#include <linux/module.h>
@@ -55,5 +55,5 @@ static struct i2c_driver pcm3060_i2c_driver = {
module_i2c_driver(pcm3060_i2c_driver);
MODULE_DESCRIPTION("PCM3060 I2C driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
+MODULE_AUTHOR("Kirill Marinushkin <k.marinushkin@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c
index 3b79734b832b..6095841f2f56 100644
--- a/sound/soc/codecs/pcm3060-spi.c
+++ b/sound/soc/codecs/pcm3060-spi.c
@@ -2,7 +2,7 @@
//
// PCM3060 SPI driver
//
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+// Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
#include <linux/module.h>
#include <linux/spi/spi.h>
@@ -55,5 +55,5 @@ static struct spi_driver pcm3060_spi_driver = {
module_spi_driver(pcm3060_spi_driver);
MODULE_DESCRIPTION("PCM3060 SPI driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
+MODULE_AUTHOR("Kirill Marinushkin <k.marinushkin@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 586ec8c7246c..8974200652e7 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -2,7 +2,7 @@
//
// PCM3060 codec driver
//
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+// Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
#include <linux/module.h>
#include <sound/pcm_params.h>
@@ -343,5 +343,5 @@ int pcm3060_probe(struct device *dev)
EXPORT_SYMBOL(pcm3060_probe);
MODULE_DESCRIPTION("PCM3060 codec driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
+MODULE_AUTHOR("Kirill Marinushkin <k.marinushkin@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h
index 5e1185e7b03d..1b96835600b4 100644
--- a/sound/soc/codecs/pcm3060.h
+++ b/sound/soc/codecs/pcm3060.h
@@ -2,7 +2,7 @@
/*
* PCM3060 codec driver
*
- * Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+ * Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
*/
#ifndef _SND_SOC_PCM3060_H
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 9d6431338fb7..c8617a488b11 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -11,7 +11,6 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -494,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;
@@ -563,7 +562,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static u64 pcm3168a_dai_formats[] = {
+static const u64 pcm3168a_dai_formats[] = {
/*
* Select below from Sound Card, not here
* SND_SOC_DAIFMT_CBC_CFC
@@ -744,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");
@@ -756,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];
@@ -847,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);
@@ -903,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/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
index 3401a25341e6..9bca53de2475 100644
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -24,7 +24,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = {
},
};
-static struct snd_soc_component_driver soc_component_dev_pcm5102a = {
+static const struct snd_soc_component_driver soc_component_dev_pcm5102a = {
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 5cd2b64b9337..a1d849b0c50f 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -39,6 +39,9 @@ static const struct i2c_device_id pcm512x_i2c_id[] = {
{ "pcm5122", },
{ "pcm5141", },
{ "pcm5142", },
+ { "pcm5242", },
+ { "tas5754", },
+ { "tas5756", },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
@@ -49,6 +52,9 @@ static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5122", },
{ .compatible = "ti,pcm5141", },
{ .compatible = "ti,pcm5142", },
+ { .compatible = "ti,pcm5242", },
+ { .compatible = "ti,tas5754", },
+ { .compatible = "ti,tas5756", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
@@ -73,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 4d29e7196380..92f7f78a4e20 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -36,6 +36,7 @@ static const struct spi_device_id pcm512x_spi_id[] = {
{ "pcm5122", },
{ "pcm5141", },
{ "pcm5142", },
+ { "pcm5242", },
{ },
};
MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
@@ -45,6 +46,7 @@ static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5122", },
{ .compatible = "ti,pcm5141", },
{ .compatible = "ti,pcm5142", },
+ { .compatible = "ti,pcm5242", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
@@ -56,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 89059a673cf0..a70e8ea166dc 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -48,6 +48,7 @@ struct pcm512x_priv {
int mute;
struct mutex mutex;
unsigned int bclk_ratio;
+ int force_pll_on;
};
/*
@@ -223,7 +224,7 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
@@ -233,10 +234,11 @@ static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_OFF:
case SND_SOC_BIAS_STANDBY:
break;
@@ -251,7 +253,7 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
@@ -261,10 +263,11 @@ static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_OFF:
case SND_SOC_BIAS_STANDBY:
break;
@@ -279,7 +282,7 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
@@ -289,10 +292,11 @@ static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_OFF:
case SND_SOC_BIAS_STANDBY:
break;
@@ -392,7 +396,7 @@ static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
mutex_lock(&pcm512x->mutex);
@@ -406,7 +410,7 @@ static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret, changed = 0;
@@ -1258,10 +1262,34 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
- PCM512x_PLLE, 0);
+ if (!pcm512x->force_pll_on) {
+ ret = regmap_update_bits(pcm512x->regmap,
+ PCM512x_PLL_EN, PCM512x_PLLE, 0);
+ } else {
+ /* provide minimum PLL config for TAS575x clocking
+ * and leave PLL enabled
+ */
+ ret = regmap_write(pcm512x->regmap,
+ PCM512x_PLL_COEFF_0, 0x01);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set pll coefficient: %d\n", ret);
+ return ret;
+ }
+ ret = regmap_write(pcm512x->regmap,
+ PCM512x_PLL_COEFF_1, 0x04);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set pll coefficient: %d\n", ret);
+ return ret;
+ }
+ ret = regmap_write(pcm512x->regmap,
+ PCM512x_PLL_EN, 0x01);
+ dev_dbg(component->dev, "Enabling PLL for TAS575x\n");
+ }
+
if (ret != 0) {
- dev_err(component->dev, "Failed to disable pll: %d\n", ret);
+ dev_err(component->dev, "Failed to set pll mode: %d\n", ret);
return ret;
}
}
@@ -1659,6 +1687,11 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
ret = -EINVAL;
goto err_pm;
}
+
+ if (!strcmp(np->name, "tas5756") ||
+ !strcmp(np->name, "tas5754"))
+ pcm512x->force_pll_on = 1;
+ dev_dbg(dev, "Device ID: %s\n", np->name);
}
#endif
@@ -1695,7 +1728,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);
@@ -1757,12 +1789,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
new file mode 100644
index 000000000000..bde190a659b1
--- /dev/null
+++ b/sound/soc/codecs/pcm6240.c
@@ -0,0 +1,2167 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC Texas Instruments PCM6240 Family Audio ADC/DAC Device
+//
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The PCM6240 driver implements a flexible and configurable
+// algo coefficient setting for one, two, or even multiple
+// PCM6240 Family chips.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+//
+
+#include <linux/unaligned.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm6240.h"
+
+static const struct i2c_device_id pcmdevice_i2c_id[] = {
+ { "adc3120", ADC3120 },
+ { "adc5120", ADC5120 },
+ { "adc6120", ADC6120 },
+ { "dix4192", DIX4192 },
+ { "pcm1690", PCM1690 },
+ { "pcm3120", PCM3120 },
+ { "pcm3140", PCM3140 },
+ { "pcm5120", PCM5120 },
+ { "pcm5140", PCM5140 },
+ { "pcm6120", PCM6120 },
+ { "pcm6140", PCM6140 },
+ { "pcm6240", PCM6240 },
+ { "pcm6260", PCM6260 },
+ { "pcm9211", PCM9211 },
+ { "pcmd3140", PCMD3140 },
+ { "pcmd3180", PCMD3180 },
+ { "pcmd512x", PCMD512X },
+ { "taa5212", TAA5212 },
+ { "taa5412", TAA5412 },
+ { "tad5212", TAD5212 },
+ { "tad5412", TAD5412 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pcmdevice_i2c_id);
+
+static const char *const pcmdev_ctrl_name[] = {
+ "%s i2c%d Dev%d Ch%d Ana Volume",
+ "%s i2c%d Dev%d Ch%d Digi Volume",
+ "%s i2c%d Dev%d Ch%d Fine Volume",
+};
+
+static const struct pcmdevice_mixer_control adc5120_analog_gain_ctl[] = {
+ {
+ .shift = 1,
+ .reg = ADC5120_REG_CH1_ANALOG_GAIN,
+ .max = 0x54,
+ .invert = 0,
+ },
+ {
+ .shift = 1,
+ .reg = ADC5120_REG_CH2_ANALOG_GAIN,
+ .max = 0x54,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control adc5120_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = ADC5120_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = ADC5120_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm1690_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH5_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH6_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH7_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH8_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6240_analog_gain_ctl[] = {
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH1_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH2_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH3_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH4_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6240_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6260_analog_gain_ctl[] = {
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH1_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH2_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH3_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH4_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH5_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH6_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6260_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH5_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH6_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm9211_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM9211_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM9211_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcmd3140_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcmd3140_fine_gain_ctl[] = {
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH1_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH2_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH3_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH4_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcmd3180_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH5_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH6_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH7_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH8_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcmd3180_fine_gain_ctl[] = {
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH1_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH2_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH3_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH4_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH5_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH6_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH7_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH8_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control taa5412_digi_vol_ctl[] = {
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH1_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH2_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH3_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH4_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control taa5412_fine_gain_ctl[] = {
+ {
+ .shift = 4,
+ .reg = TAA5412_REG_CH1_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = TAA5412_REG_CH2_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = TAA5412_REG_CH3_FINE_GAIN,
+ .max = 0xf,
+ .invert = 4,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH4_FINE_GAIN,
+ .max = 0xf,
+ .invert = 4,
+ }
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcmd3140_dig_gain_tlv,
+ -10000, 2700);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm1690_fine_dig_gain_tlv,
+ -12750, 0);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm1690_dig_gain_tlv,
+ -25500, 0);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm9211_dig_gain_tlv,
+ -11450, 2000);
+static const DECLARE_TLV_DB_MINMAX_MUTE(adc5120_fgain_tlv,
+ -10050, 2700);
+static const DECLARE_TLV_DB_LINEAR(adc5120_chgain_tlv, 0, 4200);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm6260_fgain_tlv,
+ -10000, 2700);
+static const DECLARE_TLV_DB_LINEAR(pcm6260_chgain_tlv, 0, 4200);
+static const DECLARE_TLV_DB_MINMAX_MUTE(taa5412_dig_vol_tlv,
+ -8050, 4700);
+static const DECLARE_TLV_DB_LINEAR(taa5412_fine_gain_tlv,
+ -80, 70);
+
+static int pcmdev_change_dev(struct pcmdevice_priv *pcm_priv,
+ unsigned short dev_no)
+{
+ struct i2c_client *client = (struct i2c_client *)pcm_priv->client;
+ struct regmap *map = pcm_priv->regmap;
+ int ret;
+
+ if (client->addr == pcm_priv->addr[dev_no])
+ return 0;
+
+ client->addr = pcm_priv->addr[dev_no];
+ /* All pcmdevices share the same regmap, clear the page
+ * inside regmap once switching to another pcmdevice.
+ * Register 0 at any pages inside pcmdevice is the same
+ * one for page-switching.
+ */
+ ret = regmap_write(map, PCMDEVICE_PAGE_SELECT, 0);
+ if (ret < 0)
+ dev_err(pcm_priv->dev, "%s: err = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int pcmdev_dev_read(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned int *val)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_read(map, reg, val);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: err = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int pcmdev_dev_update_bits(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned int mask,
+ unsigned int value)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(map, reg, mask, value);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: update_bits err=%d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, int vol_ctrl_type)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(component);
+ struct pcmdevice_mixer_control *mc =
+ (struct pcmdevice_mixer_control *)kcontrol->private_value;
+ int max = mc->max, ret;
+ unsigned int mask = BIT(fls(max)) - 1;
+ unsigned int dev_no = mc->dev_no;
+ unsigned int shift = mc->shift;
+ unsigned int reg = mc->reg;
+ unsigned int val;
+
+ mutex_lock(&pcm_dev->codec_lock);
+
+ if (pcm_dev->chip_id == PCM1690) {
+ ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL,
+ &val);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: read mode err=%d\n",
+ __func__, ret);
+ goto out;
+ }
+ val &= PCM1690_REG_MODE_CTRL_DAMS_MSK;
+ /* Set to wide-range mode, before using vol ctrl. */
+ if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) {
+ ucontrol->value.integer.value[0] = -25500;
+ goto out;
+ }
+ /* Set to fine mode, before using fine vol ctrl. */
+ if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) {
+ ucontrol->value.integer.value[0] = -12750;
+ goto out;
+ }
+ }
+
+ ret = pcmdev_dev_read(pcm_dev, dev_no, reg, &val);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: read err=%d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ val = (val >> shift) & mask;
+ val = (val > max) ? max : val;
+ val = mc->invert ? max - val : val;
+ ucontrol->value.integer.value[0] = val;
+out:
+ mutex_unlock(&pcm_dev->codec_lock);
+ return ret;
+}
+
+static int pcmdevice_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_get_volsw(kcontrol, ucontrol, PCMDEV_GENERIC_VOL_CTRL);
+}
+
+static int pcm1690_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_get_volsw(kcontrol, ucontrol, PCMDEV_PCM1690_VOL_CTRL);
+}
+
+static int pcm1690_get_finevolsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_get_volsw(kcontrol, ucontrol,
+ PCMDEV_PCM1690_FINE_VOL_CTRL);
+}
+
+static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, int vol_ctrl_type)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(component);
+ struct pcmdevice_mixer_control *mc =
+ (struct pcmdevice_mixer_control *)kcontrol->private_value;
+ int max = mc->max, rc;
+ unsigned int mask = BIT(fls(max)) - 1;
+ unsigned int dev_no = mc->dev_no;
+ unsigned int shift = mc->shift;
+ unsigned int val, val_mask;
+ unsigned int reg = mc->reg;
+
+ mutex_lock(&pcm_dev->codec_lock);
+ val = ucontrol->value.integer.value[0] & mask;
+ val = (val > max) ? max : val;
+ val = mc->invert ? max - val : val;
+ val_mask = mask << shift;
+ val = val << shift;
+
+ switch (vol_ctrl_type) {
+ case PCMDEV_PCM1690_VOL_CTRL:
+ val_mask |= PCM1690_REG_MODE_CTRL_DAMS_MSK;
+ val |= PCM1690_REG_MODE_CTRL_DAMS_WIDE_RANGE;
+ break;
+ case PCMDEV_PCM1690_FINE_VOL_CTRL:
+ val_mask |= PCM1690_REG_MODE_CTRL_DAMS_MSK;
+ val |= PCM1690_REG_MODE_CTRL_DAMS_FINE_STEP;
+ break;
+ }
+
+ rc = pcmdev_dev_update_bits(pcm_dev, dev_no, reg, val_mask, val);
+ if (rc < 0)
+ dev_err(pcm_dev->dev, "%s: update_bits err = %d\n",
+ __func__, rc);
+ else
+ rc = 1;
+ mutex_unlock(&pcm_dev->codec_lock);
+ return rc;
+}
+
+static int pcmdevice_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_put_volsw(kcontrol, ucontrol, PCMDEV_GENERIC_VOL_CTRL);
+}
+
+static int pcm1690_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_put_volsw(kcontrol, ucontrol, PCMDEV_PCM1690_VOL_CTRL);
+}
+
+static int pcm1690_put_finevolsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_put_volsw(kcontrol, ucontrol,
+ PCMDEV_PCM1690_FINE_VOL_CTRL);
+}
+
+static const struct pcmdev_ctrl_info pcmdev_gain_ctl_info[][2] = {
+ // ADC3120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // ADC5120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // ADC6120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // DIX4192
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+ // PCM1690
+ {
+ {
+ .gain = pcm1690_fine_dig_gain_tlv,
+ .pcmdev_ctrl = pcm1690_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm1690_digi_gain_ctl),
+ .get = pcm1690_get_volsw,
+ .put = pcm1690_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ {
+ .gain = pcm1690_dig_gain_tlv,
+ .pcmdev_ctrl = pcm1690_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm1690_digi_gain_ctl),
+ .get = pcm1690_get_finevolsw,
+ .put = pcm1690_put_finevolsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ },
+ // PCM3120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM3140
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM5120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM5140
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6140
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6240
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6260
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6260_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6260_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6260_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6260_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM9211
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .gain = pcm9211_dig_gain_tlv,
+ .pcmdev_ctrl = pcm9211_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm9211_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+
+ },
+ // PCMD3140
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = pcmd3140_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3140_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .gain = pcmd3140_dig_gain_tlv,
+ .pcmdev_ctrl = pcmd3140_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3140_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCMD3180
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = pcmd3180_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3180_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .gain = pcmd3140_dig_gain_tlv,
+ .pcmdev_ctrl = pcmd3180_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3180_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCMD512X
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+ // TAA5212
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = taa5412_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .gain = taa5412_dig_vol_tlv,
+ .pcmdev_ctrl = taa5412_digi_vol_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_digi_vol_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // TAA5412
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = taa5412_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .gain = taa5412_dig_vol_tlv,
+ .pcmdev_ctrl = taa5412_digi_vol_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_digi_vol_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // TAD5212
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+ // TAD5412
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+};
+
+static int pcmdev_dev_bulk_write(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_bulk_write(map, reg, data, len);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: bulk_write err = %d\n", __func__,
+ ret);
+
+ return ret;
+}
+
+static int pcmdev_dev_write(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned int value)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_write(map, reg, value);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: err = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int pcmdevice_info_profile(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(codec);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max(0, pcm_dev->regbin.ncfgs - 1);
+
+ return 0;
+}
+
+static int pcmdevice_get_profile_id(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = pcm_dev->cur_conf;
+
+ return 0;
+}
+
+static int pcmdevice_set_profile_id(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(codec);
+ int nr_profile = ucontrol->value.integer.value[0];
+ int max = pcm_dev->regbin.ncfgs - 1;
+ int ret = 0;
+
+ nr_profile = clamp(nr_profile, 0, max);
+
+ if (pcm_dev->cur_conf != nr_profile) {
+ pcm_dev->cur_conf = nr_profile;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int pcmdevice_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct pcmdevice_mixer_control *mc =
+ (struct pcmdevice_mixer_control *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mc->max;
+ return 0;
+}
+
+static void pcm9211_sw_rst(struct pcmdevice_priv *pcm_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < pcm_dev->ndev; i++) {
+ ret = pcmdev_dev_update_bits(pcm_dev, i,
+ PCM9211_REG_SW_CTRL, PCM9211_REG_SW_CTRL_MRST_MSK,
+ PCM9211_REG_SW_CTRL_MRST);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev %d swreset fail %d\n",
+ __func__, i, ret);
+ }
+}
+
+static void pcmdevice_sw_rst(struct pcmdevice_priv *pcm_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < pcm_dev->ndev; i++) {
+ ret = pcmdev_dev_write(pcm_dev, i, PCMDEVICE_REG_SWRESET,
+ PCMDEVICE_REG_SWRESET_RESET);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev %d swreset fail %d\n",
+ __func__, i, ret);
+ }
+}
+
+static struct pcmdevice_config_info *pcmdevice_add_config(void *ctxt,
+ const unsigned char *config_data, unsigned int config_size,
+ int *status)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *)ctxt;
+ struct pcmdevice_config_info *cfg_info;
+ struct pcmdevice_block_data **bk_da;
+ unsigned int config_offset = 0, i;
+
+ cfg_info = kzalloc(sizeof(struct pcmdevice_config_info), GFP_KERNEL);
+ if (!cfg_info) {
+ *status = -ENOMEM;
+ goto out;
+ }
+
+ if (pcm_dev->regbin.fw_hdr.binary_version_num >= 0x105) {
+ if (config_offset + 64 > (int)config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev,
+ "%s: cfg_name out of boundary\n", __func__);
+ goto out;
+ }
+ memcpy(cfg_info->cfg_name, &config_data[config_offset], 64);
+ config_offset += 64;
+ }
+
+ if (config_offset + 4 > config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev, "%s: nblocks out of boundary\n",
+ __func__);
+ goto out;
+ }
+ cfg_info->nblocks =
+ get_unaligned_be32(&config_data[config_offset]);
+ config_offset += 4;
+
+ bk_da = cfg_info->blk_data = kcalloc(cfg_info->nblocks,
+ sizeof(struct pcmdevice_block_data *), GFP_KERNEL);
+ if (!bk_da) {
+ *status = -ENOMEM;
+ goto out;
+ }
+ cfg_info->real_nblocks = 0;
+ for (i = 0; i < cfg_info->nblocks; i++) {
+ if (config_offset + 12 > config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev,
+ "%s: out of boundary i = %d nblocks = %u\n",
+ __func__, i, cfg_info->nblocks);
+ break;
+ }
+ bk_da[i] = kzalloc(sizeof(struct pcmdevice_block_data),
+ GFP_KERNEL);
+ if (!bk_da[i]) {
+ *status = -ENOMEM;
+ break;
+ }
+ bk_da[i]->dev_idx = config_data[config_offset];
+ config_offset++;
+
+ bk_da[i]->block_type = config_data[config_offset];
+ config_offset++;
+
+ if (bk_da[i]->block_type == PCMDEVICE_BIN_BLK_PRE_POWER_UP) {
+ if (bk_da[i]->dev_idx == 0)
+ cfg_info->active_dev =
+ (1 << pcm_dev->ndev) - 1;
+ else
+ cfg_info->active_dev =
+ 1 << (bk_da[i]->dev_idx - 1);
+ }
+
+ 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(pcm_dev->dev,
+ "%s: out of boundary: i = %d blks = %u\n",
+ __func__, i, cfg_info->nblocks);
+ break;
+ }
+
+ bk_da[i]->regdata = kmemdup(&config_data[config_offset],
+ bk_da[i]->block_size, GFP_KERNEL);
+ if (!bk_da[i]->regdata) {
+ *status = -ENOMEM;
+ goto out;
+ }
+ config_offset += bk_da[i]->block_size;
+ cfg_info->real_nblocks += 1;
+ }
+out:
+ return cfg_info;
+}
+
+static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev,
+ int dev_no, int ctl_id)
+{
+ struct i2c_adapter *adap = pcm_dev->client->adapter;
+ struct snd_soc_component *comp = pcm_dev->component;
+ struct pcmdevice_mixer_control *pcmdev_ctrl;
+ struct snd_kcontrol_new *pcmdev_controls;
+ int ret, mix_index = 0, name_id, chn;
+ unsigned int id = pcm_dev->chip_id;
+ const int nr_chn =
+ pcmdev_gain_ctl_info[id][ctl_id].ctrl_array_size;
+ const char *ctrl_name;
+ char *name;
+
+ if (!nr_chn) {
+ dev_dbg(pcm_dev->dev, "%s: no gain ctrl for %s\n", __func__,
+ pcm_dev->dev_name);
+ return 0;
+ }
+
+ pcmdev_controls = devm_kcalloc(pcm_dev->dev, nr_chn,
+ sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+ if (!pcmdev_controls)
+ return -ENOMEM;
+
+ name_id = pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl_name_id;
+
+ ctrl_name = pcmdev_ctrl_name[name_id];
+
+ for (chn = 1; chn <= nr_chn; chn++) {
+ name = devm_kzalloc(pcm_dev->dev,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ ctrl_name, pcm_dev->upper_dev_name, adap->nr,
+ dev_no, chn);
+ pcmdev_controls[mix_index].tlv.p =
+ pcmdev_gain_ctl_info[id][ctl_id].gain;
+ pcmdev_ctrl = devm_kmemdup(pcm_dev->dev,
+ &pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl[chn - 1],
+ sizeof(*pcmdev_ctrl), GFP_KERNEL);
+ if (!pcmdev_ctrl) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pcmdev_ctrl->dev_no = dev_no;
+ pcmdev_controls[mix_index].private_value =
+ (unsigned long)pcmdev_ctrl;
+ pcmdev_controls[mix_index].name = name;
+ pcmdev_controls[mix_index].access =
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ pcmdev_controls[mix_index].iface =
+ SNDRV_CTL_ELEM_IFACE_MIXER;
+ pcmdev_controls[mix_index].info = pcmdevice_info_volsw;
+ pcmdev_controls[mix_index].get =
+ pcmdev_gain_ctl_info[id][ctl_id].get;
+ pcmdev_controls[mix_index].put =
+ pcmdev_gain_ctl_info[id][ctl_id].put;
+ mix_index++;
+ }
+
+ ret = snd_soc_add_component_controls(comp, pcmdev_controls, mix_index);
+ if (ret)
+ dev_err(pcm_dev->dev, "%s: add_controls err = %d\n",
+ __func__, ret);
+out:
+ return ret;
+}
+
+static int pcmdev_profile_ctrl_add(struct pcmdevice_priv *pcm_dev)
+{
+ struct snd_soc_component *comp = pcm_dev->component;
+ struct i2c_adapter *adap = pcm_dev->client->adapter;
+ struct snd_kcontrol_new *pcmdev_ctrl;
+ char *name;
+ int ret;
+
+ pcmdev_ctrl = devm_kzalloc(pcm_dev->dev,
+ sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+ if (!pcmdev_ctrl)
+ return -ENOMEM;
+
+ /* Create a mixer item for selecting the active profile */
+ name = devm_kzalloc(pcm_dev->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "%s i2c%d Profile id", pcm_dev->upper_dev_name, adap->nr);
+ pcmdev_ctrl->name = name;
+ pcmdev_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ pcmdev_ctrl->info = pcmdevice_info_profile;
+ pcmdev_ctrl->get = pcmdevice_get_profile_id;
+ pcmdev_ctrl->put = pcmdevice_set_profile_id;
+
+ ret = snd_soc_add_component_controls(comp, pcmdev_ctrl, 1);
+ if (ret)
+ dev_err(pcm_dev->dev, "%s: add_controls err = %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static void pcmdevice_config_info_remove(void *ctxt)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *) ctxt;
+ struct pcmdevice_regbin *regbin = &(pcm_dev->regbin);
+ struct pcmdevice_config_info **cfg_info = regbin->cfg_info;
+ int i, j;
+
+ if (!cfg_info)
+ return;
+ for (i = 0; i < regbin->ncfgs; i++) {
+ if (!cfg_info[i])
+ continue;
+ if (cfg_info[i]->blk_data) {
+ for (j = 0; j < (int)cfg_info[i]->real_nblocks; j++) {
+ if (!cfg_info[i]->blk_data[j])
+ continue;
+ kfree(cfg_info[i]->blk_data[j]->regdata);
+ kfree(cfg_info[i]->blk_data[j]);
+ }
+ kfree(cfg_info[i]->blk_data);
+ }
+ kfree(cfg_info[i]);
+ }
+ kfree(cfg_info);
+}
+
+static int pcmdev_regbin_ready(const struct firmware *fmw, void *ctxt)
+{
+ struct pcmdevice_config_info **cfg_info;
+ struct pcmdevice_priv *pcm_dev = ctxt;
+ struct pcmdevice_regbin_hdr *fw_hdr;
+ struct pcmdevice_regbin *regbin;
+ unsigned int total_config_sz = 0;
+ int offset = 0, ret = 0, i;
+ unsigned char *buf;
+
+ regbin = &(pcm_dev->regbin);
+ fw_hdr = &(regbin->fw_hdr);
+ if (!fmw || !fmw->data) {
+ dev_err(pcm_dev->dev, "%s: failed to read %s\n",
+ __func__, pcm_dev->bin_name);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+ 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(pcm_dev->dev, "%s: file size(%d) not match %u",
+ __func__, (int)fmw->size, fw_hdr->img_sz);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ 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(pcm_dev->dev, "%s: bin version 0x%04x is out of date",
+ __func__, fw_hdr->binary_version_num);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]);
+ offset += 8;
+ fw_hdr->plat_type = buf[offset];
+ offset += 1;
+ fw_hdr->dev_family = buf[offset];
+ offset += 1;
+ fw_hdr->reserve = buf[offset];
+ offset += 1;
+ fw_hdr->ndev = buf[offset];
+ offset += 1;
+ if (fw_hdr->ndev != pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: invalid ndev(%u)\n", __func__,
+ fw_hdr->ndev);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (offset + PCMDEVICE_MAX_REGBIN_DEVICES > fw_hdr->img_sz) {
+ dev_err(pcm_dev->dev, "%s: devs out of boundary!\n", __func__);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < PCMDEVICE_MAX_REGBIN_DEVICES; i++, offset++)
+ fw_hdr->devs[i] = buf[offset];
+
+ fw_hdr->nconfig = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+
+ for (i = 0; i < PCMDEVICE_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(pcm_dev->dev, "%s: bin file error!\n", __func__);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+ cfg_info = kcalloc(fw_hdr->nconfig, sizeof(*cfg_info), GFP_KERNEL);
+ if (!cfg_info) {
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -ENOMEM;
+ goto out;
+ }
+ regbin->cfg_info = cfg_info;
+ regbin->ncfgs = 0;
+ for (i = 0; i < (int)fw_hdr->nconfig; i++) {
+ cfg_info[i] = pcmdevice_add_config(ctxt, &buf[offset],
+ fw_hdr->config_size[i], &ret);
+ if (ret) {
+ /* In case the bin file is partially destroyed. */
+ if (regbin->ncfgs == 0)
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ break;
+ }
+ offset += (int)fw_hdr->config_size[i];
+ regbin->ncfgs += 1;
+ }
+
+out:
+ if (pcm_dev->fw_state == PCMDEVICE_FW_LOAD_FAILED) {
+ dev_err(pcm_dev->dev,
+ "%s: remove config due to fw load error!\n", __func__);
+ pcmdevice_config_info_remove(pcm_dev);
+ }
+
+ return ret;
+}
+
+static int pcmdevice_comp_probe(struct snd_soc_component *comp)
+{
+ struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(comp);
+ struct i2c_adapter *adap = pcm_dev->client->adapter;
+ const struct firmware *fw_entry = NULL;
+ int ret, i, j;
+
+ mutex_lock(&pcm_dev->codec_lock);
+
+ pcm_dev->component = comp;
+
+ for (i = 0; i < pcm_dev->ndev; i++) {
+ for (j = 0; j < 2; j++) {
+ ret = pcmdev_gain_ctrl_add(pcm_dev, i, j);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ if (comp->name_prefix) {
+ /* There's name_prefix defined in DTS. Bin file name will be
+ * name_prefix.bin stores the firmware including register
+ * setting and params for different filters inside chips, it
+ * must be copied into firmware folder. The same types of
+ * pcmdevices sitting on the same i2c bus will be aggregated as
+ * one single codec, all of them share the same bin file.
+ */
+ scnprintf(pcm_dev->bin_name, PCMDEVICE_BIN_FILENAME_LEN,
+ "%s.bin", comp->name_prefix);
+ } else {
+ /* There's NO name_prefix defined in DTS. Bin file name will be
+ * device-name[defined in pcmdevice_i2c_id]-i2c-bus_id
+ * [0,1,...,N]-sum[1,...,4]dev.bin stores the firmware
+ * including register setting and params for different filters
+ * inside chips, it must be copied into firmware folder. The
+ * same types of pcmdevices sitting on the same i2c bus will be
+ * aggregated as one single codec, all of them share the same
+ * bin file.
+ */
+ scnprintf(pcm_dev->bin_name, PCMDEVICE_BIN_FILENAME_LEN,
+ "%s-i2c-%d-%udev.bin", pcm_dev->dev_name, adap->nr,
+ pcm_dev->ndev);
+ }
+
+ ret = request_firmware(&fw_entry, pcm_dev->bin_name, pcm_dev->dev);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: request %s err = %d\n", __func__,
+ pcm_dev->bin_name, ret);
+ goto out;
+ }
+
+ ret = pcmdev_regbin_ready(fw_entry, pcm_dev);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: %s parse err = %d\n", __func__,
+ pcm_dev->bin_name, ret);
+ goto out;
+ }
+ ret = pcmdev_profile_ctrl_add(pcm_dev);
+out:
+ release_firmware(fw_entry);
+
+ mutex_unlock(&pcm_dev->codec_lock);
+ return ret;
+}
+
+
+static void pcmdevice_comp_remove(struct snd_soc_component *codec)
+{
+ struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(codec);
+
+ if (!pcm_dev)
+ return;
+ mutex_lock(&pcm_dev->codec_lock);
+ pcmdevice_config_info_remove(pcm_dev);
+ mutex_unlock(&pcm_dev->codec_lock);
+}
+
+static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("ASI1 OUT", "ASI1 Capture",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+ SND_SOC_DAPM_INPUT("MIC"),
+};
+
+static const struct snd_soc_dapm_route pcmdevice_audio_map[] = {
+ {"OUT", NULL, "ASI"},
+ {"ASI1 OUT", NULL, "MIC"},
+};
+
+static const struct snd_soc_component_driver
+ soc_codec_driver_pcmdevice = {
+ .probe = pcmdevice_comp_probe,
+ .remove = pcmdevice_comp_remove,
+ .dapm_widgets = pcmdevice_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcmdevice_dapm_widgets),
+ .dapm_routes = pcmdevice_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(pcmdevice_audio_map),
+ .suspend_bias_off = 1,
+ .idle_bias_on = 0,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int pcmdev_single_byte_wr(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int offset = 2;
+ int i, ret;
+
+ offset += 2;
+ if (offset + 4 * len > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d byt wr out of boundary\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++) {
+ ret = pcmdev_dev_write(pcm_dev, devn,
+ PCMDEVICE_REG(data[offset + 1], data[offset + 2]),
+ data[offset + 3]);
+ /* skip this error for next operation or next devices */
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev-%d single write err\n",
+ __func__, devn);
+
+ offset += 4;
+ }
+
+ return offset;
+}
+
+static int pcmdev_burst_wr(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int offset = 2;
+ int ret;
+
+ offset += 2;
+ if (offset + 4 + len > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d burst Out of boundary\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+ if (len % 4) {
+ dev_err(pcm_dev->dev, "%s: dev-%d bst-len(%u) not div by 4\n",
+ __func__, devn, len);
+ return -EINVAL;
+ }
+ ret = pcmdev_dev_bulk_write(pcm_dev, devn,
+ PCMDEVICE_REG(data[offset + 1], data[offset + 2]),
+ &(data[offset + 4]), len);
+ /* skip this error for next devices */
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev-%d bulk_write err = %d\n",
+ __func__, devn, ret);
+
+ offset += (len + 4);
+
+ return offset;
+}
+
+static int pcmdev_delay(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ unsigned int delay_time = 0;
+ int offset = 2;
+
+ if (offset + 2 > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d delay out of boundary\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+ delay_time = get_unaligned_be16(&data[2]) * 1000;
+ usleep_range(delay_time, delay_time + 50);
+ offset += 2;
+
+ return offset;
+}
+
+static int pcmdev_bits_wr(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ int offset = 2;
+ int ret;
+
+ if (offset + 6 > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d bit write out of memory\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+ ret = pcmdev_dev_update_bits(pcm_dev, devn,
+ PCMDEVICE_REG(data[offset + 3], data[offset + 4]),
+ data[offset + 1], data[offset + 5]);
+ /* skip this error for next devices */
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev-%d update_bits err = %d\n",
+ __func__, devn, ret);
+
+ offset += 6;
+
+ return offset;
+}
+
+static int pcmdevice_process_block(void *ctxt, unsigned char *data,
+ unsigned char dev_idx, int sublocksize)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *)ctxt;
+ int devn, dev_end, ret = 0;
+ unsigned char subblk_typ = data[1];
+
+ if (dev_idx) {
+ devn = dev_idx - 1;
+ dev_end = dev_idx;
+ } else {
+ devn = 0;
+ dev_end = pcm_dev->ndev;
+ }
+
+ /* loop in case of several devices sharing the same sub-block */
+ for (; devn < dev_end; devn++) {
+ switch (subblk_typ) {
+ case PCMDEVICE_CMD_SING_W:
+ ret = pcmdev_single_byte_wr(pcm_dev, data, devn, sublocksize);
+ break;
+ case PCMDEVICE_CMD_BURST:
+ ret = pcmdev_burst_wr(pcm_dev, data, devn, sublocksize);
+ break;
+ case PCMDEVICE_CMD_DELAY:
+ ret = pcmdev_delay(pcm_dev, data, devn, sublocksize);
+ break;
+ case PCMDEVICE_CMD_FIELD_W:
+ ret = pcmdev_bits_wr(pcm_dev, data, devn, sublocksize);
+ break;
+ default:
+ break;
+ }
+ /*
+ * In case of sub-block error, break the loop for the rest of
+ * devices.
+ */
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static void pcmdevice_select_cfg_blk(void *ctxt, int conf_no,
+ unsigned char block_type)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *)ctxt;
+ struct pcmdevice_regbin *regbin = &(pcm_dev->regbin);
+ struct pcmdevice_config_info **cfg_info = regbin->cfg_info;
+ struct pcmdevice_block_data **blk_data;
+ int j, k;
+
+ if (conf_no >= regbin->ncfgs || conf_no < 0 || NULL == cfg_info) {
+ dev_err(pcm_dev->dev, "%s: conf_no should be less than %u\n",
+ __func__, regbin->ncfgs);
+ goto out;
+ }
+ blk_data = cfg_info[conf_no]->blk_data;
+
+ for (j = 0; j < (int)cfg_info[conf_no]->real_nblocks; j++) {
+ unsigned int length = 0, ret;
+
+ if (block_type > 5 || block_type < 2) {
+ dev_err(pcm_dev->dev,
+ "%s: block_type should be out of range\n",
+ __func__);
+ goto out;
+ }
+ if (block_type != blk_data[j]->block_type)
+ continue;
+
+ for (k = 0; k < (int)blk_data[j]->n_subblks; k++) {
+ ret = pcmdevice_process_block(pcm_dev,
+ blk_data[j]->regdata + length,
+ blk_data[j]->dev_idx,
+ blk_data[j]->block_size - length);
+ length += ret;
+ if (blk_data[j]->block_size < length) {
+ dev_err(pcm_dev->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(pcm_dev->dev, "%s: %u %u size is not same\n",
+ __func__, length, blk_data[j]->block_size);
+ }
+
+out:
+ return;
+}
+
+static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *codec = dai->component;
+ struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(codec);
+ unsigned char block_type;
+
+ if (pcm_dev->fw_state == PCMDEVICE_FW_LOAD_FAILED) {
+ dev_err(pcm_dev->dev, "%s: bin file not loaded\n", __func__);
+ return -EINVAL;
+ }
+
+ if (mute)
+ block_type = PCMDEVICE_BIN_BLK_PRE_SHUTDOWN;
+ else
+ block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP;
+
+ mutex_lock(&pcm_dev->codec_lock);
+ pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type);
+ mutex_unlock(&pcm_dev->codec_lock);
+ return 0;
+}
+
+static int pcmdevice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct pcmdevice_priv *pcm_dev = snd_soc_dai_get_drvdata(dai);
+ unsigned int fsrate;
+ unsigned int slot_width;
+ int bclk_rate;
+ int ret = 0;
+
+ fsrate = params_rate(params);
+ switch (fsrate) {
+ case 48000:
+ break;
+ case 44100:
+ break;
+ default:
+ dev_err(pcm_dev->dev, "%s: incorrect sample rate = %u\n",
+ __func__, fsrate);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ slot_width = params_width(params);
+ switch (slot_width) {
+ case 16:
+ break;
+ case 20:
+ break;
+ case 24:
+ break;
+ case 32:
+ break;
+ default:
+ dev_err(pcm_dev->dev, "%s: incorrect slot width = %u\n",
+ __func__, slot_width);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bclk_rate = snd_soc_params_to_bclk(params);
+ if (bclk_rate < 0) {
+ dev_err(pcm_dev->dev, "%s: incorrect bclk rate = %d\n",
+ __func__, bclk_rate);
+ ret = bclk_rate;
+ }
+
+out:
+ return ret;
+}
+
+static const struct snd_soc_dai_ops pcmdevice_dai_ops = {
+ .mute_stream = pcmdevice_mute,
+ .hw_params = pcmdevice_hw_params,
+};
+
+static struct snd_soc_dai_driver pcmdevice_dai_driver[] = {
+ {
+ .name = "pcmdevice-codec",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = PCMDEVICE_MAX_CHANNELS,
+ .rates = PCMDEVICE_RATES,
+ .formats = PCMDEVICE_FORMATS,
+ },
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = PCMDEVICE_MAX_CHANNELS,
+ .rates = PCMDEVICE_RATES,
+ .formats = PCMDEVICE_FORMATS,
+ },
+ .ops = &pcmdevice_dai_ops,
+ .symmetric_rate = 1,
+ }
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcmdevice_of_match[] = {
+ { .compatible = "ti,adc3120" },
+ { .compatible = "ti,adc5120" },
+ { .compatible = "ti,adc6120" },
+ { .compatible = "ti,dix4192" },
+ { .compatible = "ti,pcm1690" },
+ { .compatible = "ti,pcm3120" },
+ { .compatible = "ti,pcm3140" },
+ { .compatible = "ti,pcm5120" },
+ { .compatible = "ti,pcm5140" },
+ { .compatible = "ti,pcm6120" },
+ { .compatible = "ti,pcm6140" },
+ { .compatible = "ti,pcm6240" },
+ { .compatible = "ti,pcm6260" },
+ { .compatible = "ti,pcm9211" },
+ { .compatible = "ti,pcmd3140" },
+ { .compatible = "ti,pcmd3180" },
+ { .compatible = "ti,pcmd512x" },
+ { .compatible = "ti,taa5212" },
+ { .compatible = "ti,taa5412" },
+ { .compatible = "ti,tad5212" },
+ { .compatible = "ti,tad5412" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pcmdevice_of_match);
+#endif
+
+static const struct regmap_range_cfg pcmdevice_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 256 * 128,
+ .selector_reg = PCMDEVICE_PAGE_SELECT,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 128,
+ },
+};
+
+static const struct regmap_config pcmdevice_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .ranges = pcmdevice_ranges,
+ .num_ranges = ARRAY_SIZE(pcmdevice_ranges),
+ .max_register = 256 * 128,
+};
+
+static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev)
+{
+ if (pcm_dev->irq)
+ free_irq(pcm_dev->irq, pcm_dev);
+ mutex_destroy(&pcm_dev->codec_lock);
+}
+
+static char *str_to_upper(char *str)
+{
+ char *orig = str;
+
+ if (!str)
+ return NULL;
+
+ while (*str) {
+ *str = toupper(*str);
+ str++;
+ }
+
+ return orig;
+}
+
+static int pcmdevice_i2c_probe(struct i2c_client *i2c)
+{
+ struct pcmdevice_priv *pcm_dev;
+ struct device_node *np;
+ unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES];
+ int ret = 0, i = 0, ndev = 0;
+
+ pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL);
+ if (!pcm_dev)
+ return -ENOMEM;
+
+ pcm_dev->chip_id = (uintptr_t)i2c_get_match_data(i2c);
+
+ pcm_dev->dev = &i2c->dev;
+ pcm_dev->client = i2c;
+
+ if (pcm_dev->chip_id >= MAX_DEVICE)
+ pcm_dev->chip_id = 0;
+
+ strscpy(pcm_dev->dev_name, pcmdevice_i2c_id[pcm_dev->chip_id].name,
+ sizeof(pcm_dev->dev_name));
+
+ strscpy(pcm_dev->upper_dev_name,
+ pcmdevice_i2c_id[pcm_dev->chip_id].name,
+ sizeof(pcm_dev->upper_dev_name));
+
+ str_to_upper(pcm_dev->upper_dev_name);
+
+ pcm_dev->regmap = devm_regmap_init_i2c(i2c, &pcmdevice_i2c_regmap);
+ if (IS_ERR(pcm_dev->regmap)) {
+ ret = PTR_ERR(pcm_dev->regmap);
+ dev_err(&i2c->dev, "%s: failed to allocate register map: %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ i2c_set_clientdata(i2c, pcm_dev);
+ mutex_init(&pcm_dev->codec_lock);
+ np = pcm_dev->dev->of_node;
+
+ if (IS_ENABLED(CONFIG_OF)) {
+ u64 addr;
+
+ for (i = 0; i < PCMDEVICE_MAX_I2C_DEVICES; i++) {
+ if (of_property_read_reg(np, i, &addr, NULL))
+ break;
+ dev_addrs[ndev++] = addr;
+ }
+ } else {
+ ndev = 1;
+ dev_addrs[0] = i2c->addr;
+ }
+ pcm_dev->irq = of_irq_get(np, 0);
+
+ for (i = 0; i < ndev; i++)
+ pcm_dev->addr[i] = dev_addrs[i];
+
+ pcm_dev->ndev = ndev;
+
+ pcm_dev->hw_rst = devm_gpiod_get_optional(&i2c->dev,
+ "reset-gpios", GPIOD_OUT_HIGH);
+ /* No reset GPIO, no side-effect */
+ if (IS_ERR(pcm_dev->hw_rst)) {
+ if (pcm_dev->chip_id == PCM9211 || pcm_dev->chip_id == PCM1690)
+ pcm9211_sw_rst(pcm_dev);
+ else
+ pcmdevice_sw_rst(pcm_dev);
+ } else {
+ gpiod_set_value_cansleep(pcm_dev->hw_rst, 0);
+ usleep_range(500, 1000);
+ gpiod_set_value_cansleep(pcm_dev->hw_rst, 1);
+ }
+
+ if (pcm_dev->chip_id == PCM1690)
+ goto skip_interrupt;
+ if (pcm_dev->irq) {
+ dev_dbg(pcm_dev->dev, "irq = %d", pcm_dev->irq);
+ } else
+ dev_err(pcm_dev->dev, "No irq provided\n");
+
+skip_interrupt:
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_driver_pcmdevice, pcmdevice_dai_driver,
+ ARRAY_SIZE(pcmdevice_dai_driver));
+ if (ret < 0)
+ dev_err(&i2c->dev, "probe register comp failed %d\n", ret);
+
+out:
+ if (ret < 0)
+ pcmdevice_remove(pcm_dev);
+ return ret;
+}
+
+static void pcmdevice_i2c_remove(struct i2c_client *i2c)
+{
+ struct pcmdevice_priv *pcm_dev = i2c_get_clientdata(i2c);
+
+ pcmdevice_remove(pcm_dev);
+}
+
+static struct i2c_driver pcmdevice_i2c_driver = {
+ .driver = {
+ .name = "pcmdevice-codec",
+ .of_match_table = of_match_ptr(pcmdevice_of_match),
+ },
+ .probe = pcmdevice_i2c_probe,
+ .remove = pcmdevice_i2c_remove,
+ .id_table = pcmdevice_i2c_id,
+};
+module_i2c_driver(pcmdevice_i2c_driver);
+
+MODULE_AUTHOR("Shenghao Ding <shenghao-ding@ti.com>");
+MODULE_DESCRIPTION("ASoC PCM6240 Family Audio ADC/DAC Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h
new file mode 100644
index 000000000000..2d8f9e798139
--- /dev/null
+++ b/sound/soc/codecs/pcm6240.h
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+//
+// ALSA SoC Texas Instruments PCM6240 Family Audio ADC/DAC/Router
+//
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The PCM6240 driver implements a flexible and configurable
+// algo coefficient setting for one, two, or even multiple
+// PCM6240 Family Audio chips.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+//
+
+#ifndef __PCM6240_H__
+#define __PCM6240_H__
+
+enum pcm_device {
+ ADC3120,
+ ADC5120,
+ ADC6120,
+ DIX4192,
+ PCM1690,
+ PCM3120,
+ PCM3140,
+ PCM5120,
+ PCM5140,
+ PCM6120,
+ PCM6140,
+ PCM6240,
+ PCM6260,
+ PCM9211,
+ PCMD3140,
+ PCMD3180,
+ PCMD512X,
+ TAA5212,
+ TAA5412,
+ TAD5212,
+ TAD5412,
+ MAX_DEVICE,
+};
+
+#define PCMDEV_GENERIC_VOL_CTRL 0x0
+#define PCMDEV_PCM1690_VOL_CTRL 0x1
+#define PCMDEV_PCM1690_FINE_VOL_CTRL 0x2
+
+/* Maximum number of I2C addresses */
+#define PCMDEVICE_MAX_I2C_DEVICES 4
+/* Maximum number defined in REGBIN protocol */
+#define PCMDEVICE_MAX_REGBIN_DEVICES 8
+#define PCMDEVICE_CONFIG_SUM 64
+#define PCMDEVICE_BIN_FILENAME_LEN 64
+
+#define PCMDEVICE_RATES (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000)
+#define PCMDEVICE_MAX_CHANNELS 8
+#define PCMDEVICE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* PAGE Control Register (available in page0 of each book) */
+#define PCMDEVICE_PAGE_SELECT 0x00
+#define PCMDEVICE_REG(page, reg) ((page * 128) + reg)
+#define PCMDEVICE_REG_SWRESET PCMDEVICE_REG(0X0, 0x01)
+#define PCMDEVICE_REG_SWRESET_RESET BIT(0)
+
+#define ADC5120_REG_CH1_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x3d)
+#define ADC5120_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3e)
+#define ADC5120_REG_CH2_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x42)
+#define ADC5120_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+
+#define PCM1690_REG_MODE_CTRL PCMDEVICE_REG(0X0, 0x46)
+#define PCM1690_REG_MODE_CTRL_DAMS_MSK BIT(7)
+#define PCM1690_REG_MODE_CTRL_DAMS_FINE_STEP 0x0
+#define PCM1690_REG_MODE_CTRL_DAMS_WIDE_RANGE 0x80
+
+#define PCM1690_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCM1690_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x49)
+#define PCM1690_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4a)
+#define PCM1690_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4b)
+#define PCM1690_REG_CH5_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4c)
+#define PCM1690_REG_CH6_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4d)
+#define PCM1690_REG_CH7_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4e)
+#define PCM1690_REG_CH8_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4f)
+
+#define PCM6240_REG_CH1_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x3d)
+#define PCM6240_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3e)
+#define PCM6240_REG_CH2_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x42)
+#define PCM6240_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCM6240_REG_CH3_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x47)
+#define PCM6240_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCM6240_REG_CH4_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x4c)
+#define PCM6240_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4d)
+
+#define PCM6260_REG_CH1_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x3d)
+#define PCM6260_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3e)
+#define PCM6260_REG_CH2_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x42)
+#define PCM6260_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCM6260_REG_CH3_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x47)
+#define PCM6260_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCM6260_REG_CH4_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x4c)
+#define PCM6260_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4d)
+#define PCM6260_REG_CH5_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x51)
+#define PCM6260_REG_CH5_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x52)
+#define PCM6260_REG_CH6_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x56)
+#define PCM6260_REG_CH6_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x57)
+
+#define PCM9211_REG_SW_CTRL PCMDEVICE_REG(0X0, 0x40)
+#define PCM9211_REG_SW_CTRL_MRST_MSK BIT(7)
+#define PCM9211_REG_SW_CTRL_MRST 0x0
+
+#define PCM9211_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x46)
+#define PCM9211_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x47)
+
+#define PCMD3140_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3E)
+#define PCMD3140_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCMD3140_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCMD3140_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4D)
+
+#define PCMD3140_REG_CH1_FINE_GAIN PCMDEVICE_REG(0X0, 0x3F)
+#define PCMD3140_REG_CH2_FINE_GAIN PCMDEVICE_REG(0X0, 0x44)
+#define PCMD3140_REG_CH3_FINE_GAIN PCMDEVICE_REG(0X0, 0x49)
+#define PCMD3140_REG_CH4_FINE_GAIN PCMDEVICE_REG(0X0, 0x4E)
+
+#define PCMD3180_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3E)
+#define PCMD3180_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCMD3180_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCMD3180_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4D)
+#define PCMD3180_REG_CH5_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x52)
+#define PCMD3180_REG_CH6_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x57)
+#define PCMD3180_REG_CH7_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x5C)
+#define PCMD3180_REG_CH8_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x61)
+
+#define PCMD3180_REG_CH1_FINE_GAIN PCMDEVICE_REG(0X0, 0x3F)
+#define PCMD3180_REG_CH2_FINE_GAIN PCMDEVICE_REG(0X0, 0x44)
+#define PCMD3180_REG_CH3_FINE_GAIN PCMDEVICE_REG(0X0, 0x49)
+#define PCMD3180_REG_CH4_FINE_GAIN PCMDEVICE_REG(0X0, 0x4E)
+#define PCMD3180_REG_CH5_FINE_GAIN PCMDEVICE_REG(0X0, 0x53)
+#define PCMD3180_REG_CH6_FINE_GAIN PCMDEVICE_REG(0X0, 0x58)
+#define PCMD3180_REG_CH7_FINE_GAIN PCMDEVICE_REG(0X0, 0x5D)
+#define PCMD3180_REG_CH8_FINE_GAIN PCMDEVICE_REG(0X0, 0x62)
+
+#define TAA5412_REG_CH1_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x52)
+#define TAA5412_REG_CH2_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x57)
+#define TAA5412_REG_CH3_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x5B)
+#define TAA5412_REG_CH4_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x5F)
+
+#define TAA5412_REG_CH1_FINE_GAIN PCMDEVICE_REG(0X0, 0x53)
+#define TAA5412_REG_CH2_FINE_GAIN PCMDEVICE_REG(0X0, 0x58)
+#define TAA5412_REG_CH3_FINE_GAIN PCMDEVICE_REG(0X0, 0x5C)
+#define TAA5412_REG_CH4_FINE_GAIN PCMDEVICE_REG(0X0, 0x60)
+
+#define PCMDEVICE_CMD_SING_W 0x1
+#define PCMDEVICE_CMD_BURST 0x2
+#define PCMDEVICE_CMD_DELAY 0x3
+#define PCMDEVICE_CMD_FIELD_W 0x4
+
+enum pcmdevice_bin_blk_type {
+ PCMDEVICE_BIN_BLK_COEFF = 1,
+ PCMDEVICE_BIN_BLK_POST_POWER_UP,
+ PCMDEVICE_BIN_BLK_PRE_SHUTDOWN,
+ PCMDEVICE_BIN_BLK_PRE_POWER_UP,
+ PCMDEVICE_BIN_BLK_POST_SHUTDOWN
+};
+
+enum pcmdevice_fw_state {
+ PCMDEVICE_FW_LOAD_OK = 0,
+ PCMDEVICE_FW_LOAD_FAILED
+};
+
+struct pcmdevice_regbin_hdr {
+ unsigned int img_sz;
+ unsigned int checksum;
+ unsigned int binary_version_num;
+ unsigned int drv_fw_version;
+ unsigned int timestamp;
+ unsigned char plat_type;
+ unsigned char dev_family;
+ unsigned char reserve;
+ unsigned char ndev;
+ unsigned char devs[PCMDEVICE_MAX_REGBIN_DEVICES];
+ unsigned int nconfig;
+ unsigned int config_size[PCMDEVICE_CONFIG_SUM];
+};
+
+struct pcmdevice_block_data {
+ unsigned char dev_idx;
+ unsigned char block_type;
+ unsigned short yram_checksum;
+ unsigned int block_size;
+ unsigned int n_subblks;
+ unsigned char *regdata;
+};
+
+struct pcmdevice_config_info {
+ char cfg_name[64];
+ unsigned int nblocks;
+ unsigned int real_nblocks;
+ unsigned char active_dev;
+ struct pcmdevice_block_data **blk_data;
+};
+
+struct pcmdevice_regbin {
+ struct pcmdevice_regbin_hdr fw_hdr;
+ int ncfgs;
+ struct pcmdevice_config_info **cfg_info;
+};
+
+struct pcmdevice_priv {
+ struct snd_soc_component *component;
+ struct i2c_client *client;
+ struct device *dev;
+ struct mutex codec_lock;
+ struct gpio_desc *hw_rst;
+ struct regmap *regmap;
+ struct pcmdevice_regbin regbin;
+ int irq;
+ unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES];
+ unsigned int chip_id;
+ int cur_conf;
+ int fw_state;
+ int ndev;
+ unsigned char bin_name[PCMDEVICE_BIN_FILENAME_LEN];
+ /* used for kcontrol name */
+ unsigned char upper_dev_name[I2C_NAME_SIZE];
+ unsigned char dev_name[I2C_NAME_SIZE];
+};
+
+/* mixer control */
+struct pcmdevice_mixer_control {
+ int max;
+ int reg;
+ unsigned int dev_no;
+ unsigned int shift;
+ unsigned int invert;
+};
+struct pcmdev_ctrl_info {
+ const unsigned int *gain;
+ const struct pcmdevice_mixer_control *pcmdev_ctrl;
+ unsigned int ctrl_array_size;
+ snd_kcontrol_get_t *get;
+ snd_kcontrol_put_t *put;
+ int pcmdev_ctrl_name_id;
+};
+#endif /* __PCM6240_H__ */
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index 5dec69be0acb..f1ee42af264b 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -6,7 +6,7 @@
//
// Author: Herve Codina <herve.codina@bootlin.com>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/clk.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -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;
@@ -229,7 +228,8 @@ static int peb2466_reg_read(void *context, unsigned int reg, unsigned int *val)
case PEB2466_CMD_XOP:
case PEB2466_CMD_SOP:
ret = peb2466_read_byte(peb2466, reg, &tmp);
- *val = tmp;
+ if (!ret)
+ *val = tmp;
break;
default:
dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n");
@@ -276,7 +276,7 @@ static int peb2466_lkup_ctrl_put(struct snd_kcontrol *kcontrol,
{
struct peb2466_lkup_ctrl *lkup_ctrl =
(struct peb2466_lkup_ctrl *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component);
unsigned int index;
int ret;
@@ -377,7 +377,7 @@ static const struct soc_enum peb2466_tg_freq[][2] = {
static int peb2466_tg_freq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -415,7 +415,7 @@ static int peb2466_tg_freq_get(struct snd_kcontrol *kcontrol,
static int peb2466_tg_freq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *tg_freq_item;
@@ -814,7 +814,7 @@ static int peb2466_dai_startup(struct snd_pcm_substream *substream,
&peb2466_sample_bits_constr);
}
-static u64 peb2466_dai_formats[] = {
+static const u64 peb2466_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
@@ -1726,7 +1726,8 @@ end:
return ret;
}
-static void peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
+static int peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
+ int val)
{
struct peb2466 *peb2466 = gpiochip_get_data(c);
unsigned int xr_reg;
@@ -1740,14 +1741,14 @@ static void peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int
*/
dev_warn(&peb2466->spi->dev, "cannot set gpio %d (read-only)\n",
offset);
- return;
+ return -EINVAL;
}
ret = peb2466_chip_gpio_offset_to_data_regmask(offset, &xr_reg, &mask);
if (ret) {
dev_err(&peb2466->spi->dev, "cannot set gpio %d (%d)\n",
offset, ret);
- return;
+ return ret;
}
ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, val ? mask : 0);
@@ -1755,6 +1756,8 @@ static void peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int
dev_err(&peb2466->spi->dev, "set gpio %d (0x%x, 0x%x) failed (%d)\n",
offset, xr_reg, mask, ret);
}
+
+ return ret;
}
static int peb2466_chip_gpio_get(struct gpio_chip *c, unsigned int offset)
@@ -1879,7 +1882,9 @@ static int peb2466_chip_direction_output(struct gpio_chip *c, unsigned int offse
return -EINVAL;
}
- peb2466_chip_gpio_set(c, offset, val);
+ ret = peb2466_chip_gpio_set(c, offset, val);
+ if (ret)
+ return ret;
if (offset < 16) {
/* SOx_{0,1} */
@@ -1975,12 +1980,9 @@ static int peb2466_spi_probe(struct spi_device *spi)
if (IS_ERR(peb2466->reset_gpio))
return PTR_ERR(peb2466->reset_gpio);
- peb2466->mclk = devm_clk_get(&peb2466->spi->dev, "mclk");
+ peb2466->mclk = devm_clk_get_enabled(&peb2466->spi->dev, "mclk");
if (IS_ERR(peb2466->mclk))
return PTR_ERR(peb2466->mclk);
- ret = clk_prepare_enable(peb2466->mclk);
- if (ret)
- return ret;
if (peb2466->reset_gpio) {
gpiod_set_value_cansleep(peb2466->reset_gpio, 1);
@@ -2031,17 +2033,9 @@ static int peb2466_spi_probe(struct spi_device *spi)
return 0;
failed:
- clk_disable_unprepare(peb2466->mclk);
return ret;
}
-static void peb2466_spi_remove(struct spi_device *spi)
-{
- struct peb2466 *peb2466 = spi_get_drvdata(spi);
-
- clk_disable_unprepare(peb2466->mclk);
-}
-
static const struct of_device_id peb2466_of_match[] = {
{ .compatible = "infineon,peb2466", },
{ }
@@ -2061,7 +2055,6 @@ static struct spi_driver peb2466_spi_driver = {
},
.id_table = peb2466_id_table,
.probe = peb2466_spi_probe,
- .remove = peb2466_spi_remove,
};
module_spi_driver(peb2466_spi_driver);
diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c
new file mode 100644
index 000000000000..3167b38e2876
--- /dev/null
+++ b/sound/soc/codecs/pm4125-sdw.c
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+// Copyright, 2025 Linaro Ltd
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include "pm4125.h"
+
+static struct wcd_sdw_ch_info pm4125_sdw_rx_ch_info[] = {
+ WCD_SDW_CH(PM4125_HPH_L, PM4125_HPH_PORT, BIT(0)),
+ WCD_SDW_CH(PM4125_HPH_R, PM4125_HPH_PORT, BIT(1)),
+};
+
+static struct wcd_sdw_ch_info pm4125_sdw_tx_ch_info[] = {
+ WCD_SDW_CH(PM4125_ADC1, PM4125_ADC_1_2_DMIC1L_BCS_PORT, BIT(0)),
+ WCD_SDW_CH(PM4125_ADC2, PM4125_ADC_1_2_DMIC1L_BCS_PORT, BIT(1)),
+};
+
+static struct sdw_dpn_prop pm4125_dpn_prop[PM4125_MAX_SWR_PORTS] = {
+ {
+ .num = 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 8,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 2,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }
+};
+
+int pm4125_sdw_hw_params(struct pm4125_sdw_priv *priv, struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct sdw_port_config port_config[PM4125_MAX_SWR_PORTS];
+ unsigned long ch_mask;
+ int i, j;
+
+ priv->sconfig.ch_count = 1;
+ priv->active_ports = 0;
+ for (i = 0; i < PM4125_MAX_SWR_PORTS; i++) {
+ ch_mask = priv->port_config[i].ch_mask;
+ if (!ch_mask)
+ continue;
+
+ for_each_set_bit(j, &ch_mask, 4)
+ priv->sconfig.ch_count++;
+
+ port_config[priv->active_ports] = priv->port_config[i];
+ priv->active_ports++;
+ }
+
+ priv->sconfig.bps = 1;
+ priv->sconfig.frame_rate = params_rate(params);
+ priv->sconfig.direction = priv->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX;
+ priv->sconfig.type = SDW_STREAM_PCM;
+
+ return sdw_stream_add_slave(priv->sdev, &priv->sconfig, &port_config[0], priv->active_ports,
+ priv->sruntime);
+}
+EXPORT_SYMBOL_GPL(pm4125_sdw_hw_params);
+
+/*
+ * Handle Soundwire out-of-band interrupt event by triggering the first irq of the slave_irq
+ * irq domain, which then will be handled by the regmap_irq threaded irq.
+ * Looping is to ensure no interrupts were missed in the process.
+ */
+static int pm4125_interrupt_callback(struct sdw_slave *slave, struct sdw_slave_intr_status *status)
+{
+ struct pm4125_sdw_priv *priv = dev_get_drvdata(&slave->dev);
+
+ return wcd_interrupt_callback(slave, priv->slave_irq, PM4125_DIG_SWR_INTR_STATUS_0,
+ PM4125_DIG_SWR_INTR_STATUS_1, PM4125_DIG_SWR_INTR_STATUS_2);
+}
+
+static const struct reg_default pm4125_defaults[] = {
+ { PM4125_ANA_MICBIAS_MICB_1_2_EN, 0x01 },
+ { PM4125_ANA_MICBIAS_MICB_3_EN, 0x00 },
+ { PM4125_ANA_MICBIAS_LDO_1_SETTING, 0x21 },
+ { PM4125_ANA_MICBIAS_LDO_1_CTRL, 0x01 },
+ { PM4125_ANA_TX_AMIC1, 0x00 },
+ { PM4125_ANA_TX_AMIC2, 0x00 },
+ { PM4125_ANA_MBHC_MECH, 0x39 },
+ { PM4125_ANA_MBHC_ELECT, 0x08 },
+ { PM4125_ANA_MBHC_ZDET, 0x10 },
+ { PM4125_ANA_MBHC_RESULT_1, 0x00 },
+ { PM4125_ANA_MBHC_RESULT_2, 0x00 },
+ { PM4125_ANA_MBHC_RESULT_3, 0x00 },
+ { PM4125_ANA_MBHC_BTN0_ZDET_VREF1, 0x00 },
+ { PM4125_ANA_MBHC_BTN1_ZDET_VREF2, 0x10 },
+ { PM4125_ANA_MBHC_BTN2_ZDET_VREF3, 0x20 },
+ { PM4125_ANA_MBHC_BTN3_ZDET_DBG_400, 0x30 },
+ { PM4125_ANA_MBHC_BTN4_ZDET_DBG_1400, 0x40 },
+ { PM4125_ANA_MBHC_MICB2_RAMP, 0x00 },
+ { PM4125_ANA_MBHC_CTL_1, 0x02 },
+ { PM4125_ANA_MBHC_CTL_2, 0x05 },
+ { PM4125_ANA_MBHC_PLUG_DETECT_CTL, 0xE9 },
+ { PM4125_ANA_MBHC_ZDET_ANA_CTL, 0x0F },
+ { PM4125_ANA_MBHC_ZDET_RAMP_CTL, 0x00 },
+ { PM4125_ANA_MBHC_FSM_STATUS, 0x00 },
+ { PM4125_ANA_MBHC_ADC_RESULT, 0x00 },
+ { PM4125_ANA_MBHC_CTL_CLK, 0x30 },
+ { PM4125_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 },
+ { PM4125_ANA_NCP_EN, 0x00 },
+ { PM4125_ANA_NCP_VCTRL, 0xA7 },
+ { PM4125_ANA_HPHPA_CNP_CTL_1, 0x54 },
+ { PM4125_ANA_HPHPA_CNP_CTL_2, 0x2B },
+ { PM4125_ANA_HPHPA_PA_STATUS, 0x00 },
+ { PM4125_ANA_HPHPA_FSM_CLK, 0x12 },
+ { PM4125_ANA_HPHPA_L_GAIN, 0x00 },
+ { PM4125_ANA_HPHPA_R_GAIN, 0x00 },
+ { PM4125_SWR_HPHPA_HD2, 0x1B },
+ { PM4125_ANA_HPHPA_SPARE_CTL, 0x02 },
+ { PM4125_ANA_SURGE_EN, 0x38 },
+ { PM4125_ANA_COMBOPA_CTL, 0x35 },
+ { PM4125_ANA_COMBOPA_CTL_4, 0x84 },
+ { PM4125_ANA_COMBOPA_CTL_5, 0x05 },
+ { PM4125_ANA_RXLDO_CTL, 0x86 },
+ { PM4125_ANA_MBIAS_EN, 0x00 },
+ { PM4125_DIG_SWR_CHIP_ID0, 0x00 },
+ { PM4125_DIG_SWR_CHIP_ID1, 0x00 },
+ { PM4125_DIG_SWR_CHIP_ID2, 0x0C },
+ { PM4125_DIG_SWR_CHIP_ID3, 0x01 },
+ { PM4125_DIG_SWR_SWR_TX_CLK_RATE, 0x00 },
+ { PM4125_DIG_SWR_CDC_RST_CTL, 0x03 },
+ { PM4125_DIG_SWR_TOP_CLK_CFG, 0x00 },
+ { PM4125_DIG_SWR_CDC_RX_CLK_CTL, 0x00 },
+ { PM4125_DIG_SWR_CDC_TX_CLK_CTL, 0x33 },
+ { PM4125_DIG_SWR_SWR_RST_EN, 0x00 },
+ { PM4125_DIG_SWR_CDC_RX_RST, 0x00 },
+ { PM4125_DIG_SWR_CDC_RX0_CTL, 0xFC },
+ { PM4125_DIG_SWR_CDC_RX1_CTL, 0xFC },
+ { PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1, 0x00 },
+ { PM4125_DIG_SWR_CDC_COMP_CTL_0, 0x00 },
+ { PM4125_DIG_SWR_CDC_RX_DELAY_CTL, 0x66 },
+ { PM4125_DIG_SWR_CDC_RX_GAIN_0, 0x55 },
+ { PM4125_DIG_SWR_CDC_RX_GAIN_1, 0xA9 },
+ { PM4125_DIG_SWR_CDC_RX_GAIN_CTL, 0x00 },
+ { PM4125_DIG_SWR_CDC_TX0_CTL, 0x68 },
+ { PM4125_DIG_SWR_CDC_TX1_CTL, 0x68 },
+ { PM4125_DIG_SWR_CDC_TX_RST, 0x00 },
+ { PM4125_DIG_SWR_CDC_REQ0_CTL, 0x01 },
+ { PM4125_DIG_SWR_CDC_REQ1_CTL, 0x01 },
+ { PM4125_DIG_SWR_CDC_RST, 0x00 },
+ { PM4125_DIG_SWR_CDC_AMIC_CTL, 0x02 },
+ { PM4125_DIG_SWR_CDC_DMIC_CTL, 0x00 },
+ { PM4125_DIG_SWR_CDC_DMIC1_CTL, 0x00 },
+ { PM4125_DIG_SWR_CDC_DMIC1_RATE, 0x01 },
+ { PM4125_DIG_SWR_PDM_WD_CTL0, 0x00 },
+ { PM4125_DIG_SWR_PDM_WD_CTL1, 0x00 },
+ { PM4125_DIG_SWR_INTR_MODE, 0x00 },
+ { PM4125_DIG_SWR_INTR_MASK_0, 0xFF },
+ { PM4125_DIG_SWR_INTR_MASK_1, 0x7F },
+ { PM4125_DIG_SWR_INTR_MASK_2, 0x0C },
+ { PM4125_DIG_SWR_INTR_STATUS_0, 0x00 },
+ { PM4125_DIG_SWR_INTR_STATUS_1, 0x00 },
+ { PM4125_DIG_SWR_INTR_STATUS_2, 0x00 },
+ { PM4125_DIG_SWR_INTR_CLEAR_0, 0x00 },
+ { PM4125_DIG_SWR_INTR_CLEAR_1, 0x00 },
+ { PM4125_DIG_SWR_INTR_CLEAR_2, 0x00 },
+ { PM4125_DIG_SWR_INTR_LEVEL_0, 0x00 },
+ { PM4125_DIG_SWR_INTR_LEVEL_1, 0x2A },
+ { PM4125_DIG_SWR_INTR_LEVEL_2, 0x00 },
+ { PM4125_DIG_SWR_CDC_CONN_RX0_CTL, 0x00 },
+ { PM4125_DIG_SWR_CDC_CONN_RX1_CTL, 0x00 },
+ { PM4125_DIG_SWR_LOOP_BACK_MODE, 0x00 },
+ { PM4125_DIG_SWR_DRIVE_STRENGTH_0, 0x00 },
+ { PM4125_DIG_SWR_DIG_DEBUG_CTL, 0x00 },
+ { PM4125_DIG_SWR_DIG_DEBUG_EN, 0x00 },
+ { PM4125_DIG_SWR_DEM_BYPASS_DATA0, 0x55 },
+ { PM4125_DIG_SWR_DEM_BYPASS_DATA1, 0x55 },
+ { PM4125_DIG_SWR_DEM_BYPASS_DATA2, 0x55 },
+ { PM4125_DIG_SWR_DEM_BYPASS_DATA3, 0x01 },
+};
+
+static bool pm4125_rdwr_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PM4125_ANA_MICBIAS_MICB_1_2_EN:
+ case PM4125_ANA_MICBIAS_MICB_3_EN:
+ case PM4125_ANA_MICBIAS_LDO_1_SETTING:
+ case PM4125_ANA_MICBIAS_LDO_1_CTRL:
+ case PM4125_ANA_TX_AMIC1:
+ case PM4125_ANA_TX_AMIC2:
+ case PM4125_ANA_MBHC_MECH:
+ case PM4125_ANA_MBHC_ELECT:
+ case PM4125_ANA_MBHC_ZDET:
+ case PM4125_ANA_MBHC_BTN0_ZDET_VREF1:
+ case PM4125_ANA_MBHC_BTN1_ZDET_VREF2:
+ case PM4125_ANA_MBHC_BTN2_ZDET_VREF3:
+ case PM4125_ANA_MBHC_BTN3_ZDET_DBG_400:
+ case PM4125_ANA_MBHC_BTN4_ZDET_DBG_1400:
+ case PM4125_ANA_MBHC_MICB2_RAMP:
+ case PM4125_ANA_MBHC_CTL_1:
+ case PM4125_ANA_MBHC_CTL_2:
+ case PM4125_ANA_MBHC_PLUG_DETECT_CTL:
+ case PM4125_ANA_MBHC_ZDET_ANA_CTL:
+ case PM4125_ANA_MBHC_ZDET_RAMP_CTL:
+ case PM4125_ANA_MBHC_CTL_CLK:
+ case PM4125_ANA_NCP_EN:
+ case PM4125_ANA_NCP_VCTRL:
+ case PM4125_ANA_HPHPA_CNP_CTL_1:
+ case PM4125_ANA_HPHPA_CNP_CTL_2:
+ case PM4125_ANA_HPHPA_FSM_CLK:
+ case PM4125_ANA_HPHPA_L_GAIN:
+ case PM4125_ANA_HPHPA_R_GAIN:
+ case PM4125_ANA_HPHPA_SPARE_CTL:
+ case PM4125_SWR_HPHPA_HD2:
+ case PM4125_ANA_SURGE_EN:
+ case PM4125_ANA_COMBOPA_CTL:
+ case PM4125_ANA_COMBOPA_CTL_4:
+ case PM4125_ANA_COMBOPA_CTL_5:
+ case PM4125_ANA_RXLDO_CTL:
+ case PM4125_ANA_MBIAS_EN:
+ case PM4125_DIG_SWR_SWR_TX_CLK_RATE:
+ case PM4125_DIG_SWR_CDC_RST_CTL:
+ case PM4125_DIG_SWR_TOP_CLK_CFG:
+ case PM4125_DIG_SWR_CDC_RX_CLK_CTL:
+ case PM4125_DIG_SWR_CDC_TX_CLK_CTL:
+ case PM4125_DIG_SWR_SWR_RST_EN:
+ case PM4125_DIG_SWR_CDC_RX_RST:
+ case PM4125_DIG_SWR_CDC_RX0_CTL:
+ case PM4125_DIG_SWR_CDC_RX1_CTL:
+ case PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1:
+ case PM4125_DIG_SWR_CDC_COMP_CTL_0:
+ case PM4125_DIG_SWR_CDC_RX_DELAY_CTL:
+ case PM4125_DIG_SWR_CDC_RX_GAIN_0:
+ case PM4125_DIG_SWR_CDC_RX_GAIN_1:
+ case PM4125_DIG_SWR_CDC_RX_GAIN_CTL:
+ case PM4125_DIG_SWR_CDC_TX0_CTL:
+ case PM4125_DIG_SWR_CDC_TX1_CTL:
+ case PM4125_DIG_SWR_CDC_TX_RST:
+ case PM4125_DIG_SWR_CDC_REQ0_CTL:
+ case PM4125_DIG_SWR_CDC_REQ1_CTL:
+ case PM4125_DIG_SWR_CDC_RST:
+ case PM4125_DIG_SWR_CDC_AMIC_CTL:
+ case PM4125_DIG_SWR_CDC_DMIC_CTL:
+ case PM4125_DIG_SWR_CDC_DMIC1_CTL:
+ case PM4125_DIG_SWR_CDC_DMIC1_RATE:
+ case PM4125_DIG_SWR_PDM_WD_CTL0:
+ case PM4125_DIG_SWR_PDM_WD_CTL1:
+ case PM4125_DIG_SWR_INTR_MODE:
+ case PM4125_DIG_SWR_INTR_MASK_0:
+ case PM4125_DIG_SWR_INTR_MASK_1:
+ case PM4125_DIG_SWR_INTR_MASK_2:
+ case PM4125_DIG_SWR_INTR_CLEAR_0:
+ case PM4125_DIG_SWR_INTR_CLEAR_1:
+ case PM4125_DIG_SWR_INTR_CLEAR_2:
+ case PM4125_DIG_SWR_INTR_LEVEL_0:
+ case PM4125_DIG_SWR_INTR_LEVEL_1:
+ case PM4125_DIG_SWR_INTR_LEVEL_2:
+ case PM4125_DIG_SWR_CDC_CONN_RX0_CTL:
+ case PM4125_DIG_SWR_CDC_CONN_RX1_CTL:
+ case PM4125_DIG_SWR_LOOP_BACK_MODE:
+ case PM4125_DIG_SWR_DRIVE_STRENGTH_0:
+ case PM4125_DIG_SWR_DIG_DEBUG_CTL:
+ case PM4125_DIG_SWR_DIG_DEBUG_EN:
+ case PM4125_DIG_SWR_DEM_BYPASS_DATA0:
+ case PM4125_DIG_SWR_DEM_BYPASS_DATA1:
+ case PM4125_DIG_SWR_DEM_BYPASS_DATA2:
+ case PM4125_DIG_SWR_DEM_BYPASS_DATA3:
+ return true;
+ }
+
+ return false;
+}
+
+static bool pm4125_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PM4125_ANA_MBHC_RESULT_1:
+ case PM4125_ANA_MBHC_RESULT_2:
+ case PM4125_ANA_MBHC_RESULT_3:
+ case PM4125_ANA_MBHC_FSM_STATUS:
+ case PM4125_ANA_MBHC_ADC_RESULT:
+ case PM4125_ANA_MBHC_ZDET_CALIB_RESULT:
+ case PM4125_ANA_HPHPA_PA_STATUS:
+ case PM4125_DIG_SWR_CHIP_ID0:
+ case PM4125_DIG_SWR_CHIP_ID1:
+ case PM4125_DIG_SWR_CHIP_ID2:
+ case PM4125_DIG_SWR_CHIP_ID3:
+ case PM4125_DIG_SWR_INTR_STATUS_0:
+ case PM4125_DIG_SWR_INTR_STATUS_1:
+ case PM4125_DIG_SWR_INTR_STATUS_2:
+ return true;
+ }
+ return pm4125_rdwr_register(dev, reg);
+}
+
+static bool pm4125_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PM4125_ANA_MBHC_RESULT_1:
+ case PM4125_ANA_MBHC_RESULT_2:
+ case PM4125_ANA_MBHC_RESULT_3:
+ case PM4125_ANA_MBHC_FSM_STATUS:
+ case PM4125_ANA_MBHC_ADC_RESULT:
+ case PM4125_ANA_MBHC_ZDET_CALIB_RESULT:
+ case PM4125_ANA_HPHPA_PA_STATUS:
+ case PM4125_DIG_SWR_CHIP_ID0:
+ case PM4125_DIG_SWR_CHIP_ID1:
+ case PM4125_DIG_SWR_CHIP_ID2:
+ case PM4125_DIG_SWR_CHIP_ID3:
+ case PM4125_DIG_SWR_INTR_STATUS_0:
+ case PM4125_DIG_SWR_INTR_STATUS_1:
+ case PM4125_DIG_SWR_INTR_STATUS_2:
+ return true;
+ }
+
+ return false;
+}
+
+static const struct regmap_config pm4125_regmap_config = {
+ .name = "pm4125_csr",
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = pm4125_defaults,
+ .num_reg_defaults = ARRAY_SIZE(pm4125_defaults),
+ .max_register = PM4125_MAX_REGISTER,
+ .readable_reg = pm4125_readable_register,
+ .writeable_reg = pm4125_rdwr_register,
+ .volatile_reg = pm4125_volatile_register,
+};
+
+static const struct sdw_slave_ops pm4125_slave_ops = {
+ .update_status = wcd_update_status,
+ .interrupt_callback = pm4125_interrupt_callback,
+};
+
+static int pm4125_probe(struct sdw_slave *pdev, const struct sdw_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct pm4125_sdw_priv *priv;
+ u8 master_ch_mask[PM4125_MAX_SWR_CH_IDS];
+ int master_ch_mask_size = 0;
+ int ret, i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Port map index starts at 0, however the data port for this codec starts at index 1 */
+ if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) {
+ priv->is_tx = true;
+ ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping",
+ &pdev->m_port_map[1], PM4125_MAX_TX_SWR_PORTS);
+ } else {
+ ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping",
+ &pdev->m_port_map[1], PM4125_MAX_SWR_PORTS);
+ }
+
+ if (ret < 0)
+ dev_info(dev, "Error getting static port mapping for %s (%d)\n",
+ priv->is_tx ? "TX" : "RX", ret);
+
+ priv->sdev = pdev;
+ dev_set_drvdata(dev, priv);
+
+ pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
+ SDW_SCP_INT1_BUS_CLASH |
+ SDW_SCP_INT1_PARITY;
+ pdev->prop.lane_control_support = true;
+ pdev->prop.simple_clk_stop_capable = true;
+
+ memset(master_ch_mask, 0, PM4125_MAX_SWR_CH_IDS);
+
+ if (priv->is_tx) {
+ 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 (priv->is_tx) {
+ pdev->prop.source_ports = GENMASK(PM4125_MAX_TX_SWR_PORTS, 0);
+ pdev->prop.src_dpn_prop = pm4125_dpn_prop;
+ priv->ch_info = &pm4125_sdw_tx_ch_info[0];
+
+ for (i = 0; i < master_ch_mask_size; i++)
+ priv->ch_info[i].master_ch_mask = PM4125_SWRM_CH_MASK(master_ch_mask[i]);
+
+ pdev->prop.wake_capable = true;
+
+ priv->regmap = devm_regmap_init_sdw(pdev, &pm4125_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap), "regmap init failed\n");
+
+ /* Start in cache-only until device is enumerated */
+ regcache_cache_only(priv->regmap, true);
+ } else {
+ pdev->prop.sink_ports = GENMASK(PM4125_MAX_SWR_PORTS - 1, 0);
+ pdev->prop.sink_dpn_prop = pm4125_dpn_prop;
+ priv->ch_info = &pm4125_sdw_rx_ch_info[0];
+
+ for (i = 0; i < master_ch_mask_size; i++)
+ priv->ch_info[i].master_ch_mask = PM4125_SWRM_CH_MASK(master_ch_mask[i]);
+ }
+
+ ret = component_add(dev, &wcd_sdw_component_ops);
+ if (ret)
+ return ret;
+
+ /* Set suspended until aggregate device is bind */
+ pm_runtime_set_suspended(dev);
+
+ return 0;
+}
+
+static int pm4125_remove(struct sdw_slave *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_del(dev, &wcd_sdw_component_ops);
+
+ return 0;
+}
+
+static const struct sdw_device_id pm4125_slave_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x10c, 0), /* Soundwire pm4125 RX/TX Device ID */
+ { }
+};
+MODULE_DEVICE_TABLE(sdw, pm4125_slave_id);
+
+static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev)
+{
+ struct pm4125_sdw_priv *priv = dev_get_drvdata(dev);
+
+ if (priv->regmap) {
+ regcache_cache_only(priv->regmap, true);
+ regcache_mark_dirty(priv->regmap);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev)
+{
+ struct pm4125_sdw_priv *priv = dev_get_drvdata(dev);
+
+ if (priv->regmap) {
+ regcache_cache_only(priv->regmap, false);
+ regcache_sync(priv->regmap);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops pm4125_sdw_pm_ops = {
+ SET_RUNTIME_PM_OPS(pm4125_sdw_runtime_suspend, pm4125_sdw_runtime_resume, NULL)
+};
+
+static struct sdw_driver pm4125_codec_driver = {
+ .probe = pm4125_probe,
+ .remove = pm4125_remove,
+ .ops = &pm4125_slave_ops,
+ .id_table = pm4125_slave_id,
+ .driver = {
+ .name = "pm4125-codec",
+ .pm = &pm4125_sdw_pm_ops,
+ }
+};
+module_sdw_driver(pm4125_codec_driver);
+
+MODULE_DESCRIPTION("PM4125 SDW codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c
new file mode 100644
index 000000000000..8bc3b9994019
--- /dev/null
+++ b/sound/soc/codecs/pm4125.c
@@ -0,0 +1,1761 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+// Copyright (c) 2025, Linaro Ltd
+
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "pm4125.h"
+#include "wcd-mbhc-v2.h"
+
+#define WCD_MBHC_HS_V_MAX 1600
+#define PM4125_MBHC_MAX_BUTTONS 8
+
+#define PM4125_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_384000)
+
+/* Fractional Rates */
+#define PM4125_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define PM4125_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+/* Registers in SPMI addr space */
+#define PM4125_CODEC_RESET_REG 0xF3DB
+#define PM4125_CODEC_OFF 0x1
+#define PM4125_CODEC_ON 0x0
+#define PM4125_CODEC_FOUNDRY_ID_REG 0x7
+
+enum {
+ HPH_COMP_DELAY,
+ HPH_PA_DELAY,
+ AMIC2_BCS_ENABLE,
+};
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ NUM_CODEC_DAIS,
+};
+
+struct pm4125_priv {
+ struct sdw_slave *tx_sdw_dev;
+ struct pm4125_sdw_priv *sdw_priv[NUM_CODEC_DAIS];
+ struct device *txdev;
+ struct device *rxdev;
+ struct device_node *rxnode;
+ struct device_node *txnode;
+ struct regmap *regmap;
+ struct regmap *spmi_regmap;
+ /* mbhc module */
+ struct wcd_mbhc *wcd_mbhc;
+ struct wcd_mbhc_config mbhc_cfg;
+ struct wcd_mbhc_intr intr_ids;
+ struct wcd_common common;
+ struct irq_domain *virq;
+ const struct regmap_irq_chip *chip_desc;
+ struct regmap_irq_chip_data *irq_chip;
+ struct snd_soc_jack *jack;
+ unsigned long status_mask;
+ s32 micb_ref[PM4125_MAX_MICBIAS];
+ s32 pullup_ref[PM4125_MAX_MICBIAS];
+
+ int hphr_pdm_wd_int;
+ int hphl_pdm_wd_int;
+ bool comp1_enable;
+ bool comp2_enable;
+
+ atomic_t gloal_mbias_cnt;
+};
+
+static const char * const pm4125_power_supplies[] = {
+ "vdd-io", "vdd-cp", "vdd-mic-bias", "vdd-pa-vpos",
+};
+
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static const struct wcd_mbhc_field pm4125_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, PM4125_ANA_MBHC_MECH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, PM4125_ANA_MBHC_MECH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, PM4125_ANA_MBHC_MECH, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, PM4125_ANA_MBHC_PLUG_DETECT_CTL, 0x30),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, PM4125_ANA_MBHC_ELECT, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, PM4125_ANA_MBHC_PLUG_DETECT_CTL, 0x1F),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, PM4125_ANA_MBHC_MECH, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, PM4125_ANA_MBHC_MECH, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, PM4125_ANA_MBHC_MECH, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, PM4125_ANA_MBHC_MECH, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, PM4125_ANA_MBHC_ELECT, 0x06),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, PM4125_ANA_MBHC_ELECT, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, PM4125_ANA_MBHC_PLUG_DETECT_CTL, 0x0F),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, PM4125_ANA_MBHC_CTL_1, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, PM4125_ANA_MBHC_CTL_2, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, PM4125_ANA_MBHC_RESULT_3, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, PM4125_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, PM4125_ANA_MBHC_RESULT_3, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, PM4125_ANA_MBHC_RESULT_3, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, PM4125_ANA_MBHC_RESULT_3, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, PM4125_ANA_MBHC_RESULT_3, 0x07),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, PM4125_ANA_MBHC_ELECT, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, PM4125_ANA_MBHC_RESULT_3, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, PM4125_ANA_MICBIAS_MICB_1_2_EN, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, PM4125_ANA_HPHPA_CNP_CTL_2, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, PM4125_ANA_HPHPA_CNP_CTL_2, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, PM4125_ANA_HPHPA_CNP_CTL_2, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, PM4125_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, PM4125_ANA_MBHC_FSM_STATUS, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, PM4125_ANA_MBHC_CTL_2, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, PM4125_ANA_MBHC_FSM_STATUS, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, PM4125_ANA_HPHPA_CNP_CTL_2, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, PM4125_ANA_HPHPA_CNP_CTL_2, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, PM4125_DIG_SWR_INTR_STATUS_0, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, PM4125_DIG_SWR_INTR_STATUS_0, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, PM4125_ANA_MBHC_CTL_1, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, PM4125_ANA_MBHC_FSM_STATUS, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, PM4125_ANA_MBHC_FSM_STATUS, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, PM4125_ANA_MBHC_ADC_RESULT, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, PM4125_ANA_MICBIAS_LDO_1_SETTING, 0x3F),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, PM4125_ANA_MBHC_CTL_1, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, PM4125_ANA_MBHC_CTL_1, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, PM4125_ANA_MBHC_ZDET, 0x02),
+};
+
+static const struct regmap_irq pm4125_irqs[PM4125_NUM_IRQS] = {
+ REGMAP_IRQ_REG(PM4125_IRQ_MBHC_BUTTON_PRESS_DET, 0, BIT(0)),
+ REGMAP_IRQ_REG(PM4125_IRQ_MBHC_BUTTON_RELEASE_DET, 0, BIT(1)),
+ REGMAP_IRQ_REG(PM4125_IRQ_MBHC_ELECT_INS_REM_DET, 0, BIT(2)),
+ REGMAP_IRQ_REG(PM4125_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, BIT(3)),
+ REGMAP_IRQ_REG(PM4125_IRQ_MBHC_SW_DET, 0, BIT(4)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHR_OCP_INT, 0, BIT(5)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHR_CNP_INT, 0, BIT(6)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHL_OCP_INT, 0, BIT(7)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHL_CNP_INT, 1, BIT(0)),
+ REGMAP_IRQ_REG(PM4125_IRQ_EAR_CNP_INT, 1, BIT(1)),
+ REGMAP_IRQ_REG(PM4125_IRQ_EAR_SCD_INT, 1, BIT(2)),
+ REGMAP_IRQ_REG(PM4125_IRQ_AUX_CNP_INT, 1, BIT(3)),
+ REGMAP_IRQ_REG(PM4125_IRQ_AUX_SCD_INT, 1, BIT(4)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHL_PDM_WD_INT, 1, BIT(5)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHR_PDM_WD_INT, 1, BIT(6)),
+ REGMAP_IRQ_REG(PM4125_IRQ_AUX_PDM_WD_INT, 1, BIT(7)),
+ REGMAP_IRQ_REG(PM4125_IRQ_LDORT_SCD_INT, 2, BIT(0)),
+ REGMAP_IRQ_REG(PM4125_IRQ_MBHC_MOISTURE_INT, 2, BIT(1)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHL_SURGE_DET_INT, 2, BIT(2)),
+ REGMAP_IRQ_REG(PM4125_IRQ_HPHR_SURGE_DET_INT, 2, BIT(3)),
+};
+
+static int pm4125_handle_post_irq(void *data)
+{
+ struct pm4125_priv *pm4125 = (struct pm4125_priv *)data;
+
+ regmap_write(pm4125->regmap, PM4125_DIG_SWR_INTR_CLEAR_0, 0);
+ regmap_write(pm4125->regmap, PM4125_DIG_SWR_INTR_CLEAR_1, 0);
+ regmap_write(pm4125->regmap, PM4125_DIG_SWR_INTR_CLEAR_2, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const u32 pm4125_config_regs[] = {
+ PM4125_DIG_SWR_INTR_LEVEL_0,
+};
+
+static const struct regmap_irq_chip pm4125_regmap_irq_chip = {
+ .name = "pm4125",
+ .irqs = pm4125_irqs,
+ .num_irqs = ARRAY_SIZE(pm4125_irqs),
+ .num_regs = 3,
+ .status_base = PM4125_DIG_SWR_INTR_STATUS_0,
+ .mask_base = PM4125_DIG_SWR_INTR_MASK_0,
+ .ack_base = PM4125_DIG_SWR_INTR_CLEAR_0,
+ .use_ack = 1,
+ .clear_ack = 1,
+ .config_base = pm4125_config_regs,
+ .num_config_bases = ARRAY_SIZE(pm4125_config_regs),
+ .num_config_regs = 1,
+ .runtime_pm = true,
+ .handle_post_irq = pm4125_handle_post_irq,
+};
+
+static void pm4125_reset(struct pm4125_priv *pm4125)
+{
+ regmap_write(pm4125->spmi_regmap, PM4125_CODEC_RESET_REG, PM4125_CODEC_OFF);
+ usleep_range(20, 30);
+ regmap_write(pm4125->spmi_regmap, PM4125_CODEC_RESET_REG, PM4125_CODEC_ON);
+ usleep_range(5000, 5010);
+}
+
+static void pm4125_io_init(struct regmap *regmap)
+{
+ /* Disable HPH OCP */
+ regmap_update_bits(regmap, PM4125_ANA_HPHPA_CNP_CTL_2,
+ PM4125_ANA_HPHPA_CNP_OCP_EN_L_MASK | PM4125_ANA_HPHPA_CNP_OCP_EN_R_MASK,
+ PM4125_ANA_HPHPA_CNP_OCP_DISABLE);
+
+ /* Enable surge protection */
+ regmap_update_bits(regmap, PM4125_ANA_SURGE_EN, PM4125_ANA_SURGE_PROTECTION_HPHL_MASK,
+ FIELD_PREP(PM4125_ANA_SURGE_PROTECTION_HPHL_MASK,
+ PM4125_ANA_SURGE_PROTECTION_ENABLE));
+ regmap_update_bits(regmap, PM4125_ANA_SURGE_EN, PM4125_ANA_SURGE_PROTECTION_HPHR_MASK,
+ FIELD_PREP(PM4125_ANA_SURGE_PROTECTION_HPHR_MASK,
+ PM4125_ANA_SURGE_PROTECTION_ENABLE));
+
+ /* Disable mic bias 2 pull down */
+ regmap_update_bits(regmap, PM4125_ANA_MICBIAS_MICB_1_2_EN,
+ PM4125_ANA_MICBIAS_MICB2_PULL_DN_MASK,
+ FIELD_PREP(PM4125_ANA_MICBIAS_MICB2_PULL_DN_MASK,
+ PM4125_ANA_MICBIAS_MICB_PULL_DISABLE));
+}
+
+static int pm4125_global_mbias_disable(struct snd_soc_component *component)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ if (atomic_dec_and_test(&pm4125->gloal_mbias_cnt)) {
+
+ snd_soc_component_write_field(component, PM4125_ANA_MBIAS_EN,
+ PM4125_ANA_MBIAS_EN_V2I_MASK,
+ PM4125_ANA_MBIAS_EN_DISABLE);
+ snd_soc_component_write_field(component, PM4125_ANA_MBIAS_EN,
+ PM4125_ANA_MBIAS_EN_GLOBAL_MASK,
+ PM4125_ANA_MBIAS_EN_DISABLE);
+ }
+
+ return 0;
+}
+
+static int pm4125_global_mbias_enable(struct snd_soc_component *component)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ if (atomic_inc_return(&pm4125->gloal_mbias_cnt) == 1) {
+ snd_soc_component_write_field(component, PM4125_ANA_MBIAS_EN,
+ PM4125_ANA_MBIAS_EN_GLOBAL_MASK,
+ PM4125_ANA_MBIAS_EN_ENABLE);
+ snd_soc_component_write_field(component, PM4125_ANA_MBIAS_EN,
+ PM4125_ANA_MBIAS_EN_V2I_MASK,
+ PM4125_ANA_MBIAS_EN_ENABLE);
+ usleep_range(1000, 1100);
+ }
+
+ return 0;
+}
+
+static int pm4125_rx_clk_enable(struct snd_soc_component *component)
+{
+ pm4125_global_mbias_enable(component);
+
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_ANA_RX_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_ENABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_ANA_RX_DIV2_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_ENABLE);
+ usleep_range(5000, 5100);
+
+ snd_soc_component_write_field(component, PM4125_ANA_HPHPA_FSM_CLK,
+ PM4125_ANA_HPHPA_FSM_DIV_RATIO_MASK,
+ PM4125_ANA_HPHPA_FSM_DIV_RATIO_68);
+ snd_soc_component_write_field(component, PM4125_ANA_HPHPA_FSM_CLK,
+ PM4125_ANA_HPHPA_FSM_CLK_DIV_EN_MASK,
+ PM4125_ANA_HPHPA_FSM_CLK_DIV_ENABLE);
+ snd_soc_component_update_bits(component, PM4125_ANA_NCP_VCTRL, 0x07, 0x06);
+ snd_soc_component_write_field(component, PM4125_ANA_NCP_EN,
+ PM4125_ANA_NCP_ENABLE_MASK,
+ PM4125_ANA_NCP_ENABLE);
+ usleep_range(500, 510);
+
+ return 0;
+}
+
+static int pm4125_rx_clk_disable(struct snd_soc_component *component)
+{
+
+ snd_soc_component_write_field(component, PM4125_ANA_HPHPA_FSM_CLK,
+ PM4125_ANA_HPHPA_FSM_CLK_DIV_EN_MASK,
+ PM4125_ANA_HPHPA_FSM_CLK_DIV_DISABLE);
+ snd_soc_component_write_field(component, PM4125_ANA_HPHPA_FSM_CLK,
+ PM4125_ANA_HPHPA_FSM_DIV_RATIO_MASK,
+ 0x00);
+ snd_soc_component_write_field(component, PM4125_ANA_NCP_EN,
+ PM4125_ANA_NCP_ENABLE_MASK,
+ PM4125_ANA_NCP_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_ANA_RX_DIV2_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_ANA_RX_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_DISABLE);
+
+ pm4125_global_mbias_disable(component);
+
+ return 0;
+}
+
+
+static int pm4125_codec_enable_rxclk(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ pm4125_rx_clk_enable(component);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ pm4125_rx_clk_disable(component);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_hphl_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 pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, PM4125_ANA_HPHPA_CNP_CTL_1,
+ PM4125_ANA_HPHPA_CNP_CTL_1_EN_MASK,
+ PM4125_ANA_HPHPA_CNP_CTL_1_EN);
+ snd_soc_component_write_field(component, PM4125_SWR_HPHPA_HD2,
+ PM4125_SWR_HPHPA_HD2_LEFT_MASK,
+ PM4125_SWR_HPHPA_HD2_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (pm4125->comp1_enable) {
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHL_EN_MASK,
+ PM4125_DIG_SWR_COMP_ENABLE);
+
+ if (pm4125->comp2_enable)
+ snd_soc_component_write_field(component,
+ PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHR_EN_MASK,
+ PM4125_DIG_SWR_COMP_ENABLE);
+ /*
+ * 5ms sleep is required after COMP is enabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5100);
+ } else {
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHL_EN_MASK,
+ PM4125_DIG_SWR_COMP_DISABLE);
+ }
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX0_CTL,
+ PM4125_DIG_SWR_DSM_DITHER_EN_MASK,
+ PM4125_DIG_SWR_DSM_DITHER_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_GAIN_CTL,
+ PM4125_DIG_SWR_RX0_EN_MASK,
+ PM4125_DIG_SWR_RX_INPUT_ENABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_RX0_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_RX0_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_GAIN_CTL,
+ PM4125_DIG_SWR_RX0_EN_MASK,
+ PM4125_DIG_SWR_RX_INPUT_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX0_CTL,
+ PM4125_DIG_SWR_DSM_DITHER_EN_MASK,
+ PM4125_DIG_SWR_DSM_DITHER_ENABLE);
+ if (pm4125->comp1_enable)
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHL_EN_MASK,
+ PM4125_DIG_SWR_COMP_DISABLE);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_hphr_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 pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, PM4125_ANA_HPHPA_CNP_CTL_1,
+ PM4125_ANA_HPHPA_CNP_CTL_1_EN_MASK,
+ PM4125_ANA_HPHPA_CNP_CTL_1_EN);
+ snd_soc_component_write_field(component, PM4125_SWR_HPHPA_HD2,
+ PM4125_SWR_HPHPA_HD2_RIGHT_MASK,
+ PM4125_SWR_HPHPA_HD2_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (pm4125->comp2_enable) {
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHR_EN_MASK,
+ PM4125_DIG_SWR_COMP_ENABLE);
+ if (pm4125->comp1_enable)
+ snd_soc_component_write_field(component,
+ PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHL_EN_MASK,
+ PM4125_DIG_SWR_COMP_ENABLE);
+ /*
+ * 5ms sleep is required after COMP is enabled
+ * as per HW requirement
+ */
+ usleep_range(5000, 5100);
+ } else {
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHR_EN_MASK,
+ PM4125_DIG_SWR_COMP_DISABLE);
+ }
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX1_CTL,
+ PM4125_DIG_SWR_DSM_DITHER_EN_MASK,
+ PM4125_DIG_SWR_DSM_DITHER_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_GAIN_CTL,
+ PM4125_DIG_SWR_RX1_EN_MASK,
+ PM4125_DIG_SWR_RX_INPUT_ENABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_RX1_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_RX1_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_GAIN_CTL,
+ PM4125_DIG_SWR_RX1_EN_MASK,
+ PM4125_DIG_SWR_RX_INPUT_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX1_CTL,
+ PM4125_DIG_SWR_DSM_DITHER_EN_MASK,
+ PM4125_DIG_SWR_DSM_DITHER_ENABLE);
+ if (pm4125->comp2_enable)
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_COMP_CTL_0,
+ PM4125_DIG_SWR_COMP_HPHR_EN_MASK,
+ PM4125_DIG_SWR_COMP_DISABLE);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_ear_lo_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);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX0_CTL,
+ PM4125_DIG_SWR_DSM_DITHER_EN_MASK,
+ PM4125_DIG_SWR_DSM_DITHER_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_RX0_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_ENABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_GAIN_CTL,
+ PM4125_DIG_SWR_RX0_EN_MASK,
+ PM4125_DIG_SWR_RX_INPUT_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_CLK_CTL,
+ PM4125_DIG_SWR_RX0_CLK_EN_MASK,
+ PM4125_DIG_SWR_RX_CLK_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX_GAIN_CTL,
+ PM4125_DIG_SWR_RX0_EN_MASK,
+ PM4125_DIG_SWR_RX_INPUT_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_RX0_CTL,
+ PM4125_DIG_SWR_DSM_DITHER_EN_MASK,
+ PM4125_DIG_SWR_DSM_DITHER_ENABLE);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int pm4125_codec_enable_hphl_wdt_irq(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 pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(5000, 5100);
+ enable_irq(pm4125->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(pm4125->hphl_pdm_wd_int);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_hphr_wdt_irq(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 pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(5000, 5100);
+ enable_irq(pm4125->hphr_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(pm4125->hphr_pdm_wd_int);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ usleep_range(200, 210);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL1,
+ PM4125_WDT_ENABLE_MASK,
+ (PM4125_WDT_ENABLE_RX1_M | PM4125_WDT_ENABLE_RX1_L));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(5000, 5100);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL1,
+ PM4125_WDT_ENABLE_MASK, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ usleep_range(200, 210);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL0,
+ PM4125_WDT_ENABLE_MASK,
+ (PM4125_WDT_ENABLE_RX0_M | PM4125_WDT_ENABLE_RX0_L));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(5000, 5100);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL0,
+ PM4125_WDT_ENABLE_MASK, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_lo_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL_5, 0x04, 0x00);
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL_4, 0x0F, 0x0F);
+ usleep_range(1000, 1010);
+ snd_soc_component_write_field(component, PM4125_ANA_COMBOPA_CTL,
+ PM4125_ANA_COMBO_PA_SELECT_MASK,
+ PM4125_ANA_COMBO_PA_SELECT_LO);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL0,
+ PM4125_WDT_ENABLE_MASK,
+ (PM4125_WDT_ENABLE_RX0_M | PM4125_WDT_ENABLE_RX0_L));
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(5000, 5010);
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL_4, 0x0F, 0x04);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(2000, 2010);
+ snd_soc_component_write_field(component, PM4125_ANA_COMBOPA_CTL,
+ PM4125_ANA_COMBO_PA_SELECT_MASK,
+ PM4125_ANA_COMBO_PA_SELECT_EAR);
+ usleep_range(5000, 5100);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL0,
+ PM4125_WDT_ENABLE_MASK, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL_5, 0x04, 0x00);
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL_4, 0x0F, 0x0F);
+ usleep_range(1000, 1010);
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL,
+ PM4125_ANA_COMBO_PA_SELECT_MASK,
+ PM4125_ANA_COMBO_PA_SELECT_EAR);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL0,
+ PM4125_WDT_ENABLE_MASK,
+ (PM4125_WDT_ENABLE_RX0_M | PM4125_WDT_ENABLE_RX0_L));
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(5000, 5010);
+ snd_soc_component_update_bits(component, PM4125_ANA_COMBOPA_CTL_4, 0x0F, 0x04);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(5000, 5010);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_PDM_WD_CTL0,
+ PM4125_WDT_ENABLE_MASK, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_adc(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 pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable BCS for Headset mic */
+ if (w->shift == 1 &&
+ !(snd_soc_component_read(component, PM4125_ANA_TX_AMIC2) & 0x10)) {
+ set_bit(AMIC2_BCS_ENABLE, &pm4125->status_mask);
+ }
+ pm4125_global_mbias_enable(component);
+ if (w->shift)
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ PM4125_DIG_SWR_TX_ANA_TXD1_MODE_MASK,
+ PM4125_DIG_SWR_TXD_MODE_NORMAL);
+ else
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ PM4125_DIG_SWR_TX_ANA_TXD0_MODE_MASK,
+ PM4125_DIG_SWR_TXD_MODE_NORMAL);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (w->shift == 1 && test_bit(AMIC2_BCS_ENABLE, &pm4125->status_mask))
+ clear_bit(AMIC2_BCS_ENABLE, &pm4125->status_mask);
+
+ if (w->shift)
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ PM4125_DIG_SWR_TX_ANA_TXD1_MODE_MASK,
+ 0x00);
+ else
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1,
+ PM4125_DIG_SWR_TX_ANA_TXD0_MODE_MASK,
+ 0x00);
+ pm4125_global_mbias_disable(component);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u16 dmic_clk_reg = w->reg;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_AMIC_CTL,
+ PM4125_DIG_SWR_AMIC_SELECT_MASK,
+ PM4125_DIG_SWR_AMIC_SELECT_DMIC1);
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ PM4125_DIG_SWR_DMIC1_CLK_EN_MASK,
+ PM4125_DIG_SWR_DMIC1_CLK_ENABLE);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component, dmic_clk_reg,
+ PM4125_DIG_SWR_DMIC1_CLK_EN_MASK,
+ PM4125_DIG_SWR_DMIC1_CLK_DISABLE);
+ snd_soc_component_write_field(component, PM4125_DIG_SWR_CDC_AMIC_CTL,
+ PM4125_DIG_SWR_AMIC_SELECT_MASK,
+ PM4125_DIG_SWR_AMIC_SELECT_AMIC3);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_micbias_control(struct snd_soc_component *component, int micb_num, int req,
+ bool is_dapm)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+ int micb_index = micb_num - 1;
+ u16 micb_reg;
+ u8 pullup_mask = 0, enable_mask = 0;
+
+ if ((micb_index < 0) || (micb_index > PM4125_MAX_MICBIAS - 1)) {
+ dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n",
+ __func__, micb_index);
+ return -EINVAL;
+ }
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = PM4125_ANA_MICBIAS_MICB_1_2_EN;
+ pullup_mask = PM4125_ANA_MICBIAS_MICB1_PULL_UP_MASK;
+ enable_mask = 0x40;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = PM4125_ANA_MICBIAS_MICB_1_2_EN;
+ pullup_mask = PM4125_ANA_MICBIAS_MICB2_PULL_UP_MASK;
+ enable_mask = 0x04;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = PM4125_ANA_MICBIAS_MICB_3_EN;
+ pullup_mask = 0x02;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid micbias number: %d\n",
+ __func__, micb_num);
+ return -EINVAL;
+ }
+
+ switch (req) {
+ case MICB_PULLUP_ENABLE:
+ pm4125->pullup_ref[micb_index]++;
+ if ((pm4125->pullup_ref[micb_index] == 1) &&
+ (pm4125->micb_ref[micb_index] == 0))
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, pullup_mask);
+ break;
+ case MICB_PULLUP_DISABLE:
+ if (pm4125->pullup_ref[micb_index] > 0)
+ pm4125->pullup_ref[micb_index]--;
+ if ((pm4125->pullup_ref[micb_index] == 0) &&
+ (pm4125->micb_ref[micb_index] == 0))
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, 0x00);
+ break;
+ case MICB_ENABLE:
+ pm4125->micb_ref[micb_index]++;
+ if (pm4125->micb_ref[micb_index] == 1) {
+ pm4125_global_mbias_enable(component);
+ snd_soc_component_update_bits(component, micb_reg,
+ enable_mask, enable_mask);
+ }
+ break;
+ case MICB_DISABLE:
+ if (pm4125->micb_ref[micb_index] > 0)
+ pm4125->micb_ref[micb_index]--;
+ if ((pm4125->micb_ref[micb_index] == 0) &&
+ (pm4125->pullup_ref[micb_index] > 0)) {
+ snd_soc_component_update_bits(component, micb_reg,
+ pullup_mask, pullup_mask);
+ snd_soc_component_update_bits(component, micb_reg,
+ enable_mask, 0x00);
+ pm4125_global_mbias_disable(component);
+ } else if ((pm4125->micb_ref[micb_index] == 0) &&
+ (pm4125->pullup_ref[micb_index] == 0)) {
+ snd_soc_component_update_bits(component, micb_reg,
+ enable_mask, 0x00);
+ pm4125_global_mbias_disable(component);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_micbias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (micb_num == MIC_BIAS_3)
+ pm4125_micbias_control(component, micb_num, MICB_PULLUP_ENABLE, true);
+ else
+ pm4125_micbias_control(component, micb_num, MICB_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (micb_num == MIC_BIAS_3)
+ pm4125_micbias_control(component, micb_num, MICB_PULLUP_DISABLE, true);
+ else
+ pm4125_micbias_control(component, micb_num, MICB_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ pm4125_micbias_control(component, micb_num, MICB_PULLUP_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ pm4125_micbias_control(component, micb_num, MICB_PULLUP_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int pm4125_connect_port(struct pm4125_sdw_priv *sdw_priv, u8 port_idx, u8 ch_id, bool enable)
+{
+ struct sdw_port_config *port_config = &sdw_priv->port_config[port_idx - 1];
+ const struct wcd_sdw_ch_info *ch_info = &sdw_priv->ch_info[ch_id];
+ struct sdw_slave *sdev = sdw_priv->sdev;
+ u8 port_num = ch_info->port_num;
+ u8 ch_mask = ch_info->ch_mask;
+ u8 mstr_port_num, mstr_ch_mask;
+
+ port_config->num = port_num;
+
+ 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;
+ sdw_priv->master_channel_map[mstr_port_num] |= mstr_ch_mask;
+ } else {
+ port_config->ch_mask &= ~ch_mask;
+ sdw_priv->master_channel_map[mstr_port_num] &= ~mstr_ch_mask;
+ }
+
+ return 0;
+}
+
+static int pm4125_get_compander(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc;
+ bool hphr;
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ ucontrol->value.integer.value[0] = hphr ? pm4125->comp2_enable : pm4125->comp1_enable;
+ return 0;
+}
+
+static int pm4125_set_compander(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+ struct pm4125_sdw_priv *sdw_priv = pm4125->sdw_priv[AIF1_PB];
+ int value = ucontrol->value.integer.value[0];
+ struct soc_mixer_control *mc;
+ int portidx;
+ bool hphr;
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ if (hphr) {
+ if (value == pm4125->comp2_enable)
+ return 0;
+
+ pm4125->comp2_enable = value;
+ } else {
+ if (value == pm4125->comp1_enable)
+ return 0;
+
+ pm4125->comp1_enable = value;
+ }
+
+ portidx = sdw_priv->ch_info[mc->reg].port_num;
+
+ pm4125_connect_port(sdw_priv, portidx, mc->reg, value ? true : false);
+
+ return 1;
+}
+
+static int pm4125_get_swr_port(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(comp);
+ struct pm4125_sdw_priv *sdw_priv;
+ int dai_id = mixer->shift;
+ int ch_idx = mixer->reg;
+ int portidx;
+
+ sdw_priv = pm4125->sdw_priv[dai_id];
+ portidx = sdw_priv->ch_info[ch_idx].port_num;
+
+ ucontrol->value.integer.value[0] = sdw_priv->port_enable[portidx];
+
+ return 0;
+}
+
+static int pm4125_set_swr_port(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(comp);
+ struct pm4125_sdw_priv *sdw_priv;
+ int dai_id = mixer->shift;
+ int ch_idx = mixer->reg;
+ int portidx;
+ bool enable;
+
+ sdw_priv = pm4125->sdw_priv[dai_id];
+
+ portidx = sdw_priv->ch_info[ch_idx].port_num;
+
+ enable = ucontrol->value.integer.value[0];
+
+ if (enable == sdw_priv->port_enable[portidx]) {
+ pm4125_connect_port(sdw_priv, portidx, ch_idx, enable);
+ return 0;
+ }
+
+ sdw_priv->port_enable[portidx] = enable;
+ pm4125_connect_port(sdw_priv, portidx, ch_idx, enable);
+
+ return 1;
+}
+
+static void pm4125_mbhc_bias_control(struct snd_soc_component *component, bool enable)
+{
+ snd_soc_component_write_field(component, PM4125_ANA_MBHC_ELECT,
+ PM4125_ANA_MBHC_ELECT_BIAS_EN_MASK,
+ enable ? PM4125_ANA_MBHC_ELECT_BIAS_ENABLE :
+ PM4125_ANA_MBHC_ELECT_BIAS_DISABLE);
+}
+
+static void pm4125_mbhc_program_btn_thr(struct snd_soc_component *component,
+ int *btn_low, int *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i, vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = ((btn_high[i] * 2) / 25) & 0x3F;
+ snd_soc_component_write_field(component, PM4125_ANA_MBHC_BTN0_ZDET_VREF1 + i,
+ PM4125_ANA_MBHC_BTN0_THRESHOLD_MASK, vth << 2);
+ }
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .mbhc_bias = pm4125_mbhc_bias_control,
+ .set_btn_thr = pm4125_mbhc_program_btn_thr,
+};
+
+static int pm4125_mbhc_init(struct snd_soc_component *component)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+ struct wcd_mbhc_intr *intr_ids = &pm4125->intr_ids;
+
+ intr_ids->mbhc_sw_intr = regmap_irq_get_virq(pm4125->irq_chip, PM4125_IRQ_MBHC_SW_DET);
+
+ intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(pm4125->irq_chip,
+ PM4125_IRQ_MBHC_BUTTON_PRESS_DET);
+
+ intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(pm4125->irq_chip,
+ PM4125_IRQ_MBHC_BUTTON_RELEASE_DET);
+
+ intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(pm4125->irq_chip,
+ PM4125_IRQ_MBHC_ELECT_INS_REM_LEG_DET);
+
+ intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(pm4125->irq_chip,
+ PM4125_IRQ_MBHC_ELECT_INS_REM_DET);
+
+ intr_ids->hph_left_ocp = regmap_irq_get_virq(pm4125->irq_chip, PM4125_IRQ_HPHL_OCP_INT);
+
+ intr_ids->hph_right_ocp = regmap_irq_get_virq(pm4125->irq_chip, PM4125_IRQ_HPHR_OCP_INT);
+
+ pm4125->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, pm4125_mbhc_fields, false);
+ if (IS_ERR(pm4125->wcd_mbhc))
+ return PTR_ERR(pm4125->wcd_mbhc);
+
+ return 0;
+}
+
+static void pm4125_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ wcd_mbhc_deinit(pm4125->wcd_mbhc);
+}
+
+static const struct snd_kcontrol_new pm4125_snd_controls[] = {
+ SOC_SINGLE_EXT("HPHL_COMP Switch", PM4125_COMP_L, 0, 1, 0,
+ pm4125_get_compander, pm4125_set_compander),
+ SOC_SINGLE_EXT("HPHR_COMP Switch", PM4125_COMP_R, 1, 1, 0,
+ pm4125_get_compander, pm4125_set_compander),
+
+ SOC_SINGLE_TLV("HPHL Volume", PM4125_ANA_HPHPA_L_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", PM4125_ANA_HPHPA_R_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", PM4125_ANA_TX_AMIC1, 0, 8, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", PM4125_ANA_TX_AMIC2, 0, 8, 0,
+ analog_gain),
+
+ SOC_SINGLE_EXT("HPHL Switch", PM4125_HPH_L, 0, 1, 0,
+ pm4125_get_swr_port, pm4125_set_swr_port),
+ SOC_SINGLE_EXT("HPHR Switch", PM4125_HPH_R, 0, 1, 0,
+ pm4125_get_swr_port, pm4125_set_swr_port),
+
+ SOC_SINGLE_EXT("ADC1 Switch", PM4125_ADC1, 1, 1, 0,
+ pm4125_get_swr_port, pm4125_set_swr_port),
+ SOC_SINGLE_EXT("ADC2 Switch", PM4125_ADC2, 1, 1, 0,
+ pm4125_get_swr_port, pm4125_set_swr_port),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new lo_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+ "INP2", "INP3"
+};
+
+static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE(PM4125_ANA_TX_AMIC2, 4,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const struct snd_soc_dapm_widget pm4125_dapm_widgets[] = {
+ /* Input widgets */
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("IN1_HPHL"),
+ SND_SOC_DAPM_INPUT("IN2_HPHR"),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, pm4125_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, pm4125_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+ /* TX mixers */
+ SND_SOC_DAPM_MIXER("ADC1_MIXER", SND_SOC_NOPM, 0, 0, adc1_switch, ARRAY_SIZE(adc1_switch)),
+ SND_SOC_DAPM_MIXER("ADC2_MIXER", SND_SOC_NOPM, 1, 0, adc2_switch, ARRAY_SIZE(adc2_switch)),
+
+ /* MIC_BIAS widgets */
+ SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, pm4125_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, pm4125_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, pm4125_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("PA_VPOS", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* RX widgets */
+ SND_SOC_DAPM_PGA_E("EAR PGA", PM4125_ANA_COMBOPA_CTL, 7, 0, NULL, 0,
+ pm4125_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LO PGA", PM4125_ANA_COMBOPA_CTL, 7, 0, NULL, 0,
+ pm4125_codec_enable_lo_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PGA", PM4125_ANA_HPHPA_CNP_CTL_2, 7, 0, NULL, 0,
+ pm4125_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PGA", PM4125_ANA_HPHPA_CNP_CTL_2, 6, 0, NULL, 0,
+ pm4125_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, pm4125_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, pm4125_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, pm4125_codec_ear_lo_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+
+ SND_SOC_DAPM_SUPPLY("HPHL_WDT_IRQ", SND_SOC_NOPM, 0, 0, pm4125_codec_enable_hphl_wdt_irq,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("HPHR_WDT_IRQ", SND_SOC_NOPM, 0, 0, pm4125_codec_enable_hphr_wdt_irq,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0, pm4125_codec_enable_rxclk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+
+ /* RX mixer widgets */
+ SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, ear_rdac_switch,
+ ARRAY_SIZE(ear_rdac_switch)),
+ SND_SOC_DAPM_MIXER("LO_RDAC", SND_SOC_NOPM, 0, 0, lo_rdac_switch,
+ ARRAY_SIZE(lo_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, hphl_rdac_switch,
+ ARRAY_SIZE(hphl_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, hphr_rdac_switch,
+ ARRAY_SIZE(hphr_rdac_switch)),
+
+ /* TX output widgets */
+ SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+
+ /* RX output widgets */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("LO"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+
+ /* MIC_BIAS pull up widgets */
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ pm4125_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ pm4125_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ pm4125_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, PM4125_DIG_SWR_CDC_DMIC1_CTL, 0, 0,
+ pm4125_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, PM4125_DIG_SWR_CDC_DMIC1_CTL, 1, 0,
+ pm4125_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* TX mixer widgets */
+ SND_SOC_DAPM_MIXER("DMIC1_MIXER", SND_SOC_NOPM, 0, 0, dmic1_switch,
+ ARRAY_SIZE(dmic1_switch)),
+ SND_SOC_DAPM_MIXER("DMIC2_MIXER", SND_SOC_NOPM, 1, 0, dmic2_switch,
+ ARRAY_SIZE(dmic2_switch)),
+
+ /* Output widgets */
+ SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route pm4125_audio_map[] = {
+ { "ADC1_OUTPUT", NULL, "ADC1_MIXER" },
+ { "ADC1_MIXER", "Switch", "ADC1" },
+ { "ADC1", NULL, "AMIC1" },
+
+ { "ADC2_OUTPUT", NULL, "ADC2_MIXER" },
+ { "ADC2_MIXER", "Switch", "ADC2" },
+ { "ADC2", NULL, "ADC2 MUX" },
+ { "ADC2 MUX", "INP3", "AMIC3" },
+ { "ADC2 MUX", "INP2", "AMIC2" },
+
+ { "IN1_HPHL", NULL, "PA_VPOS" },
+ { "RX1", NULL, "IN1_HPHL" },
+ { "RX1", NULL, "RXCLK" },
+ { "RX1", NULL, "HPHL_WDT_IRQ" },
+ { "RDAC1", NULL, "RX1" },
+ { "HPHL_RDAC", "Switch", "RDAC1" },
+ { "HPHL PGA", NULL, "HPHL_RDAC" },
+ { "HPHL", NULL, "HPHL PGA" },
+
+ { "IN2_HPHR", NULL, "PA_VPOS" },
+ { "RX2", NULL, "IN2_HPHR" },
+ { "RX2", NULL, "RXCLK" },
+ { "RX2", NULL, "HPHR_WDT_IRQ" },
+ { "RDAC2", NULL, "RX2" },
+ { "HPHR_RDAC", "Switch", "RDAC2" },
+ { "HPHR PGA", NULL, "HPHR_RDAC" },
+ { "HPHR", NULL, "HPHR PGA" },
+
+ { "RDAC3", NULL, "RX1" },
+ { "EAR_RDAC", "Switch", "RDAC3" },
+ { "EAR PGA", NULL, "EAR_RDAC" },
+ { "EAR", NULL, "EAR PGA" },
+
+ { "LO_RDAC", "Switch", "RDAC3" },
+ { "LO PGA", NULL, "LO_RDAC" },
+ { "LO", NULL, "LO PGA" },
+
+ { "DMIC1_OUTPUT", NULL, "DMIC1_MIXER" },
+ { "DMIC1_MIXER", "Switch", "DMIC1" },
+
+ { "DMIC2_OUTPUT", NULL, "DMIC2_MIXER" },
+ { "DMIC2_MIXER", "Switch", "DMIC2" },
+};
+
+static int pm4125_set_micbias_data(struct device *dev, struct pm4125_priv *pm4125)
+{
+ regmap_update_bits(pm4125->regmap, PM4125_ANA_MICBIAS_LDO_1_SETTING,
+ PM4125_ANA_MICBIAS_MICB_OUT_VAL_MASK, pm4125->common.micb_vout[0]);
+ return 0;
+}
+
+static irqreturn_t pm4125_wd_handle_irq(int irq, void *data)
+{
+ /*
+ * HPHR/HPHL Watchdog interrupt threaded handler
+ * Watchdog interrupts are expected to be enabled when switching on the HPHL/R
+ * in order to make sure the interrupts are acked by the regmap_irq handler
+ * io allow PDM sync. We could leave those interrupts masked but we would
+ * not haveany valid way to enable/disable them without violating irq layers.
+ *
+ * The HPHR/HPHL Watchdog interrupts are handled by regmap_irq, so requesting
+ * a threaded handler is the safest way to be able to ack those interrupts
+ * without colliding with the regmap_irq setup.
+ */
+ return IRQ_HANDLED;
+}
+
+static const struct irq_chip pm4125_codec_irq_chip = {
+ .name = "pm4125_codec",
+};
+
+static int pm4125_codec_irq_chip_map(struct irq_domain *irqd, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &pm4125_codec_irq_chip, handle_simple_irq);
+ irq_set_nested_thread(virq, 1);
+ irq_set_noprobe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops pm4125_domain_ops = {
+ .map = pm4125_codec_irq_chip_map,
+};
+
+static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev)
+{
+ pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL);
+ if (!(pm4125->virq)) {
+ dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
+ return -EINVAL;
+ }
+
+ return devm_regmap_add_irq_chip(dev, pm4125->regmap, irq_create_mapping(pm4125->virq, 0),
+ IRQF_ONESHOT, 0, pm4125->chip_desc,
+ &pm4125->irq_chip);
+}
+
+static int pm4125_soc_codec_probe(struct snd_soc_component *component)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+ struct sdw_slave *tx_sdw_dev = pm4125->tx_sdw_dev;
+ struct device *dev = component->dev;
+ unsigned long time_left;
+ int i, ret;
+
+ time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete,
+ msecs_to_jiffies(5000));
+ if (!time_left) {
+ dev_err(dev, "soundwire device init timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ snd_soc_component_init_regmap(component, pm4125->regmap);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ pm4125_io_init(pm4125->regmap);
+
+ /* Set all interrupts as edge triggered */
+ for (i = 0; i < pm4125_regmap_irq_chip.num_regs; i++)
+ regmap_write(pm4125->regmap, (PM4125_DIG_SWR_INTR_LEVEL_0 + i), 0);
+
+ pm_runtime_put(dev);
+
+ pm4125->hphr_pdm_wd_int = regmap_irq_get_virq(pm4125->irq_chip, PM4125_IRQ_HPHR_PDM_WD_INT);
+ pm4125->hphl_pdm_wd_int = regmap_irq_get_virq(pm4125->irq_chip, PM4125_IRQ_HPHL_PDM_WD_INT);
+
+ /* Request for watchdog interrupts */
+ ret = devm_request_threaded_irq(dev, pm4125->hphr_pdm_wd_int, NULL, pm4125_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHR PDM WDOG INT", pm4125);
+ if (ret)
+ dev_err(dev, "Failed to request HPHR wdt interrupt: %d\n", ret);
+
+ ret = devm_request_threaded_irq(dev, pm4125->hphl_pdm_wd_int, NULL, pm4125_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHL PDM WDOG INT", pm4125);
+ if (ret)
+ dev_err(dev, "Failed to request HPHL wdt interrupt: %d\n", ret);
+
+ disable_irq_nosync(pm4125->hphr_pdm_wd_int);
+ disable_irq_nosync(pm4125->hphl_pdm_wd_int);
+
+ ret = pm4125_mbhc_init(component);
+ if (ret)
+ dev_err(component->dev, "mbhc initialization failed\n");
+
+ return ret;
+}
+
+static void pm4125_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct pm4125_priv *pm4125 = snd_soc_component_get_drvdata(component);
+
+ pm4125_mbhc_deinit(component);
+ free_irq(pm4125->hphl_pdm_wd_int, pm4125);
+ free_irq(pm4125->hphr_pdm_wd_int, pm4125);
+}
+
+static int pm4125_codec_set_jack(struct snd_soc_component *comp, struct snd_soc_jack *jack,
+ void *data)
+{
+ struct pm4125_priv *pm4125 = dev_get_drvdata(comp->dev);
+ int ret = 0;
+
+ if (jack)
+ ret = wcd_mbhc_start(pm4125->wcd_mbhc, &pm4125->mbhc_cfg, jack);
+ else
+ wcd_mbhc_stop(pm4125->wcd_mbhc);
+
+ return ret;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_pm4125 = {
+ .name = "pm4125_codec",
+ .probe = pm4125_soc_codec_probe,
+ .remove = pm4125_soc_codec_remove,
+ .controls = pm4125_snd_controls,
+ .num_controls = ARRAY_SIZE(pm4125_snd_controls),
+ .dapm_widgets = pm4125_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pm4125_dapm_widgets),
+ .dapm_routes = pm4125_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(pm4125_audio_map),
+ .set_jack = pm4125_codec_set_jack,
+ .endianness = 1,
+};
+
+static int pm4125_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct pm4125_priv *pm4125 = dev_get_drvdata(dai->dev);
+ struct pm4125_sdw_priv *sdw_priv = pm4125->sdw_priv[dai->id];
+
+ return pm4125_sdw_hw_params(sdw_priv, substream, params, dai);
+}
+
+static int pm4125_codec_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct pm4125_priv *pm4125 = dev_get_drvdata(dai->dev);
+ struct pm4125_sdw_priv *sdw_priv = pm4125->sdw_priv[dai->id];
+
+ return sdw_stream_remove_slave(sdw_priv->sdev, sdw_priv->sruntime);
+}
+
+static int pm4125_codec_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction)
+{
+ struct pm4125_priv *pm4125 = dev_get_drvdata(dai->dev);
+ struct pm4125_sdw_priv *sdw_priv = pm4125->sdw_priv[dai->id];
+
+ sdw_priv->sruntime = stream;
+
+ return 0;
+}
+
+static int pm4125_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 pm4125_priv *pm4125 = dev_get_drvdata(dai->dev);
+ struct pm4125_sdw_priv *sdw_priv = pm4125->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] = sdw_priv->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] = sdw_priv->master_channel_map[i];
+
+ *tx_num = i;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops pm4125_sdw_dai_ops = {
+ .hw_params = pm4125_codec_hw_params,
+ .hw_free = pm4125_codec_free,
+ .set_stream = pm4125_codec_set_sdw_stream,
+ .get_channel_map = pm4125_get_channel_map,
+};
+
+static struct snd_soc_dai_driver pm4125_dais[] = {
+ [0] = {
+ .name = "pm4125-sdw-rx",
+ .playback = {
+ .stream_name = "PM4125 AIF Playback",
+ .rates = PM4125_RATES | PM4125_FRAC_RATES,
+ .formats = PM4125_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &pm4125_sdw_dai_ops,
+ },
+ [1] = {
+ .name = "pm4125-sdw-tx",
+ .capture = {
+ .stream_name = "PM4125 AIF Capture",
+ .rates = PM4125_RATES,
+ .formats = PM4125_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &pm4125_sdw_dai_ops,
+ },
+};
+
+static int pm4125_bind(struct device *dev)
+{
+ struct pm4125_priv *pm4125 = dev_get_drvdata(dev);
+ struct device_link *devlink;
+ int ret;
+
+ /* Initialize device pointers to NULL for safe cleanup */
+ pm4125->rxdev = NULL;
+ pm4125->txdev = NULL;
+
+ /* Give the soundwire subdevices some more time to settle */
+ usleep_range(15000, 15010);
+
+ ret = component_bind_all(dev, pm4125);
+ if (ret) {
+ dev_err(dev, "Slave bind failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ pm4125->rxdev = of_sdw_find_device_by_node(pm4125->rxnode);
+ if (!pm4125->rxdev) {
+ dev_err(dev, "could not find rxslave with matching of node\n");
+ ret = -EINVAL;
+ goto error_unbind_all;
+ }
+
+ pm4125->sdw_priv[AIF1_PB] = dev_get_drvdata(pm4125->rxdev);
+ pm4125->sdw_priv[AIF1_PB]->pm4125 = pm4125;
+
+ pm4125->txdev = of_sdw_find_device_by_node(pm4125->txnode);
+ if (!pm4125->txdev) {
+ dev_err(dev, "could not find txslave with matching of node\n");
+ ret = -EINVAL;
+ goto error_put_rx;
+ }
+
+ pm4125->sdw_priv[AIF1_CAP] = dev_get_drvdata(pm4125->txdev);
+ pm4125->sdw_priv[AIF1_CAP]->pm4125 = pm4125;
+
+ pm4125->tx_sdw_dev = dev_to_sdw_dev(pm4125->txdev);
+ if (!pm4125->tx_sdw_dev) {
+ dev_err(dev, "could not get txslave with matching of dev\n");
+ ret = -EINVAL;
+ goto error_put_tx;
+ }
+
+ /*
+ * As TX is the main CSR reg interface, which should not be suspended first.
+ * expicilty add the dependency link
+ */
+ devlink = device_link_add(pm4125->rxdev, pm4125->txdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
+ if (!devlink) {
+ dev_err(dev, "Could not devlink TX and RX\n");
+ ret = -EINVAL;
+ goto error_put_tx;
+ }
+
+ devlink = device_link_add(dev, pm4125->txdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
+ if (!devlink) {
+ dev_err(dev, "Could not devlink PM4125 and TX\n");
+ ret = -EINVAL;
+ goto link_remove_rx_tx;
+ }
+
+ devlink = device_link_add(dev, pm4125->rxdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
+ if (!devlink) {
+ dev_err(dev, "Could not devlink PM4125 and RX\n");
+ ret = -EINVAL;
+ goto link_remove_dev_tx;
+ }
+
+ pm4125->regmap = pm4125->sdw_priv[AIF1_CAP]->regmap;
+ if (!pm4125->regmap) {
+ dev_err(dev, "could not get TX device regmap\n");
+ ret = -EINVAL;
+ goto link_remove_dev_rx;
+ }
+
+ ret = pm4125_irq_init(pm4125, dev);
+ if (ret) {
+ dev_err(dev, "IRQ init failed: %d\n", ret);
+ goto link_remove_dev_rx;
+ }
+
+ pm4125->sdw_priv[AIF1_PB]->slave_irq = pm4125->virq;
+ pm4125->sdw_priv[AIF1_CAP]->slave_irq = pm4125->virq;
+
+ pm4125_set_micbias_data(dev, pm4125);
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_pm4125,
+ pm4125_dais, ARRAY_SIZE(pm4125_dais));
+ if (!ret)
+ return ret;
+
+ dev_err(dev, "Codec registration failed\n");
+
+link_remove_dev_rx:
+ device_link_remove(dev, pm4125->rxdev);
+link_remove_dev_tx:
+ device_link_remove(dev, pm4125->txdev);
+link_remove_rx_tx:
+ device_link_remove(pm4125->rxdev, pm4125->txdev);
+error_put_tx:
+ put_device(pm4125->txdev);
+error_put_rx:
+ put_device(pm4125->rxdev);
+error_unbind_all:
+ component_unbind_all(dev, pm4125);
+ return ret;
+}
+
+static void pm4125_unbind(struct device *dev)
+{
+ struct pm4125_priv *pm4125 = dev_get_drvdata(dev);
+
+ snd_soc_unregister_component(dev);
+ devm_regmap_del_irq_chip(dev, irq_find_mapping(pm4125->virq, 0),
+ pm4125->irq_chip);
+ device_link_remove(dev, pm4125->txdev);
+ device_link_remove(dev, pm4125->rxdev);
+ device_link_remove(pm4125->rxdev, pm4125->txdev);
+
+ /* Release device references acquired in bind */
+ if (pm4125->txdev)
+ put_device(pm4125->txdev);
+ if (pm4125->rxdev)
+ put_device(pm4125->rxdev);
+
+ component_unbind_all(dev, pm4125);
+}
+
+static const struct component_master_ops pm4125_comp_ops = {
+ .bind = pm4125_bind,
+ .unbind = pm4125_unbind,
+};
+
+static int pm4125_add_slave_components(struct pm4125_priv *pm4125, struct device *dev,
+ struct component_match **matchptr)
+{
+ struct device_node *np = dev->of_node;
+
+ pm4125->rxnode = of_parse_phandle(np, "qcom,rx-device", 0);
+ if (!pm4125->rxnode)
+ return dev_err_probe(dev, -ENODEV, "Couldn't parse phandle to qcom,rx-device\n");
+ component_match_add_release(dev, matchptr, component_release_of, component_compare_of,
+ pm4125->rxnode);
+
+ pm4125->txnode = of_parse_phandle(np, "qcom,tx-device", 0);
+ if (!pm4125->txnode)
+ return dev_err_probe(dev, -ENODEV, "Couldn't parse phandle to qcom,tx-device\n");
+ component_match_add_release(dev, matchptr, component_release_of, component_compare_of,
+ pm4125->txnode);
+
+ return 0;
+}
+
+static int pm4125_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ struct device *dev = &pdev->dev;
+ struct regmap_irq_chip *chip_desc;
+ struct pm4125_priv *pm4125;
+ struct wcd_mbhc_config *cfg;
+ int ret;
+
+ pm4125 = devm_kzalloc(dev, sizeof(*pm4125), GFP_KERNEL);
+ if (!pm4125)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, pm4125);
+
+ chip_desc = devm_kmemdup(dev, &pm4125_regmap_irq_chip,
+ sizeof(pm4125_regmap_irq_chip),
+ GFP_KERNEL);
+ if (!chip_desc)
+ return -ENOMEM;
+ chip_desc->irq_drv_data = pm4125;
+ pm4125->chip_desc = chip_desc;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(pm4125_power_supplies),
+ pm4125_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
+
+ pm4125->spmi_regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!pm4125->spmi_regmap)
+ return -ENXIO;
+
+ pm4125_reset(pm4125);
+
+ pm4125->common.dev = dev;
+ pm4125->common.max_bias = 3;
+ ret = wcd_dt_parse_micbias_info(&pm4125->common);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get micbias\n");
+
+ atomic_set(&pm4125->gloal_mbias_cnt, 0);
+
+ cfg = &pm4125->mbhc_cfg;
+ cfg->mbhc_micbias = MIC_BIAS_2;
+ cfg->anc_micbias = MIC_BIAS_2;
+ cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
+ cfg->num_btn = PM4125_MBHC_MAX_BUTTONS;
+ cfg->micb_mv = pm4125->common.micb_mv[1];
+ cfg->linein_th = 5000;
+ cfg->hs_thr = 1700;
+ cfg->hph_thr = 50;
+
+ wcd_dt_parse_mbhc_data(dev, &pm4125->mbhc_cfg);
+
+ ret = pm4125_add_slave_components(pm4125, dev, &match);
+ if (ret)
+ return ret;
+
+ ret = component_master_add_with_match(dev, &pm4125_comp_ops, match);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+}
+
+static void pm4125_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_master_del(&pdev->dev, &pm4125_comp_ops);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+}
+
+static const struct of_device_id pm4125_of_match[] = {
+ { .compatible = "qcom,pm4125-codec" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pm4125_of_match);
+
+static struct platform_driver pm4125_codec_driver = {
+ .probe = pm4125_probe,
+ .remove = pm4125_remove,
+ .driver = {
+ .name = "pm4125_codec",
+ .of_match_table = pm4125_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(pm4125_codec_driver);
+MODULE_DESCRIPTION("PM4125 audio codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pm4125.h b/sound/soc/codecs/pm4125.h
new file mode 100644
index 000000000000..25fd3106f44f
--- /dev/null
+++ b/sound/soc/codecs/pm4125.h
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _PM4125_REGISTERS_H
+#define _PM4125_REGISTERS_H
+
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include "wcd-common.h"
+
+#define PM4125_ANA_BASE_ADDR 0x3000
+#define PM4125_DIG_BASE_ADDR 0x3400
+
+#define PM4125_ANA_MICBIAS_MICB_1_2_EN (PM4125_ANA_BASE_ADDR+0x040)
+#define PM4125_ANA_MICBIAS_MICB1_PULL_UP_MASK BIT(5)
+#define PM4125_ANA_MICBIAS_MICB2_PULL_UP_MASK BIT(1)
+#define PM4125_ANA_MICBIAS_MICB2_PULL_DN_MASK BIT(0)
+#define PM4125_ANA_MICBIAS_MICB_PULL_ENABLE 1
+#define PM4125_ANA_MICBIAS_MICB_PULL_DISABLE 0
+#define PM4125_ANA_MICBIAS_MICB_3_EN (PM4125_ANA_BASE_ADDR+0x041)
+#define PM4125_ANA_MICBIAS_LDO_1_SETTING (PM4125_ANA_BASE_ADDR+0x042)
+#define PM4125_ANA_MICBIAS_MICB_OUT_VAL_MASK GENMASK(7, 3)
+#define PM4125_ANA_MICBIAS_LDO_1_CTRL (PM4125_ANA_BASE_ADDR+0x043)
+#define PM4125_ANA_TX_AMIC1 (PM4125_ANA_BASE_ADDR+0x047)
+#define PM4125_ANA_TX_AMIC2 (PM4125_ANA_BASE_ADDR+0x048)
+#define PM4125_ANA_MBHC_MECH (PM4125_ANA_BASE_ADDR+0x05A)
+#define PM4125_ANA_MBHC_ELECT (PM4125_ANA_BASE_ADDR+0x05B)
+#define PM4125_ANA_MBHC_ELECT_BIAS_EN_MASK BIT(0)
+#define PM4125_ANA_MBHC_ELECT_BIAS_ENABLE 1
+#define PM4125_ANA_MBHC_ELECT_BIAS_DISABLE 0
+#define PM4125_ANA_MBHC_ZDET (PM4125_ANA_BASE_ADDR+0x05C)
+#define PM4125_ANA_MBHC_RESULT_1 (PM4125_ANA_BASE_ADDR+0x05D)
+#define PM4125_ANA_MBHC_RESULT_2 (PM4125_ANA_BASE_ADDR+0x05E)
+#define PM4125_ANA_MBHC_RESULT_3 (PM4125_ANA_BASE_ADDR+0x05F)
+#define PM4125_ANA_MBHC_BTN0_ZDET_VREF1 (PM4125_ANA_BASE_ADDR+0x060)
+#define PM4125_ANA_MBHC_BTN0_THRESHOLD_MASK GENMASK(7, 2)
+#define PM4125_ANA_MBHC_BTN1_ZDET_VREF2 (PM4125_ANA_BASE_ADDR+0x061)
+#define PM4125_ANA_MBHC_BTN2_ZDET_VREF3 (PM4125_ANA_BASE_ADDR+0x062)
+#define PM4125_ANA_MBHC_BTN3_ZDET_DBG_400 (PM4125_ANA_BASE_ADDR+0x063)
+#define PM4125_ANA_MBHC_BTN4_ZDET_DBG_1400 (PM4125_ANA_BASE_ADDR+0x064)
+#define PM4125_ANA_MBHC_MICB2_RAMP (PM4125_ANA_BASE_ADDR+0x065)
+#define PM4125_ANA_MBHC_CTL_1 (PM4125_ANA_BASE_ADDR+0x066)
+#define PM4125_ANA_MBHC_CTL_2 (PM4125_ANA_BASE_ADDR+0x067)
+#define PM4125_ANA_MBHC_PLUG_DETECT_CTL (PM4125_ANA_BASE_ADDR+0x068)
+#define PM4125_ANA_MBHC_ZDET_ANA_CTL (PM4125_ANA_BASE_ADDR+0x069)
+#define PM4125_ANA_MBHC_ZDET_RAMP_CTL (PM4125_ANA_BASE_ADDR+0x06A)
+#define PM4125_ANA_MBHC_FSM_STATUS (PM4125_ANA_BASE_ADDR+0x06B)
+#define PM4125_ANA_MBHC_ADC_RESULT (PM4125_ANA_BASE_ADDR+0x06C)
+#define PM4125_ANA_MBHC_CTL_CLK (PM4125_ANA_BASE_ADDR+0x06D)
+#define PM4125_ANA_MBHC_ZDET_CALIB_RESULT (PM4125_ANA_BASE_ADDR+0x072)
+#define PM4125_ANA_NCP_EN (PM4125_ANA_BASE_ADDR+0x077)
+#define PM4125_ANA_NCP_ENABLE_MASK BIT(0)
+#define PM4125_ANA_NCP_ENABLE 1
+#define PM4125_ANA_NCP_DISABLE 0
+#define PM4125_ANA_NCP_VCTRL (PM4125_ANA_BASE_ADDR+0x07C)
+#define PM4125_ANA_HPHPA_CNP_CTL_1 (PM4125_ANA_BASE_ADDR+0x083)
+#define PM4125_ANA_HPHPA_CNP_CTL_1_EN_MASK BIT(1)
+#define PM4125_ANA_HPHPA_CNP_CTL_1_EN 1
+#define PM4125_ANA_HPHPA_CNP_CTL_2 (PM4125_ANA_BASE_ADDR+0x084)
+#define PM4125_ANA_HPHPA_CNP_OCP_EN_L_MASK BIT(1)
+#define PM4125_ANA_HPHPA_CNP_OCP_EN_R_MASK BIT(0)
+#define PM4125_ANA_HPHPA_CNP_OCP_ENABLE 1
+#define PM4125_ANA_HPHPA_CNP_OCP_DISABLE 0
+#define PM4125_ANA_HPHPA_PA_STATUS (PM4125_ANA_BASE_ADDR+0x087)
+#define PM4125_ANA_HPHPA_FSM_CLK (PM4125_ANA_BASE_ADDR+0x088)
+#define PM4125_ANA_HPHPA_FSM_CLK_DIV_EN_MASK BIT(7)
+#define PM4125_ANA_HPHPA_FSM_CLK_DIV_ENABLE 1
+#define PM4125_ANA_HPHPA_FSM_CLK_DIV_DISABLE 0
+#define PM4125_ANA_HPHPA_FSM_DIV_RATIO_MASK GENMASK(6, 0)
+#define PM4125_ANA_HPHPA_FSM_DIV_RATIO_68 (0x11)
+#define PM4125_ANA_HPHPA_L_GAIN (PM4125_ANA_BASE_ADDR+0x08B)
+#define PM4125_ANA_HPHPA_R_GAIN (PM4125_ANA_BASE_ADDR+0x08C)
+#define PM4125_ANA_HPHPA_SPARE_CTL (PM4125_ANA_BASE_ADDR+0x08E)
+#define PM4125_SWR_HPHPA_HD2 (PM4125_ANA_BASE_ADDR+0x090)
+#define PM4125_SWR_HPHPA_HD2_LEFT_MASK GENMASK(5, 3)
+#define PM4125_SWR_HPHPA_HD2_RIGHT_MASK GENMASK(2, 0)
+#define PM4125_SWR_HPHPA_HD2_ENABLE (BIT(2) | BIT(1) | BIT(0))
+#define PM4125_ANA_SURGE_EN (PM4125_ANA_BASE_ADDR+0x097)
+#define PM4125_ANA_SURGE_PROTECTION_HPHL_MASK BIT(7)
+#define PM4125_ANA_SURGE_PROTECTION_HPHR_MASK BIT(6)
+#define PM4125_ANA_SURGE_PROTECTION_ENABLE 1
+#define PM4125_ANA_SURGE_PROTECTION_DISABLE 0
+#define PM4125_ANA_COMBOPA_CTL (PM4125_ANA_BASE_ADDR+0x09B)
+#define PM4125_ANA_COMBO_PA_SELECT_MASK BIT(6)
+#define PM4125_ANA_COMBO_PA_SELECT_EAR 0
+#define PM4125_ANA_COMBO_PA_SELECT_LO 1
+#define PM4125_ANA_COMBOPA_CTL_4 (PM4125_ANA_BASE_ADDR+0x09F)
+#define PM4125_ANA_COMBOPA_CTL_5 (PM4125_ANA_BASE_ADDR+0x0A0)
+#define PM4125_ANA_RXLDO_CTL (PM4125_ANA_BASE_ADDR+0x0B2)
+#define PM4125_ANA_MBIAS_EN (PM4125_ANA_BASE_ADDR+0x0B4)
+#define PM4125_ANA_MBIAS_EN_GLOBAL_MASK BIT(5)
+#define PM4125_ANA_MBIAS_EN_V2I_MASK BIT(4)
+#define PM4125_ANA_MBIAS_EN_ENABLE 1
+#define PM4125_ANA_MBIAS_EN_DISABLE 0
+
+#define PM4125_DIG_SWR_CHIP_ID0 (PM4125_DIG_BASE_ADDR+0x001)
+#define PM4125_DIG_SWR_CHIP_ID1 (PM4125_DIG_BASE_ADDR+0x002)
+#define PM4125_DIG_SWR_CHIP_ID2 (PM4125_DIG_BASE_ADDR+0x003)
+#define PM4125_DIG_SWR_CHIP_ID3 (PM4125_DIG_BASE_ADDR+0x004)
+#define PM4125_DIG_SWR_SWR_TX_CLK_RATE (PM4125_DIG_BASE_ADDR+0x040)
+#define PM4125_DIG_SWR_CDC_RST_CTL (PM4125_DIG_BASE_ADDR+0x041)
+#define PM4125_DIG_SWR_TOP_CLK_CFG (PM4125_DIG_BASE_ADDR+0x042)
+#define PM4125_DIG_SWR_CDC_RX_CLK_CTL (PM4125_DIG_BASE_ADDR+0x043)
+#define PM4125_DIG_SWR_ANA_RX_DIV2_CLK_EN_MASK BIT(5)
+#define PM4125_DIG_SWR_ANA_RX_CLK_EN_MASK BIT(4)
+#define PM4125_DIG_SWR_RX1_CLK_EN_MASK BIT(1)
+#define PM4125_DIG_SWR_RX0_CLK_EN_MASK BIT(0)
+#define PM4125_DIG_SWR_RX_CLK_ENABLE 1
+#define PM4125_DIG_SWR_RX_CLK_DISABLE 0
+#define PM4125_DIG_SWR_CDC_TX_CLK_CTL (PM4125_DIG_BASE_ADDR+0x044)
+#define PM4125_DIG_SWR_SWR_RST_EN (PM4125_DIG_BASE_ADDR+0x045)
+#define PM4125_DIG_SWR_CDC_RX_RST (PM4125_DIG_BASE_ADDR+0x047)
+#define PM4125_DIG_SWR_CDC_RX0_CTL (PM4125_DIG_BASE_ADDR+0x048)
+#define PM4125_DIG_SWR_DSM_DITHER_EN_MASK BIT(7)
+#define PM4125_DIG_SWR_DSM_DITHER_DISABLE 0
+#define PM4125_DIG_SWR_DSM_DITHER_ENABLE 1
+#define PM4125_DIG_SWR_CDC_RX1_CTL (PM4125_DIG_BASE_ADDR+0x049)
+#define PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1 (PM4125_DIG_BASE_ADDR+0x04B)
+#define PM4125_DIG_SWR_TX_ANA_TXD1_MODE_MASK GENMASK(7, 4)
+#define PM4125_DIG_SWR_TX_ANA_TXD0_MODE_MASK GENMASK(3, 0)
+#define PM4125_DIG_SWR_TXD_MODE_ULPI (0x9)
+#define PM4125_DIG_SWR_TXD_MODE_NORMAL (0x3)
+#define PM4125_DIG_SWR_CDC_COMP_CTL_0 (PM4125_DIG_BASE_ADDR+0x04F)
+#define PM4125_DIG_SWR_COMP_HPHL_EN_MASK BIT(1)
+#define PM4125_DIG_SWR_COMP_HPHR_EN_MASK BIT(0)
+#define PM4125_DIG_SWR_COMP_ENABLE 1
+#define PM4125_DIG_SWR_COMP_DISABLE 0
+#define PM4125_DIG_SWR_CDC_RX_DELAY_CTL (PM4125_DIG_BASE_ADDR+0x052)
+#define PM4125_DIG_SWR_CDC_RX_GAIN_0 (PM4125_DIG_BASE_ADDR+0x053)
+#define PM4125_DIG_SWR_CDC_RX_GAIN_1 (PM4125_DIG_BASE_ADDR+0x054)
+#define PM4125_DIG_SWR_CDC_RX_GAIN_CTL (PM4125_DIG_BASE_ADDR+0x057)
+#define PM4125_DIG_SWR_RX1_EN_MASK BIT(3)
+#define PM4125_DIG_SWR_RX0_EN_MASK BIT(2)
+#define PM4125_DIG_SWR_RX_INPUT_DISABLE 0
+#define PM4125_DIG_SWR_RX_INPUT_ENABLE 1
+#define PM4125_DIG_SWR_CDC_TX0_CTL (PM4125_DIG_BASE_ADDR+0x060)
+#define PM4125_DIG_SWR_CDC_TX1_CTL (PM4125_DIG_BASE_ADDR+0x061)
+#define PM4125_DIG_SWR_CDC_TX_RST (PM4125_DIG_BASE_ADDR+0x063)
+#define PM4125_DIG_SWR_CDC_REQ0_CTL (PM4125_DIG_BASE_ADDR+0x064)
+#define PM4125_DIG_SWR_CDC_REQ1_CTL (PM4125_DIG_BASE_ADDR+0x065)
+#define PM4125_DIG_SWR_CDC_RST (PM4125_DIG_BASE_ADDR+0x067)
+#define PM4125_DIG_SWR_CDC_AMIC_CTL (PM4125_DIG_BASE_ADDR+0x06A)
+#define PM4125_DIG_SWR_AMIC_SELECT_MASK BIT(1)
+#define PM4125_DIG_SWR_AMIC_SELECT_DMIC1 0
+#define PM4125_DIG_SWR_AMIC_SELECT_AMIC3 1
+#define PM4125_DIG_SWR_CDC_DMIC_CTL (PM4125_DIG_BASE_ADDR+0x06B)
+#define PM4125_DIG_SWR_CDC_DMIC1_CTL (PM4125_DIG_BASE_ADDR+0x06C)
+#define PM4125_DIG_SWR_DMIC1_CLK_EN_MASK BIT(3)
+#define PM4125_DIG_SWR_DMIC1_CLK_ENABLE 1
+#define PM4125_DIG_SWR_DMIC1_CLK_DISABLE 0
+#define PM4125_DIG_SWR_CDC_DMIC1_RATE (PM4125_DIG_BASE_ADDR+0x06D)
+#define PM4125_DIG_SWR_PDM_WD_CTL0 (PM4125_DIG_BASE_ADDR+0x070)
+#define PM4125_WDT_ENABLE_MASK GENMASK(1, 0)
+#define PM4125_WDT_ENABLE_RX0_L BIT(0)
+#define PM4125_WDT_ENABLE_RX0_M BIT(1)
+#define PM4125_DIG_SWR_PDM_WD_CTL1 (PM4125_DIG_BASE_ADDR+0x071)
+#define PM4125_WDT_ENABLE_RX1_L BIT(0)
+#define PM4125_WDT_ENABLE_RX1_M BIT(1)
+#define PM4125_DIG_SWR_INTR_MODE (PM4125_DIG_BASE_ADDR+0x080)
+#define PM4125_DIG_SWR_INTR_MASK_0 (PM4125_DIG_BASE_ADDR+0x081)
+#define PM4125_DIG_SWR_INTR_MASK_1 (PM4125_DIG_BASE_ADDR+0x082)
+#define PM4125_DIG_SWR_INTR_MASK_2 (PM4125_DIG_BASE_ADDR+0x083)
+#define PM4125_DIG_SWR_INTR_STATUS_0 (PM4125_DIG_BASE_ADDR+0x084)
+#define PM4125_DIG_SWR_INTR_STATUS_1 (PM4125_DIG_BASE_ADDR+0x085)
+#define PM4125_DIG_SWR_INTR_STATUS_2 (PM4125_DIG_BASE_ADDR+0x086)
+#define PM4125_DIG_SWR_INTR_CLEAR_0 (PM4125_DIG_BASE_ADDR+0x087)
+#define PM4125_DIG_SWR_INTR_CLEAR_1 (PM4125_DIG_BASE_ADDR+0x088)
+#define PM4125_DIG_SWR_INTR_CLEAR_2 (PM4125_DIG_BASE_ADDR+0x089)
+#define PM4125_DIG_SWR_INTR_LEVEL_0 (PM4125_DIG_BASE_ADDR+0x08A)
+#define PM4125_DIG_SWR_INTR_LEVEL_1 (PM4125_DIG_BASE_ADDR+0x08B)
+#define PM4125_DIG_SWR_INTR_LEVEL_2 (PM4125_DIG_BASE_ADDR+0x08C)
+#define PM4125_DIG_SWR_CDC_CONN_RX0_CTL (PM4125_DIG_BASE_ADDR+0x093)
+#define PM4125_DIG_SWR_CDC_CONN_RX1_CTL (PM4125_DIG_BASE_ADDR+0x094)
+#define PM4125_DIG_SWR_LOOP_BACK_MODE (PM4125_DIG_BASE_ADDR+0x097)
+#define PM4125_DIG_SWR_DRIVE_STRENGTH_0 (PM4125_DIG_BASE_ADDR+0x0A0)
+#define PM4125_DIG_SWR_DIG_DEBUG_CTL (PM4125_DIG_BASE_ADDR+0x0AB)
+#define PM4125_DIG_SWR_DIG_DEBUG_EN (PM4125_DIG_BASE_ADDR+0x0AC)
+#define PM4125_DIG_SWR_DEM_BYPASS_DATA0 (PM4125_DIG_BASE_ADDR+0x0B0)
+#define PM4125_DIG_SWR_DEM_BYPASS_DATA1 (PM4125_DIG_BASE_ADDR+0x0B1)
+#define PM4125_DIG_SWR_DEM_BYPASS_DATA2 (PM4125_DIG_BASE_ADDR+0x0B2)
+#define PM4125_DIG_SWR_DEM_BYPASS_DATA3 (PM4125_DIG_BASE_ADDR+0x0B3)
+
+#define PM4125_ANALOG_REGISTERS_MAX_SIZE (PM4125_ANA_BASE_ADDR+0x0B5)
+#define PM4125_DIGITAL_REGISTERS_MAX_SIZE (PM4125_DIG_BASE_ADDR+0x0B4)
+#define PM4125_ANALOG_MAX_REGISTER (PM4125_ANALOG_REGISTERS_MAX_SIZE - 1)
+#define PM4125_DIGITAL_MAX_REGISTER (PM4125_DIGITAL_REGISTERS_MAX_SIZE - 1)
+#define PM4125_MAX_REGISTER PM4125_DIGITAL_MAX_REGISTER
+
+#define PM4125_MAX_MICBIAS 3
+#define PM4125_MAX_SWR_CH_IDS 15
+#define PM4125_SWRM_CH_MASK(ch_idx) BIT(ch_idx - 1)
+
+enum pm4125_tx_sdw_ports {
+ PM4125_ADC_1_2_DMIC1L_BCS_PORT = 1,
+ PM4125_DMIC_1L_1R_ADC1_BCS_PORT,
+ PM4125_MAX_TX_SWR_PORTS = PM4125_DMIC_1L_1R_ADC1_BCS_PORT,
+};
+
+enum pm4125_rx_sdw_ports {
+ PM4125_HPH_PORT = 1,
+ PM4125_COMP_PORT,
+ PM4125_MAX_SWR_PORTS = PM4125_COMP_PORT,
+};
+
+struct pm4125_priv;
+struct pm4125_sdw_priv {
+ struct sdw_slave *sdev;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[PM4125_MAX_SWR_PORTS];
+ struct wcd_sdw_ch_info *ch_info;
+ bool port_enable[PM4125_MAX_SWR_CH_IDS];
+ unsigned int master_channel_map[SDW_MAX_PORTS];
+ int active_ports;
+ int num_ports;
+ bool is_tx;
+ struct pm4125_priv *pm4125;
+ struct irq_domain *slave_irq;
+ struct regmap *regmap;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_PM4125_SDW)
+int pm4125_sdw_free(struct pm4125_sdw_priv *pm4125, struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int pm4125_sdw_set_sdw_stream(struct pm4125_sdw_priv *pm4125, struct snd_soc_dai *dai, void *stream,
+ int direction);
+int pm4125_sdw_hw_params(struct pm4125_sdw_priv *pm4125, struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
+
+#else
+static inline int pm4125_sdw_free(struct pm4125_sdw_priv *pm4125,
+ struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int pm4125_sdw_set_sdw_stream(struct pm4125_sdw_priv *pm4125,
+ struct snd_soc_dai *dai, void *stream, int direction)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int pm4125_sdw_hw_params(struct pm4125_sdw_priv *pm4125,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+enum {
+ /* INTR_CTRL_INT_MASK_0 */
+ PM4125_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+ PM4125_IRQ_MBHC_BUTTON_RELEASE_DET,
+ PM4125_IRQ_MBHC_ELECT_INS_REM_DET,
+ PM4125_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ PM4125_IRQ_MBHC_SW_DET,
+ PM4125_IRQ_HPHR_OCP_INT,
+ PM4125_IRQ_HPHR_CNP_INT,
+ PM4125_IRQ_HPHL_OCP_INT,
+
+ /* INTR_CTRL_INT_MASK_1 */
+ PM4125_IRQ_HPHL_CNP_INT,
+ PM4125_IRQ_EAR_CNP_INT,
+ PM4125_IRQ_EAR_SCD_INT,
+ PM4125_IRQ_AUX_CNP_INT,
+ PM4125_IRQ_AUX_SCD_INT,
+ PM4125_IRQ_HPHL_PDM_WD_INT,
+ PM4125_IRQ_HPHR_PDM_WD_INT,
+ PM4125_IRQ_AUX_PDM_WD_INT,
+
+ /* INTR_CTRL_INT_MASK_2 */
+ PM4125_IRQ_LDORT_SCD_INT,
+ PM4125_IRQ_MBHC_MOISTURE_INT,
+ PM4125_IRQ_HPHL_SURGE_DET_INT,
+ PM4125_IRQ_HPHR_SURGE_DET_INT,
+ PM4125_NUM_IRQS,
+};
+
+enum pm4125_tx_sdw_channels {
+ PM4125_ADC1,
+ PM4125_ADC2,
+};
+
+enum pm4125_rx_sdw_channels {
+ PM4125_HPH_L,
+ PM4125_HPH_R,
+ PM4125_COMP_L,
+ PM4125_COMP_R,
+};
+
+#endif /* _PM4125_REGISTERS_H */
diff --git a/sound/soc/codecs/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c
new file mode 100644
index 000000000000..60befe9d37f0
--- /dev/null
+++ b/sound/soc/codecs/rk3308_codec.c
@@ -0,0 +1,975 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Rockchip RK3308 internal audio codec driver
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
+ * Copyright (c) 2024, Vivax-Metrotech Ltd
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/util_macros.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "rk3308_codec.h"
+
+#define ADC_LR_GROUP_MAX 4
+
+#define GRF_CHIP_ID 0x800
+
+enum {
+ ACODEC_VERSION_A = 'A',
+ ACODEC_VERSION_B,
+ ACODEC_VERSION_C,
+};
+
+struct rk3308_codec_priv {
+ const struct device *dev;
+ struct regmap *regmap;
+ struct regmap *grf;
+ struct reset_control *reset;
+ struct clk *hclk;
+ struct clk *mclk_rx;
+ struct clk *mclk_tx;
+ struct snd_soc_component *component;
+ unsigned char codec_ver;
+};
+
+static struct clk_bulk_data rk3308_codec_clocks[] = {
+ { .id = "hclk" },
+ { .id = "mclk_rx" },
+ { .id = "mclk_tx" },
+};
+
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_adc_alc_gain_tlv, -1800, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpout_gain_tlv, -3900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rk3308_codec_dac_hpmix_gain_tlv, -600, 600, 0);
+
+static const DECLARE_TLV_DB_RANGE(rk3308_codec_dac_lineout_gain_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(-300, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(-150, 0, 0),
+ 3, 3, TLV_DB_SCALE_ITEM(0, 0, 0),
+);
+
+static const char * const rk3308_codec_hpf_cutoff_text[] = {
+ "20 Hz", "245 Hz", "612 Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum12, RK3308_ADC_DIG_CON04(0), 0,
+ rk3308_codec_hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum34, RK3308_ADC_DIG_CON04(1), 0,
+ rk3308_codec_hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum56, RK3308_ADC_DIG_CON04(2), 0,
+ rk3308_codec_hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rk3308_codec_hpf_cutoff_enum78, RK3308_ADC_DIG_CON04(3), 0,
+ rk3308_codec_hpf_cutoff_text);
+
+static const struct snd_kcontrol_new rk3308_codec_controls[] = {
+ /* Despite the register names, these set the gain when AGC is OFF */
+ SOC_SINGLE_RANGE_TLV("MIC1 Capture Volume",
+ RK3308_ADC_ANA_CON03(0),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC2 Capture Volume",
+ RK3308_ADC_ANA_CON04(0),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC3 Capture Volume",
+ RK3308_ADC_ANA_CON03(1),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC4 Capture Volume",
+ RK3308_ADC_ANA_CON04(1),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC5 Capture Volume",
+ RK3308_ADC_ANA_CON03(2),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC6 Capture Volume",
+ RK3308_ADC_ANA_CON04(2),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC7 Capture Volume",
+ RK3308_ADC_ANA_CON03(3),
+ RK3308_ADC_CH1_ALC_GAIN_SFT,
+ RK3308_ADC_CH1_ALC_GAIN_MIN,
+ RK3308_ADC_CH1_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+ SOC_SINGLE_RANGE_TLV("MIC8 Capture Volume",
+ RK3308_ADC_ANA_CON04(3),
+ RK3308_ADC_CH2_ALC_GAIN_SFT,
+ RK3308_ADC_CH2_ALC_GAIN_MIN,
+ RK3308_ADC_CH2_ALC_GAIN_MAX,
+ 0, rk3308_codec_adc_alc_gain_tlv),
+
+ SOC_SINGLE("MIC1 Capture Switch", RK3308_ADC_ANA_CON00(0), 3, 1, 0),
+ SOC_SINGLE("MIC2 Capture Switch", RK3308_ADC_ANA_CON00(0), 7, 1, 0),
+ SOC_SINGLE("MIC3 Capture Switch", RK3308_ADC_ANA_CON00(1), 3, 1, 0),
+ SOC_SINGLE("MIC4 Capture Switch", RK3308_ADC_ANA_CON00(1), 7, 1, 0),
+ SOC_SINGLE("MIC5 Capture Switch", RK3308_ADC_ANA_CON00(2), 3, 1, 0),
+ SOC_SINGLE("MIC6 Capture Switch", RK3308_ADC_ANA_CON00(2), 7, 1, 0),
+ SOC_SINGLE("MIC7 Capture Switch", RK3308_ADC_ANA_CON00(3), 3, 1, 0),
+ SOC_SINGLE("MIC8 Capture Switch", RK3308_ADC_ANA_CON00(3), 7, 1, 0),
+
+ SOC_SINGLE("MIC12 HPF Capture Switch", RK3308_ADC_DIG_CON04(0), 2, 1, 1),
+ SOC_SINGLE("MIC34 HPF Capture Switch", RK3308_ADC_DIG_CON04(1), 2, 1, 1),
+ SOC_SINGLE("MIC56 HPF Capture Switch", RK3308_ADC_DIG_CON04(2), 2, 1, 1),
+ SOC_SINGLE("MIC78 HPF Capture Switch", RK3308_ADC_DIG_CON04(3), 2, 1, 1),
+
+ SOC_ENUM("MIC12 HPF Cutoff", rk3308_codec_hpf_cutoff_enum12),
+ SOC_ENUM("MIC34 HPF Cutoff", rk3308_codec_hpf_cutoff_enum34),
+ SOC_ENUM("MIC56 HPF Cutoff", rk3308_codec_hpf_cutoff_enum56),
+ SOC_ENUM("MIC78 HPF Cutoff", rk3308_codec_hpf_cutoff_enum78),
+
+ SOC_DOUBLE_TLV("Line Out Playback Volume",
+ RK3308_DAC_ANA_CON04,
+ RK3308_DAC_L_LINEOUT_GAIN_SFT,
+ RK3308_DAC_R_LINEOUT_GAIN_SFT,
+ RK3308_DAC_x_LINEOUT_GAIN_MAX,
+ 0, rk3308_codec_dac_lineout_gain_tlv),
+ SOC_DOUBLE("Line Out Playback Switch",
+ RK3308_DAC_ANA_CON04,
+ RK3308_DAC_L_LINEOUT_MUTE_SFT,
+ RK3308_DAC_R_LINEOUT_MUTE_SFT, 1, 0),
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume",
+ RK3308_DAC_ANA_CON05,
+ RK3308_DAC_ANA_CON06,
+ RK3308_DAC_x_HPOUT_GAIN_SFT,
+ RK3308_DAC_x_HPOUT_GAIN_MAX,
+ 0, rk3308_codec_dac_hpout_gain_tlv),
+ SOC_DOUBLE("Headphone Playback Switch",
+ RK3308_DAC_ANA_CON03,
+ RK3308_DAC_L_HPOUT_MUTE_SFT,
+ RK3308_DAC_R_HPOUT_MUTE_SFT, 1, 0),
+ SOC_DOUBLE_RANGE_TLV("DAC HPMIX Playback Volume",
+ RK3308_DAC_ANA_CON12,
+ RK3308_DAC_L_HPMIX_GAIN_SFT,
+ RK3308_DAC_R_HPMIX_GAIN_SFT,
+ 1, 2, 0, rk3308_codec_dac_hpmix_gain_tlv),
+};
+
+static int rk3308_codec_pop_sound_set(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 rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+ unsigned int val = (event == SND_SOC_DAPM_POST_PMU) ?
+ RK3308_DAC_HPOUT_POP_SOUND_x_WORK :
+ RK3308_DAC_HPOUT_POP_SOUND_x_INIT;
+ unsigned int mask = RK3308_DAC_HPOUT_POP_SOUND_x_MSK;
+
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON01,
+ mask << w->shift, val << w->shift);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rk3308_codec_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+ SND_SOC_DAPM_INPUT("MIC4"),
+ SND_SOC_DAPM_INPUT("MIC5"),
+ SND_SOC_DAPM_INPUT("MIC6"),
+ SND_SOC_DAPM_INPUT("MIC7"),
+ SND_SOC_DAPM_INPUT("MIC8"),
+
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN12", RK3308_ADC_ANA_CON06(0), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN34", RK3308_ADC_ANA_CON06(1), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN56", RK3308_ADC_ANA_CON06(2), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_CURRENT_EN78", RK3308_ADC_ANA_CON06(3), 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_EN", RK3308_ADC_ANA_CON00(0), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_EN", RK3308_ADC_ANA_CON00(0), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_EN", RK3308_ADC_ANA_CON00(1), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_EN", RK3308_ADC_ANA_CON00(1), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_EN", RK3308_ADC_ANA_CON00(2), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_EN", RK3308_ADC_ANA_CON00(2), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_EN", RK3308_ADC_ANA_CON00(3), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_EN", RK3308_ADC_ANA_CON00(3), 5, 1, 1, 0),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC1_WORK", RK3308_ADC_ANA_CON00(0), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC2_WORK", RK3308_ADC_ANA_CON00(0), 6, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC3_WORK", RK3308_ADC_ANA_CON00(1), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC4_WORK", RK3308_ADC_ANA_CON00(1), 6, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC5_WORK", RK3308_ADC_ANA_CON00(2), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC6_WORK", RK3308_ADC_ANA_CON00(2), 6, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC7_WORK", RK3308_ADC_ANA_CON00(3), 2, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mic, "MIC8_WORK", RK3308_ADC_ANA_CON00(3), 6, 1, 1, 0),
+
+ /*
+ * In theory MIC1 and MIC2 can switch to LINE IN, but this is not
+ * supported so all we can do is enabling the MIC input.
+ */
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH1_IN_SEL", RK3308_ADC_ANA_CON07(0), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "CH2_IN_SEL", RK3308_ADC_ANA_CON07(0), 6, 1, 1, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC1_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC2_BUF_REF_EN", RK3308_ADC_ANA_CON00(0), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC3_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC4_BUF_REF_EN", RK3308_ADC_ANA_CON00(1), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC5_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC6_BUF_REF_EN", RK3308_ADC_ANA_CON00(2), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC7_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC8_BUF_REF_EN", RK3308_ADC_ANA_CON00(3), 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC_MCLK_GATE", RK3308_GLB_CON, 5, 1, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC1_CLK_EN", RK3308_ADC_ANA_CON05(0), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC2_CLK_EN", RK3308_ADC_ANA_CON05(0), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC3_CLK_EN", RK3308_ADC_ANA_CON05(1), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC4_CLK_EN", RK3308_ADC_ANA_CON05(1), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC5_CLK_EN", RK3308_ADC_ANA_CON05(2), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC6_CLK_EN", RK3308_ADC_ANA_CON05(2), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC7_CLK_EN", RK3308_ADC_ANA_CON05(3), 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC8_CLK_EN", RK3308_ADC_ANA_CON05(3), 4, 0, NULL, 0),
+
+ /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_EN", RK3308_ADC_ANA_CON02(0), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_EN", RK3308_ADC_ANA_CON02(0), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_EN", RK3308_ADC_ANA_CON02(1), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_EN", RK3308_ADC_ANA_CON02(1), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_EN", RK3308_ADC_ANA_CON02(2), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_EN", RK3308_ADC_ANA_CON02(2), 4, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_EN", RK3308_ADC_ANA_CON02(3), 0, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_EN", RK3308_ADC_ANA_CON02(3), 4, 1, 1, 0),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC1_EN", RK3308_ADC_ANA_CON05(0), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC2_EN", RK3308_ADC_ANA_CON05(0), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC3_EN", RK3308_ADC_ANA_CON05(1), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC4_EN", RK3308_ADC_ANA_CON05(1), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC5_EN", RK3308_ADC_ANA_CON05(2), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC6_EN", RK3308_ADC_ANA_CON05(2), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC7_EN", RK3308_ADC_ANA_CON05(3), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC8_EN", RK3308_ADC_ANA_CON05(3), 5, 1, 1, 0),
+
+ SND_SOC_DAPM_ADC("ADC1_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 2, 0),
+ SND_SOC_DAPM_ADC("ADC2_WORK", "Capture", RK3308_ADC_ANA_CON05(0), 6, 0),
+ SND_SOC_DAPM_ADC("ADC3_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 2, 0),
+ SND_SOC_DAPM_ADC("ADC4_WORK", "Capture", RK3308_ADC_ANA_CON05(1), 6, 0),
+ SND_SOC_DAPM_ADC("ADC5_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 2, 0),
+ SND_SOC_DAPM_ADC("ADC6_WORK", "Capture", RK3308_ADC_ANA_CON05(2), 6, 0),
+ SND_SOC_DAPM_ADC("ADC7_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 2, 0),
+ SND_SOC_DAPM_ADC("ADC8_WORK", "Capture", RK3308_ADC_ANA_CON05(3), 6, 0),
+
+ /* The "ALC" name from the TRM is misleading, these are needed even without ALC/AGC */
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC1_WORK", RK3308_ADC_ANA_CON02(0), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC2_WORK", RK3308_ADC_ANA_CON02(0), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC3_WORK", RK3308_ADC_ANA_CON02(1), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC4_WORK", RK3308_ADC_ANA_CON02(1), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC5_WORK", RK3308_ADC_ANA_CON02(2), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC6_WORK", RK3308_ADC_ANA_CON02(2), 5, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC7_WORK", RK3308_ADC_ANA_CON02(3), 1, 1, 1, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ALC8_WORK", RK3308_ADC_ANA_CON02(3), 5, 1, 1, 0),
+
+ SND_SOC_DAPM_SUPPLY("MICBIAS Current", RK3308_ADC_ANA_CON08(0), 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", RK3308_ADC_ANA_CON07(1), 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", RK3308_ADC_ANA_CON07(2), 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_EN", RK3308_DAC_ANA_CON13, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_EN", RK3308_DAC_ANA_CON13, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_WORK", RK3308_DAC_ANA_CON13, 1, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_WORK", RK3308_DAC_ANA_CON13, 5, 0, NULL, 0),
+ /* HPMIX is not actually acting as a mixer as the only supported input is I2S */
+ SND_SOC_DAPM_OUT_DRV("DAC_L_HPMIX_SEL", RK3308_DAC_ANA_CON12, 2, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("DAC_R_HPMIX_SEL", RK3308_DAC_ANA_CON12, 6, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DAC HPMIX Left", RK3308_DAC_ANA_CON13, 2, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DAC HPMIX Right", RK3308_DAC_ANA_CON13, 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC_MCLK_GATE", RK3308_GLB_CON, 4, 1, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC_CURRENT_EN", RK3308_DAC_ANA_CON00, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_L_REF_EN", RK3308_DAC_ANA_CON02, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_R_REF_EN", RK3308_DAC_ANA_CON02, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_L_CLK_EN", RK3308_DAC_ANA_CON02, 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_R_CLK_EN", RK3308_DAC_ANA_CON02, 5, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("DAC_L_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 3, 0),
+ SND_SOC_DAPM_DAC("DAC_R_DAC_WORK", NULL, RK3308_DAC_ANA_CON02, 7, 0),
+
+ SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_L", RK3308_DAC_ANA_CON01, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_BUF_REF_R", RK3308_DAC_ANA_CON01, 6, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_L", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rk3308_codec_pop_sound_set,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_OUT_DRV_E("HPOUT_POP_SOUND_R", SND_SOC_NOPM, 4, 0, NULL, 0,
+ rk3308_codec_pop_sound_set,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_OUT_DRV("L_HPOUT_EN", RK3308_DAC_ANA_CON03, 1, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("R_HPOUT_EN", RK3308_DAC_ANA_CON03, 5, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("L_HPOUT_WORK", RK3308_DAC_ANA_CON03, 2, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("R_HPOUT_WORK", RK3308_DAC_ANA_CON03, 6, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("HPOUT_L"),
+ SND_SOC_DAPM_OUTPUT("HPOUT_R"),
+
+ SND_SOC_DAPM_OUT_DRV("L_LINEOUT_EN", RK3308_DAC_ANA_CON04, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("R_LINEOUT_EN", RK3308_DAC_ANA_CON04, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LINEOUT_L"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT_R"),
+};
+
+static const struct snd_soc_dapm_route rk3308_codec_dapm_routes[] = {
+ { "MICBIAS1", NULL, "MICBIAS Current" },
+ { "MICBIAS2", NULL, "MICBIAS Current" },
+
+ { "MIC1_EN", NULL, "MIC1" },
+ { "MIC2_EN", NULL, "MIC2" },
+ { "MIC3_EN", NULL, "MIC3" },
+ { "MIC4_EN", NULL, "MIC4" },
+ { "MIC5_EN", NULL, "MIC5" },
+ { "MIC6_EN", NULL, "MIC6" },
+ { "MIC7_EN", NULL, "MIC7" },
+ { "MIC8_EN", NULL, "MIC8" },
+
+ { "MIC1_WORK", NULL, "MIC1_EN" },
+ { "MIC2_WORK", NULL, "MIC2_EN" },
+ { "MIC3_WORK", NULL, "MIC3_EN" },
+ { "MIC4_WORK", NULL, "MIC4_EN" },
+ { "MIC5_WORK", NULL, "MIC5_EN" },
+ { "MIC6_WORK", NULL, "MIC6_EN" },
+ { "MIC7_WORK", NULL, "MIC7_EN" },
+ { "MIC8_WORK", NULL, "MIC8_EN" },
+
+ { "CH1_IN_SEL", NULL, "MIC1_WORK" },
+ { "CH2_IN_SEL", NULL, "MIC2_WORK" },
+
+ { "ALC1_EN", NULL, "CH1_IN_SEL" },
+ { "ALC2_EN", NULL, "CH2_IN_SEL" },
+ { "ALC3_EN", NULL, "MIC3_WORK" },
+ { "ALC4_EN", NULL, "MIC4_WORK" },
+ { "ALC5_EN", NULL, "MIC5_WORK" },
+ { "ALC6_EN", NULL, "MIC6_WORK" },
+ { "ALC7_EN", NULL, "MIC7_WORK" },
+ { "ALC8_EN", NULL, "MIC8_WORK" },
+
+ { "ADC1_EN", NULL, "ALC1_EN" },
+ { "ADC2_EN", NULL, "ALC2_EN" },
+ { "ADC3_EN", NULL, "ALC3_EN" },
+ { "ADC4_EN", NULL, "ALC4_EN" },
+ { "ADC5_EN", NULL, "ALC5_EN" },
+ { "ADC6_EN", NULL, "ALC6_EN" },
+ { "ADC7_EN", NULL, "ALC7_EN" },
+ { "ADC8_EN", NULL, "ALC8_EN" },
+
+ { "ADC1_WORK", NULL, "ADC1_EN" },
+ { "ADC2_WORK", NULL, "ADC2_EN" },
+ { "ADC3_WORK", NULL, "ADC3_EN" },
+ { "ADC4_WORK", NULL, "ADC4_EN" },
+ { "ADC5_WORK", NULL, "ADC5_EN" },
+ { "ADC6_WORK", NULL, "ADC6_EN" },
+ { "ADC7_WORK", NULL, "ADC7_EN" },
+ { "ADC8_WORK", NULL, "ADC8_EN" },
+
+ { "ADC1_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" },
+ { "ADC2_BUF_REF_EN", NULL, "ADC_CURRENT_EN12" },
+ { "ADC3_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" },
+ { "ADC4_BUF_REF_EN", NULL, "ADC_CURRENT_EN34" },
+ { "ADC5_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" },
+ { "ADC6_BUF_REF_EN", NULL, "ADC_CURRENT_EN56" },
+ { "ADC7_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" },
+ { "ADC8_BUF_REF_EN", NULL, "ADC_CURRENT_EN78" },
+
+ { "ADC1_WORK", NULL, "ADC1_BUF_REF_EN" },
+ { "ADC2_WORK", NULL, "ADC2_BUF_REF_EN" },
+ { "ADC3_WORK", NULL, "ADC3_BUF_REF_EN" },
+ { "ADC4_WORK", NULL, "ADC4_BUF_REF_EN" },
+ { "ADC5_WORK", NULL, "ADC5_BUF_REF_EN" },
+ { "ADC6_WORK", NULL, "ADC6_BUF_REF_EN" },
+ { "ADC7_WORK", NULL, "ADC7_BUF_REF_EN" },
+ { "ADC8_WORK", NULL, "ADC8_BUF_REF_EN" },
+
+ { "ADC1_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC2_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC3_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC4_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC5_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC6_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC7_CLK_EN", NULL, "ADC_MCLK_GATE" },
+ { "ADC8_CLK_EN", NULL, "ADC_MCLK_GATE" },
+
+ { "ADC1_WORK", NULL, "ADC1_CLK_EN" },
+ { "ADC2_WORK", NULL, "ADC2_CLK_EN" },
+ { "ADC3_WORK", NULL, "ADC3_CLK_EN" },
+ { "ADC4_WORK", NULL, "ADC4_CLK_EN" },
+ { "ADC5_WORK", NULL, "ADC5_CLK_EN" },
+ { "ADC6_WORK", NULL, "ADC6_CLK_EN" },
+ { "ADC7_WORK", NULL, "ADC7_CLK_EN" },
+ { "ADC8_WORK", NULL, "ADC8_CLK_EN" },
+
+ { "ALC1_WORK", NULL, "ADC1_WORK" },
+ { "ALC2_WORK", NULL, "ADC2_WORK" },
+ { "ALC3_WORK", NULL, "ADC3_WORK" },
+ { "ALC4_WORK", NULL, "ADC4_WORK" },
+ { "ALC5_WORK", NULL, "ADC5_WORK" },
+ { "ALC6_WORK", NULL, "ADC6_WORK" },
+ { "ALC7_WORK", NULL, "ADC7_WORK" },
+ { "ALC8_WORK", NULL, "ADC8_WORK" },
+
+ { "HiFi Capture", NULL, "ALC1_WORK" },
+ { "HiFi Capture", NULL, "ALC2_WORK" },
+ { "HiFi Capture", NULL, "ALC3_WORK" },
+ { "HiFi Capture", NULL, "ALC4_WORK" },
+ { "HiFi Capture", NULL, "ALC5_WORK" },
+ { "HiFi Capture", NULL, "ALC6_WORK" },
+ { "HiFi Capture", NULL, "ALC7_WORK" },
+ { "HiFi Capture", NULL, "ALC8_WORK" },
+
+ { "DAC_L_HPMIX_EN", NULL, "HiFi Playback" },
+ { "DAC_R_HPMIX_EN", NULL, "HiFi Playback" },
+ { "DAC_L_HPMIX_WORK", NULL, "DAC_L_HPMIX_EN" },
+ { "DAC_R_HPMIX_WORK", NULL, "DAC_R_HPMIX_EN" },
+ { "DAC HPMIX Left", NULL, "DAC_L_HPMIX_WORK" },
+ { "DAC HPMIX Right", NULL, "DAC_R_HPMIX_WORK" },
+
+ { "DAC_L_DAC_WORK", NULL, "DAC HPMIX Left" },
+ { "DAC_R_DAC_WORK", NULL, "DAC HPMIX Right" },
+
+ { "DAC_L_REF_EN", NULL, "DAC_CURRENT_EN" },
+ { "DAC_R_REF_EN", NULL, "DAC_CURRENT_EN" },
+ { "DAC_L_CLK_EN", NULL, "DAC_L_REF_EN" },
+ { "DAC_R_CLK_EN", NULL, "DAC_R_REF_EN" },
+ { "DAC_L_CLK_EN", NULL, "DAC_MCLK_GATE" },
+ { "DAC_R_CLK_EN", NULL, "DAC_MCLK_GATE" },
+ { "DAC_L_DAC_WORK", NULL, "DAC_L_CLK_EN" },
+ { "DAC_R_DAC_WORK", NULL, "DAC_R_CLK_EN" },
+ { "DAC_L_HPMIX_SEL", NULL, "DAC_L_DAC_WORK" },
+ { "DAC_R_HPMIX_SEL", NULL, "DAC_R_DAC_WORK" },
+
+ { "HPOUT_L", NULL, "DAC_BUF_REF_L" },
+ { "HPOUT_R", NULL, "DAC_BUF_REF_R" },
+ { "L_HPOUT_EN", NULL, "DAC_L_HPMIX_SEL" },
+ { "R_HPOUT_EN", NULL, "DAC_R_HPMIX_SEL" },
+ { "L_HPOUT_WORK", NULL, "L_HPOUT_EN" },
+ { "R_HPOUT_WORK", NULL, "R_HPOUT_EN" },
+ { "HPOUT_POP_SOUND_L", NULL, "L_HPOUT_WORK" },
+ { "HPOUT_POP_SOUND_R", NULL, "R_HPOUT_WORK" },
+ { "HPOUT_L", NULL, "HPOUT_POP_SOUND_L" },
+ { "HPOUT_R", NULL, "HPOUT_POP_SOUND_R" },
+
+ { "L_LINEOUT_EN", NULL, "DAC_L_HPMIX_SEL" },
+ { "R_LINEOUT_EN", NULL, "DAC_R_HPMIX_SEL" },
+ { "LINEOUT_L", NULL, "L_LINEOUT_EN" },
+ { "LINEOUT_R", NULL, "R_LINEOUT_EN" },
+};
+
+static int rk3308_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+ const unsigned int inv_bits = fmt & SND_SOC_DAIFMT_INV_MASK;
+ const bool inv_bitclk =
+ (inv_bits & SND_SOC_DAIFMT_IB_IF) ||
+ (inv_bits & SND_SOC_DAIFMT_IB_NF);
+ const bool inv_frmclk =
+ (inv_bits & SND_SOC_DAIFMT_IB_IF) ||
+ (inv_bits & SND_SOC_DAIFMT_NB_IF);
+ const unsigned int dac_master_bits = rk3308->codec_ver < ACODEC_VERSION_C ?
+ RK3308_DAC_IO_MODE_MASTER | RK3308_DAC_MODE_MASTER :
+ RK3308BS_DAC_IO_MODE_MASTER | RK3308BS_DAC_MODE_MASTER;
+ unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
+ bool is_master = false;
+ int grp;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ break;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ adc_aif2 |= RK3308_ADC_IO_MODE_MASTER;
+ adc_aif2 |= RK3308_ADC_MODE_MASTER;
+ dac_aif2 |= dac_master_bits;
+ is_master = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_PCM;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_PCM;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_I2S;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_RJ;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_RJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ adc_aif1 |= RK3308_ADC_I2S_MODE_LJ;
+ dac_aif1 |= RK3308_DAC_I2S_MODE_LJ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (inv_bitclk) {
+ adc_aif2 |= RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL;
+ dac_aif2 |= RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL;
+ }
+
+ if (inv_frmclk) {
+ adc_aif1 |= RK3308_ADC_I2S_LRC_POL_REVERSAL;
+ dac_aif1 |= RK3308_DAC_I2S_LRC_POL_REVERSAL;
+ }
+
+ /*
+ * Hold ADC Digital registers start at master mode
+ *
+ * There are 8 ADCs which use the same internal SCLK and LRCK for
+ * master mode. We need to make sure that they are in effect at the
+ * same time, otherwise they will cause abnormal clocks.
+ */
+ if (is_master)
+ regmap_clear_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
+ RK3308_ADC_I2S_LRC_POL_REVERSAL |
+ RK3308_ADC_I2S_MODE_MSK,
+ adc_aif1);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp),
+ RK3308_ADC_IO_MODE_MASTER |
+ RK3308_ADC_MODE_MASTER |
+ RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL,
+ adc_aif2);
+ }
+
+ /* Hold ADC Digital registers end at master mode */
+ if (is_master)
+ regmap_set_bits(rk3308->regmap, RK3308_GLB_CON, RK3308_ADC_DIG_WORK);
+
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01,
+ RK3308_DAC_I2S_LRC_POL_REVERSAL |
+ RK3308_DAC_I2S_MODE_MSK,
+ dac_aif1);
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON02,
+ dac_master_bits | RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL,
+ dac_aif2);
+
+ return 0;
+}
+
+static int rk3308_codec_dac_dig_config(struct rk3308_codec_priv *rk3308,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int dac_aif1 = 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_16BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_20BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_24BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ dac_aif1 |= RK3308_DAC_I2S_VALID_LEN_32BITS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_DIG_CON01,
+ RK3308_DAC_I2S_VALID_LEN_MSK, dac_aif1);
+ regmap_set_bits(rk3308->regmap, RK3308_DAC_DIG_CON02, RK3308_DAC_I2S_WORK);
+
+ return 0;
+}
+
+static int rk3308_codec_adc_dig_config(struct rk3308_codec_priv *rk3308,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int adc_aif1 = 0;
+ /*
+ * grp 0 = ADC1 and ADC2
+ * grp 1 = ADC3 and ADC4
+ * grp 2 = ADC5 and ADC6
+ * grp 3 = ADC7 and ADC8
+ */
+ u32 used_adc_grps;
+ int grp;
+
+ switch (params_channels(params)) {
+ case 1:
+ adc_aif1 |= RK3308_ADC_I2S_MONO;
+ used_adc_grps = 1;
+ break;
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ used_adc_grps = params_channels(params) / 2;
+ break;
+ default:
+ dev_err(rk3308->dev, "Invalid channel number %d\n", params_channels(params));
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_16BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_20BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_24BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ adc_aif1 |= RK3308_ADC_I2S_VALID_LEN_32BITS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (grp = 0; grp < used_adc_grps; grp++) {
+ regmap_update_bits(rk3308->regmap,
+ RK3308_ADC_DIG_CON03(grp),
+ RK3308_ADC_L_CH_BIST_MSK | RK3308_ADC_R_CH_BIST_MSK,
+ RK3308_ADC_L_CH_NORMAL_LEFT | RK3308_ADC_R_CH_NORMAL_RIGHT);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_DIG_CON01(grp),
+ RK3308_ADC_I2S_VALID_LEN_MSK | RK3308_ADC_I2S_MONO, adc_aif1);
+ regmap_set_bits(rk3308->regmap, RK3308_ADC_DIG_CON02(grp), RK3308_ADC_I2S_WORK);
+ }
+
+ return 0;
+}
+
+static int rk3308_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ return (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ rk3308_codec_dac_dig_config(rk3308, params) :
+ rk3308_codec_adc_dig_config(rk3308, params);
+}
+
+static const struct snd_soc_dai_ops rk3308_codec_dai_ops = {
+ .hw_params = rk3308_codec_hw_params,
+ .set_fmt = rk3308_codec_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver rk3308_codec_dai_driver = {
+ .name = "rk3308-hifi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ },
+ .ops = &rk3308_codec_dai_ops,
+};
+
+static void rk3308_codec_reset(struct snd_soc_component *component)
+{
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ reset_control_assert(rk3308->reset);
+ usleep_range(10000, 11000); /* estimated value */
+ reset_control_deassert(rk3308->reset);
+
+ regmap_write(rk3308->regmap, RK3308_GLB_CON, 0x00);
+ usleep_range(10000, 11000); /* estimated value */
+ regmap_write(rk3308->regmap, RK3308_GLB_CON,
+ RK3308_SYS_WORK |
+ RK3308_DAC_DIG_WORK |
+ RK3308_ADC_DIG_WORK);
+}
+
+/*
+ * Initialize register whose default after HW reset is problematic or which
+ * are never modified.
+ */
+static int rk3308_codec_initialize(struct rk3308_codec_priv *rk3308)
+{
+ int grp;
+
+ /*
+ * Init ADC digital vol to 0 dB (reset value is 0xff, undocumented).
+ * Range: -97dB ~ +32dB.
+ */
+ if (rk3308->codec_ver == ACODEC_VERSION_C) {
+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++) {
+ regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON05(grp),
+ RK3308_ADC_DIG_VOL_CON_x_0DB);
+ regmap_write(rk3308->regmap, RK3308_ADC_DIG_CON06(grp),
+ RK3308_ADC_DIG_VOL_CON_x_0DB);
+ }
+ }
+
+ /* set HPMIX default gains (reset value is 0, which is illegal) */
+ regmap_update_bits(rk3308->regmap, RK3308_DAC_ANA_CON12,
+ RK3308_DAC_L_HPMIX_GAIN_MSK |
+ RK3308_DAC_R_HPMIX_GAIN_MSK,
+ RK3308_DAC_L_HPMIX_GAIN_NDB_6 |
+ RK3308_DAC_R_HPMIX_GAIN_NDB_6);
+
+ /* recover DAC digital gain to 0 dB (reset value is 0xff, undocumented) */
+ if (rk3308->codec_ver == ACODEC_VERSION_C)
+ regmap_write(rk3308->regmap, RK3308_DAC_DIG_CON04,
+ RK3308BS_DAC_DIG_GAIN_0DB);
+
+ /*
+ * Unconditionally enable zero-cross detection (needed for AGC,
+ * harmless without AGC)
+ */
+ for (grp = 0; grp < ADC_LR_GROUP_MAX; grp++)
+ regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON02(grp),
+ RK3308_ADC_CH1_ZEROCROSS_DET_EN |
+ RK3308_ADC_CH2_ZEROCROSS_DET_EN);
+
+ return 0;
+}
+
+static int rk3308_codec_probe(struct snd_soc_component *component)
+{
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+
+ rk3308->component = component;
+
+ rk3308_codec_reset(component);
+ rk3308_codec_initialize(rk3308);
+
+ return 0;
+}
+
+static int rk3308_codec_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct rk3308_codec_priv *rk3308 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_OFF)
+ break;
+
+ /* Sequence from TRM Section 8.6.3 "Power Up" */
+ regmap_set_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+ RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_CURRENT_CHARGE_MSK, 1);
+ regmap_set_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_REF_EN);
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_CURRENT_CHARGE_MSK, 0x7f);
+ msleep(20); /* estimated value */
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* Sequence from TRM Section 8.6.4 "Power Down" */
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_CURRENT_CHARGE_MSK, 1);
+ regmap_clear_bits(rk3308->regmap, RK3308_ADC_ANA_CON10(0),
+ RK3308_ADC_REF_EN);
+ regmap_clear_bits(rk3308->regmap, RK3308_DAC_ANA_CON02,
+ RK3308_DAC_L_DAC_EN | RK3308_DAC_R_DAC_EN);
+ msleep(20); /* estimated value */
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_component_driver rk3308_codec_component_driver = {
+ .probe = rk3308_codec_probe,
+ .set_bias_level = rk3308_codec_set_bias_level,
+ .controls = rk3308_codec_controls,
+ .num_controls = ARRAY_SIZE(rk3308_codec_controls),
+ .dapm_widgets = rk3308_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rk3308_codec_dapm_widgets),
+ .dapm_routes = rk3308_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rk3308_codec_dapm_routes),
+};
+
+static const struct regmap_config rk3308_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = RK3308_DAC_ANA_CON15,
+};
+
+static int rk3308_codec_get_version(struct rk3308_codec_priv *rk3308)
+{
+ unsigned int chip_id;
+ int err;
+
+ err = regmap_read(rk3308->grf, GRF_CHIP_ID, &chip_id);
+ if (err)
+ return err;
+
+ switch (chip_id) {
+ case 3306:
+ rk3308->codec_ver = ACODEC_VERSION_A;
+ break;
+ case 0x3308:
+ rk3308->codec_ver = ACODEC_VERSION_B;
+ return dev_err_probe(rk3308->dev, -EINVAL, "Chip version B not supported\n");
+ case 0x3308c:
+ rk3308->codec_ver = ACODEC_VERSION_C;
+ break;
+ default:
+ return dev_err_probe(rk3308->dev, -EINVAL, "Unknown chip_id: 0x%x\n", chip_id);
+ }
+
+ dev_info(rk3308->dev, "Found codec version %c\n", rk3308->codec_ver);
+ return 0;
+}
+
+static int rk3308_codec_set_micbias_level(struct rk3308_codec_priv *rk3308)
+{
+ struct device_node *np = rk3308->dev->of_node;
+ u32 percent;
+ u32 mult;
+ int err;
+
+ err = of_property_read_u32(np, "rockchip,micbias-avdd-percent", &percent);
+ if (err == -EINVAL)
+ return 0;
+ if (err)
+ return dev_err_probe(rk3308->dev, err,
+ "Error reading 'rockchip,micbias-avdd-percent'\n");
+
+ /* Convert percent to register value, linerarly (50% -> 0, 5% step = +1) */
+ mult = (percent - 50) / 5;
+
+ /* Check range and that the percent was an exact value allowed */
+ if (mult > RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX || mult * 5 + 50 != percent)
+ return dev_err_probe(rk3308->dev, -EINVAL,
+ "Invalid value %u for 'rockchip,micbias-avdd-percent'\n",
+ percent);
+
+ regmap_update_bits(rk3308->regmap, RK3308_ADC_ANA_CON07(0),
+ RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK,
+ mult << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT);
+
+ return 0;
+}
+
+static int rk3308_codec_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct rk3308_codec_priv *rk3308;
+ void __iomem *base;
+ int err;
+
+ rk3308 = devm_kzalloc(&pdev->dev, sizeof(*rk3308), GFP_KERNEL);
+ if (!rk3308)
+ return -ENOMEM;
+
+ rk3308->dev = dev;
+
+ rk3308->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(rk3308->grf))
+ return dev_err_probe(dev, PTR_ERR(rk3308->grf), "Error getting GRF\n");
+
+ rk3308->reset = devm_reset_control_get_optional_exclusive(dev, "codec");
+ if (IS_ERR(rk3308->reset))
+ return dev_err_probe(dev, PTR_ERR(rk3308->reset), "Failed to get reset control\n");
+
+ err = devm_clk_bulk_get(dev, ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to get clocks\n");
+
+ err = clk_bulk_prepare_enable(ARRAY_SIZE(rk3308_codec_clocks), rk3308_codec_clocks);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable clocks\n");
+
+ err = rk3308_codec_get_version(rk3308);
+ if (err)
+ return err;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rk3308->regmap = devm_regmap_init_mmio(dev, base, &rk3308_codec_regmap_config);
+ if (IS_ERR(rk3308->regmap))
+ return dev_err_probe(dev, PTR_ERR(rk3308->regmap),
+ "Failed to init regmap\n");
+
+ platform_set_drvdata(pdev, rk3308);
+
+ err = rk3308_codec_set_micbias_level(rk3308);
+ if (err)
+ return err;
+
+ err = devm_snd_soc_register_component(dev, &rk3308_codec_component_driver,
+ &rk3308_codec_dai_driver, 1);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to register codec\n");
+
+ return 0;
+}
+
+static const struct of_device_id __maybe_unused rk3308_codec_of_match[] = {
+ { .compatible = "rockchip,rk3308-codec", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rk3308_codec_of_match);
+
+static struct platform_driver rk3308_codec_driver = {
+ .driver = {
+ .name = "rk3308-acodec",
+ .of_match_table = rk3308_codec_of_match,
+ },
+ .probe = rk3308_codec_platform_probe,
+};
+module_platform_driver(rk3308_codec_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
+MODULE_DESCRIPTION("ASoC RK3308 Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rk3308_codec.h b/sound/soc/codecs/rk3308_codec.h
new file mode 100644
index 000000000000..a4226b235ab7
--- /dev/null
+++ b/sound/soc/codecs/rk3308_codec.h
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Rockchip RK3308 internal audio codec driver -- register definitions
+ *
+ * Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
+ * Copyright (c) 2022, Vivax-Metrotech Ltd
+ */
+
+#ifndef __RK3308_CODEC_H__
+#define __RK3308_CODEC_H__
+
+#define RK3308_GLB_CON 0x00
+
+/* ADC DIGITAL REGISTERS */
+
+/*
+ * The ADC group are 0 ~ 3, that control:
+ *
+ * CH0: left_0(ADC1) and right_0(ADC2)
+ * CH1: left_1(ADC3) and right_1(ADC4)
+ * CH2: left_2(ADC5) and right_2(ADC6)
+ * CH3: left_3(ADC7) and right_3(ADC8)
+ */
+#define RK3308_ADC_DIG_OFFSET(ch) (((ch) & 0x3) * 0xc0 + 0x0)
+
+#define RK3308_ADC_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x04)
+#define RK3308_ADC_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x08)
+#define RK3308_ADC_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x0c)
+#define RK3308_ADC_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x10)
+#define RK3308_ADC_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x14) // ver.C only
+#define RK3308_ADC_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x18) // ver.C only
+#define RK3308_ADC_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x1c)
+
+#define RK3308_ALC_L_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x40)
+#define RK3308_ALC_L_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x44)
+#define RK3308_ALC_L_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x48)
+#define RK3308_ALC_L_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x4c)
+#define RK3308_ALC_L_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x50)
+#define RK3308_ALC_L_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x54)
+#define RK3308_ALC_L_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x58)
+#define RK3308_ALC_L_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x5c)
+#define RK3308_ALC_L_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x60)
+#define RK3308_ALC_L_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x64)
+#define RK3308_ALC_L_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x70)
+
+#define RK3308_ALC_R_DIG_CON00(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x80)
+#define RK3308_ALC_R_DIG_CON01(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x84)
+#define RK3308_ALC_R_DIG_CON02(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x88)
+#define RK3308_ALC_R_DIG_CON03(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x8c)
+#define RK3308_ALC_R_DIG_CON04(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x90)
+#define RK3308_ALC_R_DIG_CON05(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x94)
+#define RK3308_ALC_R_DIG_CON06(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x98)
+#define RK3308_ALC_R_DIG_CON07(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0x9c)
+#define RK3308_ALC_R_DIG_CON08(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa0)
+#define RK3308_ALC_R_DIG_CON09(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xa4)
+#define RK3308_ALC_R_DIG_CON12(ch) (RK3308_ADC_DIG_OFFSET((ch)) + 0xb0)
+
+/* DAC DIGITAL REGISTERS */
+#define RK3308_DAC_DIG_OFFSET 0x300
+#define RK3308_DAC_DIG_CON01 (RK3308_DAC_DIG_OFFSET + 0x04)
+#define RK3308_DAC_DIG_CON02 (RK3308_DAC_DIG_OFFSET + 0x08)
+#define RK3308_DAC_DIG_CON03 (RK3308_DAC_DIG_OFFSET + 0x0c)
+#define RK3308_DAC_DIG_CON04 (RK3308_DAC_DIG_OFFSET + 0x10)
+#define RK3308_DAC_DIG_CON05 (RK3308_DAC_DIG_OFFSET + 0x14)
+#define RK3308_DAC_DIG_CON10 (RK3308_DAC_DIG_OFFSET + 0x28)
+#define RK3308_DAC_DIG_CON11 (RK3308_DAC_DIG_OFFSET + 0x2c)
+#define RK3308_DAC_DIG_CON13 (RK3308_DAC_DIG_OFFSET + 0x34)
+#define RK3308_DAC_DIG_CON14 (RK3308_DAC_DIG_OFFSET + 0x38)
+
+/* ADC ANALOG REGISTERS */
+/*
+ * The ADC group are 0 ~ 3, that control:
+ *
+ * CH0: left_0(ADC1) and right_0(ADC2)
+ * CH1: left_1(ADC3) and right_1(ADC4)
+ * CH2: left_2(ADC5) and right_2(ADC6)
+ * CH3: left_3(ADC7) and right_3(ADC8)
+ */
+#define RK3308_ADC_ANA_OFFSET(ch) (((ch) & 0x3) * 0x40 + 0x340)
+#define RK3308_ADC_ANA_CON00(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x00)
+#define RK3308_ADC_ANA_CON01(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x04)
+#define RK3308_ADC_ANA_CON02(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x08)
+#define RK3308_ADC_ANA_CON03(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x0c)
+#define RK3308_ADC_ANA_CON04(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x10)
+#define RK3308_ADC_ANA_CON05(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x14)
+#define RK3308_ADC_ANA_CON06(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x18)
+#define RK3308_ADC_ANA_CON07(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x1c)
+#define RK3308_ADC_ANA_CON08(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x20)
+#define RK3308_ADC_ANA_CON10(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x28)
+#define RK3308_ADC_ANA_CON11(ch) (RK3308_ADC_ANA_OFFSET((ch)) + 0x2c)
+
+/* DAC ANALOG REGISTERS */
+#define RK3308_DAC_ANA_OFFSET 0x440
+#define RK3308_DAC_ANA_CON00 (RK3308_DAC_ANA_OFFSET + 0x00)
+#define RK3308_DAC_ANA_CON01 (RK3308_DAC_ANA_OFFSET + 0x04)
+#define RK3308_DAC_ANA_CON02 (RK3308_DAC_ANA_OFFSET + 0x08)
+#define RK3308_DAC_ANA_CON03 (RK3308_DAC_ANA_OFFSET + 0x0c)
+#define RK3308_DAC_ANA_CON04 (RK3308_DAC_ANA_OFFSET + 0x10)
+#define RK3308_DAC_ANA_CON05 (RK3308_DAC_ANA_OFFSET + 0x14)
+#define RK3308_DAC_ANA_CON06 (RK3308_DAC_ANA_OFFSET + 0x18)
+#define RK3308_DAC_ANA_CON07 (RK3308_DAC_ANA_OFFSET + 0x1c)
+#define RK3308_DAC_ANA_CON08 (RK3308_DAC_ANA_OFFSET + 0x20)
+#define RK3308_DAC_ANA_CON12 (RK3308_DAC_ANA_OFFSET + 0x30)
+#define RK3308_DAC_ANA_CON13 (RK3308_DAC_ANA_OFFSET + 0x34)
+#define RK3308_DAC_ANA_CON14 (RK3308_DAC_ANA_OFFSET + 0x38)
+#define RK3308_DAC_ANA_CON15 (RK3308_DAC_ANA_OFFSET + 0x3c)
+
+/*
+ * These are the bits for registers
+ */
+
+/* RK3308_GLB_CON - REG: 0x0000 */
+#define RK3308_ADC_BIST_WORK BIT(7)
+#define RK3308_DAC_BIST_WORK BIT(6)
+#define RK3308_ADC_MCLK_GATING BIT(5)
+#define RK3308_DAC_MCLK_GATING BIT(4)
+#define RK3308_ADC_DIG_WORK BIT(2)
+#define RK3308_DAC_DIG_WORK BIT(1)
+#define RK3308_SYS_WORK BIT(0)
+
+/* RK3308_ADC_DIG_CON01 - REG: 0x0004 */
+#define RK3308_ADC_I2S_LRC_POL_REVERSAL BIT(7)
+#define RK3308_ADC_I2S_VALID_LEN_SFT 5
+#define RK3308_ADC_I2S_VALID_LEN_MSK (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_32BITS (0x3 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_24BITS (0x2 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_20BITS (0x1 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_VALID_LEN_16BITS (0x0 << RK3308_ADC_I2S_VALID_LEN_SFT)
+#define RK3308_ADC_I2S_MODE_SFT 3
+#define RK3308_ADC_I2S_MODE_MSK (0x3 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_PCM (0x3 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_I2S (0x2 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_LJ (0x1 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_MODE_RJ (0x0 << RK3308_ADC_I2S_MODE_SFT)
+#define RK3308_ADC_I2S_LR_SWAP BIT(1)
+#define RK3308_ADC_I2S_MONO BIT(0)
+
+/* RK3308_ADC_DIG_CON02 - REG: 0x0008 */
+#define RK3308_ADC_IO_MODE_MASTER BIT(5)
+#define RK3308_ADC_MODE_MASTER BIT(4)
+#define RK3308_ADC_I2S_FRAME_LEN_SFT 2
+#define RK3308_ADC_I2S_FRAME_LEN_MSK (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_32BITS (0x3 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_24BITS (0x2 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_20BITS (0x1 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_FRAME_16BITS (0x0 << RK3308_ADC_I2S_FRAME_LEN_SFT)
+#define RK3308_ADC_I2S_WORK BIT(1)
+#define RK3308_ADC_I2S_BIT_CLK_POL_REVERSAL BIT(0)
+
+/* RK3308_ADC_DIG_CON03 - REG: 0x000c */
+#define RK3308_ADC_L_CH_BIST_SFT 2
+#define RK3308_ADC_L_CH_BIST_MSK (0x3 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_NORMAL_RIGHT (0x3 << RK3308_ADC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_L_CH_BIST_CUBE (0x2 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_BIST_SINE (0x1 << RK3308_ADC_L_CH_BIST_SFT)
+#define RK3308_ADC_L_CH_NORMAL_LEFT (0x0 << RK3308_ADC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_R_CH_BIST_SFT 0
+#define RK3308_ADC_R_CH_BIST_MSK (0x3 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_NORMAL_LEFT (0x3 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */
+#define RK3308_ADC_R_CH_BIST_CUBE (0x2 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_BIST_SINE (0x1 << RK3308_ADC_R_CH_BIST_SFT)
+#define RK3308_ADC_R_CH_NORMAL_RIGHT (0x0 << RK3308_ADC_R_CH_BIST_SFT) /* normal mode */
+
+/* RK3308_ADC_DIG_CON04 - REG: 0x0010 */
+#define RK3308_ADC_HPF_PATH_DIS BIT(2)
+#define RK3308_ADC_HPF_CUTOFF_SFT 0
+#define RK3308_ADC_HPF_CUTOFF_MSK (0x3 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_612HZ (0x2 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_245HZ (0x1 << RK3308_ADC_HPF_CUTOFF_SFT)
+#define RK3308_ADC_HPF_CUTOFF_20HZ (0x0 << RK3308_ADC_HPF_CUTOFF_SFT)
+
+/* RK3308_ADC_DIG_CON07 - REG: 0x001c */
+#define RK3308_ADCL_DATA_SFT 4
+#define RK3308_ADCR_DATA_SFT 2
+#define RK3308_ADCL_DATA_SEL_ADCL BIT(1)
+#define RK3308_ADCR_DATA_SEL_ADCR BIT(0)
+
+/*
+ * RK3308_ALC_L_DIG_CON00 - REG: 0x0040 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON00 - REG: 0x0080 + ch * 0xc0
+ */
+#define RK3308_GAIN_ATTACK_JACK BIT(6)
+#define RK3308_CTRL_GEN_SFT 4
+#define RK3308_CTRL_GEN_MSK (0x3 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK3 (0x3 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK2 (0x2 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_JACK1 (0x1 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_CTRL_GEN_NORMAL (0x0 << RK3308_ALC_CTRL_GEN_SFT)
+#define RK3308_AGC_HOLD_TIME_SFT 0
+#define RK3308_AGC_HOLD_TIME_MSK (0xf << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_1S (0xa << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_512MS (0x9 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_256MS (0x8 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_128MS (0x7 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_64MS (0x6 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_32MS (0x5 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_16MS (0x4 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_8MS (0x3 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_4MS (0x2 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_2MS (0x1 << RK3308_AGC_HOLD_TIME_SFT)
+#define RK3308_AGC_HOLD_TIME_0MS (0x0 << RK3308_AGC_HOLD_TIME_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON01 - REG: 0x0044 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON01 - REG: 0x0084 + ch * 0xc0
+ */
+#define RK3308_AGC_DECAY_TIME_SFT 4
+#define RK3308_AGC_ATTACK_TIME_SFT 0
+
+/*
+ * RK3308_ALC_L_DIG_CON02 - REG: 0x0048 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON02 - REG: 0x0088 + ch * 0xc0
+ */
+#define RK3308_AGC_MODE_LIMITER BIT(7)
+#define RK3308_AGC_ZERO_CRO_EN BIT(6)
+#define RK3308_AGC_AMP_RECOVER_GAIN BIT(5)
+#define RK3308_AGC_FAST_DEC_EN BIT(4)
+#define RK3308_AGC_NOISE_GATE_EN BIT(3)
+#define RK3308_AGC_NOISE_GATE_THRESH_SFT 0
+#define RK3308_AGC_NOISE_GATE_THRESH_MSK (0x7 << RK3308_AGC_NOISE_GATE_THRESH_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON03 - REG: 0x004c + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON03 - REG: 0x008c + ch * 0xc0
+ */
+#define RK3308_AGC_PGA_ZERO_CRO_EN BIT(5)
+#define RK3308_AGC_PGA_GAIN_MAX 0x1f
+#define RK3308_AGC_PGA_GAIN_MIN 0
+#define RK3308_AGC_PGA_GAIN_SFT 0
+
+/*
+ * RK3308_ALC_L_DIG_CON04 - REG: 0x0050 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON04 - REG: 0x0090 + ch * 0xc0
+ */
+#define RK3308_AGC_SLOW_CLK_EN BIT(3)
+#define RK3308_AGC_APPROX_RATE_SFT 0
+#define RK3308_AGC_APPROX_RATE_MSK (0x7 << RK3308_AGC_APPROX_RATE_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON05 - REG: 0x0054 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON05 - REG: 0x0094 + ch * 0xc0
+ */
+#define RK3308_AGC_LO_8BITS_AGC_MAX_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON06 - REG: 0x0058 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON06 - REG: 0x0098 + ch * 0xc0
+ */
+#define RK3308_AGC_HI_8BITS_AGC_MAX_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON07 - REG: 0x005c + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON07 - REG: 0x009c + ch * 0xc0
+ */
+#define RK3308_AGC_LO_8BITS_AGC_MIN_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON08 - REG: 0x0060 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON08 - REG: 0x00a0 + ch * 0xc0
+ */
+#define RK3308_AGC_HI_8BITS_AGC_MIN_MSK 0xff
+
+/*
+ * RK3308_ALC_L_DIG_CON09 - REG: 0x0064 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON09 - REG: 0x00a4 + ch * 0xc0
+ */
+#define RK3308_AGC_FUNC_SEL BIT(6)
+#define RK3308_AGC_MAX_GAIN_PGA_MAX 0x7
+#define RK3308_AGC_MAX_GAIN_PGA_MIN 0
+#define RK3308_AGC_MAX_GAIN_PGA_SFT 3
+#define RK3308_AGC_MAX_GAIN_PGA_MSK (0x7 << RK3308_AGC_MAX_GAIN_PGA_SFT)
+#define RK3308_AGC_MIN_GAIN_PGA_MAX 0x7
+#define RK3308_AGC_MIN_GAIN_PGA_MIN 0
+#define RK3308_AGC_MIN_GAIN_PGA_SFT 0
+#define RK3308_AGC_MIN_GAIN_PGA_MSK (0x7 << RK3308_AGC_MIN_GAIN_PGA_SFT)
+
+/*
+ * RK3308_ALC_L_DIG_CON12 - REG: 0x0068 + ch * 0xc0
+ * RK3308_ALC_R_DIG_CON12 - REG: 0x00a8 + ch * 0xc0
+ */
+#define RK3308_AGC_GAIN_MSK 0x1f
+
+/* RK3308_DAC_DIG_CON01 - REG: 0x0304 */
+#define RK3308_DAC_I2S_LRC_POL_REVERSAL BIT(7)
+#define RK3308_DAC_I2S_VALID_LEN_SFT 5
+#define RK3308_DAC_I2S_VALID_LEN_MSK (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_32BITS (0x3 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_24BITS (0x2 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_20BITS (0x1 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_VALID_LEN_16BITS (0x0 << RK3308_DAC_I2S_VALID_LEN_SFT)
+#define RK3308_DAC_I2S_MODE_SFT 3
+#define RK3308_DAC_I2S_MODE_MSK (0x3 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_PCM (0x3 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_I2S (0x2 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_LJ (0x1 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_MODE_RJ (0x0 << RK3308_DAC_I2S_MODE_SFT)
+#define RK3308_DAC_I2S_LR_SWAP BIT(2)
+
+/* RK3308_DAC_DIG_CON02 - REG: 0x0308 */
+#define RK3308BS_DAC_IO_MODE_MASTER BIT(7)
+#define RK3308BS_DAC_MODE_MASTER BIT(6)
+#define RK3308_DAC_IO_MODE_MASTER BIT(5)
+#define RK3308_DAC_MODE_MASTER BIT(4)
+#define RK3308_DAC_I2S_FRAME_LEN_SFT 2
+#define RK3308_DAC_I2S_FRAME_LEN_MSK (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_32BITS (0x3 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_24BITS (0x2 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_20BITS (0x1 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_FRAME_16BITS (0x0 << RK3308_DAC_I2S_FRAME_LEN_SFT)
+#define RK3308_DAC_I2S_WORK BIT(1)
+#define RK3308_DAC_I2S_BIT_CLK_POL_REVERSAL BIT(0)
+
+/* RK3308_DAC_DIG_CON03 - REG: 0x030C */
+#define RK3308_DAC_L_CH_BIST_SFT 2
+#define RK3308_DAC_L_CH_BIST_MSK (0x3 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_LEFT (0x3 << RK3308_DAC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_L_CH_BIST_CUBE (0x2 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_SINE (0x1 << RK3308_DAC_L_CH_BIST_SFT)
+#define RK3308_DAC_L_CH_BIST_RIGHT (0x0 << RK3308_DAC_L_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_R_CH_BIST_SFT 0
+#define RK3308_DAC_R_CH_BIST_MSK (0x3 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_LEFT (0x3 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */
+#define RK3308_DAC_R_CH_BIST_CUBE (0x2 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_SINE (0x1 << RK3308_DAC_R_CH_BIST_SFT)
+#define RK3308_DAC_R_CH_BIST_RIGHT (0x0 << RK3308_DAC_R_CH_BIST_SFT) /* normal mode */
+
+/* RK3308_DAC_DIG_CON04 - REG: 0x0310 */
+/* Versions up to B: */
+#define RK3308_DAC_MODULATOR_GAIN_SFT 4
+#define RK3308_DAC_MODULATOR_GAIN_MSK (0x7 << RK3308_DAC_MODULATOR_GAIN_SFT)
+#define RK3308_DAC_CIC_IF_GAIN_SFT 0
+#define RK3308_DAC_CIC_IF_GAIN_MSK (0x7 << RK3308_DAC_CIC_IF_GAIN_SFT)
+/* Version C: */
+#define RK3308BS_DAC_DIG_GAIN_SFT 0
+#define RK3308BS_DAC_DIG_GAIN_MSK (0xff << RK3308BS_DAC_DIG_GAIN_SFT)
+#define RK3308BS_DAC_DIG_GAIN_0DB (0xed << RK3308BS_DAC_DIG_GAIN_SFT)
+
+/* RK3308BS_ADC_DIG_CON05..06 (Version C only) */
+#define RK3308_ADC_DIG_VOL_CON_x_SFT 0
+#define RK3308_ADC_DIG_VOL_CON_x_MSK (0xff << RK3308_ADC_DIG_VOL_CON_x_SFT)
+#define RK3308_ADC_DIG_VOL_CON_x_0DB (0xc2 << RK3308_ADC_DIG_VOL_CON_x_SFT)
+
+/* RK3308_DAC_DIG_CON05 - REG: 0x0314 */
+#define RK3308_DAC_L_REG_CTL_INDATA BIT(2)
+#define RK3308_DAC_R_REG_CTL_INDATA BIT(1)
+
+/* RK3308_DAC_DIG_CON10 - REG: 0x0328 */
+#define RK3308_DAC_DATA_HI4(x) ((x) & 0xf)
+
+/* RK3308_DAC_DIG_CON11 - REG: 0x032c */
+#define RK3308_DAC_DATA_LO8(x) ((x) & 0xff)
+
+/* RK3308_ADC_ANA_CON00 - REG: 0x0340 */
+#define RK3308_ADC_CH1_CH2_MIC_ALL_MSK (0xff << 0)
+#define RK3308_ADC_CH1_CH2_MIC_ALL 0xff
+#define RK3308_ADC_CH2_MIC_UNMUTE BIT(7)
+#define RK3308_ADC_CH2_MIC_WORK BIT(6)
+#define RK3308_ADC_CH2_MIC_EN BIT(5)
+#define RK3308_ADC_CH2_BUF_REF_EN BIT(4)
+#define RK3308_ADC_CH1_MIC_UNMUTE BIT(3)
+#define RK3308_ADC_CH1_MIC_WORK BIT(2)
+#define RK3308_ADC_CH1_MIC_EN BIT(1)
+#define RK3308_ADC_CH1_BUF_REF_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON01 - REG: 0x0344
+ *
+ * The PGA of MIC-INs:
+ * - HW version A:
+ * 0x0 - MIC1~MIC8 0 dB (recommended when ADC used as loopback)
+ * 0x3 - MIC1~MIC8 20 dB (recommended when ADC used as MIC input)
+ * - HW version B:
+ * 0x0 - MIC1~MIC8 0 dB
+ * 0x1 - MIC1~MIC8 6.6 dB
+ * 0x2 - MIC1~MIC8 13 dB
+ * 0x3 - MIC1~MIC8 20 dB
+ */
+#define RK3308_ADC_CH2_MIC_GAIN_MAX 0x3
+#define RK3308_ADC_CH2_MIC_GAIN_MIN 0
+#define RK3308_ADC_CH2_MIC_GAIN_SFT 4
+#define RK3308_ADC_CH2_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+#define RK3308_ADC_CH2_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH2_MIC_GAIN_SFT)
+
+#define RK3308_ADC_CH1_MIC_GAIN_MAX 0x3
+#define RK3308_ADC_CH1_MIC_GAIN_MIN 0
+#define RK3308_ADC_CH1_MIC_GAIN_SFT 0
+#define RK3308_ADC_CH1_MIC_GAIN_MSK (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_20DB (0x3 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_13DB (0x2 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_6_6DB (0x1 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+#define RK3308_ADC_CH1_MIC_GAIN_0DB (0x0 << RK3308_ADC_CH1_MIC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON02 - REG: 0x0348 */
+#define RK3308_ADC_CH2_ZEROCROSS_DET_EN BIT(6)
+#define RK3308_ADC_CH2_ALC_WORK BIT(5)
+#define RK3308_ADC_CH2_ALC_EN BIT(4)
+#define RK3308_ADC_CH1_ZEROCROSS_DET_EN BIT(2)
+#define RK3308_ADC_CH1_ALC_WORK BIT(1)
+#define RK3308_ADC_CH1_ALC_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON03 - REG: 0x034c */
+#define RK3308_ADC_CH1_ALC_GAIN_MAX 0x1f
+#define RK3308_ADC_CH1_ALC_GAIN_MIN 0
+#define RK3308_ADC_CH1_ALC_GAIN_SFT 0
+#define RK3308_ADC_CH1_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH1_ALC_GAIN_SFT)
+#define RK3308_ADC_CH1_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH1_ALC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON04 - REG: 0x0350 */
+#define RK3308_ADC_CH2_ALC_GAIN_MAX 0x1f
+#define RK3308_ADC_CH2_ALC_GAIN_MIN 0
+#define RK3308_ADC_CH2_ALC_GAIN_SFT 0
+#define RK3308_ADC_CH2_ALC_GAIN_MSK (0x1f << RK3308_ADC_CH2_ALC_GAIN_SFT)
+#define RK3308_ADC_CH2_ALC_GAIN_0DB (0x0c << RK3308_ADC_CH2_ALC_GAIN_SFT)
+
+/* RK3308_ADC_ANA_CON05 - REG: 0x0354 */
+#define RK3308_ADC_CH2_ADC_WORK BIT(6)
+#define RK3308_ADC_CH2_ADC_EN BIT(5)
+#define RK3308_ADC_CH2_CLK_EN BIT(4)
+#define RK3308_ADC_CH1_ADC_WORK BIT(2)
+#define RK3308_ADC_CH1_ADC_EN BIT(1)
+#define RK3308_ADC_CH1_CLK_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON06 - REG: 0x0358 */
+#define RK3308_ADC_CURRENT_EN BIT(0)
+
+/* RK3308_ADC_ANA_CON07 - REG: 0x035c */
+/* Note: The register configuration is only valid for ADC2 */
+#define RK3308_ADC_CH2_IN_SEL_SFT 6
+#define RK3308_ADC_CH2_IN_SEL_MSK (0x3 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_LINEIN_MIC (0x3 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_LINEIN (0x2 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_MIC (0x1 << RK3308_ADC_CH2_IN_SEL_SFT)
+#define RK3308_ADC_CH2_IN_NONE (0x0 << RK3308_ADC_CH2_IN_SEL_SFT)
+/* Note: The register configuration is only valid for ADC1 */
+#define RK3308_ADC_CH1_IN_SEL_SFT 4
+#define RK3308_ADC_CH1_IN_SEL_MSK (0x3 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_LINEIN_MIC (0x3 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_LINEIN (0x2 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_MIC (0x1 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_CH1_IN_NONE (0x0 << RK3308_ADC_CH1_IN_SEL_SFT)
+#define RK3308_ADC_MIC_BIAS_BUF_EN BIT(3)
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MAX 7
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT 0
+#define RK3308_ADC_LEVEL_RANGE_MICBIAS_MSK (0x7 << RK3308_ADC_LEVEL_RANGE_MICBIAS_SFT)
+
+/* RK3308_ADC_ANA_CON08 - REG: 0x0360 */
+#define RK3308_ADC_MICBIAS_CURRENT_EN BIT(4)
+
+/* RK3308_ADC_ANA_CON10 - REG: 0x0368 */
+#define RK3308_ADC_REF_EN BIT(7)
+#define RK3308_ADC_CURRENT_CHARGE_SFT 0
+#define RK3308_ADC_CURRENT_CHARGE_MSK (0x7f << RK3308_ADC_CURRENT_CHARGE_SFT)
+
+/* RK3308_ADC_ANA_CON11 - REG: 0x036c */
+#define RK3308_ADC_ALCR_CON_GAIN_PGAR_EN BIT(1)
+#define RK3308_ADC_ALCL_CON_GAIN_PGAL_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON00 - REG: 0x0440 */
+#define RK3308_DAC_HEADPHONE_DET_EN BIT(1)
+#define RK3308_DAC_CURRENT_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON01 - REG: 0x0444 */
+#define RK3308_DAC_BUF_REF_R_EN BIT(6)
+#define RK3308_DAC_BUF_REF_L_EN BIT(2)
+#define RK3308_DAC_HPOUT_POP_SOUND_R_SFT 4
+#define RK3308_DAC_HPOUT_POP_SOUND_L_SFT 0
+// unshifted values for both L and R:
+#define RK3308_DAC_HPOUT_POP_SOUND_x_MSK 0x3
+#define RK3308_DAC_HPOUT_POP_SOUND_x_WORK 0x2
+#define RK3308_DAC_HPOUT_POP_SOUND_x_INIT 0x1
+
+/* RK3308_DAC_ANA_CON02 - REG: 0x0448 */
+#define RK3308_DAC_R_DAC_WORK BIT(7)
+#define RK3308_DAC_R_DAC_EN BIT(6)
+#define RK3308_DAC_R_CLK_EN BIT(5)
+#define RK3308_DAC_R_REF_EN BIT(4)
+#define RK3308_DAC_L_DAC_WORK BIT(3)
+#define RK3308_DAC_L_DAC_EN BIT(2)
+#define RK3308_DAC_L_CLK_EN BIT(1)
+#define RK3308_DAC_L_REF_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON03 - REG: 0x044c */
+#define RK3308_DAC_R_HPOUT_WORK BIT(6)
+#define RK3308_DAC_R_HPOUT_EN BIT(5)
+#define RK3308_DAC_R_HPOUT_MUTE_SFT 4
+#define RK3308_DAC_L_HPOUT_WORK BIT(2)
+#define RK3308_DAC_L_HPOUT_EN BIT(1)
+#define RK3308_DAC_L_HPOUT_MUTE_SFT 0
+
+/* RK3308_DAC_ANA_CON04 - REG: 0x0450 */
+#define RK3308_DAC_x_LINEOUT_GAIN_MAX 0x3
+#define RK3308_DAC_R_LINEOUT_GAIN_SFT 6
+#define RK3308_DAC_R_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_R_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_R_LINEOUT_MUTE_SFT 5
+#define RK3308_DAC_R_LINEOUT_EN BIT(4)
+#define RK3308_DAC_L_LINEOUT_GAIN_SFT 2
+#define RK3308_DAC_L_LINEOUT_GAIN_MSK (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_0DB (0x3 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_1_5 (0x2 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_3 (0x1 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_GAIN_NDB_6 (0x0 << RK3308_DAC_L_LINEOUT_GAIN_SFT)
+#define RK3308_DAC_L_LINEOUT_MUTE_SFT 1
+#define RK3308_DAC_L_LINEOUT_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON05 - REG: 0x0454, step is 1.5db */
+/* RK3308_DAC_ANA_CON06 - REG: 0x0458, step is 1.5db */
+#define RK3308_DAC_x_HPOUT_GAIN_MAX 0x1e
+#define RK3308_DAC_x_HPOUT_GAIN_SFT 0
+#define RK3308_DAC_x_HPOUT_GAIN_MSK (0x1f << RK3308_DAC_x_HPOUT_GAIN_SFT)
+#define RK3308_DAC_x_HPOUT_GAIN_MIN (0x00 << RK3308_DAC_x_HPOUT_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON07 - REG: 0x045c */
+#define RK3308_DAC_R_HPOUT_DRV_SFT 4
+#define RK3308_DAC_R_HPOUT_DRV_MSK (0xf << RK3308_DAC_R_HPOUT_DRV_SFT)
+#define RK3308_DAC_L_HPOUT_DRV_SFT 0
+#define RK3308_DAC_L_HPOUT_DRV_MSK (0xf << RK3308_DAC_L_HPOUT_DRV_SFT)
+
+/* RK3308_DAC_ANA_CON08 - REG: 0x0460 */
+#define RK3308_DAC_R_LINEOUT_DRV_SFT 4
+#define RK3308_DAC_R_LINEOUT_DRV_MSK (0xf << RK3308_DAC_R_LINEOUT_DRV_SFT)
+#define RK3308_DAC_L_LINEOUT_DRV_SFT 0
+#define RK3308_DAC_L_LINEOUT_DRV_MSK (0xf << RK3308_DAC_L_LINEOUT_DRV_SFT)
+
+/* RK3308_DAC_ANA_CON12 - REG: 0x0470 */
+#define RK3308_DAC_R_HPMIX_SEL_SFT 6
+#define RK3308_DAC_R_HPMIX_SEL_MSK (0x3 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_LINEIN_I2S (0x3 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_LINEIN (0x2 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_I2S (0x1 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_R_HPMIX_NONE (0x0 << RK3308_DAC_R_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_SEL_SFT 2
+#define RK3308_DAC_L_HPMIX_SEL_MSK (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_LINEIN_I2S (0x3 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_LINEIN (0x2 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_I2S (0x1 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_L_HPMIX_NONE (0x0 << RK3308_DAC_L_HPMIX_SEL_SFT)
+#define RK3308_DAC_x_HPMIX_GAIN_MIN 0x1 /* 0x0 and 0x3 are reserved */
+#define RK3308_DAC_x_HPMIX_GAIN_MAX 0x2
+#define RK3308_DAC_R_HPMIX_GAIN_SFT 4
+#define RK3308_DAC_R_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_R_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_R_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_SFT 0
+#define RK3308_DAC_L_HPMIX_GAIN_MSK (0x3 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_0DB (0x2 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+#define RK3308_DAC_L_HPMIX_GAIN_NDB_6 (0x1 << RK3308_DAC_L_HPMIX_GAIN_SFT)
+
+/* RK3308_DAC_ANA_CON13 - REG: 0x0474 */
+#define RK3308_DAC_R_HPMIX_UNMUTE BIT(6)
+#define RK3308_DAC_R_HPMIX_WORK BIT(5)
+#define RK3308_DAC_R_HPMIX_EN BIT(4)
+#define RK3308_DAC_L_HPMIX_UNMUTE BIT(2)
+#define RK3308_DAC_L_HPMIX_WORK BIT(1)
+#define RK3308_DAC_L_HPMIX_EN BIT(0)
+
+/* RK3308_DAC_ANA_CON14 - REG: 0x0478 */
+#define RK3308_DAC_VCM_LINEOUT_EN (0x1 << 4)
+#define RK3308_DAC_CURRENT_CHARGE_SFT 0
+#define RK3308_DAC_CURRENT_CHARGE_MSK (0xf << RK3308_DAC_CURRENT_CHARGE_SFT)
+
+/* RK3308_DAC_ANA_CON15 - REG: 0x047C */
+#define RK3308_DAC_LINEOUT_POP_SOUND_R_SFT 4
+#define RK3308_DAC_LINEOUT_POP_SOUND_R_MSK (0x3 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_DC_FROM_INTERNAL (0x2 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_DC_FROM_VCM (0x1 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_R_SEL_LINEOUT_FROM_INTERNAL (0x0 << RK3308_DAC_LINEOUT_POP_SOUND_R_SFT)
+#define RK3308_DAC_LINEOUT_POP_SOUND_L_SFT 0
+#define RK3308_DAC_LINEOUT_POP_SOUND_L_MSK (0x3 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_DC_FROM_INTERNAL (0x2 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_DC_FROM_VCM (0x1 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+#define RK3308_DAC_L_SEL_LINEOUT_FROM_INTERNAL (0x0 << RK3308_DAC_LINEOUT_POP_SOUND_L_SFT)
+
+#endif /* __RK3308_CODEC_H__ */
diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c
index d4da98469f8b..3c9957b00881 100644
--- a/sound/soc/codecs/rk817_codec.c
+++ b/sound/soc/codecs/rk817_codec.c
@@ -10,7 +10,6 @@
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <sound/core.h>
@@ -304,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:
@@ -530,7 +529,7 @@ static struct platform_driver rk817_codec_driver = {
.name = "rk817-codec",
},
.probe = rk817_platform_probe,
- .remove_new = rk817_platform_remove,
+ .remove = rk817_platform_remove,
};
module_platform_driver(rk817_codec_driver);
diff --git a/sound/soc/codecs/rt-sdw-common.c b/sound/soc/codecs/rt-sdw-common.c
new file mode 100644
index 000000000000..ad61943ce75f
--- /dev/null
+++ b/sound/soc/codecs/rt-sdw-common.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt-sdw-common.c
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+
+/*
+ * This file defines common functions used with Realtek soundwire codecs.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/jack.h>
+
+#include "rt-sdw-common.h"
+
+/**
+ * rt_sdca_index_write - Write a value to Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @value: value.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_index_write(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int value)
+{
+ unsigned int addr = (nid << 20) | reg;
+ int ret;
+
+ ret = regmap_write(map, addr, value);
+ if (ret < 0)
+ pr_err("Failed to set value: %06x <= %04x ret=%d\n",
+ addr, value, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_write);
+
+/**
+ * rt_sdca_index_read - Read value from Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @value: value.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_index_read(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int *value)
+{
+ unsigned int addr = (nid << 20) | reg;
+ int ret;
+
+ ret = regmap_read(map, addr, value);
+ if (ret < 0)
+ pr_err("Failed to get value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_read);
+
+/**
+ * rt_sdca_index_update_bits - Update value on Realtek defined register.
+ *
+ * @map: map for setting.
+ * @nid: Realtek-defined ID.
+ * @reg: register.
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+
+int rt_sdca_index_update_bits(struct regmap *map,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp;
+ int ret;
+
+ ret = rt_sdca_index_read(map, nid, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ set_mask_bits(&tmp, mask, val);
+ return rt_sdca_index_write(map, nid, reg, tmp);
+}
+EXPORT_SYMBOL_GPL(rt_sdca_index_update_bits);
+
+/**
+ * rt_sdca_btn_type - Decision of button type.
+ *
+ * @buffer: UMP message buffer.
+ *
+ * A button type will be returned regarding to buffer,
+ * it returns zero if buffer cannot be recognized.
+ */
+int rt_sdca_btn_type(unsigned char *buffer)
+{
+ u8 btn_type = 0;
+ int ret = 0;
+
+ btn_type |= buffer[0] & 0xf;
+ btn_type |= (buffer[0] >> 4) & 0xf;
+ btn_type |= buffer[1] & 0xf;
+ btn_type |= (buffer[1] >> 4) & 0xf;
+
+ if (btn_type & BIT(0))
+ ret |= SND_JACK_BTN_2;
+ if (btn_type & BIT(1))
+ ret |= SND_JACK_BTN_3;
+ if (btn_type & BIT(2))
+ ret |= SND_JACK_BTN_0;
+ if (btn_type & BIT(3))
+ ret |= SND_JACK_BTN_1;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_btn_type);
+
+/**
+ * rt_sdca_headset_detect - Headset jack type detection.
+ *
+ * @map: map for setting.
+ * @entity_id: SDCA entity ID.
+ *
+ * A headset jack type will be returned, a negative errno will
+ * be returned in error cases.
+ */
+int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id)
+{
+ unsigned int det_mode, jack_type;
+ int ret;
+
+ /* get detected_mode */
+ ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
+ RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x03:
+ jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ jack_type = SND_JACK_HEADSET;
+ break;
+ default:
+ jack_type = 0;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id,
+ RT_SDCA_CTL_SELECTED_MODE, 0), det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ return jack_type;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_headset_detect);
+
+/**
+ * rt_sdca_button_detect - Read UMP message and decide button type.
+ *
+ * @map: map for setting.
+ * @entity_id: SDCA entity ID.
+ * @hid_buf_addr: HID buffer address.
+ * @hid_id: Report ID for HID.
+ *
+ * A button type will be returned regarding to buffer,
+ * it returns zero if buffer cannot be recognized.
+ */
+int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id,
+ unsigned int hid_buf_addr, unsigned int hid_id)
+{
+ unsigned int btn_type = 0, offset, idx, val, owner;
+ unsigned char buf[3];
+ int ret;
+
+ /* get current UMP message owner */
+ ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+ RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner);
+ if (ret < 0)
+ return 0;
+
+ /* if owner is device then there is no button event from device */
+ if (owner == 1)
+ return 0;
+
+ /* read UMP message offset */
+ ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+ RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(map, hid_buf_addr + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+ /* Report ID for HID */
+ if (buf[0] == hid_id)
+ btn_type = rt_sdca_btn_type(&buf[1]);
+
+_end_btn_det_:
+ /* Host is owner, so set back to device */
+ if (owner == 0)
+ /* set owner to device */
+ regmap_write(map,
+ SDW_SDCA_CTL(SDCA_NUM_HID, entity_id,
+ RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+
+ return btn_type;
+}
+EXPORT_SYMBOL_GPL(rt_sdca_button_detect);
+
+MODULE_DESCRIPTION("Realtek soundwire common functions");
+MODULE_AUTHOR("jack yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt-sdw-common.h b/sound/soc/codecs/rt-sdw-common.h
new file mode 100644
index 000000000000..4759516feb38
--- /dev/null
+++ b/sound/soc/codecs/rt-sdw-common.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// rt-sdw-common.h
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+
+/*
+ * This file defines common functions used with Realtek soundwire codecs.
+ */
+
+#ifndef __RT_SDW_COMMON_H__
+#define __RT_SDW_COMMON_H__
+
+#define SDCA_NUM_JACK_CODEC 0x01
+#define SDCA_NUM_MIC_ARRAY 0x02
+#define SDCA_NUM_HID 0x03
+#define SDCA_NUM_AMP 0x04
+#define RT_SDCA_CTL_SELECTED_MODE 0x01
+#define RT_SDCA_CTL_DETECTED_MODE 0x02
+#define RT_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+
+struct rt_sdca_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+#define RT_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+ ((unsigned long)&(struct rt_sdca_dmic_kctrl_priv) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .invert = xinvert})
+
+#define RT_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount, \
+ xinfo, xget, xput) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = xinfo, \
+ .get = xget, \
+ .put = xput, \
+ .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, xcount, xmax, tlv_array, xinfo) \
+{ .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 = xinfo, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+
+int rt_sdca_index_write(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int value);
+int rt_sdca_index_read(struct regmap *map, unsigned int nid,
+ unsigned int reg, unsigned int *value);
+int rt_sdca_index_update_bits(struct regmap *map,
+ unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val);
+int rt_sdca_btn_type(unsigned char *buffer);
+int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id);
+int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id,
+ unsigned int hid_buf_addr, unsigned int hid_id);
+
+#endif /* __RT_SDW_COMMON_H__ */
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index 4ceb410c5024..9f34a6a35487 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -13,11 +13,9 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <sound/core.h>
@@ -1036,8 +1034,7 @@ static void rt1011_reset(struct regmap *regmap)
static int rt1011_recv_spk_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);
@@ -1049,15 +1046,15 @@ static int rt1011_recv_spk_mode_get(struct snd_kcontrol *kcontrol,
static int rt1011_recv_spk_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);
if (ucontrol->value.integer.value[0] == rt1011->recv_spk_mode)
return 0;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
rt1011->recv_spk_mode = ucontrol->value.integer.value[0];
if (rt1011->recv_spk_mode) {
@@ -1112,8 +1109,7 @@ static bool rt1011_validate_bq_drc_coeff(unsigned short reg)
static int rt1011_bq_drc_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);
struct rt1011_bq_drc_params *bq_drc_info;
@@ -1149,8 +1145,7 @@ static int rt1011_bq_drc_coeff_get(struct snd_kcontrol *kcontrol,
static int rt1011_bq_drc_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);
struct rt1011_bq_drc_params *bq_drc_info;
@@ -1226,10 +1221,11 @@ static int rt1011_r0_cali_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component);
rt1011->cali_done = 0;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF &&
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF &&
ucontrol->value.integer.value[0])
rt1011_calibrate(rt1011, 1);
@@ -1266,6 +1262,7 @@ static int rt1011_r0_load_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component);
struct device *dev;
unsigned int r0_integer, r0_factor, format;
@@ -1277,7 +1274,7 @@ static int rt1011_r0_load_mode_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
dev = regmap_get_device(rt1011->regmap);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
rt1011->r0_reg = ucontrol->value.integer.value[0];
format = 2147483648U; /* 2^24 * 128 */
@@ -1321,8 +1318,7 @@ static SOC_ENUM_SINGLE_DECL(rt1011_i2s_ref_enum, 0, 0,
static int rt1011_i2s_ref_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);
@@ -1350,8 +1346,7 @@ static int rt1011_i2s_ref_put(struct snd_kcontrol *kcontrol,
static int rt1011_i2s_ref_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1011_priv *rt1011 =
snd_soc_component_get_drvdata(component);
@@ -1666,14 +1661,13 @@ static int rt1011_hw_params(struct snd_pcm_substream *substream,
static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int reg_val = 0, reg_bclk_inv = 0;
int ret = 0;
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:
@@ -1847,8 +1841,7 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int val = 0, tdm_en = 0, rx_slotnum, tx_slotnum;
int ret = 0, first_bit, last_bit;
@@ -2184,7 +2177,7 @@ static const struct regmap_config rt1011_regmap = {
.max_register = RT1011_MAX_REG + 1,
.volatile_reg = rt1011_volatile_register,
.readable_reg = rt1011_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1011_reg,
.num_reg_defaults = ARRAY_SIZE(rt1011_reg),
.use_single_read = true,
@@ -2194,21 +2187,21 @@ 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
static const struct i2c_device_id rt1011_i2c_id[] = {
- { "rt1011", 0 },
+ { "rt1011" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt1011_i2c_id);
@@ -2220,8 +2213,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag)
unsigned int dc_offset;
unsigned int r0_integer, r0_factor, format;
struct device *dev = regmap_get_device(rt1011->regmap);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(rt1011->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1011->component);
int ret = 0;
snd_soc_dapm_mutex_lock(dapm);
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 38d9f69b08d6..ca1ed9d5a24e 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/fs.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -428,8 +427,7 @@ static SOC_ENUM_SINGLE_DECL(rt1015_boost_mode_enum, 0, 0,
static int rt1015_boost_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1015_priv *rt1015 =
snd_soc_component_get_drvdata(component);
@@ -441,8 +439,7 @@ static int rt1015_boost_mode_get(struct snd_kcontrol *kcontrol,
static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1015_priv *rt1015 =
snd_soc_component_get_drvdata(component);
int boost_mode = ucontrol->value.integer.value[0];
@@ -482,8 +479,7 @@ static int rt1015_boost_mode_put(struct snd_kcontrol *kcontrol,
static int rt1015_bypass_boost_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1015_priv *rt1015 =
snd_soc_component_get_drvdata(component);
@@ -495,9 +491,10 @@ static int rt1015_bypass_boost_get(struct snd_kcontrol *kcontrol,
static void rt1015_calibrate(struct rt1015_priv *rt1015)
{
struct snd_soc_component *component = rt1015->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct regmap *regmap = rt1015->regmap;
- snd_soc_dapm_mutex_lock(&component->dapm);
+ snd_soc_dapm_mutex_lock(dapm);
regcache_cache_bypass(regmap, true);
regmap_write(regmap, RT1015_CLK_DET, 0x0000);
@@ -519,14 +516,13 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
regcache_cache_bypass(regmap, false);
regcache_mark_dirty(regmap);
regcache_sync(regmap);
- snd_soc_dapm_mutex_unlock(&component->dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt1015_priv *rt1015 =
snd_soc_component_get_drvdata(component);
@@ -547,6 +543,16 @@ static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static const char * const rt1015_dac_output_vol_select[] = {
+ "immediate",
+ "zero detection + immediate change",
+ "zero detection + inc/dec change",
+ "zero detection + soft inc/dec change",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1015_dac_vol_ctl_enum,
+ RT1015_DAC3, 2, rt1015_dac_output_vol_select);
+
static const struct snd_kcontrol_new rt1015_snd_controls[] = {
SOC_SINGLE_TLV("DAC Playback Volume", RT1015_DAC1, RT1015_DAC_VOL_SFT,
127, 0, dac_vol_tlv),
@@ -557,6 +563,9 @@ static const struct snd_kcontrol_new rt1015_snd_controls[] = {
SOC_ENUM("Mono LR Select", rt1015_mono_lr_sel),
SOC_SINGLE_EXT("Bypass Boost", SND_SOC_NOPM, 0, 1, 0,
rt1015_bypass_boost_get, rt1015_bypass_boost_put),
+
+ /* DAC Output Volume Control */
+ SOC_ENUM("DAC Output Control", rt1015_dac_vol_ctl_enum),
};
static int rt1015_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
@@ -741,10 +750,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:
@@ -1085,7 +1094,7 @@ static const struct regmap_config rt1015_regmap = {
};
static const struct i2c_device_id rt1015_i2c_id[] = {
- { "rt1015", 0 },
+ { "rt1015" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt1015_i2c_id);
@@ -1093,15 +1102,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/rt1015p.c b/sound/soc/codecs/rt1015p.c
index 06800dad8798..44e7fe3c32da 100644
--- a/sound/soc/codecs/rt1015p.c
+++ b/sound/soc/codecs/rt1015p.c
@@ -8,7 +8,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
index b1e69fa290b2..9f86f071fca8 100644
--- a/sound/soc/codecs/rt1016.c
+++ b/sound/soc/codecs/rt1016.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -368,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:
@@ -609,7 +608,7 @@ static const struct regmap_config rt1016_regmap = {
};
static const struct i2c_device_id rt1016_i2c_id[] = {
- { "rt1016", 0 },
+ { "rt1016" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt1016_i2c_id);
@@ -617,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
new file mode 100644
index 000000000000..a9c000876be8
--- /dev/null
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -0,0 +1,822 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1017-sdca-sdw.c -- rt1017 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt1017-sdca-sdw.h"
+
+static bool rt1017_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0x3206:
+ case 0xc000:
+ case 0xc001:
+ case 0xc022:
+ case 0xc030:
+ case 0xc104:
+ case 0xc10b:
+ case 0xc10c:
+ case 0xc110:
+ case 0xc112:
+ case 0xc300:
+ case 0xc301:
+ case 0xc318:
+ case 0xc325 ... 0xc328:
+ case 0xc331:
+ case 0xc340:
+ case 0xc350 ... 0xc351:
+ case 0xc500:
+ case 0xc502:
+ case 0xc504:
+ case 0xc507:
+ case 0xc509:
+ case 0xc510:
+ case 0xc512:
+ case 0xc518:
+ case 0xc51b:
+ case 0xc51d:
+ case 0xc520:
+ case 0xc540 ... 0xc542:
+ case 0xc550 ... 0xc552:
+ case 0xc600:
+ case 0xc602:
+ case 0xc612:
+ case 0xc622:
+ case 0xc632:
+ case 0xc642:
+ case 0xc651:
+ case 0xca00:
+ case 0xca09 ... 0xca0c:
+ case 0xca0e ... 0xca0f:
+ case 0xca10 ... 0xca11:
+ case 0xca16 ... 0xca17:
+ case 0xcb00:
+ case 0xcc00:
+ case 0xcc02:
+ case 0xd017:
+ case 0xd01a ... 0xd01c:
+ case 0xd101:
+ case 0xd20c:
+ case 0xd300:
+ case 0xd370:
+ case 0xd500:
+ case 0xd545 ... 0xd548:
+ case 0xd5a5 ... 0xd5a8:
+ case 0xd5aa ... 0xd5ad:
+ case 0xda04 ... 0xda07:
+ case 0xda09 ... 0xda0a:
+ case 0xda0c ... 0xda0f:
+ case 0xda11 ... 0xda14:
+ case 0xda16 ... 0xda19:
+ case 0xdab6 ... 0xdabb:
+ case 0xdb09 ... 0xdb0a:
+ case 0xdb14:
+
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
+ RT1017_SDCA_CTL_FU_MUTE, 0x01):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
+ RT1017_SDCA_CTL_BYPASS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29,
+ RT1017_SDCA_CTL_PROT_STAT, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1017_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0xc000:
+ case 0xc022:
+ case 0xc351:
+ case 0xc518:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29,
+ RT1017_SDCA_CTL_PROT_STAT, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct reg_sequence rt1017_blind_write[] = {
+ { 0xc001, 0x43 },
+ { 0x2f55, 0x02 },
+ { 0x3206, 0x80 },
+ { 0x005f, 0x7f },
+ { 0xd101, 0xa0 },
+ { 0xc112, 0xc0 },
+ { 0xc104, 0xaa },
+ { 0xc110, 0x59 },
+ { 0xc112, 0xc0 },
+ { 0xc340, 0x80 },
+ { 0xd017, 0x2c },
+ { 0xd01a, 0xc8 },
+ { 0xd01b, 0xcf },
+ { 0xd01c, 0x0c },
+ { 0xd20c, 0x14 },
+ { 0xdb09, 0x0f },
+ { 0xdb0a, 0x7f },
+ { 0xdb14, 0x03 },
+ { 0xcb00, 0x31 },
+ { 0xc318, 0x44 },
+ { 0xc325, 0xce },
+ { 0xc326, 0x13 },
+ { 0xc327, 0x5f },
+ { 0xc328, 0xf3 },
+ { 0xc350, 0xe1 },
+ { 0xc351, 0x88 },
+ { 0xc030, 0x14 },
+ { 0xc331, 0xf2 },
+ { 0xc551, 0x0f },
+ { 0xc552, 0xff },
+ { 0xc651, 0xc0 },
+ { 0xc550, 0xd0 },
+ { 0xc612, 0x00 },
+ { 0xc622, 0x00 },
+ { 0xc632, 0x00 },
+ { 0xc642, 0x00 },
+ { 0xc602, 0xf0 },
+ { 0xc600, 0xd0 },
+ { 0xcc02, 0x78 },
+ { 0xcc00, 0x90 },
+ { 0xc300, 0x3f },
+ { 0xc301, 0x1d },
+ { 0xc10b, 0x2e },
+ { 0xc10c, 0x36 },
+
+ { 0xd5a5, 0x00 },
+ { 0xd5a6, 0x6a },
+ { 0xd5a7, 0xaa },
+ { 0xd5a8, 0xaa },
+ { 0xd5aa, 0x00 },
+ { 0xd5ab, 0x16 },
+ { 0xd5ac, 0xdb },
+ { 0xd5ad, 0x6d },
+ { 0xd545, 0x09 },
+ { 0xd546, 0x30 },
+ { 0xd547, 0xf0 },
+ { 0xd548, 0xf0 },
+ { 0xd500, 0x20 },
+ { 0xc504, 0x3f },
+ { 0xc540, 0x00 },
+ { 0xc541, 0x0a },
+ { 0xc542, 0x1a },
+ { 0xc512, 0x00 },
+ { 0xc520, 0x40 },
+ { 0xc51b, 0x7f },
+ { 0xc51d, 0x0f },
+ { 0xc500, 0x40 },
+ { 0xc502, 0xde },
+ { 0xc507, 0x05 },
+ { 0xc509, 0x05 },
+ { 0xc510, 0x40 },
+ { 0xc518, 0xc0 },
+ { 0xc500, 0xc0 },
+
+ { 0xda0c, 0x00 },
+ { 0xda0d, 0x0b },
+ { 0xda0e, 0x55 },
+ { 0xda0f, 0x55 },
+ { 0xda04, 0x00 },
+ { 0xda05, 0x51 },
+ { 0xda06, 0xeb },
+ { 0xda07, 0x85 },
+ { 0xca16, 0x0f },
+ { 0xca17, 0x00 },
+ { 0xda09, 0x5d },
+ { 0xda0a, 0xc0 },
+ { 0xda11, 0x26 },
+ { 0xda12, 0x66 },
+ { 0xda13, 0x66 },
+ { 0xda14, 0x66 },
+ { 0xda16, 0x79 },
+ { 0xda17, 0x99 },
+ { 0xda18, 0x99 },
+ { 0xda19, 0x99 },
+ { 0xca09, 0x00 },
+ { 0xca0a, 0x07 },
+ { 0xca0b, 0x89 },
+ { 0xca0c, 0x61 },
+ { 0xca0e, 0x00 },
+ { 0xca0f, 0x03 },
+ { 0xca10, 0xc4 },
+ { 0xca11, 0xb0 },
+ { 0xdab6, 0x00 },
+ { 0xdab7, 0x01 },
+ { 0xdab8, 0x00 },
+ { 0xdab9, 0x00 },
+ { 0xdaba, 0x00 },
+ { 0xdabb, 0x00 },
+ { 0xd017, 0x0e },
+ { 0xca00, 0xcd },
+ { 0xc022, 0x84 },
+};
+
+#define RT1017_MAX_REG_NUM 0x4108ffff
+
+static const struct regmap_config rt1017_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1017_sdca_readable_register,
+ .volatile_reg = rt1017_sdca_volatile_register,
+ .max_register = RT1017_MAX_REG_NUM,
+ .reg_defaults = rt1017_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1017_sdca_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1017_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists
+ * port = 1 for AMP playback
+ * port = 2 for IV capture
+ */
+ prop->source_ports = BIT(2); /* BITMAP: 00000100 */
+ prop->sink_ports = BIT(1); /* BITMAP: 00000010 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 64;
+
+ return 0;
+}
+
+static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+
+ if (rt1017->hw_init)
+ return 0;
+
+ if (rt1017->first_hw_init) {
+ regcache_cache_only(rt1017->regmap, false);
+ regcache_cache_bypass(rt1017->regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ /* sw reset */
+ regmap_write(rt1017->regmap, 0xc000, 0x02);
+
+ /* initial settings - blind write */
+ regmap_multi_reg_write(rt1017->regmap, rt1017_blind_write,
+ ARRAY_SIZE(rt1017_blind_write));
+
+ if (rt1017->first_hw_init) {
+ regcache_cache_bypass(rt1017->regmap, false);
+ regcache_mark_dirty(rt1017->regmap);
+ } else
+ rt1017->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt1017->hw_init = true;
+
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "hw_init complete\n");
+ return 0;
+}
+
+static int rt1017_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1017->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1017->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1017_sdca_io_init(&slave->dev, slave);
+}
+
+static const char * const rt1017_rx_data_ch_select[] = {
+ "Bypass",
+ "CN1",
+ "CN2",
+ "CN3",
+ "CN4",
+ "(1+2)/2",
+ "(1+3)/2",
+ "(1+4)/2",
+ "(2+3)/2",
+ "(2+4)/2",
+ "(3+4)/2",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1017_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0),
+ 0, rt1017_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1017_sdca_controls[] = {
+ /* UDMPU Cluster Selection */
+ SOC_ENUM("RX Channel Select", rt1017_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1017_sto_dac =
+ SOC_DAPM_SINGLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x1),
+ 0, 1, 1);
+
+static int rt1017_sdca_pde23_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 rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1017->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1017->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int rt1017_sdca_classd_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 rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(rt1017->regmap, RT1017_PWM_TRIM_1,
+ RT1017_PWM_FREQ_CTL_SRC_SEL_MASK, RT1017_PWM_FREQ_CTL_SRC_SEL_REG);
+ regmap_write(rt1017->regmap, RT1017_CLASSD_INT_1, 0x10);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt1017_sdca_feedback_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 rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x08);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x09);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt1017_sdca_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT_E("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0,
+ rt1017_sdca_feedback_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1017_sto_dac),
+
+ /* Output Lines */
+ SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1017_sdca_classd_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_OUTPUT("SPO"),
+
+ SND_SOC_DAPM_SUPPLY("PDE23", SND_SOC_NOPM, 0, 0,
+ rt1017_sdca_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("I Gen"),
+ SND_SOC_DAPM_SIGGEN("V Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1017_sdca_dapm_routes[] = {
+
+ { "DAC", "Switch", "DP1RX" },
+ { "CLASS D", NULL, "DAC" },
+ { "CLASS D", NULL, "PDE23" },
+ { "SPO", NULL, "CLASS D" },
+
+ { "I Sense", NULL, "I Gen" },
+ { "V Sense", NULL, "V Gen" },
+ { "I Sense", NULL, "PDE23" },
+ { "V Sense", NULL, "PDE23" },
+ { "DP2TX", NULL, "I Sense" },
+ { "DP2TX", NULL, "V Sense" },
+};
+
+static const struct sdw_slave_ops rt1017_sdca_slave_ops = {
+ .read_prop = rt1017_sdca_read_prop,
+ .update_status = rt1017_sdca_update_status,
+};
+
+static int rt1017_sdca_component_probe(struct snd_soc_component *component)
+{
+ int ret;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static void rt1017_sdca_component_remove(struct snd_soc_component *component)
+{
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1017->regmap, true);
+}
+
+static const struct snd_soc_component_driver soc_sdca_component_rt1017 = {
+ .probe = rt1017_sdca_component_probe,
+ .remove = rt1017_sdca_component_remove,
+ .controls = rt1017_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt1017_sdca_controls),
+ .dapm_widgets = rt1017_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1017_sdca_dapm_widgets),
+ .dapm_routes = rt1017_sdca_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1017_sdca_dapm_routes),
+ .endianness = 1,
+};
+
+static int rt1017_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void rt1017_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_runtime *sdw_stream;
+ int retval, port, num_channels, ch_mask;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt1017->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ port = 1;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ port = 2;
+ }
+
+ num_channels = params_channels(params);
+ ch_mask = (1 << num_channels) - 1;
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = num_channels;
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ port_config.ch_mask = ch_mask;
+ port_config.num = port;
+
+ dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n",
+ params_rate(params), num_channels, snd_pcm_format_width(params_format(params)),
+ direction, ch_mask, port);
+
+ retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 44100:
+ sampling_rate = RT1017_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT1017_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT1017_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT1017_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ regmap_write(rt1017->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0),
+ sampling_rate);
+
+ return 0;
+}
+
+static int rt1017_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1017->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1017->sdw_slave, sdw_stream);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops rt1017_sdca_ops = {
+ .hw_params = rt1017_sdca_pcm_hw_params,
+ .hw_free = rt1017_sdca_pcm_hw_free,
+ .set_stream = rt1017_sdca_set_sdw_stream,
+ .shutdown = rt1017_sdca_shutdown,
+};
+
+#define RT1017_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1017_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver rt1017_sdca_dai[] = {
+ {
+ .name = "rt1017-aif",
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = RT1017_STEREO_RATES,
+ .formats = RT1017_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = RT1017_STEREO_RATES,
+ .formats = RT1017_FORMATS,
+ },
+ .ops = &rt1017_sdca_ops,
+ },
+};
+
+static int rt1017_sdca_init(struct device *dev, struct regmap *regmap,
+ struct sdw_slave *slave)
+{
+ struct rt1017_sdca_priv *rt1017;
+ int ret;
+
+ rt1017 = devm_kzalloc(dev, sizeof(*rt1017), GFP_KERNEL);
+ if (!rt1017)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1017);
+ rt1017->sdw_slave = slave;
+ rt1017->regmap = regmap;
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1017->hw_init = false;
+ rt1017->first_hw_init = false;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_component_rt1017,
+ rt1017_sdca_dai,
+ ARRAY_SIZE(rt1017_sdca_dai));
+
+ return ret;
+}
+
+static int rt1017_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw(slave, &rt1017_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1017_sdca_init(&slave->dev, regmap, slave);
+}
+
+static int rt1017_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev);
+
+ if (rt1017->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt1017_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1017, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id);
+
+static int rt1017_sdca_dev_suspend(struct device *dev)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+
+ if (!rt1017->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1017->regmap, true);
+
+ return 0;
+}
+
+#define RT1017_PROBE_TIMEOUT 5000
+
+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);
+ unsigned long time;
+
+ if (!rt1017->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1017_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1017->regmap, false);
+ regcache_sync(rt1017->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt1017_sdca_pm = {
+ 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 = pm_ptr(&rt1017_sdca_pm),
+ },
+ .probe = rt1017_sdca_sdw_probe,
+ .remove = rt1017_sdca_sdw_remove,
+ .ops = &rt1017_sdca_slave_ops,
+ .id_table = rt1017_sdca_id,
+};
+module_sdw_driver(rt1017_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1017 driver SDCA SDW");
+MODULE_AUTHOR("Derek Fang <derek.fang@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h
new file mode 100644
index 000000000000..4932b5dbe3c0
--- /dev/null
+++ b/sound/soc/codecs/rt1017-sdca-sdw.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1017-sdca-sdw.h -- RT1017 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1017_SDW_H__
+#define __RT1017_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* RT1017 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1017 SDCA entity */
+#define RT1017_SDCA_ENT_PDE23 0x31
+#define RT1017_SDCA_ENT_PDE22 0x33
+#define RT1017_SDCA_ENT_CS21 0x21
+#define RT1017_SDCA_ENT_SAPU29 0x29
+#define RT1017_SDCA_ENT_XU22 0x22
+#define RT1017_SDCA_ENT_FU 0x03
+#define RT1017_SDCA_ENT_UDMPU21 0x02
+
+/* RT1017 SDCA control */
+#define RT1017_SDCA_CTL_FS_INDEX 0x10
+#define RT1017_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1017_SDCA_CTL_PROT_STAT 0x11
+#define RT1017_SDCA_CTL_BYPASS 0x01
+#define RT1017_SDCA_CTL_FU_MUTE 0x01
+#define RT1017_SDCA_CTL_FU_VOLUME 0x02
+#define RT1017_SDCA_CTL_UDMPU_CLUSTER 0x10
+
+
+#define RT1017_CLASSD_INT_1 0xd300
+#define RT1017_PWM_TRIM_1 0xd370
+
+
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_MASK (0x3 << 2)
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_EFUSE (0x2 << 2)
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_REG (0x0 << 2)
+
+enum {
+ RT1017_SDCA_RATE_44100HZ = 0x8,
+ RT1017_SDCA_RATE_48000HZ = 0x9,
+ RT1017_SDCA_RATE_96000HZ = 0xb,
+ RT1017_SDCA_RATE_192000HZ = 0xd,
+};
+
+struct rt1017_sdca_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct sdw_slave *sdw_slave;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+};
+
+static const struct reg_default rt1017_sdca_reg_defaults[] = {
+ { 0x3206, 0x00 },
+ { 0xc001, 0x43 },
+ { 0xc030, 0x54 },
+ { 0xc104, 0x8a },
+ { 0xc10b, 0x2f },
+ { 0xc10c, 0x2f },
+ { 0xc110, 0x49 },
+ { 0xc112, 0x10 },
+ { 0xc300, 0xff },
+ { 0xc301, 0xdd },
+ { 0xc318, 0x40 },
+ { 0xc325, 0x00 },
+ { 0xc326, 0x00 },
+ { 0xc327, 0x00 },
+ { 0xc328, 0x02 },
+ { 0xc331, 0xb2 },
+ { 0xc340, 0x02 },
+ { 0xc350, 0x21 },
+ { 0xc500, 0x00 },
+ { 0xc502, 0x00 },
+ { 0xc504, 0x3f },
+ { 0xc507, 0x1f },
+ { 0xc509, 0x1f },
+ { 0xc510, 0x40 },
+ { 0xc512, 0x00 },
+ { 0xc518, 0x02 },
+ { 0xc51b, 0x7f },
+ { 0xc51d, 0x0f },
+ { 0xc520, 0x00 },
+ { 0xc540, 0x80 },
+ { 0xc541, 0x00 },
+ { 0xc542, 0x0a },
+ { 0xc550, 0x80 },
+ { 0xc551, 0x0f },
+ { 0xc552, 0xff },
+ { 0xc600, 0x10 },
+ { 0xc602, 0x83 },
+ { 0xc612, 0x40 },
+ { 0xc622, 0x40 },
+ { 0xc632, 0x40 },
+ { 0xc642, 0x40 },
+ { 0xc651, 0x00 },
+ { 0xca00, 0xc1 },
+ { 0xca09, 0x00 },
+ { 0xca0a, 0x51 },
+ { 0xca0b, 0xeb },
+ { 0xca0c, 0x85 },
+ { 0xca0e, 0x00 },
+ { 0xca0f, 0x10 },
+ { 0xca10, 0x62 },
+ { 0xca11, 0x4d },
+ { 0xca16, 0x0f },
+ { 0xca17, 0x00 },
+ { 0xcb00, 0x10 },
+ { 0xcc00, 0x10 },
+ { 0xcc02, 0x0b },
+ { 0xd017, 0x09 },
+ { 0xd01a, 0x00 },
+ { 0xd01b, 0x00 },
+ { 0xd01c, 0x00 },
+ { 0xd101, 0xa0 },
+ { 0xd20c, 0x14 },
+ { 0xd300, 0x0f },
+ { 0xd370, 0x18 },
+ { 0xd500, 0x00 },
+ { 0xd545, 0x0b },
+ { 0xd546, 0xf9 },
+ { 0xd547, 0xb2 },
+ { 0xd548, 0xa9 },
+ { 0xd5a5, 0x00 },
+ { 0xd5a6, 0x00 },
+ { 0xd5a7, 0x00 },
+ { 0xd5a8, 0x00 },
+ { 0xd5aa, 0x00 },
+ { 0xd5ab, 0x00 },
+ { 0xd5ac, 0x00 },
+ { 0xd5ad, 0x00 },
+ { 0xda04, 0x03 },
+ { 0xda05, 0x33 },
+ { 0xda06, 0x33 },
+ { 0xda07, 0x33 },
+ { 0xda09, 0x5d },
+ { 0xda0a, 0xc0 },
+ { 0xda0c, 0x00 },
+ { 0xda0d, 0x01 },
+ { 0xda0e, 0x5d },
+ { 0xda0f, 0x86 },
+ { 0xda11, 0x20 },
+ { 0xda12, 0x00 },
+ { 0xda13, 0x00 },
+ { 0xda14, 0x00 },
+ { 0xda16, 0x7f },
+ { 0xda17, 0xff },
+ { 0xda18, 0xff },
+ { 0xda19, 0xff },
+ { 0xdab6, 0x00 },
+ { 0xdab7, 0x01 },
+ { 0xdab8, 0x00 },
+ { 0xdab9, 0x01 },
+ { 0xdaba, 0x00 },
+ { 0xdabb, 0x01 },
+ { 0xdb09, 0x0f },
+ { 0xdb0a, 0xff },
+ { 0xdb14, 0x00 },
+
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
+ RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
+ RT1017_SDCA_CTL_BYPASS, 0), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+#endif /* __RT1017_SDW_H__ */
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
index 735feea8fd92..86539c6f6cc1 100644
--- a/sound/soc/codecs/rt1019.c
+++ b/sound/soc/codecs/rt1019.c
@@ -18,7 +18,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -535,27 +534,27 @@ static const struct regmap_config rt1019_regmap = {
.max_register = RT1019_BEEP_2,
.volatile_reg = rt1019_volatile_register,
.readable_reg = rt1019_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1019_reg,
.num_reg_defaults = ARRAY_SIZE(rt1019_reg),
};
static const struct i2c_device_id rt1019_i2c_id[] = {
- { "rt1019", 0 },
+ { "rt1019" },
{ }
};
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 28a4a70c3307..26b7382f97ef 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -12,10 +12,8 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <sound/core.h>
@@ -699,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;
@@ -955,7 +953,7 @@ static const struct regmap_config rt1305_regmap = {
RT1305_PR_SPACING),
.volatile_reg = rt1305_volatile_register,
.readable_reg = rt1305_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1305_reg,
.num_reg_defaults = ARRAY_SIZE(rt1305_reg),
.ranges = rt1305_ranges,
@@ -968,23 +966,23 @@ 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
static const struct i2c_device_id rt1305_i2c_id[] = {
- { "rt1305", 0 },
- { "rt1306", 0 },
+ { "rt1305" },
+ { "rt1306" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt1305_i2c_id);
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index f43520ca3187..b6c224832a43 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -52,6 +52,7 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg)
case 0x300a:
case 0xc000:
case 0xc710:
+ case 0xcf01:
case 0xc860 ... 0xc863:
case 0xc870 ... 0xc873:
return true;
@@ -213,35 +214,28 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
int ret = 0;
- unsigned int tmp;
+ unsigned int tmp, hibernation_flag;
if (rt1308->hw_init)
return 0;
- if (rt1308->first_hw_init) {
- regcache_cache_only(rt1308->regmap, false);
+ regcache_cache_only(rt1308->regmap, false);
+ if (rt1308->first_hw_init)
regcache_cache_bypass(rt1308->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt1308->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt1308->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
+ regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag);
+ if ((hibernation_flag != 0x00) && rt1308->first_hw_init)
+ goto _preset_ready_;
+
/* sw reset */
regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0);
@@ -282,6 +276,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
regmap_write(rt1308->regmap, 0xc100, 0xd7);
regmap_write(rt1308->regmap, 0xc101, 0xd7);
+ /* apply BQ params */
+ rt1308_apply_bq_params(rt1308);
+
+ regmap_write(rt1308->regmap, 0xcf01, 0x01);
+
+_preset_ready_:
if (rt1308->first_hw_init) {
regcache_cache_bypass(rt1308->regmap, false);
regcache_mark_dirty(rt1308->regmap);
@@ -291,7 +291,6 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt1308->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
@@ -626,6 +625,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component)
rt1308->component = component;
rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
+ if (!rt1308->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -688,6 +690,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
rt1308->sdw_slave = slave;
rt1308->regmap = regmap;
+ regcache_cache_only(rt1308->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -699,10 +703,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
&soc_component_sdw_rt1308,
rt1308_sdw_dai,
ARRAY_SIZE(rt1308_sdw_dai));
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
static int rt1308_sdw_probe(struct sdw_slave *slave,
@@ -715,17 +736,12 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt1308_sdw_init(&slave->dev, regmap, slave);
-
- return 0;
+ return rt1308_sdw_init(&slave->dev, regmap, slave);
}
static int rt1308_sdw_remove(struct sdw_slave *slave)
{
- struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
-
- if (rt1308->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -736,7 +752,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);
@@ -750,7 +766,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);
@@ -780,15 +796,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",
- .owner = THIS_MODULE,
- .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 04c5d5de71ff..df50b38c24b9 100644
--- a/sound/soc/codecs/rt1308.c
+++ b/sound/soc/codecs/rt1308.c
@@ -11,10 +11,8 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
-#include <linux/of_gpio.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
@@ -525,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:
@@ -773,7 +771,7 @@ static const struct regmap_config rt1308_regmap = {
.max_register = RT1308_MAX_REG,
.volatile_reg = rt1308_volatile_register,
.readable_reg = rt1308_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt1308_reg,
.num_reg_defaults = ARRAY_SIZE(rt1308_reg),
.use_single_read = true,
@@ -783,21 +781,21 @@ 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
static const struct i2c_device_id rt1308_i2c_id[] = {
- { "rt1308", 0 },
+ { "rt1308" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt1308_i2c_id);
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 721821d9e9af..01a977398864 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -272,25 +272,16 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
if (rt1316->hw_init)
return 0;
+ regcache_cache_only(rt1316->regmap, false);
if (rt1316->first_hw_init) {
- regcache_cache_only(rt1316->regmap, false);
regcache_cache_bypass(rt1316->regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -311,7 +302,6 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt1316->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
@@ -424,6 +414,15 @@ static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum,
SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
rt1316_rx_data_ch_select);
+static const char * const rt1316_dac_output_vol_select[] = {
+ "immediately",
+ "zero crossing",
+ "zero crossing with soft ramp",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1316_dac_vol_ctl_enum,
+ 0xc010, 6, rt1316_dac_output_vol_select);
+
static const struct snd_kcontrol_new rt1316_snd_controls[] = {
/* I2S Data Channel Selection */
@@ -442,6 +441,9 @@ static const struct snd_kcontrol_new rt1316_snd_controls[] = {
/* IV mixer Control */
SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1),
SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1),
+
+ /* DAC Output Volume Control */
+ SOC_ENUM("DAC Output Vol Control", rt1316_dac_vol_ctl_enum),
};
static const struct snd_kcontrol_new rt1316_sto_dac =
@@ -534,7 +536,7 @@ static int rt1316_sdw_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt1316->sdw_slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
@@ -574,12 +576,12 @@ static int rt1316_sdw_parse_dt(struct rt1316_sdw_priv *rt1316, struct device *de
if (rt1316->bq_params_cnt) {
rt1316->bq_params = devm_kzalloc(dev, rt1316->bq_params_cnt, GFP_KERNEL);
if (!rt1316->bq_params) {
- dev_err(dev, "Could not allocate bq_params memory\n");
+ dev_err(dev, "%s: Could not allocate bq_params memory\n", __func__);
ret = -ENOMEM;
} else {
ret = device_property_read_u8_array(dev, "realtek,bq-params", rt1316->bq_params, rt1316->bq_params_cnt);
if (ret < 0)
- dev_err(dev, "Could not read list of realtek,bq-params\n");
+ dev_err(dev, "%s: Could not read list of realtek,bq-params\n", __func__);
}
}
@@ -595,6 +597,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component)
rt1316->component = component;
rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
+ if (!rt1316->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -662,6 +667,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
rt1316->sdw_slave = slave;
rt1316->regmap = regmap;
+ regcache_cache_only(rt1316->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -673,10 +680,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
&soc_component_sdw_rt1316,
rt1316_sdw_dai,
ARRAY_SIZE(rt1316_sdw_dai));
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
static int rt1316_sdw_probe(struct sdw_slave *slave,
@@ -694,10 +718,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
static int rt1316_sdw_remove(struct sdw_slave *slave)
{
- struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
-
- if (rt1316->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -708,7 +729,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);
@@ -722,7 +743,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);
@@ -737,7 +758,7 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev)
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT1316_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -752,15 +773,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",
- .owner = THIS_MODULE,
- .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 16d750102c8c..70db5450d6d2 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -408,25 +408,15 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
if (rt1318->hw_init)
return 0;
+ regcache_cache_only(rt1318->regmap, false);
if (rt1318->first_hw_init) {
- regcache_cache_only(rt1318->regmap, false);
regcache_cache_bypass(rt1318->regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
-
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -444,7 +434,6 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
rt1318->first_hw_init = true;
rt1318->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
@@ -616,7 +605,7 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
@@ -641,8 +630,8 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
sampling_rate = RT1318_SDCA_RATE_192000HZ;
break;
default:
- dev_err(component->dev, "Rate %d is not supported\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -686,6 +675,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component)
rt1318->component = component;
+ if (!rt1318->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
if (ret < 0 && ret != -EACCES)
@@ -752,6 +744,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
rt1318->sdw_slave = slave;
rt1318->regmap = regmap;
+ regcache_cache_only(rt1318->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -763,8 +757,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
&soc_component_sdw_rt1318,
rt1318_sdw_dai,
ARRAY_SIZE(rt1318_sdw_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
- dev_dbg(&slave->dev, "%s\n", __func__);
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -784,10 +795,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave,
static int rt1318_sdw_remove(struct sdw_slave *slave)
{
- struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
-
- if (rt1318->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -798,7 +806,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);
@@ -811,7 +819,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);
@@ -826,7 +834,7 @@ static int __maybe_unused rt1318_dev_resume(struct device *dev)
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT1318_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -839,15 +847,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",
- .owner = THIS_MODULE,
- .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
new file mode 100644
index 000000000000..01c58b15fd91
--- /dev/null
+++ b/sound/soc/codecs/rt1318.c
@@ -0,0 +1,1353 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1318.c -- RT1318 ALSA SoC audio amplifier driver
+// Author: Jack Yu <jack.yu@realtek.com>
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/acpi.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt1318.h>
+
+#include "rt1318.h"
+
+static const struct reg_sequence init_list[] = {
+ { 0x0000C000, 0x01},
+ { 0x0000F20D, 0x00},
+ { 0x0000F212, 0x3E},
+ { 0x0000C001, 0x02},
+ { 0x0000C003, 0x22},
+ { 0x0000C004, 0x44},
+ { 0x0000C005, 0x44},
+ { 0x0000C007, 0x64},
+ { 0x0000C00E, 0xE7},
+ { 0x0000F223, 0x7F},
+ { 0x0000F224, 0xDB},
+ { 0x0000F225, 0xEE},
+ { 0x0000F226, 0x3F},
+ { 0x0000F227, 0x0F},
+ { 0x0000F21A, 0x78},
+ { 0x0000F242, 0x3C},
+ { 0x0000C120, 0x40},
+ { 0x0000C125, 0x03},
+ { 0x0000C321, 0x0A},
+ { 0x0000C200, 0xD8},
+ { 0x0000C201, 0x27},
+ { 0x0000C202, 0x0F},
+ { 0x0000C400, 0x0E},
+ { 0x0000C401, 0x43},
+ { 0x0000C402, 0xE0},
+ { 0x0000C403, 0x00},
+ { 0x0000C404, 0x4C},
+ { 0x0000C406, 0x40},
+ { 0x0000C407, 0x02},
+ { 0x0000C408, 0x3F},
+ { 0x0000C300, 0x01},
+ { 0x0000C125, 0x03},
+ { 0x0000DF00, 0x10},
+ { 0x0000F20B, 0x2A},
+ { 0x0000DF5F, 0x01},
+ { 0x0000DF60, 0xA7},
+ { 0x0000C203, 0x84},
+ { 0x0000C206, 0x78},
+ { 0x0000F10A, 0x09},
+ { 0x0000F10B, 0x4C},
+ { 0x0000F104, 0xF4},
+ { 0x0000F105, 0x03},
+ { 0x0000F109, 0xE0},
+ { 0x0000F10B, 0x5C},
+ { 0x0000F104, 0xF4},
+ { 0x0000F105, 0x04},
+ { 0x0000F109, 0x65},
+ { 0x0000F10B, 0x5C},
+ { 0x0000F104, 0xF4},
+ { 0x0000F105, 0x02},
+ { 0x0000F109, 0x30},
+ { 0x0000F10B, 0x5C},
+ { 0x0000E706, 0x0F},
+ { 0x0000E707, 0x30},
+ { 0x0000E806, 0x0F},
+ { 0x0000E807, 0x30},
+ { 0x0000CE04, 0x03},
+ { 0x0000CE05, 0x5F},
+ { 0x0000CE06, 0xA2},
+ { 0x0000CE07, 0x6B},
+ { 0x0000CF04, 0x03},
+ { 0x0000CF05, 0x5F},
+ { 0x0000CF06, 0xA2},
+ { 0x0000CF07, 0x6B},
+ { 0x0000CE60, 0xE3},
+ { 0x0000C130, 0x51},
+ { 0x0000E000, 0xA8},
+ { 0x0000F102, 0x00},
+ { 0x0000F103, 0x00},
+ { 0x0000F104, 0xF5},
+ { 0x0000F105, 0x23},
+ { 0x0000F109, 0x04},
+ { 0x0000F10A, 0x0B},
+ { 0x0000F10B, 0x4C},
+ { 0x0000F10B, 0x5C},
+ { 0x41001888, 0x00},
+ { 0x0000C121, 0x0B},
+ { 0x0000F102, 0x00},
+ { 0x0000F103, 0x00},
+ { 0x0000F104, 0xF5},
+ { 0x0000F105, 0x23},
+ { 0x0000F109, 0x00},
+ { 0x0000F10A, 0x0B},
+ { 0x0000F10B, 0x4C},
+ { 0x0000F10B, 0x5C},
+ { 0x0000F800, 0x20},
+ { 0x0000CA00, 0x80},
+ { 0x0000CA10, 0x00},
+ { 0x0000CA02, 0x78},
+ { 0x0000CA12, 0x78},
+ { 0x0000ED00, 0x90},
+ { 0x0000E604, 0x00},
+ { 0x0000DB00, 0x0C},
+ { 0x0000DD00, 0x0C},
+ { 0x0000DC19, 0x00},
+ { 0x0000DC1A, 0x6A},
+ { 0x0000DC1B, 0xAA},
+ { 0x0000DC1C, 0xAB},
+ { 0x0000DC1D, 0x00},
+ { 0x0000DC1E, 0x16},
+ { 0x0000DC1F, 0xDB},
+ { 0x0000DC20, 0x6D},
+ { 0x0000DE19, 0x00},
+ { 0x0000DE1A, 0x6A},
+ { 0x0000DE1B, 0xAA},
+ { 0x0000DE1C, 0xAB},
+ { 0x0000DE1D, 0x00},
+ { 0x0000DE1E, 0x16},
+ { 0x0000DE1F, 0xDB},
+ { 0x0000DE20, 0x6D},
+ { 0x0000DB32, 0x00},
+ { 0x0000DD32, 0x00},
+ { 0x0000DB33, 0x0A},
+ { 0x0000DD33, 0x0A},
+ { 0x0000DB34, 0x1A},
+ { 0x0000DD34, 0x1A},
+ { 0x0000DB15, 0xEF},
+ { 0x0000DD15, 0xEF},
+ { 0x0000DB17, 0xEF},
+ { 0x0000DD17, 0xEF},
+ { 0x0000DB94, 0x70},
+ { 0x0000DD94, 0x70},
+ { 0x0000DB19, 0x40},
+ { 0x0000DD19, 0x40},
+ { 0x0000DB12, 0xC0},
+ { 0x0000DD12, 0xC0},
+ { 0x0000DB00, 0x4C},
+ { 0x0000DB04, 0x05},
+ { 0x0000DB05, 0x03},
+ { 0x0000DD04, 0x05},
+ { 0x0000DD05, 0x03},
+ { 0x0000DBBB, 0x09},
+ { 0x0000DBBC, 0x30},
+ { 0x0000DBBD, 0xF0},
+ { 0x0000DBBE, 0xF1},
+ { 0x0000DDBB, 0x09},
+ { 0x0000DDBC, 0x30},
+ { 0x0000DDBD, 0xF0},
+ { 0x0000DDBE, 0xF1},
+ { 0x0000DB01, 0x79},
+ { 0x0000DD01, 0x79},
+ { 0x0000DB08, 0x40},
+ { 0x0000DD08, 0x40},
+ { 0x0000DC52, 0xEF},
+ { 0x0000DE52, 0xEF},
+ { 0x0000DB00, 0xCC},
+ { 0x0000CC2C, 0x00},
+ { 0x0000CC2D, 0x2A},
+ { 0x0000CC2E, 0x83},
+ { 0x0000CC2F, 0xA8},
+ { 0x0000CD2C, 0x00},
+ { 0x0000CD2D, 0x2A},
+ { 0x0000CD2E, 0x83},
+ { 0x0000CD2F, 0xA8},
+ { 0x0000CC24, 0x00},
+ { 0x0000CC25, 0x51},
+ { 0x0000CC26, 0xEB},
+ { 0x0000CC27, 0x85},
+ { 0x0000CD24, 0x00},
+ { 0x0000CD25, 0x51},
+ { 0x0000CD26, 0xEB},
+ { 0x0000CD27, 0x85},
+ { 0x0000CC20, 0x00},
+ { 0x0000CC21, 0x00},
+ { 0x0000CC22, 0x43},
+ { 0x0000CD20, 0x00},
+ { 0x0000CD21, 0x00},
+ { 0x0000CD22, 0x43},
+ { 0x0000CC16, 0x0F},
+ { 0x0000CC17, 0x00},
+ { 0x0000CD16, 0x0F},
+ { 0x0000CD17, 0x00},
+ { 0x0000CC29, 0x5D},
+ { 0x0000CC2A, 0xC0},
+ { 0x0000CD29, 0x5D},
+ { 0x0000CD2A, 0xC0},
+ { 0x0000CC31, 0x20},
+ { 0x0000CC32, 0x00},
+ { 0x0000CC33, 0x00},
+ { 0x0000CC34, 0x00},
+ { 0x0000CD31, 0x20},
+ { 0x0000CD32, 0x00},
+ { 0x0000CD33, 0x00},
+ { 0x0000CD34, 0x00},
+ { 0x0000CC36, 0x79},
+ { 0x0000CC37, 0x99},
+ { 0x0000CC38, 0x99},
+ { 0x0000CC39, 0x99},
+ { 0x0000CD36, 0x79},
+ { 0x0000CD37, 0x99},
+ { 0x0000CD38, 0x99},
+ { 0x0000CD39, 0x99},
+ { 0x0000CC09, 0x00},
+ { 0x0000CC0A, 0x07},
+ { 0x0000CC0B, 0x5F},
+ { 0x0000CC0C, 0x6F},
+ { 0x0000CD09, 0x00},
+ { 0x0000CD0A, 0x07},
+ { 0x0000CD0B, 0x5F},
+ { 0x0000CD0C, 0x6F},
+ { 0x0000CC0E, 0x00},
+ { 0x0000CC0F, 0x03},
+ { 0x0000CC10, 0xAF},
+ { 0x0000CC11, 0xB7},
+ { 0x0000CD0E, 0x00},
+ { 0x0000CD0F, 0x03},
+ { 0x0000CD10, 0xAF},
+ { 0x0000CD11, 0xB7},
+ { 0x0000CCD6, 0x00},
+ { 0x0000CCD7, 0x03},
+ { 0x0000CDD6, 0x00},
+ { 0x0000CDD7, 0x03},
+ { 0x0000CCD8, 0x00},
+ { 0x0000CCD9, 0x03},
+ { 0x0000CDD8, 0x00},
+ { 0x0000CDD9, 0x03},
+ { 0x0000CCDA, 0x00},
+ { 0x0000CCDB, 0x03},
+ { 0x0000CDDA, 0x00},
+ { 0x0000CDDB, 0x03},
+ { 0x0000C320, 0x20},
+ { 0x0000C203, 0x9C},
+};
+
+static const struct reg_default rt1318_reg[] = {
+ { 0xc000, 0x00 },
+ { 0xc001, 0x43 },
+ { 0xc003, 0x22 },
+ { 0xc004, 0x44 },
+ { 0xc005, 0x44 },
+ { 0xc006, 0x33 },
+ { 0xc007, 0x64 },
+ { 0xc008, 0x05 },
+ { 0xc00a, 0xfc },
+ { 0xc00b, 0x0f },
+ { 0xc00c, 0x0e },
+ { 0xc00d, 0xef },
+ { 0xc00e, 0xe5 },
+ { 0xc00f, 0xff },
+ { 0xc120, 0xc0 },
+ { 0xc121, 0x00 },
+ { 0xc122, 0x00 },
+ { 0xc123, 0x14 },
+ { 0xc125, 0x00 },
+ { 0xc130, 0x59 },
+ { 0xc200, 0x00 },
+ { 0xc201, 0x00 },
+ { 0xc202, 0x00 },
+ { 0xc203, 0x04 },
+ { 0xc204, 0x00 },
+ { 0xc205, 0x00 },
+ { 0xc206, 0x68 },
+ { 0xc207, 0x70 },
+ { 0xc208, 0x00 },
+ { 0xc20a, 0x00 },
+ { 0xc20b, 0x01 },
+ { 0xc20c, 0x7f },
+ { 0xc20d, 0x01 },
+ { 0xc20e, 0x7f },
+ { 0xc300, 0x00 },
+ { 0xc301, 0x00 },
+ { 0xc303, 0x80 },
+ { 0xc320, 0x00 },
+ { 0xc321, 0x09 },
+ { 0xc322, 0x02 },
+ { 0xc400, 0x00 },
+ { 0xc401, 0x00 },
+ { 0xc402, 0x00 },
+ { 0xc403, 0x00 },
+ { 0xc404, 0x00 },
+ { 0xc405, 0x00 },
+ { 0xc406, 0x00 },
+ { 0xc407, 0x00 },
+ { 0xc408, 0x00 },
+ { 0xc410, 0x04 },
+ { 0xc430, 0x00 },
+ { 0xc431, 0x00 },
+ { 0xca00, 0x10 },
+ { 0xca01, 0x00 },
+ { 0xca02, 0x0b },
+ { 0xca10, 0x10 },
+ { 0xca11, 0x00 },
+ { 0xca12, 0x0b },
+ { 0xce04, 0x08 },
+ { 0xce05, 0x00 },
+ { 0xce06, 0x00 },
+ { 0xce07, 0x00 },
+ { 0xce60, 0x63 },
+ { 0xcf04, 0x08 },
+ { 0xcf05, 0x00 },
+ { 0xcf06, 0x00 },
+ { 0xcf07, 0x00 },
+ { 0xdb00, 0x00 },
+ { 0xdb08, 0x40 },
+ { 0xdb12, 0x00 },
+ { 0xdb35, 0x00 },
+ { 0xdbb5, 0x00 },
+ { 0xdbb6, 0x40 },
+ { 0xdbb7, 0x00 },
+ { 0xdbb8, 0x00 },
+ { 0xdbc5, 0x00 },
+ { 0xdbc6, 0x00 },
+ { 0xdbc7, 0x00 },
+ { 0xdbc8, 0x00 },
+ { 0xdd08, 0x40 },
+ { 0xdd12, 0x00 },
+ { 0xdd35, 0x00 },
+ { 0xddb5, 0x00 },
+ { 0xddb6, 0x40 },
+ { 0xddb7, 0x00 },
+ { 0xddb8, 0x00 },
+ { 0xddc5, 0x00 },
+ { 0xddc6, 0x00 },
+ { 0xddc7, 0x00 },
+ { 0xddc8, 0x00 },
+ { 0xdd93, 0x00 },
+ { 0xdd94, 0x64 },
+ { 0xdf00, 0x00 },
+ { 0xdf5f, 0x00 },
+ { 0xdf60, 0x00 },
+ { 0xe000, 0x08 },
+ { 0xe300, 0xa0 },
+ { 0xe400, 0x22 },
+ { 0xe706, 0x2f },
+ { 0xe707, 0x2f },
+ { 0xe806, 0x2f },
+ { 0xe807, 0x2f },
+ { 0xea00, 0x43 },
+ { 0xed00, 0x80 },
+ { 0xed01, 0x0f },
+ { 0xed02, 0xff },
+ { 0xed03, 0x00 },
+ { 0xed04, 0x00 },
+ { 0xed05, 0x0f },
+ { 0xed06, 0xff },
+ { 0xf010, 0x10 },
+ { 0xf011, 0xec },
+ { 0xf012, 0x68 },
+ { 0xf013, 0x21 },
+ { 0xf102, 0x00 },
+ { 0xf103, 0x00 },
+ { 0xf104, 0x00 },
+ { 0xf105, 0x00 },
+ { 0xf106, 0x00 },
+ { 0xf107, 0x00 },
+ { 0xf108, 0x00 },
+ { 0xf109, 0x00 },
+ { 0xf10a, 0x03 },
+ { 0xf10b, 0x40 },
+ { 0xf20b, 0x28 },
+ { 0xf20d, 0x00 },
+ { 0xf212, 0x00 },
+ { 0xf21a, 0x00 },
+ { 0xf223, 0x40 },
+ { 0xf224, 0x00 },
+ { 0xf225, 0x00 },
+ { 0xf226, 0x00 },
+ { 0xf227, 0x00 },
+ { 0xf242, 0x0c },
+ { 0xf800, 0x00 },
+ { 0xf801, 0x12 },
+ { 0xf802, 0xe0 },
+ { 0xf803, 0x2f },
+ { 0xf804, 0x00 },
+ { 0xf805, 0x00 },
+ { 0xf806, 0x07 },
+ { 0xf807, 0xff },
+};
+
+static bool rt1318_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000:
+ case 0xc301:
+ case 0xc410:
+ case 0xc430 ... 0xc431:
+ case 0xdb06:
+ case 0xdb12:
+ case 0xdb1d ... 0xdb1f:
+ case 0xdb35:
+ case 0xdb37:
+ case 0xdb8a ... 0xdb92:
+ case 0xdbc5 ... 0xdbc8:
+ case 0xdc2b ... 0xdc49:
+ case 0xdd0b:
+ case 0xdd12:
+ case 0xdd1d ... 0xdd1f:
+ case 0xdd35:
+ case 0xdd8a ... 0xdd92:
+ case 0xddc5 ... 0xddc8:
+ case 0xde2b ... 0xde44:
+ case 0xdf4a ... 0xdf55:
+ case 0xe224 ... 0xe23b:
+ case 0xea01:
+ case 0xebc5:
+ case 0xebc8:
+ case 0xebcb ... 0xebcc:
+ case 0xed03 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool rt1318_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000 ... 0xc00f:
+ case 0xc120 ... 0xc130:
+ case 0xc200 ... 0xc20e:
+ case 0xc300 ... 0xc303:
+ case 0xc320 ... 0xc322:
+ case 0xc400 ... 0xc408:
+ case 0xc430 ... 0xc431:
+ case 0xca00 ... 0xca02:
+ case 0xca10 ... 0xca12:
+ case 0xcb00 ... 0xcb0b:
+ case 0xcc00 ... 0xcce5:
+ case 0xcd00 ... 0xcde5:
+ case 0xce00 ... 0xce6a:
+ case 0xcf00 ... 0xcf53:
+ case 0xd000 ... 0xd0cc:
+ case 0xd100 ... 0xd1b9:
+ case 0xdb00 ... 0xdc53:
+ case 0xdd00 ... 0xde53:
+ case 0xdf00 ... 0xdf6b:
+ case 0xe000:
+ case 0xe300:
+ case 0xe400:
+ case 0xe706 ... 0xe707:
+ case 0xe806 ... 0xe807:
+ case 0xea00:
+ case 0xeb00 ... 0xebcc:
+ case 0xec00 ... 0xecb9:
+ case 0xed00 ... 0xed06:
+ case 0xf010 ... 0xf014:
+ case 0xf102 ... 0xf10b:
+ case 0xf20b:
+ case 0xf20d ... 0xf242:
+ case 0xf800 ... 0xf807:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int rt1318_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 rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1,
+ RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_HIGH);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(rt1318->regmap, RT1318_PWR_STA1,
+ RT1318_PDB_CTRL_MASK, RT1318_PDB_CTRL_LOW);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int rt1318_dvol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ rt1318->rt1318_dvol = ucontrol->value.integer.value[0];
+
+ if (rt1318->rt1318_dvol <= RT1318_DVOL_STEP && rt1318->rt1318_dvol >= 0) {
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_L_8,
+ rt1318->rt1318_dvol >> 8);
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_L_1_7,
+ rt1318->rt1318_dvol & 0xff);
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_R_8,
+ rt1318->rt1318_dvol >> 8);
+ regmap_write(rt1318->regmap, RT1318_DA_VOL_R_1_7,
+ rt1318->rt1318_dvol & 0xff);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rt1318_dvol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = rt1318->rt1318_dvol;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new rt1318_snd_controls[] = {
+ SOC_SINGLE_EXT("Amp Playback Volume", SND_SOC_NOPM, 0, 383, 0,
+ rt1318_dvol_get, rt1318_dvol_put),
+};
+
+static const struct snd_soc_dapm_widget rt1318_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ /* DACs */
+ SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
+ rt1318_dac_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("Amp"),
+};
+
+static const struct snd_soc_dapm_route rt1318_dapm_routes[] = {
+ {"DAC", NULL, "AIF1RX"},
+ {"Amp", NULL, "DAC"},
+};
+
+static int rt1318_get_clk_info(int sclk, int rate)
+{
+ int i, pd[] = {1, 2, 4, 8, 16, 24};
+
+ if (sclk <= 0 || rate <= 0)
+ return -EINVAL;
+
+ rate = rate << 8;
+ for (i = 0; i < ARRAY_SIZE(pd); i++)
+ if (sclk == rate * pd[i])
+ return i;
+
+ return -EINVAL;
+}
+
+static int rt1318_clk_ip_info(struct snd_soc_component *component, int lrclk)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ switch (lrclk) {
+ case RT1318_LRCLK_48000:
+ case RT1318_LRCLK_44100:
+ case RT1318_LRCLK_16000:
+ regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+ RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+ RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON4);
+ break;
+ case RT1318_LRCLK_96000:
+ regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+ RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+ RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON2);
+ break;
+ case RT1318_LRCLK_192000:
+ regmap_update_bits(rt1318->regmap, RT1318_SRC_TCON,
+ RT1318_SRCIN_F12288_MASK | RT1318_SRCIN_DACLK_MASK,
+ RT1318_SRCIN_TCON4 | RT1318_DACLK_TCON1);
+ break;
+ default:
+ dev_err(component->dev, "Unsupported clock rate.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt1318_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ int data_len = 0, ch_len = 0;
+ int pre_div, ret;
+
+ rt1318->lrck = params_rate(params);
+ pre_div = rt1318_get_clk_info(rt1318->sysclk, rt1318->lrck);
+ if (pre_div < 0) {
+ dev_err(component->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+ ret = rt1318_clk_ip_info(component, rt1318->lrck);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupported clock setting\n");
+ return -EINVAL;
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ data_len = RT1318_I2S_DL_20;
+ ch_len = RT1318_I2S_DL_20;
+ break;
+ case 24:
+ data_len = RT1318_I2S_DL_24;
+ ch_len = RT1318_I2S_DL_24;
+ break;
+ case 32:
+ data_len = RT1318_I2S_DL_32;
+ ch_len = RT1318_I2S_DL_32;
+ break;
+ case 8:
+ data_len = RT1318_I2S_DL_8;
+ ch_len = RT1318_I2S_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt1318->regmap, RT1318_CLK2,
+ RT1318_DIV_AP_MASK | RT1318_DIV_DAMOD_MASK,
+ pre_div << RT1318_DIV_AP_SFT |
+ pre_div << RT1318_DIV_DAMOD_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK3,
+ RT1318_AD_STO1_MASK | RT1318_AD_STO2_MASK,
+ pre_div << RT1318_AD_STO1_SFT |
+ pre_div << RT1318_AD_STO2_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK4,
+ RT1318_AD_ANA_STO1_MASK | RT1318_AD_ANA_STO2_MASK,
+ pre_div << RT1318_AD_ANA_STO1_SFT |
+ pre_div << RT1318_AD_ANA_STO2_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK5,
+ RT1318_DIV_FIFO_IN_MASK | RT1318_DIV_FIFO_OUT_MASK,
+ pre_div << RT1318_DIV_FIFO_IN_SFT |
+ pre_div << RT1318_DIV_FIFO_OUT_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK6,
+ RT1318_DIV_NLMS_MASK | RT1318_DIV_AD_MONO_MASK |
+ RT1318_DIV_POST_G_MASK, pre_div << RT1318_DIV_NLMS_SFT |
+ pre_div << RT1318_DIV_AD_MONO_SFT |
+ pre_div << RT1318_DIV_POST_G_SFT);
+
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2,
+ RT1318_I2S_DL_MASK, data_len << RT1318_I2S_DL_SFT);
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3,
+ RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK,
+ ch_len << RT1318_I2S_TX_CHL_SFT |
+ ch_len << RT1318_I2S_RX_CHL_SFT);
+
+ return 0;
+}
+
+static int rt1318_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0, reg_val2 = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val2 |= RT1318_TDM_BCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT1318_FMT_LEFT_J;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT1318_FMT_PCM_A_R;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT1318_FMT_PCM_B_R;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1,
+ RT1318_I2S_FMT_MASK, reg_val);
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL1,
+ RT1318_TDM_BCLK_MASK, reg_val2);
+
+ return 0;
+}
+
+static int rt1318_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ int reg_val = 0;
+
+ if (freq == rt1318->sysclk && clk_id == rt1318->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT1318_SCLK_S_BCLK:
+ reg_val |= RT1318_SYSCLK_BCLK;
+ break;
+ case RT1318_SCLK_S_SDW:
+ reg_val |= RT1318_SYSCLK_SDW;
+ break;
+ case RT1318_SCLK_S_PLL2F:
+ reg_val |= RT1318_SYSCLK_PLL2F;
+ break;
+ case RT1318_SCLK_S_PLL2B:
+ reg_val |= RT1318_SYSCLK_PLL2B;
+ break;
+ case RT1318_SCLK_S_MCLK:
+ reg_val |= RT1318_SYSCLK_MCLK;
+ break;
+ case RT1318_SCLK_S_RC0:
+ reg_val |= RT1318_SYSCLK_RC1;
+ break;
+ case RT1318_SCLK_S_RC1:
+ reg_val |= RT1318_SYSCLK_RC2;
+ break;
+ case RT1318_SCLK_S_RC2:
+ reg_val |= RT1318_SYSCLK_RC3;
+ break;
+ default:
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ rt1318->sysclk = freq;
+ rt1318->sysclk_src = clk_id;
+ dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_SYSCLK_SEL_MASK, reg_val);
+
+ return 0;
+}
+
+static const struct pll_calc_map pll_preset_table[] = {
+ {512000, 4096000, 22, 190, 0, true, false},
+ {1024000, 4096000, 22, 94, 0, true, false},
+ {1024000, 16384000, 4, 190, 0, true, false},
+ {1411200, 11289600, 6, 62, 0, true, false},
+ {1536000, 12288000, 6, 62, 0, true, false},
+ {2822400, 11289600, 6, 62, 0, true, false},
+ {2822400, 45158400, 0, 62, 0, true, false},
+ {2822400, 49152000, 0, 62, 0, true, false},
+ {3072000, 12288000, 6, 62, 0, true, false},
+ {3072000, 24576000, 2, 62, 0, true, false},
+ {3072000, 49152000, 0, 62, 0, true, false},
+ {6144000, 24576000, 2, 94, 4, false, false},
+ {6144000, 49152000, 0, 30, 0, true, false},
+ {6144000, 98304000, 0, 94, 4, false, true},
+ {12288000, 49152000, 0, 62, 6, false, false},
+};
+
+static int rt1318_pll_calc(const unsigned int freq_in,
+ const unsigned int freq_out, struct rt1318_pll_code *pll_code)
+{
+ int max_n = RT1318_PLL_N_MAX, max_m = RT1318_PLL_M_MAX;
+ int i, k, red, n_t, pll_out, in_t, out_t;
+ int n = 0, m = 0, m_t = 0;
+ int red_t = abs(freq_out - freq_in);
+ bool m_bypass = false, k_bypass = false;
+
+ if (RT1318_PLL_INP_MAX < freq_in || RT1318_PLL_INP_MIN > freq_in)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+ if (freq_in == pll_preset_table[i].pll_in &&
+ freq_out == pll_preset_table[i].pll_out) {
+ k = pll_preset_table[i].k;
+ m = pll_preset_table[i].m;
+ n = pll_preset_table[i].n;
+ m_bypass = pll_preset_table[i].m_bp;
+ k_bypass = pll_preset_table[i].k_bp;
+ goto code_find;
+ }
+ }
+
+ k = 100000000 / freq_out - 2;
+ if (k > RT1318_PLL_K_MAX)
+ k = RT1318_PLL_K_MAX;
+ if (k < 0) {
+ k = 0;
+ k_bypass = true;
+ }
+ for (n_t = 0; n_t <= max_n; n_t++) {
+ in_t = freq_in / (k_bypass ? 1 : (k + 2));
+ pll_out = freq_out / (n_t + 2);
+ if (in_t < 0)
+ continue;
+ if (in_t == pll_out) {
+ m_bypass = true;
+ n = n_t;
+ goto code_find;
+ }
+ red = abs(in_t - pll_out);
+ if (red < red_t) {
+ m_bypass = true;
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ for (m_t = 0; m_t <= max_m; m_t++) {
+ out_t = in_t / (m_t + 2);
+ red = abs(out_t - pll_out);
+ if (red < red_t) {
+ m_bypass = false;
+ n = n_t;
+ m = m_t;
+ if (red == 0)
+ goto code_find;
+ red_t = red;
+ }
+ }
+ }
+ pr_debug("Only get approximation about PLL\n");
+
+code_find:
+
+ pll_code->m_bp = m_bypass;
+ pll_code->k_bp = k_bypass;
+ pll_code->m_code = m;
+ pll_code->n_code = n;
+ pll_code->k_code = k;
+ return 0;
+}
+
+static int rt1318_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ struct rt1318_pll_code pll_code;
+ int ret;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(component->dev, "PLL disabled\n");
+ rt1318->pll_in = 0;
+ rt1318->pll_out = 0;
+ return 0;
+ }
+
+ if (source == rt1318->pll_src && freq_in == rt1318->pll_in &&
+ freq_out == rt1318->pll_out)
+ return 0;
+
+ switch (source) {
+ case RT1318_PLL_S_BCLK0:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK0);
+ break;
+ case RT1318_PLL_S_BCLK1:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_BCLK1);
+ break;
+ case RT1318_PLL_S_RC:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_RC);
+ break;
+ case RT1318_PLL_S_MCLK:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_MCLK);
+ break;
+ case RT1318_PLL_S_SDW_IN_PLL:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW1);
+ break;
+ case RT1318_PLL_S_SDW_0:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW2);
+ break;
+ case RT1318_PLL_S_SDW_1:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW3);
+ break;
+ case RT1318_PLL_S_SDW_2:
+ regmap_update_bits(rt1318->regmap, RT1318_CLK1,
+ RT1318_PLLIN_MASK, RT1318_PLLIN_SDW4);
+ break;
+ default:
+ dev_err(component->dev, "Unknown PLL source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rt1318_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_K,
+ RT1318_K_PLL1_MASK, pll_code.k_code);
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_M,
+ RT1318_M_PLL1_MASK, (pll_code.m_bp ? 0 : pll_code.m_code));
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_8,
+ RT1318_N_8_PLL1_MASK, pll_code.n_code >> 8);
+ regmap_update_bits(rt1318->regmap, RT1318_PLL1_N_7_0,
+ RT1318_N_7_0_PLL1_MASK, pll_code.n_code);
+
+ rt1318->pll_in = freq_in;
+ rt1318->pll_out = freq_out;
+ rt1318->pll_src = source;
+
+ return 0;
+}
+
+static int rt1318_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+ unsigned int cn = 0, cl = 0, rx_slotnum;
+ int ret = 0, first_bit;
+
+ switch (slots) {
+ case 4:
+ cn |= RT1318_I2S_CH_TX_4CH;
+ cn |= RT1318_I2S_CH_RX_4CH;
+ break;
+ case 6:
+ cn |= RT1318_I2S_CH_TX_6CH;
+ cn |= RT1318_I2S_CH_RX_6CH;
+ break;
+ case 8:
+ cn |= RT1318_I2S_CH_TX_8CH;
+ cn |= RT1318_I2S_CH_RX_8CH;
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (slot_width) {
+ case 20:
+ cl |= RT1318_I2S_TX_CHL_20;
+ cl |= RT1318_I2S_RX_CHL_20;
+ break;
+ case 24:
+ cl |= RT1318_I2S_TX_CHL_24;
+ cl |= RT1318_I2S_RX_CHL_24;
+ break;
+ case 32:
+ cl |= RT1318_I2S_TX_CHL_32;
+ cl |= RT1318_I2S_RX_CHL_32;
+ break;
+ case 8:
+ cl |= RT1318_I2S_TX_CHL_8;
+ cl |= RT1318_I2S_RX_CHL_8;
+ break;
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Rx slot configuration */
+ rx_slotnum = hweight_long(rx_mask);
+ if (rx_slotnum != 1) {
+ ret = -EINVAL;
+ dev_err(component->dev, "too many rx slots or zero slot\n");
+ goto _set_tdm_err_;
+ }
+
+ first_bit = __ffs(rx_mask);
+ switch (first_bit) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ regmap_update_bits(rt1318->regmap,
+ RT1318_TDM_CTRL9,
+ RT1318_TDM_I2S_TX_L_DAC1_1_MASK |
+ RT1318_TDM_I2S_TX_R_DAC1_1_MASK,
+ (first_bit << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) |
+ ((first_bit + 1) << RT1318_TDM_I2S_TX_R_DAC1_1_SFT));
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ regmap_update_bits(rt1318->regmap,
+ RT1318_TDM_CTRL9,
+ RT1318_TDM_I2S_TX_L_DAC1_1_MASK |
+ RT1318_TDM_I2S_TX_R_DAC1_1_MASK,
+ ((first_bit - 1) << RT1318_TDM_I2S_TX_L_DAC1_1_SFT) |
+ (first_bit << RT1318_TDM_I2S_TX_R_DAC1_1_SFT));
+ break;
+ default:
+ ret = -EINVAL;
+ goto _set_tdm_err_;
+ }
+
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL2,
+ RT1318_I2S_CH_TX_MASK | RT1318_I2S_CH_RX_MASK, cn);
+ regmap_update_bits(rt1318->regmap, RT1318_TDM_CTRL3,
+ RT1318_I2S_TX_CHL_MASK | RT1318_I2S_RX_CHL_MASK, cl);
+
+_set_tdm_err_:
+ return ret;
+}
+
+static int rt1318_probe(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ rt1318->component = component;
+
+ schedule_work(&rt1318->cali_work);
+ rt1318->rt1318_dvol = RT1318_DVOL_STEP;
+
+ return 0;
+}
+
+static void rt1318_remove(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ cancel_work_sync(&rt1318->cali_work);
+}
+
+#ifdef CONFIG_PM
+static int rt1318_suspend(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1318->regmap, true);
+ regcache_mark_dirty(rt1318->regmap);
+ return 0;
+}
+
+static int rt1318_resume(struct snd_soc_component *component)
+{
+ struct rt1318_priv *rt1318 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1318->regmap, false);
+ regcache_sync(rt1318->regmap);
+ return 0;
+}
+#else
+#define rt1318_suspend NULL
+#define rt1318_resume NULL
+#endif
+
+#define RT1318_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1318_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt1318_aif_dai_ops = {
+ .hw_params = rt1318_hw_params,
+ .set_fmt = rt1318_set_dai_fmt,
+ .set_sysclk = rt1318_set_dai_sysclk,
+ .set_pll = rt1318_set_dai_pll,
+ .set_tdm_slot = rt1318_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt1318_dai[] = {
+ {
+ .name = "rt1318-aif",
+ .id = 0,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1318_STEREO_RATES,
+ .formats = RT1318_FORMATS,
+ },
+ .ops = &rt1318_aif_dai_ops,
+ }
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt1318 = {
+ .probe = rt1318_probe,
+ .remove = rt1318_remove,
+ .suspend = rt1318_suspend,
+ .resume = rt1318_resume,
+ .controls = rt1318_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1318_snd_controls),
+ .dapm_widgets = rt1318_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1318_dapm_widgets),
+ .dapm_routes = rt1318_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1318_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config rt1318_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1318_readable_register,
+ .volatile_reg = rt1318_volatile_register,
+ .max_register = 0x41001888,
+ .reg_defaults = rt1318_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt1318_reg),
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct i2c_device_id rt1318_i2c_id[] = {
+ { "rt1318" },
+ { }
+};
+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" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match);
+#endif
+
+static int rt1318_parse_dt(struct rt1318_priv *rt1318, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,r0_l",
+ &rt1318->pdata.init_r0_l);
+ device_property_read_u32(dev, "realtek,r0_r",
+ &rt1318->pdata.init_r0_r);
+
+ return 0;
+}
+
+static void rt1318_calibration_sequence(struct rt1318_priv *rt1318)
+{
+ regmap_write(rt1318->regmap, RT1318_CLK1, 0x22);
+ regmap_write(rt1318->regmap, RT1318_PLL1_N_7_0, 0x06);
+ regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xCC);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x40);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x40);
+ regmap_write(rt1318->regmap, RT1318_SINE_GEN0, 0x20);
+ regmap_write(rt1318->regmap, RT1318_SPK_VOL_TH, 0x00);
+ regmap_write(rt1318->regmap, RT1318_FEEDBACK_PATH, 0x0B);
+ regmap_write(rt1318->regmap, RT1318_TCON, 0x1C);
+ regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x58);
+ regmap_write(rt1318->regmap, RT1318_TCON_RELATE, 0x78);
+ regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xC2);
+}
+
+static void rt1318_r0_calculate(struct rt1318_priv *rt1318)
+{
+ unsigned int r0_l, r0_l_byte0, r0_l_byte1, r0_l_byte2, r0_l_byte3;
+ unsigned int r0_r, r0_r_byte0, r0_r_byte1, r0_r_byte2, r0_r_byte3;
+ unsigned int r0_l_integer, r0_l_factor, r0_r_integer, r0_r_factor;
+ unsigned int format = 16777216; /* 2^24 */
+
+ regmap_read(rt1318->regmap, RT1318_R0_L_24, &r0_l_byte0);
+ regmap_read(rt1318->regmap, RT1318_R0_L_23_16, &r0_l_byte1);
+ regmap_read(rt1318->regmap, RT1318_R0_L_15_8, &r0_l_byte2);
+ regmap_read(rt1318->regmap, RT1318_R0_L_7_0, &r0_l_byte3);
+ r0_l = r0_l_byte0 << 24 | r0_l_byte1 << 16 | r0_l_byte2 << 8 | r0_l_byte3;
+ r0_l_integer = format / r0_l;
+ r0_l_factor = (format * 10) / r0_l - r0_l_integer * 10;
+
+ regmap_read(rt1318->regmap, RT1318_R0_R_24, &r0_r_byte0);
+ regmap_read(rt1318->regmap, RT1318_R0_R_23_16, &r0_r_byte1);
+ regmap_read(rt1318->regmap, RT1318_R0_R_15_8, &r0_r_byte2);
+ regmap_read(rt1318->regmap, RT1318_R0_R_7_0, &r0_r_byte3);
+ r0_r = r0_r_byte0 << 24 | r0_r_byte1 << 16 | r0_r_byte2 << 8 | r0_r_byte3;
+ r0_r_integer = format / r0_r;
+ r0_r_factor = (format * 10) / r0_r - r0_r_integer * 10;
+
+ dev_dbg(rt1318->component->dev, "r0_l_ch:%d.%d ohm\n", r0_l_integer, r0_l_factor);
+ dev_dbg(rt1318->component->dev, "r0_r_ch:%d.%d ohm\n", r0_r_integer, r0_r_factor);
+}
+
+static void rt1318_r0_restore(struct rt1318_priv *rt1318)
+{
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_24,
+ (rt1318->pdata.init_r0_l >> 24) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_23_16,
+ (rt1318->pdata.init_r0_l >> 16) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_15_8,
+ (rt1318->pdata.init_r0_l >> 8) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_L_7_0,
+ (rt1318->pdata.init_r0_l >> 0) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_24,
+ (rt1318->pdata.init_r0_r >> 24) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_23_16,
+ (rt1318->pdata.init_r0_r >> 16) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_15_8,
+ (rt1318->pdata.init_r0_r >> 8) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_PRE_R0_R_7_0,
+ (rt1318->pdata.init_r0_r >> 0) & 0xff);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_L, 0x80);
+ regmap_write(rt1318->regmap, RT1318_STP_SEL_R, 0x80);
+ regmap_write(rt1318->regmap, RT1318_R0_CMP_L_FLAG, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_R0_CMP_R_FLAG, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_STP_R0_EN_L, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_STP_R0_EN_R, 0xc0);
+ regmap_write(rt1318->regmap, RT1318_STP_TEMP_L, 0xcc);
+ regmap_write(rt1318->regmap, RT1318_TCON, 0x9c);
+}
+
+static int rt1318_calibrate(struct rt1318_priv *rt1318)
+{
+ int chk_cnt = 30, count = 0;
+ int val, val2;
+
+ regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x1);
+ usleep_range(0, 10000);
+ rt1318_calibration_sequence(rt1318);
+
+ while (count < chk_cnt) {
+ msleep(100);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2);
+ val = (val >> 1) & 0x1;
+ val2 = (val2 >> 1) & 0x1;
+ if (val & val2) {
+ dev_dbg(rt1318->component->dev, "Calibration done.\n");
+ break;
+ }
+ count++;
+ if (count == chk_cnt) {
+ regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0);
+ return RT1318_R0_CALIB_NOT_DONE;
+ }
+ }
+ regmap_write(rt1318->regmap, RT1318_PWR_STA1, 0x0);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_L_FLAG, &val);
+ regmap_read(rt1318->regmap, RT1318_R0_CMP_R_FLAG, &val2);
+ if ((val & 0x1) & (val2 & 0x1))
+ return RT1318_R0_IN_RANGE;
+ else
+ return RT1318_R0_OUT_OF_RANGE;
+}
+
+static void rt1318_calibration_work(struct work_struct *work)
+{
+ struct rt1318_priv *rt1318 =
+ container_of(work, struct rt1318_priv, cali_work);
+ int ret;
+
+ if (rt1318->pdata.init_r0_l && rt1318->pdata.init_r0_r)
+ rt1318_r0_restore(rt1318);
+ else {
+ ret = rt1318_calibrate(rt1318);
+ if (ret == RT1318_R0_IN_RANGE)
+ rt1318_r0_calculate(rt1318);
+ dev_dbg(rt1318->component->dev, "Calibrate R0 result:%d\n", ret);
+ }
+}
+
+static int rt1318_i2c_probe(struct i2c_client *i2c)
+{
+ struct rt1318_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt1318_priv *rt1318;
+ int ret, val, val2, dev_id;
+
+ rt1318 = devm_kzalloc(&i2c->dev, sizeof(struct rt1318_priv),
+ GFP_KERNEL);
+ if (!rt1318)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt1318);
+
+ if (pdata)
+ rt1318->pdata = *pdata;
+ else
+ rt1318_parse_dt(rt1318, &i2c->dev);
+
+ rt1318->regmap = devm_regmap_init_i2c(i2c, &rt1318_regmap);
+ if (IS_ERR(rt1318->regmap)) {
+ ret = PTR_ERR(rt1318->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_read(rt1318->regmap, RT1318_DEV_ID1, &val);
+ regmap_read(rt1318->regmap, RT1318_DEV_ID2, &val2);
+ dev_id = (val << 8) | val2;
+ if (dev_id != 0x6821) {
+ dev_err(&i2c->dev,
+ "Device with ID register %#x is not rt1318\n",
+ dev_id);
+ return -ENODEV;
+ }
+
+ ret = regmap_register_patch(rt1318->regmap, init_list,
+ ARRAY_SIZE(init_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ INIT_WORK(&rt1318->cali_work, rt1318_calibration_work);
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt1318, rt1318_dai, ARRAY_SIZE(rt1318_dai));
+}
+
+static struct i2c_driver rt1318_i2c_driver = {
+ .driver = {
+ .name = "rt1318",
+ .of_match_table = of_match_ptr(rt1318_of_match),
+ .acpi_match_table = ACPI_PTR(rt1318_acpi_match),
+ },
+ .probe = rt1318_i2c_probe,
+ .id_table = rt1318_i2c_id,
+};
+module_i2c_driver(rt1318_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1318 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1318.h b/sound/soc/codecs/rt1318.h
new file mode 100644
index 000000000000..cec40b484216
--- /dev/null
+++ b/sound/soc/codecs/rt1318.h
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1318.h -- Platform data for RT1318
+ *
+ * Copyright 2024 Realtek Semiconductor Corp.
+ */
+#include <sound/rt1318.h>
+
+#ifndef __RT1318_H__
+#define __RT1318_H__
+
+struct rt1318_priv {
+ struct snd_soc_component *component;
+ struct rt1318_platform_data pdata;
+ struct work_struct cali_work;
+ struct regmap *regmap;
+
+ unsigned int r0_l_integer;
+ unsigned int r0_l_factor;
+ unsigned int r0_r_integer;
+ unsigned int r0_r_factor;
+ int rt1318_init;
+ int rt1318_dvol;
+ int sysclk_src;
+ int sysclk;
+ int lrck;
+ int bclk;
+ int master;
+ int pll_src;
+ int pll_in;
+ int pll_out;
+};
+
+#define RT1318_PLL_INP_MAX 40000000
+#define RT1318_PLL_INP_MIN 256000
+#define RT1318_PLL_N_MAX 0x1ff
+#define RT1318_PLL_K_MAX 0x1f
+#define RT1318_PLL_M_MAX 0x1f
+
+#define RT1318_LRCLK_192000 192000
+#define RT1318_LRCLK_96000 96000
+#define RT1318_LRCLK_48000 48000
+#define RT1318_LRCLK_44100 44100
+#define RT1318_LRCLK_16000 16000
+#define RT1318_DVOL_STEP 383
+
+#define RT1318_CLK1 0xc001
+#define RT1318_CLK2 0xc003
+#define RT1318_CLK3 0xc004
+#define RT1318_CLK4 0xc005
+#define RT1318_CLK5 0xc006
+#define RT1318_CLK6 0xc007
+#define RT1318_CLK7 0xc008
+#define RT1318_PWR_STA1 0xc121
+#define RT1318_SPK_VOL_TH 0xc130
+#define RT1318_TCON 0xc203
+#define RT1318_SRC_TCON 0xc204
+#define RT1318_TCON_RELATE 0xc206
+#define RT1318_DA_VOL_L_8 0xc20b
+#define RT1318_DA_VOL_L_1_7 0xc20c
+#define RT1318_DA_VOL_R_8 0xc20d
+#define RT1318_DA_VOL_R_1_7 0xc20e
+#define RT1318_FEEDBACK_PATH 0xc321
+#define RT1318_STP_TEMP_L 0xdb00
+#define RT1318_STP_SEL_L 0xdb08
+#define RT1318_STP_R0_EN_L 0xdb12
+#define RT1318_R0_CMP_L_FLAG 0xdb35
+#define RT1318_PRE_R0_L_24 0xdbb5
+#define RT1318_PRE_R0_L_23_16 0xdbb6
+#define RT1318_PRE_R0_L_15_8 0xdbb7
+#define RT1318_PRE_R0_L_7_0 0xdbb8
+#define RT1318_R0_L_24 0xdbc5
+#define RT1318_R0_L_23_16 0xdbc6
+#define RT1318_R0_L_15_8 0xdbc7
+#define RT1318_R0_L_7_0 0xdbc8
+#define RT1318_STP_SEL_R 0xdd08
+#define RT1318_STP_R0_EN_R 0xdd12
+#define RT1318_R0_CMP_R_FLAG 0xdd35
+#define RT1318_PRE_R0_R_24 0xddb5
+#define RT1318_PRE_R0_R_23_16 0xddb6
+#define RT1318_PRE_R0_R_15_8 0xddb7
+#define RT1318_PRE_R0_R_7_0 0xddb8
+#define RT1318_R0_R_24 0xddc5
+#define RT1318_R0_R_23_16 0xddc6
+#define RT1318_R0_R_15_8 0xddc7
+#define RT1318_R0_R_7_0 0xddc8
+#define RT1318_DEV_ID1 0xf012
+#define RT1318_DEV_ID2 0xf013
+#define RT1318_PLL1_K 0xf20d
+#define RT1318_PLL1_M 0xf20f
+#define RT1318_PLL1_N_8 0xf211
+#define RT1318_PLL1_N_7_0 0xf212
+#define RT1318_SINE_GEN0 0xf800
+#define RT1318_TDM_CTRL1 0xf900
+#define RT1318_TDM_CTRL2 0xf901
+#define RT1318_TDM_CTRL3 0xf902
+#define RT1318_TDM_CTRL9 0xf908
+
+
+/* Clock-1 (0xC001) */
+#define RT1318_PLLIN_MASK (0x7 << 4)
+#define RT1318_PLLIN_BCLK0 (0x0 << 4)
+#define RT1318_PLLIN_BCLK1 (0x1 << 4)
+#define RT1318_PLLIN_RC (0x2 << 4)
+#define RT1318_PLLIN_MCLK (0x3 << 4)
+#define RT1318_PLLIN_SDW1 (0x4 << 4)
+#define RT1318_PLLIN_SDW2 (0x5 << 4)
+#define RT1318_PLLIN_SDW3 (0x6 << 4)
+#define RT1318_PLLIN_SDW4 (0x7 << 4)
+#define RT1318_SYSCLK_SEL_MASK (0x7 << 0)
+#define RT1318_SYSCLK_BCLK (0x0 << 0)
+#define RT1318_SYSCLK_SDW (0x1 << 0)
+#define RT1318_SYSCLK_PLL2F (0x2 << 0)
+#define RT1318_SYSCLK_PLL2B (0x3 << 0)
+#define RT1318_SYSCLK_MCLK (0x4 << 0)
+#define RT1318_SYSCLK_RC1 (0x5 << 0)
+#define RT1318_SYSCLK_RC2 (0x6 << 0)
+#define RT1318_SYSCLK_RC3 (0x7 << 0)
+/* Clock-2 (0xC003) */
+#define RT1318_DIV_AP_MASK (0x3 << 4)
+#define RT1318_DIV_AP_SFT 4
+#define RT1318_DIV_AP_DIV1 (0x0 << 4)
+#define RT1318_DIV_AP_DIV2 (0x1 << 4)
+#define RT1318_DIV_AP_DIV4 (0x2 << 4)
+#define RT1318_DIV_AP_DIV8 (0x3 << 4)
+#define RT1318_DIV_DAMOD_MASK (0x3 << 0)
+#define RT1318_DIV_DAMOD_SFT 0
+#define RT1318_DIV_DAMOD_DIV1 (0x0 << 0)
+#define RT1318_DIV_DAMOD_DIV2 (0x1 << 0)
+#define RT1318_DIV_DAMOD_DIV4 (0x2 << 0)
+#define RT1318_DIV_DAMOD_DIV8 (0x3 << 0)
+/* Clock-3 (0xC004) */
+#define RT1318_AD_STO1_MASK (0x7 << 4)
+#define RT1318_AD_STO1_SFT 4
+#define RT1318_AD_STO1_DIV1 (0x0 << 4)
+#define RT1318_AD_STO1_DIV2 (0x1 << 4)
+#define RT1318_AD_STO1_DIV4 (0x2 << 4)
+#define RT1318_AD_STO1_DIV8 (0x3 << 4)
+#define RT1318_AD_STO1_DIV16 (0x4 << 4)
+#define RT1318_AD_STO2_MASK (0x7 << 0)
+#define RT1318_AD_STO2_SFT 0
+#define RT1318_AD_STO2_DIV1 (0x0 << 0)
+#define RT1318_AD_STO2_DIV2 (0x1 << 0)
+#define RT1318_AD_STO2_DIV4 (0x2 << 0)
+#define RT1318_AD_STO2_DIV8 (0x3 << 0)
+#define RT1318_AD_STO2_DIV16 (0x4 << 0)
+#define RT1318_AD_STO2_SFT 0
+/* Clock-4 (0xC005) */
+#define RT1318_AD_ANA_STO1_MASK (0x7 << 4)
+#define RT1318_AD_ANA_STO1_SFT 4
+#define RT1318_AD_ANA_STO1_DIV1 (0x0 << 4)
+#define RT1318_AD_ANA_STO1_DIV2 (0x1 << 4)
+#define RT1318_AD_ANA_STO1_DIV4 (0x2 << 4)
+#define RT1318_AD_ANA_STO1_DIV8 (0x3 << 4)
+#define RT1318_AD_ANA_STO1_DIV16 (0x4 << 4)
+#define RT1318_AD_ANA_STO2_MASK (0x7 << 0)
+#define RT1318_AD_ANA_STO2_DIV1 (0x0 << 0)
+#define RT1318_AD_ANA_STO2_DIV2 (0x1 << 0)
+#define RT1318_AD_ANA_STO2_DIV4 (0x2 << 0)
+#define RT1318_AD_ANA_STO2_DIV8 (0x3 << 0)
+#define RT1318_AD_ANA_STO2_DIV16 (0x4 << 0)
+#define RT1318_AD_ANA_STO2_SFT 0
+/* Clock-5 (0xC006) */
+#define RT1318_DIV_FIFO_IN_MASK (0x3 << 4)
+#define RT1318_DIV_FIFO_IN_SFT 4
+#define RT1318_DIV_FIFO_IN_DIV1 (0x0 << 4)
+#define RT1318_DIV_FIFO_IN_DIV2 (0x1 << 4)
+#define RT1318_DIV_FIFO_IN_DIV4 (0x2 << 4)
+#define RT1318_DIV_FIFO_IN_DIV8 (0x3 << 4)
+#define RT1318_DIV_FIFO_OUT_MASK (0x3 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV1 (0x0 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV2 (0x1 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV4 (0x2 << 0)
+#define RT1318_DIV_FIFO_OUT_DIV8 (0x3 << 0)
+#define RT1318_DIV_FIFO_OUT_SFT 0
+/* Clock-6 (0xC007) */
+#define RT1318_DIV_NLMS_MASK (0x3 << 6)
+#define RT1318_DIV_NLMS_SFT 6
+#define RT1318_DIV_NLMS_DIV1 (0x0 << 6)
+#define RT1318_DIV_NLMS_DIV2 (0x1 << 6)
+#define RT1318_DIV_NLMS_DIV4 (0x2 << 6)
+#define RT1318_DIV_NLMS_DIV8 (0x3 << 6)
+#define RT1318_DIV_AD_MONO_MASK (0x7 << 3)
+#define RT1318_DIV_AD_MONO_SFT 3
+#define RT1318_DIV_AD_MONO_DIV1 (0x0 << 3)
+#define RT1318_DIV_AD_MONO_DIV2 (0x1 << 3)
+#define RT1318_DIV_AD_MONO_DIV4 (0x2 << 3)
+#define RT1318_DIV_AD_MONO_DIV8 (0x3 << 3)
+#define RT1318_DIV_AD_MONO_DIV16 (0x4 << 3)
+#define RT1318_DIV_POST_G_MASK (0x7 << 0)
+#define RT1318_DIV_POST_G_SFT 0
+#define RT1318_DIV_POST_G_DIV1 (0x0 << 0)
+#define RT1318_DIV_POST_G_DIV2 (0x1 << 0)
+#define RT1318_DIV_POST_G_DIV4 (0x2 << 0)
+#define RT1318_DIV_POST_G_DIV8 (0x3 << 0)
+#define RT1318_DIV_POST_G_DIV16 (0x4 << 0)
+/* Power Status 1 (0xC121) */
+#define RT1318_PDB_CTRL_MASK (0x1)
+#define RT1318_PDB_CTRL_LOW (0x0)
+#define RT1318_PDB_CTRL_HIGH (0x1)
+#define RT1318_PDB_CTRL_SFT 0
+/* SRC Tcon(0xc204) */
+#define RT1318_SRCIN_IN_SEL_MASK (0x3 << 6)
+#define RT1318_SRCIN_IN_48K (0x0 << 6)
+#define RT1318_SRCIN_IN_44P1 (0x1 << 6)
+#define RT1318_SRCIN_IN_32K (0x2 << 6)
+#define RT1318_SRCIN_IN_16K (0x3 << 6)
+#define RT1318_SRCIN_F12288_MASK (0x3 << 4)
+#define RT1318_SRCIN_TCON1 (0x0 << 4)
+#define RT1318_SRCIN_TCON2 (0x1 << 4)
+#define RT1318_SRCIN_TCON4 (0x2 << 4)
+#define RT1318_SRCIN_TCON8 (0x3 << 4)
+#define RT1318_SRCIN_DACLK_MASK (0x3 << 2)
+#define RT1318_DACLK_TCON1 (0x0 << 2)
+#define RT1318_DACLK_TCON2 (0x1 << 2)
+#define RT1318_DACLK_TCON4 (0x2 << 2)
+#define RT1318_DACLK_TCON8 (0x3 << 2)
+/* R0 Compare Flag (0xDB35) */
+#define RT1318_R0_RANGE_MASK (0x1)
+#define RT1318_R0_OUTOFRANGE (0x0)
+#define RT1318_R0_INRANGE (0x1)
+/* PLL internal setting (0xF20D), K value */
+#define RT1318_K_PLL1_MASK (0x1f << 0)
+/* PLL internal setting (0xF20F), M value */
+#define RT1318_M_PLL1_MASK (0x1f << 0)
+/* PLL internal setting (0xF211), N_8 value */
+#define RT1318_N_8_PLL1_MASK (0x1 << 0)
+/* PLL internal setting (0xF212), N_7_0 value */
+#define RT1318_N_7_0_PLL1_MASK (0xff << 0)
+/* TDM CTRL 1 (0xf900) */
+#define RT1318_TDM_BCLK_MASK (0x1 << 7)
+#define RT1318_TDM_BCLK_NORM (0x0 << 7)
+#define RT1318_TDM_BCLK_INV (0x1 << 7)
+#define RT1318_I2S_FMT_MASK (0x7 << 0)
+#define RT1318_FMT_I2S (0x0 << 0)
+#define RT1318_FMT_LEFT_J (0x1 << 0)
+#define RT1318_FMT_PCM_A_R (0x2 << 0)
+#define RT1318_FMT_PCM_B_R (0x3 << 0)
+#define RT1318_FMT_PCM_A_F (0x6 << 0)
+#define RT1318_FMT_PCM_B_F (0x7 << 0)
+#define RT1318_I2S_FMT_SFT 0
+/* TDM CTRL 2 (0xf901) */
+#define RT1318_I2S_CH_TX_MASK (0x3 << 6)
+#define RT1318_I2S_CH_TX_2CH (0x0 << 6)
+#define RT1318_I2S_CH_TX_4CH (0x1 << 6)
+#define RT1318_I2S_CH_TX_6CH (0x2 << 6)
+#define RT1318_I2S_CH_TX_8CH (0x3 << 6)
+#define RT1318_I2S_CH_RX_MASK (0x3 << 4)
+#define RT1318_I2S_CH_RX_2CH (0x0 << 4)
+#define RT1318_I2S_CH_RX_4CH (0x1 << 4)
+#define RT1318_I2S_CH_RX_6CH (0x2 << 4)
+#define RT1318_I2S_CH_RX_8CH (0x3 << 4)
+#define RT1318_I2S_DL_MASK 0x7
+#define RT1318_I2S_DL_SFT 0
+#define RT1318_I2S_DL_16 0x0
+#define RT1318_I2S_DL_20 0x1
+#define RT1318_I2S_DL_24 0x2
+#define RT1318_I2S_DL_32 0x3
+#define RT1318_I2S_DL_8 0x4
+/* TDM CTRL 3 (0xf902) */
+#define RT1318_I2S_TX_CHL_MASK (0x7 << 4)
+#define RT1318_I2S_TX_CHL_SFT 4
+#define RT1318_I2S_TX_CHL_16 (0x0 << 4)
+#define RT1318_I2S_TX_CHL_20 (0x1 << 4)
+#define RT1318_I2S_TX_CHL_24 (0x2 << 4)
+#define RT1318_I2S_TX_CHL_32 (0x3 << 4)
+#define RT1318_I2S_TX_CHL_8 (0x4 << 4)
+#define RT1318_I2S_RX_CHL_MASK (0x7 << 0)
+#define RT1318_I2S_RX_CHL_SFT 0
+#define RT1318_I2S_RX_CHL_16 (0x0 << 0)
+#define RT1318_I2S_RX_CHL_20 (0x1 << 0)
+#define RT1318_I2S_RX_CHL_24 (0x2 << 0)
+#define RT1318_I2S_RX_CHL_32 (0x3 << 0)
+#define RT1318_I2S_RX_CHL_8 (0x4 << 0)
+/* TDM CTRL 9 (0xf908) */
+#define RT1318_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 4)
+#define RT1318_TDM_I2S_TX_R_DAC1_1_MASK 0x7
+#define RT1318_TDM_I2S_TX_L_DAC1_1_SFT 4
+#define RT1318_TDM_I2S_TX_R_DAC1_1_SFT 0
+
+#define RT1318_REG_DISP_LEN 23
+
+/* System Clock Source */
+enum {
+ RT1318_SCLK_S_BCLK,
+ RT1318_SCLK_S_SDW,
+ RT1318_SCLK_S_PLL2F,
+ RT1318_SCLK_S_PLL2B,
+ RT1318_SCLK_S_MCLK,
+ RT1318_SCLK_S_RC0,
+ RT1318_SCLK_S_RC1,
+ RT1318_SCLK_S_RC2,
+};
+
+/* PLL Source */
+enum {
+ RT1318_PLL_S_BCLK0,
+ RT1318_PLL_S_BCLK1,
+ RT1318_PLL_S_RC,
+ RT1318_PLL_S_MCLK,
+ RT1318_PLL_S_SDW_IN_PLL,
+ RT1318_PLL_S_SDW_0,
+ RT1318_PLL_S_SDW_1,
+ RT1318_PLL_S_SDW_2,
+};
+
+/* TDM channel */
+enum {
+ RT1318_2CH,
+ RT1318_4CH,
+ RT1318_6CH,
+ RT1318_8CH,
+};
+
+/* R0 calibration result */
+enum {
+ RT1318_R0_OUT_OF_RANGE,
+ RT1318_R0_IN_RANGE,
+ RT1318_R0_CALIB_NOT_DONE,
+};
+
+/* PLL pre-defined M/N/K */
+
+struct pll_calc_map {
+ unsigned int pll_in;
+ unsigned int pll_out;
+ int k;
+ int n;
+ int m;
+ bool m_bp;
+ bool k_bp;
+};
+
+struct rt1318_pll_code {
+ bool m_bp; /* Indicates bypass m code or not. */
+ bool k_bp; /* Indicates bypass k code or not. */
+ int m_code;
+ int n_code;
+ int k_code;
+};
+
+#endif /* __RT1318_H__ */
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
new file mode 100644
index 000000000000..e3f9b03df3aa
--- /dev/null
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -0,0 +1,1823 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1320-sdw.c -- rt1320 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/sdw.h>
+#include "rt1320-sdw.h"
+#include "rt-sdw-common.h"
+
+/*
+ * The 'blind writes' is an SDCA term to deal with platform-specific initialization.
+ * It might include vendor-specific or SDCA control registers.
+ */
+static const struct reg_sequence rt1320_blind_write[] = {
+ { 0xc003, 0xe0 },
+ { 0xc01b, 0xfc },
+ { 0xc5c3, 0xf2 },
+ { 0xc5c2, 0x00 },
+ { 0xc5c6, 0x10 },
+ { 0xc5c4, 0x12 },
+ { 0xc5c8, 0x03 },
+ { 0xc5d8, 0x0a },
+ { 0xc5f7, 0x22 },
+ { 0xc5f6, 0x22 },
+ { 0xc5d0, 0x0f },
+ { 0xc5d1, 0x89 },
+ { 0xc057, 0x51 },
+ { 0xc054, 0x35 },
+ { 0xc053, 0x55 },
+ { 0xc052, 0x55 },
+ { 0xc051, 0x13 },
+ { 0xc050, 0x15 },
+ { 0xc060, 0x77 },
+ { 0xc061, 0x55 },
+ { 0xc063, 0x55 },
+ { 0xc065, 0xa5 },
+ { 0xc06b, 0x0a },
+ { 0xca05, 0xd6 },
+ { 0xca25, 0xd6 },
+ { 0xcd00, 0x05 },
+ { 0xc604, 0x40 },
+ { 0xc609, 0x40 },
+ { 0xc046, 0xff },
+ { 0xc045, 0xff },
+ { 0xc044, 0xff },
+ { 0xc043, 0xff },
+ { 0xc042, 0xff },
+ { 0xc041, 0xff },
+ { 0xc040, 0xff },
+ { 0xcc10, 0x01 },
+ { 0xc700, 0xf0 },
+ { 0xc701, 0x13 },
+ { 0xc901, 0x04 },
+ { 0xc900, 0x73 },
+ { 0xde03, 0x05 },
+ { 0xdd0b, 0x0d },
+ { 0xdd0a, 0xff },
+ { 0xdd09, 0x0d },
+ { 0xdd08, 0xff },
+ { 0xc570, 0x08 },
+ { 0xe803, 0xbe },
+ { 0xc003, 0xc0 },
+ { 0xc081, 0xfe },
+ { 0xce31, 0x0d },
+ { 0xce30, 0xae },
+ { 0xce37, 0x0b },
+ { 0xce36, 0xd2 },
+ { 0xce39, 0x04 },
+ { 0xce38, 0x80 },
+ { 0xce3f, 0x00 },
+ { 0xce3e, 0x00 },
+ { 0xd470, 0x8b },
+ { 0xd471, 0x18 },
+ { 0xc019, 0x10 },
+ { 0xd487, 0x3f },
+ { 0xd486, 0xc3 },
+ { 0x3fc2bfc7, 0x00 },
+ { 0x3fc2bfc6, 0x00 },
+ { 0x3fc2bfc5, 0x00 },
+ { 0x3fc2bfc4, 0x01 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x02 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x11 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x82 },
+ { 0x1000db06, 0x04 },
+ { 0x1000db07, 0xf1 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0x40 },
+ { 0x0000d540, 0x01 },
+ { 0xd172, 0x2a },
+ { 0xc5d6, 0x01 },
+ { 0xd478, 0xff },
+};
+
+static const struct reg_sequence rt1320_vc_blind_write[] = {
+ { 0xc003, 0xe0 },
+ { 0xe80a, 0x01 },
+ { 0xc5c3, 0xf3 },
+ { 0xc057, 0x51 },
+ { 0xc054, 0x35 },
+ { 0xca05, 0xd6 },
+ { 0xca07, 0x07 },
+ { 0xca25, 0xd6 },
+ { 0xca27, 0x07 },
+ { 0xc604, 0x40 },
+ { 0xc609, 0x40 },
+ { 0xc046, 0xff },
+ { 0xc045, 0xff },
+ { 0xda81, 0x14 },
+ { 0xda8d, 0x14 },
+ { 0xc044, 0xff },
+ { 0xc043, 0xff },
+ { 0xc042, 0xff },
+ { 0xc041, 0x7f },
+ { 0xc040, 0xff },
+ { 0xcc10, 0x01 },
+ { 0xc700, 0xf0 },
+ { 0xc701, 0x13 },
+ { 0xc901, 0x09 },
+ { 0xc900, 0xd0 },
+ { 0xde03, 0x05 },
+ { 0xdd0b, 0x0d },
+ { 0xdd0a, 0xff },
+ { 0xdd09, 0x0d },
+ { 0xdd08, 0xff },
+ { 0xc570, 0x08 },
+ { 0xc086, 0x02 },
+ { 0xc085, 0x7f },
+ { 0xc084, 0x00 },
+ { 0xc081, 0xfe },
+ { 0xf084, 0x0f },
+ { 0xf083, 0xff },
+ { 0xf082, 0xff },
+ { 0xf081, 0xff },
+ { 0xf080, 0xff },
+ { 0xe802, 0xf8 },
+ { 0xe803, 0xbe },
+ { 0xc003, 0xc0 },
+ { 0xd470, 0xec },
+ { 0xd471, 0x3a },
+ { 0xd474, 0x11 },
+ { 0xd475, 0x32 },
+ { 0xd478, 0xff },
+ { 0xd479, 0x20 },
+ { 0xd47a, 0x10 },
+ { 0xd47c, 0xff },
+ { 0xc019, 0x10 },
+ { 0xd487, 0x0b },
+ { 0xd487, 0x3b },
+ { 0xd486, 0xc3 },
+ { 0xc598, 0x04 },
+ { 0xdb03, 0xf0 },
+ { 0xdb09, 0x00 },
+ { 0xdb08, 0x7a },
+ { 0xdb19, 0x02 },
+ { 0xdb07, 0x5a },
+ { 0xdb05, 0x45 },
+ { 0xd500, 0x00 },
+ { 0xd500, 0x17 },
+ { 0xd600, 0x01 },
+ { 0xd601, 0x02 },
+ { 0xd602, 0x03 },
+ { 0xd603, 0x04 },
+ { 0xd64c, 0x03 },
+ { 0xd64d, 0x03 },
+ { 0xd64e, 0x03 },
+ { 0xd64f, 0x03 },
+ { 0xd650, 0x03 },
+ { 0xd651, 0x03 },
+ { 0xd652, 0x03 },
+ { 0xd610, 0x01 },
+ { 0xd608, 0x03 },
+ { 0xd609, 0x00 },
+ { 0x3fc2bf83, 0x00 },
+ { 0x3fc2bf82, 0x00 },
+ { 0x3fc2bf81, 0x00 },
+ { 0x3fc2bf80, 0x00 },
+ { 0x3fc2bfc7, 0x00 },
+ { 0x3fc2bfc6, 0x00 },
+ { 0x3fc2bfc5, 0x00 },
+ { 0x3fc2bfc4, 0x00 },
+ { 0x3fc2bfc3, 0x00 },
+ { 0x3fc2bfc2, 0x00 },
+ { 0x3fc2bfc1, 0x00 },
+ { 0x3fc2bfc0, 0x03 },
+ { 0x0000d486, 0x43 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 },
+ { 0x1000db00, 0x07 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x11 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x82 },
+ { 0x1000db06, 0x04 },
+ { 0x1000db07, 0xf1 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0x40 },
+ { 0x1000db0b, 0x02 },
+ { 0x1000db0c, 0xf2 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0xe0 },
+ { 0x1000db10, 0x00 },
+ { 0x1000db11, 0x10 },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x45 },
+ { 0x1000db15, 0x0d },
+ { 0x1000db16, 0x01 },
+ { 0x1000db17, 0x00 },
+ { 0x1000db18, 0x00 },
+ { 0x1000db19, 0xbf },
+ { 0x1000db1a, 0x13 },
+ { 0x1000db1b, 0x09 },
+ { 0x1000db1c, 0x00 },
+ { 0x1000db1d, 0x00 },
+ { 0x1000db1e, 0x00 },
+ { 0x1000db1f, 0x12 },
+ { 0x1000db20, 0x09 },
+ { 0x1000db21, 0x00 },
+ { 0x1000db22, 0x00 },
+ { 0x1000db23, 0x00 },
+ { 0x0000d540, 0x01 },
+ { 0x0000c081, 0xfc },
+ { 0x0000f01e, 0x80 },
+ { 0xc01b, 0xfc },
+ { 0xc5d1, 0x89 },
+ { 0xc5d8, 0x0a },
+ { 0xc5f7, 0x22 },
+ { 0xc5f6, 0x22 },
+ { 0xc065, 0xa5 },
+ { 0xc06b, 0x0a },
+ { 0xd172, 0x2a },
+ { 0xc5d6, 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+static const struct reg_sequence rt1321_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000cb00, 0x03 },
+ { 0x0000cb02, 0x52 },
+ { 0x0000cb04, 0x80 },
+ { 0x0000cb0b, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca07, 0x07 },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca27, 0x07 },
+ { 0x0000cd00, 0x05 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x1d },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x0000d73c, 0xb7 },
+ { 0x0000d73d, 0xd7 },
+ { 0x0000d73e, 0x00 },
+ { 0x0000d73f, 0x10 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc0, 0x07 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2df83, 0x00 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df81, 0x00 },
+ { 0x3fc2df80, 0x00 },
+ { 0x0000d541, 0x40 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x03 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x12 },
+ { 0x1000db07, 0x09 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0x00 },
+ { 0x1000db0b, 0x13 },
+ { 0x1000db0c, 0x09 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x0000d540, 0x21 },
+ { 0x41000189, 0x00 },
+ { 0x4100018a, 0x00 },
+ { 0x41001988, 0x00 },
+ { 0x41081400, 0x09 },
+ { 0x40801508, 0x03 },
+ { 0x40801588, 0x03 },
+ { 0x40801809, 0x00 },
+ { 0x4080180a, 0x00 },
+ { 0x4080180b, 0x00 },
+ { 0x4080180c, 0x00 },
+ { 0x40801b09, 0x00 },
+ { 0x40801b0a, 0x00 },
+ { 0x40801b0b, 0x00 },
+ { 0x40801b0c, 0x00 },
+ { 0x0000d714, 0x17 },
+ { 0x20009012, 0x00 },
+ { 0x0000dd0b, 0x0d },
+ { 0x0000dd0a, 0xff },
+ { 0x0000dd09, 0x0d },
+ { 0x0000dd08, 0xff },
+ { 0x0000d172, 0x2a },
+ { 0x41001988, 0x03 },
+};
+
+static const struct reg_default rt1320_reg_defaults[] = {
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 },
+};
+
+static const struct reg_default rt1320_mbq_defaults[] = {
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+};
+
+static bool rt1320_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000 ... 0xc086:
+ case 0xc400 ... 0xc409:
+ case 0xc480 ... 0xc48f:
+ case 0xc4c0 ... 0xc4c4:
+ case 0xc4e0 ... 0xc4e7:
+ case 0xc500:
+ case 0xc560 ... 0xc56b:
+ case 0xc570:
+ case 0xc580 ... 0xc59a:
+ case 0xc5b0 ... 0xc60f:
+ case 0xc640 ... 0xc64f:
+ case 0xc670:
+ case 0xc680 ... 0xc683:
+ case 0xc700 ... 0xc76f:
+ case 0xc800 ... 0xc801:
+ case 0xc820:
+ case 0xc900 ... 0xc901:
+ case 0xc920 ... 0xc921:
+ case 0xca00 ... 0xca07:
+ case 0xca20 ... 0xca27:
+ case 0xca40 ... 0xca4b:
+ case 0xca60 ... 0xca68:
+ case 0xca80 ... 0xca88:
+ case 0xcb00 ... 0xcb0c:
+ case 0xcc00 ... 0xcc12:
+ case 0xcc80 ... 0xcc81:
+ case 0xcd00:
+ case 0xcd80 ... 0xcd82:
+ case 0xce00 ... 0xce4d:
+ case 0xcf00 ... 0xcf25:
+ case 0xd000 ... 0xd0ff:
+ case 0xd100 ... 0xd1ff:
+ case 0xd200 ... 0xd2ff:
+ case 0xd300 ... 0xd3ff:
+ case 0xd400 ... 0xd403:
+ case 0xd410 ... 0xd417:
+ case 0xd470 ... 0xd497:
+ case 0xd4dc ... 0xd50f:
+ case 0xd520 ... 0xd543:
+ case 0xd560 ... 0xd5ef:
+ case 0xd600 ... 0xd663:
+ case 0xda00 ... 0xda6e:
+ case 0xda80 ... 0xda9e:
+ case 0xdb00 ... 0xdb7f:
+ case 0xdc00:
+ case 0xdc20 ... 0xdc21:
+ case 0xdd00 ... 0xdd17:
+ case 0xde00 ... 0xde09:
+ case 0xdf00 ... 0xdf1b:
+ case 0xe000 ... 0xe847:
+ case 0xf01e:
+ case 0xf717 ... 0xf719:
+ case 0xf720 ... 0xf723:
+ case 0x1000cd91 ... 0x1000cd96:
+ case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER:
+ case 0x1000f008:
+ case 0x1000f021:
+ case 0x2000300f:
+ case 0x2000301c:
+ case 0x2000900f:
+ case 0x20009018:
+ case 0x3fc29d80 ... 0x3fc29d83:
+ case 0x3fe2e000 ... 0x3fe2e003:
+ case 0x3fc2ab80 ... 0x3fc2abd4:
+ case 0x3fc2bfc0 ... 0x3fc2bfc8:
+ case 0x3fc2d300 ... 0x3fc2d354:
+ case 0x3fc2dfc0 ... 0x3fc2dfc8:
+ /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+ /* 0x40880900/0x40880980 */
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ /* 0x40881500 */
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ /* 0x41000189/0x4100018a */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+ /* 0x41001388 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+ /* 0x41001988 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+ /* 0x41080000 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
+ /* 0x41080200 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0):
+ /* 0x41080900 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ /* 0x41080980 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ /* 0x41081080 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ /* 0x41081480/0x41081488 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ /* 0x41081980 */
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0xc000:
+ case 0xc003:
+ case 0xc081:
+ case 0xc402 ... 0xc406:
+ case 0xc48c ... 0xc48f:
+ case 0xc560:
+ case 0xc5b5 ... 0xc5b7:
+ case 0xc5fc ... 0xc5ff:
+ case 0xc680 ... 0xc683:
+ case 0xc820:
+ case 0xc900:
+ case 0xc920:
+ case 0xca42:
+ case 0xca62:
+ case 0xca82:
+ case 0xcd00:
+ case 0xce03:
+ case 0xce10:
+ case 0xce14 ... 0xce17:
+ case 0xce44 ... 0xce49:
+ case 0xce4c ... 0xce4d:
+ case 0xcf0c:
+ case 0xcf10 ... 0xcf25:
+ case 0xd486 ... 0xd487:
+ case 0xd4e5 ... 0xd4e6:
+ case 0xd4e8 ... 0xd4ff:
+ case 0xd530:
+ case 0xd540 ... 0xd541:
+ case 0xd543:
+ case 0xdb58 ... 0xdb5f:
+ case 0xdb60 ... 0xdb63:
+ case 0xdb68 ... 0xdb69:
+ case 0xdb6d:
+ case 0xdb70 ... 0xdb71:
+ case 0xdb76:
+ case 0xdb7a:
+ case 0xdb7c ... 0xdb7f:
+ case 0xdd0c ... 0xdd13:
+ case 0xde02:
+ case 0xdf14 ... 0xdf1b:
+ case 0xe83c ... 0xe847:
+ case 0xf01e:
+ case 0xf717 ... 0xf719:
+ case 0xf720 ... 0xf723:
+ case 0x10000000 ... 0x10008fff:
+ case 0x1000c000 ... 0x1000dfff:
+ case 0x1000f008:
+ case 0x1000f021:
+ case 0x2000300f:
+ case 0x2000301c:
+ case 0x2000900f:
+ case 0x20009018:
+ case 0x3fc2ab80 ... 0x3fc2abd4:
+ case 0x3fc2b780:
+ case 0x3fc2bf80 ... 0x3fc2bf83:
+ case 0x3fc2bfc0 ... 0x3fc2bfc8:
+ case 0x3fc2d300 ... 0x3fc2d354:
+ case 0x3fc2dfc0 ... 0x3fc2dfc8:
+ case 0x3fe2e000 ... 0x3fe2e003:
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt1320_sdw_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1320_readable_register,
+ .volatile_reg = rt1320_volatile_register,
+ .max_register = 0x41081980,
+ .reg_defaults = rt1320_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1320_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt1320_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt1320_mbq_readable_register,
+ .max_register = 0x41000192,
+ .reg_defaults = rt1320_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1320_mbq_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1320_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ /*
+ * Due to support the multi-lane, we call 'sdw_slave_read_prop' to get the lane mapping
+ */
+ sdw_slave_read_prop(slave);
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+ prop->lane_control_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = BIT(4) | BIT(8) | BIT(10);
+ prop->sink_ports = BIT(1);
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* 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;
+}
+
+static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char func,
+ unsigned char entity, unsigned char ps)
+{
+ unsigned int delay = 2000, val;
+
+ pm_runtime_mark_last_busy(&rt1320->sdw_slave->dev);
+
+ /* waiting for Actual PDE becomes to PS0/PS3 */
+ while (delay) {
+ regmap_read(rt1320->regmap,
+ SDW_SDCA_CTL(func, entity, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
+ if (val == ps)
+ break;
+
+ usleep_range(1000, 1500);
+ delay--;
+ }
+ if (!delay) {
+ dev_warn(&rt1320->sdw_slave->dev, "%s PDE to %s is NOT ready", __func__, ps?"PS3":"PS0");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/*
+ * The 'patch code' is written to the patch code area.
+ * The patch code area is used for SDCA register expansion flexibility.
+ */
+static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
+{
+ struct sdw_slave *slave = rt1320->sdw_slave;
+ const struct firmware *patch;
+ const char *filename;
+ unsigned int addr, val, min_addr, max_addr;
+ const unsigned char *ptr;
+ int ret, i;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ if (rt1320->version_id <= RT1320_VB)
+ filename = RT1320_VAB_MCU_PATCH;
+ else
+ filename = RT1320_VC_MCU_PATCH;
+ min_addr = 0x10007000;
+ max_addr = 0x10007fff;
+ break;
+ case RT1321_DEV_ID:
+ filename = RT1321_VA_MCU_PATCH;
+ min_addr = 0x10008000;
+ max_addr = 0x10008fff;
+ break;
+ default:
+ dev_err(&slave->dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return;
+ }
+
+ /* load the patch code here */
+ ret = request_firmware(&patch, filename, &slave->dev);
+ if (ret) {
+ dev_err(&slave->dev, "%s: Failed to load %s firmware", __func__, filename);
+ regmap_write(rt1320->regmap, 0xc598, 0x00);
+ regmap_write(rt1320->regmap, min_addr, 0x67);
+ regmap_write(rt1320->regmap, min_addr + 0x1, 0x80);
+ regmap_write(rt1320->regmap, min_addr + 0x2, 0x00);
+ regmap_write(rt1320->regmap, min_addr + 0x3, 0x00);
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_write(rt1320->regmap, 0xd73c, 0x67);
+ regmap_write(rt1320->regmap, 0xd73d, 0x80);
+ regmap_write(rt1320->regmap, 0xd73e, 0x00);
+ regmap_write(rt1320->regmap, 0xd73f, 0x00);
+ }
+ } else {
+ ptr = (const unsigned char *)patch->data;
+ if ((patch->size % 8) == 0) {
+ for (i = 0; i < patch->size; i += 8) {
+ addr = (ptr[i] & 0xff) | (ptr[i + 1] & 0xff) << 8 |
+ (ptr[i + 2] & 0xff) << 16 | (ptr[i + 3] & 0xff) << 24;
+ val = (ptr[i + 4] & 0xff) | (ptr[i + 5] & 0xff) << 8 |
+ (ptr[i + 6] & 0xff) << 16 | (ptr[i + 7] & 0xff) << 24;
+
+ if (addr > max_addr || addr < min_addr) {
+ dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr);
+ goto _exit_;
+ }
+ if (val > 0xff) {
+ dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val);
+ goto _exit_;
+ }
+ regmap_write(rt1320->regmap, addr, val);
+ }
+ }
+_exit_:
+ release_firmware(patch);
+ }
+}
+
+static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320)
+{
+ unsigned int i, reg, val, delay;
+
+ for (i = 0; i < ARRAY_SIZE(rt1320_blind_write); i++) {
+ reg = rt1320_blind_write[i].reg;
+ val = rt1320_blind_write[i].def;
+ delay = rt1320_blind_write[i].delay_us;
+
+ if (reg == 0x3fc2bfc7)
+ rt1320_load_mcu_patch(rt1320);
+
+ regmap_write(rt1320->regmap, reg, val);
+ if (delay)
+ usleep_range(delay, delay + 1000);
+ }
+}
+
+static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
+{
+ struct sdw_slave *slave = rt1320->sdw_slave;
+ unsigned int i, reg, val, delay, retry, tmp;
+
+ for (i = 0; i < ARRAY_SIZE(rt1320_vc_blind_write); i++) {
+ reg = rt1320_vc_blind_write[i].reg;
+ val = rt1320_vc_blind_write[i].def;
+ delay = rt1320_vc_blind_write[i].delay_us;
+
+ if (reg == 0x3fc2bf83)
+ rt1320_load_mcu_patch(rt1320);
+
+ if ((reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) &&
+ (val == 0x00)) {
+ retry = 200;
+ while (retry) {
+ regmap_read(rt1320->regmap, RT1320_KR0_INT_READY, &tmp);
+ dev_dbg(&slave->dev, "%s, RT1320_KR0_INT_READY=0x%x\n", __func__, tmp);
+ if (tmp == 0x1f)
+ break;
+ usleep_range(1000, 1500);
+ retry--;
+ }
+ if (!retry)
+ dev_warn(&slave->dev, "%s MCU is NOT ready!", __func__);
+ }
+ regmap_write(rt1320->regmap, reg, val);
+ if (delay)
+ usleep_range(delay, delay + 1000);
+
+ if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0))
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val);
+ }
+}
+
+static void rt1321_preset(struct rt1320_sdw_priv *rt1320)
+{
+ unsigned int i, reg, val, delay;
+
+ for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) {
+ reg = rt1321_blind_write[i].reg;
+ val = rt1321_blind_write[i].def;
+ delay = rt1321_blind_write[i].delay_us;
+
+ if (reg == 0x3fc2dfc3)
+ rt1320_load_mcu_patch(rt1320);
+
+ regmap_write(rt1320->regmap, reg, val);
+
+ if (delay)
+ usleep_range(delay, delay + 1000);
+
+ if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0))
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val);
+ }
+}
+
+static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+ unsigned int amp_func_status, val, tmp;
+
+ if (rt1320->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1320->regmap, false);
+ regcache_cache_only(rt1320->mbq_regmap, false);
+ if (rt1320->first_hw_init) {
+ regcache_cache_bypass(rt1320->regmap, true);
+ regcache_cache_bypass(rt1320->mbq_regmap, true);
+ } else {
+ /*
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
+ */
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ if (rt1320->version_id < 0) {
+ regmap_read(rt1320->regmap, RT1320_DEV_VERSION_ID_1, &val);
+ rt1320->version_id = val;
+ regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val);
+ regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp);
+ rt1320->dev_id = (val << 8) | tmp;
+ }
+
+ regmap_read(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+ dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
+
+ /* initialization write */
+ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) {
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ if (rt1320->version_id < RT1320_VC)
+ rt1320_vab_preset(rt1320);
+ else
+ rt1320_vc_preset(rt1320);
+ break;
+ case RT1321_DEV_ID:
+ rt1321_preset(rt1320);
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ }
+
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+ if (!rt1320->first_hw_init && rt1320->version_id == RT1320_VA && rt1320->dev_id == RT1320_DEV_ID) {
+ regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0);
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_0, &val);
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_1, &tmp);
+ val = (tmp << 8) | val;
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_2, &tmp);
+ val = (tmp << 16) | val;
+ regmap_read(rt1320->regmap, RT1320_HIFI_VER_3, &tmp);
+ val = (tmp << 24) | val;
+ dev_dbg(dev, "%s ROM version=0x%x\n", __func__, val);
+ /*
+ * We call the version b which has the new DSP ROM code against version a.
+ * Therefore, we read the DSP address to check the ID.
+ */
+ if (val == RT1320_VER_B_ID)
+ rt1320->version_id = RT1320_VB;
+ regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 3);
+ }
+ dev_dbg(dev, "%s version_id=%d, dev_id=0x%x\n", __func__, rt1320->version_id, rt1320->dev_id);
+
+ if (rt1320->first_hw_init) {
+ regcache_cache_bypass(rt1320->regmap, false);
+ regcache_cache_bypass(rt1320->mbq_regmap, false);
+ regcache_mark_dirty(rt1320->regmap);
+ regcache_mark_dirty(rt1320->mbq_regmap);
+ }
+
+ /* Mark Slave initialization complete */
+ rt1320->first_hw_init = true;
+ rt1320->hw_init = true;
+
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+ return 0;
+}
+
+static int rt1320_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1320->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1320->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1320_io_init(&slave->dev, slave);
+}
+
+static int rt1320_pde11_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps3);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt1320_pde23_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
+ RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps3);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt1320_set_gain_put(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;
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ unsigned int gain_l_val, gain_r_val;
+ unsigned int lvalue, rvalue;
+ const unsigned int interval_offset = 0xc0;
+ unsigned int changed = 0, reg_base;
+ struct rt_sdca_dmic_kctrl_priv *p;
+ unsigned int regvalue[4], gain_val[4], i;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU Capture Volume"))
+ goto _dmic_vol_;
+
+ regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue);
+
+ /* L Channel */
+ gain_l_val = ucontrol->value.integer.value[0];
+ if (gain_l_val > mc->max)
+ gain_l_val = mc->max;
+ gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset);
+ gain_l_val &= 0xffff;
+
+ /* R Channel */
+ gain_r_val = ucontrol->value.integer.value[1];
+ if (gain_r_val > mc->max)
+ gain_r_val = mc->max;
+ gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset);
+ gain_r_val &= 0xffff;
+
+ if (lvalue == gain_l_val && rvalue == gain_r_val)
+ return 0;
+
+ /* Lch*/
+ regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val);
+ /* Rch */
+ regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val);
+ goto _done_;
+
+_dmic_vol_:
+ p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ if (i < 2) {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue[i]);
+ } else {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i - 2, &regvalue[i]);
+ }
+ break;
+ case RT1321_DEV_ID:
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue[i]);
+ break;
+ }
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ if (i < 2) {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]);
+ } else {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]);
+ }
+ break;
+ case RT1321_DEV_ID:
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]);
+ break;
+ }
+
+ if (err < 0)
+ dev_err(&rt1320->sdw_slave->dev, "0x%08x can't be set\n", reg_base + i);
+ }
+
+_done_:
+ return 1;
+}
+
+static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
+ const unsigned int interval_offset = 0xc0;
+ unsigned int reg_base, regvalue, ctl, i;
+ struct rt_sdca_dmic_kctrl_priv *p;
+
+ if (strstr(ucontrol->id.name, "FU Capture Volume"))
+ goto _dmic_vol_;
+
+ regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
+
+ ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset);
+
+ if (read_l != read_r)
+ ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset);
+ else
+ ctl_r = ctl_l;
+
+ ucontrol->value.integer.value[0] = ctl_l;
+ ucontrol->value.integer.value[1] = ctl_r;
+ goto _done_;
+
+_dmic_vol_:
+ p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ if (i < 2) {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue);
+ } else {
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i - 2, &regvalue);
+ }
+ break;
+ case RT1321_DEV_ID:
+ reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+ regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue);
+ break;
+ }
+
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+ ucontrol->value.integer.value[i] = ctl;
+ }
+_done_:
+ return 0;
+}
+
+static int rt1320_set_fu_capture_ctl(struct rt1320_sdw_priv *rt1320)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt1320->fu_mixer_mute); i++) {
+ ch_mute = (rt1320->fu_dapm_mute || rt1320->fu_mixer_mute[i]) ? 0x01 : 0x00;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ if (i < 2)
+ err = regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113,
+ RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ else
+ err = regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14,
+ RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute);
+ break;
+ case RT1321_DEV_ID:
+ err = regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113,
+ RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ break;
+ default:
+ dev_err(&rt1320->sdw_slave->dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt1320_dmic_fu_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt1320->fu_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt1320_dmic_fu_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt1320->fu_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt1320->fu_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt1320_set_fu_capture_ctl(rt1320);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt1320_dmic_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+static int rt1320_dmic_fu_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt1320->fu_dapm_mute = false;
+ rt1320_set_fu_capture_ctl(rt1320);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt1320->fu_dapm_mute = true;
+ rt1320_set_fu_capture_ctl(rt1320);
+ break;
+ }
+ return 0;
+}
+
+static const char * const rt1320_rx_data_ch_select[] = {
+ "L,R",
+ "R,L",
+ "L,L",
+ "R,R",
+ "L,L+R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0,
+ rt1320_rx_data_ch_select);
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
+
+static const struct snd_kcontrol_new rt1320_snd_controls[] = {
+ SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02),
+ 0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv),
+ SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum),
+
+ RT_SDCA_FU_CTRL("FU Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01),
+ 1, 1, 4, rt1320_dmic_fu_info, rt1320_dmic_fu_capture_get, rt1320_dmic_fu_capture_put),
+ RT_SDCA_EXT_TLV("FU Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01),
+ rt1320_set_gain_get, rt1320_set_gain_put, 4, 0x3f, in_vol_tlv, rt1320_dmic_fu_info),
+};
+
+static const struct snd_kcontrol_new rt1320_spk_l_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01),
+ 0, 1, 1);
+static const struct snd_kcontrol_new rt1320_spk_r_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02),
+ 0, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP8-10TX", "DP8-10 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt1320_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt1320_pde11_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC("FU 113", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("FU 14", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA_E("FU", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1320_dmic_fu_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* Output */
+ SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac),
+ SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt1320_spk_r_dac),
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+
+ /* Input */
+ SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("AEC Gen"),
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+};
+
+static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
+ { "FU21", NULL, "DP1RX" },
+ { "FU21", NULL, "PDE 23" },
+ { "OT23 L", "Switch", "FU21" },
+ { "OT23 R", "Switch", "FU21" },
+ { "SPOL", NULL, "OT23 L" },
+ { "SPOR", NULL, "OT23 R" },
+
+ { "AEC Data", NULL, "AEC Gen" },
+ { "DP4TX", NULL, "AEC Data" },
+
+ {"DP8-10TX", NULL, "FU"},
+ {"FU", NULL, "PDE 11"},
+ {"FU", NULL, "FU 113"},
+ {"FU", NULL, "FU 14"},
+ {"FU 113", NULL, "DMIC1"},
+ {"FU 14", NULL, "DMIC2"},
+};
+
+static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+ return 0;
+}
+
+static void rt1320_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1320_sdw_priv *rt1320 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ struct sdw_port_config dmic_port_config[2];
+ struct sdw_stream_runtime *sdw_stream;
+ int retval;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt1320->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (dai->id == RT1320_AIF1)
+ port_config.num = 1;
+ else
+ return -EINVAL;
+ } else {
+ if (dai->id == RT1320_AIF1)
+ port_config.num = 4;
+ else if (dai->id == RT1320_AIF2) {
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ dmic_port_config[0].ch_mask = BIT(0) | BIT(1);
+ dmic_port_config[0].num = 8;
+ dmic_port_config[1].ch_mask = BIT(0) | BIT(1);
+ dmic_port_config[1].num = 10;
+ break;
+ case RT1321_DEV_ID:
+ dmic_port_config[0].ch_mask = BIT(0) | BIT(1);
+ dmic_port_config[0].num = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else
+ return -EINVAL;
+ }
+
+ if (dai->id == RT1320_AIF1)
+ retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ else if (dai->id == RT1320_AIF2) {
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+ dmic_port_config, 2, sdw_stream);
+ break;
+ case RT1321_DEV_ID:
+ retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+ dmic_port_config, 1, sdw_stream);
+ break;
+ default:
+ dev_err(dai->dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+ } else
+ return -EINVAL;
+ if (retval) {
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
+ return retval;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 16000:
+ sampling_rate = RT1320_SDCA_RATE_16000HZ;
+ break;
+ case 32000:
+ sampling_rate = RT1320_SDCA_RATE_32000HZ;
+ break;
+ case 44100:
+ sampling_rate = RT1320_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT1320_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT1320_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT1320_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ if (dai->id == RT1320_AIF1)
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ else {
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+
+ if (rt1320->dev_id == RT1320_DEV_ID)
+ regmap_write(rt1320->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ }
+
+ return 0;
+}
+
+static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1320_sdw_priv *rt1320 =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1320->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1320->sdw_slave, sdw_stream);
+ return 0;
+}
+
+/*
+ * slave_ops: callbacks for get_clock_stop_mode, clock_stop and
+ * port_prep are not defined for now
+ */
+static const struct sdw_slave_ops rt1320_slave_ops = {
+ .read_prop = rt1320_read_prop,
+ .update_status = rt1320_update_status,
+};
+
+static int rt1320_sdw_component_probe(struct snd_soc_component *component)
+{
+ int ret;
+ struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+ rt1320->component = component;
+
+ if (!rt1320->first_hw_init)
+ return 0;
+
+ ret = pm_runtime_resume(component->dev);
+ dev_dbg(&rt1320->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_sdw_rt1320 = {
+ .probe = rt1320_sdw_component_probe,
+ .controls = rt1320_snd_controls,
+ .num_controls = ARRAY_SIZE(rt1320_snd_controls),
+ .dapm_widgets = rt1320_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1320_dapm_widgets),
+ .dapm_routes = rt1320_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1320_dapm_routes),
+ .endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt1320_aif_dai_ops = {
+ .hw_params = rt1320_sdw_hw_params,
+ .hw_free = rt1320_sdw_pcm_hw_free,
+ .set_stream = rt1320_set_sdw_stream,
+ .shutdown = rt1320_sdw_shutdown,
+};
+
+#define RT1320_STEREO_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1320_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rt1320_sdw_dai[] = {
+ {
+ .name = "rt1320-aif1",
+ .id = RT1320_AIF1,
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1320_STEREO_RATES,
+ .formats = RT1320_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP4 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT1320_STEREO_RATES,
+ .formats = RT1320_FORMATS,
+ },
+ .ops = &rt1320_aif_dai_ops,
+ },
+ /* DMIC: DP8 2ch + DP10 2ch */
+ {
+ .name = "rt1320-aif2",
+ .id = RT1320_AIF2,
+ .capture = {
+ .stream_name = "DP8-10 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT1320_STEREO_RATES,
+ .formats = RT1320_FORMATS,
+ },
+ .ops = &rt1320_aif_dai_ops,
+ },
+};
+
+static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt1320_sdw_priv *rt1320;
+ int ret;
+
+ rt1320 = devm_kzalloc(dev, sizeof(*rt1320), GFP_KERNEL);
+ if (!rt1320)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1320);
+ rt1320->sdw_slave = slave;
+ rt1320->mbq_regmap = mbq_regmap;
+ rt1320->regmap = regmap;
+
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1320->hw_init = false;
+ rt1320->first_hw_init = false;
+ rt1320->version_id = -1;
+ rt1320->fu_dapm_mute = true;
+ rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] =
+ rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_component_sdw_rt1320,
+ rt1320_sdw_dai,
+ ARRAY_SIZE(rt1320_sdw_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return ret;
+}
+
+static int rt1320_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap, *mbq_regmap;
+
+ /* Regmap Initialization */
+ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt1320_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt1320_sdw_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1320_sdw_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt1320_sdw_remove(struct sdw_slave *slave)
+{
+ pm_runtime_disable(&slave->dev);
+
+ return 0;
+}
+
+/*
+ * Version A/B will use the class id 0
+ * The newer version than A/B will use the class id 1, so add it in advance
+ */
+static const struct sdw_device_id rt1320_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x0, 0),
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1320, 0x3, 0x1, 0),
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1321, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1320_id);
+
+static int rt1320_dev_suspend(struct device *dev)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
+
+ if (!rt1320->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+ return 0;
+}
+
+#define RT1320_PROBE_TIMEOUT 5000
+
+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);
+ unsigned long time;
+
+ if (!rt1320->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1320_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1320->regmap, false);
+ regcache_sync(rt1320->regmap);
+ regcache_cache_only(rt1320->mbq_regmap, false);
+ regcache_sync(rt1320->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt1320_pm = {
+ 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 = pm_ptr(&rt1320_pm),
+ },
+ .probe = rt1320_sdw_probe,
+ .remove = rt1320_sdw_remove,
+ .ops = &rt1320_slave_ops,
+ .id_table = rt1320_id,
+};
+module_sdw_driver(rt1320_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1320 driver SDCA SDW");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
new file mode 100644
index 000000000000..a6d90e259dc9
--- /dev/null
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1320-sdw.h -- RT1320 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1320_SDW_H__
+#define __RT1320_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+#define RT1320_DEV_ID 0x6981
+#define RT1321_DEV_ID 0x7045
+
+/* imp-defined registers */
+#define RT1320_DEV_VERSION_ID_1 0xc404
+#define RT1320_DEV_ID_1 0xc405
+#define RT1320_DEV_ID_0 0xc406
+
+#define RT1321_PATCH_MAIN_VER 0x1000cffe
+#define RT1321_PATCH_BETA_VER 0x1000cfff
+
+#define RT1320_KR0_STATUS_CNT 0x1000f008
+#define RT1320_KR0_INT_READY 0x1000f021
+#define RT1320_HIFI_VER_0 0x3fe2e000
+#define RT1320_HIFI_VER_1 0x3fe2e001
+#define RT1320_HIFI_VER_2 0x3fe2e002
+#define RT1320_HIFI_VER_3 0x3fe2e003
+
+/* RT1320 SDCA Control - function number */
+#define FUNC_NUM_AMP 0x04
+#define FUNC_NUM_MIC 0x02
+
+/* RT1320 SDCA entity */
+#define RT1320_SDCA_ENT0 0x00
+#define RT1320_SDCA_ENT_PDE11 0x2a
+#define RT1320_SDCA_ENT_PDE23 0x33
+#define RT1320_SDCA_ENT_PDE27 0x27
+#define RT1320_SDCA_ENT_FU14 0x32
+#define RT1320_SDCA_ENT_FU21 0x03
+#define RT1320_SDCA_ENT_FU113 0x30
+#define RT1320_SDCA_ENT_CS14 0x13
+#define RT1320_SDCA_ENT_CS21 0x21
+#define RT1320_SDCA_ENT_CS113 0x12
+#define RT1320_SDCA_ENT_SAPU 0x29
+#define RT1320_SDCA_ENT_PPU21 0x04
+
+/* RT1320 SDCA control */
+#define RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT1320_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1320_SDCA_CTL_ACTUAL_POWER_STATE 0x10
+#define RT1320_SDCA_CTL_FU_MUTE 0x01
+#define RT1320_SDCA_CTL_FU_VOLUME 0x02
+#define RT1320_SDCA_CTL_SAPU_PROTECTION_MODE 0x10
+#define RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS 0x11
+#define RT1320_SDCA_CTL_POSTURE_NUMBER 0x10
+#define RT1320_SDCA_CTL_FUNC_STATUS 0x10
+
+/* RT1320 SDCA channel */
+#define CH_01 0x01
+#define CH_02 0x02
+
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION BIT(5)
+
+/* Sample Frequency Index */
+#define RT1320_SDCA_RATE_16000HZ 0x04
+#define RT1320_SDCA_RATE_32000HZ 0x07
+#define RT1320_SDCA_RATE_44100HZ 0x08
+#define RT1320_SDCA_RATE_48000HZ 0x09
+#define RT1320_SDCA_RATE_96000HZ 0x0b
+#define RT1320_SDCA_RATE_192000HZ 0x0d
+
+enum {
+ RT1320_AIF1,
+ RT1320_AIF2,
+};
+
+/*
+ * The version id will be useful to distinguish the capability between the different IC versions.
+ * Currently, VA and VB have different DSP FW versions.
+ */
+enum rt1320_version_id {
+ RT1320_VA,
+ RT1320_VB,
+ RT1320_VC,
+};
+
+#define RT1320_VER_B_ID 0x07392238
+#define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin"
+#define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin"
+#define RT1321_VA_MCU_PATCH "realtek/rt1320/rt1321-patch-code-va.bin"
+
+struct rt1320_sdw_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct regmap *mbq_regmap;
+ struct sdw_slave *sdw_slave;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+ int version_id;
+ unsigned int dev_id;
+ bool fu_dapm_mute;
+ bool fu_mixer_mute[4];
+};
+
+#endif /* __RT1320_SDW_H__ */
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index 9a33e3776b55..5c33aeaced2f 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;
@@ -925,10 +925,11 @@ static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
static int rt274_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY ==
- snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_write(component,
RT274_SET_AUDIO_POWER, AC_PWRST_D0);
}
@@ -1091,22 +1092,22 @@ 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
static const struct i2c_device_id rt274_i2c_id[] = {
- {"rt274", 0},
+ {"rt274"},
{}
};
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
@@ -1192,7 +1193,7 @@ static int rt274_i2c_probe(struct i2c_client *i2c)
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt274", rt274);
if (ret != 0) {
dev_err(&i2c->dev,
- "Failed to reguest IRQ: %d\n", ret);
+ "Failed to request IRQ: %d\n", ret);
return ret;
}
}
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 981155b046fd..2fbb5860c421 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -223,7 +223,7 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
if (!rt286->component)
return -EINVAL;
- dapm = snd_soc_component_get_dapm(rt286->component);
+ dapm = snd_soc_component_to_dapm(rt286->component);
if (rt286->pdata.cbj_en) {
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@@ -314,7 +314,7 @@ static void rt286_jack_detect_work(struct work_struct *work)
static int rt286_mic_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
rt286->jack = jack;
@@ -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;
@@ -887,9 +887,11 @@ static int rt286_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
static int rt286_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_write(component,
RT286_SET_AUDIO_POWER, AC_PWRST_D0);
snd_soc_component_update_bits(component,
@@ -1075,16 +1077,17 @@ static const struct regmap_config rt286_regmap = {
};
static const struct i2c_device_id rt286_i2c_id[] = {
- {"rt286", 0},
- {"rt288", 0},
+ {"rt286"},
+ {"rt288"},
{}
};
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
@@ -1237,7 +1240,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c)
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286);
if (ret != 0) {
dev_err(&i2c->dev,
- "Failed to reguest IRQ: %d\n", ret);
+ "Failed to request IRQ: %d\n", ret);
return ret;
}
}
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index 8fbd25ad9b47..02247593513a 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -227,7 +227,7 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
if (!rt298->component)
return -EINVAL;
- dapm = snd_soc_component_get_dapm(rt298->component);
+ dapm = snd_soc_component_to_dapm(rt298->component);
if (rt298->pdata.cbj_en) {
regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
@@ -329,7 +329,7 @@ static void rt298_jack_detect_work(struct work_struct *work)
static int rt298_mic_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
rt298->jack = jack;
@@ -789,7 +789,6 @@ static int rt298_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- d_len_code = 0;
switch (params_width(params)) {
/* bit 6:4 Bits per Sample */
case 16:
@@ -830,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;
@@ -950,10 +949,11 @@ static int rt298_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
static int rt298_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY ==
- snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_write(component,
RT298_SET_AUDIO_POWER, AC_PWRST_D0);
snd_soc_component_update_bits(component, 0x0d, 0x200, 0x200);
@@ -1138,15 +1138,16 @@ static const struct regmap_config rt298_regmap = {
};
static const struct i2c_device_id rt298_i2c_id[] = {
- {"rt298", 0},
+ {"rt298"},
{}
};
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
@@ -1285,7 +1286,7 @@ static int rt298_i2c_probe(struct i2c_client *i2c)
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt298", rt298);
if (ret != 0) {
dev_err(&i2c->dev,
- "Failed to reguest IRQ: %d\n", ret);
+ "Failed to request IRQ: %d\n", ret);
return ret;
}
}
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 362663abcb89..54d84581ec47 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
@@ -280,7 +279,7 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
rt5514_dsp);
if (ret)
dev_err(&rt5514_spi->dev,
- "%s Failed to reguest IRQ: %d\n", __func__,
+ "%s Failed to request IRQ: %d\n", __func__,
ret);
else
device_init_wakeup(rt5514_dsp->dev, true);
@@ -459,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;
@@ -469,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;
@@ -491,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[] = {
@@ -503,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 0f9f52b93e36..649b44b790b0 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -17,7 +17,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -326,6 +325,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
const struct firmware *fw = NULL;
u8 buf[8];
@@ -333,7 +333,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled)
return 0;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
rt5514->dsp_enabled = ucontrol->value.integer.value[0];
if (rt5514->dsp_enabled) {
@@ -1051,14 +1051,12 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (IS_ERR(rt5514->mclk))
- break;
-
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(rt5514->mclk);
} else {
ret = clk_prepare_enable(rt5514->mclk);
@@ -1068,7 +1066,7 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/*
* If the DSP is enabled in start of recording, the DSP
* should be disabled, and sync back to normal recording
@@ -1095,12 +1093,11 @@ 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(component->dev, "mclk");
- if (PTR_ERR(rt5514->mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ rt5514->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(rt5514->mclk))
+ return PTR_ERR(rt5514->mclk);
if (rt5514->pdata.dsp_calib_clk_name) {
rt5514->dsp_calib_clk = devm_clk_get(&pdev->dev,
@@ -1195,7 +1192,7 @@ static const struct regmap_config rt5514_regmap = {
.reg_read = rt5514_i2c_read,
.reg_write = rt5514_i2c_write,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5514_reg,
.num_reg_defaults = ARRAY_SIZE(rt5514_reg),
.use_single_read = true,
@@ -1203,7 +1200,7 @@ static const struct regmap_config rt5514_regmap = {
};
static const struct i2c_device_id rt5514_i2c_id[] = {
- { "rt5514", 0 },
+ { "rt5514" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5514_i2c_id);
@@ -1211,15 +1208,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
@@ -1236,7 +1233,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;
@@ -1318,7 +1315,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 = {
@@ -1326,7 +1323,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 91c967391de9..fb9cf127e3ff 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;
@@ -1159,6 +1159,7 @@ static int rt5616_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1174,10 +1175,7 @@ static int rt5616_set_bias_level(struct snd_soc_component *component,
* away from ON. Disable the clock in that case, otherwise
* enable it.
*/
- if (IS_ERR(rt5616->mclk))
- break;
-
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(rt5616->mclk);
} else {
ret = clk_prepare_enable(rt5616->mclk);
@@ -1187,7 +1185,7 @@ static int rt5616_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
RT5616_PWR_VREF1 | RT5616_PWR_MB |
RT5616_PWR_BG | RT5616_PWR_VREF2,
@@ -1225,9 +1223,9 @@ static int rt5616_probe(struct snd_soc_component *component)
struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
/* Check if MCLK provided */
- rt5616->mclk = devm_clk_get(component->dev, "mclk");
- if (PTR_ERR(rt5616->mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ rt5616->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(rt5616->mclk))
+ return PTR_ERR(rt5616->mclk);
rt5616->component = component;
@@ -1315,7 +1313,7 @@ static const struct regmap_config rt5616_regmap = {
RT5616_PR_SPACING),
.volatile_reg = rt5616_volatile_register,
.readable_reg = rt5616_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5616_reg,
.num_reg_defaults = ARRAY_SIZE(rt5616_reg),
.ranges = rt5616_ranges,
@@ -1323,7 +1321,7 @@ static const struct regmap_config rt5616_regmap = {
};
static const struct i2c_device_id rt5616_i2c_id[] = {
- { "rt5616", 0 },
+ { "rt5616" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id);
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 9a4cb45e37d4..19c6d8f760d9 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -183,7 +183,7 @@ static const DECLARE_TLV_DB_RANGE(mic_bst_tlv,
static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rt5631->dmic_used_flag;
@@ -194,7 +194,7 @@ static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
rt5631->dmic_used_flag = ucontrol->value.integer.value[0];
@@ -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;
@@ -1535,6 +1535,7 @@ static int rt5631_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1545,7 +1546,7 @@ static int rt5631_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
@@ -1575,6 +1576,7 @@ static int rt5631_set_bias_level(struct snd_soc_component *component,
static int rt5631_probe(struct snd_soc_component *component)
{
struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int val;
val = rt5631_read_index(component, RT5631_ADDA_MIXER_INTL_REG3);
@@ -1613,7 +1615,7 @@ static int rt5631_probe(struct snd_soc_component *component)
RT5631_DMIC_R_CH_LATCH_RISING);
}
- snd_soc_component_init_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_init_bias_level(dapm, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -1669,8 +1671,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5631 = {
};
static const struct i2c_device_id rt5631_i2c_id[] = {
- { "rt5631", 0 },
- { "alc5631", 0 },
+ { "rt5631" },
+ { "alc5631" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
@@ -1693,7 +1695,7 @@ static const struct regmap_config rt5631_regmap_config = {
.max_register = RT5631_VENDOR_ID2,
.reg_defaults = rt5631_reg,
.num_reg_defaults = ARRAY_SIZE(rt5631_reg),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index c7d2f315273e..4c08c274f50e 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -12,11 +12,10 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
@@ -53,7 +52,6 @@ static const struct reg_sequence init_list[] = {
{RT5640_PR_BASE + 0x3d, 0x3600},
{RT5640_PR_BASE + 0x12, 0x0aa8},
{RT5640_PR_BASE + 0x14, 0x0aaa},
- {RT5640_PR_BASE + 0x20, 0x6110},
{RT5640_PR_BASE + 0x21, 0xe0e0},
{RT5640_PR_BASE + 0x23, 0x1804},
};
@@ -195,7 +193,7 @@ static bool rt5640_volatile_register(struct device *dev, unsigned int reg)
case RT5640_PRIV_DATA:
case RT5640_PGM_REG_ARR1:
case RT5640_PGM_REG_ARR3:
- case RT5640_DUMMY2:
+ case RT5640_GCTL2:
case RT5640_VENDOR_ID:
case RT5640_VENDOR_ID1:
case RT5640_VENDOR_ID2:
@@ -327,8 +325,8 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg)
case RT5640_HP_CALIB2:
case RT5640_SV_ZCD1:
case RT5640_SV_ZCD2:
- case RT5640_DUMMY1:
- case RT5640_DUMMY2:
+ case RT5640_GCTL1:
+ case RT5640_GCTL2:
case RT5640_DUMMY3:
case RT5640_VENDOR_ID:
case RT5640_VENDOR_ID1:
@@ -425,7 +423,7 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
127, 0, adc_vol_tlv),
- SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1,
+ SOC_DOUBLE("Mono ADC Capture Switch", RT5640_GCTL1,
RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1),
SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
@@ -1775,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;
@@ -1937,6 +1935,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1951,10 +1950,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
* away from ON. Disable the clock in that case, otherwise
* enable it.
*/
- if (IS_ERR(rt5640->mclk))
- break;
-
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(rt5640->mclk);
} else {
ret = clk_prepare_enable(rt5640->mclk);
@@ -1964,7 +1960,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_OFF == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2,
@@ -1974,7 +1970,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
RT5640_PWR_FV1 | RT5640_PWR_FV2,
RT5640_PWR_FV1 | RT5640_PWR_FV2);
- snd_soc_component_update_bits(component, RT5640_DUMMY1,
+ snd_soc_component_update_bits(component, RT5640_GCTL1,
0x1, 0x1);
snd_soc_component_update_bits(component, RT5640_MICBIAS,
0x0030, 0x0030);
@@ -1984,7 +1980,7 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_OFF:
snd_soc_component_write(component, RT5640_DEPOP_M1, 0x0004);
snd_soc_component_write(component, RT5640_DEPOP_M2, 0x1100);
- snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x1, 0);
+ snd_soc_component_update_bits(component, RT5640_GCTL1, 0x1, 0);
snd_soc_component_write(component, RT5640_PWR_DIG1, 0x0000);
snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000);
snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000);
@@ -2103,7 +2099,7 @@ EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
snd_soc_dapm_mutex_lock(dapm);
@@ -2119,7 +2115,7 @@ EXPORT_SYMBOL_GPL(rt5640_enable_micbias1_for_ovcd);
void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
snd_soc_dapm_mutex_lock(dapm);
@@ -2333,12 +2329,12 @@ static void rt5640_jack_work(struct work_struct *work)
jack_type |= SND_JACK_MICROPHONE;
/* headphone jack */
- val = snd_soc_component_read(component, RT5640_DUMMY2);
+ val = snd_soc_component_read(component, RT5640_GCTL2);
hda_hp_plugged = !(val & (0x1 << 11));
dev_dbg(component->dev, "headphone jack status %d\n",
hda_hp_plugged);
- snd_soc_component_update_bits(component, RT5640_DUMMY2,
+ snd_soc_component_update_bits(component, RT5640_GCTL2,
(0x1 << 10), !hda_hp_plugged << 10);
if (hda_hp_plugged)
@@ -2405,13 +2401,11 @@ static irqreturn_t rt5640_irq(int irq, void *data)
struct rt5640_priv *rt5640 = data;
int delay = 0;
- if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
- cancel_delayed_work_sync(&rt5640->jack_work);
+ if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
delay = 100;
- }
if (rt5640->jack)
- queue_delayed_work(system_long_wq, &rt5640->jack_work, delay);
+ mod_delayed_work(system_long_wq, &rt5640->jack_work, delay);
return IRQ_HANDLED;
}
@@ -2426,10 +2420,20 @@ static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void rt5640_cancel_work(void *data)
+static void rt5640_disable_irq_and_cancel_work(void *data)
{
struct rt5640_priv *rt5640 = data;
+ if (rt5640->jd_gpio_irq_requested) {
+ free_irq(rt5640->jd_gpio_irq, rt5640);
+ rt5640->jd_gpio_irq_requested = false;
+ }
+
+ if (rt5640->irq_requested) {
+ free_irq(rt5640->irq, rt5640);
+ rt5640->irq_requested = false;
+ }
+
cancel_delayed_work_sync(&rt5640->jack_work);
cancel_delayed_work_sync(&rt5640->bp_work);
}
@@ -2470,13 +2474,7 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
if (!rt5640->jack)
return;
- if (rt5640->jd_gpio_irq_requested)
- free_irq(rt5640->jd_gpio_irq, rt5640);
-
- if (rt5640->irq_requested)
- free_irq(rt5640->irq, rt5640);
-
- rt5640_cancel_work(rt5640);
+ rt5640_disable_irq_and_cancel_work(rt5640);
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
rt5640_disable_micbias1_ovcd_irq(component);
@@ -2484,8 +2482,6 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
- rt5640->jd_gpio_irq_requested = false;
- rt5640->irq_requested = false;
rt5640->jd_gpio = NULL;
rt5640->jack = NULL;
}
@@ -2509,7 +2505,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3,
RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT);
- snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41);
+ snd_soc_component_write(component, RT5640_GCTL1, 0x3f41);
rt5640_set_ovcd_params(component);
@@ -2524,7 +2520,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
snd_soc_component_write(component, RT5640_IRQ_CTRL1,
RT5640_IRQ_JD_NOR);
else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N)
- snd_soc_component_update_bits(component, RT5640_DUMMY2,
+ snd_soc_component_update_bits(component, RT5640_GCTL2,
RT5640_IRQ_JD2_MASK | RT5640_JD2_MASK,
RT5640_IRQ_JD2_NOR | RT5640_JD2_EN);
} else {
@@ -2532,7 +2528,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
snd_soc_component_write(component, RT5640_IRQ_CTRL1,
RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
else if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N)
- snd_soc_component_update_bits(component, RT5640_DUMMY2,
+ snd_soc_component_update_bits(component, RT5640_GCTL2,
RT5640_IRQ_JD2_MASK | RT5640_JD2_P_MASK |
RT5640_JD2_MASK,
RT5640_IRQ_JD2_NOR | RT5640_JD2_P_INV |
@@ -2571,7 +2567,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"rt5640", rt5640);
if (ret) {
- dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
+ dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
rt5640_disable_jack_detect(component);
return;
}
@@ -2591,8 +2587,7 @@ static void rt5640_enable_hda_jack_detect(
struct snd_soc_component *component, struct snd_soc_jack *jack)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
/* Select JD1 for Mic */
@@ -2601,7 +2596,7 @@ static void rt5640_enable_hda_jack_detect(
snd_soc_component_write(component, RT5640_IRQ_CTRL1, RT5640_IRQ_JD_NOR);
/* Select JD2 for Headphone */
- snd_soc_component_update_bits(component, RT5640_DUMMY2, 0x1100, 0x1100);
+ snd_soc_component_update_bits(component, RT5640_GCTL2, 0x1100, 0x1100);
/* Selecting GPIO01 as an interrupt */
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1,
@@ -2611,7 +2606,7 @@ static void rt5640_enable_hda_jack_detect(
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3,
RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT);
- snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0);
+ snd_soc_component_update_bits(component, RT5640_GCTL1, 0x400, 0x0);
snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
RT5640_PWR_VREF2 | RT5640_PWR_MB | RT5640_PWR_BG,
@@ -2625,10 +2620,11 @@ static void rt5640_enable_hda_jack_detect(
ret = request_irq(rt5640->irq, rt5640_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5640", rt5640);
if (ret) {
- dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
- rt5640->irq = -ENXIO;
+ dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
+ rt5640->jack = NULL;
return;
}
+ rt5640->irq_requested = true;
/* sync initial jack state */
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
@@ -2656,7 +2652,7 @@ static int rt5640_set_jack(struct snd_soc_component *component,
static int rt5640_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
u32 dmic1_data_pin = 0;
u32 dmic2_data_pin = 0;
@@ -2664,15 +2660,15 @@ static int rt5640_probe(struct snd_soc_component *component)
u32 val;
/* Check if MCLK provided */
- rt5640->mclk = devm_clk_get(component->dev, "mclk");
- if (PTR_ERR(rt5640->mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ rt5640->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(rt5640->mclk))
+ return PTR_ERR(rt5640->mclk);
rt5640->component = component;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
- snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x0301, 0x0301);
+ snd_soc_component_update_bits(component, RT5640_GCTL1, 0x0301, 0x0301);
snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030);
snd_soc_component_update_bits(component, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
@@ -2723,7 +2719,7 @@ static int rt5640_probe(struct snd_soc_component *component)
RT5640_IN_DF2, RT5640_IN_DF2);
if (device_property_read_bool(component->dev, "realtek,lout-differential"))
- snd_soc_component_update_bits(component, RT5640_DUMMY1,
+ snd_soc_component_update_bits(component, RT5640_GCTL1,
RT5640_EN_LOUT_DF, RT5640_EN_LOUT_DF);
if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin",
@@ -2800,19 +2796,21 @@ static void rt5640_remove(struct snd_soc_component *component)
static int rt5640_suspend(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- if (rt5640->irq) {
+ if (rt5640->jack) {
/* disable jack interrupts during system suspend */
disable_irq(rt5640->irq);
+ cancel_delayed_work_sync(&rt5640->jack_work);
+ cancel_delayed_work_sync(&rt5640->bp_work);
}
- rt5640_cancel_work(rt5640);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
rt5640_reset(component);
regcache_cache_only(rt5640->regmap, true);
regcache_mark_dirty(rt5640->regmap);
- if (gpio_is_valid(rt5640->ldo1_en))
- gpio_set_value_cansleep(rt5640->ldo1_en, 0);
+ if (rt5640->ldo1_en)
+ gpiod_set_value_cansleep(rt5640->ldo1_en, 0);
return 0;
}
@@ -2821,26 +2819,23 @@ static int rt5640_resume(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(rt5640->ldo1_en)) {
- gpio_set_value_cansleep(rt5640->ldo1_en, 1);
+ if (rt5640->ldo1_en) {
+ gpiod_set_value_cansleep(rt5640->ldo1_en, 1);
msleep(400);
}
regcache_cache_only(rt5640->regmap, false);
regcache_sync(rt5640->regmap);
- if (rt5640->irq)
- enable_irq(rt5640->irq);
-
if (rt5640->jack) {
if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
snd_soc_component_update_bits(component,
- RT5640_DUMMY2, 0x1100, 0x1100);
+ RT5640_GCTL2, 0x1100, 0x1100);
} else {
if (rt5640->jd_inverted) {
if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N)
snd_soc_component_update_bits(
- component, RT5640_DUMMY2,
+ component, RT5640_GCTL2,
RT5640_IRQ_JD2_MASK |
RT5640_JD2_MASK,
RT5640_IRQ_JD2_NOR |
@@ -2849,7 +2844,7 @@ static int rt5640_resume(struct snd_soc_component *component)
} else {
if (rt5640->jd_src == RT5640_JD_SRC_JD2_IN4N)
snd_soc_component_update_bits(
- component, RT5640_DUMMY2,
+ component, RT5640_GCTL2,
RT5640_IRQ_JD2_MASK |
RT5640_JD2_P_MASK |
RT5640_JD2_MASK,
@@ -2859,6 +2854,7 @@ static int rt5640_resume(struct snd_soc_component *component)
}
}
+ enable_irq(rt5640->irq);
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
}
@@ -2949,7 +2945,7 @@ static const struct regmap_config rt5640_regmap = {
.volatile_reg = rt5640_volatile_register,
.readable_reg = rt5640_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5640_reg,
.num_reg_defaults = ARRAY_SIZE(rt5640_reg),
.ranges = rt5640_ranges,
@@ -2957,9 +2953,9 @@ static const struct regmap_config rt5640_regmap = {
};
static const struct i2c_device_id rt5640_i2c_id[] = {
- { "rt5640", 0 },
- { "rt5639", 0 },
- { "rt5642", 0 },
+ { "rt5640" },
+ { "rt5639" },
+ { "rt5642" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
@@ -2968,39 +2964,23 @@ 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
-static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
-{
- rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
- /*
- * LDO1_EN is optional (it may be statically tied on the board).
- * -ENOENT means that the property doesn't exist, i.e. there is no
- * GPIO, so is not an error. Any other error code means the property
- * exists, but could not be parsed.
- */
- if (!gpio_is_valid(rt5640->ldo1_en) &&
- (rt5640->ldo1_en != -ENOENT))
- return rt5640->ldo1_en;
-
- return 0;
-}
-
static int rt5640_i2c_probe(struct i2c_client *i2c)
{
struct rt5640_priv *rt5640;
@@ -3014,12 +2994,16 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
return -ENOMEM;
i2c_set_clientdata(i2c, rt5640);
- if (i2c->dev.of_node) {
- ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
- if (ret)
- return ret;
- } else
- rt5640->ldo1_en = -EINVAL;
+ rt5640->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5640->ldo1_en))
+ return PTR_ERR(rt5640->ldo1_en);
+
+ if (rt5640->ldo1_en) {
+ gpiod_set_consumer_name(rt5640->ldo1_en, "RT5640 LDO1_EN");
+ msleep(400);
+ }
rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
if (IS_ERR(rt5640->regmap)) {
@@ -3029,19 +3013,12 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5640->ldo1_en)) {
- ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
- GPIOF_OUT_INIT_HIGH,
- "RT5640 LDO1_EN");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
- rt5640->ldo1_en, ret);
- return ret;
- }
- msleep(400);
+ regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
+ if (val != RT5640_DEVICE_ID) {
+ usleep_range(60000, 100000);
+ regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
}
- regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
if (val != RT5640_DEVICE_ID) {
dev_err(&i2c->dev,
"Device with ID register %#x is not rt5640/39\n", val);
@@ -3055,7 +3032,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
- regmap_update_bits(rt5640->regmap, RT5640_DUMMY1,
+ regmap_update_bits(rt5640->regmap, RT5640_GCTL1,
RT5640_MCLK_DET, RT5640_MCLK_DET);
rt5640->hp_mute = true;
@@ -3064,7 +3041,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work);
/* Make sure work is stopped on probe-error / remove */
- ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
+ ret = devm_add_action_or_reset(&i2c->dev, rt5640_disable_irq_and_cancel_work, rt5640);
if (ret)
return ret;
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 9847a1ae01f4..8a12cee76bdc 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -139,8 +139,8 @@
#define RT5640_SV_ZCD1 0xd9
#define RT5640_SV_ZCD2 0xda
/* Dummy Register */
-#define RT5640_DUMMY1 0xfa
-#define RT5640_DUMMY2 0xfb
+#define RT5640_GCTL1 0xfa
+#define RT5640_GCTL2 0xfb
#define RT5640_DUMMY3 0xfc
@@ -1986,7 +1986,7 @@
#define RT5640_M_MONO_ADC_R_SFT 12
#define RT5640_MCLK_DET (0x1 << 11)
-/* General Control 1 (0xfb) */
+/* General Control 2 (0xfb) */
#define RT5640_IRQ_JD2_MASK (0x1 << 12)
#define RT5640_IRQ_JD2_SFT 12
#define RT5640_IRQ_JD2_BP (0x0 << 12)
@@ -2138,7 +2138,7 @@ struct rt5640_priv {
struct regmap *regmap;
struct clk *mclk;
- int ldo1_en; /* GPIO for LDO1_EN */
+ struct gpio_desc *ldo1_en; /* GPIO for LDO1_EN */
int irq;
int jd_gpio_irq;
int sysclk;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 01aa999fc6db..f7701b8d0d3c 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -14,7 +14,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
@@ -81,6 +80,9 @@ static const struct reg_sequence init_list[] = {
static const struct reg_sequence rt5650_init_list[] = {
{0xf6, 0x0100},
+ {RT5645_PWR_ANLG1, 0x02},
+ {RT5645_IL_CMD3, 0x6728},
+ {RT5645_PR_BASE + 0x3a, 0x0000},
};
static const struct reg_default rt5645_reg[] = {
@@ -428,6 +430,9 @@ struct rt5645_platform_data {
/* Invert HP detect status polarity */
bool inv_hp_pol;
+ /* Only 1 speaker connected */
+ bool mono_speaker;
+
/* Value to assign to snd_soc_card.long_name */
const char *long_name;
@@ -441,6 +446,7 @@ struct rt5645_priv {
struct regmap *regmap;
struct i2c_client *i2c;
struct gpio_desc *gpiod_hp_det;
+ struct gpio_desc *gpiod_cbj_sleeve;
struct snd_soc_jack *hp_jack;
struct snd_soc_jack *mic_jack;
struct snd_soc_jack *btn_jack;
@@ -448,6 +454,7 @@ struct rt5645_priv {
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
struct rt5645_eq_param_s *eq_param;
struct timer_list btn_check_timer;
+ struct mutex jd_mutex;
int codec_type;
int sysclk;
@@ -1697,6 +1704,9 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
regmap_write(rt5645->regmap, RT5645_PR_BASE +
RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
+ snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R);
msleep(90);
} else {
/* depop parameters */
@@ -1744,7 +1754,8 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
msleep(100);
snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001);
-
+ snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R, 0);
} else {
snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
RT5645_HP_SG_MASK |
@@ -2831,10 +2842,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;
@@ -3060,10 +3071,11 @@ static int rt5645_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2,
@@ -3088,7 +3100,7 @@ static int rt5645_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
RT5645_PWR_FV1 | RT5645_PWR_FV2,
RT5645_PWR_FV1 | RT5645_PWR_FV2);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
msleep(40);
if (rt5645->en_button_func)
@@ -3119,21 +3131,33 @@ static int rt5645_set_bias_level(struct snd_soc_component *component,
static void rt5645_enable_push_button_irq(struct snd_soc_component *component,
bool enable)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ int ret;
if (enable) {
snd_soc_dapm_force_enable_pin(dapm, "ADC L power");
snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
snd_soc_dapm_sync(dapm);
+ snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD2,
+ RT5645_EN_4BTN_IL_MASK | RT5645_RST_4BTN_IL_MASK,
+ RT5645_EN_4BTN_IL_EN | RT5645_RST_4BTN_IL_RST);
+ usleep_range(10000, 15000);
+ snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD2,
+ RT5645_EN_4BTN_IL_MASK | RT5645_RST_4BTN_IL_MASK,
+ RT5645_EN_4BTN_IL_EN | RT5645_RST_4BTN_IL_NORM);
+ msleep(50);
+ ret = snd_soc_component_read(component, RT5645_INT_IRQ_ST);
+ pr_debug("%s read %x = %x\n", __func__, RT5645_INT_IRQ_ST,
+ snd_soc_component_read(component, RT5645_INT_IRQ_ST));
+ snd_soc_component_write(component, RT5645_INT_IRQ_ST, ret);
+ ret = snd_soc_component_read(component, RT5650_4BTN_IL_CMD1);
+ pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
+ snd_soc_component_read(component, RT5650_4BTN_IL_CMD1));
+ snd_soc_component_write(component, RT5650_4BTN_IL_CMD1, ret);
snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
snd_soc_component_update_bits(component,
RT5645_INT_IRQ_ST, 0x8, 0x8);
- snd_soc_component_update_bits(component,
- RT5650_4BTN_IL_CMD2, 0x8000, 0x8000);
- snd_soc_component_read(component, RT5650_4BTN_IL_CMD1);
- pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
- snd_soc_component_read(component, RT5650_4BTN_IL_CMD1));
} else {
snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
snd_soc_component_update_bits(component, RT5645_INT_IRQ_ST, 0x8, 0x0);
@@ -3146,18 +3170,18 @@ static void rt5645_enable_push_button_irq(struct snd_soc_component *component,
static int rt5645_jack_detect(struct snd_soc_component *component, int jack_insert)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
unsigned int val;
if (jack_insert) {
- regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0206);
/* for jack type detect */
snd_soc_dapm_force_enable_pin(dapm, "LDO2");
snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm);
- if (!snd_soc_card_is_instantiated(dapm->card)) {
+ if (!snd_soc_card_is_instantiated(component->card)) {
/* Power up necessary bits for JD if dapm is
not ready yet */
regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1,
@@ -3178,6 +3202,9 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
RT5645_CBJ_MN_JD, 0);
+ if (rt5645->gpiod_cbj_sleeve)
+ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 1);
+
msleep(600);
regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
val &= 0x7;
@@ -3189,13 +3216,19 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
rt5645_enable_push_button_irq(component, true);
}
} else {
+ if (rt5645->en_button_func)
+ rt5645_enable_push_button_irq(component, false);
snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm);
rt5645->jack_type = SND_JACK_HEADPHONE;
+ if (rt5645->gpiod_cbj_sleeve)
+ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
}
if (rt5645->pdata.level_trigger_irq)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
} else { /* jack out */
rt5645->jack_type = 0;
@@ -3217,6 +3250,9 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
if (rt5645->pdata.level_trigger_irq)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+
+ if (rt5645->gpiod_cbj_sleeve)
+ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
}
return rt5645->jack_type;
@@ -3251,6 +3287,8 @@ int rt5645_set_jack_detect(struct snd_soc_component *component,
RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1,
RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+ regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1,
+ RT5645_HP_CB_MASK, RT5645_HP_CB_PU);
}
rt5645_irq(0, rt5645);
@@ -3258,6 +3296,26 @@ int rt5645_set_jack_detect(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+static int rt5645_component_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct snd_soc_jack *mic_jack = NULL;
+ struct snd_soc_jack *btn_jack = NULL;
+ int type;
+
+ if (hs_jack) {
+ type = *(int *)data;
+
+ if (type & SND_JACK_MICROPHONE)
+ mic_jack = hs_jack;
+ if (type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3))
+ btn_jack = hs_jack;
+ }
+
+ return rt5645_set_jack_detect(component, hs_jack, mic_jack, btn_jack);
+}
+
static void rt5645_jack_detect_work(struct work_struct *work)
{
struct rt5645_priv *rt5645 =
@@ -3267,6 +3325,8 @@ static void rt5645_jack_detect_work(struct work_struct *work)
if (!rt5645->component)
return;
+ mutex_lock(&rt5645->jd_mutex);
+
switch (rt5645->pdata.jd_mode) {
case 0: /* Not using rt5645 JD */
if (rt5645->gpiod_hp_det) {
@@ -3281,6 +3341,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack,
report, SND_JACK_MICROPHONE);
+ mutex_unlock(&rt5645->jd_mutex);
return;
case 4:
val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
@@ -3293,7 +3354,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
if (!val && (rt5645->jack_type == 0)) { /* jack in */
report = rt5645_jack_detect(rt5645->component, 1);
- } else if (!val && rt5645->jack_type != 0) {
+ } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) {
/* for push button and jack out */
btn_type = 0;
if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
@@ -3349,6 +3410,8 @@ static void rt5645_jack_detect_work(struct work_struct *work)
rt5645_jack_detect(rt5645->component, 0);
}
+ mutex_unlock(&rt5645->jd_mutex);
+
snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
if (rt5645->en_button_func)
@@ -3378,7 +3441,8 @@ static irqreturn_t rt5645_irq(int irq, void *data)
static void rt5645_btn_check_callback(struct timer_list *t)
{
- struct rt5645_priv *rt5645 = from_timer(rt5645, t, btn_check_timer);
+ struct rt5645_priv *rt5645 = timer_container_of(rt5645, t,
+ btn_check_timer);
queue_delayed_work(system_power_efficient_wq,
&rt5645->jack_detect_work, msecs_to_jiffies(5));
@@ -3386,7 +3450,7 @@ static void rt5645_btn_check_callback(struct timer_list *t)
static int rt5645_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
rt5645->component = component;
@@ -3415,7 +3479,7 @@ static int rt5645_probe(struct snd_soc_component *component)
break;
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
/* for JD function */
if (rt5645->pdata.jd_mode) {
@@ -3532,6 +3596,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = {
.num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets),
.dapm_routes = rt5645_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes),
+ .set_jack = rt5645_component_set_jack,
.use_pmdown_time = 1,
.endianness = 1,
};
@@ -3546,7 +3611,7 @@ static const struct regmap_config rt5645_regmap = {
.volatile_reg = rt5645_volatile_register,
.readable_reg = rt5645_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5645_reg,
.num_reg_defaults = ARRAY_SIZE(rt5645_reg),
.ranges = rt5645_ranges,
@@ -3563,7 +3628,7 @@ static const struct regmap_config rt5650_regmap = {
.volatile_reg = rt5645_volatile_register,
.readable_reg = rt5645_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5650_reg,
.num_reg_defaults = ARRAY_SIZE(rt5650_reg),
.ranges = rt5645_ranges,
@@ -3581,8 +3646,8 @@ static const struct regmap_config temp_regmap = {
};
static const struct i2c_device_id rt5645_i2c_id[] = {
- { "rt5645", 0 },
- { "rt5650", 0 },
+ { "rt5645" },
+ { "rt5650" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
@@ -3598,12 +3663,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
@@ -3624,6 +3689,7 @@ static const struct rt5645_platform_data buddy_platform_data = {
static const struct rt5645_platform_data gpd_win_platform_data = {
.jd_mode = 3,
.inv_jd1_1 = true,
+ .mono_speaker = true,
.long_name = "gpd-win-pocket-rt5645",
/* The GPD pocket has a diff. mic, for the win this does not matter. */
.in2_diff = true,
@@ -3647,6 +3713,16 @@ static const struct rt5645_platform_data lenovo_ideapad_miix_310_pdata = {
.in2_diff = true,
};
+static const struct rt5645_platform_data jd_mode3_monospk_platform_data = {
+ .jd_mode = 3,
+ .mono_speaker = true,
+};
+
+static const struct rt5645_platform_data jd_mode3_inv_data = {
+ .jd_mode = 3,
+ .inv_jd1_1 = true,
+};
+
static const struct rt5645_platform_data jd_mode3_platform_data = {
.jd_mode = 3,
};
@@ -3766,7 +3842,7 @@ static const struct dmi_system_id dmi_platform_data[] = {
DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
DMI_MATCH(DMI_PRODUCT_NAME, "X80 Pro"),
},
- .driver_data = (void *)&jd_mode3_platform_data,
+ .driver_data = (void *)&jd_mode3_monospk_platform_data,
},
{
.ident = "Lenovo Ideapad Miix 310",
@@ -3792,6 +3868,16 @@ static const struct dmi_system_id dmi_platform_data[] = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
DMI_EXACT_MATCH(DMI_BOARD_VERSION, "Default string"),
+ /*
+ * Above strings are too generic, LattePanda BIOS versions for
+ * all 4 hw revisions are:
+ * DF-BI-7-S70CR100-*
+ * DF-BI-7-S70CR110-*
+ * DF-BI-7-S70CR200-*
+ * LP-BS-7-S70CR700-*
+ * Do a partial match for S70CR to avoid false positive matches.
+ */
+ DMI_MATCH(DMI_BIOS_VERSION, "S70CR"),
},
.driver_data = (void *)&lattepanda_board_platform_data,
},
@@ -3819,12 +3905,22 @@ static const struct dmi_system_id dmi_platform_data[] = {
.driver_data = (void *)&ecs_ef20_platform_data,
},
{
- .ident = "EF20EA",
- .callback = cht_rt5645_ef20_quirk_cb,
+ .ident = "Acer Switch V 10 (SW5-017)",
.matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
},
- .driver_data = (void *)&ecs_ef20_platform_data,
+ .driver_data = (void *)&intel_braswell_platform_data,
+ },
+ {
+ .ident = "Meegopad T08",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
+ DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
+ },
+ .driver_data = (void *)&jd_mode3_inv_data,
},
{ }
};
@@ -3840,24 +3936,68 @@ static bool rt5645_check_dp(struct device *dev)
return false;
}
-static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
+static void rt5645_parse_dt(struct device *dev, struct rt5645_platform_data *pdata)
{
- rt5645->pdata.in2_diff = device_property_read_bool(dev,
- "realtek,in2-differential");
- device_property_read_u32(dev,
- "realtek,dmic1-data-pin", &rt5645->pdata.dmic1_data_pin);
- device_property_read_u32(dev,
- "realtek,dmic2-data-pin", &rt5645->pdata.dmic2_data_pin);
- device_property_read_u32(dev,
- "realtek,jd-mode", &rt5645->pdata.jd_mode);
+ pdata->in2_diff = device_property_read_bool(dev, "realtek,in2-differential");
+ device_property_read_u32(dev, "realtek,dmic1-data-pin", &pdata->dmic1_data_pin);
+ device_property_read_u32(dev, "realtek,dmic2-data-pin", &pdata->dmic2_data_pin);
+ device_property_read_u32(dev, "realtek,jd-mode", &pdata->jd_mode);
+}
- return 0;
+static void rt5645_get_pdata(struct device *codec_dev, struct rt5645_platform_data *pdata)
+{
+ const struct dmi_system_id *dmi_data;
+
+ dmi_data = dmi_first_match(dmi_platform_data);
+ if (dmi_data) {
+ dev_info(codec_dev, "Detected %s platform\n", dmi_data->ident);
+ *pdata = *((struct rt5645_platform_data *)dmi_data->driver_data);
+ } else if (rt5645_check_dp(codec_dev)) {
+ rt5645_parse_dt(codec_dev, pdata);
+ } else {
+ *pdata = jd_mode3_platform_data;
+ }
+
+ if (quirk != -1) {
+ pdata->in2_diff = QUIRK_IN2_DIFF(quirk);
+ pdata->level_trigger_irq = QUIRK_LEVEL_IRQ(quirk);
+ pdata->inv_jd1_1 = QUIRK_INV_JD1_1(quirk);
+ pdata->inv_hp_pol = QUIRK_INV_HP_POL(quirk);
+ pdata->jd_mode = QUIRK_JD_MODE(quirk);
+ pdata->dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk);
+ pdata->dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
+ }
}
+const char *rt5645_components(struct device *codec_dev)
+{
+ struct rt5645_platform_data pdata = { };
+ static char buf[32];
+ const char *mic;
+ int spk = 2;
+
+ rt5645_get_pdata(codec_dev, &pdata);
+
+ if (pdata.mono_speaker)
+ spk = 1;
+
+ if (pdata.dmic1_data_pin && pdata.dmic2_data_pin)
+ mic = "dmics12";
+ else if (pdata.dmic1_data_pin)
+ mic = "dmic1";
+ else if (pdata.dmic2_data_pin)
+ mic = "dmic2";
+ else
+ mic = "in2";
+
+ snprintf(buf, sizeof(buf), "cfg-spk:%d cfg-mic:%s", spk, mic);
+
+ return buf;
+}
+EXPORT_SYMBOL_GPL(rt5645_components);
+
static int rt5645_i2c_probe(struct i2c_client *i2c)
{
- struct rt5645_platform_data *pdata = NULL;
- const struct dmi_system_id *dmi_data;
struct rt5645_priv *rt5645;
int ret, i;
unsigned int val;
@@ -3870,29 +4010,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
rt5645->i2c = i2c;
i2c_set_clientdata(i2c, rt5645);
-
- dmi_data = dmi_first_match(dmi_platform_data);
- if (dmi_data) {
- dev_info(&i2c->dev, "Detected %s platform\n", dmi_data->ident);
- pdata = dmi_data->driver_data;
- }
-
- if (pdata)
- rt5645->pdata = *pdata;
- else if (rt5645_check_dp(&i2c->dev))
- rt5645_parse_dt(rt5645, &i2c->dev);
- else
- rt5645->pdata = jd_mode3_platform_data;
-
- if (quirk != -1) {
- rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
- rt5645->pdata.level_trigger_irq = QUIRK_LEVEL_IRQ(quirk);
- rt5645->pdata.inv_jd1_1 = QUIRK_INV_JD1_1(quirk);
- rt5645->pdata.inv_hp_pol = QUIRK_INV_HP_POL(quirk);
- rt5645->pdata.jd_mode = QUIRK_JD_MODE(quirk);
- rt5645->pdata.dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk);
- rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
- }
+ rt5645_get_pdata(&i2c->dev, &rt5645->pdata);
if (has_acpi_companion(&i2c->dev)) {
if (cht_rt5645_gpios) {
@@ -3919,6 +4037,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ rt5645->gpiod_cbj_sleeve = devm_gpiod_get_optional(&i2c->dev, "cbj-sleeve",
+ GPIOD_OUT_LOW);
+
+ if (IS_ERR(rt5645->gpiod_cbj_sleeve)) {
+ ret = PTR_ERR(rt5645->gpiod_cbj_sleeve);
+ dev_info(&i2c->dev, "failed to initialize gpiod, ret=%d\n", ret);
+ if (ret != -ENOENT)
+ return ret;
+ }
+
for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
rt5645->supplies[i].supply = rt5645_supply_names[i];
@@ -3950,7 +4078,11 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
* read and power On.
*/
msleep(TIME_TO_POWER_MS);
- regmap_read(regmap, RT5645_VENDOR_ID2, &val);
+ ret = regmap_read(regmap, RT5645_VENDOR_ID2, &val);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to read: 0x%02X\n, ret = %d", RT5645_VENDOR_ID2, ret);
+ goto err_enable;
+ }
switch (val) {
case RT5645_DEVICE_ID:
@@ -3983,13 +4115,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080);
- ret = regmap_register_patch(rt5645->regmap, init_list,
+ ret = regmap_multi_reg_write(rt5645->regmap, init_list,
ARRAY_SIZE(init_list));
if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
if (rt5645->codec_type == CODEC_TYPE_RT5650) {
- ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+ ret = regmap_multi_reg_write(rt5645->regmap, rt5650_init_list,
ARRAY_SIZE(rt5650_init_list));
if (ret != 0)
dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
@@ -4117,6 +4249,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
}
timer_setup(&rt5645->btn_check_timer, rt5645_btn_check_callback, 0);
+ mutex_init(&rt5645->jd_mutex);
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
@@ -4125,7 +4258,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5645", rt5645);
if (ret) {
- dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
goto err_enable;
}
}
@@ -4156,11 +4289,14 @@ static void rt5645_i2c_remove(struct i2c_client *i2c)
* Since the rt5645_btn_check_callback() can queue jack_detect_work,
* the timer need to be delted first
*/
- del_timer_sync(&rt5645->btn_check_timer);
+ timer_delete_sync(&rt5645->btn_check_timer);
cancel_delayed_work_sync(&rt5645->jack_detect_work);
cancel_delayed_work_sync(&rt5645->rcclock_work);
+ if (rt5645->gpiod_cbj_sleeve)
+ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
+
regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
}
@@ -4176,13 +4312,48 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
0);
msleep(20);
regmap_write(rt5645->regmap, RT5645_RESET, 0);
+
+ if (rt5645->gpiod_cbj_sleeve)
+ gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
+}
+
+static int rt5645_sys_suspend(struct device *dev)
+{
+ struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+
+ timer_delete_sync(&rt5645->btn_check_timer);
+ cancel_delayed_work_sync(&rt5645->jack_detect_work);
+ cancel_delayed_work_sync(&rt5645->rcclock_work);
+
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return 0;
}
+static int rt5645_sys_resume(struct device *dev)
+{
+ struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+
+ regcache_cache_only(rt5645->regmap, false);
+ regcache_sync(rt5645->regmap);
+
+ if (rt5645->hp_jack) {
+ rt5645->jack_type = 0;
+ rt5645_jack_detect_work(&rt5645->jack_detect_work.work);
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops rt5645_pm = {
+ SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume)
+};
+
static struct i2c_driver rt5645_i2c_driver = {
.driver = {
.name = "rt5645",
.of_match_table = of_match_ptr(rt5645_of_match),
.acpi_match_table = ACPI_PTR(rt5645_acpi_match),
+ .pm = pm_ptr(&rt5645_pm),
},
.probe = rt5645_i2c_probe,
.remove = rt5645_i2c_remove,
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index ac3de6f3bc2f..bef74b29fd54 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -2011,6 +2011,12 @@
#define RT5645_ZCD_HP_DIS (0x0 << 15)
#define RT5645_ZCD_HP_EN (0x1 << 15)
+/* Buttons Inline Command Function 2 (0xe0) */
+#define RT5645_EN_4BTN_IL_MASK (0x1 << 15)
+#define RT5645_EN_4BTN_IL_EN (0x1 << 15)
+#define RT5645_RST_4BTN_IL_MASK (0x1 << 14)
+#define RT5645_RST_4BTN_IL_RST (0x0 << 14)
+#define RT5645_RST_4BTN_IL_NORM (0x1 << 14)
/* Codec Private Register definition */
/* DAC ADC Digital Volume (0x00) */
@@ -2201,4 +2207,7 @@ int rt5645_sel_asrc_clk_src(struct snd_soc_component *component,
int rt5645_set_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
struct snd_soc_jack *btn_jack);
+
+const char *rt5645_components(struct device *codec_dev);
+
#endif /* __RT5645_H__ */
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index b2ec44fa478b..9af65a38f0ee 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;
@@ -1511,16 +1511,18 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
static int rt5651_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) {
if (snd_soc_component_read(component, RT5651_PLL_MODE_1) & 0x9200)
snd_soc_component_update_bits(component, RT5651_D_MISC,
0xc00, 0xc00);
}
break;
case SND_SOC_BIAS_STANDBY:
- if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_OFF == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
RT5651_PWR_VREF1 | RT5651_PWR_MB |
RT5651_PWR_BG | RT5651_PWR_VREF2,
@@ -1557,7 +1559,7 @@ static int rt5651_set_bias_level(struct snd_soc_component *component,
static void rt5651_enable_micbias1_for_ovcd(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO");
@@ -1570,7 +1572,7 @@ static void rt5651_enable_micbias1_for_ovcd(struct snd_soc_component *component)
static void rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock");
@@ -2058,13 +2060,14 @@ static void rt5651_apply_properties(struct snd_soc_component *component)
static int rt5651_probe(struct snd_soc_component *component)
{
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
rt5651->component = component;
snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
RT5651_PWR_LDO_DVO_MASK, RT5651_PWR_LDO_DVO_1_2V);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
rt5651_apply_properties(component);
@@ -2172,7 +2175,7 @@ static const struct regmap_config rt5651_regmap = {
.volatile_reg = rt5651_volatile_register,
.readable_reg = rt5651_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5651_reg,
.num_reg_defaults = ARRAY_SIZE(rt5651_reg),
.ranges = rt5651_ranges,
@@ -2184,22 +2187,22 @@ 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
static const struct i2c_device_id rt5651_i2c_id[] = {
- { "rt5651", 0 },
+ { "rt5651" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
@@ -2261,7 +2264,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT | IRQF_NO_AUTOEN, "rt5651", rt5651);
if (ret) {
- dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+ dev_warn(&i2c->dev, "Failed to request IRQ %d: %d\n",
rt5651->irq, ret);
rt5651->irq = -ENXIO;
}
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index df6f0d769bbd..f5957470652c 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -1198,7 +1197,7 @@ static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux =
static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (snd_soc_component_read(component, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
@@ -1214,7 +1213,7 @@ static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
static void rt5659_enable_push_button_irq(struct snd_soc_component *component,
bool enable)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (enable) {
snd_soc_component_write(component, RT5659_4BTN_IL_CMD_1, 0x000b);
@@ -1258,7 +1257,7 @@ static void rt5659_enable_push_button_irq(struct snd_soc_component *component,
static int rt5659_headset_detect(struct snd_soc_component *component, int jack_insert)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
int reg_63;
@@ -3364,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;
@@ -3612,7 +3611,7 @@ static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
static int rt5659_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
int ret;
@@ -3632,7 +3631,7 @@ static int rt5659_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (dapm->bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = clk_prepare_enable(rt5659->mclk);
if (ret) {
dev_err(component->dev,
@@ -3663,8 +3662,7 @@ static int rt5659_set_bias_level(struct snd_soc_component *component,
static int rt5659_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
rt5659->component = component;
@@ -3816,8 +3814,8 @@ static const struct regmap_config rt5659_regmap = {
};
static const struct i2c_device_id rt5659_i2c_id[] = {
- { "rt5658", 0 },
- { "rt5659", 0 },
+ { "rt5658" },
+ { "rt5659" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id);
@@ -4293,7 +4291,7 @@ static int rt5659_i2c_probe(struct i2c_client *i2c)
rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5659", rt5659);
if (ret)
- dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
/* Enable IRQ output for GPIO1 pin any way */
regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
@@ -4316,16 +4314,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 fd453f47455b..84cdfb810c66 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -11,11 +11,9 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
@@ -907,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;
@@ -1071,6 +1069,7 @@ static int rt5660_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1081,10 +1080,7 @@ static int rt5660_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, RT5660_GEN_CTRL1,
RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL);
- if (IS_ERR(rt5660->mclk))
- break;
-
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) {
clk_disable_unprepare(rt5660->mclk);
} else {
ret = clk_prepare_enable(rt5660->mclk);
@@ -1094,7 +1090,7 @@ static int rt5660_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component, RT5660_PWR_ANLG1,
RT5660_PWR_VREF1 | RT5660_PWR_MB |
RT5660_PWR_BG | RT5660_PWR_VREF2,
@@ -1221,7 +1217,7 @@ static const struct regmap_config rt5660_regmap = {
.volatile_reg = rt5660_volatile_register,
.readable_reg = rt5660_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5660_reg,
.num_reg_defaults = ARRAY_SIZE(rt5660_reg),
.ranges = rt5660_ranges,
@@ -1229,7 +1225,7 @@ static const struct regmap_config rt5660_regmap = {
};
static const struct i2c_device_id rt5660_i2c_id[] = {
- { "rt5660", 0 },
+ { "rt5660" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
@@ -1237,16 +1233,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
@@ -1279,9 +1275,9 @@ static int rt5660_i2c_probe(struct i2c_client *i2c)
return -ENOMEM;
/* Check if MCLK provided */
- rt5660->mclk = devm_clk_get(&i2c->dev, "mclk");
- if (PTR_ERR(rt5660->mclk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ rt5660->mclk = devm_clk_get_optional(&i2c->dev, "mclk");
+ if (IS_ERR(rt5660->mclk))
+ return PTR_ERR(rt5660->mclk);
i2c_set_clientdata(i2c, rt5660);
@@ -1320,14 +1316,17 @@ static int rt5660_i2c_probe(struct i2c_client *i2c)
regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,
RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL);
- if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2)
+ if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2) {
regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
RT5660_SEL_DMIC_DATA_MASK,
RT5660_SEL_DMIC_DATA_GPIO2);
- else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P)
+ regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,
+ RT5660_GP2_PIN_MASK, RT5660_GP2_PIN_DMIC1_SDA);
+ } else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P) {
regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
RT5660_SEL_DMIC_DATA_MASK,
RT5660_SEL_DMIC_DATA_IN1P);
+ }
}
return devm_snd_soc_register_component(&i2c->dev,
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index ceeadbb4f62d..e4d8785e64c1 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -74,6 +74,7 @@ struct rt5663_priv {
int pll_out;
int jack_type;
+ unsigned int irq;
};
static const struct reg_sequence rt5663_patch_list[] = {
@@ -1462,7 +1463,7 @@ static void rt5663_enable_push_button_irq(struct snd_soc_component *component,
static int rt5663_v2_jack_detect(struct snd_soc_component *component, int jack_insert)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
@@ -1858,7 +1859,7 @@ static irqreturn_t rt5663_irq(int irq, void *data)
dev_dbg(regmap_get_device(rt5663->regmap), "%s IRQ queue work\n",
__func__);
- queue_delayed_work(system_wq, &rt5663->jack_detect_work,
+ queue_delayed_work(system_dfl_wq, &rt5663->jack_detect_work,
msecs_to_jiffies(250));
return IRQ_HANDLED;
@@ -1973,7 +1974,7 @@ static void rt5663_jack_detect_work(struct work_struct *work)
cancel_delayed_work_sync(
&rt5663->jd_unplug_work);
} else {
- queue_delayed_work(system_wq,
+ queue_delayed_work(system_dfl_wq,
&rt5663->jd_unplug_work,
msecs_to_jiffies(500));
}
@@ -2023,7 +2024,7 @@ static void rt5663_jd_unplug_work(struct work_struct *work)
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3);
} else {
- queue_delayed_work(system_wq, &rt5663->jd_unplug_work,
+ queue_delayed_work(system_dfl_wq, &rt5663->jd_unplug_work,
msecs_to_jiffies(500));
}
}
@@ -2813,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:
@@ -3139,7 +3140,7 @@ static int rt5663_set_bias_level(struct snd_soc_component *component,
static int rt5663_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
rt5663->component = component;
@@ -3186,6 +3187,12 @@ static int rt5663_suspend(struct snd_soc_component *component)
{
struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+ if (rt5663->irq)
+ disable_irq(rt5663->irq);
+
+ cancel_delayed_work_sync(&rt5663->jack_detect_work);
+ cancel_delayed_work_sync(&rt5663->jd_unplug_work);
+
regcache_cache_only(rt5663->regmap, true);
regcache_mark_dirty(rt5663->regmap);
@@ -3201,6 +3208,9 @@ static int rt5663_resume(struct snd_soc_component *component)
rt5663_irq(0, rt5663);
+ if (rt5663->irq)
+ enable_irq(rt5663->irq);
+
return 0;
}
#else
@@ -3268,7 +3278,7 @@ static const struct regmap_config rt5663_v2_regmap = {
.max_register = 0x07fa,
.volatile_reg = rt5663_v2_volatile_register,
.readable_reg = rt5663_v2_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5663_v2_reg,
.num_reg_defaults = ARRAY_SIZE(rt5663_v2_reg),
};
@@ -3281,7 +3291,7 @@ static const struct regmap_config rt5663_regmap = {
.max_register = 0x03f3,
.volatile_reg = rt5663_volatile_register,
.readable_reg = rt5663_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5663_reg,
.num_reg_defaults = ARRAY_SIZE(rt5663_reg),
};
@@ -3297,7 +3307,7 @@ static const struct regmap_config temp_regmap = {
};
static const struct i2c_device_id rt5663_i2c_id[] = {
- { "rt5663", 0 },
+ { "rt5663" },
{}
};
MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id);
@@ -3305,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
@@ -3682,10 +3692,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5663", rt5663);
if (ret) {
- dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
+ dev_err(&i2c->dev, "%s Failed to request IRQ: %d\n",
__func__, ret);
goto err_enable;
}
+ rt5663->irq = i2c->irq;
}
ret = devm_snd_soc_register_component(&i2c->dev,
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 732e15e3a497..c7beccd54b16 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
@@ -32,9 +31,7 @@
#include "rl6231.h"
#include "rt5665.h"
-#define RT5665_NUM_SUPPLIES 3
-
-static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = {
+static const char * const rt5665_supply_names[] = {
"AVDD",
"MICVDD",
"VBAT",
@@ -47,7 +44,6 @@ struct rt5665_priv {
struct gpio_desc *gpiod_ldo1_en;
struct gpio_desc *gpiod_reset;
struct snd_soc_jack *hs_jack;
- struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES];
struct delayed_work jack_detect_work;
struct delayed_work calibrate_work;
struct delayed_work jd_check_work;
@@ -997,7 +993,7 @@ static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux =
static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (snd_soc_component_read(component, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) {
@@ -1013,7 +1009,7 @@ static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol,
static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (snd_soc_component_read(component, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) {
@@ -1026,102 +1022,6 @@ static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
return ret;
}
-/**
- * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @component: SoC audio component device.
- * @filter_mask: mask of filters.
- * @clk_src: clock source
- *
- * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5665 can
- * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
- * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
- * ASRC function will track i2s clock and generate a corresponding system clock
- * for codec. This function provides an API to select the clock source for a
- * set of filters specified by the mask. And the codec driver will turn on ASRC
- * for these filters if ASRC is selected as their clock source.
- */
-int rt5665_sel_asrc_clk_src(struct snd_soc_component *component,
- unsigned int filter_mask, unsigned int clk_src)
-{
- unsigned int asrc2_mask = 0;
- unsigned int asrc2_value = 0;
- unsigned int asrc3_mask = 0;
- unsigned int asrc3_value = 0;
-
- switch (clk_src) {
- case RT5665_CLK_SEL_SYS:
- case RT5665_CLK_SEL_I2S1_ASRC:
- case RT5665_CLK_SEL_I2S2_ASRC:
- case RT5665_CLK_SEL_I2S3_ASRC:
- case RT5665_CLK_SEL_SYS2:
- case RT5665_CLK_SEL_SYS3:
- case RT5665_CLK_SEL_SYS4:
- break;
-
- default:
- return -EINVAL;
- }
-
- if (filter_mask & RT5665_DA_STEREO1_FILTER) {
- asrc2_mask |= RT5665_DA_STO1_CLK_SEL_MASK;
- asrc2_value = (asrc2_value & ~RT5665_DA_STO1_CLK_SEL_MASK)
- | (clk_src << RT5665_DA_STO1_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_DA_STEREO2_FILTER) {
- asrc2_mask |= RT5665_DA_STO2_CLK_SEL_MASK;
- asrc2_value = (asrc2_value & ~RT5665_DA_STO2_CLK_SEL_MASK)
- | (clk_src << RT5665_DA_STO2_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_DA_MONO_L_FILTER) {
- asrc2_mask |= RT5665_DA_MONOL_CLK_SEL_MASK;
- asrc2_value = (asrc2_value & ~RT5665_DA_MONOL_CLK_SEL_MASK)
- | (clk_src << RT5665_DA_MONOL_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_DA_MONO_R_FILTER) {
- asrc2_mask |= RT5665_DA_MONOR_CLK_SEL_MASK;
- asrc2_value = (asrc2_value & ~RT5665_DA_MONOR_CLK_SEL_MASK)
- | (clk_src << RT5665_DA_MONOR_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_AD_STEREO1_FILTER) {
- asrc3_mask |= RT5665_AD_STO1_CLK_SEL_MASK;
- asrc3_value = (asrc2_value & ~RT5665_AD_STO1_CLK_SEL_MASK)
- | (clk_src << RT5665_AD_STO1_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_AD_STEREO2_FILTER) {
- asrc3_mask |= RT5665_AD_STO2_CLK_SEL_MASK;
- asrc3_value = (asrc2_value & ~RT5665_AD_STO2_CLK_SEL_MASK)
- | (clk_src << RT5665_AD_STO2_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_AD_MONO_L_FILTER) {
- asrc3_mask |= RT5665_AD_MONOL_CLK_SEL_MASK;
- asrc3_value = (asrc3_value & ~RT5665_AD_MONOL_CLK_SEL_MASK)
- | (clk_src << RT5665_AD_MONOL_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5665_AD_MONO_R_FILTER) {
- asrc3_mask |= RT5665_AD_MONOR_CLK_SEL_MASK;
- asrc3_value = (asrc3_value & ~RT5665_AD_MONOR_CLK_SEL_MASK)
- | (clk_src << RT5665_AD_MONOR_CLK_SEL_SFT);
- }
-
- if (asrc2_mask)
- snd_soc_component_update_bits(component, RT5665_ASRC_2,
- asrc2_mask, asrc2_value);
-
- if (asrc3_mask)
- snd_soc_component_update_bits(component, RT5665_ASRC_3,
- asrc3_mask, asrc3_value);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src);
-
static int rt5665_button_detect(struct snd_soc_component *component)
{
int btn_type, val;
@@ -1167,7 +1067,7 @@ static void rt5665_enable_push_button_irq(struct snd_soc_component *component,
static int rt5665_headset_detect(struct snd_soc_component *component, int jack_insert)
{
struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int sar_hs_type, val;
if (jack_insert) {
@@ -4220,10 +4120,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;
@@ -4626,7 +4526,7 @@ static const struct regmap_config rt5665_regmap = {
.max_register = 0x0400,
.volatile_reg = rt5665_volatile_register,
.readable_reg = rt5665_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5665_reg,
.num_reg_defaults = ARRAY_SIZE(rt5665_reg),
.use_single_read = true,
@@ -4634,7 +4534,7 @@ static const struct regmap_config rt5665_regmap = {
};
static const struct i2c_device_id rt5665_i2c_id[] = {
- {"rt5665", 0},
+ {"rt5665"},
{}
};
MODULE_DEVICE_TABLE(i2c, rt5665_i2c_id);
@@ -4657,9 +4557,6 @@ static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev)
of_property_read_u32(dev->of_node, "realtek,jd-src",
&rt5665->pdata.jd_src);
- rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
return 0;
}
@@ -4760,7 +4657,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
{
struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5665_priv *rt5665;
- int i, ret;
+ int ret;
unsigned int val;
rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv),
@@ -4776,27 +4673,19 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
else
rt5665_parse_dt(rt5665, &i2c->dev);
- for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++)
- rt5665->supplies[i].supply = rt5665_supply_names[i];
-
- ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies),
- rt5665->supplies);
+ ret = devm_regulator_bulk_get_enable(&i2c->dev, ARRAY_SIZE(rt5665_supply_names),
+ rt5665_supply_names);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
- ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies),
- rt5665->supplies);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
- return ret;
- }
-
- if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5665"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+ rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5665->gpiod_ldo1_en)) {
+ dev_err(&i2c->dev, "Failed gpio request ldo1_en\n");
+ return PTR_ERR(rt5665->gpiod_ldo1_en);
}
/* Sleep for 300 ms miniumum */
@@ -4928,7 +4817,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
rt5665_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5665", rt5665);
if (ret)
- dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
}
@@ -4948,16 +4837,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/rt5665.h b/sound/soc/codecs/rt5665.h
index 12ab28e5f10d..089e4078d37a 100644
--- a/sound/soc/codecs/rt5665.h
+++ b/sound/soc/codecs/rt5665.h
@@ -1999,7 +1999,4 @@ enum {
RT5665_CLK_SEL_SYS4,
};
-int rt5665_sel_asrc_clk_src(struct snd_soc_component *component,
- unsigned int filter_mask, unsigned int clk_src);
-
#endif /* __RT5665_H__ */
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index 13fec49d4824..5fcdb50d5184 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
@@ -43,6 +42,7 @@ static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = {
struct rt5668_priv {
struct snd_soc_component *component;
struct rt5668_platform_data pdata;
+ struct gpio_desc *ldo1_en;
struct regmap *regmap;
struct snd_soc_jack *hs_jack;
struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES];
@@ -799,49 +799,6 @@ static void rt5668_reset(struct regmap *regmap)
regmap_write(regmap, RT5668_RESET, 0);
regmap_write(regmap, RT5668_I2C_MODE, 1);
}
-/**
- * rt5668_sel_asrc_clk_src - select ASRC clock source for a set of filters
- * @component: SoC audio component device.
- * @filter_mask: mask of filters.
- * @clk_src: clock source
- *
- * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can
- * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
- * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
- * ASRC function will track i2s clock and generate a corresponding system clock
- * for codec. This function provides an API to select the clock source for a
- * set of filters specified by the mask. And the component driver will turn on
- * ASRC for these filters if ASRC is selected as their clock source.
- */
-int rt5668_sel_asrc_clk_src(struct snd_soc_component *component,
- unsigned int filter_mask, unsigned int clk_src)
-{
-
- switch (clk_src) {
- case RT5668_CLK_SEL_SYS:
- case RT5668_CLK_SEL_I2S1_ASRC:
- case RT5668_CLK_SEL_I2S2_ASRC:
- break;
-
- default:
- return -EINVAL;
- }
-
- if (filter_mask & RT5668_DA_STEREO1_FILTER) {
- snd_soc_component_update_bits(component, RT5668_PLL_TRACK_2,
- RT5668_FILTER_CLK_SEL_MASK,
- clk_src << RT5668_FILTER_CLK_SEL_SFT);
- }
-
- if (filter_mask & RT5668_AD_STEREO1_FILTER) {
- snd_soc_component_update_bits(component, RT5668_PLL_TRACK_3,
- RT5668_FILTER_CLK_SEL_MASK,
- clk_src << RT5668_FILTER_CLK_SEL_SFT);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt5668_sel_asrc_clk_src);
static int rt5668_button_detect(struct snd_soc_component *component)
{
@@ -896,8 +853,7 @@ static int rt5668_headset_detect(struct snd_soc_component *component,
int jack_insert)
{
struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int val, count;
if (jack_insert) {
@@ -2010,10 +1966,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:
@@ -2370,7 +2326,7 @@ static const struct regmap_config rt5668_regmap = {
.max_register = RT5668_I2C_MODE,
.volatile_reg = rt5668_volatile_register,
.readable_reg = rt5668_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5668_reg,
.num_reg_defaults = ARRAY_SIZE(rt5668_reg),
.use_single_read = true,
@@ -2378,7 +2334,7 @@ static const struct regmap_config rt5668_regmap = {
};
static const struct i2c_device_id rt5668_i2c_id[] = {
- {"rt5668b", 0},
+ {"rt5668b"},
{}
};
MODULE_DEVICE_TABLE(i2c, rt5668_i2c_id);
@@ -2393,9 +2349,6 @@ static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev)
of_property_read_u32(dev->of_node, "realtek,jd-src",
&rt5668->pdata.jd_src);
- rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
return 0;
}
@@ -2497,10 +2450,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5668->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5668"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+ rt5668->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5668->ldo1_en)) {
+ dev_err(&i2c->dev, "Fail gpio request ldo1_en\n");
+ return PTR_ERR(rt5668->ldo1_en);
}
/* Sleep for 300 ms miniumum */
@@ -2581,7 +2536,7 @@ static int rt5668_i2c_probe(struct i2c_client *i2c)
rt5668_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5668", rt5668);
if (ret)
- dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
}
@@ -2599,15 +2554,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/rt5668.h b/sound/soc/codecs/rt5668.h
index 6b851ddcc58a..b34a61d2109c 100644
--- a/sound/soc/codecs/rt5668.h
+++ b/sound/soc/codecs/rt5668.h
@@ -1309,7 +1309,4 @@ enum {
RT5668_CLK_SEL_I2S2_ASRC,
};
-int rt5668_sel_asrc_clk_src(struct snd_soc_component *component,
- unsigned int filter_mask, unsigned int clk_src);
-
#endif /* __RT5668_H__ */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index e8ce3e7c8e3f..cb5d03bf4c7f 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -431,7 +431,7 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
static int rt5670_headset_detect(struct snd_soc_component *component, int jack_insert)
{
int val;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
if (jack_insert) {
@@ -652,7 +652,7 @@ static void rt5670_update_ad_da_mixer_dac1_m_bits(struct rt5670_priv *rt5670)
static int rt5670_dac1_playback_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rt5670->dac1_playback_switch_l;
@@ -664,7 +664,7 @@ static int rt5670_dac1_playback_switch_get(struct snd_kcontrol *kcontrol,
static int rt5670_dac1_playback_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
if (rt5670->dac1_playback_switch_l == ucontrol->value.integer.value[0] &&
@@ -966,7 +966,7 @@ static int rt5670_put_dac1_mix_dac1_switch(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_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
int ret;
@@ -1153,25 +1153,29 @@ static SOC_ENUM_SINGLE_DECL(rt5670_dac1r_enum, RT5670_AD_DA_MIXER,
static const struct snd_kcontrol_new rt5670_dac1r_mux =
SOC_DAPM_ENUM("DAC1 R source", rt5670_dac1r_enum);
-/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */
-/* TODO Use SOC_VALUE_ENUM_SINGLE_DECL */
-static const char * const rt5670_dac12_src[] = {
- "IF1 DAC", "IF2 DAC", "IF3 DAC", "TxDC DAC",
- "Bass", "VAD_ADC", "IF4 DAC"
-};
+/* DAC2 L source*/ /* MX-1B [6:4] */
+static const char *const rt5670_dac12_src[] = {
+ "IF1 DAC", "IF2 DAC", "TxDC DAC", "VAD_ADC"
+}; /* VAD_ADC or TxDP_ADC_R */
+
+static const unsigned int rt5670_dac12_values[] = { 0, 1, 3, 5 };
-static SOC_ENUM_SINGLE_DECL(rt5670_dac2l_enum, RT5670_DAC_CTRL,
- RT5670_DAC2_L_SEL_SFT, rt5670_dac12_src);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5670_dac2l_enum, RT5670_DAC_CTRL,
+ RT5670_DAC2_L_SEL_SFT, RT5670_DAC2_L_SEL_MASK,
+ rt5670_dac12_src, rt5670_dac12_values);
static const struct snd_kcontrol_new rt5670_dac_l2_mux =
SOC_DAPM_ENUM("DAC2 L source", rt5670_dac2l_enum);
-static const char * const rt5670_dacr2_src[] = {
- "IF1 DAC", "IF2 DAC", "IF3 DAC", "TxDC DAC", "TxDP ADC", "IF4 DAC"
-};
+/*DAC2 R source*/ /* MX-1B [2:0] */
+static const char *const rt5670_dacr2_src[] = { "IF1 DAC", "IF2 DAC",
+ "TxDC DAC", "TxDP ADC" };
-static SOC_ENUM_SINGLE_DECL(rt5670_dac2r_enum, RT5670_DAC_CTRL,
- RT5670_DAC2_R_SEL_SFT, rt5670_dacr2_src);
+static const unsigned int rt5670_dacr2_values[] = { 0, 1, 3, 4 };
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5670_dac2r_enum, RT5670_DAC_CTRL,
+ RT5670_DAC2_R_SEL_SFT, RT5670_DAC2_R_SEL_MASK,
+ rt5670_dacr2_src, rt5670_dacr2_values);
static const struct snd_kcontrol_new rt5670_dac_r2_mux =
SOC_DAPM_ENUM("DAC2 R source", rt5670_dac2r_enum);
@@ -2439,10 +2443,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;
@@ -2666,10 +2670,11 @@ static int rt5670_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+ if (SND_SOC_BIAS_STANDBY == snd_soc_dapm_get_bias_level(dapm)) {
snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
RT5670_PWR_VREF1 | RT5670_PWR_MB |
RT5670_PWR_BG | RT5670_PWR_VREF2,
@@ -2719,7 +2724,7 @@ static int rt5670_set_bias_level(struct snd_soc_component *component,
static int rt5670_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
switch (snd_soc_component_read(component, RT5670_RESET) & RT5670_ID_MASK) {
@@ -2863,7 +2868,7 @@ static const struct regmap_config rt5670_regmap = {
RT5670_PR_SPACING),
.volatile_reg = rt5670_volatile_register,
.readable_reg = rt5670_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5670_reg,
.num_reg_defaults = ARRAY_SIZE(rt5670_reg),
.ranges = rt5670_ranges,
@@ -2871,19 +2876,19 @@ static const struct regmap_config rt5670_regmap = {
};
static const struct i2c_device_id rt5670_i2c_id[] = {
- { "rt5670", 0 },
- { "rt5671", 0 },
- { "rt5672", 0 },
+ { "rt5670" },
+ { "rt5671" },
+ { "rt5672" },
{ }
};
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 d25703dd7499..885edcf0a3a5 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -112,7 +112,7 @@ static int rt5677_spi_pcm_close(
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *codec_component =
snd_soc_rtdcom_lookup(rtd, "rt5677");
struct rt5677_priv *rt5677 =
@@ -158,7 +158,7 @@ static int rt5677_spi_prepare(
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *rt5677_component =
snd_soc_rtdcom_lookup(rtd, "rt5677");
struct rt5677_priv *rt5677 =
@@ -365,8 +365,8 @@ static void rt5677_spi_copy_work(struct work_struct *work)
new_bytes -= copy_bytes;
}
- delay = bytes_to_frames(runtime, period_bytes) / (runtime->rate / 1000);
- schedule_delayed_work(&rt5677_dsp->copy_work, msecs_to_jiffies(delay));
+ delay = bytes_to_frames(runtime, period_bytes) / runtime->rate;
+ schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay));
done:
mutex_unlock(&rt5677_dsp->dma_lock);
}
@@ -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 60e38a9bcd1b..d46385249867 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -6,23 +6,21 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
-#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/regmap.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/firmware.h>
-#include <linux/of_device.h>
-#include <linux/property.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -708,8 +706,7 @@ static void rt5677_set_dsp_mode(struct rt5677_priv *rt5677, bool on)
static unsigned int rt5677_set_vad_source(struct rt5677_priv *rt5677)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(rt5677->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt5677->component);
/* Force dapm to sync before we enable the
* DSP to prevent write corruption
*/
@@ -2735,11 +2732,12 @@ static int rt5677_vref_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 snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON &&
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON &&
!rt5677->is_vref_slow) {
mdelay(20);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@ -4379,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;
@@ -4645,8 +4643,8 @@ static int rt5677_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
- enum snd_soc_bias_level prev_bias =
- snd_soc_component_get_bias_level(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ enum snd_soc_bias_level prev_bias = snd_soc_dapm_get_bias_level(dapm);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -4717,50 +4715,35 @@ static int rt5677_set_bias_level(struct snd_soc_component *component,
return 0;
}
-#ifdef CONFIG_GPIOLIB
-static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int rt5677_update_gpio_bits(struct rt5677_priv *rt5677, unsigned offset, int m, int v)
{
- struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ unsigned int bank = offset / 5;
+ unsigned int shift = (offset % 5) * 3;
+ unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2;
- switch (offset) {
- case RT5677_GPIO1 ... RT5677_GPIO5:
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
- 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1));
- break;
+ return regmap_update_bits(rt5677->regmap, reg, m << shift, v << shift);
+}
- case RT5677_GPIO6:
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
- RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT);
- break;
+#ifdef CONFIG_GPIOLIB
+static int rt5677_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO;
+ int m = RT5677_GPIOx_OUT_MASK;
- default:
- break;
- }
+ return rt5677_update_gpio_bits(rt5677, offset, m, level);
}
static int rt5677_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO;
+ int m = RT5677_GPIOx_DIR_MASK | RT5677_GPIOx_OUT_MASK;
+ int v = RT5677_GPIOx_DIR_OUT | level;
- switch (offset) {
- case RT5677_GPIO1 ... RT5677_GPIO5:
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
- 0x3 << (offset * 3 + 1),
- (0x2 | !!value) << (offset * 3 + 1));
- break;
-
- case RT5677_GPIO6:
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
- RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK,
- RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT);
- break;
-
- default:
- break;
- }
-
- return 0;
+ return rt5677_update_gpio_bits(rt5677, offset, m, v);
}
static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -4778,26 +4761,14 @@ static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ int m = RT5677_GPIOx_DIR_MASK;
+ int v = RT5677_GPIOx_DIR_IN;
- switch (offset) {
- case RT5677_GPIO1 ... RT5677_GPIO5:
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
- 0x1 << (offset * 3 + 2), 0x0);
- break;
-
- case RT5677_GPIO6:
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
- RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN);
- break;
-
- default:
- break;
- }
-
- return 0;
+ return rt5677_update_gpio_bits(rt5677, offset, m, v);
}
-/** Configures the gpio as
+/*
+ * Configures the GPIO as
* 0 - floating
* 1 - pull down
* 2 - pull up
@@ -4909,7 +4880,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
static int rt5677_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
int i;
@@ -4925,7 +4896,7 @@ static int rt5677_probe(struct snd_soc_component *component)
ARRAY_SIZE(rt5677_dmic2_clk_1));
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
~RT5677_IRQ_DEBOUNCE_SEL_MASK, 0x0020);
@@ -5231,6 +5202,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 },
{ }
};
@@ -5539,7 +5511,7 @@ static int rt5677_init_irq(struct i2c_client *i2c)
RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);
/* Ready to listen for interrupts */
- rt5677->domain = irq_domain_add_linear(i2c->dev.of_node,
+ rt5677->domain = irq_domain_create_linear(dev_fwnode(&i2c->dev),
RT5677_IRQ_NUM, &rt5677_domain_ops, rt5677);
if (!rt5677->domain) {
dev_err(&i2c->dev, "Failed to create IRQ domain\n");
@@ -5559,6 +5531,7 @@ static int rt5677_init_irq(struct i2c_client *i2c)
static int rt5677_i2c_probe(struct i2c_client *i2c)
{
+ struct device *dev = &i2c->dev;
struct rt5677_priv *rt5677;
int ret;
unsigned int val;
@@ -5573,21 +5546,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work);
i2c_set_clientdata(i2c, rt5677);
- if (i2c->dev.of_node) {
- const struct of_device_id *match_id;
-
- match_id = of_match_device(rt5677_of_match, &i2c->dev);
- if (match_id)
- rt5677->type = (enum rt5677_type)match_id->data;
- } else if (ACPI_HANDLE(&i2c->dev)) {
- const struct acpi_device_id *acpi_id;
-
- acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev);
- if (acpi_id)
- rt5677->type = (enum rt5677_type)acpi_id->driver_data;
- } else {
+ rt5677->type = (enum rt5677_type)(uintptr_t)device_get_match_data(dev);
+ if (rt5677->type == 0)
return -EINVAL;
- }
rt5677_read_device_properties(rt5677, &i2c->dev);
@@ -5673,9 +5634,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
RT5677_GPIO5_FUNC_MASK,
RT5677_GPIO5_FUNC_DMIC);
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
- RT5677_GPIO5_DIR_MASK,
- RT5677_GPIO5_DIR_OUT);
+ rt5677_update_gpio_bits(rt5677, RT5677_GPIO5,
+ RT5677_GPIOx_DIR_MASK,
+ RT5677_GPIOx_DIR_OUT);
}
if (rt5677->pdata.micbias1_vdd_3v3)
@@ -5702,7 +5663,7 @@ static struct i2c_driver rt5677_i2c_driver = {
.driver = {
.name = RT5677_DRV_NAME,
.of_match_table = rt5677_of_match,
- .acpi_match_table = ACPI_PTR(rt5677_acpi_match),
+ .acpi_match_table = rt5677_acpi_match,
},
.probe = rt5677_i2c_probe,
.remove = rt5677_i2c_remove,
@@ -5712,3 +5673,5 @@ module_i2c_driver(rt5677_i2c_driver);
MODULE_DESCRIPTION("ASoC RT5677 driver");
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
MODULE_LICENSE("GPL v2");
+
+MODULE_FIRMWARE("rt5677_elf_vad");
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 944ae02aafc2..d67ebae067d9 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -1587,81 +1587,19 @@
#define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13)
#define RT5677_FUNC_MODE_JTAG (0x1 << 13)
-/* GPIO Control 2 (0xc1) */
-#define RT5677_GPIO5_DIR_MASK (0x1 << 14)
-#define RT5677_GPIO5_DIR_SFT 14
-#define RT5677_GPIO5_DIR_IN (0x0 << 14)
-#define RT5677_GPIO5_DIR_OUT (0x1 << 14)
-#define RT5677_GPIO5_OUT_MASK (0x1 << 13)
-#define RT5677_GPIO5_OUT_SFT 13
-#define RT5677_GPIO5_OUT_LO (0x0 << 13)
-#define RT5677_GPIO5_OUT_HI (0x1 << 13)
-#define RT5677_GPIO5_P_MASK (0x1 << 12)
-#define RT5677_GPIO5_P_SFT 12
-#define RT5677_GPIO5_P_NOR (0x0 << 12)
-#define RT5677_GPIO5_P_INV (0x1 << 12)
-#define RT5677_GPIO4_DIR_MASK (0x1 << 11)
-#define RT5677_GPIO4_DIR_SFT 11
-#define RT5677_GPIO4_DIR_IN (0x0 << 11)
-#define RT5677_GPIO4_DIR_OUT (0x1 << 11)
-#define RT5677_GPIO4_OUT_MASK (0x1 << 10)
-#define RT5677_GPIO4_OUT_SFT 10
-#define RT5677_GPIO4_OUT_LO (0x0 << 10)
-#define RT5677_GPIO4_OUT_HI (0x1 << 10)
-#define RT5677_GPIO4_P_MASK (0x1 << 9)
-#define RT5677_GPIO4_P_SFT 9
-#define RT5677_GPIO4_P_NOR (0x0 << 9)
-#define RT5677_GPIO4_P_INV (0x1 << 9)
-#define RT5677_GPIO3_DIR_MASK (0x1 << 8)
-#define RT5677_GPIO3_DIR_SFT 8
-#define RT5677_GPIO3_DIR_IN (0x0 << 8)
-#define RT5677_GPIO3_DIR_OUT (0x1 << 8)
-#define RT5677_GPIO3_OUT_MASK (0x1 << 7)
-#define RT5677_GPIO3_OUT_SFT 7
-#define RT5677_GPIO3_OUT_LO (0x0 << 7)
-#define RT5677_GPIO3_OUT_HI (0x1 << 7)
-#define RT5677_GPIO3_P_MASK (0x1 << 6)
-#define RT5677_GPIO3_P_SFT 6
-#define RT5677_GPIO3_P_NOR (0x0 << 6)
-#define RT5677_GPIO3_P_INV (0x1 << 6)
-#define RT5677_GPIO2_DIR_MASK (0x1 << 5)
-#define RT5677_GPIO2_DIR_SFT 5
-#define RT5677_GPIO2_DIR_IN (0x0 << 5)
-#define RT5677_GPIO2_DIR_OUT (0x1 << 5)
-#define RT5677_GPIO2_OUT_MASK (0x1 << 4)
-#define RT5677_GPIO2_OUT_SFT 4
-#define RT5677_GPIO2_OUT_LO (0x0 << 4)
-#define RT5677_GPIO2_OUT_HI (0x1 << 4)
-#define RT5677_GPIO2_P_MASK (0x1 << 3)
-#define RT5677_GPIO2_P_SFT 3
-#define RT5677_GPIO2_P_NOR (0x0 << 3)
-#define RT5677_GPIO2_P_INV (0x1 << 3)
-#define RT5677_GPIO1_DIR_MASK (0x1 << 2)
-#define RT5677_GPIO1_DIR_SFT 2
-#define RT5677_GPIO1_DIR_IN (0x0 << 2)
-#define RT5677_GPIO1_DIR_OUT (0x1 << 2)
-#define RT5677_GPIO1_OUT_MASK (0x1 << 1)
-#define RT5677_GPIO1_OUT_SFT 1
-#define RT5677_GPIO1_OUT_LO (0x0 << 1)
-#define RT5677_GPIO1_OUT_HI (0x1 << 1)
-#define RT5677_GPIO1_P_MASK (0x1 << 0)
-#define RT5677_GPIO1_P_SFT 0
-#define RT5677_GPIO1_P_NOR (0x0 << 0)
-#define RT5677_GPIO1_P_INV (0x1 << 0)
-
-/* GPIO Control 3 (0xc2) */
-#define RT5677_GPIO6_DIR_MASK (0x1 << 2)
-#define RT5677_GPIO6_DIR_SFT 2
-#define RT5677_GPIO6_DIR_IN (0x0 << 2)
-#define RT5677_GPIO6_DIR_OUT (0x1 << 2)
-#define RT5677_GPIO6_OUT_MASK (0x1 << 1)
-#define RT5677_GPIO6_OUT_SFT 1
-#define RT5677_GPIO6_OUT_LO (0x0 << 1)
-#define RT5677_GPIO6_OUT_HI (0x1 << 1)
-#define RT5677_GPIO6_P_MASK (0x1 << 0)
-#define RT5677_GPIO6_P_SFT 0
-#define RT5677_GPIO6_P_NOR (0x0 << 0)
-#define RT5677_GPIO6_P_INV (0x1 << 0)
+/* GPIO Control 2 (0xc1) & 3 (0xc2) common bits */
+#define RT5677_GPIOx_DIR_MASK (0x1 << 2)
+#define RT5677_GPIOx_DIR_SFT 2
+#define RT5677_GPIOx_DIR_IN (0x0 << 2)
+#define RT5677_GPIOx_DIR_OUT (0x1 << 2)
+#define RT5677_GPIOx_OUT_MASK (0x1 << 1)
+#define RT5677_GPIOx_OUT_SFT 1
+#define RT5677_GPIOx_OUT_LO (0x0 << 1)
+#define RT5677_GPIOx_OUT_HI (0x1 << 1)
+#define RT5677_GPIOx_P_MASK (0x1 << 0)
+#define RT5677_GPIOx_P_SFT 0
+#define RT5677_GPIOx_P_NOR (0x0 << 0)
+#define RT5677_GPIOx_P_INV (0x1 << 0)
/* General Control (0xfa) */
#define RT5677_IRQ_DEBOUNCE_SEL_MASK (0x3 << 3)
@@ -1753,8 +1691,8 @@ enum {
};
enum rt5677_type {
- RT5677,
- RT5676,
+ RT5677 = 1,
+ RT5676 = 2,
};
/* ASRC clock source selection */
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index a88fcf507386..bba987308e15 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -46,7 +45,7 @@ static const struct regmap_config rt5682_regmap = {
.max_register = RT5682_I2C_MODE,
.volatile_reg = rt5682_volatile_register,
.readable_reg = rt5682_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = rt5682_reg,
.num_reg_defaults = RT5682_REG_NUM,
.use_single_read = true,
@@ -158,11 +157,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
return ret;
}
- ret = devm_add_action_or_reset(&i2c->dev, rt5682_i2c_disable_regulators,
- rt5682);
- if (ret)
- return ret;
-
ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
rt5682->supplies);
if (ret) {
@@ -170,11 +164,14 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5682"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
- }
+ ret = devm_add_action_or_reset(&i2c->dev, rt5682_i2c_disable_regulators,
+ rt5682);
+ if (ret)
+ return ret;
+
+ ret = rt5682_get_ldo1(rt5682, &i2c->dev);
+ if (ret)
+ return ret;
/* Sleep for 300 ms miniumum */
usleep_range(300000, 350000);
@@ -189,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);
@@ -266,8 +269,10 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5682", rt5682);
- if (ret)
- dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ if (!ret)
+ rt5682->irq = i2c->irq;
+ else
+ dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
}
#ifdef CONFIG_COMMON_CLK
@@ -308,18 +313,18 @@ 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);
static const struct i2c_device_id rt5682_i2c_id[] = {
- {"rt5682", 0},
+ {"rt5682"},
{}
};
MODULE_DEVICE_TABLE(i2c, rt5682_i2c_id);
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index 67404f45389f..055bea0a4a3b 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -12,8 +12,6 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
@@ -134,7 +132,7 @@ static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt5682->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
@@ -317,11 +315,19 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
&rt5682_sdw_indirect_regmap);
if (IS_ERR(rt5682->regmap)) {
ret = PTR_ERR(rt5682->regmap);
- dev_err(dev, "Failed to allocate register map: %d\n",
- ret);
+ dev_err(dev, "%s: Failed to allocate register map: %d\n",
+ __func__, ret);
return ret;
}
+
+ ret = rt5682_get_ldo1(rt5682, dev);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -336,7 +342,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
ret = devm_snd_soc_register_component(dev,
&rt5682_soc_component_dev,
rt5682_dai, ARRAY_SIZE(rt5682_dai));
- dev_dbg(&slave->dev, "%s\n", __func__);
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -352,30 +376,20 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
if (rt5682->hw_init)
return 0;
+ regcache_cache_only(rt5682->sdw_regmap, false);
+ regcache_cache_only(rt5682->regmap, false);
+ if (rt5682->first_hw_init)
+ regcache_cache_bypass(rt5682->regmap, true);
+
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt5682->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt5682->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
- if (rt5682->first_hw_init) {
- regcache_cache_only(rt5682->regmap, false);
- regcache_cache_bypass(rt5682->regmap, true);
- }
-
while (loop > 0) {
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
if (val == DEVICE_ID)
@@ -386,7 +400,7 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
}
if (val != DEVICE_ID) {
- dev_err(dev, "Device with ID register %x is not rt5682\n", val);
+ dev_err(dev, "%s: Device with ID register %x is not rt5682\n", __func__, val);
ret = -ENODEV;
goto err_nodev;
}
@@ -460,7 +474,6 @@ reinit:
rt5682->first_hw_init = true;
err_nodev:
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret);
@@ -634,7 +647,7 @@ static int rt5682_bus_config(struct sdw_slave *slave,
ret = rt5682_clock_config(&slave->dev);
if (ret < 0)
- dev_err(&slave->dev, "Invalid clk config");
+ dev_err(&slave->dev, "%s: Invalid clk config", __func__);
return ret;
}
@@ -674,9 +687,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return -EINVAL;
- rt5682_sdw_init(&slave->dev, regmap, slave);
-
- return 0;
+ return rt5682_sdw_init(&slave->dev, regmap, slave);
}
static int rt5682_sdw_remove(struct sdw_slave *slave)
@@ -686,8 +697,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
if (rt5682->hw_init)
cancel_delayed_work_sync(&rt5682->jack_detect_work);
- if (rt5682->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -698,7 +708,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);
@@ -707,13 +717,14 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
cancel_delayed_work_sync(&rt5682->jack_detect_work);
+ regcache_cache_only(rt5682->sdw_regmap, true);
regcache_cache_only(rt5682->regmap, true);
regcache_mark_dirty(rt5682->regmap);
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);
@@ -741,7 +752,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);
@@ -750,13 +761,20 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
if (!rt5682->first_hw_init)
return 0;
- if (!slave->unattach_request)
+ if (!slave->unattach_request) {
+ mutex_lock(&rt5682->disable_irq_lock);
+ if (rt5682->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
+ rt5682->disable_irq = false;
+ }
+ mutex_unlock(&rt5682->disable_irq_lock);
goto regmap_sync;
+ }
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT5682_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -764,6 +782,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
regmap_sync:
slave->unattach_request = 0;
+ regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);
regcache_sync(rt5682->regmap);
@@ -771,15 +790,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",
- .owner = THIS_MODULE,
- .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 f6c798b65c08..d39f8e4f3474 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -396,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:
@@ -420,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:
@@ -927,7 +928,7 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
{
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = &component->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
unsigned int val, count;
if (jack_insert) {
@@ -1017,6 +1018,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
rt5682->hs_jack = hs_jack;
+ if (rt5682->is_sdw && !rt5682->first_hw_init)
+ return 0;
+
if (!hs_jack) {
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
@@ -1111,7 +1115,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
}
}
- dapm = snd_soc_component_get_dapm(rt5682->component);
+ dapm = snd_soc_component_to_dapm(rt5682->component);
snd_soc_dapm_mutex_lock(dapm);
mutex_lock(&rt5682->calibrate_mutex);
@@ -2221,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:
@@ -2591,7 +2595,7 @@ static int rt5682_wclk_prepare(struct clk_hw *hw)
return -EINVAL;
component = rt5682->component;
- dapm = snd_soc_component_get_dapm(component);
+ dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
@@ -2629,7 +2633,7 @@ static void rt5682_wclk_unprepare(struct clk_hw *hw)
return;
component = rt5682->component;
- dapm = snd_soc_component_get_dapm(component);
+ dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
@@ -2671,8 +2675,8 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw,
return rt5682->lrck[RT5682_AIF1];
}
-static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int rt5682_wclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct rt5682_priv *rt5682 =
container_of(hw, struct rt5682_priv,
@@ -2685,13 +2689,13 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
* Only accept to set wclk rate to 44.1k or 48kHz.
* It will force to 48kHz if not both.
*/
- if (rate != CLK_48 && rate != CLK_44) {
+ if (req->rate != CLK_48 && req->rate != CLK_44) {
dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n",
__func__, clk_name, CLK_44, CLK_48);
- rate = CLK_48;
+ req->rate = CLK_48;
}
- return rate;
+ return 0;
}
static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -2791,15 +2795,15 @@ static unsigned long rt5682_bclk_get_factor(unsigned long rate,
return 256;
}
-static long rt5682_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int rt5682_bclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct rt5682_priv *rt5682 =
container_of(hw, struct rt5682_priv,
dai_clks_hw[RT5682_DAI_BCLK_IDX]);
unsigned long factor;
- if (!*parent_rate || !rt5682_clk_check(rt5682))
+ if (!req->best_parent_rate || !rt5682_clk_check(rt5682))
return -EINVAL;
/*
@@ -2809,9 +2813,11 @@ static long rt5682_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
* and find the appropriate multiplier of BCLK to
* get the rounded down BCLK value.
*/
- factor = rt5682_bclk_get_factor(rate, *parent_rate);
+ factor = rt5682_bclk_get_factor(req->rate, req->best_parent_rate);
- return *parent_rate * factor;
+ req->rate = req->best_parent_rate * factor;
+
+ return 0;
}
static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -2845,12 +2851,12 @@ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = {
.prepare = rt5682_wclk_prepare,
.unprepare = rt5682_wclk_unprepare,
.recalc_rate = rt5682_wclk_recalc_rate,
- .round_rate = rt5682_wclk_round_rate,
+ .determine_rate = rt5682_wclk_determine_rate,
.set_rate = rt5682_wclk_set_rate,
},
[RT5682_DAI_BCLK_IDX] = {
.recalc_rate = rt5682_bclk_recalc_rate,
- .round_rate = rt5682_bclk_round_rate,
+ .determine_rate = rt5682_bclk_determine_rate,
.set_rate = rt5682_bclk_set_rate,
},
};
@@ -2901,8 +2907,10 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
}
if (dev->of_node) {
- devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
dai_clk_hw);
+ if (ret)
+ return ret;
} else {
ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw,
init.name,
@@ -2920,9 +2928,9 @@ EXPORT_SYMBOL_GPL(rt5682_register_dai_clks);
static int rt5682_probe(struct snd_soc_component *component)
{
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct sdw_slave *slave;
unsigned long time;
- struct snd_soc_dapm_context *dapm = &component->dapm;
rt5682->component = component;
@@ -2959,6 +2967,9 @@ static int rt5682_suspend(struct snd_soc_component *component)
if (rt5682->is_sdw)
return 0;
+ if (rt5682->irq)
+ disable_irq(rt5682->irq);
+
cancel_delayed_work_sync(&rt5682->jack_detect_work);
cancel_delayed_work_sync(&rt5682->jd_check_work);
if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
@@ -3027,6 +3038,9 @@ static int rt5682_resume(struct snd_soc_component *component)
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(0));
+ if (rt5682->irq)
+ enable_irq(rt5682->irq);
+
return 0;
}
#else
@@ -3085,9 +3099,6 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
device_property_read_u32(dev, "realtek,dmic-delay-ms",
&rt5682->pdata.dmic_delay);
- rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
if (device_property_read_string_array(dev, "clock-output-names",
rt5682->pdata.dai_clk_names,
RT5682_DAI_NUM_CLKS) < 0)
@@ -3102,6 +3113,20 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
}
EXPORT_SYMBOL_GPL(rt5682_parse_dt);
+int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev)
+{
+ rt5682->ldo1_en = devm_gpiod_get_optional(dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5682->ldo1_en)) {
+ dev_err(dev, "Fail gpio request ldo1_en\n");
+ return PTR_ERR(rt5682->ldo1_en);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5682_get_ldo1);
+
void rt5682_calibrate(struct rt5682_priv *rt5682)
{
int value, count;
@@ -3118,7 +3143,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);
@@ -3147,7 +3175,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 301d1817f8f1..de43a5d99403 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -11,6 +11,7 @@
#include <sound/rt5682.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -21,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
@@ -1430,6 +1432,7 @@ struct rt5682_priv {
struct snd_soc_component *component;
struct device *i2c_dev;
struct rt5682_platform_data pdata;
+ struct gpio_desc *ldo1_en;
struct regmap *regmap;
struct regmap *sdw_regmap;
struct snd_soc_jack *hs_jack;
@@ -1444,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];
@@ -1461,6 +1465,7 @@ struct rt5682_priv {
int pll_out[RT5682_PLLS];
int jack_type;
+ int irq;
int irq_work_delay_time;
};
@@ -1480,6 +1485,7 @@ int rt5682_register_component(struct device *dev);
void rt5682_calibrate(struct rt5682_priv *rt5682);
void rt5682_reset(struct rt5682_priv *rt5682);
int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev);
+int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev);
int rt5682_register_dai_clks(struct rt5682_priv *rt5682);
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index c77c675bd5f5..98de94a79260 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -654,14 +653,15 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode
switch (mode) {
case SAR_PWR_SAVING:
snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_3,
- RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_DIS);
+ RT5682S_CBJ_IN_BUF_MASK, RT5682S_CBJ_IN_BUF_EN);
snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1,
- RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK,
- RT5682S_CTRL_MB1_REG | RT5682S_CTRL_MB2_REG);
+ RT5682S_MB1_PATH_MASK | RT5682S_MB2_PATH_MASK |
+ RT5682S_VREF_POW_MASK, RT5682S_CTRL_MB1_FSM |
+ RT5682S_CTRL_MB2_FSM | RT5682S_VREF_POW_FSM);
snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1,
RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK |
RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS |
- RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU);
+ RT5682S_SAR_BUTDET_POW_NORM | RT5682S_SAR_SEL_MB1_2_MANU);
usleep_range(5000, 5500);
snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1,
RT5682S_SAR_BUTDET_MASK, RT5682S_SAR_BUTDET_EN);
@@ -689,7 +689,7 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode
snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1,
RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK |
RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS |
- RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU);
+ RT5682S_SAR_BUTDET_POW_NORM | RT5682S_SAR_SEL_MB1_2_MANU);
break;
default:
dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode);
@@ -726,7 +726,7 @@ static void rt5682s_disable_push_button_irq(struct snd_soc_component *component)
snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1,
RT5682S_SAR_BUTDET_MASK | RT5682S_SAR_BUTDET_POW_MASK |
RT5682S_SAR_SEL_MB1_2_CTL_MASK, RT5682S_SAR_BUTDET_DIS |
- RT5682S_SAR_BUTDET_POW_SAV | RT5682S_SAR_SEL_MB1_2_MANU);
+ RT5682S_SAR_BUTDET_POW_NORM | RT5682S_SAR_SEL_MB1_2_MANU);
}
/**
@@ -787,7 +787,7 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_
jack_type = SND_JACK_HEADSET;
snd_soc_component_write(component, RT5682S_SAR_IL_CMD_3, 0x024c);
snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1,
- RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_EN);
+ RT5682S_FAST_OFF_MASK, RT5682S_FAST_OFF_DIS);
snd_soc_component_update_bits(component, RT5682S_SAR_IL_CMD_1,
RT5682S_SAR_SEL_MB1_2_MASK, val << RT5682S_SAR_SEL_MB1_2_SFT);
rt5682s_enable_push_button_irq(component);
@@ -841,7 +841,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
return;
}
- dapm = snd_soc_component_get_dapm(rt5682s->component);
+ dapm = snd_soc_component_to_dapm(rt5682s->component);
snd_soc_dapm_mutex_lock(dapm);
mutex_lock(&rt5682s->calibrate_mutex);
@@ -967,7 +967,7 @@ static int rt5682s_set_jack_detect(struct snd_soc_component *component,
RT5682S_EMB_JD_MASK | RT5682S_DET_TYPE |
RT5682S_POL_FAST_OFF_MASK | RT5682S_MIC_CAP_MASK,
RT5682S_EMB_JD_EN | RT5682S_DET_TYPE |
- RT5682S_POL_FAST_OFF_HIGH | RT5682S_MIC_CAP_HS);
+ RT5682S_POL_FAST_OFF_LOW | RT5682S_MIC_CAP_HS);
regmap_update_bits(rt5682s->regmap, RT5682S_SAR_IL_CMD_1,
RT5682S_SAR_POW_MASK, RT5682S_SAR_POW_EN);
regmap_update_bits(rt5682s->regmap, RT5682S_GPIO_CTRL_1,
@@ -1324,9 +1324,9 @@ static int set_i2s_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_ON(event))
on = 1;
- if (!strcmp(w->name, "I2S1") && !rt5682s->wclk_enabled)
+ if (!snd_soc_dapm_widget_name_cmp(w, "I2S1") && !rt5682s->wclk_enabled)
rt5682s_set_i2s(rt5682s, RT5682S_AIF1, on);
- else if (!strcmp(w->name, "I2S2"))
+ else if (!snd_soc_dapm_widget_name_cmp(w, "I2S2"))
rt5682s_set_i2s(rt5682s, RT5682S_AIF2, on);
return 0;
@@ -2133,10 +2133,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:
@@ -2485,6 +2485,7 @@ static int rt5682s_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
@@ -2492,7 +2493,7 @@ static int rt5682s_set_bias_level(struct snd_soc_component *component,
RT5682S_PWR_LDO, RT5682S_PWR_LDO);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
break;
@@ -2611,8 +2612,8 @@ static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw,
return rt5682s->lrck[RT5682S_AIF1];
}
-static long rt5682s_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int rt5682s_wclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct rt5682s_priv *rt5682s =
container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]);
@@ -2625,13 +2626,13 @@ static long rt5682s_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
* Only accept to set wclk rate to 44.1k or 48kHz.
* It will force to 48kHz if not both.
*/
- if (rate != CLK_48 && rate != CLK_44) {
+ if (req->rate != CLK_48 && req->rate != CLK_44) {
dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n",
__func__, clk_name, CLK_44, CLK_48);
- rate = CLK_48;
+ req->rate = CLK_48;
}
- return rate;
+ return 0;
}
static int rt5682s_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -2720,14 +2721,14 @@ static unsigned long rt5682s_bclk_get_factor(unsigned long rate,
return 256;
}
-static long rt5682s_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int rt5682s_bclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct rt5682s_priv *rt5682s =
container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_BCLK_IDX]);
unsigned long factor;
- if (!*parent_rate || !rt5682s_clk_check(rt5682s))
+ if (!req->best_parent_rate || !rt5682s_clk_check(rt5682s))
return -EINVAL;
/*
@@ -2737,9 +2738,11 @@ static long rt5682s_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
* and find the appropriate multiplier of BCLK to
* get the rounded down BCLK value.
*/
- factor = rt5682s_bclk_get_factor(rate, *parent_rate);
+ factor = rt5682s_bclk_get_factor(req->rate, req->best_parent_rate);
+
+ req->rate = req->best_parent_rate * factor;
- return *parent_rate * factor;
+ return 0;
}
static int rt5682s_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -2770,12 +2773,12 @@ static const struct clk_ops rt5682s_dai_clk_ops[RT5682S_DAI_NUM_CLKS] = {
.prepare = rt5682s_wclk_prepare,
.unprepare = rt5682s_wclk_unprepare,
.recalc_rate = rt5682s_wclk_recalc_rate,
- .round_rate = rt5682s_wclk_round_rate,
+ .determine_rate = rt5682s_wclk_determine_rate,
.set_rate = rt5682s_wclk_set_rate,
},
[RT5682S_DAI_BCLK_IDX] = {
.recalc_rate = rt5682s_bclk_recalc_rate,
- .round_rate = rt5682s_bclk_round_rate,
+ .determine_rate = rt5682s_bclk_determine_rate,
.set_rate = rt5682s_bclk_set_rate,
},
};
@@ -2829,7 +2832,9 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component)
}
if (dev->of_node) {
- devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw);
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, dai_clk_hw);
+ if (ret)
+ return ret;
} else {
ret = devm_clk_hw_register_clkdev(dev, dai_clk_hw,
init.name, dev_name(dev));
@@ -2972,9 +2977,8 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev)
&rt5682s->pdata.dmic_delay);
device_property_read_u32(dev, "realtek,amic-delay-ms",
&rt5682s->pdata.amic_delay);
-
- rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
+ device_property_read_u32(dev, "realtek,ldo-sel",
+ &rt5682s->pdata.ldo_dacref);
if (device_property_read_string_array(dev, "clock-output-names",
rt5682s->pdata.dai_clk_names,
@@ -3172,10 +3176,12 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5682s->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5682s"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+ rt5682s->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5682s->ldo1_en)) {
+ dev_err(&i2c->dev, "Fail gpio request ldo1_en\n");
+ return PTR_ERR(rt5682s->ldo1_en);
}
/* Sleep for 50 ms minimum */
@@ -3252,6 +3258,27 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
break;
}
+ /* LDO output voltage control */
+ switch (rt5682s->pdata.ldo_dacref) {
+ case RT5682S_LDO_1_607V:
+ break;
+ case RT5682S_LDO_1_5V:
+ regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7,
+ RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_5V);
+ break;
+ case RT5682S_LDO_1_406V:
+ regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7,
+ RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_406V);
+ break;
+ case RT5682S_LDO_1_731V:
+ regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7,
+ RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_731V);
+ break;
+ default:
+ dev_warn(&i2c->dev, "invalid LDO output setting.\n");
+ break;
+ }
+
INIT_DELAYED_WORK(&rt5682s->jack_detect_work, rt5682s_jack_detect_handler);
INIT_DELAYED_WORK(&rt5682s->jd_check_work, rt5682s_jd_check_handler);
@@ -3262,7 +3289,7 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
if (!ret)
rt5682s->irq = i2c->irq;
else
- dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
}
return devm_snd_soc_register_component(&i2c->dev, &rt5682s_soc_component_dev,
@@ -3298,7 +3325,7 @@ static const struct acpi_device_id rt5682s_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5682s_acpi_match);
static const struct i2c_device_id rt5682s_i2c_id[] = {
- {"rt5682s", 0},
+ {"rt5682s"},
{}
};
MODULE_DEVICE_TABLE(i2c, rt5682s_i2c_id);
diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h
index caa7733b430f..67f42898de96 100644
--- a/sound/soc/codecs/rt5682s.h
+++ b/sound/soc/codecs/rt5682s.h
@@ -11,6 +11,7 @@
#include <sound/rt5682s.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -1262,6 +1263,13 @@
#define RT5682S_JDH_NO_PLUG (0x1 << 4)
#define RT5682S_JDH_PLUG (0x0 << 4)
+/* Bias current control 7 (0x0110) */
+#define RT5682S_LDO_DACREF_MASK (0x3 << 4)
+#define RT5682S_LDO_DACREF_1_607V (0x0 << 4)
+#define RT5682S_LDO_DACREF_1_5V (0x1 << 4)
+#define RT5682S_LDO_DACREF_1_406V (0x2 << 4)
+#define RT5682S_LDO_DACREF_1_731V (0x3 << 4)
+
/* Charge Pump Internal Register1 (0x0125) */
#define RT5682S_CP_CLK_HP_MASK (0x3 << 4)
#define RT5682S_CP_CLK_HP_100KHZ (0x0 << 4)
@@ -1446,6 +1454,7 @@ enum {
struct rt5682s_priv {
struct snd_soc_component *component;
struct rt5682s_platform_data pdata;
+ struct gpio_desc *ldo1_en;
struct regmap *regmap;
struct snd_soc_jack *hs_jack;
struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES];
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 8b28e47775cc..44543c0da177 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt700_init(&slave->dev, sdw_regmap, regmap, slave);
-
- return 0;
+ return rt700_init(&slave->dev, sdw_regmap, regmap, slave);
}
static int rt700_sdw_remove(struct sdw_slave *slave)
@@ -466,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
cancel_delayed_work_sync(&rt700->jack_btn_check_work);
}
- if (rt700->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -478,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);
@@ -493,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);
@@ -523,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);
@@ -554,15 +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",
- .owner = THIS_MODULE,
- .pm = &rt700_pm,
+ .pm = pm_ptr(&rt700_pm),
},
.probe = rt700_sdw_probe,
.remove = rt700_sdw_remove,
diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c
index a04b9246256b..21523d0a5f08 100644
--- a/sound/soc/codecs/rt700.c
+++ b/sound/soc/codecs/rt700.c
@@ -37,8 +37,8 @@ static int rt700_index_write(struct regmap *regmap,
ret = regmap_write(regmap, addr, value);
if (ret < 0)
- pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
- addr, value, ret);
+ pr_err("%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -52,8 +52,8 @@ static int rt700_index_read(struct regmap *regmap,
*value = 0;
ret = regmap_read(regmap, addr, value);
if (ret < 0)
- pr_err("Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ pr_err("%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -272,11 +272,10 @@ io_error:
static void rt700_jack_init(struct rt700_priv *rt700)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(rt700->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt700->component);
/* power on */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt700->regmap,
RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -307,7 +306,7 @@ static void rt700_jack_init(struct rt700_priv *rt700)
}
/* power off */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt700->regmap,
RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
}
@@ -320,6 +319,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
rt700->hs_jack = hs_jack;
+ /* we can only resume if the device was initialized at least once */
+ if (!rt700->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -334,7 +337,6 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
rt700_jack_init(rt700);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return 0;
@@ -359,8 +361,7 @@ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
@@ -395,7 +396,7 @@ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol,
val_ll |= read_ll;
}
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt700->regmap,
RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -447,7 +448,7 @@ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol,
break;
}
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt700->regmap,
RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
return 0;
@@ -521,8 +522,7 @@ static const struct snd_kcontrol_new rt700_snd_controls[] = {
static int rt700_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
unsigned int reg, val = 0, nid;
int ret;
@@ -550,10 +550,8 @@ static int rt700_mux_get(struct snd_kcontrol *kcontrol,
static int rt700_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -823,6 +821,9 @@ static int rt700_probe(struct snd_soc_component *component)
rt700->component = component;
+ if (!rt700->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -833,13 +834,12 @@ static int rt700_probe(struct snd_soc_component *component)
static int rt700_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
regmap_write(rt700->regmap,
RT700_SET_AUDIO_POWER_STATE,
AC_PWRST_D0);
@@ -855,7 +855,7 @@ static int rt700_set_bias_level(struct snd_soc_component *component,
default:
break;
}
- dapm->bias_level = level;
+
return 0;
}
@@ -923,14 +923,14 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream,
port_config.num += 2;
break;
default:
- dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
+ dev_err(component->dev, "%s: Invalid DAI id %d\n", __func__, dai->id);
return -EINVAL;
}
retval = sdw_stream_add_slave(rt700->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
@@ -938,8 +938,8 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream,
/* bit 3:0 Number of Channel */
val |= (params_channels(params) - 1);
} else {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -1099,6 +1099,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
rt700->sdw_regmap = sdw_regmap;
rt700->regmap = regmap;
+ regcache_cache_only(rt700->regmap, true);
+
mutex_init(&rt700->disable_irq_lock);
INIT_DELAYED_WORK(&rt700->jack_detect_work,
@@ -1117,10 +1119,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
&soc_codec_dev_rt700,
rt700_dai,
ARRAY_SIZE(rt700_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
dev_dbg(&slave->dev, "%s\n", __func__);
- return ret;
+ return 0;
}
int rt700_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1132,28 +1150,17 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
if (rt700->hw_init)
return 0;
- if (rt700->first_hw_init) {
- regcache_cache_only(rt700->regmap, false);
+ regcache_cache_only(rt700->regmap, false);
+ if (rt700->first_hw_init)
regcache_cache_bypass(rt700->regmap, true);
- }
/*
* PM runtime is only enabled when a Slave reports as Attached
*/
- if (!rt700->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
- /* update count of parent 'active' children */
+ if (!rt700->first_hw_init)
+ /* PM runtime status is marked as 'active' only when a Slave reports as Attached */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
/* reset */
@@ -1216,7 +1223,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt700->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index 119e1f9605d7..6eb05871db37 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -225,6 +225,14 @@ static int rt711_sdca_read_prop(struct sdw_slave *slave)
j++;
}
+ prop->dp0_prop = devm_kzalloc(&slave->dev, sizeof(*prop->dp0_prop),
+ GFP_KERNEL);
+ if (!prop->dp0_prop)
+ return -ENOMEM;
+
+ prop->dp0_prop->simple_ch_prep_sm = true;
+ prop->dp0_prop->ch_prep_timeout = 10;
+
/* set the timeout values */
prop->clk_stop_timeout = 700;
@@ -366,8 +374,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
cancel_delayed_work_sync(&rt711->jack_btn_check_work);
}
- if (rt711->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
mutex_destroy(&rt711->calibrate_mutex);
mutex_destroy(&rt711->disable_irq_lock);
@@ -381,7 +388,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);
@@ -397,7 +404,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);
@@ -429,7 +436,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);
@@ -438,13 +445,21 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
if (!rt711->first_hw_init)
return 0;
- if (!slave->unattach_request)
+ if (!slave->unattach_request) {
+ mutex_lock(&rt711->disable_irq_lock);
+ if (rt711->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt711->disable_irq = false;
+ }
+ mutex_unlock(&rt711->disable_irq_lock);
goto regmap_sync;
+ }
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT711_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -460,15 +475,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",
- .owner = THIS_MODULE,
- .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-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 07640d2f6e56..3a26c782d800 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -36,8 +36,8 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711,
ret = regmap_write(regmap, addr, value);
if (ret < 0)
dev_err(&rt711->slave->dev,
- "Failed to set private value: %06x <= %04x ret=%d\n",
- addr, value, ret);
+ "%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -52,8 +52,8 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711,
ret = regmap_read(regmap, addr, value);
if (ret < 0)
dev_err(&rt711->slave->dev,
- "Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ "%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -81,6 +81,24 @@ static void rt711_sdca_reset(struct rt711_sdca_priv *rt711)
RT711_HDA_LEGACY_RESET_CTL, 0x1, 0x1);
}
+static void rt711_sdca_ge_force_jack_type(struct rt711_sdca_priv *rt711, unsigned int det_mode)
+{
+ switch (det_mode) {
+ case 0x00:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x0000);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x10, 0x00);
+ break;
+ case 0x03:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8000);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x13);
+ break;
+ case 0x05:
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL1, 0x8400, 0x8400);
+ rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, RT711_PUSH_BTN_INT_CTL0, 0x17, 0x15);
+ break;
+ }
+}
+
static int rt711_sdca_calibration(struct rt711_sdca_priv *rt711)
{
unsigned int val, loop_rc = 0, loop_dc = 0;
@@ -248,6 +266,8 @@ static int rt711_sdca_headset_detect(struct rt711_sdca_priv *rt711)
unsigned int det_mode;
int ret;
+ rt711_sdca_ge_force_jack_type(rt711, rt711->ge_mode_override);
+
/* get detected_mode */
ret = regmap_read(rt711->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0),
@@ -507,6 +527,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
rt711->hs_jack = hs_jack;
+ /* we can only resume if the device was initialized at least once */
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -521,7 +545,6 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
rt711_sdca_jack_init(rt711);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return 0;
@@ -786,6 +809,56 @@ static int rt711_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
return changed;
}
+static int rt711_sdca_ge_select_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned int val, item;
+
+ val = (rt711->ge_mode_override >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[0] = item;
+ return 0;
+}
+
+static int rt711_sdca_ge_select_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+ unsigned int val, change = 0;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+ if (rt711->ge_mode_override != val) {
+ rt711->ge_mode_override = val;
+ change = 1;
+ }
+
+ return change;
+}
+
+static const char * const rt711_sdca_ge_select[] = {
+ "Auto",
+ "Headphone",
+ "Headset",
+};
+
+static int rt711_sdca_ge_select_values[] = {
+ 0,
+ 3,
+ 5,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt711_sdca_ge_mode_enum, SND_SOC_NOPM,
+ 0, 0x7, rt711_sdca_ge_select, rt711_sdca_ge_select_values);
+
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
@@ -820,13 +893,14 @@ static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = {
SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R),
8, 3, 0,
rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, mic_vol_tlv),
+ SOC_ENUM_EXT("GE49 Selected Mode", rt711_sdca_ge_mode_enum,
+ rt711_sdca_ge_select_get, rt711_sdca_ge_select_put),
};
static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
unsigned int val = 0, mask_sft;
@@ -848,10 +922,8 @@ static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol,
static int rt711_sdca_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -1215,6 +1287,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
rt711_sdca_parse_dt(rt711, &rt711->slave->dev);
rt711->component = component;
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -1286,13 +1361,13 @@ static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt711->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
if (params_channels(params) > 16) {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -1311,8 +1386,8 @@ static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
sampling_rate = RT711_SDCA_RATE_192000HZ;
break;
default:
- dev_err(component->dev, "Rate %d is not supported\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -1406,6 +1481,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
rt711->regmap = regmap;
rt711->mbq_regmap = mbq_regmap;
+ regcache_cache_only(rt711->regmap, true);
+ regcache_cache_only(rt711->mbq_regmap, true);
+
mutex_init(&rt711->calibrate_mutex);
mutex_init(&rt711->disable_irq_lock);
@@ -1431,9 +1509,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
rt711_sdca_dai,
ARRAY_SIZE(rt711_sdca_dai));
- dev_dbg(&slave->dev, "%s\n", __func__);
+ if (ret < 0)
+ return ret;
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711)
@@ -1500,27 +1596,19 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt711->hw_init)
return 0;
+ regcache_cache_only(rt711->regmap, false);
+ regcache_cache_only(rt711->mbq_regmap, false);
+
if (rt711->first_hw_init) {
- regcache_cache_only(rt711->regmap, false);
regcache_cache_bypass(rt711->regmap, true);
- regcache_cache_only(rt711->mbq_regmap, false);
regcache_cache_bypass(rt711->mbq_regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -1570,7 +1658,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt711->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h
index 11d421e8ab2b..15263dcb0314 100644
--- a/sound/soc/codecs/rt711-sdca.h
+++ b/sound/soc/codecs/rt711-sdca.h
@@ -33,6 +33,7 @@ struct rt711_sdca_priv {
int hw_ver;
bool fu0f_dapm_mute, fu0f_mixer_l_mute, fu0f_mixer_r_mute;
bool fu1e_dapm_mute, fu1e_mixer_l_mute, fu1e_mixer_r_mute;
+ unsigned int ge_mode_override;
};
/* NID */
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index 87dafcb4545d..93a5a89a96b1 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -38,7 +38,9 @@ static bool rt711_readable_register(struct device *dev, unsigned int reg)
case 0x8300 ... 0x83ff:
case 0x9c00 ... 0x9cff:
case 0xb900 ... 0xb9ff:
+ case 0x752008:
case 0x752009:
+ case 0x75200b:
case 0x752011:
case 0x75201a:
case 0x752045:
@@ -408,7 +410,7 @@ static int rt711_bus_config(struct sdw_slave *slave,
ret = rt711_clock_config(&slave->dev);
if (ret < 0)
- dev_err(&slave->dev, "Invalid clk config");
+ dev_err(&slave->dev, "%s: Invalid clk config", __func__);
return ret;
}
@@ -453,9 +455,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt711_init(&slave->dev, sdw_regmap, regmap, slave);
-
- return 0;
+ return rt711_init(&slave->dev, sdw_regmap, regmap, slave);
}
static int rt711_sdw_remove(struct sdw_slave *slave)
@@ -468,8 +468,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
cancel_work_sync(&rt711->calibration_work);
}
- if (rt711->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
mutex_destroy(&rt711->calibrate_mutex);
mutex_destroy(&rt711->disable_irq_lock);
@@ -483,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);
@@ -499,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);
@@ -529,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);
@@ -538,13 +537,20 @@ static int __maybe_unused rt711_dev_resume(struct device *dev)
if (!rt711->first_hw_init)
return 0;
- if (!slave->unattach_request)
+ if (!slave->unattach_request) {
+ mutex_lock(&rt711->disable_irq_lock);
+ if (rt711->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
+ rt711->disable_irq = false;
+ }
+ mutex_unlock(&rt711->disable_irq_lock);
goto regmap_sync;
+ }
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT711_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -558,15 +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",
- .owner = THIS_MODULE,
- .pm = &rt711_pm,
+ .pm = pm_ptr(&rt711_pm),
},
.probe = rt711_sdw_probe,
.remove = rt711_sdw_remove,
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index af53cbcc7bf2..5dbe9b67703e 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -37,8 +37,8 @@ static int rt711_index_write(struct regmap *regmap,
ret = regmap_write(regmap, addr, value);
if (ret < 0)
- pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
- addr, value, ret);
+ pr_err("%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -52,8 +52,8 @@ static int rt711_index_read(struct regmap *regmap,
*value = 0;
ret = regmap_read(regmap, addr, value);
if (ret < 0)
- pr_err("Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ pr_err("%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -360,12 +360,11 @@ io_error:
static void rt711_jack_init(struct rt711_priv *rt711)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(rt711->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt711->component);
mutex_lock(&rt711->calibrate_mutex);
/* power on */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -428,7 +427,7 @@ static void rt711_jack_init(struct rt711_priv *rt711)
RT711_HP_JD_FINAL_RESULT_CTL_JD12);
break;
default:
- dev_warn(rt711->component->dev, "Wrong JD source\n");
+ dev_warn(rt711->component->dev, "%s: Wrong JD source\n", __func__);
break;
}
@@ -448,7 +447,7 @@ static void rt711_jack_init(struct rt711_priv *rt711)
}
/* power off */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
mutex_unlock(&rt711->calibrate_mutex);
@@ -462,6 +461,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
rt711->hs_jack = hs_jack;
+ /* we can only resume if the device was initialized at least once */
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -476,7 +479,6 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
rt711_jack_init(rt711);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return 0;
@@ -501,8 +503,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
@@ -540,7 +541,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
val_ll |= read_ll;
}
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -594,7 +595,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
break;
}
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
@@ -679,8 +680,7 @@ static const struct snd_kcontrol_new rt711_snd_controls[] = {
static int rt711_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
unsigned int reg, val = 0, nid;
int ret;
@@ -709,10 +709,8 @@ static int rt711_mux_get(struct snd_kcontrol *kcontrol,
static int rt711_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -897,13 +895,12 @@ static const struct snd_soc_dapm_route rt711_audio_map[] = {
static int rt711_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE,
AC_PWRST_D0);
@@ -941,6 +938,9 @@ static int rt711_probe(struct snd_soc_component *component)
rt711_parse_dt(rt711, &rt711->slave->dev);
rt711->component = component;
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -1013,7 +1013,7 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt711->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
@@ -1021,8 +1021,8 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream,
/* bit 3:0 Number of Channel */
val |= (params_channels(params) - 1);
} else {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -1183,6 +1183,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
rt711->sdw_regmap = sdw_regmap;
rt711->regmap = regmap;
+ regcache_cache_only(rt711->regmap, true);
+
mutex_init(&rt711->calibrate_mutex);
mutex_init(&rt711->disable_irq_lock);
@@ -1204,8 +1206,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
&soc_codec_dev_rt711,
rt711_dai,
ARRAY_SIZE(rt711_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
- dev_dbg(&slave->dev, "%s\n", __func__);
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -1219,28 +1238,17 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
if (rt711->hw_init)
return 0;
- if (rt711->first_hw_init) {
- regcache_cache_only(rt711->regmap, false);
+ regcache_cache_only(rt711->regmap, false);
+ if (rt711->first_hw_init)
regcache_cache_bypass(rt711->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt711->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt711->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
rt711_reset(rt711->regmap);
@@ -1316,7 +1324,6 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt711->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 869cc7bfd178..2928649e80e4 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -139,8 +139,8 @@ static int rt712_sdca_dmic_index_write(struct rt712_sdca_dmic_priv *rt712,
ret = regmap_write(regmap, addr, value);
if (ret < 0)
dev_err(&rt712->slave->dev,
- "Failed to set private value: %06x <= %04x ret=%d\n",
- addr, value, ret);
+ "%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -155,8 +155,8 @@ static int rt712_sdca_dmic_index_read(struct rt712_sdca_dmic_priv *rt712,
ret = regmap_read(regmap, addr, value);
if (ret < 0)
dev_err(&rt712->slave->dev,
- "Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ "%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -182,27 +182,18 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave)
if (rt712->hw_init)
return 0;
+ regcache_cache_only(rt712->regmap, false);
+ regcache_cache_only(rt712->mbq_regmap, false);
if (rt712->first_hw_init) {
- regcache_cache_only(rt712->regmap, false);
regcache_cache_bypass(rt712->regmap, true);
- regcache_cache_only(rt712->mbq_regmap, false);
regcache_cache_bypass(rt712->mbq_regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -245,7 +236,6 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt712->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
@@ -272,12 +262,8 @@ static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
if (!adc_vol_flag) /* boost gain */
ctl = regvalue / 0x0a00;
- else { /* ADC gain */
- if (adc_vol_flag)
- ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
- else
- ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
- }
+ else /* ADC gain */
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
ucontrol->value.integer.value[i] = ctl;
}
@@ -326,7 +312,8 @@ static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
for (i = 0; i < p->count; i++) {
err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]);
if (err < 0)
- dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+ dev_err(&rt712->slave->dev, "%s: 0x%08x can't be set\n",
+ __func__, p->reg_base + i);
}
return changed;
@@ -442,8 +429,7 @@ static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = {
static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt712_sdca_dmic_priv *rt712 = snd_soc_component_get_drvdata(component);
unsigned int val = 0, mask_sft;
@@ -465,10 +451,8 @@ static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol,
static int rt712_sdca_dmic_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt712_sdca_dmic_priv *rt712 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -608,6 +592,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
rt712->component = component;
+ if (!rt712->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -673,13 +660,13 @@ static int rt712_sdca_dmic_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt712->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
if (params_channels(params) > 4) {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -704,8 +691,8 @@ static int rt712_sdca_dmic_hw_params(struct snd_pcm_substream *substream,
sampling_rate = RT712_SDCA_RATE_192000HZ;
break;
default:
- dev_err(component->dev, "Rate %d is not supported\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -777,6 +764,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
rt712->regmap = regmap;
rt712->mbq_regmap = mbq_regmap;
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -791,10 +781,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
&soc_sdca_dev_rt712_dmic,
rt712_sdca_dmic_dai,
ARRAY_SIZE(rt712_sdca_dmic_dai));
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
@@ -869,7 +876,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);
@@ -882,7 +889,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);
@@ -894,7 +901,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);
@@ -909,7 +916,8 @@ static int __maybe_unused rt712_sdca_dmic_dev_resume(struct device *dev)
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT712_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n",
+ __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -925,12 +933,12 @@ 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)
};
-static struct sdw_slave_ops rt712_sdca_dmic_slave_ops = {
+static const struct sdw_slave_ops rt712_sdca_dmic_slave_ops = {
.read_prop = rt712_sdca_dmic_read_prop,
.update_status = rt712_sdca_dmic_update_status,
};
@@ -954,10 +962,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave,
static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave)
{
- struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev);
-
- if (rt712->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -965,8 +970,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",
- .owner = THIS_MODULE,
- .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 ad06267b0ea0..ea07131edfa2 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -34,6 +34,10 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg)
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
return true;
default:
@@ -56,6 +60,10 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg)
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
return true;
default:
@@ -78,13 +86,21 @@ static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5c00000 ... 0x5c0009a:
case 0x5d00000 ... 0x5d00009:
case 0x5f00000 ... 0x5f00030:
- case 0x6100000 ... 0x6100068:
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L):
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R):
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L):
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R):
- case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L):
- case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R):
+ case 0x6100000 ... 0x61000f1:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04):
return true;
default:
return false;
@@ -96,7 +112,9 @@ static bool rt712_sdca_mbq_volatile_register(struct device *dev, unsigned int re
switch (reg) {
case 0x2000000:
case 0x200001a:
+ case 0x2000020:
case 0x2000024:
+ case 0x2000030:
case 0x2000046:
case 0x200008a:
case 0x5800000:
@@ -178,13 +196,15 @@ static int rt712_sdca_read_prop(struct sdw_slave *slave)
unsigned long addr;
struct sdw_dpn_prop *dpn;
+ sdw_slave_read_prop(slave);
+
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->paging_support = true;
/* first we need to allocate memory for set bits in port lists */
- prop->source_ports = BIT(4); /* BITMAP: 00010000 */
+ prop->source_ports = BIT(8) | BIT(4); /* BITMAP: 100010000 */
prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */
nval = hweight32(prop->source_ports);
@@ -331,7 +351,7 @@ io_error:
return ret;
}
-static struct sdw_slave_ops rt712_sdca_slave_ops = {
+static const struct sdw_slave_ops rt712_sdca_slave_ops = {
.read_prop = rt712_sdca_read_prop,
.interrupt_callback = rt712_sdca_interrupt_callback,
.update_status = rt712_sdca_update_status,
@@ -363,8 +383,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave)
cancel_delayed_work_sync(&rt712->jack_btn_check_work);
}
- if (rt712->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
mutex_destroy(&rt712->calibrate_mutex);
mutex_destroy(&rt712->disable_irq_lock);
@@ -381,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);
@@ -397,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);
@@ -429,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);
@@ -438,13 +457,22 @@ static int __maybe_unused rt712_sdca_dev_resume(struct device *dev)
if (!rt712->first_hw_init)
return 0;
- if (!slave->unattach_request)
+ if (!slave->unattach_request) {
+ mutex_lock(&rt712->disable_irq_lock);
+ if (rt712->disable_irq == true) {
+
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt712->disable_irq = false;
+ }
+ mutex_unlock(&rt712->disable_irq_lock);
goto regmap_sync;
+ }
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT712_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -460,15 +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",
- .owner = THIS_MODULE,
- .pm = &rt712_sdca_pm,
+ .pm = pm_ptr(&rt712_sdca_pm),
},
.probe = rt712_sdca_sdw_probe,
.remove = rt712_sdca_sdw_remove,
@@ -480,3 +507,4 @@ module_sdw_driver(rt712_sdca_sdw_driver);
MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver");
MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index 4be22ccd8561..99fd2d67f04d 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -12,68 +12,31 @@
#include <linux/soundwire/sdw_registers.h>
static const struct reg_default rt712_sdca_reg_defaults[] = {
- { 0x201a, 0x00 },
- { 0x201b, 0x00 },
- { 0x201c, 0x00 },
- { 0x201d, 0x00 },
- { 0x201e, 0x00 },
- { 0x201f, 0x00 },
- { 0x2029, 0x00 },
- { 0x202a, 0x00 },
- { 0x202d, 0x00 },
- { 0x202e, 0x00 },
- { 0x202f, 0x00 },
- { 0x2030, 0x00 },
- { 0x2031, 0x00 },
- { 0x2032, 0x00 },
- { 0x2033, 0x00 },
- { 0x2034, 0x00 },
- { 0x2230, 0x00 },
- { 0x2231, 0x2f },
- { 0x2232, 0x80 },
- { 0x2f01, 0x00 },
- { 0x2f02, 0x09 },
- { 0x2f03, 0x00 },
- { 0x2f04, 0x00 },
- { 0x2f05, 0x0b },
- { 0x2f06, 0x01 },
- { 0x2f08, 0x00 },
- { 0x2f09, 0x00 },
- { 0x2f0a, 0x01 },
- { 0x2f35, 0x01 },
- { 0x2f36, 0xcf },
- { 0x2f50, 0x0f },
- { 0x2f54, 0x01 },
- { 0x2f58, 0x07 },
- { 0x2f59, 0x09 },
- { 0x2f5a, 0x01 },
- { 0x2f5b, 0x07 },
- { 0x2f5c, 0x05 },
- { 0x2f5d, 0x05 },
- { 0x3201, 0x01 },
- { 0x320c, 0x00 },
- { 0x3301, 0x01 },
- { 0x3302, 0x00 },
- { 0x3303, 0x1f },
+
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x2000004, 0xaa01 },
{ 0x200000e, 0x21e0 },
- { 0x2000024, 0x01ba },
{ 0x200004a, 0x8830 },
{ 0x2000067, 0xf100 },
{ 0x5800000, 0x1893 },
@@ -81,12 +44,8 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x5b00005, 0x0000 },
{ 0x5b00029, 0x3fff },
{ 0x5b0002a, 0xf000 },
- { 0x5f00008, 0x7000 },
+ { 0x6100000, 0x04e4 },
{ 0x610000e, 0x0007 },
- { 0x6100022, 0x2828 },
- { 0x6100023, 0x2929 },
- { 0x6100026, 0x2c29 },
- { 0x610002c, 0x4150 },
{ 0x6100045, 0x0860 },
{ 0x6100046, 0x0029 },
{ 0x6100053, 0x3fff },
@@ -95,14 +54,22 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x6100064, 0x8000 },
{ 0x6100065, 0x0000 },
{ 0x6100067, 0xff12 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
};
#endif /* __RT712_SDW_H__ */
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index 89d245655ca4..4796fce084ff 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdca.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
@@ -34,8 +35,8 @@ static int rt712_sdca_index_write(struct rt712_sdca_priv *rt712,
ret = regmap_write(regmap, addr, value);
if (ret < 0)
dev_err(&rt712->slave->dev,
- "Failed to set private value: %06x <= %04x ret=%d\n",
- addr, value, ret);
+ "%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -50,8 +51,8 @@ static int rt712_sdca_index_read(struct rt712_sdca_priv *rt712,
ret = regmap_read(regmap, addr, value);
if (ret < 0)
dev_err(&rt712->slave->dev,
- "Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ "%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -82,7 +83,8 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
dev = regmap_get_device(regmap);
/* Set HP-JD source from JD1 */
- rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+ if (rt712->version_id == RT712_VA)
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
/* FSM switch to calibration manual mode */
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100);
@@ -198,11 +200,17 @@ static unsigned int rt712_sdca_button_detect(struct rt712_sdca_priv *rt712)
_end_btn_det_:
/* Host is owner, so set back to device */
- if (owner == 0)
+ if (owner == 0) {
/* set owner to device */
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
- RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+ if (rt712->version_id == RT712_VA)
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+ RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+ else
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+ RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+ }
return btn_type;
}
@@ -415,8 +423,9 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
switch (rt712->jd_src) {
case RT712_JD1:
- /* Set HP-JD source from JD1 */
- rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+ /* Set HP-JD source from JD1, VB uses JD1 in default */
+ if (rt712->version_id == RT712_VA)
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
break;
default:
dev_warn(rt712->component->dev, "Wrong JD source\n");
@@ -453,6 +462,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
rt712->hs_jack = hs_jack;
+ if (!rt712->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -467,7 +479,6 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
rt712_sdca_jack_init(rt712);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return 0;
@@ -589,20 +600,20 @@ static int rt712_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
static int rt712_sdca_set_fu0f_capture_ctl(struct rt712_sdca_priv *rt712)
{
int err;
- unsigned int ch_l, ch_r;
+ unsigned int ch_01, ch_02;
- ch_l = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00;
- ch_r = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+ ch_01 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00;
err = regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F,
- RT712_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ 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_FU0F,
- RT712_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02);
if (err < 0)
return err;
@@ -640,34 +651,91 @@ 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);
static const struct snd_kcontrol_new rt712_sdca_controls[] = {
SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x57, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv),
SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
rt712_sdca_fu0f_capture_get, rt712_sdca_fu0f_capture_put),
SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x3f, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, mic_vol_tlv),
SOC_DOUBLE_R_EXT_TLV("FU44 Boost Volume",
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+ 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[] = {
SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02),
0, 0x57, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv),
};
@@ -675,8 +743,7 @@ static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = {
static int rt712_sdca_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
unsigned int val = 0, mask = 0x3300;
@@ -700,10 +767,8 @@ static int rt712_sdca_mux_get(struct snd_kcontrol *kcontrol,
static int rt712_sdca_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -754,28 +819,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_L),
- unmute);
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_R),
- 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_L),
- mute);
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_R),
- mute);
+ rt712->fu05_dapm_mute = true;
+ rt712_sdca_set_fu05_playback_ctl(rt712);
break;
}
return 0;
@@ -851,7 +903,7 @@ static int rt712_sdca_pde12_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
+static int rt712_sdca_pde23_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component =
@@ -880,10 +932,13 @@ static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static const struct snd_kcontrol_new rt712_spk_sto_dac =
- SOC_DAPM_DOUBLE_R("Switch",
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L),
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R),
+static const struct snd_kcontrol_new rt712_spk_l_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01),
+ 0, 1, 1);
+static const struct snd_kcontrol_new rt712_spk_r_dac =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02),
0, 1, 1);
static const struct snd_soc_dapm_widget rt712_sdca_dapm_widgets[] = {
@@ -928,20 +983,26 @@ static const struct snd_soc_dapm_widget rt712_sdca_spk_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
/* Digital Interface */
- SND_SOC_DAPM_SWITCH("FU06", SND_SOC_NOPM, 0, 0, &rt712_spk_sto_dac),
+ SND_SOC_DAPM_PGA("FU06", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt712_sdca_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
/* Output */
- SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
- rt712_sdca_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt712_spk_l_dac),
+ SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt712_spk_r_dac),
SND_SOC_DAPM_OUTPUT("SPOL"),
SND_SOC_DAPM_OUTPUT("SPOR"),
};
static const struct snd_soc_dapm_route rt712_sdca_spk_dapm_routes[] = {
- { "FU06", "Switch", "DP3RX" },
- { "CLASS D", NULL, "FU06" },
- { "SPOL", NULL, "CLASS D" },
- { "SPOR", NULL, "CLASS D" },
+ { "FU06", NULL, "DP3RX" },
+ { "FU06", NULL, "PDE 23" },
+ { "OT23 L", "Switch", "FU06" },
+ { "OT23 R", "Switch", "FU06" },
+ { "SPOL", NULL, "OT23 L" },
+ { "SPOR", NULL, "OT23 R" },
};
static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev)
@@ -953,17 +1014,13 @@ static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev
static int rt712_sdca_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
int ret;
rt712_sdca_parse_dt(rt712, &rt712->slave->dev);
rt712->component = component;
- ret = pm_runtime_resume(component->dev);
- if (ret < 0 && ret != -EACCES)
- return ret;
-
/* add SPK route */
if (rt712->hw_id != RT712_DEV_ID_713) {
snd_soc_add_component_controls(component,
@@ -974,6 +1031,376 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
rt712_sdca_spk_dapm_routes, ARRAY_SIZE(rt712_sdca_spk_dapm_routes));
}
+ if (!rt712->first_hw_init)
+ return 0;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int regvalue, ctl, i;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue);
+
+ if (!adc_vol_flag) /* boost gain */
+ ctl = regvalue / 0x0a00;
+ else /* ADC gain */
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ unsigned int gain_val[4];
+ unsigned int i, adc_vol_flag = 0, changed = 0;
+ unsigned int regvalue[4];
+ const unsigned int interval_offset = 0xc0;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue[i]);
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ if (!adc_vol_flag) /* boost gain */
+ gain_val[i] = gain_val[i] * 0x0a00;
+ else { /* ADC gain */
+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ }
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+static int rt712_sdca_set_fu1e_capture_ctl(struct rt712_sdca_priv *rt712)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt712->fu1e_mixer_mute); i++) {
+ ch_mute = (rt712->fu1e_dapm_mute || rt712->fu1e_mixer_mute[i]) ? 0x01 : 0x00;
+ err = regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E,
+ RT712_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_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);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt712->fu1e_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_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);
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt712->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt712->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt712_sdca_set_fu1e_capture_ctl(rt712);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt712_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt712_dmic_kctrl_priv *p =
+ (struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+#define RT712_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+ ((unsigned long)&(struct rt712_dmic_kctrl_priv) \
+ {.reg_base = xreg_base, .count = xcount, .max = xmax, \
+ .invert = xinvert})
+
+#define RT712_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = rt712_sdca_fu_info, \
+ .get = rt712_sdca_dmic_fu1e_capture_get, \
+ .put = rt712_sdca_dmic_fu1e_capture_put, \
+ .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT712_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+ xhandler_put, xcount, xmax, 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 = rt712_sdca_fu_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = {
+ RT712_SDCA_FU_CTRL("FU1E Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01),
+ 1, 1, 4),
+ RT712_SDCA_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+ rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 0x3f, in_vol_tlv),
+ RT712_SDCA_EXT_TLV("FU15 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+ rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 3, dmic_vol_tlv),
+};
+
+static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft;
+
+ if (strstr(ucontrol->id.name, "ADC 0A Mux"))
+ mask_sft = 0;
+ else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+ mask_sft = 4;
+ else
+ return -EINVAL;
+
+ rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_MUX_CTL0, &val);
+
+ ucontrol->value.enumerated.item[0] = (((val >> mask_sft) & 0xf) == 0x4) ? 0 : 1;
+
+ return 0;
+}
+
+static int rt712_sdca_dmic_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct rt712_sdca_priv *rt712 = 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 0A Mux"))
+ mask_sft = 0;
+ else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+ mask_sft = 4;
+ else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+ rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_MUX_CTL0, &val2);
+ val2 = ((0xf << mask_sft) & val2) >> mask_sft;
+
+ if (val == 0)
+ val = 0x4;
+ else if (val >= 1)
+ val = 0xe;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change)
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+ RT712_HDA_LEGACY_MUX_CTL0, 0xf << mask_sft,
+ val << mask_sft);
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc_dmic_mux_text[] = {
+ "DMIC1",
+ "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt712_adc0a_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt712_adc0b_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0a_mux =
+ SOC_DAPM_ENUM_EXT("ADC 0A Mux", rt712_adc0a_enum,
+ rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0b_mux =
+ SOC_DAPM_ENUM_EXT("ADC 0B Mux", rt712_adc0b_enum,
+ rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static int rt712_sdca_dmic_fu1e_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt712->fu1e_dapm_mute = false;
+ rt712_sdca_set_fu1e_capture_ctl(rt712);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt712->fu1e_dapm_mute = true;
+ rt712_sdca_set_fu1e_capture_ctl(rt712);
+ break;
+ }
+ return 0;
+}
+
+static int rt712_sdca_dmic_pde11_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 rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+ RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+ RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt712_sdca_dmic_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt712_sdca_dmic_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0,
+ rt712_sdca_dmic_fu1e_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 0A Mux", SND_SOC_NOPM, 0, 0,
+ &rt712_sdca_dmic_adc0a_mux),
+ SND_SOC_DAPM_MUX("ADC 0B Mux", SND_SOC_NOPM, 0, 0,
+ &rt712_sdca_dmic_adc0b_mux),
+
+ SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt712_sdca_dmic_audio_map[] = {
+ {"DP8TX", NULL, "FU 1E"},
+
+ {"FU 1E", NULL, "PDE 11"},
+ {"FU 1E", NULL, "ADC 0A Mux"},
+ {"FU 1E", NULL, "ADC 0B Mux"},
+ {"ADC 0A Mux", "DMIC1", "DMIC1"},
+ {"ADC 0A Mux", "DMIC2", "DMIC2"},
+ {"ADC 0B Mux", "DMIC1", "DMIC1"},
+ {"ADC 0B Mux", "DMIC2", "DMIC2"},
+};
+
+static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
+{
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt712->dmic_component = component;
+
+ if (!rt712->first_hw_init)
+ return 0;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
return 0;
}
@@ -989,6 +1416,20 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
.endianness = 1,
};
+static const struct snd_soc_component_driver soc_sdca_dev_rt712_dmic = {
+ .probe = rt712_sdca_dmic_probe,
+ .controls = rt712_sdca_dmic_snd_controls,
+ .num_controls = ARRAY_SIZE(rt712_sdca_dmic_snd_controls),
+ .dapm_widgets = rt712_sdca_dmic_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt712_sdca_dmic_dapm_widgets),
+ .dapm_routes = rt712_sdca_dmic_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt712_sdca_dmic_audio_map),
+ .endianness = 1,
+#ifdef CONFIG_DEBUG_FS
+ .debugfs_prefix = "dmic",
+#endif
+};
+
static int rt712_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
int direction)
{
@@ -1016,7 +1457,7 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
int retval, port, num_channels;
unsigned int sampling_rate;
- dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!sdw_stream)
@@ -1025,6 +1466,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
if (!rt712->slave)
return -EINVAL;
+ /* VA doesn't support AIF3 */
+ if (dai->id == RT712_AIF3 && rt712->version_id == RT712_VA)
+ return -EINVAL;
+
/* SoundWire specific configuration */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
direction = SDW_DATA_DIR_RX;
@@ -1038,6 +1483,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
direction = SDW_DATA_DIR_TX;
if (dai->id == RT712_AIF1)
port = 4;
+ else if (dai->id == RT712_AIF3)
+ port = 8;
else
return -EINVAL;
}
@@ -1054,13 +1501,13 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt712->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
if (params_channels(params) > 16) {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -1079,8 +1526,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
sampling_rate = RT712_SDCA_RATE_192000HZ;
break;
default:
- dev_err(component->dev, "Rate %d is not supported\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -1099,8 +1546,16 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
sampling_rate);
break;
+ case RT712_AIF3:
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ sampling_rate);
+ break;
default:
- dev_err(component->dev, "Wrong DAI id\n");
+ dev_err(component->dev, "%s: Wrong DAI id\n", __func__);
return -EINVAL;
}
@@ -1168,6 +1623,21 @@ static struct snd_soc_dai_driver rt712_sdca_dai[] = {
}
};
+static struct snd_soc_dai_driver rt712_sdca_dmic_dai[] = {
+ {
+ .name = "rt712-sdca-aif3",
+ .id = RT712_AIF3,
+ .capture = {
+ .stream_name = "DP8 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT712_STEREO_RATES,
+ .formats = RT712_FORMATS,
+ },
+ .ops = &rt712_sdca_ops,
+ }
+};
+
int rt712_sdca_init(struct device *dev, struct regmap *regmap,
struct regmap *mbq_regmap, struct sdw_slave *slave)
{
@@ -1183,6 +1653,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
rt712->regmap = regmap;
rt712->mbq_regmap = mbq_regmap;
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+
mutex_init(&rt712->calibrate_mutex);
mutex_init(&rt712->disable_irq_lock);
@@ -1197,6 +1670,11 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
rt712->first_hw_init = false;
rt712->fu0f_dapm_mute = true;
rt712->fu0f_mixer_l_mute = rt712->fu0f_mixer_r_mute = true;
+ 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;
@@ -1207,50 +1685,45 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
else
ret = devm_snd_soc_register_component(dev,
&soc_sdca_dev_rt712, rt712_sdca_dai, 1);
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
-
- return ret;
-}
-
-int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
-{
- struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
- int ret = 0;
- unsigned int val, hibernation_flag;
-
- rt712->disable_irq = false;
-
- if (rt712->hw_init)
- return 0;
+ /* only add the dmic component if a SMART_MIC function is exposed in ACPI */
+ if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) {
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt712_dmic,
+ rt712_sdca_dmic_dai,
+ ARRAY_SIZE(rt712_sdca_dmic_dai));
+ if (ret < 0)
+ return ret;
+ rt712->dmic_function_found = true;
+ }
- if (rt712->first_hw_init) {
- regcache_cache_only(rt712->regmap, false);
- regcache_cache_bypass(rt712->regmap, true);
- regcache_cache_only(rt712->mbq_regmap, false);
- regcache_cache_bypass(rt712->mbq_regmap, true);
- } else {
- /*
- * PM runtime is only enabled when a Slave reports as Attached
- */
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
- /* update count of parent 'active' children */
- pm_runtime_set_active(&slave->dev);
+ pm_runtime_enable(dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
- pm_runtime_enable(&slave->dev);
- }
+ dev_dbg(dev, "%s\n", __func__);
- pm_runtime_get_noresume(&slave->dev);
+ return 0;
+}
- rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
- rt712->hw_id = (val & 0xf000) >> 12;
+static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712)
+{
+ int ret = 0;
+ unsigned int hibernation_flag;
+ struct device *dev = &rt712->slave->dev;
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
@@ -1290,6 +1763,135 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
regmap_write(rt712->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
}
+}
+
+static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
+{
+ int ret = 0;
+ unsigned int jack_func_status, mic_func_status, amp_func_status;
+ struct device *dev = &rt712->slave->dev;
+
+ regmap_read(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status);
+ regmap_read(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status);
+ regmap_read(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+ dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n",
+ __func__, jack_func_status, mic_func_status, amp_func_status);
+
+ /* DMIC */
+ if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_CH12_FLOAT_CTL, 0x0304);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL, 0x1f1e);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0B_FU_CH12_FLOAT_CTL, 0x0304);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_HDA_LEGACY_CONFIG_CTL0, 0x8010);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT11, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ rt712_sdca_index_write(rt712, RT712_ULTRA_SOUND_DET, RT712_ULTRA_SOUND_DETECTOR6, 0x3200);
+ regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+
+ /* clear flag */
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+
+ /* Jack */
+ if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+ rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_SEL_VEE2_HP_CTL1, 0x042a);
+ rt712_sdca_index_write(rt712, RT712_CHARGE_PUMP, RT712_HP_DET_CTL3, 0x1fff);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec67);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL1, 0x0000);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL2, 0x0000);
+ regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL1, 0x2802);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL6, 0xf215);
+
+ /* calibration */
+ ret = rt712_sdca_calibration(rt712);
+ if (ret < 0)
+ dev_err(dev, "%s, calibration failed!\n", __func__);
+
+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, RT712_MIXER_CTL1, 0x3000, 0x0000);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_IT09, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_MISC_CTL_FOR_UAJ, 0x0003);
+
+ /* clear flag */
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+
+ /* SPK */
+ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+ if (rt712->hw_id != RT712_DEV_ID_713) {
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec63);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL1, 0xfff5);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_EAPD_CTL, 0x0002);
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+ }
+ /* clear flag */
+ regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
+}
+
+int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
+ unsigned int val;
+ struct sdw_slave_prop *prop = &slave->prop;
+
+ rt712->disable_irq = false;
+
+ if (rt712->hw_init)
+ return 0;
+
+ regcache_cache_only(rt712->regmap, false);
+ regcache_cache_only(rt712->mbq_regmap, false);
+ if (rt712->first_hw_init) {
+ regcache_cache_bypass(rt712->regmap, true);
+ regcache_cache_bypass(rt712->mbq_regmap, true);
+ } else {
+ /*
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
+ */
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
+ rt712->hw_id = (val & 0xf000) >> 12;
+ rt712->version_id = (val & 0x0f00) >> 8;
+ dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
+
+ if (rt712->version_id == RT712_VA) {
+ if (rt712->dmic_function_found) {
+ dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n",
+ __func__);
+ goto suspend;
+ }
+
+ rt712_sdca_va_io_init(rt712);
+ } else {
+ if (!rt712->dmic_function_found)
+ dev_warn(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n",
+ __func__);
+
+ /* multilanes and DMIC are supported by rt712vb */
+ prop->lane_control_support = true;
+ rt712_sdca_vb_io_init(rt712);
+ }
/*
* if set_jack callback occurred early than io_init,
@@ -1298,8 +1900,7 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt712->hs_jack)
rt712_sdca_jack_init(rt712);
- if (!hibernation_flag)
- rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
if (rt712->first_hw_init) {
regcache_cache_bypass(rt712->regmap, false);
@@ -1312,10 +1913,11 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt712->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+
+suspend:
pm_runtime_put_autosuspend(&slave->dev);
- dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
return 0;
}
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index ff79e03118ce..7ab7d5feb50a 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -19,6 +19,7 @@ struct rt712_sdca_priv {
struct regmap *regmap;
struct regmap *mbq_regmap;
struct snd_soc_component *component;
+ struct snd_soc_component *dmic_component;
struct sdw_slave *slave;
struct sdw_bus_params params;
bool hw_init;
@@ -34,13 +35,35 @@ struct rt712_sdca_priv {
unsigned int scp_sdca_stat1;
unsigned int scp_sdca_stat2;
unsigned int hw_id;
+ unsigned int version_id;
+ bool dmic_function_found;
bool fu0f_dapm_mute;
bool fu0f_mixer_l_mute;
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 {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+/* SDCA (Channel) */
+#define CH_01 0x01
+#define CH_02 0x02
+#define CH_03 0x03
+#define CH_04 0x04
+
/* NID */
#define RT712_VENDOR_REG 0x20
+#define RT712_EQ_CTRL 0x53
+#define RT712_CHARGE_PUMP 0x57
#define RT712_VENDOR_CALI 0x58
#define RT712_ULTRA_SOUND_DET 0x59
#define RT712_VENDOR_IMS_DRE 0x5b
@@ -50,9 +73,13 @@ struct rt712_sdca_priv {
/* Index (NID:20h) */
#define RT712_JD_PRODUCT_NUM 0x00
#define RT712_ANALOG_BIAS_CTL3 0x04
+#define RT712_JD_CTL1 0x09
+#define RT712_IO_CTL 0x0c
#define RT712_LDO2_3_CTL1 0x0e
#define RT712_PARA_VERB_CTL 0x1a
#define RT712_CC_DET1 0x24
+#define RT712_CLASSD_AMP_CTL1 0x37
+#define RT712_CLASSD_AMP_CTL6 0x3c
#define RT712_COMBO_JACK_AUTO_CTL1 0x45
#define RT712_COMBO_JACK_AUTO_CTL2 0x46
#define RT712_COMBO_JACK_AUTO_CTL3 0x47
@@ -61,6 +88,9 @@ struct rt712_sdca_priv {
#define RT712_SW_CONFIG1 0x8a
#define RT712_SW_CONFIG2 0x8b
+/* Index (NID:57h) */
+#define RT712_HP_DET_CTL3 0x0c
+
/* Index (NID:58h) */
#define RT712_DAC_DC_CALI_CTL1 0x00
#define RT712_DAC_DC_CALI_CTL2 0x01
@@ -71,6 +101,7 @@ struct rt712_sdca_priv {
/* Index (NID:5bh) */
#define RT712_IMS_DIGITAL_CTL1 0x00
#define RT712_IMS_DIGITAL_CTL5 0x05
+#define RT712_SEL_VEE2_HP_CTL1 0x23
#define RT712_HP_DETECT_RLDET_CTL1 0x29
#define RT712_HP_DETECT_RLDET_CTL2 0x2a
@@ -109,6 +140,11 @@ struct rt712_sdca_priv {
#define RT712_UMP_HID_CTL6 0x66
#define RT712_UMP_HID_CTL7 0x67
#define RT712_UMP_HID_CTL8 0x68
+#define RT712_MISC_CTL_FOR_UAJ 0x72
+#define RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL 0xa2
+#define RT712_DMIC2_FU_IT_FLOAT_CTL 0xa6
+#define RT712_ADC0B_FU_CH12_FLOAT_CTL 0xb0
+#define RT712_DMIC2_FU_CH12_FLOAT_CTL 0xb1
/* Parameter & Verb control 01 (0x1a)(NID:20h) */
#define RT712_HIDDEN_REG_SW_RESET (0x1 << 14)
@@ -139,6 +175,7 @@ struct rt712_sdca_priv {
#define FUNC_NUM_AMP 0x04
/* RT712 SDCA entity */
+#define RT712_SDCA_ENT0 0x00
#define RT712_SDCA_ENT_HID01 0x01
#define RT712_SDCA_ENT_GE49 0x49
#define RT712_SDCA_ENT_USER_FU05 0x05
@@ -157,6 +194,7 @@ struct rt712_sdca_priv {
#define RT712_SDCA_ENT_CS1C 0x1c
#define RT712_SDCA_ENT_CS31 0x31
#define RT712_SDCA_ENT_OT23 0x42
+#define RT712_SDCA_ENT_IT11 0x26
#define RT712_SDCA_ENT_IT26 0x26
#define RT712_SDCA_ENT_IT09 0x09
#define RT712_SDCA_ENT_PLATFORM_FU15 0x15
@@ -175,10 +213,12 @@ struct rt712_sdca_priv {
#define RT712_SDCA_CTL_REQ_POWER_STATE 0x01
#define RT712_SDCA_CTL_VENDOR_DEF 0x30
#define RT712_SDCA_CTL_FU_CH_GAIN 0x0b
+#define RT712_SDCA_CTL_FUNC_STATUS 0x10
-/* RT712 SDCA channel */
-#define CH_L 0x01
-#define CH_R 0x02
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION BIT(5)
+#define FUNCTION_HAS_BEEN_RESET BIT(6)
+#define FUNCTION_BUSY BIT(7)
/* sample frequency index */
#define RT712_SDCA_RATE_16000HZ 0x04
@@ -191,6 +231,7 @@ struct rt712_sdca_priv {
enum {
RT712_AIF1,
RT712_AIF2,
+ RT712_AIF3,
};
enum rt712_sdca_jd_src {
@@ -207,6 +248,11 @@ enum rt712_sdca_hw_id {
#define RT712_PART_ID_713 0x713
+enum rt712_sdca_version {
+ RT712_VA,
+ RT712_VB,
+};
+
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
int rt712_sdca_init(struct device *dev, struct regmap *regmap,
struct regmap *mbq_regmap, struct sdw_slave *slave);
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index df10916bab46..ce7d8955efc3 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
{
- struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
-
- if (rt715->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -208,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);
@@ -225,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);
@@ -237,10 +234,10 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
if (!slave->unattach_request)
goto regmap_sync;
- time = wait_for_completion_timeout(&slave->enumeration_complete,
+ time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT715_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Enumeration not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -266,15 +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",
- .owner = THIS_MODULE,
- .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 b989f907784b..b6a7a807a428 100644
--- a/sound/soc/codecs/rt715-sdca.c
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -41,8 +41,8 @@ static int rt715_sdca_index_write(struct rt715_sdca_priv *rt715,
ret = regmap_write(regmap, addr, value);
if (ret < 0)
dev_err(&rt715->slave->dev,
- "Failed to set private value: %08x <= %04x %d\n", ret, addr,
- value);
+ "%s: Failed to set private value: %08x <= %04x %d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -59,8 +59,8 @@ static int rt715_sdca_index_read(struct rt715_sdca_priv *rt715,
ret = regmap_read(regmap, addr, value);
if (ret < 0)
dev_err(&rt715->slave->dev,
- "Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ "%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -152,8 +152,8 @@ static int rt715_sdca_set_amp_gain_put(struct snd_kcontrol *kcontrol,
mc->shift);
ret = regmap_write(rt715->mbq_regmap, mc->reg + i, gain_val);
if (ret != 0) {
- dev_err(component->dev, "Failed to write 0x%x=0x%x\n",
- mc->reg + i, gain_val);
+ dev_err(component->dev, "%s: Failed to write 0x%x=0x%x\n",
+ __func__, mc->reg + i, gain_val);
return ret;
}
}
@@ -188,8 +188,8 @@ static int rt715_sdca_set_amp_gain_4ch_put(struct snd_kcontrol *kcontrol,
ret = regmap_write(rt715->mbq_regmap, reg_base + i,
gain_val);
if (ret != 0) {
- dev_err(component->dev, "Failed to write 0x%x=0x%x\n",
- reg_base + i, gain_val);
+ dev_err(component->dev, "%s: Failed to write 0x%x=0x%x\n",
+ __func__, reg_base + i, gain_val);
return ret;
}
}
@@ -224,8 +224,8 @@ static int rt715_sdca_set_amp_gain_8ch_put(struct snd_kcontrol *kcontrol,
reg = i < 7 ? reg_base + i : (reg_base - 1) | BIT(15);
ret = regmap_write(rt715->mbq_regmap, reg, gain_val);
if (ret != 0) {
- dev_err(component->dev, "Failed to write 0x%x=0x%x\n",
- reg, gain_val);
+ dev_err(component->dev, "%s: Failed to write 0x%x=0x%x\n",
+ __func__, reg, gain_val);
return ret;
}
}
@@ -246,8 +246,8 @@ static int rt715_sdca_set_amp_gain_get(struct snd_kcontrol *kcontrol,
for (i = 0; i < 2; i++) {
ret = regmap_read(rt715->mbq_regmap, mc->reg + i, &val);
if (ret < 0) {
- dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
- mc->reg + i, ret);
+ dev_err(component->dev, "%s: Failed to read 0x%x, ret=%d\n",
+ __func__, mc->reg + i, ret);
return ret;
}
ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, mc->shift);
@@ -271,8 +271,8 @@ static int rt715_sdca_set_amp_gain_4ch_get(struct snd_kcontrol *kcontrol,
for (i = 0; i < 4; i++) {
ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val);
if (ret < 0) {
- dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
- reg_base + i, ret);
+ dev_err(component->dev, "%s: Failed to read 0x%x, ret=%d\n",
+ __func__, reg_base + i, ret);
return ret;
}
ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, gain_sft);
@@ -297,8 +297,8 @@ static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol,
for (i = 0; i < 8; i += 2) {
ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val_l);
if (ret < 0) {
- dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
- reg_base + i, ret);
+ dev_err(component->dev, "%s: Failed to read 0x%x, ret=%d\n",
+ __func__, reg_base + i, ret);
return ret;
}
ucontrol->value.integer.value[i] = (val_l >> gain_sft) / 10;
@@ -306,8 +306,8 @@ static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol,
reg = (i == 6) ? (reg_base - 1) | BIT(15) : reg_base + 1 + i;
ret = regmap_read(rt715->mbq_regmap, reg, &val_r);
if (ret < 0) {
- dev_err(component->dev, "Failed to read 0x%x, ret=%d\n",
- reg, ret);
+ dev_err(component->dev, "%s: Failed to read 0x%x, ret=%d\n",
+ __func__, reg, ret);
return ret;
}
ucontrol->value.integer.value[i + 1] = (val_r >> gain_sft) / 10;
@@ -316,7 +316,7 @@ static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
static int rt715_sdca_get_volsw(struct snd_kcontrol *kcontrol,
@@ -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), \
@@ -477,7 +469,7 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = {
RT715_SDCA_FU_VOL_CTRL, CH_01),
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
RT715_SDCA_FU_VOL_CTRL, CH_02),
- 0x2f, 0x7f, 0,
+ 0x2f, 0x3f, 0,
rt715_sdca_set_amp_gain_get, rt715_sdca_set_amp_gain_put,
in_vol_tlv),
RT715_SDCA_EXT_TLV("FU02 Capture Volume",
@@ -485,13 +477,13 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = {
RT715_SDCA_FU_VOL_CTRL, CH_01),
rt715_sdca_set_amp_gain_4ch_get,
rt715_sdca_set_amp_gain_4ch_put,
- in_vol_tlv, 4, 0x7f),
+ in_vol_tlv, 4, 0x3f),
RT715_SDCA_EXT_TLV("FU06 Capture Volume",
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
RT715_SDCA_FU_VOL_CTRL, CH_01),
rt715_sdca_set_amp_gain_4ch_get,
rt715_sdca_set_amp_gain_4ch_put,
- in_vol_tlv, 4, 0x7f),
+ in_vol_tlv, 4, 0x3f),
/* MIC Boost Control */
RT715_SDCA_BOOST_EXT_TLV("FU0E Boost",
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
@@ -510,8 +502,7 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = {
static int rt715_sdca_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
unsigned int val, mask_sft;
@@ -546,10 +537,8 @@ static int rt715_sdca_mux_get(struct snd_kcontrol *kcontrol,
static int rt715_sdca_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -761,8 +750,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = {
static int rt715_sdca_probe(struct snd_soc_component *component)
{
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
int ret;
+ if (!rt715->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -830,15 +823,15 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
0xaf00);
break;
default:
- dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
+ dev_err(component->dev, "%s: Invalid DAI id %d\n", __func__, dai->id);
return -EINVAL;
}
retval = sdw_stream_add_slave(rt715->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(component->dev, "Unable to configure port, retval:%d\n",
- retval);
+ dev_err(component->dev, "%s: Unable to configure port, retval:%d\n",
+ __func__, retval);
return retval;
}
@@ -889,8 +882,8 @@ static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
val = 0xf;
break;
default:
- dev_err(component->dev, "Unsupported sample rate %d\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Unsupported sample rate %d\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -929,7 +922,7 @@ static const struct snd_soc_dai_ops rt715_sdca_ops = {
static struct snd_soc_dai_driver rt715_sdca_dai[] = {
{
- .name = "rt715-aif1",
+ .name = "rt715-sdca-aif1",
.id = RT715_AIF1,
.capture = {
.stream_name = "DP6 Capture",
@@ -941,7 +934,7 @@ static struct snd_soc_dai_driver rt715_sdca_dai[] = {
.ops = &rt715_sdca_ops,
},
{
- .name = "rt715-aif2",
+ .name = "rt715-sdca-aif2",
.id = RT715_AIF2,
.capture = {
.stream_name = "DP4 Capture",
@@ -977,6 +970,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
rt715->regmap = regmap;
rt715->mbq_regmap = mbq_regmap;
rt715->hw_sdw_ver = slave->id.sdw_version;
+
+ regcache_cache_only(rt715->regmap, true);
+ regcache_cache_only(rt715->mbq_regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -988,6 +985,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
&soc_codec_dev_rt715_sdca,
rt715_sdca_dai,
ARRAY_SIZE(rt715_sdca_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -1000,22 +1016,16 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt715->hw_init)
return 0;
+ regcache_cache_only(rt715->regmap, false);
+ regcache_cache_only(rt715->mbq_regmap, false);
+
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
if (!rt715->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
-
rt715->first_hw_init = true;
}
@@ -1052,7 +1062,6 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt715->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
return 0;
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 6db87442b783..a3df4bbedf86 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -111,6 +111,7 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg)
case 0x839d:
case 0x83a7:
case 0x83a9:
+ case 0x752001:
case 0x752039:
return true;
default:
@@ -371,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)
{
@@ -482,7 +442,7 @@ static int rt715_bus_config(struct sdw_slave *slave,
ret = rt715_clock_config(&slave->dev);
if (ret < 0)
- dev_err(&slave->dev, "Invalid clk config");
+ dev_err(&slave->dev, "%s: Invalid clk config", __func__);
return 0;
}
@@ -508,17 +468,12 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt715_init(&slave->dev, sdw_regmap, regmap, slave);
-
- return 0;
+ return rt715_init(&slave->dev, sdw_regmap, regmap, slave);
}
static int rt715_sdw_remove(struct sdw_slave *slave)
{
- struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
-
- if (rt715->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -530,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);
@@ -544,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);
@@ -559,7 +514,7 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT715_PROBE_TIMEOUT));
if (!time) {
- dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ dev_err(&slave->dev, "%s: Initialization not complete, timed out\n", __func__);
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
@@ -575,15 +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",
- .owner = THIS_MODULE,
- .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 6c2e165dd621..0881826de2f1 100644
--- a/sound/soc/codecs/rt715.c
+++ b/sound/soc/codecs/rt715.c
@@ -16,15 +16,10 @@
#include <linux/pm_runtime.h>
#include <linux/pm.h>
#include <linux/soundwire/sdw.h>
-#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -45,13 +40,67 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg,
ret = regmap_write(regmap, addr, value);
if (ret < 0) {
- pr_err("Failed to set private value: %08x <= %04x %d\n", ret,
- addr, value);
+ pr_err("%s: Failed to set private value: %08x <= %04x %d\n",
+ __func__, addr, value, ret);
}
return ret;
}
+static int rt715_index_write_nid(struct regmap *regmap,
+ unsigned int nid, unsigned int reg, unsigned int value)
+{
+ int ret;
+ unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
+
+ ret = regmap_write(regmap, addr, value);
+ if (ret < 0)
+ pr_err("%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
+
+ return ret;
+}
+
+static int rt715_index_read_nid(struct regmap *regmap,
+ unsigned int nid, unsigned int reg, unsigned int *value)
+{
+ int ret;
+ unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
+
+ *value = 0;
+ ret = regmap_read(regmap, addr, value);
+ if (ret < 0)
+ pr_err("%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
+
+ return ret;
+}
+
+static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp, orig;
+ int ret;
+
+ ret = rt715_index_read_nid(regmap, nid, reg, &orig);
+ if (ret < 0)
+ return ret;
+
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+
+ return rt715_index_write_nid(regmap, nid, reg, tmp);
+}
+
+static void rt715_reset(struct regmap *regmap)
+{
+ regmap_write(regmap, RT715_FUNC_RESET, 0);
+ rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS,
+ RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG,
+ RT715_CLEAR_HIDDEN_REG);
+}
+
+
static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h,
unsigned int addr_l, unsigned int val_h,
unsigned int *r_val, unsigned int *l_val)
@@ -76,8 +125,7 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
@@ -103,7 +151,7 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -157,7 +205,7 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol,
}
/* D0:power on state, D3: power saving mode */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
return k_vol_changed;
@@ -201,8 +249,7 @@ static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
static const unsigned int capture_reg_H[] = {
RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
@@ -225,7 +272,7 @@ static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol,
addr_l = capture_reg_L[j];
rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -273,7 +320,7 @@ static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol,
}
/* D0:power on state, D3: power saving mode */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
return k_changed;
@@ -309,8 +356,7 @@ static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
static const unsigned int capture_reg_H[] = {
RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H,
@@ -332,7 +378,7 @@ static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol,
addr_l = capture_reg_L[j];
rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll);
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
@@ -382,7 +428,7 @@ static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol,
}
/* D0:power on state, D3: power saving mode */
- if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
return k_changed;
@@ -437,14 +483,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, \
@@ -505,8 +543,7 @@ static const struct snd_kcontrol_new rt715_snd_controls[] = {
static int rt715_mux_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg, val;
@@ -536,10 +573,8 @@ static int rt715_mux_get(struct snd_kcontrol *kcontrol,
static int rt715_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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
@@ -711,13 +746,12 @@ static const struct snd_soc_dapm_route rt715_audio_map[] = {
static int rt715_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
regmap_write(rt715->regmap,
RT715_SET_AUDIO_POWER_STATE,
AC_PWRST_D0);
@@ -734,14 +768,18 @@ static int rt715_set_bias_level(struct snd_soc_component *component,
default:
break;
}
- dapm->bias_level = level;
+
return 0;
}
static int rt715_probe(struct snd_soc_component *component)
{
+ struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
int ret;
+ if (!rt715->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -809,14 +847,14 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa000);
break;
default:
- dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
+ dev_err(component->dev, "%s: Invalid DAI id %d\n", __func__, dai->id);
return -EINVAL;
}
retval = sdw_stream_add_slave(rt715->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
@@ -830,8 +868,8 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
val |= 0x0 << 8;
break;
default:
- dev_err(component->dev, "Unsupported sample rate %d\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Unsupported sample rate %d\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -839,8 +877,8 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream,
/* bit 3:0 Number of Channel */
val |= (params_channels(params) - 1);
} else {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -984,6 +1022,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
rt715->regmap = regmap;
rt715->sdw_regmap = sdw_regmap;
+ regcache_cache_only(rt715->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -995,8 +1035,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
&soc_codec_dev_rt715,
rt715_dai,
ARRAY_SIZE(rt715_dai));
+ if (ret < 0)
+ return ret;
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ return 0;
}
int rt715_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1006,25 +1063,19 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave)
if (rt715->hw_init)
return 0;
+ regcache_cache_only(rt715->regmap, false);
+
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt715->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt715->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
+ rt715_reset(rt715->regmap);
+
/* Mute nid=08h/09h */
regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080);
regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080);
@@ -1071,7 +1122,6 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt715->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
return 0;
diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h
index 12a0ae656d09..a0c56aa1003a 100644
--- a/sound/soc/codecs/rt715.h
+++ b/sound/soc/codecs/rt715.h
@@ -48,6 +48,7 @@ struct rt715_priv {
#define RT715_INLINE_CMD 0x55
/* Index (NID:20h) */
+#define RT715_VD_CLEAR_CTRL 0x01
#define RT715_SDW_INPUT_SEL 0x39
#define RT715_EXT_DMIC_CLK_CTRL2 0x54
@@ -71,6 +72,8 @@ struct rt715_priv {
#define RT715_READ_HDA_0 0x2015
#define RT715_PRIV_INDEX_W_H 0x7520
#define RT715_PRIV_INDEX_W_L 0x85a0
+#define RT715_PRIV_INDEX_W_H_2 0x7500
+#define RT715_PRIV_INDEX_W_L_2 0x8580
#define RT715_PRIV_DATA_W_H 0x7420
#define RT715_PRIV_DATA_W_L 0x84a0
#define RT715_PRIV_INDEX_R_H 0x9d20
@@ -198,6 +201,10 @@ struct rt715_priv {
#define RT715_SET_DMIC4_CONFIG_DEFAULT4\
(RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4)
+/* vendor register clear ctrl-1 (0x01)(NID:20h) */
+#define RT715_CLEAR_HIDDEN_REG (0x1 << 15)
+
+
#define RT715_MUTE_SFT 7
#define RT715_DIR_IN_SFT 6
#define RT715_DIR_OUT_SFT 7
@@ -213,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
new file mode 100644
index 000000000000..4d8a12b13015
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt721-sdca-sdw.c -- rt721 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+
+#include "rt721-sdca.h"
+#include "rt721-sdca-sdw.h"
+#include "rt-sdw-common.h"
+
+static bool rt721_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01 ... 0x2f0a:
+ case 0x2f35:
+ case 0x2f50:
+ case 0x2f51:
+ case 0x2f58 ... 0x2f5d:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV,
+ RT721_SDCA_CTL_XUV, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_SELECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_DETECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
+ RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
+ RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f01:
+ case 0x2f51:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_DETECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV,
+ RT721_SDCA_CTL_XUV, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
+ RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
+ RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x0900004 ... 0x0900009:
+ case 0x0a00005:
+ case 0x0c00005:
+ case 0x0d00014:
+ case 0x0310100:
+ case 0x2000000 ... 0x2000003:
+ case 0x2000013:
+ case 0x200002c:
+ case 0x200003c:
+ case 0x2000046:
+ case 0x5810000:
+ case 0x5810036:
+ case 0x5810037:
+ case 0x5810038:
+ case 0x5810039:
+ case 0x5b10018:
+ case 0x5b10019:
+ case 0x5f00045:
+ case 0x5f00048:
+ case 0x6100000:
+ case 0x6100005:
+ case 0x6100006:
+ case 0x610000d:
+ case 0x6100010:
+ case 0x6100011:
+ case 0x6100013:
+ case 0x6100015:
+ case 0x6100017:
+ case 0x6100025:
+ case 0x6100029:
+ case 0x610002c ... 0x610002f:
+ case 0x6100053 ... 0x6100055:
+ case 0x6100057:
+ case 0x610005a:
+ case 0x610005b:
+ case 0x610006a:
+ case 0x610006d:
+ case 0x6100092:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_01):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_02):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_03):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x0310100:
+ case 0x0900005:
+ case 0x0900009:
+ case 0x0a00005:
+ case 0x0c00005:
+ case 0x0d00014:
+ case 0x2000000:
+ case 0x200000d:
+ case 0x2000019:
+ case 0x2000020:
+ case 0x200002c:
+ case 0x2000030:
+ case 0x2000046:
+ case 0x2000067:
+ case 0x2000084:
+ case 0x2000086:
+ case 0x5810000:
+ case 0x5810036:
+ case 0x5810037:
+ case 0x5810038:
+ case 0x5810039:
+ case 0x5b10018:
+ case 0x5b10019:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt721_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt721_sdca_readable_register,
+ .volatile_reg = rt721_sdca_volatile_register,
+ .max_register = 0x44ffffff,
+ .reg_defaults = rt721_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt721_sdca_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_config rt721_sdca_mbq_regmap = {
+ .name = "sdw-mbq",
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt721_sdca_mbq_readable_register,
+ .volatile_reg = rt721_sdca_mbq_volatile_register,
+ .max_register = 0x41000312,
+ .reg_defaults = rt721_sdca_mbq_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt721_sdca_mbq_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt721_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt721->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt721->hs_jack) {
+ /*
+ * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then
+ * if the device attached again, we will need to set the setting back.
+ * It could avoid losing the jack detection interrupt.
+ * This also could sync with the cache value as the rt721_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ }
+ }
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt721->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt721_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt721_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ sdw_slave_read_prop(slave);
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+
+ /*
+ * port = 1 for headphone playback
+ * port = 2 for headset-mic capture
+ * port = 3 for speaker playback
+ * port = 6 for digital-mic capture
+ */
+ prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */
+ prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 1380;
+
+ /* wake-up event */
+ prop->wake_capable = 1;
+
+ /* Three data lanes are supported by rt721-sdca codec */
+ prop->lane_control_support = true;
+
+ return 0;
+}
+
+static int rt721_sdca_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev);
+ int ret, stat;
+ int count = 0, retry = 3;
+ unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0;
+
+ if (cancel_delayed_work_sync(&rt721->jack_detect_work)) {
+ dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__);
+ /* avoid the HID owner doesn't change to device */
+ if (rt721->scp_sdca_stat2)
+ scp_sdca_stat2 = rt721->scp_sdca_stat2;
+ }
+
+ /*
+ * The critical section below intentionally protects a rather large piece of code.
+ * We don't want to allow the system suspend to disable an interrupt while we are
+ * processing it, which could be problematic given the quirky SoundWire interrupt
+ * scheme. We do want however to prevent new workqueues from being scheduled if
+ * the disable_irq flag was set during system suspend.
+ */
+ mutex_lock(&rt721->disable_irq_lock);
+
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+
+ rt721->scp_sdca_stat1 = ret;
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+
+ rt721->scp_sdca_stat2 = ret;
+ if (scp_sdca_stat2)
+ rt721->scp_sdca_stat2 |= scp_sdca_stat2;
+ do {
+ /* clear flag */
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) {
+ ret = sdw_update_no_pm(rt721->slave, SDW_SCP_SDCA_INT1,
+ SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0);
+ if (ret < 0)
+ goto io_error;
+ }
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) {
+ ret = sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INT2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ /* check if flag clear or not */
+ ret = sdw_read_no_pm(rt721->slave, SDW_DP0_INT);
+ if (ret < 0)
+ goto io_error;
+ sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
+
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ if (ret < 0)
+ goto io_error;
+ scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0;
+
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+ if (ret < 0)
+ goto io_error;
+ scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8;
+
+ stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade;
+
+ count++;
+ } while (stat != 0 && count < retry);
+
+ if (stat)
+ dev_warn(&slave->dev,
+ "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt721->scp_sdca_stat1, rt721->scp_sdca_stat2);
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1);
+ ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2);
+
+ if (status->sdca_cascade && !rt721->disable_irq)
+ mod_delayed_work(system_power_efficient_wq,
+ &rt721->jack_detect_work, msecs_to_jiffies(280));
+
+ mutex_unlock(&rt721->disable_irq_lock);
+
+ return 0;
+
+io_error:
+ mutex_unlock(&rt721->disable_irq_lock);
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static const struct sdw_slave_ops rt721_sdca_slave_ops = {
+ .read_prop = rt721_sdca_read_prop,
+ .interrupt_callback = rt721_sdca_interrupt_callback,
+ .update_status = rt721_sdca_update_status,
+};
+
+static int rt721_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap, *mbq_regmap;
+
+ /* Regmap Initialization */
+ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt721_sdca_mbq_regmap);
+ if (IS_ERR(mbq_regmap))
+ return PTR_ERR(mbq_regmap);
+
+ regmap = devm_regmap_init_sdw(slave, &rt721_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt721_sdca_init(&slave->dev, regmap, mbq_regmap, slave);
+}
+
+static int rt721_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev);
+
+ if (rt721->hw_init) {
+ cancel_delayed_work_sync(&rt721->jack_detect_work);
+ cancel_delayed_work_sync(&rt721->jack_btn_check_work);
+ }
+
+ if (rt721->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ mutex_destroy(&rt721->calibrate_mutex);
+ mutex_destroy(&rt721->disable_irq_lock);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt721_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x721, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt721_sdca_id);
+
+static int rt721_sdca_dev_suspend(struct device *dev)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
+
+ if (!rt721->hw_init)
+ return 0;
+
+ cancel_delayed_work_sync(&rt721->jack_detect_work);
+ cancel_delayed_work_sync(&rt721->jack_btn_check_work);
+
+ regcache_cache_only(rt721->regmap, true);
+ regcache_cache_only(rt721->mbq_regmap, true);
+
+ return 0;
+}
+
+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);
+ int ret1, ret2;
+
+ if (!rt721_sdca->hw_init)
+ return 0;
+
+ /*
+ * prevent new interrupts from being handled after the
+ * deferred work completes and before the parent disables
+ * interrupts on the link
+ */
+ mutex_lock(&rt721_sdca->disable_irq_lock);
+ rt721_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ mutex_unlock(&rt721_sdca->disable_irq_lock);
+
+ if (ret1 < 0 || ret2 < 0) {
+ /* log but don't prevent suspend from happening */
+ dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__);
+ }
+
+ return rt721_sdca_dev_suspend(dev);
+}
+
+#define RT721_PROBE_TIMEOUT 5000
+
+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);
+ unsigned long time;
+
+ if (!rt721->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request) {
+ mutex_lock(&rt721->disable_irq_lock);
+ if (rt721->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt721->disable_irq = false;
+ }
+ mutex_unlock(&rt721->disable_irq_lock);
+ goto regmap_sync;
+ }
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT721_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt721->regmap, false);
+ regcache_sync(rt721->regmap);
+ regcache_cache_only(rt721->mbq_regmap, false);
+ regcache_sync(rt721->mbq_regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops rt721_sdca_pm = {
+ 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 = pm_ptr(&rt721_sdca_pm),
+ },
+ .probe = rt721_sdca_sdw_probe,
+ .remove = rt721_sdca_sdw_remove,
+ .ops = &rt721_sdca_slave_ops,
+ .id_table = rt721_sdca_id,
+};
+module_sdw_driver(rt721_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h
new file mode 100644
index 000000000000..214b31b82583
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca-sdw.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt721-sdca-sdw.h -- RT721 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT721_SDW_H__
+#define __RT721_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt721_sdca_reg_defaults[] = {
+ { 0x202d, 0x00 },
+ { 0x2f01, 0x00 },
+ { 0x2f02, 0x09 },
+ { 0x2f03, 0x08 },
+ { 0x2f04, 0x00 },
+ { 0x2f05, 0x0e },
+ { 0x2f06, 0x01 },
+ { 0x2f09, 0x00 },
+ { 0x2f0a, 0x00 },
+ { 0x2f35, 0x00 },
+ { 0x2f50, 0xf0 },
+ { 0x2f58, 0x07 },
+ { 0x2f59, 0x07 },
+ { 0x2f5a, 0x00 },
+ { 0x2f5b, 0x07 },
+ { 0x2f5c, 0x27 },
+ { 0x2f5d, 0x07 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+};
+
+static const struct reg_default rt721_sdca_mbq_defaults[] = {
+ { 0x0900007, 0xc004 },
+ { 0x2000001, 0x0000 },
+ { 0x2000002, 0x0000 },
+ { 0x2000003, 0x0000 },
+ { 0x2000013, 0x8001 },
+ { 0x200003c, 0x0000 },
+ { 0x2000046, 0x3400 },
+ { 0x5f00044, 0x6040 },
+ { 0x5f00045, 0x3333 },
+ { 0x5f00048, 0x0000 },
+ { 0x6100005, 0x0005 },
+ { 0x6100006, 0x0000 },
+ { 0x610000d, 0x0051 },
+ { 0x6100010, 0x0180 },
+ { 0x6100011, 0x0000 },
+ { 0x6100013, 0x0000 },
+ { 0x6100015, 0x0000 },
+ { 0x6100017, 0x8049 },
+ { 0x6100025, 0x1000 },
+ { 0x6100029, 0x0809 },
+ { 0x610002c, 0x2828 },
+ { 0x610002d, 0x2929 },
+ { 0x610002e, 0x3529 },
+ { 0x610002f, 0x2901 },
+ { 0x6100053, 0x2630 },
+ { 0x6100054, 0x2a2a },
+ { 0x6100055, 0x152f },
+ { 0x6100057, 0x2200 },
+ { 0x610005a, 0x2a4b },
+ { 0x610005b, 0x2a00 },
+ { 0x610006a, 0x0102 },
+ { 0x610006d, 0x0102 },
+ { 0x6100092, 0x4f61 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_L), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME,
+ CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN,
+ CH_L), 0xfe00 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN,
+ CH_R), 0xfe00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_01),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_02),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_03),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_04),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME,
+ CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R),
+ 0x0000 },
+};
+
+#endif /* __RT721_SDW_H__ */
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
new file mode 100644
index 000000000000..8233532a1752
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -0,0 +1,1561 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt721-sdca.c -- rt721 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2024 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/bitops.h>
+#include <sound/core.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/pcm.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/slab.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "rt721-sdca.h"
+#include "rt-sdw-common.h"
+
+static void rt721_sdca_jack_detect_handler(struct work_struct *work)
+{
+ struct rt721_sdca_priv *rt721 =
+ container_of(work, struct rt721_sdca_priv, jack_detect_work.work);
+ int btn_type = 0;
+
+ if (!rt721->hs_jack)
+ return;
+
+ if (!rt721->component->card || !rt721->component->card->instantiated)
+ return;
+
+ /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
+ if (rt721->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ rt721->jack_type = rt_sdca_headset_detect(rt721->regmap,
+ RT721_SDCA_ENT_GE49);
+ if (rt721->jack_type < 0)
+ return;
+ }
+
+ /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */
+ if (rt721->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8)
+ btn_type = rt_sdca_button_detect(rt721->regmap,
+ RT721_SDCA_ENT_HID01, RT721_BUF_ADDR_HID1,
+ RT721_SDCA_HID_ID);
+
+ if (rt721->jack_type == 0)
+ btn_type = 0;
+
+ dev_dbg(&rt721->slave->dev,
+ "in %s, jack_type=%d\n", __func__, rt721->jack_type);
+ dev_dbg(&rt721->slave->dev,
+ "in %s, btn_type=0x%x\n", __func__, btn_type);
+ dev_dbg(&rt721->slave->dev,
+ "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__,
+ rt721->scp_sdca_stat1, rt721->scp_sdca_stat2);
+
+ snd_soc_jack_report(rt721->hs_jack, rt721->jack_type | btn_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (btn_type) {
+ /* button released */
+ snd_soc_jack_report(rt721->hs_jack, rt721->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt721->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+}
+
+static void rt721_sdca_btn_check_handler(struct work_struct *work)
+{
+ struct rt721_sdca_priv *rt721 =
+ container_of(work, struct rt721_sdca_priv, jack_btn_check_work.work);
+ int btn_type = 0, ret, idx;
+ unsigned int det_mode, offset, val;
+ unsigned char buf[3];
+
+ ret = regmap_read(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49,
+ RT721_SDCA_CTL_DETECTED_MODE, 0), &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ /* pin attached */
+ if (det_mode) {
+ /* read UMP message offset */
+ ret = regmap_read(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01,
+ RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset);
+ if (ret < 0)
+ goto io_error;
+
+ for (idx = 0; idx < sizeof(buf); idx++) {
+ ret = regmap_read(rt721->regmap,
+ RT721_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto io_error;
+ buf[idx] = val & 0xff;
+ }
+ /* Report ID for HID1 */
+ if (buf[0] == 0x11)
+ btn_type = rt_sdca_btn_type(&buf[1]);
+ } else
+ rt721->jack_type = 0;
+
+ dev_dbg(&rt721->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type);
+ snd_soc_jack_report(rt721->hs_jack, rt721->jack_type | btn_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (btn_type) {
+ /* button released */
+ snd_soc_jack_report(rt721->hs_jack, rt721->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt721->jack_btn_check_work, msecs_to_jiffies(200));
+ }
+
+ return;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+}
+
+static void rt721_sdca_dmic_preset(struct rt721_sdca_priv *rt721)
+{
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF1_HV_CTRL1, 0xe000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8007);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL9, 0x2a2a);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL10, 0x2a00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL6, 0x2a2a);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL5, 0x2626);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL8, 0x1e00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL7, 0x1515);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_CH_FLOAT_CTL3, 0x0304);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_CH_FLOAT_CTL4, 0x0304);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_CTL1, 0x0000);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ regmap_write(rt721->mbq_regmap, 0x5910009, 0x2e01);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b40);
+ regmap_write(rt721->regmap, 0x2f5c, 0x25);
+}
+
+static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721)
+{
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF1_HV_CTRL1, 0xe000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8007);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x6420);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x6421);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0xe421);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_CH_FLOAT_CTL6, 0x5561);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_REG,
+ RT721_GPIO_PAD_CTRL5, 0x8003);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
+ RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+}
+
+static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
+{
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF1_HV_CTRL1, 0xe000);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_MISC_POWER_CTL31, 0x8007);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_GE_REL_CTRL1, 0x8011);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL3, 0xcf00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL4, 0x000f);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL1, 0x1100);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_UMP_HID_CTRL5, 0x0c12);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_JD_CTRL,
+ RT721_JD_1PIN_GAT_CTRL2, 0xc002);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL,
+ RT721_RC_CALIB_CTRL0, 0x0b40);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON14, 0x3333);
+ regmap_write(rt721->mbq_regmap, 0x5810035, 0x0036);
+ regmap_write(rt721->mbq_regmap, 0x5810030, 0xee00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+ RT721_HP_AMP_2CH_CAL1, 0x0140);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x0021);
+ regmap_write(rt721->mbq_regmap, 0x5810000, 0x8021);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+ RT721_HP_AMP_2CH_CAL18, 0x5522);
+ regmap_write(rt721->mbq_regmap, 0x5b10007, 0x2000);
+ regmap_write(rt721->mbq_regmap, 0x5B10017, 0x1b0f);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CBJ_CTRL,
+ RT721_CBJ_A0_GAT_CTRL1, 0x2a02);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL,
+ RT721_HP_AMP_2CH_CAL4, 0xa105);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON14, 0x3b33);
+ regmap_write(rt721->mbq_regmap, 0x310400, 0x3023);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON14, 0x3f33);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON13, 0x6048);
+ regmap_write(rt721->mbq_regmap, 0x310401, 0x3000);
+ regmap_write(rt721->mbq_regmap, 0x310402, 0x1b00);
+ regmap_write(rt721->mbq_regmap, 0x310300, 0x000f);
+ regmap_write(rt721->mbq_regmap, 0x310301, 0x3000);
+ regmap_write(rt721->mbq_regmap, 0x310302, 0x1b00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL,
+ RT721_UAJ_TOP_TCON17, 0x0008);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
+ RT721_DAC_2CH_CTRL3, 0x55ff);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL,
+ RT721_DAC_2CH_CTRL4, 0xcc00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_MBIAS_LV_CTRL2, 0x6677);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART,
+ RT721_VREF2_LV_CTRL1, 0x7600);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL2, 0x1234);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL3, 0x3512);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL1, 0x4040);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_ENT_FLOAT_CTL4, 0x1201);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_BOOST_CTRL,
+ RT721_BST_4CH_TOP_GATING_CTRL1, 0x002a);
+ regmap_write(rt721->regmap, 0x2f58, 0x07);
+
+ regmap_write(rt721->regmap, 0x2f51, 0x00);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_MISC_CTL, 0x0004);
+}
+
+static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
+{
+ mutex_lock(&rt721->calibrate_mutex);
+ if (rt721->hs_jack) {
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ dev_dbg(&rt721->slave->dev, "in %s enable\n", __func__);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_UAJ_CTL, 0x036E);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU03,
+ RT721_SDCA_CTL_SELECTED_MODE, 0), 0);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU0D,
+ RT721_SDCA_CTL_SELECTED_MODE, 0), 0);
+ rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_XU_REL_CTRL, 0x0000);
+ rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_GE_REL_CTRL1, 0x4000, 0x4000);
+ }
+ mutex_unlock(&rt721->calibrate_mutex);
+}
+
+static int rt721_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt721->hs_jack = hs_jack;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0) {
+ if (ret != -EACCES) {
+ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+ return ret;
+ }
+ /* pm_runtime not enabled yet */
+ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ rt721_sdca_jack_init(rt721);
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return 0;
+}
+
+/* For SDCA control DAC/ADC Gain */
+static int rt721_sdca_set_gain_put(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;
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned int read_l, read_r, gain_l_val, gain_r_val;
+ unsigned int adc_vol_flag = 0, changed = 0;
+ unsigned int lvalue, rvalue;
+ const unsigned int interval_offset = 0xc0;
+ const unsigned int tendA = 0x200;
+ const unsigned int tendB = 0xa00;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt721->mbq_regmap, mc->reg, &lvalue);
+ regmap_read(rt721->mbq_regmap, mc->rreg, &rvalue);
+
+ /* L Channel */
+ gain_l_val = ucontrol->value.integer.value[0];
+ if (gain_l_val > mc->max)
+ gain_l_val = mc->max;
+
+ if (mc->shift == 8) {
+ /* boost gain */
+ gain_l_val = gain_l_val * tendB;
+ } else if (mc->shift == 1) {
+ /* FU33 boost gain */
+ if (gain_l_val == 0)
+ gain_l_val = 0x8000;
+ else
+ gain_l_val = (gain_l_val - 1) * tendA;
+ } else {
+ /* ADC/DAC gain */
+ if (adc_vol_flag)
+ gain_l_val = 0x1e00 - ((mc->max - gain_l_val) * interval_offset);
+ else
+ gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset);
+ gain_l_val &= 0xffff;
+ }
+
+ /* R Channel */
+ gain_r_val = ucontrol->value.integer.value[1];
+ if (gain_r_val > mc->max)
+ gain_r_val = mc->max;
+
+ if (mc->shift == 8) {
+ /* boost gain */
+ gain_r_val = gain_r_val * tendB;
+ } else if (mc->shift == 1) {
+ /* FU33 boost gain */
+ if (gain_r_val == 0)
+ gain_r_val = 0x8000;
+ else
+ gain_r_val = (gain_r_val - 1) * tendA;
+ } else {
+ /* ADC/DAC gain */
+ if (adc_vol_flag)
+ gain_r_val = 0x1e00 - ((mc->max - gain_r_val) * interval_offset);
+ else
+ gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset);
+ gain_r_val &= 0xffff;
+ }
+
+ if (lvalue != gain_l_val || rvalue != gain_r_val)
+ changed = 1;
+ else
+ return 0;
+
+ /* Lch*/
+ regmap_write(rt721->mbq_regmap, mc->reg, gain_l_val);
+
+ /* Rch */
+ regmap_write(rt721->mbq_regmap, mc->rreg, gain_r_val);
+
+ regmap_read(rt721->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt721->mbq_regmap, mc->rreg, &read_r);
+ if (read_r == gain_r_val && read_l == gain_l_val)
+ return changed;
+
+ return -EIO;
+}
+
+static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+ const unsigned int tendA = 0x200;
+ const unsigned int tendB = 0xa00;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume") ||
+ strstr(ucontrol->id.name, "FU0F Capture Volume"))
+ adc_vol_flag = 1;
+
+ regmap_read(rt721->mbq_regmap, mc->reg, &read_l);
+ regmap_read(rt721->mbq_regmap, mc->rreg, &read_r);
+
+ if (mc->shift == 8) {
+ /* boost gain */
+ ctl_l = read_l / tendB;
+ } else if (mc->shift == 1) {
+ /* FU33 boost gain */
+ if (read_l == 0x8000 || read_l == 0xfe00)
+ ctl_l = 0;
+ else
+ ctl_l = read_l / tendA + 1;
+ } else {
+ if (adc_vol_flag)
+ ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset);
+ else
+ ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset);
+ }
+
+ if (read_l != read_r) {
+ if (mc->shift == 8) {
+ /* boost gain */
+ ctl_r = read_r / tendB;
+ } else if (mc->shift == 1) {
+ /* FU33 boost gain */
+ if (read_r == 0x8000 || read_r == 0xfe00)
+ ctl_r = 0;
+ else
+ ctl_r = read_r / tendA + 1;
+ } else { /* ADC/DAC gain */
+ if (adc_vol_flag)
+ ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset);
+ else
+ ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset);
+ }
+ } else {
+ ctl_r = ctl_l;
+ }
+
+ ucontrol->value.integer.value[0] = ctl_l;
+ ucontrol->value.integer.value[1] = ctl_r;
+
+ return 0;
+}
+
+static int rt721_sdca_set_fu1e_capture_ctl(struct rt721_sdca_priv *rt721)
+{
+ int err, i;
+ unsigned int ch_mute;
+
+ for (i = 0; i < ARRAY_SIZE(rt721->fu1e_mixer_mute); i++) {
+ ch_mute = rt721->fu1e_dapm_mute || rt721->fu1e_mixer_mute[i];
+ err = regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int rt721_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++)
+ ucontrol->value.integer.value[i] = !rt721->fu1e_mixer_mute[i];
+
+ return 0;
+}
+
+static int rt721_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ int err, changed = 0, i;
+
+ for (i = 0; i < p->count; i++) {
+ if (rt721->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt721->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt721_sdca_set_fu1e_capture_ctl(rt721);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt721_sdca_set_fu0f_capture_ctl(struct rt721_sdca_priv *rt721)
+{
+ int err;
+ unsigned int ch_l, ch_r;
+
+ ch_l = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_l_mute) ? 0x01 : 0x00;
+ ch_r = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), ch_l);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), ch_r);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt721_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt721->fu0f_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt721->fu0f_mixer_r_mute;
+ return 0;
+}
+
+static int rt721_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0;
+
+ if (rt721->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] ||
+ rt721->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1])
+ changed = 1;
+
+ rt721->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt721->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt721_sdca_set_fu0f_capture_ctl(rt721);
+ if (err < 0)
+ return err;
+
+ return changed;
+}
+
+static int rt721_sdca_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+static int rt721_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ unsigned int boost_step = 0x0a00;
+ unsigned int vol_max = 0x1e00;
+ unsigned int regvalue, ctl, i;
+ unsigned int adc_vol_flag = 0;
+ const unsigned int interval_offset = 0xc0;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt721->mbq_regmap, p->reg_base + i, &regvalue);
+
+ if (!adc_vol_flag) /* boost gain */
+ ctl = regvalue / boost_step;
+ else /* ADC gain */
+ ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt721_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt721_sdca_dmic_kctrl_priv *p =
+ (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned int boost_step = 0x0a00;
+ unsigned int vol_max = 0x1e00;
+ unsigned int gain_val[4];
+ unsigned int i, adc_vol_flag = 0, changed = 0;
+ unsigned int regvalue[4];
+ const unsigned int interval_offset = 0xc0;
+ int err;
+
+ if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+ adc_vol_flag = 1;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt721->mbq_regmap, p->reg_base + i, &regvalue[i]);
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ if (!adc_vol_flag) /* boost gain */
+ gain_val[i] = gain_val[i] * boost_step;
+ else { /* ADC gain */
+ gain_val[i] = vol_max - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+ }
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt721->mbq_regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt721->slave->dev, "%#08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+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);
+static const DECLARE_TLV_DB_SCALE(mic2_boost_vol_tlv, -200, 200, 0);
+
+static const struct snd_kcontrol_new rt721_sdca_controls[] = {
+ /* Headphone playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv),
+ /* Headset mic capture settings */
+ SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt721_sdca_fu0f_capture_get, rt721_sdca_fu0f_capture_put),
+ SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
+ RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic_vol_tlv),
+ SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_R), 1, 0x15, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic2_boost_vol_tlv),
+ /* AMP playback settings */
+ SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume",
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_VOLUME, CH_L),
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0,
+ rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv),
+ /* DMIC capture settings */
+ RT_SDCA_FU_CTRL("FU1E Capture Switch",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4, rt721_sdca_fu_info,
+ rt721_sdca_fu1e_capture_get, rt721_sdca_fu1e_capture_put),
+ RT_SDCA_EXT_TLV("FU1E Capture Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
+ RT721_SDCA_CTL_FU_VOLUME, CH_01),
+ rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put,
+ 4, 0x3f, mic_vol_tlv, rt721_sdca_fu_info),
+ RT_SDCA_EXT_TLV("FU15 Boost Volume",
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15,
+ RT721_SDCA_CTL_FU_CH_GAIN, CH_01),
+ rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put,
+ 4, 3, boost_vol_tlv, rt721_sdca_fu_info),
+};
+
+static int rt721_sdca_adc_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0, mask_sft, mask;
+
+ if (strstr(ucontrol->id.name, "ADC 09 Mux")) {
+ mask_sft = 12;
+ mask = 0x7;
+ } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) {
+ mask_sft = 10;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) {
+ mask_sft = 8;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) {
+ mask_sft = 6;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) {
+ mask_sft = 4;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) {
+ mask_sft = 2;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) {
+ mask_sft = 0;
+ mask = 0x3;
+ } else
+ return -EINVAL;
+
+ rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, &val);
+
+ ucontrol->value.enumerated.item[0] = (val >> mask_sft) & mask;
+
+ return 0;
+}
+
+static int rt721_sdca_adc_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct rt721_sdca_priv *rt721 = 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, mask;
+ unsigned int check;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ if (strstr(ucontrol->id.name, "ADC 09 Mux")) {
+ mask_sft = 12;
+ mask = 0x7;
+ } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) {
+ mask_sft = 10;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) {
+ mask_sft = 8;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) {
+ mask_sft = 6;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) {
+ mask_sft = 4;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) {
+ mask_sft = 2;
+ mask = 0x3;
+ } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) {
+ mask_sft = 0;
+ mask = 0x3;
+ } else
+ return -EINVAL;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+ rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, &val2);
+
+ if (strstr(ucontrol->id.name, "ADC 09 Mux"))
+ val2 = (val2 >> mask_sft) & 0x7;
+ else
+ val2 = (val2 >> mask_sft) & 0x3;
+
+ if (val == val2)
+ change = 0;
+ else
+ change = 1;
+
+ if (change) {
+ rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, &check);
+ rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
+ RT721_HDA_LEGACY_MUX_CTL0, mask << mask_sft,
+ val << mask_sft);
+ }
+
+ snd_soc_dapm_mux_update_power(dapm, kcontrol,
+ item[0], e, NULL);
+
+ return change;
+}
+
+static const char * const adc09_mux_text[] = {
+ "MIC2",
+ "LINE1",
+ "LINE2",
+};
+static const char * const adc07_10_mux_text[] = {
+ "DMIC1 RE",
+ "DMIC1 FE",
+ "DMIC2 RE",
+ "DMIC2 FE",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt721_adc09_enum, SND_SOC_NOPM, 0, adc09_mux_text);
+static SOC_ENUM_SINGLE_DECL(
+ rt721_dmic_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+
+static const struct snd_kcontrol_new rt721_sdca_adc09_mux =
+ SOC_DAPM_ENUM_EXT("ADC 09 Mux", rt721_adc09_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc08_r_mux =
+ SOC_DAPM_ENUM_EXT("ADC 08 R Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc08_l_mux =
+ SOC_DAPM_ENUM_EXT("ADC 08 L Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc10_r_mux =
+ SOC_DAPM_ENUM_EXT("ADC 10 R Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc10_l_mux =
+ SOC_DAPM_ENUM_EXT("ADC 10 L Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc07_r_mux =
+ SOC_DAPM_ENUM_EXT("ADC 07 R Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+static const struct snd_kcontrol_new rt721_sdca_adc07_l_mux =
+ SOC_DAPM_ENUM_EXT("ADC 07 L Mux", rt721_dmic_enum,
+ rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put);
+
+
+static int rt721_sdca_fu42_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(100);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_fu21_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_fu23_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char unmute = 0x0, mute = 0x1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), unmute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), unmute);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_L), mute);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
+ RT721_SDCA_CTL_FU_MUTE, CH_R), mute);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_fu113_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt721->fu1e_dapm_mute = false;
+ rt721_sdca_set_fu1e_capture_ctl(rt721);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt721->fu1e_dapm_mute = true;
+ rt721_sdca_set_fu1e_capture_ctl(rt721);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_fu36_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt721->fu0f_dapm_mute = false;
+ rt721_sdca_set_fu0f_capture_ctl(rt721);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt721->fu0f_dapm_mute = true;
+ rt721_sdca_set_fu0f_capture_ctl(rt721);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_pde47_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_pde41_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_pde11_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static int rt721_sdca_pde34_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 rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt721_sdca_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("LINE1"),
+ SND_SOC_DAPM_INPUT("LINE2"),
+ SND_SOC_DAPM_INPUT("DMIC1_2"),
+ SND_SOC_DAPM_INPUT("DMIC3_4"),
+
+ SND_SOC_DAPM_SUPPLY("PDE 41", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde41_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde47_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0,
+ rt721_sdca_pde34_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 23", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu42_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu36_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0,
+ rt721_sdca_fu113_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX("ADC 09 Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc09_mux),
+ SND_SOC_DAPM_MUX("ADC 08 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc08_r_mux),
+ SND_SOC_DAPM_MUX("ADC 08 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc08_l_mux),
+ SND_SOC_DAPM_MUX("ADC 10 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc10_r_mux),
+ SND_SOC_DAPM_MUX("ADC 10 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc10_l_mux),
+ SND_SOC_DAPM_MUX("ADC 07 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc07_r_mux),
+ SND_SOC_DAPM_MUX("ADC 07 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt721_sdca_adc07_l_mux),
+
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Headphone Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Headset Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Speaker Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 DMic Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt721_sdca_audio_map[] = {
+ {"FU 42", NULL, "DP1RX"},
+ {"FU 21", NULL, "DP3RX"},
+ {"FU 23", NULL, "DP3RX"},
+
+ {"ADC 09 Mux", "MIC2", "MIC2"},
+ {"ADC 09 Mux", "LINE1", "LINE1"},
+ {"ADC 09 Mux", "LINE2", "LINE2"},
+ {"ADC 07 R Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 07 R Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 07 R Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 07 R Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 07 L Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 07 L Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 07 L Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 07 L Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 08 R Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 08 R Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 08 R Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 08 R Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 08 L Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 08 L Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 08 L Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 08 L Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 10 R Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 10 R Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 10 R Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 10 R Mux", "DMIC2 FE", "DMIC3_4"},
+ {"ADC 10 L Mux", "DMIC1 RE", "DMIC1_2"},
+ {"ADC 10 L Mux", "DMIC1 FE", "DMIC1_2"},
+ {"ADC 10 L Mux", "DMIC2 RE", "DMIC3_4"},
+ {"ADC 10 L Mux", "DMIC2 FE", "DMIC3_4"},
+ {"FU 36", NULL, "PDE 34"},
+ {"FU 36", NULL, "ADC 09 Mux"},
+ {"FU 113", NULL, "PDE 11"},
+ {"FU 113", NULL, "ADC 07 R Mux"},
+ {"FU 113", NULL, "ADC 07 L Mux"},
+ {"FU 113", NULL, "ADC 10 R Mux"},
+ {"FU 113", NULL, "ADC 10 L Mux"},
+ {"DP2TX", NULL, "FU 36"},
+ {"DP6TX", NULL, "FU 113"},
+
+ {"HP", NULL, "PDE 47"},
+ {"HP", NULL, "FU 42"},
+ {"SPK", NULL, "PDE 41"},
+ {"SPK", NULL, "FU 21"},
+ {"SPK", NULL, "FU 23"},
+};
+
+static int rt721_sdca_parse_dt(struct rt721_sdca_priv *rt721, struct device *dev)
+{
+ device_property_read_u32(dev, "realtek,jd-src", &rt721->jd_src);
+
+ return 0;
+}
+
+static int rt721_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ rt721_sdca_parse_dt(rt721, &rt721->slave->dev);
+ rt721->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_sdca_dev_rt721 = {
+ .probe = rt721_sdca_probe,
+ .controls = rt721_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt721_sdca_controls),
+ .dapm_widgets = rt721_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt721_sdca_dapm_widgets),
+ .dapm_routes = rt721_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt721_sdca_audio_map),
+ .set_jack = rt721_sdca_set_jack_detect,
+ .endianness = 1,
+};
+
+static int rt721_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void rt721_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_runtime *sdw_stream;
+ int retval, port, num_channels;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt721->slave)
+ return -EINVAL;
+
+ /*
+ * RT721_AIF1 with port = 1 for headphone playback
+ * RT721_AIF1 with port = 2 for headset-mic capture
+ * RT721_AIF2 with port = 3 for speaker playback
+ * RT721_AIF3 with port = 6 for digital-mic capture
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ if (dai->id == RT721_AIF1)
+ port = 1;
+ else if (dai->id == RT721_AIF2)
+ port = 3;
+ else
+ return -EINVAL;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT721_AIF1)
+ port = 2;
+ else if (dai->id == RT721_AIF3)
+ port = 6;
+ else
+ return -EINVAL;
+ }
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = params_channels(params);
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ num_channels = params_channels(params);
+ port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ port_config.num = port;
+
+ retval = sdw_stream_add_slave(rt721->slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ if (params_channels(params) > 16) {
+ dev_err(component->dev, "Unsupported channels %d\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 8000:
+ sampling_rate = RT721_SDCA_RATE_8000HZ;
+ break;
+ case 16000:
+ sampling_rate = RT721_SDCA_RATE_16000HZ;
+ break;
+ case 24000:
+ sampling_rate = RT721_SDCA_RATE_24000HZ;
+ break;
+ case 32000:
+ sampling_rate = RT721_SDCA_RATE_32000HZ;
+ break;
+ case 44100:
+ sampling_rate = RT721_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT721_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT721_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT721_SDCA_RATE_192000HZ;
+ break;
+ case 384000:
+ sampling_rate = RT721_SDCA_RATE_384000HZ;
+ break;
+ case 768000:
+ sampling_rate = RT721_SDCA_RATE_768000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ if (dai->id == RT721_AIF1) {
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+ }
+
+ if (dai->id == RT721_AIF2)
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ if (dai->id == RT721_AIF3)
+ regmap_write(rt721->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate);
+
+ return 0;
+}
+
+static int rt721_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt721->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt721->slave, sdw_stream);
+ return 0;
+}
+
+#define RT721_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT721_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt721_sdca_ops = {
+ .hw_params = rt721_sdca_pcm_hw_params,
+ .hw_free = rt721_sdca_pcm_hw_free,
+ .set_stream = rt721_sdca_set_sdw_stream,
+ .shutdown = rt721_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt721_sdca_dai[] = {
+ {
+ .name = "rt721-sdca-aif1",
+ .id = RT721_AIF1,
+ .playback = {
+ .stream_name = "DP1 Headphone Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Headset Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .ops = &rt721_sdca_ops,
+ },
+ {
+ .name = "rt721-sdca-aif2",
+ .id = RT721_AIF2,
+ .playback = {
+ .stream_name = "DP3 Speaker Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .ops = &rt721_sdca_ops,
+ },
+ {
+ .name = "rt721-sdca-aif3",
+ .id = RT721_AIF3,
+ .capture = {
+ .stream_name = "DP6 DMic Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT721_STEREO_RATES,
+ .formats = RT721_FORMATS,
+ },
+ .ops = &rt721_sdca_ops,
+ }
+};
+
+int rt721_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave)
+{
+ struct rt721_sdca_priv *rt721;
+
+ rt721 = devm_kzalloc(dev, sizeof(*rt721), GFP_KERNEL);
+ if (!rt721)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt721);
+ rt721->slave = slave;
+ rt721->regmap = regmap;
+ rt721->mbq_regmap = mbq_regmap;
+
+ regcache_cache_only(rt721->regmap, true);
+ regcache_cache_only(rt721->mbq_regmap, true);
+
+ mutex_init(&rt721->calibrate_mutex);
+ mutex_init(&rt721->disable_irq_lock);
+
+ INIT_DELAYED_WORK(&rt721->jack_detect_work, rt721_sdca_jack_detect_handler);
+ INIT_DELAYED_WORK(&rt721->jack_btn_check_work, rt721_sdca_btn_check_handler);
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt721->hw_init = false;
+ rt721->first_hw_init = false;
+ rt721->fu1e_dapm_mute = true;
+ rt721->fu0f_dapm_mute = true;
+ rt721->fu0f_mixer_l_mute = rt721->fu0f_mixer_r_mute = true;
+ rt721->fu1e_mixer_mute[0] = rt721->fu1e_mixer_mute[1] =
+ rt721->fu1e_mixer_mute[2] = rt721->fu1e_mixer_mute[3] = true;
+
+ return devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt721, rt721_sdca_dai, ARRAY_SIZE(rt721_sdca_dai));
+}
+
+int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
+
+ rt721->disable_irq = false;
+
+ if (rt721->hw_init)
+ return 0;
+
+ regcache_cache_only(rt721->regmap, false);
+ regcache_cache_only(rt721->mbq_regmap, false);
+ if (rt721->first_hw_init) {
+ regcache_cache_bypass(rt721->regmap, true);
+ regcache_cache_bypass(rt721->mbq_regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+ rt721_sdca_dmic_preset(rt721);
+ rt721_sdca_amp_preset(rt721);
+ rt721_sdca_jack_preset(rt721);
+ if (rt721->first_hw_init) {
+ regcache_cache_bypass(rt721->regmap, false);
+ regcache_mark_dirty(rt721->regmap);
+ regcache_cache_bypass(rt721->mbq_regmap, false);
+ regcache_mark_dirty(rt721->mbq_regmap);
+ } else
+ rt721->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt721->hw_init = true;
+
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+ return 0;
+}
+
+MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt721-sdca.h b/sound/soc/codecs/rt721-sdca.h
new file mode 100644
index 000000000000..24ce188562ba
--- /dev/null
+++ b/sound/soc/codecs/rt721-sdca.h
@@ -0,0 +1,274 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt721-sdca.h -- RT721 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2024 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT721_H__
+#define __RT721_H__
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+
+struct rt721_sdca_priv {
+ struct regmap *regmap;
+ struct regmap *mbq_regmap;
+ struct snd_soc_component *component;
+ struct sdw_slave *slave;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+ struct mutex calibrate_mutex;
+ struct mutex disable_irq_lock;
+ bool disable_irq;
+ /* For Headset jack & Headphone */
+ unsigned int scp_sdca_stat1;
+ unsigned int scp_sdca_stat2;
+ struct snd_soc_jack *hs_jack;
+ struct delayed_work jack_detect_work;
+ struct delayed_work jack_btn_check_work;
+ int jack_type;
+ int jd_src;
+ bool fu0f_dapm_mute;
+ bool fu0f_mixer_l_mute;
+ bool fu0f_mixer_r_mute;
+ /* For DMIC */
+ bool fu1e_dapm_mute;
+ bool fu1e_mixer_mute[4];
+};
+
+struct rt721_sdca_dmic_kctrl_priv {
+ unsigned int reg_base;
+ unsigned int count;
+ unsigned int max;
+ unsigned int invert;
+};
+
+/* NID */
+#define RT721_ANA_POW_PART 0x01
+#define RT721_DAC_CTRL 0x04
+#define RT721_JD_CTRL 0x09
+#define RT721_CBJ_CTRL 0x0a
+#define RT721_CAP_PORT_CTRL 0x0c
+#define RT721_CLASD_AMP_CTRL 0x0d
+#define RT721_BOOST_CTRL 0x0f
+#define RT721_VENDOR_REG 0x20
+#define RT721_RC_CALIB_CTRL 0x40
+#define RT721_VENDOR_EQ_L 0x53
+#define RT721_VENDOR_EQ_R 0x54
+#define RT721_VENDOR_HP_CALI 0x56
+#define RT721_VENDOR_CHARGE_PUMP 0x57
+#define RT721_VENDOR_CLASD_CALI 0x58
+#define RT721_VENDOR_IMS_DRE 0x5b
+#define RT721_VENDOR_SPK_EFUSE 0x5c
+#define RT721_VENDOR_LEVEL_CTRL 0x5d
+#define RT721_VENDOR_ANA_CTL 0x5f
+#define RT721_HDA_SDCA_FLOAT 0x61
+
+/* Index (NID:01h) */
+#define RT721_MBIAS_LV_CTRL2 0x07
+#define RT721_VREF1_HV_CTRL1 0x0a
+#define RT721_VREF2_LV_CTRL1 0x0b
+
+/* Index (NID:04h) */
+#define RT721_DAC_2CH_CTRL3 0x02
+#define RT721_DAC_2CH_CTRL4 0x03
+
+/* Index (NID:09h) */
+#define RT721_JD_1PIN_GAT_CTRL2 0x07
+
+/* Index (NID:0ah) */
+#define RT721_CBJ_A0_GAT_CTRL1 0x04
+#define RT721_CBJ_A0_GAT_CTRL2 0x05
+
+/* Index (NID:0Ch) */
+#define RT721_HP_AMP_2CH_CAL1 0x05
+#define RT721_HP_AMP_2CH_CAL4 0x08
+#define RT721_HP_AMP_2CH_CAL18 0x1b
+
+/* Index (NID:0dh) */
+#define RT721_CLASD_AMP_2CH_CAL 0x14
+
+/* Index (NID:0fh) */
+#define RT721_BST_4CH_TOP_GATING_CTRL1 0x05
+
+/* Index (NID:20h) */
+#define RT721_JD_PRODUCT_NUM 0x00
+#define RT721_ANALOG_BIAS_CTL3 0x04
+#define RT721_JD_CTRL1 0x09
+#define RT721_LDO2_3_CTL1 0x0e
+#define RT721_GPIO_PAD_CTRL5 0x13
+#define RT721_LDO1_CTL 0x1a
+#define RT721_HP_JD_CTRL 0x24
+#define RT721_VD_HIDDEN_CTRL 0x26
+#define RT721_CLSD_CTRL6 0x3c
+#define RT721_COMBO_JACK_AUTO_CTL1 0x45
+#define RT721_COMBO_JACK_AUTO_CTL2 0x46
+#define RT721_COMBO_JACK_AUTO_CTL3 0x47
+#define RT721_DIGITAL_MISC_CTRL4 0x4a
+#define RT721_VREFO_GAT 0x63
+#define RT721_FSM_CTL 0x67
+#define RT721_SDCA_INTR_REC 0x82
+#define RT721_SW_CONFIG1 0x8a
+#define RT721_SW_CONFIG2 0x8b
+
+/* Index (NID:40h) */
+#define RT721_RC_CALIB_CTRL0 0x00
+
+/* Index (NID:58h) */
+#define RT721_DAC_DC_CALI_CTL1 0x01
+#define RT721_DAC_DC_CALI_CTL2 0x02
+#define RT721_DAC_DC_CALI_CTL3 0x03
+
+/* Index (NID:5fh) */
+#define RT721_MISC_POWER_CTL0 0x00
+#define RT721_MISC_POWER_CTL31 0x31
+#define RT721_UAJ_TOP_TCON13 0x44
+#define RT721_UAJ_TOP_TCON14 0x45
+#define RT721_UAJ_TOP_TCON17 0x48
+
+/* Index (NID:61h) */
+#define RT721_HDA_LEGACY_MUX_CTL0 0x00
+#define RT721_HDA_LEGACY_UAJ_CTL 0x02
+#define RT721_HDA_LEGACY_CTL1 0x05
+#define RT721_HDA_LEGACY_RESET_CTL 0x06
+#define RT721_MISC_CTL 0x07
+#define RT721_XU_REL_CTRL 0x0c
+#define RT721_GE_REL_CTRL1 0x0d
+#define RT721_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e
+#define RT721_GE_SDCA_RST_CTRL 0x10
+#define RT721_INT_RST_EN_CTRL 0x11
+#define RT721_XU_EVENT_EN 0x13
+#define RT721_INLINE_CTL2 0x17
+#define RT721_UMP_HID_CTRL1 0x18
+#define RT721_UMP_HID_CTRL2 0x19
+#define RT721_UMP_HID_CTRL3 0x1a
+#define RT721_UMP_HID_CTRL4 0x1b
+#define RT721_UMP_HID_CTRL5 0x1c
+#define RT721_FUNC_FLOAT_CTL0 0x22
+#define RT721_FUNC_FLOAT_CTL1 0x23
+#define RT721_FUNC_FLOAT_CTL2 0x24
+#define RT721_FUNC_FLOAT_CTL3 0x25
+#define RT721_ENT_FLOAT_CTL0 0x29
+#define RT721_ENT_FLOAT_CTL1 0x2c
+#define RT721_ENT_FLOAT_CTL2 0x2d
+#define RT721_ENT_FLOAT_CTL3 0x2e
+#define RT721_ENT_FLOAT_CTL4 0x2f
+#define RT721_CH_FLOAT_CTL1 0x45
+#define RT721_CH_FLOAT_CTL2 0x46
+#define RT721_ENT_FLOAT_CTL5 0x53
+#define RT721_ENT_FLOAT_CTL6 0x54
+#define RT721_ENT_FLOAT_CTL7 0x55
+#define RT721_ENT_FLOAT_CTL8 0x57
+#define RT721_ENT_FLOAT_CTL9 0x5a
+#define RT721_ENT_FLOAT_CTL10 0x5b
+#define RT721_CH_FLOAT_CTL3 0x6a
+#define RT721_CH_FLOAT_CTL4 0x6d
+#define RT721_CH_FLOAT_CTL5 0x70
+#define RT721_CH_FLOAT_CTL6 0x92
+
+/* Parameter & Verb control 01 (0x26)(NID:20h) */
+#define RT721_HIDDEN_REG_SW_RESET (0x1 << 14)
+
+/* Buffer address for HID */
+#define RT721_BUF_ADDR_HID1 0x44030000
+#define RT721_BUF_ADDR_HID2 0x44030020
+
+/* RT721 SDCA Control - function number */
+#define FUNC_NUM_JACK_CODEC 0x01
+#define FUNC_NUM_MIC_ARRAY 0x02
+#define FUNC_NUM_HID 0x03
+#define FUNC_NUM_AMP 0x04
+
+/* RT721 SDCA entity */
+#define RT721_SDCA_ENT_HID01 0x01
+#define RT721_SDCA_ENT_XUV 0x03
+#define RT721_SDCA_ENT_GE49 0x49
+#define RT721_SDCA_ENT_USER_FU05 0x05
+#define RT721_SDCA_ENT_USER_FU06 0x06
+#define RT721_SDCA_ENT_USER_FU0F 0x0f
+#define RT721_SDCA_ENT_USER_FU10 0x19
+#define RT721_SDCA_ENT_USER_FU1E 0x1e
+#define RT721_SDCA_ENT_FU15 0x15
+#define RT721_SDCA_ENT_PDE23 0x23
+#define RT721_SDCA_ENT_PDE40 0x40
+#define RT721_SDCA_ENT_PDE41 0x41
+#define RT721_SDCA_ENT_PDE11 0x11
+#define RT721_SDCA_ENT_PDE12 0x12
+#define RT721_SDCA_ENT_PDE2A 0x2a
+#define RT721_SDCA_ENT_CS01 0x01
+#define RT721_SDCA_ENT_CS11 0x11
+#define RT721_SDCA_ENT_CS1F 0x1f
+#define RT721_SDCA_ENT_CS1C 0x1c
+#define RT721_SDCA_ENT_CS31 0x31
+#define RT721_SDCA_ENT_OT23 0x42
+#define RT721_SDCA_ENT_IT26 0x26
+#define RT721_SDCA_ENT_IT09 0x09
+#define RT721_SDCA_ENT_PLATFORM_FU15 0x15
+#define RT721_SDCA_ENT_PLATFORM_FU44 0x44
+#define RT721_SDCA_ENT_XU03 0x03
+#define RT721_SDCA_ENT_XU0D 0x0d
+#define RT721_SDCA_ENT_FU55 0x55
+
+/* RT721 SDCA control */
+#define RT721_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
+#define RT721_SDCA_CTL_FU_MUTE 0x01
+#define RT721_SDCA_CTL_FU_VOLUME 0x02
+#define RT721_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10
+#define RT721_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11
+#define RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12
+#define RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13
+#define RT721_SDCA_CTL_SELECTED_MODE 0x01
+#define RT721_SDCA_CTL_DETECTED_MODE 0x02
+#define RT721_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT721_SDCA_CTL_VENDOR_DEF 0x30
+#define RT721_SDCA_CTL_XUV 0x34
+#define RT721_SDCA_CTL_FU_CH_GAIN 0x0b
+
+/* RT721 SDCA channel */
+#define CH_L 0x01
+#define CH_R 0x02
+#define CH_01 0x01
+#define CH_02 0x02
+#define CH_03 0x03
+#define CH_04 0x04
+#define CH_08 0x08
+#define CH_09 0x09
+#define CH_0A 0x0a
+
+/* sample frequency index */
+#define RT721_SDCA_RATE_8000HZ 0x01
+#define RT721_SDCA_RATE_11025HZ 0x02
+#define RT721_SDCA_RATE_12000HZ 0x03
+#define RT721_SDCA_RATE_16000HZ 0x04
+#define RT721_SDCA_RATE_22050HZ 0x05
+#define RT721_SDCA_RATE_24000HZ 0x06
+#define RT721_SDCA_RATE_32000HZ 0x07
+#define RT721_SDCA_RATE_44100HZ 0x08
+#define RT721_SDCA_RATE_48000HZ 0x09
+#define RT721_SDCA_RATE_88200HZ 0x0a
+#define RT721_SDCA_RATE_96000HZ 0x0b
+#define RT721_SDCA_RATE_176400HZ 0x0c
+#define RT721_SDCA_RATE_192000HZ 0x0d
+#define RT721_SDCA_RATE_384000HZ 0x0e
+#define RT721_SDCA_RATE_768000HZ 0x0f
+
+/* RT721 HID ID */
+#define RT721_SDCA_HID_ID 0x11
+
+enum {
+ RT721_AIF1, /* For headset mic and headphone */
+ RT721_AIF2, /* For speaker */
+ RT721_AIF3, /* For dmic */
+ RT721_AIFS,
+};
+
+int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt721_sdca_init(struct device *dev, struct regmap *regmap,
+ struct regmap *mbq_regmap, struct sdw_slave *slave);
+#endif /* __RT721_H__ */
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index cc57e4e27805..a0f5601a262a 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -16,48 +16,75 @@
#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:
case 0x2f35 ... 0x2f36:
- case 0x2f50:
+ case 0x2f50 ... 0x2f52:
case 0x2f54:
case 0x2f58 ... 0x2f5d:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_SELECTED_MODE,
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_PDE40,
+ RT722_SDCA_CTL_ACTUAL_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_PDE12,
+ RT722_SDCA_CTL_ACTUAL_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_PDE2A,
+ RT722_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 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_PDE23,
+ RT722_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 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:
@@ -68,11 +95,13 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x200007f:
case 0x2000082 ... 0x200008e:
case 0x2000090 ... 0x2000094:
+ case 0x3110000:
case 0x5300000 ... 0x5300002:
case 0x5400002:
case 0x5600000 ... 0x5600007:
case 0x5700000 ... 0x5700004:
case 0x5800000 ... 0x5800004:
+ case 0x5810000:
case 0x5b00003:
case 0x5c00011:
case 0x5d00006:
@@ -80,11 +109,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,
@@ -107,15 +141,39 @@ 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 const 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_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_ACTUAL_POWER_STATE, 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_MIC_ARRAY, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_ACTUAL_POWER_STATE, 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_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
case 0x2000000:
case 0x200000d:
case 0x2000019:
@@ -125,6 +183,9 @@ static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int re
case 0x2000067:
case 0x2000084:
case 0x2000086:
+ case 0x3110000:
+ case 0x5800003:
+ case 0x5810000:
return true;
default:
return false;
@@ -133,7 +194,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,
@@ -144,20 +205,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)
{
@@ -175,7 +222,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave,
* This also could sync with the cache value as the rt722_sdca_jack_init set.
*/
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8);
}
@@ -201,6 +248,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;
@@ -251,11 +300,14 @@ static int rt722_sdca_read_prop(struct sdw_slave *slave)
}
/* set the timeout values */
- prop->clk_stop_timeout = 200;
+ prop->clk_stop_timeout = 900;
/* wake-up event */
prop->wake_capable = 1;
+ /* Three data lanes are supported by rt722-sdca codec */
+ prop->lane_control_support = true;
+
return 0;
}
@@ -303,12 +355,8 @@ static int rt722_sdca_interrupt_callback(struct sdw_slave *slave,
SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0);
if (ret < 0)
goto io_error;
- } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) {
- ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1,
- SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6);
- if (ret < 0)
- goto io_error;
}
+
ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2);
if (ret < 0)
goto io_error;
@@ -347,7 +395,7 @@ static int rt722_sdca_interrupt_callback(struct sdw_slave *slave,
if (status->sdca_cascade && !rt722->disable_irq)
mod_delayed_work(system_power_efficient_wq,
- &rt722->jack_detect_work, msecs_to_jiffies(30));
+ &rt722->jack_detect_work, msecs_to_jiffies(280));
mutex_unlock(&rt722->disable_irq_lock);
@@ -359,7 +407,7 @@ io_error:
return ret;
}
-static struct sdw_slave_ops rt722_sdca_slave_ops = {
+static const struct sdw_slave_ops rt722_sdca_slave_ops = {
.read_prop = rt722_sdca_read_prop,
.interrupt_callback = rt722_sdca_interrupt_callback,
.update_status = rt722_sdca_update_status,
@@ -368,18 +416,16 @@ static 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->dev, 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)
@@ -406,7 +452,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);
@@ -417,12 +463,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);
@@ -439,7 +484,7 @@ static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev)
mutex_lock(&rt722_sdca->disable_irq_lock);
rt722_sdca->disable_irq = true;
ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, 0);
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
mutex_unlock(&rt722_sdca->disable_irq_lock);
@@ -454,7 +499,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);
@@ -463,8 +508,16 @@ static int __maybe_unused rt722_sdca_dev_resume(struct device *dev)
if (!rt722->first_hw_init)
return 0;
- if (!slave->unattach_request)
+ if (!slave->unattach_request) {
+ mutex_lock(&rt722->disable_irq_lock);
+ if (rt722->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt722->disable_irq = false;
+ }
+ mutex_unlock(&rt722->disable_irq_lock);
goto regmap_sync;
+ }
time = wait_for_completion_timeout(&slave->initialization_complete,
msecs_to_jiffies(RT722_PROBE_TIMEOUT));
@@ -479,21 +532,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",
- .owner = THIS_MODULE,
- .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..c5dd472a2c00 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.h
+++ b/sound/soc/codecs/rt722-sdca-sdw.h
@@ -31,50 +31,10 @@ 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 },
+ { 0x6100000, 0x0201 },
{ 0x6100006, 0x0005 },
{ 0x6100010, 0x2630 },
{ 0x6100011, 0x152f },
@@ -86,27 +46,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 +82,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 9c0d34366c9e..79b8b7e70a33 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -25,18 +25,20 @@
#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);
if (ret < 0)
dev_err(&rt722->slave->dev,
- "Failed to set private value: %06x <= %04x ret=%d\n",
- addr, value, ret);
+ "%s: Failed to set private value: %06x <= %04x ret=%d\n",
+ __func__, addr, value, ret);
return ret;
}
@@ -45,14 +47,14 @@ 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)
dev_err(&rt722->slave->dev,
- "Failed to get private value: %06x => %04x ret=%d\n",
- addr, *value, ret);
+ "%s: Failed to get private value: %06x => %04x ret=%d\n",
+ __func__, addr, *value, ret);
return ret;
}
@@ -190,9 +192,8 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work)
if (!rt722->component->card || !rt722->component->card->instantiated)
return;
- /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
- if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 ||
- rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */
+ if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
ret = rt722_sdca_headset_detect(rt722);
if (ret < 0)
return;
@@ -295,7 +296,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
if (rt722->hs_jack) {
/* set SCP_SDCA_IntMask1[0]=1 */
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
/* set SCP_SDCA_IntMask2[0]=1 */
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8);
@@ -309,6 +310,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
RT722_SDCA_CTL_SELECTED_MODE, 0), 0);
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL1, 0x0000);
/* trigger GE interrupt */
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
RT722_GE_RELATED_CTL2, 0x4000, 0x4000);
@@ -337,7 +339,6 @@ static int rt722_sdca_set_jack_detect(struct snd_soc_component *component,
rt722_sdca_jack_init(rt722);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return 0;
@@ -361,8 +362,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 +403,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 +432,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,16 +605,12 @@ 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;
- else { /* ADC gain */
- if (adc_vol_flag)
- ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
- else
- ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
- }
+ else /* ADC gain */
+ ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset);
ucontrol->value.integer.value[i] = ctl;
}
@@ -641,7 +638,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)
@@ -662,9 +659,10 @@ 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, "%#08x can't be set\n", p->reg_base + i);
+ dev_err(&rt722->slave->dev, "%s: %#08x can't be set\n",
+ __func__, p->reg_base + i);
}
return changed;
@@ -742,77 +740,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",
@@ -824,26 +751,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)
@@ -914,6 +841,7 @@ static int rt722_sdca_fu113_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
rt722->fu1e_dapm_mute = false;
rt722_sdca_set_fu1e_capture_ctl(rt722);
+ usleep_range(150000, 160000);
break;
case SND_SOC_DAPM_PRE_PMD:
rt722->fu1e_dapm_mute = true;
@@ -943,6 +871,28 @@ static int rt722_sdca_fu36_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static void rt722_pde_transition_delay(struct rt722_sdca_priv *rt722, unsigned char func,
+ unsigned char entity, unsigned char ps)
+{
+ unsigned int delay = 1000, val;
+
+ pm_runtime_mark_last_busy(&rt722->slave->dev);
+
+ /* waiting for Actual PDE becomes to PS0/PS3 */
+ while (delay) {
+ regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(func, entity, RT722_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
+ if (val == ps)
+ break;
+
+ usleep_range(1000, 1500);
+ delay--;
+ }
+ if (!delay) {
+ dev_warn(&rt722->slave->dev, "%s PDE to %s is NOT ready", __func__, ps?"PS3":"PS0");
+ }
+}
+
static int rt722_sdca_pde47_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -956,11 +906,13 @@ static int rt722_sdca_pde47_event(struct snd_soc_dapm_widget *w,
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, ps0);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, ps3);
break;
}
return 0;
@@ -979,11 +931,13 @@ static int rt722_sdca_pde23_event(struct snd_soc_dapm_widget *w,
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, ps0);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, ps3);
break;
}
return 0;
@@ -1002,11 +956,13 @@ static int rt722_sdca_pde11_event(struct snd_soc_dapm_widget *w,
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, ps0);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, ps3);
break;
}
return 0;
@@ -1025,11 +981,13 @@ static int rt722_sdca_pde12_event(struct snd_soc_dapm_widget *w,
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, ps0);
break;
case SND_SOC_DAPM_PRE_PMD:
regmap_write(rt722->regmap,
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
RT722_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+ rt722_pde_transition_delay(rt722, FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, ps3);
break;
}
return 0;
@@ -1212,13 +1170,13 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
retval = sdw_stream_add_slave(rt722->slave, &stream_config,
&port_config, 1, sdw_stream);
if (retval) {
- dev_err(dai->dev, "Unable to configure port\n");
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
return retval;
}
if (params_channels(params) > 16) {
- dev_err(component->dev, "Unsupported channels %d\n",
- params_channels(params));
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
return -EINVAL;
}
@@ -1237,8 +1195,8 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
sampling_rate = RT722_SDCA_RATE_192000HZ;
break;
default:
- dev_err(component->dev, "Rate %d is not supported\n",
- params_rate(params));
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
return -EINVAL;
}
@@ -1330,7 +1288,7 @@ static struct snd_soc_dai_driver rt722_sdca_dai[] = {
.capture = {
.stream_name = "DP6 DMic Capture",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rates = RT722_STEREO_RATES,
.formats = RT722_FORMATS,
},
@@ -1338,8 +1296,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;
@@ -1350,7 +1307,8 @@ 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;
+
+ regcache_cache_only(rt722->regmap, true);
mutex_init(&rt722->calibrate_mutex);
mutex_init(&rt722->disable_irq_lock);
@@ -1376,138 +1334,207 @@ int rt722_sdca_init(struct device *dev, struct regmap *regmap,
static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
{
- /* Set AD07 power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_ADC0A_08_PDE_FLOAT_CTL, 0x2a29);
- /* Set AD10 power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_ADC10_PDE_FLOAT_CTL, 0x2a00);
- /* Set DMIC1/DMIC2 power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_DMIC1_2_PDE_FLOAT_CTL, 0x2a2a);
- /* Set DMIC2 IT entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_DMIC_ENT_FLOAT_CTL, 0x2626);
- /* Set AD10 FU entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_ADC_ENT_FLOAT_CTL, 0x1e00);
- /* Set DMIC2 FU entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_DMIC_GAIN_ENT_FLOAT_CTL0, 0x1515);
- /* Set AD10 FU channel floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_ADC_VOL_CH_FLOAT_CTL, 0x0304);
- /* Set DMIC2 FU channel floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_DMIC_GAIN_ENT_FLOAT_CTL2, 0x0304);
- /* vf71f_r12_07_06 and vf71f_r13_07_06 = 2’b00 */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
- RT722_HDA_LEGACY_CONFIG_CTL0, 0x0000);
- /* Enable vf707_r12_05/vf707_r13_05 */
- regmap_write(rt722->regmap,
- SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
- RT722_SDCA_CTL_VENDOR_DEF, 0), 0x01);
- /* Fine tune PDE2A latency */
- regmap_write(rt722->regmap, 0x2f5c, 0x25);
+ unsigned int mic_func_status;
+ struct device *dev = &rt722->slave->dev;
+
+ regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status);
+ dev_dbg(dev, "%s mic func_status=0x%x\n", __func__, mic_func_status);
+
+ if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt722->first_hw_init)) {
+ /* Set AD07 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC0A_08_PDE_FLOAT_CTL, 0x2a29);
+ /* Set AD10 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC10_PDE_FLOAT_CTL, 0x2a00);
+ /* Set DMIC1/DMIC2 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC1_2_PDE_FLOAT_CTL, 0x2a2a);
+ /* Set DMIC2 IT entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_ENT_FLOAT_CTL, 0x2626);
+ /* Set AD10 FU entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC_ENT_FLOAT_CTL, 0x1e00);
+ /* Set DMIC2 FU entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_GAIN_ENT_FLOAT_CTL0, 0x1515);
+ /* Set AD10 FU channel floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_ADC_VOL_CH_FLOAT_CTL, 0x0304);
+ /* Set DMIC2 FU channel floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_DMIC_GAIN_ENT_FLOAT_CTL2, 0x0304);
+ /* vf71f_r12_07_06 and vf71f_r13_07_06 = 2’b00 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL,
+ RT722_HDA_LEGACY_CONFIG_CTL0, 0x0000);
+ /* Enable vf707_r12_05/vf707_r13_05 */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
+ RT722_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+ /* Fine tune PDE2A latency */
+ regmap_write(rt722->regmap, 0x2f5c, 0x25);
+ /* PHYtiming TDZ/TZD control */
+ regmap_write(rt722->regmap, 0x2f03, 0x06);
+
+ if (rt722->hw_vid == RT722_VB)
+ regmap_write(rt722->regmap, 0x2f52, 0x00);
+
+ /* clear flag */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
}
static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
{
- /* Set DVQ=01 */
- rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
- 0xc215);
- /* Reset dc_cal_top */
- rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
- 0x702c);
- /* W1C Trigger Calibration */
- rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
- 0xf02d);
- /* Set DAC02/ClassD power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_AMP_PDE_FLOAT_CTL,
- 0x2323);
- /* Set EAPD high */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_EAPD_CTL,
- 0x0002);
- /* Enable vf707_r14 */
- regmap_write(rt722->regmap,
- SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
- RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
+ unsigned int amp_func_status;
+ struct device *dev = &rt722->slave->dev;
+
+ regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+ dev_dbg(dev, "%s amp func_status=0x%x\n", __func__, amp_func_status);
+
+ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt722->first_hw_init)) {
+ /* Set DVQ=01 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
+ 0xc215);
+ /* Reset dc_cal_top */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
+ 0x702c);
+ /* W1C Trigger Calibration */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DC_CALIB_CTRL,
+ 0xf02d);
+ /* Set DAC02/ClassD power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_AMP_PDE_FLOAT_CTL,
+ 0x2323);
+ /* Set EAPD high */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_EAPD_CTL,
+ 0x0002);
+ /* Enable vf707_r14 */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
+ RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
+
+ if (rt722->hw_vid == RT722_VB)
+ regmap_write(rt722->regmap, 0x2f54, 0x00);
+
+ /* clear flag */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
+ }
}
static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
{
int loop_check, chk_cnt = 100, ret;
unsigned int calib_status = 0;
+ unsigned int jack_func_status;
+ struct device *dev = &rt722->slave->dev;
+
+ regmap_read(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status);
+ dev_dbg(dev, "%s jack func_status=0x%x\n", __func__, jack_func_status);
+
+ if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt722->first_hw_init)) {
+ /* Config analog bias */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_ANALOG_BIAS_CTL3,
+ 0xa081);
+ /* GE related settings */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2,
+ 0xa009);
+ /* Button A, B, C, D bypass mode */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4,
+ 0xcf00);
+ /* HID1 slot enable */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL5,
+ 0x000f);
+ /* Report ID for HID1 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL0,
+ 0x1100);
+ /* OSC/OOC for slot 2, 3 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL7,
+ 0x0c12);
+ /* Set JD de-bounce clock control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_JD_CTRL1,
+ 0x7002);
+ /* Set DVQ=01 */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
+ 0xc215);
+ /* FSM switch to calibration manual mode */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_FSM_CTL,
+ 0x4100);
+ /* W1C Trigger DC calibration (HP) */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DAC_DC_CALI_CTL3,
+ 0x008d);
+ /* check HP calibration FSM status */
+ for (loop_check = 0; loop_check < chk_cnt; loop_check++) {
+ usleep_range(10000, 11000);
+ ret = rt722_sdca_index_read(rt722, RT722_VENDOR_CALI,
+ RT722_DAC_DC_CALI_CTL3, &calib_status);
+ if (ret < 0)
+ dev_dbg(&rt722->slave->dev, "calibration failed!, ret=%d\n", ret);
+ if ((calib_status & 0x0040) == 0x0)
+ break;
+ }
- /* Read eFuse */
- rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL,
- 0x4808);
- /* Button A, B, C, D bypass mode */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4,
- 0xcf00);
- /* HID1 slot enable */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL5,
- 0x000f);
- /* Report ID for HID1 */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL0,
- 0x1100);
- /* OSC/OOC for slot 2, 3 */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL7,
- 0x0c12);
- /* Set JD de-bounce clock control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_JD_CTRL1,
- 0x7002);
- /* Set DVQ=01 */
- rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL6,
- 0xc215);
- /* FSM switch to calibration manual mode */
- rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_FSM_CTL,
- 0x4100);
- /* W1C Trigger DC calibration (HP) */
- rt722_sdca_index_write(rt722, RT722_VENDOR_CALI, RT722_DAC_DC_CALI_CTL3,
- 0x008d);
- /* check HP calibration FSM status */
- for (loop_check = 0; loop_check < chk_cnt; loop_check++) {
- ret = rt722_sdca_index_read(rt722, RT722_VENDOR_CALI,
- RT722_DAC_DC_CALI_CTL3, &calib_status);
- if (ret < 0 || loop_check == chk_cnt)
- dev_dbg(&rt722->slave->dev, "calibration failed!, ret=%d\n", ret);
- if ((calib_status & 0x0040) == 0x0)
- break;
+ if (loop_check == chk_cnt)
+ dev_dbg(&rt722->slave->dev, "%s, calibration time-out!\n", __func__);
+
+ /* Set ADC09 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL,
+ 0x2a12);
+ /* Set MIC2 and LINE1 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_MIC2_LINE2_PDE_FLOAT_CTL,
+ 0x3429);
+ /* Set ET41h and LINE2 power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ET41_LINE2_PDE_FLOAT_CTL,
+ 0x4112);
+ /* Set DAC03 and HP power entity floating control */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL,
+ 0x4040);
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ENT_FLOAT_CTRL_1,
+ 0x4141);
+ rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_FLOAT_CTRL_1,
+ 0x0101);
+ /* Fine tune PDE40 latency */
+ regmap_write(rt722->regmap, 0x2f58, 0x07);
+ regmap_write(rt722->regmap, 0x2f03, 0x06);
+ /* MIC VRefo */
+ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
+ RT722_COMBO_JACK_AUTO_CTL1, 0x0200, 0x0200);
+ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
+ RT722_VREFO_GAT, 0x4000, 0x4000);
+ /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */
+ rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
+ 0x0010);
+
+ if (rt722->hw_vid == RT722_VB)
+ regmap_write(rt722->regmap, 0x2f51, 0x00);
+
+ /* clear flag */
+ regmap_write(rt722->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
+ FUNCTION_NEEDS_INITIALIZATION);
}
- /* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */
- rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
- 0x0010);
- /* Set ADC09 power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL,
- 0x2a12);
- /* Set MIC2 and LINE1 power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_MIC2_LINE2_PDE_FLOAT_CTL,
- 0x3429);
- /* Set ET41h and LINE2 power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ET41_LINE2_PDE_FLOAT_CTL,
- 0x4112);
- /* Set DAC03 and HP power entity floating control */
- rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL,
- 0x4040);
- /* Fine tune PDE40 latency */
- regmap_write(rt722->regmap, 0x2f58, 0x07);
}
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
+ unsigned int val;
rt722->disable_irq = false;
if (rt722->hw_init)
return 0;
+ regcache_cache_only(rt722->regmap, false);
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
@@ -1528,6 +1555,10 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
pm_runtime_get_noresume(&slave->dev);
+ rt722_sdca_index_read(rt722, RT722_VENDOR_REG, RT722_JD_PRODUCT_NUM, &val);
+ rt722->hw_vid = (val & 0x0f00) >> 8;
+ dev_dbg(&slave->dev, "%s hw_vid=0x%x\n", __func__, rt722->hw_vid);
+
rt722_sdca_dmic_preset(rt722);
rt722_sdca_amp_preset(rt722);
rt722_sdca_jack_preset(rt722);
@@ -1535,15 +1566,12 @@ 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;
/* Mark Slave initialization complete */
rt722->hw_init = true;
- pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h
index 44af8901352e..823abee9ab76 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;
@@ -40,6 +39,7 @@ struct rt722_sdca_priv {
/* For DMIC */
bool fu1e_dapm_mute;
bool fu1e_mixer_mute[4];
+ int hw_vid;
};
struct rt722_sdca_dmic_kctrl_priv {
@@ -69,6 +69,7 @@ struct rt722_sdca_dmic_kctrl_priv {
#define RT722_COMBO_JACK_AUTO_CTL2 0x46
#define RT722_COMBO_JACK_AUTO_CTL3 0x47
#define RT722_DIGITAL_MISC_CTRL4 0x4a
+#define RT722_VREFO_GAT 0x63
#define RT722_FSM_CTL 0x67
#define RT722_SDCA_INTR_REC 0x82
#define RT722_SW_CONFIG1 0x8a
@@ -127,6 +128,8 @@ struct rt722_sdca_dmic_kctrl_priv {
#define RT722_UMP_HID_CTL6 0x66
#define RT722_UMP_HID_CTL7 0x67
#define RT722_UMP_HID_CTL8 0x68
+#define RT722_FLOAT_CTRL_1 0x70
+#define RT722_ENT_FLOAT_CTRL_1 0x76
/* Parameter & Verb control 01 (0x1a)(NID:20h) */
#define RT722_HIDDEN_REG_SW_RESET (0x1 << 14)
@@ -181,6 +184,7 @@ struct rt722_sdca_dmic_kctrl_priv {
#define RT722_SDCA_ENT_PLATFORM_FU44 0x44
#define RT722_SDCA_ENT_XU03 0x03
#define RT722_SDCA_ENT_XU0D 0x0d
+#define RT722_SDCA_ENT0 0x00
/* RT722 SDCA control */
#define RT722_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10
@@ -195,6 +199,8 @@ struct rt722_sdca_dmic_kctrl_priv {
#define RT722_SDCA_CTL_REQ_POWER_STATE 0x01
#define RT722_SDCA_CTL_VENDOR_DEF 0x30
#define RT722_SDCA_CTL_FU_CH_GAIN 0x0b
+#define RT722_SDCA_CTL_FUNC_STATUS 0x10
+#define RT722_SDCA_CTL_ACTUAL_POWER_STATE 0x10
/* RT722 SDCA channel */
#define CH_L 0x01
@@ -213,6 +219,9 @@ struct rt722_sdca_dmic_kctrl_priv {
#define RT722_SDCA_RATE_96000HZ 0x0b
#define RT722_SDCA_RATE_192000HZ 0x0d
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION BIT(5)
+
enum {
RT722_AIF1, /* For headset mic and headphone */
RT722_AIF2, /* For speaker */
@@ -225,9 +234,13 @@ enum rt722_sdca_jd_src {
RT722_JD1,
};
+enum rt722_sdca_version {
+ RT722_VA,
+ RT722_VB,
+};
+
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/rt9123.c b/sound/soc/codecs/rt9123.c
new file mode 100644
index 000000000000..84fd3d6861de
--- /dev/null
+++ b/sound/soc/codecs/rt9123.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt9123.c -- RT9123 (SW I2C Mode) ALSA SoC Codec driver
+//
+// Author: ChiYuan Huang <cy_huang@richtek.com>
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/byteorder/generic.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#define RT9123_REG_AMPCTRL 0x01
+#define RT9123_REG_I2SOPT 0x02
+#define RT9123_REG_TDMRX 0x03
+#define RT9123_REG_SILVOLEN 0x04
+#define RT9123_REG_VOLGAIN 0x12
+#define RT9123_REG_ANAFLAG 0x36
+#define RT9123_REG_COMBOID 0xF7
+
+#define RT9123_MASK_SWRST BIT(15)
+#define RT9123_MASK_SWMUTE BIT(14)
+#define RT9123_MASK_AMPON BIT(12)
+#define RT9123_MASK_AUDBIT GENMASK(14, 12)
+#define RT9123_MASK_AUDFMT GENMASK(11, 8)
+#define RT9123_MASK_TDMRXLOC GENMASK(4, 0)
+#define RT9123_MASK_VENID GENMASK(15, 4)
+
+#define RT9123_FIXED_VENID 0x340
+
+struct rt9123_priv {
+ struct gpio_desc *enable;
+ unsigned int dai_fmt;
+ int tdm_slots;
+ int tdm_slot_width;
+};
+
+static int rt9123_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct device *dev = comp->dev;
+ unsigned int enable;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ enable = 1;
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ enable = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ /* AMPON bit is located in volatile RG, use pm_runtime to guarantee the RG access */
+ snd_soc_component_write_field(comp, RT9123_REG_AMPCTRL, RT9123_MASK_AMPON, enable);
+
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt9123_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rt9123_enable_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route rt9123_dapm_routes[] = {
+ { "Amp Drv", NULL, "HiFi Playback" },
+ { "SPK", NULL, "Amp Drv" },
+};
+
+static const DECLARE_TLV_DB_SCALE(dig_tlv, -10375, 25, 0);
+static const DECLARE_TLV_DB_RANGE(ana_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(-1200, 0, 0),
+ 1, 9, TLV_DB_SCALE_ITEM(0, 150, 0),
+ 10, 10, TLV_DB_SCALE_ITEM(1400, 0, 0));
+static const char * const pwmfreq_text[] = { "300KHz", "325KHz", "350KHz", "375KHz" };
+static const struct soc_enum rt9123_pwm_freq_enum =
+ SOC_ENUM_SINGLE(RT9123_REG_AMPCTRL, 4, ARRAY_SIZE(pwmfreq_text), pwmfreq_text);
+static const char * const i2sch_text[] = { "(L+R)/2", "LCH", "RCH", "(L+R)/2" };
+static const struct soc_enum rt9123_i2sch_select_enum =
+ SOC_ENUM_SINGLE(RT9123_REG_I2SOPT, 4, ARRAY_SIZE(i2sch_text), i2sch_text);
+
+static int rt9123_kcontrol_name_comp(struct snd_kcontrol *kcontrol, const char *s)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ const char *kctlname = kcontrol->id.name;
+
+ if (comp && comp->name_prefix)
+ kctlname += strlen(comp->name_prefix) + 1;
+
+ return strcmp(kctlname, s);
+}
+
+static int rt9123_xhandler_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct device *dev = comp->dev;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Since the RG bitfield for 'Speaker Volume' and 'PWM Frequency Select' are located in
+ * volatile RG address, special handling here with pm runtime API to guarantee RG read
+ * operation.
+ */
+ if (rt9123_kcontrol_name_comp(kcontrol, "Speaker Volume") == 0)
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+ else
+ ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to get control (%d)\n", ret);
+
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+}
+
+static int rt9123_xhandler_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct device *dev = comp->dev;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Since the RG bitfield for 'Speaker Volume' and 'PWM Frequency Select' are located in
+ * volatile RG address, special handling here with pm runtime API to guarantee RG write
+ * operation.
+ */
+ if (rt9123_kcontrol_name_comp(kcontrol, "Speaker Volume") == 0)
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ else
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to put control (%d)\n", ret);
+
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+}
+
+static const struct snd_kcontrol_new rt9123_controls[] = {
+ SOC_SINGLE_TLV("Master Volume", RT9123_REG_VOLGAIN, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_EXT_TLV("Speaker Volume", RT9123_REG_AMPCTRL, 0, 10, 0, rt9123_xhandler_get,
+ rt9123_xhandler_put, ana_tlv),
+ SOC_ENUM_EXT("PWM Frequency Select", rt9123_pwm_freq_enum, rt9123_xhandler_get,
+ rt9123_xhandler_put),
+ SOC_ENUM("I2S CH Select", rt9123_i2sch_select_enum),
+ SOC_SINGLE("Silence Detect Switch", RT9123_REG_SILVOLEN, 14, 1, 0),
+};
+
+static const struct snd_soc_component_driver rt9123_comp_driver = {
+ .controls = rt9123_controls,
+ .num_controls = ARRAY_SIZE(rt9123_controls),
+ .dapm_widgets = rt9123_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt9123_dapm_widgets),
+ .dapm_routes = rt9123_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt9123_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int rt9123_dai_set_format(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct rt9123_priv *rt9123 = snd_soc_dai_get_drvdata(dai);
+
+ rt9123->dai_fmt = fmt;
+ return 0;
+}
+
+static int rt9123_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct rt9123_priv *rt9123 = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *comp = dai->component;
+ struct device *dev = dai->dev;
+ unsigned int rx_loc;
+
+ dev_dbg(dev, "(slots, slot_width) = (%d, %d), (txmask, rxmask) = 0x%x, 0x%x\n", slots,
+ slot_width, tx_mask, rx_mask);
+
+ if (slots <= 0 || slot_width <= 0 || slots % 2 || slot_width % 8 ||
+ slots * slot_width > 256) {
+ dev_err(dev, "Invalid slot parameter (%d, %d)\n", slots, slot_width);
+ return -EINVAL;
+ }
+
+ if (!rx_mask || hweight_long(rx_mask) > 1 || ffs(rx_mask) > slots) {
+ dev_err(dev, "Invalid rx_mask 0x%08x, slots = %d\n", rx_mask, slots);
+ return -EINVAL;
+ }
+
+ /* Configure rx channel data location */
+ rx_loc = (ffs(rx_mask) - 1) * slot_width / 8;
+ snd_soc_component_write_field(comp, RT9123_REG_TDMRX, RT9123_MASK_TDMRXLOC, rx_loc);
+
+ rt9123->tdm_slots = slots;
+ rt9123->tdm_slot_width = slot_width;
+
+ return 0;
+}
+
+static int rt9123_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *param, struct snd_soc_dai *dai)
+{
+ struct rt9123_priv *rt9123 = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *comp = dai->component;
+ unsigned int fmtval, width, slot_width;
+ struct device *dev = dai->dev;
+ unsigned int audfmt, audbit;
+
+ fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, rt9123->dai_fmt);
+ if (rt9123->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && fmtval != SND_SOC_DAIFMT_DSP_B) {
+ dev_err(dev, "TDM only can support DSP_A or DSP_B format\n");
+ return -EINVAL;
+ }
+
+ switch (fmtval) {
+ case SND_SOC_DAIFMT_I2S:
+ audfmt = 0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ audfmt = 1;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ audfmt = 2;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ audfmt = rt9123->tdm_slots ? 4 : 3;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ audfmt = rt9123->tdm_slots ? 12 : 11;
+ break;
+ default:
+ dev_err(dev, "Unsupported format %d\n", fmtval);
+ return -EINVAL;
+ }
+
+ switch (width = params_width(param)) {
+ case 16:
+ audbit = 0;
+ break;
+ case 20:
+ audbit = 1;
+ break;
+ case 24:
+ audbit = 2;
+ break;
+ case 32:
+ audbit = 3;
+ break;
+ case 8:
+ audbit = 4;
+ break;
+ default:
+ dev_err(dev, "Unsupported width %d\n", width);
+ return -EINVAL;
+ }
+
+ slot_width = params_physical_width(param);
+ if (rt9123->tdm_slots && slot_width > rt9123->tdm_slot_width) {
+ dev_err(dev, "Slot width is larger than TDM slot width\n");
+ return -EINVAL;
+ }
+
+ snd_soc_component_write_field(comp, RT9123_REG_I2SOPT, RT9123_MASK_AUDFMT, audfmt);
+ snd_soc_component_write_field(comp, RT9123_REG_I2SOPT, RT9123_MASK_AUDBIT, audbit);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops rt9123_dai_ops = {
+ .set_fmt = rt9123_dai_set_format,
+ .set_tdm_slot = rt9123_dai_set_tdm_slot,
+ .hw_params = rt9123_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver rt9123_dai_driver = {
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_24000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &rt9123_dai_ops,
+};
+
+static bool rt9123_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x05:
+ case 0x12 ... 0x13:
+ case 0x20 ... 0x21:
+ case 0x36:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt9123_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x01 ... 0x05:
+ case 0x12 ... 0x13:
+ case 0x20 ... 0x21:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt9123_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x01:
+ case 0x20:
+ case 0x36:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt9123_regmap_config = {
+ .name = "rt9123",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .readable_reg = rt9123_readable_reg,
+ .writeable_reg = rt9123_writeable_reg,
+ .volatile_reg = rt9123_volatile_reg,
+ .cache_type = REGCACHE_MAPLE,
+ .num_reg_defaults_raw = RT9123_REG_ANAFLAG + 1,
+};
+
+static int rt9123_i2c_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct rt9123_priv *rt9123;
+ struct regmap *regmap;
+ __be16 value;
+ u16 venid;
+ int ret;
+
+ rt9123 = devm_kzalloc(dev, sizeof(*rt9123), GFP_KERNEL);
+ if (!rt9123)
+ return -ENOMEM;
+
+ rt9123->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(rt9123->enable))
+ return PTR_ERR(rt9123->enable);
+ else if (rt9123->enable)
+ usleep_range(250, 350);
+ else
+ dev_dbg(dev, "No 'enable' GPIO specified, treat it as default on\n");
+
+ /* Check vendor id information */
+ ret = i2c_smbus_read_i2c_block_data(i2c, RT9123_REG_COMBOID, sizeof(value), (u8 *)&value);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read vendor-id\n");
+
+ venid = be16_to_cpu(value);
+ if ((venid & RT9123_MASK_VENID) != RT9123_FIXED_VENID)
+ return dev_err_probe(dev, -ENODEV, "Incorrect vendor-id 0x%04x\n", venid);
+
+ /* Trigger RG reset before regmap init cache */
+ value = cpu_to_be16(RT9123_MASK_SWRST);
+ ret = i2c_smbus_write_i2c_block_data(i2c, RT9123_REG_AMPCTRL, sizeof(value), (u8 *)&value);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to trigger RG reset\n");
+
+ /* Need to wait 10ms for the reset to complete */
+ usleep_range(10000, 11000);
+
+ regmap = devm_regmap_init_i2c(i2c, &rt9123_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
+
+ i2c_set_clientdata(i2c, rt9123);
+
+ pm_runtime_set_autosuspend_delay(dev, 500);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
+
+ return devm_snd_soc_register_component(dev, &rt9123_comp_driver, &rt9123_dai_driver, 1);
+}
+
+#ifdef CONFIG_PM
+static int rt9123_runtime_suspend(struct device *dev)
+{
+ struct rt9123_priv *rt9123 = dev_get_drvdata(dev);
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+
+ if (rt9123->enable) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ gpiod_set_value(rt9123->enable, 0);
+ }
+
+ return 0;
+}
+
+static int rt9123_runtime_resume(struct device *dev)
+{
+ struct rt9123_priv *rt9123 = dev_get_drvdata(dev);
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
+
+ if (rt9123->enable) {
+ gpiod_set_value(rt9123->enable, 1);
+ usleep_range(250, 350);
+
+ regcache_cache_only(regmap, false);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops rt9123_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(rt9123_runtime_suspend, rt9123_runtime_resume, NULL)
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt9123_device_id[] = {
+ { .compatible = "richtek,rt9123" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt9123_device_id);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt9123_acpi_match[] = {
+ { "RT9123", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, rt9123_acpi_match);
+#endif
+
+static struct i2c_driver rt9123_i2c_driver = {
+ .driver = {
+ .name = "rt9123",
+ .of_match_table = of_match_ptr(rt9123_device_id),
+ .acpi_match_table = ACPI_PTR(rt9123_acpi_match),
+ .pm = pm_ptr(&rt9123_dev_pm_ops),
+ },
+ .probe = rt9123_i2c_probe,
+};
+module_i2c_driver(rt9123_i2c_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("ASoC rt9123 Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt9123p.c b/sound/soc/codecs/rt9123p.c
new file mode 100644
index 000000000000..d509659e735b
--- /dev/null
+++ b/sound/soc/codecs/rt9123p.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt9123p.c -- RT9123 (HW Mode) ALSA SoC Codec driver
+//
+// Author: ChiYuan Huang <cy_huang@richtek.com>
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+
+struct rt9123p_priv {
+ struct gpio_desc *enable;
+ unsigned int enable_delay;
+ int enable_switch;
+};
+
+static int rt9123p_daiops_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct rt9123p_priv *rt9123p = snd_soc_component_get_drvdata(comp);
+
+ if (!rt9123p->enable)
+ return 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ mdelay(rt9123p->enable_delay);
+ if (rt9123p->enable_switch) {
+ gpiod_set_value(rt9123p->enable, 1);
+ dev_dbg(comp->dev, "set enable to 1");
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ gpiod_set_value(rt9123p->enable, 0);
+ dev_dbg(comp->dev, "set enable to 0");
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt9123p_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ struct rt9123p_priv *rt9123p = snd_soc_component_get_drvdata(comp);
+
+ if (event & SND_SOC_DAPM_POST_PMU)
+ rt9123p->enable_switch = 1;
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ rt9123p->enable_switch = 0;
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt9123p_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rt9123p_enable_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route rt9123p_dapm_routes[] = {
+ {"Amp Drv", NULL, "HiFi Playback"},
+ {"SPK", NULL, "Amp Drv"},
+};
+
+static const struct snd_soc_component_driver rt9123p_comp_driver = {
+ .dapm_widgets = rt9123p_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt9123p_dapm_widgets),
+ .dapm_routes = rt9123p_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt9123p_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct snd_soc_dai_ops rt9123p_dai_ops = {
+ .trigger = rt9123p_daiops_trigger,
+};
+
+static struct snd_soc_dai_driver rt9123p_dai_driver = {
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_24000 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &rt9123p_dai_ops,
+};
+
+static int rt9123p_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rt9123p_priv *rt9123p;
+ int ret;
+
+ rt9123p = devm_kzalloc(dev, sizeof(*rt9123p), GFP_KERNEL);
+ if (!rt9123p)
+ return -ENOMEM;
+
+ rt9123p->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(rt9123p->enable))
+ return PTR_ERR(rt9123p->enable);
+
+ ret = device_property_read_u32(dev, "enable-delay-ms", &rt9123p->enable_delay);
+ if (ret) {
+ rt9123p->enable_delay = 0;
+ dev_dbg(dev, "no optional property 'enable-delay-ms' found, default: no delay\n");
+ }
+
+ platform_set_drvdata(pdev, rt9123p);
+
+ return devm_snd_soc_register_component(dev, &rt9123p_comp_driver, &rt9123p_dai_driver, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt9123p_device_id[] = {
+ { .compatible = "richtek,rt9123p" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt9123p_device_id);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt9123p_acpi_match[] = {
+ { "RT9123P", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, rt9123p_acpi_match);
+#endif
+
+static struct platform_driver rt9123p_platform_driver = {
+ .driver = {
+ .name = "rt9123p",
+ .of_match_table = of_match_ptr(rt9123p_device_id),
+ .acpi_match_table = ACPI_PTR(rt9123p_acpi_match),
+ },
+ .probe = rt9123p_platform_probe,
+};
+module_platform_driver(rt9123p_platform_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("ASoC rt9123p Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rtq9124.c b/sound/soc/codecs/rtq9124.c
new file mode 100644
index 000000000000..186904b31434
--- /dev/null
+++ b/sound/soc/codecs/rtq9124.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rtq9124.c -- RTQ9124 ALSA SoC Codec driver
+//
+// Author: ChiYuan Huang <cy_huang@richtek.com>
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/byteorder/generic.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#define RTQ9124_REG_SDI_SEL 0x00
+#define RTQ9124_REG_SDO_SEL 0x01
+#define RTQ9124_REG_I2S_OPT 0x02
+#define RTQ9124_REG_AMP_OPT 0x03
+#define RTQ9124_REG_STATE_CTRL 0x04
+#define RTQ9124_REG_PWM_PHASE 0x05
+#define RTQ9124_REG_SIL_CTRL 0x06
+#define RTQ9124_REG_PWM_SS_OPT 0x07
+#define RTQ9124_REG_ERR_INT_0 0x10
+#define RTQ9124_REG_ERR_MASK6 0x26
+#define RTQ9124_REG_TDM_TX_CH0 0x32
+#define RTQ9124_REG_TDM_RX_CH0 0x34
+#define RTQ9124_REG_VOL_OPT 0x38
+#define RTQ9124_REG_DCR_TH 0x4B
+#define RTQ9124_REG_ERR_TH 0x4C
+#define RTQ9124_REG_PROT_EN 0x5B
+#define RTQ9124_REG_PRJ_CODE 0xF9
+
+#define RTQ9124_MASK_CS_DATA_INV BIT(9)
+#define RTQ9124_MASK_VDDIO_SDO_SEL BIT(8)
+#define RTQ9124_MASK_AUD_BITS GENMASK(5, 4)
+#define RTQ9124_MASK_AUD_FMT GENMASK(3, 0)
+#define RTQ9124_MASK_CH_STATE GENMASK(1, 0)
+#define RTQ9124_MASK_SF_RESET BIT(15)
+
+#define RTQ9124_FIXED_VENID 0x9124
+
+struct rtq9124_priv {
+ struct gpio_desc *enable;
+ unsigned int dai_fmt;
+ int tdm_slots;
+ int tdm_slot_width;
+};
+
+static int rtq9124_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ unsigned int i, chan_state;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Change state to normal */
+ chan_state = 0;
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Change state to HiZ */
+ chan_state = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Before amp turn on, clear old events first */
+ for (i = 0; !chan_state && i < 8; i++)
+ snd_soc_component_write(comp, RTQ9124_REG_ERR_INT_0 + i, 0xffff);
+
+ snd_soc_component_write_field(comp, RTQ9124_REG_STATE_CTRL, RTQ9124_MASK_CH_STATE,
+ chan_state);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rtq9124_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rtq9124_enable_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route rtq9124_dapm_routes[] = {
+ { "Amp Drv", NULL, "HiFi Playback" },
+ { "SPK", NULL, "Amp Drv" },
+};
+
+static const DECLARE_TLV_DB_SCALE(dig_tlv, -10375, 25, 0);
+static const DECLARE_TLV_DB_RANGE(ana_tlv,
+ 0, 3, TLV_DB_SCALE_ITEM(-600, 600, 0),
+ 4, 6, TLV_DB_SCALE_ITEM(1400, 200, 0));
+static const char * const i2sch_text[] = { "(L+R)/2", "LCH", "RCH", "(L+R)/2" };
+static const struct soc_enum rtq9124_i2sch_select_enum =
+ SOC_ENUM_SINGLE(RTQ9124_REG_SDI_SEL, 0, ARRAY_SIZE(i2sch_text), i2sch_text);
+static const char * const sdo_vsel_text[] = { "1.8V", "3.3V" };
+static const struct soc_enum rtq9124_sdo_vselect_enum =
+ SOC_ENUM_SINGLE(RTQ9124_REG_SDO_SEL, 8, ARRAY_SIZE(sdo_vsel_text), sdo_vsel_text);
+static const char * const pwmfreq_text[] = { "8*fs", "10*fs", "40*fs", "44*fs", "48*fs" };
+static const struct soc_enum rtq9124_pwm_freq_enum =
+ SOC_ENUM_SINGLE(RTQ9124_REG_AMP_OPT, 4, ARRAY_SIZE(pwmfreq_text), pwmfreq_text);
+static const char * const out_angle_text[] = { "0", "45", "90", "135", "180", "225", "270", "315" };
+static const struct soc_enum rtq9124_out_angle_enum =
+ SOC_ENUM_SINGLE(RTQ9124_REG_PWM_PHASE, 0, ARRAY_SIZE(out_angle_text), out_angle_text);
+static const char * const sdo_select_text[] = {
+ "None", "I2S DataI", "Interface", "DSP", "DF", "ISense", "ACLoad Cos", "ACLoad Sin",
+ "DCR",
+};
+static const struct soc_enum rtq9124_sdo_select_enum =
+ SOC_ENUM_DOUBLE(RTQ9124_REG_SDO_SEL, 4, 0, ARRAY_SIZE(sdo_select_text), sdo_select_text);
+static const char * const ulqm_dcvt_text[] = { "Disable", "DC", "VT", "DC+VT" };
+static const struct soc_enum rtq9124_ulqm_dcvt_select_enum =
+ SOC_ENUM_SINGLE(RTQ9124_REG_STATE_CTRL, 10, ARRAY_SIZE(ulqm_dcvt_text), ulqm_dcvt_text);
+
+static const struct snd_kcontrol_new rtq9124_controls[] = {
+ SOC_SINGLE_TLV("Master Volume", RTQ9124_REG_VOL_OPT, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_TLV("Speaker Volume", RTQ9124_REG_AMP_OPT, 0, 6, 0, ana_tlv),
+ SOC_ENUM("I2S CH Select", rtq9124_i2sch_select_enum),
+ SOC_ENUM("SDO VDDIO Select", rtq9124_sdo_vselect_enum),
+ SOC_ENUM("PWM Frequency Select", rtq9124_pwm_freq_enum),
+ SOC_ENUM("PWM Output Phase Select", rtq9124_out_angle_enum),
+ SOC_ENUM("SDO Select", rtq9124_sdo_select_enum),
+ SOC_ENUM("ULQM DCVT Select", rtq9124_ulqm_dcvt_select_enum),
+ SOC_SINGLE("Silence Detect Enable Switch", RTQ9124_REG_SIL_CTRL, 7, 1, 0),
+ SOC_SINGLE("Spread Spectrum Enable Switch", RTQ9124_REG_PWM_SS_OPT, 7, 1, 0),
+};
+
+static int rtq9124_comp_probe(struct snd_soc_component *comp)
+{
+ /* CS Data INV */
+ snd_soc_component_write_field(comp, RTQ9124_REG_SDO_SEL, RTQ9124_MASK_CS_DATA_INV, 1);
+
+ /* RTLD */
+ snd_soc_component_write(comp, RTQ9124_REG_DCR_TH, 0x5e30);
+ snd_soc_component_write(comp, RTQ9124_REG_ERR_TH, 0x3ff);
+ snd_soc_component_write(comp, RTQ9124_REG_PROT_EN, 0x3fc);
+ snd_soc_component_write(comp, RTQ9124_REG_ERR_MASK6, 0);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver rtq9124_comp_driver = {
+ .probe = rtq9124_comp_probe,
+ .controls = rtq9124_controls,
+ .num_controls = ARRAY_SIZE(rtq9124_controls),
+ .dapm_widgets = rtq9124_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rtq9124_dapm_widgets),
+ .dapm_routes = rtq9124_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rtq9124_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int rtq9124_dai_set_format(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai);
+
+ rtq9124->dai_fmt = fmt;
+ return 0;
+}
+
+static int rtq9124_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *comp = dai->component;
+ struct device *dev = dai->dev;
+ unsigned int byte_loc, i;
+
+ dev_dbg(dev, "(slots, slot_width) = (%d, %d), (txmask, rxmask) = 0x%x, 0x%x\n", slots,
+ slot_width, tx_mask, rx_mask);
+
+ if (slots <= 0 || slots > 16 || slot_width <= 0 || slots % 2 || slot_width % 8) {
+ dev_err(dev, "Invalid slot parameter (%d, %d)\n", slots, slot_width);
+ return -EINVAL;
+ }
+
+ if (tx_mask && (hweight_long(tx_mask) > 2 || fls(tx_mask) > slots)) {
+ dev_err(dev, "Invalid tx_mask 0x%08x, slots = %d\n", tx_mask, slots);
+ return -EINVAL;
+ }
+
+ if (!rx_mask || hweight_long(rx_mask) > 1 || fls(rx_mask) > slots) {
+ dev_err(dev, "Invalid rx_mask 0x%08x, slots = %d\n", rx_mask, slots);
+ return -EINVAL;
+ }
+
+ /* Configure tx channel data location */
+ for (i = 0; tx_mask; i++, tx_mask ^= BIT(ffs(tx_mask) - 1)) {
+ byte_loc = (ffs(tx_mask) - 1) * slot_width / 8;
+ snd_soc_component_write(comp, RTQ9124_REG_TDM_TX_CH0 + i, byte_loc);
+ }
+
+ /* Configure rx channel data location */
+ byte_loc = (ffs(rx_mask) - 1) * slot_width / 8;
+ snd_soc_component_write(comp, RTQ9124_REG_TDM_RX_CH0, byte_loc);
+
+ rtq9124->tdm_slots = slots;
+ rtq9124->tdm_slot_width = slot_width;
+
+ return 0;
+}
+
+static int rtq9124_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *param, struct snd_soc_dai *dai)
+{
+ struct rtq9124_priv *rtq9124 = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *comp = dai->component;
+ unsigned int fmtval, width, slot_width, bitrate;
+ struct device *dev = dai->dev;
+ unsigned int audfmt, audbit;
+
+ fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, rtq9124->dai_fmt);
+ if (rtq9124->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A &&
+ fmtval != SND_SOC_DAIFMT_DSP_B) {
+ dev_err(dev, "TDM only can support DSP_A or DSP_B format\n");
+ return -EINVAL;
+ }
+
+ switch (fmtval) {
+ case SND_SOC_DAIFMT_I2S:
+ audfmt = 0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ audfmt = 1;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ audfmt = 2;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ audfmt = rtq9124->tdm_slots ? 7 : 3;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ audfmt = rtq9124->tdm_slots ? 15 : 11;
+ break;
+ default:
+ dev_err(dev, "Unsupported format %d\n", fmtval);
+ return -EINVAL;
+ }
+
+ switch (width = params_width(param)) {
+ case 16:
+ audbit = 0;
+ break;
+ case 20:
+ audbit = 1;
+ break;
+ case 24:
+ case 32:
+ audbit = 3;
+ break;
+ default:
+ dev_err(dev, "Unsupported width %d\n", width);
+ return -EINVAL;
+ }
+
+ if (rtq9124->tdm_slots) {
+ slot_width = params_physical_width(param);
+ if (slot_width > rtq9124->tdm_slot_width) {
+ dev_err(dev, "Slot width is larger than TDM slot width\n");
+ return -EINVAL;
+ }
+
+ bitrate = rtq9124->tdm_slots * rtq9124->tdm_slot_width * params_rate(param);
+ if (bitrate > 24576000) {
+ dev_err(dev, "Bitrate exceed the internal PLL 24.576MHz (%d)\n", bitrate);
+ return -EINVAL;
+ }
+ }
+
+ snd_soc_component_write_field(comp, RTQ9124_REG_I2S_OPT, RTQ9124_MASK_AUD_FMT, audfmt);
+ snd_soc_component_write_field(comp, RTQ9124_REG_I2S_OPT, RTQ9124_MASK_AUD_BITS, audbit);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops rtq9124_dai_ops = {
+ .set_fmt = rtq9124_dai_set_format,
+ .set_tdm_slot = rtq9124_dai_set_tdm_slot,
+ .hw_params = rtq9124_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver rtq9124_dai_driver = {
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_24000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &rtq9124_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static bool rtq9124_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x17:
+ case 0x20 ... 0x27:
+ case 0x30 ... 0x3D:
+ case 0x40 ... 0x68:
+ case 0x80 ... 0xBC:
+ case 0xC0 ... 0xDE:
+ case 0xE0 ... 0xE7:
+ case 0xF0 ... 0xFD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rtq9124_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x09:
+ case 0x0C ... 0x0E:
+ case 0x10 ... 0x17:
+ case 0x20 ... 0x27:
+ case 0x30:
+ case 0x32 ... 0x3D:
+ case 0x40 ... 0x4E:
+ case 0x50 ... 0x68:
+ case 0x80 ... 0xBC:
+ case 0xC0 ... 0xDE:
+ case 0xE0 ... 0xE7:
+ case 0xF0 ... 0xFD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rtq9124_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x0A ... 0x0B:
+ case 0x0F ... 0x17:
+ case 0x31:
+ case 0x4F:
+ case 0x51:
+ case 0x53 ... 0x57:
+ case 0x80 ... 0xBC:
+ case 0xC0 ... 0xDE:
+ case 0xE0 ... 0xE7:
+ case 0xF0 ... 0xFD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline u8 rtq9124_get_reg_len(unsigned int reg)
+{
+ return (reg >= 0x40 && reg <= 0x47) ? 4 : 2;
+}
+
+static int rtq9124_regmap_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct i2c_client *i2c = context;
+ u8 reg = *(u8 *)reg_buf;
+ u8 size = rtq9124_get_reg_len(reg);
+ u32 *val = val_buf;
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(i2c, reg, size, val_buf);
+ if (ret < 0)
+ return ret;
+ else if (ret != size)
+ return -EIO;
+
+ *val = size == 4 ? be32_to_cpup(val_buf) : be16_to_cpup(val_buf);
+
+ return 0;
+}
+
+static int rtq9124_regmap_write(void *context, const void *data, size_t count)
+{
+ struct i2c_client *i2c = context;
+ u8 reg = *(u8 *)data, *vbuf;
+ u8 size = rtq9124_get_reg_len(reg);
+ __be16 val16 = cpu_to_be16p(data + 1);
+ __be32 val32 = cpu_to_be32p(data + 1);
+
+ vbuf = size == 4 ? (u8 *)&val32 : (u8 *)&val16;
+ return i2c_smbus_write_i2c_block_data(i2c, reg, size, vbuf);
+}
+
+static const struct regmap_config rtq9124_regmap_config = {
+ .name = "rtq9124",
+ .reg_bits = 8,
+ .val_bits = 32,
+ .read = rtq9124_regmap_read,
+ .write = rtq9124_regmap_write,
+ .readable_reg = rtq9124_readable_reg,
+ .writeable_reg = rtq9124_writeable_reg,
+ .volatile_reg = rtq9124_volatile_reg,
+ .cache_type = REGCACHE_MAPLE,
+ .num_reg_defaults_raw = 0xFD + 1,
+ .use_single_read = 1,
+ .use_single_write = 1,
+};
+
+static const struct reg_sequence rtq9124_init_regs[] = {
+ { 0xfb, 0x0065 },
+ { 0x93, 0x2000 },
+ { 0xfb, 0x0000 },
+};
+
+static int rtq9124_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct rtq9124_priv *rtq9124;
+ struct regmap *regmap;
+ int ret;
+
+ rtq9124 = devm_kzalloc(dev, sizeof(*rtq9124), GFP_KERNEL);
+ if (!rtq9124)
+ return -ENOMEM;
+
+ rtq9124->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(rtq9124->enable))
+ return PTR_ERR(rtq9124->enable);
+ else if (rtq9124->enable)
+ usleep_range(6000, 7000);
+ else
+ dev_dbg(dev, "No 'enable' GPIO specified, treat it as default on\n");
+
+ /* Check vendor id information */
+ ret = i2c_smbus_read_word_swapped(i2c, RTQ9124_REG_PRJ_CODE);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read project code\n");
+ else if (ret != RTQ9124_FIXED_VENID)
+ return dev_err_probe(dev, -ENODEV, "Incorrect project-code 0x%04x\n", ret);
+
+ /* Trigger RG reset before regmap init */
+ ret = i2c_smbus_write_word_swapped(i2c, RTQ9124_REG_STATE_CTRL, RTQ9124_MASK_SF_RESET);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to trigger RG reset\n");
+
+ /* Need to wait 10ms for the reset to complete */
+ usleep_range(10000, 11000);
+
+ regmap = devm_regmap_init(dev, NULL, i2c, &rtq9124_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
+
+ ret = regmap_register_patch(regmap, rtq9124_init_regs, ARRAY_SIZE(rtq9124_init_regs));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register regmap patch\n");
+
+ i2c_set_clientdata(i2c, rtq9124);
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
+
+ return devm_snd_soc_register_component(dev, &rtq9124_comp_driver, &rtq9124_dai_driver, 1);
+}
+
+#ifdef CONFIG_PM
+static int rtq9124_runtime_suspend(struct device *dev)
+{
+ struct rtq9124_priv *rtq9124 = dev_get_drvdata(dev);
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+
+ if (rtq9124->enable) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ gpiod_set_value(rtq9124->enable, 0);
+ }
+
+ return 0;
+}
+
+static int rtq9124_runtime_resume(struct device *dev)
+{
+ struct rtq9124_priv *rtq9124 = dev_get_drvdata(dev);
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
+
+ if (rtq9124->enable) {
+ gpiod_set_value(rtq9124->enable, 1);
+ usleep_range(6000, 7000);
+
+ regcache_cache_only(regmap, false);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops rtq9124_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(rtq9124_runtime_suspend, rtq9124_runtime_resume, NULL)
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtq9124_device_id[] = {
+ { .compatible = "richtek,rtq9124" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rtq9124_device_id);
+#endif
+
+static struct i2c_driver rtq9124_driver = {
+ .driver = {
+ .name = "rtq9124",
+ .of_match_table = of_match_ptr(rtq9124_device_id),
+ .pm = pm_ptr(&rtq9124_dev_pm_ops),
+ },
+ .probe = rtq9124_probe,
+};
+module_i2c_driver(rtq9124_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("ASoC RTQ9124 Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c
new file mode 100644
index 000000000000..391cc03d687f
--- /dev/null
+++ b/sound/soc/codecs/rtq9128.c
@@ -0,0 +1,789 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright (c) 2023 Richtek Technology Corp.
+//
+// Author: ChiYuan Huang <cy_huang@richtek.com>
+//
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define RTQ9128_REG_SDI_SEL 0x00
+#define RTQ9128_REG_SDO_SEL 0x01
+#define RTQ9128_REG_I2S_OPT 0x02
+#define RTQ9128_REG_MISC 0x03
+#define RTQ9128_REG_STATE_CTRL 0x04
+#define RTQ9128_REG_PLLTRI_GEN1 0x05
+#define RTQ9128_REG_PLLTRI_GEN2 0x06
+#define RTQ9128_REG_PWM_SS_OPT 0x07
+#define RTQ9128_REG_DSP_EN 0x08
+#define RTQ9128_REG_TDM_TX_CH1 0x21
+#define RTQ9128_REG_TDM_RX_CH1 0x25
+#define RTQ9128_REG_MS_VOL 0x30
+#define RTQ9128_REG_CH1_VOL 0x31
+#define RTQ9128_REG_CH2_VOL 0x32
+#define RTQ9128_REG_CH3_VOL 0x33
+#define RTQ9128_REG_CH4_VOL 0x34
+#define RTQ9128_REG_PROT_OPT 0x71
+#define RTQ9128_REG_EFUSE_DATA 0xE0
+#define RTQ9128_REG_VENDOR_ID 0xF9
+
+#define RTQ9128_CHSTAT_VAL_MASK GENMASK(1, 0)
+#define RTQ9128_DOLEN_MASK GENMASK(7, 6)
+#define RTQ9128_TDMSRCIN_MASK GENMASK(5, 4)
+#define RTQ9128_AUDBIT_MASK GENMASK(5, 4)
+#define RTQ9128_AUDFMT_MASK GENMASK(3, 0)
+#define RTQ9128_MSMUTE_MASK BIT(0)
+#define RTQ9128_DIE_CHECK_MASK GENMASK(4, 0)
+#define RTQ9128_VENDOR_ID_MASK GENMASK(19, 8)
+
+#define RTQ9128_SOFT_RESET_VAL 0x80
+#define RTQ9128_VENDOR_ID_VAL 0x470
+#define RTQ9128_ALLCH_HIZ_VAL 0x55
+#define RTQ9128_ALLCH_ULQM_VAL 0xFF
+#define RTQ9128_TKA470B_VAL 0
+#define RTQ9128_RTQ9128DH_VAL 0x0F
+#define RTQ9128_RTQ9128DL_VAL 0x10
+
+struct rtq9128_data {
+ struct gpio_desc *enable;
+ unsigned int daifmt;
+ int tdm_slots;
+ int tdm_slot_width;
+ bool tdm_input_data2_select;
+};
+
+struct rtq9128_init_reg {
+ unsigned int reg;
+ unsigned int val;
+};
+
+static int rtq9128_get_reg_size(unsigned int reg)
+{
+ switch (reg) {
+ case 0x5C ... 0x6F:
+ case 0x98 ... 0x9F:
+ case 0xC0 ... 0xC3:
+ case 0xC8 ... 0xCF:
+ case 0xDF ... 0xE5:
+ case 0xF9:
+ return 4;
+ case 0x40 ... 0x4F:
+ return 3;
+ case 0x30 ... 0x35:
+ case 0x8C ... 0x97:
+ case 0xC4 ... 0xC7:
+ case 0xD7 ... 0xDA:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+static int rtq9128_i2c_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ u8 reg = *(u8 *)data;
+ int rg_size;
+
+ if (count != 5) {
+ dev_err(dev, "Invalid write for data length (%d)\n", (int)count);
+ return -EINVAL;
+ }
+
+ rg_size = rtq9128_get_reg_size(reg);
+ return i2c_smbus_write_i2c_block_data(i2c, reg, rg_size, data + count - rg_size);
+}
+
+static int rtq9128_i2c_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ u8 reg = *(u8 *)reg_buf;
+ u8 data_tmp[4] = {};
+ int rg_size, ret;
+
+ if (reg_size != 1 || val_size != 4) {
+ dev_err(dev, "Invalid read for reg_size (%d) or val_size (%d)\n", (int)reg_size,
+ (int)val_size);
+ return -EINVAL;
+ }
+
+ rg_size = rtq9128_get_reg_size(reg);
+ ret = i2c_smbus_read_i2c_block_data(i2c, reg, rg_size, data_tmp);
+ if (ret < 0)
+ return ret;
+ else if (ret != rg_size)
+ return -EIO;
+
+ memset(val_buf, 0, val_size - rg_size);
+ memcpy(val_buf + val_size - rg_size, data_tmp, rg_size);
+
+ return 0;
+}
+
+static const struct regmap_bus rtq9128_regmap_bus = {
+ .write = rtq9128_i2c_write,
+ .read = rtq9128_i2c_read,
+ .max_raw_read = 4,
+ .max_raw_write = 4,
+};
+
+static bool rtq9128_is_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x2B:
+ case 0x30 ... 0x35:
+ case 0x40 ... 0x56:
+ case 0x5C ... 0x76:
+ case 0x80 ... 0xAD:
+ case 0xB0 ... 0xBA:
+ case 0xC0 ... 0xE5:
+ case 0xF0 ... 0xFB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rtq9128_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x1F:
+ case 0x21 ... 0x2B:
+ case 0x30 ... 0x35:
+ case 0x40 ... 0x56:
+ case 0x5C ... 0x76:
+ case 0x80 ... 0x8B:
+ case 0xA0 ... 0xAD:
+ case 0xB0 ... 0xBA:
+ case 0xC0:
+ case 0xD0 ... 0xDE:
+ case 0xE0 ... 0xE5:
+ case 0xF0 ... 0xF3:
+ case 0xF6 ... 0xF8:
+ case 0xFA ... 0xFB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rtq9128_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x0F ... 0x17:
+ case 0x20:
+ case 0x53:
+ case 0x55:
+ case 0x5C ... 0x6F:
+ case 0x8C ... 0x9F:
+ case 0xC0 ... 0xCF:
+ case 0xDF:
+ case 0xF0 ... 0xF1:
+ case 0xF4 ... 0xF5:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rtq9128_regmap_config = {
+ .name = "rtq9128",
+ .reg_bits = 8,
+ .val_bits = 32,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .cache_type = REGCACHE_MAPLE,
+
+ .readable_reg = rtq9128_is_readable_reg,
+ .writeable_reg = rtq9128_is_writeable_reg,
+ .volatile_reg = rtq9128_is_volatile_reg,
+ .num_reg_defaults_raw = RTQ9128_REG_VENDOR_ID + 1,
+};
+
+static const DECLARE_TLV_DB_SCALE(dig_tlv, -10375, 25, 0);
+
+static const DECLARE_TLV_DB_RANGE(spkgain_tlv,
+ 0, 3, TLV_DB_SCALE_ITEM(-600, 600, 0),
+ 4, 5, TLV_DB_SCALE_ITEM(1500, 300, 0),
+);
+
+static const char * const source_select_text[] = { "CH1", "CH2", "CH3", "CH4" };
+static const char * const pwmfreq_select_text[] = { "8fs", "10fs", "40fs", "44fs", "48fs" };
+static const char * const phase_select_text[] = {
+ "0 degree", "45 degree", "90 degree", "135 degree",
+ "180 degree", "225 degree", "270 degree", "315 degree",
+};
+static const char * const dvdduv_select_text[] = { "1P4V", "1P5V", "2P1V", "2P3V" };
+
+static const struct soc_enum rtq9128_ch1_si_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 6, ARRAY_SIZE(source_select_text), source_select_text);
+static const struct soc_enum rtq9128_ch2_si_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 4, ARRAY_SIZE(source_select_text), source_select_text);
+static const struct soc_enum rtq9128_ch3_si_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 2, ARRAY_SIZE(source_select_text), source_select_text);
+static const struct soc_enum rtq9128_ch4_si_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_SDI_SEL, 0, ARRAY_SIZE(source_select_text), source_select_text);
+static const struct soc_enum rtq9128_pwm_freq_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN1, 4, ARRAY_SIZE(pwmfreq_select_text),
+ pwmfreq_select_text);
+static const struct soc_enum rtq9128_out2_phase_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN1, 0, ARRAY_SIZE(phase_select_text),
+ phase_select_text);
+static const struct soc_enum rtq9128_out3_phase_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN2, 4, ARRAY_SIZE(phase_select_text),
+ phase_select_text);
+static const struct soc_enum rtq9128_out4_phase_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_PLLTRI_GEN2, 0, ARRAY_SIZE(phase_select_text),
+ phase_select_text);
+
+/*
+ * In general usage, DVDD could be 1P8V, 3P0V or 3P3V.
+ * This DVDD undervoltage protection is to prevent from the abnormal power
+ * lose case while the amplifier is operating. Due to the different DVDD
+ * application, treat this threshold as a user choosable option.
+ */
+static const struct soc_enum rtq9128_dvdduv_select_enum =
+ SOC_ENUM_SINGLE(RTQ9128_REG_PROT_OPT, 6, ARRAY_SIZE(dvdduv_select_text),
+ dvdduv_select_text);
+
+static const struct snd_kcontrol_new rtq9128_snd_ctrls[] = {
+ SOC_SINGLE_TLV("MS Volume", RTQ9128_REG_MS_VOL, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_TLV("CH1 Volume", RTQ9128_REG_CH1_VOL, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_TLV("CH2 Volume", RTQ9128_REG_CH2_VOL, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_TLV("CH3 Volume", RTQ9128_REG_CH3_VOL, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_TLV("CH4 Volume", RTQ9128_REG_CH4_VOL, 2, 511, 1, dig_tlv),
+ SOC_SINGLE_TLV("SPK Gain Volume", RTQ9128_REG_MISC, 0, 5, 0, spkgain_tlv),
+ SOC_SINGLE("PBTL12 Switch", RTQ9128_REG_MISC, 5, 1, 0),
+ SOC_SINGLE("PBTL34 Switch", RTQ9128_REG_MISC, 4, 1, 0),
+ SOC_SINGLE("Spread Spectrum Switch", RTQ9128_REG_PWM_SS_OPT, 7, 1, 0),
+ SOC_SINGLE("SDO Select", RTQ9128_REG_SDO_SEL, 0, 15, 0),
+ SOC_ENUM("CH1 SI Select", rtq9128_ch1_si_enum),
+ SOC_ENUM("CH2 SI Select", rtq9128_ch2_si_enum),
+ SOC_ENUM("CH3 SI Select", rtq9128_ch3_si_enum),
+ SOC_ENUM("CH4 SI Select", rtq9128_ch4_si_enum),
+ SOC_ENUM("PWM FREQ Select", rtq9128_pwm_freq_enum),
+ SOC_ENUM("OUT2 Phase Select", rtq9128_out2_phase_enum),
+ SOC_ENUM("OUT3 Phase Select", rtq9128_out3_phase_enum),
+ SOC_ENUM("OUT4 Phase Select", rtq9128_out4_phase_enum),
+ SOC_ENUM("DVDD UV Threshold Select", rtq9128_dvdduv_select_enum),
+};
+
+static int rtq9128_dac_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+ unsigned int shift, mask;
+ int ret;
+
+ dev_dbg(comp->dev, "%s: %s event %d\n", __func__, w->name, event);
+
+ if (snd_soc_dapm_widget_name_cmp(w, "DAC1") == 0)
+ shift = 6;
+ else if (snd_soc_dapm_widget_name_cmp(w, "DAC2") == 0)
+ shift = 4;
+ else if (snd_soc_dapm_widget_name_cmp(w, "DAC3") == 0)
+ shift = 2;
+ else
+ shift = 0;
+
+ mask = RTQ9128_CHSTAT_VAL_MASK << shift;
+
+ /* Turn channel state to Normal or HiZ */
+ ret = snd_soc_component_write_field(comp, RTQ9128_REG_STATE_CTRL, mask,
+ event != SND_SOC_DAPM_POST_PMU);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * For each channel turns on, HW will trigger DC load detect and DC
+ * offset calibration, the time is needed for all the actions done.
+ */
+ if (event == SND_SOC_DAPM_POST_PMU)
+ msleep(25);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rtq9128_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC_E("DAC1", NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("DAC2", NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("DAC3", NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("DAC4", NULL, SND_SOC_NOPM, 0, 0, rtq9128_dac_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("OUT1"),
+ SND_SOC_DAPM_OUTPUT("OUT2"),
+ SND_SOC_DAPM_OUTPUT("OUT3"),
+ SND_SOC_DAPM_OUTPUT("OUT4"),
+};
+
+static const struct snd_soc_dapm_route rtq9128_dapm_routes[] = {
+ { "DAC1", NULL, "Playback" },
+ { "DAC2", NULL, "Playback" },
+ { "DAC3", NULL, "Playback" },
+ { "DAC4", NULL, "Playback" },
+ { "OUT1", NULL, "DAC1" },
+ { "OUT2", NULL, "DAC2" },
+ { "OUT3", NULL, "DAC3" },
+ { "OUT4", NULL, "DAC4" },
+ { "Capture", NULL, "DAC1" },
+ { "Capture", NULL, "DAC2" },
+ { "Capture", NULL, "DAC3" },
+ { "Capture", NULL, "DAC4" },
+};
+
+static const struct rtq9128_init_reg rtq9128_tka470b_tables[] = {
+ { 0xA0, 0xEF },
+ { 0x0D, 0x00 },
+ { 0x03, 0x05 },
+ { 0x05, 0x31 },
+ { 0x06, 0x23 },
+ { 0x70, 0x11 },
+ { 0x75, 0x1F },
+ { 0xB6, 0x03 },
+ { 0xB9, 0x03 },
+ { 0xB8, 0x03 },
+ { 0xC1, 0xFF },
+ { 0xF8, 0x72 },
+ { 0x30, 0x180 },
+};
+
+static const struct rtq9128_init_reg rtq9128_dh_tables[] = {
+ { 0x0F, 0x00 },
+ { 0x03, 0x0D },
+ { 0xB2, 0xFF },
+ { 0xB3, 0xFF },
+ { 0x30, 0x180 },
+ { 0x8A, 0x55 },
+ { 0x72, 0x00 },
+ { 0xB1, 0xE3 },
+};
+
+static const struct rtq9128_init_reg rtq9128_dl_tables[] = {
+ { 0x0F, 0x00 },
+ { 0x03, 0x0D },
+ { 0x30, 0x180 },
+ { 0x8A, 0x55 },
+ { 0x72, 0x00 },
+ { 0xB1, 0xE3 },
+};
+
+static int rtq9128_component_probe(struct snd_soc_component *comp)
+{
+ const struct rtq9128_init_reg *table, *curr;
+ size_t table_size;
+ unsigned int val;
+ int i, ret;
+
+ ret = pm_runtime_resume_and_get(comp->dev);
+ if (ret < 0) {
+ dev_err(comp->dev, "Failed to resume device (%d)\n", ret);
+ return ret;
+ }
+
+ val = snd_soc_component_read(comp, RTQ9128_REG_EFUSE_DATA);
+
+ switch (FIELD_GET(RTQ9128_DIE_CHECK_MASK, val)) {
+ case RTQ9128_TKA470B_VAL:
+ table = rtq9128_tka470b_tables;
+ table_size = ARRAY_SIZE(rtq9128_tka470b_tables);
+ break;
+ case RTQ9128_RTQ9128DH_VAL:
+ table = rtq9128_dh_tables;
+ table_size = ARRAY_SIZE(rtq9128_dh_tables);
+ break;
+ default:
+ table = rtq9128_dl_tables;
+ table_size = ARRAY_SIZE(rtq9128_dl_tables);
+ break;
+ }
+
+ for (i = 0, curr = table; i < table_size; i++, curr++) {
+ ret = snd_soc_component_write(comp, curr->reg, curr->val);
+ if (ret < 0)
+ return ret;
+ }
+
+ pm_runtime_mark_last_busy(comp->dev);
+ pm_runtime_put(comp->dev);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver rtq9128_comp_driver = {
+ .probe = rtq9128_component_probe,
+ .controls = rtq9128_snd_ctrls,
+ .num_controls = ARRAY_SIZE(rtq9128_snd_ctrls),
+ .dapm_widgets = rtq9128_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rtq9128_dapm_widgets),
+ .dapm_routes = rtq9128_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rtq9128_dapm_routes),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int rtq9128_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai);
+ struct device *dev = dai->dev;
+
+ dev_dbg(dev, "%s: fmt 0x%8x\n", __func__, fmt);
+
+ /* Only support bitclock & framesync as consumer */
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) {
+ dev_err(dev, "Only support BCK and LRCK as consumer\n");
+ return -EINVAL;
+ }
+
+ /* Store here and will be used in runtime hw_params for DAI format setting */
+ data->daifmt = fmt;
+
+ return 0;
+}
+
+static int rtq9128_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_component *comp = dai->component;
+ struct device *dev = dai->dev;
+ unsigned int mask, start_loc, srcin_select;
+ int i, frame_length, ret;
+
+ dev_dbg(dev, "%s: slot %d slot_width %d, tx/rx mask 0x%x 0x%x\n", __func__, slots,
+ slot_width, tx_mask, rx_mask);
+
+ if (slots <= 0 || slot_width <= 0 || slot_width % 8) {
+ dev_err(dev, "Invalid slot numbers (%d) or width (%d)\n", slots, slot_width);
+ return -EINVAL;
+ }
+
+ /* HW supported maximum frame length 512 */
+ frame_length = slots * slot_width;
+ if (frame_length > 512) {
+ dev_err(dev, "frame length exceed the maximum (%d)\n", frame_length);
+ return -EINVAL;
+ }
+
+ if (!rx_mask || hweight_long(tx_mask) > slots || hweight_long(rx_mask) > slots ||
+ fls(tx_mask) > slots || fls(rx_mask) > slots) {
+ dev_err(dev, "Invalid tx/rx mask (0x%x/0x%x)\n", tx_mask, rx_mask);
+ return -EINVAL;
+ }
+
+ for (mask = tx_mask, i = 0; i < 4 && mask; i++) {
+ start_loc = (ffs(mask) - 1) * slot_width / 8;
+ mask &= ~BIT(ffs(mask) - 1);
+
+ ret = snd_soc_component_write(comp, RTQ9128_REG_TDM_TX_CH1 + i, start_loc);
+ if (ret < 0) {
+ dev_err(dev, "Failed to assign tx_loc %d (%d)\n", i, ret);
+ return ret;
+ }
+ }
+
+ for (mask = rx_mask, i = 0; i < 4 && mask; i++) {
+ start_loc = (ffs(mask) - 1) * slot_width / 8;
+ mask &= ~BIT(ffs(mask) - 1);
+
+ ret = snd_soc_component_write(comp, RTQ9128_REG_TDM_RX_CH1 + i, start_loc);
+ if (ret < 0) {
+ dev_err(dev, "Failed to assign rx_loc %d (%d)\n", i, ret);
+ return ret;
+ }
+ }
+
+ srcin_select = data->tdm_input_data2_select ? RTQ9128_TDMSRCIN_MASK : 0;
+ ret = snd_soc_component_update_bits(comp, RTQ9128_REG_SDO_SEL, RTQ9128_TDMSRCIN_MASK,
+ srcin_select);
+ if (ret < 0) {
+ dev_err(dev, "Failed to configure TDM source input select\n");
+ return ret;
+ }
+
+ data->tdm_slots = slots;
+ data->tdm_slot_width = slot_width;
+
+ return 0;
+}
+
+static int rtq9128_dai_hw_params(struct snd_pcm_substream *stream, struct snd_pcm_hw_params *param,
+ struct snd_soc_dai *dai)
+{
+ struct rtq9128_data *data = snd_soc_dai_get_drvdata(dai);
+ unsigned int width, slot_width, bitrate, audbit, dolen;
+ struct snd_soc_component *comp = dai->component;
+ struct device *dev = dai->dev;
+ unsigned int fmtval, audfmt;
+ int ret;
+
+ dev_dbg(dev, "%s: width %d\n", __func__, params_width(param));
+
+ fmtval = FIELD_GET(SND_SOC_DAIFMT_FORMAT_MASK, data->daifmt);
+ if (data->tdm_slots && fmtval != SND_SOC_DAIFMT_DSP_A && fmtval != SND_SOC_DAIFMT_DSP_B) {
+ dev_err(dev, "TDM is used, format only support DSP_A or DSP_B\n");
+ return -EINVAL;
+ }
+
+ switch (fmtval) {
+ case SND_SOC_DAIFMT_I2S:
+ audfmt = 8;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ audfmt = 9;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ audfmt = 10;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ audfmt = data->tdm_slots ? 12 : 11;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ audfmt = data->tdm_slots ? 4 : 3;
+ break;
+ default:
+ dev_err(dev, "Unsupported format 0x%8x\n", fmtval);
+ return -EINVAL;
+ }
+
+ switch (width = params_width(param)) {
+ case 16:
+ audbit = 0;
+ break;
+ case 18:
+ audbit = 1;
+ break;
+ case 20:
+ audbit = 2;
+ break;
+ case 24:
+ case 32:
+ audbit = 3;
+ break;
+ default:
+ dev_err(dev, "Unsupported width (%d)\n", width);
+ return -EINVAL;
+ }
+
+ slot_width = params_physical_width(param);
+
+ if (data->tdm_slots) {
+ if (slot_width > data->tdm_slot_width) {
+ dev_err(dev, "slot width is larger than TDM slot width\n");
+ return -EINVAL;
+ }
+
+ /* Check BCK not exceed the maximum supported rate 24.576MHz */
+ bitrate = data->tdm_slots * data->tdm_slot_width * params_rate(param);
+ if (bitrate > 24576000) {
+ dev_err(dev, "bitrate exceed the maximum (%d)\n", bitrate);
+ return -EINVAL;
+ }
+
+ /* If TDM is used, configure slot width as TDM slot witdh */
+ slot_width = data->tdm_slot_width;
+ }
+
+ switch (slot_width) {
+ case 16:
+ dolen = 0;
+ break;
+ case 24:
+ dolen = 1;
+ break;
+ case 32:
+ dolen = 2;
+ break;
+ default:
+ dev_err(dev, "Unsupported slot width (%d)\n", slot_width);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_write_field(comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDFMT_MASK, audfmt);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_write_field(comp, RTQ9128_REG_I2S_OPT, RTQ9128_AUDBIT_MASK, audbit);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_write_field(comp, RTQ9128_REG_SDO_SEL, RTQ9128_DOLEN_MASK, dolen);
+ return ret < 0 ? ret : 0;
+}
+
+static int rtq9128_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct device *dev = dai->dev;
+ int ret;
+
+ dev_dbg(dev, "%s: mute (%d), stream (%d)\n", __func__, mute, stream);
+
+ ret = snd_soc_component_write_field(comp, RTQ9128_REG_DSP_EN, RTQ9128_MSMUTE_MASK,
+ mute ? 1 : 0);
+ return ret < 0 ? ret : 0;
+}
+
+static const struct snd_soc_dai_ops rtq9128_dai_ops = {
+ .set_fmt = rtq9128_dai_set_fmt,
+ .set_tdm_slot = rtq9128_dai_set_tdm_slot,
+ .hw_params = rtq9128_dai_hw_params,
+ .mute_stream = rtq9128_dai_mute_stream,
+ .no_capture_mute = 1,
+};
+
+#define RTQ9128_FMTS_MASK (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
+ SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver rtq9128_dai = {
+ .name = "rtq9128-aif",
+ .playback = {
+ .stream_name = "Playback",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = RTQ9128_FMTS_MASK,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = RTQ9128_FMTS_MASK,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &rtq9128_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static int rtq9128_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct rtq9128_data *data;
+ struct regmap *regmap;
+ unsigned int venid;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(data->enable))
+ return dev_err_probe(dev, PTR_ERR(data->enable), "Failed to get 'enable' gpio\n");
+ else if (data->enable)
+ usleep_range(10000, 11000);
+
+ data->tdm_input_data2_select = device_property_read_bool(dev,
+ "richtek,tdm-input-data2-select");
+
+ i2c_set_clientdata(i2c, data);
+
+ /*
+ * Due to the bad design to combine SOFT_RESET bit with other function,
+ * directly use generic i2c API to trigger SOFT_RESET.
+ */
+ ret = i2c_smbus_write_byte_data(i2c, RTQ9128_REG_MISC, RTQ9128_SOFT_RESET_VAL);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to trigger software reset\n");
+
+ /* After trigger soft reset, have to wait 10ms for digital reset done */
+ usleep_range(10000, 11000);
+
+ regmap = devm_regmap_init(dev, &rtq9128_regmap_bus, dev, &rtq9128_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
+
+ ret = regmap_read(regmap, RTQ9128_REG_VENDOR_ID, &venid);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get vendor id\n");
+
+ venid = FIELD_GET(RTQ9128_VENDOR_ID_MASK, venid);
+ if (venid != RTQ9128_VENDOR_ID_VAL)
+ return dev_err_probe(dev, -ENODEV, "Vendor ID not match (0x%x)\n", venid);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_mark_last_busy(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
+
+ return devm_snd_soc_register_component(dev, &rtq9128_comp_driver, &rtq9128_dai, 1);
+}
+
+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);
+
+ /* If 'enable' gpio not specified, change all channels to ultra low quiescent */
+ if (!data->enable)
+ return regmap_write(regmap, RTQ9128_REG_STATE_CTRL, RTQ9128_ALLCH_ULQM_VAL);
+
+ gpiod_set_value_cansleep(data->enable, 0);
+
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+
+ return 0;
+}
+
+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);
+
+ /* If 'enable' gpio not specified, change all channels to default Hi-Z */
+ if (!data->enable)
+ return regmap_write(regmap, RTQ9128_REG_STATE_CTRL, RTQ9128_ALLCH_HIZ_VAL);
+
+ gpiod_set_value_cansleep(data->enable, 1);
+
+ /* Wait digital block to be ready */
+ usleep_range(10000, 11000);
+
+ regcache_cache_only(regmap, false);
+ return regcache_sync(regmap);
+}
+
+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[] = {
+ { .compatible = "richtek,rtq9128" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rtq9128_device_table);
+
+static struct i2c_driver rtq9128_driver = {
+ .driver = {
+ .name = "rtq9128",
+ .of_match_table = rtq9128_device_table,
+ .pm = pm_ptr(&rtq9128_pm_ops),
+ },
+ .probe = rtq9128_probe,
+};
+module_i2c_driver(rtq9128_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("RTQ9128 4CH Audio Amplifier Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c
index 5498ff027c58..574c08b14f0c 100644
--- a/sound/soc/codecs/sdw-mockup.c
+++ b/sound/soc/codecs/sdw-mockup.c
@@ -262,7 +262,6 @@ MODULE_DEVICE_TABLE(sdw, sdw_mockup_id);
static struct sdw_driver sdw_mockup_sdw_driver = {
.driver = {
.name = "sdw-mockup",
- .owner = THIS_MODULE,
},
.probe = sdw_mockup_sdw_probe,
.remove = sdw_mockup_sdw_remove,
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index b22ba95bd0c0..320312f8db92 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -13,11 +13,11 @@
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/log2.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
@@ -540,7 +540,7 @@ static int dac_info_volsw(struct snd_kcontrol *kcontrol,
static int dac_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int reg;
int l;
int r;
@@ -593,7 +593,7 @@ static int dac_get_volsw(struct snd_kcontrol *kcontrol,
static int dac_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int reg;
int l;
int r;
@@ -631,7 +631,7 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
static int avc_get_threshold(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int db, i;
u16 reg = snd_soc_component_read(component, SGTL5000_DAP_AVC_THRESHOLD);
@@ -664,7 +664,7 @@ static int avc_get_threshold(struct snd_kcontrol *kcontrol,
static int avc_put_threshold(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int db;
u16 reg;
@@ -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;
@@ -1809,7 +1809,7 @@ static void sgtl5000_i2c_shutdown(struct i2c_client *client)
}
static const struct i2c_device_id sgtl5000_id[] = {
- {"sgtl5000", 0},
+ {"sgtl5000"},
{},
};
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c
index cb4c491078c2..07c9d89ab24a 100644
--- a/sound/soc/codecs/sigmadsp-i2c.c
+++ b/sound/soc/codecs/sigmadsp-i2c.c
@@ -9,7 +9,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "sigmadsp.h"
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index 3047a6fbb380..201f74e3a7ae 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -43,7 +43,7 @@ struct sigmadsp_data {
uint32_t samplerates;
unsigned int addr;
unsigned int length;
- uint8_t data[];
+ uint8_t data[] __counted_by(length);
};
struct sigma_fw_chunk {
@@ -270,7 +270,7 @@ static int sigma_fw_load_data(struct sigmadsp *sigmadsp,
length -= sizeof(*data_chunk);
- data = kzalloc(sizeof(*data) + length, GFP_KERNEL);
+ data = kzalloc(struct_size(data, data, length), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -413,7 +413,8 @@ static int process_sigma_action(struct sigmadsp *sigmadsp,
if (len < 3)
return -EINVAL;
- data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL);
+ data = kzalloc(struct_size(data, data, size_sub(len, 2)),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -669,36 +670,19 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
{
struct snd_card *card = sigmadsp->component->card->snd_card;
- struct snd_kcontrol_volatile *vd;
- struct snd_ctl_elem_id id;
bool active;
- bool changed = false;
+ int changed;
active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask);
-
- down_write(&card->controls_rwsem);
- if (!ctrl->kcontrol) {
- up_write(&card->controls_rwsem);
+ if (!ctrl->kcontrol)
return;
- }
-
- id = ctrl->kcontrol->id;
- vd = &ctrl->kcontrol->vd[0];
- if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) {
- vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- changed = true;
- }
- up_write(&card->controls_rwsem);
-
- if (active && changed) {
+ changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active);
+ if (active && changed > 0) {
mutex_lock(&sigmadsp->lock);
if (ctrl->cached)
sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
mutex_unlock(&sigmadsp->lock);
}
-
- if (changed)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id);
}
/**
@@ -821,4 +805,5 @@ int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
}
EXPORT_SYMBOL_GPL(sigmadsp_restrict_params);
+MODULE_DESCRIPTION("Analog Devices SigmaStudio firmware helpers");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c
index bf67de12d20b..069555f35f73 100644
--- a/sound/soc/codecs/simple-mux.c
+++ b/sound/soc/codecs/simple-mux.c
@@ -6,15 +6,26 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/mux/driver.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
+#define MUX_TEXT_SIZE 2
+#define MUX_WIDGET_SIZE 4
+#define MUX_ROUTE_SIZE 3
struct simple_mux {
struct gpio_desc *gpiod_mux;
unsigned int mux;
+ const char *mux_texts[MUX_TEXT_SIZE];
+ unsigned int idle_state;
+ struct soc_enum mux_enum;
+ struct snd_kcontrol_new mux_mux;
+ struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE];
+ struct snd_soc_dapm_route mux_routes[MUX_ROUTE_SIZE];
+ struct snd_soc_component_driver mux_driver;
};
-static const char * const simple_mux_texts[] = {
+static const char * const simple_mux_texts[MUX_TEXT_SIZE] = {
"Input 1", "Input 2"
};
@@ -23,7 +34,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(simple_mux_enum, simple_mux_texts);
static int simple_mux_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
struct simple_mux *priv = snd_soc_component_get_drvdata(c);
@@ -35,7 +46,7 @@ static int simple_mux_control_get(struct snd_kcontrol *kcontrol,
static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
struct simple_mux *priv = snd_soc_component_get_drvdata(c);
@@ -48,6 +59,10 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol,
priv->mux = ucontrol->value.enumerated.item[0];
+ if (priv->idle_state != MUX_IDLE_AS_IS &&
+ snd_soc_dapm_get_bias_level(dapm) < SND_SOC_BIAS_PREPARE)
+ return 0;
+
gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux);
return snd_soc_dapm_mux_update_power(dapm, kcontrol,
@@ -66,31 +81,48 @@ static unsigned int simple_mux_read(struct snd_soc_component *component,
static const struct snd_kcontrol_new simple_mux_mux =
SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put);
-static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[] = {
+static int simple_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct simple_mux *priv = snd_soc_component_get_drvdata(c);
+
+ if (priv->idle_state != MUX_IDLE_AS_IS) {
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ gpiod_set_value_cansleep(priv->gpiod_mux, priv->idle_state);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = {
SND_SOC_DAPM_INPUT("IN1"),
SND_SOC_DAPM_INPUT("IN2"),
- SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux),
+ SND_SOC_DAPM_MUX_E("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux, // see simple_mux_probe()
+ simple_mux_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("OUT"),
};
-static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = {
+static const struct snd_soc_dapm_route simple_mux_dapm_routes[MUX_ROUTE_SIZE] = {
{ "OUT", NULL, "MUX" },
- { "MUX", "Input 1", "IN1" },
- { "MUX", "Input 2", "IN2" },
-};
-
-static const struct snd_soc_component_driver simple_mux_component_driver = {
- .dapm_widgets = simple_mux_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets),
- .dapm_routes = simple_mux_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes),
- .read = simple_mux_read,
+ { "MUX", "Input 1", "IN1" }, // see simple_mux_probe()
+ { "MUX", "Input 2", "IN2" }, // see simple_mux_probe()
};
static int simple_mux_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct simple_mux *priv;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -103,7 +135,38 @@ static int simple_mux_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->gpiod_mux),
"Failed to get 'mux' gpio");
- return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0);
+ /* Copy default settings */
+ memcpy(&priv->mux_texts, &simple_mux_texts, sizeof(priv->mux_texts));
+ memcpy(&priv->mux_enum, &simple_mux_enum, sizeof(priv->mux_enum));
+ memcpy(&priv->mux_mux, &simple_mux_mux, sizeof(priv->mux_mux));
+ memcpy(&priv->mux_widgets, &simple_mux_dapm_widgets, sizeof(priv->mux_widgets));
+ memcpy(&priv->mux_routes, &simple_mux_dapm_routes, sizeof(priv->mux_routes));
+
+ priv->mux_driver.dapm_widgets = priv->mux_widgets;
+ priv->mux_driver.num_dapm_widgets = MUX_WIDGET_SIZE;
+ priv->mux_driver.dapm_routes = priv->mux_routes;
+ priv->mux_driver.num_dapm_routes = MUX_ROUTE_SIZE;
+ priv->mux_driver.read = simple_mux_read;
+
+ /* Overwrite text ("Input 1", "Input 2") if property exists */
+ of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE);
+
+ ret = of_property_read_u32(np, "idle-state", &priv->idle_state);
+ if (ret < 0) {
+ priv->idle_state = MUX_IDLE_AS_IS;
+ } else if (priv->idle_state != MUX_IDLE_AS_IS && priv->idle_state >= 2) {
+ dev_err(dev, "invalid idle-state %u\n", priv->idle_state);
+ return -EINVAL;
+ }
+
+ /* switch to use priv data instead of default */
+ priv->mux_enum.texts = priv->mux_texts;
+ priv->mux_mux.private_value = (unsigned long)&priv->mux_enum;
+ priv->mux_widgets[2].kcontrol_news = &priv->mux_mux;
+ priv->mux_routes[1].control = priv->mux_texts[0]; // "Input 1"
+ priv->mux_routes[2].control = priv->mux_texts[1]; // "Input 2"
+
+ return devm_snd_soc_register_component(dev, &priv->mux_driver, NULL, 0);
}
#ifdef CONFIG_OF
diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c
index 7b9abbc1bd94..06de2b4fce5e 100644
--- a/sound/soc/codecs/sma1303.c
+++ b/sound/soc/codecs/sma1303.c
@@ -7,6 +7,7 @@
// Auther: Gyuhwa Park <gyuhwa.park@irondevice.com>
// Kiseok Jo <kiseok.jo@irondevice.com>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -21,7 +22,6 @@
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
#include <asm/div64.h>
@@ -309,8 +309,7 @@ static const struct soc_enum sma1303_tdm_slot_enum =
static int sma1303_force_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = (int)sma1303->force_mute_status;
@@ -323,8 +322,7 @@ static int sma1303_force_mute_get(struct snd_kcontrol *kcontrol,
static int sma1303_force_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
bool change = false, val = (bool)ucontrol->value.integer.value[0];
@@ -343,8 +341,7 @@ static int sma1303_force_mute_put(struct snd_kcontrol *kcontrol,
static int sma1303_postscaler_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
int val, ret;
@@ -360,8 +357,7 @@ static int sma1303_postscaler_get(struct snd_kcontrol *kcontrol,
static int sma1303_postscaler_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
int ret, val = (int)ucontrol->value.integer.value[0];
bool change;
@@ -377,8 +373,7 @@ static int sma1303_postscaler_put(struct snd_kcontrol *kcontrol,
static int sma1303_tdm_slot_rx_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
int val, ret;
@@ -395,8 +390,7 @@ static int sma1303_tdm_slot_rx_get(struct snd_kcontrol *kcontrol,
static int sma1303_tdm_slot_rx_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
int ret, val = (int)ucontrol->value.integer.value[0];
bool change;
@@ -412,8 +406,7 @@ static int sma1303_tdm_slot_rx_put(struct snd_kcontrol *kcontrol,
static int sma1303_tdm_slot_tx_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
int val, ret;
@@ -430,8 +423,7 @@ static int sma1303_tdm_slot_tx_get(struct snd_kcontrol *kcontrol,
static int sma1303_tdm_slot_tx_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
int ret, val = (int)ucontrol->value.integer.value[0];
bool change;
@@ -526,7 +518,7 @@ static int sma1303_aif_in_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
int ret = 0;
bool change = false, temp = false;
@@ -596,7 +588,7 @@ static int sma1303_aif_out_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct sma1303_priv *sma1303 = snd_soc_component_get_drvdata(component);
- unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);
+ unsigned int mux = snd_soc_dapm_kcontrol_get_value(w->kcontrols[0]);
int ret = 0;
bool change = false, temp = false;
@@ -1565,8 +1557,7 @@ static void sma1303_check_fault_worker(struct work_struct *work)
static int sma1303_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_sync(dapm);
@@ -1791,7 +1782,7 @@ static void sma1303_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id sma1303_i2c_id[] = {
- {"sma1303", 0},
+ {"sma1303"},
{}
};
MODULE_DEVICE_TABLE(i2c, sma1303_i2c_id);
diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
new file mode 100644
index 000000000000..4bb59e5c0891
--- /dev/null
+++ b/sound/soc/codecs/sma1307.c
@@ -0,0 +1,2044 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// sma1307.c -- sma1307 ALSA SoC Audio driver
+//
+// Copyright 2024 Iron Device Corporation
+//
+// Auther: Gyuhwa Park <gyuwha.park@irondevice.com>
+// Auther: Kiseok Jo <kiseok.jo@irondevice.com>
+
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "sma1307.h"
+
+#define CHECK_PERIOD_TIME 1 /* sec per HZ */
+#define PLL_MATCH(_input_clk_name, _output_clk_name, _input_clk,\
+ _post_n, _n, _vco, _p_cp)\
+{\
+ .input_clk_name = _input_clk_name,\
+ .output_clk_name = _output_clk_name,\
+ .input_clk = _input_clk,\
+ .post_n = _post_n,\
+ .n = _n,\
+ .vco = _vco,\
+ .p_cp = _p_cp,\
+}
+
+static const char *setting_file = "sma1307_setting.bin";
+#define SMA1307_SETTING_CHECKSUM 0x100000
+
+/* PLL clock setting Table */
+struct sma1307_pll_match {
+ char *input_clk_name;
+ char *output_clk_name;
+ unsigned int input_clk;
+ unsigned int post_n;
+ unsigned int n;
+ unsigned int vco;
+ unsigned int p_cp;
+};
+
+struct sma1307_data {
+ char *name;
+ void (*init)(struct regmap *regmap);
+};
+
+struct sma1307_priv {
+ bool check_fault_status;
+ bool force_mute_status;
+ bool sw_ot1_prot;
+ char *name;
+ enum sma1307_mode amp_mode;
+ int binary_mode;
+ int dapm_aif_in;
+ int dapm_aif_out0;
+ int dapm_aif_out1;
+ int dapm_sdo_en;
+ int dapm_sdo_setting;
+ int num_of_pll_matches;
+ int check_fault_period;
+ struct delayed_work check_fault_work;
+ struct device *dev;
+ struct kobject *kobj;
+ struct mutex default_lock;
+ struct regmap *regmap;
+ struct sma1307_setting_file set;
+ const struct sma1307_pll_match *pll_matches;
+ const struct sma1307_data *data;
+ unsigned int cur_vol;
+ unsigned int format;
+ unsigned int frame_size;
+ unsigned int init_vol;
+ unsigned int last_bclk;
+ unsigned int otp_trm2;
+ unsigned int otp_trm3;
+ unsigned int rev_num;
+ unsigned int sys_clk_id;
+ unsigned int tdm_slot0_rx;
+ unsigned int tdm_slot1_rx;
+ unsigned int tdm_slot0_tx;
+ unsigned int tdm_slot1_tx;
+ unsigned int tsdw_cnt;
+};
+
+static const struct sma1307_pll_match sma1307_pll_matches[] = {
+ /* in_clk_name, out_clk_name, input_clk post_n, n, vco, p_cp */
+ PLL_MATCH("1.411MHz", "24.554MHz",
+ 1411200, 0x06, 0xD1, 0x88, 0x00),
+ PLL_MATCH("1.536MHz", "24.576MHz",
+ 1536000, 0x06, 0xC0, 0x88, 0x00),
+ PLL_MATCH("2.822MHz", "24.554MHz",
+ 2822400, 0x06, 0xD1, 0x88, 0x04),
+ PLL_MATCH("3.072MHz", "24.576MHz",
+ 3072000, 0x06, 0x60, 0x88, 0x00),
+ PLL_MATCH("6.144MHz", "24.576MHz",
+ 6144000, 0x06, 0x60, 0x88, 0x04),
+ PLL_MATCH("12.288MHz", "24.576MHz",
+ 12288000, 0x06, 0x60, 0x88, 0x08),
+ PLL_MATCH("19.2MHz", "24.48MHz",
+ 19200000, 0x06, 0x7B, 0x88, 0x0C),
+ PLL_MATCH("24.576MHz", "24.576MHz",
+ 24576000, 0x06, 0x60, 0x88, 0x0C),
+};
+
+static struct snd_soc_component *sma1307_amp_component;
+
+static void sma1307_startup(struct snd_soc_component *);
+static void sma1307_shutdown(struct snd_soc_component *);
+static void sma1307_reset(struct snd_soc_component *);
+static void sma1307_set_binary(struct snd_soc_component *);
+static void sma1307_set_default(struct snd_soc_component *);
+
+/* Initial register value - 6.0W SPK (8ohm load) */
+static const struct reg_default sma1307_reg_def[] = {
+ { 0x00, 0x80 },
+ { 0x01, 0x00 },
+ { 0x02, 0x52 },
+ { 0x03, 0x4C },
+ { 0x04, 0x47 },
+ { 0x05, 0x42 },
+ { 0x06, 0x40 },
+ { 0x07, 0x40 },
+ { 0x08, 0x3C },
+ { 0x09, 0x2F },
+ { 0x0A, 0x32 },
+ { 0x0B, 0x50 },
+ { 0x0C, 0x8C },
+ { 0x0D, 0x00 },
+ { 0x0E, 0x3F },
+ { 0x0F, 0x00 },
+ { 0x10, 0x00 },
+ { 0x11, 0x00 },
+ { 0x12, 0x00 },
+ { 0x13, 0x09 },
+ { 0x14, 0x12 },
+ { 0x1C, 0x00 },
+ { 0x1D, 0x85 },
+ { 0x1E, 0xA1 },
+ { 0x1F, 0x67 },
+ { 0x22, 0x00 },
+ { 0x23, 0x1F },
+ { 0x24, 0x7A },
+ { 0x25, 0x00 },
+ { 0x26, 0xFF },
+ { 0x27, 0x39 },
+ { 0x28, 0x54 },
+ { 0x29, 0x92 },
+ { 0x2A, 0xB0 },
+ { 0x2B, 0xED },
+ { 0x2C, 0xED },
+ { 0x2D, 0xFF },
+ { 0x2E, 0xFF },
+ { 0x2F, 0xFF },
+ { 0x30, 0xFF },
+ { 0x31, 0xFF },
+ { 0x32, 0xFF },
+ { 0x34, 0x01 },
+ { 0x35, 0x17 },
+ { 0x36, 0x92 },
+ { 0x37, 0x00 },
+ { 0x38, 0x01 },
+ { 0x39, 0x10 },
+ { 0x3E, 0x01 },
+ { 0x3F, 0x08 },
+ { 0x8B, 0x05 },
+ { 0x8C, 0x50 },
+ { 0x8D, 0x80 },
+ { 0x8E, 0x10 },
+ { 0x8F, 0x02 },
+ { 0x90, 0x02 },
+ { 0x91, 0x83 },
+ { 0x92, 0xC0 },
+ { 0x93, 0x00 },
+ { 0x94, 0xA4 },
+ { 0x95, 0x74 },
+ { 0x96, 0x57 },
+ { 0xA2, 0xCC },
+ { 0xA3, 0x28 },
+ { 0xA4, 0x40 },
+ { 0xA5, 0x01 },
+ { 0xA6, 0x41 },
+ { 0xA7, 0x08 },
+ { 0xA8, 0x04 },
+ { 0xA9, 0x27 },
+ { 0xAA, 0x10 },
+ { 0xAB, 0x10 },
+ { 0xAC, 0x10 },
+ { 0xAD, 0x0F },
+ { 0xAE, 0xCD },
+ { 0xAF, 0x70 },
+ { 0xB0, 0x03 },
+ { 0xB1, 0xEF },
+ { 0xB2, 0x03 },
+ { 0xB3, 0xEF },
+ { 0xB4, 0xF3 },
+ { 0xB5, 0x3D },
+};
+
+static bool sma1307_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > SMA1307_FF_DEVICE_INDEX)
+ return false;
+
+ switch (reg) {
+ case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME:
+ case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19:
+ case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL:
+ case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2:
+ case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3:
+ case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2:
+ case SMA1307_F5_READY_FOR_V_SAR:
+ case SMA1307_F7_READY_FOR_T_SAR ... SMA1307_FF_DEVICE_INDEX:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static bool sma1307_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > SMA1307_FF_DEVICE_INDEX)
+ return false;
+
+ switch (reg) {
+ case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME:
+ case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19:
+ case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL:
+ case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2:
+ case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3:
+ case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static bool sma1307_volatile_register(struct device *dev, unsigned int reg)
+{
+ if (reg > SMA1307_FF_DEVICE_INDEX)
+ return false;
+
+ switch (reg) {
+ case SMA1307_F8_STATUS_T1 ... SMA1307_FF_DEVICE_INDEX:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/* DB scale conversion of speaker volume */
+static const DECLARE_TLV_DB_SCALE(sma1307_spk_tlv, -6000, 50, 0);
+
+static const char *const sma1307_aif_in_source_text[] = {
+ "Mono", "Left", "Right"
+};
+
+static const char *const sma1307_sdo_setting_text[] = {
+ "Data_One_48k", "Data_Two_48k", "Data_Two_24k",
+ "Clk_PLL", "Clk_OSC"
+};
+
+static const char *const sma1307_aif_out_source_text[] = {
+ "Disable", "After_FmtC", "After_Mixer", "After_DSP",
+ "Vrms2_Avg", "Battery", "Temperature", "After_Delay"
+};
+
+static const char *const sma1307_tdm_slot_text[] = {
+ "Slot0", "Slot1", "Slot2", "Slot3",
+ "Slot4", "Slot5", "Slot6", "Slot7"
+};
+
+static const char *const sma1307_binary_mode_text[] = {
+ "Mode0", "Mode1", "Mode2", "Mode3", "Mode4"
+};
+
+static const char *const sma1307_reset_text[] = {
+ "Reset"
+};
+
+static const struct soc_enum sma1307_aif_in_source_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_in_source_text),
+ sma1307_aif_in_source_text);
+static const struct soc_enum sma1307_sdo_setting_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_sdo_setting_text),
+ sma1307_sdo_setting_text);
+static const struct soc_enum sma1307_aif_out_source_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_out_source_text),
+ sma1307_aif_out_source_text);
+static const struct soc_enum sma1307_tdm_slot_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_tdm_slot_text),
+ sma1307_tdm_slot_text);
+static const struct soc_enum sma1307_binary_mode_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_binary_mode_text),
+ sma1307_binary_mode_text);
+static const struct soc_enum sma1307_reset_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_reset_text),
+ sma1307_reset_text);
+
+static int sma1307_force_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)sma1307->force_mute_status;
+
+ return 0;
+}
+
+static int sma1307_force_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ bool change = false, val = (bool)ucontrol->value.integer.value[0];
+
+ if (sma1307->force_mute_status == val) {
+ change = false;
+ } else {
+ change = true;
+ sma1307->force_mute_status = val;
+ }
+
+ return change;
+}
+
+static int sma1307_tdm_slot_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val1, val2;
+
+ regmap_read(sma1307->regmap, SMA1307_A5_TDM1, &val1);
+ regmap_read(sma1307->regmap, SMA1307_A6_TDM2, &val2);
+
+ if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = (val1 & SMA1307_TDM_SLOT0_RX_POS_MASK) >> 3;
+ sma1307->tdm_slot0_rx = ucontrol->value.integer.value[0];
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = val1 & SMA1307_TDM_SLOT1_RX_POS_MASK;
+ sma1307->tdm_slot1_rx = ucontrol->value.integer.value[0];
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = (val2 & SMA1307_TDM_SLOT0_TX_POS_MASK) >> 3;
+ sma1307->tdm_slot0_tx = ucontrol->value.integer.value[0];
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) {
+ ucontrol->value.integer.value[0]
+ = val2 & SMA1307_TDM_SLOT1_TX_POS_MASK;
+ sma1307->tdm_slot1_tx = ucontrol->value.integer.value[0];
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sma1307_tdm_slot_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val = (int)ucontrol->value.integer.value[0];
+ bool change;
+
+ if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) {
+ if (sma1307->tdm_slot0_rx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot0_rx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT0_RX_POS_MASK, val << 3);
+ }
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) {
+ if (sma1307->tdm_slot1_rx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot1_rx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT1_RX_POS_MASK, val);
+ }
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) {
+ if (sma1307->tdm_slot0_tx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot0_tx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT0_TX_POS_MASK, val << 3);
+ }
+ } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) {
+ if (sma1307->tdm_slot1_tx == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->tdm_slot1_tx = val;
+ regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT1_TX_POS_MASK, val);
+ }
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ return change;
+}
+
+static int sma1307_sw_ot1_prot_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)sma1307->sw_ot1_prot;
+
+ return 0;
+}
+
+static int sma1307_sw_ot1_prot_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ bool change = false, val = (bool)ucontrol->value.integer.value[0];
+
+ if (sma1307->sw_ot1_prot == val)
+ change = false;
+ else {
+ change = true;
+ sma1307->sw_ot1_prot = val;
+ }
+
+ return change;
+}
+
+static int sma1307_check_fault_status_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)sma1307->check_fault_status;
+
+ return 0;
+}
+
+static int sma1307_check_fault_status_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ bool change = false, val = (bool)ucontrol->value.integer.value[0];
+
+ if (sma1307->check_fault_status == val) {
+ change = false;
+ } else {
+ change = true;
+ sma1307->check_fault_status = val;
+ }
+
+ return change;
+}
+
+static int sma1307_check_fault_period_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = sma1307->check_fault_period;
+
+ return 0;
+}
+
+static int sma1307_check_fault_period_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ bool change = false;
+ int val = ucontrol->value.integer.value[0];
+
+ if (val < mc->min || val > mc->max)
+ return -EINVAL;
+ if (sma1307->check_fault_period == val) {
+ change = false;
+ } else {
+ change = true;
+ sma1307->check_fault_period = val;
+ }
+
+ return change;
+}
+
+static int sma1307_reset_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL,
+ SMA1307_RESET_MASK, SMA1307_RESET_ON);
+ sma1307_reset(component);
+
+ snd_ctl_notify(component->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &kcontrol->id);
+
+ return true;
+}
+
+static int sma1307_binary_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sma1307_priv *sma1307 = snd_kcontrol_chip(kcontrol);
+
+ sma1307->binary_mode = (int)ucontrol->value.enumerated.item[0];
+ if (sma1307->set.status)
+ sma1307_set_binary(component);
+
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
+}
+
+static void sma1307_startup(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1,
+ SMA1307_PLL_MASK, SMA1307_PLL_ON);
+ regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL,
+ SMA1307_POWER_MASK, SMA1307_POWER_ON);
+
+ if (sma1307->amp_mode == SMA1307_MONO_MODE) {
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_10_SYSTEM_CTRL1,
+ SMA1307_SPK_MODE_MASK,
+ SMA1307_SPK_MONO);
+ } else {
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_10_SYSTEM_CTRL1,
+ SMA1307_SPK_MODE_MASK,
+ SMA1307_SPK_STEREO);
+ }
+
+ if (sma1307->check_fault_status) {
+ if (sma1307->check_fault_period > 0)
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ sma1307->check_fault_period * HZ);
+ else
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ CHECK_PERIOD_TIME * HZ);
+ }
+}
+
+static void sma1307_shutdown(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ /* for SMA1307A */
+ cancel_delayed_work_sync(&sma1307->check_fault_work);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_0E_MUTE_VOL_CTRL,
+ SMA1307_SPK_MUTE_MASK, SMA1307_SPK_MUTE);
+ /* Need to wait time for mute slope */
+ msleep(55);
+
+ regmap_update_bits(sma1307->regmap, SMA1307_10_SYSTEM_CTRL1,
+ SMA1307_SPK_MODE_MASK, SMA1307_SPK_OFF);
+ regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1,
+ SMA1307_PLL_MASK, SMA1307_PLL_OFF);
+ regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL,
+ SMA1307_POWER_MASK, SMA1307_POWER_OFF);
+}
+
+static int sma1307_aif_in_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int mux = sma1307->dapm_aif_in;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (mux) {
+ case SMA1307_MONO_MODE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_MONOMIX_MASK,
+ SMA1307_MONOMIX_ON);
+ break;
+ case SMA1307_LEFT_MODE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_MONOMIX_MASK,
+ SMA1307_MONOMIX_OFF);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_LR_DATA_SW_MASK,
+ SMA1307_LR_DATA_SW_NORMAL);
+ break;
+ case SMA1307_RIGHT_MODE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_MONOMIX_MASK,
+ SMA1307_MONOMIX_OFF);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_11_SYSTEM_CTRL2,
+ SMA1307_LR_DATA_SW_MASK,
+ SMA1307_LR_DATA_SW_SWAP);
+ break;
+ default:
+
+ dev_err(sma1307->dev, "%s: Invalid value (%d)\n",
+ __func__, mux);
+ return -EINVAL;
+ }
+ sma1307->amp_mode = mux;
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_sdo_setting_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int mux = sma1307->dapm_sdo_setting;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (mux) {
+ case SMA1307_OUT_DATA_ONE_48K:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_SDO_OUTPUT2_MASK,
+ SMA1307_ONE_SDO_PER_CH);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT3_MASK
+ |
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_OUTPUT3_DIS
+ | SMA1307_SDO_DATA);
+ break;
+ case SMA1307_OUT_DATA_TWO_48K:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_SDO_OUTPUT2_MASK,
+ SMA1307_TWO_SDO_PER_CH);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT3_MASK
+ |
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_OUTPUT3_DIS
+ | SMA1307_SDO_DATA);
+ break;
+ case SMA1307_OUT_DATA_TWO_24K:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_SDO_OUTPUT2_MASK,
+ SMA1307_TWO_SDO_PER_CH);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT3_MASK
+ |
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_TWO_SDO_PER_CH_24K
+ | SMA1307_SDO_DATA);
+ break;
+ case SMA1307_OUT_CLK_PLL:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_CLK_PLL);
+
+ break;
+ case SMA1307_OUT_CLK_OSC:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_DATA_CLK_SEL_MASK,
+ SMA1307_SDO_CLK_OSC);
+
+ break;
+ default:
+ dev_err(sma1307->dev, "%s: Invalid value (%d)\n",
+ __func__, mux);
+ return -EINVAL;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_aif_out_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int mux = 0, val = 0, mask = 0;
+
+ if (!strcmp(w->name, SMA1307_AIF_OUT0_NAME)) {
+ mux = sma1307->dapm_aif_out0;
+ val = mux;
+ mask = SMA1307_SDO_OUT0_SEL_MASK;
+ } else if (!strcmp(w->name, SMA1307_AIF_OUT1_NAME)) {
+ mux = sma1307->dapm_aif_out1;
+ val = mux << 3;
+ mask = SMA1307_SDO_OUT1_SEL_MASK;
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid widget - %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(sma1307->regmap, SMA1307_09_OUTPUT_CTRL,
+ mask, val);
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_sdo_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 sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_09_OUTPUT_CTRL,
+ SMA1307_PORT_CONFIG_MASK,
+ SMA1307_OUTPUT_PORT_ENABLE);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT_MASK,
+ SMA1307_LOGIC_OUTPUT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_09_OUTPUT_CTRL,
+ SMA1307_PORT_CONFIG_MASK,
+ SMA1307_INPUT_PORT_ONLY);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A3_TOP_MAN2,
+ SMA1307_SDO_OUTPUT_MASK,
+ SMA1307_HIGH_Z_OUTPUT);
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ sma1307_startup(component);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ sma1307_shutdown(component);
+ break;
+ }
+ return 0;
+}
+
+static int sma1307_dapm_aif_in_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.enumerated.item[0] = (unsigned int)sma1307->dapm_aif_in;
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_aif_in_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val = (int)ucontrol->value.enumerated.item[0];
+ bool change;
+
+ if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_in_source_text))) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sma1307->dapm_aif_in != val) {
+ change = true;
+ sma1307->dapm_aif_in = val;
+ } else
+ change = false;
+
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return change;
+}
+
+static int sma1307_dapm_sdo_setting_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.enumerated.item[0] =
+ (unsigned int)sma1307->dapm_sdo_setting;
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_sdo_setting_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val = (int)ucontrol->value.enumerated.item[0];
+ bool change;
+
+ if ((val < 0) || (val >= ARRAY_SIZE(sma1307_sdo_setting_text))) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sma1307->dapm_sdo_setting != val) {
+ change = true;
+ sma1307->dapm_sdo_setting = val;
+ } else
+ change = false;
+
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return change;
+}
+
+static int sma1307_dapm_aif_out_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int val = 0;
+
+ if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) {
+ val = (unsigned int)sma1307->dapm_aif_out0;
+ } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) {
+ val = (unsigned int)sma1307->dapm_aif_out1;
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+ ucontrol->value.enumerated.item[0] = val;
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_aif_out_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val = (int)ucontrol->value.enumerated.item[0];
+ bool change;
+
+ if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_out_source_text))) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) {
+ if (sma1307->dapm_aif_out0 != val) {
+ change = true;
+ sma1307->dapm_aif_out0 = val;
+ } else
+ change = false;
+ } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) {
+ if (sma1307->dapm_aif_out1 != val) {
+ change = true;
+ sma1307->dapm_aif_out1 = val;
+ } else
+ change = false;
+ } else {
+ dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n",
+ __func__, kcontrol->id.name);
+ return -EINVAL;
+ }
+
+ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return change;
+}
+
+static int sma1307_dapm_sdo_enable_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (long)sma1307->dapm_sdo_en;
+ snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+ return 0;
+}
+
+static int sma1307_dapm_sdo_enable_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int val = (int)ucontrol->value.integer.value[0];
+ bool change;
+
+ if ((val < 0) || (val > 1)) {
+ dev_err(sma1307->dev, "%s: Out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sma1307->dapm_sdo_en != val) {
+ change = true;
+ sma1307->dapm_sdo_en = val;
+ } else
+ change = false;
+
+ snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+ return change;
+}
+
+static const struct snd_kcontrol_new sma1307_aif_in_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SMA1307_AIF_IN_NAME,
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_aif_in_get,
+ .put = sma1307_dapm_aif_in_put,
+ .private_value = (unsigned long)&sma1307_aif_in_source_enum
+};
+
+static const struct snd_kcontrol_new sma1307_sdo_setting_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "SDO Setting",
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_sdo_setting_get,
+ .put = sma1307_dapm_sdo_setting_put,
+ .private_value = (unsigned long)&sma1307_sdo_setting_enum
+};
+
+static const struct snd_kcontrol_new sma1307_aif_out0_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SMA1307_AIF_OUT0_NAME,
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_aif_out_get,
+ .put = sma1307_dapm_aif_out_put,
+ .private_value = (unsigned long)&sma1307_aif_out_source_enum
+};
+
+static const struct snd_kcontrol_new sma1307_aif_out1_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SMA1307_AIF_OUT1_NAME,
+ .info = snd_soc_info_enum_double,
+ .get = sma1307_dapm_aif_out_get,
+ .put = sma1307_dapm_aif_out_put,
+ .private_value = (unsigned long)&sma1307_aif_out_source_enum
+};
+
+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);
+
+static const struct snd_kcontrol_new sma1307_binary_mode_control[] = {
+ SOC_ENUM_EXT("Binary Mode", sma1307_binary_mode_enum,
+ snd_soc_get_enum_double, sma1307_binary_mode_put),
+};
+
+static const struct snd_kcontrol_new sma1307_snd_controls[] = {
+ SOC_SINGLE_TLV(SMA1307_VOL_CTRL_NAME, SMA1307_0A_SPK_VOL,
+ 0, 167, 1, sma1307_spk_tlv),
+ SOC_ENUM_EXT(SMA1307_TDM_RX0_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_TDM_RX1_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_TDM_TX0_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_TDM_TX1_POS_NAME, sma1307_tdm_slot_enum,
+ sma1307_tdm_slot_get, sma1307_tdm_slot_put),
+ SOC_ENUM_EXT(SMA1307_RESET_CTRL_NAME, sma1307_reset_enum,
+ snd_soc_get_enum_double, sma1307_reset_put),
+ SOC_SINGLE_BOOL_EXT(SMA1307_FORCE_MUTE_CTRL_NAME, 0,
+ sma1307_force_mute_get, sma1307_force_mute_put),
+ SOC_SINGLE_BOOL_EXT(SMA1307_OT1_SW_PROT_CTRL_NAME, 0,
+ sma1307_sw_ot1_prot_get, sma1307_sw_ot1_prot_put),
+ SOC_SINGLE_BOOL_EXT(SMA1307_CHECK_FAULT_STATUS_NAME, 0,
+ sma1307_check_fault_status_get,
+ sma1307_check_fault_status_put),
+ SOC_SINGLE_EXT(SMA1307_CHECK_FAULT_PERIOD_NAME, SND_SOC_NOPM, 0, 600, 0,
+ sma1307_check_fault_period_get,
+ sma1307_check_fault_period_put),
+};
+
+static const struct snd_soc_dapm_widget sma1307_dapm_widgets[] = {
+ /* platform domain */
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_INPUT("SDO"),
+
+ /* path domain */
+ SND_SOC_DAPM_MUX_E(SMA1307_AIF_IN_NAME, SND_SOC_NOPM, 0, 0,
+ &sma1307_aif_in_source_control,
+ sma1307_aif_in_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("SDO Setting", SND_SOC_NOPM, 0, 0,
+ &sma1307_sdo_setting_control,
+ sma1307_sdo_setting_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT0_NAME, SND_SOC_NOPM, 0, 0,
+ &sma1307_aif_out0_source_control,
+ sma1307_aif_out_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT1_NAME, SND_SOC_NOPM, 0, 0,
+ &sma1307_aif_out1_source_control,
+ sma1307_aif_out_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SWITCH_E("SDO Enable", SND_SOC_NOPM, 0, 0,
+ &sma1307_sdo_control,
+ sma1307_sdo_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("Entry", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("AMP Power", SND_SOC_NOPM, 0, 0, NULL, 0,
+ sma1307_power_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 0,
+ &sma1307_enable_control),
+
+ /* stream domain */
+ SND_SOC_DAPM_AIF_IN("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route sma1307_audio_map[] = {
+ /* Playback */
+ { "AIF IN Source", "Mono", "AIF IN" },
+ { "AIF IN Source", "Left", "AIF IN" },
+ { "AIF IN Source", "Right", "AIF IN" },
+
+ { "SDO Enable", "Switch", "AIF IN" },
+
+ { "SDO Setting", "Data_One_48k", "SDO Enable" },
+ { "SDO Setting", "Data_Two_48k", "SDO Enable" },
+ { "SDO Setting", "Data_Two_24k", "SDO Enable" },
+ { "SDO Setting", "Clk_PLL", "SDO Enable" },
+ { "SDO Setting", "Clk_OSC", "SDO Enable" },
+
+ { "AIF OUT0 Source", "Disable", "SDO Setting" },
+ { "AIF OUT0 Source", "After_FmtC", "SDO Setting" },
+ { "AIF OUT0 Source", "After_Mixer", "SDO Setting" },
+ { "AIF OUT0 Source", "After_DSP", "SDO Setting" },
+ { "AIF OUT0 Source", "Vrms2_Avg", "SDO Setting" },
+ { "AIF OUT0 Source", "Battery", "SDO Setting" },
+ { "AIF OUT0 Source", "Temperature", "SDO Setting" },
+ { "AIF OUT0 Source", "After_Delay", "SDO Setting" },
+
+ { "AIF OUT1 Source", "Disable", "SDO Setting" },
+ { "AIF OUT1 Source", "After_FmtC", "SDO Setting" },
+ { "AIF OUT1 Source", "After_Mixer", "SDO Setting" },
+ { "AIF OUT1 Source", "After_DSP", "SDO Setting" },
+ { "AIF OUT1 Source", "Vrms2_Avg", "SDO Setting" },
+ { "AIF OUT1 Source", "Battery", "SDO Setting" },
+ { "AIF OUT1 Source", "Temperature", "SDO Setting" },
+ { "AIF OUT1 Source", "After_Delay", "SDO Setting" },
+
+ { "Entry", NULL, "AIF OUT0 Source" },
+ { "Entry", NULL, "AIF OUT1 Source" },
+ { "Entry", NULL, "AIF IN Source" },
+
+ { "AMP Power", NULL, "Entry" },
+
+ { "AMP Enable", "Switch", "AMP Power" },
+ { "SPK", NULL, "AMP Enable" },
+
+ /* Capture */
+ { "AIF OUT", NULL, "AMP Enable" },
+};
+
+static void sma1307_setup_pll(struct snd_soc_component *component,
+ unsigned int bclk)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ int i = 0;
+
+ dev_dbg(component->dev, "%s: BCLK = %dHz\n", __func__, bclk);
+
+ if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_MCLK) {
+ dev_warn(component->dev, "%s: MCLK is not supported\n",
+ __func__);
+ } else if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) {
+ for (i = 0; i < sma1307->num_of_pll_matches; i++) {
+ if (sma1307->pll_matches[i].input_clk == bclk)
+ break;
+ }
+ if (i == sma1307->num_of_pll_matches) {
+ dev_warn(component->dev,
+ "%s: No matching value between pll table and SCK\n",
+ __func__);
+ return;
+ }
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A2_TOP_MAN1,
+ SMA1307_PLL_MASK, SMA1307_PLL_ON);
+ }
+
+ regmap_write(sma1307->regmap, SMA1307_8B_PLL_POST_N,
+ sma1307->pll_matches[i].post_n);
+ regmap_write(sma1307->regmap, SMA1307_8C_PLL_N,
+ sma1307->pll_matches[i].n);
+ regmap_write(sma1307->regmap, SMA1307_8D_PLL_A_SETTING,
+ sma1307->pll_matches[i].vco);
+ regmap_write(sma1307->regmap, SMA1307_8E_PLL_P_CP,
+ sma1307->pll_matches[i].p_cp);
+}
+
+static int sma1307_dai_hw_params_amp(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int bclk = 0;
+
+ if (sma1307->format == SND_SOC_DAIFMT_DSP_A)
+ bclk = params_rate(params) * sma1307->frame_size;
+ else
+ bclk = params_rate(params) * params_physical_width(params)
+ * params_channels(params);
+
+ dev_dbg(component->dev,
+ "%s: rate = %d : bit size = %d : channel = %d\n",
+ __func__, params_rate(params), params_width(params),
+ params_channels(params));
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) {
+ if (sma1307->last_bclk != bclk) {
+ sma1307_setup_pll(component, bclk);
+ sma1307->last_bclk = bclk;
+ }
+ }
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ break;
+
+ case 96000:
+ dev_warn(component->dev,
+ "%s: %d rate not support SDO\n", __func__,
+ params_rate(params));
+ break;
+
+ default:
+ dev_err(component->dev, "%s: not support rate : %d\n",
+ __func__, params_rate(params));
+
+ return -EINVAL;
+ }
+
+ /* substream->stream is SNDRV_PCM_STREAM_CAPTURE */
+ } else {
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_SCK_RATE_MASK
+ |
+ SMA1307_DATA_WIDTH_MASK,
+ SMA1307_SCK_32FS |
+ SMA1307_DATA_16BIT);
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_SCK_RATE_MASK
+ |
+ SMA1307_DATA_WIDTH_MASK,
+ SMA1307_SCK_64FS |
+ SMA1307_DATA_24BIT);
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_SCK_RATE_MASK
+ |
+ SMA1307_DATA_WIDTH_MASK,
+ SMA1307_SCK_64FS |
+ SMA1307_DATA_24BIT);
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: not support data bit : %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
+ }
+ }
+
+ switch (sma1307->format) {
+ case SND_SOC_DAIFMT_I2S:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_STANDARD_I2S);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK,
+ SMA1307_I2S_FORMAT);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK, SMA1307_LJ);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK,
+ SMA1307_LJ_FORMAT);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 16:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_RJ_16BIT);
+ break;
+ case 24:
+ case 32:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_RJ_24BIT);
+ break;
+ }
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_I2S_MODE_MASK,
+ SMA1307_STANDARD_I2S);
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK,
+ SMA1307_TDM_FORMAT);
+ break;
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: not support data bit : %d\n", __func__,
+ params_format(params));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sma1307_dai_set_sysclk_amp(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ switch (clk_id) {
+ case SMA1307_EXTERNAL_CLOCK_19_2:
+ case SMA1307_EXTERNAL_CLOCK_24_576:
+ case SMA1307_PLL_CLKIN_MCLK:
+ case SMA1307_PLL_CLKIN_BCLK:
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid clk id: %d\n",
+ __func__, clk_id);
+ return -EINVAL;
+ }
+ sma1307->sys_clk_id = clk_id;
+
+ return 0;
+}
+
+static int sma1307_dai_set_fmt_amp(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+
+ case SND_SOC_DAIFMT_CBC_CFC:
+ dev_dbg(component->dev,
+ "%s: %s\n", __func__, "I2S/TDM Device mode");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_CONTROLLER_DEVICE_MASK,
+ SMA1307_DEVICE_MODE);
+ break;
+
+ case SND_SOC_DAIFMT_CBP_CFP:
+ dev_dbg(component->dev,
+ "%s: %s\n", __func__, "I2S/TDM Controller mode");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_CONTROLLER_DEVICE_MASK,
+ SMA1307_CONTROLLER_MODE);
+ break;
+
+ default:
+ dev_err(component->dev,
+ "%s: Unsupported Controller/Device : 0x%x\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ sma1307->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: Unsupported Audio Interface Format : 0x%x\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+
+ case SND_SOC_DAIFMT_IB_NF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Invert BCLK + Normal Frame");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_SCK_RISING_MASK,
+ SMA1307_SCK_RISING_EDGE);
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Invert BCLK + Invert Frame");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_LEFTPOL_MASK
+ | SMA1307_SCK_RISING_MASK,
+ SMA1307_HIGH_FIRST_CH
+ | SMA1307_SCK_RISING_EDGE);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Normal BCLK + Invert Frame");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_01_INPUT_CTRL1,
+ SMA1307_LEFTPOL_MASK,
+ SMA1307_HIGH_FIRST_CH);
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ dev_dbg(component->dev, "%s: %s\n",
+ __func__, "Normal BCLK + Normal Frame");
+ break;
+ default:
+ dev_err(component->dev,
+ "%s: Unsupported Bit & Frameclock : 0x%x\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sma1307_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s: slots = %d, slot_width - %d\n",
+ __func__, slots, slot_width);
+
+ sma1307->frame_size = slot_width * slots;
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A4_TOP_MAN3,
+ SMA1307_INTERFACE_MASK, SMA1307_TDM_FORMAT);
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A5_TDM1,
+ SMA1307_TDM_TX_MODE_MASK,
+ SMA1307_TDM_TX_MONO);
+
+ switch (slot_width) {
+ case 16:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_DL_MASK,
+ SMA1307_TDM_DL_16);
+ break;
+ case 32:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_DL_MASK,
+ SMA1307_TDM_DL_32);
+ break;
+ default:
+ dev_err(component->dev, "%s: not support TDM %d slot_width\n",
+ __func__, slot_width);
+ return -EINVAL;
+ }
+
+ switch (slots) {
+ case 4:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_N_SLOT_MASK,
+ SMA1307_TDM_N_SLOT_4);
+ break;
+ case 8:
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_N_SLOT_MASK,
+ SMA1307_TDM_N_SLOT_8);
+ break;
+ default:
+ dev_err(component->dev, "%s: not support TDM %d slots\n",
+ __func__, slots);
+ return -EINVAL;
+ }
+
+ if (sma1307->tdm_slot0_rx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT0_RX_POS_MASK,
+ sma1307->tdm_slot0_rx << 3);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot0-rx %d set\n",
+ __func__, sma1307->tdm_slot0_rx);
+
+ if (sma1307->tdm_slot1_rx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A5_TDM1,
+ SMA1307_TDM_SLOT1_RX_POS_MASK,
+ sma1307->tdm_slot1_rx);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot1-rx %d set\n",
+ __func__, sma1307->tdm_slot1_rx);
+
+ if (sma1307->tdm_slot0_tx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT0_TX_POS_MASK,
+ sma1307->tdm_slot0_tx << 3);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot0-tx %d set\n",
+ __func__, sma1307->tdm_slot0_tx);
+
+ if (sma1307->tdm_slot1_tx < slots)
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_A6_TDM2,
+ SMA1307_TDM_SLOT1_TX_POS_MASK,
+ sma1307->tdm_slot1_tx);
+ else
+ dev_err(component->dev, "%s: Incorrect tdm-slot1-tx %d set\n",
+ __func__, sma1307->tdm_slot1_tx);
+
+ return 0;
+}
+
+static int sma1307_dai_mute_stream(struct snd_soc_dai *dai, int mute,
+ int stream)
+{
+ struct snd_soc_component *component = dai->component;
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+
+ if (stream == SNDRV_PCM_STREAM_CAPTURE)
+ return 0;
+ if (mute) {
+ dev_dbg(component->dev, "%s: %s\n", __func__, "MUTE");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_0E_MUTE_VOL_CTRL,
+ SMA1307_SPK_MUTE_MASK,
+ SMA1307_SPK_MUTE);
+ } else {
+ if (!sma1307->force_mute_status) {
+ dev_dbg(component->dev, "%s: %s\n", __func__,
+ "UNMUTE");
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_0E_MUTE_VOL_CTRL,
+ SMA1307_SPK_MUTE_MASK,
+ SMA1307_SPK_UNMUTE);
+ } else {
+ dev_dbg(sma1307->dev, "%s: FORCE MUTE!!!\n", __func__);
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops sma1307_dai_ops_amp = {
+ .hw_params = sma1307_dai_hw_params_amp,
+ .set_fmt = sma1307_dai_set_fmt_amp,
+ .set_sysclk = sma1307_dai_set_sysclk_amp,
+ .set_tdm_slot = sma1307_dai_set_tdm_slot,
+ .mute_stream = sma1307_dai_mute_stream,
+};
+
+#define SMA1307_RATES_PLAYBACK SNDRV_PCM_RATE_8000_96000
+#define SMA1307_RATES_CAPTURE SNDRV_PCM_RATE_8000_48000
+#define SMA1307_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver sma1307_dai[] = {
+ {
+ .name = "sma1307-amplifier",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SMA1307_RATES_PLAYBACK,
+ .formats = SMA1307_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SMA1307_RATES_CAPTURE,
+ .formats = SMA1307_FORMATS,
+ },
+ .ops = &sma1307_dai_ops_amp,
+ },
+};
+
+static void sma1307_check_fault_worker(struct work_struct *work)
+{
+ struct sma1307_priv *sma1307 =
+ container_of(work, struct sma1307_priv, check_fault_work.work);
+ unsigned int status1_val, status2_val;
+ char *envp[3] = { NULL, NULL, NULL };
+
+ if (sma1307->tsdw_cnt)
+ regmap_read(sma1307->regmap,
+ SMA1307_0A_SPK_VOL, &sma1307->cur_vol);
+ else
+ regmap_read(sma1307->regmap,
+ SMA1307_0A_SPK_VOL, &sma1307->init_vol);
+
+ regmap_read(sma1307->regmap, SMA1307_FA_STATUS1, &status1_val);
+ regmap_read(sma1307->regmap, SMA1307_FB_STATUS2, &status2_val);
+
+ if (~status1_val & SMA1307_OT1_OK_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OT1(Over Temperature Level 1)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1");
+ if (sma1307->sw_ot1_prot) {
+ /* Volume control (Current Volume -3dB) */
+ if ((sma1307->cur_vol + 6) <= 0xFA) {
+ sma1307->cur_vol += 6;
+ regmap_write(sma1307->regmap,
+ SMA1307_0A_SPK_VOL,
+ sma1307->cur_vol);
+ envp[1] = kasprintf(GFP_KERNEL,
+ "VOLUME=0x%02X", sma1307->cur_vol);
+ }
+ }
+ sma1307->tsdw_cnt++;
+ } else if (sma1307->tsdw_cnt) {
+ regmap_write(sma1307->regmap,
+ SMA1307_0A_SPK_VOL, sma1307->init_vol);
+ sma1307->tsdw_cnt = 0;
+ sma1307->cur_vol = sma1307->init_vol;
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1_CLEAR");
+ envp[1] = kasprintf(GFP_KERNEL,
+ "VOLUME=0x%02X", sma1307->cur_vol);
+ }
+
+ if (~status1_val & SMA1307_OT2_OK_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OT2(Over Temperature Level 2)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT2");
+ }
+ if (status1_val & SMA1307_UVLO_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: UVLO(Under Voltage Lock Out)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=UVLO");
+ }
+ if (status1_val & SMA1307_OVP_BST_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OVP_BST(Over Voltage Protection)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OVP_BST");
+ }
+ if (status2_val & SMA1307_OCP_SPK_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OCP_SPK(Over Current Protect SPK)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_SPK");
+ }
+ if (status2_val & SMA1307_OCP_BST_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: OCP_BST(Over Current Protect Boost)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_BST");
+ }
+ if (status2_val & SMA1307_CLK_MON_STATUS) {
+ dev_crit(sma1307->dev,
+ "%s: CLK_FAULT(No clock input)\n", __func__);
+ envp[0] = kasprintf(GFP_KERNEL, "STATUS=CLK_FAULT");
+ }
+
+ if (envp[0] != NULL) {
+ if (kobject_uevent_env(sma1307->kobj, KOBJ_CHANGE, envp))
+ dev_err(sma1307->dev,
+ "%s: Error sending uevent\n", __func__);
+ kfree(envp[0]);
+ kfree(envp[1]);
+ }
+
+ if (sma1307->check_fault_status) {
+ if (sma1307->check_fault_period > 0)
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ sma1307->check_fault_period * HZ);
+ else
+ queue_delayed_work(system_freezable_wq,
+ &sma1307->check_fault_work,
+ CHECK_PERIOD_TIME * HZ);
+ }
+}
+
+static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file)
+{
+ const struct firmware *fw;
+ int size, offset, num_mode;
+ int ret;
+
+ ret = request_firmware(&fw, file, sma1307->dev);
+
+ if (ret) {
+ dev_err(sma1307->dev, "%s: failed to read \"%s\": %pe\n",
+ __func__, setting_file, ERR_PTR(ret));
+ sma1307->set.status = false;
+ return;
+ } else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) {
+ dev_err(sma1307->dev, "%s: Invalid file\n", __func__);
+ release_firmware(fw);
+ sma1307->set.status = false;
+ return;
+ }
+
+ int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL);
+ if (!data) {
+ release_firmware(fw);
+ sma1307->set.status = false;
+ return;
+ }
+ size = fw->size >> 2;
+ memcpy(data, fw->data, fw->size);
+
+ release_firmware(fw);
+
+ /* HEADER */
+ sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE;
+ sma1307->set.checksum = data[sma1307->set.header_size - 2];
+ sma1307->set.num_mode = data[sma1307->set.header_size - 1];
+ num_mode = sma1307->set.num_mode;
+ sma1307->set.header = devm_kmalloc_array(sma1307->dev,
+ sma1307->set.header_size,
+ sizeof(int),
+ GFP_KERNEL);
+ if (!sma1307->set.header) {
+ sma1307->set.status = false;
+ return;
+ }
+
+ memcpy(sma1307->set.header, data,
+ sma1307->set.header_size * sizeof(int));
+
+ if ((sma1307->set.checksum >> 8) != SMA1307_SETTING_CHECKSUM) {
+ dev_err(sma1307->dev, "%s: checksum failed \"%s\"\n",
+ __func__, setting_file);
+ sma1307->set.status = false;
+ return;
+ }
+
+ /* DEFAULT */
+ sma1307->set.def_size = SMA1307_SETTING_DEFAULT_SIZE;
+ sma1307->set.def
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.def_size * sizeof(int), GFP_KERNEL);
+ if (!sma1307->set.def) {
+ sma1307->set.status = false;
+ return;
+ }
+
+ memcpy(sma1307->set.def,
+ &data[sma1307->set.header_size],
+ sma1307->set.def_size * sizeof(int));
+
+ /* MODE */
+ offset = sma1307->set.header_size + sma1307->set.def_size;
+ sma1307->set.mode_size = DIV_ROUND_CLOSEST(size - offset, num_mode + 1);
+ for (int i = 0; i < num_mode; i++) {
+ sma1307->set.mode_set[i]
+ = devm_kzalloc(sma1307->dev,
+ sma1307->set.mode_size * 2 * sizeof(int),
+ GFP_KERNEL);
+ if (!sma1307->set.mode_set[i]) {
+ 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)];
+ sma1307->set.mode_set[i][2 * j + 1]
+ = data[offset + ((num_mode + 1) * j + i + 1)];
+ }
+ }
+
+ sma1307->set.status = true;
+
+}
+
+static void sma1307_reset(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ unsigned int status = 0;
+
+ regmap_read(sma1307->regmap, SMA1307_FF_DEVICE_INDEX, &status);
+
+ sma1307->rev_num = status & SMA1307_REV_NUM_STATUS;
+ dev_dbg(component->dev, "%s: SMA1307 Revision %d\n",
+ __func__, sma1307->rev_num);
+ regmap_read(sma1307->regmap, SMA1307_99_OTP_TRM2, &sma1307->otp_trm2);
+ regmap_read(sma1307->regmap, SMA1307_9A_OTP_TRM3, &sma1307->otp_trm3);
+
+ if ((sma1307->otp_trm2 & SMA1307_OTP_STAT_MASK) != SMA1307_OTP_STAT_1)
+ dev_warn(component->dev, "%s: SMA1307 OTP Status Fail\n",
+ __func__);
+
+ /* Register Initial Value Setting */
+ sma1307_setting_loaded(sma1307, setting_file);
+ if (sma1307->set.status)
+ sma1307_set_binary(component);
+ else
+ sma1307_set_default(component);
+
+ regmap_update_bits(sma1307->regmap,
+ SMA1307_93_INT_CTRL,
+ SMA1307_DIS_INT_MASK, SMA1307_HIGH_Z_INT);
+ regmap_write(sma1307->regmap, SMA1307_0A_SPK_VOL, sma1307->init_vol);
+}
+
+static void sma1307_set_binary(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int i = 0, mode = 0;
+
+ for (i = 0; i < (sma1307->set.def_size); i++) {
+ if (sma1307_writeable_register(sma1307->dev, i)
+ && ((i < SMA1307_97_OTP_TRM0)
+ || (i > SMA1307_9A_OTP_TRM3))) {
+ regmap_write(sma1307->regmap, i, sma1307->set.def[i]);
+
+ }
+ }
+ for (i = 0; i < (sma1307->set.mode_size); i++) {
+ if (sma1307_writeable_register(sma1307->dev, i)
+ && ((i < SMA1307_97_OTP_TRM0)
+ || (i > SMA1307_9A_OTP_TRM3))) {
+ mode = sma1307->binary_mode;
+ regmap_write(sma1307->regmap,
+ sma1307->set.mode_set[mode][2 * i],
+ sma1307->set.mode_set[mode][2 * i +
+ 1]);
+ }
+ }
+}
+
+static void sma1307_set_default(struct snd_soc_component *component)
+{
+ struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component);
+ int i = 0;
+
+ for (i = 0; i < (unsigned int)ARRAY_SIZE(sma1307_reg_def); i++)
+ regmap_write(sma1307->regmap,
+ sma1307_reg_def[i].reg,
+ sma1307_reg_def[i].def);
+
+ if (!strcmp(sma1307->name, DEVICE_NAME_SMA1307AQ))
+ sma1307->data->init(sma1307->regmap);
+}
+
+static int sma1307_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
+ snd_soc_dapm_sync(dapm);
+
+ sma1307_amp_component = component;
+
+ snd_soc_add_component_controls(component, sma1307_binary_mode_control,
+ ARRAY_SIZE(sma1307_binary_mode_control));
+ sma1307_reset(component);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver sma1307_component = {
+ .probe = sma1307_probe,
+ .controls = sma1307_snd_controls,
+ .num_controls = ARRAY_SIZE(sma1307_snd_controls),
+ .dapm_widgets = sma1307_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sma1307_dapm_widgets),
+ .dapm_routes = sma1307_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(sma1307_audio_map),
+};
+
+static const struct regmap_config sma_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SMA1307_FF_DEVICE_INDEX,
+ .readable_reg = sma1307_readable_register,
+ .writeable_reg = sma1307_writeable_register,
+ .volatile_reg = sma1307_volatile_register,
+
+ .reg_defaults = sma1307_reg_def,
+ .num_reg_defaults = ARRAY_SIZE(sma1307_reg_def),
+};
+
+static void sma1307aq_init(struct regmap *regmap)
+{
+ /* Guidelines for driving 4ohm load */
+ /* Brown Out Protection */
+ regmap_write(regmap, SMA1307_02_BROWN_OUT_PROT1, 0x62);
+ regmap_write(regmap, SMA1307_03_BROWN_OUT_PROT2, 0x5D);
+ regmap_write(regmap, SMA1307_04_BROWN_OUT_PROT3, 0x57);
+ regmap_write(regmap, SMA1307_05_BROWN_OUT_PROT8, 0x54);
+ regmap_write(regmap, SMA1307_06_BROWN_OUT_PROT9, 0x51);
+ regmap_write(regmap,
+ SMA1307_07_BROWN_OUT_PROT10, 0x4D);
+ regmap_write(regmap,
+ SMA1307_08_BROWN_OUT_PROT11, 0x4B);
+ regmap_write(regmap, SMA1307_27_BROWN_OUT_PROT4, 0x3C);
+ regmap_write(regmap, SMA1307_28_BROWN_OUT_PROT5, 0x5B);
+ regmap_write(regmap,
+ SMA1307_29_BROWN_OUT_PROT12, 0x78);
+ regmap_write(regmap,
+ SMA1307_2A_BROWN_OUT_PROT13, 0x96);
+ regmap_write(regmap,
+ SMA1307_2B_BROWN_OUT_PROT14, 0xB4);
+ regmap_write(regmap,
+ SMA1307_2C_BROWN_OUT_PROT15, 0xD3);
+ /* FDPEC Gain */
+ regmap_write(regmap, SMA1307_35_FDPEC_CTRL0, 0x16);
+ /* FLT Vdd */
+ regmap_write(regmap, SMA1307_92_FDPEC_CTRL1, 0xA0);
+ /* Boost Max */
+ regmap_write(regmap, SMA1307_AB_BOOST_CTRL4, 0x0F);
+}
+
+static const struct sma1307_data sma1307aq_data = {
+ .name = DEVICE_NAME_SMA1307AQ,
+ .init = sma1307aq_init,
+};
+
+static int sma1307_i2c_probe(struct i2c_client *client)
+{
+ struct sma1307_priv *sma1307;
+ const struct sma1307_data *data;
+ int ret = 0;
+ unsigned int device_info;
+
+ sma1307 = devm_kzalloc(&client->dev,
+ sizeof(*sma1307), GFP_KERNEL);
+ if (!sma1307)
+ return -ENOMEM;
+
+ sma1307->regmap = devm_regmap_init_i2c(client, &sma_i2c_regmap);
+ if (IS_ERR(sma1307->regmap)) {
+ return dev_err_probe(&client->dev, PTR_ERR(sma1307->regmap),
+ "%s: failed to allocate register map\n", __func__);
+ }
+
+ data = device_get_match_data(&client->dev);
+ if (!data)
+ return -ENODEV;
+
+ sma1307->data = data;
+
+ /* set initial value as normal AMP IC status */
+ sma1307->name = client->name;
+ sma1307->format = SND_SOC_DAIFMT_I2S;
+ sma1307->sys_clk_id = SMA1307_PLL_CLKIN_BCLK;
+ sma1307->num_of_pll_matches = ARRAY_SIZE(sma1307_pll_matches);
+
+ sma1307->check_fault_period = CHECK_PERIOD_TIME;
+ sma1307->check_fault_status = true;
+ sma1307->init_vol = 0x32;
+ sma1307->cur_vol = sma1307->init_vol;
+ sma1307->sw_ot1_prot = true;
+
+ mutex_init(&sma1307->default_lock);
+
+ INIT_DELAYED_WORK(&sma1307->check_fault_work,
+ sma1307_check_fault_worker);
+
+ sma1307->dev = &client->dev;
+ sma1307->kobj = &client->dev.kobj;
+
+ i2c_set_clientdata(client, sma1307);
+
+ sma1307->pll_matches = sma1307_pll_matches;
+
+ regmap_read(sma1307->regmap,
+ SMA1307_FF_DEVICE_INDEX, &device_info);
+
+ if ((device_info & 0xF8) != SMA1307_DEVICE_ID) {
+ dev_err(&client->dev,
+ "%s: device initialization error (0x%02X)",
+ __func__, device_info);
+ return -ENODEV;
+ }
+ dev_dbg(&client->dev, "%s: chip version 0x%02X\n",
+ __func__, device_info);
+
+ i2c_set_clientdata(client, sma1307);
+
+ ret = devm_snd_soc_register_component(&client->dev,
+ &sma1307_component, sma1307_dai,
+ 1);
+
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to register component\n",
+ __func__);
+
+ return ret;
+ }
+
+ return ret;
+}
+
+static void sma1307_i2c_remove(struct i2c_client *client)
+{
+ struct sma1307_priv *sma1307 =
+ (struct sma1307_priv *)i2c_get_clientdata(client);
+
+ cancel_delayed_work_sync(&sma1307->check_fault_work);
+}
+
+static const struct i2c_device_id sma1307_i2c_id[] = {
+ { "sma1307a" },
+ { "sma1307aq" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, sma1307_i2c_id);
+
+static const struct of_device_id sma1307_of_match[] = {
+ {
+ .compatible = "irondevice,sma1307a",
+ },
+ {
+ .compatible = "irondevice,sma1307aq",
+ .data = &sma1307aq_data //AEC-Q100 Qualificated
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, sma1307_of_match);
+
+static struct i2c_driver sma1307_i2c_driver = {
+ .driver = {
+ .name = "sma1307",
+ .of_match_table = sma1307_of_match,
+ },
+ .probe = sma1307_i2c_probe,
+ .remove = sma1307_i2c_remove,
+ .id_table = sma1307_i2c_id,
+};
+
+module_i2c_driver(sma1307_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC SMA1307 driver");
+MODULE_AUTHOR("Gyuhwa Park, <gyuhwa.park@irondevice.com>");
+MODULE_AUTHOR("KS Jo, <kiseok.jo@irondevice.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sma1307.h b/sound/soc/codecs/sma1307.h
new file mode 100644
index 000000000000..44aab52a32f9
--- /dev/null
+++ b/sound/soc/codecs/sma1307.h
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * sma1307.h -- sma1307 ALSA SoC Audio driver
+ *
+ * Copyright 2024 Iron Device Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SMA1307_H
+#define _SMA1307_H
+
+#include <sound/soc.h>
+
+enum sma1307_fault {
+ SMA1307_FAULT_OT1,
+ SMA1307_FAULT_OT2,
+ SMA1307_FAULT_UVLO,
+ SMA1307_FAULT_OVP_BST,
+ SMA1307_FAULT_OCP_SPK,
+ SMA1307_FAULT_OCP_BST,
+ SMA1307_FAULT_CLK
+};
+
+enum sma1307_mode {
+ SMA1307_MONO_MODE,
+ SMA1307_LEFT_MODE,
+ SMA1307_RIGHT_MODE,
+};
+
+enum sma1307_sdo_mode {
+ SMA1307_OUT_DATA_ONE_48K,
+ SMA1307_OUT_DATA_TWO_48K,
+ SMA1307_OUT_DATA_TWO_24K,
+ SMA1307_OUT_CLK_PLL,
+ SMA1307_OUT_CLK_OSC
+};
+
+enum sma1307_sdo_source {
+ SMA1307_OUT_DISABLE,
+ SMA1307_OUT_FORMAT_C,
+ SMA1307_OUT_MIXER_OUT,
+ SMA1307_OUT_AFTER_DSP,
+ SMA1307_OUT_VRMS2_AVG,
+ SMA1307_OUT_BATTERY,
+ SMA1307_OUT_TEMP,
+ SMA1307_OUT_AFTER_DELAY
+};
+
+struct sma1307_setting_file {
+ bool status;
+ char *header;
+ int *def;
+ int *mode_set[5];
+ int checksum;
+ int num_mode;
+ size_t header_size;
+ size_t def_size;
+ size_t mode_size;
+};
+
+#define SMA1307_I2C_ADDR_00 0x1e
+#define SMA1307_I2C_ADDR_01 0x3e
+#define SMA1307_I2C_ADDR_10 0x5e
+#define SMA1307_I2C_ADDR_11 0x7e
+
+#define DEVICE_NAME_SMA1307A "sma1307a"
+#define DEVICE_NAME_SMA1307AQ "sma1307aq"
+
+#define SMA1307_EXTERNAL_CLOCK_19_2 0x00
+#define SMA1307_EXTERNAL_CLOCK_24_576 0x01
+#define SMA1307_PLL_CLKIN_MCLK 0x02
+#define SMA1307_PLL_CLKIN_BCLK 0x03
+
+#define SMA1307_OFFSET_DEFAULT_MODE 0x00
+#define SMA1307_OFFSET_BURNING_MODE 0x01
+
+#define SMA1307_SETTING_HEADER_SIZE 0x08
+#define SMA1307_SETTING_DEFAULT_SIZE 0xC0
+
+#define SMA1307_DEFAULT_SET 0x00
+#define SMA1307_BINARY_FILE_SET 0x01
+
+/* Controls Name */
+#define SMA1307_REG_CTRL_NAME "Register Byte Control"
+#define SMA1307_VOL_CTRL_NAME "Speaker Volume"
+#define SMA1307_FORCE_MUTE_CTRL_NAME "Force Mute Switch"
+#define SMA1307_TDM_RX0_POS_NAME "TDM RX Slot0 Position"
+#define SMA1307_TDM_RX1_POS_NAME "TDM RX Slot1 Position"
+#define SMA1307_TDM_TX0_POS_NAME "TDM TX Slot0 Position"
+#define SMA1307_TDM_TX1_POS_NAME "TDM TX Slot1 Position"
+#define SMA1307_OT1_SW_PROT_CTRL_NAME "OT1 SW Protection Switch"
+#define SMA1307_RESET_CTRL_NAME "Reset Switch"
+#define SMA1307_CHECK_FAULT_STATUS_NAME "Check Fault Status"
+#define SMA1307_CHECK_FAULT_PERIOD_NAME "Check Fault Period"
+
+/* DAPM Name */
+#define SMA1307_AIF_IN_NAME "AIF IN Source"
+#define SMA1307_AIF_OUT0_NAME "AIF OUT0 Source"
+#define SMA1307_AIF_OUT1_NAME "AIF OUT1 Source"
+
+/*
+ * SMA1307 Register Definition
+ */
+
+/* SMA1307 Register Addresses */
+#define SMA1307_00_SYSTEM_CTRL 0x00
+#define SMA1307_01_INPUT_CTRL1 0x01
+#define SMA1307_02_BROWN_OUT_PROT1 0x02
+#define SMA1307_03_BROWN_OUT_PROT2 0x03
+#define SMA1307_04_BROWN_OUT_PROT3 0x04
+#define SMA1307_05_BROWN_OUT_PROT8 0x05
+#define SMA1307_06_BROWN_OUT_PROT9 0x06
+#define SMA1307_07_BROWN_OUT_PROT10 0x07
+#define SMA1307_08_BROWN_OUT_PROT11 0x08
+#define SMA1307_09_OUTPUT_CTRL 0x09
+#define SMA1307_0A_SPK_VOL 0x0A
+#define SMA1307_0B_BST_TEST 0x0B
+#define SMA1307_0C_BOOST_CTRL8 0x0C
+#define SMA1307_0D_SPK_TEST 0x0D
+#define SMA1307_0E_MUTE_VOL_CTRL 0x0E
+#define SMA1307_0F_VBAT_TEMP_SENSING 0x0F
+
+#define SMA1307_10_SYSTEM_CTRL1 0x10
+#define SMA1307_11_SYSTEM_CTRL2 0x11
+#define SMA1307_12_SYSTEM_CTRL3 0x12
+#define SMA1307_13_DELAY 0x13
+#define SMA1307_14_MODULATOR 0x14
+#define SMA1307_15_BASS_SPK1 0x15
+#define SMA1307_16_BASS_SPK2 0x16
+#define SMA1307_17_BASS_SPK3 0x17
+#define SMA1307_18_BASS_SPK4 0x18
+#define SMA1307_19_BASS_SPK5 0x19
+#define SMA1307_1A_BASS_SPK6 0x1A
+#define SMA1307_1B_BASS_SPK7 0x1B
+#define SMA1307_1C_BROWN_OUT_PROT20 0x1C
+#define SMA1307_1D_BROWN_OUT_PROT0 0x1D
+#define SMA1307_1E_TONE_GENERATOR 0x1E
+#define SMA1307_1F_TONE_FINE_VOLUME 0x1F
+
+#define SMA1307_22_COMP_HYS_SEL 0x22
+#define SMA1307_23_COMPLIM1 0x23
+#define SMA1307_24_COMPLIM2 0x24
+#define SMA1307_25_COMPLIM3 0x25
+#define SMA1307_26_COMPLIM4 0x26
+#define SMA1307_27_BROWN_OUT_PROT4 0x27
+#define SMA1307_28_BROWN_OUT_PROT5 0x28
+#define SMA1307_29_BROWN_OUT_PROT12 0x29
+#define SMA1307_2A_BROWN_OUT_PROT13 0x2A
+#define SMA1307_2B_BROWN_OUT_PROT14 0x2B
+#define SMA1307_2C_BROWN_OUT_PROT15 0x2C
+#define SMA1307_2D_BROWN_OUT_PROT6 0x2D
+#define SMA1307_2E_BROWN_OUT_PROT7 0x2E
+#define SMA1307_2F_BROWN_OUT_PROT16 0x2F
+
+#define SMA1307_30_BROWN_OUT_PROT17 0x30
+#define SMA1307_31_BROWN_OUT_PROT18 0x31
+#define SMA1307_32_BROWN_OUT_PROT19 0x32
+#define SMA1307_34_OCP_SPK 0x34
+#define SMA1307_35_FDPEC_CTRL0 0x35
+#define SMA1307_36_PROTECTION 0x36
+#define SMA1307_37_SLOPECTRL 0x37
+#define SMA1307_38_POWER_METER 0x38
+#define SMA1307_39_PMT_NZ_VAL 0x39
+#define SMA1307_3B_TEST1 0x3B
+#define SMA1307_3C_TEST2 0x3C
+#define SMA1307_3D_TEST3 0x3D
+#define SMA1307_3E_IDLE_MODE_CTRL 0x3E
+#define SMA1307_3F_ATEST2 0x3F
+#define SMA1307_8B_PLL_POST_N 0x8B
+#define SMA1307_8C_PLL_N 0x8C
+#define SMA1307_8D_PLL_A_SETTING 0x8D
+#define SMA1307_8E_PLL_P_CP 0x8E
+#define SMA1307_8F_ANALOG_TEST 0x8F
+
+#define SMA1307_90_CRESTLIM1 0x90
+#define SMA1307_91_CRESTLIM2 0x91
+#define SMA1307_92_FDPEC_CTRL1 0x92
+#define SMA1307_93_INT_CTRL 0x93
+#define SMA1307_94_BOOST_CTRL9 0x94
+#define SMA1307_95_BOOST_CTRL10 0x95
+#define SMA1307_96_BOOST_CTRL11 0x96
+#define SMA1307_97_OTP_TRM0 0x97
+#define SMA1307_98_OTP_TRM1 0x98
+#define SMA1307_99_OTP_TRM2 0x99
+#define SMA1307_9A_OTP_TRM3 0x9A
+
+#define SMA1307_A0_PAD_CTRL0 0xA0
+#define SMA1307_A1_PAD_CTRL1 0xA1
+#define SMA1307_A2_TOP_MAN1 0xA2
+#define SMA1307_A3_TOP_MAN2 0xA3
+#define SMA1307_A4_TOP_MAN3 0xA4
+#define SMA1307_A5_TDM1 0xA5
+#define SMA1307_A6_TDM2 0xA6
+#define SMA1307_A7_CLK_MON 0xA7
+#define SMA1307_A8_BOOST_CTRL1 0xA8
+#define SMA1307_A9_BOOST_CTRL2 0xA9
+#define SMA1307_AA_BOOST_CTRL3 0xAA
+#define SMA1307_AB_BOOST_CTRL4 0xAB
+#define SMA1307_AC_BOOST_CTRL5 0xAC
+#define SMA1307_AD_BOOST_CTRL6 0xAD
+#define SMA1307_AE_BOOST_CTRL7 0xAE
+#define SMA1307_AF_LPF 0xAF
+
+#define SMA1307_B0_RMS_TC1 0xB0
+#define SMA1307_B1_RMS_TC2 0xB1
+#define SMA1307_B2_AVG_TC1 0xB2
+#define SMA1307_B3_AVG_TC2 0xB3
+#define SMA1307_B4_PRVALUE1 0xB4
+#define SMA1307_B5_PRVALUE2 0xB5
+#define SMA1307_B8_SPK_NG_CTRL1 0xB8
+#define SMA1307_B9_SPK_NG_CTRL2 0xB9
+#define SMA1307_BA_DGC1 0xBA
+#define SMA1307_BB_DGC2 0xBB
+#define SMA1307_BC_DGC3 0xBC
+#define SMA1307_BD_MCBS_CTRL1 0xBD
+#define SMA1307_BE_MCBS_CTRL2 0xBE
+
+/* Status Register Read Only */
+#define SMA1307_F5_READY_FOR_V_SAR 0xF5
+#define SMA1307_F7_READY_FOR_T_SAR 0xF7
+#define SMA1307_F8_STATUS_T1 0xF8
+#define SMA1307_F9_STATUS_T2 0xF9
+#define SMA1307_FA_STATUS1 0xFA
+#define SMA1307_FB_STATUS2 0xFB
+#define SMA1307_FC_STATUS3 0xFC
+#define SMA1307_FD_STATUS4 0xFD
+#define SMA1307_FE_STATUS5 0xFE
+#define SMA1307_FF_DEVICE_INDEX 0xFF
+
+/* SMA1307 Registers Bit Fields */
+/* Power On/Off */
+#define SMA1307_POWER_MASK BIT(0)
+#define SMA1307_POWER_OFF 0
+#define SMA1307_POWER_ON BIT(0)
+
+/* Reset */
+#define SMA1307_RESET_MASK BIT(1)
+#define SMA1307_RESET_ON BIT(1)
+
+/* Left Polarity */
+#define SMA1307_LEFTPOL_MASK BIT(3)
+#define SMA1307_LOW_FIRST_CH 0
+#define SMA1307_HIGH_FIRST_CH BIT(3)
+
+/* SCK Falling/Rising */
+#define SMA1307_SCK_RISING_MASK BIT(2)
+#define SMA1307_SCK_FALLING_EDGE 0
+#define SMA1307_SCK_RISING_EDGE BIT(2)
+
+/* SPK Mute */
+#define SMA1307_SPK_MUTE_MASK BIT(0)
+#define SMA1307_SPK_UNMUTE 0
+#define SMA1307_SPK_MUTE BIT(0)
+
+/* SPK Mode */
+#define SMA1307_SPK_MODE_MASK (BIT(2)|BIT(3)|BIT(4))
+#define SMA1307_SPK_OFF 0
+#define SMA1307_SPK_MONO BIT(2)
+#define SMA1307_SPK_STEREO BIT(4)
+
+/* Mono Mix */
+#define SMA1307_MONOMIX_MASK BIT(0)
+#define SMA1307_MONOMIX_OFF 0
+#define SMA1307_MONOMIX_ON BIT(0)
+
+/* LR Data Swap */
+#define SMA1307_LR_DATA_SW_MASK BIT(4)
+#define SMA1307_LR_DATA_SW_NORMAL 0
+#define SMA1307_LR_DATA_SW_SWAP BIT(4)
+
+/* PLL On/Off */
+#define SMA1307_PLL_MASK BIT(6)
+#define SMA1307_PLL_ON 0
+#define SMA1307_PLL_OFF BIT(6)
+
+/* Input Format */
+#define SMA1307_I2S_MODE_MASK (BIT(4)|BIT(5)|BIT(6))
+#define SMA1307_STANDARD_I2S 0
+#define SMA1307_LJ BIT(4)
+#define SMA1307_RJ_16BIT BIT(6)
+#define SMA1307_RJ_18BIT (BIT(4)|BIT(6))
+#define SMA1307_RJ_20BIT (BIT(5)|BIT(6))
+#define SMA1307_RJ_24BIT (BIT(4)|BIT(5)|BIT(6))
+
+/* Controller / Device Setting */
+#define SMA1307_CONTROLLER_DEVICE_MASK BIT(7)
+#define SMA1307_DEVICE_MODE 0
+#define SMA1307_CONTROLLER_MODE BIT(7)
+
+/* Port Config */
+#define SMA1307_PORT_CONFIG_MASK (BIT(6)|BIT(7))
+#define SMA1307_INPUT_PORT_ONLY 0
+#define SMA1307_OUTPUT_PORT_ENABLE BIT(7)
+
+/* SDO Output */
+#define SMA1307_SDO_OUTPUT_MASK BIT(3)
+#define SMA1307_LOGIC_OUTPUT 0
+#define SMA1307_HIGH_Z_OUTPUT BIT(3)
+
+#define SMA1307_DATA_CLK_SEL_MASK (BIT(6)|BIT(7))
+#define SMA1307_SDO_DATA 0
+#define SMA1307_SDO_CLK_PLL BIT(6)
+#define SMA1307_SDO_CLK_OSC (BIT(6)|BIT(7))
+
+/* SDO Output2 */
+#define SMA1307_SDO_OUTPUT2_MASK BIT(0)
+#define SMA1307_ONE_SDO_PER_CH 0
+#define SMA1307_TWO_SDO_PER_CH BIT(0)
+
+/* SDO Output3 */
+#define SMA1307_SDO_OUTPUT3_MASK BIT(2)
+#define SMA1307_SDO_OUTPUT3_DIS 0
+#define SMA1307_TWO_SDO_PER_CH_24K BIT(2)
+
+/* SDO OUT1 Select*/
+#define SMA1307_SDO_OUT1_SEL_MASK (BIT(3)|BIT(4)|BIT(5))
+#define SMA1307_SDO1_DISABLE 0
+#define SMA1307_SDO1_FORMAT_C BIT(3)
+#define SMA1307_SDO1_MONO_MIX BIT(4)
+#define SMA1307_SDO1_AFTER_DSP (BIT(3)|BIT(4))
+#define SMA1307_SDO1_VRMS2_AVG BIT(5)
+#define SMA1307_SDO1_VBAT_MON (BIT(3)|BIT(5))
+#define SMA1307_SDO1_TEMP_MON (BIT(4)|BIT(5))
+#define SMA1307_SDO1_AFTER_DELAY (BIT(3)|BIT(4)|BIT(5))
+
+/* SDO OUT0 Select*/
+#define SMA1307_SDO_OUT0_SEL_MASK (BIT(0)|BIT(1)|BIT(2))
+#define SMA1307_SDO0_DISABLE 0
+#define SMA1307_SDO0_FORMAT_C BIT(0)
+#define SMA1307_SDO0_MONO_MIX BIT(1)
+#define SMA1307_SDO0_AFTER_DSP (BIT(0)|BIT(1))
+#define SMA1307_SDO0_VRMS2_AVG BIT(2)
+#define SMA1307_SDO0_VBAT_MON (BIT(0)|BIT(2))
+#define SMA1307_SDO0_TEMP_MON (BIT(1)|BIT(2))
+#define SMA1307_SDO0_AFTER_DELAY (BIT(0)|BIT(1)|BIT(2))
+
+/* INTERRUPT Operation */
+#define SMA1307_SEL_INT_MASK BIT(2)
+#define SMA1307_INT_CLEAR_AUTO 0
+#define SMA1307_INT_CLEAR_MANUAL BIT(2)
+
+/* INTERRUPT CLEAR */
+#define SMA1307_CLR_INT_MASK BIT(1)
+#define SMA1307_INT_READY 0
+#define SMA1307_INT_CLEAR BIT(1)
+
+/* INTERRUPT Disable */
+#define SMA1307_DIS_INT_MASK BIT(0)
+#define SMA1307_NORMAL_INT 0
+#define SMA1307_HIGH_Z_INT BIT(0)
+
+/* Interface Control */
+#define SMA1307_INTERFACE_MASK (BIT(5)|BIT(6)|BIT(7))
+#define SMA1307_LJ_FORMAT BIT(5)
+#define SMA1307_I2S_FORMAT (BIT(5)|BIT(6))
+#define SMA1307_TDM_FORMAT BIT(7)
+
+#define SMA1307_SCK_RATE_MASK (BIT(3)|BIT(4))
+#define SMA1307_SCK_64FS 0
+#define SMA1307_SCK_32FS BIT(4)
+
+#define SMA1307_DATA_WIDTH_MASK (BIT(1)|BIT(2))
+#define SMA1307_DATA_24BIT 0
+#define SMA1307_DATA_16BIT (BIT(1)|BIT(2))
+
+#define SMA1307_TDM_TX_MODE_MASK BIT(6)
+#define SMA1307_TDM_TX_MONO 0
+#define SMA1307_TDM_TX_STEREO BIT(6)
+
+#define SMA1307_TDM_SLOT0_RX_POS_MASK (BIT(3)|BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_RX_POS_0 0
+#define SMA1307_TDM_SLOT0_RX_POS_1 BIT(3)
+#define SMA1307_TDM_SLOT0_RX_POS_2 BIT(4)
+#define SMA1307_TDM_SLOT0_RX_POS_3 (BIT(3)|BIT(4))
+#define SMA1307_TDM_SLOT0_RX_POS_4 BIT(5)
+#define SMA1307_TDM_SLOT0_RX_POS_5 (BIT(3)|BIT(5))
+#define SMA1307_TDM_SLOT0_RX_POS_6 (BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_RX_POS_7 (BIT(3)|BIT(4)|BIT(5))
+
+#define SMA1307_TDM_SLOT1_RX_POS_MASK (BIT(0)|BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_RX_POS_0 0
+#define SMA1307_TDM_SLOT1_RX_POS_1 BIT(0)
+#define SMA1307_TDM_SLOT1_RX_POS_2 BIT(1)
+#define SMA1307_TDM_SLOT1_RX_POS_3 (BIT(0)|BIT(1))
+#define SMA1307_TDM_SLOT1_RX_POS_4 BIT(2)
+#define SMA1307_TDM_SLOT1_RX_POS_5 (BIT(0)|BIT(2))
+#define SMA1307_TDM_SLOT1_RX_POS_6 (BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_RX_POS_7 (BIT(0)|BIT(1)|BIT(2))
+
+/* TDM2 FORMAT : 0xA6 */
+#define SMA1307_TDM_DL_MASK BIT(7)
+#define SMA1307_TDM_DL_16 0
+#define SMA1307_TDM_DL_32 BIT(7)
+
+#define SMA1307_TDM_N_SLOT_MASK BIT(6)
+#define SMA1307_TDM_N_SLOT_4 0
+#define SMA1307_TDM_N_SLOT_8 BIT(6)
+
+#define SMA1307_TDM_SLOT0_TX_POS_MASK (BIT(3)|BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_TX_POS_0 0
+#define SMA1307_TDM_SLOT0_TX_POS_1 BIT(3)
+#define SMA1307_TDM_SLOT0_TX_POS_2 BIT(4)
+#define SMA1307_TDM_SLOT0_TX_POS_3 (BIT(3)|BIT(4))
+#define SMA1307_TDM_SLOT0_TX_POS_4 BIT(5)
+#define SMA1307_TDM_SLOT0_TX_POS_5 (BIT(3)|BIT(5))
+#define SMA1307_TDM_SLOT0_TX_POS_6 (BIT(4)|BIT(5))
+#define SMA1307_TDM_SLOT0_TX_POS_7 (BIT(3)|BIT(4)|BIT(5))
+
+#define SMA1307_TDM_SLOT1_TX_POS_MASK (BIT(0)|BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_TX_POS_0 0
+#define SMA1307_TDM_SLOT1_TX_POS_1 BIT(0)
+#define SMA1307_TDM_SLOT1_TX_POS_2 BIT(1)
+#define SMA1307_TDM_SLOT1_TX_POS_3 (BIT(0)|BIT(1))
+#define SMA1307_TDM_SLOT1_TX_POS_4 BIT(2)
+#define SMA1307_TDM_SLOT1_TX_POS_5 (BIT(0)|BIT(2))
+#define SMA1307_TDM_SLOT1_TX_POS_6 (BIT(1)|BIT(2))
+#define SMA1307_TDM_SLOT1_TX_POS_7 (BIT(0)|BIT(1)|BIT(2))
+
+/* OTP STATUS */
+#define SMA1307_OTP_STAT_MASK BIT(6)
+#define SMA1307_OTP_STAT_0 0
+#define SMA1307_OTP_STAT_1 BIT(6)
+
+/* STATUS */
+#define SMA1307_OT1_OK_STATUS BIT(7)
+#define SMA1307_OT2_OK_STATUS BIT(6)
+#define SMA1307_UVLO_STATUS BIT(5)
+#define SMA1307_OVP_BST_STATUS BIT(4)
+#define SMA1307_POWER_FLAG BIT(3)
+
+#define SMA1307_SCAN_CHK BIT(7)
+#define SMA1307_OCP_SPK_STATUS BIT(5)
+#define SMA1307_OCP_BST_STATUS BIT(4)
+#define SMA1307_BOP_STATE (BIT(1)|BIT(2)|BIT(3))
+#define SMA1307_CLK_MON_STATUS BIT(0)
+
+#define SMA1307_DEVICE_ID (BIT(3)|BIT(4))
+#define SMA1307_REV_NUM_STATUS (BIT(0)|BIT(1))
+#define SMA1307_REV_NUM_REV0 0
+#define SMA1307_REV_NUM_REV1 BIT(0)
+
+#endif
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index 862e0b654a1c..c9766979b1d7 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -28,14 +28,15 @@ static const struct snd_soc_dapm_route dir_routes[] = {
{ "Capture", NULL, "spdif-in" },
};
-#define STUB_RATES SNDRV_PCM_RATE_8000_192000
+#define STUB_RATES (SNDRV_PCM_RATE_8000_768000 | \
+ SNDRV_PCM_RATE_128000)
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE | \
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
-static struct snd_soc_component_driver soc_codec_spdif_dir = {
+static const struct snd_soc_component_driver soc_codec_spdif_dir = {
.dapm_widgets = dir_widgets,
.num_dapm_widgets = ARRAY_SIZE(dir_widgets),
.dapm_routes = dir_routes,
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index 736518921555..2409fd834f84 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -21,7 +21,8 @@
#define DRV_NAME "spdif-dit"
-#define STUB_RATES SNDRV_PCM_RATE_8000_192000
+#define STUB_RATES (SNDRV_PCM_RATE_8000_768000 | \
+ SNDRV_PCM_RATE_128000)
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
@@ -35,7 +36,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
{ "spdif-out", NULL, "Playback" },
};
-static struct snd_soc_component_driver soc_codec_spdif_dit = {
+static const struct snd_soc_component_driver soc_codec_spdif_dit = {
.dapm_widgets = dit_widgets,
.num_dapm_widgets = ARRAY_SIZE(dit_widgets),
.dapm_routes = dit_routes,
diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c
index 93af8e209b05..55f00ce7c718 100644
--- a/sound/soc/codecs/src4xxx-i2c.c
+++ b/sound/soc/codecs/src4xxx-i2c.c
@@ -19,7 +19,7 @@ static int src4xxx_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id src4xxx_i2c_ids[] = {
- { "src4392", 0 },
+ { "src4392" },
{ }
};
MODULE_DEVICE_TABLE(i2c, src4xxx_i2c_ids);
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/ssm2518.c b/sound/soc/codecs/ssm2518.c
index d20d897407eb..9008e5416004 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -500,6 +500,7 @@ static int ssm2518_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret = 0;
switch (level) {
@@ -508,7 +509,7 @@ static int ssm2518_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
ret = ssm2518_set_power(ssm2518, true);
break;
case SND_SOC_BIAS_OFF:
@@ -793,7 +794,7 @@ MODULE_DEVICE_TABLE(of, ssm2518_dt_ids);
#endif
static const struct i2c_device_id ssm2518_i2c_ids[] = {
- { "ssm2518", 0 },
+ { "ssm2518" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids);
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/ssm2602.c b/sound/soc/codecs/ssm2602.c
index c29324403e9d..fccd2eacd7a6 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -562,7 +562,7 @@ static int ssm2602_resume(struct snd_soc_component *component)
static int ssm2602_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
int ret;
@@ -587,7 +587,7 @@ static int ssm2602_component_probe(struct snd_soc_component *component)
static int ssm2604_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c
index 008cb3eb5758..8c6665677a17 100644
--- a/sound/soc/codecs/ssm3515.c
+++ b/sound/soc/codecs/ssm3515.c
@@ -437,7 +437,7 @@ MODULE_DEVICE_TABLE(of, ssm3515_of_match);
static struct i2c_driver ssm3515_i2c_driver = {
.driver = {
.name = "ssm3515",
- .of_match_table = of_match_ptr(ssm3515_of_match),
+ .of_match_table = ssm3515_of_match,
},
.probe = ssm3515_i2c_probe,
};
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 0a6f04d8f636..15f88624faeb 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -369,6 +369,7 @@ static int ssm4567_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret = 0;
switch (level) {
@@ -377,7 +378,7 @@ static int ssm4567_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
ret = ssm4567_set_power(ssm4567, true);
break;
case SND_SOC_BIAS_OFF:
@@ -471,7 +472,7 @@ static int ssm4567_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ssm4567_i2c_ids[] = {
- { "ssm4567", 0 },
+ { "ssm4567" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 4a694d0bfd68..b9f9784f5164 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -21,8 +21,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
@@ -265,7 +264,7 @@ static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
@@ -307,7 +306,7 @@ exit_unlock:
static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
@@ -800,6 +799,7 @@ static int sta32x_set_bias_level(struct snd_soc_component *component,
{
int ret;
struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
dev_dbg(component->dev, "level = %d\n", level);
switch (level) {
@@ -814,7 +814,7 @@ static int sta32x_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies);
if (ret != 0) {
@@ -871,6 +871,7 @@ static struct snd_soc_dai_driver sta32x_dai = {
static int sta32x_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
struct sta32x_platform_data *pdata = sta32x->pdata;
int i, ret = 0, thermal = 0;
@@ -975,7 +976,7 @@ static int sta32x_probe(struct snd_soc_component *component)
if (sta32x->pdata->needs_esd_watchdog)
INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
@@ -984,8 +985,7 @@ static int sta32x_probe(struct snd_soc_component *component)
err_regulator_bulk_disable:
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
err_clk_disable_unprepare:
- if (sta32x->xti_clk)
- clk_disable_unprepare(sta32x->xti_clk);
+ clk_disable_unprepare(sta32x->xti_clk);
return ret;
}
@@ -996,8 +996,7 @@ static void sta32x_remove(struct snd_soc_component *component)
sta32x_watchdog_stop(sta32x);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
- if (sta32x->xti_clk)
- clk_disable_unprepare(sta32x->xti_clk);
+ clk_disable_unprepare(sta32x->xti_clk);
}
static const struct snd_soc_component_driver sta32x_component = {
@@ -1022,7 +1021,7 @@ static const struct regmap_config sta32x_regmap = {
.max_register = STA32X_FDRC2,
.reg_defaults = sta32x_regs,
.num_reg_defaults = ARRAY_SIZE(sta32x_regs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.wr_table = &sta32x_write_regs,
.rd_table = &sta32x_read_regs,
.volatile_table = &sta32x_volatile_regs,
@@ -1155,9 +1154,9 @@ static int sta32x_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id sta32x_i2c_id[] = {
- { "sta326", 0 },
- { "sta328", 0 },
- { "sta329", 0 },
+ { "sta326" },
+ { "sta328" },
+ { "sta329" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index d05f3fd57661..71af82b099c0 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -22,8 +22,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
@@ -302,7 +301,7 @@ static int sta350_coefficient_info(struct snd_kcontrol *kcontrol,
static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
@@ -344,7 +343,7 @@ exit_unlock:
static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
@@ -831,6 +830,7 @@ static int sta350_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
dev_dbg(component->dev, "level = %d\n", level);
@@ -846,7 +846,7 @@ static int sta350_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(
ARRAY_SIZE(sta350->supplies),
sta350->supplies);
@@ -906,6 +906,7 @@ static struct snd_soc_dai_driver sta350_dai = {
static int sta350_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
struct sta350_platform_data *pdata = sta350->pdata;
int i, ret = 0, thermal = 0;
@@ -1029,7 +1030,7 @@ static int sta350_probe(struct snd_soc_component *component)
sta350->coef_shadow[60] = 0x400000;
sta350->coef_shadow[61] = 0x400000;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
@@ -1065,7 +1066,7 @@ static const struct regmap_config sta350_regmap = {
.max_register = STA350_MISC2,
.reg_defaults = sta350_regs,
.num_reg_defaults = ARRAY_SIZE(sta350_regs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.wr_table = &sta350_write_regs,
.rd_table = &sta350_read_regs,
.volatile_table = &sta350_volatile_regs,
@@ -1239,7 +1240,7 @@ static void sta350_i2c_remove(struct i2c_client *client)
{}
static const struct i2c_device_id sta350_i2c_id[] = {
- { "sta350", 0 },
+ { "sta350" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sta350_i2c_id);
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 0ac08478ddac..8c3b2652b02e 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -155,6 +155,7 @@ static int sta529_set_bias_level(struct snd_soc_component *component, enum
snd_soc_bias_level level)
{
struct sta529 *sta529 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -165,7 +166,7 @@ static int sta529_set_bias_level(struct snd_soc_component *component, enum
FFX_CLK_ENB);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
regcache_sync(sta529->regmap);
snd_soc_component_update_bits(component, STA529_FFXCFG0,
POWER_CNTLMSAK, POWER_STDBY);
@@ -331,7 +332,7 @@ static const struct regmap_config sta529_regmap = {
.max_register = STA529_MAX_REGISTER,
.readable_reg = sta529_readable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = sta529_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults),
};
@@ -363,7 +364,7 @@ static int sta529_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id sta529_i2c_id[] = {
- { "sta529", 0 },
+ { "sta529" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sta529_i2c_id);
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 1824a71fe053..2f9f10a4dfed 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -67,7 +67,7 @@ static const struct regmap_config stac9766_regmap_config = {
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x78,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = regmap_ac97_default_volatile,
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 99545bcb2ba9..4ab15be69f3a 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -63,10 +63,6 @@ struct sti_spdif_audio {
struct sti_sas_dev_data {
const struct regmap_config *regmap;
const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
- const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
- const int num_dapm_widgets; /* dapms declaration */
- const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
- const int num_dapm_routes; /* route declaration */
};
/* driver data structure */
@@ -316,7 +312,7 @@ static const struct regmap_config stih407_sas_regmap = {
.reg_defaults = stih407_sas_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
.volatile_reg = sti_sas_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_read = sti_sas_read_reg,
.reg_write = sti_sas_write_reg,
};
@@ -324,10 +320,6 @@ static const struct regmap_config stih407_sas_regmap = {
static const struct sti_sas_dev_data stih407_data = {
.regmap = &stih407_sas_regmap,
.dac_ops = &stih407_dac_ops,
- .dapm_widgets = stih407_sas_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
- .dapm_routes = stih407_sas_route,
- .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
};
static struct snd_soc_dai_driver sti_sas_dai[] = {
@@ -386,12 +378,16 @@ static int sti_sas_component_probe(struct snd_soc_component *component)
return sti_sas_init_sas_registers(component, drvdata);
}
-static struct snd_soc_component_driver sti_sas_driver = {
+static const struct snd_soc_component_driver sti_sas_driver = {
.probe = sti_sas_component_probe,
.resume = sti_sas_resume,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
+ .dapm_widgets = stih407_sas_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
+ .dapm_routes = stih407_sas_route,
+ .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
};
static const struct of_device_id sti_sas_dev_match[] = {
@@ -446,13 +442,6 @@ static int sti_sas_driver_probe(struct platform_device *pdev)
sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
- /* Set dapms*/
- sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
- sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
-
- sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
- sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
-
/* Store context */
dev_set_drvdata(&pdev->dev, drvdata);
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 8c9dc318b0e8..43449d7c2584 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -2,7 +2,8 @@
/*
* tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
*
- * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com
+ * Copyright (C) 2014 - 2024 Texas Instruments Incorporated -
+ * https://www.ti.com
*
* Author: Dan Murphy <dmurphy@ti.com>
*/
@@ -11,8 +12,6 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -119,12 +118,14 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
&tas2552_input_mux_control),
SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("ASI OUT", "DAC Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
- SND_SOC_DAPM_OUTPUT("OUT")
+ SND_SOC_DAPM_OUTPUT("OUT"),
+ SND_SOC_DAPM_INPUT("DMIC")
};
static const struct snd_soc_dapm_route tas2552_audio_map[] = {
@@ -134,9 +135,9 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = {
{"ClassD", NULL, "Input selection"},
{"OUT", NULL, "ClassD"},
{"ClassD", NULL, "PLL"},
+ {"ASI OUT", NULL, "DMIC"}
};
-#ifdef CONFIG_PM
static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown)
{
u8 cfg1_reg = 0;
@@ -150,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)
@@ -478,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);
@@ -506,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 = {
@@ -538,6 +535,13 @@ static struct snd_soc_dai_driver tas2552_dai[] = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = TAS2552_FORMATS,
},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = TAS2552_FORMATS,
+ },
.ops = &tas2552_speaker_dai_ops,
},
};
@@ -720,7 +724,6 @@ static int tas2552_probe(struct i2c_client *client)
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev);
pm_runtime_enable(&client->dev);
- pm_runtime_mark_last_busy(&client->dev);
pm_runtime_put_sync_autosuspend(&client->dev);
dev_set_drvdata(&client->dev, data);
@@ -742,7 +745,7 @@ static void tas2552_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id tas2552_id[] = {
- { "tas2552", 0 },
+ { "tas2552" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tas2552_id);
@@ -759,7 +762,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 962c2cdfa017..ceb367ae05ba 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -59,7 +59,6 @@ struct tas2562_data {
enum tas256x_model {
TAS2562,
- TAS2563,
TAS2564,
TAS2110,
};
@@ -460,7 +459,7 @@ static int tas2562_dac_event(struct snd_soc_dapm_widget *w,
static int tas2562_volume_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = tas2562->volume_lvl;
@@ -470,7 +469,7 @@ static int tas2562_volume_control_get(struct snd_kcontrol *kcontrol,
static int tas2562_volume_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
int ret;
u32 reg_val;
@@ -514,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[] = {
@@ -721,7 +712,6 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562)
static const struct i2c_device_id tas2562_id[] = {
{ "tas2562", TAS2562 },
- { "tas2563", TAS2563 },
{ "tas2564", TAS2564 },
{ "tas2110", TAS2110 },
{ }
@@ -733,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);
@@ -770,7 +758,6 @@ static int tas2562_probe(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id tas2562_of_match[] = {
{ .compatible = "ti,tas2562", },
- { .compatible = "ti,tas2563", },
{ .compatible = "ti,tas2564", },
{ .compatible = "ti,tas2110", },
{ },
diff --git a/sound/soc/codecs/tas2764-quirks.h b/sound/soc/codecs/tas2764-quirks.h
new file mode 100644
index 000000000000..7a62b3ba5b40
--- /dev/null
+++ b/sound/soc/codecs/tas2764-quirks.h
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __TAS2764_QUIRKS__
+#define __TAS2764_QUIRKS__
+
+#include <linux/regmap.h>
+
+#include "tas2764.h"
+
+/* Bitmask of enabled Apple quirks */
+#define ENABLED_APPLE_QUIRKS 0x3f
+
+/*
+ * Disable noise gate and flip down reserved bit in NS_CFG0
+ */
+#define TAS2764_NOISE_GATE_DISABLE BIT(0)
+
+static const struct reg_sequence tas2764_noise_gate_dis_seq[] = {
+ REG_SEQ0(TAS2764_REG(0x0, 0x35), 0xb0)
+};
+
+/*
+ * CONV_VBAT_PVDD_MODE=1
+ */
+#define TAS2764_CONV_VBAT_PVDD_MODE BIT(1)
+
+static const struct reg_sequence tas2764_conv_vbat_pvdd_mode_seq[] = {
+ REG_SEQ0(TAS2764_REG(0x0, 0x6b), 0x41)
+};
+
+/*
+ * Reset of DAC modulator when DSP is OFF
+ */
+#define TAS2764_DMOD_RST BIT(2)
+
+static const struct reg_sequence tas2764_dmod_rst_seq[] = {
+ REG_SEQ0(TAS2764_REG(0x0, 0x76), 0x0)
+};
+
+/*
+ * Unknown 0x133/0x137 writes (maybe TDM related)
+ */
+#define TAS2764_UNK_SEQ0 BIT(3)
+
+static const struct reg_sequence tas2764_unk_seq0[] = {
+ REG_SEQ0(TAS2764_REG(0x1, 0x33), 0x80),
+ REG_SEQ0(TAS2764_REG(0x1, 0x37), 0x3a),
+};
+
+/*
+ * Unknown 0x614 - 0x61f writes
+ */
+#define TAS2764_APPLE_UNK_SEQ1 BIT(4)
+
+static const struct reg_sequence tas2764_unk_seq1[] = {
+ REG_SEQ0(TAS2764_REG(0x6, 0x14), 0x0),
+ REG_SEQ0(TAS2764_REG(0x6, 0x15), 0x13),
+ REG_SEQ0(TAS2764_REG(0x6, 0x16), 0x52),
+ REG_SEQ0(TAS2764_REG(0x6, 0x17), 0x0),
+ REG_SEQ0(TAS2764_REG(0x6, 0x18), 0xe4),
+ REG_SEQ0(TAS2764_REG(0x6, 0x19), 0xc),
+ REG_SEQ0(TAS2764_REG(0x6, 0x16), 0xaa),
+ REG_SEQ0(TAS2764_REG(0x6, 0x1b), 0x0),
+ REG_SEQ0(TAS2764_REG(0x6, 0x1c), 0x12),
+ REG_SEQ0(TAS2764_REG(0x6, 0x1d), 0xa0),
+ REG_SEQ0(TAS2764_REG(0x6, 0x1e), 0xd8),
+ REG_SEQ0(TAS2764_REG(0x6, 0x1f), 0x0),
+};
+
+/*
+ * Unknown writes in the 0xfd page (with secondary paging inside)
+ */
+#define TAS2764_APPLE_UNK_SEQ2 BIT(5)
+
+static const struct reg_sequence tas2764_unk_seq2[] = {
+ REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd),
+ REG_SEQ0(TAS2764_REG(0xfd, 0x6c), 0x2),
+ REG_SEQ0(TAS2764_REG(0xfd, 0x6d), 0xf),
+ REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0),
+};
+
+/*
+ * Disable 'Thermal Threshold 1'
+ */
+#define TAS2764_THERMAL_TH1_DISABLE BIT(6)
+
+static const struct reg_sequence tas2764_thermal_th1_dis_seq[] = {
+ REG_SEQ0(TAS2764_REG(0x1, 0x47), 0x2),
+};
+
+/*
+ * Imitate Apple's shutdown dance
+ */
+#define TAS2764_SHUTDOWN_DANCE BIT(7)
+
+static const struct reg_sequence tas2764_shutdown_dance_init_seq[] = {
+ /*
+ * SDZ_MODE=01 (immediate)
+ *
+ * We want the shutdown to happen under the influence of
+ * the magic writes in the 0xfdXX region, so make sure
+ * the shutdown is immediate and there's no grace period
+ * followed by the codec part.
+ */
+ REG_SEQ0(TAS2764_REG(0x0, 0x7), 0x60),
+};
+
+static const struct reg_sequence tas2764_pre_shutdown_seq[] = {
+ REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd), /* switch hidden page */
+ REG_SEQ0(TAS2764_REG(0xfd, 0x64), 0x4), /* do write (unknown semantics) */
+ REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0), /* switch hidden page back */
+};
+
+static const struct reg_sequence tas2764_post_shutdown_seq[] = {
+ REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0xd),
+ REG_SEQ0(TAS2764_REG(0xfd, 0x64), 0x0), /* revert write from pre sequence */
+ REG_SEQ0(TAS2764_REG(0xfd, 0x0d), 0x0),
+};
+
+static int tas2764_do_quirky_pwr_ctrl_change(struct tas2764_priv *tas2764,
+ unsigned int target)
+{
+ unsigned int curr;
+ int ret;
+
+ curr = snd_soc_component_read_field(tas2764->component,
+ TAS2764_PWR_CTRL,
+ TAS2764_PWR_CTRL_MASK);
+
+ if (target == curr)
+ return 0;
+
+ /* Handle power state transition to shutdown */
+ if (target == TAS2764_PWR_CTRL_SHUTDOWN &&
+ (curr == TAS2764_PWR_CTRL_MUTE || curr == TAS2764_PWR_CTRL_ACTIVE)) {
+ ret = regmap_multi_reg_write(tas2764->regmap, tas2764_pre_shutdown_seq,
+ ARRAY_SIZE(tas2764_pre_shutdown_seq));
+ if (!ret)
+ ret = snd_soc_component_update_bits(tas2764->component,
+ TAS2764_PWR_CTRL,
+ TAS2764_PWR_CTRL_MASK,
+ TAS2764_PWR_CTRL_SHUTDOWN);
+ if (!ret)
+ ret = regmap_multi_reg_write(tas2764->regmap,
+ tas2764_post_shutdown_seq,
+ ARRAY_SIZE(tas2764_post_shutdown_seq));
+ }
+
+ ret = snd_soc_component_update_bits(tas2764->component, TAS2764_PWR_CTRL,
+ TAS2764_PWR_CTRL_MASK, target);
+
+ return ret;
+}
+
+/*
+ * Via devicetree (TODO):
+ * - switch from spread spectrum to class-D switching
+ * - disable edge control
+ * - set BOP settings (the BOP config bits *and* BOP_SRC)
+ */
+
+/*
+ * Other setup TODOs:
+ * - DVC ramp rate
+ */
+
+static const struct tas2764_quirk_init_sequence {
+ const struct reg_sequence *seq;
+ int len;
+} tas2764_quirk_init_sequences[] = {
+ { tas2764_noise_gate_dis_seq, ARRAY_SIZE(tas2764_noise_gate_dis_seq) },
+ { tas2764_dmod_rst_seq, ARRAY_SIZE(tas2764_dmod_rst_seq) },
+ { tas2764_conv_vbat_pvdd_mode_seq, ARRAY_SIZE(tas2764_conv_vbat_pvdd_mode_seq) },
+ { tas2764_unk_seq0, ARRAY_SIZE(tas2764_unk_seq0) },
+ { tas2764_unk_seq1, ARRAY_SIZE(tas2764_unk_seq1) },
+ { tas2764_unk_seq2, ARRAY_SIZE(tas2764_unk_seq2) },
+ { tas2764_thermal_th1_dis_seq, ARRAY_SIZE(tas2764_thermal_th1_dis_seq) },
+ { tas2764_shutdown_dance_init_seq, ARRAY_SIZE(tas2764_shutdown_dance_init_seq) },
+};
+
+#endif /* __TAS2764_QUIRKS__ */
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index a9838e0738cc..36e25e48b354 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -8,14 +8,14 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/hwmon.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
@@ -25,6 +25,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;
@@ -32,7 +37,8 @@ struct tas2764_priv {
struct regmap *regmap;
struct device *dev;
int irq;
-
+ enum tas2764_devid devid;
+
int v_sense_slot;
int i_sense_slot;
@@ -40,6 +46,8 @@ struct tas2764_priv {
bool unmuted;
};
+#include "tas2764-quirks.h"
+
static const char *tas2764_int_ltch0_msgs[8] = {
"fault: over temperature", /* INT_LTCH0 & BIT(0) */
"fault: over current",
@@ -117,6 +125,9 @@ static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764)
else
val = TAS2764_PWR_CTRL_SHUTDOWN;
+ if (ENABLED_APPLE_QUIRKS & TAS2764_SHUTDOWN_DANCE)
+ return tas2764_do_quirky_pwr_ctrl_change(tas2764, val);
+
ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
TAS2764_PWR_CTRL_MASK, val);
if (ret < 0)
@@ -144,6 +155,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;
}
@@ -182,33 +195,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 =
@@ -221,8 +207,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")
@@ -243,9 +228,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)
@@ -367,7 +377,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) {
@@ -376,12 +386,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;
}
@@ -391,6 +403,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;
@@ -528,10 +546,116 @@ 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 const struct regmap_config tas2764_i2c_regmap;
+
+static int tas2764_apply_init_quirks(struct tas2764_priv *tas2764)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(tas2764_quirk_init_sequences); i++) {
+ const struct tas2764_quirk_init_sequence *init_seq =
+ &tas2764_quirk_init_sequences[i];
+
+ if (!init_seq->seq)
+ continue;
+
+ if (!(BIT(i) & ENABLED_APPLE_QUIRKS))
+ continue;
+
+ ret = regmap_multi_reg_write(tas2764->regmap, init_seq->seq,
+ init_seq->len);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tas2764_read_die_temp(struct tas2764_priv *tas2764, long *result)
+{
+ int ret, reg;
+
+ ret = regmap_read(tas2764->regmap, TAS2764_TEMP, &reg);
+ if (ret)
+ return ret;
+ /*
+ * As per datasheet, subtract 93 from raw value to get degrees
+ * Celsius. hwmon wants millidegrees.
+ *
+ * NOTE: The chip will initialise the TAS2764_TEMP register to
+ * 2.6 *C to avoid triggering temperature protection. Since the
+ * ADC is powered down during software shutdown, this value will
+ * persist until the chip is fully powered up (e.g. the PCM it's
+ * attached to is opened). The ADC will power down again when
+ * the chip is put back into software shutdown, with the last
+ * value sampled persisting in the ADC's register.
+ */
+ *result = (reg - 93) * 1000;
+ return 0;
+}
+
+static umode_t tas2764_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 tas2764_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct tas2764_priv *tas2764 = dev_get_drvdata(dev);
+ int ret;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ ret = tas2764_read_die_temp(tas2764, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct hwmon_channel_info *const tas2764_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops tas2764_hwmon_ops = {
+ .is_visible = tas2764_hwmon_is_visible,
+ .read = tas2764_hwmon_read,
+};
+
+static const struct hwmon_chip_info tas2764_hwmon_chip_info = {
+ .ops = &tas2764_hwmon_ops,
+ .info = tas2764_hwmon_info,
+};
+
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;
@@ -541,9 +665,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
}
tas2764_reset(tas2764);
+ regmap_reinit_cache(tas2764->regmap, &tas2764_i2c_regmap);
if (tas2764->irq) {
- ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff);
+ ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0x00);
if (ret < 0)
return ret;
@@ -580,6 +705,34 @@ 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;
+ }
+
+ /* Apply all enabled Apple quirks */
+ ret = tas2764_apply_init_quirks(tas2764);
+
+ if (ret < 0)
+ return ret;
+
+ break;
+ default:
+ break;
+ }
+
return 0;
}
@@ -595,12 +748,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 = {
@@ -628,12 +790,13 @@ 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[] = {
{
.range_min = 0,
- .range_max = 1 * 128,
+ .range_max = 0xffff,
.selector_reg = TAS2764_PAGE,
.selector_mask = 0xff,
.selector_shift = 0,
@@ -645,9 +808,13 @@ 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;
+ case TAS2764_REG(0xf0, 0x0) ... TAS2764_REG(0xff, 0x0):
+ /* TI's undocumented registers for the application of quirks */
+ return true;
default:
return false;
}
@@ -662,7 +829,7 @@ static const struct regmap_config tas2764_i2c_regmap = {
.cache_type = REGCACHE_RBTREE,
.ranges = tas2764_regmap_ranges,
.num_ranges = ARRAY_SIZE(tas2764_regmap_ranges),
- .max_register = 1 * 128,
+ .max_register = 0xffff,
};
static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764)
@@ -709,6 +876,8 @@ static int tas2764_i2c_probe(struct i2c_client *client)
if (!tas2764)
return -ENOMEM;
+ tas2764->devid = (kernel_ulong_t)of_device_get_match_data(&client->dev);
+
tas2764->dev = &client->dev;
tas2764->irq = client->irq;
i2c_set_clientdata(client, tas2764);
@@ -731,6 +900,20 @@ static int tas2764_i2c_probe(struct i2c_client *client)
}
}
+ if (IS_REACHABLE(CONFIG_HWMON)) {
+ struct device *hwmon;
+
+ hwmon = devm_hwmon_device_register_with_info(&client->dev, "tas2764",
+ tas2764,
+ &tas2764_hwmon_chip_info,
+ NULL);
+ if (IS_ERR(hwmon)) {
+ return dev_err_probe(&client->dev, PTR_ERR(hwmon),
+ "Failed to register temp sensor\n");
+ }
+ }
+
+
return devm_snd_soc_register_component(tas2764->dev,
&soc_component_driver_tas2764,
tas2764_dai_driver,
@@ -738,14 +921,15 @@ static int tas2764_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id tas2764_i2c_id[] = {
- { "tas2764", 0},
+ { "tas2764"},
{ }
};
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..538290ed3d92 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)
@@ -106,8 +117,13 @@
#define TAS2764_INT_LTCH3 TAS2764_REG(0x0, 0x50)
#define TAS2764_INT_LTCH4 TAS2764_REG(0x0, 0x51)
+/* Readout Registers */
+#define TAS2764_TEMP TAS2764_REG(0x0, 0x56)
+
/* Clock/IRQ Settings */
#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 99bf402eb566..6f878b01716f 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -12,15 +12,14 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/hwmon.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
@@ -158,11 +157,37 @@ static const struct snd_kcontrol_new isense_switch =
static const struct snd_kcontrol_new vsense_switch =
SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1);
+static int sense_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 tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component);
+
+ /*
+ * Powering up ISENSE/VSENSE requires a trip through the shutdown state.
+ * Do that here to ensure that our changes are applied properly, otherwise
+ * we might end up with non-functional IVSENSE if playback started earlier,
+ * which would break software speaker protection.
+ */
+ switch (event) {
+ case SND_SOC_DAPM_PRE_REG:
+ return snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
+ TAS2770_PWR_CTRL_MASK,
+ TAS2770_PWR_CTRL_SHUTDOWN);
+ case SND_SOC_DAPM_POST_REG:
+ return tas2770_update_pwr_ctrl(tas2770);
+ default:
+ return 0;
+ }
+}
+
static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux),
- SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch),
- SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch),
+ SND_SOC_DAPM_SWITCH_E("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch,
+ sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH_E("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch,
+ sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG),
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUTPUT("OUT"),
@@ -191,6 +216,44 @@ 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_pdm_transmit(struct tas2770_priv *tas2770, int slot)
+{
+ struct snd_soc_component *component = tas2770->component;
+ int ret;
+
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG7,
+ TAS2770_TDM_CFG_REG7_PDM_MASK |
+ TAS2770_TDM_CFG_REG7_50_MASK,
+ TAS2770_TDM_CFG_REG7_PDM_ENABLE |
+ slot);
+ return ret;
+}
+
static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
{
int ret;
@@ -201,19 +264,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:
@@ -223,22 +283,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;
}
@@ -487,12 +531,95 @@ static struct snd_soc_dai_driver tas2770_dai_driver[] = {
},
};
+static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result)
+{
+ int ret = 0;
+ int reading, msb, lsb;
+
+ ret = regmap_read(tas2770->regmap, TAS2770_TEMP_MSB, &msb);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(tas2770->regmap, TAS2770_TEMP_LSB, &lsb);
+ if (ret)
+ return ret;
+
+ reading = (msb << 4) | (lsb >> 4);
+
+ /*
+ * As per datasheet: divide register by 16 and subtract 93 to get
+ * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding
+ * errors by subtracting 93 * 16 then multiplying by 1000 / 16.
+ *
+ * NOTE: The ADC registers are initialised to 0 on reset. This means
+ * that the temperature will read -93 *C until the chip is brought out
+ * of software shutdown (e.g. the PCM it's attached to is opened). The
+ * ADC is also shut down in software shutdown/low-power mode, so the
+ * value read back from its registers will be the last value sampled
+ * before entering software shutdown.
+ */
+ *result = (reading - (93 * 16)) * (1000 / 16);
+ return 0;
+}
+
+static umode_t tas2770_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 tas2770_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct tas2770_priv *tas2770 = dev_get_drvdata(dev);
+ int ret;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ ret = tas2770_read_die_temp(tas2770, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct hwmon_channel_info *const tas2770_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops tas2770_hwmon_ops = {
+ .is_visible = tas2770_hwmon_is_visible,
+ .read = tas2770_hwmon_read,
+};
+
+static const struct hwmon_chip_info tas2770_hwmon_chip_info = {
+ .ops = &tas2770_hwmon_ops,
+ .info = tas2770_hwmon_info,
+};
+
static const struct regmap_config tas2770_i2c_regmap;
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;
@@ -504,11 +631,26 @@ 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;
+ }
+
+ if (tas2770->pdm_slot != -1) {
+ ret = tas2770_set_pdm_transmit(tas2770, tas2770->pdm_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,
@@ -631,7 +773,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",
@@ -640,9 +782,14 @@ 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;
}
+ rc = fwnode_property_read_u32(dev->fwnode, "ti,pdm-slot-no",
+ &tas2770->pdm_slot);
+ if (rc)
+ tas2770->pdm_slot = -1;
+
tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
if (IS_ERR(tas2770->sdz_gpio)) {
if (PTR_ERR(tas2770->sdz_gpio) == -EPROBE_DEFER)
@@ -694,6 +841,19 @@ static int tas2770_i2c_probe(struct i2c_client *client)
}
}
+ if (IS_REACHABLE(CONFIG_HWMON)) {
+ struct device *hwmon;
+
+ hwmon = devm_hwmon_device_register_with_info(&client->dev, "tas2770",
+ tas2770,
+ &tas2770_hwmon_chip_info,
+ NULL);
+ if (IS_ERR(hwmon)) {
+ return dev_err_probe(&client->dev, PTR_ERR(hwmon),
+ "Failed to register temp sensor\n");
+ }
+ }
+
result = tas2770_register_codec(tas2770);
if (result)
dev_err(tas2770->dev, "Register codec failed.\n");
@@ -702,7 +862,7 @@ static int tas2770_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id tas2770_i2c_id[] = {
- { "tas2770", 0},
+ { "tas2770"},
{ }
};
MODULE_DEVICE_TABLE(i2c, tas2770_i2c_id);
diff --git a/sound/soc/codecs/tas2770.h b/sound/soc/codecs/tas2770.h
index f75f40781ab1..3fd2e7003c50 100644
--- a/sound/soc/codecs/tas2770.h
+++ b/sound/soc/codecs/tas2770.h
@@ -77,6 +77,11 @@
#define TAS2770_TDM_CFG_REG6_ISNS_MASK BIT(6)
#define TAS2770_TDM_CFG_REG6_ISNS_ENABLE BIT(6)
#define TAS2770_TDM_CFG_REG6_50_MASK GENMASK(5, 0)
+ /* TDM Configuration Reg10 */
+#define TAS2770_TDM_CFG_REG7 TAS2770_REG(0X0, 0x11)
+#define TAS2770_TDM_CFG_REG7_PDM_MASK BIT(6)
+#define TAS2770_TDM_CFG_REG7_PDM_ENABLE BIT(6)
+#define TAS2770_TDM_CFG_REG7_50_MASK GENMASK(5, 0)
/* Brown Out Prevention Reg0 */
#define TAS2770_BO_PRV_REG0 TAS2770_REG(0X0, 0x1B)
/* Interrupt MASK Reg0 */
@@ -138,6 +143,7 @@ struct tas2770_priv {
struct device *dev;
int v_sense_slot;
int i_sense_slot;
+ int pdm_slot;
bool dac_powered;
bool unmuted;
};
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index 86bd6c18a944..a1963415c931 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -7,11 +7,9 @@
#include <linux/err.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -39,7 +37,7 @@ static void tas2780_reset(struct tas2780_priv *tas2780)
usleep_range(2000, 2050);
}
- snd_soc_component_write(tas2780->component, TAS2780_SW_RST,
+ ret = snd_soc_component_write(tas2780->component, TAS2780_SW_RST,
TAS2780_RST);
if (ret)
dev_err(tas2780->dev, "%s:errCode:0x%x Reset error!\n",
@@ -71,7 +69,7 @@ static int tas2780_codec_resume(struct snd_soc_component *component)
{
struct tas2780_priv *tas2780 =
snd_soc_component_get_drvdata(component);
- int ret = 0;
+ int ret;
ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL,
TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_ACTIVE);
@@ -81,7 +79,6 @@ static int tas2780_codec_resume(struct snd_soc_component *component)
__func__, ret);
goto err;
}
- ret = 0;
regcache_cache_only(tas2780->regmap, false);
ret = regcache_sync(tas2780->regmap);
err:
@@ -627,7 +624,7 @@ static int tas2780_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id tas2780_i2c_id[] = {
- { "tas2780", 0},
+ { "tas2780"},
{ }
};
MODULE_DEVICE_TABLE(i2c, tas2780_i2c_id);
diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c
new file mode 100644
index 000000000000..e24d56a14cfd
--- /dev/null
+++ b/sound/soc/codecs/tas2781-comlib-i2c.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers based on I2C
+//
+// Copyright 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/crc8.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+#include <sound/tas2781-comlib-i2c.h>
+
+static const struct regmap_range_cfg tasdevice_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 256 * 128,
+ .selector_reg = TASDEVICE_PAGE_SELECT,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 128,
+ },
+};
+
+static const struct regmap_config tasdevice_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_NONE,
+ .ranges = tasdevice_ranges,
+ .num_ranges = ARRAY_SIZE(tasdevice_ranges),
+ .max_register = 256 * 128,
+};
+
+static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv,
+ unsigned short chn, int book)
+{
+ struct i2c_client *client = (struct i2c_client *)tas_priv->client;
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
+ struct regmap *map = tas_priv->regmap;
+
+ if (client->addr != tasdev->dev_addr) {
+ client->addr = tasdev->dev_addr;
+ /* All tas2781s share the same regmap, clear the page
+ * inside regmap once switching to another tas2781.
+ * Register 0 at any pages and any books inside tas2781
+ * is the same one for page-switching.
+ */
+ ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d channel:%d\n",
+ __func__, ret, chn);
+ goto out;
+ }
+ }
+
+ if (tasdev->cur_book != book) {
+ ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n",
+ __func__, ret);
+ goto out;
+ }
+ tasdev->cur_book = book;
+ }
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+
+int tasdev_chn_switch(struct tasdevice_priv *tas_priv,
+ unsigned short chn)
+{
+ struct i2c_client *client = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
+ struct regmap *map = tas_priv->regmap;
+ int ret;
+
+ if (client->addr != tasdev->dev_addr) {
+ client->addr = tasdev->dev_addr;
+ /* All devices share the same regmap, clear the page
+ * inside regmap once switching to another device.
+ * Register 0 at any pages and any books inside tas2781
+ * is the same one for page-switching.
+ */
+ ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ return ret;
+ }
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tasdev_chn_switch);
+
+int tasdevice_dev_update_bits(
+ struct tasdevice_priv *tas_priv, unsigned short chn,
+ unsigned int reg, unsigned int mask, unsigned int value)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tas_priv->change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_update_bits(map, TASDEVICE_PGRG(reg),
+ mask, value);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ ret = -EINVAL;
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_update_bits);
+
+struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c)
+{
+ struct tasdevice_priv *tas_priv;
+
+ tas_priv = devm_kzalloc(&i2c->dev, sizeof(*tas_priv), GFP_KERNEL);
+ if (!tas_priv)
+ return NULL;
+ tas_priv->dev = &i2c->dev;
+ tas_priv->client = (void *)i2c;
+
+ return tas_priv;
+}
+EXPORT_SYMBOL_GPL(tasdevice_kzalloc);
+
+int tasdevice_init(struct tasdevice_priv *tas_priv)
+{
+ int ret = 0;
+ int i;
+
+ tas_priv->regmap = devm_regmap_init_i2c(tas_priv->client,
+ &tasdevice_regmap);
+ if (IS_ERR(tas_priv->regmap)) {
+ ret = PTR_ERR(tas_priv->regmap);
+ dev_err(tas_priv->dev, "Failed to allocate register map: %d\n",
+ ret);
+ goto out;
+ }
+
+ tas_priv->cur_prog = -1;
+ tas_priv->cur_conf = -1;
+ tas_priv->isspi = false;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ tas_priv->tasdevice[i].cur_book = -1;
+ tas_priv->tasdevice[i].cur_prog = -1;
+ tas_priv->tasdevice[i].cur_conf = -1;
+ }
+
+ tas_priv->update_bits = tasdevice_dev_update_bits;
+ tas_priv->change_chn_book = tasdevice_change_chn_book;
+ tas_priv->dev_read = tasdevice_dev_read;
+ tas_priv->dev_bulk_read = tasdevice_dev_bulk_read;
+
+ mutex_init(&tas_priv->codec_lock);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_init);
+
+static int tasdevice_clamp(int val, int max, unsigned int invert)
+{
+ if (val > max)
+ val = max;
+ if (invert)
+ val = max - val;
+ if (val < 0)
+ val = 0;
+ return val;
+}
+
+int tasdevice_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 err_cnt = 0;
+ int val, i, ret;
+
+ mask = (1 << fls(max)) - 1;
+ mask <<= mc->shift;
+ val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert);
+ for (i = 0; i < tas_priv->ndev; i++) {
+ ret = tasdevice_dev_update_bits(tas_priv, i,
+ mc->reg, mask, (unsigned int)(val << mc->shift));
+ if (!ret)
+ continue;
+ err_cnt++;
+ dev_err(tas_priv->dev, "set AMP vol error in dev %d\n", i);
+ }
+
+ /* All the devices set error, return 0 */
+ return (err_cnt == tas_priv->ndev) ? 0 : 1;
+}
+EXPORT_SYMBOL_GPL(tasdevice_amp_putvol);
+
+int tasdevice_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 = 0;
+ int val;
+
+ /* Read the primary device */
+ ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ mask = (1 << fls(max)) - 1;
+ mask <<= mc->shift;
+ val = (val & mask) >> mc->shift;
+ val = tasdevice_clamp(val, max, invert);
+ ucontrol->value.integer.value[0] = val;
+
+out:
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(tasdevice_amp_getvol);
+
+int tasdevice_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_dev_read(tas_priv, 0, mc->reg, &val);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s, get digital vol error\n",
+ __func__);
+ goto out;
+ }
+
+ val = tasdevice_clamp(val, max, invert);
+ ucontrol->value.integer.value[0] = val;
+
+out:
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(tasdevice_digital_getvol);
+
+int tasdevice_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 err_cnt = 0;
+ int ret;
+ int val, i;
+
+ val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert);
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ ret = tasdevice_dev_write(tas_priv, i, mc->reg,
+ (unsigned int)val);
+ if (!ret)
+ continue;
+ err_cnt++;
+ dev_err(tas_priv->dev,
+ "set digital vol err in dev %d\n", i);
+ }
+
+ /* All the devices set error, return 0 */
+ return (err_cnt == tas_priv->ndev) ? 0 : 1;
+
+}
+EXPORT_SYMBOL_GPL(tasdevice_digital_putvol);
+
+void tasdevice_reset(struct tasdevice_priv *tas_dev)
+{
+ int ret, i;
+
+ if (tas_dev->reset) {
+ gpiod_set_value_cansleep(tas_dev->reset, 0);
+ usleep_range(500, 1000);
+ gpiod_set_value_cansleep(tas_dev->reset, 1);
+ } else {
+ for (i = 0; i < tas_dev->ndev; i++) {
+ ret = tasdevice_dev_write(tas_dev, i,
+ TASDEVICE_REG_SWRESET,
+ tas_dev->chip_id >= TAS5802 ?
+ TAS5825_REG_SWRESET_RESET :
+ TASDEVICE_REG_SWRESET_RESET);
+ if (ret < 0)
+ dev_err(tas_dev->dev,
+ "dev %d swreset fail, %d\n",
+ i, ret);
+ }
+ }
+ usleep_range(1000, 1050);
+}
+EXPORT_SYMBOL_GPL(tasdevice_reset);
+
+int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
+ struct module *module,
+ void (*cont)(const struct firmware *fw, void *context))
+{
+ int ret = 0;
+
+ /* Codec Lock Hold to ensure that codec_probe and firmware parsing and
+ * loading do not simultaneously execute.
+ */
+ mutex_lock(&tas_priv->codec_lock);
+
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
+ tas_priv->name_prefix, tas_priv->dev_name,
+ tas_priv->ndev);
+ else
+ scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
+ tas_priv->dev_name, tas_priv->ndev);
+ 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);
+
+ /* Codec Lock Release*/
+ mutex_unlock(&tas_priv->codec_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tascodec_init);
+
+MODULE_DESCRIPTION("TAS2781 common library for I2C");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2781-comlib.c b/sound/soc/codecs/tas2781-comlib.c
new file mode 100644
index 000000000000..4cec9f8a00af
--- /dev/null
+++ b/sound/soc/codecs/tas2781-comlib.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers
+//
+// Copyright 2023 - 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/crc8.h>
+#include <linux/dev_printk.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/tas2781.h>
+
+int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned int *val)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tas_priv->change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_read(map, TASDEVICE_PGRG(reg), val);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_read);
+
+int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tas_priv->change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read);
+
+int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
+ unsigned short chn, unsigned int reg, unsigned int value)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tas_priv->change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_write(map, TASDEVICE_PGRG(reg),
+ value);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_write);
+
+int tasdevice_dev_bulk_write(
+ struct tasdevice_priv *tas_priv, unsigned short chn,
+ unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ int ret = 0;
+
+ if (chn < tas_priv->ndev) {
+ struct regmap *map = tas_priv->regmap;
+
+ ret = tas_priv->change_chn_book(tas_priv, chn,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_bulk_write(map, TASDEVICE_PGRG(reg),
+ data, len);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
+ chn);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_write);
+
+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);
+}
+
+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);
+}
+
+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);
+ }
+}
+
+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);
+}
+
+void tasdevice_dsp_remove(void *context)
+{
+ struct tasdevice_priv *tas_dev = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_dev->fmw;
+
+ if (!tas_dev->fmw)
+ return;
+
+ if (tas_fmw->programs)
+ tasdev_dsp_prog_remove(tas_fmw->programs,
+ tas_fmw->nr_programs);
+ if (tas_fmw->configs)
+ tasdev_dsp_cfg_remove(tas_fmw->configs,
+ tas_fmw->nr_configurations);
+ kfree(tas_fmw);
+ tas_dev->fmw = NULL;
+}
+EXPORT_SYMBOL_GPL(tasdevice_dsp_remove);
+
+void tasdevice_remove(struct tasdevice_priv *tas_priv)
+{
+ mutex_destroy(&tas_priv->codec_lock);
+}
+EXPORT_SYMBOL_GPL(tasdevice_remove);
+
+MODULE_DESCRIPTION("TAS2781 common library");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
new file mode 100644
index 000000000000..78fd0a5dc6f2
--- /dev/null
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -0,0 +1,2618 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// tas2781-fmwlib.c -- TASDEVICE firmware support
+//
+// 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>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/tas2781.h>
+#include <linux/unaligned.h>
+
+#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_CMD_SING_W 0x1
+#define TASDEVICE_CMD_BURST 0x2
+#define TASDEVICE_CMD_DELAY 0x3
+#define TASDEVICE_CMD_FIELD_W 0x4
+
+#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;
+};
+
+static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
+ 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2
+};
+
+/* 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, 0xC1 },
+ { PRE_DEVICE_A_1X, 0xC1 },
+ { PRE_SOFTWARE_RESET_DEVICE_A, 0xC1 },
+ { POST_SOFTWARE_RESET_DEVICE_A, 0xC1 },
+ { MAIN_DEVICE_B_1X, 0x82 },
+ { COEFF_DEVICE_B_1X, 0xC2 },
+ { PRE_DEVICE_B_1X, 0xC2 },
+ { PRE_SOFTWARE_RESET_DEVICE_B, 0xC2 },
+ { POST_SOFTWARE_RESET_DEVICE_B, 0xC2 },
+ { MAIN_DEVICE_C_1X, 0x83 },
+ { COEFF_DEVICE_C_1X, 0xC3 },
+ { PRE_DEVICE_C_1X, 0xC3 },
+ { PRE_SOFTWARE_RESET_DEVICE_C, 0xC3 },
+ { POST_SOFTWARE_RESET_DEVICE_C, 0xC3 },
+ { MAIN_DEVICE_D_1X, 0x84 },
+ { COEFF_DEVICE_D_1X, 0xC4 },
+ { PRE_DEVICE_D_1X, 0xC4 },
+ { 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 },
+};
+
+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(struct tasdevice_config_info), GFP_KERNEL);
+ if (!cfg_info) {
+ *status = -ENOMEM;
+ goto out;
+ }
+
+ if (tas_priv->rcabin.fw_hdr.binary_version_num >= 0x105) {
+ if (config_offset + 64 > (int)config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev, "add conf: Out of boundary\n");
+ goto out;
+ }
+ /* If in the RCA bin file are several profiles with the
+ * keyword "init", init_profile_id only store the last
+ * init profile id.
+ */
+ if (strnstr(&config_data[config_offset], "init", 64)) {
+ tas_priv->rcabin.init_profile_id =
+ tas_priv->rcabin.ncfgs - 1;
+ dev_dbg(tas_priv->dev, "%s: init profile id = %d\n",
+ __func__, tas_priv->rcabin.init_profile_id);
+ }
+ config_offset += 64;
+ }
+
+ if (config_offset + 4 > (int)config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev, "add config: Out of boundary\n");
+ goto out;
+ }
+
+ /* 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(struct tasdev_blk_data *), GFP_KERNEL);
+ if (!bk_da) {
+ *status = -ENOMEM;
+ goto out;
+ }
+ 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);
+ break;
+ }
+ bk_da[i] = kzalloc(sizeof(struct tasdev_blk_data), GFP_KERNEL);
+ if (!bk_da[i]) {
+ *status = -ENOMEM;
+ break;
+ }
+
+ bk_da[i]->dev_idx = config_data[config_offset];
+ config_offset++;
+
+ bk_da[i]->block_type = config_data[config_offset];
+ config_offset++;
+
+ if (bk_da[i]->block_type == TASDEVICE_BIN_BLK_PRE_POWER_UP) {
+ if (bk_da[i]->dev_idx == 0)
+ cfg_info->active_dev =
+ (1 << tas_priv->ndev) - 1;
+ else
+ cfg_info->active_dev |= 1 <<
+ (bk_da[i]->dev_idx - 1);
+
+ }
+ 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);
+ break;
+ }
+ /* 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;
+ goto out;
+ }
+
+ config_offset += bk_da[i]->block_size;
+ cfg_info->real_nblocks += 1;
+ }
+
+out:
+ return cfg_info;
+}
+
+int tasdevice_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;
+ unsigned char *buf;
+ int offset = 0;
+ int ret = 0;
+ int i;
+
+ rca = &(tas_priv->rcabin);
+ /* Initialize to none */
+ rca->init_profile_id = -1;
+ 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;
+ ret = -EINVAL;
+ goto out;
+ }
+ 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;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ 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;
+ ret = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]);
+ offset += 8;
+ fw_hdr->plat_type = buf[offset];
+ offset += 1;
+ fw_hdr->dev_family = buf[offset];
+ offset += 1;
+ fw_hdr->reserve = buf[offset];
+ offset += 1;
+ fw_hdr->ndev = buf[offset];
+ offset += 1;
+ if (fw_hdr->ndev != tas_priv->ndev) {
+ dev_err(tas_priv->dev,
+ "ndev(%u) in rcabin mismatch ndev(%u) in DTS\n",
+ fw_hdr->ndev, tas_priv->ndev);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ ret = -EINVAL;
+ goto out;
+ }
+ if (offset + TASDEVICE_DEVICE_SUM > fw_hdr->img_sz) {
+ dev_err(tas_priv->dev, "rca_ready: Out of boundary!\n");
+ ret = -EINVAL;
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+
+ 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 error!\n");
+ ret = -EINVAL;
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+
+ cfg_info = kcalloc(fw_hdr->nconfig, sizeof(*cfg_info), GFP_KERNEL);
+ if (!cfg_info) {
+ ret = -ENOMEM;
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+ 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;
+ goto out;
+ }
+ offset += (int)fw_hdr->config_size[i];
+ }
+out:
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, "SND_SOC_TAS2781_FMWLIB");
+
+/* 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;
+}
+
+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__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ /* 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];
+ offset++;
+
+ block->pchksum = data[offset];
+ offset++;
+
+ block->is_ychksum_present = data[offset];
+ offset++;
+
+ block->ychksum = data[offset];
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ /* instead of kzalloc+memcpy */
+ block->data = kmemdup(&data[offset], block->blk_size, GFP_KERNEL);
+ if (!block->data) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ offset += block->blk_size;
+
+out:
+ return offset;
+}
+
+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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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) {
+ offset = -ENOMEM;
+ goto out;
+ }
+
+ 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) {
+ offset = -EINVAL;
+ break;
+ }
+ }
+
+out:
+ return offset;
+}
+
+static int fw_parse_tas5825_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 65 unused byts*/
+ offset += 65;
+ offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ return offset;
+ }
+
+ return offset;
+}
+
+static int fw_parse_tas5825_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 8 bytes*/
+ offset += 72;
+ offset = fw_parse_data_kernel(tas_fmw, &(config->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ return offset;
+ }
+
+ return offset;
+}
+
+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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ /*skip 72 unused byts*/
+ offset += 72;
+
+ offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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)
+ goto out;
+ }
+
+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)
+{
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr);
+ struct tasdevice_prog *program;
+ struct tasdevice_config *config;
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 2;
+ fw_hdr->ndev = deviceNumber[fw_hdr->device];
+
+ if (fw_hdr->ndev != tas_priv->ndev) {
+ dev_err(tas_priv->dev,
+ "%s: ndev(%u) in dspbin mismatch ndev(%u) in DTS\n",
+ __func__, fw_hdr->ndev, tas_priv->ndev);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ 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");
+ offset = -EINVAL;
+ goto out;
+ }
+
+ tas_fmw->programs = kcalloc(tas_fmw->nr_programs,
+ sizeof(struct tasdevice_prog), GFP_KERNEL);
+ if (!tas_fmw->programs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+
+ 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 = (fw_hdr->ndev >= 4) ?
+ TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS :
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ if (offset + 4 * max_confs > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpConfigurations err\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ tas_fmw->configs = kcalloc(tas_fmw->nr_configurations,
+ sizeof(struct tasdevice_config), GFP_KERNEL);
+ if (!tas_fmw->configs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+
+ 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);
+
+out:
+ return offset;
+}
+
+static int tasdevice_process_block(void *context, unsigned char *data,
+ unsigned char dev_idx, int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
+ int subblk_offset, chn, chnend, rc;
+ unsigned char subblk_typ = data[1];
+ int blktyp = dev_idx & 0xC0;
+ int idx = dev_idx & 0x3F;
+ bool is_err = false;
+
+ if (idx) {
+ chn = idx - 1;
+ chnend = idx;
+ } else {
+ if (tas_priv->isspi) {
+ chn = tas_priv->index;
+ chnend = chn + 1;
+ } else {
+ chn = 0;
+ chnend = tas_priv->ndev;
+ }
+ }
+
+ for (; chn < chnend; chn++) {
+ if (tas_priv->tasdevice[chn].is_loading == false)
+ continue;
+
+ is_err = false;
+ subblk_offset = 2;
+ switch (subblk_typ) {
+ case TASDEVICE_CMD_SING_W: {
+ int i;
+ unsigned short len = get_unaligned_be16(&data[2]);
+
+ subblk_offset += 2;
+ if (subblk_offset + 4 * len > sublocksize) {
+ dev_err(tas_priv->dev,
+ "process_block: Out of boundary\n");
+ is_err = true;
+ break;
+ }
+
+ for (i = 0; i < len; i++) {
+ rc = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_REG(data[subblk_offset],
+ data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ data[subblk_offset + 3]);
+ if (rc < 0) {
+ is_err = true;
+ dev_err(tas_priv->dev,
+ "process_block: single write error\n");
+ }
+ subblk_offset += 4;
+ }
+ }
+ break;
+ case TASDEVICE_CMD_BURST: {
+ unsigned short len = get_unaligned_be16(&data[2]);
+
+ subblk_offset += 2;
+ if (subblk_offset + 4 + len > sublocksize) {
+ dev_err(tas_priv->dev,
+ "%s: BST Out of boundary\n",
+ __func__);
+ is_err = true;
+ break;
+ }
+ if (len % 4) {
+ dev_err(tas_priv->dev,
+ "%s:Bst-len(%u)not div by 4\n",
+ __func__, len);
+ break;
+ }
+
+ rc = tasdevice_dev_bulk_write(tas_priv, chn,
+ TASDEVICE_REG(data[subblk_offset],
+ data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ &(data[subblk_offset + 4]), len);
+ if (rc < 0) {
+ is_err = true;
+ dev_err(tas_priv->dev,
+ "%s: bulk_write error = %d\n",
+ __func__, rc);
+ }
+ subblk_offset += (len + 4);
+ }
+ break;
+ case TASDEVICE_CMD_DELAY: {
+ unsigned int sleep_time = 0;
+
+ if (subblk_offset + 2 > sublocksize) {
+ dev_err(tas_priv->dev,
+ "%s: delay Out of boundary\n",
+ __func__);
+ is_err = true;
+ break;
+ }
+ sleep_time = get_unaligned_be16(&data[2]) * 1000;
+ usleep_range(sleep_time, sleep_time + 50);
+ subblk_offset += 2;
+ }
+ break;
+ case TASDEVICE_CMD_FIELD_W:
+ if (subblk_offset + 6 > sublocksize) {
+ dev_err(tas_priv->dev,
+ "%s: bit write Out of boundary\n",
+ __func__);
+ is_err = true;
+ break;
+ }
+ rc = tas_priv->update_bits(tas_priv, chn,
+ 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) {
+ is_err = true;
+ dev_err(tas_priv->dev,
+ "%s: update_bits error = %d\n",
+ __func__, rc);
+ }
+ subblk_offset += 6;
+ break;
+ default:
+ break;
+ }
+ if (is_err == true && blktyp != 0) {
+ if (blktyp == 0x80) {
+ tas_priv->tasdevice[chn].cur_prog = -1;
+ tas_priv->tasdevice[chn].cur_conf = -1;
+ } else
+ tas_priv->tasdevice[chn].cur_conf = -1;
+ }
+ }
+
+ return subblk_offset;
+}
+
+void tasdevice_select_cfg_blk(void *pContext, int conf_no,
+ unsigned char block_type)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) pContext;
+ struct tasdevice_rca *rca = &(tas_priv->rcabin);
+ struct tasdevice_config_info **cfg_info = rca->cfg_info;
+ struct tasdev_blk_data **blk_data;
+ int j, k, chn, chnend;
+
+ 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 < (int)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 < (int)blk_data[j]->n_subblks; k++) {
+ if (blk_data[j]->dev_idx) {
+ chn = blk_data[j]->dev_idx - 1;
+ chnend = blk_data[j]->dev_idx;
+ } else {
+ chn = 0;
+ chnend = tas_priv->ndev;
+ }
+ for (; chn < chnend; chn++)
+ tas_priv->tasdevice[chn].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);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_select_cfg_blk, "SND_SOC_TAS2781_FMWLIB");
+
+static int tasdevice_load_block_kernel(
+ struct tasdevice_priv *tasdevice, struct tasdev_blk *block)
+{
+ const unsigned int blk_size = block->blk_size;
+ unsigned int i, length;
+ unsigned char *data = block->data;
+
+ 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);
+ break;
+ }
+ length += (unsigned int)rc;
+ if (blk_size < length) {
+ dev_err(tasdevice->dev, "%s: %u %u out of boundary\n",
+ __func__, length, blk_size);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+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__);
+ offset = -EINVAL;
+ goto out;
+ }
+
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_hdr->ndev = deviceNumber[fw_hdr->device];
+
+out:
+ return offset;
+}
+
+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);
+ if (offset < 0)
+ goto out;
+ if (fw_hdr->ndev != tas_priv->ndev) {
+ dev_err(tas_priv->dev,
+ "%s: ndev(%u) in dspbin mismatch ndev(%u) in DTS\n",
+ __func__, fw_hdr->ndev, tas_priv->ndev);
+ offset = -EINVAL;
+ }
+
+out:
+ return offset;
+}
+
+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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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");
+ offset = -EINVAL;
+ goto out;
+ }
+ 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);
+ offset = -EINVAL;
+ goto out;
+ }
+ /* instead of kzalloc+memcpy */
+ block->data = kmemdup(&data[offset], n, GFP_KERNEL);
+ if (!block->data) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ offset += n;
+
+out:
+ 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;
+ int n;
+
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Name error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += n;
+ img_data->nr_blk = get_unaligned_be16(&data[offset]);
+ offset += 2;
+
+ img_data->dev_blks = kcalloc(img_data->nr_blk,
+ sizeof(struct tasdev_blk), GFP_KERNEL);
+ if (!img_data->dev_blks) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ 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) {
+ offset = -EINVAL;
+ goto out;
+ }
+ }
+
+out:
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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_info(tas_priv->dev, "%s: No Programs data, maybe calbin\n",
+ __func__);
+ goto out;
+ }
+
+ tas_fmw->programs =
+ kcalloc(tas_fmw->nr_programs, sizeof(struct tasdevice_prog),
+ GFP_KERNEL);
+ if (!tas_fmw->programs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ 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__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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");
+ offset = -EINVAL;
+ goto out;
+ }
+
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &(program->dev_data), fmw,
+ offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ 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;
+ int n;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ 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*/
+ goto out;
+ }
+ tas_fmw->configs = kcalloc(tas_fmw->nr_configurations,
+ sizeof(struct tasdevice_config), GFP_KERNEL);
+ if (!tas_fmw->configs) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ 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");
+ offset = -EINVAL;
+ goto out;
+ }
+ 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");
+ offset = -EINVAL;
+ goto out;
+ }
+
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &(config->dev_data),
+ fmw, offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+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;
+}
+
+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);
+ goto end;
+ }
+ if (book == TAS2781_YRAM_BOOK2 && page == TAS2781_YRAM5_PAGE)
+ in = check_inpage_yram_rg(cd, reg, len);
+
+end:
+ return in;
+}
+
+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;
+}
+
+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)
+ goto end;
+ in = check_inblock_yram(cd, book, page, reg, len);
+
+end:
+ return in;
+}
+
+static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice,
+ unsigned short chn, 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;
+ int 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_PAGE_REG(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->dev_bulk_read(tasdevice, chn,
+ 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_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG))
+ && ((i + crc_data.offset)
+ <= (TASDEVICE_PAGE_REG(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;
+}
+
+static int do_singlereg_checksum(struct tasdevice_priv *tasdevice,
+ unsigned short chl, 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;
+
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG))
+ && (reg >= TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG))
+ && (reg <= (TASDEVICE_PAGE_REG(
+ TAS2781_SA_COEFF_SWAP_REG) + 4))) {
+ /*DSP swap command, pass */
+ ret = 0;
+ goto end;
+ }
+
+ in = check_yram(&crc_data, book, page, reg, 1);
+ if (!in)
+ goto end;
+ ret = tasdevice->dev_read(tasdevice, chl,
+ TASDEVICE_REG(book, page, reg), &nData1);
+ if (ret < 0)
+ goto end;
+
+ 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->tasdevice[chl].err_code |= ERROR_YRAM_CRCCHK;
+ ret = -EAGAIN;
+ goto end;
+ }
+
+ ret = crc8(tasdevice->crc8_lkp_tbl, &val, 1, 0);
+
+end:
+ return ret;
+}
+
+static void set_err_prg_cfg(unsigned int type, struct tasdevice *dev)
+{
+ if ((type == MAIN_ALL_DEVICES) || (type == MAIN_DEVICE_A)
+ || (type == MAIN_DEVICE_B) || (type == MAIN_DEVICE_C)
+ || (type == MAIN_DEVICE_D))
+ dev->cur_prog = -1;
+ else
+ dev->cur_conf = -1;
+}
+
+static int tasdev_bytes_chksum(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn, 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, chn, book, page, reg,
+ len);
+ else
+ ret = do_singlereg_checksum(tas_priv, chn, book, page, reg,
+ val);
+
+ if (ret > 0) {
+ *crc_chksum += (unsigned char)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->tasdevice[chn]);
+
+end:
+ return ret;
+}
+
+static int tasdev_multibytes_wr(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn, 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_dev_bulk_write(tas_priv, chn,
+ TASDEVICE_REG(book, page, reg), data + 3, len);
+ if (ret < 0)
+ goto end;
+ if (block->is_ychksum_present)
+ ret = tasdev_bytes_chksum(tas_priv, block, chn,
+ book, page, reg, len, 0, crc_chksum);
+ } else {
+ ret = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_REG(book, page, reg), data[3]);
+ if (ret < 0)
+ goto end;
+ if (block->is_ychksum_present)
+ ret = tasdev_bytes_chksum(tas_priv, block, chn, 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;
+ }
+
+end:
+ return ret;
+}
+
+static int tasdev_block_chksum(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn)
+{
+ unsigned int nr_value;
+ int ret;
+
+ ret = tas_priv->dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG,
+ &nr_value);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s: Chn %d\n", __func__, chn);
+ set_err_prg_cfg(block->type, &tas_priv->tasdevice[chn]);
+ goto end;
+ }
+
+ if ((nr_value & 0xff) != block->pchksum) {
+ dev_err(tas_priv->dev, "%s: Blk PChkSum Chn %d ", __func__,
+ chn);
+ dev_err(tas_priv->dev, "PChkSum = 0x%x, Reg = 0x%x\n",
+ block->pchksum, (nr_value & 0xff));
+ tas_priv->tasdevice[chn].err_code |= ERROR_PRAM_CRCCHK;
+ ret = -EAGAIN;
+ block->nr_retry--;
+
+ if (block->nr_retry <= 0)
+ set_err_prg_cfg(block->type,
+ &tas_priv->tasdevice[chn]);
+ } else
+ tas_priv->tasdevice[chn].err_code &= ~ERROR_PRAM_CRCCHK;
+
+end:
+ return ret;
+}
+
+static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, int chn)
+{
+ unsigned int sleep_time;
+ unsigned int len;
+ unsigned int nr_cmds;
+ unsigned char *data;
+ unsigned char crc_chksum = 0;
+ unsigned char offset;
+ unsigned char book;
+ unsigned char page;
+ unsigned char val;
+ int ret = 0;
+
+ while (block->nr_retry > 0) {
+ if (block->is_pchksum_present) {
+ ret = tasdevice_dev_write(tas_priv, chn,
+ TASDEVICE_CHECKSUM_REG, 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_dev_write(tas_priv, chn,
+ TASDEVICE_REG(book, page, offset),
+ val);
+ if (ret < 0)
+ goto end;
+ if (block->is_ychksum_present) {
+ ret = tasdev_bytes_chksum(tas_priv,
+ block, chn, 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;
+ usleep_range(sleep_time, sleep_time + 50);
+ 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, chn, 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, chn);
+ 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->tasdevice[chn].err_code &=
+ ~ERROR_YRAM_CRCCHK;
+ ret = 0;
+ }
+ /*skip current blk*/
+ break;
+ }
+
+end:
+ return ret;
+}
+
+static int tasdevice_load_block(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block)
+{
+ int chnend = 0;
+ int ret = 0;
+ int chn = 0;
+ int rc = 0;
+
+ switch (block->type) {
+ case MAIN_ALL_DEVICES:
+ chn = 0;
+ chnend = tas_priv->ndev;
+ break;
+ case MAIN_DEVICE_A:
+ case COEFF_DEVICE_A:
+ case PRE_DEVICE_A:
+ chn = 0;
+ chnend = 1;
+ break;
+ case MAIN_DEVICE_B:
+ case COEFF_DEVICE_B:
+ case PRE_DEVICE_B:
+ chn = 1;
+ chnend = 2;
+ break;
+ case MAIN_DEVICE_C:
+ case COEFF_DEVICE_C:
+ case PRE_DEVICE_C:
+ chn = 2;
+ chnend = 3;
+ break;
+ case MAIN_DEVICE_D:
+ case COEFF_DEVICE_D:
+ case PRE_DEVICE_D:
+ chn = 3;
+ chnend = 4;
+ break;
+ default:
+ dev_dbg(tas_priv->dev, "load blk: Other Type = 0x%02x\n",
+ block->type);
+ break;
+ }
+
+ for (; chn < chnend; chn++) {
+ block->nr_retry = 6;
+ if (tas_priv->tasdevice[chn].is_loading == false)
+ continue;
+ ret = tasdev_load_blk(tas_priv, block, chn);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "dev %d, Blk (%d) load error\n",
+ chn, block->type);
+ rc |= ret;
+ }
+
+ 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) &&
+ (ppcver < PPC3_VERSION_TAS5825_BASE))
+ 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_TAS5825_BASE) {
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_kernel;
+ tas_priv->fw_parse_program_data =
+ fw_parse_tas5825_program_data_kernel;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_tas5825_configuration_data_kernel;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block_kernel;
+ dspbin_type_check(tas_priv, ppcver);
+ } else 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;
+ dspbin_type_check(tas_priv, ppcver);
+ } else {
+ switch (ppcver) {
+ case 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;
+ break;
+ default:
+ dev_err(tas_priv->dev,
+ "%s: PPCVer must be 0x0 or 0x%02x",
+ __func__, PPC3_VERSION_BASE);
+ dev_err(tas_priv->dev, " Current:0x%02x\n",
+ ppcver);
+ rc = -EINVAL;
+ break;
+ }
+ }
+ } else {
+ dev_err(tas_priv->dev,
+ "DrvVer must be 0x0, 0x230 or above 0x230 ");
+ dev_err(tas_priv->dev, "current is 0x%02x\n", drv_ver);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int load_calib_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 = tasdevice_load_block(tas_priv, block);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+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;
+}
+
+static int fw_parse_variable_hdr_cal(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);
+
+ offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset);
+ if (offset < 0)
+ goto out;
+ if (fw_hdr->ndev != 1) {
+ dev_err(tas_priv->dev,
+ "%s: calbin must be 1, but currently ndev(%u)\n",
+ __func__, fw_hdr->ndev);
+ offset = -EINVAL;
+ }
+
+out:
+ return offset;
+}
+
+/* When calibrated data parsing error occurs, DSP can still work with default
+ * calibrated data, memory resource related to calibrated data will be
+ * released in the tasdevice_codec_remove.
+ */
+static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_calibration *calibration;
+ unsigned char *data = (unsigned char *)fmw->data;
+ unsigned int i, n;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: Calibrations error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ tas_fmw->nr_calibrations = get_unaligned_be16(&data[offset]);
+ offset += 2;
+
+ if (tas_fmw->nr_calibrations != 1) {
+ dev_err(tas_priv->dev,
+ "%s: only supports one calibration (%d)!\n",
+ __func__, tas_fmw->nr_calibrations);
+ goto out;
+ }
+
+ tas_fmw->calibrations = kcalloc(tas_fmw->nr_calibrations,
+ sizeof(struct tasdevice_calibration), GFP_KERNEL);
+ if (!tas_fmw->calibrations) {
+ offset = -ENOMEM;
+ goto out;
+ }
+ for (i = 0; i < tas_fmw->nr_calibrations; i++) {
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_priv->dev, "Calibrations error\n");
+ offset = -EINVAL;
+ goto out;
+ }
+ calibration = &(tas_fmw->calibrations[i]);
+ offset += 64;
+
+ n = strlen((char *)&data[offset]);
+ /* skip '\0' and 2 unused bytes */
+ n += 3;
+ if (offset + n > fmw->size) {
+ dev_err(tas_priv->dev, "Description err\n");
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &(calibration->dev_data), fmw,
+ offset);
+ if (offset < 0)
+ goto out;
+ }
+
+out:
+ return offset;
+}
+
+int tas2781_load_calibration(void *context, char *file_name,
+ unsigned short i)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
+ struct tasdevice *tasdev = &(tas_priv->tasdevice[i]);
+ const struct firmware *fw_entry = NULL;
+ struct tasdevice_fw *tas_fmw;
+ struct firmware fmw;
+ int offset = 0;
+ int ret;
+
+ ret = request_firmware(&fw_entry, file_name, tas_priv->dev);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s: Request firmware %s failed\n",
+ __func__, file_name);
+ goto out;
+ }
+
+ if (!fw_entry->size) {
+ dev_err(tas_priv->dev, "%s: file read error: size = %lu\n",
+ __func__, (unsigned long)fw_entry->size);
+ ret = -EINVAL;
+ goto out;
+ }
+ fmw.size = fw_entry->size;
+ fmw.data = fw_entry->data;
+
+ tas_fmw = tasdev->cali_data_fmw = kzalloc(sizeof(struct tasdevice_fw),
+ GFP_KERNEL);
+ if (!tasdev->cali_data_fmw) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ tas_fmw->dev = tas_priv->dev;
+ offset = fw_parse_header(tas_priv, tas_fmw, &fmw, offset);
+ if (offset == -EINVAL) {
+ dev_err(tas_priv->dev, "fw_parse_header EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, &fmw, offset);
+ if (offset == -EINVAL) {
+ dev_err(tas_priv->dev,
+ "%s: fw_parse_variable_header_cal EXIT!\n", __func__);
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_program_data(tas_priv, tas_fmw, &fmw, offset);
+ if (offset < 0) {
+ dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_configuration_data(tas_priv, tas_fmw, &fmw, offset);
+ if (offset < 0) {
+ dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+ offset = fw_parse_calibration_data(tas_priv, tas_fmw, &fmw, offset);
+ if (offset < 0) {
+ dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n");
+ ret = offset;
+ goto out;
+ }
+
+out:
+ release_firmware(fw_entry);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB");
+
+static int tasdevice_dspfw_ready(const struct firmware *fmw,
+ void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr;
+ struct tasdevice_fw *tas_fmw;
+ int offset = 0;
+ int ret;
+
+ 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(struct tasdevice_fw), 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:
+ case 0x401:
+ 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)
+ return offset;
+
+ 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)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_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);
+ goto out;
+ }
+
+ ret = tasdevice_dspfw_ready(fw_entry, tas_priv);
+ release_firmware(fw_entry);
+ fw_entry = NULL;
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB");
+
+static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw)
+{
+ struct tasdevice_calibration *calibration;
+ struct tasdev_blk *block;
+ struct tasdevice_data *im;
+ 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;
+
+ im = &(calibration->dev_data);
+
+ if (!im->dev_blks)
+ continue;
+
+ for (blks = 0; blks < im->nr_blk; blks++) {
+ block = &(im->dev_blks[blks]);
+ if (!block)
+ continue;
+ kfree(block->data);
+ }
+ kfree(im->dev_blks);
+ }
+ kfree(tas_fmw->calibrations);
+out:
+ kfree(tas_fmw);
+}
+
+void tasdevice_calbin_remove(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice *tasdev;
+ int i;
+
+ if (!tas_priv)
+ return;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ tasdev = &(tas_priv->tasdevice[i]);
+ if (!tasdev->cali_data_fmw)
+ continue;
+ tas2781_clear_calfirmware(tasdev->cali_data_fmw);
+ tasdev->cali_data_fmw = NULL;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, "SND_SOC_TAS2781_FMWLIB");
+
+void tasdevice_config_info_remove(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_rca *rca = &(tas_priv->rcabin);
+ struct tasdevice_config_info **ci = rca->cfg_info;
+ 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 < (int)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);
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_info_remove, "SND_SOC_TAS2781_FMWLIB");
+
+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;
+}
+
+static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
+{
+ struct tasdevice_fw *cal_fmw = priv->tasdevice[i].cali_data_fmw;
+ struct calidata *cali_data = &priv->cali_data;
+ struct cali_reg *p = &cali_data->cali_reg_array;
+ unsigned char *data = cali_data->data;
+ struct tasdevice_calibration *cal;
+ int k = i * (cali_data->cali_dat_sz_per_dev + 1);
+ int rc;
+
+ /* Load the calibrated data from cal bin file */
+ if (!priv->is_user_space_calidata && cal_fmw) {
+ cal = cal_fmw->calibrations;
+
+ if (cal)
+ load_calib_data(priv, &cal->dev_data);
+ return;
+ }
+ if (!priv->is_user_space_calidata)
+ return;
+ /* load calibrated data from user space */
+ if (data[k] != i) {
+ dev_err(priv->dev, "%s: no cal-data for dev %d from usr-spc\n",
+ __func__, i);
+ return;
+ }
+ k++;
+
+ rc = tasdevice_dev_bulk_write(priv, i, p->r0_reg, &(data[k]), 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d r0_reg bulk_wr err = %d\n", i, rc);
+ return;
+ }
+ k += 4;
+ rc = tasdevice_dev_bulk_write(priv, i, p->r0_low_reg, &(data[k]), 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d r0_low_reg err = %d\n", i, rc);
+ return;
+ }
+ k += 4;
+ rc = tasdevice_dev_bulk_write(priv, i, p->invr0_reg, &(data[k]), 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d invr0_reg err = %d\n", i, rc);
+ return;
+ }
+ k += 4;
+ rc = tasdevice_dev_bulk_write(priv, i, p->pow_reg, &(data[k]), 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d pow_reg bulk_wr err = %d\n", i, rc);
+ return;
+ }
+ k += 4;
+ rc = tasdevice_dev_bulk_write(priv, i, p->tlimit_reg, &(data[k]), 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d tlimit_reg err = %d\n", i, rc);
+ return;
+ }
+}
+
+int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
+ int cfg_no, int rca_conf_no)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_rca *rca = &(tas_priv->rcabin);
+ struct tasdevice_config_info **cfg_info = rca->cfg_info;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_prog *program;
+ struct tasdevice_config *conf;
+ int prog_status = 0;
+ int status, i;
+
+ if (!tas_fmw) {
+ dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__);
+ goto out;
+ }
+
+ if (cfg_no >= tas_fmw->nr_configurations) {
+ dev_err(tas_priv->dev,
+ "%s: cfg(%d) is not in range of conf %u\n",
+ __func__, cfg_no, tas_fmw->nr_configurations);
+ goto out;
+ }
+
+ if (prm_no >= tas_fmw->nr_programs) {
+ dev_err(tas_priv->dev,
+ "%s: prm(%d) is not in range of Programs %u\n",
+ __func__, prm_no, tas_fmw->nr_programs);
+ goto out;
+ }
+
+ if (rca_conf_no >= rca->ncfgs || rca_conf_no < 0 ||
+ !cfg_info) {
+ dev_err(tas_priv->dev,
+ "conf_no:%d should be in range from 0 to %u\n",
+ rca_conf_no, rca->ncfgs-1);
+ goto out;
+ }
+
+ for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
+ if (cfg_info[rca_conf_no]->active_dev & (1 << i)) {
+ if (prm_no >= 0
+ && (tas_priv->tasdevice[i].cur_prog != prm_no
+ || tas_priv->force_fwload_status)) {
+ tas_priv->tasdevice[i].cur_conf = -1;
+ tas_priv->tasdevice[i].is_loading = true;
+ prog_status++;
+ }
+ } else
+ tas_priv->tasdevice[i].is_loading = false;
+ tas_priv->tasdevice[i].is_loaderr = false;
+ }
+
+ if (prog_status) {
+ program = &(tas_fmw->programs[prm_no]);
+ tasdevice_load_data(tas_priv, &(program->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true)
+ continue;
+ if (tas_priv->tasdevice[i].is_loaderr == false &&
+ tas_priv->tasdevice[i].is_loading == true)
+ tas_priv->tasdevice[i].cur_prog = prm_no;
+ }
+ }
+
+ for (i = 0, status = 0; i < tas_priv->ndev; i++) {
+ if (cfg_no >= 0
+ && tas_priv->tasdevice[i].cur_conf != cfg_no
+ && (cfg_info[rca_conf_no]->active_dev & (1 << i))
+ && (tas_priv->tasdevice[i].is_loaderr == false)) {
+ status++;
+ tas_priv->tasdevice[i].is_loading = true;
+ } else
+ tas_priv->tasdevice[i].is_loading = false;
+ }
+
+ if (status) {
+ conf = &(tas_fmw->configs[cfg_no]);
+ status = 0;
+ tasdevice_load_data(tas_priv, &(conf->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true) {
+ status |= BIT(i + 4);
+ continue;
+ }
+
+ if (tas_priv->tasdevice[i].is_loaderr == false &&
+ tas_priv->tasdevice[i].is_loading == true) {
+ tasdev_load_calibrated_data(tas_priv, i);
+ tas_priv->tasdevice[i].cur_conf = cfg_no;
+ }
+ }
+ } else {
+ dev_dbg(tas_priv->dev, "%s: Unneeded loading dsp conf %d\n",
+ __func__, cfg_no);
+ }
+
+ status |= cfg_info[rca_conf_no]->active_dev;
+
+out:
+ return prog_status;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg, "SND_SOC_TAS2781_FMWLIB");
+
+int tasdevice_prmg_load(void *context, int prm_no)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_prog *program;
+ int prog_status = 0;
+ int i;
+
+ if (!tas_fmw) {
+ dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__);
+ goto out;
+ }
+
+ if (prm_no >= tas_fmw->nr_programs) {
+ dev_err(tas_priv->dev,
+ "%s: prm(%d) is not in range of Programs %u\n",
+ __func__, prm_no, tas_fmw->nr_programs);
+ goto out;
+ }
+
+ for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
+ if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) {
+ tas_priv->tasdevice[i].cur_conf = -1;
+ tas_priv->tasdevice[i].is_loading = true;
+ prog_status++;
+ }
+ }
+
+ if (prog_status) {
+ program = &(tas_fmw->programs[prm_no]);
+ tasdevice_load_data(tas_priv, &(program->dev_data));
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->tasdevice[i].is_loaderr == true)
+ continue;
+ else if (tas_priv->tasdevice[i].is_loaderr == false
+ && tas_priv->tasdevice[i].is_loading == true)
+ tas_priv->tasdevice[i].cur_prog = prm_no;
+ }
+ }
+
+out:
+ return prog_status;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB");
+
+void tasdevice_tuning_switch(void *context, int state)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+
+ /*
+ * Only RCA-based Playback can still work with no dsp program running
+ * inside the chip.
+ */
+ switch (tas_priv->fw_state) {
+ case TASDEVICE_RCA_FW_OK:
+ case TASDEVICE_DSP_FW_ALL_OK:
+ break;
+ default:
+ return;
+ }
+
+ if (state == 0) {
+ if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) {
+ /* dsp mode or tuning mode */
+ profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+ tasdevice_select_tuningprm_cfg(tas_priv,
+ tas_priv->cur_prog, tas_priv->cur_conf,
+ profile_cfg_id);
+ }
+
+ tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+ } else {
+ tasdevice_select_cfg_blk(tas_priv, profile_cfg_id,
+ TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, "SND_SOC_TAS2781_FMWLIB");
+
+MODULE_DESCRIPTION("Texas Firmware Support");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
new file mode 100644
index 000000000000..d1c76ab0144d
--- /dev/null
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -0,0 +1,2132 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
+//
+// Copyright (C) 2022 - 2025 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The TAS2563/TAS2781 driver implements a flexible and configurable
+// algo coefficient setting for one, two, or even multiple
+// TAS2563/TAS2781 chips.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+// Author: Kevin Lu <kevin-lu@ti.com>
+//
+
+#include <linux/crc8.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+#include <sound/tas2781-comlib-i2c.h>
+#include <sound/tlv.h>
+#include <sound/tas2x20-tlv.h>
+#include <sound/tas2563-tlv.h>
+#include <sound/tas2781-tlv.h>
+#include <sound/tas5825-tlv.h>
+#include <linux/unaligned.h>
+
+#define X2563_CL_STT_VAL(xreg, xval) \
+{ .reg = xreg, \
+ .val = { xval }, \
+ .val_len = 1, }
+
+#define X2563_CL_STT_4BYTS(xreg, byte0, byte1, byte2, byte3) \
+{ .reg = xreg, \
+ .val = { byte0, byte1, byte2, byte3 }, \
+ .val_len = 4, }
+
+static const struct bulk_reg_val tas2563_cali_start_reg[] = {
+ X2563_CL_STT_VAL(TAS2563_IDLE, 0x00),
+ X2563_CL_STT_4BYTS(TAS2563_PRM_ENFF_REG, 0x40, 0x00, 0x00, 0x00),
+ X2563_CL_STT_4BYTS(TAS2563_PRM_DISTCK_REG, 0x40, 0x00, 0x00, 0x00),
+ X2563_CL_STT_4BYTS(TAS2563_PRM_TE_SCTHR_REG, 0x7f, 0xff, 0xff, 0xff),
+ X2563_CL_STT_4BYTS(TAS2563_PRM_PLT_FLAG_REG, 0x40, 0x00, 0x00, 0x00),
+ X2563_CL_STT_4BYTS(TAS2563_PRM_SINEGAIN_REG, 0x0a, 0x3d, 0x70, 0xa4),
+ X2563_CL_STT_4BYTS(TAS2563_TE_TA1_REG, 0x00, 0x36, 0x91, 0x5e),
+ X2563_CL_STT_4BYTS(TAS2563_TE_TA1_AT_REG, 0x00, 0x36, 0x91, 0x5e),
+ X2563_CL_STT_4BYTS(TAS2563_TE_TA2_REG, 0x00, 0x06, 0xd3, 0x72),
+ X2563_CL_STT_4BYTS(TAS2563_TE_AT_REG, 0x00, 0x36, 0x91, 0x5e),
+ X2563_CL_STT_4BYTS(TAS2563_TE_DT_REG, 0x00, 0x36, 0x91, 0x5e),
+};
+
+#define X2781_CL_STT_VAL(xreg, xval, xlocked) \
+{ .reg = xreg, \
+ .val = { xval }, \
+ .val_len = 1, \
+ .is_locked = xlocked, }
+
+#define X2781_CL_STT_4BYTS_UNLOCKED(xreg, byte0, byte1, byte2, byte3) \
+{ .reg = xreg, \
+ .val = { byte0, byte1, byte2, byte3 }, \
+ .val_len = 4, \
+ .is_locked = false, }
+
+#define X2781_CL_STT_LEN_UNLOCKED(xreg) \
+{ .reg = xreg, \
+ .val_len = 4, \
+ .is_locked = false, }
+
+static const struct bulk_reg_val tas2781_cali_start_reg[] = {
+ X2781_CL_STT_VAL(TAS2781_PRM_INT_MASK_REG, 0xfe, false),
+ X2781_CL_STT_VAL(TAS2781_PRM_CLK_CFG_REG, 0xdd, false),
+ X2781_CL_STT_VAL(TAS2781_PRM_RSVD_REG, 0x20, false),
+ X2781_CL_STT_VAL(TAS2781_PRM_TEST_57_REG, 0x14, true),
+ X2781_CL_STT_VAL(TAS2781_PRM_TEST_62_REG, 0x45, true),
+ X2781_CL_STT_VAL(TAS2781_PRM_PVDD_UVLO_REG, 0x03, false),
+ X2781_CL_STT_VAL(TAS2781_PRM_CHNL_0_REG, 0xa8, false),
+ X2781_CL_STT_VAL(TAS2781_PRM_NG_CFG0_REG, 0xb9, false),
+ X2781_CL_STT_VAL(TAS2781_PRM_IDLE_CH_DET_REG, 0x92, false),
+ /*
+ * This register is pilot tone threshold, different with the
+ * calibration tool version, it will be updated in
+ * tas2781_calib_start_put(), set to 1mA.
+ */
+ X2781_CL_STT_4BYTS_UNLOCKED(0, 0x00, 0x00, 0x00, 0x56),
+ X2781_CL_STT_4BYTS_UNLOCKED(TAS2781_PRM_PLT_FLAG_REG,
+ 0x40, 0x00, 0x00, 0x00),
+ X2781_CL_STT_LEN_UNLOCKED(TAS2781_PRM_SINEGAIN_REG),
+ X2781_CL_STT_LEN_UNLOCKED(TAS2781_PRM_SINEGAIN2_REG),
+};
+
+static const struct i2c_device_id tasdevice_id[] = {
+ { "tas2020", TAS2020 },
+ { "tas2118", TAS2118 },
+ { "tas2120", TAS2120 },
+ { "tas2320", TAS2320 },
+ { "tas2563", TAS2563 },
+ { "tas2568", TAS2568 },
+ { "tas2570", TAS2570 },
+ { "tas2572", TAS2572 },
+ { "tas2574", TAS2574 },
+ { "tas2781", TAS2781 },
+ { "tas5802", TAS5802 },
+ { "tas5806m", TAS5806M },
+ { "tas5806md", TAS5806MD },
+ { "tas5815", TAS5815 },
+ { "tas5822", TAS5822 },
+ { "tas5825", TAS5825 },
+ { "tas5827", TAS5827 },
+ { "tas5828", TAS5828 },
+ { "tas5830", TAS5830 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tasdevice_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tasdevice_of_match[] = {
+ { .compatible = "ti,tas2020" },
+ { .compatible = "ti,tas2118" },
+ { .compatible = "ti,tas2120" },
+ { .compatible = "ti,tas2320" },
+ { .compatible = "ti,tas2563" },
+ { .compatible = "ti,tas2568" },
+ { .compatible = "ti,tas2570" },
+ { .compatible = "ti,tas2572" },
+ { .compatible = "ti,tas2574" },
+ { .compatible = "ti,tas2781" },
+ { .compatible = "ti,tas5802" },
+ { .compatible = "ti,tas5806m" },
+ { .compatible = "ti,tas5806md" },
+ { .compatible = "ti,tas5815" },
+ { .compatible = "ti,tas5822" },
+ { .compatible = "ti,tas5825" },
+ { .compatible = "ti,tas5827" },
+ { .compatible = "ti,tas5828" },
+ { .compatible = "ti,tas5830" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tasdevice_of_match);
+#endif
+
+/**
+ * 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.
+ */
+static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_digital_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_digital_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_amp_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv =
+ snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv =
+ snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
+ dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+ tas_priv->force_fwload_status ? "ON" : "OFF");
+
+ return 0;
+}
+
+static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv =
+ snd_soc_component_get_drvdata(component);
+ 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__,
+ tas_priv->force_fwload_status ? "ON" : "OFF");
+
+ return change;
+}
+
+static int tasdev_cali_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ struct calidata *cali_data = &priv->cali_data;
+ struct cali_reg *p = &cali_data->cali_reg_array;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned char *data = cali_data->data;
+ unsigned int i = 0;
+ unsigned int j, k;
+ int rc;
+
+ guard(mutex)(&priv->codec_lock);
+ if (!priv->is_user_space_calidata)
+ return -1;
+
+ if (!p->r0_reg)
+ return -1;
+
+ dst[i++] = bytes_ext->max;
+ dst[i++] = 'r';
+
+ dst[i++] = TASDEVICE_BOOK_ID(p->r0_reg);
+ dst[i++] = TASDEVICE_PAGE_ID(p->r0_reg);
+ dst[i++] = TASDEVICE_PAGE_REG(p->r0_reg);
+
+ dst[i++] = TASDEVICE_BOOK_ID(p->r0_low_reg);
+ dst[i++] = TASDEVICE_PAGE_ID(p->r0_low_reg);
+ dst[i++] = TASDEVICE_PAGE_REG(p->r0_low_reg);
+
+ dst[i++] = TASDEVICE_BOOK_ID(p->invr0_reg);
+ dst[i++] = TASDEVICE_PAGE_ID(p->invr0_reg);
+ dst[i++] = TASDEVICE_PAGE_REG(p->invr0_reg);
+
+ dst[i++] = TASDEVICE_BOOK_ID(p->pow_reg);
+ dst[i++] = TASDEVICE_PAGE_ID(p->pow_reg);
+ dst[i++] = TASDEVICE_PAGE_REG(p->pow_reg);
+
+ dst[i++] = TASDEVICE_BOOK_ID(p->tlimit_reg);
+ dst[i++] = TASDEVICE_PAGE_ID(p->tlimit_reg);
+ dst[i++] = TASDEVICE_PAGE_REG(p->tlimit_reg);
+
+ for (j = 0, k = 0; j < priv->ndev; j++) {
+ if (j == data[k]) {
+ dst[i++] = j;
+ k++;
+ } else {
+ dev_err(priv->dev, "chn %d device %u not match\n",
+ j, data[k]);
+ k += 21;
+ continue;
+ }
+ rc = tasdevice_dev_bulk_read(priv, j, p->r0_reg, &dst[i], 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d r0_reg bulk_rd err = %d\n",
+ j, rc);
+ i += 20;
+ k += 20;
+ continue;
+ }
+ rc = memcmp(&dst[i], &data[k], 4);
+ if (rc != 0)
+ dev_dbg(priv->dev, "chn %d r0_data is not same\n", j);
+ k += 4;
+ i += 4;
+ rc = tasdevice_dev_bulk_read(priv, j, p->r0_low_reg,
+ &dst[i], 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d r0_low bulk_rd err = %d\n",
+ j, rc);
+ i += 16;
+ k += 16;
+ continue;
+ }
+ rc = memcmp(&dst[i], &data[k], 4);
+ if (rc != 0)
+ dev_dbg(priv->dev, "chn %d r0_low is not same\n", j);
+ i += 4;
+ k += 4;
+ rc = tasdevice_dev_bulk_read(priv, j, p->invr0_reg,
+ &dst[i], 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d invr0 bulk_rd err = %d\n",
+ j, rc);
+ i += 12;
+ k += 12;
+ continue;
+ }
+ rc = memcmp(&dst[i], &data[k], 4);
+ if (rc != 0)
+ dev_dbg(priv->dev, "chn %d invr0 is not same\n", j);
+ i += 4;
+ k += 4;
+ rc = tasdevice_dev_bulk_read(priv, j, p->pow_reg, &dst[i], 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d pow_reg bulk_rd err = %d\n",
+ j, rc);
+ i += 8;
+ k += 8;
+ continue;
+ }
+ rc = memcmp(&dst[i], &data[k], 4);
+ if (rc != 0)
+ dev_dbg(priv->dev, "chn %d pow_reg is not same\n", j);
+ i += 4;
+ k += 4;
+ rc = tasdevice_dev_bulk_read(priv, j, p->tlimit_reg,
+ &dst[i], 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "chn %d tlimit bulk_rd err = %d\n",
+ j, rc);
+ }
+ rc = memcmp(&dst[i], &data[k], 4);
+ if (rc != 0)
+ dev_dbg(priv->dev, "chn %d tlimit is not same\n", j);
+ i += 4;
+ k += 4;
+ }
+ return 0;
+}
+
+static int calib_data_get(struct tasdevice_priv *tas_priv, int reg,
+ unsigned char *dst)
+{
+ struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int rc = -1;
+ int i;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (clt->addr == tasdev[i].dev_addr) {
+ /* First byte is the device index. */
+ dst[0] = i;
+ rc = tasdevice_dev_bulk_read(tas_priv, i, reg, &dst[1],
+ 4);
+ break;
+ }
+ }
+
+ 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);
+ unsigned char val[4];
+ int j, r;
+
+ if (p == NULL)
+ return;
+
+ /* Store the current setting from the chip */
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1) {
+ if (p[j].is_locked)
+ tasdevice_dev_write(tas_priv, i,
+ TAS2781_TEST_UNLOCK_REG,
+ TAS2781_TEST_PAGE_UNLOCK);
+ tasdevice_dev_read(tas_priv, i, p[j].reg,
+ (int *)&p[j].val[0]);
+ } else {
+ if (!tas_priv->dspbin_typ) {
+ r = partial_cali_data_update(reg, j);
+ if (r)
+ p[j].reg = r;
+ }
+
+ 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 - 4; j++) {
+ if (p[j].val_len == 1) {
+ if (p[j].is_locked)
+ tasdevice_dev_write(tas_priv, i,
+ TAS2781_TEST_UNLOCK_REG,
+ TAS2781_TEST_PAGE_UNLOCK);
+ tasdevice_dev_write(tas_priv, i, p[j].reg,
+ tas2781_cali_start_reg[j].val[0]);
+ }
+ }
+
+ 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,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dat = ucontrol->value.bytes.data;
+ int i, reg[4];
+ int j = 0;
+
+ guard(mutex)(&priv->codec_lock);
+ if (priv->chip_id != TAS2781 || bytes_ext->max != dat[0] ||
+ dat[1] != 'r') {
+ dev_err(priv->dev, "%s: package fmt or chipid incorrect\n",
+ __func__);
+ return 0;
+ }
+ j += 2;
+ /* refresh pilot tone and SineGain register */
+ for (i = 0; i < ARRAY_SIZE(reg); i++) {
+ reg[i] = TASDEVICE_REG(dat[j], dat[j + 1], dat[j + 2]);
+ j += 3;
+ }
+
+ for (i = 0; i < priv->ndev; i++) {
+ int k = i * 9 + j;
+
+ if (dat[k] != i) {
+ dev_err(priv->dev, "%s:no cal-setting for dev %d\n",
+ __func__, i);
+ continue;
+ }
+ sngl_calib_start(priv, i, reg, dat + k);
+ }
+ return 1;
+}
+
+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 < 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;
+
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1) {
+ if (p[j].is_locked)
+ tasdevice_dev_write(priv, i,
+ TAS2781_TEST_UNLOCK_REG,
+ TAS2781_TEST_PAGE_UNLOCK);
+ tasdevice_dev_write(priv, i, p[j].reg,
+ p[j].val[0]);
+ } else {
+ if (!p[j].reg)
+ continue;
+ 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);
+ }
+}
+
+static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bulk_reg_val *q = (struct bulk_reg_val *)tas2563_cali_start_reg;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
+ int i, j;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ if (tas_priv->chip_id != TAS2563)
+ return -1;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ struct bulk_reg_val *p = tasdev[i].cali_data_backup;
+
+ if (p == NULL)
+ continue;
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1)
+ tasdevice_dev_read(tas_priv,
+ i, p[j].reg,
+ (unsigned int *)&p[j].val[0]);
+ else
+ tasdevice_dev_bulk_read(tas_priv,
+ i, p[j].reg, p[j].val, 4);
+ }
+
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1)
+ tasdevice_dev_write(tas_priv, i, p[j].reg,
+ q[j].val[0]);
+ else
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ q[j].val, 4);
+ }
+ }
+
+ return 1;
+}
+
+static void tas2563_calib_stop_put(struct tasdevice_priv *tas_priv)
+{
+ const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
+ int i, j;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ struct bulk_reg_val *p = tasdev[i].cali_data_backup;
+
+ if (p == NULL)
+ continue;
+
+ for (j = 0; j < sum; j++) {
+ if (p[j].val_len == 1)
+ tasdevice_dev_write(tas_priv, i, p[j].reg,
+ p[j].val[0]);
+ else
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ p[j].val, 4);
+ }
+ }
+}
+
+static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+
+ guard(mutex)(&priv->codec_lock);
+ if (priv->chip_id == TAS2563)
+ tas2563_calib_stop_put(priv);
+ else
+ tas2781_calib_stop_put(priv);
+
+ return 1;
+}
+
+static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ struct calidata *cali_data = &priv->cali_data;
+ struct cali_reg *p = &cali_data->cali_reg_array;
+ unsigned char *src = ucontrol->value.bytes.data;
+ unsigned char *dst = cali_data->data;
+ int i = 0;
+ int j;
+
+ guard(mutex)(&priv->codec_lock);
+ if (src[0] != bytes_ext->max || src[1] != 'r') {
+ dev_err(priv->dev, "%s: pkg fmt invalid\n", __func__);
+ return 0;
+ }
+ for (j = 0; j < priv->ndev; j++) {
+ if (src[17 + j * 21] != j) {
+ dev_err(priv->dev, "%s: pkg fmt invalid\n", __func__);
+ return 0;
+ }
+ }
+ i += 2;
+ priv->is_user_space_calidata = true;
+
+ 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 1;
+}
+
+static int tas2781_latch_reg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ int i, val, rc = -1;
+
+ dst[0] = bytes_ext->max;
+ guard(mutex)(&tas_priv->codec_lock);
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (clt->addr == tasdev[i].dev_addr) {
+ /* First byte is the device index. */
+ dst[1] = i;
+ rc = tasdevice_dev_read(tas_priv, i,
+ TAS2781_RUNTIME_LATCH_RE_REG, &val);
+ if (rc < 0)
+ dev_err(tas_priv->dev, "%s, get value error\n",
+ __func__);
+ else
+ dst[2] = val;
+
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ 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);
+
+ reg = TAS2781_RUNTIME_RE_REG_TF;
+ 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;
+ return calib_data_get(tas_priv, reg, &dst[1]);
+}
+
+static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg = TAS2781_RUNTIME_RE_REG;
+
+ 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]);
+}
+
+static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct calidata *cali_data = &tas_priv->cali_data;
+ struct soc_bytes_ext *bytes_ext =
+ (struct soc_bytes_ext *) kcontrol->private_value;
+ unsigned char *dst = ucontrol->value.bytes.data;
+ unsigned int reg;
+
+ guard(mutex)(&tas_priv->codec_lock);
+
+ if (tas_priv->chip_id == TAS2563)
+ reg = TAS2563_PRM_R0_REG;
+ else if (cali_data->cali_reg_array.r0_reg)
+ reg = cali_data->cali_reg_array.r0_reg;
+ else
+ return -1;
+ dst[0] = bytes_ext->max;
+ return calib_data_get(tas_priv, reg, &dst[1]);
+}
+
+static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(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]);
+}
+
+static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(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]);
+}
+
+static int tasdev_nop_get(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return 0;
+}
+
+static int tasdevice_digital_gain_get(
+ 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 *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ unsigned int l = 0, r = mc->max;
+ unsigned int target, ar_mid, mid, ar_l, ar_r;
+ unsigned int reg = mc->reg;
+ unsigned char data[4];
+ int ret;
+
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ goto out;
+ }
+
+ target = get_unaligned_be32(&data[0]);
+
+ while (r > 1 + l) {
+ mid = (l + r) / 2;
+ ar_mid = get_unaligned_be32(tas_dev->dvc_tlv_table[mid]);
+ if (target < ar_mid)
+ r = mid;
+ else
+ l = mid;
+ }
+
+ ar_l = get_unaligned_be32(tas_dev->dvc_tlv_table[l]);
+ ar_r = get_unaligned_be32(tas_dev->dvc_tlv_table[r]);
+
+ /* find out the member same as or closer to the current volume */
+ ucontrol->value.integer.value[0] =
+ abs(target - ar_l) <= abs(target - ar_r) ? l : r;
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return 0;
+}
+
+static int tasdevice_digital_gain_put(
+ 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 *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
+ int vol = ucontrol->value.integer.value[0];
+ int status = 0, max = mc->max, rc = 1;
+ int i, ret;
+ unsigned int reg = mc->reg;
+ unsigned int volrd, volwr;
+ unsigned char data[4];
+
+ vol = clamp(vol, 0, max);
+ mutex_lock(&tas_dev->codec_lock);
+ /* Read the primary device */
+ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
+ if (ret) {
+ dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
+ rc = -1;
+ goto out;
+ }
+
+ volrd = get_unaligned_be32(&data[0]);
+ volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]);
+
+ if (volrd == volwr) {
+ rc = 0;
+ goto out;
+ }
+
+ for (i = 0; i < tas_dev->ndev; i++) {
+ ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
+ (unsigned char *)tas_dev->dvc_tlv_table[vol], 4);
+ if (ret) {
+ dev_err(tas_dev->dev,
+ "%s, set digital vol error in dev %d\n",
+ __func__, i);
+ status |= BIT(i);
+ }
+ }
+
+ if (status)
+ rc = -1;
+out:
+ mutex_unlock(&tas_dev->codec_lock);
+ return rc;
+}
+
+static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
+ SOC_SINGLE_EXT("Calibration Stop", SND_SOC_NOPM, 0, 1, 0,
+ tasdev_nop_get, tasdev_calib_stop_put),
+ SND_SOC_BYTES_EXT("Amp TF Data", 6, tasdev_tf_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp RE Data", 6, tasdev_re_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp R0 Data", 6, tasdev_r0_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp XMA1 Data", 6, tasdev_XMA1_data_get, NULL),
+ SND_SOC_BYTES_EXT("Amp XMA2 Data", 6, tasdev_XMA2_data_get, NULL),
+};
+
+static const struct snd_kcontrol_new tas2x20_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2X20_AMP_LEVEL,
+ 0, 0, 42, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas2x20_amp_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2X20_DVC_LEVEL,
+ 0, 0, ARRAY_SIZE(tas2x20_dvc_table) - 1, 0,
+ tasdevice_digital_gain_get, tasdevice_digital_gain_put,
+ tas2x20_dvc_tlv),
+};
+
+static const struct snd_kcontrol_new tas2781_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL,
+ 1, 0, 20, 0, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas2781_amp_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2781_DVC_LVL,
+ 0, 0, 200, 1, tas2781_digital_getvol,
+ tas2781_digital_putvol, tas2781_dvc_tlv),
+};
+
+static const struct snd_kcontrol_new tas5825_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL,
+ 0, 0, 31, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_amp_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL,
+ 0, 0, 254, 1, tas2781_amp_getvol,
+ tas2781_amp_putvol, tas5825_dvc_tlv),
+};
+
+static const struct snd_kcontrol_new tas2781_cali_controls[] = {
+ SND_SOC_BYTES_EXT("Amp Latch Data", 3, tas2781_latch_reg_get, NULL),
+};
+
+static const struct snd_kcontrol_new tas2563_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0,
+ 0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
+ tasdevice_digital_gain_get, tasdevice_digital_gain_put,
+ tas2563_dvc_tlv),
+};
+
+static const struct snd_kcontrol_new tas2563_cali_controls[] = {
+ SOC_SINGLE_EXT("Calibration Start", SND_SOC_NOPM, 0, 1, 0,
+ tasdev_nop_get, tas2563_calib_start_put),
+};
+
+static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int ret = 0;
+
+ if (tas_priv->rcabin.profile_cfg_id !=
+ ucontrol->value.integer.value[0]) {
+ tas_priv->rcabin.profile_cfg_id =
+ ucontrol->value.integer.value[0];
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = tas_priv->ndev - 1;
+
+ return 0;
+}
+
+static int tasdevice_info_chip_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = TAS2020;
+ uinfo->value.integer.max = TAS_OTHERS;
+
+ return 0;
+}
+
+static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)tas_fw->nr_programs;
+
+ return 0;
+}
+
+static int tasdevice_info_configurations(
+ struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)tas_fw->nr_configurations - 1;
+
+ return 0;
+}
+
+static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ 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 snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
+
+ return 0;
+}
+
+static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->chip_id;
+
+ return 0;
+}
+
+static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
+{
+ struct snd_kcontrol_new *prof_ctrls;
+ int nr_controls = 1;
+ int mix_index = 0;
+ int ret;
+ char *name;
+
+ prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
+ sizeof(prof_ctrls[0]), GFP_KERNEL);
+ if (!prof_ctrls) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Create a mixer item for selecting the active profile */
+ name = devm_kstrdup(tas_priv->dev, "Speaker Profile Id", GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ prof_ctrls[mix_index].name = name;
+ prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ prof_ctrls[mix_index].info = tasdevice_info_profile;
+ prof_ctrls[mix_index].get = tasdevice_get_profile_id;
+ prof_ctrls[mix_index].put = tasdevice_set_profile_id;
+ mix_index++;
+
+ ret = snd_soc_add_component_controls(tas_priv->codec,
+ prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+
+out:
+ return ret;
+}
+
+static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ 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 snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int nr_program = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ if (tas_priv->cur_prog != nr_program) {
+ tas_priv->cur_prog = nr_program;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int tasdevice_configuration_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tas_priv->cur_conf;
+
+ return 0;
+}
+
+static int tasdevice_configuration_put(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int nr_configuration = ucontrol->value.integer.value[0];
+ int ret = 0;
+
+ if (tas_priv->cur_conf != nr_configuration) {
+ tas_priv->cur_conf = nr_configuration;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int tasdevice_active_num_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int i;
+
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (clt->addr == tasdev[i].dev_addr) {
+ ucontrol->value.integer.value[0] = i;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int dev_id = ucontrol->value.integer.value[0];
+ int max = tas_priv->ndev - 1;
+
+ dev_id = clamp(dev_id, 0, max);
+
+ guard(mutex)(&tas_priv->codec_lock);
+ return tasdev_chn_switch(tas_priv, dev_id);
+}
+
+static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
+{
+ struct snd_kcontrol_new *dsp_ctrls;
+ char *active_dev_num, *chip_id, *fw_load;
+ char *conf_name, *prog_name;
+ int nr_controls = 5;
+ int mix_index = 0;
+
+ /* 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)
+ 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)
+ 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;
+ dsp_ctrls[mix_index].get = tasdevice_program_get;
+ dsp_ctrls[mix_index].put = tasdevice_program_put;
+ mix_index++;
+
+ conf_name = devm_kstrdup(tas_priv->dev, "Speaker Config Id",
+ GFP_KERNEL);
+ 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;
+ dsp_ctrls[mix_index].get = tasdevice_configuration_get;
+ dsp_ctrls[mix_index].put = tasdevice_configuration_put;
+ mix_index++;
+
+ active_dev_num = devm_kstrdup(tas_priv->dev, "Activate Tasdevice Num",
+ GFP_KERNEL);
+ 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;
+ dsp_ctrls[mix_index].get = tasdevice_active_num_get;
+ dsp_ctrls[mix_index].put = tasdevice_active_num_put;
+ mix_index++;
+
+ chip_id = devm_kstrdup(tas_priv->dev, "Tasdevice Chip Id", GFP_KERNEL);
+ 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++;
+
+ fw_load = devm_kstrdup(tas_priv->dev, "Speaker Force Firmware Load",
+ GFP_KERNEL);
+ if (!fw_load)
+ return -ENOMEM;
+
+ dsp_ctrls[mix_index].name = fw_load;
+ dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ dsp_ctrls[mix_index].info = snd_soc_info_bool_ext;
+ dsp_ctrls[mix_index].put = tasdev_force_fwload_put;
+ dsp_ctrls[mix_index].get = tasdev_force_fwload_get;
+ dsp_ctrls[mix_index].private_value = 0UL;
+ mix_index++;
+
+ return snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
+ nr_controls < mix_index ? nr_controls : mix_index);
+}
+
+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;
+ char *cali_name;
+ int rc, i;
+
+ rc = snd_soc_add_component_controls(priv->codec,
+ tasdevice_cali_controls, ARRAY_SIZE(tasdevice_cali_controls));
+ if (rc < 0) {
+ dev_err(priv->dev, "%s: Add cali controls err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+
+ 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++) {
+ 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;
+ nctrls = ARRAY_SIZE(tas2563_cali_controls);
+ for (i = 0; i < priv->ndev; i++) {
+ tasdev[i].cali_data_backup =
+ kmemdup(tas2563_cali_start_reg,
+ sizeof(tas2563_cali_start_reg), GFP_KERNEL);
+ if (!tasdev[i].cali_data_backup)
+ return -ENOMEM;
+ }
+ }
+
+ rc = snd_soc_add_component_controls(priv->codec, cali_ctrls, nctrls);
+ if (rc < 0) {
+ dev_err(priv->dev, "%s: Add chip cali ctrls err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+
+ /* index for cali_ctrls */
+ i = 0;
+ if (priv->chip_id == TAS2781)
+ nctrls = 2;
+ else
+ nctrls = 1;
+
+ /*
+ * Alloc kcontrol via devm_kzalloc(), which don't manually
+ * free the kcontrol.
+ */
+ cali_ctrls = devm_kcalloc(priv->dev, nctrls,
+ sizeof(cali_ctrls[0]), GFP_KERNEL);
+ if (!cali_ctrls)
+ return -ENOMEM;
+
+ ext_cali_data = devm_kzalloc(priv->dev, sizeof(*ext_cali_data),
+ GFP_KERNEL);
+ if (!ext_cali_data)
+ return -ENOMEM;
+
+ cali_name = devm_kstrdup(priv->dev, "Speaker Calibrated Data",
+ GFP_KERNEL);
+ if (!cali_name)
+ return -ENOMEM;
+ /* the number of calibrated data per tas2563/tas2781 */
+ cali_data->cali_dat_sz_per_dev = 20;
+ /*
+ * Data structure for tas2563/tas2781 calibrated data:
+ * Pkg len (1 byte)
+ * Reg id (1 byte, constant 'r')
+ * book, page, register array for calibrated data (15 bytes)
+ * for (i = 0; i < Device-Sum; i++) {
+ * Device #i index_info (1 byte)
+ * Calibrated data for Device #i (20 bytes)
+ * }
+ */
+ ext_cali_data->max = priv->ndev *
+ (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);
+ cali_ctrls[i].name = cali_name;
+ cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ cali_ctrls[i].info = snd_soc_bytes_info_ext;
+ cali_ctrls[i].get = tasdev_cali_data_get;
+ cali_ctrls[i].put = tasdev_cali_data_put;
+ cali_ctrls[i].private_value = (unsigned long)ext_cali_data;
+ i++;
+
+ cali_data->data = devm_kzalloc(priv->dev, cali_data->total_sz,
+ GFP_KERNEL);
+ if (!cali_data->data)
+ return -ENOMEM;
+
+ if (priv->chip_id == TAS2781) {
+ struct soc_bytes_ext *ext_cali_start;
+ char *cali_start_name;
+
+ ext_cali_start = devm_kzalloc(priv->dev,
+ sizeof(*ext_cali_start), GFP_KERNEL);
+ if (!ext_cali_start)
+ return -ENOMEM;
+
+ cali_start_name = devm_kstrdup(priv->dev,
+ "Calibration Start", GFP_KERNEL);
+ if (!cali_start_name)
+ return -ENOMEM;
+ /*
+ * package structure for tas2781 ftc start:
+ * Pkg len (1 byte)
+ * Reg id (1 byte, constant 'r')
+ * book, page, register for pilot threshold, pilot tone
+ * and sine gain (12 bytes)
+ * for (i = 0; i < Device-Sum; i++) {
+ * Device #i index_info (1 byte)
+ * Sine gain for Device #i (8 bytes)
+ * }
+ */
+ ext_cali_start->max = 14 + priv->ndev * 9;
+ cali_ctrls[i].name = cali_start_name;
+ cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ cali_ctrls[i].info = snd_soc_bytes_info_ext;
+ cali_ctrls[i].put = tas2781_calib_start_put;
+ cali_ctrls[i].get = tasdev_nop_get;
+ cali_ctrls[i].private_value = (unsigned long)ext_cali_start;
+ i++;
+ }
+
+ return snd_soc_add_component_controls(priv->codec, cali_ctrls,
+ nctrls < i ? nctrls : i);
+}
+
+#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
+/*
+ * This debugfs node is a bridge to the acoustic tuning application
+ * tool which can tune the chips' acoustic effect.
+ *
+ * package structure for PPC3 communications:
+ * Pkg len (1 byte)
+ * Pkg id (1 byte, 'r' or 'w')
+ * Dev id (1 byte, i2c address)
+ * Book id (1 byte)
+ * Page id (1 byte)
+ * Reg id (1 byte)
+ * switch (pkg id) {
+ * case 'w':
+ * 1 byte, length of data to read
+ * case 'r':
+ * data payload (1~128 bytes)
+ * }
+ */
+static ssize_t acoustic_ctl_read(struct file *file, char __user *to,
+ size_t count, loff_t *ppos)
+{
+ struct snd_soc_component *comp = file->private_data;
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct acoustic_data *p = &tas_priv->acou_data;
+ int ret = -1;
+
+ if (p->id == 'r' && p->len == count && count <= sizeof(*p))
+ ret = simple_read_from_buffer(to, count, ppos, p, p->len);
+ else
+ dev_err(tas_priv->dev, "Not ready for get.\n");
+ return ret;
+}
+
+static ssize_t acoustic_ctl_write(struct file *file,
+ const char __user *from, size_t count, loff_t *ppos)
+{
+ struct snd_soc_component *comp = file->private_data;
+ struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+ struct acoustic_data *p = &priv->acou_data;
+ unsigned int max_pkg_len = sizeof(*p);
+ unsigned char *src;
+ int j, len, reg, val;
+ unsigned short chn;
+ int ret = -1;
+
+ if (count > sizeof(*p)) {
+ dev_err(priv->dev, "count(%u) is larger than max(%u).\n",
+ (unsigned int)count, max_pkg_len);
+ return ret;
+ }
+
+ src = memdup_user(from, count);
+ if (IS_ERR(src))
+ return PTR_ERR(src);
+
+ if (src[0] > max_pkg_len && src[0] != count) {
+ dev_err(priv->dev, "pkg(%u), max(%u), count(%u) mismatch.\n",
+ src[0], max_pkg_len, (unsigned int)count);
+ ret = 0;
+ goto exit;
+ }
+
+ switch (src[1]) {
+ case 'r':
+ /* length of data to read */
+ len = src[6];
+ break;
+ case 'w':
+ /* Skip 6 bytes for package type and register address */
+ len = src[0] - 6;
+ break;
+ default:
+ dev_err(priv->dev, "%s Wrong code %02x.\n", __func__, src[1]);
+ ret = 0;
+ goto exit;
+ }
+
+ if (len < 1) {
+ dev_err(priv->dev, "pkg fmt invalid %02x.\n", len);
+ ret = 0;
+ goto exit;
+ }
+
+ for (j = 0; j < priv->ndev; j++)
+ if (src[2] == priv->tasdevice[j].dev_addr) {
+ chn = j;
+ break;
+ }
+ if (j >= priv->ndev) {
+ dev_err(priv->dev, "no such device 0x%02x.\n", src[2]);
+ ret = 0;
+ goto exit;
+ }
+
+ reg = TASDEVICE_REG(src[3], src[4], src[5]);
+
+ guard(mutex)(&priv->codec_lock);
+
+ if (src[1] == 'w') {
+ if (len > 1)
+ ret = tasdevice_dev_bulk_write(priv, chn, reg,
+ &src[6], len);
+ else
+ ret = tasdevice_dev_write(priv, chn, reg, src[6]);
+ } else {
+ struct acoustic_data *p = &priv->acou_data;
+
+ memcpy(p, src, 6);
+ if (len > 1) {
+ ret = tasdevice_dev_bulk_read(priv, chn, reg,
+ p->data, len);
+ } else {
+ ret = tasdevice_dev_read(priv, chn, reg, &val);
+ p->data[0] = val;
+ }
+ p->len = len + 6;
+ }
+
+ if (ret)
+ dev_err(priv->dev, "i2c communication error.\n");
+ else
+ ret = count;
+exit:
+ kfree(src);
+ return ret;
+}
+
+static const struct file_operations acoustic_ctl_fops = {
+ .open = simple_open,
+ .read = acoustic_ctl_read,
+ .write = acoustic_ctl_write,
+};
+#endif
+
+static void tasdevice_fw_ready(const struct firmware *fmw,
+ void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
+ struct snd_soc_component *comp = tas_priv->codec;
+ struct dentry *debugfs_root = comp->debugfs_root;
+ char *acoustic_debugfs_node;
+#endif
+ int ret = 0;
+ int i;
+
+ mutex_lock(&tas_priv->codec_lock);
+
+ ret = tasdevice_rca_parser(tas_priv, fmw);
+ if (ret) {
+ tasdevice_config_info_remove(tas_priv);
+ goto out;
+ }
+ tasdevice_create_control(tas_priv);
+
+ tasdevice_dsp_remove(tas_priv);
+ tasdevice_calbin_remove(tas_priv);
+ /*
+ * The baseline is the RCA-only case, and then the code attempts to
+ * load DSP firmware but in case of failures just keep going, i.e.
+ * failing to load DSP firmware is NOT an error.
+ */
+ tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
+ /* There is no DSP firmware required for TAS2118/2X20/257X. */
+ switch (tas_priv->chip_id) {
+ case TAS2020:
+ case TAS2118:
+ case TAS2120:
+ case TAS2320:
+ case TAS2568:
+ case TAS2570:
+ case TAS2572:
+ case TAS2574:
+ goto out;
+ }
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->coef_binaryname, 64, "%s-%s_coef.bin",
+ tas_priv->name_prefix, tas_priv->dev_name);
+ else
+ scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
+ tas_priv->dev_name);
+ ret = tasdevice_dsp_parser(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "dspfw load %s error\n",
+ tas_priv->coef_binaryname);
+ goto out;
+ }
+
+ /*
+ * If no dsp-related kcontrol created, the dsp resource will be freed.
+ */
+ ret = tasdevice_dsp_create_ctrls(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "dsp controls error\n");
+ goto out;
+ }
+ tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+
+ /* There is no calibration required for TAS58XX. */
+ if (tas_priv->chip_id < TAS5802) {
+ ret = tasdevice_create_cali_ctrls(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "cali controls error\n");
+ goto out;
+ }
+ /* If calibrated data occurs error, dsp will still works
+ * with default calibrated data inside algo.
+ */
+ for (i = 0; i < tas_priv->ndev; i++) {
+ if (tas_priv->name_prefix)
+ scnprintf(tas_priv->cal_binaryname[i], 64,
+ "%s-%s_cal_0x%02x.bin",
+ tas_priv->name_prefix,
+ tas_priv->dev_name,
+ tas_priv->tasdevice[i].dev_addr);
+ else
+ scnprintf(tas_priv->cal_binaryname[i], 64,
+ "%s_cal_0x%02x.bin",
+ tas_priv->dev_name,
+ tas_priv->tasdevice[i].dev_addr);
+ ret = tas2781_load_calibration(tas_priv,
+ tas_priv->cal_binaryname[i], i);
+ if (ret != 0)
+ dev_err(tas_priv->dev,
+ "%s: load %s error, keep default.\n",
+ __func__, tas_priv->cal_binaryname[i]);
+ }
+ }
+
+ tasdevice_prmg_load(tas_priv, 0);
+ tas_priv->cur_prog = 0;
+
+ /* Init common setting for different audio profiles */
+ if (tas_priv->rcabin.init_profile_id >= 0)
+ tasdevice_select_cfg_blk(tas_priv,
+ tas_priv->rcabin.init_profile_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+
+#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
+ if (tas_priv->name_prefix)
+ acoustic_debugfs_node = devm_kasprintf(tas_priv->dev,
+ GFP_KERNEL, "%s_acoustic_ctl", tas_priv->name_prefix);
+ else
+ acoustic_debugfs_node = devm_kstrdup(tas_priv->dev,
+ "acoustic_ctl", GFP_KERNEL);
+ debugfs_create_file(acoustic_debugfs_node, 0644, debugfs_root,
+ comp, &acoustic_ctl_fops);
+#endif
+out:
+ if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
+ switch (tas_priv->chip_id) {
+ case TAS2563:
+ case TAS2781:
+ case TAS5802:
+ case TAS5806M:
+ case TAS5806MD:
+ case TAS5815:
+ case TAS5822:
+ case TAS5825:
+ case TAS5827:
+ case TAS5828:
+ case TAS5830:
+ /* If DSP FW fail, DSP kcontrol won't be created. */
+ tasdevice_dsp_remove(tas_priv);
+ }
+ }
+ mutex_unlock(&tas_priv->codec_lock);
+ release_firmware(fmw);
+}
+
+static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int state = 0;
+
+ /* Codec Lock Hold */
+ mutex_lock(&tas_priv->codec_lock);
+ if (event == SND_SOC_DAPM_PRE_PMD)
+ state = 1;
+ tasdevice_tuning_switch(tas_priv, state);
+ /* Codec Lock Release*/
+ mutex_unlock(&tas_priv->codec_lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM,
+ 0, 0, tasdevice_dapm_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+ SND_SOC_DAPM_INPUT("DMIC"),
+};
+
+static const struct snd_soc_dapm_route tasdevice_audio_map[] = {
+ {"SPK", NULL, "ASI"},
+ {"OUT", NULL, "SPK"},
+ {"ASI OUT", NULL, "DMIC"},
+};
+
+static int tasdevice_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *codec = dai->component;
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ switch (tas_priv->fw_state) {
+ case TASDEVICE_RCA_FW_OK:
+ case TASDEVICE_DSP_FW_ALL_OK:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tasdevice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int slot_width;
+ unsigned int fsrate;
+ int bclk_rate;
+
+ fsrate = params_rate(params);
+ switch (fsrate) {
+ case 48000:
+ case 44100:
+ break;
+ default:
+ dev_err(tas_priv->dev, "%s: incorrect sample rate = %u\n",
+ __func__, fsrate);
+ return -EINVAL;
+ }
+
+ slot_width = params_width(params);
+ switch (slot_width) {
+ case 16:
+ case 20:
+ case 24:
+ case 32:
+ break;
+ default:
+ dev_err(tas_priv->dev, "%s: incorrect slot width = %u\n",
+ __func__, slot_width);
+ 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);
+ return bclk_rate;
+ }
+
+ return 0;
+}
+
+static int tasdevice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(codec_dai);
+
+ tas_priv->sysclk = freq;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tasdevice_dai_ops = {
+ .startup = tasdevice_startup,
+ .hw_params = tasdevice_hw_params,
+ .set_sysclk = tasdevice_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
+ {
+ .name = "tasdev_codec",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = TASDEVICE_RATES,
+ .formats = TASDEVICE_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = TASDEVICE_RATES,
+ .formats = TASDEVICE_FORMATS,
+ },
+ .ops = &tasdevice_dai_ops,
+ .symmetric_rate = 1,
+ },
+};
+
+static int tasdevice_codec_probe(struct snd_soc_component *codec)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ struct snd_kcontrol_new *p;
+ unsigned int size;
+ int rc;
+
+ switch (tas_priv->chip_id) {
+ case TAS2020:
+ case TAS2118:
+ case TAS2120:
+ case TAS2320:
+ case TAS2568:
+ case TAS2570:
+ case TAS2572:
+ case TAS2574:
+ p = (struct snd_kcontrol_new *)tas2x20_snd_controls;
+ size = ARRAY_SIZE(tas2x20_snd_controls);
+ tas_priv->dvc_tlv_table = tas2x20_dvc_table;
+ break;
+ case TAS2781:
+ p = (struct snd_kcontrol_new *)tas2781_snd_controls;
+ size = ARRAY_SIZE(tas2781_snd_controls);
+ break;
+ case TAS5802:
+ case TAS5806M:
+ case TAS5806MD:
+ case TAS5815:
+ case TAS5822:
+ case TAS5825:
+ case TAS5827:
+ case TAS5828:
+ case TAS5830:
+ p = (struct snd_kcontrol_new *)tas5825_snd_controls;
+ size = ARRAY_SIZE(tas5825_snd_controls);
+ break;
+ default:
+ p = (struct snd_kcontrol_new *)tas2563_snd_controls;
+ size = ARRAY_SIZE(tas2563_snd_controls);
+ tas_priv->dvc_tlv_table = tas2563_dvc_table;
+ break;
+ }
+
+ rc = snd_soc_add_component_controls(codec, p, size);
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: Add control err rc = %d",
+ __func__, rc);
+ return rc;
+ }
+
+ tas_priv->name_prefix = codec->name_prefix;
+ return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
+}
+
+static void tasdevice_deinit(void *context)
+{
+ struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
+ struct tasdevice *tasdev = tas_priv->tasdevice;
+ int i;
+
+ for (i = 0; i < tas_priv->ndev; i++)
+ kfree(tasdev[i].cali_data_backup);
+
+ tasdevice_config_info_remove(tas_priv);
+ tasdevice_dsp_remove(tas_priv);
+ tasdevice_calbin_remove(tas_priv);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+}
+
+static void tasdevice_codec_remove(struct snd_soc_component *codec)
+{
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+
+ tasdevice_deinit(tas_priv);
+}
+
+static const struct snd_soc_component_driver
+ soc_codec_driver_tasdevice = {
+ .probe = tasdevice_codec_probe,
+ .remove = tasdevice_codec_remove,
+ .dapm_widgets = tasdevice_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
+ .dapm_routes = tasdevice_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(tasdevice_audio_map),
+ .idle_bias_on = 1,
+ .endianness = 1,
+};
+
+static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
+{
+ struct i2c_client *client = (struct i2c_client *)tas_priv->client;
+ unsigned int dev_addrs[TASDEVICE_MAX_CHANNELS];
+ int ndev = 0;
+ int i, rc;
+
+ if (tas_priv->isacpi) {
+ ndev = device_property_read_u32_array(&client->dev,
+ "ti,audio-slots", NULL, 0);
+ if (ndev <= 0) {
+ ndev = 1;
+ dev_addrs[0] = client->addr;
+ } else {
+ ndev = (ndev < ARRAY_SIZE(dev_addrs))
+ ? ndev : ARRAY_SIZE(dev_addrs);
+ rc = device_property_read_u32_array(&client->dev,
+ "ti,audio-slots", dev_addrs, ndev);
+ if (rc != 0) {
+ ndev = 1;
+ dev_addrs[0] = client->addr;
+ }
+ }
+
+ tas_priv->irq =
+ acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0);
+ } else if (IS_ENABLED(CONFIG_OF)) {
+ struct device_node *np = tas_priv->dev->of_node;
+ u64 addr;
+
+ for (i = 0; i < TASDEVICE_MAX_CHANNELS; i++) {
+ if (of_property_read_reg(np, i, &addr, NULL))
+ break;
+ dev_addrs[ndev++] = addr;
+ }
+
+ tas_priv->irq = of_irq_get(np, 0);
+ } else {
+ ndev = 1;
+ dev_addrs[0] = client->addr;
+ }
+ tas_priv->ndev = ndev;
+ for (i = 0; i < ndev; i++)
+ tas_priv->tasdevice[i].dev_addr = dev_addrs[i];
+
+ tas_priv->reset = devm_gpiod_get_optional(&client->dev,
+ "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(tas_priv->reset))
+ dev_err(tas_priv->dev, "%s Can't get reset GPIO\n",
+ __func__);
+
+ strscpy(tas_priv->dev_name, tasdevice_id[tas_priv->chip_id].name,
+ sizeof(tas_priv->dev_name));
+}
+
+static int tasdevice_i2c_probe(struct i2c_client *i2c)
+{
+ const struct acpi_device_id *acpi_id;
+ struct tasdevice_priv *tas_priv;
+ int ret;
+
+ tas_priv = tasdevice_kzalloc(i2c);
+ if (!tas_priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&i2c->dev, tas_priv);
+
+ 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");
+ ret = -EINVAL;
+ goto err;
+ }
+ tas_priv->chip_id = acpi_id->driver_data;
+ tas_priv->isacpi = true;
+ } else {
+ tas_priv->chip_id = (uintptr_t)i2c_get_match_data(i2c);
+ tas_priv->isacpi = false;
+ }
+
+ tasdevice_parse_dt(tas_priv);
+
+ ret = tasdevice_init(tas_priv);
+ if (ret)
+ goto err;
+
+ tasdevice_reset(tas_priv);
+
+ ret = devm_snd_soc_register_component(tas_priv->dev,
+ &soc_codec_driver_tasdevice,
+ tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver));
+ if (ret) {
+ dev_err(tas_priv->dev, "%s: codec register error:0x%08x\n",
+ __func__, ret);
+ goto err;
+ }
+err:
+ if (ret < 0)
+ tasdevice_remove(tas_priv);
+ return ret;
+}
+
+static void tasdevice_i2c_remove(struct i2c_client *client)
+{
+ struct tasdevice_priv *tas_priv = i2c_get_clientdata(client);
+
+ tasdevice_remove(tas_priv);
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id tasdevice_acpi_match[] = {
+ { "TXNW2020", TAS2020 },
+ { "TXNW2118", TAS2118 },
+ { "TXNW2120", TAS2120 },
+ { "TXNW2320", TAS2320 },
+ { "TXNW2563", TAS2563 },
+ { "TXNW2568", TAS2568 },
+ { "TXNW2570", TAS2570 },
+ { "TXNW2572", TAS2572 },
+ { "TXNW2574", TAS2574 },
+ { "TXNW2781", TAS2781 },
+ { "TXNW5802", TAS5802 },
+ { "TXNW806M", TAS5806M },
+ { "TXNW806D", TAS5806MD },
+ { "TXNW5815", TAS5815 },
+ { "TXNW5822", TAS5822 },
+ { "TXNW5825", TAS5825 },
+ { "TXNW5827", TAS5827 },
+ { "TXNW5828", TAS5828 },
+ { "TXNW5830", TAS5830 },
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
+#endif
+
+static struct i2c_driver tasdevice_i2c_driver = {
+ .driver = {
+ .name = "tasdev-codec",
+ .of_match_table = of_match_ptr(tasdevice_of_match),
+#ifdef CONFIG_ACPI
+ .acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
+#endif
+ },
+ .probe = tasdevice_i2c_probe,
+ .remove = tasdevice_i2c_remove,
+ .id_table = tasdevice_id,
+};
+
+module_i2c_driver(tasdevice_i2c_driver);
+
+MODULE_AUTHOR("Shenghao Ding <shenghao-ding@ti.com>");
+MODULE_AUTHOR("Kevin Lu <kevin-lu@ti.com>");
+MODULE_DESCRIPTION("ASoC TAS2781 Driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
new file mode 100644
index 000000000000..43b779873b93
--- /dev/null
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -0,0 +1,1347 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC Texas Instruments TAS2783 Audio Smart Amplifier
+//
+// Copyright (C) 2025 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The TAS2783 driver implements a flexible and configurable
+// algo coefficient setting for single TAS2783 chips.
+//
+// Author: Niranjan H Y <niranjanhy@ti.com>
+// Author: Baojun Xu <baojun.xu@ti.com>
+// Author: Kevin Lu <kevin-lu@ti.com>
+
+#include <linux/unaligned.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <sound/pcm_params.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/wait.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/sdw.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/tas2781-tlv.h>
+
+#include "tas2783.h"
+
+#define TIMEOUT_FW_DL_MS (3000)
+#define FW_DL_OFFSET 36
+#define FW_FL_HDR 12
+#define TAS2783_PROBE_TIMEOUT 5000
+#define TAS2783_CALI_GUID EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, \
+ 0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92)
+
+static const u32 tas2783_cali_reg[] = {
+ TAS2783_CAL_R0,
+ TAS2783_CAL_INVR0,
+ TAS2783_CAL_R0LOW,
+ TAS2783_CAL_POWER,
+ TAS2783_CAL_TLIM,
+};
+
+struct bin_header_t {
+ u16 vendor_id;
+ u16 version;
+ u32 file_id;
+ u32 length;
+};
+
+struct calibration_data {
+ u32 is_valid;
+ unsigned long read_sz;
+ u8 data[TAS2783_CALIB_DATA_SZ];
+};
+
+struct tas2783_prv {
+ struct snd_soc_component *component;
+ struct calibration_data cali_data;
+ struct sdw_slave *sdw_peripheral;
+ enum sdw_slave_status status;
+ /* calibration */
+ struct mutex calib_lock;
+ /* pde and firmware download */
+ struct mutex pde_lock;
+ struct regmap *regmap;
+ struct device *dev;
+ struct class *class;
+ struct attribute_group *cal_attr_groups;
+ struct tm tm;
+ u8 rca_binaryname[64];
+ u8 dev_name[32];
+ bool hw_init;
+ /* wq for firmware download */
+ wait_queue_head_t fw_wait;
+ bool fw_dl_task_done;
+ bool fw_dl_success;
+};
+
+static const struct reg_default tas2783_reg_default[] = {
+ {TAS2783_AMP_LEVEL, 0x28},
+ {TASDEV_REG_SDW(0, 0, 0x03), 0x28},
+ {TASDEV_REG_SDW(0, 0, 0x04), 0x21},
+ {TASDEV_REG_SDW(0, 0, 0x05), 0x41},
+ {TASDEV_REG_SDW(0, 0, 0x06), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x07), 0x20},
+ {TASDEV_REG_SDW(0, 0, 0x08), 0x09},
+ {TASDEV_REG_SDW(0, 0, 0x09), 0x02},
+ {TASDEV_REG_SDW(0, 0, 0x0a), 0x0a},
+ {TASDEV_REG_SDW(0, 0, 0x0c), 0x10},
+ {TASDEV_REG_SDW(0, 0, 0x0d), 0x13},
+ {TASDEV_REG_SDW(0, 0, 0x0e), 0xc2},
+ {TASDEV_REG_SDW(0, 0, 0x0f), 0x40},
+ {TASDEV_REG_SDW(0, 0, 0x10), 0x04},
+ {TASDEV_REG_SDW(0, 0, 0x13), 0x13},
+ {TASDEV_REG_SDW(0, 0, 0x14), 0x12},
+ {TASDEV_REG_SDW(0, 0, 0x15), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x16), 0x12},
+ {TASDEV_REG_SDW(0, 0, 0x17), 0x80},
+ {TAS2783_DVC_LVL, 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x1b), 0x61},
+ {TASDEV_REG_SDW(0, 0, 0x1c), 0x36},
+ {TASDEV_REG_SDW(0, 0, 0x1d), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x1f), 0x01},
+ {TASDEV_REG_SDW(0, 0, 0x20), 0x2e},
+ {TASDEV_REG_SDW(0, 0, 0x21), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x34), 0x06},
+ {TASDEV_REG_SDW(0, 0, 0x35), 0xbd},
+ {TASDEV_REG_SDW(0, 0, 0x36), 0xad},
+ {TASDEV_REG_SDW(0, 0, 0x37), 0xa8},
+ {TASDEV_REG_SDW(0, 0, 0x38), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x3b), 0xfc},
+ {TASDEV_REG_SDW(0, 0, 0x3d), 0xdd},
+ {TASDEV_REG_SDW(0, 0, 0x40), 0xf6},
+ {TASDEV_REG_SDW(0, 0, 0x41), 0x14},
+ {TASDEV_REG_SDW(0, 0, 0x5c), 0x19},
+ {TASDEV_REG_SDW(0, 0, 0x5d), 0x80},
+ {TASDEV_REG_SDW(0, 0, 0x63), 0x48},
+ {TASDEV_REG_SDW(0, 0, 0x65), 0x08},
+ {TASDEV_REG_SDW(0, 0, 0x66), 0xb2},
+ {TASDEV_REG_SDW(0, 0, 0x67), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x6a), 0x12},
+ {TASDEV_REG_SDW(0, 0, 0x6b), 0xfb},
+ {TASDEV_REG_SDW(0, 0, 0x6c), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x6d), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x6e), 0x1a},
+ {TASDEV_REG_SDW(0, 0, 0x6f), 0x00},
+ {TASDEV_REG_SDW(0, 0, 0x70), 0x96},
+ {TASDEV_REG_SDW(0, 0, 0x71), 0x02},
+ {TASDEV_REG_SDW(0, 0, 0x73), 0x08},
+ {TASDEV_REG_SDW(0, 0, 0x75), 0xe0},
+ {TASDEV_REG_SDW(0, 0, 0x7a), 0x60},
+ {TASDEV_REG_SDW(0, 0, 0x60), 0x21},
+ {TASDEV_REG_SDW(0, 1, 0x02), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x17), 0xc0},
+ {TASDEV_REG_SDW(0, 1, 0x19), 0x60},
+ {TASDEV_REG_SDW(0, 1, 0x35), 0x75},
+ {TASDEV_REG_SDW(0, 1, 0x3d), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x3e), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x3f), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x40), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x41), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x42), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x43), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x44), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x45), 0x00},
+ {TASDEV_REG_SDW(0, 1, 0x47), 0xab},
+ {TASDEV_REG_SDW(0, 0xfd, 0x0d), 0x0d},
+ {TASDEV_REG_SDW(0, 0xfd, 0x39), 0x00},
+ {TASDEV_REG_SDW(0, 0xfd, 0x3e), 0x00},
+ {TASDEV_REG_SDW(0, 0xfd, 0x45), 0x00},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x01, 1), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x02, 1), 0x9c00},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 1), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x0b, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 3), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 4), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 5), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 2), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 3), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 4), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 8), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 9), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xa), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xb), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xc), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xd), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xe), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xf), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
+};
+
+static const struct reg_sequence tas2783_init_seq[] = {
+ REG_SEQ0(SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0x00), 0x04),
+ REG_SEQ0(0x00800418, 0x00),
+ REG_SEQ0(0x00800419, 0x00),
+ REG_SEQ0(0x0080041a, 0x00),
+ REG_SEQ0(0x0080041b, 0x00),
+ REG_SEQ0(0x00800428, 0x40),
+ REG_SEQ0(0x00800429, 0x00),
+ REG_SEQ0(0x0080042a, 0x00),
+ REG_SEQ0(0x0080042b, 0x00),
+ REG_SEQ0(SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x1, 0x00), 0x00),
+ REG_SEQ0(0x0080005c, 0xD9),
+ REG_SEQ0(0x00800082, 0x20),
+ REG_SEQ0(0x008000a1, 0x00),
+ REG_SEQ0(0x00800097, 0xc8),
+ REG_SEQ0(0x00800099, 0x20),
+ REG_SEQ0(0x008000c7, 0xaa),
+ REG_SEQ0(0x008000b5, 0x74),
+ REG_SEQ0(0x00800082, 0x20),
+ REG_SEQ0(0x00807e8d, 0x0d),
+ REG_SEQ0(0x00807eb9, 0x53),
+ REG_SEQ0(0x00807ebe, 0x42),
+ REG_SEQ0(0x00807ec5, 0x37),
+ REG_SEQ0(0x00800066, 0x92),
+ REG_SEQ0(0x00800003, 0x28),
+ REG_SEQ0(0x00800004, 0x21),
+ REG_SEQ0(0x00800005, 0x41),
+ REG_SEQ0(0x00800006, 0x00),
+ REG_SEQ0(0x00800007, 0x20),
+ REG_SEQ0(0x0080000c, 0x10),
+ REG_SEQ0(0x00800013, 0x08),
+ REG_SEQ0(0x00800015, 0x00),
+ REG_SEQ0(0x00800017, 0x80),
+ REG_SEQ0(0x0080001a, 0x00),
+ REG_SEQ0(0x0080001b, 0x22),
+ REG_SEQ0(0x0080001c, 0x36),
+ REG_SEQ0(0x0080001d, 0x01),
+ REG_SEQ0(0x0080001f, 0x00),
+ REG_SEQ0(0x00800020, 0x2e),
+ REG_SEQ0(0x00800034, 0x06),
+ REG_SEQ0(0x00800035, 0xb9),
+ REG_SEQ0(0x00800036, 0xad),
+ REG_SEQ0(0x00800037, 0xa8),
+ REG_SEQ0(0x00800038, 0x00),
+ REG_SEQ0(0x0080003b, 0xfc),
+ REG_SEQ0(0x0080003d, 0xdd),
+ REG_SEQ0(0x00800040, 0xf6),
+ REG_SEQ0(0x00800041, 0x14),
+ REG_SEQ0(0x0080005c, 0x19),
+ REG_SEQ0(0x0080005d, 0x80),
+ REG_SEQ0(0x00800063, 0x48),
+ REG_SEQ0(0x00800065, 0x08),
+ REG_SEQ0(0x00800067, 0x00),
+ REG_SEQ0(0x0080006a, 0x12),
+ REG_SEQ0(0x0080006b, 0x7b),
+ REG_SEQ0(0x0080006c, 0x00),
+ REG_SEQ0(0x0080006d, 0x00),
+ REG_SEQ0(0x0080006e, 0x1a),
+ REG_SEQ0(0x0080006f, 0x00),
+ REG_SEQ0(0x00800070, 0x96),
+ REG_SEQ0(0x00800071, 0x02),
+ REG_SEQ0(0x00800073, 0x08),
+ REG_SEQ0(0x00800075, 0xe0),
+ REG_SEQ0(0x0080007a, 0x60),
+ REG_SEQ0(0x008000bd, 0x00),
+ REG_SEQ0(0x008000be, 0x00),
+ REG_SEQ0(0x008000bf, 0x00),
+ REG_SEQ0(0x008000c0, 0x00),
+ REG_SEQ0(0x008000c1, 0x00),
+ REG_SEQ0(0x008000c2, 0x00),
+ REG_SEQ0(0x008000c3, 0x00),
+ REG_SEQ0(0x008000c4, 0x00),
+ REG_SEQ0(0x008000c5, 0x00),
+ REG_SEQ0(0x00800008, 0x49),
+ REG_SEQ0(0x00800009, 0x02),
+ REG_SEQ0(0x0080000a, 0x1a),
+ REG_SEQ0(0x0080000d, 0x93),
+ REG_SEQ0(0x0080000e, 0x82),
+ REG_SEQ0(0x0080000f, 0x42),
+ REG_SEQ0(0x00800010, 0x84),
+ REG_SEQ0(0x00800014, 0x0a),
+ REG_SEQ0(0x00800016, 0x00),
+ REG_SEQ0(0x00800060, 0x21),
+};
+
+static int tas2783_sdca_mbq_size(struct device *dev, u32 reg)
+{
+ switch (reg) {
+ case 0x000 ... 0x080: /* Data port 0. */
+ case 0x100 ... 0x140: /* Data port 1. */
+ case 0x200 ... 0x240: /* Data port 2. */
+ case 0x300 ... 0x340: /* Data port 3. */
+ case 0x400 ... 0x440: /* Data port 4. */
+ case 0x500 ... 0x540: /* Data port 5. */
+ case 0x800000 ... 0x803fff: /* Page 0 ~ 127. */
+ case 0x807e80 ... 0x807eff: /* Page 253. */
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23,
+ TAS2783_SDCA_CTL_UDMPU_CLUSTER, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, TAS2783_SDCA_CTL_FU_MUTE,
+ TAS2783_DEVICE_CHANNEL_LEFT):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 2):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 3):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 4):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 8):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 9):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xa):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xb):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xc):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xd):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xe):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xf):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS25, 0x02, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS25, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0):
+ return 1;
+
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x11, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 3):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 4):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 5):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x02, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x0b, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0):
+ return 2;
+
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0):
+ case SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0):
+ return 4;
+
+ default:
+ return 0;
+ }
+}
+
+static bool tas2783_readable_register(struct device *dev, unsigned int reg)
+{
+ return tas2783_sdca_mbq_size(dev, reg) > 0;
+}
+
+static bool tas2783_volatile_register(struct device *dev, u32 reg)
+{
+ switch (reg) {
+ case 0x000 ... 0x080: /* Data port 0. */
+ case 0x100 ... 0x140: /* Data port 1. */
+ case 0x200 ... 0x240: /* Data port 2. */
+ case 0x300 ... 0x340: /* Data port 3. */
+ case 0x400 ... 0x440: /* Data port 4. */
+ case 0x500 ... 0x540: /* Data port 5. */
+ case 0x800001:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config tas_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = tas2783_readable_register,
+ .volatile_reg = tas2783_volatile_register,
+ .reg_defaults = tas2783_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(tas2783_reg_default),
+ .max_register = 0x41008000 + TASDEV_REG_SDW(0xa1, 0x60, 0x7f),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static const struct regmap_sdw_mbq_cfg tas2783_mbq_cfg = {
+ .mbq_size = tas2783_sdca_mbq_size,
+};
+
+static s32 tas2783_digital_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return snd_soc_get_volsw(kcontrol, ucontrol);
+}
+
+static s32 tas2783_digital_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+static s32 tas2783_amp_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return snd_soc_get_volsw(kcontrol, ucontrol);
+}
+
+static s32 tas2783_amp_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new tas2783_snd_controls[] = {
+ SOC_SINGLE_RANGE_EXT_TLV("Amp Volume", TAS2783_AMP_LEVEL,
+ 1, 0, 20, 0, tas2783_amp_getvol,
+ tas2783_amp_putvol, tas2781_amp_tlv),
+ SOC_SINGLE_RANGE_EXT_TLV("Speaker Volume", TAS2783_DVC_LVL,
+ 0, 0, 200, 1, tas2783_digital_getvol,
+ tas2783_digital_putvol, tas2781_dvc_tlv),
+};
+
+static s32 tas2783_validate_calibdata(struct tas2783_prv *tas_dev,
+ u8 *data, u32 size)
+{
+ u32 ts, spk_count, size_calculated;
+ u32 crc_calculated, crc_read, i;
+ u32 *tmp_val;
+ struct tm tm;
+
+ i = 0;
+ tmp_val = (u32 *)data;
+ if (tmp_val[i++] != 2783) {
+ dev_err(tas_dev->dev, "cal data magic number mismatch");
+ return -EINVAL;
+ }
+
+ spk_count = tmp_val[i++];
+ if (spk_count > TAS2783_CALIB_MAX_SPK_COUNT) {
+ dev_err(tas_dev->dev, "cal data spk_count too large");
+ return -EINVAL;
+ }
+
+ ts = tmp_val[i++];
+ time64_to_tm(ts, 0, &tm);
+ dev_dbg(tas_dev->dev, "cal data timestamp: %ld-%d-%d %d:%d:%d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ size_calculated =
+ (spk_count * TAS2783_CALIB_PARAMS * sizeof(u32)) +
+ TAS2783_CALIB_HDR_SZ + TAS2783_CALIB_CRC_SZ;
+ if (size_calculated > TAS2783_CALIB_DATA_SZ) {
+ dev_err(tas_dev->dev, "cali data sz too large");
+ return -EINVAL;
+ } else if (size < size_calculated) {
+ dev_err(tas_dev->dev, "cali data size mismatch calc=%u vs %d\n",
+ size, size_calculated);
+ return -EINVAL;
+ }
+
+ crc_calculated = crc32(~0, data,
+ size_calculated - TAS2783_CALIB_CRC_SZ) ^ ~0;
+ crc_read = tmp_val[(size_calculated - TAS2783_CALIB_CRC_SZ) / sizeof(u32)];
+ if (crc_calculated != crc_read) {
+ dev_err(tas_dev->dev,
+ "calib data integrity check fail, 0x%08x vs 0x%08x\n",
+ crc_calculated, crc_read);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void tas2783_set_calib_params_to_device(struct tas2783_prv *tas_dev, u32 *cali_data)
+{
+ u32 dev_count, offset, i, device_num;
+ u32 reg_value;
+ u8 buf[4];
+
+ dev_count = cali_data[1];
+ offset = 3;
+
+ for (device_num = 0; device_num < dev_count; device_num++) {
+ if (cali_data[offset] != tas_dev->sdw_peripheral->id.unique_id) {
+ offset += TAS2783_CALIB_PARAMS;
+ continue;
+ }
+ offset++;
+
+ for (i = 0; i < ARRAY_SIZE(tas2783_cali_reg); i++) {
+ reg_value = cali_data[offset + i];
+ buf[0] = reg_value >> 24;
+ buf[1] = reg_value >> 16;
+ buf[2] = reg_value >> 8;
+ buf[3] = reg_value & 0xff;
+ regmap_bulk_write(tas_dev->regmap, tas2783_cali_reg[i],
+ buf, sizeof(u32));
+ }
+ break;
+ }
+
+ if (device_num == dev_count)
+ dev_err(tas_dev->dev, "device not found\n");
+ else
+ dev_dbg(tas_dev->dev, "calib data update done\n");
+}
+
+static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev)
+{
+ efi_guid_t efi_guid = TAS2783_CALI_GUID;
+ u32 attr, i, *tmp_val;
+ unsigned long size;
+ s32 ret;
+ efi_status_t status;
+ static efi_char16_t efi_names[][32] = {
+ L"SmartAmpCalibrationData", L"CALI_DATA"};
+
+ tmp_val = (u32 *)tas_dev->cali_data.data;
+ attr = 0;
+
+ /*
+ * In some cases, the calibration is performed in Windows,
+ * and data was saved in UEFI. Linux can access it.
+ */
+ for (i = 0; i < ARRAY_SIZE(efi_names); i++) {
+ size = 0;
+ status = efi.get_variable(efi_names[i], &efi_guid, &attr,
+ &size, NULL);
+ if (size > TAS2783_CALIB_DATA_SZ) {
+ dev_err(tas_dev->dev, "cali data too large\n");
+ break;
+ }
+
+ tas_dev->cali_data.read_sz = size;
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ status = efi.get_variable(efi_names[i], &efi_guid, &attr,
+ &tas_dev->cali_data.read_sz,
+ tas_dev->cali_data.data);
+ dev_dbg(tas_dev->dev, "cali get %lu bytes result:%ld\n",
+ tas_dev->cali_data.read_sz, status);
+ }
+ if (status == EFI_SUCCESS)
+ break;
+ }
+
+ if (status != EFI_SUCCESS) {
+ /* Failed got calibration data from EFI. */
+ dev_dbg(tas_dev->dev, "No calibration data in UEFI.");
+ return 0;
+ }
+
+ mutex_lock(&tas_dev->calib_lock);
+ ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data,
+ tas_dev->cali_data.read_sz);
+ if (!ret)
+ tas2783_set_calib_params_to_device(tas_dev, tmp_val);
+ mutex_unlock(&tas_dev->calib_lock);
+
+ return ret;
+}
+
+static s32 read_header(const u8 *data, struct bin_header_t *hdr)
+{
+ hdr->vendor_id = get_unaligned_le16(&data[0]);
+ hdr->file_id = get_unaligned_le32(&data[2]);
+ hdr->version = get_unaligned_le16(&data[6]);
+ hdr->length = get_unaligned_le32(&data[8]);
+ return 12;
+}
+
+static void tas2783_fw_ready(const struct firmware *fmw, void *context)
+{
+ struct tas2783_prv *tas_dev =
+ (struct tas2783_prv *)context;
+ const u8 *buf = NULL;
+ s32 offset = 0, img_sz, file_blk_size, ret;
+ struct bin_header_t hdr;
+
+ if (!fmw || !fmw->data) {
+ /* No firmware binary, devices will work in ROM mode. */
+ dev_err(tas_dev->dev,
+ "Failed to read %s, no side-effect on driver running\n",
+ tas_dev->rca_binaryname);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ img_sz = fmw->size;
+ buf = fmw->data;
+ offset += FW_DL_OFFSET;
+ if (offset >= (img_sz - FW_FL_HDR)) {
+ dev_err(tas_dev->dev,
+ "firmware is too small");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ mutex_lock(&tas_dev->pde_lock);
+ while (offset < (img_sz - FW_FL_HDR)) {
+ memset(&hdr, 0, sizeof(hdr));
+ offset += read_header(&buf[offset], &hdr);
+ dev_dbg(tas_dev->dev,
+ "vndr=%d, file=%d, version=%d, len=%d, off=%d\n",
+ hdr.vendor_id, hdr.file_id, hdr.version,
+ hdr.length, offset);
+ /* size also includes the header */
+ file_blk_size = hdr.length - FW_FL_HDR;
+
+ /* make sure that enough data is there */
+ if (offset + file_blk_size > img_sz) {
+ ret = -EINVAL;
+ dev_err(tas_dev->dev,
+ "corrupt firmware file");
+ break;
+ }
+
+ switch (hdr.file_id) {
+ case 0:
+ ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral,
+ PRAM_ADDR_START, file_blk_size,
+ &buf[offset]);
+ if (ret < 0)
+ dev_err(tas_dev->dev,
+ "PRAM update failed: %d", ret);
+ break;
+
+ case 1:
+ ret = sdw_nwrite_no_pm(tas_dev->sdw_peripheral,
+ YRAM_ADDR_START, file_blk_size,
+ &buf[offset]);
+ if (ret < 0)
+ dev_err(tas_dev->dev,
+ "YRAM update failed: %d", ret);
+
+ break;
+
+ default:
+ ret = -EINVAL;
+ dev_err(tas_dev->dev, "Unsupported file");
+ break;
+ }
+
+ if (ret == 0)
+ offset += file_blk_size;
+ else
+ break;
+ }
+ mutex_unlock(&tas_dev->pde_lock);
+ if (!ret)
+ tas2783_update_calibdata(tas_dev);
+
+out:
+ if (!ret)
+ tas_dev->fw_dl_success = true;
+ tas_dev->fw_dl_task_done = true;
+ wake_up(&tas_dev->fw_wait);
+ if (fmw)
+ release_firmware(fmw);
+}
+
+static inline s32 tas_clear_latch(struct tas2783_prv *priv)
+{
+ return regmap_update_bits(priv->regmap,
+ TASDEV_REG_SDW(0, 0, 0x5c),
+ 0x04, 0x04);
+}
+
+static s32 tas_fu21_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, s32 event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct tas2783_prv *tas_dev = snd_soc_component_get_drvdata(component);
+ s32 mute;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ mute = 0;
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ mute = 1;
+ break;
+ }
+
+ return sdw_write_no_pm(tas_dev->sdw_peripheral,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21,
+ TAS2783_SDCA_CTL_FU_MUTE, 1), mute);
+}
+
+static s32 tas_fu23_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, s32 event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct tas2783_prv *tas_dev = snd_soc_component_get_drvdata(component);
+ s32 mute;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ mute = 0;
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ mute = 1;
+ break;
+ }
+
+ return sdw_write_no_pm(tas_dev->sdw_peripheral,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23,
+ TAS2783_SDCA_CTL_FU_MUTE, 1), mute);
+}
+
+static const struct snd_soc_dapm_widget tas_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_DAC_E("FU21", NULL, SND_SOC_NOPM, 0, 0, tas_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU23", NULL, SND_SOC_NOPM, 0, 0, tas_fu23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_OUTPUT("SPK"),
+ SND_SOC_DAPM_INPUT("DMIC"),
+};
+
+static const struct snd_soc_dapm_route tas_audio_map[] = {
+ {"FU21", NULL, "ASI"},
+ {"SPK", NULL, "FU21"},
+ {"FU23", NULL, "ASI"},
+ {"SPK", NULL, "FU23"},
+ {"ASI OUT", NULL, "DMIC"},
+};
+
+static s32 tas_set_sdw_stream(struct snd_soc_dai *dai,
+ void *sdw_stream, s32 direction)
+{
+ if (!sdw_stream)
+ return 0;
+
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void tas_sdw_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct tas2783_prv *tas_dev =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config = {0};
+ struct sdw_port_config port_config = {0};
+ struct sdw_stream_runtime *sdw_stream;
+ struct sdw_slave *sdw_peripheral = tas_dev->sdw_peripheral;
+ s32 ret, retry = 3;
+
+ if (!tas_dev->fw_dl_success) {
+ dev_err(tas_dev->dev, "error playback without fw download");
+ return -EINVAL;
+ }
+
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ if (!sdw_stream)
+ return -EINVAL;
+
+ ret = tas_clear_latch(tas_dev);
+ if (ret)
+ dev_err(tas_dev->dev,
+ "clear latch failed, err=%d", ret);
+
+ mutex_lock(&tas_dev->pde_lock);
+ /*
+ * Sometimes, there is error returned during power on.
+ * So added retry logic to ensure power on so that
+ * port prepare succeeds
+ */
+ do {
+ ret = regmap_write(tas_dev->regmap,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
+ TAS2783_SDCA_POW_STATE_ON);
+ if (!ret)
+ break;
+ usleep_range(2000, 2200);
+ } while (retry--);
+ mutex_unlock(&tas_dev->pde_lock);
+ if (ret)
+ return ret;
+
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params,
+ &stream_config, &port_config);
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ port_config.num = 1;
+ else
+ port_config.num = 2;
+
+ ret = sdw_stream_add_slave(sdw_peripheral,
+ &stream_config, &port_config, 1, sdw_stream);
+ if (ret)
+ dev_err(dai->dev, "Unable to configure port\n");
+
+ return ret;
+}
+
+static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ s32 ret;
+ struct snd_soc_component *component = dai->component;
+ struct tas2783_prv *tas_dev =
+ snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ sdw_stream_remove_slave(tas_dev->sdw_peripheral, sdw_stream);
+
+ mutex_lock(&tas_dev->pde_lock);
+ ret = regmap_write(tas_dev->regmap,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
+ TAS2783_SDCA_POW_STATE_OFF);
+ mutex_unlock(&tas_dev->pde_lock);
+
+ return ret;
+}
+
+static const struct snd_soc_dai_ops tas_dai_ops = {
+ .hw_params = tas_sdw_hw_params,
+ .hw_free = tas_sdw_pcm_hw_free,
+ .set_stream = tas_set_sdw_stream,
+ .shutdown = tas_sdw_shutdown,
+};
+
+static struct snd_soc_dai_driver tas_dai_driver[] = {
+ {
+ .name = "tas2783-codec",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = TAS2783_DEVICE_RATES,
+ .formats = TAS2783_DEVICE_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = TAS2783_DEVICE_RATES,
+ .formats = TAS2783_DEVICE_FORMATS,
+ },
+ .ops = &tas_dai_ops,
+ .symmetric_rate = 1,
+ },
+};
+
+static s32 tas_component_probe(struct snd_soc_component *component)
+{
+ struct tas2783_prv *tas_dev =
+ snd_soc_component_get_drvdata(component);
+
+ tas_dev->component = component;
+ tas25xx_register_misc(tas_dev->sdw_peripheral);
+
+ return 0;
+}
+
+static void tas_component_remove(struct snd_soc_component *codec)
+{
+ struct tas2783_prv *tas_dev =
+ snd_soc_component_get_drvdata(codec);
+ tas25xx_deregister_misc();
+ tas_dev->component = NULL;
+}
+
+static const struct snd_soc_component_driver soc_codec_driver_tasdevice = {
+ .probe = tas_component_probe,
+ .remove = tas_component_remove,
+ .controls = tas2783_snd_controls,
+ .num_controls = ARRAY_SIZE(tas2783_snd_controls),
+ .dapm_widgets = tas_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tas_dapm_widgets),
+ .dapm_routes = tas_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(tas_audio_map),
+ .idle_bias_on = 1,
+ .endianness = 1,
+};
+
+static s32 tas_init(struct tas2783_prv *tas_dev)
+{
+ s32 ret;
+
+ dev_set_drvdata(tas_dev->dev, tas_dev);
+ ret = devm_snd_soc_register_component(tas_dev->dev,
+ &soc_codec_driver_tasdevice,
+ tas_dai_driver,
+ ARRAY_SIZE(tas_dai_driver));
+ if (ret) {
+ dev_err(tas_dev->dev, "%s: codec register error:%d.\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(tas_dev->dev, 3000);
+ pm_runtime_use_autosuspend(tas_dev->dev);
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(tas_dev->dev);
+ pm_runtime_enable(tas_dev->dev);
+
+ return ret;
+}
+
+static s32 tas_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ s32 nval;
+ s32 i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask =
+ SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists */
+ prop->source_ports = 0x04; /* BITMAP: 00000100 */
+ prop->sink_ports = 0x2; /* BITMAP: 00000010 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = false;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = false;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 200;
+
+ return 0;
+}
+
+static s32 tas2783_sdca_dev_suspend(struct device *dev)
+{
+ struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+
+ if (!tas_dev->hw_init)
+ return 0;
+
+ regcache_cache_only(tas_dev->regmap, true);
+ return 0;
+}
+
+static s32 tas2783_sdca_dev_system_suspend(struct device *dev)
+{
+ return tas2783_sdca_dev_suspend(dev);
+}
+
+static s32 tas2783_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+ unsigned long t;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ t = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(TAS2783_PROBE_TIMEOUT));
+ if (!t) {
+ dev_err(&slave->dev, "resume: initialization timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+ return -ETIMEDOUT;
+ }
+
+ slave->unattach_request = 0;
+
+regmap_sync:
+ regcache_cache_only(tas_dev->regmap, false);
+ regcache_sync(tas_dev->regmap);
+ return 0;
+}
+
+static const struct dev_pm_ops tas2783_sdca_pm = {
+ SYSTEM_SLEEP_PM_OPS(tas2783_sdca_dev_system_suspend, tas2783_sdca_dev_resume)
+ RUNTIME_PM_OPS(tas2783_sdca_dev_suspend, tas2783_sdca_dev_resume, NULL)
+};
+
+static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+ s32 ret;
+ u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
+
+ if (tas_dev->hw_init)
+ return 0;
+
+ tas_dev->fw_dl_task_done = false;
+ tas_dev->fw_dl_success = false;
+ scnprintf(tas_dev->rca_binaryname, sizeof(tas_dev->rca_binaryname),
+ "tas2783-%01x.bin", unique_id);
+
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
+ tas_dev->rca_binaryname, tas_dev->dev,
+ GFP_KERNEL, tas_dev, tas2783_fw_ready);
+ if (ret) {
+ dev_err(tas_dev->dev,
+ "firmware request failed for uid=%d, ret=%d\n",
+ unique_id, ret);
+ return ret;
+ }
+
+ ret = wait_event_timeout(tas_dev->fw_wait, tas_dev->fw_dl_task_done,
+ msecs_to_jiffies(TIMEOUT_FW_DL_MS));
+ if (!ret) {
+ dev_err(tas_dev->dev, "fw request, wait_event timeout\n");
+ ret = -EAGAIN;
+ } else {
+ ret = regmap_multi_reg_write(tas_dev->regmap, tas2783_init_seq,
+ ARRAY_SIZE(tas2783_init_seq));
+ tas_dev->hw_init = true;
+ }
+
+ return ret;
+}
+
+static s32 tas_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
+ struct device *dev = &slave->dev;
+
+ dev_dbg(dev, "Peripheral status = %s",
+ status == SDW_SLAVE_UNATTACHED ? "unattached" :
+ status == SDW_SLAVE_ATTACHED ? "attached" : "alert");
+
+ tas_dev->status = status;
+ if (status == SDW_SLAVE_UNATTACHED)
+ tas_dev->hw_init = false;
+
+ /* Perform initialization only if slave status
+ * is present and hw_init flag is false
+ */
+ if (tas_dev->hw_init || tas_dev->status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* updated the cache data to device */
+ regcache_cache_only(tas_dev->regmap, false);
+ regcache_sync(tas_dev->regmap);
+
+ /* perform I/O transfers required for Slave initialization */
+ return tas_io_init(&slave->dev, slave);
+}
+
+static const struct sdw_slave_ops tas_sdw_ops = {
+ .read_prop = tas_read_prop,
+ .update_status = tas_update_status,
+};
+
+static void tas_remove(struct tas2783_prv *tas_dev)
+{
+ snd_soc_unregister_component(tas_dev->dev);
+}
+
+static s32 tas_sdw_probe(struct sdw_slave *peripheral,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+ struct device *dev = &peripheral->dev;
+ struct tas2783_prv *tas_dev;
+
+ tas_dev = devm_kzalloc(dev, sizeof(*tas_dev), GFP_KERNEL);
+ if (!tas_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "Failed devm_kzalloc");
+
+ tas_dev->dev = dev;
+ tas_dev->sdw_peripheral = peripheral;
+ tas_dev->hw_init = false;
+ mutex_init(&tas_dev->calib_lock);
+ mutex_init(&tas_dev->pde_lock);
+
+ init_waitqueue_head(&tas_dev->fw_wait);
+ dev_set_drvdata(dev, tas_dev);
+ regmap = devm_regmap_init_sdw_mbq_cfg(&peripheral->dev,
+ peripheral,
+ &tas_regmap,
+ &tas2783_mbq_cfg);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed devm_regmap_init_sdw.");
+
+ /* keep in cache until the device is fully initialized */
+ regcache_cache_only(regmap, true);
+ tas_dev->regmap = regmap;
+ return tas_init(tas_dev);
+}
+
+static s32 tas_sdw_remove(struct sdw_slave *peripheral)
+{
+ struct tas2783_prv *tas_dev = dev_get_drvdata(&peripheral->dev);
+
+ pm_runtime_disable(tas_dev->dev);
+ tas_remove(tas_dev);
+ mutex_destroy(&tas_dev->calib_lock);
+ mutex_destroy(&tas_dev->pde_lock);
+ dev_set_drvdata(&peripheral->dev, NULL);
+
+ return 0;
+}
+
+static const struct sdw_device_id tas_sdw_id[] = {
+ /* chipid for the TAS2783 is 0x0000 */
+ SDW_SLAVE_ENTRY(0x0102, 0x0000, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, tas_sdw_id);
+
+static struct sdw_driver tas_sdw_driver = {
+ .driver = {
+ .name = "slave-tas2783",
+ .pm = pm_ptr(&tas2783_sdca_pm),
+ },
+ .probe = tas_sdw_probe,
+ .remove = tas_sdw_remove,
+ .ops = &tas_sdw_ops,
+ .id_table = tas_sdw_id,
+};
+module_sdw_driver(tas_sdw_driver);
+
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("ASoC TAS2783 SoundWire Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2783.h b/sound/soc/codecs/tas2783.h
new file mode 100644
index 000000000000..794333e0a350
--- /dev/null
+++ b/sound/soc/codecs/tas2783.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * ALSA SoC Texas Instruments TAS2783 Audio Smart Amplifier
+ *
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ * https://www.ti.com
+ *
+ * The TAS2783 driver implements a flexible and configurable
+ * algo coefficient setting for single TAS2783 chips.
+ *
+ * Author: Niranjan H Y <niranjanhy@ti.com>
+ * Author: Baojun Xu <baojun.xu@ti.com>
+ */
+#include <linux/workqueue.h>
+
+#ifndef __TAS2783_H__
+#define __TAS2783_H__
+
+#define TAS2783_DEVICE_RATES (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_88200)
+#define TAS2783_DEVICE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* book, page, register */
+#define TASDEV_REG_SDW(book, page, reg) (((book) * 256 * 128) + \
+ 0x800000 + ((page) * 128) + (reg))
+
+/* Volume control */
+#define TAS2783_DVC_LVL TASDEV_REG_SDW(0x0, 0x00, 0x1A)
+#define TAS2783_AMP_LEVEL TASDEV_REG_SDW(0x0, 0x00, 0x03)
+#define TAS2783_AMP_LEVEL_MASK GENMASK(5, 1)
+
+#define PRAM_ADDR_START TASDEV_REG_SDW(0x8c, 0x01, 0x8)
+#define PRAM_ADDR_END TASDEV_REG_SDW(0x8c, 0xff, 0x7f)
+#define YRAM_ADDR_START TASDEV_REG_SDW(0x00, 0x02, 0x8)
+#define YRAM_ADDR_END TASDEV_REG_SDW(0x00, 0x37, 0x7f)
+
+/* Calibration data */
+#define TAS2783_CAL_R0 TASDEV_REG_SDW(0, 0x16, 0x4C)
+#define TAS2783_CAL_INVR0 TASDEV_REG_SDW(0, 0x16, 0x5C)
+#define TAS2783_CAL_R0LOW TASDEV_REG_SDW(0, 0x16, 0x64)
+#define TAS2783_CAL_POWER TASDEV_REG_SDW(0, 0x15, 0x44)
+#define TAS2783_CAL_TLIM TASDEV_REG_SDW(0, 0x17, 0x58)
+
+/* TAS2783 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x01
+
+/* TAS2783 SDCA entity */
+
+#define TAS2783_SDCA_ENT_FU21 0x01
+#define TAS2783_SDCA_ENT_FU23 0x02
+#define TAS2783_SDCA_ENT_FU26 0x03
+#define TAS2783_SDCA_ENT_XU22 0x04
+#define TAS2783_SDCA_ENT_CS24 0x05
+#define TAS2783_SDCA_ENT_CS21 0x06
+#define TAS2783_SDCA_ENT_CS25 0x07
+#define TAS2783_SDCA_ENT_CS26 0x08
+#define TAS2783_SDCA_ENT_CS28 0x09
+#define TAS2783_SDCA_ENT_PDE23 0x0C
+#define TAS2783_SDCA_ENT_UDMPU23 0x0E
+#define TAS2783_SDCA_ENT_SAPU29 0x0F
+#define TAS2783_SDCA_ENT_PPU21 0x10
+#define TAS2783_SDCA_ENT_PPU26 0x11
+#define TAS2783_SDCA_ENT_TG23 0x12
+#define TAS2783_SDCA_ENT_IT21 0x13
+#define TAS2783_SDCA_ENT_IT29 0x14
+#define TAS2783_SDCA_ENT_IT26 0x15
+#define TAS2783_SDCA_ENT_IT28 0x16
+#define TAS2783_SDCA_ENT_OT24 0x17
+#define TAS2783_SDCA_ENT_OT23 0x18
+#define TAS2783_SDCA_ENT_OT25 0x19
+#define TAS2783_SDCA_ENT_OT28 0x1A
+#define TAS2783_SDCA_ENT_MU26 0x1b
+#define TAS2783_SDCA_ENT_OT127 0x1E
+#define TAS2783_SDCA_ENT_FU127 0x1F
+#define TAS2783_SDCA_ENT_CS127 0x20
+#define TAS2783_SDCA_ENT_MFPU21 0x22
+#define TAS2783_SDCA_ENT_MFPU26 0x23
+
+/* TAS2783 SDCA control */
+#define TAS2783_SDCA_CTL_REQ_POW_STATE 0x01
+#define TAS2783_SDCA_CTL_FU_MUTE 0x01
+#define TAS2783_SDCA_CTL_UDMPU_CLUSTER 0x10
+
+#define TAS2783_DEVICE_CHANNEL_LEFT 1
+#define TAS2783_DEVICE_CHANNEL_RIGHT 2
+
+#define TAS2783_SDCA_POW_STATE_ON 0
+#define TAS2783_SDCA_POW_STATE_OFF 3
+
+/* calibration data */
+#define TAS2783_CALIB_PARAMS 6 /* 5 + 1 unique id */
+#define TAS2783_CALIB_MAX_SPK_COUNT 8
+#define TAS2783_CALIB_HDR_SZ 12
+#define TAS2783_CALIB_CRC_SZ 4
+#define TAS2783_CALIB_DATA_SZ ((TAS2783_CALIB_HDR_SZ) + TAS2783_CALIB_CRC_SZ + \
+ ((TAS2783_CALIB_PARAMS) * 4 * (TAS2783_CALIB_MAX_SPK_COUNT)))
+
+#if IS_ENABLED(CONFIG_SND_SOC_TAS2783_UTIL)
+int32_t tas25xx_register_misc(struct sdw_slave *peripheral);
+int32_t tas25xx_deregister_misc(void);
+#else
+static void tas25xx_register_misc(struct sdw_slave *peripheral) {}
+static void tas25xx_deregister_misc(void) {}
+#endif
+
+#endif /*__TAS2783_H__ */
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 60e59e993ba6..12bf6a89dbd8 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -24,14 +24,13 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -246,7 +245,7 @@ struct tas5086_private {
/* Current sample rate for de-emphasis control */
int rate;
/* GPIO driving Reset pin, if any */
- int gpio_nreset;
+ struct gpio_desc *reset;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
@@ -273,7 +272,7 @@ static int tas5086_set_deemph(struct snd_soc_component *component)
static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = priv->deemph;
@@ -284,7 +283,7 @@ static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
priv->deemph = ucontrol->value.integer.value[0];
@@ -462,11 +461,11 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
static void tas5086_reset(struct tas5086_private *priv)
{
- if (gpio_is_valid(priv->gpio_nreset)) {
+ if (priv->reset) {
/* Reset codec - minimum assertion time is 400ns */
- gpio_direction_output(priv->gpio_nreset, 0);
+ gpiod_set_value_cansleep(priv->reset, 1);
udelay(1);
- gpio_set_value(priv->gpio_nreset, 1);
+ gpiod_set_value_cansleep(priv->reset, 0);
/* Codec needs ~15ms to wake up */
msleep(15);
@@ -867,9 +866,10 @@ static void tas5086_remove(struct snd_soc_component *component)
{
struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(priv->gpio_nreset))
+ if (priv->reset) {
/* Set codec to the reset state */
- gpio_set_value(priv->gpio_nreset, 0);
+ gpiod_set_value_cansleep(priv->reset, 1);
+ }
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
};
@@ -891,7 +891,7 @@ static const struct snd_soc_component_driver soc_component_dev_tas5086 = {
};
static const struct i2c_device_id tas5086_i2c_id[] = {
- { "tas5086", 0 },
+ { "tas5086" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
@@ -914,7 +914,6 @@ static int tas5086_i2c_probe(struct i2c_client *i2c)
{
struct tas5086_private *priv;
struct device *dev = &i2c->dev;
- int gpio_nreset = -EINVAL;
int i, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -940,16 +939,11 @@ static int tas5086_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, priv);
- if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) {
- struct device_node *of_node = dev->of_node;
- gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0);
- }
-
- if (gpio_is_valid(gpio_nreset))
- if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
- gpio_nreset = -EINVAL;
-
- priv->gpio_nreset = gpio_nreset;
+ /* Request line asserted */
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+ gpiod_set_consumer_name(priv->reset, "TAS5086 Reset");
ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
if (ret < 0) {
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index 1756edb35961..19ccf8641e16 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -20,14 +20,14 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/stddef.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "tas571x.h"
@@ -241,7 +241,7 @@ static int tas571x_coefficient_info(struct snd_kcontrol *kcontrol,
static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct i2c_client *i2c = to_i2c_client(component->dev);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
@@ -253,7 +253,7 @@ static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct i2c_client *i2c = to_i2c_client(component->dev);
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
@@ -322,6 +322,7 @@ static int tas571x_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct tas571x_private *priv = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -330,7 +331,7 @@ static int tas571x_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
if (!IS_ERR(priv->mclk)) {
ret = clk_prepare_enable(priv->mclk);
if (ret) {
@@ -718,6 +719,69 @@ static const struct regmap_config tas5721_regmap_config = {
.volatile_table = &tas571x_volatile_regs,
};
+static const struct snd_kcontrol_new tas5733_controls[] = {
+ /* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */
+ SOC_SINGLE_TLV("Master Volume",
+ TAS571X_MVOL_REG, 1, 0x1ff, 1,
+ tas5717_volume_tlv),
+ SOC_DOUBLE_R_TLV("Speaker Volume",
+ TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG,
+ 1, 0x1ff, 1, tas5717_volume_tlv),
+ SOC_DOUBLE("Speaker Switch",
+ TAS571X_SOFT_MUTE_REG,
+ TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+ 1, 1),
+
+ SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
+ TAS5717_CH1_LEFT_CH_MIX_REG,
+ TAS5717_CH1_RIGHT_CH_MIX_REG,
+ 16, 0, 0x80, 0),
+
+ SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
+ TAS5717_CH2_LEFT_CH_MIX_REG,
+ TAS5717_CH2_RIGHT_CH_MIX_REG,
+ 16, 0, 0x80, 0),
+
+ /*
+ * The biquads are named according to the register names.
+ * Please note that TI's TAS57xx Graphical Development Environment
+ * tool names them different.
+ */
+ BIQUAD_COEFS("CH1 - Biquad 0", TAS5733_CH1_BQ0_REG),
+ BIQUAD_COEFS("CH1 - Biquad 1", TAS5733_CH1_BQ1_REG),
+ BIQUAD_COEFS("CH1 - Biquad 2", TAS5733_CH1_BQ2_REG),
+ BIQUAD_COEFS("CH1 - Biquad 3", TAS5733_CH1_BQ3_REG),
+ BIQUAD_COEFS("CH1 - Biquad 4", TAS5733_CH1_BQ4_REG),
+ BIQUAD_COEFS("CH1 - Biquad 5", TAS5733_CH1_BQ5_REG),
+ BIQUAD_COEFS("CH1 - Biquad 6", TAS5733_CH1_BQ6_REG),
+ BIQUAD_COEFS("CH1 - Biquad 7", TAS5733_CH1_BQ7_REG),
+ BIQUAD_COEFS("CH1 - Biquad 8", TAS5733_CH1_BQ8_REG),
+ BIQUAD_COEFS("CH1 - Biquad 9", TAS5733_CH1_BQ9_REG),
+ BIQUAD_COEFS("CH1 - Biquad 10", TAS5733_CH1_BQ10_REG),
+
+ BIQUAD_COEFS("CH2 - Biquad 0", TAS5733_CH2_BQ0_REG),
+ BIQUAD_COEFS("CH2 - Biquad 1", TAS5733_CH2_BQ1_REG),
+ BIQUAD_COEFS("CH2 - Biquad 2", TAS5733_CH2_BQ2_REG),
+ BIQUAD_COEFS("CH2 - Biquad 3", TAS5733_CH2_BQ3_REG),
+ BIQUAD_COEFS("CH2 - Biquad 4", TAS5733_CH2_BQ4_REG),
+ BIQUAD_COEFS("CH2 - Biquad 5", TAS5733_CH2_BQ5_REG),
+ BIQUAD_COEFS("CH2 - Biquad 6", TAS5733_CH2_BQ6_REG),
+ BIQUAD_COEFS("CH2 - Biquad 7", TAS5733_CH2_BQ7_REG),
+ BIQUAD_COEFS("CH2 - Biquad 8", TAS5733_CH2_BQ8_REG),
+ BIQUAD_COEFS("CH2 - Biquad 9", TAS5733_CH2_BQ9_REG),
+ BIQUAD_COEFS("CH2 - Biquad 10", TAS5733_CH2_BQ10_REG),
+
+ BIQUAD_COEFS("CH1 - Cross Biquad 0", TAS5733_CH1_CBQ0_REG),
+ BIQUAD_COEFS("CH1 - Cross Biquad 1", TAS5733_CH1_CBQ1_REG),
+ BIQUAD_COEFS("CH1 - Cross Biquad 2", TAS5733_CH1_CBQ2_REG),
+ BIQUAD_COEFS("CH1 - Cross Biquad 3", TAS5733_CH1_CBQ3_REG),
+
+ BIQUAD_COEFS("CH2 - Cross Biquad 0", TAS5733_CH2_CBQ0_REG),
+ BIQUAD_COEFS("CH2 - Cross Biquad 1", TAS5733_CH2_CBQ1_REG),
+ BIQUAD_COEFS("CH2 - Cross Biquad 2", TAS5733_CH2_CBQ2_REG),
+ BIQUAD_COEFS("CH2 - Cross Biquad 3", TAS5733_CH2_CBQ3_REG),
+};
+
static const char *const tas5733_supply_names[] = {
"AVDD",
"DVDD",
@@ -770,12 +834,62 @@ static const struct regmap_config tas5733_regmap_config = {
static const struct tas571x_chip tas5733_chip = {
.supply_names = tas5733_supply_names,
.num_supply_names = ARRAY_SIZE(tas5733_supply_names),
- .controls = tas5717_controls,
- .num_controls = ARRAY_SIZE(tas5717_controls),
+ .controls = tas5733_controls,
+ .num_controls = ARRAY_SIZE(tas5733_controls),
.regmap_config = &tas5733_regmap_config,
.vol_reg_size = 2,
};
+static const struct reg_default tas5753_reg_defaults[] = {
+ {TAS571X_CLK_CTRL_REG, 0x6c},
+ {TAS571X_DEV_ID_REG, 0x41},
+ {TAS571X_ERR_STATUS_REG, 0x00},
+ {TAS571X_SYS_CTRL_1_REG, 0xa0},
+ {TAS571X_SDI_REG, 0x05},
+ {TAS571X_SYS_CTRL_2_REG, 0x40},
+ {TAS571X_SOFT_MUTE_REG, 0x00},
+ {TAS571X_MVOL_REG, 0x03ff},
+ {TAS571X_CH1_VOL_REG, 0x00c0},
+ {TAS571X_CH2_VOL_REG, 0x00c0},
+ {TAS571X_CH3_VOL_REG, 0x00c0},
+ {TAS571X_VOL_CFG_REG, 0xf0},
+ {TAS571X_MODULATION_LIMIT_REG, 0x01},
+ {TAS571X_IC_DELAY_CH1_REG, 0xac},
+ {TAS571X_IC_DELAY_CH2_REG, 0x54},
+ {TAS571X_IC_DELAY_CH3_REG, 0xac},
+ {TAS571X_IC_DELAY_CH4_REG, 0x54},
+ {TAS571X_OSC_TRIM_REG, 0x82},
+ {TAS571X_BKND_ERR_REG, 0x57},
+ {TAS571X_INPUT_MUX_REG, 0x00017772},
+ {TAS571X_PWM_MUX_REG, 0x01021345},
+ {TAS5717_CH1_RIGHT_CH_MIX_REG, 0x00},
+ {TAS5717_CH1_LEFT_CH_MIX_REG, 0x800000},
+ {TAS5717_CH2_LEFT_CH_MIX_REG, 0x00},
+ {TAS5717_CH2_RIGHT_CH_MIX_REG, 0x800000},
+};
+
+static const struct regmap_config tas5753_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .max_register = 0xff,
+ .reg_read = tas571x_reg_read,
+ .reg_write = tas571x_reg_write,
+ .reg_defaults = tas5753_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5753_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .wr_table = &tas571x_write_regs,
+ .volatile_table = &tas571x_volatile_regs,
+};
+
+static const struct tas571x_chip tas5753_chip = {
+ .supply_names = tas5721_supply_names,
+ .num_supply_names = ARRAY_SIZE(tas5721_supply_names),
+ .controls = tas5733_controls,
+ .num_controls = ARRAY_SIZE(tas5733_controls),
+ .regmap_config = &tas5753_regmap_config,
+ .vol_reg_size = 2,
+};
+
static const struct tas571x_chip tas5721_chip = {
.supply_names = tas5721_supply_names,
.num_supply_names = ARRAY_SIZE(tas5721_supply_names),
@@ -829,14 +943,10 @@ static struct snd_soc_dai_driver tas571x_dai = {
.ops = &tas571x_dai_ops,
};
-static const struct of_device_id tas571x_of_match[] __maybe_unused;
-static const struct i2c_device_id tas571x_i2c_id[];
-
static int tas571x_i2c_probe(struct i2c_client *client)
{
struct tas571x_private *priv;
struct device *dev = &client->dev;
- const struct of_device_id *of_id;
int i, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -844,14 +954,7 @@ static int tas571x_i2c_probe(struct i2c_client *client)
return -ENOMEM;
i2c_set_clientdata(client, priv);
- of_id = of_match_device(tas571x_of_match, dev);
- if (of_id)
- priv->chip = of_id->data;
- else {
- const struct i2c_device_id *id =
- i2c_match_id(tas571x_i2c_id, client);
- priv->chip = (void *) id->driver_data;
- }
+ priv->chip = i2c_get_match_data(client);
priv->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) {
@@ -955,6 +1058,7 @@ static const struct of_device_id tas571x_of_match[] __maybe_unused = {
{ .compatible = "ti,tas5719", .data = &tas5717_chip, },
{ .compatible = "ti,tas5721", .data = &tas5721_chip, },
{ .compatible = "ti,tas5733", .data = &tas5733_chip, },
+ { .compatible = "ti,tas5753", .data = &tas5753_chip, },
{ }
};
MODULE_DEVICE_TABLE(of, tas571x_of_match);
@@ -966,6 +1070,7 @@ static const struct i2c_device_id tas571x_i2c_id[] = {
{ "tas5719", (kernel_ulong_t) &tas5717_chip },
{ "tas5721", (kernel_ulong_t) &tas5721_chip },
{ "tas5733", (kernel_ulong_t) &tas5733_chip },
+ { "tas5753", (kernel_ulong_t) &tas5753_chip },
{ }
};
MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id);
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h
index 5340d3bec31d..2b3eff4023b9 100644
--- a/sound/soc/codecs/tas571x.h
+++ b/sound/soc/codecs/tas571x.h
@@ -104,4 +104,38 @@
#define TAS5717_CH2_LEFT_CH_MIX_REG 0x76
#define TAS5717_CH2_RIGHT_CH_MIX_REG 0x77
+#define TAS5733_CH1_BQ0_REG 0x26
+#define TAS5733_CH1_BQ1_REG 0x27
+#define TAS5733_CH1_BQ2_REG 0x28
+#define TAS5733_CH1_BQ3_REG 0x29
+#define TAS5733_CH1_BQ4_REG 0x2a
+#define TAS5733_CH1_BQ5_REG 0x2b
+#define TAS5733_CH1_BQ6_REG 0x2c
+#define TAS5733_CH1_BQ7_REG 0x2d
+#define TAS5733_CH1_BQ8_REG 0x2e
+#define TAS5733_CH1_BQ9_REG 0x2f
+
+#define TAS5733_CH2_BQ0_REG 0x30
+#define TAS5733_CH2_BQ1_REG 0x31
+#define TAS5733_CH2_BQ2_REG 0x32
+#define TAS5733_CH2_BQ3_REG 0x33
+#define TAS5733_CH2_BQ4_REG 0x34
+#define TAS5733_CH2_BQ5_REG 0x35
+#define TAS5733_CH2_BQ6_REG 0x36
+#define TAS5733_CH2_BQ7_REG 0x37
+#define TAS5733_CH2_BQ8_REG 0x38
+#define TAS5733_CH2_BQ9_REG 0x39
+
+#define TAS5733_CH1_BQ10_REG 0x58
+#define TAS5733_CH1_CBQ0_REG 0x59
+#define TAS5733_CH1_CBQ1_REG 0x5a
+#define TAS5733_CH1_CBQ2_REG 0x5b
+#define TAS5733_CH1_CBQ3_REG 0x5c
+
+#define TAS5733_CH2_BQ10_REG 0x5d
+#define TAS5733_CH2_CBQ0_REG 0x5e
+#define TAS5733_CH2_CBQ1_REG 0x5f
+#define TAS5733_CH2_CBQ2_REG 0x60
+#define TAS5733_CH2_CBQ3_REG 0x61
+
#endif /* _TAS571X_H */
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index 6dd6c0896eff..2dcdd0a4bf80 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;
@@ -565,7 +564,7 @@ static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int val;
val = snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG);
@@ -580,7 +579,7 @@ static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int sel = ucontrol->value.integer.value[0];
snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
@@ -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/tas5805m.c b/sound/soc/codecs/tas5805m.c
index aca3756ffab6..867046b7aaa0 100644
--- a/sound/soc/codecs/tas5805m.c
+++ b/sound/soc/codecs/tas5805m.c
@@ -226,8 +226,7 @@ static int tas5805m_vol_info(struct snd_kcontrol *kcontrol,
static int tas5805m_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
@@ -247,8 +246,7 @@ static inline int volume_is_valid(int v)
static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
int ret = 0;
@@ -474,7 +472,7 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
return ret;
}
- tas5805m = devm_kzalloc(dev, sizeof(struct tas5805m_priv), GFP_KERNEL);
+ tas5805m = devm_kzalloc(dev, sizeof(*tas5805m), GFP_KERNEL);
if (!tas5805m)
return -ENOMEM;
@@ -520,12 +518,11 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
}
tas5805m->dsp_cfg_len = fw->size;
- tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL);
+ tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL);
if (!tas5805m->dsp_cfg_data) {
release_firmware(fw);
return -ENOMEM;
}
- memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size);
release_firmware(fw);
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index da89e8c681dd..85ecc246896f 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -346,6 +346,8 @@ static int tas6424_power_on(struct snd_soc_component *component)
static int tas6424_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
dev_dbg(component->dev, "%s() level=%d\n", __func__, level);
switch (level) {
@@ -353,7 +355,7 @@ static int tas6424_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
tas6424_power_on(component);
break;
case SND_SOC_BIAS_OFF:
@@ -364,7 +366,7 @@ static int tas6424_set_bias_level(struct snd_soc_component *component,
return 0;
}
-static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
+static const struct snd_soc_component_driver soc_codec_dev_tas6424 = {
.set_bias_level = tas6424_set_bias_level,
.controls = tas6424_snd_controls,
.num_controls = ARRAY_SIZE(tas6424_snd_controls),
@@ -792,7 +794,7 @@ static void tas6424_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id tas6424_i2c_ids[] = {
- { "tas6424", 0 },
+ { "tas6424" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tas6424_i2c_ids);
diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c
index e187d74a1737..7d6fcba9986e 100644
--- a/sound/soc/codecs/tda7419.c
+++ b/sound/soc/codecs/tda7419.c
@@ -614,7 +614,7 @@ static int tda7419_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id tda7419_i2c_id[] = {
- { "tda7419", 0 },
+ { "tda7419" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tda7419_i2c_id);
@@ -623,6 +623,7 @@ static const struct of_device_id tda7419_of_match[] = {
{ .compatible = "st,tda7419" },
{ },
};
+MODULE_DEVICE_TABLE(of, tda7419_of_match);
static struct i2c_driver tda7419_driver = {
.driver = {
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index 8cca2ceadd9e..ac0c5c337677 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -296,7 +296,7 @@ static int tfa9879_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id tfa9879_i2c_id[] = {
- { "tfa9879", 0 },
+ { "tfa9879" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id);
diff --git a/sound/soc/codecs/tfa989x.c b/sound/soc/codecs/tfa989x.c
index 79847a90ac46..7204be155eb9 100644
--- a/sound/soc/codecs/tfa989x.c
+++ b/sound/soc/codecs/tfa989x.c
@@ -105,7 +105,7 @@ static const struct snd_soc_dapm_route tfa989x_dapm_routes[] = {
static int tfa989x_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component);
gpiod_set_value_cansleep(tfa989x->rcv_gpiod, ucontrol->value.enumerated.item[0]);
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index b976c1946286..270eee1ea534 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -25,7 +25,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -40,9 +39,10 @@
*/
#define ADC3XXX_MICBIAS_PINS 2
+#define ADC3XXX_GPIO_PINS 2
/* Number of GPIO pins exposed via the gpiolib interface */
-#define ADC3XXX_GPIOS_MAX 2
+#define ADC3XXX_GPIOS_MAX (ADC3XXX_MICBIAS_PINS + ADC3XXX_GPIO_PINS)
#define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000
#define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -293,7 +293,7 @@
#define ADC3XXX_BYPASS_RPGA 0x80
/* MICBIAS control bits */
-#define ADC3XXX_MICBIAS_MASK 0x2
+#define ADC3XXX_MICBIAS_MASK 0x3
#define ADC3XXX_MICBIAS1_SHIFT 5
#define ADC3XXX_MICBIAS2_SHIFT 3
@@ -321,7 +321,8 @@ struct adc3xxx {
struct gpio_desc *rst_pin;
unsigned int pll_mode;
unsigned int sysclk;
- unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */
+ unsigned int gpio_cfg[ADC3XXX_GPIO_PINS]; /* value+1 (0 => not set) */
+ unsigned int micbias_gpo[ADC3XXX_MICBIAS_PINS]; /* 1 => pin is GPO */
unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS];
int master;
u8 page_no;
@@ -329,7 +330,7 @@ struct adc3xxx {
struct gpio_chip gpio_chip;
};
-static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = {
+static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIO_PINS] = {
ADC3XXX_GPIO1_CTRL,
ADC3XXX_GPIO2_CTRL
};
@@ -564,7 +565,7 @@ static int adc3xxx_coefficient_info(struct snd_kcontrol *kcontrol,
static int adc3xxx_coefficient_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int numcoeff = kcontrol->private_value >> 16;
int reg = kcontrol->private_value & 0xffff;
int index = 0;
@@ -590,7 +591,7 @@ static int adc3xxx_coefficient_get(struct snd_kcontrol *kcontrol,
static int adc3xxx_coefficient_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int numcoeff = kcontrol->private_value >> 16;
int reg = kcontrol->private_value & 0xffff;
int index = 0;
@@ -960,14 +961,23 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset)
if (offset >= ADC3XXX_GPIOS_MAX)
return -EINVAL;
- /* GPIO1 is offset 0, GPIO2 is offset 1 */
- /* We check here that the GPIO pins are either not configured in the
- * DT, or that they purposely are set as outputs.
- * (Input mode not yet implemented).
- */
- if (adc3xxx->gpio_cfg[offset] != 0 &&
- adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
- return -EINVAL;
+ if (offset < ADC3XXX_GPIO_PINS) {
+ /* GPIO1 is offset 0, GPIO2 is offset 1 */
+ /* We check here that the GPIO pins are either not configured
+ * in the DT, or that they purposely are set as outputs.
+ * (Input mode not yet implemented).
+ */
+ if (adc3xxx->gpio_cfg[offset] != 0 &&
+ adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1)
+ return -EINVAL;
+ } else if (offset >= ADC3XXX_GPIO_PINS && offset < ADC3XXX_GPIOS_MAX) {
+ /* MICBIAS1 is offset 2, MICBIAS2 is offset 3 */
+ /* We check here if the MICBIAS pins are in fact configured
+ * as GPOs.
+ */
+ if (!adc3xxx->micbias_gpo[offset - ADC3XXX_GPIO_PINS])
+ return -EINVAL;
+ }
return 0;
}
@@ -977,6 +987,21 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip,
{
struct adc3xxx *adc3xxx = gpiochip_get_data(chip);
+ /* For the MICBIAS pins, they are by definition outputs. */
+ if (offset >= ADC3XXX_GPIO_PINS) {
+ unsigned int vg;
+ unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
+
+ if (value)
+ vg = adc3xxx->micbias_vg[micbias];
+ else
+ vg = ADC3XXX_MICBIAS_OFF;
+ return regmap_update_bits(adc3xxx->regmap,
+ ADC3XXX_MICBIAS_CTRL,
+ ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias],
+ vg << adc3xxx_micbias_shift[micbias]);
+ }
+
/* Set GPIO output function. */
return regmap_update_bits(adc3xxx->regmap,
adc3xxx_gpio_ctrl_reg[offset],
@@ -990,10 +1015,10 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip,
* so we set the output mode and output value in the same call. Hence
* .set in practice does the same thing as .direction_out .
*/
-static void adc3xxx_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int adc3xxx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
- (void) adc3xxx_gpio_direction_out(chip, offset, value);
+ return adc3xxx_gpio_direction_out(chip, offset, value);
}
/* Even though we only support GPIO output for now, some GPIO clients
@@ -1005,9 +1030,17 @@ static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset)
unsigned int regval;
int ret;
- /* We only allow output pins, so just read the value set in the output
- * pin register field.
- */
+ /* We only allow output pins, so just read the value prevously set. */
+ if (offset >= ADC3XXX_GPIO_PINS) {
+ /* MICBIAS pins */
+ unsigned int micbias = offset - ADC3XXX_GPIO_PINS;
+
+ ret = regmap_read(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, &regval);
+ if (ret)
+ return ret;
+ return ((regval >> adc3xxx_micbias_shift[micbias]) & ADC3XXX_MICBIAS_MASK) !=
+ ADC3XXX_MICBIAS_OFF;
+ }
ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], &regval);
if (ret)
return ret;
@@ -1049,7 +1082,7 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
* This allows us to set up things which are not software
* controllable GPIOs, such as PDM microphone I/O,
*/
- for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) {
+ for (gpio = 0; gpio < ADC3XXX_GPIO_PINS; gpio++) {
unsigned int cfg = adc3xxx->gpio_cfg[gpio];
if (cfg) {
@@ -1061,9 +1094,15 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx)
}
}
- /* Set up micbias voltage */
+ /* Set up micbias voltage. */
+ /* If pin is configured as GPO, set off initially. */
for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) {
- unsigned int vg = adc3xxx->micbias_vg[micbias];
+ unsigned int vg;
+
+ if (adc3xxx->micbias_gpo[micbias])
+ vg = ADC3XXX_MICBIAS_OFF;
+ else
+ vg = adc3xxx->micbias_vg[micbias];
regmap_update_bits(adc3xxx->regmap,
ADC3XXX_MICBIAS_CTRL,
@@ -1091,15 +1130,26 @@ static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx,
return 0;
}
-static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx,
- const char *propname, unsigned int *vg)
+static int adc3xxx_parse_dt_micbias_gpo(struct adc3xxx *adc3xxx,
+ const char *propname,
+ unsigned int *cfg)
+{
+ struct device *dev = adc3xxx->dev;
+ struct device_node *np = dev->of_node;
+
+ *cfg = of_property_read_bool(np, propname);
+ return 0;
+}
+
+static int adc3xxx_parse_dt_micbias_vg(struct adc3xxx *adc3xxx,
+ const char *propname, unsigned int *vg)
{
struct device *dev = adc3xxx->dev;
struct device_node *np = dev->of_node;
unsigned int val;
if (!of_property_read_u32(np, propname, &val)) {
- if (val >= ADC3XXX_MICBIAS_AVDD) {
+ if (val > ADC3XXX_MICBIAS_AVDD) {
dev_err(dev, "Invalid property value for '%s'\n", propname);
return -EINVAL;
}
@@ -1143,7 +1193,7 @@ static int adc3xxx_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dai->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(dai->component);
struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component);
int i, width = 16;
u8 iface_len, bdiv;
@@ -1249,7 +1299,7 @@ static int adc3xxx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_component *component = codec_dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct adc3xxx *adc3xxx = snd_soc_component_get_drvdata(component);
u8 clkdir = 0, format = 0;
int master = 0;
@@ -1351,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);
@@ -1383,16 +1432,28 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c)
dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk));
}
+ /* Configure mode for DMDIN/GPIO1 pin */
ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]);
if (ret < 0)
goto err_unprepare_mclk;
+ /* Configure mode for DMCLK/GPIO2 pin */
ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]);
if (ret < 0)
goto err_unprepare_mclk;
- ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
+ /* Configure mode for MICBIAS1: as Mic Bias output or GPO */
+ ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias1-gpo", &adc3xxx->micbias_gpo[0]);
+ if (ret < 0)
+ goto err_unprepare_mclk;
+ /* Configure mode for MICBIAS2: as Mic Bias output or GPO */
+ ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias2-gpo", &adc3xxx->micbias_gpo[1]);
if (ret < 0)
goto err_unprepare_mclk;
- ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
+ /* Configure voltage for MICBIAS1 pin (ON voltage when used as GPO) */
+ ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]);
+ if (ret < 0)
+ goto err_unprepare_mclk;
+ /* Configure voltage for MICBIAS2 pin (ON voltage when used as GPO) */
+ ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]);
if (ret < 0)
goto err_unprepare_mclk;
@@ -1404,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);
@@ -1429,12 +1489,11 @@ err_unprepare_mclk:
return ret;
}
-static void __exit adc3xxx_i2c_remove(struct i2c_client *client)
+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);
}
@@ -1452,7 +1511,7 @@ static struct i2c_driver adc3xxx_i2c_driver = {
.of_match_table = tlv320adc3xxx_of_match,
},
.probe = adc3xxx_i2c_probe,
- .remove = __exit_p(adc3xxx_i2c_remove),
+ .remove = adc3xxx_i2c_remove,
.id_table = adc3xxx_i2c_id,
};
diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c
index 41342b340680..443cf59cb71a 100644
--- a/sound/soc/codecs/tlv320adcx140.c
+++ b/sound/soc/codecs/tlv320adcx140.c
@@ -12,7 +12,6 @@
#include <linux/regulator/consumer.h>
#include <linux/acpi.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -613,8 +612,7 @@ static int adcx140_phase_calib_info(struct snd_kcontrol *kcontrol,
static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
- struct snd_soc_component *codec =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec);
value->value.integer.value[0] = adcx140->phase_calib_on ? 1 : 0;
@@ -626,8 +624,7 @@ static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol,
static int adcx140_phase_calib_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
- struct snd_soc_component *codec
- = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(codec);
bool v = value->value.integer.value[0] ? true : false;
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
index 9692ae007c91..a31fb95048b8 100644
--- a/sound/soc/codecs/tlv320aic23-i2c.c
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -28,7 +28,7 @@ static int tlv320aic23_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id tlv320aic23_id[] = {
- {"tlv320aic23", 0},
+ {"tlv320aic23"},
{}
};
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index c47aa4d4162d..04ec8fb5c6e5 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -77,7 +77,7 @@ static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u16 val, reg;
val = (ucontrol->value.integer.value[0] & 0x07);
@@ -100,7 +100,7 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u16 val;
val = snd_soc_component_read(component, TLV320AIC23_ANLG) & (0x1C0);
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 9611aa8acb0d..4362c2c06ce8 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -12,6 +12,7 @@
* and mono/stereo Class-D speaker driver.
*/
+#include <linux/unaligned.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -22,8 +23,8 @@
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/acpi.h>
+#include <linux/firmware.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -798,7 +799,7 @@ static int aic31xx_add_controls(struct snd_soc_component *component)
static int aic31xx_add_widgets(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
int ret = 0;
@@ -894,7 +895,7 @@ static int aic31xx_setup_pll(struct snd_soc_component *component,
dev_err(component->dev,
"%s: Sample rate (%u) and format not supported\n",
__func__, params_rate(params));
- /* See bellow for details how fix this. */
+ /* See below for details on how to fix this. */
return -EINVAL;
}
if (bclk_score != 0) {
@@ -1029,7 +1030,7 @@ static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute,
static int aic31xx_clock_master_routes(struct snd_soc_component *component,
unsigned int fmt)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
int ret;
@@ -1208,7 +1209,7 @@ static int aic31xx_regulator_event(struct notifier_block *nb,
* supplies was disabled.
*/
if (aic31xx->gpio_reset)
- gpiod_set_value(aic31xx->gpio_reset, 1);
+ gpiod_set_value_cansleep(aic31xx->gpio_reset, 1);
regcache_mark_dirty(aic31xx->regmap);
dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
@@ -1222,9 +1223,9 @@ static int aic31xx_reset(struct aic31xx_priv *aic31xx)
int ret = 0;
if (aic31xx->gpio_reset) {
- gpiod_set_value(aic31xx->gpio_reset, 1);
+ gpiod_set_value_cansleep(aic31xx->gpio_reset, 1);
ndelay(10); /* At least 10ns */
- gpiod_set_value(aic31xx->gpio_reset, 0);
+ gpiod_set_value_cansleep(aic31xx->gpio_reset, 0);
} else {
ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1);
}
@@ -1315,18 +1316,20 @@ static void aic31xx_power_off(struct snd_soc_component *component)
static int aic31xx_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
- snd_soc_component_get_bias_level(component), level);
+ snd_soc_dapm_get_bias_level(dapm), level);
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY)
aic31xx_clk_on(component);
break;
case SND_SOC_BIAS_STANDBY:
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_OFF:
aic31xx_power_on(component);
break;
@@ -1338,7 +1341,7 @@ static int aic31xx_set_bias_level(struct snd_soc_component *component,
}
break;
case SND_SOC_BIAS_OFF:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY)
aic31xx_power_off(component);
break;
}
@@ -1639,16 +1642,104 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
+static int tlv320dac3100_fw_load(struct aic31xx_priv *aic31xx,
+ const u8 *data, size_t size)
+{
+ int ret, reg;
+ u16 val16;
+
+ /*
+ * Coefficients firmware binary structure. Multi-byte values are big-endian.
+ *
+ * @0, 16bits: Magic (0xB30C)
+ * @2, 16bits: Version (0x0100 for version 1.0)
+ * @4, 8bits: DAC Processing Block Selection
+ * @5, 62 16-bit values: Page 8 buffer A DAC programmable filter coefficients
+ * @129, 12 16-bit values: Page 9 Buffer A DAC programmable filter coefficients
+ *
+ * Filter coefficients are interpreted as two's complement values
+ * ranging from -32 768 to 32 767. For more details on filter coefficients,
+ * please refer to the TLV320DAC3100 datasheet, tables 6-120 and 6-123.
+ */
+
+ if (size != 153) {
+ dev_err(aic31xx->dev, "firmware size is %zu, expected 153 bytes\n", size);
+ return -EINVAL;
+ }
+
+ /* Check magic */
+ val16 = get_unaligned_be16(data);
+ if (val16 != 0xb30c) {
+ dev_err(aic31xx->dev, "fw magic is 0x%04x expected 0xb30c\n", val16);
+ return -EINVAL;
+ }
+ data += 2;
+
+ /* Check version */
+ val16 = get_unaligned_be16(data);
+ if (val16 != 0x0100) {
+ dev_err(aic31xx->dev, "invalid firmware version 0x%04x! expected 1", val16);
+ return -EINVAL;
+ }
+ data += 2;
+
+ ret = regmap_write(aic31xx->regmap, AIC31XX_DACPRB, *data);
+ if (ret) {
+ dev_err(aic31xx->dev, "failed to write PRB index: err %d\n", ret);
+ return ret;
+ }
+ data += 1;
+
+ /* Page 8 Buffer A coefficients */
+ for (reg = 2; reg < 126; reg++) {
+ ret = regmap_write(aic31xx->regmap, AIC31XX_REG(8, reg), *data);
+ if (ret) {
+ dev_err(aic31xx->dev,
+ "failed to write page 8 filter coefficient %d: err %d\n", reg, ret);
+ return ret;
+ }
+ data++;
+ }
+
+ /* Page 9 Buffer A coefficients */
+ for (reg = 2; reg < 26; reg++) {
+ ret = regmap_write(aic31xx->regmap, AIC31XX_REG(9, reg), *data);
+ if (ret) {
+ dev_err(aic31xx->dev,
+ "failed to write page 9 filter coefficient %d: err %d\n", reg, ret);
+ return ret;
+ }
+ data++;
+ }
+
+ dev_info(aic31xx->dev, "done loading DAC filter coefficients\n");
+
+ return ret;
+}
+
+static int tlv320dac3100_load_coeffs(struct aic31xx_priv *aic31xx,
+ const char *fw_name)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, fw_name, aic31xx->dev);
+ if (ret)
+ return ret;
+
+ ret = tlv320dac3100_fw_load(aic31xx, fw->data, fw->size);
+
+ release_firmware(fw);
+
+ return ret;
+}
+
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;
@@ -1665,7 +1756,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);
@@ -1728,6 +1819,12 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c)
}
}
+ if (aic31xx->codec_type == DAC3100) {
+ ret = tlv320dac3100_load_coeffs(aic31xx, "tlv320dac3100-coeffs.bin");
+ if (ret)
+ dev_warn(aic31xx->dev, "Did not load any filter coefficients\n");
+ }
+
if (aic31xx->codec_type & DAC31XX_BIT)
return devm_snd_soc_register_component(&i2c->dev,
&soc_codec_driver_aic31xx,
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index 2f78e6820c75..5c0a76a4a106 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -204,18 +204,19 @@ static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
}
-static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *parent_rate)
+static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_aic32x4_pll_muldiv settings;
int ret;
- ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
+ ret = clk_aic32x4_pll_calc_muldiv(&settings, req->rate, req->best_parent_rate);
if (ret < 0)
- return 0;
+ return -EINVAL;
- return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
+ req->rate = clk_aic32x4_pll_calc_rate(&settings, req->best_parent_rate);
+
+ return 0;
}
static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
@@ -266,7 +267,7 @@ static const struct clk_ops aic32x4_pll_ops = {
.unprepare = clk_aic32x4_pll_unprepare,
.is_prepared = clk_aic32x4_pll_is_prepared,
.recalc_rate = clk_aic32x4_pll_recalc_rate,
- .round_rate = clk_aic32x4_pll_round_rate,
+ .determine_rate = clk_aic32x4_pll_determine_rate,
.set_rate = clk_aic32x4_pll_set_rate,
.set_parent = clk_aic32x4_pll_set_parent,
.get_parent = clk_aic32x4_pll_get_parent,
@@ -292,6 +293,7 @@ static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
}
static const struct clk_ops aic32x4_codec_clkin_ops = {
+ .determine_rate = clk_hw_determine_rate_no_reparent,
.set_parent = clk_aic32x4_codec_clkin_set_parent,
.get_parent = clk_aic32x4_codec_clkin_get_parent,
};
@@ -319,42 +321,49 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
u8 divisor;
divisor = DIV_ROUND_UP(parent_rate, rate);
- if (divisor > 128)
+ if (divisor > AIC32X4_DIV_MAX)
return -EINVAL;
return regmap_update_bits(div->regmap, div->reg,
AIC32X4_DIV_MASK, divisor);
}
-static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
unsigned long divisor;
- divisor = DIV_ROUND_UP(*parent_rate, rate);
- if (divisor > 128)
+ divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
+ if (divisor > AIC32X4_DIV_MAX)
return -EINVAL;
- return DIV_ROUND_UP(*parent_rate, divisor);
+ req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);
+ return 0;
}
static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-
unsigned int val;
+ int err;
+
+ err = regmap_read(div->regmap, div->reg, &val);
+ if (err)
+ return 0;
- regmap_read(div->regmap, div->reg, &val);
+ val &= AIC32X4_DIV_MASK;
+ if (!val)
+ val = AIC32X4_DIV_MAX;
- return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
+ return DIV_ROUND_UP(parent_rate, val);
}
static const struct clk_ops aic32x4_div_ops = {
.prepare = clk_aic32x4_div_prepare,
.unprepare = clk_aic32x4_div_unprepare,
.set_rate = clk_aic32x4_div_set_rate,
- .round_rate = clk_aic32x4_div_round_rate,
+ .determine_rate = clk_aic32x4_div_determine_rate,
.recalc_rate = clk_aic32x4_div_recalc_rate,
};
@@ -382,7 +391,7 @@ static const struct clk_ops aic32x4_bdiv_ops = {
.set_parent = clk_aic32x4_bdiv_set_parent,
.get_parent = clk_aic32x4_bdiv_get_parent,
.set_rate = clk_aic32x4_div_set_rate,
- .round_rate = clk_aic32x4_div_round_rate,
+ .determine_rate = clk_aic32x4_div_determine_rate,
.recalc_rate = clk_aic32x4_div_recalc_rate,
};
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
index 49b33a256cd7..b27b5ae1e4b2 100644
--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -16,33 +16,20 @@
#include "tlv320aic32x4.h"
-static const struct of_device_id aic32x4_of_id[];
-static const struct i2c_device_id aic32x4_i2c_id[];
-
static int aic32x4_i2c_probe(struct i2c_client *i2c)
{
struct regmap *regmap;
struct regmap_config config;
+ enum aic32x4_type type;
config = aic32x4_regmap_config;
config.reg_bits = 8;
config.val_bits = 8;
regmap = devm_regmap_init_i2c(i2c, &config);
+ type = (uintptr_t)i2c_get_match_data(i2c);
- if (i2c->dev.of_node) {
- const struct of_device_id *oid;
-
- oid = of_match_node(aic32x4_of_id, i2c->dev.of_node);
- dev_set_drvdata(&i2c->dev, (void *)oid->data);
- } else {
- const struct i2c_device_id *id;
-
- id = i2c_match_id(aic32x4_i2c_id, i2c);
- dev_set_drvdata(&i2c->dev, (void *)id->driver_data);
- }
-
- return aic32x4_probe(&i2c->dev, regmap);
+ return aic32x4_probe(&i2c->dev, regmap, type);
}
static void aic32x4_i2c_remove(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
index 03cce8d6404f..92246243ff94 100644
--- a/sound/soc/codecs/tlv320aic32x4-spi.c
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -16,12 +16,11 @@
#include "tlv320aic32x4.h"
-static const struct of_device_id aic32x4_of_id[];
-
static int aic32x4_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
struct regmap_config config;
+ enum aic32x4_type type;
config = aic32x4_regmap_config;
config.reg_bits = 7;
@@ -30,20 +29,9 @@ static int aic32x4_spi_probe(struct spi_device *spi)
config.read_flag_mask = 0x01;
regmap = devm_regmap_init_spi(spi, &config);
+ type = (uintptr_t)spi_get_device_match_data(spi);
- if (spi->dev.of_node) {
- const struct of_device_id *oid;
-
- oid = of_match_node(aic32x4_of_id, spi->dev.of_node);
- dev_set_drvdata(&spi->dev, (void *)oid->data);
- } else {
- const struct spi_device_id *id_entry;
-
- id_entry = spi_get_device_id(spi);
- dev_set_drvdata(&spi->dev, (void *)id_entry->driver_data);
- }
-
- return aic32x4_probe(&spi->dev, regmap);
+ return aic32x4_probe(&spi->dev, regmap, type);
}
static void aic32x4_spi_remove(struct spi_device *spi)
@@ -68,7 +56,6 @@ MODULE_DEVICE_TABLE(of, aic32x4_of_id);
static struct spi_driver aic32x4_spi_driver = {
.driver = {
.name = "tlv320aic32x4",
- .owner = THIS_MODULE,
.of_match_table = aic32x4_of_id,
},
.probe = aic32x4_spi_probe,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index ffe1828a4b7e..d85094557215 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -9,27 +9,26 @@
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/cdev.h>
-#include <linux/slab.h>
#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/of_clk.h>
+#include <linux/pm.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
-#include <sound/tlv320aic32x4.h>
#include <sound/core.h>
+#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
+#include <sound/tlv320aic32x4.h>
#include "tlv320aic32x4.h"
@@ -38,7 +37,7 @@ struct aic32x4_priv {
u32 power_cfg;
u32 micpga_routing;
bool swapdacs;
- int rstn_gpio;
+ struct gpio_desc *rstn_gpio;
const char *mclk_name;
struct regulator *supply_ldo;
@@ -884,6 +883,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction)
static int aic32x4_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
static struct clk_bulk_data clocks[] = {
@@ -908,7 +908,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
/* Initial cold start */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
break;
clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
@@ -1073,6 +1073,13 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
return 0;
}
+static int aic32x4_of_xlate_dai_id(struct snd_soc_component *component,
+ struct device_node *endpoint)
+{
+ /* return dai id 0, whatever the endpoint index */
+ return 0;
+}
+
static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
.probe = aic32x4_component_probe,
.set_bias_level = aic32x4_set_bias_level,
@@ -1082,6 +1089,7 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
.num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
.dapm_routes = aic32x4_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
+ .of_xlate_dai_id = aic32x4_of_xlate_dai_id,
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
@@ -1203,6 +1211,7 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 =
.num_dapm_widgets = ARRAY_SIZE(aic32x4_tas2505_dapm_widgets),
.dapm_routes = aic32x4_tas2505_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(aic32x4_tas2505_dapm_routes),
+ .of_xlate_dai_id = aic32x4_of_xlate_dai_id,
.suspend_bias_off = 1,
.idle_bias_on = 1,
.use_pmdown_time = 1,
@@ -1227,7 +1236,14 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
aic32x4->swapdacs = false;
aic32x4->micpga_routing = 0;
- aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+ /* Assert reset using GPIOD_OUT_HIGH, because reset is GPIO_ACTIVE_LOW */
+ aic32x4->rstn_gpio = devm_gpiod_get_optional(aic32x4->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(aic32x4->rstn_gpio)) {
+ return dev_err_probe(aic32x4->dev, PTR_ERR(aic32x4->rstn_gpio),
+ "Failed to get reset gpio\n");
+ } else {
+ gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn");
+ }
if (of_property_read_u32_array(np, "aic32x4-gpio-func",
aic32x4_setup->gpio_func, 5) >= 0)
@@ -1262,8 +1278,8 @@ static int aic32x4_setup_regulators(struct device *dev,
/* Check if the regulator requirements are fulfilled */
if (IS_ERR(aic32x4->supply_iov)) {
- dev_err(dev, "Missing supply 'iov'\n");
- return PTR_ERR(aic32x4->supply_iov);
+ return dev_err_probe(dev, PTR_ERR(aic32x4->supply_iov),
+ "Missing supply 'iov'\n");
}
if (IS_ERR(aic32x4->supply_ldo)) {
@@ -1271,12 +1287,12 @@ static int aic32x4_setup_regulators(struct device *dev,
return -EPROBE_DEFER;
if (IS_ERR(aic32x4->supply_dv)) {
- dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
- return PTR_ERR(aic32x4->supply_dv);
+ return dev_err_probe(dev, PTR_ERR(aic32x4->supply_dv),
+ "Missing supply 'dv' or 'ldoin'\n");
}
if (IS_ERR(aic32x4->supply_av)) {
- dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
- return PTR_ERR(aic32x4->supply_av);
+ return dev_err_probe(dev, PTR_ERR(aic32x4->supply_av),
+ "Missing supply 'av' or 'ldoin'\n");
}
} else {
if (PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
@@ -1333,10 +1349,10 @@ error_ldo:
return ret;
}
-int aic32x4_probe(struct device *dev, struct regmap *regmap)
+int aic32x4_probe(struct device *dev, struct regmap *regmap,
+ enum aic32x4_type type)
{
struct aic32x4_priv *aic32x4;
- struct aic32x4_pdata *pdata = dev->platform_data;
struct device_node *np = dev->of_node;
int ret;
@@ -1349,17 +1365,11 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
return -ENOMEM;
aic32x4->dev = dev;
- aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev);
+ aic32x4->type = type;
dev_set_drvdata(dev, aic32x4);
- if (pdata) {
- aic32x4->power_cfg = pdata->power_cfg;
- aic32x4->swapdacs = pdata->swapdacs;
- aic32x4->micpga_routing = pdata->micpga_routing;
- aic32x4->rstn_gpio = pdata->rstn_gpio;
- aic32x4->mclk_name = "mclk";
- } else if (np) {
+ if (np) {
ret = aic32x4_parse_dt(aic32x4, np);
if (ret) {
dev_err(dev, "Failed to parse DT node\n");
@@ -1369,26 +1379,18 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
aic32x4->power_cfg = 0;
aic32x4->swapdacs = false;
aic32x4->micpga_routing = 0;
- aic32x4->rstn_gpio = -1;
+ aic32x4->rstn_gpio = NULL;
aic32x4->mclk_name = "mclk";
}
- if (gpio_is_valid(aic32x4->rstn_gpio)) {
- ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
- GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
- if (ret != 0)
- return ret;
- }
-
ret = aic32x4_setup_regulators(dev, aic32x4);
- if (ret) {
- dev_err(dev, "Failed to setup regulators\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup regulators\n");
- if (gpio_is_valid(aic32x4->rstn_gpio)) {
+ if (aic32x4->rstn_gpio) {
ndelay(10);
- gpio_set_value_cansleep(aic32x4->rstn_gpio, 1);
+ /* deassert reset */
+ gpiod_set_value_cansleep(aic32x4->rstn_gpio, 0);
mdelay(1);
}
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index 4de5bd9e8cc5..f68a846ef61d 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -17,7 +17,8 @@ enum aic32x4_type {
};
extern const struct regmap_config aic32x4_regmap_config;
-int aic32x4_probe(struct device *dev, struct regmap *regmap);
+int aic32x4_probe(struct device *dev, struct regmap *regmap,
+ enum aic32x4_type type);
void aic32x4_remove(struct device *dev);
int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
@@ -223,8 +224,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
#define AIC32X4_REFPOWERUP_120MS 0x07
/* Common mask and enable for all of the dividers */
-#define AIC32X4_DIVEN BIT(7)
-#define AIC32X4_DIV_MASK GENMASK(6, 0)
+#define AIC32X4_DIVEN BIT(7)
+#define AIC32X4_DIV_MASK GENMASK(6, 0)
+#define AIC32X4_DIV_MAX 128
/* Clock Limits */
#define AIC32X4_MAX_DOSR_FREQ 6200000
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/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c
index deed6ec7e081..f8c1c16eaa0e 100644
--- a/sound/soc/codecs/tlv320aic3x-spi.c
+++ b/sound/soc/codecs/tlv320aic3x-spi.c
@@ -63,7 +63,6 @@ MODULE_DEVICE_TABLE(of, aic3x_of_id);
static struct spi_driver aic3x_spi_driver = {
.driver = {
.name = "tlv320aic3x",
- .owner = THIS_MODULE,
.of_match_table = aic3x_of_id,
},
.probe = aic3x_spi_probe,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 56e795a00e22..ce22298b43ef 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -121,6 +121,16 @@ static const struct reg_default aic3x_reg[] = {
{ 108, 0x00 }, { 109, 0x00 },
};
+static const struct reg_sequence aic3007_class_d[] = {
+ /* Class-D speaker driver init; datasheet p. 46 */
+ { AIC3X_PAGE_SELECT, 0x0D },
+ { 0xD, 0x0D },
+ { 0x8, 0x5C },
+ { 0x8, 0x5D },
+ { 0x8, 0x5C },
+ { AIC3X_PAGE_SELECT, 0x00 },
+};
+
static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -153,8 +163,8 @@ EXPORT_SYMBOL_GPL(aic3x_regmap);
static int snd_soc_dapm_put_volsw_aic3x(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_component_get_dapm(component);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
@@ -999,7 +1009,7 @@ static const struct snd_soc_dapm_route intercon_3007[] = {
static int aic3x_add_widgets(struct snd_soc_component *component)
{
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (aic3x->model) {
case AIC3X_MODEL_3X:
@@ -1393,6 +1403,10 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
gpiod_set_value(aic3x->gpio_reset, 0);
}
+ if (aic3x->model == AIC3X_MODEL_3007)
+ regmap_multi_reg_write_bypassed(aic3x->regmap, aic3007_class_d,
+ ARRAY_SIZE(aic3007_class_d));
+
/* Sync reg_cache with the hardware */
regcache_cache_only(aic3x->regmap, false);
regcache_sync(aic3x->regmap);
@@ -1435,13 +1449,14 @@ out:
static int aic3x_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY &&
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY &&
aic3x->master) {
/* enable pll */
snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
@@ -1451,7 +1466,7 @@ static int aic3x_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_STANDBY:
if (!aic3x->power)
aic3x_set_power(component, 1);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE &&
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE &&
aic3x->master) {
/* disable pll */
snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
@@ -1723,17 +1738,6 @@ static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x)
}
}
-
-static const struct reg_sequence aic3007_class_d[] = {
- /* Class-D speaker driver init; datasheet p. 46 */
- { AIC3X_PAGE_SELECT, 0x0D },
- { 0xD, 0x0D },
- { 0x8, 0x5C },
- { 0x8, 0x5D },
- { 0x8, 0x5C },
- { AIC3X_PAGE_SELECT, 0x00 },
-};
-
int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data)
{
struct aic3x_priv *aic3x;
@@ -1818,20 +1822,11 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
- if (ret) {
- dev_err(dev, "Failed to request supplies: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request supplies\n");
aic3x_configure_ocmv(dev, aic3x);
- if (aic3x->model == AIC3X_MODEL_3007) {
- ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
- ARRAY_SIZE(aic3007_class_d));
- if (ret != 0)
- dev_err(dev, "Failed to init class D: %d\n", ret);
- }
-
ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
if (ret)
return ret;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index fa46f51d4341..605da1259fc6 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -14,7 +14,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -24,7 +24,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <sound/tlv320dac33-plat.h>
#include "tlv320dac33.h"
/*
@@ -80,7 +79,7 @@ struct tlv320dac33_priv {
struct snd_soc_component *component;
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
struct snd_pcm_substream *substream;
- int power_gpio;
+ struct gpio_desc *reset_gpiod;
int chip_power;
int irq;
unsigned int refclk;
@@ -383,14 +382,26 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
goto exit;
}
- if (dac33->power_gpio >= 0)
- gpio_set_value(dac33->power_gpio, 1);
+ if (dac33->reset_gpiod) {
+ ret = gpiod_set_value(dac33->reset_gpiod, 1);
+ if (ret < 0) {
+ dev_err(&dac33->i2c->dev,
+ "Failed to set reset GPIO: %d\n", ret);
+ goto exit;
+ }
+ }
dac33->chip_power = 1;
} else {
dac33_soft_power(component, 0);
- if (dac33->power_gpio >= 0)
- gpio_set_value(dac33->power_gpio, 0);
+ if (dac33->reset_gpiod) {
+ ret = gpiod_set_value(dac33->reset_gpiod, 0);
+ if (ret < 0) {
+ dev_err(&dac33->i2c->dev,
+ "Failed to set reset GPIO: %d\n", ret);
+ goto exit;
+ }
+ }
ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies),
dac33->supplies);
@@ -431,7 +442,7 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,
static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = dac33->fifo_mode;
@@ -442,7 +453,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
int ret = 0;
@@ -612,6 +623,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int dac33_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -620,7 +632,7 @@ static int dac33_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Coming from OFF, switch on the component */
ret = dac33_hard_power(component, 1);
if (ret != 0)
@@ -631,7 +643,7 @@ static int dac33_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_OFF:
/* Do not power off, when the component is already off */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
return 0;
ret = dac33_hard_power(component, 0);
if (ret != 0)
@@ -1462,25 +1474,16 @@ static struct snd_soc_dai_driver dac33_dai = {
static int dac33_i2c_probe(struct i2c_client *client)
{
- struct tlv320dac33_platform_data *pdata;
struct tlv320dac33_priv *dac33;
int ret, i;
- if (client->dev.platform_data == NULL) {
- dev_err(&client->dev, "Platform data not set\n");
- return -ENODEV;
- }
- pdata = client->dev.platform_data;
-
dac33 = devm_kzalloc(&client->dev, sizeof(struct tlv320dac33_priv),
GFP_KERNEL);
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;
@@ -1490,26 +1493,22 @@ static int dac33_i2c_probe(struct i2c_client *client)
i2c_set_clientdata(client, dac33);
- dac33->power_gpio = pdata->power_gpio;
- dac33->burst_bclkdiv = pdata->burst_bclkdiv;
- dac33->keep_bclk = pdata->keep_bclk;
- dac33->mode1_latency = pdata->mode1_latency;
+ if (!dac33->burst_bclkdiv)
+ dac33->burst_bclkdiv = 8;
if (!dac33->mode1_latency)
dac33->mode1_latency = 10000; /* 10ms */
dac33->irq = client->irq;
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;
- /* Check if the reset GPIO number is valid and request it */
- if (dac33->power_gpio >= 0) {
- ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
- if (ret < 0) {
- dev_err(&client->dev,
- "Failed to request reset GPIO (%d)\n",
- dac33->power_gpio);
- goto err_gpio;
- }
- gpio_direction_output(dac33->power_gpio, 0);
+ /* request optional reset GPIO */
+ dac33->reset_gpiod =
+ devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(dac33->reset_gpiod)) {
+ ret = PTR_ERR(dac33->reset_gpiod);
+ dev_err_probe(&client->dev, ret,
+ "Failed to get reset GPIO\n");
+ goto err;
}
for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
@@ -1520,19 +1519,17 @@ static int dac33_i2c_probe(struct i2c_client *client)
if (ret != 0) {
dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
- goto err_get;
+ goto err;
}
ret = devm_snd_soc_register_component(&client->dev,
&soc_component_dev_tlv320dac33, &dac33_dai, 1);
if (ret < 0)
- goto err_get;
+ goto err;
return ret;
-err_get:
- if (dac33->power_gpio >= 0)
- gpio_free(dac33->power_gpio);
-err_gpio:
+
+err:
return ret;
}
@@ -1542,9 +1539,6 @@ static void dac33_i2c_remove(struct i2c_client *client)
if (unlikely(dac33->chip_power))
dac33_hard_power(dac33->component, 0);
-
- if (dac33->power_gpio >= 0)
- gpio_free(dac33->power_gpio);
}
static const struct i2c_device_id tlv320dac33_i2c_id[] = {
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 5bc486283fde..38cc000891ea 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -7,19 +7,17 @@
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
-#include <linux/module.h>
-#include <linux/errno.h>
#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <sound/tpa6130a2-plat.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/regmap.h>
#include "tpa6130a2.h"
@@ -33,7 +31,7 @@ struct tpa6130a2_data {
struct device *dev;
struct regmap *regmap;
struct regulator *supply;
- int power_gpio;
+ struct gpio_desc *power_gpio;
enum tpa_model id;
};
@@ -49,8 +47,7 @@ static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
return ret;
}
/* Power on */
- if (data->power_gpio >= 0)
- gpio_set_value(data->power_gpio, 1);
+ gpiod_set_value(data->power_gpio, 1);
/* Sync registers */
regcache_cache_only(data->regmap, false);
@@ -59,8 +56,7 @@ static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
dev_err(data->dev,
"Failed to sync registers: %d\n", ret);
regcache_cache_only(data->regmap, true);
- if (data->power_gpio >= 0)
- gpio_set_value(data->power_gpio, 0);
+ gpiod_set_value(data->power_gpio, 0);
ret2 = regulator_disable(data->supply);
if (ret2 != 0)
dev_err(data->dev,
@@ -76,8 +72,7 @@ static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
regcache_cache_only(data->regmap, true);
/* Power off */
- if (data->power_gpio >= 0)
- gpio_set_value(data->power_gpio, 0);
+ gpiod_set_value(data->power_gpio, 0);
ret = regulator_disable(data->supply);
if (ret != 0) {
@@ -209,20 +204,11 @@ static const struct regmap_config tpa6130a2_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
-static const struct i2c_device_id tpa6130a2_id[] = {
- { "tpa6130a2", TPA6130A2 },
- { "tpa6140a2", TPA6140A2 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
-
static int tpa6130a2_probe(struct i2c_client *client)
{
struct device *dev;
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;
@@ -239,10 +225,13 @@ static int tpa6130a2_probe(struct i2c_client *client)
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
- if (pdata) {
- data->power_gpio = pdata->power_gpio;
- } else if (np) {
- data->power_gpio = of_get_named_gpio(np, "power-gpio", 0);
+ if (np) {
+ data->power_gpio = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
+ if (IS_ERR(data->power_gpio)) {
+ return dev_err_probe(dev, PTR_ERR(data->power_gpio),
+ "Failed to request power GPIO\n");
+ }
+ gpiod_set_consumer_name(data->power_gpio, "tpa6130a2 enable");
} else {
dev_err(dev, "Platform data not set\n");
dump_stack();
@@ -251,19 +240,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;
-
- if (data->power_gpio >= 0) {
- ret = devm_gpio_request(dev, data->power_gpio,
- "tpa6130a2 enable");
- if (ret < 0) {
- dev_err(dev, "Failed to request power GPIO (%d)\n",
- data->power_gpio);
- return ret;
- }
- gpio_direction_output(data->power_gpio, 0);
- }
+ data->id = (uintptr_t)i2c_get_match_data(client);
switch (data->id) {
default:
@@ -320,7 +297,6 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
.of_match_table = of_match_ptr(tpa6130a2_of_match),
},
.probe = tpa6130a2_probe,
- .id_table = tpa6130a2_id,
};
module_i2c_driver(tpa6130a2_i2c_driver);
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 6d9166d9116a..5ce0db9326fd 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
@@ -400,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);
@@ -420,14 +418,13 @@ 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[] = {
- { "ts3a227e", 0 },
+ { "ts3a227e" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids);
@@ -451,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/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index 1eefc1fe6ea8..7390ab250ebb 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -263,8 +263,7 @@ exit:
static int coeff_ram_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
struct coeff_ram_ctl *ctl =
(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -283,8 +282,7 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
static int coeff_ram_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
struct coeff_ram_ctl *ctl =
(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -1485,8 +1483,8 @@ static int tscs42xx_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id tscs42xx_i2c_id[] = {
- { "tscs42A1", 0 },
- { "tscs42A2", 0 },
+ { "tscs42A1" },
+ { "tscs42A2" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tscs42xx_i2c_id);
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index 744aef32a21f..64d0da40fbaf 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>
@@ -307,8 +308,7 @@ struct reg_setting {
static int coeff_ram_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
struct coeff_ram_ctl *ctl =
(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -388,8 +388,7 @@ static int write_coeff_ram(struct snd_soc_component *component, u8 *coeff_ram,
static int coeff_ram_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
struct coeff_ram_ctl *ctl =
(struct coeff_ram_ctl *)kcontrol->private_value;
@@ -737,9 +736,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;
}
@@ -3457,7 +3454,7 @@ static int tscs454_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id tscs454_i2c_id[] = {
- { "tscs454", 0 },
+ { "tscs454" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tscs454_i2c_id);
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 9c50ac356c89..9476cdfd4dde 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -5,28 +5,25 @@
* Author: Steve Sakoman, <steve@sakoman.com>
*/
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/mfd/twl.h>
+#include <linux/mfd/twl4030-audio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/of.h>
#include <linux/pm.h>
-#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/mfd/twl.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <sound/core.h>
+#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
-/* Register descriptions are here */
-#include <linux/mfd/twl4030-audio.h>
-
/* TWL4030 PMBR1 Register */
#define TWL4030_PMBR1_REG 0x0D
/* TWL4030 PMBR1 Register GPIO6 mux bits */
@@ -39,7 +36,7 @@ struct twl4030_board_params {
unsigned int ramp_delay_value;
unsigned int offset_cncl_path;
unsigned int hs_extmute:1;
- int hs_extmute_gpio;
+ struct gpio_desc *hs_extmute_gpio;
};
/* codec private data */
@@ -213,8 +210,7 @@ twl4030_get_board_param_values(struct twl4030_board_params *board_params,
if (!of_property_read_u32(node, "ti,hs_extmute", &value))
board_params->hs_extmute = value;
- board_params->hs_extmute_gpio = of_get_named_gpio(node, "ti,hs_extmute_gpio", 0);
- if (gpio_is_valid(board_params->hs_extmute_gpio))
+ if (of_property_present(node, "ti,hs_extmute_gpio"))
board_params->hs_extmute = 1;
}
@@ -242,7 +238,7 @@ twl4030_get_board_params(struct snd_soc_component *component)
return board_params;
}
-static void twl4030_init_chip(struct snd_soc_component *component)
+static int twl4030_init_chip(struct snd_soc_component *component)
{
struct twl4030_board_params *board_params;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
@@ -252,24 +248,20 @@ static void twl4030_init_chip(struct snd_soc_component *component)
board_params = twl4030_get_board_params(component);
if (board_params && board_params->hs_extmute) {
- if (gpio_is_valid(board_params->hs_extmute_gpio)) {
- int ret;
-
- if (!board_params->hs_extmute_gpio)
- dev_warn(component->dev,
- "Extmute GPIO is 0 is this correct?\n");
-
- ret = gpio_request_one(board_params->hs_extmute_gpio,
- GPIOF_OUT_INIT_LOW,
- "hs_extmute");
- if (ret) {
- dev_err(component->dev,
- "Failed to get hs_extmute GPIO\n");
- board_params->hs_extmute_gpio = -1;
- }
+ board_params->hs_extmute_gpio = devm_gpiod_get_optional(component->dev,
+ "ti,hs_extmute",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(board_params->hs_extmute_gpio))
+ return dev_err_probe(component->dev, PTR_ERR(board_params->hs_extmute_gpio),
+ "Failed to get hs_extmute GPIO\n");
+
+ if (board_params->hs_extmute_gpio) {
+ gpiod_set_consumer_name(board_params->hs_extmute_gpio, "hs_extmute");
} else {
u8 pin_mux;
+ dev_info(component->dev, "use TWL4030 GPIO6\n");
+
/* Set TWL4030 GPIO6 as EXTMUTE signal */
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
TWL4030_PMBR1_REG);
@@ -297,7 +289,7 @@ static void twl4030_init_chip(struct snd_soc_component *component)
/* Machine dependent setup */
if (!board_params)
- return;
+ return 0;
twl4030->board_params = board_params;
@@ -332,6 +324,8 @@ static void twl4030_init_chip(struct snd_soc_component *component)
TWL4030_CNCL_OFFSET_START));
twl4030_codec_enable(component, 0);
+
+ return 0;
}
static void twl4030_apll_enable(struct snd_soc_component *component, int enable)
@@ -555,7 +549,7 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
* On unmute: restore the register content from the reg_cache
* Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R
*/
-#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
+#define TWL4030_OUTPUT_PGA(pin_name, reg) \
static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
struct snd_kcontrol *kcontrol, int event) \
{ \
@@ -575,11 +569,11 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
return 0; \
}
-TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN);
-TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN);
-TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN);
-TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN);
-TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN);
+TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL);
+TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL);
+TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL);
+TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL);
+TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL);
static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp)
{
@@ -714,8 +708,8 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
/* Enable external mute control, this dramatically reduces
* the pop-noise */
if (board_params && board_params->hs_extmute) {
- if (gpio_is_valid(board_params->hs_extmute_gpio)) {
- gpio_set_value(board_params->hs_extmute_gpio, 1);
+ if (board_params->hs_extmute_gpio) {
+ gpiod_set_value(board_params->hs_extmute_gpio, 1);
} else {
hs_pop |= TWL4030_EXTMUTE;
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -750,8 +744,8 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
/* Disable external mute */
if (board_params && board_params->hs_extmute) {
- if (gpio_is_valid(board_params->hs_extmute_gpio)) {
- gpio_set_value(board_params->hs_extmute_gpio, 0);
+ if (board_params->hs_extmute_gpio) {
+ gpiod_set_value(board_params->hs_extmute_gpio, 0);
} else {
hs_pop &= ~TWL4030_EXTMUTE;
twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -836,7 +830,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
@@ -865,7 +859,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
@@ -894,7 +888,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -921,7 +915,7 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
@@ -962,7 +956,7 @@ static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
if (twl4030->configured) {
@@ -1576,13 +1570,15 @@ static const struct snd_soc_dapm_route intercon[] = {
static int twl4030_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
twl4030_codec_enable(component, 1);
break;
case SND_SOC_BIAS_OFF:
@@ -2049,7 +2045,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:
@@ -2168,24 +2164,11 @@ static int twl4030_soc_probe(struct snd_soc_component *component)
/* Set the defaults, and power up the codec */
twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
- twl4030_init_chip(component);
-
- return 0;
-}
-
-static void twl4030_soc_remove(struct snd_soc_component *component)
-{
- struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
- struct twl4030_board_params *board_params = twl4030->board_params;
-
- if (board_params && board_params->hs_extmute &&
- gpio_is_valid(board_params->hs_extmute_gpio))
- gpio_free(board_params->hs_extmute_gpio);
+ return twl4030_init_chip(component);
}
static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
.probe = twl4030_soc_probe,
- .remove = twl4030_soc_remove,
.read = twl4030_read,
.write = twl4030_write,
.set_bias_level = twl4030_set_bias_level,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index dd5ee5dc0cd7..e10c51092a35 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -323,7 +323,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val;
@@ -472,7 +472,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
@@ -483,7 +483,7 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int high_perf = ucontrol->value.enumerated.item[0];
int ret = 0;
@@ -500,7 +500,7 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
@@ -511,7 +511,7 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
priv->pll_power_mode = ucontrol->value.enumerated.item[0];
@@ -521,7 +521,7 @@ static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
int twl6040_get_dl1_gain(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (snd_soc_dapm_get_pin_status(dapm, "EP"))
return -1; /* -1dB */
@@ -1097,6 +1097,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
static int twl6040_probe(struct snd_soc_component *component)
{
struct twl6040_data *priv;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct platform_device *pdev = to_platform_device(component->dev);
int ret = 0;
@@ -1125,7 +1126,7 @@ static int twl6040_probe(struct snd_soc_component *component)
return ret;
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
twl6040_init_chip(component);
return 0;
diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c
index eace96533600..f799772ff747 100644
--- a/sound/soc/codecs/uda1334.c
+++ b/sound/soc/codecs/uda1334.c
@@ -4,13 +4,13 @@
//
// Based on WM8523 ALSA SoC Audio driver written by Mark Brown
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -42,7 +42,7 @@ static const struct snd_soc_dapm_route uda1334_dapm_routes[] = {
static int uda1334_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);
int deemph = ucontrol->value.integer.value[0];
@@ -57,7 +57,7 @@ static int uda1334_put_deemph(struct snd_kcontrol *kcontrol,
static int uda1334_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component);
int ret;
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
new file mode 100644
index 000000000000..b0b29012842d
--- /dev/null
+++ b/sound/soc/codecs/uda1342.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// uda1342.c -- UDA1342 ALSA SoC Codec driver
+// Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
+//
+// Copyright 2007 Dension Audio Systems Ltd.
+// Copyright 2024 Loongson Technology Co.,Ltd.
+//
+// Modifications by Christian Pellegrin <chripell@evolware.org>
+// Further cleanup and restructuring by:
+// Binbin Zhou <zhoubinbin@loongson.cn>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "uda1342.h"
+
+#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
+
+struct uda1342_priv {
+ int sysclk;
+ int dai_fmt;
+
+ struct snd_pcm_substream *provider_substream;
+ struct snd_pcm_substream *consumer_substream;
+
+ struct regmap *regmap;
+ struct i2c_client *i2c;
+};
+
+static const struct reg_default uda1342_reg_defaults[] = {
+ { 0x00, 0x1042 },
+ { 0x01, 0x0000 },
+ { 0x10, 0x0088 },
+ { 0x11, 0x0000 },
+ { 0x12, 0x0000 },
+ { 0x20, 0x0080 },
+ { 0x21, 0x0080 },
+};
+
+static int uda1342_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ unsigned int mask;
+ unsigned int val = 0;
+
+ /* Master mute */
+ mask = BIT(5);
+ if (mute)
+ val = mask;
+
+ return regmap_update_bits(uda1342->regmap, 0x10, mask, val);
+}
+
+static int uda1342_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ struct snd_pcm_runtime *provider_runtime;
+
+ if (uda1342->provider_substream) {
+ provider_runtime = uda1342->provider_substream->runtime;
+
+ snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE, provider_runtime->rate);
+ snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ provider_runtime->sample_bits);
+
+ uda1342->consumer_substream = substream;
+ } else {
+ uda1342->provider_substream = substream;
+ }
+
+ return 0;
+}
+
+static void uda1342_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+
+ if (uda1342->provider_substream == substream)
+ uda1342->provider_substream = uda1342->consumer_substream;
+
+ uda1342->consumer_substream = NULL;
+}
+
+static int uda1342_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ struct device *dev = &uda1342->i2c->dev;
+ unsigned int hw_params = 0;
+
+ if (substream == uda1342->consumer_substream)
+ return 0;
+
+ /* set SYSCLK / fs ratio */
+ switch (uda1342->sysclk / params_rate(params)) {
+ case 512:
+ break;
+ case 384:
+ hw_params |= BIT(4);
+ break;
+ case 256:
+ hw_params |= BIT(5);
+ break;
+ default:
+ dev_err(dev, "unsupported frequency\n");
+ return -EINVAL;
+ }
+
+ /* set DAI format and word length */
+ switch (uda1342->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_width(params)) {
+ case 16:
+ hw_params |= BIT(1);
+ break;
+ case 18:
+ hw_params |= BIT(2);
+ break;
+ case 20:
+ hw_params |= BIT(2) | BIT(1);
+ break;
+ default:
+ dev_err(dev, "unsupported format (right)\n");
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ hw_params |= BIT(3);
+ break;
+ default:
+ dev_err(dev, "unsupported format\n");
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(uda1342->regmap, 0x0,
+ STATUS0_DAIFMT_MASK | STATUS0_SYSCLK_MASK, hw_params);
+}
+
+static int uda1342_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+ struct device *dev = &uda1342->i2c->dev;
+
+ /*
+ * Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
+ * because the codec is slave. Of course limitations of the clock
+ * master (the IIS controller) apply.
+ * We'll error out on set_hw_params if it's not OK
+ */
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+ uda1342->sysclk = freq;
+ return 0;
+ }
+
+ dev_err(dev, "unsupported sysclk\n");
+
+ return -EINVAL;
+}
+
+static int uda1342_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = codec_dai->component;
+ struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component);
+
+ /* codec supports only full consumer mode */
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) {
+ dev_err(&uda1342->i2c->dev, "unsupported consumer mode.\n");
+ return -EINVAL;
+ }
+
+ /* We can't setup DAI format here as it depends on the word bit num */
+ /* so let's just store the value for later */
+ uda1342->dai_fmt = fmt;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new uda1342_snd_controls[] = {
+ SOC_SINGLE("Master Playback Volume", 0x11, 0, 0x3F, 1),
+ SOC_SINGLE("Analog1 Volume", 0x12, 0, 0x1F, 1),
+};
+
+/* Common DAPM widgets */
+static const struct snd_soc_dapm_widget uda1342_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("VINL1"),
+ SND_SOC_DAPM_INPUT("VINR1"),
+ SND_SOC_DAPM_INPUT("VINL2"),
+ SND_SOC_DAPM_INPUT("VINR2"),
+
+ SND_SOC_DAPM_DAC("DAC", "Playback", 0, 1, 0),
+ SND_SOC_DAPM_ADC("ADC", "Capture", 0, 9, 0),
+
+ SND_SOC_DAPM_OUTPUT("VOUTL"),
+ SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route uda1342_dapm_routes[] = {
+ { "ADC", NULL, "VINL1" },
+ { "ADC", NULL, "VINR1" },
+ { "ADC", NULL, "VINL2" },
+ { "ADC", NULL, "VINR2" },
+ { "VOUTL", NULL, "DAC" },
+ { "VOUTR", NULL, "DAC" },
+};
+
+static const struct snd_soc_dai_ops uda1342_dai_ops = {
+ .startup = uda1342_startup,
+ .shutdown = uda1342_shutdown,
+ .hw_params = uda1342_hw_params,
+ .mute_stream = uda1342_mute,
+ .set_sysclk = uda1342_set_dai_sysclk,
+ .set_fmt = uda1342_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver uda1342_dai = {
+ .name = "uda1342-hifi",
+ /* playback capabilities */
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = UDA134X_FORMATS,
+ },
+ /* capture capabilities */
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = UDA134X_FORMATS,
+ },
+ /* pcm operations */
+ .ops = &uda1342_dai_ops,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_uda1342 = {
+ .controls = uda1342_snd_controls,
+ .num_controls = ARRAY_SIZE(uda1342_snd_controls),
+ .dapm_widgets = uda1342_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(uda1342_dapm_widgets),
+ .dapm_routes = uda1342_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(uda1342_dapm_routes),
+ .suspend_bias_off = 1,
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct regmap_config uda1342_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = 0x21,
+ .reg_defaults = uda1342_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(uda1342_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static int uda1342_i2c_probe(struct i2c_client *i2c)
+{
+ struct uda1342_priv *uda1342;
+
+ uda1342 = devm_kzalloc(&i2c->dev, sizeof(*uda1342), GFP_KERNEL);
+ if (!uda1342)
+ return -ENOMEM;
+
+ uda1342->regmap = devm_regmap_init_i2c(i2c, &uda1342_regmap);
+ if (IS_ERR(uda1342->regmap))
+ return PTR_ERR(uda1342->regmap);
+
+ i2c_set_clientdata(i2c, uda1342);
+ uda1342->i2c = i2c;
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_uda1342,
+ &uda1342_dai, 1);
+}
+
+static int uda1342_suspend(struct device *dev)
+{
+ struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+
+ regcache_cache_only(uda1342->regmap, true);
+
+ return 0;
+}
+
+static int uda1342_resume(struct device *dev)
+{
+ struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+
+ regcache_mark_dirty(uda1342->regmap);
+ regcache_sync(uda1342->regmap);
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(uda1342_pm_ops,
+ uda1342_suspend, uda1342_resume, NULL);
+
+static const struct i2c_device_id uda1342_i2c_id[] = {
+ { "uda1342" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, uda1342_i2c_id);
+
+static const struct of_device_id uda1342_of_match[] = {
+ { .compatible = "nxp,uda1342" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, uda1342_of_match);
+
+static struct i2c_driver uda1342_i2c_driver = {
+ .driver = {
+ .name = "uda1342",
+ .of_match_table = uda1342_of_match,
+ .pm = pm_sleep_ptr(&uda1342_pm_ops),
+ },
+ .probe = uda1342_i2c_probe,
+ .id_table = uda1342_i2c_id,
+};
+module_i2c_driver(uda1342_i2c_driver);
+
+MODULE_DESCRIPTION("UDA1342 ALSA soc codec driver");
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
+MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda1342.h b/sound/soc/codecs/uda1342.h
new file mode 100644
index 000000000000..ff6aea0a8b01
--- /dev/null
+++ b/sound/soc/codecs/uda1342.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Audio support for NXP UDA1342
+ *
+ * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ * Copyright (c) 2024 Binbin Zhou <zhoubinbin@loongson.cn>
+ */
+
+#ifndef _UDA1342_H
+#define _UDA1342_H
+
+#define UDA1342_CLK 0x00
+#define UDA1342_IFACE 0x01
+#define UDA1342_PM 0x02
+#define UDA1342_AMIX 0x03
+#define UDA1342_HP 0x04
+#define UDA1342_MVOL 0x11
+#define UDA1342_MIXVOL 0x12
+#define UDA1342_MODE 0x12
+#define UDA1342_DEEMP 0x13
+#define UDA1342_MIXER 0x14
+#define UDA1342_INTSTAT 0x18
+#define UDA1342_DEC 0x20
+#define UDA1342_PGA 0x21
+#define UDA1342_ADC 0x22
+#define UDA1342_AGC 0x23
+#define UDA1342_DECSTAT 0x28
+#define UDA1342_RESET 0x7f
+
+/* Register flags */
+#define R00_EN_ADC 0x0800
+#define R00_EN_DEC 0x0400
+#define R00_EN_DAC 0x0200
+#define R00_EN_INT 0x0100
+#define R00_DAC_CLK 0x0010
+#define R01_SFORI_I2S 0x0000
+#define R01_SFORI_LSB16 0x0100
+#define R01_SFORI_LSB18 0x0200
+#define R01_SFORI_LSB20 0x0300
+#define R01_SFORI_MSB 0x0500
+#define R01_SFORI_MASK 0x0700
+#define R01_SFORO_I2S 0x0000
+#define R01_SFORO_LSB16 0x0001
+#define R01_SFORO_LSB18 0x0002
+#define R01_SFORO_LSB20 0x0003
+#define R01_SFORO_LSB24 0x0004
+#define R01_SFORO_MSB 0x0005
+#define R01_SFORO_MASK 0x0007
+#define R01_SEL_SOURCE 0x0040
+#define R01_SIM 0x0010
+#define R02_PON_PLL 0x8000
+#define R02_PON_HP 0x2000
+#define R02_PON_DAC 0x0400
+#define R02_PON_BIAS 0x0100
+#define R02_EN_AVC 0x0080
+#define R02_PON_AVC 0x0040
+#define R02_PON_LNA 0x0010
+#define R02_PON_PGAL 0x0008
+#define R02_PON_ADCL 0x0004
+#define R02_PON_PGAR 0x0002
+#define R02_PON_ADCR 0x0001
+#define R13_MTM 0x4000
+#define R14_SILENCE 0x0080
+#define R14_SDET_ON 0x0040
+#define R21_MT_ADC 0x8000
+#define R22_SEL_LNA 0x0008
+#define R22_SEL_MIC 0x0004
+#define R22_SKIP_DCFIL 0x0002
+#define R23_AGC_EN 0x0001
+
+#define UDA1342_DAI_DUPLEX 0 /* playback and capture on single DAI */
+#define UDA1342_DAI_PLAYBACK 1 /* playback DAI */
+#define UDA1342_DAI_CAPTURE 2 /* capture DAI */
+
+#define STATUS0_DAIFMT_MASK (~(7 << 1))
+#define STATUS0_SYSCLK_MASK (~(3 << 4))
+
+#endif /* _UDA1342_H */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
deleted file mode 100644
index 1a62bec94005..000000000000
--- a/sound/soc/codecs/uda134x.c
+++ /dev/null
@@ -1,587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * uda134x.c -- UDA134X ALSA SoC Codec driver
- *
- * Modifications by Christian Pellegrin <chripell@evolware.org>
- *
- * Copyright 2007 Dension Audio Systems Ltd.
- * Author: Zoltan Devai
- *
- * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
-
-#include <sound/uda134x.h>
-#include <sound/l3.h>
-
-#include "uda134x.h"
-
-
-#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
-#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
-
-struct uda134x_priv {
- int sysclk;
- int dai_fmt;
-
- struct snd_pcm_substream *master_substream;
- struct snd_pcm_substream *slave_substream;
-
- struct regmap *regmap;
- struct uda134x_platform_data *pd;
-};
-
-static const struct reg_default uda134x_reg_defaults[] = {
- { UDA134X_EA000, 0x04 },
- { UDA134X_EA001, 0x04 },
- { UDA134X_EA010, 0x04 },
- { UDA134X_EA011, 0x00 },
- { UDA134X_EA100, 0x00 },
- { UDA134X_EA101, 0x00 },
- { UDA134X_EA110, 0x00 },
- { UDA134X_EA111, 0x00 },
- { UDA134X_STATUS0, 0x00 },
- { UDA134X_STATUS1, 0x03 },
- { UDA134X_DATA000, 0x00 },
- { UDA134X_DATA001, 0x00 },
- { UDA134X_DATA010, 0x00 },
- { UDA134X_DATA011, 0x00 },
- { UDA134X_DATA1, 0x00 },
-};
-
-/*
- * Write to the uda134x registers
- *
- */
-static int uda134x_regmap_write(void *context, unsigned int reg,
- unsigned int value)
-{
- struct uda134x_platform_data *pd = context;
- int ret;
- u8 addr;
- u8 data = value;
-
- switch (reg) {
- case UDA134X_STATUS0:
- case UDA134X_STATUS1:
- addr = UDA134X_STATUS_ADDR;
- data |= (reg - UDA134X_STATUS0) << 7;
- break;
- case UDA134X_DATA000:
- case UDA134X_DATA001:
- case UDA134X_DATA010:
- case UDA134X_DATA011:
- addr = UDA134X_DATA0_ADDR;
- data |= (reg - UDA134X_DATA000) << 6;
- break;
- case UDA134X_DATA1:
- addr = UDA134X_DATA1_ADDR;
- break;
- default:
- /* It's an extended address register */
- addr = (reg | UDA134X_EXTADDR_PREFIX);
-
- ret = l3_write(&pd->l3,
- UDA134X_DATA0_ADDR, &addr, 1);
- if (ret != 1)
- return -EIO;
-
- addr = UDA134X_DATA0_ADDR;
- data = (value | UDA134X_EXTDATA_PREFIX);
- break;
- }
-
- ret = l3_write(&pd->l3,
- addr, &data, 1);
- if (ret != 1)
- return -EIO;
-
- return 0;
-}
-
-static inline void uda134x_reset(struct snd_soc_component *component)
-{
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- unsigned int mask = 1<<6;
-
- regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
- msleep(1);
- regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0);
-}
-
-static int uda134x_mute(struct snd_soc_dai *dai, int mute, int direction)
-{
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
- unsigned int mask = 1<<2;
- unsigned int val;
-
- pr_debug("%s mute: %d\n", __func__, mute);
-
- if (mute)
- val = mask;
- else
- val = 0;
-
- return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val);
-}
-
-static int uda134x_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- struct snd_pcm_runtime *master_runtime;
-
- if (uda134x->master_substream) {
- master_runtime = uda134x->master_substream->runtime;
-
- pr_debug("%s constraining to %d bits at %d\n", __func__,
- master_runtime->sample_bits,
- master_runtime->rate);
-
- snd_pcm_hw_constraint_single(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- master_runtime->rate);
-
- snd_pcm_hw_constraint_single(substream->runtime,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- master_runtime->sample_bits);
-
- uda134x->slave_substream = substream;
- } else
- uda134x->master_substream = substream;
-
- return 0;
-}
-
-static void uda134x_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
-
- if (uda134x->master_substream == substream)
- uda134x->master_substream = uda134x->slave_substream;
-
- uda134x->slave_substream = NULL;
-}
-
-static int uda134x_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- unsigned int hw_params = 0;
-
- if (substream == uda134x->slave_substream) {
- pr_debug("%s ignoring hw_params for slave substream\n",
- __func__);
- return 0;
- }
-
- pr_debug("%s sysclk: %d, rate:%d\n", __func__,
- uda134x->sysclk, params_rate(params));
-
- /* set SYSCLK / fs ratio */
- switch (uda134x->sysclk / params_rate(params)) {
- case 512:
- break;
- case 384:
- hw_params |= (1<<4);
- break;
- case 256:
- hw_params |= (1<<5);
- break;
- default:
- printk(KERN_ERR "%s unsupported fs\n", __func__);
- return -EINVAL;
- }
-
- pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
- uda134x->dai_fmt, params_format(params));
-
- /* set DAI format and word length */
- switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- break;
- case SND_SOC_DAIFMT_RIGHT_J:
- switch (params_width(params)) {
- case 16:
- hw_params |= (1<<1);
- break;
- case 18:
- hw_params |= (1<<2);
- break;
- case 20:
- hw_params |= ((1<<2) | (1<<1));
- break;
- default:
- printk(KERN_ERR "%s unsupported format (right)\n",
- __func__);
- return -EINVAL;
- }
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- hw_params |= (1<<3);
- break;
- default:
- printk(KERN_ERR "%s unsupported format\n", __func__);
- return -EINVAL;
- }
-
- return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
- STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
-}
-
-static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct snd_soc_component *component = codec_dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
-
- pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
- clk_id, freq, dir);
-
- /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
- because the codec is slave. Of course limitations of the clock
- master (the IIS controller) apply.
- We'll error out on set_hw_params if it's not OK */
- if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
- uda134x->sysclk = freq;
- return 0;
- }
-
- printk(KERN_ERR "%s unsupported sysclk\n", __func__);
- return -EINVAL;
-}
-
-static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
-{
- struct snd_soc_component *component = codec_dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
-
- pr_debug("%s fmt: %08X\n", __func__, fmt);
-
- /* codec supports only full consumer mode */
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
- printk(KERN_ERR "%s unsupported clocking mode\n", __func__);
- return -EINVAL;
- }
-
- /* no support for clock inversion */
- if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
- printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
- return -EINVAL;
- }
-
- /* We can't setup DAI format here as it depends on the word bit num */
- /* so let's just store the value for later */
- uda134x->dai_fmt = fmt;
-
- return 0;
-}
-
-static int uda134x_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
-{
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- struct uda134x_platform_data *pd = uda134x->pd;
- pr_debug("%s bias level %d\n", __func__, level);
-
- switch (level) {
- case SND_SOC_BIAS_ON:
- break;
- case SND_SOC_BIAS_PREPARE:
- /* power on */
- if (pd->power) {
- pd->power(1);
- regcache_sync(uda134x->regmap);
- }
- break;
- case SND_SOC_BIAS_STANDBY:
- break;
- case SND_SOC_BIAS_OFF:
- /* power off */
- if (pd->power) {
- pd->power(0);
- regcache_mark_dirty(uda134x->regmap);
- }
- break;
- }
- return 0;
-}
-
-static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
- "Minimum2", "Maximum"};
-static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
-static const char *uda134x_mixmode[] = {"Differential", "Analog1",
- "Analog2", "Both"};
-
-static const struct soc_enum uda134x_mixer_enum[] = {
-SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
-SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
-SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
-};
-
-static const struct snd_kcontrol_new uda1341_snd_controls[] = {
-SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
-SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
-SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
-SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
-
-SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
-SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
-
-SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
-SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
-
-SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
-SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
-SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
-
-SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
-SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
-SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
-
-SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
-SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
-SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
-SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
-SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
-SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new uda1340_snd_controls[] = {
-SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
-
-SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
-SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
-
-SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
-SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
-
-SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new uda1345_snd_controls[] = {
-SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
-
-SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
-
-SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
-};
-
-/* UDA1341 has the DAC/ADC power down in STATUS1 */
-static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
- SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
-};
-
-/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
-static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
- SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
-};
-
-/* Common DAPM widgets */
-static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
- SND_SOC_DAPM_INPUT("VINL1"),
- SND_SOC_DAPM_INPUT("VINR1"),
- SND_SOC_DAPM_INPUT("VINL2"),
- SND_SOC_DAPM_INPUT("VINR2"),
- SND_SOC_DAPM_OUTPUT("VOUTL"),
- SND_SOC_DAPM_OUTPUT("VOUTR"),
-};
-
-static const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
- { "ADC", NULL, "VINL1" },
- { "ADC", NULL, "VINR1" },
- { "ADC", NULL, "VINL2" },
- { "ADC", NULL, "VINR2" },
- { "VOUTL", NULL, "DAC" },
- { "VOUTR", NULL, "DAC" },
-};
-
-static const struct snd_soc_dai_ops uda134x_dai_ops = {
- .startup = uda134x_startup,
- .shutdown = uda134x_shutdown,
- .hw_params = uda134x_hw_params,
- .mute_stream = uda134x_mute,
- .set_sysclk = uda134x_set_dai_sysclk,
- .set_fmt = uda134x_set_dai_fmt,
- .no_capture_mute = 1,
-};
-
-static struct snd_soc_dai_driver uda134x_dai = {
- .name = "uda134x-hifi",
- /* playback capabilities */
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = UDA134X_RATES,
- .formats = UDA134X_FORMATS,
- },
- /* capture capabilities */
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = UDA134X_RATES,
- .formats = UDA134X_FORMATS,
- },
- /* pcm operations */
- .ops = &uda134x_dai_ops,
-};
-
-static int uda134x_soc_probe(struct snd_soc_component *component)
-{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- struct uda134x_platform_data *pd = uda134x->pd;
- const struct snd_soc_dapm_widget *widgets;
- unsigned int num_widgets;
- int ret;
-
- printk(KERN_INFO "UDA134X SoC Audio Codec\n");
-
- switch (pd->model) {
- case UDA134X_UDA1340:
- case UDA134X_UDA1341:
- case UDA134X_UDA1344:
- case UDA134X_UDA1345:
- break;
- default:
- printk(KERN_ERR "UDA134X SoC codec: "
- "unsupported model %d\n",
- pd->model);
- return -EINVAL;
- }
-
- if (pd->power)
- pd->power(1);
-
- uda134x_reset(component);
-
- if (pd->model == UDA134X_UDA1341) {
- widgets = uda1341_dapm_widgets;
- num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
- } else {
- widgets = uda1340_dapm_widgets;
- num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
- }
-
- ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
- if (ret) {
- printk(KERN_ERR "%s failed to register dapm controls: %d",
- __func__, ret);
- return ret;
- }
-
- switch (pd->model) {
- case UDA134X_UDA1340:
- case UDA134X_UDA1344:
- ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
- ARRAY_SIZE(uda1340_snd_controls));
- break;
- case UDA134X_UDA1341:
- ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
- ARRAY_SIZE(uda1341_snd_controls));
- break;
- case UDA134X_UDA1345:
- ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
- ARRAY_SIZE(uda1345_snd_controls));
- break;
- default:
- printk(KERN_ERR "%s unknown codec type: %d",
- __func__, pd->model);
- return -EINVAL;
- }
-
- if (ret < 0) {
- printk(KERN_ERR "UDA134X: failed to register controls\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_component_driver soc_component_dev_uda134x = {
- .probe = uda134x_soc_probe,
- .set_bias_level = uda134x_set_bias_level,
- .dapm_widgets = uda134x_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
- .dapm_routes = uda134x_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
- .suspend_bias_off = 1,
- .idle_bias_on = 1,
- .use_pmdown_time = 1,
- .endianness = 1,
-};
-
-static const struct regmap_config uda134x_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = UDA134X_DATA1,
- .reg_defaults = uda134x_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
-
- .reg_write = uda134x_regmap_write,
-};
-
-static int uda134x_codec_probe(struct platform_device *pdev)
-{
- struct uda134x_platform_data *pd = pdev->dev.platform_data;
- struct uda134x_priv *uda134x;
- int ret;
-
- if (!pd) {
- dev_err(&pdev->dev, "Missing L3 bitbang function\n");
- return -ENODEV;
- }
-
- uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL);
- if (!uda134x)
- return -ENOMEM;
-
- uda134x->pd = pd;
- platform_set_drvdata(pdev, uda134x);
-
- if (pd->l3.use_gpios) {
- ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3);
- if (ret < 0)
- return ret;
- }
-
- uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
- &uda134x_regmap_config);
- if (IS_ERR(uda134x->regmap))
- return PTR_ERR(uda134x->regmap);
-
- return devm_snd_soc_register_component(&pdev->dev,
- &soc_component_dev_uda134x, &uda134x_dai, 1);
-}
-
-static struct platform_driver uda134x_codec_driver = {
- .driver = {
- .name = "uda134x-codec",
- },
- .probe = uda134x_codec_probe,
-};
-
-module_platform_driver(uda134x_codec_driver);
-
-MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
-MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
deleted file mode 100644
index 664618c2571c..000000000000
--- a/sound/soc/codecs/uda134x.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _UDA134X_CODEC_H
-#define _UDA134X_CODEC_H
-
-#define UDA134X_L3ADDR 5
-#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0)
-#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1)
-#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2)
-
-#define UDA134X_EXTADDR_PREFIX 0xC0
-#define UDA134X_EXTDATA_PREFIX 0xE0
-
-/* UDA134X registers */
-#define UDA134X_EA000 0
-#define UDA134X_EA001 1
-#define UDA134X_EA010 2
-#define UDA134X_EA011 3
-#define UDA134X_EA100 4
-#define UDA134X_EA101 5
-#define UDA134X_EA110 6
-#define UDA134X_EA111 7
-#define UDA134X_STATUS0 8
-#define UDA134X_STATUS1 9
-#define UDA134X_DATA000 10
-#define UDA134X_DATA001 11
-#define UDA134X_DATA010 12
-#define UDA134X_DATA011 13
-#define UDA134X_DATA1 14
-
-#define STATUS0_DAIFMT_MASK (~(7<<1))
-#define STATUS0_SYSCLK_MASK (~(3<<4))
-
-#endif
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 5c5751dc14e5..9e9c540a45ca 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -588,6 +588,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
static int uda1380_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int pm = uda1380_read_reg_cache(component, UDA1380_PM);
int reg;
struct uda1380_platform_data *pdata = component->dev->platform_data;
@@ -599,7 +600,7 @@ static int uda1380_set_bias_level(struct snd_soc_component *component,
uda1380_write(component, UDA1380_PM, R02_PON_BIAS | pm);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
if (gpio_is_valid(pdata->gpio_power)) {
gpio_set_value(pdata->gpio_power, 1);
mdelay(1);
@@ -766,10 +767,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;
@@ -782,7 +781,7 @@ static int uda1380_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id uda1380_i2c_id[] = {
- { "uda1380", 0 },
+ { "uda1380" },
{ }
};
MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
index a75db27e5205..d96e23ec43d4 100644
--- a/sound/soc/codecs/wcd-clsh-v2.c
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -355,6 +355,7 @@ void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode)
wcd_clsh_v2_set_hph_mode(comp, mode);
}
+EXPORT_SYMBOL_GPL(wcd_clsh_set_hph_mode);
static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp,
int mode)
@@ -869,11 +870,13 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
return 0;
}
+EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_set_state);
int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl)
{
return ctrl->state;
}
+EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_get_state);
struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
int version)
@@ -890,8 +893,13 @@ struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
return ctrl;
}
+EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_alloc);
void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl)
{
kfree(ctrl);
}
+EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_free);
+
+MODULE_DESCRIPTION("WCD93XX Class-H driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h
index 4e3653058275..eeb9bc5b01e2 100644
--- a/sound/soc/codecs/wcd-clsh-v2.h
+++ b/sound/soc/codecs/wcd-clsh-v2.h
@@ -47,6 +47,7 @@ enum wcd_codec_version {
/* New CLSH after this */
WCD937X = 2,
WCD938X = 3,
+ WCD939X = 4,
};
struct wcd_clsh_ctrl;
diff --git a/sound/soc/codecs/wcd-common.c b/sound/soc/codecs/wcd-common.c
new file mode 100644
index 000000000000..9016e974582f
--- /dev/null
+++ b/sound/soc/codecs/wcd-common.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries.
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/printk.h>
+#include <linux/component.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/regmap.h>
+
+#include "wcd-common.h"
+
+#define WCD_MIN_MICBIAS_MV 1000
+#define WCD_DEF_MICBIAS_MV 1800
+#define WCD_MAX_MICBIAS_MV 2850
+
+#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
+
+int wcd_get_micb_vout_ctl_val(struct device *dev, u32 micb_mv)
+{
+ /* min micbias voltage is 1V and maximum is 2.85V */
+ if (micb_mv < WCD_MIN_MICBIAS_MV || micb_mv > WCD_MAX_MICBIAS_MV) {
+ dev_err(dev, "Unsupported micbias voltage (%u mV)\n", micb_mv);
+ return -EINVAL;
+ }
+
+ return (micb_mv - WCD_MIN_MICBIAS_MV) / 50;
+}
+EXPORT_SYMBOL_GPL(wcd_get_micb_vout_ctl_val);
+
+static int wcd_get_micbias_val(struct device *dev, int micb_num, u32 *micb_mv)
+{
+ char micbias[64];
+ int mv;
+
+ sprintf(micbias, "qcom,micbias%d-microvolt", micb_num);
+
+ if (of_property_read_u32(dev->of_node, micbias, &mv)) {
+ dev_err(dev, "%s value not found, using default\n", micbias);
+ mv = WCD_DEF_MICBIAS_MV;
+ } else {
+ /* convert it to milli volts */
+ mv = mv/1000;
+ }
+ if (micb_mv)
+ *micb_mv = mv;
+
+ mv = wcd_get_micb_vout_ctl_val(dev, mv);
+ if (mv < 0) {
+ dev_err(dev, "Unsupported %s voltage (%d mV), falling back to default (%d mV)\n",
+ micbias, mv, WCD_DEF_MICBIAS_MV);
+ return wcd_get_micb_vout_ctl_val(dev, WCD_DEF_MICBIAS_MV);
+ }
+
+ return mv;
+}
+
+int wcd_dt_parse_micbias_info(struct wcd_common *common)
+{
+ int ret, i;
+
+ for (i = 0; i < common->max_bias; i++) {
+ ret = wcd_get_micbias_val(common->dev, i + 1, &common->micb_mv[i]);
+ if (ret < 0)
+ return ret;
+ common->micb_vout[i] = ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd_dt_parse_micbias_info);
+
+static int wcd_sdw_component_bind(struct device *dev, struct device *master, void *data)
+{
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static void wcd_sdw_component_unbind(struct device *dev, struct device *master, void *data)
+{
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+}
+
+const struct component_ops wcd_sdw_component_ops = {
+ .bind = wcd_sdw_component_bind,
+ .unbind = wcd_sdw_component_unbind,
+};
+EXPORT_SYMBOL_GPL(wcd_sdw_component_ops);
+
+int wcd_update_status(struct sdw_slave *slave, enum sdw_slave_status status)
+{
+ struct regmap *regmap = dev_get_regmap(&slave->dev, NULL);
+
+ if (regmap && status == SDW_SLAVE_ATTACHED) {
+ /* Write out any cached changes that happened between probe and attach */
+ regcache_cache_only(regmap, false);
+ return regcache_sync(regmap);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd_update_status);
+
+int wcd_bus_config(struct sdw_slave *slave, struct sdw_bus_params *params)
+{
+ sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd_bus_config);
+
+int wcd_interrupt_callback(struct sdw_slave *slave, struct irq_domain *slave_irq,
+ unsigned int wcd_intr_status0, unsigned int wcd_intr_status1,
+ unsigned int wcd_intr_status2)
+{
+ struct regmap *regmap = dev_get_regmap(&slave->dev, NULL);
+ u32 sts1, sts2, sts3;
+
+ do {
+ handle_nested_irq(irq_find_mapping(slave_irq, 0));
+ regmap_read(regmap, wcd_intr_status0, &sts1);
+ regmap_read(regmap, wcd_intr_status1, &sts2);
+ regmap_read(regmap, wcd_intr_status2, &sts3);
+
+ } while (sts1 || sts2 || sts3);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wcd_interrupt_callback);
+
+MODULE_DESCRIPTION("Common Qualcomm WCD Codec helpers driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd-common.h b/sound/soc/codecs/wcd-common.h
new file mode 100644
index 000000000000..d5c156e641fc
--- /dev/null
+++ b/sound/soc/codecs/wcd-common.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __WCD_COMMON_H__
+#define __WCD_COMMON_H__
+
+struct device;
+struct sdw_slave;
+struct sdw_bus_params;
+struct irq_domain;
+enum sdw_slave_status;
+
+#define WCD_MAX_MICBIAS 4
+
+struct wcd_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 wcd_common {
+ struct device *dev;
+ int max_bias;
+ u32 micb_mv[WCD_MAX_MICBIAS];
+ u32 micb_vout[WCD_MAX_MICBIAS];
+};
+
+extern const struct component_ops wcd_sdw_component_ops;
+int wcd_get_micb_vout_ctl_val(struct device *dev, u32 micb_mv);
+int wcd_dt_parse_micbias_info(struct wcd_common *common);
+int wcd_update_status(struct sdw_slave *slave, enum sdw_slave_status status);
+int wcd_bus_config(struct sdw_slave *slave, struct sdw_bus_params *params);
+int wcd_interrupt_callback(struct sdw_slave *slave, struct irq_domain *slave_irq,
+ unsigned int wcd_intr_status0, unsigned int wcd_intr_status1,
+ unsigned int wcd_intr_status2);
+
+#endif /* __WCD_COMMON_H__ */
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 1911750f7445..26ebcdadeb7d 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -16,6 +16,7 @@
#define HS_DETECT_PLUG_TIME_MS (3 * 1000)
#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
#define GND_MIC_SWAP_THRESHOLD 4
+#define GND_MIC_USBC_SWAP_THRESHOLD 2
#define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100
#define HPHL_CROSS_CONN_THRESHOLD 100
#define HS_VREF_MIN_VAL 1400
@@ -49,15 +50,18 @@ struct wcd_mbhc {
struct wcd_mbhc_config *cfg;
const struct wcd_mbhc_cb *mbhc_cb;
const struct wcd_mbhc_intr *intr_ids;
- struct wcd_mbhc_field *fields;
+ const struct wcd_mbhc_field *fields;
/* Delayed work to report long button press */
struct delayed_work mbhc_btn_dwork;
+ /* Work to handle plug report */
+ struct work_struct mbhc_plug_detect_work;
/* Work to correct accessory type */
struct work_struct correct_plug_swch;
struct mutex lock;
int buttons_pressed;
u32 hph_status; /* track headhpone status */
u8 current_plug;
+ unsigned int swap_thr;
bool is_btn_press;
bool in_swch_irq_handler;
bool hs_detect_work_stop;
@@ -506,14 +510,13 @@ static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
}
}
-static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
+static void mbhc_plug_detect_fn(struct work_struct *work)
{
- struct snd_soc_component *component;
+ struct wcd_mbhc *mbhc = container_of(work, struct wcd_mbhc, mbhc_plug_detect_work);
+ struct snd_soc_component *component = mbhc->component;
enum snd_jack_types jack_type;
- struct wcd_mbhc *mbhc = data;
bool detection_type;
- component = mbhc->component;
mutex_lock(&mbhc->lock);
mbhc->in_swch_irq_handler = true;
@@ -576,9 +579,51 @@ static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
exit:
mbhc->in_swch_irq_handler = false;
mutex_unlock(&mbhc->lock);
+}
+
+static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
+{
+ struct wcd_mbhc *mbhc = data;
+
+ if (!mbhc->cfg->typec_analog_mux)
+ schedule_work(&mbhc->mbhc_plug_detect_work);
+
return IRQ_HANDLED;
}
+int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc)
+{
+
+ if (!mbhc || !mbhc->cfg->typec_analog_mux)
+ return -EINVAL;
+
+ if (mbhc->mbhc_cb->clk_setup)
+ mbhc->mbhc_cb->clk_setup(mbhc->component, false);
+
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0);
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, 0);
+
+ schedule_work(&mbhc->mbhc_plug_detect_work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_unplug);
+
+int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc)
+{
+ if (!mbhc || !mbhc->cfg->typec_analog_mux)
+ return -EINVAL;
+
+ if (mbhc->mbhc_cb->clk_setup)
+ mbhc->mbhc_cb->clk_setup(mbhc->component, true);
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
+
+ schedule_work(&mbhc->mbhc_plug_detect_work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_plug);
+
static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
{
int mask = 0;
@@ -725,14 +770,23 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
mutex_lock(&mbhc->lock);
- /* enable HS detection */
+ if (mbhc->cfg->typec_analog_mux)
+ mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD;
+ else
+ mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD;
+
+ /* setup HS detection */
if (mbhc->mbhc_cb->hph_pull_up_control_v2)
mbhc->mbhc_cb->hph_pull_up_control_v2(component,
- HS_PULLUP_I_DEFAULT);
+ mbhc->cfg->typec_analog_mux ?
+ HS_PULLUP_I_OFF : HS_PULLUP_I_DEFAULT);
else if (mbhc->mbhc_cb->hph_pull_up_control)
- mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT);
+ mbhc->mbhc_cb->hph_pull_up_control(component,
+ mbhc->cfg->typec_analog_mux ?
+ I_OFF : I_DEFAULT);
else
- wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
+ mbhc->cfg->typec_analog_mux ? 0 : 3);
wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh);
wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh);
@@ -741,10 +795,18 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true);
wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
- wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
+ /* Plug detect is triggered manually if analog goes through USBCC */
+ if (mbhc->cfg->typec_analog_mux)
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0);
+ else
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
- /* Insertion debounce set to 96ms */
- wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
+ if (mbhc->cfg->typec_analog_mux)
+ /* Insertion debounce set to 48ms */
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 4);
+ else
+ /* Insertion debounce set to 96ms */
+ wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
/* Button Debounce set to 16ms */
wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
@@ -753,7 +815,8 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
mbhc->mbhc_cb->mbhc_bias(component, true);
/* enable MBHC clock */
if (mbhc->mbhc_cb->clk_setup)
- mbhc->mbhc_cb->clk_setup(component, true);
+ mbhc->mbhc_cb->clk_setup(component,
+ mbhc->cfg->typec_analog_mux ? false : true);
/* program HS_VREF value */
wcd_program_hs_vref(mbhc);
@@ -762,7 +825,6 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
mutex_unlock(&mbhc->lock);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return 0;
@@ -1115,7 +1177,7 @@ static void wcd_correct_swch_plug(struct work_struct *work)
do {
cross_conn = wcd_check_cross_conn(mbhc);
try++;
- } while (try < GND_MIC_SWAP_THRESHOLD);
+ } while (try < mbhc->swap_thr);
if (cross_conn > 0) {
plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
@@ -1183,7 +1245,7 @@ correct_plug_type:
cross_conn = wcd_check_cross_conn(mbhc);
if (cross_conn > 0) { /* cross-connection */
pt_gnd_mic_swap_cnt++;
- if (pt_gnd_mic_swap_cnt < GND_MIC_SWAP_THRESHOLD)
+ if (pt_gnd_mic_swap_cnt < mbhc->swap_thr)
continue;
else
plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
@@ -1194,10 +1256,10 @@ correct_plug_type:
} else /* Error if (cross_conn < 0) */
continue;
- if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) {
+ if (pt_gnd_mic_swap_cnt == mbhc->swap_thr) {
/* US_EU gpio present, flip switch */
if (mbhc->cfg->swap_gnd_mic) {
- if (mbhc->cfg->swap_gnd_mic(component, true))
+ if (mbhc->cfg->swap_gnd_mic(component))
continue;
}
}
@@ -1256,7 +1318,6 @@ exit:
if (mbhc->mbhc_cb->hph_pull_down_ctrl)
mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
}
@@ -1442,7 +1503,7 @@ EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
const struct wcd_mbhc_cb *mbhc_cb,
const struct wcd_mbhc_intr *intr_ids,
- struct wcd_mbhc_field *fields,
+ const struct wcd_mbhc_field *fields,
bool impedance_det_en)
{
struct device *dev = component->dev;
@@ -1454,7 +1515,7 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
return ERR_PTR(-EINVAL);
}
- mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL);
+ mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL);
if (!mbhc)
return ERR_PTR(-ENOMEM);
@@ -1473,62 +1534,78 @@ struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
mutex_init(&mbhc->lock);
INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
+ INIT_WORK(&mbhc->mbhc_plug_detect_work, mbhc_plug_detect_fn);
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL,
wcd_mbhc_mech_plug_detect_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"mbhc sw intr", mbhc);
if (ret)
- goto err;
+ goto err_free_mbhc;
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL,
wcd_mbhc_btn_press_handler,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"Button Press detect", mbhc);
if (ret)
- goto err;
+ goto err_free_sw_intr;
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL,
wcd_mbhc_btn_release_handler,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"Button Release detect", mbhc);
if (ret)
- goto err;
+ goto err_free_btn_press_intr;
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
wcd_mbhc_adc_hs_ins_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"Elect Insert", mbhc);
if (ret)
- goto err;
+ goto err_free_btn_release_intr;
disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
wcd_mbhc_adc_hs_rem_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"Elect Remove", mbhc);
if (ret)
- goto err;
+ goto err_free_hs_ins_intr;
disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL,
wcd_mbhc_hphl_ocp_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"HPH_L OCP detect", mbhc);
if (ret)
- goto err;
+ goto err_free_hs_rem_intr;
- ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL,
+ ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL,
wcd_mbhc_hphr_ocp_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"HPH_R OCP detect", mbhc);
if (ret)
- goto err;
+ goto err_free_hph_left_ocp;
return mbhc;
-err:
+
+err_free_hph_left_ocp:
+ free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
+err_free_hs_rem_intr:
+ free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
+err_free_hs_ins_intr:
+ free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
+err_free_btn_release_intr:
+ free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
+err_free_btn_press_intr:
+ free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
+err_free_sw_intr:
+ free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
+err_free_mbhc:
+ kfree(mbhc);
+
dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
return ERR_PTR(ret);
@@ -1537,9 +1614,20 @@ EXPORT_SYMBOL(wcd_mbhc_init);
void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
{
+ free_irq(mbhc->intr_ids->hph_right_ocp, mbhc);
+ free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
+ free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
+ free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
+ free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
+ free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
+ free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
+
mutex_lock(&mbhc->lock);
wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
+ cancel_work_sync(&mbhc->mbhc_plug_detect_work);
mutex_unlock(&mbhc->lock);
+
+ kfree(mbhc);
}
EXPORT_SYMBOL(wcd_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index 006118f3e81f..a5d52b9643f5 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -193,7 +193,8 @@ struct wcd_mbhc_config {
int v_hs_max;
int num_btn;
bool mono_stero_detection;
- bool (*swap_gnd_mic)(struct snd_soc_component *component, bool active);
+ bool typec_analog_mux;
+ bool (*swap_gnd_mic)(struct snd_soc_component *component);
bool hs_ext_micbias;
bool gnd_det_en;
uint32_t linein_th;
@@ -273,10 +274,12 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg,
void wcd_mbhc_stop(struct wcd_mbhc *mbhc);
void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type);
int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc);
+int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc);
+int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc);
struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
const struct wcd_mbhc_cb *mbhc_cb,
const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
- struct wcd_mbhc_field *fields,
+ const struct wcd_mbhc_field *fields,
bool impedance_det_en);
int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
uint32_t *zr);
@@ -297,7 +300,7 @@ static inline void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
static inline struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
const struct wcd_mbhc_cb *mbhc_cb,
const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
- struct wcd_mbhc_field *fields,
+ const struct wcd_mbhc_field *fields,
bool impedance_det_en)
{
return ERR_PTR(-ENOTSUPP);
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 8bf3510a3ea3..640e43ee1975 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/bitops.h>
@@ -16,7 +17,7 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <sound/tlv.h>
@@ -158,6 +159,8 @@
{"AMIC MUX" #id, "ADC5", "ADC5"}, \
{"AMIC MUX" #id, "ADC6", "ADC6"}
+#define NUM_CODEC_DAIS 7
+
enum {
WCD9335_RX0 = 0,
WCD9335_RX1,
@@ -297,7 +300,6 @@ struct wcd9335_codec {
struct clk *mclk;
struct clk *native_clk;
u32 mclk_rate;
- u8 version;
struct slim_device *slim;
struct slim_device *slim_ifc_dev;
@@ -310,7 +312,6 @@ struct wcd9335_codec {
u32 num_rx_port;
u32 num_tx_port;
- int sido_input_src;
enum wcd9335_sido_voltage sido_voltage;
struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS];
@@ -329,8 +330,7 @@ struct wcd9335_codec {
int comp_enabled[COMPANDER_MAX];
int intr1;
- int reset_gpio;
- struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
+ struct gpio_desc *reset_gpio;
unsigned int rx_port_value[WCD9335_RX_MAX];
unsigned int tx_port_value[WCD9335_TX_MAX];
@@ -345,10 +345,6 @@ struct wcd9335_codec {
int dmic_0_1_clk_cnt;
int dmic_2_3_clk_cnt;
int dmic_4_5_clk_cnt;
- int dmic_sample_rate;
- int mad_dmic_sample_rate;
-
- int native_clk_users;
};
struct wcd9335_irq {
@@ -357,6 +353,10 @@ struct wcd9335_irq {
char *name;
};
+static const char * const wcd9335_supplies[] = {
+ "vdd-buck", "vdd-buck-sido", "vdd-tx", "vdd-rx", "vdd-io",
+};
+
static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = {
WCD9335_SLIM_TX_CH(0),
WCD9335_SLIM_TX_CH(1),
@@ -397,13 +397,13 @@ struct interp_sample_rate {
int rate_val;
};
-static struct interp_sample_rate int_mix_rate_val[] = {
+static const struct interp_sample_rate int_mix_rate_val[] = {
{48000, 0x4}, /* 48K */
{96000, 0x5}, /* 96K */
{192000, 0x6}, /* 192K */
};
-static struct interp_sample_rate int_prim_rate_val[] = {
+static const struct interp_sample_rate int_prim_rate_val[] = {
{8000, 0x0}, /* 8K */
{16000, 0x1}, /* 16K */
{24000, -EINVAL},/* 24K */
@@ -1260,8 +1260,9 @@ static const struct snd_kcontrol_new sb_tx8_mux =
static int slim_rx_mux_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
- struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev);
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_to_widget(kc);
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+ struct wcd9335_codec *wcd = dev_get_drvdata(dev);
u32 port_id = w->shift;
ucontrol->value.enumerated.item[0] = wcd->rx_port_value[port_id];
@@ -1272,8 +1273,9 @@ static int slim_rx_mux_get(struct snd_kcontrol *kc,
static int slim_rx_mux_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
- struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev);
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_to_widget(kc);
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+ struct wcd9335_codec *wcd = dev_get_drvdata(dev);
struct soc_enum *e = (struct soc_enum *)kc->private_value;
struct snd_soc_dapm_update *update = NULL;
u32 port_id = w->shift;
@@ -1323,9 +1325,10 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
- struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc);
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+ struct wcd9335_codec *wcd = dev_get_drvdata(dev);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kc);
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kc->private_value;
int dai_id = widget->shift;
@@ -1340,8 +1343,9 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
- struct wcd9335_codec *wcd = dev_get_drvdata(widget->dapm->dev);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kc);
+ struct device *dev = snd_soc_dapm_to_dev(widget->dapm);
+ struct wcd9335_codec *wcd = dev_get_drvdata(dev);
struct snd_soc_dapm_update *update = NULL;
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kc->private_value;
@@ -1474,7 +1478,7 @@ static const struct snd_kcontrol_new aif3_cap_mixer[] = {
static int wcd9335_put_dec_enum(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct soc_enum *e = (struct soc_enum *)kc->private_value;
unsigned int val, reg, sel;
@@ -1529,7 +1533,7 @@ static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc,
struct snd_soc_component *component;
int reg, val;
- component = snd_soc_dapm_kcontrol_component(kc);
+ component = snd_soc_dapm_kcontrol_to_component(kc);
val = ucontrol->value.enumerated.item[0];
if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0)
@@ -1983,8 +1987,10 @@ static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd,
}
static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct wcd9335_codec *wcd;
int i;
@@ -2012,7 +2018,7 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
+static int wcd9335_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)
{
@@ -2175,7 +2181,7 @@ static int wcd9335_get_compander(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
int comp = ((struct soc_mixer_control *)kc->private_value)->shift;
struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
@@ -2186,7 +2192,7 @@ static int wcd9335_get_compander(struct snd_kcontrol *kc,
static int wcd9335_set_compander(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
int comp = ((struct soc_mixer_control *) kc->private_value)->shift;
int value = ucontrol->value.integer.value[0];
@@ -2225,7 +2231,7 @@ static int wcd9335_set_compander(struct snd_kcontrol *kc,
static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
ucontrol->value.enumerated.item[0] = wcd->hph_mode;
@@ -2236,7 +2242,7 @@ static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kc,
static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
u32 mode_val;
@@ -2717,25 +2723,23 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
unsigned int decimator;
char *dec_adc_mux_name = NULL;
- char *widget_name = NULL;
- char *wname;
+ char *widget_name;
int ret = 0, amic_n;
u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
u16 tx_gain_ctl_reg;
char *dec;
u8 hpf_coff_freq;
- widget_name = kmemdup_nul(w->name, 15, GFP_KERNEL);
- if (!widget_name)
+ char *wname __free(kfree) = kmemdup_nul(w->name, 15, GFP_KERNEL);
+ if (!wname)
return -ENOMEM;
- wname = widget_name;
+ widget_name = wname;
dec_adc_mux_name = strsep(&widget_name, " ");
if (!dec_adc_mux_name) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, w->name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
dec_adc_mux_name = widget_name;
@@ -2743,16 +2747,14 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
if (!dec) {
dev_err(comp->dev, "%s: decimator index not found\n",
__func__);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ret = kstrtouint(dec, 10, &decimator);
if (ret < 0) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, wname);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator;
@@ -2839,62 +2841,20 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00);
break;
}
-out:
- kfree(wname);
+
return ret;
}
static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component,
- u32 mclk_rate, u32 dmic_clk_rate)
+ u32 mclk_rate)
{
- u32 div_factor;
u8 dmic_ctl_val;
- dev_err(component->dev,
- "%s: mclk_rate = %d, dmic_sample_rate = %d\n",
- __func__, mclk_rate, dmic_clk_rate);
-
- /* Default value to return in case of error */
if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ)
dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
else
dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
- if (dmic_clk_rate == 0) {
- dev_err(component->dev,
- "%s: dmic_sample_rate cannot be 0\n",
- __func__);
- goto done;
- }
-
- div_factor = mclk_rate / dmic_clk_rate;
- switch (div_factor) {
- case 2:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
- break;
- case 3:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
- break;
- case 4:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4;
- break;
- case 6:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6;
- break;
- case 8:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8;
- break;
- case 16:
- dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16;
- break;
- default:
- dev_err(component->dev,
- "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
- __func__, div_factor, mclk_rate, dmic_clk_rate);
- break;
- }
-
-done:
return dmic_ctl_val;
}
@@ -2948,11 +2908,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- dmic_rate_val =
- wcd9335_get_dmic_clk_val(comp,
- wcd->mclk_rate,
- wcd->dmic_sample_rate);
-
+ dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate);
(*dmic_clk_cnt)++;
if (*dmic_clk_cnt == 1) {
snd_soc_component_update_bits(comp, dmic_clk_reg,
@@ -2964,10 +2920,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMD:
- dmic_rate_val =
- wcd9335_get_dmic_clk_val(comp,
- wcd->mclk_rate,
- wcd->mad_dmic_sample_rate);
+ dmic_rate_val = wcd9335_get_dmic_clk_val(comp, wcd->mclk_rate);
(*dmic_clk_cnt)--;
if (*dmic_clk_cnt == 0) {
snd_soc_component_update_bits(comp, dmic_clk_reg,
@@ -3033,7 +2986,6 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
u16 gain_reg;
- int offset_val = 0;
int val = 0;
switch (w->reg) {
@@ -3073,7 +3025,6 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
val = snd_soc_component_read(comp, gain_reg);
- val += offset_val;
snd_soc_component_write(comp, gain_reg, val);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -3294,33 +3245,32 @@ static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
u16 gain_reg;
u16 reg;
int val;
- int offset_val = 0;
- if (!(strcmp(w->name, "RX INT0 INTERP"))) {
+ if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT0 INTERP"))) {
reg = WCD9335_CDC_RX0_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT1 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT1 INTERP"))) {
reg = WCD9335_CDC_RX1_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT2 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT2 INTERP"))) {
reg = WCD9335_CDC_RX2_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT3 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT3 INTERP"))) {
reg = WCD9335_CDC_RX3_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT4 INTERP"))) {
reg = WCD9335_CDC_RX4_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT5 INTERP"))) {
reg = WCD9335_CDC_RX5_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT6 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT6 INTERP"))) {
reg = WCD9335_CDC_RX6_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT7 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT7 INTERP"))) {
reg = WCD9335_CDC_RX7_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL;
- } else if (!(strcmp(w->name, "RX INT8 INTERP"))) {
+ } else if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT8 INTERP"))) {
reg = WCD9335_CDC_RX8_RX_PATH_CTL;
gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL;
} else {
@@ -3337,7 +3287,6 @@ static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
wcd9335_config_compander(comp, w->shift, event);
val = snd_soc_component_read(comp, gain_reg);
- val += offset_val;
snd_soc_component_write(comp, gain_reg, val);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -4028,7 +3977,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
return ret;
}
-static struct wcd9335_irq wcd9335_irqs[] = {
+static const struct wcd9335_irq wcd9335_irqs[] = {
{
.irq = WCD9335_IRQ_SLIMBUS,
.handler = wcd9335_slimbus_irq,
@@ -4779,8 +4728,6 @@ static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = {
static void wcd9335_enable_sido_buck(struct snd_soc_component *component)
{
- struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
-
snd_soc_component_update_bits(component, WCD9335_ANA_RCO,
WCD9335_ANA_RCO_BG_EN_MASK,
WCD9335_ANA_RCO_BG_ENABLE);
@@ -4794,7 +4741,6 @@ static void wcd9335_enable_sido_buck(struct snd_soc_component *component)
WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT);
/* 100us sleep needed after VREF settings */
usleep_range(100, 110);
- wcd->sido_input_src = SIDO_SOURCE_RCO_BG;
}
static int wcd9335_enable_efuse_sensing(struct snd_soc_component *comp)
@@ -4925,7 +4871,6 @@ static int wcd9335_probe(struct wcd9335_codec *wcd)
memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs));
memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs));
- wcd->sido_input_src = SIDO_SOURCE_INTERNAL;
wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV;
return devm_snd_soc_register_component(dev, &wcd9335_component_drv,
@@ -4965,10 +4910,10 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config wcd9335_regmap_config = {
+static const struct regmap_config wcd9335_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = WCD9335_MAX_REGISTER,
.can_multi_write = true,
.ranges = wcd9335_ranges,
@@ -4989,7 +4934,7 @@ static const struct regmap_range_cfg wcd9335_ifc_ranges[] = {
},
};
-static struct regmap_config wcd9335_ifc_regmap_config = {
+static const struct regmap_config wcd9335_ifc_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.can_multi_write = true,
@@ -5032,53 +4977,30 @@ static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
static int wcd9335_parse_dt(struct wcd9335_codec *wcd)
{
struct device *dev = wcd->dev;
- struct device_node *np = dev->of_node;
int ret;
- wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
- if (wcd->reset_gpio < 0) {
- dev_err(dev, "Reset GPIO missing from DT\n");
- return wcd->reset_gpio;
- }
+ wcd->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd->reset_gpio), "Reset GPIO missing from DT\n");
wcd->mclk = devm_clk_get(dev, "mclk");
- if (IS_ERR(wcd->mclk)) {
- dev_err(dev, "mclk not found\n");
- return PTR_ERR(wcd->mclk);
- }
+ if (IS_ERR(wcd->mclk))
+ return dev_err_probe(dev, PTR_ERR(wcd->mclk), "mclk not found\n");
wcd->native_clk = devm_clk_get(dev, "slimbus");
- if (IS_ERR(wcd->native_clk)) {
- dev_err(dev, "slimbus clock not found\n");
- return PTR_ERR(wcd->native_clk);
- }
+ if (IS_ERR(wcd->native_clk))
+ return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n");
- wcd->supplies[0].supply = "vdd-buck";
- wcd->supplies[1].supply = "vdd-buck-sido";
- wcd->supplies[2].supply = "vdd-tx";
- wcd->supplies[3].supply = "vdd-rx";
- wcd->supplies[4].supply = "vdd-io";
-
- ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies);
- if (ret) {
- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
- return ret;
- }
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd9335_supplies),
+ wcd9335_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
return 0;
}
static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
{
- struct device *dev = wcd->dev;
- int ret;
-
- ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies);
- if (ret) {
- dev_err(dev, "Failed to get supplies: err = %d\n", ret);
- return ret;
- }
-
/*
* For WCD9335, it takes about 600us for the Vout_A and
* Vout_D to be ready after BUCK_SIDO is powered up.
@@ -5088,9 +5010,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
*/
usleep_range(600, 650);
- gpio_direction_output(wcd->reset_gpio, 0);
+ gpiod_set_value(wcd->reset_gpio, 1);
msleep(20);
- gpio_set_value(wcd->reset_gpio, 1);
+ gpiod_set_value(wcd->reset_gpio, 0);
msleep(20);
return 0;
@@ -5111,7 +5033,6 @@ static int wcd9335_bring_up(struct wcd9335_codec *wcd)
if (byte0 == 0x1) {
dev_info(wcd->dev, "WCD9335 CODEC version is v2.0\n");
- wcd->version = WCD9335_VERSION_2_0;
regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01);
regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00);
regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
@@ -5163,10 +5084,8 @@ static int wcd9335_slim_probe(struct slim_device *slim)
wcd->dev = dev;
ret = wcd9335_parse_dt(wcd);
- if (ret) {
- dev_err(dev, "Error parsing DT: %d\n", ret);
+ if (ret)
return ret;
- }
ret = wcd9335_power_on_reset(wcd);
if (ret)
@@ -5247,4 +5166,3 @@ static struct slim_driver wcd9335_slim_driver = {
module_slim_driver(wcd9335_slim_driver);
MODULE_DESCRIPTION("WCD9335 slim driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("slim:217:1a0:*");
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index c0d1fa36d841..c8db33f78a1b 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019, Linaro Limited
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/interrupt.h>
@@ -13,7 +14,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/slimbus.h>
#include <sound/pcm_params.h>
@@ -21,8 +21,11 @@
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "wcd-clsh-v2.h"
+#include "wcd-common.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)
@@ -114,9 +117,6 @@
#define WCD934X_DEC_PWR_LVL_DF 0x00
#define WCD934X_DEC_PWR_LVL_HYBRID WCD934X_DEC_PWR_LVL_DF
-#define WCD934X_DEF_MICBIAS_MV 1800
-#define WCD934X_MAX_MICBIAS_MV 2850
-
#define WCD_IIR_FILTER_SIZE (sizeof(u32) * BAND_MAX)
#define WCD_IIR_FILTER_CTL(xname, iidx, bidx) \
@@ -307,6 +307,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 +436,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,
@@ -476,17 +464,12 @@ enum {
INTn_2_INP_SEL_PROXIMITY,
};
-enum {
- INTERP_MAIN_PATH,
- INTERP_MIX_PATH,
-};
-
struct interp_sample_rate {
int sample_rate;
int rate_val;
};
-static struct interp_sample_rate sr_val_tbl[] = {
+static const struct interp_sample_rate sr_val_tbl[] = {
{8000, 0x0},
{16000, 0x1},
{32000, 0x3},
@@ -528,7 +511,7 @@ static const struct regmap_range_cfg wcd934x_ifc_ranges[] = {
},
};
-static struct regmap_config wcd934x_ifc_regmap_config = {
+static const struct regmap_config wcd934x_ifc_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.max_register = 0xffff,
@@ -545,6 +528,7 @@ struct wcd934x_codec {
struct slim_device *sdev;
struct slim_device *sidev;
struct wcd_clsh_ctrl *clsh_ctrl;
+ struct wcd_common common;
struct snd_soc_component *component;
struct wcd934x_slim_ch rx_chs[WCD934X_RX_MAX];
struct wcd934x_slim_ch tx_chs[WCD934X_TX_MAX];
@@ -552,8 +536,6 @@ struct wcd934x_codec {
int rate;
u32 version;
u32 hph_mode;
- int num_rx_port;
- int num_tx_port;
u32 tx_port_value[WCD934X_TX_MAX];
u32 rx_port_value[WCD934X_RX_MAX];
int sido_input_src;
@@ -572,10 +554,6 @@ struct wcd934x_codec {
struct mutex micb_lock;
u32 micb_ref[WCD934X_MAX_MICBIAS];
u32 pullup_ref[WCD934X_MAX_MICBIAS];
- u32 micb1_mv;
- u32 micb2_mv;
- u32 micb3_mv;
- u32 micb4_mv;
};
#define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw)
@@ -1218,7 +1196,7 @@ static const struct soc_enum cdc_if_tx13_mux_enum =
SOC_ENUM_SINGLE(WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0,
ARRAY_SIZE(cdc_if_tx13_mux_text), cdc_if_tx13_mux_text);
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD934X_ANA_MBHC_MECH, 0x80),
WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD934X_ANA_MBHC_MECH, 0x40),
WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD934X_ANA_MBHC_MECH, 0x20),
@@ -1924,8 +1902,10 @@ static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd,
}
static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct wcd934x_codec *wcd;
int i;
@@ -1944,13 +1924,11 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
return -EINVAL;
}
- wcd->num_rx_port = rx_num;
for (i = 0; i < rx_num; i++) {
wcd->rx_chs[i].ch_num = rx_slot[i];
INIT_LIST_HEAD(&wcd->rx_chs[i].list);
}
- wcd->num_tx_port = tx_num;
for (i = 0; i < tx_num; i++) {
wcd->tx_chs[i].ch_num = tx_slot[i];
INIT_LIST_HEAD(&wcd->tx_chs[i].list);
@@ -1959,7 +1937,7 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
return 0;
}
-static int wcd934x_get_channel_map(struct snd_soc_dai *dai,
+static int wcd934x_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)
{
@@ -2188,57 +2166,24 @@ static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd)
return NULL;
}
-static int wcd934x_get_micbias_val(struct device *dev, const char *micbias,
- u32 *micb_mv)
-{
- int mv;
-
- if (of_property_read_u32(dev->parent->of_node, micbias, &mv)) {
- dev_err(dev, "%s value not found, using default\n", micbias);
- mv = WCD934X_DEF_MICBIAS_MV;
- } else {
- /* convert it to milli volts */
- mv = mv/1000;
- }
-
- if (mv < 1000 || mv > 2850) {
- dev_err(dev, "%s value not in valid range, using default\n",
- micbias);
- mv = WCD934X_DEF_MICBIAS_MV;
- }
-
- *micb_mv = mv;
-
- return (mv - 1000) / 50;
-}
-
static int wcd934x_init_dmic(struct snd_soc_component *comp)
{
- int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
u32 def_dmic_rate, dmic_clk_drv;
+ int ret;
- vout_ctl_1 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias1-microvolt",
- &wcd->micb1_mv);
- vout_ctl_2 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias2-microvolt",
- &wcd->micb2_mv);
- vout_ctl_3 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias3-microvolt",
- &wcd->micb3_mv);
- vout_ctl_4 = wcd934x_get_micbias_val(comp->dev,
- "qcom,micbias4-microvolt",
- &wcd->micb4_mv);
+ ret = wcd_dt_parse_mbhc_data(comp->dev, &wcd->mbhc_cfg);
+ if (ret)
+ return ret;
snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1,
- WCD934X_MICB_VAL_MASK, vout_ctl_1);
+ WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[0]);
snd_soc_component_update_bits(comp, WCD934X_ANA_MICB2,
- WCD934X_MICB_VAL_MASK, vout_ctl_2);
+ WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[1]);
snd_soc_component_update_bits(comp, WCD934X_ANA_MICB3,
- WCD934X_MICB_VAL_MASK, vout_ctl_3);
+ WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[2]);
snd_soc_component_update_bits(comp, WCD934X_ANA_MICB4,
- WCD934X_MICB_VAL_MASK, vout_ctl_4);
+ WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[3]);
if (wcd->rate == WCD934X_MCLK_CLK_9P6MHZ)
def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
@@ -2281,7 +2226,7 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data)
{
struct wcd934x_codec *wcd = data;
unsigned long status = 0;
- int i, j, port_id;
+ unsigned int i, j, port_id;
unsigned int val, int_val = 0;
irqreturn_t ret = IRQ_NONE;
bool tx;
@@ -2539,15 +2484,6 @@ static void wcd934x_mbhc_micb_ramp_control(struct snd_soc_component *component,
}
}
-static int wcd934x_get_micb_vout_ctl_val(u32 micb_mv)
-{
- /* min micbias voltage is 1V and maximum is 2.85V */
- if (micb_mv < 1000 || micb_mv > 2850)
- return -EINVAL;
-
- return (micb_mv - 1000) / 50;
-}
-
static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
@@ -2584,7 +2520,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
WCD934X_MICB_VAL_MASK);
- req_vout_ctl = wcd934x_get_micb_vout_ctl_val(req_volt);
+ req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
if (req_vout_ctl < 0) {
ret = -EINVAL;
goto exit;
@@ -2632,17 +2568,17 @@ static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon
* voltage needed to detect threshold microphone, then do
* not change the micbias, just return.
*/
- if (wcd934x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+ if (wcd934x->common.micb_mv[1] >= WCD_MBHC_THR_HS_MICB_MV)
return 0;
- micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd934x->micb2_mv;
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd934x->common.micb_mv[1];
rc = wcd934x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
return rc;
}
-static inline void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x,
+static void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x,
s16 *d1_a, u16 noff,
int32_t *zdet)
{
@@ -2651,8 +2587,8 @@ static inline void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x,
s16 c1;
s32 x1, d1;
int32_t denom;
- int minCode_param[] = {
- 3277, 1639, 820, 410, 205, 103, 52, 26
+ static const int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
};
regmap_update_bits(wcd934x->regmap, WCD934X_ANA_MBHC_ZDET, 0x20, 0x20);
@@ -2683,7 +2619,7 @@ static inline void wcd934x_mbhc_get_result_params(struct wcd934x_codec *wcd934x,
else if (x1 < minCode_param[noff])
*zdet = WCD934X_ZDET_FLOATING_IMPEDANCE;
- dev_info(wcd934x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+ dev_dbg(wcd934x->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%di (milliohm)\n",
__func__, d1, c1, x1, *zdet);
ramp_down:
i = 0;
@@ -2740,8 +2676,8 @@ z_right:
*zr = zdet;
}
-static inline void wcd934x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
- int32_t *z_val, int flag_l_r)
+static void wcd934x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+ int32_t *z_val, int flag_l_r)
{
s16 q1;
int q1_cal;
@@ -2973,7 +2909,7 @@ static const struct wcd_mbhc_cb mbhc_cb = {
static int wcd934x_get_hph_type(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd->mbhc);
@@ -2987,7 +2923,7 @@ static int wcd934x_hph_impedance_get(struct snd_kcontrol *kcontrol,
uint32_t zl, zr;
bool hphr;
struct soc_mixer_control *mc;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component);
mc = (struct soc_mixer_control *)(kcontrol->private_value);
@@ -3044,10 +2980,21 @@ static int wcd934x_mbhc_init(struct snd_soc_component *component)
return 0;
}
+
+static void wcd934x_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(component);
+
+ if (!wcd->mbhc)
+ return;
+
+ wcd_mbhc_deinit(wcd->mbhc);
+}
+
static int wcd934x_comp_probe(struct snd_soc_component *component)
{
struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
- int i;
+ int i, ret;
snd_soc_component_init_regmap(component, wcd->regmap);
wcd->component = component;
@@ -3065,7 +3012,12 @@ static int wcd934x_comp_probe(struct snd_soc_component *component)
for (i = 0; i < NUM_CODEC_DAIS; i++)
INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list);
- wcd934x_init_dmic(component);
+
+ ret = wcd934x_init_dmic(component);
+ if (ret) {
+ dev_err(component->dev, "Failed to Initialize micbias\n");
+ return ret;
+ }
if (wcd934x_mbhc_init(component))
dev_err(component->dev, "Failed to Initialize MBHC\n");
@@ -3077,6 +3029,7 @@ static void wcd934x_comp_remove(struct snd_soc_component *comp)
{
struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+ wcd934x_mbhc_deinit(comp);
wcd_clsh_ctrl_free(wcd->clsh_ctrl);
}
@@ -3149,8 +3102,7 @@ static int wcd934x_put_iir_band_audio_mixer(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd_iir_filter_ctl *ctl =
(struct wcd_iir_filter_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -3178,8 +3130,7 @@ static int wcd934x_put_iir_band_audio_mixer(
static int wcd934x_get_iir_band_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd_iir_filter_ctl *ctl =
(struct wcd_iir_filter_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
@@ -3214,7 +3165,7 @@ static int wcd934x_iir_filter_info(struct snd_kcontrol *kcontrol,
static int wcd934x_compander_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
int comp = ((struct soc_mixer_control *)kc->private_value)->shift;
struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
@@ -3226,7 +3177,7 @@ static int wcd934x_compander_get(struct snd_kcontrol *kc,
static int wcd934x_compander_set(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
int comp = ((struct soc_mixer_control *)kc->private_value)->shift;
int value = ucontrol->value.integer.value[0];
@@ -3267,7 +3218,7 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
static int wcd934x_rx_hph_mode_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
ucontrol->value.enumerated.item[0] = wcd->hph_mode;
@@ -3278,7 +3229,7 @@ static int wcd934x_rx_hph_mode_get(struct snd_kcontrol *kc,
static int wcd934x_rx_hph_mode_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *component = snd_kcontrol_chip(kc);
struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
u32 mode_val;
@@ -3299,9 +3250,10 @@ static int wcd934x_rx_hph_mode_put(struct snd_kcontrol *kc,
static int slim_rx_mux_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
- struct wcd934x_codec *wcd = dev_get_drvdata(dapm->dev);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc);
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_to_widget(kc);
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(dev);
ucontrol->value.enumerated.item[0] = wcd->rx_port_value[w->shift];
@@ -3336,8 +3288,9 @@ static int slim_rx_mux_to_dai_id(int mux)
static int slim_rx_mux_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
- struct wcd934x_codec *wcd = dev_get_drvdata(w->dapm->dev);
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_to_widget(kc);
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(dev);
struct soc_enum *e = (struct soc_enum *)kc->private_value;
struct snd_soc_dapm_update *update = NULL;
struct wcd934x_slim_ch *ch, *c;
@@ -3404,7 +3357,7 @@ static int wcd934x_int_dem_inp_mux_put(struct snd_kcontrol *kc,
struct snd_soc_component *component;
int reg, val;
- component = snd_soc_dapm_kcontrol_component(kc);
+ component = snd_soc_dapm_kcontrol_to_component(kc);
val = ucontrol->value.enumerated.item[0];
if (e->reg == WCD934X_CDC_RX0_RX_PATH_SEC0)
reg = WCD934X_CDC_RX0_RX_PATH_CFG0;
@@ -3437,7 +3390,7 @@ static int wcd934x_dec_enum_put(struct snd_kcontrol *kcontrol,
u16 mic_sel_reg = 0;
u8 mic_sel;
- comp = snd_soc_dapm_kcontrol_component(kcontrol);
+ comp = snd_soc_dapm_kcontrol_to_component(kcontrol);
val = ucontrol->value.enumerated.item[0];
if (val > e->items - 1)
@@ -3816,8 +3769,9 @@ static const struct snd_kcontrol_new cdc_if_tx13_inp1_mux =
static int slim_tx_mixer_get(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
- struct wcd934x_codec *wcd = dev_get_drvdata(dapm->dev);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc);
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(dev);
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kc->private_value;
int port_id = mixer->shift;
@@ -3830,8 +3784,9 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc,
static int slim_tx_mixer_put(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
- struct wcd934x_codec *wcd = dev_get_drvdata(widget->dapm->dev);
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_to_widget(kc);
+ struct device *dev = snd_soc_dapm_to_dev(widget->dapm);
+ struct wcd934x_codec *wcd = dev_get_drvdata(dev);
struct snd_soc_dapm_update *update = NULL;
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kc->private_value;
@@ -4970,25 +4925,23 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
unsigned int decimator;
char *dec_adc_mux_name = NULL;
- char *widget_name = NULL;
- char *wname;
+ char *widget_name;
int ret = 0, amic_n;
u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
u16 tx_gain_ctl_reg;
char *dec;
u8 hpf_coff_freq;
- widget_name = kstrndup(w->name, 15, GFP_KERNEL);
- if (!widget_name)
+ char *wname __free(kfree) = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!wname)
return -ENOMEM;
- wname = widget_name;
+ widget_name = wname;
dec_adc_mux_name = strsep(&widget_name, " ");
if (!dec_adc_mux_name) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, w->name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
dec_adc_mux_name = widget_name;
@@ -4996,16 +4949,14 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
if (!dec) {
dev_err(comp->dev, "%s: decimator index not found\n",
__func__);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ret = kstrtouint(dec, 10, &decimator);
if (ret < 0) {
dev_err(comp->dev, "%s: Invalid decimator = %s\n",
__func__, wname);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator;
@@ -5098,8 +5049,7 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w,
WCD934X_DEC_PWR_LVL_DF);
break;
}
-out:
- kfree(wname);
+
return ret;
}
@@ -5846,6 +5796,13 @@ static const struct snd_soc_component_driver wcd934x_component_drv = {
.endianness = 1,
};
+static void wcd934x_put_device_action(void *data)
+{
+ struct device *dev = data;
+
+ put_device(dev);
+}
+
static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
{
struct device *dev = &wcd->sdev->dev;
@@ -5853,24 +5810,22 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
struct device_node *ifc_dev_np;
ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0);
- if (!ifc_dev_np) {
- dev_err(dev, "No Interface device found\n");
- return -EINVAL;
- }
+ if (!ifc_dev_np)
+ return dev_err_probe(dev, -EINVAL, "No Interface device found\n");
wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np);
of_node_put(ifc_dev_np);
- if (!wcd->sidev) {
- dev_err(dev, "Unable to get SLIM Interface device\n");
- return -EINVAL;
- }
+ if (!wcd->sidev)
+ return dev_err_probe(dev, -EINVAL, "Unable to get SLIM Interface device\n");
slim_get_logical_addr(wcd->sidev);
- wcd->if_regmap = regmap_init_slimbus(wcd->sidev,
+ wcd->if_regmap = devm_regmap_init_slimbus(wcd->sidev,
&wcd934x_ifc_regmap_config);
- if (IS_ERR(wcd->if_regmap))
+ if (IS_ERR(wcd->if_regmap)) {
+ put_device(&wcd->sidev->dev);
return dev_err_probe(dev, PTR_ERR(wcd->if_regmap),
"Failed to allocate ifc register map\n");
+ }
of_property_read_u32(dev->parent->of_node, "qcom,dmic-sample-rate",
&wcd->dmic_sample_rate);
@@ -5879,14 +5834,13 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
cfg->anc_micbias = MIC_BIAS_2;
cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
cfg->num_btn = WCD934X_MBHC_MAX_BUTTONS;
- cfg->micb_mv = wcd->micb2_mv;
+ cfg->micb_mv = wcd->common.micb_mv[1];
cfg->linein_th = 5000;
cfg->hs_thr = 1700;
cfg->hph_thr = 50;
wcd_dt_parse_mbhc_data(dev, cfg);
-
return 0;
}
@@ -5907,12 +5861,16 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
wcd->sdev = to_slim_device(data->dev);
mutex_init(&wcd->sysclk_mutex);
mutex_init(&wcd->micb_lock);
+ wcd->common.dev = dev->parent;
+ wcd->common.max_bias = 4;
ret = wcd934x_codec_parse_data(wcd);
- if (ret) {
- dev_err(wcd->dev, "Failed to get SLIM IRQ\n");
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, wcd934x_put_device_action, &wcd->sidev->dev);
+ if (ret)
return ret;
- }
/* set default rate 9P6MHz */
regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
@@ -5956,7 +5914,6 @@ static struct platform_driver wcd934x_codec_driver = {
}
};
-MODULE_ALIAS("platform:wcd934x-codec");
module_platform_driver(wcd934x_codec_driver);
MODULE_DESCRIPTION("WCD934x codec driver");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
new file mode 100644
index 000000000000..1878d67e3fa1
--- /dev/null
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -0,0 +1,1115 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include "wcd937x.h"
+
+static struct wcd_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)),
+ WCD_SDW_CH(WCD937X_COMP_L, WCD937X_COMP_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_COMP_R, WCD937X_COMP_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_LO, WCD937X_LO_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DSD_L, WCD937X_DSD_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)),
+};
+
+static struct wcd_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)),
+ WCD_SDW_CH(WCD937X_DMIC0, WCD937X_DMIC_0_3_MBHC_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DMIC1, WCD937X_DMIC_0_3_MBHC_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_MBHC, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)),
+ WCD_SDW_CH(WCD937X_DMIC2, WCD937X_DMIC_0_3_MBHC_PORT, BIT(2)),
+ WCD_SDW_CH(WCD937X_DMIC3, WCD937X_DMIC_0_3_MBHC_PORT, BIT(3)),
+ WCD_SDW_CH(WCD937X_DMIC4, WCD937X_DMIC_4_6_PORT, BIT(0)),
+ WCD_SDW_CH(WCD937X_DMIC5, WCD937X_DMIC_4_6_PORT, BIT(1)),
+ WCD_SDW_CH(WCD937X_DMIC6, WCD937X_DMIC_4_6_PORT, BIT(2)),
+};
+
+static struct sdw_dpn_prop wcd937x_dpn_prop[WCD937X_MAX_SWR_PORTS] = {
+ {
+ .num = 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 8,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 2,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 3,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 4,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }, {
+ .num = 5,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }
+};
+
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
+ unsigned long ch_mask;
+ int i, j;
+
+ wcd->sconfig.ch_count = 1;
+ wcd->active_ports = 0;
+ for (i = 0; i < WCD937X_MAX_SWR_PORTS; i++) {
+ ch_mask = wcd->port_config[i].ch_mask;
+ if (!ch_mask)
+ continue;
+
+ for_each_set_bit(j, &ch_mask, 4)
+ wcd->sconfig.ch_count++;
+
+ port_config[wcd->active_ports] = wcd->port_config[i];
+ wcd->active_ports++;
+ }
+
+ wcd->sconfig.bps = 1;
+ wcd->sconfig.frame_rate = params_rate(params);
+ wcd->sconfig.direction = wcd->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX;
+ wcd->sconfig.type = SDW_STREAM_PCM;
+
+ return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig,
+ &port_config[0], wcd->active_ports,
+ wcd->sruntime);
+}
+EXPORT_SYMBOL_GPL(wcd937x_sdw_hw_params);
+
+/*
+ * Handle Soundwire out-of-band interrupt event by triggering
+ * the first irq of the slave_irq irq domain, which then will
+ * be handled by the regmap_irq threaded irq.
+ * Looping is to ensure no interrupts were missed in the process.
+ */
+static int wcd9370_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+
+ return wcd_interrupt_callback(slave, wcd->slave_irq, WCD937X_DIGITAL_INTR_STATUS_0,
+ WCD937X_DIGITAL_INTR_STATUS_1, WCD937X_DIGITAL_INTR_STATUS_2);
+}
+
+static const struct reg_default wcd937x_defaults[] = {
+ /* Default values except for Read-Only & Volatile registers */
+ { WCD937X_ANA_BIAS, 0x00 },
+ { WCD937X_ANA_RX_SUPPLIES, 0x00 },
+ { WCD937X_ANA_HPH, 0x0c },
+ { WCD937X_ANA_EAR, 0x00 },
+ { WCD937X_ANA_EAR_COMPANDER_CTL, 0x02 },
+ { WCD937X_ANA_TX_CH1, 0x20 },
+ { WCD937X_ANA_TX_CH2, 0x00 },
+ { WCD937X_ANA_TX_CH3, 0x20 },
+ { WCD937X_ANA_TX_CH3_HPF, 0x00 },
+ { WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00 },
+ { WCD937X_ANA_MICB3_DSP_EN_LOGIC, 0x00 },
+ { WCD937X_ANA_MBHC_MECH, 0x39 },
+ { WCD937X_ANA_MBHC_ELECT, 0x08 },
+ { WCD937X_ANA_MBHC_ZDET, 0x00 },
+ { WCD937X_ANA_MBHC_BTN0, 0x00 },
+ { WCD937X_ANA_MBHC_BTN1, 0x10 },
+ { WCD937X_ANA_MBHC_BTN2, 0x20 },
+ { WCD937X_ANA_MBHC_BTN3, 0x30 },
+ { WCD937X_ANA_MBHC_BTN4, 0x40 },
+ { WCD937X_ANA_MBHC_BTN5, 0x50 },
+ { WCD937X_ANA_MBHC_BTN6, 0x60 },
+ { WCD937X_ANA_MBHC_BTN7, 0x70 },
+ { WCD937X_ANA_MICB1, 0x10 },
+ { WCD937X_ANA_MICB2, 0x10 },
+ { WCD937X_ANA_MICB2_RAMP, 0x00 },
+ { WCD937X_ANA_MICB3, 0x10 },
+ { WCD937X_BIAS_CTL, 0x2a },
+ { WCD937X_BIAS_VBG_FINE_ADJ, 0x55 },
+ { WCD937X_LDOL_VDDCX_ADJUST, 0x01 },
+ { WCD937X_LDOL_DISABLE_LDOL, 0x00 },
+ { WCD937X_MBHC_CTL_CLK, 0x00 },
+ { WCD937X_MBHC_CTL_ANA, 0x00 },
+ { WCD937X_MBHC_CTL_SPARE_1, 0x00 },
+ { WCD937X_MBHC_CTL_SPARE_2, 0x00 },
+ { WCD937X_MBHC_CTL_BCS, 0x00 },
+ { WCD937X_MBHC_TEST_CTL, 0x00 },
+ { WCD937X_LDOH_MODE, 0x2b },
+ { WCD937X_LDOH_BIAS, 0x68 },
+ { WCD937X_LDOH_STB_LOADS, 0x00 },
+ { WCD937X_LDOH_SLOWRAMP, 0x50 },
+ { WCD937X_MICB1_TEST_CTL_1, 0x1a },
+ { WCD937X_MICB1_TEST_CTL_2, 0x18 },
+ { WCD937X_MICB1_TEST_CTL_3, 0xa4 },
+ { WCD937X_MICB2_TEST_CTL_1, 0x1a },
+ { WCD937X_MICB2_TEST_CTL_2, 0x18 },
+ { WCD937X_MICB2_TEST_CTL_3, 0xa4 },
+ { WCD937X_MICB3_TEST_CTL_1, 0x1a },
+ { WCD937X_MICB3_TEST_CTL_2, 0x18 },
+ { WCD937X_MICB3_TEST_CTL_3, 0xa4 },
+ { WCD937X_TX_COM_ADC_VCM, 0x39 },
+ { WCD937X_TX_COM_BIAS_ATEST, 0xc0 },
+ { WCD937X_TX_COM_ADC_INT1_IB, 0x6f },
+ { WCD937X_TX_COM_ADC_INT2_IB, 0x4f },
+ { WCD937X_TX_COM_TXFE_DIV_CTL, 0x2e },
+ { WCD937X_TX_COM_TXFE_DIV_START, 0x00 },
+ { WCD937X_TX_COM_TXFE_DIV_STOP_9P6M, 0xc7 },
+ { WCD937X_TX_COM_TXFE_DIV_STOP_12P288M, 0xff },
+ { WCD937X_TX_1_2_TEST_EN, 0xcc },
+ { WCD937X_TX_1_2_ADC_IB, 0x09 },
+ { WCD937X_TX_1_2_ATEST_REFCTL, 0x0a },
+ { WCD937X_TX_1_2_TEST_CTL, 0x38 },
+ { WCD937X_TX_1_2_TEST_BLK_EN, 0xff },
+ { WCD937X_TX_1_2_TXFE_CLKDIV, 0x00 },
+ { WCD937X_TX_3_TEST_EN, 0xcc },
+ { WCD937X_TX_3_ADC_IB, 0x09 },
+ { WCD937X_TX_3_ATEST_REFCTL, 0x0a },
+ { WCD937X_TX_3_TEST_CTL, 0x38 },
+ { WCD937X_TX_3_TEST_BLK_EN, 0xff },
+ { WCD937X_TX_3_TXFE_CLKDIV, 0x00 },
+ { WCD937X_TX_3_SPARE_MONO, 0x00 },
+ { WCD937X_CLASSH_MODE_1, 0x40 },
+ { WCD937X_CLASSH_MODE_2, 0x3a },
+ { WCD937X_CLASSH_MODE_3, 0x00 },
+ { WCD937X_CLASSH_CTRL_VCL_1, 0x70 },
+ { WCD937X_CLASSH_CTRL_VCL_2, 0x82 },
+ { WCD937X_CLASSH_CTRL_CCL_1, 0x31 },
+ { WCD937X_CLASSH_CTRL_CCL_2, 0x80 },
+ { WCD937X_CLASSH_CTRL_CCL_3, 0x80 },
+ { WCD937X_CLASSH_CTRL_CCL_4, 0x51 },
+ { WCD937X_CLASSH_CTRL_CCL_5, 0x00 },
+ { WCD937X_CLASSH_BUCK_TMUX_A_D, 0x00 },
+ { WCD937X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 },
+ { WCD937X_CLASSH_SPARE, 0x00 },
+ { WCD937X_FLYBACK_EN, 0x4e },
+ { WCD937X_FLYBACK_VNEG_CTRL_1, 0x0b },
+ { WCD937X_FLYBACK_VNEG_CTRL_2, 0x45 },
+ { WCD937X_FLYBACK_VNEG_CTRL_3, 0x74 },
+ { WCD937X_FLYBACK_VNEG_CTRL_4, 0x7f },
+ { WCD937X_FLYBACK_VNEG_CTRL_5, 0x83 },
+ { WCD937X_FLYBACK_VNEG_CTRL_6, 0x98 },
+ { WCD937X_FLYBACK_VNEG_CTRL_7, 0xa9 },
+ { WCD937X_FLYBACK_VNEG_CTRL_8, 0x68 },
+ { WCD937X_FLYBACK_VNEG_CTRL_9, 0x64 },
+ { WCD937X_FLYBACK_VNEGDAC_CTRL_1, 0xed },
+ { WCD937X_FLYBACK_VNEGDAC_CTRL_2, 0xf0 },
+ { WCD937X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 },
+ { WCD937X_FLYBACK_CTRL_1, 0x65 },
+ { WCD937X_FLYBACK_TEST_CTL, 0x00 },
+ { WCD937X_RX_AUX_SW_CTL, 0x00 },
+ { WCD937X_RX_PA_AUX_IN_CONN, 0x00 },
+ { WCD937X_RX_TIMER_DIV, 0x32 },
+ { WCD937X_RX_OCP_CTL, 0x1f },
+ { WCD937X_RX_OCP_COUNT, 0x77 },
+ { WCD937X_RX_BIAS_EAR_DAC, 0xa0 },
+ { WCD937X_RX_BIAS_EAR_AMP, 0xaa },
+ { WCD937X_RX_BIAS_HPH_LDO, 0xa9 },
+ { WCD937X_RX_BIAS_HPH_PA, 0xaa },
+ { WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a },
+ { WCD937X_RX_BIAS_HPH_RDAC_LDO, 0x88 },
+ { WCD937X_RX_BIAS_HPH_CNP1, 0x82 },
+ { WCD937X_RX_BIAS_HPH_LOWPOWER, 0x82 },
+ { WCD937X_RX_BIAS_AUX_DAC, 0xa0 },
+ { WCD937X_RX_BIAS_AUX_AMP, 0xaa },
+ { WCD937X_RX_BIAS_VNEGDAC_BLEEDER, 0x50 },
+ { WCD937X_RX_BIAS_MISC, 0x00 },
+ { WCD937X_RX_BIAS_BUCK_RST, 0x08 },
+ { WCD937X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 },
+ { WCD937X_RX_BIAS_FLYB_ERRAMP, 0x40 },
+ { WCD937X_RX_BIAS_FLYB_BUFF, 0xaa },
+ { WCD937X_RX_BIAS_FLYB_MID_RST, 0x14 },
+ { WCD937X_HPH_CNP_EN, 0x80 },
+ { WCD937X_HPH_CNP_WG_CTL, 0x9a },
+ { WCD937X_HPH_CNP_WG_TIME, 0x14 },
+ { WCD937X_HPH_OCP_CTL, 0x28 },
+ { WCD937X_HPH_AUTO_CHOP, 0x16 },
+ { WCD937X_HPH_CHOP_CTL, 0x83 },
+ { WCD937X_HPH_PA_CTL1, 0x46 },
+ { WCD937X_HPH_PA_CTL2, 0x50 },
+ { WCD937X_HPH_L_EN, 0x80 },
+ { WCD937X_HPH_L_TEST, 0xe0 },
+ { WCD937X_HPH_L_ATEST, 0x50 },
+ { WCD937X_HPH_R_EN, 0x80 },
+ { WCD937X_HPH_R_TEST, 0xe0 },
+ { WCD937X_HPH_R_ATEST, 0x54 },
+ { WCD937X_HPH_RDAC_CLK_CTL1, 0x99 },
+ { WCD937X_HPH_RDAC_CLK_CTL2, 0x9b },
+ { WCD937X_HPH_RDAC_LDO_CTL, 0x33 },
+ { WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 },
+ { WCD937X_HPH_REFBUFF_UHQA_CTL, 0xa8 },
+ { WCD937X_HPH_REFBUFF_LP_CTL, 0x0e },
+ { WCD937X_HPH_L_DAC_CTL, 0x20 },
+ { WCD937X_HPH_R_DAC_CTL, 0x20 },
+ { WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55 },
+ { WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0x19 },
+ { WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xa0 },
+ { WCD937X_EAR_EAR_EN_REG, 0x22 },
+ { WCD937X_EAR_EAR_PA_CON, 0x44 },
+ { WCD937X_EAR_EAR_SP_CON, 0xdb },
+ { WCD937X_EAR_EAR_DAC_CON, 0x80 },
+ { WCD937X_EAR_EAR_CNP_FSM_CON, 0xb2 },
+ { WCD937X_EAR_TEST_CTL, 0x00 },
+ { WCD937X_ANA_NEW_PAGE_REGISTER, 0x00 },
+ { WCD937X_HPH_NEW_ANA_HPH2, 0x00 },
+ { WCD937X_HPH_NEW_ANA_HPH3, 0x00 },
+ { WCD937X_SLEEP_CTL, 0x16 },
+ { WCD937X_SLEEP_WATCHDOG_CTL, 0x00 },
+ { WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 },
+ { WCD937X_MBHC_NEW_CTL_1, 0x02 },
+ { WCD937X_MBHC_NEW_CTL_2, 0x05 },
+ { WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 },
+ { WCD937X_MBHC_NEW_ZDET_ANA_CTL, 0x0f },
+ { WCD937X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 },
+ { WCD937X_TX_NEW_TX_CH2_SEL, 0x00 },
+ { WCD937X_AUX_AUXPA, 0x00 },
+ { WCD937X_LDORXTX_MODE, 0x0c },
+ { WCD937X_LDORXTX_CONFIG, 0x10 },
+ { WCD937X_DIE_CRACK_DIE_CRK_DET_EN, 0x00 },
+ { WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40 },
+ { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81 },
+ { WCD937X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 },
+ { WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+ { WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81 },
+ { WCD937X_HPH_NEW_INT_PA_MISC1, 0x22 },
+ { WCD937X_HPH_NEW_INT_PA_MISC2, 0x00 },
+ { WCD937X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER1, 0xfe },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER2, 0x02 },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER3, 0x4e },
+ { WCD937X_HPH_NEW_INT_HPH_TIMER4, 0x54 },
+ { WCD937X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 },
+ { WCD937X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
+ { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 },
+ { WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 },
+ { WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 },
+ { WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 },
+ { WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 },
+ { WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00 },
+ { WCD937X_MBHC_NEW_INT_SPARE_2, 0x00 },
+ { WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xa8 },
+ { WCD937X_EAR_INT_NEW_CNP_VCM_CON1, 0x42 },
+ { WCD937X_EAR_INT_NEW_CNP_VCM_CON2, 0x22 },
+ { WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00 },
+ { WCD937X_AUX_INT_EN_REG, 0x00 },
+ { WCD937X_AUX_INT_PA_CTRL, 0x06 },
+ { WCD937X_AUX_INT_SP_CTRL, 0xd2 },
+ { WCD937X_AUX_INT_DAC_CTRL, 0x80 },
+ { WCD937X_AUX_INT_CLK_CTRL, 0x50 },
+ { WCD937X_AUX_INT_TEST_CTRL, 0x00 },
+ { WCD937X_AUX_INT_STATUS_REG, 0x00 },
+ { WCD937X_AUX_INT_MISC, 0x00 },
+ { WCD937X_LDORXTX_INT_BIAS, 0x6e },
+ { WCD937X_LDORXTX_INT_STB_LOADS_DTEST, 0x50 },
+ { WCD937X_LDORXTX_INT_TEST0, 0x1c },
+ { WCD937X_LDORXTX_INT_STARTUP_TIMER, 0xff },
+ { WCD937X_LDORXTX_INT_TEST1, 0x1f },
+ { WCD937X_LDORXTX_INT_STATUS, 0x00 },
+ { WCD937X_SLEEP_INT_WATCHDOG_CTL_1, 0x0a },
+ { WCD937X_SLEEP_INT_WATCHDOG_CTL_2, 0x0a },
+ { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02 },
+ { WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60 },
+ { WCD937X_DIGITAL_PAGE_REGISTER, 0x00 },
+ { WCD937X_DIGITAL_CDC_RST_CTL, 0x03 },
+ { WCD937X_DIGITAL_TOP_CLK_CFG, 0x00 },
+ { WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x00 },
+ { WCD937X_DIGITAL_SWR_RST_EN, 0x00 },
+ { WCD937X_DIGITAL_CDC_PATH_MODE, 0x55 },
+ { WCD937X_DIGITAL_CDC_RX_RST, 0x00 },
+ { WCD937X_DIGITAL_CDC_RX0_CTL, 0xfc },
+ { WCD937X_DIGITAL_CDC_RX1_CTL, 0xfc },
+ { WCD937X_DIGITAL_CDC_RX2_CTL, 0xfc },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA0, 0x55 },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA1, 0x55 },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA2, 0x55 },
+ { WCD937X_DIGITAL_DEM_BYPASS_DATA3, 0x01 },
+ { WCD937X_DIGITAL_CDC_COMP_CTL_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_RX_DELAY_CTL, 0x66 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A3_0, 0xac },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1a },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A5_0, 0xbc },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A6_0, 0xc7 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_A7_0, 0xf8 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_0, 0x47 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_1, 0x43 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_2, 0xb1 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_C_3, 0x17 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R1, 0x4b },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R2, 0x26 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R3, 0x32 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R4, 0x57 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R5, 0x63 },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R6, 0x7c },
+ { WCD937X_DIGITAL_CDC_HPH_DSM_R7, 0x57 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A3_0, 0xab },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1c },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A6_0, 0xaa },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_A7_0, 0xe3 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_0, 0x69 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_1, 0x54 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_2, 0x02 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_C_3, 0x15 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R1, 0xa4 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R2, 0xb5 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R3, 0x86 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R4, 0x85 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R5, 0xaa },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R6, 0xe2 },
+ { WCD937X_DIGITAL_CDC_AUX_DSM_R7, 0x62 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xa9 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3d },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2e },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01 },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00 },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xfc },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01 },
+ { WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_SWR_CLH, 0x00 },
+ { WCD937X_DIGITAL_SWR_CLH_BYP, 0x00 },
+ { WCD937X_DIGITAL_CDC_TX0_CTL, 0x68 },
+ { WCD937X_DIGITAL_CDC_TX1_CTL, 0x68 },
+ { WCD937X_DIGITAL_CDC_TX2_CTL, 0x68 },
+ { WCD937X_DIGITAL_CDC_TX_RST, 0x00 },
+ { WCD937X_DIGITAL_CDC_REQ_CTL, 0x01 },
+ { WCD937X_DIGITAL_CDC_AMIC_CTL, 0x07 },
+ { WCD937X_DIGITAL_CDC_DMIC_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_DMIC1_CTL, 0x01 },
+ { WCD937X_DIGITAL_CDC_DMIC2_CTL, 0x01 },
+ { WCD937X_DIGITAL_CDC_DMIC3_CTL, 0x01 },
+ { WCD937X_DIGITAL_EFUSE_CTL, 0x2b },
+ { WCD937X_DIGITAL_EFUSE_PRG_CTL, 0x00 },
+ { WCD937X_DIGITAL_EFUSE_TEST_CTL_0, 0x00 },
+ { WCD937X_DIGITAL_EFUSE_TEST_CTL_1, 0x00 },
+ { WCD937X_DIGITAL_PDM_WD_CTL0, 0x00 },
+ { WCD937X_DIGITAL_PDM_WD_CTL1, 0x00 },
+ { WCD937X_DIGITAL_PDM_WD_CTL2, 0x00 },
+ { WCD937X_DIGITAL_INTR_MODE, 0x00 },
+ { WCD937X_DIGITAL_INTR_MASK_0, 0xff },
+ { WCD937X_DIGITAL_INTR_MASK_1, 0xff },
+ { WCD937X_DIGITAL_INTR_MASK_2, 0x0f },
+ { WCD937X_DIGITAL_INTR_CLEAR_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_CLEAR_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_CLEAR_2, 0x00 },
+ { WCD937X_DIGITAL_INTR_LEVEL_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_LEVEL_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_LEVEL_2, 0x00 },
+ { WCD937X_DIGITAL_INTR_SET_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_SET_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_SET_2, 0x00 },
+ { WCD937X_DIGITAL_INTR_TEST_0, 0x00 },
+ { WCD937X_DIGITAL_INTR_TEST_1, 0x00 },
+ { WCD937X_DIGITAL_INTR_TEST_2, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_RX0_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_RX1_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_RX2_CTL, 0x00 },
+ { WCD937X_DIGITAL_CDC_CONN_TX_CTL, 0x00 },
+ { WCD937X_DIGITAL_LOOP_BACK_MODE, 0x00 },
+ { WCD937X_DIGITAL_SWR_DAC_TEST, 0x00 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_RX_0, 0x40 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_TX_0, 0x40 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_RX_1, 0x00 },
+ { WCD937X_DIGITAL_SWR_HM_TEST_TX_1, 0x00 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_RX0, 0xf1 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_RX1, 0xf1 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_TX0, 0xf1 },
+ { WCD937X_DIGITAL_PAD_CTL_PDM_TX1, 0xf1 },
+ { WCD937X_DIGITAL_PAD_INP_DIS_0, 0x00 },
+ { WCD937X_DIGITAL_PAD_INP_DIS_1, 0x00 },
+ { WCD937X_DIGITAL_DRIVE_STRENGTH_0, 0x00 },
+ { WCD937X_DIGITAL_DRIVE_STRENGTH_1, 0x00 },
+ { WCD937X_DIGITAL_DRIVE_STRENGTH_2, 0x00 },
+ { WCD937X_DIGITAL_RX_DATA_EDGE_CTL, 0x1f },
+ { WCD937X_DIGITAL_TX_DATA_EDGE_CTL, 0x10 },
+ { WCD937X_DIGITAL_GPIO_MODE, 0x00 },
+ { WCD937X_DIGITAL_PIN_CTL_OE, 0x00 },
+ { WCD937X_DIGITAL_PIN_CTL_DATA_0, 0x00 },
+ { WCD937X_DIGITAL_PIN_CTL_DATA_1, 0x00 },
+ { WCD937X_DIGITAL_DIG_DEBUG_CTL, 0x00 },
+ { WCD937X_DIGITAL_DIG_DEBUG_EN, 0x00 },
+ { WCD937X_DIGITAL_ANA_CSR_DBG_ADD, 0x00 },
+ { WCD937X_DIGITAL_ANA_CSR_DBG_CTL, 0x48 },
+ { WCD937X_DIGITAL_SSP_DBG, 0x00 },
+ { WCD937X_DIGITAL_SPARE_0, 0x00 },
+ { WCD937X_DIGITAL_SPARE_1, 0x00 },
+ { WCD937X_DIGITAL_SPARE_2, 0x00 },
+};
+
+static bool wcd937x_rdwr_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD937X_ANA_BIAS:
+ case WCD937X_ANA_RX_SUPPLIES:
+ case WCD937X_ANA_HPH:
+ case WCD937X_ANA_EAR:
+ case WCD937X_ANA_EAR_COMPANDER_CTL:
+ case WCD937X_ANA_TX_CH1:
+ case WCD937X_ANA_TX_CH2:
+ case WCD937X_ANA_TX_CH3:
+ case WCD937X_ANA_TX_CH3_HPF:
+ case WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC:
+ case WCD937X_ANA_MICB3_DSP_EN_LOGIC:
+ case WCD937X_ANA_MBHC_MECH:
+ case WCD937X_ANA_MBHC_ELECT:
+ case WCD937X_ANA_MBHC_ZDET:
+ case WCD937X_ANA_MBHC_BTN0:
+ case WCD937X_ANA_MBHC_BTN1:
+ case WCD937X_ANA_MBHC_BTN2:
+ case WCD937X_ANA_MBHC_BTN3:
+ case WCD937X_ANA_MBHC_BTN4:
+ case WCD937X_ANA_MBHC_BTN5:
+ case WCD937X_ANA_MBHC_BTN6:
+ case WCD937X_ANA_MBHC_BTN7:
+ case WCD937X_ANA_MICB1:
+ case WCD937X_ANA_MICB2:
+ case WCD937X_ANA_MICB2_RAMP:
+ case WCD937X_ANA_MICB3:
+ case WCD937X_BIAS_CTL:
+ case WCD937X_BIAS_VBG_FINE_ADJ:
+ case WCD937X_LDOL_VDDCX_ADJUST:
+ case WCD937X_LDOL_DISABLE_LDOL:
+ case WCD937X_MBHC_CTL_CLK:
+ case WCD937X_MBHC_CTL_ANA:
+ case WCD937X_MBHC_CTL_SPARE_1:
+ case WCD937X_MBHC_CTL_SPARE_2:
+ case WCD937X_MBHC_CTL_BCS:
+ case WCD937X_MBHC_TEST_CTL:
+ case WCD937X_LDOH_MODE:
+ case WCD937X_LDOH_BIAS:
+ case WCD937X_LDOH_STB_LOADS:
+ case WCD937X_LDOH_SLOWRAMP:
+ case WCD937X_MICB1_TEST_CTL_1:
+ case WCD937X_MICB1_TEST_CTL_2:
+ case WCD937X_MICB1_TEST_CTL_3:
+ case WCD937X_MICB2_TEST_CTL_1:
+ case WCD937X_MICB2_TEST_CTL_2:
+ case WCD937X_MICB2_TEST_CTL_3:
+ case WCD937X_MICB3_TEST_CTL_1:
+ case WCD937X_MICB3_TEST_CTL_2:
+ case WCD937X_MICB3_TEST_CTL_3:
+ case WCD937X_TX_COM_ADC_VCM:
+ case WCD937X_TX_COM_BIAS_ATEST:
+ case WCD937X_TX_COM_ADC_INT1_IB:
+ case WCD937X_TX_COM_ADC_INT2_IB:
+ case WCD937X_TX_COM_TXFE_DIV_CTL:
+ case WCD937X_TX_COM_TXFE_DIV_START:
+ case WCD937X_TX_COM_TXFE_DIV_STOP_9P6M:
+ case WCD937X_TX_COM_TXFE_DIV_STOP_12P288M:
+ case WCD937X_TX_1_2_TEST_EN:
+ case WCD937X_TX_1_2_ADC_IB:
+ case WCD937X_TX_1_2_ATEST_REFCTL:
+ case WCD937X_TX_1_2_TEST_CTL:
+ case WCD937X_TX_1_2_TEST_BLK_EN:
+ case WCD937X_TX_1_2_TXFE_CLKDIV:
+ case WCD937X_TX_3_TEST_EN:
+ case WCD937X_TX_3_ADC_IB:
+ case WCD937X_TX_3_ATEST_REFCTL:
+ case WCD937X_TX_3_TEST_CTL:
+ case WCD937X_TX_3_TEST_BLK_EN:
+ case WCD937X_TX_3_TXFE_CLKDIV:
+ case WCD937X_CLASSH_MODE_1:
+ case WCD937X_CLASSH_MODE_2:
+ case WCD937X_CLASSH_MODE_3:
+ case WCD937X_CLASSH_CTRL_VCL_1:
+ case WCD937X_CLASSH_CTRL_VCL_2:
+ case WCD937X_CLASSH_CTRL_CCL_1:
+ case WCD937X_CLASSH_CTRL_CCL_2:
+ case WCD937X_CLASSH_CTRL_CCL_3:
+ case WCD937X_CLASSH_CTRL_CCL_4:
+ case WCD937X_CLASSH_CTRL_CCL_5:
+ case WCD937X_CLASSH_BUCK_TMUX_A_D:
+ case WCD937X_CLASSH_BUCK_SW_DRV_CNTL:
+ case WCD937X_CLASSH_SPARE:
+ case WCD937X_FLYBACK_EN:
+ case WCD937X_FLYBACK_VNEG_CTRL_1:
+ case WCD937X_FLYBACK_VNEG_CTRL_2:
+ case WCD937X_FLYBACK_VNEG_CTRL_3:
+ case WCD937X_FLYBACK_VNEG_CTRL_4:
+ case WCD937X_FLYBACK_VNEG_CTRL_5:
+ case WCD937X_FLYBACK_VNEG_CTRL_6:
+ case WCD937X_FLYBACK_VNEG_CTRL_7:
+ case WCD937X_FLYBACK_VNEG_CTRL_8:
+ case WCD937X_FLYBACK_VNEG_CTRL_9:
+ case WCD937X_FLYBACK_VNEGDAC_CTRL_1:
+ case WCD937X_FLYBACK_VNEGDAC_CTRL_2:
+ case WCD937X_FLYBACK_VNEGDAC_CTRL_3:
+ case WCD937X_FLYBACK_CTRL_1:
+ case WCD937X_FLYBACK_TEST_CTL:
+ case WCD937X_RX_AUX_SW_CTL:
+ case WCD937X_RX_PA_AUX_IN_CONN:
+ case WCD937X_RX_TIMER_DIV:
+ case WCD937X_RX_OCP_CTL:
+ case WCD937X_RX_OCP_COUNT:
+ case WCD937X_RX_BIAS_EAR_DAC:
+ case WCD937X_RX_BIAS_EAR_AMP:
+ case WCD937X_RX_BIAS_HPH_LDO:
+ case WCD937X_RX_BIAS_HPH_PA:
+ case WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2:
+ case WCD937X_RX_BIAS_HPH_RDAC_LDO:
+ case WCD937X_RX_BIAS_HPH_CNP1:
+ case WCD937X_RX_BIAS_HPH_LOWPOWER:
+ case WCD937X_RX_BIAS_AUX_DAC:
+ case WCD937X_RX_BIAS_AUX_AMP:
+ case WCD937X_RX_BIAS_VNEGDAC_BLEEDER:
+ case WCD937X_RX_BIAS_MISC:
+ case WCD937X_RX_BIAS_BUCK_RST:
+ case WCD937X_RX_BIAS_BUCK_VREF_ERRAMP:
+ case WCD937X_RX_BIAS_FLYB_ERRAMP:
+ case WCD937X_RX_BIAS_FLYB_BUFF:
+ case WCD937X_RX_BIAS_FLYB_MID_RST:
+ case WCD937X_HPH_CNP_EN:
+ case WCD937X_HPH_CNP_WG_CTL:
+ case WCD937X_HPH_CNP_WG_TIME:
+ case WCD937X_HPH_OCP_CTL:
+ case WCD937X_HPH_AUTO_CHOP:
+ case WCD937X_HPH_CHOP_CTL:
+ case WCD937X_HPH_PA_CTL1:
+ case WCD937X_HPH_PA_CTL2:
+ case WCD937X_HPH_L_EN:
+ case WCD937X_HPH_L_TEST:
+ case WCD937X_HPH_L_ATEST:
+ case WCD937X_HPH_R_EN:
+ case WCD937X_HPH_R_TEST:
+ case WCD937X_HPH_R_ATEST:
+ case WCD937X_HPH_RDAC_CLK_CTL1:
+ case WCD937X_HPH_RDAC_CLK_CTL2:
+ case WCD937X_HPH_RDAC_LDO_CTL:
+ case WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL:
+ case WCD937X_HPH_REFBUFF_UHQA_CTL:
+ case WCD937X_HPH_REFBUFF_LP_CTL:
+ case WCD937X_HPH_L_DAC_CTL:
+ case WCD937X_HPH_R_DAC_CTL:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_EN:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1:
+ case WCD937X_EAR_EAR_EN_REG:
+ case WCD937X_EAR_EAR_PA_CON:
+ case WCD937X_EAR_EAR_SP_CON:
+ case WCD937X_EAR_EAR_DAC_CON:
+ case WCD937X_EAR_EAR_CNP_FSM_CON:
+ case WCD937X_EAR_TEST_CTL:
+ case WCD937X_HPH_NEW_ANA_HPH2:
+ case WCD937X_HPH_NEW_ANA_HPH3:
+ case WCD937X_SLEEP_CTL:
+ case WCD937X_SLEEP_WATCHDOG_CTL:
+ case WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL:
+ case WCD937X_MBHC_NEW_CTL_1:
+ case WCD937X_MBHC_NEW_CTL_2:
+ case WCD937X_MBHC_NEW_PLUG_DETECT_CTL:
+ case WCD937X_MBHC_NEW_ZDET_ANA_CTL:
+ case WCD937X_MBHC_NEW_ZDET_RAMP_CTL:
+ case WCD937X_TX_NEW_TX_CH2_SEL:
+ case WCD937X_AUX_AUXPA:
+ case WCD937X_LDORXTX_MODE:
+ case WCD937X_LDORXTX_CONFIG:
+ case WCD937X_DIE_CRACK_DIE_CRK_DET_EN:
+ case WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL:
+ case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L:
+ case WCD937X_HPH_NEW_INT_RDAC_VREF_CTL:
+ case WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL:
+ case WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R:
+ case WCD937X_HPH_NEW_INT_PA_MISC1:
+ case WCD937X_HPH_NEW_INT_PA_MISC2:
+ case WCD937X_HPH_NEW_INT_PA_RDAC_MISC:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER1:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER2:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER3:
+ case WCD937X_HPH_NEW_INT_HPH_TIMER4:
+ case WCD937X_HPH_NEW_INT_PA_RDAC_MISC2:
+ case WCD937X_HPH_NEW_INT_PA_RDAC_MISC3:
+ case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI:
+ case WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP:
+ case WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP:
+ case WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL:
+ case WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL:
+ case WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT:
+ case WCD937X_MBHC_NEW_INT_SPARE_2:
+ case WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON:
+ case WCD937X_EAR_INT_NEW_CNP_VCM_CON1:
+ case WCD937X_EAR_INT_NEW_CNP_VCM_CON2:
+ case WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS:
+ case WCD937X_AUX_INT_EN_REG:
+ case WCD937X_AUX_INT_PA_CTRL:
+ case WCD937X_AUX_INT_SP_CTRL:
+ case WCD937X_AUX_INT_DAC_CTRL:
+ case WCD937X_AUX_INT_CLK_CTRL:
+ case WCD937X_AUX_INT_TEST_CTRL:
+ case WCD937X_AUX_INT_MISC:
+ case WCD937X_LDORXTX_INT_BIAS:
+ case WCD937X_LDORXTX_INT_STB_LOADS_DTEST:
+ case WCD937X_LDORXTX_INT_TEST0:
+ case WCD937X_LDORXTX_INT_STARTUP_TIMER:
+ case WCD937X_LDORXTX_INT_TEST1:
+ case WCD937X_SLEEP_INT_WATCHDOG_CTL_1:
+ case WCD937X_SLEEP_INT_WATCHDOG_CTL_2:
+ case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1:
+ case WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2:
+ case WCD937X_DIGITAL_CDC_RST_CTL:
+ case WCD937X_DIGITAL_TOP_CLK_CFG:
+ case WCD937X_DIGITAL_CDC_ANA_CLK_CTL:
+ case WCD937X_DIGITAL_CDC_DIG_CLK_CTL:
+ case WCD937X_DIGITAL_SWR_RST_EN:
+ case WCD937X_DIGITAL_CDC_PATH_MODE:
+ case WCD937X_DIGITAL_CDC_RX_RST:
+ case WCD937X_DIGITAL_CDC_RX0_CTL:
+ case WCD937X_DIGITAL_CDC_RX1_CTL:
+ case WCD937X_DIGITAL_CDC_RX2_CTL:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA0:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA1:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA2:
+ case WCD937X_DIGITAL_DEM_BYPASS_DATA3:
+ case WCD937X_DIGITAL_CDC_COMP_CTL_0:
+ case WCD937X_DIGITAL_CDC_RX_DELAY_CTL:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A1_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A1_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A2_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A2_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A3_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A3_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A4_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A4_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A5_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A5_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A6_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_A7_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_0:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_2:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_C_3:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R1:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R2:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R3:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R4:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R5:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R6:
+ case WCD937X_DIGITAL_CDC_HPH_DSM_R7:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A1_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A1_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A2_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A2_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A3_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A3_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A4_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A4_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A5_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A5_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A6_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_A7_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_0:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_2:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_C_3:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R1:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R2:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R3:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R4:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R5:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R6:
+ case WCD937X_DIGITAL_CDC_AUX_DSM_R7:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2:
+ case WCD937X_DIGITAL_CDC_HPH_GAIN_CTL:
+ case WCD937X_DIGITAL_CDC_AUX_GAIN_CTL:
+ case WCD937X_DIGITAL_CDC_EAR_PATH_CTL:
+ case WCD937X_DIGITAL_CDC_SWR_CLH:
+ case WCD937X_DIGITAL_SWR_CLH_BYP:
+ case WCD937X_DIGITAL_CDC_TX0_CTL:
+ case WCD937X_DIGITAL_CDC_TX1_CTL:
+ case WCD937X_DIGITAL_CDC_TX2_CTL:
+ case WCD937X_DIGITAL_CDC_TX_RST:
+ case WCD937X_DIGITAL_CDC_REQ_CTL:
+ case WCD937X_DIGITAL_CDC_AMIC_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC1_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC2_CTL:
+ case WCD937X_DIGITAL_CDC_DMIC3_CTL:
+ case WCD937X_DIGITAL_EFUSE_CTL:
+ case WCD937X_DIGITAL_EFUSE_PRG_CTL:
+ case WCD937X_DIGITAL_EFUSE_TEST_CTL_0:
+ case WCD937X_DIGITAL_EFUSE_TEST_CTL_1:
+ case WCD937X_DIGITAL_PDM_WD_CTL0:
+ case WCD937X_DIGITAL_PDM_WD_CTL1:
+ case WCD937X_DIGITAL_PDM_WD_CTL2:
+ case WCD937X_DIGITAL_INTR_MODE:
+ case WCD937X_DIGITAL_INTR_MASK_0:
+ case WCD937X_DIGITAL_INTR_MASK_1:
+ case WCD937X_DIGITAL_INTR_MASK_2:
+ case WCD937X_DIGITAL_INTR_CLEAR_0:
+ case WCD937X_DIGITAL_INTR_CLEAR_1:
+ case WCD937X_DIGITAL_INTR_CLEAR_2:
+ case WCD937X_DIGITAL_INTR_LEVEL_0:
+ case WCD937X_DIGITAL_INTR_LEVEL_1:
+ case WCD937X_DIGITAL_INTR_LEVEL_2:
+ case WCD937X_DIGITAL_INTR_SET_0:
+ case WCD937X_DIGITAL_INTR_SET_1:
+ case WCD937X_DIGITAL_INTR_SET_2:
+ case WCD937X_DIGITAL_INTR_TEST_0:
+ case WCD937X_DIGITAL_INTR_TEST_1:
+ case WCD937X_DIGITAL_INTR_TEST_2:
+ case WCD937X_DIGITAL_CDC_CONN_RX0_CTL:
+ case WCD937X_DIGITAL_CDC_CONN_RX1_CTL:
+ case WCD937X_DIGITAL_CDC_CONN_RX2_CTL:
+ case WCD937X_DIGITAL_CDC_CONN_TX_CTL:
+ case WCD937X_DIGITAL_LOOP_BACK_MODE:
+ case WCD937X_DIGITAL_SWR_DAC_TEST:
+ case WCD937X_DIGITAL_SWR_HM_TEST_RX_0:
+ case WCD937X_DIGITAL_SWR_HM_TEST_TX_0:
+ case WCD937X_DIGITAL_SWR_HM_TEST_RX_1:
+ case WCD937X_DIGITAL_SWR_HM_TEST_TX_1:
+ case WCD937X_DIGITAL_SWR_HM_TEST:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_RX0:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_RX1:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_TX0:
+ case WCD937X_DIGITAL_PAD_CTL_PDM_TX1:
+ case WCD937X_DIGITAL_PAD_INP_DIS_0:
+ case WCD937X_DIGITAL_PAD_INP_DIS_1:
+ case WCD937X_DIGITAL_DRIVE_STRENGTH_0:
+ case WCD937X_DIGITAL_DRIVE_STRENGTH_1:
+ case WCD937X_DIGITAL_DRIVE_STRENGTH_2:
+ case WCD937X_DIGITAL_RX_DATA_EDGE_CTL:
+ case WCD937X_DIGITAL_TX_DATA_EDGE_CTL:
+ case WCD937X_DIGITAL_GPIO_MODE:
+ case WCD937X_DIGITAL_PIN_CTL_OE:
+ case WCD937X_DIGITAL_PIN_CTL_DATA_0:
+ case WCD937X_DIGITAL_PIN_CTL_DATA_1:
+ case WCD937X_DIGITAL_PIN_STATUS_0:
+ case WCD937X_DIGITAL_PIN_STATUS_1:
+ case WCD937X_DIGITAL_DIG_DEBUG_CTL:
+ case WCD937X_DIGITAL_DIG_DEBUG_EN:
+ case WCD937X_DIGITAL_ANA_CSR_DBG_ADD:
+ case WCD937X_DIGITAL_ANA_CSR_DBG_CTL:
+ case WCD937X_DIGITAL_SSP_DBG:
+ case WCD937X_DIGITAL_MODE_STATUS_0:
+ case WCD937X_DIGITAL_MODE_STATUS_1:
+ case WCD937X_DIGITAL_SPARE_0:
+ case WCD937X_DIGITAL_SPARE_1:
+ case WCD937X_DIGITAL_SPARE_2:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wcd937x_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD937X_ANA_MBHC_RESULT_1:
+ case WCD937X_ANA_MBHC_RESULT_2:
+ case WCD937X_ANA_MBHC_RESULT_3:
+ case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS:
+ case WCD937X_TX_1_2_SAR2_ERR:
+ case WCD937X_TX_1_2_SAR1_ERR:
+ case WCD937X_TX_3_SPARE_MONO:
+ case WCD937X_TX_3_SAR1_ERR:
+ case WCD937X_HPH_L_STATUS:
+ case WCD937X_HPH_R_STATUS:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS:
+ case WCD937X_EAR_STATUS_REG_1:
+ case WCD937X_EAR_STATUS_REG_2:
+ case WCD937X_MBHC_NEW_FSM_STATUS:
+ case WCD937X_MBHC_NEW_ADC_RESULT:
+ case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT:
+ case WCD937X_AUX_INT_STATUS_REG:
+ case WCD937X_LDORXTX_INT_STATUS:
+ case WCD937X_DIGITAL_CHIP_ID0:
+ case WCD937X_DIGITAL_CHIP_ID1:
+ case WCD937X_DIGITAL_CHIP_ID2:
+ case WCD937X_DIGITAL_CHIP_ID3:
+ case WCD937X_DIGITAL_EFUSE_T_DATA_0:
+ case WCD937X_DIGITAL_EFUSE_T_DATA_1:
+ case WCD937X_DIGITAL_INTR_STATUS_0:
+ case WCD937X_DIGITAL_INTR_STATUS_1:
+ case WCD937X_DIGITAL_INTR_STATUS_2:
+ case WCD937X_DIGITAL_EFUSE_REG_0:
+ case WCD937X_DIGITAL_EFUSE_REG_1:
+ case WCD937X_DIGITAL_EFUSE_REG_2:
+ case WCD937X_DIGITAL_EFUSE_REG_3:
+ case WCD937X_DIGITAL_EFUSE_REG_4:
+ case WCD937X_DIGITAL_EFUSE_REG_5:
+ case WCD937X_DIGITAL_EFUSE_REG_6:
+ case WCD937X_DIGITAL_EFUSE_REG_7:
+ case WCD937X_DIGITAL_EFUSE_REG_8:
+ case WCD937X_DIGITAL_EFUSE_REG_9:
+ case WCD937X_DIGITAL_EFUSE_REG_10:
+ case WCD937X_DIGITAL_EFUSE_REG_11:
+ case WCD937X_DIGITAL_EFUSE_REG_12:
+ case WCD937X_DIGITAL_EFUSE_REG_13:
+ case WCD937X_DIGITAL_EFUSE_REG_14:
+ case WCD937X_DIGITAL_EFUSE_REG_15:
+ case WCD937X_DIGITAL_EFUSE_REG_16:
+ case WCD937X_DIGITAL_EFUSE_REG_17:
+ case WCD937X_DIGITAL_EFUSE_REG_18:
+ case WCD937X_DIGITAL_EFUSE_REG_19:
+ case WCD937X_DIGITAL_EFUSE_REG_20:
+ case WCD937X_DIGITAL_EFUSE_REG_21:
+ case WCD937X_DIGITAL_EFUSE_REG_22:
+ case WCD937X_DIGITAL_EFUSE_REG_23:
+ case WCD937X_DIGITAL_EFUSE_REG_24:
+ case WCD937X_DIGITAL_EFUSE_REG_25:
+ case WCD937X_DIGITAL_EFUSE_REG_26:
+ case WCD937X_DIGITAL_EFUSE_REG_27:
+ case WCD937X_DIGITAL_EFUSE_REG_28:
+ case WCD937X_DIGITAL_EFUSE_REG_29:
+ case WCD937X_DIGITAL_EFUSE_REG_30:
+ case WCD937X_DIGITAL_EFUSE_REG_31:
+ return true;
+ }
+
+ return wcd937x_rdwr_register(dev, reg);
+}
+
+static bool wcd937x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD937X_ANA_MBHC_RESULT_1:
+ case WCD937X_ANA_MBHC_RESULT_2:
+ case WCD937X_ANA_MBHC_RESULT_3:
+ case WCD937X_MBHC_MOISTURE_DET_FSM_STATUS:
+ case WCD937X_TX_1_2_SAR1_ERR:
+ case WCD937X_TX_1_2_SAR2_ERR:
+ case WCD937X_TX_3_SAR1_ERR:
+ case WCD937X_HPH_L_STATUS:
+ case WCD937X_HPH_R_STATUS:
+ case WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS:
+ case WCD937X_EAR_STATUS_REG_1:
+ case WCD937X_EAR_STATUS_REG_2:
+ case WCD937X_MBHC_NEW_FSM_STATUS:
+ case WCD937X_MBHC_NEW_ADC_RESULT:
+ case WCD937X_DIE_CRACK_DIE_CRK_DET_OUT:
+ case WCD937X_DIGITAL_INTR_STATUS_0:
+ case WCD937X_DIGITAL_INTR_STATUS_1:
+ case WCD937X_DIGITAL_INTR_STATUS_2:
+ case WCD937X_DIGITAL_SWR_HM_TEST:
+ case WCD937X_DIGITAL_PIN_STATUS_0:
+ case WCD937X_DIGITAL_PIN_STATUS_1:
+ case WCD937X_DIGITAL_MODE_STATUS_0:
+ case WCD937X_DIGITAL_MODE_STATUS_1:
+ return true;
+ }
+ return false;
+}
+
+static const struct regmap_config wcd937x_regmap_config = {
+ .name = "wcd937x_csr",
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = wcd937x_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wcd937x_defaults),
+ .max_register = WCD937X_MAX_REGISTER,
+ .readable_reg = wcd937x_readable_register,
+ .writeable_reg = wcd937x_rdwr_register,
+ .volatile_reg = wcd937x_volatile_register,
+};
+
+static const struct sdw_slave_ops wcd9370_slave_ops = {
+ .update_status = wcd_update_status,
+ .interrupt_callback = wcd9370_interrupt_callback,
+};
+
+static int wcd9370_probe(struct sdw_slave *pdev,
+ const struct sdw_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct wcd937x_sdw_priv *wcd;
+ 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_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],
+ WCD937X_MAX_TX_SWR_PORTS);
+ } else {
+ ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping",
+ &pdev->m_port_map[1],
+ WCD937X_MAX_SWR_PORTS);
+ }
+ if (ret < 0)
+ dev_info(dev, "Error getting static port mapping for %s (%d)\n",
+ wcd->is_tx ? "TX" : "RX", ret);
+
+ wcd->sdev = pdev;
+ dev_set_drvdata(dev, wcd);
+
+ pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
+ SDW_SCP_INT1_BUS_CLASH |
+ 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) {
+ 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);
+ if (IS_ERR(wcd->regmap))
+ return dev_err_probe(dev, PTR_ERR(wcd->regmap),
+ "Regmap init failed\n");
+
+ /* Start in cache-only until device is enumerated */
+ regcache_cache_only(wcd->regmap, true);
+ } else {
+ 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]);
+ }
+
+
+ ret = component_add(dev, &wcd_sdw_component_ops);
+ if (ret)
+ return ret;
+
+ /* Set suspended until aggregate device is bind */
+ pm_runtime_set_suspended(dev);
+
+ return 0;
+}
+
+static int wcd9370_remove(struct sdw_slave *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_del(dev, &wcd_sdw_component_ops);
+
+ return 0;
+}
+
+static const struct sdw_device_id wcd9370_slave_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x10a, 0), /* WCD9370 RX/TX Device ID */
+ { },
+};
+MODULE_DEVICE_TABLE(sdw, wcd9370_slave_id);
+
+static int wcd937x_sdw_runtime_suspend(struct device *dev)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ if (wcd->regmap) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ }
+
+ return 0;
+}
+
+static int wcd937x_sdw_runtime_resume(struct device *dev)
+{
+ struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ if (wcd->regmap) {
+ regcache_cache_only(wcd->regmap, false);
+ regcache_sync(wcd->regmap);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops wcd937x_sdw_pm_ops = {
+ RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL)
+};
+
+static struct sdw_driver wcd9370_codec_driver = {
+ .probe = wcd9370_probe,
+ .remove = wcd9370_remove,
+ .ops = &wcd9370_slave_ops,
+ .id_table = wcd9370_slave_id,
+ .driver = {
+ .name = "wcd9370-codec",
+ .pm = pm_ptr(&wcd937x_sdw_pm_ops),
+ }
+};
+module_sdw_driver(wcd9370_codec_driver);
+
+MODULE_DESCRIPTION("WCD937X SDW codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
new file mode 100644
index 000000000000..f1dced57a59b
--- /dev/null
+++ b/sound/soc/codecs/wcd937x.c
@@ -0,0 +1,2987 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "wcd-clsh-v2.h"
+#include "wcd-common.h"
+#include "wcd-mbhc-v2.h"
+#include "wcd937x.h"
+
+#define CHIPID_WCD9370 0x0
+#define CHIPID_WCD9375 0x5
+
+/* Z value defined in milliohm */
+#define WCD937X_ZDET_VAL_32 (32000)
+#define WCD937X_ZDET_VAL_400 (400000)
+#define WCD937X_ZDET_VAL_1200 (1200000)
+#define WCD937X_ZDET_VAL_100K (100000000)
+/* Z floating defined in ohms */
+#define WCD937X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE)
+#define WCD937X_ZDET_NUM_MEASUREMENTS (900)
+#define WCD937X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14)
+#define WCD937X_MBHC_GET_X1(x) ((x) & 0x3FFF)
+/* Z value compared in milliOhm */
+#define WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z) (((z) > 400000) || ((z) < 32000))
+#define WCD937X_MBHC_ZDET_CONST (86 * 16384)
+#define WCD937X_MBHC_MOISTURE_RREF R_24_KOHM
+#define WCD_MBHC_HS_V_MAX 1600
+#define EAR_RX_PATH_AUX 1
+#define WCD937X_MBHC_MAX_BUTTONS 8
+
+#define WCD937X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_384000)
+
+/* Fractional Rates */
+#define WCD937X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define WCD937X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+enum {
+ ALLOW_BUCK_DISABLE,
+ HPH_COMP_DELAY,
+ HPH_PA_DELAY,
+ AMIC2_BCS_ENABLE,
+};
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ NUM_CODEC_DAIS,
+};
+
+struct wcd937x_priv {
+ struct sdw_slave *tx_sdw_dev;
+ struct wcd937x_sdw_priv *sdw_priv[NUM_CODEC_DAIS];
+ struct device *txdev;
+ struct device *rxdev;
+ struct device_node *rxnode;
+ struct device_node *txnode;
+ struct regmap *regmap;
+ /* micb setup lock */
+ struct mutex micb_lock;
+ /* mbhc module */
+ struct wcd_mbhc *wcd_mbhc;
+ struct wcd_mbhc_config mbhc_cfg;
+ struct wcd_mbhc_intr intr_ids;
+ struct wcd_clsh_ctrl *clsh_info;
+ struct wcd_common common;
+ struct irq_domain *virq;
+ struct regmap_irq_chip_data *irq_chip;
+ struct snd_soc_jack *jack;
+ unsigned long status_mask;
+ s32 micb_ref[WCD937X_MAX_MICBIAS];
+ s32 pullup_ref[WCD937X_MAX_MICBIAS];
+ u32 hph_mode;
+ int ear_rx_path;
+ int hphr_pdm_wd_int;
+ int hphl_pdm_wd_int;
+ int aux_pdm_wd_int;
+ bool comp1_enable;
+ bool comp2_enable;
+
+ struct gpio_desc *us_euro_gpio;
+ struct gpio_desc *reset_gpio;
+
+ atomic_t rx_clk_cnt;
+ atomic_t ana_clk_count;
+};
+
+static const char * const wcd937x_supplies[] = {
+ "vdd-rxtx", "vdd-px", "vdd-mic-bias", "vdd-buck",
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+struct wcd937x_mbhc_zdet_param {
+ u16 ldo_ctl;
+ u16 noff;
+ u16 nshift;
+ u16 btn5;
+ u16 btn6;
+ u16 btn7;
+};
+
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD937X_ANA_MBHC_MECH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD937X_ANA_MBHC_MECH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD937X_ANA_MBHC_MECH, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x30),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD937X_ANA_MBHC_ELECT, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD937X_ANA_MBHC_MECH, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD937X_ANA_MBHC_MECH, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD937X_ANA_MBHC_MECH, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD937X_ANA_MBHC_ELECT, 0x06),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD937X_ANA_MBHC_ELECT, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD937X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD937X_MBHC_NEW_CTL_1, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD937X_MBHC_NEW_CTL_2, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD937X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD937X_HPH_OCP_CTL, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0x07),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD937X_ANA_MBHC_ELECT, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD937X_ANA_MBHC_RESULT_3, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD937X_ANA_MICB2, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD937X_HPH_CNP_WG_TIME, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD937X_ANA_HPH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD937X_ANA_HPH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD937X_ANA_HPH, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD937X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD937X_MBHC_CTL_BCS, 0x02),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD937X_MBHC_NEW_CTL_2, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD937X_MBHC_NEW_FSM_STATUS, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD937X_HPH_PA_CTL2, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD937X_HPH_PA_CTL2, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD937X_HPH_L_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD937X_HPH_R_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD937X_DIGITAL_INTR_STATUS_0, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD937X_MBHC_NEW_CTL_1, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD937X_MBHC_NEW_FSM_STATUS, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD937X_MBHC_NEW_FSM_STATUS, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD937X_MBHC_NEW_ADC_RESULT, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD937X_ANA_MICB2, 0x3F),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD937X_MBHC_NEW_CTL_1, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD937X_MBHC_NEW_CTL_1, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD937X_ANA_MBHC_ZDET, 0x02),
+};
+
+static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = {
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, BIT(0)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, BIT(1)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_DET, 0, BIT(2)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, BIT(3)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_SW_DET, 0, BIT(4)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_OCP_INT, 0, BIT(5)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_CNP_INT, 0, BIT(6)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_OCP_INT, 0, BIT(7)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_CNP_INT, 1, BIT(0)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_EAR_CNP_INT, 1, BIT(1)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_EAR_SCD_INT, 1, BIT(2)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_AUX_CNP_INT, 1, BIT(3)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_AUX_SCD_INT, 1, BIT(4)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_PDM_WD_INT, 1, BIT(5)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_PDM_WD_INT, 1, BIT(6)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_AUX_PDM_WD_INT, 1, BIT(7)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_LDORT_SCD_INT, 2, BIT(0)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_MOISTURE_INT, 2, BIT(1)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHL_SURGE_DET_INT, 2, BIT(2)),
+ REGMAP_IRQ_REG(WCD937X_IRQ_HPHR_SURGE_DET_INT, 2, BIT(3)),
+};
+
+static int wcd937x_handle_post_irq(void *data)
+{
+ struct wcd937x_priv *wcd937x;
+
+ if (data)
+ wcd937x = (struct wcd937x_priv *)data;
+ else
+ return IRQ_HANDLED;
+
+ regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_0, 0);
+ regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_1, 0);
+ regmap_write(wcd937x->regmap, WCD937X_DIGITAL_INTR_CLEAR_2, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const u32 wcd937x_config_regs[] = {
+ WCD937X_DIGITAL_INTR_LEVEL_0,
+};
+
+static const struct regmap_irq_chip wcd937x_regmap_irq_chip = {
+ .name = "wcd937x",
+ .irqs = wcd937x_irqs,
+ .num_irqs = ARRAY_SIZE(wcd937x_irqs),
+ .num_regs = 3,
+ .status_base = WCD937X_DIGITAL_INTR_STATUS_0,
+ .mask_base = WCD937X_DIGITAL_INTR_MASK_0,
+ .ack_base = WCD937X_DIGITAL_INTR_CLEAR_0,
+ .use_ack = 1,
+ .clear_ack = 1,
+ .config_base = wcd937x_config_regs,
+ .num_config_bases = ARRAY_SIZE(wcd937x_config_regs),
+ .num_config_regs = 1,
+ .runtime_pm = true,
+ .handle_post_irq = wcd937x_handle_post_irq,
+ .irq_drv_data = NULL,
+};
+
+static void wcd937x_reset(struct wcd937x_priv *wcd937x)
+{
+ gpiod_set_value(wcd937x->reset_gpio, 1);
+ usleep_range(20, 30);
+ gpiod_set_value(wcd937x->reset_gpio, 0);
+ usleep_range(20, 30);
+}
+
+static void wcd937x_io_init(struct regmap *regmap)
+{
+ u32 val = 0, temp = 0, temp1 = 0;
+
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_29, &val);
+
+ val = val & 0x0F;
+
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &temp);
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_17, &temp1);
+
+ if (temp == 0x02 || temp1 > 0x09)
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0E, val);
+ else
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x0e, 0x0e);
+
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x80, 0x80);
+ usleep_range(1000, 1010);
+
+ regmap_update_bits(regmap, WCD937X_SLEEP_CTL, 0x40, 0x40);
+ usleep_range(1000, 1010);
+
+ regmap_update_bits(regmap, WCD937X_LDORXTX_CONFIG, BIT(4), 0x00);
+ regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xf0, BIT(7));
+ regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(7), BIT(7));
+ regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), BIT(6));
+ usleep_range(10000, 10010);
+
+ regmap_update_bits(regmap, WCD937X_ANA_BIAS, BIT(6), 0x00);
+ regmap_update_bits(regmap, WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xff, 0xd9);
+ regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_1, 0xff, 0xfa);
+ regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_1, 0xff, 0xfa);
+ regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_1, 0xff, 0xfa);
+
+ regmap_update_bits(regmap, WCD937X_MICB1_TEST_CTL_2, 0x38, 0x00);
+ regmap_update_bits(regmap, WCD937X_MICB2_TEST_CTL_2, 0x38, 0x00);
+ regmap_update_bits(regmap, WCD937X_MICB3_TEST_CTL_2, 0x38, 0x00);
+
+ /* Set Bandgap Fine Adjustment to +5mV for Tanggu SMIC part */
+ regmap_read(regmap, WCD937X_DIGITAL_EFUSE_REG_16, &val);
+ if (val == 0x01) {
+ regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+ } else if (val == 0x02) {
+ regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x1F, 0x04);
+ regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x1F, 0x04);
+ regmap_update_bits(regmap, WCD937X_BIAS_VBG_FINE_ADJ, 0xF0, 0xB0);
+ regmap_update_bits(regmap, WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL, 0xF0, 0x50);
+ }
+}
+
+static int wcd937x_rx_clk_enable(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (atomic_read(&wcd937x->rx_clk_cnt))
+ return 0;
+
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), BIT(0));
+ snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), BIT(0));
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX0_CTL, BIT(6), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX1_CTL, BIT(6), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_RX2_CTL, BIT(6), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), BIT(1));
+
+ atomic_inc(&wcd937x->rx_clk_cnt);
+
+ return 0;
+}
+
+static int wcd937x_rx_clk_disable(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (!atomic_read(&wcd937x->rx_clk_cnt)) {
+ dev_err(component->dev, "clk already disabled\n");
+ return 0;
+ }
+
+ atomic_dec(&wcd937x->rx_clk_cnt);
+
+ snd_soc_component_update_bits(component, WCD937X_ANA_RX_SUPPLIES, BIT(0), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(1), 0x00);
+ snd_soc_component_update_bits(component, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(0), 0x00);
+
+ return 0;
+}
+
+static int wcd937x_codec_hphl_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_RDAC_CLK_CTL1,
+ BIT(7), 0x00);
+ set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(1));
+ else if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, 0x06);
+
+ if (wcd937x->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_L_EN,
+ BIT(5), 0x00);
+
+ if (wcd937x->comp2_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_R_EN, BIT(5), 0x00);
+ }
+
+ if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+ usleep_range(5000, 5110);
+ clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_L_EN,
+ BIT(5), BIT(5));
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(0));
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_hphr_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_RDAC_CLK_CTL1, BIT(7), 0x00);
+ set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ 0x0f, BIT(1));
+ else if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ 0x0f, 0x06);
+ if (wcd937x->comp2_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_R_EN, BIT(5), 0x00);
+ if (wcd937x->comp1_enable) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_L_EN,
+ BIT(5), 0x00);
+ }
+
+ if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+ usleep_range(5000, 5110);
+ clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+ }
+ } else {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(0), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_R_EN,
+ BIT(5), BIT(5));
+ }
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ 0x0f, BIT(0));
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_ear_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(0), BIT(0));
+
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(1));
+ else if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, 0x06);
+ if (wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), BIT(1));
+ usleep_range(5000, 5010);
+
+ snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, BIT(2), 0x00);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_EAR,
+ hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ 0x0f, BIT(0));
+ if (wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_COMP_CTL_0,
+ BIT(1), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_aux_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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_rx_clk_enable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(2), BIT(2));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,
+ BIT(0), BIT(0));
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_AUX,
+ hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(2), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHR,
+ hph_mode);
+ snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+ BIT(4), BIT(4));
+ usleep_range(100, 110);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL1,
+ 0x07, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (wcd937x->comp2_enable)
+ usleep_range(7000, 7100);
+ else
+ usleep_range(20000, 20100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), BIT(1));
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+ enable_irq(wcd937x->hphr_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHR_PA_OFF);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (wcd937x->comp2_enable)
+ usleep_range(7000, 7100);
+ else
+ usleep_range(20000, 20100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHR_PA_OFF);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00);
+ snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+ BIT(4), 0x00);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHR,
+ hph_mode);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHL,
+ hph_mode);
+ snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+ BIT(5), BIT(5));
+ usleep_range(100, 110);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (!wcd937x->comp1_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_HPH_NEW_INT_HPH_TIMER1,
+ BIT(1), BIT(1));
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+ enable_irq(wcd937x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+ set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+ if (!wcd937x->comp1_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+ }
+
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHL_PA_OFF);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_HPH, BIT(5), 0x00);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHL,
+ hph_mode);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+ u8 val;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ val = WCD937X_DIGITAL_PDM_WD_CTL2_EN |
+ WCD937X_DIGITAL_PDM_WD_CTL2_TIMEOUT_SEL |
+ WCD937X_DIGITAL_PDM_WD_CTL2_HOLD_OFF;
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ WCD937X_DIGITAL_PDM_WD_CTL2_MASK,
+ val);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1010);
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+ enable_irq(wcd937x->aux_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(2000, 2010);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_AUX,
+ hph_mode);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ WCD937X_DIGITAL_PDM_WD_CTL2_MASK,
+ 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd937x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable watchdog interrupt for HPHL or AUX depending on mux value */
+ wcd937x->ear_rx_path = snd_soc_component_read(component,
+ WCD937X_DIGITAL_CDC_EAR_PATH_CTL);
+
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ BIT(0), BIT(0));
+ else
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0,
+ 0x07, 0x03);
+ if (!wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_EAR_COMPANDER_CTL,
+ BIT(7), BIT(7));
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(6000, 6010);
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_RX_SUPPLIES,
+ BIT(1), BIT(1));
+
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ enable_irq(wcd937x->aux_pdm_wd_int);
+ else
+ enable_irq(wcd937x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+ else
+ disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (!wcd937x->comp1_enable)
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_EAR_COMPANDER_CTL,
+ BIT(7), 0x00);
+ usleep_range(7000, 7010);
+ wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_EAR,
+ hph_mode);
+ snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN,
+ BIT(2), BIT(2));
+
+ if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL2,
+ BIT(0), 0x00);
+ else
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_PDM_WD_CTL0,
+ 0x07, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_rx1(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (event == SND_SOC_DAPM_POST_PMD) {
+ wcd937x_rx_clk_disable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(0), 0x00);
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_rx2(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (event == SND_SOC_DAPM_POST_PMD) {
+ wcd937x_rx_clk_disable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(1), 0x00);
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (event == SND_SOC_DAPM_POST_PMD) {
+ usleep_range(6000, 6010);
+ wcd937x_rx_clk_disable(component);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(2), 0x00);
+ }
+
+ return 0;
+}
+
+
+static int wcd937x_tx_swr_ctrl(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ bool use_amic3 = snd_soc_component_read(component, WCD937X_TX_NEW_TX_CH2_SEL) & BIT(7);
+
+ /* Enable BCS for Headset mic */
+ if (event == SND_SOC_DAPM_PRE_PMU && strnstr(w->name, "ADC", sizeof("ADC")))
+ if (w->shift == 1 && !use_amic3)
+ set_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_adc(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ atomic_inc(&wcd937x->ana_clk_count);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(4), BIT(4));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (w->shift == 1 && test_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask))
+ clear_bit(AMIC2_BCS_ENABLE, &wcd937x->status_mask);
+
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL, BIT(3), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_enable_req(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 wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_REQ_CTL, BIT(1), BIT(1));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_REQ_CTL, BIT(0), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(6), BIT(6));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3_HPF, BIT(6), BIT(6));
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, 0x70, 0x70);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH1, BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(6), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3, BIT(7), BIT(7));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH1, BIT(7), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH2, BIT(7), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_ANA_TX_CH3, BIT(7), 0x00);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(4), 0x00);
+
+ atomic_dec(&wcd937x->ana_clk_count);
+ if (atomic_read(&wcd937x->ana_clk_count) <= 0) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(4), 0x00);
+ atomic_set(&wcd937x->ana_clk_count, 0);
+ }
+
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(7), 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u16 dmic_clk_reg;
+
+ switch (w->shift) {
+ case 0:
+ case 1:
+ dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC1_CTL;
+ break;
+ case 2:
+ case 3:
+ dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC2_CTL;
+ break;
+ case 4:
+ case 5:
+ dmic_clk_reg = WCD937X_DIGITAL_CDC_DMIC3_CTL;
+ break;
+ default:
+ dev_err(component->dev, "Invalid DMIC Selection\n");
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ BIT(7), BIT(7));
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x07, BIT(1));
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, BIT(3), BIT(3));
+ snd_soc_component_update_bits(component,
+ dmic_clk_reg, 0x70, BIT(5));
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int micb_index = micb_num - 1;
+ u16 micb_reg;
+
+ if (micb_index < 0 || (micb_index > WCD937X_MAX_MICBIAS - 1)) {
+ dev_err(component->dev, "Invalid micbias index, micb_ind:%d\n", micb_index);
+ return -EINVAL;
+ }
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD937X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD937X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD937X_ANA_MICB3;
+ break;
+ default:
+ dev_err(component->dev, "Invalid micbias number: %d\n", micb_num);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wcd937x->micb_lock);
+ switch (req) {
+ case MICB_PULLUP_ENABLE:
+ wcd937x->pullup_ref[micb_index]++;
+ if (wcd937x->pullup_ref[micb_index] == 1 &&
+ wcd937x->micb_ref[micb_index] == 0)
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, BIT(7));
+ break;
+ case MICB_PULLUP_DISABLE:
+ if (wcd937x->pullup_ref[micb_index] > 0)
+ wcd937x->pullup_ref[micb_index]++;
+ if (wcd937x->pullup_ref[micb_index] == 0 &&
+ wcd937x->micb_ref[micb_index] == 0)
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, 0x00);
+ break;
+ case MICB_ENABLE:
+ wcd937x->micb_ref[micb_index]++;
+ atomic_inc(&wcd937x->ana_clk_count);
+ if (wcd937x->micb_ref[micb_index] == 1) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+ 0xf0, 0xf0);
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(4), BIT(4));
+ snd_soc_component_update_bits(component,
+ WCD937X_MICB1_TEST_CTL_2,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_MICB2_TEST_CTL_2,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ WCD937X_MICB3_TEST_CTL_2,
+ BIT(0), BIT(0));
+ snd_soc_component_update_bits(component,
+ micb_reg, 0xc0, BIT(6));
+
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_ON);
+
+ if (micb_num == MIC_BIAS_2 && is_dapm)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
+ }
+ break;
+ case MICB_DISABLE:
+ atomic_dec(&wcd937x->ana_clk_count);
+ if (wcd937x->micb_ref[micb_index] > 0)
+ wcd937x->micb_ref[micb_index]--;
+ if (wcd937x->micb_ref[micb_index] == 0 &&
+ wcd937x->pullup_ref[micb_index] > 0)
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, BIT(7));
+ else if (wcd937x->micb_ref[micb_index] == 0 &&
+ wcd937x->pullup_ref[micb_index] == 0) {
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_PRE_MICBIAS_2_OFF);
+
+ snd_soc_component_update_bits(component, micb_reg,
+ 0xc0, 0x00);
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_OFF);
+ }
+
+ if (is_dapm && micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd937x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
+ if (atomic_read(&wcd937x->ana_clk_count) <= 0) {
+ snd_soc_component_update_bits(component,
+ WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+ BIT(4), 0x00);
+ atomic_set(&wcd937x->ana_clk_count, 0);
+ }
+ break;
+ }
+ mutex_unlock(&wcd937x->micb_lock);
+
+ return 0;
+}
+
+static int __wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_micbias_control(component, micb_num,
+ MICB_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd937x_micbias_control(component, micb_num,
+ MICB_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __wcd937x_codec_enable_micbias(w, event);
+}
+
+static int __wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd937x_micbias_control(component, micb_num, MICB_PULLUP_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd937x_micbias_control(component, micb_num, MICB_PULLUP_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ return __wcd937x_codec_enable_micbias_pullup(w, event);
+}
+
+static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch_id, bool enable)
+{
+ struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1];
+ const struct wcd_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;
+
+ 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;
+ 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;
+}
+
+static int wcd937x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd937x->hph_mode;
+ return 0;
+}
+
+static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ u32 mode_val;
+
+ mode_val = ucontrol->value.enumerated.item[0];
+
+ if (!mode_val)
+ mode_val = CLS_AB;
+
+ if (mode_val == wcd937x->hph_mode)
+ return 0;
+
+ switch (mode_val) {
+ case CLS_H_NORMAL:
+ case CLS_H_HIFI:
+ case CLS_H_LP:
+ case CLS_AB:
+ case CLS_H_LOHIFI:
+ case CLS_H_ULP:
+ case CLS_AB_LP:
+ case CLS_AB_HIFI:
+ wcd937x->hph_mode = mode_val;
+ return 1;
+ }
+
+ dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__);
+ return -EINVAL;
+}
+
+static int wcd937x_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc;
+ bool hphr;
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ ucontrol->value.integer.value[0] = hphr ? wcd937x->comp2_enable :
+ wcd937x->comp1_enable;
+ return 0;
+}
+
+static int wcd937x_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[AIF1_PB];
+ int value = ucontrol->value.integer.value[0];
+ struct soc_mixer_control *mc;
+ int portidx;
+ bool hphr;
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+
+ if (hphr) {
+ if (value == wcd937x->comp2_enable)
+ return 0;
+
+ wcd937x->comp2_enable = value;
+ } else {
+ if (value == wcd937x->comp1_enable)
+ return 0;
+
+ wcd937x->comp1_enable = value;
+ }
+
+ portidx = wcd->ch_info[mc->reg].port_num;
+
+ if (value)
+ wcd937x_connect_port(wcd, portidx, mc->reg, true);
+ else
+ wcd937x_connect_port(wcd, portidx, mc->reg, false);
+
+ return 1;
+}
+
+static int wcd937x_get_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp);
+ struct wcd937x_sdw_priv *wcd;
+ int dai_id = mixer->shift;
+ int ch_idx = mixer->reg;
+ int portidx;
+
+ wcd = wcd937x->sdw_priv[dai_id];
+ portidx = wcd->ch_info[ch_idx].port_num;
+
+ ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
+
+ return 0;
+}
+
+static int wcd937x_set_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(comp);
+ struct wcd937x_sdw_priv *wcd;
+ int dai_id = mixer->shift;
+ int ch_idx = mixer->reg;
+ int portidx;
+ bool enable;
+
+ wcd = wcd937x->sdw_priv[dai_id];
+
+ portidx = wcd->ch_info[ch_idx].port_num;
+
+ enable = ucontrol->value.integer.value[0];
+
+ if (enable == wcd->port_enable[portidx]) {
+ wcd937x_connect_port(wcd, portidx, ch_idx, enable);
+ return 0;
+ }
+
+ wcd->port_enable[portidx] = enable;
+ wcd937x_connect_port(wcd, portidx, ch_idx, enable);
+
+ return 1;
+}
+
+static const char * const rx_hph_mode_mux_text[] = {
+ "CLS_H_NORMAL", "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB",
+ "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_AB_LP", "CLS_AB_HIFI",
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text);
+
+/* MBHC related */
+static void wcd937x_mbhc_clk_setup(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_1,
+ WCD937X_MBHC_CTL_RCO_EN_MASK, enable);
+}
+
+static void wcd937x_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_ELECT,
+ WCD937X_ANA_MBHC_BIAS_EN, enable);
+}
+
+static void wcd937x_mbhc_program_btn_thr(struct snd_soc_component *component,
+ int *btn_low, int *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i, vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = ((btn_high[i] * 2) / 25) & 0x3F;
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_BTN0 + i,
+ WCD937X_MBHC_BTN_VTH_MASK, vth);
+ }
+}
+
+static bool wcd937x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
+{
+ u8 val;
+
+ if (micb_num == MIC_BIAS_2) {
+ val = snd_soc_component_read_field(component,
+ WCD937X_ANA_MICB2,
+ WCD937X_ANA_MICB2_ENABLE_MASK);
+ if (val == WCD937X_MICB_ENABLE)
+ return true;
+ }
+ return false;
+}
+
+static void wcd937x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component,
+ int pull_up_cur)
+{
+ /* Default pull up current to 2uA */
+ if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA)
+ pull_up_cur = HS_PULLUP_I_2P0_UA;
+
+ snd_soc_component_write_field(component,
+ WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT,
+ WCD937X_HSDET_PULLUP_C_MASK, pull_up_cur);
+}
+
+static int wcd937x_mbhc_request_micbias(struct snd_soc_component *component,
+ int micb_num, int req)
+{
+ return wcd937x_micbias_control(component, micb_num, req, false);
+}
+
+static void wcd937x_mbhc_micb_ramp_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_SHIFT_CTRL_MASK, 0x0C);
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_EN_MASK, 1);
+ } else {
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_EN_MASK, 0);
+ snd_soc_component_write_field(component, WCD937X_ANA_MICB2_RAMP,
+ WCD937X_RAMP_SHIFT_CTRL_MASK, 0);
+ }
+}
+
+static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int req_volt, int micb_num)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD937X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD937X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD937X_ANA_MICB3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mutex_lock(&wcd937x->micb_lock);
+ /*
+ * If requested micbias voltage is same as current micbias
+ * voltage, then just return. Otherwise, adjust voltage as
+ * per requested value. If micbias is already enabled, then
+ * to avoid slow micbias ramp-up or down enable pull-up
+ * momentarily, change the micbias value and then re-enable
+ * micbias.
+ */
+ micb_en = snd_soc_component_read_field(component, micb_reg,
+ WCD937X_MICB_EN_MASK);
+ cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
+ WCD937X_MICB_VOUT_MASK);
+
+ req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
+ if (req_vout_ctl < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (cur_vout_ctl == req_vout_ctl) {
+ ret = 0;
+ goto exit;
+ }
+
+ if (micb_en == WCD937X_MICB_ENABLE)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD937X_MICB_EN_MASK,
+ WCD937X_MICB_PULL_UP);
+
+ snd_soc_component_write_field(component, micb_reg,
+ WCD937X_MICB_VOUT_MASK,
+ req_vout_ctl);
+
+ if (micb_en == WCD937X_MICB_ENABLE) {
+ snd_soc_component_write_field(component, micb_reg,
+ WCD937X_MICB_EN_MASK,
+ WCD937X_MICB_ENABLE);
+ /*
+ * Add 2ms delay as per HW requirement after enabling
+ * micbias
+ */
+ usleep_range(2000, 2100);
+ }
+exit:
+ mutex_unlock(&wcd937x->micb_lock);
+ return ret;
+}
+
+static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
+ int micb_num, bool req_en)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int micb_mv;
+
+ if (micb_num != MIC_BIAS_2)
+ return -EINVAL;
+ /*
+ * If device tree micbias level is already above the minimum
+ * voltage needed to detect threshold microphone, then do
+ * not change the micbias, just return.
+ */
+ if (wcd937x->common.micb_mv[2] >= WCD_MBHC_THR_HS_MICB_MV)
+ return 0;
+
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd937x->common.micb_mv[2];
+
+ return wcd937x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+}
+
+static void wcd937x_mbhc_get_result_params(struct snd_soc_component *component,
+ s16 *d1_a, u16 noff,
+ int32_t *zdet)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ int i;
+ int val, val1;
+ s16 c1;
+ s32 x1, d1;
+ s32 denom;
+ static const int minCode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
+ };
+
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x20);
+ for (i = 0; i < WCD937X_ZDET_NUM_MEASUREMENTS; i++) {
+ regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_2, &val);
+ if (val & 0x80)
+ break;
+ }
+ val = val << 0x8;
+ regmap_read(wcd937x->regmap, WCD937X_ANA_MBHC_RESULT_1, &val1);
+ val |= val1;
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MBHC_ZDET, 0x20, 0x00);
+ x1 = WCD937X_MBHC_GET_X1(val);
+ c1 = WCD937X_MBHC_GET_C1(val);
+ /* If ramp is not complete, give additional 5ms */
+ if (c1 < 2 && x1)
+ usleep_range(5000, 5050);
+
+ if (!c1 || !x1) {
+ dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ c1, x1);
+ goto ramp_down;
+ }
+ d1 = d1_a[c1];
+ denom = (x1 * d1) - (1 << (14 - noff));
+ if (denom > 0)
+ *zdet = (WCD937X_MBHC_ZDET_CONST * 1000) / denom;
+ else if (x1 < minCode_param[noff])
+ *zdet = WCD937X_ZDET_FLOATING_IMPEDANCE;
+
+ dev_err(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n",
+ __func__, d1, c1, x1, *zdet);
+ramp_down:
+ i = 0;
+ while (x1) {
+ regmap_read(wcd937x->regmap,
+ WCD937X_ANA_MBHC_RESULT_1, &val);
+ regmap_read(wcd937x->regmap,
+ WCD937X_ANA_MBHC_RESULT_2, &val1);
+ val = val << 0x08;
+ val |= val1;
+ x1 = WCD937X_MBHC_GET_X1(val);
+ i++;
+ if (i == WCD937X_ZDET_NUM_MEASUREMENTS)
+ break;
+ }
+}
+
+static void wcd937x_mbhc_zdet_ramp(struct snd_soc_component *component,
+ struct wcd937x_mbhc_zdet_param *zdet_param,
+ s32 *zl, s32 *zr, s16 *d1_a)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ s32 zdet = 0;
+
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD937X_ZDET_MAXV_CTL_MASK, zdet_param->ldo_ctl);
+ snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN5,
+ WCD937X_VTH_MASK, zdet_param->btn5);
+ snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN6,
+ WCD937X_VTH_MASK, zdet_param->btn6);
+ snd_soc_component_update_bits(component, WCD937X_ANA_MBHC_BTN7,
+ WCD937X_VTH_MASK, zdet_param->btn7);
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD937X_ZDET_RANGE_CTL_MASK, zdet_param->noff);
+ snd_soc_component_update_bits(component, WCD937X_MBHC_NEW_ZDET_RAMP_CTL,
+ 0x0F, zdet_param->nshift);
+
+ if (!zl)
+ goto z_right;
+ /* Start impedance measurement for HPH_L */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x80, 0x80);
+ wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x80, 0x00);
+
+ *zl = zdet;
+
+z_right:
+ if (!zr)
+ return;
+ /* Start impedance measurement for HPH_R */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x40, 0x40);
+ wcd937x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ZDET, 0x40, 0x00);
+
+ *zr = zdet;
+}
+
+static void wcd937x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+ s32 *z_val, int flag_l_r)
+{
+ s16 q1;
+ int q1_cal;
+
+ if (*z_val < (WCD937X_ZDET_VAL_400 / 1000))
+ q1 = snd_soc_component_read(component,
+ WCD937X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r));
+ else
+ q1 = snd_soc_component_read(component,
+ WCD937X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r));
+ if (q1 & 0x80)
+ q1_cal = (10000 - ((q1 & 0x7F) * 25));
+ else
+ q1_cal = (10000 + (q1 * 25));
+ if (q1_cal > 0)
+ *z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void wcd937x_wcd_mbhc_calc_impedance(struct snd_soc_component *component,
+ u32 *zl, u32 *zr)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ s16 reg0, reg1, reg2, reg3, reg4;
+ s32 z1l, z1r, z1ls;
+ int zMono, z_diff1, z_diff2;
+ bool is_fsm_disable = false;
+ struct wcd937x_mbhc_zdet_param zdet_param[] = {
+ {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */
+ {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */
+ {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */
+ {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */
+ };
+ struct wcd937x_mbhc_zdet_param *zdet_param_ptr = NULL;
+ s16 d1_a[][4] = {
+ {0, 30, 90, 30},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ {0, 30, 30, 5},
+ };
+ s16 *d1 = NULL;
+
+ reg0 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN5);
+ reg1 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN6);
+ reg2 = snd_soc_component_read(component, WCD937X_ANA_MBHC_BTN7);
+ reg3 = snd_soc_component_read(component, WCD937X_MBHC_CTL_CLK);
+ reg4 = snd_soc_component_read(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL);
+
+ if (snd_soc_component_read(component, WCD937X_ANA_MBHC_ELECT) & 0x80) {
+ is_fsm_disable = true;
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ELECT, 0x80, 0x00);
+ }
+
+ /* For NO-jack, disable L_DET_EN before Z-det measurements */
+ if (wcd937x->mbhc_cfg.hphl_swh)
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x80, 0x00);
+
+ /* Turn off 100k pull down on HPHL */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x01, 0x00);
+
+ /* Disable surge protection before impedance detection.
+ * This is done to give correct value for high impedance.
+ */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00);
+ /* 1ms delay needed after disable surge protection */
+ usleep_range(1000, 1010);
+
+ /* First get impedance on Left */
+ d1 = d1_a[1];
+ zdet_param_ptr = &zdet_param[1];
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1);
+
+ if (!WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1l))
+ goto left_ch_impedance;
+
+ /* Second ramp for left ch */
+ if (z1l < WCD937X_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1l > WCD937X_ZDET_VAL_400) &&
+ (z1l <= WCD937X_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1l > WCD937X_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, &z1l, NULL, d1);
+
+left_ch_impedance:
+ if (z1l == WCD937X_ZDET_FLOATING_IMPEDANCE ||
+ z1l > WCD937X_ZDET_VAL_100K) {
+ *zl = WCD937X_ZDET_FLOATING_IMPEDANCE;
+ zdet_param_ptr = &zdet_param[1];
+ d1 = d1_a[1];
+ } else {
+ *zl = z1l / 1000;
+ wcd937x_wcd_mbhc_qfuse_cal(component, zl, 0);
+ }
+
+ /* Start of right impedance ramp and calculation */
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1);
+ if (WCD937X_MBHC_IS_SECOND_RAMP_REQUIRED(z1r)) {
+ if ((z1r > WCD937X_ZDET_VAL_1200 &&
+ zdet_param_ptr->noff == 0x6) ||
+ ((*zl) != WCD937X_ZDET_FLOATING_IMPEDANCE))
+ goto right_ch_impedance;
+ /* Second ramp for right ch */
+ if (z1r < WCD937X_ZDET_VAL_32) {
+ zdet_param_ptr = &zdet_param[0];
+ d1 = d1_a[0];
+ } else if ((z1r > WCD937X_ZDET_VAL_400) &&
+ (z1r <= WCD937X_ZDET_VAL_1200)) {
+ zdet_param_ptr = &zdet_param[2];
+ d1 = d1_a[2];
+ } else if (z1r > WCD937X_ZDET_VAL_1200) {
+ zdet_param_ptr = &zdet_param[3];
+ d1 = d1_a[3];
+ }
+ wcd937x_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1r, d1);
+ }
+right_ch_impedance:
+ if (z1r == WCD937X_ZDET_FLOATING_IMPEDANCE ||
+ z1r > WCD937X_ZDET_VAL_100K) {
+ *zr = WCD937X_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zr = z1r / 1000;
+ wcd937x_wcd_mbhc_qfuse_cal(component, zr, 1);
+ }
+
+ /* Mono/stereo detection */
+ if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) &&
+ (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE)) {
+ dev_err(component->dev,
+ "%s: plug type is invalid or extension cable\n",
+ __func__);
+ goto zdet_complete;
+ }
+ if ((*zl == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+ (*zr == WCD937X_ZDET_FLOATING_IMPEDANCE) ||
+ ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) ||
+ ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) {
+ wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+ goto zdet_complete;
+ }
+ snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST,
+ WCD937X_HPHPA_GND_OVR_MASK, 1);
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_R_MASK, 1);
+ if (*zl < (WCD937X_ZDET_VAL_32 / 1000))
+ wcd937x_mbhc_zdet_ramp(component, &zdet_param[0], &z1ls, NULL, d1);
+ else
+ wcd937x_mbhc_zdet_ramp(component, &zdet_param[1], &z1ls, NULL, d1);
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_R_MASK, 0);
+ snd_soc_component_write_field(component, WCD937X_HPH_R_ATEST,
+ WCD937X_HPHPA_GND_OVR_MASK, 0);
+ z1ls /= 1000;
+ wcd937x_wcd_mbhc_qfuse_cal(component, &z1ls, 0);
+ /* Parallel of left Z and 9 ohm pull down resistor */
+ zMono = ((*zl) * 9) / ((*zl) + 9);
+ z_diff1 = (z1ls > zMono) ? (z1ls - zMono) : (zMono - z1ls);
+ z_diff2 = ((*zl) > z1ls) ? ((*zl) - z1ls) : (z1ls - (*zl));
+ if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + zMono)))
+ wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_STEREO);
+ else
+ wcd_mbhc_set_hph_type(wcd937x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+
+ /* Enable surge protection again after impedance detection */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0);
+zdet_complete:
+ snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN5, reg0);
+ snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN6, reg1);
+ snd_soc_component_write(component, WCD937X_ANA_MBHC_BTN7, reg2);
+ /* Turn on 100k pull down on HPHL */
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x01, 0x01);
+
+ /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+ if (wcd937x->mbhc_cfg.hphl_swh)
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_MECH, 0x80, 0x80);
+
+ snd_soc_component_write(component, WCD937X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+ snd_soc_component_write(component, WCD937X_MBHC_CTL_CLK, reg3);
+ if (is_fsm_disable)
+ regmap_update_bits(wcd937x->regmap,
+ WCD937X_ANA_MBHC_ELECT, 0x80, 0x80);
+}
+
+static void wcd937x_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_HSG_PULLUP_COMP_EN, 1);
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_GND_DET_EN_MASK, 1);
+ } else {
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_GND_DET_EN_MASK, 0);
+ snd_soc_component_write_field(component, WCD937X_ANA_MBHC_MECH,
+ WCD937X_MBHC_HSG_PULLUP_COMP_EN, 0);
+ }
+}
+
+static void wcd937x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_R_MASK, enable);
+ snd_soc_component_write_field(component, WCD937X_HPH_PA_CTL2,
+ WCD937X_HPHPA_GND_L_MASK, enable);
+}
+
+static void wcd937x_mbhc_moisture_config(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ return;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd937x->mbhc_cfg.hphl_swh) {
+ dev_err(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ return;
+ }
+
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref);
+}
+
+static void wcd937x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ if (enable)
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, wcd937x->mbhc_cfg.moist_rref);
+ else
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+}
+
+static bool wcd937x_mbhc_get_moisture_status(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ bool ret = false;
+
+ if (wcd937x->mbhc_cfg.moist_rref == R_OFF) {
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ goto done;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd937x->mbhc_cfg.hphl_swh) {
+ dev_err(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD937X_MBHC_NEW_CTL_2,
+ WCD937X_M_RTH_CTL_MASK, R_OFF);
+ goto done;
+ }
+
+ /*
+ * If moisture_en is already enabled, then skip to plug type
+ * detection.
+ */
+ if (snd_soc_component_read_field(component, WCD937X_MBHC_NEW_CTL_2, WCD937X_M_RTH_CTL_MASK))
+ goto done;
+
+ wcd937x_mbhc_moisture_detect_en(component, true);
+ /* Read moisture comparator status */
+ ret = ((snd_soc_component_read(component, WCD937X_MBHC_NEW_FSM_STATUS)
+ & 0x20) ? 0 : 1);
+done:
+ return ret;
+}
+
+static void wcd937x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component,
+ WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL,
+ WCD937X_MOISTURE_EN_POLLING_MASK, enable);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .clk_setup = wcd937x_mbhc_clk_setup,
+ .mbhc_bias = wcd937x_mbhc_mbhc_bias_control,
+ .set_btn_thr = wcd937x_mbhc_program_btn_thr,
+ .micbias_enable_status = wcd937x_mbhc_micb_en_status,
+ .hph_pull_up_control_v2 = wcd937x_mbhc_hph_l_pull_up_control,
+ .mbhc_micbias_control = wcd937x_mbhc_request_micbias,
+ .mbhc_micb_ramp_control = wcd937x_mbhc_micb_ramp_control,
+ .mbhc_micb_ctrl_thr_mic = wcd937x_mbhc_micb_ctrl_threshold_mic,
+ .compute_impedance = wcd937x_wcd_mbhc_calc_impedance,
+ .mbhc_gnd_det_ctrl = wcd937x_mbhc_gnd_det_ctrl,
+ .hph_pull_down_ctrl = wcd937x_mbhc_hph_pull_down_ctrl,
+ .mbhc_moisture_config = wcd937x_mbhc_moisture_config,
+ .mbhc_get_moisture_status = wcd937x_mbhc_get_moisture_status,
+ .mbhc_moisture_polling_ctrl = wcd937x_mbhc_moisture_polling_ctrl,
+ .mbhc_moisture_detect_en = wcd937x_mbhc_moisture_detect_en,
+};
+
+static int wcd937x_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd937x->wcd_mbhc);
+
+ return 0;
+}
+
+static int wcd937x_hph_impedance_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u32 zl, zr;
+ bool hphr;
+ struct soc_mixer_control *mc;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ mc = (struct soc_mixer_control *)(kcontrol->private_value);
+ hphr = mc->shift;
+ wcd_mbhc_get_impedance(wcd937x->wcd_mbhc, &zl, &zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, WCD_MBHC_HPH_STEREO, 0,
+ wcd937x_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, INT_MAX, 0,
+ wcd937x_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, INT_MAX, 0,
+ wcd937x_hph_impedance_get, NULL),
+};
+
+static int wcd937x_mbhc_init(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct wcd_mbhc_intr *intr_ids = &wcd937x->intr_ids;
+
+ intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_SW_DET);
+ intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_BUTTON_PRESS_DET);
+ intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET);
+ intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET);
+ intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_DET);
+ intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHL_OCP_INT);
+ intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHR_OCP_INT);
+
+ wcd937x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+ if (IS_ERR(wcd937x->wcd_mbhc))
+ return PTR_ERR(wcd937x->wcd_mbhc);
+
+ snd_soc_add_component_controls(component, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_component_controls(component, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ return 0;
+}
+
+static void wcd937x_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ wcd_mbhc_deinit(wcd937x->wcd_mbhc);
+}
+
+/* END MBHC */
+
+static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
+ SOC_SINGLE_TLV("EAR_PA Volume", WCD937X_ANA_EAR_COMPANDER_CTL,
+ 2, 0x10, 0, ear_pa_gain),
+ SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+ wcd937x_rx_hph_mode_get, wcd937x_rx_hph_mode_put),
+
+ SOC_SINGLE_EXT("HPHL_COMP Switch", WCD937X_COMP_L, 0, 1, 0,
+ wcd937x_get_compander, wcd937x_set_compander),
+ SOC_SINGLE_EXT("HPHR_COMP Switch", WCD937X_COMP_R, 1, 1, 0,
+ wcd937x_get_compander, wcd937x_set_compander),
+
+ SOC_SINGLE_TLV("HPHL Volume", WCD937X_HPH_L_EN, 0, 20, 1, line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", WCD937X_HPH_R_EN, 0, 20, 1, line_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", WCD937X_ANA_TX_CH1, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", WCD937X_ANA_TX_CH2, 0, 20, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", WCD937X_ANA_TX_CH3, 0, 20, 0, analog_gain),
+
+ SOC_SINGLE_EXT("HPHL Switch", WCD937X_HPH_L, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("HPHR Switch", WCD937X_HPH_R, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+
+ SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("ADC2 Switch", WCD937X_ADC2, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("ADC3 Switch", WCD937X_ADC3, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC0 Switch", WCD937X_DMIC0, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC1 Switch", WCD937X_DMIC1, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("MBHC Switch", WCD937X_MBHC, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC2 Switch", WCD937X_DMIC2, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC3 Switch", WCD937X_DMIC3, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC4 Switch", WCD937X_DMIC4, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC5 Switch", WCD937X_DMIC5, 1, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic4_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic5_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic6_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new aux_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc2_mux_text[] = {
+ "INP2", "INP3"
+};
+
+static const char * const rdac3_mux_text[] = {
+ "RX1", "RX3"
+};
+
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE(WCD937X_TX_NEW_TX_CH2_SEL, 7,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum rdac3_enum =
+ SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0,
+ ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+
+static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
+
+static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = {
+ /* Input widgets */
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("IN1_HPHL"),
+ SND_SOC_DAPM_INPUT("IN2_HPHR"),
+ SND_SOC_DAPM_INPUT("IN3_AUX"),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0,
+ wcd937x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wcd937x_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wcd937x_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+
+ /* TX mixers */
+ SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+ adc1_switch, ARRAY_SIZE(adc1_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 1, 0,
+ adc2_switch, ARRAY_SIZE(adc2_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* MIC_BIAS widgets */
+ SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ wcd937x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ wcd937x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ wcd937x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* RX widgets */
+ SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0,
+ wcd937x_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0,
+ wcd937x_codec_enable_aux_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0,
+ wcd937x_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0,
+ wcd937x_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_aux_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux),
+
+ SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* RX mixer widgets*/
+ SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+ ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+ SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0,
+ aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+ hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+ hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+ /* TX output widgets */
+ SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("WCD_TX_OUTPUT"),
+
+ /* RX output widgets */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("AUX"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+
+ /* MIC_BIAS pull up widgets */
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ wcd937x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = {
+ /* Input widgets */
+ SND_SOC_DAPM_INPUT("AMIC4"),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0,
+ wcd937x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 0, 0,
+ NULL, 0, wcd937x_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0,
+ wcd937x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* TX mixer widgets */
+ SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0,
+ 0, dmic1_switch, ARRAY_SIZE(dmic1_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 1,
+ 0, dmic2_switch, ARRAY_SIZE(dmic2_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 2,
+ 0, dmic3_switch, ARRAY_SIZE(dmic3_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 3,
+ 0, dmic4_switch, ARRAY_SIZE(dmic4_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 4,
+ 0, dmic5_switch, ARRAY_SIZE(dmic5_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 5,
+ 0, dmic6_switch, ARRAY_SIZE(dmic6_switch),
+ wcd937x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 2, 0, adc3_switch,
+ ARRAY_SIZE(adc3_switch), wcd937x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Output widgets */
+ SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route wcd937x_audio_map[] = {
+ { "ADC1_OUTPUT", NULL, "ADC1_MIXER" },
+ { "ADC1_MIXER", "Switch", "ADC1 REQ" },
+ { "ADC1 REQ", NULL, "ADC1" },
+ { "ADC1", NULL, "AMIC1" },
+
+ { "ADC2_OUTPUT", NULL, "ADC2_MIXER" },
+ { "ADC2_MIXER", "Switch", "ADC2 REQ" },
+ { "ADC2 REQ", NULL, "ADC2" },
+ { "ADC2", NULL, "ADC2 MUX" },
+ { "ADC2 MUX", "INP3", "AMIC3" },
+ { "ADC2 MUX", "INP2", "AMIC2" },
+
+ { "IN1_HPHL", NULL, "VDD_BUCK" },
+ { "IN1_HPHL", NULL, "CLS_H_PORT" },
+ { "RX1", NULL, "IN1_HPHL" },
+ { "RDAC1", NULL, "RX1" },
+ { "HPHL_RDAC", "Switch", "RDAC1" },
+ { "HPHL PGA", NULL, "HPHL_RDAC" },
+ { "HPHL", NULL, "HPHL PGA" },
+
+ { "IN2_HPHR", NULL, "VDD_BUCK" },
+ { "IN2_HPHR", NULL, "CLS_H_PORT" },
+ { "RX2", NULL, "IN2_HPHR" },
+ { "RDAC2", NULL, "RX2" },
+ { "HPHR_RDAC", "Switch", "RDAC2" },
+ { "HPHR PGA", NULL, "HPHR_RDAC" },
+ { "HPHR", NULL, "HPHR PGA" },
+
+ { "IN3_AUX", NULL, "VDD_BUCK" },
+ { "IN3_AUX", NULL, "CLS_H_PORT" },
+ { "RX3", NULL, "IN3_AUX" },
+ { "RDAC4", NULL, "RX3" },
+ { "AUX_RDAC", "Switch", "RDAC4" },
+ { "AUX PGA", NULL, "AUX_RDAC" },
+ { "AUX", NULL, "AUX PGA" },
+
+ { "RDAC3_MUX", "RX3", "RX3" },
+ { "RDAC3_MUX", "RX1", "RX1" },
+ { "RDAC3", NULL, "RDAC3_MUX" },
+ { "EAR_RDAC", "Switch", "RDAC3" },
+ { "EAR PGA", NULL, "EAR_RDAC" },
+ { "EAR", NULL, "EAR PGA" },
+};
+
+static const struct snd_soc_dapm_route wcd9375_audio_map[] = {
+ { "ADC3_OUTPUT", NULL, "ADC3_MIXER" },
+ { "ADC3_OUTPUT", NULL, "ADC3_MIXER" },
+ { "ADC3_MIXER", "Switch", "ADC3 REQ" },
+ { "ADC3 REQ", NULL, "ADC3" },
+ { "ADC3", NULL, "AMIC4" },
+
+ { "DMIC1_OUTPUT", NULL, "DMIC1_MIXER" },
+ { "DMIC1_MIXER", "Switch", "DMIC1" },
+
+ { "DMIC2_OUTPUT", NULL, "DMIC2_MIXER" },
+ { "DMIC2_MIXER", "Switch", "DMIC2" },
+
+ { "DMIC3_OUTPUT", NULL, "DMIC3_MIXER" },
+ { "DMIC3_MIXER", "Switch", "DMIC3" },
+
+ { "DMIC4_OUTPUT", NULL, "DMIC4_MIXER" },
+ { "DMIC4_MIXER", "Switch", "DMIC4" },
+
+ { "DMIC5_OUTPUT", NULL, "DMIC5_MIXER" },
+ { "DMIC5_MIXER", "Switch", "DMIC5" },
+
+ { "DMIC6_OUTPUT", NULL, "DMIC6_MIXER" },
+ { "DMIC6_MIXER", "Switch", "DMIC6" },
+};
+
+static void wcd937x_set_micbias_data(struct device *dev, struct wcd937x_priv *wcd937x)
+{
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB1, WCD937X_ANA_MICB_VOUT,
+ wcd937x->common.micb_vout[0]);
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB2, WCD937X_ANA_MICB_VOUT,
+ wcd937x->common.micb_vout[1]);
+ regmap_update_bits(wcd937x->regmap, WCD937X_ANA_MICB3, WCD937X_ANA_MICB_VOUT,
+ wcd937x->common.micb_vout[2]);
+}
+
+static irqreturn_t wcd937x_wd_handle_irq(int irq, void *data)
+{
+ return IRQ_HANDLED;
+}
+
+static const struct irq_chip wcd_irq_chip = {
+ .name = "WCD937x",
+};
+
+static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq);
+ irq_set_nested_thread(virq, 1);
+ irq_set_noprobe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops wcd_domain_ops = {
+ .map = wcd_irq_chip_map,
+};
+
+static int wcd937x_irq_init(struct wcd937x_priv *wcd, struct device *dev)
+{
+ 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;
+ }
+
+ return devm_regmap_add_irq_chip(dev, wcd->regmap,
+ irq_create_mapping(wcd->virq, 0),
+ IRQF_ONESHOT, 0, &wcd937x_regmap_irq_chip,
+ &wcd->irq_chip);
+}
+
+static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+ struct sdw_slave *tx_sdw_dev = wcd937x->tx_sdw_dev;
+ struct device *dev = component->dev;
+ unsigned long time_left;
+ int i, ret;
+ u32 chipid;
+
+ time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete,
+ msecs_to_jiffies(5000));
+ if (!time_left) {
+ dev_err(dev, "soundwire device init timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ snd_soc_component_init_regmap(component, wcd937x->regmap);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ chipid = (snd_soc_component_read(component,
+ WCD937X_DIGITAL_EFUSE_REG_0) & 0x1e) >> 1;
+ if (chipid != CHIPID_WCD9370 && chipid != CHIPID_WCD9375) {
+ dev_err(dev, "Got unknown chip id: 0x%x\n", chipid);
+ pm_runtime_put(dev);
+ return -EINVAL;
+ }
+
+ wcd937x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD937X);
+ if (IS_ERR(wcd937x->clsh_info)) {
+ pm_runtime_put(dev);
+ return PTR_ERR(wcd937x->clsh_info);
+ }
+
+ wcd937x_io_init(wcd937x->regmap);
+ /* Set all interrupts as edge triggered */
+ for (i = 0; i < wcd937x_regmap_irq_chip.num_regs; i++)
+ regmap_write(wcd937x->regmap, (WCD937X_DIGITAL_INTR_LEVEL_0 + i), 0);
+
+ pm_runtime_put(dev);
+
+ wcd937x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHR_PDM_WD_INT);
+ wcd937x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_HPHL_PDM_WD_INT);
+ wcd937x->aux_pdm_wd_int = regmap_irq_get_virq(wcd937x->irq_chip,
+ WCD937X_IRQ_AUX_PDM_WD_INT);
+
+ /* Request for watchdog interrupt */
+ ret = devm_request_threaded_irq(dev, wcd937x->hphr_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHR PDM WDOG INT", wcd937x);
+ if (ret)
+ dev_err(dev, "Failed to request HPHR watchdog interrupt (%d)\n", ret);
+
+ ret = devm_request_threaded_irq(dev, wcd937x->hphl_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHL PDM WDOG INT", wcd937x);
+ if (ret)
+ dev_err(dev, "Failed to request HPHL watchdog interrupt (%d)\n", ret);
+
+ ret = devm_request_threaded_irq(dev, wcd937x->aux_pdm_wd_int, NULL, wcd937x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "AUX PDM WDOG INT", wcd937x);
+ if (ret)
+ dev_err(dev, "Failed to request Aux watchdog interrupt (%d)\n", ret);
+
+ /* Disable watchdog interrupt for HPH and AUX */
+ disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+ disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+ disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+
+ if (chipid == CHIPID_WCD9375) {
+ ret = snd_soc_dapm_new_controls(dapm, wcd9375_dapm_widgets,
+ 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;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, wcd9375_audio_map,
+ 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;
+ }
+ }
+
+ ret = wcd937x_mbhc_init(component);
+ if (ret)
+ dev_err(component->dev, "mbhc initialization failed\n");
+
+ return ret;
+}
+
+static void wcd937x_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+
+ wcd937x_mbhc_deinit(component);
+ free_irq(wcd937x->aux_pdm_wd_int, wcd937x);
+ free_irq(wcd937x->hphl_pdm_wd_int, wcd937x);
+ free_irq(wcd937x->hphr_pdm_wd_int, wcd937x);
+
+ wcd_clsh_ctrl_free(wcd937x->clsh_info);
+}
+
+static int wcd937x_codec_set_jack(struct snd_soc_component *comp,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct wcd937x_priv *wcd = dev_get_drvdata(comp->dev);
+ int ret = 0;
+
+ if (jack)
+ ret = wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack);
+ else
+ wcd_mbhc_stop(wcd->wcd_mbhc);
+
+ return ret;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_wcd937x = {
+ .name = "wcd937x_codec",
+ .probe = wcd937x_soc_codec_probe,
+ .remove = wcd937x_soc_codec_remove,
+ .controls = wcd937x_snd_controls,
+ .num_controls = ARRAY_SIZE(wcd937x_snd_controls),
+ .dapm_widgets = wcd937x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets),
+ .dapm_routes = wcd937x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wcd937x_audio_map),
+ .set_jack = wcd937x_codec_set_jack,
+ .endianness = 1,
+};
+
+static bool wcd937x_swap_gnd_mic(struct snd_soc_component *component)
+{
+ int value;
+ struct wcd937x_priv *wcd937x;
+
+ wcd937x = snd_soc_component_get_drvdata(component);
+
+ value = gpiod_get_value(wcd937x->us_euro_gpio);
+ gpiod_set_value(wcd937x->us_euro_gpio, !value);
+
+ return true;
+}
+
+static int wcd937x_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+ return wcd937x_sdw_hw_params(wcd, substream, params, dai);
+}
+
+static int wcd937x_codec_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+ return sdw_stream_remove_slave(wcd->sdev, wcd->sruntime);
+}
+
+static int wcd937x_codec_set_sdw_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+
+ wcd->sruntime = stream;
+
+ 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[] = {
+ [0] = {
+ .name = "wcd937x-sdw-rx",
+ .playback = {
+ .stream_name = "WCD AIF Playback",
+ .rates = WCD937X_RATES | WCD937X_FRAC_RATES,
+ .formats = WCD937X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd937x_sdw_dai_ops,
+ },
+ [1] = {
+ .name = "wcd937x-sdw-tx",
+ .capture = {
+ .stream_name = "WCD AIF Capture",
+ .rates = WCD937X_RATES,
+ .formats = WCD937X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd937x_sdw_dai_ops,
+ },
+};
+
+static int wcd937x_bind(struct device *dev)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+ int ret;
+
+ /* Give the SDW subdevices some more time to settle */
+ usleep_range(5000, 5010);
+
+ ret = component_bind_all(dev, wcd937x);
+ if (ret) {
+ dev_err(dev, "Slave bind failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ wcd937x->rxdev = of_sdw_find_device_by_node(wcd937x->rxnode);
+ if (!wcd937x->rxdev) {
+ dev_err(dev, "could not find slave with matching of node\n");
+ ret = -EINVAL;
+ goto err_component_unbind;
+ }
+
+ wcd937x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd937x->rxdev);
+ wcd937x->sdw_priv[AIF1_PB]->wcd937x = wcd937x;
+
+ wcd937x->txdev = of_sdw_find_device_by_node(wcd937x->txnode);
+ if (!wcd937x->txdev) {
+ dev_err(dev, "could not find txslave with matching of node\n");
+ ret = -EINVAL;
+ goto err_put_rxdev;
+ }
+
+ wcd937x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd937x->txdev);
+ wcd937x->sdw_priv[AIF1_CAP]->wcd937x = wcd937x;
+ wcd937x->tx_sdw_dev = dev_to_sdw_dev(wcd937x->txdev);
+ if (!wcd937x->tx_sdw_dev) {
+ dev_err(dev, "could not get txslave with matching of dev\n");
+ ret = -EINVAL;
+ goto err_put_txdev;
+ }
+
+ /*
+ * As TX is the main CSR reg interface, which should not be suspended first.
+ * expicilty add the dependency link
+ */
+ if (!device_link_add(wcd937x->rxdev, wcd937x->txdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "Could not devlink TX and RX\n");
+ ret = -EINVAL;
+ goto err_put_txdev;
+ }
+
+ if (!device_link_add(dev, wcd937x->txdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "Could not devlink WCD and TX\n");
+ ret = -EINVAL;
+ goto err_remove_link1;
+ }
+
+ if (!device_link_add(dev, wcd937x->rxdev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "Could not devlink WCD and RX\n");
+ ret = -EINVAL;
+ goto err_remove_link2;
+ }
+
+ wcd937x->regmap = wcd937x->sdw_priv[AIF1_CAP]->regmap;
+ if (!wcd937x->regmap) {
+ dev_err(dev, "could not get TX device regmap\n");
+ ret = -EINVAL;
+ goto err_remove_link3;
+ }
+
+ ret = wcd937x_irq_init(wcd937x, dev);
+ if (ret) {
+ dev_err(dev, "IRQ init failed: %d\n", ret);
+ goto err_remove_link3;
+ }
+
+ wcd937x->sdw_priv[AIF1_PB]->slave_irq = wcd937x->virq;
+ wcd937x->sdw_priv[AIF1_CAP]->slave_irq = wcd937x->virq;
+
+ wcd937x_set_micbias_data(dev, wcd937x);
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_wcd937x,
+ wcd937x_dais, ARRAY_SIZE(wcd937x_dais));
+ if (ret) {
+ dev_err(dev, "Codec registration failed\n");
+ goto err_remove_link3;
+ }
+
+ return ret;
+
+err_remove_link3:
+ device_link_remove(dev, wcd937x->rxdev);
+err_remove_link2:
+ device_link_remove(dev, wcd937x->txdev);
+err_remove_link1:
+ device_link_remove(wcd937x->rxdev, wcd937x->txdev);
+err_put_txdev:
+ put_device(wcd937x->txdev);
+err_put_rxdev:
+ put_device(wcd937x->rxdev);
+err_component_unbind:
+ component_unbind_all(dev, wcd937x);
+ return ret;
+}
+
+static void wcd937x_unbind(struct device *dev)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dev);
+
+ snd_soc_unregister_component(dev);
+ device_link_remove(dev, wcd937x->txdev);
+ device_link_remove(dev, wcd937x->rxdev);
+ device_link_remove(wcd937x->rxdev, wcd937x->txdev);
+ component_unbind_all(dev, wcd937x);
+ mutex_destroy(&wcd937x->micb_lock);
+ put_device(wcd937x->txdev);
+ put_device(wcd937x->rxdev);
+}
+
+static const struct component_master_ops wcd937x_comp_ops = {
+ .bind = wcd937x_bind,
+ .unbind = wcd937x_unbind,
+};
+
+static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x,
+ struct device *dev,
+ struct component_match **matchptr)
+{
+ struct device_node *np = dev->of_node;
+
+ wcd937x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0);
+ if (!wcd937x->rxnode) {
+ dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n");
+ return -ENODEV;
+ }
+ of_node_get(wcd937x->rxnode);
+ component_match_add_release(dev, matchptr, component_release_of,
+ component_compare_of, wcd937x->rxnode);
+
+ wcd937x->txnode = of_parse_phandle(np, "qcom,tx-device", 0);
+ if (!wcd937x->txnode) {
+ dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n");
+ return -ENODEV;
+ }
+ of_node_get(wcd937x->txnode);
+ component_match_add_release(dev, matchptr, component_release_of,
+ component_compare_of, wcd937x->txnode);
+
+ return 0;
+}
+
+static int wcd937x_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ struct device *dev = &pdev->dev;
+ struct wcd937x_priv *wcd937x;
+ struct wcd_mbhc_config *cfg;
+ int ret;
+
+ wcd937x = devm_kzalloc(dev, sizeof(*wcd937x), GFP_KERNEL);
+ if (!wcd937x)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, wcd937x);
+ mutex_init(&wcd937x->micb_lock);
+ wcd937x->common.dev = dev;
+ wcd937x->common.max_bias = 3;
+
+ wcd937x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd937x->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd937x->reset_gpio),
+ "failed to reset wcd gpio\n");
+
+ wcd937x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd937x->us_euro_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd937x->us_euro_gpio),
+ "us-euro swap Control GPIO not found\n");
+
+ cfg = &wcd937x->mbhc_cfg;
+ cfg->swap_gnd_mic = wcd937x_swap_gnd_mic;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd937x_supplies),
+ wcd937x_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
+
+ ret = wcd_dt_parse_micbias_info(&wcd937x->common);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get micbias\n");
+
+ cfg->mbhc_micbias = MIC_BIAS_2;
+ cfg->anc_micbias = MIC_BIAS_2;
+ cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
+ cfg->num_btn = WCD937X_MBHC_MAX_BUTTONS;
+ cfg->micb_mv = wcd937x->common.micb_mv[2];
+ cfg->linein_th = 5000;
+ cfg->hs_thr = 1700;
+ cfg->hph_thr = 50;
+
+ wcd_dt_parse_mbhc_data(dev, &wcd937x->mbhc_cfg);
+
+ ret = wcd937x_add_slave_components(wcd937x, dev, &match);
+ if (ret)
+ return ret;
+
+ wcd937x_reset(wcd937x);
+
+ ret = component_master_add_with_match(dev, &wcd937x_comp_ops, match);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+}
+
+static void wcd937x_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_master_del(&pdev->dev, &wcd937x_comp_ops);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id wcd937x_of_match[] = {
+ { .compatible = "qcom,wcd9370-codec" },
+ { .compatible = "qcom,wcd9375-codec" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wcd937x_of_match);
+#endif
+
+static struct platform_driver wcd937x_codec_driver = {
+ .probe = wcd937x_probe,
+ .remove = wcd937x_remove,
+ .driver = {
+ .name = "wcd937x_codec",
+ .of_match_table = of_match_ptr(wcd937x_of_match),
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(wcd937x_codec_driver);
+MODULE_DESCRIPTION("WCD937X Codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h
new file mode 100644
index 000000000000..3d0ba3cc0ee6
--- /dev/null
+++ b/sound/soc/codecs/wcd937x.h
@@ -0,0 +1,618 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _WCD937X_REGISTERS_H
+#define _WCD937X_REGISTERS_H
+
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include "wcd-common.h"
+
+#define WCD937X_BASE_ADDRESS 0x3000
+#define WCD937X_ANA_BIAS 0x3001
+#define WCD937X_ANA_RX_SUPPLIES 0x3008
+#define WCD937X_ANA_HPH 0x3009
+#define WCD937X_ANA_EAR 0x300A
+#define WCD937X_ANA_EAR_COMPANDER_CTL 0x300B
+#define WCD937X_EAR_GAIN_MASK GENMASK(6, 2)
+#define WCD937X_ANA_TX_CH1 0x300E
+#define WCD937X_ANA_TX_CH2 0x300F
+#define WCD937X_ANA_TX_CH3 0x3010
+#define WCD937X_ANA_TX_CH3_HPF 0x3011
+#define WCD937X_ANA_MICB1_MICB2_DSP_EN_LOGIC 0x3012
+#define WCD937X_ANA_MICB3_DSP_EN_LOGIC 0x3013
+#define WCD937X_ANA_MBHC_MECH 0x3014
+#define WCD937X_MBHC_L_DET_EN_MASK BIT(7)
+#define WCD937X_MBHC_L_DET_EN BIT(7)
+#define WCD937X_MBHC_GND_DET_EN_MASK BIT(6)
+#define WCD937X_MBHC_MECH_DETECT_TYPE_MASK BIT(5)
+#define WCD937X_MBHC_MECH_DETECT_TYPE_INS 1
+#define WCD937X_MBHC_HPHL_PLUG_TYPE_MASK BIT(4)
+#define WCD937X_MBHC_HPHL_PLUG_TYPE_NO 1
+#define WCD937X_MBHC_GND_PLUG_TYPE_MASK BIT(3)
+#define WCD937X_MBHC_GND_PLUG_TYPE_NO 1
+#define WCD937X_MBHC_HSL_PULLUP_COMP_EN BIT(2)
+#define WCD937X_MBHC_HSG_PULLUP_COMP_EN BIT(1)
+#define WCD937X_MBHC_HPHL_100K_TO_GND_EN BIT(0)
+#define WCD937X_ANA_MBHC_ELECT 0x3015
+#define WCD937X_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4)
+#define WCD937X_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4)
+#define WCD937X_ANA_MBHC_BD_ISRC_OFF 0
+#define WCD937X_ANA_MBHC_BIAS_EN_MASK BIT(0)
+#define WCD937X_ANA_MBHC_BIAS_EN BIT(0)
+#define WCD937X_ANA_MBHC_ZDET 0x3016
+#define WCD937X_ANA_MBHC_RESULT_1 0x3017
+#define WCD937X_ANA_MBHC_RESULT_2 0x3018
+#define WCD937X_ANA_MBHC_RESULT_3 0x3019
+#define WCD937X_MBHC_BTN_RESULT_MASK GENMASK(2, 0)
+#define WCD937X_ANA_MBHC_BTN0 0x301A
+#define WCD937X_MBHC_BTN_VTH_MASK GENMASK(7, 2)
+#define WCD937X_ANA_MBHC_BTN1 0x301B
+#define WCD937X_ANA_MBHC_BTN2 0x301C
+#define WCD937X_ANA_MBHC_BTN3 0x301D
+#define WCD937X_ANA_MBHC_BTN4 0x301E
+#define WCD937X_ANA_MBHC_BTN5 0x301F
+#define WCD937X_VTH_MASK GENMASK(7, 2)
+#define WCD937X_ANA_MBHC_BTN6 0x3020
+#define WCD937X_ANA_MBHC_BTN7 0x3021
+#define WCD937X_ANA_MICB1 0x3022
+#define WCD937X_MICB_VOUT_MASK GENMASK(5, 0)
+#define WCD937X_MICB_EN_MASK GENMASK(7, 6)
+#define WCD937X_MICB_DISABLE 0
+#define WCD937X_MICB_ENABLE 1
+#define WCD937X_MICB_PULL_UP 2
+#define WCD937X_MICB_PULL_DOWN 3
+#define WCD937X_ANA_MICB2 0x3023
+#define WCD937X_ANA_MICB2_ENABLE BIT(6)
+#define WCD937X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6)
+#define WCD937X_ANA_MICB2_VOUT_MASK GENMASK(5, 0)
+#define WCD937X_ANA_MICB2_RAMP 0x3024
+#define WCD937X_RAMP_EN_MASK BIT(7)
+#define WCD937X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2)
+#define WCD937X_ANA_MICB3 0x3025
+#define WCD937X_ANA_MICB_EN GENMASK(7, 6)
+#define WCD937X_MICB_DISABLE 0
+#define WCD937X_MICB_ENABLE 1
+#define WCD937X_MICB_PULL_UP 2
+#define WCD937X_ANA_MICB_VOUT GENMASK(5, 0)
+#define WCD937X_BIAS_CTL 0x3028
+#define WCD937X_BIAS_VBG_FINE_ADJ 0x3029
+#define WCD937X_LDOL_VDDCX_ADJUST 0x3040
+#define WCD937X_LDOL_DISABLE_LDOL 0x3041
+#define WCD937X_MBHC_CTL_CLK 0x3056
+#define WCD937X_MBHC_CTL_ANA 0x3057
+#define WCD937X_MBHC_CTL_SPARE_1 0x3058
+#define WCD937X_MBHC_CTL_SPARE_2 0x3059
+#define WCD937X_MBHC_CTL_BCS 0x305A
+#define WCD937X_MBHC_MOISTURE_DET_FSM_STATUS 0x305B
+#define WCD937X_MBHC_TEST_CTL 0x305C
+#define WCD937X_LDOH_MODE 0x3067
+#define WCD937X_LDOH_BIAS 0x3068
+#define WCD937X_LDOH_STB_LOADS 0x3069
+#define WCD937X_LDOH_SLOWRAMP 0x306A
+#define WCD937X_MICB1_TEST_CTL_1 0x306B
+#define WCD937X_MICB1_TEST_CTL_2 0x306C
+#define WCD937X_MICB1_TEST_CTL_3 0x306D
+#define WCD937X_MICB2_TEST_CTL_1 0x306E
+#define WCD937X_MICB2_TEST_CTL_2 0x306F
+#define WCD937X_MICB2_TEST_CTL_3 0x3070
+#define WCD937X_MICB3_TEST_CTL_1 0x3071
+#define WCD937X_MICB3_TEST_CTL_2 0x3072
+#define WCD937X_MICB3_TEST_CTL_3 0x3073
+#define WCD937X_TX_COM_ADC_VCM 0x3077
+#define WCD937X_TX_COM_BIAS_ATEST 0x3078
+#define WCD937X_TX_COM_ADC_INT1_IB 0x3079
+#define WCD937X_TX_COM_ADC_INT2_IB 0x307A
+#define WCD937X_TX_COM_TXFE_DIV_CTL 0x307B
+#define WCD937X_TX_COM_TXFE_DIV_START 0x307C
+#define WCD937X_TX_COM_TXFE_DIV_STOP_9P6M 0x307D
+#define WCD937X_TX_COM_TXFE_DIV_STOP_12P288M 0x307E
+#define WCD937X_TX_1_2_TEST_EN 0x307F
+#define WCD937X_TX_1_2_ADC_IB 0x3080
+#define WCD937X_TX_1_2_ATEST_REFCTL 0x3081
+#define WCD937X_TX_1_2_TEST_CTL 0x3082
+#define WCD937X_TX_1_2_TEST_BLK_EN 0x3083
+#define WCD937X_TX_1_2_TXFE_CLKDIV 0x3084
+#define WCD937X_TX_1_2_SAR2_ERR 0x3085
+#define WCD937X_TX_1_2_SAR1_ERR 0x3086
+#define WCD937X_TX_3_TEST_EN 0x3087
+#define WCD937X_TX_3_ADC_IB 0x3088
+#define WCD937X_TX_3_ATEST_REFCTL 0x3089
+#define WCD937X_TX_3_TEST_CTL 0x308A
+#define WCD937X_TX_3_TEST_BLK_EN 0x308B
+#define WCD937X_TX_3_TXFE_CLKDIV 0x308C
+#define WCD937X_TX_3_SPARE_MONO 0x308D
+#define WCD937X_TX_3_SAR1_ERR 0x308E
+#define WCD937X_CLASSH_MODE_1 0x3097
+#define WCD937X_CLASSH_MODE_2 0x3098
+#define WCD937X_CLASSH_MODE_3 0x3099
+#define WCD937X_CLASSH_CTRL_VCL_1 0x309A
+#define WCD937X_CLASSH_CTRL_VCL_2 0x309B
+#define WCD937X_CLASSH_CTRL_CCL_1 0x309C
+#define WCD937X_CLASSH_CTRL_CCL_2 0x309D
+#define WCD937X_CLASSH_CTRL_CCL_3 0x309E
+#define WCD937X_CLASSH_CTRL_CCL_4 0x309F
+#define WCD937X_CLASSH_CTRL_CCL_5 0x30A0
+#define WCD937X_CLASSH_BUCK_TMUX_A_D 0x30A1
+#define WCD937X_CLASSH_BUCK_SW_DRV_CNTL 0x30A2
+#define WCD937X_CLASSH_SPARE 0x30A3
+#define WCD937X_FLYBACK_EN 0x30A4
+#define WCD937X_FLYBACK_VNEG_CTRL_1 0x30A5
+#define WCD937X_FLYBACK_VNEG_CTRL_2 0x30A6
+#define WCD937X_FLYBACK_VNEG_CTRL_3 0x30A7
+#define WCD937X_FLYBACK_VNEG_CTRL_4 0x30A8
+#define WCD937X_FLYBACK_VNEG_CTRL_5 0x30A9
+#define WCD937X_FLYBACK_VNEG_CTRL_6 0x30AA
+#define WCD937X_FLYBACK_VNEG_CTRL_7 0x30AB
+#define WCD937X_FLYBACK_VNEG_CTRL_8 0x30AC
+#define WCD937X_FLYBACK_VNEG_CTRL_9 0x30AD
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_1 0x30AE
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_2 0x30AF
+#define WCD937X_FLYBACK_VNEGDAC_CTRL_3 0x30B0
+#define WCD937X_FLYBACK_CTRL_1 0x30B1
+#define WCD937X_FLYBACK_TEST_CTL 0x30B2
+#define WCD937X_RX_AUX_SW_CTL 0x30B3
+#define WCD937X_RX_PA_AUX_IN_CONN 0x30B4
+#define WCD937X_RX_TIMER_DIV 0x30B5
+#define WCD937X_RX_OCP_CTL 0x30B6
+#define WCD937X_RX_OCP_COUNT 0x30B7
+#define WCD937X_RX_BIAS_EAR_DAC 0x30B8
+#define WCD937X_RX_BIAS_EAR_AMP 0x30B9
+#define WCD937X_RX_BIAS_HPH_LDO 0x30BA
+#define WCD937X_RX_BIAS_HPH_PA 0x30BB
+#define WCD937X_RX_BIAS_HPH_RDACBUFF_CNP2 0x30BC
+#define WCD937X_RX_BIAS_HPH_RDAC_LDO 0x30BD
+#define WCD937X_RX_BIAS_HPH_CNP1 0x30BE
+#define WCD937X_RX_BIAS_HPH_LOWPOWER 0x30BF
+#define WCD937X_RX_BIAS_AUX_DAC 0x30C0
+#define WCD937X_RX_BIAS_AUX_AMP 0x30C1
+#define WCD937X_RX_BIAS_VNEGDAC_BLEEDER 0x30C2
+#define WCD937X_RX_BIAS_MISC 0x30C3
+#define WCD937X_RX_BIAS_BUCK_RST 0x30C4
+#define WCD937X_RX_BIAS_BUCK_VREF_ERRAMP 0x30C5
+#define WCD937X_RX_BIAS_FLYB_ERRAMP 0x30C6
+#define WCD937X_RX_BIAS_FLYB_BUFF 0x30C7
+#define WCD937X_RX_BIAS_FLYB_MID_RST 0x30C8
+#define WCD937X_HPH_L_STATUS 0x30C9
+#define WCD937X_HPH_R_STATUS 0x30CA
+#define WCD937X_HPH_CNP_EN 0x30CB
+#define WCD937X_HPH_CNP_WG_CTL 0x30CC
+#define WCD937X_HPH_CNP_WG_TIME 0x30CD
+#define WCD937X_HPH_OCP_CTL 0x30CE
+#define WCD937X_HPH_AUTO_CHOP 0x30CF
+#define WCD937X_HPH_CHOP_CTL 0x30D0
+#define WCD937X_HPH_PA_CTL1 0x30D1
+#define WCD937X_HPH_PA_CTL2 0x30D2
+#define WCD937X_HPHPA_GND_R_MASK BIT(6)
+#define WCD937X_HPHPA_GND_L_MASK BIT(4)
+#define WCD937X_HPH_L_EN 0x30D3
+#define WCD937X_HPH_L_TEST 0x30D4
+#define WCD937X_HPH_L_ATEST 0x30D5
+#define WCD937X_HPH_R_EN 0x30D6
+#define WCD937X_GAIN_SRC_SEL_MASK BIT(5)
+#define WCD937X_GAIN_SRC_SEL_REGISTER 1
+#define WCD937X_HPH_R_TEST 0x30D7
+#define WCD937X_HPH_R_ATEST 0x30D8
+#define WCD937X_HPH_RDAC_CLK_CTL1 0x30D9
+#define WCD937X_HPHPA_GND_OVR_MASK BIT(1)
+#define WCD937X_CHOP_CLK_EN_MASK BIT(7)
+#define WCD937X_HPH_RDAC_CLK_CTL2 0x30DA
+#define WCD937X_HPH_RDAC_LDO_CTL 0x30DB
+#define WCD937X_HPH_RDAC_CHOP_CLK_LP_CTL 0x30DC
+#define WCD937X_HPH_REFBUFF_UHQA_CTL 0x30DD
+#define WCD937X_HPH_REFBUFF_LP_CTL 0x30DE
+#define WCD937X_PREREF_FLIT_BYPASS_MASK BIT(0)
+#define WCD937X_HPH_L_DAC_CTL 0x30DF
+#define WCD937X_HPH_R_DAC_CTL 0x30E0
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_COMP_SEL 0x30E1
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_EN 0x30E2
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_MISC1 0x30E3
+#define WCD937X_HPH_SURGE_HPHLR_SURGE_STATUS 0x30E4
+#define WCD937X_EAR_EAR_EN_REG 0x30E9
+#define WCD937X_EAR_EAR_PA_CON 0x30EA
+#define WCD937X_EAR_EAR_SP_CON 0x30EB
+#define WCD937X_EAR_EAR_DAC_CON 0x30EC
+#define WCD937X_EAR_EAR_CNP_FSM_CON 0x30ED
+#define WCD937X_EAR_TEST_CTL 0x30EE
+#define WCD937X_EAR_STATUS_REG_1 0x30EF
+#define WCD937X_EAR_STATUS_REG_2 0x30F0
+#define WCD937X_ANA_NEW_PAGE_REGISTER 0x3100
+#define WCD937X_HPH_NEW_ANA_HPH2 0x3101
+#define WCD937X_HPH_NEW_ANA_HPH3 0x3102
+#define WCD937X_SLEEP_CTL 0x3103
+#define WCD937X_SLEEP_WATCHDOG_CTL 0x3104
+#define WCD937X_MBHC_NEW_ELECT_REM_CLAMP_CTL 0x311F
+#define WCD937X_MBHC_NEW_CTL_1 0x3120
+#define WCD937X_MBHC_CTL_RCO_EN_MASK BIT(7)
+#define WCD937X_MBHC_CTL_RCO_EN BIT(7)
+#define WCD937X_MBHC_BTN_DBNC_MASK GENMASK(1, 0)
+#define WCD937X_MBHC_BTN_DBNC_T_16_MS 0x2
+#define WCD937X_MBHC_NEW_CTL_2 0x3121
+#define WCD937X_MBHC_NEW_PLUG_DETECT_CTL 0x3122
+#define WCD937X_MBHC_NEW_ZDET_ANA_CTL 0x3123
+#define WCD937X_M_RTH_CTL_MASK GENMASK(3, 2)
+#define WCD937X_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0)
+#define WCD937X_MBHC_HS_VREF_1P5_V 0x1
+#define WCD937X_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6
+#define WCD937X_ZDET_RANGE_CTL_MASK GENMASK(3, 0)
+#define WCD937X_ZDET_MAXV_CTL_MASK GENMASK(6, 4)
+#define WCD937X_MBHC_NEW_ZDET_RAMP_CTL 0x3124
+#define WCD937X_MBHC_NEW_FSM_STATUS 0x3125
+#define WCD937X_MBHC_NEW_ADC_RESULT 0x3126
+#define WCD937X_TX_NEW_TX_CH2_SEL 0x3127
+#define WCD937X_AUX_AUXPA 0x3128
+#define WCD937X_AUXPA_CLK_EN_MASK BIT(4)
+#define WCD937X_AUXPA_CLK_EN_MASK BIT(4)
+#define WCD937X_LDORXTX_MODE 0x3129
+#define WCD937X_LDORXTX_CONFIG 0x312A
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_EN 0x312C
+#define WCD937X_DIE_CRACK_DIE_CRK_DET_OUT 0x312D
+#define WCD937X_HPH_NEW_INT_RDAC_GAIN_CTL 0x3132
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L 0x3133
+#define WCD937X_HPH_NEW_INT_RDAC_VREF_CTL 0x3134
+#define WCD937X_HPH_NEW_INT_RDAC_OVERRIDE_CTL 0x3135
+#define WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R 0x3136
+#define WCD937X_HPH_NEW_INT_PA_MISC1 0x3137
+#define WCD937X_HPH_NEW_INT_PA_MISC2 0x3138
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC 0x3139
+#define WCD937X_HPH_NEW_INT_HPH_TIMER1 0x313A
+#define WCD937X_HPH_NEW_INT_HPH_TIMER2 0x313B
+#define WCD937X_HPH_NEW_INT_HPH_TIMER3 0x313C
+#define WCD937X_HPH_NEW_INT_HPH_TIMER4 0x313D
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC2 0x313E
+#define WCD937X_HPH_NEW_INT_PA_RDAC_MISC3 0x313F
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI 0x3145
+#define WCD937X_RX_NEW_INT_HPH_RDAC_BIAS_ULP 0x3146
+#define WCD937X_RX_NEW_INT_HPH_RDAC_LDO_LP 0x3147
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL 0x31AF
+#define WCD937X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL 0x31B0
+#define WCD937X_MOISTURE_EN_POLLING_MASK BIT(2)
+#define WCD937X_HSDET_PULLUP_C_MASK GENMASK(4, 0)
+#define WCD937X_MBHC_NEW_INT_MECH_DET_CURRENT 0x31B1
+#define WCD937X_MBHC_NEW_INT_SPARE_2 0x31B2
+#define WCD937X_EAR_INT_NEW_EAR_CHOPPER_CON 0x31B7
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON1 0x31B8
+#define WCD937X_EAR_INT_NEW_CNP_VCM_CON2 0x31B9
+#define WCD937X_EAR_INT_NEW_EAR_DYNAMIC_BIAS 0x31BA
+#define WCD937X_AUX_INT_EN_REG 0x31BD
+#define WCD937X_AUX_INT_PA_CTRL 0x31BE
+#define WCD937X_AUX_INT_SP_CTRL 0x31BF
+#define WCD937X_AUX_INT_DAC_CTRL 0x31C0
+#define WCD937X_AUX_INT_CLK_CTRL 0x31C1
+#define WCD937X_AUX_INT_TEST_CTRL 0x31C2
+#define WCD937X_AUX_INT_STATUS_REG 0x31C3
+#define WCD937X_AUX_INT_MISC 0x31C4
+#define WCD937X_LDORXTX_INT_BIAS 0x31C5
+#define WCD937X_LDORXTX_INT_STB_LOADS_DTEST 0x31C6
+#define WCD937X_LDORXTX_INT_TEST0 0x31C7
+#define WCD937X_LDORXTX_INT_STARTUP_TIMER 0x31C8
+#define WCD937X_LDORXTX_INT_TEST1 0x31C9
+#define WCD937X_LDORXTX_INT_STATUS 0x31CA
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_1 0x31D0
+#define WCD937X_SLEEP_INT_WATCHDOG_CTL_2 0x31D1
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT1 0x31D3
+#define WCD937X_DIE_CRACK_INT_DIE_CRK_DET_INT2 0x31D4
+#define WCD937X_DIGITAL_PAGE_REGISTER 0x3400
+#define WCD937X_DIGITAL_CHIP_ID0 0x3401
+#define WCD937X_DIGITAL_CHIP_ID1 0x3402
+#define WCD937X_DIGITAL_CHIP_ID2 0x3403
+#define WCD937X_DIGITAL_CHIP_ID3 0x3404
+#define WCD937X_DIGITAL_CDC_RST_CTL 0x3406
+#define WCD937X_DIGITAL_TOP_CLK_CFG 0x3407
+#define WCD937X_DIGITAL_CDC_ANA_CLK_CTL 0x3408
+#define WCD937X_DIGITAL_CDC_DIG_CLK_CTL 0x3409
+#define WCD937X_DIGITAL_SWR_RST_EN 0x340A
+#define WCD937X_DIGITAL_CDC_PATH_MODE 0x340B
+#define WCD937X_DIGITAL_CDC_RX_RST 0x340C
+#define WCD937X_DIGITAL_CDC_RX0_CTL 0x340D
+#define WCD937X_DIGITAL_CDC_RX1_CTL 0x340E
+#define WCD937X_DIGITAL_CDC_RX2_CTL 0x340F
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA0 0x3410
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA1 0x3411
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA2 0x3412
+#define WCD937X_DIGITAL_DEM_BYPASS_DATA3 0x3413
+#define WCD937X_DIGITAL_CDC_COMP_CTL_0 0x3414
+#define WCD937X_DIGITAL_CDC_RX_DELAY_CTL 0x3417
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_0 0x3418
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A1_1 0x3419
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_0 0x341A
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A2_1 0x341B
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_0 0x341C
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A3_1 0x341D
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_0 0x341E
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A4_1 0x341F
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_0 0x3420
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A5_1 0x3421
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A6_0 0x3422
+#define WCD937X_DIGITAL_CDC_HPH_DSM_A7_0 0x3423
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_0 0x3424
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_1 0x3425
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_2 0x3426
+#define WCD937X_DIGITAL_CDC_HPH_DSM_C_3 0x3427
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R1 0x3428
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R2 0x3429
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R3 0x342A
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R4 0x342B
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R5 0x342C
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R6 0x342D
+#define WCD937X_DIGITAL_CDC_HPH_DSM_R7 0x342E
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_0 0x342F
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A1_1 0x3430
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_0 0x3431
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A2_1 0x3432
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_0 0x3433
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A3_1 0x3434
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_0 0x3435
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A4_1 0x3436
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_0 0x3437
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A5_1 0x3438
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A6_0 0x3439
+#define WCD937X_DIGITAL_CDC_AUX_DSM_A7_0 0x343A
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_0 0x343B
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_1 0x343C
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_2 0x343D
+#define WCD937X_DIGITAL_CDC_AUX_DSM_C_3 0x343E
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R1 0x343F
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R2 0x3440
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R3 0x3441
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R4 0x3442
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R5 0x3443
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R6 0x3444
+#define WCD937X_DIGITAL_CDC_AUX_DSM_R7 0x3445
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_0 0x3446
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_RX_1 0x3447
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_0 0x3448
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_1 0x3449
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_DSD_2 0x344A
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_0 0x344B
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_1 0x344C
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_DSD_2 0x344D
+#define WCD937X_DIGITAL_CDC_HPH_GAIN_CTL 0x344E
+#define WCD937X_DIGITAL_CDC_AUX_GAIN_CTL 0x344F
+#define WCD937X_DIGITAL_CDC_EAR_PATH_CTL 0x3450
+#define WCD937X_DIGITAL_CDC_SWR_CLH 0x3451
+#define WCD937X_DIGITAL_SWR_CLH_BYP 0x3452
+#define WCD937X_DIGITAL_CDC_TX0_CTL 0x3453
+#define WCD937X_DIGITAL_CDC_TX1_CTL 0x3454
+#define WCD937X_DIGITAL_CDC_TX2_CTL 0x3455
+#define WCD937X_DIGITAL_CDC_TX_RST 0x3456
+#define WCD937X_DIGITAL_CDC_REQ_CTL 0x3457
+#define WCD937X_DIGITAL_CDC_AMIC_CTL 0x345A
+#define WCD937X_DIGITAL_CDC_DMIC_CTL 0x345B
+#define WCD937X_DIGITAL_CDC_DMIC1_CTL 0x345C
+#define WCD937X_DIGITAL_CDC_DMIC2_CTL 0x345D
+#define WCD937X_DIGITAL_CDC_DMIC3_CTL 0x345E
+#define WCD937X_DIGITAL_EFUSE_CTL 0x345F
+#define WCD937X_DIGITAL_EFUSE_PRG_CTL 0x3460
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_0 0x3461
+#define WCD937X_DIGITAL_EFUSE_TEST_CTL_1 0x3462
+#define WCD937X_DIGITAL_EFUSE_T_DATA_0 0x3463
+#define WCD937X_DIGITAL_EFUSE_T_DATA_1 0x3464
+#define WCD937X_DIGITAL_PDM_WD_CTL0 0x3465
+#define WCD937X_DIGITAL_PDM_WD_CTL1 0x3466
+#define WCD937X_DIGITAL_PDM_WD_CTL2 0x3467
+#define WCD937X_DIGITAL_PDM_WD_CTL2_HOLD_OFF BIT(2)
+#define WCD937X_DIGITAL_PDM_WD_CTL2_TIMEOUT_SEL BIT(1)
+#define WCD937X_DIGITAL_PDM_WD_CTL2_EN BIT(0)
+#define WCD937X_DIGITAL_PDM_WD_CTL2_MASK GENMASK(2, 0)
+#define WCD937X_DIGITAL_INTR_MODE 0x346A
+#define WCD937X_DIGITAL_INTR_MASK_0 0x346B
+#define WCD937X_DIGITAL_INTR_MASK_1 0x346C
+#define WCD937X_DIGITAL_INTR_MASK_2 0x346D
+#define WCD937X_DIGITAL_INTR_STATUS_0 0x346E
+#define WCD937X_DIGITAL_INTR_STATUS_1 0x346F
+#define WCD937X_DIGITAL_INTR_STATUS_2 0x3470
+#define WCD937X_DIGITAL_INTR_CLEAR_0 0x3471
+#define WCD937X_DIGITAL_INTR_CLEAR_1 0x3472
+#define WCD937X_DIGITAL_INTR_CLEAR_2 0x3473
+#define WCD937X_DIGITAL_INTR_LEVEL_0 0x3474
+#define WCD937X_DIGITAL_INTR_LEVEL_1 0x3475
+#define WCD937X_DIGITAL_INTR_LEVEL_2 0x3476
+#define WCD937X_DIGITAL_INTR_SET_0 0x3477
+#define WCD937X_DIGITAL_INTR_SET_1 0x3478
+#define WCD937X_DIGITAL_INTR_SET_2 0x3479
+#define WCD937X_DIGITAL_INTR_TEST_0 0x347A
+#define WCD937X_DIGITAL_INTR_TEST_1 0x347B
+#define WCD937X_DIGITAL_INTR_TEST_2 0x347C
+#define WCD937X_DIGITAL_CDC_CONN_RX0_CTL 0x347F
+#define WCD937X_DIGITAL_CDC_CONN_RX1_CTL 0x3480
+#define WCD937X_DIGITAL_CDC_CONN_RX2_CTL 0x3481
+#define WCD937X_DIGITAL_CDC_CONN_TX_CTL 0x3482
+#define WCD937X_DIGITAL_LOOP_BACK_MODE 0x3483
+#define WCD937X_DIGITAL_SWR_DAC_TEST 0x3484
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_0 0x3485
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_0 0x3491
+#define WCD937X_DIGITAL_SWR_HM_TEST_RX_1 0x3492
+#define WCD937X_DIGITAL_SWR_HM_TEST_TX_1 0x3493
+#define WCD937X_DIGITAL_SWR_HM_TEST 0x3494
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX0 0x3495
+#define WCD937X_DIGITAL_PAD_CTL_PDM_RX1 0x3496
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX0 0x3497
+#define WCD937X_DIGITAL_PAD_CTL_PDM_TX1 0x3498
+#define WCD937X_DIGITAL_PAD_INP_DIS_0 0x3499
+#define WCD937X_DIGITAL_PAD_INP_DIS_1 0x349A
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_0 0x349B
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_1 0x349C
+#define WCD937X_DIGITAL_DRIVE_STRENGTH_2 0x349D
+#define WCD937X_DIGITAL_RX_DATA_EDGE_CTL 0x349E
+#define WCD937X_DIGITAL_TX_DATA_EDGE_CTL 0x349F
+#define WCD937X_DIGITAL_GPIO_MODE 0x34A0
+#define WCD937X_DIGITAL_PIN_CTL_OE 0x34A1
+#define WCD937X_DIGITAL_PIN_CTL_DATA_0 0x34A2
+#define WCD937X_DIGITAL_PIN_CTL_DATA_1 0x34A3
+#define WCD937X_DIGITAL_PIN_STATUS_0 0x34A4
+#define WCD937X_DIGITAL_PIN_STATUS_1 0x34A5
+#define WCD937X_DIGITAL_DIG_DEBUG_CTL 0x34A6
+#define WCD937X_DIGITAL_DIG_DEBUG_EN 0x34A7
+#define WCD937X_DIGITAL_ANA_CSR_DBG_ADD 0x34A8
+#define WCD937X_DIGITAL_ANA_CSR_DBG_CTL 0x34A9
+#define WCD937X_DIGITAL_SSP_DBG 0x34AA
+#define WCD937X_DIGITAL_MODE_STATUS_0 0x34AB
+#define WCD937X_DIGITAL_MODE_STATUS_1 0x34AC
+#define WCD937X_DIGITAL_SPARE_0 0x34AD
+#define WCD937X_DIGITAL_SPARE_1 0x34AE
+#define WCD937X_DIGITAL_SPARE_2 0x34AF
+#define WCD937X_DIGITAL_EFUSE_REG_0 0x34B0
+#define WCD937X_DIGITAL_EFUSE_REG_1 0x34B1
+#define WCD937X_DIGITAL_EFUSE_REG_2 0x34B2
+#define WCD937X_DIGITAL_EFUSE_REG_3 0x34B3
+#define WCD937X_DIGITAL_EFUSE_REG_4 0x34B4
+#define WCD937X_DIGITAL_EFUSE_REG_5 0x34B5
+#define WCD937X_DIGITAL_EFUSE_REG_6 0x34B6
+#define WCD937X_DIGITAL_EFUSE_REG_7 0x34B7
+#define WCD937X_DIGITAL_EFUSE_REG_8 0x34B8
+#define WCD937X_DIGITAL_EFUSE_REG_9 0x34B9
+#define WCD937X_DIGITAL_EFUSE_REG_10 0x34BA
+#define WCD937X_DIGITAL_EFUSE_REG_11 0x34BB
+#define WCD937X_DIGITAL_EFUSE_REG_12 0x34BC
+#define WCD937X_DIGITAL_EFUSE_REG_13 0x34BD
+#define WCD937X_DIGITAL_EFUSE_REG_14 0x34BE
+#define WCD937X_DIGITAL_EFUSE_REG_15 0x34BF
+#define WCD937X_DIGITAL_EFUSE_REG_16 0x34C0
+#define WCD937X_DIGITAL_EFUSE_REG_17 0x34C1
+#define WCD937X_DIGITAL_EFUSE_REG_18 0x34C2
+#define WCD937X_DIGITAL_EFUSE_REG_19 0x34C3
+#define WCD937X_DIGITAL_EFUSE_REG_20 0x34C4
+#define WCD937X_DIGITAL_EFUSE_REG_21 0x34C5
+#define WCD937X_DIGITAL_EFUSE_REG_22 0x34C6
+#define WCD937X_DIGITAL_EFUSE_REG_23 0x34C7
+#define WCD937X_DIGITAL_EFUSE_REG_24 0x34C8
+#define WCD937X_DIGITAL_EFUSE_REG_25 0x34C9
+#define WCD937X_DIGITAL_EFUSE_REG_26 0x34CA
+#define WCD937X_DIGITAL_EFUSE_REG_27 0x34CB
+#define WCD937X_DIGITAL_EFUSE_REG_28 0x34CC
+#define WCD937X_DIGITAL_EFUSE_REG_29 0x34CD
+#define WCD937X_DIGITAL_EFUSE_REG_30 0x34CE
+#define WCD937X_DIGITAL_EFUSE_REG_31 0x34CF
+#define WCD937X_MAX_REGISTER (WCD937X_DIGITAL_EFUSE_REG_31)
+
+#define WCD937X_MAX_MICBIAS 3
+#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,
+ WCD937X_ADC_2_3_PORT,
+ WCD937X_DMIC_0_3_MBHC_PORT,
+ WCD937X_DMIC_4_6_PORT,
+ WCD937X_MAX_TX_SWR_PORTS = WCD937X_DMIC_4_6_PORT,
+};
+
+enum wcd937x_rx_sdw_ports {
+ WCD937X_HPH_PORT = 1,
+ WCD937X_CLSH_PORT,
+ WCD937X_COMP_PORT,
+ WCD937X_LO_PORT,
+ WCD937X_DSD_PORT,
+ WCD937X_MAX_SWR_PORTS = WCD937X_DSD_PORT,
+};
+
+struct wcd937x_priv;
+struct wcd937x_sdw_priv {
+ struct sdw_slave *sdev;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
+ struct wcd_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;
+ struct regmap *regmap;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD937X_SDW)
+int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd,
+ struct snd_soc_dai *dai,
+ void *stream, int direction);
+int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+
+#else
+static inline int wcd937x_sdw_free(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int wcd937x_sdw_set_sdw_stream(struct wcd937x_sdw_priv *wcd,
+ struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int wcd937x_sdw_hw_params(struct wcd937x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+enum {
+ /* INTR_CTRL_INT_MASK_0 */
+ WCD937X_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+ WCD937X_IRQ_MBHC_BUTTON_RELEASE_DET,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_DET,
+ WCD937X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ WCD937X_IRQ_MBHC_SW_DET,
+ WCD937X_IRQ_HPHR_OCP_INT,
+ WCD937X_IRQ_HPHR_CNP_INT,
+ WCD937X_IRQ_HPHL_OCP_INT,
+
+ /* INTR_CTRL_INT_MASK_1 */
+ WCD937X_IRQ_HPHL_CNP_INT,
+ WCD937X_IRQ_EAR_CNP_INT,
+ WCD937X_IRQ_EAR_SCD_INT,
+ WCD937X_IRQ_AUX_CNP_INT,
+ WCD937X_IRQ_AUX_SCD_INT,
+ WCD937X_IRQ_HPHL_PDM_WD_INT,
+ WCD937X_IRQ_HPHR_PDM_WD_INT,
+ WCD937X_IRQ_AUX_PDM_WD_INT,
+
+ /* INTR_CTRL_INT_MASK_2 */
+ WCD937X_IRQ_LDORT_SCD_INT,
+ WCD937X_IRQ_MBHC_MOISTURE_INT,
+ WCD937X_IRQ_HPHL_SURGE_DET_INT,
+ WCD937X_IRQ_HPHR_SURGE_DET_INT,
+ WCD937X_NUM_IRQS,
+};
+
+enum wcd937x_tx_sdw_channels {
+ WCD937X_ADC1,
+ WCD937X_ADC2,
+ WCD937X_ADC3,
+ WCD937X_DMIC0,
+ WCD937X_DMIC1,
+ WCD937X_MBHC,
+ WCD937X_DMIC2,
+ WCD937X_DMIC3,
+ WCD937X_DMIC4,
+ WCD937X_DMIC5,
+ WCD937X_DMIC6,
+};
+
+enum wcd937x_rx_sdw_channels {
+ WCD937X_HPH_L,
+ WCD937X_HPH_R,
+ WCD937X_CLSH,
+ WCD937X_COMP_L,
+ WCD937X_COMP_R,
+ WCD937X_LO,
+ WCD937X_DSD_R,
+ WCD937X_DSD_L,
+};
+
+#endif
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index 5befae414636..8c8f39d04972 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -18,10 +18,9 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "wcd938x.h"
+#include "wcd-common.h"
-#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
-
-static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
+static const struct wcd_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
@@ -32,7 +31,7 @@ static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
};
-static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
+static const struct wcd_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
@@ -82,23 +81,6 @@ static struct sdw_dpn_prop wcd938x_dpn_prop[WCD938X_MAX_SWR_PORTS] = {
}
};
-struct device *wcd938x_sdw_device_get(struct device_node *np)
-{
- return bus_find_device_by_of_node(&sdw_bus_type, np);
-
-}
-EXPORT_SYMBOL_GPL(wcd938x_sdw_device_get);
-
-int wcd938x_swr_get_current_bank(struct sdw_slave *sdev)
-{
- int bank;
-
- bank = sdw_read(sdev, SDW_SCP_CTRL);
-
- return ((bank & 0x40) ? 1 : 0);
-}
-EXPORT_SYMBOL_GPL(wcd938x_swr_get_current_bank);
-
int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -158,44 +140,13 @@ int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd,
}
EXPORT_SYMBOL_GPL(wcd938x_sdw_set_sdw_stream);
-static int wcd9380_update_status(struct sdw_slave *slave,
- enum sdw_slave_status status)
-{
- struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
-
- if (wcd->regmap && (status == SDW_SLAVE_ATTACHED)) {
- /* Write out any cached changes that happened between probe and attach */
- regcache_cache_only(wcd->regmap, false);
- return regcache_sync(wcd->regmap);
- }
-
- return 0;
-}
-
-static int wcd9380_bus_config(struct sdw_slave *slave,
- struct sdw_bus_params *params)
-{
- sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01);
-
- return 0;
-}
-
static int wcd9380_interrupt_callback(struct sdw_slave *slave,
struct sdw_slave_intr_status *status)
{
struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
- struct irq_domain *slave_irq = wcd->slave_irq;
- u32 sts1, sts2, sts3;
-
- do {
- handle_nested_irq(irq_find_mapping(slave_irq, 0));
- regmap_read(wcd->regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1);
- regmap_read(wcd->regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2);
- regmap_read(wcd->regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3);
-
- } while (sts1 || sts2 || sts3);
- return IRQ_HANDLED;
+ return wcd_interrupt_callback(slave, wcd->slave_irq, WCD938X_DIGITAL_INTR_STATUS_0,
+ WCD938X_DIGITAL_INTR_STATUS_1, WCD938X_DIGITAL_INTR_STATUS_2);
}
static const struct reg_default wcd938x_defaults[] = {
@@ -1183,36 +1134,19 @@ static const struct regmap_config wcd938x_regmap_config = {
.name = "wcd938x_csr",
.reg_bits = 32,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wcd938x_defaults,
.num_reg_defaults = ARRAY_SIZE(wcd938x_defaults),
.max_register = WCD938X_MAX_REGISTER,
.readable_reg = wcd938x_readable_register,
.writeable_reg = wcd938x_writeable_register,
.volatile_reg = wcd938x_volatile_register,
- .can_multi_write = true,
};
static const struct sdw_slave_ops wcd9380_slave_ops = {
- .update_status = wcd9380_update_status,
+ .update_status = wcd_update_status,
.interrupt_callback = wcd9380_interrupt_callback,
- .bus_config = wcd9380_bus_config,
-};
-
-static int wcd938x_sdw_component_bind(struct device *dev,
- struct device *master, void *data)
-{
- return 0;
-}
-
-static void wcd938x_sdw_component_unbind(struct device *dev,
- struct device *master, void *data)
-{
-}
-
-static const struct component_ops wcd938x_sdw_component_ops = {
- .bind = wcd938x_sdw_component_bind,
- .unbind = wcd938x_sdw_component_unbind,
+ .bus_config = wcd_bus_config,
};
static int wcd9380_probe(struct sdw_slave *pdev,
@@ -1226,11 +1160,11 @@ static int wcd9380_probe(struct sdw_slave *pdev,
if (!wcd)
return -ENOMEM;
- /**
+ /*
* 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],
@@ -1253,12 +1187,12 @@ static int wcd9380_probe(struct sdw_slave *pdev,
pdev->prop.lane_control_support = true;
pdev->prop.simple_clk_stop_capable = true;
if (wcd->is_tx) {
- pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0);
+ pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS - 1, 0);
pdev->prop.src_dpn_prop = wcd938x_dpn_prop;
wcd->ch_info = &wcd938x_sdw_tx_ch_info[0];
pdev->prop.wake_capable = true;
} else {
- pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0);
+ pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS - 1, 0);
pdev->prop.sink_dpn_prop = wcd938x_dpn_prop;
wcd->ch_info = &wcd938x_sdw_rx_ch_info[0];
}
@@ -1273,13 +1207,23 @@ static int wcd9380_probe(struct sdw_slave *pdev,
regcache_cache_only(wcd->regmap, true);
}
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ ret = component_add(dev, &wcd_sdw_component_ops);
+ if (ret)
+ return ret;
+
+ /* Set suspended until aggregate device is bind */
+ pm_runtime_set_suspended(dev);
+
+ return 0;
+}
- return component_add(dev, &wcd938x_sdw_component_ops);
+static int wcd9380_remove(struct sdw_slave *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_del(dev, &wcd_sdw_component_ops);
+
+ return 0;
}
static const struct sdw_device_id wcd9380_slave_id[] = {
@@ -1288,7 +1232,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);
@@ -1300,7 +1244,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);
@@ -1315,17 +1259,18 @@ 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)
};
static struct sdw_driver wcd9380_codec_driver = {
.probe = wcd9380_probe,
+ .remove = wcd9380_remove,
.ops = &wcd9380_slave_ops,
.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 e7d6a02cdec0..f5b7de2bc896 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -11,7 +11,6 @@
#include <linux/pm_runtime.h>
#include <linux/component.h>
#include <sound/tlv.h>
-#include <linux/of_gpio.h>
#include <linux/of.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -19,17 +18,20 @@
#include <linux/regmap.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <linux/mux/consumer.h>
#include <linux/regulator/consumer.h>
#include "wcd-clsh-v2.h"
+#include "wcd-common.h"
#include "wcd-mbhc-v2.h"
#include "wcd938x.h"
+#define CHIPID_WCD9380 0x0
+#define CHIPID_WCD9385 0x5
+
#define WCD938X_MAX_MICBIAS (4)
-#define WCD938X_MAX_SUPPLY (4)
#define WCD938X_MBHC_MAX_BUTTONS (8)
#define TX_ADC_MAX (4)
-#define WCD938X_TX_MAX_SWR_PORTS (5)
#define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
@@ -39,8 +41,6 @@
SNDRV_PCM_RATE_176400)
#define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
-/* Convert from vout ctl to micbias voltage in mV */
-#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50)
#define SWR_CLK_RATE_0P6MHZ (600000)
#define SWR_CLK_RATE_1P2MHZ (1200000)
#define SWR_CLK_RATE_2P4MHZ (2400000)
@@ -48,8 +48,6 @@
#define SWR_CLK_RATE_9P6MHZ (9600000)
#define SWR_CLK_RATE_11P2896MHZ (1128960)
-#define WCD938X_DRV_NAME "wcd938x_codec"
-#define WCD938X_VERSION_1_0 (1)
#define EAR_RX_PATH_AUX (1)
#define ADC_MODE_VAL_HIFI 0x01
@@ -72,34 +70,11 @@
/* Z value compared in milliOhm */
#define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
#define WCD938X_MBHC_ZDET_CONST (86 * 16384)
-#define WCD938X_MBHC_MOISTURE_RREF R_24_KOHM
#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) }
-
-enum {
- WCD9380 = 0,
- WCD9385 = 5,
-};
-
-enum {
- TX_HDR12 = 0,
- TX_HDR34,
- TX_HDR_MAX,
-};
-
-enum {
- WCD_RX1,
- WCD_RX2,
- WCD_RX3
-};
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, snd_soc_get_volsw, \
+ wcd938x_ear_pa_put_gain, tlv_array)
enum {
/* INTR_CTRL_INT_MASK_0 */
@@ -181,10 +156,9 @@ struct wcd938x_priv {
struct wcd_mbhc_config mbhc_cfg;
struct wcd_mbhc_intr intr_ids;
struct wcd_clsh_ctrl *clsh_info;
+ struct wcd_common common;
struct irq_domain *virq;
- struct regmap_irq_chip *wcd_regmap_irq_chip;
struct regmap_irq_chip_data *irq_chip;
- struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY];
struct snd_soc_jack *jack;
unsigned long status_mask;
s32 micb_ref[WCD938X_MAX_MICBIAS];
@@ -193,24 +167,25 @@ struct wcd938x_priv {
u32 tx_mode[TX_ADC_MAX];
int flyback_cur_det_disable;
int ear_rx_path;
- int variant;
- int reset_gpio;
+ struct gpio_desc *reset_gpio;
struct gpio_desc *us_euro_gpio;
- u32 micb1_mv;
- u32 micb2_mv;
- u32 micb3_mv;
- u32 micb4_mv;
+ struct mux_control *us_euro_mux;
+ unsigned int mux_state;
int hphr_pdm_wd_int;
int hphl_pdm_wd_int;
int aux_pdm_wd_int;
bool comp1_enable;
bool comp2_enable;
bool ldoh;
- bool bcs_dis;
+ bool mux_setup_done;
+};
+
+static const char * const wcd938x_supplies[] = {
+ "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias",
};
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
-static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000);
+static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000);
struct wcd938x_mbhc_zdet_param {
@@ -222,7 +197,7 @@ struct wcd938x_mbhc_zdet_param {
u16 btn7;
};
-static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD938X_ANA_MBHC_MECH, 0x80),
WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD938X_ANA_MBHC_MECH, 0x40),
WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD938X_ANA_MBHC_MECH, 0x20),
@@ -296,7 +271,7 @@ static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = {
REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
};
-static struct regmap_irq_chip wcd938x_regmap_irq_chip = {
+static const struct regmap_irq_chip wcd938x_regmap_irq_chip = {
.name = "wcd938x",
.irqs = wcd938x_irqs,
.num_irqs = ARRAY_SIZE(wcd938x_irqs),
@@ -419,7 +394,7 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
}
-static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
+static int wcd938x_sdw_connect_port(const struct wcd_sdw_ch_info *ch_info,
struct sdw_port_config *port_config,
u8 enable)
{
@@ -1117,8 +1092,7 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w,
int bank;
int rate;
- bank = (wcd938x_swr_get_current_bank(wcd938x->sdw_priv[AIF1_CAP]->sdev)) ? 0 : 1;
- bank = bank ? 0 : 1;
+ bank = sdw_slave_get_current_bank(wcd938x->sdw_priv[AIF1_CAP]->sdev);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1505,7 +1479,7 @@ static int wcd938x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -1518,7 +1492,7 @@ static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol,
static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
@@ -1534,7 +1508,7 @@ static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wcd938x->hph_mode;
@@ -1545,7 +1519,7 @@ static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0])
@@ -1559,7 +1533,7 @@ static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
if (wcd938x->comp1_enable) {
@@ -1578,7 +1552,7 @@ static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc;
bool hphr;
@@ -1597,7 +1571,7 @@ static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
struct wcd938x_sdw_priv *wcd;
int value = ucontrol->value.integer.value[0];
@@ -1628,7 +1602,7 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wcd938x->ldoh;
@@ -1639,7 +1613,7 @@ static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol,
static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
if (wcd938x->ldoh == ucontrol->value.integer.value[0])
@@ -1650,31 +1624,6 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
- ucontrol->value.integer.value[0] = wcd938x->bcs_dis;
-
- return 0;
-}
-
-static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
-
- if (wcd938x->bcs_dis == ucontrol->value.integer.value[0])
- return 0;
-
- wcd938x->bcs_dis = ucontrol->value.integer.value[0];
-
- return 1;
-}
-
static const char * const tx_mode_mux_text_wcd9380[] = {
"ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
};
@@ -1894,7 +1843,7 @@ static const struct snd_kcontrol_new wcd9385_snd_controls[] = {
static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(comp);
struct wcd938x_sdw_priv *wcd;
struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
@@ -1913,7 +1862,7 @@ static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol,
static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(comp);
struct wcd938x_sdw_priv *wcd;
struct soc_mixer_control *mixer =
@@ -1982,7 +1931,7 @@ static bool wcd938x_mbhc_micb_en_status(struct snd_soc_component *component, int
if (micb_num == MIC_BIAS_2) {
val = snd_soc_component_read_field(component,
WCD938X_ANA_MICB2,
- WCD938X_ANA_MICB2_ENABLE_MASK);
+ WCD938X_MICB_EN_MASK);
if (val == WCD938X_MICB_ENABLE)
return true;
}
@@ -2023,15 +1972,6 @@ static void wcd938x_mbhc_micb_ramp_control(struct snd_soc_component *component,
}
}
-static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv)
-{
- /* min micbias voltage is 1V and maximum is 2.85V */
- if (micb_mv < 1000 || micb_mv > 2850)
- return -EINVAL;
-
- return (micb_mv - 1000) / 50;
-}
-
static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
@@ -2068,7 +2008,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
WCD938X_MICB_VOUT_MASK);
- req_vout_ctl = wcd938x_get_micb_vout_ctl_val(req_volt);
+ req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
if (req_vout_ctl < 0) {
ret = -EINVAL;
goto exit;
@@ -2116,18 +2056,19 @@ static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon
* voltage needed to detect threshold microphone, then do
* not change the micbias, just return.
*/
- if (wcd938x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
+ if (wcd938x->common.micb_mv[2] >= WCD_MBHC_THR_HS_MICB_MV)
return 0;
- micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd938x->micb2_mv;
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd938x->common.micb_mv[2];
return wcd938x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
}
-static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x,
+static void wcd938x_mbhc_get_result_params(struct snd_soc_component *component,
s16 *d1_a, u16 noff,
int32_t *zdet)
{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
int i;
int val, val1;
s16 c1;
@@ -2154,8 +2095,8 @@ static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x,
usleep_range(5000, 5050);
if (!c1 || !x1) {
- pr_err("%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
- __func__, c1, x1);
+ dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ c1, x1);
goto ramp_down;
}
d1 = d1_a[c1];
@@ -2165,7 +2106,7 @@ static inline void wcd938x_mbhc_get_result_params(struct wcd938x_priv *wcd938x,
else if (x1 < minCode_param[noff])
*zdet = WCD938X_ZDET_FLOATING_IMPEDANCE;
- pr_err("%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+ dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n",
__func__, d1, c1, x1, *zdet);
ramp_down:
i = 0;
@@ -2210,7 +2151,7 @@ static void wcd938x_mbhc_zdet_ramp(struct snd_soc_component *component,
WCD938X_ANA_MBHC_ZDET, 0x80, 0x80);
dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n",
__func__, zdet_param->noff);
- wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet);
+ wcd938x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
regmap_update_bits(wcd938x->regmap,
WCD938X_ANA_MBHC_ZDET, 0x80, 0x00);
@@ -2224,15 +2165,15 @@ z_right:
WCD938X_ANA_MBHC_ZDET, 0x40, 0x40);
dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n",
__func__, zdet_param->noff);
- wcd938x_mbhc_get_result_params(wcd938x, d1_a, zdet_param->noff, &zdet);
+ wcd938x_mbhc_get_result_params(component, d1_a, zdet_param->noff, &zdet);
regmap_update_bits(wcd938x->regmap,
WCD938X_ANA_MBHC_ZDET, 0x40, 0x00);
*zr = zdet;
}
-static inline void wcd938x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
- int32_t *z_val, int flag_l_r)
+static void wcd938x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+ int32_t *z_val, int flag_l_r)
{
s16 q1;
int q1_cal;
@@ -2565,7 +2506,7 @@ static const struct wcd_mbhc_cb mbhc_cb = {
static int wcd938x_get_hph_type(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd938x->wcd_mbhc);
@@ -2579,8 +2520,7 @@ static int wcd938x_hph_impedance_get(struct snd_kcontrol *kcontrol,
uint32_t zl, zr;
bool hphr;
struct soc_mixer_control *mc;
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
mc = (struct soc_mixer_control *)(kcontrol->private_value);
@@ -2625,6 +2565,8 @@ static int wcd938x_mbhc_init(struct snd_soc_component *component)
WCD938X_IRQ_HPHR_OCP_INT);
wcd938x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+ if (IS_ERR(wcd938x->wcd_mbhc))
+ return PTR_ERR(wcd938x->wcd_mbhc);
snd_soc_add_component_controls(component, impedance_detect_controls,
ARRAY_SIZE(impedance_detect_controls));
@@ -2633,6 +2575,14 @@ static int wcd938x_mbhc_init(struct snd_soc_component *component)
return 0;
}
+
+static void wcd938x_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ wcd_mbhc_deinit(wcd938x->wcd_mbhc);
+}
+
/* END MBHC */
static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
@@ -2652,8 +2602,8 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
wcd938x_get_swr_port, wcd938x_set_swr_port),
SOC_SINGLE_EXT("DSD_R Switch", WCD938X_DSD_R, 0, 1, 0,
wcd938x_get_swr_port, wcd938x_set_swr_port),
- SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 0x18, 0, line_gain),
- SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 0x18, 0, line_gain),
+ SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 0x18, 1, line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 0x18, 1, line_gain),
WCD938X_EAR_PA_GAIN_TLV("EAR_PA Volume", WCD938X_ANA_EAR_COMPANDER_CTL,
2, 0x10, 0, ear_pa_gain),
SOC_SINGLE_EXT("ADC1 Switch", WCD938X_ADC1, 1, 1, 0,
@@ -2684,8 +2634,6 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = {
wcd938x_get_swr_port, wcd938x_set_swr_port),
SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0,
wcd938x_ldoh_get, wcd938x_ldoh_put),
- SOC_SINGLE_EXT("ADC2_BCS Disable Switch", SND_SOC_NOPM, 0, 1, 0,
- wcd938x_bcs_get, wcd938x_bcs_put),
SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain),
SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain),
@@ -3015,28 +2963,16 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = {
{"EAR", NULL, "EAR PGA"},
};
-static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x)
+static void wcd938x_set_micbias_data(struct device *dev, struct wcd938x_priv *wcd938x)
{
- int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
-
- /* set micbias voltage */
- vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb1_mv);
- vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb2_mv);
- vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb3_mv);
- vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb4_mv);
- if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0)
- return -EINVAL;
-
regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB1,
- WCD938X_MICB_VOUT_MASK, vout_ctl_1);
+ WCD938X_MICB_VOUT_MASK, wcd938x->common.micb_vout[0]);
regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB2,
- WCD938X_MICB_VOUT_MASK, vout_ctl_2);
+ WCD938X_MICB_VOUT_MASK, wcd938x->common.micb_vout[1]);
regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB3,
- WCD938X_MICB_VOUT_MASK, vout_ctl_3);
+ WCD938X_MICB_VOUT_MASK, wcd938x->common.micb_vout[2]);
regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB4,
- WCD938X_MICB_VOUT_MASK, vout_ctl_4);
-
- return 0;
+ WCD938X_MICB_VOUT_MASK, wcd938x->common.micb_vout[3]);
}
static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data)
@@ -3044,7 +2980,7 @@ static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static struct irq_chip wcd_irq_chip = {
+static const struct irq_chip wcd_irq_chip = {
.name = "WCD938x",
};
@@ -3065,7 +3001,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;
@@ -3080,16 +3016,34 @@ static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev)
static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
{
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ struct sdw_slave *tx_sdw_dev = wcd938x->tx_sdw_dev;
struct device *dev = component->dev;
+ unsigned long time_left;
+ unsigned int variant;
int ret, i;
+ time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete,
+ msecs_to_jiffies(2000));
+ if (!time_left) {
+ dev_err(dev, "soundwire device init timeout\n");
+ return -ETIMEDOUT;
+ }
+
snd_soc_component_init_regmap(component, wcd938x->regmap);
- wcd938x->variant = snd_soc_component_read_field(component,
- WCD938X_DIGITAL_EFUSE_REG_0,
- WCD938X_ID_MASK);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ variant = snd_soc_component_read_field(component,
+ WCD938X_DIGITAL_EFUSE_REG_0,
+ WCD938X_ID_MASK);
wcd938x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD938X);
+ if (IS_ERR(wcd938x->clsh_info)) {
+ pm_runtime_put(dev);
+ return PTR_ERR(wcd938x->clsh_info);
+ }
wcd938x_io_init(wcd938x);
/* Set all interrupts as edge triggered */
@@ -3098,6 +3052,8 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
(WCD938X_DIGITAL_INTR_LEVEL_0 + i), 0);
}
+ pm_runtime_put(dev);
+
wcd938x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip,
WCD938X_IRQ_HPHR_PDM_WD_INT);
wcd938x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip,
@@ -3109,45 +3065,51 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
ret = request_threaded_irq(wcd938x->hphr_pdm_wd_int, NULL, wcd938x_wd_handle_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"HPHR PDM WD INT", wcd938x);
- if (ret)
+ if (ret) {
dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret);
+ goto err_free_clsh_ctrl;
+ }
ret = request_threaded_irq(wcd938x->hphl_pdm_wd_int, NULL, wcd938x_wd_handle_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"HPHL PDM WD INT", wcd938x);
- if (ret)
+ if (ret) {
dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret);
+ goto err_free_hphr_pdm_wd_int;
+ }
ret = request_threaded_irq(wcd938x->aux_pdm_wd_int, NULL, wcd938x_wd_handle_irq,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"AUX PDM WD INT", wcd938x);
- if (ret)
+ if (ret) {
dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret);
+ goto err_free_hphl_pdm_wd_int;
+ }
/* Disable watchdog interrupt for HPH and AUX */
disable_irq_nosync(wcd938x->hphr_pdm_wd_int);
disable_irq_nosync(wcd938x->hphl_pdm_wd_int);
disable_irq_nosync(wcd938x->aux_pdm_wd_int);
- switch (wcd938x->variant) {
- case WCD9380:
+ switch (variant) {
+ case CHIPID_WCD9380:
ret = snd_soc_add_component_controls(component, wcd9380_snd_controls,
ARRAY_SIZE(wcd9380_snd_controls));
if (ret < 0) {
dev_err(component->dev,
"%s: Failed to add snd ctrls for variant: %d\n",
- __func__, wcd938x->variant);
- goto err;
+ __func__, variant);
+ goto err_free_aux_pdm_wd_int;
}
break;
- case WCD9385:
+ case CHIPID_WCD9385:
ret = snd_soc_add_component_controls(component, wcd9385_snd_controls,
ARRAY_SIZE(wcd9385_snd_controls));
if (ret < 0) {
dev_err(component->dev,
"%s: Failed to add snd ctrls for variant: %d\n",
- __func__, wcd938x->variant);
- goto err;
+ __func__, variant);
+ goto err_free_aux_pdm_wd_int;
}
break;
default:
@@ -3155,12 +3117,38 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
}
ret = wcd938x_mbhc_init(component);
- if (ret)
+ if (ret) {
dev_err(component->dev, "mbhc initialization failed\n");
-err:
+ goto err_free_aux_pdm_wd_int;
+ }
+
+ return 0;
+
+err_free_aux_pdm_wd_int:
+ free_irq(wcd938x->aux_pdm_wd_int, wcd938x);
+err_free_hphl_pdm_wd_int:
+ free_irq(wcd938x->hphl_pdm_wd_int, wcd938x);
+err_free_hphr_pdm_wd_int:
+ free_irq(wcd938x->hphr_pdm_wd_int, wcd938x);
+err_free_clsh_ctrl:
+ wcd_clsh_ctrl_free(wcd938x->clsh_info);
+
return ret;
}
+static void wcd938x_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+
+ wcd938x_mbhc_deinit(component);
+
+ free_irq(wcd938x->aux_pdm_wd_int, wcd938x);
+ free_irq(wcd938x->hphl_pdm_wd_int, wcd938x);
+ free_irq(wcd938x->hphr_pdm_wd_int, wcd938x);
+
+ wcd_clsh_ctrl_free(wcd938x->clsh_info);
+}
+
static int wcd938x_codec_set_jack(struct snd_soc_component *comp,
struct snd_soc_jack *jack, void *data)
{
@@ -3177,6 +3165,7 @@ static int wcd938x_codec_set_jack(struct snd_soc_component *comp,
static const struct snd_soc_component_driver soc_codec_dev_wcd938x = {
.name = "wcd938x_codec",
.probe = wcd938x_soc_codec_probe,
+ .remove = wcd938x_soc_codec_remove,
.controls = wcd938x_snd_controls,
.num_controls = ARRAY_SIZE(wcd938x_snd_controls),
.dapm_widgets = wcd938x_dapm_widgets,
@@ -3187,48 +3176,28 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd938x = {
.endianness = 1,
};
-static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd)
-{
- struct device_node *np = dev->of_node;
- u32 prop_val = 0;
- int rc = 0;
-
- rc = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val);
- if (!rc)
- wcd->micb1_mv = prop_val/1000;
- else
- dev_info(dev, "%s: Micbias1 DT property not found\n", __func__);
-
- rc = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val);
- if (!rc)
- wcd->micb2_mv = prop_val/1000;
- else
- dev_info(dev, "%s: Micbias2 DT property not found\n", __func__);
-
- rc = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val);
- if (!rc)
- wcd->micb3_mv = prop_val/1000;
- else
- dev_info(dev, "%s: Micbias3 DT property not found\n", __func__);
-
- rc = of_property_read_u32(np, "qcom,micbias4-microvolt", &prop_val);
- if (!rc)
- wcd->micb4_mv = prop_val/1000;
- else
- dev_info(dev, "%s: Micbias4 DT property not found\n", __func__);
-}
-
-static bool wcd938x_swap_gnd_mic(struct snd_soc_component *component, bool active)
+static bool wcd938x_swap_gnd_mic(struct snd_soc_component *component)
{
- int value;
-
- struct wcd938x_priv *wcd938x;
+ struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+ int ret;
- wcd938x = snd_soc_component_get_drvdata(component);
+ if (wcd938x->us_euro_mux) {
+ if (wcd938x->mux_setup_done)
+ mux_control_deselect(wcd938x->us_euro_mux);
- value = gpiod_get_value(wcd938x->us_euro_gpio);
+ ret = mux_control_try_select(wcd938x->us_euro_mux, !wcd938x->mux_state);
+ if (ret) {
+ dev_err(dev, "Error (%d) Unable to select us/euro mux state\n", ret);
+ wcd938x->mux_setup_done = false;
+ return false;
+ }
+ wcd938x->mux_setup_done = true;
+ } else {
+ gpiod_set_value(wcd938x->us_euro_gpio, !wcd938x->mux_state);
+ }
- gpiod_set_value(wcd938x->us_euro_gpio, !value);
+ wcd938x->mux_state = !wcd938x->mux_state;
return true;
}
@@ -3239,39 +3208,47 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
struct wcd_mbhc_config *cfg = &wcd938x->mbhc_cfg;
int ret;
- wcd938x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
- if (wcd938x->reset_gpio < 0)
- return dev_err_probe(dev, wcd938x->reset_gpio,
+ wcd938x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd938x->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd938x->reset_gpio),
"Failed to get reset gpio\n");
- wcd938x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro",
- GPIOD_OUT_LOW);
- if (IS_ERR(wcd938x->us_euro_gpio))
- return dev_err_probe(dev, PTR_ERR(wcd938x->us_euro_gpio),
- "us-euro swap Control GPIO not found\n");
+ if (of_property_present(dev->of_node, "mux-controls")) {
+ wcd938x->us_euro_mux = devm_mux_control_get(dev, NULL);
+ if (IS_ERR(wcd938x->us_euro_mux)) {
+ ret = PTR_ERR(wcd938x->us_euro_mux);
+ return dev_err_probe(dev, ret, "failed to get mux control\n");
+ }
- cfg->swap_gnd_mic = wcd938x_swap_gnd_mic;
+ ret = mux_control_try_select(wcd938x->us_euro_mux, wcd938x->mux_state);
+ if (ret) {
+ dev_err(dev, "Error (%d) Unable to select us/euro mux state\n", ret);
+ return ret;
+ }
+ wcd938x->mux_setup_done = true;
+ } else {
+ wcd938x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd938x->us_euro_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd938x->us_euro_gpio),
+ "us-euro swap Control GPIO not found\n");
+ }
- wcd938x->supplies[0].supply = "vdd-rxtx";
- wcd938x->supplies[1].supply = "vdd-io";
- wcd938x->supplies[2].supply = "vdd-buck";
- wcd938x->supplies[3].supply = "vdd-mic-bias";
+ cfg->swap_gnd_mic = wcd938x_swap_gnd_mic;
- ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, wcd938x->supplies);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd938x_supplies),
+ wcd938x_supplies);
if (ret)
- return dev_err_probe(dev, ret, "Failed to get supplies\n");
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
- ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies);
+ ret = wcd_dt_parse_micbias_info(&wcd938x->common);
if (ret)
- return dev_err_probe(dev, ret, "Failed to enable supplies\n");
-
- wcd938x_dt_parse_micbias_info(dev, wcd938x);
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
cfg->mbhc_micbias = MIC_BIAS_2;
cfg->anc_micbias = MIC_BIAS_2;
cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
cfg->num_btn = WCD938X_MBHC_MAX_BUTTONS;
- cfg->micb_mv = wcd938x->micb2_mv;
+ cfg->micb_mv = wcd938x->common.micb_mv[2];
cfg->linein_th = 5000;
cfg->hs_thr = 1700;
cfg->hph_thr = 50;
@@ -3283,10 +3260,10 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device
static int wcd938x_reset(struct wcd938x_priv *wcd938x)
{
- gpio_direction_output(wcd938x->reset_gpio, 0);
+ gpiod_set_value(wcd938x->reset_gpio, 1);
/* 20us sleep required after pulling the reset gpio to LOW */
usleep_range(20, 30);
- gpio_set_value(wcd938x->reset_gpio, 1);
+ gpiod_set_value(wcd938x->reset_gpio, 0);
/* 20us sleep required after pulling the reset gpio to HIGH */
usleep_range(20, 30);
@@ -3329,7 +3306,7 @@ static const struct snd_soc_dai_ops wcd938x_sdw_dai_ops = {
};
static struct snd_soc_dai_driver wcd938x_dais[] = {
- [0] = {
+ [AIF1_PB] = {
.name = "wcd938x-sdw-rx",
.playback = {
.stream_name = "WCD AIF1 Playback",
@@ -3342,7 +3319,7 @@ static struct snd_soc_dai_driver wcd938x_dais[] = {
},
.ops = &wcd938x_sdw_dai_ops,
},
- [1] = {
+ [AIF1_CAP] = {
.name = "wcd938x-sdw-tx",
.capture = {
.stream_name = "WCD AIF1 Capture",
@@ -3369,86 +3346,102 @@ static int wcd938x_bind(struct device *dev)
return ret;
}
- wcd938x->rxdev = wcd938x_sdw_device_get(wcd938x->rxnode);
+ wcd938x->rxdev = of_sdw_find_device_by_node(wcd938x->rxnode);
if (!wcd938x->rxdev) {
dev_err(dev, "could not find slave with matching of node\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_unbind;
}
wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd938x->rxdev);
wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x;
- wcd938x->txdev = wcd938x_sdw_device_get(wcd938x->txnode);
+ wcd938x->txdev = of_sdw_find_device_by_node(wcd938x->txnode);
if (!wcd938x->txdev) {
dev_err(dev, "could not find txslave with matching of node\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_put_rxdev;
}
wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd938x->txdev);
wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x;
wcd938x->tx_sdw_dev = dev_to_sdw_dev(wcd938x->txdev);
- if (!wcd938x->tx_sdw_dev) {
- dev_err(dev, "could not get txslave with matching of dev\n");
- return -EINVAL;
- }
/* As TX is main CSR reg interface, which should not be suspended first.
* expicilty add the dependency link */
if (!device_link_add(wcd938x->rxdev, wcd938x->txdev, DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME)) {
dev_err(dev, "could not devlink tx and rx\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_put_txdev;
}
if (!device_link_add(dev, wcd938x->txdev, DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME)) {
dev_err(dev, "could not devlink wcd and tx\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_remove_rxtx_link;
}
if (!device_link_add(dev, wcd938x->rxdev, DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME)) {
dev_err(dev, "could not devlink wcd and rx\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_remove_tx_link;
}
- wcd938x->regmap = dev_get_regmap(&wcd938x->tx_sdw_dev->dev, NULL);
+ wcd938x->regmap = wcd938x->sdw_priv[AIF1_CAP]->regmap;
if (!wcd938x->regmap) {
dev_err(dev, "could not get TX device regmap\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_remove_rx_link;
}
ret = wcd938x_irq_init(wcd938x, dev);
if (ret) {
dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret);
- return ret;
+ goto err_remove_rx_link;
}
wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq;
wcd938x->sdw_priv[AIF1_CAP]->slave_irq = wcd938x->virq;
- ret = wcd938x_set_micbias_data(wcd938x);
- if (ret < 0) {
- dev_err(dev, "%s: bad micbias pdata\n", __func__);
- return ret;
- }
+ wcd938x_set_micbias_data(dev, wcd938x);
ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x,
wcd938x_dais, ARRAY_SIZE(wcd938x_dais));
- if (ret)
+ if (ret) {
dev_err(dev, "%s: Codec registration failed\n",
__func__);
+ goto err_remove_rx_link;
+ }
- return ret;
+ return 0;
+
+err_remove_rx_link:
+ device_link_remove(dev, wcd938x->rxdev);
+err_remove_tx_link:
+ device_link_remove(dev, wcd938x->txdev);
+err_remove_rxtx_link:
+ device_link_remove(wcd938x->rxdev, wcd938x->txdev);
+err_put_txdev:
+ put_device(wcd938x->txdev);
+err_put_rxdev:
+ put_device(wcd938x->rxdev);
+err_unbind:
+ component_unbind_all(dev, wcd938x);
+ return ret;
}
static void wcd938x_unbind(struct device *dev)
{
struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
+ snd_soc_unregister_component(dev);
device_link_remove(dev, wcd938x->txdev);
device_link_remove(dev, wcd938x->rxdev);
device_link_remove(wcd938x->rxdev, wcd938x->txdev);
- snd_soc_unregister_component(dev);
+ put_device(wcd938x->txdev);
+ put_device(wcd938x->rxdev);
component_unbind_all(dev, wcd938x);
}
@@ -3500,12 +3493,12 @@ static int wcd938x_probe(struct platform_device *pdev)
dev_set_drvdata(dev, wcd938x);
mutex_init(&wcd938x->micb_lock);
+ wcd938x->common.dev = dev;
+ wcd938x->common.max_bias = 4;
ret = wcd938x_populate_dt_data(wcd938x, dev);
- if (ret) {
- dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
- return -EINVAL;
- }
+ if (ret)
+ return ret;
ret = wcd938x_add_slave_components(wcd938x, dev, &match);
if (ret)
@@ -3529,7 +3522,17 @@ static int wcd938x_probe(struct platform_device *pdev)
static void wcd938x_remove(struct platform_device *pdev)
{
- component_master_del(&pdev->dev, &wcd938x_comp_ops);
+ struct device *dev = &pdev->dev;
+ struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
+
+ component_master_del(dev, &wcd938x_comp_ops);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+
+ if (wcd938x->us_euro_mux && wcd938x->mux_setup_done)
+ mux_control_deselect(wcd938x->us_euro_mux);
}
#if defined(CONFIG_OF)
@@ -3543,7 +3546,7 @@ MODULE_DEVICE_TABLE(of, wcd938x_dt_match);
static struct platform_driver wcd938x_codec_driver = {
.probe = wcd938x_probe,
- .remove_new = wcd938x_remove,
+ .remove = wcd938x_remove,
.driver = {
.name = "wcd938x_codec",
.of_match_table = of_match_ptr(wcd938x_dt_match),
diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h
index 74b1498fec38..c18610466d7d 100644
--- a/sound/soc/codecs/wcd938x.h
+++ b/sound/soc/codecs/wcd938x.h
@@ -75,9 +75,6 @@
#define WCD938X_MICB_PULL_UP 2
#define WCD938X_MICB_PULL_DOWN 3
#define WCD938X_ANA_MICB2 (0x3023)
-#define WCD938X_ANA_MICB2_ENABLE BIT(6)
-#define WCD938X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6)
-#define WCD938X_ANA_MICB2_VOUT_MASK GENMASK(5, 0)
#define WCD938X_ANA_MICB2_RAMP (0x3024)
#define WCD938X_RAMP_EN_MASK BIT(7)
#define WCD938X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2)
@@ -588,27 +585,15 @@
#define WCD938X_DIGITAL_DEM_BYPASS_DATA3 (0x34D8)
#define WCD938X_MAX_REGISTER (WCD938X_DIGITAL_DEM_BYPASS_DATA3)
-#define WCD938X_MAX_SWR_PORTS 5
-#define WCD938X_MAX_TX_SWR_PORTS 4
#define WCD938X_MAX_SWR_CH_IDS 15
-struct wcd938x_sdw_ch_info {
- int port_num;
- unsigned int ch_mask;
-};
-
-#define WCD_SDW_CH(id, pn, cmask) \
- [id] = { \
- .port_num = pn, \
- .ch_mask = cmask, \
- }
-
enum wcd938x_tx_sdw_ports {
WCD938X_ADC_1_2_PORT = 1,
WCD938X_ADC_3_4_PORT,
/* DMIC0_0, DMIC0_1, DMIC1_0, DMIC1_1 */
WCD938X_DMIC_0_3_MBHC_PORT,
WCD938X_DMIC_4_7_PORT,
+ WCD938X_MAX_TX_SWR_PORTS = WCD938X_DMIC_4_7_PORT,
};
enum wcd938x_tx_sdw_channels {
@@ -633,6 +618,7 @@ enum wcd938x_rx_sdw_ports {
WCD938X_COMP_PORT,
WCD938X_LO_PORT,
WCD938X_DSD_PORT,
+ WCD938X_MAX_SWR_PORTS = WCD938X_DSD_PORT,
};
enum wcd938x_rx_sdw_channels {
@@ -645,10 +631,6 @@ enum wcd938x_rx_sdw_channels {
WCD938X_DSD_R,
WCD938X_DSD_L,
};
-enum {
- WCD938X_SDW_DIR_RX,
- WCD938X_SDW_DIR_TX,
-};
struct wcd938x_priv;
struct wcd938x_sdw_priv {
@@ -656,10 +638,9 @@ struct wcd938x_sdw_priv {
struct sdw_stream_config sconfig;
struct sdw_stream_runtime *sruntime;
struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS];
- struct wcd938x_sdw_ch_info *ch_info;
+ const struct wcd_sdw_ch_info *ch_info;
bool port_enable[WCD938X_MAX_SWR_CH_IDS];
int active_ports;
- int num_ports;
bool is_tx;
struct wcd938x_priv *wcd938x;
struct irq_domain *slave_irq;
@@ -677,10 +658,6 @@ int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai);
-
-struct device *wcd938x_sdw_device_get(struct device_node *np);
-int wcd938x_swr_get_current_bank(struct sdw_slave *sdev);
-
#else
static inline int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd,
@@ -705,14 +682,5 @@ static inline int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd,
return -EOPNOTSUPP;
}
-static inline struct device *wcd938x_sdw_device_get(struct device_node *np)
-{
- return NULL;
-}
-
-static inline int wcd938x_swr_get_current_bank(struct sdw_slave *sdev)
-{
- return 0;
-}
#endif /* CONFIG_SND_SOC_WCD938X_SDW */
#endif /* __WCD938X_H__ */
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
new file mode 100644
index 000000000000..da342a0c95a5
--- /dev/null
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -0,0 +1,1477 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/component.h>
+#include <linux/pm_runtime.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include "wcd939x.h"
+#include "wcd-common.h"
+
+static const struct wcd_sdw_ch_info wcd939x_sdw_rx_ch_info[] = {
+ WCD_SDW_CH(WCD939X_HPH_L, WCD939X_HPH_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_HPH_R, WCD939X_HPH_PORT, BIT(1)),
+ WCD_SDW_CH(WCD939X_CLSH, WCD939X_CLSH_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_COMP_L, WCD939X_COMP_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_COMP_R, WCD939X_COMP_PORT, BIT(1)),
+ WCD_SDW_CH(WCD939X_LO, WCD939X_LO_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_DSD_L, WCD939X_DSD_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_DSD_R, WCD939X_DSD_PORT, BIT(1)),
+ WCD_SDW_CH(WCD939X_HIFI_PCM_L, WCD939X_HIFI_PCM_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_HIFI_PCM_R, WCD939X_HIFI_PCM_PORT, BIT(1)),
+};
+
+static const struct wcd_sdw_ch_info wcd939x_sdw_tx_ch_info[] = {
+ WCD_SDW_CH(WCD939X_ADC1, WCD939X_ADC_1_4_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_ADC2, WCD939X_ADC_1_4_PORT, BIT(1)),
+ WCD_SDW_CH(WCD939X_ADC3, WCD939X_ADC_1_4_PORT, BIT(2)),
+ WCD_SDW_CH(WCD939X_ADC4, WCD939X_ADC_1_4_PORT, BIT(3)),
+ WCD_SDW_CH(WCD939X_DMIC0, WCD939X_DMIC_0_3_MBHC_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_DMIC1, WCD939X_DMIC_0_3_MBHC_PORT, BIT(1)),
+ WCD_SDW_CH(WCD939X_MBHC, WCD939X_DMIC_0_3_MBHC_PORT, BIT(2)),
+ WCD_SDW_CH(WCD939X_DMIC2, WCD939X_DMIC_0_3_MBHC_PORT, BIT(2)),
+ WCD_SDW_CH(WCD939X_DMIC3, WCD939X_DMIC_0_3_MBHC_PORT, BIT(3)),
+ WCD_SDW_CH(WCD939X_DMIC4, WCD939X_DMIC_3_7_PORT, BIT(0)),
+ WCD_SDW_CH(WCD939X_DMIC5, WCD939X_DMIC_3_7_PORT, BIT(1)),
+ WCD_SDW_CH(WCD939X_DMIC6, WCD939X_DMIC_3_7_PORT, BIT(2)),
+ WCD_SDW_CH(WCD939X_DMIC7, WCD939X_DMIC_3_7_PORT, BIT(3)),
+};
+
+static struct sdw_dpn_prop wcd939x_rx_dpn_prop[WCD939X_MAX_RX_SWR_PORTS] = {
+ {
+ .num = WCD939X_HPH_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 2,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_CLSH_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_COMP_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 2,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_LO_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_DSD_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 2,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_HIFI_PCM_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 2,
+ .simple_ch_prep_sm = true,
+ }
+};
+
+static struct sdw_dpn_prop wcd939x_tx_dpn_prop[WCD939X_MAX_TX_SWR_PORTS] = {
+ {
+ .num = WCD939X_ADC_1_4_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_ADC_DMIC_1_2_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_DMIC_0_3_MBHC_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ },
+ {
+ .num = WCD939X_DMIC_3_7_PORT,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 4,
+ .simple_ch_prep_sm = true,
+ }
+};
+
+int wcd939x_sdw_hw_params(struct wcd939x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS];
+ unsigned long ch_mask;
+ int i, j;
+
+ wcd->sconfig.ch_count = 1;
+ wcd->active_ports = 0;
+ for (i = 0; i < WCD939X_MAX_SWR_PORTS; i++) {
+ ch_mask = wcd->port_config[i].ch_mask;
+
+ if (!ch_mask)
+ continue;
+
+ for_each_set_bit(j, &ch_mask, 4)
+ wcd->sconfig.ch_count++;
+
+ port_config[wcd->active_ports] = wcd->port_config[i];
+ wcd->active_ports++;
+ }
+
+ wcd->sconfig.bps = 1;
+ wcd->sconfig.frame_rate = params_rate(params);
+ if (wcd->is_tx)
+ wcd->sconfig.direction = SDW_DATA_DIR_TX;
+ else
+ wcd->sconfig.direction = SDW_DATA_DIR_RX;
+
+ wcd->sconfig.type = SDW_STREAM_PCM;
+
+ return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, &port_config[0],
+ wcd->active_ports, wcd->sruntime);
+}
+EXPORT_SYMBOL_GPL(wcd939x_sdw_hw_params);
+
+int wcd939x_sdw_free(struct wcd939x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ sdw_stream_remove_slave(wcd->sdev, wcd->sruntime);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd939x_sdw_free);
+
+int wcd939x_sdw_set_sdw_stream(struct wcd939x_sdw_priv *wcd,
+ struct snd_soc_dai *dai, void *stream,
+ int direction)
+{
+ wcd->sruntime = stream;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wcd939x_sdw_set_sdw_stream);
+
+/*
+ * Handle Soundwire out-of-band interrupt event by triggering
+ * the first irq of the slave_irq irq domain, which then will
+ * be handled by the regmap_irq threaded irq.
+ * Looping is to ensure no interrupts were missed in the process.
+ */
+static int wcd9390_interrupt_callback(struct sdw_slave *slave,
+ struct sdw_slave_intr_status *status)
+{
+ struct wcd939x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
+
+ return wcd_interrupt_callback(slave, wcd->slave_irq, WCD939X_DIGITAL_INTR_STATUS_0,
+ WCD939X_DIGITAL_INTR_STATUS_1, WCD939X_DIGITAL_INTR_STATUS_2);
+}
+
+static const struct reg_default wcd939x_defaults[] = {
+ /* Default values except for Read-Only & Volatile registers */
+ { WCD939X_ANA_PAGE, 0x00 },
+ { WCD939X_ANA_BIAS, 0x00 },
+ { WCD939X_ANA_RX_SUPPLIES, 0x00 },
+ { WCD939X_ANA_HPH, 0x0c },
+ { WCD939X_ANA_EAR, 0x00 },
+ { WCD939X_ANA_EAR_COMPANDER_CTL, 0x02 },
+ { WCD939X_ANA_TX_CH1, 0x20 },
+ { WCD939X_ANA_TX_CH2, 0x00 },
+ { WCD939X_ANA_TX_CH3, 0x20 },
+ { WCD939X_ANA_TX_CH4, 0x00 },
+ { WCD939X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00 },
+ { WCD939X_ANA_MICB3_DSP_EN_LOGIC, 0x00 },
+ { WCD939X_ANA_MBHC_MECH, 0x39 },
+ { WCD939X_ANA_MBHC_ELECT, 0x08 },
+ { WCD939X_ANA_MBHC_ZDET, 0x00 },
+ { WCD939X_ANA_MBHC_BTN0, 0x00 },
+ { WCD939X_ANA_MBHC_BTN1, 0x10 },
+ { WCD939X_ANA_MBHC_BTN2, 0x20 },
+ { WCD939X_ANA_MBHC_BTN3, 0x30 },
+ { WCD939X_ANA_MBHC_BTN4, 0x40 },
+ { WCD939X_ANA_MBHC_BTN5, 0x50 },
+ { WCD939X_ANA_MBHC_BTN6, 0x60 },
+ { WCD939X_ANA_MBHC_BTN7, 0x70 },
+ { WCD939X_ANA_MICB1, 0x10 },
+ { WCD939X_ANA_MICB2, 0x10 },
+ { WCD939X_ANA_MICB2_RAMP, 0x00 },
+ { WCD939X_ANA_MICB3, 0x00 },
+ { WCD939X_ANA_MICB4, 0x00 },
+ { WCD939X_BIAS_CTL, 0x2a },
+ { WCD939X_BIAS_VBG_FINE_ADJ, 0x55 },
+ { WCD939X_LDOL_VDDCX_ADJUST, 0x01 },
+ { WCD939X_LDOL_DISABLE_LDOL, 0x00 },
+ { WCD939X_MBHC_CTL_CLK, 0x00 },
+ { WCD939X_MBHC_CTL_ANA, 0x00 },
+ { WCD939X_MBHC_ZDET_VNEG_CTL, 0x00 },
+ { WCD939X_MBHC_ZDET_BIAS_CTL, 0x46 },
+ { WCD939X_MBHC_CTL_BCS, 0x00 },
+ { WCD939X_MBHC_TEST_CTL, 0x00 },
+ { WCD939X_LDOH_MODE, 0x2b },
+ { WCD939X_LDOH_BIAS, 0x68 },
+ { WCD939X_LDOH_STB_LOADS, 0x00 },
+ { WCD939X_LDOH_SLOWRAMP, 0x50 },
+ { WCD939X_MICB1_TEST_CTL_1, 0x1a },
+ { WCD939X_MICB1_TEST_CTL_2, 0x00 },
+ { WCD939X_MICB1_TEST_CTL_3, 0xa4 },
+ { WCD939X_MICB2_TEST_CTL_1, 0x1a },
+ { WCD939X_MICB2_TEST_CTL_2, 0x00 },
+ { WCD939X_MICB2_TEST_CTL_3, 0x24 },
+ { WCD939X_MICB3_TEST_CTL_1, 0x9a },
+ { WCD939X_MICB3_TEST_CTL_2, 0x80 },
+ { WCD939X_MICB3_TEST_CTL_3, 0x24 },
+ { WCD939X_MICB4_TEST_CTL_1, 0x1a },
+ { WCD939X_MICB4_TEST_CTL_2, 0x80 },
+ { WCD939X_MICB4_TEST_CTL_3, 0x24 },
+ { WCD939X_TX_COM_ADC_VCM, 0x39 },
+ { WCD939X_TX_COM_BIAS_ATEST, 0xe0 },
+ { WCD939X_TX_COM_SPARE1, 0x00 },
+ { WCD939X_TX_COM_SPARE2, 0x00 },
+ { WCD939X_TX_COM_TXFE_DIV_CTL, 0x22 },
+ { WCD939X_TX_COM_TXFE_DIV_START, 0x00 },
+ { WCD939X_TX_COM_SPARE3, 0x00 },
+ { WCD939X_TX_COM_SPARE4, 0x00 },
+ { WCD939X_TX_1_2_TEST_EN, 0xcc },
+ { WCD939X_TX_1_2_ADC_IB, 0xe9 },
+ { WCD939X_TX_1_2_ATEST_REFCTL, 0x0b },
+ { WCD939X_TX_1_2_TEST_CTL, 0x38 },
+ { WCD939X_TX_1_2_TEST_BLK_EN1, 0xff },
+ { WCD939X_TX_1_2_TXFE1_CLKDIV, 0x00 },
+ { WCD939X_TX_3_4_TEST_EN, 0xcc },
+ { WCD939X_TX_3_4_ADC_IB, 0xe9 },
+ { WCD939X_TX_3_4_ATEST_REFCTL, 0x0b },
+ { WCD939X_TX_3_4_TEST_CTL, 0x38 },
+ { WCD939X_TX_3_4_TEST_BLK_EN3, 0xff },
+ { WCD939X_TX_3_4_TXFE3_CLKDIV, 0x00 },
+ { WCD939X_TX_3_4_TEST_BLK_EN2, 0xfb },
+ { WCD939X_TX_3_4_TXFE2_CLKDIV, 0x00 },
+ { WCD939X_TX_3_4_SPARE1, 0x00 },
+ { WCD939X_TX_3_4_TEST_BLK_EN4, 0xfb },
+ { WCD939X_TX_3_4_TXFE4_CLKDIV, 0x00 },
+ { WCD939X_TX_3_4_SPARE2, 0x00 },
+ { WCD939X_CLASSH_MODE_1, 0x40 },
+ { WCD939X_CLASSH_MODE_2, 0x3a },
+ { WCD939X_CLASSH_MODE_3, 0xf0 },
+ { WCD939X_CLASSH_CTRL_VCL_1, 0x7c },
+ { WCD939X_CLASSH_CTRL_VCL_2, 0x82 },
+ { WCD939X_CLASSH_CTRL_CCL_1, 0x31 },
+ { WCD939X_CLASSH_CTRL_CCL_2, 0x80 },
+ { WCD939X_CLASSH_CTRL_CCL_3, 0x80 },
+ { WCD939X_CLASSH_CTRL_CCL_4, 0x51 },
+ { WCD939X_CLASSH_CTRL_CCL_5, 0x00 },
+ { WCD939X_CLASSH_BUCK_TMUX_A_D, 0x00 },
+ { WCD939X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 },
+ { WCD939X_CLASSH_SPARE, 0x80 },
+ { WCD939X_FLYBACK_EN, 0x4e },
+ { WCD939X_FLYBACK_VNEG_CTRL_1, 0x0b },
+ { WCD939X_FLYBACK_VNEG_CTRL_2, 0x45 },
+ { WCD939X_FLYBACK_VNEG_CTRL_3, 0x14 },
+ { WCD939X_FLYBACK_VNEG_CTRL_4, 0xdb },
+ { WCD939X_FLYBACK_VNEG_CTRL_5, 0x83 },
+ { WCD939X_FLYBACK_VNEG_CTRL_6, 0x98 },
+ { WCD939X_FLYBACK_VNEG_CTRL_7, 0xa9 },
+ { WCD939X_FLYBACK_VNEG_CTRL_8, 0x68 },
+ { WCD939X_FLYBACK_VNEG_CTRL_9, 0x66 },
+ { WCD939X_FLYBACK_VNEGDAC_CTRL_1, 0xed },
+ { WCD939X_FLYBACK_VNEGDAC_CTRL_2, 0xf8 },
+ { WCD939X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 },
+ { WCD939X_FLYBACK_CTRL_1, 0x65 },
+ { WCD939X_FLYBACK_TEST_CTL, 0x02 },
+ { WCD939X_RX_AUX_SW_CTL, 0x00 },
+ { WCD939X_RX_PA_AUX_IN_CONN, 0x01 },
+ { WCD939X_RX_TIMER_DIV, 0x32 },
+ { WCD939X_RX_OCP_CTL, 0x1f },
+ { WCD939X_RX_OCP_COUNT, 0x77 },
+ { WCD939X_RX_BIAS_EAR_DAC, 0xa0 },
+ { WCD939X_RX_BIAS_EAR_AMP, 0xaa },
+ { WCD939X_RX_BIAS_HPH_LDO, 0xa9 },
+ { WCD939X_RX_BIAS_HPH_PA, 0xaa },
+ { WCD939X_RX_BIAS_HPH_RDACBUFF_CNP2, 0xca },
+ { WCD939X_RX_BIAS_HPH_RDAC_LDO, 0x88 },
+ { WCD939X_RX_BIAS_HPH_CNP1, 0x82 },
+ { WCD939X_RX_BIAS_HPH_LOWPOWER, 0x82 },
+ { WCD939X_RX_BIAS_AUX_DAC, 0xa0 },
+ { WCD939X_RX_BIAS_AUX_AMP, 0xaa },
+ { WCD939X_RX_BIAS_VNEGDAC_BLEEDER, 0x50 },
+ { WCD939X_RX_BIAS_MISC, 0x00 },
+ { WCD939X_RX_BIAS_BUCK_RST, 0x08 },
+ { WCD939X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 },
+ { WCD939X_RX_BIAS_FLYB_ERRAMP, 0x40 },
+ { WCD939X_RX_BIAS_FLYB_BUFF, 0xaa },
+ { WCD939X_RX_BIAS_FLYB_MID_RST, 0x14 },
+ { WCD939X_HPH_CNP_EN, 0x80 },
+ { WCD939X_HPH_CNP_WG_CTL, 0x9a },
+ { WCD939X_HPH_CNP_WG_TIME, 0x14 },
+ { WCD939X_HPH_OCP_CTL, 0x28 },
+ { WCD939X_HPH_AUTO_CHOP, 0x56 },
+ { WCD939X_HPH_CHOP_CTL, 0x83 },
+ { WCD939X_HPH_PA_CTL1, 0x46 },
+ { WCD939X_HPH_PA_CTL2, 0x50 },
+ { WCD939X_HPH_L_EN, 0x80 },
+ { WCD939X_HPH_L_TEST, 0xe0 },
+ { WCD939X_HPH_L_ATEST, 0x50 },
+ { WCD939X_HPH_R_EN, 0x80 },
+ { WCD939X_HPH_R_TEST, 0xe0 },
+ { WCD939X_HPH_R_ATEST, 0x50 },
+ { WCD939X_HPH_RDAC_CLK_CTL1, 0x80 },
+ { WCD939X_HPH_RDAC_CLK_CTL2, 0x0b },
+ { WCD939X_HPH_RDAC_LDO_CTL, 0x33 },
+ { WCD939X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 },
+ { WCD939X_HPH_REFBUFF_UHQA_CTL, 0x00 },
+ { WCD939X_HPH_REFBUFF_LP_CTL, 0x8e },
+ { WCD939X_HPH_L_DAC_CTL, 0x20 },
+ { WCD939X_HPH_R_DAC_CTL, 0x20 },
+ { WCD939X_HPH_SURGE_COMP_SEL, 0x55 },
+ { WCD939X_HPH_SURGE_EN, 0x19 },
+ { WCD939X_HPH_SURGE_MISC1, 0xa0 },
+ { WCD939X_EAR_EN, 0x22 },
+ { WCD939X_EAR_PA_CON, 0x44 },
+ { WCD939X_EAR_SP_CON, 0xdb },
+ { WCD939X_EAR_DAC_CON, 0x80 },
+ { WCD939X_EAR_CNP_FSM_CON, 0xb2 },
+ { WCD939X_EAR_TEST_CTL, 0x00 },
+ { WCD939X_FLYBACK_NEW_CTRL_2, 0x00 },
+ { WCD939X_FLYBACK_NEW_CTRL_3, 0x00 },
+ { WCD939X_FLYBACK_NEW_CTRL_4, 0x44 },
+ { WCD939X_ANA_NEW_PAGE, 0x00 },
+ { WCD939X_HPH_NEW_ANA_HPH2, 0x00 },
+ { WCD939X_HPH_NEW_ANA_HPH3, 0x00 },
+ { WCD939X_SLEEP_CTL, 0x18 },
+ { WCD939X_SLEEP_WATCHDOG_CTL, 0x00 },
+ { WCD939X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 },
+ { WCD939X_MBHC_NEW_CTL_1, 0x02 },
+ { WCD939X_MBHC_NEW_CTL_2, 0x05 },
+ { WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 },
+ { WCD939X_MBHC_NEW_ZDET_ANA_CTL, 0x0f },
+ { WCD939X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 },
+ { WCD939X_TX_NEW_CH12_MUX, 0x11 },
+ { WCD939X_TX_NEW_CH34_MUX, 0x23 },
+ { WCD939X_DIE_CRACK_DET_EN, 0x00 },
+ { WCD939X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 },
+ { WCD939X_HPH_NEW_INT_PA_GAIN_CTL_L, 0x00 },
+ { WCD939X_HPH_NEW_INT_RDAC_VREF_CTL, 0x08 },
+ { WCD939X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 },
+ { WCD939X_HPH_NEW_INT_PA_GAIN_CTL_R, 0x00 },
+ { WCD939X_HPH_NEW_INT_PA_MISC1, 0x32 },
+ { WCD939X_HPH_NEW_INT_PA_MISC2, 0x00 },
+ { WCD939X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 },
+ { WCD939X_HPH_NEW_INT_TIMER1, 0xfe },
+ { WCD939X_HPH_NEW_INT_TIMER2, 0x02 },
+ { WCD939X_HPH_NEW_INT_TIMER3, 0x4e },
+ { WCD939X_HPH_NEW_INT_TIMER4, 0x54 },
+ { WCD939X_HPH_NEW_INT_PA_RDAC_MISC2, 0x0b },
+ { WCD939X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 },
+ { WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xa0 },
+ { WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xa0 },
+ { WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x64 },
+ { WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 },
+ { WCD939X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 },
+ { WCD939X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57 },
+ { WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01 },
+ { WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00 },
+ { WCD939X_MBHC_NEW_INT_ZDET_CLK_AND_MOISTURE_CTL_NEW, 0x47 },
+ { WCD939X_EAR_INT_NEW_CHOPPER_CON, 0xa8 },
+ { WCD939X_EAR_INT_NEW_CNP_VCM_CON1, 0x42 },
+ { WCD939X_EAR_INT_NEW_CNP_VCM_CON2, 0x22 },
+ { WCD939X_EAR_INT_NEW_DYNAMIC_BIAS, 0x00 },
+ { WCD939X_SLEEP_INT_WATCHDOG_CTL_1, 0x0a },
+ { WCD939X_SLEEP_INT_WATCHDOG_CTL_2, 0x0a },
+ { WCD939X_DIE_CRACK_INT_DET_INT1, 0x02 },
+ { WCD939X_DIE_CRACK_INT_DET_INT2, 0x60 },
+ { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L2, 0xff },
+ { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L1, 0x7f },
+ { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L0, 0x3f },
+ { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP1P2M, 0x1f },
+ { WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP0P6M, 0x0f },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L2L1, 0xd7 },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L0, 0xc8 },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_ULP, 0xc6 },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L2L1, 0x95 },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L0, 0x6a },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP, 0x05 },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_L2L1L0, 0xa5 },
+ { WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, 0x13 },
+ { WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L2L1, 0x88 },
+ { WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L0ULP, 0x42 },
+ { WCD939X_TX_COM_NEW_INT_ADC_INT_L2, 0xff },
+ { WCD939X_TX_COM_NEW_INT_ADC_INT_L1, 0x64 },
+ { WCD939X_TX_COM_NEW_INT_ADC_INT_L0, 0x64 },
+ { WCD939X_TX_COM_NEW_INT_ADC_INT_ULP, 0x77 },
+ { WCD939X_DIGITAL_PAGE, 0x00 },
+ { WCD939X_DIGITAL_SWR_TX_CLK_RATE, 0x00 },
+ { WCD939X_DIGITAL_CDC_RST_CTL, 0x03 },
+ { WCD939X_DIGITAL_TOP_CLK_CFG, 0x00 },
+ { WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 0x00 },
+ { WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 0xf0 },
+ { WCD939X_DIGITAL_SWR_RST_EN, 0x00 },
+ { WCD939X_DIGITAL_CDC_PATH_MODE, 0x55 },
+ { WCD939X_DIGITAL_CDC_RX_RST, 0x00 },
+ { WCD939X_DIGITAL_CDC_RX0_CTL, 0xfc },
+ { WCD939X_DIGITAL_CDC_RX1_CTL, 0xfc },
+ { WCD939X_DIGITAL_CDC_RX2_CTL, 0xfc },
+ { WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00 },
+ { WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00 },
+ { WCD939X_DIGITAL_CDC_COMP_CTL_0, 0x00 },
+ { WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1e },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A3_0, 0xac },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1a },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A5_0, 0xbc },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A6_0, 0xc7 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_A7_0, 0xf8 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_C_0, 0x47 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_C_1, 0x43 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_C_2, 0xb1 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_C_3, 0x17 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R1, 0x4d },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R2, 0x29 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R3, 0x34 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R4, 0x59 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R5, 0x66 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R6, 0x87 },
+ { WCD939X_DIGITAL_CDC_HPH_DSM_R7, 0x64 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A1_0, 0x00 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A1_1, 0x01 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A2_0, 0x96 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A2_1, 0x09 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A3_0, 0xab },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A3_1, 0x05 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A4_0, 0x1c },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A4_1, 0x02 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A5_0, 0x17 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A5_1, 0x02 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A6_0, 0xaa },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_A7_0, 0xe3 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_C_0, 0x69 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_C_1, 0x54 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_C_2, 0x02 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_C_3, 0x15 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R1, 0xa4 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R2, 0xb5 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R3, 0x86 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R4, 0x85 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R5, 0xaa },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R6, 0xe2 },
+ { WCD939X_DIGITAL_CDC_EAR_DSM_R7, 0x62 },
+ { WCD939X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55 },
+ { WCD939X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xa9 },
+ { WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3d },
+ { WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2e },
+ { WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01 },
+ { WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_0, 0x00 },
+ { WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_1, 0xfc },
+ { WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_2, 0x01 },
+ { WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00 },
+ { WCD939X_DIGITAL_CDC_EAR_GAIN_CTL, 0x00 },
+ { WCD939X_DIGITAL_CDC_EAR_PATH_CTL, 0x00 },
+ { WCD939X_DIGITAL_CDC_SWR_CLH, 0x00 },
+ { WCD939X_DIGITAL_SWR_CLH_BYP, 0x00 },
+ { WCD939X_DIGITAL_CDC_TX0_CTL, 0x68 },
+ { WCD939X_DIGITAL_CDC_TX1_CTL, 0x68 },
+ { WCD939X_DIGITAL_CDC_TX2_CTL, 0x68 },
+ { WCD939X_DIGITAL_CDC_TX_RST, 0x00 },
+ { WCD939X_DIGITAL_CDC_REQ_CTL, 0x01 },
+ { WCD939X_DIGITAL_CDC_RST, 0x00 },
+ { WCD939X_DIGITAL_CDC_AMIC_CTL, 0x0f },
+ { WCD939X_DIGITAL_CDC_DMIC_CTL, 0x04 },
+ { WCD939X_DIGITAL_CDC_DMIC1_CTL, 0x01 },
+ { WCD939X_DIGITAL_CDC_DMIC2_CTL, 0x01 },
+ { WCD939X_DIGITAL_CDC_DMIC3_CTL, 0x01 },
+ { WCD939X_DIGITAL_CDC_DMIC4_CTL, 0x01 },
+ { WCD939X_DIGITAL_EFUSE_PRG_CTL, 0x00 },
+ { WCD939X_DIGITAL_EFUSE_CTL, 0x2b },
+ { WCD939X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11 },
+ { WCD939X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11 },
+ { WCD939X_DIGITAL_PDM_WD_CTL0, 0x00 },
+ { WCD939X_DIGITAL_PDM_WD_CTL1, 0x00 },
+ { WCD939X_DIGITAL_PDM_WD_CTL2, 0x00 },
+ { WCD939X_DIGITAL_INTR_MODE, 0x00 },
+ { WCD939X_DIGITAL_INTR_MASK_0, 0xff },
+ { WCD939X_DIGITAL_INTR_MASK_1, 0xe7 },
+ { WCD939X_DIGITAL_INTR_MASK_2, 0x0e },
+ { WCD939X_DIGITAL_INTR_CLEAR_0, 0x00 },
+ { WCD939X_DIGITAL_INTR_CLEAR_1, 0x00 },
+ { WCD939X_DIGITAL_INTR_CLEAR_2, 0x00 },
+ { WCD939X_DIGITAL_INTR_LEVEL_0, 0x00 },
+ { WCD939X_DIGITAL_INTR_LEVEL_1, 0x00 },
+ { WCD939X_DIGITAL_INTR_LEVEL_2, 0x00 },
+ { WCD939X_DIGITAL_INTR_SET_0, 0x00 },
+ { WCD939X_DIGITAL_INTR_SET_1, 0x00 },
+ { WCD939X_DIGITAL_INTR_SET_2, 0x00 },
+ { WCD939X_DIGITAL_INTR_TEST_0, 0x00 },
+ { WCD939X_DIGITAL_INTR_TEST_1, 0x00 },
+ { WCD939X_DIGITAL_INTR_TEST_2, 0x00 },
+ { WCD939X_DIGITAL_TX_MODE_DBG_EN, 0x00 },
+ { WCD939X_DIGITAL_TX_MODE_DBG_0_1, 0x00 },
+ { WCD939X_DIGITAL_TX_MODE_DBG_2_3, 0x00 },
+ { WCD939X_DIGITAL_LB_IN_SEL_CTL, 0x00 },
+ { WCD939X_DIGITAL_LOOP_BACK_MODE, 0x00 },
+ { WCD939X_DIGITAL_SWR_DAC_TEST, 0x00 },
+ { WCD939X_DIGITAL_SWR_HM_TEST_RX_0, 0x40 },
+ { WCD939X_DIGITAL_SWR_HM_TEST_TX_0, 0x40 },
+ { WCD939X_DIGITAL_SWR_HM_TEST_RX_1, 0x00 },
+ { WCD939X_DIGITAL_SWR_HM_TEST_TX_1, 0x00 },
+ { WCD939X_DIGITAL_SWR_HM_TEST_TX_2, 0x00 },
+ { WCD939X_DIGITAL_PAD_CTL_SWR_0, 0x8f },
+ { WCD939X_DIGITAL_PAD_CTL_SWR_1, 0x06 },
+ { WCD939X_DIGITAL_I2C_CTL, 0x00 },
+ { WCD939X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00 },
+ { WCD939X_DIGITAL_EFUSE_TEST_CTL_0, 0x00 },
+ { WCD939X_DIGITAL_EFUSE_TEST_CTL_1, 0x00 },
+ { WCD939X_DIGITAL_PAD_CTL_PDM_RX0, 0xf1 },
+ { WCD939X_DIGITAL_PAD_CTL_PDM_RX1, 0xf1 },
+ { WCD939X_DIGITAL_PAD_CTL_PDM_TX0, 0xf1 },
+ { WCD939X_DIGITAL_PAD_CTL_PDM_TX1, 0xf1 },
+ { WCD939X_DIGITAL_PAD_CTL_PDM_TX2, 0xf1 },
+ { WCD939X_DIGITAL_PAD_INP_DIS_0, 0x00 },
+ { WCD939X_DIGITAL_PAD_INP_DIS_1, 0x00 },
+ { WCD939X_DIGITAL_DRIVE_STRENGTH_0, 0x00 },
+ { WCD939X_DIGITAL_DRIVE_STRENGTH_1, 0x00 },
+ { WCD939X_DIGITAL_DRIVE_STRENGTH_2, 0x00 },
+ { WCD939X_DIGITAL_RX_DATA_EDGE_CTL, 0x1f },
+ { WCD939X_DIGITAL_TX_DATA_EDGE_CTL, 0x80 },
+ { WCD939X_DIGITAL_GPIO_MODE, 0x00 },
+ { WCD939X_DIGITAL_PIN_CTL_OE, 0x00 },
+ { WCD939X_DIGITAL_PIN_CTL_DATA_0, 0x00 },
+ { WCD939X_DIGITAL_PIN_CTL_DATA_1, 0x00 },
+ { WCD939X_DIGITAL_DIG_DEBUG_CTL, 0x00 },
+ { WCD939X_DIGITAL_DIG_DEBUG_EN, 0x00 },
+ { WCD939X_DIGITAL_ANA_CSR_DBG_ADD, 0x00 },
+ { WCD939X_DIGITAL_ANA_CSR_DBG_CTL, 0x48 },
+ { WCD939X_DIGITAL_SSP_DBG, 0x00 },
+ { WCD939X_DIGITAL_SPARE_0, 0x00 },
+ { WCD939X_DIGITAL_SPARE_1, 0x00 },
+ { WCD939X_DIGITAL_SPARE_2, 0x00 },
+ { WCD939X_DIGITAL_TX_REQ_FB_CTL_0, 0x88 },
+ { WCD939X_DIGITAL_TX_REQ_FB_CTL_1, 0x88 },
+ { WCD939X_DIGITAL_TX_REQ_FB_CTL_2, 0x88 },
+ { WCD939X_DIGITAL_TX_REQ_FB_CTL_3, 0x88 },
+ { WCD939X_DIGITAL_TX_REQ_FB_CTL_4, 0x88 },
+ { WCD939X_DIGITAL_DEM_BYPASS_DATA0, 0x55 },
+ { WCD939X_DIGITAL_DEM_BYPASS_DATA1, 0x55 },
+ { WCD939X_DIGITAL_DEM_BYPASS_DATA2, 0x55 },
+ { WCD939X_DIGITAL_DEM_BYPASS_DATA3, 0x01 },
+ { WCD939X_DIGITAL_DEM_SECOND_ORDER, 0x03 },
+ { WCD939X_DIGITAL_DSM_CTRL, 0x00 },
+ { WCD939X_DIGITAL_DSM_0_STATIC_DATA_0, 0x00 },
+ { WCD939X_DIGITAL_DSM_0_STATIC_DATA_1, 0x00 },
+ { WCD939X_DIGITAL_DSM_0_STATIC_DATA_2, 0x00 },
+ { WCD939X_DIGITAL_DSM_0_STATIC_DATA_3, 0x00 },
+ { WCD939X_DIGITAL_DSM_1_STATIC_DATA_0, 0x00 },
+ { WCD939X_DIGITAL_DSM_1_STATIC_DATA_1, 0x00 },
+ { WCD939X_DIGITAL_DSM_1_STATIC_DATA_2, 0x00 },
+ { WCD939X_DIGITAL_DSM_1_STATIC_DATA_3, 0x00 },
+ { WCD939X_RX_TOP_PAGE, 0x00 },
+ { WCD939X_RX_TOP_TOP_CFG0, 0x00 },
+ { WCD939X_RX_TOP_HPHL_COMP_WR_LSB, 0x00 },
+ { WCD939X_RX_TOP_HPHL_COMP_WR_MSB, 0x00 },
+ { WCD939X_RX_TOP_HPHL_COMP_LUT, 0x00 },
+ { WCD939X_RX_TOP_HPHR_COMP_WR_LSB, 0x00 },
+ { WCD939X_RX_TOP_HPHR_COMP_WR_MSB, 0x00 },
+ { WCD939X_RX_TOP_HPHR_COMP_LUT, 0x00 },
+ { WCD939X_RX_TOP_DSD0_DEBUG_CFG1, 0x05 },
+ { WCD939X_RX_TOP_DSD0_DEBUG_CFG2, 0x08 },
+ { WCD939X_RX_TOP_DSD0_DEBUG_CFG3, 0x00 },
+ { WCD939X_RX_TOP_DSD0_DEBUG_CFG4, 0x00 },
+ { WCD939X_RX_TOP_DSD1_DEBUG_CFG1, 0x03 },
+ { WCD939X_RX_TOP_DSD1_DEBUG_CFG2, 0x08 },
+ { WCD939X_RX_TOP_DSD1_DEBUG_CFG3, 0x00 },
+ { WCD939X_RX_TOP_DSD1_DEBUG_CFG4, 0x00 },
+ { WCD939X_RX_TOP_HPHL_PATH_CFG0, 0x00 },
+ { WCD939X_RX_TOP_HPHL_PATH_CFG1, 0x00 },
+ { WCD939X_RX_TOP_HPHR_PATH_CFG0, 0x00 },
+ { WCD939X_RX_TOP_HPHR_PATH_CFG1, 0x00 },
+ { WCD939X_RX_TOP_PATH_CFG2, 0x00 },
+ { WCD939X_RX_TOP_HPHL_PATH_SEC0, 0x00 },
+ { WCD939X_RX_TOP_HPHL_PATH_SEC1, 0x00 },
+ { WCD939X_RX_TOP_HPHL_PATH_SEC2, 0x00 },
+ { WCD939X_RX_TOP_HPHL_PATH_SEC3, 0x00 },
+ { WCD939X_RX_TOP_HPHR_PATH_SEC0, 0x00 },
+ { WCD939X_RX_TOP_HPHR_PATH_SEC1, 0x00 },
+ { WCD939X_RX_TOP_HPHR_PATH_SEC2, 0x00 },
+ { WCD939X_RX_TOP_HPHR_PATH_SEC3, 0x00 },
+ { WCD939X_RX_TOP_PATH_SEC4, 0x00 },
+ { WCD939X_RX_TOP_PATH_SEC5, 0x00 },
+ { WCD939X_COMPANDER_HPHL_CTL0, 0x60 },
+ { WCD939X_COMPANDER_HPHL_CTL1, 0xdb },
+ { WCD939X_COMPANDER_HPHL_CTL2, 0xff },
+ { WCD939X_COMPANDER_HPHL_CTL3, 0x35 },
+ { WCD939X_COMPANDER_HPHL_CTL4, 0xff },
+ { WCD939X_COMPANDER_HPHL_CTL5, 0x00 },
+ { WCD939X_COMPANDER_HPHL_CTL7, 0x08 },
+ { WCD939X_COMPANDER_HPHL_CTL8, 0x00 },
+ { WCD939X_COMPANDER_HPHL_CTL9, 0x00 },
+ { WCD939X_COMPANDER_HPHL_CTL10, 0x06 },
+ { WCD939X_COMPANDER_HPHL_CTL11, 0x12 },
+ { WCD939X_COMPANDER_HPHL_CTL12, 0x1e },
+ { WCD939X_COMPANDER_HPHL_CTL13, 0x2a },
+ { WCD939X_COMPANDER_HPHL_CTL14, 0x36 },
+ { WCD939X_COMPANDER_HPHL_CTL15, 0x3c },
+ { WCD939X_COMPANDER_HPHL_CTL16, 0xc4 },
+ { WCD939X_COMPANDER_HPHL_CTL17, 0x00 },
+ { WCD939X_COMPANDER_HPHL_CTL18, 0x0c },
+ { WCD939X_COMPANDER_HPHL_CTL19, 0x16 },
+ { WCD939X_R_CTL0, 0x60 },
+ { WCD939X_R_CTL1, 0xdb },
+ { WCD939X_R_CTL2, 0xff },
+ { WCD939X_R_CTL3, 0x35 },
+ { WCD939X_R_CTL4, 0xff },
+ { WCD939X_R_CTL5, 0x00 },
+ { WCD939X_R_CTL7, 0x08 },
+ { WCD939X_R_CTL8, 0x00 },
+ { WCD939X_R_CTL9, 0x00 },
+ { WCD939X_R_CTL10, 0x06 },
+ { WCD939X_R_CTL11, 0x12 },
+ { WCD939X_R_CTL12, 0x1e },
+ { WCD939X_R_CTL13, 0x2a },
+ { WCD939X_R_CTL14, 0x36 },
+ { WCD939X_R_CTL15, 0x3c },
+ { WCD939X_R_CTL16, 0xc4 },
+ { WCD939X_R_CTL17, 0x00 },
+ { WCD939X_R_CTL18, 0x0c },
+ { WCD939X_R_CTL19, 0x16 },
+ { WCD939X_E_PATH_CTL, 0x00 },
+ { WCD939X_E_CFG0, 0x07 },
+ { WCD939X_E_CFG1, 0x3c },
+ { WCD939X_E_CFG2, 0x00 },
+ { WCD939X_E_CFG3, 0x00 },
+ { WCD939X_DSD_HPHL_PATH_CTL, 0x00 },
+ { WCD939X_DSD_HPHL_CFG0, 0x00 },
+ { WCD939X_DSD_HPHL_CFG1, 0x00 },
+ { WCD939X_DSD_HPHL_CFG2, 0x22 },
+ { WCD939X_DSD_HPHL_CFG3, 0x00 },
+ { WCD939X_DSD_HPHL_CFG4, 0x1a },
+ { WCD939X_DSD_HPHL_CFG5, 0x00 },
+ { WCD939X_DSD_HPHR_PATH_CTL, 0x00 },
+ { WCD939X_DSD_HPHR_CFG0, 0x00 },
+ { WCD939X_DSD_HPHR_CFG1, 0x00 },
+ { WCD939X_DSD_HPHR_CFG2, 0x22 },
+ { WCD939X_DSD_HPHR_CFG3, 0x00 },
+ { WCD939X_DSD_HPHR_CFG4, 0x1a },
+ { WCD939X_DSD_HPHR_CFG5, 0x00 },
+};
+
+static bool wcd939x_rdwr_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD939X_ANA_PAGE:
+ case WCD939X_ANA_BIAS:
+ case WCD939X_ANA_RX_SUPPLIES:
+ case WCD939X_ANA_HPH:
+ case WCD939X_ANA_EAR:
+ case WCD939X_ANA_EAR_COMPANDER_CTL:
+ case WCD939X_ANA_TX_CH1:
+ case WCD939X_ANA_TX_CH2:
+ case WCD939X_ANA_TX_CH3:
+ case WCD939X_ANA_TX_CH4:
+ case WCD939X_ANA_MICB1_MICB2_DSP_EN_LOGIC:
+ case WCD939X_ANA_MICB3_DSP_EN_LOGIC:
+ case WCD939X_ANA_MBHC_MECH:
+ case WCD939X_ANA_MBHC_ELECT:
+ case WCD939X_ANA_MBHC_ZDET:
+ case WCD939X_ANA_MBHC_BTN0:
+ case WCD939X_ANA_MBHC_BTN1:
+ case WCD939X_ANA_MBHC_BTN2:
+ case WCD939X_ANA_MBHC_BTN3:
+ case WCD939X_ANA_MBHC_BTN4:
+ case WCD939X_ANA_MBHC_BTN5:
+ case WCD939X_ANA_MBHC_BTN6:
+ case WCD939X_ANA_MBHC_BTN7:
+ case WCD939X_ANA_MICB1:
+ case WCD939X_ANA_MICB2:
+ case WCD939X_ANA_MICB2_RAMP:
+ case WCD939X_ANA_MICB3:
+ case WCD939X_ANA_MICB4:
+ case WCD939X_BIAS_CTL:
+ case WCD939X_BIAS_VBG_FINE_ADJ:
+ case WCD939X_LDOL_VDDCX_ADJUST:
+ case WCD939X_LDOL_DISABLE_LDOL:
+ case WCD939X_MBHC_CTL_CLK:
+ case WCD939X_MBHC_CTL_ANA:
+ case WCD939X_MBHC_ZDET_VNEG_CTL:
+ case WCD939X_MBHC_ZDET_BIAS_CTL:
+ case WCD939X_MBHC_CTL_BCS:
+ case WCD939X_MBHC_TEST_CTL:
+ case WCD939X_LDOH_MODE:
+ case WCD939X_LDOH_BIAS:
+ case WCD939X_LDOH_STB_LOADS:
+ case WCD939X_LDOH_SLOWRAMP:
+ case WCD939X_MICB1_TEST_CTL_1:
+ case WCD939X_MICB1_TEST_CTL_2:
+ case WCD939X_MICB1_TEST_CTL_3:
+ case WCD939X_MICB2_TEST_CTL_1:
+ case WCD939X_MICB2_TEST_CTL_2:
+ case WCD939X_MICB2_TEST_CTL_3:
+ case WCD939X_MICB3_TEST_CTL_1:
+ case WCD939X_MICB3_TEST_CTL_2:
+ case WCD939X_MICB3_TEST_CTL_3:
+ case WCD939X_MICB4_TEST_CTL_1:
+ case WCD939X_MICB4_TEST_CTL_2:
+ case WCD939X_MICB4_TEST_CTL_3:
+ case WCD939X_TX_COM_ADC_VCM:
+ case WCD939X_TX_COM_BIAS_ATEST:
+ case WCD939X_TX_COM_SPARE1:
+ case WCD939X_TX_COM_SPARE2:
+ case WCD939X_TX_COM_TXFE_DIV_CTL:
+ case WCD939X_TX_COM_TXFE_DIV_START:
+ case WCD939X_TX_COM_SPARE3:
+ case WCD939X_TX_COM_SPARE4:
+ case WCD939X_TX_1_2_TEST_EN:
+ case WCD939X_TX_1_2_ADC_IB:
+ case WCD939X_TX_1_2_ATEST_REFCTL:
+ case WCD939X_TX_1_2_TEST_CTL:
+ case WCD939X_TX_1_2_TEST_BLK_EN1:
+ case WCD939X_TX_1_2_TXFE1_CLKDIV:
+ case WCD939X_TX_3_4_TEST_EN:
+ case WCD939X_TX_3_4_ADC_IB:
+ case WCD939X_TX_3_4_ATEST_REFCTL:
+ case WCD939X_TX_3_4_TEST_CTL:
+ case WCD939X_TX_3_4_TEST_BLK_EN3:
+ case WCD939X_TX_3_4_TXFE3_CLKDIV:
+ case WCD939X_TX_3_4_TEST_BLK_EN2:
+ case WCD939X_TX_3_4_TXFE2_CLKDIV:
+ case WCD939X_TX_3_4_SPARE1:
+ case WCD939X_TX_3_4_TEST_BLK_EN4:
+ case WCD939X_TX_3_4_TXFE4_CLKDIV:
+ case WCD939X_TX_3_4_SPARE2:
+ case WCD939X_CLASSH_MODE_1:
+ case WCD939X_CLASSH_MODE_2:
+ case WCD939X_CLASSH_MODE_3:
+ case WCD939X_CLASSH_CTRL_VCL_1:
+ case WCD939X_CLASSH_CTRL_VCL_2:
+ case WCD939X_CLASSH_CTRL_CCL_1:
+ case WCD939X_CLASSH_CTRL_CCL_2:
+ case WCD939X_CLASSH_CTRL_CCL_3:
+ case WCD939X_CLASSH_CTRL_CCL_4:
+ case WCD939X_CLASSH_CTRL_CCL_5:
+ case WCD939X_CLASSH_BUCK_TMUX_A_D:
+ case WCD939X_CLASSH_BUCK_SW_DRV_CNTL:
+ case WCD939X_CLASSH_SPARE:
+ case WCD939X_FLYBACK_EN:
+ case WCD939X_FLYBACK_VNEG_CTRL_1:
+ case WCD939X_FLYBACK_VNEG_CTRL_2:
+ case WCD939X_FLYBACK_VNEG_CTRL_3:
+ case WCD939X_FLYBACK_VNEG_CTRL_4:
+ case WCD939X_FLYBACK_VNEG_CTRL_5:
+ case WCD939X_FLYBACK_VNEG_CTRL_6:
+ case WCD939X_FLYBACK_VNEG_CTRL_7:
+ case WCD939X_FLYBACK_VNEG_CTRL_8:
+ case WCD939X_FLYBACK_VNEG_CTRL_9:
+ case WCD939X_FLYBACK_VNEGDAC_CTRL_1:
+ case WCD939X_FLYBACK_VNEGDAC_CTRL_2:
+ case WCD939X_FLYBACK_VNEGDAC_CTRL_3:
+ case WCD939X_FLYBACK_CTRL_1:
+ case WCD939X_FLYBACK_TEST_CTL:
+ case WCD939X_RX_AUX_SW_CTL:
+ case WCD939X_RX_PA_AUX_IN_CONN:
+ case WCD939X_RX_TIMER_DIV:
+ case WCD939X_RX_OCP_CTL:
+ case WCD939X_RX_OCP_COUNT:
+ case WCD939X_RX_BIAS_EAR_DAC:
+ case WCD939X_RX_BIAS_EAR_AMP:
+ case WCD939X_RX_BIAS_HPH_LDO:
+ case WCD939X_RX_BIAS_HPH_PA:
+ case WCD939X_RX_BIAS_HPH_RDACBUFF_CNP2:
+ case WCD939X_RX_BIAS_HPH_RDAC_LDO:
+ case WCD939X_RX_BIAS_HPH_CNP1:
+ case WCD939X_RX_BIAS_HPH_LOWPOWER:
+ case WCD939X_RX_BIAS_AUX_DAC:
+ case WCD939X_RX_BIAS_AUX_AMP:
+ case WCD939X_RX_BIAS_VNEGDAC_BLEEDER:
+ case WCD939X_RX_BIAS_MISC:
+ case WCD939X_RX_BIAS_BUCK_RST:
+ case WCD939X_RX_BIAS_BUCK_VREF_ERRAMP:
+ case WCD939X_RX_BIAS_FLYB_ERRAMP:
+ case WCD939X_RX_BIAS_FLYB_BUFF:
+ case WCD939X_RX_BIAS_FLYB_MID_RST:
+ case WCD939X_HPH_CNP_EN:
+ case WCD939X_HPH_CNP_WG_CTL:
+ case WCD939X_HPH_CNP_WG_TIME:
+ case WCD939X_HPH_OCP_CTL:
+ case WCD939X_HPH_AUTO_CHOP:
+ case WCD939X_HPH_CHOP_CTL:
+ case WCD939X_HPH_PA_CTL1:
+ case WCD939X_HPH_PA_CTL2:
+ case WCD939X_HPH_L_EN:
+ case WCD939X_HPH_L_TEST:
+ case WCD939X_HPH_L_ATEST:
+ case WCD939X_HPH_R_EN:
+ case WCD939X_HPH_R_TEST:
+ case WCD939X_HPH_R_ATEST:
+ case WCD939X_HPH_RDAC_CLK_CTL1:
+ case WCD939X_HPH_RDAC_CLK_CTL2:
+ case WCD939X_HPH_RDAC_LDO_CTL:
+ case WCD939X_HPH_RDAC_CHOP_CLK_LP_CTL:
+ case WCD939X_HPH_REFBUFF_UHQA_CTL:
+ case WCD939X_HPH_REFBUFF_LP_CTL:
+ case WCD939X_HPH_L_DAC_CTL:
+ case WCD939X_HPH_R_DAC_CTL:
+ case WCD939X_HPH_SURGE_COMP_SEL:
+ case WCD939X_HPH_SURGE_EN:
+ case WCD939X_HPH_SURGE_MISC1:
+ case WCD939X_EAR_EN:
+ case WCD939X_EAR_PA_CON:
+ case WCD939X_EAR_SP_CON:
+ case WCD939X_EAR_DAC_CON:
+ case WCD939X_EAR_CNP_FSM_CON:
+ case WCD939X_EAR_TEST_CTL:
+ case WCD939X_FLYBACK_NEW_CTRL_2:
+ case WCD939X_FLYBACK_NEW_CTRL_3:
+ case WCD939X_FLYBACK_NEW_CTRL_4:
+ case WCD939X_ANA_NEW_PAGE:
+ case WCD939X_HPH_NEW_ANA_HPH2:
+ case WCD939X_HPH_NEW_ANA_HPH3:
+ case WCD939X_SLEEP_CTL:
+ case WCD939X_SLEEP_WATCHDOG_CTL:
+ case WCD939X_MBHC_NEW_ELECT_REM_CLAMP_CTL:
+ case WCD939X_MBHC_NEW_CTL_1:
+ case WCD939X_MBHC_NEW_CTL_2:
+ case WCD939X_MBHC_NEW_PLUG_DETECT_CTL:
+ case WCD939X_MBHC_NEW_ZDET_ANA_CTL:
+ case WCD939X_MBHC_NEW_ZDET_RAMP_CTL:
+ case WCD939X_TX_NEW_CH12_MUX:
+ case WCD939X_TX_NEW_CH34_MUX:
+ case WCD939X_DIE_CRACK_DET_EN:
+ case WCD939X_HPH_NEW_INT_RDAC_GAIN_CTL:
+ case WCD939X_HPH_NEW_INT_PA_GAIN_CTL_L:
+ case WCD939X_HPH_NEW_INT_RDAC_VREF_CTL:
+ case WCD939X_HPH_NEW_INT_RDAC_OVERRIDE_CTL:
+ case WCD939X_HPH_NEW_INT_PA_GAIN_CTL_R:
+ case WCD939X_HPH_NEW_INT_PA_MISC1:
+ case WCD939X_HPH_NEW_INT_PA_MISC2:
+ case WCD939X_HPH_NEW_INT_PA_RDAC_MISC:
+ case WCD939X_HPH_NEW_INT_TIMER1:
+ case WCD939X_HPH_NEW_INT_TIMER2:
+ case WCD939X_HPH_NEW_INT_TIMER3:
+ case WCD939X_HPH_NEW_INT_TIMER4:
+ case WCD939X_HPH_NEW_INT_PA_RDAC_MISC2:
+ case WCD939X_HPH_NEW_INT_PA_RDAC_MISC3:
+ case WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L:
+ case WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R:
+ case WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI:
+ case WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_ULP:
+ case WCD939X_RX_NEW_INT_HPH_RDAC_LDO_LP:
+ case WCD939X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL:
+ case WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL:
+ case WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT:
+ case WCD939X_MBHC_NEW_INT_ZDET_CLK_AND_MOISTURE_CTL_NEW:
+ case WCD939X_EAR_INT_NEW_CHOPPER_CON:
+ case WCD939X_EAR_INT_NEW_CNP_VCM_CON1:
+ case WCD939X_EAR_INT_NEW_CNP_VCM_CON2:
+ case WCD939X_EAR_INT_NEW_DYNAMIC_BIAS:
+ case WCD939X_SLEEP_INT_WATCHDOG_CTL_1:
+ case WCD939X_SLEEP_INT_WATCHDOG_CTL_2:
+ case WCD939X_DIE_CRACK_INT_DET_INT1:
+ case WCD939X_DIE_CRACK_INT_DET_INT2:
+ case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L2:
+ case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L1:
+ case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L0:
+ case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP1P2M:
+ case WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP0P6M:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L2L1:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L0:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_ULP:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L2L1:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L0:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_L2L1L0:
+ case WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP:
+ case WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L2L1:
+ case WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L0ULP:
+ case WCD939X_TX_COM_NEW_INT_ADC_INT_L2:
+ case WCD939X_TX_COM_NEW_INT_ADC_INT_L1:
+ case WCD939X_TX_COM_NEW_INT_ADC_INT_L0:
+ case WCD939X_TX_COM_NEW_INT_ADC_INT_ULP:
+ case WCD939X_DIGITAL_PAGE:
+ case WCD939X_DIGITAL_SWR_TX_CLK_RATE:
+ case WCD939X_DIGITAL_CDC_RST_CTL:
+ case WCD939X_DIGITAL_TOP_CLK_CFG:
+ case WCD939X_DIGITAL_CDC_ANA_CLK_CTL:
+ case WCD939X_DIGITAL_CDC_DIG_CLK_CTL:
+ case WCD939X_DIGITAL_SWR_RST_EN:
+ case WCD939X_DIGITAL_CDC_PATH_MODE:
+ case WCD939X_DIGITAL_CDC_RX_RST:
+ case WCD939X_DIGITAL_CDC_RX0_CTL:
+ case WCD939X_DIGITAL_CDC_RX1_CTL:
+ case WCD939X_DIGITAL_CDC_RX2_CTL:
+ case WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1:
+ case WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3:
+ case WCD939X_DIGITAL_CDC_COMP_CTL_0:
+ case WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A1_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A1_1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A2_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A2_1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A3_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A3_1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A4_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A4_1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A5_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A5_1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A6_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_A7_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_C_0:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_C_1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_C_2:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_C_3:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R1:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R2:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R3:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R4:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R5:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R6:
+ case WCD939X_DIGITAL_CDC_HPH_DSM_R7:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A1_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A1_1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A2_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A2_1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A3_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A3_1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A4_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A4_1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A5_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A5_1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A6_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_A7_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_C_0:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_C_1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_C_2:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_C_3:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R1:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R2:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R3:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R4:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R5:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R6:
+ case WCD939X_DIGITAL_CDC_EAR_DSM_R7:
+ case WCD939X_DIGITAL_CDC_HPH_GAIN_RX_0:
+ case WCD939X_DIGITAL_CDC_HPH_GAIN_RX_1:
+ case WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_0:
+ case WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_1:
+ case WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_2:
+ case WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_0:
+ case WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_1:
+ case WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_2:
+ case WCD939X_DIGITAL_CDC_HPH_GAIN_CTL:
+ case WCD939X_DIGITAL_CDC_EAR_GAIN_CTL:
+ case WCD939X_DIGITAL_CDC_EAR_PATH_CTL:
+ case WCD939X_DIGITAL_CDC_SWR_CLH:
+ case WCD939X_DIGITAL_SWR_CLH_BYP:
+ case WCD939X_DIGITAL_CDC_TX0_CTL:
+ case WCD939X_DIGITAL_CDC_TX1_CTL:
+ case WCD939X_DIGITAL_CDC_TX2_CTL:
+ case WCD939X_DIGITAL_CDC_TX_RST:
+ case WCD939X_DIGITAL_CDC_REQ_CTL:
+ case WCD939X_DIGITAL_CDC_RST:
+ case WCD939X_DIGITAL_CDC_AMIC_CTL:
+ case WCD939X_DIGITAL_CDC_DMIC_CTL:
+ case WCD939X_DIGITAL_CDC_DMIC1_CTL:
+ case WCD939X_DIGITAL_CDC_DMIC2_CTL:
+ case WCD939X_DIGITAL_CDC_DMIC3_CTL:
+ case WCD939X_DIGITAL_CDC_DMIC4_CTL:
+ case WCD939X_DIGITAL_EFUSE_PRG_CTL:
+ case WCD939X_DIGITAL_EFUSE_CTL:
+ case WCD939X_DIGITAL_CDC_DMIC_RATE_1_2:
+ case WCD939X_DIGITAL_CDC_DMIC_RATE_3_4:
+ case WCD939X_DIGITAL_PDM_WD_CTL0:
+ case WCD939X_DIGITAL_PDM_WD_CTL1:
+ case WCD939X_DIGITAL_PDM_WD_CTL2:
+ case WCD939X_DIGITAL_INTR_MODE:
+ case WCD939X_DIGITAL_INTR_MASK_0:
+ case WCD939X_DIGITAL_INTR_MASK_1:
+ case WCD939X_DIGITAL_INTR_MASK_2:
+ case WCD939X_DIGITAL_INTR_CLEAR_0:
+ case WCD939X_DIGITAL_INTR_CLEAR_1:
+ case WCD939X_DIGITAL_INTR_CLEAR_2:
+ case WCD939X_DIGITAL_INTR_LEVEL_0:
+ case WCD939X_DIGITAL_INTR_LEVEL_1:
+ case WCD939X_DIGITAL_INTR_LEVEL_2:
+ case WCD939X_DIGITAL_INTR_SET_0:
+ case WCD939X_DIGITAL_INTR_SET_1:
+ case WCD939X_DIGITAL_INTR_SET_2:
+ case WCD939X_DIGITAL_INTR_TEST_0:
+ case WCD939X_DIGITAL_INTR_TEST_1:
+ case WCD939X_DIGITAL_INTR_TEST_2:
+ case WCD939X_DIGITAL_TX_MODE_DBG_EN:
+ case WCD939X_DIGITAL_TX_MODE_DBG_0_1:
+ case WCD939X_DIGITAL_TX_MODE_DBG_2_3:
+ case WCD939X_DIGITAL_LB_IN_SEL_CTL:
+ case WCD939X_DIGITAL_LOOP_BACK_MODE:
+ case WCD939X_DIGITAL_SWR_DAC_TEST:
+ case WCD939X_DIGITAL_SWR_HM_TEST_RX_0:
+ case WCD939X_DIGITAL_SWR_HM_TEST_TX_0:
+ case WCD939X_DIGITAL_SWR_HM_TEST_RX_1:
+ case WCD939X_DIGITAL_SWR_HM_TEST_TX_1:
+ case WCD939X_DIGITAL_SWR_HM_TEST_TX_2:
+ case WCD939X_DIGITAL_PAD_CTL_SWR_0:
+ case WCD939X_DIGITAL_PAD_CTL_SWR_1:
+ case WCD939X_DIGITAL_I2C_CTL:
+ case WCD939X_DIGITAL_CDC_TX_TANGGU_SW_MODE:
+ case WCD939X_DIGITAL_EFUSE_TEST_CTL_0:
+ case WCD939X_DIGITAL_EFUSE_TEST_CTL_1:
+ case WCD939X_DIGITAL_PAD_CTL_PDM_RX0:
+ case WCD939X_DIGITAL_PAD_CTL_PDM_RX1:
+ case WCD939X_DIGITAL_PAD_CTL_PDM_TX0:
+ case WCD939X_DIGITAL_PAD_CTL_PDM_TX1:
+ case WCD939X_DIGITAL_PAD_CTL_PDM_TX2:
+ case WCD939X_DIGITAL_PAD_INP_DIS_0:
+ case WCD939X_DIGITAL_PAD_INP_DIS_1:
+ case WCD939X_DIGITAL_DRIVE_STRENGTH_0:
+ case WCD939X_DIGITAL_DRIVE_STRENGTH_1:
+ case WCD939X_DIGITAL_DRIVE_STRENGTH_2:
+ case WCD939X_DIGITAL_RX_DATA_EDGE_CTL:
+ case WCD939X_DIGITAL_TX_DATA_EDGE_CTL:
+ case WCD939X_DIGITAL_GPIO_MODE:
+ case WCD939X_DIGITAL_PIN_CTL_OE:
+ case WCD939X_DIGITAL_PIN_CTL_DATA_0:
+ case WCD939X_DIGITAL_PIN_CTL_DATA_1:
+ case WCD939X_DIGITAL_DIG_DEBUG_CTL:
+ case WCD939X_DIGITAL_DIG_DEBUG_EN:
+ case WCD939X_DIGITAL_ANA_CSR_DBG_ADD:
+ case WCD939X_DIGITAL_ANA_CSR_DBG_CTL:
+ case WCD939X_DIGITAL_SSP_DBG:
+ case WCD939X_DIGITAL_SPARE_0:
+ case WCD939X_DIGITAL_SPARE_1:
+ case WCD939X_DIGITAL_SPARE_2:
+ case WCD939X_DIGITAL_TX_REQ_FB_CTL_0:
+ case WCD939X_DIGITAL_TX_REQ_FB_CTL_1:
+ case WCD939X_DIGITAL_TX_REQ_FB_CTL_2:
+ case WCD939X_DIGITAL_TX_REQ_FB_CTL_3:
+ case WCD939X_DIGITAL_TX_REQ_FB_CTL_4:
+ case WCD939X_DIGITAL_DEM_BYPASS_DATA0:
+ case WCD939X_DIGITAL_DEM_BYPASS_DATA1:
+ case WCD939X_DIGITAL_DEM_BYPASS_DATA2:
+ case WCD939X_DIGITAL_DEM_BYPASS_DATA3:
+ case WCD939X_DIGITAL_DEM_SECOND_ORDER:
+ case WCD939X_DIGITAL_DSM_CTRL:
+ case WCD939X_DIGITAL_DSM_0_STATIC_DATA_0:
+ case WCD939X_DIGITAL_DSM_0_STATIC_DATA_1:
+ case WCD939X_DIGITAL_DSM_0_STATIC_DATA_2:
+ case WCD939X_DIGITAL_DSM_0_STATIC_DATA_3:
+ case WCD939X_DIGITAL_DSM_1_STATIC_DATA_0:
+ case WCD939X_DIGITAL_DSM_1_STATIC_DATA_1:
+ case WCD939X_DIGITAL_DSM_1_STATIC_DATA_2:
+ case WCD939X_DIGITAL_DSM_1_STATIC_DATA_3:
+ case WCD939X_RX_TOP_PAGE:
+ case WCD939X_RX_TOP_TOP_CFG0:
+ case WCD939X_RX_TOP_HPHL_COMP_WR_LSB:
+ case WCD939X_RX_TOP_HPHL_COMP_WR_MSB:
+ case WCD939X_RX_TOP_HPHL_COMP_LUT:
+ case WCD939X_RX_TOP_HPHR_COMP_WR_LSB:
+ case WCD939X_RX_TOP_HPHR_COMP_WR_MSB:
+ case WCD939X_RX_TOP_HPHR_COMP_LUT:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG1:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG2:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG3:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG4:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG1:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG2:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG3:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG4:
+ case WCD939X_RX_TOP_HPHL_PATH_CFG0:
+ case WCD939X_RX_TOP_HPHL_PATH_CFG1:
+ case WCD939X_RX_TOP_HPHR_PATH_CFG0:
+ case WCD939X_RX_TOP_HPHR_PATH_CFG1:
+ case WCD939X_RX_TOP_PATH_CFG2:
+ case WCD939X_RX_TOP_HPHL_PATH_SEC0:
+ case WCD939X_RX_TOP_HPHL_PATH_SEC1:
+ case WCD939X_RX_TOP_HPHL_PATH_SEC2:
+ case WCD939X_RX_TOP_HPHL_PATH_SEC3:
+ case WCD939X_RX_TOP_HPHR_PATH_SEC0:
+ case WCD939X_RX_TOP_HPHR_PATH_SEC1:
+ case WCD939X_RX_TOP_HPHR_PATH_SEC2:
+ case WCD939X_RX_TOP_HPHR_PATH_SEC3:
+ case WCD939X_RX_TOP_PATH_SEC4:
+ case WCD939X_RX_TOP_PATH_SEC5:
+ case WCD939X_COMPANDER_HPHL_CTL0:
+ case WCD939X_COMPANDER_HPHL_CTL1:
+ case WCD939X_COMPANDER_HPHL_CTL2:
+ case WCD939X_COMPANDER_HPHL_CTL3:
+ case WCD939X_COMPANDER_HPHL_CTL4:
+ case WCD939X_COMPANDER_HPHL_CTL5:
+ case WCD939X_COMPANDER_HPHL_CTL7:
+ case WCD939X_COMPANDER_HPHL_CTL8:
+ case WCD939X_COMPANDER_HPHL_CTL9:
+ case WCD939X_COMPANDER_HPHL_CTL10:
+ case WCD939X_COMPANDER_HPHL_CTL11:
+ case WCD939X_COMPANDER_HPHL_CTL12:
+ case WCD939X_COMPANDER_HPHL_CTL13:
+ case WCD939X_COMPANDER_HPHL_CTL14:
+ case WCD939X_COMPANDER_HPHL_CTL15:
+ case WCD939X_COMPANDER_HPHL_CTL16:
+ case WCD939X_COMPANDER_HPHL_CTL17:
+ case WCD939X_COMPANDER_HPHL_CTL18:
+ case WCD939X_COMPANDER_HPHL_CTL19:
+ case WCD939X_R_CTL0:
+ case WCD939X_R_CTL1:
+ case WCD939X_R_CTL2:
+ case WCD939X_R_CTL3:
+ case WCD939X_R_CTL4:
+ case WCD939X_R_CTL5:
+ case WCD939X_R_CTL7:
+ case WCD939X_R_CTL8:
+ case WCD939X_R_CTL9:
+ case WCD939X_R_CTL10:
+ case WCD939X_R_CTL11:
+ case WCD939X_R_CTL12:
+ case WCD939X_R_CTL13:
+ case WCD939X_R_CTL14:
+ case WCD939X_R_CTL15:
+ case WCD939X_R_CTL16:
+ case WCD939X_R_CTL17:
+ case WCD939X_R_CTL18:
+ case WCD939X_R_CTL19:
+ case WCD939X_E_PATH_CTL:
+ case WCD939X_E_CFG0:
+ case WCD939X_E_CFG1:
+ case WCD939X_E_CFG2:
+ case WCD939X_E_CFG3:
+ case WCD939X_DSD_HPHL_PATH_CTL:
+ case WCD939X_DSD_HPHL_CFG0:
+ case WCD939X_DSD_HPHL_CFG1:
+ case WCD939X_DSD_HPHL_CFG2:
+ case WCD939X_DSD_HPHL_CFG3:
+ case WCD939X_DSD_HPHL_CFG4:
+ case WCD939X_DSD_HPHL_CFG5:
+ case WCD939X_DSD_HPHR_PATH_CTL:
+ case WCD939X_DSD_HPHR_CFG0:
+ case WCD939X_DSD_HPHR_CFG1:
+ case WCD939X_DSD_HPHR_CFG2:
+ case WCD939X_DSD_HPHR_CFG3:
+ case WCD939X_DSD_HPHR_CFG4:
+ case WCD939X_DSD_HPHR_CFG5:
+ return true;
+ }
+
+ return false;
+}
+
+static bool wcd939x_readable_register(struct device *dev, unsigned int reg)
+{
+ /* Read-Only Registers */
+ switch (reg) {
+ case WCD939X_ANA_MBHC_RESULT_1:
+ case WCD939X_ANA_MBHC_RESULT_2:
+ case WCD939X_ANA_MBHC_RESULT_3:
+ case WCD939X_MBHC_MOISTURE_DET_FSM_STATUS:
+ case WCD939X_TX_1_2_SAR2_ERR:
+ case WCD939X_TX_1_2_SAR1_ERR:
+ case WCD939X_TX_3_4_SAR4_ERR:
+ case WCD939X_TX_3_4_SAR3_ERR:
+ case WCD939X_HPH_L_STATUS:
+ case WCD939X_HPH_R_STATUS:
+ case WCD939X_HPH_SURGE_STATUS:
+ case WCD939X_EAR_STATUS_REG_1:
+ case WCD939X_EAR_STATUS_REG_2:
+ case WCD939X_MBHC_NEW_FSM_STATUS:
+ case WCD939X_MBHC_NEW_ADC_RESULT:
+ case WCD939X_DIE_CRACK_DET_OUT:
+ case WCD939X_DIGITAL_CHIP_ID0:
+ case WCD939X_DIGITAL_CHIP_ID1:
+ case WCD939X_DIGITAL_CHIP_ID2:
+ case WCD939X_DIGITAL_CHIP_ID3:
+ case WCD939X_DIGITAL_INTR_STATUS_0:
+ case WCD939X_DIGITAL_INTR_STATUS_1:
+ case WCD939X_DIGITAL_INTR_STATUS_2:
+ case WCD939X_DIGITAL_SWR_HM_TEST_0:
+ case WCD939X_DIGITAL_SWR_HM_TEST_1:
+ case WCD939X_DIGITAL_EFUSE_T_DATA_0:
+ case WCD939X_DIGITAL_EFUSE_T_DATA_1:
+ case WCD939X_DIGITAL_PIN_STATUS_0:
+ case WCD939X_DIGITAL_PIN_STATUS_1:
+ case WCD939X_DIGITAL_MODE_STATUS_0:
+ case WCD939X_DIGITAL_MODE_STATUS_1:
+ case WCD939X_DIGITAL_EFUSE_REG_0:
+ case WCD939X_DIGITAL_EFUSE_REG_1:
+ case WCD939X_DIGITAL_EFUSE_REG_2:
+ case WCD939X_DIGITAL_EFUSE_REG_3:
+ case WCD939X_DIGITAL_EFUSE_REG_4:
+ case WCD939X_DIGITAL_EFUSE_REG_5:
+ case WCD939X_DIGITAL_EFUSE_REG_6:
+ case WCD939X_DIGITAL_EFUSE_REG_7:
+ case WCD939X_DIGITAL_EFUSE_REG_8:
+ case WCD939X_DIGITAL_EFUSE_REG_9:
+ case WCD939X_DIGITAL_EFUSE_REG_10:
+ case WCD939X_DIGITAL_EFUSE_REG_11:
+ case WCD939X_DIGITAL_EFUSE_REG_12:
+ case WCD939X_DIGITAL_EFUSE_REG_13:
+ case WCD939X_DIGITAL_EFUSE_REG_14:
+ case WCD939X_DIGITAL_EFUSE_REG_15:
+ case WCD939X_DIGITAL_EFUSE_REG_16:
+ case WCD939X_DIGITAL_EFUSE_REG_17:
+ case WCD939X_DIGITAL_EFUSE_REG_18:
+ case WCD939X_DIGITAL_EFUSE_REG_19:
+ case WCD939X_DIGITAL_EFUSE_REG_20:
+ case WCD939X_DIGITAL_EFUSE_REG_21:
+ case WCD939X_DIGITAL_EFUSE_REG_22:
+ case WCD939X_DIGITAL_EFUSE_REG_23:
+ case WCD939X_DIGITAL_EFUSE_REG_24:
+ case WCD939X_DIGITAL_EFUSE_REG_25:
+ case WCD939X_DIGITAL_EFUSE_REG_26:
+ case WCD939X_DIGITAL_EFUSE_REG_27:
+ case WCD939X_DIGITAL_EFUSE_REG_28:
+ case WCD939X_DIGITAL_EFUSE_REG_29:
+ case WCD939X_DIGITAL_EFUSE_REG_30:
+ case WCD939X_DIGITAL_EFUSE_REG_31:
+ case WCD939X_RX_TOP_HPHL_COMP_RD_LSB:
+ case WCD939X_RX_TOP_HPHL_COMP_RD_MSB:
+ case WCD939X_RX_TOP_HPHR_COMP_RD_LSB:
+ case WCD939X_RX_TOP_HPHR_COMP_RD_MSB:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG5:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG6:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG5:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG6:
+ case WCD939X_COMPANDER_HPHL_CTL6:
+ case WCD939X_R_CTL6:
+ return true;
+ }
+
+ return wcd939x_rdwr_register(dev, reg);
+}
+
+static bool wcd939x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WCD939X_ANA_MBHC_RESULT_1:
+ case WCD939X_ANA_MBHC_RESULT_2:
+ case WCD939X_ANA_MBHC_RESULT_3:
+ case WCD939X_MBHC_MOISTURE_DET_FSM_STATUS:
+ case WCD939X_TX_1_2_SAR2_ERR:
+ case WCD939X_TX_1_2_SAR1_ERR:
+ case WCD939X_TX_3_4_SAR4_ERR:
+ case WCD939X_TX_3_4_SAR3_ERR:
+ case WCD939X_HPH_L_STATUS:
+ case WCD939X_HPH_R_STATUS:
+ case WCD939X_HPH_SURGE_STATUS:
+ case WCD939X_EAR_STATUS_REG_1:
+ case WCD939X_EAR_STATUS_REG_2:
+ case WCD939X_MBHC_NEW_FSM_STATUS:
+ case WCD939X_MBHC_NEW_ADC_RESULT:
+ case WCD939X_DIE_CRACK_DET_OUT:
+ case WCD939X_DIGITAL_INTR_STATUS_0:
+ case WCD939X_DIGITAL_INTR_STATUS_1:
+ case WCD939X_DIGITAL_INTR_STATUS_2:
+ case WCD939X_DIGITAL_SWR_HM_TEST_0:
+ case WCD939X_DIGITAL_SWR_HM_TEST_1:
+ case WCD939X_DIGITAL_PIN_STATUS_0:
+ case WCD939X_DIGITAL_PIN_STATUS_1:
+ case WCD939X_DIGITAL_MODE_STATUS_0:
+ case WCD939X_DIGITAL_MODE_STATUS_1:
+ case WCD939X_RX_TOP_HPHL_COMP_RD_LSB:
+ case WCD939X_RX_TOP_HPHL_COMP_RD_MSB:
+ case WCD939X_RX_TOP_HPHR_COMP_RD_LSB:
+ case WCD939X_RX_TOP_HPHR_COMP_RD_MSB:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG5:
+ case WCD939X_RX_TOP_DSD0_DEBUG_CFG6:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG5:
+ case WCD939X_RX_TOP_DSD1_DEBUG_CFG6:
+ case WCD939X_COMPANDER_HPHL_CTL6:
+ case WCD939X_R_CTL6:
+ return true;
+ }
+ return false;
+}
+
+static bool wcd939x_writeable_register(struct device *dev, unsigned int reg)
+{
+ return wcd939x_rdwr_register(dev, reg);
+}
+
+static const struct regmap_config wcd939x_regmap_config = {
+ .name = "wcd939x_csr",
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = wcd939x_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wcd939x_defaults),
+ .max_register = WCD939X_MAX_REGISTER,
+ .readable_reg = wcd939x_readable_register,
+ .writeable_reg = wcd939x_writeable_register,
+ .volatile_reg = wcd939x_volatile_register,
+};
+
+static const struct sdw_slave_ops wcd9390_slave_ops = {
+ .update_status = wcd_update_status,
+ .interrupt_callback = wcd9390_interrupt_callback,
+ .bus_config = wcd_bus_config,
+};
+
+static int wcd9390_probe(struct sdw_slave *pdev, const struct sdw_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct wcd939x_sdw_priv *wcd;
+ int ret;
+
+ wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+ if (!wcd)
+ return -ENOMEM;
+
+ /*
+ * Port map index starts with 0, however the data port for this codec
+ * are from index 1
+ */
+ 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],
+ WCD939X_MAX_TX_SWR_PORTS);
+ } else {
+ ret = of_property_read_u32_array(dev->of_node,
+ "qcom,rx-port-mapping",
+ &pdev->m_port_map[1],
+ WCD939X_MAX_RX_SWR_PORTS);
+ }
+
+ if (ret < 0)
+ dev_info(dev, "Static Port mapping not specified\n");
+
+ wcd->sdev = pdev;
+ dev_set_drvdata(dev, wcd);
+
+ pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
+ SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ pdev->prop.lane_control_support = true;
+ pdev->prop.simple_clk_stop_capable = true;
+ if (wcd->is_tx) {
+ pdev->prop.source_ports = GENMASK(WCD939X_MAX_TX_SWR_PORTS - 1, 0);
+ pdev->prop.src_dpn_prop = wcd939x_tx_dpn_prop;
+ wcd->ch_info = &wcd939x_sdw_tx_ch_info[0];
+ pdev->prop.wake_capable = true;
+ } else {
+ pdev->prop.sink_ports = GENMASK(WCD939X_MAX_RX_SWR_PORTS - 1, 0);
+ pdev->prop.sink_dpn_prop = wcd939x_rx_dpn_prop;
+ wcd->ch_info = &wcd939x_sdw_rx_ch_info[0];
+ }
+
+ if (wcd->is_tx) {
+ /*
+ * Do not use devres here since devres_release_group() could
+ * be called by component_unbind() id the aggregate device
+ * fails to bind.
+ */
+ wcd->regmap = regmap_init_sdw(pdev, &wcd939x_regmap_config);
+ if (IS_ERR(wcd->regmap))
+ return dev_err_probe(dev, PTR_ERR(wcd->regmap),
+ "Regmap init failed\n");
+
+ /* Start in cache-only until device is enumerated */
+ regcache_cache_only(wcd->regmap, true);
+ }
+
+ ret = component_add(dev, &wcd_sdw_component_ops);
+ if (ret)
+ goto err_free_regmap;
+
+ /* Set suspended until aggregate device is bind */
+ pm_runtime_set_suspended(dev);
+
+ return 0;
+
+err_free_regmap:
+ if (wcd->regmap)
+ regmap_exit(wcd->regmap);
+
+ return ret;
+}
+
+static int wcd9390_remove(struct sdw_slave *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ component_del(dev, &wcd_sdw_component_ops);
+
+ if (wcd->regmap)
+ regmap_exit(wcd->regmap);
+
+ return 0;
+}
+
+static const struct sdw_device_id wcd9390_slave_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x10e, 0), /* WCD9390 & WCD9390 RX/TX Device ID */
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, wcd9390_slave_id);
+
+static int wcd939x_sdw_runtime_suspend(struct device *dev)
+{
+ struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ if (wcd->regmap) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ }
+
+ return 0;
+}
+
+static int wcd939x_sdw_runtime_resume(struct device *dev)
+{
+ struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
+
+ if (wcd->regmap) {
+ regcache_cache_only(wcd->regmap, false);
+ regcache_sync(wcd->regmap);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops wcd939x_sdw_pm_ops = {
+ RUNTIME_PM_OPS(wcd939x_sdw_runtime_suspend, wcd939x_sdw_runtime_resume, NULL)
+};
+
+static struct sdw_driver wcd9390_codec_driver = {
+ .probe = wcd9390_probe,
+ .remove = wcd9390_remove,
+ .ops = &wcd9390_slave_ops,
+ .id_table = wcd9390_slave_id,
+ .driver = {
+ .name = "wcd9390-codec",
+ .pm = pm_ptr(&wcd939x_sdw_pm_ops),
+ }
+};
+module_sdw_driver(wcd9390_codec_driver);
+
+MODULE_DESCRIPTION("WCD939X SDW codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
new file mode 100644
index 000000000000..7c5dd0484384
--- /dev/null
+++ b/sound/soc/codecs/wcd939x.c
@@ -0,0 +1,3623 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/component.h>
+#include <sound/tlv.h>
+#include <linux/of_graph.h>
+#include <linux/of.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_altmode.h>
+
+#include "wcd-clsh-v2.h"
+#include "wcd-common.h"
+#include "wcd-mbhc-v2.h"
+#include "wcd939x.h"
+
+#define WCD939X_MAX_MICBIAS (4)
+#define WCD939X_MBHC_MAX_BUTTONS (8)
+#define TX_ADC_MAX (4)
+#define WCD_MBHC_HS_V_MAX 1600
+
+#define CHIPID_WCD9390 0x0
+#define CHIPID_WCD9395 0x5
+
+/* Version major: 1.x */
+#define CHIPID_WCD939X_VER_MAJOR_1 0x0
+/* Version minor: x.1 */
+#define CHIPID_WCD939X_VER_MINOR_1 0x3
+
+enum {
+ WCD939X_VERSION_1_0 = 0,
+ WCD939X_VERSION_1_1,
+ WCD939X_VERSION_2_0,
+};
+
+#define WCD939X_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 |\
+ SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define WCD939X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+#define WCD939X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* Convert from vout ctl to micbias voltage in mV */
+#define WCD_VOUT_CTL_TO_MICB(v) (1000 + (v) * 50)
+#define SWR_CLK_RATE_0P6MHZ (600000)
+#define SWR_CLK_RATE_1P2MHZ (1200000)
+#define SWR_CLK_RATE_2P4MHZ (2400000)
+#define SWR_CLK_RATE_4P8MHZ (4800000)
+#define SWR_CLK_RATE_9P6MHZ (9600000)
+#define SWR_CLK_RATE_11P2896MHZ (1128960)
+
+#define ADC_MODE_VAL_HIFI 0x01
+#define ADC_MODE_VAL_LO_HIF 0x02
+#define ADC_MODE_VAL_NORMAL 0x03
+#define ADC_MODE_VAL_LP 0x05
+#define ADC_MODE_VAL_ULP1 0x09
+#define ADC_MODE_VAL_ULP2 0x0B
+
+/* Z value defined in milliohm */
+#define WCD939X_ZDET_VAL_32 (32000)
+#define WCD939X_ZDET_VAL_400 (400000)
+#define WCD939X_ZDET_VAL_1200 (1200000)
+#define WCD939X_ZDET_VAL_100K (100000000)
+
+/* Z floating defined in ohms */
+#define WCD939X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE)
+#define WCD939X_ZDET_NUM_MEASUREMENTS (900)
+#define WCD939X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14)
+#define WCD939X_MBHC_GET_X1(x) ((x) & 0x3FFF)
+
+/* Z value compared in milliOhm */
+#define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024)
+
+enum {
+ /* INTR_CTRL_INT_MASK_0 */
+ WCD939X_IRQ_MBHC_BUTTON_PRESS_DET = 0,
+ WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET,
+ WCD939X_IRQ_MBHC_ELECT_INS_REM_DET,
+ WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ WCD939X_IRQ_MBHC_SW_DET,
+ WCD939X_IRQ_HPHR_OCP_INT,
+ WCD939X_IRQ_HPHR_CNP_INT,
+ WCD939X_IRQ_HPHL_OCP_INT,
+
+ /* INTR_CTRL_INT_MASK_1 */
+ WCD939X_IRQ_HPHL_CNP_INT,
+ WCD939X_IRQ_EAR_CNP_INT,
+ WCD939X_IRQ_EAR_SCD_INT,
+ WCD939X_IRQ_HPHL_PDM_WD_INT,
+ WCD939X_IRQ_HPHR_PDM_WD_INT,
+ WCD939X_IRQ_EAR_PDM_WD_INT,
+
+ /* INTR_CTRL_INT_MASK_2 */
+ WCD939X_IRQ_MBHC_MOISTURE_INT,
+ WCD939X_IRQ_HPHL_SURGE_DET_INT,
+ WCD939X_IRQ_HPHR_SURGE_DET_INT,
+ WCD939X_NUM_IRQS,
+};
+
+enum {
+ MICB_BIAS_DISABLE = 0,
+ MICB_BIAS_ENABLE,
+ MICB_BIAS_PULL_UP,
+ MICB_BIAS_PULL_DOWN,
+};
+
+enum {
+ WCD_ADC1 = 0,
+ WCD_ADC2,
+ WCD_ADC3,
+ WCD_ADC4,
+ HPH_PA_DELAY,
+};
+
+enum {
+ ADC_MODE_INVALID = 0,
+ ADC_MODE_HIFI,
+ ADC_MODE_LO_HIF,
+ ADC_MODE_NORMAL,
+ ADC_MODE_LP,
+ ADC_MODE_ULP1,
+ ADC_MODE_ULP2,
+};
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ NUM_CODEC_DAIS,
+};
+
+static u8 tx_mode_bit[] = {
+ [ADC_MODE_INVALID] = 0x00,
+ [ADC_MODE_HIFI] = 0x01,
+ [ADC_MODE_LO_HIF] = 0x02,
+ [ADC_MODE_NORMAL] = 0x04,
+ [ADC_MODE_LP] = 0x08,
+ [ADC_MODE_ULP1] = 0x10,
+ [ADC_MODE_ULP2] = 0x20,
+};
+
+struct zdet_param {
+ u16 ldo_ctl;
+ u16 noff;
+ u16 nshift;
+ u16 btn5;
+ u16 btn6;
+ u16 btn7;
+};
+
+struct wcd939x_priv {
+ struct sdw_slave *tx_sdw_dev;
+ struct wcd939x_sdw_priv *sdw_priv[NUM_CODEC_DAIS];
+ struct device *txdev;
+ struct device *rxdev;
+ struct device_node *rxnode, *txnode;
+ struct regmap *regmap;
+ struct snd_soc_component *component;
+ /* micb setup lock */
+ struct mutex micb_lock;
+ /* typec handling */
+ bool typec_analog_mux;
+#if IS_ENABLED(CONFIG_TYPEC)
+ enum typec_orientation typec_orientation;
+ unsigned long typec_mode;
+ struct typec_switch *typec_switch;
+#endif /* CONFIG_TYPEC */
+ /* mbhc module */
+ struct wcd_mbhc *wcd_mbhc;
+ struct wcd_mbhc_config mbhc_cfg;
+ struct wcd_mbhc_intr intr_ids;
+ struct wcd_clsh_ctrl *clsh_info;
+ struct wcd_common common;
+ struct irq_domain *virq;
+ struct regmap_irq_chip_data *irq_chip;
+ struct snd_soc_jack *jack;
+ unsigned long status_mask;
+ s32 micb_ref[WCD939X_MAX_MICBIAS];
+ s32 pullup_ref[WCD939X_MAX_MICBIAS];
+ u32 hph_mode;
+ u32 tx_mode[TX_ADC_MAX];
+ int variant;
+ struct gpio_desc *reset_gpio;
+ int hphr_pdm_wd_int;
+ int hphl_pdm_wd_int;
+ int ear_pdm_wd_int;
+ bool comp1_enable;
+ bool comp2_enable;
+ bool ldoh;
+};
+
+static const char * const wcd939x_supplies[] = {
+ "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", "vdd-px",
+};
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static const struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = {
+ WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x30),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD939X_ANA_MBHC_ELECT, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD939X_ANA_MBHC_MECH, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD939X_ANA_MBHC_MECH, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD939X_ANA_MBHC_ELECT, 0x06),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD939X_ANA_MBHC_ELECT, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD939X_MBHC_NEW_CTL_1, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD939X_MBHC_NEW_CTL_2, 0x03),
+ WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD939X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD939X_HPH_OCP_CTL, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x07),
+ WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD939X_ANA_MBHC_ELECT, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD939X_ANA_MICB2, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD939X_HPH_CNP_WG_TIME, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD939X_ANA_HPH, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD939X_ANA_HPH, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD939X_ANA_HPH, 0xC0),
+ WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD939X_ANA_MBHC_RESULT_3, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD939X_MBHC_CTL_BCS, 0x02),
+ WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD939X_MBHC_NEW_CTL_2, 0x70),
+ WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD939X_HPH_PA_CTL2, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD939X_HPH_PA_CTL2, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD939X_HPH_L_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD939X_HPH_R_TEST, 0x01),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x20),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD939X_MBHC_NEW_CTL_1, 0x08),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD939X_MBHC_NEW_FSM_STATUS, 0x40),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD939X_MBHC_NEW_FSM_STATUS, 0x80),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD939X_MBHC_NEW_ADC_RESULT, 0xFF),
+ WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD939X_ANA_MICB2, 0x3F),
+ WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD939X_MBHC_NEW_CTL_1, 0x10),
+ WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD939X_MBHC_NEW_CTL_1, 0x04),
+ WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD939X_ANA_MBHC_ZDET, 0x02),
+};
+
+static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = {
+ REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01),
+ REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02),
+ REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04),
+ REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08),
+ REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_SW_DET, 0, 0x10),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_OCP_INT, 0, 0x20),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_CNP_INT, 0, 0x40),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_OCP_INT, 0, 0x80),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_CNP_INT, 1, 0x01),
+ REGMAP_IRQ_REG(WCD939X_IRQ_EAR_CNP_INT, 1, 0x02),
+ REGMAP_IRQ_REG(WCD939X_IRQ_EAR_SCD_INT, 1, 0x04),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_PDM_WD_INT, 1, 0x20),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_PDM_WD_INT, 1, 0x40),
+ REGMAP_IRQ_REG(WCD939X_IRQ_EAR_PDM_WD_INT, 1, 0x80),
+ REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_MOISTURE_INT, 2, 0x02),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04),
+ REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08),
+};
+
+static const struct regmap_irq_chip wcd939x_regmap_irq_chip = {
+ .name = "wcd939x",
+ .irqs = wcd939x_irqs,
+ .num_irqs = ARRAY_SIZE(wcd939x_irqs),
+ .num_regs = 3,
+ .status_base = WCD939X_DIGITAL_INTR_STATUS_0,
+ .mask_base = WCD939X_DIGITAL_INTR_MASK_0,
+ .ack_base = WCD939X_DIGITAL_INTR_CLEAR_0,
+ .use_ack = 1,
+ .runtime_pm = true,
+ .irq_drv_data = NULL,
+};
+
+static int wcd939x_get_clk_rate(int mode)
+{
+ int rate;
+
+ switch (mode) {
+ case ADC_MODE_ULP2:
+ rate = SWR_CLK_RATE_0P6MHZ;
+ break;
+ case ADC_MODE_ULP1:
+ rate = SWR_CLK_RATE_1P2MHZ;
+ break;
+ case ADC_MODE_LP:
+ rate = SWR_CLK_RATE_4P8MHZ;
+ break;
+ case ADC_MODE_NORMAL:
+ case ADC_MODE_LO_HIF:
+ case ADC_MODE_HIFI:
+ case ADC_MODE_INVALID:
+ default:
+ rate = SWR_CLK_RATE_9P6MHZ;
+ break;
+ }
+
+ return rate;
+}
+
+static int wcd939x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank)
+{
+ u8 mask = (bank ? 0xF0 : 0x0F);
+ u8 val = 0;
+
+ switch (rate) {
+ case SWR_CLK_RATE_0P6MHZ:
+ val = 6;
+ break;
+ case SWR_CLK_RATE_1P2MHZ:
+ val = 5;
+ break;
+ case SWR_CLK_RATE_2P4MHZ:
+ val = 3;
+ break;
+ case SWR_CLK_RATE_4P8MHZ:
+ val = 1;
+ break;
+ case SWR_CLK_RATE_9P6MHZ:
+ default:
+ val = 0;
+ break;
+ }
+
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_SWR_TX_CLK_RATE, mask, val);
+
+ return 0;
+}
+
+static int wcd939x_io_init(struct snd_soc_component *component)
+{
+ snd_soc_component_write_field(component, WCD939X_ANA_BIAS,
+ WCD939X_BIAS_ANALOG_BIAS_EN, true);
+ snd_soc_component_write_field(component, WCD939X_ANA_BIAS,
+ WCD939X_BIAS_PRECHRG_EN, true);
+
+ /* 10 msec delay as per HW requirement */
+ usleep_range(10000, 10010);
+ snd_soc_component_write_field(component, WCD939X_ANA_BIAS,
+ WCD939X_BIAS_PRECHRG_EN, false);
+
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x15);
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x15);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL,
+ WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true);
+
+ snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP,
+ WCD939X_FE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M, 1);
+ snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP,
+ WCD939X_FE_ICTRL_STG2CASC_ULP_VALUE, 4);
+
+ snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP,
+ WCD939X_FE_ICTRL_STG2MAIN_ULP_VALUE, 8);
+
+ snd_soc_component_write_field(component, WCD939X_MICB1_TEST_CTL_1,
+ WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7);
+ snd_soc_component_write_field(component, WCD939X_MICB2_TEST_CTL_1,
+ WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7);
+ snd_soc_component_write_field(component, WCD939X_MICB3_TEST_CTL_1,
+ WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7);
+ snd_soc_component_write_field(component, WCD939X_MICB4_TEST_CTL_1,
+ WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7);
+ snd_soc_component_write_field(component, WCD939X_TX_3_4_TEST_BLK_EN2,
+ WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN, false);
+
+ snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN,
+ WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false);
+ snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN,
+ WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false);
+
+ snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL,
+ WCD939X_OCP_CTL_OCP_FSM_EN, true);
+ snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL,
+ WCD939X_OCP_CTL_SCD_OP_EN, true);
+
+ snd_soc_component_write(component, WCD939X_E_CFG0,
+ WCD939X_CFG0_IDLE_STEREO |
+ WCD939X_CFG0_AUTO_DISABLE_ANC);
+
+ return 0;
+}
+
+static int wcd939x_sdw_connect_port(const struct wcd_sdw_ch_info *ch_info,
+ struct sdw_port_config *port_config,
+ u8 enable)
+{
+ u8 ch_mask, port_num;
+
+ port_num = ch_info->port_num;
+ ch_mask = ch_info->ch_mask;
+
+ port_config->num = port_num;
+
+ if (enable)
+ port_config->ch_mask |= ch_mask;
+ else
+ port_config->ch_mask &= ~ch_mask;
+
+ return 0;
+}
+
+static int wcd939x_connect_port(struct wcd939x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable)
+{
+ return wcd939x_sdw_connect_port(&wcd->ch_info[ch_id],
+ &wcd->port_config[port_num - 1],
+ enable);
+}
+
+static int wcd939x_codec_enable_rxclk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, true);
+
+ /* Analog path clock controls */
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN,
+ true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN,
+ true);
+
+ /* Digital path clock controls */
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_VNEG_EN, false);
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_VPOS_EN, false);
+
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, false);
+
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN,
+ false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN,
+ false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, false);
+
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, false);
+
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_hphl_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1,
+ WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN,
+ false);
+
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL,
+ WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x1d);
+ if (wcd939x->comp1_enable) {
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_COMP_CTL_0,
+ WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN,
+ true);
+ /* 5msec compander delay as per HW requirement */
+ if (!wcd939x->comp2_enable ||
+ snd_soc_component_read_field(component,
+ WCD939X_DIGITAL_CDC_COMP_CTL_0,
+ WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN))
+ usleep_range(5000, 5010);
+
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1,
+ WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN,
+ false);
+ } else {
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_COMP_CTL_0,
+ WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN,
+ false);
+ snd_soc_component_write_field(component, WCD939X_HPH_L_EN,
+ WCD939X_L_EN_GAIN_SOURCE_SEL, true);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+ WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 1);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL,
+ WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, false);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_hphr_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1,
+ WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN,
+ false);
+
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL,
+ WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x1d);
+ if (wcd939x->comp2_enable) {
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_COMP_CTL_0,
+ WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN,
+ true);
+ /* 5msec compander delay as per HW requirement */
+ if (!wcd939x->comp1_enable ||
+ snd_soc_component_read_field(component,
+ WCD939X_DIGITAL_CDC_COMP_CTL_0,
+ WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN))
+ usleep_range(5000, 5010);
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1,
+ WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN,
+ false);
+ } else {
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_COMP_CTL_0,
+ WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN,
+ false);
+ snd_soc_component_write_field(component, WCD939X_HPH_R_EN,
+ WCD939X_R_EN_GAIN_SOURCE_SEL, true);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+ WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 1);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL,
+ WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, false);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_ear_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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_EAR_GAIN_CTL,
+ WCD939X_CDC_EAR_GAIN_CTL_EAR_EN, true);
+
+ snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON,
+ WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, false);
+
+ /* 5 msec delay as per HW requirement */
+ usleep_range(5000, 5010);
+ wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_EAR, CLS_AB_HIFI);
+
+ snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4,
+ WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON,
+ WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd939x->hph_mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (wcd939x->ldoh)
+ snd_soc_component_write_field(component, WCD939X_LDOH_MODE,
+ WCD939X_MODE_LDOH_EN, true);
+
+ wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHR, hph_mode);
+ wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI);
+
+ if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP)
+ snd_soc_component_write_field(component,
+ WCD939X_HPH_REFBUFF_LP_CTL,
+ WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, true);
+ if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_PWR_LEVEL, 0);
+
+ snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4,
+ WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd);
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHR_REF_ENABLE, true);
+
+ if (snd_soc_component_read_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHL_REF_ENABLE))
+ usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */
+
+ set_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1,
+ WCD939X_PDM_WD_CTL1_PDM_WD_EN, 3);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 7ms sleep is required if compander is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) {
+ if (!wcd939x->comp2_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+
+ if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_ULP)
+ snd_soc_component_write_field(component,
+ WCD939X_HPH_REFBUFF_LP_CTL,
+ WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS,
+ false);
+ clear_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ }
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1,
+ WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true);
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI ||
+ hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI)
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_REGULATOR_MODE,
+ true);
+
+ enable_irq(wcd939x->hphr_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd939x->hphr_pdm_wd_int);
+ /*
+ * 7ms sleep is required if compander is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (!wcd939x->comp2_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHR_ENABLE, false);
+
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_PRE_HPHR_PA_OFF);
+ set_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 7ms sleep is required if compander is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) {
+ if (!wcd939x->comp2_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ }
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_POST_HPHR_PA_OFF);
+
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHR_REF_ENABLE, false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1,
+ WCD939X_PDM_WD_CTL1_PDM_WD_EN, 0);
+
+ wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHR, hph_mode);
+ if (wcd939x->ldoh)
+ snd_soc_component_write_field(component, WCD939X_LDOH_MODE,
+ WCD939X_MODE_LDOH_EN, false);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ int hph_mode = wcd939x->hph_mode;
+
+ dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__,
+ w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (wcd939x->ldoh)
+ snd_soc_component_write_field(component, WCD939X_LDOH_MODE,
+ WCD939X_MODE_LDOH_EN, true);
+ wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHL, hph_mode);
+ wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI);
+
+ if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP)
+ snd_soc_component_write_field(component,
+ WCD939X_HPH_REFBUFF_LP_CTL,
+ WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS,
+ true);
+ if (hph_mode == CLS_H_LOHIFI)
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_PWR_LEVEL, 0);
+
+ snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4,
+ WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd);
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHL_REF_ENABLE, true);
+
+ if (snd_soc_component_read_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHR_REF_ENABLE))
+ usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */
+
+ set_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0,
+ WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 7ms sleep is required if compander is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) {
+ if (!wcd939x->comp1_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+ if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI ||
+ hph_mode == CLS_H_ULP)
+ snd_soc_component_write_field(component,
+ WCD939X_HPH_REFBUFF_LP_CTL,
+ WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS,
+ false);
+ clear_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ }
+ snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1,
+ WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true);
+ if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI ||
+ hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI)
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_REGULATOR_MODE,
+ true);
+ enable_irq(wcd939x->hphl_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd939x->hphl_pdm_wd_int);
+ /*
+ * 7ms sleep is required if compander is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (!wcd939x->comp1_enable)
+ usleep_range(20000, 20100);
+ else
+ usleep_range(7000, 7100);
+
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHL_ENABLE, false);
+
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF);
+ set_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 7ms sleep is required if compander is enabled as per
+ * HW requirement. If compander is disabled, then
+ * 20ms delay is required.
+ */
+ if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) {
+ if (!wcd939x->comp1_enable)
+ usleep_range(21000, 21100);
+ else
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd939x->status_mask);
+ }
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_POST_HPHL_PA_OFF);
+ snd_soc_component_write_field(component, WCD939X_ANA_HPH,
+ WCD939X_HPH_HPHL_REF_ENABLE, false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0,
+ WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0);
+ wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHL, hph_mode);
+ if (wcd939x->ldoh)
+ snd_soc_component_write_field(component, WCD939X_LDOH_MODE,
+ WCD939X_MODE_LDOH_EN, false);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Enable watchdog interrupt for HPHL */
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0,
+ WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3);
+ /* For EAR, use CLASS_AB regulator mode */
+ snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES,
+ WCD939X_RX_SUPPLIES_REGULATOR_MODE, true);
+ snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL,
+ WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 6 msec delay as per HW requirement */
+ usleep_range(6000, 6010);
+ enable_irq(wcd939x->ear_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ disable_irq_nosync(wcd939x->ear_pdm_wd_int);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL,
+ WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG,
+ false);
+ /* 7 msec delay as per HW requirement */
+ usleep_range(7000, 7010);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0,
+ WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0);
+ wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_EAR, CLS_AB_HIFI);
+ break;
+ }
+
+ return 0;
+}
+
+/* TX Controls */
+
+static int wcd939x_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u16 dmic_clk_reg, dmic_clk_en_reg;
+ u8 dmic_clk_en_mask;
+ u8 dmic_ctl_mask;
+ u8 dmic_clk_mask;
+
+ switch (w->shift) {
+ case 0:
+ case 1:
+ dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2;
+ dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC1_CTL;
+ dmic_clk_en_mask = WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN;
+ dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE;
+ dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL;
+ break;
+ case 2:
+ case 3:
+ dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2;
+ dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC2_CTL;
+ dmic_clk_en_mask = WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN;
+ dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE;
+ dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL;
+ break;
+ case 4:
+ case 5:
+ dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4;
+ dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC3_CTL;
+ dmic_clk_en_mask = WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN;
+ dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE;
+ dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL;
+ break;
+ case 6:
+ case 7:
+ dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4;
+ dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC4_CTL;
+ dmic_clk_en_mask = WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN;
+ dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE;
+ dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid DMIC Selection\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL,
+ dmic_ctl_mask, false);
+ /* 250us sleep as per HW requirement */
+ usleep_range(250, 260);
+ if (w->shift == 2)
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DMIC2_CTL,
+ WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN,
+ true);
+ /* Setting DMIC clock rate to 2.4MHz */
+ snd_soc_component_write_field(component, dmic_clk_reg,
+ dmic_clk_mask, 3);
+ snd_soc_component_write_field(component, dmic_clk_en_reg,
+ dmic_clk_en_mask, true);
+ /* enable clock scaling */
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL,
+ WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL,
+ WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL,
+ dmic_ctl_mask, 1);
+ if (w->shift == 2)
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DMIC2_CTL,
+ WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN,
+ false);
+ snd_soc_component_write_field(component, dmic_clk_en_reg,
+ dmic_clk_en_mask, 0);
+ break;
+ }
+ return 0;
+}
+
+static int wcd939x_tx_swr_ctrl(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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ int bank;
+ int rate;
+
+ bank = sdw_slave_get_current_bank(wcd939x->sdw_priv[AIF1_CAP]->sdev);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strnstr(w->name, "ADC", sizeof("ADC"))) {
+ int mode = 0;
+
+ if (test_bit(WCD_ADC1, &wcd939x->status_mask))
+ mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC1]];
+ if (test_bit(WCD_ADC2, &wcd939x->status_mask))
+ mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC2]];
+ if (test_bit(WCD_ADC3, &wcd939x->status_mask))
+ mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC3]];
+ if (test_bit(WCD_ADC4, &wcd939x->status_mask))
+ mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC4]];
+
+ if (mode)
+ rate = wcd939x_get_clk_rate(ffs(mode) - 1);
+ else
+ rate = wcd939x_get_clk_rate(ADC_MODE_INVALID);
+ wcd939x_set_swr_clk_rate(component, rate, bank);
+ wcd939x_set_swr_clk_rate(component, rate, !bank);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (strnstr(w->name, "ADC", sizeof("ADC"))) {
+ rate = wcd939x_get_clk_rate(ADC_MODE_INVALID);
+ wcd939x_set_swr_clk_rate(component, rate, !bank);
+ wcd939x_set_swr_clk_rate(component, rate, bank);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_get_adc_mode(int val)
+{
+ int ret = 0;
+
+ switch (val) {
+ case ADC_MODE_INVALID:
+ ret = ADC_MODE_VAL_NORMAL;
+ break;
+ case ADC_MODE_HIFI:
+ ret = ADC_MODE_VAL_HIFI;
+ break;
+ case ADC_MODE_LO_HIF:
+ ret = ADC_MODE_VAL_LO_HIF;
+ break;
+ case ADC_MODE_NORMAL:
+ ret = ADC_MODE_VAL_NORMAL;
+ break;
+ case ADC_MODE_LP:
+ ret = ADC_MODE_VAL_LP;
+ break;
+ case ADC_MODE_ULP1:
+ ret = ADC_MODE_VAL_ULP1;
+ break;
+ case ADC_MODE_ULP2:
+ ret = ADC_MODE_VAL_ULP2;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int wcd939x_codec_enable_adc(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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN,
+ true);
+ set_bit(w->shift, &wcd939x->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN,
+ false);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN,
+ false);
+ clear_bit(w->shift, &wcd939x->status_mask);
+ break;
+ }
+
+ return 0;
+}
+
+static void wcd939x_tx_channel_config(struct snd_soc_component *component,
+ int channel, bool init)
+{
+ int reg, mask;
+
+ switch (channel) {
+ case 0:
+ reg = WCD939X_ANA_TX_CH2;
+ mask = WCD939X_TX_CH2_HPF1_INIT;
+ break;
+ case 1:
+ reg = WCD939X_ANA_TX_CH2;
+ mask = WCD939X_TX_CH2_HPF2_INIT;
+ break;
+ case 2:
+ reg = WCD939X_ANA_TX_CH4;
+ mask = WCD939X_TX_CH4_HPF3_INIT;
+ break;
+ case 3:
+ reg = WCD939X_ANA_TX_CH4;
+ mask = WCD939X_TX_CH4_HPF4_INIT;
+ break;
+ default:
+ return;
+ }
+
+ snd_soc_component_write_field(component, reg, mask, init);
+}
+
+static int wcd939x_adc_enable_req(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 wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ int mode;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL,
+ WCD939X_CDC_REQ_CTL_FS_RATE_4P8, true);
+ snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL,
+ WCD939X_CDC_REQ_CTL_NO_NOTCH, false);
+
+ wcd939x_tx_channel_config(component, w->shift, true);
+ mode = wcd939x_get_adc_mode(wcd939x->tx_mode[w->shift]);
+ if (mode < 0) {
+ dev_info(component->dev, "Invalid ADC mode\n");
+ return -EINVAL;
+ }
+
+ switch (w->shift) {
+ case 0:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1,
+ WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE,
+ mode);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN,
+ true);
+ break;
+ case 1:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1,
+ WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE,
+ mode);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN,
+ true);
+ break;
+ case 2:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3,
+ WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE,
+ mode);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN,
+ true);
+ break;
+ case 3:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3,
+ WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE,
+ mode);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN,
+ true);
+ break;
+ default:
+ break;
+ }
+
+ wcd939x_tx_channel_config(component, w->shift, false);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ switch (w->shift) {
+ case 0:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1,
+ WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE,
+ false);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN,
+ false);
+ break;
+ case 1:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1,
+ WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE,
+ false);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN,
+ false);
+ break;
+ case 2:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3,
+ WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE,
+ false);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN,
+ false);
+ break;
+ case 3:
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3,
+ WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE,
+ false);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN,
+ false);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_micbias_control(struct snd_soc_component *component,
+ int micb_num, int req, bool is_dapm)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ int micb_index = micb_num - 1;
+ u16 micb_reg;
+
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD939X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD939X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD939X_ANA_MICB3;
+ break;
+ case MIC_BIAS_4:
+ micb_reg = WCD939X_ANA_MICB4;
+ break;
+ default:
+ dev_err(component->dev, "%s: Invalid micbias number: %d\n",
+ __func__, micb_num);
+ return -EINVAL;
+ }
+
+ switch (req) {
+ case MICB_PULLUP_ENABLE:
+ wcd939x->pullup_ref[micb_index]++;
+ if (wcd939x->pullup_ref[micb_index] == 1 &&
+ wcd939x->micb_ref[micb_index] == 0)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_PULL_UP);
+ break;
+ case MICB_PULLUP_DISABLE:
+ if (wcd939x->pullup_ref[micb_index] > 0)
+ wcd939x->pullup_ref[micb_index]--;
+ if (wcd939x->pullup_ref[micb_index] == 0 &&
+ wcd939x->micb_ref[micb_index] == 0)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_DISABLE);
+ break;
+ case MICB_ENABLE:
+ wcd939x->micb_ref[micb_index]++;
+ if (wcd939x->micb_ref[micb_index] == 1) {
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, true);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, true);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, true);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_DIG_CLK_CTL,
+ WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, true);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_ANA_CLK_CTL,
+ WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN,
+ true);
+ snd_soc_component_write_field(component,
+ WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL,
+ WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN,
+ true);
+ snd_soc_component_write_field(component,
+ WCD939X_MICB1_TEST_CTL_2,
+ WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true);
+ snd_soc_component_write_field(component,
+ WCD939X_MICB2_TEST_CTL_2,
+ WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true);
+ snd_soc_component_write_field(component,
+ WCD939X_MICB3_TEST_CTL_2,
+ WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true);
+ snd_soc_component_write_field(component,
+ WCD939X_MICB4_TEST_CTL_2,
+ WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true);
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_ENABLE);
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_ON);
+ }
+ if (micb_num == MIC_BIAS_2 && is_dapm)
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
+ break;
+ case MICB_DISABLE:
+ if (wcd939x->micb_ref[micb_index] > 0)
+ wcd939x->micb_ref[micb_index]--;
+
+ if (wcd939x->micb_ref[micb_index] == 0 &&
+ wcd939x->pullup_ref[micb_index] > 0)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_PULL_UP);
+ else if (wcd939x->micb_ref[micb_index] == 0 &&
+ wcd939x->pullup_ref[micb_index] == 0) {
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_PRE_MICBIAS_2_OFF);
+
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_DISABLE);
+ if (micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_POST_MICBIAS_2_OFF);
+ }
+ if (is_dapm && micb_num == MIC_BIAS_2)
+ wcd_mbhc_event_notify(wcd939x->wcd_mbhc,
+ WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd939x_micbias_control(component, micb_num, MICB_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 1 msec delay as per HW requirement */
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd939x_micbias_control(component, micb_num, MICB_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int micb_num = w->shift;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd939x_micbias_control(component, micb_num,
+ MICB_PULLUP_ENABLE, true);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 1 msec delay as per HW requirement */
+ usleep_range(1000, 1100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd939x_micbias_control(component, micb_num,
+ MICB_PULLUP_DISABLE, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd939x_tx_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int path = e->shift_l;
+
+ ucontrol->value.enumerated.item[0] = wcd939x->tx_mode[path];
+
+ return 0;
+}
+
+static int wcd939x_tx_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int path = e->shift_l;
+
+ if (wcd939x->tx_mode[path] == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ wcd939x->tx_mode[path] = ucontrol->value.enumerated.item[0];
+
+ return 1;
+}
+
+/* RX Controls */
+
+static int wcd939x_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd939x->hph_mode;
+
+ return 0;
+}
+
+static int wcd939x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ u32 mode_val;
+
+ mode_val = ucontrol->value.enumerated.item[0];
+
+ if (mode_val == wcd939x->hph_mode)
+ return 0;
+
+ if (wcd939x->variant == CHIPID_WCD9390) {
+ switch (mode_val) {
+ case CLS_H_NORMAL:
+ case CLS_H_LP:
+ case CLS_AB:
+ case CLS_H_LOHIFI:
+ case CLS_H_ULP:
+ case CLS_AB_LP:
+ case CLS_AB_LOHIFI:
+ wcd939x->hph_mode = mode_val;
+ return 1;
+ }
+ } else {
+ switch (mode_val) {
+ case CLS_H_NORMAL:
+ case CLS_H_HIFI:
+ case CLS_H_LP:
+ case CLS_AB:
+ case CLS_H_LOHIFI:
+ case CLS_H_ULP:
+ case CLS_AB_HIFI:
+ case CLS_AB_LP:
+ case CLS_AB_LOHIFI:
+ wcd939x->hph_mode = mode_val;
+ return 1;
+ }
+ }
+
+ dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__);
+ return -EINVAL;
+}
+
+static int wcd939x_get_compander(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);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ if (mc->shift)
+ ucontrol->value.integer.value[0] = wcd939x->comp2_enable ? 1 : 0;
+ else
+ ucontrol->value.integer.value[0] = wcd939x->comp1_enable ? 1 : 0;
+
+ return 0;
+}
+
+static int wcd939x_set_compander(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);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[AIF1_PB];
+ bool value = !!ucontrol->value.integer.value[0];
+ int portidx = wcd->ch_info[mc->reg].port_num;
+
+ if (mc->shift)
+ wcd939x->comp2_enable = value;
+ else
+ wcd939x->comp1_enable = value;
+
+ if (value)
+ wcd939x_connect_port(wcd, portidx, mc->reg, true);
+ else
+ wcd939x_connect_port(wcd, portidx, mc->reg, false);
+
+ return 1;
+}
+
+static int wcd939x_ldoh_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd939x->ldoh ? 1 : 0;
+
+ return 0;
+}
+
+static int wcd939x_ldoh_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ if (wcd939x->ldoh == !!ucontrol->value.integer.value[0])
+ return 0;
+
+ wcd939x->ldoh = !!ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+static const char * const tx_mode_mux_text_wcd9390[] = {
+ "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
+};
+
+static const struct soc_enum tx0_mode_mux_enum_wcd9390 =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9390),
+ tx_mode_mux_text_wcd9390);
+
+static const struct soc_enum tx1_mode_mux_enum_wcd9390 =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9390),
+ tx_mode_mux_text_wcd9390);
+
+static const struct soc_enum tx2_mode_mux_enum_wcd9390 =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9390),
+ tx_mode_mux_text_wcd9390);
+
+static const struct soc_enum tx3_mode_mux_enum_wcd9390 =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9390),
+ tx_mode_mux_text_wcd9390);
+
+static const char * const tx_mode_mux_text[] = {
+ "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP",
+ "ADC_ULP1", "ADC_ULP2",
+};
+
+static const struct soc_enum tx0_mode_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text),
+ tx_mode_mux_text);
+
+static const struct soc_enum tx1_mode_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text),
+ tx_mode_mux_text);
+
+static const struct soc_enum tx2_mode_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text),
+ tx_mode_mux_text);
+
+static const struct soc_enum tx3_mode_mux_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text),
+ tx_mode_mux_text);
+
+static const char * const rx_hph_mode_mux_text_wcd9390[] = {
+ "CLS_H_NORMAL", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB",
+ "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP",
+ "CLS_AB_LOHIFI",
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum_wcd9390 =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9390),
+ rx_hph_mode_mux_text_wcd9390);
+
+static const char * const rx_hph_mode_mux_text[] = {
+ "CLS_H_NORMAL", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI",
+ "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI",
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
+ rx_hph_mode_mux_text);
+
+static const struct snd_kcontrol_new wcd9390_snd_controls[] = {
+ SOC_SINGLE_TLV("EAR_PA Volume", WCD939X_ANA_EAR_COMPANDER_CTL,
+ 2, 0x10, 0, ear_pa_gain),
+
+ SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9390,
+ wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put),
+
+ SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum_wcd9390,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+ SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum_wcd9390,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+ SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum_wcd9390,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+ SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum_wcd9390,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+};
+
+static const struct snd_kcontrol_new wcd9395_snd_controls[] = {
+ SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+ wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put),
+
+ SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+ SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+ SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+ SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum,
+ wcd939x_tx_mode_get, wcd939x_tx_mode_put),
+};
+
+static const struct snd_kcontrol_new adc1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new adc4_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic4_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic5_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic6_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic7_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new dmic8_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const adc1_mux_text[] = {
+ "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4", "CH1_AMIC5"
+};
+
+static const struct soc_enum adc1_enum =
+ SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 0,
+ ARRAY_SIZE(adc1_mux_text), adc1_mux_text);
+
+static const struct snd_kcontrol_new tx_adc1_mux =
+ SOC_DAPM_ENUM("ADC1 MUX Mux", adc1_enum);
+
+static const char * const adc2_mux_text[] = {
+ "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4", "CH2_AMIC5"
+};
+
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 3,
+ ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+ SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const char * const adc3_mux_text[] = {
+ "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4", "CH3_AMIC5"
+};
+
+static const struct soc_enum adc3_enum =
+ SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 0,
+ ARRAY_SIZE(adc3_mux_text), adc3_mux_text);
+
+static const struct snd_kcontrol_new tx_adc3_mux =
+ SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum);
+
+static const char * const adc4_mux_text[] = {
+ "CH4_AMIC_DISABLE", "CH4_AMIC1", "CH4_AMIC3", "CH4_AMIC4", "CH4_AMIC5"
+};
+
+static const struct soc_enum adc4_enum =
+ SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 3,
+ ARRAY_SIZE(adc4_mux_text), adc4_mux_text);
+
+static const struct snd_kcontrol_new tx_adc4_mux =
+ SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum);
+
+static const char * const rdac3_mux_text[] = {
+ "RX3", "RX1"
+};
+
+static const struct soc_enum rdac3_enum =
+ SOC_ENUM_SINGLE(WCD939X_DIGITAL_CDC_EAR_PATH_CTL, 0,
+ ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+
+static const struct snd_kcontrol_new rx_rdac3_mux =
+ SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
+
+static int wcd939x_get_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp);
+ struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift];
+ unsigned int portidx = wcd->ch_info[mixer->reg].port_num;
+
+ ucontrol->value.integer.value[0] = wcd->port_enable[portidx] ? 1 : 0;
+
+ return 0;
+}
+
+static const char *version_to_str(u32 version)
+{
+ switch (version) {
+ case WCD939X_VERSION_1_0:
+ return __stringify(WCD939X_1_0);
+ case WCD939X_VERSION_1_1:
+ return __stringify(WCD939X_1_1);
+ case WCD939X_VERSION_2_0:
+ return __stringify(WCD939X_2_0);
+ }
+ return NULL;
+}
+
+static int wcd939x_set_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp);
+ struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift];
+ unsigned int portidx = wcd->ch_info[mixer->reg].port_num;
+
+ wcd->port_enable[portidx] = !!ucontrol->value.integer.value[0];
+
+ wcd939x_connect_port(wcd, portidx, mixer->reg, wcd->port_enable[portidx]);
+
+ return 1;
+}
+
+/* MBHC Related */
+
+static void wcd939x_mbhc_clk_setup(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_1,
+ WCD939X_CTL_1_RCO_EN, enable);
+}
+
+static void wcd939x_mbhc_mbhc_bias_control(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT,
+ WCD939X_MBHC_ELECT_BIAS_EN, enable);
+}
+
+static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component,
+ int *btn_low, int *btn_high,
+ int num_btn, bool is_micbias)
+{
+ int i, vth;
+
+ if (num_btn > WCD_MBHC_DEF_BUTTONS) {
+ dev_err(component->dev, "%s: invalid number of buttons: %d\n",
+ __func__, num_btn);
+ return;
+ }
+
+ for (i = 0; i < num_btn; i++) {
+ vth = (btn_high[i] * 2) / 25;
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_BTN0 + i,
+ WCD939X_MBHC_BTN0_VTH, vth);
+ dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n",
+ __func__, i, btn_high[i], vth);
+ }
+}
+
+static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num)
+{
+ if (micb_num == MIC_BIAS_2) {
+ u8 val;
+
+ val = FIELD_GET(WCD939X_MICB_ENABLE,
+ snd_soc_component_read(component, WCD939X_ANA_MICB2));
+ if (val == MICB_BIAS_ENABLE)
+ return true;
+ }
+
+ return false;
+}
+
+static void wcd939x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component,
+ int pull_up_cur)
+{
+ /* Default pull up current to 2uA */
+ if (pull_up_cur > HS_PULLUP_I_OFF ||
+ pull_up_cur < HS_PULLUP_I_3P0_UA ||
+ pull_up_cur == HS_PULLUP_I_DEFAULT)
+ pull_up_cur = HS_PULLUP_I_2P0_UA;
+
+ dev_dbg(component->dev, "%s: HS pull up current:%d\n",
+ __func__, pull_up_cur);
+
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT,
+ WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL, pull_up_cur);
+}
+
+static int wcd939x_mbhc_request_micbias(struct snd_soc_component *component,
+ int micb_num, int req)
+{
+ return wcd939x_micbias_control(component, micb_num, req, false);
+}
+
+static void wcd939x_mbhc_micb_ramp_control(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP,
+ WCD939X_MICB2_RAMP_SHIFT_CTL, 3);
+ snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP,
+ WCD939X_MICB2_RAMP_RAMP_ENABLE, true);
+ } else {
+ snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP,
+ WCD939X_MICB2_RAMP_RAMP_ENABLE, false);
+ snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP,
+ WCD939X_MICB2_RAMP_SHIFT_CTL, 0);
+ }
+}
+
+static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
+ int req_volt, int micb_num)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ unsigned int micb_reg, cur_vout_ctl, micb_en;
+ int req_vout_ctl;
+ int ret = 0;
+
+ switch (micb_num) {
+ case MIC_BIAS_1:
+ micb_reg = WCD939X_ANA_MICB1;
+ break;
+ case MIC_BIAS_2:
+ micb_reg = WCD939X_ANA_MICB2;
+ break;
+ case MIC_BIAS_3:
+ micb_reg = WCD939X_ANA_MICB3;
+ break;
+ case MIC_BIAS_4:
+ micb_reg = WCD939X_ANA_MICB4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mutex_lock(&wcd939x->micb_lock);
+
+ /*
+ * If requested micbias voltage is same as current micbias
+ * voltage, then just return. Otherwise, adjust voltage as
+ * per requested value. If micbias is already enabled, then
+ * to avoid slow micbias ramp-up or down enable pull-up
+ * momentarily, change the micbias value and then re-enable
+ * micbias.
+ */
+ micb_en = snd_soc_component_read_field(component, micb_reg,
+ WCD939X_MICB_ENABLE);
+ cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
+ WCD939X_MICB_VOUT_CTL);
+
+ req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
+ if (req_vout_ctl < 0) {
+ ret = req_vout_ctl;
+ goto exit;
+ }
+
+ if (cur_vout_ctl == req_vout_ctl) {
+ ret = 0;
+ goto exit;
+ }
+
+ dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
+ __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
+ req_volt, micb_en);
+
+ if (micb_en == MICB_BIAS_ENABLE)
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_PULL_DOWN);
+
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_VOUT_CTL, req_vout_ctl);
+
+ if (micb_en == MICB_BIAS_ENABLE) {
+ snd_soc_component_write_field(component, micb_reg,
+ WCD939X_MICB_ENABLE,
+ MICB_BIAS_ENABLE);
+ /*
+ * Add 2ms delay as per HW requirement after enabling
+ * micbias
+ */
+ usleep_range(2000, 2100);
+ }
+
+exit:
+ mutex_unlock(&wcd939x->micb_lock);
+ return ret;
+}
+
+static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
+ int micb_num, bool req_en)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ int micb_mv;
+
+ if (micb_num != MIC_BIAS_2)
+ return -EINVAL;
+ /*
+ * If device tree micbias level is already above the minimum
+ * voltage needed to detect threshold microphone, then do
+ * not change the micbias, just return.
+ */
+ if (wcd939x->common.micb_mv[1] >= WCD_MBHC_THR_HS_MICB_MV)
+ return 0;
+
+ micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd939x->common.micb_mv[1];
+
+ return wcd939x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);
+}
+
+/* Selected by WCD939X_MBHC_GET_C1() */
+static const s16 wcd939x_wcd_mbhc_d1_a[4] = {
+ 0, 30, 30, 6
+};
+
+/* Selected by zdet_param.noff */
+static const int wcd939x_mbhc_mincode_param[] = {
+ 3277, 1639, 820, 410, 205, 103, 52, 26
+};
+
+static const struct zdet_param wcd939x_mbhc_zdet_param = {
+ .ldo_ctl = 4,
+ .noff = 0,
+ .nshift = 6,
+ .btn5 = 0x18,
+ .btn6 = 0x60,
+ .btn7 = 0x78,
+};
+
+static void wcd939x_mbhc_get_result_params(struct snd_soc_component *component,
+ int32_t *zdet)
+{
+ const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param;
+ s32 x1, d1, denom;
+ int val;
+ s16 c1;
+ int i;
+
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET,
+ WCD939X_MBHC_ZDET_ZDET_CHG_EN, true);
+ for (i = 0; i < WCD939X_ZDET_NUM_MEASUREMENTS; i++) {
+ val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2,
+ WCD939X_MBHC_RESULT_2_Z_RESULT_MSB);
+ if (val & BIT(7))
+ break;
+ }
+ val = val << 8;
+ val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1,
+ WCD939X_MBHC_RESULT_1_Z_RESULT_LSB);
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET,
+ WCD939X_MBHC_ZDET_ZDET_CHG_EN, false);
+ x1 = WCD939X_MBHC_GET_X1(val);
+ c1 = WCD939X_MBHC_GET_C1(val);
+
+ /* If ramp is not complete, give additional 5ms */
+ if (c1 < 2 && x1)
+ mdelay(5);
+
+ if (!c1 || !x1) {
+ dev_dbg(component->dev,
+ "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n",
+ __func__, c1, x1);
+ goto ramp_down;
+ }
+
+ d1 = wcd939x_wcd_mbhc_d1_a[c1];
+ denom = (x1 * d1) - (1 << (14 - zdet_param->noff));
+ if (denom > 0)
+ *zdet = (WCD939X_ANA_MBHC_ZDET_CONST * 1000) / denom;
+ else if (x1 < wcd939x_mbhc_mincode_param[zdet_param->noff])
+ *zdet = WCD939X_ZDET_FLOATING_IMPEDANCE;
+
+ dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n",
+ __func__, d1, c1, x1, *zdet);
+ramp_down:
+ i = 0;
+ while (x1) {
+ val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1,
+ WCD939X_MBHC_RESULT_1_Z_RESULT_LSB) << 8;
+ val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2,
+ WCD939X_MBHC_RESULT_2_Z_RESULT_MSB);
+ x1 = WCD939X_MBHC_GET_X1(val);
+ i++;
+ if (i == WCD939X_ZDET_NUM_MEASUREMENTS)
+ break;
+ }
+}
+
+static void wcd939x_mbhc_zdet_ramp(struct snd_soc_component *component,
+ s32 *zl, int32_t *zr)
+{
+ const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param;
+ s32 zdet = 0;
+
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD939X_ZDET_ANA_CTL_MAXV_CTL, zdet_param->ldo_ctl);
+ snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN5, WCD939X_MBHC_BTN5_VTH,
+ zdet_param->btn5);
+ snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN6, WCD939X_MBHC_BTN6_VTH,
+ zdet_param->btn6);
+ snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN7, WCD939X_MBHC_BTN7_VTH,
+ zdet_param->btn7);
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL,
+ WCD939X_ZDET_ANA_CTL_RANGE_CTL, zdet_param->noff);
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL,
+ WCD939X_ZDET_RAMP_CTL_TIME_CTL, zdet_param->nshift);
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL,
+ WCD939X_ZDET_RAMP_CTL_ACC1_MIN_CTL, 6); /*acc1_min_63 */
+
+ if (!zl)
+ goto z_right;
+
+ /* Start impedance measurement for HPH_L */
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET,
+ WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, true);
+ dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n",
+ __func__, zdet_param->noff);
+ wcd939x_mbhc_get_result_params(component, &zdet);
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET,
+ WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, false);
+
+ *zl = zdet;
+
+z_right:
+ if (!zr)
+ return;
+
+ /* Start impedance measurement for HPH_R */
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET,
+ WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, true);
+ dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n",
+ __func__, zdet_param->noff);
+ wcd939x_mbhc_get_result_params(component, &zdet);
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET,
+ WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, false);
+
+ *zr = zdet;
+}
+
+static void wcd939x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component,
+ s32 *z_val, int flag_l_r)
+{
+ int q1_cal;
+ s16 q1;
+
+ q1 = snd_soc_component_read(component, WCD939X_DIGITAL_EFUSE_REG_21 + flag_l_r);
+ if (q1 & BIT(7))
+ q1_cal = (10000 - ((q1 & GENMASK(6, 0)) * 10));
+ else
+ q1_cal = (10000 + (q1 * 10));
+
+ if (q1_cal > 0)
+ *z_val = ((*z_val) * 10000) / q1_cal;
+}
+
+static void wcd939x_wcd_mbhc_calc_impedance(struct snd_soc_component *component,
+ u32 *zl, uint32_t *zr)
+{
+ struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev);
+ unsigned int reg0, reg1, reg2, reg3, reg4;
+ int z_mono, z_diff1, z_diff2;
+ bool is_fsm_disable = false;
+ s32 z1l, z1r, z1ls;
+
+ reg0 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN5);
+ reg1 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN6);
+ reg2 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN7);
+ reg3 = snd_soc_component_read(component, WCD939X_MBHC_CTL_CLK);
+ reg4 = snd_soc_component_read(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL);
+
+ if (snd_soc_component_read_field(component, WCD939X_ANA_MBHC_ELECT,
+ WCD939X_MBHC_ELECT_FSM_EN)) {
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT,
+ WCD939X_MBHC_ELECT_FSM_EN, false);
+ is_fsm_disable = true;
+ }
+
+ /* For NO-jack, disable L_DET_EN before Z-det measurements */
+ if (wcd939x->mbhc_cfg.hphl_swh)
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_L_DET_EN, false);
+
+ /* Turn off 100k pull down on HPHL */
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND,
+ false);
+
+ /*
+ * Disable surge protection before impedance detection.
+ * This is done to give correct value for high impedance.
+ */
+ snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN,
+ WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false);
+ snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN,
+ WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false);
+
+ /* 1ms delay needed after disable surge protection */
+ usleep_range(1000, 1010);
+
+ /* First get impedance on Left */
+ wcd939x_mbhc_zdet_ramp(component, &z1l, NULL);
+ if (z1l == WCD939X_ZDET_FLOATING_IMPEDANCE || z1l > WCD939X_ZDET_VAL_100K) {
+ *zl = WCD939X_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zl = z1l / 1000;
+ wcd939x_wcd_mbhc_qfuse_cal(component, zl, 0);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n",
+ __func__, *zl);
+
+ /* Start of right impedance ramp and calculation */
+ wcd939x_mbhc_zdet_ramp(component, NULL, &z1r);
+ if (z1r == WCD939X_ZDET_FLOATING_IMPEDANCE || z1r > WCD939X_ZDET_VAL_100K) {
+ *zr = WCD939X_ZDET_FLOATING_IMPEDANCE;
+ } else {
+ *zr = z1r / 1000;
+ wcd939x_wcd_mbhc_qfuse_cal(component, zr, 1);
+ }
+ dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n",
+ __func__, *zr);
+
+ /* Mono/stereo detection */
+ if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE &&
+ *zr == WCD939X_ZDET_FLOATING_IMPEDANCE) {
+ dev_dbg(component->dev,
+ "%s: plug type is invalid or extension cable\n",
+ __func__);
+ goto zdet_complete;
+ }
+
+ if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE ||
+ *zr == WCD939X_ZDET_FLOATING_IMPEDANCE ||
+ (*zl < WCD_MONO_HS_MIN_THR && *zr > WCD_MONO_HS_MIN_THR) ||
+ (*zl > WCD_MONO_HS_MIN_THR && *zr < WCD_MONO_HS_MIN_THR)) {
+ dev_dbg(component->dev,
+ "%s: Mono plug type with one ch floating or shorted to GND\n",
+ __func__);
+ wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+ goto zdet_complete;
+ }
+
+ snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST,
+ WCD939X_R_ATEST_HPH_GND_OVR, true);
+ snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2,
+ WCD939X_PA_CTL2_HPHPA_GND_R, true);
+ wcd939x_mbhc_zdet_ramp(component, &z1ls, NULL);
+ snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2,
+ WCD939X_PA_CTL2_HPHPA_GND_R, false);
+ snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST,
+ WCD939X_R_ATEST_HPH_GND_OVR, false);
+
+ z1ls /= 1000;
+ wcd939x_wcd_mbhc_qfuse_cal(component, &z1ls, 0);
+
+ /* Parallel of left Z and 9 ohm pull down resistor */
+ z_mono = (*zl * 9) / (*zl + 9);
+ z_diff1 = z1ls > z_mono ? z1ls - z_mono : z_mono - z1ls;
+ z_diff2 = *zl > z1ls ? *zl - z1ls : z1ls - *zl;
+ if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + z_mono))) {
+ dev_dbg(component->dev, "%s: stereo plug type detected\n",
+ __func__);
+ wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_STEREO);
+ } else {
+ dev_dbg(component->dev, "%s: MONO plug type detected\n",
+ __func__);
+ wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO);
+ }
+
+ /* Enable surge protection again after impedance detection */
+ snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN,
+ WCD939X_EN_EN_SURGE_PROTECTION_HPHR, true);
+ snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN,
+ WCD939X_EN_EN_SURGE_PROTECTION_HPHL, true);
+
+zdet_complete:
+ snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN5, reg0);
+ snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN6, reg1);
+ snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN7, reg2);
+
+ /* Turn on 100k pull down on HPHL */
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, true);
+
+ /* For NO-jack, re-enable L_DET_EN after Z-det measurements */
+ if (wcd939x->mbhc_cfg.hphl_swh)
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_L_DET_EN, true);
+
+ snd_soc_component_write(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, reg4);
+ snd_soc_component_write(component, WCD939X_MBHC_CTL_CLK, reg3);
+
+ if (is_fsm_disable)
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT,
+ WCD939X_MBHC_ELECT_FSM_EN, true);
+}
+
+static void wcd939x_mbhc_gnd_det_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN,
+ true);
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_GND_DET_EN, true);
+ } else {
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_GND_DET_EN, false);
+ snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH,
+ WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN,
+ false);
+ }
+}
+
+static void wcd939x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2,
+ WCD939X_PA_CTL2_HPHPA_GND_R, enable);
+ snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2,
+ WCD939X_PA_CTL2_HPHPA_GND_L, enable);
+}
+
+static void wcd939x_mbhc_moisture_config(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) {
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL, R_OFF);
+ return;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd939x->mbhc_cfg.hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL, R_OFF);
+ return;
+ }
+
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL, wcd939x->mbhc_cfg.moist_rref);
+}
+
+static void wcd939x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ if (enable)
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL,
+ wcd939x->mbhc_cfg.moist_rref);
+ else
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL, R_OFF);
+}
+
+static bool wcd939x_mbhc_get_moisture_status(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ bool ret = false;
+
+ if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) {
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL, R_OFF);
+ goto done;
+ }
+
+ /* Do not enable moisture detection if jack type is NC */
+ if (!wcd939x->mbhc_cfg.hphl_swh) {
+ dev_dbg(component->dev, "%s: disable moisture detection for NC\n",
+ __func__);
+ snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL, R_OFF);
+ goto done;
+ }
+
+ /*
+ * If moisture_en is already enabled, then skip to plug type
+ * detection.
+ */
+ if (snd_soc_component_read_field(component, WCD939X_MBHC_NEW_CTL_2,
+ WCD939X_CTL_2_M_RTH_CTL))
+ goto done;
+
+ wcd939x_mbhc_moisture_detect_en(component, true);
+
+ /* Read moisture comparator status, invert of status bit */
+ ret = !snd_soc_component_read_field(component, WCD939X_MBHC_NEW_FSM_STATUS,
+ WCD939X_FSM_STATUS_HS_M_COMP_STATUS);
+done:
+ return ret;
+}
+
+static void wcd939x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component,
+ bool enable)
+{
+ snd_soc_component_write_field(component,
+ WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL,
+ WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_EN_POLLING,
+ enable);
+}
+
+static const struct wcd_mbhc_cb mbhc_cb = {
+ .clk_setup = wcd939x_mbhc_clk_setup,
+ .mbhc_bias = wcd939x_mbhc_mbhc_bias_control,
+ .set_btn_thr = wcd939x_mbhc_program_btn_thr,
+ .micbias_enable_status = wcd939x_mbhc_micb_en_status,
+ .hph_pull_up_control_v2 = wcd939x_mbhc_hph_l_pull_up_control,
+ .mbhc_micbias_control = wcd939x_mbhc_request_micbias,
+ .mbhc_micb_ramp_control = wcd939x_mbhc_micb_ramp_control,
+ .mbhc_micb_ctrl_thr_mic = wcd939x_mbhc_micb_ctrl_threshold_mic,
+ .compute_impedance = wcd939x_wcd_mbhc_calc_impedance,
+ .mbhc_gnd_det_ctrl = wcd939x_mbhc_gnd_det_ctrl,
+ .hph_pull_down_ctrl = wcd939x_mbhc_hph_pull_down_ctrl,
+ .mbhc_moisture_config = wcd939x_mbhc_moisture_config,
+ .mbhc_get_moisture_status = wcd939x_mbhc_get_moisture_status,
+ .mbhc_moisture_polling_ctrl = wcd939x_mbhc_moisture_polling_ctrl,
+ .mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en,
+};
+
+static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd939x->wcd_mbhc);
+
+ return 0;
+}
+
+static int wcd939x_hph_impedance_get(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);
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ bool hphr = mc->shift;
+ u32 zl, zr;
+
+ wcd_mbhc_get_impedance(wcd939x->wcd_mbhc, &zl, &zr);
+ dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr);
+ ucontrol->value.integer.value[0] = hphr ? zr : zl;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new hph_type_detect_controls[] = {
+ SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
+ wcd939x_get_hph_type, NULL),
+};
+
+static const struct snd_kcontrol_new impedance_detect_controls[] = {
+ SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
+ wcd939x_hph_impedance_get, NULL),
+ SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
+ wcd939x_hph_impedance_get, NULL),
+};
+
+static int wcd939x_mbhc_init(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ struct wcd_mbhc_intr *intr_ids = &wcd939x->intr_ids;
+
+ intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_MBHC_SW_DET);
+ intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_MBHC_BUTTON_PRESS_DET);
+ intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET);
+ intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET);
+ intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_MBHC_ELECT_INS_REM_DET);
+ intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_HPHL_OCP_INT);
+ intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_HPHR_OCP_INT);
+
+ wcd939x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true);
+ if (IS_ERR(wcd939x->wcd_mbhc))
+ return PTR_ERR(wcd939x->wcd_mbhc);
+
+ snd_soc_add_component_controls(component, impedance_detect_controls,
+ ARRAY_SIZE(impedance_detect_controls));
+ snd_soc_add_component_controls(component, hph_type_detect_controls,
+ ARRAY_SIZE(hph_type_detect_controls));
+
+ return 0;
+}
+
+static void wcd939x_mbhc_deinit(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ wcd_mbhc_deinit(wcd939x->wcd_mbhc);
+}
+
+/* END MBHC */
+
+static const struct snd_kcontrol_new wcd939x_snd_controls[] = {
+ /* RX Path */
+ SOC_SINGLE_EXT("HPHL_COMP Switch", WCD939X_COMP_L, 0, 1, 0,
+ wcd939x_get_compander, wcd939x_set_compander),
+ SOC_SINGLE_EXT("HPHR_COMP Switch", WCD939X_COMP_R, 1, 1, 0,
+ wcd939x_get_compander, wcd939x_set_compander),
+ SOC_SINGLE_EXT("HPHL Switch", WCD939X_HPH_L, 0, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("HPHR Switch", WCD939X_HPH_R, 0, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("CLSH Switch", WCD939X_CLSH, 0, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("LO Switch", WCD939X_LO, 0, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DSD_L Switch", WCD939X_DSD_L, 0, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DSD_R Switch", WCD939X_DSD_R, 0, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_TLV("HPHL Volume", WCD939X_HPH_L_EN, 0, 20, 1, line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", WCD939X_HPH_R_EN, 0, 20, 1, line_gain),
+ SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0,
+ wcd939x_ldoh_get, wcd939x_ldoh_put),
+
+ /* TX Path */
+ SOC_SINGLE_EXT("ADC1 Switch", WCD939X_ADC1, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("ADC2 Switch", WCD939X_ADC2, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("ADC3 Switch", WCD939X_ADC3, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("ADC4 Switch", WCD939X_ADC4, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC0 Switch", WCD939X_DMIC0, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC1 Switch", WCD939X_DMIC1, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("MBHC Switch", WCD939X_MBHC, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC2 Switch", WCD939X_DMIC2, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC3 Switch", WCD939X_DMIC3, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC4 Switch", WCD939X_DMIC4, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC5 Switch", WCD939X_DMIC5, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC6 Switch", WCD939X_DMIC6, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_EXT("DMIC7 Switch", WCD939X_DMIC7, 1, 1, 0,
+ wcd939x_get_swr_port, wcd939x_set_swr_port),
+ SOC_SINGLE_TLV("ADC1 Volume", WCD939X_ANA_TX_CH1, 0, 20, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", WCD939X_ANA_TX_CH2, 0, 20, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", WCD939X_ANA_TX_CH3, 0, 20, 0,
+ analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", WCD939X_ANA_TX_CH4, 0, 20, 0,
+ analog_gain),
+};
+
+static const struct snd_soc_dapm_widget wcd939x_dapm_widgets[] = {
+ /*input widgets*/
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_INPUT("AMIC4"),
+ SND_SOC_DAPM_INPUT("AMIC5"),
+
+ SND_SOC_DAPM_MIC("Analog Mic1", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic2", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic3", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic5", NULL),
+
+ /* TX widgets */
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd939x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0,
+ wcd939x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0,
+ wcd939x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0,
+ wcd939x_codec_enable_adc,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0,
+ wcd939x_codec_enable_dmic,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, NULL, 0,
+ wcd939x_adc_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, NULL, 0,
+ wcd939x_adc_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, NULL, 0,
+ wcd939x_adc_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, NULL, 0,
+ wcd939x_adc_enable_req,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, &tx_adc1_mux),
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+ SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &tx_adc3_mux),
+ SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, &tx_adc4_mux),
+
+ /* tx mixers */
+ SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0,
+ adc1_switch, ARRAY_SIZE(adc1_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0,
+ adc2_switch, ARRAY_SIZE(adc2_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0,
+ adc3_switch, ARRAY_SIZE(adc3_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0,
+ adc4_switch, ARRAY_SIZE(adc4_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic1_switch, ARRAY_SIZE(dmic1_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic2_switch, ARRAY_SIZE(dmic2_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic3_switch, ARRAY_SIZE(dmic3_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic4_switch, ARRAY_SIZE(dmic4_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic5_switch, ARRAY_SIZE(dmic5_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic6_switch, ARRAY_SIZE(dmic6_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic7_switch, ARRAY_SIZE(dmic7_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, 0,
+ dmic8_switch, ARRAY_SIZE(dmic8_switch), wcd939x_tx_swr_ctrl,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* micbias widgets */
+ SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ wcd939x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ wcd939x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ wcd939x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0,
+ wcd939x_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* micbias pull up widgets */
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0,
+ wcd939x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0,
+ wcd939x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0,
+ wcd939x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0,
+ wcd939x_codec_enable_micbias_pullup,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* output widgets tx */
+ SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT"),
+ SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT"),
+
+ SND_SOC_DAPM_INPUT("IN1_HPHL"),
+ SND_SOC_DAPM_INPUT("IN2_HPHR"),
+ SND_SOC_DAPM_INPUT("IN3_EAR"),
+
+ /* rx widgets */
+ SND_SOC_DAPM_PGA_E("EAR PGA", WCD939X_ANA_EAR, 7, 0, NULL, 0,
+ wcd939x_codec_enable_ear_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PGA", WCD939X_ANA_HPH, 7, 0, NULL, 0,
+ wcd939x_codec_enable_hphl_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHR PGA", WCD939X_ANA_HPH, 6, 0, NULL, 0,
+ wcd939x_codec_enable_hphr_pa,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+ wcd939x_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+ wcd939x_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+ wcd939x_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux),
+
+ SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0,
+ wcd939x_codec_enable_rxclk,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0),
+
+ /* rx mixer widgets */
+ SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+ ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+ hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+ SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+ hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+ /* output widgets rx */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+};
+
+static const struct snd_soc_dapm_route wcd939x_audio_map[] = {
+ /* TX Path */
+ {"ADC1_OUTPUT", NULL, "ADC1_MIXER"},
+ {"ADC1_MIXER", "Switch", "ADC1 REQ"},
+ {"ADC1 REQ", NULL, "ADC1"},
+ {"ADC1", NULL, "ADC1 MUX"},
+ {"ADC1 MUX", "CH1_AMIC1", "AMIC1"},
+ {"ADC1 MUX", "CH1_AMIC2", "AMIC2"},
+ {"ADC1 MUX", "CH1_AMIC3", "AMIC3"},
+ {"ADC1 MUX", "CH1_AMIC4", "AMIC4"},
+ {"ADC1 MUX", "CH1_AMIC5", "AMIC5"},
+
+ {"ADC2_OUTPUT", NULL, "ADC2_MIXER"},
+ {"ADC2_MIXER", "Switch", "ADC2 REQ"},
+ {"ADC2 REQ", NULL, "ADC2"},
+ {"ADC2", NULL, "ADC2 MUX"},
+ {"ADC2 MUX", "CH2_AMIC1", "AMIC1"},
+ {"ADC2 MUX", "CH2_AMIC2", "AMIC2"},
+ {"ADC2 MUX", "CH2_AMIC3", "AMIC3"},
+ {"ADC2 MUX", "CH2_AMIC4", "AMIC4"},
+ {"ADC2 MUX", "CH2_AMIC5", "AMIC5"},
+
+ {"ADC3_OUTPUT", NULL, "ADC3_MIXER"},
+ {"ADC3_MIXER", "Switch", "ADC3 REQ"},
+ {"ADC3 REQ", NULL, "ADC3"},
+ {"ADC3", NULL, "ADC3 MUX"},
+ {"ADC3 MUX", "CH3_AMIC1", "AMIC1"},
+ {"ADC3 MUX", "CH3_AMIC3", "AMIC3"},
+ {"ADC3 MUX", "CH3_AMIC4", "AMIC4"},
+ {"ADC3 MUX", "CH3_AMIC5", "AMIC5"},
+
+ {"ADC4_OUTPUT", NULL, "ADC4_MIXER"},
+ {"ADC4_MIXER", "Switch", "ADC4 REQ"},
+ {"ADC4 REQ", NULL, "ADC4"},
+ {"ADC4", NULL, "ADC4 MUX"},
+ {"ADC4 MUX", "CH4_AMIC1", "AMIC1"},
+ {"ADC4 MUX", "CH4_AMIC3", "AMIC3"},
+ {"ADC4 MUX", "CH4_AMIC4", "AMIC4"},
+ {"ADC4 MUX", "CH4_AMIC5", "AMIC5"},
+
+ {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"},
+ {"DMIC1_MIXER", "Switch", "DMIC1"},
+
+ {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"},
+ {"DMIC2_MIXER", "Switch", "DMIC2"},
+
+ {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"},
+ {"DMIC3_MIXER", "Switch", "DMIC3"},
+
+ {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"},
+ {"DMIC4_MIXER", "Switch", "DMIC4"},
+
+ {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"},
+ {"DMIC5_MIXER", "Switch", "DMIC5"},
+
+ {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"},
+ {"DMIC6_MIXER", "Switch", "DMIC6"},
+
+ {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"},
+ {"DMIC7_MIXER", "Switch", "DMIC7"},
+
+ {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"},
+ {"DMIC8_MIXER", "Switch", "DMIC8"},
+
+ /* RX Path */
+ {"IN1_HPHL", NULL, "VDD_BUCK"},
+ {"IN1_HPHL", NULL, "CLS_H_PORT"},
+
+ {"RX1", NULL, "IN1_HPHL"},
+ {"RX1", NULL, "RXCLK"},
+ {"RDAC1", NULL, "RX1"},
+ {"HPHL_RDAC", "Switch", "RDAC1"},
+ {"HPHL PGA", NULL, "HPHL_RDAC"},
+ {"HPHL", NULL, "HPHL PGA"},
+
+ {"IN2_HPHR", NULL, "VDD_BUCK"},
+ {"IN2_HPHR", NULL, "CLS_H_PORT"},
+ {"RX2", NULL, "IN2_HPHR"},
+ {"RDAC2", NULL, "RX2"},
+ {"RX2", NULL, "RXCLK"},
+ {"HPHR_RDAC", "Switch", "RDAC2"},
+ {"HPHR PGA", NULL, "HPHR_RDAC"},
+ {"HPHR", NULL, "HPHR PGA"},
+
+ {"IN3_EAR", NULL, "VDD_BUCK"},
+ {"RX3", NULL, "IN3_EAR"},
+ {"RX3", NULL, "RXCLK"},
+
+ {"RDAC3_MUX", "RX3", "RX3"},
+ {"RDAC3_MUX", "RX1", "RX1"},
+ {"RDAC3", NULL, "RDAC3_MUX"},
+ {"EAR_RDAC", "Switch", "RDAC3"},
+ {"EAR PGA", NULL, "EAR_RDAC"},
+ {"EAR", NULL, "EAR PGA"},
+};
+
+static void wcd939x_set_micbias_data(struct device *dev, struct wcd939x_priv *wcd939x)
+{
+ regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1,
+ WCD939X_MICB_VOUT_CTL, wcd939x->common.micb_vout[0]);
+ regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2,
+ WCD939X_MICB_VOUT_CTL, wcd939x->common.micb_vout[1]);
+ regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3,
+ WCD939X_MICB_VOUT_CTL, wcd939x->common.micb_vout[2]);
+ regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4,
+ WCD939X_MICB_VOUT_CTL, wcd939x->common.micb_vout[3]);
+}
+
+static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data)
+{
+ /*
+ * HPHR/HPHL/EAR Watchdog interrupt threaded handler
+ *
+ * Watchdog interrupts are expected to be enabled when switching
+ * on the HPHL/R and EAR RX PGA in order to make sure the interrupts
+ * are acked by the regmap_irq handler to allow PDM sync.
+ * We could leave those interrupts masked but we would not have
+ * any valid way to enable/disable them without violating irq layers.
+ *
+ * The HPHR/HPHL/EAR Watchdog interrupts are handled
+ * by regmap_irq, so requesting a threaded handler is the
+ * safest way to be able to ack those interrupts without
+ * colliding with the regmap_irq setup.
+ */
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Setup a virtual interrupt domain to hook regmap_irq
+ * The root domain will have a single interrupt which mapping
+ * will trigger the regmap_irq handler.
+ *
+ * root:
+ * wcd_irq_chip
+ * [0] wcd939x_regmap_irq_chip
+ * [0] MBHC_BUTTON_PRESS_DET
+ * [1] MBHC_BUTTON_RELEASE_DET
+ * ...
+ * [16] HPHR_SURGE_DET_INT
+ *
+ * Interrupt trigger:
+ * soundwire_interrupt_callback()
+ * \-handle_nested_irq(0)
+ * \- regmap_irq_thread()
+ * \- handle_nested_irq(i)
+ */
+static const struct irq_chip wcd_irq_chip = {
+ .name = "WCD939x",
+};
+
+static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq);
+ irq_set_nested_thread(virq, 1);
+ irq_set_noprobe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops wcd_domain_ops = {
+ .map = wcd_irq_chip_map,
+};
+
+static int wcd939x_irq_init(struct wcd939x_priv *wcd, struct device *dev)
+{
+ 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;
+ }
+
+ return devm_regmap_add_irq_chip(dev, wcd->regmap,
+ irq_create_mapping(wcd->virq, 0),
+ IRQF_ONESHOT, 0, &wcd939x_regmap_irq_chip,
+ &wcd->irq_chip);
+}
+
+static int wcd939x_soc_codec_probe(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+ struct sdw_slave *tx_sdw_dev = wcd939x->tx_sdw_dev;
+ struct device *dev = component->dev;
+ unsigned long time_left;
+ int ret, i;
+
+ time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete,
+ msecs_to_jiffies(2000));
+ if (!time_left) {
+ dev_err(dev, "soundwire device init timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ snd_soc_component_init_regmap(component, wcd939x->regmap);
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ wcd939x->variant = snd_soc_component_read_field(component,
+ WCD939X_DIGITAL_EFUSE_REG_0,
+ WCD939X_EFUSE_REG_0_WCD939X_ID);
+
+ wcd939x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD939X);
+ if (IS_ERR(wcd939x->clsh_info)) {
+ pm_runtime_put(dev);
+ return PTR_ERR(wcd939x->clsh_info);
+ }
+
+ wcd939x_io_init(component);
+
+ /* Set all interrupts as edge triggered */
+ for (i = 0; i < wcd939x_regmap_irq_chip.num_regs; i++)
+ regmap_write(wcd939x->regmap,
+ (WCD939X_DIGITAL_INTR_LEVEL_0 + i), 0);
+
+ pm_runtime_put(dev);
+
+ /* Request for watchdog interrupt */
+ wcd939x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_HPHR_PDM_WD_INT);
+ wcd939x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_HPHL_PDM_WD_INT);
+ wcd939x->ear_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip,
+ WCD939X_IRQ_EAR_PDM_WD_INT);
+
+ ret = request_threaded_irq(wcd939x->hphr_pdm_wd_int, NULL, wcd939x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHR PDM WD INT", wcd939x);
+ if (ret) {
+ dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret);
+ goto err_free_clsh_ctrl;
+ }
+
+ ret = request_threaded_irq(wcd939x->hphl_pdm_wd_int, NULL, wcd939x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "HPHL PDM WD INT", wcd939x);
+ if (ret) {
+ dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret);
+ goto err_free_hphr_pdm_wd_int;
+ }
+
+ ret = request_threaded_irq(wcd939x->ear_pdm_wd_int, NULL, wcd939x_wd_handle_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "AUX PDM WD INT", wcd939x);
+ if (ret) {
+ dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret);
+ goto err_free_hphl_pdm_wd_int;
+ }
+
+ /* Disable watchdog interrupt for HPH and AUX */
+ disable_irq_nosync(wcd939x->hphr_pdm_wd_int);
+ disable_irq_nosync(wcd939x->hphl_pdm_wd_int);
+ disable_irq_nosync(wcd939x->ear_pdm_wd_int);
+
+ switch (wcd939x->variant) {
+ case CHIPID_WCD9390:
+ ret = snd_soc_add_component_controls(component, wcd9390_snd_controls,
+ ARRAY_SIZE(wcd9390_snd_controls));
+ if (ret < 0) {
+ dev_err(component->dev,
+ "%s: Failed to add snd ctrls for variant: %d\n",
+ __func__, wcd939x->variant);
+ goto err_free_ear_pdm_wd_int;
+ }
+ break;
+ case CHIPID_WCD9395:
+ ret = snd_soc_add_component_controls(component, wcd9395_snd_controls,
+ ARRAY_SIZE(wcd9395_snd_controls));
+ if (ret < 0) {
+ dev_err(component->dev,
+ "%s: Failed to add snd ctrls for variant: %d\n",
+ __func__, wcd939x->variant);
+ goto err_free_ear_pdm_wd_int;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = wcd939x_mbhc_init(component);
+ if (ret) {
+ dev_err(component->dev, "mbhc initialization failed\n");
+ goto err_free_ear_pdm_wd_int;
+ }
+
+ return 0;
+
+err_free_ear_pdm_wd_int:
+ free_irq(wcd939x->ear_pdm_wd_int, wcd939x);
+err_free_hphl_pdm_wd_int:
+ free_irq(wcd939x->hphl_pdm_wd_int, wcd939x);
+err_free_hphr_pdm_wd_int:
+ free_irq(wcd939x->hphr_pdm_wd_int, wcd939x);
+err_free_clsh_ctrl:
+ wcd_clsh_ctrl_free(wcd939x->clsh_info);
+
+ return ret;
+}
+
+static void wcd939x_soc_codec_remove(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ wcd939x_mbhc_deinit(component);
+
+ free_irq(wcd939x->ear_pdm_wd_int, wcd939x);
+ free_irq(wcd939x->hphl_pdm_wd_int, wcd939x);
+ free_irq(wcd939x->hphr_pdm_wd_int, wcd939x);
+
+ wcd_clsh_ctrl_free(wcd939x->clsh_info);
+}
+
+static int wcd939x_codec_set_jack(struct snd_soc_component *comp,
+ struct snd_soc_jack *jack, void *data)
+{
+ struct wcd939x_priv *wcd = dev_get_drvdata(comp->dev);
+
+ if (jack)
+ return wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack);
+
+ wcd_mbhc_stop(wcd->wcd_mbhc);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_wcd939x = {
+ .name = "wcd939x_codec",
+ .probe = wcd939x_soc_codec_probe,
+ .remove = wcd939x_soc_codec_remove,
+ .controls = wcd939x_snd_controls,
+ .num_controls = ARRAY_SIZE(wcd939x_snd_controls),
+ .dapm_widgets = wcd939x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wcd939x_dapm_widgets),
+ .dapm_routes = wcd939x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wcd939x_audio_map),
+ .set_jack = wcd939x_codec_set_jack,
+ .endianness = 1,
+};
+
+#if IS_ENABLED(CONFIG_TYPEC)
+/* Get USB-C plug orientation to provide swap event for MBHC */
+static int wcd939x_typec_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct wcd939x_priv *wcd939x = typec_switch_get_drvdata(sw);
+
+ wcd939x->typec_orientation = orientation;
+
+ return 0;
+}
+
+static int wcd939x_typec_mux_set(struct typec_mux_dev *mux,
+ struct typec_mux_state *state)
+{
+ struct wcd939x_priv *wcd939x = typec_mux_get_drvdata(mux);
+ unsigned int previous_mode = wcd939x->typec_mode;
+
+ if (!wcd939x->wcd_mbhc)
+ return -EINVAL;
+
+ if (wcd939x->typec_mode != state->mode) {
+ wcd939x->typec_mode = state->mode;
+
+ if (wcd939x->typec_mode == TYPEC_MODE_AUDIO)
+ return wcd_mbhc_typec_report_plug(wcd939x->wcd_mbhc);
+ else if (previous_mode == TYPEC_MODE_AUDIO)
+ return wcd_mbhc_typec_report_unplug(wcd939x->wcd_mbhc);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_TYPEC */
+
+#if IS_ENABLED(CONFIG_TYPEC)
+static bool wcd939x_swap_gnd_mic(struct snd_soc_component *component)
+{
+ struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
+
+ if (!wcd939x->typec_analog_mux || !wcd939x->typec_switch)
+ return false;
+
+ /* Report inversion via Type Switch of USBSS */
+ typec_switch_set(wcd939x->typec_switch,
+ wcd939x->typec_orientation == TYPEC_ORIENTATION_REVERSE ?
+ TYPEC_ORIENTATION_NORMAL : TYPEC_ORIENTATION_REVERSE);
+
+ return true;
+}
+#endif /* CONFIG_TYPEC */
+
+static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device *dev)
+{
+ struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg;
+#if IS_ENABLED(CONFIG_TYPEC)
+ struct device_node *np;
+#endif /* CONFIG_TYPEC */
+ int ret;
+
+ wcd939x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(wcd939x->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(wcd939x->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd939x_supplies),
+ wcd939x_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get and enable supplies\n");
+
+ ret = wcd_dt_parse_micbias_info(&wcd939x->common);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get micbias\n");
+
+ cfg->mbhc_micbias = MIC_BIAS_2;
+ cfg->anc_micbias = MIC_BIAS_2;
+ cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
+ cfg->num_btn = WCD939X_MBHC_MAX_BUTTONS;
+ cfg->micb_mv = wcd939x->common.micb_mv[1];
+ cfg->linein_th = 5000;
+ cfg->hs_thr = 1700;
+ cfg->hph_thr = 50;
+
+ wcd_dt_parse_mbhc_data(dev, cfg);
+
+#if IS_ENABLED(CONFIG_TYPEC)
+ /*
+ * Is node has a port and a valid remote endpoint
+ * consider HP lines are connected to the USBSS part
+ */
+ np = of_graph_get_remote_node(dev->of_node, 0, 0);
+ if (np) {
+ wcd939x->typec_analog_mux = true;
+ cfg->typec_analog_mux = true;
+ cfg->swap_gnd_mic = wcd939x_swap_gnd_mic;
+ }
+#endif /* CONFIG_TYPEC */
+
+ return 0;
+}
+
+static int wcd939x_reset(struct wcd939x_priv *wcd939x)
+{
+ gpiod_set_value(wcd939x->reset_gpio, 1);
+ /* 20us sleep required after pulling the reset gpio to LOW */
+ usleep_range(20, 30);
+ gpiod_set_value(wcd939x->reset_gpio, 0);
+ /* 20us sleep required after pulling the reset gpio to HIGH */
+ usleep_range(20, 30);
+
+ return 0;
+}
+
+static int wcd939x_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev);
+ struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id];
+
+ return wcd939x_sdw_hw_params(wcd, substream, params, dai);
+}
+
+static int wcd939x_codec_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev);
+ struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id];
+
+ return wcd939x_sdw_free(wcd, substream, dai);
+}
+
+static int wcd939x_codec_set_sdw_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev);
+ struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id];
+
+ return wcd939x_sdw_set_sdw_stream(wcd, dai, stream, direction);
+}
+
+static const struct snd_soc_dai_ops wcd939x_sdw_dai_ops = {
+ .hw_params = wcd939x_codec_hw_params,
+ .hw_free = wcd939x_codec_free,
+ .set_stream = wcd939x_codec_set_sdw_stream,
+};
+
+static struct snd_soc_dai_driver wcd939x_dais[] = {
+ [0] = {
+ .name = "wcd939x-sdw-rx",
+ .playback = {
+ .stream_name = "WCD AIF1 Playback",
+ .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK,
+ .formats = WCD939X_FORMATS,
+ .rate_max = 384000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd939x_sdw_dai_ops,
+ },
+ [1] = {
+ .name = "wcd939x-sdw-tx",
+ .capture = {
+ .stream_name = "WCD AIF1 Capture",
+ .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK,
+ .formats = WCD939X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &wcd939x_sdw_dai_ops,
+ },
+};
+
+static int wcd939x_bind(struct device *dev)
+{
+ struct wcd939x_priv *wcd939x = dev_get_drvdata(dev);
+ unsigned int version, id1, status1;
+ int ret;
+
+#if IS_ENABLED(CONFIG_TYPEC)
+ /*
+ * Get USBSS type-c switch to send gnd/mic swap events
+ * typec_switch is fetched now to avoid a probe deadlock since
+ * the USBSS depends on the typec_mux register in wcd939x_probe()
+ */
+ if (wcd939x->typec_analog_mux) {
+ wcd939x->typec_switch = fwnode_typec_switch_get(dev->fwnode);
+ if (IS_ERR(wcd939x->typec_switch))
+ return dev_err_probe(dev, PTR_ERR(wcd939x->typec_switch),
+ "failed to acquire orientation-switch\n");
+ }
+#endif /* CONFIG_TYPEC */
+
+ ret = component_bind_all(dev, wcd939x);
+ if (ret) {
+ dev_err(dev, "%s: Slave bind failed, ret = %d\n",
+ __func__, ret);
+ goto err_put_typec_switch;
+ }
+
+ wcd939x->rxdev = of_sdw_find_device_by_node(wcd939x->rxnode);
+ if (!wcd939x->rxdev) {
+ dev_err(dev, "could not find slave with matching of node\n");
+ ret = -EINVAL;
+ goto err_unbind;
+ }
+ wcd939x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd939x->rxdev);
+ wcd939x->sdw_priv[AIF1_PB]->wcd939x = wcd939x;
+
+ wcd939x->txdev = of_sdw_find_device_by_node(wcd939x->txnode);
+ if (!wcd939x->txdev) {
+ dev_err(dev, "could not find txslave with matching of node\n");
+ ret = -EINVAL;
+ goto err_put_rxdev;
+ }
+ wcd939x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd939x->txdev);
+ wcd939x->sdw_priv[AIF1_CAP]->wcd939x = wcd939x;
+ wcd939x->tx_sdw_dev = dev_to_sdw_dev(wcd939x->txdev);
+
+ /*
+ * As TX is main CSR reg interface, which should not be suspended first.
+ * explicitly add the dependency link
+ */
+ if (!device_link_add(wcd939x->rxdev, wcd939x->txdev, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "could not devlink tx and rx\n");
+ ret = -EINVAL;
+ goto err_put_txdev;
+ }
+
+ if (!device_link_add(dev, wcd939x->txdev, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "could not devlink wcd and tx\n");
+ ret = -EINVAL;
+ goto err_remove_rxtx_link;
+ }
+
+ if (!device_link_add(dev, wcd939x->rxdev, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME)) {
+ dev_err(dev, "could not devlink wcd and rx\n");
+ ret = -EINVAL;
+ goto err_remove_tx_link;
+ }
+
+ /* Get regmap from TX SoundWire device */
+ wcd939x->regmap = wcd939x->sdw_priv[AIF1_CAP]->regmap;
+ if (!wcd939x->regmap) {
+ dev_err(dev, "could not get TX device regmap\n");
+ ret = -ENODEV;
+ goto err_remove_rx_link;
+ }
+
+ ret = wcd939x_irq_init(wcd939x, dev);
+ if (ret) {
+ dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret);
+ goto err_remove_rx_link;
+ }
+
+ wcd939x->sdw_priv[AIF1_PB]->slave_irq = wcd939x->virq;
+ wcd939x->sdw_priv[AIF1_CAP]->slave_irq = wcd939x->virq;
+
+ wcd939x_set_micbias_data(dev, wcd939x);
+
+ /* Check WCD9395 version */
+ regmap_read(wcd939x->regmap, WCD939X_DIGITAL_CHIP_ID1, &id1);
+ regmap_read(wcd939x->regmap, WCD939X_EAR_STATUS_REG_1, &status1);
+
+ if (id1 == CHIPID_WCD939X_VER_MAJOR_1)
+ version = ((status1 & CHIPID_WCD939X_VER_MINOR_1) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0);
+ else
+ version = WCD939X_VERSION_2_0;
+
+ dev_dbg(dev, "wcd939x version: %s\n", version_to_str(version));
+
+ ret = snd_soc_register_component(dev, &soc_codec_dev_wcd939x,
+ wcd939x_dais, ARRAY_SIZE(wcd939x_dais));
+ if (ret) {
+ dev_err(dev, "%s: Codec registration failed\n",
+ __func__);
+ goto err_remove_rx_link;
+ }
+
+ return 0;
+
+err_remove_rx_link:
+ device_link_remove(dev, wcd939x->rxdev);
+err_remove_tx_link:
+ device_link_remove(dev, wcd939x->txdev);
+err_remove_rxtx_link:
+ device_link_remove(wcd939x->rxdev, wcd939x->txdev);
+err_put_txdev:
+ put_device(wcd939x->txdev);
+err_put_rxdev:
+ put_device(wcd939x->rxdev);
+err_unbind:
+ component_unbind_all(dev, wcd939x);
+err_put_typec_switch:
+#if IS_ENABLED(CONFIG_TYPEC)
+ if (wcd939x->typec_analog_mux)
+ typec_switch_put(wcd939x->typec_switch);
+#endif /* CONFIG_TYPEC */
+
+ return ret;
+}
+
+static void wcd939x_unbind(struct device *dev)
+{
+ struct wcd939x_priv *wcd939x = dev_get_drvdata(dev);
+
+ snd_soc_unregister_component(dev);
+ device_link_remove(dev, wcd939x->txdev);
+ device_link_remove(dev, wcd939x->rxdev);
+ device_link_remove(wcd939x->rxdev, wcd939x->txdev);
+ put_device(wcd939x->txdev);
+ put_device(wcd939x->rxdev);
+ component_unbind_all(dev, wcd939x);
+}
+
+static const struct component_master_ops wcd939x_comp_ops = {
+ .bind = wcd939x_bind,
+ .unbind = wcd939x_unbind,
+};
+
+static void __maybe_unused wcd939x_typec_mux_unregister(void *data)
+{
+ struct typec_mux_dev *typec_mux = data;
+
+ typec_mux_unregister(typec_mux);
+}
+
+static void __maybe_unused wcd939x_typec_switch_unregister(void *data)
+{
+ struct typec_switch_dev *typec_sw = data;
+
+ typec_switch_unregister(typec_sw);
+}
+
+static int wcd939x_add_typec(struct wcd939x_priv *wcd939x, struct device *dev)
+{
+#if IS_ENABLED(CONFIG_TYPEC)
+ int ret;
+ struct typec_mux_dev *typec_mux;
+ struct typec_switch_dev *typec_sw;
+ struct typec_mux_desc mux_desc = {
+ .drvdata = wcd939x,
+ .fwnode = dev_fwnode(dev),
+ .set = wcd939x_typec_mux_set,
+ };
+ struct typec_switch_desc sw_desc = {
+ .drvdata = wcd939x,
+ .fwnode = dev_fwnode(dev),
+ .set = wcd939x_typec_switch_set,
+ };
+
+ /*
+ * Is USBSS is used to mux analog lines,
+ * register a typec mux/switch to get typec events
+ */
+ if (!wcd939x->typec_analog_mux)
+ return 0;
+
+ typec_mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(typec_mux))
+ return dev_err_probe(dev, PTR_ERR(typec_mux),
+ "failed to register typec mux\n");
+
+ ret = devm_add_action_or_reset(dev, wcd939x_typec_mux_unregister,
+ typec_mux);
+ if (ret)
+ return ret;
+
+ typec_sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(typec_sw))
+ return dev_err_probe(dev, PTR_ERR(typec_sw),
+ "failed to register typec switch\n");
+
+ ret = devm_add_action_or_reset(dev, wcd939x_typec_switch_unregister,
+ typec_sw);
+ if (ret)
+ return ret;
+#endif
+
+ return 0;
+}
+
+static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x,
+ struct device *dev,
+ struct component_match **matchptr)
+{
+ struct device_node *np = dev->of_node;
+
+ wcd939x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0);
+ if (!wcd939x->rxnode) {
+ dev_err(dev, "%s: Rx-device node not defined\n", __func__);
+ return -ENODEV;
+ }
+
+ of_node_get(wcd939x->rxnode);
+ component_match_add_release(dev, matchptr, component_release_of,
+ component_compare_of, wcd939x->rxnode);
+
+ wcd939x->txnode = of_parse_phandle(np, "qcom,tx-device", 0);
+ if (!wcd939x->txnode) {
+ dev_err(dev, "%s: Tx-device node not defined\n", __func__);
+ return -ENODEV;
+ }
+ of_node_get(wcd939x->txnode);
+ component_match_add_release(dev, matchptr, component_release_of,
+ component_compare_of, wcd939x->txnode);
+ return 0;
+}
+
+static int wcd939x_probe(struct platform_device *pdev)
+{
+ struct component_match *match = NULL;
+ struct wcd939x_priv *wcd939x = NULL;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ wcd939x = devm_kzalloc(dev, sizeof(struct wcd939x_priv),
+ GFP_KERNEL);
+ if (!wcd939x)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, wcd939x);
+ mutex_init(&wcd939x->micb_lock);
+ wcd939x->common.dev = dev;
+ wcd939x->common.max_bias = 4;
+
+ ret = wcd939x_populate_dt_data(wcd939x, dev);
+ if (ret) {
+ dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = wcd939x_add_typec(wcd939x, dev);
+ if (ret)
+ return ret;
+
+ ret = wcd939x_add_slave_components(wcd939x, dev, &match);
+ if (ret)
+ return ret;
+
+ wcd939x_reset(wcd939x);
+
+ ret = component_master_add_with_match(dev, &wcd939x_comp_ops, match);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+}
+
+static void wcd939x_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ component_master_del(dev, &wcd939x_comp_ops);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id wcd939x_dt_match[] = {
+ { .compatible = "qcom,wcd9390-codec" },
+ { .compatible = "qcom,wcd9395-codec" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, wcd939x_dt_match);
+#endif
+
+static struct platform_driver wcd939x_codec_driver = {
+ .probe = wcd939x_probe,
+ .remove = wcd939x_remove,
+ .driver = {
+ .name = "wcd939x_codec",
+ .of_match_table = of_match_ptr(wcd939x_dt_match),
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(wcd939x_codec_driver);
+MODULE_DESCRIPTION("WCD939X Codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wcd939x.h b/sound/soc/codecs/wcd939x.h
new file mode 100644
index 000000000000..6bd2366587a8
--- /dev/null
+++ b/sound/soc/codecs/wcd939x.h
@@ -0,0 +1,947 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __WCD939X_H__
+#define __WCD939X_H__
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+
+#define WCD939X_BASE (0x3000)
+#define WCD939X_ANA_PAGE (0x3000)
+#define WCD939X_ANA_BIAS (0x3001)
+#define WCD939X_BIAS_ANALOG_BIAS_EN BIT(7)
+#define WCD939X_BIAS_PRECHRG_EN BIT(6)
+#define WCD939X_BIAS_PRECHRG_CTL_MODE BIT(5)
+#define WCD939X_ANA_RX_SUPPLIES (0x3008)
+#define WCD939X_RX_SUPPLIES_VPOS_EN BIT(7)
+#define WCD939X_RX_SUPPLIES_VNEG_EN BIT(6)
+#define WCD939X_RX_SUPPLIES_VPOS_PWR_LVL BIT(3)
+#define WCD939X_RX_SUPPLIES_VNEG_PWR_LVL BIT(2)
+#define WCD939X_RX_SUPPLIES_REGULATOR_MODE BIT(1)
+#define WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE BIT(0)
+#define WCD939X_ANA_HPH (0x3009)
+#define WCD939X_HPH_HPHL_ENABLE BIT(7)
+#define WCD939X_HPH_HPHR_ENABLE BIT(6)
+#define WCD939X_HPH_HPHL_REF_ENABLE BIT(5)
+#define WCD939X_HPH_HPHR_REF_ENABLE BIT(4)
+#define WCD939X_HPH_PWR_LEVEL GENMASK(3, 2)
+#define WCD939X_ANA_EAR (0x300a)
+#define WCD939X_ANA_EAR_COMPANDER_CTL (0x300b)
+#define WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG BIT(7)
+#define WCD939X_EAR_COMPANDER_CTL_EAR_GAIN GENMASK(6, 2)
+#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_BYP BIT(1)
+#define WCD939X_EAR_COMPANDER_CTL_COMP_DFF_CLK_EDGE BIT(0)
+#define WCD939X_ANA_TX_CH1 (0x300e)
+#define WCD939X_ANA_TX_CH2 (0x300f)
+#define WCD939X_TX_CH2_ENABLE BIT(7)
+#define WCD939X_TX_CH2_HPF1_INIT BIT(6)
+#define WCD939X_TX_CH2_HPF2_INIT BIT(5)
+#define WCD939X_TX_CH2_GAIN GENMASK(4, 0)
+#define WCD939X_ANA_TX_CH3 (0x3010)
+#define WCD939X_ANA_TX_CH4 (0x3011)
+#define WCD939X_TX_CH4_ENABLE BIT(7)
+#define WCD939X_TX_CH4_HPF3_INIT BIT(6)
+#define WCD939X_TX_CH4_HPF4_INIT BIT(5)
+#define WCD939X_TX_CH4_GAIN GENMASK(4, 0)
+#define WCD939X_ANA_MICB1_MICB2_DSP_EN_LOGIC (0x3012)
+#define WCD939X_ANA_MICB3_DSP_EN_LOGIC (0x3013)
+#define WCD939X_ANA_MBHC_MECH (0x3014)
+#define WCD939X_MBHC_MECH_L_DET_EN BIT(7)
+#define WCD939X_MBHC_MECH_GND_DET_EN BIT(6)
+#define WCD939X_MBHC_MECH_MECH_DETECT_TYPE BIT(5)
+#define WCD939X_MBHC_MECH_HPHL_PLUG_TYPE BIT(4)
+#define WCD939X_MBHC_MECH_GND_PLUG_TYPE BIT(3)
+#define WCD939X_MBHC_MECH_MECH_HS_L_PULLUP_COMP_EN BIT(2)
+#define WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN BIT(1)
+#define WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND BIT(0)
+#define WCD939X_ANA_MBHC_ELECT (0x3015)
+#define WCD939X_MBHC_ELECT_FSM_EN BIT(7)
+#define WCD939X_MBHC_ELECT_BTNDET_ISRC_CTL GENMASK(6, 4)
+#define WCD939X_MBHC_ELECT_ELECT_DET_TYPE BIT(3)
+#define WCD939X_MBHC_ELECT_ELECT_SCHMT_ISRC_CTL GENMASK(2, 1)
+#define WCD939X_MBHC_ELECT_BIAS_EN BIT(0)
+#define WCD939X_ANA_MBHC_ZDET (0x3016)
+#define WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN BIT(7)
+#define WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN BIT(6)
+#define WCD939X_MBHC_ZDET_ZDET_CHG_EN BIT(5)
+#define WCD939X_MBHC_ZDET_ZDET_ILEAK_COMP_EN BIT(4)
+#define WCD939X_MBHC_ZDET_ELECT_ISRC_EN BIT(1)
+#define WCD939X_ANA_MBHC_RESULT_1 (0x3017)
+#define WCD939X_MBHC_RESULT_1_Z_RESULT_LSB GENMASK(7, 0)
+#define WCD939X_ANA_MBHC_RESULT_2 (0x3018)
+#define WCD939X_MBHC_RESULT_2_Z_RESULT_MSB GENMASK(7, 0)
+#define WCD939X_ANA_MBHC_RESULT_3 (0x3019)
+#define WCD939X_ANA_MBHC_BTN0 (0x301a)
+#define WCD939X_MBHC_BTN0_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN1 (0x301b)
+#define WCD939X_MBHC_BTN1_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN2 (0x301c)
+#define WCD939X_MBHC_BTN2_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN3 (0x301d)
+#define WCD939X_MBHC_BTN3_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN4 (0x301e)
+#define WCD939X_MBHC_BTN4_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN5 (0x301f)
+#define WCD939X_MBHC_BTN5_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN6 (0x3020)
+#define WCD939X_MBHC_BTN6_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MBHC_BTN7 (0x3021)
+#define WCD939X_MBHC_BTN7_VTH GENMASK(7, 2)
+#define WCD939X_ANA_MICB1 (0x3022)
+#define WCD939X_MICB_ENABLE GENMASK(7, 6)
+#define WCD939X_MICB_VOUT_CTL GENMASK(5, 0)
+#define WCD939X_ANA_MICB2 (0x3023)
+#define WCD939X_ANA_MICB2_RAMP (0x3024)
+#define WCD939X_MICB2_RAMP_RAMP_ENABLE BIT(7)
+#define WCD939X_MICB2_RAMP_MB2_IN2P_SHORT_ENABLE BIT(6)
+#define WCD939X_MICB2_RAMP_ALLSW_OVRD_ENABLE BIT(5)
+#define WCD939X_MICB2_RAMP_SHIFT_CTL GENMASK(4, 2)
+#define WCD939X_MICB2_RAMP_USB_MGDET_MICB2_RAMP GENMASK(1, 0)
+#define WCD939X_ANA_MICB3 (0x3025)
+#define WCD939X_ANA_MICB4 (0x3026)
+#define WCD939X_BIAS_CTL (0x3028)
+#define WCD939X_BIAS_VBG_FINE_ADJ (0x3029)
+#define WCD939X_LDOL_VDDCX_ADJUST (0x3040)
+#define WCD939X_LDOL_DISABLE_LDOL (0x3041)
+#define WCD939X_MBHC_CTL_CLK (0x3056)
+#define WCD939X_MBHC_CTL_ANA (0x3057)
+#define WCD939X_MBHC_ZDET_VNEG_CTL (0x3058)
+#define WCD939X_MBHC_ZDET_BIAS_CTL (0x3059)
+#define WCD939X_MBHC_CTL_BCS (0x305a)
+#define WCD939X_MBHC_MOISTURE_DET_FSM_STATUS (0x305b)
+#define WCD939X_MBHC_TEST_CTL (0x305c)
+#define WCD939X_LDOH_MODE (0x3067)
+#define WCD939X_MODE_LDOH_EN BIT(7)
+#define WCD939X_MODE_PWRDN_STATE BIT(6)
+#define WCD939X_MODE_SLOWRAMP_EN BIT(5)
+#define WCD939X_MODE_VOUT_ADJUST GENMASK(4, 3)
+#define WCD939X_MODE_VOUT_COARSE_ADJ GENMASK(2, 0)
+#define WCD939X_LDOH_BIAS (0x3068)
+#define WCD939X_LDOH_STB_LOADS (0x3069)
+#define WCD939X_LDOH_SLOWRAMP (0x306a)
+#define WCD939X_MICB1_TEST_CTL_1 (0x306b)
+#define WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL GENMASK(7, 5)
+#define WCD939X_TEST_CTL_1_EN_VREFGEN BIT(4)
+#define WCD939X_TEST_CTL_1_EN_LDO BIT(3)
+#define WCD939X_TEST_CTL_1_LDO_BLEEDER_I_CTRL GENMASK(2, 0)
+#define WCD939X_MICB1_TEST_CTL_2 (0x306c)
+#define WCD939X_TEST_CTL_2_IBIAS_VREFGEN GENMASK(7, 6)
+#define WCD939X_TEST_CTL_2_INRUSH_CURRENT_FIX_DIS BIT(5)
+#define WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER GENMASK(2, 0)
+#define WCD939X_MICB1_TEST_CTL_3 (0x306d)
+#define WCD939X_TEST_CTL_3_CFILT_REF_EN BIT(7)
+#define WCD939X_TEST_CTL_3_RZ_LDO_VAL GENMASK(6, 4)
+#define WCD939X_TEST_CTL_3_IBIAS_LDO_STG3 GENMASK(3, 2)
+#define WCD939X_TEST_CTL_3_ATEST_CTRL GENMASK(1, 0)
+#define WCD939X_MICB2_TEST_CTL_1 (0x306e)
+#define WCD939X_MICB2_TEST_CTL_2 (0x306f)
+#define WCD939X_MICB2_TEST_CTL_3 (0x3070)
+#define WCD939X_MICB3_TEST_CTL_1 (0x3071)
+#define WCD939X_MICB3_TEST_CTL_2 (0x3072)
+#define WCD939X_MICB3_TEST_CTL_3 (0x3073)
+#define WCD939X_MICB4_TEST_CTL_1 (0x3074)
+#define WCD939X_MICB4_TEST_CTL_2 (0x3075)
+#define WCD939X_MICB4_TEST_CTL_3 (0x3076)
+#define WCD939X_TX_COM_ADC_VCM (0x3077)
+#define WCD939X_TX_COM_BIAS_ATEST (0x3078)
+#define WCD939X_TX_COM_SPARE1 (0x3079)
+#define WCD939X_TX_COM_SPARE2 (0x307a)
+#define WCD939X_TX_COM_TXFE_DIV_CTL (0x307b)
+#define WCD939X_TX_COM_TXFE_DIV_START (0x307c)
+#define WCD939X_TX_COM_SPARE3 (0x307d)
+#define WCD939X_TX_COM_SPARE4 (0x307e)
+#define WCD939X_TX_1_2_TEST_EN (0x307f)
+#define WCD939X_TX_1_2_ADC_IB (0x3080)
+#define WCD939X_TX_1_2_ATEST_REFCTL (0x3081)
+#define WCD939X_TX_1_2_TEST_CTL (0x3082)
+#define WCD939X_TX_1_2_TEST_BLK_EN1 (0x3083)
+#define WCD939X_TX_1_2_TXFE1_CLKDIV (0x3084)
+#define WCD939X_TX_1_2_SAR2_ERR (0x3085)
+#define WCD939X_TX_1_2_SAR1_ERR (0x3086)
+#define WCD939X_TX_3_4_TEST_EN (0x3087)
+#define WCD939X_TX_3_4_ADC_IB (0x3088)
+#define WCD939X_TX_3_4_ATEST_REFCTL (0x3089)
+#define WCD939X_TX_3_4_TEST_CTL (0x308a)
+#define WCD939X_TX_3_4_TEST_BLK_EN3 (0x308b)
+#define WCD939X_TX_3_4_TXFE3_CLKDIV (0x308c)
+#define WCD939X_TX_3_4_SAR4_ERR (0x308d)
+#define WCD939X_TX_3_4_SAR3_ERR (0x308e)
+#define WCD939X_TX_3_4_TEST_BLK_EN2 (0x308f)
+#define WCD939X_TEST_BLK_EN2_ADC2_INT1_EN BIT(7)
+#define WCD939X_TEST_BLK_EN2_ADC2_INT2_EN BIT(6)
+#define WCD939X_TEST_BLK_EN2_ADC2_SAR_EN BIT(5)
+#define WCD939X_TEST_BLK_EN2_ADC2_CMGEN_EN BIT(4)
+#define WCD939X_TEST_BLK_EN2_ADC2_CLKGEN_EN BIT(3)
+#define WCD939X_TEST_BLK_EN2_ADC12_VREF_NONL2 GENMASK(2, 1)
+#define WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN BIT(0)
+#define WCD939X_TX_3_4_TXFE2_CLKDIV (0x3090)
+#define WCD939X_TX_3_4_SPARE1 (0x3091)
+#define WCD939X_TX_3_4_TEST_BLK_EN4 (0x3092)
+#define WCD939X_TX_3_4_TXFE4_CLKDIV (0x3093)
+#define WCD939X_TX_3_4_SPARE2 (0x3094)
+#define WCD939X_CLASSH_MODE_1 (0x3097)
+#define WCD939X_CLASSH_MODE_2 (0x3098)
+#define WCD939X_CLASSH_MODE_3 (0x3099)
+#define WCD939X_CLASSH_CTRL_VCL_1 (0x309a)
+#define WCD939X_CLASSH_CTRL_VCL_2 (0x309b)
+#define WCD939X_CLASSH_CTRL_CCL_1 (0x309c)
+#define WCD939X_CLASSH_CTRL_CCL_2 (0x309d)
+#define WCD939X_CLASSH_CTRL_CCL_3 (0x309e)
+#define WCD939X_CLASSH_CTRL_CCL_4 (0x309f)
+#define WCD939X_CLASSH_CTRL_CCL_5 (0x30a0)
+#define WCD939X_CLASSH_BUCK_TMUX_A_D (0x30a1)
+#define WCD939X_CLASSH_BUCK_SW_DRV_CNTL (0x30a2)
+#define WCD939X_CLASSH_SPARE (0x30a3)
+#define WCD939X_FLYBACK_EN (0x30a4)
+#define WCD939X_FLYBACK_VNEG_CTRL_1 (0x30a5)
+#define WCD939X_FLYBACK_VNEG_CTRL_2 (0x30a6)
+#define WCD939X_FLYBACK_VNEG_CTRL_3 (0x30a7)
+#define WCD939X_FLYBACK_VNEG_CTRL_4 (0x30a8)
+#define WCD939X_VNEG_CTRL_4_ILIM_SEL GENMASK(7, 4)
+#define WCD939X_VNEG_CTRL_4_PW_BUF_POS GENMASK(3, 2)
+#define WCD939X_VNEG_CTRL_4_PW_BUF_NEG GENMASK(1, 0)
+#define WCD939X_FLYBACK_VNEG_CTRL_5 (0x30a9)
+#define WCD939X_FLYBACK_VNEG_CTRL_6 (0x30aa)
+#define WCD939X_FLYBACK_VNEG_CTRL_7 (0x30ab)
+#define WCD939X_FLYBACK_VNEG_CTRL_8 (0x30ac)
+#define WCD939X_FLYBACK_VNEG_CTRL_9 (0x30ad)
+#define WCD939X_FLYBACK_VNEGDAC_CTRL_1 (0x30ae)
+#define WCD939X_FLYBACK_VNEGDAC_CTRL_2 (0x30af)
+#define WCD939X_FLYBACK_VNEGDAC_CTRL_3 (0x30b0)
+#define WCD939X_FLYBACK_CTRL_1 (0x30b1)
+#define WCD939X_FLYBACK_TEST_CTL (0x30b2)
+#define WCD939X_RX_AUX_SW_CTL (0x30b3)
+#define WCD939X_RX_PA_AUX_IN_CONN (0x30b4)
+#define WCD939X_RX_TIMER_DIV (0x30b5)
+#define WCD939X_RX_OCP_CTL (0x30b6)
+#define WCD939X_RX_OCP_COUNT (0x30b7)
+#define WCD939X_RX_BIAS_EAR_DAC (0x30b8)
+#define WCD939X_RX_BIAS_EAR_AMP (0x30b9)
+#define WCD939X_RX_BIAS_HPH_LDO (0x30ba)
+#define WCD939X_RX_BIAS_HPH_PA (0x30bb)
+#define WCD939X_RX_BIAS_HPH_RDACBUFF_CNP2 (0x30bc)
+#define WCD939X_RX_BIAS_HPH_RDAC_LDO (0x30bd)
+#define WCD939X_RX_BIAS_HPH_CNP1 (0x30be)
+#define WCD939X_RX_BIAS_HPH_LOWPOWER (0x30bf)
+#define WCD939X_RX_BIAS_AUX_DAC (0x30c0)
+#define WCD939X_RX_BIAS_AUX_AMP (0x30c1)
+#define WCD939X_RX_BIAS_VNEGDAC_BLEEDER (0x30c2)
+#define WCD939X_RX_BIAS_MISC (0x30c3)
+#define WCD939X_RX_BIAS_BUCK_RST (0x30c4)
+#define WCD939X_RX_BIAS_BUCK_VREF_ERRAMP (0x30c5)
+#define WCD939X_RX_BIAS_FLYB_ERRAMP (0x30c6)
+#define WCD939X_RX_BIAS_FLYB_BUFF (0x30c7)
+#define WCD939X_RX_BIAS_FLYB_MID_RST (0x30c8)
+#define WCD939X_HPH_L_STATUS (0x30c9)
+#define WCD939X_HPH_R_STATUS (0x30ca)
+#define WCD939X_HPH_CNP_EN (0x30cb)
+#define WCD939X_HPH_CNP_WG_CTL (0x30cc)
+#define WCD939X_HPH_CNP_WG_TIME (0x30cd)
+#define WCD939X_HPH_OCP_CTL (0x30ce)
+#define WCD939X_OCP_CTL_OCP_CURR_LIMIT GENMASK(7, 5)
+#define WCD939X_OCP_CTL_OCP_FSM_EN BIT(4)
+#define WCD939X_OCP_CTL_SPARE_BITS BIT(3)
+#define WCD939X_OCP_CTL_SCD_OP_EN BIT(1)
+#define WCD939X_HPH_AUTO_CHOP (0x30cf)
+#define WCD939X_HPH_CHOP_CTL (0x30d0)
+#define WCD939X_HPH_PA_CTL1 (0x30d1)
+#define WCD939X_HPH_PA_CTL2 (0x30d2)
+#define WCD939X_PA_CTL2_HPHPA_GND_R BIT(6)
+#define WCD939X_PA_CTL2_HPHPA_GND_L BIT(4)
+#define WCD939X_PA_CTL2_GM3_CASCODE_CTL_NORMAL GENMASK(1, 0)
+#define WCD939X_HPH_L_EN (0x30d3)
+#define WCD939X_L_EN_CONST_SEL_L GENMASK(7, 6)
+#define WCD939X_L_EN_GAIN_SOURCE_SEL BIT(5)
+#define WCD939X_L_EN_SPARE_BITS GENMASK(4, 0)
+#define WCD939X_HPH_L_TEST (0x30d4)
+#define WCD939X_HPH_L_ATEST (0x30d5)
+#define WCD939X_HPH_R_EN (0x30d6)
+#define WCD939X_R_EN_CONST_SEL_R GENMASK(7, 6)
+#define WCD939X_R_EN_GAIN_SOURCE_SEL BIT(5)
+#define WCD939X_R_EN_SPARE_BITS GENMASK(4, 0)
+#define WCD939X_HPH_R_TEST (0x30d7)
+#define WCD939X_HPH_R_ATEST (0x30d8)
+#define WCD939X_R_ATEST_DACR_REF_ATEST1_CONN BIT(7)
+#define WCD939X_R_ATEST_LDO1_R_ATEST2_CONN BIT(6)
+#define WCD939X_R_ATEST_LDO_R_ATEST2_CAL BIT(5)
+#define WCD939X_R_ATEST_LDO2_R_ATEST2_CONN BIT(4)
+#define WCD939X_R_ATEST_LDO_1P65V_ATEST1_CONN BIT(3)
+#define WCD939X_R_ATEST_HPH_GND_OVR BIT(1)
+#define WCD939X_HPH_RDAC_CLK_CTL1 (0x30d9)
+#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN BIT(7)
+#define WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_DIV_CTRL GENMASK(6, 4)
+#define WCD939X_RDAC_CLK_CTL1_SPARE_BITS GENMASK(3, 0)
+#define WCD939X_HPH_RDAC_CLK_CTL2 (0x30da)
+#define WCD939X_HPH_RDAC_LDO_CTL (0x30db)
+#define WCD939X_HPH_RDAC_CHOP_CLK_LP_CTL (0x30dc)
+#define WCD939X_HPH_REFBUFF_UHQA_CTL (0x30dd)
+#define WCD939X_REFBUFF_UHQA_CTL_SPARE_BITS GENMASK(7, 6)
+#define WCD939X_REFBUFF_UHQA_CTL_HPH_VNEGREG2_COMP_CTL_OV BIT(5)
+#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_RBIAS_ADJUST BIT(4)
+#define WCD939X_REFBUFF_UHQA_CTL_REFBUFP_IOUT_CTL GENMASK(3, 2)
+#define WCD939X_REFBUFF_UHQA_CTL_REFBUFN_IOUT_CTL GENMASK(1, 0)
+#define WCD939X_HPH_REFBUFF_LP_CTL (0x30de)
+#define WCD939X_REFBUFF_LP_CTL_HPH_VNEGREG2_CURR_COMP GENMASK(7, 6)
+#define WCD939X_REFBUFF_LP_CTL_SPARE_BITS GENMASK(5, 4)
+#define WCD939X_REFBUFF_LP_CTL_EN_PREREF_FILT_STARTUP_CLKDIV BIT(3)
+#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_STARTUP_CLKDIV_CTL GENMASK(2, 1)
+#define WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS BIT(0)
+#define WCD939X_HPH_L_DAC_CTL (0x30df)
+#define WCD939X_HPH_R_DAC_CTL (0x30e0)
+#define WCD939X_HPH_SURGE_COMP_SEL (0x30e1)
+#define WCD939X_HPH_SURGE_EN (0x30e2)
+#define WCD939X_EN_EN_SURGE_PROTECTION_HPHL BIT(7)
+#define WCD939X_EN_EN_SURGE_PROTECTION_HPHR BIT(6)
+#define WCD939X_EN_SEL_SURGE_COMP_IQ GENMASK(5, 4)
+#define WCD939X_EN_SURGE_VOLT_MODE_SHUTOFF_EN BIT(3)
+#define WCD939X_EN_LATCH_INTR_OP_STG_HIZ_EN BIT(2)
+#define WCD939X_EN_SURGE_LATCH_REG_RESET BIT(1)
+#define WCD939X_EN_SWTICH_VN_VNDAC_NSURGE_EN BIT(0)
+#define WCD939X_HPH_SURGE_MISC1 (0x30e3)
+#define WCD939X_HPH_SURGE_STATUS (0x30e4)
+#define WCD939X_EAR_EN (0x30e9)
+#define WCD939X_EAR_PA_CON (0x30ea)
+#define WCD939X_EAR_SP_CON (0x30eb)
+#define WCD939X_EAR_DAC_CON (0x30ec)
+#define WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL BIT(7)
+#define WCD939X_DAC_CON_REF_DBG_EN BIT(6)
+#define WCD939X_DAC_CON_REF_DBG_GAIN GENMASK(5, 3)
+#define WCD939X_DAC_CON_GAIN_DAC GENMASK(2, 1)
+#define WCD939X_DAC_CON_INV_DATA BIT(0)
+#define WCD939X_EAR_CNP_FSM_CON (0x30ed)
+#define WCD939X_EAR_TEST_CTL (0x30ee)
+#define WCD939X_EAR_STATUS_REG_1 (0x30ef)
+#define WCD939X_EAR_STATUS_REG_2 (0x30f0)
+#define WCD939X_FLYBACK_NEW_CTRL_2 (0x30f6)
+#define WCD939X_FLYBACK_NEW_CTRL_3 (0x30f7)
+#define WCD939X_FLYBACK_NEW_CTRL_4 (0x30f8)
+#define WCD939X_ANA_NEW_PAGE (0x3100)
+#define WCD939X_HPH_NEW_ANA_HPH2 (0x3101)
+#define WCD939X_HPH_NEW_ANA_HPH3 (0x3102)
+#define WCD939X_SLEEP_CTL (0x3103)
+#define WCD939X_SLEEP_WATCHDOG_CTL (0x3104)
+#define WCD939X_MBHC_NEW_ELECT_REM_CLAMP_CTL (0x311f)
+#define WCD939X_MBHC_NEW_CTL_1 (0x3120)
+#define WCD939X_CTL_1_RCO_EN BIT(7)
+#define WCD939X_CTL_1_ADC_MODE BIT(4)
+#define WCD939X_CTL_1_ADC_ENABLE BIT(3)
+#define WCD939X_CTL_1_DETECTION_DONE BIT(2)
+#define WCD939X_CTL_1_BTN_DBNC_CTL GENMASK(1, 0)
+#define WCD939X_MBHC_NEW_CTL_2 (0x3121)
+#define WCD939X_CTL_2_MUX_CTL GENMASK(6, 4)
+#define WCD939X_CTL_2_M_RTH_CTL GENMASK(3, 2)
+#define WCD939X_CTL_2_HS_VREF_CTL GENMASK(1, 0)
+#define WCD939X_MBHC_NEW_PLUG_DETECT_CTL (0x3122)
+#define WCD939X_MBHC_NEW_ZDET_ANA_CTL (0x3123)
+#define WCD939X_ZDET_ANA_CTL_AVERAGING_EN BIT(7)
+#define WCD939X_ZDET_ANA_CTL_MAXV_CTL GENMASK(6, 4)
+#define WCD939X_ZDET_ANA_CTL_RANGE_CTL GENMASK(3, 0)
+#define WCD939X_MBHC_NEW_ZDET_RAMP_CTL (0x3124)
+#define WCD939X_ZDET_RAMP_CTL_ACC1_MIN_CTL GENMASK(6, 4)
+#define WCD939X_ZDET_RAMP_CTL_TIME_CTL GENMASK(3, 0)
+#define WCD939X_MBHC_NEW_FSM_STATUS (0x3125)
+#define WCD939X_FSM_STATUS_ADC_TIMEOUT BIT(7)
+#define WCD939X_FSM_STATUS_ADC_COMPLETE BIT(6)
+#define WCD939X_FSM_STATUS_HS_M_COMP_STATUS BIT(5)
+#define WCD939X_FSM_STATUS_FAST_PRESS_FLAG_STATUS BIT(4)
+#define WCD939X_FSM_STATUS_FAST_REMOVAL_FLAG_STATUS BIT(3)
+#define WCD939X_FSM_STATUS_REMOVAL_FLAG_STATUS BIT(2)
+#define WCD939X_FSM_STATUS_ELECT_REM_RT_STATUS BIT(1)
+#define WCD939X_FSM_STATUS_BTN_STATUS BIT(0)
+#define WCD939X_MBHC_NEW_ADC_RESULT (0x3126)
+#define WCD939X_ADC_RESULT_VALUE GENMASK(7, 0)
+#define WCD939X_TX_NEW_CH12_MUX (0x3127)
+#define WCD939X_TX_NEW_CH34_MUX (0x3128)
+#define WCD939X_DIE_CRACK_DET_EN (0x312c)
+#define WCD939X_DIE_CRACK_DET_OUT (0x312d)
+#define WCD939X_HPH_NEW_INT_RDAC_GAIN_CTL (0x3132)
+#define WCD939X_HPH_NEW_INT_PA_GAIN_CTL_L (0x3133)
+#define WCD939X_PA_GAIN_CTL_L_EN_HPHPA_2VPK BIT(7)
+#define WCD939X_PA_GAIN_CTL_L_RX_SUPPLY_LEVEL BIT(6)
+#define WCD939X_PA_GAIN_CTL_L_DAC_DR_BOOST BIT(5)
+#define WCD939X_PA_GAIN_CTL_L_VALUE GENMASK(4, 0)
+#define WCD939X_HPH_NEW_INT_RDAC_VREF_CTL (0x3134)
+#define WCD939X_HPH_NEW_INT_RDAC_OVERRIDE_CTL (0x3135)
+#define WCD939X_HPH_NEW_INT_PA_GAIN_CTL_R (0x3136)
+#define WCD939X_PA_GAIN_CTL_R_D_RCO_CLK_EN BIT(7)
+#define WCD939X_PA_GAIN_CTL_R_SPARE_BITS GENMASK(6, 5)
+#define WCD939X_PA_GAIN_CTL_R_VALUE GENMASK(4, 0)
+#define WCD939X_HPH_NEW_INT_PA_MISC1 (0x3137)
+#define WCD939X_HPH_NEW_INT_PA_MISC2 (0x3138)
+#define WCD939X_HPH_NEW_INT_PA_RDAC_MISC (0x3139)
+#define WCD939X_HPH_NEW_INT_TIMER1 (0x313a)
+#define WCD939X_TIMER1_CURR_IDIV_CTL_CMPDR_OFF GENMASK(7, 5)
+#define WCD939X_TIMER1_CURR_IDIV_CTL_AUTOCHOP GENMASK(4, 2)
+#define WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN BIT(1)
+#define WCD939X_HPH_NEW_INT_TIMER2 (0x313b)
+#define WCD939X_HPH_NEW_INT_TIMER3 (0x313c)
+#define WCD939X_HPH_NEW_INT_TIMER4 (0x313d)
+#define WCD939X_HPH_NEW_INT_PA_RDAC_MISC2 (0x313e)
+#define WCD939X_HPH_NEW_INT_PA_RDAC_MISC3 (0x313f)
+#define WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L (0x3140)
+#define WCD939X_RDAC_HD2_CTL_L_EN_HD2_RES_DIV_L BIT(7)
+#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_PULLGND_L BIT(6)
+#define WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L GENMASK(5, 0)
+#define WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R (0x3141)
+#define WCD939X_RDAC_HD2_CTL_R_EN_HD2_RES_DIV_R BIT(7)
+#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_PULLGND_L BIT(6)
+#define WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R GENMASK(5, 0)
+#define WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (0x3145)
+#define WCD939X_RX_NEW_INT_HPH_RDAC_BIAS_ULP (0x3146)
+#define WCD939X_RX_NEW_INT_HPH_RDAC_LDO_LP (0x3147)
+#define WCD939X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (0x31af)
+#define WCD939X_MOISTURE_DET_DC_CTRL_ONCOUNT GENMASK(6, 5)
+#define WCD939X_MOISTURE_DET_DC_CTRL_OFFCOUNT GENMASK(4, 0)
+#define WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL (0x31b0)
+#define WCD939X_MOISTURE_DET_POLLING_CTRL_HPHL_PA_EN BIT(6)
+#define WCD939X_MOISTURE_DET_POLLING_CTRL_DTEST_EN GENMASK(5, 4)
+#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_OVRD_POLLING BIT(3)
+#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_EN_POLLING BIT(2)
+#define WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_DBNC_TIME GENMASK(1, 0)
+#define WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT (0x31b1)
+#define WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL GENMASK(4, 0)
+#define WCD939X_MBHC_NEW_INT_ZDET_CLK_AND_MOISTURE_CTL_NEW (0x31b2)
+#define WCD939X_EAR_INT_NEW_CHOPPER_CON (0x31b7)
+#define WCD939X_EAR_INT_NEW_CNP_VCM_CON1 (0x31b8)
+#define WCD939X_EAR_INT_NEW_CNP_VCM_CON2 (0x31b9)
+#define WCD939X_EAR_INT_NEW_DYNAMIC_BIAS (0x31ba)
+#define WCD939X_SLEEP_INT_WATCHDOG_CTL_1 (0x31d0)
+#define WCD939X_SLEEP_INT_WATCHDOG_CTL_2 (0x31d1)
+#define WCD939X_DIE_CRACK_INT_DET_INT1 (0x31d3)
+#define WCD939X_DIE_CRACK_INT_DET_INT2 (0x31d4)
+#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L2 (0x31d5)
+#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L1 (0x31d6)
+#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_L0 (0x31d7)
+#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP1P2M (0x31d8)
+#define WCD939X_TX_COM_NEW_INT_FE_DIVSTOP_ULP0P6M (0x31d9)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L2L1 (0x31da)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_L0 (0x31db)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG1_ULP (0x31dc)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L2L1 (0x31dd)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_L0 (0x31de)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP (0x31df)
+#define WCD939X_FE_ICTRL_STG2MAIN_ULP_VALUE GENMASK(4, 0)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_L2L1L0 (0x31e0)
+#define WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP (0x31e1)
+#define WCD939X_FE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M GENMASK(7, 4)
+#define WCD939X_FE_ICTRL_STG2CASC_ULP_VALUE GENMASK(3, 0)
+#define WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L2L1 (0x31e2)
+#define WCD939X_TX_COM_NEW_INT_ADC_SCBIAS_L0ULP (0x31e3)
+#define WCD939X_TX_COM_NEW_INT_ADC_INT_L2 (0x31e4)
+#define WCD939X_TX_COM_NEW_INT_ADC_INT_L1 (0x31e5)
+#define WCD939X_TX_COM_NEW_INT_ADC_INT_L0 (0x31e6)
+#define WCD939X_TX_COM_NEW_INT_ADC_INT_ULP (0x31e7)
+#define WCD939X_DIGITAL_PAGE (0x3400)
+#define WCD939X_DIGITAL_CHIP_ID0 (0x3401)
+#define WCD939X_DIGITAL_CHIP_ID1 (0x3402)
+#define WCD939X_DIGITAL_CHIP_ID2 (0x3403)
+#define WCD939X_DIGITAL_CHIP_ID3 (0x3404)
+#define WCD939X_DIGITAL_SWR_TX_CLK_RATE (0x3405)
+#define WCD939X_DIGITAL_CDC_RST_CTL (0x3406)
+#define WCD939X_DIGITAL_TOP_CLK_CFG (0x3407)
+#define WCD939X_DIGITAL_CDC_ANA_CLK_CTL (0x3408)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV4_CLK_EN BIT(5)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN BIT(4)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN BIT(3)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN BIT(2)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN BIT(1)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN BIT(0)
+#define WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN BIT(4)
+#define WCD939X_DIGITAL_CDC_DIG_CLK_CTL (0x3409)
+#define WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN BIT(7)
+#define WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN BIT(6)
+#define WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN BIT(5)
+#define WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN BIT(4)
+#define WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN BIT(2)
+#define WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN BIT(1)
+#define WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN BIT(0)
+#define WCD939X_DIGITAL_SWR_RST_EN (0x340a)
+#define WCD939X_DIGITAL_CDC_PATH_MODE (0x340b)
+#define WCD939X_DIGITAL_CDC_RX_RST (0x340c)
+#define WCD939X_DIGITAL_CDC_RX0_CTL (0x340d)
+#define WCD939X_DIGITAL_CDC_RX1_CTL (0x340e)
+#define WCD939X_DIGITAL_CDC_RX2_CTL (0x340f)
+#define WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1 (0x3410)
+#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE GENMASK(7, 4)
+#define WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE GENMASK(3, 0)
+#define WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3 (0x3411)
+#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE GENMASK(7, 4)
+#define WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE GENMASK(3, 0)
+#define WCD939X_DIGITAL_CDC_COMP_CTL_0 (0x3414)
+#define WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN BIT(1)
+#define WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN BIT(0)
+#define WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL (0x3417)
+#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_MBHC_1P2M_CLK_EN BIT(5)
+#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX3_ADC_CLK_EN BIT(4)
+#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX2_ADC_CLK_EN BIT(3)
+#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX1_ADC_CLK_EN BIT(2)
+#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TX0_ADC_CLK_EN BIT(1)
+#define WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN BIT(0)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A1_0 (0x3418)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A1_1 (0x3419)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A2_0 (0x341a)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A2_1 (0x341b)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A3_0 (0x341c)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A3_1 (0x341d)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A4_0 (0x341e)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A4_1 (0x341f)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A5_0 (0x3420)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A5_1 (0x3421)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A6_0 (0x3422)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_A7_0 (0x3423)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_C_0 (0x3424)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_C_1 (0x3425)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_C_2 (0x3426)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_C_3 (0x3427)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R1 (0x3428)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R2 (0x3429)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R3 (0x342a)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R4 (0x342b)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R5 (0x342c)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R6 (0x342d)
+#define WCD939X_DIGITAL_CDC_HPH_DSM_R7 (0x342e)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A1_0 (0x342f)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A1_1 (0x3430)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A2_0 (0x3431)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A2_1 (0x3432)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A3_0 (0x3433)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A3_1 (0x3434)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A4_0 (0x3435)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A4_1 (0x3436)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A5_0 (0x3437)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A5_1 (0x3438)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A6_0 (0x3439)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_A7_0 (0x343a)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_C_0 (0x343b)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_C_1 (0x343c)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_C_2 (0x343d)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_C_3 (0x343e)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R1 (0x343f)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R2 (0x3440)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R3 (0x3441)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R4 (0x3442)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R5 (0x3443)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R6 (0x3444)
+#define WCD939X_DIGITAL_CDC_EAR_DSM_R7 (0x3445)
+#define WCD939X_DIGITAL_CDC_HPH_GAIN_RX_0 (0x3446)
+#define WCD939X_DIGITAL_CDC_HPH_GAIN_RX_1 (0x3447)
+#define WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_0 (0x3448)
+#define WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_1 (0x3449)
+#define WCD939X_DIGITAL_CDC_HPH_GAIN_DSD_2 (0x344a)
+#define WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_0 (0x344b)
+#define WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_1 (0x344c)
+#define WCD939X_DIGITAL_CDC_EAR_GAIN_DSD_2 (0x344d)
+#define WCD939X_DIGITAL_CDC_HPH_GAIN_CTL (0x344e)
+#define WCD939X_CDC_HPH_GAIN_CTL_HPH_STEREO_EN BIT(4)
+#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN BIT(3)
+#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN BIT(2)
+#define WCD939X_CDC_HPH_GAIN_CTL_HPHR_DSD_EN BIT(1)
+#define WCD939X_CDC_HPH_GAIN_CTL_HPHL_DSD_EN BIT(0)
+#define WCD939X_DIGITAL_CDC_EAR_GAIN_CTL (0x344f)
+#define WCD939X_CDC_EAR_GAIN_CTL_EAR_EN BIT(0)
+#define WCD939X_DIGITAL_CDC_EAR_PATH_CTL (0x3450)
+#define WCD939X_DIGITAL_CDC_SWR_CLH (0x3451)
+#define WCD939X_CDC_SWR_CLH_CLH_CTL GENMASK(7, 0)
+#define WCD939X_DIGITAL_SWR_CLH_BYP (0x3452)
+#define WCD939X_DIGITAL_CDC_TX0_CTL (0x3453)
+#define WCD939X_DIGITAL_CDC_TX1_CTL (0x3454)
+#define WCD939X_DIGITAL_CDC_TX2_CTL (0x3455)
+#define WCD939X_DIGITAL_CDC_TX_RST (0x3456)
+#define WCD939X_DIGITAL_CDC_REQ_CTL (0x3457)
+#define WCD939X_CDC_REQ_CTL_TX3_WIDE_BAND BIT(5)
+#define WCD939X_CDC_REQ_CTL_TX2_WIDE_BAND BIT(4)
+#define WCD939X_CDC_REQ_CTL_TX1_WIDE_BAND BIT(3)
+#define WCD939X_CDC_REQ_CTL_TX0_WIDE_BAND BIT(2)
+#define WCD939X_CDC_REQ_CTL_FS_RATE_4P8 BIT(1)
+#define WCD939X_CDC_REQ_CTL_NO_NOTCH BIT(0)
+#define WCD939X_DIGITAL_CDC_RST (0x3458)
+#define WCD939X_DIGITAL_CDC_AMIC_CTL (0x345a)
+#define WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL BIT(3)
+#define WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL BIT(2)
+#define WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL BIT(1)
+#define WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL BIT(0)
+#define WCD939X_DIGITAL_CDC_DMIC_CTL (0x345b)
+#define WCD939X_CDC_DMIC_CTL_DMIC_LEGACY_SW_MODE BIT(3)
+#define WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN BIT(2)
+#define WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN BIT(1)
+#define WCD939X_CDC_DMIC_CTL_SOFT_RESET BIT(0)
+#define WCD939X_DIGITAL_CDC_DMIC1_CTL (0x345c)
+#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4)
+#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN BIT(3)
+#define WCD939X_CDC_DMIC1_CTL_DMIC_CLK_SEL GENMASK(2, 0)
+#define WCD939X_DIGITAL_CDC_DMIC2_CTL (0x345d)
+#define WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN BIT(7)
+#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4)
+#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN BIT(3)
+#define WCD939X_CDC_DMIC2_CTL_DMIC_CLK_SEL GENMASK(2, 0)
+#define WCD939X_DIGITAL_CDC_DMIC3_CTL (0x345e)
+#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4)
+#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN BIT(3)
+#define WCD939X_CDC_DMIC3_CTL_DMIC_CLK_SEL GENMASK(2, 0)
+#define WCD939X_DIGITAL_CDC_DMIC4_CTL (0x345f)
+#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SCALE_SEL GENMASK(6, 4)
+#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN BIT(3)
+#define WCD939X_CDC_DMIC4_CTL_DMIC_CLK_SEL GENMASK(2, 0)
+#define WCD939X_DIGITAL_EFUSE_PRG_CTL (0x3460)
+#define WCD939X_DIGITAL_EFUSE_CTL (0x3461)
+#define WCD939X_DIGITAL_CDC_DMIC_RATE_1_2 (0x3462)
+#define WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE GENMASK(7, 4)
+#define WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE GENMASK(3, 0)
+#define WCD939X_DIGITAL_CDC_DMIC_RATE_3_4 (0x3463)
+#define WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE GENMASK(7, 4)
+#define WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE GENMASK(3, 0)
+#define WCD939X_DIGITAL_PDM_WD_CTL0 (0x3465)
+#define WCD939X_PDM_WD_CTL0_HOLD_OFF BIT(4)
+#define WCD939X_PDM_WD_CTL0_TIME_OUT_SEL BIT(3)
+#define WCD939X_PDM_WD_CTL0_PDM_WD_EN GENMASK(2, 0)
+#define WCD939X_DIGITAL_PDM_WD_CTL1 (0x3466)
+#define WCD939X_PDM_WD_CTL1_HOLD_OFF BIT(4)
+#define WCD939X_PDM_WD_CTL1_TIME_OUT_SEL BIT(3)
+#define WCD939X_PDM_WD_CTL1_PDM_WD_EN GENMASK(2, 0)
+#define WCD939X_DIGITAL_PDM_WD_CTL2 (0x3467)
+#define WCD939X_DIGITAL_INTR_MODE (0x346a)
+#define WCD939X_DIGITAL_INTR_MASK_0 (0x346b)
+#define WCD939X_DIGITAL_INTR_MASK_1 (0x346c)
+#define WCD939X_DIGITAL_INTR_MASK_2 (0x346d)
+#define WCD939X_DIGITAL_INTR_STATUS_0 (0x346e)
+#define WCD939X_DIGITAL_INTR_STATUS_1 (0x346f)
+#define WCD939X_DIGITAL_INTR_STATUS_2 (0x3470)
+#define WCD939X_DIGITAL_INTR_CLEAR_0 (0x3471)
+#define WCD939X_DIGITAL_INTR_CLEAR_1 (0x3472)
+#define WCD939X_DIGITAL_INTR_CLEAR_2 (0x3473)
+#define WCD939X_DIGITAL_INTR_LEVEL_0 (0x3474)
+#define WCD939X_DIGITAL_INTR_LEVEL_1 (0x3475)
+#define WCD939X_DIGITAL_INTR_LEVEL_2 (0x3476)
+#define WCD939X_DIGITAL_INTR_SET_0 (0x3477)
+#define WCD939X_DIGITAL_INTR_SET_1 (0x3478)
+#define WCD939X_DIGITAL_INTR_SET_2 (0x3479)
+#define WCD939X_DIGITAL_INTR_TEST_0 (0x347a)
+#define WCD939X_DIGITAL_INTR_TEST_1 (0x347b)
+#define WCD939X_DIGITAL_INTR_TEST_2 (0x347c)
+#define WCD939X_DIGITAL_TX_MODE_DBG_EN (0x347f)
+#define WCD939X_DIGITAL_TX_MODE_DBG_0_1 (0x3480)
+#define WCD939X_DIGITAL_TX_MODE_DBG_2_3 (0x3481)
+#define WCD939X_DIGITAL_LB_IN_SEL_CTL (0x3482)
+#define WCD939X_DIGITAL_LOOP_BACK_MODE (0x3483)
+#define WCD939X_DIGITAL_SWR_DAC_TEST (0x3484)
+#define WCD939X_DIGITAL_SWR_HM_TEST_RX_0 (0x3485)
+#define WCD939X_DIGITAL_SWR_HM_TEST_TX_0 (0x3486)
+#define WCD939X_DIGITAL_SWR_HM_TEST_RX_1 (0x3487)
+#define WCD939X_DIGITAL_SWR_HM_TEST_TX_1 (0x3488)
+#define WCD939X_DIGITAL_SWR_HM_TEST_TX_2 (0x3489)
+#define WCD939X_DIGITAL_SWR_HM_TEST_0 (0x348a)
+#define WCD939X_DIGITAL_SWR_HM_TEST_1 (0x348b)
+#define WCD939X_DIGITAL_PAD_CTL_SWR_0 (0x348c)
+#define WCD939X_DIGITAL_PAD_CTL_SWR_1 (0x348d)
+#define WCD939X_DIGITAL_I2C_CTL (0x348e)
+#define WCD939X_DIGITAL_CDC_TX_TANGGU_SW_MODE (0x348f)
+#define WCD939X_DIGITAL_EFUSE_TEST_CTL_0 (0x3490)
+#define WCD939X_DIGITAL_EFUSE_TEST_CTL_1 (0x3491)
+#define WCD939X_DIGITAL_EFUSE_T_DATA_0 (0x3492)
+#define WCD939X_DIGITAL_EFUSE_T_DATA_1 (0x3493)
+#define WCD939X_DIGITAL_PAD_CTL_PDM_RX0 (0x3494)
+#define WCD939X_DIGITAL_PAD_CTL_PDM_RX1 (0x3495)
+#define WCD939X_DIGITAL_PAD_CTL_PDM_TX0 (0x3496)
+#define WCD939X_DIGITAL_PAD_CTL_PDM_TX1 (0x3497)
+#define WCD939X_DIGITAL_PAD_CTL_PDM_TX2 (0x3498)
+#define WCD939X_DIGITAL_PAD_INP_DIS_0 (0x3499)
+#define WCD939X_DIGITAL_PAD_INP_DIS_1 (0x349a)
+#define WCD939X_DIGITAL_DRIVE_STRENGTH_0 (0x349b)
+#define WCD939X_DIGITAL_DRIVE_STRENGTH_1 (0x349c)
+#define WCD939X_DIGITAL_DRIVE_STRENGTH_2 (0x349d)
+#define WCD939X_DIGITAL_RX_DATA_EDGE_CTL (0x349e)
+#define WCD939X_DIGITAL_TX_DATA_EDGE_CTL (0x349f)
+#define WCD939X_DIGITAL_GPIO_MODE (0x34a0)
+#define WCD939X_DIGITAL_PIN_CTL_OE (0x34a1)
+#define WCD939X_DIGITAL_PIN_CTL_DATA_0 (0x34a2)
+#define WCD939X_DIGITAL_PIN_CTL_DATA_1 (0x34a3)
+#define WCD939X_DIGITAL_PIN_STATUS_0 (0x34a4)
+#define WCD939X_DIGITAL_PIN_STATUS_1 (0x34a5)
+#define WCD939X_DIGITAL_DIG_DEBUG_CTL (0x34a6)
+#define WCD939X_DIGITAL_DIG_DEBUG_EN (0x34a7)
+#define WCD939X_DIGITAL_ANA_CSR_DBG_ADD (0x34a8)
+#define WCD939X_DIGITAL_ANA_CSR_DBG_CTL (0x34a9)
+#define WCD939X_DIGITAL_SSP_DBG (0x34aa)
+#define WCD939X_DIGITAL_MODE_STATUS_0 (0x34ab)
+#define WCD939X_DIGITAL_MODE_STATUS_1 (0x34ac)
+#define WCD939X_DIGITAL_SPARE_0 (0x34ad)
+#define WCD939X_DIGITAL_SPARE_1 (0x34ae)
+#define WCD939X_DIGITAL_SPARE_2 (0x34af)
+#define WCD939X_DIGITAL_EFUSE_REG_0 (0x34b0)
+#define WCD939X_EFUSE_REG_0_WCD939X_ID GENMASK(4, 1)
+#define WCD939X_EFUSE_REG_0_EFUSE_BLOWN BIT(0)
+#define WCD939X_DIGITAL_EFUSE_REG_1 (0x34b1)
+#define WCD939X_DIGITAL_EFUSE_REG_2 (0x34b2)
+#define WCD939X_DIGITAL_EFUSE_REG_3 (0x34b3)
+#define WCD939X_DIGITAL_EFUSE_REG_4 (0x34b4)
+#define WCD939X_DIGITAL_EFUSE_REG_5 (0x34b5)
+#define WCD939X_DIGITAL_EFUSE_REG_6 (0x34b6)
+#define WCD939X_DIGITAL_EFUSE_REG_7 (0x34b7)
+#define WCD939X_DIGITAL_EFUSE_REG_8 (0x34b8)
+#define WCD939X_DIGITAL_EFUSE_REG_9 (0x34b9)
+#define WCD939X_DIGITAL_EFUSE_REG_10 (0x34ba)
+#define WCD939X_DIGITAL_EFUSE_REG_11 (0x34bb)
+#define WCD939X_DIGITAL_EFUSE_REG_12 (0x34bc)
+#define WCD939X_DIGITAL_EFUSE_REG_13 (0x34bd)
+#define WCD939X_DIGITAL_EFUSE_REG_14 (0x34be)
+#define WCD939X_DIGITAL_EFUSE_REG_15 (0x34bf)
+#define WCD939X_DIGITAL_EFUSE_REG_16 (0x34c0)
+#define WCD939X_DIGITAL_EFUSE_REG_17 (0x34c1)
+#define WCD939X_DIGITAL_EFUSE_REG_18 (0x34c2)
+#define WCD939X_DIGITAL_EFUSE_REG_19 (0x34c3)
+#define WCD939X_DIGITAL_EFUSE_REG_20 (0x34c4)
+#define WCD939X_DIGITAL_EFUSE_REG_21 (0x34c5)
+#define WCD939X_DIGITAL_EFUSE_REG_22 (0x34c6)
+#define WCD939X_DIGITAL_EFUSE_REG_23 (0x34c7)
+#define WCD939X_DIGITAL_EFUSE_REG_24 (0x34c8)
+#define WCD939X_DIGITAL_EFUSE_REG_25 (0x34c9)
+#define WCD939X_DIGITAL_EFUSE_REG_26 (0x34ca)
+#define WCD939X_DIGITAL_EFUSE_REG_27 (0x34cb)
+#define WCD939X_DIGITAL_EFUSE_REG_28 (0x34cc)
+#define WCD939X_DIGITAL_EFUSE_REG_29 (0x34cd)
+#define WCD939X_DIGITAL_EFUSE_REG_30 (0x34ce)
+#define WCD939X_DIGITAL_EFUSE_REG_31 (0x34cf)
+#define WCD939X_DIGITAL_TX_REQ_FB_CTL_0 (0x34d0)
+#define WCD939X_DIGITAL_TX_REQ_FB_CTL_1 (0x34d1)
+#define WCD939X_DIGITAL_TX_REQ_FB_CTL_2 (0x34d2)
+#define WCD939X_DIGITAL_TX_REQ_FB_CTL_3 (0x34d3)
+#define WCD939X_DIGITAL_TX_REQ_FB_CTL_4 (0x34d4)
+#define WCD939X_DIGITAL_DEM_BYPASS_DATA0 (0x34d5)
+#define WCD939X_DIGITAL_DEM_BYPASS_DATA1 (0x34d6)
+#define WCD939X_DIGITAL_DEM_BYPASS_DATA2 (0x34d7)
+#define WCD939X_DIGITAL_DEM_BYPASS_DATA3 (0x34d8)
+#define WCD939X_DIGITAL_DEM_SECOND_ORDER (0x34d9)
+#define WCD939X_DIGITAL_DSM_CTRL (0x34da)
+#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_0 (0x34db)
+#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_1 (0x34dc)
+#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_2 (0x34dd)
+#define WCD939X_DIGITAL_DSM_0_STATIC_DATA_3 (0x34de)
+#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_0 (0x34df)
+#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_1 (0x34e0)
+#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_2 (0x34e1)
+#define WCD939X_DIGITAL_DSM_1_STATIC_DATA_3 (0x34e2)
+#define WCD939X_RX_TOP_PAGE (0x3500)
+#define WCD939X_RX_TOP_TOP_CFG0 (0x3501)
+#define WCD939X_TOP_CFG0_HPH_DAC_RATE_SEL BIT(1)
+#define WCD939X_TOP_CFG0_PGA_UPDATE BIT(0)
+#define WCD939X_RX_TOP_HPHL_COMP_WR_LSB (0x3502)
+#define WCD939X_RX_TOP_HPHL_COMP_WR_MSB (0x3503)
+#define WCD939X_RX_TOP_HPHL_COMP_LUT (0x3504)
+#define WCD939X_RX_TOP_HPHL_COMP_RD_LSB (0x3505)
+#define WCD939X_RX_TOP_HPHL_COMP_RD_MSB (0x3506)
+#define WCD939X_RX_TOP_HPHR_COMP_WR_LSB (0x3507)
+#define WCD939X_RX_TOP_HPHR_COMP_WR_MSB (0x3508)
+#define WCD939X_RX_TOP_HPHR_COMP_LUT (0x3509)
+#define WCD939X_RX_TOP_HPHR_COMP_RD_LSB (0x350a)
+#define WCD939X_RX_TOP_HPHR_COMP_RD_MSB (0x350b)
+#define WCD939X_RX_TOP_DSD0_DEBUG_CFG1 (0x350c)
+#define WCD939X_RX_TOP_DSD0_DEBUG_CFG2 (0x350d)
+#define WCD939X_RX_TOP_DSD0_DEBUG_CFG3 (0x350e)
+#define WCD939X_RX_TOP_DSD0_DEBUG_CFG4 (0x350f)
+#define WCD939X_RX_TOP_DSD0_DEBUG_CFG5 (0x3510)
+#define WCD939X_RX_TOP_DSD0_DEBUG_CFG6 (0x3511)
+#define WCD939X_RX_TOP_DSD1_DEBUG_CFG1 (0x3512)
+#define WCD939X_RX_TOP_DSD1_DEBUG_CFG2 (0x3513)
+#define WCD939X_RX_TOP_DSD1_DEBUG_CFG3 (0x3514)
+#define WCD939X_RX_TOP_DSD1_DEBUG_CFG4 (0x3515)
+#define WCD939X_RX_TOP_DSD1_DEBUG_CFG5 (0x3516)
+#define WCD939X_RX_TOP_DSD1_DEBUG_CFG6 (0x3517)
+#define WCD939X_RX_TOP_HPHL_PATH_CFG0 (0x351c)
+#define WCD939X_HPHL_PATH_CFG0_INT_EN BIT(1)
+#define WCD939X_HPHL_PATH_CFG0_DLY_ZN_EN BIT(0)
+#define WCD939X_RX_TOP_HPHL_PATH_CFG1 (0x351d)
+#define WCD939X_HPHL_PATH_CFG1_DSM_SOFT_RST BIT(5)
+#define WCD939X_HPHL_PATH_CFG1_INT_SOFT_RST BIT(4)
+#define WCD939X_HPHL_PATH_CFG1_FMT_CONV BIT(3)
+#define WCD939X_HPHL_PATH_CFG1_IDLE_OVRD_EN BIT(2)
+#define WCD939X_HPHL_PATH_CFG1_RX_DC_DROOP_COEFF_SEL GENMASK(1, 0)
+#define WCD939X_RX_TOP_HPHR_PATH_CFG0 (0x351e)
+#define WCD939X_HPHR_PATH_CFG0_INT_EN BIT(2)
+#define WCD939X_HPHR_PATH_CFG0_DLY_ZN_EN BIT(1)
+#define WCD939X_RX_TOP_HPHR_PATH_CFG1 (0x351f)
+#define WCD939X_HPHR_PATH_CFG1_DSM_SOFT_RST BIT(5)
+#define WCD939X_HPHR_PATH_CFG1_INT_SOFT_RST BIT(4)
+#define WCD939X_HPHR_PATH_CFG1_FMT_CONV BIT(3)
+#define WCD939X_HPHR_PATH_CFG1_IDLE_OVRD_EN BIT(2)
+#define WCD939X_HPHR_PATH_CFG1_RX_DC_DROOP_COEFF_SEL GENMASK(1, 0)
+#define WCD939X_RX_TOP_PATH_CFG2 (0x3520)
+#define WCD939X_RX_TOP_HPHL_PATH_SEC0 (0x3521)
+#define WCD939X_RX_TOP_HPHL_PATH_SEC1 (0x3522)
+#define WCD939X_RX_TOP_HPHL_PATH_SEC2 (0x3523)
+#define WCD939X_RX_TOP_HPHL_PATH_SEC3 (0x3524)
+#define WCD939X_RX_TOP_HPHR_PATH_SEC0 (0x3525)
+#define WCD939X_RX_TOP_HPHR_PATH_SEC1 (0x3526)
+#define WCD939X_RX_TOP_HPHR_PATH_SEC2 (0x3527)
+#define WCD939X_RX_TOP_HPHR_PATH_SEC3 (0x3528)
+#define WCD939X_RX_TOP_PATH_SEC4 (0x3529)
+#define WCD939X_RX_TOP_PATH_SEC5 (0x352a)
+#define WCD939X_COMPANDER_HPHL_CTL0 (0x3540)
+#define WCD939X_COMPANDER_HPHL_CTL1 (0x3541)
+#define WCD939X_COMPANDER_HPHL_CTL2 (0x3542)
+#define WCD939X_COMPANDER_HPHL_CTL3 (0x3543)
+#define WCD939X_COMPANDER_HPHL_CTL4 (0x3544)
+#define WCD939X_COMPANDER_HPHL_CTL5 (0x3545)
+#define WCD939X_COMPANDER_HPHL_CTL6 (0x3546)
+#define WCD939X_COMPANDER_HPHL_CTL7 (0x3547)
+#define WCD939X_COMPANDER_HPHL_CTL8 (0x3548)
+#define WCD939X_COMPANDER_HPHL_CTL9 (0x3549)
+#define WCD939X_COMPANDER_HPHL_CTL10 (0x354a)
+#define WCD939X_COMPANDER_HPHL_CTL11 (0x354b)
+#define WCD939X_COMPANDER_HPHL_CTL12 (0x354c)
+#define WCD939X_COMPANDER_HPHL_CTL13 (0x354d)
+#define WCD939X_COMPANDER_HPHL_CTL14 (0x354e)
+#define WCD939X_COMPANDER_HPHL_CTL15 (0x354f)
+#define WCD939X_COMPANDER_HPHL_CTL16 (0x3550)
+#define WCD939X_COMPANDER_HPHL_CTL17 (0x3551)
+#define WCD939X_COMPANDER_HPHL_CTL18 (0x3552)
+#define WCD939X_COMPANDER_HPHL_CTL19 (0x3553)
+#define WCD939X_R_CTL0 (0x3560)
+#define WCD939X_R_CTL1 (0x3561)
+#define WCD939X_R_CTL2 (0x3562)
+#define WCD939X_R_CTL3 (0x3563)
+#define WCD939X_R_CTL4 (0x3564)
+#define WCD939X_R_CTL5 (0x3565)
+#define WCD939X_R_CTL6 (0x3566)
+#define WCD939X_R_CTL7 (0x3567)
+#define WCD939X_R_CTL8 (0x3568)
+#define WCD939X_R_CTL9 (0x3569)
+#define WCD939X_R_CTL10 (0x356a)
+#define WCD939X_R_CTL11 (0x356b)
+#define WCD939X_R_CTL12 (0x356c)
+#define WCD939X_R_CTL13 (0x356d)
+#define WCD939X_R_CTL14 (0x356e)
+#define WCD939X_R_CTL15 (0x356f)
+#define WCD939X_R_CTL16 (0x3570)
+#define WCD939X_R_CTL17 (0x3571)
+#define WCD939X_R_CTL18 (0x3572)
+#define WCD939X_R_CTL19 (0x3573)
+#define WCD939X_E_PATH_CTL (0x3580)
+#define WCD939X_E_CFG0 (0x3581)
+#define WCD939X_CFG0_AUTO_DISABLE_ANC BIT(2)
+#define WCD939X_CFG0_AUTO_DISABLE_DSD BIT(1)
+#define WCD939X_CFG0_IDLE_STEREO BIT(0)
+#define WCD939X_E_CFG1 (0x3582)
+#define WCD939X_E_CFG2 (0x3583)
+#define WCD939X_E_CFG3 (0x3584)
+#define WCD939X_DSD_HPHL_PATH_CTL (0x3590)
+#define WCD939X_DSD_HPHL_CFG0 (0x3591)
+#define WCD939X_DSD_HPHL_CFG1 (0x3592)
+#define WCD939X_DSD_HPHL_CFG2 (0x3593)
+#define WCD939X_DSD_HPHL_CFG3 (0x3594)
+#define WCD939X_DSD_HPHL_CFG4 (0x3595)
+#define WCD939X_DSD_HPHL_CFG5 (0x3596)
+#define WCD939X_DSD_HPHR_PATH_CTL (0x35a0)
+#define WCD939X_DSD_HPHR_CFG0 (0x35a1)
+#define WCD939X_DSD_HPHR_CFG1 (0x35a2)
+#define WCD939X_DSD_HPHR_CFG2 (0x35a3)
+#define WCD939X_DSD_HPHR_CFG3 (0x35a4)
+#define WCD939X_DSD_HPHR_CFG4 (0x35a5)
+#define WCD939X_DSD_HPHR_CFG5 (0x35a6)
+#define WCD939X_MAX_REGISTER (WCD939X_DSD_HPHR_CFG5)
+
+#define WCD939X_MAX_SWR_CH_IDS (15)
+
+enum wcd939x_tx_sdw_ports {
+ WCD939X_ADC_1_4_PORT = 1,
+ WCD939X_ADC_DMIC_1_2_PORT,
+ WCD939X_DMIC_0_3_MBHC_PORT,
+ WCD939X_DMIC_3_7_PORT,
+ WCD939X_MAX_TX_SWR_PORTS = WCD939X_DMIC_3_7_PORT,
+};
+
+enum wcd939x_tx_sdw_channels {
+ WCD939X_ADC1,
+ WCD939X_ADC2,
+ WCD939X_ADC3,
+ WCD939X_ADC4,
+ WCD939X_DMIC0,
+ WCD939X_DMIC1,
+ WCD939X_MBHC,
+ WCD939X_DMIC2,
+ WCD939X_DMIC3,
+ WCD939X_DMIC4,
+ WCD939X_DMIC5,
+ WCD939X_DMIC6,
+ WCD939X_DMIC7,
+};
+
+enum wcd939x_rx_sdw_ports {
+ WCD939X_HPH_PORT = 1,
+ WCD939X_CLSH_PORT,
+ WCD939X_COMP_PORT,
+ WCD939X_LO_PORT,
+ WCD939X_DSD_PORT,
+ WCD939X_HIFI_PCM_PORT,
+ WCD939X_MAX_RX_SWR_PORTS = WCD939X_HIFI_PCM_PORT,
+ WCD939X_MAX_SWR_PORTS = WCD939X_MAX_RX_SWR_PORTS,
+};
+
+enum wcd939x_rx_sdw_channels {
+ WCD939X_HPH_L,
+ WCD939X_HPH_R,
+ WCD939X_CLSH,
+ WCD939X_COMP_L,
+ WCD939X_COMP_R,
+ WCD939X_LO,
+ WCD939X_DSD_L,
+ WCD939X_DSD_R,
+ WCD939X_HIFI_PCM_L,
+ WCD939X_HIFI_PCM_R,
+};
+
+struct wcd939x_priv;
+struct wcd939x_sdw_priv {
+ struct sdw_slave *sdev;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[WCD939X_MAX_SWR_PORTS];
+ const struct wcd_sdw_ch_info *ch_info;
+ bool port_enable[WCD939X_MAX_SWR_CH_IDS];
+ int active_ports;
+ bool is_tx;
+ struct wcd939x_priv *wcd939x;
+ struct irq_domain *slave_irq;
+ struct regmap *regmap;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_WCD939X_SDW)
+int wcd939x_sdw_free(struct wcd939x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int wcd939x_sdw_set_sdw_stream(struct wcd939x_sdw_priv *wcd,
+ struct snd_soc_dai *dai,
+ void *stream, int direction);
+int wcd939x_sdw_hw_params(struct wcd939x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+#else
+
+static inline int wcd939x_sdw_free(struct wcd939x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int wcd939x_sdw_set_sdw_stream(struct wcd939x_sdw_priv *wcd,
+ struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int wcd939x_sdw_hw_params(struct wcd939x_sdw_priv *wcd,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_SND_SOC_WCD939X_SDW */
+
+#endif /* __WCD939X_H__ */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
deleted file mode 100644
index 737ca82cf976..000000000000
--- a/sound/soc/codecs/wl1273.c
+++ /dev/null
@@ -1,500 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ALSA SoC WL1273 codec driver
- *
- * Author: Matti Aaltonen, <matti.j.aaltonen@nokia.com>
- *
- * Copyright: (C) 2010, 2011 Nokia Corporation
- */
-
-#include <linux/mfd/wl1273-core.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
-
-#include "wl1273.h"
-
-enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
-
-/* codec private data */
-struct wl1273_priv {
- enum wl1273_mode mode;
- struct wl1273_core *core;
- unsigned int channels;
-};
-
-static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
- int rate, int width)
-{
- struct device *dev = &core->client->dev;
- int r = 0;
- u16 mode;
-
- dev_dbg(dev, "rate: %d\n", rate);
- dev_dbg(dev, "width: %d\n", width);
-
- mutex_lock(&core->lock);
-
- mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
-
- switch (rate) {
- case 48000:
- mode |= WL1273_IS2_RATE_48K;
- break;
- case 44100:
- mode |= WL1273_IS2_RATE_44_1K;
- break;
- case 32000:
- mode |= WL1273_IS2_RATE_32K;
- break;
- case 22050:
- mode |= WL1273_IS2_RATE_22_05K;
- break;
- case 16000:
- mode |= WL1273_IS2_RATE_16K;
- break;
- case 12000:
- mode |= WL1273_IS2_RATE_12K;
- break;
- case 11025:
- mode |= WL1273_IS2_RATE_11_025;
- break;
- case 8000:
- mode |= WL1273_IS2_RATE_8K;
- break;
- default:
- dev_err(dev, "Sampling rate: %d not supported\n", rate);
- r = -EINVAL;
- goto out;
- }
-
- switch (width) {
- case 16:
- mode |= WL1273_IS2_WIDTH_32;
- break;
- case 20:
- mode |= WL1273_IS2_WIDTH_40;
- break;
- case 24:
- mode |= WL1273_IS2_WIDTH_48;
- break;
- case 25:
- mode |= WL1273_IS2_WIDTH_50;
- break;
- case 30:
- mode |= WL1273_IS2_WIDTH_60;
- break;
- case 32:
- mode |= WL1273_IS2_WIDTH_64;
- break;
- case 40:
- mode |= WL1273_IS2_WIDTH_80;
- break;
- case 48:
- mode |= WL1273_IS2_WIDTH_96;
- break;
- case 64:
- mode |= WL1273_IS2_WIDTH_128;
- break;
- default:
- dev_err(dev, "Data width: %d not supported\n", width);
- r = -EINVAL;
- goto out;
- }
-
- dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n", WL1273_I2S_DEF_MODE);
- dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
- dev_dbg(dev, "mode: 0x%04x\n", mode);
-
- if (core->i2s_mode != mode) {
- r = core->write(core, WL1273_I2S_MODE_CONFIG_SET, mode);
- if (r)
- goto out;
-
- core->i2s_mode = mode;
- r = core->write(core, WL1273_AUDIO_ENABLE,
- WL1273_AUDIO_ENABLE_I2S);
- if (r)
- goto out;
- }
-out:
- mutex_unlock(&core->lock);
-
- return r;
-}
-
-static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
- int channel_number)
-{
- struct device *dev = &core->client->dev;
- int r = 0;
-
- dev_dbg(dev, "%s\n", __func__);
-
- mutex_lock(&core->lock);
-
- if (core->channel_number == channel_number)
- goto out;
-
- if (channel_number == 1 && core->mode == WL1273_MODE_RX)
- r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO);
- else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
- r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO);
- else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
- r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO);
- else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
- r = core->write(core, WL1273_MONO_SET, WL1273_TX_STEREO);
- else
- r = -EINVAL;
-out:
- mutex_unlock(&core->lock);
-
- return r;
-}
-
-static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
-
- ucontrol->value.enumerated.item[0] = wl1273->mode;
-
- return 0;
-}
-
-/*
- * TODO: Implement the audio routing in the driver. Now this control
- * only indicates the setting that has been done elsewhere (in the user
- * space).
- */
-static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
-
-static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
-
- if (wl1273->mode == ucontrol->value.enumerated.item[0])
- return 0;
-
- /* Do not allow changes while stream is running */
- if (snd_soc_component_active(component))
- return -EPERM;
-
- if (ucontrol->value.enumerated.item[0] >= ARRAY_SIZE(wl1273_audio_route))
- return -EINVAL;
-
- wl1273->mode = ucontrol->value.enumerated.item[0];
-
- return 1;
-}
-
-static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
-
-static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
-
- dev_dbg(component->dev, "%s: enter.\n", __func__);
-
- ucontrol->value.enumerated.item[0] = wl1273->core->audio_mode;
-
- return 0;
-}
-
-static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
- int val, r = 0;
-
- dev_dbg(component->dev, "%s: enter.\n", __func__);
-
- val = ucontrol->value.enumerated.item[0];
- if (wl1273->core->audio_mode == val)
- return 0;
-
- r = wl1273->core->set_audio(wl1273->core, val);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static const char * const wl1273_audio_strings[] = { "Digital", "Analog" };
-
-static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
-
-static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
-
- dev_dbg(component->dev, "%s: enter.\n", __func__);
-
- ucontrol->value.integer.value[0] = wl1273->core->volume;
-
- return 0;
-}
-
-static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
- int r;
-
- dev_dbg(component->dev, "%s: enter.\n", __func__);
-
- r = wl1273->core->set_volume(wl1273->core,
- ucontrol->value.integer.value[0]);
- if (r)
- return r;
-
- return 1;
-}
-
-static const struct snd_kcontrol_new wl1273_controls[] = {
- SOC_ENUM_EXT("Codec Mode", wl1273_enum,
- snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
- SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
- snd_wl1273_fm_audio_get, snd_wl1273_fm_audio_put),
- SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
- snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
-};
-
-static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = {
- SND_SOC_DAPM_INPUT("RX"),
-
- SND_SOC_DAPM_OUTPUT("TX"),
-};
-
-static const struct snd_soc_dapm_route wl1273_dapm_routes[] = {
- { "Capture", NULL, "RX" },
-
- { "TX", NULL, "Playback" },
-};
-
-static int wl1273_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
-
- switch (wl1273->mode) {
- case WL1273_MODE_BT:
- snd_pcm_hw_constraint_single(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE, 8000);
- snd_pcm_hw_constraint_single(substream->runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS, 1);
- break;
- case WL1273_MODE_FM_RX:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- pr_err("Cannot play in RX mode.\n");
- return -EINVAL;
- }
- break;
- case WL1273_MODE_FM_TX:
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- pr_err("Cannot capture in TX mode.\n");
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int wl1273_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(dai->component);
- struct wl1273_core *core = wl1273->core;
- unsigned int rate, width, r;
-
- if (params_width(params) != 16) {
- dev_err(dai->dev, "%d bits/sample not supported\n",
- params_width(params));
- return -EINVAL;
- }
-
- rate = params_rate(params);
- width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
-
- if (wl1273->mode == WL1273_MODE_BT) {
- if (rate != 8000) {
- pr_err("Rate %d not supported.\n", params_rate(params));
- return -EINVAL;
- }
-
- if (params_channels(params) != 1) {
- pr_err("Only mono supported.\n");
- return -EINVAL;
- }
-
- return 0;
- }
-
- if (wl1273->mode == WL1273_MODE_FM_TX &&
- substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- pr_err("Only playback supported with TX.\n");
- return -EINVAL;
- }
-
- if (wl1273->mode == WL1273_MODE_FM_RX &&
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- pr_err("Only capture supported with RX.\n");
- return -EINVAL;
- }
-
- if (wl1273->mode != WL1273_MODE_FM_RX &&
- wl1273->mode != WL1273_MODE_FM_TX) {
- pr_err("Unexpected mode: %d.\n", wl1273->mode);
- return -EINVAL;
- }
-
- r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
- if (r)
- return r;
-
- wl1273->channels = params_channels(params);
- r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
- if (r)
- return r;
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops wl1273_dai_ops = {
- .startup = wl1273_startup,
- .hw_params = wl1273_hw_params,
-};
-
-static struct snd_soc_dai_driver wl1273_dai = {
- .name = "wl1273-fm",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE},
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE},
- .ops = &wl1273_dai_ops,
-};
-
-/* Audio interface format for the soc_card driver */
-int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt)
-{
- struct wl1273_priv *wl1273;
-
- if (component == NULL || fmt == NULL)
- return -EINVAL;
-
- wl1273 = snd_soc_component_get_drvdata(component);
-
- switch (wl1273->mode) {
- case WL1273_MODE_FM_RX:
- case WL1273_MODE_FM_TX:
- *fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBP_CFP;
-
- break;
- case WL1273_MODE_BT:
- *fmt = SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBP_CFP;
-
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(wl1273_get_format);
-
-static int wl1273_probe(struct snd_soc_component *component)
-{
- struct wl1273_core **core = component->dev->platform_data;
- struct wl1273_priv *wl1273;
-
- dev_dbg(component->dev, "%s.\n", __func__);
-
- if (!core) {
- dev_err(component->dev, "Platform data is missing.\n");
- return -EINVAL;
- }
-
- wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
- if (!wl1273)
- return -ENOMEM;
-
- wl1273->mode = WL1273_MODE_BT;
- wl1273->core = *core;
-
- snd_soc_component_set_drvdata(component, wl1273);
-
- return 0;
-}
-
-static void wl1273_remove(struct snd_soc_component *component)
-{
- struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
-
- dev_dbg(component->dev, "%s\n", __func__);
- kfree(wl1273);
-}
-
-static const struct snd_soc_component_driver soc_component_dev_wl1273 = {
- .probe = wl1273_probe,
- .remove = wl1273_remove,
- .controls = wl1273_controls,
- .num_controls = ARRAY_SIZE(wl1273_controls),
- .dapm_widgets = wl1273_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets),
- .dapm_routes = wl1273_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes),
- .idle_bias_on = 1,
- .use_pmdown_time = 1,
- .endianness = 1,
-};
-
-static int wl1273_platform_probe(struct platform_device *pdev)
-{
- return devm_snd_soc_register_component(&pdev->dev,
- &soc_component_dev_wl1273,
- &wl1273_dai, 1);
-}
-
-MODULE_ALIAS("platform:wl1273-codec");
-
-static struct platform_driver wl1273_platform_driver = {
- .driver = {
- .name = "wl1273-codec",
- },
- .probe = wl1273_platform_probe,
-};
-
-module_platform_driver(wl1273_platform_driver);
-
-MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
-MODULE_DESCRIPTION("ASoC WL1273 codec driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
deleted file mode 100644
index 66c312fa7eee..000000000000
--- a/sound/soc/codecs/wl1273.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * sound/soc/codec/wl1273.h
- *
- * ALSA SoC WL1273 codec driver
- *
- * Copyright (C) Nokia Corporation
- * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
- */
-
-#ifndef __WL1273_CODEC_H__
-#define __WL1273_CODEC_H__
-
-int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt);
-
-#endif /* End of __WL1273_CODEC_H__ */
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 034a4e858c7e..7511c71695c6 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -18,7 +18,7 @@
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/fs.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
@@ -94,8 +94,7 @@ struct wm0010_priv {
struct wm0010_pdata pdata;
- int gpio_reset;
- int gpio_reset_value;
+ struct gpio_desc *reset;
struct regulator_bulk_data core_supplies[2];
struct regulator *dbvdd;
@@ -116,14 +115,6 @@ struct wm0010_priv {
struct completion boot_completion;
};
-struct wm0010_spi_msg {
- struct spi_message m;
- struct spi_transfer t;
- u8 *tx_buf;
- u8 *rx_buf;
- size_t len;
-};
-
static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("CLKIN", SND_SOC_NOPM, 0, 0, NULL, 0),
};
@@ -174,8 +165,7 @@ static void wm0010_halt(struct snd_soc_component *component)
case WM0010_STAGE2:
case WM0010_FIRMWARE:
/* Remember to put chip back into reset */
- gpio_set_value_cansleep(wm0010->gpio_reset,
- wm0010->gpio_reset_value);
+ gpiod_set_value_cansleep(wm0010->reset, 1);
/* Disable the regulators */
regulator_disable(wm0010->dbvdd);
regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
@@ -610,7 +600,7 @@ static int wm0010_boot(struct snd_soc_component *component)
}
/* Release reset */
- gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
+ gpiod_set_value_cansleep(wm0010->reset, 0);
spin_lock_irqsave(&wm0010->irq_lock, flags);
wm0010->state = WM0010_OUT_OF_RESET;
spin_unlock_irqrestore(&wm0010->irq_lock, flags);
@@ -733,16 +723,17 @@ static int wm0010_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE)
wm0010_boot(component);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) {
mutex_lock(&wm0010->lock);
wm0010_halt(component);
mutex_unlock(&wm0010->lock);
@@ -863,7 +854,6 @@ static int wm0010_probe(struct snd_soc_component *component)
static int wm0010_spi_probe(struct spi_device *spi)
{
- unsigned long gpio_flags;
int ret;
int trigger;
int irq;
@@ -903,31 +893,11 @@ static int wm0010_spi_probe(struct spi_device *spi)
return ret;
}
- if (wm0010->pdata.gpio_reset) {
- wm0010->gpio_reset = wm0010->pdata.gpio_reset;
-
- if (wm0010->pdata.reset_active_high)
- wm0010->gpio_reset_value = 1;
- else
- wm0010->gpio_reset_value = 0;
-
- if (wm0010->gpio_reset_value)
- gpio_flags = GPIOF_OUT_INIT_HIGH;
- else
- gpio_flags = GPIOF_OUT_INIT_LOW;
-
- ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset,
- gpio_flags, "wm0010 reset");
- if (ret < 0) {
- dev_err(wm0010->dev,
- "Failed to request GPIO for DSP reset: %d\n",
- ret);
- return ret;
- }
- } else {
- dev_err(wm0010->dev, "No reset GPIO configured\n");
- return -EINVAL;
- }
+ wm0010->reset = devm_gpiod_get(wm0010->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(wm0010->reset))
+ return dev_err_probe(wm0010->dev, PTR_ERR(wm0010->reset),
+ "could not get RESET GPIO\n");
+ gpiod_set_consumer_name(wm0010->reset, "wm0010 reset");
wm0010->state = WM0010_POWER_OFF;
@@ -951,7 +921,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)
@@ -963,17 +933,25 @@ 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)
{
struct wm0010_priv *wm0010 = spi_get_drvdata(spi);
- gpio_set_value_cansleep(wm0010->gpio_reset,
- wm0010->gpio_reset_value);
+ gpiod_set_value_cansleep(wm0010->reset, 1);
irq_set_irq_wake(wm0010->irq, 0);
@@ -994,3 +972,6 @@ module_spi_driver(wm0010_spi_driver);
MODULE_DESCRIPTION("ASoC WM0010 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
+
+MODULE_FIRMWARE("wm0010.dfw");
+MODULE_FIRMWARE("wm0010_stage2.bin");
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index d7eeb41ba60f..1f59309d8c69 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -9,34 +9,23 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/wm1250-ev1.h>
-
-static const char *wm1250_gpio_names[WM1250_EV1_NUM_GPIOS] = {
- "WM1250 CLK_ENA",
- "WM1250 CLK_SEL0",
- "WM1250 CLK_SEL1",
- "WM1250 OSR",
- "WM1250 MASTER",
-};
struct wm1250_priv {
- struct gpio gpios[WM1250_EV1_NUM_GPIOS];
+ struct gpio_desc *clk_ena;
+ struct gpio_desc *clk_sel0;
+ struct gpio_desc *clk_sel1;
+ struct gpio_desc *osr;
+ struct gpio_desc *master;
};
static int wm1250_ev1_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm1250_priv *wm1250 = dev_get_drvdata(component->dev);
- int ena;
-
- if (wm1250)
- ena = wm1250->gpios[WM1250_EV1_GPIO_CLK_ENA].gpio;
- else
- ena = -1;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -46,13 +35,11 @@ static int wm1250_ev1_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (ena >= 0)
- gpio_set_value_cansleep(ena, 1);
+ gpiod_set_value_cansleep(wm1250->clk_ena, 1);
break;
case SND_SOC_BIAS_OFF:
- if (ena >= 0)
- gpio_set_value_cansleep(ena, 0);
+ gpiod_set_value_cansleep(wm1250->clk_ena, 0);
break;
}
@@ -80,28 +67,20 @@ static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 8000:
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
- 1);
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
- 1);
+ gpiod_set_value(wm1250->clk_sel0, 1);
+ gpiod_set_value(wm1250->clk_sel1, 1);
break;
case 16000:
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
- 0);
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
- 1);
+ gpiod_set_value(wm1250->clk_sel0, 0);
+ gpiod_set_value(wm1250->clk_sel1, 1);
break;
case 32000:
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
- 1);
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
- 0);
+ gpiod_set_value(wm1250->clk_sel0, 1);
+ gpiod_set_value(wm1250->clk_sel1, 0);
break;
case 64000:
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
- 0);
- gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
- 0);
+ gpiod_set_value(wm1250->clk_sel0, 0);
+ gpiod_set_value(wm1250->clk_sel1, 0);
break;
default:
return -EINVAL;
@@ -150,45 +129,42 @@ static int wm1250_ev1_pdata(struct i2c_client *i2c)
{
struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev);
struct wm1250_priv *wm1250;
- int i, ret;
if (!pdata)
return 0;
wm1250 = devm_kzalloc(&i2c->dev, sizeof(*wm1250), GFP_KERNEL);
- if (!wm1250) {
- ret = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(wm1250->gpios); i++) {
- wm1250->gpios[i].gpio = pdata->gpios[i];
- wm1250->gpios[i].label = wm1250_gpio_names[i];
- wm1250->gpios[i].flags = GPIOF_OUT_INIT_LOW;
- }
- wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].flags = GPIOF_OUT_INIT_HIGH;
- wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].flags = GPIOF_OUT_INIT_HIGH;
-
- ret = gpio_request_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to get GPIOs: %d\n", ret);
- goto err;
- }
+ if (!wm1250)
+ return -ENOMEM;
+
+ wm1250->clk_ena = devm_gpiod_get(&i2c->dev, "clk-ena", GPIOD_OUT_LOW);
+ if (IS_ERR(wm1250->clk_ena))
+ return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->clk_ena),
+ "failed to get clock enable GPIO\n");
+
+ wm1250->clk_sel0 = devm_gpiod_get(&i2c->dev, "clk-sel0", GPIOD_OUT_HIGH);
+ if (IS_ERR(wm1250->clk_sel0))
+ return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->clk_sel0),
+ "failed to get clock sel0 GPIO\n");
+
+ wm1250->clk_sel1 = devm_gpiod_get(&i2c->dev, "clk-sel1", GPIOD_OUT_HIGH);
+ if (IS_ERR(wm1250->clk_sel1))
+ return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->clk_sel1),
+ "failed to get clock sel1 GPIO\n");
+
+ wm1250->osr = devm_gpiod_get(&i2c->dev, "osr", GPIOD_OUT_LOW);
+ if (IS_ERR(wm1250->osr))
+ return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->osr),
+ "failed to get OSR GPIO\n");
+
+ wm1250->master = devm_gpiod_get(&i2c->dev, "master", GPIOD_OUT_LOW);
+ if (IS_ERR(wm1250->master))
+ return dev_err_probe(&i2c->dev, PTR_ERR(wm1250->master),
+ "failed to get MASTER GPIO\n");
dev_set_drvdata(&i2c->dev, wm1250);
- return ret;
-
-err:
- return ret;
-}
-
-static void wm1250_ev1_free(struct i2c_client *i2c)
-{
- struct wm1250_priv *wm1250 = dev_get_drvdata(&i2c->dev);
-
- if (wm1250)
- gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
+ return 0;
}
static int wm1250_ev1_probe(struct i2c_client *i2c)
@@ -221,20 +197,14 @@ static int wm1250_ev1_probe(struct i2c_client *i2c)
&wm1250_ev1_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
- wm1250_ev1_free(i2c);
return ret;
}
return 0;
}
-static void wm1250_ev1_remove(struct i2c_client *i2c)
-{
- wm1250_ev1_free(i2c);
-}
-
static const struct i2c_device_id wm1250_ev1_i2c_id[] = {
- { "wm1250-ev1", 0 },
+ { "wm1250-ev1" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id);
@@ -244,7 +214,6 @@ static struct i2c_driver wm1250_ev1_i2c_driver = {
.name = "wm1250-ev1",
},
.probe = wm1250_ev1_probe,
- .remove = wm1250_ev1_remove,
.id_table = wm1250_ev1_i2c_id,
};
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 9571ea53cb3f..126be2a2a8f3 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -598,7 +598,7 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
ucontrol->value.integer.value[0] = wm2000->anc_active;
@@ -609,7 +609,7 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
unsigned int anc_active = ucontrol->value.integer.value[0];
int ret;
@@ -631,7 +631,7 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
ucontrol->value.integer.value[0] = wm2000->spk_ena;
@@ -642,7 +642,7 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
unsigned int val = ucontrol->value.integer.value[0];
int ret;
@@ -929,7 +929,7 @@ out:
}
static const struct i2c_device_id wm2000_i2c_id[] = {
- { "wm2000", 0 },
+ { "wm2000" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id);
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 277b8c468c78..87418c838ca0 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -14,7 +14,7 @@
#include <linux/pm.h>
#include <linux/firmware.h>
#include <linux/gcd.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -79,6 +79,8 @@ struct wm2200_priv {
struct snd_soc_component *component;
struct wm2200_pdata pdata;
struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES];
+ struct gpio_desc *ldo_ena;
+ struct gpio_desc *reset;
struct completion fll_lock;
int fll_fout;
@@ -975,9 +977,10 @@ static const struct reg_sequence wm2200_reva_patch[] = {
static int wm2200_reset(struct wm2200_priv *wm2200)
{
- if (wm2200->pdata.reset) {
- gpio_set_value_cansleep(wm2200->pdata.reset, 0);
- gpio_set_value_cansleep(wm2200->pdata.reset, 1);
+ if (wm2200->reset) {
+ /* Descriptor flagged active low, so this will be inverted */
+ gpiod_set_value_cansleep(wm2200->reset, 1);
+ gpiod_set_value_cansleep(wm2200->reset, 0);
return 0;
} else {
@@ -1573,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;
@@ -1770,11 +1773,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops wm2200_dai_ops = {
- .set_fmt = wm2200_set_fmt,
- .hw_params = wm2200_hw_params,
-};
-
static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id,
int source, unsigned int freq, int dir)
{
@@ -2068,6 +2066,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops wm2200_dai_ops = {
+ .probe = wm2200_dai_probe,
+ .set_fmt = wm2200_set_fmt,
+ .hw_params = wm2200_hw_params,
+};
+
#define WM2200_RATES SNDRV_PCM_RATE_8000_48000
#define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
@@ -2075,7 +2079,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver wm2200_dai = {
.name = "wm2200",
- .probe = wm2200_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -2151,7 +2154,7 @@ static const struct regmap_config wm2200_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
.volatile_reg = wm2200_volatile_register,
.readable_reg = wm2200_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.ranges = wm2200_ranges,
.num_ranges = ARRAY_SIZE(wm2200_ranges),
};
@@ -2246,28 +2249,28 @@ static int wm2200_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (wm2200->pdata.ldo_ena) {
- ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena,
- GPIOF_OUT_INIT_HIGH,
- "WM2200 LDOENA");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
- wm2200->pdata.ldo_ena, ret);
- goto err_enable;
- }
+ wm2200->ldo_ena = devm_gpiod_get_optional(&i2c->dev, "wlf,ldo1ena",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(wm2200->ldo_ena)) {
+ ret = PTR_ERR(wm2200->ldo_ena);
+ dev_err(&i2c->dev, "Failed to request LDOENA GPIO %d\n",
+ ret);
+ goto err_enable;
+ }
+ if (wm2200->ldo_ena) {
+ gpiod_set_consumer_name(wm2200->ldo_ena, "WM2200 LDOENA");
msleep(2);
}
- if (wm2200->pdata.reset) {
- ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset,
- GPIOF_OUT_INIT_HIGH,
- "WM2200 /RESET");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
- wm2200->pdata.reset, ret);
- goto err_ldo;
- }
+ wm2200->reset = devm_gpiod_get_optional(&i2c->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(wm2200->reset)) {
+ ret = PTR_ERR(wm2200->reset);
+ dev_err(&i2c->dev, "Failed to request RESET GPIO %d\n",
+ ret);
+ goto err_ldo;
}
+ gpiod_set_consumer_name(wm2200->reset, "WM2200 /RESET");
ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, &reg);
if (ret < 0) {
@@ -2403,11 +2406,9 @@ err_pm_runtime:
if (i2c->irq)
free_irq(i2c->irq, wm2200);
err_reset:
- if (wm2200->pdata.reset)
- gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+ gpiod_set_value_cansleep(wm2200->reset, 1);
err_ldo:
- if (wm2200->pdata.ldo_ena)
- gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
wm2200->core_supplies);
@@ -2421,23 +2422,20 @@ static void wm2200_i2c_remove(struct i2c_client *i2c)
pm_runtime_disable(&i2c->dev);
if (i2c->irq)
free_irq(i2c->irq, wm2200);
- if (wm2200->pdata.reset)
- gpio_set_value_cansleep(wm2200->pdata.reset, 0);
- if (wm2200->pdata.ldo_ena)
- gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+ /* Assert RESET, disable LDO */
+ gpiod_set_value_cansleep(wm2200->reset, 1);
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
wm2200->core_supplies);
}
-#ifdef CONFIG_PM
static int wm2200_runtime_suspend(struct device *dev)
{
struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
regcache_cache_only(wm2200->regmap, true);
regcache_mark_dirty(wm2200->regmap);
- if (wm2200->pdata.ldo_ena)
- gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
wm2200->core_supplies);
@@ -2457,8 +2455,8 @@ static int wm2200_runtime_resume(struct device *dev)
return ret;
}
- if (wm2200->pdata.ldo_ena) {
- gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1);
+ if (wm2200->ldo_ena) {
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 1);
msleep(2);
}
@@ -2467,15 +2465,13 @@ 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[] = {
- { "wm2200", 0 },
+ { "wm2200" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
@@ -2483,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 a86eacb2a9bb..96fd098a9d36 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -15,7 +15,7 @@
#include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/gpio/driver.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -55,6 +55,9 @@ struct wm5100_priv {
struct snd_soc_component *component;
struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
+ struct gpio_desc *reset;
+ struct gpio_desc *ldo_ena;
+ struct gpio_desc *hp_pol;
int rev;
@@ -205,9 +208,9 @@ static void wm5100_free_sr(struct snd_soc_component *component, int rate)
static int wm5100_reset(struct wm5100_priv *wm5100)
{
- if (wm5100->pdata.reset) {
- gpio_set_value_cansleep(wm5100->pdata.reset, 0);
- gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+ if (wm5100->reset) {
+ gpiod_set_value_cansleep(wm5100->reset, 1);
+ gpiod_set_value_cansleep(wm5100->reset, 0);
return 0;
} else {
@@ -1300,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;
@@ -1974,7 +1977,7 @@ static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)
if (WARN_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes)))
return;
- gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
+ gpiod_set_value_cansleep(wm5100->hp_pol, mode->hp_pol);
regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1,
WM5100_ACCDET_BIAS_SRC_MASK |
WM5100_ACCDET_SRC,
@@ -2098,7 +2101,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)
int wm5100_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
{
struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
if (jack) {
wm5100->jack = jack;
@@ -2233,12 +2236,14 @@ static irqreturn_t wm5100_edge_irq(int irq, void *data)
}
#ifdef CONFIG_GPIOLIB
-static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm5100_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
- regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
- WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
+ return regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+ WM5100_GP1_LVL,
+ !!value << WM5100_GP1_LVL_SHIFT);
}
static int wm5100_gpio_direction_out(struct gpio_chip *chip,
@@ -2299,11 +2304,7 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
wm5100->gpio_chip = wm5100_template_chip;
wm5100->gpio_chip.ngpio = 6;
wm5100->gpio_chip.parent = &i2c->dev;
-
- if (wm5100->pdata.gpio_base)
- wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
- else
- wm5100->gpio_chip.base = -1;
+ wm5100->gpio_chip.base = -1;
ret = gpiochip_add_data(&wm5100->gpio_chip, wm5100);
if (ret != 0)
@@ -2328,7 +2329,7 @@ static void wm5100_free_gpio(struct i2c_client *i2c)
static int wm5100_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct i2c_client *i2c = to_i2c_client(component->dev);
struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
int ret, i;
@@ -2349,35 +2350,20 @@ static int wm5100_probe(struct snd_soc_component *component)
snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq,
ARRAY_SIZE(wm5100_dapm_widgets_noirq));
- if (wm5100->pdata.hp_pol) {
- ret = gpio_request_one(wm5100->pdata.hp_pol,
- GPIOF_OUT_INIT_HIGH, "WM5100 HP_POL");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request HP_POL %d: %d\n",
- wm5100->pdata.hp_pol, ret);
- goto err_gpio;
- }
+ wm5100->hp_pol = devm_gpiod_get_optional(&i2c->dev, "hp-pol",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(wm5100->hp_pol)) {
+ ret = PTR_ERR(wm5100->hp_pol);
+ dev_err(&i2c->dev, "Failed to request HP_POL GPIO: %d\n",
+ ret);
+ return ret;
}
return 0;
-
-err_gpio:
-
- return ret;
-}
-
-static void wm5100_remove(struct snd_soc_component *component)
-{
- struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
-
- if (wm5100->pdata.hp_pol) {
- gpio_free(wm5100->pdata.hp_pol);
- }
}
static const struct snd_soc_component_driver soc_component_dev_wm5100 = {
.probe = wm5100_probe,
- .remove = wm5100_remove,
.set_sysclk = wm5100_set_sysclk,
.set_pll = wm5100_set_fll,
.seq_notifier = wm5100_seq_notifier,
@@ -2400,7 +2386,7 @@ static const struct regmap_config wm5100_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults),
.volatile_reg = wm5100_volatile_register,
.readable_reg = wm5100_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const unsigned int wm5100_mic_ctrl_reg[] = {
@@ -2460,26 +2446,26 @@ static int wm5100_i2c_probe(struct i2c_client *i2c)
goto err;
}
- if (wm5100->pdata.ldo_ena) {
- ret = gpio_request_one(wm5100->pdata.ldo_ena,
- GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
- wm5100->pdata.ldo_ena, ret);
- goto err_enable;
- }
+ wm5100->ldo_ena = devm_gpiod_get_optional(&i2c->dev, "wlf,ldo1ena",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(wm5100->ldo_ena)) {
+ ret = PTR_ERR(wm5100->ldo_ena);
+ dev_err(&i2c->dev, "Failed to request LDOENA GPIO: %d\n", ret);
+ goto err_enable;
+ }
+ if (wm5100->ldo_ena) {
+ gpiod_set_consumer_name(wm5100->ldo_ena, "WM5100 LDOENA");
msleep(2);
}
- if (wm5100->pdata.reset) {
- ret = gpio_request_one(wm5100->pdata.reset,
- GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
- wm5100->pdata.reset, ret);
- goto err_ldo;
- }
+ wm5100->reset = devm_gpiod_get_optional(&i2c->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(wm5100->reset)) {
+ ret = PTR_ERR(wm5100->reset);
+ dev_err(&i2c->dev, "Failed to request /RESET GPIO: %d\n", ret);
+ goto err_ldo;
}
+ gpiod_set_consumer_name(wm5100->reset, "WM5100 /RESET");
ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, &reg);
if (ret < 0) {
@@ -2619,15 +2605,9 @@ err_reset:
if (i2c->irq)
free_irq(i2c->irq, wm5100);
wm5100_free_gpio(i2c);
- if (wm5100->pdata.reset) {
- gpio_set_value_cansleep(wm5100->pdata.reset, 0);
- gpio_free(wm5100->pdata.reset);
- }
+ gpiod_set_value_cansleep(wm5100->reset, 1);
err_ldo:
- if (wm5100->pdata.ldo_ena) {
- gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
- gpio_free(wm5100->pdata.ldo_ena);
- }
+ gpiod_set_value_cansleep(wm5100->ldo_ena, 0);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
@@ -2643,25 +2623,17 @@ static void wm5100_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, wm5100);
wm5100_free_gpio(i2c);
- if (wm5100->pdata.reset) {
- gpio_set_value_cansleep(wm5100->pdata.reset, 0);
- gpio_free(wm5100->pdata.reset);
- }
- if (wm5100->pdata.ldo_ena) {
- gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
- gpio_free(wm5100->pdata.ldo_ena);
- }
+ gpiod_set_value_cansleep(wm5100->reset, 1);
+ 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);
regcache_cache_only(wm5100->regmap, true);
regcache_mark_dirty(wm5100->regmap);
- if (wm5100->pdata.ldo_ena)
- gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+ gpiod_set_value_cansleep(wm5100->ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
@@ -2681,8 +2653,8 @@ static int wm5100_runtime_resume(struct device *dev)
return ret;
}
- if (wm5100->pdata.ldo_ena) {
- gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1);
+ if (wm5100->ldo_ena) {
+ gpiod_set_value_cansleep(wm5100->ldo_ena, 1);
msleep(2);
}
@@ -2691,15 +2663,13 @@ 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[] = {
- { "wm5100", 0 },
+ { "wm5100" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
@@ -2707,7 +2677,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/wm5102.c b/sound/soc/codecs/wm5102.c
index 3bdbdf3770b5..b4d4137c05b4 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -25,7 +25,7 @@
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/registers.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "arizona.h"
#include "wm5102.h"
@@ -664,7 +664,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
mutex_lock(&arizona->dac_comp_lock);
@@ -678,7 +678,7 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
int ret = 0;
@@ -696,7 +696,7 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
mutex_lock(&arizona->dac_comp_lock);
@@ -709,7 +709,7 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
int ret = 0;
@@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id,
#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static const struct snd_soc_dai_ops wm5102_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver wm5102_dai[] = {
{
.name = "wm5102-aif1",
@@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &wm5102_dai_ops,
},
{
.name = "wm5102-dsp-trace",
@@ -1945,7 +1949,7 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
static int wm5102_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int ret;
@@ -1967,7 +1971,7 @@ static int wm5102_component_probe(struct snd_soc_component *component)
arizona_init_gpio(component);
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
priv->core.arizona->dapm = dapm;
@@ -2170,7 +2174,7 @@ static struct platform_driver wm5102_codec_driver = {
.name = "wm5102-codec",
},
.probe = wm5102_probe,
- .remove_new = wm5102_remove,
+ .remove = wm5102_remove,
};
module_platform_driver(wm5102_codec_driver);
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index ad670300de8d..7a311c869bd3 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:
@@ -402,8 +402,8 @@ static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -467,8 +467,8 @@ err:
static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
/*
@@ -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);
@@ -487,8 +487,8 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
/*
@@ -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);
@@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id,
#define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static const struct snd_soc_dai_ops wm5110_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver wm5110_dai[] = {
{
.name = "wm5110-aif1",
@@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &wm5110_dai_ops,
},
{
.name = "wm5110-dsp-voicectrl",
@@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &wm5110_dai_ops,
},
{
.name = "wm5110-dsp-trace",
@@ -2249,14 +2253,14 @@ static int wm5110_open(struct snd_soc_component *component,
struct arizona *arizona = priv->core.arizona;
int n_adsp;
- if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "wm5110-dsp-voicectrl") == 0) {
+ if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "wm5110-dsp-voicectrl") == 0) {
n_adsp = 2;
- } else if (strcmp(asoc_rtd_to_codec(rtd, 0)->name, "wm5110-dsp-trace") == 0) {
+ } else if (strcmp(snd_soc_rtd_to_codec(rtd, 0)->name, "wm5110-dsp-trace") == 0) {
n_adsp = 0;
} else {
dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
return -EINVAL;
}
@@ -2293,7 +2297,7 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
static int wm5110_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int i, ret;
@@ -2320,7 +2324,7 @@ static int wm5110_component_probe(struct snd_soc_component *component)
if (ret)
goto err_adsp2_codec_probe;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
return 0;
@@ -2530,7 +2534,7 @@ static struct platform_driver wm5110_codec_driver = {
.name = "wm5110-codec",
},
.probe = wm5110_probe,
- .remove_new = wm5110_remove,
+ .remove = wm5110_remove,
};
module_platform_driver(wm5110_codec_driver);
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 66bd281095e1..ad68ff1790e0 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -297,7 +297,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
struct wm8350_output *out = NULL;
struct soc_mixer_control *mc =
@@ -340,7 +340,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
struct wm8350_output *out1 = &wm8350_priv->out1;
struct wm8350_output *out2 = &wm8350_priv->out2;
@@ -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;
@@ -1075,6 +1075,7 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
static int wm8350_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
struct wm8350 *wm8350 = priv->wm8350;
struct wm8350_audio_platform_data *platform =
@@ -1099,7 +1100,7 @@ static int wm8350_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
priv->supplies);
if (ret != 0)
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 19ce839f6ef7..0eecc8657a38 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -82,7 +82,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int reg = mc->reg;
@@ -318,6 +318,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
u32 reg_shift = mc->shift;
int ret = 0;
u16 reg;
@@ -326,7 +327,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
reg = snd_soc_component_read(component, WM8400_OUTPUT_MIXER1);
if (reg & WM8400_LDLO) {
- printk(KERN_WARNING
+ dev_warn(wm8400->wm8400->dev,
"Cannot set as Output Mixer 1 LDLO Set\n");
ret = -1;
}
@@ -334,7 +335,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
reg = snd_soc_component_read(component, WM8400_OUTPUT_MIXER2);
if (reg & WM8400_RDRO) {
- printk(KERN_WARNING
+ dev_warn(wm8400->wm8400->dev,
"Cannot set as Output Mixer 2 RDRO Set\n");
ret = -1;
}
@@ -342,7 +343,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
reg = snd_soc_component_read(component, WM8400_SPEAKER_MIXER);
if (reg & WM8400_LDSPK) {
- printk(KERN_WARNING
+ dev_warn(wm8400->wm8400->dev,
"Cannot set as Speaker Mixer LDSPK Set\n");
ret = -1;
}
@@ -350,7 +351,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
reg = snd_soc_component_read(component, WM8400_SPEAKER_MIXER);
if (reg & WM8400_RDSPK) {
- printk(KERN_WARNING
+ dev_warn(wm8400->wm8400->dev,
"Cannot set as Speaker Mixer RDSPK Set\n");
ret = -1;
}
@@ -986,10 +987,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:
@@ -1110,6 +1111,7 @@ static int wm8400_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 val;
int ret;
@@ -1125,7 +1127,7 @@ static int wm8400_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(power),
&power[0]);
if (ret != 0) {
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index c0ed76d5b65f..bebee333d3fd 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -7,6 +7,7 @@
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -16,7 +17,6 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -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;
@@ -504,6 +504,7 @@ static int wm8510_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8510_priv *wm8510 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 power1 = snd_soc_component_read(component, WM8510_POWER1) & ~0x3;
switch (level) {
@@ -516,7 +517,7 @@ static int wm8510_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_STANDBY:
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_sync(wm8510->regmap);
/* Initial cap charge at VMID 5k */
@@ -607,7 +608,7 @@ static const struct regmap_config wm8510_regmap = {
.reg_defaults = wm8510_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8510_volatile,
};
@@ -668,7 +669,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8510_i2c_id[] = {
- { "wm8510", 0 },
+ { "wm8510" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 55c72c5ac845..f003f19766e2 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -16,7 +17,6 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -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;
@@ -317,6 +317,7 @@ static int wm8523_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -330,7 +331,7 @@ static int wm8523_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
wm8523->supplies);
if (ret != 0) {
@@ -437,7 +438,7 @@ static const struct regmap_config wm8523_regmap = {
.reg_defaults = wm8523_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8523_volatile_register,
};
@@ -517,7 +518,7 @@ err_enable:
}
static const struct i2c_device_id wm8523_i2c_id[] = {
- { "wm8523", 0 },
+ { "wm8523" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index b56dcac60244..6b1a7450b0ac 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -8,20 +8,20 @@
* Based on WM8523 ALSA SoC Audio driver written by Mark Brown
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
-#define WM8524_NUM_RATES 7
+#define WM8524_NUM_RATES 12
/* codec private data */
struct wm8524_priv {
@@ -46,7 +46,7 @@ static const struct snd_soc_dapm_route wm8524_dapm_routes[] = {
static const struct {
int value;
int ratio;
-} lrclk_ratios[WM8524_NUM_RATES] = {
+} lrclk_ratios[] = {
{ 1, 128 },
{ 2, 192 },
{ 3, 256 },
@@ -63,17 +63,12 @@ static int wm8524_startup(struct snd_pcm_substream *substream,
struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
/* The set of sample rates that can be supported depends on the
- * MCLK supplied to the CODEC - enforce this.
+ * MCLK supplied to the CODEC.
*/
- if (!wm8524->sysclk) {
- dev_err(component->dev,
- "No MCLK configured, call set_sysclk() on init\n");
- return -EINVAL;
- }
-
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &wm8524->rate_constraint);
+ if (wm8524->sysclk)
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &wm8524->rate_constraint);
gpiod_set_value_cansleep(wm8524->mute, 1);
@@ -97,9 +92,11 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
unsigned int val;
int i, j = 0;
+ wm8524->rate_constraint.count = 0;
wm8524->sysclk = freq;
+ if (!wm8524->sysclk)
+ return 0;
- wm8524->rate_constraint.count = 0;
for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
val = freq / lrclk_ratios[i].ratio;
/* Check that it's a standard rate since core can't
@@ -108,9 +105,13 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
*/
switch (val) {
case 8000:
+ case 11025:
+ case 16000:
+ case 22050:
case 32000:
case 44100:
case 48000:
+ case 64000:
case 88200:
case 96000:
case 176400:
@@ -139,7 +140,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;
}
@@ -157,6 +158,33 @@ static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
+static int wm8524_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
+ int i;
+
+ /* If sysclk is not configured, no need to check the rate */
+ if (!wm8524->sysclk)
+ return 0;
+
+ /* Find a supported LRCLK rate */
+ for (i = 0; i < wm8524->rate_constraint.count; i++) {
+ if (wm8524->rate_constraint.list[i] == params_rate(params))
+ break;
+ }
+
+ if (i == wm8524->rate_constraint.count) {
+ dev_err(component->dev, "LRCLK %d unsupported with MCLK %d\n",
+ params_rate(params), wm8524->sysclk);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
#define WM8524_RATES SNDRV_PCM_RATE_8000_192000
#define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
@@ -169,6 +197,7 @@ static const struct snd_soc_dai_ops wm8524_dai_ops = {
.set_sysclk = wm8524_set_dai_sysclk,
.set_fmt = wm8524_set_fmt,
.mute_stream = wm8524_mute_stream,
+ .hw_params = wm8524_hw_params,
};
static struct snd_soc_dai_driver wm8524_dai = {
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 34ae7fe05398..2be265bb0751 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -15,6 +15,7 @@
* the secondary audio interfaces are not.
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -25,7 +26,6 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -258,7 +258,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
@@ -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:
@@ -820,13 +820,15 @@ static int wm8580_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
static int wm8580_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Power up and get individual control of the DACs */
snd_soc_component_update_bits(component, WM8580_PWRDN1,
WM8580_PWRDN1_PWDN |
@@ -907,7 +909,7 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
static int wm8580_probe(struct snd_soc_component *component)
{
struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret = 0;
switch (wm8580->drvdata->num_dacs) {
@@ -975,7 +977,7 @@ static const struct regmap_config wm8580_regmap = {
.reg_defaults = wm8580_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8580_volatile,
};
@@ -988,16 +990,8 @@ static const struct wm8580_driver_data wm8581_data = {
.num_dacs = 4,
};
-static const struct of_device_id wm8580_of_match[] = {
- { .compatible = "wlf,wm8580", .data = &wm8580_data },
- { .compatible = "wlf,wm8581", .data = &wm8581_data },
- { },
-};
-MODULE_DEVICE_TABLE(of, wm8580_of_match);
-
static int wm8580_i2c_probe(struct i2c_client *i2c)
{
- const struct of_device_id *of_id;
struct wm8580_priv *wm8580;
int ret, i;
@@ -1022,14 +1016,9 @@ static int wm8580_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, wm8580);
- of_id = of_match_device(wm8580_of_match, &i2c->dev);
- if (of_id)
- wm8580->drvdata = of_id->data;
-
- if (!wm8580->drvdata) {
- dev_err(&i2c->dev, "failed to find driver data\n");
- return -EINVAL;
- }
+ wm8580->drvdata = i2c_get_match_data(i2c);
+ if (!wm8580->drvdata)
+ return dev_err_probe(&i2c->dev, -EINVAL, "failed to find driver data\n");
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
@@ -1037,6 +1026,13 @@ static int wm8580_i2c_probe(struct i2c_client *i2c)
return ret;
}
+static const struct of_device_id wm8580_of_match[] = {
+ { .compatible = "wlf,wm8580", .data = &wm8580_data },
+ { .compatible = "wlf,wm8581", .data = &wm8581_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8580_of_match);
+
static const struct i2c_device_id wm8580_i2c_id[] = {
{ "wm8580", (kernel_ulong_t)&wm8580_data },
{ "wm8581", (kernel_ulong_t)&wm8581_data },
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 903a0147d584..2bab9d189519 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -9,6 +9,7 @@
* Based on wm8731.c by Richard Purdie
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -18,7 +19,6 @@
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -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;
@@ -298,6 +298,7 @@ static int wm8711_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8711_priv *wm8711 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 reg = snd_soc_component_read(component, WM8711_PWR) & 0xff7f;
switch (level) {
@@ -307,7 +308,7 @@ static int wm8711_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
regcache_sync(wm8711->regmap);
snd_soc_component_write(component, WM8711_PWR, reg | 0x0040);
@@ -393,7 +394,7 @@ static const struct regmap_config wm8711_regmap = {
.reg_defaults = wm8711_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8711_volatile,
};
@@ -454,7 +455,7 @@ static int wm8711_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id wm8711_i2c_id[] = {
- { "wm8711", 0 },
+ { "wm8711" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 5ea6d8fd10f6..4c1a80561f06 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -17,7 +18,6 @@
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -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;
@@ -161,13 +161,14 @@ static int wm8728_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8728_priv *wm8728 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 reg;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Power everything up... */
reg = snd_soc_component_read(component, WM8728_DACCTL);
snd_soc_component_write(component, WM8728_DACCTL, reg & ~0x4);
@@ -236,7 +237,7 @@ static const struct regmap_config wm8728_regmap = {
.reg_defaults = wm8728_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
#if defined(CONFIG_SPI_MASTER)
@@ -295,7 +296,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8728_i2c_id[] = {
- { "wm8728", 0 },
+ { "wm8728" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
diff --git a/sound/soc/codecs/wm8731-i2c.c b/sound/soc/codecs/wm8731-i2c.c
index c39e637d813d..1254e583af51 100644
--- a/sound/soc/codecs/wm8731-i2c.c
+++ b/sound/soc/codecs/wm8731-i2c.c
@@ -11,8 +11,8 @@
*/
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include "wm8731.h"
@@ -47,7 +47,7 @@ static int wm8731_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8731_i2c_id[] = {
- { "wm8731", 0 },
+ { "wm8731" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
diff --git a/sound/soc/codecs/wm8731-spi.c b/sound/soc/codecs/wm8731-spi.c
index 542ed097d89a..c02086afa7fb 100644
--- a/sound/soc/codecs/wm8731-spi.c
+++ b/sound/soc/codecs/wm8731-spi.c
@@ -11,8 +11,8 @@
*/
#include <linux/spi/spi.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include "wm8731.h"
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index d5ab3ba126a6..a03bbde5d852 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -96,7 +96,7 @@ static int wm8731_set_deemph(struct snd_soc_component *component)
static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8731->deemph;
@@ -107,7 +107,7 @@ static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
int ret = 0;
@@ -362,7 +362,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = codec_dai->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
switch (clk_id) {
@@ -465,6 +465,7 @@ static int wm8731_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
u16 reg;
@@ -479,7 +480,7 @@ static int wm8731_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
wm8731->supplies);
if (ret != 0)
@@ -642,7 +643,7 @@ const struct regmap_config wm8731_regmap = {
.max_register = WM8731_RESET,
.volatile_reg = wm8731_volatile,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8731_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults),
};
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 9f4e372e90ea..fee8a37ed1df 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -17,7 +18,6 @@
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -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;
@@ -452,6 +452,7 @@ static int wm8737_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -465,7 +466,7 @@ static int wm8737_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
wm8737->supplies);
if (ret != 0) {
@@ -537,6 +538,7 @@ static struct snd_soc_dai_driver wm8737_dai = {
static int wm8737_probe(struct snd_soc_component *component)
{
struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
@@ -557,7 +559,7 @@ static int wm8737_probe(struct snd_soc_component *component)
snd_soc_component_update_bits(component, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
WM8737_RVU);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
@@ -599,7 +601,7 @@ static const struct regmap_config wm8737_regmap = {
.reg_defaults = wm8737_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8737_volatile,
};
@@ -639,7 +641,7 @@ static int wm8737_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8737_i2c_id[] = {
- { "wm8737", 0 },
+ { "wm8737" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id);
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 787156b980a1..4dfbb33edb09 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -14,10 +14,10 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -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;
@@ -543,7 +543,7 @@ static const struct regmap_config wm8741_regmap = {
.reg_defaults = wm8741_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
@@ -606,7 +606,7 @@ static int wm8741_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8741_i2c_id[] = {
- { "wm8741", 0 },
+ { "wm8741" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 20dc9ff9fea9..0e1d3ebb15c4 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -15,10 +15,10 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -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;
@@ -621,6 +621,7 @@ static int wm8750_mute(struct snd_soc_dai *dai, int mute, int direction)
static int wm8750_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 pwr_reg = snd_soc_component_read(component, WM8750_PWR1) & 0xfe3e;
switch (level) {
@@ -631,7 +632,7 @@ static int wm8750_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_cache_sync(component);
/* Set VMID to 5k */
@@ -735,7 +736,7 @@ static const struct regmap_config wm8750_regmap = {
.reg_defaults = wm8750_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
#if defined(CONFIG_SPI_MASTER)
@@ -802,8 +803,8 @@ static int wm8750_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8750_i2c_id[] = {
- { "wm8750", 0 },
- { "wm8987", 0 },
+ { "wm8750" },
+ { "wm8987" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 5e8a8eb41b2b..a532a95e8048 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -26,13 +26,13 @@
* an alsa kcontrol. This allows the PCM to remain open.
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -224,7 +224,7 @@ SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8753->dai_func;
@@ -234,7 +234,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
u16 ioctl;
@@ -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:
@@ -1331,6 +1331,7 @@ static int wm8753_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 pwr_reg = snd_soc_component_read(component, WM8753_PWR1) & 0xfe3e;
switch (level) {
@@ -1343,7 +1344,7 @@ static int wm8753_set_bias_level(struct snd_soc_component *component,
flush_delayed_work(&wm8753->charge_work);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* set vmid to 5k for quick power up */
snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x01c1);
schedule_delayed_work(&wm8753->charge_work,
@@ -1507,7 +1508,7 @@ static const struct regmap_config wm8753_regmap = {
.max_register = WM8753_ADCTL2,
.volatile_reg = wm8753_volatile,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8753_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults),
};
@@ -1580,7 +1581,7 @@ static int wm8753_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8753_i2c_id[] = {
- { "wm8753", 0 },
+ { "wm8753" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index e03fee8869c3..d382b476c89c 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -7,11 +7,11 @@
* Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/of_device.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
@@ -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:
@@ -497,6 +497,7 @@ static int wm8770_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int ret;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8770_priv *wm8770;
wm8770 = snd_soc_component_get_drvdata(component);
@@ -507,7 +508,7 @@ static int wm8770_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
wm8770->supplies);
if (ret) {
@@ -632,7 +633,7 @@ static const struct regmap_config wm8770_regmap = {
.reg_defaults = wm8770_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8770_volatile_reg,
};
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 212224a68006..c3f340657f0c 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -9,13 +9,13 @@
* TODO: Input ALC/limiter support
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
@@ -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:
@@ -334,6 +334,7 @@ static int wm8776_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -341,7 +342,7 @@ static int wm8776_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_sync(wm8776->regmap);
/* Disable the global powerdown; DAPM does the rest */
@@ -451,7 +452,7 @@ static const struct regmap_config wm8776_regmap = {
.reg_defaults = wm8776_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8776_volatile,
};
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index 95ff4339d103..3a2acdfa9b85 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -23,6 +23,27 @@
#include <sound/initval.h>
#include <sound/soc.h>
+/* regulator power supply names */
+static const char *supply_names[] = {
+ "Vdda", /* analog supply, 2.7V - 3.6V */
+ "Vdd", /* digital supply, 2.7V - 5.5V */
+};
+
+struct wm8782_priv {
+ struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+ int max_rate;
+};
+
+static int wm8782_dai_startup(struct snd_pcm_substream *sub, struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = sub->runtime;
+ struct wm8782_priv *priv =
+ snd_soc_component_get_drvdata(dai->component);
+
+ return snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
+ 8000, priv->max_rate);
+}
+
static const struct snd_soc_dapm_widget wm8782_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AINL"),
SND_SOC_DAPM_INPUT("AINR"),
@@ -33,28 +54,22 @@ static const struct snd_soc_dapm_route wm8782_dapm_routes[] = {
{ "Capture", NULL, "AINR" },
};
+static const struct snd_soc_dai_ops wm8782_dai_ops = {
+ .startup = &wm8782_dai_startup,
+};
+
static struct snd_soc_dai_driver wm8782_dai = {
.name = "wm8782",
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
- /* For configurations with FSAMPEN=0 */
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE,
},
-};
-
-/* regulator power supply names */
-static const char *supply_names[] = {
- "Vdda", /* analog supply, 2.7V - 3.6V */
- "Vdd", /* digital supply, 2.7V - 5.5V */
-};
-
-struct wm8782_priv {
- struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+ .ops = &wm8782_dai_ops,
};
static int wm8782_soc_probe(struct snd_soc_component *component)
@@ -104,8 +119,9 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
static int wm8782_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct wm8782_priv *priv;
- int ret, i;
+ int ret, i, fsampen;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -121,6 +137,27 @@ static int wm8782_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ // Assume lowest value by default to avoid inadvertent overclocking
+ fsampen = 0;
+
+ if (np)
+ of_property_read_u32(np, "wlf,fsampen", &fsampen);
+
+ switch (fsampen) {
+ case 0:
+ priv->max_rate = 48000;
+ break;
+ case 1:
+ priv->max_rate = 96000;
+ break;
+ case 2:
+ priv->max_rate = 192000;
+ break;
+ default:
+ dev_err(dev, "Invalid wlf,fsampen value");
+ return -EINVAL;
+ }
+
return devm_snd_soc_register_component(&pdev->dev,
&soc_component_dev_wm8782, &wm8782_dai, 1);
}
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
index 7062a8b2f8b5..3380d7301b17 100644
--- a/sound/soc/codecs/wm8804-i2c.c
+++ b/sound/soc/codecs/wm8804-i2c.c
@@ -31,7 +31,7 @@ static void wm8804_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8804_i2c_id[] = {
- { "wm8804", 0 },
+ { "wm8804" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
@@ -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 0b234bae480e..94aa3c8de0ab 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -14,7 +14,6 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -158,8 +157,8 @@ static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
static int txsrc_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_component_get_dapm(component);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l;
unsigned int mask = 1 << e->shift_l;
@@ -244,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:
@@ -555,7 +554,7 @@ const struct regmap_config wm8804_regmap_config = {
.max_register = WM8804_MAX_REGISTER,
.volatile_reg = wm8804_volatile,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8804_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
};
@@ -681,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);
@@ -714,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 320ccd92f318..fea629541acd 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;
@@ -1023,6 +1023,7 @@ static struct snd_soc_dai_driver wm8900_dai = {
static int wm8900_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 reg;
switch (level) {
@@ -1041,7 +1042,7 @@ static int wm8900_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_STANDBY:
/* Charge capacitors if initial power up */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* STARTUP_BIAS_ENA on */
snd_soc_component_write(component, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA);
@@ -1115,6 +1116,7 @@ static int wm8900_set_bias_level(struct snd_soc_component *component,
static int wm8900_suspend(struct snd_soc_component *component)
{
struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int fll_out = wm8900->fll_out;
int fll_in = wm8900->fll_in;
int ret;
@@ -1129,7 +1131,7 @@ static int wm8900_suspend(struct snd_soc_component *component)
wm8900->fll_out = fll_out;
wm8900->fll_in = fll_in;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1137,6 +1139,7 @@ static int wm8900_suspend(struct snd_soc_component *component)
static int wm8900_resume(struct snd_soc_component *component)
{
struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
wm8900_reset(component);
@@ -1147,7 +1150,7 @@ static int wm8900_resume(struct snd_soc_component *component)
return ret;
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Restart the FLL? */
if (wm8900->fll_out) {
@@ -1169,6 +1172,7 @@ static int wm8900_resume(struct snd_soc_component *component)
static int wm8900_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int reg;
reg = snd_soc_component_read(component, WM8900_REG_ID);
@@ -1180,7 +1184,7 @@ static int wm8900_probe(struct snd_soc_component *component)
wm8900_reset(component);
/* Turn the chip on */
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Latch the volume update bits */
snd_soc_component_update_bits(component, WM8900_REG_LINVOL, 0x100, 0x100);
@@ -1223,7 +1227,7 @@ static const struct regmap_config wm8900_regmap = {
.reg_defaults = wm8900_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8900_volatile_register,
};
@@ -1286,7 +1290,7 @@ static void wm8900_i2c_remove(struct i2c_client *client)
{}
static const struct i2c_device_id wm8900_i2c_id[] = {
- { "wm8900", 0 },
+ { "wm8900" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 901b65ef8de5..f73f6ad06b38 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -369,7 +369,7 @@ static void wm8903_seq_notifier(struct snd_soc_component *component,
static int wm8903_class_w_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_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
u16 reg;
int ret;
@@ -444,7 +444,7 @@ static int wm8903_set_deemph(struct snd_soc_component *component)
static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8903->deemph;
@@ -455,7 +455,7 @@ static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
int ret = 0;
@@ -1099,6 +1099,8 @@ static const struct snd_soc_dapm_route wm8903_intercon[] = {
static int wm8903_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
break;
@@ -1110,7 +1112,7 @@ static int wm8903_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
WM8903_POBCTRL | WM8903_ISEL_MASK |
WM8903_STARTUP_BIAS_ENA |
@@ -1229,15 +1231,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:
@@ -1825,13 +1827,15 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
return 0;
}
-static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm8903_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
- regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
- WM8903_GP1_LVL_MASK,
- !!value << WM8903_GP1_LVL_SHIFT);
+ return regmap_update_bits(wm8903->regmap,
+ WM8903_GPIO_CONTROL_1 + offset,
+ WM8903_GP1_LVL_MASK,
+ !!value << WM8903_GP1_LVL_SHIFT);
}
static const struct gpio_chip wm8903_template_chip = {
@@ -1902,7 +1906,7 @@ static const struct regmap_config wm8903_regmap = {
.volatile_reg = wm8903_volatile_register,
.readable_reg = wm8903_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8903_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults),
};
@@ -2199,7 +2203,7 @@ static const struct of_device_id wm8903_of_match[] = {
MODULE_DEVICE_TABLE(of, wm8903_of_match);
static const struct i2c_device_id wm8903_i2c_id[] = {
- { "wm8903", 0 },
+ { "wm8903" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 068e610b1b4c..4c73a340f25f 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -388,7 +388,7 @@ static void wm8904_set_drc(struct snd_soc_component *component)
static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.enumerated.item[0];
@@ -406,7 +406,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
@@ -459,7 +459,7 @@ static void wm8904_set_retune_mobile(struct snd_soc_component *component)
static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
struct wm8904_pdata *pdata = wm8904->pdata;
int value = ucontrol->value.enumerated.item[0];
@@ -477,7 +477,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
@@ -517,7 +517,7 @@ static int wm8904_set_deemph(struct snd_soc_component *component)
static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8904->deemph;
@@ -527,7 +527,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
@@ -555,7 +555,7 @@ static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int val;
int ret;
@@ -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" },
@@ -1184,7 +1246,7 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = {
static int wm8904_add_widgets(struct snd_soc_component *component)
{
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets,
ARRAY_SIZE(wm8904_core_dapm_widgets));
@@ -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;
@@ -1872,6 +1934,7 @@ static int wm8904_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1890,7 +1953,7 @@ static int wm8904_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
wm8904->supplies);
if (ret != 0) {
@@ -2050,18 +2113,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_to_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_to_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 +2232,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;
}
@@ -2148,7 +2264,7 @@ static const struct regmap_config wm8904_regmap = {
.volatile_reg = wm8904_volatile_register,
.readable_reg = wm8904_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8904_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults),
};
@@ -2168,6 +2284,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 +2490,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 = (enum wm8904_type)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 +2573,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,
@@ -2308,6 +2601,9 @@ static int wm8904_i2c_probe(struct i2c_client *i2c)
regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0,
WM8904_POBCTRL, 0);
+ /* Fill the cache for the ADC test register */
+ regmap_read(wm8904->regmap, WM8904_ADC_TEST_0, &val);
+
/* Can leave the device powered off until we need it */
regcache_cache_only(wm8904->regmap, true);
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 53c27986d216..2f55d0c572a4 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -220,7 +220,7 @@ static const struct snd_kcontrol_new wm8940_snd_controls[] = {
SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL,
0, 255, 0, wm8940_adc_tlv),
SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum),
- SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST,
+ SOC_SINGLE_TLV("Capture Boost Volume", WM8940_ADCBOOST,
8, 1, 0, wm8940_capture_boost_vol_tlv),
SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL,
0, 63, 0, wm8940_spk_vol_tlv),
@@ -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;
@@ -476,6 +476,7 @@ static int wm8940_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8940_priv *wm8940 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 val;
u16 pwr_reg = snd_soc_component_read(component, WM8940_POWER1) & 0x1F0;
int ret = 0;
@@ -498,7 +499,7 @@ static int wm8940_set_bias_level(struct snd_soc_component *component,
ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x1);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(wm8940->regmap);
if (ret < 0) {
dev_err(component->dev, "Failed to sync cache: %d\n", ret);
@@ -693,7 +694,12 @@ static int wm8940_update_clocks(struct snd_soc_dai *dai)
f = wm8940_get_mclkdiv(priv->mclk, fs256, &mclkdiv);
if (f != priv->mclk) {
/* The PLL performs best around 90MHz */
- fpll = wm8940_get_mclkdiv(22500000, fs256, &mclkdiv);
+ if (fs256 % 8000)
+ f = 22579200;
+ else
+ f = 24576000;
+
+ fpll = wm8940_get_mclkdiv(f, fs256, &mclkdiv);
}
wm8940_set_dai_pll(dai, 0, 0, priv->mclk, fpll);
@@ -756,6 +762,7 @@ static struct snd_soc_dai_driver wm8940_dai = {
static int wm8940_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8940_setup_data *pdata = component->dev->platform_data;
int ret;
u16 reg;
@@ -777,7 +784,7 @@ static int wm8940_probe(struct snd_soc_component *component)
return ret;
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
ret = snd_soc_component_write(component, WM8940_POWER1, 0x180);
if (ret < 0)
@@ -815,7 +822,7 @@ static const struct regmap_config wm8940_regmap = {
.max_register = WM8940_MONOMIX,
.reg_defaults = wm8940_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.readable_reg = wm8940_readable_register,
.volatile_reg = wm8940_volatile_register,
@@ -844,7 +851,7 @@ static int wm8940_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8940_i2c_id[] = {
- { "wm8940", 0 },
+ { "wm8940" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 78044f580a67..e1c61e026cbc 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -387,7 +387,7 @@ static int wm8955_set_deemph(struct snd_soc_component *component)
static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8955->deemph;
@@ -397,7 +397,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
@@ -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:
@@ -764,6 +764,7 @@ static int wm8955_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -783,7 +784,7 @@ static int wm8955_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
wm8955->supplies);
if (ret != 0) {
@@ -866,6 +867,7 @@ static struct snd_soc_dai_driver wm8955_dai = {
static int wm8955_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
struct wm8955_pdata *pdata = dev_get_platdata(component->dev);
int ret, i;
@@ -927,7 +929,7 @@ static int wm8955_probe(struct snd_soc_component *component)
WM8955_DMEN, WM8955_DMEN);
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
@@ -962,7 +964,7 @@ static const struct regmap_config wm8955_regmap = {
.volatile_reg = wm8955_volatile,
.writeable_reg = wm8955_writeable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8955_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults),
};
@@ -994,7 +996,7 @@ static int wm8955_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8955_i2c_id[] = {
- { "wm8955", 0 },
+ { "wm8955" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 7878c7a58ff1..8ff0882732e7 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -25,7 +25,7 @@
#include <linux/mfd/wm8994/pdata.h>
#include <linux/mfd/wm8994/gpio.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "wm8994.h"
@@ -453,7 +453,7 @@ static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.enumerated.item[0];
@@ -475,7 +475,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
@@ -497,7 +497,7 @@ static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int mbc = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
@@ -509,7 +509,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int mbc = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
@@ -543,7 +543,7 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.enumerated.item[0];
@@ -565,7 +565,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
@@ -576,7 +576,7 @@ static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.enumerated.item[0];
@@ -598,7 +598,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
@@ -620,7 +620,7 @@ static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int vss = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
@@ -632,7 +632,7 @@ static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int vss = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
@@ -681,7 +681,7 @@ static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int hpf = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (hpf < 3)
@@ -696,7 +696,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int hpf = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (hpf < 3) {
@@ -743,7 +743,7 @@ static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
int value = ucontrol->value.enumerated.item[0];
@@ -765,7 +765,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
@@ -787,7 +787,7 @@ static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int eq = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
@@ -799,7 +799,7 @@ static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int eq = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 366f5d769d6d..384e8e703446 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -120,6 +120,15 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
}
}
+#define WM8960_NUM_SUPPLIES 5
+static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD",
+ "AVDD",
+ "SPKVDD1",
+ "SPKVDD2",
+};
+
struct wm8960_priv {
struct clk *mclk;
struct regmap *regmap;
@@ -137,6 +146,7 @@ struct wm8960_priv {
bool is_stream_in_use[2];
struct wm8960_data pdata;
ktime_t dsch_start;
+ struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES];
};
#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0)
@@ -155,6 +165,7 @@ static const char *wm8960_adc_data_output_sel[] = {
"Left Data = Right ADC; Right Data = Left ADC",
};
static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
+static const char *wm8960_dacslope[] = {"Normal", "Sloping"};
static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
@@ -165,6 +176,7 @@ static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
+ SOC_ENUM_SINGLE(WM8960_DACCTL2, 1, 2, wm8960_dacslope),
};
static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
@@ -199,7 +211,7 @@ static int wm8960_set_deemph(struct snd_soc_component *component)
static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wm8960->deemph;
@@ -209,7 +221,7 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
@@ -307,6 +319,7 @@ SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
+SOC_ENUM("DAC Filter Characteristics", wm8960_enum[8]),
};
static const struct snd_kcontrol_new wm8960_lin_boost[] = {
@@ -475,7 +488,7 @@ static int wm8960_add_widgets(struct snd_soc_component *component)
{
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
struct wm8960_data *pdata = &wm8960->pdata;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct snd_soc_dapm_widget *w;
snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
@@ -527,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;
@@ -900,6 +913,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 pm2 = snd_soc_component_read(component, WM8960_POWER2);
int ret;
ktime_t tout;
@@ -909,7 +923,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_STANDBY:
if (!IS_ERR(wm8960->mclk)) {
ret = clk_prepare_enable(wm8960->mclk);
@@ -948,7 +962,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* ensure discharge is complete */
tout = WM8960_DSCH_TOUT - ktime_ms_delta(ktime_get(), wm8960->dsch_start);
if (tout > 0)
@@ -996,6 +1010,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 pm2 = snd_soc_component_read(component, WM8960_POWER2);
int reg, ret;
@@ -1004,7 +1019,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_STANDBY:
/* Enable anti pop mode */
snd_soc_component_update_bits(component, WM8960_APOP1,
@@ -1087,7 +1102,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- switch (snd_soc_component_get_bias_level(component)) {
+ switch (snd_soc_dapm_get_bias_level(dapm)) {
case SND_SOC_BIAS_PREPARE:
/* Disable HP discharge */
snd_soc_component_update_bits(component, WM8960_APOP2,
@@ -1387,7 +1402,7 @@ static const struct regmap_config wm8960_regmap = {
.reg_defaults = wm8960_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8960_volatile,
};
@@ -1414,7 +1429,9 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
{
struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
struct wm8960_priv *wm8960;
+ unsigned int i;
int ret;
+ u8 val;
wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv),
GFP_KERNEL);
@@ -1425,21 +1442,55 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(wm8960->mclk)) {
if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
+ } else {
+ ret = clk_get_rate(wm8960->mclk);
+ if (ret >= 0) {
+ wm8960->freq_in = ret;
+ } else {
+ dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n",
+ ret);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++)
+ wm8960->supplies[i].supply = wm8960_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8960->supplies),
+ wm8960->supplies);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies),
+ wm8960->supplies);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
}
wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
- if (IS_ERR(wm8960->regmap))
- return PTR_ERR(wm8960->regmap);
+ if (IS_ERR(wm8960->regmap)) {
+ ret = PTR_ERR(wm8960->regmap);
+ goto bulk_disable;
+ }
if (pdata)
memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data));
else if (i2c->dev.of_node)
wm8960_set_pdata_from_of(i2c, &wm8960->pdata);
+ ret = i2c_master_recv(i2c, &val, sizeof(val));
+ if (ret >= 0) {
+ dev_err(&i2c->dev, "Not wm8960, wm8960 reg can not read by i2c\n");
+ ret = -EINVAL;
+ goto bulk_disable;
+ }
+
ret = wm8960_reset(wm8960->regmap);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to issue reset\n");
- return ret;
+ goto bulk_disable;
}
if (wm8960->pdata.shared_lrclk) {
@@ -1448,7 +1499,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
if (ret != 0) {
dev_err(&i2c->dev, "Failed to enable LRCM: %d\n",
ret);
- return ret;
+ goto bulk_disable;
}
}
@@ -1482,15 +1533,25 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_wm8960, &wm8960_dai, 1);
+ if (ret)
+ goto bulk_disable;
+ return 0;
+
+bulk_disable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies);
return ret;
}
static void wm8960_i2c_remove(struct i2c_client *client)
-{}
+{
+ struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies);
+}
static const struct i2c_device_id wm8960_i2c_id[] = {
- { "wm8960", 0 },
+ { "wm8960" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index 63ba6c03c488..e8ff33b188e9 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -77,9 +77,9 @@
#define WM8960_SYSCLK_DIV_1 (0 << 1)
#define WM8960_SYSCLK_DIV_2 (2 << 1)
-#define WM8960_SYSCLK_MCLK (0 << 0)
+#define WM8960_SYSCLK_AUTO (0 << 0)
#define WM8960_SYSCLK_PLL (1 << 0)
-#define WM8960_SYSCLK_AUTO (2 << 0)
+#define WM8960_SYSCLK_MCLK (2 << 0)
#define WM8960_DAC_DIV_1 (0 << 3)
#define WM8960_DAC_DIV_1_5 (1 << 3)
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index c076f78d04ce..cfb8cfc91873 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;
@@ -743,6 +743,7 @@ static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
static int wm8961_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 reg;
/* This is all slightly unusual since we have no bypass paths
@@ -755,7 +756,7 @@ static int wm8961_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_PREPARE:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
/* Enable bias generation */
reg = snd_soc_component_read(component, WM8961_ANTI_POP);
reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
@@ -770,7 +771,7 @@ static int wm8961_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) {
/* VREF off */
reg = snd_soc_component_read(component, WM8961_PWR_MGMT_1);
reg &= ~WM8961_VREF;
@@ -904,7 +905,7 @@ static const struct regmap_config wm8961_regmap = {
.reg_defaults = wm8961_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm8961_volatile,
.readable_reg = wm8961_readable,
@@ -966,7 +967,7 @@ static int wm8961_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8961_i2c_id[] = {
- { "wm8961", 0 },
+ { "wm8961" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 68ea15be7330..e9e317ce6898 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -82,6 +82,7 @@ struct wm8962_priv {
#endif
int irq;
+ bool master_flag;
};
/* We can't use the same notifier block for more than one supply and
@@ -1544,7 +1545,7 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int shift = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
@@ -1556,7 +1557,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int shift = kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int old = wm8962->dsp2_ena;
int ret = 0;
@@ -1594,7 +1595,7 @@ out:
static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1624,7 +1625,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int ret;
/* Apply the update (if any) */
@@ -1854,10 +1855,10 @@ static int tp_event(struct snd_soc_dapm_widget *w,
reg = WM8962_ADDITIONAL_CONTROL_4;
- if (!strcmp(w->name, "TEMP_HP")) {
+ if (!snd_soc_dapm_widget_name_cmp(w, "TEMP_HP")) {
mask = WM8962_TEMP_ENA_HP_MASK;
val = WM8962_TEMP_ENA_HP;
- } else if (!strcmp(w->name, "TEMP_SPK")) {
+ } else if (!snd_soc_dapm_widget_name_cmp(w, "TEMP_SPK")) {
mask = WM8962_TEMP_ENA_SPK_MASK;
val = WM8962_TEMP_ENA_SPK;
} else {
@@ -2229,6 +2230,9 @@ SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
SND_SOC_DAPM_OUTPUT("HPOUTL"),
SND_SOC_DAPM_OUTPUT("HPOUTR"),
+
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
};
static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
@@ -2236,7 +2240,6 @@ SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
spkmixl, ARRAY_SIZE(spkmixl)),
SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
out_pga_event, SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("SPKOUT"),
};
@@ -2251,9 +2254,6 @@ SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
out_pga_event, SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
-SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
-
SND_SOC_DAPM_OUTPUT("SPKOUTL"),
SND_SOC_DAPM_OUTPUT("SPKOUTR"),
};
@@ -2366,12 +2366,18 @@ static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
{ "Speaker PGA", "Mixer", "Speaker Mixer" },
{ "Speaker PGA", "DAC", "DACL" },
- { "Speaker Output", NULL, "Speaker PGA" },
- { "Speaker Output", NULL, "SYSCLK" },
- { "Speaker Output", NULL, "TOCLK" },
- { "Speaker Output", NULL, "TEMP_SPK" },
+ { "SPKOUTL Output", NULL, "Speaker PGA" },
+ { "SPKOUTL Output", NULL, "SYSCLK" },
+ { "SPKOUTL Output", NULL, "TOCLK" },
+ { "SPKOUTL Output", NULL, "TEMP_SPK" },
- { "SPKOUT", NULL, "Speaker Output" },
+ { "SPKOUTR Output", NULL, "Speaker PGA" },
+ { "SPKOUTR Output", NULL, "SYSCLK" },
+ { "SPKOUTR Output", NULL, "TOCLK" },
+ { "SPKOUTR Output", NULL, "TEMP_SPK" },
+
+ { "SPKOUT", NULL, "SPKOUTL Output" },
+ { "SPKOUT", NULL, "SPKOUTR Output" },
};
static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
@@ -2413,7 +2419,7 @@ static int wm8962_add_widgets(struct snd_soc_component *component)
{
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
struct wm8962_pdata *pdata = &wm8962->pdata;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
snd_soc_add_component_controls(component, wm8962_snd_controls,
ARRAY_SIZE(wm8962_snd_controls));
@@ -2460,6 +2466,7 @@ static const int sysclk_rates[] = {
static void wm8962_configure_bclk(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int best, min_diff, diff;
int dspclk, i;
@@ -2499,7 +2506,7 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
* So we here provisionally enable it and then disable it afterward
* if current bias_level hasn't reached SND_SOC_BIAS_ON.
*/
- if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON)
snd_soc_component_update_bits(component, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
@@ -2513,7 +2520,7 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
usleep_range(500, 1000);
dspclk = snd_soc_component_read(component, WM8962_CLOCKING1);
- if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON)
snd_soc_component_update_bits(component, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, 0);
@@ -2573,6 +2580,8 @@ static void wm8962_configure_bclk(struct snd_soc_component *component)
static int wm8962_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
switch (level) {
case SND_SOC_BIAS_ON:
break;
@@ -2590,7 +2599,7 @@ static int wm8962_set_bias_level(struct snd_soc_component *component,
snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK, 0x100);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF)
msleep(100);
break;
@@ -2623,6 +2632,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int i;
int aif0 = 0;
@@ -2673,7 +2683,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
dev_dbg(component->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
wm8962->bclk, wm8962->lrclk);
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON)
wm8962_configure_bclk(component);
return 0;
@@ -2710,6 +2720,7 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
+ struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int aif0 = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -2756,11 +2767,13 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
+ wm8962->master_flag = false;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif0 |= WM8962_MSTR;
+ wm8962->master_flag = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
@@ -2881,7 +2894,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
{
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
struct _fll_div fll_div;
- unsigned long timeout;
+ unsigned long time_left;
int ret;
int fll1 = 0;
@@ -2914,8 +2927,12 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
switch (fll_id) {
case WM8962_FLL_MCLK:
case WM8962_FLL_BCLK:
+ fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+ break;
case WM8962_FLL_OSC:
fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+ snd_soc_component_update_bits(component, WM8962_PLL2,
+ WM8962_OSC_ENA, WM8962_OSC_ENA);
break;
case WM8962_FLL_INT:
snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
@@ -2924,7 +2941,7 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
break;
default:
- dev_err(component->dev, "Unknown FLL source %d\n", ret);
+ dev_err(component->dev, "Unknown FLL source %d\n", source);
return -EINVAL;
}
@@ -2965,14 +2982,14 @@ static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int s
* higher if we'll error out
*/
if (wm8962->irq)
- timeout = msecs_to_jiffies(5);
+ time_left = msecs_to_jiffies(5);
else
- timeout = msecs_to_jiffies(1);
+ time_left = msecs_to_jiffies(1);
- timeout = wait_for_completion_timeout(&wm8962->fll_lock,
- timeout);
+ time_left = wait_for_completion_timeout(&wm8962->fll_lock,
+ time_left);
- if (timeout == 0 && wm8962->irq) {
+ if (time_left == 0 && wm8962->irq) {
dev_err(component->dev, "FLL lock timed out");
snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, 0);
@@ -3180,7 +3197,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
{
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int irq_mask, enable;
wm8962->jack = jack;
@@ -3226,7 +3243,7 @@ static void wm8962_beep_work(struct work_struct *work)
struct wm8962_priv *wm8962 =
container_of(work, struct wm8962_priv, beep_work);
struct snd_soc_component *component = wm8962->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i;
int reg = 0;
int best = 0;
@@ -3398,13 +3415,16 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
return 0;
}
-static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm8962_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
struct snd_soc_component *component = wm8962->component;
- snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset,
- WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT);
+ return snd_soc_component_update_bits(component,
+ WM8962_GPIO_BASE + offset,
+ WM8962_GP2_LVL,
+ !!value << WM8962_GP2_LVL_SHIFT);
}
static int wm8962_gpio_direction_out(struct gpio_chip *chip,
@@ -3472,7 +3492,7 @@ static void wm8962_free_gpio(struct snd_soc_component *component)
static int wm8962_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int i;
@@ -3527,7 +3547,7 @@ static int wm8962_probe(struct snd_soc_component *component)
}
if (!dmicclk || !dmicdat) {
dev_dbg(component->dev, "DMIC not in use, disabling\n");
- snd_soc_dapm_nc_pin(dapm, "DMICDAT");
+ snd_soc_dapm_disable_pin(dapm, "DMICDAT");
}
if (dmicclk != dmicdat)
dev_warn(component->dev, "DMIC GPIOs partially configured\n");
@@ -3573,7 +3593,7 @@ static const struct regmap_config wm8962_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm8962_reg),
.volatile_reg = wm8962_volatile_register,
.readable_reg = wm8962_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
@@ -3841,7 +3861,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);
@@ -3892,6 +3911,9 @@ static int wm8962_runtime_resume(struct device *dev)
WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK,
WM8962_BIAS_ENA | 0x180);
+ if (wm8962->master_flag)
+ regmap_update_bits(wm8962->regmap, WM8962_AUDIO_INTERFACE_0,
+ WM8962_MSTR, WM8962_MSTR);
msleep(5);
return 0;
@@ -3905,6 +3927,10 @@ static int wm8962_runtime_suspend(struct device *dev)
{
struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+ if (wm8962->master_flag)
+ regmap_update_bits(wm8962->regmap, WM8962_AUDIO_INTERFACE_0,
+ WM8962_MSTR, 0);
+
regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
@@ -3921,15 +3947,14 @@ 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[] = {
- { "wm8962", 0 },
+ { "wm8962" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
@@ -3944,7 +3969,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 b22d8f0b59be..46aa556b44fa 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;
@@ -561,6 +561,7 @@ static int wm8971_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 pwr_reg = snd_soc_component_read(component, WM8971_PWR1) & 0xfe3e;
switch (level) {
@@ -573,7 +574,7 @@ static int wm8971_set_bias_level(struct snd_soc_component *component,
flush_delayed_work(&wm8971->charge_work);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
snd_soc_component_cache_sync(component);
/* charge output caps - set vmid to 5k for quick power up */
snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x01c0);
@@ -668,7 +669,7 @@ static const struct regmap_config wm8971_regmap = {
.reg_defaults = wm8971_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm8971_i2c_probe(struct i2c_client *i2c)
@@ -691,7 +692,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8971_i2c_id[] = {
- { "wm8971", 0 },
+ { "wm8971" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 044b6f604c09..0bb5e947f46d 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -186,7 +186,7 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 0),
/* Boost mixer */
static const struct snd_kcontrol_new wm8974_boost_mixer[] = {
-SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 1),
+SOC_DAPM_SINGLE("PGA Switch", WM8974_INPPGA, 6, 1, 1),
};
/* Input PGA */
@@ -246,8 +246,8 @@ static const struct snd_soc_dapm_route wm8974_dapm_routes[] = {
/* Boost Mixer */
{"ADC", NULL, "Boost Mixer"},
- {"Boost Mixer", "Aux Switch", "Aux Input"},
- {"Boost Mixer", NULL, "Input PGA"},
+ {"Boost Mixer", NULL, "Aux Input"},
+ {"Boost Mixer", "PGA Switch", "Input PGA"},
{"Boost Mixer", NULL, "MICP"},
/* Input PGA */
@@ -419,10 +419,14 @@ static int wm8974_update_clocks(struct snd_soc_dai *dai)
fs256 = 256 * priv->fs;
f = wm8974_get_mclkdiv(priv->mclk, fs256, &mclkdiv);
-
if (f != priv->mclk) {
/* The PLL performs best around 90MHz */
- fpll = wm8974_get_mclkdiv(22500000, fs256, &mclkdiv);
+ if (fs256 % 8000)
+ f = 22579200;
+ else
+ f = 24576000;
+
+ fpll = wm8974_get_mclkdiv(f, fs256, &mclkdiv);
}
wm8974_set_dai_pll(dai, 0, 0, priv->mclk, fpll);
@@ -454,10 +458,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;
@@ -579,6 +583,7 @@ static int wm8974_mute(struct snd_soc_dai *dai, int mute, int direction)
static int wm8974_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 power1 = snd_soc_component_read(component, WM8974_POWER1) & ~0x3;
switch (level) {
@@ -591,7 +596,7 @@ static int wm8974_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_STANDBY:
power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_sync(dev_get_regmap(component->dev, NULL));
/* Initial cap charge at VMID 5k */
@@ -707,7 +712,7 @@ static int wm8974_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8974_i2c_id[] = {
- { "wm8974", 0 },
+ { "wm8974" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 5c829301cf4c..935761e50865 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:
@@ -853,6 +853,7 @@ static int wm8978_mute(struct snd_soc_dai *dai, int mute, int direction)
static int wm8978_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 power1 = snd_soc_component_read(component, WM8978_POWER_MANAGEMENT_1) & ~3;
switch (level) {
@@ -865,7 +866,7 @@ static int wm8978_set_bias_level(struct snd_soc_component *component,
/* bit 3: enable bias, bit 2: enable I/O tie off buffer */
power1 |= 0xc;
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Initial cap charge at VMID 5k */
snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1,
power1 | 0x3);
@@ -924,8 +925,9 @@ static struct snd_soc_dai_driver wm8978_dai = {
static int wm8978_suspend(struct snd_soc_component *component)
{
struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
/* Also switch PLL off */
snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, 0);
@@ -937,11 +939,12 @@ static int wm8978_suspend(struct snd_soc_component *component)
static int wm8978_resume(struct snd_soc_component *component)
{
struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
/* Sync reg_cache with the hardware */
regcache_sync(wm8978->regmap);
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
if (wm8978->f_pllout)
/* Switch PLL on */
@@ -1014,7 +1017,7 @@ static const struct regmap_config wm8978_regmap_config = {
.max_register = WM8978_MAX_REGISTER,
.volatile_reg = wm8978_volatile,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8978_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults),
};
@@ -1056,7 +1059,7 @@ static int wm8978_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8978_i2c_id[] = {
- { "wm8978", 0 },
+ { "wm8978" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 2bd26e2478d9..cd34f71cf42a 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -489,7 +489,7 @@ static const struct snd_soc_dapm_route wm8983_audio_map[] = {
static int eqmode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg;
reg = snd_soc_component_read(component, WM8983_EQ1_LOW_SHELF);
@@ -504,7 +504,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
static int eqmode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int regpwr2, regpwr3;
unsigned int reg_eq;
@@ -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:
@@ -848,6 +848,7 @@ static int wm8983_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -859,7 +860,7 @@ static int wm8983_set_bias_level(struct snd_soc_component *component,
1 << WM8983_VMIDSEL_SHIFT);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(wm8983->regmap);
if (ret < 0) {
dev_err(component->dev, "Failed to sync cache: %d\n", ret);
@@ -995,7 +996,7 @@ static const struct regmap_config wm8983_regmap = {
.reg_defaults = wm8983_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = WM8983_MAX_REGISTER,
.writeable_reg = wm8983_writeable,
@@ -1059,7 +1060,7 @@ static int wm8983_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8983_i2c_id[] = {
- { "wm8983", 0 },
+ { "wm8983" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id);
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index c0816bcfa294..be23c0c608d1 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -564,7 +564,7 @@ static const struct snd_soc_dapm_route wm8985_aux_dapm_routes[] = {
static int wm8985_add_widgets(struct snd_soc_component *component)
{
struct wm8985_priv *wm8985 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (wm8985->dev_type) {
case WM8758:
@@ -589,7 +589,7 @@ static int wm8985_add_widgets(struct snd_soc_component *component)
static int eqmode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg;
reg = snd_soc_component_read(component, WM8985_EQ1_LOW_SHELF);
@@ -604,7 +604,7 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
static int eqmode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int regpwr2, regpwr3;
unsigned int reg_eq;
@@ -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:
@@ -948,6 +948,7 @@ static int wm8985_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int ret;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8985_priv *wm8985;
wm8985 = snd_soc_component_get_drvdata(component);
@@ -960,7 +961,7 @@ static int wm8985_set_bias_level(struct snd_soc_component *component,
1 << WM8985_VMIDSEL_SHIFT);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
wm8985->supplies);
if (ret) {
@@ -1125,7 +1126,7 @@ static const struct regmap_config wm8985_regmap = {
.max_register = WM8985_MAX_REGISTER,
.writeable_reg = wm8985_writeable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8985_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults),
};
@@ -1166,12 +1167,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 +1179,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 b440719cca7d..9bffe7a6ccec 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;
@@ -723,6 +723,7 @@ static int wm8988_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 pwr_reg = snd_soc_component_read(component, WM8988_PWR1) & ~0x1c1;
switch (level) {
@@ -735,7 +736,7 @@ static int wm8988_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_sync(wm8988->regmap);
/* VREF, VMID=2x5k */
@@ -832,7 +833,7 @@ static const struct regmap_config wm8988_regmap = {
.max_register = WM8988_LPPB,
.writeable_reg = wm8988_writeable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8988_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults),
};
@@ -896,7 +897,7 @@ static int wm8988_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8988_i2c_id[] = {
- { "wm8988", 0 },
+ { "wm8988" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 5a8e765090af..9f2b42025ec9 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -49,7 +49,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int reg = mc->reg;
@@ -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:
@@ -1017,6 +1017,7 @@ static int wm8990_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1030,7 +1031,7 @@ static int wm8990_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(wm8990->regmap);
if (ret < 0) {
dev_err(component->dev, "Failed to sync cache: %d\n", ret);
@@ -1184,10 +1185,12 @@ static struct snd_soc_dai_driver wm8990_dai = {
*/
static int wm8990_probe(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+
wm8990_reset(component);
/* charge output caps */
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
snd_soc_component_update_bits(component, WM8990_AUDIO_INTERFACE_4,
WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
@@ -1238,7 +1241,7 @@ static int wm8990_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8990_i2c_id[] = {
- { "wm8990", 0 },
+ { "wm8990" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 8cb2ae829699..b8ed2a3e699b 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -129,7 +129,7 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_sidetone_tlv,
static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int reg = kcontrol->private_value & 0xff;
int ret;
u16 val;
@@ -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:
@@ -1081,6 +1081,7 @@ static int wm8991_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8991_priv *wm8991 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u16 val;
switch (level) {
@@ -1095,7 +1096,7 @@ static int wm8991_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_sync(wm8991->regmap);
/* Enable all output discharge bits */
snd_soc_component_write(component, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
@@ -1253,7 +1254,7 @@ static const struct regmap_config wm8991_regmap = {
.volatile_reg = wm8991_volatile,
.reg_defaults = wm8991_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm8991_i2c_probe(struct i2c_client *i2c)
@@ -1314,7 +1315,7 @@ static int wm8991_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8991_i2c_id[] = {
- { "wm8991", 0 },
+ { "wm8991" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id);
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index feb997c698e2..1c9299979898 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -470,7 +470,7 @@ static int _wm8993_set_fll(struct snd_soc_component *component, int fll_id, int
struct i2c_client *i2c = to_i2c_client(component->dev);
u16 reg1, reg4, reg5;
struct _fll_div fll_div;
- unsigned int timeout;
+ unsigned long time_left;
int ret;
/* Any change? */
@@ -543,19 +543,19 @@ static int _wm8993_set_fll(struct snd_soc_component *component, int fll_id, int
/* If we've got an interrupt wired up make sure we get it */
if (i2c->irq)
- timeout = msecs_to_jiffies(20);
+ time_left = msecs_to_jiffies(20);
else if (Fref < 1000000)
- timeout = msecs_to_jiffies(3);
+ time_left = msecs_to_jiffies(3);
else
- timeout = msecs_to_jiffies(1);
+ time_left = msecs_to_jiffies(1);
try_wait_for_completion(&wm8993->fll_lock);
/* Enable the FLL */
snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
- timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
- if (i2c->irq && !timeout)
+ time_left = wait_for_completion_timeout(&wm8993->fll_lock, time_left);
+ if (i2c->irq && !time_left)
dev_warn(component->dev, "Timed out waiting for FLL\n");
dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
@@ -973,6 +973,7 @@ static int wm8993_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
wm_hubs_set_bias_level(component, level);
@@ -988,7 +989,7 @@ static int wm8993_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
wm8993->supplies);
if (ret != 0)
@@ -1098,18 +1099,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;
@@ -1482,7 +1483,7 @@ static struct snd_soc_dai_driver wm8993_dai = {
static int wm8993_probe(struct snd_soc_component *component)
{
struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
wm8993->hubs_data.hp_startup_mode = 1;
wm8993->hubs_data.dcs_codes_l = -2;
@@ -1536,7 +1537,7 @@ static int wm8993_probe(struct snd_soc_component *component)
* VMID as an output and can disable it.
*/
if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff)
- dapm->idle_bias_off = 1;
+ snd_soc_dapm_set_idle_bias(dapm, false);
return 0;
@@ -1546,6 +1547,7 @@ static int wm8993_probe(struct snd_soc_component *component)
static int wm8993_suspend(struct snd_soc_component *component)
{
struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int fll_fout = wm8993->fll_fout;
int fll_fref = wm8993->fll_fref;
int ret;
@@ -1560,7 +1562,7 @@ static int wm8993_suspend(struct snd_soc_component *component)
wm8993->fll_fout = fll_fout;
wm8993->fll_fref = fll_fref;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1568,9 +1570,10 @@ static int wm8993_suspend(struct snd_soc_component *component)
static int wm8993_resume(struct snd_soc_component *component)
{
struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* Restart the FLL? */
if (wm8993->fll_fout) {
@@ -1608,7 +1611,7 @@ static const struct regmap_config wm8993_regmap = {
.volatile_reg = wm8993_volatile,
.readable_reg = wm8993_readable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm8993_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
};
@@ -1732,7 +1735,7 @@ static void wm8993_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8993_i2c_id[] = {
- { "wm8993", 0 },
+ { "wm8993" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index bca3ebe0dac4..1d64c7c42ed1 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -214,7 +214,7 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
static int configure_clock(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
int change, new;
@@ -262,7 +262,7 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
else
clk = "AIF1CLK";
- return strcmp(source->name, clk) == 0;
+ return snd_soc_dapm_widget_name_cmp(source, clk) == 0;
}
static const char *sidetone_hpf_text[] = {
@@ -301,7 +301,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
int mask, ret;
/* Can't enable both ADC and DAC paths simultaneously */
@@ -358,7 +358,7 @@ static int wm8994_get_drc(const char *name)
static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
@@ -381,7 +381,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
int drc = wm8994_get_drc(kcontrol->id.name);
@@ -465,7 +465,7 @@ static int wm8994_get_retune_mobile_block(const char *name)
static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
@@ -488,7 +488,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
@@ -1515,7 +1515,7 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
int ret;
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -2210,7 +2210,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
int reg_offset, ret;
struct fll_div fll;
u16 reg, clk1, aif_reg, aif_src;
- unsigned long timeout;
+ unsigned long time_left;
bool was_enabled;
struct clk *mclk;
@@ -2403,9 +2403,9 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
WM8994_FLL1_FRAC, reg);
if (wm8994->fll_locked_irq) {
- timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
- msecs_to_jiffies(10));
- if (timeout == 0)
+ time_left = wait_for_completion_timeout(&wm8994->fll_locked[id],
+ msecs_to_jiffies(10));
+ if (time_left == 0)
dev_warn(component->dev,
"Timed out waiting for FLL lock\n");
} else {
@@ -2615,6 +2615,7 @@ static int wm8994_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8994 *control = wm8994->wm8994;
wm_hubs_set_bias_level(component, level);
@@ -2637,12 +2638,12 @@ static int wm8994_set_bias_level(struct snd_soc_component *component,
break;
}
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY)
active_reference(component);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
switch (control->type) {
case WM8958:
if (control->revision == 0) {
@@ -2666,7 +2667,7 @@ static int wm8994_set_bias_level(struct snd_soc_component *component,
WM8994_LINEOUT2_DISCH);
}
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE)
active_dereference(component);
/* MICBIAS into bypass mode on newer devices */
@@ -2686,7 +2687,7 @@ static int wm8994_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_OFF:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY)
wm8994->cur_fw = NULL;
break;
}
@@ -2697,7 +2698,7 @@ static int wm8994_set_bias_level(struct snd_soc_component *component,
int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (mode) {
case WM8994_VMID_NORMAL:
@@ -2783,9 +2784,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:
@@ -3215,6 +3216,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
};
static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
+ .probe = wm8994_aif2_probe,
.set_sysclk = wm8994_set_dai_sysclk,
.set_fmt = wm8994_set_dai_fmt,
.hw_params = wm8994_hw_params,
@@ -3269,7 +3271,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
.formats = WM8994_FORMATS,
.sig_bits = 24,
},
- .probe = wm8994_aif2_probe,
.ops = &wm8994_aif2_dai_ops,
},
{
@@ -3299,6 +3300,7 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
static int wm8994_component_suspend(struct snd_soc_component *component)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i, ret;
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
@@ -3310,7 +3312,7 @@ static int wm8994_component_suspend(struct snd_soc_component *component)
i + 1, ret);
}
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_OFF);
return 0;
}
@@ -3503,7 +3505,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
int micbias)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994_micdet *micdet;
struct wm8994 *control = wm8994->wm8994;
@@ -3653,7 +3655,7 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
/* Should be called with accdet_lock held */
static void wm1811_micd_stop(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (!wm8994->jackdet)
@@ -3773,7 +3775,7 @@ static void wm1811_mic_work(struct work_struct *work)
mic_work.work);
struct wm8994 *control = wm8994->wm8994;
struct snd_soc_component *component = wm8994->hubs.component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
pm_runtime_get_sync(component->dev);
@@ -3812,7 +3814,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
struct wm8994_priv *wm8994 = data;
struct wm8994 *control = wm8994->wm8994;
struct snd_soc_component *component = wm8994->hubs.component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int reg, delay;
bool present;
@@ -3928,7 +3930,7 @@ int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *
wm1811_micdet_cb det_cb, void *det_cb_data,
wm1811_mic_id_cb id_cb, void *id_cb_data)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
struct wm8994 *control = wm8994->wm8994;
u16 micd_lvl_sel;
@@ -3980,7 +3982,7 @@ int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *
snd_soc_component_update_bits(component, WM8958_MIC_DETECT_2,
WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
- WARN_ON(snd_soc_component_get_bias_level(component) > SND_SOC_BIAS_STANDBY);
+ WARN_ON(snd_soc_dapm_get_bias_level(dapm) > SND_SOC_BIAS_STANDBY);
/*
* If we can use jack detection start off with that,
@@ -4148,7 +4150,7 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data)
static int wm8994_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8994 *control = dev_get_drvdata(component->dev->parent);
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
unsigned int reg;
@@ -4182,8 +4184,8 @@ static int wm8994_component_probe(struct snd_soc_component *component)
wm8994->micdet_irq = control->pdata.micdet_irq;
- /* By default use idle_bias_off, will override for WM8994 */
- dapm->idle_bias_off = 1;
+ /* By default use idle_bias false, will override for WM8994 */
+ snd_soc_dapm_set_idle_bias(dapm, false);
/* Set revision-specific configuration */
switch (control->type) {
@@ -4191,7 +4193,7 @@ static int wm8994_component_probe(struct snd_soc_component *component)
/* Single ended line outputs should have VMID on. */
if (!control->pdata.lineout1_diff ||
!control->pdata.lineout2_diff)
- dapm->idle_bias_off = 0;
+ snd_soc_dapm_set_idle_bias(dapm, true);
switch (control->revision) {
case 2:
@@ -4662,7 +4664,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,19 +4688,18 @@ 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_new = wm8994_remove,
+ .remove = wm8994_remove,
};
module_platform_driver(wm8994_codec_driver);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index bc584b17bf28..b28398aa9e48 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -106,33 +106,33 @@ struct wm8994_priv {
int vss_ena[3];
int enh_eq_ena[3];
- /* Platform dependant DRC configuration */
+ /* Platform dependent DRC configuration */
const char **drc_texts;
int drc_cfg[WM8994_NUM_DRC];
struct soc_enum drc_enum;
- /* Platform dependant ReTune mobile configuration */
+ /* Platform dependent ReTune mobile configuration */
int num_retune_mobile_texts;
const char **retune_mobile_texts;
int retune_mobile_cfg[WM8994_NUM_EQ];
struct soc_enum retune_mobile_enum;
- /* Platform dependant MBC configuration */
+ /* Platform dependent MBC configuration */
int mbc_cfg;
const char **mbc_texts;
struct soc_enum mbc_enum;
- /* Platform dependant VSS configuration */
+ /* Platform dependent VSS configuration */
int vss_cfg;
const char **vss_texts;
struct soc_enum vss_enum;
- /* Platform dependant VSS HPF configuration */
+ /* Platform dependent VSS HPF configuration */
int vss_hpf_cfg;
const char **vss_hpf_texts;
struct soc_enum vss_hpf_enum;
- /* Platform dependant enhanced EQ configuration */
+ /* Platform dependent enhanced EQ configuration */
int enh_eq_cfg;
const char **enh_eq_texts;
struct soc_enum enh_eq_enum;
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 90588614edcc..104ce09c02e0 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -541,13 +541,13 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
clk = "AIF2CLK";
else
clk = "AIF1CLK";
- return !strcmp(source->name, clk);
+ return !snd_soc_dapm_widget_name_cmp(source, clk);
}
static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
int ret;
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -718,7 +718,7 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
static int configure_clock(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8995_priv *wm8995;
int change, new;
@@ -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:
@@ -1955,6 +1955,7 @@ static int wm8995_set_dai_sysclk(struct snd_soc_dai *dai,
static int wm8995_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8995_priv *wm8995;
int ret;
@@ -1964,7 +1965,7 @@ static int wm8995_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
wm8995->supplies);
if (ret)
@@ -2193,7 +2194,7 @@ static const struct regmap_config wm8995_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm8995_reg_defaults),
.volatile_reg = wm8995_volatile,
.readable_reg = wm8995_readable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
#if defined(CONFIG_SPI_MASTER)
@@ -2258,7 +2259,7 @@ static int wm8995_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm8995_i2c_id[] = {
- {"wm8995", 0},
+ {"wm8995"},
{}
};
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 5d0eb0ae0475..2d9cbf66f7d4 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -14,7 +14,7 @@
#include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/gpio/driver.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -51,7 +51,7 @@ struct wm8996_priv {
struct regmap *regmap;
struct snd_soc_component *component;
- int ldo1ena;
+ struct gpio_desc *ldo_ena;
int sysclk;
int sysclk_src;
@@ -77,7 +77,7 @@ struct wm8996_priv {
int rx_rate[WM8996_AIFS];
int bclk_rate[WM8996_AIFS];
- /* Platform dependant ReTune mobile configuration */
+ /* Platform dependent ReTune mobile configuration */
int num_retune_mobile_texts;
const char **retune_mobile_texts;
int retune_mobile_cfg[2];
@@ -409,7 +409,7 @@ static int wm8996_get_retune_mobile_block(const char *name)
static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
struct wm8996_pdata *pdata = &wm8996->pdata;
int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
@@ -431,7 +431,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
@@ -655,28 +655,28 @@ static void wait_for_dc_servo(struct snd_soc_component *component, u16 mask)
struct i2c_client *i2c = to_i2c_client(component->dev);
struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
int ret;
- unsigned long timeout = 200;
+ unsigned long time_left = 200;
snd_soc_component_write(component, WM8996_DC_SERVO_2, mask);
/* Use the interrupt if possible */
do {
if (i2c->irq) {
- timeout = wait_for_completion_timeout(&wm8996->dcs_done,
- msecs_to_jiffies(200));
- if (timeout == 0)
+ time_left = wait_for_completion_timeout(&wm8996->dcs_done,
+ msecs_to_jiffies(200));
+ if (time_left == 0)
dev_err(component->dev, "DC servo timed out\n");
} else {
msleep(1);
- timeout--;
+ time_left--;
}
ret = snd_soc_component_read(component, WM8996_DC_SERVO_2);
dev_dbg(component->dev, "DC servo state: %x\n", ret);
- } while (timeout && ret & mask);
+ } while (time_left && ret & mask);
- if (timeout == 0)
+ if (time_left == 0)
dev_err(component->dev, "DC servo timed out for %x\n", mask);
else
dev_dbg(component->dev, "DC servo complete for %x\n", mask);
@@ -1572,6 +1572,7 @@ static int wm8996_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
switch (level) {
@@ -1586,7 +1587,7 @@ static int wm8996_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
wm8996->supplies);
if (ret != 0) {
@@ -1596,9 +1597,9 @@ static int wm8996_set_bias_level(struct snd_soc_component *component,
return ret;
}
- if (wm8996->pdata.ldo_ena >= 0) {
- gpio_set_value_cansleep(wm8996->pdata.ldo_ena,
- 1);
+ if (wm8996->ldo_ena) {
+ gpiod_set_value_cansleep(wm8996->ldo_ena,
+ 1);
msleep(5);
}
@@ -1615,8 +1616,8 @@ static int wm8996_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_OFF:
regcache_cache_only(wm8996->regmap, true);
- if (wm8996->pdata.ldo_ena >= 0) {
- gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+ if (wm8996->ldo_ena) {
+ gpiod_set_value_cansleep(wm8996->ldo_ena, 0);
regcache_cache_only(wm8996->regmap, true);
}
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
@@ -1672,16 +1673,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;
@@ -2136,12 +2137,14 @@ static int wm8996_set_fll(struct snd_soc_component *component, int fll_id, int s
}
#ifdef CONFIG_GPIOLIB
-static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm8996_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
- regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
- WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT);
+ return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+ WM8996_GP1_LVL,
+ !!value << WM8996_GP1_LVL_SHIFT);
}
static int wm8996_gpio_direction_out(struct gpio_chip *chip,
@@ -2188,6 +2191,8 @@ static const struct gpio_chip wm8996_template_chip = {
.direction_input = wm8996_gpio_direction_in,
.get = wm8996_gpio_get,
.can_sleep = 1,
+ .ngpio = 5,
+ .base = -1,
};
static void wm8996_init_gpio(struct wm8996_priv *wm8996)
@@ -2195,14 +2200,8 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
int ret;
wm8996->gpio_chip = wm8996_template_chip;
- wm8996->gpio_chip.ngpio = 5;
wm8996->gpio_chip.parent = wm8996->dev;
- if (wm8996->pdata.gpio_base)
- wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
- else
- wm8996->gpio_chip.base = -1;
-
ret = gpiochip_add_data(&wm8996->gpio_chip, wm8996);
if (ret != 0)
dev_err(wm8996->dev, "Failed to add GPIOs: %d\n", ret);
@@ -2240,7 +2239,7 @@ int wm8996_detect(struct snd_soc_component *component, struct snd_soc_jack *jack
wm8996_polarity_fn polarity_cb)
{
struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
wm8996->jack = jack;
wm8996->detecting = true;
@@ -2285,7 +2284,7 @@ EXPORT_SYMBOL_GPL(wm8996_detect);
static void wm8996_hpdet_irq(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
int val, reg, report;
@@ -2345,7 +2344,7 @@ out:
static void wm8996_hpdet_start(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
/* Unclamp the output, we can't measure while we're shorting it */
snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1,
@@ -2610,7 +2609,7 @@ static const struct regmap_config wm8996_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm8996_reg),
.volatile_reg = wm8996_volatile_register,
.readable_reg = wm8996_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm8996_probe(struct snd_soc_component *component)
@@ -2771,15 +2770,15 @@ static int wm8996_i2c_probe(struct i2c_client *i2c)
memcpy(&wm8996->pdata, dev_get_platdata(&i2c->dev),
sizeof(wm8996->pdata));
- if (wm8996->pdata.ldo_ena > 0) {
- ret = gpio_request_one(wm8996->pdata.ldo_ena,
- GPIOF_OUT_INIT_LOW, "WM8996 ENA");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
- wm8996->pdata.ldo_ena, ret);
- goto err;
- }
+ wm8996->ldo_ena = devm_gpiod_get_optional(&i2c->dev, "wlf,ldo1ena",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(wm8996->ldo_ena)) {
+ ret = PTR_ERR(wm8996->ldo_ena);
+ dev_err(&i2c->dev, "Failed to request LDO ENA GPIO: %d\n",
+ ret);
+ goto err;
}
+ gpiod_set_consumer_name(wm8996->ldo_ena, "WM8996 ENA");
for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
wm8996->supplies[i].supply = wm8996_supply_names[i];
@@ -2814,8 +2813,8 @@ static int wm8996_i2c_probe(struct i2c_client *i2c)
goto err_gpio;
}
- if (wm8996->pdata.ldo_ena > 0) {
- gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
+ if (wm8996->ldo_ena) {
+ gpiod_set_value_cansleep(wm8996->ldo_ena, 1);
msleep(5);
}
@@ -2847,8 +2846,8 @@ static int wm8996_i2c_probe(struct i2c_client *i2c)
dev_info(&i2c->dev, "revision %c\n",
(reg & WM8996_CHIP_REV_MASK) + 'A');
- if (wm8996->pdata.ldo_ena > 0) {
- gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+ if (wm8996->ldo_ena) {
+ gpiod_set_value_cansleep(wm8996->ldo_ena, 0);
regcache_cache_only(wm8996->regmap, true);
} else {
ret = regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
@@ -3054,12 +3053,10 @@ err_gpiolib:
wm8996_free_gpio(wm8996);
err_regmap:
err_enable:
- if (wm8996->pdata.ldo_ena > 0)
- gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+ if (wm8996->ldo_ena)
+ gpiod_set_value_cansleep(wm8996->ldo_ena, 0);
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
err_gpio:
- if (wm8996->pdata.ldo_ena > 0)
- gpio_free(wm8996->pdata.ldo_ena);
err:
return ret;
@@ -3070,14 +3067,12 @@ static void wm8996_i2c_remove(struct i2c_client *client)
struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
wm8996_free_gpio(wm8996);
- if (wm8996->pdata.ldo_ena > 0) {
- gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
- gpio_free(wm8996->pdata.ldo_ena);
- }
+ if (wm8996->ldo_ena)
+ gpiod_set_value_cansleep(wm8996->ldo_ena, 0);
}
static const struct i2c_device_id wm8996_i2c_id[] = {
- { "wm8996", 0 },
+ { "wm8996" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id);
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 87442840f0af..83106523385a 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1055,7 +1055,7 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
static int wm8997_component_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
struct arizona *arizona = priv->core.arizona;
int ret;
@@ -1066,7 +1066,7 @@ static int wm8997_component_probe(struct snd_soc_component *component)
if (ret < 0)
return ret;
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
priv->core.arizona->dapm = dapm;
@@ -1210,7 +1210,7 @@ static struct platform_driver wm8997_codec_driver = {
.name = "wm8997-codec",
},
.probe = wm8997_probe,
- .remove_new = wm8997_remove,
+ .remove = wm8997_remove,
};
module_platform_driver(wm8997_codec_driver);
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 3c2c4d12c08e..8e6f03d00c71 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -101,8 +101,8 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
static int wm8998_inmux_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_component_get_dapm(component);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
struct arizona *arizona = wm8998->core.arizona;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -1279,7 +1279,7 @@ static int wm8998_set_fll(struct snd_soc_component *component, int fll_id,
static int wm8998_component_probe(struct snd_soc_component *component)
{
struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct arizona *arizona = priv->core.arizona;
int ret;
@@ -1292,7 +1292,7 @@ static int wm8998_component_probe(struct snd_soc_component *component)
arizona_init_gpio(component);
- snd_soc_component_disable_pin(component, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
return 0;
}
@@ -1426,7 +1426,7 @@ static struct platform_driver wm8998_codec_driver = {
.name = "wm8998-codec",
},
.probe = wm8998_probe,
- .remove_new = wm8998_remove,
+ .remove = wm8998_remove,
};
module_platform_driver(wm8998_codec_driver);
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 34a07db7342a..5bfe43c6c1f4 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -335,7 +335,7 @@ static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
static int speaker_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg;
reg = snd_soc_component_read(component, WM9081_ANALOGUE_SPEAKER_2);
@@ -356,7 +356,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,
static int speaker_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
unsigned int reg_pwr = snd_soc_component_read(component, WM9081_POWER_MANAGEMENT);
unsigned int reg2 = snd_soc_component_read(component, WM9081_ANALOGUE_SPEAKER_2);
@@ -816,6 +816,7 @@ static int wm9081_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -833,7 +834,7 @@ static int wm9081_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_STANDBY:
/* Initial cold start */
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
regcache_cache_only(wm9081->regmap, false);
regcache_sync(wm9081->regmap);
@@ -907,18 +908,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;
@@ -1295,7 +1296,7 @@ static const struct regmap_config wm9081_regmap = {
.num_reg_defaults = ARRAY_SIZE(wm9081_reg),
.volatile_reg = wm9081_volatile_register,
.readable_reg = wm9081_readable_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int wm9081_i2c_probe(struct i2c_client *i2c)
@@ -1360,7 +1361,7 @@ static void wm9081_i2c_remove(struct i2c_client *client)
{}
static const struct i2c_device_id wm9081_i2c_id[] = {
- { "wm9081", 0 },
+ { "wm9081" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 432729c753dd..5182f0839b7c 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -409,7 +409,7 @@ static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
static int wm9090_add_controls(struct snd_soc_component *component)
{
struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int i;
snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
@@ -463,6 +463,7 @@ static int wm9090_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
switch (level) {
case SND_SOC_BIAS_ON:
@@ -480,7 +481,7 @@ static int wm9090_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
/* Restore the register cache */
regcache_sync(wm9090->regmap);
}
@@ -553,7 +554,7 @@ static const struct regmap_config wm9090_regmap = {
.volatile_reg = wm9090_volatile,
.readable_reg = wm9090_readable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm9090_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults),
};
@@ -606,8 +607,8 @@ static int wm9090_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id wm9090_id[] = {
- { "wm9090", 0 },
- { "wm9093", 0 },
+ { "wm9090" },
+ { "wm9093" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm9090_id);
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index d04902ef1d5f..5c6aebe29cf1 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -64,7 +64,7 @@ static const struct regmap_config wm9705_regmap_config = {
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = regmap_ac97_default_volatile,
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index df9b7980706b..83cd42fa0c28 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -86,7 +86,7 @@ static const struct regmap_config wm9712_regmap_config = {
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = wm9712_volatile_reg,
@@ -215,7 +215,7 @@ static const unsigned int wm9712_mixer_mute_regs[] = {
static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
unsigned int val = ucontrol->value.integer.value[0];
@@ -259,7 +259,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
@@ -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[] = {
@@ -615,6 +611,7 @@ static int wm9712_set_bias_level(struct snd_soc_component *component,
static int wm9712_soc_resume(struct snd_soc_component *component)
{
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,
@@ -622,7 +619,7 @@ static int wm9712_soc_resume(struct snd_soc_component *component)
if (ret < 0)
return ret;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
if (ret == 0)
snd_soc_component_cache_sync(component);
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 5d2e54e06e30..b3bbecf074ee 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -224,7 +224,7 @@ static const unsigned int wm9713_mixer_mute_regs[] = {
static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
unsigned int val = ucontrol->value.integer.value[0];
@@ -268,7 +268,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
@@ -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[] = {
@@ -727,7 +723,7 @@ static const struct regmap_config wm9713_regmap_config = {
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wm9713_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
@@ -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;
}
@@ -1180,6 +1176,7 @@ static int wm9713_soc_suspend(struct snd_soc_component *component)
static int wm9713_soc_resume(struct snd_soc_component *component)
{
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
@@ -1187,7 +1184,7 @@ static int wm9713_soc_resume(struct snd_soc_component *component)
if (ret < 0)
return ret;
- snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY);
/* do we need to re-start the PLL ? */
if (wm9713->pll_in)
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 5a89abfe8784..17cec79245d4 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -7,6 +7,8 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/array_size.h>
+#include <linux/cleanup.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -18,7 +20,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
+#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <sound/core.h>
@@ -171,7 +173,7 @@ struct wm_adsp_compr {
struct snd_compressed_buffer size;
u32 *raw_buf;
- unsigned int copied_total;
+ u64 copied_total;
unsigned int sample_rate;
@@ -317,7 +319,7 @@ struct wm_coeff_ctl {
int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
@@ -330,7 +332,7 @@ EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
int ret = 1;
@@ -403,13 +405,8 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
char *p = ucontrol->value.bytes.data;
- int ret = 0;
-
- mutex_lock(&cs_ctl->dsp->pwr_lock);
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len);
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
- return ret;
+ return cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, p, cs_ctl->len);
}
static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
@@ -419,23 +416,12 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
(struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
- void *scratch;
- int ret = 0;
-
- scratch = vmalloc(size);
- if (!scratch)
- return -ENOMEM;
+ void *scratch __free(kvfree) = vmemdup_user(bytes, size);
- if (copy_from_user(scratch, bytes, size)) {
- ret = -EFAULT;
- } else {
- mutex_lock(&cs_ctl->dsp->pwr_lock);
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, scratch, size);
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
- }
- vfree(scratch);
+ if (IS_ERR(scratch))
+ return PTR_ERR(scratch);
- return ret;
+ return cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, scratch, size);
}
static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
@@ -474,13 +460,8 @@ static int wm_coeff_get(struct snd_kcontrol *kctl,
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
char *p = ucontrol->value.bytes.data;
- int ret;
-
- mutex_lock(&cs_ctl->dsp->pwr_lock);
- ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len);
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
- return ret;
+ return cs_dsp_coeff_lock_and_read_ctrl(cs_ctl, 0, p, cs_ctl->len);
}
static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
@@ -594,7 +575,7 @@ static void wm_adsp_ctl_work(struct work_struct *work)
kfree(kcontrol);
}
-static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
+int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
{
struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
struct cs_dsp *cs_dsp = &dsp->cs_dsp;
@@ -612,7 +593,7 @@ static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
return -EINVAL;
}
- switch (cs_dsp->fw_ver) {
+ switch (cs_dsp->wmfw_ver) {
case 0:
case 1:
ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
@@ -669,6 +650,17 @@ err_ctl:
return ret;
}
+EXPORT_SYMBOL_GPL(wm_adsp_control_add);
+
+static int wm_adsp_control_add_cb(struct cs_dsp_coeff_ctl *cs_ctl)
+{
+ struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
+
+ if (dsp->control_add)
+ return (dsp->control_add)(dsp, cs_ctl);
+ else
+ return wm_adsp_control_add(cs_ctl);
+}
static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
{
@@ -683,28 +675,32 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len)
{
- struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
- struct wm_coeff_ctl *ctl;
+ struct cs_dsp_coeff_ctl *cs_ctl;
int ret;
+ mutex_lock(&dsp->cs_dsp.pwr_lock);
+ cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
+ mutex_unlock(&dsp->cs_dsp.pwr_lock);
+
if (ret < 0)
return ret;
- if (ret == 0 || (cs_ctl->flags & WMFW_CTL_FLAG_SYS))
- return 0;
-
- ctl = cs_ctl->priv;
-
- return snd_soc_component_notify_control(dsp->component, ctl->name);
+ return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len)
{
- return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
- 0, buf, len);
+ int ret;
+
+ mutex_lock(&dsp->cs_dsp.pwr_lock);
+ ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
+ 0, buf, len);
+ mutex_unlock(&dsp->cs_dsp.pwr_lock);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
@@ -714,12 +710,10 @@ static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
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);
}
@@ -730,19 +724,25 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
const char *filetype)
{
struct cs_dsp *cs_dsp = &dsp->cs_dsp;
+ const char *fwf;
char *s, c;
int ret = 0;
+ if (dsp->fwf_name)
+ fwf = dsp->fwf_name;
+ else
+ fwf = dsp->cs_dsp.name;
+
if (system_name && asoc_component_prefix)
*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
- dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
+ fwf, wm_adsp_fw[dsp->fw].file, system_name,
asoc_component_prefix, filetype);
else if (system_name)
*filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
- dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
+ fwf, wm_adsp_fw[dsp->fw].file, system_name,
filetype);
else
- *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, dsp->fwf_name,
+ *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf,
wm_adsp_fw[dsp->fw].file, filetype);
if (*filename == NULL)
@@ -775,7 +775,7 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
return ret;
}
-static const char *cirrus_dir = "cirrus/";
+static const char * const cirrus_dir = "cirrus/";
static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
const struct firmware **wmfw_firmware,
char **wmfw_filename,
@@ -783,16 +783,19 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
char **coeff_filename)
{
const char *system_name = dsp->system_name;
- const char *asoc_component_prefix = dsp->component->name_prefix;
+ const char *suffix = dsp->component->name_prefix;
int ret = 0;
- if (system_name && asoc_component_prefix) {
+ if (dsp->fwf_suffix)
+ suffix = dsp->fwf_suffix;
+
+ if (system_name && suffix) {
if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
cirrus_dir, system_name,
- asoc_component_prefix, "wmfw")) {
+ suffix, "wmfw")) {
wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
cirrus_dir, system_name,
- asoc_component_prefix, "bin");
+ suffix, "bin");
return 0;
}
}
@@ -801,10 +804,10 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
cirrus_dir, system_name,
NULL, "wmfw")) {
- if (asoc_component_prefix)
+ if (suffix)
wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
cirrus_dir, system_name,
- asoc_component_prefix, "bin");
+ suffix, "bin");
if (!*coeff_firmware)
wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
@@ -814,6 +817,23 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
}
}
+ /* Check system-specific bin without wmfw before falling back to generic */
+ if (dsp->wmfw_optional && system_name) {
+ if (suffix)
+ wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+ cirrus_dir, system_name,
+ suffix, "bin");
+
+ if (!*coeff_firmware)
+ wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+ cirrus_dir, system_name,
+ NULL, "bin");
+
+ if (*coeff_firmware)
+ return 0;
+ }
+
+ /* Check legacy location */
if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
"", NULL, NULL, "wmfw")) {
wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
@@ -821,62 +841,28 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
return 0;
}
+ /* Fall back to generic wmfw and optional matching bin */
ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
cirrus_dir, NULL, NULL, "wmfw");
- if (!ret) {
+ if (!ret || dsp->wmfw_optional) {
wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
cirrus_dir, NULL, NULL, "bin");
return 0;
}
- if (dsp->wmfw_optional) {
- if (system_name) {
- if (asoc_component_prefix)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- asoc_component_prefix, "bin");
-
- if (!*coeff_firmware)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, system_name,
- NULL, "bin");
- }
-
- if (!*coeff_firmware)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- "", NULL, NULL, "bin");
-
- if (!*coeff_firmware)
- wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
- cirrus_dir, NULL, NULL, "bin");
-
- return 0;
- }
-
adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n",
- cirrus_dir, dsp->part, dsp->fwf_name, wm_adsp_fw[dsp->fw].file,
- system_name, asoc_component_prefix);
+ cirrus_dir, dsp->part,
+ dsp->fwf_name ? dsp->fwf_name : dsp->cs_dsp.name,
+ wm_adsp_fw[dsp->fw].file, system_name, suffix);
return -ENOENT;
}
static int wm_adsp_common_init(struct wm_adsp *dsp)
{
- char *p;
-
INIT_LIST_HEAD(&dsp->compr_list);
INIT_LIST_HEAD(&dsp->buffer_list);
- if (!dsp->fwf_name) {
- p = devm_kstrdup(dsp->cs_dsp.dev, dsp->cs_dsp.name, GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- dsp->fwf_name = p;
- for (; *p != 0; ++p)
- *p = tolower(*p);
- }
-
return 0;
}
@@ -950,7 +936,7 @@ EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -965,9 +951,9 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct wm_adsp *dsp = &dsps[mc->shift - 1];
@@ -979,9 +965,9 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
if (ucontrol->value.integer.value[0] || dsp->toggle_preload)
- snd_soc_component_force_enable_pin(component, preload);
+ snd_soc_dapm_force_enable_pin(dapm, preload);
else
- snd_soc_component_disable_pin(component, preload);
+ snd_soc_dapm_disable_pin(dapm, preload);
snd_soc_dapm_sync(dapm);
@@ -990,7 +976,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
dsp->preloaded = ucontrol->value.integer.value[0];
if (dsp->toggle_preload) {
- snd_soc_component_disable_pin(component, preload);
+ snd_soc_dapm_disable_pin(dapm, preload);
snd_soc_dapm_sync(dapm);
}
@@ -998,7 +984,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
-int wm_adsp_power_up(struct wm_adsp *dsp)
+int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware)
{
int ret = 0;
char *wmfw_filename = NULL;
@@ -1006,17 +992,25 @@ int wm_adsp_power_up(struct wm_adsp *dsp)
char *coeff_filename = NULL;
const struct firmware *coeff_firmware = NULL;
- ret = wm_adsp_request_firmware_files(dsp,
- &wmfw_firmware, &wmfw_filename,
- &coeff_firmware, &coeff_filename);
- if (ret)
- return ret;
+ if (load_firmware) {
+ ret = wm_adsp_request_firmware_files(dsp,
+ &wmfw_firmware, &wmfw_filename,
+ &coeff_firmware, &coeff_filename);
+ if (ret)
+ return ret;
+ }
+
+ if (dsp->bin_mandatory && !coeff_firmware) {
+ ret = -ENOENT;
+ goto err;
+ }
ret = cs_dsp_power_up(&dsp->cs_dsp,
wmfw_firmware, wmfw_filename,
coeff_firmware, coeff_filename,
wm_adsp_fw_text[dsp->fw]);
+err:
wm_adsp_release_firmware_files(dsp,
wmfw_firmware, wmfw_filename,
coeff_firmware, coeff_filename);
@@ -1025,13 +1019,19 @@ int wm_adsp_power_up(struct wm_adsp *dsp)
}
EXPORT_SYMBOL_GPL(wm_adsp_power_up);
+void wm_adsp_power_down(struct wm_adsp *dsp)
+{
+ cs_dsp_power_down(&dsp->cs_dsp);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_power_down);
+
static void wm_adsp_boot_work(struct work_struct *work)
{
struct wm_adsp *dsp = container_of(work,
struct wm_adsp,
boot_work);
- wm_adsp_power_up(dsp);
+ wm_adsp_power_up(dsp, true);
}
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
@@ -1043,10 +1043,10 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- queue_work(system_unbound_wq, &dsp->boot_work);
+ queue_work(system_dfl_wq, &dsp->boot_work);
break;
case SND_SOC_DAPM_PRE_PMD:
- cs_dsp_power_down(&dsp->cs_dsp);
+ wm_adsp_power_down(dsp);
break;
default:
break;
@@ -1086,37 +1086,47 @@ static void wm_adsp_event_post_stop(struct cs_dsp *cs_dsp)
dsp->fatal_error = false;
}
+int wm_adsp_run(struct wm_adsp *dsp)
+{
+ flush_work(&dsp->boot_work);
+
+ return cs_dsp_run(&dsp->cs_dsp);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_run);
+
+void wm_adsp_stop(struct wm_adsp *dsp)
+{
+ cs_dsp_stop(&dsp->cs_dsp);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_stop);
+
int wm_adsp_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 wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct wm_adsp *dsp = &dsps[w->shift];
- int ret = 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- flush_work(&dsp->boot_work);
- ret = cs_dsp_run(&dsp->cs_dsp);
- break;
+ return wm_adsp_run(dsp);
case SND_SOC_DAPM_PRE_PMD:
- cs_dsp_stop(&dsp->cs_dsp);
- break;
+ wm_adsp_stop(dsp);
+ return 0;
default:
- break;
+ return 0;
}
-
- return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_event);
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
char preload[32];
if (!dsp->cs_dsp.no_core_startstop) {
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
- snd_soc_component_disable_pin(component, preload);
+ snd_soc_dapm_disable_pin(dapm, preload);
}
cs_dsp_init_debugfs(&dsp->cs_dsp, component->debugfs_root);
@@ -1228,22 +1238,22 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
if (wm_adsp_fw[dsp->fw].num_caps == 0) {
adsp_err(dsp, "%s: Firmware does not support compressed API\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
ret = -ENXIO;
goto out;
}
if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
adsp_err(dsp, "%s: Firmware does not support stream direction\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
ret = -EINVAL;
goto out;
}
list_for_each_entry(tmp, &dsp->compr_list, list) {
- if (!strcmp(tmp->name, asoc_rtd_to_codec(rtd, 0)->name)) {
+ if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) {
adsp_err(dsp, "%s: Only a single stream supported per dai\n",
- asoc_rtd_to_codec(rtd, 0)->name);
+ snd_soc_rtd_to_codec(rtd, 0)->name);
ret = -EBUSY;
goto out;
}
@@ -1257,7 +1267,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
compr->dsp = dsp;
compr->stream = stream;
- compr->name = asoc_rtd_to_codec(rtd, 0)->name;
+ compr->name = snd_soc_rtd_to_codec(rtd, 0)->name;
list_add_tail(&compr->list, &dsp->compr_list);
@@ -1434,12 +1444,12 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
&region->base_addr);
if (ret < 0)
- return ret;
+ goto err;
ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
&offset);
if (ret < 0)
- return ret;
+ goto err;
region->cumulative_size = offset;
@@ -1450,6 +1460,10 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
}
return 0;
+
+err:
+ kfree(buf->regions);
+ return ret;
}
static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
@@ -1547,7 +1561,7 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
for (i = 0; i < 5; ++i) {
ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1,
- min(cs_ctl->len, sizeof(coeff_v1)));
+ min((size_t)cs_ctl->len, sizeof(coeff_v1)));
if (ret < 0)
return ret;
@@ -1847,7 +1861,7 @@ static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
int wm_adsp_compr_pointer(struct snd_soc_component *component,
struct snd_compr_stream *stream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp *dsp = compr->dsp;
@@ -2069,12 +2083,12 @@ irqreturn_t wm_halo_wdt_expire(int irq, void *data)
EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
static const struct cs_dsp_client_ops wm_adsp1_client_ops = {
- .control_add = wm_adsp_control_add,
+ .control_add = wm_adsp_control_add_cb,
.control_remove = wm_adsp_control_remove,
};
static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
- .control_add = wm_adsp_control_add,
+ .control_add = wm_adsp_control_add_cb,
.control_remove = wm_adsp_control_remove,
.pre_run = wm_adsp_pre_run,
.post_run = wm_adsp_event_post_run,
@@ -2082,5 +2096,6 @@ static const struct cs_dsp_client_ops wm_adsp2_client_ops = {
.watchdog_expired = wm_adsp_fatal_error,
};
+MODULE_DESCRIPTION("Cirrus Logic ASoC DSP Support");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(FW_CS_DSP);
+MODULE_IMPORT_NS("FW_CS_DSP");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 769904d34a87..8035fda71f8d 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -29,14 +29,17 @@ struct wm_adsp {
const char *part;
const char *fwf_name;
const char *system_name;
+ const char *fwf_suffix;
struct snd_soc_component *component;
unsigned int sys_config_size;
int fw;
bool wmfw_optional;
+ bool bin_mandatory;
struct work_struct boot_work;
+ int (*control_add)(struct wm_adsp *dsp, struct cs_dsp_coeff_ctl *cs_ctl);
int (*pre_run)(struct wm_adsp *dsp);
bool preloaded;
@@ -91,12 +94,15 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
-int wm_adsp_power_up(struct wm_adsp *dsp);
+int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware);
+void wm_adsp_power_down(struct wm_adsp *dsp);
irqreturn_t wm_adsp2_bus_error(int irq, void *data);
irqreturn_t wm_halo_bus_error(int irq, void *data);
irqreturn_t wm_halo_wdt_expire(int irq, void *data);
+int wm_adsp_run(struct wm_adsp *dsp);
+void wm_adsp_stop(struct wm_adsp *dsp);
int wm_adsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -125,10 +131,12 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component,
int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
int wm_adsp_compr_pointer(struct snd_soc_component *component,
struct snd_compr_stream *stream,
- struct snd_compr_tstamp *tstamp);
+ struct snd_compr_tstamp64 *tstamp);
int wm_adsp_compr_copy(struct snd_soc_component *component,
struct snd_compr_stream *stream,
char __user *buf, size_t count);
+
+int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl);
int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len);
int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 0c881846f485..f80dfc488e3c 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>
@@ -330,7 +331,7 @@ static void enable_dc_servo(struct snd_soc_component *component)
static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
int ret;
@@ -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);
@@ -693,7 +694,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
int ret;
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -713,7 +714,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
static int class_w_put_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
int ret;
ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
@@ -1111,7 +1112,7 @@ static const struct snd_soc_dapm_route lineout2_se_routes[] = {
int wm_hubs_add_analogue_controls(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
/* Latch volume update bits & default ZC on */
snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
@@ -1155,7 +1156,7 @@ int wm_hubs_add_analogue_routes(struct snd_soc_component *component,
int lineout1_diff, int lineout2_diff)
{
struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
hubs->component = component;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index f709231b1277..d7aca6567c2d 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -199,15 +199,10 @@
#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) }
-
-static struct reg_default wsa881x_defaults[] = {
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+ snd_soc_get_volsw, wsa881x_put_pa_gain, tlv_array)
+
+static const struct reg_default wsa881x_defaults[] = {
{ WSA881X_CHIP_ID0, 0x00 },
{ WSA881X_CHIP_ID1, 0x00 },
{ WSA881X_CHIP_ID2, 0x00 },
@@ -351,7 +346,7 @@ static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = {
};
/* Default register reset values for WSA881x rev 2.0 */
-static struct reg_sequence wsa881x_rev_2_0[] = {
+static const struct reg_sequence wsa881x_rev_2_0[] = {
{ WSA881X_RESET_CTL, 0x00, 0x00 },
{ WSA881X_TADC_VALUE_CTL, 0x01, 0x00 },
{ WSA881X_INTR_MASK, 0x1B, 0x00 },
@@ -386,33 +381,32 @@ enum wsa_port_ids {
/* 4 ports */
static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
- {
- /* DAC */
- .num = 1,
+ [WSA881X_PORT_DAC] = {
+ .num = WSA881X_PORT_DAC + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
- }, {
- /* COMP */
- .num = 2,
+ },
+ [WSA881X_PORT_COMP] = {
+ .num = WSA881X_PORT_COMP + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
- }, {
- /* BOOST */
- .num = 3,
+ },
+ [WSA881X_PORT_BOOST] = {
+ .num = WSA881X_PORT_BOOST + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
- }, {
- /* VISENSE */
- .num = 4,
+ },
+ [WSA881X_PORT_VISENSE] = {
+ .num = WSA881X_PORT_VISENSE + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
@@ -422,17 +416,20 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = {
};
static const struct sdw_port_config wsa881x_pconfig[WSA881X_MAX_SWR_PORTS] = {
- {
- .num = 1,
+ [WSA881X_PORT_DAC] = {
+ .num = WSA881X_PORT_DAC + 1,
.ch_mask = 0x1,
- }, {
- .num = 2,
+ },
+ [WSA881X_PORT_COMP] = {
+ .num = WSA881X_PORT_COMP + 1,
.ch_mask = 0xf,
- }, {
- .num = 3,
+ },
+ [WSA881X_PORT_BOOST] = {
+ .num = WSA881X_PORT_BOOST + 1,
.ch_mask = 0x3,
- }, { /* IV feedback */
- .num = 4,
+ },
+ [WSA881X_PORT_VISENSE] = {
+ .num = WSA881X_PORT_VISENSE + 1,
.ch_mask = 0x3,
},
};
@@ -634,10 +631,10 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config wsa881x_regmap_config = {
+static const struct regmap_config wsa881x_regmap_config = {
.reg_bits = 32,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wsa881x_defaults,
.max_register = WSA881X_SPKR_STATUS3,
.num_reg_defaults = ARRAY_SIZE(wsa881x_defaults),
@@ -645,7 +642,6 @@ static struct regmap_config wsa881x_regmap_config = {
.readable_reg = wsa881x_readable_register,
.reg_format_endian = REGMAP_ENDIAN_NATIVE,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
- .can_multi_write = true,
};
enum {
@@ -681,7 +677,6 @@ struct wsa881x_priv {
* For backwards compatibility.
*/
unsigned int sd_n_val;
- int version;
int active_ports;
bool port_prepared[WSA881X_MAX_SWR_PORTS];
bool port_enable[WSA881X_MAX_SWR_PORTS];
@@ -692,7 +687,6 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x)
struct regmap *rm = wsa881x->regmap;
unsigned int val = 0;
- regmap_read(rm, WSA881X_CHIP_ID1, &wsa881x->version);
regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0,
ARRAY_SIZE(wsa881x_rev_2_0));
@@ -744,7 +738,7 @@ static int wsa881x_component_probe(struct snd_soc_component *comp)
static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kc);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kc);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kc->private_value;
int max = mc->max;
@@ -781,7 +775,6 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
usleep_range(1000, 1010);
}
- pm_runtime_mark_last_busy(comp->dev);
pm_runtime_put_autosuspend(comp->dev);
return 1;
@@ -790,7 +783,7 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
static int wsa881x_get_port(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct wsa881x_priv *data = snd_soc_component_get_drvdata(comp);
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -822,7 +815,7 @@ static int wsa881x_boost_ctrl(struct snd_soc_component *comp, bool enable)
static int wsa881x_set_port(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct wsa881x_priv *data = snd_soc_component_get_drvdata(comp);
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -1119,8 +1112,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
if (!wsa881x)
return -ENOMEM;
- wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown",
- GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", 0);
if (IS_ERR(wsa881x->sd_n))
return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n),
"Shutdown Control GPIO not found\n");
@@ -1153,9 +1145,10 @@ static int wsa881x_probe(struct sdw_slave *pdev,
wsa881x->sconfig.frame_rate = 48000;
wsa881x->sconfig.direction = SDW_DATA_DIR_RX;
wsa881x->sconfig.type = SDW_STREAM_PDM;
- pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0);
+ pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS - 1, 0);
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ pdev->prop.clk_stop_mode1 = true;
gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val);
wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
@@ -1174,7 +1167,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 +1180,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 +1204,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 +1220,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 5c1cfceb2956..c3046e260cb9 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -6,14 +6,15 @@
#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>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/printk.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
@@ -157,8 +158,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)
@@ -428,6 +449,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;
@@ -437,13 +469,19 @@ struct wsa883x_priv {
struct sdw_stream_runtime *sruntime;
struct sdw_port_config port_config[WSA883X_MAX_SWR_PORTS];
struct gpio_desc *sd_n;
+ struct reset_control *sd_reset;
bool port_prepared[WSA883X_MAX_SWR_PORTS];
bool port_enable[WSA883X_MAX_SWR_PORTS];
- int version;
- int variant;
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 {
@@ -483,33 +521,32 @@ static const struct soc_enum wsa_dev_mode_enum =
/* 4 ports */
static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
- {
- /* DAC */
- .num = 1,
+ [WSA883X_PORT_DAC] = {
+ .num = WSA883X_PORT_DAC + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
- }, {
- /* COMP */
- .num = 2,
+ },
+ [WSA883X_PORT_COMP] = {
+ .num = WSA883X_PORT_COMP + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
- }, {
- /* BOOST */
- .num = 3,
+ },
+ [WSA883X_PORT_BOOST] = {
+ .num = WSA883X_PORT_BOOST + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
.simple_ch_prep_sm = true,
.read_only_wordlength = true,
- }, {
- /* VISENSE */
- .num = 4,
+ },
+ [WSA883X_PORT_VISENSE] = {
+ .num = WSA883X_PORT_VISENSE + 1,
.type = SDW_DPN_SIMPLE,
.min_ch = 1,
.max_ch = 1,
@@ -519,22 +556,25 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
};
static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
- {
- .num = 1,
+ [WSA883X_PORT_DAC] = {
+ .num = WSA883X_PORT_DAC + 1,
.ch_mask = 0x1,
- }, {
- .num = 2,
+ },
+ [WSA883X_PORT_COMP] = {
+ .num = WSA883X_PORT_COMP + 1,
.ch_mask = 0xf,
- }, {
- .num = 3,
- .ch_mask = 0x3,
- }, { /* IV feedback */
- .num = 4,
+ },
+ [WSA883X_PORT_BOOST] = {
+ .num = WSA883X_PORT_BOOST + 1,
.ch_mask = 0x3,
},
+ [WSA883X_PORT_VISENSE] = {
+ .num = WSA883X_PORT_VISENSE + 1,
+ .ch_mask = 0x1,
+ },
};
-static struct reg_default wsa883x_defaults[] = {
+static const struct reg_default wsa883x_defaults[] = {
{ WSA883X_REF_CTRL, 0xD5 },
{ WSA883X_TEST_CTL_0, 0x06 },
{ WSA883X_BIAS_0, 0xD2 },
@@ -935,10 +975,10 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
return wsa883x_readonly_register(dev, reg);
}
-static struct regmap_config wsa883x_regmap_config = {
+static const struct regmap_config wsa883x_regmap_config = {
.reg_bits = 32,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = wsa883x_defaults,
.max_register = WSA883X_MAX_REGISTER,
.num_reg_defaults = ARRAY_SIZE(wsa883x_defaults),
@@ -946,7 +986,6 @@ static struct regmap_config wsa883x_regmap_config = {
.writeable_reg = wsa883x_writeable_register,
.reg_format_endian = REGMAP_ENDIAN_NATIVE,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
- .can_multi_write = true,
.use_single_read = true,
};
@@ -999,33 +1038,36 @@ static const struct reg_sequence reg_init[] = {
{WSA883X_GMAMP_SUP1, 0xE2},
};
-static void wsa883x_init(struct wsa883x_priv *wsa883x)
+static int wsa883x_init(struct wsa883x_priv *wsa883x)
{
struct regmap *regmap = wsa883x->regmap;
- int variant, version;
+ int variant, version, ret;
- regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
- wsa883x->variant = variant & WSA883X_ID_MASK;
+ ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
+ if (ret)
+ return ret;
+ variant = variant & WSA883X_ID_MASK;
- regmap_read(regmap, WSA883X_CHIP_ID0, &version);
- wsa883x->version = version;
+ ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version);
+ if (ret)
+ return ret;
- switch (wsa883x->variant) {
+ switch (variant) {
case WSA8830:
dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n",
- wsa883x->version);
+ version);
break;
case WSA8835:
dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n",
- wsa883x->version);
+ version);
break;
case WSA8832:
dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n",
- wsa883x->version);
+ version);
break;
case WSA8835_V2:
dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n",
- wsa883x->version);
+ version);
break;
default:
break;
@@ -1036,12 +1078,14 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x)
/* Initial settings */
regmap_multi_reg_write(regmap, reg_init, ARRAY_SIZE(reg_init));
- if (wsa883x->variant == WSA8830 || wsa883x->variant == WSA8832) {
+ if (variant == WSA8830 || variant == WSA8832) {
wsa883x->comp_offset = COMP_OFFSET3;
regmap_update_bits(regmap, WSA883X_DRE_CTL_0,
WSA883X_DRE_OFFSET_MASK,
wsa883x->comp_offset);
}
+
+ return 0;
}
static int wsa883x_update_status(struct sdw_slave *slave,
@@ -1050,7 +1094,7 @@ static int wsa883x_update_status(struct sdw_slave *slave,
struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0)
- wsa883x_init(wsa883x);
+ return wsa883x_init(wsa883x);
return 0;
}
@@ -1077,7 +1121,7 @@ static const struct sdw_slave_ops wsa883x_slave_ops = {
static int wsa_dev_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
ucontrol->value.enumerated.item[0] = wsa883x->dev_mode;
@@ -1088,7 +1132,7 @@ static int wsa_dev_mode_get(struct snd_kcontrol *kcontrol,
static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
if (wsa883x->dev_mode == ucontrol->value.enumerated.item[0])
@@ -1099,12 +1143,16 @@ static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const DECLARE_TLV_DB_SCALE(pa_gain, -300, 150, -300);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(pa_gain,
+ 0, 14, TLV_DB_SCALE_ITEM(-300, 0, 0),
+ 15, 29, TLV_DB_SCALE_ITEM(-300, 150, 0),
+ 30, 31, TLV_DB_SCALE_ITEM(1800, 0, 0),
+);
static int wsa883x_get_swr_port(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp);
struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
int portidx = mixer->reg;
@@ -1117,7 +1165,7 @@ static int wsa883x_get_swr_port(struct snd_kcontrol *kcontrol,
static int wsa883x_set_swr_port(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp);
struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
int portidx = mixer->reg;
@@ -1140,7 +1188,7 @@ static int wsa883x_set_swr_port(struct snd_kcontrol *kcontrol,
static int wsa883x_get_comp_offset(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = wsa883x->comp_offset;
@@ -1151,7 +1199,7 @@ static int wsa883x_get_comp_offset(struct snd_kcontrol *kcontrol,
static int wsa883x_set_comp_offset(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
if (wsa883x->comp_offset == ucontrol->value.integer.value[0])
@@ -1179,6 +1227,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,
@@ -1204,9 +1256,6 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
break;
}
- snd_soc_component_write_field(component, WSA883X_DRE_CTL_1,
- WSA883X_DRE_GAIN_EN_MASK,
- WSA883X_DRE_GAIN_FROM_CSR);
if (wsa883x->port_enable[WSA883X_PORT_COMP])
snd_soc_component_write_field(component, WSA883X_DRE_CTL_0,
WSA883X_DRE_OFFSET_MASK,
@@ -1219,9 +1268,6 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL,
WSA883X_PDM_EN_MASK,
WSA883X_PDM_ENABLE);
- snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
- WSA883X_GLOBAL_PA_EN_MASK,
- WSA883X_GLOBAL_PA_ENABLE);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -1234,6 +1280,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;
@@ -1347,6 +1396,7 @@ static const struct snd_soc_dai_ops wsa883x_dai_ops = {
.hw_free = wsa883x_hw_free,
.mute_stream = wsa883x_digital_mute,
.set_stream = wsa883x_set_sdw_stream,
+ .mute_unmute_on_trigger = true,
};
static struct snd_soc_dai_driver wsa883x_dais[] = {
@@ -1365,6 +1415,176 @@ 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_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 void wsa883x_reset_assert(void *data)
+{
+ struct wsa883x_priv *wsa883x = data;
+
+ if (wsa883x->sd_reset)
+ reset_control_assert(wsa883x->sd_reset);
+ else
+ gpiod_direction_output(wsa883x->sd_n, 1);
+}
+
+static void wsa883x_reset_deassert(struct wsa883x_priv *wsa883x)
+{
+ if (wsa883x->sd_reset)
+ reset_control_deassert(wsa883x->sd_reset);
+ else
+ gpiod_direction_output(wsa883x->sd_n, 0);
+}
+
+static int wsa883x_get_reset(struct device *dev, struct wsa883x_priv *wsa883x)
+{
+ wsa883x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(wsa883x->sd_reset))
+ return dev_err_probe(dev, PTR_ERR(wsa883x->sd_reset),
+ "Failed to get reset\n");
+
+ /* if sd_reset: NULL, so use the backwards compatible way for powerdown-gpios */
+ if (!wsa883x->sd_reset) {
+ wsa883x->sd_n = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(wsa883x->sd_n))
+ return dev_err_probe(dev, PTR_ERR(wsa883x->sd_n),
+ "Shutdown Control GPIO not found\n");
+ }
+
+ return 0;
+}
+
static int wsa883x_probe(struct sdw_slave *pdev,
const struct sdw_device_id *id)
{
@@ -1385,13 +1605,9 @@ static int wsa883x_probe(struct sdw_slave *pdev,
if (ret)
return dev_err_probe(dev, ret, "Failed to enable vdd regulator\n");
- wsa883x->sd_n = devm_gpiod_get_optional(dev, "powerdown",
- GPIOD_FLAGS_BIT_NONEXCLUSIVE | GPIOD_OUT_HIGH);
- if (IS_ERR(wsa883x->sd_n)) {
- ret = dev_err_probe(dev, PTR_ERR(wsa883x->sd_n),
- "Shutdown Control GPIO not found\n");
+ ret = wsa883x_get_reset(dev, wsa883x);
+ if (ret)
goto err;
- }
dev_set_drvdata(dev, wsa883x);
wsa883x->slave = pdev;
@@ -1400,20 +1616,45 @@ 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);
- pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0);
+ /*
+ * Port map index starts with 0, however the data port for this codec
+ * are from index 1
+ */
+ if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1],
+ WSA883X_MAX_SWR_PORTS))
+ dev_dbg(dev, "Static Port mapping not specified\n");
+
+ pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS - 1, 0);
pdev->prop.simple_clk_stop_capable = true;
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
- gpiod_direction_output(wsa883x->sd_n, 0);
+
+ wsa883x_reset_deassert(wsa883x);
+ ret = devm_add_action_or_reset(dev, wsa883x_reset_assert, wsa883x);
+ if (ret)
+ return ret;
wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config);
if (IS_ERR(wsa883x->regmap)) {
- gpiod_direction_output(wsa883x->sd_n, 1);
ret = dev_err_probe(dev, PTR_ERR(wsa883x->regmap),
"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);
@@ -1432,7 +1673,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);
@@ -1442,7 +1683,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);
@@ -1453,7 +1694,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[] = {
@@ -1466,7 +1707,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
new file mode 100644
index 000000000000..887edd2be705
--- /dev/null
+++ b/sound/soc/codecs/wsa884x.c
@@ -0,0 +1,2181 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.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>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define WSA884X_BASE 0x3000
+#define WSA884X_ANA_BG_TSADC_BASE (WSA884X_BASE + 0x0001)
+#define WSA884X_BG_CTRL (WSA884X_ANA_BG_TSADC_BASE + 0x00)
+#define WSA884X_ADC_CTRL (WSA884X_ANA_BG_TSADC_BASE + 0x01)
+#define WSA884X_BOP1_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x02)
+#define WSA884X_BOP2_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x03)
+#define WSA884X_BOP2_PROG_BOP2_VTH_MASK 0xf0
+#define WSA884X_BOP2_PROG_BOP2_VTH_SHIFT 4
+#define WSA884X_BOP2_PROG_BOP2_HYST_MASK 0x0f
+#define WSA884X_BOP2_PROG_BOP2_HYST_SHIFT 0
+#define WSA884X_UVLO_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x04)
+#define WSA884X_UVLO_PROG1 (WSA884X_ANA_BG_TSADC_BASE + 0x05)
+#define WSA884X_SPARE_CTRL_0 (WSA884X_ANA_BG_TSADC_BASE + 0x06)
+#define WSA884X_SPARE_CTRL_1 (WSA884X_ANA_BG_TSADC_BASE + 0x07)
+#define WSA884X_SPARE_CTRL_2 (WSA884X_ANA_BG_TSADC_BASE + 0x08)
+#define WSA884X_SPARE_CTRL_3 (WSA884X_ANA_BG_TSADC_BASE + 0x09)
+#define WSA884X_REF_CTRL (WSA884X_ANA_BG_TSADC_BASE + 0x0a)
+#define WSA884X_REF_CTRL_BG_RDY_SEL_MASK 0x03
+#define WSA884X_REF_CTRL_BG_RDY_SEL_SHIFT 0
+#define WSA884X_BG_TEST_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x0b)
+#define WSA884X_BG_BIAS (WSA884X_ANA_BG_TSADC_BASE + 0x0c)
+#define WSA884X_ADC_PROG (WSA884X_ANA_BG_TSADC_BASE + 0x0d)
+#define WSA884X_ADC_IREF_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x0e)
+#define WSA884X_ADC_ISENS_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x0f)
+#define WSA884X_ADC_CLK_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x10)
+#define WSA884X_ADC_TEST_CTL (WSA884X_ANA_BG_TSADC_BASE + 0x11)
+#define WSA884X_ADC_BIAS (WSA884X_ANA_BG_TSADC_BASE + 0x12)
+#define WSA884X_VBAT_SNS (WSA884X_ANA_BG_TSADC_BASE + 0x13)
+#define WSA884X_DOUT_MSB (WSA884X_ANA_BG_TSADC_BASE + 0x14)
+#define WSA884X_DOUT_LSB (WSA884X_ANA_BG_TSADC_BASE + 0x15)
+#define WSA884X_BOP_ATEST_SEL (WSA884X_ANA_BG_TSADC_BASE + 0x16)
+#define WSA884X_MISC0 (WSA884X_ANA_BG_TSADC_BASE + 0x17)
+#define WSA884X_MISC1 (WSA884X_ANA_BG_TSADC_BASE + 0x18)
+#define WSA884X_MISC2 (WSA884X_ANA_BG_TSADC_BASE + 0x19)
+#define WSA884X_MISC3 (WSA884X_ANA_BG_TSADC_BASE + 0x1a)
+#define WSA884X_SPARE_TSBG_0 (WSA884X_ANA_BG_TSADC_BASE + 0x1b)
+#define WSA884X_SPARE_TUNE_0 (WSA884X_ANA_BG_TSADC_BASE + 0x1c)
+#define WSA884X_SPARE_TUNE_1 (WSA884X_ANA_BG_TSADC_BASE + 0x1d)
+
+#define WSA884X_ANA_IVSENSE_BASE (WSA884X_BASE + 0x0020)
+#define WSA884X_VSENSE1 (WSA884X_ANA_IVSENSE_BASE + 0x00)
+#define WSA884X_VSENSE1_GAIN_VSENSE_FE_MASK 0xe0
+#define WSA884X_VSENSE1_GAIN_VSENSE_FE_SHIFT 5
+#define WSA884X_ISENSE2 (WSA884X_ANA_IVSENSE_BASE + 0x01)
+#define WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK 0xe0
+#define WSA884X_ISENSE2_ISENSE_GAIN_CTL_SHIFT 5
+
+#define WSA884X_SPARE_CTL_1 (WSA884X_ANA_IVSENSE_BASE + 0x02)
+#define WSA884X_SPARE_CTL_2 (WSA884X_ANA_IVSENSE_BASE + 0x03)
+#define WSA884X_SPARE_CTL_3 (WSA884X_ANA_IVSENSE_BASE + 0x04)
+#define WSA884X_SPARE_CTL_4 (WSA884X_ANA_IVSENSE_BASE + 0x05)
+#define WSA884X_EN (WSA884X_ANA_IVSENSE_BASE + 0x06)
+#define WSA884X_OVERRIDE1 (WSA884X_ANA_IVSENSE_BASE + 0x07)
+#define WSA884X_OVERRIDE2 (WSA884X_ANA_IVSENSE_BASE + 0x08)
+#define WSA884X_ISENSE1 (WSA884X_ANA_IVSENSE_BASE + 0x09)
+#define WSA884X_ISENSE_CAL (WSA884X_ANA_IVSENSE_BASE + 0x0a)
+#define WSA884X_MISC (WSA884X_ANA_IVSENSE_BASE + 0x0b)
+#define WSA884X_ADC_0 (WSA884X_ANA_IVSENSE_BASE + 0x0c)
+#define WSA884X_ADC_1 (WSA884X_ANA_IVSENSE_BASE + 0x0d)
+#define WSA884X_ADC_2 (WSA884X_ANA_IVSENSE_BASE + 0x0e)
+#define WSA884X_ADC_3 (WSA884X_ANA_IVSENSE_BASE + 0x0f)
+#define WSA884X_ADC_4 (WSA884X_ANA_IVSENSE_BASE + 0x10)
+#define WSA884X_ADC_5 (WSA884X_ANA_IVSENSE_BASE + 0x11)
+#define WSA884X_ADC_6 (WSA884X_ANA_IVSENSE_BASE + 0x12)
+#define WSA884X_ADC_7 (WSA884X_ANA_IVSENSE_BASE + 0x13)
+#define WSA884X_STATUS (WSA884X_ANA_IVSENSE_BASE + 0x14)
+#define WSA884X_IVSENSE_SPARE_TUNE_1 (WSA884X_ANA_IVSENSE_BASE + 0x15)
+#define WSA884X_SPARE_TUNE_2 (WSA884X_ANA_IVSENSE_BASE + 0x16)
+#define WSA884X_SPARE_TUNE_3 (WSA884X_ANA_IVSENSE_BASE + 0x17)
+#define WSA884X_SPARE_TUNE_4 (WSA884X_ANA_IVSENSE_BASE + 0x18)
+
+#define WSA884X_ANA_SPK_TOP_BASE (WSA884X_BASE + 0x0040)
+#define WSA884X_TOP_CTRL1 (WSA884X_ANA_SPK_TOP_BASE + 0x00)
+#define WSA884X_TOP_CTRL1_OCP_LOWVBAT_ITH_EN_MASK 0x01
+#define WSA884X_CLIP_DET_CTRL1 (WSA884X_ANA_SPK_TOP_BASE + 0x01)
+#define WSA884X_CLIP_DET_CTRL2 (WSA884X_ANA_SPK_TOP_BASE + 0x02)
+#define WSA884X_DAC_CTRL1 (WSA884X_ANA_SPK_TOP_BASE + 0x03)
+#define WSA884X_DAC_VCM_CTRL_REG1 (WSA884X_ANA_SPK_TOP_BASE + 0x04)
+#define WSA884X_DAC_VCM_CTRL_REG2 (WSA884X_ANA_SPK_TOP_BASE + 0x05)
+#define WSA884X_DAC_VCM_CTRL_REG3 (WSA884X_ANA_SPK_TOP_BASE + 0x06)
+#define WSA884X_DAC_VCM_CTRL_REG4 (WSA884X_ANA_SPK_TOP_BASE + 0x07)
+#define WSA884X_DAC_VCM_CTRL_REG5 (WSA884X_ANA_SPK_TOP_BASE + 0x08)
+#define WSA884X_DAC_VCM_CTRL_REG6 (WSA884X_ANA_SPK_TOP_BASE + 0x09)
+#define WSA884X_PWM_CLK_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0a)
+#define WSA884X_PWM_CLK_CTL_VCMO_INT1_IDLE_MODE_OVRT_MASK 0x80
+#define WSA884X_PWM_CLK_CTL_VCMO_INT1_IDLE_MODE_OVRT_SHIFT 7
+#define WSA884X_PWM_CLK_CTL_REG_MCLK_DIV_RATIO_MASK 0x40
+#define WSA884X_PWM_CLK_CTL_REG_MCLK_DIV_RATIO_SHIFT 6
+#define WSA884X_PWM_CLK_CTL_PWM_DEGLITCH_CLK_DELAY_CTRL_MASK 0x30
+#define WSA884X_PWM_CLK_CTL_PWM_DEGLITCH_CLK_DELAY_CTRL_SHIFT 4
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_FREQ_SEL_MASK 0x08
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_FREQ_SEL_SHIFT 3
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_RATIO_MASK 0x06
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_RATIO_SHIFT 1
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_BYPASS_MASK 0x01
+#define WSA884X_PWM_CLK_CTL_PWM_CLK_DIV_BYPASS_SHIFT 0
+#define WSA884X_DRV_LF_LDO_SEL (WSA884X_ANA_SPK_TOP_BASE + 0x0b)
+#define WSA884X_OCP_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0c)
+#define WSA884X_PDRV_HS_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0d)
+#define WSA884X_PDRV_LS_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x0e)
+#define WSA884X_SPK_TOP_SPARE_CTL_1 (WSA884X_ANA_SPK_TOP_BASE + 0x0f)
+#define WSA884X_SPK_TOP_SPARE_CTL_2 (WSA884X_ANA_SPK_TOP_BASE + 0x10)
+#define WSA884X_SPK_TOP_SPARE_CTL_3 (WSA884X_ANA_SPK_TOP_BASE + 0x11)
+#define WSA884X_SPK_TOP_SPARE_CTL_4 (WSA884X_ANA_SPK_TOP_BASE + 0x12)
+#define WSA884X_SPARE_CTL_5 (WSA884X_ANA_SPK_TOP_BASE + 0x13)
+#define WSA884X_DAC_EN_DEBUG_REG (WSA884X_ANA_SPK_TOP_BASE + 0x14)
+#define WSA884X_DAC_OPAMP_BIAS1_REG (WSA884X_ANA_SPK_TOP_BASE + 0x15)
+#define WSA884X_DAC_OPAMP_BIAS2_REG (WSA884X_ANA_SPK_TOP_BASE + 0x16)
+#define WSA884X_DAC_TUNE1 (WSA884X_ANA_SPK_TOP_BASE + 0x17)
+#define WSA884X_DAC_VOLTAGE_CTRL_REG (WSA884X_ANA_SPK_TOP_BASE + 0x18)
+#define WSA884X_ATEST1_REG (WSA884X_ANA_SPK_TOP_BASE + 0x19)
+#define WSA884X_ATEST2_REG (WSA884X_ANA_SPK_TOP_BASE + 0x1a)
+#define WSA884X_TOP_BIAS_REG1 (WSA884X_ANA_SPK_TOP_BASE + 0x1b)
+#define WSA884X_TOP_BIAS_REG2 (WSA884X_ANA_SPK_TOP_BASE + 0x1c)
+#define WSA884X_TOP_BIAS_REG3 (WSA884X_ANA_SPK_TOP_BASE + 0x1d)
+#define WSA884X_TOP_BIAS_REG4 (WSA884X_ANA_SPK_TOP_BASE + 0x1e)
+#define WSA884X_PWRSTG_DBG2 (WSA884X_ANA_SPK_TOP_BASE + 0x1f)
+#define WSA884X_DRV_LF_BLK_EN (WSA884X_ANA_SPK_TOP_BASE + 0x20)
+#define WSA884X_DRV_LF_EN (WSA884X_ANA_SPK_TOP_BASE + 0x21)
+#define WSA884X_DRV_LF_MASK_DCC_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x22)
+#define WSA884X_DRV_LF_MISC_CTL1 (WSA884X_ANA_SPK_TOP_BASE + 0x23)
+#define WSA884X_DRV_LF_REG_GAIN (WSA884X_ANA_SPK_TOP_BASE + 0x24)
+#define WSA884X_DRV_OS_CAL_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x25)
+#define WSA884X_DRV_OS_CAL_CTL1 (WSA884X_ANA_SPK_TOP_BASE + 0x26)
+#define WSA884X_PWRSTG_DBG (WSA884X_ANA_SPK_TOP_BASE + 0x27)
+#define WSA884X_BBM_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x28)
+#define WSA884X_TOP_MISC1 (WSA884X_ANA_SPK_TOP_BASE + 0x29)
+#define WSA884X_DAC_VCM_CTRL_REG7 (WSA884X_ANA_SPK_TOP_BASE + 0x2a)
+#define WSA884X_TOP_BIAS_REG5 (WSA884X_ANA_SPK_TOP_BASE + 0x2b)
+#define WSA884X_DRV_LF_MISC_CTL2 (WSA884X_ANA_SPK_TOP_BASE + 0x2c)
+#define WSA884X_SPK_TOP_SPARE_TUNE_2 (WSA884X_ANA_SPK_TOP_BASE + 0x2d)
+#define WSA884X_SPK_TOP_SPARE_TUNE_3 (WSA884X_ANA_SPK_TOP_BASE + 0x2e)
+#define WSA884X_SPK_TOP_SPARE_TUNE_4 (WSA884X_ANA_SPK_TOP_BASE + 0x2f)
+#define WSA884X_SPARE_TUNE_5 (WSA884X_ANA_SPK_TOP_BASE + 0x30)
+#define WSA884X_SPARE_TUNE_6 (WSA884X_ANA_SPK_TOP_BASE + 0x31)
+#define WSA884X_SPARE_TUNE_7 (WSA884X_ANA_SPK_TOP_BASE + 0x32)
+#define WSA884X_SPARE_TUNE_8 (WSA884X_ANA_SPK_TOP_BASE + 0x33)
+#define WSA884X_SPARE_TUNE_9 (WSA884X_ANA_SPK_TOP_BASE + 0x34)
+#define WSA884X_SPARE_TUNE_10 (WSA884X_ANA_SPK_TOP_BASE + 0x35)
+#define WSA884X_PA_STATUS0 (WSA884X_ANA_SPK_TOP_BASE + 0x36)
+#define WSA884X_PA_STATUS1 (WSA884X_ANA_SPK_TOP_BASE + 0x37)
+#define WSA884X_PA_STATUS2 (WSA884X_ANA_SPK_TOP_BASE + 0x38)
+#define WSA884X_PA_STATUS3 (WSA884X_ANA_SPK_TOP_BASE + 0x39)
+#define WSA884X_PA_STATUS4 (WSA884X_ANA_SPK_TOP_BASE + 0x3a)
+#define WSA884X_PA_STATUS5 (WSA884X_ANA_SPK_TOP_BASE + 0x3b)
+#define WSA884X_SPARE_RO_1 (WSA884X_ANA_SPK_TOP_BASE + 0x3c)
+#define WSA884X_SPARE_RO_2 (WSA884X_ANA_SPK_TOP_BASE + 0x3d)
+#define WSA884X_SPARE_RO_3 (WSA884X_ANA_SPK_TOP_BASE + 0x3e)
+
+#define WSA884X_ANA_BOOST_BASE (WSA884X_BASE + 0x0090)
+#define WSA884X_STB_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x00)
+#define WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_MASK 0xf8
+#define WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_SHIFT 3
+#define WSA884X_STB_CTRL1_VOUT_FS_MASK 0x07
+#define WSA884X_STB_CTRL1_VOUT_FS_SHIFT 0
+#define WSA884X_CURRENT_LIMIT (WSA884X_ANA_BOOST_BASE + 0x01)
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_OVRD_EN_MASK 0x80
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_OVRD_EN_SHIFT 7
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK 0x7c
+#define WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_SHIFT 2
+#define WSA884X_CURRENT_LIMIT_CLK_PHASE_SHIFT 0
+#define WSA884X_BYP_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x02)
+#define WSA884X_SPARE_CTL_0 (WSA884X_ANA_BOOST_BASE + 0x03)
+#define WSA884X_BOOST_SPARE_CTL_1 (WSA884X_ANA_BOOST_BASE + 0x04)
+#define WSA884X_SPARE_RO_0 (WSA884X_ANA_BOOST_BASE + 0x05)
+#define WSA884X_BOOST_SPARE_RO_1 (WSA884X_ANA_BOOST_BASE + 0x06)
+#define WSA884X_IBIAS1 (WSA884X_ANA_BOOST_BASE + 0x07)
+#define WSA884X_IBIAS2 (WSA884X_ANA_BOOST_BASE + 0x08)
+#define WSA884X_IBIAS3 (WSA884X_ANA_BOOST_BASE + 0x09)
+#define WSA884X_EN_CTRL (WSA884X_ANA_BOOST_BASE + 0x0a)
+#define WSA884X_STB_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x0b)
+#define WSA884X_STB_CTRL3 (WSA884X_ANA_BOOST_BASE + 0x0c)
+#define WSA884X_STB_CTRL4 (WSA884X_ANA_BOOST_BASE + 0x0d)
+#define WSA884X_BYP_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x0e)
+#define WSA884X_BYP_CTRL3 (WSA884X_ANA_BOOST_BASE + 0x0f)
+#define WSA884X_ZX_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x10)
+#define WSA884X_ZX_CTRL1_ZX_DET_EN_MASK 0x80
+#define WSA884X_ZX_CTRL1_ZX_DET_EN_SHIFT 7
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_EN_MASK 0x40
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_EN_SHIFT 6
+#define WSA884X_ZX_CTRL1_ZX_DET_STAGE_DEFAULT_MASK 0x20
+#define WSA884X_ZX_CTRL1_ZX_DET_STAGE_DEFAULT_SHIFT 5
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_MASK 0x18
+#define WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_SHIFT 3
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_IGNORE_MASK 0x04
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_IGNORE_SHIFT 2
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_DEL_MASK 0x02
+#define WSA884X_ZX_CTRL1_ZX_BYP_MASK_DEL_SHIFT 1
+#define WSA884X_ZX_CTRL1_BOOTCAP_REFRESH_DIS_MASK 0x01
+#define WSA884X_ZX_CTRL1_BOOTCAP_REFRESH_DIS_SHIFT 0
+#define WSA884X_ZX_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x11)
+#define WSA884X_BLEEDER_CTRL (WSA884X_ANA_BOOST_BASE + 0x12)
+#define WSA884X_BOOST_MISC (WSA884X_ANA_BOOST_BASE + 0x13)
+#define WSA884X_PWRSTAGE_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x14)
+#define WSA884X_PWRSTAGE_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x15)
+#define WSA884X_PWRSTAGE_CTRL3 (WSA884X_ANA_BOOST_BASE + 0x16)
+#define WSA884X_PWRSTAGE_CTRL4 (WSA884X_ANA_BOOST_BASE + 0x17)
+#define WSA884X_MAXD_REG1 (WSA884X_ANA_BOOST_BASE + 0x18)
+#define WSA884X_MAXD_REG2 (WSA884X_ANA_BOOST_BASE + 0x19)
+#define WSA884X_ILIM_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x1a)
+#define WSA884X_ILIM_CTRL1_EN_AUTO_MAXD_SEL_MASK 0x80
+#define WSA884X_ILIM_CTRL1_EN_AUTO_MAXD_SEL_SHIFT 0x07
+#define WSA884X_ILIM_CTRL1_EN_ILIM_SW_CLH_MASK 0x40
+#define WSA884X_ILIM_CTRL1_EN_ILIM_SW_CLH_SHIFT 0x06
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_CLH_MASK 0x38
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_CLH_SHIFT 0x03
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_MASK 0x07
+#define WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_SHIFT 0x00
+#define WSA884X_ILIM_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x1b)
+#define WSA884X_TEST_CTRL1 (WSA884X_ANA_BOOST_BASE + 0x1c)
+#define WSA884X_TEST_CTRL2 (WSA884X_ANA_BOOST_BASE + 0x1d)
+#define WSA884X_SPARE1 (WSA884X_ANA_BOOST_BASE + 0x1e)
+#define WSA884X_BOOT_CAP_CHECK (WSA884X_ANA_BOOST_BASE + 0x1f)
+
+#define WSA884X_ANA_PON_LDOL_BASE (WSA884X_BASE + 0x00b0)
+#define WSA884X_PON_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x00)
+#define WSA884X_PWRSAV_CTL (WSA884X_ANA_PON_LDOL_BASE + 0x01)
+#define WSA884X_PON_LDOL_SPARE_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x02)
+#define WSA884X_PON_LDOL_SPARE_CTL_1 (WSA884X_ANA_PON_LDOL_BASE + 0x03)
+#define WSA884X_PON_LDOL_SPARE_CTL_2 (WSA884X_ANA_PON_LDOL_BASE + 0x04)
+#define WSA884X_PON_LDOL_SPARE_CTL_3 (WSA884X_ANA_PON_LDOL_BASE + 0x05)
+#define WSA884X_PON_CLT_1 (WSA884X_ANA_PON_LDOL_BASE + 0x06)
+#define WSA884X_PON_CTL_2 (WSA884X_ANA_PON_LDOL_BASE + 0x07)
+#define WSA884X_PON_CTL_3 (WSA884X_ANA_PON_LDOL_BASE + 0x08)
+#define WSA884X_CKWD_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x09)
+#define WSA884X_CKWD_CTL_1 (WSA884X_ANA_PON_LDOL_BASE + 0x0a)
+#define WSA884X_CKWD_CTL_1_VPP_SW_CTL_MASK 0x20
+#define WSA884X_CKWD_CTL_1_VPP_SW_CTL_SHIFT 5
+#define WSA884X_CKWD_CTL_1_CKWD_VCOMP_VREF_SEL_MASK 0x1f
+#define WSA884X_CKWD_CTL_1_CKWD_VCOMP_VREF_SEL_SHIFT 0
+#define WSA884X_CKWD_CTL_2 (WSA884X_ANA_PON_LDOL_BASE + 0x0b)
+#define WSA884X_CKSK_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x0c)
+#define WSA884X_PADSW_CTL_0 (WSA884X_ANA_PON_LDOL_BASE + 0x0d)
+#define WSA884X_TEST_0 (WSA884X_ANA_PON_LDOL_BASE + 0x0e)
+#define WSA884X_TEST_1 (WSA884X_ANA_PON_LDOL_BASE + 0x0f)
+#define WSA884X_STATUS_0 (WSA884X_ANA_PON_LDOL_BASE + 0x10)
+#define WSA884X_STATUS_1 (WSA884X_ANA_PON_LDOL_BASE + 0x11)
+#define WSA884X_PON_LDOL_SPARE_TUNE_0 (WSA884X_ANA_PON_LDOL_BASE + 0x12)
+#define WSA884X_PON_LDOL_SPARE_TUNE_1 (WSA884X_ANA_PON_LDOL_BASE + 0x13)
+#define WSA884X_PON_LDOL_SPARE_TUNE_2 (WSA884X_ANA_PON_LDOL_BASE + 0x14)
+#define WSA884X_PON_LDOL_SPARE_TUNE_3 (WSA884X_ANA_PON_LDOL_BASE + 0x15)
+#define WSA884X_PON_LDOL_SPARE_TUNE_4 (WSA884X_ANA_PON_LDOL_BASE + 0x16)
+
+#define WSA884X_DIG_CTRL0_BASE (WSA884X_BASE + 0x0400)
+#define WSA884X_DIG_CTRL0_PAGE (WSA884X_DIG_CTRL0_BASE + 0x00)
+#define WSA884X_CHIP_ID0 (WSA884X_DIG_CTRL0_BASE + 0x01)
+#define WSA884X_CHIP_ID1 (WSA884X_DIG_CTRL0_BASE + 0x02)
+#define WSA884X_CHIP_ID2 (WSA884X_DIG_CTRL0_BASE + 0x03)
+#define WSA884X_CHIP_ID3 (WSA884X_DIG_CTRL0_BASE + 0x04)
+#define WSA884X_BUS_ID (WSA884X_DIG_CTRL0_BASE + 0x05)
+#define WSA884X_CDC_RST_CTL (WSA884X_DIG_CTRL0_BASE + 0x10)
+#define WSA884X_SWR_RESET_EN (WSA884X_DIG_CTRL0_BASE + 0x14)
+#define WSA884X_TOP_CLK_CFG (WSA884X_DIG_CTRL0_BASE + 0x18)
+#define WSA884X_SWR_CLK_RATE (WSA884X_DIG_CTRL0_BASE + 0x19)
+#define WSA884X_CDC_PATH_MODE (WSA884X_DIG_CTRL0_BASE + 0x1a)
+#define WSA884X_CDC_PATH_MODE_RXD_MODE_MASK 0x02
+#define WSA884X_CDC_PATH_MODE_RXD_MODE_SHIFT 0
+#define WSA884X_CDC_PATH_MODE_TXD_MODE_MASK 0x01
+#define WSA884X_CDC_PATH_MODE_TXD_MODE_SHIFT 0
+#define WSA884X_CDC_CLK_CTL (WSA884X_DIG_CTRL0_BASE + 0x1c)
+#define WSA884X_PA_FSM_EN (WSA884X_DIG_CTRL0_BASE + 0x30)
+#define WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK 0x01
+#define WSA884X_PA_FSM_EN_GLOBAL_PA_EN_SHIFT 0
+#define WSA884X_PA_FSM_CTL0 (WSA884X_DIG_CTRL0_BASE + 0x31)
+#define WSA884X_PA_FSM_CTL1 (WSA884X_DIG_CTRL0_BASE + 0x32)
+#define WSA884X_PA_FSM_CTL1_NOISE_GATE_BLOCK_MASK 0x38
+#define WSA884X_PA_FSM_TIMER0 (WSA884X_DIG_CTRL0_BASE + 0x33)
+#define WSA884X_PA_FSM_TIMER1 (WSA884X_DIG_CTRL0_BASE + 0x34)
+#define WSA884X_PA_FSM_STA0 (WSA884X_DIG_CTRL0_BASE + 0x35)
+#define WSA884X_PA_FSM_STA1 (WSA884X_DIG_CTRL0_BASE + 0x36)
+#define WSA884X_PA_FSM_ERR_CTL (WSA884X_DIG_CTRL0_BASE + 0x37)
+#define WSA884X_PA_FSM_ERR_COND0 (WSA884X_DIG_CTRL0_BASE + 0x38)
+#define WSA884X_PA_FSM_ERR_COND1 (WSA884X_DIG_CTRL0_BASE + 0x39)
+#define WSA884X_PA_FSM_MSK0 (WSA884X_DIG_CTRL0_BASE + 0x3a)
+#define WSA884X_PA_FSM_MSK1 (WSA884X_DIG_CTRL0_BASE + 0x3b)
+#define WSA884X_PA_FSM_BYP_CTL (WSA884X_DIG_CTRL0_BASE + 0x3c)
+#define WSA884X_PA_FSM_BYP0 (WSA884X_DIG_CTRL0_BASE + 0x3d)
+#define WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK 0x01
+#define WSA884X_PA_FSM_BYP0_DC_CAL_EN_SHIFT 0
+#define WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK 0x02
+#define WSA884X_PA_FSM_BYP0_CLK_WD_EN_SHIFT 1
+#define WSA884X_PA_FSM_BYP0_BG_EN_MASK 0x04
+#define WSA884X_PA_FSM_BYP0_BG_EN_SHIFT 2
+#define WSA884X_PA_FSM_BYP0_BOOST_EN_MASK 0x08
+#define WSA884X_PA_FSM_BYP0_BOOST_EN_SHIFT 3
+#define WSA884X_PA_FSM_BYP0_PA_EN_MASK 0x10
+#define WSA884X_PA_FSM_BYP0_PA_EN_SHIFT 4
+#define WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK 0x20
+#define WSA884X_PA_FSM_BYP0_D_UNMUTE_SHIFT 5
+#define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK 0x40
+#define WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_SHIFT 6
+#define WSA884X_PA_FSM_BYP0_TSADC_EN_MASK 0x80
+#define WSA884X_PA_FSM_BYP0_TSADC_EN_SHIFT 7
+#define WSA884X_PA_FSM_BYP1 (WSA884X_DIG_CTRL0_BASE + 0x3e)
+#define WSA884X_TADC_VALUE_CTL (WSA884X_DIG_CTRL0_BASE + 0x50)
+#define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK 0x01
+#define WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_SHIFT 0
+#define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_MASK 0x02
+#define WSA884X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_SHIFT 1
+#define WSA884X_TEMP_DETECT_CTL (WSA884X_DIG_CTRL0_BASE + 0x51)
+#define WSA884X_TEMP_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x52)
+#define WSA884X_TEMP_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x53)
+#define WSA884X_TEMP_DOUT_MSB (WSA884X_DIG_CTRL0_BASE + 0x54)
+#define WSA884X_TEMP_DOUT_LSB (WSA884X_DIG_CTRL0_BASE + 0x55)
+#define WSA884X_TEMP_CONFIG0 (WSA884X_DIG_CTRL0_BASE + 0x56)
+#define WSA884X_TEMP_CONFIG1 (WSA884X_DIG_CTRL0_BASE + 0x57)
+#define WSA884X_VBAT_THRM_FLT_CTL (WSA884X_DIG_CTRL0_BASE + 0x58)
+#define WSA884X_VBAT_THRM_FLT_CTL_THRM_COEF_SEL_MASK 0xe0
+#define WSA884X_VBAT_THRM_FLT_CTL_THRM_COEF_SEL_SHIFT 5
+#define WSA884X_VBAT_THRM_FLT_CTL_THRM_FLT_EN_SHIFT 4
+#define WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_MASK 0x0e
+#define WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_SHIFT 1
+#define WSA884X_VBAT_THRM_FLT_CTL_VBAT_FLT_EN_SHIFT 0
+#define WSA884X_VBAT_CAL_CTL (WSA884X_DIG_CTRL0_BASE + 0x59)
+#define WSA884X_VBAT_CAL_CTL_RESERVE_MASK 0x0e
+#define WSA884X_VBAT_CAL_CTL_VBAT_CAL_EN_MASK 0x01
+#define WSA884X_VBAT_DIN_MSB (WSA884X_DIG_CTRL0_BASE + 0x5a)
+#define WSA884X_VBAT_DIN_LSB (WSA884X_DIG_CTRL0_BASE + 0x5b)
+#define WSA884X_VBAT_DOUT_MSB (WSA884X_DIG_CTRL0_BASE + 0x5c)
+#define WSA884X_VBAT_DOUT_LSB (WSA884X_DIG_CTRL0_BASE + 0x5d)
+#define WSA884X_VBAT_CAL_MSB (WSA884X_DIG_CTRL0_BASE + 0x5e)
+#define WSA884X_VBAT_CAL_LSB (WSA884X_DIG_CTRL0_BASE + 0x5f)
+#define WSA884X_UVLO_DEGLITCH_CTL (WSA884X_DIG_CTRL0_BASE + 0x60)
+#define WSA884X_BOP_DEGLITCH_CTL (WSA884X_DIG_CTRL0_BASE + 0x61)
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_SETTING_MASK 0x1e
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_SETTING_SHIFT 1
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_EN_MASK 0x1
+#define WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_EN_SHIFT 0
+#define WSA884X_VBAT_ZONE_DETC_CTL (WSA884X_DIG_CTRL0_BASE + 0x64)
+#define WSA884X_CPS_CTL (WSA884X_DIG_CTRL0_BASE + 0x68)
+#define WSA884X_CDC_RX_CTL (WSA884X_DIG_CTRL0_BASE + 0x70)
+#define WSA884X_CDC_SPK_DSM_A1_0 (WSA884X_DIG_CTRL0_BASE + 0x71)
+#define WSA884X_CDC_SPK_DSM_A1_1 (WSA884X_DIG_CTRL0_BASE + 0x72)
+#define WSA884X_CDC_SPK_DSM_A2_0 (WSA884X_DIG_CTRL0_BASE + 0x73)
+#define WSA884X_CDC_SPK_DSM_A2_1 (WSA884X_DIG_CTRL0_BASE + 0x74)
+#define WSA884X_CDC_SPK_DSM_A3_0 (WSA884X_DIG_CTRL0_BASE + 0x75)
+#define WSA884X_CDC_SPK_DSM_A3_1 (WSA884X_DIG_CTRL0_BASE + 0x76)
+#define WSA884X_CDC_SPK_DSM_A4_0 (WSA884X_DIG_CTRL0_BASE + 0x77)
+#define WSA884X_CDC_SPK_DSM_A4_1 (WSA884X_DIG_CTRL0_BASE + 0x78)
+#define WSA884X_CDC_SPK_DSM_A5_0 (WSA884X_DIG_CTRL0_BASE + 0x79)
+#define WSA884X_CDC_SPK_DSM_A5_1 (WSA884X_DIG_CTRL0_BASE + 0x7a)
+#define WSA884X_CDC_SPK_DSM_A6_0 (WSA884X_DIG_CTRL0_BASE + 0x7b)
+#define WSA884X_CDC_SPK_DSM_A7_0 (WSA884X_DIG_CTRL0_BASE + 0x7c)
+#define WSA884X_CDC_SPK_DSM_C_0 (WSA884X_DIG_CTRL0_BASE + 0x7d)
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C3_MASK 0xf0
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C3_SHIFT 4
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C2_MASK 0x0f
+#define WSA884X_CDC_SPK_DSM_C_0_COEF_C2_SHIFT 0
+#define WSA884X_CDC_SPK_DSM_C_1 (WSA884X_DIG_CTRL0_BASE + 0x7e)
+#define WSA884X_CDC_SPK_DSM_C_2 (WSA884X_DIG_CTRL0_BASE + 0x7f)
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C7_MASK 0xf0
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C7_SHIFT 4
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C6_MASK 0x0f
+#define WSA884X_CDC_SPK_DSM_C_2_COEF_C6_SHIFT 0
+#define WSA884X_CDC_SPK_DSM_C_3 (WSA884X_DIG_CTRL0_BASE + 0x80)
+#define WSA884X_CDC_SPK_DSM_C_3_COEF_C7_MASK 0x3f
+#define WSA884X_CDC_SPK_DSM_C_3_COEF_C7_SHIFT 0
+#define WSA884X_CDC_SPK_DSM_R1 (WSA884X_DIG_CTRL0_BASE + 0x81)
+#define WSA884X_CDC_SPK_DSM_R2 (WSA884X_DIG_CTRL0_BASE + 0x82)
+#define WSA884X_CDC_SPK_DSM_R3 (WSA884X_DIG_CTRL0_BASE + 0x83)
+#define WSA884X_CDC_SPK_DSM_R4 (WSA884X_DIG_CTRL0_BASE + 0x84)
+#define WSA884X_CDC_SPK_DSM_R5 (WSA884X_DIG_CTRL0_BASE + 0x85)
+#define WSA884X_CDC_SPK_DSM_R6 (WSA884X_DIG_CTRL0_BASE + 0x86)
+#define WSA884X_CDC_SPK_DSM_R7 (WSA884X_DIG_CTRL0_BASE + 0x87)
+#define WSA884X_CDC_SPK_GAIN_PDM_0 (WSA884X_DIG_CTRL0_BASE + 0x88)
+#define WSA884X_CDC_SPK_GAIN_PDM_1 (WSA884X_DIG_CTRL0_BASE + 0x89)
+#define WSA884X_CDC_SPK_GAIN_PDM_2 (WSA884X_DIG_CTRL0_BASE + 0x8a)
+#define WSA884X_PDM_WD_CTL (WSA884X_DIG_CTRL0_BASE + 0x8b)
+#define WSA884X_PDM_WD_CTL_HOLD_OFF_MASK 0x04
+#define WSA884X_PDM_WD_CTL_HOLD_OFF_SHIFT 2
+#define WSA884X_PDM_WD_CTL_TIME_OUT_SEL_MASK 0x02
+#define WSA884X_PDM_WD_CTL_TIME_OUT_SEL_SHIFT 1
+#define WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK 0x01
+#define WSA884X_PDM_WD_CTL_PDM_WD_EN_SHIFT 0
+#define WSA884X_DEM_BYPASS_DATA0 (WSA884X_DIG_CTRL0_BASE + 0x90)
+#define WSA884X_DEM_BYPASS_DATA1 (WSA884X_DIG_CTRL0_BASE + 0x91)
+#define WSA884X_DEM_BYPASS_DATA2 (WSA884X_DIG_CTRL0_BASE + 0x92)
+#define WSA884X_DEM_BYPASS_DATA3 (WSA884X_DIG_CTRL0_BASE + 0x93)
+#define WSA884X_DRE_CTL_0 (WSA884X_DIG_CTRL0_BASE + 0xb0)
+#define WSA884X_DRE_CTL_0_PROG_DELAY_MASK 0xf0
+#define WSA884X_DRE_CTL_0_PROG_DELAY_SHIFT 4
+#define WSA884X_DRE_CTL_0_OFFSET_MASK 0x07
+#define WSA884X_DRE_CTL_0_OFFSET_SHIFT 0
+#define WSA884X_DRE_CTL_1 (WSA884X_DIG_CTRL0_BASE + 0xb1)
+#define WSA884X_DRE_CTL_1_CSR_GAIN_MASK 0x3e
+#define WSA884X_DRE_CTL_1_CSR_GAIN_SHIFT 1
+#define WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK 0x01
+#define WSA884X_DRE_CTL_1_CSR_GAIN_EN_SHIFT 0
+#define WSA884X_DRE_IDLE_DET_CTL (WSA884X_DIG_CTRL0_BASE + 0xb2)
+#define WSA884X_GAIN_RAMPING_CTL (WSA884X_DIG_CTRL0_BASE + 0xb8)
+#define WSA884X_GAIN_RAMPING_MIN (WSA884X_DIG_CTRL0_BASE + 0xb9)
+#define WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_MASK 0x1f
+#define WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_SHIFT 0
+#define WSA884X_TAGC_CTL (WSA884X_DIG_CTRL0_BASE + 0xc0)
+#define WSA884X_TAGC_TIME (WSA884X_DIG_CTRL0_BASE + 0xc1)
+#define WSA884X_TAGC_FORCE_VAL (WSA884X_DIG_CTRL0_BASE + 0xc2)
+#define WSA884X_VAGC_CTL (WSA884X_DIG_CTRL0_BASE + 0xc8)
+#define WSA884X_VAGC_TIME (WSA884X_DIG_CTRL0_BASE + 0xc9)
+#define WSA884X_VAGC_ATTN_LVL_1 (WSA884X_DIG_CTRL0_BASE + 0xca)
+#define WSA884X_VAGC_ATTN_LVL_2 (WSA884X_DIG_CTRL0_BASE + 0xcb)
+#define WSA884X_VAGC_ATTN_LVL_3 (WSA884X_DIG_CTRL0_BASE + 0xcc)
+#define WSA884X_CLSH_CTL_0 (WSA884X_DIG_CTRL0_BASE + 0xd0)
+#define WSA884X_CLSH_CTL_0_CSR_GAIN_EN_SHIFT 7
+#define WSA884X_CLSH_CTL_0_DLY_CODE_MASK 0x70
+#define WSA884X_CLSH_CTL_0_DLY_CODE_SHIFT 4
+#define WSA884X_CLSH_CTL_0_DLY_RST_SHIFT 3
+#define WSA884X_CLSH_CTL_0_DLY_EN_SHIFT 2
+#define WSA884X_CLSH_CTL_0_INPUT_EN_SHIFT 1
+#define WSA884X_CLSH_CTL_0_CLSH_EN_SHIFT 0
+#define WSA884X_CLSH_CTL_1 (WSA884X_DIG_CTRL0_BASE + 0xd1)
+#define WSA884X_CLSH_V_HD_PA (WSA884X_DIG_CTRL0_BASE + 0xd2)
+#define WSA884X_CLSH_V_PA_MIN (WSA884X_DIG_CTRL0_BASE + 0xd3)
+#define WSA884X_CLSH_OVRD_VAL (WSA884X_DIG_CTRL0_BASE + 0xd4)
+#define WSA884X_CLSH_HARD_MAX (WSA884X_DIG_CTRL0_BASE + 0xd5)
+#define WSA884X_CLSH_SOFT_MAX (WSA884X_DIG_CTRL0_BASE + 0xd6)
+#define WSA884X_CLSH_SIG_DP (WSA884X_DIG_CTRL0_BASE + 0xd7)
+#define WSA884X_PBR_DELAY_CTL (WSA884X_DIG_CTRL0_BASE + 0xd8)
+#define WSA884X_CLSH_SRL_MAX_PBR (WSA884X_DIG_CTRL0_BASE + 0xe0)
+#define WSA884X_PBR_MAX_VOLTAGE 20
+#define WSA884X_PBR_MAX_CODE 255
+#define WSA884X_VTH_TO_REG(vth) \
+ ((vth) != 0 ? (((vth) - 150) * WSA884X_PBR_MAX_CODE / (WSA884X_PBR_MAX_VOLTAGE * 100) + 1) : 0)
+#define WSA884X_CLSH_VTH1 (WSA884X_DIG_CTRL0_BASE + 0xe1)
+#define WSA884X_CLSH_VTH2 (WSA884X_DIG_CTRL0_BASE + 0xe2)
+#define WSA884X_CLSH_VTH3 (WSA884X_DIG_CTRL0_BASE + 0xe3)
+#define WSA884X_CLSH_VTH4 (WSA884X_DIG_CTRL0_BASE + 0xe4)
+#define WSA884X_CLSH_VTH5 (WSA884X_DIG_CTRL0_BASE + 0xe5)
+#define WSA884X_CLSH_VTH6 (WSA884X_DIG_CTRL0_BASE + 0xe6)
+#define WSA884X_CLSH_VTH7 (WSA884X_DIG_CTRL0_BASE + 0xe7)
+#define WSA884X_CLSH_VTH8 (WSA884X_DIG_CTRL0_BASE + 0xe8)
+#define WSA884X_CLSH_VTH9 (WSA884X_DIG_CTRL0_BASE + 0xe9)
+#define WSA884X_CLSH_VTH10 (WSA884X_DIG_CTRL0_BASE + 0xea)
+#define WSA884X_CLSH_VTH11 (WSA884X_DIG_CTRL0_BASE + 0xeb)
+#define WSA884X_CLSH_VTH12 (WSA884X_DIG_CTRL0_BASE + 0xec)
+#define WSA884X_CLSH_VTH13 (WSA884X_DIG_CTRL0_BASE + 0xed)
+#define WSA884X_CLSH_VTH14 (WSA884X_DIG_CTRL0_BASE + 0xee)
+#define WSA884X_CLSH_VTH15 (WSA884X_DIG_CTRL0_BASE + 0xef)
+
+#define WSA884X_DIG_CTRL1_BASE (WSA884X_BASE + 0x0500)
+#define WSA884X_DIG_CTRL1_PAGE (WSA884X_DIG_CTRL1_BASE + 0x00)
+#define WSA884X_VPHX_SYS_EN_STATUS (WSA884X_DIG_CTRL1_BASE + 0x01)
+#define WSA884X_ANA_WO_CTL_0 (WSA884X_DIG_CTRL1_BASE + 0x04)
+#define WSA884X_ANA_WO_CTL_0_MODE_SHIFT 0
+#define WSA884X_ANA_WO_CTL_0_VPHX_SYS_EN_MASK 0xc0
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_DISABLE 0x0
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_18_DB 0xa
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_0_DB 0x7
+#define WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK 0x3c
+#define WSA884X_ANA_WO_CTL_0_PA_MIN_GAIN_BYP_MASK 0x02
+#define WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER 0x1
+#define WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK 0x01
+#define WSA884X_ANA_WO_CTL_1 (WSA884X_DIG_CTRL1_BASE + 0x05)
+#define WSA884X_PIN_CTL (WSA884X_DIG_CTRL1_BASE + 0x10)
+#define WSA884X_PIN_CTL_OE (WSA884X_DIG_CTRL1_BASE + 0x11)
+#define WSA884X_PIN_WDATA_IOPAD (WSA884X_DIG_CTRL1_BASE + 0x12)
+#define WSA884X_PIN_STATUS (WSA884X_DIG_CTRL1_BASE + 0x13)
+#define WSA884X_I2C_SLAVE_CTL (WSA884X_DIG_CTRL1_BASE + 0x14)
+#define WSA884X_SPMI_PAD_CTL0 (WSA884X_DIG_CTRL1_BASE + 0x15)
+#define WSA884X_SPMI_PAD_CTL1 (WSA884X_DIG_CTRL1_BASE + 0x16)
+#define WSA884X_SPMI_PAD_CTL2 (WSA884X_DIG_CTRL1_BASE + 0x17)
+#define WSA884X_MEM_CTL (WSA884X_DIG_CTRL1_BASE + 0x18)
+#define WSA884X_SWR_HM_TEST0 (WSA884X_DIG_CTRL1_BASE + 0x19)
+#define WSA884X_SWR_HM_TEST1 (WSA884X_DIG_CTRL1_BASE + 0x1a)
+#define WSA884X_OTP_CTRL0 (WSA884X_DIG_CTRL1_BASE + 0x30)
+#define WSA884X_OTP_CTRL1 (WSA884X_DIG_CTRL1_BASE + 0x31)
+#define WSA884X_OTP_CTRL2 (WSA884X_DIG_CTRL1_BASE + 0x32)
+#define WSA884X_OTP_STAT (WSA884X_DIG_CTRL1_BASE + 0x33)
+#define WSA884X_OTP_PRG_TCSP0 (WSA884X_DIG_CTRL1_BASE + 0x34)
+#define WSA884X_OTP_PRG_TCSP1 (WSA884X_DIG_CTRL1_BASE + 0x35)
+#define WSA884X_OTP_PRG_TPPS (WSA884X_DIG_CTRL1_BASE + 0x36)
+#define WSA884X_OTP_PRG_TVPS (WSA884X_DIG_CTRL1_BASE + 0x37)
+#define WSA884X_OTP_PRG_TVPH (WSA884X_DIG_CTRL1_BASE + 0x38)
+#define WSA884X_OTP_PRG_TPPR0 (WSA884X_DIG_CTRL1_BASE + 0x39)
+#define WSA884X_OTP_PRG_TPPR1 (WSA884X_DIG_CTRL1_BASE + 0x3a)
+#define WSA884X_OTP_PRG_TPPH (WSA884X_DIG_CTRL1_BASE + 0x3b)
+#define WSA884X_OTP_PRG_END (WSA884X_DIG_CTRL1_BASE + 0x3c)
+#define WSA884X_WAVG_PLAY (WSA884X_DIG_CTRL1_BASE + 0x40)
+#define WSA884X_WAVG_CTL (WSA884X_DIG_CTRL1_BASE + 0x41)
+#define WSA884X_WAVG_LRA_PER_0 (WSA884X_DIG_CTRL1_BASE + 0x43)
+#define WSA884X_WAVG_LRA_PER_1 (WSA884X_DIG_CTRL1_BASE + 0x44)
+#define WSA884X_WAVG_DELTA_THETA_0 (WSA884X_DIG_CTRL1_BASE + 0x45)
+#define WSA884X_WAVG_DELTA_THETA_1 (WSA884X_DIG_CTRL1_BASE + 0x46)
+#define WSA884X_WAVG_DIRECT_AMP_0 (WSA884X_DIG_CTRL1_BASE + 0x47)
+#define WSA884X_WAVG_DIRECT_AMP_1 (WSA884X_DIG_CTRL1_BASE + 0x48)
+#define WSA884X_WAVG_PTRN_AMP0_0 (WSA884X_DIG_CTRL1_BASE + 0x49)
+#define WSA884X_WAVG_PTRN_AMP0_1 (WSA884X_DIG_CTRL1_BASE + 0x4a)
+#define WSA884X_WAVG_PTRN_AMP1_0 (WSA884X_DIG_CTRL1_BASE + 0x4b)
+#define WSA884X_WAVG_PTRN_AMP1_1 (WSA884X_DIG_CTRL1_BASE + 0x4c)
+#define WSA884X_WAVG_PTRN_AMP2_0 (WSA884X_DIG_CTRL1_BASE + 0x4d)
+#define WSA884X_WAVG_PTRN_AMP2_1 (WSA884X_DIG_CTRL1_BASE + 0x4e)
+#define WSA884X_WAVG_PTRN_AMP3_0 (WSA884X_DIG_CTRL1_BASE + 0x4f)
+#define WSA884X_WAVG_PTRN_AMP3_1 (WSA884X_DIG_CTRL1_BASE + 0x50)
+#define WSA884X_WAVG_PTRN_AMP4_0 (WSA884X_DIG_CTRL1_BASE + 0x51)
+#define WSA884X_WAVG_PTRN_AMP4_1 (WSA884X_DIG_CTRL1_BASE + 0x52)
+#define WSA884X_WAVG_PTRN_AMP5_0 (WSA884X_DIG_CTRL1_BASE + 0x53)
+#define WSA884X_WAVG_PTRN_AMP5_1 (WSA884X_DIG_CTRL1_BASE + 0x54)
+#define WSA884X_WAVG_PTRN_AMP6_0 (WSA884X_DIG_CTRL1_BASE + 0x55)
+#define WSA884X_WAVG_PTRN_AMP6_1 (WSA884X_DIG_CTRL1_BASE + 0x56)
+#define WSA884X_WAVG_PTRN_AMP7_0 (WSA884X_DIG_CTRL1_BASE + 0x57)
+#define WSA884X_WAVG_PTRN_AMP7_1 (WSA884X_DIG_CTRL1_BASE + 0x58)
+#define WSA884X_WAVG_PER_0_1 (WSA884X_DIG_CTRL1_BASE + 0x59)
+#define WSA884X_WAVG_PER_2_3 (WSA884X_DIG_CTRL1_BASE + 0x5a)
+#define WSA884X_WAVG_PER_4_5 (WSA884X_DIG_CTRL1_BASE + 0x5b)
+#define WSA884X_WAVG_PER_6_7 (WSA884X_DIG_CTRL1_BASE + 0x5c)
+#define WSA884X_WAVG_STA (WSA884X_DIG_CTRL1_BASE + 0x5d)
+#define WSA884X_INTR_MODE (WSA884X_DIG_CTRL1_BASE + 0x80)
+#define WSA884X_INTR_MASK0 (WSA884X_DIG_CTRL1_BASE + 0x81)
+#define WSA884X_INTR_MASK1 (WSA884X_DIG_CTRL1_BASE + 0x82)
+#define WSA884X_INTR_STATUS0 (WSA884X_DIG_CTRL1_BASE + 0x83)
+#define WSA884X_INTR_STATUS1 (WSA884X_DIG_CTRL1_BASE + 0x84)
+#define WSA884X_INTR_CLEAR0 (WSA884X_DIG_CTRL1_BASE + 0x85)
+#define WSA884X_INTR_CLEAR1 (WSA884X_DIG_CTRL1_BASE + 0x86)
+#define WSA884X_INTR_LEVEL0 (WSA884X_DIG_CTRL1_BASE + 0x87)
+#define WSA884X_INTR_LEVEL1 (WSA884X_DIG_CTRL1_BASE + 0x88)
+#define WSA884X_INTR_SET0 (WSA884X_DIG_CTRL1_BASE + 0x89)
+#define WSA884X_INTR_SET1 (WSA884X_DIG_CTRL1_BASE + 0x8a)
+#define WSA884X_INTR_TEST0 (WSA884X_DIG_CTRL1_BASE + 0x8b)
+#define WSA884X_INTR_TEST1 (WSA884X_DIG_CTRL1_BASE + 0x8c)
+#define WSA884X_PDM_TEST_MODE (WSA884X_DIG_CTRL1_BASE + 0xc0)
+#define WSA884X_ATE_TEST_MODE (WSA884X_DIG_CTRL1_BASE + 0xc1)
+#define WSA884X_PA_FSM_DBG (WSA884X_DIG_CTRL1_BASE + 0xc2)
+#define WSA884X_DIG_DEBUG_MODE (WSA884X_DIG_CTRL1_BASE + 0xc3)
+#define WSA884X_DIG_DEBUG_SEL (WSA884X_DIG_CTRL1_BASE + 0xc4)
+#define WSA884X_DIG_DEBUG_EN (WSA884X_DIG_CTRL1_BASE + 0xc5)
+#define WSA884X_TADC_DETECT_DBG_CTL (WSA884X_DIG_CTRL1_BASE + 0xc9)
+#define WSA884X_TADC_DEBUG_MSB (WSA884X_DIG_CTRL1_BASE + 0xca)
+#define WSA884X_TADC_DEBUG_LSB (WSA884X_DIG_CTRL1_BASE + 0xcb)
+#define WSA884X_SAMPLE_EDGE_SEL (WSA884X_DIG_CTRL1_BASE + 0xcc)
+#define WSA884X_SWR_EDGE_SEL (WSA884X_DIG_CTRL1_BASE + 0xcd)
+#define WSA884X_TEST_MODE_CTL (WSA884X_DIG_CTRL1_BASE + 0xce)
+#define WSA884X_IOPAD_CTL (WSA884X_DIG_CTRL1_BASE + 0xcf)
+#define WSA884X_ANA_CSR_DBG_ADD (WSA884X_DIG_CTRL1_BASE + 0xd0)
+#define WSA884X_ANA_CSR_DBG_CTL (WSA884X_DIG_CTRL1_BASE + 0xd1)
+#define WSA884X_CLK_DBG_CTL (WSA884X_DIG_CTRL1_BASE + 0xd2)
+#define WSA884X_SPARE_R (WSA884X_DIG_CTRL1_BASE + 0xf0)
+#define WSA884X_SPARE_0 (WSA884X_DIG_CTRL1_BASE + 0xf1)
+#define WSA884X_SPARE_1 (WSA884X_DIG_CTRL1_BASE + 0xf2)
+#define WSA884X_SPARE_2 (WSA884X_DIG_CTRL1_BASE + 0xf3)
+#define WSA884X_SCODE (WSA884X_DIG_CTRL1_BASE + 0xff)
+
+#define WSA884X_DIG_TRIM_BASE (WSA884X_BASE + 0x0800)
+#define WSA884X_DIG_TRIM_PAGE (WSA884X_DIG_TRIM_BASE + 0x00)
+#define WSA884X_OTP_REG_0 (WSA884X_DIG_TRIM_BASE + 0x80)
+#define WSA884X_OTP_ID_WSA8840 0x0
+#define WSA884X_OTP_ID_WSA8845 0x5
+#define WSA884X_OTP_ID_WSA8845H 0xc
+#define WSA884X_OTP_REG_0_ID_MASK 0x0f
+#define WSA884X_OTP_REG_1 (WSA884X_DIG_TRIM_BASE + 0x81)
+#define WSA884X_OTP_REG_2 (WSA884X_DIG_TRIM_BASE + 0x82)
+#define WSA884X_OTP_REG_3 (WSA884X_DIG_TRIM_BASE + 0x83)
+#define WSA884X_OTP_REG_4 (WSA884X_DIG_TRIM_BASE + 0x84)
+#define WSA884X_OTP_REG_5 (WSA884X_DIG_TRIM_BASE + 0x85)
+#define WSA884X_OTP_REG_6 (WSA884X_DIG_TRIM_BASE + 0x86)
+#define WSA884X_OTP_REG_7 (WSA884X_DIG_TRIM_BASE + 0x87)
+#define WSA884X_OTP_REG_8 (WSA884X_DIG_TRIM_BASE + 0x88)
+#define WSA884X_OTP_REG_9 (WSA884X_DIG_TRIM_BASE + 0x89)
+#define WSA884X_OTP_REG_10 (WSA884X_DIG_TRIM_BASE + 0x8a)
+#define WSA884X_OTP_REG_11 (WSA884X_DIG_TRIM_BASE + 0x8b)
+#define WSA884X_OTP_REG_12 (WSA884X_DIG_TRIM_BASE + 0x8c)
+#define WSA884X_OTP_REG_13 (WSA884X_DIG_TRIM_BASE + 0x8d)
+#define WSA884X_OTP_REG_14 (WSA884X_DIG_TRIM_BASE + 0x8e)
+#define WSA884X_OTP_REG_15 (WSA884X_DIG_TRIM_BASE + 0x8f)
+#define WSA884X_OTP_REG_16 (WSA884X_DIG_TRIM_BASE + 0x90)
+#define WSA884X_OTP_REG_17 (WSA884X_DIG_TRIM_BASE + 0x91)
+#define WSA884X_OTP_REG_18 (WSA884X_DIG_TRIM_BASE + 0x92)
+#define WSA884X_OTP_REG_19 (WSA884X_DIG_TRIM_BASE + 0x93)
+#define WSA884X_OTP_REG_20 (WSA884X_DIG_TRIM_BASE + 0x94)
+#define WSA884X_OTP_REG_21 (WSA884X_DIG_TRIM_BASE + 0x95)
+#define WSA884X_OTP_REG_22 (WSA884X_DIG_TRIM_BASE + 0x96)
+#define WSA884X_OTP_REG_23 (WSA884X_DIG_TRIM_BASE + 0x97)
+#define WSA884X_OTP_REG_24 (WSA884X_DIG_TRIM_BASE + 0x98)
+#define WSA884X_OTP_REG_25 (WSA884X_DIG_TRIM_BASE + 0x99)
+#define WSA884X_OTP_REG_26 (WSA884X_DIG_TRIM_BASE + 0x9a)
+#define WSA884X_OTP_REG_27 (WSA884X_DIG_TRIM_BASE + 0x9b)
+#define WSA884X_OTP_REG_28 (WSA884X_DIG_TRIM_BASE + 0x9c)
+#define WSA884X_OTP_REG_29 (WSA884X_DIG_TRIM_BASE + 0x9d)
+#define WSA884X_OTP_REG_30 (WSA884X_DIG_TRIM_BASE + 0x9e)
+#define WSA884X_OTP_REG_31 (WSA884X_DIG_TRIM_BASE + 0x9f)
+#define WSA884X_OTP_REG_32 (WSA884X_DIG_TRIM_BASE + 0xa0)
+#define WSA884X_OTP_REG_33 (WSA884X_DIG_TRIM_BASE + 0xa1)
+#define WSA884X_OTP_REG_34 (WSA884X_DIG_TRIM_BASE + 0xa2)
+#define WSA884X_OTP_REG_35 (WSA884X_DIG_TRIM_BASE + 0xa3)
+#define WSA884X_OTP_REG_36 (WSA884X_DIG_TRIM_BASE + 0xa4)
+#define WSA884X_OTP_REG_37 (WSA884X_DIG_TRIM_BASE + 0xa5)
+#define WSA884X_OTP_REG_38 (WSA884X_DIG_TRIM_BASE + 0xa6)
+#define WSA884X_OTP_REG_38_RESERVER_MASK 0xf0
+#define WSA884X_OTP_REG_38_RESERVER_SHIFT 4
+#define WSA884X_OTP_REG_38_BST_CFG_SEL_MASK 0x08
+#define WSA884X_OTP_REG_38_BST_CFG_SEL_SHIFT 3
+#define WSA884X_OTP_REG_38_BOOST_ILIM_TUNE_MASK 0x07
+#define WSA884X_OTP_REG_38_BOOST_ILIM_TUNE_SHIFT 0
+#define WSA884X_OTP_REG_39 (WSA884X_DIG_TRIM_BASE + 0xa7)
+#define WSA884X_OTP_REG_40 (WSA884X_DIG_TRIM_BASE + 0xa8)
+#define WSA884X_OTP_REG_40_SPARE_TYPE2_MASK 0xc0
+#define WSA884X_OTP_REG_40_SPARE_TYPE2_SHIFT 6
+#define WSA884X_OTP_REG_40_ISENSE_RESCAL_MASK 0x3c
+#define WSA884X_OTP_REG_40_ISENSE_RESCAL_SHIFT 2
+#define WSA884X_OTP_REG_40_ATE_BOOST_RDSON_TEST_MASK 0x2
+#define WSA884X_OTP_REG_40_ATE_BOOST_RDSON_TEST_SHIFT 1
+#define WSA884X_OTP_REG_40_ATE_CLASSD_RDSON_TEST_MASK 0x1
+#define WSA884X_OTP_REG_40_ATE_CLASSD_RDSON_TEST_SHIFT 0
+#define WSA884X_OTP_REG_41 (WSA884X_DIG_TRIM_BASE + 0xa9)
+#define WSA884X_OTP_REG_63 (WSA884X_DIG_TRIM_BASE + 0xbf)
+
+#define WSA884X_DIG_EMEM_BASE (WSA884X_BASE + 0x08C0)
+#define WSA884X_EMEM_0 (WSA884X_DIG_EMEM_BASE + 0x00)
+#define WSA884X_EMEM_1 (WSA884X_DIG_EMEM_BASE + 0x01)
+#define WSA884X_EMEM_2 (WSA884X_DIG_EMEM_BASE + 0x02)
+#define WSA884X_EMEM_3 (WSA884X_DIG_EMEM_BASE + 0x03)
+#define WSA884X_EMEM_4 (WSA884X_DIG_EMEM_BASE + 0x04)
+#define WSA884X_EMEM_5 (WSA884X_DIG_EMEM_BASE + 0x05)
+#define WSA884X_EMEM_6 (WSA884X_DIG_EMEM_BASE + 0x06)
+#define WSA884X_EMEM_7 (WSA884X_DIG_EMEM_BASE + 0x07)
+#define WSA884X_EMEM_8 (WSA884X_DIG_EMEM_BASE + 0x08)
+#define WSA884X_EMEM_9 (WSA884X_DIG_EMEM_BASE + 0x09)
+#define WSA884X_EMEM_10 (WSA884X_DIG_EMEM_BASE + 0x0a)
+#define WSA884X_EMEM_11 (WSA884X_DIG_EMEM_BASE + 0x0b)
+#define WSA884X_EMEM_12 (WSA884X_DIG_EMEM_BASE + 0x0c)
+#define WSA884X_EMEM_13 (WSA884X_DIG_EMEM_BASE + 0x0d)
+#define WSA884X_EMEM_14 (WSA884X_DIG_EMEM_BASE + 0x0e)
+#define WSA884X_EMEM_15 (WSA884X_DIG_EMEM_BASE + 0x0f)
+#define WSA884X_EMEM_16 (WSA884X_DIG_EMEM_BASE + 0x10)
+#define WSA884X_EMEM_17 (WSA884X_DIG_EMEM_BASE + 0x11)
+#define WSA884X_EMEM_18 (WSA884X_DIG_EMEM_BASE + 0x12)
+#define WSA884X_EMEM_19 (WSA884X_DIG_EMEM_BASE + 0x13)
+#define WSA884X_EMEM_20 (WSA884X_DIG_EMEM_BASE + 0x14)
+#define WSA884X_EMEM_21 (WSA884X_DIG_EMEM_BASE + 0x15)
+#define WSA884X_EMEM_22 (WSA884X_DIG_EMEM_BASE + 0x16)
+#define WSA884X_EMEM_23 (WSA884X_DIG_EMEM_BASE + 0x17)
+#define WSA884X_EMEM_24 (WSA884X_DIG_EMEM_BASE + 0x18)
+#define WSA884X_EMEM_25 (WSA884X_DIG_EMEM_BASE + 0x19)
+#define WSA884X_EMEM_26 (WSA884X_DIG_EMEM_BASE + 0x1a)
+#define WSA884X_EMEM_27 (WSA884X_DIG_EMEM_BASE + 0x1b)
+#define WSA884X_EMEM_28 (WSA884X_DIG_EMEM_BASE + 0x1c)
+#define WSA884X_EMEM_29 (WSA884X_DIG_EMEM_BASE + 0x1d)
+#define WSA884X_EMEM_30 (WSA884X_DIG_EMEM_BASE + 0x1e)
+#define WSA884X_EMEM_31 (WSA884X_DIG_EMEM_BASE + 0x1f)
+#define WSA884X_EMEM_32 (WSA884X_DIG_EMEM_BASE + 0x20)
+#define WSA884X_EMEM_33 (WSA884X_DIG_EMEM_BASE + 0x21)
+#define WSA884X_EMEM_34 (WSA884X_DIG_EMEM_BASE + 0x22)
+#define WSA884X_EMEM_35 (WSA884X_DIG_EMEM_BASE + 0x23)
+#define WSA884X_EMEM_36 (WSA884X_DIG_EMEM_BASE + 0x24)
+#define WSA884X_EMEM_37 (WSA884X_DIG_EMEM_BASE + 0x25)
+#define WSA884X_EMEM_38 (WSA884X_DIG_EMEM_BASE + 0x26)
+#define WSA884X_EMEM_39 (WSA884X_DIG_EMEM_BASE + 0x27)
+#define WSA884X_EMEM_40 (WSA884X_DIG_EMEM_BASE + 0x28)
+#define WSA884X_EMEM_41 (WSA884X_DIG_EMEM_BASE + 0x29)
+#define WSA884X_EMEM_42 (WSA884X_DIG_EMEM_BASE + 0x2a)
+#define WSA884X_EMEM_43 (WSA884X_DIG_EMEM_BASE + 0x2b)
+#define WSA884X_EMEM_44 (WSA884X_DIG_EMEM_BASE + 0x2c)
+#define WSA884X_EMEM_45 (WSA884X_DIG_EMEM_BASE + 0x2d)
+#define WSA884X_EMEM_46 (WSA884X_DIG_EMEM_BASE + 0x2e)
+#define WSA884X_EMEM_47 (WSA884X_DIG_EMEM_BASE + 0x2f)
+#define WSA884X_EMEM_48 (WSA884X_DIG_EMEM_BASE + 0x30)
+#define WSA884X_EMEM_49 (WSA884X_DIG_EMEM_BASE + 0x31)
+#define WSA884X_EMEM_50 (WSA884X_DIG_EMEM_BASE + 0x32)
+#define WSA884X_EMEM_51 (WSA884X_DIG_EMEM_BASE + 0x33)
+#define WSA884X_EMEM_52 (WSA884X_DIG_EMEM_BASE + 0x34)
+#define WSA884X_EMEM_53 (WSA884X_DIG_EMEM_BASE + 0x35)
+#define WSA884X_EMEM_54 (WSA884X_DIG_EMEM_BASE + 0x36)
+#define WSA884X_EMEM_55 (WSA884X_DIG_EMEM_BASE + 0x37)
+#define WSA884X_EMEM_56 (WSA884X_DIG_EMEM_BASE + 0x38)
+#define WSA884X_EMEM_57 (WSA884X_DIG_EMEM_BASE + 0x39)
+#define WSA884X_EMEM_58 (WSA884X_DIG_EMEM_BASE + 0x3a)
+#define WSA884X_EMEM_59 (WSA884X_DIG_EMEM_BASE + 0x3b)
+#define WSA884X_EMEM_60 (WSA884X_DIG_EMEM_BASE + 0x3c)
+#define WSA884X_EMEM_61 (WSA884X_DIG_EMEM_BASE + 0x3d)
+#define WSA884X_EMEM_62 (WSA884X_DIG_EMEM_BASE + 0x3e)
+#define WSA884X_EMEM_63 (WSA884X_DIG_EMEM_BASE + 0x3f)
+
+#define WSA884X_NUM_REGISTERS (WSA884X_EMEM_63 + 1)
+#define WSA884X_MAX_REGISTER (WSA884X_NUM_REGISTERS - 1)
+
+#define WSA884X_SUPPLIES_NUM 2
+#define WSA884X_MAX_SWR_PORTS 6
+#define WSA884X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define WSA884X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define WSA884X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+/* Two-point trimming for temperature calibration */
+#define WSA884X_T1_TEMP -10L
+#define WSA884X_T2_TEMP 150L
+
+/*
+ * Device will report senseless data in many cases, so discard any measurements
+ * outside of valid range.
+ */
+#define WSA884X_LOW_TEMP_THRESHOLD 5
+#define WSA884X_HIGH_TEMP_THRESHOLD 45
+
+struct wsa884x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct regulator_bulk_data supplies[WSA884X_SUPPLIES_NUM];
+ struct sdw_slave *slave;
+ struct sdw_stream_config sconfig;
+ struct sdw_stream_runtime *sruntime;
+ struct sdw_port_config port_config[WSA884X_MAX_SWR_PORTS];
+ struct gpio_desc *sd_n;
+ struct reset_control *sd_reset;
+ bool port_prepared[WSA884X_MAX_SWR_PORTS];
+ bool port_enable[WSA884X_MAX_SWR_PORTS];
+ int active_ports;
+ int dev_mode;
+ bool hw_init;
+ /*
+ * 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 {
+ COMP_OFFSET0,
+ COMP_OFFSET1,
+ COMP_OFFSET2,
+ COMP_OFFSET3,
+ COMP_OFFSET4,
+};
+
+enum wsa884x_gain {
+ G_21_DB = 0,
+ G_19P5_DB,
+ G_18_DB,
+ G_16P5_DB,
+ G_15_DB,
+ G_13P5_DB,
+ G_12_DB,
+ G_10P5_DB,
+ G_9_DB,
+ G_7P5_DB,
+ G_6_DB,
+ G_4P5_DB,
+ G_3_DB,
+ G_1P5_DB,
+ G_0_DB,
+ G_M1P5_DB,
+ G_M3_DB,
+ G_M4P5_DB,
+ G_M6_DB,
+ G_MAX_DB,
+};
+
+enum wsa884x_isense {
+ ISENSE_6_DB = 0,
+ ISENSE_12_DB,
+ ISENSE_15_DB,
+ ISENSE_18_DB,
+};
+
+enum wsa884x_vsense {
+ VSENSE_M12_DB = 0,
+ VSENSE_M15_DB,
+ VSENSE_M18_DB,
+ VSENSE_M21_DB,
+ VSENSE_M24_DB,
+};
+
+enum wsa884x_port_ids {
+ WSA884X_PORT_DAC,
+ WSA884X_PORT_COMP,
+ WSA884X_PORT_BOOST,
+ WSA884X_PORT_PBR,
+ WSA884X_PORT_VISENSE,
+ WSA884X_PORT_CPS,
+};
+
+static const char * const wsa884x_supply_name[] = {
+ "vdd-io",
+ "vdd-1p8",
+};
+
+static const char * const wsa884x_dev_mode_text[] = {
+ "Speaker", "Receiver"
+};
+
+enum wsa884x_mode {
+ WSA884X_SPEAKER,
+ WSA884X_RECEIVER,
+};
+
+static const struct soc_enum wsa884x_dev_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa884x_dev_mode_text), wsa884x_dev_mode_text);
+
+static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = {
+ [WSA884X_PORT_DAC] = {
+ .num = WSA884X_PORT_DAC + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ },
+ [WSA884X_PORT_COMP] = {
+ .num = WSA884X_PORT_COMP + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ },
+ [WSA884X_PORT_BOOST] = {
+ .num = WSA884X_PORT_BOOST + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ },
+ [WSA884X_PORT_PBR] = {
+ .num = WSA884X_PORT_PBR + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ },
+ [WSA884X_PORT_VISENSE] = {
+ .num = WSA884X_PORT_VISENSE + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ },
+ [WSA884X_PORT_CPS] = {
+ .num = WSA884X_PORT_CPS + 1,
+ .type = SDW_DPN_SIMPLE,
+ .min_ch = 1,
+ .max_ch = 1,
+ .simple_ch_prep_sm = true,
+ .read_only_wordlength = true,
+ }
+};
+
+static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
+ [WSA884X_PORT_DAC] = {
+ .num = WSA884X_PORT_DAC + 1,
+ .ch_mask = 0x1,
+ },
+ [WSA884X_PORT_COMP] = {
+ .num = WSA884X_PORT_COMP + 1,
+ .ch_mask = 0xf,
+ },
+ [WSA884X_PORT_BOOST] = {
+ .num = WSA884X_PORT_BOOST + 1,
+ .ch_mask = 0x3,
+ },
+ [WSA884X_PORT_PBR] = {
+ .num = WSA884X_PORT_PBR + 1,
+ .ch_mask = 0x1,
+ },
+ [WSA884X_PORT_VISENSE] = {
+ .num = WSA884X_PORT_VISENSE + 1,
+ .ch_mask = 0x1,
+ },
+ [WSA884X_PORT_CPS] = {
+ .num = WSA884X_PORT_CPS + 1,
+ .ch_mask = 0x3,
+ },
+};
+
+static const struct reg_default wsa884x_defaults[] = {
+ { WSA884X_BG_CTRL, 0xa5 },
+ { WSA884X_ADC_CTRL, 0x00 },
+ { WSA884X_BOP1_PROG, 0x22 },
+ { WSA884X_BOP2_PROG, 0x44 },
+ { WSA884X_UVLO_PROG, 0x99 },
+ { WSA884X_UVLO_PROG1, 0x70 },
+ { WSA884X_SPARE_CTRL_0, 0x00 },
+ { WSA884X_SPARE_CTRL_1, 0x00 },
+ { WSA884X_SPARE_CTRL_2, 0x00 },
+ { WSA884X_SPARE_CTRL_3, 0x00 },
+ { WSA884X_REF_CTRL, 0xd2 },
+ { WSA884X_BG_TEST_CTL, 0x06 },
+ { WSA884X_BG_BIAS, 0xd7 },
+ { WSA884X_ADC_PROG, 0x08 },
+ { WSA884X_ADC_IREF_CTL, 0x57 },
+ { WSA884X_ADC_ISENS_CTL, 0x47 },
+ { WSA884X_ADC_CLK_CTL, 0x87 },
+ { WSA884X_ADC_TEST_CTL, 0x00 },
+ { WSA884X_ADC_BIAS, 0x51 },
+ { WSA884X_VBAT_SNS, 0xa0 },
+ { WSA884X_BOP_ATEST_SEL, 0x00 },
+ { WSA884X_MISC0, 0x04 },
+ { WSA884X_MISC1, 0x75 },
+ { WSA884X_MISC2, 0x00 },
+ { WSA884X_MISC3, 0x10 },
+ { WSA884X_SPARE_TSBG_0, 0x00 },
+ { WSA884X_SPARE_TUNE_0, 0x00 },
+ { WSA884X_SPARE_TUNE_1, 0x00 },
+ { WSA884X_VSENSE1, 0xe7 },
+ { WSA884X_ISENSE2, 0x27 },
+ { WSA884X_SPARE_CTL_1, 0x00 },
+ { WSA884X_SPARE_CTL_2, 0x00 },
+ { WSA884X_SPARE_CTL_3, 0x00 },
+ { WSA884X_SPARE_CTL_4, 0x00 },
+ { WSA884X_EN, 0x10 },
+ { WSA884X_OVERRIDE1, 0x00 },
+ { WSA884X_OVERRIDE2, 0x08 },
+ { WSA884X_ISENSE1, 0xd4 },
+ { WSA884X_ISENSE_CAL, 0x00 },
+ { WSA884X_MISC, 0x00 },
+ { WSA884X_ADC_0, 0x00 },
+ { WSA884X_ADC_1, 0x00 },
+ { WSA884X_ADC_2, 0x40 },
+ { WSA884X_ADC_3, 0x80 },
+ { WSA884X_ADC_4, 0x25 },
+ { WSA884X_ADC_5, 0x24 },
+ { WSA884X_ADC_6, 0x0a },
+ { WSA884X_ADC_7, 0x81 },
+ { WSA884X_IVSENSE_SPARE_TUNE_1, 0x00 },
+ { WSA884X_SPARE_TUNE_2, 0x00 },
+ { WSA884X_SPARE_TUNE_3, 0x00 },
+ { WSA884X_SPARE_TUNE_4, 0x00 },
+ { WSA884X_TOP_CTRL1, 0xd3 },
+ { WSA884X_CLIP_DET_CTRL1, 0x7e },
+ { WSA884X_CLIP_DET_CTRL2, 0x4c },
+ { WSA884X_DAC_CTRL1, 0xa4 },
+ { WSA884X_DAC_VCM_CTRL_REG1, 0x02 },
+ { WSA884X_DAC_VCM_CTRL_REG2, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG3, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG4, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG5, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG6, 0x00 },
+ { WSA884X_PWM_CLK_CTL, 0x20 },
+ { WSA884X_DRV_LF_LDO_SEL, 0xaa },
+ { WSA884X_OCP_CTL, 0xc6 },
+ { WSA884X_PDRV_HS_CTL, 0x52 },
+ { WSA884X_PDRV_LS_CTL, 0x4a },
+ { WSA884X_SPK_TOP_SPARE_CTL_1, 0x00 },
+ { WSA884X_SPK_TOP_SPARE_CTL_2, 0x00 },
+ { WSA884X_SPK_TOP_SPARE_CTL_3, 0x00 },
+ { WSA884X_SPK_TOP_SPARE_CTL_4, 0x00 },
+ { WSA884X_SPARE_CTL_5, 0x00 },
+ { WSA884X_DAC_EN_DEBUG_REG, 0x00 },
+ { WSA884X_DAC_OPAMP_BIAS1_REG, 0x48 },
+ { WSA884X_DAC_OPAMP_BIAS2_REG, 0x48 },
+ { WSA884X_DAC_TUNE1, 0x02 },
+ { WSA884X_DAC_VOLTAGE_CTRL_REG, 0x05 },
+ { WSA884X_ATEST1_REG, 0x00 },
+ { WSA884X_ATEST2_REG, 0x00 },
+ { WSA884X_TOP_BIAS_REG1, 0x6a },
+ { WSA884X_TOP_BIAS_REG2, 0x65 },
+ { WSA884X_TOP_BIAS_REG3, 0x55 },
+ { WSA884X_TOP_BIAS_REG4, 0xa9 },
+ { WSA884X_PWRSTG_DBG2, 0x21 },
+ { WSA884X_DRV_LF_BLK_EN, 0x0f },
+ { WSA884X_DRV_LF_EN, 0x0a },
+ { WSA884X_DRV_LF_MASK_DCC_CTL, 0x08 },
+ { WSA884X_DRV_LF_MISC_CTL1, 0x30 },
+ { WSA884X_DRV_LF_REG_GAIN, 0x00 },
+ { WSA884X_DRV_OS_CAL_CTL, 0x00 },
+ { WSA884X_DRV_OS_CAL_CTL1, 0x90 },
+ { WSA884X_PWRSTG_DBG, 0x08 },
+ { WSA884X_BBM_CTL, 0x92 },
+ { WSA884X_TOP_MISC1, 0x00 },
+ { WSA884X_DAC_VCM_CTRL_REG7, 0x00 },
+ { WSA884X_TOP_BIAS_REG5, 0x15 },
+ { WSA884X_DRV_LF_MISC_CTL2, 0x00 },
+ { WSA884X_STB_CTRL1, 0x42 },
+ { WSA884X_CURRENT_LIMIT, 0x54 },
+ { WSA884X_BYP_CTRL1, 0x01 },
+ { WSA884X_SPARE_CTL_0, 0x00 },
+ { WSA884X_BOOST_SPARE_CTL_1, 0x00 },
+ { WSA884X_IBIAS1, 0x00 },
+ { WSA884X_IBIAS2, 0x00 },
+ { WSA884X_IBIAS3, 0x00 },
+ { WSA884X_EN_CTRL, 0x42 },
+ { WSA884X_STB_CTRL2, 0x03 },
+ { WSA884X_STB_CTRL3, 0x3c },
+ { WSA884X_STB_CTRL4, 0x30 },
+ { WSA884X_BYP_CTRL2, 0x97 },
+ { WSA884X_BYP_CTRL3, 0x11 },
+ { WSA884X_ZX_CTRL1, 0xf0 },
+ { WSA884X_ZX_CTRL2, 0x04 },
+ { WSA884X_BLEEDER_CTRL, 0x04 },
+ { WSA884X_BOOST_MISC, 0x62 },
+ { WSA884X_PWRSTAGE_CTRL1, 0x00 },
+ { WSA884X_PWRSTAGE_CTRL2, 0x31 },
+ { WSA884X_PWRSTAGE_CTRL3, 0x81 },
+ { WSA884X_PWRSTAGE_CTRL4, 0x5f },
+ { WSA884X_MAXD_REG1, 0x00 },
+ { WSA884X_MAXD_REG2, 0x5b },
+ { WSA884X_ILIM_CTRL1, 0xe2 },
+ { WSA884X_ILIM_CTRL2, 0x90 },
+ { WSA884X_TEST_CTRL1, 0x00 },
+ { WSA884X_TEST_CTRL2, 0x00 },
+ { WSA884X_SPARE1, 0x00 },
+ { WSA884X_BOOT_CAP_CHECK, 0x01 },
+ { WSA884X_PON_CTL_0, 0x12 },
+ { WSA884X_PWRSAV_CTL, 0xaa },
+ { WSA884X_PON_LDOL_SPARE_CTL_0, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_CTL_1, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_CTL_2, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_CTL_3, 0x00 },
+ { WSA884X_PON_CLT_1, 0xe1 },
+ { WSA884X_PON_CTL_2, 0x00 },
+ { WSA884X_PON_CTL_3, 0x70 },
+ { WSA884X_CKWD_CTL_0, 0x14 },
+ { WSA884X_CKWD_CTL_1, 0x3b },
+ { WSA884X_CKWD_CTL_2, 0x00 },
+ { WSA884X_CKSK_CTL_0, 0x00 },
+ { WSA884X_PADSW_CTL_0, 0x00 },
+ { WSA884X_TEST_0, 0x00 },
+ { WSA884X_TEST_1, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_0, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_1, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_2, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_3, 0x00 },
+ { WSA884X_PON_LDOL_SPARE_TUNE_4, 0x00 },
+ { WSA884X_DIG_CTRL0_PAGE, 0x00 },
+ { WSA884X_CDC_RST_CTL, 0x01 },
+ { WSA884X_SWR_RESET_EN, 0x00 },
+ { WSA884X_TOP_CLK_CFG, 0x00 },
+ { WSA884X_SWR_CLK_RATE, 0x00 },
+ { WSA884X_CDC_PATH_MODE, 0x00 },
+ { WSA884X_CDC_CLK_CTL, 0x1f },
+ { WSA884X_PA_FSM_EN, 0x00 },
+ { WSA884X_PA_FSM_CTL0, 0x00 },
+ { WSA884X_PA_FSM_CTL1, 0xfe },
+ { WSA884X_PA_FSM_TIMER0, 0x80 },
+ { WSA884X_PA_FSM_TIMER1, 0x80 },
+ { WSA884X_PA_FSM_ERR_CTL, 0x00 },
+ { WSA884X_PA_FSM_MSK0, 0x00 },
+ { WSA884X_PA_FSM_MSK1, 0x00 },
+ { WSA884X_PA_FSM_BYP_CTL, 0x00 },
+ { WSA884X_PA_FSM_BYP0, 0x00 },
+ { WSA884X_PA_FSM_BYP1, 0x00 },
+ { WSA884X_TADC_VALUE_CTL, 0x03 },
+ { WSA884X_TEMP_DETECT_CTL, 0x01 },
+ { WSA884X_TEMP_CONFIG0, 0x00 },
+ { WSA884X_TEMP_CONFIG1, 0x00 },
+ { WSA884X_VBAT_THRM_FLT_CTL, 0x7f },
+ { WSA884X_VBAT_CAL_CTL, 0x01 },
+ { WSA884X_UVLO_DEGLITCH_CTL, 0x05 },
+ { WSA884X_BOP_DEGLITCH_CTL, 0x05 },
+ { WSA884X_VBAT_ZONE_DETC_CTL, 0x31 },
+ { WSA884X_CPS_CTL, 0x00 },
+ { WSA884X_CDC_RX_CTL, 0xfe },
+ { WSA884X_CDC_SPK_DSM_A1_0, 0x00 },
+ { WSA884X_CDC_SPK_DSM_A1_1, 0x01 },
+ { WSA884X_CDC_SPK_DSM_A2_0, 0x96 },
+ { WSA884X_CDC_SPK_DSM_A2_1, 0x09 },
+ { WSA884X_CDC_SPK_DSM_A3_0, 0xab },
+ { WSA884X_CDC_SPK_DSM_A3_1, 0x05 },
+ { WSA884X_CDC_SPK_DSM_A4_0, 0x1c },
+ { WSA884X_CDC_SPK_DSM_A4_1, 0x02 },
+ { WSA884X_CDC_SPK_DSM_A5_0, 0x17 },
+ { WSA884X_CDC_SPK_DSM_A5_1, 0x02 },
+ { WSA884X_CDC_SPK_DSM_A6_0, 0xaa },
+ { WSA884X_CDC_SPK_DSM_A7_0, 0xe3 },
+ { WSA884X_CDC_SPK_DSM_C_0, 0x69 },
+ { WSA884X_CDC_SPK_DSM_C_1, 0x54 },
+ { WSA884X_CDC_SPK_DSM_C_2, 0x02 },
+ { WSA884X_CDC_SPK_DSM_C_3, 0x15 },
+ { WSA884X_CDC_SPK_DSM_R1, 0xa4 },
+ { WSA884X_CDC_SPK_DSM_R2, 0xb5 },
+ { WSA884X_CDC_SPK_DSM_R3, 0x86 },
+ { WSA884X_CDC_SPK_DSM_R4, 0x85 },
+ { WSA884X_CDC_SPK_DSM_R5, 0xaa },
+ { WSA884X_CDC_SPK_DSM_R6, 0xe2 },
+ { WSA884X_CDC_SPK_DSM_R7, 0x62 },
+ { WSA884X_CDC_SPK_GAIN_PDM_0, 0x00 },
+ { WSA884X_CDC_SPK_GAIN_PDM_1, 0xfc },
+ { WSA884X_CDC_SPK_GAIN_PDM_2, 0x05 },
+ { WSA884X_PDM_WD_CTL, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA0, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA1, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA2, 0x00 },
+ { WSA884X_DEM_BYPASS_DATA3, 0x00 },
+ { WSA884X_DRE_CTL_0, 0x70 },
+ { WSA884X_DRE_CTL_1, 0x04 },
+ { WSA884X_DRE_IDLE_DET_CTL, 0x2f },
+ { WSA884X_GAIN_RAMPING_CTL, 0x50 },
+ { WSA884X_GAIN_RAMPING_MIN, 0x12 },
+ { WSA884X_TAGC_CTL, 0x15 },
+ { WSA884X_TAGC_TIME, 0xbc },
+ { WSA884X_TAGC_FORCE_VAL, 0x00 },
+ { WSA884X_VAGC_CTL, 0x01 },
+ { WSA884X_VAGC_TIME, 0x0f },
+ { WSA884X_VAGC_ATTN_LVL_1, 0x03 },
+ { WSA884X_VAGC_ATTN_LVL_2, 0x06 },
+ { WSA884X_VAGC_ATTN_LVL_3, 0x09 },
+ { WSA884X_CLSH_CTL_0, 0x37 },
+ { WSA884X_CLSH_CTL_1, 0x81 },
+ { WSA884X_CLSH_V_HD_PA, 0x0c },
+ { WSA884X_CLSH_V_PA_MIN, 0x00 },
+ { WSA884X_CLSH_OVRD_VAL, 0x00 },
+ { WSA884X_CLSH_HARD_MAX, 0xff },
+ { WSA884X_CLSH_SOFT_MAX, 0xf5 },
+ { WSA884X_CLSH_SIG_DP, 0x00 },
+ { WSA884X_PBR_DELAY_CTL, 0x07 },
+ { WSA884X_CLSH_SRL_MAX_PBR, 0x02 },
+ { WSA884X_CLSH_VTH1, 0x00 },
+ { WSA884X_CLSH_VTH2, 0x00 },
+ { WSA884X_CLSH_VTH3, 0x00 },
+ { WSA884X_CLSH_VTH4, 0x00 },
+ { WSA884X_CLSH_VTH5, 0x00 },
+ { WSA884X_CLSH_VTH6, 0x00 },
+ { WSA884X_CLSH_VTH7, 0x00 },
+ { WSA884X_CLSH_VTH8, 0x00 },
+ { WSA884X_CLSH_VTH9, 0x00 },
+ { WSA884X_CLSH_VTH10, 0x00 },
+ { WSA884X_CLSH_VTH11, 0x00 },
+ { WSA884X_CLSH_VTH12, 0x00 },
+ { WSA884X_CLSH_VTH13, 0x00 },
+ { WSA884X_CLSH_VTH14, 0x00 },
+ { WSA884X_CLSH_VTH15, 0x00 },
+ { WSA884X_DIG_CTRL1_PAGE, 0x00 },
+ { WSA884X_PIN_CTL, 0x04 },
+ { WSA884X_PIN_CTL_OE, 0x00 },
+ { WSA884X_PIN_WDATA_IOPAD, 0x00 },
+ { WSA884X_I2C_SLAVE_CTL, 0x00 },
+ { WSA884X_SPMI_PAD_CTL0, 0x2f },
+ { WSA884X_SPMI_PAD_CTL1, 0x2f },
+ { WSA884X_SPMI_PAD_CTL2, 0x2f },
+ { WSA884X_MEM_CTL, 0x00 },
+ { WSA884X_SWR_HM_TEST0, 0x08 },
+ { WSA884X_OTP_CTRL0, 0x00 },
+ { WSA884X_OTP_CTRL2, 0x00 },
+ { WSA884X_OTP_PRG_TCSP0, 0x77 },
+ { WSA884X_OTP_PRG_TCSP1, 0x00 },
+ { WSA884X_OTP_PRG_TPPS, 0x47 },
+ { WSA884X_OTP_PRG_TVPS, 0x3b },
+ { WSA884X_OTP_PRG_TVPH, 0x47 },
+ { WSA884X_OTP_PRG_TPPR0, 0x47 },
+ { WSA884X_OTP_PRG_TPPR1, 0x00 },
+ { WSA884X_OTP_PRG_TPPH, 0x47 },
+ { WSA884X_OTP_PRG_END, 0x47 },
+ { WSA884X_WAVG_PLAY, 0x00 },
+ { WSA884X_WAVG_CTL, 0x06 },
+ { WSA884X_WAVG_LRA_PER_0, 0xd1 },
+ { WSA884X_WAVG_LRA_PER_1, 0x00 },
+ { WSA884X_WAVG_DELTA_THETA_0, 0xe6 },
+ { WSA884X_WAVG_DELTA_THETA_1, 0x04 },
+ { WSA884X_WAVG_DIRECT_AMP_0, 0x50 },
+ { WSA884X_WAVG_DIRECT_AMP_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP0_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP0_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP1_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP1_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP2_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP2_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP3_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP3_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP4_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP4_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP5_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP5_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP6_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP6_1, 0x00 },
+ { WSA884X_WAVG_PTRN_AMP7_0, 0x50 },
+ { WSA884X_WAVG_PTRN_AMP7_1, 0x00 },
+ { WSA884X_WAVG_PER_0_1, 0x88 },
+ { WSA884X_WAVG_PER_2_3, 0x88 },
+ { WSA884X_WAVG_PER_4_5, 0x88 },
+ { WSA884X_WAVG_PER_6_7, 0x88 },
+ { WSA884X_INTR_MODE, 0x00 },
+ { WSA884X_INTR_MASK0, 0x90 },
+ { WSA884X_INTR_MASK1, 0x00 },
+ { WSA884X_INTR_CLEAR0, 0x00 },
+ { WSA884X_INTR_CLEAR1, 0x00 },
+ { WSA884X_INTR_LEVEL0, 0x04 },
+ { WSA884X_INTR_LEVEL1, 0x00 },
+ { WSA884X_INTR_SET0, 0x00 },
+ { WSA884X_INTR_SET1, 0x00 },
+ { WSA884X_INTR_TEST0, 0x00 },
+ { WSA884X_INTR_TEST1, 0x00 },
+ { WSA884X_PDM_TEST_MODE, 0x00 },
+ { WSA884X_PA_FSM_DBG, 0x00 },
+ { WSA884X_DIG_DEBUG_MODE, 0x00 },
+ { WSA884X_DIG_DEBUG_SEL, 0x00 },
+ { WSA884X_DIG_DEBUG_EN, 0x00 },
+ { WSA884X_TADC_DETECT_DBG_CTL, 0x00 },
+ { WSA884X_TADC_DEBUG_MSB, 0x00 },
+ { WSA884X_TADC_DEBUG_LSB, 0x00 },
+ { WSA884X_SAMPLE_EDGE_SEL, 0x7f },
+ { WSA884X_SWR_EDGE_SEL, 0x00 },
+ { WSA884X_TEST_MODE_CTL, 0x05 },
+ { WSA884X_IOPAD_CTL, 0x00 },
+ { WSA884X_ANA_CSR_DBG_ADD, 0x00 },
+ { WSA884X_ANA_CSR_DBG_CTL, 0x12 },
+ { WSA884X_CLK_DBG_CTL, 0x00 },
+ { WSA884X_SPARE_0, 0x00 },
+ { WSA884X_SPARE_1, 0x00 },
+ { WSA884X_SPARE_2, 0x00 },
+ { WSA884X_SCODE, 0x00 },
+ { WSA884X_DIG_TRIM_PAGE, 0x00 },
+ { WSA884X_EMEM_0, 0x00 },
+ { WSA884X_EMEM_1, 0x00 },
+ { WSA884X_EMEM_2, 0x00 },
+ { WSA884X_EMEM_3, 0x00 },
+ { WSA884X_EMEM_4, 0x00 },
+ { WSA884X_EMEM_5, 0x00 },
+ { WSA884X_EMEM_6, 0x00 },
+ { WSA884X_EMEM_7, 0x00 },
+ { WSA884X_EMEM_8, 0x00 },
+ { WSA884X_EMEM_9, 0x00 },
+ { WSA884X_EMEM_10, 0x00 },
+ { WSA884X_EMEM_11, 0x00 },
+ { WSA884X_EMEM_12, 0x00 },
+ { WSA884X_EMEM_13, 0x00 },
+ { WSA884X_EMEM_14, 0x00 },
+ { WSA884X_EMEM_15, 0x00 },
+ { WSA884X_EMEM_16, 0x00 },
+ { WSA884X_EMEM_17, 0x00 },
+ { WSA884X_EMEM_18, 0x00 },
+ { WSA884X_EMEM_19, 0x00 },
+ { WSA884X_EMEM_20, 0x00 },
+ { WSA884X_EMEM_21, 0x00 },
+ { WSA884X_EMEM_22, 0x00 },
+ { WSA884X_EMEM_23, 0x00 },
+ { WSA884X_EMEM_24, 0x00 },
+ { WSA884X_EMEM_25, 0x00 },
+ { WSA884X_EMEM_26, 0x00 },
+ { WSA884X_EMEM_27, 0x00 },
+ { WSA884X_EMEM_28, 0x00 },
+ { WSA884X_EMEM_29, 0x00 },
+ { WSA884X_EMEM_30, 0x00 },
+ { WSA884X_EMEM_31, 0x00 },
+ { WSA884X_EMEM_32, 0x00 },
+ { WSA884X_EMEM_33, 0x00 },
+ { WSA884X_EMEM_34, 0x00 },
+ { WSA884X_EMEM_35, 0x00 },
+ { WSA884X_EMEM_36, 0x00 },
+ { WSA884X_EMEM_37, 0x00 },
+ { WSA884X_EMEM_38, 0x00 },
+ { WSA884X_EMEM_39, 0x00 },
+ { WSA884X_EMEM_40, 0x00 },
+ { WSA884X_EMEM_41, 0x00 },
+ { WSA884X_EMEM_42, 0x00 },
+ { WSA884X_EMEM_43, 0x00 },
+ { WSA884X_EMEM_44, 0x00 },
+ { WSA884X_EMEM_45, 0x00 },
+ { WSA884X_EMEM_46, 0x00 },
+ { WSA884X_EMEM_47, 0x00 },
+ { WSA884X_EMEM_48, 0x00 },
+ { WSA884X_EMEM_49, 0x00 },
+ { WSA884X_EMEM_50, 0x00 },
+ { WSA884X_EMEM_51, 0x00 },
+ { WSA884X_EMEM_52, 0x00 },
+ { WSA884X_EMEM_53, 0x00 },
+ { WSA884X_EMEM_54, 0x00 },
+ { WSA884X_EMEM_55, 0x00 },
+ { WSA884X_EMEM_56, 0x00 },
+ { WSA884X_EMEM_57, 0x00 },
+ { WSA884X_EMEM_58, 0x00 },
+ { WSA884X_EMEM_59, 0x00 },
+ { WSA884X_EMEM_60, 0x00 },
+ { WSA884X_EMEM_61, 0x00 },
+ { WSA884X_EMEM_62, 0x00 },
+ { WSA884X_EMEM_63, 0x00 },
+};
+
+static bool wsa884x_readonly_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA884X_DOUT_MSB:
+ case WSA884X_DOUT_LSB:
+ case WSA884X_STATUS:
+ case WSA884X_SPK_TOP_SPARE_TUNE_2:
+ case WSA884X_SPK_TOP_SPARE_TUNE_3:
+ case WSA884X_SPK_TOP_SPARE_TUNE_4:
+ case WSA884X_SPARE_TUNE_5:
+ case WSA884X_SPARE_TUNE_6:
+ case WSA884X_SPARE_TUNE_7:
+ case WSA884X_SPARE_TUNE_8:
+ case WSA884X_SPARE_TUNE_9:
+ case WSA884X_SPARE_TUNE_10:
+ case WSA884X_PA_STATUS0:
+ case WSA884X_PA_STATUS1:
+ case WSA884X_PA_STATUS2:
+ case WSA884X_PA_STATUS3:
+ case WSA884X_PA_STATUS4:
+ case WSA884X_PA_STATUS5:
+ case WSA884X_SPARE_RO_1:
+ case WSA884X_SPARE_RO_2:
+ case WSA884X_SPARE_RO_3:
+ case WSA884X_SPARE_RO_0:
+ case WSA884X_BOOST_SPARE_RO_1:
+ case WSA884X_STATUS_0:
+ case WSA884X_STATUS_1:
+ case WSA884X_CHIP_ID0:
+ case WSA884X_CHIP_ID1:
+ case WSA884X_CHIP_ID2:
+ case WSA884X_CHIP_ID3:
+ case WSA884X_BUS_ID:
+ case WSA884X_PA_FSM_STA0:
+ case WSA884X_PA_FSM_STA1:
+ case WSA884X_PA_FSM_ERR_COND0:
+ case WSA884X_PA_FSM_ERR_COND1:
+ case WSA884X_TEMP_DIN_MSB:
+ case WSA884X_TEMP_DIN_LSB:
+ case WSA884X_TEMP_DOUT_MSB:
+ case WSA884X_TEMP_DOUT_LSB:
+ case WSA884X_VBAT_DIN_MSB:
+ case WSA884X_VBAT_DIN_LSB:
+ case WSA884X_VBAT_DOUT_MSB:
+ case WSA884X_VBAT_DOUT_LSB:
+ case WSA884X_VBAT_CAL_MSB:
+ case WSA884X_VBAT_CAL_LSB:
+ case WSA884X_VPHX_SYS_EN_STATUS:
+ case WSA884X_PIN_STATUS:
+ case WSA884X_SWR_HM_TEST1:
+ case WSA884X_OTP_CTRL1:
+ case WSA884X_OTP_STAT:
+ case WSA884X_WAVG_STA:
+ case WSA884X_INTR_STATUS0:
+ case WSA884X_INTR_STATUS1:
+ case WSA884X_ATE_TEST_MODE:
+ case WSA884X_SPARE_R:
+ return true;
+ }
+ return false;
+}
+
+static bool wsa884x_writeable_register(struct device *dev, unsigned int reg)
+{
+ return !wsa884x_readonly_register(dev, reg);
+}
+
+static bool wsa884x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA884X_ANA_WO_CTL_0:
+ case WSA884X_ANA_WO_CTL_1:
+ return true;
+ }
+ return wsa884x_readonly_register(dev, reg);
+}
+
+static const struct regmap_config wsa884x_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = wsa884x_defaults,
+ .max_register = WSA884X_MAX_REGISTER,
+ .num_reg_defaults = ARRAY_SIZE(wsa884x_defaults),
+ .volatile_reg = wsa884x_volatile_register,
+ .writeable_reg = wsa884x_writeable_register,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .use_single_read = true,
+};
+
+static const struct reg_sequence wsa884x_reg_init[] = {
+ { WSA884X_BOP2_PROG, FIELD_PREP_CONST(WSA884X_BOP2_PROG_BOP2_VTH_MASK, 0x6) |
+ FIELD_PREP_CONST(WSA884X_BOP2_PROG_BOP2_HYST_MASK, 0x6) },
+ { WSA884X_REF_CTRL, (0xd2 & ~WSA884X_REF_CTRL_BG_RDY_SEL_MASK) |
+ FIELD_PREP_CONST(WSA884X_REF_CTRL_BG_RDY_SEL_MASK, 0x1) },
+ /*
+ * Downstream suggests for batteries different than 1-Stacked (1S):
+ * { WSA884X_TOP_CTRL1, 0xd3 & ~WSA884X_TOP_CTRL1_OCP_LOWVBAT_ITH_EN_MASK },
+ */
+ { WSA884X_STB_CTRL1, (0x42 & ~WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_MASK) |
+ FIELD_PREP_CONST(WSA884X_STB_CTRL1_SLOPE_COMP_CURRENT_MASK, 0xd) },
+ { WSA884X_CURRENT_LIMIT, (0x54 & ~WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK) |
+ FIELD_PREP_CONST(WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK, 0x9) },
+ { WSA884X_ZX_CTRL1, (0xf0 & ~WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_MASK) |
+ FIELD_PREP_CONST(WSA884X_ZX_CTRL1_ZX_DET_SW_SEL_MASK, 0x3) },
+ { WSA884X_ILIM_CTRL1, (0xe2 & ~WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_MASK) |
+ FIELD_PREP_CONST(WSA884X_ILIM_CTRL1_ILIM_OFFSET_PB_MASK, 0x3) },
+ { WSA884X_CKWD_CTL_1, FIELD_PREP_CONST(WSA884X_CKWD_CTL_1_VPP_SW_CTL_MASK, 0x0) |
+ FIELD_PREP_CONST(WSA884X_CKWD_CTL_1_CKWD_VCOMP_VREF_SEL_MASK, 0x13) },
+ { WSA884X_PA_FSM_CTL1, (0xfe & ~WSA884X_PA_FSM_CTL1_NOISE_GATE_BLOCK_MASK) |
+ FIELD_PREP_CONST(WSA884X_PA_FSM_CTL1_NOISE_GATE_BLOCK_MASK, 0x4) }, /* == 0xfe */
+ { WSA884X_VBAT_THRM_FLT_CTL, (0x7f & ~WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_MASK) |
+ FIELD_PREP_CONST(WSA884X_VBAT_THRM_FLT_CTL_VBAT_COEF_SEL_MASK, 0x4) },
+ { WSA884X_VBAT_CAL_CTL, FIELD_PREP_CONST(WSA884X_VBAT_CAL_CTL_RESERVE_MASK, 0x2) |
+ FIELD_PREP_CONST(WSA884X_VBAT_CAL_CTL_VBAT_CAL_EN_MASK, 0x1) },
+ { WSA884X_BOP_DEGLITCH_CTL, FIELD_PREP_CONST(WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_SETTING_MASK, 0x8) |
+ FIELD_PREP_CONST(WSA884X_BOP_DEGLITCH_CTL_BOP_DEGLITCH_EN_MASK, 0x1) },
+ { WSA884X_CDC_SPK_DSM_A2_0, 0x0a },
+ { WSA884X_CDC_SPK_DSM_A2_1, 0x08 },
+ { WSA884X_CDC_SPK_DSM_A3_0, 0xf3 },
+ { WSA884X_CDC_SPK_DSM_A3_1, 0x07 },
+ { WSA884X_CDC_SPK_DSM_A4_0, 0x79 },
+ { WSA884X_CDC_SPK_DSM_A5_0, 0x0b },
+ { WSA884X_CDC_SPK_DSM_A6_0, 0x8a },
+ { WSA884X_CDC_SPK_DSM_A7_0, 0x9b },
+ { WSA884X_CDC_SPK_DSM_C_0, FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_0_COEF_C3_MASK, 0x6) |
+ FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_0_COEF_C2_MASK, 0x8) },
+ { WSA884X_CDC_SPK_DSM_C_2, FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_2_COEF_C7_MASK, 0xf) },
+ { WSA884X_CDC_SPK_DSM_C_3, FIELD_PREP_CONST(WSA884X_CDC_SPK_DSM_C_3_COEF_C7_MASK, 0x20) },
+ { WSA884X_CDC_SPK_DSM_R1, 0x83 },
+ { WSA884X_CDC_SPK_DSM_R2, 0x7f },
+ { WSA884X_CDC_SPK_DSM_R3, 0x9d },
+ { WSA884X_CDC_SPK_DSM_R4, 0x82 },
+ { WSA884X_CDC_SPK_DSM_R5, 0x8b },
+ { WSA884X_CDC_SPK_DSM_R6, 0x9b },
+ { WSA884X_CDC_SPK_DSM_R7, 0x3f },
+ /* Speaker mode by default */
+ { WSA884X_DRE_CTL_0, FIELD_PREP_CONST(WSA884X_DRE_CTL_0_PROG_DELAY_MASK, 0x7) },
+ { WSA884X_CLSH_CTL_0, (0x37 & ~WSA884X_CLSH_CTL_0_DLY_CODE_MASK) |
+ FIELD_PREP_CONST(WSA884X_CLSH_CTL_0_DLY_CODE_MASK, 0x6) },
+ /*
+ * WSA884X_CLSH_VTH values for speaker mode with G_21_DB system gain,
+ * battery 1S and rload 8 Ohms.
+ */
+ { WSA884X_CLSH_VTH1, WSA884X_VTH_TO_REG(863), },
+ { WSA884X_CLSH_VTH2, WSA884X_VTH_TO_REG(918), },
+ { WSA884X_CLSH_VTH3, WSA884X_VTH_TO_REG(980), },
+ { WSA884X_CLSH_VTH4, WSA884X_VTH_TO_REG(1043), },
+ { WSA884X_CLSH_VTH5, WSA884X_VTH_TO_REG(1098), },
+ { WSA884X_CLSH_VTH6, WSA884X_VTH_TO_REG(1137), },
+ { WSA884X_CLSH_VTH7, WSA884X_VTH_TO_REG(1184), },
+ { WSA884X_CLSH_VTH8, WSA884X_VTH_TO_REG(1239), },
+ { WSA884X_CLSH_VTH9, WSA884X_VTH_TO_REG(1278), },
+ { WSA884X_CLSH_VTH10, WSA884X_VTH_TO_REG(1380), },
+ { WSA884X_CLSH_VTH11, WSA884X_VTH_TO_REG(1482), },
+ { WSA884X_CLSH_VTH12, WSA884X_VTH_TO_REG(1584), },
+ { WSA884X_CLSH_VTH13, WSA884X_VTH_TO_REG(1663), },
+ { WSA884X_CLSH_VTH14, WSA884X_VTH_TO_REG(1780), },
+ { WSA884X_CLSH_VTH15, WSA884X_VTH_TO_REG(2000), },
+ { WSA884X_ANA_WO_CTL_1, 0x00 },
+ { WSA884X_OTP_REG_38, 0x00 },
+ { WSA884X_OTP_REG_40, FIELD_PREP_CONST(WSA884X_OTP_REG_40_ISENSE_RESCAL_MASK, 0x8) },
+};
+
+static void wsa884x_set_gain_parameters(struct wsa884x_priv *wsa884x)
+{
+ struct regmap *regmap = wsa884x->regmap;
+ unsigned int min_gain, igain, vgain, comp_offset;
+
+ /*
+ * Downstream sets gain parameters customized per boards per use-case.
+ * Choose here some sane values matching knowon users, like QRD8550
+ * board:.
+ *
+ * Values match here downstream:
+ * For WSA884X_RECEIVER - G_7P5_DB system gain
+ * For WSA884X_SPEAKER - G_21_DB system gain
+ */
+ if (wsa884x->dev_mode == WSA884X_RECEIVER) {
+ comp_offset = COMP_OFFSET4;
+ min_gain = G_M6_DB;
+ igain = ISENSE_18_DB;
+ vgain = VSENSE_M12_DB;
+ } else {
+ /* WSA884X_SPEAKER */
+ comp_offset = COMP_OFFSET0;
+ min_gain = G_0_DB;
+ igain = ISENSE_12_DB;
+ vgain = VSENSE_M24_DB;
+ }
+
+ regmap_update_bits(regmap, WSA884X_ISENSE2,
+ WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK,
+ FIELD_PREP(WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK, igain));
+ regmap_update_bits(regmap, WSA884X_VSENSE1,
+ WSA884X_VSENSE1_GAIN_VSENSE_FE_MASK,
+ FIELD_PREP(WSA884X_VSENSE1_GAIN_VSENSE_FE_MASK, vgain));
+ regmap_update_bits(regmap, WSA884X_GAIN_RAMPING_MIN,
+ WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_MASK,
+ FIELD_PREP(WSA884X_GAIN_RAMPING_MIN_MIN_GAIN_MASK, min_gain));
+
+ if (wsa884x->port_enable[WSA884X_PORT_COMP]) {
+ regmap_update_bits(regmap, WSA884X_DRE_CTL_0,
+ WSA884X_DRE_CTL_0_OFFSET_MASK,
+ FIELD_PREP(WSA884X_DRE_CTL_0_OFFSET_MASK, comp_offset));
+
+ regmap_update_bits(regmap, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ FIELD_PREP(WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK, 0x0));
+ } else {
+ regmap_update_bits(regmap, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ FIELD_PREP(WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK, 0x1));
+ }
+}
+
+static void wsa884x_init(struct wsa884x_priv *wsa884x)
+{
+ unsigned int wo_ctl_0;
+ unsigned int variant = 0;
+
+ if (!regmap_read(wsa884x->regmap, WSA884X_OTP_REG_0, &variant))
+ variant = variant & WSA884X_OTP_REG_0_ID_MASK;
+
+ regmap_multi_reg_write(wsa884x->regmap, wsa884x_reg_init,
+ ARRAY_SIZE(wsa884x_reg_init));
+
+ wo_ctl_0 = 0xc;
+ wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK,
+ WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER);
+ /* Assume that compander is enabled by default unless it is haptics sku */
+ if (variant == WSA884X_OTP_ID_WSA8845H)
+ wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK,
+ WSA884X_ANA_WO_CTL_0_PA_AUX_18_DB);
+ else
+ wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_PA_AUX_GAIN_MASK,
+ WSA884X_ANA_WO_CTL_0_PA_AUX_0_DB);
+ regmap_write(wsa884x->regmap, WSA884X_ANA_WO_CTL_0, wo_ctl_0);
+
+ wsa884x_set_gain_parameters(wsa884x);
+
+ wsa884x->hw_init = false;
+}
+
+static int wsa884x_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(&slave->dev);
+ int ret;
+
+ if (status == SDW_SLAVE_UNATTACHED) {
+ wsa884x->hw_init = false;
+ regcache_cache_only(wsa884x->regmap, true);
+ regcache_mark_dirty(wsa884x->regmap);
+ return 0;
+ }
+
+ if (wsa884x->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ regcache_cache_only(wsa884x->regmap, false);
+ ret = regcache_sync(wsa884x->regmap);
+ if (ret < 0) {
+ dev_err(&slave->dev, "Cannot sync regmap cache\n");
+ return ret;
+ }
+
+ wsa884x_init(wsa884x);
+
+ return 0;
+}
+
+static int wsa884x_port_prep(struct sdw_slave *slave,
+ struct sdw_prepare_ch *prepare_ch,
+ enum sdw_port_prep_ops state)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(&slave->dev);
+
+ if (state == SDW_OPS_PORT_POST_PREP)
+ wsa884x->port_prepared[prepare_ch->num - 1] = true;
+ else
+ wsa884x->port_prepared[prepare_ch->num - 1] = false;
+
+ return 0;
+}
+
+static const struct sdw_slave_ops wsa884x_slave_ops = {
+ .update_status = wsa884x_update_status,
+ .port_prep = wsa884x_port_prep,
+};
+
+static int wsa884x_dev_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.enumerated.item[0] = wsa884x->dev_mode;
+
+ return 0;
+}
+
+static int wsa884x_dev_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component);
+
+ if (wsa884x->dev_mode == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ wsa884x->dev_mode = ucontrol->value.enumerated.item[0];
+
+ return 1;
+}
+
+static int wsa884x_get_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(comp);
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+ ucontrol->value.integer.value[0] = wsa884x->port_enable[portidx];
+
+ return 0;
+}
+
+static int wsa884x_set_swr_port(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(comp);
+ struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+ int portidx = mixer->reg;
+
+ if (ucontrol->value.integer.value[0]) {
+ if (wsa884x->port_enable[portidx])
+ return 0;
+
+ wsa884x->port_enable[portidx] = true;
+ } else {
+ if (!wsa884x->port_enable[portidx])
+ return 0;
+
+ wsa884x->port_enable[portidx] = false;
+ }
+
+ return 1;
+}
+
+static int wsa884x_codec_probe(struct snd_soc_component *comp)
+{
+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(comp);
+
+ snd_soc_component_init_regmap(comp, wsa884x->regmap);
+
+ return 0;
+}
+
+static void wsa884x_spkr_post_pmu(struct snd_soc_component *component,
+ struct wsa884x_priv *wsa884x)
+{
+ unsigned int curr_limit, curr_ovrd_en;
+
+ wsa884x_set_gain_parameters(wsa884x);
+ if (wsa884x->dev_mode == WSA884X_RECEIVER) {
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_0,
+ WSA884X_DRE_CTL_0_PROG_DELAY_MASK, 0x3);
+ snd_soc_component_write_field(component, WSA884X_CDC_PATH_MODE,
+ WSA884X_CDC_PATH_MODE_RXD_MODE_MASK,
+ 0x1);
+ snd_soc_component_write_field(component, WSA884X_PWM_CLK_CTL,
+ WSA884X_PWM_CLK_CTL_PWM_CLK_FREQ_SEL_MASK,
+ 0x1);
+ } else {
+ /* WSA884X_SPEAKER */
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_0,
+ WSA884X_DRE_CTL_0_PROG_DELAY_MASK, 0xf);
+ }
+
+ if (wsa884x->port_enable[WSA884X_PORT_PBR]) {
+ curr_ovrd_en = 0x0;
+ curr_limit = 0x15;
+ } else {
+ curr_ovrd_en = 0x1;
+ if (wsa884x->dev_mode == WSA884X_RECEIVER)
+ curr_limit = 0x9;
+ else
+ curr_limit = 0x15;
+ }
+ snd_soc_component_write_field(component, WSA884X_CURRENT_LIMIT,
+ WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_OVRD_EN_MASK,
+ curr_ovrd_en);
+ snd_soc_component_write_field(component, WSA884X_CURRENT_LIMIT,
+ WSA884X_CURRENT_LIMIT_CURRENT_LIMIT_MASK,
+ curr_limit);
+}
+
+static int wsa884x_spkr_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 wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ mutex_lock(&wsa884x->sp_lock);
+ wsa884x->pa_on = true;
+ mutex_unlock(&wsa884x->sp_lock);
+
+ wsa884x_spkr_post_pmu(component, wsa884x);
+
+ snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL,
+ WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK,
+ 0x1);
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL,
+ WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK,
+ 0x0);
+
+ mutex_lock(&wsa884x->sp_lock);
+ wsa884x->pa_on = false;
+ mutex_unlock(&wsa884x->sp_lock);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa884x_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("IN"),
+ SND_SOC_DAPM_SPK("SPKR", wsa884x_spkr_event),
+};
+
+static const DECLARE_TLV_DB_SCALE(pa_gain, -900, 150, -900);
+
+static const struct snd_kcontrol_new wsa884x_snd_controls[] = {
+ SOC_SINGLE_RANGE_TLV("PA Volume", WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_SHIFT,
+ 0x0, 0x1f, 1, pa_gain),
+ SOC_ENUM_EXT("WSA MODE", wsa884x_dev_mode_enum,
+ wsa884x_dev_mode_get, wsa884x_dev_mode_put),
+ SOC_SINGLE_EXT("DAC Switch", WSA884X_PORT_DAC, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("COMP Switch", WSA884X_PORT_COMP, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("BOOST Switch", WSA884X_PORT_BOOST, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("PBR Switch", WSA884X_PORT_PBR, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("VISENSE Switch", WSA884X_PORT_VISENSE, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+ SOC_SINGLE_EXT("CPS Switch", WSA884X_PORT_CPS, 0, 1, 0,
+ wsa884x_get_swr_port, wsa884x_set_swr_port),
+};
+
+static const struct snd_soc_dapm_route wsa884x_audio_map[] = {
+ {"SPKR", NULL, "IN"},
+};
+
+static const struct snd_soc_component_driver wsa884x_component_drv = {
+ .name = "WSA884x",
+ .probe = wsa884x_codec_probe,
+ .controls = wsa884x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa884x_snd_controls),
+ .dapm_widgets = wsa884x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wsa884x_dapm_widgets),
+ .dapm_routes = wsa884x_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wsa884x_audio_map),
+};
+
+static int wsa884x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(dai->dev);
+ int i;
+
+ wsa884x->active_ports = 0;
+ for (i = 0; i < WSA884X_MAX_SWR_PORTS; i++) {
+ if (!wsa884x->port_enable[i])
+ continue;
+
+ wsa884x->port_config[wsa884x->active_ports] = wsa884x_pconfig[i];
+ wsa884x->active_ports++;
+ }
+
+ wsa884x->sconfig.frame_rate = params_rate(params);
+
+ return sdw_stream_add_slave(wsa884x->slave, &wsa884x->sconfig,
+ wsa884x->port_config, wsa884x->active_ports,
+ wsa884x->sruntime);
+}
+
+static int wsa884x_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(dai->dev);
+
+ sdw_stream_remove_slave(wsa884x->slave, wsa884x->sruntime);
+
+ return 0;
+}
+
+static int wsa884x_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *component = dai->component;
+
+ if (mute) {
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ 0x0);
+ snd_soc_component_write_field(component, WSA884X_PA_FSM_EN,
+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK,
+ 0x0);
+
+ } else {
+ snd_soc_component_write_field(component, WSA884X_DRE_CTL_1,
+ WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK,
+ 0x1);
+ snd_soc_component_write_field(component, WSA884X_PA_FSM_EN,
+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK,
+ 0x1);
+ }
+
+ return 0;
+}
+
+static int wsa884x_set_stream(struct snd_soc_dai *dai,
+ void *stream, int direction)
+{
+ struct wsa884x_priv *wsa884x = dev_get_drvdata(dai->dev);
+
+ wsa884x->sruntime = stream;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops wsa884x_dai_ops = {
+ .hw_params = wsa884x_hw_params,
+ .hw_free = wsa884x_hw_free,
+ .mute_stream = wsa884x_mute_stream,
+ .set_stream = wsa884x_set_stream,
+ .mute_unmute_on_trigger = true,
+};
+
+static struct snd_soc_dai_driver wsa884x_dais[] = {
+ {
+ .name = "SPKR",
+ .playback = {
+ .stream_name = "SPKR Playback",
+ .rates = WSA884X_RATES | WSA884X_FRAC_RATES,
+ .formats = WSA884X_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 1,
+ },
+ .ops = &wsa884x_dai_ops,
+ },
+};
+
+static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, 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;
+ long val;
+ int ret;
+
+ guard(mutex)(&wsa884x->sp_lock);
+
+ if (wsa884x->pa_on) {
+ /*
+ * Reading temperature is possible only when Power Amplifier is
+ * off. Report last cached data.
+ */
+ *temp = wsa884x->temperature * 1000;
+ return 0;
+ }
+
+ ret = pm_runtime_resume_and_get(wsa884x->dev);
+ if (ret < 0)
+ return ret;
+
+ mask = WSA884X_PA_FSM_BYP0_DC_CAL_EN_MASK |
+ WSA884X_PA_FSM_BYP0_CLK_WD_EN_MASK |
+ WSA884X_PA_FSM_BYP0_BG_EN_MASK |
+ WSA884X_PA_FSM_BYP0_D_UNMUTE_MASK |
+ WSA884X_PA_FSM_BYP0_SPKR_PROT_EN_MASK |
+ WSA884X_PA_FSM_BYP0_TSADC_EN_MASK;
+ /*
+ * Here and further do not care about read or update failures.
+ * For example, before turning on Power Amplifier for the first
+ * time, reading WSA884X_TEMP_DIN_MSB will always return 0.
+ * Instead, check if returned value is within reasonable
+ * thresholds.
+ */
+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, mask, mask);
+
+ regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL,
+ WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK,
+ FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x0));
+
+ regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_MSB, &dmeas_msb);
+ regmap_read(wsa884x->regmap, WSA884X_TEMP_DIN_LSB, &dmeas_lsb);
+
+ regmap_update_bits(wsa884x->regmap, WSA884X_TADC_VALUE_CTL,
+ WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK,
+ FIELD_PREP(WSA884X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x1));
+
+ regmap_read(wsa884x->regmap, WSA884X_OTP_REG_1, &d1_msb);
+ regmap_read(wsa884x->regmap, WSA884X_OTP_REG_2, &d1_lsb);
+ regmap_read(wsa884x->regmap, WSA884X_OTP_REG_3, &d2_msb);
+ regmap_read(wsa884x->regmap, WSA884X_OTP_REG_4, &d2_lsb);
+
+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_BYP0, 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 = WSA884X_T1_TEMP + (((dmeas - d1) * (WSA884X_T2_TEMP - WSA884X_T1_TEMP))/(d2 - d1));
+
+ dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n",
+ val, dmeas, d1, d2);
+
+ if ((val > WSA884X_LOW_TEMP_THRESHOLD) &&
+ (val < WSA884X_HIGH_TEMP_THRESHOLD)) {
+ wsa884x->temperature = val;
+ *temp = val * 1000;
+ ret = 0;
+ } else {
+ ret = -EAGAIN;
+ }
+
+out:
+ pm_runtime_put_autosuspend(wsa884x->dev);
+
+ return ret;
+}
+
+static umode_t wsa884x_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 wsa884x_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 = wsa884x_get_temp(dev_get_drvdata(dev), temp);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct hwmon_channel_info *const wsa884x_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops wsa884x_hwmon_ops = {
+ .is_visible = wsa884x_hwmon_is_visible,
+ .read = wsa884x_hwmon_read,
+};
+
+static const struct hwmon_chip_info wsa884x_hwmon_chip_info = {
+ .ops = &wsa884x_hwmon_ops,
+ .info = wsa884x_hwmon_info,
+};
+
+static void wsa884x_reset_powerdown(void *data)
+{
+ struct wsa884x_priv *wsa884x = data;
+
+ if (wsa884x->sd_reset)
+ reset_control_assert(wsa884x->sd_reset);
+ else
+ gpiod_direction_output(wsa884x->sd_n, 1);
+}
+
+static void wsa884x_reset_deassert(struct wsa884x_priv *wsa884x)
+{
+ if (wsa884x->sd_reset)
+ reset_control_deassert(wsa884x->sd_reset);
+ else
+ gpiod_direction_output(wsa884x->sd_n, 0);
+}
+
+static void wsa884x_regulator_disable(void *data)
+{
+ regulator_bulk_disable(WSA884X_SUPPLIES_NUM, data);
+}
+
+static int wsa884x_get_reset(struct device *dev, struct wsa884x_priv *wsa884x)
+{
+ wsa884x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(wsa884x->sd_reset))
+ return dev_err_probe(dev, PTR_ERR(wsa884x->sd_reset),
+ "Failed to get reset\n");
+ else if (wsa884x->sd_reset)
+ return 0;
+ /*
+ * else: NULL, so use the backwards compatible way for powerdown-gpios,
+ * which does not handle sharing GPIO properly.
+ */
+ wsa884x->sd_n = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(wsa884x->sd_n))
+ return dev_err_probe(dev, PTR_ERR(wsa884x->sd_n),
+ "Shutdown Control GPIO not found\n");
+
+ return 0;
+}
+
+static int wsa884x_probe(struct sdw_slave *pdev,
+ const struct sdw_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct wsa884x_priv *wsa884x;
+ unsigned int i;
+ int ret;
+
+ wsa884x = devm_kzalloc(dev, sizeof(*wsa884x), GFP_KERNEL);
+ if (!wsa884x)
+ return -ENOMEM;
+
+ mutex_init(&wsa884x->sp_lock);
+
+ for (i = 0; i < WSA884X_SUPPLIES_NUM; i++)
+ wsa884x->supplies[i].supply = wsa884x_supply_name[i];
+
+ ret = devm_regulator_bulk_get(dev, WSA884X_SUPPLIES_NUM,
+ wsa884x->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ret = regulator_bulk_enable(WSA884X_SUPPLIES_NUM, wsa884x->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ ret = devm_add_action_or_reset(dev, wsa884x_regulator_disable,
+ wsa884x->supplies);
+ if (ret)
+ return ret;
+
+ ret = wsa884x_get_reset(dev, wsa884x);
+ if (ret)
+ return ret;
+
+ dev_set_drvdata(dev, wsa884x);
+ wsa884x->slave = pdev;
+ wsa884x->dev = dev;
+ wsa884x->dev_mode = WSA884X_SPEAKER;
+ wsa884x->sconfig.ch_count = 1;
+ wsa884x->sconfig.bps = 1;
+ wsa884x->sconfig.direction = SDW_DATA_DIR_RX;
+ wsa884x->sconfig.type = SDW_STREAM_PDM;
+
+ /*
+ * Port map index starts with 0, however the data port for this codec
+ * are from index 1
+ */
+ if (of_property_read_u32_array(dev->of_node, "qcom,port-mapping", &pdev->m_port_map[1],
+ WSA884X_MAX_SWR_PORTS))
+ dev_dbg(dev, "Static Port mapping not specified\n");
+
+ pdev->prop.sink_ports = GENMASK(WSA884X_MAX_SWR_PORTS - 1, 0);
+ pdev->prop.simple_clk_stop_capable = true;
+ pdev->prop.sink_dpn_prop = wsa884x_sink_dpn_prop;
+ pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+
+ wsa884x_reset_deassert(wsa884x);
+ ret = devm_add_action_or_reset(dev, wsa884x_reset_powerdown, wsa884x);
+ if (ret)
+ return ret;
+
+ wsa884x->regmap = devm_regmap_init_sdw(pdev, &wsa884x_regmap_config);
+ if (IS_ERR(wsa884x->regmap))
+ return dev_err_probe(dev, PTR_ERR(wsa884x->regmap),
+ "regmap_init failed\n");
+
+ /* Start in cache-only until device is enumerated */
+ regcache_cache_only(wsa884x->regmap, true);
+ wsa884x->hw_init = true;
+
+ if (IS_REACHABLE(CONFIG_HWMON)) {
+ struct device *hwmon;
+
+ hwmon = devm_hwmon_device_register_with_info(dev, "wsa884x",
+ wsa884x,
+ &wsa884x_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);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return devm_snd_soc_register_component(dev,
+ &wsa884x_component_drv,
+ wsa884x_dais,
+ ARRAY_SIZE(wsa884x_dais));
+}
+
+static int wsa884x_runtime_suspend(struct device *dev)
+{
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+
+ return 0;
+}
+
+static int wsa884x_runtime_resume(struct device *dev)
+{
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+
+ regcache_cache_only(regmap, false);
+ regcache_sync(regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops wsa884x_pm_ops = {
+ RUNTIME_PM_OPS(wsa884x_runtime_suspend, wsa884x_runtime_resume, NULL)
+};
+
+static const struct sdw_device_id wsa884x_swr_id[] = {
+ SDW_SLAVE_ENTRY(0x0217, 0x204, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, wsa884x_swr_id);
+
+static struct sdw_driver wsa884x_codec_driver = {
+ .driver = {
+ .name = "wsa884x-codec",
+ .pm = pm_ptr(&wsa884x_pm_ops),
+ },
+ .probe = wsa884x_probe,
+ .ops = &wsa884x_slave_ops,
+ .id_table = wsa884x_swr_id,
+};
+module_sdw_driver(wsa884x_codec_driver);
+
+MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
+MODULE_DESCRIPTION("WSA884x codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c
index 28c92d90299e..7de4014e626d 100644
--- a/sound/soc/codecs/zl38060.c
+++ b/sound/soc/codecs/zl38060.c
@@ -387,12 +387,12 @@ static const struct snd_soc_component_driver zl38_component_dev = {
.endianness = 1,
};
-static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
+static int chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
{
struct regmap *regmap = gpiochip_get_data(c);
unsigned int mask = BIT(offset);
- regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0);
+ return regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0);
}
static int chip_gpio_get(struct gpio_chip *c, unsigned int offset)
@@ -422,8 +422,12 @@ chip_direction_output(struct gpio_chip *c, unsigned int offset, int val)
{
struct regmap *regmap = gpiochip_get_data(c);
unsigned int mask = BIT(offset);
+ int ret;
+
+ ret = chip_gpio_set(c, offset, val);
+ if (ret)
+ return ret;
- chip_gpio_set(c, offset, val);
return regmap_update_bits(regmap, REG_GPIO_DIR, mask, mask);
}
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
index 71a58f7ac13a..6bb31b64210a 100644
--- a/sound/soc/dwc/Kconfig
+++ b/sound/soc/dwc/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "DesignWare"
+
config SND_DESIGNWARE_I2S
tristate "Synopsys I2S Device Driver"
depends on HAVE_CLK
@@ -18,3 +20,4 @@ config SND_DESIGNWARE_PCM
This functionality is specially suited for I2S devices that don't have
DMA support.
+endmenu
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index dd5d8d77bdc9..28001e9857d9 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -150,19 +151,58 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static void i2s_enable_dma(struct dw_i2s_dev *dev, u32 stream)
+{
+ u32 dma_reg = i2s_read_reg(dev->i2s_base, I2S_DMACR);
+
+ /* Enable DMA handshake for stream */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_reg |= I2S_DMAEN_TXBLOCK;
+ else
+ dma_reg |= I2S_DMAEN_RXBLOCK;
+
+ i2s_write_reg(dev->i2s_base, I2S_DMACR, dma_reg);
+}
+
+static void i2s_disable_dma(struct dw_i2s_dev *dev, u32 stream)
+{
+ u32 dma_reg = i2s_read_reg(dev->i2s_base, I2S_DMACR);
+
+ /* Disable DMA handshake for stream */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_reg &= ~I2S_DMAEN_TXBLOCK;
+ i2s_write_reg(dev->i2s_base, I2S_RTXDMA, 1);
+ } else {
+ dma_reg &= ~I2S_DMAEN_RXBLOCK;
+ i2s_write_reg(dev->i2s_base, I2S_RRXDMA, 1);
+ }
+ i2s_write_reg(dev->i2s_base, I2S_DMACR, dma_reg);
+}
+
static void i2s_start(struct dw_i2s_dev *dev,
struct snd_pcm_substream *substream)
{
struct i2s_clk_config_data *config = &dev->config;
- i2s_write_reg(dev->i2s_base, IER, 1);
- i2s_enable_irqs(dev, substream->stream, config->chan_nr);
+ u32 reg = IER_IEN;
+
+ if (dev->tdm_slots) {
+ reg |= (dev->tdm_slots - 1) << IER_TDM_SLOTS_SHIFT;
+ reg |= IER_INTF_TYPE;
+ reg |= dev->frame_offset << IER_FRAME_OFF_SHIFT;
+ }
+
+ i2s_write_reg(dev->i2s_base, IER, reg);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
i2s_write_reg(dev->i2s_base, ITER, 1);
else
i2s_write_reg(dev->i2s_base, IRER, 1);
+ if (!(dev->use_pio || dev->is_jh7110))
+ i2s_enable_dma(dev, substream->stream);
+
+ i2s_enable_irqs(dev, substream->stream, config->chan_nr);
i2s_write_reg(dev->i2s_base, CER, 1);
}
@@ -176,8 +216,12 @@ static void i2s_stop(struct dw_i2s_dev *dev,
else
i2s_write_reg(dev->i2s_base, IRER, 0);
+ if (!(dev->use_pio || dev->is_jh7110))
+ i2s_disable_dma(dev, substream->stream);
+
i2s_disable_irqs(dev, substream->stream, 8);
+
if (!dev->active) {
i2s_write_reg(dev->i2s_base, CER, 0);
i2s_write_reg(dev->i2s_base, IER, 0);
@@ -185,25 +229,16 @@ static void i2s_stop(struct dw_i2s_dev *dev,
}
static int dw_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *cpu_dai)
+ struct snd_soc_dai *cpu_dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
- union dw_i2s_snd_dma_data *dma_data = NULL;
-
- if (!(dev->capability & DWC_I2S_RECORD) &&
- (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
- return -EINVAL;
-
- if (!(dev->capability & DWC_I2S_PLAY) &&
- (substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
- return -EINVAL;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = &dev->play_dma_data;
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- dma_data = &dev->capture_dma_data;
+ if (dev->is_jh7110) {
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
- snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
+ dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC;
+ }
return 0;
}
@@ -222,13 +257,15 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
dev->fifo_th - 1);
- i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+ i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
+ dev->tdm_mask << TER_TXSLOT_SHIFT);
} else {
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, RFCR(ch_reg),
dev->fifo_th - 1);
- i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+ i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN |
+ dev->tdm_mask << RER_RXSLOT_SHIFT);
}
}
@@ -265,6 +302,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ if (dev->tdm_slots)
+ config->data_width = 32;
+
config->chan_nr = params_channels(params);
switch (config->chan_nr) {
@@ -306,12 +346,6 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- snd_soc_dai_set_dma_data(dai, substream, NULL);
-}
-
static int dw_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -379,19 +413,70 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
ret = -EINVAL;
break;
}
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ dev->frame_offset = 1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ dev->frame_offset = 0;
+ break;
+ default:
+ dev_err(dev->dev, "DAI format unsupported");
+ return -EINVAL;
+ }
+
return ret;
}
+static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (slot_width != 32)
+ return -EINVAL;
+
+ if (slots < 0 || slots > 16)
+ return -EINVAL;
+
+ if (rx_mask != tx_mask)
+ return -EINVAL;
+
+ if (!rx_mask)
+ return -EINVAL;
+
+ dev->tdm_slots = slots;
+ dev->tdm_mask = rx_mask;
+
+ dev->l_reg = RSLOT_TSLOT(ffs(rx_mask) - 1);
+ dev->r_reg = RSLOT_TSLOT(fls(rx_mask) - 1);
+
+ return 0;
+}
+
+static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
+ return 0;
+}
+
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
+ .probe = dw_i2s_dai_probe,
.startup = dw_i2s_startup,
- .shutdown = dw_i2s_shutdown,
.hw_params = dw_i2s_hw_params,
.prepare = dw_i2s_prepare,
.trigger = dw_i2s_trigger,
.set_fmt = dw_i2s_set_fmt,
+ .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);
@@ -414,6 +499,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);
@@ -568,17 +654,39 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE)
idx = 1;
- /* Set DMA slaves info */
- dev->play_dma_data.pd.data = pdata->play_dma_data;
- dev->capture_dma_data.pd.data = pdata->capture_dma_data;
- dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
- dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
- dev->play_dma_data.pd.max_burst = 16;
- dev->capture_dma_data.pd.max_burst = 16;
- dev->play_dma_data.pd.addr_width = bus_widths[idx];
- dev->capture_dma_data.pd.addr_width = bus_widths[idx];
- dev->play_dma_data.pd.filter = pdata->filter;
- dev->capture_dma_data.pd.filter = pdata->filter;
+
+ if (dev->is_jh7110) {
+ /* Use platform data and snd_dmaengine_dai_dma_data struct at the same time */
+ u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+ u32 idx2;
+
+ if (COMP1_TX_ENABLED(comp1)) {
+ idx2 = COMP1_TX_WORDSIZE_0(comp1);
+ dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
+ dev->play_dma_data.dt.fifo_size = dev->fifo_th * 2 *
+ (fifo_width[idx2]) >> 8;
+ dev->play_dma_data.dt.maxburst = 16;
+ }
+ if (COMP1_RX_ENABLED(comp1)) {
+ idx2 = COMP2_RX_WORDSIZE_0(comp2);
+ dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
+ dev->capture_dma_data.dt.fifo_size = dev->fifo_th * 2 *
+ (fifo_width[idx2] >> 8);
+ dev->capture_dma_data.dt.maxburst = 16;
+ }
+ } else {
+ /* Set DMA slaves info */
+ dev->play_dma_data.pd.data = pdata->play_dma_data;
+ dev->capture_dma_data.pd.data = pdata->capture_dma_data;
+ dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
+ dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
+ dev->play_dma_data.pd.max_burst = 16;
+ dev->capture_dma_data.pd.max_burst = 16;
+ dev->play_dma_data.pd.addr_width = bus_widths[idx];
+ dev->capture_dma_data.pd.addr_width = bus_widths[idx];
+ dev->play_dma_data.pd.filter = pdata->filter;
+ dev->capture_dma_data.pd.filter = pdata->filter;
+ }
return 0;
}
@@ -590,13 +698,9 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
- u32 idx = COMP1_APB_DATA_WIDTH(comp1);
u32 idx2;
int ret;
- if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
- return -EINVAL;
-
ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000);
if (ret < 0)
return ret;
@@ -606,7 +710,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
dev->capability |= DWC_I2S_PLAY;
dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
- dev->play_dma_data.dt.addr_width = bus_widths[idx];
dev->play_dma_data.dt.fifo_size = fifo_depth *
(fifo_width[idx2]) >> 8;
dev->play_dma_data.dt.maxburst = 16;
@@ -616,7 +719,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
dev->capability |= DWC_I2S_RECORD;
dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
- dev->capture_dma_data.dt.addr_width = bus_widths[idx];
dev->capture_dma_data.dt.fifo_size = fifo_depth *
(fifo_width[idx2] >> 8);
dev->capture_dma_data.dt.maxburst = 16;
@@ -626,6 +728,192 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
}
+#ifdef CONFIG_OF
+/* clocks initialization with master mode on JH7110 SoC */
+static int jh7110_i2s_crg_master_init(struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data clks[] = {
+ { .id = "mclk" },
+ { .id = "mclk_ext" },
+ { .id = "mclk_inner" },
+ { .id = "apb" },
+ { .id = "i2sclk" },
+ };
+ struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev);
+ int ret;
+ struct clk *pclk;
+ struct clk *bclk_mst;
+ struct clk *mclk;
+ struct clk *mclk_ext;
+ struct clk *mclk_inner;
+
+ if (IS_ERR(resets))
+ return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n");
+
+ ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks);
+ if (ret)
+ return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n");
+
+ mclk = clks[0].clk;
+ mclk_ext = clks[1].clk;
+ mclk_inner = clks[2].clk;
+ pclk = clks[3].clk;
+ bclk_mst = clks[4].clk;
+
+ ret = clk_prepare_enable(pclk);
+ if (ret)
+ goto exit;
+
+ /* Use inner mclk first and avoid uninitialized gpio for external mclk */
+ ret = clk_set_parent(mclk, mclk_inner);
+ if (ret)
+ goto err_dis_pclk;
+
+ ret = clk_prepare_enable(bclk_mst);
+ if (ret)
+ goto err_dis_pclk;
+
+ /* deassert resets before set clock parent */
+ ret = reset_control_deassert(resets);
+ if (ret)
+ goto err_dis_all;
+
+ /* external clock (12.288MHz) for Audio */
+ ret = clk_set_parent(mclk, mclk_ext);
+ if (ret)
+ goto err_dis_all;
+
+ /* i2sclk will be got and enabled repeatedly later and should be disabled now. */
+ clk_disable_unprepare(bclk_mst);
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ dev->is_jh7110 = true;
+
+ return 0;
+
+err_dis_all:
+ clk_disable_unprepare(bclk_mst);
+err_dis_pclk:
+ clk_disable_unprepare(pclk);
+exit:
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ return ret;
+}
+
+/* clocks initialization with slave mode on JH7110 SoC */
+static int jh7110_i2s_crg_slave_init(struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data clks[] = {
+ { .id = "mclk" },
+ { .id = "mclk_ext" },
+ { .id = "apb" },
+ { .id = "bclk_ext" },
+ { .id = "lrck_ext" },
+ { .id = "bclk" },
+ { .id = "lrck" },
+ { .id = "mclk_inner" },
+ { .id = "i2sclk" },
+ };
+ struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev);
+ int ret;
+ struct clk *pclk;
+ struct clk *bclk_mst;
+ struct clk *bclk_ext;
+ struct clk *lrck_ext;
+ struct clk *bclk;
+ struct clk *lrck;
+ struct clk *mclk;
+ struct clk *mclk_ext;
+ struct clk *mclk_inner;
+
+ if (IS_ERR(resets))
+ return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n");
+
+ ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks);
+ if (ret)
+ return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n");
+
+ mclk = clks[0].clk;
+ mclk_ext = clks[1].clk;
+ pclk = clks[2].clk;
+ bclk_ext = clks[3].clk;
+ lrck_ext = clks[4].clk;
+ bclk = clks[5].clk;
+ lrck = clks[6].clk;
+ mclk_inner = clks[7].clk;
+ bclk_mst = clks[8].clk;
+
+ ret = clk_prepare_enable(pclk);
+ if (ret)
+ goto exit;
+
+ ret = clk_set_parent(mclk, mclk_inner);
+ if (ret)
+ goto err_dis_pclk;
+
+ ret = clk_prepare_enable(bclk_mst);
+ if (ret)
+ goto err_dis_pclk;
+
+ ret = reset_control_deassert(resets);
+ if (ret)
+ goto err_dis_all;
+
+ /* The sources of BCLK and LRCK are the external codec. */
+ ret = clk_set_parent(bclk, bclk_ext);
+ if (ret)
+ goto err_dis_all;
+
+ ret = clk_set_parent(lrck, lrck_ext);
+ if (ret)
+ goto err_dis_all;
+
+ ret = clk_set_parent(mclk, mclk_ext);
+ if (ret)
+ goto err_dis_all;
+
+ /* The i2sclk will be got and enabled repeatedly later and should be disabled now. */
+ clk_disable_unprepare(bclk_mst);
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ dev->is_jh7110 = true;
+
+ return 0;
+
+err_dis_all:
+ clk_disable_unprepare(bclk_mst);
+err_dis_pclk:
+ clk_disable_unprepare(pclk);
+exit:
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ return ret;
+}
+
+/* Special syscon initialization about RX channel with slave mode on JH7110 SoC */
+static int jh7110_i2srx_crg_init(struct dw_i2s_dev *dev)
+{
+ struct regmap *regmap;
+ unsigned int args[2];
+
+ regmap = syscon_regmap_lookup_by_phandle_args(dev->dev->of_node,
+ "starfive,syscon",
+ 2, args);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev->dev, PTR_ERR(regmap), "getting the regmap failed\n");
+
+ /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */
+ regmap_update_bits(regmap, args[0], args[1], args[1]);
+
+ return jh7110_i2s_crg_slave_init(dev);
+}
+
+static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config)
+{
+ struct dw_i2s_dev *dev = container_of(config, struct dw_i2s_dev, config);
+ u32 bclk_rate = config->sample_rate * 64;
+
+ return clk_set_rate(dev->clk, bclk_rate);
+}
+#endif /* CONFIG_OF */
+
static int dw_i2s_probe(struct platform_device *pdev)
{
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
@@ -649,15 +937,25 @@ static int dw_i2s_probe(struct platform_device *pdev)
if (IS_ERR(dev->i2s_base))
return PTR_ERR(dev->i2s_base);
- dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
- if (IS_ERR(dev->reset))
- return PTR_ERR(dev->reset);
+ dev->dev = &pdev->dev;
+ dev->is_jh7110 = false;
+ if (pdata) {
+ if (pdata->i2s_pd_init) {
+ ret = pdata->i2s_pd_init(dev);
+ if (ret)
+ return ret;
+ }
+ }
- ret = reset_control_deassert(dev->reset);
- if (ret)
- return ret;
+ if (!dev->is_jh7110) {
+ dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
+ if (IS_ERR(dev->reset))
+ return PTR_ERR(dev->reset);
- dev->dev = &pdev->dev;
+ ret = reset_control_deassert(dev->reset);
+ if (ret)
+ return ret;
+ }
irq = platform_get_irq_optional(pdev, 0);
if (irq >= 0) {
@@ -696,16 +994,12 @@ static int dw_i2s_probe(struct platform_device *pdev)
goto err_assert_reset;
}
}
- dev->clk = devm_clk_get(&pdev->dev, clk_id);
+ dev->clk = devm_clk_get_enabled(&pdev->dev, clk_id);
if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk);
goto err_assert_reset;
}
-
- ret = clk_prepare_enable(dev->clk);
- if (ret < 0)
- goto err_assert_reset;
}
dev_set_drvdata(&pdev->dev, dev);
@@ -713,13 +1007,15 @@ static int dw_i2s_probe(struct platform_device *pdev)
dw_i2s_dai, 1);
if (ret != 0) {
dev_err(&pdev->dev, "not able to register dai\n");
- goto err_clk_disable;
+ goto err_assert_reset;
}
- if (!pdata) {
+ if (!pdata || dev->is_jh7110) {
if (irq >= 0) {
ret = dw_pcm_register(pdev);
dev->use_pio = true;
+ dev->l_reg = LRBR_LTHR(0);
+ dev->r_reg = RRBR_RTHR(0);
} else {
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
0);
@@ -729,16 +1025,13 @@ static int dw_i2s_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "could not register pcm: %d\n",
ret);
- goto err_clk_disable;
+ goto err_assert_reset;
}
}
pm_runtime_enable(&pdev->dev);
return 0;
-err_clk_disable:
- if (dev->capability & DW_I2S_MASTER)
- clk_disable_unprepare(dev->clk);
err_assert_reset:
reset_control_assert(dev->reset);
return ret;
@@ -748,16 +1041,41 @@ static void dw_i2s_remove(struct platform_device *pdev)
{
struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
- if (dev->capability & DW_I2S_MASTER)
- clk_disable_unprepare(dev->clk);
-
reset_control_assert(dev->reset);
pm_runtime_disable(&pdev->dev);
}
#ifdef CONFIG_OF
+static const struct i2s_platform_data jh7110_i2stx0_data = {
+ .cap = DWC_I2S_PLAY | DW_I2S_MASTER,
+ .channel = TWO_CHANNEL_SUPPORT,
+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .snd_rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .i2s_clk_cfg = jh7110_i2stx0_clk_cfg,
+ .i2s_pd_init = jh7110_i2s_crg_master_init,
+};
+
+static const struct i2s_platform_data jh7110_i2stx1_data = {
+ .cap = DWC_I2S_PLAY | DW_I2S_SLAVE,
+ .channel = TWO_CHANNEL_SUPPORT,
+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .snd_rates = SNDRV_PCM_RATE_8000_192000,
+ .i2s_pd_init = jh7110_i2s_crg_slave_init,
+};
+
+static const struct i2s_platform_data jh7110_i2srx_data = {
+ .cap = DWC_I2S_RECORD | DW_I2S_SLAVE,
+ .channel = TWO_CHANNEL_SUPPORT,
+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .snd_rates = SNDRV_PCM_RATE_8000_192000,
+ .i2s_pd_init = jh7110_i2srx_crg_init,
+};
+
static const struct of_device_id dw_i2s_of_match[] = {
{ .compatible = "snps,designware-i2s", },
+ { .compatible = "starfive,jh7110-i2stx0", .data = &jh7110_i2stx0_data, },
+ { .compatible = "starfive,jh7110-i2stx1", .data = &jh7110_i2stx1_data,},
+ { .compatible = "starfive,jh7110-i2srx", .data = &jh7110_i2srx_data,},
{},
};
@@ -765,16 +1083,16 @@ 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 = {
.probe = dw_i2s_probe,
- .remove_new = dw_i2s_remove,
+ .remove = dw_i2s_remove,
.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/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c
index 9f25631d43d3..a418265c030a 100644
--- a/sound/soc/dwc/dwc-pcm.c
+++ b/sound/soc/dwc/dwc-pcm.c
@@ -31,8 +31,8 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \
int i; \
\
for (i = 0; i < dev->fifo_th; i++) { \
- iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \
- iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \
+ iowrite32(p[tx_ptr][0], dev->i2s_base + dev->l_reg); \
+ iowrite32(p[tx_ptr][1], dev->i2s_base + dev->r_reg); \
period_pos++; \
if (++tx_ptr >= runtime->buffer_size) \
tx_ptr = 0; \
@@ -51,8 +51,8 @@ static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \
int i; \
\
for (i = 0; i < dev->fifo_th; i++) { \
- p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \
- p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \
+ p[rx_ptr][0] = ioread32(dev->i2s_base + dev->l_reg); \
+ p[rx_ptr][1] = ioread32(dev->i2s_base + dev->r_reg); \
period_pos++; \
if (++rx_ptr >= runtime->buffer_size) \
rx_ptr = 0; \
@@ -139,8 +139,8 @@ static int dw_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
snd_soc_set_runtime_hwparams(substream, &dw_pcm_hardware);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
index d64bd4f8fd34..dce88c9ad5f3 100644
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -25,6 +25,13 @@
#define RXFFR 0x014
#define TXFFR 0x018
+/* Enable register fields */
+#define IER_TDM_SLOTS_SHIFT 8
+#define IER_FRAME_OFF_SHIFT 5
+#define IER_FRAME_OFF BIT(5)
+#define IER_INTF_TYPE BIT(1)
+#define IER_IEN BIT(0)
+
/* Interrupt status register fields */
#define ISR_TXFO BIT(5)
#define ISR_TXFE BIT(4)
@@ -46,6 +53,15 @@
#define TFCR(x) (0x40 * x + 0x04C)
#define RFF(x) (0x40 * x + 0x050)
#define TFF(x) (0x40 * x + 0x054)
+#define RSLOT_TSLOT(x) (0x4 * (x) + 0x224)
+
+/* Receive enable register fields */
+#define RER_RXSLOT_SHIFT 8
+#define RER_RXCHEN BIT(0)
+
+/* Transmit enable register fields */
+#define TER_TXSLOT_SHIFT 8
+#define TER_TXCHEN BIT(0)
/* I2SCOMPRegisters */
#define I2S_COMP_PARAM_2 0x01F0
@@ -53,6 +69,12 @@
#define I2S_COMP_VERSION 0x01F8
#define I2S_COMP_TYPE 0x01FC
+#define I2S_RRXDMA 0x01C4
+#define I2S_RTXDMA 0x01CC
+#define I2S_DMACR 0x0200
+#define I2S_DMAEN_RXBLOCK (1 << 16)
+#define I2S_DMAEN_TXBLOCK (1 << 17)
+
/*
* Component parameter register fields - define the I2S block's
* configuration.
@@ -99,6 +121,9 @@ struct dw_i2s_dev {
u32 ccr;
u32 xfer_resolution;
u32 fifo_th;
+ u32 l_reg;
+ u32 r_reg;
+ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
/* data related to DMA transfers b/w i2s and DMAC */
union dw_i2s_snd_dma_data play_dma_data;
@@ -108,6 +133,12 @@ struct dw_i2s_dev {
/* data related to PIO transfers */
bool use_pio;
+
+ /* data related to TDM mode */
+ u32 tdm_slots;
+ u32 tdm_mask;
+ u32 frame_offset;
+
struct snd_pcm_substream __rcu *tx_substream;
struct snd_pcm_substream __rcu *rx_substream;
unsigned int (*tx_fn)(struct dw_i2s_dev *dev,
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 725c530a3636..c4a00b22bc2a 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,13 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-only
-menu "SoC Audio for Freescale CPUs"
+menu "Freescale"
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.
@@ -29,6 +32,7 @@ config SND_SOC_FSL_SAI
config SND_SOC_FSL_MQS
tristate "Medium Quality Sound (MQS) module support"
depends on SND_SOC_FSL_SAI
+ depends on IMX_SCMI_MISC_DRV || !IMX_SCMI_MISC_DRV
select REGMAP_MMIO
help
Say Y if you want to add Medium Quality Sound (MQS)
@@ -103,6 +107,7 @@ config SND_SOC_FSL_XCVR
select REGMAP_MMIO
select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
select SND_SOC_GENERIC_DMAENGINE_PCM
+ select SND_SOC_FSL_UTILS
help
Say Y if you want to add Audio Transceiver (XCVR) support for NXP
iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC,
@@ -121,6 +126,7 @@ config SND_SOC_FSL_UTILS
config SND_SOC_FSL_RPMSG
tristate "NXP Audio Base On RPMSG support"
depends on COMMON_CLK
+ depends on OF && I2C
depends on RPMSG
depends on SND_IMX_SOC || SND_IMX_SOC = n
select SND_SOC_IMX_RPMSG if SND_IMX_SOC != n
@@ -129,6 +135,13 @@ config SND_SOC_FSL_RPMSG
This option is only useful for out-of-tree drivers since
in-tree drivers select it automatically.
+config SND_SOC_FSL_LPC3XXX
+ tristate "SoC Audio for NXP LPC32XX CPUs"
+ depends on ARCH_LPC32XX || COMPILE_TEST
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for the LPC3XXX I2S interface.
+
config SND_SOC_IMX_PCM_DMA
tristate
select SND_SOC_GENERIC_DMAENGINE_PCM
@@ -183,19 +196,6 @@ config SND_SOC_POWERPC_QMC_AUDIO
comment "SoC Audio support for Freescale PPC boards:"
-config SND_SOC_MPC8610_HPCD
- tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
- # I2C is necessary for the CS4270 driver
- depends on MPC8610_HPCD && I2C
- select SND_SOC_FSL_SSI
- select SND_SOC_FSL_UTILS
- select SND_SOC_POWERPC_DMA
- select SND_SOC_CS4270
- select SND_SOC_CS4270_VD33_ERRATA
- default y if MPC8610_HPCD
- help
- Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
-
config SND_SOC_P1022_DS
tristate "ALSA SoC support for the Freescale P1022 DS board"
# I2C is necessary for the WM8776 driver
@@ -307,15 +307,6 @@ config SND_SOC_IMX_SGTL5000
SND_SOC_FSL_ASOC_CARD and SND_SOC_SGTL5000 to use the newer
driver.
-config SND_SOC_IMX_SPDIF
- tristate "SoC Audio support for i.MX boards with S/PDIF"
- select SND_SOC_IMX_PCM_DMA
- select SND_SOC_FSL_SPDIF
- help
- SoC Audio support for i.MX boards with S/PDIF
- Say Y if you want to add support for SoC audio on an i.MX board with
- a S/DPDIF.
-
config SND_SOC_FSL_ASOC_CARD
tristate "Generic ASoC Sound Card with ASRC support"
depends on OF && I2C
@@ -327,6 +318,7 @@ config SND_SOC_FSL_ASOC_CARD
select SND_SOC_FSL_ESAI
select SND_SOC_FSL_SAI
select SND_SOC_FSL_SSI
+ select SND_SOC_FSL_SPDIF
select SND_SOC_TLV320AIC31XX
select SND_SOC_WM8994
select MFD_WM8994
@@ -360,6 +352,7 @@ config SND_SOC_IMX_HDMI
config SND_SOC_IMX_RPMSG
tristate "SoC Audio support for i.MX boards with rpmsg"
depends on RPMSG
+ depends on OF && I2C
select SND_SOC_IMX_PCM_RPMSG
select SND_SOC_IMX_AUDIO_RPMSG
help
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8db7e97d0bd5..d656a9ab54e3 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -1,38 +1,36 @@
# SPDX-License-Identifier: GPL-2.0
-# MPC8610 HPCD Machine Support
-snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
-obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
-
# P1022 DS Machine Support
-snd-soc-p1022-ds-objs := p1022_ds.o
+snd-soc-p1022-ds-y := p1022_ds.o
obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
# P1022 RDK Machine Support
-snd-soc-p1022-rdk-objs := p1022_rdk.o
+snd-soc-p1022-rdk-y := p1022_rdk.o
obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
# Freescale SSI/DMA/SAI/SPDIF Support
-snd-soc-fsl-audmix-objs := fsl_audmix.o
-snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
-snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
-snd-soc-fsl-sai-objs := fsl_sai.o
+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 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
snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
-snd-soc-fsl-spdif-objs := fsl_spdif.o
-snd-soc-fsl-esai-objs := fsl_esai.o
-snd-soc-fsl-micfil-objs := fsl_micfil.o
-snd-soc-fsl-utils-objs := fsl_utils.o
-snd-soc-fsl-dma-objs := fsl_dma.o
-snd-soc-fsl-mqs-objs := fsl_mqs.o
-snd-soc-fsl-easrc-objs := fsl_easrc.o
-snd-soc-fsl-xcvr-objs := fsl_xcvr.o
-snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
-snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o
-snd-soc-fsl-qmc-audio-objs := fsl_qmc_audio.o
+snd-soc-fsl-spdif-y := fsl_spdif.o
+snd-soc-fsl-esai-y := fsl_esai.o
+snd-soc-fsl-micfil-y := fsl_micfil.o
+snd-soc-fsl-utils-y := fsl_utils.o
+snd-soc-fsl-dma-y := fsl_dma.o
+snd-soc-fsl-mqs-y := fsl_mqs.o
+snd-soc-fsl-easrc-y := fsl_easrc.o
+snd-soc-fsl-xcvr-y := fsl_xcvr.o
+snd-soc-fsl-aud2htx-y := fsl_aud2htx.o
+snd-soc-fsl-rpmsg-y := fsl_rpmsg.o
+snd-soc-fsl-qmc-audio-y := fsl_qmc_audio.o
obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
+obj-$(CONFIG_SND_SOC_FSL_LPC3XXX) += snd-soc-fsl-lpc3xxx.o
obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
@@ -57,7 +55,7 @@ obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
# i.MX Platform Support
-snd-soc-imx-audmux-objs := imx-audmux.o
+snd-soc-imx-audmux-y := imx-audmux.o
obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
@@ -66,19 +64,17 @@ obj-$(CONFIG_SND_SOC_IMX_AUDIO_RPMSG) += imx-audio-rpmsg.o
obj-$(CONFIG_SND_SOC_IMX_PCM_RPMSG) += imx-pcm-rpmsg.o
# i.MX Machine Support
-snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-imx-es8328-objs := imx-es8328.o
-snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
-snd-soc-imx-spdif-objs := imx-spdif.o
-snd-soc-imx-audmix-objs := imx-audmix.o
-snd-soc-imx-hdmi-objs := imx-hdmi.o
-snd-soc-imx-rpmsg-objs := imx-rpmsg.o
-snd-soc-imx-card-objs := imx-card.o
+snd-soc-eukrea-tlv320-y := eukrea-tlv320.o
+snd-soc-imx-es8328-y := imx-es8328.o
+snd-soc-imx-sgtl5000-y := imx-sgtl5000.o
+snd-soc-imx-audmix-y := imx-audmix.o
+snd-soc-imx-hdmi-y := imx-hdmi.o
+snd-soc-imx-rpmsg-y := imx-rpmsg.o
+snd-soc-imx-card-y := imx-card.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
-obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
index 8f6396faec9b..de17b103a4cf 100644
--- a/sound/soc/fsl/efika-audio-fabric.c
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -15,8 +15,8 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/delay.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index e65a85feba78..6be074ea0b3f 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -30,9 +30,9 @@
static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
@@ -196,7 +196,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
}
}
- ret = snd_soc_register_card(&eukrea_tlv320);
+ ret = devm_snd_soc_register_card(&pdev->dev, &eukrea_tlv320);
err:
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
@@ -205,11 +205,6 @@ err:
return ret;
}
-static void eukrea_tlv320_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&eukrea_tlv320);
-}
-
static const struct of_device_id imx_tlv320_dt_ids[] = {
{ .compatible = "eukrea,asoc-tlv320"},
{ /* sentinel */ }
@@ -222,7 +217,6 @@ static struct platform_driver eukrea_tlv320_driver = {
.of_match_table = imx_tlv320_dt_ids,
},
.probe = eukrea_tlv320_probe,
- .remove_new = eukrea_tlv320_remove,
};
module_platform_driver(eukrea_tlv320_driver);
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 40870668ee24..2c7eb0baa0f3 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -27,6 +27,8 @@
#include "../codecs/wm8960.h"
#include "../codecs/wm8994.h"
#include "../codecs/tlv320aic31xx.h"
+#include "../codecs/nau8822.h"
+#include "../codecs/wm8904.h"
#define DRIVER_NAME "fsl-asoc-card"
@@ -40,6 +42,7 @@
/**
* struct codec_priv - CODEC private data
+ * @mclk: Main clock of the CODEC
* @mclk_freq: Clock rate of MCLK
* @free_freq: Clock rate of MCLK for hw_free()
* @mclk_id: MCLK (or main clock) id for set_sysclk()
@@ -47,11 +50,12 @@
* @pll_id: PLL id for set_pll()
*/
struct codec_priv {
+ struct clk *mclk;
unsigned long mclk_freq;
unsigned long free_freq;
u32 mclk_id;
- u32 fll_id;
- u32 pll_id;
+ int fll_id;
+ int pll_id;
};
/**
@@ -59,7 +63,9 @@ struct codec_priv {
* @sysclk_freq: SYSCLK rates for set_sysclk()
* @sysclk_dir: SYSCLK directions for set_sysclk()
* @sysclk_id: SYSCLK ids for set_sysclk()
+ * @sysclk_ratio: SYSCLK ratio on sample rate
* @slot_width: Slot width of each frame
+ * @slot_num: Number of slots of each frame
*
* Note: [1] for tx and [0] for rx
*/
@@ -67,7 +73,9 @@ struct cpu_priv {
unsigned long sysclk_freq[2];
u32 sysclk_dir[2];
u32 sysclk_id[2];
+ u32 sysclk_ratio[2];
u32 slot_width;
+ u32 slot_num;
};
/**
@@ -90,10 +98,10 @@ struct cpu_priv {
struct fsl_asoc_card_priv {
struct snd_soc_dai_link dai_link[3];
- struct asoc_simple_jack hp_jack;
- struct asoc_simple_jack mic_jack;
+ struct simple_util_jack hp_jack;
+ struct simple_util_jack mic_jack;
struct platform_device *pdev;
- struct codec_priv codec_priv;
+ struct codec_priv codec_priv[2];
struct cpu_priv cpu_priv;
struct snd_soc_card card;
u8 streams;
@@ -163,13 +171,15 @@ static bool fsl_asoc_card_is_ac97(struct fsl_asoc_card_priv *priv)
static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- struct codec_priv *codec_priv = &priv->codec_priv;
+ struct codec_priv *codec_priv;
+ struct snd_soc_dai *codec_dai;
struct cpu_priv *cpu_priv = &priv->cpu_priv;
struct device *dev = rtd->card->dev;
- unsigned int pll_out;
+ unsigned int pll_out, sysclk_freq;
+ int codec_idx;
int ret;
priv->sample_rate = params_rate(params);
@@ -179,9 +189,14 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
if (fsl_asoc_card_is_ac97(priv))
return 0;
+ if (!cpu_priv->sysclk_freq[tx] && cpu_priv->sysclk_ratio[tx])
+ sysclk_freq = priv->sample_rate * cpu_priv->sysclk_ratio[tx];
+ else
+ sysclk_freq = cpu_priv->sysclk_freq[tx];
+
/* Specific configurations of DAIs starts from here */
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), cpu_priv->sysclk_id[tx],
- cpu_priv->sysclk_freq[tx],
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), cpu_priv->sysclk_id[tx],
+ sysclk_freq,
cpu_priv->sysclk_dir[tx]);
if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set sysclk for cpu dai\n");
@@ -189,7 +204,11 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
}
if (cpu_priv->slot_width) {
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2,
+ if (!cpu_priv->slot_num)
+ cpu_priv->slot_num = 2;
+
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3,
+ cpu_priv->slot_num,
cpu_priv->slot_width);
if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set TDM slot for cpu dai\n");
@@ -198,28 +217,32 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
}
/* Specific configuration for PLL */
- if (codec_priv->pll_id && codec_priv->fll_id) {
- if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
- pll_out = priv->sample_rate * 384;
- else
- pll_out = priv->sample_rate * 256;
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
- ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0),
- codec_priv->pll_id,
- codec_priv->mclk_id,
- codec_priv->mclk_freq, pll_out);
- if (ret) {
- dev_err(dev, "failed to start FLL: %d\n", ret);
- goto fail;
- }
+ if (codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
+ if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
+ pll_out = priv->sample_rate * 384;
+ else
+ pll_out = priv->sample_rate * 256;
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
- codec_priv->fll_id,
- pll_out, SND_SOC_CLOCK_IN);
+ ret = snd_soc_dai_set_pll(codec_dai,
+ codec_priv->pll_id,
+ codec_priv->mclk_id,
+ codec_priv->mclk_freq, pll_out);
+ if (ret) {
+ dev_err(dev, "failed to start FLL: %d\n", ret);
+ goto fail;
+ }
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to set SYSCLK: %d\n", ret);
- goto fail;
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ codec_priv->fll_id,
+ pll_out, SND_SOC_CLOCK_IN);
+
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+ goto fail;
+ }
}
}
@@ -232,30 +255,36 @@ fail:
static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct codec_priv *codec_priv = &priv->codec_priv;
+ struct codec_priv *codec_priv;
+ struct snd_soc_dai *codec_dai;
struct device *dev = rtd->card->dev;
+ int codec_idx;
int ret;
priv->streams &= ~BIT(substream->stream);
- if (!priv->streams && codec_priv->pll_id && codec_priv->fll_id) {
- /* Force freq to be free_freq to avoid error message in codec */
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
- codec_priv->mclk_id,
- codec_priv->free_freq,
- SND_SOC_CLOCK_IN);
- if (ret) {
- dev_err(dev, "failed to switch away from FLL: %d\n", ret);
- return ret;
- }
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
- ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0),
- codec_priv->pll_id, 0, 0, 0);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to stop FLL: %d\n", ret);
- return ret;
+ if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) {
+ /* Force freq to be free_freq to avoid error message in codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ codec_priv->mclk_id,
+ codec_priv->free_freq,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(dev, "failed to switch away from FLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai,
+ codec_priv->pll_id, 0, 0, 0);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to stop FLL: %d\n", ret);
+ return ret;
+ }
}
}
@@ -284,47 +313,25 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-SND_SOC_DAILINK_DEFS(hifi,
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(hifi_fe,
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(hifi_be,
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
static const struct snd_soc_dai_link fsl_asoc_card_dai[] = {
/* Default ASoC DAI Link*/
{
.name = "HiFi",
.stream_name = "HiFi",
.ops = &fsl_asoc_card_ops,
- SND_SOC_DAILINK_REG(hifi),
},
/* DPCM Link between Front-End and Back-End (Optional) */
{
.name = "HiFi-ASRC-FE",
.stream_name = "HiFi-ASRC-FE",
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.dynamic = 1,
- SND_SOC_DAILINK_REG(hifi_fe),
},
{
.name = "HiFi-ASRC-BE",
.stream_name = "HiFi-ASRC-BE",
.be_hw_params_fixup = be_hw_params_fixup,
.ops = &fsl_asoc_card_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.no_pcm = 1,
- SND_SOC_DAILINK_REG(hifi_be),
},
};
@@ -456,11 +463,80 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
return 0;
}
+static int fsl_asoc_card_spdif_init(struct device_node *codec_np[],
+ struct device_node *cpu_np,
+ const char *codec_dai_name[],
+ struct fsl_asoc_card_priv *priv)
+{
+ struct device *dev = &priv->pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ if (!of_node_name_eq(cpu_np, "spdif")) {
+ dev_err(dev, "CPU phandle invalid, should be an SPDIF device\n");
+ return -EINVAL;
+ }
+
+ priv->dai_link[0].playback_only = true;
+ priv->dai_link[0].capture_only = true;
+
+ for (int i = 0; i < 2; i++) {
+ if (!codec_np[i])
+ break;
+
+ if (of_device_is_compatible(codec_np[i], "linux,spdif-dit")) {
+ priv->dai_link[0].capture_only = false;
+ codec_dai_name[i] = "dit-hifi";
+ } else if (of_device_is_compatible(codec_np[i], "linux,spdif-dir")) {
+ priv->dai_link[0].playback_only = false;
+ codec_dai_name[i] = "dir-hifi";
+ }
+ }
+
+ // Old SPDIF DT binding
+ if (!codec_np[0]) {
+ codec_dai_name[0] = snd_soc_dummy_dlc.dai_name;
+ if (of_property_read_bool(np, "spdif-out"))
+ priv->dai_link[0].capture_only = false;
+ if (of_property_read_bool(np, "spdif-in"))
+ priv->dai_link[0].playback_only = false;
+ }
+
+ if (priv->dai_link[0].playback_only && priv->dai_link[0].capture_only) {
+ dev_err(dev, "no enabled S/PDIF DAI link\n");
+ return -EINVAL;
+ }
+
+ if (priv->dai_link[0].playback_only) {
+ priv->dai_link[1].playback_only = true;
+ priv->dai_link[2].playback_only = true;
+ priv->card.dapm_routes = audio_map_tx;
+ priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
+ } else if (priv->dai_link[0].capture_only) {
+ priv->dai_link[1].capture_only = true;
+ priv->dai_link[2].capture_only = true;
+ priv->card.dapm_routes = audio_map_rx;
+ priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
+ }
+
+ // No DAPM routes with old bindings and dummy codec
+ if (!codec_np[0]) {
+ priv->card.dapm_routes = NULL;
+ priv->card.num_dapm_routes = 0;
+ }
+
+ if (codec_np[0] && codec_np[1]) {
+ priv->dai_link[0].num_codecs = 2;
+ priv->dai_link[2].num_codecs = 2;
+ }
+
+ return 0;
+}
+
static int hp_jack_event(struct notifier_block *nb, unsigned long event,
void *data)
{
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
- struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(jack->card);
if (event & SND_JACK_HEADPHONE)
/* Disable speaker if headphone is plugged in */
@@ -477,7 +553,7 @@ static int mic_jack_event(struct notifier_block *nb, unsigned long event,
void *data)
{
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
- struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(jack->card);
if (event & SND_JACK_MICROPHONE)
/* Disable dmic if microphone is plugged in */
@@ -495,14 +571,15 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_pcm_runtime *rtd = list_first_entry(
&card->rtd_list, struct snd_soc_pcm_runtime, list);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct codec_priv *codec_priv = &priv->codec_priv;
+ struct snd_soc_dai *codec_dai;
+ struct codec_priv *codec_priv;
struct device *dev = card->dev;
+ int codec_idx;
int ret;
if (fsl_asoc_card_is_ac97(priv)) {
#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
/*
@@ -517,11 +594,18 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
return 0;
}
- ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
- codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to set sysclk in %s\n", __func__);
- return ret;
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+ codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set sysclk in %s\n", __func__);
+ return ret;
+ }
+
+ if (!IS_ERR_OR_NULL(codec_priv->mclk))
+ clk_prepare_enable(codec_priv->mclk);
}
return 0;
@@ -529,17 +613,21 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
static int fsl_asoc_card_probe(struct platform_device *pdev)
{
- struct device_node *cpu_np, *codec_np, *asrc_np;
+ struct device_node *cpu_np, *asrc_np;
+ struct snd_soc_dai_link_component *codec_comp;
+ struct device_node *codec_np[2];
struct device_node *np = pdev->dev.of_node;
struct platform_device *asrc_pdev = NULL;
struct device_node *bitclkprovider = NULL;
struct device_node *frameprovider = NULL;
struct platform_device *cpu_pdev;
struct fsl_asoc_card_priv *priv;
- struct device *codec_dev = NULL;
- const char *codec_dai_name;
- const char *codec_dev_name;
+ struct device *codec_dev[2] = { NULL, NULL };
+ struct snd_soc_dai_link_component *dlc;
+ const char *codec_dai_name[2];
+ const char *codec_dev_name[2];
u32 asrc_fmt = 0;
+ int codec_idx;
u32 width;
int ret;
@@ -547,10 +635,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ priv->pdev = pdev;
+
cpu_np = of_parse_phandle(np, "audio-cpu", 0);
- /* Give a chance to old DT binding */
+ /* Give a chance to old DT bindings */
if (!cpu_np)
cpu_np = of_parse_phandle(np, "ssi-controller", 0);
+ if (!cpu_np)
+ cpu_np = of_parse_phandle(np, "spdif-controller", 0);
if (!cpu_np) {
dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
ret = -EINVAL;
@@ -564,21 +656,25 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto fail;
}
- codec_np = of_parse_phandle(np, "audio-codec", 0);
- if (codec_np) {
- struct platform_device *codec_pdev;
- struct i2c_client *codec_i2c;
+ codec_np[0] = of_parse_phandle(np, "audio-codec", 0);
+ codec_np[1] = of_parse_phandle(np, "audio-codec", 1);
- codec_i2c = of_find_i2c_device_by_node(codec_np);
- if (codec_i2c) {
- codec_dev = &codec_i2c->dev;
- codec_dev_name = codec_i2c->name;
- }
- if (!codec_dev) {
- codec_pdev = of_find_device_by_node(codec_np);
- if (codec_pdev) {
- codec_dev = &codec_pdev->dev;
- codec_dev_name = codec_pdev->name;
+ for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+ if (codec_np[codec_idx]) {
+ struct platform_device *codec_pdev;
+ struct i2c_client *codec_i2c;
+
+ codec_i2c = of_find_i2c_device_by_node(codec_np[codec_idx]);
+ if (codec_i2c) {
+ codec_dev[codec_idx] = &codec_i2c->dev;
+ codec_dev_name[codec_idx] = codec_i2c->name;
+ }
+ if (!codec_dev[codec_idx]) {
+ codec_pdev = of_find_device_by_node(codec_np[codec_idx]);
+ if (codec_pdev) {
+ codec_dev[codec_idx] = &codec_pdev->dev;
+ codec_dev_name[codec_idx] = codec_pdev->name;
+ }
}
}
}
@@ -588,12 +684,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
asrc_pdev = of_find_device_by_node(asrc_np);
/* Get the MCLK rate only, and leave it controlled by CODEC drivers */
- if (codec_dev) {
- struct clk *codec_clk = clk_get(codec_dev, NULL);
+ for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+ if (codec_dev[codec_idx]) {
+ struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL);
- if (!IS_ERR(codec_clk)) {
- priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
- clk_put(codec_clk);
+ if (!IS_ERR(codec_clk)) {
+ priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk);
+ clk_put(codec_clk);
+ }
}
}
@@ -606,86 +704,142 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
memcpy(priv->dai_link, fsl_asoc_card_dai,
sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
+ /*
+ * "Default ASoC DAI Link": 1 cpus, 2 codecs, 1 platforms
+ * "DPCM Link Front-End": 1 cpus, 1 codecs (dummy), 1 platforms
+ * "DPCM Link Back-End": 1 cpus, 2 codecs
+ * totally 10 components
+ */
+ dlc = devm_kcalloc(&pdev->dev, 10, sizeof(*dlc), GFP_KERNEL);
+ if (!dlc) {
+ ret = -ENOMEM;
+ goto asrc_fail;
+ }
+
+ priv->dai_link[0].cpus = &dlc[0];
+ priv->dai_link[0].num_cpus = 1;
+ priv->dai_link[0].codecs = &dlc[1];
+ priv->dai_link[0].num_codecs = 1;
+ priv->dai_link[0].platforms = &dlc[3];
+ priv->dai_link[0].num_platforms = 1;
+
+ priv->dai_link[1].cpus = &dlc[4];
+ priv->dai_link[1].num_cpus = 1;
+ priv->dai_link[1].codecs = &dlc[5];
+ priv->dai_link[1].num_codecs = 0; /* dummy */
+ priv->dai_link[1].platforms = &dlc[6];
+ priv->dai_link[1].num_platforms = 1;
+
+ priv->dai_link[2].cpus = &dlc[7];
+ priv->dai_link[2].num_cpus = 1;
+ priv->dai_link[2].codecs = &dlc[8];
+ priv->dai_link[2].num_codecs = 1;
priv->card.dapm_routes = audio_map;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
priv->card.driver_name = DRIVER_NAME;
+
+ for (codec_idx = 0; codec_idx < 2; codec_idx++) {
+ priv->codec_priv[codec_idx].fll_id = -1;
+ priv->codec_priv[codec_idx].pll_id = -1;
+ }
+
/* Diversify the card configurations */
if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
- codec_dai_name = "cs42888";
- priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
- priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
+ codec_dai_name[0] = "cs42888";
+ priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv[0].mclk_freq;
+ priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv[0].mclk_freq;
priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.slot_width = 32;
priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
} else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) {
- codec_dai_name = "cs4271-hifi";
- priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK;
+ codec_dai_name[0] = "cs4271-hifi";
+ priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
- codec_dai_name = "sgtl5000";
- priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
+ codec_dai_name[0] = "sgtl5000";
+ priv->codec_priv[0].mclk_id = SGTL5000_SYSCLK;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) {
- codec_dai_name = "tlv320aic32x4-hifi";
+ codec_dai_name[0] = "tlv320aic32x4-hifi";
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) {
- codec_dai_name = "tlv320dac31xx-hifi";
- priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
- priv->dai_link[1].dpcm_capture = 0;
- priv->dai_link[2].dpcm_capture = 0;
+ codec_dai_name[0] = "tlv320dac31xx-hifi";
+ priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
+ priv->dai_link[1].playback_only = 1;
+ priv->dai_link[2].playback_only = 1;
priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
- codec_dai_name = "wm8962";
- priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
- priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
- priv->codec_priv.pll_id = WM8962_FLL;
+ codec_dai_name[0] = "wm8962";
+ priv->codec_priv[0].mclk_id = WM8962_SYSCLK_MCLK;
+ priv->codec_priv[0].fll_id = WM8962_SYSCLK_FLL;
+ priv->codec_priv[0].pll_id = WM8962_FLL;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
- codec_dai_name = "wm8960-hifi";
- priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
- priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
+ codec_dai_name[0] = "wm8960-hifi";
+ priv->codec_priv[0].fll_id = WM8960_SYSCLK_AUTO;
+ priv->codec_priv[0].pll_id = WM8960_SYSCLK_AUTO;
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
} else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
- codec_dai_name = "ac97-hifi";
+ codec_dai_name[0] = "ac97-hifi";
priv->dai_fmt = SND_SOC_DAIFMT_AC97;
priv->card.dapm_routes = audio_map_ac97;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97);
} else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) {
- codec_dai_name = "fsl-mqs-dai";
+ codec_dai_name[0] = "fsl-mqs-dai";
priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
SND_SOC_DAIFMT_CBC_CFC |
SND_SOC_DAIFMT_NB_NF;
- priv->dai_link[1].dpcm_capture = 0;
- priv->dai_link[2].dpcm_capture = 0;
+ priv->dai_link[1].playback_only = 1;
+ priv->dai_link[2].playback_only = 1;
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) {
- codec_dai_name = "wm8524-hifi";
+ codec_dai_name[0] = "wm8524-hifi";
priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
- priv->dai_link[1].dpcm_capture = 0;
- priv->dai_link[2].dpcm_capture = 0;
+ priv->dai_link[1].playback_only = 1;
+ priv->dai_link[2].playback_only = 1;
priv->cpu_priv.slot_width = 32;
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
+ priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
+ priv->cpu_priv.sysclk_ratio[TX] = 256;
} else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
- codec_dai_name = "si476x-codec";
+ codec_dai_name[0] = "si476x-codec";
priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
priv->card.dapm_routes = audio_map_rx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) {
- codec_dai_name = "wm8994-aif1";
+ codec_dai_name[0] = "wm8994-aif1";
priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1;
- priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1;
- priv->codec_priv.pll_id = WM8994_FLL1;
- priv->codec_priv.free_freq = priv->codec_priv.mclk_freq;
+ priv->codec_priv[0].mclk_id = WM8994_FLL_SRC_MCLK1;
+ priv->codec_priv[0].fll_id = WM8994_SYSCLK_FLL1;
+ priv->codec_priv[0].pll_id = WM8994_FLL1;
+ priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq;
priv->card.dapm_routes = NULL;
priv->card.num_dapm_routes = 0;
+ } else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) {
+ codec_dai_name[0] = "nau8822-hifi";
+ priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK;
+ priv->codec_priv[0].fll_id = NAU8822_CLK_PLL;
+ priv->codec_priv[0].pll_id = NAU8822_CLK_PLL;
+ priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
+ if (codec_dev[0])
+ priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL);
+ } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) {
+ codec_dai_name[0] = "wm8904-hifi";
+ priv->codec_priv[0].mclk_id = WM8904_FLL_MCLK;
+ priv->codec_priv[0].fll_id = WM8904_CLK_FLL;
+ priv->codec_priv[0].pll_id = WM8904_FLL_MCLK;
+ priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
+ } else if (of_device_is_compatible(np, "fsl,imx-audio-spdif")) {
+ ret = fsl_asoc_card_spdif_init(codec_np, cpu_np, codec_dai_name, priv);
+ if (ret)
+ goto asrc_fail;
} else {
dev_err(&pdev->dev, "unknown Device Tree compatible\n");
ret = -EINVAL;
@@ -696,18 +850,30 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
* Allow setting mclk-id from the device-tree node. Otherwise, the
* default value for each card configuration is used.
*/
- of_property_read_u32(np, "mclk-id", &priv->codec_priv.mclk_id);
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ of_property_read_u32_index(np, "mclk-id", codec_idx,
+ &priv->codec_priv[codec_idx].mclk_id);
+ }
/* Format info from DT is optional. */
snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider);
if (bitclkprovider || frameprovider) {
unsigned int daifmt = snd_soc_daifmt_parse_format(np, NULL);
+ bool codec_bitclkprovider = false;
+ bool codec_frameprovider = false;
+
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ if (bitclkprovider && codec_np[codec_idx] == bitclkprovider)
+ codec_bitclkprovider = true;
+ if (frameprovider && codec_np[codec_idx] == frameprovider)
+ codec_frameprovider = true;
+ }
- if (codec_np == bitclkprovider)
- daifmt |= (codec_np == frameprovider) ?
+ if (codec_bitclkprovider)
+ daifmt |= (codec_frameprovider) ?
SND_SOC_DAIFMT_CBP_CFP : SND_SOC_DAIFMT_CBP_CFC;
else
- daifmt |= (codec_np == frameprovider) ?
+ daifmt |= (codec_frameprovider) ?
SND_SOC_DAIFMT_CBC_CFP : SND_SOC_DAIFMT_CBC_CFC;
/* Override dai_fmt with value from DT */
@@ -723,7 +889,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
of_node_put(bitclkprovider);
of_node_put(frameprovider);
- if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) {
+ if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]
+ && codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) {
dev_dbg(&pdev->dev, "failed to find codec device\n");
ret = -EPROBE_DEFER;
goto asrc_fail;
@@ -757,13 +924,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/* Initialize sound card */
- priv->pdev = pdev;
priv->card.dev = &pdev->dev;
priv->card.owner = THIS_MODULE;
ret = snd_soc_of_parse_card_name(&priv->card, "model");
if (ret) {
snprintf(priv->name, sizeof(priv->name), "%s-audio",
- fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name);
+ fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name[0]);
priv->card.name = priv->name;
}
priv->card.dai_link = priv->dai_link;
@@ -775,7 +941,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);
@@ -785,11 +951,19 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* Normal DAI Link */
priv->dai_link[0].cpus->of_node = cpu_np;
- priv->dai_link[0].codecs->dai_name = codec_dai_name;
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ codec_comp->dai_name = codec_dai_name[codec_idx];
+ }
- if (!fsl_asoc_card_is_ac97(priv))
- priv->dai_link[0].codecs->of_node = codec_np;
- else {
+ // Old SPDIF DT binding support
+ if (codec_dai_name[0] == snd_soc_dummy_dlc.dai_name)
+ priv->dai_link[0].codecs[0].name = snd_soc_dummy_dlc.name;
+
+ if (!fsl_asoc_card_is_ac97(priv)) {
+ for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
+ codec_comp->of_node = codec_np[codec_idx];
+ }
+ } else {
u32 idx;
ret = of_property_read_u32(cpu_np, "cell-index", &idx);
@@ -799,11 +973,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto asrc_fail;
}
- priv->dai_link[0].codecs->name =
+ priv->dai_link[0].codecs[0].name =
devm_kasprintf(&pdev->dev, GFP_KERNEL,
"ac97-codec.%u",
(unsigned int)idx);
- if (!priv->dai_link[0].codecs->name) {
+ if (!priv->dai_link[0].codecs[0].name) {
ret = -ENOMEM;
goto asrc_fail;
}
@@ -817,10 +991,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* DPCM DAI Links only if ASRC exists */
priv->dai_link[1].cpus->of_node = asrc_np;
priv->dai_link[1].platforms->of_node = asrc_np;
- priv->dai_link[2].codecs->dai_name = codec_dai_name;
- priv->dai_link[2].codecs->of_node = codec_np;
- priv->dai_link[2].codecs->name =
- priv->dai_link[0].codecs->name;
+ for_each_link_codecs((&(priv->dai_link[2])), codec_idx, codec_comp) {
+ codec_comp->dai_name = priv->dai_link[0].codecs[codec_idx].dai_name;
+ codec_comp->of_node = priv->dai_link[0].codecs[codec_idx].of_node;
+ codec_comp->name = priv->dai_link[0].codecs[codec_idx].name;
+ }
priv->dai_link[2].cpus->of_node = cpu_np;
priv->dai_link[2].dai_fmt = priv->dai_fmt;
priv->card.num_links = 3;
@@ -863,15 +1038,16 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/*
- * Properties "hp-det-gpio" and "mic-det-gpio" are optional, and
- * asoc_simple_init_jack uses these properties for creating
+ * Properties "hp-det-gpios" and "mic-det-gpios" are optional, and
+ * simple_util_init_jack() uses these properties for creating
* Headphone Jack and Microphone Jack.
*
* The notifier is initialized in snd_soc_card_jack_new(), then
* snd_soc_jack_notifier_register can be called.
*/
- if (of_property_read_bool(np, "hp-det-gpio")) {
- ret = asoc_simple_init_jack(&priv->card, &priv->hp_jack,
+ if (of_property_read_bool(np, "hp-det-gpios") ||
+ of_property_read_bool(np, "hp-det-gpio") /* deprecated */) {
+ ret = simple_util_init_jack(&priv->card, &priv->hp_jack,
1, NULL, "Headphone Jack");
if (ret)
goto asrc_fail;
@@ -879,8 +1055,9 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb);
}
- if (of_property_read_bool(np, "mic-det-gpio")) {
- ret = asoc_simple_init_jack(&priv->card, &priv->mic_jack,
+ if (of_property_read_bool(np, "mic-det-gpios") ||
+ of_property_read_bool(np, "mic-det-gpio") /* deprecated */) {
+ ret = simple_util_init_jack(&priv->card, &priv->mic_jack,
0, NULL, "Mic Jack");
if (ret)
goto asrc_fail;
@@ -890,7 +1067,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
asrc_fail:
of_node_put(asrc_np);
- of_node_put(codec_np);
+ of_node_put(codec_np[0]);
+ of_node_put(codec_np[1]);
put_device(&cpu_pdev->dev);
fail:
of_node_put(cpu_np);
@@ -911,6 +1089,9 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
{ .compatible = "fsl,imx-audio-wm8524", },
{ .compatible = "fsl,imx-audio-si476x", },
{ .compatible = "fsl,imx-audio-wm8958", },
+ { .compatible = "fsl,imx-audio-nau8822", },
+ { .compatible = "fsl,imx-audio-wm8904", },
+ { .compatible = "fsl,imx-audio-spdif", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index adb8a59de2bd..92fb16f7be45 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -517,7 +517,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate)
regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index));
regmap_update_bits(asrc->regmap, REG_ASRCTR,
- ASRCTR_USRi_MASK(index), 0);
+ ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index),
+ ASRCTR_USR(index));
/* Set the input and output clock sources */
regmap_update_bits(asrc->regmap, REG_ASRCSR,
@@ -780,13 +781,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
- .startup = fsl_asrc_dai_startup,
- .hw_params = fsl_asrc_dai_hw_params,
- .hw_free = fsl_asrc_dai_hw_free,
- .trigger = fsl_asrc_dai_trigger,
-};
-
static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
@@ -797,12 +791,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
+ .probe = fsl_asrc_dai_probe,
+ .startup = fsl_asrc_dai_startup,
+ .hw_params = fsl_asrc_dai_hw_params,
+ .hw_free = fsl_asrc_dai_hw_free,
+ .trigger = fsl_asrc_dai_trigger,
+};
+
#define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_3LE)
static struct snd_soc_dai_driver fsl_asrc_dai = {
- .probe = fsl_asrc_dai_probe,
.playback = {
.stream_name = "ASRC-Playback",
.channels_min = 1,
@@ -930,7 +931,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static struct reg_default fsl_asrc_reg[] = {
+static const struct reg_default fsl_asrc_reg[] = {
{ REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 },
{ REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 },
{ REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 },
@@ -1063,6 +1064,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 +1281,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 +1385,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 +1403,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 +1508,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 = {
@@ -1392,11 +1564,11 @@ MODULE_DEVICE_TABLE(of, fsl_asrc_ids);
static struct platform_driver fsl_asrc_driver = {
.probe = fsl_asrc_probe,
- .remove_new = fsl_asrc_remove,
+ .remove = fsl_asrc_remove,
.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_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 05a7d1588d20..1bba48318e2d 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -130,7 +130,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
{
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
struct snd_dmaengine_dai_dma_data *dma_params_be = NULL;
@@ -156,11 +156,24 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
for_each_dpcm_be(rtd, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
struct snd_pcm_substream *substream_be;
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(be, 0);
+ struct snd_soc_dai *dai_cpu = snd_soc_rtd_to_cpu(be, 0);
+ struct snd_soc_dai *dai_codec = snd_soc_rtd_to_codec(be, 0);
+ struct snd_soc_dai *dai;
if (dpcm->fe != rtd)
continue;
+ /*
+ * With audio graph card, original cpu dai is changed to codec
+ * device in backend, so if cpu dai is dummy device in backend,
+ * get the codec dai device, which is the real hardware device
+ * connected.
+ */
+ if (!snd_soc_dai_is_dummy(dai_cpu))
+ dai = dai_cpu;
+ else
+ dai = dai_codec;
+
substream_be = snd_soc_dpcm_get_substream(be, stream);
dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be);
dev_be = dai->dev;
@@ -173,7 +186,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
}
/* Override dma_data of the Front-End and config its dmaengine */
- dma_params_fe = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_params_fe = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
dma_params_fe->addr = asrc->paddr + asrc->get_fifo_addr(!dir, index);
dma_params_fe->maxburst = dma_params_be->maxburst;
@@ -330,7 +343,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dmaengine_dai_dma_data *dma_data;
struct device *dev = component->dev;
@@ -375,7 +388,7 @@ static int fsl_asrc_dma_startup(struct snd_soc_component *component,
goto dma_chan_err;
}
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
/* Refine the snd_imx_hardware according to caps of DMA. */
ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream,
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 46b0c5dcc4a5..da401561e2de 100644
--- a/sound/soc/fsl/fsl_aud2htx.c
+++ b/sound/soc/fsl/fsl_aud2htx.c
@@ -5,9 +5,8 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -49,10 +48,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
- .trigger = fsl_aud2htx_trigger,
-};
-
static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
@@ -84,8 +79,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+ .probe = fsl_aud2htx_dai_probe,
+ .trigger = fsl_aud2htx_trigger,
+};
+
static struct snd_soc_dai_driver fsl_aud2htx_dai = {
- .probe = fsl_aud2htx_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
@@ -170,7 +169,7 @@ static const struct regmap_config fsl_aud2htx_regmap_config = {
.readable_reg = fsl_aud2htx_readable_reg,
.volatile_reg = fsl_aud2htx_volatile_reg,
.writeable_reg = fsl_aud2htx_writeable_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const struct of_device_id fsl_aud2htx_dt_ids[] = {
@@ -262,7 +261,7 @@ static void fsl_aud2htx_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
+static int fsl_aud2htx_runtime_suspend(struct device *dev)
{
struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
@@ -272,7 +271,7 @@ static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
+static int fsl_aud2htx_runtime_resume(struct device *dev)
{
struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
int ret;
@@ -289,19 +288,17 @@ static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
- SET_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)
+ RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend, fsl_aud2htx_runtime_resume,
+ NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_aud2htx_driver = {
.probe = fsl_aud2htx_probe,
- .remove_new = fsl_aud2htx_remove,
+ .remove = fsl_aud2htx_remove,
.driver = {
.name = "fsl-aud2htx",
- .pm = &fsl_aud2htx_pm_ops,
+ .pm = pm_ptr(&fsl_aud2htx_pm_ops),
.of_match_table = fsl_aud2htx_dt_ids,
},
};
diff --git a/sound/soc/fsl/fsl_aud2htx.h b/sound/soc/fsl/fsl_aud2htx.h
index ad70d6a7694c..cf292e3ccc02 100644
--- a/sound/soc/fsl/fsl_aud2htx.h
+++ b/sound/soc/fsl/fsl_aud2htx.h
@@ -7,7 +7,8 @@
#define _FSL_AUD2HTX_H
#define FSL_AUD2HTX_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE)
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
/* AUD2HTX Register Map */
#define AUD2HTX_CTRL 0x0 /* AUD2HTX Control Register */
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 0ab2c1962117..7981d598ba13 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -326,15 +326,6 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = {
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = FSL_AUDMIX_FORMATS,
},
- .capture = {
- .stream_name = "AUDMIX-Capture-0",
- .channels_min = 8,
- .channels_max = 8,
- .rate_min = 8000,
- .rate_max = 96000,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = FSL_AUDMIX_FORMATS,
- },
.ops = &fsl_audmix_dai_ops,
},
{
@@ -349,8 +340,13 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = {
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = FSL_AUDMIX_FORMATS,
},
+ .ops = &fsl_audmix_dai_ops,
+ },
+ {
+ .id = 2,
+ .name = "audmix-2",
.capture = {
- .stream_name = "AUDMIX-Capture-1",
+ .stream_name = "AUDMIX-Capture-0",
.channels_min = 8,
.channels_max = 8,
.rate_min = 8000,
@@ -492,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;
@@ -516,7 +518,6 @@ static void fsl_audmix_remove(struct platform_device *pdev)
platform_device_unregister(priv->pdev);
}
-#ifdef CONFIG_PM
static int fsl_audmix_runtime_resume(struct device *dev)
{
struct fsl_audmix *priv = dev_get_drvdata(dev);
@@ -544,23 +545,20 @@ static int fsl_audmix_runtime_suspend(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM */
static const struct dev_pm_ops fsl_audmix_pm = {
- SET_RUNTIME_PM_OPS(fsl_audmix_runtime_suspend,
- fsl_audmix_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_audmix_runtime_suspend, fsl_audmix_runtime_resume,
+ NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_audmix_driver = {
.probe = fsl_audmix_probe,
- .remove_new = fsl_audmix_remove,
+ .remove = fsl_audmix_remove,
.driver = {
.name = "fsl-audmix",
.of_match_table = fsl_audmix_ids,
- .pm = &fsl_audmix_pm,
+ .pm = pm_ptr(&fsl_audmix_pm),
},
};
module_platform_driver(fsl_audmix_driver);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 963f9774c883..aca066b5a43c 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -200,7 +200,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
{
struct fsl_dma_private *dma_private = dev_id;
struct snd_pcm_substream *substream = dma_private->substream;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct device *dev = rtd->dev;
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
irqreturn_t ret = IRQ_NONE;
@@ -911,7 +911,7 @@ static struct platform_driver fsl_soc_dma_driver = {
.of_match_table = fsl_soc_dma_ids,
},
.probe = fsl_soc_dma_probe,
- .remove_new = fsl_soc_dma_remove,
+ .remove = fsl_soc_dma_remove,
};
module_platform_driver(fsl_soc_dma_driver);
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 670cbdb361b6..f404a39009e1 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
- .startup = fsl_easrc_startup,
- .trigger = fsl_easrc_trigger,
- .hw_params = fsl_easrc_hw_params,
- .hw_free = fsl_easrc_hw_free,
-};
-
static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev);
@@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+ .probe = fsl_easrc_dai_probe,
+ .startup = fsl_easrc_startup,
+ .trigger = fsl_easrc_trigger,
+ .hw_params = fsl_easrc_hw_params,
+ .hw_free = fsl_easrc_hw_free,
+};
+
static struct snd_soc_dai_driver fsl_easrc_dai = {
- .probe = fsl_easrc_dai_probe,
.playback = {
.stream_name = "ASRC-Playback",
.channels_min = 1,
@@ -1748,7 +1748,7 @@ static const struct regmap_config fsl_easrc_regmap_config = {
.rd_table = &fsl_easrc_readable_table,
.wr_table = &fsl_easrc_writeable_table,
.volatile_table = &fsl_easrc_volatileable_table,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
#ifdef DEBUG
@@ -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;
@@ -1966,25 +2194,39 @@ static int fsl_easrc_probe(struct platform_device *pdev)
&fsl_easrc_dai, 1);
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
- return ret;
+ goto err_pm_disable;
}
ret = devm_snd_soc_register_component(dev, &fsl_asrc_component,
NULL, 0);
if (ret) {
dev_err(&pdev->dev, "failed to register ASoC platform\n");
+ 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:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
}
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);
}
-static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev)
+static int fsl_easrc_runtime_suspend(struct device *dev)
{
struct fsl_asrc *easrc = dev_get_drvdata(dev);
struct fsl_easrc_priv *easrc_priv = easrc->private;
@@ -2001,7 +2243,7 @@ static __maybe_unused int fsl_easrc_runtime_suspend(struct device *dev)
return 0;
}
-static __maybe_unused int fsl_easrc_runtime_resume(struct device *dev)
+static int fsl_easrc_runtime_resume(struct device *dev)
{
struct fsl_asrc *easrc = dev_get_drvdata(dev);
struct fsl_easrc_priv *easrc_priv = easrc->private;
@@ -2081,20 +2323,37 @@ 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 = {
- SET_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)
+ RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume)
};
static struct platform_driver fsl_easrc_driver = {
.probe = fsl_easrc_probe,
- .remove_new = fsl_easrc_remove,
+ .remove = fsl_easrc_remove,
.driver = {
.name = "fsl-easrc",
- .pm = &fsl_easrc_pm_ops,
+ .pm = pm_ptr(&fsl_easrc_pm_ops),
.of_match_table = fsl_easrc_dt_ids,
},
};
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 936f0cd4b06d..cde0b0c6c1ef 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -119,10 +119,10 @@ static irqreturn_t esai_isr(int irq, void *devid)
dev_dbg(&pdev->dev, "isr: Transmission Initialized\n");
if (esr & ESAI_ESR_RFF_MASK)
- dev_warn(&pdev->dev, "isr: Receiving overrun\n");
+ dev_dbg(&pdev->dev, "isr: Receiving overrun\n");
if (esr & ESAI_ESR_TFE_MASK)
- dev_warn(&pdev->dev, "isr: Transmission underrun\n");
+ dev_dbg(&pdev->dev, "isr: Transmission underrun\n");
if (esr & ESAI_ESR_TLS_MASK)
dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
@@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
- .startup = fsl_esai_startup,
- .trigger = fsl_esai_trigger,
- .hw_params = fsl_esai_hw_params,
- .set_sysclk = fsl_esai_set_dai_sysclk,
- .set_fmt = fsl_esai_set_dai_fmt,
- .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
-};
-
static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
@@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
+ .probe = fsl_esai_dai_probe,
+ .startup = fsl_esai_startup,
+ .trigger = fsl_esai_trigger,
+ .hw_params = fsl_esai_hw_params,
+ .set_sysclk = fsl_esai_set_dai_sysclk,
+ .set_fmt = fsl_esai_set_dai_fmt,
+ .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
static struct snd_soc_dai_driver fsl_esai_dai = {
- .probe = fsl_esai_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
@@ -1189,19 +1189,16 @@ 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 = {
.probe = fsl_esai_probe,
- .remove_new = fsl_esai_remove,
+ .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 3f08082a55be..d6cde2757c6d 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
// Copyright 2018 NXP
#include <linux/bitfield.h>
@@ -17,8 +17,10 @@
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/dma/imx-dma.h>
+#include <linux/log2.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>
@@ -28,6 +30,22 @@
#define MICFIL_OSR_DEFAULT 16
+#define MICFIL_NUM_RATES 7
+#define MICFIL_CLK_SRC_NUM 3
+/* clock source ids */
+#define MICFIL_AUDIO_PLL1 0
+#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,
@@ -45,9 +63,12 @@ struct fsl_micfil {
struct clk *mclk;
struct clk *pll8k_clk;
struct clk *pll11k_clk;
+ struct clk *clk_src[MICFIL_CLK_SRC_NUM];
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct sdma_peripheral_config sdmacfg;
struct snd_soc_card *card;
+ struct snd_pcm_hw_constraint_list constraint_rates;
+ unsigned int constraint_rates_list[MICFIL_NUM_RATES];
unsigned int dataline;
char name[32];
int irq[MICFIL_IRQ_LINES];
@@ -56,6 +77,10 @@ struct fsl_micfil {
int vad_init_mode;
int vad_enabled;
int vad_detected;
+ struct fsl_micfil_verid verid;
+ struct fsl_micfil_param param;
+ bool mclk_flag; /* mclk enable flag */
+ bool dec_bypass;
};
struct fsl_micfil_soc_data {
@@ -64,7 +89,13 @@ struct fsl_micfil_soc_data {
unsigned int dataline;
bool imx;
bool use_edma;
+ bool use_verid;
+ bool volume_sx;
u64 formats;
+ int fifo_offset;
+ enum quality default_quality;
+ /* stores const value in formula to calculate range */
+ int rangeadj_const[3][2];
};
static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
@@ -73,6 +104,9 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
.fifo_depth = 8,
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .volume_sx = true,
+ .fifo_offset = 0,
+ .default_quality = QUALITY_VLOW0,
};
static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
@@ -81,6 +115,10 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
.fifo_depth = 32,
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .volume_sx = false,
+ .fifo_offset = 0,
+ .default_quality = QUALITY_MEDIUM,
+ .rangeadj_const = {{27, 7}, {27, 7}, {26, 7}},
};
static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
@@ -90,12 +128,32 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.use_edma = true,
+ .use_verid = true,
+ .volume_sx = false,
+ .fifo_offset = 0,
+ .default_quality = QUALITY_MEDIUM,
+ .rangeadj_const = {{30, 6}, {30, 6}, {29, 6}},
+};
+
+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_LE,
+ .use_edma = true,
+ .use_verid = true,
+ .volume_sx = false,
+ .fifo_offset = -4,
+ .default_quality = QUALITY_MEDIUM,
+ .rangeadj_const = {{34, 6}, {34, 6}, {33, 6}},
};
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);
@@ -115,9 +173,69 @@ static const struct soc_enum fsl_micfil_quality_enum =
static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0);
+static int micfil_get_max_range(struct fsl_micfil *micfil)
+{
+ int max_range;
+
+ switch (micfil->quality) {
+ case QUALITY_HIGH:
+ case QUALITY_VLOW0:
+ max_range = micfil->soc->rangeadj_const[0][0] - micfil->soc->rangeadj_const[0][1] *
+ ilog2(2 * MICFIL_OSR_DEFAULT);
+ break;
+ case QUALITY_MEDIUM:
+ case QUALITY_VLOW1:
+ max_range = micfil->soc->rangeadj_const[1][0] - micfil->soc->rangeadj_const[1][1] *
+ ilog2(MICFIL_OSR_DEFAULT);
+ break;
+ case QUALITY_LOW:
+ case QUALITY_VLOW2:
+ max_range = micfil->soc->rangeadj_const[2][0] - micfil->soc->rangeadj_const[2][1] *
+ ilog2(MICFIL_OSR_DEFAULT);
+ break;
+ default:
+ return 0;
+ }
+ max_range = max_range < 0 ? 0 : max_range;
+
+ return max_range;
+}
+
+static int micfil_range_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int shift = mc->shift;
+ int max_range, new_range;
+
+ new_range = ucontrol->value.integer.value[0];
+ max_range = micfil_get_max_range(micfil);
+ if (new_range > max_range)
+ dev_warn(&micfil->pdev->dev, "range makes channel %d data unreliable\n", shift / 4);
+
+ regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, new_range << shift);
+
+ return 0;
+}
+
static int micfil_set_quality(struct fsl_micfil *micfil)
{
- u32 qsel;
+ int range, max_range;
+ u32 qsel, val;
+ int i;
+
+ if (!micfil->soc->volume_sx) {
+ regmap_read(micfil->regmap, REG_MICFIL_OUT_CTRL, &val);
+ max_range = micfil_get_max_range(micfil);
+ for (i = 0; i < micfil->soc->fifos; i++) {
+ range = (val >> MICFIL_OUTGAIN_CHX_SHIFT(i)) & 0xF;
+ if (range > max_range)
+ dev_warn(&micfil->pdev->dev, "please reset channel %d range\n", i);
+ }
+ }
switch (micfil->quality) {
case QUALITY_HIGH:
@@ -138,6 +256,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,
@@ -148,7 +268,7 @@ static int micfil_set_quality(struct fsl_micfil *micfil)
static int micfil_quality_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);
ucontrol->value.integer.value[0] = micfil->quality;
@@ -159,7 +279,7 @@ static int micfil_quality_get(struct snd_kcontrol *kcontrol,
static int micfil_quality_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);
micfil->quality = ucontrol->value.integer.value[0];
@@ -313,7 +433,34 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
+static const struct snd_kcontrol_new fsl_micfil_range_controls[] = {
+ SOC_SINGLE_EXT("CH0 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH1 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH2 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH3 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH4 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH5 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH6 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+ SOC_SINGLE_EXT("CH7 Range", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0,
+ snd_soc_get_volsw, micfil_range_set),
+};
+
+static const struct snd_kcontrol_new fsl_micfil_volume_sx_controls[] = {
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
@@ -330,6 +477,9 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv),
+};
+
+static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_ENUM_EXT("MICFIL Quality Select",
fsl_micfil_quality_enum,
micfil_quality_get, micfil_quality_set),
@@ -356,6 +506,49 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
};
+static int fsl_micfil_use_verid(struct device *dev)
+{
+ struct fsl_micfil *micfil = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ if (!micfil->soc->use_verid)
+ return 0;
+
+ ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "VERID: 0x%016X\n", val);
+
+ micfil->verid.version = val &
+ (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK);
+ micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT;
+ micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK;
+
+ ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "PARAM: 0x%016X\n", val);
+
+ micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >>
+ MICFIL_PARAM_NUM_HWVAD_SHIFT;
+ micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD;
+ micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE;
+ micfil->param.hwvad = val & MICFIL_PARAM_HWVAD;
+ micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS;
+ micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS;
+ micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER;
+ micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH;
+ micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >>
+ MICFIL_PARAM_FIFO_PTRWID_SHIFT;
+ micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >>
+ MICFIL_PARAM_NPAIR_SHIFT;
+
+ return 0;
+}
+
/* The SRES is a self-negated bit which provides the CPU with the
* capability to initialize the PDM Interface module through the
* slave-bus interface. This bit always reads as zero, and this
@@ -408,6 +601,11 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ if (micfil->constraint_rates.count > 0)
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &micfil->constraint_rates);
+
return 0;
}
@@ -603,23 +801,23 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
/* Enable the module */
ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1,
- MICFIL_CTRL1_PDMIEN);
+ MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN);
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 */
ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1,
- MICFIL_CTRL1_PDMIEN);
+ MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN);
if (ret)
return ret;
@@ -646,7 +844,6 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s
clk = micfil->mclk;
/* Disable clock first, for it was enabled by pm_runtime */
- clk_disable_unprepare(clk);
fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk,
micfil->pll11k_clk, ratio);
ret = clk_prepare_enable(clk);
@@ -662,8 +859,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;
@@ -683,7 +881,41 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
- ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8);
+ micfil->mclk_flag = true;
+
+ /* 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_LE) {
+ 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;
@@ -691,10 +923,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,
@@ -717,24 +953,36 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
- .startup = fsl_micfil_startup,
- .trigger = fsl_micfil_trigger,
- .hw_params = fsl_micfil_hw_params,
-};
+static int fsl_micfil_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(micfil->mclk);
+ micfil->mclk_flag = false;
+
+ return 0;
+}
static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev);
struct device *dev = cpu_dai->dev;
unsigned int val = 0;
- int ret, i;
+ int ret, i, max_range;
- micfil->quality = QUALITY_VLOW0;
+ micfil->quality = micfil->soc->default_quality;
micfil->card = cpu_dai->component->card;
/* set default gain to 2 */
- regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
+ if (micfil->soc->volume_sx) {
+ regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
+ } else {
+ max_range = micfil_get_max_range(micfil);
+ for (i = 1; i < micfil->soc->fifos; i++)
+ max_range |= max_range << 4;
+ regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, max_range);
+ }
/* set DC Remover in bypass mode*/
for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++)
@@ -760,8 +1008,29 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static int fsl_micfil_component_probe(struct snd_soc_component *component)
+{
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(component);
+
+ if (micfil->soc->volume_sx)
+ snd_soc_add_component_controls(component, fsl_micfil_volume_sx_controls,
+ ARRAY_SIZE(fsl_micfil_volume_sx_controls));
+ else
+ snd_soc_add_component_controls(component, fsl_micfil_range_controls,
+ ARRAY_SIZE(fsl_micfil_range_controls));
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
+ .probe = fsl_micfil_dai_probe,
+ .startup = fsl_micfil_startup,
+ .trigger = fsl_micfil_trigger,
+ .hw_params = fsl_micfil_hw_params,
+ .hw_free = fsl_micfil_hw_free,
+};
+
static struct snd_soc_dai_driver fsl_micfil_dai = {
- .probe = fsl_micfil_dai_probe,
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
@@ -774,6 +1043,7 @@ static struct snd_soc_dai_driver fsl_micfil_dai = {
static const struct snd_soc_component_driver fsl_micfil_component = {
.name = "fsl-micfil-dai",
+ .probe = fsl_micfil_component_probe,
.controls = fsl_micfil_snd_controls,
.num_controls = ARRAY_SIZE(fsl_micfil_snd_controls),
.legacy_dai_naming = 1,
@@ -784,7 +1054,7 @@ static const struct reg_default fsl_micfil_reg_defaults[] = {
{REG_MICFIL_CTRL1, 0x00000000},
{REG_MICFIL_CTRL2, 0x00000000},
{REG_MICFIL_STAT, 0x00000000},
- {REG_MICFIL_FIFO_CTRL, 0x00000007},
+ {REG_MICFIL_FIFO_CTRL, 0x0000001F},
{REG_MICFIL_FIFO_STAT, 0x00000000},
{REG_MICFIL_DATACH0, 0x00000000},
{REG_MICFIL_DATACH1, 0x00000000},
@@ -806,22 +1076,46 @@ 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:
case REG_MICFIL_CTRL2:
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:
@@ -833,6 +1127,12 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg)
case REG_MICFIL_VAD0_NDATA:
case REG_MICFIL_VAD0_ZCD:
return true;
+ case REG_MICFIL_FSYNC_CTRL:
+ case REG_MICFIL_VERID:
+ case REG_MICFIL_PARAM:
+ if (micfil->soc->use_verid)
+ return true;
+ fallthrough;
default:
return false;
}
@@ -840,6 +1140,8 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg)
static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg)
{
+ struct fsl_micfil *micfil = dev_get_drvdata(dev);
+
switch (reg) {
case REG_MICFIL_CTRL1:
case REG_MICFIL_CTRL2:
@@ -856,6 +1158,10 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg)
case REG_MICFIL_VAD0_NCONFIG:
case REG_MICFIL_VAD0_ZCD:
return true;
+ case REG_MICFIL_FSYNC_CTRL:
+ if (micfil->soc->use_verid)
+ return true;
+ fallthrough;
default:
return false;
}
@@ -863,16 +1169,18 @@ 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_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_FIFO_STAT:
+ case REG_MICFIL_OUT_STAT:
+ case REG_MICFIL_VERID:
+ case REG_MICFIL_PARAM:
case REG_MICFIL_VAD0_STAT:
case REG_MICFIL_VAD0_NDATA:
return true;
@@ -892,7 +1200,21 @@ static const struct regmap_config fsl_micfil_regmap_config = {
.readable_reg = fsl_micfil_readable_reg,
.volatile_reg = fsl_micfil_volatile_reg,
.writeable_reg = fsl_micfil_writeable_reg,
- .cache_type = REGCACHE_RBTREE,
+ .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 */
@@ -925,7 +1247,7 @@ static irqreturn_t micfil_isr(int irq, void *devid)
regmap_write_bits(micfil->regmap,
REG_MICFIL_STAT,
MICFIL_STAT_CHXF(i),
- 1);
+ MICFIL_STAT_CHXF(i));
}
for (i = 0; i < MICFIL_FIFO_NUM; i++) {
@@ -947,6 +1269,8 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
{
struct fsl_micfil *micfil = (struct fsl_micfil *)devid;
struct platform_device *pdev = micfil->pdev;
+ u32 fifo_stat_reg;
+ u32 out_stat_reg;
u32 stat_reg;
regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg);
@@ -960,9 +1284,17 @@ static irqreturn_t micfil_err_isr(int irq, void *devid)
if (stat_reg & MICFIL_STAT_LOWFREQF) {
dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n");
regmap_write_bits(micfil->regmap, REG_MICFIL_STAT,
- MICFIL_STAT_LOWFREQF, 1);
+ MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF);
}
+ regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg);
+ regmap_write_bits(micfil->regmap, REG_MICFIL_FIFO_STAT,
+ fifo_stat_reg, fifo_stat_reg);
+
+ regmap_read(micfil->regmap, REG_MICFIL_OUT_STAT, &out_stat_reg);
+ regmap_write_bits(micfil->regmap, REG_MICFIL_OUT_STAT,
+ out_stat_reg, out_stat_reg);
+
return IRQ_HANDLED;
}
@@ -1031,6 +1363,9 @@ static irqreturn_t hwvad_err_isr(int irq, void *devid)
return IRQ_HANDLED;
}
+static int fsl_micfil_runtime_suspend(struct device *dev);
+static int fsl_micfil_runtime_resume(struct device *dev);
+
static int fsl_micfil_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1044,7 +1379,7 @@ static int fsl_micfil_probe(struct platform_device *pdev)
return -ENOMEM;
micfil->pdev = pdev;
- strncpy(micfil->name, np->name, sizeof(micfil->name) - 1);
+ strscpy(micfil->name, np->name, sizeof(micfil->name));
micfil->soc = of_device_get_match_data(&pdev->dev);
@@ -1068,14 +1403,32 @@ static int fsl_micfil_probe(struct platform_device *pdev)
fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk,
&micfil->pll11k_clk);
+ micfil->clk_src[MICFIL_AUDIO_PLL1] = micfil->pll8k_clk;
+ micfil->clk_src[MICFIL_AUDIO_PLL2] = micfil->pll11k_clk;
+ micfil->clk_src[MICFIL_CLK_EXT3] = devm_clk_get(&pdev->dev, "clkext3");
+ 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));
@@ -1144,12 +1497,31 @@ 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);
pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = fsl_micfil_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ goto err_pm_get_sync;
+
+ /* Get micfil version */
+ ret = fsl_micfil_use_verid(&pdev->dev);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret);
+
+ ret = pm_runtime_put_sync(&pdev->dev);
+ if (ret < 0 && ret != -ENOSYS)
+ goto err_pm_get_sync;
+
regcache_cache_only(micfil->regmap, true);
/*
@@ -1174,6 +1546,9 @@ static int fsl_micfil_probe(struct platform_device *pdev)
return ret;
+err_pm_get_sync:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ fsl_micfil_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
@@ -1185,19 +1560,20 @@ static void fsl_micfil_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev)
+static int fsl_micfil_runtime_suspend(struct device *dev)
{
struct fsl_micfil *micfil = dev_get_drvdata(dev);
regcache_cache_only(micfil->regmap, true);
- clk_disable_unprepare(micfil->mclk);
+ if (micfil->mclk_flag)
+ clk_disable_unprepare(micfil->mclk);
clk_disable_unprepare(micfil->busclk);
return 0;
}
-static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
+static int fsl_micfil_runtime_resume(struct device *dev)
{
struct fsl_micfil *micfil = dev_get_drvdata(dev);
int ret;
@@ -1206,10 +1582,12 @@ static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
if (ret < 0)
return ret;
- ret = clk_prepare_enable(micfil->mclk);
- if (ret < 0) {
- clk_disable_unprepare(micfil->busclk);
- return ret;
+ if (micfil->mclk_flag) {
+ ret = clk_prepare_enable(micfil->mclk);
+ if (ret < 0) {
+ clk_disable_unprepare(micfil->busclk);
+ return ret;
+ }
}
regcache_cache_only(micfil->regmap, false);
@@ -1219,34 +1597,17 @@ static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused fsl_micfil_suspend(struct device *dev)
-{
- pm_runtime_force_suspend(dev);
-
- return 0;
-}
-
-static int __maybe_unused fsl_micfil_resume(struct device *dev)
-{
- pm_runtime_force_resume(dev);
-
- return 0;
-}
-
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(fsl_micfil_suspend,
- fsl_micfil_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 = {
.probe = fsl_micfil_probe,
- .remove_new = fsl_micfil_remove,
+ .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,
},
};
@@ -1254,4 +1615,4 @@ module_platform_driver(fsl_micfil_driver);
MODULE_AUTHOR("Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>");
MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h
index 9237a1c4cb8f..fdfe4e7125bc 100644
--- a/sound/soc/fsl/fsl_micfil.h
+++ b/sound/soc/fsl/fsl_micfil.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* PDM Microphone Interface for the NXP i.MX SoC
* Copyright 2018 NXP
@@ -24,6 +24,9 @@
#define REG_MICFIL_DC_CTRL 0x64
#define REG_MICFIL_OUT_CTRL 0x74
#define REG_MICFIL_OUT_STAT 0x7C
+#define REG_MICFIL_FSYNC_CTRL 0x80
+#define REG_MICFIL_VERID 0x84
+#define REG_MICFIL_PARAM 0x88
#define REG_MICFIL_VAD0_CTRL1 0x90
#define REG_MICFIL_VAD0_CTRL2 0x94
#define REG_MICFIL_VAD0_STAT 0x98
@@ -39,6 +42,8 @@
#define MICFIL_CTRL1_DBG BIT(28)
#define MICFIL_CTRL1_SRES BIT(27)
#define MICFIL_CTRL1_DBGE BIT(26)
+#define MICFIL_CTRL1_DECFILS BIT(20)
+#define MICFIL_CTRL1_FSYNCEN BIT(16)
#define MICFIL_CTRL1_DISEL_DISABLE 0
#define MICFIL_CTRL1_DISEL_DMA 1
@@ -48,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
@@ -57,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 */
@@ -67,7 +73,7 @@
#define MICFIL_STAT_CHXF(ch) BIT(ch)
/* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */
-#define MICFIL_FIFO_CTRL_FIFOWMK GENMASK(2, 0)
+#define MICFIL_FIFO_CTRL_FIFOWMK GENMASK(4, 0)
/* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */
#define MICFIL_FIFO_STAT_FIFOX_OVER(ch) BIT(ch)
@@ -82,6 +88,29 @@
#define MICFIL_DC_CUTOFF_152Hz 2
#define MICFIL_DC_BYPASS 3
+/* MICFIL VERID Register -- REG_MICFIL_VERID */
+#define MICFIL_VERID_MAJOR_SHIFT 24
+#define MICFIL_VERID_MAJOR_MASK GENMASK(31, 24)
+#define MICFIL_VERID_MINOR_SHIFT 16
+#define MICFIL_VERID_MINOR_MASK GENMASK(23, 16)
+#define MICFIL_VERID_FEATURE_SHIFT 0
+#define MICFIL_VERID_FEATURE_MASK GENMASK(15, 0)
+
+/* MICFIL PARAM Register -- REG_MICFIL_PARAM */
+#define MICFIL_PARAM_NUM_HWVAD_SHIFT 24
+#define MICFIL_PARAM_NUM_HWVAD_MASK GENMASK(27, 24)
+#define MICFIL_PARAM_HWVAD_ZCD BIT(19)
+#define MICFIL_PARAM_HWVAD_ENERGY_MODE BIT(17)
+#define MICFIL_PARAM_HWVAD BIT(16)
+#define MICFIL_PARAM_DC_OUT_BYPASS BIT(11)
+#define MICFIL_PARAM_DC_IN_BYPASS BIT(10)
+#define MICFIL_PARAM_LOW_POWER BIT(9)
+#define MICFIL_PARAM_FIL_OUT_WIDTH BIT(8)
+#define MICFIL_PARAM_FIFO_PTRWID_SHIFT 4
+#define MICFIL_PARAM_FIFO_PTRWID_MASK GENMASK(7, 4)
+#define MICFIL_PARAM_NPAIR_SHIFT 0
+#define MICFIL_PARAM_NPAIR_MASK GENMASK(3, 0)
+
/* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/
#define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24)
#define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16)
@@ -146,4 +175,40 @@
#define MICFIL_HWVAD_ENVELOPE_MODE 0
#define MICFIL_HWVAD_ENERGY_MODE 1
+/**
+ * struct fsl_micfil_verid - version id data
+ * @version: version number
+ * @feature: feature specification number
+ */
+struct fsl_micfil_verid {
+ u32 version;
+ u32 feature;
+};
+
+/**
+ * struct fsl_micfil_param - parameter data
+ * @hwvad_num: the number of HWVADs
+ * @hwvad_zcd: HWVAD zero-cross detector is active
+ * @hwvad_energy_mode: HWVAD energy mode is active
+ * @hwvad: HWVAD is active
+ * @dc_out_bypass: points out if the output DC remover is disabled
+ * @dc_in_bypass: points out if the input DC remover is disabled
+ * @low_power: low power decimation filter
+ * @fil_out_width: filter output width
+ * @fifo_ptrwid: FIFO pointer width
+ * @npair: number of microphone pairs
+ */
+struct fsl_micfil_param {
+ u32 hwvad_num;
+ bool hwvad_zcd;
+ bool hwvad_energy_mode;
+ bool hwvad;
+ bool dc_out_bypass;
+ bool dc_in_bypass;
+ bool low_power;
+ bool fil_out_width;
+ u32 fifo_ptrwid;
+ u32 npair;
+};
+
#endif /* _FSL_MICFIL_H */
diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c
index 49ae7f6267d3..901f840df904 100644
--- a/sound/soc/fsl/fsl_mqs.c
+++ b/sound/soc/fsl/fsl_mqs.c
@@ -6,13 +6,12 @@
// Copyright 2019 NXP
#include <linux/clk.h>
+#include <linux/firmware/imx/sm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
-#include <linux/of.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <sound/soc.h>
@@ -30,10 +29,17 @@
#define MQS_CLK_DIV_MASK (0xFF << 0)
#define MQS_CLK_DIV_SHIFT (0)
+enum reg_type {
+ TYPE_REG_OWN, /* module own register space */
+ TYPE_REG_GPR, /* register in GPR space */
+ TYPE_REG_SM, /* System Manager controls the register */
+};
+
/**
* struct fsl_mqs_soc_data - soc specific data
*
- * @use_gpr: control register is in General Purpose Register group
+ * @type: control register space type
+ * @sm_index: index from definition in system manager
* @ctrl_off: control register offset
* @en_mask: enable bit mask
* @en_shift: enable bit shift
@@ -45,7 +51,8 @@
* @div_shift: clock divider bit shift
*/
struct fsl_mqs_soc_data {
- bool use_gpr;
+ enum reg_type type;
+ int sm_index;
int ctrl_off;
int en_mask;
int en_shift;
@@ -70,6 +77,29 @@ struct fsl_mqs {
#define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
#define FSL_MQS_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct fsl_mqs *mqs_priv = context;
+ int num = 1;
+
+ if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) &&
+ mqs_priv->soc->ctrl_off == reg)
+ return scmi_imx_misc_ctrl_get(mqs_priv->soc->sm_index, &num, val);
+
+ return -EINVAL;
+};
+
+static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct fsl_mqs *mqs_priv = context;
+
+ if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) &&
+ mqs_priv->soc->ctrl_off == reg)
+ return scmi_imx_misc_ctrl_set(mqs_priv->soc->sm_index, val);
+
+ return -EINVAL;
+};
+
static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -184,6 +214,13 @@ static const struct regmap_config fsl_mqs_regmap_config = {
.cache_type = REGCACHE_NONE,
};
+static const struct regmap_config fsl_mqs_sm_regmap = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_read = fsl_mqs_sm_read,
+ .reg_write = fsl_mqs_sm_write,
+};
+
static int fsl_mqs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -202,7 +239,7 @@ static int fsl_mqs_probe(struct platform_device *pdev)
*/
mqs_priv->soc = of_device_get_match_data(&pdev->dev);
- if (mqs_priv->soc->use_gpr) {
+ if (mqs_priv->soc->type == TYPE_REG_GPR) {
gpr_np = of_parse_phandle(np, "gpr", 0);
if (!gpr_np) {
dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
@@ -215,6 +252,16 @@ static int fsl_mqs_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get gpr regmap\n");
return PTR_ERR(mqs_priv->regmap);
}
+ } else if (mqs_priv->soc->type == TYPE_REG_SM) {
+ mqs_priv->regmap = devm_regmap_init(&pdev->dev,
+ NULL,
+ mqs_priv,
+ &fsl_mqs_sm_regmap);
+ if (IS_ERR(mqs_priv->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ PTR_ERR(mqs_priv->regmap));
+ return PTR_ERR(mqs_priv->regmap);
+ }
} else {
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
@@ -261,7 +308,6 @@ static void fsl_mqs_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#ifdef CONFIG_PM
static int fsl_mqs_runtime_resume(struct device *dev)
{
struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
@@ -295,18 +341,14 @@ static int fsl_mqs_runtime_suspend(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops fsl_mqs_pm_ops = {
- SET_RUNTIME_PM_OPS(fsl_mqs_runtime_suspend,
- fsl_mqs_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_mqs_runtime_suspend, fsl_mqs_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
- .use_gpr = false,
+ .type = TYPE_REG_OWN,
.ctrl_off = REG_MQS_CTRL,
.en_mask = MQS_EN_MASK,
.en_shift = MQS_EN_SHIFT,
@@ -319,7 +361,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
};
static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
- .use_gpr = true,
+ .type = TYPE_REG_GPR,
.ctrl_off = IOMUXC_GPR2,
.en_mask = IMX6SX_GPR2_MQS_EN_MASK,
.en_shift = IMX6SX_GPR2_MQS_EN_SHIFT,
@@ -332,7 +374,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
};
static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
- .use_gpr = true,
+ .type = TYPE_REG_GPR,
.ctrl_off = 0x20,
.en_mask = BIT(1),
.en_shift = 1,
@@ -344,21 +386,80 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
.div_shift = 8,
};
+static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = {
+ .type = TYPE_REG_SM,
+ .sm_index = SCMI_IMX95_CTRL_MQS1_SETTINGS,
+ .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_imx95_netc_data = {
+ .type = TYPE_REG_GPR,
+ .ctrl_off = 0x0,
+ .en_mask = BIT(2),
+ .en_shift = 2,
+ .rst_mask = BIT(3),
+ .rst_shift = 3,
+ .osr_mask = BIT(4),
+ .osr_shift = 4,
+ .div_mask = GENMASK(16, 9),
+ .div_shift = 9,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx943_aon_data = {
+ .type = TYPE_REG_SM,
+ .sm_index = SCMI_IMX94_CTRL_MQS1_SETTINGS,
+ .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_SM,
+ .sm_index = SCMI_IMX94_CTRL_MQS2_SETTINGS,
+ .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);
static struct platform_driver fsl_mqs_driver = {
.probe = fsl_mqs_probe,
- .remove_new = fsl_mqs_remove,
+ .remove = fsl_mqs_remove,
.driver = {
.name = "fsl-mqs",
.of_match_table = fsl_mqs_dt_ids,
- .pm = &fsl_mqs_pm_ops,
+ .pm = pm_ptr(&fsl_mqs_pm_ops),
},
};
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 7cbb8e4758cc..3de448ef724c 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -21,9 +21,13 @@ struct qmc_dai {
char *name;
int id;
struct device *dev;
- struct qmc_chan *qmc_chan;
unsigned int nb_tx_ts;
unsigned int nb_rx_ts;
+
+ unsigned int nb_chans_avail;
+ unsigned int nb_chans_used_tx;
+ unsigned int nb_chans_used_rx;
+ struct qmc_chan **qmc_chans;
};
struct qmc_audio {
@@ -35,11 +39,18 @@ struct qmc_audio {
struct qmc_dai_prtd {
struct qmc_dai *qmc_dai;
- dma_addr_t dma_buffer_start;
- dma_addr_t period_ptr_submitted;
- dma_addr_t period_ptr_ended;
- dma_addr_t dma_buffer_end;
- size_t period_size;
+
+ snd_pcm_uframes_t buffer_ended;
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_uframes_t period_size;
+
+ dma_addr_t ch_dma_addr_start;
+ dma_addr_t ch_dma_addr_current;
+ dma_addr_t ch_dma_addr_end;
+ size_t ch_dma_size;
+ size_t ch_dma_offset;
+
+ unsigned int channels;
struct snd_pcm_substream *substream;
};
@@ -54,10 +65,22 @@ static int qmc_audio_pcm_construct(struct snd_soc_component *component,
return ret;
snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
- 64*1024, 64*1024);
+ 64 * 1024, 64 * 1024);
return 0;
}
+static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access)
+{
+ switch (access) {
+ case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
+ case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
@@ -65,66 +88,111 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
- prtd->dma_buffer_start = runtime->dma_addr;
- prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params);
- prtd->period_size = params_period_bytes(params);
- prtd->period_ptr_submitted = prtd->dma_buffer_start;
- prtd->period_ptr_ended = prtd->dma_buffer_start;
+ /*
+ * In interleaved mode, the driver uses one QMC channel for all audio
+ * channels whereas in non-interleaved mode, it uses one QMC channel per
+ * audio channel.
+ */
+ prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ?
+ 1 : params_channels(params);
+
prtd->substream = substream;
+ prtd->buffer_ended = 0;
+ prtd->buffer_size = params_buffer_size(params);
+ prtd->period_size = params_period_size(params);
+
+ prtd->ch_dma_addr_start = runtime->dma_addr;
+ prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels;
+ prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset;
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+ prtd->ch_dma_size = params_period_bytes(params) / prtd->channels;
+
+ return 0;
+}
+
+static void qmc_audio_pcm_write_complete(void *context);
+
+static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < prtd->channels; i++) {
+ ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chans[i],
+ prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
+ prtd->ch_dma_size,
+ i == prtd->channels - 1 ? qmc_audio_pcm_write_complete :
+ NULL, prtd);
+ if (ret) {
+ dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+
return 0;
}
static void qmc_audio_pcm_write_complete(void *context)
{
struct qmc_dai_prtd *prtd = context;
- int ret;
- prtd->period_ptr_ended += prtd->period_size;
- if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
- prtd->period_ptr_ended = prtd->dma_buffer_start;
+ prtd->buffer_ended += prtd->period_size;
+ if (prtd->buffer_ended >= prtd->buffer_size)
+ prtd->buffer_ended = 0;
- prtd->period_ptr_submitted += prtd->period_size;
- if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
- prtd->period_ptr_submitted = prtd->dma_buffer_start;
+ prtd->ch_dma_addr_current += prtd->ch_dma_size;
+ if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
- ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
- prtd->period_ptr_submitted, prtd->period_size,
- qmc_audio_pcm_write_complete, prtd);
- if (ret) {
- dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n",
- ret);
- }
+ qmc_audio_pcm_write_submit(prtd);
snd_pcm_period_elapsed(prtd->substream);
}
-static void qmc_audio_pcm_read_complete(void *context, size_t length)
+static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags);
+
+static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)
{
- struct qmc_dai_prtd *prtd = context;
+ unsigned int i;
int ret;
- if (length != prtd->period_size) {
- dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
- length, prtd->period_size);
+ for (i = 0; i < prtd->channels; i++) {
+ ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chans[i],
+ prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,
+ prtd->ch_dma_size,
+ i == prtd->channels - 1 ? qmc_audio_pcm_read_complete :
+ NULL, prtd);
+ if (ret) {
+ dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",
+ i, ret);
+ return ret;
+ }
}
- prtd->period_ptr_ended += prtd->period_size;
- if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
- prtd->period_ptr_ended = prtd->dma_buffer_start;
+ return 0;
+}
- prtd->period_ptr_submitted += prtd->period_size;
- if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
- prtd->period_ptr_submitted = prtd->dma_buffer_start;
+static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
+{
+ struct qmc_dai_prtd *prtd = context;
- ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
- prtd->period_ptr_submitted, prtd->period_size,
- qmc_audio_pcm_read_complete, prtd);
- if (ret) {
- dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n",
- ret);
+ if (length != prtd->ch_dma_size) {
+ dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
+ length, prtd->ch_dma_size);
}
+ prtd->buffer_ended += prtd->period_size;
+ if (prtd->buffer_ended >= prtd->buffer_size)
+ prtd->buffer_ended = 0;
+
+ prtd->ch_dma_addr_current += prtd->ch_dma_size;
+ if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+
+ qmc_audio_pcm_read_submit(prtd);
+
snd_pcm_period_elapsed(prtd->substream);
}
@@ -141,56 +209,39 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ prtd->buffer_ended = 0;
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* Submit first chunk ... */
- ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
- prtd->period_ptr_submitted, prtd->period_size,
- qmc_audio_pcm_write_complete, prtd);
- if (ret) {
- dev_err(component->dev, "write_submit failed %d\n",
- ret);
+ ret = qmc_audio_pcm_write_submit(prtd);
+ if (ret)
return ret;
- }
/* ... prepare next one ... */
- prtd->period_ptr_submitted += prtd->period_size;
- if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
- prtd->period_ptr_submitted = prtd->dma_buffer_start;
+ prtd->ch_dma_addr_current += prtd->ch_dma_size;
+ if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
/* ... and send it */
- ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
- prtd->period_ptr_submitted, prtd->period_size,
- qmc_audio_pcm_write_complete, prtd);
- if (ret) {
- dev_err(component->dev, "write_submit failed %d\n",
- ret);
+ ret = qmc_audio_pcm_write_submit(prtd);
+ if (ret)
return ret;
- }
} else {
/* Submit first chunk ... */
- ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
- prtd->period_ptr_submitted, prtd->period_size,
- qmc_audio_pcm_read_complete, prtd);
- if (ret) {
- dev_err(component->dev, "read_submit failed %d\n",
- ret);
+ ret = qmc_audio_pcm_read_submit(prtd);
+ if (ret)
return ret;
- }
/* ... prepare next one ... */
- prtd->period_ptr_submitted += prtd->period_size;
- if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
- prtd->period_ptr_submitted = prtd->dma_buffer_start;
+ prtd->ch_dma_addr_current += prtd->ch_dma_size;
+ if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)
+ prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
/* ... and send it */
- ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
- prtd->period_ptr_submitted, prtd->period_size,
- qmc_audio_pcm_read_complete, prtd);
- if (ret) {
- dev_err(component->dev, "write_submit failed %d\n",
- ret);
+ ret = qmc_audio_pcm_read_submit(prtd);
+ if (ret)
return ret;
- }
}
break;
@@ -215,13 +266,12 @@ static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *compone
{
struct qmc_dai_prtd *prtd = substream->runtime->private_data;
- return bytes_to_frames(substream->runtime,
- prtd->period_ptr_ended - prtd->dma_buffer_start);
+ return prtd->buffer_ended;
}
static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
- const struct of_phandle_args *args,
- const char **dai_name)
+ const struct of_phandle_args *args,
+ const char **dai_name)
{
struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
struct snd_soc_dai_driver *dai_driver;
@@ -243,12 +293,13 @@ static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_NONINTERLEAVED |
SNDRV_PCM_INFO_PAUSE,
.period_bytes_min = 32,
- .period_bytes_max = 64*1024,
+ .period_bytes_max = 64 * 1024,
.periods_min = 2,
- .periods_max = 2*1024,
- .buffer_bytes_max = 64*1024,
+ .periods_max = 2 * 1024,
+ .buffer_bytes_max = 64 * 1024,
};
static int qmc_audio_pcm_open(struct snd_soc_component *component,
@@ -266,7 +317,7 @@ static int qmc_audio_pcm_open(struct snd_soc_component *component,
return ret;
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
- if (prtd == NULL)
+ if (!prtd)
return -ENOMEM;
runtime->private_data = prtd;
@@ -329,13 +380,13 @@ static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai,
ch.max = nb_ts;
break;
case 16:
- ch.max = nb_ts/2;
+ ch.max = nb_ts / 2;
break;
case 32:
- ch.max = nb_ts/4;
+ ch.max = nb_ts / 4;
break;
case 64:
- ch.max = nb_ts/8;
+ ch.max = nb_ts / 8;
break;
default:
dev_err(qmc_dai->dev, "format physical width %u not supported\n",
@@ -356,9 +407,8 @@ static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params
return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
}
-static int qmc_dai_hw_rule_capture_channels_by_format(
- struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct qmc_dai *qmc_dai = rule->private;
@@ -372,8 +422,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
unsigned int channels = params_channels(params);
unsigned int slot_width;
+ snd_pcm_format_t format;
struct snd_mask f_new;
- unsigned int i;
if (!channels || channels > nb_ts) {
dev_err(qmc_dai->dev, "channels %u not supported\n",
@@ -384,52 +434,41 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
slot_width = (nb_ts / channels) * 8;
snd_mask_none(&f_new);
- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
- if (snd_mask_test(f_old, i)) {
- if (snd_pcm_format_physical_width(i) <= slot_width)
- snd_mask_set(&f_new, i);
+ pcm_for_each_format(format) {
+ if (snd_mask_test_format(f_old, format)) {
+ if (snd_pcm_format_physical_width(format) <= slot_width)
+ snd_mask_set_format(&f_new, format);
}
}
return snd_mask_refine(f_old, &f_new);
}
-static int qmc_dai_hw_rule_playback_format_by_channels(
- struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct qmc_dai *qmc_dai = rule->private;
return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
}
-static int qmc_dai_hw_rule_capture_format_by_channels(
- struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct qmc_dai *qmc_dai = rule->private;
return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
}
-static int qmc_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,
+ struct qmc_dai *qmc_dai)
{
- struct qmc_dai_prtd *prtd = substream->runtime->private_data;
snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
- struct qmc_dai *qmc_dai;
unsigned int frame_bits;
+ u64 access;
int ret;
- qmc_dai = qmc_dai_get_data(dai);
- if (!qmc_dai) {
- dev_err(dai->dev, "Invalid dai\n");
- return -EINVAL;
- }
-
- prtd->qmc_dai = qmc_dai;
-
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
@@ -444,7 +483,7 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream,
hw_rule_channels_by_format, qmc_dai,
SNDRV_PCM_HW_PARAM_FORMAT, -1);
if (ret) {
- dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret);
+ dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret);
return ret;
}
@@ -452,27 +491,86 @@ static int qmc_dai_startup(struct snd_pcm_substream *substream,
hw_rule_format_by_channels, qmc_dai,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
if (ret) {
- dev_err(dai->dev, "Failed to add format rule (%d)\n", ret);
+ dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret);
+ return ret;
+ }
+
+ ret = snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ frame_bits);
+ if (ret < 0) {
+ dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+ return ret;
+ }
+
+ access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
+ 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+ ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
+ access);
+ if (ret) {
+ dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);
return ret;
}
+ return 0;
+}
+
+static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream,
+ struct qmc_dai *qmc_dai)
+{
+ unsigned int frame_bits;
+ u64 access;
+ int ret;
+
+ frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ?
+ qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8;
ret = snd_pcm_hw_constraint_single(substream->runtime,
SNDRV_PCM_HW_PARAM_FRAME_BITS,
frame_bits);
if (ret < 0) {
- dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+ dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
+ return ret;
+ }
+
+ access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
+ 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
+ ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
+ access);
+ if (ret) {
+ dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);
return ret;
}
return 0;
}
+static int qmc_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+ struct qmc_dai *qmc_dai;
+
+ qmc_dai = qmc_dai_get_data(dai);
+ if (!qmc_dai) {
+ dev_err(dai->dev, "Invalid dai\n");
+ return -EINVAL;
+ }
+
+ prtd->qmc_dai = qmc_dai;
+
+ return qmc_dai->nb_chans_avail > 1 ?
+ qmc_dai_constraints_noninterleaved(substream, qmc_dai) :
+ qmc_dai_constraints_interleaved(substream, qmc_dai);
+}
+
static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct qmc_chan_param chan_param = {0};
+ unsigned int nb_chans_used;
struct qmc_dai *qmc_dai;
+ unsigned int i;
int ret;
qmc_dai = qmc_dai_get_data(dai);
@@ -481,15 +579,34 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ /*
+ * In interleaved mode, the driver uses one QMC channel for all audio
+ * channels whereas in non-interleaved mode, it uses one QMC channel per
+ * audio channel.
+ */
+ nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ?
+ 1 : params_channels(params);
+
+ if (nb_chans_used > qmc_dai->nb_chans_avail) {
+ dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n",
+ nb_chans_used, qmc_dai->nb_chans_avail);
+ return -EINVAL;
+ }
+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
chan_param.mode = QMC_TRANSPARENT;
- chan_param.transp.max_rx_buf_size = params_period_bytes(params);
- ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param);
- if (ret) {
- dev_err(dai->dev, "set param failed %d\n",
- ret);
- return ret;
+ chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;
+ for (i = 0; i < nb_chans_used; i++) {
+ ret = qmc_chan_set_param(qmc_dai->qmc_chans[i], &chan_param);
+ if (ret) {
+ dev_err(dai->dev, "qmc_chans[%u], set param failed %d\n",
+ i, ret);
+ return ret;
+ }
}
+ qmc_dai->nb_chans_used_rx = nb_chans_used;
+ } else {
+ qmc_dai->nb_chans_used_tx = nb_chans_used;
}
return 0;
@@ -498,9 +615,12 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
+ unsigned int nb_chans_used;
struct qmc_dai *qmc_dai;
+ unsigned int i;
int direction;
- int ret;
+ int ret = 0;
+ int ret_tmp;
qmc_dai = qmc_dai_get_data(dai);
if (!qmc_dai) {
@@ -508,30 +628,50 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return -EINVAL;
}
- direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- QMC_CHAN_WRITE : QMC_CHAN_READ;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = QMC_CHAN_WRITE;
+ nb_chans_used = qmc_dai->nb_chans_used_tx;
+ } else {
+ direction = QMC_CHAN_READ;
+ nb_chans_used = qmc_dai->nb_chans_used_rx;
+ }
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = qmc_chan_start(qmc_dai->qmc_chan, direction);
- if (ret)
- return ret;
+ for (i = 0; i < nb_chans_used; i++) {
+ ret = qmc_chan_start(qmc_dai->qmc_chans[i], direction);
+ if (ret)
+ goto err_stop;
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
- ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
- if (ret)
- return ret;
- ret = qmc_chan_reset(qmc_dai->qmc_chan, direction);
+ /* Stop and reset all QMC channels and return the first error encountered */
+ for (i = 0; i < nb_chans_used; i++) {
+ ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
+ if (!ret)
+ ret = ret_tmp;
+ if (ret_tmp)
+ continue;
+
+ ret_tmp = qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
+ if (!ret)
+ ret = ret_tmp;
+ }
if (ret)
return ret;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+ /* Stop all QMC channels and return the first error encountered */
+ for (i = 0; i < nb_chans_used; i++) {
+ ret_tmp = qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
+ if (!ret)
+ ret = ret_tmp;
+ }
if (ret)
return ret;
break;
@@ -541,6 +681,13 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
}
return 0;
+
+err_stop:
+ while (i--) {
+ qmc_chan_stop(qmc_dai->qmc_chans[i], direction);
+ qmc_chan_reset(qmc_dai->qmc_chans[i], direction);
+ }
+ return ret;
}
static const struct snd_soc_dai_ops qmc_dai_ops = {
@@ -549,28 +696,28 @@ static const struct snd_soc_dai_ops qmc_dai_ops = {
.hw_params = qmc_dai_hw_params,
};
-static u64 qmc_audio_formats(u8 nb_ts)
+static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved)
{
- u64 formats;
- unsigned int chan_width;
unsigned int format_width;
- int i;
+ unsigned int chan_width;
+ snd_pcm_format_t format;
+ u64 formats_mask;
if (!nb_ts)
return 0;
- formats = 0;
+ formats_mask = 0;
chan_width = nb_ts * 8;
- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+ pcm_for_each_format(format) {
/*
* Support format other than little-endian (ie big-endian or
* without endianness such as 8bit formats)
*/
- if (snd_pcm_format_little_endian(i) == 1)
+ if (snd_pcm_format_little_endian(format) == 1)
continue;
/* Support physical width multiple of 8bit */
- format_width = snd_pcm_format_physical_width(i);
+ format_width = snd_pcm_format_physical_width(format);
if (format_width == 0 || format_width % 8)
continue;
@@ -581,15 +728,34 @@ static u64 qmc_audio_formats(u8 nb_ts)
if (format_width > chan_width || chan_width % format_width)
continue;
- formats |= (1ULL << i);
+ /*
+ * In non interleaved mode, we can only support formats that
+ * can fit only 1 time in the channel
+ */
+ if (is_noninterleaved && format_width != chan_width)
+ continue;
+
+ formats_mask |= pcm_format_to_bits(format);
}
- return formats;
+ return formats_mask;
}
static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
- struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver)
+ struct qmc_dai *qmc_dai,
+ struct snd_soc_dai_driver *qmc_soc_dai_driver)
{
+ struct qmc_chan_ts_info ts_info;
struct qmc_chan_info info;
+ unsigned long rx_fs_rate;
+ unsigned long tx_fs_rate;
+ int prev_last_rx_ts = 0;
+ int prev_last_tx_ts = 0;
+ unsigned int nb_tx_ts;
+ unsigned int nb_rx_ts;
+ unsigned int i;
+ int last_rx_ts;
+ int last_tx_ts;
+ int count;
u32 val;
int ret;
@@ -604,57 +770,131 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
np->parent->name, qmc_dai->id);
+ if (!qmc_dai->name)
+ return -ENOMEM;
- qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
- "fsl,qmc-chan");
- if (IS_ERR(qmc_dai->qmc_chan)) {
- ret = PTR_ERR(qmc_dai->qmc_chan);
- return dev_err_probe(qmc_audio->dev, ret,
- "dai %d get QMC channel failed\n", qmc_dai->id);
- }
+ count = qmc_chan_count_phandles(np, "fsl,qmc-chan");
+ if (count < 0)
+ return dev_err_probe(qmc_audio->dev, count,
+ "dai %d get number of QMC channel failed\n", qmc_dai->id);
+ if (!count)
+ return dev_err_probe(qmc_audio->dev, -EINVAL,
+ "dai %d no QMC channel defined\n", qmc_dai->id);
+
+ qmc_dai->qmc_chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->qmc_chans),
+ GFP_KERNEL);
+ if (!qmc_dai->qmc_chans)
+ return -ENOMEM;
- qmc_soc_dai_driver->id = qmc_dai->id;
- qmc_soc_dai_driver->name = qmc_dai->name;
+ for (i = 0; i < count; i++) {
+ qmc_dai->qmc_chans[i] = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,
+ "fsl,qmc-chan", i);
+ if (IS_ERR(qmc_dai->qmc_chans[i])) {
+ return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->qmc_chans[i]),
+ "dai %d get QMC channel %d failed\n", qmc_dai->id, i);
+ }
- ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
- if (ret) {
- dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
- qmc_dai->id, ret);
- return ret;
- }
- dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
- qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
+ ret = qmc_chan_get_info(qmc_dai->qmc_chans[i], &info);
+ if (ret) {
+ dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",
+ qmc_dai->id, i, ret);
+ return ret;
+ }
- if (info.mode != QMC_TRANSPARENT) {
- dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
- qmc_dai->id, info.mode);
- return -EINVAL;
+ if (info.mode != QMC_TRANSPARENT) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n",
+ qmc_dai->id, i, info.mode);
+ return -EINVAL;
+ }
+
+ /*
+ * All channels must have the same number of Tx slots and the
+ * same numbers of Rx slots.
+ */
+ if (i == 0) {
+ nb_tx_ts = info.nb_tx_ts;
+ nb_rx_ts = info.nb_rx_ts;
+ tx_fs_rate = info.tx_fs_rate;
+ rx_fs_rate = info.rx_fs_rate;
+ } else {
+ if (nb_tx_ts != info.nb_tx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n",
+ qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts);
+ return -EINVAL;
+ }
+ if (nb_rx_ts != info.nb_rx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n",
+ qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts);
+ return -EINVAL;
+ }
+ if (tx_fs_rate != info.tx_fs_rate) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n",
+ qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate);
+ return -EINVAL;
+ }
+ if (rx_fs_rate != info.rx_fs_rate) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n",
+ qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate);
+ return -EINVAL;
+ }
+ }
+
+ ret = qmc_chan_get_ts_info(qmc_dai->qmc_chans[i], &ts_info);
+ if (ret) {
+ dev_err(qmc_audio->dev, "dai %d get QMC %d channel TS info failed %d\n",
+ qmc_dai->id, i, ret);
+ return ret;
+ }
+
+ last_rx_ts = fls64(ts_info.rx_ts_mask);
+ last_tx_ts = fls64(ts_info.tx_ts_mask);
+
+ if (prev_last_rx_ts > last_rx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (RX timeslot %d before %d)\n",
+ qmc_dai->id, i, prev_last_rx_ts, last_rx_ts);
+ return -EINVAL;
+ }
+ if (prev_last_tx_ts > last_tx_ts) {
+ dev_err(qmc_audio->dev, "dai %d QMC chan %d unordered channels (TX timeslot %d before %d)\n",
+ qmc_dai->id, i, prev_last_tx_ts, last_tx_ts);
+ return -EINVAL;
+ }
+
+ prev_last_rx_ts = last_rx_ts;
+ prev_last_tx_ts = last_tx_ts;
}
- qmc_dai->nb_tx_ts = info.nb_tx_ts;
- qmc_dai->nb_rx_ts = info.nb_rx_ts;
+
+ qmc_dai->nb_chans_avail = count;
+ qmc_dai->nb_tx_ts = nb_tx_ts * count;
+ qmc_dai->nb_rx_ts = nb_rx_ts * count;
+
+ qmc_soc_dai_driver->id = qmc_dai->id;
+ qmc_soc_dai_driver->name = qmc_dai->name;
qmc_soc_dai_driver->playback.channels_min = 0;
qmc_soc_dai_driver->playback.channels_max = 0;
- if (qmc_dai->nb_tx_ts) {
+ if (nb_tx_ts) {
qmc_soc_dai_driver->playback.channels_min = 1;
- qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
+ qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;
}
- qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
+ qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,
+ count > 1);
qmc_soc_dai_driver->capture.channels_min = 0;
qmc_soc_dai_driver->capture.channels_max = 0;
- if (qmc_dai->nb_rx_ts) {
+ if (nb_rx_ts) {
qmc_soc_dai_driver->capture.channels_min = 1;
- qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
+ qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;
}
- qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
+ qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,
+ count > 1);
- qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
- qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
- qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
- qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
- qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
- qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
+ 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;
+ qmc_soc_dai_driver->playback.rate_max = tx_fs_rate;
+ qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate);
+ qmc_soc_dai_driver->capture.rate_min = rx_fs_rate;
+ qmc_soc_dai_driver->capture.rate_max = rx_fs_rate;
qmc_soc_dai_driver->ops = &qmc_dai_ops;
@@ -702,7 +942,6 @@ static int qmc_audio_probe(struct platform_device *pdev)
i++;
}
-
platform_set_drvdata(pdev, qmc_audio);
ret = devm_snd_soc_register_component(qmc_audio->dev,
diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c
index 15b48b5ea856..5708b3a9878d 100644
--- a/sound/soc/fsl/fsl_rpmsg.c
+++ b/sound/soc/fsl/fsl_rpmsg.c
@@ -6,8 +6,7 @@
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/rpmsg.h>
#include <linux/slab.h>
@@ -25,6 +24,8 @@
/* 192kHz/32bit/2ch/60s size is 0x574e00 */
#define LPA_LARGE_BUFFER_SIZE (0x6000000)
+/* 16kHz/32bit/8ch/1s size is 0x7D000 */
+#define LPA_CAPTURE_BUFFER_SIZE (0x100000)
static const unsigned int fsl_rpmsg_rates[] = {
8000, 11025, 16000, 22050, 44100,
@@ -98,13 +99,9 @@ static int fsl_rpmsg_hw_free(struct snd_pcm_substream *substream,
static int fsl_rpmsg_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- int ret;
-
- ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &fsl_rpmsg_rate_constraints);
-
- return ret;
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &fsl_rpmsg_rate_constraints);
}
static const struct snd_soc_dai_ops fsl_rpmsg_dai_ops = {
@@ -136,7 +133,6 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = {
static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-rpmsg",
- .legacy_dai_naming = 1,
};
static const struct fsl_rpmsg_soc_data imx7ulp_data = {
@@ -170,12 +166,29 @@ static const struct fsl_rpmsg_soc_data imx8mp_data = {
SNDRV_PCM_FMTBIT_S32_LE,
};
+static const struct fsl_rpmsg_soc_data imx93_data = {
+ .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+};
+
+static const struct fsl_rpmsg_soc_data imx95_data = {
+ .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+};
+
static const struct of_device_id fsl_rpmsg_ids[] = {
{ .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data},
{ .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data},
{ .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data},
{ .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data},
{ .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data},
+ { .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data},
+ { .compatible = "fsl,imx95-rpmsg-audio", .data = &imx95_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
@@ -183,25 +196,58 @@ MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
static int fsl_rpmsg_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_dai_driver *dai_drv;
+ const char *dai_name;
struct fsl_rpmsg *rpmsg;
int ret;
+ dai_drv = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+ memcpy(dai_drv, &fsl_rpmsg_dai, sizeof(fsl_rpmsg_dai));
+
rpmsg = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg), GFP_KERNEL);
if (!rpmsg)
return -ENOMEM;
rpmsg->soc_data = of_device_get_match_data(&pdev->dev);
- fsl_rpmsg_dai.playback.rates = rpmsg->soc_data->rates;
- fsl_rpmsg_dai.capture.rates = rpmsg->soc_data->rates;
- fsl_rpmsg_dai.playback.formats = rpmsg->soc_data->formats;
- fsl_rpmsg_dai.capture.formats = rpmsg->soc_data->formats;
+ if (rpmsg->soc_data) {
+ dai_drv->playback.rates = rpmsg->soc_data->rates;
+ dai_drv->capture.rates = rpmsg->soc_data->rates;
+ dai_drv->playback.formats = rpmsg->soc_data->formats;
+ dai_drv->capture.formats = rpmsg->soc_data->formats;
+ }
+
+ /* Use rpmsg channel name as cpu dai name */
+ ret = of_property_read_string(np, "fsl,rpmsg-channel-name", &dai_name);
+ if (ret) {
+ if (ret == -EINVAL) {
+ dai_name = "rpmsg-audio-channel";
+ } else {
+ dev_err(&pdev->dev, "Failed to get rpmsg channel name: %d!\n", ret);
+ return ret;
+ }
+ }
+ dai_drv->name = dai_name;
+
+ /* Setup cpu dai for sound card that sits on rpmsg-micfil-channel */
+ if (!strcmp(dai_name, "rpmsg-micfil-channel")) {
+ dai_drv->capture.channels_min = 1;
+ dai_drv->capture.channels_max = 8;
+ dai_drv->capture.rates = SNDRV_PCM_RATE_8000_48000;
+ dai_drv->capture.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ if (of_device_is_compatible(np, "fsl,imx8mm-rpmsg-audio"))
+ dai_drv->capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ }
if (of_property_read_bool(np, "fsl,enable-lpa")) {
rpmsg->enable_lpa = 1;
- rpmsg->buffer_size = LPA_LARGE_BUFFER_SIZE;
+ rpmsg->buffer_size[SNDRV_PCM_STREAM_PLAYBACK] = LPA_LARGE_BUFFER_SIZE;
+ rpmsg->buffer_size[SNDRV_PCM_STREAM_CAPTURE] = LPA_CAPTURE_BUFFER_SIZE;
} else {
- rpmsg->buffer_size = IMX_DEFAULT_DMABUF_SIZE;
+ rpmsg->buffer_size[SNDRV_PCM_STREAM_PLAYBACK] = IMX_DEFAULT_DMABUF_SIZE;
+ rpmsg->buffer_size[SNDRV_PCM_STREAM_CAPTURE] = IMX_DEFAULT_DMABUF_SIZE;
}
/* Get the optional clocks */
@@ -229,33 +275,27 @@ static int fsl_rpmsg_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
- &fsl_rpmsg_dai, 1);
+ dai_drv, 1);
if (ret)
- return ret;
-
- rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
- "imx-audio-rpmsg",
- PLATFORM_DEVID_AUTO,
- NULL,
- 0);
- if (IS_ERR(rpmsg->card_pdev)) {
- dev_err(&pdev->dev, "failed to register rpmsg card\n");
- ret = PTR_ERR(rpmsg->card_pdev);
- return ret;
- }
+ goto err_pm_disable;
return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
}
static void fsl_rpmsg_remove(struct platform_device *pdev)
{
struct fsl_rpmsg *rpmsg = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
+
if (rpmsg->card_pdev)
platform_device_unregister(rpmsg->card_pdev);
}
-#ifdef CONFIG_PM
static int fsl_rpmsg_runtime_resume(struct device *dev)
{
struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev);
@@ -290,20 +330,18 @@ static int fsl_rpmsg_runtime_suspend(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops fsl_rpmsg_pm_ops = {
- SET_RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend,
- fsl_rpmsg_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend, fsl_rpmsg_runtime_resume,
+ NULL)
};
static struct platform_driver fsl_rpmsg_driver = {
.probe = fsl_rpmsg_probe,
- .remove_new = fsl_rpmsg_remove,
+ .remove = fsl_rpmsg_remove,
.driver = {
.name = "fsl_rpmsg",
- .pm = &fsl_rpmsg_pm_ops,
+ .pm = pm_ptr(&fsl_rpmsg_pm_ops),
.of_match_table = fsl_rpmsg_ids,
},
};
diff --git a/sound/soc/fsl/fsl_rpmsg.h b/sound/soc/fsl/fsl_rpmsg.h
index b04086fbf828..1b1683808507 100644
--- a/sound/soc/fsl/fsl_rpmsg.h
+++ b/sound/soc/fsl/fsl_rpmsg.h
@@ -42,6 +42,6 @@ struct fsl_rpmsg {
unsigned int mclk_streams;
int force_lpa;
int enable_lpa;
- int buffer_size;
+ int buffer_size[2];
};
#endif /* __FSL_RPMSG_H */
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index d9344025dc16..72bfc91e21b9 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -8,8 +8,7 @@
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
@@ -164,14 +163,46 @@ out:
return iret;
}
-static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
- u32 rx_mask, int slots, int slot_width)
+static int fsl_sai_set_dai_tdm_slot_tx(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ bool tx = true;
+
+ sai->slots[tx] = slots;
+ sai->slot_width[tx] = slot_width;
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_tdm_slot_rx(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ bool tx = false;
+
+ sai->slots[tx] = slots;
+ sai->slot_width[tx] = slot_width;
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ int ret;
- sai->slots = slots;
- sai->slot_width = slot_width;
+ ret = fsl_sai_set_dai_tdm_slot_tx(cpu_dai, tx_mask, rx_mask, slots, slot_width);
+ if (ret)
+ return ret;
+ return fsl_sai_set_dai_tdm_slot_rx(cpu_dai, tx_mask, rx_mask, slots, slot_width);
+}
+
+static int fsl_sai_xlate_tdm_slot_mask(unsigned int slots,
+ unsigned int *tx_mask, unsigned int *rx_mask)
+{
+ /* Leave it empty, don't change the value of tx_mask and rx_mask */
return 0;
}
@@ -239,22 +270,22 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
if (dir == SND_SOC_CLOCK_IN)
return 0;
- if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) {
- if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
- dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
- return -EINVAL;
- }
+ if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
+ dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
+ return -EINVAL;
+ }
- if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) {
- dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id);
- return -EINVAL;
- }
+ if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) {
+ dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id);
+ return -EINVAL;
+ }
- if (sai->mclk_streams == 0) {
- ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
- if (ret < 0)
- return ret;
- }
+ if (sai->mclk_streams == 0 && freq > 0) {
+ ret = fsl_sai_set_mclk_rate(cpu_dai,
+ clk_id ? clk_id : FSL_SAI_CLK_MAST1,
+ freq);
+ if (ret < 0)
+ return ret;
}
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, true);
@@ -281,7 +312,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
val_cr4 |= FSL_SAI_CR4_MF;
sai->is_pdm_mode = false;
- sai->is_dsp_mode = false;
+ sai->is_dsp_mode[tx] = false;
/* DAI mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -310,7 +341,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
*/
val_cr2 |= FSL_SAI_CR2_BCP;
val_cr4 |= FSL_SAI_CR4_FSE;
- sai->is_dsp_mode = true;
+ sai->is_dsp_mode[tx] = true;
break;
case SND_SOC_DAIFMT_DSP_B:
/*
@@ -318,11 +349,10 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
* frame sync asserts with the first bit of the frame.
*/
val_cr2 |= FSL_SAI_CR2_BCP;
- sai->is_dsp_mode = true;
+ sai->is_dsp_mode[tx] = true;
break;
case SND_SOC_DAIFMT_PDM:
val_cr2 |= FSL_SAI_CR2_BCP;
- val_cr4 &= ~FSL_SAI_CR4_MF;
sai->is_pdm_mode = true;
break;
case SND_SOC_DAIFMT_RIGHT_J:
@@ -358,18 +388,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_BP_FP:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
- sai->is_consumer_mode = false;
+ sai->is_consumer_mode[tx] = false;
break;
case SND_SOC_DAIFMT_BC_FC:
- sai->is_consumer_mode = true;
+ sai->is_consumer_mode[tx] = true;
break;
case SND_SOC_DAIFMT_BP_FC:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
- sai->is_consumer_mode = false;
+ sai->is_consumer_mode[tx] = false;
break;
case SND_SOC_DAIFMT_BC_FP:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
- sai->is_consumer_mode = true;
+ sai->is_consumer_mode[tx] = true;
break;
default:
return -EINVAL;
@@ -401,6 +431,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
return ret;
}
+static int fsl_sai_set_dai_fmt_tx(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true);
+}
+
+static int fsl_sai_set_dai_fmt_rx(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false);
+}
+
static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
@@ -413,7 +453,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
bool support_1_1_ratio = sai->verid.version >= 0x0301;
/* Don't apply to consumer mode */
- if (sai->is_consumer_mode)
+ if (sai->is_consumer_mode[tx])
return 0;
/*
@@ -491,19 +531,20 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK,
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
- if (savediv == 1)
+ if (savediv == 1) {
regmap_update_bits(sai->regmap, reg,
FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
FSL_SAI_CR2_BYP);
- else
+ if (fsl_sai_dir_is_synced(sai, adir))
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
+ FSL_SAI_CR2_BCI, FSL_SAI_CR2_BCI);
+ else
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
+ FSL_SAI_CR2_BCI, 0);
+ } else {
regmap_update_bits(sai->regmap, reg,
FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
savediv / 2 - 1);
-
- if (sai->soc_data->max_register >= FSL_SAI_MCTL) {
- /* SAI is in master mode at this point, so enable MCLK */
- regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
- FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
}
return 0;
@@ -531,11 +572,11 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
u32 watermark;
int ret, i;
- if (sai->slot_width)
- slot_width = sai->slot_width;
+ if (sai->slot_width[tx])
+ slot_width = sai->slot_width[tx];
- if (sai->slots)
- slots = sai->slots;
+ if (sai->slots[tx])
+ slots = sai->slots[tx];
else if (sai->bclk_ratio)
slots = sai->bclk_ratio / slot_width;
@@ -575,7 +616,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
}
}
- if (!sai->is_consumer_mode) {
+ if (!sai->is_consumer_mode[tx]) {
ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
if (ret)
return ret;
@@ -590,30 +631,33 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
}
}
- if (!sai->is_dsp_mode && !sai->is_pdm_mode)
+ if (!sai->is_dsp_mode[tx] && !sai->is_pdm_mode)
val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
- if (sai->is_lsb_first || sai->is_pdm_mode)
+ if (sai->is_lsb_first)
val_cr5 |= FSL_SAI_CR5_FBT(0);
else
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
+ /* Set to avoid channel swap */
+ val_cr4 |= FSL_SAI_CR4_FCONT;
+
/* Set to output mode to avoid tri-stated data pins */
if (tx)
val_cr4 |= FSL_SAI_CR4_CHMOD;
/*
- * For SAI provider mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
- * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
- * RCR5(TCR5) for playback(capture), or there will be sync error.
+ * When Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will provide bclk and
+ * frame clock for Tx(Rx). We should set RCR4(TCR4), RCR5(TCR5)
+ * for playback(capture), or there will be sync error.
*/
- if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) {
+ if (fsl_sai_dir_is_synced(sai, adir)) {
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
FSL_SAI_CR4_CHMOD_MASK,
@@ -673,13 +717,34 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
FSL_SAI_CR3_TRCE_MASK,
FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
+ /*
+ * When the TERE and FSD_MSTR enabled before configuring the word width
+ * There will be no frame sync clock issue, because word width impact
+ * the generation of frame sync clock.
+ *
+ * TERE enabled earlier only for i.MX8MP case for the hardware limitation,
+ * We need to disable FSD_MSTR before configuring word width, then enable
+ * FSD_MSTR bit for this specific case.
+ */
+ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
+ !sai->is_consumer_mode[tx])
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
+ FSL_SAI_CR4_FSD_MSTR, 0);
+
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
- FSL_SAI_CR4_CHMOD_MASK,
+ FSL_SAI_CR4_CHMOD_MASK | FSL_SAI_CR4_FCONT_MASK,
val_cr4);
regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
FSL_SAI_CR5_FBT_MASK, val_cr5);
+
+ /* Enable FSD_MSTR after configuring word width */
+ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
+ !sai->is_consumer_mode[tx])
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
+ FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR);
+
regmap_write(sai->regmap, FSL_SAI_xMR(tx),
~0UL - ((1 << min(channels, slots)) - 1));
@@ -693,11 +758,14 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int ofs = sai->soc_data->reg_offset;
+ /* Clear xMR to avoid channel swap with mclk_with_tere enabled case */
+ regmap_write(sai->regmap, FSL_SAI_xMR(tx), 0);
+
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
FSL_SAI_CR3_TRCE_MASK, 0);
- if (!sai->is_consumer_mode &&
- sai->mclk_streams & BIT(substream->stream)) {
+ if (!sai->is_consumer_mode[tx] &&
+ sai->mclk_streams & BIT(substream->stream)) {
clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
sai->mclk_streams &= ~BIT(substream->stream);
}
@@ -709,10 +777,15 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
{
unsigned int ofs = sai->soc_data->reg_offset;
bool tx = dir == TX;
- u32 xcsr, count = 100;
+ u32 xcsr, count = 100, mask;
+
+ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output)
+ mask = FSL_SAI_CSR_TERE;
+ else
+ mask = FSL_SAI_CSR_TERE | FSL_SAI_CSR_BCE;
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
- FSL_SAI_CSR_TERE, 0);
+ mask, 0);
/* TERE will remain set till the end of current frame */
do {
@@ -729,13 +802,15 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
* anymore. Add software reset to fix this issue.
* This is a hardware bug, and will be fix in the
* next sai version.
+ *
+ * In consumer mode, this can happen even after a
+ * single open/close, especially if both tx and rx
+ * are running concurrently.
*/
- if (!sai->is_consumer_mode) {
- /* Software Reset */
- regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
- /* Clear SR bit to finish the reset */
- regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0);
- }
+ /* Software Reset */
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR, FSL_SAI_CSR_SR);
+ /* Clear SR bit to finish the reset */
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR, 0);
}
static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -843,33 +918,22 @@ 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;
}
-static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
- .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
- .set_sysclk = fsl_sai_set_dai_sysclk,
- .set_fmt = fsl_sai_set_dai_fmt,
- .set_tdm_slot = fsl_sai_set_dai_tdm_slot,
- .hw_params = fsl_sai_hw_params,
- .hw_free = fsl_sai_hw_free,
- .trigger = fsl_sai_trigger,
- .startup = fsl_sai_startup,
-};
-
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
unsigned int ofs = sai->soc_data->reg_offset;
/* Software Reset for both Tx and Rx */
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR, FSL_SAI_CSR_SR);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR, FSL_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR, 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR, 0);
regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs),
FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
@@ -884,6 +948,44 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+ .probe = fsl_sai_dai_probe,
+ .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+ .set_sysclk = fsl_sai_set_dai_sysclk,
+ .set_fmt = fsl_sai_set_dai_fmt,
+ .set_tdm_slot = fsl_sai_set_dai_tdm_slot,
+ .hw_params = fsl_sai_hw_params,
+ .hw_free = fsl_sai_hw_free,
+ .trigger = fsl_sai_trigger,
+ .startup = fsl_sai_startup,
+};
+
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_ops = {
+ .probe = fsl_sai_dai_probe,
+ .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+ .set_sysclk = fsl_sai_set_dai_sysclk,
+ .set_fmt = fsl_sai_set_dai_fmt_tx,
+ .set_tdm_slot = fsl_sai_set_dai_tdm_slot_tx,
+ .xlate_tdm_slot_mask = fsl_sai_xlate_tdm_slot_mask,
+ .hw_params = fsl_sai_hw_params,
+ .hw_free = fsl_sai_hw_free,
+ .trigger = fsl_sai_trigger,
+ .startup = fsl_sai_startup,
+};
+
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_ops = {
+ .probe = fsl_sai_dai_probe,
+ .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+ .set_sysclk = fsl_sai_set_dai_sysclk,
+ .set_fmt = fsl_sai_set_dai_fmt_rx,
+ .set_tdm_slot = fsl_sai_set_dai_tdm_slot_rx,
+ .xlate_tdm_slot_mask = fsl_sai_xlate_tdm_slot_mask,
+ .hw_params = fsl_sai_hw_params,
+ .hw_free = fsl_sai_hw_free,
+ .trigger = fsl_sai_trigger,
+ .startup = fsl_sai_startup,
+};
+
static int fsl_sai_dai_resume(struct snd_soc_component *component)
{
struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
@@ -901,27 +1003,55 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
return 0;
}
-static struct snd_soc_dai_driver fsl_sai_dai_template = {
- .probe = fsl_sai_dai_probe,
- .playback = {
- .stream_name = "CPU-Playback",
- .channels_min = 1,
- .channels_max = 32,
- .rate_min = 8000,
- .rate_max = 2822400,
- .rates = SNDRV_PCM_RATE_KNOT,
- .formats = FSL_SAI_FORMATS,
+static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
+ {
+ .name = "sai-tx-rx",
+ .playback = {
+ .stream_name = "CPU-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 2822400,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .capture = {
+ .stream_name = "CPU-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 2822400,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .ops = &fsl_sai_pcm_dai_ops,
},
- .capture = {
- .stream_name = "CPU-Capture",
- .channels_min = 1,
- .channels_max = 32,
- .rate_min = 8000,
- .rate_max = 2822400,
- .rates = SNDRV_PCM_RATE_KNOT,
- .formats = FSL_SAI_FORMATS,
+ {
+ .name = "sai-tx",
+ .playback = {
+ .stream_name = "SAI-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 2822400,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .ops = &fsl_sai_pcm_dai_tx_ops,
+ },
+ {
+ .name = "sai-rx",
+ .capture = {
+ .stream_name = "SAI-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 2822400,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .ops = &fsl_sai_pcm_dai_rx_ops,
},
- .ops = &fsl_sai_pcm_dai_ops,
};
static const struct snd_soc_component_driver fsl_component = {
@@ -930,7 +1060,7 @@ static const struct snd_soc_component_driver fsl_component = {
.legacy_dai_naming = 1,
};
-static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
+static const struct reg_default fsl_sai_reg_defaults_ofs0[] = {
{FSL_SAI_TCR1(0), 0},
{FSL_SAI_TCR2(0), 0},
{FSL_SAI_TCR3(0), 0},
@@ -953,7 +1083,7 @@ static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
{FSL_SAI_RMR, 0},
};
-static struct reg_default fsl_sai_reg_defaults_ofs8[] = {
+static const struct reg_default fsl_sai_reg_defaults_ofs8[] = {
{FSL_SAI_TCR1(8), 0},
{FSL_SAI_TCR2(8), 0},
{FSL_SAI_TCR3(8), 0},
@@ -1113,7 +1243,6 @@ static struct regmap_config fsl_sai_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .fast_io = true,
.max_register = FSL_SAI_RMR,
.reg_defaults = fsl_sai_reg_defaults_ofs0,
@@ -1215,7 +1344,7 @@ static int fsl_sai_read_dlcfg(struct fsl_sai *sai)
num_cfg = elems / 3;
/* Add one more for default value */
- cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL);
+ cfg = devm_kcalloc(&pdev->dev, num_cfg + 1, sizeof(*cfg), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
@@ -1347,6 +1476,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)
@@ -1370,15 +1504,15 @@ static int fsl_sai_probe(struct platform_device *pdev)
return ret;
}
- memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template,
- sizeof(fsl_sai_dai_template));
+ memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template,
+ sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template));
/* Sync Tx with Rx as default by following old DT binding */
sai->synchronous[RX] = true;
sai->synchronous[TX] = false;
- sai->cpu_dai_drv.symmetric_rate = 1;
- sai->cpu_dai_drv.symmetric_channels = 1;
- sai->cpu_dai_drv.symmetric_sample_bits = 1;
+ sai->cpu_dai_drv[0].symmetric_rate = 1;
+ sai->cpu_dai_drv[0].symmetric_channels = 1;
+ sai->cpu_dai_drv[0].symmetric_sample_bits = 1;
if (of_property_read_bool(np, "fsl,sai-synchronous-rx") &&
of_property_read_bool(np, "fsl,sai-asynchronous")) {
@@ -1395,9 +1529,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
/* Discard all settings for asynchronous mode */
sai->synchronous[RX] = false;
sai->synchronous[TX] = false;
- sai->cpu_dai_drv.symmetric_rate = 0;
- sai->cpu_dai_drv.symmetric_channels = 0;
- sai->cpu_dai_drv.symmetric_sample_bits = 0;
+ sai->cpu_dai_drv[0].symmetric_rate = 0;
+ sai->cpu_dai_drv[0].symmetric_channels = 0;
+ sai->cpu_dai_drv[0].symmetric_sample_bits = 0;
}
sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output");
@@ -1476,7 +1610,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
}
ret = devm_snd_soc_register_component(dev, &fsl_component,
- &sai->cpu_dai_drv, 1);
+ sai->cpu_dai_drv, ARRAY_SIZE(fsl_sai_dai_template));
if (ret)
goto err_pm_get_sync;
@@ -1610,6 +1744,18 @@ static const struct fsl_sai_soc_data fsl_sai_imx93_data = {
.max_burst = {8, 8},
};
+static const struct fsl_sai_soc_data fsl_sai_imx95_data = {
+ .use_imx_pcm = true,
+ .use_edma = true,
+ .fifo_depth = 128,
+ .reg_offset = 8,
+ .mclk0_is_mclk1 = false,
+ .pins = 8,
+ .flags = 0,
+ .max_register = FSL_SAI_MCTL,
+ .max_burst = {8, 8},
+};
+
static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
{ .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
@@ -1622,6 +1768,7 @@ static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data },
{ .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mn_data },
{ .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data },
+ { .compatible = "fsl,imx95-sai", .data = &fsl_sai_imx95_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_sai_ids);
@@ -1675,11 +1822,11 @@ static int fsl_sai_runtime_resume(struct device *dev)
regcache_cache_only(sai->regmap, false);
regcache_mark_dirty(sai->regmap);
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR, FSL_SAI_CSR_SR);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR, FSL_SAI_CSR_SR);
usleep_range(1000, 2000);
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR, 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR, 0);
ret = regcache_sync(sai->regmap);
if (ret)
@@ -1704,18 +1851,16 @@ 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 = {
.probe = fsl_sai_probe,
- .remove_new = fsl_sai_remove,
+ .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 3eb994aef36a..6c917f79c6b0 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 |\
@@ -91,6 +92,7 @@
/* SAI Transmit/Receive Control Register */
#define FSL_SAI_CSR_TERE BIT(31)
#define FSL_SAI_CSR_SE BIT(30)
+#define FSL_SAI_CSR_BCE BIT(28)
#define FSL_SAI_CSR_FR BIT(25)
#define FSL_SAI_CSR_SR BIT(24)
#define FSL_SAI_CSR_xF_SHIFT 16
@@ -116,6 +118,7 @@
/* SAI Transmit and Receive Configuration 2 Register */
#define FSL_SAI_CR2_SYNC BIT(30)
+#define FSL_SAI_CR2_BCI BIT(28)
#define FSL_SAI_CR2_MSEL_MASK (0x3 << 26)
#define FSL_SAI_CR2_MSEL_BUS 0
#define FSL_SAI_CR2_MSEL_MCLK1 BIT(26)
@@ -135,6 +138,7 @@
/* SAI Transmit and Receive Configuration 4 Register */
+#define FSL_SAI_CR4_FCONT_MASK BIT(28)
#define FSL_SAI_CR4_FCONT BIT(28)
#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
#define FSL_SAI_CR4_FCOMB_SOFT BIT(27)
@@ -280,9 +284,9 @@ struct fsl_sai {
struct clk *pll11k_clk;
struct resource *res;
- bool is_consumer_mode;
+ bool is_consumer_mode[2];
bool is_lsb_first;
- bool is_dsp_mode;
+ bool is_dsp_mode[2];
bool is_pdm_mode;
bool is_multi_fifo_dma;
bool synchronous[2];
@@ -292,12 +296,12 @@ struct fsl_sai {
unsigned int mclk_id[2];
unsigned int mclk_streams;
- unsigned int slots;
- unsigned int slot_width;
+ unsigned int slots[2];
+ unsigned int slot_width[2];
unsigned int bclk_ratio;
const struct fsl_sai_soc_data *soc_data;
- struct snd_soc_dai_driver cpu_dai_drv;
+ struct snd_soc_dai_driver cpu_dai_drv[3];
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct fsl_sai_verid verid;
@@ -306,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_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 015c3708aa04..1b9be85b34c2 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -12,9 +12,7 @@
#include <linux/bitrev.h>
#include <linux/clk.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
@@ -150,7 +148,7 @@ struct fsl_spdif_priv {
struct clk *pll11k_clk;
};
-static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
+static const struct fsl_spdif_soc_data fsl_spdif_vf610 = {
.imx = false,
.shared_root_clock = false,
.raw_capture_mode = false,
@@ -160,7 +158,7 @@ static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
.tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
};
-static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
+static const struct fsl_spdif_soc_data fsl_spdif_imx35 = {
.imx = true,
.shared_root_clock = false,
.raw_capture_mode = false,
@@ -170,7 +168,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
.tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
};
-static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
+static const struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
.imx = true,
.shared_root_clock = true,
.raw_capture_mode = false,
@@ -181,7 +179,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
};
-static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
+static const struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
.imx = true,
.shared_root_clock = true,
.raw_capture_mode = false,
@@ -191,7 +189,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
.tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */
};
-static struct fsl_spdif_soc_data fsl_spdif_imx8mm = {
+static const struct fsl_spdif_soc_data fsl_spdif_imx8mm = {
.imx = true,
.shared_root_clock = false,
.raw_capture_mode = true,
@@ -201,7 +199,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx8mm = {
.tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
};
-static struct fsl_spdif_soc_data fsl_spdif_imx8ulp = {
+static const struct fsl_spdif_soc_data fsl_spdif_imx8ulp = {
.imx = true,
.shared_root_clock = true,
.raw_capture_mode = false,
@@ -502,8 +500,8 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_t
static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
int sample_rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
struct regmap *regmap = spdif_priv->regmap;
struct platform_device *pdev = spdif_priv->pdev;
@@ -514,6 +512,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
int ret;
switch (sample_rate) {
+ case 22050:
+ rate = SPDIF_TXRATE_22050;
+ csfs = IEC958_AES3_CON_FS_22050;
+ break;
case 32000:
rate = SPDIF_TXRATE_32000;
csfs = IEC958_AES3_CON_FS_32000;
@@ -601,8 +603,8 @@ clk_set_bypass:
static int fsl_spdif_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct platform_device *pdev = spdif_priv->pdev;
struct regmap *regmap = spdif_priv->regmap;
u32 scr, mask;
@@ -643,8 +645,8 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct regmap *regmap = spdif_priv->regmap;
u32 scr, mask;
@@ -697,8 +699,8 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
struct platform_device *pdev = spdif_priv->pdev;
u32 sample_rate = params_rate(params);
@@ -732,8 +734,8 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct regmap *regmap = spdif_priv->regmap;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 intr = SIE_INTR_FOR(tx);
@@ -751,6 +753,8 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0);
regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0);
+ regmap_write(regmap, REG_SPDIF_STL, 0x0);
+ regmap_write(regmap, REG_SPDIF_STR, 0x0);
break;
default:
return -EINVAL;
@@ -759,14 +763,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
- .startup = fsl_spdif_startup,
- .hw_params = fsl_spdif_hw_params,
- .trigger = fsl_spdif_trigger,
- .shutdown = fsl_spdif_shutdown,
-};
-
-
/*
* FSL SPDIF IEC958 controller(mixer) functions
*
@@ -1150,7 +1146,7 @@ static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol,
}
/* FSL SPDIF IEC958 controller defines */
-static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
+static const struct snd_kcontrol_new fsl_spdif_ctrls[] = {
/* Status cchanel controller */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1208,7 +1204,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
},
/* DPLL lock info get controller */
{
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = RX_SAMPLE_RATE_KCONTROL,
.access = SNDRV_CTL_ELEM_ACCESS_READ |
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
@@ -1237,7 +1233,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
},
};
-static struct snd_kcontrol_new fsl_spdif_ctrls_rcm[] = {
+static const struct snd_kcontrol_new fsl_spdif_ctrls_rcm[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "IEC958 Raw Capture Mode",
@@ -1277,8 +1273,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+ .probe = fsl_spdif_dai_probe,
+ .startup = fsl_spdif_startup,
+ .hw_params = fsl_spdif_hw_params,
+ .trigger = fsl_spdif_trigger,
+ .shutdown = fsl_spdif_shutdown,
+};
+
static struct snd_soc_dai_driver fsl_spdif_dai = {
- .probe = &fsl_spdif_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 2,
@@ -1422,7 +1425,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
struct clk *clk, u64 savesub,
enum spdif_txrate index, bool round)
{
- static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+ static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400,
192000, };
bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
u64 rate_ideal, rate_actual, sub;
@@ -1483,7 +1486,7 @@ out:
static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
enum spdif_txrate index)
{
- static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+ static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400,
192000, };
struct platform_device *pdev = spdif_priv->pdev;
struct device *dev = &pdev->dev;
@@ -1664,7 +1667,6 @@ static void fsl_spdif_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#ifdef CONFIG_PM
static int fsl_spdif_runtime_suspend(struct device *dev)
{
struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
@@ -1736,13 +1738,11 @@ disable_core_clk:
return ret;
}
-#endif /* CONFIG_PM */
static const struct dev_pm_ops fsl_spdif_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume,
+ NULL)
};
static const struct of_device_id fsl_spdif_dt_ids[] = {
@@ -1760,10 +1760,10 @@ static struct platform_driver fsl_spdif_driver = {
.driver = {
.name = "fsl-spdif-dai",
.of_match_table = fsl_spdif_dt_ids,
- .pm = &fsl_spdif_pm,
+ .pm = pm_ptr(&fsl_spdif_pm),
},
.probe = fsl_spdif_probe,
- .remove_new = fsl_spdif_remove,
+ .remove = fsl_spdif_remove,
};
module_platform_driver(fsl_spdif_driver);
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
index 75b42a692c90..2bc1b10c17d4 100644
--- a/sound/soc/fsl/fsl_spdif.h
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -175,7 +175,8 @@ enum spdif_gainsel {
/* SPDIF tx rate */
enum spdif_txrate {
- SPDIF_TXRATE_32000 = 0,
+ SPDIF_TXRATE_22050 = 0,
+ SPDIF_TXRATE_32000,
SPDIF_TXRATE_44100,
SPDIF_TXRATE_48000,
SPDIF_TXRATE_88200,
@@ -191,7 +192,8 @@ enum spdif_txrate {
#define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE / 8)
-#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \
+#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_88200 | \
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 53ed3701b0b0..320108bebf30 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -634,8 +634,8 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi)
static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
int ret;
ret = clk_prepare_enable(ssi->clk);
@@ -658,8 +658,8 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
clk_disable_unprepare(ssi->clk);
}
@@ -890,8 +890,8 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
if (fsl_ssi_is_i2s_clock_provider(ssi) &&
ssi->baudclk_streams & BIT(substream->stream)) {
@@ -1107,8 +1107,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
switch (cmd) {
@@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+ .probe = fsl_ssi_dai_probe,
.startup = fsl_ssi_startup,
.shutdown = fsl_ssi_shutdown,
.hw_params = fsl_ssi_hw_params,
@@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
};
static struct snd_soc_dai_driver fsl_ssi_dai_template = {
- .probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
@@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.symmetric_channels = 1,
- .probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "CPU AC97 Playback",
.channels_min = 2,
@@ -1402,8 +1401,10 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
goto error_pcm;
} else {
ret = imx_pcm_dma_init(pdev);
- if (ret)
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to init PCM DMA\n");
goto error_pcm;
+ }
}
return 0;
@@ -1692,7 +1693,6 @@ static void fsl_ssi_remove(struct platform_device *pdev)
}
}
-#ifdef CONFIG_PM_SLEEP
static int fsl_ssi_suspend(struct device *dev)
{
struct fsl_ssi *ssi = dev_get_drvdata(dev);
@@ -1722,20 +1722,19 @@ static int fsl_ssi_resume(struct device *dev)
return regcache_sync(regs);
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops fsl_ssi_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume)
+ SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume)
};
static struct platform_driver fsl_ssi_driver = {
.driver = {
.name = "fsl-ssi-dai",
.of_match_table = fsl_ssi_ids,
- .pm = &fsl_ssi_pm,
+ .pm = pm_sleep_ptr(&fsl_ssi_pm),
},
.probe = fsl_ssi_probe,
- .remove_new = fsl_ssi_remove,
+ .remove = fsl_ssi_remove,
};
module_platform_driver(fsl_ssi_driver);
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 318fe77683f5..06434b2c9a0f 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -15,24 +15,37 @@
#include <sound/pcm_params.h>
#include "fsl_xcvr.h"
+#include "fsl_utils.h"
#include "imx-pcm.h"
#define FSL_XCVR_CAPDS_SIZE 256
+#define SPDIF_NUM_RATES 7
+
+enum fsl_xcvr_pll_verison {
+ PLL_MX8MP,
+ PLL_MX95,
+};
struct fsl_xcvr_soc_data {
const char *fw_name;
bool spdif_only;
bool use_edma;
+ bool use_phy;
+ enum fsl_xcvr_pll_verison pll_ver;
};
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;
struct clk *spba_clk;
+ struct clk *pll8k_clk;
+ struct clk *pll11k_clk;
struct reset_control *reset;
u8 streams;
u32 mode;
@@ -43,6 +56,10 @@ struct fsl_xcvr {
struct snd_aes_iec958 rx_iec958;
struct snd_aes_iec958 tx_iec958;
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 {
@@ -159,7 +176,7 @@ static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol,
}
static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = {
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capabilities Data Structure",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = fsl_xcvr_type_capds_bytes_info,
@@ -174,6 +191,8 @@ static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name,
struct snd_kcontrol *kctl;
bool enabled;
+ lockdep_assert_held(&card->snd_card->controls_rwsem);
+
kctl = snd_soc_card_get_kcontrol(card, name);
if (kctl == NULL)
return -ENOENT;
@@ -243,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);
@@ -257,13 +276,66 @@ 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;
- u32 i, div = 0, log2;
+ u32 i, div = 0, log2, val;
int ret;
- if (xcvr->soc_data->spdif_only)
+ if (!xcvr->soc_data->use_phy)
return 0;
for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
@@ -286,65 +358,82 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
return ret;
}
- /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
- FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
-
- /* PLL: CTRL0: DIV_INTEGER */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0);
- /* PLL: NUMERATOR: MFN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0);
- /* PLL: DENOMINATOR: MFD */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0);
- /* 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);
- udelay(25);
- /* PLL: CTRL0: Clear Hold Ring Off */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR,
- FSL_XCVR_PLL_CTRL0_HROFF, 0);
- 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);
- /* PLL: CTRL_SET: CLKMUX0_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_CM0_EN, 0);
- } 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);
- /* PLL: CTRL_SET: CLKMUX1_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_CM1_EN, 0);
- } else { /* SPDIF / ARC RX */
- /* PLL: POSTDIV: PDIV2 */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
- FSL_XCVR_PLL_PDIVx(log2, 2), 0);
- /* PLL: CTRL_SET: CLKMUX2_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
+ switch (xcvr->soc_data->pll_ver) {
+ case PLL_MX8MP:
+ /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_BANDGAP,
+ FSL_XCVR_PLL_BANDGAP_EN_VBG);
+
+ /* PLL: CTRL0: DIV_INTEGER */
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi);
+ /* PLL: NUMERATOR: MFN */
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn);
+ /* PLL: DENOMINATOR: MFD */
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd);
+ /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
+ 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 */
+ 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 */
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 0));
+ /* PLL: CTRL_SET: CLKMUX0_EN */
+ 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 */
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 1));
+ /* PLL: CTRL_SET: CLKMUX1_EN */
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
+ FSL_XCVR_PLL_CTRL0_CM1_EN);
+ } else { /* SPDIF / ARC RX */
+ /* PLL: POSTDIV: PDIV2 */
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 2));
+ /* PLL: CTRL_SET: CLKMUX2_EN */
+ 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;
+ 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;
+ 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;
+ 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);
+ return -EINVAL;
}
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",
@@ -358,8 +447,10 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
struct device *dev = &xcvr->pdev->dev;
int ret;
- freq = xcvr->soc_data->spdif_only ? freq / 10 : freq;
+ freq = xcvr->soc_data->spdif_only ? freq / 5 : freq;
clk_disable_unprepare(xcvr->phy_clk);
+ fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk,
+ xcvr->pll8k_clk, xcvr->pll11k_clk, freq);
ret = clk_set_rate(xcvr->phy_clk, freq);
if (ret < 0) {
dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
@@ -371,7 +462,7 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
return ret;
}
- if (xcvr->soc_data->spdif_only)
+ if (!xcvr->soc_data->use_phy)
return 0;
/* Release AI interface from reset */
ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
@@ -383,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);
@@ -409,11 +500,21 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 m_ctl = 0, v_ctl = 0;
u32 r = substream->runtime->rate, ch = substream->runtime->channels;
- u32 fout = 32 * r * ch * 10 * 2;
+ u32 fout = 32 * r * ch * 10;
int ret = 0;
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,
+ FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM,
+ FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set bypass fem: %d\n", ret);
+ return ret;
+ }
+ }
+ fallthrough;
case FSL_XCVR_MODE_ARC:
if (tx) {
ret = fsl_xcvr_en_aud_pll(xcvr, fout);
@@ -423,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;
@@ -441,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;
@@ -462,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;
@@ -488,16 +589,6 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
break;
}
- ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
- FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
- if (ret < 0) {
- dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
- return ret;
- }
-
- /* set DPATH RESET */
- m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
- v_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl);
if (ret < 0) {
dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret);
@@ -552,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,
@@ -566,10 +661,14 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
xcvr->streams |= BIT(substream->stream);
if (!xcvr->soc_data->spdif_only) {
+ struct snd_soc_card *card = dai->component->card;
+
/* Disable XCVR controls if there is stream started */
+ down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
+ up_read(&card->snd_card->controls_rwsem);
}
return 0;
@@ -588,11 +687,15 @@ static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
/* Enable XCVR controls if there is no stream started */
if (!xcvr->streams) {
if (!xcvr->soc_data->spdif_only) {
+ struct snd_soc_card *card = dai->component->card;
+
+ down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_EARC));
+ up_read(&card->snd_card->controls_rwsem);
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0);
@@ -624,12 +727,24 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- int ret;
+ unsigned long lock_flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&xcvr->lock, lock_flags);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /* set DPATH RESET */
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
+ FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
+ goto release_lock;
+ }
+
if (tx) {
switch (xcvr->mode) {
case FSL_XCVR_MODE_EARC:
@@ -639,16 +754,16 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_ISR_CMDC_TX_EN);
if (ret < 0) {
dev_err(dai->dev, "err updating isr %d\n", ret);
- return ret;
+ goto release_lock;
}
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);
- return ret;
+ goto release_lock;
}
break;
}
@@ -659,7 +774,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
- return ret;
+ goto release_lock;
+ }
+
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+ FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
+ if (ret < 0) {
+ dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
+ goto release_lock;
}
/* clear DPATH RESET */
@@ -668,7 +790,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret);
- return ret;
+ goto release_lock;
}
break;
@@ -681,18 +803,25 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
- return ret;
+ goto release_lock;
+ }
+
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+ FSL_XCVR_IRQ_EARC_ALL, 0);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to clear IER0: %d\n", ret);
+ goto release_lock;
}
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);
- return ret;
+ goto release_lock;
}
if (xcvr->soc_data->spdif_only)
break;
@@ -706,17 +835,20 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0) {
dev_err(dai->dev,
"Err updating ISR %d\n", ret);
- return ret;
+ goto release_lock;
}
break;
}
}
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
- return 0;
+release_lock:
+ spin_unlock_irqrestore(&xcvr->lock, lock_flags);
+ return ret;
}
static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
@@ -888,13 +1020,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
},
};
-static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
- .prepare = fsl_xcvr_prepare,
- .startup = fsl_xcvr_startup,
- .shutdown = fsl_xcvr_shutdown,
- .trigger = fsl_xcvr_trigger,
-};
-
static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
@@ -915,8 +1040,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+ .probe = fsl_xcvr_dai_probe,
+ .prepare = fsl_xcvr_prepare,
+ .startup = fsl_xcvr_startup,
+ .shutdown = fsl_xcvr_shutdown,
+ .trigger = fsl_xcvr_trigger,
+};
+
static struct snd_soc_dai_driver fsl_xcvr_dai = {
- .probe = fsl_xcvr_dai_probe,
.ops = &fsl_xcvr_dai_ops,
.playback = {
.stream_name = "CPU-Playback",
@@ -997,7 +1129,7 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
{
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
- if (xcvr->soc_data->spdif_only)
+ if (!xcvr->soc_data->use_phy)
if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) ||
reg > FSL_XCVR_TX_DPTH_BCRR)
return false;
@@ -1070,7 +1202,7 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
{
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
- if (xcvr->soc_data->spdif_only)
+ if (!xcvr->soc_data->use_phy)
if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA)
return false;
switch (reg) {
@@ -1099,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:
@@ -1120,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 = {
@@ -1136,6 +1311,77 @@ 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);
+ struct device *dev = &xcvr->pdev->dev;
+ unsigned long lock_flags;
+ u32 ext_ctrl;
+
+ dev_dbg(dev, "reset rx path\n");
+ spin_lock_irqsave(&xcvr->lock, lock_flags);
+ regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl);
+
+ if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) {
+ regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_DMA_RD_DIS,
+ FSL_XCVR_EXT_CTRL_DMA_RD_DIS);
+ regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
+ FSL_XCVR_EXT_CTRL_RX_DPTH_RESET);
+ regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_DMA_RD_DIS,
+ 0);
+ regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
+ 0);
+ }
+ spin_unlock_irqrestore(&xcvr->lock, lock_flags);
+}
+
static irqreturn_t irq0_isr(int irq, void *devid)
{
struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
@@ -1149,7 +1395,7 @@ static irqreturn_t irq0_isr(int irq, void *devid)
if (isr & FSL_XCVR_IRQ_NEW_CS) {
dev_dbg(dev, "Received new CS block\n");
isr_clr |= FSL_XCVR_IRQ_NEW_CS;
- if (!xcvr->soc_data->spdif_only) {
+ if (xcvr->soc_data->fw_name) {
/* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
@@ -1175,8 +1421,28 @@ static irqreturn_t irq0_isr(int irq, void *devid)
bitrev32(val);
}
/* clear CS control register */
- memset_io(reg_ctrl, 0, sizeof(val));
+ writel_relaxed(0, reg_ctrl);
}
+ } else {
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_0,
+ (u32 *)&xcvr->rx_iec958.status[0]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_1,
+ (u32 *)&xcvr->rx_iec958.status[4]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_2,
+ (u32 *)&xcvr->rx_iec958.status[8]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_3,
+ (u32 *)&xcvr->rx_iec958.status[12]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_4,
+ (u32 *)&xcvr->rx_iec958.status[16]);
+ regmap_read(xcvr->regmap, FSL_XCVR_RX_CS_DATA_5,
+ (u32 *)&xcvr->rx_iec958.status[20]);
+ for (i = 0; i < 6; i++) {
+ val = *(u32 *)(xcvr->rx_iec958.status + i * 4);
+ *(u32 *)(xcvr->rx_iec958.status + i * 4) =
+ bitrev32(val);
+ }
+ regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
+ FSL_XCVR_RX_DPTH_CTRL_CSA);
}
}
if (isr & FSL_XCVR_IRQ_NEW_UD) {
@@ -1203,6 +1469,33 @@ static irqreturn_t irq0_isr(int irq, void *devid)
dev_dbg(dev, "DMA write request\n");
isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ;
}
+ if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD) {
+ dev_dbg(dev, "CMDC status update\n");
+ isr_clr |= FSL_XCVR_IRQ_CMDC_STATUS_UPD;
+ }
+ if (isr & FSL_XCVR_IRQ_PREAMBLE_MISMATCH) {
+ dev_dbg(dev, "Preamble mismatch\n");
+ isr_clr |= FSL_XCVR_IRQ_PREAMBLE_MISMATCH;
+ }
+ if (isr & FSL_XCVR_IRQ_UNEXP_PRE_REC) {
+ dev_dbg(dev, "Unexpected preamble received\n");
+ isr_clr |= FSL_XCVR_IRQ_UNEXP_PRE_REC;
+ }
+ if (isr & FSL_XCVR_IRQ_M_W_PRE_MISMATCH) {
+ dev_dbg(dev, "M/W preamble mismatch\n");
+ isr_clr |= FSL_XCVR_IRQ_M_W_PRE_MISMATCH;
+ }
+ if (isr & FSL_XCVR_IRQ_B_PRE_MISMATCH) {
+ dev_dbg(dev, "B preamble mismatch\n");
+ isr_clr |= FSL_XCVR_IRQ_B_PRE_MISMATCH;
+ }
+
+ if (isr & (FSL_XCVR_IRQ_PREAMBLE_MISMATCH |
+ FSL_XCVR_IRQ_UNEXP_PRE_REC |
+ FSL_XCVR_IRQ_M_W_PRE_MISMATCH |
+ FSL_XCVR_IRQ_B_PRE_MISMATCH)) {
+ schedule_work(&xcvr->work_rst);
+ }
if (isr_clr) {
regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr);
@@ -1214,6 +1507,8 @@ static irqreturn_t irq0_isr(int irq, void *devid)
static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
.fw_name = "imx/xcvr/xcvr-imx8mp.bin",
+ .use_phy = true,
+ .pll_ver = PLL_MX8MP,
};
static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
@@ -1221,9 +1516,18 @@ static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
.use_edma = true,
};
+static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = {
+ .fw_name = "imx/xcvr/xcvr-imx95.bin",
+ .spdif_only = true,
+ .use_phy = true,
+ .use_edma = true,
+ .pll_ver = PLL_MX95,
+};
+
static const struct of_device_id fsl_xcvr_dt_ids[] = {
{ .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
{ .compatible = "fsl,imx93-xcvr", .data = &fsl_xcvr_imx93_data},
+ { .compatible = "fsl,imx95-xcvr", .data = &fsl_xcvr_imx95_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
@@ -1244,27 +1548,35 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
xcvr->soc_data = of_device_get_match_data(&pdev->dev);
xcvr->ipg_clk = devm_clk_get(dev, "ipg");
- if (IS_ERR(xcvr->ipg_clk)) {
- dev_err(dev, "failed to get ipg clock\n");
- return PTR_ERR(xcvr->ipg_clk);
- }
+ if (IS_ERR(xcvr->ipg_clk))
+ return dev_err_probe(dev, PTR_ERR(xcvr->ipg_clk),
+ "failed to get ipg clock\n");
xcvr->phy_clk = devm_clk_get(dev, "phy");
- if (IS_ERR(xcvr->phy_clk)) {
- dev_err(dev, "failed to get phy clock\n");
- return PTR_ERR(xcvr->phy_clk);
- }
+ if (IS_ERR(xcvr->phy_clk))
+ return dev_err_probe(dev, PTR_ERR(xcvr->phy_clk),
+ "failed to get phy clock\n");
xcvr->spba_clk = devm_clk_get(dev, "spba");
- if (IS_ERR(xcvr->spba_clk)) {
- dev_err(dev, "failed to get spba clock\n");
- return PTR_ERR(xcvr->spba_clk);
- }
+ if (IS_ERR(xcvr->spba_clk))
+ return dev_err_probe(dev, PTR_ERR(xcvr->spba_clk),
+ "failed to get spba clock\n");
xcvr->pll_ipg_clk = devm_clk_get(dev, "pll_ipg");
- if (IS_ERR(xcvr->pll_ipg_clk)) {
- dev_err(dev, "failed to get pll_ipg clock\n");
- return PTR_ERR(xcvr->pll_ipg_clk);
+ if (IS_ERR(xcvr->pll_ipg_clk))
+ return dev_err_probe(dev, PTR_ERR(xcvr->pll_ipg_clk),
+ "failed to get pll_ipg clock\n");
+
+ 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");
@@ -1277,17 +1589,42 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
xcvr->regmap = devm_regmap_init_mmio_clk(dev, NULL, regs,
&fsl_xcvr_regmap_cfg);
- if (IS_ERR(xcvr->regmap)) {
- dev_err(dev, "failed to init XCVR regmap: %ld\n",
- PTR_ERR(xcvr->regmap));
- return PTR_ERR(xcvr->regmap);
+ if (IS_ERR(xcvr->regmap))
+ return dev_err_probe(dev, PTR_ERR(xcvr->regmap), "failed to init XCVR regmap\n");
+
+ 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))
+ return dev_err_probe(dev, PTR_ERR(xcvr->regmap_phy),
+ "failed to init XCVR PHY regmap\n");
+
+ 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))
+ return dev_err_probe(dev, PTR_ERR(xcvr->regmap_pll),
+ "failed to init XCVR PLL regmap\n");
+ break;
+ case PLL_MX95:
+ xcvr->regmap_pll = devm_regmap_init(dev, NULL, xcvr,
+ &fsl_xcvr_regmap_pllv1_cfg);
+ if (IS_ERR(xcvr->regmap_pll))
+ return dev_err_probe(dev, PTR_ERR(xcvr->regmap_pll),
+ "failed to init XCVR PLL regmap\n");
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL,
+ "Error for PLL version %d\n",
+ xcvr->soc_data->pll_ver);
+ }
}
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");
- return PTR_ERR(xcvr->reset);
- }
+ if (IS_ERR(xcvr->reset))
+ return dev_err_probe(dev, PTR_ERR(xcvr->reset),
+ "failed to get XCVR reset control\n");
/* get IRQs */
irq = platform_get_irq(pdev, 0);
@@ -1295,17 +1632,13 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
return irq;
ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr);
- if (ret) {
- dev_err(dev, "failed to claim IRQ0: %i\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to claim IRQ0\n");
rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo");
tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo");
- if (!rx_res || !tx_res) {
- dev_err(dev, "could not find rxfifo or txfifo resource\n");
- return -EINVAL;
- }
+ if (!rx_res || !tx_res)
+ return dev_err_probe(dev, -EINVAL, "could not find rxfifo or txfifo resource\n");
xcvr->dma_prms_rx.chan_name = "rx";
xcvr->dma_prms_tx.chan_name = "tx";
xcvr->dma_prms_rx.addr = rx_res->start;
@@ -1316,6 +1649,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
@@ -1324,8 +1661,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
if (ret) {
pm_runtime_disable(dev);
- dev_err(dev, "failed to pcm register\n");
- return ret;
+ return dev_err_probe(dev, ret, "failed to pcm register\n");
}
ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
@@ -1336,30 +1672,26 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
fsl_xcvr_comp.name);
}
+ INIT_WORK(&xcvr->work_rst, reset_rx_work);
+ spin_lock_init(&xcvr->lock);
return ret;
}
static void fsl_xcvr_remove(struct platform_device *pdev)
{
+ struct fsl_xcvr *xcvr = dev_get_drvdata(&pdev->dev);
+
+ cancel_work_sync(&xcvr->work_rst);
pm_runtime_disable(&pdev->dev);
}
-static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
+static int fsl_xcvr_runtime_suspend(struct device *dev)
{
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
int ret;
- /*
- * Clear interrupts, when streams starts or resumes after
- * suspend, interrupts are enabled in prepare(), so no need
- * to enable interrupts in resume().
- */
- ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
- FSL_XCVR_IRQ_EARC_ALL, 0);
- if (ret < 0)
- dev_err(dev, "Failed to clear IER0: %d\n", 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,
@@ -1369,6 +1701,10 @@ static __maybe_unused 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);
@@ -1378,7 +1714,7 @@ static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
return 0;
}
-static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev)
+static int fsl_xcvr_runtime_resume(struct device *dev)
{
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
int ret;
@@ -1413,6 +1749,12 @@ static __maybe_unused 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);
@@ -1422,31 +1764,49 @@ static __maybe_unused 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->soc_data->fw_name) {
+ 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;
@@ -1463,21 +1823,18 @@ stop_ipg_clk:
}
static const struct dev_pm_ops fsl_xcvr_pm_ops = {
- SET_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)
+ RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend, fsl_xcvr_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_xcvr_driver = {
.probe = fsl_xcvr_probe,
.driver = {
- .name = "fsl,imx8mp-audio-xcvr",
- .pm = &fsl_xcvr_pm_ops,
+ .name = "fsl-xcvr",
+ .pm = pm_ptr(&fsl_xcvr_pm_ops),
.of_match_table = fsl_xcvr_dt_ids,
},
- .remove_new = fsl_xcvr_remove,
+ .remove = fsl_xcvr_remove,
};
module_platform_driver(fsl_xcvr_driver);
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
index 044058fc6aa2..dade3945cc0c 100644
--- a/sound/soc/fsl/fsl_xcvr.h
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -165,6 +165,11 @@
FSL_XCVR_IRQ_MUTE | \
FSL_XCVR_IRQ_FIFO_UOFL_ERR | \
FSL_XCVR_IRQ_HOST_WAKEUP | \
+ FSL_XCVR_IRQ_CMDC_STATUS_UPD |\
+ FSL_XCVR_IRQ_B_PRE_MISMATCH |\
+ FSL_XCVR_IRQ_M_W_PRE_MISMATCH |\
+ FSL_XCVR_IRQ_PREAMBLE_MISMATCH |\
+ FSL_XCVR_IRQ_UNEXP_PRE_REC |\
FSL_XCVR_IRQ_ARC_MODE)
#define FSL_XCVR_ISR_CMDC_TX_EN BIT(3)
@@ -229,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
@@ -236,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)
@@ -291,4 +309,95 @@
#define FSL_XCVR_RX_CS_BUFF_1 0xA0 /* Second RX CS buffer */
#define FSL_XCVR_CAP_DATA_STR 0x300 /* Capabilities data structure */
+/* GP PLL Registers */
+#define FSL_XCVR_GP_PLL_CTRL 0x00
+#define FSL_XCVR_GP_PLL_CTRL_SET 0x04
+#define FSL_XCVR_GP_PLL_CTRL_CLR 0x08
+#define FSL_XCVR_GP_PLL_CTRL_TOG 0x0C
+#define FSL_XCVR_GP_PLL_ANA_PRG 0x10
+#define FSL_XCVR_GP_PLL_ANA_PRG_SET 0x14
+#define FSL_XCVR_GP_PLL_ANA_PRG_CLR 0x18
+#define FSL_XCVR_GP_PLL_ANA_PRG_TOG 0x1C
+#define FSL_XCVR_GP_PLL_TEST 0x20
+#define FSL_XCVR_GP_PLL_TEST_SET 0x24
+#define FSL_XCVR_GP_PLL_TEST_CLR 0x28
+#define FSL_XCVR_GP_PLL_TEST_TOG 0x2C
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM 0x30
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_SET 0x34
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_CLR 0x38
+#define FSL_XCVR_GP_PLL_SPREAD_SPECTRUM_TOG 0x3C
+#define FSL_XCVR_GP_PLL_NUMERATOR 0x40
+#define FSL_XCVR_GP_PLL_NUMERATOR_SET 0x44
+#define FSL_XCVR_GP_PLL_NUMERATOR_CLR 0x48
+#define FSL_XCVR_GP_PLL_NUMERATOR_TOG 0x4C
+#define FSL_XCVR_GP_PLL_DENOMINATOR 0x50
+#define FSL_XCVR_GP_PLL_DENOMINATOR_SET 0x54
+#define FSL_XCVR_GP_PLL_DENOMINATOR_CLR 0x58
+#define FSL_XCVR_GP_PLL_DENOMINATOR_TOG 0x5C
+#define FSL_XCVR_GP_PLL_DIV 0x60
+#define FSL_XCVR_GP_PLL_DIV_SET 0x64
+#define FSL_XCVR_GP_PLL_DIV_CLR 0x68
+#define FSL_XCVR_GP_PLL_DIV_TOG 0x6C
+#define FSL_XCVR_GP_PLL_DFS_CTRL0 0x70
+#define FSL_XCVR_GP_PLL_DFS_CTRL0_SET 0x74
+#define FSL_XCVR_GP_PLL_DFS_CTRL0_CLR 0x78
+#define FSL_XCVR_GP_PLL_DFS_CTRL0_TOG 0x7C
+#define FSL_XCVR_GP_PLL_DFS_DIV0 0x80
+#define FSL_XCVR_GP_PLL_DFS_DIV0_SET 0x84
+#define FSL_XCVR_GP_PLL_DFS_DIV0_CLR 0x88
+#define FSL_XCVR_GP_PLL_DFS_DIV0_TOG 0x8C
+#define FSL_XCVR_GP_PLL_DFS_CTRL1 0x90
+#define FSL_XCVR_GP_PLL_DFS_CTRL1_SET 0x94
+#define FSL_XCVR_GP_PLL_DFS_CTRL1_CLR 0x98
+#define FSL_XCVR_GP_PLL_DFS_CTRL1_TOG 0x9C
+#define FSL_XCVR_GP_PLL_DFS_DIV1 0xA0
+#define FSL_XCVR_GP_PLL_DFS_DIV1_SET 0xA4
+#define FSL_XCVR_GP_PLL_DFS_DIV1_CLR 0xA8
+#define FSL_XCVR_GP_PLL_DFS_DIV1_TOG 0xAC
+#define FSL_XCVR_GP_PLL_DFS_CTRL2 0xB0
+#define FSL_XCVR_GP_PLL_DFS_CTRL2_SET 0xB4
+#define FSL_XCVR_GP_PLL_DFS_CTRL2_CLR 0xB8
+#define FSL_XCVR_GP_PLL_DFS_CTRL2_TOG 0xBC
+#define FSL_XCVR_GP_PLL_DFS_DIV2 0xC0
+#define FSL_XCVR_GP_PLL_DFS_DIV2_SET 0xC4
+#define FSL_XCVR_GP_PLL_DFS_DIV2_CLR 0xC8
+#define FSL_XCVR_GP_PLL_DFS_DIV2_TOG 0xCC
+#define FSL_XCVR_GP_PLL_DFS_CTRL3 0xD0
+#define FSL_XCVR_GP_PLL_DFS_CTRL3_SET 0xD4
+#define FSL_XCVR_GP_PLL_DFS_CTRL3_CLR 0xD8
+#define FSL_XCVR_GP_PLL_DFS_CTRL3_TOG 0xDC
+#define FSL_XCVR_GP_PLL_DFS_DIV3 0xE0
+#define FSL_XCVR_GP_PLL_DFS_DIV3_SET 0xE4
+#define FSL_XCVR_GP_PLL_DFS_DIV3_CLR 0xE8
+#define FSL_XCVR_GP_PLL_DFS_DIV3_TOG 0xEC
+#define FSL_XCVR_GP_PLL_STATUS 0xF0
+#define FSL_XCVR_GP_PLL_STATUS_SET 0xF4
+#define FSL_XCVR_GP_PLL_STATUS_CLR 0xF8
+#define FSL_XCVR_GP_PLL_STATUS_TOG 0xFC
+
+/* GP PLL Control Register */
+#define FSL_XCVR_GP_PLL_CTRL_LBYPASS BIT(31)
+#define FSL_XCVR_GP_PLL_CTRL_HCS BIT(16)
+#define FSL_XCVR_GP_PLL_CTRL_MSD BIT(12)
+#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN3 BIT(11)
+#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN2 BIT(10)
+#define FSL_XCVR_GP_PLL_CTRL_DITHER_EN1 BIT(9)
+#define FSL_XCVR_GP_PLL_CTRL_SPREADCTL BIT(8)
+#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_BYPASS BIT(2)
+#define FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN BIT(1)
+#define FSL_XCVR_GP_PLL_CTRL_POWERUP BIT(0)
+
+/* GP PLL Numerator Register */
+#define FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT 2
+#define FSL_XCVR_GP_PLL_NUMERATOR_MFN GENMASK(31, 2)
+
+/* GP PLL Denominator Register */
+#define FSL_XCVR_GP_PLL_DENOMINATOR_MFD GENMASK(29, 0)
+
+/* GP PLL Dividers Register */
+#define FSL_XCVR_GP_PLL_DIV_MFI_SHIFT 16
+#define FSL_XCVR_GP_PLL_DIV_MFI GENMASK(24, 16)
+#define FSL_XCVR_GP_PLL_DIV_RDIV GENMASK(15, 13)
+#define FSL_XCVR_GP_PLL_DIV_ODIV GENMASK(7, 0)
+
#endif /* __FSL_XCVR_H */
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index d5234ac4b09b..38aafb8954c7 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -12,6 +12,7 @@
*/
struct imx_audio_rpmsg {
struct platform_device *rpmsg_pdev;
+ struct platform_device *card_pdev;
};
static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
@@ -87,14 +88,24 @@ static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
/* Register platform driver for rpmsg routine */
data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
- IMX_PCM_DRV_NAME,
- PLATFORM_DEVID_AUTO,
+ rpdev->id.name,
+ PLATFORM_DEVID_NONE,
NULL, 0);
if (IS_ERR(data->rpmsg_pdev)) {
dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
ret = PTR_ERR(data->rpmsg_pdev);
}
+ data->card_pdev = platform_device_register_data(&rpdev->dev,
+ "imx-audio-rpmsg",
+ PLATFORM_DEVID_AUTO,
+ rpdev->id.name,
+ strlen(rpdev->id.name) + 1);
+ if (IS_ERR(data->card_pdev)) {
+ dev_err(&rpdev->dev, "failed to register rpmsg card.\n");
+ ret = PTR_ERR(data->card_pdev);
+ }
+
return ret;
}
@@ -105,6 +116,9 @@ static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
if (data->rpmsg_pdev)
platform_device_unregister(data->rpmsg_pdev);
+ if (data->card_pdev)
+ platform_device_unregister(data->card_pdev);
+
dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
}
@@ -113,10 +127,10 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
{ .name = "rpmsg-micfil-channel" },
{ },
};
+MODULE_DEVICE_TABLE(rpmsg, imx_audio_rpmsg_id_table);
static struct rpmsg_driver imx_audio_rpmsg_driver = {
.drv.name = "imx_audio_rpmsg",
- .drv.owner = THIS_MODULE,
.id_table = imx_audio_rpmsg_id_table,
.probe = imx_audio_rpmsg_probe,
.callback = imx_audio_rpmsg_cb,
@@ -127,5 +141,5 @@ module_rpmsg_driver(imx_audio_rpmsg_driver);
MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
-MODULE_ALIAS("platform:imx_audio_rpmsg");
+MODULE_ALIAS("rpmsg:imx_audio_rpmsg");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
index c93616e50f4d..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 = asoc_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)
@@ -72,7 +48,7 @@ static int imx_audmix_fe_startup(struct snd_pcm_substream *substream)
static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct device *dev = rtd->card->dev;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF;
@@ -84,13 +60,13 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN;
/* set DAI configuration */
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), fmt);
if (ret) {
dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
return ret;
}
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), FSL_SAI_CLK_MAST1, 0, dir);
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), FSL_SAI_CLK_MAST1, 0, dir);
if (ret) {
dev_err(dev, "failed to set cpu sysclk: %d\n", ret);
return ret;
@@ -100,7 +76,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
* Per datasheet, AUDMIX expects 8 slots and 32 bits
* for every slot in TDM mode.
*/
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), BIT(channels) - 1,
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), BIT(channels) - 1,
BIT(channels) - 1, 8, 32);
if (ret)
dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
@@ -111,7 +87,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct device *dev = rtd->card->dev;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF;
@@ -124,7 +100,7 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream,
fmt |= SND_SOC_DAIFMT_BC_FC;
/* set AUDMIX DAI configuration */
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), fmt);
if (ret)
dev_err(dev, "failed to set AUDMIX DAI fmt: %d\n", ret);
@@ -140,6 +116,13 @@ static const struct snd_soc_ops imx_audmix_be_ops = {
.hw_params = imx_audmix_be_hw_params,
};
+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", "SAI-Capture"},
+ {"SAI-Playback", "SAI-Playback", "AUDMIX-Capture-0"},
+};
+
static int imx_audmix_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -150,7 +133,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
struct imx_audmix *priv;
int i, num_dai, ret;
const char *fe_name_pref = "HiFi-AUDMIX-FE-";
- char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name;
+ char *be_name, *dai_name;
if (pdev->dev.parent) {
audmix_np = pdev->dev.parent->of_node;
@@ -183,6 +166,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ num_dai += 1;
priv->num_dai = 2 * num_dai;
priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai,
sizeof(struct snd_soc_dai_link), GFP_KERNEL);
@@ -196,7 +180,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
if (!priv->dai_conf)
return -ENOMEM;
- priv->num_dapm_routes = 3 * num_dai;
+ priv->num_dapm_routes = num_dai;
priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes,
sizeof(struct snd_soc_dapm_route),
GFP_KERNEL);
@@ -211,8 +195,12 @@ static int imx_audmix_probe(struct platform_device *pdev)
if (!dlc)
return -ENOMEM;
- ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i,
- &args);
+ if (i == num_dai - 1)
+ ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, 0,
+ &args);
+ else
+ ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i,
+ &args);
if (ret < 0) {
dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n");
return ret;
@@ -226,16 +214,14 @@ static int imx_audmix_probe(struct platform_device *pdev)
put_device(&cpu_pdev->dev);
dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s",
- fe_name_pref, args.np->full_name + 1);
+ fe_name_pref, args.np->full_name);
+ if (!dai_name)
+ return -ENOMEM;
dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name);
- if (i == 0) {
+ if (i == num_dai - 1)
out_cpu_np = args.np;
- capture_dai_name =
- devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
- dai_name, "CPU-Capture");
- }
/*
* CPU == Platform
@@ -243,32 +229,32 @@ static int imx_audmix_probe(struct platform_device *pdev)
*/
priv->dai[i].cpus =
priv->dai[i].platforms = &dlc[0];
- priv->dai[i].codecs = &asoc_dummy_dlc;
+ priv->dai[i].codecs = &snd_soc_dummy_dlc;
priv->dai[i].num_cpus = 1;
priv->dai[i].num_codecs = 1;
priv->dai[i].num_platforms = 1;
-
- priv->dai[i].name = dai_name;
+ priv->dai[i].name = name[0][i];
priv->dai[i].stream_name = "HiFi-AUDMIX-FE";
priv->dai[i].cpus->of_node = args.np;
- priv->dai[i].cpus->dai_name = dev_name(&cpu_pdev->dev);
+ priv->dai[i].cpus->dai_name = name[1][i];
+
priv->dai[i].dynamic = 1;
- priv->dai[i].dpcm_playback = 1;
- priv->dai[i].dpcm_capture = (i == 0 ? 1 : 0);
+ if (i == num_dai - 1)
+ priv->dai[i].capture_only = 1;
+ else
+ priv->dai[i].playback_only = 1;
priv->dai[i].ignore_pmdown_time = 1;
priv->dai[i].ops = &imx_audmix_fe_ops;
/* Add AUDMIX Backend */
be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"audmix-%d", i);
- be_pb = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- "AUDMIX-Playback-%d", i);
- be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- "AUDMIX-Capture-%d", i);
+ if (!be_name)
+ return -ENOMEM;
priv->dai[num_dai + i].cpus = &dlc[1];
- priv->dai[num_dai + i].codecs = &asoc_dummy_dlc;
+ priv->dai[num_dai + i].codecs = &snd_soc_dummy_dlc;
priv->dai[num_dai + i].num_cpus = 1;
priv->dai[num_dai + i].num_codecs = 1;
@@ -277,22 +263,33 @@ static int imx_audmix_probe(struct platform_device *pdev)
priv->dai[num_dai + i].cpus->of_node = audmix_np;
priv->dai[num_dai + i].cpus->dai_name = be_name;
priv->dai[num_dai + i].no_pcm = 1;
- priv->dai[num_dai + i].dpcm_playback = 1;
- priv->dai[num_dai + i].dpcm_capture = 1;
+ if (i == num_dai - 1)
+ priv->dai[num_dai + i].capture_only = 1;
+ else
+ priv->dai[num_dai + i].playback_only = 1;
priv->dai[num_dai + i].ignore_pmdown_time = 1;
priv->dai[num_dai + i].ops = &imx_audmix_be_ops;
priv->dai_conf[i].dlc.of_node = args.np;
priv->dai_conf[i].name_prefix = dai_name;
- priv->dapm_routes[i].source =
- devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
- dai_name, "CPU-Playback");
- priv->dapm_routes[i].sink = be_pb;
- priv->dapm_routes[num_dai + i].source = be_pb;
- priv->dapm_routes[num_dai + i].sink = be_cp;
- priv->dapm_routes[2 * num_dai + i].source = be_cp;
- priv->dapm_routes[2 * num_dai + i].sink = capture_dai_name;
+ if (i == num_dai - 1) {
+ priv->dapm_routes[i].sink =
+ devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
+ dai_name, name[2][i]);
+ if (!priv->dapm_routes[i].sink)
+ return -ENOMEM;
+
+ priv->dapm_routes[i].source = name[3][i];
+ } else {
+ priv->dapm_routes[i].source =
+ devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
+ dai_name, name[3][i]);
+ if (!priv->dapm_routes[i].source)
+ return -ENOMEM;
+
+ priv->dapm_routes[i].sink = name[2][i];
+ }
}
cpu_pdev = of_find_device_by_node(out_cpu_np);
@@ -302,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 -EINVAL;
- }
-
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 be003a117b39..f8335a04595a 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -13,7 +13,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -238,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;
@@ -306,7 +305,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
return -EINVAL;
}
- regcache = devm_kzalloc(&pdev->dev, sizeof(u32) * reg_max, GFP_KERNEL);
+ regcache = devm_kcalloc(&pdev->dev, reg_max, sizeof(u32), GFP_KERNEL);
if (!regcache)
return -ENOMEM;
@@ -321,7 +320,6 @@ static void imx_audmux_remove(struct platform_device *pdev)
audmux_debugfs_remove();
}
-#ifdef CONFIG_PM_SLEEP
static int imx_audmux_suspend(struct device *dev)
{
int i;
@@ -349,18 +347,17 @@ static int imx_audmux_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops imx_audmux_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume)
+ SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume)
};
static struct platform_driver imx_audmux_driver = {
.probe = imx_audmux_probe,
- .remove_new = imx_audmux_remove,
+ .remove = imx_audmux_remove,
.driver = {
.name = DRIVER_NAME,
- .pm = &imx_audmux_pm,
+ .pm = pm_sleep_ptr(&imx_audmux_pm),
.of_match_table = imx_audmux_dt_ids,
}
};
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
index 78e2e3932ba5..28699d7b75ca 100644
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -5,9 +5,8 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/i2c.h>
-#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -26,6 +25,8 @@ enum codec_type {
CODEC_AK4458,
CODEC_AK4497,
CODEC_AK5552,
+ CODEC_CS42888,
+ CODEC_WM8524,
};
/*
@@ -186,6 +187,23 @@ static struct imx_akcodec_tdm_fs_mul ak5558_tdm_fs_mul[] = {
{ .min = 512, .max = 512, .mul = 1024 },
};
+static struct imx_akcodec_fs_mul cs42888_fs_mul[] = {
+ { .rmin = 8000, .rmax = 48000, .wmin = 256, .wmax = 1024, },
+ { .rmin = 64000, .rmax = 96000, .wmin = 128, .wmax = 512, },
+ { .rmin = 176400, .rmax = 192000, .wmin = 64, .wmax = 256, },
+};
+
+static struct imx_akcodec_tdm_fs_mul cs42888_tdm_fs_mul[] = {
+ { .min = 256, .max = 256, .mul = 256 },
+};
+
+static struct imx_akcodec_fs_mul wm8524_fs_mul[] = {
+ { .rmin = 8000, .rmax = 32000, .wmin = 256, .wmax = 1152, },
+ { .rmin = 44100, .rmax = 48000, .wmin = 256, .wmax = 768, },
+ { .rmin = 88200, .rmax = 96000, .wmin = 128, .wmax = 384, },
+ { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 192, },
+};
+
static const u32 akcodec_rates[] = {
8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
96000, 176400, 192000, 352800, 384000, 705600, 768000,
@@ -211,6 +229,18 @@ static const u32 ak5558_tdm_channels[] = {
1, 2, 3, 4, 5, 6, 7, 8,
};
+static const u32 cs42888_channels[] = {
+ 1, 2, 4, 6, 8,
+};
+
+static const u32 cs42888_tdm_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8,
+};
+
+static const u32 wm8524_channels[] = {
+ 2,
+};
+
static bool format_is_dsd(struct snd_pcm_hw_params *params)
{
snd_pcm_format_t format = params_format(params);
@@ -242,6 +272,8 @@ static bool codec_is_akcodec(unsigned int type)
case CODEC_AK4497:
case CODEC_AK5558:
case CODEC_AK5552:
+ case CODEC_CS42888:
+ case CODEC_WM8524:
return true;
default:
break;
@@ -253,10 +285,10 @@ static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
int slots, int slot_width)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card);
const struct imx_card_plat_data *plat_data = data->plat_data;
- struct dai_link_data *link_data = &data->link_data[rtd->num];
+ struct dai_link_data *link_data = &data->link_data[rtd->id];
unsigned int width = slots * slot_width;
unsigned int rate = params_rate(params);
int i;
@@ -290,11 +322,11 @@ static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream,
static int imx_aif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_card *card = rtd->card;
struct imx_card_data *data = snd_soc_card_get_drvdata(card);
- struct dai_link_data *link_data = &data->link_data[rtd->num];
+ struct dai_link_data *link_data = &data->link_data[rtd->id];
struct imx_card_plat_data *plat_data = data->plat_data;
struct device *dev = card->dev;
struct snd_soc_dai *codec_dai;
@@ -341,13 +373,15 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- BIT(slots) - 1,
- BIT(slots) - 1,
- slots, slot_width);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret);
- return ret;
+ if (format_is_tdm(link_data)) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ BIT(slots) - 1,
+ BIT(slots) - 1,
+ slots, slot_width);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret);
+ return ret;
+ }
}
}
@@ -371,6 +405,11 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret);
return ret;
}
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set codec dai mclk rate (%lu): %d\n", mclk_freq, ret);
+ return ret;
+ }
return 0;
}
@@ -406,10 +445,10 @@ static int ak5558_hw_rule_rate(struct snd_pcm_hw_params *p, struct snd_pcm_hw_ru
static int imx_aif_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct imx_card_data *data = snd_soc_card_get_drvdata(card);
- struct dai_link_data *link_data = &data->link_data[rtd->num];
+ struct dai_link_data *link_data = &data->link_data[rtd->id];
static struct snd_pcm_hw_constraint_list constraint_rates;
static struct snd_pcm_hw_constraint_list constraint_channels;
int ret = 0;
@@ -451,9 +490,24 @@ static int imx_aif_startup(struct snd_pcm_substream *substream)
return ret;
}
+static void imx_aif_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai;
+ struct snd_soc_dai *codec_dai;
+ int i;
+
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai)
+ snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT);
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai)
+ snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN);
+}
+
static const struct snd_soc_ops imx_aif_ops = {
.hw_params = imx_aif_hw_params,
.startup = imx_aif_startup,
+ .shutdown = imx_aif_shutdown,
};
static const struct snd_soc_ops imx_aif_ops_be = {
@@ -487,11 +541,11 @@ static int imx_card_parse_of(struct imx_card_data *data)
struct device_node *platform = NULL;
struct device_node *codec = NULL;
struct device_node *cpu = NULL;
- struct device_node *np;
struct device *dev = card->dev;
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;
@@ -503,7 +557,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;
@@ -517,7 +571,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
if (!card->dai_link)
return -ENOMEM;
- data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
+ data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL);
if (!data->link_data)
return -ENOMEM;
@@ -525,11 +579,10 @@ static int imx_card_parse_of(struct imx_card_data *data)
link = card->dai_link;
link_data = data->link_data;
- for_each_child_of_node(dev->of_node, np) {
+ for_each_child_of_node_scoped(dev->of_node, np) {
dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
if (!dlc) {
- ret = -ENOMEM;
- goto err_put_np;
+ return -ENOMEM;
}
link->cpus = &dlc[0];
@@ -540,8 +593,8 @@ static int imx_card_parse_of(struct imx_card_data *data)
ret = of_property_read_string(np, "link-name", &link->name);
if (ret) {
- dev_err(card->dev, "error getting codec dai_link name\n");
- goto err_put_np;
+ return dev_err_probe(card->dev, ret,
+ "error getting codec dai_link name\n");
}
cpu = of_get_child_by_name(np, "cpu");
@@ -551,10 +604,10 @@ static int imx_card_parse_of(struct imx_card_data *data)
goto err;
}
- ret = of_parse_phandle_with_args(cpu, "sound-dai",
- "#sound-dai-cells", 0, &args);
+ ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0);
if (ret) {
- dev_err(card->dev, "%s: error getting cpu phandle\n", link->name);
+ dev_err_probe(card->dev, ret,
+ "%s: error getting cpu dai info\n", link->name);
goto err;
}
@@ -582,17 +635,9 @@ static int imx_card_parse_of(struct imx_card_data *data)
}
}
- link->cpus->of_node = args.np;
link->platforms->of_node = link->cpus->of_node;
link->id = args.args[0];
- ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name);
- if (ret) {
- dev_err_probe(card->dev, ret,
- "%s: error getting cpu dai name\n", link->name);
- goto err;
- }
-
codec = of_get_child_by_name(np, "codec");
if (codec) {
ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
@@ -613,9 +658,13 @@ static int imx_card_parse_of(struct imx_card_data *data)
plat_data->type = CODEC_AK5558;
else if (!strcmp(link->codecs->dai_name, "ak5552-aif"))
plat_data->type = CODEC_AK5552;
+ else if (!strcmp(link->codecs->dai_name, "cs42888"))
+ plat_data->type = CODEC_CS42888;
+ else if (!strcmp(link->codecs->dai_name, "wm8524-hifi"))
+ plat_data->type = CODEC_WM8524;
} else {
- link->codecs = &asoc_dummy_dlc;
+ link->codecs = &snd_soc_dummy_dlc;
link->num_codecs = 1;
}
@@ -649,9 +698,12 @@ static int imx_card_parse_of(struct imx_card_data *data)
}
} else if (!strncmp(link->name, "HiFi-ASRC-BE", 12)) {
/* DPCM backend */
+ /*
+ * No need to have link->platforms. alloced dlc[1] will be just wasted,
+ * but it won't leak.
+ */
link->no_pcm = 1;
- link->platforms->of_node = NULL;
- link->platforms->name = "snd-soc-dummy";
+ link->platforms = NULL;
link->be_hw_params_fixup = be_hw_params_fixup;
link->ops = &imx_aif_ops_be;
@@ -659,11 +711,12 @@ static int imx_card_parse_of(struct imx_card_data *data)
link->ops = &imx_aif_ops;
}
- if (link->no_pcm || link->dynamic)
- snd_soc_dai_link_set_capabilities(link);
+ graph_util_parse_link_direction(np, &playback_only, &capture_only);
+ link->playback_only = playback_only;
+ link->capture_only = capture_only;
/* Get dai fmt */
- ret = asoc_simple_parse_daifmt(dev, np, codec,
+ ret = simple_util_parse_daifmt(dev, np, codec,
NULL, &link->dai_fmt);
if (ret)
link->dai_fmt = SND_SOC_DAIFMT_NB_NF |
@@ -700,8 +753,7 @@ err:
of_node_put(cpu);
of_node_put(codec);
of_node_put(platform);
-err_put_np:
- of_node_put(np);
+
return ret;
}
@@ -722,6 +774,7 @@ static int imx_card_probe(struct platform_device *pdev)
data->plat_data = plat_data;
data->card.dev = &pdev->dev;
+ data->card.owner = THIS_MODULE;
dev_set_drvdata(&pdev->dev, &data->card);
snd_soc_card_set_drvdata(&data->card, data);
@@ -749,6 +802,8 @@ static int imx_card_probe(struct platform_device *pdev)
data->dapm_routes[i].sink =
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s",
i + 1, "Playback");
+ if (!data->dapm_routes[i].sink)
+ return -ENOMEM;
data->dapm_routes[i].source = "CPU-Playback";
}
}
@@ -766,12 +821,24 @@ static int imx_card_probe(struct platform_device *pdev)
data->dapm_routes[i].source =
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s",
i + 1, "Capture");
+ if (!data->dapm_routes[i].source)
+ return -ENOMEM;
data->dapm_routes[i].sink = "CPU-Capture";
}
}
data->dapm_routes[i].sink = "ASRC-Capture";
data->dapm_routes[i].source = "CPU-Capture";
break;
+ case CODEC_CS42888:
+ data->dapm_routes[0].sink = "Playback";
+ data->dapm_routes[0].source = "CPU-Playback";
+ data->dapm_routes[1].sink = "CPU-Capture";
+ data->dapm_routes[1].source = "Capture";
+ break;
+ case CODEC_WM8524:
+ data->dapm_routes[0].sink = "Playback";
+ data->dapm_routes[0].source = "CPU-Playback";
+ break;
default:
break;
}
@@ -811,6 +878,22 @@ static int imx_card_probe(struct platform_device *pdev)
plat_data->support_tdm_channels = ak5558_tdm_channels;
plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels);
break;
+ case CODEC_CS42888:
+ plat_data->fs_mul = cs42888_fs_mul;
+ plat_data->num_fs_mul = ARRAY_SIZE(cs42888_fs_mul);
+ plat_data->tdm_fs_mul = cs42888_tdm_fs_mul;
+ plat_data->num_tdm_fs_mul = ARRAY_SIZE(cs42888_tdm_fs_mul);
+ plat_data->support_channels = cs42888_channels;
+ plat_data->num_channels = ARRAY_SIZE(cs42888_channels);
+ plat_data->support_tdm_channels = cs42888_tdm_channels;
+ plat_data->num_tdm_channels = ARRAY_SIZE(cs42888_tdm_channels);
+ break;
+ case CODEC_WM8524:
+ plat_data->fs_mul = wm8524_fs_mul;
+ plat_data->num_fs_mul = ARRAY_SIZE(wm8524_fs_mul);
+ plat_data->support_channels = wm8524_channels;
+ plat_data->num_channels = ARRAY_SIZE(wm8524_channels);
+ break;
default:
break;
}
@@ -826,8 +909,8 @@ static int imx_card_probe(struct platform_device *pdev)
}
for_each_card_prelinks(&data->card, i, link) {
if (link->dynamic == 1 && link_be) {
- link->dpcm_playback = link_be->dpcm_playback;
- link->dpcm_capture = link_be->dpcm_capture;
+ link->playback_only = link_be->playback_only;
+ link->capture_only = link_be->capture_only;
}
}
}
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 85bd36fb68a2..3ef92f6dfc6b 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -3,12 +3,11 @@
// Copyright 2012 Freescale Semiconductor, Inc.
// Copyright 2012 Linaro Ltd.
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/i2c.h>
-#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -23,12 +22,11 @@ struct imx_es8328_data {
struct snd_soc_card card;
char codec_dai_name[DAI_NAME_SIZE];
char platform_name[DAI_NAME_SIZE];
- int jack_gpio;
+ struct gpio_desc *jack_gpiod;
};
static struct snd_soc_jack_gpio headset_jack_gpios[] = {
{
- .gpio = -1,
.name = "headset-gpio",
.report = SND_JACK_HEADSET,
.invert = 0,
@@ -37,6 +35,16 @@ static struct snd_soc_jack_gpio headset_jack_gpios[] = {
};
static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
{
@@ -44,15 +52,17 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
struct imx_es8328_data, card);
int ret = 0;
- /* Headphone jack detection */
- if (gpio_is_valid(data->jack_gpio)) {
- ret = snd_soc_card_jack_new(rtd->card, "Headphone",
- SND_JACK_HEADPHONE | SND_JACK_BTN_0,
- &headset_jack);
+ if (data->jack_gpiod) {
+ /* Headphone jack detection */
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
if (ret)
return ret;
- headset_jack_gpios[0].gpio = data->jack_gpio;
+ headset_jack_gpios[0].desc = data->jack_gpiod;
ret = snd_soc_jack_add_gpios(&headset_jack,
ARRAY_SIZE(headset_jack_gpios),
headset_jack_gpios);
@@ -68,6 +78,11 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
};
+static const struct snd_kcontrol_new imx_es8328_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
static int imx_es8328_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -157,7 +172,11 @@ static int imx_es8328_probe(struct platform_device *pdev)
data->dev = dev;
- data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
+ data->jack_gpiod = devm_gpiod_get_optional(dev, "jack", GPIOD_IN);
+ if (IS_ERR(data->jack_gpiod)) {
+ ret = PTR_ERR(data->jack_gpiod);
+ goto put_device;
+ }
/*
* CPU == Platform
@@ -183,6 +202,8 @@ static int imx_es8328_probe(struct platform_device *pdev)
data->card.dev = dev;
data->card.dapm_widgets = imx_es8328_dapm_widgets;
data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
+ data->card.controls = imx_es8328_controls;
+ data->card.num_controls = ARRAY_SIZE(imx_es8328_controls);
ret = snd_soc_of_parse_card_name(&data->card, "model");
if (ret) {
dev_err(dev, "Unable to parse card name\n");
diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c
index b6cc7e6c2a32..1115189cc640 100644
--- a/sound/soc/fsl/imx-hdmi.c
+++ b/sound/soc/fsl/imx-hdmi.c
@@ -32,10 +32,10 @@ struct imx_hdmi_data {
static int imx_hdmi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct imx_hdmi_data *data = snd_soc_card_get_drvdata(rtd->card);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_card *card = rtd->card;
struct device *dev = card->dev;
u32 slot_width = data->cpu_priv.slot_width;
@@ -70,7 +70,7 @@ static const struct snd_soc_dapm_widget imx_hdmi_widgets[] = {
static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
struct imx_hdmi_data *data = snd_soc_card_get_drvdata(card);
int ret;
@@ -101,7 +101,6 @@ static int imx_hdmi_probe(struct platform_device *pdev)
bool hdmi_out = of_property_read_bool(np, "hdmi-out");
bool hdmi_in = of_property_read_bool(np, "hdmi-in");
struct snd_soc_dai_link_component *dlc;
- struct platform_device *cpu_pdev;
struct device_node *cpu_np;
struct imx_hdmi_data *data;
int ret;
@@ -117,17 +116,9 @@ static int imx_hdmi_probe(struct platform_device *pdev)
goto fail;
}
- cpu_pdev = of_find_device_by_node(cpu_np);
- if (!cpu_pdev) {
- dev_err(&pdev->dev, "failed to find SAI platform device\n");
- ret = -EINVAL;
- goto fail;
- }
-
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
- put_device(&cpu_pdev->dev);
goto fail;
}
@@ -140,15 +131,13 @@ static int imx_hdmi_probe(struct platform_device *pdev)
data->dai.name = "i.MX HDMI";
data->dai.stream_name = "i.MX HDMI";
- data->dai.cpus->dai_name = dev_name(&cpu_pdev->dev);
+ data->dai.cpus->of_node = cpu_np;
data->dai.platforms->of_node = cpu_np;
data->dai.ops = &imx_hdmi_ops;
data->dai.playback_only = true;
data->dai.capture_only = false;
data->dai.init = imx_hdmi_init;
- put_device(&cpu_pdev->dev);
-
if (of_node_name_eq(cpu_np, "sai")) {
data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 14e94270911c..4fa208d6a032 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -50,4 +50,5 @@ int imx_pcm_dma_init(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
+MODULE_DESCRIPTION("Freescale i.MX PCM DMA interface");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 0d124002678e..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);
@@ -319,4 +318,5 @@ void imx_pcm_fiq_exit(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
+MODULE_DESCRIPTION("Freescale i.MX PCM FIQ handler");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 765dad607bf6..edab68ae8366 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -16,9 +16,10 @@
#include "fsl_rpmsg.h"
#include "imx-pcm-rpmsg.h"
-static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
+static const struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
@@ -208,7 +209,7 @@ static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *compone
static void imx_rpmsg_timer_callback(struct timer_list *t)
{
struct stream_timer *stream_timer =
- from_timer(stream_timer, t, timer);
+ timer_container_of(stream_timer, t, timer);
struct snd_pcm_substream *substream = stream_timer->substream;
struct rpmsg_info *info = stream_timer->info;
struct rpmsg_msg *msg;
@@ -228,6 +229,10 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct rpmsg_info *info = dev_get_drvdata(component->dev);
+ 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 fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+ struct snd_pcm_hardware pcm_hardware;
struct rpmsg_msg *msg;
int ret = 0;
int cmd;
@@ -255,10 +260,11 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
info->send_message(msg, info);
- imx_rpmsg_pcm_hardware.period_bytes_max =
- imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
+ pcm_hardware = imx_rpmsg_pcm_hardware;
+ pcm_hardware.buffer_bytes_max = rpmsg->buffer_size[substream->stream];
+ pcm_hardware.period_bytes_max = pcm_hardware.buffer_bytes_max / 2;
- snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
+ snd_soc_set_runtime_hwparams(substream, &pcm_hardware);
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
@@ -278,7 +284,7 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct rpmsg_info *info = dev_get_drvdata(component->dev);
struct rpmsg_msg *msg;
@@ -295,7 +301,7 @@ static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
info->send_message(msg, info);
- del_timer(&info->stream_timer[substream->stream].timer);
+ timer_delete(&info->stream_timer[substream->stream].timer);
rtd->dai_link->ignore_suspend = 0;
@@ -310,8 +316,8 @@ static int imx_rpmsg_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
/*
@@ -446,7 +452,7 @@ static int imx_rpmsg_terminate_all(struct snd_soc_component *component,
info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
}
- del_timer(&info->stream_timer[substream->stream].timer);
+ timer_delete(&info->stream_timer[substream->stream].timer);
return imx_rpmsg_insert_workqueue(substream, msg, info);
}
@@ -455,8 +461,8 @@ static int imx_rpmsg_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
int ret = 0;
@@ -509,8 +515,8 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
struct rpmsg_info *info = dev_get_drvdata(component->dev);
snd_pcm_uframes_t period_size = runtime->period_size;
@@ -589,17 +595,31 @@ static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+ struct snd_pcm_substream *substream;
int ret;
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
- imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
- return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
- pcm->card->dev, rpmsg->buffer_size);
+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (substream) {
+ ret = snd_pcm_set_fixed_buffer(substream, SNDRV_DMA_TYPE_DEV_WC, pcm->card->dev,
+ rpmsg->buffer_size[SNDRV_PCM_STREAM_PLAYBACK]);
+ if (ret < 0)
+ return ret;
+ }
+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ if (substream) {
+ ret = snd_pcm_set_fixed_buffer(substream, SNDRV_DMA_TYPE_DEV_WC, pcm->card->dev,
+ rpmsg->buffer_size[SNDRV_PCM_STREAM_CAPTURE]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
}
static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
@@ -727,9 +747,6 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
goto fail;
}
- /* platform component name is used by machine driver to link with */
- component->name = info->rpdev->id.name;
-
#ifdef CONFIG_DEBUG_FS
component->debugfs_prefix = "rpmsg";
#endif
@@ -751,7 +768,6 @@ static void imx_rpmsg_pcm_remove(struct platform_device *pdev)
destroy_workqueue(info->rpmsg_wq);
}
-#ifdef CONFIG_PM
static int imx_rpmsg_pcm_runtime_resume(struct device *dev)
{
struct rpmsg_info *info = dev_get_drvdata(dev);
@@ -769,9 +785,7 @@ static int imx_rpmsg_pcm_runtime_suspend(struct device *dev)
return 0;
}
-#endif
-#ifdef CONFIG_PM_SLEEP
static int imx_rpmsg_pcm_suspend(struct device *dev)
{
struct rpmsg_info *info = dev_get_drvdata(dev);
@@ -807,22 +821,27 @@ static int imx_rpmsg_pcm_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
- SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend,
- imx_rpmsg_pcm_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend,
- imx_rpmsg_pcm_resume)
+ RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend,
+ imx_rpmsg_pcm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend, imx_rpmsg_pcm_resume)
+};
+
+static const struct platform_device_id imx_rpmsg_pcm_id_table[] = {
+ { .name = "rpmsg-audio-channel" },
+ { .name = "rpmsg-micfil-channel" },
+ { },
};
+MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table);
static struct platform_driver imx_pcm_rpmsg_driver = {
.probe = imx_rpmsg_pcm_probe,
- .remove_new = imx_rpmsg_pcm_remove,
+ .remove = imx_rpmsg_pcm_remove,
+ .id_table = imx_rpmsg_pcm_id_table,
.driver = {
.name = IMX_PCM_DRV_NAME,
- .pm = &imx_rpmsg_pcm_pm_ops,
+ .pm = pm_ptr(&imx_rpmsg_pcm_pm_ops),
},
};
module_platform_driver(imx_pcm_rpmsg_driver);
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index 93fc976e98dc..53f04d1f3280 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -5,9 +5,7 @@
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/i2c.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/clk.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -20,8 +18,11 @@ struct imx_rpmsg {
struct snd_soc_dai_link dai;
struct snd_soc_card card;
unsigned long sysclk;
+ bool lpa;
};
+static struct dev_pm_ops lpa_pm;
+
static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
@@ -34,10 +35,62 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card)
struct imx_rpmsg *data = snd_soc_card_get_drvdata(card);
struct snd_soc_pcm_runtime *rtd = list_first_entry(&card->rtd_list,
struct snd_soc_pcm_runtime, list);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct device *dev = card->dev;
int ret;
+ if (data->lpa) {
+ struct snd_soc_component *codec_comp;
+ struct device_node *codec_np;
+ struct device_driver *codec_drv;
+ struct device *codec_dev = NULL;
+
+ codec_np = data->dai.codecs->of_node;
+ if (codec_np) {
+ struct platform_device *codec_pdev;
+ struct i2c_client *codec_i2c;
+
+ codec_i2c = of_find_i2c_device_by_node(codec_np);
+ if (codec_i2c)
+ codec_dev = &codec_i2c->dev;
+ if (!codec_dev) {
+ codec_pdev = of_find_device_by_node(codec_np);
+ if (codec_pdev)
+ codec_dev = &codec_pdev->dev;
+ }
+ }
+ if (codec_dev) {
+ codec_comp = snd_soc_lookup_component_nolocked(codec_dev, NULL);
+ if (codec_comp) {
+ int i, num_widgets;
+ const char *widgets;
+ struct snd_soc_dapm_context *dapm;
+
+ num_widgets = of_property_count_strings(data->card.dev->of_node,
+ "ignore-suspend-widgets");
+ for (i = 0; i < num_widgets; i++) {
+ of_property_read_string_index(data->card.dev->of_node,
+ "ignore-suspend-widgets",
+ i, &widgets);
+ dapm = snd_soc_component_to_dapm(codec_comp);
+ snd_soc_dapm_ignore_suspend(dapm, widgets);
+ }
+ }
+ codec_drv = codec_dev->driver;
+ if (codec_drv->pm) {
+ memcpy(&lpa_pm, codec_drv->pm, sizeof(lpa_pm));
+ lpa_pm.suspend = NULL;
+ lpa_pm.resume = NULL;
+ lpa_pm.freeze = NULL;
+ lpa_pm.thaw = NULL;
+ lpa_pm.poweroff = NULL;
+ lpa_pm.restore = NULL;
+ codec_drv->pm = &lpa_pm;
+ }
+ put_device(codec_dev);
+ }
+ }
+
if (!data->sysclk)
return 0;
@@ -53,10 +106,8 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card)
static int imx_rpmsg_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link_component *dlc;
- struct device *dev = pdev->dev.parent;
- /* rpmsg_pdev is the platform device for the rpmsg node that probed us */
- struct platform_device *rpmsg_pdev = to_platform_device(dev);
- struct device_node *np = rpmsg_pdev->dev.of_node;
+ struct snd_soc_dai *cpu_dai;
+ struct device_node *np = NULL;
struct of_phandle_args args;
const char *platform_name;
struct imx_rpmsg *data;
@@ -72,10 +123,6 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
goto fail;
}
- ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
- if (ret)
- dev_warn(&pdev->dev, "no reserved DMA memory\n");
-
data->dai.cpus = &dlc[0];
data->dai.num_cpus = 1;
data->dai.platforms = &dlc[1];
@@ -89,15 +136,39 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC;
+ /*
+ * i.MX rpmsg sound cards work on codec slave mode. MCLK will be
+ * disabled by CPU DAI driver in hw_free(). Some codec requires MCLK
+ * present at power up/down sequence. So need to set ignore_pmdown_time
+ * to power down codec immediately before MCLK is turned off.
+ */
+ data->dai.ignore_pmdown_time = 1;
+
+ data->dai.cpus->dai_name = pdev->dev.platform_data;
+ cpu_dai = snd_soc_find_dai(data->dai.cpus);
+ if (!cpu_dai) {
+ ret = -EPROBE_DEFER;
+ goto fail;
+ }
+ np = cpu_dai->dev->of_node;
+ if (!np) {
+ dev_err(&pdev->dev, "failed to parse CPU DAI device node\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
+ if (ret)
+ dev_warn(&pdev->dev, "no reserved DMA memory\n");
+
/* Optional codec node */
ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args);
if (ret) {
- *data->dai.codecs = asoc_dummy_dlc;
+ *data->dai.codecs = snd_soc_dummy_dlc;
} else {
struct clk *clk;
- data->dai.codecs->of_node = args.np;
- ret = snd_soc_get_dai_name(&args, &data->dai.codecs->dai_name);
+ ret = snd_soc_get_dlc(&args, data->dai.codecs);
if (ret) {
dev_err(&pdev->dev, "Unable to get codec_dai_name\n");
goto fail;
@@ -108,7 +179,6 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
data->sysclk = clk_get_rate(clk);
}
- data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev);
if (!of_property_read_string(np, "fsl,rpmsg-channel-name", &platform_name))
data->dai.platforms->name = platform_name;
else
@@ -130,6 +200,9 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
goto fail;
}
+ if (of_property_read_bool(np, "fsl,enable-lpa"))
+ data->lpa = true;
+
data->card.dev = &pdev->dev;
data->card.owner = THIS_MODULE;
data->card.dapm_widgets = imx_rpmsg_dapm_widgets;
@@ -145,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/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 26c22783927b..8bcf54ef709e 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -30,7 +30,7 @@ static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
struct device *dev = rtd->card->dev;
int ret;
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), SGTL5000_SYSCLK,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), SGTL5000_SYSCLK,
data->clk_frequency, SND_SOC_CLOCK_IN);
if (ret) {
dev_err(dev, "could not set codec driver clock params\n");
@@ -214,7 +214,7 @@ static struct platform_driver imx_sgtl5000_driver = {
.of_match_table = imx_sgtl5000_dt_ids,
},
.probe = imx_sgtl5000_probe,
- .remove_new = imx_sgtl5000_remove,
+ .remove = imx_sgtl5000_remove,
};
module_platform_driver(imx_sgtl5000_driver);
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
deleted file mode 100644
index 44463f92e522..000000000000
--- a/sound/soc/fsl/imx-spdif.c
+++ /dev/null
@@ -1,103 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// Copyright (C) 2013 Freescale Semiconductor, Inc.
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <sound/soc.h>
-
-struct imx_spdif_data {
- struct snd_soc_dai_link dai;
- struct snd_soc_card card;
-};
-
-static int imx_spdif_audio_probe(struct platform_device *pdev)
-{
- struct device_node *spdif_np, *np = pdev->dev.of_node;
- struct imx_spdif_data *data;
- struct snd_soc_dai_link_component *comp;
- int ret = 0;
-
- spdif_np = of_parse_phandle(np, "spdif-controller", 0);
- if (!spdif_np) {
- dev_err(&pdev->dev, "failed to find spdif-controller\n");
- ret = -EINVAL;
- goto end;
- }
-
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- comp = devm_kzalloc(&pdev->dev, sizeof(*comp), GFP_KERNEL);
- if (!data || !comp) {
- ret = -ENOMEM;
- goto end;
- }
-
- /*
- * CPU == Platform
- * platform is using soc-generic-dmaengine-pcm
- */
- data->dai.cpus =
- data->dai.platforms = comp;
- data->dai.codecs = &asoc_dummy_dlc;
-
- data->dai.num_cpus = 1;
- data->dai.num_codecs = 1;
- data->dai.num_platforms = 1;
-
- data->dai.name = "S/PDIF PCM";
- data->dai.stream_name = "S/PDIF PCM";
- data->dai.cpus->of_node = spdif_np;
- data->dai.playback_only = true;
- data->dai.capture_only = true;
-
- if (of_property_read_bool(np, "spdif-out"))
- data->dai.capture_only = false;
-
- if (of_property_read_bool(np, "spdif-in"))
- data->dai.playback_only = false;
-
- if (data->dai.playback_only && data->dai.capture_only) {
- dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
- goto end;
- }
-
- data->card.dev = &pdev->dev;
- data->card.dai_link = &data->dai;
- data->card.num_links = 1;
- data->card.owner = THIS_MODULE;
-
- ret = snd_soc_of_parse_card_name(&data->card, "model");
- if (ret)
- goto end;
-
- ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
- if (ret)
- dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
-
-end:
- of_node_put(spdif_np);
-
- return ret;
-}
-
-static const struct of_device_id imx_spdif_dt_ids[] = {
- { .compatible = "fsl,imx-audio-spdif", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
-
-static struct platform_driver imx_spdif_driver = {
- .driver = {
- .name = "imx-spdif",
- .pm = &snd_soc_pm_ops,
- .of_match_table = imx_spdif_dt_ids,
- },
- .probe = imx_spdif_audio_probe,
-};
-
-module_platform_driver(imx_spdif_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:imx-spdif");
diff --git a/sound/soc/fsl/lpc3xxx-i2s.c b/sound/soc/fsl/lpc3xxx-i2s.c
new file mode 100644
index 000000000000..c65c17dfa174
--- /dev/null
+++ b/sound/soc/fsl/lpc3xxx-i2s.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Author: Kevin Wells <kevin.wells@nxp.com>
+//
+// Copyright (C) 2008 NXP Semiconductors
+// Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "lpc3xxx-i2s.h"
+
+#define I2S_PLAYBACK_FLAG 0x1
+#define I2S_CAPTURE_FLAG 0x2
+
+#define LPC3XXX_I2S_RATES ( \
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+#define LPC3XXX_I2S_FORMATS ( \
+ SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u32 clkrate)
+{
+ u32 i2srate;
+ u32 idxx, idyy;
+ u32 diff, trate, baseclk;
+
+ /* Adjust rate for sample size (bits) and 2 channels and offset for
+ * divider in clock output
+ */
+ i2srate = (freq / 100) * 2 * (8 * xbytes);
+ i2srate = i2srate << 1;
+ clkrate = clkrate / 100;
+ baseclk = clkrate;
+ *clkx = 1;
+ *clky = 1;
+
+ /* Find the best divider */
+ *clkx = *clky = 0;
+ diff = ~0;
+ for (idxx = 1; idxx < 0xFF; idxx++) {
+ for (idyy = 1; idyy < 0xFF; idyy++) {
+ trate = (baseclk * idxx) / idyy;
+ if (abs(trate - i2srate) < diff) {
+ diff = abs(trate - i2srate);
+ *clkx = idxx;
+ *clky = idyy;
+ }
+ }
+ }
+}
+
+static int lpc3xxx_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+ struct device *dev = i2s_info_p->dev;
+ u32 flag;
+ int ret = 0;
+
+ guard(mutex)(&i2s_info_p->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ flag = I2S_PLAYBACK_FLAG;
+ else
+ flag = I2S_CAPTURE_FLAG;
+
+ if (flag & i2s_info_p->streams_in_use) {
+ dev_warn(dev, "I2S channel is busy\n");
+ ret = -EBUSY;
+ return ret;
+ }
+
+ if (i2s_info_p->streams_in_use == 0) {
+ ret = clk_prepare_enable(i2s_info_p->clk);
+ if (ret) {
+ dev_err(dev, "Can't enable clock, err=%d\n", ret);
+ return ret;
+ }
+ }
+
+ i2s_info_p->streams_in_use |= flag;
+ return 0;
+}
+
+static void lpc3xxx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+ struct regmap *regs = i2s_info_p->regs;
+ const u32 stop_bits = (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP);
+ u32 flag;
+
+ guard(mutex)(&i2s_info_p->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ flag = I2S_PLAYBACK_FLAG;
+ regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, 0);
+ regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, stop_bits, stop_bits);
+ } else {
+ flag = I2S_CAPTURE_FLAG;
+ regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, 0);
+ regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, stop_bits, stop_bits);
+ }
+ i2s_info_p->streams_in_use &= ~flag;
+
+ if (i2s_info_p->streams_in_use == 0)
+ clk_disable_unprepare(i2s_info_p->clk);
+}
+
+static int lpc3xxx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+
+ /* Will use in HW params later */
+ i2s_info_p->freq = freq;
+
+ return 0;
+}
+
+static int lpc3xxx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+ struct device *dev = i2s_info_p->dev;
+
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+ dev_warn(dev, "unsupported bus format %d\n", fmt);
+ return -EINVAL;
+ }
+
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) {
+ dev_warn(dev, "unsupported clock provider %d\n", fmt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+ struct device *dev = i2s_info_p->dev;
+ struct regmap *regs = i2s_info_p->regs;
+ int xfersize;
+ u32 tmp, clkx, clky;
+
+ tmp = LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ tmp |= LPC3XXX_I2S_WW8 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW8_HP);
+ xfersize = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tmp |= LPC3XXX_I2S_WW16 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW16_HP);
+ xfersize = 2;
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ tmp |= LPC3XXX_I2S_WW32 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW32_HP);
+ xfersize = 4;
+ break;
+
+ default:
+ dev_warn(dev, "Unsupported audio data format %d\n", params_format(params));
+ return -EINVAL;
+ }
+
+ if (params_channels(params) == 1)
+ tmp |= LPC3XXX_I2S_MONO;
+
+ __lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, i2s_info_p->clkrate);
+
+ dev_dbg(dev, "Stream : %s\n", snd_pcm_direction_name(substream->stream));
+ dev_dbg(dev, "Desired clock rate : %d\n", i2s_info_p->freq);
+ dev_dbg(dev, "Base clock rate : %d\n", i2s_info_p->clkrate);
+ dev_dbg(dev, "Transfer size (bytes) : %d\n", xfersize);
+ dev_dbg(dev, "Clock divider (x) : %d\n", clkx);
+ dev_dbg(dev, "Clock divider (y) : %d\n", clky);
+ dev_dbg(dev, "Channels : %d\n", params_channels(params));
+ dev_dbg(dev, "Data format : %s\n", "I2S");
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_write(regs, LPC3XXX_REG_I2S_DMA1,
+ LPC3XXX_I2S_DMA1_TX_EN | LPC3XXX_I2S_DMA0_TX_DEPTH(4));
+ regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, (clkx << 8) | clky);
+ regmap_write(regs, LPC3XXX_REG_I2S_DAO, tmp);
+ } else {
+ regmap_write(regs, LPC3XXX_REG_I2S_DMA0,
+ LPC3XXX_I2S_DMA0_RX_EN | LPC3XXX_I2S_DMA1_RX_DEPTH(4));
+ regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, (clkx << 8) | clky);
+ regmap_write(regs, LPC3XXX_REG_I2S_DAI, tmp);
+ }
+
+ return 0;
+}
+
+static int lpc3xxx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai);
+ struct regmap *regs = i2s_info_p->regs;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO,
+ LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP);
+ else
+ regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI,
+ LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP);
+ break;
+
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO,
+ (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0);
+ else
+ regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI,
+ (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int lpc3xxx_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &i2s_info_p->playback_dma_config,
+ &i2s_info_p->capture_dma_config);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = {
+ .probe = lpc3xxx_i2s_dai_probe,
+ .startup = lpc3xxx_i2s_startup,
+ .shutdown = lpc3xxx_i2s_shutdown,
+ .trigger = lpc3xxx_i2s_trigger,
+ .hw_params = lpc3xxx_i2s_hw_params,
+ .set_sysclk = lpc3xxx_i2s_set_dai_sysclk,
+ .set_fmt = lpc3xxx_i2s_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = {
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = LPC3XXX_I2S_RATES,
+ .formats = LPC3XXX_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = LPC3XXX_I2S_RATES,
+ .formats = LPC3XXX_I2S_FORMATS,
+ },
+ .ops = &lpc3xxx_i2s_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_channels = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static const struct snd_soc_component_driver lpc32xx_i2s_component = {
+ .name = "lpc32xx-i2s",
+ .legacy_dai_naming = 1,
+};
+
+static const struct regmap_config lpc32xx_i2s_regconfig = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = LPC3XXX_REG_I2S_RX_RATE,
+};
+
+static int lpc32xx_i2s_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lpc3xxx_i2s_info *i2s_info_p;
+ struct resource *res;
+ void __iomem *iomem;
+ int ret;
+
+ i2s_info_p = devm_kzalloc(dev, sizeof(*i2s_info_p), GFP_KERNEL);
+ if (!i2s_info_p)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, i2s_info_p);
+ i2s_info_p->dev = dev;
+
+ iomem = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(iomem))
+ return dev_err_probe(dev, PTR_ERR(iomem), "Can't map registers\n");
+
+ i2s_info_p->regs = devm_regmap_init_mmio(dev, iomem, &lpc32xx_i2s_regconfig);
+ if (IS_ERR(i2s_info_p->regs))
+ return dev_err_probe(dev, PTR_ERR(i2s_info_p->regs),
+ "failed to init register map: %pe\n", i2s_info_p->regs);
+
+ i2s_info_p->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(i2s_info_p->clk))
+ return dev_err_probe(dev, PTR_ERR(i2s_info_p->clk), "Can't get clock\n");
+
+ i2s_info_p->clkrate = clk_get_rate(i2s_info_p->clk);
+ if (i2s_info_p->clkrate == 0)
+ return dev_err_probe(dev, -EINVAL, "Invalid returned clock rate\n");
+
+ mutex_init(&i2s_info_p->lock);
+
+ ret = devm_snd_soc_register_component(dev, &lpc32xx_i2s_component,
+ &lpc3xxx_i2s_dai_driver, 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't register cpu_dai component\n");
+
+ i2s_info_p->playback_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_TX_FIFO);
+ i2s_info_p->playback_dma_config.maxburst = 4;
+
+ i2s_info_p->capture_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_RX_FIFO);
+ i2s_info_p->capture_dma_config.maxburst = 4;
+
+ ret = lpc3xxx_pcm_register(pdev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't register pcm component\n");
+
+ return 0;
+}
+
+static const struct of_device_id lpc32xx_i2s_match[] = {
+ { .compatible = "nxp,lpc3220-i2s" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_i2s_match);
+
+static struct platform_driver lpc32xx_i2s_driver = {
+ .probe = lpc32xx_i2s_probe,
+ .driver = {
+ .name = "lpc3xxx-i2s",
+ .of_match_table = lpc32xx_i2s_match,
+ },
+};
+
+module_platform_driver(lpc32xx_i2s_driver);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Piotr Wojtaszczyk <piotr.wojtaszczyk@timesys.com>");
+MODULE_DESCRIPTION("ASoC LPC3XXX I2S interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/lpc3xxx-i2s.h b/sound/soc/fsl/lpc3xxx-i2s.h
new file mode 100644
index 000000000000..b6657853017a
--- /dev/null
+++ b/sound/soc/fsl/lpc3xxx-i2s.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2008 NXP Semiconductors
+ * Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com>
+ */
+
+#ifndef __SOUND_SOC_LPC3XXX_I2S_H
+#define __SOUND_SOC_LPC3XXX_I2S_H
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+#include <linux/regmap.h>
+
+struct lpc3xxx_i2s_info {
+ struct device *dev;
+ struct clk *clk;
+ struct mutex lock; /* To serialize user-space access */
+ struct regmap *regs;
+ u32 streams_in_use;
+ u32 clkrate;
+ int freq;
+ struct snd_dmaengine_dai_dma_data playback_dma_config;
+ struct snd_dmaengine_dai_dma_data capture_dma_config;
+};
+
+int lpc3xxx_pcm_register(struct platform_device *pdev);
+
+/* I2S controller register offsets */
+#define LPC3XXX_REG_I2S_DAO 0x00
+#define LPC3XXX_REG_I2S_DAI 0x04
+#define LPC3XXX_REG_I2S_TX_FIFO 0x08
+#define LPC3XXX_REG_I2S_RX_FIFO 0x0C
+#define LPC3XXX_REG_I2S_STAT 0x10
+#define LPC3XXX_REG_I2S_DMA0 0x14
+#define LPC3XXX_REG_I2S_DMA1 0x18
+#define LPC3XXX_REG_I2S_IRQ 0x1C
+#define LPC3XXX_REG_I2S_TX_RATE 0x20
+#define LPC3XXX_REG_I2S_RX_RATE 0x24
+
+/* i2s_daO i2s_dai register definitions */
+#define LPC3XXX_I2S_WW8 FIELD_PREP(0x3, 0) /* Word width is 8bit */
+#define LPC3XXX_I2S_WW16 FIELD_PREP(0x3, 1) /* Word width is 16bit */
+#define LPC3XXX_I2S_WW32 FIELD_PREP(0x3, 3) /* Word width is 32bit */
+#define LPC3XXX_I2S_MONO BIT(2) /* Mono */
+#define LPC3XXX_I2S_STOP BIT(3) /* Stop, diables the access to FIFO, mutes the channel */
+#define LPC3XXX_I2S_RESET BIT(4) /* Reset the channel */
+#define LPC3XXX_I2S_WS_SEL BIT(5) /* Channel Master(0) or slave(1) mode select */
+#define LPC3XXX_I2S_WS_HP(s) FIELD_PREP(0x7FC0, s) /* Word select half period - 1 */
+#define LPC3XXX_I2S_MUTE BIT(15) /* Mute the channel, Transmit channel only */
+
+#define LPC3XXX_I2S_WW32_HP 0x1f /* Word select half period for 32bit word width */
+#define LPC3XXX_I2S_WW16_HP 0x0f /* Word select half period for 16bit word width */
+#define LPC3XXX_I2S_WW8_HP 0x7 /* Word select half period for 8bit word width */
+
+/* i2s_stat register definitions */
+#define LPC3XXX_I2S_IRQ_STAT BIT(0)
+#define LPC3XXX_I2S_DMA0_REQ BIT(1)
+#define LPC3XXX_I2S_DMA1_REQ BIT(2)
+
+/* i2s_dma0 Configuration register definitions */
+#define LPC3XXX_I2S_DMA0_RX_EN BIT(0) /* Enable RX DMA1 */
+#define LPC3XXX_I2S_DMA0_TX_EN BIT(1) /* Enable TX DMA1 */
+#define LPC3XXX_I2S_DMA0_RX_DEPTH(s) FIELD_PREP(0xF00, s) /* Set the DMA1 RX Request level */
+#define LPC3XXX_I2S_DMA0_TX_DEPTH(s) FIELD_PREP(0xF0000, s) /* Set the DMA1 TX Request level */
+
+/* i2s_dma1 Configuration register definitions */
+#define LPC3XXX_I2S_DMA1_RX_EN BIT(0) /* Enable RX DMA1 */
+#define LPC3XXX_I2S_DMA1_TX_EN BIT(1) /* Enable TX DMA1 */
+#define LPC3XXX_I2S_DMA1_RX_DEPTH(s) FIELD_PREP(0x700, s) /* Set the DMA1 RX Request level */
+#define LPC3XXX_I2S_DMA1_TX_DEPTH(s) FIELD_PREP(0x70000, s) /* Set the DMA1 TX Request level */
+
+/* i2s_irq register definitions */
+#define LPC3XXX_I2S_RX_IRQ_EN BIT(0) /* Enable RX IRQ */
+#define LPC3XXX_I2S_TX_IRQ_EN BIT(1) /* Enable TX IRQ */
+#define LPC3XXX_I2S_IRQ_RX_DEPTH(s) FIELD_PREP(0xFF00, s) /* valid values ar 0 to 7 */
+#define LPC3XXX_I2S_IRQ_TX_DEPTH(s) FIELD_PREP(0xFF0000, s) /* valid values ar 0 to 7 */
+
+#endif
diff --git a/sound/soc/fsl/lpc3xxx-pcm.c b/sound/soc/fsl/lpc3xxx-pcm.c
new file mode 100644
index 000000000000..e6abaf63895a
--- /dev/null
+++ b/sound/soc/fsl/lpc3xxx-pcm.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Author: Kevin Wells <kevin.wells@nxp.com>
+//
+// Copyright (C) 2008 NXP Semiconductors
+// Copyright 2023 Timesys Corporation <piotr.wojtaszczyk@timesys.com>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/pl08x.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+
+#include "lpc3xxx-i2s.h"
+
+#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE | \
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
+
+static const struct snd_pcm_hardware lpc3xxx_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME),
+ .formats = STUB_FORMATS,
+ .period_bytes_min = 128,
+ .period_bytes_max = 2048,
+ .periods_min = 2,
+ .periods_max = 1024,
+ .buffer_bytes_max = 128 * 1024
+};
+
+static const struct snd_dmaengine_pcm_config lpc3xxx_dmaengine_pcm_config = {
+ .pcm_hardware = &lpc3xxx_pcm_hardware,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .compat_filter_fn = pl08x_filter_id,
+ .prealloc_buffer_size = 128 * 1024,
+};
+
+static const struct snd_soc_component_driver lpc3xxx_soc_platform_driver = {
+ .name = "lpc32xx-pcm",
+};
+
+int lpc3xxx_pcm_register(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &lpc3xxx_dmaengine_pcm_config, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dmaengine: %d\n", ret);
+ return ret;
+ }
+
+ return devm_snd_soc_register_component(&pdev->dev, &lpc3xxx_soc_platform_driver,
+ NULL, 0);
+}
+EXPORT_SYMBOL(lpc3xxx_pcm_register);
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 901497810020..345f338251ac 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -7,12 +7,12 @@
// Copyright (C) 2009 Jon Smirl, Digispeaker
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <sound/soc.h>
@@ -100,6 +100,9 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
/**
* psc_dma_trigger: start and stop the DMA transfer.
+ * @component: triggered component
+ * @substream: triggered substream
+ * @cmd: triggered command
*
* This function is called by ALSA to start, stop, pause, and resume the DMA
* transfer of data.
@@ -107,8 +110,8 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
static int psc_dma_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct snd_pcm_runtime *runtime = substream->runtime;
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
@@ -209,8 +212,8 @@ static int psc_dma_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct psc_dma_stream *s;
int rc;
@@ -237,8 +240,8 @@ static int psc_dma_open(struct snd_soc_component *component,
static int psc_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct psc_dma_stream *s;
dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
@@ -263,8 +266,8 @@ static snd_pcm_uframes_t
psc_dma_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct psc_dma_stream *s;
dma_addr_t count;
@@ -282,7 +285,7 @@ static int psc_dma_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_pcm *pcm = rtd->pcm;
size_t size = psc_dma_hardware.buffer_bytes_max;
int rc;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 40a4a2667394..8554fb690772 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -5,9 +5,8 @@
// Copyright (C) 2009 Jon Smirl, Digispeaker
// Author: Jon Smirl <jonsmirl@gmail.com>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/time.h>
@@ -222,6 +221,7 @@ static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
* psc_ac97_dai_template: template CPU Digital Audio Interface
*/
static const struct snd_soc_dai_ops psc_ac97_analog_ops = {
+ .probe = psc_ac97_probe,
.hw_params = psc_ac97_hw_analog_params,
.trigger = psc_ac97_trigger,
};
@@ -233,7 +233,6 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = {
static struct snd_soc_dai_driver psc_ac97_dai[] = {
{
.name = "mpc5200-psc-ac97.0",
- .probe = psc_ac97_probe,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 1,
@@ -328,7 +327,7 @@ MODULE_DEVICE_TABLE(of, psc_ac97_match);
static struct platform_driver psc_ac97_driver = {
.probe = psc_ac97_of_probe,
- .remove_new = psc_ac97_of_remove,
+ .remove = psc_ac97_of_remove,
.driver = {
.name = "mpc5200-psc-ac97",
.of_match_table = psc_ac97_match,
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 413df413b5eb..9ad44eeed6ad 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -7,8 +7,7 @@
// Copyright (C) 2009 Jon Smirl, Digispeaker
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -38,8 +37,8 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
u32 mode;
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -185,7 +184,7 @@ static int psc_i2s_of_probe(struct platform_device *op)
/* Check for the codec handle. If it is not present then we
* are done */
- if (!of_get_property(op->dev.of_node, "codec-handle", NULL))
+ if (!of_property_present(op->dev.of_node, "codec-handle"))
return 0;
/* Due to errata in the dma mode; need to line up enabling
@@ -226,7 +225,7 @@ MODULE_DEVICE_TABLE(of, psc_i2s_match);
static struct platform_driver psc_i2s_driver = {
.probe = psc_i2s_of_probe,
- .remove_new = psc_i2s_of_remove,
+ .remove = psc_i2s_of_remove,
.driver = {
.name = "mpc5200-psc-i2s",
.of_match_table = psc_i2s_match,
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
deleted file mode 100644
index ea2076ea8afe..000000000000
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ /dev/null
@@ -1,451 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Freescale MPC8610HPCD ALSA SoC Machine driver
-//
-// Author: Timur Tabi <timur@freescale.com>
-//
-// Copyright 2007-2010 Freescale Semiconductor, Inc.
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/fsl/guts.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/slab.h>
-#include <sound/soc.h>
-
-#include "fsl_dma.h"
-#include "fsl_ssi.h"
-#include "fsl_utils.h"
-
-/* There's only one global utilities register */
-static phys_addr_t guts_phys;
-
-/**
- * mpc8610_hpcd_data: machine-specific ASoC device data
- *
- * This structure contains data for a single sound platform device on an
- * MPC8610 HPCD. Some of the data is taken from the device tree.
- */
-struct mpc8610_hpcd_data {
- struct snd_soc_dai_link dai[2];
- struct snd_soc_card card;
- unsigned int dai_format;
- unsigned int codec_clk_direction;
- unsigned int cpu_clk_direction;
- unsigned int clk_frequency;
- unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
- unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
- unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
- char codec_dai_name[DAI_NAME_SIZE];
- char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
-};
-
-/**
- * mpc8610_hpcd_machine_probe: initialize the board
- *
- * This function is used to initialize the board-specific hardware.
- *
- * Here we program the DMACR and PMUXCR registers.
- */
-static int mpc8610_hpcd_machine_probe(struct snd_soc_card *card)
-{
- struct mpc8610_hpcd_data *machine_data =
- container_of(card, struct mpc8610_hpcd_data, card);
- struct ccsr_guts __iomem *guts;
-
- guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
- if (!guts) {
- dev_err(card->dev, "could not map global utilities\n");
- return -ENOMEM;
- }
-
- /* Program the signal routing between the SSI and the DMA */
- guts_set_dmacr(guts, machine_data->dma_id[0],
- machine_data->dma_channel_id[0],
- CCSR_GUTS_DMACR_DEV_SSI);
- guts_set_dmacr(guts, machine_data->dma_id[1],
- machine_data->dma_channel_id[1],
- CCSR_GUTS_DMACR_DEV_SSI);
-
- guts_set_pmuxcr_dma(guts, machine_data->dma_id[0],
- machine_data->dma_channel_id[0], 0);
- guts_set_pmuxcr_dma(guts, machine_data->dma_id[1],
- machine_data->dma_channel_id[1], 0);
-
- switch (machine_data->ssi_id) {
- case 0:
- clrsetbits_be32(&guts->pmuxcr,
- CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
- break;
- case 1:
- clrsetbits_be32(&guts->pmuxcr,
- CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
- break;
- }
-
- iounmap(guts);
-
- return 0;
-}
-
-/**
- * mpc8610_hpcd_startup: program the board with various hardware parameters
- *
- * This function takes board-specific information, like clock frequencies
- * and serial data formats, and passes that information to the codec and
- * transport drivers.
- */
-static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct mpc8610_hpcd_data *machine_data =
- container_of(rtd->card, struct mpc8610_hpcd_data, card);
- struct device *dev = rtd->card->dev;
- int ret = 0;
-
- /* Tell the codec driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), machine_data->dai_format);
- if (ret < 0) {
- dev_err(dev, "could not set codec driver audio format\n");
- return ret;
- }
-
- /*
- * Tell the codec driver what the MCLK frequency is, and whether it's
- * a slave or master.
- */
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), 0,
- machine_data->clk_frequency,
- machine_data->codec_clk_direction);
- if (ret < 0) {
- dev_err(dev, "could not set codec driver clock params\n");
- return ret;
- }
-
- return 0;
-}
-
-/**
- * mpc8610_hpcd_machine_remove: Remove the sound device
- *
- * This function is called to remove the sound device for one SSI. We
- * de-program the DMACR and PMUXCR register.
- */
-static int mpc8610_hpcd_machine_remove(struct snd_soc_card *card)
-{
- struct mpc8610_hpcd_data *machine_data =
- container_of(card, struct mpc8610_hpcd_data, card);
- struct ccsr_guts __iomem *guts;
-
- guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
- if (!guts) {
- dev_err(card->dev, "could not map global utilities\n");
- return -ENOMEM;
- }
-
- /* Restore the signal routing */
-
- guts_set_dmacr(guts, machine_data->dma_id[0],
- machine_data->dma_channel_id[0], 0);
- guts_set_dmacr(guts, machine_data->dma_id[1],
- machine_data->dma_channel_id[1], 0);
-
- switch (machine_data->ssi_id) {
- case 0:
- clrsetbits_be32(&guts->pmuxcr,
- CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
- break;
- case 1:
- clrsetbits_be32(&guts->pmuxcr,
- CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
- break;
- }
-
- iounmap(guts);
-
- return 0;
-}
-
-/**
- * mpc8610_hpcd_ops: ASoC machine driver operations
- */
-static const struct snd_soc_ops mpc8610_hpcd_ops = {
- .startup = mpc8610_hpcd_startup,
-};
-
-/**
- * mpc8610_hpcd_probe: platform probe function for the machine driver
- *
- * Although this is a machine driver, the SSI node is the "master" node with
- * respect to audio hardware connections. Therefore, we create a new ASoC
- * device for each new SSI node that has a codec attached.
- */
-static int mpc8610_hpcd_probe(struct platform_device *pdev)
-{
- struct device *dev = pdev->dev.parent;
- /* ssi_pdev is the platform device for the SSI node that probed us */
- struct platform_device *ssi_pdev = to_platform_device(dev);
- struct device_node *np = ssi_pdev->dev.of_node;
- struct device_node *codec_np = NULL;
- struct mpc8610_hpcd_data *machine_data;
- struct snd_soc_dai_link_component *comp;
- int ret;
- const char *sprop;
- const u32 *iprop;
-
- /* Find the codec node for this SSI. */
- codec_np = of_parse_phandle(np, "codec-handle", 0);
- if (!codec_np) {
- dev_err(dev, "invalid codec node\n");
- return -EINVAL;
- }
-
- machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
- if (!machine_data) {
- ret = -ENOMEM;
- goto error_alloc;
- }
-
- comp = devm_kzalloc(&pdev->dev, 6 * sizeof(*comp), GFP_KERNEL);
- if (!comp) {
- ret = -ENOMEM;
- goto error_alloc;
- }
-
- machine_data->dai[0].cpus = &comp[0];
- machine_data->dai[0].codecs = &comp[1];
- machine_data->dai[0].platforms = &comp[2];
-
- machine_data->dai[0].num_cpus = 1;
- machine_data->dai[0].num_codecs = 1;
- machine_data->dai[0].num_platforms = 1;
-
- machine_data->dai[1].cpus = &comp[3];
- machine_data->dai[1].codecs = &comp[4];
- machine_data->dai[1].platforms = &comp[5];
-
- machine_data->dai[1].num_cpus = 1;
- machine_data->dai[1].num_codecs = 1;
- machine_data->dai[1].num_platforms = 1;
-
- machine_data->dai[0].cpus->dai_name = dev_name(&ssi_pdev->dev);
- machine_data->dai[0].ops = &mpc8610_hpcd_ops;
-
- /* ASoC core can match codec with device node */
- machine_data->dai[0].codecs->of_node = codec_np;
-
- /* The DAI name from the codec (snd_soc_dai_driver.name) */
- machine_data->dai[0].codecs->dai_name = "cs4270-hifi";
-
- /* We register two DAIs per SSI, one for playback and the other for
- * capture. Currently, we only support codecs that have one DAI for
- * both playback and capture.
- */
- memcpy(&machine_data->dai[1], &machine_data->dai[0],
- sizeof(struct snd_soc_dai_link));
-
- /* Get the device ID */
- iprop = of_get_property(np, "cell-index", NULL);
- if (!iprop) {
- dev_err(&pdev->dev, "cell-index property not found\n");
- ret = -EINVAL;
- goto error;
- }
- machine_data->ssi_id = be32_to_cpup(iprop);
-
- /* Get the serial format and clock direction. */
- sprop = of_get_property(np, "fsl,mode", NULL);
- if (!sprop) {
- dev_err(&pdev->dev, "fsl,mode property not found\n");
- ret = -EINVAL;
- goto error;
- }
-
- if (strcasecmp(sprop, "i2s-slave") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
-
- /* In i2s-slave mode, the codec has its own clock source, so we
- * need to get the frequency from the device tree and pass it to
- * the codec driver.
- */
- iprop = of_get_property(codec_np, "clock-frequency", NULL);
- if (!iprop || !*iprop) {
- dev_err(&pdev->dev, "codec bus-frequency "
- "property is missing or invalid\n");
- ret = -EINVAL;
- goto error;
- }
- machine_data->clk_frequency = be32_to_cpup(iprop);
- } else if (strcasecmp(sprop, "i2s-master") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
- } else if (strcasecmp(sprop, "lj-slave") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBP_CFP;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
- } else if (strcasecmp(sprop, "lj-master") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
- } else if (strcasecmp(sprop, "rj-slave") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBP_CFP;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
- } else if (strcasecmp(sprop, "rj-master") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBC_CFC;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
- } else if (strcasecmp(sprop, "ac97-slave") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBP_CFP;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
- } else if (strcasecmp(sprop, "ac97-master") == 0) {
- machine_data->dai_format =
- SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBC_CFC;
- machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
- machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
- } else {
- dev_err(&pdev->dev,
- "unrecognized fsl,mode property '%s'\n", sprop);
- ret = -EINVAL;
- goto error;
- }
-
- if (!machine_data->clk_frequency) {
- dev_err(&pdev->dev, "unknown clock frequency\n");
- ret = -EINVAL;
- goto error;
- }
-
- /* Find the playback DMA channel to use. */
- machine_data->dai[0].platforms->name = machine_data->platform_name[0];
- ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma",
- &machine_data->dai[0],
- &machine_data->dma_channel_id[0],
- &machine_data->dma_id[0]);
- if (ret) {
- dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
- goto error;
- }
-
- /* Find the capture DMA channel to use. */
- machine_data->dai[1].platforms->name = machine_data->platform_name[1];
- ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma",
- &machine_data->dai[1],
- &machine_data->dma_channel_id[1],
- &machine_data->dma_id[1]);
- if (ret) {
- dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
- goto error;
- }
-
- /* Initialize our DAI data structure. */
- machine_data->dai[0].stream_name = "playback";
- machine_data->dai[1].stream_name = "capture";
- machine_data->dai[0].name = machine_data->dai[0].stream_name;
- machine_data->dai[1].name = machine_data->dai[1].stream_name;
-
- machine_data->card.probe = mpc8610_hpcd_machine_probe;
- machine_data->card.remove = mpc8610_hpcd_machine_remove;
- machine_data->card.name = pdev->name; /* The platform driver name */
- machine_data->card.owner = THIS_MODULE;
- machine_data->card.dev = &pdev->dev;
- machine_data->card.num_links = 2;
- machine_data->card.dai_link = machine_data->dai;
-
- /* Register with ASoC */
- ret = snd_soc_register_card(&machine_data->card);
- if (ret) {
- dev_err(&pdev->dev, "could not register card\n");
- goto error;
- }
-
- of_node_put(codec_np);
-
- return 0;
-
-error:
- kfree(machine_data);
-error_alloc:
- of_node_put(codec_np);
- return ret;
-}
-
-/**
- * mpc8610_hpcd_remove: remove the platform device
- *
- * This function is called when the platform device is removed.
- */
-static void mpc8610_hpcd_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct mpc8610_hpcd_data *machine_data =
- container_of(card, struct mpc8610_hpcd_data, card);
-
- snd_soc_unregister_card(card);
- kfree(machine_data);
-}
-
-static struct platform_driver mpc8610_hpcd_driver = {
- .probe = mpc8610_hpcd_probe,
- .remove_new = mpc8610_hpcd_remove,
- .driver = {
- /* The name must match 'compatible' property in the device tree,
- * in lowercase letters.
- */
- .name = "snd-soc-mpc8610hpcd",
- },
-};
-
-/**
- * mpc8610_hpcd_init: machine driver initialization.
- *
- * This function is called when this module is loaded.
- */
-static int __init mpc8610_hpcd_init(void)
-{
- struct device_node *guts_np;
- struct resource res;
-
- pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n");
-
- /* Get the physical address of the global utilities registers */
- guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
- if (of_address_to_resource(guts_np, 0, &res)) {
- pr_err("mpc8610-hpcd: missing/invalid global utilities node\n");
- of_node_put(guts_np);
- return -EINVAL;
- }
- guts_phys = res.start;
- of_node_put(guts_np);
-
- return platform_driver_register(&mpc8610_hpcd_driver);
-}
-
-/**
- * mpc8610_hpcd_exit: machine driver exit
- *
- * This function is called when this driver is unloaded.
- */
-static void __exit mpc8610_hpcd_exit(void)
-{
- platform_driver_unregister(&mpc8610_hpcd_driver);
-}
-
-module_init(mpc8610_hpcd_init);
-module_exit(mpc8610_hpcd_exit);
-
-MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 0b1418abeb9c..66db05970d82 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -9,8 +9,8 @@
#include <linux/module.h>
#include <linux/fsl/guts.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
@@ -121,14 +121,14 @@ static int p1022_ds_machine_probe(struct snd_soc_card *card)
*/
static int p1022_ds_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct machine_data *mdata =
container_of(rtd->card, struct machine_data, card);
struct device *dev = rtd->card->dev;
int ret = 0;
/* Tell the codec driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), mdata->dai_format);
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0), mdata->dai_format);
if (ret < 0) {
dev_err(dev, "could not set codec driver audio format\n");
return ret;
@@ -138,7 +138,7 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream)
* Tell the codec driver what the MCLK frequency is, and whether it's
* a slave or master.
*/
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), 0, mdata->clk_frequency,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, mdata->clk_frequency,
mdata->codec_clk_direction);
if (ret < 0) {
dev_err(dev, "could not set codec driver clock params\n");
@@ -408,7 +408,7 @@ static void p1022_ds_remove(struct platform_device *pdev)
static struct platform_driver p1022_ds_driver = {
.probe = p1022_ds_probe,
- .remove_new = p1022_ds_remove,
+ .remove = p1022_ds_remove,
.driver = {
/*
* The name must match 'compatible' property in the device tree,
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index 4d85b742114c..d4568346714f 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <linux/fsl/guts.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
@@ -61,7 +61,7 @@ static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts,
/* There's only one global utilities register */
static phys_addr_t guts_phys;
-/**
+/*
* machine_data: machine-specific ASoC device data
*
* This structure contains data for a single sound platform device on an
@@ -80,11 +80,14 @@ struct machine_data {
};
/**
- * p1022_rdk_machine_probe: initialize the board
+ * p1022_rdk_machine_probe - initialize the board
+ * @card: ASoC card instance
*
* This function is used to initialize the board-specific hardware.
*
* Here we program the DMACR and PMUXCR registers.
+ *
+ * Returns: %0 on success or negative errno value on error
*/
static int p1022_rdk_machine_probe(struct snd_soc_card *card)
{
@@ -119,29 +122,32 @@ static int p1022_rdk_machine_probe(struct snd_soc_card *card)
}
/**
- * p1022_rdk_startup: program the board with various hardware parameters
+ * p1022_rdk_startup - program the board with various hardware parameters
+ * @substream: ASoC substream object
*
* This function takes board-specific information, like clock frequencies
* and serial data formats, and passes that information to the codec and
* transport drivers.
+ *
+ * Returns: %0 on success or negative errno value on error
*/
static int p1022_rdk_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct machine_data *mdata =
container_of(rtd->card, struct machine_data, card);
struct device *dev = rtd->card->dev;
int ret = 0;
/* Tell the codec driver what the serial protocol is. */
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0), mdata->dai_format);
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0), mdata->dai_format);
if (ret < 0) {
dev_err(dev, "could not set codec driver audio format (ret=%i)\n",
ret);
return ret;
}
- ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0), 0, 0, mdata->clk_frequency,
+ ret = snd_soc_dai_set_pll(snd_soc_rtd_to_codec(rtd, 0), 0, 0, mdata->clk_frequency,
mdata->clk_frequency);
if (ret < 0) {
dev_err(dev, "could not set codec PLL frequency (ret=%i)\n",
@@ -153,10 +159,13 @@ static int p1022_rdk_startup(struct snd_pcm_substream *substream)
}
/**
- * p1022_rdk_machine_remove: Remove the sound device
+ * p1022_rdk_machine_remove - Remove the sound device
+ * @card: ASoC card instance
*
* This function is called to remove the sound device for one SSI. We
* de-program the DMACR and PMUXCR register.
+ *
+ * Returns: %0 on success or negative errno value on error
*/
static int p1022_rdk_machine_remove(struct snd_soc_card *card)
{
@@ -181,7 +190,7 @@ static int p1022_rdk_machine_remove(struct snd_soc_card *card)
return 0;
}
-/**
+/*
* p1022_rdk_ops: ASoC machine driver operations
*/
static const struct snd_soc_ops p1022_rdk_ops = {
@@ -189,11 +198,14 @@ static const struct snd_soc_ops p1022_rdk_ops = {
};
/**
- * p1022_rdk_probe: platform probe function for the machine driver
+ * p1022_rdk_probe - platform probe function for the machine driver
+ * @pdev: platform device pointer
*
* Although this is a machine driver, the SSI node is the "master" node with
* respect to audio hardware connections. Therefore, we create a new ASoC
* device for each new SSI node that has a codec attached.
+ *
+ * Returns: %0 on success or negative errno value on error
*/
static int p1022_rdk_probe(struct platform_device *pdev)
{
@@ -341,7 +353,8 @@ error_put:
}
/**
- * p1022_rdk_remove: remove the platform device
+ * p1022_rdk_remove - remove the platform device
+ * @pdev: platform device pointer
*
* This function is called when the platform device is removed.
*/
@@ -357,7 +370,7 @@ static void p1022_rdk_remove(struct platform_device *pdev)
static struct platform_driver p1022_rdk_driver = {
.probe = p1022_rdk_probe,
- .remove_new = p1022_rdk_remove,
+ .remove = p1022_rdk_remove,
.driver = {
/*
* The name must match 'compatible' property in the device tree,
@@ -368,9 +381,11 @@ static struct platform_driver p1022_rdk_driver = {
};
/**
- * p1022_rdk_init: machine driver initialization.
+ * p1022_rdk_init - machine driver initialization.
*
* This function is called when this module is loaded.
+ *
+ * Returns: %0 on success or negative errno value on error
*/
static int __init p1022_rdk_init(void)
{
@@ -391,7 +406,7 @@ static int __init p1022_rdk_init(void)
}
/**
- * p1022_rdk_exit: machine driver exit
+ * p1022_rdk_exit - machine driver exit
*
* This function is called when this driver is unloaded.
*/
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index d24c02e90878..5542c4ee6d12 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -9,8 +9,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <sound/soc.h>
@@ -125,7 +124,7 @@ MODULE_DEVICE_TABLE(of, pcm030_audio_match);
static struct platform_driver pcm030_fabric_driver = {
.probe = pcm030_fabric_probe,
- .remove_new = pcm030_fabric_remove,
+ .remove = pcm030_fabric_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = pcm030_audio_match,
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index b6df4e26bc4a..64b0817e2955 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Generic drivers"
+
config SND_SIMPLE_CARD_UTILS
tristate
@@ -37,3 +39,5 @@ config SND_TEST_COMPONENT
depends on OF
help
This option enables test component sound driver support.
+
+endmenu
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
index 084862156506..d5abb3eed3df 100644
--- a/sound/soc/generic/Makefile
+++ b/sound/soc/generic/Makefile
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
-snd-soc-simple-card-utils-objs := simple-card-utils.o
-snd-soc-simple-card-objs := simple-card.o
-snd-soc-audio-graph-card-objs := audio-graph-card.o
-snd-soc-audio-graph-card2-objs := audio-graph-card2.o
-snd-soc-audio-graph-card2-custom-sample-objs := audio-graph-card2-custom-sample.o
-snd-soc-test-component-objs := test-component.o
+snd-soc-simple-card-utils-y := simple-card-utils.o
+snd-soc-simple-card-y := simple-card.o
+snd-soc-audio-graph-card-y := audio-graph-card.o
+snd-soc-audio-graph-card2-y := audio-graph-card2.o
+snd-soc-audio-graph-card2-custom-sample-y := audio-graph-card2-custom-sample.o
+snd-soc-test-component-y := test-component.o
obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o
obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index c6e0f9132193..7720cf1fd6e1 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -7,14 +7,12 @@
//
// based on ${LINUX}/sound/soc/generic/simple-card.c
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/device.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/string.h>
@@ -22,12 +20,31 @@
#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)
+{
+ struct device_node *ports = of_get_parent(port);
+
+ if (!of_node_name_eq(ports, "ports")) {
+ of_node_put(ports);
+ return NULL;
+ }
+ return ports;
+}
+
static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(dapm->card);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -50,9 +67,9 @@ static const struct snd_soc_dapm_widget graph_dapm_widgets[] = {
};
static const struct snd_soc_ops graph_ops = {
- .startup = asoc_simple_startup,
- .shutdown = asoc_simple_shutdown,
- .hw_params = asoc_simple_hw_params,
+ .startup = simple_util_startup,
+ .shutdown = simple_util_shutdown,
+ .hw_params = simple_util_hw_params,
};
static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
@@ -60,7 +77,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
if (dai && (dai->component->driver->pcm_construct ||
- dai->driver->pcm_new))
+ (dai->driver->ops && dai->driver->ops->pcm_new)))
return true;
return false;
@@ -68,103 +85,115 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
static void graph_parse_convert(struct device *dev,
struct device_node *ep,
- struct asoc_simple_data *adata)
+ struct simple_util_data *adata)
{
struct device_node *top = dev->of_node;
- struct device_node *port = of_get_parent(ep);
- struct device_node *ports = of_get_parent(port);
- struct device_node *node = of_graph_get_port_parent(ep);
-
- asoc_simple_parse_convert(top, NULL, adata);
- if (of_node_name_eq(ports, "ports"))
- asoc_simple_parse_convert(ports, NULL, adata);
- asoc_simple_parse_convert(port, NULL, adata);
- asoc_simple_parse_convert(ep, NULL, adata);
-
- of_node_put(port);
- of_node_put(ports);
- of_node_put(node);
-}
-
-static void graph_parse_mclk_fs(struct device_node *top,
- struct device_node *ep,
- struct simple_dai_props *props)
-{
- struct device_node *port = of_get_parent(ep);
- struct device_node *ports = of_get_parent(port);
-
- of_property_read_u32(top, "mclk-fs", &props->mclk_fs);
- if (of_node_name_eq(ports, "ports"))
- of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
-
- of_node_put(port);
- of_node_put(ports);
+ 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);
}
-static int graph_parse_node(struct asoc_simple_priv *priv,
+static int graph_parse_node(struct simple_util_priv *priv,
struct device_node *ep,
struct link_info *li,
int *cpu)
{
struct device *dev = simple_priv_to_dev(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 snd_soc_dai_link_component *dlc;
- struct asoc_simple_dai *dai;
+ struct simple_util_dai *dai;
int ret;
if (cpu) {
- dlc = asoc_link_to_cpu(dai_link, 0);
+ dlc = snd_soc_link_to_cpu(dai_link, 0);
dai = simple_props_to_dai_cpu(dai_props, 0);
} else {
- dlc = asoc_link_to_codec(dai_link, 0);
+ dlc = snd_soc_link_to_codec(dai_link, 0);
dai = simple_props_to_dai_codec(dai_props, 0);
}
- graph_parse_mclk_fs(top, ep, dai_props);
-
- ret = asoc_graph_parse_dai(ep, dlc, cpu);
+ ret = graph_util_parse_dai(priv, ep, dlc, cpu);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_parse_tdm(ep, dai);
+ ret = simple_util_parse_tdm(ep, dai);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_parse_clk(dev, ep, dai, dlc);
- if (ret < 0)
- return ret;
-
- return 0;
+ ret = simple_util_parse_clk(dev, ep, dai, dlc);
+end:
+ return graph_ret(priv, ret);
}
-static int graph_link_init(struct asoc_simple_priv *priv,
- struct device_node *cpu_ep,
- struct device_node *codec_ep,
+static int graph_link_init(struct simple_util_priv *priv,
+ struct device_node *ep_cpu,
+ struct device_node *ep_codec,
struct link_info *li,
char *name)
{
struct device *dev = simple_priv_to_dev(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 __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;
int ret;
- ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
+ ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec,
NULL, &dai_link->dai_fmt);
if (ret < 0)
- return ret;
-
- dai_link->init = asoc_simple_dai_init;
+ goto end;
+
+ graph_util_parse_link_direction(top, &playback_only, &capture_only);
+ graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(port_codec, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only);
+
+ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs);
+
+ graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop);
+
+ dai_link->playback_only = playback_only;
+ dai_link->capture_only = capture_only;
+
+ dai_link->trigger_start = trigger_start;
+ dai_link->trigger_stop = trigger_stop;
+
+ dai_link->init = simple_util_dai_init;
dai_link->ops = &graph_ops;
if (priv->ops)
dai_link->ops = priv->ops;
- return asoc_simple_set_dailink_name(dev, dai_link, name);
+ ret = simple_util_set_dailink_name(priv, dai_link, name);
+end:
+ return graph_ret(priv, ret);
}
-static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
+static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li)
@@ -181,8 +210,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
if (li->cpu) {
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
- struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
+ struct snd_soc_dai_link_component *cpus = snd_soc_link_to_cpu(dai_link, 0);
+ struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, 0);
int is_single_links = 0;
/* Codec is dummy */
@@ -193,7 +222,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_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);
@@ -209,65 +238,56 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
*/
if (card->component_chaining && !soc_component_is_pcm(cpus)) {
dai_link->no_pcm = 1;
- dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
+ dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
}
- asoc_simple_canonicalize_cpu(cpus, is_single_links);
- asoc_simple_canonicalize_platform(platforms, cpus);
+ simple_util_canonicalize_cpu(cpus, is_single_links);
+ simple_util_canonicalize_platform(platforms, cpus);
} else {
struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0);
- struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
- struct device_node *port;
- struct device_node *ports;
+ struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, 0);
/* CPU is dummy */
/* BE settings */
dai_link->no_pcm = 1;
- dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
+ dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
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 = of_get_parent(ep);
- ports = of_get_parent(port);
- snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
- "prefix");
- if (of_node_name_eq(ports, "ports"))
- snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
- snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
- "prefix");
+ struct device_node *port __free(device_node) = ep_to_port(ep);
+ struct device_node *ports __free(device_node) = port_to_ports(port);
- of_node_put(ports);
- of_node_put(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");
}
graph_parse_convert(dev, ep, &dai_props->adata);
- snd_soc_dai_link_set_capabilities(dai_link);
-
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 asoc_simple_priv *priv,
+static int graph_dai_link_of(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
- struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
- struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
- struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
+ struct snd_soc_dai_link_component *cpus = snd_soc_link_to_cpu(dai_link, 0);
+ 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);
char dai_name[64];
int ret, is_single_links = 0;
@@ -275,30 +295,30 @@ static int graph_dai_link_of(struct asoc_simple_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);
- asoc_simple_canonicalize_cpu(cpus, is_single_links);
- asoc_simple_canonicalize_platform(platforms, cpus);
+ simple_util_canonicalize_cpu(cpus, is_single_links);
+ simple_util_canonicalize_platform(platforms, cpus);
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 asoc_simple_priv *priv,
+static inline bool parse_as_dpcm_link(struct simple_util_priv *priv,
struct device_node *codec_port,
- struct asoc_simple_data *adata)
+ struct simple_util_data *adata)
{
if (priv->force_dpcm)
return true;
@@ -312,19 +332,19 @@ static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv,
* or has convert-xxx property
*/
if ((of_get_child_count(codec_port) > 1) ||
- asoc_simple_is_convert_required(adata))
+ simple_util_is_convert_required(adata))
return true;
return false;
}
-static int __graph_for_each_link(struct asoc_simple_priv *priv,
+static int __graph_for_each_link(struct simple_util_priv *priv,
struct link_info *li,
- int (*func_noml)(struct asoc_simple_priv *priv,
+ int (*func_noml)(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li),
- int (*func_dpcm)(struct asoc_simple_priv *priv,
+ int (*func_dpcm)(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li))
@@ -333,27 +353,19 @@ static int __graph_for_each_link(struct asoc_simple_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 *cpu_ep;
- struct device_node *codec_ep;
- struct device_node *codec_port;
struct device_node *codec_port_old = NULL;
- struct asoc_simple_data adata;
+ struct simple_util_data adata;
int rc, ret = 0;
/* loop for all listed CPU port */
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
- cpu_ep = NULL;
/* loop for all CPU endpoint */
- while (1) {
- cpu_ep = of_get_next_child(cpu_port, cpu_ep);
- if (!cpu_ep)
- break;
-
+ for_each_of_graph_port_endpoint(cpu_port, cpu_ep) {
/* get codec */
- codec_ep = of_graph_get_remote_endpoint(cpu_ep);
- codec_port = of_get_parent(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));
@@ -377,28 +389,23 @@ static int __graph_for_each_link(struct asoc_simple_priv *priv,
ret = func_noml(priv, cpu_ep, codec_ep, li);
}
- of_node_put(codec_ep);
- of_node_put(codec_port);
-
- if (ret < 0) {
- of_node_put(cpu_ep);
- return ret;
- }
+ if (ret < 0)
+ goto end;
codec_port_old = codec_port;
}
}
-
- return 0;
+end:
+ return graph_ret(priv, ret);
}
-static int graph_for_each_link(struct asoc_simple_priv *priv,
+static int graph_for_each_link(struct simple_util_priv *priv,
struct link_info *li,
- int (*func_noml)(struct asoc_simple_priv *priv,
+ int (*func_noml)(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li),
- int (*func_dpcm)(struct asoc_simple_priv *priv,
+ int (*func_dpcm)(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li))
@@ -422,91 +429,19 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
break;
}
- return ret;
+ return graph_ret(priv, ret);
}
-static int graph_get_dais_count(struct asoc_simple_priv *priv,
- struct link_info *li);
-
-int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
-{
- struct snd_soc_card *card = simple_priv_to_card(priv);
- struct link_info *li;
- int ret;
-
- li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
- if (!li)
- return -ENOMEM;
-
- card->owner = THIS_MODULE;
- card->dev = dev;
-
- ret = graph_get_dais_count(priv, li);
- if (ret < 0)
- return ret;
-
- if (!li->link)
- return -EINVAL;
-
- ret = asoc_simple_init_priv(priv, li);
- if (ret < 0)
- return ret;
-
- 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;
- }
-
- ret = asoc_simple_parse_widgets(card, NULL);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_routing(card, NULL);
- if (ret < 0)
- return ret;
-
- memset(li, 0, sizeof(*li));
- ret = graph_for_each_link(priv, li,
- graph_dai_link_of,
- graph_dai_link_of_dpcm);
- if (ret < 0)
- goto err;
-
- ret = asoc_simple_parse_card_name(card, NULL);
- if (ret < 0)
- goto err;
-
- snd_soc_card_set_drvdata(card, priv);
-
- asoc_simple_debug_info(priv);
-
- ret = devm_snd_soc_register_card(dev, card);
- if (ret < 0)
- goto err;
-
- devm_kfree(dev, li);
- return 0;
-
-err:
- asoc_simple_clean_reference(card);
-
- return dev_err_probe(dev, ret, "parse error\n");
-}
-EXPORT_SYMBOL_GPL(audio_graph_parse_of);
-
-static int graph_count_noml(struct asoc_simple_priv *priv,
+static int graph_count_noml(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
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
@@ -521,21 +456,21 @@ static int graph_count_noml(struct asoc_simple_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 asoc_simple_priv *priv,
+static int graph_count_dpcm(struct simple_util_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
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) {
/*
@@ -554,11 +489,12 @@ static int graph_count_dpcm(struct asoc_simple_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 asoc_simple_priv *priv,
+static int graph_get_dais_count(struct simple_util_priv *priv,
struct link_info *li)
{
/*
@@ -612,9 +548,75 @@ static int graph_get_dais_count(struct asoc_simple_priv *priv,
graph_count_dpcm);
}
+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 = -ENOMEM;
+
+ struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
+ if (!li)
+ goto end;
+
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+
+ ret = graph_get_dais_count(priv, li);
+ if (ret < 0)
+ goto end;
+
+ ret = -EINVAL;
+ if (!li->link)
+ goto end;
+
+ ret = simple_util_init_priv(priv, li);
+ if (ret < 0)
+ goto end;
+
+ priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->pa_gpio)) {
+ ret = PTR_ERR(priv->pa_gpio);
+ dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
+ goto end;
+ }
+
+ ret = simple_util_parse_widgets(card, NULL);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_routing(card, NULL);
+ if (ret < 0)
+ goto end;
+
+ memset(li, 0, sizeof(*li));
+ ret = graph_for_each_link(priv, li,
+ graph_dai_link_of,
+ graph_dai_link_of_dpcm);
+ if (ret < 0)
+ goto err;
+
+ ret = simple_util_parse_card_name(priv, NULL);
+ if (ret < 0)
+ goto err;
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ simple_util_debug_info(priv);
+
+ ret = devm_snd_soc_register_card(dev, card);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ simple_util_clean_reference(card);
+end:
+ return dev_err_probe(dev, ret, "parse error\n");
+}
+EXPORT_SYMBOL_GPL(audio_graph_parse_of);
+
static int graph_probe(struct platform_device *pdev)
{
- struct asoc_simple_priv *priv;
+ struct simple_util_priv *priv;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
@@ -626,7 +628,7 @@ static int graph_probe(struct platform_device *pdev)
card = simple_priv_to_card(priv);
card->dapm_widgets = graph_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets);
- card->probe = asoc_graph_card_probe;
+ card->probe = graph_util_card_probe;
if (of_device_get_match_data(dev))
priv->dpcm_selectable = 1;
@@ -649,7 +651,7 @@ static struct platform_driver graph_card = {
.of_match_table = graph_of_match,
},
.probe = graph_probe,
- .remove = asoc_simple_remove,
+ .remove = simple_util_remove,
};
module_platform_driver(graph_card);
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c
index a3142be9323e..7151d426bee9 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.c
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.c
@@ -5,17 +5,18 @@
// Copyright (C) 2020 Renesas Electronics Corp.
// Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
//
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <sound/graph_card.h>
/*
* Custom driver can have own priv
- * which includes asoc_simple_priv.
+ * which includes simple_util_priv.
*/
struct custom_priv {
- struct asoc_simple_priv simple_priv;
+ struct simple_util_priv simple_priv;
/* custom driver's own params */
int custom_params;
@@ -26,7 +27,7 @@ struct custom_priv {
static int custom_card_probe(struct snd_soc_card *card)
{
- struct asoc_simple_priv *simple_priv = snd_soc_card_get_drvdata(card);
+ struct simple_util_priv *simple_priv = snd_soc_card_get_drvdata(card);
struct custom_priv *custom_priv = simple_to_custom(simple_priv);
struct device *dev = simple_priv_to_dev(simple_priv);
@@ -35,10 +36,10 @@ static int custom_card_probe(struct snd_soc_card *card)
custom_priv->custom_params = 1;
/* you can use generic probe function */
- return asoc_graph_card_probe(card);
+ return graph_util_card_probe(card);
}
-static int custom_hook_pre(struct asoc_simple_priv *priv)
+static int custom_hook_pre(struct simple_util_priv *priv)
{
struct device *dev = simple_priv_to_dev(priv);
@@ -48,7 +49,7 @@ static int custom_hook_pre(struct asoc_simple_priv *priv)
return 0;
}
-static int custom_hook_post(struct asoc_simple_priv *priv)
+static int custom_hook_post(struct simple_util_priv *priv)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_card *card;
@@ -63,7 +64,7 @@ static int custom_hook_post(struct asoc_simple_priv *priv)
return 0;
}
-static int custom_normal(struct asoc_simple_priv *priv,
+static int custom_normal(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
@@ -78,7 +79,7 @@ static int custom_normal(struct asoc_simple_priv *priv,
return audio_graph2_link_normal(priv, lnk, li);
}
-static int custom_dpcm(struct asoc_simple_priv *priv,
+static int custom_dpcm(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
@@ -93,7 +94,7 @@ static int custom_dpcm(struct asoc_simple_priv *priv,
return audio_graph2_link_dpcm(priv, lnk, li);
}
-static int custom_c2c(struct asoc_simple_priv *priv,
+static int custom_c2c(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
@@ -121,26 +122,26 @@ static struct graph2_custom_hooks custom_hooks = {
static int custom_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ 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 device *dev = simple_priv_to_dev(priv);
dev_info(dev, "custom startup\n");
- return asoc_simple_startup(substream);
+ return simple_util_startup(substream);
}
/* You can use custom ops */
static const struct snd_soc_ops custom_ops = {
.startup = custom_startup,
- .shutdown = asoc_simple_shutdown,
- .hw_params = asoc_simple_hw_params,
+ .shutdown = simple_util_shutdown,
+ .hw_params = simple_util_hw_params,
};
static int custom_probe(struct platform_device *pdev)
{
struct custom_priv *custom_priv;
- struct asoc_simple_priv *simple_priv;
+ struct simple_util_priv *simple_priv;
struct device *dev = &pdev->dev;
int ret;
@@ -176,7 +177,7 @@ static struct platform_driver custom_card = {
.of_match_table = custom_of_match,
},
.probe = custom_probe,
- .remove = asoc_simple_remove,
+ .remove = simple_util_remove,
};
module_platform_driver(custom_card);
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 2ac0de3c21da..000000000000
--- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
+++ /dev/null
@@ -1,393 +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";
- * ...
- * };
- *
- */
-/ {
- /*
- * @ : used at links
- *
- * [Normal]
- * cpu0 <-@-----------------> codec0
- *
- * [Semi-Multi]
- *
- * CPU:Codec = 1:N
- *
- * +-+
- * cpu7 <-@------->| |-> codec12
- * | |-> codec13
- * +-+
- *
- * [Multi-CPU/Codec]
- * +-+ +-+
- * cpu1 <--| |<-@--------->| |-> codec1
- * cpu2 <--| | | |-> codec2
- * +-+ +-+
- *
- * [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] */
- &sm0
-
- /*
- * [Multi-CPU/Codec]: cpu side only
- * cpu1/cpu2/codec1/codec2
- */
- &mcpu0
-
- /*
- * [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>;
-
- ports@0 {
- reg = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
- /* [Multi-CPU] */
- mcpu0: port@0 { reg = <0>; mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
- port@1 { reg = <1>; mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
- port@2 { reg = <2>; mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
- };
-
- /* [Multi-Codec] */
- ports@1 {
- reg = <1>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
- port@1 { reg = <1>; mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
- port@2 { reg = <2>; mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
- };
-
- /* [DPCM-Multi]::BE */
- ports@2 {
- reg = <2>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; }; };
- port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; };
- port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; };
- };
-
- /* [Codec2Codec-Multi]::CPU */
- ports@3 {
- reg = <3>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; }; };
- port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; };
- port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; };
- };
-
- /* [Codec2Codec-Multi]::Codec */
- ports@4 {
- reg = <4>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; }; };
- port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; };
- port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; }; };
- };
-
- /* [Semi-Multi] */
- ports@5 {
- reg = <5>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; }; };
- port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; }; };
- port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; }; };
- };
- };
-
- dpcm {
- #address-cells = <1>;
- #size-cells = <0>;
-
- ports@0 {
- reg = <0>;
-
- #address-cells = <1>;
- #size-cells = <0>;
- /* [DPCM]::FE */
- 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 */
- 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 */
- be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; };
-
- /* [DPCM-Multi]::BE */
- be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; };
- };
- };
-
- codec2codec {
- #address-cells = <1>;
- #size-cells = <0>;
- /* [Codec2Codec] */
- 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] */
- 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] */
- port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
- port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu2_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>; }; };
- };
- };
-
- 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] */
- port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
- port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec2_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>; }; };
-
- };
- };
-};
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 542c4a114940..5dcc78c551a2 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -8,12 +8,9 @@
// based on ${LINUX}/sound/soc/generic/audio-graph-card.c
#include <linux/clk.h>
#include <linux/device.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/string.h>
@@ -47,6 +44,18 @@
see
graph_parse_daifmt().
+ "format" property is no longer needed on DT if both CPU/Codec drivers are
+ supporting snd_soc_dai_ops :: .auto_selectable_formats.
+ see
+ snd_soc_runtime_get_dai_fmt()
+
+ sample driver
+ linux/sound/soc/renesas/rcar/core.c
+ linux/sound/soc/codecs/ak4613.c
+ linux/sound/soc/codecs/pcm3168a.c
+ linux/sound/soc/soc-utils.c
+ linux/sound/soc/generic/test-component.c
+
************************************
Normal Audio-Graph
************************************
@@ -73,32 +82,32 @@
Multi-CPU/Codec
************************************
-It has connection part (= X) and list part (= y).
-links indicates connection part of CPU side (= A).
+It has link connection part (= X,x) and list part (= A,B,a,b).
+"links" is connection part of CPU side (= @).
- +-+ (A) +-+
- CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1
- CPU2 --(y) | | | | (y)-- Codec2
- +-+ +-+
+ +----+ +---+
+ CPU1 --|A X| <-@----> |x a|-- Codec1
+ CPU2 --|B | | b|-- Codec2
+ +----+ +---+
- sound {
- compatible = "audio-graph-card2";
+ sound {
+ compatible = "audio-graph-card2";
-(A) links = <&mcpu>;
+(@) links = <&mcpu>;
- multi {
- ports@0 {
-(X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
-(y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
-(y) port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
- };
- ports@1 {
-(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
-(y) port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
-(y) port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
- };
+ multi {
+ ports@0 {
+(@) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; // (X) to pair
+ port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; // (A) Multi Element
+ port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; // (B) Multi Element
+ };
+ ports@1 {
+ port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; // (x) to pair
+ port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; // (a) Multi Element
+ port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; // (b) Multi Element
};
};
+ };
CPU {
ports {
@@ -225,7 +234,24 @@ enum graph_type {
#define GRAPH_NODENAME_DPCM "dpcm"
#define GRAPH_NODENAME_C2C "codec2codec"
-#define port_to_endpoint(port) of_get_child_by_name(port, "endpoint")
+#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)
+{
+ struct device_node *ports = of_get_parent(port);
+
+ if (!of_node_name_eq(ports, "ports")) {
+ of_node_put(ports);
+ return NULL;
+ }
+ return ports;
+}
static enum graph_type __graph_get_type(struct device_node *lnk)
{
@@ -249,16 +275,19 @@ static enum graph_type __graph_get_type(struct device_node *lnk)
if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) {
ret = GRAPH_MULTI;
+ fw_devlink_purge_absent_suppliers(&np->fwnode);
goto out_put;
}
if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) {
ret = GRAPH_DPCM;
+ fw_devlink_purge_absent_suppliers(&np->fwnode);
goto out_put;
}
if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) {
ret = GRAPH_C2C;
+ fw_devlink_purge_absent_suppliers(&np->fwnode);
goto out_put;
}
@@ -270,7 +299,7 @@ out_put:
}
-static enum graph_type graph_get_type(struct asoc_simple_priv *priv,
+static enum graph_type graph_get_type(struct simple_util_priv *priv,
struct device_node *lnk)
{
enum graph_type type = __graph_get_type(lnk);
@@ -286,7 +315,7 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv,
switch (type) {
case GRAPH_DPCM:
- if (asoc_graph_is_ports0(lnk))
+ if (graph_util_is_ports0(lnk))
str = "DPCM Front-End";
else
str = "DPCM Back-End";
@@ -309,18 +338,17 @@ 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 = of_get_parent(*port);
- struct device_node *ep = NULL;
+ struct device_node *ports __free(device_node) = port_to_ports(*port);
struct device_node *rep = NULL;
/*
* multi {
* ports {
- * => lnk: port@0 { ... };
- * port@1 { ep { ... = rep0 } };
- * port@2 { ep { ... = rep1 } };
+ * => lnk: port@0 { ... }; // to pair
+ * port@1 { ep { ... = rep0 } }; // Multi Element
+ * port@2 { ep { ... = rep1 } }; // Multi Element
* ...
* };
* };
@@ -330,61 +358,44 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port)
* port@1 { rep1 };
* };
*/
- do {
- *port = of_get_next_child(ports, *port);
- if (!*port)
- break;
- } while (!of_node_name_eq(*port, "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 = port_to_endpoint(*port);
+ 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;
}
static const struct snd_soc_ops graph_ops = {
- .startup = asoc_simple_startup,
- .shutdown = asoc_simple_shutdown,
- .hw_params = asoc_simple_hw_params,
+ .startup = simple_util_startup,
+ .shutdown = simple_util_shutdown,
+ .hw_params = simple_util_hw_params,
};
static void graph_parse_convert(struct device_node *ep,
struct simple_dai_props *props)
{
- struct device_node *port = of_get_parent(ep);
- struct device_node *ports = of_get_parent(port);
- struct asoc_simple_data *adata = &props->adata;
-
- if (of_node_name_eq(ports, "ports"))
- asoc_simple_parse_convert(ports, NULL, adata);
- asoc_simple_parse_convert(port, NULL, adata);
- asoc_simple_parse_convert(ep, NULL, adata);
-
- of_node_put(port);
- of_node_put(ports);
-}
-
-static void graph_parse_mclk_fs(struct device_node *ep,
- struct simple_dai_props *props)
-{
- struct device_node *port = of_get_parent(ep);
- struct device_node *ports = of_get_parent(port);
-
- if (of_node_name_eq(ports, "ports"))
- of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
- of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
+ 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;
- of_node_put(port);
- of_node_put(ports);
+ simple_util_parse_convert(ports, NULL, adata);
+ simple_util_parse_convert(port, NULL, adata);
+ simple_util_parse_convert(ep, NULL, adata);
}
-static int __graph_parse_node(struct asoc_simple_priv *priv,
+static int __graph_parse_node(struct simple_util_priv *priv,
enum graph_type gtype,
struct device_node *ep,
struct link_info *li,
@@ -394,41 +405,39 @@ static int __graph_parse_node(struct asoc_simple_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 snd_soc_dai_link_component *dlc;
- struct asoc_simple_dai *dai;
+ struct simple_util_dai *dai;
int ret, is_single_links = 0;
if (is_cpu) {
- dlc = asoc_link_to_cpu(dai_link, idx);
+ dlc = snd_soc_link_to_cpu(dai_link, idx);
dai = simple_props_to_dai_cpu(dai_props, idx);
} else {
- dlc = asoc_link_to_codec(dai_link, idx);
+ dlc = snd_soc_link_to_codec(dai_link, idx);
dai = simple_props_to_dai_codec(dai_props, idx);
}
- graph_parse_mclk_fs(ep, dai_props);
-
- ret = asoc_graph_parse_dai(ep, dlc, &is_single_links);
+ ret = graph_util_parse_dai(priv, ep, dlc, &is_single_links);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_parse_tdm(ep, dai);
+ ret = simple_util_parse_tdm(ep, dai);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_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 = asoc_simple_parse_clk(dev, ep, dai, dlc);
+ ret = simple_util_parse_clk(dev, ep, dai, dlc);
if (ret < 0)
- return ret;
+ goto end;
/*
* set DAI Name
*/
if (!dai_link->name) {
struct snd_soc_dai_link_component *cpus = dlc;
- struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, idx);
+ struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
char *cpu_multi = "";
char *codec_multi = "";
@@ -441,22 +450,22 @@ static int __graph_parse_node(struct asoc_simple_priv *priv,
case GRAPH_NORMAL:
/* run is_cpu only. see audio_graph2_link_normal() */
if (is_cpu)
- asoc_simple_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)
- asoc_simple_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
- asoc_simple_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)
- asoc_simple_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;
@@ -470,69 +479,212 @@ static int __graph_parse_node(struct asoc_simple_priv *priv,
* if DPCM-BE case
*/
if (!is_cpu && gtype == GRAPH_DPCM) {
- struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, idx);
+ 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 = of_get_parent(ep);
- struct device_node *rports = of_get_parent(rport);
+ struct device_node *rport __free(device_node) = ep_to_port(ep);
+ struct device_node *rports __free(device_node) = port_to_ports(rport);
- if (of_node_name_eq(rports, "ports"))
- snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
+ 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) {
struct snd_soc_dai_link_component *cpus = dlc;
- struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, idx);
+ struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, idx);
- asoc_simple_canonicalize_cpu(cpus, is_single_links);
- asoc_simple_canonicalize_platform(platforms, cpus);
+ 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(struct asoc_simple_priv *priv,
- enum graph_type gtype,
- struct device_node *port,
- struct link_info *li, int is_cpu)
+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)
{
- struct device_node *ep;
- int ret = 0;
+ /*
+ * +---+ +---+
+ * | X|<-@------->|x |
+ * | | | |
+ * cpu0 <--|A 1|<--------->|4 a|-> codec0
+ * cpu1 <--|B 2|<-----+--->|5 b|-> codec1
+ * cpu2 <--|C 3|<----/ +---+
+ * +---+
+ *
+ * multi {
+ * ports {
+ * port@0 { mcpu_top_ep {... = mcodec_ep; }; }; // (X) to pair
+ * <mcpu_port> port@1 { mcpu0_ep { ... = cpu0_ep; }; // (A) Multi Element
+ * mcpu0_ep_0 { ... = mcodec0_ep_0; }; }; // (1) connected Codec
+ * port@2 { mcpu1_ep { ... = cpu1_ep; }; // (B) Multi Element
+ * mcpu1_ep_0 { ... = mcodec1_ep_0; }; }; // (2) connected Codec
+ * port@3 { mcpu2_ep { ... = cpu2_ep; }; // (C) Multi Element
+ * mcpu2_ep_0 { ... = mcodec1_ep_1; }; }; // (3) connected Codec
+ * };
+ *
+ * ports {
+ * port@0 { mcodec_top_ep {... = mcpu_ep; }; }; // (x) to pair
+ * <mcodec_port>port@1 { mcodec0_ep { ... = codec0_ep; }; // (a) Multi Element
+ * mcodec0_ep_0 { ... = mcpu0_ep_0; }; }; // (4) connected CPU
+ * port@2 { mcodec1_ep { ... = codec1_ep; }; // (b) Multi Element
+ * mcodec1_ep_0 { ... = mcpu1_ep_0; }; // (5) connected CPU
+ * mcodec1_ep_1 { ... = mcpu2_ep_0; }; }; // (5) connected CPU
+ * };
+ * };
+ */
+ 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 = -EINVAL;
- if (graph_lnk_is_multi(port)) {
- int idx;
+ if (cpu_idx > dai_link->num_cpus)
+ goto end;
- of_node_get(port);
+ for_each_of_graph_port_endpoint(mcpu_port, mcpu_ep_n) {
+ int codec_idx = 0;
+
+ /* ignore 1st ep which is for element */
+ if (mcpu_ep_n == mcpu_ep)
+ continue;
+
+ if (*nm_idx > nm_max)
+ break;
- for (idx = 0;; idx++) {
- ep = graph_get_next_multi_ep(&port);
- if (!ep)
+ 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);
+
+ 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 */
+ if (mcodec_port_top == mcodec_port_i)
+ continue;
+
+ if (codec_idx > dai_link->num_codecs)
break;
- ret = __graph_parse_node(priv, gtype, ep,
- li, is_cpu, idx);
- of_node_put(ep);
- if (ret < 0)
+ if (mcodec_port_i == mcodec_port) {
+ dai_link->ch_maps[*nm_idx].cpu = cpu_idx;
+ dai_link->ch_maps[*nm_idx].codec = codec_idx;
+
+ (*nm_idx)++;
+ ret = 0;
break;
+ }
+ codec_idx++;
}
- } else {
- /* Single CPU / Codec */
- ep = port_to_endpoint(port);
- ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0);
- of_node_put(ep);
+ if (ret < 0)
+ break;
}
+end:
+ return graph_ret(priv, ret);
+}
- return ret;
+static int graph_parse_node_multi(struct simple_util_priv *priv,
+ enum graph_type gtype,
+ struct device_node *port,
+ struct link_info *li, int is_cpu)
+{
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
+ struct device *dev = simple_priv_to_dev(priv);
+ int ret = -ENOMEM;
+ int nm_idx = 0;
+ int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
+
+ /*
+ * create ch_maps if CPU:Codec = N:M
+ * DPCM is out of scope
+ */
+ if (gtype != GRAPH_DPCM && !dai_link->ch_maps &&
+ dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
+ dai_link->num_cpus != dai_link->num_codecs) {
+
+ dai_link->ch_maps = devm_kcalloc(dev, nm_max,
+ sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL);
+ if (!dai_link->ch_maps)
+ goto multi_err;
+ }
+
+ for (int idx = 0;; idx++) {
+ /*
+ * multi {
+ * ports {
+ * <port> port@0 { ... }; // to pair
+ * port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element
+ * port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element
+ * };
+ * };
+ *
+ * cpu {
+ * ports {
+ * <ep> port@0 { cpu1_ep { ... = mcpu1_ep };};
+ * };
+ * };
+ */
+ 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);
+ if (ret < 0)
+ goto multi_err;
+
+ /* CPU:Codec = N:M */
+ if (is_cpu && dai_link->ch_maps) {
+ ret = graph_parse_node_multi_nm(priv, dai_link, &nm_idx, idx, port);
+ if (ret < 0)
+ goto multi_err;
+ }
+ }
+
+ if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max))
+ ret = -EINVAL;
+
+multi_err:
+ return graph_ret(priv, ret);
+}
+
+static int graph_parse_node_single(struct simple_util_priv *priv,
+ enum graph_type gtype,
+ struct device_node *ep,
+ struct link_info *li, int is_cpu)
+{
+ return graph_ret(priv, __graph_parse_node(priv, gtype, ep, li, is_cpu, 0));
}
-static void graph_parse_daifmt(struct device_node *node,
- unsigned int *daifmt, unsigned int *bit_frame)
+static int graph_parse_node(struct simple_util_priv *priv,
+ enum graph_type gtype,
+ 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))
+ ret = graph_parse_node_multi(priv, gtype, port, li, is_cpu);
+ else
+ 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 fmt;
+ if (!node)
+ return;
+
/*
* see also above "daifmt" explanation
* and samples.
@@ -551,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)) \
@@ -578,67 +720,130 @@ static void graph_parse_daifmt(struct device_node *node,
update_daifmt(INV);
}
-static void graph_link_init(struct asoc_simple_priv *priv,
- struct device_node *port,
+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 *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 device_node *ep;
- struct device_node *ports;
- unsigned int daifmt = 0, daiclk = 0;
- unsigned int bit_frame = 0;
-
- if (graph_lnk_is_multi(port)) {
- of_node_get(port);
- ep = graph_get_next_multi_ep(&port);
- port = of_get_parent(ep);
+ 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 *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;
+ int multi_cpu_port_idx = 1, multi_codec_port_idx = 1;
+ int i;
+
+ if (graph_lnk_is_multi(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 = port_to_endpoint(port);
+ of_node_get(ep_cpu);
}
+ struct device_node *ports_cpu __free(device_node) = port_to_ports(port_cpu);
- ports = of_get_parent(port);
+ if (graph_lnk_is_multi(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 {
+ of_node_get(ep_codec);
+ }
+ struct device_node *ports_codec __free(device_node) = port_to_ports(port_codec);
+
+ 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);
+ graph_util_parse_link_direction(ports_codec, &playback_only, &capture_only);
+ graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(port_codec, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only);
+
+ of_property_read_u32(lnk, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs);
+
+ graph_util_parse_trigger_order(priv, lnk, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop);
+
+ 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++);
+ }
- /*
- * ports {
- * (A)
- * port {
- * (B)
- * endpoint {
- * (C)
- * };
- * };
- * };
- * };
- */
- graph_parse_daifmt(ep, &daifmt, &bit_frame); /* (C) */
- graph_parse_daifmt(port, &daifmt, &bit_frame); /* (B) */
- if (of_node_name_eq(ports, "ports"))
- graph_parse_daifmt(ports, &daifmt, &bit_frame); /* (A) */
+ for_each_link_codecs(dai_link, i, dlc) {
+ dlc->ext_fmt = graph_parse_bitframe(ep_codec);
- /*
- * 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);
+ 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;
+
+ dai_link->trigger_start = trigger_start;
+ dai_link->trigger_stop = trigger_stop;
- dai_link->dai_fmt = daifmt | daiclk;
- dai_link->init = asoc_simple_dai_init;
+ 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(port_cpu);
+ of_node_put(port_codec);
+ of_node_put(ep_cpu);
+ of_node_put(ep_codec);
}
-int audio_graph2_link_normal(struct asoc_simple_priv *priv,
+int audio_graph2_link_normal(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
struct device_node *cpu_port = lnk;
- struct device_node *cpu_ep = port_to_endpoint(cpu_port);
- 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;
/*
@@ -646,39 +851,40 @@ int audio_graph2_link_normal(struct asoc_simple_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, cpu_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);
-int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
+int audio_graph2_link_dpcm(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ep = port_to_endpoint(lnk);
- struct device_node *rep = of_graph_get_remote_endpoint(ep);
- 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 *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 = asoc_graph_is_ports0(lnk);
+ int is_cpu = graph_util_is_ports0(lnk);
int ret;
if (is_cpu) {
+ cpu_ep = rep;
+
/*
* dpcm {
* // Front-End
@@ -701,15 +907,18 @@ int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
/*
* setup CPU here, Codec is already set as dummy.
* see
- * asoc_simple_init_priv()
+ * simple_util_init_priv()
*/
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
- ret = graph_parse_node(priv, GRAPH_DPCM, rport, li, 1);
+ ret = graph_parse_node(priv, GRAPH_DPCM, cpu_ep, li, 1);
if (ret)
- goto err;
+ return ret;
+
} else {
+ codec_ep = rep;
+
/*
* dpcm {
* // Front-End
@@ -732,41 +941,35 @@ int audio_graph2_link_dpcm(struct asoc_simple_priv *priv,
/*
* setup Codec here, CPU is already set as dummy.
* see
- * asoc_simple_init_priv()
+ * simple_util_init_priv()
*/
/* BE settings */
dai_link->no_pcm = 1;
- dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
+ dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
- ret = graph_parse_node(priv, GRAPH_DPCM, rport, 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> */
- snd_soc_dai_link_set_capabilities(dai_link);
+ graph_link_init(priv, lnk, cpu_ep, codec_ep, li, is_cpu);
- graph_link_init(priv, rport, li, is_cpu);
-err:
- of_node_put(ep);
- of_node_put(rep);
- of_node_put(rport);
-
- return ret;
+ return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm);
-int audio_graph2_link_c2c(struct asoc_simple_priv *priv,
+int audio_graph2_link_c2c(struct simple_util_priv *priv,
struct device_node *lnk,
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;
@@ -786,16 +989,12 @@ int audio_graph2_link_c2c(struct asoc_simple_priv *priv,
* };
* };
*/
- of_node_get(lnk);
- port0 = lnk;
- ports = of_get_parent(port0);
- port1 = of_get_next_child(ports, lnk);
/*
* Card2 can use original Codec2Codec settings if DT has.
* It will use default settings if no settings on DT.
* see
- * asoc_simple_init_for_codec2codec()
+ * simple_util_init_for_codec2codec()
*
* Add more settings here if needed
*/
@@ -805,8 +1004,13 @@ int audio_graph2_link_c2c(struct asoc_simple_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;
@@ -819,44 +1023,35 @@ int audio_graph2_link_c2c(struct asoc_simple_priv *priv,
dai_link->num_c2c_params = 1;
}
- ep0 = port_to_endpoint(port0);
- ep1 = port_to_endpoint(port1);
+ 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, codec0_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);
-static int graph_link(struct asoc_simple_priv *priv,
+static int graph_link(struct simple_util_priv *priv,
struct graph2_custom_hooks *hooks,
enum graph_type gtype,
struct device_node *lnk,
@@ -900,7 +1095,7 @@ static int graph_link(struct asoc_simple_priv *priv,
li->link++;
err:
- return ret;
+ return graph_ret(priv, ret);
}
static int graph_counter(struct device_node *lnk)
@@ -910,17 +1105,24 @@ static int graph_counter(struct device_node *lnk)
*
* multi {
* ports {
- * => lnk: port@0 { ... };
- * port@1 { ... };
- * port@2 { ... };
+ * => lnk: port@0 { ... }; // to pair
+ * port@1 { ... }; // Multi Element
+ * port@2 { ... }; // Multi Element
* ...
* };
* };
*
* ignore first lnk part
*/
- if (graph_lnk_is_multi(lnk))
- return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1;
+ if (graph_lnk_is_multi(lnk)) {
+ struct device_node *ports = port_to_ports(lnk);
+
+ /*
+ * CPU/Codec = N:M case has many endpoints.
+ * We can't use of_graph_get_endpoint_count() here
+ */
+ return of_graph_get_port_count(ports) - 1;
+ }
/*
* Single CPU / Codec
*/
@@ -928,13 +1130,13 @@ static int graph_counter(struct device_node *lnk)
return 1;
}
-static int graph_count_normal(struct asoc_simple_priv *priv,
+static int graph_count_normal(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
struct device_node *cpu_port = lnk;
- struct device_node *cpu_ep = port_to_endpoint(cpu_port);
- 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 {
@@ -951,18 +1153,15 @@ static int graph_count_normal(struct asoc_simple_priv *priv,
li->num[li->link].codecs = graph_counter(codec_port);
- of_node_put(cpu_ep);
- of_node_put(codec_port);
-
return 0;
}
-static int graph_count_dpcm(struct asoc_simple_priv *priv,
+static int graph_count_dpcm(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ep = port_to_endpoint(lnk);
- 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 {
@@ -979,7 +1178,7 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
* };
*/
- if (asoc_graph_is_ports0(lnk)) {
+ if (graph_util_is_ports0(lnk)) {
/*
* DON'T REMOVE platforms
* see
@@ -991,25 +1190,20 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
li->num[li->link].codecs = graph_counter(rport); /* BE */
}
- of_node_put(ep);
- of_node_put(rport);
-
return 0;
}
-static int graph_count_c2c(struct asoc_simple_priv *priv,
+static int graph_count_c2c(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ports = of_get_parent(lnk);
- struct device_node *port0 = lnk;
- struct device_node *port1 = of_get_next_child(ports, lnk);
- struct device_node *ep0 = port_to_endpoint(port0);
- struct device_node *ep1 = port_to_endpoint(port1);
- struct device_node *codec0 = of_graph_get_remote_port(ep0);
- struct device_node *codec1 = of_graph_get_remote_port(ep1);
-
- of_node_get(lnk);
+ 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 {
@@ -1029,17 +1223,10 @@ static int graph_count_c2c(struct asoc_simple_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;
}
-static int graph_count(struct asoc_simple_priv *priv,
+static int graph_count(struct simple_util_priv *priv,
struct graph2_custom_hooks *hooks,
enum graph_type gtype,
struct device_node *lnk,
@@ -1079,13 +1266,13 @@ static int graph_count(struct asoc_simple_priv *priv,
li->link++;
err:
- return ret;
+ return graph_ret(priv, ret);
}
-static int graph_for_each_link(struct asoc_simple_priv *priv,
+static int graph_for_each_link(struct simple_util_priv *priv,
struct graph2_custom_hooks *hooks,
struct link_info *li,
- int (*func)(struct asoc_simple_priv *priv,
+ int (*func)(struct simple_util_priv *priv,
struct graph2_custom_hooks *hooks,
enum graph_type gtype,
struct device_node *lnk,
@@ -1096,7 +1283,7 @@ static int graph_for_each_link(struct asoc_simple_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) {
@@ -1106,24 +1293,23 @@ static int graph_for_each_link(struct asoc_simple_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 asoc_simple_priv *priv, struct device *dev,
+int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
struct graph2_custom_hooks *hooks)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct link_info *li;
int ret;
- li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+ struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
if (!li)
return -ENOMEM;
- card->probe = asoc_graph_card_probe;
+ card->probe = graph_util_card_probe;
card->owner = THIS_MODULE;
card->dev = dev;
@@ -1139,7 +1325,7 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
if (ret < 0)
goto err;
- ret = asoc_simple_init_priv(priv, li);
+ ret = simple_util_init_priv(priv, li);
if (ret < 0)
goto err;
@@ -1150,11 +1336,11 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
goto err;
}
- ret = asoc_simple_parse_widgets(card, NULL);
+ ret = simple_util_parse_widgets(card, NULL);
if (ret < 0)
goto err;
- ret = asoc_simple_parse_routing(card, NULL);
+ ret = simple_util_parse_routing(card, NULL);
if (ret < 0)
goto err;
@@ -1163,7 +1349,7 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
if (ret < 0)
goto err;
- ret = asoc_simple_parse_card_name(card, NULL);
+ ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -1175,22 +1361,24 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
goto err;
}
- asoc_simple_debug_info(priv);
+ simple_util_debug_info(priv);
+
+ ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
+ if (ret < 0)
+ goto err;
ret = devm_snd_soc_register_card(dev, card);
err:
- devm_kfree(dev, li);
-
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);
static int graph_probe(struct platform_device *pdev)
{
- struct asoc_simple_priv *priv;
+ struct simple_util_priv *priv;
struct device *dev = &pdev->dev;
/* Allocate the private data and the DAI link array */
@@ -1214,7 +1402,7 @@ static struct platform_driver graph_card = {
.of_match_table = graph_of_match,
},
.probe = graph_probe,
- .remove = asoc_simple_remove,
+ .remove = simple_util_remove,
};
module_platform_driver(graph_card);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index f94c48aa126c..355f7ec8943c 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -4,8 +4,9 @@
//
// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+#include <dt-bindings/sound/audio-graph.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -14,12 +15,18 @@
#include <sound/pcm_params.h>
#include <sound/simple_card_utils.h>
-static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data,
- struct snd_pcm_hw_params *params)
+#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;
- struct snd_mask *mask = hw_param_mask(params,
- SNDRV_PCM_HW_PARAM_FORMAT);
+ int val = -EINVAL;
+
struct {
char *fmt;
u32 val;
@@ -34,19 +41,37 @@ static void asoc_simple_fixup_sample_fmt(struct asoc_simple_data *data,
for (i = 0; i < ARRAY_SIZE(of_sample_fmt_table); i++) {
if (!strcmp(data->convert_sample_format,
of_sample_fmt_table[i].fmt)) {
- snd_mask_none(mask);
- snd_mask_set(mask, of_sample_fmt_table[i].val);
+ val = of_sample_fmt_table[i].val;
break;
}
}
+ return val;
+}
+EXPORT_SYMBOL_GPL(simple_util_get_sample_fmt);
+
+static void simple_fixup_sample_fmt(struct simple_util_data *data,
+ struct snd_pcm_hw_params *params)
+{
+ int val;
+ struct snd_mask *mask = hw_param_mask(params,
+ SNDRV_PCM_HW_PARAM_FORMAT);
+
+ val = simple_util_get_sample_fmt(data);
+ if (val >= 0) {
+ snd_mask_none(mask);
+ snd_mask_set(mask, val);
+ }
}
-void asoc_simple_parse_convert(struct device_node *np,
+void simple_util_parse_convert(struct device_node *np,
char *prefix,
- struct asoc_simple_data *data)
+ struct simple_util_data *data)
{
char prop[128];
+ if (!np)
+ return;
+
if (!prefix)
prefix = "";
@@ -62,24 +87,24 @@ void asoc_simple_parse_convert(struct device_node *np,
snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-sample-format");
of_property_read_string(np, prop, &data->convert_sample_format);
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
+EXPORT_SYMBOL_GPL(simple_util_parse_convert);
/**
- * asoc_simple_is_convert_required() - Query if HW param conversion was requested
+ * simple_util_is_convert_required() - Query if HW param conversion was requested
* @data: Link data.
*
* Returns true if any HW param conversion was requested for this DAI link with
* any "convert-xxx" properties.
*/
-bool asoc_simple_is_convert_required(const struct asoc_simple_data *data)
+bool simple_util_is_convert_required(const struct simple_util_data *data)
{
return data->convert_rate ||
data->convert_channels ||
data->convert_sample_format;
}
-EXPORT_SYMBOL_GPL(asoc_simple_is_convert_required);
+EXPORT_SYMBOL_GPL(simple_util_is_convert_required);
-int asoc_simple_parse_daifmt(struct device *dev,
+int simple_util_parse_daifmt(struct device *dev,
struct device_node *node,
struct device_node *codec,
char *prefix,
@@ -113,35 +138,44 @@ int asoc_simple_parse_daifmt(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
+EXPORT_SYMBOL_GPL(simple_util_parse_daifmt);
-int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np,
- struct asoc_simple_dai *dai)
+int simple_util_parse_tdm_width_map(struct simple_util_priv *priv, struct device_node *np,
+ struct simple_util_dai *dai)
{
- u32 *array_values, *p;
+ 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 */
- array_values = 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);
- goto out;
+ goto end;
}
p = array_values;
@@ -153,17 +187,16 @@ int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np,
dai->n_tdm_widths = i;
ret = 0;
-out:
- kfree(array_values);
-
- return ret;
+end:
+ return simple_ret(priv, ret);
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_tdm_width_map);
+EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map);
-int asoc_simple_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;
@@ -179,13 +212,14 @@ int asoc_simple_set_dailink_name(struct device *dev,
dai_link->stream_name = name;
}
- return ret;
+ return simple_ret(priv, ret);
}
-EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
+EXPORT_SYMBOL_GPL(simple_util_set_dailink_name);
-int asoc_simple_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)
@@ -199,17 +233,17 @@ int asoc_simple_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(asoc_simple_parse_card_name);
+EXPORT_SYMBOL_GPL(simple_util_parse_card_name);
-static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
+static int simple_clk_enable(struct simple_util_dai *dai)
{
if (dai)
return clk_prepare_enable(dai->clk);
@@ -217,15 +251,15 @@ static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
return 0;
}
-static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
+static void simple_clk_disable(struct simple_util_dai *dai)
{
if (dai)
clk_disable_unprepare(dai->clk);
}
-int asoc_simple_parse_clk(struct device *dev,
+int simple_util_parse_clk(struct device *dev,
struct device_node *node,
- struct asoc_simple_dai *simple_dai,
+ struct simple_util_dai *simple_dai,
struct snd_soc_dai_link_component *dlc)
{
struct clk *clk;
@@ -258,10 +292,10 @@ int asoc_simple_parse_clk(struct device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
+EXPORT_SYMBOL_GPL(simple_util_parse_clk);
-static int asoc_simple_check_fixed_sysclk(struct device *dev,
- struct asoc_simple_dai *dai,
+static int simple_check_fixed_sysclk(struct device *dev,
+ struct simple_util_dai *dai,
unsigned int *fixed_sysclk)
{
if (dai->clk_fixed) {
@@ -276,30 +310,30 @@ static int asoc_simple_check_fixed_sysclk(struct device *dev,
return 0;
}
-int asoc_simple_startup(struct snd_pcm_substream *substream)
+int simple_util_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
- struct asoc_simple_dai *dai;
+ 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 = runtime_simple_priv_to_props(priv, rtd);
+ struct simple_util_dai *dai;
unsigned int fixed_sysclk = 0;
int i1, i2, i;
int ret;
for_each_prop_dai_cpu(props, i1, dai) {
- ret = asoc_simple_clk_enable(dai);
+ ret = simple_clk_enable(dai);
if (ret)
goto cpu_err;
- ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
+ ret = simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
if (ret)
goto cpu_err;
}
for_each_prop_dai_codec(props, i2, dai) {
- ret = asoc_simple_clk_enable(dai);
+ ret = simple_clk_enable(dai);
if (ret)
goto codec_err;
- ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
+ ret = simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
if (ret)
goto codec_err;
}
@@ -310,11 +344,12 @@ int asoc_simple_startup(struct snd_pcm_substream *substream)
if (fixed_sysclk % props->mclk_fs) {
dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n",
fixed_sysclk, props->mclk_fs);
- return -EINVAL;
+ ret = -EINVAL;
+ goto codec_err;
}
ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
fixed_rate, fixed_rate);
- if (ret)
+ if (ret < 0)
goto codec_err;
}
@@ -324,57 +359,59 @@ codec_err:
for_each_prop_dai_codec(props, i, dai) {
if (i >= i2)
break;
- asoc_simple_clk_disable(dai);
+ simple_clk_disable(dai);
}
cpu_err:
for_each_prop_dai_cpu(props, i, dai) {
if (i >= i1)
break;
- asoc_simple_clk_disable(dai);
+ simple_clk_disable(dai);
}
- return ret;
+
+ return simple_ret(priv, ret);
}
-EXPORT_SYMBOL_GPL(asoc_simple_startup);
+EXPORT_SYMBOL_GPL(simple_util_startup);
-void asoc_simple_shutdown(struct snd_pcm_substream *substream)
+void simple_util_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
- struct asoc_simple_dai *dai;
+ 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 = runtime_simple_priv_to_props(priv, rtd);
+ struct simple_util_dai *dai;
int i;
for_each_prop_dai_cpu(props, i, dai) {
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, i);
+ 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);
- asoc_simple_clk_disable(dai);
+ simple_clk_disable(dai);
}
for_each_prop_dai_codec(props, i, dai) {
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i);
+ 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);
- asoc_simple_clk_disable(dai);
+ simple_clk_disable(dai);
}
}
-EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
+EXPORT_SYMBOL_GPL(simple_util_shutdown);
-static int asoc_simple_set_clk_rate(struct device *dev,
- struct asoc_simple_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)
@@ -383,12 +420,15 @@ static int asoc_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 asoc_simple_set_tdm(struct snd_soc_dai *dai,
- struct asoc_simple_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;
@@ -416,22 +456,18 @@ static int asoc_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 asoc_simple_hw_params(struct snd_pcm_substream *substream,
+int simple_util_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct asoc_simple_dai *pdai;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct simple_util_dai *pdai;
struct snd_soc_dai *sdai;
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
unsigned int mclk, mclk_fs = 0;
int i, ret;
@@ -443,15 +479,15 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream,
mclk = params_rate(params) * mclk_fs;
for_each_prop_dai_codec(props, i, pdai) {
- ret = asoc_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 = asoc_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
@@ -462,46 +498,49 @@ int asoc_simple_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 = asoc_rtd_to_codec(rtd, i);
- ret = asoc_simple_set_tdm(sdai, pdai, params);
+ sdai = snd_soc_rtd_to_codec(rtd, i);
+ ret = simple_set_tdm(priv, sdai, pdai, params);
if (ret < 0)
- return ret;
+ goto end;
}
for_each_prop_dai_cpu(props, i, pdai) {
- sdai = asoc_rtd_to_cpu(rtd, i);
- ret = asoc_simple_set_tdm(sdai, pdai, params);
+ sdai = snd_soc_rtd_to_cpu(rtd, i);
+ 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(asoc_simple_hw_params);
+EXPORT_SYMBOL_GPL(simple_util_hw_params);
-int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
- struct asoc_simple_data *data = &dai_props->adata;
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ 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);
@@ -514,14 +553,14 @@ int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
channels->max = data->convert_channels;
if (data->convert_sample_format)
- asoc_simple_fixup_sample_fmt(data, params);
+ simple_fixup_sample_fmt(data, params);
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
+EXPORT_SYMBOL_GPL(simple_util_be_hw_params_fixup);
-static int asoc_simple_init_dai(struct snd_soc_dai *dai,
- struct asoc_simple_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;
@@ -533,7 +572,7 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
simple_dai->clk_direction);
if (ret && ret != -ENOTSUPP) {
dev_err(dai->dev, "simple-card: set_sysclk error\n");
- return ret;
+ goto end;
}
}
@@ -545,20 +584,22 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
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 asoc_simple_component_is_codec(struct snd_soc_component *component)
+static inline int simple_component_is_codec(struct snd_soc_component *component)
{
return component->driver->endianness;
}
-static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
- struct simple_dai_props *dai_props)
+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;
struct snd_soc_component *component;
@@ -576,7 +617,7 @@ static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
/* Only Codecs */
for_each_rtd_components(rtd, i, component) {
- if (!asoc_simple_component_is_codec(component))
+ if (!simple_component_is_codec(component))
return 0;
}
@@ -589,12 +630,13 @@ static int asoc_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;
@@ -606,36 +648,36 @@ static int asoc_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 asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
- struct asoc_simple_dai *dai;
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ 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 = asoc_simple_init_dai(asoc_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 = asoc_simple_init_dai(asoc_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 = asoc_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(asoc_simple_dai_init);
+EXPORT_SYMBOL_GPL(simple_util_dai_init);
-void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
+void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
struct snd_soc_dai_link_component *cpus)
{
/*
@@ -649,11 +691,11 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo
* simple-card.c :: simple_count_noml()
*/
if (!platforms->of_node)
- platforms->of_node = cpus->of_node;
+ snd_soc_dlc_use_cpu_as_platform(platforms, cpus);
}
-EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
+EXPORT_SYMBOL_GPL(simple_util_canonicalize_platform);
-void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
+void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links)
{
/*
@@ -668,9 +710,9 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
if (is_single_links)
cpus->dai_name = NULL;
}
-EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
+EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu);
-void asoc_simple_clean_reference(struct snd_soc_card *card)
+void simple_util_clean_reference(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_dai_link_component *cpu;
@@ -684,9 +726,9 @@ void asoc_simple_clean_reference(struct snd_soc_card *card)
of_node_put(codec->of_node);
}
}
-EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
+EXPORT_SYMBOL_GPL(simple_util_clean_reference);
-int asoc_simple_parse_routing(struct snd_soc_card *card,
+int simple_util_parse_routing(struct snd_soc_card *card,
char *prefix)
{
struct device_node *node = card->dev->of_node;
@@ -697,14 +739,14 @@ int asoc_simple_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);
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
+EXPORT_SYMBOL_GPL(simple_util_parse_routing);
-int asoc_simple_parse_widgets(struct snd_soc_card *card,
+int simple_util_parse_widgets(struct snd_soc_card *card,
char *prefix)
{
struct device_node *node = card->dev->of_node;
@@ -715,15 +757,15 @@ int asoc_simple_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 */
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
+EXPORT_SYMBOL_GPL(simple_util_parse_widgets);
-int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
+int simple_util_parse_pin_switches(struct snd_soc_card *card,
char *prefix)
{
char prop[128];
@@ -735,10 +777,10 @@ int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
return snd_soc_of_parse_pin_switches(card, prop);
}
-EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
+EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches);
-int asoc_simple_init_jack(struct snd_soc_card *card,
- struct asoc_simple_jack *sjack,
+int simple_util_init_jack(struct snd_soc_card *card,
+ struct simple_util_jack *sjack,
int is_hp, char *prefix,
char *pin)
{
@@ -753,8 +795,6 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
if (!prefix)
prefix = "";
- sjack->gpio.gpio = -ENOENT;
-
if (is_hp) {
snprintf(prop, sizeof(prop), "%shp-det", prefix);
pin_name = pin ? pin : "Headphones";
@@ -793,9 +833,9 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
+EXPORT_SYMBOL_GPL(simple_util_init_jack);
-int asoc_simple_init_aux_jacks(struct asoc_simple_priv *priv, char *prefix)
+int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
struct snd_soc_component *component;
@@ -818,7 +858,7 @@ int asoc_simple_init_aux_jacks(struct asoc_simple_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];
@@ -842,16 +882,20 @@ int asoc_simple_init_aux_jacks(struct asoc_simple_priv *priv, char *prefix)
}
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_init_aux_jacks);
+EXPORT_SYMBOL_GPL(simple_util_init_aux_jacks);
+
+static struct simple_util_dai dummy_util_dais = {
+ .name = "dummy_util_dais",
+};
-int asoc_simple_init_priv(struct asoc_simple_priv *priv,
+int simple_util_init_priv(struct simple_util_priv *priv,
struct link_info *li)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
- struct asoc_simple_dai *dais;
+ struct simple_util_dai *dais;
struct snd_soc_dai_link_component *dlcs;
struct snd_soc_codec_conf *cconf = NULL;
int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
@@ -912,9 +956,10 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
dais += li->num[i].cpus;
} else {
/* DPCM Be's CPU = dummy */
- dai_link[i].cpus = &asoc_dummy_dlc;
+ dai_link[i].cpus = &snd_soc_dummy_dlc;
dai_props[i].num.cpus =
dai_link[i].num_cpus = 1;
+ dai_props[i].cpu_dai = &dummy_util_dais;
}
if (li->num[i].codecs) {
@@ -934,9 +979,10 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
}
} else {
/* DPCM Fe's Codec = dummy */
- dai_link[i].codecs = &asoc_dummy_dlc;
+ dai_link[i].codecs = &snd_soc_dummy_dlc;
dai_props[i].num.codecs =
dai_link[i].num_codecs = 1;
+ dai_props[i].codec_dai = &dummy_util_dais;
}
if (li->num[i].platforms) {
@@ -956,67 +1002,54 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
return 0;
}
-EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
+EXPORT_SYMBOL_GPL(simple_util_init_priv);
-int asoc_simple_remove(struct platform_device *pdev)
+void simple_util_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- asoc_simple_clean_reference(card);
-
- return 0;
+ simple_util_clean_reference(card);
}
-EXPORT_SYMBOL_GPL(asoc_simple_remove);
+EXPORT_SYMBOL_GPL(simple_util_remove);
-int asoc_graph_card_probe(struct snd_soc_card *card)
+int graph_util_card_probe(struct snd_soc_card *card)
{
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
int ret;
- ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
+ ret = simple_util_init_hp(card, &priv->hp_jack, NULL);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
- if (ret < 0)
- return ret;
-
- return 0;
+ ret = simple_util_init_mic(card, &priv->mic_jack, NULL);
+end:
+ return simple_ret(priv, ret);
}
-EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
+EXPORT_SYMBOL_GPL(graph_util_card_probe);
-int asoc_graph_is_ports0(struct device_node *np)
+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;
+ 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");
- of_node_put(port);
- of_node_put(ports);
- of_node_put(ports0);
- of_node_put(top);
-
- return ret;
+ return ports0 == ports;
}
-EXPORT_SYMBOL_GPL(asoc_graph_is_ports0);
+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;
@@ -1035,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
@@ -1052,26 +1085,27 @@ 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 asoc_graph_parse_dai(struct device_node *ep,
- struct snd_soc_dai_link_component *dlc,
- int *is_single_link)
+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;
int ret;
if (!ep)
@@ -1079,6 +1113,26 @@ int asoc_graph_parse_dai(struct device_node *ep,
node = of_graph_get_port_parent(ep);
+ /*
+ * Try to find from DAI node
+ */
+ args.np = ep;
+ dai = snd_soc_get_dai_via_args(&args);
+ if (dai) {
+ const char *dai_name = snd_soc_dai_name_get(dai);
+ const struct of_phandle_args *dai_args = snd_soc_copy_dai_args(dev, &args);
+
+ ret = -ENOMEM;
+ if (!dai_args)
+ goto err;
+
+ dlc->of_node = node;
+ dlc->dai_name = dai_name;
+ dlc->dai_args = dai_args;
+
+ goto parse_dai_end;
+ }
+
/* Get dai->name */
args.np = node;
args.args[0] = graph_get_dai_id(ep);
@@ -1103,20 +1157,104 @@ int asoc_graph_parse_dai(struct device_node *ep,
* 2) user need to rebind Sound Card everytime
* if he unbinded CPU or Codec.
*/
- ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
- if (ret < 0) {
+ ret = snd_soc_get_dlc(&args, dlc);
+ if (ret < 0)
+ goto err;
+
+parse_dai_end:
+ if (is_single_link)
+ *is_single_link = of_graph_get_endpoint_count(node) == 1;
+ ret = 0;
+err:
+ if (ret < 0)
of_node_put(node);
- return ret;
+
+ return simple_ret(priv, ret);
+}
+EXPORT_SYMBOL_GPL(graph_util_parse_dai);
+
+void graph_util_parse_link_direction(struct device_node *np,
+ bool *playback_only, bool *capture_only)
+{
+ bool is_playback_only = of_property_read_bool(np, "playback-only");
+ bool is_capture_only = of_property_read_bool(np, "capture-only");
+
+ if (playback_only)
+ *playback_only = is_playback_only;
+ if (capture_only)
+ *capture_only = is_capture_only;
+}
+EXPORT_SYMBOL_GPL(graph_util_parse_link_direction);
+
+static enum snd_soc_trigger_order
+__graph_util_parse_trigger_order(struct simple_util_priv *priv,
+ struct device_node *np,
+ const char *prop)
+{
+ u32 val[SND_SOC_TRIGGER_SIZE];
+ int ret;
+
+ ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE);
+ if (ret == 0) {
+ struct device *dev = simple_priv_to_dev(priv);
+ u32 order = (val[0] << 8) +
+ (val[1] << 4) +
+ (val[2]);
+
+ switch (order) {
+ case (SND_SOC_TRIGGER_LINK << 8) +
+ (SND_SOC_TRIGGER_COMPONENT << 4) +
+ (SND_SOC_TRIGGER_DAI):
+ return SND_SOC_TRIGGER_ORDER_DEFAULT;
+
+ case (SND_SOC_TRIGGER_LINK << 8) +
+ (SND_SOC_TRIGGER_DAI << 4) +
+ (SND_SOC_TRIGGER_COMPONENT):
+ return SND_SOC_TRIGGER_ORDER_LDC;
+
+ default:
+ dev_err(dev, "unsupported trigger order [0x%x]\n", order);
+ }
}
- dlc->of_node = node;
+ /* SND_SOC_TRIGGER_ORDER_MAX means error */
+ return SND_SOC_TRIGGER_ORDER_MAX;
+}
- if (is_single_link)
- *is_single_link = of_graph_get_endpoint_count(node) == 1;
+void graph_util_parse_trigger_order(struct simple_util_priv *priv,
+ struct device_node *np,
+ enum snd_soc_trigger_order *trigger_start,
+ enum snd_soc_trigger_order *trigger_stop)
+{
+ static enum snd_soc_trigger_order order;
- return 0;
+ /*
+ * We can use it like below
+ *
+ * #include <dt-bindings/sound/audio-graph.h>
+ *
+ * link-trigger-order = <SND_SOC_TRIGGER_LINK
+ * SND_SOC_TRIGGER_COMPONENT
+ * SND_SOC_TRIGGER_DAI>;
+ */
+
+ order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order");
+ if (order < SND_SOC_TRIGGER_ORDER_MAX) {
+ *trigger_start = order;
+ *trigger_stop = order;
+ }
+
+ order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start");
+ if (order < SND_SOC_TRIGGER_ORDER_MAX)
+ *trigger_start = order;
+
+ order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop");
+ if (order < SND_SOC_TRIGGER_ORDER_MAX)
+ *trigger_stop = order;
+
+ return;
}
-EXPORT_SYMBOL_GPL(asoc_graph_parse_dai);
+EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order);
/* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 6f044cc8357e..5af6d1b308f2 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -5,11 +5,12 @@
// Copyright (C) 2012 Renesas Solutions Corp.
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <sound/simple_card.h>
@@ -23,13 +24,21 @@
#define PREFIX "simple-audio-card,"
static const struct snd_soc_ops simple_ops = {
- .startup = asoc_simple_startup,
- .shutdown = asoc_simple_shutdown,
- .hw_params = asoc_simple_hw_params,
+ .startup = simple_util_startup,
+ .shutdown = simple_util_shutdown,
+ .hw_params = simple_util_hw_params,
};
-static int asoc_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 asoc_simple_parse_platform(struct device_node *node,
*/
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,14 @@ static int asoc_simple_parse_platform(struct device_node *node,
return 0;
}
-static int asoc_simple_parse_dai(struct device_node *node,
- struct snd_soc_dai_link_component *dlc,
- int *is_single_link)
+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;
if (!node)
@@ -68,7 +80,21 @@ static int asoc_simple_parse_dai(struct device_node *node,
*/
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)
+ goto end;
+
+ goto parse_dai_end;
+ }
/*
* FIXME
@@ -89,112 +115,120 @@ static int asoc_simple_parse_dai(struct device_node *node,
* 2) user need to rebind Sound Card everytime
* if he unbinded CPU or Codec.
*/
- ret = snd_soc_of_get_dai_name(node, &dlc->dai_name);
+ ret = snd_soc_get_dlc(&args, dlc);
if (ret < 0)
- return ret;
-
- dlc->of_node = args.np;
+ 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,
struct device_node *np,
- struct asoc_simple_data *adata)
+ 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);
- asoc_simple_parse_convert(top, PREFIX, adata);
- asoc_simple_parse_convert(node, PREFIX, adata);
- asoc_simple_parse_convert(node, NULL, adata);
- asoc_simple_parse_convert(np, NULL, adata);
-
- of_node_put(node);
+ 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);
}
-static void simple_parse_mclk_fs(struct device_node *top,
- struct device_node *np,
- struct simple_dai_props *props,
- char *prefix)
-{
- struct device_node *node = of_get_parent(np);
- char prop[128];
-
- snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
- of_property_read_u32(top, prop, &props->mclk_fs);
-
- snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
- of_property_read_u32(node, prop, &props->mclk_fs);
- of_property_read_u32(np, prop, &props->mclk_fs);
-
- of_node_put(node);
-}
-
-static int simple_parse_node(struct asoc_simple_priv *priv,
+static int simple_parse_node(struct simple_util_priv *priv,
struct device_node *np,
struct link_info *li,
char *prefix,
int *cpu)
{
struct device *dev = simple_priv_to_dev(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 snd_soc_dai_link_component *dlc;
- struct asoc_simple_dai *dai;
+ struct simple_util_dai *dai;
int ret;
if (cpu) {
- dlc = asoc_link_to_cpu(dai_link, 0);
+ dlc = snd_soc_link_to_cpu(dai_link, 0);
dai = simple_props_to_dai_cpu(dai_props, 0);
} else {
- dlc = asoc_link_to_codec(dai_link, 0);
+ dlc = snd_soc_link_to_codec(dai_link, 0);
dai = simple_props_to_dai_codec(dai_props, 0);
}
- simple_parse_mclk_fs(top, np, dai_props, prefix);
-
- ret = asoc_simple_parse_dai(np, dlc, cpu);
- if (ret)
- return ret;
-
- ret = asoc_simple_parse_clk(dev, np, dai, dlc);
+ ret = simple_parse_dai(priv, np, dlc, cpu);
if (ret)
- return ret;
+ goto end;
- ret = asoc_simple_parse_tdm(np, dai);
+ ret = simple_util_parse_clk(dev, np, dai, dlc);
if (ret)
- return ret;
+ goto end;
- return 0;
+ ret = simple_util_parse_tdm(np, dai);
+end:
+ return simple_ret(priv, ret);
}
-static int simple_link_init(struct asoc_simple_priv *priv,
- struct device_node *node,
+static int simple_link_init(struct simple_util_priv *priv,
+ struct device_node *cpu,
struct device_node *codec,
struct link_info *li,
char *prefix, char *name)
{
struct device *dev = simple_priv_to_dev(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 __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;
int ret;
- ret = asoc_simple_parse_daifmt(dev, node, codec,
+ ret = simple_util_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
- return 0;
-
- dai_link->init = asoc_simple_dai_init;
+ goto end;
+
+ graph_util_parse_link_direction(top, &playback_only, &capture_only);
+ graph_util_parse_link_direction(node, &playback_only, &capture_only);
+ graph_util_parse_link_direction(cpu, &playback_only, &capture_only);
+ graph_util_parse_link_direction(codec, &playback_only, &capture_only);
+
+ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(node, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec, PREFIX "mclk-fs", &dai_props->mclk_fs);
+
+ graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, node, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, cpu, &trigger_start, &trigger_stop);
+ graph_util_parse_trigger_order(priv, codec, &trigger_start, &trigger_stop);
+
+ dai_link->playback_only = playback_only;
+ dai_link->capture_only = capture_only;
+
+ dai_link->trigger_start = trigger_start;
+ dai_link->trigger_stop = trigger_stop;
+
+ dai_link->init = simple_util_dai_init;
dai_link->ops = &simple_ops;
- return asoc_simple_set_dailink_name(dev, dai_link, name);
+ ret = simple_util_set_dailink_name(priv, dai_link, name);
+end:
+ return simple_ret(priv, ret);
}
-static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
+static int simple_dai_link_of_dpcm(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li,
@@ -204,7 +238,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_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;
@@ -216,8 +250,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
prefix = PREFIX;
if (li->cpu) {
- struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
- struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
+ struct snd_soc_dai_link_component *cpus = snd_soc_link_to_cpu(dai_link, 0);
+ struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, 0);
int is_single_links = 0;
/* Codec is dummy */
@@ -232,17 +266,17 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name);
- asoc_simple_canonicalize_cpu(cpus, is_single_links);
- asoc_simple_canonicalize_platform(platforms, cpus);
+ simple_util_canonicalize_cpu(cpus, is_single_links);
+ simple_util_canonicalize_platform(platforms, cpus);
} else {
- struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
+ struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, 0);
struct snd_soc_codec_conf *cconf;
/* CPU is dummy */
/* BE settings */
dai_link->no_pcm = 1;
- dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
+ dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
cconf = simple_props_to_codec_conf(dai_props, 0);
@@ -263,18 +297,15 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
simple_parse_convert(dev, np, &dai_props->adata);
- snd_soc_dai_link_set_capabilities(dai_link);
-
- ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
+ ret = simple_link_init(priv, np, codec, li, prefix, dai_name);
out_put_node:
li->link++;
- of_node_put(node);
- return ret;
+ return simple_ret(priv, ret);
}
-static int simple_dai_link_of(struct asoc_simple_priv *priv,
+static int simple_dai_link_of(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li,
@@ -282,19 +313,17 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
- struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
- struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
- struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
+ struct snd_soc_dai_link_component *cpus = snd_soc_link_to_cpu(dai_link, 0);
+ 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);
@@ -303,7 +332,7 @@ static int simple_dai_link_of(struct asoc_simple_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)
@@ -313,34 +342,31 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
if (ret < 0)
goto dai_link_of_err;
- ret = asoc_simple_parse_platform(plat, platforms);
+ ret = simple_parse_platform(priv, plat, platforms);
if (ret < 0)
goto dai_link_of_err;
snprintf(dai_name, sizeof(dai_name),
"%s-%s", cpus->dai_name, codecs->dai_name);
- asoc_simple_canonicalize_cpu(cpus, single_cpu);
- asoc_simple_canonicalize_platform(platforms, cpus);
+ simple_util_canonicalize_cpu(cpus, single_cpu);
+ simple_util_canonicalize_platform(platforms, cpus);
- ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
+ 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 asoc_simple_priv *priv,
+static int __simple_for_each_link(struct simple_util_priv *priv,
struct link_info *li,
- int (*func_noml)(struct asoc_simple_priv *priv,
+ int (*func_noml)(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li, bool is_top),
- int (*func_dpcm)(struct asoc_simple_priv *priv,
+ int (*func_dpcm)(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li, bool is_top))
@@ -359,33 +385,41 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
is_top = 1;
}
+ struct device_node *add_devs __free(device_node) = of_get_child_by_name(top, PREFIX "additional-devs");
+
/* loop for all dai-link */
do {
- struct asoc_simple_data adata;
- struct device_node *codec;
- struct device_node *plat;
- struct device_node *np;
+ struct simple_util_data adata;
int num = of_get_child_count(node);
+ /* Skip additional-devs node */
+ if (node == add_devs) {
+ node = of_get_next_child(top, node);
+ continue;
+ }
+
/* 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) {
- if (plat == np)
+ for_each_child_of_node_scoped(node, np) {
+ if (plat == np || add_devs == np)
continue;
/*
* It is DPCM
@@ -393,7 +427,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
* or has convert-xxx property
*/
if (dpcm_selectable &&
- (num > 2 || asoc_simple_is_convert_required(&adata))) {
+ (num > 2 || simple_util_is_convert_required(&adata))) {
/*
* np
* |1(CPU)|0(Codec) li->cpu
@@ -414,30 +448,26 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
ret = func_noml(priv, np, codec, li, is_top);
}
- if (ret < 0) {
- of_node_put(codec);
- 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:
+error:
of_node_put(node);
- return ret;
+
+ return simple_ret(priv, ret);
}
-static int simple_for_each_link(struct asoc_simple_priv *priv,
+static int simple_for_each_link(struct simple_util_priv *priv,
struct link_info *li,
- int (*func_noml)(struct asoc_simple_priv *priv,
+ int (*func_noml)(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li, bool is_top),
- int (*func_dpcm)(struct asoc_simple_priv *priv,
+ int (*func_dpcm)(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li, bool is_top))
@@ -461,25 +491,50 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
break;
}
- return ret;
+ return simple_ret(priv, ret);
+}
+
+static void simple_depopulate_aux(void *data)
+{
+ struct simple_util_priv *priv = data;
+
+ of_platform_depopulate(simple_priv_to_dev(priv));
+}
+
+static int simple_populate_aux(struct simple_util_priv *priv)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *node __free(device_node) = of_get_child_by_name(dev->of_node, PREFIX "additional-devs");
+ int ret;
+
+ if (!node)
+ return 0;
+
+ ret = of_platform_populate(node, NULL, NULL, dev);
+ if (ret)
+ goto end;
+
+ ret = devm_add_action_or_reset(dev, simple_depopulate_aux, priv);
+end:
+ return simple_ret(priv, ret);
}
-static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
+static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
int ret;
- ret = asoc_simple_parse_widgets(card, PREFIX);
+ ret = simple_util_parse_widgets(card, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_parse_routing(card, PREFIX);
+ ret = simple_util_parse_routing(card, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_parse_pin_switches(card, PREFIX);
+ 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));
@@ -487,28 +542,30 @@ static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
simple_dai_link_of,
simple_dai_link_of_dpcm);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_parse_card_name(card, PREFIX);
+ ret = simple_util_parse_card_name(priv, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
- ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
+ ret = simple_populate_aux(priv);
+ if (ret < 0)
+ goto end;
- return ret;
+ ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
+end:
+ return simple_ret(priv, ret);
}
-static int simple_count_noml(struct asoc_simple_priv *priv,
+static int simple_count_noml(struct simple_util_priv *priv,
struct device_node *np,
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
@@ -522,7 +579,7 @@ static int simple_count_noml(struct asoc_simple_priv *priv,
* ignored by snd_soc_rtd_add_component().
*
* see
- * simple-card-utils.c :: asoc_simple_canonicalize_platform()
+ * simple-card-utils.c :: simple_util_canonicalize_platform()
*/
li->num[li->link].cpus = 1;
li->num[li->link].platforms = 1;
@@ -530,21 +587,20 @@ static int simple_count_noml(struct asoc_simple_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 asoc_simple_priv *priv,
+static int simple_count_dpcm(struct simple_util_priv *priv,
struct device_node *np,
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) {
/*
@@ -561,11 +617,12 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv,
li->link++; /* dummy-Codec */
}
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
-static int simple_get_dais_count(struct asoc_simple_priv *priv,
+static int simple_get_dais_count(struct simple_util_priv *priv,
struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
@@ -633,31 +690,28 @@ static int simple_get_dais_count(struct asoc_simple_priv *priv,
static int simple_soc_probe(struct snd_soc_card *card)
{
- struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
int ret;
- ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
+ ret = simple_util_init_hp(card, &priv->hp_jack, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
- ret = asoc_simple_init_aux_jacks(priv, PREFIX);
+ ret = simple_util_init_mic(card, &priv->mic_jack, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
- return 0;
+ ret = simple_util_init_aux_jacks(priv, PREFIX);
+end:
+ return simple_ret(priv, ret);
}
-static int asoc_simple_probe(struct platform_device *pdev)
+static int simple_probe(struct platform_device *pdev)
{
- struct asoc_simple_priv *priv;
+ struct simple_util_priv *priv;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
- struct link_info *li;
int ret;
/* Allocate the private data and the DAI link array */
@@ -671,20 +725,22 @@ static int asoc_simple_probe(struct platform_device *pdev)
card->probe = simple_soc_probe;
card->driver_name = "simple-card";
- li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+ 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 = asoc_simple_init_priv(priv, li);
+ ret = simple_util_init_priv(priv, li);
if (ret < 0)
- return ret;
+ goto end;
if (np && of_device_is_available(np)) {
@@ -695,17 +751,19 @@ static int asoc_simple_probe(struct platform_device *pdev)
}
} else {
- struct asoc_simple_card_info *cinfo;
+ struct simple_util_info *cinfo;
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platform;
struct snd_soc_dai_link *dai_link = priv->dai_link;
struct simple_dai_props *dai_props = priv->dai_props;
+ ret = -EINVAL;
+
cinfo = dev->platform_data;
if (!cinfo) {
dev_err(dev, "no info for asoc-simple-card\n");
- return -EINVAL;
+ goto err;
}
if (!cinfo->name ||
@@ -713,8 +771,8 @@ static int asoc_simple_probe(struct platform_device *pdev)
!cinfo->codec ||
!cinfo->platform ||
!cinfo->cpu_dai.name) {
- dev_err(dev, "insufficient asoc_simple_card_info settings\n");
- return -EINVAL;
+ dev_err(dev, "insufficient simple_util_info settings\n");
+ goto err;
}
cpus = dai_link->cpus;
@@ -731,7 +789,7 @@ static int asoc_simple_probe(struct platform_device *pdev)
dai_link->name = cinfo->name;
dai_link->stream_name = cinfo->name;
dai_link->dai_fmt = cinfo->daifmt;
- dai_link->init = asoc_simple_dai_init;
+ dai_link->init = simple_util_dai_init;
memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
sizeof(*dai_props->cpu_dai));
memcpy(dai_props->codec_dai, &cinfo->codec_dai,
@@ -740,18 +798,17 @@ static int asoc_simple_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, priv);
- asoc_simple_debug_info(priv);
+ simple_util_debug_info(priv);
ret = devm_snd_soc_register_card(dev, card);
if (ret < 0)
goto err;
- devm_kfree(dev, li);
return 0;
err:
- asoc_simple_clean_reference(card);
-
- return ret;
+ simple_util_clean_reference(card);
+end:
+ return dev_err_probe(dev, ret, "parse error\n");
}
static const struct of_device_id simple_of_match[] = {
@@ -762,17 +819,17 @@ static const struct of_device_id simple_of_match[] = {
};
MODULE_DEVICE_TABLE(of, simple_of_match);
-static struct platform_driver asoc_simple_card = {
+static struct platform_driver simple_card = {
.driver = {
.name = "asoc-simple-card",
.pm = &snd_soc_pm_ops,
.of_match_table = simple_of_match,
},
- .probe = asoc_simple_probe,
- .remove = asoc_simple_remove,
+ .probe = simple_probe,
+ .remove = simple_util_remove,
};
-module_platform_driver(asoc_simple_card);
+module_platform_driver(simple_card);
MODULE_ALIAS("platform:asoc-simple-card");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c
index e10e5bf28432..2e49066dedd4 100644
--- a/sound/soc/generic/test-component.c
+++ b/sound/soc/generic/test-component.c
@@ -6,7 +6,7 @@
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
#include <linux/slab.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/module.h>
#include <linux/workqueue.h>
@@ -140,6 +140,15 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int test_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ dev_info(dai->dev, "set tdm slot: tx_mask=0x%08X, rx_mask=0x%08X, slots=%d, slot_width=%d\n",
+ tx_mask, rx_mask, slots, slot_width);
+ return 0;
+}
+
static int test_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
mile_stone(dai);
@@ -181,15 +190,7 @@ static int test_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct
return 0;
}
-static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
-{
- mile_stone(dai);
-
- return 0;
-}
-
-static u64 test_dai_formats =
+static const u64 test_dai_formats =
/*
* Select below from Sound Card, not auto
* SND_SOC_POSSIBLE_DAIFMT_BP_FP
@@ -211,6 +212,7 @@ static u64 test_dai_formats =
static const struct snd_soc_dai_ops test_ops = {
.set_fmt = test_dai_set_fmt,
+ .set_tdm_slot = test_dai_set_tdm_slot,
.startup = test_dai_startup,
.shutdown = test_dai_shutdown,
.auto_selectable_formats = &test_dai_formats,
@@ -222,18 +224,18 @@ static const struct snd_soc_dai_ops test_verbose_ops = {
.set_pll = test_dai_set_pll,
.set_clkdiv = test_dai_set_clkdiv,
.set_fmt = test_dai_set_fmt,
+ .set_tdm_slot = test_dai_set_tdm_slot,
.mute_stream = test_dai_mute_stream,
.startup = test_dai_startup,
.shutdown = test_dai_shutdown,
.hw_params = test_dai_hw_params,
.hw_free = test_dai_hw_free,
.trigger = test_dai_trigger,
- .bespoke_trigger = test_dai_bespoke_trigger,
.auto_selectable_formats = &test_dai_formats,
.num_auto_selectable_formats = 1,
};
-#define STUB_RATES SNDRV_PCM_RATE_8000_384000
+#define STUB_RATES SNDRV_PCM_RATE_CONTINUOUS
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
@@ -352,7 +354,7 @@ static const struct snd_pcm_hardware test_component_hardware = {
static int test_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
mile_stone(component);
@@ -530,7 +532,6 @@ static int test_driver_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
- struct device_node *ep;
const struct test_adata *adata = of_device_get_match_data(&pdev->dev);
struct snd_soc_component_driver *cdriv;
struct snd_soc_dai_driver *ddriv;
@@ -546,8 +547,8 @@ static int test_driver_probe(struct platform_device *pdev)
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
cdriv = devm_kzalloc(dev, sizeof(*cdriv), GFP_KERNEL);
- ddriv = devm_kzalloc(dev, sizeof(*ddriv) * num, GFP_KERNEL);
- dname = devm_kzalloc(dev, sizeof(*dname) * num, GFP_KERNEL);
+ ddriv = devm_kcalloc(dev, num, sizeof(*ddriv), GFP_KERNEL);
+ dname = devm_kcalloc(dev, num, sizeof(*dname), GFP_KERNEL);
if (!priv || !cdriv || !ddriv || !dname || !adata)
return -EINVAL;
@@ -600,7 +601,7 @@ static int test_driver_probe(struct platform_device *pdev)
}
i = 0;
- for_each_endpoint_of_node(node, ep) {
+ for_each_of_graph_port(node, port) {
snprintf(dname[i].name, TEST_NAME_LEN, "%s.%d", node->name, i);
ddriv[i].name = dname[i].name;
@@ -646,7 +647,7 @@ static struct platform_driver test_driver = {
.of_match_table = test_of_match,
},
.probe = test_driver_probe,
- .remove_new = test_driver_remove,
+ .remove = test_driver_remove,
};
module_platform_driver(test_driver);
diff --git a/sound/soc/google/Kconfig b/sound/soc/google/Kconfig
index 7603782fb060..6005653170a8 100644
--- a/sound/soc/google/Kconfig
+++ b/sound/soc/google/Kconfig
@@ -1,6 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Google"
config SND_SOC_CHV3_I2S
tristate "Google Chameleon v3 I2S device"
help
Enable support for the Google Chameleon v3 I2S device.
+
+endmenu
diff --git a/sound/soc/google/chv3-i2s.c b/sound/soc/google/chv3-i2s.c
index 0f6513444906..0ff24653d49f 100644
--- a/sound/soc/google/chv3-i2s.c
+++ b/sound/soc/google/chv3-i2s.c
@@ -131,8 +131,8 @@ static irqreturn_t chv3_i2s_isr(int irq, void *data)
static int chv3_dma_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
int res;
snd_soc_set_runtime_hwparams(substream, &chv3_dma_hw);
@@ -152,8 +152,8 @@ static int chv3_dma_open(struct snd_soc_component *component,
static int chv3_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
chv3_i2s_wr(i2s, I2S_RX_ENABLE, 0);
@@ -166,7 +166,7 @@ static int chv3_dma_close(struct snd_soc_component *component,
static int chv3_dma_pcm_construct(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
struct snd_pcm_substream *substream;
int res;
@@ -200,8 +200,8 @@ static int chv3_dma_hw_params(struct snd_soc_component *component,
static int chv3_dma_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
unsigned int buffer_bytes, period_bytes, period_size;
buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
@@ -229,8 +229,8 @@ static int chv3_dma_prepare(struct snd_soc_component *component,
static snd_pcm_uframes_t chv3_dma_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
u32 frame_bytes, buffer_bytes;
u32 idx_bytes;
@@ -252,8 +252,8 @@ static int chv3_dma_ack(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
unsigned int bytes, idx;
bytes = frames_to_bytes(runtime, runtime->control->appl_ptr);
@@ -322,6 +322,7 @@ static const struct of_device_id chv3_i2s_of_match[] = {
{ .compatible = "google,chv3-i2s" },
{},
};
+MODULE_DEVICE_TABLE(of, chv3_i2s_of_match);
static struct platform_driver chv3_i2s_driver = {
.probe = chv3_i2s_probe,
diff --git a/sound/soc/hisilicon/Kconfig b/sound/soc/hisilicon/Kconfig
index df8fbd8bb4b0..d95da932f352 100644
--- a/sound/soc/hisilicon/Kconfig
+++ b/sound/soc/hisilicon/Kconfig
@@ -1,6 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Hisilicon"
+
config SND_I2S_HI6210_I2S
tristate "Hisilicon I2S controller"
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Hisilicon I2S
+
+endmenu
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index 27219a9e7d0d..250ae3781d14 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -15,7 +15,6 @@
#include <linux/clk.h>
#include <linux/jiffies.h>
#include <linux/io.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -511,6 +510,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
+ .probe = hi6210_i2s_dai_probe,
.trigger = hi6210_i2s_trigger,
.hw_params = hi6210_i2s_hw_params,
.set_fmt = hi6210_i2s_set_fmt,
@@ -519,7 +519,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
};
static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
- .probe = hi6210_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig
index 568efa606ca4..22b75a8144a1 100644
--- a/sound/soc/img/Kconfig
+++ b/sound/soc/img/Kconfig
@@ -1,12 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
-config SND_SOC_IMG
- bool "Audio support for Imagination Technologies designs"
- help
- Audio support for Imagination Technologies audio hardware
+menu "Imagination Technologies"
+ depends on MIPS || COMPILE_TEST
config SND_SOC_IMG_I2S_IN
tristate "Imagination I2S Input Device Driver"
- depends on SND_SOC_IMG
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for I2S in driver for
@@ -14,7 +11,6 @@ config SND_SOC_IMG_I2S_IN
config SND_SOC_IMG_I2S_OUT
tristate "Imagination I2S Output Device Driver"
- depends on SND_SOC_IMG
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for I2S out driver for
@@ -22,7 +18,6 @@ config SND_SOC_IMG_I2S_OUT
config SND_SOC_IMG_PARALLEL_OUT
tristate "Imagination Parallel Output Device Driver"
- depends on SND_SOC_IMG
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for parallel out driver for
@@ -30,7 +25,6 @@ config SND_SOC_IMG_PARALLEL_OUT
config SND_SOC_IMG_SPDIF_IN
tristate "Imagination SPDIF Input Device Driver"
- depends on SND_SOC_IMG
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for SPDIF input driver for
@@ -38,7 +32,6 @@ config SND_SOC_IMG_SPDIF_IN
config SND_SOC_IMG_SPDIF_OUT
tristate "Imagination SPDIF Output Device Driver"
- depends on SND_SOC_IMG
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for SPDIF out driver for
@@ -47,7 +40,8 @@ config SND_SOC_IMG_SPDIF_OUT
config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC
tristate "Support for Pistachio SoC Internal DAC Driver"
- depends on SND_SOC_IMG
help
Say Y or M if you want to add support for Pistachio internal DAC
driver for Imagination Technologies Pistachio internal DAC device.
+
+endmenu
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index b7ab8467b5cf..98d2ab68883a 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
- .trigger = img_i2s_in_trigger,
- .hw_params = img_i2s_in_hw_params,
- .set_fmt = img_i2s_in_set_fmt
-};
-
static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
{
struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
@@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
+ .probe = img_i2s_in_dai_probe,
+ .trigger = img_i2s_in_trigger,
+ .hw_params = img_i2s_in_hw_params,
+ .set_fmt = img_i2s_in_set_fmt
+};
+
static const struct snd_soc_component_driver img_i2s_in_component = {
.name = "img-i2s-in",
.legacy_dai_naming = 1,
@@ -394,11 +395,11 @@ static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
{
unsigned int i2s_channels = params_channels(params) / 2;
- struct snd_soc_pcm_runtime *rtd = st->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(st);
struct snd_dmaengine_dai_dma_data *dma_data;
int ret;
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), st);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), st);
ret = snd_hwparams_to_dma_slave_config(st, params, sc);
if (ret)
@@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev)
i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
i2s->dma_data.addr_width = 4;
- i2s->dai_driver.probe = img_i2s_in_dai_probe;
i2s->dai_driver.capture.channels_min = 2;
i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
@@ -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,19 +593,18 @@ 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_new = img_i2s_in_dev_remove
+ .remove = img_i2s_in_dev_remove
};
module_platform_driver(img_i2s_in_driver);
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index fe95ddfb8407..aedcf56a5359 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
- .trigger = img_i2s_out_trigger,
- .hw_params = img_i2s_out_hw_params,
- .set_fmt = img_i2s_out_set_fmt
-};
-
static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
{
struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
@@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
+ .probe = img_i2s_out_dai_probe,
+ .trigger = img_i2s_out_trigger,
+ .hw_params = img_i2s_out_hw_params,
+ .set_fmt = img_i2s_out_set_fmt
+};
+
static const struct snd_soc_component_driver img_i2s_out_component = {
.name = "img-i2s-out",
.legacy_dai_naming = 1,
@@ -400,11 +401,11 @@ static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st,
struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
{
unsigned int i2s_channels = params_channels(params) / 2;
- struct snd_soc_pcm_runtime *rtd = st->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(st);
struct snd_dmaengine_dai_dma_data *dma_data;
int ret;
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), st);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), st);
ret = snd_hwparams_to_dma_slave_config(st, params, sc);
if (ret)
@@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev)
i2s->dma_data.addr_width = 4;
i2s->dma_data.maxburst = 4;
- i2s->dai_driver.probe = img_i2s_out_dai_probe;
i2s->dai_driver.playback.channels_min = 2;
i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2;
i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000;
@@ -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,19 +593,18 @@ 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_new = img_i2s_out_dev_remove
+ .remove = img_i2s_out_dev_remove
};
module_platform_driver(img_i2s_out_driver);
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index df1291ee2b3b..86b60e6dab38 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
- .trigger = img_prl_out_trigger,
- .hw_params = img_prl_out_hw_params,
- .set_fmt = img_prl_out_set_fmt
-};
-
static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
{
struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
@@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
+ .probe = img_prl_out_dai_probe,
+ .trigger = img_prl_out_trigger,
+ .hw_params = img_prl_out_hw_params,
+ .set_fmt = img_prl_out_set_fmt
+};
+
static struct snd_soc_dai_driver img_prl_out_dai = {
- .probe = img_prl_out_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -300,18 +300,17 @@ 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_new = img_prl_out_dev_remove
+ .remove = img_prl_out_dev_remove
};
module_platform_driver(img_prl_out_driver);
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
index 558062a1804a..82295e2508fa 100644
--- a/sound/soc/img/img-spdif-in.c
+++ b/sound/soc/img/img-spdif-in.c
@@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
return img_spdif_in_do_clkgen_single(spdif, rate);
}
-static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
- .trigger = img_spdif_in_trigger,
- .hw_params = img_spdif_in_hw_params
-};
-
static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
{
struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
@@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
+ .probe = img_spdif_in_dai_probe,
+ .trigger = img_spdif_in_trigger,
+ .hw_params = img_spdif_in_hw_params
+};
+
static struct snd_soc_dai_driver img_spdif_in_dai = {
- .probe = img_spdif_in_dai_probe,
.capture = {
.channels_min = 2,
.channels_max = 2,
@@ -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,19 +864,18 @@ 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_new = img_spdif_in_dev_remove
+ .remove = img_spdif_in_dev_remove
};
module_platform_driver(img_spdif_in_driver);
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
index b13e128e50d6..52f696219ef4 100644
--- a/sound/soc/img/img-spdif-out.c
+++ b/sound/soc/img/img-spdif-out.c
@@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
- .trigger = img_spdif_out_trigger,
- .hw_params = img_spdif_out_hw_params
-};
-
static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
{
struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
@@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
+ .probe = img_spdif_out_dai_probe,
+ .trigger = img_spdif_out_trigger,
+ .hw_params = img_spdif_out_hw_params
+};
+
static struct snd_soc_dai_driver img_spdif_out_dai = {
- .probe = img_spdif_out_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -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,19 +455,18 @@ 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_new = img_spdif_out_dev_remove
+ .remove = img_spdif_out_dev_remove
};
module_platform_driver(img_spdif_out_driver);
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
index da6251680e41..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,10 +266,10 @@ 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_new = pistachio_internal_dac_remove
+ .remove = pistachio_internal_dac_remove
};
module_platform_driver(pistachio_internal_dac_plat_driver);
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 4b9e498e3303..412555e626b8 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Intel"
+
config SND_SOC_INTEL_SST_TOPLEVEL
bool "Intel ASoC SST drivers"
default y
@@ -15,9 +17,6 @@ config SND_SOC_INTEL_SST_TOPLEVEL
if SND_SOC_INTEL_SST_TOPLEVEL
-config SND_SOC_INTEL_SST
- tristate
-
config SND_SOC_INTEL_CATPT
tristate "Haswell and Broadwell"
depends on ACPI || COMPILE_TEST
@@ -67,126 +66,6 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
Baytrail/Cherrytrail. If you want to enable SOF on
Baytrail/Cherrytrail, you need to deselect this option first.
-config SND_SOC_INTEL_SKYLAKE
- tristate "All Skylake/SST Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKL
- select SND_SOC_INTEL_APL
- select SND_SOC_INTEL_KBL
- select SND_SOC_INTEL_GLK
- select SND_SOC_INTEL_CNL
- select SND_SOC_INTEL_CFL
- help
- This is a backwards-compatible option to select all devices
- supported by the Intel SST/Skylake driver. This option is no
- longer recommended and will be deprecated when the SOF
- driver is introduced. Distributions should explicitly
- select which platform uses this driver.
-
-config SND_SOC_INTEL_SKL
- tristate "Skylake Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel Skylake platform with the DSP enabled
- in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_APL
- tristate "Broxton/ApolloLake Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel Broxton/ApolloLake platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_KBL
- tristate "Kabylake Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel Kabylake platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_GLK
- tristate "GeminiLake Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel GeminiLake platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_CNL
- tristate "CannonLake/WhiskyLake Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel CNL/WHL platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_CFL
- tristate "CoffeeLake Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel CoffeeLake platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_CML_H
- tristate "CometLake-H Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel CometLake-H platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_CML_LP
- tristate "CometLake-LP Platforms"
- depends on PCI && ACPI
- depends on COMMON_CLK
- select SND_SOC_INTEL_SKYLAKE_FAMILY
- help
- If you have a Intel CometLake-LP platform with the DSP
- enabled in the BIOS then enable this option by saying Y or m.
-
-config SND_SOC_INTEL_SKYLAKE_FAMILY
- tristate
- select SND_SOC_INTEL_SKYLAKE_COMMON
-
-if SND_SOC_INTEL_SKYLAKE_FAMILY
-
-config SND_SOC_INTEL_SKYLAKE_SSP_CLK
- tristate
-
-config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
- bool "HDAudio codec support"
- help
- If you have Intel Skylake or Kabylake with HDAudio codec
- and DMIC present then enable this option by saying Y.
-
-config SND_SOC_INTEL_SKYLAKE_COMMON
- tristate
- select SND_HDA_EXT_CORE
- select SND_HDA_DSP_LOADER
- select SND_SOC_TOPOLOGY
- select SND_SOC_INTEL_SST
- select SND_SOC_HDAC_HDA
- select SND_SOC_ACPI_INTEL_MATCH
- select SND_INTEL_DSP_CONFIG
- help
- If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
- GeminiLake or CannonLake platform with the DSP enabled in the BIOS
- then enable this option by saying Y or m.
-
-endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
-
endif ## SND_SOC_INTEL_SST_TOPLEVEL
if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
@@ -194,9 +73,14 @@ if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
config SND_SOC_ACPI_INTEL_MATCH
tristate
select SND_SOC_ACPI if ACPI
+ select SND_SOC_ACPI_INTEL_SDCA_QUIRKS
# this option controls the compilation of ACPI matching tables and
# helpers and is not meant to be selected by the user.
+config SND_SOC_ACPI_INTEL_SDCA_QUIRKS
+ tristate
+ select SND_SOC_SDCA if ACPI
+
endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
config SND_SOC_INTEL_KEEMBAY
@@ -214,6 +98,7 @@ config SND_SOC_INTEL_AVS
depends on X86 || COMPILE_TEST
depends on PCI
depends on COMMON_CLK
+ select ACPI_NHLT if ACPI
select SND_SOC_ACPI if ACPI
select SND_SOC_TOPOLOGY
select SND_SOC_HDA
@@ -232,3 +117,5 @@ source "sound/soc/intel/avs/boards/Kconfig"
# ASoC codec drivers
source "sound/soc/intel/boards/Kconfig"
+
+endmenu
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index d44b2652c707..8ecc7047d700 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -5,7 +5,6 @@ obj-$(CONFIG_SND_SOC) += common/
# Platform Support
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/
obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/
-obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += skylake/
obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/
obj-$(CONFIG_SND_SOC_INTEL_AVS) += avs/
diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile
index c66f03f5d8d6..38e4876025c7 100644
--- a/sound/soc/intel/atom/Makefile
+++ b/sound/soc/intel/atom/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \
+snd-soc-sst-atom-hifi2-platform-y := sst-mfld-platform-pcm.o \
sst-mfld-platform-compress.o \
sst-atom-controls.o
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 38116c758717..3629ceaaac17 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -142,7 +142,7 @@ static int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
if (uinfo->value.enumerated.item > e->max - 1)
uinfo->value.enumerated.item = e->max - 1;
- strcpy(uinfo->value.enumerated.name,
+ strscpy(uinfo->value.enumerated.name,
e->texts[uinfo->value.enumerated.item]);
return 0;
@@ -218,7 +218,7 @@ static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol
static int sst_slot_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
struct sst_data *drv = snd_soc_component_get_drvdata(c);
struct sst_enum *e = (void *)kcontrol->private_value;
int i, ret = 0;
@@ -349,7 +349,7 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int ret = 0;
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
struct sst_algo_control *bc = (void *)kcontrol->private_value;
@@ -470,7 +470,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int ret = 0;
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
struct sst_gain_value *gv = mc->gain_val;
@@ -637,7 +637,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
* inputs as an IPC to the DSP.
*/
for (i = 0; i < w->num_kcontrols; i++) {
- if (dapm_kcontrol_get_value(w->kcontrols[i])) {
+ if (snd_soc_dapm_kcontrol_get_value(w->kcontrols[i])) {
mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
val |= 1 << mc->shift;
}
@@ -1530,8 +1530,7 @@ static int sst_map_modules_to_pipe(struct snd_soc_component *component)
int sst_dsp_init_v2_dpcm(struct snd_soc_component *component)
{
int i, ret = 0;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct sst_data *drv = snd_soc_component_get_drvdata(component);
unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3;
@@ -1544,7 +1543,7 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_component *component)
ARRAY_SIZE(sst_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon,
ARRAY_SIZE(intercon));
- snd_soc_dapm_new_widgets(dapm->card);
+ snd_soc_dapm_new_widgets(component->card);
for (i = 0; i < gains; i++) {
sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT;
diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c
index 89c9c5ad6b21..9dfb0a814b94 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c
@@ -18,6 +18,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/compress_driver.h>
+#include <asm/div64.h>
#include "sst-mfld-platform.h"
/* compress stream operations */
@@ -202,15 +203,16 @@ static int sst_platform_compr_trigger(struct snd_soc_component *component,
static int sst_platform_compr_pointer(struct snd_soc_component *component,
struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct sst_runtime_stream *stream;
+ u64 temp_copied_total = tstamp->copied_total;
- stream = cstream->runtime->private_data;
+ stream = cstream->runtime->private_data;
stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
- tstamp->byte_offset = tstamp->copied_total %
- (u32)cstream->runtime->buffer_size;
- pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+ tstamp->byte_offset =
+ do_div(temp_copied_total, cstream->runtime->buffer_size);
+ pr_debug("calc bytes offset/copied bytes as %u\n", tstamp->byte_offset);
return 0;
}
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index ba4597bdf32e..373d68b4cf88 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -273,7 +273,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
{
struct sst_runtime_stream *stream =
substream->runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret_val;
dev_dbg(rtd->dev, "setting buffer ptr param\n");
@@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = {
};
static const struct snd_soc_dai_ops sst_compr_dai_ops = {
+ .compress_new = snd_soc_new_compress,
.mute_stream = sst_media_digital_mute,
};
@@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
},
{
.name = "compress-cpu-dai",
- .compress_new = snd_soc_new_compress,
.ops = &sst_compr_dai_ops,
.playback = {
.stream_name = "Compress Playback",
@@ -593,7 +593,7 @@ static int sst_soc_trigger(struct snd_soc_component *component,
int ret_val = 0, str_id;
struct sst_runtime_stream *stream;
int status;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
dev_dbg(rtd->dev, "%s called\n", __func__);
if (substream->pcm->internal)
@@ -641,7 +641,7 @@ static snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component,
struct sst_runtime_stream *stream;
int ret_val, status;
struct pcm_stream_info *str_info;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
stream = substream->runtime->private_data;
status = sst_get_stream_status(stream);
@@ -671,7 +671,7 @@ static snd_pcm_sframes_t sst_soc_delay(struct snd_soc_component *component,
static int sst_soc_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_pcm *pcm = rtd->pcm;
if (dai->driver->playback.channels_min ||
@@ -762,7 +762,7 @@ static int sst_soc_prepare(struct device *dev)
/* set the SSPs to idle */
for_each_card_rtds(drv->soc_card, rtd) {
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
if (snd_soc_dai_active(dai)) {
send_ssp_cmd(dai, dai->name, 0);
@@ -783,7 +783,7 @@ static void sst_soc_complete(struct device *dev)
/* restart SSPs */
for_each_card_rtds(drv->soc_card, rtd) {
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
if (snd_soc_dai_active(dai)) {
sst_handle_vb_timer(dai, true);
@@ -812,7 +812,7 @@ static struct platform_driver sst_platform_driver = {
.pm = &sst_platform_pm,
},
.probe = sst_platform_probe,
- .remove_new = sst_platform_remove,
+ .remove = sst_platform_remove,
};
module_platform_driver(sst_platform_driver);
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h
index 8b5777d3229a..a0e33f7f01c5 100644
--- a/sound/soc/intel/atom/sst-mfld-platform.h
+++ b/sound/soc/intel/atom/sst-mfld-platform.h
@@ -105,7 +105,7 @@ struct compress_sst_ops {
int (*stream_pause_release)(struct device *dev, unsigned int str_id);
int (*tstamp)(struct device *dev, unsigned int str_id,
- struct snd_compr_tstamp *tstamp);
+ struct snd_compr_tstamp64 *tstamp);
int (*ack)(struct device *dev, unsigned int str_id,
unsigned long bytes);
int (*close)(struct device *dev, unsigned int str_id);
diff --git a/sound/soc/intel/atom/sst/Makefile b/sound/soc/intel/atom/sst/Makefile
index 5761d30a5f9d..16be0463424d 100644
--- a/sound/soc/intel/atom/sst/Makefile
+++ b/sound/soc/intel/atom/sst/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o
-snd-intel-sst-pci-objs += sst_pci.o
-snd-intel-sst-acpi-objs += sst_acpi.o
+snd-intel-sst-core-y := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o
+snd-intel-sst-pci-y += sst_pci.o
+snd-intel-sst-acpi-y += sst_acpi.o
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += snd-intel-sst-core.o
obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI) += snd-intel-sst-pci.o
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c
index a0d29510d2bc..3c47c8de04b7 100644
--- a/sound/soc/intel/atom/sst/sst.c
+++ b/sound/soc/intel/atom/sst/sst.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/firmware.h>
+#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/async.h>
@@ -63,7 +64,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
header.p.header_high.part.done = 0;
sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full);
- /* write 1 to clear status register */;
+ /* write 1 to clear status register */
isr.part.done_interrupt = 1;
sst_shim_write64(drv->shim, SST_ISRX, isr.full);
spin_unlock(&drv->ipc_spin_lock);
@@ -174,9 +175,9 @@ int sst_driver_ops(struct intel_sst_drv *sst)
{
switch (sst->dev_id) {
- case SST_MRFLD_PCI_ID:
- case SST_BYT_ACPI_ID:
- case SST_CHV_ACPI_ID:
+ case PCI_DEVICE_ID_INTEL_SST_TNG:
+ case PCI_DEVICE_ID_INTEL_SST_BYT:
+ case PCI_DEVICE_ID_INTEL_SST_BSW:
sst->tstamp = SST_TIME_STAMP_MRFLD;
sst->ops = &mrfld_ops;
return 0;
@@ -221,8 +222,13 @@ static void sst_init_locks(struct intel_sst_drv *ctx)
spin_lock_init(&ctx->block_lock);
}
+/*
+ * Driver handles PCI IDs in ACPI - sst_acpi_probe() - and we are using only
+ * device ID part. If real ACPI ID appears, the kstrtouint() returns error, so
+ * we are fine with using unsigned short as dev_id type.
+ */
int sst_alloc_drv_context(struct intel_sst_drv **ctx,
- struct device *dev, unsigned int dev_id)
+ struct device *dev, unsigned short dev_id)
{
*ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL);
if (!(*ctx))
diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h
index 4d37d39fd8f4..c43946c5ecee 100644
--- a/sound/soc/intel/atom/sst/sst.h
+++ b/sound/soc/intel/atom/sst/sst.h
@@ -20,9 +20,6 @@
/* driver names */
#define SST_DRV_NAME "intel_sst_driver"
-#define SST_MRFLD_PCI_ID 0x119A
-#define SST_BYT_ACPI_ID 0x80860F28
-#define SST_CHV_ACPI_ID 0x808622A8
#define SST_SUSPEND_DELAY 2000
#define FW_CONTEXT_MEM (64*1024)
@@ -358,7 +355,7 @@ struct sst_fw_save {
struct intel_sst_drv {
int sst_state;
int irq_num;
- unsigned int dev_id;
+ unsigned short dev_id;
void __iomem *ddr;
void __iomem *shim;
void __iomem *mailbox;
@@ -446,9 +443,6 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param);
int sst_set_metadata(int str_id, char *params);
int sst_get_stream(struct intel_sst_drv *ctx,
struct snd_sst_params *str_param);
-int sst_get_stream_allocated(struct intel_sst_drv *ctx,
- struct snd_sst_params *str_param,
- struct snd_sst_lib_download **lib_dnld);
int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
int str_id, bool partial_drain);
int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx,
@@ -464,8 +458,6 @@ void sst_post_download_mrfld(struct intel_sst_drv *ctx);
int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx);
-int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
- struct sst_block *block);
int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
struct sst_block *block);
int sst_create_ipc_msg(struct ipc_post **arg, bool large);
@@ -473,7 +465,6 @@ int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id);
void sst_clean_stream(struct stream_info *stream);
int intel_sst_register_compress(struct intel_sst_drv *sst);
int intel_sst_remove_compress(struct intel_sst_drv *sst);
-void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id);
int sst_send_sync_msg(int ipc, int str_id);
int sst_get_num_channel(struct snd_sst_params *str_param);
int sst_get_sfreq(struct snd_sst_params *str_param);
@@ -523,7 +514,7 @@ int sst_register(struct device *);
int sst_unregister(struct device *);
int sst_alloc_drv_context(struct intel_sst_drv **ctx,
- struct device *dev, unsigned int dev_id);
+ struct device *dev, unsigned short dev_id);
int sst_context_init(struct intel_sst_drv *ctx);
void sst_context_cleanup(struct intel_sst_drv *ctx);
void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 29d44c989e5f..73624e1b138a 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -12,6 +12,7 @@
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
@@ -125,6 +126,28 @@ static const struct sst_res_info bytcr_res_info = {
.acpi_ipc_irq_index = 0
};
+/* For "LPE0F28" ACPI device found on some Android factory OS models */
+static const struct sst_res_info lpe8086_res_info = {
+ .shim_offset = 0x140000,
+ .shim_size = 0x000100,
+ .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
+ .ssp0_offset = 0xa0000,
+ .ssp0_size = 0x1000,
+ .dma0_offset = 0x98000,
+ .dma0_size = 0x4000,
+ .dma1_offset = 0x9c000,
+ .dma1_size = 0x4000,
+ .iram_offset = 0x0c0000,
+ .iram_size = 0x14000,
+ .dram_offset = 0x100000,
+ .dram_size = 0x28000,
+ .mbox_offset = 0x144000,
+ .mbox_size = 0x1000,
+ .acpi_lpe_res_index = 1,
+ .acpi_ddr_index = 0,
+ .acpi_ipc_irq_index = 0
+};
+
static struct sst_platform_info byt_rvp_platform_data = {
.probe_data = &byt_fwparse_info,
.ipc_info = &byt_ipc_info,
@@ -268,10 +291,38 @@ static int sst_acpi_probe(struct platform_device *pdev)
mach->pdata = &chv_platform_data;
pdata = mach->pdata;
- ret = kstrtouint(id->id, 16, &dev_id);
- if (ret < 0) {
- dev_err(dev, "Unique device id conversion error: %d\n", ret);
- return ret;
+ if (!strcmp(id->id, "LPE0F28")) {
+ struct resource *rsrc;
+
+ /* Use regular BYT SST PCI VID:PID */
+ dev_id = 0x80860F28;
+ byt_rvp_platform_data.res_info = &lpe8086_res_info;
+
+ /*
+ * The "LPE0F28" ACPI device has separate IO-mem resources for:
+ * DDR, SHIM, MBOX, IRAM, DRAM, CFG
+ * None of which covers the entire LPE base address range.
+ * lpe8086_res_info.acpi_lpe_res_index points to the SHIM.
+ * Patch this to cover the entire base address range as expected
+ * by sst_platform_get_resources().
+ */
+ rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
+ pdata->res_info->acpi_lpe_res_index);
+ if (!rsrc) {
+ dev_err(dev, "Invalid SHIM base\n");
+ return -EIO;
+ }
+ rsrc->start -= pdata->res_info->shim_offset;
+ rsrc->end = rsrc->start + 0x200000 - 1;
+ } else {
+ ret = kstrtouint(id->id, 16, &dev_id);
+ if (ret < 0) {
+ dev_err(dev, "Unique device id conversion error: %d\n", ret);
+ return ret;
+ }
+
+ if (soc_intel_is_byt_cr(pdev))
+ byt_rvp_platform_data.res_info = &bytcr_res_info;
}
dev_dbg(dev, "ACPI device id: %x\n", dev_id);
@@ -280,11 +331,6 @@ static int sst_acpi_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- if (soc_intel_is_byt_cr(pdev)) {
- /* override resource info */
- byt_rvp_platform_data.res_info = &bytcr_res_info;
- }
-
/* update machine parameters */
mach->mach_params.acpi_ipc_irq_index =
pdata->res_info->acpi_ipc_irq_index;
@@ -311,7 +357,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
/* Fill sst platform data */
ctx->pdata = pdata;
- strcpy(ctx->firmware_name, mach->fw_filename);
+ strscpy(ctx->firmware_name, mach->fw_filename);
ret = sst_platform_get_resources(ctx);
if (ret)
@@ -344,6 +390,7 @@ static void sst_acpi_remove(struct platform_device *pdev)
}
static const struct acpi_device_id sst_acpi_ids[] = {
+ { "LPE0F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
{ "80860F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
{ "808622A8", (unsigned long)&snd_soc_acpi_intel_cherrytrail_machines},
{ },
@@ -358,7 +405,7 @@ static struct platform_driver sst_acpi_driver = {
.pm = &intel_sst_pm,
},
.probe = sst_acpi_probe,
- .remove_new = sst_acpi_remove,
+ .remove = sst_acpi_remove,
};
module_platform_driver(sst_acpi_driver);
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c
index dc31c2c8f54c..2646c4632ca1 100644
--- a/sound/soc/intel/atom/sst/sst_drv_interface.c
+++ b/sound/soc/intel/atom/sst/sst_drv_interface.c
@@ -55,19 +55,6 @@ int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
return ret;
}
-int sst_get_stream_allocated(struct intel_sst_drv *ctx,
- struct snd_sst_params *str_param,
- struct snd_sst_lib_download **lib_dnld)
-{
- int retval;
-
- retval = ctx->ops->alloc_stream(ctx, str_param);
- if (retval > 0)
- dev_dbg(ctx->dev, "Stream allocated %d\n", retval);
- return retval;
-
-}
-
/*
* sst_get_sfreq - this function returns the frequency of the stream
*
@@ -339,7 +326,7 @@ static int sst_cdev_stream_partial_drain(struct device *dev,
}
static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct snd_sst_tstamp fw_tstamp = {0,};
struct stream_info *stream;
@@ -362,10 +349,11 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
(u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24));
tstamp->sampling_rate = fw_tstamp.sampling_frequency;
- dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames);
- dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n",
+ dev_dbg(dev, "PCM = %llu\n", tstamp->pcm_io_frames);
+ dev_dbg(dev,
+ "Ptr Query on strid = %d copied_total %llu, decodec %llu\n",
str_id, tstamp->copied_total, tstamp->pcm_frames);
- dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames);
+ dev_dbg(dev, "rendered %llu\n", tstamp->pcm_io_frames);
return 0;
}
@@ -430,17 +418,6 @@ static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec)
return 0;
}
-void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id)
-{
- struct stream_info *stream;
-
- dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n",
- str_id);
- stream = &ctx->streams[str_id];
- if (stream->compr_cb)
- stream->compr_cb(stream->compr_cb_param);
-}
-
/*
* sst_close_pcm_stream - Close PCM interface
*
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 3fc2c9a6c44d..0630e58b9d6b 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -19,8 +19,9 @@
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/compress_driver.h>
-#include <asm/intel-mid.h>
+
#include <asm/platform_sst_audio.h>
+
#include "../sst-mfld-platform.h"
#include "sst.h"
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
index 4058b4f80a0c..22ae2d22f121 100644
--- a/sound/soc/intel/atom/sst/sst_pci.c
+++ b/sound/soc/intel/atom/sst/sst_pci.c
@@ -26,79 +26,69 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
int ddr_base, ret = 0;
struct pci_dev *pci = ctx->pci;
- ret = pci_request_regions(pci, SST_DRV_NAME);
+ ret = pcim_request_all_regions(pci, SST_DRV_NAME);
if (ret)
return ret;
/* map registers */
/* DDR base */
- if (ctx->dev_id == SST_MRFLD_PCI_ID) {
+ if (ctx->dev_id == PCI_DEVICE_ID_INTEL_SST_TNG) {
ctx->ddr_base = pci_resource_start(pci, 0);
/* check that the relocated IMR base matches with FW Binary */
ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
if (!ctx->pdata->lib_info) {
dev_err(ctx->dev, "lib_info pointer NULL\n");
- ret = -EINVAL;
- goto do_release_regions;
+ return -EINVAL;
}
if (ddr_base != ctx->pdata->lib_info->mod_base) {
dev_err(ctx->dev,
"FW LSP DDR BASE does not match with IFWI\n");
- ret = -EINVAL;
- goto do_release_regions;
+ return -EINVAL;
}
ctx->ddr_end = pci_resource_end(pci, 0);
- ctx->ddr = pcim_iomap(pci, 0,
- pci_resource_len(pci, 0));
- if (!ctx->ddr) {
- ret = -EINVAL;
- goto do_release_regions;
- }
+ ctx->ddr = pcim_iomap(pci, 0, 0);
+ if (!ctx->ddr)
+ return -ENOMEM;
+
dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
} else {
ctx->ddr = NULL;
}
/* SHIM */
ctx->shim_phy_add = pci_resource_start(pci, 1);
- ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
- if (!ctx->shim) {
- ret = -EINVAL;
- goto do_release_regions;
- }
+ ctx->shim = pcim_iomap(pci, 1, 0);
+ if (!ctx->shim)
+ return -ENOMEM;
+
dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
/* Shared SRAM */
ctx->mailbox_add = pci_resource_start(pci, 2);
- ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
- if (!ctx->mailbox) {
- ret = -EINVAL;
- goto do_release_regions;
- }
+ ctx->mailbox = pcim_iomap(pci, 2, 0);
+ if (!ctx->mailbox)
+ return -ENOMEM;
+
dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
/* IRAM */
ctx->iram_end = pci_resource_end(pci, 3);
ctx->iram_base = pci_resource_start(pci, 3);
- ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
- if (!ctx->iram) {
- ret = -EINVAL;
- goto do_release_regions;
- }
+ ctx->iram = pcim_iomap(pci, 3, 0);
+ if (!ctx->iram)
+ return -ENOMEM;
+
dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
/* DRAM */
ctx->dram_end = pci_resource_end(pci, 4);
ctx->dram_base = pci_resource_start(pci, 4);
- ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
- if (!ctx->dram) {
- ret = -EINVAL;
- goto do_release_regions;
- }
+ ctx->dram = pcim_iomap(pci, 4, 0);
+ if (!ctx->dram)
+ return -ENOMEM;
+
dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
-do_release_regions:
- pci_release_regions(pci);
- return ret;
+ return 0;
}
/*
@@ -167,13 +157,12 @@ static void intel_sst_remove(struct pci_dev *pci)
sst_context_cleanup(sst_drv_ctx);
pci_dev_put(sst_drv_ctx->pci);
- pci_release_regions(pci);
pci_set_drvdata(pci, NULL);
}
/* PCI Routines */
static const struct pci_device_id intel_sst_ids[] = {
- { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
+ { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
{ 0, }
};
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index e6a5c18a7018..c01b29616ebc 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -70,39 +70,6 @@ void sst_set_fw_state_locked(
}
/*
- * sst_wait_interruptible - wait on event
- *
- * @sst_drv_ctx: Driver context
- * @block: Driver block to wait on
- *
- * This function waits without a timeout (and is interruptable) for a
- * given block event
- */
-int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
- struct sst_block *block)
-{
- int retval = 0;
-
- if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
- block->condition)) {
- /* event wake */
- if (block->ret_code < 0) {
- dev_err(sst_drv_ctx->dev,
- "stream failed %d\n", block->ret_code);
- retval = -EBUSY;
- } else {
- dev_dbg(sst_drv_ctx->dev, "event up\n");
- retval = 0;
- }
- } else {
- dev_err(sst_drv_ctx->dev, "signal interrupted\n");
- retval = -EINTR;
- }
- return retval;
-
-}
-
-/*
* sst_wait_timeout - wait on event for timeout
*
* @sst_drv_ctx: Driver context
@@ -292,7 +259,6 @@ int sst_pm_runtime_put(struct intel_sst_drv *sst_drv)
{
int ret;
- pm_runtime_mark_last_busy(sst_drv->dev);
ret = pm_runtime_put_autosuspend(sst_drv->dev);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index 862a19ae5429..288221db7323 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -173,10 +173,11 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
u32 length;
int pvt_id, ret = 0;
struct sst_block *block = NULL;
+ u8 bytes_block = bytes->block;
dev_dbg(sst_drv_ctx->dev,
"type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
- bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
+ bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id,
bytes->pipe_id, bytes->len);
if (sst_create_ipc_msg(&msg, true))
@@ -185,12 +186,12 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
pvt_id = sst_assign_pvt_id(sst_drv_ctx);
sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
bytes->task_id, 1, pvt_id);
- msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
+ msg->mrfld_header.p.header_high.part.res_rqd = bytes_block;
length = bytes->len;
msg->mrfld_header.p.header_low_payload = length;
dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
- if (bytes->block) {
+ if (bytes_block) {
block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
if (block == NULL) {
kfree(msg);
@@ -203,7 +204,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
msg->mrfld_header.p.header_low_payload);
- if (bytes->block) {
+ if (bytes_block) {
ret = sst_wait_timeout(sst_drv_ctx, block);
if (ret) {
dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
@@ -216,7 +217,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
* copy the reply and send back
* we need to update only sz and payload
*/
- if (bytes->block) {
+ if (bytes_block) {
unsigned char *r = block->data;
dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
@@ -224,7 +225,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
memcpy(bytes->bytes, r, bytes->len);
}
}
- if (bytes->block)
+ if (bytes_block)
sst_free_block(sst_drv_ctx, block);
out:
test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 460ee6599daf..576dc0da381d 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -1,16 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
- topology.o path.o pcm.o board_selection.o control.o
-snd-soc-avs-objs += cldma.o
-snd-soc-avs-objs += skl.o apl.o
+snd-soc-avs-y := dsp.o ipc.o messages.o utils.o core.o loader.o \
+ topology.o path.o pcm.o board_selection.o control.o \
+ sysfs.o
+snd-soc-avs-y += cldma.o
+snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.o mtl.o lnl.o ptl.o
-snd-soc-avs-objs += trace.o
+snd-soc-avs-y += trace.o
# tell define_trace.h where to find the trace header
CFLAGS_trace.o := -I$(src)
ifneq ($(CONFIG_DEBUG_FS),)
-snd-soc-avs-objs += probes.o debugfs.o
+snd-soc-avs-y += probes.o debugfs.o
endif
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index 02683dce277a..b922eeaba843 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -8,16 +8,35 @@
#include <linux/devcoredump.h>
#include <linux/slab.h>
+#include <sound/hdaudio_ext.h>
#include "avs.h"
+#include "debug.h"
#include "messages.h"
#include "path.h"
+#include "registers.h"
#include "topology.h"
-static int __maybe_unused
-apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
- u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+static irqreturn_t avs_apl_dsp_interrupt(struct avs_dev *adev)
{
- struct apl_log_state_info *info;
+ u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (adspis == UINT_MAX)
+ return ret;
+
+ if (adspis & AVS_ADSP_ADSPIS_IPC) {
+ avs_skl_ipc_interrupt(adev);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+{
+ struct avs_apl_log_state_info *info;
u32 size, num_cores = adev->hw_cfg.dsp_cores;
int ret, i;
@@ -47,10 +66,11 @@ apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_peri
return 0;
}
+#endif
-static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
+int avs_apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
{
- struct apl_log_buffer_layout layout;
+ struct avs_apl_log_buffer_layout layout;
void __iomem *addr, *buf;
addr = avs_log_buffer_addr(adev, msg->log.core);
@@ -63,11 +83,11 @@ static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg
/* consume the logs regardless of consumer presence */
goto update_read_ptr;
- buf = apl_log_payload_addr(addr);
+ buf = avs_apl_log_payload_addr(addr);
if (layout.read_ptr > layout.write_ptr) {
avs_dump_fw_log(adev, buf + layout.read_ptr,
- apl_log_payload_size(adev) - layout.read_ptr);
+ avs_apl_log_payload_size(adev) - layout.read_ptr);
layout.read_ptr = 0;
}
avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr);
@@ -77,7 +97,8 @@ update_read_ptr:
return 0;
}
-static int apl_wait_log_entry(struct avs_dev *adev, u32 core, struct apl_log_buffer_layout *layout)
+static int avs_apl_wait_log_entry(struct avs_dev *adev, u32 core,
+ struct avs_apl_log_buffer_layout *layout)
{
unsigned long timeout;
void __iomem *addr;
@@ -99,14 +120,14 @@ static int apl_wait_log_entry(struct avs_dev *adev, u32 core, struct apl_log_buf
}
/* reads log header and tests its type */
-#define apl_is_entry_stackdump(addr) ((readl(addr) >> 30) & 0x1)
+#define avs_apl_is_entry_stackdump(addr) ((readl(addr) >> 30) & 0x1)
-static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
+int avs_apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
{
- struct apl_log_buffer_layout layout;
+ 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;
@@ -124,9 +145,9 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
if (!addr)
goto exit;
- buf = apl_log_payload_addr(addr);
+ buf = avs_apl_log_payload_addr(addr);
memcpy_fromio(&layout, addr, sizeof(layout));
- if (!apl_is_entry_stackdump(buf + layout.read_ptr)) {
+ if (!avs_apl_is_entry_stackdump(buf + layout.read_ptr)) {
union avs_notify_msg lbs_msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
/*
@@ -142,11 +163,11 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
do {
u32 count;
- if (apl_wait_log_entry(adev, msg->ext.coredump.core_id, &layout))
+ if (avs_apl_wait_log_entry(adev, msg->ext.coredump.core_id, &layout))
break;
if (layout.read_ptr > layout.write_ptr) {
- count = apl_log_payload_size(adev) - layout.read_ptr;
+ count = avs_apl_log_payload_size(adev) - layout.read_ptr;
memcpy_fromio(pos + offset, buf + layout.read_ptr, count);
layout.read_ptr = 0;
offset += count;
@@ -165,10 +186,11 @@ exit:
return 0;
}
-static bool apl_lp_streaming(struct avs_dev *adev)
+static bool avs_apl_lp_streaming(struct avs_dev *adev)
{
struct avs_path *path;
+ spin_lock(&adev->path_list_lock);
/* Any gateway without buffer allocated in LP area disqualifies D0IX. */
list_for_each_entry(path, &adev->path_list, node) {
struct avs_path_pipeline *ppl;
@@ -188,16 +210,19 @@ static bool apl_lp_streaming(struct avs_dev *adev)
if (cfg->copier.dma_type == INVALID_OBJECT_ID)
continue;
- if (!mod->gtw_attrs.lp_buffer_alloc)
+ if (!mod->gtw_attrs.lp_buffer_alloc) {
+ spin_unlock(&adev->path_list_lock);
return false;
+ }
}
}
}
+ spin_unlock(&adev->path_list_lock);
return true;
}
-static bool apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
+bool avs_apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
{
/* wake in all cases */
if (wake)
@@ -211,10 +236,10 @@ static bool apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool w
* Note: for cAVS 1.5+ and 1.8, D0IX is LP-firmware transition,
* not the power-gating mechanism known from cAVS 2.0.
*/
- return apl_lp_streaming(adev);
+ return avs_apl_lp_streaming(adev);
}
-static int apl_set_d0ix(struct avs_dev *adev, bool enable)
+int avs_apl_set_d0ix(struct avs_dev *adev, bool enable)
{
bool streaming = false;
int ret;
@@ -227,20 +252,19 @@ static int apl_set_d0ix(struct avs_dev *adev, bool enable)
return AVS_IPC_RET(ret);
}
-const struct avs_dsp_ops apl_dsp_ops = {
+const struct avs_dsp_ops avs_apl_dsp_ops = {
.power = avs_dsp_core_power,
.reset = avs_dsp_core_reset,
.stall = avs_dsp_core_stall,
- .irq_handler = avs_dsp_irq_handler,
- .irq_thread = avs_dsp_irq_thread,
+ .dsp_interrupt = avs_apl_dsp_interrupt,
.int_control = avs_dsp_interrupt_control,
.load_basefw = avs_hda_load_basefw,
.load_lib = avs_hda_load_library,
.transfer_mods = avs_hda_transfer_modules,
- .log_buffer_offset = skl_log_buffer_offset,
- .log_buffer_status = apl_log_buffer_status,
- .coredump = apl_coredump,
- .d0ix_toggle = apl_d0ix_toggle,
- .set_d0ix = apl_set_d0ix,
+ .log_buffer_offset = avs_skl_log_buffer_offset,
+ .log_buffer_status = avs_apl_log_buffer_status,
+ .coredump = avs_apl_coredump,
+ .d0ix_toggle = avs_apl_d0ix_toggle,
+ .set_d0ix = avs_apl_set_d0ix,
AVS_SET_ENABLE_LOGS_OP(apl)
};
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index d7fccdcb9c16..0f8ddd0e9e5f 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021-2022 Intel Corporation
*
* Authors: Cezary Rojewski <cezary.rojewski@intel.com>
* Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -22,7 +22,6 @@
struct avs_dev;
struct avs_tplg;
struct avs_tplg_library;
-struct avs_soc_component;
struct avs_ipc_msg;
#ifdef CONFIG_ACPI
@@ -46,12 +45,12 @@ struct avs_dsp_ops {
int (* const power)(struct avs_dev *, u32, bool);
int (* const reset)(struct avs_dev *, u32, bool);
int (* const stall)(struct avs_dev *, u32, bool);
- irqreturn_t (* const irq_handler)(int, void *);
- irqreturn_t (* const irq_thread)(int, void *);
+ irqreturn_t (* const dsp_interrupt)(struct avs_dev *);
void (* const int_control)(struct avs_dev *, bool);
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);
@@ -64,15 +63,38 @@ struct avs_dsp_ops {
#define avs_dsp_op(adev, op, ...) \
((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__))
-extern const struct avs_dsp_ops skl_dsp_ops;
-extern const struct avs_dsp_ops apl_dsp_ops;
+extern const struct avs_dsp_ops avs_skl_dsp_ops;
+extern const struct avs_dsp_ops avs_apl_dsp_ops;
+extern const struct avs_dsp_ops avs_cnl_dsp_ops;
+extern const struct avs_dsp_ops avs_icl_dsp_ops;
+extern const struct avs_dsp_ops avs_tgl_dsp_ops;
+extern const struct avs_dsp_ops avs_ptl_dsp_ops;
#define AVS_PLATATTR_CLDMA BIT_ULL(0)
#define AVS_PLATATTR_IMR BIT_ULL(1)
+#define AVS_PLATATTR_ACE BIT_ULL(2)
+#define AVS_PLATATTR_ALTHDA BIT_ULL(3)
#define avs_platattr_test(adev, attr) \
((adev)->spec->attributes & AVS_PLATATTR_##attr)
+struct avs_sram_spec {
+ const u32 base_offset;
+ const u32 window_size;
+};
+
+struct avs_hipc_spec {
+ const u32 req_offset;
+ const u32 req_ext_offset;
+ const u32 req_busy_mask;
+ const u32 ack_offset;
+ const u32 ack_done_mask;
+ const u32 rsp_offset;
+ const u32 rsp_busy_mask;
+ const u32 ctl_offset;
+ const u32 sts_offset;
+};
+
/* Platform specific descriptor */
struct avs_spec {
const char *name;
@@ -82,13 +104,12 @@ struct avs_spec {
const u32 core_init_mask; /* used during DSP boot */
const u64 attributes; /* bitmask of AVS_PLATATTR_* */
- const u32 sram_base_offset;
- const u32 sram_window_size;
- const u32 rom_status;
+ const struct avs_sram_spec *sram;
+ const struct avs_hipc_spec *hipc;
};
struct avs_fw_entry {
- char *name;
+ const char *name;
const struct firmware *fw;
struct list_head node;
@@ -121,16 +142,17 @@ struct avs_dev {
struct avs_mods_info *mods_info;
struct ida **mod_idas;
struct mutex modres_mutex;
+ void *modcfg_buf; /* module configuration buffer */
struct ida ppl_ida;
struct list_head fw_list;
int *core_refs; /* reference count per core */
char **lib_names;
int num_lp_paths;
+ atomic_t l1sen_counter; /* controls whether L1SEN should be disabled */
struct completion fw_ready;
struct work_struct probe_work;
- struct nhlt_acpi_table *nhlt;
struct list_head comp_list;
struct mutex comp_list_mutex;
struct list_head path_list;
@@ -224,39 +246,20 @@ struct avs_ipc {
#define AVS_IPC_RET(ret) \
(((ret) <= 0) ? (ret) : -AVS_EIPC)
-static inline void avs_ipc_err(struct avs_dev *adev, struct avs_ipc_msg *tx,
- const char *name, int error)
-{
- /*
- * If IPC channel is blocked e.g.: due to ongoing recovery,
- * -EPERM error code is expected and thus it's not an actual error.
- *
- * Unsupported IPCs are of no harm either.
- */
- if (error == -EPERM || error == AVS_IPC_NOT_SUPPORTED)
- dev_dbg(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
- tx->glb.primary, tx->glb.ext.val, error);
- else
- dev_err(adev->dev, "%s 0x%08x 0x%08x failed: %d\n", name,
- tx->glb.primary, tx->glb.ext.val, error);
-}
-
-irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id);
-irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id);
void avs_dsp_process_response(struct avs_dev *adev, u64 header);
-int avs_dsp_send_msg_timeout(struct avs_dev *adev,
- struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, int timeout);
-int avs_dsp_send_msg(struct avs_dev *adev,
- struct avs_ipc_msg *request, struct avs_ipc_msg *reply);
+int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
+ struct avs_ipc_msg *reply, int timeout, const char *name);
+int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
+ struct avs_ipc_msg *reply, const char *name);
/* Two variants below are for messages that control DSP power states. */
int avs_dsp_send_pm_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, int timeout, bool wake_d0i0);
+ struct avs_ipc_msg *reply, int timeout, bool wake_d0i0,
+ const char *name);
int avs_dsp_send_pm_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, bool wake_d0i0);
-int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev,
- struct avs_ipc_msg *request, int timeout);
-int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request);
+ struct avs_ipc_msg *reply, bool wake_d0i0, const char *name);
+int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout,
+ const char *name);
+int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, const char *name);
void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable);
int avs_ipc_init(struct avs_ipc *ipc, struct device *dev);
void avs_ipc_block(struct avs_ipc *ipc);
@@ -264,7 +267,26 @@ void avs_ipc_block(struct avs_ipc *ipc);
int avs_dsp_disable_d0ix(struct avs_dev *adev);
int avs_dsp_enable_d0ix(struct avs_dev *adev);
-int skl_log_buffer_offset(struct avs_dev *adev, u32 core);
+int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power);
+int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power);
+int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall);
+int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall);
+void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable);
+void avs_skl_ipc_interrupt(struct avs_dev *adev);
+irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev);
+irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev);
+int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities);
+int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities);
+int avs_skl_log_buffer_offset(struct avs_dev *adev, u32 core);
+int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core);
+int avs_apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg);
+int avs_apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg);
+bool avs_apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake);
+bool avs_icl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake);
+int avs_apl_set_d0ix(struct avs_dev *adev, bool enable);
+int avs_icl_set_d0ix(struct avs_dev *adev, bool enable);
/* Firmware resources management */
@@ -283,8 +305,8 @@ void avs_release_firmwares(struct avs_dev *adev);
int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
u8 core_id, u8 domain, void *param, u32 param_size,
- u16 *instance_id);
-void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
+ u8 *instance_id);
+void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u8 instance_id,
u8 ppl_instance_id, u8 core_id);
int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
bool lp, u16 attributes, u8 *instance_id);
@@ -309,6 +331,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id);
int avs_hda_transfer_modules(struct avs_dev *adev, bool load,
struct avs_module_entry *mods, u32 num_mods);
+int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw);
+
/* Soc component members */
struct avs_soc_component {
@@ -323,89 +347,21 @@ struct avs_soc_component {
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
-int avs_soc_component_register(struct device *dev, const char *name,
- const struct snd_soc_component_driver *drv,
- struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
-int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
-int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
- unsigned long *tdms);
-int avs_hda_platform_register(struct avs_dev *adev, const char *name);
+int avs_register_dmic_component(struct avs_dev *adev, const char *name);
+int avs_register_i2s_component(struct avs_dev *adev, const char *name, unsigned long port_mask,
+ unsigned long *tdms);
+int avs_register_hda_component(struct avs_dev *adev, const char *name);
+int avs_register_component(struct device *dev, const char *name,
+ struct snd_soc_component_driver *drv,
+ struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
int avs_register_all_boards(struct avs_dev *adev);
void avs_unregister_all_boards(struct avs_dev *adev);
-/* Firmware tracing helpers */
-
-#define avs_log_buffer_size(adev) \
- ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
-
-#define avs_log_buffer_addr(adev, core) \
-({ \
- s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \
- (__offset < 0) ? NULL : \
- (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
-})
-
-static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&adev->trace_lock, flags);
- ret = avs_dsp_op(adev, log_buffer_status, msg);
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
- return ret;
-}
+int avs_parse_sched_cfg(struct avs_dev *adev, const char *buf, size_t len);
-struct apl_log_buffer_layout {
- u32 read_ptr;
- u32 write_ptr;
- u8 buffer[];
-} __packed;
+/* Filesystems integration */
-#define apl_log_payload_size(adev) \
- (avs_log_buffer_size(adev) - sizeof(struct apl_log_buffer_layout))
-
-#define apl_log_payload_addr(addr) \
- (addr + sizeof(struct apl_log_buffer_layout))
-
-#ifdef CONFIG_DEBUG_FS
-#define AVS_SET_ENABLE_LOGS_OP(name) \
- .enable_logs = name##_enable_logs
-
-bool avs_logging_fw(struct avs_dev *adev);
-void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len);
-void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len);
-
-int avs_probe_platform_register(struct avs_dev *adev, const char *name);
-
-void avs_debugfs_init(struct avs_dev *adev);
-void avs_debugfs_exit(struct avs_dev *adev);
-#else
-#define AVS_SET_ENABLE_LOGS_OP(name)
-
-static inline bool avs_logging_fw(struct avs_dev *adev)
-{
- return false;
-}
-
-static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
-{
-}
-
-static inline void
-avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
-{
-}
-
-static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name)
-{
- return 0;
-}
-
-static inline void avs_debugfs_init(struct avs_dev *adev) { }
-static inline void avs_debugfs_exit(struct avs_dev *adev) { }
-#endif
+extern const struct attribute_group *avs_attr_groups[];
#endif /* __SOUND_SOC_INTEL_AVS_H */
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index b2823c2107f7..52e6266a7cb8 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -10,17 +10,24 @@
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/pci.h>
+#include <acpi/nhlt.h>
#include <linux/platform_device.h>
#include <sound/hda_codec.h>
#include <sound/hda_register.h>
-#include <sound/intel-nhlt.h>
#include <sound/soc-acpi.h>
#include <sound/soc-component.h>
#include "avs.h"
+#include "debug.h"
+#include "pcm.h"
+#include "utils.h"
-static bool i2s_test;
-module_param(i2s_test, bool, 0444);
-MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
+static char *i2s_test;
+module_param(i2s_test, charp, 0444);
+MODULE_PARM_DESC(i2s_test, "Use I2S test-board instead of ACPI, i2s_test=ssp0tdm,ssp1tdm,... 0 to ignore port");
+
+bool obsolete_card_names = IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE);
+module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444);
+MODULE_PARM_DESC(obsolete_card_names, "Use obsolete card names 0=no, 1=yes");
static const struct dmi_system_id kbl_dmi_table[] = {
{
@@ -51,19 +58,13 @@ static const struct dmi_system_id kblr_dmi_table[] = {
static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
{
struct snd_soc_acpi_mach *mach = arg;
- const struct dmi_system_id *dmi_id;
struct dmi_system_id *dmi_table;
- if (mach->quirk_data == NULL)
- return mach;
-
dmi_table = (struct dmi_system_id *)mach->quirk_data;
- dmi_id = dmi_first_match(dmi_table);
- if (!dmi_id)
- return NULL;
-
- return mach;
+ if (!dmi_table || dmi_first_match(dmi_table))
+ return mach;
+ return NULL;
}
#define AVS_SSP(x) (BIT(x))
@@ -136,6 +137,23 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "max98927-tplg.bin",
},
{
+ .id = "10EC5514",
+ .drv_name = "avs_rt5514",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .pdata = (struct avs_mach_pdata[]){ { .tdms = (unsigned long[]){ 0x2 } } },
+ .tplg_filename = "rt5514-tplg.bin",
+ },
+ {
+ .id = "10EC5663",
+ .drv_name = "avs_rt5663",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(1),
+ },
+ .tplg_filename = "rt5663-tplg.bin",
+ },
+ {
.id = "MX98373",
.drv_name = "avs_max98373",
.mach_params = {
@@ -159,6 +177,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
},
.tplg_filename = "da7219-tplg.bin",
},
+ {
+ .id = "ESSX8336",
+ .drv_name = "avs_es8336",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "es8336-tplg.bin",
+ },
{},
};
@@ -177,7 +203,9 @@ static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
.mach_params = {
.i2s_link_mask = AVS_SSP_RANGE(0, 5),
},
- .pdata = (unsigned long[]){ 0, 0, 0x14, 0, 0, 0 }, /* SSP2 TDMs */
+ .pdata = (struct avs_mach_pdata[]){ {
+ .tdms = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }
+ } },
.tplg_filename = "tdf8532-tplg.bin",
},
{
@@ -211,50 +239,119 @@ static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
{},
};
-static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
+static struct snd_soc_acpi_mach avs_cnl_i2s_machines[] = {
{
- .drv_name = "avs_i2s_test",
+ .id = "INT34C2",
+ .drv_name = "avs_rt274",
.mach_params = {
.i2s_link_mask = AVS_SSP(0),
},
- .tplg_filename = "i2s-test-tplg.bin",
+ .tplg_filename = "rt274-tplg.bin",
},
{
- .drv_name = "avs_i2s_test",
+ .id = "10EC5682",
+ .drv_name = "avs_rt5682",
.mach_params = {
.i2s_link_mask = AVS_SSP(1),
},
- .tplg_filename = "i2s-test-tplg.bin",
+ .tplg_filename = "rt5682-tplg.bin",
},
+ {},
+};
+
+static struct snd_soc_acpi_mach avs_icl_i2s_machines[] = {
{
- .drv_name = "avs_i2s_test",
+ .id = "INT343A",
+ .drv_name = "avs_rt298",
.mach_params = {
- .i2s_link_mask = AVS_SSP(2),
+ .i2s_link_mask = AVS_SSP(0),
},
- .tplg_filename = "i2s-test-tplg.bin",
+ .tplg_filename = "rt298-tplg.bin",
},
{
- .drv_name = "avs_i2s_test",
+ .id = "INT34C2",
+ .drv_name = "avs_rt274",
.mach_params = {
- .i2s_link_mask = AVS_SSP(3),
+ .i2s_link_mask = AVS_SSP(0),
},
- .tplg_filename = "i2s-test-tplg.bin",
+ .tplg_filename = "rt274-tplg.bin",
},
+ {},
+};
+
+static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {
{
- .drv_name = "avs_i2s_test",
+ .id = "INT34C2",
+ .drv_name = "avs_rt274",
.mach_params = {
- .i2s_link_mask = AVS_SSP(4),
+ .i2s_link_mask = AVS_SSP(0),
},
- .tplg_filename = "i2s-test-tplg.bin",
+ .tplg_filename = "rt274-tplg.bin",
},
{
- .drv_name = "avs_i2s_test",
+ .id = "10EC0298",
+ .drv_name = "avs_rt298",
.mach_params = {
- .i2s_link_mask = AVS_SSP(5),
+ .i2s_link_mask = AVS_SSP(0),
},
- .tplg_filename = "i2s-test-tplg.bin",
+ .tplg_filename = "rt298-tplg.bin",
},
- /* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */
+ {
+ .id = "10EC1308",
+ .drv_name = "avs_rt1308",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(1),
+ },
+ .tplg_filename = "rt1308-tplg.bin",
+ },
+ {
+ .id = "10EC5640",
+ .uid = "1",
+ .drv_name = "avs_rt5640",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "rt5640-tplg.bin",
+ },
+ {
+ .id = "10EC5640",
+ .uid = "3",
+ .drv_name = "avs_rt5640",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(1),
+ },
+ .tplg_filename = "rt5640-tplg.bin",
+ },
+ {
+ .id = "10EC5640",
+ .uid = "2",
+ .drv_name = "avs_rt5640",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(2),
+ },
+ .tplg_filename = "rt5640-tplg.bin",
+ },
+ {
+ .id = "ESSX8336",
+ .drv_name = "avs_es8336",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "es8336-tplg.bin",
+ },
+ {},
+};
+
+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",
+ },
+ {}
};
struct avs_acpi_boards {
@@ -263,189 +360,225 @@ struct avs_acpi_boards {
};
#define AVS_MACH_ENTRY(_id, _mach) \
- { .id = (_id), .machs = (_mach), }
+ { .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }
/* supported I2S boards per platform */
static const struct avs_acpi_boards i2s_boards[] = {
- AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */
- AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */
- AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */
- AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */
- {},
+ AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),
+ AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines),
+ 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_mbl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines),
+ { },
};
-static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
+static struct snd_soc_acpi_mach *avs_get_i2s_machines(struct avs_dev *adev)
{
int id, i;
id = adev->base.pci->device;
for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
if (i2s_boards[i].id == id)
- return &i2s_boards[i];
+ return i2s_boards[i].machs;
return NULL;
}
-/* platform devices owned by AVS audio are removed with this hook */
-static void board_pdev_unregister(void *data)
+/* Platform devices spawned by AVS driver are removed with this hook. */
+static void avs_unregister_board(void *pdev)
{
- platform_device_unregister(data);
+ platform_device_unregister(pdev);
}
-static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
+static struct platform_device *avs_register_board(struct avs_dev *adev, const char *name,
+ const void *data, size_t size)
{
- struct platform_device *board;
- struct snd_soc_acpi_mach mach = {{0}};
+ struct platform_device *pdev;
int ret;
- ret = avs_probe_platform_register(adev, "probe-platform");
- if (ret < 0)
- return ret;
+ pdev = platform_device_register_data(NULL, name, PLATFORM_DEVID_AUTO, data, size);
+ if (IS_ERR(pdev))
+ return pdev;
- mach.mach_params.platform = "probe-platform";
+ ret = devm_add_action_or_reset(adev->dev, avs_unregister_board, pdev);
+ if (ret)
+ return ERR_PTR(ret);
- board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,
- (const void *)&mach, sizeof(mach));
- if (IS_ERR(board)) {
- dev_err(adev->dev, "probe board register failed\n");
- return PTR_ERR(board);
- }
+ return pdev;
+}
- ret = devm_add_action(adev->dev, board_pdev_unregister, board);
- if (ret < 0) {
- platform_device_unregister(board);
- return ret;
- }
- return 0;
+static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, const char *name,
+ struct snd_soc_acpi_mach *mach,
+ struct hda_codec *codec,
+ unsigned long *tdms, char *codec_name)
+{
+ struct avs_mach_pdata *pdata;
+
+ pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->codec = codec;
+ pdata->tdms = tdms;
+ pdata->codec_name = codec_name;
+ pdata->obsolete_card_names = obsolete_card_names;
+ mach->pdata = pdata;
+
+ return avs_register_board(adev, name, mach, sizeof(*mach));
+}
+
+static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
+{
+ struct platform_device *pdev;
+
+ pdev = avs_register_board(adev, "avs_probe_mb", NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return avs_register_probe_component(adev, dev_name(&pdev->dev));
}
static int avs_register_dmic_board(struct avs_dev *adev)
{
- struct platform_device *codec, *board;
- struct snd_soc_acpi_mach mach = {{0}};
- int ret;
+ static struct snd_soc_acpi_mach mach = {
+ .tplg_filename = "dmic-tplg.bin",
+ };
+ struct platform_device *pdev;
+ char *codec_name;
- if (!adev->nhlt ||
- !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_DMIC)) {
+ if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {
dev_dbg(adev->dev, "no DMIC endpoints present\n");
return 0;
}
- codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
- if (IS_ERR(codec)) {
- dev_err(adev->dev, "dmic codec register failed\n");
- return PTR_ERR(codec);
- }
+ /* DMIC present in Intel PCH is enumerated statically. */
+ pdev = avs_register_board(adev, "dmic-codec", NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
- ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
- if (ret < 0) {
- platform_device_unregister(codec);
- return ret;
- }
+ codec_name = devm_kstrdup(adev->dev, dev_name(&pdev->dev), GFP_KERNEL);
+ if (!codec_name)
+ return -ENOMEM;
- ret = avs_dmic_platform_register(adev, "dmic-platform");
- if (ret < 0)
- return ret;
+ pdev = avs_register_board_pdata(adev, "avs_dmic", &mach, NULL, NULL, codec_name);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
- mach.tplg_filename = "dmic-tplg.bin";
- mach.mach_params.platform = "dmic-platform";
+ return avs_register_dmic_component(adev, dev_name(&pdev->dev));
+}
- board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
- (const void *)&mach, sizeof(mach));
- if (IS_ERR(board)) {
- dev_err(adev->dev, "dmic board register failed\n");
- return PTR_ERR(board);
- }
+static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot)
+{
+ struct snd_soc_acpi_mach mach = {{0}};
+ struct platform_device *pdev;
+ unsigned long *tdms;
+
+ tdms = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(*tdms), GFP_KERNEL);
+ mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
+ AVS_STRING_FMT("i2s", "-test-tplg.bin",
+ ssp_port, tdm_slot));
+ if (!tdms || !mach.tplg_filename)
+ return -ENOMEM;
- ret = devm_add_action(adev->dev, board_pdev_unregister, board);
- if (ret < 0) {
- platform_device_unregister(board);
- return ret;
- }
+ tdms[ssp_port] = BIT(tdm_slot);
+ mach.drv_name = "avs_i2s_test";
+ mach.mach_params.i2s_link_mask = AVS_SSP(ssp_port);
- return 0;
+ pdev = avs_register_board_pdata(adev, mach.drv_name, &mach, NULL, tdms, NULL);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return avs_register_i2s_component(adev, dev_name(&pdev->dev), AVS_SSP(ssp_port), tdms);
}
-static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
+static int avs_register_i2s_test_boards(struct avs_dev *adev)
{
- struct platform_device *board;
- int num_ssps;
- char *name;
- int ret;
-
- num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
- if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
- dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
- num_ssps, mach->drv_name,
- (unsigned long)__fls(mach->mach_params.i2s_link_mask));
- return -ENODEV;
- }
+ int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
+ int ssp_port, tdm_slot, ret;
+ unsigned long tdm_slots;
+ u32 *array, num_elems;
- name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
- mach->mach_params.i2s_link_mask);
- if (!name)
- return -ENOMEM;
+ if (!i2s_test)
+ return 0;
- ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
- if (ret < 0)
+ ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array);
+ if (ret) {
+ dev_err(adev->dev, "failed to parse i2s_test parameter\n");
return ret;
+ }
- mach->mach_params.platform = name;
-
- board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
- (const void *)mach, sizeof(*mach));
- if (IS_ERR(board)) {
- dev_err(adev->dev, "ssp board register failed\n");
- return PTR_ERR(board);
+ num_elems = *array;
+ if (num_elems > max_ssps) {
+ dev_err(adev->dev, "board supports only %d SSP, %d specified\n",
+ max_ssps, num_elems);
+ return -EINVAL;
}
- ret = devm_add_action(adev->dev, board_pdev_unregister, board);
- if (ret < 0) {
- platform_device_unregister(board);
- return ret;
+ for (ssp_port = 0; ssp_port < num_elems; ssp_port++) {
+ tdm_slots = array[1 + ssp_port];
+ for_each_set_bit(tdm_slot, &tdm_slots, 16) {
+ ret = avs_register_i2s_test_board(adev, ssp_port, tdm_slot);
+ if (ret)
+ return ret;
+ }
}
return 0;
}
-static int avs_register_i2s_boards(struct avs_dev *adev)
+static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
{
- const struct avs_acpi_boards *boards;
- struct snd_soc_acpi_mach *mach;
- int ret;
+ u32 i2s_mask = mach->mach_params.i2s_link_mask;
+ struct platform_device *pdev;
+ unsigned long *tdms = NULL;
- if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) {
- dev_dbg(adev->dev, "no I2S endpoints present\n");
- return 0;
- }
+ if (mach->pdata)
+ tdms = ((struct avs_mach_pdata *)mach->pdata)->tdms;
- if (i2s_test) {
- int i, num_ssps;
+ pdev = avs_register_board_pdata(adev, mach->drv_name, mach, NULL, tdms, NULL);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
- num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
- /* constrain just in case FW says there can be more SSPs than possible */
- num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
+ return avs_register_i2s_component(adev, dev_name(&pdev->dev), i2s_mask, tdms);
+}
- mach = avs_test_i2s_machines;
+static int avs_register_i2s_boards(struct avs_dev *adev)
+{
+ int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
+ struct snd_soc_acpi_mach *machs;
+ struct snd_soc_acpi_mach *mach;
+ int ret;
- for (i = 0; i < num_ssps; i++) {
- ret = avs_register_i2s_board(adev, &mach[i]);
- if (ret < 0)
- dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
- ret);
- }
+ if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) {
+ dev_dbg(adev->dev, "no I2S endpoints present\n");
return 0;
}
- boards = avs_get_i2s_boards(adev);
- if (!boards) {
+ machs = avs_get_i2s_machines(adev);
+ if (!machs) {
dev_dbg(adev->dev, "no I2S endpoints supported\n");
return 0;
}
- for (mach = boards->machs; mach->id[0]; mach++) {
- if (!acpi_dev_present(mach->id, NULL, -1))
+ for (mach = machs; mach->id[0]; mach++) {
+ if (!acpi_dev_present(mach->id, mach->uid, -1))
continue;
+ if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
+ dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
+ num_ssps, mach->drv_name,
+ (unsigned long)__fls(mach->mach_params.i2s_link_mask));
+ continue;
+ }
if (mach->machine_quirk)
if (!mach->machine_quirk(mach))
continue;
@@ -460,42 +593,20 @@ static int avs_register_i2s_boards(struct avs_dev *adev)
static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
{
- struct snd_soc_acpi_mach mach = {{0}};
- struct platform_device *board;
struct hdac_device *hdev = &codec->core;
- char *pname;
- int ret, id;
-
- pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
- if (!pname)
- return -ENOMEM;
-
- ret = avs_hda_platform_register(adev, pname);
- if (ret < 0)
- return ret;
+ struct snd_soc_acpi_mach mach = {{0}};
+ struct platform_device *pdev;
- mach.pdata = codec;
- mach.mach_params.platform = pname;
mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
hdev->vendor_id);
if (!mach.tplg_filename)
return -ENOMEM;
- id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
- board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
- sizeof(mach));
- if (IS_ERR(board)) {
- dev_err(adev->dev, "hda board register failed\n");
- return PTR_ERR(board);
- }
+ pdev = avs_register_board_pdata(adev, "avs_hdaudio", &mach, codec, NULL, NULL);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
- ret = devm_add_action(adev->dev, board_pdev_unregister, board);
- if (ret < 0) {
- platform_device_unregister(board);
- return ret;
- }
-
- return 0;
+ return avs_register_hda_component(adev, dev_name(&pdev->dev));
}
static int avs_register_hda_boards(struct avs_dev *adev)
@@ -538,6 +649,10 @@ int avs_register_all_boards(struct avs_dev *adev)
dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
ret);
+ ret = avs_register_i2s_test_boards(adev);
+ if (ret)
+ dev_dbg(adev->dev, "enumerate I2S TEST endpoints failed: %d\n", ret);
+
ret = avs_register_i2s_boards(adev);
if (ret < 0)
dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index e4c230efe8d7..82f50207bb2f 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -4,6 +4,14 @@ menu "Intel AVS Machine drivers"
comment "Available DSP configurations"
+config SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE
+ bool "Use obsolete card names"
+ default n
+ help
+ Use obsolete names for some of avs cards. This option should be
+ used if your system depends on old card names, for example having
+ not up to date UCM files.
+
config SND_SOC_INTEL_AVS_MACH_DA7219
tristate "da7219 I2S board"
depends on I2C
@@ -22,6 +30,16 @@ config SND_SOC_INTEL_AVS_MACH_DMIC
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_ES8336
+ tristate "es8336 I2S board"
+ depends on X86 && I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_ES8316
+ help
+ This adds support for AVS with ES8336 I2S 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_HDAUDIO
tristate "HD-Audio generic board"
select SND_SOC_HDA
@@ -77,6 +95,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
@@ -115,6 +143,38 @@ config SND_SOC_INTEL_AVS_MACH_RT298
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_RT5514
+ tristate "rt5514 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5514
+ help
+ This adds support for ASoC machine driver with RT5514 I2S audio codec.
+ 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_RT5640
+ tristate "rt5640 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5640
+ help
+ This adds support for ASoC machine board connecting AVS with RT5640,
+ components representing Intel AudioDSP and Realtek 5640 codec respectively.
+ The codec chip is present on I2C bus and the streaming occurs over I2S
+ interface.
+ Say Y or m if you have such a device.
+
+config SND_SOC_INTEL_AVS_MACH_RT5663
+ tristate "rt5663 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5663
+ help
+ This adds support for ASoC machine driver with RT5663 I2S audio codec.
+ 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_RT5682
tristate "rt5682 in I2S mode"
depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index b81343420370..46ef1babda34 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -1,31 +1,41 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-avs-da7219-objs := da7219.o
-snd-soc-avs-dmic-objs := dmic.o
-snd-soc-avs-hdaudio-objs := hdaudio.o
-snd-soc-avs-i2s-test-objs := i2s_test.o
-snd-soc-avs-max98927-objs := max98927.o
-snd-soc-avs-max98357a-objs := max98357a.o
-snd-soc-avs-max98373-objs := max98373.o
-snd-soc-avs-nau8825-objs := nau8825.o
-snd-soc-avs-probe-objs := probe.o
-snd-soc-avs-rt274-objs := rt274.o
-snd-soc-avs-rt286-objs := rt286.o
-snd-soc-avs-rt298-objs := rt298.o
-snd-soc-avs-rt5682-objs := rt5682.o
-snd-soc-avs-ssm4567-objs := ssm4567.o
+snd-soc-avs-da7219-y := da7219.o
+snd-soc-avs-dmic-y := dmic.o
+snd-soc-avs-es8336-y := es8336.o
+snd-soc-avs-hdaudio-y := hdaudio.o
+snd-soc-avs-i2s-test-y := i2s_test.o
+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
+snd-soc-avs-rt298-y := rt298.o
+snd-soc-avs-rt5514-y := rt5514.o
+snd-soc-avs-rt5640-y := rt5640.o
+snd-soc-avs-rt5663-y := rt5663.o
+snd-soc-avs-rt5682-y := rt5682.o
+snd-soc-avs-ssm4567-y := ssm4567.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_ES8336) += snd-soc-avs-es8336.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
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
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5514) += snd-soc-avs-rt5514.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5640) += snd-soc-avs-rt5640.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663) += snd-soc-avs-rt5663.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 964a763732ab..2b17abcbd2bc 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -16,19 +16,20 @@
#include <sound/soc-dapm.h>
#include <uapi/linux/input-event-codes.h>
#include "../../../codecs/da7219.h"
+#include "../utils.h"
#define DA7219_DAI_NAME "da7219-hifi"
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
int ret = 0;
@@ -55,6 +56,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget card_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
};
@@ -68,14 +70,32 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
+};
+
+static const struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_jack_pin *pins;
struct snd_soc_jack *jack;
+ int num_pins;
int clk_freq;
int ret;
@@ -91,14 +111,21 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
+ num_pins = ARRAY_SIZE(card_headset_pins);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
/*
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+ jack, pins, num_pins);
if (ret) {
dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
@@ -114,7 +141,7 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
static void avs_da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int
@@ -137,7 +164,7 @@ avs_da7219_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_param
return 0;
}
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -148,69 +175,57 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-DLGS7219:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, DA7219_DAI_NAME);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
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;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
return 0;
}
-static int avs_card_suspend_pre(struct snd_soc_card *card)
-{
- struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
-
- return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
-}
-
-static int avs_card_resume_post(struct snd_soc_card *card)
-{
- struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
- struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
-
- return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
-}
-
static int avs_da7219_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct snd_soc_jack *jack;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
+
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -221,11 +236,14 @@ static int avs_da7219_probe(struct platform_device *pdev)
if (!jack || !card)
return -ENOMEM;
- card->name = "avs_da7219";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_da7219";
+ } else {
+ card->driver_name = "avs_da7219";
+ card->long_name = card->name = "AVS I2S DA7219";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
- card->suspend_pre = avs_card_suspend_pre;
- card->resume_post = avs_card_resume_post;
card->dai_link = dai_link;
card->num_links = 1;
card->controls = card_controls;
@@ -237,23 +255,28 @@ static int avs_da7219_probe(struct platform_device *pdev)
card->fully_routed = true;
snd_soc_card_set_drvdata(card, jack);
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_da7219_driver_ids[] = {
+ {
+ .name = "avs_da7219",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids);
+
static struct platform_driver avs_da7219_driver = {
.probe = avs_da7219_probe,
.driver = {
.name = "avs_da7219",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_da7219_driver_ids,
};
module_platform_driver(avs_da7219_driver);
+MODULE_DESCRIPTION("Intel da7219 machine driver");
MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_da7219");
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
index c270646faf86..bf6f580a5164 100644
--- a/sound/soc/intel/avs/boards/dmic.c
+++ b/sound/soc/intel/avs/boards/dmic.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -10,33 +10,10 @@
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
+#include "../utils.h"
SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-/* Name overridden on probe */
-SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("")));
-
-static struct snd_soc_dai_link card_dai_links[] = {
- /* Back ends */
- {
- .name = "DMIC",
- .id = 0,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "DMIC WoV",
- .id = 1,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .no_pcm = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform),
- },
-};
static const struct snd_soc_dapm_widget card_widgets[] = {
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
@@ -46,46 +23,104 @@ static const struct snd_soc_dapm_route card_routes[] = {
{"DMic", NULL, "SoC DMIC"},
};
+static int avs_create_dai_links(struct device *dev, const char *codec_name,
+ 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;
+
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->codecs)
+ return -ENOMEM;
+
+ dl->codecs->name = devm_kstrdup(dev, codec_name, GFP_KERNEL);
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "dmic-hifi");
+ if (!dl->codecs->name || !dl->codecs->dai_name)
+ 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].nonatomic = 1;
+ dl[0].no_pcm = 1;
+ dl[0].capture_only = 1;
+ memcpy(&dl[1], &dl[0], sizeof(*dl));
+
+ dl[0].name = "DMIC";
+ dl[0].cpus = dmic_pin;
+ dl[0].id = 0;
+ dl[1].name = "DMIC WoV";
+ dl[1].cpus = dmic_wov_pin;
+ dl[1].id = 1;
+ dl[1].ignore_suspend = 1;
+
+ *links = dl;
+ *num_links = num_dl;
+ return 0;
+}
+
static int avs_dmic_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
- struct device *dev = &pdev->dev;
int ret;
mach = dev_get_platdata(dev);
+ pdata = mach->pdata;
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
- card->name = "avs_dmic";
+ ret = avs_create_dai_links(dev, pdata->codec_name, &card->dai_link, &card->num_links);
+ if (ret)
+ return ret;
+
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_dmic";
+ } else {
+ card->driver_name = "avs_dmic";
+ card->long_name = card->name = "AVS DMIC";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
- card->dai_link = card_dai_links;
- card->num_links = ARRAY_SIZE(card_dai_links);
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;
- ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_dmic_driver_ids[] = {
+ {
+ .name = "avs_dmic",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids);
+
static struct platform_driver avs_dmic_driver = {
.probe = avs_dmic_probe,
.driver = {
.name = "avs_dmic",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_dmic_driver_ids,
};
module_platform_driver(avs_dmic_driver);
+MODULE_DESCRIPTION("Intel DMIC machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_dmic");
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
new file mode 100644
index 000000000000..301cfb3cf15b
--- /dev/null
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2023 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/processor.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <asm/cpu_device_id.h>
+#include "../utils.h"
+
+#define ES8336_CODEC_DAI "ES8316 HiFi"
+
+struct avs_card_drvdata {
+ struct snd_soc_jack jack;
+ struct gpio_desc *gpiod;
+};
+
+static const struct acpi_gpio_params enable_gpio = { 0, 0, true };
+
+static const struct acpi_gpio_mapping speaker_gpios[] = {
+ { "speaker-enable-gpios", &enable_gpio, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+ { }
+};
+
+static int avs_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct avs_card_drvdata *data;
+ bool speaker_en;
+
+ data = snd_soc_card_get_drvdata(card);
+ /* As enable_gpio has active_low=true, logic is inverted. */
+ speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
+
+ gpiod_set_value_cansleep(data->gpiod, speaker_en);
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+
+ SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
+ avs_es8336_speaker_power_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+
+ /*
+ * There is no separate speaker output instead the speakers are muxed to
+ * the HP outputs. The mux is controlled by the "Speaker Power" widget.
+ */
+ {"Speaker", NULL, "HPOL"},
+ {"Speaker", NULL, "HPOR"},
+ {"Speaker", NULL, "Speaker Power"},
+
+ /* Mic route map */
+ {"MIC1", NULL, "Internal Mic"},
+ {"MIC2", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static const struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct snd_soc_jack_pin *pins;
+ struct avs_card_drvdata *data;
+ struct gpio_desc *gpiod;
+ int num_pins, ret;
+
+ data = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &data->jack, pins, num_pins);
+ if (ret)
+ return ret;
+
+ ret = devm_acpi_dev_add_driver_gpios(codec_dai->dev, speaker_gpios);
+ if (ret)
+ dev_warn(codec_dai->dev, "Unable to add GPIO mapping table\n");
+
+ gpiod = gpiod_get_optional(codec_dai->dev, "speaker-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod))
+ return dev_err_probe(codec_dai->dev, PTR_ERR(gpiod), "Get gpiod failed: %ld\n",
+ PTR_ERR(gpiod));
+
+ data->gpiod = gpiod;
+ snd_jack_set_key(data->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_soc_component_set_jack(component, &data->jack, NULL);
+
+ snd_soc_dapm_set_idle_bias(dapm, false);
+
+ return 0;
+}
+
+static void avs_es8336_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+ struct avs_card_drvdata *data = snd_soc_card_get_drvdata(runtime->card);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+
+ snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+ gpiod_put(data->gpiod);
+}
+
+static int avs_es8336_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+ int clk_freq;
+ int ret;
+
+ switch (boot_cpu_data.x86_vfm) {
+ case INTEL_KABYLAKE_L:
+ case INTEL_KABYLAKE:
+ clk_freq = 24000000;
+ break;
+ default:
+ clk_freq = 19200000;
+ break;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1, clk_freq, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_es8336_ops = {
+ .hw_params = avs_es8336_hw_params,
+};
+
+static int avs_es8336_be_fixup(struct snd_soc_pcm_runtime *runtime,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSPN to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_3LE);
+
+ return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ 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), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-ESSX8336:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, ES8336_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ platform->name = dev_name(dev);
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ 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_CBC_CFC;
+ dl->init = avs_es8336_codec_init;
+ dl->exit = avs_es8336_codec_exit;
+ dl->be_hw_params_fixup = avs_es8336_be_fixup;
+ dl->ops = &avs_es8336_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI);
+ struct avs_card_drvdata *data = snd_soc_card_get_drvdata(card);
+
+ return snd_soc_component_set_jack(codec_dai->component, &data->jack, NULL);
+}
+
+static int avs_es8336_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
+ struct avs_card_drvdata *data;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ int ssp_port, tdm_slot, ret;
+
+ mach = dev_get_platdata(dev);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
+
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!data || !card)
+ return -ENOMEM;
+
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_es8336";
+ } else {
+ card->driver_name = "avs_es8336";
+ card->long_name = card->name = "AVS I2S ES8336";
+ }
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ 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;
+ snd_soc_card_set_drvdata(card, data);
+
+ return devm_snd_soc_register_deferrable_card(dev, card);
+}
+
+static const struct platform_device_id avs_es8336_driver_ids[] = {
+ {
+ .name = "avs_es8336",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids);
+
+static struct platform_driver avs_es8336_driver = {
+ .probe = avs_es8336_probe,
+ .driver = {
+ .name = "avs_es8336",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = avs_es8336_driver_ids,
+};
+
+module_platform_driver(avs_es8336_driver);
+
+MODULE_DESCRIPTION("Intel es8336 machine driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index cb00bc86ac94..aec769e2396c 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -13,9 +13,10 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../../codecs/hda.h"
+#include "../utils.h"
static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
- const char *platform_name, struct snd_soc_dai_link **links)
+ struct snd_soc_dai_link **links)
{
struct snd_soc_dai_link_component *platform;
struct snd_soc_dai_link *dl;
@@ -28,7 +29,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
+ platform->name = dev_name(dev);
pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
@@ -39,8 +40,6 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
dl[i].id = i;
dl[i].nonatomic = 1;
dl[i].no_pcm = 1;
- dl[i].dpcm_playback = 1;
- dl[i].dpcm_capture = 1;
dl[i].platforms = platform;
dl[i].num_platforms = 1;
dl[i].ignore_pmdown_time = 1;
@@ -54,7 +53,10 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
if (!dl[i].cpus->dai_name)
return -ENOMEM;
- dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+ dl[i].codecs->name = devm_kstrdup_const(dev, cname, GFP_KERNEL);
+ if (!dl[i].codecs->name)
+ return -ENOMEM;
+
dl[i].codecs->dai_name = pcm->name;
dl[i].num_codecs = 1;
dl[i].num_cpus = 1;
@@ -94,7 +96,8 @@ avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx)
static int avs_card_late_probe(struct snd_soc_card *card)
{
struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
- struct hda_codec *codec = mach->pdata;
+ struct avs_mach_pdata *pdata = mach->pdata;
+ struct hda_codec *codec = pdata->codec;
struct hda_pcm *hpcm;
/* Topology pcm indexing is 1-based */
int i = 1;
@@ -123,6 +126,7 @@ static int avs_card_late_probe(struct snd_soc_card *card)
static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
{
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_dai_link *links = NULL;
struct snd_soc_card *card = rtm->card;
struct hda_codec *codec;
@@ -130,14 +134,15 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
int ret, pcm_count = 0;
mach = dev_get_platdata(card->dev);
- codec = mach->pdata;
+ pdata = mach->pdata;
+ codec = pdata->codec;
if (list_empty(&codec->pcm_list_head))
return -EINVAL;
list_for_each_entry(pcm, &codec->pcm_list_head, list)
pcm_count++;
- ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links);
+ ret = avs_create_dai_links(card->dev, codec, pcm_count, &links);
if (ret < 0) {
dev_err(card->dev, "create links failed: %d\n", ret);
return ret;
@@ -152,17 +157,13 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
return 0;
}
-SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-static struct snd_soc_dai_link probing_link = {
+static const struct snd_soc_dai_link probing_link = {
.name = "probing-LINK",
.id = -1,
.nonatomic = 1,
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .cpus = dummy,
- .num_cpus = ARRAY_SIZE(dummy),
+ .cpus = &snd_soc_dummy_dlc,
+ .num_cpus = 1,
.init = avs_probing_link_init,
};
@@ -170,12 +171,14 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *binder;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
struct hda_codec *codec;
mach = dev_get_platdata(dev);
- codec = mach->pdata;
+ pdata = mach->pdata;
+ codec = pdata->codec;
/* codec may be unloaded before card's probe() fires */
if (!device_is_registered(&codec->core.dev))
@@ -190,11 +193,11 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
if (!binder->platforms || !binder->codecs)
return -ENOMEM;
- binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL);
+ binder->codecs->name = devm_kstrdup_const(dev, dev_name(&codec->core.dev), GFP_KERNEL);
if (!binder->codecs->name)
return -ENOMEM;
- binder->platforms->name = mach->mach_params.platform;
+ binder->platforms->name = dev_name(dev);
binder->num_platforms = 1;
binder->codecs->dai_name = "codec-probing-DAI";
binder->num_codecs = 1;
@@ -203,7 +206,19 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
- card->name = binder->codecs->name;
+ if (pdata->obsolete_card_names) {
+ card->name = devm_kasprintf(dev, GFP_KERNEL, "hdaudioB%dD%d", codec->bus->core.idx,
+ codec->core.addr);
+ if (!card->name)
+ return -ENOMEM;
+ } else {
+ card->driver_name = "avs_hdaudio";
+ if (hda_codec_is_display(codec))
+ card->long_name = card->name = "AVS HDMI";
+ else
+ card->long_name = card->name = "AVS HD-Audio";
+ }
+
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = binder;
@@ -212,15 +227,24 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
if (hda_codec_is_display(codec))
card->late_probe = avs_card_late_probe;
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_hdaudio_driver_ids[] = {
+ {
+ .name = "avs_hdaudio",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids);
+
static struct platform_driver avs_hdaudio_driver = {
.probe = avs_hdaudio_probe,
.driver = {
.name = "avs_hdaudio",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_hdaudio_driver_ids,
};
module_platform_driver(avs_hdaudio_driver)
@@ -228,4 +252,3 @@ module_platform_driver(avs_hdaudio_driver)
MODULE_DESCRIPTION("Intel HD-Audio machine driver");
MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_hdaudio");
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
index bc3065c6ceda..9a6b89ffdf14 100644
--- a/sound/soc/intel/avs/boards/i2s_test.c
+++ b/sound/soc/intel/avs/boards/i2s_test.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -12,8 +12,9 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include "../utils.h"
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -24,18 +25,19 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
if (!dl->name || !dl->cpus)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
- dl->codecs = &asoc_dummy_dlc;
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
+ dl->codecs = &snd_soc_dummy_dlc;
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
dl->platforms = platform;
@@ -43,136 +45,85 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->id = 0;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
return 0;
}
-static int avs_create_dapm_routes(struct device *dev, int ssp_port,
- struct snd_soc_dapm_route **routes, int *num_routes)
-{
- struct snd_soc_dapm_route *dr;
- const int num_dr = 2;
-
- dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return -ENOMEM;
-
- dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
- dr[0].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
- if (!dr[0].sink || !dr[0].source)
- return -ENOMEM;
-
- dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
- dr[1].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
- if (!dr[1].sink || !dr[1].source)
- return -ENOMEM;
-
- *routes = dr;
- *num_routes = num_dr;
-
- return 0;
-}
-
-static int avs_create_dapm_widgets(struct device *dev, int ssp_port,
- struct snd_soc_dapm_widget **widgets, int *num_widgets)
-{
- struct snd_soc_dapm_widget *dw;
- const int num_dw = 2;
-
- dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL);
- if (!dw)
- return -ENOMEM;
-
- dw[0].id = snd_soc_dapm_hp;
- dw[0].reg = SND_SOC_NOPM;
- dw[0].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
- if (!dw[0].name)
- return -ENOMEM;
-
- dw[1].id = snd_soc_dapm_mic;
- dw[1].reg = SND_SOC_NOPM;
- dw[1].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
- if (!dw[1].name)
- return -ENOMEM;
-
- *widgets = dw;
- *num_widgets = num_dw;
-
- return 0;
-}
-
static int avs_i2s_test_probe(struct platform_device *pdev)
{
- struct snd_soc_dapm_widget *widgets;
- struct snd_soc_dapm_route *routes;
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
- const char *pname;
- int num_routes, num_widgets;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ if (!avs_mach_singular_ssp(mach)) {
+ dev_err(dev, "Invalid SSP configuration\n");
+ return -EINVAL;
+ }
+ ssp_port = avs_mach_ssp_port(mach);
+
+ if (!avs_mach_singular_tdm(mach, ssp_port)) {
+ dev_err(dev, "Invalid TDM configuration\n");
+ return -EINVAL;
+ }
+ tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
- card->name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-loopback", ssp_port);
+ if (pdata->obsolete_card_names) {
+ card->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("ssp", "-loopback", ssp_port, tdm_slot));
+ } else {
+ card->driver_name = "avs_i2s_test";
+ card->long_name = card->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("AVS I2S TEST-", "",
+ ssp_port, tdm_slot));
+ }
if (!card->name)
return -ENOMEM;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d\n", ret);
return ret;
}
- ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
- if (ret) {
- dev_err(dev, "Failed to create dapm routes: %d\n", ret);
- return ret;
- }
-
- ret = avs_create_dapm_widgets(dev, ssp_port, &widgets, &num_widgets);
- if (ret) {
- dev_err(dev, "Failed to create dapm widgets: %d\n", ret);
- return ret;
- }
-
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
card->num_links = 1;
- card->dapm_routes = routes;
- card->num_dapm_routes = num_routes;
- card->dapm_widgets = widgets;
- card->num_dapm_widgets = num_widgets;
card->fully_routed = true;
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_i2s_test_driver_ids[] = {
+ {
+ .name = "avs_i2s_test",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids);
+
static struct platform_driver avs_i2s_test_driver = {
.probe = avs_i2s_test_probe,
.driver = {
.name = "avs_i2s_test",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_i2s_test_driver_ids,
};
module_platform_driver(avs_i2s_test_driver);
+MODULE_DESCRIPTION("Intel i2s test machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_i2s_test");
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
index b9b20562c691..e9a87804f918 100644
--- a/sound/soc/intel/avs/boards/max98357a.c
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -12,6 +12,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include "../utils.h"
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Spk"),
@@ -45,7 +46,7 @@ avs_max98357a_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_pa
return 0;
}
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -56,30 +57,31 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "MX98357A:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "HiFi");
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
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;
- dl->dpcm_playback = 1;
+ dl->playback_only = 1;
*dai_link = dl;
@@ -90,16 +92,19 @@ static int avs_max98357a_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -109,7 +114,12 @@ static int avs_max98357a_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
- card->name = "avs_max98357a";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_max98357a";
+ } else {
+ card->driver_name = "avs_max98357a";
+ card->long_name = card->name = "AVS I2S MAX98357A";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
@@ -122,22 +132,27 @@ static int avs_max98357a_probe(struct platform_device *pdev)
card->num_dapm_routes = ARRAY_SIZE(card_base_routes);
card->fully_routed = true;
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_max98357a_driver_ids[] = {
+ {
+ .name = "avs_max98357a",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids);
+
static struct platform_driver avs_max98357a_driver = {
.probe = avs_max98357a_probe,
.driver = {
.name = "avs_max98357a",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_max98357a_driver_ids,
};
module_platform_driver(avs_max98357a_driver)
+MODULE_DESCRIPTION("Intel max98357a machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_max98357a");
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 3833251ade26..8b45b643ca29 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -12,6 +12,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include "../utils.h"
#define MAX98373_DEV0_NAME "i2c-MX98373:00"
#define MAX98373_DEV1_NAME "i2c-MX98373:01"
@@ -66,7 +67,7 @@ avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_par
static int avs_max98373_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int ret, i;
@@ -94,7 +95,7 @@ static const struct snd_soc_ops avs_max98373_ops = {
.hw_params = avs_max98373_hw_params,
};
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -105,15 +106,15 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
- 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;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV0_NAME);
dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV1_NAME);
@@ -122,6 +123,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
!dl->codecs[1].name || !dl->codecs[1].dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 2;
dl->platforms = platform;
@@ -131,8 +133,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->be_hw_params_fixup = avs_max98373_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
dl->ignore_pmdown_time = 1;
dl->ops = &avs_max98373_ops;
@@ -145,16 +145,19 @@ static int avs_max98373_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -164,7 +167,12 @@ static int avs_max98373_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
- card->name = "avs_max98373";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_max98373";
+ } else {
+ card->driver_name = "avs_max98373";
+ card->long_name = card->name = "AVS I2S MAX98373";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
@@ -179,22 +187,27 @@ static int avs_max98373_probe(struct platform_device *pdev)
card->num_dapm_routes = ARRAY_SIZE(card_base_routes);
card->fully_routed = true;
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_max98373_driver_ids[] = {
+ {
+ .name = "avs_max98373",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids);
+
static struct platform_driver avs_max98373_driver = {
.probe = avs_max98373_probe,
.driver = {
.name = "avs_max98373",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_max98373_driver_ids,
};
module_platform_driver(avs_max98373_driver)
+MODULE_DESCRIPTION("Intel max98373 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_max98373");
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
index 09b231bf4e6d..db073125fa4d 100644
--- a/sound/soc/intel/avs/boards/max98927.c
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -12,6 +12,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include "../utils.h"
#define MAX98927_DEV0_NAME "i2c-MX98927:00"
#define MAX98927_DEV1_NAME "i2c-MX98927:01"
@@ -66,7 +67,7 @@ avs_max98927_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_par
static int avs_max98927_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int ret = 0;
int i;
@@ -91,7 +92,7 @@ static const struct snd_soc_ops avs_max98927_ops = {
.hw_params = avs_max98927_hw_params,
};
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -102,15 +103,15 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
- 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;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV0_NAME);
dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_CODEC_NAME);
dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98927_DEV1_NAME);
@@ -119,17 +120,16 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
!dl->codecs[1].name || !dl->codecs[1].dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 2;
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;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
dl->ignore_pmdown_time = 1;
dl->ops = &avs_max98927_ops;
@@ -142,16 +142,19 @@ static int avs_max98927_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -161,7 +164,12 @@ static int avs_max98927_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
- card->name = "avs_max98927";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_max98927";
+ } else {
+ card->driver_name = "avs_max98927";
+ card->long_name = card->name = "AVS I2S MAX98927";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
@@ -176,22 +184,27 @@ static int avs_max98927_probe(struct platform_device *pdev)
card->num_dapm_routes = ARRAY_SIZE(card_base_routes);
card->fully_routed = true;
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_max98927_driver_ids[] = {
+ {
+ .name = "avs_max98927",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids);
+
static struct platform_driver avs_max98927_driver = {
.probe = avs_max98927_probe,
.driver = {
.name = "avs_max98927",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_max98927_driver_ids,
};
module_platform_driver(avs_max98927_driver)
+MODULE_DESCRIPTION("Intel max98927 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_max98927");
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index 38c5087d98e9..d44edacbfc9a 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -16,14 +16,14 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../../codecs/nau8825.h"
+#include "../utils.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
static int
avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
int ret;
@@ -66,7 +66,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "Headset Mic", NULL, "Platform Clock" },
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
@@ -87,7 +87,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;
@@ -95,7 +96,7 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
* 4 buttons here map to the google Reference headset.
* The use of these buttons can be decided by the user space.
*/
- ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
jack, pins, num_pins);
if (ret)
@@ -106,12 +107,12 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+ return snd_soc_component_set_jack(snd_soc_rtd_to_codec(runtime, 0)->component, jack, NULL);
}
static void avs_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int
@@ -138,8 +139,8 @@ avs_nau8825_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_para
static int avs_nau8825_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
+ struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtm, 0);
int ret = 0;
switch (cmd) {
@@ -170,7 +171,7 @@ static const struct snd_soc_ops avs_nau8825_ops = {
.trigger = avs_nau8825_trigger,
};
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -181,34 +182,33 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10508825:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, SKL_NUVOTON_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
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;
dl->ops = &avs_nau8825_ops;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
@@ -244,17 +244,20 @@ static int avs_nau8825_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct snd_soc_jack *jack;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -265,7 +268,12 @@ static int avs_nau8825_probe(struct platform_device *pdev)
if (!jack || !card)
return -ENOMEM;
- card->name = "avs_nau8825";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_nau8825";
+ } else {
+ card->driver_name = "avs_nau8825";
+ card->long_name = card->name = "AVS I2S NAU8825";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->suspend_pre = avs_card_suspend_pre;
@@ -281,22 +289,27 @@ static int avs_nau8825_probe(struct platform_device *pdev)
card->fully_routed = true;
snd_soc_card_set_drvdata(card, jack);
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_nau8825_driver_ids[] = {
+ {
+ .name = "avs_nau8825",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids);
+
static struct platform_driver avs_nau8825_driver = {
.probe = avs_nau8825_probe,
.driver = {
.name = "avs_nau8825",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_nau8825_driver_ids,
};
module_platform_driver(avs_nau8825_driver)
+MODULE_DESCRIPTION("Intel nau8825 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_nau8825");
diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c
new file mode 100644
index 000000000000..b5bebadbbcb2
--- /dev/null
+++ b/sound/soc/intel/avs/boards/pcm3168a.c
@@ -0,0 +1,155 @@
+// 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>
+#include <sound/soc-acpi.h>
+#include "../utils.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 snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card;
+ int ret;
+
+ mach = dev_get_platdata(dev);
+ pdata = mach->pdata;
+
+ 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;
+
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_pcm3168a";
+ } else {
+ card->driver_name = "avs_pcm3168a";
+ card->long_name = card->name = "AVS I2S 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_deferrable_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/probe.c b/sound/soc/intel/avs/boards/probe.c
index 411acaee74f9..73884f8a535c 100644
--- a/sound/soc/intel/avs/boards/probe.c
+++ b/sound/soc/intel/avs/boards/probe.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -9,56 +9,75 @@
#include <linux/device.h>
#include <linux/module.h>
#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
-SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI")));
-SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform")));
+static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links)
+{
+ struct snd_soc_dai_link *dl;
-static struct snd_soc_dai_link probe_mb_dai_links[] = {
- {
- .name = "Compress Probe Capture",
- .nonatomic = 1,
- SND_SOC_DAILINK_REG(probe_cp, dummy, platform),
- },
-};
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ if (!dl)
+ return -ENOMEM;
+
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->platforms = devm_kzalloc(dev, sizeof(*dl->platforms), GFP_KERNEL);
+ if (!dl->cpus || !dl->platforms)
+ return -ENOMEM;
+
+ dl->name = "Compress Probe Capture";
+ dl->cpus->dai_name = "Probe Extraction CPU DAI";
+ dl->num_cpus = 1;
+ dl->codecs = &snd_soc_dummy_dlc;
+ dl->num_codecs = 1;
+ dl->platforms->name = dev_name(dev);
+ dl->num_platforms = 1;
+ dl->nonatomic = 1;
+
+ *links = dl;
+ *num_links = 1;
+ return 0;
+}
static int avs_probe_mb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct snd_soc_acpi_mach *mach;
struct snd_soc_card *card;
int ret;
- mach = dev_get_platdata(dev);
-
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
- card->name = "avs_probe_mb";
+ ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links);
+ if (ret)
+ return ret;
+
+ card->driver_name = "avs_probe_mb";
+ card->long_name = card->name = "AVS PROBE";
card->dev = dev;
card->owner = THIS_MODULE;
- card->dai_link = probe_mb_dai_links;
- card->num_links = ARRAY_SIZE(probe_mb_dai_links);
card->fully_routed = true;
- ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_probe_mb_driver_ids[] = {
+ {
+ .name = "avs_probe_mb",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids);
+
static struct platform_driver avs_probe_mb_driver = {
.probe = avs_probe_mb_probe,
.driver = {
.name = "avs_probe_mb",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_probe_mb_driver_ids,
};
module_platform_driver(avs_probe_mb_driver);
+MODULE_DESCRIPTION("Intel probe machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_probe_mb");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index ebfee54814ce..a689f4c80867 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -13,6 +13,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../../codecs/rt274.h"
+#include "../utils.h"
#define AVS_RT274_FREQ_OUT 24000000
#define AVS_RT274_BE_FIXUP_RATE 48000
@@ -26,8 +27,7 @@ static const struct snd_kcontrol_new card_controls[] = {
static int
avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
int ret;
@@ -74,7 +74,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{"MIC", NULL, "Platform Clock"},
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
@@ -87,21 +87,24 @@ static struct snd_soc_jack_pin card_headset_pins[] = {
static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_soc_jack_pin *pins;
struct snd_soc_jack *jack;
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int num_pins, ret;
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;
- ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins,
+ num_pins);
if (ret)
return ret;
@@ -114,14 +117,14 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
return 0;
}
static void avs_rt274_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -144,7 +147,7 @@ static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc
return 0;
}
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -155,33 +158,32 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT274_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
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;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
@@ -207,17 +209,20 @@ static int avs_rt274_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct snd_soc_jack *jack;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -228,7 +233,12 @@ static int avs_rt274_probe(struct platform_device *pdev)
if (!jack || !card)
return -ENOMEM;
- card->name = "avs_rt274";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_rt274";
+ } else {
+ card->driver_name = "avs_rt274";
+ card->long_name = card->name = "AVS I2S ALC274";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->suspend_pre = avs_card_suspend_pre;
@@ -244,22 +254,27 @@ static int avs_rt274_probe(struct platform_device *pdev)
card->fully_routed = true;
snd_soc_card_set_drvdata(card, jack);
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_rt274_driver_ids[] = {
+ {
+ .name = "avs_rt274",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids);
+
static struct platform_driver avs_rt274_driver = {
.probe = avs_rt274_probe,
.driver = {
.name = "avs_rt274",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_rt274_driver_ids,
};
module_platform_driver(avs_rt274_driver);
+MODULE_DESCRIPTION("Intel rt274 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_rt274");
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index 84cf9a0c8dfe..4c9ac545555a 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -13,6 +13,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../../codecs/rt286.h"
+#include "../utils.h"
#define RT286_CODEC_DAI "rt286-aif1"
@@ -37,7 +38,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{"Speaker", NULL, "SPOL"},
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
@@ -58,21 +59,22 @@ 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;
- ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
- pins, num_pins);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0,
+ jack, pins, num_pins);
if (ret)
return ret;
- return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+ return snd_soc_component_set_jack(snd_soc_rtd_to_codec(runtime, 0)->component, jack, NULL);
}
static void avs_rt286_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -98,8 +100,8 @@ static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc
static int
avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
@@ -113,7 +115,7 @@ static const struct snd_soc_ops avs_rt286_ops = {
.hw_params = avs_rt286_hw_params,
};
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -124,34 +126,33 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT286_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
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;
dl->ops = &avs_rt286_ops;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
@@ -177,17 +178,21 @@ static int avs_rt286_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct snd_soc_jack *jack;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
+
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -198,7 +203,12 @@ static int avs_rt286_probe(struct platform_device *pdev)
if (!jack || !card)
return -ENOMEM;
- card->name = "avs_rt286";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_rt286";
+ } else {
+ card->driver_name = "avs_rt286";
+ card->long_name = card->name = "AVS I2S ALC286";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->suspend_pre = avs_card_suspend_pre;
@@ -214,22 +224,27 @@ static int avs_rt286_probe(struct platform_device *pdev)
card->fully_routed = true;
snd_soc_card_set_drvdata(card, jack);
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_rt286_driver_ids[] = {
+ {
+ .name = "avs_rt286",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids);
+
static struct platform_driver avs_rt286_driver = {
.probe = avs_rt286_probe,
.driver = {
.name = "avs_rt286",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_rt286_driver_ids,
};
module_platform_driver(avs_rt286_driver);
+MODULE_DESCRIPTION("Intel rt286 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_rt286");
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index 3b0e2b1a3251..2d7a7748d577 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -14,6 +14,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../../codecs/rt298.h"
+#include "../utils.h"
#define RT298_CODEC_DAI "rt298-aif1"
@@ -48,7 +49,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{"Speaker", NULL, "SPOL"},
};
-static struct snd_soc_jack_pin card_headset_pins[] = {
+static const struct snd_soc_jack_pin card_headset_pins[] = {
{
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
@@ -69,21 +70,22 @@ 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;
- ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
- pins, num_pins);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0,
+ jack, pins, num_pins);
if (ret)
return ret;
- return snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+ return snd_soc_component_set_jack(snd_soc_rtd_to_codec(runtime, 0)->component, jack, NULL);
}
static void avs_rt298_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
@@ -109,8 +111,8 @@ static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc
static int
avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int clk_freq;
int ret;
@@ -130,7 +132,7 @@ static const struct snd_soc_ops avs_rt298_ops = {
.hw_params = avs_rt298_hw_params,
};
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -141,37 +143,36 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT298_CODEC_DAI);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
dl->platforms = platform;
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;
dl->ops = &avs_rt298_ops;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
@@ -197,17 +198,20 @@ static int avs_rt298_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct snd_soc_jack *jack;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -218,7 +222,12 @@ static int avs_rt298_probe(struct platform_device *pdev)
if (!jack || !card)
return -ENOMEM;
- card->name = "avs_rt298";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_rt298";
+ } else {
+ card->driver_name = "avs_rt298";
+ card->long_name = card->name = "AVS I2S ALC298";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->suspend_pre = avs_card_suspend_pre;
@@ -234,22 +243,27 @@ static int avs_rt298_probe(struct platform_device *pdev)
card->fully_routed = true;
snd_soc_card_set_drvdata(card, jack);
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_rt298_driver_ids[] = {
+ {
+ .name = "avs_rt298",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids);
+
static struct platform_driver avs_rt298_driver = {
.probe = avs_rt298_probe,
.driver = {
.name = "avs_rt298",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_rt298_driver_ids,
};
module_platform_driver(avs_rt298_driver);
+MODULE_DESCRIPTION("Intel rt298 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_rt298");
diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c
new file mode 100644
index 000000000000..22139eaad83a
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5514.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2023 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt5514.h"
+#include "../utils.h"
+
+#define RT5514_CODEC_DAI "rt5514-aif1"
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+ /* DMIC */
+ { "DMIC1L", NULL, "DMIC" },
+ { "DMIC1R", NULL, "DMIC" },
+ { "DMIC2L", NULL, "DMIC" },
+ { "DMIC2R", NULL, "DMIC" },
+};
+
+static int avs_rt5514_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(runtime->card);
+ int ret = snd_soc_dapm_ignore_suspend(dapm, "DMIC");
+
+ if (ret)
+ dev_err(runtime->dev, "DMIC - Ignore suspend failed = %d\n", ret);
+
+ return ret;
+}
+
+static int avs_rt5514_be_fixup(struct snd_soc_pcm_runtime *runtime,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 4;
+
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+
+ return 0;
+}
+
+static int avs_rt5514_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16);
+ if (ret < 0) {
+ dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "set sysclk err: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt5514_ops = {
+ .hw_params = avs_rt5514_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ 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), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5514:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5514_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ platform->name = dev_name(dev);
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ 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_CBC_CFC;
+ dl->init = avs_rt5514_codec_init;
+ dl->be_hw_params_fixup = avs_rt5514_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->capture_only = 1;
+ dl->ops = &avs_rt5514_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_rt5514_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ int ssp_port, tdm_slot, ret;
+
+ mach = dev_get_platdata(dev);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
+
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_rt5514";
+ } else {
+ card->driver_name = "avs_rt5514";
+ card->long_name = card->name = "AVS I2S ALC5514";
+ }
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_base_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_base_routes);
+ card->fully_routed = true;
+
+ return devm_snd_soc_register_deferrable_card(dev, card);
+}
+
+static const struct platform_device_id avs_rt5514_driver_ids[] = {
+ {
+ .name = "avs_rt5514",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids);
+
+static struct platform_driver avs_rt5514_driver = {
+ .probe = avs_rt5514_probe,
+ .driver = {
+ .name = "avs_rt5514",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = avs_rt5514_driver_ids,
+};
+
+module_platform_driver(avs_rt5514_driver);
+
+MODULE_DESCRIPTION("Intel rt5514 machine driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c
new file mode 100644
index 000000000000..2990d32f2301
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5640.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022-2025 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt5640.h"
+#include "../utils.h"
+
+#define AVS_RT5640_MCLK_HZ 19200000
+#define RT5640_CODEC_DAI "rt5640-aif1"
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ { "Headphone Jack", NULL, "HPOR" },
+ { "Headphone Jack", NULL, "HPOL" },
+ { "IN2P", NULL, "Mic Jack" },
+ { "IN2P", NULL, "MICBIAS1" },
+ { "Speaker", NULL, "SPOLP" },
+ { "Speaker", NULL, "SPOLN" },
+ { "Speaker", NULL, "SPORP" },
+ { "Speaker", NULL, "SPORN" },
+};
+
+static const struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt5640_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ int num_pins, ret;
+
+ 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);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins,
+ num_pins);
+ if (ret)
+ return ret;
+
+ snd_soc_component_set_jack(codec_dai->component, jack, NULL);
+ snd_soc_dapm_set_idle_bias(dapm, false);
+
+ return 0;
+}
+
+static void avs_rt5640_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+
+ snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+}
+
+static int avs_rt5640_be_fixup(struct snd_soc_pcm_runtime *runtime,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* Format 24/32 is MSB-aligned for HDAudio and LSB-aligned for I2S. */
+ if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
+ snd_mask_set_format(fmask, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_rt5640_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+ int ret;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_MCLK, AVS_RT5640_MCLK_HZ,
+ params_rate(params) * 512);
+ if (ret < 0) {
+ dev_err(runtime->dev, "Set codec PLL failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(runtime->dev, "Set codec SCLK failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = rt5640_sel_asrc_clk_src(codec_dai->component,
+ RT5640_DA_STEREO_FILTER | RT5640_AD_STEREO_FILTER |
+ RT5640_DA_MONO_L_FILTER | RT5640_DA_MONO_R_FILTER |
+ RT5640_AD_MONO_L_FILTER | RT5640_AD_MONO_R_FILTER,
+ RT5640_CLK_SEL_ASRC);
+ if (ret)
+ dev_err(runtime->dev, "Set codec ASRC failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt5640_ops = {
+ .hw_params = avs_rt5640_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
+ struct snd_soc_acpi_mach *mach,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+ u32 uid = 0;
+ int ret;
+
+ if (mach->uid) {
+ ret = kstrtou32(mach->uid, 0, &uid);
+ if (ret)
+ return ret;
+ uid--; /* 0-based indexing. */
+ }
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ 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), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5640:0%d", uid);
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5640_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ platform->name = dev_name(dev);
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ 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_CBC_CFC;
+ dl->init = avs_rt5640_codec_init;
+ dl->exit = avs_rt5640_codec_exit;
+ dl->be_hw_params_fixup = avs_rt5640_be_fixup;
+ dl->ops = &avs_rt5640_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI);
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
+}
+
+static int avs_rt5640_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jack;
+ int ssp_port, tdm_slot, ret;
+
+ mach = dev_get_platdata(dev);
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
+
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, mach, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!jack || !card)
+ return -ENOMEM;
+
+ if (mach->uid) {
+ card->name = devm_kasprintf(dev, GFP_KERNEL, "AVS I2S ALC5640.%s", mach->uid);
+ if (!card->name)
+ return -ENOMEM;
+ } else {
+ card->name = "AVS I2S ALC5640";
+ }
+ card->driver_name = "avs_rt5640";
+ card->long_name = card->name;
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ 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;
+ snd_soc_card_set_drvdata(card, jack);
+
+ return devm_snd_soc_register_deferrable_card(dev, card);
+}
+
+static const struct platform_device_id avs_rt5640_driver_ids[] = {
+ {
+ .name = "avs_rt5640",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids);
+
+static struct platform_driver avs_rt5640_driver = {
+ .probe = avs_rt5640_probe,
+ .driver = {
+ .name = "avs_rt5640",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = avs_rt5640_driver_ids,
+};
+
+module_platform_driver(avs_rt5640_driver);
+
+MODULE_DESCRIPTION("Intel rt5640 machine driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
new file mode 100644
index 000000000000..68fea325376a
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022-2023 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt5663.h"
+#include "../utils.h"
+
+#define RT5663_CODEC_DAI "rt5663-aif"
+
+struct rt5663_private {
+ struct snd_soc_jack jack;
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ /* HP jack connectors */
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* Mic jacks */
+ { "IN1P", NULL, "Headset Mic" },
+ { "IN1N", NULL, "Headset Mic" },
+};
+
+static const struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_card *card = runtime->card;
+ struct rt5663_private *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ int num_pins, ret;
+
+ jack = &priv->jack;
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
+ pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+
+ return 0;
+}
+
+static void avs_rt5663_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(runtime, 0)->component, NULL, NULL);
+}
+
+static int
+avs_rt5663_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSPN to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_rt5663_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
+ rt5663_sel_asrc_clk_src(codec_dai->component,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt5663_ops = {
+ .hw_params = avs_rt5663_hw_params,
+};
+
+
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ 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), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5663:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5663_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ platform->name = dev_name(dev);
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ 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_CBC_CFC;
+ dl->init = avs_rt5663_codec_init;
+ dl->exit = avs_rt5663_codec_exit;
+ dl->be_hw_params_fixup = avs_rt5663_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->ops = &avs_rt5663_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI);
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
+}
+
+static int avs_rt5663_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
+ struct snd_soc_card *card;
+ struct rt5663_private *priv;
+ struct device *dev = &pdev->dev;
+ int ssp_port, tdm_slot, ret;
+
+ mach = dev_get_platdata(dev);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
+
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!priv || !card)
+ return -ENOMEM;
+
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_rt5663";
+ } else {
+ card->driver_name = "avs_rt5663";
+ card->long_name = card->name = "AVS I2S ALC5663";
+ }
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ 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;
+ snd_soc_card_set_drvdata(card, priv);
+
+ return devm_snd_soc_register_deferrable_card(dev, card);
+}
+
+static const struct platform_device_id avs_rt5663_driver_ids[] = {
+ {
+ .name = "avs_rt5663",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids);
+
+static struct platform_driver avs_rt5663_driver = {
+ .probe = avs_rt5663_probe,
+ .driver = {
+ .name = "avs_rt5663",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = avs_rt5663_driver_ids,
+};
+
+module_platform_driver(avs_rt5663_driver);
+
+MODULE_DESCRIPTION("Intel rt5663 machine driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 7142a67900bf..81863728da1d 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -21,6 +21,7 @@
#include <sound/soc-acpi.h>
#include "../../common/soc-intel-quirks.h"
#include "../../../codecs/rt5682.h"
+#include "../utils.h"
#define AVS_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
#define AVS_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
@@ -79,14 +80,32 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "IN1P", NULL, "Headset Mic" },
};
+static const struct snd_soc_jack_pin card_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
- struct snd_soc_jack *jack;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
struct snd_soc_card *card = runtime->card;
- int ret;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ int num_pins, ret;
jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_jack_pins);
+
+ pins = devm_kmemdup_array(card->dev, card_jack_pins, num_pins,
+ sizeof(card_jack_pins[0]), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
/* Need to enable ASRC function for 24MHz mclk rate */
if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
@@ -95,12 +114,10 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC);
}
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack);
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
+ pins, num_pins);
if (ret) {
dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
@@ -122,47 +139,44 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
static void avs_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
+ snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component, NULL, NULL);
}
static int
avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
- int clk_id, clk_freq;
- int pll_out, ret;
+ struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
+ int pll_source, freq_in, freq_out;
+ int ret;
if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
- clk_id = RT5682_PLL1_S_MCLK;
+ pll_source = RT5682_PLL1_S_MCLK;
if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
- clk_freq = 24000000;
+ freq_in = 24000000;
else
- clk_freq = 19200000;
+ freq_in = 19200000;
} else {
- clk_id = RT5682_PLL1_S_BCLK1;
- clk_freq = params_rate(params) * 50;
+ pll_source = RT5682_PLL1_S_BCLK1;
+ freq_in = params_rate(params) * 50;
}
- pll_out = params_rate(params) * 512;
+ freq_out = params_rate(params) * 512;
- ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, pll_source, freq_in, freq_out);
if (ret < 0)
- dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+ dev_err(runtime->dev, "Set PLL failed: %d\n", ret);
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN);
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, freq_out, SND_SOC_CLOCK_IN);
if (ret < 0)
- dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+ dev_err(runtime->dev, "Set sysclk failed: %d\n", ret);
- /* slot_width should equal or large than data length, set them be the same */
+ /* slot_width should be equal or larger than data length. */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params));
- if (ret < 0) {
- dev_err(runtime->dev, "set TDM slot err:%d\n", ret);
- return ret;
- }
+ if (ret < 0)
+ dev_err(runtime->dev, "Set TDM slot failed: %d\n", ret);
- return 0;
+ return ret;
}
static const struct snd_soc_ops avs_rt5682_ops = {
@@ -190,7 +204,7 @@ avs_rt5682_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_param
return 0;
}
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -201,33 +215,33 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00");
dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, AVS_RT5682_CODEC_DAI_NAME);
if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 1;
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_CBC_CFC;
dl->init = avs_rt5682_codec_init;
dl->exit = avs_rt5682_codec_exit;
dl->be_hw_params_fixup = avs_rt5682_be_fixup;
dl->ops = &avs_rt5682_ops;
dl->nonatomic = 1;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
*dai_link = dl;
@@ -253,11 +267,11 @@ static int avs_rt5682_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct snd_soc_jack *jack;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
if (pdev->id_entry && pdev->id_entry->driver_data)
avs_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
@@ -266,10 +280,13 @@ static int avs_rt5682_probe(struct platform_device *pdev)
dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk);
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -280,7 +297,12 @@ static int avs_rt5682_probe(struct platform_device *pdev)
if (!jack || !card)
return -ENOMEM;
- card->name = "avs_rt5682";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_rt5682";
+ } else {
+ card->driver_name = "avs_rt5682";
+ card->long_name = card->name = "AVS I2S ALC5682";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->suspend_pre = avs_card_suspend_pre;
@@ -296,23 +318,28 @@ static int avs_rt5682_probe(struct platform_device *pdev)
card->fully_routed = true;
snd_soc_card_set_drvdata(card, jack);
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_rt5682_driver_ids[] = {
+ {
+ .name = "avs_rt5682",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids);
+
static struct platform_driver avs_rt5682_driver = {
.probe = avs_rt5682_probe,
.driver = {
.name = "avs_rt5682",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_rt5682_driver_ids,
};
module_platform_driver(avs_rt5682_driver)
+MODULE_DESCRIPTION("Intel rt5682 machine driver");
MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_rt5682");
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index 7324869d6132..ae0e6e27a8b8 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -14,6 +14,7 @@
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "../../../codecs/nau8825.h"
+#include "../utils.h"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
@@ -36,8 +37,6 @@ static const struct snd_kcontrol_new card_controls[] = {
static const struct snd_soc_dapm_widget card_widgets[] = {
SND_SOC_DAPM_SPK("Left Speaker", NULL),
SND_SOC_DAPM_SPK("Right Speaker", NULL),
- SND_SOC_DAPM_SPK("DP1", NULL),
- SND_SOC_DAPM_SPK("DP2", NULL),
};
static const struct snd_soc_dapm_route card_base_routes[] = {
@@ -50,12 +49,12 @@ static int avs_ssm4567_codec_init(struct snd_soc_pcm_runtime *runtime)
int ret;
/* Slot 1 for left */
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48);
if (ret < 0)
return ret;
/* Slot 2 for right */
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48);
if (ret < 0)
return ret;
@@ -82,7 +81,7 @@ avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_para
return 0;
}
-static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
struct snd_soc_dai_link **dai_link)
{
struct snd_soc_dai_link_component *platform;
@@ -93,15 +92,15 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
if (!dl || !platform)
return -ENOMEM;
- platform->name = platform_name;
-
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
- 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;
- dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot));
dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:00");
dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:01");
@@ -110,18 +109,17 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
!dl->codecs[1].name || !dl->codecs[1].dai_name)
return -ENOMEM;
+ platform->name = dev_name(dev);
dl->num_cpus = 1;
dl->num_codecs = 2;
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;
dl->no_pcm = 1;
- dl->dpcm_capture = 1;
- dl->dpcm_playback = 1;
dl->ignore_pmdown_time = 1;
*dai_link = dl;
@@ -133,16 +131,19 @@ static int avs_ssm4567_probe(struct platform_device *pdev)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
- const char *pname;
- int ssp_port, ret;
+ int ssp_port, tdm_slot, ret;
mach = dev_get_platdata(dev);
- pname = mach->mach_params.platform;
- ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+ pdata = mach->pdata;
+
+ ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot);
+ if (ret)
+ return ret;
- ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link);
if (ret) {
dev_err(dev, "Failed to create dai link: %d", ret);
return ret;
@@ -152,7 +153,12 @@ static int avs_ssm4567_probe(struct platform_device *pdev)
if (!card)
return -ENOMEM;
- card->name = "avs_ssm4567-adi";
+ if (pdata->obsolete_card_names) {
+ card->name = "avs_ssm4567";
+ } else {
+ card->driver_name = "avs_ssm4567";
+ card->long_name = card->name = "AVS I2S SSM4567";
+ }
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = dai_link;
@@ -166,24 +172,28 @@ static int avs_ssm4567_probe(struct platform_device *pdev)
card->dapm_routes = card_base_routes;
card->num_dapm_routes = ARRAY_SIZE(card_base_routes);
card->fully_routed = true;
- card->disable_route_checks = true;
- ret = snd_soc_fixup_dai_links_platform_name(card, pname);
- if (ret)
- return ret;
-
- return devm_snd_soc_register_card(dev, card);
+ return devm_snd_soc_register_deferrable_card(dev, card);
}
+static const struct platform_device_id avs_ssm4567_driver_ids[] = {
+ {
+ .name = "avs_ssm4567",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids);
+
static struct platform_driver avs_ssm4567_driver = {
.probe = avs_ssm4567_probe,
.driver = {
.name = "avs_ssm4567",
.pm = &snd_soc_pm_ops,
},
+ .id_table = avs_ssm4567_driver_ids,
};
module_platform_driver(avs_ssm4567_driver)
+MODULE_DESCRIPTION("Intel ssm4567 machine driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:avs_ssm4567");
diff --git a/sound/soc/intel/avs/cldma.c b/sound/soc/intel/avs/cldma.c
index d7a9390b5e48..61326d7059b1 100644
--- a/sound/soc/intel/avs/cldma.c
+++ b/sound/soc/intel/avs/cldma.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -35,7 +35,7 @@ struct hda_cldma {
unsigned int buffer_size;
unsigned int num_periods;
- unsigned int stream_tag;
+ unsigned char stream_tag;
void __iomem *sd_addr;
struct snd_dma_buffer dmab_data;
@@ -248,32 +248,20 @@ void hda_cldma_setup(struct hda_cldma *cl)
snd_hdac_stream_writel(cl, CL_SPBFCTL, 1);
}
-static irqreturn_t cldma_irq_handler(int irq, void *dev_id)
+void hda_cldma_interrupt(struct hda_cldma *cl)
{
- struct hda_cldma *cl = dev_id;
- u32 adspis;
-
- adspis = snd_hdac_adsp_readl(cl, AVS_ADSP_REG_ADSPIS);
- if (adspis == UINT_MAX)
- return IRQ_NONE;
- if (!(adspis & AVS_ADSP_ADSPIS_CLDMA))
- return IRQ_NONE;
-
- cl->sd_status = snd_hdac_stream_readb(cl, SD_STS);
- dev_warn(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status);
-
/* disable CLDMA interrupt */
snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0);
- complete(&cl->completion);
+ cl->sd_status = snd_hdac_stream_readb(cl, SD_STS);
+ dev_dbg(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status);
- return IRQ_HANDLED;
+ complete(&cl->completion);
}
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
unsigned int buffer_size)
{
- struct pci_dev *pci = to_pci_dev(bus->dev);
int ret;
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, buffer_size, &cl->dmab_data);
@@ -281,8 +269,10 @@ int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp
return ret;
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, bus->dev, BDL_SIZE, &cl->dmab_bdl);
- if (ret < 0)
- goto alloc_err;
+ if (ret < 0) {
+ snd_dma_free_pages(&cl->dmab_data);
+ return ret;
+ }
cl->dev = bus->dev;
cl->bus = bus;
@@ -290,27 +280,11 @@ int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp
cl->buffer_size = buffer_size;
cl->sd_addr = dsp_ba + AZX_CL_SD_BASE;
- ret = pci_request_irq(pci, 0, cldma_irq_handler, NULL, cl, "CLDMA");
- if (ret < 0) {
- dev_err(cl->dev, "Failed to request CLDMA IRQ handler: %d\n", ret);
- goto req_err;
- }
-
return 0;
-
-req_err:
- snd_dma_free_pages(&cl->dmab_bdl);
-alloc_err:
- snd_dma_free_pages(&cl->dmab_data);
-
- return ret;
}
void hda_cldma_free(struct hda_cldma *cl)
{
- struct pci_dev *pci = to_pci_dev(cl->dev);
-
- pci_free_irq(pci, 0, cl);
snd_dma_free_pages(&cl->dmab_data);
snd_dma_free_pages(&cl->dmab_bdl);
}
diff --git a/sound/soc/intel/avs/cldma.h b/sound/soc/intel/avs/cldma.h
index 754fcf9ee585..7f9b2b1c566e 100644
--- a/sound/soc/intel/avs/cldma.h
+++ b/sound/soc/intel/avs/cldma.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021-2022 Intel Corporation
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/
@@ -8,7 +8,9 @@
#ifndef __SOUND_SOC_INTEL_AVS_CLDMA_H
#define __SOUND_SOC_INTEL_AVS_CLDMA_H
-#define AVS_CL_DEFAULT_BUFFER_SIZE (32 * PAGE_SIZE)
+#include <linux/sizes.h>
+
+#define AVS_CL_DEFAULT_BUFFER_SIZE SZ_128K
struct hda_cldma;
extern struct hda_cldma code_loader;
@@ -22,6 +24,7 @@ int hda_cldma_reset(struct hda_cldma *cl);
void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size);
void hda_cldma_setup(struct hda_cldma *cl);
+void hda_cldma_interrupt(struct hda_cldma *cl);
int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba,
unsigned int buffer_size);
void hda_cldma_free(struct hda_cldma *cl);
diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c
new file mode 100644
index 000000000000..5b5359e9128b
--- /dev/null
+++ b/sound/soc/intel/avs/cnl.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2024 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "debug.h"
+#include "messages.h"
+#include "registers.h"
+
+static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
+{
+ const struct avs_spec *spec = adev->spec;
+ u32 hipc_ack, hipc_rsp;
+
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
+
+ hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
+ hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
+
+ /* DSP acked host's request. */
+ if (hipc_ack & spec->hipc->ack_done_mask) {
+ complete(&adev->ipc->done_completion);
+
+ /* Tell DSP it has our attention. */
+ snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
+ spec->hipc->ack_done_mask);
+ }
+
+ /* DSP sent new response to process. */
+ if (hipc_rsp & spec->hipc->rsp_busy_mask) {
+ union avs_reply_msg msg;
+ u32 hipctda;
+
+ msg.primary = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR);
+ msg.ext.val = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD);
+
+ avs_dsp_process_response(adev, msg.val);
+
+ /* Tell DSP we accepted its message. */
+ snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR,
+ CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY);
+ /* Ack this response. */
+ snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA,
+ CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE);
+ /* HW might have been clock gated, give some time for change to propagate. */
+ snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda,
+ !(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000);
+ }
+
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
+}
+
+irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev)
+{
+ u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (adspis == UINT_MAX)
+ return ret;
+
+ if (adspis & AVS_ADSP_ADSPIS_IPC) {
+ avs_cnl_ipc_interrupt(adev);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+const struct avs_dsp_ops avs_cnl_dsp_ops = {
+ .power = avs_dsp_core_power,
+ .reset = avs_dsp_core_reset,
+ .stall = avs_dsp_core_stall,
+ .dsp_interrupt = avs_cnl_dsp_interrupt,
+ .int_control = avs_dsp_interrupt_control,
+ .load_basefw = avs_hda_load_basefw,
+ .load_lib = avs_hda_load_library,
+ .transfer_mods = avs_hda_transfer_modules,
+ .log_buffer_offset = avs_skl_log_buffer_offset,
+ .log_buffer_status = avs_apl_log_buffer_status,
+ .coredump = avs_apl_coredump,
+ .d0ix_toggle = avs_apl_d0ix_toggle,
+ .set_d0ix = avs_apl_set_d0ix,
+ AVS_SET_ENABLE_LOGS_OP(apl)
+};
diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c
index a8b14b784f8a..a8f05de338e0 100644
--- a/sound/soc/intel/avs/control.c
+++ b/sound/soc/intel/avs/control.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
// Cezary Rojewski <cezary.rojewski@intel.com>
//
+#include <linux/cleanup.h>
#include <sound/soc.h>
#include "avs.h"
#include "control.h"
@@ -14,92 +15,200 @@
static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol)
{
- struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
- w = snd_soc_dapm_kcontrol_widget(kcontrol);
-
- return to_avs_dev(w->dapm->component->dev);
+ return to_avs_dev(dev);
}
-static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id)
+static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 id)
{
struct avs_path *path;
struct avs_path_pipeline *ppl;
struct avs_path_module *mod;
- 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 (mod->template->ctl_id && mod->template->ctl_id == id)
+ spin_lock(&adev->path_list_lock);
+ list_for_each_entry(path, &adev->path_list, node) {
+ list_for_each_entry(ppl, &path->ppl_list, node) {
+ list_for_each_entry(mod, &ppl->mod_list, node) {
+ 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;
+ }
+ }
+ }
+ }
+ spin_unlock(&adev->path_list_lock);
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;
- /* prevent access to modules while path is being constructed */
- mutex_lock(&adev->path_mutex);
+ adev = avs_get_kcontrol_adev(kctl);
- active_module = avs_get_kcontrol_module(adev, ctl_data->id);
+ /* 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);
+
+ 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;
+ }
- if (ctlvol < 0 || ctlvol > mc->max)
- return -EINVAL;
+ memcpy(ctl_data->values, input, sizeof(ctl_data->values));
+ return 1;
+}
- /* prevent access to modules while path is being constructed */
- mutex_lock(&adev->path_mutex);
+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;
- if (*volume != ctlvol) {
- *volume = ctlvol;
- changed = 1;
- }
+ 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_kcontrol_module(adev, ctl_data->id);
+ 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);
+ }
+
+ memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
+ return 0;
+}
- ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id,
- active_module->instance_id, &dspvol);
- ret = AVS_IPC_RET(ret);
+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 08631bde13c3..08b2919e4629 100644
--- a/sound/soc/intel/avs/control.h
+++ b/sound/soc/intel/avs/control.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021-2022 Intel Corporation
*
* Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
* Cezary Rojewski <cezary.rojewski@intel.com>
@@ -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 637501850728..6e0e65584c7f 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -14,18 +14,22 @@
// foundation of this driver
//
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <acpi/nhlt.h>
#include <sound/hda_codec.h>
#include <sound/hda_i915.h>
#include <sound/hda_register.h>
#include <sound/hdaudio.h>
#include <sound/hdaudio_ext.h>
#include <sound/intel-dsp-config.h>
-#include <sound/intel-nhlt.h>
#include "../../codecs/hda.h"
#include "avs.h"
#include "cldma.h"
+#include "debug.h"
+#include "messages.h"
+#include "pcm.h"
static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
module_param(pgctl_mask, uint, 0444);
@@ -51,14 +55,17 @@ void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable)
{
u32 value = enable ? 0 : pgctl_mask;
- avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value);
+ if (!avs_platattr_test(adev, ACE))
+ avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value);
}
static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable)
{
+ struct avs_dev *adev = hdac_to_avs(bus);
u32 value = enable ? cgctl_mask : 0;
- avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value);
+ if (!avs_platattr_test(adev, ACE))
+ avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value);
}
void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
@@ -68,9 +75,16 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable)
void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable)
{
- u32 value = enable ? AZX_VS_EM2_L1SEN : 0;
-
- snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value);
+ if (avs_platattr_test(adev, ACE))
+ return;
+ if (enable) {
+ if (atomic_inc_and_test(&adev->l1sen_counter))
+ snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN,
+ AZX_VS_EM2_L1SEN);
+ } else {
+ if (atomic_dec_return(&adev->l1sen_counter) == -1)
+ snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, 0);
+ }
}
static int avs_hdac_bus_init_streams(struct hdac_bus *bus)
@@ -91,6 +105,7 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus)
static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
{
+ struct avs_dev *adev = hdac_to_avs(bus);
struct hdac_ext_link *hlink;
bool ret;
@@ -106,7 +121,8 @@ static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
/* Set DUM bit to address incorrect position reporting for capture
* streams. In order to do so, CTRL needs to be out of reset state
*/
- snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
+ if (!avs_platattr_test(adev, ACE))
+ snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
return ret;
}
@@ -143,7 +159,7 @@ static int probe_codec(struct hdac_bus *bus, int addr)
/* configure effectively creates new ASoC component */
ret = snd_hda_codec_configure(codec);
if (ret < 0) {
- dev_err(bus->dev, "failed to config codec %d\n", ret);
+ dev_warn(bus->dev, "failed to config codec #%d: %d\n", addr, ret);
return ret;
}
@@ -152,15 +168,16 @@ static int probe_codec(struct hdac_bus *bus, int addr)
static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus)
{
- int c;
+ int ret, c;
/* First try to probe all given codec slots */
for (c = 0; c < HDA_MAX_CODECS; c++) {
if (!(bus->codec_mask & BIT(c)))
continue;
- if (!probe_codec(bus, c))
- /* success, continue probing */
+ ret = probe_codec(bus, c);
+ /* Ignore codecs with no supporting driver. */
+ if (!ret || ret == -ENODEV)
continue;
/*
@@ -191,10 +208,6 @@ static void avs_hda_probe_work(struct work_struct *work)
pm_runtime_set_active(bus->dev); /* clear runtime_error flag */
- ret = snd_hdac_i915_init(bus);
- if (ret < 0)
- dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret);
-
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
avs_hdac_bus_init_chip(bus, true);
avs_hdac_bus_probe_codecs(bus);
@@ -206,22 +219,19 @@ static void avs_hda_probe_work(struct work_struct *work)
snd_hdac_ext_bus_ppcap_enable(bus, true);
snd_hdac_ext_bus_ppcap_int_enable(bus, true);
+ avs_debugfs_init(adev);
ret = avs_dsp_first_boot_firmware(adev);
if (ret < 0)
return;
- adev->nhlt = intel_nhlt_init(adev->dev);
- if (!adev->nhlt)
- dev_info(bus->dev, "platform has no NHLT\n");
- avs_debugfs_init(adev);
+ acpi_nhlt_get_gbl_table();
avs_register_all_boards(adev);
/* configure PM */
pm_runtime_set_autosuspend_delay(bus->dev, 2000);
pm_runtime_use_autosuspend(bus->dev);
- pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
pm_runtime_allow(bus->dev);
}
@@ -245,7 +255,7 @@ static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size)
static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
{
if (stream->substream) {
- snd_pcm_period_elapsed(stream->substream);
+ avs_period_elapsed(stream->substream);
} else if (stream->cstream) {
u64 buffer_size = stream->cstream->runtime->buffer_size;
@@ -254,67 +264,78 @@ static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
}
}
-static irqreturn_t hdac_bus_irq_handler(int irq, void *context)
+static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
{
- struct hdac_bus *bus = context;
- u32 mask, int_enable;
+ irqreturn_t ret = IRQ_NONE;
u32 status;
- int ret = IRQ_NONE;
-
- if (!pm_runtime_active(bus->dev))
- return ret;
-
- spin_lock(&bus->reg_lock);
status = snd_hdac_chip_readl(bus, INTSTS);
- if (status == 0 || status == UINT_MAX) {
- spin_unlock(&bus->reg_lock);
- return ret;
- }
+ if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream))
+ ret = IRQ_HANDLED;
- /* clear rirb int */
+ spin_lock_irq(&bus->reg_lock);
+ /* Clear RIRB interrupt. */
status = snd_hdac_chip_readb(bus, RIRBSTS);
if (status & RIRB_INT_MASK) {
if (status & RIRB_INT_RESPONSE)
snd_hdac_bus_update_rirb(bus);
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
- }
-
- mask = (0x1 << bus->num_streams) - 1;
-
- status = snd_hdac_chip_readl(bus, INTSTS);
- status &= mask;
- if (status) {
- /* Disable stream interrupts; Re-enable in bottom half */
- int_enable = snd_hdac_chip_readl(bus, INTCTL);
- snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask)));
- ret = IRQ_WAKE_THREAD;
- } else {
ret = IRQ_HANDLED;
}
- spin_unlock(&bus->reg_lock);
+ spin_unlock_irq(&bus->reg_lock);
return ret;
}
-static irqreturn_t hdac_bus_irq_thread(int irq, void *context)
+static irqreturn_t avs_hda_irq_handler(int irq, void *dev_id)
{
- struct hdac_bus *bus = context;
+ struct hdac_bus *bus = dev_id;
+ u32 intsts;
+
+ intsts = snd_hdac_chip_readl(bus, INTSTS);
+ if (intsts == UINT_MAX || !(intsts & AZX_INT_GLOBAL_EN))
+ return IRQ_NONE;
+
+ /* Mask GIE, unmasked in irq_thread(). */
+ snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, 0);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t avs_hda_irq_thread(int irq, void *dev_id)
+{
+ struct hdac_bus *bus = dev_id;
u32 status;
- u32 int_enable;
- u32 mask;
- unsigned long flags;
status = snd_hdac_chip_readl(bus, INTSTS);
+ if (status & ~AZX_INT_GLOBAL_EN)
+ avs_hda_interrupt(bus);
+
+ /* Unmask GIE, masked in irq_handler(). */
+ snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id)
+{
+ struct avs_dev *adev = dev_id;
+
+ return avs_hda_irq_handler(irq, &adev->base.core);
+}
- snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream);
+static irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
+{
+ struct avs_dev *adev = dev_id;
+ struct hdac_bus *bus = &adev->base.core;
+ u32 status;
- /* Re-enable stream interrupts */
- mask = (0x1 << bus->num_streams) - 1;
- spin_lock_irqsave(&bus->reg_lock, flags);
- int_enable = snd_hdac_chip_readl(bus, INTCTL);
- snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask));
- spin_unlock_irqrestore(&bus->reg_lock, flags);
+ status = readl(bus->ppcap + AZX_REG_PP_PPSTS);
+ if (status & AZX_PPCTL_PIE)
+ avs_dsp_op(adev, dsp_interrupt);
+
+ /* Unmask GIE, masked in irq_handler(). */
+ snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN);
return IRQ_HANDLED;
}
@@ -326,13 +347,13 @@ static int avs_hdac_acquire_irq(struct avs_dev *adev)
int ret;
/* request one and check that we only got one interrupt */
- ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY);
+ ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_INTX);
if (ret != 1) {
dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret);
return ret;
}
- ret = pci_request_irq(pci, 0, hdac_bus_irq_handler, hdac_bus_irq_thread, bus,
+ ret = pci_request_irq(pci, 0, avs_hda_irq_handler, avs_hda_irq_thread, bus,
KBUILD_MODNAME);
if (ret < 0) {
dev_err(adev->dev, "Failed to request stream IRQ handler: %d\n", ret);
@@ -380,6 +401,10 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
if (ret < 0)
return ret;
+ adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!adev->modcfg_buf)
+ return -ENOMEM;
+
adev->dev = dev;
adev->spec = (const struct avs_spec *)id->driver_data;
adev->ipc = ipc;
@@ -405,8 +430,14 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
int ret;
ret = snd_intel_dsp_driver_probe(pci);
- if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS)
+ switch (ret) {
+ case SND_INTEL_DSP_DRIVER_ANY:
+ case SND_INTEL_DSP_DRIVER_SST:
+ case SND_INTEL_DSP_DRIVER_AVS:
+ break;
+ default:
return -ENODEV;
+ }
ret = pcim_enable_device(pci);
if (ret < 0)
@@ -415,23 +446,23 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
+ bus = &adev->base.core;
+
ret = avs_bus_init(adev, pci, id);
if (ret < 0) {
dev_err(dev, "failed to init avs bus: %d\n", ret);
return ret;
}
- ret = pci_request_regions(pci, "AVS HDAudio");
+ ret = pcim_request_all_regions(pci, "AVS HDAudio");
if (ret < 0)
return ret;
- bus = &adev->base.core;
bus->addr = pci_resource_start(pci, 0);
bus->remap_addr = pci_ioremap_bar(pci, 0);
if (!bus->remap_addr) {
dev_err(bus->dev, "ioremap error\n");
- ret = -ENXIO;
- goto err_remap_bar0;
+ return -ENXIO;
}
adev->dsp_ba = pci_ioremap_bar(pci, 4);
@@ -465,10 +496,22 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
pci_set_drvdata(pci, bus);
device_disable_async_suspend(dev);
+ ret = snd_hdac_i915_init(bus);
+ if (ret == -EPROBE_DEFER)
+ goto err_i915_init;
+ else if (ret < 0)
+ dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret);
+
schedule_work(&adev->probe_work);
return 0;
+err_i915_init:
+ pci_free_irq(pci, 0, adev);
+ pci_free_irq(pci, 0, bus);
+ pci_free_irq_vectors(pci);
+ pci_clear_master(pci);
+ pci_set_drvdata(pci, NULL);
err_acquire_irq:
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
@@ -476,8 +519,6 @@ err_init_streams:
iounmap(adev->dsp_ba);
err_remap_bar4:
iounmap(bus->remap_addr);
-err_remap_bar0:
- pci_release_regions(pci);
return ret;
}
@@ -497,8 +538,6 @@ static void avs_pci_shutdown(struct pci_dev *pci)
snd_hdac_bus_stop_chip(bus);
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
- if (avs_platattr_test(adev, CLDMA))
- pci_free_irq(pci, 0, &code_loader);
pci_free_irq(pci, 0, adev);
pci_free_irq(pci, 0, bus);
pci_free_irq_vectors(pci);
@@ -515,9 +554,8 @@ static void avs_pci_remove(struct pci_dev *pci)
avs_unregister_all_boards(adev);
+ acpi_nhlt_put_gbl_table();
avs_debugfs_exit(adev);
- if (adev->nhlt)
- intel_nhlt_free(adev->nhlt);
if (avs_platattr_test(adev, CLDMA))
hda_cldma_free(&code_loader);
@@ -551,7 +589,6 @@ static void avs_pci_remove(struct pci_dev *pci)
pci_free_irq_vectors(pci);
iounmap(bus->remap_addr);
iounmap(adev->dsp_ba);
- pci_release_regions(pci);
/* Firmware is not needed anymore */
avs_release_firmwares(adev);
@@ -579,7 +616,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;
@@ -640,7 +677,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;
@@ -663,41 +700,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);
}
@@ -709,50 +746,185 @@ 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 = {
+ .base_offset = SKL_ADSP_SRAM_BASE_OFFSET,
+ .window_size = SKL_ADSP_SRAM_WINDOW_SIZE,
+};
+
+static const struct avs_sram_spec apl_sram_spec = {
+ .base_offset = APL_ADSP_SRAM_BASE_OFFSET,
+ .window_size = APL_ADSP_SRAM_WINDOW_SIZE,
+};
+
+static const struct avs_sram_spec mtl_sram_spec = {
+ .base_offset = MTL_ADSP_SRAM_BASE_OFFSET,
+ .window_size = MTL_ADSP_SRAM_WINDOW_SIZE,
+};
+
+static const struct avs_hipc_spec skl_hipc_spec = {
+ .req_offset = SKL_ADSP_REG_HIPCI,
+ .req_ext_offset = SKL_ADSP_REG_HIPCIE,
+ .req_busy_mask = SKL_ADSP_HIPCI_BUSY,
+ .ack_offset = SKL_ADSP_REG_HIPCIE,
+ .ack_done_mask = SKL_ADSP_HIPCIE_DONE,
+ .rsp_offset = SKL_ADSP_REG_HIPCT,
+ .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY,
+ .ctl_offset = SKL_ADSP_REG_HIPCCTL,
+ .sts_offset = SKL_ADSP_SRAM_BASE_OFFSET,
+};
+
+static const struct avs_hipc_spec apl_hipc_spec = {
+ .req_offset = SKL_ADSP_REG_HIPCI,
+ .req_ext_offset = SKL_ADSP_REG_HIPCIE,
+ .req_busy_mask = SKL_ADSP_HIPCI_BUSY,
+ .ack_offset = SKL_ADSP_REG_HIPCIE,
+ .ack_done_mask = SKL_ADSP_HIPCIE_DONE,
+ .rsp_offset = SKL_ADSP_REG_HIPCT,
+ .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY,
+ .ctl_offset = SKL_ADSP_REG_HIPCCTL,
+ .sts_offset = APL_ADSP_SRAM_BASE_OFFSET,
+};
+
+static const struct avs_hipc_spec cnl_hipc_spec = {
+ .req_offset = CNL_ADSP_REG_HIPCIDR,
+ .req_ext_offset = CNL_ADSP_REG_HIPCIDD,
+ .req_busy_mask = CNL_ADSP_HIPCIDR_BUSY,
+ .ack_offset = CNL_ADSP_REG_HIPCIDA,
+ .ack_done_mask = CNL_ADSP_HIPCIDA_DONE,
+ .rsp_offset = CNL_ADSP_REG_HIPCTDR,
+ .rsp_busy_mask = CNL_ADSP_HIPCTDR_BUSY,
+ .ctl_offset = CNL_ADSP_REG_HIPCCTL,
+ .sts_offset = APL_ADSP_SRAM_BASE_OFFSET,
+};
+
+static const struct avs_hipc_spec lnl_hipc_spec = {
+ .req_offset = MTL_REG_HfIPCxIDR,
+ .req_ext_offset = MTL_REG_HfIPCxIDD,
+ .req_busy_mask = MTL_HfIPCxIDR_BUSY,
+ .ack_offset = MTL_REG_HfIPCxIDA,
+ .ack_done_mask = MTL_HfIPCxIDA_DONE,
+ .rsp_offset = MTL_REG_HfIPCxTDR,
+ .rsp_busy_mask = MTL_HfIPCxTDR_BUSY,
+ .ctl_offset = MTL_REG_HfIPCxCTL,
+ .sts_offset = LNL_REG_HfDFR(0),
};
static const struct avs_spec skl_desc = {
.name = "skl",
- .min_fw_version = {
- .major = 9,
- .minor = 21,
- .hotfix = 0,
- .build = 4732,
- },
- .dsp_ops = &skl_dsp_ops,
+ .min_fw_version = { 9, 21, 0, 4732 },
+ .dsp_ops = &avs_skl_dsp_ops,
.core_init_mask = 1,
.attributes = AVS_PLATATTR_CLDMA,
- .sram_base_offset = SKL_ADSP_SRAM_BASE_OFFSET,
- .sram_window_size = SKL_ADSP_SRAM_WINDOW_SIZE,
- .rom_status = SKL_ADSP_SRAM_BASE_OFFSET,
+ .sram = &skl_sram_spec,
+ .hipc = &skl_hipc_spec,
};
static const struct avs_spec apl_desc = {
.name = "apl",
- .min_fw_version = {
- .major = 9,
- .minor = 22,
- .hotfix = 1,
- .build = 4323,
- },
- .dsp_ops = &apl_dsp_ops,
+ .min_fw_version = { 9, 22, 1, 4323 },
+ .dsp_ops = &avs_apl_dsp_ops,
.core_init_mask = 3,
.attributes = AVS_PLATATTR_IMR,
- .sram_base_offset = APL_ADSP_SRAM_BASE_OFFSET,
- .sram_window_size = APL_ADSP_SRAM_WINDOW_SIZE,
- .rom_status = APL_ADSP_SRAM_BASE_OFFSET,
+ .sram = &apl_sram_spec,
+ .hipc = &apl_hipc_spec,
+};
+
+static const struct avs_spec cnl_desc = {
+ .name = "cnl",
+ .min_fw_version = { 10, 23, 0, 5314 },
+ .dsp_ops = &avs_cnl_dsp_ops,
+ .core_init_mask = 1,
+ .attributes = AVS_PLATATTR_IMR,
+ .sram = &apl_sram_spec,
+ .hipc = &cnl_hipc_spec,
+};
+
+static const struct avs_spec icl_desc = {
+ .name = "icl",
+ .min_fw_version = { 10, 23, 0, 5040 },
+ .dsp_ops = &avs_icl_dsp_ops,
+ .core_init_mask = 1,
+ .attributes = AVS_PLATATTR_IMR,
+ .sram = &apl_sram_spec,
+ .hipc = &cnl_hipc_spec,
+};
+
+static const struct avs_spec jsl_desc = {
+ .name = "jsl",
+ .min_fw_version = { 10, 26, 0, 5872 },
+ .dsp_ops = &avs_icl_dsp_ops,
+ .core_init_mask = 1,
+ .attributes = AVS_PLATATTR_IMR,
+ .sram = &apl_sram_spec,
+ .hipc = &cnl_hipc_spec,
+};
+
+#define AVS_TGL_BASED_SPEC(sname, min) \
+static const struct avs_spec sname##_desc = { \
+ .name = #sname, \
+ .min_fw_version = { 10, min, 0, 5646 }, \
+ .dsp_ops = &avs_tgl_dsp_ops, \
+ .core_init_mask = 1, \
+ .attributes = AVS_PLATATTR_IMR, \
+ .sram = &apl_sram_spec, \
+ .hipc = &cnl_hipc_spec, \
+}
+
+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 avs_spec fcl_desc = {
+ .name = "fcl",
+ .min_fw_version = { 0 },
+ .dsp_ops = &avs_ptl_dsp_ops,
+ .core_init_mask = 1,
+ .attributes = AVS_PLATATTR_IMR | AVS_PLATATTR_ACE | AVS_PLATATTR_ALTHDA,
+ .sram = &mtl_sram_spec,
+ .hipc = &lnl_hipc_spec,
};
static const struct pci_device_id avs_ids[] = {
- { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
- { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
- { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
- { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
- { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
- { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
- { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
- { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
+ { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_APL, &apl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_GML, &apl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cnl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cnl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cnl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RKL_S, &cnl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &icl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_LKF, &lkf_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tgl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_R, &tgl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_FCL, &fcl_desc) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, avs_ids);
@@ -763,8 +935,9 @@ static struct pci_driver avs_pci_driver = {
.probe = avs_pci_probe,
.remove = avs_pci_remove,
.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);
@@ -773,3 +946,14 @@ 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/avs/skl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/apl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/cnl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/icl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/jsl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/lkf/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/tgl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/ehl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/adl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/adl_n/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/fcl/dsp_basefw.bin");
diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h
new file mode 100644
index 000000000000..94fe8729a5c1
--- /dev/null
+++ b/sound/soc/intel/avs/debug.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2024-2025 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H
+#define __SOUND_SOC_INTEL_AVS_DEBUG_H
+
+#include "messages.h"
+#include "registers.h"
+
+struct avs_dev;
+
+#define avs_log_buffer_size(adev) \
+ ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
+
+#define avs_log_buffer_addr(adev, core) \
+({ \
+ s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \
+ (__offset < 0) ? NULL : \
+ (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
+})
+
+static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&adev->trace_lock, flags);
+ ret = avs_dsp_op(adev, log_buffer_status, msg);
+ spin_unlock_irqrestore(&adev->trace_lock, flags);
+
+ return ret;
+}
+
+struct avs_apl_log_buffer_layout {
+ u32 read_ptr;
+ u32 write_ptr;
+ u8 buffer[];
+} __packed;
+static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8);
+
+#define avs_apl_log_payload_size(adev) \
+ (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout))
+
+#define avs_apl_log_payload_addr(addr) \
+ (addr + sizeof(struct avs_apl_log_buffer_layout))
+
+#ifdef CONFIG_DEBUG_FS
+int avs_register_probe_component(struct avs_dev *adev, const char *name);
+
+#define AVS_SET_ENABLE_LOGS_OP(name) \
+ .enable_logs = avs_##name##_enable_logs
+
+bool avs_logging_fw(struct avs_dev *adev);
+void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len);
+void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len);
+
+void avs_debugfs_init(struct avs_dev *adev);
+void avs_debugfs_exit(struct avs_dev *adev);
+
+#else
+static inline int avs_register_probe_component(struct avs_dev *adev, const char *name)
+{
+ return -EOPNOTSUPP;
+}
+
+#define AVS_SET_ENABLE_LOGS_OP(name)
+
+static inline bool avs_logging_fw(struct avs_dev *adev)
+{
+ return false;
+}
+
+static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
+{
+}
+
+static inline void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src,
+ unsigned int len)
+{
+}
+
+static inline void avs_debugfs_init(struct avs_dev *adev) { }
+static inline void avs_debugfs_exit(struct avs_dev *adev) { }
+#endif
+
+#endif
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index bdd388ec01ea..701c247227bf 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -10,8 +10,10 @@
#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 "debug.h"
#include "messages.h"
static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len)
@@ -68,7 +70,6 @@ static ssize_t fw_regs_read(struct file *file, char __user *to, size_t count, lo
static const struct file_operations fw_regs_fops = {
.open = simple_open,
.read = fw_regs_read,
- .llseek = no_llseek,
};
static ssize_t debug_window_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
@@ -93,7 +94,6 @@ static ssize_t debug_window_read(struct file *file, char __user *to, size_t coun
static const struct file_operations debug_window_fops = {
.open = simple_open,
.read = debug_window_read,
- .llseek = no_llseek,
};
static ssize_t probe_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
@@ -119,16 +119,13 @@ static ssize_t probe_points_read(struct file *file, char __user *to, size_t coun
}
for (i = 0; i < num_desc; i++) {
- ret = snprintf(buf + len, PAGE_SIZE - len,
- "Id: %#010x Purpose: %d Node id: %#x\n",
- desc[i].id.value, desc[i].purpose, desc[i].node_id.val);
- if (ret < 0)
- goto free_desc;
+ ret = scnprintf(buf + len, PAGE_SIZE - len,
+ "Id: %#010x Purpose: %d Node id: %#x\n",
+ desc[i].id.value, desc[i].purpose, desc[i].node_id.val);
len += ret;
}
ret = simple_read_from_buffer(to, count, ppos, buf, len);
-free_desc:
kfree(desc);
exit:
kfree(buf);
@@ -145,7 +142,7 @@ static ssize_t probe_points_write(struct file *file, const char __user *from, si
int ret;
ret = parse_int_array_user(from, count, (int **)&array);
- if (ret < 0)
+ if (ret)
return ret;
num_elems = *array;
@@ -170,7 +167,6 @@ static const struct file_operations probe_points_fops = {
.open = simple_open,
.read = probe_points_read,
.write = probe_points_write,
- .llseek = no_llseek,
};
static ssize_t probe_points_disconnect_write(struct file *file, const char __user *from,
@@ -183,7 +179,7 @@ static ssize_t probe_points_disconnect_write(struct file *file, const char __use
int ret;
ret = parse_int_array_user(from, count, (int **)&array);
- if (ret < 0)
+ if (ret)
return ret;
num_elems = *array;
@@ -236,6 +232,9 @@ static int strace_open(struct inode *inode, struct file *file)
struct avs_dev *adev = inode->i_private;
int ret;
+ if (!try_module_get(adev->dev->driver->owner))
+ return -ENODEV;
+
if (kfifo_initialized(&adev->trace_fifo))
return -EBUSY;
@@ -270,6 +269,7 @@ static int strace_release(struct inode *inode, struct file *file)
spin_unlock_irqrestore(&adev->trace_lock, flags);
+ module_put(adev->dev->driver->owner);
return 0;
}
@@ -313,7 +313,6 @@ err_ipc:
if (!adev->logged_resources) {
avs_dsp_enable_d0ix(adev);
err_d0ix:
- pm_runtime_mark_last_busy(adev->dev);
pm_runtime_put_autosuspend(adev->dev);
}
@@ -340,7 +339,6 @@ static int disable_logs(struct avs_dev *adev, u32 resource_mask)
/* If that's the last resource, allow for D3. */
if (!adev->logged_resources) {
avs_dsp_enable_d0ix(adev);
- pm_runtime_mark_last_busy(adev->dev);
pm_runtime_put_autosuspend(adev->dev);
}
@@ -367,11 +365,14 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s
int ret;
ret = parse_int_array_user(from, count, (int **)&array);
- if (ret < 0)
+ if (ret)
return ret;
num_elems = *array;
- resource_mask = array[1];
+ if (!num_elems) {
+ ret = -EINVAL;
+ goto free_array;
+ }
/*
* Disable if just resource mask is provided - no log priority flags.
@@ -379,6 +380,7 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s
* Enable input format: mask, prio1, .., prioN
* Where 'N' equals number of bits set in the 'mask'.
*/
+ resource_mask = array[1];
if (num_elems == 1) {
ret = disable_logs(adev, resource_mask);
} else {
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index b881100d3e02..464bd6859182 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -1,18 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/string_choices.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
#include "registers.h"
#include "trace.h"
-#define AVS_ADSPCS_INTERVAL_US 500
-#define AVS_ADSPCS_TIMEOUT_US 50000
#define AVS_ADSPCS_DELAY_US 1000
int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
@@ -39,7 +38,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;
}
@@ -225,7 +224,7 @@ err:
int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
u8 core_id, u8 domain, void *param, u32 param_size,
- u16 *instance_id)
+ u8 *instance_id)
{
struct avs_module_entry mentry;
bool was_loaded = false;
@@ -272,7 +271,7 @@ err_mod_entry:
return ret;
}
-void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
+void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u8 instance_id,
u8 ppl_instance_id, u8 core_id)
{
struct avs_module_entry mentry;
diff --git a/sound/soc/intel/avs/icl.c b/sound/soc/intel/avs/icl.c
new file mode 100644
index 000000000000..d655e727bebd
--- /dev/null
+++ b/sound/soc/intel/avs/icl.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2024 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/slab.h>
+#include <sound/hdaudio.h>
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "debug.h"
+#include "messages.h"
+
+#define ICL_VS_LTRP_GB_ICCMAX 95
+
+#ifdef CONFIG_DEBUG_FS
+int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+{
+ struct avs_icl_log_state_info *info;
+ u32 size, num_libs = adev->fw_cfg.max_libs_count;
+ int i, ret;
+
+ if (fls_long(resource_mask) > num_libs)
+ return -EINVAL;
+ size = struct_size(info, logs_priorities_mask, num_libs);
+ info = kzalloc(size, GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->aging_timer_period = aging_period;
+ info->fifo_full_timer_period = fifo_full_period;
+ info->enable = enable;
+ if (enable)
+ for_each_set_bit(i, &resource_mask, num_libs)
+ info->logs_priorities_mask[i] = *priorities++;
+
+ ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
+ kfree(info);
+ if (ret)
+ return AVS_IPC_RET(ret);
+
+ return 0;
+}
+#endif
+
+union avs_icl_memwnd2_slot_type {
+ u32 val;
+ struct {
+ u32 resource_id:8;
+ u32 type:24;
+ };
+} __packed;
+static_assert(sizeof(union avs_icl_memwnd2_slot_type) == 4);
+
+struct avs_icl_memwnd2_desc {
+ u32 resource_id;
+ union avs_icl_memwnd2_slot_type slot_id;
+ u32 vma;
+} __packed;
+static_assert(sizeof(struct avs_icl_memwnd2_desc) == 12);
+
+#define AVS_ICL_MEMWND2_SLOTS_COUNT 15
+
+struct avs_icl_memwnd2 {
+ union {
+ struct avs_icl_memwnd2_desc slot_desc[AVS_ICL_MEMWND2_SLOTS_COUNT];
+ u8 rsvd[SZ_4K];
+ };
+ u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][SZ_4K];
+} __packed;
+static_assert(sizeof(struct avs_icl_memwnd2) == 65536);
+
+#define AVS_ICL_SLOT_UNUSED \
+ ((union avs_icl_memwnd2_slot_type) { 0x00000000U })
+#define AVS_ICL_SLOT_CRITICAL_LOG \
+ ((union avs_icl_memwnd2_slot_type) { 0x54524300U })
+#define AVS_ICL_SLOT_DEBUG_LOG \
+ ((union avs_icl_memwnd2_slot_type) { 0x474f4c00U })
+#define AVS_ICL_SLOT_GDB_STUB \
+ ((union avs_icl_memwnd2_slot_type) { 0x42444700U })
+#define AVS_ICL_SLOT_BROKEN \
+ ((union avs_icl_memwnd2_slot_type) { 0x44414544U })
+
+static int avs_icl_slot_offset(struct avs_dev *adev, union avs_icl_memwnd2_slot_type slot_type)
+{
+ struct avs_icl_memwnd2_desc desc[AVS_ICL_MEMWND2_SLOTS_COUNT];
+ int i;
+
+ memcpy_fromio(&desc, avs_sram_addr(adev, AVS_DEBUG_WINDOW), sizeof(desc));
+
+ for (i = 0; i < AVS_ICL_MEMWND2_SLOTS_COUNT; i++)
+ if (desc[i].slot_id.val == slot_type.val)
+ return offsetof(struct avs_icl_memwnd2, slot_array) + i * SZ_4K;
+ return -ENXIO;
+}
+
+int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core)
+{
+ union avs_icl_memwnd2_slot_type slot_type = AVS_ICL_SLOT_DEBUG_LOG;
+ int ret;
+
+ slot_type.resource_id = core;
+ ret = avs_icl_slot_offset(adev, slot_type);
+ if (ret < 0)
+ dev_dbg(adev->dev, "No slot offset found for: %x\n",
+ slot_type.val);
+
+ return ret;
+}
+
+bool avs_icl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
+{
+ /* Full-power when starting DMA engines. */
+ if (tx->glb.set_ppl_state.state == AVS_PPL_STATE_RUNNING)
+ return true;
+
+ /* Payload-less IPCs do not take part in d0ix toggling. */
+ return tx->size;
+}
+
+int avs_icl_set_d0ix(struct avs_dev *adev, bool enable)
+{
+ int ret;
+
+ ret = avs_ipc_set_d0ix(adev, enable, false);
+ return AVS_IPC_RET(ret);
+}
+
+int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw)
+{
+ struct hdac_bus *bus = &adev->base.core;
+ struct hdac_ext_stream *host_stream;
+ struct snd_pcm_substream substream;
+ struct snd_dma_buffer dmab;
+ unsigned int sd_fmt;
+ u8 ltrp_gb;
+ int ret;
+
+ /*
+ * ICCMAX:
+ *
+ * For ICL+ platforms, as per HW recommendation LTRP_GB is set to 95us
+ * during FW load. Its original value shall be restored once load completes.
+ *
+ * To avoid DMI/OPIO L1 entry during the load procedure, additional CAPTURE
+ * stream is allocated and set to run.
+ */
+
+ memset(&substream, 0, sizeof(substream));
+ substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+
+ host_stream = snd_hdac_ext_stream_assign(bus, &substream, HDAC_EXT_STREAM_TYPE_HOST);
+ if (!host_stream)
+ return -EBUSY;
+
+ ltrp_gb = snd_hdac_chip_readb(bus, VS_LTRP) & AZX_REG_VS_LTRP_GB_MASK;
+ /* Carries no real data, use default format. */
+ sd_fmt = snd_hdac_stream_format(1, 32, 48000);
+
+ ret = snd_hdac_dsp_prepare(hdac_stream(host_stream), sd_fmt, fw->size, &dmab);
+ if (ret < 0)
+ goto release_stream;
+
+ snd_hdac_chip_updateb(bus, VS_LTRP, AZX_REG_VS_LTRP_GB_MASK, ICL_VS_LTRP_GB_ICCMAX);
+
+ spin_lock(&bus->reg_lock);
+ snd_hdac_stream_start(hdac_stream(host_stream));
+ spin_unlock(&bus->reg_lock);
+
+ ret = avs_hda_load_basefw(adev, fw);
+
+ spin_lock(&bus->reg_lock);
+ snd_hdac_stream_stop(hdac_stream(host_stream));
+ spin_unlock(&bus->reg_lock);
+
+ snd_hdac_dsp_cleanup(hdac_stream(host_stream), &dmab);
+
+release_stream:
+ snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST);
+ snd_hdac_chip_updateb(bus, VS_LTRP, AZX_REG_VS_LTRP_GB_MASK, ltrp_gb);
+
+ return ret;
+}
+
+const struct avs_dsp_ops avs_icl_dsp_ops = {
+ .power = avs_dsp_core_power,
+ .reset = avs_dsp_core_reset,
+ .stall = avs_dsp_core_stall,
+ .dsp_interrupt = avs_cnl_dsp_interrupt,
+ .int_control = avs_dsp_interrupt_control,
+ .load_basefw = avs_icl_load_basefw,
+ .load_lib = avs_hda_load_library,
+ .transfer_mods = avs_hda_transfer_modules,
+ .log_buffer_offset = avs_icl_log_buffer_offset,
+ .log_buffer_status = avs_apl_log_buffer_status,
+ .coredump = avs_apl_coredump,
+ .d0ix_toggle = avs_icl_d0ix_toggle,
+ .set_d0ix = avs_icl_set_d0ix,
+ AVS_SET_ENABLE_LOGS_OP(icl)
+};
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index bdf013c3dd12..c0feb9edd7f6 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
+#include "debug.h"
#include "messages.h"
#include "registers.h"
#include "trace.h"
@@ -141,7 +142,6 @@ static void avs_dsp_recovery(struct avs_dev *adev)
if (ret < 0)
dev_err(adev->dev, "dsp reboot failed: %d\n", ret);
- pm_runtime_mark_last_busy(adev->dev);
pm_runtime_enable(adev->dev);
pm_request_autosuspend(adev->dev);
@@ -169,7 +169,9 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
dev_crit(adev->dev, "communication severed, rebooting dsp..\n");
- cancel_delayed_work_sync(&ipc->d0ix_work);
+ /* Avoid deadlock as the exception may be the response to SET_D0IX. */
+ if (current_work() != &ipc->d0ix_work.work)
+ cancel_delayed_work_sync(&ipc->d0ix_work);
ipc->in_d0ix = false;
/* Re-enabled on recovery completion. */
pm_runtime_disable(adev->dev);
@@ -184,10 +186,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 +212,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) {
@@ -301,88 +305,14 @@ void avs_dsp_process_response(struct avs_dev *adev, u64 header)
complete(&ipc->busy_completion);
}
-irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id)
-{
- struct avs_dev *adev = dev_id;
- struct avs_ipc *ipc = adev->ipc;
- u32 adspis, hipc_rsp, hipc_ack;
- irqreturn_t ret = IRQ_NONE;
-
- adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
- if (adspis == UINT_MAX || !(adspis & AVS_ADSP_ADSPIS_IPC))
- return ret;
-
- hipc_ack = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCIE);
- hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
-
- /* DSP acked host's request */
- if (hipc_ack & SKL_ADSP_HIPCIE_DONE) {
- /*
- * As an extra precaution, mask done interrupt. Code executed
- * due to complete() found below does not assume any masking.
- */
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
- AVS_ADSP_HIPCCTL_DONE, 0);
-
- complete(&ipc->done_completion);
-
- /* tell DSP it has our attention */
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCIE,
- SKL_ADSP_HIPCIE_DONE,
- SKL_ADSP_HIPCIE_DONE);
- /* unmask done interrupt */
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
- AVS_ADSP_HIPCCTL_DONE,
- AVS_ADSP_HIPCCTL_DONE);
- ret = IRQ_HANDLED;
- }
-
- /* DSP sent new response to process */
- if (hipc_rsp & SKL_ADSP_HIPCT_BUSY) {
- /* mask busy interrupt */
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
- AVS_ADSP_HIPCCTL_BUSY, 0);
-
- ret = IRQ_WAKE_THREAD;
- }
-
- return ret;
-}
-
-irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
-{
- struct avs_dev *adev = dev_id;
- union avs_reply_msg msg;
- u32 hipct, hipcte;
-
- hipct = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
- hipcte = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
-
- /* ensure DSP sent new response to process */
- if (!(hipct & SKL_ADSP_HIPCT_BUSY))
- return IRQ_NONE;
-
- msg.primary = hipct;
- msg.ext.val = hipcte;
- avs_dsp_process_response(adev, msg.val);
-
- /* tell DSP we accepted its message */
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT,
- SKL_ADSP_HIPCT_BUSY, SKL_ADSP_HIPCT_BUSY);
- /* unmask busy interrupt */
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
- AVS_ADSP_HIPCCTL_BUSY, AVS_ADSP_HIPCCTL_BUSY);
-
- return IRQ_HANDLED;
-}
-
static bool avs_ipc_is_busy(struct avs_ipc *ipc)
{
struct avs_dev *adev = to_avs_dev(ipc->dev);
+ const struct avs_spec *const spec = adev->spec;
u32 hipc_rsp;
- hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
- return hipc_rsp & SKL_ADSP_HIPCT_BUSY;
+ hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
+ return hipc_rsp & spec->hipc->rsp_busy_mask;
}
static int avs_ipc_wait_busy_completion(struct avs_ipc *ipc, int timeout)
@@ -440,22 +370,26 @@ 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)
{
- u64 reg = ULONG_MAX;
-
- tx->header |= SKL_ADSP_HIPCI_BUSY;
- if (read_fwregs)
- reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
+ const struct avs_spec *const spec = adev->spec;
+ u32 sts = UINT_MAX;
+ u32 lec = UINT_MAX;
+
+ tx->header |= spec->hipc->req_busy_mask;
+ 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);
- snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCIE, tx->header >> 32);
- snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCI, tx->header & UINT_MAX);
+ snd_hdac_adsp_writel(adev, spec->hipc->req_ext_offset, tx->header >> 32);
+ snd_hdac_adsp_writel(adev, spec->hipc->req_offset, tx->header & UINT_MAX);
}
static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, int timeout)
+ struct avs_ipc_msg *reply, int timeout, const char *name)
{
struct avs_ipc *ipc = adev->ipc;
int ret;
@@ -482,6 +416,19 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
}
ret = ipc->rx.rsp.status;
+ /*
+ * If IPC channel is blocked e.g.: due to ongoing recovery,
+ * -EPERM error code is expected and thus it's not an actual error.
+ *
+ * Unsupported IPCs are of no harm either.
+ */
+ if (ret == -EPERM || ret == AVS_IPC_NOT_SUPPORTED)
+ dev_dbg(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n",
+ name, request->glb.primary, request->glb.ext.val, ret);
+ else if (ret)
+ dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n",
+ name, request->glb.primary, request->glb.ext.val, ret);
+
if (reply) {
reply->header = ipc->rx.header;
reply->size = ipc->rx.size;
@@ -496,7 +443,7 @@ exit:
static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *request,
struct avs_ipc_msg *reply, int timeout, bool wake_d0i0,
- bool schedule_d0ix)
+ bool schedule_d0ix, const char *name)
{
int ret;
@@ -507,7 +454,7 @@ static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *r
return ret;
}
- ret = avs_dsp_do_send_msg(adev, request, reply, timeout);
+ ret = avs_dsp_do_send_msg(adev, request, reply, timeout, name);
if (ret)
return ret;
@@ -519,34 +466,37 @@ static int avs_dsp_send_msg_sequence(struct avs_dev *adev, struct avs_ipc_msg *r
}
int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, int timeout)
+ struct avs_ipc_msg *reply, int timeout, const char *name)
{
bool wake_d0i0 = avs_dsp_op(adev, d0ix_toggle, request, true);
bool schedule_d0ix = avs_dsp_op(adev, d0ix_toggle, request, false);
- return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, schedule_d0ix);
+ return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, schedule_d0ix,
+ name);
}
int avs_dsp_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply)
+ struct avs_ipc_msg *reply, const char *name)
{
- return avs_dsp_send_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms);
+ return avs_dsp_send_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms, name);
}
int avs_dsp_send_pm_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, int timeout, bool wake_d0i0)
+ struct avs_ipc_msg *reply, int timeout, bool wake_d0i0,
+ const char *name)
{
- return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, false);
+ return avs_dsp_send_msg_sequence(adev, request, reply, timeout, wake_d0i0, false, name);
}
int avs_dsp_send_pm_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
- struct avs_ipc_msg *reply, bool wake_d0i0)
+ struct avs_ipc_msg *reply, bool wake_d0i0, const char *name)
{
return avs_dsp_send_pm_msg_timeout(adev, request, reply, adev->ipc->default_timeout_ms,
- wake_d0i0);
+ wake_d0i0, name);
}
-static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout)
+static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout,
+ const char *name)
{
struct avs_ipc *ipc = adev->ipc;
int ret;
@@ -568,24 +518,29 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
ret = wait_for_completion_timeout(&ipc->done_completion, msecs_to_jiffies(timeout));
ret = ret ? 0 : -ETIMEDOUT;
}
+ if (ret)
+ dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n",
+ name, request->glb.primary, request->glb.ext.val, ret);
mutex_unlock(&ipc->msg_mutex);
return ret;
}
-int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout)
+int avs_dsp_send_rom_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, int timeout,
+ const char *name)
{
- return avs_dsp_do_send_rom_msg(adev, request, timeout);
+ return avs_dsp_do_send_rom_msg(adev, request, timeout, name);
}
-int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request)
+int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, const char *name)
{
- return avs_dsp_send_rom_msg_timeout(adev, request, adev->ipc->default_timeout_ms);
+ return avs_dsp_send_rom_msg_timeout(adev, request, adev->ipc->default_timeout_ms, name);
}
void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable)
{
+ const struct avs_spec *const spec = adev->spec;
u32 value, mask;
/*
@@ -597,7 +552,7 @@ void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable)
mask = AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY;
value = enable ? mask : 0;
- snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL, mask, value);
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, mask, value);
}
int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
diff --git a/sound/soc/intel/avs/lnl.c b/sound/soc/intel/avs/lnl.c
new file mode 100644
index 000000000000..4fbc62bfd6c5
--- /dev/null
+++ b/sound/soc/intel/avs/lnl.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright(c) 2021-2025 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "debug.h"
+#include "registers.h"
+
+int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
+{
+ struct hdac_bus *bus = &adev->base.core;
+ struct hdac_ext_link *hlink;
+ int ret;
+
+ ret = avs_mtl_core_stall(adev, core_mask, stall);
+
+ /* On unstall, route interrupts from the links to the DSP firmware. */
+ if (!ret && !stall)
+ list_for_each_entry(hlink, &bus->hlink_list, list)
+ snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_OFLEN,
+ AZX_ML_LCTL_OFLEN);
+ return ret;
+}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 56bb0a59249d..353e343b1d28 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -9,6 +9,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <sound/hdaudio.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
@@ -56,6 +57,7 @@ struct avs_fw_manifest {
u32 feature_mask;
struct avs_fw_version version;
} __packed;
+static_assert(sizeof(struct avs_fw_manifest) == 36);
struct avs_fw_ext_manifest {
u32 id;
@@ -64,6 +66,7 @@ struct avs_fw_ext_manifest {
u16 version_minor;
u32 entries;
} __packed;
+static_assert(sizeof(struct avs_fw_ext_manifest) == 16);
static int avs_fw_ext_manifest_strip(struct firmware *fw)
{
@@ -165,7 +168,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;
}
@@ -178,7 +182,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;
}
@@ -306,12 +311,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->rom_status, reg,
+ ret = snd_hdac_adsp_readl_poll(adev, spec->hipc->sts_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;
}
@@ -335,15 +341,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;
}
@@ -371,7 +377,7 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
hstream = hdac_stream(estream);
/* code loading performed with default format */
- sdfmt = snd_hdac_calc_stream_format(48000, 1, SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+ sdfmt = snd_hdac_stream_format(1, 32, 48000);
ret = snd_hdac_dsp_prepare(hstream, sdfmt, fw->size, &dmab);
if (ret < 0)
goto release_stream;
@@ -390,7 +396,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;
@@ -402,7 +408,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);
}
@@ -438,7 +445,7 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id)
stream = hdac_stream(estream);
/* code loading performed with default format */
- sdfmt = snd_hdac_calc_stream_format(48000, 1, SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+ sdfmt = snd_hdac_stream_format(1, 32, 48000);
ret = snd_hdac_dsp_prepare(stream, sdfmt, lib->size, &dmab);
if (ret < 0)
goto release_stream;
@@ -535,7 +542,7 @@ int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs,
if (ret)
return ret;
- strncpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE);
+ strscpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE);
id++;
next_lib:
i++;
@@ -582,7 +589,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;
@@ -595,7 +604,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;
@@ -649,35 +658,49 @@ 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_boot_firmware(adev, true);
- if (ret < 0) {
- dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+ return 0;
+}
+
+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)
+{
+ struct hdac_ext_link *link;
+ 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);
+
+ /* If hw allows, read capabilities directly from it. */
+ if (avs_platattr_test(adev, ALTHDA)) {
+ link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core,
+ AZX_REG_ML_LEPTR_ID_INTEL_SSP);
+ if (link)
+ adev->hw_cfg.i2s_caps.ctrl_count = link->slcount;
}
adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores,
@@ -694,9 +717,34 @@ int avs_dsp_first_boot_firmware(struct avs_dev *adev)
}
/* basefw always occupies slot 0 */
- strcpy(&adev->lib_names[0][0], "BASEFW");
+ 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 f887ab5b0311..a5ba27983091 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -16,71 +16,52 @@ int avs_ipc_set_boot_config(struct avs_dev *adev, u32 dma_id, u32 purge)
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(ROM_CONTROL);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.boot_cfg.rom_ctrl_msg_type = AVS_ROM_SET_BOOT_CONFIG;
msg.boot_cfg.dma_id = dma_id;
msg.boot_cfg.purge_request = purge;
request.header = msg.val;
- ret = avs_dsp_send_rom_msg(adev, &request);
- if (ret)
- avs_ipc_err(adev, &request, "set boot config", ret);
-
- return ret;
+ return avs_dsp_send_rom_msg(adev, &request, "set boot config");
}
int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_MULTIPLE_MODULES);
struct avs_ipc_msg request;
- int ret;
msg.load_multi_mods.mod_cnt = num_mod_ids;
request.header = msg.val;
request.data = mod_ids;
request.size = sizeof(*mod_ids) * num_mod_ids;
- ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
- if (ret)
- avs_ipc_err(adev, &request, "load multiple modules", ret);
-
- return ret;
+ return avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS,
+ "load multiple modules");
}
int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(UNLOAD_MULTIPLE_MODULES);
struct avs_ipc_msg request;
- int ret;
msg.load_multi_mods.mod_cnt = num_mod_ids;
request.header = msg.val;
request.data = mod_ids;
request.size = sizeof(*mod_ids) * num_mod_ids;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "unload multiple modules", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "unload multiple modules");
}
int avs_ipc_load_library(struct avs_dev *adev, u32 dma_id, u32 lib_id)
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_LIBRARY);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.load_lib.dma_id = dma_id;
msg.load_lib.lib_id = lib_id;
request.header = msg.val;
- ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
- if (ret)
- avs_ipc_err(adev, &request, "load library", ret);
-
- return ret;
+ return avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS, "load library");
}
int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
@@ -88,7 +69,6 @@ int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(CREATE_PIPELINE);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.create_ppl.ppl_mem_size = req_size;
msg.create_ppl.ppl_priority = priority;
@@ -97,27 +77,18 @@ int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
msg.ext.create_ppl.attributes = attributes;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "create pipeline", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "create pipeline");
}
int avs_ipc_delete_pipeline(struct avs_dev *adev, u8 instance_id)
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(DELETE_PIPELINE);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.ppl.instance_id = instance_id;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "delete pipeline", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "delete pipeline");
}
int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
@@ -125,17 +96,12 @@ int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id,
{
union avs_global_msg msg = AVS_GLOBAL_REQUEST(SET_PIPELINE_STATE);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.set_ppl_state.ppl_id = instance_id;
msg.set_ppl_state.state = state;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "set pipeline state", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "set pipeline state");
}
int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
@@ -149,13 +115,9 @@ int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id,
msg.get_ppl_state.ppl_id = instance_id;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, &reply);
- if (ret) {
- avs_ipc_err(adev, &request, "get pipeline state", ret);
- return ret;
- }
-
- *state = reply.rsp.ext.get_ppl_state.state;
+ ret = avs_dsp_send_msg(adev, &request, &reply, "get pipeline state");
+ if (!ret)
+ *state = reply.rsp.ext.get_ppl_state.state;
return ret;
}
@@ -183,7 +145,6 @@ int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8 instance_id,
{
union avs_module_msg msg = AVS_MODULE_REQUEST(INIT_INSTANCE);
struct avs_ipc_msg request;
- int ret;
msg.module_id = module_id;
msg.instance_id = instance_id;
@@ -197,11 +158,7 @@ int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8 instance_id,
request.data = param;
request.size = param_size;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "init instance", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "init instance");
}
/*
@@ -222,17 +179,12 @@ int avs_ipc_delete_instance(struct avs_dev *adev, u16 module_id, u8 instance_id)
{
union avs_module_msg msg = AVS_MODULE_REQUEST(DELETE_INSTANCE);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.module_id = module_id;
msg.instance_id = instance_id;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "delete instance", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "delete instance");
}
/*
@@ -252,7 +204,6 @@ int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8 instance_id,
{
union avs_module_msg msg = AVS_MODULE_REQUEST(BIND);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.module_id = module_id;
msg.instance_id = instance_id;
@@ -262,11 +213,7 @@ int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8 instance_id,
msg.ext.bind_unbind.src_queue = src_queue;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "bind modules", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "bind modules");
}
/*
@@ -286,7 +233,6 @@ int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8 instance_id,
{
union avs_module_msg msg = AVS_MODULE_REQUEST(UNBIND);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.module_id = module_id;
msg.instance_id = instance_id;
@@ -296,11 +242,7 @@ int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8 instance_id,
msg.ext.bind_unbind.src_queue = src_queue;
request.header = msg.val;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "unbind modules", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "unbind modules");
}
static int __avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id,
@@ -309,7 +251,6 @@ static int __avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, u8 in
{
union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_SET);
struct avs_ipc_msg request;
- int ret;
msg.module_id = module_id;
msg.instance_id = instance_id;
@@ -322,11 +263,7 @@ static int __avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, u8 in
request.data = request_data;
request.size = request_size;
- ret = avs_dsp_send_msg(adev, &request, NULL);
- if (ret)
- avs_ipc_err(adev, &request, "large config set", ret);
-
- return ret;
+ return avs_dsp_send_msg(adev, &request, NULL, "large config set");
}
int avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id,
@@ -398,9 +335,8 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
request.size = request_size;
reply.size = AVS_MAILBOX_SIZE;
- ret = avs_dsp_send_msg(adev, &request, &reply);
+ ret = avs_dsp_send_msg(adev, &request, &reply, "large config get");
if (ret) {
- avs_ipc_err(adev, &request, "large config get", ret);
kfree(reply.data);
return ret;
}
@@ -422,7 +358,6 @@ int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup)
union avs_module_msg msg = AVS_MODULE_REQUEST(SET_DX);
struct avs_ipc_msg request;
struct avs_dxstate_info dx;
- int ret;
dx.core_mask = core_mask;
dx.dx_mask = powerup ? core_mask : 0;
@@ -430,11 +365,7 @@ int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup)
request.data = &dx;
request.size = sizeof(dx);
- ret = avs_dsp_send_pm_msg(adev, &request, NULL, true);
- if (ret)
- avs_ipc_err(adev, &request, "set dx", ret);
-
- return ret;
+ return avs_dsp_send_pm_msg(adev, &request, NULL, true, "set dx");
}
/*
@@ -447,18 +378,14 @@ int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming)
{
union avs_module_msg msg = AVS_MODULE_REQUEST(SET_D0IX);
struct avs_ipc_msg request = {{0}};
- int ret;
msg.ext.set_d0ix.wake = enable_pg;
msg.ext.set_d0ix.streaming = streaming;
+ msg.ext.set_d0ix.prevent_pg = !enable_pg;
request.header = msg.val;
- ret = avs_dsp_send_pm_msg(adev, &request, NULL, false);
- if (ret)
- avs_ipc_err(adev, &request, "set d0ix", ret);
-
- return ret;
+ return avs_dsp_send_pm_msg(adev, &request, NULL, false, "set d0ix");
}
int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
@@ -473,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);
@@ -575,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;
}
@@ -590,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);
@@ -663,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;
}
@@ -702,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)
{
@@ -731,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 d3b60ae7d743..55c04b0142ae 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021-2022 Intel Corporation
*
* Authors: Cezary Rojewski <cezary.rojewski@intel.com>
* Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -9,9 +9,11 @@
#ifndef __SOUND_SOC_INTEL_AVS_MSGS_H
#define __SOUND_SOC_INTEL_AVS_MSGS_H
+#include <linux/sizes.h>
+
struct avs_dev;
-#define AVS_MAILBOX_SIZE 4096
+#define AVS_MAILBOX_SIZE SZ_4K
enum avs_msg_target {
AVS_FW_GEN_MSG = 0,
@@ -91,12 +93,16 @@ union avs_global_msg {
} ext;
};
} __packed;
+static_assert(sizeof(union avs_global_msg) == 8);
struct avs_tlv {
u32 type;
u32 length;
u32 value[];
} __packed;
+static_assert(sizeof(struct avs_tlv) == 8);
+
+#define avs_tlv_size(tlv) struct_size(tlv, value, (tlv)->length / 4)
enum avs_module_msg_type {
AVS_MOD_INIT_INSTANCE = 0,
@@ -143,12 +149,17 @@ union avs_module_msg {
u32 src_queue:3;
} bind_unbind;
struct {
+ /* pre-IceLake */
u32 wake:1;
u32 streaming:1;
+ /* IceLake and onwards */
+ u32 prevent_pg:1;
+ u32 prevent_local_cg:1;
} set_d0ix;
} ext;
};
} __packed;
+static_assert(sizeof(union avs_module_msg) == 8);
#define AVS_IPC_NOT_SUPPORTED 15
@@ -184,6 +195,7 @@ union avs_reply_msg {
} ext;
};
} __packed;
+static_assert(sizeof(union avs_reply_msg) == 8);
enum avs_notify_msg_type {
AVS_NOTIFY_PHRASE_DETECTED = 4,
@@ -220,6 +232,7 @@ union avs_notify_msg {
} ext;
};
} __packed;
+static_assert(sizeof(union avs_notify_msg) == 8);
#define AVS_MSG(hdr) { .val = hdr }
@@ -258,6 +271,7 @@ struct avs_notify_voice_data {
u16 kpd_score;
u16 reserved;
} __packed;
+static_assert(sizeof(struct avs_notify_voice_data) == 4);
struct avs_notify_res_data {
u32 resource_type;
@@ -266,6 +280,7 @@ struct avs_notify_res_data {
u32 reserved;
u32 data[6];
} __packed;
+static_assert(sizeof(struct avs_notify_res_data) == 40);
struct avs_notify_mod_data {
u32 module_instance_id;
@@ -273,6 +288,7 @@ struct avs_notify_mod_data {
u32 data_size;
u32 data[];
} __packed;
+static_assert(sizeof(struct avs_notify_mod_data) == 12);
/* ROM messages */
enum avs_rom_control_msg_type {
@@ -326,6 +342,7 @@ struct avs_dxstate_info {
u32 core_mask; /* which cores are subject for power transition */
u32 dx_mask; /* bit[n]=1 core n goes to D0, bit[n]=0 it goes to D3 */
} __packed;
+static_assert(sizeof(struct avs_dxstate_info) == 8);
int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup);
int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming);
@@ -357,22 +374,50 @@ enum avs_skl_log_priority {
AVS_SKL_LOG_VERBOSE,
};
-struct skl_log_state {
+struct avs_skl_log_state {
u32 enable;
u32 min_priority;
} __packed;
+static_assert(sizeof(struct avs_skl_log_state) == 8);
-struct skl_log_state_info {
+struct avs_skl_log_state_info {
u32 core_mask;
- struct skl_log_state logs_core[];
+ struct avs_skl_log_state logs_core[];
} __packed;
+static_assert(sizeof(struct avs_skl_log_state_info) == 4);
-struct apl_log_state_info {
+struct avs_apl_log_state_info {
u32 aging_timer_period;
u32 fifo_full_timer_period;
u32 core_mask;
- struct skl_log_state logs_core[];
+ struct avs_skl_log_state logs_core[];
+} __packed;
+static_assert(sizeof(struct avs_apl_log_state_info) == 12);
+
+enum avs_icl_log_priority {
+ AVS_ICL_LOG_CRITICAL = 0,
+ AVS_ICL_LOG_HIGH,
+ AVS_ICL_LOG_MEDIUM,
+ AVS_ICL_LOG_LOW,
+ AVS_ICL_LOG_VERBOSE,
+};
+
+enum avs_icl_log_source {
+ AVS_ICL_LOG_INFRA = 0,
+ AVS_ICL_LOG_HAL,
+ AVS_ICL_LOG_MODULE,
+ AVS_ICL_LOG_AUDIO,
+ AVS_ICL_LOG_SENSING,
+ AVS_ICL_LOG_ULP_INFRA,
+};
+
+struct avs_icl_log_state_info {
+ u32 aging_timer_period;
+ u32 fifo_full_timer_period;
+ u32 enable;
+ u32 logs_priorities_mask[];
} __packed;
+static_assert(sizeof(struct avs_icl_log_state_info) == 12);
int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size);
@@ -408,6 +453,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 {
@@ -432,7 +479,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,
@@ -491,6 +545,7 @@ struct avs_module_type {
u32 lib_code:1;
u32 rsvd:24;
} __packed;
+static_assert(sizeof(struct avs_module_type) == 4);
union avs_segment_flags {
u32 ul;
@@ -507,12 +562,14 @@ union avs_segment_flags {
u32 length:16;
};
} __packed;
+static_assert(sizeof(union avs_segment_flags) == 4);
struct avs_segment_desc {
union avs_segment_flags flags;
u32 v_base_addr;
u32 file_offset;
} __packed;
+static_assert(sizeof(struct avs_segment_desc) == 12);
struct avs_module_entry {
u16 module_id;
@@ -529,11 +586,13 @@ struct avs_module_entry {
u16 instance_bss_size;
struct avs_segment_desc segments[3];
} __packed;
+static_assert(sizeof(struct avs_module_entry) == 116);
struct avs_mods_info {
u32 count;
struct avs_module_entry entries[];
} __packed;
+static_assert(sizeof(struct avs_mods_info) == 4);
static inline bool avs_module_entry_is_loaded(struct avs_module_entry *mentry)
{
@@ -547,6 +606,7 @@ struct avs_sys_time {
u32 val_l;
u32 val_u;
} __packed;
+static_assert(sizeof(struct avs_sys_time) == 8);
int avs_ipc_set_system_time(struct avs_dev *adev);
@@ -594,6 +654,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,
@@ -619,7 +682,7 @@ enum avs_channel_config {
AVS_CHANNEL_CONFIG_DUAL_MONO = 9,
AVS_CHANNEL_CONFIG_I2S_DUAL_STEREO_0 = 10,
AVS_CHANNEL_CONFIG_I2S_DUAL_STEREO_1 = 11,
- AVS_CHANNEL_CONFIG_4_CHANNEL = 12,
+ AVS_CHANNEL_CONFIG_7_1 = 12,
AVS_CHANNEL_CONFIG_INVALID
};
@@ -636,8 +699,9 @@ enum avs_sample_type {
AVS_SAMPLE_TYPE_FLOAT = 4,
};
-#define AVS_CHANNELS_MAX 8
+#define AVS_COEFF_CHANNELS_MAX 8
#define AVS_ALL_CHANNELS_MASK UINT_MAX
+#define AVS_CHANNELS_MAX 16
struct avs_audio_format {
u32 sampling_freq;
@@ -650,6 +714,7 @@ struct avs_audio_format {
u32 sample_type:8;
u32 reserved:8;
} __packed;
+static_assert(sizeof(struct avs_audio_format) == 24);
struct avs_modcfg_base {
u32 cpc;
@@ -658,12 +723,14 @@ struct avs_modcfg_base {
u32 is_pages;
struct avs_audio_format audio_fmt;
} __packed;
+static_assert(sizeof(struct avs_modcfg_base) == 40);
struct avs_pin_format {
u32 pin_index;
u32 iobs;
struct avs_audio_format audio_fmt;
} __packed;
+static_assert(sizeof(struct avs_pin_format) == 32);
struct avs_modcfg_ext {
struct avs_modcfg_base base;
@@ -673,6 +740,7 @@ struct avs_modcfg_ext {
/* input pin formats followed by output ones */
struct avs_pin_format pin_fmts[];
} __packed;
+static_assert(sizeof(struct avs_modcfg_ext) == 56);
enum avs_dma_type {
AVS_DMA_HDA_HOST_OUTPUT = 0,
@@ -696,6 +764,7 @@ union avs_virtual_index {
u8 instance:3;
} dmic;
} __packed;
+static_assert(sizeof(union avs_virtual_index) == 1);
union avs_connector_node_id {
u32 val;
@@ -705,6 +774,7 @@ union avs_connector_node_id {
u32 rsvd:19;
};
} __packed;
+static_assert(sizeof(union avs_connector_node_id) == 4);
#define INVALID_PIPELINE_ID 0xFF
#define INVALID_NODE_ID \
@@ -717,16 +787,45 @@ union avs_gtw_attributes {
u32 rsvd:31;
};
} __packed;
+static_assert(sizeof(union avs_gtw_attributes) == 4);
+
+#define AVS_GTW_DMA_CONFIG_ID 0x1000
+#define AVS_DMA_METHOD_HDA 1
+
+struct avs_dma_device_stream_channel_map {
+ u32 device_address;
+ u32 channel_map;
+} __packed;
+static_assert(sizeof(struct avs_dma_device_stream_channel_map) == 8);
+
+struct avs_dma_stream_channel_map {
+ u32 device_count;
+ struct avs_dma_device_stream_channel_map map[16];
+} __packed;
+static_assert(sizeof(struct avs_dma_stream_channel_map) == 132);
+
+struct avs_dma_cfg {
+ u8 dma_method;
+ u8 pre_allocated;
+ u16 rsvd;
+ u32 dma_channel_id;
+ u32 stream_id;
+ struct avs_dma_stream_channel_map map;
+ u32 config_size;
+ u8 config[] __counted_by(config_size);
+} __packed;
+static_assert(sizeof(struct avs_dma_cfg) == 148);
struct avs_copier_gtw_cfg {
union avs_connector_node_id node_id;
u32 dma_buffer_size;
u32 config_length;
- struct {
+ union {
union avs_gtw_attributes attrs;
- u32 blob[];
+ DECLARE_FLEX_ARRAY(u32, blob);
} config;
} __packed;
+static_assert(sizeof(struct avs_copier_gtw_cfg) == 16);
struct avs_copier_cfg {
struct avs_modcfg_base base;
@@ -734,6 +833,7 @@ struct avs_copier_cfg {
u32 feature_mask;
struct avs_copier_gtw_cfg gtw_cfg;
} __packed;
+static_assert(sizeof(struct avs_copier_cfg) == 84);
struct avs_volume_cfg {
u32 channel_id;
@@ -742,45 +842,62 @@ struct avs_volume_cfg {
u32 reserved; /* alignment */
u64 curve_duration;
} __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[];
} __packed;
+static_assert(sizeof(struct avs_peakvol_cfg) == 40);
struct avs_micsel_cfg {
struct avs_modcfg_base base;
struct avs_audio_format out_fmt;
} __packed;
+static_assert(sizeof(struct avs_micsel_cfg) == 64);
struct avs_mux_cfg {
struct avs_modcfg_base base;
struct avs_audio_format ref_fmt;
struct avs_audio_format out_fmt;
} __packed;
+static_assert(sizeof(struct avs_mux_cfg) == 88);
struct avs_updown_mixer_cfg {
struct avs_modcfg_base base;
u32 out_channel_config;
u32 coefficients_select;
- s32 coefficients[AVS_CHANNELS_MAX];
+ s32 coefficients[AVS_COEFF_CHANNELS_MAX];
u32 channel_map;
} __packed;
+static_assert(sizeof(struct avs_updown_mixer_cfg) == 84);
struct avs_src_cfg {
struct avs_modcfg_base base;
u32 out_freq;
} __packed;
+static_assert(sizeof(struct avs_src_cfg) == 44);
struct avs_probe_gtw_cfg {
union avs_connector_node_id node_id;
u32 dma_buffer_size;
} __packed;
+static_assert(sizeof(struct avs_probe_gtw_cfg) == 8);
struct avs_probe_cfg {
struct avs_modcfg_base base;
struct avs_probe_gtw_cfg gtw_cfg;
} __packed;
+static_assert(sizeof(struct avs_probe_cfg) == 48);
struct avs_aec_cfg {
struct avs_modcfg_base base;
@@ -788,24 +905,38 @@ struct avs_aec_cfg {
struct avs_audio_format out_fmt;
u32 cpc_lp_mode;
} __packed;
+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;
} __packed;
+static_assert(sizeof(struct avs_asrc_cfg) == 48);
struct avs_wov_cfg {
struct avs_modcfg_base base;
u32 cpc_lp_mode;
} __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,
};
@@ -815,6 +946,7 @@ struct avs_copier_sink_format {
struct avs_audio_format src_fmt;
struct avs_audio_format sink_fmt;
} __packed;
+static_assert(sizeof(struct avs_copier_sink_format) == 52);
int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
u8 instance_id, u32 sink_id,
@@ -823,6 +955,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 {
@@ -830,10 +963,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
@@ -848,6 +989,7 @@ struct avs_probe_dma {
union avs_connector_node_id node_id;
u32 dma_buffer_size;
} __packed;
+static_assert(sizeof(struct avs_probe_dma) == 8);
enum avs_probe_type {
AVS_PROBE_TYPE_INPUT = 0,
@@ -864,6 +1006,7 @@ union avs_probe_point_id {
u32 index:6;
} id;
} __packed;
+static_assert(sizeof(union avs_probe_point_id) == 4);
enum avs_connection_purpose {
AVS_CONNECTION_PURPOSE_EXTRACT = 0,
@@ -876,6 +1019,7 @@ struct avs_probe_point_desc {
u32 purpose;
union avs_connector_node_id node_id;
} __packed;
+static_assert(sizeof(struct avs_probe_point_desc) == 12);
int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas);
int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas);
diff --git a/sound/soc/intel/avs/mtl.c b/sound/soc/intel/avs/mtl.c
new file mode 100644
index 000000000000..d8bdd03275d7
--- /dev/null
+++ b/sound/soc/intel/avs/mtl.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright(c) 2021-2025 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "debug.h"
+#include "registers.h"
+#include "trace.h"
+
+#define MTL_HfDSSGBL_BASE 0x1000
+#define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0)
+#define MTL_HfDSSCS_SPA BIT(16)
+#define MTL_HfDSSCS_CPA BIT(24)
+
+#define MTL_DSPCS_BASE 0x178D00
+#define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4)
+#define MTL_DSPCCTL_SPA BIT(0)
+#define MTL_DSPCCTL_CPA BIT(8)
+#define MTL_DSPCCTL_OSEL GENMASK(25, 24)
+#define MTL_DSPCCTL_OSEL_HOST BIT(25)
+
+#define MTL_HfINT_BASE 0x1100
+#define MTL_REG_HfINTIPPTR (MTL_HfINT_BASE + 0x8)
+#define MTL_REG_HfHIPCIE (MTL_HfINT_BASE + 0x40)
+#define MTL_HfINTIPPTR_PTR GENMASK(20, 0)
+#define MTL_HfHIPCIE_IE BIT(0)
+
+#define MTL_DWICTL_INTENL_IE BIT(0)
+#define MTL_DWICTL_FINALSTATUSL_IPC BIT(0) /* same as ADSPIS_IPC */
+
+static int avs_mtl_core_power_on(struct avs_dev *adev)
+{
+ u32 reg;
+ int ret;
+
+ /* Power up DSP domain. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA);
+ trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true);
+
+ ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg,
+ (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+ if (ret) {
+ dev_err(adev->dev, "power on domain dsp failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Prevent power gating of DSP domain. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG,
+ MTL_HfPWRCTL_WPDSPHPxPG);
+ trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true);
+
+ ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS, reg,
+ (reg & MTL_HfPWRSTS_DSPHPxPGS) == MTL_HfPWRSTS_DSPHPxPGS,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+
+ /* Set ownership to HOST. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST);
+ return ret;
+}
+
+static int avs_mtl_core_power_off(struct avs_dev *adev)
+{
+ u32 reg;
+
+ /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, 0);
+ trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false);
+
+ /* Power down DSP domain. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0);
+ trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false);
+
+ return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg,
+ (reg & MTL_HfDSSCS_CPA) == 0,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+}
+
+int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power)
+{
+ core_mask &= AVS_MAIN_CORE_MASK;
+ if (!core_mask)
+ return 0;
+
+ if (power)
+ return avs_mtl_core_power_on(adev);
+ return avs_mtl_core_power_off(adev);
+}
+
+int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power)
+{
+ /* No logical equivalent on ACE 1.x. */
+ return 0;
+}
+
+int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
+{
+ u32 value, reg;
+ int ret;
+
+ core_mask &= AVS_MAIN_CORE_MASK;
+ if (!core_mask)
+ return 0;
+
+ value = snd_hdac_adsp_readl(adev, MTL_REG_DSPCCTL);
+ trace_avs_dsp_core_op(value, core_mask, "stall", stall);
+ if (value == UINT_MAX)
+ return 0;
+
+ value = stall ? 0 : MTL_DSPCCTL_SPA;
+ snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_SPA, value);
+
+ value = stall ? 0 : MTL_DSPCCTL_CPA;
+ ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_DSPCCTL,
+ reg, (reg & MTL_DSPCCTL_CPA) == value,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+ if (ret)
+ dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
+ core_mask, stall ? "" : "un", ret);
+ return ret;
+}
+
+static void avs_mtl_ipc_interrupt(struct avs_dev *adev)
+{
+ const struct avs_spec *spec = adev->spec;
+ u32 hipc_ack, hipc_rsp;
+
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
+
+ hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
+ hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
+
+ /* DSP acked host's request. */
+ if (hipc_ack & spec->hipc->ack_done_mask) {
+ complete(&adev->ipc->done_completion);
+
+ /* Tell DSP it has our attention. */
+ snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
+ spec->hipc->ack_done_mask);
+ }
+
+ /* DSP sent new response to process. */
+ if (hipc_rsp & spec->hipc->rsp_busy_mask) {
+ union avs_reply_msg msg;
+
+ msg.primary = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDR);
+ msg.ext.val = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDD);
+
+ avs_dsp_process_response(adev, msg.val);
+
+ /* Tell DSP we accepted its message. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDR,
+ MTL_HfIPCxTDR_BUSY, MTL_HfIPCxTDR_BUSY);
+ /* Ack this response. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDA, MTL_HfIPCxTDA_BUSY, 0);
+ }
+
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
+}
+
+irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev)
+{
+ u32 adspis = snd_hdac_adsp_readl(adev, MTL_DWICTL_REG_FINALSTATUSL);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (adspis == UINT_MAX)
+ return ret;
+
+ if (adspis & MTL_DWICTL_FINALSTATUSL_IPC) {
+ avs_mtl_ipc_interrupt(adev);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable)
+{
+ if (enable) {
+ snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE,
+ MTL_DWICTL_INTENL_IE);
+ snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, MTL_HfHIPCIE_IE);
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE,
+ AVS_ADSP_HIPCCTL_DONE);
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY,
+ AVS_ADSP_HIPCCTL_BUSY);
+ } else {
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, 0);
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, 0);
+ snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, 0);
+ snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, 0);
+ }
+}
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index adbe23a47847..c8b586aced20 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2021 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
-#include <sound/intel-nhlt.h>
+#include <linux/acpi.h>
+#include <acpi/nhlt.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "avs.h"
@@ -87,7 +88,7 @@ static bool avs_test_hw_params(struct snd_pcm_hw_params *params,
return (params_rate(params) == fmt->sampling_freq &&
params_channels(params) == fmt->num_channels &&
params_physical_width(params) == fmt->bit_depth &&
- params_width(params) == fmt->valid_bit_depth);
+ snd_pcm_hw_params_bits(params) == fmt->valid_bit_depth);
}
static struct avs_tplg_path *
@@ -114,158 +115,364 @@ avs_path_find_variant(struct avs_dev *adev,
return NULL;
}
-__maybe_unused
-static bool avs_dma_type_is_host(u32 dma_type)
+static struct avs_tplg_path *avs_condpath_find_variant(struct avs_dev *adev,
+ struct avs_tplg_path_template *template,
+ struct avs_path *source,
+ struct avs_path *sink)
{
- return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||
- dma_type == AVS_DMA_HDA_HOST_INPUT;
-}
+ struct avs_tplg_path *variant;
-__maybe_unused
-static bool avs_dma_type_is_link(u32 dma_type)
-{
- return !avs_dma_type_is_host(dma_type);
-}
+ list_for_each_entry(variant, &template->path_list, node) {
+ if (variant->source_path_id == source->template->id &&
+ variant->sink_path_id == sink->template->id)
+ return variant;
+ }
-__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;
+ return NULL;
}
-__maybe_unused
-static bool avs_dma_type_is_input(u32 dma_type)
+static bool avs_tplg_path_template_id_equal(struct avs_tplg_path_template_id *id,
+ struct avs_tplg_path_template_id *id2)
{
- return !avs_dma_type_is_output(dma_type);
+ return id->id == id2->id && !strcmp(id->tplg_name, id2->tplg_name);
}
-static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)
+static struct avs_path *avs_condpath_find_match(struct avs_dev *adev,
+ struct avs_tplg_path_template *template,
+ struct avs_path *path, int dir)
{
- struct nhlt_acpi_table *nhlt = adev->nhlt;
- struct avs_tplg_module *t = mod->template;
- struct avs_copier_cfg *cfg;
- struct nhlt_specific_cfg *ep_blob;
- union avs_connector_node_id node_id = {0};
- size_t cfg_size, data_size = 0;
- void *data = NULL;
- u32 dma_type;
- int ret;
+ struct avs_tplg_path_template_id *id, *id2;
- dma_type = t->cfg_ext->copier.dma_type;
- node_id.dma_type = dma_type;
+ if (dir) {
+ id = &template->source;
+ id2 = &template->sink;
+ } else {
+ id = &template->sink;
+ id2 = &template->source;
+ }
- switch (dma_type) {
- struct avs_audio_format *fmt;
- int direction;
+ /* Check whether this path is either source or sink of condpath template. */
+ if (id->id != path->template->owner->id ||
+ strcmp(id->tplg_name, path->template->owner->owner->name))
+ return NULL;
- 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_blob = intel_nhlt_get_endpoint_blob(adev->dev,
- nhlt, t->cfg_ext->copier.vindex.i2s.instance,
- NHLT_LINK_SSP, fmt->valid_bit_depth, fmt->bit_depth,
- fmt->num_channels, fmt->sampling_freq, direction,
- NHLT_DEVICE_I2S);
- if (!ep_blob) {
- dev_err(adev->dev, "no I2S ep_blob found\n");
- return -ENOENT;
- }
+ /* Unidirectional condpaths are allowed. */
+ if (avs_tplg_path_template_id_equal(id, id2))
+ return path;
- data = ep_blob->caps;
- data_size = ep_blob->size;
- /* I2S gateway's vindex is statically assigned in topology */
- node_id.vindex = t->cfg_ext->copier.vindex.val;
+ /* Now find the counterpart. */
+ return avs_path_find_path(adev, id2->tplg_name, id2->id);
+}
- break;
+static struct acpi_nhlt_config *
+avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t);
- 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_blob = intel_nhlt_get_endpoint_blob(adev->dev, nhlt, 0,
- NHLT_LINK_DMIC, fmt->valid_bit_depth,
- fmt->bit_depth, fmt->num_channels,
- fmt->sampling_freq, direction, NHLT_DEVICE_DMIC);
- if (!ep_blob) {
- dev_err(adev->dev, "no DMIC ep_blob found\n");
- return -ENOENT;
+int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template,
+ struct snd_pcm_hw_constraint_list *rate_list,
+ struct snd_pcm_hw_constraint_list *channels_list,
+ struct snd_pcm_hw_constraint_list *sample_bits_list)
+{
+ struct avs_tplg_path *path_template;
+ unsigned int *rlist, *clist, *slist;
+ size_t i;
+
+ i = 0;
+ list_for_each_entry(path_template, &template->path_list, node)
+ i++;
+
+ rlist = kcalloc(i, sizeof(*rlist), GFP_KERNEL);
+ clist = kcalloc(i, sizeof(*clist), GFP_KERNEL);
+ slist = kcalloc(i, sizeof(*slist), GFP_KERNEL);
+ if (!rlist || !clist || !slist)
+ return -ENOMEM;
+
+ i = 0;
+ list_for_each_entry(path_template, &template->path_list, node) {
+ struct avs_tplg_pipeline *pipeline_template;
+
+ list_for_each_entry(pipeline_template, &path_template->ppl_list, node) {
+ struct avs_tplg_module *module_template;
+
+ list_for_each_entry(module_template, &pipeline_template->mod_list, node) {
+ const guid_t *type = &module_template->cfg_ext->type;
+ struct acpi_nhlt_config *blob;
+
+ if (!guid_equal(type, &AVS_COPIER_MOD_UUID) &&
+ !guid_equal(type, &AVS_WOVHOSTM_MOD_UUID))
+ continue;
+
+ switch (module_template->cfg_ext->copier.dma_type) {
+ case AVS_DMA_DMIC_LINK_INPUT:
+ case AVS_DMA_I2S_LINK_OUTPUT:
+ case AVS_DMA_I2S_LINK_INPUT:
+ break;
+ default:
+ continue;
+ }
+
+ if (!module_template->nhlt_config) {
+ blob = avs_nhlt_config_or_default(adev, module_template);
+ if (IS_ERR(blob))
+ continue;
+ }
+
+ rlist[i] = path_template->fe_fmt->sampling_freq;
+ clist[i] = path_template->fe_fmt->num_channels;
+ slist[i] = path_template->fe_fmt->bit_depth;
+ i++;
+ }
}
+ }
+
+ if (i) {
+ rate_list->count = i;
+ rate_list->list = rlist;
+ channels_list->count = i;
+ channels_list->list = clist;
+ sample_bits_list->count = i;
+ sample_bits_list->list = slist;
+ } else {
+ kfree(rlist);
+ kfree(clist);
+ kfree(slist);
+ }
- data = ep_blob->caps;
- data_size = ep_blob->size;
- /* DMIC gateway's vindex is statically assigned in topology */
- node_id.vindex = t->cfg_ext->copier.vindex.val;
+ return i;
+}
+
+static void avs_init_node_id(union avs_connector_node_id *node_id,
+ struct avs_tplg_modcfg_ext *te, u32 dma_id)
+{
+ node_id->val = 0;
+ node_id->dma_type = te->copier.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;
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;
+ /* Gateway's virtual index is dynamically assigned with DMA ID */
+ node_id->vindex = dma_id;
break;
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;
+ node_id->vindex = te->copier.vindex.val | dma_id;
break;
- case INVALID_OBJECT_ID:
default:
- node_id = INVALID_NODE_ID;
+ *node_id = INVALID_NODE_ID;
break;
}
+}
- cfg_size = sizeof(*cfg) + data_size;
- /* Every config-BLOB contains gateway attributes. */
- if (data_size)
- cfg_size -= sizeof(cfg->gtw_cfg.config.attrs);
+/* Every BLOB contains at least gateway attributes. */
+static struct acpi_nhlt_config *default_blob = (struct acpi_nhlt_config *)&(u32[2]) {4};
- cfg = kzalloc(cfg_size, GFP_KERNEL);
- if (!cfg)
- return -ENOMEM;
+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;
+
+ te = t->cfg_ext;
+
+ switch (te->copier.dma_type) {
+ case AVS_DMA_I2S_LINK_OUTPUT:
+ 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:
+ link_type = ACPI_NHLT_LINKTYPE_PDM;
+ dev_type = -1; /* ignored */
+ bus_id = 0;
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ fmt = t->in_fmt;
+ break;
+
+ default:
+ return default_blob;
+ }
+
+ /* Override format selection if necessary. */
+ if (te->copier.blob_fmt)
+ fmt = te->copier.blob_fmt;
+
+ 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);
+ }
+
+ 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_append_dma_cfg(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw,
+ struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size)
+{
+ u32 dma_type = t->cfg_ext->copier.dma_type;
+ struct avs_dma_cfg *dma;
+ struct avs_tlv *tlv;
+ size_t tlv_size;
+
+ if (!avs_platattr_test(adev, ALTHDA))
+ return 0;
+
+ switch (dma_type) {
+ case AVS_DMA_HDA_HOST_OUTPUT:
+ case AVS_DMA_HDA_HOST_INPUT:
+ case AVS_DMA_HDA_LINK_OUTPUT:
+ case AVS_DMA_HDA_LINK_INPUT:
+ return 0;
+ default:
+ break;
+ }
+
+ tlv_size = sizeof(*tlv) + sizeof(*dma);
+ if (*cfg_size + tlv_size > AVS_MAILBOX_SIZE)
+ return -E2BIG;
+
+ /* DMA config is a TLV tailing the existing payload. */
+ tlv = (struct avs_tlv *)&gtw->config.blob[gtw->config_length];
+ tlv->type = AVS_GTW_DMA_CONFIG_ID;
+ tlv->length = sizeof(*dma);
+
+ dma = (struct avs_dma_cfg *)tlv->value;
+ memset(dma, 0, sizeof(*dma));
+ dma->dma_method = AVS_DMA_METHOD_HDA;
+ dma->pre_allocated = true;
+ dma->dma_channel_id = dma_id;
+ dma->stream_id = dma_id + 1;
+
+ gtw->config_length += tlv_size / sizeof(u32);
+ *cfg_size += tlv_size;
+
+ return 0;
+}
+
+static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw,
+ struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size)
+{
+ struct acpi_nhlt_config *blob;
+ size_t gtw_size;
+
+ if (t->nhlt_config)
+ blob = t->nhlt_config->blob;
+ else
+ 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 avs_append_dma_cfg(adev, gtw, t, dma_id, cfg_size);
+}
+
+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;
+ 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, dma_id, &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, 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, dma_id, &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);
- kfree(cfg);
+ 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;
@@ -281,47 +488,126 @@ 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 size;
+ 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. */
- size = struct_size(cfg, vols, 1);
- cfg = kzalloc(size, GFP_KERNEL);
- if (!cfg)
- return -ENOMEM;
+ cfg_size = struct_size(cfg, vols, 1);
+ if (cfg_size > AVS_MAILBOX_SIZE)
+ return -EINVAL;
+ cfg = adev->modcfg_buf;
+ memset(cfg, 0, cfg_size);
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->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, size, &mod->instance_id);
+ t->domain, cfg, cfg_size, &mod->instance_id);
+ if (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;
+ }
- kfree(cfg);
- 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)
@@ -337,7 +623,7 @@ static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *m
cfg.base.audio_fmt = *t->in_fmt;
cfg.out_channel_config = t->cfg_ext->updown_mix.out_channel_config;
cfg.coefficients_select = t->cfg_ext->updown_mix.coefficients_select;
- for (i = 0; i < AVS_CHANNELS_MAX; i++)
+ for (i = 0; i < AVS_COEFF_CHANNELS_MAX; i++)
cfg.coefficients[i] = t->cfg_ext->updown_mix.coefficients[i];
cfg.channel_map = t->cfg_ext->updown_mix.channel_map;
@@ -368,6 +654,7 @@ static int avs_asrc_create(struct avs_dev *adev, struct avs_path_module *mod)
struct avs_tplg_module *t = mod->template;
struct avs_asrc_cfg cfg;
+ memset(&cfg, 0, sizeof(cfg));
cfg.base.cpc = t->cfg_base->cpc;
cfg.base.ibs = t->cfg_base->ibs;
cfg.base.obs = t->cfg_base->obs;
@@ -480,10 +767,11 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)
num_pins = tcfg->generic.num_input_pins + tcfg->generic.num_output_pins;
cfg_size = struct_size(cfg, pin_fmts, num_pins);
- cfg = kzalloc(cfg_size, GFP_KERNEL);
- if (!cfg)
- return -ENOMEM;
+ if (cfg_size > AVS_MAILBOX_SIZE)
+ return -EINVAL;
+ cfg = adev->modcfg_buf;
+ memset(cfg, 0, cfg_size);
cfg->base.cpc = t->cfg_base->cpc;
cfg->base.ibs = t->cfg_base->ibs;
cfg->base.obs = t->cfg_base->obs;
@@ -505,7 +793,6 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)
ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,
t->core_id, t->domain, cfg, cfg_size,
&mod->instance_id);
- kfree(cfg);
return ret;
}
@@ -535,6 +822,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)
@@ -548,6 +836,33 @@ static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_mod
return avs_modext_create(adev, mod);
}
+static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod)
+{
+ struct avs_soc_component *acomp;
+
+ acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp);
+
+ u32 num_ids = mod->template->num_config_ids;
+ u32 *ids = mod->template->config_ids;
+
+ for (int i = 0; i < num_ids; i++) {
+ struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]];
+ size_t len = config->length;
+ void *data = config->data;
+ u32 param = config->param;
+ int ret;
+
+ ret = avs_ipc_set_large_config(adev, mod->module_id, mod->instance_id,
+ param, data, len);
+ if (ret) {
+ dev_err(adev->dev, "send initial module config failed: %d\n", ret);
+ return AVS_IPC_RET(ret);
+ }
+ }
+
+ return 0;
+}
+
static void avs_path_module_free(struct avs_dev *adev, struct avs_path_module *mod)
{
kfree(mod);
@@ -581,6 +896,12 @@ avs_path_module_create(struct avs_dev *adev,
return ERR_PTR(ret);
}
+ ret = avs_path_module_send_init_configs(adev, mod);
+ if (ret) {
+ kfree(mod);
+ return ERR_PTR(ret);
+ }
+
return mod;
}
@@ -678,8 +999,6 @@ static int avs_path_pipeline_arm(struct avs_dev *adev,
/* bind current module to next module on list */
source = mod;
sink = list_next_entry(mod, node);
- if (!source || !sink)
- return -EINVAL;
ret = avs_ipc_bind(adev, source->module_id, source->instance_id,
sink->module_id, sink->instance_id, 0, 0);
@@ -786,6 +1105,10 @@ static int avs_path_init(struct avs_dev *adev, struct avs_path *path,
path->dma_id = dma_id;
INIT_LIST_HEAD(&path->ppl_list);
INIT_LIST_HEAD(&path->node);
+ INIT_LIST_HEAD(&path->source_list);
+ INIT_LIST_HEAD(&path->sink_list);
+ INIT_LIST_HEAD(&path->source_node);
+ INIT_LIST_HEAD(&path->sink_node);
/* create all the pipelines */
list_for_each_entry(tppl, &template->ppl_list, node) {
@@ -869,12 +1192,129 @@ err:
return ERR_PTR(ret);
}
+static void avs_condpath_free(struct avs_dev *adev, struct avs_path *path)
+{
+ int ret;
+
+ list_del(&path->source_node);
+ list_del(&path->sink_node);
+
+ ret = avs_path_reset(path);
+ if (ret < 0)
+ dev_err(adev->dev, "reset condpath failed: %d\n", ret);
+
+ ret = avs_path_unbind(path);
+ if (ret < 0)
+ dev_err(adev->dev, "unbind condpath failed: %d\n", ret);
+
+ avs_path_free_unlocked(path);
+}
+
+static struct avs_path *avs_condpath_create(struct avs_dev *adev,
+ struct avs_tplg_path *template,
+ struct avs_path *source,
+ struct avs_path *sink)
+{
+ struct avs_path *path;
+ int ret;
+
+ path = avs_path_create_unlocked(adev, 0, template);
+ if (IS_ERR(path))
+ return path;
+
+ ret = avs_path_bind(path);
+ if (ret)
+ goto err_bind;
+
+ ret = avs_path_reset(path);
+ if (ret)
+ goto err_reset;
+
+ path->source = source;
+ path->sink = sink;
+ list_add_tail(&path->source_node, &source->source_list);
+ list_add_tail(&path->sink_node, &sink->sink_list);
+
+ return path;
+
+err_reset:
+ avs_path_unbind(path);
+err_bind:
+ avs_path_free_unlocked(path);
+ return ERR_PTR(ret);
+}
+
+static int avs_condpaths_walk(struct avs_dev *adev, struct avs_path *path, int dir)
+{
+ struct avs_soc_component *acomp;
+ struct avs_path *source, *sink;
+ struct avs_path **other;
+
+ if (dir) {
+ source = path;
+ other = &sink;
+ } else {
+ sink = path;
+ other = &source;
+ }
+
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ for (int i = 0; i < acomp->tplg->num_condpath_tmpls; i++) {
+ struct avs_tplg_path_template *template;
+ struct avs_tplg_path *variant;
+ struct avs_path *cpath;
+
+ template = &acomp->tplg->condpath_tmpls[i];
+
+ /* Do not create unidirectional condpaths twice. */
+ if (avs_tplg_path_template_id_equal(&template->source,
+ &template->sink) && dir)
+ continue;
+
+ *other = avs_condpath_find_match(adev, template, path, dir);
+ if (!*other)
+ continue;
+
+ variant = avs_condpath_find_variant(adev, template, source, sink);
+ if (!variant)
+ continue;
+
+ cpath = avs_condpath_create(adev, variant, source, sink);
+ if (IS_ERR(cpath))
+ return PTR_ERR(cpath);
+ }
+ }
+
+ return 0;
+}
+
+/* Caller responsible for holding adev->path_mutex. */
+static int avs_condpaths_walk_all(struct avs_dev *adev, struct avs_path *path)
+{
+ int ret;
+
+ ret = avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ return ret;
+
+ return avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_PLAYBACK);
+}
+
void avs_path_free(struct avs_path *path)
{
+ struct avs_path *cpath, *csave;
struct avs_dev *adev = path->owner;
mutex_lock(&adev->path_mutex);
+
+ /* Free all condpaths this path spawned. */
+ list_for_each_entry_safe(cpath, csave, &path->source_list, source_node)
+ avs_condpath_free(path->owner, cpath);
+ list_for_each_entry_safe(cpath, csave, &path->sink_list, sink_node)
+ avs_condpath_free(path->owner, cpath);
+
avs_path_free_unlocked(path);
+
mutex_unlock(&adev->path_mutex);
}
@@ -885,6 +1325,7 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
{
struct avs_tplg_path *variant;
struct avs_path *path;
+ int ret;
variant = avs_path_find_variant(adev, template, fe_params, be_params);
if (!variant) {
@@ -898,7 +1339,16 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
mutex_lock(&adev->comp_list_mutex);
path = avs_path_create_unlocked(adev, dma_id, variant);
+ if (IS_ERR(path))
+ goto exit;
+
+ ret = avs_condpaths_walk_all(adev, path);
+ if (ret) {
+ avs_path_free_unlocked(path);
+ path = ERR_PTR(ret);
+ }
+exit:
mutex_unlock(&adev->comp_list_mutex);
mutex_unlock(&adev->path_mutex);
@@ -1021,6 +1471,42 @@ int avs_path_reset(struct avs_path *path)
return 0;
}
+static int avs_condpath_pause(struct avs_dev *adev, struct avs_path *cpath)
+{
+ struct avs_path_pipeline *ppl;
+ int ret;
+
+ if (cpath->state == AVS_PPL_STATE_PAUSED)
+ return 0;
+
+ list_for_each_entry_reverse(ppl, &cpath->ppl_list, node) {
+ ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_PAUSED);
+ if (ret) {
+ dev_err(adev->dev, "pause cpath failed: %d\n", ret);
+ cpath->state = AVS_PPL_STATE_INVALID;
+ return AVS_IPC_RET(ret);
+ }
+ }
+
+ cpath->state = AVS_PPL_STATE_PAUSED;
+ return 0;
+}
+
+static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path)
+{
+ struct avs_path *cpath;
+
+ mutex_lock(&adev->path_mutex);
+
+ /* If either source or sink stops, so do the attached conditional paths. */
+ list_for_each_entry(cpath, &path->source_list, source_node)
+ avs_condpath_pause(adev, cpath);
+ list_for_each_entry(cpath, &path->sink_list, sink_node)
+ avs_condpath_pause(adev, cpath);
+
+ mutex_unlock(&adev->path_mutex);
+}
+
int avs_path_pause(struct avs_path *path)
{
struct avs_path_pipeline *ppl;
@@ -1030,6 +1516,8 @@ int avs_path_pause(struct avs_path *path)
if (path->state == AVS_PPL_STATE_PAUSED)
return 0;
+ avs_condpaths_pause(adev, path);
+
list_for_each_entry_reverse(ppl, &path->ppl_list, node) {
ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id,
AVS_PPL_STATE_PAUSED);
@@ -1044,6 +1532,50 @@ int avs_path_pause(struct avs_path *path)
return 0;
}
+static int avs_condpath_run(struct avs_dev *adev, struct avs_path *cpath, int trigger)
+{
+ struct avs_path_pipeline *ppl;
+ int ret;
+
+ if (cpath->state == AVS_PPL_STATE_RUNNING)
+ return 0;
+
+ list_for_each_entry(ppl, &cpath->ppl_list, node) {
+ if (ppl->template->cfg->trigger != trigger)
+ continue;
+
+ ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_RUNNING);
+ if (ret) {
+ dev_err(adev->dev, "run cpath failed: %d\n", ret);
+ cpath->state = AVS_PPL_STATE_INVALID;
+ return AVS_IPC_RET(ret);
+ }
+ }
+
+ cpath->state = AVS_PPL_STATE_RUNNING;
+ return 0;
+}
+
+static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int trigger)
+{
+ struct avs_path *cpath;
+
+ mutex_lock(&adev->path_mutex);
+
+ /* Run conditional paths only if source and sink are both running. */
+ list_for_each_entry(cpath, &path->source_list, source_node)
+ if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
+ cpath->sink->state == AVS_PPL_STATE_RUNNING)
+ avs_condpath_run(adev, cpath, trigger);
+
+ list_for_each_entry(cpath, &path->sink_list, sink_node)
+ if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
+ cpath->sink->state == AVS_PPL_STATE_RUNNING)
+ avs_condpath_run(adev, cpath, trigger);
+
+ mutex_unlock(&adev->path_mutex);
+}
+
int avs_path_run(struct avs_path *path, int trigger)
{
struct avs_path_pipeline *ppl;
@@ -1067,5 +1599,10 @@ int avs_path_run(struct avs_path *path, int trigger)
}
path->state = AVS_PPL_STATE_RUNNING;
+
+ /* Granular pipeline triggering not intended for conditional paths. */
+ if (trigger == AVS_TPLG_TRIGGER_AUTO)
+ avs_condpaths_run(adev, path, trigger);
+
return 0;
}
diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h
index 197222c5e008..ceb89971a902 100644
--- a/sound/soc/intel/avs/path.h
+++ b/sound/soc/intel/avs/path.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021 Intel Corporation
*
* Authors: Cezary Rojewski <cezary.rojewski@intel.com>
* Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -13,11 +13,24 @@
#include "avs.h"
#include "topology.h"
+#define AVS_COND_TYPE_NONE 0
+#define AVS_COND_TYPE_AECREF 1
+
struct avs_path {
u32 dma_id;
struct list_head ppl_list;
u32 state;
+ /* condpath navigation for standard paths */
+ struct list_head source_list;
+ struct list_head sink_list;
+
+ /* conditional path fields */
+ struct avs_path *source;
+ struct avs_path *sink;
+ struct list_head source_node;
+ struct list_head sink_node;
+
struct avs_tplg_path *template;
struct avs_dev *owner;
/* device path management */
@@ -37,7 +50,7 @@ struct avs_path_pipeline {
struct avs_path_module {
u16 module_id;
- u16 instance_id;
+ u8 instance_id;
union avs_gtw_attributes gtw_attrs;
struct avs_tplg_module *template;
@@ -69,4 +82,14 @@ 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_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template,
+ struct snd_pcm_hw_constraint_list *rate_list,
+ struct snd_pcm_hw_constraint_list *channels_list,
+ struct snd_pcm_hw_constraint_list *sample_bits_list);
+
+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 31c032a0f7e4..4a6deb599c88 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -16,19 +16,28 @@
#include <sound/soc-component.h>
#include "avs.h"
#include "path.h"
+#include "pcm.h"
#include "topology.h"
+#include "utils.h"
+#include "../../codecs/hda.h"
struct avs_dma_data {
struct avs_tplg_path_template *template;
struct avs_path *path;
- /*
- * link stream is stored within substream's runtime
- * private_data to fulfill the needs of codec BE path
- *
- * host stream assigned
- */
- struct hdac_ext_stream *host_stream;
+ struct avs_dev *adev;
+
+ /* LINK-stream utilized in BE operations while HOST in FE ones. */
+ union {
+ struct hdac_ext_stream *link_stream;
+ struct hdac_ext_stream *host_stream;
+ };
+ struct snd_pcm_hw_constraint_list rate_list;
+ struct snd_pcm_hw_constraint_list channels_list;
+ struct snd_pcm_hw_constraint_list sample_bits_list;
+
+ struct work_struct period_elapsed_work;
+ struct hdac_ext_link *link;
struct snd_pcm_substream *substream;
};
@@ -55,15 +64,66 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
return dw->priv;
}
-static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe,
- const struct snd_soc_dai_ops *ops)
+static void avs_period_elapsed_work(struct work_struct *work)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct avs_dev *adev = to_avs_dev(dai->dev);
+ struct avs_dma_data *data = container_of(work, struct avs_dma_data, period_elapsed_work);
+
+ snd_pcm_period_elapsed(data->substream);
+}
+
+void avs_period_elapsed(struct snd_pcm_substream *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 avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);
+
+ schedule_work(&data->period_elapsed_work);
+}
+
+static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule);
+static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_constraint_list *r, *c, *s;
+ struct avs_dma_data *data;
+ int ret;
+
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ return ret;
+
+ data = snd_soc_dai_get_dma_data(dai, substream);
+ r = &(data->rate_list);
+ c = &(data->channels_list);
+ s = &(data->sample_bits_list);
+
+ ret = avs_path_set_constraint(data->adev, data->template, r, c, s);
+ if (ret <= 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, r);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, c);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, s);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct avs_dev *adev = to_avs_dev(dai->component->dev);
struct avs_tplg_path_template *template;
struct avs_dma_data *data;
- template = avs_dai_find_path_template(dai, is_fe, substream->stream);
+ template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream);
if (!template) {
dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n",
snd_pcm_stream_str(substream), dai->name);
@@ -76,12 +136,32 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
data->substream = substream;
data->template = template;
+ data->adev = adev;
+ INIT_WORK(&data->period_elapsed_work, avs_period_elapsed_work);
snd_soc_dai_set_dma_data(dai, substream, data);
if (rtd->dai_link->ignore_suspend)
adev->num_lp_paths++;
- return 0;
+ return avs_hw_constraints_init(substream, dai);
+}
+
+static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct avs_dma_data *data;
+
+ data = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (rtd->dai_link->ignore_suspend)
+ data->adev->num_lp_paths--;
+
+ kfree(data->rate_list.list);
+ kfree(data->channels_list.list);
+ kfree(data->sample_bits_list.list);
+
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(data);
}
static int avs_dai_hw_params(struct snd_pcm_substream *substream,
@@ -91,7 +171,6 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream,
{
struct avs_dma_data *data;
struct avs_path *path;
- struct avs_dev *adev = to_avs_dev(dai->dev);
int ret;
data = snd_soc_dai_get_dma_data(dai, substream);
@@ -108,7 +187,7 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream,
params_rate(be_hw_params), params_channels(be_hw_params),
params_width(be_hw_params), params_physical_width(be_hw_params));
- path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params);
+ path = avs_path_create(data->adev, dma_id, data->template, fe_hw_params, be_hw_params);
if (IS_ERR(path)) {
ret = PTR_ERR(path);
dev_err(dai->dev, "create path failed: %d\n", ret);
@@ -127,7 +206,8 @@ static int avs_dai_be_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *fe, *be;
struct snd_soc_dpcm *dpcm;
- be = asoc_substream_to_rtd(substream);
+ 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;
@@ -136,8 +216,7 @@ static int avs_dai_be_hw_params(struct snd_pcm_substream *substream,
return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id);
}
-static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int avs_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct avs_dma_data *data;
int ret;
@@ -158,28 +237,6 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst
return ret;
}
-static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops;
-
-static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
-{
- return avs_dai_startup(substream, dai, false, &avs_dai_nonhda_be_ops);
-}
-
-static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct avs_dev *adev = to_avs_dev(dai->dev);
- struct avs_dma_data *data;
-
- if (rtd->dai_link->ignore_suspend)
- adev->num_lp_paths--;
-
- data = snd_soc_dai_get_dma_data(dai, substream);
-
- snd_soc_dai_set_dma_data(dai, substream, NULL);
- kfree(data);
-}
-
static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
{
@@ -208,15 +265,10 @@ static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct
return 0;
}
-static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
-{
- return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
-}
-
static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct avs_dma_data *data;
int ret = 0;
@@ -264,104 +316,167 @@ static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cm
}
static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
- .startup = avs_dai_nonhda_be_startup,
- .shutdown = avs_dai_nonhda_be_shutdown,
+ .startup = avs_dai_startup,
+ .shutdown = avs_dai_shutdown,
.hw_params = avs_dai_nonhda_be_hw_params,
.hw_free = avs_dai_nonhda_be_hw_free,
- .prepare = avs_dai_nonhda_be_prepare,
+ .prepare = avs_dai_prepare,
.trigger = avs_dai_nonhda_be_trigger,
};
-static const struct snd_soc_dai_ops avs_dai_hda_be_ops;
+static int __avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
+ struct hdac_ext_link *link)
+{
+ struct hdac_ext_stream *link_stream;
+ struct avs_dma_data *data;
+ int ret;
+
+ ret = avs_dai_startup(substream, dai);
+ if (ret)
+ return ret;
+
+ data = snd_soc_dai_get_dma_data(dai, substream);
+ link_stream = snd_hdac_ext_stream_assign(&data->adev->base.core, substream,
+ HDAC_EXT_STREAM_TYPE_LINK);
+ if (!link_stream) {
+ avs_dai_shutdown(substream, dai);
+ return -EBUSY;
+ }
+
+ data->link_stream = link_stream;
+ data->link = link;
+ return 0;
+}
static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- return avs_dai_startup(substream, dai, false, &avs_dai_hda_be_ops);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct hdac_ext_link *link;
+ struct avs_dma_data *data;
+ struct hda_codec *codec;
+ int ret;
+
+ codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev);
+
+ link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);
+ if (!link)
+ return -EINVAL;
+
+ ret = __avs_dai_hda_be_startup(substream, dai, link);
+ if (!ret) {
+ data = snd_soc_dai_get_dma_data(dai, substream);
+ substream->runtime->private_data = data->link_stream;
+ }
+
+ return ret;
+}
+
+static int avs_dai_i2shda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct avs_dev *adev = to_avs_dev(dai->component->dev);
+ struct hdac_ext_link *link;
+
+ link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_SSP);
+ if (!link)
+ return -EINVAL;
+ return __avs_dai_hda_be_startup(substream, dai, link);
+}
+
+static int avs_dai_dmichda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct avs_dev *adev = to_avs_dev(dai->component->dev);
+ struct hdac_ext_link *link;
+
+ link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_DMIC);
+ if (!link)
+ return -EINVAL;
+ return __avs_dai_hda_be_startup(substream, dai, link);
}
static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- return avs_dai_nonhda_be_shutdown(substream, dai);
+ struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);
+
+ snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK);
+ substream->runtime->private_data = NULL;
+ avs_dai_shutdown(substream, dai);
+}
+
+static void avs_dai_althda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);
+
+ snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK);
+ avs_dai_shutdown(substream, dai);
}
static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
{
struct avs_dma_data *data;
- struct hdac_ext_stream *link_stream;
data = snd_soc_dai_get_dma_data(dai, substream);
if (data->path)
return 0;
- link_stream = substream->runtime->private_data;
-
return avs_dai_be_hw_params(substream, hw_params, dai,
- hdac_stream(link_stream)->stream_tag - 1);
+ hdac_stream(data->link_stream)->stream_tag - 1);
}
static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- struct avs_dma_data *data;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct hdac_ext_stream *link_stream;
- struct hdac_ext_link *link;
- struct hda_codec *codec;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
+ struct avs_dma_data *data;
data = snd_soc_dai_get_dma_data(dai, substream);
if (!data->path)
return 0;
- link_stream = substream->runtime->private_data;
+ link_stream = data->link_stream;
link_stream->link_prepared = false;
avs_path_free(data->path);
data->path = NULL;
/* clear link <-> stream mapping */
- codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
- link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);
- if (!link)
- return -EINVAL;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_clear_stream_id(data->link,
+ hdac_stream(link_stream)->stream_tag);
return 0;
}
static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct hdac_ext_stream *link_stream = runtime->private_data;
- struct hdac_ext_link *link;
- struct hda_codec *codec;
- struct hdac_bus *bus;
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ const struct snd_soc_pcm_stream *stream_info;
+ struct hdac_ext_stream *link_stream;
+ const struct snd_pcm_hw_params *p;
+ struct avs_dma_data *data;
unsigned int format_val;
+ unsigned int bits;
int ret;
+ data = snd_soc_dai_get_dma_data(dai, substream);
+ link_stream = data->link_stream;
+ p = &be->dpcm[substream->stream].hw_params;
+
if (link_stream->link_prepared)
return 0;
- codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
- bus = &codec->bus->core;
- format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
- runtime->sample_bits, 0);
+ stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream);
+ bits = snd_hdac_stream_format_bits(params_format(p), params_subformat(p),
+ stream_info->sig_bits);
+ format_val = snd_hdac_stream_format(params_channels(p), bits, params_rate(p));
- snd_hdac_ext_stream_decouple(bus, link_stream, true);
+ snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true);
snd_hdac_ext_stream_reset(link_stream);
snd_hdac_ext_stream_setup(link_stream, format_val);
- link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr);
- if (!link)
- return -EINVAL;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);
+ snd_hdac_ext_bus_link_set_stream_id(data->link,
+ hdac_stream(link_stream)->stream_tag);
- ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
+ ret = avs_dai_prepare(substream, dai);
if (ret)
return ret;
@@ -372,15 +487,13 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct hdac_ext_stream *link_stream;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct avs_dma_data *data;
int ret = 0;
dev_dbg(dai->dev, "entry %s cmd=%d\n", __func__, cmd);
data = snd_soc_dai_get_dma_data(dai, substream);
- link_stream = substream->runtime->private_data;
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
@@ -389,7 +502,7 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
fallthrough;
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_stream_start(link_stream);
+ snd_hdac_ext_stream_start(data->link_stream);
ret = avs_path_pause(data->path);
if (ret < 0) {
@@ -412,7 +525,7 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0)
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
- snd_hdac_ext_stream_clear(link_stream);
+ snd_hdac_ext_stream_clear(data->link_stream);
ret = avs_path_reset(data->path);
if (ret < 0)
@@ -436,47 +549,94 @@ static const struct snd_soc_dai_ops avs_dai_hda_be_ops = {
.trigger = avs_dai_hda_be_trigger,
};
-static const unsigned int rates[] = {
- 8000, 11025, 12000, 16000,
- 22050, 24000, 32000, 44100,
- 48000, 64000, 88200, 96000,
- 128000, 176400, 192000,
+static const struct snd_soc_dai_ops avs_dai_i2shda_be_ops = {
+ .startup = avs_dai_i2shda_be_startup,
+ .shutdown = avs_dai_althda_be_shutdown,
+ .hw_params = avs_dai_hda_be_hw_params,
+ .hw_free = avs_dai_hda_be_hw_free,
+ .prepare = avs_dai_hda_be_prepare,
+ .trigger = avs_dai_hda_be_trigger,
};
-static const struct snd_pcm_hw_constraint_list hw_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
+static const struct snd_soc_dai_ops avs_dai_dmichda_be_ops = {
+ .startup = avs_dai_dmichda_be_startup,
+ .shutdown = avs_dai_althda_be_shutdown,
+ .hw_params = avs_dai_hda_be_hw_params,
+ .hw_free = avs_dai_hda_be_hw_free,
+ .prepare = avs_dai_hda_be_prepare,
+ .trigger = avs_dai_hda_be_trigger,
};
-const struct snd_soc_dai_ops avs_dai_fe_ops;
+static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *interval = hw_param_interval(params, rule->var);
+ struct snd_interval to;
-static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+ snd_interval_any(&to);
+ to.integer = interval->integer;
+ to.max = interval->max;
+ /*
+ * Commonly 2ms buffer size is used in HDA scenarios whereas 4ms is used
+ * when streaming through GPDMA. Align to the latter to account for both.
+ */
+ to.min = params_rate(params) / 1000 * 4;
+
+ if (rule->var == SNDRV_PCM_HW_PARAM_PERIOD_SIZE)
+ to.min /= params_periods(params);
+
+ return snd_interval_refine(interval, &to);
+}
+
+static int avs_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct avs_dma_data *data;
- struct avs_dev *adev = to_avs_dev(dai->dev);
- struct hdac_bus *bus = &adev->base.core;
+ int ret;
+
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ return ret;
+
+ /* Avoid wrap-around with wall-clock. */
+ ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);
+ if (ret < 0)
+ return ret;
+
+ /* Adjust buffer and period size based on the audio format. */
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, hw_rule_param_size, NULL,
+ SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, hw_rule_param_size, NULL,
+ SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+
+ return 0;
+}
+
+static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
struct hdac_ext_stream *host_stream;
+ struct avs_dma_data *data;
+ struct hdac_bus *bus;
int ret;
- ret = avs_dai_startup(substream, dai, true, &avs_dai_fe_ops);
+ ret = avs_pcm_hw_constraints_init(substream);
+ if (ret)
+ return ret;
+
+ ret = avs_dai_startup(substream, dai);
if (ret)
return ret;
data = snd_soc_dai_get_dma_data(dai, substream);
+ bus = &data->adev->base.core;
host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST);
if (!host_stream) {
- kfree(data);
+ avs_dai_shutdown(substream, dai);
return -EBUSY;
}
data->host_stream = host_stream;
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- /* avoid wrap-around with wall-clock */
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates);
snd_pcm_set_sync(substream);
dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p",
@@ -487,18 +647,13 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct avs_dev *adev = to_avs_dev(dai->dev);
struct avs_dma_data *data;
- if (rtd->dai_link->ignore_suspend)
- adev->num_lp_paths--;
-
data = snd_soc_dai_get_dma_data(dai, substream);
- snd_soc_dai_set_dma_data(dai, substream, NULL);
+ disable_work_sync(&data->period_elapsed_work);
snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST);
- kfree(data);
+ avs_dai_shutdown(substream, dai);
}
static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream,
@@ -521,7 +676,8 @@ static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream,
hdac_stream(host_stream)->period_bytes = 0;
hdac_stream(host_stream)->format_val = 0;
- fe = asoc_substream_to_rtd(substream);
+ 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;
@@ -588,16 +744,19 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so
static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ const struct snd_soc_pcm_stream *stream_info;
struct avs_dma_data *data;
- struct avs_dev *adev = to_avs_dev(dai->dev);
struct hdac_ext_stream *host_stream;
- struct hdac_bus *bus;
unsigned int format_val;
+ struct hdac_bus *bus;
+ unsigned int bits;
int ret;
data = snd_soc_dai_get_dma_data(dai, substream);
host_stream = data->host_stream;
+ if (runtime->state == SNDRV_PCM_STATE_XRUN)
+ hdac_stream(host_stream)->prepared = false;
if (hdac_stream(host_stream)->prepared)
return 0;
@@ -605,18 +764,20 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
snd_hdac_ext_stream_decouple(bus, data->host_stream, true);
snd_hdac_stream_reset(hdac_stream(host_stream));
- format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
- runtime->sample_bits, 0);
+ stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream);
+ bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat,
+ stream_info->sig_bits);
+ format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate);
ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
if (ret < 0)
return ret;
- ret = snd_hdac_stream_setup(hdac_stream(host_stream));
+ ret = snd_hdac_ext_host_stream_setup(host_stream, false);
if (ret < 0)
return ret;
- ret = avs_dai_prepare(adev, substream, dai);
+ ret = avs_dai_prepare(substream, dai);
if (ret)
return ret;
@@ -624,9 +785,82 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
return 0;
}
+static void avs_hda_stream_start(struct hdac_bus *bus, struct hdac_ext_stream *host_stream)
+{
+ struct hdac_stream *first_running = NULL;
+ struct hdac_stream *pos;
+ struct avs_dev *adev = hdac_to_avs(bus);
+
+ list_for_each_entry(pos, &bus->stream_list, list) {
+ if (pos->running) {
+ if (first_running)
+ break; /* more than one running */
+ first_running = pos;
+ }
+ }
+
+ /*
+ * If host_stream is a CAPTURE stream and will be the only one running,
+ * disable L1SEN to avoid sound clipping.
+ */
+ if (!first_running) {
+ if (hdac_stream(host_stream)->direction == SNDRV_PCM_STREAM_CAPTURE)
+ avs_hda_l1sen_enable(adev, false);
+ snd_hdac_stream_start(hdac_stream(host_stream));
+ return;
+ }
+
+ snd_hdac_stream_start(hdac_stream(host_stream));
+ /*
+ * If host_stream is the first stream to break the rule above,
+ * re-enable L1SEN.
+ */
+ if (list_entry_is_head(pos, &bus->stream_list, list) &&
+ first_running->direction == SNDRV_PCM_STREAM_CAPTURE)
+ avs_hda_l1sen_enable(adev, true);
+}
+
+static void avs_hda_stream_stop(struct hdac_bus *bus, struct hdac_ext_stream *host_stream)
+{
+ struct hdac_stream *first_running = NULL;
+ struct hdac_stream *pos;
+ struct avs_dev *adev = hdac_to_avs(bus);
+
+ list_for_each_entry(pos, &bus->stream_list, list) {
+ if (pos == hdac_stream(host_stream))
+ continue; /* ignore stream that is about to be stopped */
+ if (pos->running) {
+ if (first_running)
+ break; /* more than one running */
+ first_running = pos;
+ }
+ }
+
+ /*
+ * If host_stream is a CAPTURE stream and is the only one running,
+ * re-enable L1SEN.
+ */
+ if (!first_running) {
+ snd_hdac_stream_stop(hdac_stream(host_stream));
+ if (hdac_stream(host_stream)->direction == SNDRV_PCM_STREAM_CAPTURE)
+ avs_hda_l1sen_enable(adev, true);
+ return;
+ }
+
+ /*
+ * If by stopping host_stream there is only a single, CAPTURE stream running
+ * left, disable L1SEN to avoid sound clipping.
+ */
+ if (list_entry_is_head(pos, &bus->stream_list, list) &&
+ first_running->direction == SNDRV_PCM_STREAM_CAPTURE)
+ avs_hda_l1sen_enable(adev, false);
+
+ snd_hdac_stream_stop(hdac_stream(host_stream));
+}
+
static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct avs_dma_data *data;
struct hdac_ext_stream *host_stream;
struct hdac_bus *bus;
@@ -645,7 +879,7 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
spin_lock_irqsave(&bus->reg_lock, flags);
- snd_hdac_stream_start(hdac_stream(host_stream));
+ avs_hda_stream_start(bus, host_stream);
spin_unlock_irqrestore(&bus->reg_lock, flags);
/* Timeout on DRSM poll shall not stop the resume so ignore the result. */
@@ -675,7 +909,7 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru
dev_err(dai->dev, "pause FE path failed: %d\n", ret);
spin_lock_irqsave(&bus->reg_lock, flags);
- snd_hdac_stream_stop(hdac_stream(host_stream));
+ avs_hda_stream_stop(bus, host_stream);
spin_unlock_irqrestore(&bus->reg_lock, flags);
ret = avs_path_reset(data->path);
@@ -748,7 +982,6 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
if (!ret)
ret = avs_module_info_init(adev, false);
- pm_runtime_mark_last_busy(adev->dev);
pm_runtime_put_autosuspend(adev->dev);
return ret;
@@ -783,6 +1016,29 @@ static int avs_component_probe(struct snd_soc_component *component)
ret = avs_load_topology(component, filename);
kfree(filename);
+ if (ret == -ENOENT && !strncmp(mach->tplg_filename, "hda-", 4)) {
+ unsigned int vendor_id;
+
+ if (sscanf(mach->tplg_filename, "hda-%08x-tplg.bin", &vendor_id) != 1)
+ return ret;
+
+ if (((vendor_id >> 16) & 0xFFFF) == 0x8086)
+ mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
+ "hda-8086-generic-tplg.bin");
+ else
+ mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
+ "hda-generic-tplg.bin");
+ if (!mach->tplg_filename)
+ return -ENOMEM;
+ filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
+ mach->tplg_filename);
+ if (!filename)
+ return -ENOMEM;
+
+ dev_info(card->dev, "trying to load fallback topology %s\n", mach->tplg_filename);
+ ret = avs_load_topology(component, filename);
+ kfree(filename);
+ }
if (ret < 0)
return ret;
@@ -834,7 +1090,7 @@ static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data
int ret;
substream = data->substream;
- rtd = asoc_substream_to_rtd(substream);
+ rtd = snd_soc_substream_to_rtd(substream);
ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai);
if (ret)
@@ -929,7 +1185,7 @@ static int avs_component_pm_op(struct snd_soc_component *component, bool be,
for_each_component_dais(component, dai) {
data = snd_soc_dai_dma_data_get_playback(dai);
if (data) {
- rtd = asoc_substream_to_rtd(data->substream);
+ rtd = snd_soc_substream_to_rtd(data->substream);
if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
ret = op(dai, data);
if (ret < 0) {
@@ -942,7 +1198,7 @@ static int avs_component_pm_op(struct snd_soc_component *component, bool be,
data = snd_soc_dai_dma_data_get_capture(dai);
if (data) {
- rtd = asoc_substream_to_rtd(data->substream);
+ rtd = snd_soc_substream_to_rtd(data->substream);
if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {
ret = op(dai, data);
if (ret < 0) {
@@ -1033,8 +1289,10 @@ static const struct snd_pcm_hardware avs_pcm_hardware = {
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
.buffer_bytes_max = AZX_MAX_BUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = AZX_MAX_BUF_SIZE / 2,
@@ -1046,7 +1304,7 @@ static const struct snd_pcm_hardware avs_pcm_hardware = {
static int avs_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
/* only FE DAI links are handled here */
if (rtd->dai_link->no_pcm)
@@ -1064,12 +1322,12 @@ static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
static snd_pcm_uframes_t
avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct avs_dma_data *data;
struct hdac_ext_stream *host_stream;
unsigned int pos;
- data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if (!data->host_stream)
return 0;
@@ -1094,7 +1352,7 @@ static int avs_component_mmap(struct snd_soc_component *component,
static int avs_component_construct(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_pcm *pcm = rtd->pcm;
if (dai->driver->playback.channels_min)
@@ -1110,7 +1368,7 @@ static int avs_component_construct(struct snd_soc_component *component,
return 0;
}
-static const struct snd_soc_component_driver avs_component_driver = {
+static struct snd_soc_component_driver avs_component_driver = {
.name = "avs-pcm",
.probe = avs_component_probe,
.remove = avs_component_remove,
@@ -1124,9 +1382,9 @@ static const struct snd_soc_component_driver avs_component_driver = {
.topology_name_prefix = "intel/avs",
};
-int avs_soc_component_register(struct device *dev, const char *name,
- const struct snd_soc_component_driver *drv,
- struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
+int avs_register_component(struct device *dev, const char *name,
+ struct snd_soc_component_driver *drv,
+ struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
{
struct avs_soc_component *acomp;
int ret;
@@ -1135,21 +1393,24 @@ int avs_soc_component_register(struct device *dev, const char *name,
if (!acomp)
return -ENOMEM;
+ acomp->base.name = devm_kstrdup(dev, name, GFP_KERNEL);
+ if (!acomp->base.name)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&acomp->node);
+
+ drv->use_dai_pcm_id = !obsolete_card_names;
+
ret = snd_soc_component_initialize(&acomp->base, drv, dev);
if (ret < 0)
return ret;
- /* force name change after ASoC is done with its init */
- acomp->base.name = name;
- INIT_LIST_HEAD(&acomp->node);
-
return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
}
static struct snd_soc_dai_driver dmic_cpu_dais[] = {
{
.name = "DMIC Pin",
- .ops = &avs_dai_nonhda_be_ops,
.capture = {
.stream_name = "DMIC Rx",
.channels_min = 1,
@@ -1160,7 +1421,6 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = {
},
{
.name = "DMIC WoV Pin",
- .ops = &avs_dai_nonhda_be_ops,
.capture = {
.stream_name = "DMIC WoV Rx",
.channels_min = 1,
@@ -1171,72 +1431,100 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = {
},
};
-int avs_dmic_platform_register(struct avs_dev *adev, const char *name)
+int avs_register_dmic_component(struct avs_dev *adev, const char *name)
{
- return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais,
- ARRAY_SIZE(dmic_cpu_dais));
+ const struct snd_soc_dai_ops *ops;
+
+ if (avs_platattr_test(adev, ALTHDA))
+ ops = &avs_dai_dmichda_be_ops;
+ else
+ ops = &avs_dai_nonhda_be_ops;
+
+ dmic_cpu_dais[0].ops = ops;
+ dmic_cpu_dais[1].ops = ops;
+ return avs_register_component(adev->dev, name, &avs_component_driver, dmic_cpu_dais,
+ ARRAY_SIZE(dmic_cpu_dais));
}
static const struct snd_soc_dai_driver i2s_dai_template = {
- .ops = &avs_dai_nonhda_be_ops,
.playback = {
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = AVS_CHANNELS_MAX,
.rates = SNDRV_PCM_RATE_8000_192000 |
- SNDRV_PCM_RATE_KNOT,
+ SNDRV_PCM_RATE_12000 |
+ SNDRV_PCM_RATE_24000 |
+ SNDRV_PCM_RATE_128000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
.capture = {
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = AVS_CHANNELS_MAX,
.rates = SNDRV_PCM_RATE_8000_192000 |
- SNDRV_PCM_RATE_KNOT,
+ SNDRV_PCM_RATE_12000 |
+ SNDRV_PCM_RATE_24000 |
+ SNDRV_PCM_RATE_128000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
};
-int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
- unsigned long *tdms)
+int avs_register_i2s_component(struct avs_dev *adev, const char *name, unsigned long port_mask,
+ unsigned long *tdms)
{
struct snd_soc_dai_driver *cpus, *dai;
+ const struct snd_soc_dai_ops *ops;
size_t ssp_count, cpu_count;
int i, j;
ssp_count = adev->hw_cfg.i2s_caps.ctrl_count;
- cpu_count = hweight_long(port_mask);
+ if (avs_platattr_test(adev, ALTHDA))
+ ops = &avs_dai_i2shda_be_ops;
+ else
+ ops = &avs_dai_nonhda_be_ops;
+
+ cpu_count = 0;
+ for_each_set_bit(i, &port_mask, ssp_count)
+ if (!tdms || test_bit(0, &tdms[i]))
+ cpu_count++;
if (tdms)
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;
dai = cpus;
for_each_set_bit(i, &port_mask, ssp_count) {
- memcpy(dai, &i2s_dai_template, sizeof(*dai));
+ if (!tdms || test_bit(0, &tdms[i])) {
+ memcpy(dai, &i2s_dai_template, sizeof(*dai));
- dai->name =
- devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i);
- dai->playback.stream_name =
- devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i);
- dai->capture.stream_name =
- devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i);
+ dai->name =
+ devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i);
+ dai->playback.stream_name =
+ devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i);
+ dai->capture.stream_name =
+ devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i);
- if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
- return -ENOMEM;
- dai++;
+ if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
+ return -ENOMEM;
+ dai->ops = ops;
+ dai++;
+ }
}
if (!tdms)
goto plat_register;
for_each_set_bit(i, &port_mask, ssp_count) {
- for_each_set_bit(j, &tdms[i], ssp_count) {
+ for_each_set_bit(j, &tdms[i], AVS_CHANNELS_MAX) {
memcpy(dai, &i2s_dai_template, sizeof(*dai));
dai->name =
@@ -1248,12 +1536,13 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
return -ENOMEM;
+ dai->ops = ops;
dai++;
}
}
plat_register:
- return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count);
+ return avs_register_component(adev->dev, name, &avs_component_driver, cpus, cpu_count);
}
/* HD-Audio CPU DAI template */
@@ -1261,19 +1550,23 @@ static const struct snd_soc_dai_driver hda_cpu_dai = {
.ops = &avs_dai_hda_be_ops,
.playback = {
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = AVS_CHANNELS_MAX,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
.capture = {
.channels_min = 1,
- .channels_max = 8,
+ .channels_max = AVS_CHANNELS_MAX,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
};
@@ -1281,12 +1574,14 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen
{
struct snd_soc_acpi_mach *mach;
struct snd_soc_dai *dai, *save;
+ struct avs_mach_pdata *pdata;
struct hda_codec *codec;
char name[32];
mach = dev_get_platdata(component->card->dev);
- codec = mach->pdata;
- sprintf(name, "%s-cpu", dev_name(&codec->core.dev));
+ pdata = mach->pdata;
+ codec = pdata->codec;
+ snprintf(name, sizeof(name), "%s-cpu", dev_name(&codec->core.dev));
for_each_component_dais_safe(component, dai, save) {
int stream;
@@ -1306,6 +1601,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
struct snd_soc_dapm_context *dapm;
struct snd_soc_dai_driver *dais;
struct snd_soc_acpi_mach *mach;
+ struct avs_mach_pdata *pdata;
struct hda_codec *codec;
struct hda_pcm *pcm;
const char *cname;
@@ -1315,7 +1611,8 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
if (!mach)
return -EINVAL;
- codec = mach->pdata;
+ pdata = mach->pdata;
+ codec = pdata->codec;
if (list_empty(&codec->pcm_list_head))
return -EINVAL;
list_for_each_entry(pcm, &codec->pcm_list_head, list)
@@ -1327,7 +1624,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
return -ENOMEM;
cname = dev_name(&codec->core.dev);
- dapm = snd_soc_component_get_dapm(component);
+ dapm = snd_soc_component_to_dapm(component);
pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
@@ -1350,6 +1647,15 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
ret = -ENOMEM;
goto exit;
}
+
+ if (!hda_codec_is_display(codec)) {
+ dais[i].playback.formats = pcm->stream[0].formats;
+ dais[i].playback.subformats = pcm->stream[0].subformats;
+ dais[i].playback.rates = pcm->stream[0].rates;
+ dais[i].playback.channels_min = pcm->stream[0].channels_min;
+ dais[i].playback.channels_max = pcm->stream[0].channels_max;
+ dais[i].playback.sig_bits = pcm->stream[0].maxbps;
+ }
}
if (pcm->stream[1].substreams) {
@@ -1360,6 +1666,15 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
ret = -ENOMEM;
goto exit;
}
+
+ if (!hda_codec_is_display(codec)) {
+ dais[i].capture.formats = pcm->stream[1].formats;
+ dais[i].capture.subformats = pcm->stream[1].subformats;
+ dais[i].capture.rates = pcm->stream[1].rates;
+ dais[i].capture.channels_min = pcm->stream[1].channels_min;
+ dais[i].capture.channels_max = pcm->stream[1].channels_max;
+ dais[i].capture.sig_bits = pcm->stream[1].maxbps;
+ }
}
dai = snd_soc_register_dai(component, &dais[i], false);
@@ -1374,6 +1689,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;
}
}
@@ -1388,16 +1704,14 @@ 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,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct hdac_ext_stream *link_stream;
- struct hda_codec *codec;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (!rtd->dai_link->no_pcm) {
struct snd_pcm_hardware hwparams = avs_pcm_hardware;
@@ -1429,41 +1743,16 @@ static int avs_component_hda_open(struct snd_soc_component *component,
return snd_soc_set_runtime_hwparams(substream, &hwparams);
}
- codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev);
- link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream,
- HDAC_EXT_STREAM_TYPE_LINK);
- if (!link_stream)
- return -EBUSY;
-
- substream->runtime->private_data = link_stream;
- return 0;
-}
-
-static int avs_component_hda_close(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct hdac_ext_stream *link_stream;
-
- /* only BE DAI links are handled here */
- if (!rtd->dai_link->no_pcm)
- return 0;
-
- link_stream = substream->runtime->private_data;
- snd_hdac_ext_stream_release(link_stream, HDAC_EXT_STREAM_TYPE_LINK);
- substream->runtime->private_data = NULL;
-
return 0;
}
-static const struct snd_soc_component_driver avs_hda_component_driver = {
+static struct snd_soc_component_driver avs_hda_component_driver = {
.name = "avs-hda-pcm",
.probe = avs_component_hda_probe,
.remove = avs_component_hda_remove,
.suspend = avs_component_suspend,
.resume = avs_component_resume,
.open = avs_component_hda_open,
- .close = avs_component_hda_close,
.pointer = avs_component_pointer,
.mmap = avs_component_mmap,
.pcm_construct = avs_component_construct,
@@ -1478,8 +1767,7 @@ static const struct snd_soc_component_driver avs_hda_component_driver = {
.topology_name_prefix = "intel/avs",
};
-int avs_hda_platform_register(struct avs_dev *adev, const char *name)
+int avs_register_hda_component(struct avs_dev *adev, const char *name)
{
- return avs_soc_component_register(adev->dev, name,
- &avs_hda_component_driver, NULL, 0);
+ return avs_register_component(adev->dev, name, &avs_hda_component_driver, NULL, 0);
}
diff --git a/sound/soc/intel/avs/pcm.h b/sound/soc/intel/avs/pcm.h
new file mode 100644
index 000000000000..0f3615c90398
--- /dev/null
+++ b/sound/soc/intel/avs/pcm.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2024 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_PCM_H
+#define __SOUND_SOC_INTEL_AVS_PCM_H
+
+#include <sound/pcm.h>
+
+void avs_period_elapsed(struct snd_pcm_substream *substream);
+
+#endif
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
index 70a94201d6a5..74096236984a 100644
--- a/sound/soc/intel/avs/probes.c
+++ b/sound/soc/intel/avs/probes.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -11,24 +11,32 @@
#include <sound/hdaudio.h>
#include <sound/soc.h>
#include "avs.h"
+#include "debug.h"
#include "messages.h"
-static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
- size_t buffer_size)
+static int avs_dsp_init_probe(struct avs_dev *adev, struct snd_compr_params *params, int bps,
+ union avs_connector_node_id node_id, size_t buffer_size)
{
struct avs_probe_cfg cfg = {{0}};
struct avs_module_entry mentry;
- u16 dummy;
+ u8 dummy;
+ int ret;
- avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+ ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+ if (ret)
+ return ret;
/*
- * Probe module uses no cycles, audio data format and input and output
- * frame sizes are unused. It is also not owned by any pipeline.
+ * Probe module uses no cycles, input and output frame sizes are unused.
+ * It is also not owned by any pipeline.
*/
cfg.base.ibs = 1;
/* BSS module descriptor is always segment of index=2. */
cfg.base.is_pages = mentry.segments[2].flags.length;
+ cfg.base.audio_fmt.sampling_freq = params->codec.sample_rate;
+ cfg.base.audio_fmt.bit_depth = bps;
+ cfg.base.audio_fmt.num_channels = params->codec.ch_out;
+ cfg.base.audio_fmt.valid_bit_depth = bps;
cfg.gtw_cfg.node_id = node_id;
cfg.gtw_cfg.dma_buffer_size = buffer_size;
@@ -39,11 +47,12 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id
static void avs_dsp_delete_probe(struct avs_dev *adev)
{
struct avs_module_entry mentry;
+ int ret;
- avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
-
- /* There is only ever one probe module instance. */
- avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
+ ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
+ if (!ret)
+ /* There is only ever one probe module instance. */
+ avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
}
static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream)
@@ -123,8 +132,6 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
struct snd_compr_runtime *rtd = cstream->runtime;
struct avs_dev *adev = to_avs_dev(dai->dev);
- /* compr params do not store bit depth, default to S32_LE. */
- snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
unsigned int format_val;
int bps, ret;
@@ -137,15 +144,14 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
if (ret < 0)
return ret;
- bps = snd_pcm_format_physical_width(format);
+ bps = snd_pcm_format_physical_width(params->codec.format);
if (bps < 0)
return bps;
- format_val = snd_hdac_calc_stream_format(params->codec.sample_rate, params->codec.ch_out,
- format, bps, 0);
+ format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
if (ret < 0)
return ret;
- ret = snd_hdac_stream_setup(hdac_stream(host_stream));
+ ret = snd_hdac_stream_setup(hdac_stream(host_stream), false);
if (ret < 0)
return ret;
@@ -162,7 +168,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
- ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
+ ret = avs_dsp_init_probe(adev, params, bps, node_id, rtd->dma_bytes);
if (ret < 0) {
dev_err(dai->dev, "probe init failed: %d\n", ret);
avs_dsp_enable_d0ix(adev);
@@ -210,7 +216,7 @@ static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
}
static int avs_probe_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
+ struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai)
{
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
struct snd_soc_pcm_stream *pstream;
@@ -249,7 +255,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr
return count;
}
-static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
+static const struct snd_soc_cdai_ops avs_probe_cdai_ops = {
.startup = avs_probe_compr_open,
.shutdown = avs_probe_compr_free,
.set_params = avs_probe_compr_set_params,
@@ -257,6 +263,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
.pointer = avs_probe_compr_pointer,
};
+static const struct snd_soc_dai_ops avs_probe_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static const struct snd_compress_ops avs_probe_compress_ops = {
.copy = avs_probe_compr_copy,
};
@@ -264,8 +274,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = {
static struct snd_soc_dai_driver probe_cpu_dais[] = {
{
.name = "Probe Extraction CPU DAI",
- .compress_new = snd_soc_new_compress,
- .cops = &avs_probe_dai_ops,
+ .cops = &avs_probe_cdai_ops,
+ .ops = &avs_probe_dai_ops,
.capture = {
.stream_name = "Probe Extraction",
.channels_min = 1,
@@ -283,8 +293,22 @@ static const struct snd_soc_component_driver avs_probe_component_driver = {
.module_get_upon_open = 1, /* increment refcount when a stream is opened */
};
-int avs_probe_platform_register(struct avs_dev *adev, const char *name)
+int avs_register_probe_component(struct avs_dev *adev, const char *name)
{
- return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver,
- probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
+ struct snd_soc_component *component;
+ int ret;
+
+ component = devm_kzalloc(adev->dev, sizeof(*component), GFP_KERNEL);
+ if (!component)
+ return -ENOMEM;
+
+ component->name = devm_kstrdup(adev->dev, name, GFP_KERNEL);
+ if (!component->name)
+ return -ENOMEM;
+
+ ret = snd_soc_component_initialize(component, &avs_probe_component_driver, adev->dev);
+ if (ret)
+ return ret;
+
+ return snd_soc_add_component(component, probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
}
diff --git a/sound/soc/intel/avs/ptl.c b/sound/soc/intel/avs/ptl.c
new file mode 100644
index 000000000000..07da9b0aa2b8
--- /dev/null
+++ b/sound/soc/intel/avs/ptl.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright(c) 2024-2025 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "debug.h"
+#include "registers.h"
+#include "trace.h"
+
+#define MTL_HfDSSGBL_BASE 0x1000
+#define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0)
+#define MTL_HfDSSCS_SPA BIT(16)
+#define MTL_HfDSSCS_CPA BIT(24)
+
+#define MTL_DSPCS_BASE 0x178D00
+#define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4)
+#define MTL_DSPCCTL_OSEL GENMASK(25, 24)
+#define MTL_DSPCCTL_OSEL_HOST BIT(25)
+
+static int avs_ptl_core_power_on(struct avs_dev *adev)
+{
+ u32 reg;
+ int ret;
+
+ /* Power up DSP domain. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA);
+ trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true);
+
+ ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg,
+ (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+ if (ret) {
+ dev_err(adev->dev, "power on domain dsp failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Prevent power gating of DSP domain. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG,
+ MTL_HfPWRCTL2_WPDSPHPxPG);
+ trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true);
+
+ ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS2, reg,
+ (reg & MTL_HfPWRSTS2_DSPHPxPGS) == MTL_HfPWRSTS2_DSPHPxPGS,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+
+ /* Set ownership to HOST. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST);
+ return ret;
+}
+
+static int avs_ptl_core_power_off(struct avs_dev *adev)
+{
+ u32 reg;
+
+ /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, 0);
+ trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false);
+
+ /* Power down DSP domain. */
+ snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0);
+ trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false);
+
+ return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg,
+ (reg & MTL_HfDSSCS_CPA) == 0,
+ AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
+}
+
+static int avs_ptl_core_power(struct avs_dev *adev, u32 core_mask, bool power)
+{
+ core_mask &= AVS_MAIN_CORE_MASK;
+ if (!core_mask)
+ return 0;
+
+ if (power)
+ return avs_ptl_core_power_on(adev);
+ return avs_ptl_core_power_off(adev);
+}
+
+const struct avs_dsp_ops avs_ptl_dsp_ops = {
+ .power = avs_ptl_core_power,
+ .reset = avs_mtl_core_reset,
+ .stall = avs_lnl_core_stall,
+ .dsp_interrupt = avs_mtl_dsp_interrupt,
+ .int_control = avs_mtl_interrupt_control,
+ .load_basefw = avs_hda_load_basefw,
+ .load_lib = avs_hda_load_library,
+ .transfer_mods = avs_hda_transfer_modules,
+ .log_buffer_offset = avs_icl_log_buffer_offset,
+ .log_buffer_status = avs_apl_log_buffer_status,
+ .coredump = avs_apl_coredump,
+ .d0ix_toggle = avs_icl_d0ix_toggle,
+ .set_d0ix = avs_icl_set_d0ix,
+ AVS_SET_ENABLE_LOGS_OP(icl)
+};
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 2b464e466ed5..97767882ffa1 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021-2022 Intel Corporation
*
* Authors: Cezary Rojewski <cezary.rojewski@intel.com>
* Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -9,6 +9,10 @@
#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
#define AZX_PCIREG_CGCTL 0x48
#define AZX_PGCTL_LSRMD_MASK BIT(4)
@@ -31,6 +35,8 @@
#define AVS_ADSPCS_CSTALL_MASK(cm) ((cm) << 8)
#define AVS_ADSPCS_SPA_MASK(cm) ((cm) << 16)
#define AVS_ADSPCS_CPA_MASK(cm) ((cm) << 24)
+#define AVS_ADSPCS_INTERVAL_US 500
+#define AVS_ADSPCS_TIMEOUT_US 10000
#define AVS_MAIN_CORE_MASK BIT(0)
#define AVS_ADSP_HIPCCTL_BUSY BIT(0)
@@ -48,18 +54,69 @@
#define SKL_ADSP_HIPCIE_DONE BIT(30)
#define SKL_ADSP_HIPCT_BUSY BIT(31)
+/* CNL Intel HD Audio Inter-Processor Communication Registers */
+#define CNL_ADSP_IPC_BASE 0xC0
+#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00)
+#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04)
+#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08)
+#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10)
+#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14)
+#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18)
+#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28)
+
+#define CNL_ADSP_HIPCTDR_BUSY BIT(31)
+#define CNL_ADSP_HIPCTDA_DONE BIT(31)
+#define CNL_ADSP_HIPCIDR_BUSY BIT(31)
+#define CNL_ADSP_HIPCIDA_DONE BIT(31)
+
+/* MTL Intel HOST Inter-Processor Communication Registers */
+#define MTL_HfIPC_BASE 0x73000
+#define MTL_REG_HfIPCxTDR (MTL_HfIPC_BASE + 0x200)
+#define MTL_REG_HfIPCxTDA (MTL_HfIPC_BASE + 0x204)
+#define MTL_REG_HfIPCxIDR (MTL_HfIPC_BASE + 0x210)
+#define MTL_REG_HfIPCxIDA (MTL_HfIPC_BASE + 0x214)
+#define MTL_REG_HfIPCxCTL (MTL_HfIPC_BASE + 0x228)
+#define MTL_REG_HfIPCxTDD (MTL_HfIPC_BASE + 0x300)
+#define MTL_REG_HfIPCxIDD (MTL_HfIPC_BASE + 0x380)
+
+#define MTL_HfIPCxTDR_BUSY BIT(31)
+#define MTL_HfIPCxTDA_BUSY BIT(31)
+#define MTL_HfIPCxIDR_BUSY BIT(31)
+#define MTL_HfIPCxIDA_DONE BIT(31)
+
+#define MTL_HfFLV_BASE 0x162000
+#define MTL_REG_HfFLGP(x, y) (MTL_HfFLV_BASE + 0x1200 + (x) * 0x20 + (y) * 0x08)
+#define LNL_REG_HfDFR(x) (0x160200 + (x) * 0x8)
+
+#define MTL_DWICTL_BASE 0x1800
+#define MTL_DWICTL_REG_INTENL (MTL_DWICTL_BASE + 0x0)
+#define MTL_DWICTL_REG_FINALSTATUSL (MTL_DWICTL_BASE + 0x30)
+
+#define MTL_HfPMCCU_BASE 0x1D00
+#define MTL_REG_HfCLKCTL (MTL_HfPMCCU_BASE + 0x10)
+#define MTL_REG_HfPWRCTL (MTL_HfPMCCU_BASE + 0x18)
+#define MTL_REG_HfPWRSTS (MTL_HfPMCCU_BASE + 0x1C)
+#define MTL_REG_HfPWRCTL2 (MTL_HfPMCCU_BASE + 0x20)
+#define MTL_REG_HfPWRSTS2 (MTL_HfPMCCU_BASE + 0x24)
+#define MTL_HfPWRCTL_WPDSPHPxPG BIT(0)
+#define MTL_HfPWRSTS_DSPHPxPGS BIT(0)
+#define MTL_HfPWRCTL2_WPDSPHPxPG BIT(0)
+#define MTL_HfPWRSTS2_DSPHPxPGS BIT(0)
+
/* Intel HD Audio SRAM windows base addresses */
#define SKL_ADSP_SRAM_BASE_OFFSET 0x8000
#define SKL_ADSP_SRAM_WINDOW_SIZE 0x2000
#define APL_ADSP_SRAM_BASE_OFFSET 0x80000
#define APL_ADSP_SRAM_WINDOW_SIZE 0x20000
+#define MTL_ADSP_SRAM_BASE_OFFSET 0x180000
+#define MTL_ADSP_SRAM_WINDOW_SIZE 0x8000
/* Constants used when accessing SRAM, space shared with firmware */
-#define AVS_FW_REG_BASE(adev) ((adev)->spec->sram_base_offset)
+#define AVS_FW_REG_BASE(adev) ((adev)->spec->hipc->sts_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 PAGE_SIZE
+#define AVS_WINDOW_CHUNK_SIZE SZ_4K
#define AVS_FW_REGS_SIZE AVS_WINDOW_CHUNK_SIZE
#define AVS_FW_REGS_WINDOW 0
/* DSP -> HOST communication window */
@@ -70,8 +127,8 @@
/* registry I/O helpers */
#define avs_sram_offset(adev, window_idx) \
- ((adev)->spec->sram_base_offset + \
- (adev)->spec->sram_window_size * (window_idx))
+ ((adev)->spec->sram->base_offset + \
+ (adev)->spec->sram->window_size * (window_idx))
#define avs_sram_addr(adev, window_idx) \
((adev)->dsp_ba + avs_sram_offset(adev, window_idx))
@@ -81,4 +138,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 6bb8bbc70442..8fb86f364ff3 100644
--- a/sound/soc/intel/avs/skl.c
+++ b/sound/soc/intel/avs/skl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -10,13 +10,76 @@
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
+#include "cldma.h"
+#include "debug.h"
#include "messages.h"
+#include "registers.h"
+
+void avs_skl_ipc_interrupt(struct avs_dev *adev)
+{
+ const struct avs_spec *spec = adev->spec;
+ u32 hipc_ack, hipc_rsp;
+
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
+
+ hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
+ hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
+
+ /* DSP acked host's request. */
+ if (hipc_ack & spec->hipc->ack_done_mask) {
+ complete(&adev->ipc->done_completion);
+
+ /* Tell DSP it has our attention. */
+ snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
+ spec->hipc->ack_done_mask);
+ }
+
+ /* DSP sent new response to process */
+ if (hipc_rsp & spec->hipc->rsp_busy_mask) {
+ union avs_reply_msg msg;
+
+ msg.primary = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
+ msg.ext.val = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
+
+ avs_dsp_process_response(adev, msg.val);
+
+ /* Tell DSP we accepted its message. */
+ snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY,
+ SKL_ADSP_HIPCT_BUSY);
+ }
+
+ snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
+ AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
+}
+
+static irqreturn_t avs_skl_dsp_interrupt(struct avs_dev *adev)
+{
+ u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (adspis == UINT_MAX)
+ return ret;
+
+ if (adspis & AVS_ADSP_ADSPIS_CLDMA) {
+ hda_cldma_interrupt(&code_loader);
+ ret = IRQ_HANDLED;
+ }
+
+ if (adspis & AVS_ADSP_ADSPIS_IPC) {
+ avs_skl_ipc_interrupt(adev);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
static int __maybe_unused
-skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
- u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
+avs_skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+ u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
{
- struct skl_log_state_info *info;
+ struct avs_skl_log_state_info *info;
u32 size, num_cores = adev->hw_cfg.dsp_cores;
int ret, i;
@@ -45,7 +108,7 @@ skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_peri
return 0;
}
-int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
+int avs_skl_log_buffer_offset(struct avs_dev *adev, u32 core)
{
return core * avs_log_buffer_size(adev);
}
@@ -53,8 +116,7 @@ int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
/* fw DbgLogWp registers */
#define FW_REGS_DBG_LOG_WP(core) (0x30 + 0x4 * core)
-static int
-skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
+static int avs_skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
{
void __iomem *buf;
u16 size, write, offset;
@@ -74,7 +136,7 @@ skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
return 0;
}
-static int skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
+static int avs_skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
{
u8 *dump;
@@ -88,33 +150,31 @@ static int skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
return 0;
}
-static bool
-skl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
+static bool avs_skl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
{
/* unsupported on cAVS 1.5 hw */
return false;
}
-static int skl_set_d0ix(struct avs_dev *adev, bool enable)
+static int avs_skl_set_d0ix(struct avs_dev *adev, bool enable)
{
/* unsupported on cAVS 1.5 hw */
return 0;
}
-const struct avs_dsp_ops skl_dsp_ops = {
+const struct avs_dsp_ops avs_skl_dsp_ops = {
.power = avs_dsp_core_power,
.reset = avs_dsp_core_reset,
.stall = avs_dsp_core_stall,
- .irq_handler = avs_dsp_irq_handler,
- .irq_thread = avs_dsp_irq_thread,
+ .dsp_interrupt = avs_skl_dsp_interrupt,
.int_control = avs_dsp_interrupt_control,
.load_basefw = avs_cldma_load_basefw,
.load_lib = avs_cldma_load_library,
.transfer_mods = avs_cldma_transfer_modules,
- .log_buffer_offset = skl_log_buffer_offset,
- .log_buffer_status = skl_log_buffer_status,
- .coredump = skl_coredump,
- .d0ix_toggle = skl_d0ix_toggle,
- .set_d0ix = skl_set_d0ix,
+ .log_buffer_offset = avs_skl_log_buffer_offset,
+ .log_buffer_status = avs_skl_log_buffer_status,
+ .coredump = avs_skl_coredump,
+ .d0ix_toggle = avs_skl_d0ix_toggle,
+ .set_d0ix = avs_skl_set_d0ix,
AVS_SET_ENABLE_LOGS_OP(skl)
};
diff --git a/sound/soc/intel/avs/sysfs.c b/sound/soc/intel/avs/sysfs.c
new file mode 100644
index 000000000000..74b2e6f38d76
--- /dev/null
+++ b/sound/soc/intel/avs/sysfs.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2024 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/sysfs.h>
+#include "avs.h"
+
+static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct avs_dev *adev = to_avs_dev(dev);
+ struct avs_fw_version *fw_version = &adev->fw_cfg.fw_version;
+
+ return sysfs_emit(buf, "%d.%d.%d.%d\n", fw_version->major, fw_version->minor,
+ fw_version->hotfix, fw_version->build);
+}
+static DEVICE_ATTR_RO(fw_version);
+
+static struct attribute *avs_fw_attrs[] = {
+ &dev_attr_fw_version.attr,
+ NULL
+};
+
+static const struct attribute_group avs_attr_group = {
+ .name = "avs",
+ .attrs = avs_fw_attrs,
+};
+
+const struct attribute_group *avs_attr_groups[] = {
+ &avs_attr_group,
+ NULL
+};
diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c
new file mode 100644
index 000000000000..afb066516101
--- /dev/null
+++ b/sound/soc/intel/avs/tgl.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2024 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/pci.h>
+#include "avs.h"
+#include "debug.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)
+{
+ core_mask &= AVS_MAIN_CORE_MASK;
+
+ if (!core_mask)
+ return 0;
+ return avs_dsp_core_power(adev, core_mask, power);
+}
+
+static int avs_tgl_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
+{
+ core_mask &= AVS_MAIN_CORE_MASK;
+
+ if (!core_mask)
+ return 0;
+ return avs_dsp_core_reset(adev, core_mask, reset);
+}
+
+static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
+{
+ core_mask &= AVS_MAIN_CORE_MASK;
+
+ if (!core_mask)
+ return 0;
+ 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/api.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,
+ .stall = avs_tgl_dsp_core_stall,
+ .dsp_interrupt = avs_cnl_dsp_interrupt,
+ .int_control = avs_dsp_interrupt_control,
+ .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,
+ .d0ix_toggle = avs_icl_d0ix_toggle,
+ .set_d0ix = avs_icl_set_d0ix,
+ AVS_SET_ENABLE_LOGS_OP(icl)
+};
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index cdb4ec500261..9033f683393c 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2021 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -15,6 +15,7 @@
#include "avs.h"
#include "control.h"
#include "topology.h"
+#include "utils.h"
/* Get pointer to vendor array at the specified offset. */
#define avs_tplg_vendor_array_at(array, offset) \
@@ -349,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
+AVS_DEFINE_PTR_PARSER(nhlt_config, struct avs_tplg_nhlt_config, nhlt_configs);
static int
parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
@@ -371,23 +373,67 @@ parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *ob
return 0;
}
+static int avs_ssp_sprint(char *buf, size_t size, const char *fmt, int port, int tdm)
+{
+ char *needle = strstr(fmt, "%d");
+ int retsize;
+
+ /*
+ * If there is %d present in fmt string it should be replaced by either
+ * SSP or SSP:TDM, where SSP and TDM are numbers, all other formatting
+ * will be ignored.
+ */
+ if (needle) {
+ retsize = scnprintf(buf, min_t(size_t, size, needle - fmt + 1), "%s", fmt);
+ retsize += scnprintf(buf + retsize, size - retsize, "%d", port);
+ if (tdm)
+ retsize += scnprintf(buf + retsize, size - retsize, ":%d", tdm);
+ retsize += scnprintf(buf + retsize, size - retsize, "%s", needle + 2);
+ return retsize;
+ }
+
+ return snprintf(buf, size, "%s", fmt);
+}
+
static int parse_link_formatted_string(struct snd_soc_component *comp, void *elem,
void *object, u32 offset)
{
struct snd_soc_tplg_vendor_string_elem *tuple = elem;
struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
char *val = (char *)((u8 *)object + offset);
+ int ssp_port, tdm_slot;
/*
* Dynamic naming - string formats, e.g.: ssp%d - supported only for
* topologies describing single device e.g.: an I2S codec on SSP0.
*/
- if (hweight_long(mach->mach_params.i2s_link_mask) != 1)
+ if (!avs_mach_singular_ssp(mach))
+ return avs_parse_string_token(comp, elem, object, offset);
+
+ ssp_port = avs_mach_ssp_port(mach);
+ if (!avs_mach_singular_tdm(mach, ssp_port))
return avs_parse_string_token(comp, elem, object, offset);
- snprintf(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string,
- __ffs(mach->mach_params.i2s_link_mask));
+ tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+ avs_ssp_sprint(val, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, tuple->string, ssp_port, tdm_slot);
+
+ return 0;
+}
+
+static int avs_parse_nhlt_config_size(struct snd_soc_component *comp, void *elem, void *object,
+ u32 offset)
+{
+ struct snd_soc_tplg_vendor_value_elem *tuple = elem;
+ struct acpi_nhlt_config **blob = (struct acpi_nhlt_config **)((u8 *)object + offset);
+ u32 size;
+
+ size = le32_to_cpu(tuple->value);
+ *blob = devm_kzalloc(comp->card->dev, struct_size(*blob, capabilities, size), GFP_KERNEL);
+ if (!*blob)
+ return -ENOMEM;
+
+ (*blob)->capabilities_size = size;
return 0;
}
@@ -786,6 +832,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[] = {
@@ -813,6 +919,7 @@ static void
assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
{
struct snd_soc_acpi_mach *mach;
+ int ssp_port, tdm_slot;
if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
return;
@@ -826,11 +933,22 @@ assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcf
return;
}
+ /* If topology sets value don't overwrite it */
+ if (cfg->copier.vindex.val)
+ return;
+
mach = dev_get_platdata(comp->card->dev);
- /* Automatic assignment only when board describes single SSP. */
- if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance)
- cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask);
+ if (!avs_mach_singular_ssp(mach))
+ return;
+ ssp_port = avs_mach_ssp_port(mach);
+
+ if (!avs_mach_singular_tdm(mach, ssp_port))
+ return;
+ tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+ cfg->copier.vindex.i2s.instance = ssp_port;
+ cfg->copier.vindex.i2s.time_slot = tdm_slot;
}
static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
@@ -1077,6 +1195,27 @@ static const struct avs_tplg_token_parser module_parsers[] = {
.offset = offsetof(struct avs_tplg_module, ctl_id),
.parse = avs_parse_byte_token,
},
+ {
+ .token = AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_module, num_config_ids),
+ .parse = avs_parse_byte_token,
+ },
+ {
+ .token = AVS_TKN_MOD_NHLT_CONFIG_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_module, nhlt_config),
+ .parse = avs_parse_nhlt_config_ptr,
+ },
+};
+
+static const struct avs_tplg_token_parser init_config_parsers[] = {
+ {
+ .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = 0,
+ .parse = avs_parse_word_token,
+ },
};
static struct avs_tplg_module *
@@ -1084,17 +1223,50 @@ avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
{
struct avs_tplg_module *module;
+ u32 esize;
int ret;
+ /* See where config id block starts. */
+ ret = avs_tplg_vendor_entry_size(tuples, block_size,
+ AVS_TKN_MOD_INIT_CONFIG_ID_U32, &esize);
+ if (ret)
+ return ERR_PTR(ret);
+
module = devm_kzalloc(comp->card->dev, sizeof(*module), GFP_KERNEL);
if (!module)
return ERR_PTR(-ENOMEM);
ret = avs_parse_tokens(comp, module, module_parsers,
- ARRAY_SIZE(module_parsers), tuples, block_size);
+ ARRAY_SIZE(module_parsers), tuples, esize);
if (ret < 0)
return ERR_PTR(ret);
+ block_size -= esize;
+ /* Parse trailing config ids if any. */
+ if (block_size) {
+ u32 num_config_ids = module->num_config_ids;
+ u32 *config_ids;
+
+ if (!num_config_ids)
+ return ERR_PTR(-EINVAL);
+
+ config_ids = devm_kcalloc(comp->card->dev, num_config_ids, sizeof(*config_ids),
+ GFP_KERNEL);
+ if (!config_ids)
+ return ERR_PTR(-ENOMEM);
+
+ tuples = avs_tplg_vendor_array_at(tuples, esize);
+ ret = parse_dictionary_entries(comp, tuples, block_size,
+ config_ids, num_config_ids, sizeof(*config_ids),
+ AVS_TKN_MOD_INIT_CONFIG_ID_U32,
+ init_config_parsers,
+ ARRAY_SIZE(init_config_parsers));
+ if (ret)
+ return ERR_PTR(ret);
+
+ module->config_ids = config_ids;
+ }
+
module->owner = owner;
INIT_LIST_HEAD(&module->node);
@@ -1238,6 +1410,27 @@ static const struct avs_tplg_token_parser path_parsers[] = {
},
};
+static const struct avs_tplg_token_parser condpath_parsers[] = {
+ {
+ .token = AVS_TKN_CONDPATH_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_path, id),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_CONDPATH_SOURCE_PATH_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_path, source_path_id),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_CONDPATH_SINK_PATH_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_path, sink_path_id),
+ .parse = avs_parse_word_token,
+ },
+};
+
static struct avs_tplg_path *
avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
@@ -1305,6 +1498,39 @@ static const struct avs_tplg_token_parser path_tmpl_parsers[] = {
},
};
+static const struct avs_tplg_token_parser condpath_tmpl_parsers[] = {
+ {
+ .token = AVS_TKN_CONDPATH_TMPL_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_path_template, id),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_CONDPATH_TMPL_SOURCE_TPLG_NAME_STRING,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
+ .offset = offsetof(struct avs_tplg_path_template, source.tplg_name),
+ .parse = avs_parse_string_token,
+ },
+ {
+ .token = AVS_TKN_CONDPATH_TMPL_SOURCE_PATH_TMPL_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_path_template, source.id),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_CONDPATH_TMPL_SINK_TPLG_NAME_STRING,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
+ .offset = offsetof(struct avs_tplg_path_template, sink.tplg_name),
+ .parse = avs_parse_string_token,
+ },
+ {
+ .token = AVS_TKN_CONDPATH_TMPL_SINK_PATH_TMPL_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_path_template, sink.id),
+ .parse = avs_parse_word_token,
+ },
+};
+
static int parse_path_template(struct snd_soc_component *comp,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size,
struct avs_tplg_path_template *template,
@@ -1375,26 +1601,236 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o
return template;
}
+static int avs_tplg_parse_condpath_templates(struct snd_soc_component *comp,
+ struct snd_soc_tplg_vendor_array *tuples,
+ u32 block_size)
+{
+ struct avs_soc_component *acomp = to_avs_soc_component(comp);
+ struct avs_tplg *tplg = acomp->tplg;
+ int ret, i;
+
+ ret = parse_dictionary_header(comp, tuples, (void **)&tplg->condpath_tmpls,
+ &tplg->num_condpath_tmpls,
+ sizeof(*tplg->condpath_tmpls),
+ AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32);
+ if (ret)
+ return ret;
+
+ block_size -= le32_to_cpu(tuples->size);
+ /* With header parsed, move on to parsing entries. */
+ tuples = avs_tplg_vendor_array_next(tuples);
+
+ for (i = 0; i < tplg->num_condpath_tmpls; i++) {
+ struct avs_tplg_path_template *template;
+ u32 esize;
+
+ template = &tplg->condpath_tmpls[i];
+ template->owner = tplg; /* Used when building sysfs hierarchy. */
+ INIT_LIST_HEAD(&template->path_list);
+ INIT_LIST_HEAD(&template->node);
+
+ ret = avs_tplg_vendor_entry_size(tuples, block_size,
+ AVS_TKN_CONDPATH_TMPL_ID_U32, &esize);
+ if (ret)
+ return ret;
+
+ ret = parse_path_template(comp, tuples, esize, template,
+ condpath_tmpl_parsers,
+ ARRAY_SIZE(condpath_tmpl_parsers),
+ condpath_parsers,
+ ARRAY_SIZE(condpath_parsers));
+ if (ret < 0) {
+ dev_err(comp->dev, "parse condpath_tmpl: %d failed: %d\n", i, ret);
+ return ret;
+ }
+
+ block_size -= esize;
+ tuples = avs_tplg_vendor_array_at(tuples, esize);
+ }
+
+ return 0;
+}
+
+static const struct avs_tplg_token_parser mod_init_config_parsers[] = {
+ {
+ .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,
+ },
+ {
+ .token = AVS_TKN_INIT_CONFIG_PARAM_U8,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
+ .offset = offsetof(struct avs_tplg_init_config, param),
+ .parse = avs_parse_byte_token,
+ },
+ {
+ .token = AVS_TKN_INIT_CONFIG_LENGTH_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_init_config, length),
+ .parse = avs_parse_word_token,
+ },
+};
+
+static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
+ struct snd_soc_tplg_vendor_array *tuples,
+ u32 block_size, u32 *offset)
+{
+ struct avs_soc_component *acomp = to_avs_soc_component(comp);
+ struct avs_tplg *tplg = acomp->tplg;
+ int ret, i;
+
+ *offset = 0;
+
+ /* Parse tuple section telling how many init configs there are. */
+ ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs,
+ &tplg->num_init_configs,
+ sizeof(*tplg->init_configs),
+ AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32);
+ if (ret)
+ return ret;
+
+ block_size -= le32_to_cpu(tuples->size);
+ *offset += le32_to_cpu(tuples->size);
+ /* With header parsed, move on to parsing entries. */
+ tuples = avs_tplg_vendor_array_next(tuples);
+
+ for (i = 0; i < tplg->num_init_configs && block_size > 0; i++) {
+ struct avs_tplg_init_config *config = &tplg->init_configs[i];
+ struct snd_soc_tplg_vendor_array *tmp;
+ void *init_config_data;
+ u32 esize;
+
+ /*
+ * Usually to get section length we search for first token of next group of data,
+ * but in this case we can't as tuples are followed by raw data.
+ */
+ tmp = avs_tplg_vendor_array_next(tuples);
+ esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size);
+ *offset += esize;
+
+ ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config),
+ AVS_TKN_INIT_CONFIG_ID_U32,
+ mod_init_config_parsers,
+ ARRAY_SIZE(mod_init_config_parsers));
+
+ block_size -= esize;
+
+ /* handle raw data section */
+ init_config_data = (void *)tuples + esize;
+ esize = config->length;
+ *offset += esize;
+
+ config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL);
+ if (!config->data)
+ return -ENOMEM;
+
+ tuples = init_config_data + esize;
+ block_size -= esize;
+ }
+
+ return 0;
+}
+
+static const struct avs_tplg_token_parser mod_nhlt_config_parsers[] = {
+ {
+ .token = AVS_TKN_NHLT_CONFIG_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_nhlt_config, id),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_NHLT_CONFIG_SIZE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_nhlt_config, blob),
+ .parse = avs_parse_nhlt_config_size,
+ },
+};
+
+static int avs_tplg_parse_nhlt_configs(struct snd_soc_component *comp,
+ struct snd_soc_tplg_vendor_array *tuples,
+ u32 block_size)
+{
+ struct avs_soc_component *acomp = to_avs_soc_component(comp);
+ struct avs_tplg *tplg = acomp->tplg;
+ int ret, i;
+
+ /* Parse the header section to know how many entries there are. */
+ ret = parse_dictionary_header(comp, tuples, (void **)&tplg->nhlt_configs,
+ &tplg->num_nhlt_configs,
+ sizeof(*tplg->nhlt_configs),
+ AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32);
+ if (ret)
+ return ret;
+
+ block_size -= le32_to_cpu(tuples->size);
+ /* With the header parsed, move on to parsing entries. */
+ tuples = avs_tplg_vendor_array_next(tuples);
+
+ for (i = 0; i < tplg->num_nhlt_configs && block_size > 0; i++) {
+ struct avs_tplg_nhlt_config *config;
+ u32 esize;
+
+ config = &tplg->nhlt_configs[i];
+ esize = le32_to_cpu(tuples->size);
+
+ ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config),
+ AVS_TKN_NHLT_CONFIG_ID_U32,
+ mod_nhlt_config_parsers,
+ ARRAY_SIZE(mod_nhlt_config_parsers));
+ if (ret)
+ return ret;
+ /* With tuples parsed, the blob shall be allocated. */
+ if (!config->blob)
+ return -EINVAL;
+
+ /* Consume the raw data and move to the next entry. */
+ memcpy(config->blob->capabilities, (u8 *)tuples + esize,
+ config->blob->capabilities_size);
+ esize += config->blob->capabilities_size;
+
+ block_size -= esize;
+ tuples = avs_tplg_vendor_array_at(tuples, esize);
+ }
+
+ return 0;
+}
+
static int avs_route_load(struct snd_soc_component *comp, int index,
struct snd_soc_dapm_route *route)
{
struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
- char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
- u32 port;
+ int ssp_port, tdm_slot;
+ char *buf;
/* See parse_link_formatted_string() for dynamic naming when(s). */
- if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
- port = __ffs(mach->mach_params.i2s_link_mask);
-
- snprintf(buf, len, route->source, port);
- strncpy((char *)route->source, buf, len);
- snprintf(buf, len, route->sink, port);
- strncpy((char *)route->sink, buf, len);
- if (route->control) {
- snprintf(buf, len, route->control, port);
- strncpy((char *)route->control, buf, len);
- }
+ if (!avs_mach_singular_ssp(mach))
+ return 0;
+ ssp_port = avs_mach_ssp_port(mach);
+
+ if (!avs_mach_singular_tdm(mach, ssp_port))
+ return 0;
+ tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+ buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot);
+ route->source = buf;
+
+ buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ avs_ssp_sprint(buf, len, route->sink, ssp_port, tdm_slot);
+ route->sink = buf;
+
+ if (route->control) {
+ buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ avs_ssp_sprint(buf, len, route->control, ssp_port, tdm_slot);
+ route->control = buf;
}
return 0;
@@ -1408,10 +1844,13 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
struct avs_tplg_path_template *template;
struct avs_soc_component *acomp = to_avs_soc_component(comp);
struct avs_tplg *tplg;
+ int ssp_port, tdm_slot;
if (!le32_to_cpu(dw->priv.size))
return 0;
+ w->no_wname_in_kcontrol_name = true;
+
if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
w->ignore_suspend = false;
@@ -1419,16 +1858,28 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
tplg = acomp->tplg;
mach = dev_get_platdata(comp->card->dev);
+ if (!avs_mach_singular_ssp(mach))
+ goto static_name;
+ ssp_port = avs_mach_ssp_port(mach);
/* See parse_link_formatted_string() for dynamic naming when(s). */
- if (hweight_long(mach->mach_params.i2s_link_mask) == 1) {
+ if (avs_mach_singular_tdm(mach, ssp_port)) {
+ /* size is based on possible %d -> SSP:TDM, where SSP and TDM < 16 + '\0' */
+ size_t size = strlen(dw->name) + 3;
+ char *buf;
+
+ tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ avs_ssp_sprint(buf, size, dw->name, ssp_port, tdm_slot);
kfree(w->name);
/* w->name is freed later by soc_tplg_dapm_widget_create() */
- w->name = kasprintf(GFP_KERNEL, dw->name, __ffs(mach->mach_params.i2s_link_mask));
- if (!w->name)
- return -ENOMEM;
+ w->name = buf;
}
+static_name:
template = avs_tplg_path_template_create(comp, tplg, dw->priv.array,
le32_to_cpu(dw->priv.size));
if (IS_ERR(template)) {
@@ -1456,8 +1907,16 @@ static int avs_dai_load(struct snd_soc_component *comp, int index,
struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm,
struct snd_soc_dai *dai)
{
- if (pcm)
+ u32 fe_subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX;
+
+ if (pcm) {
dai_drv->ops = &avs_dai_fe_ops;
+ dai_drv->capture.subformats = fe_subformats;
+ dai_drv->playback.subformats = fe_subformats;
+ }
+
return 0;
}
@@ -1476,6 +1935,9 @@ static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_s
/* Open LINK (BE) pipes last and close them first to prevent xruns. */
link->trigger[0] = SND_SOC_DPCM_TRIGGER_PRE;
link->trigger[1] = SND_SOC_DPCM_TRIGGER_PRE;
+ } else {
+ /* Do not ignore codec capabilities. */
+ link->dpcm_merged_format = 1;
}
return 0;
@@ -1502,6 +1964,7 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array;
struct avs_soc_component *acomp = to_avs_soc_component(comp);
size_t remaining = le32_to_cpu(manifest->priv.size);
+ bool has_init_config = true;
u32 offset;
int ret;
@@ -1599,17 +2062,83 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
remaining -= offset;
tuples = avs_tplg_vendor_array_at(tuples, offset);
+ ret = avs_tplg_vendor_array_lookup(tuples, remaining,
+ AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32, &offset);
+ if (ret) {
+ dev_err(comp->dev, "condpath lookup failed: %d\n", ret);
+ return ret;
+ }
+
/* Bindings dictionary. */
- return avs_tplg_parse_bindings(comp, tuples, remaining);
+ ret = avs_tplg_parse_bindings(comp, tuples, offset);
+ if (ret < 0)
+ return ret;
+
+ remaining -= offset;
+ tuples = avs_tplg_vendor_array_at(tuples, offset);
+
+ ret = avs_tplg_vendor_array_lookup(tuples, remaining,
+ AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32, &offset);
+ if (ret == -ENOENT) {
+ dev_dbg(comp->dev, "init config lookup failed: %d\n", ret);
+ has_init_config = false;
+ } else if (ret) {
+ dev_err(comp->dev, "init config lookup failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Condpaths dictionary. */
+ ret = avs_tplg_parse_condpath_templates(comp, tuples,
+ has_init_config ? offset : remaining);
+ if (ret < 0)
+ return ret;
+
+ if (!has_init_config)
+ return 0;
+
+ remaining -= offset;
+ tuples = avs_tplg_vendor_array_at(tuples, offset);
+
+ /* Initial configs dictionary. */
+ ret = avs_tplg_parse_initial_configs(comp, tuples, remaining, &offset);
+ if (ret < 0)
+ return ret;
+
+ remaining -= offset;
+ tuples = avs_tplg_vendor_array_at(tuples, offset);
+
+ ret = avs_tplg_vendor_array_lookup(tuples, remaining,
+ AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32, &offset);
+ if (ret == -ENOENT)
+ return 0;
+ if (ret) {
+ dev_err(comp->dev, "NHLT config lookup failed: %d\n", ret);
+ return ret;
+ }
+
+ tuples = avs_tplg_vendor_array_at(tuples, offset);
+
+ /* NHLT configs dictionary. */
+ return avs_tplg_parse_nhlt_configs(comp, tuples, remaining);
}
-#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,
},
};
@@ -1631,18 +2160,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;
@@ -1653,12 +2184,17 @@ 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;
}
-static struct snd_soc_tplg_ops avs_tplg_ops = {
+static const struct snd_soc_tplg_ops avs_tplg_ops = {
.io_ops = avs_control_ops,
.io_ops_count = ARRAY_SIZE(avs_control_ops),
.control_load = avs_control_load,
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 6e1c8e9b2496..1cf7455b6c01 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021 Intel Corporation
*
* Authors: Cezary Rojewski <cezary.rojewski@intel.com>
* Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -33,6 +33,12 @@ struct avs_tplg {
u32 num_pplcfgs;
struct avs_tplg_binding *bindings;
u32 num_bindings;
+ struct avs_tplg_path_template *condpath_tmpls;
+ u32 num_condpath_tmpls;
+ struct avs_tplg_init_config *init_configs;
+ u32 num_init_configs;
+ struct avs_tplg_nhlt_config *nhlt_configs;
+ u32 num_nhlt_configs;
struct list_head path_tmpl_list;
};
@@ -71,13 +77,20 @@ 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];
+ s32 coefficients[AVS_COEFF_CHANNELS_MAX];
u32 channel_map;
} updown_mix;
struct {
@@ -103,6 +116,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;
};
};
@@ -140,6 +158,10 @@ struct avs_tplg_path_template {
struct snd_soc_dapm_widget *w;
+ /* Conditional path. */
+ struct avs_tplg_path_template_id source;
+ struct avs_tplg_path_template_id sink;
+
struct list_head path_list;
struct avs_tplg *owner;
@@ -147,12 +169,28 @@ struct avs_tplg_path_template {
struct list_head node;
};
+struct avs_tplg_init_config {
+ u32 id;
+
+ u8 param;
+ size_t length;
+ void *data;
+};
+
+struct avs_tplg_nhlt_config {
+ u32 id;
+ struct acpi_nhlt_config *blob;
+};
+
struct avs_tplg_path {
u32 id;
/* Path format requirements. */
struct avs_audio_format *fe_fmt;
struct avs_audio_format *be_fmt;
+ /* Condpath path-variant requirements. */
+ u32 source_path_id;
+ u32 sink_path_id;
struct list_head ppl_list;
@@ -183,6 +221,9 @@ struct avs_tplg_module {
u8 domain;
struct avs_tplg_modcfg_ext *cfg_ext;
u32 ctl_id;
+ u32 num_config_ids;
+ u32 *config_ids;
+ struct avs_tplg_nhlt_config *nhlt_config;
struct avs_tplg_pipeline *owner;
/* Pipeline modules management. */
diff --git a/sound/soc/intel/avs/trace.c b/sound/soc/intel/avs/trace.c
index c63eea909b5e..a98da521db0f 100644
--- a/sound/soc/intel/avs/trace.c
+++ b/sound/soc/intel/avs/trace.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
diff --git a/sound/soc/intel/avs/trace.h b/sound/soc/intel/avs/trace.h
index 855b06bb14b0..f4288d0ad5ef 100644
--- a/sound/soc/intel/avs/trace.h
+++ b/sound/soc/intel/avs/trace.h
@@ -24,7 +24,7 @@ TRACE_EVENT(avs_dsp_core_op,
TP_fast_assign(
__entry->reg = reg;
__entry->mask = mask;
- __assign_str(op, op);
+ __assign_str(op);
__entry->flag = flag;
),
@@ -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,
@@ -135,7 +137,7 @@ TRACE_EVENT(avs_d0ix,
),
TP_fast_assign(
- __assign_str(op, op);
+ __assign_str(op);
__entry->proceed = proceed;
__entry->header = header;
),
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index 82416b86662d..81f9b67d8e29 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2021-2022 Intel Corporation
//
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
@@ -250,7 +250,7 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con
if (!entry)
return -ENOMEM;
- entry->name = kstrdup(name, GFP_KERNEL);
+ entry->name = kstrdup_const(name, GFP_KERNEL);
if (!entry->name) {
kfree(entry);
return -ENOMEM;
@@ -258,7 +258,7 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con
ret = request_firmware(&entry->fw, name, adev->dev);
if (ret < 0) {
- kfree(entry->name);
+ kfree_const(entry->name);
kfree(entry);
return ret;
}
@@ -282,7 +282,7 @@ void avs_release_last_firmware(struct avs_dev *adev)
list_del(&entry->node);
release_firmware(entry->fw);
- kfree(entry->name);
+ kfree_const(entry->name);
kfree(entry);
}
@@ -296,7 +296,7 @@ void avs_release_firmwares(struct avs_dev *adev)
list_for_each_entry_safe(entry, tmp, &adev->fw_list, node) {
list_del(&entry->node);
release_firmware(entry->fw);
- kfree(entry->name);
+ kfree_const(entry->name);
kfree(entry);
}
}
diff --git a/sound/soc/intel/avs/utils.h b/sound/soc/intel/avs/utils.h
new file mode 100644
index 000000000000..955a40d2c30c
--- /dev/null
+++ b/sound/soc/intel/avs/utils.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2023 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_UTILS_H
+#define __SOUND_SOC_INTEL_AVS_UTILS_H
+
+#include <sound/soc-acpi.h>
+
+extern bool obsolete_card_names;
+
+struct avs_mach_pdata {
+ struct hda_codec *codec;
+ unsigned long *tdms;
+ char *codec_name; /* DMIC only */
+
+ bool obsolete_card_names;
+};
+
+static inline bool avs_mach_singular_ssp(struct snd_soc_acpi_mach *mach)
+{
+ return hweight_long(mach->mach_params.i2s_link_mask) == 1;
+}
+
+static inline u32 avs_mach_ssp_port(struct snd_soc_acpi_mach *mach)
+{
+ return __ffs(mach->mach_params.i2s_link_mask);
+}
+
+static inline bool avs_mach_singular_tdm(struct snd_soc_acpi_mach *mach, u32 port)
+{
+ struct avs_mach_pdata *pdata = mach->pdata;
+ unsigned long *tdms = pdata->tdms;
+
+ return !tdms || (hweight_long(tdms[port]) == 1);
+}
+
+static inline u32 avs_mach_ssp_tdm(struct snd_soc_acpi_mach *mach, u32 port)
+{
+ struct avs_mach_pdata *pdata = mach->pdata;
+ unsigned long *tdms = pdata->tdms;
+
+ return tdms ? __ffs(tdms[port]) : 0;
+}
+
+static inline int avs_mach_get_ssp_tdm(struct device *dev, struct snd_soc_acpi_mach *mach,
+ int *ssp_port, int *tdm_slot)
+{
+ int port;
+
+ if (!avs_mach_singular_ssp(mach)) {
+ dev_err(dev, "Invalid SSP configuration\n");
+ return -EINVAL;
+ }
+ port = avs_mach_ssp_port(mach);
+
+ if (!avs_mach_singular_tdm(mach, port)) {
+ dev_err(dev, "Invalid TDM configuration\n");
+ return -EINVAL;
+ }
+ *ssp_port = port;
+ *tdm_slot = avs_mach_ssp_tdm(mach, *ssp_port);
+
+ return 0;
+}
+
+/*
+ * Macro to easily generate format strings
+ */
+#define AVS_STRING_FMT(prefix, suffix, ssp, tdm) \
+ (tdm) ? prefix "%d:%d" suffix : prefix "%d" suffix, (ssp), (tdm)
+
+#endif
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index f472f603ab75..c23fdb6aad4c 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -11,7 +11,7 @@ menuconfig SND_SOC_INTEL_MACH
kernel: saying N will just cause the configurator to skip all
the questions about Intel ASoC machine drivers.
-if SND_SOC_INTEL_MACH
+if SND_SOC_INTEL_MACH && (SND_SOC_SOF_INTEL_COMMON || !SND_SOC_SOF_INTEL_COMMON)
config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES
bool "Use more user friendly long card names"
@@ -38,6 +38,13 @@ config SND_SOC_INTEL_SOF_REALTEK_COMMON
config SND_SOC_INTEL_SOF_CIRRUS_COMMON
tristate
+config SND_SOC_INTEL_SOF_NUVOTON_COMMON
+ tristate
+
+config SND_SOC_INTEL_SOF_BOARD_HELPERS
+ select SND_SOC_ACPI_INTEL_MATCH
+ tristate
+
if SND_SOC_INTEL_CATPT
config SND_SOC_INTEL_HASWELL_MACH
@@ -220,6 +227,7 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
depends on GPIOLIB || COMPILE_TEST
select SND_SOC_ACPI
select SND_SOC_ES8316
+ select SND_SOC_ES83XX_DSM_COMMON
help
This adds support for ASoC machine driver for Intel(R) Baytrail &
Cherrytrail platforms with ES8316 audio codec.
@@ -245,94 +253,6 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
endif ## SND_SST_ATOM_HIFI2_PLATFORM
-if SND_SOC_INTEL_SKL
-
-config SND_SOC_INTEL_SKL_RT286_MACH
- tristate "SKL with RT286 I2S mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_RT286
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC machine driver for Skylake platforms
- with RT286 I2S audio codec.
- Say Y or m if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
- tristate "SKL with NAU88L25 and SSM4567 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_NAU8825
- select SND_SOC_SSM4567
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for NAU88L25 + SSM4567.
- Say Y or m if you have such a device. This is a recommended option.
- If unsure select "N".
-
-config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
- tristate "SKL with NAU88L25 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_NAU8825
- select SND_SOC_MAX98357A
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for NAU88L25 + MAX98357A.
- Say Y or m if you have such a device. This is a recommended option.
- If unsure select "N".
-
-endif ## SND_SOC_INTEL_SKL
-
-config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
- tristate
- select SND_SOC_DA7219
- select SND_SOC_MAX98357A
- select SND_SOC_MAX98390
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_SOC_INTEL_HDA_DSP_COMMON
-
-config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
- tristate
- select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
-
-if SND_SOC_INTEL_APL
-
-config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
- tristate "Broxton with DA7219 and MAX98357A/MAX98390 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- depends on SND_HDA_CODEC_HDMI
- select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
- help
- This adds support for ASoC machine driver for Broxton-P platforms
- with DA7219 + MAX98357A/MAX98390 I2S audio codec.
- Say Y or m if you have such a device. This is a recommended option.
- If unsure select "N".
-
-config SND_SOC_INTEL_BXT_RT298_MACH
- tristate "Broxton with RT298 I2S mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_RT298
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_SOC_INTEL_HDA_DSP_COMMON
- help
- This adds support for ASoC machine driver for Broxton platforms
- with RT286 I2S audio codec.
- Say Y or m if you have such a device. This is a recommended option.
- If unsure select "N".
-
-endif ## SND_SOC_INTEL_APL
-
if SND_SOC_SOF_APOLLOLAKE
config SND_SOC_INTEL_SOF_WM8804_MACH
@@ -349,119 +269,37 @@ config SND_SOC_INTEL_SOF_WM8804_MACH
endif ## SND_SOC_SOF_APOLLOLAKE
-if SND_SOC_INTEL_KBL
-
-config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
- tristate "KBL with RT5663 and MAX98927 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_RT5663
- select SND_SOC_MAX98927
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_SOC_INTEL_SKYLAKE_SSP_CLK
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for RT5663 + MAX98927.
- Say Y or m if you have such a device. This is a recommended option.
- If unsure select "N".
-
-config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
- tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- depends on SPI
- select SND_SOC_RT5663
- select SND_SOC_RT5514
- select SND_SOC_RT5514_SPI
- select SND_SOC_MAX98927
- select SND_SOC_HDAC_HDMI
- select SND_SOC_INTEL_SKYLAKE_SSP_CLK
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for RT5663 + RT5514 + MAX98927.
- Say Y or m if you have such a device. This is a recommended option.
- If unsure select "N".
-
-config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
- tristate "KBL with DA7219 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for DA7219 + MAX98357A I2S audio codec.
- Say Y if you have such a device.
-
-config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
- tristate "KBL with DA7219 and MAX98927 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_DA7219
- select SND_SOC_MAX98927
- select SND_SOC_MAX98373_I2C
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for DA7219 + MAX98927 I2S audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_KBL_RT5660_MACH
- tristate "KBL with RT5660 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- depends on GPIOLIB || COMPILE_TEST
- select SND_SOC_RT5660
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for RT5660 I2S audio codec.
- Say Y if you have such a device.
-
-endif ## SND_SOC_INTEL_KBL
-
if SND_SOC_SOF_GEMINILAKE
config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH
tristate "GLK with DA7219 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
- select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
+ imply SND_SOC_INTEL_SOF_DA7219_MACH
help
This adds support for ASoC machine driver for Geminilake platforms
- with DA7219 + MAX98357A I2S audio codec.
+ with DA7219 + MAX98357A I2S audio codec. This option is deprecated
+ and please use SND_SOC_INTEL_SOF_DA7219_MACH instead.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
tristate "GLK with RT5682 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
- select SND_SOC_RT5682_I2C
- select SND_SOC_RT5682S
- select SND_SOC_MAX98357A
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_SOC_INTEL_HDA_DSP_COMMON
+ imply SND_SOC_INTEL_SOF_RT5682_MACH
help
This adds support for ASoC machine driver for Geminilake platforms
- with RT5682 + MAX98357A I2S audio codec.
+ with RT5682 + MAX98357A I2S audio codec. This option is deprecated
+ and please use SND_SOC_INTEL_SOF_RT5682_MACH instead.
Say Y if you have such a device.
If unsure select "N".
endif ## SND_SOC_SOF_GEMINILAKE
-if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
+if SND_SOC_SOF_HDA_AUDIO_CODEC
config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
tristate "Skylake+ with HDA Codecs"
depends on SND_HDA_CODEC_HDMI
- select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_HDA_DSP_COMMON
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_DMIC
# SND_SOC_HDAC_HDA is already selected
help
@@ -471,30 +309,33 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
-endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
+endif ## SND_SOC_SOF_HDA_AUDIO_CODEC
if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL
config SND_SOC_INTEL_SOF_RT5682_MACH
- tristate "SOF with rt5682 codec in I2S Mode"
+ tristate "SOF with rt5650/rt5682 codec in I2S Mode"
depends on I2C && ACPI
depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\
(MFD_INTEL_LPSS || COMPILE_TEST)) ||\
(SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST))
+ select SND_SOC_MAX98357A
select SND_SOC_MAX98373_I2C
select SND_SOC_MAX98390
select SND_SOC_RT1011
select SND_SOC_RT1015
select SND_SOC_RT1015P
+ select SND_SOC_RT5645
select SND_SOC_RT5682_I2C
select SND_SOC_RT5682S
select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_HDA_DSP_COMMON
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_MAXIM_COMMON
select SND_SOC_INTEL_SOF_REALTEK_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
- with rt5682 codec.
+ with rt5650 or rt5682 codec.
Say Y if you have such a device.
If unsure select "N".
@@ -506,9 +347,10 @@ config SND_SOC_INTEL_SOF_CS42L42_MACH
select SND_SOC_CS42L42
select SND_SOC_MAX98357A
select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_HDA_DSP_COMMON
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_MAXIM_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with cs42l42 codec.
@@ -556,10 +398,12 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH
select SND_SOC_MAX98357A
select SND_SOC_NAU8315
select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_HDA_DSP_COMMON
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_MAXIM_COMMON
+ select SND_SOC_INTEL_SOF_NUVOTON_COMMON
select SND_SOC_INTEL_SOF_REALTEK_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with nau8825 codec.
@@ -572,52 +416,46 @@ if (SND_SOC_SOF_COMETLAKE && SND_SOC_SOF_HDA_LINK)
config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH
tristate "CML_LP with DA7219 and MAX98357A in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON
+ imply SND_SOC_INTEL_SOF_DA7219_MACH
help
This adds support for ASoC machine driver for Cometlake platforms
- with DA7219 + MAX98357A I2S audio codec.
+ with DA7219 + MAX98357A I2S audio codec. This option is deprecated
+ and please use SND_SOC_INTEL_SOF_DA7219_MACH instead.
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH
tristate "CML with RT1011 and RT5682 in I2S Mode"
- depends on I2C && ACPI
- depends on MFD_INTEL_LPSS || COMPILE_TEST
- depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
- select SND_SOC_RT1011
- select SND_SOC_RT5682_I2C
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_SOC_INTEL_HDA_DSP_COMMON
+ imply SND_SOC_INTEL_SOF_RT5682_MACH
help
This adds support for ASoC machine driver for SOF platform with
- RT1011 + RT5682 I2S codec.
+ RT1011 + RT5682 I2S codec. This option is deprecated and please used
+ SND_SOC_INTEL_SOF_RT5682_MACH instead.
Say Y if you have such a device.
If unsure select "N".
endif ## SND_SOC_SOF_COMETLAKE && SND_SOC_SOF_HDA_LINK
-if SND_SOC_SOF_JASPERLAKE
-
-config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH
- tristate "SOF with DA7219 and MAX98373/MAX98360A in I2S Mode"
+config SND_SOC_INTEL_SOF_DA7219_MACH
+ tristate "SOF with DA7219 codec in I2S Mode"
depends on I2C && ACPI
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_INTEL_HDA_DSP_COMMON
select SND_SOC_DA7219
+ select SND_SOC_MAX98357A
select SND_SOC_MAX98373_I2C
+ select SND_SOC_MAX98390
select SND_SOC_DMIC
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
+ select SND_SOC_INTEL_SOF_MAXIM_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
- with DA7219 + MAX98373/MAX98360A I2S audio codec.
+ with Dialog DA7219 I2S audio codec.
Say Y if you have such a device.
If unsure select "N".
-endif ## SND_SOC_SOF_JASPERLAKE
-
if SND_SOC_SOF_HDA_LINK
config SND_SOC_INTEL_SOF_SSP_AMP_MACH
@@ -627,10 +465,11 @@ config SND_SOC_INTEL_SOF_SSP_AMP_MACH
select SND_SOC_RT1308
select SND_SOC_CS35L41_I2C
select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_HDA_DSP_COMMON
+ select SND_SOC_INTEL_SOF_BOARD_HELPERS
select SND_SOC_INTEL_SOF_REALTEK_COMMON
select SND_SOC_INTEL_SOF_CIRRUS_COMMON
+ select SND_SOC_ACPI_INTEL_MATCH
help
This adds support for ASoC machine driver for SOF platforms
with RT1308/CS35L41 I2S audio codec.
@@ -658,10 +497,11 @@ if SND_SOC_SOF_INTEL_SOUNDWIRE
config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
tristate "SoundWire generic machine driver"
- depends on I2C && ACPI
+ depends on I2C && SPI_MASTER && ACPI
depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
depends on SOUNDWIRE
+ select SND_SOC_SDW_UTILS
select SND_SOC_MAX98363
select SND_SOC_MAX98373_I2C
select SND_SOC_MAX98373_SDW
@@ -670,17 +510,27 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_RT711_SDCA_SDW
select SND_SOC_RT712_SDCA_SDW
select SND_SOC_RT712_SDCA_DMIC_SDW
+ select SND_SOC_RT715_SDW
+ select SND_SOC_RT715_SDCA_SDW
+ select SND_SOC_RT721_SDCA_SDW
+ select SND_SOC_RT722_SDCA_SDW
select SND_SOC_RT1308_SDW
select SND_SOC_RT1308
select SND_SOC_RT1316_SDW
select SND_SOC_RT1318_SDW
- select SND_SOC_RT715_SDW
- select SND_SOC_RT715_SDCA_SDW
+ select SND_SOC_RT1320_SDW
select SND_SOC_RT5682_SDW
select SND_SOC_CS42L42_SDW
+ select SND_SOC_CS42L43
+ select SND_SOC_CS42L43_SDW
+ select MFD_CS42L43
+ select MFD_CS42L43_SDW
+ select PINCTRL_CS42L43
+ select SPI_CS42L43
+ select SND_SOC_CS35L56_SPI
+ select SND_SOC_CS35L56_SDW
select SND_SOC_DMIC
select SND_SOC_INTEL_HDA_DSP_COMMON
- select SND_SOC_INTEL_SOF_MAXIM_COMMON
imply SND_SOC_SDW_MOCKUP
help
Add support for Intel SoundWire-based platforms connected to
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 931415d9cf6f..fcd517d6c279 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -1,59 +1,39 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-hsw-rt5640-objs := hsw_rt5640.o
-snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o
-snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
-snd-soc-bdw-rt286-objs := bdw_rt286.o
-snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
-snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
-snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o
-snd-soc-sst-sof-wm8804-objs := sof_wm8804.o
-snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o
-snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
-snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
-snd-soc-sst-bytcr-wm5102-objs := bytcr_wm5102.o
-snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
-snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
-snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
-snd-soc-sst-cht-bsw-nau8824-objs := cht_bsw_nau8824.o
-snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o
-snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
-snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
-snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
-snd-soc-sof_rt5682-objs := sof_rt5682.o
-snd-soc-sof_cs42l42-objs := sof_cs42l42.o
-snd-soc-sof_es8336-objs := sof_es8336.o
-snd-soc-sof_nau8825-objs := sof_nau8825.o
-snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o
-snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
-snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
-snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
-snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
-snd-soc-kbl_rt5660-objs := kbl_rt5660.o
-snd-soc-skl_rt286-objs := skl_rt286.o
-snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
-snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
-snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
-snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
-snd-soc-ehl-rt5660-objs := ehl_rt5660.o
-snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
-snd-soc-sof-sdw-objs += sof_sdw.o \
- sof_sdw_maxim.o sof_sdw_rt_amp.o \
- sof_sdw_rt5682.o sof_sdw_rt700.o \
- sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \
- sof_sdw_rt712_sdca.o sof_sdw_rt715.o \
- sof_sdw_rt715_sdca.o sof_sdw_dmic.o \
- sof_sdw_cs42l42.o \
+snd-soc-hsw-rt5640-y := hsw_rt5640.o
+snd-soc-sst-bdw-rt5650-mach-y := bdw-rt5650.o
+snd-soc-sst-bdw-rt5677-mach-y := bdw-rt5677.o
+snd-soc-bdw-rt286-y := bdw_rt286.o
+snd-soc-sst-sof-pcm512x-y := sof_pcm512x.o
+snd-soc-sst-sof-wm8804-y := sof_wm8804.o
+snd-soc-sst-bytcr-rt5640-y := bytcr_rt5640.o
+snd-soc-sst-bytcr-rt5651-y := bytcr_rt5651.o
+snd-soc-sst-bytcr-wm5102-y := bytcr_wm5102.o
+snd-soc-sst-cht-bsw-rt5672-y := cht_bsw_rt5672.o
+snd-soc-sst-cht-bsw-rt5645-y := cht_bsw_rt5645.o
+snd-soc-sst-cht-bsw-max98090_ti-y := cht_bsw_max98090_ti.o
+snd-soc-sst-cht-bsw-nau8824-y := cht_bsw_nau8824.o
+snd-soc-sst-byt-cht-cx2072x-y := bytcht_cx2072x.o
+snd-soc-sst-byt-cht-da7213-y := bytcht_da7213.o
+snd-soc-sst-byt-cht-es8316-y := bytcht_es8316.o
+snd-soc-sst-byt-cht-nocodec-y := bytcht_nocodec.o
+snd-soc-sof_rt5682-y := sof_rt5682.o
+snd-soc-sof_cs42l42-y := sof_cs42l42.o
+snd-soc-sof_es8336-y := sof_es8336.o
+snd-soc-sof_nau8825-y := sof_nau8825.o
+snd-soc-sof_da7219-y := sof_da7219.o
+snd-soc-skl_hda_dsp-y := skl_hda_dsp_generic.o
+snd-soc-ehl-rt5660-y := ehl_rt5660.o
+snd-soc-sof-ssp-amp-y := sof_ssp_amp.o
+snd-soc-sof-sdw-y += sof_sdw.o \
sof_sdw_hdmi.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_ES8336_MACH) += snd-soc-sof_es8336.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_NAU8825_MACH) += snd-soc-sof_nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MACH) += snd-soc-sof_da7219.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-hsw-rt5640.o
-obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o
-obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH) += snd-soc-sst-sof-wm8804.o
-obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-bdw-rt286.o
obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
@@ -68,30 +48,26 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x.
obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o
-obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += snd-soc-cml_rt1011_rt5682.o
-obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o
-obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o
-obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
-obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
-obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o
-obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
-obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
-obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o
-obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o
obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o
obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_AMP_MACH) += snd-soc-sof-ssp-amp.o
# common modules
-snd-soc-intel-hda-dsp-common-objs := hda_dsp_common.o
+snd-soc-intel-hda-dsp-common-y := hda_dsp_common.o
obj-$(CONFIG_SND_SOC_INTEL_HDA_DSP_COMMON) += snd-soc-intel-hda-dsp-common.o
-snd-soc-intel-sof-maxim-common-objs += sof_maxim_common.o
+snd-soc-intel-sof-maxim-common-y += sof_maxim_common.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_MAXIM_COMMON) += snd-soc-intel-sof-maxim-common.o
-snd-soc-intel-sof-realtek-common-objs += sof_realtek_common.o
+snd-soc-intel-sof-realtek-common-y += sof_realtek_common.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_REALTEK_COMMON) += snd-soc-intel-sof-realtek-common.o
-snd-soc-intel-sof-cirrus-common-objs += sof_cirrus_common.o
+snd-soc-intel-sof-cirrus-common-y += sof_cirrus_common.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_CIRRUS_COMMON) += snd-soc-intel-sof-cirrus-common.o
+
+snd-soc-intel-sof-nuvoton-common-y += sof_nuvoton_common.o
+obj-$(CONFIG_SND_SOC_INTEL_SOF_NUVOTON_COMMON) += snd-soc-intel-sof-nuvoton-common.o
+
+snd-soc-intel-sof-board-helpers-y += sof_board_helpers.o
+obj-$(CONFIG_SND_SOC_INTEL_SOF_BOARD_HELPERS) += snd-soc-intel-sof-board-helpers.o
diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index d0682bc543c9..d25a7188f603 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -103,8 +103,8 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
/* Workaround: set codec PLL to 19.2MHz that PLL source is
@@ -131,7 +131,7 @@ static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_ops bdw_rt5650_ops = {
+static const struct snd_soc_ops bdw_rt5650_ops = {
.hw_params = bdw_rt5650_hw_params,
};
@@ -167,7 +167,7 @@ static int bdw_rt5650_init(struct snd_soc_pcm_runtime *rtd)
{
struct bdw_rt5650_priv *bdw_rt5650 =
snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
int ret;
@@ -239,8 +239,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST
},
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(fe, dummy, platform),
},
@@ -256,8 +254,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
.ignore_pmdown_time = 1,
.be_hw_params_fixup = broadwell_ssp0_fixup,
.ops = &bdw_rt5650_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.init = bdw_rt5650_init,
SND_SOC_DAILINK_REG(ssp0_port, be, platform),
},
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index f3e08d258ac1..408d20ed8cee 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -27,8 +27,7 @@ struct bdw_rt5677_priv {
static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card);
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -153,8 +152,8 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000,
@@ -170,8 +169,8 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream,
static int bdw_rt5677_dsp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_PLL1, 24576000,
@@ -227,8 +226,8 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
{
struct bdw_rt5677_priv *bdw_rt5677 =
snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
ret = devm_acpi_dev_add_driver_gpios(component->dev, bdw_rt5677_gpios);
@@ -329,8 +328,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST
},
- .dpcm_capture = 1,
- .dpcm_playback = 1,
.ops = &bdw_rt5677_fe_ops,
SND_SOC_DAILINK_REG(fe, dummy, platform),
},
@@ -356,8 +353,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
.ignore_pmdown_time = 1,
.be_hw_params_fixup = broadwell_ssp0_fixup,
.ops = &bdw_rt5677_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.init = bdw_rt5677_init,
.exit = bdw_rt5677_exit,
SND_SOC_DAILINK_REG(ssp0_port, be, platform),
@@ -370,7 +365,7 @@ static int bdw_rt5677_suspend_pre(struct snd_soc_card *card)
struct snd_soc_dapm_context *dapm;
if (bdw_rt5677->component) {
- dapm = snd_soc_component_get_dapm(bdw_rt5677->component);
+ dapm = snd_soc_component_to_dapm(bdw_rt5677->component);
snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
}
return 0;
@@ -382,7 +377,7 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card)
struct snd_soc_dapm_context *dapm;
if (bdw_rt5677->component) {
- dapm = snd_soc_component_get_dapm(bdw_rt5677->component);
+ dapm = snd_soc_component_to_dapm(bdw_rt5677->component);
snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
}
return 0;
diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c
index b7687a93a923..523ade9f31ab 100644
--- a/sound/soc/intel/boards/bdw_rt286.c
+++ b/sound/soc/intel/boards/bdw_rt286.c
@@ -2,7 +2,7 @@
/*
* Sound card driver for Intel Broadwell Wildcat Point with Realtek 286
*
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ * Copyright (C) 2013, Intel Corporation
*/
#include <linux/module.h>
@@ -61,7 +61,7 @@ static const struct snd_soc_dapm_route card_routes[] = {
static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
@@ -75,7 +75,7 @@ static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
static void codec_link_exit(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(codec, NULL, NULL);
}
@@ -98,8 +98,8 @@ static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int codec_link_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
@@ -133,8 +133,6 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(system, dummy, platform),
},
{
@@ -143,7 +141,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(offload0, dummy, platform),
},
{
@@ -152,7 +150,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(offload1, dummy, platform),
},
{
@@ -161,7 +159,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(loopback, dummy, platform),
},
/* Back End DAI links */
@@ -177,8 +175,6 @@ static struct snd_soc_dai_link card_dai_links[] = {
.ignore_pmdown_time = 1,
.be_hw_params_fixup = codec_link_hw_params_fixup,
.ops = &codec_link_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
},
};
@@ -187,6 +183,9 @@ static int card_suspend_pre(struct snd_soc_card *card)
{
struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
+ if (!codec_dai)
+ return 0;
+
return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
@@ -194,6 +193,9 @@ static int card_resume_post(struct snd_soc_card *card)
{
struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
+ if (!codec_dai)
+ return 0;
+
return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
}
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
deleted file mode 100644
index c593995facaa..000000000000
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ /dev/null
@@ -1,881 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Broxton-P I2S Machine Driver
- *
- * Copyright (C) 2016, Intel Corporation. All rights reserved.
- *
- * Modified from:
- * Intel Skylake I2S Machine driver
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/da7219.h"
-#include "../common/soc-intel-quirks.h"
-#include "hda_dsp_common.h"
-
-#define BXT_DIALOG_CODEC_DAI "da7219-hifi"
-#define BXT_MAXIM_CODEC_DAI "HiFi"
-#define MAX98390_DEV0_NAME "i2c-MX98390:00"
-#define MAX98390_DEV1_NAME "i2c-MX98390:01"
-#define DUAL_CHANNEL 2
-#define QUAD_CHANNEL 4
-
-#define SPKAMP_MAX98357A 1
-#define SPKAMP_MAX98390 2
-
-static struct snd_soc_jack broxton_headset;
-static struct snd_soc_jack broxton_hdmi[3];
-
-struct bxt_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct bxt_card_private {
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
- int spkamp;
-};
-
-enum {
- BXT_DPCM_AUDIO_PB = 0,
- BXT_DPCM_AUDIO_CP,
- BXT_DPCM_AUDIO_HS_PB,
- BXT_DPCM_AUDIO_REF_CP,
- BXT_DPCM_AUDIO_DMIC_CP,
- BXT_DPCM_AUDIO_HDMI1_PB,
- BXT_DPCM_AUDIO_HDMI2_PB,
- BXT_DPCM_AUDIO_HDMI3_PB,
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- int ret = 0;
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct snd_soc_dai *codec_dai;
-
- codec_dai = snd_soc_card_get_codec_dai(card, BXT_DIALOG_CODEC_DAI);
- if (!codec_dai) {
- dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
- return -EIO;
- }
-
- if (SND_SOC_DAPM_EVENT_OFF(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- DA7219_SYSCLK_MCLK, 0, 0);
- if (ret)
- dev_err(card->dev, "failed to stop PLL: %d\n", ret);
- } else if(SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304);
- if (ret)
- dev_err(card->dev, "failed to start PLL: %d\n", ret);
- }
-
- return ret;
-}
-
-static const struct snd_kcontrol_new broxton_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
-};
-
-static const struct snd_kcontrol_new max98357a_controls[] = {
- SOC_DAPM_PIN_SWITCH("Spk"),
-};
-
-static const struct snd_kcontrol_new max98390_controls[] = {
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_soc_dapm_widget broxton_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU),
-};
-
-static const struct snd_soc_dapm_widget max98357a_widgets[] = {
- SND_SOC_DAPM_SPK("Spk", NULL),
-};
-
-static const struct snd_soc_dapm_widget max98390_widgets[] = {
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* HP jack connectors - unknown if we have jack detection */
- {"Headphone Jack", NULL, "HPL"},
- {"Headphone Jack", NULL, "HPR"},
-
- /* other jacks */
- {"MIC", NULL, "Headset Mic"},
-
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-
- /* CODEC BE connections */
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI2", NULL, "hif7-0 Output"},
-
- {"hifi3", NULL, "iDisp3 Tx"},
- {"iDisp3 Tx", NULL, "iDisp3_out"},
- {"hifi2", NULL, "iDisp2 Tx"},
- {"iDisp2 Tx", NULL, "iDisp2_out"},
- {"hifi1", NULL, "iDisp1 Tx"},
- {"iDisp1 Tx", NULL, "iDisp1_out"},
-
- /* DMIC */
- {"dmic01_hifi", NULL, "DMIC01 Rx"},
- {"DMIC01 Rx", NULL, "DMIC AIF"},
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-};
-
-static const struct snd_soc_dapm_route max98357a_routes[] = {
- /* speaker */
- {"Spk", NULL, "Speaker"},
-};
-
-static const struct snd_soc_dapm_route max98390_routes[] = {
- /* Speaker */
- {"Left Spk", NULL, "Left BE_OUT"},
- {"Right Spk", NULL, "Right BE_OUT"},
-};
-
-static const struct snd_soc_dapm_route broxton_map[] = {
- {"HiFi Playback", NULL, "ssp5 Tx"},
- {"ssp5 Tx", NULL, "codec0_out"},
-
- {"Playback", NULL, "ssp1 Tx"},
- {"ssp1 Tx", NULL, "codec1_out"},
-
- {"codec0_in", NULL, "ssp1 Rx"},
- {"ssp1 Rx", NULL, "Capture"},
-};
-
-static const struct snd_soc_dapm_route gemini_map[] = {
- {"HiFi Playback", NULL, "ssp1 Tx"},
- {"ssp1 Tx", NULL, "codec0_out"},
-
- {"Playback", NULL, "ssp2 Tx"},
- {"ssp2 Tx", NULL, "codec1_out"},
-
- {"codec0_in", NULL, "ssp2 Rx"},
- {"ssp2 Rx", NULL, "Capture"},
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = DUAL_CHANNEL;
-
- /* set SSP to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
-
- return 0;
-}
-
-static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- int clk_freq;
-
- /* Configure sysclk for codec */
- if (soc_intel_is_cml())
- clk_freq = 24000000;
- else
- clk_freq = 19200000;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq,
- SND_SOC_CLOCK_IN);
-
- if (ret) {
- dev_err(rtd->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- 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 | SND_JACK_LINEOUT,
- &broxton_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
- snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
- snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3,
- KEY_VOICECOMMAND);
-
- snd_soc_component_set_jack(component, &broxton_headset, NULL);
-
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
-
- return ret;
-}
-
-static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct bxt_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- DUAL_CHANNEL,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static const unsigned int channels_quad[] = {
- QUAD_CHANNEL,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels_quad = {
- .count = ARRAY_SIZE(channels_quad),
- .list = channels_quad,
- .mask = 0,
-};
-
-static int bxt_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = DUAL_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops broxton_da7219_fe_ops = {
- .startup = bxt_fe_startup,
-};
-
-static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- if (params_channels(params) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static int broxton_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels_quad);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static const struct snd_soc_ops broxton_dmic_ops = {
- .startup = broxton_dmic_startup,
-};
-
-static const unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_refcap = {
- .count = ARRAY_SIZE(ch_mono),
- .list = ch_mono,
-};
-
-static int broxton_refcap_startup(struct snd_pcm_substream *substream)
-{
- substream->runtime->hw.channels_max = 1;
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_refcap);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-};
-
-static const struct snd_soc_ops broxton_refcap_ops = {
- .startup = broxton_refcap_startup,
-};
-
-/* broxton digital audio interface glue - connects codec <--> CPU */
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(system2,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin2")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
- /* Back End DAI */
-SND_SOC_DAILINK_DEF(ssp5_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin")));
-SND_SOC_DAILINK_DEF(ssp5_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00",
- BXT_MAXIM_CODEC_DAI)));
-SND_SOC_DAILINK_DEF(max98390_codec,
- DAILINK_COMP_ARRAY(
- /* Left */ COMP_CODEC(MAX98390_DEV0_NAME, "max98390-aif1"),
- /* Right */ COMP_CODEC(MAX98390_DEV1_NAME, "max98390-aif1")));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00",
- BXT_DIALOG_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-
-SND_SOC_DAILINK_DEF(dmic16k_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
-
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2",
- "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2",
- "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0")));
-
-static struct snd_soc_dai_link broxton_dais[] = {
- /* Front End DAI links */
- [BXT_DPCM_AUDIO_PB] =
- {
- .name = "Bxt Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = broxton_da7219_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &broxton_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [BXT_DPCM_AUDIO_CP] =
- {
- .name = "Bxt Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &broxton_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HS_PB] = {
- .name = "Bxt Audio Headset Playback",
- .stream_name = "Headset Playback",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &broxton_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system2, dummy, platform),
- },
- [BXT_DPCM_AUDIO_REF_CP] =
- {
- .name = "Bxt Audio Reference cap",
- .stream_name = "Refcap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &broxton_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [BXT_DPCM_AUDIO_DMIC_CP] =
- {
- .name = "Bxt Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &broxton_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HDMI1_PB] =
- {
- .name = "Bxt HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HDMI2_PB] =
- {
- .name = "Bxt HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HDMI3_PB] =
- {
- .name = "Bxt HDMI Port3",
- .stream_name = "Hdmi3",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
- /* Back End DAI links */
- {
- /* SSP5 - Codec */
- .name = "SSP5-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = broxton_ssp_fixup,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform),
- },
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = broxton_da7219_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = broxton_ssp_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .ignore_suspend = 1,
- .be_hw_params_fixup = broxton_dmic_fixup,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = broxton_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = broxton_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = broxton_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
- {
- .name = "dmic16k",
- .id = 6,
- .be_hw_params_fixup = broxton_dmic_fixup,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
- },
-};
-
-static struct snd_soc_codec_conf max98390_codec_confs[] = {
- {
- .dlc = COMP_CODEC_CONF(MAX98390_DEV0_NAME),
- .name_prefix = "Left",
- },
- {
- .dlc = COMP_CODEC_CONF(MAX98390_DEV1_NAME),
- .name_prefix = "Right",
- },
-};
-
-#define NAME_SIZE 32
-static int bxt_card_late_probe(struct snd_soc_card *card)
-{
- struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card);
- struct bxt_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- const struct snd_kcontrol_new *controls;
- const struct snd_soc_dapm_widget *widgets;
- const struct snd_soc_dapm_route *routes;
- int num_controls, num_widgets, num_routes, err, i = 0;
- char jack_name[NAME_SIZE];
-
- switch (ctx->spkamp) {
- case SPKAMP_MAX98357A:
- controls = max98357a_controls;
- num_controls = ARRAY_SIZE(max98357a_controls);
- widgets = max98357a_widgets;
- num_widgets = ARRAY_SIZE(max98357a_widgets);
- routes = max98357a_routes;
- num_routes = ARRAY_SIZE(max98357a_routes);
- break;
- case SPKAMP_MAX98390:
- controls = max98390_controls;
- num_controls = ARRAY_SIZE(max98390_controls);
- widgets = max98390_widgets;
- num_widgets = ARRAY_SIZE(max98390_widgets);
- routes = max98390_routes;
- num_routes = ARRAY_SIZE(max98390_routes);
- break;
- default:
- dev_err(card->dev, "Invalid speaker amplifier %d\n", ctx->spkamp);
- return -EINVAL;
- }
-
- err = snd_soc_dapm_new_controls(&card->dapm, widgets, num_widgets);
- if (err) {
- dev_err(card->dev, "Fail to new widgets\n");
- return err;
- }
-
- err = snd_soc_add_card_controls(card, controls, num_controls);
- if (err) {
- dev_err(card->dev, "Fail to add controls\n");
- return err;
- }
-
- err = snd_soc_dapm_add_routes(&card->dapm, routes, num_routes);
- if (err) {
- dev_err(card->dev, "Fail to add routes\n");
- return err;
- }
-
- if (soc_intel_is_glk())
- snd_soc_dapm_add_routes(&card->dapm, gemini_map,
- ARRAY_SIZE(gemini_map));
- else
- snd_soc_dapm_add_routes(&card->dapm, broxton_map,
- ARRAY_SIZE(broxton_map));
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &broxton_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &broxton_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* broxton audio machine driver for SPT + da7219 */
-static struct snd_soc_card broxton_audio_card = {
- .name = "bxtda7219max",
- .owner = THIS_MODULE,
- .dai_link = broxton_dais,
- .num_links = ARRAY_SIZE(broxton_dais),
- .controls = broxton_controls,
- .num_controls = ARRAY_SIZE(broxton_controls),
- .dapm_widgets = broxton_widgets,
- .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
- .fully_routed = true,
- .late_probe = bxt_card_late_probe,
-};
-
-static int broxton_audio_probe(struct platform_device *pdev)
-{
- struct bxt_card_private *ctx;
- struct snd_soc_acpi_mach *mach;
- const char *platform_name;
- int ret;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- if (acpi_dev_present("MX98390", NULL, -1))
- ctx->spkamp = SPKAMP_MAX98390;
- else
- ctx->spkamp = SPKAMP_MAX98357A;
-
- broxton_audio_card.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&broxton_audio_card, ctx);
- if (soc_intel_is_glk()) {
- unsigned int i;
-
- broxton_audio_card.name = "glkda7219max";
- /* Fixup the SSP entries for geminilake */
- for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) {
- /* MAXIM_CODEC is connected to SSP1. */
- if (!strcmp(broxton_dais[i].codecs->dai_name,
- BXT_MAXIM_CODEC_DAI)) {
- broxton_dais[i].name = "SSP1-Codec";
- broxton_dais[i].cpus->dai_name = "SSP1 Pin";
- }
- /* DIALOG_CODE is connected to SSP2 */
- else if (!strcmp(broxton_dais[i].codecs->dai_name,
- BXT_DIALOG_CODEC_DAI)) {
- broxton_dais[i].name = "SSP2-Codec";
- broxton_dais[i].cpus->dai_name = "SSP2 Pin";
- }
- }
- } else if (soc_intel_is_cml()) {
- unsigned int i;
-
- if (ctx->spkamp == SPKAMP_MAX98390) {
- broxton_audio_card.name = "cml_max98390_da7219";
-
- broxton_audio_card.codec_conf = max98390_codec_confs;
- broxton_audio_card.num_configs = ARRAY_SIZE(max98390_codec_confs);
- } else
- broxton_audio_card.name = "cmlda7219max";
-
- for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) {
- /* MAXIM_CODEC is connected to SSP1. */
- if (!strcmp(broxton_dais[i].codecs->dai_name,
- BXT_MAXIM_CODEC_DAI)) {
- broxton_dais[i].name = "SSP1-Codec";
- broxton_dais[i].cpus->dai_name = "SSP1 Pin";
-
- if (ctx->spkamp == SPKAMP_MAX98390) {
- broxton_dais[i].codecs = max98390_codec;
- broxton_dais[i].num_codecs = ARRAY_SIZE(max98390_codec);
- broxton_dais[i].dpcm_capture = 1;
- }
- }
- /* DIALOG_CODEC is connected to SSP0 */
- else if (!strcmp(broxton_dais[i].codecs->dai_name,
- BXT_DIALOG_CODEC_DAI)) {
- broxton_dais[i].name = "SSP0-Codec";
- broxton_dais[i].cpus->dai_name = "SSP0 Pin";
- }
- }
- }
-
- /* override platform name, if required */
- mach = pdev->dev.platform_data;
- platform_name = mach->mach_params.platform;
-
- ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card,
- platform_name);
- if (ret)
- return ret;
-
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
- return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
-}
-
-static const struct platform_device_id bxt_board_ids[] = {
- { .name = "bxt_da7219_mx98357a" },
- { .name = "glk_da7219_mx98357a" },
- { .name = "cml_da7219_mx98357a" },
- { }
-};
-MODULE_DEVICE_TABLE(platform, bxt_board_ids);
-
-static struct platform_driver broxton_audio = {
- .probe = broxton_audio_probe,
- .driver = {
- .name = "bxt_da7219_max98357a",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = bxt_board_ids,
-};
-module_platform_driver(broxton_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode");
-MODULE_AUTHOR("Sathyanarayana Nujella <sathyanarayana.nujella@intel.com>");
-MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>");
-MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
-MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
-MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
-MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
-MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
deleted file mode 100644
index bf89fe80423d..000000000000
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ /dev/null
@@ -1,668 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Broxton-P I2S Machine Driver
- *
- * Copyright (C) 2014-2016, Intel Corporation. All rights reserved.
- *
- * Modified from:
- * Intel Skylake I2S Machine driver
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/rt298.h"
-#include "hda_dsp_common.h"
-
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack broxton_headset;
-static struct snd_soc_jack broxton_hdmi[3];
-
-struct bxt_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct bxt_rt286_private {
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
-};
-
-enum {
- BXT_DPCM_AUDIO_PB = 0,
- BXT_DPCM_AUDIO_CP,
- BXT_DPCM_AUDIO_REF_CP,
- BXT_DPCM_AUDIO_DMIC_CP,
- BXT_DPCM_AUDIO_HDMI1_PB,
- BXT_DPCM_AUDIO_HDMI2_PB,
- BXT_DPCM_AUDIO_HDMI3_PB,
-};
-
-static struct snd_soc_jack_pin broxton_headset_pins[] = {
- {
- .pin = "Mic Jack",
- .mask = SND_JACK_MICROPHONE,
- },
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
-};
-
-static const struct snd_kcontrol_new broxton_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Mic Jack"),
-};
-
-static const struct snd_soc_dapm_widget broxton_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_SPK("Speaker", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
- SND_SOC_DAPM_MIC("DMIC2", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
-};
-
-static const struct snd_soc_dapm_route broxton_rt298_map[] = {
- /* speaker */
- {"Speaker", NULL, "SPOR"},
- {"Speaker", NULL, "SPOL"},
-
- /* HP jack connectors - unknown if we have jack detect */
- {"Headphone Jack", NULL, "HPO Pin"},
-
- /* other jacks */
- {"MIC1", NULL, "Mic Jack"},
-
- /* digital mics */
- {"DMIC1 Pin", NULL, "DMIC2"},
- {"DMic", NULL, "SoC DMIC"},
-
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI2", NULL, "hif7-0 Output"},
-
- /* CODEC BE connections */
- { "AIF1 Playback", NULL, "ssp5 Tx"},
- { "ssp5 Tx", NULL, "codec0_out"},
- { "ssp5 Tx", NULL, "codec1_out"},
-
- { "codec0_in", NULL, "ssp5 Rx" },
- { "ssp5 Rx", NULL, "AIF1 Capture" },
-
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "Capture" },
-
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-};
-
-static const struct snd_soc_dapm_route geminilake_rt298_map[] = {
- /* speaker */
- {"Speaker", NULL, "SPOR"},
- {"Speaker", NULL, "SPOL"},
-
- /* HP jack connectors - unknown if we have jack detect */
- {"Headphone Jack", NULL, "HPO Pin"},
-
- /* other jacks */
- {"MIC1", NULL, "Mic Jack"},
-
- /* digital mics */
- {"DMIC1 Pin", NULL, "DMIC2"},
- {"DMic", NULL, "SoC DMIC"},
-
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI2", NULL, "hif7-0 Output"},
-
- /* CODEC BE connections */
- { "AIF1 Playback", NULL, "ssp2 Tx"},
- { "ssp2 Tx", NULL, "codec0_out"},
- { "ssp2 Tx", NULL, "codec1_out"},
-
- { "codec0_in", NULL, "ssp2 Rx" },
- { "ssp2 Rx", NULL, "AIF1 Capture" },
-
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "Capture" },
-
- { "dmic_voice", NULL, "DMIC16k Rx" },
- { "DMIC16k Rx", NULL, "Capture" },
-
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-};
-
-static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- int ret = 0;
-
- ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
- SND_JACK_HEADSET | SND_JACK_BTN_0,
- &broxton_headset,
- broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins));
-
- if (ret)
- return ret;
-
- snd_soc_component_set_jack(component, &broxton_headset, NULL);
-
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
-
- return 0;
-}
-
-static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct bxt_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
-
- /* set SSP5 to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
-
- return 0;
-}
-
-static int broxton_rt298_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL,
- 19200000, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(rtd->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- return ret;
-}
-
-static const struct snd_soc_ops broxton_rt298_ops = {
- .hw_params = broxton_rt298_hw_params,
-};
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static const unsigned int channels_dmic[] = {
- 1, 2, 3, 4,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
- .count = ARRAY_SIZE(channels_dmic),
- .list = channels_dmic,
- .mask = 0,
-};
-
-static int broxton_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_max = 4;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_dmic_channels);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static const struct snd_soc_ops broxton_dmic_ops = {
- .startup = broxton_dmic_startup,
-};
-
-static const unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int bxt_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * on this platform for PCM device we support:
- * 48Khz
- * stereo
- * 16-bit audio
- */
-
- runtime->hw.channels_max = 2;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops broxton_rt286_fe_ops = {
- .startup = bxt_fe_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp5_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin")));
-SND_SOC_DAILINK_DEF(ssp5_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00",
- "rt298-aif1")));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec",
- "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(dmic16k,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2",
- "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2",
- "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2",
- "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0")));
-
-/* broxton digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link broxton_rt298_dais[] = {
- /* Front End DAI links */
- [BXT_DPCM_AUDIO_PB] =
- {
- .name = "Bxt Audio Port",
- .stream_name = "Audio",
- .nonatomic = 1,
- .dynamic = 1,
- .init = broxton_rt298_fe_init,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &broxton_rt286_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [BXT_DPCM_AUDIO_CP] =
- {
- .name = "Bxt Audio Capture Port",
- .stream_name = "Audio Record",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &broxton_rt286_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [BXT_DPCM_AUDIO_REF_CP] =
- {
- .name = "Bxt Audio Reference cap",
- .stream_name = "refcap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [BXT_DPCM_AUDIO_DMIC_CP] =
- {
- .name = "Bxt Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &broxton_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HDMI1_PB] =
- {
- .name = "Bxt HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HDMI2_PB] =
- {
- .name = "Bxt HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [BXT_DPCM_AUDIO_HDMI3_PB] =
- {
- .name = "Bxt HDMI Port3",
- .stream_name = "Hdmi3",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
- /* Back End DAI links */
- {
- /* SSP5 - Codec */
- .name = "SSP5-Codec",
- .id = 0,
- .no_pcm = 1,
- .init = broxton_rt298_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = broxton_ssp5_fixup,
- .ops = &broxton_rt298_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 1,
- .be_hw_params_fixup = broxton_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "dmic16k",
- .id = 2,
- .be_hw_params_fixup = broxton_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = broxton_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = broxton_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = broxton_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-#define NAME_SIZE 32
-static int bxt_card_late_probe(struct snd_soc_card *card)
-{
- struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card);
- struct bxt_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &broxton_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &broxton_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-
-/* broxton audio machine driver for SPT + RT298S */
-static struct snd_soc_card broxton_rt298 = {
- .name = "broxton-rt298",
- .owner = THIS_MODULE,
- .dai_link = broxton_rt298_dais,
- .num_links = ARRAY_SIZE(broxton_rt298_dais),
- .controls = broxton_controls,
- .num_controls = ARRAY_SIZE(broxton_controls),
- .dapm_widgets = broxton_widgets,
- .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
- .dapm_routes = broxton_rt298_map,
- .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
- .fully_routed = true,
- .late_probe = bxt_card_late_probe,
-
-};
-
-static struct snd_soc_card geminilake_rt298 = {
- .name = "geminilake-rt298",
- .owner = THIS_MODULE,
- .dai_link = broxton_rt298_dais,
- .num_links = ARRAY_SIZE(broxton_rt298_dais),
- .controls = broxton_controls,
- .num_controls = ARRAY_SIZE(broxton_controls),
- .dapm_widgets = broxton_widgets,
- .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
- .dapm_routes = geminilake_rt298_map,
- .num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map),
- .fully_routed = true,
- .late_probe = bxt_card_late_probe,
-};
-
-static int broxton_audio_probe(struct platform_device *pdev)
-{
- struct bxt_rt286_private *ctx;
- struct snd_soc_card *card =
- (struct snd_soc_card *)pdev->id_entry->driver_data;
- struct snd_soc_acpi_mach *mach;
- const char *platform_name;
- int ret;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) {
- if (!strncmp(card->dai_link[i].codecs->name, "i2c-INT343A:00",
- I2C_NAME_SIZE)) {
- if (!strncmp(card->name, "broxton-rt298",
- PLATFORM_NAME_SIZE)) {
- card->dai_link[i].name = "SSP5-Codec";
- card->dai_link[i].cpus->dai_name = "SSP5 Pin";
- } else if (!strncmp(card->name, "geminilake-rt298",
- PLATFORM_NAME_SIZE)) {
- card->dai_link[i].name = "SSP2-Codec";
- card->dai_link[i].cpus->dai_name = "SSP2 Pin";
- }
- }
- }
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(card, ctx);
-
- /* override platform name, if required */
- mach = pdev->dev.platform_data;
- platform_name = mach->mach_params.platform;
-
- ret = snd_soc_fixup_dai_links_platform_name(card,
- platform_name);
- if (ret)
- return ret;
-
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
- return devm_snd_soc_register_card(&pdev->dev, card);
-}
-
-static const struct platform_device_id bxt_board_ids[] = {
- { .name = "bxt_alc298s_i2s", .driver_data =
- (unsigned long)&broxton_rt298 },
- { .name = "glk_alc298s_i2s", .driver_data =
- (unsigned long)&geminilake_rt298 },
- {}
-};
-MODULE_DEVICE_TABLE(platform, bxt_board_ids);
-
-static struct platform_driver broxton_audio = {
- .probe = broxton_audio_probe,
- .driver = {
- .name = "bxt_alc298s_i2s",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = bxt_board_ids,
-};
-module_platform_driver(broxton_audio)
-
-/* Module information */
-MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>");
-MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
-MODULE_DESCRIPTION("Intel SST Audio for Broxton");
-MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
index 9942a2de6f7a..0a7e6d2e37cb 100644
--- a/sound/soc/intel/boards/bytcht_cx2072x.c
+++ b/sound/soc/intel/boards/bytcht_cx2072x.c
@@ -70,17 +70,18 @@ static const struct acpi_gpio_mapping byt_cht_cx2072x_acpi_gpios[] = {
static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
- struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
if (devm_acpi_dev_add_driver_gpios(codec->dev,
byt_cht_cx2072x_acpi_gpios))
dev_warn(rtd->dev, "Unable to add GPIO mapping table\n");
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
/* set the default PLL rate, the clock is handled by the codec driver */
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL,
19200000, SND_SOC_CLOCK_IN);
if (ret) {
dev_err(rtd->dev, "Could not set sysclk\n");
@@ -97,7 +98,7 @@ static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_component_set_jack(codec, &byt_cht_cx2072x_headset, NULL);
- snd_soc_dai_set_bclk_ratio(asoc_rtd_to_codec(rtd, 0), 50);
+ snd_soc_dai_set_bclk_ratio(snd_soc_rtd_to_codec(rtd, 0), 50);
return 0;
}
@@ -123,7 +124,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch 24-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP);
@@ -132,7 +133,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -175,8 +176,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &byt_cht_cx2072x_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -185,7 +184,7 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &byt_cht_cx2072x_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -198,8 +197,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = {
| SND_SOC_DAIFMT_CBC_CFC,
.init = byt_cht_cx2072x_init,
.be_hw_params_fixup = byt_cht_cx2072x_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp2, cx2072x, platform),
},
};
@@ -241,7 +238,8 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) {
- if (!strcmp(byt_cht_cx2072x_dais[i].codecs->name,
+ if (byt_cht_cx2072x_dais[i].num_codecs &&
+ !strcmp(byt_cht_cx2072x_dais[i].codecs->name,
"i2c-14F10720:00")) {
dai_index = i;
break;
@@ -254,7 +252,11 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
snprintf(codec_name, sizeof(codec_name), "i2c-%s",
acpi_dev_name(adev));
byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name;
+ } else {
+ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
+ return -ENOENT;
}
+
acpi_dev_put(adev);
/* override platform name, if required */
diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
index a3b0cfab17b0..31141d4b6b25 100644
--- a/sound/soc/intel/boards/bytcht_da7213.c
+++ b/sound/soc/intel/boards/bytcht_da7213.c
@@ -78,7 +78,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch 24-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP);
@@ -87,7 +87,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -105,8 +105,8 @@ static int aif1_startup(struct snd_pcm_substream *substream)
static int aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK,
@@ -126,8 +126,8 @@ static int aif1_hw_params(struct snd_pcm_substream *substream,
static int aif1_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_pll(codec_dai, 0,
@@ -174,8 +174,6 @@ static struct snd_soc_dai_link dailink[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -184,7 +182,7 @@ static struct snd_soc_dai_link dailink[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -197,8 +195,6 @@ static struct snd_soc_dai_link dailink[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
.be_hw_params_fixup = codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &ssp2_ops,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
},
@@ -245,7 +241,8 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(dailink); i++) {
- if (!strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {
+ if (dailink[i].num_codecs &&
+ !strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) {
dai_index = i;
break;
}
@@ -257,7 +254,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
snprintf(codec_name, sizeof(codec_name),
"i2c-%s", acpi_dev_name(adev));
dailink[dai_index].codecs->name = codec_name;
+ } else {
+ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
+ return -ENOENT;
}
+
acpi_dev_put(adev);
/* override platform name, if required */
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 7a30d2d36f19..192e2a394ff3 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -27,6 +27,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
+#include "../../codecs/es83xx-dsm-common.h"
#include "../atom/sst-atom-controls.h"
#include "../common/soc-intel-quirks.h"
@@ -46,7 +47,8 @@ enum {
BYT_CHT_ES8316_INTMIC_IN2_MAP,
};
-#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0))
+#define BYT_CHT_ES8316_MAP_MASK GENMASK(3, 0)
+#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & BYT_CHT_ES8316_MAP_MASK)
#define BYT_CHT_ES8316_SSP0 BIT(16)
#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17)
#define BYT_CHT_ES8316_JD_INVERTED BIT(18)
@@ -59,10 +61,23 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");
static void log_quirks(struct device *dev)
{
- if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP)
+ int map;
+
+ map = BYT_CHT_ES8316_MAP(quirk);
+ switch (map) {
+ case BYT_CHT_ES8316_INTMIC_IN1_MAP:
dev_info(dev, "quirk IN1_MAP enabled");
- if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP)
+ break;
+ case BYT_CHT_ES8316_INTMIC_IN2_MAP:
dev_info(dev, "quirk IN2_MAP enabled");
+ break;
+ default:
+ dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to INTMIC_IN1_MAP\n", map);
+ quirk &= ~BYT_CHT_ES8316_MAP_MASK;
+ quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP;
+ break;
+ }
+
if (quirk & BYT_CHT_ES8316_SSP0)
dev_info(dev, "quirk SSP0 enabled");
if (quirk & BYT_CHT_ES8316_MONO_SPEAKER)
@@ -74,7 +89,7 @@ static void log_quirks(struct device *dev)
static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -157,14 +172,15 @@ static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = {
static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component;
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
const struct snd_soc_dapm_route *custom_map;
int num_routes;
int ret;
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
switch (BYT_CHT_ES8316_MAP(quirk)) {
case BYT_CHT_ES8316_INTMIC_IN1_MAP:
@@ -177,7 +193,7 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map);
break;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
if (ret)
return ret;
@@ -188,7 +204,7 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
custom_map = byt_cht_es8316_ssp2_map;
num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map);
}
- ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
if (ret)
return ret;
@@ -212,7 +228,7 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
dev_err(card->dev, "unable to enable MCLK\n");
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(runtime, 0), 0, 19200000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(card->dev, "can't set codec clock %d\n", ret);
@@ -262,7 +278,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch 24-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP
@@ -272,7 +288,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -314,8 +330,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &byt_cht_es8316_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -325,7 +339,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &byt_cht_es8316_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -338,8 +352,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
.be_hw_params_fixup = byt_cht_es8316_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.init = byt_cht_es8316_init,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
},
@@ -461,6 +473,66 @@ static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
{}
};
+static int byt_cht_es8316_get_quirks_from_dsm(struct byt_cht_es8316_private *priv,
+ bool is_bytcr)
+{
+ int ret, val1, val2, dsm_quirk = 0;
+
+ if (is_bytcr)
+ dsm_quirk |= BYT_CHT_ES8316_SSP0;
+
+ ret = es83xx_dsm(priv->codec_dev, PLATFORM_MAINMIC_TYPE_ARG, &val1);
+ if (ret < 0)
+ return ret;
+
+ ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPMIC_TYPE_ARG, &val2);
+ if (ret < 0)
+ return ret;
+
+ if (val1 == PLATFORM_MIC_AMIC_LIN1RIN1 && val2 == PLATFORM_MIC_AMIC_LIN2RIN2) {
+ dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP;
+ } else if (val1 == PLATFORM_MIC_AMIC_LIN2RIN2 && val2 == PLATFORM_MIC_AMIC_LIN1RIN1) {
+ dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN2_MAP;
+ } else {
+ dev_warn(priv->codec_dev, "Unknown mic settings mainmic 0x%02x hpmic 0x%02x\n",
+ val1, val2);
+ return -EINVAL;
+ }
+
+ ret = es83xx_dsm(priv->codec_dev, PLATFORM_SPK_TYPE_ARG, &val1);
+ if (ret < 0)
+ return ret;
+
+ switch (val1) {
+ case PLATFORM_SPK_MONO:
+ dsm_quirk |= BYT_CHT_ES8316_MONO_SPEAKER;
+ break;
+ case PLATFORM_SPK_STEREO:
+ break;
+ default:
+ dev_warn(priv->codec_dev, "Unknown speaker setting 0x%02x\n", val1);
+ return -EINVAL;
+ }
+
+ ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPDET_INV_ARG, &val1);
+ if (ret < 0)
+ return ret;
+
+ switch (val1) {
+ case PLATFORM_HPDET_NORMAL:
+ break;
+ case PLATFORM_HPDET_INVERTED:
+ dsm_quirk |= BYT_CHT_ES8316_JD_INVERTED;
+ break;
+ default:
+ dev_warn(priv->codec_dev, "Unknown hpdet-inv setting 0x%02x\n", val1);
+ return -EINVAL;
+ }
+
+ quirk = dsm_quirk;
+ return 0;
+}
+
static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -470,10 +542,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
struct byt_cht_es8316_private *priv;
const struct dmi_system_id *dmi_id;
struct fwnode_handle *fwnode;
+ bool sof_parent, is_bytcr;
const char *platform_name;
struct acpi_device *adev;
struct device *codec_dev;
- bool sof_parent;
unsigned int cnt = 0;
int dai_index = 0;
int i;
@@ -485,7 +557,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) {
- if (!strcmp(byt_cht_es8316_dais[i].codecs->name,
+ if (byt_cht_es8316_dais[i].num_codecs &&
+ !strcmp(byt_cht_es8316_dais[i].codecs->name,
"i2c-ESSX8316:00")) {
dai_index = i;
break;
@@ -500,7 +573,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
byt_cht_es8316_dais[dai_index].codecs->name = codec_name;
} else {
dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
- return -ENXIO;
+ return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
@@ -520,12 +593,16 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
return ret;
}
+ es83xx_dsm_dump(priv->codec_dev);
+
/* Check for BYTCR or other platform and setup quirks */
+ is_bytcr = soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0;
dmi_id = dmi_first_match(byt_cht_es8316_quirk_table);
if (dmi_id) {
quirk = (unsigned long)dmi_id->driver_data;
- } else if (soc_intel_is_byt() &&
- mach->mach_params.acpi_ipc_irq_index == 0) {
+ } else if (!byt_cht_es8316_get_quirks_from_dsm(priv, is_bytcr)) {
+ dev_info(dev, "Using ACPI DSM info for quirks\n");
+ } else if (is_bytcr) {
/* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */
quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP |
BYT_CHT_ES8316_MONO_SPEAKER;
@@ -643,7 +720,7 @@ static struct platform_driver snd_byt_cht_es8316_mc_driver = {
.name = "bytcht_es8316",
},
.probe = snd_byt_cht_es8316_mc_probe,
- .remove_new = snd_byt_cht_es8316_mc_remove,
+ .remove = snd_byt_cht_es8316_mc_remove,
};
module_platform_driver(snd_byt_cht_es8316_mc_driver);
diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c
index 7fc03f2efd35..fec23bda9e64 100644
--- a/sound/soc/intel/boards/bytcht_nocodec.c
+++ b/sound/soc/intel/boards/bytcht_nocodec.c
@@ -58,7 +58,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch 24-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP);
@@ -68,7 +68,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 24);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -119,8 +119,6 @@ static struct snd_soc_dai_link dais[] = {
.ignore_suspend = 1,
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -130,7 +128,7 @@ static struct snd_soc_dai_link dais[] = {
.ignore_suspend = 1,
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -144,8 +142,6 @@ static struct snd_soc_dai_link dais[] = {
| SND_SOC_DAIFMT_CBC_CFC,
.be_hw_params_fixup = codec_fixup,
.ignore_suspend = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp2_port, dummy, platform),
},
};
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 630784b6cb6d..103e0b445603 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -17,6 +17,7 @@
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/device/bus.h>
#include <linux/dmi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
@@ -32,6 +33,8 @@
#include "../atom/sst-atom-controls.h"
#include "../common/soc-intel-quirks.h"
+#define BYT_RT5640_FALLBACK_CODEC_DEV_NAME "i2c-rt5640"
+
enum {
BYT_RT5640_DMIC1_MAP,
BYT_RT5640_DMIC2_MAP,
@@ -65,7 +68,8 @@ enum {
BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13),
};
-#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0))
+#define BYT_RT5640_MAP_MASK GENMASK(3, 0)
+#define BYT_RT5640_MAP(quirk) ((quirk) & BYT_RT5640_MAP_MASK)
#define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4)
#define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8)
#define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13)
@@ -83,6 +87,7 @@ enum {
#define BYT_RT5640_HSMIC2_ON_IN1 BIT(27)
#define BYT_RT5640_JD_HP_ELITEP_1000G2 BIT(28)
#define BYT_RT5640_USE_AMCR0F28 BIT(29)
+#define BYT_RT5640_SWAPPED_SPEAKERS BIT(30)
#define BYTCR_INPUT_DEFAULTS \
(BYT_RT5640_IN3_MAP | \
@@ -136,7 +141,9 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk NO_INTERNAL_MIC_MAP enabled\n");
break;
default:
- dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map);
+ dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to DMIC1_MAP\n", map);
+ byt_rt5640_quirk &= ~BYT_RT5640_MAP_MASK;
+ byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP;
break;
}
if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1)
@@ -157,6 +164,8 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk MONO_SPEAKER enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)
dev_info(dev, "quirk NO_SPEAKERS enabled\n");
+ if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS)
+ dev_info(dev, "quirk SWAPPED_SPEAKERS enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT)
dev_info(dev, "quirk LINEOUT enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2)
@@ -248,7 +257,7 @@ static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
static struct snd_soc_dai *byt_rt5640_get_codec_dai(struct snd_soc_dapm_context *dapm)
{
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct snd_soc_dai *codec_dai;
codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1);
@@ -264,7 +273,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
struct snd_soc_dai *codec_dai;
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
int ret;
@@ -525,8 +534,8 @@ static int byt_rt5640_hp_elitepad_1000g2_jack2_check(void *data)
static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params));
}
@@ -570,6 +579,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
+ { /* Acer Aspire SW3-013 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"),
+ },
+ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -610,6 +632,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 101 CESIUM"),
+ },
+ .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+ BYT_RT5640_JD_NOT_INV |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
@@ -633,28 +666,30 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_USE_AMCR0F28),
},
{
+ /* Asus T100TAF, unlike other T100TA* models this one has a mono speaker */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_MONO_SPEAKER |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{
+ /* Asus T100TA and T100TAM, must come after T100TAF (mono spk) match */
.matches = {
- DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
- BYT_RT5640_MONO_SPEAKER |
- BYT_RT5640_DIFF_MIC |
- BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{
@@ -682,6 +717,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
+ { /* Chuwi Vi8 dual-boot (CWI506) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"),
+ /* The above are too generic, also match BIOS info */
+ DMI_MATCH(DMI_BIOS_VERSION, "CHUWI2.D86JHBNR02"),
+ },
+ .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+ BYT_RT5640_MONO_SPEAKER |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{
/* Chuwi Vi10 (CWI505) */
.matches = {
@@ -894,6 +941,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
+ {
+ /* Medion Lifetab S10346 */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+ /* Above strings are much too generic, also match on BIOS date */
+ DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"),
+ },
+ .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+ BYT_RT5640_SWAPPED_SPEAKERS |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{ /* Mele PCG03 Mini PC */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
@@ -1088,6 +1148,36 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
+ {
+ /* 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"),
+ /* Above strings are too generic, also match on BIOS date */
+ DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
+ },
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF2 |
+ BYT_RT5640_MCLK_EN),
+ },
{ /* Voyo Winpad A15 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
@@ -1227,14 +1317,15 @@ put_adev:
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
struct rt5640_set_jack_data *jack_data = &priv->jack_data;
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
const struct snd_soc_dapm_route *custom_map = NULL;
int num_routes = 0;
int ret;
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
jack_data->use_platform_clock = true;
/* Start with RC clk for jack-detect (we disable MCLK below) */
@@ -1277,12 +1368,12 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
break;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
if (ret)
return ret;
if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_hsmic2_in1_map,
ARRAY_SIZE(byt_rt5640_hsmic2_in1_map));
if (ret)
@@ -1290,19 +1381,19 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
}
if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_ssp2_aif2_map,
ARRAY_SIZE(byt_rt5640_ssp2_aif2_map));
} else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_ssp0_aif1_map,
ARRAY_SIZE(byt_rt5640_ssp0_aif1_map));
} else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_ssp0_aif2_map,
ARRAY_SIZE(byt_rt5640_ssp0_aif2_map));
} else {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_ssp2_aif1_map,
ARRAY_SIZE(byt_rt5640_ssp2_aif1_map));
}
@@ -1310,11 +1401,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
return ret;
if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_mono_spk_map,
ARRAY_SIZE(byt_rt5640_mono_spk_map));
} else if (!(byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_stereo_spk_map,
ARRAY_SIZE(byt_rt5640_stereo_spk_map));
}
@@ -1322,7 +1413,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
return ret;
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5640_lineout_map,
ARRAY_SIZE(byt_rt5640_lineout_map));
if (ret)
@@ -1447,7 +1538,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP);
@@ -1456,7 +1547,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -1505,8 +1596,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
.stream_name = "Baytrail Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &byt_rt5640_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -1515,7 +1604,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &byt_rt5640_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -1527,8 +1616,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
.be_hw_params_fixup = byt_rt5640_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.init = byt_rt5640_init,
.exit = byt_rt5640_exit,
.ops = &byt_rt5640_be_ssp2_ops,
@@ -1619,11 +1706,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
const char *platform_name;
struct acpi_device *adev;
struct device *codec_dev;
+ const char *cfg_spk;
bool sof_parent;
int ret_val = 0;
int dai_index = 0;
- int i, cfg_spk;
- int aif;
+ int i, aif;
is_bytcr = false;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -1636,7 +1723,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) {
- if (!strcmp(byt_rt5640_dais[i].codecs->name,
+ if (byt_rt5640_dais[i].num_codecs &&
+ !strcmp(byt_rt5640_dais[i].codecs->name,
"i2c-10EC5640:00")) {
dai_index = i;
break;
@@ -1651,14 +1739,38 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name;
} else {
dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
- return -ENXIO;
+ return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
acpi_dev_put(adev);
- if (!codec_dev)
- return -EPROBE_DEFER;
- priv->codec_dev = get_device(codec_dev);
+
+ if (codec_dev) {
+ priv->codec_dev = get_device(codec_dev);
+ } else {
+ /*
+ * Special case for Android tablets where the codec i2c_client
+ * has been manually instantiated by x86_android_tablets.ko due
+ * to a broken DSDT.
+ */
+ codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL,
+ BYT_RT5640_FALLBACK_CODEC_DEV_NAME);
+ if (!codec_dev)
+ return -EPROBE_DEFER;
+
+ if (!i2c_verify_client(codec_dev)) {
+ dev_err(dev, "Error '%s' is not an i2c_client\n",
+ BYT_RT5640_FALLBACK_CODEC_DEV_NAME);
+ put_device(codec_dev);
+ }
+
+ /* fixup codec name */
+ strscpy(byt_rt5640_codec_name, BYT_RT5640_FALLBACK_CODEC_DEV_NAME,
+ sizeof(byt_rt5640_codec_name));
+
+ /* bus_find_device() returns a reference no need to get() */
+ priv->codec_dev = codec_dev;
+ }
/*
* swap SSP0 if bytcr is detected
@@ -1783,13 +1895,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) {
- cfg_spk = 0;
+ cfg_spk = "0";
spk_type = "none";
} else if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
- cfg_spk = 1;
+ cfg_spk = "1";
spk_type = "mono";
+ } else if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS) {
+ cfg_spk = "swapped";
+ spk_type = "swapped";
} else {
- cfg_spk = 2;
+ cfg_spk = "2";
spk_type = "stereo";
}
@@ -1804,7 +1919,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
headset2_string = " cfg-hs2:in1";
snprintf(byt_rt5640_components, sizeof(byt_rt5640_components),
- "cfg-spk:%d cfg-mic:%s aif:%d%s%s", cfg_spk,
+ "cfg-spk:%s cfg-mic:%s aif:%d%s%s", cfg_spk,
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif,
lineout_string, headset2_string);
byt_rt5640_card.components = byt_rt5640_components;
@@ -1873,7 +1988,7 @@ static struct platform_driver snd_byt_rt5640_mc_driver = {
.name = "bytcr_rt5640",
},
.probe = snd_byt_rt5640_mc_probe,
- .remove_new = snd_byt_rt5640_mc_remove,
+ .remove = snd_byt_rt5640_mc_remove,
};
module_platform_driver(snd_byt_rt5640_mc_driver);
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 805afaf47b29..68cf463f1d50 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -58,7 +58,8 @@ enum {
BYT_RT5651_OVCD_SF_1P5 = (RT5651_OVCD_SF_1P5 << 13),
};
-#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(3, 0))
+#define BYT_RT5651_MAP_MASK GENMASK(3, 0)
+#define BYT_RT5651_MAP(quirk) ((quirk) & BYT_RT5651_MAP_MASK)
#define BYT_RT5651_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4)
#define BYT_RT5651_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8)
#define BYT_RT5651_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13)
@@ -100,14 +101,29 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");
static void log_quirks(struct device *dev)
{
- if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP)
+ int map;
+
+ map = BYT_RT5651_MAP(byt_rt5651_quirk);
+ switch (map) {
+ case BYT_RT5651_DMIC_MAP:
dev_info(dev, "quirk DMIC_MAP enabled");
- if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_MAP)
+ break;
+ case BYT_RT5651_IN1_MAP:
dev_info(dev, "quirk IN1_MAP enabled");
- if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
+ break;
+ case BYT_RT5651_IN2_MAP:
dev_info(dev, "quirk IN2_MAP enabled");
- if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_IN2_MAP)
+ break;
+ case BYT_RT5651_IN1_IN2_MAP:
dev_info(dev, "quirk IN1_IN2_MAP enabled");
+ break;
+ default:
+ dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to DMIC_MAP\n", map);
+ byt_rt5651_quirk &= ~BYT_RT5651_MAP_MASK;
+ byt_rt5651_quirk |= BYT_RT5651_DMIC_MAP;
+ break;
+ }
+
if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) {
dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
BYT_RT5651_JDSRC(byt_rt5651_quirk));
@@ -172,8 +188,7 @@ static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai,
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
int ret;
@@ -218,7 +233,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
static int rt5651_ext_amp_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -344,8 +359,8 @@ static struct snd_soc_jack_pin bytcr_jack_pins[] = {
static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
snd_pcm_format_t format = params_format(params);
int rate = params_rate(params);
int bclk_ratio;
@@ -563,14 +578,15 @@ static int byt_rt5651_add_codec_device_props(struct device *i2c_dev,
static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
- struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component;
struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
const struct snd_soc_dapm_route *custom_map;
int num_routes;
int report;
int ret;
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
/* Start with RC clk for jack-detect (we disable MCLK below) */
if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
@@ -594,24 +610,24 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
custom_map = byt_rt5651_intmic_dmic_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
}
- ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
if (ret)
return ret;
if (byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5651_ssp2_aif2_map,
ARRAY_SIZE(byt_rt5651_ssp2_aif2_map));
} else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5651_ssp0_aif1_map,
ARRAY_SIZE(byt_rt5651_ssp0_aif1_map));
} else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5651_ssp0_aif2_map,
ARRAY_SIZE(byt_rt5651_ssp0_aif2_map));
} else {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
byt_rt5651_ssp2_aif1_map,
ARRAY_SIZE(byt_rt5651_ssp2_aif1_map));
}
@@ -703,7 +719,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP
@@ -714,7 +730,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -770,8 +786,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &byt_rt5651_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -780,7 +794,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &byt_rt5651_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -793,8 +807,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
.be_hw_params_fixup = byt_rt5651_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.init = byt_rt5651_init,
.ops = &byt_rt5651_be_ssp2_ops,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
@@ -910,7 +922,8 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
/* fix index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) {
- if (!strcmp(byt_rt5651_dais[i].codecs->name,
+ if (byt_rt5651_dais[i].num_codecs &&
+ !strcmp(byt_rt5651_dais[i].codecs->name,
"i2c-10EC5651:00")) {
dai_index = i;
break;
@@ -925,7 +938,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name;
} else {
dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
- return -ENXIO;
+ return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
@@ -1141,7 +1154,7 @@ static struct platform_driver snd_byt_rt5651_mc_driver = {
.name = "bytcr_rt5651",
},
.probe = snd_byt_rt5651_mc_probe,
- .remove_new = snd_byt_rt5651_mc_remove,
+ .remove = snd_byt_rt5651_mc_remove,
};
module_platform_driver(snd_byt_rt5651_mc_driver);
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index f2382d4cb76f..4879f79aef29 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -10,11 +10,13 @@
*/
#include <linux/acpi.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
@@ -26,8 +28,6 @@
#include "../../codecs/wm5102.h"
#include "../atom/sst-atom-controls.h"
-#define MCLK_FREQ 25000000
-
#define WM5102_MAX_SYSCLK_4K 49152000 /* max sysclk for 4K family */
#define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */
@@ -35,12 +35,71 @@ struct byt_wm5102_private {
struct snd_soc_jack jack;
struct clk *mclk;
struct gpio_desc *spkvdd_en_gpio;
+ int mclk_freq;
};
+#define BYT_WM5102_IN_MAP GENMASK(3, 0)
+#define BYT_WM5102_OUT_MAP GENMASK(7, 4)
+#define BYT_WM5102_SSP2 BIT(16)
+#define BYT_WM5102_MCLK_19_2MHZ BIT(17)
+
+enum {
+ BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L,
+ BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L,
+};
+
+/* Note these values are pre-shifted for easy use of setting quirks */
+enum {
+ BYT_WM5102_SPK_SPK_MAP = FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 0),
+ BYT_WM5102_SPK_HPOUT2_MAP = FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 1),
+};
+
+static unsigned long quirk;
+
+static int quirk_override = -1;
+module_param_named(quirk, quirk_override, int, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
+static void log_quirks(struct device *dev)
+{
+ switch (quirk & BYT_WM5102_IN_MAP) {
+ case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L:
+ dev_info_once(dev, "quirk INTMIC_IN3L_HSMIC_IN1L enabled\n");
+ break;
+ case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L:
+ dev_info_once(dev, "quirk INTMIC_IN1L_HSMIC_IN2L enabled\n");
+ break;
+ default:
+ dev_warn_once(dev, "quirk sets invalid input map: 0x%lx, defaulting to INTMIC_IN3L_HSMIC_IN1L\n",
+ quirk & BYT_WM5102_IN_MAP);
+ quirk &= ~BYT_WM5102_IN_MAP;
+ quirk |= BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L;
+ break;
+ }
+ switch (quirk & BYT_WM5102_OUT_MAP) {
+ case BYT_WM5102_SPK_SPK_MAP:
+ dev_info_once(dev, "quirk SPK_SPK_MAP enabled\n");
+ break;
+ case BYT_WM5102_SPK_HPOUT2_MAP:
+ dev_info_once(dev, "quirk SPK_HPOUT2_MAP enabled\n");
+ break;
+ default:
+ dev_warn_once(dev, "quirk sets invalid output map: 0x%lx, defaulting to SPK_SPK_MAP\n",
+ quirk & BYT_WM5102_OUT_MAP);
+ quirk &= ~BYT_WM5102_OUT_MAP;
+ quirk |= BYT_WM5102_SPK_SPK_MAP;
+ break;
+ }
+ if (quirk & BYT_WM5102_SSP2)
+ dev_info_once(dev, "quirk SSP2 enabled");
+ if (quirk & BYT_WM5102_MCLK_19_2MHZ)
+ dev_info_once(dev, "quirk MCLK 19.2MHz enabled");
+}
+
static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
gpiod_set_value_cansleep(priv->spkvdd_en_gpio,
@@ -52,6 +111,7 @@ static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate)
{
struct snd_soc_component *codec_component = codec_dai->component;
+ struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(codec_component->card);
int sr_mult = ((rate % 4000) == 0) ?
(WM5102_MAX_SYSCLK_4K / rate) :
(WM5102_MAX_SYSCLK_11025 / rate);
@@ -63,7 +123,7 @@ static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int
/* Configure the FLL1 PLL before selecting it */
ret = snd_soc_dai_set_pll(codec_dai, WM5102_FLL1, ARIZONA_CLK_SRC_MCLK1,
- MCLK_FREQ, rate * sr_mult);
+ priv->mclk_freq, rate * sr_mult);
if (ret) {
dev_err(codec_component->dev, "Error setting PLL: %d\n", ret);
return ret;
@@ -90,8 +150,7 @@ static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
int ret;
@@ -131,6 +190,7 @@ static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Internal Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
@@ -144,39 +204,64 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
{"Headset Mic", NULL, "Platform Clock"},
{"Internal Mic", NULL, "Platform Clock"},
{"Speaker", NULL, "Platform Clock"},
-
- {"Speaker", NULL, "SPKOUTLP"},
- {"Speaker", NULL, "SPKOUTLN"},
- {"Speaker", NULL, "SPKOUTRP"},
- {"Speaker", NULL, "SPKOUTRN"},
{"Speaker", NULL, "Speaker VDD"},
{"Headphone", NULL, "HPOUT1L"},
{"Headphone", NULL, "HPOUT1R"},
- {"Internal Mic", NULL, "MICBIAS3"},
- {"IN3L", NULL, "Internal Mic"},
-
/*
* The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset
* is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch.
*/
{"Headset Mic", NULL, "MICBIAS1"},
{"Headset Mic", NULL, "MICBIAS2"},
- {"IN1L", NULL, "Headset Mic"},
+ {"Internal Mic", NULL, "MICBIAS3"},
+};
+static const struct snd_soc_dapm_route bytcr_wm5102_ssp0_map[] = {
{"AIF1 Playback", NULL, "ssp0 Tx"},
{"ssp0 Tx", NULL, "modem_out"},
-
{"modem_in", NULL, "ssp0 Rx"},
{"ssp0 Rx", NULL, "AIF1 Capture"},
};
+static const struct snd_soc_dapm_route bytcr_wm5102_ssp2_map[] = {
+ {"AIF1 Playback", NULL, "ssp2 Tx"},
+ {"ssp2 Tx", NULL, "codec_out0"},
+ {"ssp2 Tx", NULL, "codec_out1"},
+ {"codec_in0", NULL, "ssp2 Rx"},
+ {"codec_in1", NULL, "ssp2 Rx"},
+ {"ssp2 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_soc_dapm_route byt_wm5102_spk_spk_map[] = {
+ {"Speaker", NULL, "SPKOUTLP"},
+ {"Speaker", NULL, "SPKOUTLN"},
+ {"Speaker", NULL, "SPKOUTRP"},
+ {"Speaker", NULL, "SPKOUTRN"},
+};
+
+static const struct snd_soc_dapm_route byt_wm5102_spk_hpout2_map[] = {
+ {"Speaker", NULL, "HPOUT2L"},
+ {"Speaker", NULL, "HPOUT2R"},
+};
+
+static const struct snd_soc_dapm_route byt_wm5102_intmic_in3l_hsmic_in1l_map[] = {
+ {"IN3L", NULL, "Internal Mic"},
+ {"IN1L", NULL, "Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_wm5102_intmic_in1l_hsmic_in2l_map[] = {
+ {"IN1L", NULL, "Internal Mic"},
+ {"IN2L", NULL, "Headset Mic"},
+};
+
static const struct snd_kcontrol_new byt_wm5102_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Internal Mic"),
SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static struct snd_soc_jack_pin byt_wm5102_pins[] = {
@@ -188,16 +273,22 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
- int ret, jack_type;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
+ const struct snd_soc_dapm_route *custom_map = NULL;
+ int ret, jack_type, num_routes = 0;
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
ret = snd_soc_add_card_controls(card, byt_wm5102_controls,
ARRAY_SIZE(byt_wm5102_controls));
@@ -206,6 +297,50 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
+ switch (quirk & BYT_WM5102_IN_MAP) {
+ case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L:
+ custom_map = byt_wm5102_intmic_in3l_hsmic_in1l_map;
+ num_routes = ARRAY_SIZE(byt_wm5102_intmic_in3l_hsmic_in1l_map);
+ break;
+ case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L:
+ custom_map = byt_wm5102_intmic_in1l_hsmic_in2l_map;
+ num_routes = ARRAY_SIZE(byt_wm5102_intmic_in1l_hsmic_in2l_map);
+ break;
+ }
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+ if (ret)
+ return ret;
+
+ switch (quirk & BYT_WM5102_OUT_MAP) {
+ case BYT_WM5102_SPK_SPK_MAP:
+ custom_map = byt_wm5102_spk_spk_map;
+ num_routes = ARRAY_SIZE(byt_wm5102_spk_spk_map);
+ break;
+ case BYT_WM5102_SPK_HPOUT2_MAP:
+ custom_map = byt_wm5102_spk_hpout2_map;
+ num_routes = ARRAY_SIZE(byt_wm5102_spk_hpout2_map);
+ break;
+ }
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+ if (ret)
+ return ret;
+
+ if (quirk & BYT_WM5102_SSP2) {
+ custom_map = bytcr_wm5102_ssp2_map;
+ num_routes = ARRAY_SIZE(bytcr_wm5102_ssp2_map);
+ } else {
+ custom_map = bytcr_wm5102_ssp0_map;
+ num_routes = ARRAY_SIZE(bytcr_wm5102_ssp0_map);
+ }
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+ if (ret)
+ return ret;
+
+ if (quirk & BYT_WM5102_MCLK_19_2MHZ)
+ priv->mclk_freq = 19200000;
+ else
+ priv->mclk_freq = 25000000;
+
/*
* The firmware might enable the clock at boot (this information
* may or may not be reflected in the enable clock register).
@@ -218,7 +353,7 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
if (!ret)
clk_disable_unprepare(priv->mclk);
- ret = clk_set_rate(priv->mclk, MCLK_FREQ);
+ ret = clk_set_rate(priv->mclk, priv->mclk_freq);
if (ret) {
dev_err(card->dev, "Error setting MCLK rate: %d\n", ret);
return ret;
@@ -246,7 +381,7 @@ static int byt_wm5102_codec_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);
- int ret;
+ int ret, bits;
/* The DSP will convert the FE rate to 48k, stereo */
rate->min = 48000;
@@ -254,15 +389,22 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = 2;
channels->max = 2;
- /* set SSP0 to 16-bit */
- params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+ if (quirk & BYT_WM5102_SSP2) {
+ /* set SSP2 to 24-bit */
+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+ bits = 24;
+ } else {
+ /* set SSP0 to 16-bit */
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+ bits = 16;
+ }
/*
* Default mode for SSP configuration is TDM 4 slot, override config
* with explicit setting to I2S 2ch 16-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP);
@@ -271,7 +413,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
if (ret) {
dev_err(rtd->dev, "Error setting I2S config: %d\n", ret);
return ret;
@@ -320,8 +462,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = {
.stream_name = "Baytrail Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &byt_wm5102_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
@@ -331,19 +471,16 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &byt_wm5102_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
/* back ends */
{
/*
- * This must be named SSP2-Codec even though this machine driver
- * always uses SSP0. Most machine drivers support both and dynamically
- * update the dailink to point to SSP0 or SSP2, while keeping the name
- * as "SSP2-Codec". The SOF tplg files hardcode the "SSP2-Codec" even
- * in the byt-foo-ssp0.tplg versions because the other machine-drivers
- * use "SSP2-Codec" even when SSP0 is used.
+ * This dailink is updated dynamically to point to SSP0 or SSP2.
+ * Yet its name is always kept as "SSP2-Codec" because the SOF
+ * tplg files hardcode "SSP2-Codec" even in byt-foo-ssp0.tplg.
*/
.name = "SSP2-Codec",
.id = 0,
@@ -351,8 +488,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBC_CFC,
.be_hw_params_fixup = byt_wm5102_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.init = byt_wm5102_init,
SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform),
},
@@ -377,8 +512,13 @@ static struct snd_soc_card byt_wm5102_card = {
.fully_routed = true,
};
+static char byt_wm5102_components[64]; /* = "cfg-spk:* cfg-int-mic:* cfg-hs-mic:* ..." */
+
static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
{
+ static const char * const out_map_name[] = { "spk", "hpout2" };
+ static const char * const intmic_map_name[] = { "in3l", "in1l" };
+ static const char * const hsmic_map_name[] = { "in1l", "in2l" };
char codec_name[SND_ACPI_I2C_ID_LEN];
struct device *dev = &pdev->dev;
struct byt_wm5102_private *priv;
@@ -386,8 +526,9 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
const char *platform_name;
struct acpi_device *adev;
struct device *codec_dev;
+ int dai_index = 0;
bool sof_parent;
- int ret;
+ int i, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -406,14 +547,15 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
*/
mach = dev->platform_data;
adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
- if (!adev) {
- dev_err(dev, "Error cannot find acpi-dev for codec\n");
- return -ENOENT;
+ if (adev) {
+ snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev));
+ acpi_dev_put(adev);
+ } else {
+ /* Special case for when the codec is missing from the DSTD */
+ strscpy(codec_name, "spi-wm5102", sizeof(codec_name));
}
- snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev));
codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name);
- acpi_dev_put(adev);
if (!codec_dev)
return -EPROBE_DEFER;
@@ -433,6 +575,40 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n");
}
+ if (soc_intel_is_cht()) {
+ /*
+ * CHT always uses SSP2 and 19.2 MHz; and
+ * the one currently supported CHT design uses HPOUT2 as
+ * speaker output and has the intmic on IN1L + hsmic on IN2L.
+ */
+ quirk = BYT_WM5102_SSP2 | BYT_WM5102_MCLK_19_2MHZ |
+ BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L |
+ BYT_WM5102_SPK_HPOUT2_MAP;
+ }
+ if (quirk_override != -1) {
+ dev_info_once(dev, "Overriding quirk 0x%lx => 0x%x\n",
+ quirk, quirk_override);
+ quirk = quirk_override;
+ }
+ log_quirks(dev);
+
+ snprintf(byt_wm5102_components, sizeof(byt_wm5102_components),
+ "cfg-spk:%s cfg-intmic:%s cfg-hsmic:%s",
+ out_map_name[FIELD_GET(BYT_WM5102_OUT_MAP, quirk)],
+ intmic_map_name[FIELD_GET(BYT_WM5102_IN_MAP, quirk)],
+ hsmic_map_name[FIELD_GET(BYT_WM5102_IN_MAP, quirk)]);
+ byt_wm5102_card.components = byt_wm5102_components;
+
+ /* find index of codec dai */
+ for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) {
+ if (byt_wm5102_dais[i].num_codecs &&
+ !strcmp(byt_wm5102_dais[i].codecs->name,
+ "wm5102-codec")) {
+ dai_index = i;
+ break;
+ }
+ }
+
/* override platform name, if required */
byt_wm5102_card.dev = dev;
platform_name = mach->mach_params.platform;
@@ -440,6 +616,10 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
if (ret)
goto out_put_gpio;
+ /* override SSP port, if required */
+ if (quirk & BYT_WM5102_SSP2)
+ byt_wm5102_dais[dai_index].cpus->dai_name = "ssp2-port";
+
/* set card and driver name and pm-ops */
sof_parent = snd_soc_acpi_sof_parent(dev);
if (sof_parent) {
@@ -479,7 +659,7 @@ static struct platform_driver snd_byt_wm5102_mc_driver = {
.name = "bytcr_wm5102",
},
.probe = snd_byt_wm5102_mc_probe,
- .remove_new = snd_byt_wm5102_mc_remove,
+ .remove = snd_byt_wm5102_mc_remove,
};
module_platform_driver(snd_byt_wm5102_mc_driver);
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 850310de774b..ad45b79d3e4b 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -42,8 +42,7 @@ struct cht_mc_private {
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
@@ -112,8 +111,8 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
@@ -130,7 +129,7 @@ static int cht_ti_jack_event(struct notifier_block *nb,
unsigned long event, void *data)
{
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
- struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(jack->card);
if (event & SND_JACK_MICROPHONE) {
snd_soc_dapm_force_enable_pin(dapm, "SHDN");
@@ -258,7 +257,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
int ret = 0;
unsigned int fmt = 0;
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
if (ret < 0) {
dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
return ret;
@@ -266,7 +265,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), fmt);
if (ret < 0) {
dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
return ret;
@@ -351,8 +350,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -361,7 +358,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -374,8 +371,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
| SND_SOC_DAIFMT_CBC_CFC,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_be_ssp2_ops,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
},
@@ -637,7 +632,7 @@ static struct platform_driver snd_cht_mc_driver = {
.name = "cht-bsw-max98090",
},
.probe = snd_cht_mc_probe,
- .remove_new = snd_cht_mc_remove,
+ .remove = snd_cht_mc_remove,
};
module_platform_driver(snd_cht_mc_driver)
diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c
index af2d9a78465d..4afb292d4f13 100644
--- a/sound/soc/intel/boards/cht_bsw_nau8824.c
+++ b/sound/soc/intel/boards/cht_bsw_nau8824.c
@@ -72,8 +72,8 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8824_CLK_FLL_FS, 0,
@@ -96,7 +96,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
struct snd_soc_jack *jack = &ctx->jack;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
struct snd_soc_component *component = codec_dai->component;
int ret, jack_type;
@@ -145,7 +145,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0xf, 0x1, 4, 24);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
return ret;
@@ -193,8 +193,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -203,7 +201,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -217,8 +215,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
| SND_SOC_DAIFMT_CBC_CFC,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_be_ssp2_ops,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
},
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 875bc0b3d85d..249be121be15 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -40,7 +40,6 @@ struct cht_acpi_card {
struct cht_mc_private {
struct snd_soc_jack jack;
struct cht_acpi_card *acpi_card;
- char codec_name[SND_ACPI_I2C_ID_LEN];
struct clk *mclk;
};
@@ -67,8 +66,7 @@ static void log_quirks(struct device *dev)
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
@@ -207,8 +205,8 @@ static struct snd_soc_jack_pin cht_bsw_jack_pins[] = {
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
/* set codec PLL source to the 19.2MHz platform clock (MCLK) */
@@ -251,8 +249,9 @@ static const struct dmi_system_id cht_rt5645_quirk_table[] = {
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
int jack_type;
int ret;
@@ -276,19 +275,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
}
if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
cht_rt5645_ssp2_aif2_map,
ARRAY_SIZE(cht_rt5645_ssp2_aif2_map));
} else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
cht_rt5645_ssp0_aif1_map,
ARRAY_SIZE(cht_rt5645_ssp0_aif1_map));
} else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
cht_rt5645_ssp0_aif2_map,
ARRAY_SIZE(cht_rt5645_ssp0_aif2_map));
} else {
- ret = snd_soc_dapm_add_routes(&card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
cht_rt5645_ssp2_aif1_map,
ARRAY_SIZE(cht_rt5645_ssp2_aif1_map));
}
@@ -359,7 +358,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
* with explicit setting to I2S 2ch 16-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP
@@ -369,7 +368,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BC_FC
@@ -379,7 +378,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -393,7 +392,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
/*
* Default mode for SSP configuration is TDM 4 slot
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0),
SND_SOC_DAIFMT_DSP_B |
SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_BC_FC);
@@ -403,7 +402,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
}
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0xF, 0xF, 4, 24);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0xF, 0xF, 4, 24);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
return ret;
@@ -449,8 +448,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -459,7 +456,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -471,8 +468,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.no_pcm = 1,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_be_ssp2_ops,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
},
@@ -534,6 +529,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
const char *platform_name;
struct cht_mc_private *drv;
struct acpi_device *adev;
+ struct device *codec_dev;
bool sof_parent;
bool found = false;
bool is_bytcr = false;
@@ -566,14 +562,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
card->dev = &pdev->dev;
- sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
/* set correct codec name */
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
- if (!strcmp(card->dai_link[i].codecs->name,
+ if (cht_dailink[i].num_codecs &&
+ !strcmp(cht_dailink[i].codecs->name,
"i2c-10EC5645:00")) {
- card->dai_link[i].codecs->name = drv->codec_name;
dai_index = i;
+ break;
}
/* fixup codec name based on HID */
@@ -582,8 +578,19 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
"i2c-%s", acpi_dev_name(adev));
cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name;
+ } else {
+ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
+ return -ENOENT;
}
+
+ /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */
+ codec_dev = acpi_get_first_physical_node(adev);
acpi_dev_put(adev);
+ if (!codec_dev)
+ return -EPROBE_DEFER;
+
+ snd_soc_card_chtrt5645.components = rt5645_components(codec_dev);
+ snd_soc_card_chtrt5650.components = rt5645_components(codec_dev);
/*
* swap SSP0 if bytcr is detected
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index daa630a0efc1..359723f2700e 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
+#include <linux/string.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -50,8 +51,7 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
@@ -93,8 +93,12 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
* when codec is runtime suspended. Codec needs clock for jack
* detection and button press.
*/
- snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
- 48000 * 512, SND_SOC_CLOCK_IN);
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
+ 48000 * 512, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "failed to set codec sysclk: %d\n", ret);
+ return ret;
+ }
if (ctx->mclk)
clk_disable_unprepare(ctx->mclk);
@@ -155,8 +159,8 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
/* set codec PLL source to the 19.2MHz platform clock (MCLK) */
@@ -188,7 +192,8 @@ static const struct acpi_gpio_mapping cht_rt5672_gpios[] = {
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(runtime->card);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0);
struct snd_soc_component *component = codec_dai->component;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
@@ -210,11 +215,11 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
RT5670_CLK_SEL_I2S1_ASRC);
if (ctx->use_ssp0) {
- ret = snd_soc_dapm_add_routes(&runtime->card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
cht_audio_ssp0_map,
ARRAY_SIZE(cht_audio_ssp0_map));
} else {
- ret = snd_soc_dapm_add_routes(&runtime->card->dapm,
+ ret = snd_soc_dapm_add_routes(dapm,
cht_audio_ssp2_map,
ARRAY_SIZE(cht_audio_ssp2_map));
}
@@ -297,7 +302,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
* board. Since we only support 2 channels anyways, there is no need
* for TDM on any cht-bsw-rt5672 designs. So we use I2S 2ch everywhere.
*/
- ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
+ ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0),
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_BP_FP);
@@ -306,7 +311,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
+ ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
if (ret < 0) {
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
return ret;
@@ -354,8 +359,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(media, dummy, platform),
},
@@ -364,7 +367,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
.stream_name = "Deep-Buffer Audio",
.nonatomic = true,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &cht_aif1_ops,
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
},
@@ -377,8 +380,6 @@ static struct snd_soc_dai_link cht_dailink[] = {
.no_pcm = 1,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &cht_be_ssp2_ops,
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
},
@@ -458,11 +459,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
if (!drv)
return -ENOMEM;
- strcpy(drv->codec_name, RT5672_I2C_DEFAULT);
+ strscpy(drv->codec_name, RT5672_I2C_DEFAULT, sizeof(drv->codec_name));
/* find index of codec dai */
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
- if (!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
+ if (cht_dailink[i].num_codecs &&
+ !strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
dai_index = i;
break;
}
@@ -474,7 +476,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
snprintf(drv->codec_name, sizeof(drv->codec_name),
"i2c-%s", acpi_dev_name(adev));
cht_dailink[dai_index].codecs->name = drv->codec_name;
+ } else {
+ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
+ return -ENOENT;
}
+
acpi_dev_put(adev);
/* Use SSP0 on Bay Trail CR devices */
diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c
deleted file mode 100644
index 20da83d9eece..000000000000
--- a/sound/soc/intel/boards/cml_rt1011_rt5682.c
+++ /dev/null
@@ -1,609 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2019 Intel Corporation.
-
-/*
- * Intel Cometlake I2S Machine driver for RT1011 + RT5682 codec
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/dmi.h>
-#include <linux/slab.h>
-#include <linux/acpi.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/rt5682.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/rt1011.h"
-#include "../../codecs/rt5682.h"
-#include "../../codecs/hdac_hdmi.h"
-#include "hda_dsp_common.h"
-
-/* The platform clock outputs 24Mhz clock to codec as I2S MCLK */
-#define CML_PLAT_CLK 24000000
-#define CML_RT1011_CODEC_DAI "rt1011-aif"
-#define CML_RT5682_CODEC_DAI "rt5682-aif1"
-#define NAME_SIZE 32
-
-#define SOF_RT1011_SPEAKER_WL BIT(0)
-#define SOF_RT1011_SPEAKER_WR BIT(1)
-#define SOF_RT1011_SPEAKER_TL BIT(2)
-#define SOF_RT1011_SPEAKER_TR BIT(3)
-
-/* Default: Woofer speakers */
-static unsigned long sof_rt1011_quirk = SOF_RT1011_SPEAKER_WL |
- SOF_RT1011_SPEAKER_WR;
-
-static int sof_rt1011_quirk_cb(const struct dmi_system_id *id)
-{
- sof_rt1011_quirk = (unsigned long)id->driver_data;
- return 1;
-}
-
-static const struct dmi_system_id sof_rt1011_quirk_table[] = {
- {
- .callback = sof_rt1011_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Google"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Helios"),
- },
- .driver_data = (void *)(SOF_RT1011_SPEAKER_WL | SOF_RT1011_SPEAKER_WR |
- SOF_RT1011_SPEAKER_TL | SOF_RT1011_SPEAKER_TR),
- },
- {
- }
-};
-
-static struct snd_soc_jack hdmi_jack[3];
-
-struct hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct card_private {
- char codec_name[SND_ACPI_I2C_ID_LEN];
- struct snd_soc_jack headset;
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
-};
-
-static const struct snd_kcontrol_new cml_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("WL Ext Spk"),
- SOC_DAPM_PIN_SWITCH("WR Ext Spk"),
-};
-
-static const struct snd_kcontrol_new cml_rt1011_tt_controls[] = {
- SOC_DAPM_PIN_SWITCH("TL Ext Spk"),
- SOC_DAPM_PIN_SWITCH("TR Ext Spk"),
-};
-
-static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = {
- SND_SOC_DAPM_SPK("WL Ext Spk", NULL),
- SND_SOC_DAPM_SPK("WR Ext Spk", NULL),
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
-static const struct snd_soc_dapm_widget cml_rt1011_tt_widgets[] = {
- SND_SOC_DAPM_SPK("TL Ext Spk", NULL),
- SND_SOC_DAPM_SPK("TR Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = {
- /*WL/WR speaker*/
- {"WL Ext Spk", NULL, "WL SPO"},
- {"WR Ext Spk", NULL, "WR SPO"},
-
- /* HP jack connectors - unknown if we have jack detection */
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
-
- /* other jacks */
- { "IN1P", NULL, "Headset Mic" },
-
- /* DMIC */
- {"DMic", NULL, "SoC DMIC"},
-};
-
-static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = {
- /*TL/TR speaker*/
- {"TL Ext Spk", NULL, "TL SPO" },
- {"TR Ext Spk", NULL, "TR SPO" },
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_jack *jack;
- int ret;
-
- /* need to enable ASRC function for 24MHz mclk rate */
- rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
- RT5682_AD_STEREO1_FILTER,
- RT5682_CLK_SEL_I2S1_ASRC);
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- 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,
- &ctx->headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- jack = &ctx->headset;
-
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, jack, NULL);
- if (ret)
- dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
-
- return ret;
-};
-
-static void cml_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
- snd_soc_component_set_jack(component, NULL, NULL);
-}
-
-static int cml_rt1011_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret = 0;
- struct snd_soc_card *card = rtd->card;
-
- if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
- SOF_RT1011_SPEAKER_TR)) {
-
- ret = snd_soc_add_card_controls(card, cml_rt1011_tt_controls,
- ARRAY_SIZE(cml_rt1011_tt_controls));
- if (ret)
- return ret;
-
- ret = snd_soc_dapm_new_controls(&card->dapm,
- cml_rt1011_tt_widgets,
- ARRAY_SIZE(cml_rt1011_tt_widgets));
- if (ret)
- return ret;
-
- ret = snd_soc_dapm_add_routes(&card->dapm, cml_rt1011_tt_map,
- ARRAY_SIZE(cml_rt1011_tt_map));
-
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-static int cml_rt5682_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int clk_id, clk_freq, pll_out, ret;
-
- clk_id = RT5682_PLL1_S_MCLK;
- clk_freq = CML_PLAT_CLK;
-
- pll_out = params_rate(params) * 512;
-
- ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
- if (ret < 0)
- dev_warn(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
-
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
- pll_out, SND_SOC_CLOCK_IN);
- if (ret < 0)
- dev_warn(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
-
- /*
- * slot_width should be equal or large than data length, set them
- * be the same
- */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
- params_width(params));
- if (ret < 0)
- dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
- return ret;
-}
-
-static int cml_rt1011_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- struct snd_soc_card *card = rtd->card;
- int srate, i, ret = 0;
-
- srate = params_rate(params);
-
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
-
- /* 100 Fs to drive 24 bit data */
- ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,
- 100 * srate, 256 * srate);
- if (ret < 0) {
- dev_err(card->dev, "codec_dai clock not set\n");
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT1011_FS_SYS_PRE_S_PLL1,
- 256 * srate, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(card->dev, "codec_dai clock not set\n");
- return ret;
- }
-
- /*
- * Codec TDM is configured as 24 bit capture/ playback.
- * 2 CH PB is done over 4 codecs - 2 Woofers and 2 Tweeters.
- * The Left woofer and tweeter plays the Left playback data
- * and similar by the Right.
- * Hence 2 codecs (1 T and 1 W pair) share same Rx slot.
- * The feedback is captured for each codec individually.
- * Hence all 4 codecs use 1 Tx slot each for feedback.
- */
- if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_WL |
- SOF_RT1011_SPEAKER_WR)) {
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x4, 0x1, 4, 24);
- if (ret < 0)
- break;
- }
-
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x8, 0x2, 4, 24);
- if (ret < 0)
- break;
- }
- }
-
- if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
- SOF_RT1011_SPEAKER_TR)) {
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x1, 0x1, 4, 24);
- if (ret < 0)
- break;
- }
-
- if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x2, 0x2, 4, 24);
- if (ret < 0)
- break;
- }
- }
- }
- if (ret < 0)
- dev_err(rtd->dev,
- "set codec TDM slot for %s failed with error %d\n",
- codec_dai->component->name, ret);
- return ret;
-}
-
-static struct snd_soc_ops cml_rt5682_ops = {
- .hw_params = cml_rt5682_hw_params,
-};
-
-static const struct snd_soc_ops cml_rt1011_ops = {
- .hw_params = cml_rt1011_hw_params,
-};
-
-static int sof_card_late_probe(struct snd_soc_card *card)
-{
- struct card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = NULL;
- char jack_name[NAME_SIZE];
- struct hdmi_pcm *pcm;
- int ret, i = 0;
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- ret = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &hdmi_jack[i]);
- if (ret)
- return ret;
-
- ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &hdmi_jack[i]);
- if (ret < 0)
- return ret;
-
- i++;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = dai->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-/* Cometlake digital audio interface glue - connects codec <--> CPU */
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00",
- CML_RT5682_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec_2spk,
- DAILINK_COMP_ARRAY(
- /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI),
- /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI)));
-SND_SOC_DAILINK_DEF(ssp1_codec_4spk,
- DAILINK_COMP_ARRAY(
- /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI),
- /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI),
- /* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI),
- /* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI)));
-
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-
-SND_SOC_DAILINK_DEF(dmic16k_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
-
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = {
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .init = cml_rt5682_codec_init,
- .exit = cml_rt5682_codec_exit,
- .ignore_pmdown_time = 1,
- .ops = &cml_rt5682_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 1,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "dmic16k",
- .id = 2,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
- {
- /*
- * SSP1 - Codec : added to end of list ensuring
- * reuse of common topologies for other end points
- * and changing only SSP1's codec
- */
- .name = "SSP1-Codec",
- .id = 6,
- .dpcm_playback = 1,
- .dpcm_capture = 1, /* Capture stream provides Feedback */
- .no_pcm = 1,
- .init = cml_rt1011_spk_init,
- .ops = &cml_rt1011_ops,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec_2spk, platform),
- },
-};
-
-static struct snd_soc_codec_conf rt1011_conf[] = {
- {
- .dlc = COMP_CODEC_CONF("i2c-10EC1011:00"),
- .name_prefix = "WL",
- },
- {
- .dlc = COMP_CODEC_CONF("i2c-10EC1011:01"),
- .name_prefix = "WR",
- },
- /* single configuration structure for 2 and 4 channels */
- {
- .dlc = COMP_CODEC_CONF("i2c-10EC1011:02"),
- .name_prefix = "TL",
- },
- {
- .dlc = COMP_CODEC_CONF("i2c-10EC1011:03"),
- .name_prefix = "TR",
- },
-};
-
-/* Cometlake audio machine driver for RT1011 and RT5682 */
-static struct snd_soc_card snd_soc_card_cml = {
- .name = "cml_rt1011_rt5682",
- .owner = THIS_MODULE,
- .dai_link = cml_rt1011_rt5682_dailink,
- .num_links = ARRAY_SIZE(cml_rt1011_rt5682_dailink),
- .codec_conf = rt1011_conf,
- .num_configs = ARRAY_SIZE(rt1011_conf),
- .dapm_widgets = cml_rt1011_rt5682_widgets,
- .num_dapm_widgets = ARRAY_SIZE(cml_rt1011_rt5682_widgets),
- .dapm_routes = cml_rt1011_rt5682_map,
- .num_dapm_routes = ARRAY_SIZE(cml_rt1011_rt5682_map),
- .controls = cml_controls,
- .num_controls = ARRAY_SIZE(cml_controls),
- .fully_routed = true,
- .late_probe = sof_card_late_probe,
-};
-
-static int snd_cml_rt1011_probe(struct platform_device *pdev)
-{
- struct snd_soc_dai_link *dai_link;
- struct card_private *ctx;
- struct snd_soc_acpi_mach *mach;
- const char *platform_name;
- int ret, i;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- mach = pdev->dev.platform_data;
- snd_soc_card_cml.dev = &pdev->dev;
- platform_name = mach->mach_params.platform;
-
- dmi_check_system(sof_rt1011_quirk_table);
-
- dev_dbg(&pdev->dev, "sof_rt1011_quirk = %lx\n", sof_rt1011_quirk);
-
- /* when 4 speaker is available, update codec config */
- if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
- SOF_RT1011_SPEAKER_TR)) {
- for_each_card_prelinks(&snd_soc_card_cml, i, dai_link) {
- if (!strcmp(dai_link->codecs[0].dai_name,
- CML_RT1011_CODEC_DAI)) {
- dai_link->codecs = ssp1_codec_4spk;
- dai_link->num_codecs = ARRAY_SIZE(ssp1_codec_4spk);
- }
- }
- }
-
- /* set platform name for each dailink */
- ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml,
- platform_name);
- if (ret)
- return ret;
-
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
- snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx);
-
- return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml);
-}
-
-static struct platform_driver snd_cml_rt1011_rt5682_driver = {
- .probe = snd_cml_rt1011_probe,
- .driver = {
- .name = "cml_rt1011_rt5682",
- .pm = &snd_soc_pm_ops,
- },
-};
-module_platform_driver(snd_cml_rt1011_rt5682_driver);
-
-/* Module information */
-MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mode");
-MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
-MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
-MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
-MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:cml_rt1011_rt5682");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c
index fee80638cba2..5c7b218f22b7 100644
--- a/sound/soc/intel/boards/ehl_rt5660.c
+++ b/sound/soc/intel/boards/ehl_rt5660.c
@@ -74,7 +74,7 @@ struct sof_hdmi_pcm {
static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
struct sof_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
@@ -109,8 +109,8 @@ static int card_late_probe(struct snd_soc_card *card)
static int rt5660_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai,
@@ -132,7 +132,7 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_ops rt5660_ops = {
+static const struct snd_soc_ops rt5660_ops = {
.hw_params = rt5660_hw_params,
};
@@ -178,8 +178,6 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "SSP0-Codec",
.id = 0,
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &rt5660_ops,
SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform),
},
@@ -187,7 +185,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "dmic48k",
.id = 1,
.ignore_suspend = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
},
@@ -195,7 +193,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "dmic16k",
.id = 2,
.ignore_suspend = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform),
},
@@ -203,7 +201,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "iDisp1",
.id = 5,
.init = hdmi_init,
- .dpcm_playback = 1,
+ .playback_only = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
},
@@ -211,7 +209,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "iDisp2",
.id = 6,
.init = hdmi_init,
- .dpcm_playback = 1,
+ .playback_only = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
},
@@ -219,7 +217,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "iDisp3",
.id = 7,
.init = hdmi_init,
- .dpcm_playback = 1,
+ .playback_only = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
},
@@ -227,7 +225,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = {
.name = "iDisp4",
.id = 8,
.init = hdmi_init,
- .dpcm_playback = 1,
+ .playback_only = 1,
.no_pcm = 1,
SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform),
},
@@ -256,8 +254,7 @@ static void hdmi_link_init(struct snd_soc_card *card,
{
int i;
- if (mach->mach_params.common_hdmi_codec_drv &&
- (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) {
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) {
ctx->idisp_codec = true;
return;
}
@@ -267,7 +264,7 @@ static void hdmi_link_init(struct snd_soc_card *card,
* hdmi codec is not supported
*/
for (i = HDMI_LINK_START; i <= HDMI_LINE_END; i++)
- card->dai_link[i].codecs[0] = asoc_dummy_dlc;
+ card->dai_link[i].codecs[0] = snd_soc_dummy_dlc;
}
static int snd_ehl_rt5660_probe(struct platform_device *pdev)
@@ -316,4 +313,4 @@ module_platform_driver(snd_ehl_rt5660_driver);
MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver");
MODULE_AUTHOR("libin.yang@intel.com");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
deleted file mode 100644
index cf0f89db3e20..000000000000
--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c
+++ /dev/null
@@ -1,691 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2018 Intel Corporation.
-
-/*
- * Intel Geminilake I2S Machine Driver with MAX98357A & RT5682 Codecs
- *
- * Modified from:
- * Intel Apollolake I2S Machine driver
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/rt5682.h"
-#include "../../codecs/rt5682s.h"
-#include "../../codecs/hdac_hdmi.h"
-#include "hda_dsp_common.h"
-
-/* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */
-#define GLK_PLAT_CLK_FREQ 19200000
-#define RT5682_PLL_FREQ (48000 * 512)
-#define RT5682_DAI_NAME "rt5682-aif1"
-#define RT5682S_DAI_NAME "rt5682s-aif1"
-#define GLK_MAXIM_CODEC_DAI "HiFi"
-#define RT5682_DEV0_NAME "i2c-10EC5682:00"
-#define RT5682S_DEV0_NAME "i2c-RTL5682:00"
-#define MAXIM_DEV0_NAME "MX98357A:00"
-#define DUAL_CHANNEL 2
-#define QUAD_CHANNEL 4
-#define NAME_SIZE 32
-
-static struct snd_soc_jack geminilake_hdmi[3];
-
-struct glk_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct glk_card_private {
- struct snd_soc_jack geminilake_headset;
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
- int is_rt5682s;
-};
-
-enum {
- GLK_DPCM_AUDIO_PB = 0,
- GLK_DPCM_AUDIO_CP,
- GLK_DPCM_AUDIO_HS_PB,
- GLK_DPCM_AUDIO_ECHO_REF_CP,
- GLK_DPCM_AUDIO_REF_CP,
- GLK_DPCM_AUDIO_DMIC_CP,
- GLK_DPCM_AUDIO_HDMI1_PB,
- GLK_DPCM_AUDIO_HDMI2_PB,
- GLK_DPCM_AUDIO_HDMI3_PB,
-};
-
-static const struct snd_kcontrol_new geminilake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
-};
-
-static const struct snd_soc_dapm_widget geminilake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route geminilake_map[] = {
- /* HP jack connectors - unknown if we have jack detection */
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
-
- /* speaker */
- { "Spk", NULL, "Speaker" },
-
- /* other jacks */
- { "IN1P", NULL, "Headset Mic" },
-
- /* digital mics */
- { "DMic", NULL, "SoC DMIC" },
-
- /* CODEC BE connections */
- { "HiFi Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec0_out" },
-
- { "AIF1 Playback", NULL, "ssp2 Tx" },
- { "ssp2 Tx", NULL, "codec1_out" },
-
- { "codec0_in", NULL, "ssp2 Rx" },
- { "ssp2 Rx", NULL, "AIF1 Capture" },
-
- { "HDMI1", NULL, "hif5-0 Output" },
- { "HDMI2", NULL, "hif6-0 Output" },
- { "HDMI2", NULL, "hif7-0 Output" },
-
- { "hifi3", NULL, "iDisp3 Tx" },
- { "iDisp3 Tx", NULL, "iDisp3_out" },
- { "hifi2", NULL, "iDisp2 Tx" },
- { "iDisp2 Tx", NULL, "iDisp2_out" },
- { "hifi1", NULL, "iDisp1 Tx" },
- { "iDisp1 Tx", NULL, "iDisp1_out" },
-
- /* DMIC */
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-};
-
-static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = DUAL_CHANNEL;
-
- /* set SSP to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
-
- return 0;
-}
-
-static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_jack *jack;
- int pll_id, pll_source, clk_id, ret;
-
- if (ctx->is_rt5682s) {
- pll_id = RT5682S_PLL2;
- pll_source = RT5682S_PLL_S_MCLK;
- clk_id = RT5682S_SCLK_S_PLL2;
- } else {
- pll_id = RT5682_PLL1;
- pll_source = RT5682_PLL1_S_MCLK;
- clk_id = RT5682_SCLK_S_PLL1;
- }
-
- ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source,
- GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ);
- if (ret < 0) {
- dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
- return ret;
- }
-
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, clk_id,
- RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
- if (ret < 0)
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &ctx->geminilake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- jack = &ctx->geminilake_headset;
-
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
-
- ret = snd_soc_component_set_jack(component, jack, NULL);
-
- if (ret) {
- dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
- return ret;
- }
-
- return ret;
-};
-
-static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- /* Set valid bitmask & configuration for I2S in 24 bit */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 24);
- if (ret < 0) {
- dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
- return ret;
- }
-
- return ret;
-}
-
-static struct snd_soc_ops geminilake_rt5682_ops = {
- .hw_params = geminilake_rt5682_hw_params,
-};
-
-static int geminilake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct glk_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = GLK_DPCM_AUDIO_HDMI1_PB + dai->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int geminilake_rt5682_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
- struct snd_soc_dapm_context *dapm;
- int ret;
-
- dapm = snd_soc_component_get_dapm(component);
- ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
- if (ret) {
- dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static unsigned int channels_quad[] = {
- QUAD_CHANNEL,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
- .count = ARRAY_SIZE(channels_quad),
- .list = channels_quad,
- .mask = 0,
-};
-
-static int geminilake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /*
- * set BE channel constraint as user FE channels
- */
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static int geminilake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels_quad);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static const struct snd_soc_ops geminilake_dmic_ops = {
- .startup = geminilake_dmic_startup,
-};
-
-static const unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static int geminilake_refcap_startup(struct snd_pcm_substream *substream)
-{
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-};
-
-static const struct snd_soc_ops geminilake_refcap_ops = {
- .startup = geminilake_refcap_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(system2,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin2")));
-
-SND_SOC_DAILINK_DEF(echoref,
- DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME,
- GLK_MAXIM_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin")));
-SND_SOC_DAILINK_DEF(ssp2_codec_5682,
- DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME,
- RT5682_DAI_NAME)));
-SND_SOC_DAILINK_DEF(ssp2_codec_5682s,
- DAILINK_COMP_ARRAY(COMP_CODEC(RT5682S_DEV0_NAME,
- RT5682S_DAI_NAME)));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0")));
-
-/* geminilake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link geminilake_dais[] = {
- /* Front End DAI links */
- [GLK_DPCM_AUDIO_PB] = {
- .name = "Glk Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = geminilake_rt5682_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [GLK_DPCM_AUDIO_CP] = {
- .name = "Glk Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [GLK_DPCM_AUDIO_HS_PB] = {
- .name = "Glk Audio Headset Playback",
- .stream_name = "Headset Audio",
- .dpcm_playback = 1,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(system2, dummy, platform),
- },
- [GLK_DPCM_AUDIO_ECHO_REF_CP] = {
- .name = "Glk Audio Echo Reference cap",
- .stream_name = "Echoreference Capture",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(echoref, dummy, platform),
- },
- [GLK_DPCM_AUDIO_REF_CP] = {
- .name = "Glk Audio Reference cap",
- .stream_name = "Refcap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &geminilake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [GLK_DPCM_AUDIO_DMIC_CP] = {
- .name = "Glk Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &geminilake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [GLK_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Glk HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [GLK_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Glk HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [GLK_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Glk HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
- /* Back End DAI links */
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = geminilake_ssp_fixup,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- /* SSP2 - Codec */
- .name = "SSP2-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = geminilake_rt5682_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = geminilake_ssp_fixup,
- .ops = &geminilake_rt5682_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp2_pin, ssp2_codec_5682, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .ignore_suspend = 1,
- .be_hw_params_fixup = geminilake_dmic_fixup,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = geminilake_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = geminilake_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = geminilake_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-static int glk_card_late_probe(struct snd_soc_card *card)
-{
- struct glk_card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = NULL;
- char jack_name[NAME_SIZE];
- struct glk_hdmi_pcm *pcm;
- int err;
- int i = 0;
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct glk_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &geminilake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &geminilake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* geminilake audio machine driver for SPT + RT5682 */
-static struct snd_soc_card glk_audio_card_rt5682_m98357a = {
- .name = "glkrt5682max",
- .owner = THIS_MODULE,
- .dai_link = geminilake_dais,
- .num_links = ARRAY_SIZE(geminilake_dais),
- .controls = geminilake_controls,
- .num_controls = ARRAY_SIZE(geminilake_controls),
- .dapm_widgets = geminilake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(geminilake_widgets),
- .dapm_routes = geminilake_map,
- .num_dapm_routes = ARRAY_SIZE(geminilake_map),
- .fully_routed = true,
- .late_probe = glk_card_late_probe,
-};
-
-static int geminilake_audio_probe(struct platform_device *pdev)
-{
- struct glk_card_private *ctx;
- struct snd_soc_acpi_mach *mach;
- const char *platform_name;
- struct snd_soc_card *card;
- int ret, i;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- /* Detect the headset codec variant */
- if (acpi_dev_present("RTL5682", NULL, -1)) {
- /* ALC5682I-VS is detected */
- ctx->is_rt5682s = 1;
-
- for (i = 0; i < glk_audio_card_rt5682_m98357a.num_links; i++) {
- if (strcmp(geminilake_dais[i].name, "SSP2-Codec"))
- continue;
-
- /* update the dai link to use rt5682s codec */
- geminilake_dais[i].codecs = ssp2_codec_5682s;
- geminilake_dais[i].num_codecs = ARRAY_SIZE(ssp2_codec_5682s);
- break;
- }
- }
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- card = &glk_audio_card_rt5682_m98357a;
- card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(card, ctx);
-
- /* override platform name, if required */
- mach = pdev->dev.platform_data;
- platform_name = mach->mach_params.platform;
-
- ret = snd_soc_fixup_dai_links_platform_name(card, platform_name);
- if (ret)
- return ret;
-
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
- return devm_snd_soc_register_card(&pdev->dev, card);
-}
-
-static const struct platform_device_id glk_board_ids[] = {
- {
- .name = "glk_rt5682_mx98357a",
- .driver_data =
- (kernel_ulong_t)&glk_audio_card_rt5682_m98357a,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, glk_board_ids);
-
-static struct platform_driver geminilake_audio = {
- .probe = geminilake_audio_probe,
- .driver = {
- .name = "glk_rt5682_max98357a",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = glk_board_ids,
-};
-module_platform_driver(geminilake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mode");
-MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
-MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c
index 04b7d4f7f9e2..328ffff336a8 100644
--- a/sound/soc/intel/boards/hda_dsp_common.c
+++ b/sound/soc/intel/boards/hda_dsp_common.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2019 Intel Corporation. All rights reserved.
+// Copyright(c) 2019 Intel Corporation
#include <linux/module.h>
#include <sound/pcm.h>
@@ -15,7 +15,7 @@
/*
* Search card topology and return PCM device number
- * matching Nth HDMI device (zero-based index).
+ * matching Nth playback HDMI device (zero-based index).
*/
static struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card,
int hdmi_idx)
@@ -25,8 +25,17 @@ static struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card,
int i = 0;
for_each_card_rtds(card, rtd) {
- spcm = rtd->pcm ?
- rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].pcm : NULL;
+ /* ignore BE PCMs */
+ if (rtd->dai_link && rtd->dai_link->no_pcm)
+ continue;
+
+ spcm = rtd->pcm;
+
+ /* ignore PCMs with no playback streams */
+ if (!spcm || !spcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+ continue;
+
+ /* look for FE PCMs with name "HDMI x" */
if (spcm && strstr(spcm->id, "HDMI")) {
if (i == hdmi_idx)
return rtd->pcm;
@@ -83,7 +92,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card,
return err;
}
-EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, SND_SOC_INTEL_HDA_DSP_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, "SND_SOC_INTEL_HDA_DSP_COMMON");
#endif
diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c
index 050c53ebd6ba..9bb2822ba63e 100644
--- a/sound/soc/intel/boards/hsw_rt5640.c
+++ b/sound/soc/intel/boards/hsw_rt5640.c
@@ -2,7 +2,7 @@
/*
* Sound card driver for Intel Haswell Lynx Point with Realtek 5640
*
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ * Copyright (C) 2013, Intel Corporation
*/
#include <linux/module.h>
@@ -47,8 +47,8 @@ static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int codec_link_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, SND_SOC_CLOCK_IN);
@@ -85,8 +85,6 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(system, dummy, platform),
},
{
@@ -95,7 +93,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(offload0, dummy, platform),
},
{
@@ -104,7 +102,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(offload1, dummy, platform),
},
{
@@ -113,7 +111,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(loopback, dummy, platform),
},
/* Back End DAI links */
@@ -127,8 +125,6 @@ static struct snd_soc_dai_link card_dai_links[] = {
.ignore_pmdown_time = 1,
.be_hw_params_fixup = codec_link_hw_params_fixup,
.ops = &codec_link_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
},
};
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
deleted file mode 100644
index 18365ce6bcba..000000000000
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ /dev/null
@@ -1,680 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2017-18 Intel Corporation.
-
-/*
- * Intel Kabylake I2S Machine Driver with MAX98357A & DA7219 Codecs
- *
- * Modified from:
- * Intel Kabylake I2S Machine driver supporting MAXIM98927 and
- * RT5663 codecs
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "../../codecs/da7219.h"
-#include "../../codecs/hdac_hdmi.h"
-
-#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
-#define KBL_MAXIM_CODEC_DAI "HiFi"
-#define MAXIM_DEV0_NAME "MX98357A:00"
-#define DUAL_CHANNEL 2
-#define QUAD_CHANNEL 4
-
-static struct snd_soc_card *kabylake_audio_card;
-static struct snd_soc_jack skylake_hdmi[3];
-
-struct kbl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct kbl_codec_private {
- struct snd_soc_jack kabylake_headset;
- struct list_head hdmi_pcm_list;
-};
-
-enum {
- KBL_DPCM_AUDIO_PB = 0,
- KBL_DPCM_AUDIO_CP,
- KBL_DPCM_AUDIO_REF_CP,
- KBL_DPCM_AUDIO_DMIC_CP,
- KBL_DPCM_AUDIO_HDMI1_PB,
- KBL_DPCM_AUDIO_HDMI2_PB,
- KBL_DPCM_AUDIO_HDMI3_PB,
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct snd_soc_dai *codec_dai;
- int ret = 0;
-
- codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI);
- if (!codec_dai) {
- dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
- return -EIO;
- }
-
- if (SND_SOC_DAPM_EVENT_OFF(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- DA7219_SYSCLK_MCLK, 0, 0);
- if (ret)
- dev_err(card->dev, "failed to stop PLL: %d\n", ret);
- } else if (SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
- 0, DA7219_PLL_FREQ_OUT_98304);
- if (ret)
- dev_err(card->dev, "failed to start PLL: %d\n", ret);
- }
-
- return ret;
-}
-
-static const struct snd_kcontrol_new kabylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
-};
-
-static const struct snd_soc_dapm_widget kabylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route kabylake_map[] = {
- { "Headphone Jack", NULL, "HPL" },
- { "Headphone Jack", NULL, "HPR" },
-
- /* speaker */
- { "Spk", NULL, "Speaker" },
-
- /* other jacks */
- { "MIC", NULL, "Headset Mic" },
- { "DMic", NULL, "SoC DMIC" },
-
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI3", NULL, "hif7-0 Output"},
-
- /* CODEC BE connections */
- { "HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "codec0_out" },
-
- { "Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
-
- { "codec0_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "Capture" },
-
- /* DMIC */
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-
- { "hifi1", NULL, "iDisp1 Tx" },
- { "iDisp1 Tx", NULL, "iDisp1_out" },
- { "hifi2", NULL, "iDisp2 Tx" },
- { "iDisp2 Tx", NULL, "iDisp2_out" },
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-};
-
-static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = DUAL_CHANNEL;
-
- /* set SSP to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
-
- return 0;
-}
-
-static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_jack *jack;
- int ret;
-
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
- SND_SOC_CLOCK_IN);
- if (ret) {
- dev_err(rtd->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &ctx->kabylake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- jack = &ctx->kabylake_headset;
-
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
-
- ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
- if (ret)
- dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret);
-
- return ret;
-}
-
-static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = device;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
-}
-
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
-}
-
-static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
-}
-
-static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- DUAL_CHANNEL,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static unsigned int channels_quad[] = {
- QUAD_CHANNEL,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
- .count = ARRAY_SIZE(channels_quad),
- .list = channels_quad,
- .mask = 0,
-};
-
-static int kbl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = DUAL_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops kabylake_da7219_fe_ops = {
- .startup = kbl_fe_startup,
-};
-
-static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /*
- * set BE channel constraint as user FE channels
- */
-
- if (params_channels(params) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels_quad);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static struct snd_soc_ops kabylake_dmic_ops = {
- .startup = kabylake_dmic_startup,
-};
-
-static unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_refcap = {
- .count = ARRAY_SIZE(ch_mono),
- .list = ch_mono,
-};
-
-static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
-{
- substream->runtime->hw.channels_max = 1;
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_refcap);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-}
-
-static struct snd_soc_ops skylake_refcap_ops = {
- .startup = kabylake_refcap_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME,
- KBL_MAXIM_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00",
- KBL_DIALOG_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2",
- "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* kabylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link kabylake_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = kabylake_da7219_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_CP] = {
- .name = "Kbl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &kabylake_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_REF_CP] = {
- .name = "Kbl Audio Reference cap",
- .stream_name = "Wake on Voice",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [KBL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Kbl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &kabylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Kbl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = kabylake_da7219_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .be_hw_params_fixup = kabylake_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .dpcm_playback = 1,
- .init = kabylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = kabylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = kabylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-#define NAME_SIZE 32
-static int kabylake_card_late_probe(struct snd_soc_card *card)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
- struct kbl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &skylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &skylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
-
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* kabylake audio machine driver for SPT + DA7219 */
-static struct snd_soc_card kabylake_audio_card_da7219_m98357a = {
- .name = "kblda7219max",
- .owner = THIS_MODULE,
- .dai_link = kabylake_dais,
- .num_links = ARRAY_SIZE(kabylake_dais),
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static int kabylake_audio_probe(struct platform_device *pdev)
-{
- struct kbl_codec_private *ctx;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- kabylake_audio_card =
- (struct snd_soc_card *)pdev->id_entry->driver_data;
-
- kabylake_audio_card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
- return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
-}
-
-static const struct platform_device_id kbl_board_ids[] = {
- {
- .name = "kbl_da7219_mx98357a",
- .driver_data =
- (kernel_ulong_t)&kabylake_audio_card_da7219_m98357a,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, kbl_board_ids);
-
-static struct platform_driver kabylake_audio = {
- .probe = kabylake_audio_probe,
- .driver = {
- .name = "kbl_da7219_max98357a",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = kbl_board_ids,
-};
-
-module_platform_driver(kabylake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode");
-MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
deleted file mode 100644
index ad4223fee0c5..000000000000
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ /dev/null
@@ -1,1164 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2018 Intel Corporation.
-
-/*
- * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs
- *
- * Modified from:
- * Intel Kabylake I2S Machine driver supporting MAX98927 and
- * RT5663 codecs
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "../../codecs/da7219.h"
-#include "../../codecs/hdac_hdmi.h"
-
-#define KBL_DIALOG_CODEC_DAI "da7219-hifi"
-#define MAX98927_CODEC_DAI "max98927-aif1"
-#define MAX98927_DEV0_NAME "i2c-MX98927:00"
-#define MAX98927_DEV1_NAME "i2c-MX98927:01"
-
-#define MAX98373_CODEC_DAI "max98373-aif1"
-#define MAX98373_DEV0_NAME "i2c-MX98373:00"
-#define MAX98373_DEV1_NAME "i2c-MX98373:01"
-
-
-#define DUAL_CHANNEL 2
-#define QUAD_CHANNEL 4
-#define NAME_SIZE 32
-
-static struct snd_soc_card *kabylake_audio_card;
-static struct snd_soc_jack kabylake_hdmi[3];
-
-struct kbl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct kbl_codec_private {
- struct snd_soc_jack kabylake_headset;
- struct list_head hdmi_pcm_list;
-};
-
-enum {
- KBL_DPCM_AUDIO_PB = 0,
- KBL_DPCM_AUDIO_ECHO_REF_CP,
- KBL_DPCM_AUDIO_REF_CP,
- KBL_DPCM_AUDIO_DMIC_CP,
- KBL_DPCM_AUDIO_HDMI1_PB,
- KBL_DPCM_AUDIO_HDMI2_PB,
- KBL_DPCM_AUDIO_HDMI3_PB,
- KBL_DPCM_AUDIO_HS_PB,
- KBL_DPCM_AUDIO_CP,
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct snd_soc_dai *codec_dai;
- int ret = 0;
-
- codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI);
- if (!codec_dai) {
- dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
- return -EIO;
- }
-
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000,
- SND_SOC_CLOCK_IN);
- if (ret) {
- dev_err(card->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- if (SND_SOC_DAPM_EVENT_OFF(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- DA7219_SYSCLK_MCLK, 0, 0);
- if (ret)
- dev_err(card->dev, "failed to stop PLL: %d\n", ret);
- } else if (SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
- 0, DA7219_PLL_FREQ_OUT_98304);
- if (ret)
- dev_err(card->dev, "failed to start PLL: %d\n", ret);
- }
-
- return ret;
-}
-
-static const struct snd_kcontrol_new kabylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_soc_dapm_widget kabylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route kabylake_map[] = {
- /* speaker */
- { "Left Spk", NULL, "Left BE_OUT" },
- { "Right Spk", NULL, "Right BE_OUT" },
-
- /* other jacks */
- { "DMic", NULL, "SoC DMIC" },
-
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI3", NULL, "hif7-0 Output"},
-
- /* CODEC BE connections */
- { "Left HiFi Playback", NULL, "ssp0 Tx" },
- { "Right HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "spk_out" },
-
- /* IV feedback path */
- { "codec0_fb_in", NULL, "ssp0 Rx"},
- { "ssp0 Rx", NULL, "Left HiFi Capture" },
- { "ssp0 Rx", NULL, "Right HiFi Capture" },
-
- /* AEC capture path */
- { "echo_ref_out", NULL, "ssp0 Rx" },
-
- /* DMIC */
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-
- { "hifi1", NULL, "iDisp1 Tx" },
- { "iDisp1 Tx", NULL, "iDisp1_out" },
- { "hifi2", NULL, "iDisp2 Tx" },
- { "iDisp2 Tx", NULL, "iDisp2_out" },
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
-};
-
-static const struct snd_soc_dapm_route kabylake_ssp1_map[] = {
- { "Headphone Jack", NULL, "HPL" },
- { "Headphone Jack", NULL, "HPR" },
-
- /* other jacks */
- { "MIC", NULL, "Headset Mic" },
-
- /* CODEC BE connections */
- { "Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
-
- { "hs_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "Capture" },
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-};
-
-static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- int ret, j;
-
- for_each_rtd_codec_dais(runtime, j, codec_dai) {
-
- if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
- if (ret < 0) {
- dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
- if (ret < 0) {
- dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0x30, 3, 8, 16);
- if (ret < 0) {
- dev_err(runtime->dev,
- "DEV0 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai,
- 0xC0, 3, 8, 16);
- if (ret < 0) {
- dev_err(runtime->dev,
- "DEV1 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- int j, ret;
-
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- const char *name = codec_dai->component->name;
- struct snd_soc_component *component = codec_dai->component;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
- char pin_name[20];
-
- if (strcmp(name, MAX98927_DEV0_NAME) &&
- strcmp(name, MAX98927_DEV1_NAME) &&
- strcmp(name, MAX98373_DEV0_NAME) &&
- strcmp(name, MAX98373_DEV1_NAME))
- continue;
-
- snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
- codec_dai->component->name_prefix);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = snd_soc_dapm_enable_pin(dapm, pin_name);
- if (ret) {
- dev_err(rtd->dev, "failed to enable %s: %d\n",
- pin_name, ret);
- return ret;
- }
- snd_soc_dapm_sync(dapm);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = snd_soc_dapm_disable_pin(dapm, pin_name);
- if (ret) {
- dev_err(rtd->dev, "failed to disable %s: %d\n",
- pin_name, ret);
- return ret;
- }
- snd_soc_dapm_sync(dapm);
- break;
- }
- }
-
- return 0;
-}
-
-static struct snd_soc_ops kabylake_ssp0_ops = {
- .hw_params = kabylake_ssp0_hw_params,
- .trigger = kabylake_ssp0_trigger,
-};
-
-static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL;
-
- /*
- * The following loop will be called only for playback stream
- * In this platform, there is only one playback device on every SSP
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
- rtd_dpcm = dpcm;
- break;
- }
-
- /*
- * This following loop will be called only for capture stream
- * In this platform, there is only one capture device on every SSP
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
- rtd_dpcm = dpcm;
- break;
- }
-
- if (!rtd_dpcm)
- return -EINVAL;
-
- /*
- * The above 2 loops are mutually exclusive based on the stream direction,
- * thus rtd_dpcm variable will never be overwritten
- */
-
- /*
- * The ADSP will convert the FE rate to 48k, stereo, 24 bit
- */
- if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") ||
- !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") ||
- !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) {
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- }
-
- /*
- * The speaker on the SSP0 supports S16_LE and not S24_LE.
- * thus changing the mask here
- */
- if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec"))
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
-
- return 0;
-}
-
-static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_jack *jack;
- struct snd_soc_card *card = rtd->card;
- int ret;
-
-
- ret = snd_soc_dapm_add_routes(&card->dapm,
- kabylake_ssp1_map,
- ARRAY_SIZE(kabylake_ssp1_map));
-
- if (ret)
- return ret;
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
- &ctx->kabylake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- jack = &ctx->kabylake_headset;
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
-
- snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
-
- return 0;
-}
-
-static int kabylake_dmic_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
- if (ret)
- dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret);
-
- return ret;
-}
-
-static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = device;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
-}
-
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
-}
-
-static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
-}
-
-static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- DUAL_CHANNEL,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static unsigned int channels_quad[] = {
- QUAD_CHANNEL,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
- .count = ARRAY_SIZE(channels_quad),
- .list = channels_quad,
- .mask = 0,
-};
-
-static int kbl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = DUAL_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops kabylake_da7219_fe_ops = {
- .startup = kbl_fe_startup,
-};
-
-static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /*
- * set BE channel constraint as user FE channels
- */
-
- if (params_channels(params) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels_quad);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static struct snd_soc_ops kabylake_dmic_ops = {
- .startup = kabylake_dmic_startup,
-};
-
-static const unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-static const struct snd_pcm_hw_constraint_list constraints_refcap = {
- .count = ARRAY_SIZE(ch_mono),
- .list = ch_mono,
-};
-
-static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
-{
- substream->runtime->hw.channels_max = 1;
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_refcap);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-}
-
-
-static struct snd_soc_ops skylake_refcap_ops = {
- .startup = kabylake_refcap_startup,
-};
-
-static struct snd_soc_codec_conf max98927_codec_conf[] = {
-
- {
- .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME),
- .name_prefix = "Right",
- },
-
- {
- .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME),
- .name_prefix = "Left",
- },
-};
-
-static struct snd_soc_codec_conf max98373_codec_conf[] = {
-
- {
- .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME),
- .name_prefix = "Right",
- },
-
- {
- .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME),
- .name_prefix = "Left",
- },
-};
-
-static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = {
- { /* Left */
- .name = MAX98373_DEV0_NAME,
- .dai_name = MAX98373_CODEC_DAI,
- },
-
- { /* For Right */
- .name = MAX98373_DEV1_NAME,
- .dai_name = MAX98373_CODEC_DAI,
- },
-
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(echoref,
- DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(system2,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin2")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(
- /* Left */ COMP_CODEC(MAX98927_DEV0_NAME, MAX98927_CODEC_DAI),
- /* For Right */ COMP_CODEC(MAX98927_DEV1_NAME, MAX98927_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00",
- KBL_DIALOG_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* kabylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link kabylake_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = kabylake_da7219_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
- .name = "Kbl Audio Echo Reference cap",
- .stream_name = "Echoreference Capture",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- SND_SOC_DAILINK_REG(echoref, dummy, platform),
- },
- [KBL_DPCM_AUDIO_REF_CP] = {
- .name = "Kbl Audio Reference cap",
- .stream_name = "Wake on Voice",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [KBL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Kbl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &kabylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Kbl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HS_PB] = {
- .name = "Kbl Audio Headset Playback",
- .stream_name = "Headset Audio",
- .dpcm_playback = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .init = kabylake_da7219_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .ops = &kabylake_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_CP] = {
- .name = "Kbl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &kabylake_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .ops = &kabylake_ssp0_ops,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = kabylake_da7219_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .init = kabylake_dmic_init,
- .be_hw_params_fixup = kabylake_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .dpcm_playback = 1,
- .init = kabylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = kabylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = kabylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-/* kabylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = kabylake_da7219_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_da7219_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
- .name = "Kbl Audio Echo Reference cap",
- .stream_name = "Echoreference Capture",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- SND_SOC_DAILINK_REG(echoref, dummy, platform),
- },
- [KBL_DPCM_AUDIO_REF_CP] = {
- .name = "Kbl Audio Reference cap",
- .stream_name = "Wake on Voice",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [KBL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Kbl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &kabylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Kbl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .ops = &kabylake_ssp0_ops,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec),
- },
- {
- .name = "dmic01",
- .id = 1,
- .init = kabylake_dmic_init,
- .be_hw_params_fixup = kabylake_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 2,
- .dpcm_playback = 1,
- .init = kabylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 3,
- .init = kabylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 4,
- .init = kabylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-static int kabylake_card_late_probe(struct snd_soc_card *card)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
- struct kbl_hdmi_pcm *pcm;
- struct snd_soc_dapm_context *dapm = &card->dapm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &kabylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &kabylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- if (!component)
- return -EINVAL;
-
-
- err = hdac_hdmi_jack_port_init(component, &card->dapm);
-
- if (err < 0)
- return err;
-
- err = snd_soc_dapm_disable_pin(dapm, "Left Spk");
- if (err) {
- dev_err(card->dev, "failed to disable Left Spk: %d\n", err);
- return err;
- }
-
- err = snd_soc_dapm_disable_pin(dapm, "Right Spk");
- if (err) {
- dev_err(card->dev, "failed to disable Right Spk: %d\n", err);
- return err;
- }
-
- return snd_soc_dapm_sync(dapm);
-}
-
-/* kabylake audio machine driver for SPT + DA7219 */
-static struct snd_soc_card kbl_audio_card_da7219_m98927 = {
- .name = "kblda7219m98927",
- .owner = THIS_MODULE,
- .dai_link = kabylake_dais,
- .num_links = ARRAY_SIZE(kabylake_dais),
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .codec_conf = max98927_codec_conf,
- .num_configs = ARRAY_SIZE(max98927_codec_conf),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-/* kabylake audio machine driver for Maxim98927 */
-static struct snd_soc_card kbl_audio_card_max98927 = {
- .name = "kblmax98927",
- .owner = THIS_MODULE,
- .dai_link = kabylake_max98_927_373_dais,
- .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais),
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .codec_conf = max98927_codec_conf,
- .num_configs = ARRAY_SIZE(max98927_codec_conf),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static struct snd_soc_card kbl_audio_card_da7219_m98373 = {
- .name = "kblda7219m98373",
- .owner = THIS_MODULE,
- .dai_link = kabylake_dais,
- .num_links = ARRAY_SIZE(kabylake_dais),
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .codec_conf = max98373_codec_conf,
- .num_configs = ARRAY_SIZE(max98373_codec_conf),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static struct snd_soc_card kbl_audio_card_max98373 = {
- .name = "kblmax98373",
- .owner = THIS_MODULE,
- .dai_link = kabylake_max98_927_373_dais,
- .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais),
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .codec_conf = max98373_codec_conf,
- .num_configs = ARRAY_SIZE(max98373_codec_conf),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static int kabylake_audio_probe(struct platform_device *pdev)
-{
- struct kbl_codec_private *ctx;
- struct snd_soc_dai_link *kbl_dai_link;
- struct snd_soc_dai_link_component **codecs;
- int i;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- kabylake_audio_card =
- (struct snd_soc_card *)pdev->id_entry->driver_data;
-
- kbl_dai_link = kabylake_audio_card->dai_link;
-
- /* Update codecs for SSP0 with max98373 codec info */
- if (!strcmp(pdev->name, "kbl_da7219_max98373") ||
- (!strcmp(pdev->name, "kbl_max98373"))) {
- for (i = 0; i < kabylake_audio_card->num_links; ++i) {
- if (strcmp(kbl_dai_link[i].name, "SSP0-Codec"))
- continue;
-
- codecs = &(kbl_dai_link[i].codecs);
- *codecs = max98373_ssp0_codec_components;
- kbl_dai_link[i].num_codecs =
- ARRAY_SIZE(max98373_ssp0_codec_components);
- break;
- }
- }
- kabylake_audio_card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
-
- return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
-}
-
-static const struct platform_device_id kbl_board_ids[] = {
- {
- .name = "kbl_da7219_max98927",
- .driver_data =
- (kernel_ulong_t)&kbl_audio_card_da7219_m98927,
- },
- {
- .name = "kbl_max98927",
- .driver_data =
- (kernel_ulong_t)&kbl_audio_card_max98927,
- },
- {
- .name = "kbl_da7219_max98373",
- .driver_data =
- (kernel_ulong_t)&kbl_audio_card_da7219_m98373,
- },
- {
- .name = "kbl_max98373",
- .driver_data =
- (kernel_ulong_t)&kbl_audio_card_max98373,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, kbl_board_ids);
-
-static struct platform_driver kabylake_audio = {
- .probe = kabylake_audio_probe,
- .driver = {
- .name = "kbl_da7219_max98_927_373",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = kbl_board_ids,
-};
-
-module_platform_driver(kabylake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219");
-MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
deleted file mode 100644
index 2c7a547f63c9..000000000000
--- a/sound/soc/intel/boards/kbl_rt5660.c
+++ /dev/null
@@ -1,566 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2018-19 Canonical Corporation.
-
-/*
- * Intel Kabylake I2S Machine Driver with RT5660 Codec
- *
- * Modified from:
- * Intel Kabylake I2S Machine driver supporting MAXIM98357a and
- * DA7219 codecs
- * Also referred to:
- * Intel Broadwell I2S Machine driver supporting RT5677 codec
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/acpi.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "../../codecs/hdac_hdmi.h"
-#include "../../codecs/rt5660.h"
-
-#define KBL_RT5660_CODEC_DAI "rt5660-aif1"
-#define DUAL_CHANNEL 2
-
-static struct snd_soc_card *kabylake_audio_card;
-static struct snd_soc_jack skylake_hdmi[3];
-static struct snd_soc_jack lineout_jack;
-static struct snd_soc_jack mic_jack;
-
-struct kbl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct kbl_codec_private {
- struct gpio_desc *gpio_lo_mute;
- struct list_head hdmi_pcm_list;
-};
-
-enum {
- KBL_DPCM_AUDIO_PB = 0,
- KBL_DPCM_AUDIO_CP,
- KBL_DPCM_AUDIO_HDMI1_PB,
- KBL_DPCM_AUDIO_HDMI2_PB,
- KBL_DPCM_AUDIO_HDMI3_PB,
-};
-
-#define GPIO_LINEOUT_MUTE_INDEX 0
-#define GPIO_LINEOUT_DET_INDEX 3
-#define GPIO_LINEIN_DET_INDEX 4
-
-static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true };
-static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false };
-static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false };
-
-
-static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = {
- { "lineout-mute-gpios", &lineout_mute_gpio, 1 },
- { "lineout-det-gpios", &lineout_det_gpio, 1 },
- { "mic-det-gpios", &mic_det_gpio, 1 },
- { NULL },
-};
-
-static struct snd_soc_jack_pin lineout_jack_pin = {
- .pin = "Line Out",
- .mask = SND_JACK_LINEOUT,
-};
-
-static struct snd_soc_jack_pin mic_jack_pin = {
- .pin = "Line In",
- .mask = SND_JACK_MICROPHONE,
-};
-
-static struct snd_soc_jack_gpio lineout_jack_gpio = {
- .name = "lineout-det",
- .report = SND_JACK_LINEOUT,
- .debounce_time = 200,
-};
-
-static struct snd_soc_jack_gpio mic_jack_gpio = {
- .name = "mic-det",
- .report = SND_JACK_MICROPHONE,
- .debounce_time = 200,
-};
-
-static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card);
-
- gpiod_set_value_cansleep(priv->gpio_lo_mute,
- !(SND_SOC_DAPM_EVENT_ON(event)));
-
- return 0;
-}
-
-static const struct snd_kcontrol_new kabylake_rt5660_controls[] = {
- SOC_DAPM_PIN_SWITCH("Line In"),
- SOC_DAPM_PIN_SWITCH("Line Out"),
-};
-
-static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = {
- SND_SOC_DAPM_MIC("Line In", NULL),
- SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout),
-};
-
-static const struct snd_soc_dapm_route kabylake_rt5660_map[] = {
- /* other jacks */
- {"IN1P", NULL, "Line In"},
- {"IN2P", NULL, "Line In"},
- {"Line Out", NULL, "LOUTR"},
- {"Line Out", NULL, "LOUTL"},
-
- /* CODEC BE connections */
- { "AIF1 Playback", NULL, "ssp0 Tx"},
- { "ssp0 Tx", NULL, "codec0_out"},
-
- { "codec0_in", NULL, "ssp0 Rx" },
- { "ssp0 Rx", NULL, "AIF1 Capture" },
-
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
-};
-
-static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = DUAL_CHANNEL;
-
- /* set SSP0 to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
-
- return 0;
-}
-
-static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
-
- ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios);
- if (ret)
- dev_warn(component->dev, "Failed to add driver gpios\n");
-
- /* Request rt5660 GPIO for lineout mute control, return if fails */
- ctx->gpio_lo_mute = gpiod_get(component->dev, "lineout-mute",
- GPIOD_OUT_HIGH);
- if (IS_ERR(ctx->gpio_lo_mute)) {
- dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n");
- return PTR_ERR(ctx->gpio_lo_mute);
- }
-
- /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */
- ret = snd_soc_card_jack_new_pins(rtd->card, "Lineout Jack",
- SND_JACK_LINEOUT, &lineout_jack,
- &lineout_jack_pin, 1);
- if (ret)
- dev_warn(component->dev, "Can't create Lineout jack\n");
- else {
- lineout_jack_gpio.gpiod_dev = component->dev;
- ret = snd_soc_jack_add_gpios(&lineout_jack, 1,
- &lineout_jack_gpio);
- if (ret)
- dev_warn(component->dev, "Can't add Lineout jack gpio\n");
- }
-
- /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */
- ret = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",
- SND_JACK_MICROPHONE, &mic_jack,
- &mic_jack_pin, 1);
- if (ret)
- dev_warn(component->dev, "Can't create mic jack\n");
- else {
- mic_jack_gpio.gpiod_dev = component->dev;
- ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio);
- if (ret)
- dev_warn(component->dev, "Can't add mic jack gpio\n");
- }
-
- /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */
- snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
- snd_soc_dapm_force_enable_pin(dapm, "BST1");
- snd_soc_dapm_force_enable_pin(dapm, "BST2");
-
- return 0;
-}
-
-static void kabylake_rt5660_codec_exit(struct snd_soc_pcm_runtime *rtd)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
-
- /*
- * The .exit() can be reached without going through the .init()
- * so explicitly test if the gpiod is valid
- */
- if (!IS_ERR_OR_NULL(ctx->gpio_lo_mute))
- gpiod_put(ctx->gpio_lo_mute);
-}
-
-static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = device;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
-}
-
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
-}
-
-static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
-}
-
-static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT5660_SCLK_S_PLL1, params_rate(params) * 512,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- RT5660_PLL1_S_BCLK,
- params_rate(params) * 50,
- params_rate(params) * 512);
- if (ret < 0)
- dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
-
- return ret;
-}
-
-static struct snd_soc_ops kabylake_rt5660_ops = {
- .hw_params = kabylake_rt5660_hw_params,
-};
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- DUAL_CHANNEL,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int kbl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = DUAL_CHANNEL;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops kabylake_rt5660_fe_ops = {
- .startup = kbl_fe_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC3277:00", KBL_RT5660_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */
-static struct snd_soc_dai_link kabylake_rt5660_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_rt5660_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_CP] = {
- .name = "Kbl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &kabylake_rt5660_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Kbl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .init = kabylake_rt5660_codec_init,
- .exit = kabylake_rt5660_codec_exit,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp0_fixup,
- .ops = &kabylake_rt5660_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 1,
- .dpcm_playback = 1,
- .init = kabylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 2,
- .init = kabylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 3,
- .init = kabylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-
-#define NAME_SIZE 32
-static int kabylake_card_late_probe(struct snd_soc_card *card)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
- struct kbl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &skylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &skylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
-
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* kabylake audio machine driver for rt5660 */
-static struct snd_soc_card kabylake_audio_card_rt5660 = {
- .name = "kblrt5660",
- .owner = THIS_MODULE,
- .dai_link = kabylake_rt5660_dais,
- .num_links = ARRAY_SIZE(kabylake_rt5660_dais),
- .controls = kabylake_rt5660_controls,
- .num_controls = ARRAY_SIZE(kabylake_rt5660_controls),
- .dapm_widgets = kabylake_rt5660_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets),
- .dapm_routes = kabylake_rt5660_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static int kabylake_audio_probe(struct platform_device *pdev)
-{
- struct kbl_codec_private *ctx;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- kabylake_audio_card =
- (struct snd_soc_card *)pdev->id_entry->driver_data;
-
- kabylake_audio_card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
- return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
-}
-
-static const struct platform_device_id kbl_board_ids[] = {
- {
- .name = "kbl_rt5660",
- .driver_data =
- (kernel_ulong_t)&kabylake_audio_card_rt5660,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, kbl_board_ids);
-
-static struct platform_driver kabylake_audio = {
- .probe = kabylake_audio_probe,
- .driver = {
- .name = "kbl_rt5660",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = kbl_board_ids,
-};
-
-module_platform_driver(kabylake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode");
-MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
deleted file mode 100644
index 2d4224c5b152..000000000000
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Kabylake I2S Machine Driver with MAXIM98927
- * and RT5663 Codecs
- *
- * Copyright (C) 2017, Intel Corporation. All rights reserved.
- *
- * Modified from:
- * Intel Skylake I2S Machine driver
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/rt5663.h"
-#include "../../codecs/hdac_hdmi.h"
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-
-#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
-#define KBL_MAXIM_CODEC_DAI "max98927-aif1"
-#define DMIC_CH(p) p->list[p->count-1]
-#define MAXIM_DEV0_NAME "i2c-MX98927:00"
-#define MAXIM_DEV1_NAME "i2c-MX98927:01"
-
-static struct snd_soc_card *kabylake_audio_card;
-static const struct snd_pcm_hw_constraint_list *dmic_constraints;
-static struct snd_soc_jack skylake_hdmi[3];
-
-struct kbl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct kbl_rt5663_private {
- struct snd_soc_jack kabylake_headset;
- struct list_head hdmi_pcm_list;
- struct clk *mclk;
- struct clk *sclk;
-};
-
-enum {
- KBL_DPCM_AUDIO_PB = 0,
- KBL_DPCM_AUDIO_CP,
- KBL_DPCM_AUDIO_HS_PB,
- KBL_DPCM_AUDIO_ECHO_REF_CP,
- KBL_DPCM_AUDIO_REF_CP,
- KBL_DPCM_AUDIO_DMIC_CP,
- KBL_DPCM_AUDIO_HDMI1_PB,
- KBL_DPCM_AUDIO_HDMI2_PB,
- KBL_DPCM_AUDIO_HDMI3_PB,
-};
-
-static const struct snd_kcontrol_new kabylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct kbl_rt5663_private *priv = snd_soc_card_get_drvdata(card);
- int ret = 0;
-
- /*
- * MCLK/SCLK need to be ON early for a successful synchronization of
- * codec internal clock. And the clocks are turned off during
- * POST_PMD after the stream is stopped.
- */
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- /* Enable MCLK */
- ret = clk_set_rate(priv->mclk, 24000000);
- if (ret < 0) {
- dev_err(card->dev, "Can't set rate for mclk, err: %d\n",
- ret);
- return ret;
- }
-
- ret = clk_prepare_enable(priv->mclk);
- if (ret < 0) {
- dev_err(card->dev, "Can't enable mclk, err: %d\n", ret);
- return ret;
- }
-
- /* Enable SCLK */
- ret = clk_set_rate(priv->sclk, 3072000);
- if (ret < 0) {
- dev_err(card->dev, "Can't set rate for sclk, err: %d\n",
- ret);
- clk_disable_unprepare(priv->mclk);
- return ret;
- }
-
- ret = clk_prepare_enable(priv->sclk);
- if (ret < 0) {
- dev_err(card->dev, "Can't enable sclk, err: %d\n", ret);
- clk_disable_unprepare(priv->mclk);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- clk_disable_unprepare(priv->mclk);
- clk_disable_unprepare(priv->sclk);
- break;
- default:
- return 0;
- }
-
- return 0;
-}
-
-static const struct snd_soc_dapm_widget kabylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-};
-
-static const struct snd_soc_dapm_route kabylake_map[] = {
- /* HP jack connectors - unknown if we have jack detection */
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
-
- /* speaker */
- { "Left Spk", NULL, "Left BE_OUT" },
- { "Right Spk", NULL, "Right BE_OUT" },
-
- /* other jacks */
- { "Headset Mic", NULL, "Platform Clock" },
- { "IN1P", NULL, "Headset Mic" },
- { "IN1N", NULL, "Headset Mic" },
- { "DMic", NULL, "SoC DMIC" },
-
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI3", NULL, "hif7-0 Output"},
-
- /* CODEC BE connections */
- { "Left HiFi Playback", NULL, "ssp0 Tx" },
- { "Right HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "spk_out" },
-
- { "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
-
- { "hs_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "AIF Capture" },
-
- /* IV feedback path */
- { "codec0_fb_in", NULL, "ssp0 Rx"},
- { "ssp0 Rx", NULL, "Left HiFi Capture" },
- { "ssp0 Rx", NULL, "Right HiFi Capture" },
-
- /* DMIC */
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-};
-
-enum {
- KBL_DPCM_AUDIO_5663_PB = 0,
- KBL_DPCM_AUDIO_5663_CP,
- KBL_DPCM_AUDIO_5663_HDMI1_PB,
- KBL_DPCM_AUDIO_5663_HDMI2_PB,
-};
-
-static const struct snd_kcontrol_new kabylake_5663_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
-};
-
-static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route kabylake_5663_map[] = {
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
-
- /* other jacks */
- { "Headset Mic", NULL, "Platform Clock" },
- { "IN1P", NULL, "Headset Mic" },
- { "IN1N", NULL, "Headset Mic" },
-
- {"HDMI1", NULL, "hif5-0 Output"},
- {"HDMI2", NULL, "hif6-0 Output"},
- {"HDMI3", NULL, "hif7-0 Output"},
-
- /* CODEC BE connections */
- { "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
-
- { "codec0_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "AIF Capture" },
-
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-};
-
-static struct snd_soc_codec_conf max98927_codec_conf[] = {
- {
- .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
- .name_prefix = "Right",
- },
- {
- .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
- .name_prefix = "Left",
- },
-};
-
-static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
- if (ret) {
- dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-
-static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_jack *jack;
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &ctx->kabylake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
- return ret;
- }
-
- jack = &ctx->kabylake_headset;
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
-
- snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
-
- return ret;
-}
-
-static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
-
- ret = kabylake_rt5663_codec_init(rtd);
- if (ret)
- return ret;
-
- ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
- if (ret) {
- dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-
-static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
-{
- struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = device;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
-}
-
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
-}
-
-static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
-}
-
-static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB);
-}
-
-static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB);
-}
-
-static unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int kbl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = 2;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
- .startup = kbl_fe_startup,
-};
-
-static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL;
-
- /*
- * The following loop will be called only for playback stream
- * In this platform, there is only one playback device on every SSP
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
- rtd_dpcm = dpcm;
- break;
- }
-
- /*
- * This following loop will be called only for capture stream
- * In this platform, there is only one capture device on every SSP
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
- rtd_dpcm = dpcm;
- break;
- }
-
- if (!rtd_dpcm)
- return -EINVAL;
-
- /*
- * The above 2 loops are mutually exclusive based on the stream direction,
- * thus rtd_dpcm variable will never be overwritten
- */
-
- /*
- * The ADSP will convert the FE rate to 48k, stereo, 24 bit
- */
- if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") ||
- !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") ||
- !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) {
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- }
- /*
- * The speaker on the SSP0 supports S16_LE and not S24_LE.
- * thus changing the mask here
- */
- if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec"))
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
-
- return 0;
-}
-
-static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
- rt5663_sel_asrc_clk_src(codec_dai->component,
- RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
- RT5663_CLK_SEL_I2S1_ASRC);
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
-
- return ret;
-}
-
-static struct snd_soc_ops kabylake_rt5663_ops = {
- .hw_params = kabylake_rt5663_hw_params,
-};
-
-static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- int ret = 0, j;
-
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
- /*
- * Use channel 4 and 5 for the first amp
- */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
- if (ret < 0) {
- dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
- return ret;
- }
- }
- if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
- /*
- * Use channel 6 and 7 for the second amp
- */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
- if (ret < 0) {
- dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
- return ret;
- }
- }
- }
- return ret;
-}
-
-static struct snd_soc_ops kabylake_ssp0_ops = {
- .hw_params = kabylake_ssp0_hw_params,
-};
-
-static unsigned int channels_dmic[] = {
- 2, 4,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
- .count = ARRAY_SIZE(channels_dmic),
- .list = channels_dmic,
- .mask = 0,
-};
-
-static const unsigned int dmic_2ch[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
- .count = ARRAY_SIZE(dmic_2ch),
- .list = dmic_2ch,
- .mask = 0,
-};
-
-static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_max = DMIC_CH(dmic_constraints);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- dmic_constraints);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static struct snd_soc_ops kabylake_dmic_ops = {
- .startup = kabylake_dmic_startup,
-};
-
-static unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_refcap = {
- .count = ARRAY_SIZE(ch_mono),
- .list = ch_mono,
-};
-
-static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
-{
- substream->runtime->hw.channels_max = 1;
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_refcap);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-}
-
-static struct snd_soc_ops skylake_refcap_ops = {
- .startup = kabylake_refcap_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(system2,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin2")));
-
-SND_SOC_DAILINK_DEF(echoref,
- DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(
- /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI),
- /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5663:00",
- KBL_REALTEK_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(dmic01_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* kabylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link kabylake_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = kabylake_rt5663_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_rt5663_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_CP] = {
- .name = "Kbl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &kabylake_rt5663_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HS_PB] = {
- .name = "Kbl Audio Headset Playback",
- .stream_name = "Headset Audio",
- .dpcm_playback = 1,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(system2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
- .name = "Kbl Audio Echo Reference cap",
- .stream_name = "Echoreference Capture",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- SND_SOC_DAILINK_REG(echoref, dummy, platform),
- },
- [KBL_DPCM_AUDIO_REF_CP] = {
- .name = "Kbl Audio Reference cap",
- .stream_name = "Wake on Voice",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [KBL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Kbl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &kabylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Kbl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .dpcm_playback = 1,
- .ops = &kabylake_ssp0_ops,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = kabylake_rt5663_max98927_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .ops = &kabylake_rt5663_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .be_hw_params_fixup = kabylake_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .dpcm_playback = 1,
- .init = kabylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = kabylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = kabylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-static struct snd_soc_dai_link kabylake_5663_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_5663_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_rt5663_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_5663_CP] = {
- .name = "Kbl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &kabylake_rt5663_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_5663_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_5663_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 0,
- .no_pcm = 1,
- .init = kabylake_rt5663_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .ops = &kabylake_rt5663_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 1,
- .dpcm_playback = 1,
- .init = kabylake_5663_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 2,
- .init = kabylake_5663_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
-};
-
-#define NAME_SIZE 32
-static int kabylake_card_late_probe(struct snd_soc_card *card)
-{
- struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
- struct kbl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &skylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &skylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* kabylake audio machine driver for SPT + RT5663 */
-static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
- .name = "kblrt5663max",
- .owner = THIS_MODULE,
- .dai_link = kabylake_dais,
- .num_links = ARRAY_SIZE(kabylake_dais),
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .codec_conf = max98927_codec_conf,
- .num_configs = ARRAY_SIZE(max98927_codec_conf),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-/* kabylake audio machine driver for RT5663 */
-static struct snd_soc_card kabylake_audio_card_rt5663 = {
- .name = "kblrt5663",
- .owner = THIS_MODULE,
- .dai_link = kabylake_5663_dais,
- .num_links = ARRAY_SIZE(kabylake_5663_dais),
- .controls = kabylake_5663_controls,
- .num_controls = ARRAY_SIZE(kabylake_5663_controls),
- .dapm_widgets = kabylake_5663_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets),
- .dapm_routes = kabylake_5663_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static int kabylake_audio_probe(struct platform_device *pdev)
-{
- struct kbl_rt5663_private *ctx;
- struct snd_soc_acpi_mach *mach;
- int ret;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- kabylake_audio_card =
- (struct snd_soc_card *)pdev->id_entry->driver_data;
-
- kabylake_audio_card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
-
- mach = pdev->dev.platform_data;
- if (mach)
- dmic_constraints = mach->mach_params.dmic_num == 2 ?
- &constraints_dmic_2ch : &constraints_dmic_channels;
-
- ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
- if (IS_ERR(ctx->mclk)) {
- ret = PTR_ERR(ctx->mclk);
- if (ret == -ENOENT) {
- dev_info(&pdev->dev,
- "Failed to get ssp1_sclk, defer probe\n");
- return -EPROBE_DEFER;
- }
-
- dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n",
- ret);
- return ret;
- }
-
- ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk");
- if (IS_ERR(ctx->sclk)) {
- ret = PTR_ERR(ctx->sclk);
- if (ret == -ENOENT) {
- dev_info(&pdev->dev,
- "Failed to get ssp1_sclk, defer probe\n");
- return -EPROBE_DEFER;
- }
-
- dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n",
- ret);
- return ret;
- }
-
- return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
-}
-
-static const struct platform_device_id kbl_board_ids[] = {
- {
- .name = "kbl_rt5663",
- .driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663,
- },
- {
- .name = "kbl_rt5663_m98927",
- .driver_data =
- (kernel_ulong_t)&kabylake_audio_card_rt5663_m98927,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, kbl_board_ids);
-
-static struct platform_driver kabylake_audio = {
- .probe = kabylake_audio_probe,
- .driver = {
- .name = "kbl_rt5663_m98927",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = kbl_board_ids,
-};
-
-module_platform_driver(kabylake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
-MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
-MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
deleted file mode 100644
index 2c79fca57b19..000000000000
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ /dev/null
@@ -1,868 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Kabylake I2S Machine Driver with MAXIM98927
- * RT5514 and RT5663 Codecs
- *
- * Copyright (C) 2017, Intel Corporation. All rights reserved.
- *
- * Modified from:
- * Intel Kabylake I2S Machine driver supporting MAXIM98927 and
- * RT5663 codecs
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/rt5514.h"
-#include "../../codecs/rt5663.h"
-#include "../../codecs/hdac_hdmi.h"
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-
-#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
-#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
-#define KBL_MAXIM_CODEC_DAI "max98927-aif1"
-#define MAXIM_DEV0_NAME "i2c-MX98927:00"
-#define MAXIM_DEV1_NAME "i2c-MX98927:01"
-#define RT5514_DEV_NAME "i2c-10EC5514:00"
-#define RT5663_DEV_NAME "i2c-10EC5663:00"
-#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16)
-#define RT5514_AIF1_SYSCLK_FREQ 12288000
-#define NAME_SIZE 32
-
-#define DMIC_CH(p) p->list[p->count-1]
-
-
-static struct snd_soc_card kabylake_audio_card;
-static const struct snd_pcm_hw_constraint_list *dmic_constraints;
-
-struct kbl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct kbl_codec_private {
- struct snd_soc_jack kabylake_headset;
- struct list_head hdmi_pcm_list;
- struct snd_soc_jack kabylake_hdmi[2];
- struct clk *mclk;
- struct clk *sclk;
-};
-
-enum {
- KBL_DPCM_AUDIO_PB = 0,
- KBL_DPCM_AUDIO_CP,
- KBL_DPCM_AUDIO_HS_PB,
- KBL_DPCM_AUDIO_ECHO_REF_CP,
- KBL_DPCM_AUDIO_DMIC_CP,
- KBL_DPCM_AUDIO_RT5514_DSP,
- KBL_DPCM_AUDIO_HDMI1_PB,
- KBL_DPCM_AUDIO_HDMI2_PB,
-};
-
-static const struct snd_kcontrol_new kabylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
- SOC_DAPM_PIN_SWITCH("DMIC"),
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card);
- int ret = 0;
-
- /*
- * MCLK/SCLK need to be ON early for a successful synchronization of
- * codec internal clock. And the clocks are turned off during
- * POST_PMD after the stream is stopped.
- */
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- /* Enable MCLK */
- ret = clk_set_rate(priv->mclk, 24000000);
- if (ret < 0) {
- dev_err(card->dev, "Can't set rate for mclk, err: %d\n",
- ret);
- return ret;
- }
-
- ret = clk_prepare_enable(priv->mclk);
- if (ret < 0) {
- dev_err(card->dev, "Can't enable mclk, err: %d\n", ret);
- return ret;
- }
-
- /* Enable SCLK */
- ret = clk_set_rate(priv->sclk, 3072000);
- if (ret < 0) {
- dev_err(card->dev, "Can't set rate for sclk, err: %d\n",
- ret);
- clk_disable_unprepare(priv->mclk);
- return ret;
- }
-
- ret = clk_prepare_enable(priv->sclk);
- if (ret < 0) {
- dev_err(card->dev, "Can't enable sclk, err: %d\n", ret);
- clk_disable_unprepare(priv->mclk);
- }
- break;
- case SND_SOC_DAPM_POST_PMD:
- clk_disable_unprepare(priv->mclk);
- clk_disable_unprepare(priv->sclk);
- break;
- default:
- return 0;
- }
-
- return 0;
-}
-
-static const struct snd_soc_dapm_widget kabylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
- SND_SOC_DAPM_MIC("DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route kabylake_map[] = {
- /* Headphones */
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
-
- /* speaker */
- { "Left Spk", NULL, "Left BE_OUT" },
- { "Right Spk", NULL, "Right BE_OUT" },
-
- /* other jacks */
- { "Headset Mic", NULL, "Platform Clock" },
- { "IN1P", NULL, "Headset Mic" },
- { "IN1N", NULL, "Headset Mic" },
-
- /* CODEC BE connections */
- { "Left HiFi Playback", NULL, "ssp0 Tx" },
- { "Right HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "spk_out" },
-
- { "AIF Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
-
- { "hs_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "AIF Capture" },
-
- { "codec1_in", NULL, "ssp0 Rx" },
- { "ssp0 Rx", NULL, "AIF1 Capture" },
-
- /* IV feedback path */
- { "codec0_fb_in", NULL, "ssp0 Rx"},
- { "ssp0 Rx", NULL, "Left HiFi Capture" },
- { "ssp0 Rx", NULL, "Right HiFi Capture" },
-
- /* DMIC */
- { "DMIC1L", NULL, "DMIC" },
- { "DMIC1R", NULL, "DMIC" },
- { "DMIC2L", NULL, "DMIC" },
- { "DMIC2R", NULL, "DMIC" },
-
- { "hifi2", NULL, "iDisp2 Tx" },
- { "iDisp2 Tx", NULL, "iDisp2_out" },
- { "hifi1", NULL, "iDisp1 Tx" },
- { "iDisp1 Tx", NULL, "iDisp1_out" },
-};
-
-static struct snd_soc_codec_conf max98927_codec_conf[] = {
- {
- .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
- .name_prefix = "Right",
- },
- {
- .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
- .name_prefix = "Left",
- },
-};
-
-
-static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
- int ret;
-
- dapm = snd_soc_component_get_dapm(component);
- ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
- if (ret)
- dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret);
-
- return ret;
-}
-
-static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_jack *jack;
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &ctx->kabylake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
- return ret;
- }
-
- jack = &ctx->kabylake_headset;
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
-
- snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL);
-
- ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
- if (ret)
- dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret);
-
- return ret;
-}
-
-static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct kbl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = device;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
-}
-
-static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int kbl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = 2;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
- .startup = kbl_fe_startup,
-};
-
-static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL;
-
- /*
- * The following loop will be called only for playback stream
- * In this platform, there is only one playback device on every SSP
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
- rtd_dpcm = dpcm;
- break;
- }
-
- /*
- * This following loop will be called only for capture stream
- * In this platform, there is only one capture device on every SSP
- */
- for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
- rtd_dpcm = dpcm;
- break;
- }
-
- if (!rtd_dpcm)
- return -EINVAL;
-
- /*
- * The above 2 loops are mutually exclusive based on the stream direction,
- * thus rtd_dpcm variable will never be overwritten
- */
-
- /*
- * The ADSP will convert the FE rate to 48k, stereo, 24 bit
- */
- if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") ||
- !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") ||
- !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) {
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- } else if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio DMIC cap")) {
- if (params_channels(params) == 2 ||
- DMIC_CH(dmic_constraints) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
- }
- /*
- * The speaker on the SSP0 supports S16_LE and not S24_LE.
- * thus changing the mask here
- */
- if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec"))
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
-
- return 0;
-}
-
-static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
- rt5663_sel_asrc_clk_src(codec_dai->component,
- RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
- RT5663_CLK_SEL_I2S1_ASRC);
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
-
- return ret;
-}
-
-static struct snd_soc_ops kabylake_rt5663_ops = {
- .hw_params = kabylake_rt5663_hw_params,
-};
-
-static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- int ret = 0, j;
-
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16);
- if (ret < 0) {
- dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(rtd->dev, "set sysclk err: %d\n", ret);
- return ret;
- }
- }
- if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
- if (ret < 0) {
- dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret);
- return ret;
- }
- }
-
- if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
- if (ret < 0) {
- dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- }
- return ret;
-}
-
-static struct snd_soc_ops kabylake_ssp0_ops = {
- .hw_params = kabylake_ssp0_hw_params,
-};
-
-static const unsigned int channels_dmic[] = {
- 4,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
- .count = ARRAY_SIZE(channels_dmic),
- .list = channels_dmic,
- .mask = 0,
-};
-
-static const unsigned int dmic_2ch[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
- .count = ARRAY_SIZE(dmic_2ch),
- .list = dmic_2ch,
- .mask = 0,
-};
-
-static int kabylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_max = DMIC_CH(dmic_constraints);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- dmic_constraints);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static struct snd_soc_ops kabylake_dmic_ops = {
- .startup = kabylake_dmic_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(system2,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin2")));
-
-SND_SOC_DAILINK_DEF(echoref,
- DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin")));
-
-SND_SOC_DAILINK_DEF(spi_cpu,
- DAILINK_COMP_ARRAY(COMP_CPU("spi-PRP0001:00")));
-SND_SOC_DAILINK_DEF(spi_platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("spi-PRP0001:00")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(
- /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI),
- /* Right */COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI),
- /* dmic */ COMP_CODEC(RT5514_DEV_NAME, KBL_REALTEK_DMIC_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC(RT5663_DEV_NAME, KBL_REALTEK_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* kabylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link kabylake_dais[] = {
- /* Front End DAI links */
- [KBL_DPCM_AUDIO_PB] = {
- .name = "Kbl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = kabylake_rt5663_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &kabylake_rt5663_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_CP] = {
- .name = "Kbl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &kabylake_rt5663_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HS_PB] = {
- .name = "Kbl Audio Headset Playback",
- .stream_name = "Headset Audio",
- .dpcm_playback = 1,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(system2, dummy, platform),
- },
- [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
- .name = "Kbl Audio Echo Reference cap",
- .stream_name = "Echoreference Capture",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- SND_SOC_DAILINK_REG(echoref, dummy, platform),
- },
- [KBL_DPCM_AUDIO_RT5514_DSP] = {
- .name = "rt5514 dsp",
- .stream_name = "Wake on Voice",
- SND_SOC_DAILINK_REG(spi_cpu, dummy, spi_platform),
- },
- [KBL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Kbl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &kabylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Kbl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [KBL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Kbl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- /* Back End DAI links */
- /* single Back end dai for both max speakers and dmic */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ops = &kabylake_ssp0_ops,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = kabylake_rt5663_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
- .ops = &kabylake_rt5663_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .dpcm_playback = 1,
- .init = kabylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = kabylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
-};
-
-static int kabylake_set_bias_level(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
-{
- struct snd_soc_component *component = dapm->component;
- struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card);
- int ret = 0;
-
- if (!component || strcmp(component->name, RT5514_DEV_NAME))
- return 0;
-
- if (IS_ERR(priv->mclk))
- return 0;
-
- /*
- * It's required to control mclk directly in the set_bias_level
- * function for rt5514 codec or the recording function could
- * break.
- */
- switch (level) {
- case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level == SND_SOC_BIAS_ON) {
- if (!__clk_is_enabled(priv->mclk))
- return 0;
- dev_dbg(card->dev, "Disable mclk");
- clk_disable_unprepare(priv->mclk);
- } else {
- dev_dbg(card->dev, "Enable mclk");
- ret = clk_set_rate(priv->mclk, 24000000);
- if (ret) {
- dev_err(card->dev, "Can't set rate for mclk, err: %d\n",
- ret);
- return ret;
- }
-
- ret = clk_prepare_enable(priv->mclk);
- if (ret) {
- dev_err(card->dev, "Can't enable mclk, err: %d\n",
- ret);
-
- /* mclk is already enabled in FW */
- ret = 0;
- }
- }
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static int kabylake_card_late_probe(struct snd_soc_card *card)
-{
- struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
- struct kbl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP,pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &ctx->kabylake_hdmi[i]);
-
- if (err)
- return err;
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &ctx->kabylake_hdmi[i]);
- if (err < 0)
- return err;
- i++;
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/*
- * kabylake audio machine driver for MAX98927 + RT5514 + RT5663
- */
-static struct snd_soc_card kabylake_audio_card = {
- .name = "kbl-r5514-5663-max",
- .owner = THIS_MODULE,
- .dai_link = kabylake_dais,
- .num_links = ARRAY_SIZE(kabylake_dais),
- .set_bias_level = kabylake_set_bias_level,
- .controls = kabylake_controls,
- .num_controls = ARRAY_SIZE(kabylake_controls),
- .dapm_widgets = kabylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets),
- .dapm_routes = kabylake_map,
- .num_dapm_routes = ARRAY_SIZE(kabylake_map),
- .codec_conf = max98927_codec_conf,
- .num_configs = ARRAY_SIZE(max98927_codec_conf),
- .fully_routed = true,
- .late_probe = kabylake_card_late_probe,
-};
-
-static int kabylake_audio_probe(struct platform_device *pdev)
-{
- struct kbl_codec_private *ctx;
- struct snd_soc_acpi_mach *mach;
- int ret;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- kabylake_audio_card.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
-
- mach = pdev->dev.platform_data;
- if (mach)
- dmic_constraints = mach->mach_params.dmic_num == 2 ?
- &constraints_dmic_2ch : &constraints_dmic_channels;
-
- ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
- if (IS_ERR(ctx->mclk)) {
- ret = PTR_ERR(ctx->mclk);
- if (ret == -ENOENT) {
- dev_info(&pdev->dev,
- "Failed to get ssp1_mclk, defer probe\n");
- return -EPROBE_DEFER;
- }
-
- dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n",
- ret);
- return ret;
- }
-
- ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk");
- if (IS_ERR(ctx->sclk)) {
- ret = PTR_ERR(ctx->sclk);
- if (ret == -ENOENT) {
- dev_info(&pdev->dev,
- "Failed to get ssp1_sclk, defer probe\n");
- return -EPROBE_DEFER;
- }
-
- dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n",
- ret);
- return ret;
- }
-
- return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
-}
-
-static const struct platform_device_id kbl_board_ids[] = {
- { .name = "kbl_r5514_5663_max" },
- { }
-};
-MODULE_DEVICE_TABLE(platform, kbl_board_ids);
-
-static struct platform_driver kabylake_audio = {
- .probe = kabylake_audio_probe,
- .driver = {
- .name = "kbl_r5514_5663_max",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = kbl_board_ids,
-};
-
-module_platform_driver(kabylake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927");
-MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c
deleted file mode 100644
index e9cefa4ae56d..000000000000
--- a/sound/soc/intel/boards/skl_hda_dsp_common.c
+++ /dev/null
@@ -1,168 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2015-18 Intel Corporation.
-
-/*
- * Common functions used in different Intel machine drivers
- */
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "../../codecs/hdac_hdmi.h"
-#include "skl_hda_dsp_common.h"
-
-#include <sound/hda_codec.h>
-#include "../../codecs/hdac_hda.h"
-
-#define NAME_SIZE 32
-
-int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device)
-{
- struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
- struct skl_hda_hdmi_pcm *pcm;
- char dai_name[NAME_SIZE];
-
- pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d",
- ctx->dai_index);
- pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name);
- if (!pcm->codec_dai)
- return -EINVAL;
-
- pcm->device = device;
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-SND_SOC_DAILINK_DEF(idisp1_cpu,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_cpu,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_cpu,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(analog_cpu,
- DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI")));
-SND_SOC_DAILINK_DEF(analog_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI")));
-
-SND_SOC_DAILINK_DEF(digital_cpu,
- DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI")));
-SND_SOC_DAILINK_DEF(digital_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI")));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(dmic16k,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* skl_hda_digital audio interface glue - connects codec <--> CPU */
-struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = {
- /* Back End DAI links */
- {
- .name = "iDisp1",
- .id = 1,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_cpu, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 2,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_cpu, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 3,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_cpu, idisp3_codec, platform),
- },
- {
- .name = "Analog Playback and Capture",
- .id = 4,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(analog_cpu, analog_codec, platform),
- },
- {
- .name = "Digital Playback and Capture",
- .id = 5,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(digital_cpu, digital_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 6,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "dmic16k",
- .id = 7,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform),
- },
-};
-
-int skl_hda_hdmi_jack_init(struct snd_soc_card *card)
-{
- struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = NULL;
- struct skl_hda_hdmi_pcm *pcm;
- char jack_name[NAME_SIZE];
- int err;
-
- if (ctx->common_hdmi_codec_drv)
- return skl_hda_hdmi_build_controls(card);
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &pcm->hdmi_jack);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &pcm->hdmi_jack);
- if (err < 0)
- return err;
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h
deleted file mode 100644
index 4b0b3959182e..000000000000
--- a/sound/soc/intel/boards/skl_hda_dsp_common.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright(c) 2015-18 Intel Corporation.
- */
-
-/*
- * This file defines data structures used in Machine Driver for Intel
- * platforms with HDA Codecs.
- */
-
-#ifndef __SKL_HDA_DSP_COMMON_H
-#define __SKL_HDA_DSP_COMMON_H
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/hda_codec.h>
-#include "../../codecs/hdac_hda.h"
-#include "hda_dsp_common.h"
-
-#define HDA_DSP_MAX_BE_DAI_LINKS 7
-
-struct skl_hda_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- struct snd_soc_jack hdmi_jack;
- int device;
-};
-
-struct skl_hda_private {
- struct list_head hdmi_pcm_list;
- int pcm_count;
- int dai_index;
- const char *platform_name;
- bool common_hdmi_codec_drv;
- bool idisp_codec;
-};
-
-extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS];
-int skl_hda_hdmi_jack_init(struct snd_soc_card *card);
-int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device);
-
-/*
- * Search card topology and register HDMI PCM related controls
- * to codec driver.
- */
-static inline int skl_hda_hdmi_build_controls(struct snd_soc_card *card)
-{
- struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component;
- struct skl_hda_hdmi_pcm *pcm;
-
- /* HDMI disabled, do not create controls */
- if (list_empty(&ctx->hdmi_pcm_list))
- return 0;
-
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct skl_hda_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- if (!component)
- return -EINVAL;
-
- return hda_dsp_hdmi_build_controls(card, component);
-}
-
-#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index a06e05154ae1..519218385fdf 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -8,168 +8,23 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
+#include <sound/hda_codec.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
-#include "../../codecs/hdac_hdmi.h"
-#include "skl_hda_dsp_common.h"
-
-static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
- SND_SOC_DAPM_HP("Analog Out", NULL),
- SND_SOC_DAPM_MIC("Analog In", NULL),
- SND_SOC_DAPM_HP("Alt Analog Out", NULL),
- SND_SOC_DAPM_MIC("Alt Analog In", NULL),
- SND_SOC_DAPM_SPK("Digital Out", NULL),
- SND_SOC_DAPM_MIC("Digital In", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
-static const struct snd_soc_dapm_route skl_hda_map[] = {
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-
- { "Analog Out", NULL, "Codec Output Pin1" },
- { "Digital Out", NULL, "Codec Output Pin2" },
- { "Alt Analog Out", NULL, "Codec Output Pin3" },
-
- { "Codec Input Pin1", NULL, "Analog In" },
- { "Codec Input Pin2", NULL, "Digital In" },
- { "Codec Input Pin3", NULL, "Alt Analog In" },
-
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-
- /* CODEC BE connections */
- { "Analog Codec Playback", NULL, "Analog CPU Playback" },
- { "Analog CPU Playback", NULL, "codec0_out" },
- { "Digital Codec Playback", NULL, "Digital CPU Playback" },
- { "Digital CPU Playback", NULL, "codec1_out" },
- { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" },
- { "Alt Analog CPU Playback", NULL, "codec2_out" },
-
- { "codec0_in", NULL, "Analog CPU Capture" },
- { "Analog CPU Capture", NULL, "Analog Codec Capture" },
- { "codec1_in", NULL, "Digital CPU Capture" },
- { "Digital CPU Capture", NULL, "Digital Codec Capture" },
- { "codec2_in", NULL, "Alt Analog CPU Capture" },
- { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" },
-};
+#include "../../codecs/hdac_hda.h"
+#include "../../sof/intel/hda.h"
+#include "sof_board_helpers.h"
static int skl_hda_card_late_probe(struct snd_soc_card *card)
{
- return skl_hda_hdmi_jack_init(card);
+ return sof_intel_board_card_late_probe(card);
}
-static int
-skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
-{
- struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
- int ret = 0;
-
- dev_dbg(card->dev, "dai link name - %s\n", link->name);
- link->platforms->name = ctx->platform_name;
- link->nonatomic = 1;
-
- if (!ctx->idisp_codec)
- return 0;
-
- if (strstr(link->name, "HDMI")) {
- ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count);
-
- if (ret < 0)
- return ret;
-
- ctx->dai_index++;
- }
-
- ctx->pcm_count++;
- return ret;
-}
-
-static struct snd_soc_card hda_soc_card = {
- .name = "hda-dsp",
- .owner = THIS_MODULE,
- .dai_link = skl_hda_be_dai_links,
- .dapm_widgets = skl_hda_widgets,
- .dapm_routes = skl_hda_map,
- .add_dai_link = skl_hda_add_dai_link,
- .fully_routed = true,
- .late_probe = skl_hda_card_late_probe,
-};
-
-static char hda_soc_components[30];
-
-#define IDISP_DAI_COUNT 3
-#define HDAC_DAI_COUNT 2
-#define DMIC_DAI_COUNT 2
-
-/* there are two routes per iDisp output */
-#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
-#define IDISP_CODEC_MASK 0x4
-
#define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000
-static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
-{
- struct snd_soc_card *card = &hda_soc_card;
- struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai_link *dai_link;
- u32 codec_count, codec_mask;
- int i, num_links, num_route;
-
- codec_mask = mach_params->codec_mask;
- codec_count = hweight_long(codec_mask);
- ctx->idisp_codec = !!(codec_mask & IDISP_CODEC_MASK);
-
- if (!codec_count || codec_count > 2 ||
- (codec_count == 2 && !ctx->idisp_codec))
- return -EINVAL;
-
- if (codec_mask == IDISP_CODEC_MASK) {
- /* topology with iDisp as the only HDA codec */
- num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT;
- num_route = IDISP_ROUTE_COUNT;
-
- /*
- * rearrange the dai link array and make the
- * dmic dai links follow idsp dai links for only
- * num_links of dai links need to be registered
- * to ASoC.
- */
- for (i = 0; i < DMIC_DAI_COUNT; i++) {
- skl_hda_be_dai_links[IDISP_DAI_COUNT + i] =
- skl_hda_be_dai_links[IDISP_DAI_COUNT +
- HDAC_DAI_COUNT + i];
- }
- } else {
- /* topology with external and iDisp HDA codecs */
- num_links = ARRAY_SIZE(skl_hda_be_dai_links);
- num_route = ARRAY_SIZE(skl_hda_map);
- card->dapm_widgets = skl_hda_widgets;
- card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets);
- if (!ctx->idisp_codec) {
- for (i = 0; i < IDISP_DAI_COUNT; i++) {
- skl_hda_be_dai_links[i].codecs = &asoc_dummy_dlc;
- skl_hda_be_dai_links[i].num_codecs = 1;
- }
- }
- }
-
- card->num_links = num_links;
- card->num_dapm_routes = num_route;
-
- for_each_card_prelinks(card, i, dai_link)
- dai_link->platforms->name = mach_params->platform;
-
- return 0;
-}
-
static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
@@ -179,7 +34,7 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card)
for_each_card_rtds(card, rtd) {
if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0"))
continue;
- dai = asoc_rtd_to_codec(rtd, 0);
+ dai = snd_soc_rtd_to_codec(rtd, 0);
hda_pvt = snd_soc_component_get_drvdata(dai->component);
if (hda_pvt) {
/*
@@ -193,48 +48,114 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card)
}
}
+#define IDISP_HDMI_BE_ID 1
+#define HDA_BE_ID 4
+#define DMIC01_BE_ID 6
+#define DMIC16K_BE_ID 7
+#define BT_OFFLOAD_BE_ID 8
+
+#define HDA_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_HDA, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_BT_OFFLOAD, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
+
+#define HDA_LINK_IDS SOF_LINK_ORDER(IDISP_HDMI_BE_ID, \
+ HDA_BE_ID, \
+ DMIC01_BE_ID, \
+ DMIC16K_BE_ID, \
+ BT_OFFLOAD_BE_ID, \
+ 0, \
+ 0)
+
+static unsigned long
+skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params)
+{
+ unsigned long board_quirk = 0;
+ int ssp_bt;
+
+ if (hweight_long(mach_params->bt_link_mask) == 1) {
+ ssp_bt = fls(mach_params->bt_link_mask) - 1;
+ board_quirk |= SOF_SSP_PORT_BT_OFFLOAD(ssp_bt) |
+ SOF_BT_OFFLOAD_PRESENT;
+ }
+
+ return board_quirk;
+}
+
+static int skl_hda_add_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+
+ /* Ignore the HDMI PCM link if iDisp is not present */
+ if (strstr(link->stream_name, "HDMI") && !ctx->hdmi.idisp_codec)
+ link->ignore = true;
+
+ return 0;
+}
+
static int skl_hda_audio_probe(struct platform_device *pdev)
{
- struct snd_soc_acpi_mach *mach;
- struct skl_hda_private *ctx;
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
+ struct sof_card_private *ctx;
+ struct snd_soc_card *card;
+ unsigned long board_quirk = skl_hda_get_board_quirk(&mach->mach_params);
int ret;
- dev_dbg(&pdev->dev, "entry\n");
+ card = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->name = "hda-dsp";
+ card->owner = THIS_MODULE;
+ card->fully_routed = true;
+ card->late_probe = skl_hda_card_late_probe;
+ card->add_dai_link = skl_hda_add_dai_link;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
+
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk);
if (!ctx)
return -ENOMEM;
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ if (HDA_EXT_CODEC(mach->mach_params.codec_mask))
+ ctx->hda_codec_present = true;
- mach = pdev->dev.platform_data;
- if (!mach)
- return -EINVAL;
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
+ ctx->hdmi.idisp_codec = true;
- snd_soc_card_set_drvdata(&hda_soc_card, ctx);
+ ctx->link_order_overwrite = HDA_LINK_ORDER;
+ ctx->link_id_overwrite = HDA_LINK_IDS;
- ret = skl_hda_fill_card_info(&mach->mach_params);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
+ /* update dai_link */
+ ret = sof_intel_board_set_dai_link(&pdev->dev, card, ctx);
+ if (ret)
return ret;
- }
-
- ctx->pcm_count = hda_soc_card.num_links;
- ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
- ctx->platform_name = mach->mach_params.platform;
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
- hda_soc_card.dev = &pdev->dev;
+ card->dev = &pdev->dev;
if (mach->mach_params.dmic_num > 0) {
- snprintf(hda_soc_components, sizeof(hda_soc_components),
- "cfg-dmics:%d", mach->mach_params.dmic_num);
- hda_soc_card.components = hda_soc_components;
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "cfg-dmics:%d",
+ mach->mach_params.dmic_num);
+ if (!card->components)
+ return -ENOMEM;
}
- ret = devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
+ ret = snd_soc_fixup_dai_links_platform_name(card,
+ mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ snd_soc_card_set_drvdata(card, ctx);
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (!ret)
- skl_set_hda_codec_autosuspend_delay(&hda_soc_card);
+ skl_set_hda_codec_autosuspend_delay(card);
return ret;
}
@@ -254,4 +175,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver");
MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:skl_hda_dsp_generic");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
deleted file mode 100644
index e13a5a4d8f7e..000000000000
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ /dev/null
@@ -1,703 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Skylake I2S Machine Driver with MAXIM98357A
- * and NAU88L25
- *
- * Copyright (C) 2015, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/nau8825.h"
-#include "../../codecs/hdac_hdmi.h"
-
-#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
-#define SKL_MAXIM_CODEC_DAI "HiFi"
-#define DMIC_CH(p) p->list[p->count-1]
-
-static struct snd_soc_jack skylake_headset;
-static struct snd_soc_card skylake_audio_card;
-static const struct snd_pcm_hw_constraint_list *dmic_constraints;
-static struct snd_soc_jack skylake_hdmi[3];
-
-struct skl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct skl_nau8825_private {
- struct list_head hdmi_pcm_list;
-};
-
-enum {
- SKL_DPCM_AUDIO_PB = 0,
- SKL_DPCM_AUDIO_CP,
- SKL_DPCM_AUDIO_REF_CP,
- SKL_DPCM_AUDIO_DMIC_CP,
- SKL_DPCM_AUDIO_HDMI1_PB,
- SKL_DPCM_AUDIO_HDMI2_PB,
- SKL_DPCM_AUDIO_HDMI3_PB,
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct snd_soc_dai *codec_dai;
- int ret;
-
- codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
- if (!codec_dai) {
- dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
- return -EIO;
- }
-
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_sysclk(codec_dai,
- NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(card->dev, "set sysclk err = %d\n", ret);
- return -EIO;
- }
- } else {
- ret = snd_soc_dai_set_sysclk(codec_dai,
- NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(card->dev, "set sysclk err = %d\n", ret);
- return -EIO;
- }
- }
-
- return ret;
-}
-
-static const struct snd_kcontrol_new skylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
-};
-
-static const struct snd_soc_dapm_widget skylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("DP1", NULL),
- SND_SOC_DAPM_SPK("DP2", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route skylake_map[] = {
- /* HP jack connectors - unknown if we have jack detection */
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
-
- /* speaker */
- { "Spk", NULL, "Speaker" },
-
- /* other jacks */
- { "MIC", NULL, "Headset Mic" },
- { "DMic", NULL, "SoC DMIC" },
-
- /* CODEC BE connections */
- { "HiFi Playback", NULL, "ssp0 Tx" },
- { "ssp0 Tx", NULL, "codec0_out" },
-
- { "Playback", NULL, "ssp1 Tx" },
- { "ssp1 Tx", NULL, "codec1_out" },
-
- { "codec0_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "Capture" },
-
- /* DMIC */
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-};
-
-static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
-
- /* set SSP0 to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
-
- return 0;
-}
-
-static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
- return ret;
- }
-
- nau8825_enable_jack_detect(component, &skylake_headset);
-
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
-
- return ret;
-}
-
-static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI1_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI2_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI3_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int skl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * On this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = 2;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops skylake_nau8825_fe_ops = {
- .startup = skl_fe_startup,
-};
-
-static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
-
- if (ret < 0)
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
-
- return ret;
-}
-
-static const struct snd_soc_ops skylake_nau8825_ops = {
- .hw_params = skylake_nau8825_hw_params,
-};
-
-static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static const unsigned int channels_dmic[] = {
- 2, 4,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
- .count = ARRAY_SIZE(channels_dmic),
- .list = channels_dmic,
- .mask = 0,
-};
-
-static const unsigned int dmic_2ch[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
- .count = ARRAY_SIZE(dmic_2ch),
- .list = dmic_2ch,
- .mask = 0,
-};
-
-static int skylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_max = DMIC_CH(dmic_constraints);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- dmic_constraints);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static const struct snd_soc_ops skylake_dmic_ops = {
- .startup = skylake_dmic_startup,
-};
-
-static const unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_refcap = {
- .count = ARRAY_SIZE(ch_mono),
- .list = ch_mono,
-};
-
-static int skylake_refcap_startup(struct snd_pcm_substream *substream)
-{
- substream->runtime->hw.channels_max = 1;
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_refcap);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-}
-
-static const struct snd_soc_ops skylake_refcap_ops = {
- .startup = skylake_refcap_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", SKL_MAXIM_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00",
- SKL_NUVOTON_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* skylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link skylake_dais[] = {
- /* Front End DAI links */
- [SKL_DPCM_AUDIO_PB] = {
- .name = "Skl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = skylake_nau8825_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &skylake_nau8825_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [SKL_DPCM_AUDIO_CP] = {
- .name = "Skl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &skylake_nau8825_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [SKL_DPCM_AUDIO_REF_CP] = {
- .name = "Skl Audio Reference cap",
- .stream_name = "Wake on Voice",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [SKL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Skl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Skl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Skl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Skl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = skylake_ssp_fixup,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = skylake_nau8825_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = skylake_ssp_fixup,
- .ops = &skylake_nau8825_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .be_hw_params_fixup = skylake_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .dpcm_playback = 1,
- .init = skylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = skylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = skylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-#define NAME_SIZE 32
-static int skylake_card_late_probe(struct snd_soc_card *card)
-{
- struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card);
- struct skl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT,
- &skylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &skylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* skylake audio machine driver for SPT + NAU88L25 */
-static struct snd_soc_card skylake_audio_card = {
- .name = "sklnau8825max",
- .owner = THIS_MODULE,
- .dai_link = skylake_dais,
- .num_links = ARRAY_SIZE(skylake_dais),
- .controls = skylake_controls,
- .num_controls = ARRAY_SIZE(skylake_controls),
- .dapm_widgets = skylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
- .dapm_routes = skylake_map,
- .num_dapm_routes = ARRAY_SIZE(skylake_map),
- .fully_routed = true,
- .late_probe = skylake_card_late_probe,
-};
-
-static int skylake_audio_probe(struct platform_device *pdev)
-{
- struct skl_nau8825_private *ctx;
- struct snd_soc_acpi_mach *mach;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- skylake_audio_card.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
-
- mach = pdev->dev.platform_data;
- if (mach)
- dmic_constraints = mach->mach_params.dmic_num == 2 ?
- &constraints_dmic_2ch : &constraints_dmic_channels;
-
- return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
-}
-
-static const struct platform_device_id skl_board_ids[] = {
- { .name = "skl_n88l25_m98357a" },
- { .name = "kbl_n88l25_m98357a" },
- { }
-};
-MODULE_DEVICE_TABLE(platform, skl_board_ids);
-
-static struct platform_driver skylake_audio = {
- .probe = skylake_audio_probe,
- .driver = {
- .name = "skl_n88l25_m98357a",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = skl_board_ids,
-};
-
-module_platform_driver(skylake_audio)
-
-/* Module information */
-MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode");
-MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
deleted file mode 100644
index 575604dc8936..000000000000
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ /dev/null
@@ -1,751 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567
- *
- * Copyright (C) 2015, Intel Corporation. All rights reserved.
- *
- * Modified from:
- * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567
- *
- * Copyright (C) 2015, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-#include "../../codecs/nau8825.h"
-#include "../../codecs/hdac_hdmi.h"
-
-#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
-#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
-#define DMIC_CH(p) p->list[p->count-1]
-
-static struct snd_soc_jack skylake_headset;
-static struct snd_soc_card skylake_audio_card;
-static const struct snd_pcm_hw_constraint_list *dmic_constraints;
-static struct snd_soc_jack skylake_hdmi[3];
-
-struct skl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct skl_nau88125_private {
- struct list_head hdmi_pcm_list;
-};
-enum {
- SKL_DPCM_AUDIO_PB = 0,
- SKL_DPCM_AUDIO_CP,
- SKL_DPCM_AUDIO_REF_CP,
- SKL_DPCM_AUDIO_DMIC_CP,
- SKL_DPCM_AUDIO_HDMI1_PB,
- SKL_DPCM_AUDIO_HDMI2_PB,
- SKL_DPCM_AUDIO_HDMI3_PB,
-};
-
-static const struct snd_kcontrol_new skylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Speaker"),
- SOC_DAPM_PIN_SWITCH("Right Speaker"),
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct snd_soc_dai *codec_dai;
- int ret;
-
- codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
- if (!codec_dai) {
- dev_err(card->dev, "Codec dai not found\n");
- return -EIO;
- }
-
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_sysclk(codec_dai,
- NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(card->dev, "set sysclk err = %d\n", ret);
- return -EIO;
- }
- } else {
- ret = snd_soc_dai_set_sysclk(codec_dai,
- NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(card->dev, "set sysclk err = %d\n", ret);
- return -EIO;
- }
- }
- return ret;
-}
-
-static const struct snd_soc_dapm_widget skylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Left Speaker", NULL),
- SND_SOC_DAPM_SPK("Right Speaker", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("DP1", NULL),
- SND_SOC_DAPM_SPK("DP2", NULL),
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMD),
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static const struct snd_soc_dapm_route skylake_map[] = {
- /* HP jack connectors - unknown if we have jack detection */
- {"Headphone Jack", NULL, "HPOL"},
- {"Headphone Jack", NULL, "HPOR"},
-
- /* speaker */
- {"Left Speaker", NULL, "Left OUT"},
- {"Right Speaker", NULL, "Right OUT"},
-
- /* other jacks */
- {"MIC", NULL, "Headset Mic"},
- {"DMic", NULL, "SoC DMIC"},
-
- /* CODEC BE connections */
- { "Left Playback", NULL, "ssp0 Tx"},
- { "Right Playback", NULL, "ssp0 Tx"},
- { "ssp0 Tx", NULL, "codec0_out"},
-
- /* IV feedback path */
- { "codec0_lp_in", NULL, "ssp0 Rx"},
- { "ssp0 Rx", NULL, "Left Capture Sense" },
- { "ssp0 Rx", NULL, "Right Capture Sense" },
-
- { "Playback", NULL, "ssp1 Tx"},
- { "ssp1 Tx", NULL, "codec1_out"},
-
- { "codec0_in", NULL, "ssp1 Rx" },
- { "ssp1 Rx", NULL, "Capture" },
-
- /* DMIC */
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-};
-
-static struct snd_soc_codec_conf ssm4567_codec_conf[] = {
- {
- .dlc = COMP_CODEC_CONF("i2c-INT343B:00"),
- .name_prefix = "Left",
- },
- {
- .dlc = COMP_CODEC_CONF("i2c-INT343B:01"),
- .name_prefix = "Right",
- },
-};
-
-static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
-
- /* Slot 1 for left */
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 0), 0x01, 0x01, 2, 48);
- if (ret < 0)
- return ret;
-
- /* Slot 2 for right */
- ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(rtd, 1), 0x02, 0x02, 2, 48);
- if (ret < 0)
- return ret;
-
- return ret;
-}
-
-static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
- /*
- * 4 buttons here map to the google Reference headset
- * The use of these buttons can be decided by the user space.
- */
- ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
- return ret;
- }
-
- nau8825_enable_jack_detect(component, &skylake_headset);
-
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
-
- return ret;
-}
-
-static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI1_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI2_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-
-static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI3_PB;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int skl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * on this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = 2;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops skylake_nau8825_fe_ops = {
- .startup = skl_fe_startup,
-};
-
-static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
-
- /* set SSP0 to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- return 0;
-}
-
-static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai,
- NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
-
- if (ret < 0)
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
-
- return ret;
-}
-
-static const struct snd_soc_ops skylake_nau8825_ops = {
- .hw_params = skylake_nau8825_hw_params,
-};
-
-static const unsigned int channels_dmic[] = {
- 2, 4,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
- .count = ARRAY_SIZE(channels_dmic),
- .list = channels_dmic,
- .mask = 0,
-};
-
-static const unsigned int dmic_2ch[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
- .count = ARRAY_SIZE(dmic_2ch),
- .list = dmic_2ch,
- .mask = 0,
-};
-
-static int skylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_max = DMIC_CH(dmic_constraints);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- dmic_constraints);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static const struct snd_soc_ops skylake_dmic_ops = {
- .startup = skylake_dmic_startup,
-};
-
-static const unsigned int rates_16000[] = {
- 16000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_16000 = {
- .count = ARRAY_SIZE(rates_16000),
- .list = rates_16000,
-};
-
-static const unsigned int ch_mono[] = {
- 1,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_refcap = {
- .count = ARRAY_SIZE(ch_mono),
- .list = ch_mono,
-};
-
-static int skylake_refcap_startup(struct snd_pcm_substream *substream)
-{
- substream->runtime->hw.channels_max = 1;
- snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_refcap);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_16000);
-}
-
-static const struct snd_soc_ops skylake_refcap_ops = {
- .startup = skylake_refcap_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(
- /* Left */ COMP_CODEC("i2c-INT343B:00", SKL_SSM_CODEC_DAI),
- /* Right */ COMP_CODEC("i2c-INT343B:01", SKL_SSM_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", SKL_NUVOTON_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(dmic01_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* skylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link skylake_dais[] = {
- /* Front End DAI links */
- [SKL_DPCM_AUDIO_PB] = {
- .name = "Skl Audio Port",
- .stream_name = "Audio",
- .dynamic = 1,
- .nonatomic = 1,
- .init = skylake_nau8825_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .ops = &skylake_nau8825_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [SKL_DPCM_AUDIO_CP] = {
- .name = "Skl Audio Capture Port",
- .stream_name = "Audio Record",
- .dynamic = 1,
- .nonatomic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- .ops = &skylake_nau8825_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [SKL_DPCM_AUDIO_REF_CP] = {
- .name = "Skl Audio Reference cap",
- .stream_name = "Wake on Voice",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_refcap_ops,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [SKL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Skl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Skl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Skl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Skl HDMI Port3",
- .stream_name = "Hdmi3",
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .init = skylake_ssm4567_codec_init,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = skylake_ssp_fixup,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- /* SSP1 - Codec */
- .name = "SSP1-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = skylake_nau8825_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = skylake_ssp_fixup,
- .ops = &skylake_nau8825_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .ignore_suspend = 1,
- .be_hw_params_fixup = skylake_dmic_fixup,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .dpcm_playback = 1,
- .init = skylake_hdmi1_init,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = skylake_hdmi2_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = skylake_hdmi3_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-#define NAME_SIZE 32
-static int skylake_card_late_probe(struct snd_soc_card *card)
-{
- struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card);
- struct skl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT,
- &skylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &skylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* skylake audio machine driver for SPT + NAU88L25 */
-static struct snd_soc_card skylake_audio_card = {
- .name = "sklnau8825adi",
- .owner = THIS_MODULE,
- .dai_link = skylake_dais,
- .num_links = ARRAY_SIZE(skylake_dais),
- .controls = skylake_controls,
- .num_controls = ARRAY_SIZE(skylake_controls),
- .dapm_widgets = skylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
- .dapm_routes = skylake_map,
- .num_dapm_routes = ARRAY_SIZE(skylake_map),
- .codec_conf = ssm4567_codec_conf,
- .num_configs = ARRAY_SIZE(ssm4567_codec_conf),
- .fully_routed = true,
- .disable_route_checks = true,
- .late_probe = skylake_card_late_probe,
-};
-
-static int skylake_audio_probe(struct platform_device *pdev)
-{
- struct skl_nau88125_private *ctx;
- struct snd_soc_acpi_mach *mach;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- skylake_audio_card.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
-
- mach = pdev->dev.platform_data;
- if (mach)
- dmic_constraints = mach->mach_params.dmic_num == 2 ?
- &constraints_dmic_2ch : &constraints_dmic_channels;
-
- return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
-}
-
-static const struct platform_device_id skl_board_ids[] = {
- { .name = "skl_n88l25_s4567" },
- { .name = "kbl_n88l25_s4567" },
- { }
-};
-MODULE_DEVICE_TABLE(platform, skl_board_ids);
-
-static struct platform_driver skylake_audio = {
- .probe = skylake_audio_probe,
- .driver = {
- .name = "skl_n88l25_s4567",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = skl_board_ids,
-};
-
-module_platform_driver(skylake_audio)
-
-/* Module information */
-MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
-MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
-MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
-MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
-MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
-MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
deleted file mode 100644
index 4f3d655e2bfa..000000000000
--- a/sound/soc/intel/boards/skl_rt286.c
+++ /dev/null
@@ -1,567 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Skylake I2S Machine Driver
- *
- * Copyright (C) 2014-2015, Intel Corporation. All rights reserved.
- *
- * Modified from:
- * Intel Broadwell Wildcatpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-#include "../../codecs/rt286.h"
-#include "../../codecs/hdac_hdmi.h"
-
-static struct snd_soc_jack skylake_headset;
-static struct snd_soc_jack skylake_hdmi[3];
-
-struct skl_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct skl_rt286_private {
- struct list_head hdmi_pcm_list;
-};
-
-enum {
- SKL_DPCM_AUDIO_PB = 0,
- SKL_DPCM_AUDIO_DB_PB,
- SKL_DPCM_AUDIO_CP,
- SKL_DPCM_AUDIO_REF_CP,
- SKL_DPCM_AUDIO_DMIC_CP,
- SKL_DPCM_AUDIO_HDMI1_PB,
- SKL_DPCM_AUDIO_HDMI2_PB,
- SKL_DPCM_AUDIO_HDMI3_PB,
-};
-
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin skylake_headset_pins[] = {
- {
- .pin = "Mic Jack",
- .mask = SND_JACK_MICROPHONE,
- },
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
-};
-
-static const struct snd_kcontrol_new skylake_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Mic Jack"),
-};
-
-static const struct snd_soc_dapm_widget skylake_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_SPK("Speaker", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
- SND_SOC_DAPM_MIC("DMIC2", NULL),
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SPK("HDMI1", NULL),
- SND_SOC_DAPM_SPK("HDMI2", NULL),
- SND_SOC_DAPM_SPK("HDMI3", NULL),
-};
-
-static const struct snd_soc_dapm_route skylake_rt286_map[] = {
- /* speaker */
- {"Speaker", NULL, "SPOR"},
- {"Speaker", NULL, "SPOL"},
-
- /* HP jack connectors - unknown if we have jack deteck */
- {"Headphone Jack", NULL, "HPO Pin"},
-
- /* other jacks */
- {"MIC1", NULL, "Mic Jack"},
-
- /* digital mics */
- {"DMIC1 Pin", NULL, "DMIC2"},
- {"DMic", NULL, "SoC DMIC"},
-
- /* CODEC BE connections */
- { "AIF1 Playback", NULL, "ssp0 Tx"},
- { "ssp0 Tx", NULL, "codec0_out"},
- { "ssp0 Tx", NULL, "codec1_out"},
-
- { "codec0_in", NULL, "ssp0 Rx" },
- { "codec1_in", NULL, "ssp0 Rx" },
- { "ssp0 Rx", NULL, "AIF1 Capture" },
-
- { "dmic01_hifi", NULL, "DMIC01 Rx" },
- { "DMIC01 Rx", NULL, "DMIC AIF" },
-
- { "hifi3", NULL, "iDisp3 Tx"},
- { "iDisp3 Tx", NULL, "iDisp3_out"},
- { "hifi2", NULL, "iDisp2 Tx"},
- { "iDisp2 Tx", NULL, "iDisp2_out"},
- { "hifi1", NULL, "iDisp1 Tx"},
- { "iDisp1 Tx", NULL, "iDisp1_out"},
-
-};
-
-static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dapm_context *dapm;
- struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
-
- dapm = snd_soc_component_get_dapm(component);
- snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
-
- return 0;
-}
-
-static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- int ret;
-
- ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
- SND_JACK_HEADSET | SND_JACK_BTN_0,
- &skylake_headset,
- skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins));
-
- if (ret)
- return ret;
-
- snd_soc_component_set_jack(component, &skylake_headset, NULL);
-
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
-
- return 0;
-}
-
-static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static const unsigned int rates[] = {
- 48000,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static const unsigned int channels[] = {
- 2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
-};
-
-static int skl_fe_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- /*
- * on this platform for PCM device we support,
- * 48Khz
- * stereo
- * 16 bit audio
- */
-
- runtime->hw.channels_max = 2;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
-
- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
- snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
-
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-
- return 0;
-}
-
-static const struct snd_soc_ops skylake_rt286_fe_ops = {
- .startup = skl_fe_startup,
-};
-
-static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *rate = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
- /* The output is 48KHz, stereo, 16bits */
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
-
- /* set SSP0 to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- return 0;
-}
-
-static int skylake_rt286_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
-
- return ret;
-}
-
-static const struct snd_soc_ops skylake_rt286_ops = {
- .hw_params = skylake_rt286_hw_params,
-};
-
-static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- struct snd_interval *chan = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- if (params_channels(params) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
-
- return 0;
-}
-
-static const unsigned int channels_dmic[] = {
- 2, 4,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
- .count = ARRAY_SIZE(channels_dmic),
- .list = channels_dmic,
- .mask = 0,
-};
-
-static int skylake_dmic_startup(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- runtime->hw.channels_max = 4;
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_dmic_channels);
-
- return snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
-}
-
-static const struct snd_soc_ops skylake_dmic_ops = {
- .startup = skylake_dmic_startup,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
- DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(deepbuffer,
- DAILINK_COMP_ARRAY(COMP_CPU("Deepbuffer Pin")));
-
-SND_SOC_DAILINK_DEF(reference,
- DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
-
-SND_SOC_DAILINK_DEF(dmic,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi1,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi2,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
-
-SND_SOC_DAILINK_DEF(hdmi3,
- DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
-
-SND_SOC_DAILINK_DEF(dmic01_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform,
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-/* skylake digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link skylake_rt286_dais[] = {
- /* Front End DAI links */
- [SKL_DPCM_AUDIO_PB] = {
- .name = "Skl Audio Port",
- .stream_name = "Audio",
- .nonatomic = 1,
- .dynamic = 1,
- .init = skylake_rt286_fe_init,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST
- },
- .dpcm_playback = 1,
- .ops = &skylake_rt286_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [SKL_DPCM_AUDIO_DB_PB] = {
- .name = "Skl Deepbuffer Port",
- .stream_name = "Deep Buffer Audio",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST
- },
- .dpcm_playback = 1,
- .ops = &skylake_rt286_fe_ops,
- SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
- },
- [SKL_DPCM_AUDIO_CP] = {
- .name = "Skl Audio Capture Port",
- .stream_name = "Audio Record",
- .nonatomic = 1,
- .dynamic = 1,
- .trigger = {
- SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST
- },
- .dpcm_capture = 1,
- .ops = &skylake_rt286_fe_ops,
- SND_SOC_DAILINK_REG(system, dummy, platform),
- },
- [SKL_DPCM_AUDIO_REF_CP] = {
- .name = "Skl Audio Reference cap",
- .stream_name = "refcap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(reference, dummy, platform),
- },
- [SKL_DPCM_AUDIO_DMIC_CP] = {
- .name = "Skl Audio DMIC cap",
- .stream_name = "dmiccap",
- .init = NULL,
- .dpcm_capture = 1,
- .nonatomic = 1,
- .dynamic = 1,
- .ops = &skylake_dmic_ops,
- SND_SOC_DAILINK_REG(dmic, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI1_PB] = {
- .name = "Skl HDMI Port1",
- .stream_name = "Hdmi1",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI2_PB] = {
- .name = "Skl HDMI Port2",
- .stream_name = "Hdmi2",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
- },
- [SKL_DPCM_AUDIO_HDMI3_PB] = {
- .name = "Skl HDMI Port3",
- .stream_name = "Hdmi3",
- .dpcm_playback = 1,
- .init = NULL,
- .nonatomic = 1,
- .dynamic = 1,
- SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
- },
-
- /* Back End DAI links */
- {
- /* SSP0 - Codec */
- .name = "SSP0-Codec",
- .id = 0,
- .no_pcm = 1,
- .init = skylake_rt286_codec_init,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBC_CFC,
- .ignore_pmdown_time = 1,
- .be_hw_params_fixup = skylake_ssp0_fixup,
- .ops = &skylake_rt286_ops,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 1,
- .be_hw_params_fixup = skylake_dmic_fixup,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 2,
- .init = skylake_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 3,
- .init = skylake_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 4,
- .init = skylake_hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
-};
-
-#define NAME_SIZE 32
-static int skylake_card_late_probe(struct snd_soc_card *card)
-{
- struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
- struct skl_hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
- int err, i = 0;
- char jack_name[NAME_SIZE];
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &skylake_hdmi[i]);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &skylake_hdmi[i]);
- if (err < 0)
- return err;
-
- i++;
- }
-
- if (!component)
- return -EINVAL;
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
-}
-
-/* skylake audio machine driver for SPT + RT286S */
-static struct snd_soc_card skylake_rt286 = {
- .name = "skylake-rt286",
- .owner = THIS_MODULE,
- .dai_link = skylake_rt286_dais,
- .num_links = ARRAY_SIZE(skylake_rt286_dais),
- .controls = skylake_controls,
- .num_controls = ARRAY_SIZE(skylake_controls),
- .dapm_widgets = skylake_widgets,
- .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
- .dapm_routes = skylake_rt286_map,
- .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map),
- .fully_routed = true,
- .late_probe = skylake_card_late_probe,
-};
-
-static int skylake_audio_probe(struct platform_device *pdev)
-{
- struct skl_rt286_private *ctx;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
- skylake_rt286.dev = &pdev->dev;
- snd_soc_card_set_drvdata(&skylake_rt286, ctx);
-
- return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286);
-}
-
-static const struct platform_device_id skl_board_ids[] = {
- { .name = "skl_alc286s_i2s" },
- { .name = "kbl_alc286s_i2s" },
- { }
-};
-MODULE_DEVICE_TABLE(platform, skl_board_ids);
-
-static struct platform_driver skylake_audio = {
- .probe = skylake_audio_probe,
- .driver = {
- .name = "skl_alc286s_i2s",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = skl_board_ids,
-
-};
-
-module_platform_driver(skylake_audio)
-
-/* Module information */
-MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>");
-MODULE_DESCRIPTION("Intel SST Audio for Skylake");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c
new file mode 100644
index 000000000000..f741a1e142be
--- /dev/null
+++ b/sound/soc/intel/boards/sof_board_helpers.c
@@ -0,0 +1,785 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2023 Intel Corporation
+
+#include <sound/soc.h>
+#include "../common/soc-intel-quirks.h"
+#include "hda_dsp_common.h"
+#include "sof_board_helpers.h"
+
+/*
+ * Intel HDMI DAI Link
+ */
+static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
+
+ ctx->hdmi.hdmi_comp = dai->component;
+
+ return 0;
+}
+
+int sof_intel_board_card_late_probe(struct snd_soc_card *card)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (!ctx->hdmi_num)
+ return 0;
+
+ if (!ctx->hdmi.idisp_codec)
+ return 0;
+
+ if (!ctx->hdmi.hdmi_comp)
+ return -EINVAL;
+
+ return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp);
+}
+EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, "SND_SOC_INTEL_SOF_BOARD_HELPERS");
+
+/*
+ * DMIC DAI Link
+ */
+static const struct snd_soc_dapm_widget dmic_widgets[] = {
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route dmic_routes[] = {
+ {"DMic", NULL, "SoC DMIC"},
+};
+
+static int dmic_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, dmic_widgets,
+ ARRAY_SIZE(dmic_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add dmic widgets, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, dmic_routes,
+ ARRAY_SIZE(dmic_routes));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add dmic routes, ret %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * HDA External Codec DAI Link
+ */
+static const struct snd_soc_dapm_widget hda_widgets[] = {
+ SND_SOC_DAPM_MIC("Analog In", NULL),
+ SND_SOC_DAPM_MIC("Digital In", NULL),
+ SND_SOC_DAPM_MIC("Alt Analog In", NULL),
+
+ SND_SOC_DAPM_HP("Analog Out", NULL),
+ SND_SOC_DAPM_SPK("Digital Out", NULL),
+ SND_SOC_DAPM_HP("Alt Analog Out", NULL),
+};
+
+static const struct snd_soc_dapm_route hda_routes[] = {
+ { "Codec Input Pin1", NULL, "Analog In" },
+ { "Codec Input Pin2", NULL, "Digital In" },
+ { "Codec Input Pin3", NULL, "Alt Analog In" },
+
+ { "Analog Out", NULL, "Codec Output Pin1" },
+ { "Digital Out", NULL, "Codec Output Pin2" },
+ { "Alt Analog Out", NULL, "Codec Output Pin3" },
+
+ /* CODEC BE connections */
+ { "codec0_in", NULL, "Analog CPU Capture" },
+ { "Analog CPU Capture", NULL, "Analog Codec Capture" },
+ { "codec1_in", NULL, "Digital CPU Capture" },
+ { "Digital CPU Capture", NULL, "Digital Codec Capture" },
+ { "codec2_in", NULL, "Alt Analog CPU Capture" },
+ { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" },
+
+ { "Analog Codec Playback", NULL, "Analog CPU Playback" },
+ { "Analog CPU Playback", NULL, "codec0_out" },
+ { "Digital Codec Playback", NULL, "Digital CPU Playback" },
+ { "Digital CPU Playback", NULL, "codec1_out" },
+ { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" },
+ { "Alt Analog CPU Playback", NULL, "codec2_out" },
+};
+
+static int hda_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, hda_widgets,
+ ARRAY_SIZE(hda_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, hda_routes,
+ ARRAY_SIZE(hda_routes));
+ if (ret)
+ dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret);
+
+ return ret;
+}
+
+/*
+ * DAI Link Helpers
+ */
+
+enum sof_dmic_be_type {
+ SOF_DMIC_01,
+ SOF_DMIC_16K,
+};
+
+enum sof_hda_be_type {
+ SOF_HDA_ANALOG,
+ SOF_HDA_DIGITAL,
+};
+
+/* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */
+#define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_AMP, \
+ SOF_LINK_BT_OFFLOAD, \
+ SOF_LINK_HDMI_IN)
+
+static struct snd_soc_dai_link_component dmic_component[] = {
+ {
+ .name = "dmic-codec",
+ .dai_name = "dmic-hifi",
+ }
+};
+
+SND_SOC_DAILINK_DEF(hda_analog_cpus,
+ DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI")));
+SND_SOC_DAILINK_DEF(hda_analog_codecs,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI")));
+
+SND_SOC_DAILINK_DEF(hda_digital_cpus,
+ DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI")));
+SND_SOC_DAILINK_DEF(hda_digital_codecs,
+ DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI")));
+
+static struct snd_soc_dai_link_component platform_component[] = {
+ {
+ /* name might be overridden during probe */
+ .name = "0000:00:1f.3"
+ }
+};
+
+static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum snd_soc_acpi_intel_codec codec_type,
+ int ssp_codec)
+{
+ struct snd_soc_dai_link_component *cpus;
+
+ dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id,
+ snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec);
+
+ /* link name */
+ link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
+ if (!link->name)
+ return -ENOMEM;
+
+ /* cpus */
+ cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ if (soc_intel_is_byt() || soc_intel_is_cht()) {
+ /* backward-compatibility for BYT/CHT boards */
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port",
+ ssp_codec);
+ } else {
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin",
+ ssp_codec);
+ }
+ if (!cpus->dai_name)
+ return -ENOMEM;
+
+ link->cpus = cpus;
+ link->num_cpus = 1;
+
+ /* codecs - caller to handle */
+
+ /* platforms */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ link->no_pcm = 1;
+
+ return 0;
+}
+
+static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum sof_dmic_be_type be_type)
+{
+ struct snd_soc_dai_link_component *cpus;
+
+ /* cpus */
+ cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ switch (be_type) {
+ case SOF_DMIC_01:
+ dev_dbg(dev, "link %d: dmic01\n", be_id);
+
+ link->name = "dmic01";
+ cpus->dai_name = "DMIC01 Pin";
+ break;
+ case SOF_DMIC_16K:
+ dev_dbg(dev, "link %d: dmic16k\n", be_id);
+
+ link->name = "dmic16k";
+ cpus->dai_name = "DMIC16k Pin";
+ break;
+ default:
+ dev_err(dev, "invalid be type %d\n", be_type);
+ return -EINVAL;
+ }
+
+ link->cpus = cpus;
+ link->num_cpus = 1;
+
+ /* codecs */
+ link->codecs = dmic_component;
+ link->num_codecs = ARRAY_SIZE(dmic_component);
+
+ /* platforms */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ if (be_type == SOF_DMIC_01)
+ link->init = dmic_init;
+ link->ignore_suspend = 1;
+ link->no_pcm = 1;
+ link->capture_only = 1;
+
+ return 0;
+}
+
+static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, int hdmi_id, bool idisp_codec)
+{
+ struct snd_soc_dai_link_component *cpus, *codecs;
+
+ dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id,
+ idisp_codec);
+
+ /* link name */
+ link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id);
+ if (!link->name)
+ return -ENOMEM;
+
+ /* cpus */
+ cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id);
+ if (!cpus->dai_name)
+ return -ENOMEM;
+
+ link->cpus = cpus;
+ link->num_cpus = 1;
+
+ /* codecs */
+ if (idisp_codec) {
+ codecs = devm_kzalloc(dev,
+ sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!codecs)
+ return -ENOMEM;
+
+ codecs->name = "ehdaudio0D2";
+ codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "intel-hdmi-hifi%d", hdmi_id);
+ if (!codecs->dai_name)
+ return -ENOMEM;
+
+ link->codecs = codecs;
+ } else {
+ link->codecs = &snd_soc_dummy_dlc;
+ }
+ link->num_codecs = 1;
+
+ /* platforms */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ link->init = (hdmi_id == 1) ? hdmi_init : NULL;
+ link->no_pcm = 1;
+ link->playback_only = 1;
+
+ return 0;
+}
+
+static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum snd_soc_acpi_intel_codec amp_type,
+ int ssp_amp)
+{
+ struct snd_soc_dai_link_component *cpus;
+
+ dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id,
+ snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp);
+
+ /* link name */
+ link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp);
+ if (!link->name)
+ return -ENOMEM;
+
+ /* cpus */
+ cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp);
+ if (!cpus->dai_name)
+ return -ENOMEM;
+
+ link->cpus = cpus;
+ link->num_cpus = 1;
+
+ /* codecs - caller to handle */
+
+ /* platforms */
+ /* feedback stream or firmware-generated echo reference */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ link->no_pcm = 1;
+
+ return 0;
+}
+
+static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, int ssp_bt)
+{
+ struct snd_soc_dai_link_component *cpus;
+
+ dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt);
+
+ /* link name */
+ link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt);
+ if (!link->name)
+ return -ENOMEM;
+
+ /* cpus */
+ cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt);
+ if (!cpus->dai_name)
+ return -ENOMEM;
+
+ link->cpus = cpus;
+ link->num_cpus = 1;
+
+ /* codecs */
+ link->codecs = &snd_soc_dummy_dlc;
+ link->num_codecs = 1;
+
+ /* platforms */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ link->no_pcm = 1;
+
+ return 0;
+}
+
+static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, int ssp_hdmi)
+{
+ struct snd_soc_dai_link_component *cpus;
+
+ dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi);
+
+ /* link name */
+ link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi);
+ if (!link->name)
+ return -ENOMEM;
+
+ /* cpus */
+ cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
+
+ cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi);
+ if (!cpus->dai_name)
+ return -ENOMEM;
+
+ link->cpus = cpus;
+ link->num_cpus = 1;
+
+ /* codecs */
+ link->codecs = &snd_soc_dummy_dlc;
+ link->num_codecs = 1;
+
+ /* platforms */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ link->no_pcm = 1;
+ link->capture_only = 1;
+
+ return 0;
+}
+
+static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link,
+ int be_id, enum sof_hda_be_type be_type)
+{
+ switch (be_type) {
+ case SOF_HDA_ANALOG:
+ dev_dbg(dev, "link %d: hda analog\n", be_id);
+
+ link->name = "Analog Playback and Capture";
+
+ /* cpus */
+ link->cpus = hda_analog_cpus;
+ link->num_cpus = ARRAY_SIZE(hda_analog_cpus);
+
+ /* codecs */
+ link->codecs = hda_analog_codecs;
+ link->num_codecs = ARRAY_SIZE(hda_analog_codecs);
+ break;
+ case SOF_HDA_DIGITAL:
+ dev_dbg(dev, "link %d: hda digital\n", be_id);
+
+ link->name = "Digital Playback and Capture";
+
+ /* cpus */
+ link->cpus = hda_digital_cpus;
+ link->num_cpus = ARRAY_SIZE(hda_digital_cpus);
+
+ /* codecs */
+ link->codecs = hda_digital_codecs;
+ link->num_codecs = ARRAY_SIZE(hda_digital_codecs);
+ break;
+ default:
+ dev_err(dev, "invalid be type %d\n", be_type);
+ return -EINVAL;
+ }
+
+ /* platforms */
+ link->platforms = platform_component;
+ link->num_platforms = ARRAY_SIZE(platform_component);
+
+ link->id = be_id;
+ if (be_type == SOF_HDA_ANALOG)
+ link->init = hda_init;
+ link->no_pcm = 1;
+
+ return 0;
+}
+
+static int calculate_num_links(struct sof_card_private *ctx)
+{
+ int num_links = 0;
+
+ /* headphone codec */
+ if (ctx->codec_type != CODEC_NONE)
+ num_links++;
+
+ /* dmic01 and dmic16k */
+ if (ctx->dmic_be_num > 0)
+ num_links++;
+
+ if (ctx->dmic_be_num > 1)
+ num_links++;
+
+ /* idisp HDMI */
+ num_links += ctx->hdmi_num;
+
+ /* speaker amp */
+ if (ctx->amp_type != CODEC_NONE)
+ num_links++;
+
+ /* BT audio offload */
+ if (ctx->bt_offload_present)
+ num_links++;
+
+ /* HDMI-In */
+ num_links += hweight32(ctx->ssp_mask_hdmi_in);
+
+ /* HDA external codec */
+ if (ctx->hda_codec_present)
+ num_links += 2;
+
+ return num_links;
+}
+
+int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
+{
+ struct snd_soc_dai_link *links;
+ int num_links;
+ int i;
+ int idx = 0;
+ int ret;
+ int ssp_hdmi_in = 0;
+ unsigned long link_order, link;
+ unsigned long link_ids, be_id;
+
+ num_links = calculate_num_links(ctx);
+
+ links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link),
+ GFP_KERNEL);
+ if (!links)
+ return -ENOMEM;
+
+ if (ctx->link_order_overwrite)
+ link_order = ctx->link_order_overwrite;
+ else
+ link_order = DEFAULT_LINK_ORDER;
+
+ if (ctx->link_id_overwrite)
+ link_ids = ctx->link_id_overwrite;
+ else
+ link_ids = 0;
+
+ dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n",
+ link_order, link_ids);
+
+ while (link_order) {
+ link = link_order & SOF_LINK_ORDER_MASK;
+ link_order >>= SOF_LINK_ORDER_SHIFT;
+
+ if (ctx->link_id_overwrite) {
+ be_id = link_ids & SOF_LINK_IDS_MASK;
+ link_ids >>= SOF_LINK_IDS_SHIFT;
+ } else {
+ /* use array index as link id */
+ be_id = idx;
+ }
+
+ switch (link) {
+ case SOF_LINK_CODEC:
+ /* headphone codec */
+ if (ctx->codec_type == CODEC_NONE)
+ continue;
+
+ ret = set_ssp_codec_link(dev, &links[idx], be_id,
+ ctx->codec_type, ctx->ssp_codec);
+ if (ret) {
+ dev_err(dev, "fail to set codec link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ctx->codec_link = &links[idx];
+ idx++;
+ break;
+ case SOF_LINK_DMIC01:
+ /* dmic01 */
+ if (ctx->dmic_be_num == 0)
+ continue;
+
+ /* at least we have dmic01 */
+ ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01);
+ if (ret) {
+ dev_err(dev, "fail to set dmic01 link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ break;
+ case SOF_LINK_DMIC16K:
+ /* dmic16k */
+ if (ctx->dmic_be_num <= 1)
+ continue;
+
+ /* set up 2 BE links at most */
+ ret = set_dmic_link(dev, &links[idx], be_id,
+ SOF_DMIC_16K);
+ if (ret) {
+ dev_err(dev, "fail to set dmic16k link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ break;
+ case SOF_LINK_IDISP_HDMI:
+ /* idisp HDMI */
+ for (i = 1; i <= ctx->hdmi_num; i++) {
+ ret = set_idisp_hdmi_link(dev, &links[idx],
+ be_id, i,
+ ctx->hdmi.idisp_codec);
+ if (ret) {
+ dev_err(dev, "fail to set hdmi link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ be_id++;
+ }
+ break;
+ case SOF_LINK_AMP:
+ /* speaker amp */
+ if (ctx->amp_type == CODEC_NONE)
+ continue;
+
+ ret = set_ssp_amp_link(dev, &links[idx], be_id,
+ ctx->amp_type, ctx->ssp_amp);
+ if (ret) {
+ dev_err(dev, "fail to set amp link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ctx->amp_link = &links[idx];
+ idx++;
+ break;
+ case SOF_LINK_BT_OFFLOAD:
+ /* BT audio offload */
+ if (!ctx->bt_offload_present)
+ continue;
+
+ ret = set_bt_offload_link(dev, &links[idx], be_id,
+ ctx->ssp_bt);
+ if (ret) {
+ dev_err(dev, "fail to set bt link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ break;
+ case SOF_LINK_HDMI_IN:
+ /* HDMI-In */
+ for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) {
+ ret = set_hdmi_in_link(dev, &links[idx], be_id,
+ ssp_hdmi_in);
+ if (ret) {
+ dev_err(dev, "fail to set hdmi-in link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ be_id++;
+ }
+ break;
+ case SOF_LINK_HDA:
+ /* HDA external codec */
+ if (!ctx->hda_codec_present)
+ continue;
+
+ ret = set_hda_codec_link(dev, &links[idx], be_id,
+ SOF_HDA_ANALOG);
+ if (ret) {
+ dev_err(dev, "fail to set hda analog link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ be_id++;
+
+ ret = set_hda_codec_link(dev, &links[idx], be_id,
+ SOF_HDA_DIGITAL);
+ if (ret) {
+ dev_err(dev, "fail to set hda digital link, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ idx++;
+ break;
+ case SOF_LINK_NONE:
+ /* caught here if it's not used as terminator in macro */
+ fallthrough;
+ default:
+ dev_err(dev, "invalid link type %ld\n", link);
+ return -EINVAL;
+ }
+ }
+
+ if (idx != num_links) {
+ dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx,
+ num_links);
+ return -EINVAL;
+ }
+
+ card->dai_link = links;
+ card->num_links = num_links;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, "SND_SOC_INTEL_SOF_BOARD_HELPERS");
+
+struct sof_card_private *
+sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk)
+{
+ struct sof_card_private *ctx;
+
+ dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk);
+
+ ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev);
+ ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev);
+
+ ctx->dmic_be_num = 2;
+ ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >>
+ SOF_NUM_IDISP_HDMI_SHIFT;
+ /* default number of HDMI DAI's */
+ if (!ctx->hdmi_num)
+ ctx->hdmi_num = 3;
+
+ /* port number/mask of peripherals attached to ssp interface */
+ if (ctx->codec_type != CODEC_NONE)
+ ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >>
+ SOF_SSP_PORT_CODEC_SHIFT;
+
+ if (ctx->amp_type != CODEC_NONE)
+ ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >>
+ SOF_SSP_PORT_AMP_SHIFT;
+
+ if (board_quirk & SOF_BT_OFFLOAD_PRESENT) {
+ ctx->bt_offload_present = true;
+ ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >>
+ SOF_SSP_PORT_BT_OFFLOAD_SHIFT;
+ }
+
+ ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >>
+ SOF_SSP_MASK_HDMI_CAPTURE_SHIFT;
+
+ return ctx;
+}
+EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, "SND_SOC_INTEL_SOF_BOARD_HELPERS");
+
+MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
+MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");
diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h
new file mode 100644
index 000000000000..33a9601b770c
--- /dev/null
+++ b/sound/soc/intel/boards/sof_board_helpers.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2023 Intel Corporation.
+ */
+
+#ifndef __SOF_INTEL_BOARD_HELPERS_H
+#define __SOF_INTEL_BOARD_HELPERS_H
+
+#include <sound/soc.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+#include "sof_hdmi_common.h"
+
+/*
+ * Common board quirks: from bit 8 to 31, LSB 8 bits reserved for machine
+ * drivers
+ */
+
+/* SSP port number for headphone codec: 3 bits */
+#define SOF_SSP_PORT_CODEC_SHIFT 8
+#define SOF_SSP_PORT_CODEC_MASK (GENMASK(10, 8))
+#define SOF_SSP_PORT_CODEC(quirk) \
+ (((quirk) << SOF_SSP_PORT_CODEC_SHIFT) & SOF_SSP_PORT_CODEC_MASK)
+
+/* SSP port number for speaker amplifier: 3 bits */
+#define SOF_SSP_PORT_AMP_SHIFT 11
+#define SOF_SSP_PORT_AMP_MASK (GENMASK(13, 11))
+#define SOF_SSP_PORT_AMP(quirk) \
+ (((quirk) << SOF_SSP_PORT_AMP_SHIFT) & SOF_SSP_PORT_AMP_MASK)
+
+/* SSP port number for BT audio offload: 3 bits */
+#define SOF_SSP_PORT_BT_OFFLOAD_SHIFT 14
+#define SOF_SSP_PORT_BT_OFFLOAD_MASK (GENMASK(16, 14))
+#define SOF_SSP_PORT_BT_OFFLOAD(quirk) \
+ (((quirk) << SOF_SSP_PORT_BT_OFFLOAD_SHIFT) & SOF_SSP_PORT_BT_OFFLOAD_MASK)
+
+/* SSP port mask for HDMI capture: 6 bits */
+#define SOF_SSP_MASK_HDMI_CAPTURE_SHIFT 17
+#define SOF_SSP_MASK_HDMI_CAPTURE_MASK (GENMASK(22, 17))
+#define SOF_SSP_MASK_HDMI_CAPTURE(quirk) \
+ (((quirk) << SOF_SSP_MASK_HDMI_CAPTURE_SHIFT) & SOF_SSP_MASK_HDMI_CAPTURE_MASK)
+
+/* Number of idisp HDMI BE link: 3 bits */
+#define SOF_NUM_IDISP_HDMI_SHIFT 23
+#define SOF_NUM_IDISP_HDMI_MASK (GENMASK(25, 23))
+#define SOF_NUM_IDISP_HDMI(quirk) \
+ (((quirk) << SOF_NUM_IDISP_HDMI_SHIFT) & SOF_NUM_IDISP_HDMI_MASK)
+
+/* Board uses BT audio offload */
+#define SOF_BT_OFFLOAD_PRESENT BIT(26)
+
+enum {
+ SOF_LINK_NONE = 0,
+ SOF_LINK_CODEC,
+ SOF_LINK_DMIC01,
+ SOF_LINK_DMIC16K,
+ SOF_LINK_IDISP_HDMI,
+ SOF_LINK_AMP,
+ SOF_LINK_BT_OFFLOAD,
+ SOF_LINK_HDMI_IN,
+ SOF_LINK_HDA,
+};
+
+#define SOF_LINK_ORDER_MASK (0xF)
+#define SOF_LINK_ORDER_SHIFT (4)
+
+#define SOF_LINK_ORDER(k1, k2, k3, k4, k5, k6, k7) \
+ ((((k1) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 0)) | \
+ (((k2) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 1)) | \
+ (((k3) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 2)) | \
+ (((k4) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 3)) | \
+ (((k5) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 4)) | \
+ (((k6) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 5)) | \
+ (((k7) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 6)))
+
+#define SOF_LINK_IDS_MASK (0xF)
+#define SOF_LINK_IDS_SHIFT (4)
+
+#define SOF_LINK_IDS(k1, k2, k3, k4, k5, k6, k7) \
+ ((((k1) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 0)) | \
+ (((k2) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 1)) | \
+ (((k3) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 2)) | \
+ (((k4) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 3)) | \
+ (((k5) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 4)) | \
+ (((k6) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 5)) | \
+ (((k7) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 6)))
+
+/*
+ * sof_da7219_private: private data for da7219 machine driver
+ *
+ * @mclk_en: true for mclk pin is connected
+ * @pll_bypass: true for PLL bypass mode
+ */
+struct sof_da7219_private {
+ bool mclk_en;
+ bool pll_bypass;
+};
+
+/*
+ * sof_rt5682_private: private data for rt5682 machine driver
+ *
+ * @mclk: mclk clock data
+ * @is_legacy_cpu: true for BYT/CHT boards
+ * @mclk_en: true for mclk pin is connected
+ */
+struct sof_rt5682_private {
+ struct clk *mclk;
+ bool is_legacy_cpu;
+ bool mclk_en;
+};
+
+/*
+ * sof_card_private: common data for machine drivers
+ *
+ * @headset_jack: headset jack data
+ * @hdmi: init data for hdmi dai link
+ * @codec_type: type of headset codec
+ * @amp_type: type of speaker amplifier
+ * @dmic_be_num: number of Intel PCH DMIC BE link
+ * @hdmi_num: number of Intel HDMI BE link
+ * @ssp_codec: ssp port number of headphone BE link
+ * @ssp_amp: ssp port number of speaker BE link
+ * @ssp_bt: ssp port number of BT offload BE link
+ * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link
+ * @bt_offload_present: true to create BT offload BE link
+ * @hda_codec_present: true to create HDA codec BE links
+ * @codec_link: pointer to headset codec dai link
+ * @amp_link: pointer to speaker amplifier dai link
+ * @link_order_overwrite: custom DAI link order
+ * @link_id_overwrite: custom DAI link ID
+ * @da7219: private data for da7219 machine driver
+ * @rt5682: private data for rt5682 machine driver
+ */
+struct sof_card_private {
+ struct snd_soc_jack headset_jack;
+ struct sof_hdmi_private hdmi;
+
+ enum snd_soc_acpi_intel_codec codec_type;
+ enum snd_soc_acpi_intel_codec amp_type;
+
+ int dmic_be_num;
+ int hdmi_num;
+
+ int ssp_codec;
+ int ssp_amp;
+ int ssp_bt;
+ unsigned long ssp_mask_hdmi_in;
+
+ bool bt_offload_present;
+ bool hda_codec_present;
+
+ struct snd_soc_dai_link *codec_link;
+ struct snd_soc_dai_link *amp_link;
+
+ unsigned long link_order_overwrite;
+ /*
+ * A variable stores id for all BE DAI links, use SOF_LINK_IDS macro to
+ * build the value; use DAI link array index as id if zero.
+ */
+ unsigned long link_id_overwrite;
+
+ union {
+ struct sof_da7219_private da7219;
+ struct sof_rt5682_private rt5682;
+ };
+};
+
+int sof_intel_board_card_late_probe(struct snd_soc_card *card);
+int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx);
+struct sof_card_private *
+sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk);
+
+#endif /* __SOF_INTEL_BOARD_HELPERS_H */
diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c
index 8b8b07e4f2fe..88fc6cb2bfd4 100644
--- a/sound/soc/intel/boards/sof_cirrus_common.c
+++ b/sound/soc/intel/boards/sof_cirrus_common.c
@@ -48,9 +48,10 @@ static struct snd_soc_codec_conf cs35l41_codec_conf[CS35L41_MAX_AMPS];
static int cs35l41_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, cs35l41_dapm_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, cs35l41_dapm_widgets,
ARRAY_SIZE(cs35l41_dapm_widgets));
if (ret) {
dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);
@@ -64,7 +65,7 @@ static int cs35l41_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, cs35l41_dapm_routes,
+ ret = snd_soc_dapm_add_routes(dapm, cs35l41_dapm_routes,
ARRAY_SIZE(cs35l41_dapm_routes));
if (ret)
@@ -91,7 +92,7 @@ static const struct {
static int cs35l41_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int clk_freq, i, ret;
@@ -193,14 +194,14 @@ void cs35l41_set_dai_link(struct snd_soc_dai_link *link)
link->init = cs35l41_init;
link->ops = &cs35l41_ops;
}
-EXPORT_SYMBOL_NS(cs35l41_set_dai_link, SND_SOC_INTEL_SOF_CIRRUS_COMMON);
+EXPORT_SYMBOL_NS(cs35l41_set_dai_link, "SND_SOC_INTEL_SOF_CIRRUS_COMMON");
void cs35l41_set_codec_conf(struct snd_soc_card *card)
{
card->codec_conf = cs35l41_codec_conf;
card->num_configs = ARRAY_SIZE(cs35l41_codec_conf);
}
-EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, SND_SOC_INTEL_SOF_CIRRUS_COMMON);
+EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, "SND_SOC_INTEL_SOF_CIRRUS_COMMON");
MODULE_DESCRIPTION("ASoC Intel SOF Cirrus Logic helpers");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/boards/sof_cirrus_common.h b/sound/soc/intel/boards/sof_cirrus_common.h
index ca438c12c386..1c87637b9ef7 100644
--- a/sound/soc/intel/boards/sof_cirrus_common.h
+++ b/sound/soc/intel/boards/sof_cirrus_common.h
@@ -9,15 +9,16 @@
#define __SOF_CIRRUS_COMMON_H
#include <sound/soc.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
/*
* Cirrus Logic CS35L41/CS35L53
*/
#define CS35L41_CODEC_DAI "cs35l41-pcm"
-#define CS35L41_DEV0_NAME "i2c-CSC3541:00"
-#define CS35L41_DEV1_NAME "i2c-CSC3541:01"
-#define CS35L41_DEV2_NAME "i2c-CSC3541:02"
-#define CS35L41_DEV3_NAME "i2c-CSC3541:03"
+#define CS35L41_DEV0_NAME "i2c-" CS35L41_ACPI_HID ":00"
+#define CS35L41_DEV1_NAME "i2c-" CS35L41_ACPI_HID ":01"
+#define CS35L41_DEV2_NAME "i2c-" CS35L41_ACPI_HID ":02"
+#define CS35L41_DEV3_NAME "i2c-" CS35L41_ACPI_HID ":03"
void cs35l41_set_dai_link(struct snd_soc_dai_link *link);
void cs35l41_set_codec_conf(struct snd_soc_card *card);
diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c
index e6695e77d594..455c5bc8c634 100644
--- a/sound/soc/intel/boards/sof_cs42l42.c
+++ b/sound/soc/intel/boards/sof_cs42l42.c
@@ -19,45 +19,10 @@
#include <sound/sof.h>
#include <sound/soc-acpi.h>
#include <dt-bindings/sound/cs42l42.h>
-#include "../../codecs/hdac_hdmi.h"
#include "../common/soc-intel-quirks.h"
-#include "hda_dsp_common.h"
+#include "sof_board_helpers.h"
#include "sof_maxim_common.h"
-#define NAME_SIZE 32
-
-#define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
-#define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0))
-#define SOF_SPEAKER_AMP_PRESENT BIT(3)
-#define SOF_CS42L42_SSP_AMP_SHIFT 4
-#define SOF_CS42L42_SSP_AMP_MASK (GENMASK(6, 4))
-#define SOF_CS42L42_SSP_AMP(quirk) \
- (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
-#define SOF_CS42L42_NUM_HDMIDEV_SHIFT 7
-#define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7))
-#define SOF_CS42L42_NUM_HDMIDEV(quirk) \
- (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
-#define SOF_CS42L42_DAILINK_SHIFT 10
-#define SOF_CS42L42_DAILINK_MASK (GENMASK(24, 10))
-#define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
- ((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
-#define SOF_BT_OFFLOAD_PRESENT BIT(25)
-#define SOF_CS42L42_SSP_BT_SHIFT 26
-#define SOF_CS42L42_SSP_BT_MASK (GENMASK(28, 26))
-#define SOF_CS42L42_SSP_BT(quirk) \
- (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
-#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(29)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(30)
-
-enum {
- LINK_NONE = 0,
- LINK_HP = 1,
- LINK_SPK = 2,
- LINK_DMIC = 3,
- LINK_HDMI = 4,
- LINK_BT = 5,
-};
-
static struct snd_soc_jack_pin jack_pins[] = {
{
.pin = "Headphone Jack",
@@ -70,44 +35,12 @@ static struct snd_soc_jack_pin jack_pins[] = {
};
/* Default: SSP2 */
-static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
-
-struct sof_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- struct snd_soc_jack hdmi_jack;
- int device;
-};
-
-struct sof_card_private {
- struct snd_soc_jack headset_jack;
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
-};
-
-static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct sof_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- /* dai_link id is 1:1 mapped to the PCM device */
- pcm->device = rtd->dai_link->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
+static unsigned long sof_cs42l42_quirk = SOF_SSP_PORT_CODEC(2);
static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
struct snd_soc_jack *jack = &ctx->headset_jack;
int ret;
@@ -143,7 +76,7 @@ static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(component, NULL, NULL);
}
@@ -151,8 +84,8 @@ static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int clk_freq, ret;
clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
@@ -175,48 +108,9 @@ static const struct snd_soc_ops sof_cs42l42_ops = {
.hw_params = sof_cs42l42_hw_params,
};
-static struct snd_soc_dai_link_component platform_component[] = {
- {
- /* name might be overridden during probe */
- .name = "0000:00:1f.3"
- }
-};
-
static int sof_card_late_probe(struct snd_soc_card *card)
{
- struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = NULL;
- char jack_name[NAME_SIZE];
- struct sof_hdmi_pcm *pcm;
- int err;
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &pcm->hdmi_jack);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &pcm->hdmi_jack);
- if (err < 0)
- return err;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
+ return sof_intel_board_card_late_probe(card);
}
static const struct snd_kcontrol_new sof_controls[] = {
@@ -229,10 +123,6 @@ static const struct snd_soc_dapm_widget sof_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
-static const struct snd_soc_dapm_widget dmic_widgets[] = {
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
static const struct snd_soc_dapm_route sof_map[] = {
/* HP jack connectors - unknown if we have jack detection */
{"Headphone Jack", NULL, "HP"},
@@ -241,33 +131,6 @@ static const struct snd_soc_dapm_route sof_map[] = {
{"HS", NULL, "Headset Mic"},
};
-static const struct snd_soc_dapm_route dmic_map[] = {
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-};
-
-static int dmic_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
- ARRAY_SIZE(dmic_widgets));
- if (ret) {
- dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
- /* Don't need to add routes if widget addition failed */
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
- ARRAY_SIZE(dmic_map));
-
- if (ret)
- dev_err(card->dev, "DMic map addition failed: %d\n", ret);
-
- return ret;
-}
-
/* sof audio machine driver for cs42l42 codec */
static struct snd_soc_card sof_audio_card_cs42l42 = {
.name = "cs42l42", /* the sof- prefix is added by the core */
@@ -289,379 +152,90 @@ static struct snd_soc_dai_link_component cs42l42_component[] = {
}
};
-static struct snd_soc_dai_link_component dmic_component[] = {
- {
- .name = "dmic-codec",
- .dai_name = "dmic-hifi",
- }
-};
-
-static int create_spk_amp_dai_links(struct device *dev,
- struct snd_soc_dai_link *links,
- struct snd_soc_dai_link_component *cpus,
- int *id, int ssp_amp)
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
{
- int ret = 0;
-
- /* speaker amp */
- if (!(sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT))
- return 0;
-
- links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
- ssp_amp);
- if (!links[*id].name) {
- ret = -ENOMEM;
- goto devm_err;
- }
-
- links[*id].id = *id;
+ int ret;
- if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) {
- max_98357a_dai_link(&links[*id]);
- } else if (sof_cs42l42_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
- max_98360a_dai_link(&links[*id]);
- } else {
- dev_err(dev, "no amp defined\n");
- ret = -EINVAL;
- goto devm_err;
- }
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
- links[*id].platforms = platform_component;
- links[*id].num_platforms = ARRAY_SIZE(platform_component);
- links[*id].dpcm_playback = 1;
- /* firmware-generated echo reference */
- links[*id].dpcm_capture = 1;
-
- links[*id].no_pcm = 1;
- links[*id].cpus = &cpus[*id];
- links[*id].num_cpus = 1;
-
- links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin", ssp_amp);
- if (!links[*id].cpus->dai_name) {
- ret = -ENOMEM;
- goto devm_err;
+ if (!ctx->codec_link) {
+ dev_err(dev, "codec link not available");
+ return -EINVAL;
}
- (*id)++;
-
-devm_err:
- return ret;
-}
-
-static int create_hp_codec_dai_links(struct device *dev,
- struct snd_soc_dai_link *links,
- struct snd_soc_dai_link_component *cpus,
- int *id, int ssp_codec)
-{
- /* codec SSP */
- links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
- ssp_codec);
- if (!links[*id].name)
- goto devm_err;
-
- links[*id].id = *id;
- links[*id].codecs = cs42l42_component;
- links[*id].num_codecs = ARRAY_SIZE(cs42l42_component);
- links[*id].platforms = platform_component;
- links[*id].num_platforms = ARRAY_SIZE(platform_component);
- links[*id].init = sof_cs42l42_init;
- links[*id].exit = sof_cs42l42_exit;
- links[*id].ops = &sof_cs42l42_ops;
- links[*id].dpcm_playback = 1;
- links[*id].dpcm_capture = 1;
- links[*id].no_pcm = 1;
- links[*id].cpus = &cpus[*id];
- links[*id].num_cpus = 1;
-
- links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin",
- ssp_codec);
- if (!links[*id].cpus->dai_name)
- goto devm_err;
-
- (*id)++;
-
- return 0;
-
-devm_err:
- return -ENOMEM;
-}
+ /* codec-specific fields for headphone codec */
+ ctx->codec_link->codecs = cs42l42_component;
+ ctx->codec_link->num_codecs = ARRAY_SIZE(cs42l42_component);
+ ctx->codec_link->init = sof_cs42l42_init;
+ ctx->codec_link->exit = sof_cs42l42_exit;
+ ctx->codec_link->ops = &sof_cs42l42_ops;
-static int create_dmic_dai_links(struct device *dev,
- struct snd_soc_dai_link *links,
- struct snd_soc_dai_link_component *cpus,
- int *id, int dmic_be_num)
-{
- int i;
-
- /* dmic */
- if (dmic_be_num <= 0)
+ if (ctx->amp_type == CODEC_NONE)
return 0;
- /* at least we have dmic01 */
- links[*id].name = "dmic01";
- links[*id].cpus = &cpus[*id];
- links[*id].cpus->dai_name = "DMIC01 Pin";
- links[*id].init = dmic_init;
- if (dmic_be_num > 1) {
- /* set up 2 BE links at most */
- links[*id + 1].name = "dmic16k";
- links[*id + 1].cpus = &cpus[*id + 1];
- links[*id + 1].cpus->dai_name = "DMIC16k Pin";
- dmic_be_num = 2;
- }
-
- for (i = 0; i < dmic_be_num; i++) {
- links[*id].id = *id;
- links[*id].num_cpus = 1;
- links[*id].codecs = dmic_component;
- links[*id].num_codecs = ARRAY_SIZE(dmic_component);
- links[*id].platforms = platform_component;
- links[*id].num_platforms = ARRAY_SIZE(platform_component);
- links[*id].ignore_suspend = 1;
- links[*id].dpcm_capture = 1;
- links[*id].no_pcm = 1;
-
- (*id)++;
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
}
- return 0;
-}
-
-static int create_hdmi_dai_links(struct device *dev,
- struct snd_soc_dai_link *links,
- struct snd_soc_dai_link_component *cpus,
- int *id, int hdmi_num)
-{
- struct snd_soc_dai_link_component *idisp_components;
- int i;
-
- /* HDMI */
- if (hdmi_num <= 0)
- return 0;
-
- idisp_components = devm_kcalloc(dev,
- hdmi_num,
- sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
- if (!idisp_components)
- goto devm_err;
-
- for (i = 1; i <= hdmi_num; i++) {
- links[*id].name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d", i);
- if (!links[*id].name)
- goto devm_err;
-
- links[*id].id = *id;
- links[*id].cpus = &cpus[*id];
- links[*id].num_cpus = 1;
- links[*id].cpus->dai_name = devm_kasprintf(dev,
- GFP_KERNEL,
- "iDisp%d Pin",
- i);
- if (!links[*id].cpus->dai_name)
- goto devm_err;
-
- idisp_components[i - 1].name = "ehdaudio0D2";
- idisp_components[i - 1].dai_name = devm_kasprintf(dev,
- GFP_KERNEL,
- "intel-hdmi-hifi%d",
- i);
- if (!idisp_components[i - 1].dai_name)
- goto devm_err;
-
- links[*id].codecs = &idisp_components[i - 1];
- links[*id].num_codecs = 1;
- links[*id].platforms = platform_component;
- links[*id].num_platforms = ARRAY_SIZE(platform_component);
- links[*id].init = sof_hdmi_init;
- links[*id].dpcm_playback = 1;
- links[*id].no_pcm = 1;
-
- (*id)++;
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98357A:
+ max_98357a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98360A:
+ max_98360a_dai_link(ctx->amp_link);
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
return 0;
-
-devm_err:
- return -ENOMEM;
}
-static int create_bt_offload_dai_links(struct device *dev,
- struct snd_soc_dai_link *links,
- struct snd_soc_dai_link_component *cpus,
- int *id, int ssp_bt)
-{
- /* bt offload */
- if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT))
- return 0;
-
- links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT",
- ssp_bt);
- if (!links[*id].name)
- goto devm_err;
-
- links[*id].id = *id;
- links[*id].codecs = &asoc_dummy_dlc;
- links[*id].num_codecs = 1;
- links[*id].platforms = platform_component;
- links[*id].num_platforms = ARRAY_SIZE(platform_component);
-
- links[*id].dpcm_playback = 1;
- links[*id].dpcm_capture = 1;
- links[*id].no_pcm = 1;
- links[*id].cpus = &cpus[*id];
- links[*id].num_cpus = 1;
-
- links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin",
- ssp_bt);
- if (!links[*id].cpus->dai_name)
- goto devm_err;
-
- (*id)++;
-
- return 0;
-
-devm_err:
- return -ENOMEM;
-}
-
-static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
- int ssp_codec,
- int ssp_amp,
- int ssp_bt,
- int dmic_be_num,
- int hdmi_num)
-{
- struct snd_soc_dai_link_component *cpus;
- struct snd_soc_dai_link *links;
- int ret, id = 0, link_seq;
-
- links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
- sizeof(struct snd_soc_dai_link), GFP_KERNEL);
- cpus = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
- sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
- if (!links || !cpus)
- goto devm_err;
-
- link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT;
-
- while (link_seq) {
- int link_type = link_seq & 0x07;
-
- switch (link_type) {
- case LINK_HP:
- ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec);
- if (ret < 0) {
- dev_err(dev, "fail to create hp codec dai links, ret %d\n",
- ret);
- goto devm_err;
- }
- break;
- case LINK_SPK:
- ret = create_spk_amp_dai_links(dev, links, cpus, &id, ssp_amp);
- if (ret < 0) {
- dev_err(dev, "fail to create spk amp dai links, ret %d\n",
- ret);
- goto devm_err;
- }
- break;
- case LINK_DMIC:
- ret = create_dmic_dai_links(dev, links, cpus, &id, dmic_be_num);
- if (ret < 0) {
- dev_err(dev, "fail to create dmic dai links, ret %d\n",
- ret);
- goto devm_err;
- }
- break;
- case LINK_HDMI:
- ret = create_hdmi_dai_links(dev, links, cpus, &id, hdmi_num);
- if (ret < 0) {
- dev_err(dev, "fail to create hdmi dai links, ret %d\n",
- ret);
- goto devm_err;
- }
- break;
- case LINK_BT:
- ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt);
- if (ret < 0) {
- dev_err(dev, "fail to create bt offload dai links, ret %d\n",
- ret);
- goto devm_err;
- }
- break;
- case LINK_NONE:
- /* caught here if it's not used as terminator in macro */
- default:
- dev_err(dev, "invalid link type %d\n", link_type);
- goto devm_err;
- }
-
- link_seq >>= 3;
- }
-
- return links;
-devm_err:
- return NULL;
-}
+#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
+ SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
static int sof_audio_probe(struct platform_device *pdev)
{
- struct snd_soc_dai_link *dai_links;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct sof_card_private *ctx;
- int dmic_be_num, hdmi_num;
- int ret, ssp_bt, ssp_amp, ssp_codec;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ int ret;
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
- mach = pdev->dev.platform_data;
-
- if (soc_intel_is_glk()) {
- dmic_be_num = 1;
- hdmi_num = 3;
- } else {
- dmic_be_num = 2;
- hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
- SOF_CS42L42_NUM_HDMIDEV_SHIFT;
- /* default number of HDMI DAI's */
- if (!hdmi_num)
- hdmi_num = 3;
- }
-
dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
- ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
- SOF_CS42L42_SSP_BT_SHIFT;
-
- ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
- SOF_CS42L42_SSP_AMP_SHIFT;
-
- ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
-
- /* compute number of dai links */
- sof_audio_card_cs42l42.num_links = 1 + dmic_be_num + hdmi_num;
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_cs42l42_quirk);
+ if (!ctx)
+ return -ENOMEM;
- if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT)
- sof_audio_card_cs42l42.num_links++;
- if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)
- sof_audio_card_cs42l42.num_links++;
+ if (soc_intel_is_glk()) {
+ ctx->dmic_be_num = 1;
- dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
- ssp_bt, dmic_be_num, hdmi_num);
- if (!dai_links)
- return -ENOMEM;
+ /* overwrite the DAI link order for GLK boards */
+ ctx->link_order_overwrite = GLK_LINK_ORDER;
+ }
- sof_audio_card_cs42l42.dai_link = dai_links;
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
+ ctx->hdmi.idisp_codec = true;
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx);
+ if (ret)
+ return ret;
sof_audio_card_cs42l42.dev = &pdev->dev;
@@ -671,8 +245,6 @@ static int sof_audio_probe(struct platform_device *pdev)
if (ret)
return ret;
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
return devm_snd_soc_register_card(&pdev->dev,
@@ -682,30 +254,36 @@ static int sof_audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
.name = "glk_cs4242_mx98357a",
- .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98357A_SPEAKER_AMP_PRESENT |
- SOF_CS42L42_SSP_AMP(1)) |
- SOF_CS42L42_DAILINK(LINK_SPK, LINK_HP, LINK_DMIC, LINK_HDMI, LINK_NONE),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(1)),
},
{
.name = "jsl_cs4242_mx98360a",
- .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_CS42L42_SSP_AMP(1)) |
- SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
+ },
+ {
+ .name = "adl_cs42l42_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_SSP_PORT_BT_OFFLOAD(2)),
+ },
+ {
+ .name = "rpl_cs42l42_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_SSP_PORT_BT_OFFLOAD(2)),
},
{
- .name = "adl_mx98360a_cs4242",
- .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_CS42L42_SSP_AMP(1) |
- SOF_CS42L42_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_PRESENT |
- SOF_CS42L42_SSP_BT(2) |
- SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)),
+ .name = "mtl_cs42l42_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_BT_OFFLOAD_PRESENT |
+ SOF_SSP_PORT_BT_OFFLOAD(1)),
},
{ }
};
@@ -725,5 +303,5 @@ module_platform_driver(sof_audio)
MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON");
diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c
new file mode 100644
index 000000000000..ad845d32f642
--- /dev/null
+++ b/sound/soc/intel/boards/sof_da7219.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright(c) 2019 Intel Corporation.
+
+/*
+ * Intel SOF Machine driver for Dialog headphone codec
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/sof.h>
+#include "../../codecs/da7219.h"
+#include "sof_board_helpers.h"
+#include "sof_maxim_common.h"
+
+/* Driver-specific board quirks: from bit 0 to 7 */
+#define SOF_DA7219_GLK_BOARD BIT(0)
+#define SOF_DA7219_CML_BOARD BIT(1)
+#define SOF_DA7219_JSL_BOARD BIT(2)
+#define SOF_DA7219_MCLK_EN BIT(3)
+
+#define DIALOG_CODEC_DAI "da7219-hifi"
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+
+ if (ctx->da7219.pll_bypass)
+ return ret;
+
+ /* PLL SRM mode */
+ codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
+ 0, 0);
+ if (ret)
+ dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+ dev_dbg(card->dev, "pll srm mode\n");
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+ 0, DA7219_PLL_FREQ_OUT_98304);
+ if (ret)
+ dev_err(card->dev, "failed to start PLL: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
+};
+
+static const struct snd_soc_dapm_widget widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_POST_PMD |
+ SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ { "Headphone Jack", NULL, "HPL" },
+ { "Headphone Jack", NULL, "HPR" },
+
+ { "MIC", NULL, "Headset Mic" },
+
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_jack_pin jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_jack *jack = &ctx->headset_jack;
+ int mclk_rate, ret;
+
+ mclk_rate = sof_dai_get_mclk(rtd);
+ if (mclk_rate <= 0) {
+ dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Use PLL bypass mode if MCLK is available, be sure to set the
+ * frequency of MCLK to 12.288 or 24.576MHz on topology side.
+ */
+ if (ctx->da7219.mclk_en &&
+ (mclk_rate == 12288000 || mclk_rate == 24576000)) {
+ /* PLL bypass mode */
+ dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate);
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+ if (ret) {
+ dev_err(rtd->dev, "fail to set pll, ret %d\n", ret);
+ return ret;
+ }
+
+ ctx->da7219.pll_bypass = true;
+ }
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ 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 | SND_JACK_LINEOUT,
+ jack, jack_pins, ARRAY_SIZE(jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "fail to set component jack, ret %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int card_late_probe(struct snd_soc_card *card)
+{
+ struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int err;
+
+ if (ctx->amp_type == CODEC_MAX98373) {
+ /* Disable Left and Right Spk pin after boot */
+ snd_soc_dapm_disable_pin(dapm, "Left Spk");
+ snd_soc_dapm_disable_pin(dapm, "Right Spk");
+ err = snd_soc_dapm_sync(dapm);
+ if (err < 0)
+ return err;
+ }
+
+ return sof_intel_board_card_late_probe(card);
+}
+
+static struct snd_soc_card card_da7219 = {
+ .name = "da7219", /* the sof- prefix is added by the core */
+ .owner = THIS_MODULE,
+ .controls = controls,
+ .num_controls = ARRAY_SIZE(controls),
+ .dapm_widgets = widgets,
+ .num_dapm_widgets = ARRAY_SIZE(widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+ .fully_routed = true,
+ .late_probe = card_late_probe,
+};
+
+static struct snd_soc_dai_link_component da7219_component[] = {
+ {
+ .name = "i2c-DLGS7219:00",
+ .dai_name = DIALOG_CODEC_DAI,
+ }
+};
+
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
+{
+ int ret;
+
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
+
+ if (!ctx->codec_link) {
+ dev_err(dev, "codec link not available");
+ return -EINVAL;
+ }
+
+ /* codec-specific fields for headphone codec */
+ ctx->codec_link->codecs = da7219_component;
+ ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component);
+ ctx->codec_link->init = da7219_codec_init;
+ ctx->codec_link->exit = da7219_codec_exit;
+
+ if (ctx->amp_type == CODEC_NONE)
+ return 0;
+
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
+ }
+
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98357A:
+ max_98357a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98360A:
+ max_98360a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98373:
+ max_98373_dai_link(dev, ctx->amp_link);
+ break;
+ case CODEC_MAX98390:
+ max_98390_dai_link(dev, ctx->amp_link);
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
+ SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
+
+#define CML_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
+ SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
+
+#define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
+ SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
+
+static int audio_probe(struct platform_device *pdev)
+{
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
+ struct sof_card_private *ctx;
+ char *card_name;
+ unsigned long board_quirk = 0;
+ int ret;
+
+ if (pdev->id_entry && pdev->id_entry->driver_data)
+ board_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+ dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
+
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk);
+ if (!ctx)
+ return -ENOMEM;
+
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
+ ctx->hdmi.idisp_codec = true;
+
+ if (board_quirk & SOF_DA7219_GLK_BOARD) {
+ /* dmic16k not support */
+ ctx->dmic_be_num = 1;
+
+ /* overwrite the DAI link order for GLK boards */
+ ctx->link_order_overwrite = GLK_LINK_ORDER;
+
+ /* backward-compatible with existing devices */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98357A:
+ card_name = devm_kstrdup(&pdev->dev, "glkda7219max",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ card_da7219.name = card_name;
+ break;
+ default:
+ break;
+ }
+ } else if (board_quirk & SOF_DA7219_CML_BOARD) {
+ /* overwrite the DAI link order for CML boards */
+ ctx->link_order_overwrite = CML_LINK_ORDER;
+
+ /* backward-compatible with existing devices */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98357A:
+ card_name = devm_kstrdup(&pdev->dev, "cmlda7219max",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ card_da7219.name = card_name;
+ break;
+ case CODEC_MAX98390:
+ card_name = devm_kstrdup(&pdev->dev,
+ "cml_max98390_da7219",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ card_da7219.name = card_name;
+ break;
+ default:
+ break;
+ }
+ } else if (board_quirk & SOF_DA7219_JSL_BOARD) {
+ /* overwrite the DAI link order for JSL boards */
+ ctx->link_order_overwrite = JSL_LINK_ORDER;
+
+ /* backward-compatible with existing devices */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98360A:
+ card_name = devm_kstrdup(&pdev->dev, "da7219max98360a",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ card_da7219.name = card_name;
+ break;
+ case CODEC_MAX98373:
+ card_name = devm_kstrdup(&pdev->dev, "da7219max",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ card_da7219.name = card_name;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (board_quirk & SOF_DA7219_MCLK_EN)
+ ctx->da7219.mclk_en = true;
+
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx);
+ if (ret)
+ return ret;
+
+ /* update codec_conf */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98373:
+ max_98373_set_codec_conf(&card_da7219);
+ break;
+ case CODEC_MAX98390:
+ max_98390_set_codec_conf(&pdev->dev, &card_da7219);
+ break;
+ case CODEC_MAX98357A:
+ case CODEC_MAX98360A:
+ case CODEC_NONE:
+ /* no codec conf required */
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
+ }
+
+ card_da7219.dev = &pdev->dev;
+
+ ret = snd_soc_fixup_dai_links_platform_name(&card_da7219,
+ mach->mach_params.platform);
+ if (ret)
+ return ret;
+
+ snd_soc_card_set_drvdata(&card_da7219, ctx);
+
+ return devm_snd_soc_register_card(&pdev->dev, &card_da7219);
+}
+
+static const struct platform_device_id board_ids[] = {
+ {
+ .name = "glk_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_GLK_BOARD |
+ SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(1)),
+ },
+ {
+ .name = "cml_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_CML_BOARD |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
+ },
+ {
+ .name = "jsl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
+ },
+ {
+ .name = "adl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
+ },
+ {
+ .name = "rpl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
+ },
+ {
+ .name = "mtl_da7219_def",
+ .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
+ SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_SSP_PORT_BT_OFFLOAD(1) |
+ SOF_BT_OFFLOAD_PRESENT),
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, board_ids);
+
+static struct platform_driver audio = {
+ .probe = audio_probe,
+ .driver = {
+ .name = "sof_da7219",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = board_ids,
+};
+module_platform_driver(audio)
+
+/* Module information */
+MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec");
+MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON");
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
deleted file mode 100644
index 740aa11cb019..000000000000
--- a/sound/soc/intel/boards/sof_da7219_max98373.c
+++ /dev/null
@@ -1,472 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2019 Intel Corporation.
-
-/*
- * Intel SOF Machine driver for DA7219 + MAX98373/MAX98360A codec
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <linux/platform_device.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "../../codecs/da7219.h"
-#include "hda_dsp_common.h"
-
-#define DIALOG_CODEC_DAI "da7219-hifi"
-#define MAX98373_CODEC_DAI "max98373-aif1"
-#define MAXIM_DEV0_NAME "i2c-MX98373:00"
-#define MAXIM_DEV1_NAME "i2c-MX98373:01"
-
-struct hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct card_private {
- struct snd_soc_jack headset;
- struct list_head hdmi_pcm_list;
- struct snd_soc_jack hdmi[3];
-};
-
-static int platform_clock_control(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_card *card = dapm->card;
- struct snd_soc_dai *codec_dai;
- int ret = 0;
-
- codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
- if (!codec_dai) {
- dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
- return -EIO;
- }
-
- if (SND_SOC_DAPM_EVENT_OFF(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
- 0, 0);
- if (ret)
- dev_err(card->dev, "failed to stop PLL: %d\n", ret);
- } else if (SND_SOC_DAPM_EVENT_ON(event)) {
- ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
- 0, DA7219_PLL_FREQ_OUT_98304);
- if (ret)
- dev_err(card->dev, "failed to start PLL: %d\n", ret);
- }
-
- return ret;
-}
-
-static const struct snd_kcontrol_new controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_kcontrol_new m98360a_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
-};
-
-/* For MAX98373 amp */
-static const struct snd_soc_dapm_widget widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
-
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_POST_PMD |
- SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- { "Headphone Jack", NULL, "HPL" },
- { "Headphone Jack", NULL, "HPR" },
-
- { "MIC", NULL, "Headset Mic" },
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-
- { "Left Spk", NULL, "Left BE_OUT" },
- { "Right Spk", NULL, "Right BE_OUT" },
-
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-};
-
-/* For MAX98360A amp */
-static const struct snd_soc_dapm_widget max98360a_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
-
- SND_SOC_DAPM_SPK("Spk", NULL),
-
- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
- platform_clock_control, SND_SOC_DAPM_POST_PMD |
- SND_SOC_DAPM_PRE_PMU),
-
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
-static const struct snd_soc_dapm_route max98360a_map[] = {
- { "Headphone Jack", NULL, "HPL" },
- { "Headphone Jack", NULL, "HPR" },
-
- { "MIC", NULL, "Headset Mic" },
-
- { "Headphone Jack", NULL, "Platform Clock" },
- { "Headset Mic", NULL, "Platform Clock" },
-
- {"Spk", NULL, "Speaker"},
-
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-};
-
-static struct snd_soc_jack_pin jack_pins[] = {
- {
- .pin = "Headphone Jack",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static struct snd_soc_jack headset;
-
-static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
- struct snd_soc_jack *jack;
- int ret;
-
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000,
- SND_SOC_CLOCK_IN);
- if (ret) {
- dev_err(rtd->dev, "can't set codec sysclk configuration\n");
- return ret;
- }
-
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- 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 | SND_JACK_LINEOUT,
- &headset,
- jack_pins,
- ARRAY_SIZE(jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- jack = &headset;
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
- snd_soc_component_set_jack(component, jack, NULL);
-
- return ret;
-}
-
-static int ssp1_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
- int ret, j;
-
- for (j = 0; j < runtime->dai_link->num_codecs; j++) {
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, j);
-
- if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
- /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16);
- if (ret < 0) {
- dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
- /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16);
- if (ret < 0) {
- dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static struct snd_soc_ops ssp1_ops = {
- .hw_params = ssp1_hw_params,
-};
-
-static struct snd_soc_codec_conf max98373_codec_conf[] = {
- {
- .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
- .name_prefix = "Right",
- },
- {
- .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
- .name_prefix = "Left",
- },
-};
-
-static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- pcm->device = dai->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-static int card_late_probe(struct snd_soc_card *card)
-{
- struct card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_acpi_mach *mach = (card->dev)->platform_data;
- struct hdmi_pcm *pcm;
-
- if (mach->mach_params.common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
- head);
- return hda_dsp_hdmi_build_controls(card,
- pcm->codec_dai->component);
- }
-
- return -EINVAL;
-}
-
-SND_SOC_DAILINK_DEF(ssp0_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
-SND_SOC_DAILINK_DEF(ssp0_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
-SND_SOC_DAILINK_DEF(ssp1_amps,
- DAILINK_COMP_ARRAY(
- /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI),
- /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI)));
-
-SND_SOC_DAILINK_DEF(ssp1_m98360a,
- DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
-
-SND_SOC_DAILINK_DEF(dmic_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
-SND_SOC_DAILINK_DEF(dmic_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
-
-SND_SOC_DAILINK_DEF(dmic16k_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
-
-SND_SOC_DAILINK_DEF(idisp1_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
-SND_SOC_DAILINK_DEF(idisp1_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
-
-SND_SOC_DAILINK_DEF(idisp2_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
-SND_SOC_DAILINK_DEF(idisp2_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
-
-SND_SOC_DAILINK_DEF(idisp3_pin,
- DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
-SND_SOC_DAILINK_DEF(idisp3_codec,
- DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
-
-SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */
- DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
-
-static struct snd_soc_dai_link dais[] = {
- /* Back End DAI links */
- {
- .name = "SSP1-Codec",
- .id = 0,
- .ignore_pmdown_time = 1,
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1, /* IV feedback */
- .ops = &ssp1_ops,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform),
- },
- {
- .name = "SSP0-Codec",
- .id = 1,
- .no_pcm = 1,
- .init = da7219_codec_init,
- .ignore_pmdown_time = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
- },
- {
- .name = "dmic01",
- .id = 2,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
- },
- {
- .name = "iDisp1",
- .id = 3,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
- },
- {
- .name = "iDisp2",
- .id = 4,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
- },
- {
- .name = "iDisp3",
- .id = 5,
- .init = hdmi_init,
- .dpcm_playback = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
- },
- {
- .name = "dmic16k",
- .id = 6,
- .ignore_suspend = 1,
- .dpcm_capture = 1,
- .no_pcm = 1,
- SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
- }
-};
-
-static struct snd_soc_card card_da7219_m98373 = {
- .name = "da7219max",
- .owner = THIS_MODULE,
- .dai_link = dais,
- .num_links = ARRAY_SIZE(dais),
- .controls = controls,
- .num_controls = ARRAY_SIZE(controls),
- .dapm_widgets = widgets,
- .num_dapm_widgets = ARRAY_SIZE(widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
- .codec_conf = max98373_codec_conf,
- .num_configs = ARRAY_SIZE(max98373_codec_conf),
- .fully_routed = true,
- .late_probe = card_late_probe,
-};
-
-static struct snd_soc_card card_da7219_m98360a = {
- .name = "da7219max98360a",
- .owner = THIS_MODULE,
- .dai_link = dais,
- .num_links = ARRAY_SIZE(dais),
- .controls = m98360a_controls,
- .num_controls = ARRAY_SIZE(m98360a_controls),
- .dapm_widgets = max98360a_widgets,
- .num_dapm_widgets = ARRAY_SIZE(max98360a_widgets),
- .dapm_routes = max98360a_map,
- .num_dapm_routes = ARRAY_SIZE(max98360a_map),
- .fully_routed = true,
- .late_probe = card_late_probe,
-};
-
-static int audio_probe(struct platform_device *pdev)
-{
- static struct snd_soc_card *card;
- struct snd_soc_acpi_mach *mach;
- struct card_private *ctx;
- int ret;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- /* By default dais[0] is configured for max98373 */
- if (!strcmp(pdev->name, "sof_da7219_mx98360a")) {
- dais[0] = (struct snd_soc_dai_link) {
- .name = "SSP1-Codec",
- .id = 0,
- .no_pcm = 1,
- .dpcm_playback = 1,
- .ignore_pmdown_time = 1,
- SND_SOC_DAILINK_REG(ssp1_pin, ssp1_m98360a, platform) };
- }
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- card = (struct snd_soc_card *)pdev->id_entry->driver_data;
- card->dev = &pdev->dev;
-
- mach = pdev->dev.platform_data;
- ret = snd_soc_fixup_dai_links_platform_name(card,
- mach->mach_params.platform);
- if (ret)
- return ret;
-
- snd_soc_card_set_drvdata(card, ctx);
-
- return devm_snd_soc_register_card(&pdev->dev, card);
-}
-
-static const struct platform_device_id board_ids[] = {
- {
- .name = "sof_da7219_mx98373",
- .driver_data = (kernel_ulong_t)&card_da7219_m98373,
- },
- {
- .name = "sof_da7219_mx98360a",
- .driver_data = (kernel_ulong_t)&card_da7219_m98360a,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, board_ids);
-
-static struct platform_driver audio = {
- .probe = audio_probe,
- .driver = {
- .name = "sof_da7219_max98_360a_373",
- .pm = &snd_soc_pm_ops,
- },
- .id_table = board_ids,
-};
-module_platform_driver(audio)
-
-/* Module information */
-MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver");
-MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index d6c38d8ea2ff..774fff58d51b 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -126,7 +126,7 @@ static void pcm_pop_work_events(struct work_struct *work)
static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
@@ -155,7 +155,7 @@ static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd)
static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event))
@@ -163,7 +163,7 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
- queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70));
+ queue_delayed_work(system_dfl_wq, &priv->pcm_pop_work, msecs_to_jiffies(70));
return 0;
}
@@ -231,16 +231,17 @@ static struct snd_soc_jack_pin sof_es8316_jack_pins[] = {
static int dmic_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, dmic_widgets,
ARRAY_SIZE(dmic_widgets));
if (ret) {
dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+ ret = snd_soc_dapm_add_routes(dapm, dmic_map,
ARRAY_SIZE(dmic_map));
if (ret)
dev_err(card->dev, "DMic map addition failed: %d\n", ret);
@@ -251,7 +252,7 @@ static int dmic_init(struct snd_soc_pcm_runtime *runtime)
static int sof_hdmi_init(struct snd_soc_pcm_runtime *runtime)
{
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(runtime->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(runtime, 0);
struct sof_hdmi_pcm *pcm;
pcm = devm_kzalloc(runtime->card->dev, sizeof(*pcm), GFP_KERNEL);
@@ -269,14 +270,15 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *runtime)
static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component;
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
const struct snd_soc_dapm_route *custom_map;
int num_routes;
int ret;
- card->dapm.idle_bias_off = true;
+ snd_soc_dapm_set_idle_bias(dapm, false);
if (quirk & SOC_ES8336_HEADSET_MIC1) {
custom_map = sof_es8316_headset_mic1_map;
@@ -286,7 +288,7 @@ static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime)
num_routes = ARRAY_SIZE(sof_es8316_headset_mic2_map);
}
- ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
if (ret)
return ret;
@@ -308,7 +310,7 @@ static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime)
static void sof_es8316_exit(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(component, NULL, NULL);
}
@@ -355,8 +357,8 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = {
static int sof_es8336_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
const int sysclk = 19200000;
int ret;
@@ -371,7 +373,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream,
}
/* machine stream operations */
-static struct snd_soc_ops sof_es8336_ops = {
+static const struct snd_soc_ops sof_es8336_ops = {
.hw_params = sof_es8336_hw_params,
.trigger = sof_8336_trigger,
};
@@ -455,8 +457,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].exit = sof_es8316_exit;
links[id].ops = &sof_es8336_ops;
links[id].nonatomic = true;
- links[id].dpcm_playback = 1;
- links[id].dpcm_capture = 1;
links[id].no_pcm = 1;
links[id].cpus = &cpus[id];
links[id].num_cpus = 1;
@@ -496,7 +496,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].ignore_suspend = 1;
- links[id].dpcm_capture = 1;
+ links[id].capture_only = 1;
links[id].no_pcm = 1;
id++;
@@ -539,7 +539,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].init = sof_hdmi_init;
- links[id].dpcm_playback = 1;
+ links[id].playback_only = 1;
links[id].no_pcm = 1;
id++;
@@ -565,11 +565,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
if (!links[id].name)
return NULL;
links[id].id = id + hdmi_id_offset;
- links[id].codecs = &asoc_dummy_dlc;
+ links[id].codecs = &snd_soc_dummy_dlc;
links[id].num_codecs = 1;
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_capture = 1;
+ links[id].capture_only = 1;
links[id].no_pcm = 1;
links[id].num_cpus = 1;
id++;
@@ -681,7 +681,7 @@ static int sof_es8336_probe(struct platform_device *pdev)
dai_links[0].codecs->dai_name = "ES8326 HiFi";
} else {
dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
- return -ENXIO;
+ return -ENOENT;
}
codec_dev = acpi_get_first_physical_node(adev);
@@ -798,6 +798,46 @@ static const struct platform_device_id board_ids[] = {
SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
SOF_ES8336_JD_INVERTED),
},
+ {
+ .name = "rpl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
+ {
+ .name = "mtl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
+ {
+ .name = "arl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
+ {
+ .name = "ptl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
@@ -808,11 +848,11 @@ static struct platform_driver sof_es8336_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = sof_es8336_probe,
- .remove_new = sof_es8336_remove,
+ .remove = sof_es8336_remove,
.id_table = board_ids,
};
module_platform_driver(sof_es8336_driver);
MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
diff --git a/sound/soc/intel/boards/sof_hdmi_common.h b/sound/soc/intel/boards/sof_hdmi_common.h
new file mode 100644
index 000000000000..1573e089c0e5
--- /dev/null
+++ b/sound/soc/intel/boards/sof_hdmi_common.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2023 Intel Corporation.
+ */
+
+#ifndef __SOF_HDMI_COMMON_H
+#define __SOF_HDMI_COMMON_H
+
+#include <sound/soc.h>
+
+#define IDISP_CODEC_MASK 0x4
+
+/*
+ * sof_hdmi_private: data for Intel HDMI dai link (idisp) initialization
+ *
+ * @hdmi_comp: ASoC component of idisp codec
+ * @idisp_codec: true to indicate idisp codec is present
+ */
+struct sof_hdmi_private {
+ struct snd_soc_component *hdmi_comp;
+ bool idisp_codec;
+};
+
+#endif /* __SOF_HDMI_COMMON_H */
diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c
index 112e89951da0..c3d0f697ff8d 100644
--- a/sound/soc/intel/boards/sof_maxim_common.c
+++ b/sound/soc/intel/boards/sof_maxim_common.c
@@ -1,24 +1,55 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
#include <linux/module.h>
#include <linux/string.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dai.h>
#include <sound/soc-dapm.h>
+#include <sound/sof.h>
#include <uapi/sound/asound.h>
+#include "../common/soc-intel-quirks.h"
#include "sof_maxim_common.h"
+/*
+ * Common structures and functions
+ */
+static const struct snd_kcontrol_new maxim_2spk_kcontrols[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+
+};
+
+static const struct snd_soc_dapm_widget maxim_2spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+/* helper function to get the number of specific codec */
+static unsigned int get_num_codecs(const char *hid)
+{
+ struct acpi_device *adev;
+ unsigned int dev_num = 0;
+
+ for_each_acpi_dev_match(adev, hid, NULL, -1)
+ dev_num++;
+
+ return dev_num;
+}
+
+/*
+ * Maxim MAX98373
+ */
#define MAX_98373_PIN_NAME 16
-const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
+static const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
/* speaker */
{ "Left Spk", NULL, "Left BE_OUT" },
{ "Right Spk", NULL, "Right BE_OUT" },
};
-EXPORT_SYMBOL_NS(max_98373_dapm_routes, SND_SOC_INTEL_SOF_MAXIM_COMMON);
static struct snd_soc_codec_conf max_98373_codec_conf[] = {
{
@@ -31,7 +62,7 @@ static struct snd_soc_codec_conf max_98373_codec_conf[] = {
},
};
-struct snd_soc_dai_link_component max_98373_components[] = {
+static struct snd_soc_dai_link_component max_98373_components[] = {
{ /* For Right */
.name = MAX_98373_DEV0_NAME,
.dai_name = MAX_98373_CODEC_DAI,
@@ -41,31 +72,124 @@ struct snd_soc_dai_link_component max_98373_components[] = {
.dai_name = MAX_98373_CODEC_DAI,
},
};
-EXPORT_SYMBOL_NS(max_98373_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+/*
+ * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask
+ * should choose two channels from TDM slots, the LSB of rx mask is left channel
+ * and the other one is right channel.
+ */
+static const struct {
+ unsigned int rx;
+} max_98373_tdm_mask[] = {
+ {.rx = 0x3},
+ {.rx = 0x3},
+};
+
+/*
+ * The tx mask indicates which channel(s) contains output IV-sense data and
+ * others should set to Hi-Z. Here we get the channel number from codec's ACPI
+ * device property "maxim,vmon-slot-no" and "maxim,imon-slot-no" to generate the
+ * mask. Refer to the max98373_slot_config() function in max98373.c codec driver.
+ */
+static unsigned int max_98373_get_tx_mask(struct device *dev)
+{
+ int vmon_slot;
+ int imon_slot;
+
+ if (device_property_read_u32(dev, "maxim,vmon-slot-no", &vmon_slot))
+ vmon_slot = 0;
+
+ if (device_property_read_u32(dev, "maxim,imon-slot-no", &imon_slot))
+ imon_slot = 1;
+
+ dev_dbg(dev, "vmon_slot %d imon_slot %d\n", vmon_slot, imon_slot);
+
+ return (0x1 << vmon_slot) | (0x1 << imon_slot);
+}
static int max_98373_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *codec_dai;
- int j;
+ int i;
+ int tdm_slots;
+ unsigned int tx_mask;
+ unsigned int tx_mask_used = 0x0;
+ int ret = 0;
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
- /* DEV0 tdm slot configuration */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ if (i >= ARRAY_SIZE(max_98373_tdm_mask)) {
+ dev_err(codec_dai->dev, "only 2 amps are supported\n");
+ return -EINVAL;
}
- if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
- /* DEV1 tdm slot configuration */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
+
+ switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ /* get the tplg configured tdm slot number */
+ tdm_slots = sof_dai_get_tdm_slots(rtd);
+ if (tdm_slots <= 0) {
+ dev_err(rtd->dev, "invalid tdm slots %d\n",
+ tdm_slots);
+ return -EINVAL;
+ }
+
+ /* get the tx mask from ACPI device properties */
+ tx_mask = max_98373_get_tx_mask(codec_dai->dev);
+ if (!tx_mask)
+ return -EINVAL;
+
+ if (tx_mask & tx_mask_used) {
+ dev_err(codec_dai->dev, "invalid tx mask 0x%x, used 0x%x\n",
+ tx_mask, tx_mask_used);
+ return -EINVAL;
+ }
+
+ tx_mask_used |= tx_mask;
+
+ /*
+ * check if tdm slot number is too small for channel
+ * allocation
+ */
+ if (fls(tx_mask) > tdm_slots) {
+ dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n",
+ fls(tx_mask), tdm_slots);
+ return -EINVAL;
+ }
+
+ if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) {
+ dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n",
+ fls(max_98373_tdm_mask[i].rx), tdm_slots);
+ return -EINVAL;
+ }
+
+ dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n",
+ tx_mask, max_98373_tdm_mask[i].rx,
+ tdm_slots, params_width(params));
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask,
+ max_98373_tdm_mask[i].rx,
+ tdm_slots,
+ params_width(params));
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
+ break;
}
}
return 0;
}
-int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
+static int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
int j;
@@ -75,10 +199,9 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
return 0;
- cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
for_each_rtd_codec_dais(rtd, j, codec_dai) {
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(cpu_dai->component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cpu_dai->component);
char pin_name[MAX_98373_PIN_NAME];
snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
@@ -106,33 +229,68 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
-EXPORT_SYMBOL_NS(max_98373_trigger, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-struct snd_soc_ops max_98373_ops = {
+static const struct snd_soc_ops max_98373_ops = {
.hw_params = max_98373_hw_params,
.trigger = max_98373_trigger,
};
-EXPORT_SYMBOL_NS(max_98373_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
+static int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ unsigned int num_codecs = get_num_codecs(MAX_98373_ACPI_HID);
int ret;
- ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes,
- ARRAY_SIZE(max_98373_dapm_routes));
- if (ret)
- dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
+ switch (num_codecs) {
+ case 2:
+ ret = snd_soc_dapm_new_controls(dapm, maxim_2spk_widgets,
+ ARRAY_SIZE(maxim_2spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add max98373 widgets, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols,
+ ARRAY_SIZE(maxim_2spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add max98373 kcontrols, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, max_98373_dapm_routes,
+ ARRAY_SIZE(max_98373_dapm_routes));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add max98373 routes, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(rtd->dev, "max98373: invalid num_codecs %d\n", num_codecs);
+ return -EINVAL;
+ }
+
return ret;
}
-EXPORT_SYMBOL_NS(max_98373_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link)
+{
+ link->codecs = max_98373_components;
+ link->num_codecs = ARRAY_SIZE(max_98373_components);
+ link->init = max_98373_spk_codec_init;
+ link->ops = &max_98373_ops;
+}
+EXPORT_SYMBOL_NS(max_98373_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
void max_98373_set_codec_conf(struct snd_soc_card *card)
{
card->codec_conf = max_98373_codec_conf;
card->num_configs = ARRAY_SIZE(max_98373_codec_conf);
}
-EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+EXPORT_SYMBOL_NS(max_98373_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
/*
* Maxim MAX98390
@@ -159,18 +317,18 @@ static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = {
{ "TR Spk", NULL, "Tweeter Right BE_OUT" },
};
-static struct snd_soc_codec_conf max_98390_codec_conf[] = {
+static struct snd_soc_codec_conf max_98390_cml_codec_conf[] = {
{
.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
- .name_prefix = "Right",
+ .name_prefix = "Left",
},
{
.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
- .name_prefix = "Left",
+ .name_prefix = "Right",
},
};
-static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = {
+static struct snd_soc_codec_conf max_98390_codec_conf[] = {
{
.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
.name_prefix = "Right",
@@ -189,19 +347,7 @@ static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = {
},
};
-struct snd_soc_dai_link_component max_98390_components[] = {
- {
- .name = MAX_98390_DEV0_NAME,
- .dai_name = MAX_98390_CODEC_DAI,
- },
- {
- .name = MAX_98390_DEV1_NAME,
- .dai_name = MAX_98390_CODEC_DAI,
- },
-};
-EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-
-struct snd_soc_dai_link_component max_98390_4spk_components[] = {
+static struct snd_soc_dai_link_component max_98390_components[] = {
{
.name = MAX_98390_DEV0_NAME,
.dai_name = MAX_98390_CODEC_DAI,
@@ -219,62 +365,69 @@ struct snd_soc_dai_link_component max_98390_4spk_components[] = {
.dai_name = MAX_98390_CODEC_DAI,
},
};
-EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+static const struct {
+ unsigned int tx;
+ unsigned int rx;
+} max_98390_tdm_mask[] = {
+ {.tx = 0x01, .rx = 0x3},
+ {.tx = 0x02, .rx = 0x3},
+ {.tx = 0x04, .rx = 0x3},
+ {.tx = 0x08, .rx = 0x3},
+};
static int max_98390_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *codec_dai;
- int i;
+ int i, ret;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- if (i >= ARRAY_SIZE(max_98390_4spk_components)) {
+ if (i >= ARRAY_SIZE(max_98390_tdm_mask)) {
dev_err(codec_dai->dev, "invalid codec index %d\n", i);
return -ENODEV;
}
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) {
- /* DEV0 tdm slot configuration Right */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32);
- }
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) {
- /* DEV1 tdm slot configuration Left */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32);
- }
-
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) {
- /* DEVi2 tdm slot configuration Tweeter Right */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32);
- }
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) {
- /* DEV3 tdm slot configuration Tweeter Left */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32);
+ switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ /* 4-slot TDM */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ max_98390_tdm_mask[i].tx,
+ max_98390_tdm_mask[i].rx,
+ 4,
+ params_width(params));
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
+ break;
}
}
return 0;
}
-int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
+static int max_98390_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
int ret;
- /* add regular speakers dapm route */
- ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
- ARRAY_SIZE(max_98390_dapm_routes));
- if (ret) {
- dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret);
- return ret;
- }
-
- /* add widgets/controls/dapm for tweeter speakers */
- if (acpi_dev_present("MX98390", "3", -1)) {
- ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets,
+ switch (num_codecs) {
+ case 4:
+ /* add widgets/controls/dapm for tweeter speakers */
+ ret = snd_soc_dapm_new_controls(dapm, max_98390_tt_dapm_widgets,
ARRAY_SIZE(max_98390_tt_dapm_widgets));
-
if (ret) {
- dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret);
+ dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n",
+ ret);
/* Don't need to add routes if widget addition failed */
return ret;
}
@@ -282,36 +435,102 @@ int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols,
ARRAY_SIZE(max_98390_tt_kcontrols));
if (ret) {
- dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret);
+ dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n",
+ ret);
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes,
+ ret = snd_soc_dapm_add_routes(dapm, max_98390_tt_dapm_routes,
ARRAY_SIZE(max_98390_tt_dapm_routes));
- if (ret)
- dev_err(rtd->dev,
- "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret);
+ if (ret) {
+ dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ fallthrough;
+ case 2:
+ /* add regular speakers dapm route */
+ ret = snd_soc_dapm_new_controls(dapm, maxim_2spk_widgets,
+ ARRAY_SIZE(maxim_2spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add max98390 woofer widgets, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols,
+ ARRAY_SIZE(maxim_2spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add max98390 woofer kcontrols, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, max_98390_dapm_routes,
+ ARRAY_SIZE(max_98390_dapm_routes));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add dapm routes, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec number %d\n", num_codecs);
+ return -EINVAL;
}
+
return ret;
}
-EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-const struct snd_soc_ops max_98390_ops = {
+static const struct snd_soc_ops max_98390_ops = {
.hw_params = max_98390_hw_params,
};
-EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-void max_98390_set_codec_conf(struct snd_soc_card *card, int ch)
+void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link)
+{
+ unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
+
+ link->codecs = max_98390_components;
+
+ switch (num_codecs) {
+ case 2:
+ case 4:
+ link->num_codecs = num_codecs;
+ break;
+ default:
+ dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
+ MAX_98390_ACPI_HID);
+ break;
+ }
+
+ link->init = max_98390_init;
+ link->ops = &max_98390_ops;
+}
+EXPORT_SYMBOL_NS(max_98390_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
+
+void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card)
{
- if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) {
- card->codec_conf = max_98390_4spk_codec_conf;
- card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf);
- } else {
- card->codec_conf = max_98390_codec_conf;
- card->num_configs = ARRAY_SIZE(max_98390_codec_conf);
+ unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
+
+ card->codec_conf = max_98390_codec_conf;
+
+ switch (num_codecs) {
+ case 2:
+ if (soc_intel_is_cml())
+ card->codec_conf = max_98390_cml_codec_conf;
+
+ fallthrough;
+ case 4:
+ card->num_configs = num_codecs;
+ break;
+ default:
+ dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
+ MAX_98390_ACPI_HID);
+ break;
}
}
-EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+EXPORT_SYMBOL_NS(max_98390_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
/*
* Maxim MAX98357A/MAX98360A
@@ -346,9 +565,10 @@ static struct snd_soc_dai_link_component max_98360a_components[] = {
static int max_98357a_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, max_98357a_dapm_widgets,
ARRAY_SIZE(max_98357a_dapm_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
@@ -363,7 +583,7 @@ static int max_98357a_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes,
+ ret = snd_soc_dapm_add_routes(dapm, max_98357a_dapm_routes,
ARRAY_SIZE(max_98357a_dapm_routes));
if (ret)
@@ -378,7 +598,7 @@ void max_98357a_dai_link(struct snd_soc_dai_link *link)
link->num_codecs = ARRAY_SIZE(max_98357a_components);
link->init = max_98357a_init;
}
-EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+EXPORT_SYMBOL_NS(max_98357a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
void max_98360a_dai_link(struct snd_soc_dai_link *link)
{
@@ -386,7 +606,7 @@ void max_98360a_dai_link(struct snd_soc_dai_link *link)
link->num_codecs = ARRAY_SIZE(max_98360a_components);
link->init = max_98357a_init;
}
-EXPORT_SYMBOL_NS(max_98360a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+EXPORT_SYMBOL_NS(max_98360a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON");
MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h
index 7a8c53049e4d..3d34c7dae6f5 100644
--- a/sound/soc/intel/boards/sof_maxim_common.h
+++ b/sound/soc/intel/boards/sof_maxim_common.h
@@ -11,41 +11,36 @@
#define __SOF_MAXIM_COMMON_H
#include <sound/soc.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+/*
+ * Maxim MAX98373
+ */
#define MAX_98373_CODEC_DAI "max98373-aif1"
-#define MAX_98373_DEV0_NAME "i2c-MX98373:00"
-#define MAX_98373_DEV1_NAME "i2c-MX98373:01"
+#define MAX_98373_DEV0_NAME "i2c-" MAX_98373_ACPI_HID ":00"
+#define MAX_98373_DEV1_NAME "i2c-" MAX_98373_ACPI_HID ":01"
-extern struct snd_soc_dai_link_component max_98373_components[2];
-extern struct snd_soc_ops max_98373_ops;
-extern const struct snd_soc_dapm_route max_98373_dapm_routes[];
-
-int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd);
+void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link);
void max_98373_set_codec_conf(struct snd_soc_card *card);
-int max_98373_trigger(struct snd_pcm_substream *substream, int cmd);
/*
* Maxim MAX98390
*/
-#define MAX_98390_CODEC_DAI "max98390-aif1"
-#define MAX_98390_DEV0_NAME "i2c-MX98390:00"
-#define MAX_98390_DEV1_NAME "i2c-MX98390:01"
-#define MAX_98390_DEV2_NAME "i2c-MX98390:02"
-#define MAX_98390_DEV3_NAME "i2c-MX98390:03"
-
-extern struct snd_soc_dai_link_component max_98390_components[2];
-extern struct snd_soc_dai_link_component max_98390_4spk_components[4];
-extern const struct snd_soc_ops max_98390_ops;
+#define MAX_98390_CODEC_DAI "max98390-aif1"
+#define MAX_98390_DEV0_NAME "i2c-" MAX_98390_ACPI_HID ":00"
+#define MAX_98390_DEV1_NAME "i2c-" MAX_98390_ACPI_HID ":01"
+#define MAX_98390_DEV2_NAME "i2c-" MAX_98390_ACPI_HID ":02"
+#define MAX_98390_DEV3_NAME "i2c-" MAX_98390_ACPI_HID ":03"
-void max_98390_set_codec_conf(struct snd_soc_card *card, int ch);
-int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd);
+void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link);
+void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card);
/*
* Maxim MAX98357A/MAX98360A
*/
#define MAX_98357A_CODEC_DAI "HiFi"
-#define MAX_98357A_DEV0_NAME "MX98357A:00"
-#define MAX_98360A_DEV0_NAME "MX98360A:00"
+#define MAX_98357A_DEV0_NAME MAX_98357A_ACPI_HID ":00"
+#define MAX_98360A_DEV0_NAME MAX_98360A_ACPI_HID ":00"
void max_98357a_dai_link(struct snd_soc_dai_link *link);
void max_98360a_dai_link(struct snd_soc_dai_link *link);
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 4fc6e1c6aef3..15ba6f5c697c 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -20,68 +20,12 @@
#include <sound/soc-acpi.h>
#include "../../codecs/nau8825.h"
#include "../common/soc-intel-quirks.h"
-#include "hda_dsp_common.h"
+#include "sof_board_helpers.h"
#include "sof_realtek_common.h"
#include "sof_maxim_common.h"
+#include "sof_nuvoton_common.h"
-#define NAME_SIZE 32
-
-#define SOF_NAU8825_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
-#define SOF_NAU8825_SSP_CODEC_MASK (GENMASK(2, 0))
-#define SOF_SPEAKER_AMP_PRESENT BIT(3)
-#define SOF_NAU8825_SSP_AMP_SHIFT 4
-#define SOF_NAU8825_SSP_AMP_MASK (GENMASK(6, 4))
-#define SOF_NAU8825_SSP_AMP(quirk) \
- (((quirk) << SOF_NAU8825_SSP_AMP_SHIFT) & SOF_NAU8825_SSP_AMP_MASK)
-#define SOF_NAU8825_NUM_HDMIDEV_SHIFT 7
-#define SOF_NAU8825_NUM_HDMIDEV_MASK (GENMASK(9, 7))
-#define SOF_NAU8825_NUM_HDMIDEV(quirk) \
- (((quirk) << SOF_NAU8825_NUM_HDMIDEV_SHIFT) & SOF_NAU8825_NUM_HDMIDEV_MASK)
-
-/* BT audio offload: reserve 3 bits for future */
-#define SOF_BT_OFFLOAD_SSP_SHIFT 10
-#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(12, 10))
-#define SOF_BT_OFFLOAD_SSP(quirk) \
- (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
-#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(13)
-#define SOF_RT1019P_SPEAKER_AMP_PRESENT BIT(14)
-#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16)
-#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(17)
-#define SOF_NAU8318_SPEAKER_AMP_PRESENT BIT(18)
-
-static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
-
-struct sof_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct sof_card_private {
- struct clk *mclk;
- struct snd_soc_jack sof_headset;
- struct list_head hdmi_pcm_list;
-};
-
-static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct sof_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- /* dai_link id is 1:1 mapped to the PCM device */
- pcm->device = rtd->dai_link->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
+static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0);
static struct snd_soc_jack_pin jack_pins[] = {
{
@@ -97,9 +41,8 @@ static struct snd_soc_jack_pin jack_pins[] = {
static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
- struct snd_soc_jack *jack;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_jack *jack = &ctx->headset_jack;
int ret;
/*
@@ -110,7 +53,7 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3,
- &ctx->sof_headset,
+ jack,
jack_pins,
ARRAY_SIZE(jack_pins));
if (ret) {
@@ -118,14 +61,12 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- jack = &ctx->sof_headset;
-
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, jack, NULL);
+ ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
@@ -136,7 +77,7 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(component, NULL, NULL);
}
@@ -144,8 +85,8 @@ static void sof_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
static int sof_nau8825_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int clk_freq, ret;
clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
@@ -174,25 +115,17 @@ static int sof_nau8825_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_ops sof_nau8825_ops = {
+static const struct snd_soc_ops sof_nau8825_ops = {
.hw_params = sof_nau8825_hw_params,
};
-static struct snd_soc_dai_link_component platform_component[] = {
- {
- /* name might be overridden during probe */
- .name = "0000:00:1f.3"
- }
-};
-
static int sof_card_late_probe(struct snd_soc_card *card)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dapm_context *dapm = &card->dapm;
- struct sof_hdmi_pcm *pcm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int err;
- if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
+ if (ctx->amp_type == CODEC_MAX98373) {
/* Disable Left and Right Spk pin after boot */
snd_soc_dapm_disable_pin(dapm, "Left Spk");
snd_soc_dapm_disable_pin(dapm, "Right Spk");
@@ -201,38 +134,17 @@ static int sof_card_late_probe(struct snd_soc_card *card)
return err;
}
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
-
- return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
+ return sof_intel_board_card_late_probe(card);
}
static const struct snd_kcontrol_new sof_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_kcontrol_new speaker_controls[] = {
- SOC_DAPM_PIN_SWITCH("Spk"),
};
static const struct snd_soc_dapm_widget sof_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
-static const struct snd_soc_dapm_widget speaker_widgets[] = {
- SND_SOC_DAPM_SPK("Spk", NULL),
-};
-
-static const struct snd_soc_dapm_widget dmic_widgets[] = {
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
};
static const struct snd_soc_dapm_route sof_map[] = {
@@ -244,66 +156,6 @@ static const struct snd_soc_dapm_route sof_map[] = {
{ "MIC", NULL, "Headset Mic" },
};
-static const struct snd_soc_dapm_route speaker_map[] = {
- /* speaker */
- { "Spk", NULL, "Speaker" },
-};
-
-static const struct snd_soc_dapm_route dmic_map[] = {
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-};
-
-static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- ret = snd_soc_dapm_new_controls(&card->dapm, speaker_widgets,
- ARRAY_SIZE(speaker_widgets));
- if (ret) {
- dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
- /* Don't need to add routes if widget addition failed */
- return ret;
- }
-
- ret = snd_soc_add_card_controls(card, speaker_controls,
- ARRAY_SIZE(speaker_controls));
- if (ret) {
- dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map,
- ARRAY_SIZE(speaker_map));
-
- if (ret)
- dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
- return ret;
-}
-
-static int dmic_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
- ARRAY_SIZE(dmic_widgets));
- if (ret) {
- dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
- /* Don't need to add routes if widget addition failed */
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
- ARRAY_SIZE(dmic_map));
-
- if (ret)
- dev_err(card->dev, "DMic map addition failed: %d\n", ret);
-
- return ret;
-}
-
/* sof audio machine driver for nau8825 codec */
static struct snd_soc_card sof_audio_card_nau8825 = {
.name = "nau8825", /* the sof- prefix is added by the core */
@@ -325,281 +177,103 @@ static struct snd_soc_dai_link_component nau8825_component[] = {
}
};
-static struct snd_soc_dai_link_component dmic_component[] = {
- {
- .name = "dmic-codec",
- .dai_name = "dmic-hifi",
- }
-};
-
-static struct snd_soc_dai_link_component rt1019p_component[] = {
- {
- .name = "RTL1019:00",
- .dai_name = "HiFi",
- }
-};
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
+{
+ int ret;
-static struct snd_soc_dai_link_component nau8318_components[] = {
- {
- .name = "NVTN2012:00",
- .dai_name = "nau8315-hifi",
- }
-};
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
-static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
- int ssp_codec,
- int ssp_amp,
- int dmic_be_num,
- int hdmi_num)
-{
- struct snd_soc_dai_link_component *idisp_components;
- struct snd_soc_dai_link_component *cpus;
- struct snd_soc_dai_link *links;
- int i, id = 0;
-
- links = devm_kcalloc(dev, sof_audio_card_nau8825.num_links,
- sizeof(struct snd_soc_dai_link), GFP_KERNEL);
- cpus = devm_kcalloc(dev, sof_audio_card_nau8825.num_links,
- sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
- if (!links || !cpus)
- goto devm_err;
-
- /* codec SSP */
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d-Codec", ssp_codec);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- links[id].codecs = nau8825_component;
- links[id].num_codecs = ARRAY_SIZE(nau8825_component);
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].init = sof_nau8825_codec_init;
- links[id].exit = sof_nau8825_codec_exit;
- links[id].ops = &sof_nau8825_ops;
- links[id].dpcm_playback = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
-
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin",
- ssp_codec);
- if (!links[id].cpus->dai_name)
- goto devm_err;
-
- id++;
-
- /* dmic */
- if (dmic_be_num > 0) {
- /* at least we have dmic01 */
- links[id].name = "dmic01";
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = "DMIC01 Pin";
- links[id].init = dmic_init;
- if (dmic_be_num > 1) {
- /* set up 2 BE links at most */
- links[id + 1].name = "dmic16k";
- links[id + 1].cpus = &cpus[id + 1];
- links[id + 1].cpus->dai_name = "DMIC16k Pin";
- dmic_be_num = 2;
- }
+ if (!ctx->codec_link) {
+ dev_err(dev, "codec link not available");
+ return -EINVAL;
}
- for (i = 0; i < dmic_be_num; i++) {
- links[id].id = id;
- links[id].num_cpus = 1;
- links[id].codecs = dmic_component;
- links[id].num_codecs = ARRAY_SIZE(dmic_component);
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].ignore_suspend = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- id++;
- }
+ /* codec-specific fields for headphone codec */
+ ctx->codec_link->codecs = nau8825_component;
+ ctx->codec_link->num_codecs = ARRAY_SIZE(nau8825_component);
+ ctx->codec_link->init = sof_nau8825_codec_init;
+ ctx->codec_link->exit = sof_nau8825_codec_exit;
+ ctx->codec_link->ops = &sof_nau8825_ops;
- /* HDMI */
- if (hdmi_num > 0) {
- idisp_components = devm_kcalloc(dev,
- hdmi_num,
- sizeof(struct snd_soc_dai_link_component),
- GFP_KERNEL);
- if (!idisp_components)
- goto devm_err;
- }
- for (i = 1; i <= hdmi_num; i++) {
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d", i);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d Pin", i);
- if (!links[id].cpus->dai_name)
- goto devm_err;
-
- idisp_components[i - 1].name = "ehdaudio0D2";
- idisp_components[i - 1].dai_name = devm_kasprintf(dev,
- GFP_KERNEL,
- "intel-hdmi-hifi%d",
- i);
- if (!idisp_components[i - 1].dai_name)
- goto devm_err;
-
- links[id].codecs = &idisp_components[i - 1];
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].init = sof_hdmi_init;
- links[id].dpcm_playback = 1;
- links[id].no_pcm = 1;
- id++;
- }
+ if (ctx->amp_type == CODEC_NONE)
+ return 0;
- /* speaker amp */
- if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) {
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d-Codec", ssp_amp);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- if (sof_nau8825_quirk & SOF_RT1019P_SPEAKER_AMP_PRESENT) {
- links[id].codecs = rt1019p_component;
- links[id].num_codecs = ARRAY_SIZE(rt1019p_component);
- links[id].init = speaker_codec_init;
- } else if (sof_nau8825_quirk &
- SOF_MAX98373_SPEAKER_AMP_PRESENT) {
- links[id].codecs = max_98373_components;
- links[id].num_codecs = ARRAY_SIZE(max_98373_components);
- links[id].init = max_98373_spk_codec_init;
- links[id].ops = &max_98373_ops;
- } else if (sof_nau8825_quirk &
- SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
- max_98360a_dai_link(&links[id]);
- } else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
- sof_rt1015p_dai_link(&links[id]);
- } else if (sof_nau8825_quirk &
- SOF_NAU8318_SPEAKER_AMP_PRESENT) {
- links[id].codecs = nau8318_components;
- links[id].num_codecs = ARRAY_SIZE(nau8318_components);
- links[id].init = speaker_codec_init;
- } else {
- goto devm_err;
- }
-
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_playback = 1;
- /* feedback stream or firmware-generated echo reference */
- links[id].dpcm_capture = 1;
-
- links[id].no_pcm = 1;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin",
- ssp_amp);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- id++;
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
}
- /* BT audio offload */
- if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- links[id].id = id;
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin", port);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
- if (!links[id].name)
- goto devm_err;
- links[id].codecs = &asoc_dummy_dlc;
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_playback = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].num_cpus = 1;
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98360A:
+ max_98360a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98373:
+ max_98373_dai_link(dev, ctx->amp_link);
+ break;
+ case CODEC_NAU8318:
+ nau8318_set_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT1015P:
+ sof_rt1015p_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT1019P:
+ sof_rt1019p_dai_link(ctx->amp_link);
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
- return links;
-devm_err:
- return NULL;
+ return 0;
}
static int sof_audio_probe(struct platform_device *pdev)
{
- struct snd_soc_dai_link *dai_links;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct sof_card_private *ctx;
- int dmic_be_num, hdmi_num;
- int ret, ssp_amp, ssp_codec;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ int ret;
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data;
- mach = pdev->dev.platform_data;
-
- /* A speaker amp might not be present when the quirk claims one is.
- * Detect this via whether the machine driver match includes quirk_data.
- */
- if ((sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data)
- sof_nau8825_quirk &= ~SOF_SPEAKER_AMP_PRESENT;
-
dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk);
- /* default number of DMIC DAI's */
- dmic_be_num = 2;
- hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >>
- SOF_NAU8825_NUM_HDMIDEV_SHIFT;
- /* default number of HDMI DAI's */
- if (!hdmi_num)
- hdmi_num = 3;
-
- ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >>
- SOF_NAU8825_SSP_AMP_SHIFT;
-
- ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK;
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk);
+ if (!ctx)
+ return -ENOMEM;
- /* compute number of dai links */
- sof_audio_card_nau8825.num_links = 1 + dmic_be_num + hdmi_num;
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
+ ctx->hdmi.idisp_codec = true;
- if (sof_nau8825_quirk & SOF_SPEAKER_AMP_PRESENT)
- sof_audio_card_nau8825.num_links++;
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx);
+ if (ret)
+ return ret;
- if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
+ /* update codec_conf */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98373:
max_98373_set_codec_conf(&sof_audio_card_nau8825);
- else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
+ break;
+ case CODEC_RT1015P:
sof_rt1015p_codec_conf(&sof_audio_card_nau8825);
-
- if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- sof_audio_card_nau8825.num_links++;
-
- dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
- dmic_be_num, hdmi_num);
- if (!dai_links)
- return -ENOMEM;
-
- sof_audio_card_nau8825.dai_link = dai_links;
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ break;
+ case CODEC_MAX98360A:
+ case CODEC_NAU8318:
+ case CODEC_RT1019P:
+ case CODEC_NONE:
+ /* no codec conf required */
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
+ }
sof_audio_card_nau8825.dev = &pdev->dev;
@@ -617,72 +291,33 @@ static int sof_audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
- .name = "sof_nau8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
-
- },
- {
.name = "adl_rt1019p_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1019P_SPEAKER_AMP_PRESENT |
- SOF_NAU8825_SSP_AMP(2) |
- SOF_NAU8825_NUM_HDMIDEV(4)),
- },
- {
- .name = "adl_max98373_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98373_SPEAKER_AMP_PRESENT |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
- },
- {
- /* The limitation of length of char array, shorten the name */
- .name = "adl_mx98360a_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
-
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
- .name = "adl_rt1015p_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1015P_SPEAKER_AMP_PRESENT |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ .name = "adl_nau8825_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "adl_nau8318_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_NAU8318_SPEAKER_AMP_PRESENT |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ .name = "rpl_nau8825_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "rpl_max98373_8825",
- .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98373_SPEAKER_AMP_PRESENT |
- SOF_NAU8825_SSP_AMP(1) |
- SOF_NAU8825_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ .name = "mtl_nau8825_def",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_SSP_PORT_BT_OFFLOAD(1) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{ }
};
@@ -702,7 +337,9 @@ module_platform_driver(sof_audio)
MODULE_DESCRIPTION("SOF Audio Machine driver for NAU8825");
MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_NUVOTON_COMMON");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON");
diff --git a/sound/soc/intel/boards/sof_nuvoton_common.c b/sound/soc/intel/boards/sof_nuvoton_common.c
new file mode 100644
index 000000000000..b09ecbab2fc9
--- /dev/null
+++ b/sound/soc/intel/boards/sof_nuvoton_common.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * This file defines data structures and functions used in Machine
+ * Driver for Intel platforms with Nuvoton Codecs.
+ *
+ * Copyright 2023 Intel Corporation.
+ */
+#include <linux/module.h>
+#include <sound/sof.h>
+#include "sof_nuvoton_common.h"
+
+/*
+ * Nuvoton NAU8318
+ */
+static const struct snd_kcontrol_new nau8318_kcontrols[] = {
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget nau8318_widgets[] = {
+ SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route nau8318_routes[] = {
+ { "Spk", NULL, "Speaker" },
+};
+
+static struct snd_soc_dai_link_component nau8318_components[] = {
+ {
+ .name = NAU8318_DEV0_NAME,
+ .dai_name = NAU8318_CODEC_DAI,
+ }
+};
+
+static int nau8318_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, nau8318_widgets,
+ ARRAY_SIZE(nau8318_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add nau8318 widgets, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, nau8318_kcontrols,
+ ARRAY_SIZE(nau8318_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add nau8318 kcontrols, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, nau8318_routes,
+ ARRAY_SIZE(nau8318_routes));
+
+ if (ret) {
+ dev_err(rtd->dev, "fail to add nau8318 routes, ret %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+void nau8318_set_dai_link(struct snd_soc_dai_link *link)
+{
+ link->codecs = nau8318_components;
+ link->num_codecs = ARRAY_SIZE(nau8318_components);
+ link->init = nau8318_init;
+}
+EXPORT_SYMBOL_NS(nau8318_set_dai_link, "SND_SOC_INTEL_SOF_NUVOTON_COMMON");
+
+MODULE_DESCRIPTION("ASoC Intel SOF Nuvoton helpers");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/boards/sof_nuvoton_common.h b/sound/soc/intel/boards/sof_nuvoton_common.h
new file mode 100644
index 000000000000..8a0f283260e7
--- /dev/null
+++ b/sound/soc/intel/boards/sof_nuvoton_common.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * This file defines data structures used in Machine Driver for Intel
+ * platforms with Nuvoton Codecs.
+ *
+ * Copyright 2023 Intel Corporation.
+ */
+#ifndef __SOF_NUVOTON_COMMON_H
+#define __SOF_NUVOTON_COMMON_H
+
+#include <sound/soc.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+
+/*
+ * Nuvoton NAU8318
+ */
+#define NAU8318_CODEC_DAI "nau8315-hifi"
+#define NAU8318_DEV0_NAME "i2c-" NAU8318_ACPI_HID ":00"
+
+void nau8318_set_dai_link(struct snd_soc_dai_link *link);
+
+#endif /* __SOF_NUVOTON_COMMON_H */
diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c
index 9f673ccf81b5..359559b6175b 100644
--- a/sound/soc/intel/boards/sof_pcm512x.c
+++ b/sound/soc/intel/boards/sof_pcm512x.c
@@ -71,7 +71,7 @@ static const struct dmi_system_id sof_pcm512x_quirk_table[] = {
static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
struct sof_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
@@ -89,7 +89,7 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
snd_soc_component_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
@@ -101,8 +101,8 @@ static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd)
static int aif1_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
0x08, 0x08);
@@ -112,8 +112,8 @@ static int aif1_startup(struct snd_pcm_substream *substream)
static void aif1_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
0x08, 0x00);
@@ -177,9 +177,10 @@ static const struct snd_soc_dapm_route dmic_map[] = {
static int dmic_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, dmic_widgets,
ARRAY_SIZE(dmic_widgets));
if (ret) {
dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
@@ -187,7 +188,7 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+ ret = snd_soc_dapm_add_routes(dapm, dmic_map,
ARRAY_SIZE(dmic_map));
if (ret)
@@ -246,12 +247,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].init = sof_pcm512x_codec_init;
links[id].ops = &sof_pcm512x_ops;
- links[id].dpcm_playback = 1;
/*
* capture only supported with specific versions of the Hifiberry DAC+
*/
- if (sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)
- links[id].dpcm_capture = 1;
+ if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE))
+ links[id].playback_only = 1;
links[id].no_pcm = 1;
links[id].cpus = &cpus[id];
links[id].num_cpus = 1;
@@ -294,7 +294,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].ignore_suspend = 1;
- links[id].dpcm_capture = 1;
+ links[id].capture_only = 1;
links[id].no_pcm = 1;
id++;
}
@@ -331,7 +331,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
devm_kasprintf(dev, GFP_KERNEL,
"intel-hdmi-hifi%d", i);
} else {
- idisp_components[i - 1] = asoc_dummy_dlc;
+ idisp_components[i - 1] = snd_soc_dummy_dlc;
}
if (!idisp_components[i - 1].dai_name)
goto devm_err;
@@ -341,7 +341,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].init = sof_hdmi_init;
- links[id].dpcm_playback = 1;
+ links[id].playback_only = 1;
links[id].no_pcm = 1;
id++;
}
@@ -371,8 +371,7 @@ static int sof_audio_probe(struct platform_device *pdev)
sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2);
} else {
dmic_be_num = 2;
- if (mach->mach_params.common_hdmi_codec_drv &&
- (mach->mach_params.codec_mask & IDISP_CODEC_MASK))
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->idisp_codec = true;
/* links are always present in topology */
@@ -430,7 +429,7 @@ static void sof_pcm512x_remove(struct platform_device *pdev)
static struct platform_driver sof_audio = {
.probe = sof_audio_probe,
- .remove_new = sof_pcm512x_remove,
+ .remove = sof_pcm512x_remove,
.driver = {
.name = "sof_pcm512x",
.pm = &snd_soc_pm_ops,
@@ -442,4 +441,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver");
MODULE_AUTHOR("Pierre-Louis Bossart");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sof_pcm512x");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c
index 6c12ca92f371..835186cf04d0 100644
--- a/sound/soc/intel/boards/sof_realtek_common.c
+++ b/sound/soc/intel/boards/sof_realtek_common.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
#include <linux/device.h>
#include <linux/kernel.h>
@@ -15,10 +15,51 @@
#include "../../codecs/rt1011.h"
#include "../../codecs/rt1015.h"
#include "../../codecs/rt1308.h"
+#include "../common/soc-intel-quirks.h"
#include "sof_realtek_common.h"
/*
- * Current only 2-amp configuration is supported for rt1011
+ * Common structures and functions
+ */
+static const struct snd_kcontrol_new realtek_2spk_kcontrols[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+
+};
+
+static const struct snd_soc_dapm_widget realtek_2spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_kcontrol_new realtek_4spk_kcontrols[] = {
+ SOC_DAPM_PIN_SWITCH("WL Ext Spk"),
+ SOC_DAPM_PIN_SWITCH("WR Ext Spk"),
+ SOC_DAPM_PIN_SWITCH("TL Ext Spk"),
+ SOC_DAPM_PIN_SWITCH("TR Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget realtek_4spk_widgets[] = {
+ SND_SOC_DAPM_SPK("WL Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("WR Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("TL Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("TR Ext Spk", NULL),
+};
+
+/* helper function to get the number of specific codec */
+static unsigned int get_num_codecs(const char *hid)
+{
+ struct acpi_device *adev;
+ unsigned int dev_num = 0;
+
+ for_each_acpi_dev_match(adev, hid, NULL, -1)
+ dev_num++;
+
+ return dev_num;
+}
+
+/*
+ * Realtek ALC1011
*/
static const struct snd_soc_dapm_route speaker_map_lr[] = {
/* speaker */
@@ -26,16 +67,14 @@ static const struct snd_soc_dapm_route speaker_map_lr[] = {
{ "Right Spk", NULL, "Right SPO" },
};
-/*
- * Make sure device's Unique ID follows this configuration:
- *
- * Two speakers:
- * 0: left, 1: right
- * Four speakers:
- * 0: Woofer left, 1: Woofer right
- * 2: Tweeter left, 3: Tweeter right
- */
-static struct snd_soc_codec_conf rt1011_codec_confs[] = {
+static const struct snd_soc_dapm_route rt1011_4spk_routes[] = {
+ {"WL Ext Spk", NULL, "WL SPO" },
+ {"WR Ext Spk", NULL, "WR SPO" },
+ {"TL Ext Spk", NULL, "TL SPO" },
+ {"TR Ext Spk", NULL, "TR SPO" },
+};
+
+static struct snd_soc_codec_conf rt1011_2spk_codec_confs[] = {
{
.dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),
.name_prefix = "Left",
@@ -46,6 +85,25 @@ static struct snd_soc_codec_conf rt1011_codec_confs[] = {
},
};
+static struct snd_soc_codec_conf rt1011_4spk_codec_confs[] = {
+ {
+ .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME),
+ .name_prefix = "WL",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME),
+ .name_prefix = "WR",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(RT1011_DEV2_NAME),
+ .name_prefix = "TL",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(RT1011_DEV3_NAME),
+ .name_prefix = "TR",
+ },
+};
+
static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {
{
.name = RT1011_DEV0_NAME,
@@ -55,6 +113,14 @@ static struct snd_soc_dai_link_component rt1011_dai_link_components[] = {
.name = RT1011_DEV1_NAME,
.dai_name = RT1011_CODEC_DAI,
},
+ {
+ .name = RT1011_DEV2_NAME,
+ .dai_name = RT1011_CODEC_DAI,
+ },
+ {
+ .name = RT1011_DEV3_NAME,
+ .dai_name = RT1011_CODEC_DAI,
+ },
};
static const struct {
@@ -63,12 +129,14 @@ static const struct {
} rt1011_tdm_mask[] = {
{.tx = 0x4, .rx = 0x1},
{.tx = 0x8, .rx = 0x2},
+ {.tx = 0x1, .rx = 0x1},
+ {.tx = 0x2, .rx = 0x2},
};
static int rt1011_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int srate, i, ret = 0;
@@ -118,30 +186,125 @@ static const struct snd_soc_ops rt1011_ops = {
static int rt1011_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);
int ret;
- ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr,
- ARRAY_SIZE(speaker_map_lr));
- if (ret)
- dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
+ switch (num_codecs) {
+ case 2:
+ if (!soc_intel_is_cml()) {
+ ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets,
+ ARRAY_SIZE(realtek_2spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,
+ ARRAY_SIZE(realtek_2spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1011 kcontrols, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, speaker_map_lr,
+ ARRAY_SIZE(speaker_map_lr));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ break;
+ }
+
+ /*
+ * register speaker widgets "WL Ext Spk" and "WR Ext Spk" to
+ * keep backward compatible with cml devices
+ */
+ fallthrough;
+ case 4:
+ ret = snd_soc_dapm_new_controls(dapm, realtek_4spk_widgets, num_codecs);
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols, num_codecs);
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, rt1011_4spk_routes, num_codecs);
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(rtd->dev, "rt1011: invalid num_codecs %d\n", num_codecs);
+ return -EINVAL;
+ }
+
return ret;
}
-void sof_rt1011_dai_link(struct snd_soc_dai_link *link)
+void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link)
{
+ unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);
+
link->codecs = rt1011_dai_link_components;
- link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components);
+
+ switch (num_codecs) {
+ case 2:
+ case 4:
+ link->num_codecs = num_codecs;
+ break;
+ default:
+ dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);
+ break;
+ }
+
link->init = rt1011_init;
link->ops = &rt1011_ops;
}
-EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1011_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
-void sof_rt1011_codec_conf(struct snd_soc_card *card)
+void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card)
{
- card->codec_conf = rt1011_codec_confs;
- card->num_configs = ARRAY_SIZE(rt1011_codec_confs);
+ unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID);
+
+ switch (num_codecs) {
+ case 2:
+ if (soc_intel_is_cml()) {
+ /*
+ * use name prefix 'WL' and 'WR' for speaker widgets to
+ * keep backward compatible with cml devices
+ */
+ card->codec_conf = rt1011_4spk_codec_confs;
+ } else {
+ card->codec_conf = rt1011_2spk_codec_confs;
+ }
+
+ card->num_configs = num_codecs;
+ break;
+ case 4:
+ card->codec_conf = rt1011_4spk_codec_confs;
+ card->num_configs = ARRAY_SIZE(rt1011_4spk_codec_confs);
+ break;
+ default:
+ dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs);
+ break;
+ }
+
}
-EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
/*
* rt1015: i2c mode driver for ALC1015 and ALC1015Q
@@ -149,59 +312,21 @@ EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
*
* For stereo output, there are always two amplifiers on the board.
* However, the ACPI implements only one device instance (UID=0) if they
- * are sharing the same enable pin. The code will detect the number of
- * device instance and use corresponding DAPM structures for
- * initialization.
+ * are sharing the same enable pin. This is the case of rt1015p.
*/
-static const struct snd_soc_dapm_route rt1015p_1dev_dapm_routes[] = {
+static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = {
/* speaker */
{ "Left Spk", NULL, "Speaker" },
{ "Right Spk", NULL, "Speaker" },
};
-static const struct snd_soc_dapm_route rt1015p_2dev_dapm_routes[] = {
- /* speaker */
- { "Left Spk", NULL, "Left Speaker" },
- { "Right Spk", NULL, "Right Speaker" },
-};
-
-static struct snd_soc_codec_conf rt1015p_codec_confs[] = {
- {
- .dlc = COMP_CODEC_CONF(RT1015P_DEV0_NAME),
- .name_prefix = "Left",
- },
- {
- .dlc = COMP_CODEC_CONF(RT1015P_DEV1_NAME),
- .name_prefix = "Right",
- },
-};
-
static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = {
{
.name = RT1015P_DEV0_NAME,
.dai_name = RT1015P_CODEC_DAI,
},
- {
- .name = RT1015P_DEV1_NAME,
- .dai_name = RT1015P_CODEC_DAI,
- },
};
-static int rt1015p_get_num_codecs(void)
-{
- static int dev_num;
-
- if (dev_num)
- return dev_num;
-
- if (!acpi_dev_present("RTL1015", "1", -1))
- dev_num = 1;
- else
- dev_num = 2;
-
- return dev_num;
-}
-
static int rt1015p_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -217,14 +342,25 @@ static const struct snd_soc_ops rt1015p_ops = {
static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- if (rt1015p_get_num_codecs() == 1)
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_1dev_dapm_routes,
- ARRAY_SIZE(rt1015p_1dev_dapm_routes));
- else
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_2dev_dapm_routes,
- ARRAY_SIZE(rt1015p_2dev_dapm_routes));
+ ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets,
+ ARRAY_SIZE(realtek_2spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,
+ ARRAY_SIZE(realtek_2spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1015p kcontrols, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, rt1015p_dapm_routes,
+ ARRAY_SIZE(rt1015p_dapm_routes));
if (ret)
dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
return ret;
@@ -233,21 +369,16 @@ static int rt1015p_init(struct snd_soc_pcm_runtime *rtd)
void sof_rt1015p_dai_link(struct snd_soc_dai_link *link)
{
link->codecs = rt1015p_dai_link_components;
- link->num_codecs = rt1015p_get_num_codecs();
+ link->num_codecs = ARRAY_SIZE(rt1015p_dai_link_components);
link->init = rt1015p_init;
link->ops = &rt1015p_ops;
}
-EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
void sof_rt1015p_codec_conf(struct snd_soc_card *card)
{
- if (rt1015p_get_num_codecs() == 1)
- return;
-
- card->codec_conf = rt1015p_codec_confs;
- card->num_configs = ARRAY_SIZE(rt1015p_codec_confs);
}
-EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
/*
* RT1015 audio amplifier
@@ -264,7 +395,7 @@ static const struct {
static int rt1015_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *codec_dai;
int i, clk_freq;
@@ -320,7 +451,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_ops rt1015_ops = {
+static const struct snd_soc_ops rt1015_ops = {
.hw_params = rt1015_hw_params,
};
@@ -348,8 +479,43 @@ static struct snd_soc_dai_link_component rt1015_components[] = {
static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd)
{
- return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr,
- ARRAY_SIZE(speaker_map_lr));
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID);
+ int ret;
+
+ switch (num_codecs) {
+ case 2:
+ ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets,
+ ARRAY_SIZE(realtek_2spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,
+ ARRAY_SIZE(realtek_2spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1015 kcontrols, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, speaker_map_lr,
+ ARRAY_SIZE(speaker_map_lr));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(rtd->dev, "rt1015: invalid num_codecs %d\n", num_codecs);
+ return -EINVAL;
+ }
+
+ return ret;
}
void sof_rt1015_codec_conf(struct snd_soc_card *card)
@@ -357,7 +523,7 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card)
card->codec_conf = rt1015_amp_conf;
card->num_configs = ARRAY_SIZE(rt1015_amp_conf);
}
-EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
void sof_rt1015_dai_link(struct snd_soc_dai_link *link)
{
@@ -366,7 +532,7 @@ void sof_rt1015_dai_link(struct snd_soc_dai_link *link)
link->init = speaker_codec_init_lr;
link->ops = &rt1015_ops;
}
-EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1015_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
/*
* RT1308 audio amplifier
@@ -395,9 +561,10 @@ static struct snd_soc_dai_link_component rt1308_components[] = {
static int rt1308_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, rt1308_dapm_widgets,
ARRAY_SIZE(rt1308_dapm_widgets));
if (ret) {
dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret);
@@ -411,7 +578,7 @@ static int rt1308_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes,
+ ret = snd_soc_dapm_add_routes(dapm, rt1308_dapm_routes,
ARRAY_SIZE(rt1308_dapm_routes));
if (ret)
@@ -423,9 +590,9 @@ static int rt1308_init(struct snd_soc_pcm_runtime *rtd)
static int rt1308_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int clk_id, clk_freq, pll_out;
int ret;
@@ -462,7 +629,7 @@ void sof_rt1308_dai_link(struct snd_soc_dai_link *link)
link->init = rt1308_init;
link->ops = &rt1308_ops;
}
-EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1308_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
/*
* 2-amp Configuration for RT1019
@@ -484,9 +651,24 @@ static struct snd_soc_dai_link_component rt1019p_components[] = {
static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,
+ ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets,
+ ARRAY_SIZE(realtek_2spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols,
+ ARRAY_SIZE(realtek_2spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt1019p kcontrols, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, rt1019p_dapm_routes,
ARRAY_SIZE(rt1019p_dapm_routes));
if (ret) {
dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
@@ -501,7 +683,7 @@ void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)
link->num_codecs = ARRAY_SIZE(rt1019p_components);
link->init = rt1019p_init;
}
-EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON");
MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h
index 3ae99d8239e0..876290555c22 100644
--- a/sound/soc/intel/boards/sof_realtek_common.h
+++ b/sound/soc/intel/boards/sof_realtek_common.h
@@ -11,36 +11,52 @@
#define __SOF_REALTEK_COMMON_H
#include <sound/soc.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+
+/*
+ * Realtek ALC1011
+ */
#define RT1011_CODEC_DAI "rt1011-aif"
-#define RT1011_DEV0_NAME "i2c-10EC1011:00"
-#define RT1011_DEV1_NAME "i2c-10EC1011:01"
-#define RT1011_DEV2_NAME "i2c-10EC1011:02"
-#define RT1011_DEV3_NAME "i2c-10EC1011:03"
+#define RT1011_DEV0_NAME "i2c-" RT1011_ACPI_HID ":00"
+#define RT1011_DEV1_NAME "i2c-" RT1011_ACPI_HID ":01"
+#define RT1011_DEV2_NAME "i2c-" RT1011_ACPI_HID ":02"
+#define RT1011_DEV3_NAME "i2c-" RT1011_ACPI_HID ":03"
-void sof_rt1011_dai_link(struct snd_soc_dai_link *link);
-void sof_rt1011_codec_conf(struct snd_soc_card *card);
+void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link);
+void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card);
+/*
+ * Realtek ALC1015 (AUTO)
+ */
#define RT1015P_CODEC_DAI "HiFi"
-#define RT1015P_DEV0_NAME "RTL1015:00"
-#define RT1015P_DEV1_NAME "RTL1015:01"
+#define RT1015P_DEV0_NAME RT1015P_ACPI_HID ":00"
void sof_rt1015p_dai_link(struct snd_soc_dai_link *link);
void sof_rt1015p_codec_conf(struct snd_soc_card *card);
+/*
+ * Realtek ALC1015 (I2C)
+ */
#define RT1015_CODEC_DAI "rt1015-aif"
-#define RT1015_DEV0_NAME "i2c-10EC1015:00"
-#define RT1015_DEV1_NAME "i2c-10EC1015:01"
+#define RT1015_DEV0_NAME "i2c-" RT1015_ACPI_HID ":00"
+#define RT1015_DEV1_NAME "i2c-" RT1015_ACPI_HID ":01"
void sof_rt1015_dai_link(struct snd_soc_dai_link *link);
void sof_rt1015_codec_conf(struct snd_soc_card *card);
+/*
+ * Realtek ALC1308
+ */
#define RT1308_CODEC_DAI "rt1308-aif"
-#define RT1308_DEV0_NAME "i2c-10EC1308:00"
+#define RT1308_DEV0_NAME "i2c-" RT1308_ACPI_HID ":00"
void sof_rt1308_dai_link(struct snd_soc_dai_link *link);
+/*
+ * Realtek ALC1019
+ */
#define RT1019P_CODEC_DAI "HiFi"
-#define RT1019P_DEV0_NAME "RTL1019:00"
+#define RT1019P_DEV0_NAME RT1019P_ACPI_HID ":00"
void sof_rt1019p_dai_link(struct snd_soc_dai_link *link);
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 86bbc1fea6ff..3d9d8a97d153 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -22,66 +22,22 @@
#include <sound/soc-acpi.h>
#include "../../codecs/rt5682.h"
#include "../../codecs/rt5682s.h"
-#include "../../codecs/hdac_hdmi.h"
+#include "../../codecs/rt5645.h"
#include "../common/soc-intel-quirks.h"
-#include "hda_dsp_common.h"
+#include "sof_board_helpers.h"
#include "sof_maxim_common.h"
#include "sof_realtek_common.h"
-#define NAME_SIZE 32
-
-#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
-#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
-#define SOF_RT5682_MCLK_EN BIT(3)
-#define SOF_RT5682_MCLK_24MHZ BIT(4)
-#define SOF_SPEAKER_AMP_PRESENT BIT(5)
-#define SOF_RT5682_SSP_AMP_SHIFT 6
-#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
-#define SOF_RT5682_SSP_AMP(quirk) \
- (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
-#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9)
-#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10
-#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10))
-#define SOF_RT5682_NUM_HDMIDEV(quirk) \
- ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK)
-#define SOF_RT1011_SPEAKER_AMP_PRESENT BIT(13)
-#define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(14)
-#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(16)
-#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(17)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(18)
-
-/* BT audio offload: reserve 3 bits for future */
-#define SOF_BT_OFFLOAD_SSP_SHIFT 19
-#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(21, 19))
-#define SOF_BT_OFFLOAD_SSP(quirk) \
- (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
-#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22)
-#define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23)
-#define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24)
-#define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25)
-#define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26)
-
+/* Driver-specific board quirks: from bit 0 to 7 */
+#define SOF_RT5682_MCLK_EN BIT(0)
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0);
-
-static int is_legacy_cpu;
-
-struct sof_hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- struct snd_soc_jack hdmi_jack;
- int device;
-};
+ SOF_SSP_PORT_CODEC(0);
-struct sof_card_private {
- struct clk *mclk;
- struct snd_soc_jack sof_headset;
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
- bool idisp_codec;
-};
+static int quirk_override = -1;
+module_param_named(quirk, quirk_override, int, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
{
@@ -96,7 +52,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"),
},
- .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
+ .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -104,7 +60,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
},
- .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
+ .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -113,45 +69,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(1)),
- },
- {
- /*
- * Dooly is hatch family but using rt1015 amp so it
- * requires a quirk before "Google_Hatch".
- */
- .callback = sof_rt5682_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "HP"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Dooly"),
- },
- .driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1015_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1)),
- },
- {
- .callback = sof_rt5682_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"),
- },
- .driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1)),
- },
- {
- .callback = sof_rt5682_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
- },
- .driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0)),
+ SOF_SSP_PORT_CODEC(1)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -160,11 +78,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98373_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -174,11 +90,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98373_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -187,28 +101,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98390_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
- },
- {
- .callback = sof_rt5682_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
- DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"),
- },
- .driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98390_SPEAKER_AMP_PRESENT |
- SOF_MAX98390_TWEETER_SPEAKER_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
-
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -217,27 +112,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
- },
- {
- .callback = sof_rt5682_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Rex"),
- DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S"),
- },
- .driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(2) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(0) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(1) |
- SOF_SSP_BT_OFFLOAD_PRESENT
- ),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
.callback = sof_rt5682_quirk_cb,
@@ -245,36 +122,15 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Rex"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(2) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(0) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(1) |
- SOF_SSP_BT_OFFLOAD_PRESENT
+ SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(0) |
+ SOF_SSP_PORT_BT_OFFLOAD(1) |
+ SOF_BT_OFFLOAD_PRESENT
),
},
{}
};
-static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct sof_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- /* dai_link id is 1:1 mapped to the PCM device */
- pcm->device = rtd->dai_link->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
static struct snd_soc_jack_pin jack_pins[] = {
{
.pin = "Headphone Jack",
@@ -289,44 +145,72 @@ static struct snd_soc_jack_pin jack_pins[] = {
static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_jack *jack;
- int ret;
-
- /* need to enable ASRC function for 24MHz mclk rate */
- if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) &&
- (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) {
- if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT)
- rt5682s_sel_asrc_clk_src(component,
- RT5682S_DA_STEREO1_FILTER |
- RT5682S_AD_STEREO1_FILTER,
- RT5682S_CLK_SEL_I2S1_ASRC);
- else
- rt5682_sel_asrc_clk_src(component,
- RT5682_DA_STEREO1_FILTER |
- RT5682_AD_STEREO1_FILTER,
- RT5682_CLK_SEL_I2S1_ASRC);
- }
-
- if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
- /*
- * The firmware might enable the clock at
- * boot (this information may or may not
- * be reflected in the enable clock register).
- * To change the rate we must disable the clock
- * first to cover these cases. Due to common
- * clock framework restrictions that do not allow
- * to disable a clock that has not been enabled,
- * we need to enable the clock first.
- */
- ret = clk_prepare_enable(ctx->mclk);
- if (!ret)
- clk_disable_unprepare(ctx->mclk);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_jack *jack = &ctx->headset_jack;
+ int extra_jack_data;
+ int ret, mclk_freq;
+
+ if (ctx->rt5682.mclk_en) {
+ mclk_freq = sof_dai_get_mclk(rtd);
+ if (mclk_freq <= 0) {
+ dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_freq);
+ return -EINVAL;
+ }
- ret = clk_set_rate(ctx->mclk, 19200000);
+ /* need to enable ASRC function for 24MHz mclk rate */
+ if (mclk_freq == 24000000) {
+ dev_info(rtd->dev, "enable ASRC\n");
+
+ switch (ctx->codec_type) {
+ case CODEC_RT5650:
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_DA_STEREO_FILTER |
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+ rt5645_sel_asrc_clk_src(component,
+ RT5645_DA_MONO_L_FILTER |
+ RT5645_DA_MONO_R_FILTER,
+ RT5645_CLK_SEL_I2S2_ASRC);
+ break;
+ case CODEC_RT5682:
+ rt5682_sel_asrc_clk_src(component,
+ RT5682_DA_STEREO1_FILTER |
+ RT5682_AD_STEREO1_FILTER,
+ RT5682_CLK_SEL_I2S1_ASRC);
+ break;
+ case CODEC_RT5682S:
+ rt5682s_sel_asrc_clk_src(component,
+ RT5682S_DA_STEREO1_FILTER |
+ RT5682S_AD_STEREO1_FILTER,
+ RT5682S_CLK_SEL_I2S1_ASRC);
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec type %d\n",
+ ctx->codec_type);
+ return -EINVAL;
+ }
+ }
- if (ret)
- dev_err(rtd->dev, "unable to set MCLK rate\n");
+ if (ctx->rt5682.is_legacy_cpu) {
+ /*
+ * The firmware might enable the clock at
+ * boot (this information may or may not
+ * be reflected in the enable clock register).
+ * To change the rate we must disable the clock
+ * first to cover these cases. Due to common
+ * clock framework restrictions that do not allow
+ * to disable a clock that has not been enabled,
+ * we need to enable the clock first.
+ */
+ ret = clk_prepare_enable(ctx->rt5682.mclk);
+ if (!ret)
+ clk_disable_unprepare(ctx->rt5682.mclk);
+
+ ret = clk_set_rate(ctx->rt5682.mclk, 19200000);
+
+ if (ret)
+ dev_err(rtd->dev, "unable to set MCLK rate\n");
+ }
}
/*
@@ -337,7 +221,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3,
- &ctx->sof_headset,
+ jack,
jack_pins,
ARRAY_SIZE(jack_pins));
if (ret) {
@@ -345,13 +229,16 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- jack = &ctx->sof_headset;
-
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, jack, NULL);
+
+ if (ctx->codec_type == CODEC_RT5650) {
+ extra_jack_data = SND_JACK_MICROPHONE | SND_JACK_BTN_0;
+ ret = snd_soc_component_set_jack(component, jack, &extra_jack_data);
+ } else
+ ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
@@ -363,7 +250,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
static void sof_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(component, NULL, NULL);
}
@@ -371,14 +258,14 @@ static void sof_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int pll_id, pll_source, pll_in, pll_out, clk_id, ret;
- if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
- if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
- ret = clk_prepare_enable(ctx->mclk);
+ if (ctx->rt5682.mclk_en) {
+ if (ctx->rt5682.is_legacy_cpu) {
+ ret = clk_prepare_enable(ctx->rt5682.mclk);
if (ret < 0) {
dev_err(rtd->dev,
"could not configure MCLK state");
@@ -386,48 +273,107 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
}
}
- if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT)
- pll_source = RT5682S_PLL_S_MCLK;
- else
+ switch (ctx->codec_type) {
+ case CODEC_RT5650:
+ pll_source = RT5645_PLL1_S_MCLK;
+ break;
+ case CODEC_RT5682:
pll_source = RT5682_PLL1_S_MCLK;
+ break;
+ case CODEC_RT5682S:
+ pll_source = RT5682S_PLL_S_MCLK;
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec type %d\n",
+ ctx->codec_type);
+ return -EINVAL;
+ }
/* get the tplg configured mclk. */
pll_in = sof_dai_get_mclk(rtd);
-
- /* mclk from the quirk is the first choice */
- if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) {
- if (pll_in != 24000000)
- dev_warn(rtd->dev, "configure wrong mclk in tplg, please use 24MHz.\n");
- pll_in = 24000000;
- } else if (pll_in == 0) {
- /* use default mclk if not specified correct in topology */
- pll_in = 19200000;
- } else if (pll_in < 0) {
- return pll_in;
+ if (pll_in <= 0) {
+ dev_err(rtd->dev, "invalid mclk freq %d\n", pll_in);
+ return -EINVAL;
}
} else {
- if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT)
- pll_source = RT5682S_PLL_S_BCLK1;
- else
+ switch (ctx->codec_type) {
+ case CODEC_RT5650:
+ pll_source = RT5645_PLL1_S_BCLK1;
+ break;
+ case CODEC_RT5682:
pll_source = RT5682_PLL1_S_BCLK1;
+ break;
+ case CODEC_RT5682S:
+ pll_source = RT5682S_PLL_S_BCLK1;
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec type %d\n",
+ ctx->codec_type);
+ return -EINVAL;
+ }
- pll_in = params_rate(params) * 50;
- }
-
- if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) {
- pll_id = RT5682S_PLL2;
- clk_id = RT5682S_SCLK_S_PLL2;
- } else {
- pll_id = RT5682_PLL1;
- clk_id = RT5682_SCLK_S_PLL1;
+ /* get the tplg configured bclk. */
+ pll_in = sof_dai_get_bclk(rtd);
+ if (pll_in <= 0) {
+ dev_err(rtd->dev, "invalid bclk freq %d\n", pll_in);
+ return -EINVAL;
+ }
}
pll_out = params_rate(params) * 512;
/* when MCLK is 512FS, no need to set PLL configuration additionally. */
- if (pll_in == pll_out)
- clk_id = RT5682S_SCLK_S_MCLK;
- else {
+ if (pll_in == pll_out) {
+ switch (ctx->codec_type) {
+ case CODEC_RT5650:
+ clk_id = RT5645_SCLK_S_MCLK;
+ break;
+ case CODEC_RT5682:
+ clk_id = RT5682_SCLK_S_MCLK;
+ break;
+ case CODEC_RT5682S:
+ clk_id = RT5682S_SCLK_S_MCLK;
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec type %d\n",
+ ctx->codec_type);
+ return -EINVAL;
+ }
+ } else {
+ switch (ctx->codec_type) {
+ case CODEC_RT5650:
+ pll_id = 0; /* not used in codec driver */
+ clk_id = RT5645_SCLK_S_PLL1;
+ break;
+ case CODEC_RT5682:
+ pll_id = RT5682_PLL1;
+ clk_id = RT5682_SCLK_S_PLL1;
+ break;
+ case CODEC_RT5682S:
+ /* check plla_table and pllb_table in rt5682s.c */
+ switch (pll_in) {
+ case 3072000:
+ case 24576000:
+ /*
+ * For MCLK = 24.576MHz and sample rate = 96KHz case, use PLL1 We don't test
+ * pll_out or params_rate() here since rt5682s PLL2 doesn't support 24.576MHz
+ * input, so we have no choice but to use PLL1. Besides, we will not use PLL at
+ * all if pll_in == pll_out. ex, MCLK = 24.576Mhz and sample rate = 48KHz
+ */
+ pll_id = RT5682S_PLL1;
+ clk_id = RT5682S_SCLK_S_PLL1;
+ break;
+ default:
+ pll_id = RT5682S_PLL2;
+ clk_id = RT5682S_SCLK_S_PLL2;
+ break;
+ }
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type);
+ return -EINVAL;
+ }
+
/* Configure pll for codec */
ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, pll_in,
pll_out);
@@ -455,27 +401,17 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_ops sof_rt5682_ops = {
+static const struct snd_soc_ops sof_rt5682_ops = {
.hw_params = sof_rt5682_hw_params,
};
-static struct snd_soc_dai_link_component platform_component[] = {
- {
- /* name might be overridden during probe */
- .name = "0000:00:1f.3"
- }
-};
-
static int sof_card_late_probe(struct snd_soc_card *card)
{
struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = NULL;
- struct snd_soc_dapm_context *dapm = &card->dapm;
- char jack_name[NAME_SIZE];
- struct sof_hdmi_pcm *pcm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int err;
- if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
+ if (ctx->amp_type == CODEC_MAX98373) {
/* Disable Left and Right Spk pin after boot */
snd_soc_dapm_disable_pin(dapm, "Left Spk");
snd_soc_dapm_disable_pin(dapm, "Right Spk");
@@ -484,56 +420,17 @@ static int sof_card_late_probe(struct snd_soc_card *card)
return err;
}
- /* HDMI is not supported by SOF on Baytrail/CherryTrail */
- if (is_legacy_cpu || !ctx->idisp_codec)
- return 0;
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &pcm->hdmi_jack);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &pcm->hdmi_jack);
- if (err < 0)
- return err;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
+ return sof_intel_board_card_late_probe(card);
}
static const struct snd_kcontrol_new sof_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-
};
static const struct snd_soc_dapm_widget sof_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
-static const struct snd_soc_dapm_widget dmic_widgets[] = {
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
};
static const struct snd_soc_dapm_route sof_map[] = {
@@ -545,29 +442,49 @@ static const struct snd_soc_dapm_route sof_map[] = {
{ "IN1P", NULL, "Headset Mic" },
};
-static const struct snd_soc_dapm_route dmic_map[] = {
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
+static const struct snd_kcontrol_new rt5650_spk_kcontrols[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+
+};
+
+static const struct snd_soc_dapm_widget rt5650_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = {
+ /* speaker */
+ { "Left Spk", NULL, "SPOL" },
+ { "Right Spk", NULL, "SPOR" },
};
-static int dmic_init(struct snd_soc_pcm_runtime *rtd)
+static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
- ARRAY_SIZE(dmic_widgets));
+ ret = snd_soc_dapm_new_controls(dapm, rt5650_spk_widgets,
+ ARRAY_SIZE(rt5650_spk_widgets));
if (ret) {
- dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
- /* Don't need to add routes if widget addition failed */
+ dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n",
+ ret);
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
- ARRAY_SIZE(dmic_map));
+ ret = snd_soc_add_card_controls(card, rt5650_spk_kcontrols,
+ ARRAY_SIZE(rt5650_spk_kcontrols));
+ if (ret) {
+ dev_err(rtd->dev, "fail to add rt5650 spk kcontrols, ret %d\n",
+ ret);
+ return ret;
+ }
+ ret = snd_soc_dapm_add_routes(dapm, rt5650_spk_dapm_routes,
+ ARRAY_SIZE(rt5650_spk_dapm_routes));
if (ret)
- dev_err(card->dev, "DMic map addition failed: %d\n", ret);
+ dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret);
return ret;
}
@@ -600,65 +517,56 @@ static struct snd_soc_dai_link_component rt5682s_component[] = {
}
};
-static struct snd_soc_dai_link_component dmic_component[] = {
+static struct snd_soc_dai_link_component rt5650_components[] = {
{
- .name = "dmic-codec",
- .dai_name = "dmic-hifi",
+ .name = "i2c-10EC5650:00",
+ .dai_name = "rt5645-aif1",
+ },
+ {
+ .name = "i2c-10EC5650:00",
+ .dai_name = "rt5645-aif2",
}
};
-#define IDISP_CODEC_MASK 0x4
-
-static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
- int ssp_codec,
- int ssp_amp,
- int dmic_be_num,
- int hdmi_num,
- bool idisp_codec)
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
{
- struct snd_soc_dai_link_component *idisp_components;
- struct snd_soc_dai_link_component *cpus;
- struct snd_soc_dai_link *links;
- int i, id = 0;
-
- links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links,
- sizeof(struct snd_soc_dai_link), GFP_KERNEL);
- cpus = devm_kcalloc(dev, sof_audio_card_rt5682.num_links,
- sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
- if (!links || !cpus)
- goto devm_err;
-
- /* codec SSP */
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d-Codec", ssp_codec);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) {
- links[id].codecs = rt5682s_component;
- links[id].num_codecs = ARRAY_SIZE(rt5682s_component);
- } else {
- links[id].codecs = rt5682_component;
- links[id].num_codecs = ARRAY_SIZE(rt5682_component);
+ int ret;
+
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
+
+ if (!ctx->codec_link) {
+ dev_err(dev, "codec link not available");
+ return -EINVAL;
}
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].init = sof_rt5682_codec_init;
- links[id].exit = sof_rt5682_codec_exit;
- links[id].ops = &sof_rt5682_ops;
- links[id].dpcm_playback = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- if (is_legacy_cpu) {
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "ssp%d-port",
- ssp_codec);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- } else {
+
+ /* codec-specific fields for headphone codec */
+ switch (ctx->codec_type) {
+ case CODEC_RT5650:
+ ctx->codec_link->codecs = &rt5650_components[0];
+ ctx->codec_link->num_codecs = 1;
+ break;
+ case CODEC_RT5682:
+ ctx->codec_link->codecs = rt5682_component;
+ ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682_component);
+ break;
+ case CODEC_RT5682S:
+ ctx->codec_link->codecs = rt5682s_component;
+ ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682s_component);
+ break;
+ default:
+ dev_err(dev, "invalid codec type %d\n", ctx->codec_type);
+ return -EINVAL;
+ }
+
+ ctx->codec_link->init = sof_rt5682_codec_init;
+ ctx->codec_link->exit = sof_rt5682_codec_exit;
+ ctx->codec_link->ops = &sof_rt5682_ops;
+
+ if (!ctx->rt5682.is_legacy_cpu) {
/*
* Currently, On SKL+ platforms MCLK will be turned off in sof
* runtime suspended, and it will go into runtime suspended
@@ -668,298 +576,205 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
* avoid the noise.
* It can be removed once we can control MCLK by driver.
*/
- links[id].ignore_pmdown_time = 1;
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin",
- ssp_codec);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- }
- id++;
-
- /* dmic */
- if (dmic_be_num > 0) {
- /* at least we have dmic01 */
- links[id].name = "dmic01";
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = "DMIC01 Pin";
- links[id].init = dmic_init;
- if (dmic_be_num > 1) {
- /* set up 2 BE links at most */
- links[id + 1].name = "dmic16k";
- links[id + 1].cpus = &cpus[id + 1];
- links[id + 1].cpus->dai_name = "DMIC16k Pin";
- dmic_be_num = 2;
- }
- }
-
- for (i = 0; i < dmic_be_num; i++) {
- links[id].id = id;
- links[id].num_cpus = 1;
- links[id].codecs = dmic_component;
- links[id].num_codecs = ARRAY_SIZE(dmic_component);
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].ignore_suspend = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- id++;
- }
-
- /* HDMI */
- if (hdmi_num > 0) {
- idisp_components = devm_kcalloc(dev,
- hdmi_num,
- sizeof(struct snd_soc_dai_link_component),
- GFP_KERNEL);
- if (!idisp_components)
- goto devm_err;
- }
- for (i = 1; i <= hdmi_num; i++) {
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d", i);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d Pin", i);
- if (!links[id].cpus->dai_name)
- goto devm_err;
-
- if (idisp_codec) {
- idisp_components[i - 1].name = "ehdaudio0D2";
- idisp_components[i - 1].dai_name = devm_kasprintf(dev,
- GFP_KERNEL,
- "intel-hdmi-hifi%d",
- i);
- if (!idisp_components[i - 1].dai_name)
- goto devm_err;
- } else {
- idisp_components[i - 1] = asoc_dummy_dlc;
- }
-
- links[id].codecs = &idisp_components[i - 1];
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].init = sof_hdmi_init;
- links[id].dpcm_playback = 1;
- links[id].no_pcm = 1;
- id++;
+ ctx->codec_link->ignore_pmdown_time = 1;
}
- /* speaker amp */
- if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) {
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d-Codec", ssp_amp);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) {
- sof_rt1015_dai_link(&links[id]);
- } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
- sof_rt1015p_dai_link(&links[id]);
- } else if (sof_rt5682_quirk & SOF_RT1019_SPEAKER_AMP_PRESENT) {
- sof_rt1019p_dai_link(&links[id]);
- } else if (sof_rt5682_quirk &
- SOF_MAX98373_SPEAKER_AMP_PRESENT) {
- links[id].codecs = max_98373_components;
- links[id].num_codecs = ARRAY_SIZE(max_98373_components);
- links[id].init = max_98373_spk_codec_init;
- links[id].ops = &max_98373_ops;
- } else if (sof_rt5682_quirk &
- SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
- max_98360a_dai_link(&links[id]);
- } else if (sof_rt5682_quirk &
- SOF_RT1011_SPEAKER_AMP_PRESENT) {
- sof_rt1011_dai_link(&links[id]);
- } else if (sof_rt5682_quirk &
- SOF_MAX98390_SPEAKER_AMP_PRESENT) {
- if (sof_rt5682_quirk &
- SOF_MAX98390_TWEETER_SPEAKER_PRESENT) {
- links[id].codecs = max_98390_4spk_components;
- links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components);
- } else {
- links[id].codecs = max_98390_components;
- links[id].num_codecs = ARRAY_SIZE(max_98390_components);
- }
- links[id].init = max_98390_spk_codec_init;
- links[id].ops = &max_98390_ops;
+ if (ctx->amp_type == CODEC_NONE)
+ return 0;
- } else {
- max_98357a_dai_link(&links[id]);
- }
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_playback = 1;
- /* feedback stream or firmware-generated echo reference */
- links[id].dpcm_capture = 1;
-
- links[id].no_pcm = 1;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- if (is_legacy_cpu) {
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "ssp%d-port",
- ssp_amp);
- if (!links[id].cpus->dai_name)
- goto devm_err;
-
- } else {
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin",
- ssp_amp);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- }
- id++;
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
}
- /* BT audio offload */
- if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- int port = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- links[id].id = id;
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin", port);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
- if (!links[id].name)
- goto devm_err;
- links[id].codecs = &asoc_dummy_dlc;
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_playback = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].num_cpus = 1;
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98357A:
+ max_98357a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98360A:
+ max_98360a_dai_link(ctx->amp_link);
+ break;
+ case CODEC_MAX98373:
+ max_98373_dai_link(dev, ctx->amp_link);
+ break;
+ case CODEC_MAX98390:
+ max_98390_dai_link(dev, ctx->amp_link);
+ break;
+ case CODEC_RT1011:
+ sof_rt1011_dai_link(dev, ctx->amp_link);
+ break;
+ case CODEC_RT1015:
+ sof_rt1015_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT1015P:
+ sof_rt1015p_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT1019P:
+ sof_rt1019p_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT5650:
+ /* use AIF2 to support speaker pipeline */
+ ctx->amp_link->codecs = &rt5650_components[1];
+ ctx->amp_link->num_codecs = 1;
+ ctx->amp_link->init = rt5650_spk_init;
+ ctx->amp_link->ops = &sof_rt5682_ops;
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
- return links;
-devm_err:
- return NULL;
+ return 0;
}
+#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
+ SOF_LINK_CODEC, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE, \
+ SOF_LINK_NONE)
+
static int sof_audio_probe(struct platform_device *pdev)
{
- struct snd_soc_dai_link *dai_links;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct sof_card_private *ctx;
- int dmic_be_num, hdmi_num;
- int ret, ssp_amp, ssp_codec;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ char *card_name;
+ int ret;
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
dmi_check_system(sof_rt5682_quirk_table);
- mach = pdev->dev.platform_data;
+ if (quirk_override != -1) {
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ sof_rt5682_quirk, quirk_override);
+ sof_rt5682_quirk = quirk_override;
+ }
- /* A speaker amp might not be present when the quirk claims one is.
- * Detect this via whether the machine driver match includes quirk_data.
- */
- if ((sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data)
- sof_rt5682_quirk &= ~SOF_SPEAKER_AMP_PRESENT;
+ dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
+
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_rt5682_quirk);
+ if (!ctx)
+ return -ENOMEM;
- /* Detect the headset codec variant */
- if (acpi_dev_present("RTL5682", NULL, -1))
- sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
+ if (ctx->codec_type == CODEC_RT5650) {
+ card_name = devm_kstrdup(&pdev->dev, "rt5650", GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
- if (soc_intel_is_byt() || soc_intel_is_cht()) {
- is_legacy_cpu = 1;
- dmic_be_num = 0;
- hdmi_num = 0;
- /* default quirk for legacy cpu */
- sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_BYTCHT_EN |
- SOF_RT5682_SSP_CODEC(2);
- } else {
- dmic_be_num = 2;
- hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >>
- SOF_RT5682_NUM_HDMIDEV_SHIFT;
- /* default number of HDMI DAI's */
- if (!hdmi_num)
- hdmi_num = 3;
-
- if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
- ctx->idisp_codec = true;
+ sof_audio_card_rt5682.name = card_name;
+
+ /* create speaker dai link also */
+ if (ctx->amp_type == CODEC_NONE)
+ ctx->amp_type = CODEC_RT5650;
}
- /* need to get main clock from pmc */
- if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
- ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
- if (IS_ERR(ctx->mclk)) {
- ret = PTR_ERR(ctx->mclk);
+ if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
+ ctx->hdmi.idisp_codec = true;
- dev_err(&pdev->dev,
- "Failed to get MCLK from pmc_plt_clk_3: %d\n",
- ret);
- return ret;
+ if (soc_intel_is_byt() || soc_intel_is_cht()) {
+ ctx->rt5682.is_legacy_cpu = true;
+ ctx->dmic_be_num = 0;
+ /* HDMI is not supported by SOF on Baytrail/CherryTrail */
+ ctx->hdmi_num = 0;
+ } else if (soc_intel_is_glk()) {
+ /* dmic16k not support */
+ ctx->dmic_be_num = 1;
+
+ /* overwrite the DAI link order for GLK boards */
+ ctx->link_order_overwrite = GLK_LINK_ORDER;
+
+ /* backward-compatible with existing devices */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98357A:
+ card_name = devm_kstrdup(&pdev->dev, "glkrt5682max",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ sof_audio_card_rt5682.name = card_name;
+ break;
+ default:
+ break;
}
-
- ret = clk_prepare_enable(ctx->mclk);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "could not configure MCLK state");
- return ret;
+ } else if (soc_intel_is_cml()) {
+ /* backward-compatible with existing devices */
+ switch (ctx->amp_type) {
+ case CODEC_RT1011:
+ card_name = devm_kstrdup(&pdev->dev, "cml_rt1011_rt5682",
+ GFP_KERNEL);
+ if (!card_name)
+ return -ENOMEM;
+
+ sof_audio_card_rt5682.name = card_name;
+ break;
+ default:
+ break;
}
}
- dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
+ if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
+ ctx->rt5682.mclk_en = true;
- ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >>
- SOF_RT5682_SSP_AMP_SHIFT;
+ /* need to get main clock from pmc */
+ if (ctx->rt5682.is_legacy_cpu) {
+ ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+ if (IS_ERR(ctx->rt5682.mclk)) {
+ ret = PTR_ERR(ctx->rt5682.mclk);
- ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK;
+ dev_err(&pdev->dev,
+ "Failed to get MCLK from pmc_plt_clk_3: %d\n",
+ ret);
+ return ret;
+ }
- /* compute number of dai links */
- sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num;
+ ret = clk_prepare_enable(ctx->rt5682.mclk);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "could not configure MCLK state");
+ return ret;
+ }
+ }
+ }
- if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT)
- sof_audio_card_rt5682.num_links++;
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx);
+ if (ret)
+ return ret;
- if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT)
+ /* update codec_conf */
+ switch (ctx->amp_type) {
+ case CODEC_MAX98373:
max_98373_set_codec_conf(&sof_audio_card_rt5682);
- else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT)
- sof_rt1011_codec_conf(&sof_audio_card_rt5682);
- else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
+ break;
+ case CODEC_MAX98390:
+ max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682);
+ break;
+ case CODEC_RT1011:
+ sof_rt1011_codec_conf(&pdev->dev, &sof_audio_card_rt5682);
+ break;
+ case CODEC_RT1015:
+ sof_rt1015_codec_conf(&sof_audio_card_rt5682);
+ break;
+ case CODEC_RT1015P:
sof_rt1015p_codec_conf(&sof_audio_card_rt5682);
- else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) {
- if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT)
- max_98390_set_codec_conf(&sof_audio_card_rt5682,
- ARRAY_SIZE(max_98390_4spk_components));
- else
- max_98390_set_codec_conf(&sof_audio_card_rt5682,
- ARRAY_SIZE(max_98390_components));
+ break;
+ case CODEC_MAX98357A:
+ case CODEC_MAX98360A:
+ case CODEC_RT1019P:
+ case CODEC_RT5650:
+ case CODEC_NONE:
+ /* no codec conf required */
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
- if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- sof_audio_card_rt5682.num_links++;
-
- dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
- dmic_be_num, hdmi_num, ctx->idisp_codec);
- if (!dai_links)
- return -ENOMEM;
-
- sof_audio_card_rt5682.dai_link = dai_links;
-
- if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT)
- sof_rt1015_codec_conf(&sof_audio_card_rt5682);
-
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
sof_audio_card_rt5682.dev = &pdev->dev;
/* set platform name for each dailink */
@@ -968,8 +783,6 @@ static int sof_audio_probe(struct platform_device *pdev)
if (ret)
return ret;
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx);
return devm_snd_soc_register_card(&pdev->dev,
@@ -979,181 +792,123 @@ static int sof_audio_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
.name = "sof_rt5682",
- },
- {
- .name = "tgl_mx98357_rt5682",
- .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
- },
- {
- .name = "jsl_rt5682_rt1015",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1015_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(2)),
},
{
- .name = "tgl_mx98373_rt5682",
+ .name = "glk_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98373_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(2) |
+ SOF_SSP_PORT_AMP(1)),
},
{
- .name = "jsl_rt5682_mx98360",
+ .name = "icl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(0)),
},
{
- .name = "cml_rt1015_rt5682",
+ .name = "cml_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1015_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
- .name = "tgl_rt1011_rt5682",
+ .name = "jsl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1011_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1)),
},
{
- .name = "jsl_rt5682_rt1015p",
+ .name = "tgl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1015P_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "adl_mx98373_rt5682",
+ .name = "adl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98373_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "adl_mx98357_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(2) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
- .name = "adl_max98390_rt5682",
+ .name = "adl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98390_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(1) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{
- .name = "adl_mx98360_rt5682",
+ .name = "rpl_mx98357_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(2) |
+ SOF_NUM_IDISP_HDMI(4)),
},
{
- .name = "adl_rt5682",
+ .name = "rpl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "adl_rt1019_rt5682",
+ .name = "rpl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1019_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(1) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{
- .name = "rpl_mx98360_rt5682",
+ .name = "mtl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "rpl_rt1019_rt5682",
+ .name = "mtl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT1019_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(1) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{
- .name = "mtl_mx98357_rt5682",
+ .name = "arl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
+ SOF_SSP_PORT_CODEC(1) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{
- .name = "mtl_mx98360_rt5682",
+ .name = "ptl_rt5682_def",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98360A_SPEAKER_AMP_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4)),
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
- .name = "jsl_rt5682",
+ .name = "ptl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_MCLK_24MHZ |
- SOF_RT5682_SSP_CODEC(0)),
+ SOF_SSP_PORT_CODEC(1) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
},
{ }
};
@@ -1176,6 +931,6 @@ MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON");
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index f2f56150e1da..2c1001148d54 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -5,44 +5,48 @@
* sof_sdw - ASOC Machine driver for Intel SoundWire platforms
*/
+#include <linux/acpi.h>
+#include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
-#include <sound/soc.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"
-unsigned long sof_sdw_quirk = RT711_JD1;
+static unsigned long sof_sdw_quirk = RT711_JD1;
static int quirk_override = -1;
module_param_named(quirk, quirk_override, int, 0444);
MODULE_PARM_DESC(quirk, "Board-specific quirk override");
-#define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0)
-
-#define SDW_MAX_LINKS 4
-
-/* To store SDW Pin index for each SoundWire link */
-static unsigned int sdw_pin_index[SDW_MAX_LINKS];
+#define DMIC_DEFAULT_CHANNELS 2
static void log_quirks(struct device *dev)
{
- if (SOF_JACK_JDSRC(sof_sdw_quirk))
+ if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk))
dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
- SOF_JACK_JDSRC(sof_sdw_quirk));
- if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
- dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n");
+ SOC_SDW_JACK_JDSRC(sof_sdw_quirk));
+ if (sof_sdw_quirk & SOC_SDW_FOUR_SPK)
+ dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n");
if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
- if (sof_sdw_quirk & SOF_SDW_PCH_DMIC)
- dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n");
+ if (sof_sdw_quirk & SOC_SDW_PCH_DMIC)
+ dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n");
if (SOF_SSP_GET_PORT(sof_sdw_quirk))
dev_dbg(dev, "SSP port %ld\n",
SOF_SSP_GET_PORT(sof_sdw_quirk));
- if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
- dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
+ if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION)
+ dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n");
+ if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR)
+ 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)
@@ -59,7 +63,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
},
- .driver_data = (void *)SOF_SDW_PCH_DMIC,
+ .driver_data = (void *)SOC_SDW_PCH_DMIC,
},
{
.callback = sof_sdw_quirk_cb,
@@ -84,8 +88,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
},
- .driver_data = (void *)(RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ .driver_data = (void *)(RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -93,8 +96,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
},
- .driver_data = (void *)(RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ .driver_data = (void *)(RT711_JD2),
},
/* IceLake devices */
{
@@ -103,7 +105,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
},
- .driver_data = (void *)SOF_SDW_PCH_DMIC,
+ .driver_data = (void *)SOC_SDW_PCH_DMIC,
},
/* TigerLake devices */
{
@@ -115,7 +117,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
RT711_JD1 |
- SOF_SDW_PCH_DMIC |
+ SOC_SDW_PCH_DMIC |
SOF_SSP_PORT(SOF_I2S_SSP2)),
},
{
@@ -145,8 +147,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -155,8 +156,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -165,8 +165,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
- SOF_SDW_FOUR_SPK |
+ SOC_SDW_PCH_DMIC |
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
@@ -177,8 +176,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
- SOF_SDW_FOUR_SPK),
+ SOC_SDW_PCH_DMIC),
},
{
/*
@@ -193,7 +191,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
+ SOC_SDW_PCH_DMIC |
RT711_JD1),
},
{
@@ -207,7 +205,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "8709"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
+ SOC_SDW_PCH_DMIC |
RT711_JD1),
},
{
@@ -218,7 +216,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
+ SOC_SDW_PCH_DMIC |
RT711_JD1),
},
{
@@ -229,7 +227,21 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
+ SOC_SDW_PCH_DMIC |
+ RT711_JD1),
+ },
+ {
+ /*
+ * Avell B.ON (OEM rebrand of NUC15 'Bishop County' LAPBC510 and
+ * LAPBC710)
+ */
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Avell High Performance"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "B.ON"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ SOC_SDW_PCH_DMIC |
RT711_JD1),
},
{
@@ -240,7 +252,18 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
+ SOC_SDW_PCH_DMIC |
+ RT711_JD2_100K),
+ },
+ {
+ /* NUC15 LAPRC710 skews */
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ SOC_SDW_PCH_DMIC |
RT711_JD2_100K),
},
/* TigerLake-SDCA devices */
@@ -251,8 +274,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -278,12 +300,20 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
{
.callback = sof_sdw_quirk_cb,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2_100K),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_PCH_DMIC |
- SOF_SDW_FOUR_SPK |
+ SOC_SDW_PCH_DMIC |
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
@@ -294,8 +324,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -304,8 +333,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
},
/* No Jack */
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+ },
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -314,8 +351,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -324,8 +360,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -334,8 +369,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -344,8 +378,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -354,8 +387,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -370,11 +402,20 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
+ },
+ /* No Jack */
+ .driver_data = (void *)SOF_SDW_TGL_HDMI,
+ },
+
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -388,8 +429,17 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
{
.callback = sof_sdw_quirk_cb,
.matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"),
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
- DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
RT711_JD2),
@@ -402,8 +452,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -412,8 +470,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
},
/* No Jack */
- .driver_data = (void *)(SOF_SDW_TGL_HDMI |
- SOF_SDW_FOUR_SPK),
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI),
},
{
.callback = sof_sdw_quirk_cb,
@@ -422,8 +479,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -432,8 +488,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -442,8 +497,31 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
},
/* MeteorLake devices */
{
@@ -467,8 +545,19 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
},
- .driver_data = (void *)(SOF_SDW_PCH_DMIC),
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(1) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
},
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"),
+ },
+ .driver_data = (void *)(RT711_JD2),
+ },
+
/* LunarLake devices */
{
.callback = sof_sdw_quirk_cb,
@@ -476,1517 +565,869 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
},
- .driver_data = (void *)(RT711_JD2_100K),
+ .driver_data = (void *)(RT711_JD2),
},
- {}
-};
-
-static struct snd_soc_dai_link_component dmic_component[] = {
{
- .name = "dmic-codec",
- .dai_name = "dmic-hifi",
- }
-};
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3")
+ },
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4")
+ },
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83JX")
+ },
+ .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, "83LC")
+ },
+ .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, "83MC")
+ },
+ .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,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21QB")
+ },
+ /* Note this quirk excludes the CODEC mic */
+ .driver_data = (void *)(SOC_SDW_CODEC_MIC),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21QA")
+ },
+ /* Note this quirk excludes the CODEC mic */
+ .driver_data = (void *)(SOC_SDW_CODEC_MIC),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21Q6")
+ },
+ .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, "21Q7")
+ },
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
+ },
-static struct snd_soc_dai_link_component platform_component[] = {
+ /* ArrowLake devices */
{
- /* name might be overridden during probe */
- .name = "0000:00:1f.3"
- }
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCC")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
+ /* Pantherlake devices*/
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"),
+ },
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Lapis"),
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR |
+ SOC_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Francka"),
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR |
+ SOC_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Fatcat"),
+ },
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
+ /* Wildcatlake devices*/
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"),
+ },
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"),
+ },
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
+ {}
};
-/* these wrappers are only needed to avoid typecast compilation errors */
-int sdw_startup(struct snd_pcm_substream *substream)
-{
- return sdw_startup_stream(substream);
-}
+static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = {
+ SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC),
+ {}
+};
-int sdw_prepare(struct snd_pcm_substream *substream)
+static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct sdw_stream_runtime *sdw_stream;
- struct snd_soc_dai *dai;
+ const struct snd_pci_quirk *quirk_entry;
- /* Find stream from first CPU DAI */
- dai = asoc_rtd_to_cpu(rtd, 0);
+ quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor,
+ mach->mach_params.subsystem_device,
+ sof_sdw_ssid_quirk_table);
- sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
+ if (quirk_entry)
+ sof_sdw_quirk = quirk_entry->value;
+}
- if (IS_ERR(sdw_stream)) {
- dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
- return PTR_ERR(sdw_stream);
- }
+static const struct snd_soc_ops sdw_ops = {
+ .startup = asoc_sdw_startup,
+ .prepare = asoc_sdw_prepare,
+ .trigger = asoc_sdw_trigger,
+ .hw_params = asoc_sdw_hw_params,
+ .hw_free = asoc_sdw_hw_free,
+ .shutdown = asoc_sdw_shutdown,
+};
- return sdw_prepare_stream(sdw_stream);
-}
+static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
-int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
+static int create_sdw_dailink(struct snd_soc_card *card,
+ struct asoc_sdw_dailink *sof_dai,
+ struct snd_soc_dai_link **dai_links,
+ int *be_id, struct snd_soc_codec_conf **codec_conf)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct sdw_stream_runtime *sdw_stream;
- struct snd_soc_dai *dai;
+ 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;
int ret;
- /* Find stream from first CPU DAI */
- dai = asoc_rtd_to_cpu(rtd, 0);
-
- sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
- if (IS_ERR(sdw_stream)) {
- dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
- return PTR_ERR(sdw_stream);
- }
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- ret = sdw_enable_stream(sdw_stream);
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- ret = sdw_disable_stream(sdw_stream);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- if (ret)
- dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
-
- return ret;
-}
-
-int sdw_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- int ch = params_channels(params);
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
- unsigned int ch_mask;
- int num_codecs;
- int step;
- int i;
- int j;
-
- if (!rtd->dai_link->codec_ch_maps)
- return 0;
-
- /* Identical data will be sent to all codecs in playback */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ch_mask = GENMASK(ch - 1, 0);
- step = 0;
- } else {
- num_codecs = rtd->dai_link->num_codecs;
-
- if (ch < num_codecs || ch % num_codecs != 0) {
- dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
- ch, num_codecs);
- return -EINVAL;
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (sof_end->name_prefix) {
+ (*codec_conf)->dlc.name = sof_end->codec_name;
+ (*codec_conf)->name_prefix = sof_end->name_prefix;
+ (*codec_conf)++;
}
- ch_mask = GENMASK(ch / num_codecs - 1, 0);
- step = hweight_long(ch_mask);
-
- }
-
- /*
- * The captured data will be combined from each cpu DAI if the dai
- * link has more than one codec DAIs. Set codec channel mask and
- * ASoC will set the corresponding channel numbers for each cpu dai.
- */
- for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i)
- continue;
- rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step);
+ if (sof_end->include_sidecar && sof_end->codec_info->add_sidecar) {
+ ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
+ if (ret)
+ return ret;
}
}
- return 0;
-}
-
-int sdw_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct sdw_stream_runtime *sdw_stream;
- struct snd_soc_dai *dai;
- /* Find stream from first CPU DAI */
- dai = asoc_rtd_to_cpu(rtd, 0);
-
- sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
- if (IS_ERR(sdw_stream)) {
- dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
- return PTR_ERR(sdw_stream);
- }
+ for_each_pcm_streams(stream) {
+ static const char * const sdw_stream_name[] = {
+ "SDW%d-Playback",
+ "SDW%d-Capture",
+ "SDW%d-Playback-%s",
+ "SDW%d-Capture-%s",
+ };
+ struct snd_soc_dai_link_ch_map *codec_maps;
+ struct snd_soc_dai_link_component *codecs;
+ struct snd_soc_dai_link_component *cpus;
+ struct snd_soc_dai_link_component *platform;
+ int num_cpus = hweight32(sof_dai->link_mask[stream]);
+ int num_codecs = sof_dai->num_devs[stream];
+ int playback, capture;
+ int cur_link = 0;
+ int i = 0, j = 0;
+ char *name;
- return sdw_deprepare_stream(sdw_stream);
-}
+ if (!sof_dai->num_devs[stream])
+ continue;
-void sdw_shutdown(struct snd_pcm_substream *substream)
-{
- sdw_shutdown_stream(substream);
-}
+ sof_end = list_first_entry(&sof_dai->endpoints,
+ struct asoc_sdw_endpoint, list);
-static const struct snd_soc_ops sdw_ops = {
- .startup = sdw_startup,
- .prepare = sdw_prepare,
- .trigger = sdw_trigger,
- .hw_params = sdw_hw_params,
- .hw_free = sdw_hw_free,
- .shutdown = sdw_shutdown,
-};
+ *be_id = sof_end->dai_info->dailink[stream];
+ if (*be_id < 0) {
+ dev_err(dev, "Invalid dailink id %d\n", *be_id);
+ return -EINVAL;
+ }
-static struct sof_sdw_codec_info codec_info_list[] = {
- {
- .part_id = 0x700,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt700-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_rt700_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x711,
- .version_id = 3,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt711-sdca-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_rt_sdca_jack_init,
- .exit = sof_sdw_rt_sdca_jack_exit,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x711,
- .version_id = 2,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt711-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_rt711_init,
- .exit = sof_sdw_rt711_exit,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x712,
- .version_id = 3,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt712-sdca-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_rt_sdca_jack_init,
- .exit = sof_sdw_rt_sdca_jack_exit,
- },
- {
- .direction = {true, false},
- .dai_name = "rt712-sdca-aif2",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
- .init = sof_sdw_rt712_spk_init,
- },
- },
- .dai_num = 2,
- },
- {
- .part_id = 0x1712,
- .version_id = 3,
- .dais = {
- {
- .direction = {false, true},
- .dai_name = "rt712-sdca-dmic-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt712_sdca_dmic_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x713,
- .version_id = 3,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt712-sdca-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_rt_sdca_jack_init,
- .exit = sof_sdw_rt_sdca_jack_exit,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x1713,
- .version_id = 3,
- .dais = {
- {
- .direction = {false, true},
- .dai_name = "rt712-sdca-dmic-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt712_sdca_dmic_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x1308,
- .acpi_id = "10EC1308",
- .dais = {
- {
- .direction = {true, false},
- .dai_name = "rt1308-aif",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
- .init = sof_sdw_rt_amp_init,
- .exit = sof_sdw_rt_amp_exit,
- },
- },
- .dai_num = 1,
- .ops = &sof_sdw_rt1308_i2s_ops,
- },
- {
- .part_id = 0x1316,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt1316-aif",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
- .init = sof_sdw_rt_amp_init,
- .exit = sof_sdw_rt_amp_exit,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x1318,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt1318-aif",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
- .init = sof_sdw_rt_amp_init,
- .exit = sof_sdw_rt_amp_exit,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x714,
- .version_id = 3,
- .ignore_pch_dmic = true,
- .dais = {
- {
- .direction = {false, true},
- .dai_name = "rt715-aif2",
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt715_sdca_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x715,
- .version_id = 3,
- .ignore_pch_dmic = true,
- .dais = {
- {
- .direction = {false, true},
- .dai_name = "rt715-aif2",
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt715_sdca_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x714,
- .version_id = 2,
- .ignore_pch_dmic = true,
- .dais = {
- {
- .direction = {false, true},
- .dai_name = "rt715-aif2",
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt715_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x715,
- .version_id = 2,
- .ignore_pch_dmic = true,
- .dais = {
- {
- .direction = {false, true},
- .dai_name = "rt715-aif2",
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = sof_sdw_rt715_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x8373,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "max98373-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
- .init = sof_sdw_maxim_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x8363,
- .dais = {
- {
- .direction = {true, false},
- .dai_name = "max98363-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
- .init = sof_sdw_maxim_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x5682,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "rt5682-sdw",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_rt5682_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x4242,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "cs42l42-sdw",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = sof_sdw_cs42l42_init,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0xaaaa, /* generic codec mockup */
- .version_id = 0,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "sdw-mockup-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = NULL,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0xaa55, /* headset codec mockup */
- .version_id = 0,
- .dais = {
- {
- .direction = {true, true},
- .dai_name = "sdw-mockup-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_JACK,
- .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},
- .init = NULL,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x55aa, /* amplifier mockup */
- .version_id = 0,
- .dais = {
- {
- .direction = {true, false},
- .dai_name = "sdw-mockup-aif1",
- .dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
- .init = NULL,
- },
- },
- .dai_num = 1,
- },
- {
- .part_id = 0x5555,
- .version_id = 0,
- .dais = {
- {
- .dai_name = "sdw-mockup-aif1",
- .direction = {false, true},
- .dai_type = SOF_SDW_DAI_TYPE_MIC,
- .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},
- .init = NULL,
- },
- },
- .dai_num = 1,
- },
-};
+ /* create stream name according to first link id */
+ if (ctx->append_dai_type)
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ sdw_stream_name[stream + 2],
+ ffs(sof_end->link_mask) - 1,
+ type_strings[sof_end->dai_info->dai_type]);
+ else
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ sdw_stream_name[stream],
+ ffs(sof_end->link_mask) - 1);
+ if (!name)
+ return -ENOMEM;
-static inline int find_codec_info_part(u64 adr)
-{
- unsigned int part_id, sdw_version;
- int i;
+ cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
- part_id = SDW_PART_ID(adr);
- sdw_version = SDW_VERSION(adr);
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
- /*
- * A codec info is for all sdw version with the part id if
- * version_id is not specified in the codec info.
- */
- if (part_id == codec_info_list[i].part_id &&
- (!codec_info_list[i].version_id ||
- sdw_version == codec_info_list[i].version_id))
- return i;
+ codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
+ if (!codecs)
+ return -ENOMEM;
- return -EINVAL;
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!platform)
+ return -ENOMEM;
-}
+ codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
+ if (!codec_maps)
+ return -ENOMEM;
-static inline int find_codec_info_acpi(const u8 *acpi_id)
-{
- int i;
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (!sof_end->dai_info->direction[stream])
+ continue;
- if (!acpi_id[0])
- return -EINVAL;
+ if (cur_link != sof_end->link_mask) {
+ int link_num = ffs(sof_end->link_mask) - 1;
+ int pin_num = intel_ctx->sdw_pin_index[link_num]++;
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
- if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
- ACPI_ID_LEN))
- break;
+ cur_link = sof_end->link_mask;
- if (i == ARRAY_SIZE(codec_info_list))
- return -EINVAL;
+ cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SDW%d Pin%d",
+ link_num, pin_num);
+ if (!cpus[i].dai_name)
+ return -ENOMEM;
+ i++;
+ }
- return i;
-}
+ codec_maps[j].cpu = i - 1;
+ codec_maps[j].codec = j;
-/*
- * get BE dailink number and CPU DAI number based on sdw link adr.
- * Since some sdw slaves may be aggregated, the CPU DAI number
- * may be larger than the number of BE dailinks.
- */
-static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
- int *sdw_be_num, int *sdw_cpu_dai_num)
-{
- const struct snd_soc_acpi_link_adr *link;
- bool group_visited[SDW_MAX_GROUPS];
- bool no_aggregation;
- int i;
- int j;
-
- no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
- *sdw_cpu_dai_num = 0;
- *sdw_be_num = 0;
-
- if (!links)
- return -EINVAL;
-
- for (i = 0; i < SDW_MAX_GROUPS; i++)
- group_visited[i] = false;
-
- for (link = links; link->num_adr; link++) {
- const struct snd_soc_acpi_endpoint *endpoint;
- struct sof_sdw_codec_info *codec_info;
- int codec_index;
- int stream;
- u64 adr;
-
- for (i = 0; i < link->num_adr; i++) {
- adr = link->adr_d[i].adr;
- codec_index = find_codec_info_part(adr);
- if (codec_index < 0)
- return codec_index;
- codec_info = &codec_info_list[codec_index];
-
- endpoint = link->adr_d[i].endpoints;
-
- for (j = 0; j < codec_info->dai_num; j++) {
- /* count DAI number for playback and capture */
- for_each_pcm_streams(stream) {
- if (!codec_info->dais[j].direction[stream])
- continue;
-
- (*sdw_cpu_dai_num)++;
-
- /* count BE for each non-aggregated slave or group */
- if (!endpoint->aggregated || no_aggregation ||
- !group_visited[endpoint->group_id])
- (*sdw_be_num)++;
- }
+ 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");
}
-
- if (endpoint->aggregated)
- group_visited[endpoint->group_id] = true;
+ j++;
}
- }
- return 0;
-}
-
-static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
- int be_id, char *name, int playback, int capture,
- struct snd_soc_dai_link_component *cpus, int cpus_num,
- struct snd_soc_dai_link_component *codecs, int codecs_num,
- int (*init)(struct snd_soc_pcm_runtime *rtd),
- const struct snd_soc_ops *ops)
-{
- dev_dbg(dev, "create dai link %s, id %d\n", name, be_id);
- dai_links->id = be_id;
- dai_links->name = name;
- dai_links->platforms = platform_component;
- dai_links->num_platforms = ARRAY_SIZE(platform_component);
- dai_links->no_pcm = 1;
- dai_links->cpus = cpus;
- dai_links->num_cpus = cpus_num;
- dai_links->codecs = codecs;
- dai_links->num_codecs = codecs_num;
- dai_links->dpcm_playback = playback;
- dai_links->dpcm_capture = capture;
- dai_links->init = init;
- dai_links->ops = ops;
-}
-
-static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
- unsigned int sdw_version,
- unsigned int mfg_id,
- unsigned int part_id,
- unsigned int class_id,
- int index_in_link
- )
-{
- int i;
-
- for (i = 0; i < link->num_adr; i++) {
- unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
- u64 adr;
-
- /* skip itself */
- if (i == index_in_link)
- continue;
+ WARN_ON(i != num_cpus || j != num_codecs);
- adr = link->adr_d[i].adr;
-
- sdw1_version = SDW_VERSION(adr);
- mfg1_id = SDW_MFG_ID(adr);
- part1_id = SDW_PART_ID(adr);
- class1_id = SDW_CLASS_ID(adr);
-
- if (sdw_version == sdw1_version &&
- mfg_id == mfg1_id &&
- part_id == part1_id &&
- class_id == class1_id)
- return false;
- }
-
- return true;
-}
-
-static int create_codec_dai_name(struct device *dev,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link_component *codec,
- int offset,
- struct snd_soc_codec_conf *codec_conf,
- int codec_count,
- int *codec_conf_index,
- int adr_index,
- int dai_index)
-{
- int _codec_index = -1;
- int i;
-
- /* sanity check */
- if (*codec_conf_index + link->num_adr - adr_index > codec_count) {
- dev_err(dev, "codec_conf: out-of-bounds access requested\n");
- return -EINVAL;
- }
-
- for (i = adr_index; i < link->num_adr; i++) {
- unsigned int sdw_version, unique_id, mfg_id;
- unsigned int link_id, part_id, class_id;
- int codec_index, comp_index;
- char *codec_str;
- u64 adr;
-
- adr = link->adr_d[i].adr;
-
- sdw_version = SDW_VERSION(adr);
- link_id = SDW_DISCO_LINK_ID(adr);
- unique_id = SDW_UNIQUE_ID(adr);
- mfg_id = SDW_MFG_ID(adr);
- part_id = SDW_PART_ID(adr);
- class_id = SDW_CLASS_ID(adr);
-
- comp_index = i - adr_index + offset;
- if (is_unique_device(link, sdw_version, mfg_id, part_id,
- class_id, i)) {
- codec_str = "sdw:%01x:%04x:%04x:%02x";
- codec[comp_index].name =
- devm_kasprintf(dev, GFP_KERNEL, codec_str,
- link_id, mfg_id, part_id,
- class_id);
- } else {
- codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
- codec[comp_index].name =
- devm_kasprintf(dev, GFP_KERNEL, codec_str,
- link_id, mfg_id, part_id,
- class_id, unique_id);
- }
+ playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
- if (!codec[comp_index].name)
- return -ENOMEM;
+ asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
+ cpus, num_cpus, platform, 1, codecs, num_codecs,
+ 1, asoc_sdw_rtd_init, &sdw_ops);
- codec_index = find_codec_info_part(adr);
- if (codec_index < 0)
- return codec_index;
- if (_codec_index != -1 && codec_index != _codec_index) {
- dev_dbg(dev, "Different devices on the same sdw link\n");
- break;
+ /*
+ * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
+ * based on wait_for_completion(), tag them as 'nonatomic'.
+ */
+ (*dai_links)->nonatomic = true;
+ (*dai_links)->ch_maps = codec_maps;
+
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (sof_end->dai_info->init)
+ sof_end->dai_info->init(card, *dai_links,
+ sof_end->codec_info,
+ playback);
}
- _codec_index = codec_index;
- codec[comp_index].dai_name =
- codec_info_list[codec_index].dais[dai_index].dai_name;
-
- codec_conf[*codec_conf_index].dlc = codec[comp_index];
- codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
-
- ++*codec_conf_index;
+ (*dai_links)++;
}
return 0;
}
-static int set_codec_init_func(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- bool playback, int group_id, int adr_index, int dai_index)
+static int create_sdw_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ struct asoc_sdw_dailink *sof_dais,
+ struct snd_soc_codec_conf **codec_conf)
{
- int i = adr_index;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
+ int ret, i;
- do {
- /*
- * Initialize the codec. If codec is part of an aggregated
- * group (group_id>0), initialize all codecs belonging to
- * same group.
- * The first link should start with link->adr_d[adr_index]
- * because that is the device that we want to initialize and
- * we should end immediately if it is not aggregated (group_id=0)
- */
- for ( ; i < link->num_adr; i++) {
- int codec_index;
+ for (i = 0; i < SDW_INTEL_MAX_LINKS; i++)
+ intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE;
- codec_index = find_codec_info_part(link->adr_d[i].adr);
+ /* generate DAI links by each sdw link */
+ while (sof_dais->initialised) {
+ int current_be_id = 0;
- if (codec_index < 0)
- return codec_index;
+ ret = create_sdw_dailink(card, sof_dais, dai_links,
+ &current_be_id, codec_conf);
+ if (ret)
+ return ret;
- /* The group_id is > 0 iff the codec is aggregated */
- if (link->adr_d[i].endpoints->group_id != group_id)
- continue;
+ /* Update the be_id to match the highest ID used for SDW link */
+ if (*be_id < current_be_id)
+ *be_id = current_be_id;
- if (codec_info_list[codec_index].dais[dai_index].init)
- codec_info_list[codec_index].dais[dai_index].init(card,
- link,
- dai_links,
- &codec_info_list[codec_index],
- playback);
- if (!group_id)
- return 0;
- }
- i = 0;
- link++;
- } while (link->mask);
+ sof_dais++;
+ }
return 0;
}
-/*
- * check endpoint status in slaves and gather link ID for all slaves in
- * the same group to generate different CPU DAI. Now only support
- * one sdw link with all slaves set with only single group id.
- *
- * one slave on one sdw link with aggregated = 0
- * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
- *
- * two or more slaves on one sdw link with aggregated = 0
- * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs
- *
- * multiple links with multiple slaves with aggregated = 1
- * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
- */
-static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
- struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
- int *codec_num, unsigned int *group_id,
- bool *group_generated, int adr_index)
+static int create_ssp_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ struct asoc_sdw_codec_info *ssp_info,
+ unsigned long ssp_mask)
{
- const struct snd_soc_acpi_adr_device *adr_d;
- const struct snd_soc_acpi_link_adr *adr_next;
- bool no_aggregation;
- int index = 0;
- int i;
-
- no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
- adr_d = &adr_link->adr_d[adr_index];
-
- /* make sure the link mask has a single bit set */
- if (!is_power_of_2(adr_link->mask))
- return -EINVAL;
-
- cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
- if (!adr_d->endpoints->aggregated || no_aggregation) {
- *cpu_dai_num = 1;
- *codec_num = 1;
- *group_id = 0;
- return 0;
- }
-
- *group_id = adr_d->endpoints->group_id;
-
- /* Count endpoints with the same group_id in the adr_link */
- *codec_num = 0;
- for (i = 0; i < adr_link->num_adr; i++) {
- if (adr_link->adr_d[i].endpoints->aggregated &&
- adr_link->adr_d[i].endpoints->group_id == *group_id)
- (*codec_num)++;
- }
+ struct device *dev = card->dev;
+ int i, j = 0;
+ int ret;
- /* gather other link ID of slaves in the same group */
- for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
- adr_next++) {
- const struct snd_soc_acpi_endpoint *endpoint;
+ for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
+ char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
+ char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
+ ssp_info->acpi_id, j++);
+ if (!name || !cpu_dai_name || !codec_name)
+ return -ENOMEM;
- endpoint = adr_next->adr_d->endpoints;
- if (!endpoint->aggregated ||
- endpoint->group_id != *group_id)
- continue;
+ int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
+ int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
- /* make sure the link mask has a single bit set */
- if (!is_power_of_2(adr_next->mask))
- return -EINVAL;
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
+ playback, capture, cpu_dai_name,
+ "dummy", codec_name,
+ ssp_info->dais[0].dai_name, 1, NULL,
+ ssp_info->ops);
+ if (ret)
+ return ret;
- if (index >= SDW_MAX_CPU_DAIS) {
- dev_err(dev, " cpu_dai_id array overflows");
- return -EINVAL;
- }
+ ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
+ if (ret < 0)
+ return ret;
- cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
- for (i = 0; i < adr_next->num_adr; i++) {
- if (adr_next->adr_d[i].endpoints->aggregated &&
- adr_next->adr_d[i].endpoints->group_id == *group_id)
- (*codec_num)++;
- }
+ (*dai_links)++;
}
- /*
- * indicate CPU DAIs for this group have been generated
- * to avoid generating CPU DAIs for this group again.
- */
- group_generated[*group_id] = true;
- *cpu_dai_num = index;
-
return 0;
}
-static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps,
- int codec_num, int cpu_num)
+static int create_dmic_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id)
{
- int step;
- int i;
-
- step = codec_num / cpu_num;
- for (i = 0; i < codec_num; i++)
- sdw_codec_ch_maps[i].connected_cpu_id = i / step;
-}
-
-static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
-
-static int create_sdw_dailink(struct snd_soc_card *card,
- struct device *dev, int *link_index,
- struct snd_soc_dai_link *dai_links,
- int sdw_be_num, int sdw_cpu_dai_num,
- struct snd_soc_dai_link_component *cpus,
- const struct snd_soc_acpi_link_adr *link,
- int *cpu_id, bool *group_generated,
- struct snd_soc_codec_conf *codec_conf,
- int codec_count, int *link_id,
- int *codec_conf_index,
- bool *ignore_pch_dmic,
- bool append_dai_type,
- int adr_index,
- int dai_index)
-{
- const struct snd_soc_acpi_link_adr *link_next;
- struct snd_soc_dai_link_component *codecs;
- struct sof_sdw_codec_info *codec_info;
- int cpu_dai_id[SDW_MAX_CPU_DAIS];
- int cpu_dai_num, cpu_dai_index;
- unsigned int group_id;
- int codec_idx = 0;
- int codec_index;
- int codec_num;
- int stream;
- int i = 0;
+ struct device *dev = card->dev;
int ret;
- int k;
- ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
- &group_id, group_generated, adr_index);
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
+ 0, 1, // DMIC only supports capture
+ "DMIC01 Pin", "dummy",
+ "dmic-codec", "dmic-hifi", 1,
+ asoc_sdw_dmic_init, NULL);
if (ret)
return ret;
- codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
- if (!codecs)
- return -ENOMEM;
-
- /* generate codec name on different links in the same group */
- for (link_next = link; link_next && link_next->num_adr &&
- i < cpu_dai_num; link_next++) {
- const struct snd_soc_acpi_endpoint *endpoints;
+ (*dai_links)++;
- endpoints = link_next->adr_d->endpoints;
- if (group_id && (!endpoints->aggregated ||
- endpoints->group_id != group_id))
- continue;
-
- /* skip the link excluded by this processed group */
- if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
- continue;
-
- ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
- codec_conf, codec_count, codec_conf_index,
- adr_index, dai_index);
- if (ret < 0)
- return ret;
-
- /* check next link to create codec dai in the processed group */
- i++;
- codec_idx += link_next->num_adr;
- }
-
- /* find codec info to create BE DAI */
- codec_index = find_codec_info_part(link->adr_d[adr_index].adr);
- if (codec_index < 0)
- return codec_index;
- codec_info = &codec_info_list[codec_index];
-
- if (codec_info->ignore_pch_dmic)
- *ignore_pch_dmic = true;
-
- cpu_dai_index = *cpu_id;
- for_each_pcm_streams(stream) {
- struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps;
- char *name, *cpu_name;
- int playback, capture;
- static const char * const sdw_stream_name[] = {
- "SDW%d-Playback",
- "SDW%d-Capture",
- "SDW%d-Playback-%s",
- "SDW%d-Capture-%s",
- };
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
+ 0, 1, // DMIC only supports capture
+ "DMIC16k Pin", "dummy",
+ "dmic-codec", "dmic-hifi", 1,
+ /* don't call asoc_sdw_dmic_init() twice */
+ NULL, NULL);
+ if (ret)
+ return ret;
- if (!codec_info->dais[dai_index].direction[stream])
- continue;
+ (*dai_links)++;
- *link_id = codec_info->dais[dai_index].dailink[stream];
- if (*link_id < 0) {
- dev_err(dev, "Invalid dailink id %d\n", *link_id);
- return -EINVAL;
- }
+ return 0;
+}
- sdw_codec_ch_maps = devm_kcalloc(dev, codec_num,
- sizeof(*sdw_codec_ch_maps), GFP_KERNEL);
- if (!sdw_codec_ch_maps)
- return -ENOMEM;
+static int create_hdmi_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id,
+ int hdmi_num)
+{
+ struct device *dev = card->dev;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
+ int i, ret;
- /* create stream name according to first link id */
- if (append_dai_type) {
- name = devm_kasprintf(dev, GFP_KERNEL,
- sdw_stream_name[stream + 2], cpu_dai_id[0],
- type_strings[codec_info->dais[dai_index].dai_type]);
- } else {
- name = devm_kasprintf(dev, GFP_KERNEL,
- sdw_stream_name[stream], cpu_dai_id[0]);
- }
- if (!name)
+ for (i = 0; i < hdmi_num; i++) {
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
+ char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
+ if (!name || !cpu_dai_name)
return -ENOMEM;
- /*
- * generate CPU DAI name base on the sdw link ID and
- * PIN ID with offset of 2 according to sdw dai driver.
- */
- for (k = 0; k < cpu_dai_num; k++) {
- cpu_name = devm_kasprintf(dev, GFP_KERNEL,
- "SDW%d Pin%d", cpu_dai_id[k],
- sdw_pin_index[cpu_dai_id[k]]++);
- if (!cpu_name)
- return -ENOMEM;
-
- if (cpu_dai_index >= sdw_cpu_dai_num) {
- dev_err(dev, "invalid cpu dai index %d",
- cpu_dai_index);
- return -EINVAL;
- }
-
- cpus[cpu_dai_index++].dai_name = cpu_name;
- }
-
- /*
- * We create sdw dai links at first stage, so link index should
- * not be larger than sdw_be_num
- */
- if (*link_index >= sdw_be_num) {
- dev_err(dev, "invalid dai link index %d", *link_index);
- return -EINVAL;
- }
+ char *codec_name, *codec_dai_name;
- if (*cpu_id >= sdw_cpu_dai_num) {
- dev_err(dev, " invalid cpu dai index %d", *cpu_id);
- return -EINVAL;
+ if (intel_ctx->hdmi.idisp_codec) {
+ codec_name = "ehdaudio0D2";
+ codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "intel-hdmi-hifi%d", i + 1);
+ } else {
+ codec_name = "snd-soc-dummy";
+ codec_dai_name = "snd-soc-dummy-dai";
}
- playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
- capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
- init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
- playback, capture,
- cpus + *cpu_id, cpu_dai_num,
- codecs, codec_num,
- NULL, &sdw_ops);
+ if (!codec_dai_name)
+ return -ENOMEM;
- /*
- * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
- * based on wait_for_completion(), tag them as 'nonatomic'.
- */
- dai_links[*link_index].nonatomic = true;
-
- set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
- dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps;
- ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
- playback, group_id, adr_index, dai_index);
- if (ret < 0) {
- dev_err(dev, "failed to init codec %d", codec_index);
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
+ 1, 0, // HDMI only supports playback
+ cpu_dai_name, "dummy",
+ codec_name, codec_dai_name, 1,
+ i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
+ if (ret)
return ret;
- }
- *cpu_id += cpu_dai_num;
+ (*dai_links)++;
}
return 0;
}
-#define IDISP_CODEC_MASK 0x4
-
-static int sof_card_codec_conf_alloc(struct device *dev,
- struct snd_soc_acpi_mach_params *mach_params,
- struct snd_soc_codec_conf **codec_conf,
- int *codec_conf_count)
+static int create_bt_dailinks(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links, int *be_id)
{
- const struct snd_soc_acpi_link_adr *adr_link;
- struct snd_soc_codec_conf *c_conf;
- int num_codecs = 0;
- int codec_index;
- int i;
-
- adr_link = mach_params->links;
- if (!adr_link)
- return -EINVAL;
+ struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
+ char *cpu_dai_name;
+ char *name;
+ int port;
+ int ret;
- /* generate DAI links by each sdw link */
- for (; adr_link->num_adr; adr_link++) {
- for (i = 0; i < adr_link->num_adr; i++) {
- if (!adr_link->adr_d[i].name_prefix) {
- dev_err(dev, "codec 0x%llx does not have a name prefix\n",
- adr_link->adr_d[i].adr);
- return -EINVAL;
- }
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
- num_codecs += codec_info_list[codec_index].dai_num;
- }
- }
+ if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
+ port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT;
+ else
+ port = fls(mach->mach_params.bt_link_mask) - 1;
- c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
- if (!c_conf)
+ name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
+ cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
+ if (!name || !cpu_dai_name)
return -ENOMEM;
- *codec_conf = c_conf;
- *codec_conf_count = num_codecs;
+ ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
+ 1, 1, cpu_dai_name, "dummy",
+ snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
+ 1, NULL, NULL);
+ if (ret)
+ return ret;
+
+ (*dai_links)++;
return 0;
}
-static int sof_card_dai_links_create(struct device *dev,
- struct snd_soc_acpi_mach *mach,
- struct snd_soc_card *card)
+static int sof_card_dai_links_create(struct snd_soc_card *card)
{
- int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai_link_component *idisp_components;
- struct snd_soc_dai_link_component *ssp_components;
- struct snd_soc_acpi_mach_params *mach_params;
- const struct snd_soc_acpi_link_adr *adr_link;
- struct snd_soc_dai_link_component *cpus;
+ struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+ int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
struct snd_soc_codec_conf *codec_conf;
- bool append_dai_type = false;
- bool ignore_pch_dmic = false;
- int codec_conf_count;
- int codec_conf_index = 0;
- bool group_generated[SDW_MAX_GROUPS];
- int ssp_codec_index, ssp_mask;
- struct snd_soc_dai_link *links;
- int num_links, link_index = 0;
- char *name, *cpu_name;
- int total_cpu_dai_num;
- int sdw_cpu_dai_num;
- int i, j, be_id = 0;
- int codec_index;
- int cpu_id = 0;
- int comp_num;
+ struct asoc_sdw_codec_info *ssp_info;
+ struct asoc_sdw_endpoint *sof_ends;
+ struct asoc_sdw_dailink *sof_dais;
+ struct snd_soc_aux_dev *sof_aux;
+ int num_devs = 0;
+ int num_ends = 0;
+ int num_aux = 0;
+ int num_confs;
+ struct snd_soc_dai_link *dai_links;
+ int num_links;
+ int be_id = 0;
+ int hdmi_num;
+ unsigned long ssp_mask;
int ret;
- mach_params = &mach->mach_params;
-
- /* allocate codec conf, will be populated when dailinks are created */
- ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
- if (ret < 0)
+ ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
+ if (ret < 0) {
+ dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
+ }
- /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
- codec_info_list[i].amp_num = 0;
+ num_confs = num_ends;
- if (mach_params->codec_mask & IDISP_CODEC_MASK) {
- ctx->idisp_codec = true;
+ /*
+ * One per DAI link, worst case is a DAI link for every endpoint, also
+ * add one additional to act as a terminator such that code can iterate
+ * until it hits an uninitialised DAI.
+ */
+ sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL);
+ if (!sof_dais)
+ return -ENOMEM;
- if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
- hdmi_num = SOF_TGL_HDMI_COUNT;
- else
- hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
+ /* One per endpoint, ie. each DAI on each codec/amp */
+ sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
+ if (!sof_ends) {
+ ret = -ENOMEM;
+ goto err_dai;
+ }
+
+ sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL);
+ if (!sof_aux) {
+ ret = -ENOMEM;
+ goto err_dai;
}
- ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
+ ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs);
+ if (ret < 0)
+ goto err_end;
+
+ sdw_be_num = ret;
+
/*
* on generic tgl platform, I2S or sdw mode is supported
* based on board rework. A ACPI device is registered in
* system only when I2S mode is supported, not sdw mode.
* Here check ACPI ID to confirm I2S is supported.
*/
- ssp_codec_index = find_codec_info_acpi(mach->id);
- ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
- comp_num = hdmi_num + ssp_num;
-
- ret = get_sdw_dailink_info(dev, mach_params->links,
- &sdw_be_num, &sdw_cpu_dai_num);
- if (ret < 0) {
- dev_err(dev, "failed to get sdw link info %d", ret);
- return ret;
+ ssp_info = asoc_sdw_find_codec_info_acpi(mach->id);
+ if (ssp_info) {
+ ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
+ ssp_num = hweight_long(ssp_mask);
}
- /* enable dmic01 & dmic16k */
- dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
- comp_num += dmic_num;
-
- if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- comp_num++;
-
- dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
- dmic_num, ctx->idisp_codec ? hdmi_num : 0);
+ if (mach_params->codec_mask & IDISP_CODEC_MASK)
+ intel_ctx->hdmi.idisp_codec = true;
- /* allocate BE dailinks */
- num_links = comp_num + sdw_be_num;
- links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
-
- /* allocated CPU DAIs */
- total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
- cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
- GFP_KERNEL);
-
- if (!links || !cpus)
- return -ENOMEM;
-
- /* SDW */
- if (!sdw_be_num)
- goto SSP;
-
- adr_link = mach_params->links;
- if (!adr_link)
- return -EINVAL;
-
- /*
- * SoundWire Slaves aggregated in the same group may be
- * located on different hardware links. Clear array to indicate
- * CPU DAIs for this group have not been generated.
- */
- for (i = 0; i < SDW_MAX_GROUPS; i++)
- group_generated[i] = false;
-
- for (i = 0; i < SDW_MAX_LINKS; i++)
- sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
+ if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
+ hdmi_num = SOF_TGL_HDMI_COUNT;
+ else
+ hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
- for (; adr_link->num_adr; adr_link++) {
+ /* enable dmic01 & dmic16k */
+ 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;
/*
- * If there are two or more different devices on the same sdw link, we have to
- * append the codec type to the dai link name to prevent duplicated dai link name.
- * The same type devices on the same sdw link will be in the same
- * snd_soc_acpi_adr_device array. They won't be described in different adr_links.
+ * mach_params->dmic_num will be used to set the cfg-mics value of
+ * card->components string. Set it to the default value.
*/
- for (i = 0; i < adr_link->num_adr; i++) {
- /* find codec info to get dai_num */
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
- if (codec_info_list[codec_index].dai_num > 1) {
- append_dai_type = true;
- goto out;
- }
- for (j = 0; j < i; j++) {
- if ((SDW_PART_ID(adr_link->adr_d[i].adr) !=
- SDW_PART_ID(adr_link->adr_d[j].adr)) ||
- (SDW_MFG_ID(adr_link->adr_d[i].adr) !=
- SDW_MFG_ID(adr_link->adr_d[i].adr))) {
- append_dai_type = true;
- goto out;
- }
- }
- }
+ mach_params->dmic_num = DMIC_DEFAULT_CHANNELS;
}
-out:
- /* generate DAI links by each sdw link */
- for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) {
- for (i = 0; i < adr_link->num_adr; i++) {
- const struct snd_soc_acpi_endpoint *endpoint;
-
- endpoint = adr_link->adr_d[i].endpoints;
- if (endpoint->aggregated && !endpoint->group_id) {
- dev_err(dev, "invalid group id on link %x",
- adr_link->mask);
- continue;
- }
+ if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT || mach_params->bt_link_mask)
+ bt_num = 1;
- /* this group has been generated */
- if (endpoint->aggregated &&
- group_generated[endpoint->group_id])
- continue;
+ 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);
- /* find codec info to get dai_num */
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
-
- for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) {
- ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
- sdw_cpu_dai_num, cpus, adr_link,
- &cpu_id, group_generated,
- codec_conf, codec_conf_count,
- &be_id, &codec_conf_index,
- &ignore_pch_dmic, append_dai_type, i, j);
- if (ret < 0) {
- dev_err(dev, "failed to create dai link %d", link_index);
- return ret;
- }
- }
- }
+ codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL);
+ if (!codec_conf) {
+ ret = -ENOMEM;
+ goto err_end;
}
-SSP:
- /* SSP */
- if (!ssp_num)
- goto DMIC;
-
- for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
- struct sof_sdw_codec_info *info;
- int playback, capture;
- char *codec_name;
-
- if (!(ssp_mask & 0x1))
- continue;
-
- name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d-Codec", i);
- if (!name)
- return -ENOMEM;
-
- cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
- if (!cpu_name)
- return -ENOMEM;
-
- ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
- GFP_KERNEL);
- if (!ssp_components)
- return -ENOMEM;
-
- info = &codec_info_list[ssp_codec_index];
- codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
- info->acpi_id, j++);
- if (!codec_name)
- return -ENOMEM;
-
- ssp_components->name = codec_name;
- /* TODO: support multi codec dai on SSP when it is needed */
- ssp_components->dai_name = info->dais[0].dai_name;
- cpus[cpu_id].dai_name = cpu_name;
+ /* allocate BE dailinks */
+ num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
+ dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
+ if (!dai_links) {
+ ret = -ENOMEM;
+ goto err_end;
+ }
- playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
- capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
- init_dai_link(dev, links + link_index, be_id, name,
- playback, capture,
- cpus + cpu_id, 1,
- ssp_components, 1,
- NULL, info->ops);
+ card->codec_conf = codec_conf;
+ card->num_configs = num_confs;
+ card->dai_link = dai_links;
+ card->num_links = num_links;
+ card->aux_dev = sof_aux;
+ card->num_aux_devs = num_aux;
- ret = info->dais[0].init(card, NULL, links + link_index, info, 0);
- if (ret < 0)
- return ret;
+ /* SDW */
+ if (sdw_be_num) {
+ ret = create_sdw_dailinks(card, &dai_links, &be_id,
+ sof_dais, &codec_conf);
+ if (ret)
+ goto err_end;
+ }
- INC_ID(be_id, cpu_id, link_index);
+ /* SSP */
+ if (ssp_num) {
+ ret = create_ssp_dailinks(card, &dai_links, &be_id,
+ ssp_info, ssp_mask);
+ if (ret)
+ goto err_end;
}
-DMIC:
/* dmic */
- if (dmic_num > 0) {
- if (ignore_pch_dmic) {
- dev_warn(dev, "Ignoring PCH DMIC\n");
- goto HDMI;
- }
- cpus[cpu_id].dai_name = "DMIC01 Pin";
- init_dai_link(dev, links + link_index, be_id, "dmic01",
- 0, 1, // DMIC only supports capture
- cpus + cpu_id, 1,
- dmic_component, 1,
- sof_sdw_dmic_init, NULL);
- INC_ID(be_id, cpu_id, link_index);
-
- cpus[cpu_id].dai_name = "DMIC16k Pin";
- init_dai_link(dev, links + link_index, be_id, "dmic16k",
- 0, 1, // DMIC only supports capture
- cpus + cpu_id, 1,
- dmic_component, 1,
- /* don't call sof_sdw_dmic_init() twice */
- NULL, NULL);
- INC_ID(be_id, cpu_id, link_index);
+ if (dmic_num) {
+ ret = create_dmic_dailinks(card, &dai_links, &be_id);
+ if (ret)
+ goto err_end;
}
-HDMI:
/* HDMI */
- if (hdmi_num > 0) {
- idisp_components = devm_kcalloc(dev, hdmi_num,
- sizeof(*idisp_components),
- GFP_KERNEL);
- if (!idisp_components)
- return -ENOMEM;
- }
-
- for (i = 0; i < hdmi_num; i++) {
- name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d", i + 1);
- if (!name)
- return -ENOMEM;
-
- if (ctx->idisp_codec) {
- idisp_components[i].name = "ehdaudio0D2";
- idisp_components[i].dai_name = devm_kasprintf(dev,
- GFP_KERNEL,
- "intel-hdmi-hifi%d",
- i + 1);
- if (!idisp_components[i].dai_name)
- return -ENOMEM;
- } else {
- idisp_components[i] = asoc_dummy_dlc;
- }
-
- cpu_name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d Pin", i + 1);
- if (!cpu_name)
- return -ENOMEM;
+ ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
+ if (ret)
+ goto err_end;
- cpus[cpu_id].dai_name = cpu_name;
- init_dai_link(dev, links + link_index, be_id, name,
- 1, 0, // HDMI only supports playback
- cpus + cpu_id, 1,
- idisp_components + i, 1,
- sof_sdw_hdmi_init, NULL);
- INC_ID(be_id, cpu_id, link_index);
+ /* BT */
+ if (bt_num) {
+ ret = create_bt_dailinks(card, &dai_links, &be_id);
+ if (ret)
+ goto err_end;
}
- if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
+ WARN_ON(codec_conf != card->codec_conf + card->num_configs);
+ WARN_ON(dai_links != card->dai_link + card->num_links);
- name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
- if (!name)
- return -ENOMEM;
+err_end:
+ kfree(sof_ends);
+err_dai:
+ kfree(sof_dais);
- cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
- if (!cpu_name)
- return -ENOMEM;
-
- cpus[cpu_id].dai_name = cpu_name;
- init_dai_link(dev, links + link_index, be_id, name, 1, 1,
- cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
- }
-
- card->dai_link = links;
- card->num_links = num_links;
-
- card->codec_conf = codec_conf;
- card->num_configs = codec_conf_count;
-
- return 0;
+ return ret;
}
static int sof_sdw_card_late_probe(struct snd_soc_card *card)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
int ret = 0;
- int i;
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
- if (codec_info_list[i].codec_card_late_probe) {
- ret = codec_info_list[i].codec_card_late_probe(card);
-
- if (ret < 0)
- return ret;
- }
- }
+ ret = asoc_sdw_card_late_probe(card);
+ if (ret < 0)
+ return ret;
- if (ctx->idisp_codec)
+ if (intel_ctx->hdmi.idisp_codec)
ret = sof_sdw_hdmi_card_late_probe(card);
return ret;
}
-/* SoC card */
-static const char sdw_card_long_name[] = "Intel Soundwire SOF";
-
-static struct snd_soc_card card_sof_sdw = {
- .name = "soundwire",
- .owner = THIS_MODULE,
- .late_probe = sof_sdw_card_late_probe,
-};
-
-/* helper to get the link that the codec DAI is used */
-static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
- const char *dai_name)
+static int sof_sdw_add_dai_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link)
{
- struct snd_soc_dai_link *link;
- int i;
- int j;
-
- for_each_card_prelinks(card, i, link) {
- for (j = 0; j < link->num_codecs; j++) {
- /* Check each codec in a link */
- if (!strcmp(link->codecs[j].dai_name, dai_name))
- return link;
- }
- }
- return NULL;
-}
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
-static void mc_dailink_exit_loop(struct snd_soc_card *card)
-{
- struct snd_soc_dai_link *link;
- int ret;
- int i, j;
+ /* Ignore the HDMI PCM link if iDisp is not present */
+ if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec)
+ link->ignore = true;
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
- for (j = 0; j < codec_info_list[i].dai_num; j++) {
- /* Check each dai in codec_info_lis to see if it is used in the link */
- if (!codec_info_list[i].dais[j].exit)
- continue;
- /*
- * We don't need to call .exit function if there is no matched
- * dai link found.
- */
- link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name);
- if (link) {
- /* Do the .exit function if the codec dai is used in the link */
- ret = codec_info_list[i].dais[j].exit(card, link);
- if (ret)
- dev_warn(card->dev,
- "codec exit failed %d\n",
- ret);
- break;
- }
- }
- }
+ return 0;
}
static int mc_probe(struct platform_device *pdev)
{
- struct snd_soc_card *card = &card_sof_sdw;
- struct snd_soc_acpi_mach *mach;
- struct mc_private *ctx;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
+ struct snd_soc_card *card;
+ struct asoc_sdw_mc_private *ctx;
+ struct intel_mc_ctx *intel_ctx;
int amp_num = 0, i;
int ret;
dev_dbg(&pdev->dev, "Entry\n");
+ intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL);
+ if (!intel_ctx)
+ return -ENOMEM;
+
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+ ctx->private = intel_ctx;
+ ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
+ card = &ctx->card;
+ card->dev = &pdev->dev;
+ card->name = "soundwire";
+ card->owner = THIS_MODULE;
+ card->late_probe = sof_sdw_card_late_probe;
+ card->add_dai_link = sof_sdw_add_dai_link;
+
+ 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) {
- dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
sof_sdw_quirk, quirk_override);
sof_sdw_quirk = quirk_override;
}
- log_quirks(&pdev->dev);
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ log_quirks(card->dev);
- card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(card, ctx);
+ ctx->mc_quirk = sof_sdw_quirk;
+ /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
+ for (i = 0; i < ctx->codec_info_list_count; i++)
+ codec_info_list[i].amp_num = 0;
- mach = pdev->dev.platform_data;
- ret = sof_card_dai_links_create(&pdev->dev, mach,
- card);
+ ret = sof_card_dai_links_create(card);
if (ret < 0)
return ret;
@@ -1995,13 +1436,11 @@ static int mc_probe(struct platform_device *pdev)
* amp_num will only be increased for active amp
* codecs on used platform
*/
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
+ for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "cfg-spk:%d cfg-amp:%d",
- (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
- ? 4 : 2, amp_num);
+ " cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
@@ -2014,13 +1453,11 @@ static int mc_probe(struct platform_device *pdev)
return -ENOMEM;
}
- card->long_name = sdw_card_long_name;
-
/* Register the card */
- ret = devm_snd_soc_register_card(&pdev->dev, card);
+ ret = devm_snd_soc_register_card(card->dev, card);
if (ret) {
- dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
- mc_dailink_exit_loop(card);
+ dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -2033,16 +1470,23 @@ static void mc_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- mc_dailink_exit_loop(card);
+ asoc_sdw_mc_dailink_exit_loop(card);
}
+static const struct platform_device_id mc_id_table[] = {
+ { "sof_sdw", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, mc_id_table);
+
static struct platform_driver sof_sdw_driver = {
.driver = {
.name = "sof_sdw",
.pm = &snd_soc_pm_ops,
},
.probe = mc_probe,
- .remove_new = mc_remove,
+ .remove = mc_remove,
+ .id_table = mc_id_table,
};
module_platform_driver(sof_sdw_driver);
@@ -2052,6 +1496,5 @@ MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sof_sdw");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index 37402170d5f9..3aa1dcec5172 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -12,17 +12,12 @@
#include <linux/bits.h>
#include <linux/types.h>
#include <sound/soc.h>
+#include <sound/soc_sdw_utils.h>
+#include "sof_hdmi_common.h"
-#define MAX_NO_PROPS 2
#define MAX_HDMI_NUM 4
-#define SDW_UNUSED_DAI_ID -1
-#define SDW_JACK_OUT_DAI_ID 0
-#define SDW_JACK_IN_DAI_ID 1
-#define SDW_AMP_OUT_DAI_ID 2
-#define SDW_AMP_IN_DAI_ID 3
-#define SDW_DMIC_DAI_ID 4
-#define SDW_MAX_CPU_DAIS 16
-#define SDW_INTEL_BIDIR_PDI_BASE 2
+#define SOC_SDW_MAX_CPU_DAIS 16
+#define SOC_SDW_INTEL_BIDIR_PDI_BASE 2
/* 8 combinations with 4 links + unused group 0 */
#define SDW_MAX_GROUPS 9
@@ -41,13 +36,14 @@ enum {
SOF_I2S_SSP5 = BIT(5),
};
-#define SOF_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0))
-#define SOF_SDW_FOUR_SPK BIT(4)
+/* Deprecated and no longer supported by the code */
+#define SOC_SDW_FOUR_SPK BIT(4)
#define SOF_SDW_TGL_HDMI BIT(5)
-#define SOF_SDW_PCH_DMIC BIT(6)
+#define SOC_SDW_PCH_DMIC BIT(6)
#define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7)
#define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0))
-#define SOF_SDW_NO_AGGREGATION BIT(14)
+/* Deprecated and no longer supported by the code */
+#define SOC_SDW_NO_AGGREGATION BIT(14)
/* BT audio offload: reserve 3 bits for future */
#define SOF_BT_OFFLOAD_SSP_SHIFT 15
@@ -56,153 +52,15 @@ enum {
(((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(18)
-#define SOF_SDW_DAI_TYPE_JACK 0
-#define SOF_SDW_DAI_TYPE_AMP 1
-#define SOF_SDW_DAI_TYPE_MIC 2
-
-#define SOF_SDW_MAX_DAI_NUM 3
-
-struct sof_sdw_codec_info;
-
-struct sof_sdw_dai_info {
- const bool direction[2]; /* playback & capture support */
- const char *dai_name;
- const int dai_type;
- const int dailink[2]; /* dailink id for each direction */
- int (*init)(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
- int (*exit)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-};
-
-struct sof_sdw_codec_info {
- const int part_id;
- const int version_id;
- int amp_num;
- const u8 acpi_id[ACPI_ID_LEN];
- const bool ignore_pch_dmic;
- const struct snd_soc_ops *ops;
- struct sof_sdw_dai_info dais[SOF_SDW_MAX_DAI_NUM];
- const int dai_num;
-
- int (*codec_card_late_probe)(struct snd_soc_card *card);
+struct intel_mc_ctx {
+ struct sof_hdmi_private hdmi;
+ /* To store SDW Pin index for each SoundWire link */
+ unsigned int sdw_pin_index[SDW_INTEL_MAX_LINKS];
};
-struct mc_private {
- struct list_head hdmi_pcm_list;
- bool idisp_codec;
- struct snd_soc_jack sdw_headset;
- struct device *headset_codec_dev; /* only one headset per card */
- struct device *amp_dev1, *amp_dev2;
-};
-
-extern unsigned long sof_sdw_quirk;
-
-int sdw_startup(struct snd_pcm_substream *substream);
-int sdw_prepare(struct snd_pcm_substream *substream);
-int sdw_trigger(struct snd_pcm_substream *substream, int cmd);
-int sdw_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params);
-int sdw_hw_free(struct snd_pcm_substream *substream);
-void sdw_shutdown(struct snd_pcm_substream *substream);
-
/* generic HDMI support */
int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd);
int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card);
-/* DMIC support */
-int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd);
-
-/* RT711 support */
-int sof_sdw_rt711_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-
-/* RT711-SDCA support */
-int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-
-/* RT712-SDCA support */
-int sof_sdw_rt712_sdca_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-int sof_sdw_rt712_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-int sof_sdw_rt712_spk_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-int sof_sdw_rt712_sdca_dmic_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
-/* RT700 support */
-int sof_sdw_rt700_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
-/* RT1308 I2S support */
-extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
-
-/* generic amp support */
-int sof_sdw_rt_amp_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
-
-/* RT1316 support */
-
-/* RT715 support */
-int sof_sdw_rt715_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
-/* RT715-SDCA support */
-int sof_sdw_rt715_sdca_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
-/* MAXIM codec support */
-int sof_sdw_maxim_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
-/* RT5682 support */
-int sof_sdw_rt5682_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
-/* CS42L42 support */
-int sof_sdw_cs42l42_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback);
-
#endif
diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c
index d47d8bf528c1..f92867deb029 100644
--- a/sound/soc/intel/boards/sof_sdw_hdmi.c
+++ b/sound/soc/intel/boards/sof_sdw_hdmi.c
@@ -5,57 +5,39 @@
* sof_sdw_hdmi - Helpers to handle HDMI from generic machine driver
*/
+#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/soundwire/sdw_intel.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/jack.h>
#include "sof_sdw_common.h"
#include "hda_dsp_common.h"
-struct hdmi_pcm {
- struct list_head head;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
- /* dai_link id is 1:1 mapped to the PCM device */
- pcm->device = rtd->dai_link->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+ intel_ctx->hdmi.hdmi_comp = dai->component;
return 0;
}
-#define NAME_SIZE 32
int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct hdmi_pcm *pcm;
- struct snd_soc_component *component = NULL;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
- if (!ctx->idisp_codec)
+ if (!intel_ctx->hdmi.idisp_codec)
return 0;
- if (list_empty(&ctx->hdmi_pcm_list))
+ if (!intel_ctx->hdmi.hdmi_comp)
return -EINVAL;
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
-
- return hda_dsp_hdmi_build_controls(card, component);
+ return hda_dsp_hdmi_build_controls(card, intel_ctx->hdmi.hdmi_comp);
}
diff --git a/sound/soc/intel/boards/sof_sdw_maxim.c b/sound/soc/intel/boards/sof_sdw_maxim.c
deleted file mode 100644
index 414c4d8dac77..000000000000
--- a/sound/soc/intel/boards/sof_sdw_maxim.c
+++ /dev/null
@@ -1,167 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-//
-// sof_sdw_maxim - Helpers to handle maxim codecs
-// codec devices from generic machine driver
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/control.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/soc-dapm.h>
-#include "sof_sdw_common.h"
-#include "sof_maxim_common.h"
-
-static int maxim_part_id;
-#define SOF_SDW_PART_ID_MAX98363 0x8363
-#define SOF_SDW_PART_ID_MAX98373 0x8373
-
-static const struct snd_soc_dapm_widget maxim_widgets[] = {
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
-static const struct snd_kcontrol_new maxim_controls[] = {
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static int spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:mx%04x",
- card->components, maxim_part_id);
- if (!card->components)
- return -ENOMEM;
-
- dev_dbg(card->dev, "soundwire maxim card components assigned : %s\n",
- card->components);
-
- ret = snd_soc_add_card_controls(card, maxim_controls,
- ARRAY_SIZE(maxim_controls));
- if (ret) {
- dev_err(card->dev, "mx%04x ctrls addition failed: %d\n", maxim_part_id, ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, maxim_widgets,
- ARRAY_SIZE(maxim_widgets));
- if (ret) {
- dev_err(card->dev, "mx%04x widgets addition failed: %d\n", maxim_part_id, ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
-
- return ret;
-}
-
-static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
- int ret;
- int j;
-
- /* set spk pin by playback only */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- return 0;
-
- cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(cpu_dai->component);
- char pin_name[16];
-
- snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
- codec_dai->component->name_prefix);
-
- if (enable)
- ret = snd_soc_dapm_enable_pin(dapm, pin_name);
- else
- ret = snd_soc_dapm_disable_pin(dapm, pin_name);
-
- if (!ret)
- snd_soc_dapm_sync(dapm);
- }
-
- return 0;
-}
-
-static int mx8373_sdw_prepare(struct snd_pcm_substream *substream)
-{
- int ret;
-
- /* according to soc_pcm_prepare dai link prepare is called first */
- ret = sdw_prepare(substream);
- if (ret < 0)
- return ret;
-
- return mx8373_enable_spk_pin(substream, true);
-}
-
-static int mx8373_sdw_hw_free(struct snd_pcm_substream *substream)
-{
- int ret;
-
- /* according to soc_pcm_hw_free dai link free is called first */
- ret = sdw_hw_free(substream);
- if (ret < 0)
- return ret;
-
- return mx8373_enable_spk_pin(substream, false);
-}
-
-static const struct snd_soc_ops max_98373_sdw_ops = {
- .startup = sdw_startup,
- .prepare = mx8373_sdw_prepare,
- .trigger = sdw_trigger,
- .hw_params = sdw_hw_params,
- .hw_free = mx8373_sdw_hw_free,
- .shutdown = sdw_shutdown,
-};
-
-static int mx8373_sdw_late_probe(struct snd_soc_card *card)
-{
- struct snd_soc_dapm_context *dapm = &card->dapm;
-
- /* Disable Left and Right Spk pin after boot */
- snd_soc_dapm_disable_pin(dapm, "Left Spk");
- snd_soc_dapm_disable_pin(dapm, "Right Spk");
- return snd_soc_dapm_sync(dapm);
-}
-
-int sof_sdw_maxim_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- info->amp_num++;
- if (info->amp_num == 2)
- dai_links->init = spk_init;
-
- maxim_part_id = info->part_id;
- switch (maxim_part_id) {
- case SOF_SDW_PART_ID_MAX98363:
- /* Default ops are set in function init_dai_link.
- * called as part of function create_sdw_dailink
- */
- break;
- case SOF_SDW_PART_ID_MAX98373:
- info->codec_card_late_probe = mx8373_sdw_late_probe;
- dai_links->ops = &max_98373_sdw_ops;
- break;
- default:
- dev_err(card->dev, "Invalid maxim_part_id %#x\n", maxim_part_id);
- return -EINVAL;
- }
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c b/sound/soc/intel/boards/sof_sdw_rt712_sdca.c
deleted file mode 100644
index 84c8025d24e3..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2023 Intel Corporation
-
-/*
- * sof_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/soundwire/sdw.h>
-#include <linux/soundwire/sdw_type.h>
-#include <sound/control.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/soc-dapm.h>
-#include "sof_sdw_common.h"
-
-static const struct snd_soc_dapm_widget rt712_spk_widgets[] = {
- SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-/*
- * dapm routes for rt712 spk will be registered dynamically according
- * to the number of rt712 spk used. The first two entries will be registered
- * for one codec case, and the last two entries are also registered
- * if two rt712s are used.
- */
-static const struct snd_soc_dapm_route rt712_spk_map[] = {
- { "Speaker", NULL, "rt712 SPOL" },
- { "Speaker", NULL, "rt712 SPOR" },
-};
-
-static const struct snd_kcontrol_new rt712_spk_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static int rt712_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- int ret;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:rt712",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- ret = snd_soc_add_card_controls(card, rt712_spk_controls,
- ARRAY_SIZE(rt712_spk_controls));
- if (ret) {
- dev_err(card->dev, "rt712 spk controls addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt712_spk_widgets,
- ARRAY_SIZE(rt712_spk_widgets));
- if (ret) {
- dev_err(card->dev, "rt712 spk widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt712_spk_map, ARRAY_SIZE(rt712_spk_map));
- if (ret)
- dev_err(rtd->dev, "failed to add SPK map: %d\n", ret);
-
- return ret;
-}
-
-int sof_sdw_rt712_spk_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- dai_links->init = rt712_spk_init;
-
- return 0;
-}
-
-static int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:rt712-sdca-dmic",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-
-int sof_sdw_rt712_sdca_dmic_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- dai_links->init = rt712_sdca_dmic_rtd_init;
-
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c
deleted file mode 100644
index 7c068dc6b9cf..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt715.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- * sof_sdw_rt715 - Helpers to handle RT715 from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "sof_sdw_common.h"
-
-static int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:rt715",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-
-int sof_sdw_rt715_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- dai_links->init = rt715_rtd_init;
-
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c
deleted file mode 100644
index ca0cf3db2e4d..000000000000
--- a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (c) 2020 Intel Corporation
-
-/*
- * sof_sdw_rt715_sdca - Helpers to handle RT715-SDCA from generic machine driver
- */
-
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include "sof_sdw_common.h"
-
-static int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s mic:rt715-sdca",
- card->components);
- if (!card->components)
- return -ENOMEM;
-
- return 0;
-}
-
-int sof_sdw_rt715_sdca_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- dai_links->init = rt715_sdca_rtd_init;
-
- return 0;
-}
diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c
index 0aef718e82b2..729c0cd7c19c 100644
--- a/sound/soc/intel/boards/sof_ssp_amp.c
+++ b/sound/soc/intel/boards/sof_ssp_amp.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
/*
* sof_ssp_amp.c - ASoc Machine driver for Intel platforms
@@ -17,67 +17,15 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/sof.h>
-#include "../../codecs/hdac_hdmi.h"
-#include "hda_dsp_common.h"
+#include "sof_board_helpers.h"
#include "sof_realtek_common.h"
#include "sof_cirrus_common.h"
-#define NAME_SIZE 32
-
-/* SSP port ID for speaker amplifier */
-#define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0))
-#define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0))
-
-/* HDMI capture*/
-#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4)
-#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5
-#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5))
-#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \
- (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
-
-#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7
-#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7))
-#define SOF_HDMI_CAPTURE_1_SSP(quirk) \
- (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
-
-#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10
-#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10))
-#define SOF_HDMI_CAPTURE_2_SSP(quirk) \
- (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
-
-/* HDMI playback */
-#define SOF_HDMI_PLAYBACK_PRESENT BIT(13)
-#define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14
-#define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14))
-#define SOF_NO_OF_HDMI_PLAYBACK(quirk) \
- (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
-
-/* BT audio offload */
-#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17)
-#define SOF_BT_OFFLOAD_SSP_SHIFT 18
-#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18))
-#define SOF_BT_OFFLOAD_SSP(quirk) \
- (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
-
-/* Speaker amplifiers */
-#define SOF_RT1308_SPEAKER_AMP_PRESENT BIT(21)
-#define SOF_CS35L41_SPEAKER_AMP_PRESENT BIT(22)
+/* Driver-specific board quirks: from bit 0 to 7 */
+#define SOF_HDMI_PLAYBACK_PRESENT BIT(0)
/* Default: SSP2 */
-static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
-
-struct sof_hdmi_pcm {
- struct list_head head;
- struct snd_soc_jack sof_hdmi;
- struct snd_soc_dai *codec_dai;
- int device;
-};
-
-struct sof_card_private {
- struct list_head hdmi_pcm_list;
- bool common_hdmi_codec_drv;
- bool idisp_codec;
-};
+static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2);
static const struct dmi_system_id chromebook_platforms[] = {
{
@@ -89,343 +37,130 @@ static const struct dmi_system_id chromebook_platforms[] = {
{},
};
-static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
-static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = {
- /* digital mics */
- {"DMic", NULL, "SoC DMIC"},
-};
-
static int sof_card_late_probe(struct snd_soc_card *card)
{
- struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = NULL;
- char jack_name[NAME_SIZE];
- struct sof_hdmi_pcm *pcm;
- int err;
-
- if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
- return 0;
-
- /* HDMI is not supported by SOF on Baytrail/CherryTrail */
- if (!ctx->idisp_codec)
- return 0;
-
- if (list_empty(&ctx->hdmi_pcm_list))
- return -EINVAL;
-
- if (ctx->common_hdmi_codec_drv) {
- pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
- head);
- component = pcm->codec_dai->component;
- return hda_dsp_hdmi_build_controls(card, component);
- }
-
- list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
- component = pcm->codec_dai->component;
- snprintf(jack_name, sizeof(jack_name),
- "HDMI/DP, pcm=%d Jack", pcm->device);
- err = snd_soc_card_jack_new(card, jack_name,
- SND_JACK_AVOUT, &pcm->sof_hdmi);
-
- if (err)
- return err;
-
- err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
- &pcm->sof_hdmi);
- if (err < 0)
- return err;
- }
-
- return hdac_hdmi_jack_port_init(component, &card->dapm);
+ return sof_intel_board_card_late_probe(card);
}
static struct snd_soc_card sof_ssp_amp_card = {
.name = "ssp_amp",
.owner = THIS_MODULE,
- .dapm_widgets = sof_ssp_amp_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
- .dapm_routes = sof_ssp_amp_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
.fully_routed = true,
.late_probe = sof_card_late_probe,
};
-static struct snd_soc_dai_link_component platform_component[] = {
- {
- /* name might be overridden during probe */
- .name = "0000:00:1f.3"
- }
-};
-
-static struct snd_soc_dai_link_component dmic_component[] = {
- {
- .name = "dmic-codec",
- .dai_name = "dmic-hifi",
- }
-};
-
-static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+/* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */
+#define HDMI_IN_BE_ID 0
+#define SPK_BE_ID 2
+#define DMIC01_BE_ID 3
+#define INTEL_HDMI_BE_ID 5
+/* extra BE links to support no-hdmi-in boards */
+#define DMIC16K_BE_ID 4
+#define BT_OFFLOAD_BE_ID 8
+
+#define SSP_AMP_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \
+ SOF_LINK_AMP, \
+ SOF_LINK_DMIC01, \
+ SOF_LINK_DMIC16K, \
+ SOF_LINK_IDISP_HDMI, \
+ SOF_LINK_BT_OFFLOAD, \
+ SOF_LINK_NONE)
+
+#define SSP_AMP_LINK_IDS SOF_LINK_ORDER(HDMI_IN_BE_ID, \
+ SPK_BE_ID, \
+ DMIC01_BE_ID, \
+ DMIC16K_BE_ID, \
+ INTEL_HDMI_BE_ID, \
+ BT_OFFLOAD_BE_ID, \
+ 0)
+
+static int
+sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
+ struct sof_card_private *ctx)
{
- struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
- struct sof_hdmi_pcm *pcm;
-
- pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
- if (!pcm)
- return -ENOMEM;
-
- /* dai_link id is 1:1 mapped to the PCM device */
- pcm->device = rtd->dai_link->id;
- pcm->codec_dai = dai;
-
- list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
-
- return 0;
-}
-
-#define IDISP_CODEC_MASK 0x4
-
-static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
- int ssp_codec,
- int dmic_be_num,
- int hdmi_num,
- bool idisp_codec)
-{
- struct snd_soc_dai_link_component *idisp_components;
- struct snd_soc_dai_link_component *cpus;
- struct snd_soc_dai_link *links;
- int i, id = 0;
-
- links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
- sizeof(struct snd_soc_dai_link), GFP_KERNEL);
- cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
- sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
- if (!links || !cpus)
- return NULL;
-
- /* HDMI-In SSP */
- if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
- int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
- SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
-
- for (i = 1; i <= num_of_hdmi_ssp; i++) {
- int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
- SOF_HDMI_CAPTURE_1_SSP_SHIFT :
- (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
- SOF_HDMI_CAPTURE_2_SSP_SHIFT);
-
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin", port);
- if (!links[id].cpus->dai_name)
- return NULL;
- links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
- if (!links[id].name)
- return NULL;
- links[id].id = id;
- links[id].codecs = &asoc_dummy_dlc;
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].num_cpus = 1;
- id++;
- }
- }
-
- /* codec SSP */
- links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
- if (!links[id].name)
- return NULL;
+ int ret;
- links[id].id = id;
- if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
- sof_rt1308_dai_link(&links[id]);
- } else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
- cs35l41_set_dai_link(&links[id]);
- }
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_playback = 1;
- /* feedback from amplifier or firmware-generated echo reference */
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
- if (!links[id].cpus->dai_name)
- return NULL;
-
- id++;
-
- /* dmic */
- if (dmic_be_num > 0) {
- /* at least we have dmic01 */
- links[id].name = "dmic01";
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = "DMIC01 Pin";
- if (dmic_be_num > 1) {
- /* set up 2 BE links at most */
- links[id + 1].name = "dmic16k";
- links[id + 1].cpus = &cpus[id + 1];
- links[id + 1].cpus->dai_name = "DMIC16k Pin";
- dmic_be_num = 2;
- }
- }
+ ret = sof_intel_board_set_dai_link(dev, card, ctx);
+ if (ret)
+ return ret;
- for (i = 0; i < dmic_be_num; i++) {
- links[id].id = id;
- links[id].num_cpus = 1;
- links[id].codecs = dmic_component;
- links[id].num_codecs = ARRAY_SIZE(dmic_component);
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].ignore_suspend = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- id++;
- }
+ if (ctx->amp_type == CODEC_NONE)
+ return 0;
- /* HDMI playback */
- if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
- /* HDMI */
- if (hdmi_num > 0) {
- idisp_components = devm_kcalloc(dev,
- hdmi_num,
- sizeof(struct snd_soc_dai_link_component),
- GFP_KERNEL);
- if (!idisp_components)
- goto devm_err;
- }
- for (i = 1; i <= hdmi_num; i++) {
- links[id].name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d", i);
- if (!links[id].name)
- goto devm_err;
-
- links[id].id = id;
- links[id].cpus = &cpus[id];
- links[id].num_cpus = 1;
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "iDisp%d Pin", i);
- if (!links[id].cpus->dai_name)
- goto devm_err;
-
- if (idisp_codec) {
- idisp_components[i - 1].name = "ehdaudio0D2";
- idisp_components[i - 1].dai_name = devm_kasprintf(dev,
- GFP_KERNEL,
- "intel-hdmi-hifi%d",
- i);
- if (!idisp_components[i - 1].dai_name)
- goto devm_err;
- } else {
- idisp_components[i - 1] = asoc_dummy_dlc;
- }
-
- links[id].codecs = &idisp_components[i - 1];
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].init = sof_hdmi_init;
- links[id].dpcm_playback = 1;
- links[id].no_pcm = 1;
- id++;
- }
+ if (!ctx->amp_link) {
+ dev_err(dev, "amp link not available");
+ return -EINVAL;
}
- /* BT audio offload */
- if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
- int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
- SOF_BT_OFFLOAD_SSP_SHIFT;
-
- links[id].id = id;
- links[id].cpus = &cpus[id];
- links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
- "SSP%d Pin", port);
- if (!links[id].cpus->dai_name)
- goto devm_err;
- links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
- if (!links[id].name)
- goto devm_err;
- links[id].codecs = &asoc_dummy_dlc;
- links[id].num_codecs = 1;
- links[id].platforms = platform_component;
- links[id].num_platforms = ARRAY_SIZE(platform_component);
- links[id].dpcm_playback = 1;
- links[id].dpcm_capture = 1;
- links[id].no_pcm = 1;
- links[id].num_cpus = 1;
- id++;
+ /* codec-specific fields for speaker amplifier */
+ switch (ctx->amp_type) {
+ case CODEC_CS35L41:
+ cs35l41_set_dai_link(ctx->amp_link);
+ break;
+ case CODEC_RT1308:
+ sof_rt1308_dai_link(ctx->amp_link);
+ break;
+ default:
+ dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
- return links;
-devm_err:
- return NULL;
+ return 0;
}
static int sof_ssp_amp_probe(struct platform_device *pdev)
{
- struct snd_soc_dai_link *dai_links;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct sof_card_private *ctx;
- int dmic_be_num = 0, hdmi_num = 0;
- int ret, ssp_codec;
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ int ret;
if (pdev->id_entry && pdev->id_entry->driver_data)
sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
- mach = pdev->dev.platform_data;
+ dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk);
- if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
- dmic_be_num = 2;
-
- ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
-
- /* set number of dai links */
- sof_ssp_amp_card.num_links = 1 + dmic_be_num;
+ /* initialize ctx with board quirk */
+ ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk);
+ if (!ctx)
+ return -ENOMEM;
- if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
- sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
- SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+ if (!dmi_check_system(chromebook_platforms) &&
+ (mach->mach_params.dmic_num == 0))
+ ctx->dmic_be_num = 0;
if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
- hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
- SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
- /* default number of HDMI DAI's */
- if (!hdmi_num)
- hdmi_num = 3;
-
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
- ctx->idisp_codec = true;
-
- sof_ssp_amp_card.num_links += hdmi_num;
+ ctx->hdmi.idisp_codec = true;
+ } else {
+ ctx->hdmi_num = 0;
}
- if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- sof_ssp_amp_card.num_links++;
+ ctx->link_order_overwrite = SSP_AMP_LINK_ORDER;
- dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
- if (!dai_links)
- return -ENOMEM;
+ if (ctx->ssp_mask_hdmi_in) {
+ /* the topology supports HDMI-IN uses fixed BE ID for DAI links */
+ ctx->link_id_overwrite = SSP_AMP_LINK_IDS;
+ }
- sof_ssp_amp_card.dai_link = dai_links;
+ /* update dai_link */
+ ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx);
+ if (ret)
+ return ret;
/* update codec_conf */
- if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
+ switch (ctx->amp_type) {
+ case CODEC_CS35L41:
cs35l41_set_codec_conf(&sof_ssp_amp_card);
+ break;
+ case CODEC_RT1308:
+ case CODEC_NONE:
+ /* no codec conf required */
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
+ return -EINVAL;
}
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
-
sof_ssp_amp_card.dev = &pdev->dev;
/* set platform name for each dailink */
@@ -434,8 +169,6 @@ static int sof_ssp_amp_probe(struct platform_device *pdev)
if (ret)
return ret;
- ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
-
snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
@@ -447,29 +180,46 @@ static const struct platform_device_id board_ids[] = {
},
{
.name = "tgl_rt1308_hdmi_ssp",
- .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
- SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
- SOF_HDMI_CAPTURE_1_SSP(1) |
- SOF_HDMI_CAPTURE_2_SSP(5) |
- SOF_SSP_HDMI_CAPTURE_PRESENT |
- SOF_RT1308_SPEAKER_AMP_PRESENT),
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) |
+ SOF_SSP_MASK_HDMI_CAPTURE(0x22)),
+ /* SSP 1 and SSP 5 are used for HDMI IN */
},
{
.name = "adl_cs35l41",
- .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
- SOF_NO_OF_HDMI_PLAYBACK(4) |
+ .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) |
+ SOF_NUM_IDISP_HDMI(4) |
SOF_HDMI_PLAYBACK_PRESENT |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT |
- SOF_CS35L41_SPEAKER_AMP_PRESENT),
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
},
{
.name = "adl_lt6911_hdmi_ssp",
- .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
- SOF_HDMI_CAPTURE_1_SSP(0) |
- SOF_HDMI_CAPTURE_2_SSP(2) |
- SOF_SSP_HDMI_CAPTURE_PRESENT |
- SOF_NO_OF_HDMI_PLAYBACK(3) |
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_PLAYBACK_PRESENT),
+ },
+ {
+ .name = "rpl_lt6911_hdmi_ssp",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_PLAYBACK_PRESENT),
+ },
+ {
+ .name = "mtl_lt6911_hdmi_ssp",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_PLAYBACK_PRESENT),
+ },
+ {
+ .name = "arl_lt6911_hdmi_ssp",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_PLAYBACK_PRESENT),
+ },
+ {
+ .name = "ptl_lt6911_hdmi_ssp",
+ .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
SOF_HDMI_PLAYBACK_PRESENT),
},
{ }
@@ -490,6 +240,6 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>");
MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON");
+MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_CIRRUS_COMMON");
diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c
index 17224d26d9d6..51922347409f 100644
--- a/sound/soc/intel/boards/sof_wm8804.c
+++ b/sound/soc/intel/boards/sof_wm8804.c
@@ -49,9 +49,9 @@ static const struct dmi_system_id sof_wm8804_quirk_table[] = {
static int sof_wm8804_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *codec = codec_dai->component;
const int sysclk = 27000000; /* This is fixed on this board */
int samplerate;
@@ -148,7 +148,7 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream,
}
/* machine stream operations */
-static struct snd_soc_ops sof_wm8804_ops = {
+static const struct snd_soc_ops sof_wm8804_ops = {
.hw_params = sof_wm8804_hw_params,
};
@@ -167,8 +167,6 @@ static struct snd_soc_dai_link dailink[] = {
.name = "SSP5-Codec",
.id = 0,
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ops = &sof_wm8804_ops,
SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform),
},
@@ -270,7 +268,11 @@ static int sof_wm8804_probe(struct platform_device *pdev)
snprintf(codec_name, sizeof(codec_name),
"%s%s", "i2c-", acpi_dev_name(adev));
dailink[dai_index].codecs->name = codec_name;
+ } else {
+ dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
+ return -ENOENT;
}
+
acpi_dev_put(adev);
snd_soc_card_set_drvdata(card, ctx);
@@ -290,7 +292,7 @@ static struct platform_driver sof_wm8804_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = sof_wm8804_probe,
- .remove_new = sof_wm8804_remove,
+ .remove = sof_wm8804_remove,
};
module_platform_driver(sof_wm8804_driver);
diff --git a/sound/soc/intel/catpt/Makefile b/sound/soc/intel/catpt/Makefile
index c393a45795da..f5f6a7e956ce 100644
--- a/sound/soc/intel/catpt/Makefile
+++ b/sound/soc/intel/catpt/Makefile
@@ -1,4 +1,4 @@
-snd-soc-catpt-objs := device.o dsp.o loader.o ipc.o messages.o pcm.o sysfs.o
+snd-soc-catpt-y := device.o dsp.o loader.o ipc.o messages.o pcm.o sysfs.o
# tell define_trace.h where to find the trace header
CFLAGS_device.o := -I$(src)
diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
index a64a0a77dcb7..c01d27e9fd88 100644
--- a/sound/soc/intel/catpt/core.h
+++ b/sound/soc/intel/catpt/core.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ * Copyright(c) 2020 Intel Corporation
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index cac3dffbd0d9..d13062c8e907 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -28,7 +28,7 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
-static int __maybe_unused catpt_suspend(struct device *dev)
+static int catpt_do_suspend(struct device *dev)
{
struct catpt_dev *cdev = dev_get_drvdata(dev);
struct dma_chan *chan;
@@ -72,7 +72,14 @@ release_dma_chan:
return catpt_dsp_power_down(cdev);
}
-static int __maybe_unused catpt_resume(struct device *dev)
+/* Do not block the system from suspending, recover on resume() if needed. */
+static int catpt_suspend(struct device *dev)
+{
+ catpt_do_suspend(dev);
+ return 0;
+}
+
+static int catpt_resume(struct device *dev)
{
struct catpt_dev *cdev = dev_get_drvdata(dev);
int ret, i;
@@ -106,7 +113,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");
@@ -114,17 +121,17 @@ static int __maybe_unused catpt_runtime_suspend(struct device *dev)
}
module_put(dev->driver->owner);
- return catpt_suspend(dev);
+ return catpt_do_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 */
@@ -184,22 +191,25 @@ static int catpt_probe_components(struct catpt_dev *cdev)
goto err_boot_fw;
}
- ret = catpt_register_board(cdev);
- if (ret) {
- dev_err(cdev->dev, "register board failed: %d\n", ret);
- goto err_reg_board;
- }
-
/* reflect actual ADSP state in pm_runtime */
pm_runtime_set_active(cdev->dev);
pm_runtime_set_autosuspend_delay(cdev->dev, 2000);
pm_runtime_use_autosuspend(cdev->dev);
pm_runtime_mark_last_busy(cdev->dev);
+ /* Enable PM before spawning child device. See catpt_dai_pcm_new(). */
pm_runtime_enable(cdev->dev);
+
+ ret = catpt_register_board(cdev);
+ if (ret) {
+ dev_err(cdev->dev, "register board failed: %d\n", ret);
+ goto err_reg_board;
+ }
+
return 0;
err_reg_board:
+ pm_runtime_disable(cdev->dev);
snd_soc_unregister_component(cdev->dev);
err_boot_fw:
catpt_dmac_remove(cdev);
@@ -374,11 +384,11 @@ MODULE_DEVICE_TABLE(acpi, catpt_ids);
static struct platform_driver catpt_acpi_driver = {
.probe = catpt_acpi_probe,
- .remove_new = catpt_acpi_remove,
+ .remove = catpt_acpi_remove,
.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/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c
index 346bec000306..008a20a2acbd 100644
--- a/sound/soc/intel/catpt/dsp.c
+++ b/sound/soc/intel/catpt/dsp.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -156,7 +156,7 @@ static void catpt_dsp_set_srampge(struct catpt_dev *cdev, struct resource *sram,
{
unsigned long old;
u32 off = sram->start;
- u32 b = __ffs(mask);
+ unsigned long b = __ffs(mask);
old = catpt_readl_pci(cdev, VDRTCTL0) & mask;
dev_dbg(cdev->dev, "SRAMPGE [0x%08lx] 0x%08lx -> 0x%08lx",
@@ -387,7 +387,7 @@ int catpt_dsp_power_down(struct catpt_dev *cdev)
mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
catpt_updatel_pci(cdev, VDRTCTL0, mask, cdev->spec->d3pgd_bit);
- catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot);
+ catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, (__force u32)PCI_D3hot);
/* give hw time to drop off */
udelay(50);
@@ -411,7 +411,7 @@ int catpt_dsp_power_up(struct catpt_dev *cdev)
val = mask & (~CATPT_VDRTCTL2_DTCGE);
catpt_updatel_pci(cdev, VDRTCTL2, mask, val);
- catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0);
+ catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, (__force u32)PCI_D0);
/* SRAM power gating none */
mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
diff --git a/sound/soc/intel/catpt/ipc.c b/sound/soc/intel/catpt/ipc.c
index 5b718a846fda..d26863249097 100644
--- a/sound/soc/intel/catpt/ipc.c
+++ b/sound/soc/intel/catpt/ipc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c
index ff7b8f0d34ac..f5705cd2c1e1 100644
--- a/sound/soc/intel/catpt/loader.c
+++ b/sound/soc/intel/catpt/loader.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -208,6 +208,7 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) {
struct catpt_save_meminfo *info;
+ struct resource r = {};
u32 off;
int ret;
@@ -216,7 +217,8 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
continue;
off = catpt_to_host_offset(info->offset);
- if (off < cdev->dram.start || off > cdev->dram.end)
+ resource_set_range(&r, off, info->size);
+ if (!resource_contains(&cdev->dram, &r))
continue;
dev_dbg(cdev->dev, "restoring memdump: off 0x%08x size %d\n",
@@ -239,34 +241,32 @@ static int catpt_restore_fwimage(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
struct catpt_fw_block_hdr *blk)
{
- struct resource r1, r2, common;
+ struct resource r1 = {};
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
blk, sizeof(*blk), false);
- r1.start = cdev->dram.start + blk->ram_offset;
- r1.end = r1.start + blk->size - 1;
+ resource_set_range(&r1, cdev->dram.start + blk->ram_offset, blk->size);
/* advance to data area */
paddr += sizeof(*blk);
for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) {
struct catpt_save_meminfo *info;
+ struct resource common = {};
+ struct resource r2 = {};
u32 off;
int ret;
info = &cdev->dx_ctx.meminfo[i];
-
if (info->source != CATPT_DX_TYPE_FW_IMAGE)
continue;
off = catpt_to_host_offset(info->offset);
- if (off < cdev->dram.start || off > cdev->dram.end)
+ resource_set_range(&r2, off, info->size);
+ if (!resource_contains(&cdev->dram, &r2))
continue;
- r2.start = off;
- r2.end = r2.start + info->size - 1;
-
if (!resource_intersection(&r2, &r1, &common))
continue;
/* calculate start offset of common data area */
diff --git a/sound/soc/intel/catpt/messages.c b/sound/soc/intel/catpt/messages.c
index a793d114afa4..30eec2de4dc1 100644
--- a/sound/soc/intel/catpt/messages.c
+++ b/sound/soc/intel/catpt/messages.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
diff --git a/sound/soc/intel/catpt/messages.h b/sound/soc/intel/catpt/messages.h
index c17e948d9f52..a634943eb669 100644
--- a/sound/soc/intel/catpt/messages.h
+++ b/sound/soc/intel/catpt/messages.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ * Copyright(c) 2020 Intel Corporation
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index 30ca5416c9a3..abd1cb07c60c 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -74,8 +74,8 @@ static struct catpt_stream_template *catpt_topology[] = {
static struct catpt_stream_template *
catpt_get_stream_template(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
+ struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0);
enum catpt_stream_type type;
type = cpu_dai->driver->id;
@@ -417,8 +417,10 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
return CATPT_IPC_ERROR(ret);
ret = catpt_dai_apply_usettings(dai, stream);
- if (ret)
+ if (ret) {
+ catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
return ret;
+ }
stream->allocated = true;
return 0;
@@ -568,8 +570,9 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = {
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
.period_bytes_min = PAGE_SIZE,
.period_bytes_max = CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN,
.periods_min = CATPT_PCM_PERIODS_MIN,
@@ -593,7 +596,7 @@ static int catpt_component_pcm_construct(struct snd_soc_component *component,
static int catpt_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
if (!rtm->dai_link->no_pcm)
snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
@@ -604,8 +607,8 @@ static snd_pcm_uframes_t
catpt_component_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
+ struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0);
struct catpt_stream_runtime *stream;
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
u32 pos;
@@ -631,7 +634,7 @@ static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
struct snd_soc_dai *dai)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtm, 0);
struct catpt_ssp_device_format devfmt;
struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
int ret;
@@ -668,12 +671,11 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
return 0;
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
ret = catpt_ipc_set_device_format(cdev, &devfmt);
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
if (ret)
@@ -684,6 +686,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
return 0;
}
+static const struct snd_soc_dai_ops catpt_dai_ops = {
+ .pcm_new = catpt_dai_pcm_new,
+};
+
static struct snd_soc_dai_driver dai_drivers[] = {
/* FE DAIs */
{
@@ -695,14 +701,18 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
.capture = {
.stream_name = "Analog Capture",
.channels_min = 2,
.channels_max = 4,
.rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
},
{
@@ -714,7 +724,9 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
},
{
@@ -726,7 +738,9 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
},
{
@@ -738,7 +752,9 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 |
+ SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,
},
},
{
@@ -764,7 +780,6 @@ static struct snd_soc_dai_driver dai_drivers[] = {
{
.name = "ssp0-port",
.id = CATPT_SSP_IFACE_0,
- .pcm_new = catpt_dai_pcm_new,
.playback = {
.channels_min = 1,
.channels_max = 8,
@@ -773,11 +788,11 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 1,
.channels_max = 8,
},
+ .ops = &catpt_dai_ops,
},
{
.name = "ssp1-port",
.id = CATPT_SSP_IFACE_1,
- .pcm_new = catpt_dai_pcm_new,
.playback = {
.channels_min = 1,
.channels_max = 8,
@@ -786,6 +801,7 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 1,
.channels_max = 8,
},
+ .ops = &catpt_dai_ops,
},
};
@@ -851,15 +867,14 @@ static int catpt_volume_info(struct snd_kcontrol *kcontrol,
static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
u32 dspvol;
int ret;
int i;
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
@@ -867,7 +882,6 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
}
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
return 0;
@@ -876,19 +890,17 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
int ret;
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
ucontrol->value.integer.value);
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
return ret;
@@ -898,8 +910,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
enum catpt_pin_id pin_id)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct catpt_stream_runtime *stream;
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
long *ctlvol = (long *)kcontrol->private_value;
@@ -915,7 +926,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
}
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
@@ -923,7 +934,6 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
}
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
return 0;
@@ -933,8 +943,7 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
enum catpt_pin_id pin_id)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct catpt_stream_runtime *stream;
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
long *ctlvol = (long *)kcontrol->private_value;
@@ -948,13 +957,12 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
}
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
ucontrol->value.integer.value);
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
if (ret)
@@ -1011,8 +1019,7 @@ static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol,
static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct catpt_stream_runtime *stream;
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
bool mute;
@@ -1026,12 +1033,11 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
}
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
if (ret)
diff --git a/sound/soc/intel/catpt/registers.h b/sound/soc/intel/catpt/registers.h
index 47280d82842e..6c1ad28c6d69 100644
--- a/sound/soc/intel/catpt/registers.h
+++ b/sound/soc/intel/catpt/registers.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ * Copyright(c) 2020 Intel Corporation
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/
diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c
index 9b6d2d93a2e7..e961e172f9b7 100644
--- a/sound/soc/intel/catpt/sysfs.c
+++ b/sound/soc/intel/catpt/sysfs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//
@@ -16,12 +16,11 @@ static ssize_t fw_version_show(struct device *dev,
int ret;
ret = pm_runtime_resume_and_get(cdev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret)
return ret;
ret = catpt_ipc_get_fw_version(cdev, &version);
- pm_runtime_mark_last_busy(cdev->dev);
pm_runtime_put_autosuspend(cdev->dev);
if (ret)
diff --git a/sound/soc/intel/catpt/trace.h b/sound/soc/intel/catpt/trace.h
index bb3d627dbeaf..010f57b6a7a8 100644
--- a/sound/soc/intel/catpt/trace.h
+++ b/sound/soc/intel/catpt/trace.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ * Copyright(c) 2020 Intel Corporation
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 07aa37dd90e9..dbfd9e2ac015 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-sst-dsp-objs := sst-dsp.o
-snd-soc-sst-ipc-objs := sst-ipc.o
-snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \
+snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \
soc-acpi-intel-hsw-bdw-match.o \
soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
@@ -10,9 +8,16 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \
soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \
soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \
+ soc-acpi-intel-arl-match.o \
soc-acpi-intel-lnl-match.o \
+ soc-acpi-intel-ptl-match.o \
+ soc-acpi-intel-nvl-match.o \
soc-acpi-intel-hda-match.o \
- soc-acpi-intel-sdw-mockup-match.o
+ soc-acpi-intel-sdw-mockup-match.o sof-function-topology-lib.o
+
+snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o
+
+snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o
-obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o
+obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o
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 bcd66e0094b4..a68efbe98948 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -7,6 +7,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
@@ -34,6 +35,86 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
.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_adr_device cs35l56_2_r_adr[] = {
+ {
+ .adr = 0x00023201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00023301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = {
+ {
+ .adr = 0x00033001fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00033101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+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_0_adr[] = {
+ {
+ .adr = 0x00003001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
{
.adr = 0x000020025D071100ull,
@@ -133,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,
@@ -415,6 +505,25 @@ static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = {
}
};
+static const struct snd_soc_acpi_link_adr adl_cs42l43_l0_cs35l56_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_r_adr),
+ .adr_d = cs35l56_2_r_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_l_adr),
+ .adr_d = cs35l56_3_l_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr adl_rvp[] = {
{
.mask = BIT(0),
@@ -447,9 +556,18 @@ static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = {
{}
};
-static const struct snd_soc_acpi_codecs adl_max98373_amp = {
- .num_codecs = 1,
- .codecs = {"MX98373"}
+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 = {
@@ -457,19 +575,9 @@ static const struct snd_soc_acpi_codecs adl_max98357a_amp = {
.codecs = {"MX98357A"}
};
-static const struct snd_soc_acpi_codecs adl_max98360a_amp = {
- .num_codecs = 1,
- .codecs = {"MX98360A"}
-};
-
static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = {
.num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
-};
-
-static const struct snd_soc_acpi_codecs adl_rt1015p_amp = {
- .num_codecs = 1,
- .codecs = {"RTL1015"}
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
@@ -477,44 +585,20 @@ static const struct snd_soc_acpi_codecs adl_rt1019p_amp = {
.codecs = {"RTL1019"}
};
-static const struct snd_soc_acpi_codecs adl_max98390_amp = {
- .num_codecs = 1,
- .codecs = {"MX98390"}
-};
-
static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
.num_codecs = 1,
.codecs = {"INTC10B0"}
};
-static const struct snd_soc_acpi_codecs adl_nau8318_amp = {
- .num_codecs = 1,
- .codecs = {"NVTN2012"}
-};
-
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
{
.comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_mx98373_rt5682",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98373_amp,
- .sof_tplg_filename = "sof-adl-max98373-rt5682.tplg",
- },
- {
- .comp_ids = &adl_rt5682_rt5682s_hp,
.drv_name = "adl_mx98357_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_max98357a_amp,
.sof_tplg_filename = "sof-adl-max98357a-rt5682.tplg",
},
{
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_mx98360_rt5682",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98360a_amp,
- .sof_tplg_filename = "sof-adl-max98360a-rt5682.tplg",
- },
- {
.id = "10508825",
.drv_name = "adl_rt1019p_8825",
.machine_quirk = snd_soc_acpi_codec_list,
@@ -522,63 +606,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg",
},
{
- .id = "10508825",
- .drv_name = "adl_max98373_8825",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98373_amp,
- .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "adl_mx98360a_8825",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98360a_amp,
- .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
- },
- {
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt1019_rt5682",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_rt1019p_amp,
- .sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "adl_rt1015p_8825",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_rt1015p_amp,
- .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "adl_nau8318_8825",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_nau8318_amp,
- .sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg",
- },
- {
- .id = "10508825",
- .drv_name = "sof_nau8825",
- .sof_tplg_filename = "sof-adl-nau8825.tplg",
- },
- {
.comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_max98390_rt5682",
+ .drv_name = "adl_rt5682_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98390_amp,
- .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg",
- },
- {
- .comp_ids = &adl_rt5682_rt5682s_hp,
- .drv_name = "adl_rt5682",
- .sof_tplg_filename = "sof-adl-rt5682.tplg",
- },
- {
- .id = "10134242",
- .drv_name = "adl_mx98360a_cs4242",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &adl_max98360a_amp,
- .sof_tplg_filename = "sof-adl-max98360a-cs42l42.tplg",
+ .quirk_data = &adl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg",
},
{
.comp_ids = &essx_83x6,
@@ -595,6 +627,44 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .id = CS42L42_ACPI_HID,
+ .drv_name = "adl_cs42l42_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = DA7219_ACPI_HID,
+ .drv_name = "adl_da7219_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = NAU8825_ACPI_HID,
+ .drv_name = "adl_nau8825_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = RT5650_ACPI_HID,
+ .drv_name = "adl_rt5682_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &adl_rt5682_rt5682s_hp,
+ .drv_name = "adl_rt5682_def",
+ .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
/* place amp-only boards in the end of table */
{
.id = "CSC3541",
@@ -613,6 +683,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
{
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = adl_cs42l43_l0_cs35l56_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-adl-cs42l43-l0-cs35l56-l23.tplg",
+ },
+ {
.link_mask = 0xF, /* 4 active links required */
.links = adl_default,
.drv_name = "sof_sdw",
@@ -649,18 +725,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
.sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l3.tplg",
},
{
- .link_mask = 0x3, /* rt1316 on link1 & rt714 on link0 */
- .links = adl_sdw_rt1316_link1_rt714_link0,
- .drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-adl-rt1316-l1-mono-rt714-l0.tplg",
- },
- {
.link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
.links = adl_sdw_rt1316_link12_rt714_link0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-adl-rt1316-l12-rt714-l0.tplg",
},
{
+ .link_mask = 0x3, /* rt1316 on link1 & rt714 on link0 */
+ .links = adl_sdw_rt1316_link1_rt714_link0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-adl-rt1316-l1-mono-rt714-l0.tplg",
+ },
+ {
.link_mask = 0x5, /* 2 active links required */
.links = adl_sdw_rt1316_link2_rt714_link0,
.drv_name = "sof_sdw",
@@ -696,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
new file mode 100644
index 000000000000..6bf7a6250ddc
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-apci-intel-arl-match.c - tables and support for ARL ACPI enumeration.
+ *
+ * Copyright (c) 2023 Intel Corporation.
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+#include "sof-function-topology-lib.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_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,
+};
+
+/*
+ * RT722 is a multi-function codec, three endpoints are created for
+ * its headset, amp and dmic functions.
+ */
+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 cs35l56_2_lr_adr[] = {
+ {
+ .adr = 0x00023001FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00023101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = {
+ {
+ .adr = 0x00033001FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00033401FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = {
+ {
+ .adr = 0x00023201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00023301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = {
+ {
+ .adr = 0x00033001fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00033101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_2_r1_adr[] = {
+ {
+ .adr = 0x00023101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_l3_adr[] = {
+ {
+ .adr = 0x00033301fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+};
+
+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,
+ .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_0_adr[] = {
+ {
+ .adr = 0x00003001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = {
+ {
+ .adr = 0x00023001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
+ {
+ .adr = 0x000020025D071100ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
+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 rt1316_3_single_adr[] = {
+ {
+ .adr = 0x000330025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = {
+ {
+ .adr = 0x000230025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l2[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs42l43_2_adr),
+ .adr_d = cs42l43_2_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l2_cs35l56_l3[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs42l43_2_adr),
+ .adr_d = cs42l43_2_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_lr_adr),
+ .adr_d = cs35l56_3_lr_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_l2[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs35l56_2_lr_adr),
+ .adr_d = cs35l56_2_lr_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_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_r_adr),
+ .adr_d = cs35l56_2_r_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_l_adr),
+ .adr_d = cs35l56_3_l_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_2_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_r1_adr),
+ .adr_d = cs35l56_2_r1_adr,
+ },
+ {
+ .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,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_0_adr),
+ .adr_d = rt711_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_rt711_l0_rt1316_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1316_3_single_adr),
+ .adr_d = rt1316_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt722_0_single_adr),
+ .adr_d = rt722_0_single_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1320_2_single_adr),
+ .adr_d = rt1320_2_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_codecs arl_essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
+static const struct snd_soc_acpi_codecs arl_rt5682_hp = {
+ .num_codecs = 2,
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
+};
+
+static const struct snd_soc_acpi_codecs arl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = {
+ {
+ .comp_ids = &arl_essx_83x6,
+ .drv_name = "arl_es83x6_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &arl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-arl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &arl_essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-arl-es8336", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
+ {
+ .comp_ids = &arl_rt5682_hp,
+ .drv_name = "arl_rt5682_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &arl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-arl-rt5682-ssp1-hdmi-ssp02.tplg",
+ },
+ /* place amp-only boards in the end of table */
+ {
+ .id = "INTC10B0",
+ .drv_name = "arl_lt6911_hdmi_ssp",
+ .sof_tplg_filename = "sof-arl-hdmi-ssp02.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines);
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
+ {
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = arl_cs42l43_l0_cs35l56_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = arl_cs42l43_l0_cs35l56_2_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0) | BIT(2),
+ .links = arl_cs42l43_l0_cs35l56_l2,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0),
+ .links = arl_cs42l43_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(2) | BIT(3),
+ .links = arl_cs42l43_l2_cs35l56_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(2),
+ .links = arl_cs42l43_l2,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0) | BIT(3),
+ .links = arl_rt711_l0_rt1316_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg",
+ },
+ {
+ .link_mask = 0x1, /* link0 required */
+ .links = arl_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-rt711.tplg",
+ },
+ {
+ .link_mask = 0x1, /* link0 required */
+ .links = arl_sdca_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-rt711-l0.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(2),
+ .links = arl_rt722_l0_rt1320_l2,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
index cdcbf04b8832..e4c3492a0c28 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -75,6 +75,38 @@ static struct snd_soc_acpi_mach *cht_ess8316_quirk(void *arg)
return arg;
}
+/*
+ * The Lenovo Yoga Tab 3 Pro YT3-X90, with Android factory OS has a buggy DSDT
+ * with the coded not being listed at all.
+ */
+static const struct dmi_system_id lenovo_yoga_tab3_x90[] = {
+ {
+ /* Lenovo Yoga Tab 3 Pro YT3-X90, codec missing from DSDT */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
+ },
+ },
+ { }
+};
+
+static struct snd_soc_acpi_mach cht_lenovo_yoga_tab3_x90_mach = {
+ .id = "10WM5102",
+ .drv_name = "bytcr_wm5102",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcr_wm5102",
+ .sof_tplg_filename = "sof-cht-wm5102.tplg",
+};
+
+static struct snd_soc_acpi_mach *lenovo_yt3_x90_quirk(void *arg)
+{
+ if (dmi_check_system(lenovo_yoga_tab3_x90))
+ return &cht_lenovo_yoga_tab3_x90_mach;
+
+ /* Skip wildcard match snd_soc_acpi_intel_cherrytrail_machines[] entry */
+ return NULL;
+}
+
static const struct snd_soc_acpi_codecs rt5640_comp_ids = {
.num_codecs = 2,
.codecs = { "10EC5640", "10EC3276" },
@@ -175,6 +207,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "sof_pcm512x",
.sof_tplg_filename = "sof-cht-src-50khz-pcm512x.tplg",
},
+ /*
+ * Special case for the Lenovo Yoga Tab 3 Pro YT3-X90 where the DSDT
+ * misses the codec. Match on the SST id instead, lenovo_yt3_x90_quirk()
+ * will return a YT3 specific mach or NULL when called on other hw,
+ * skipping this entry.
+ */
+ {
+ .id = "808622A8",
+ .machine_quirk = lenovo_yt3_x90_quirk,
+ },
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
/*
diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
index 5eab17820532..f79d7558174a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c
@@ -42,40 +42,40 @@ static const struct snd_soc_acpi_codecs max98390_spk_codecs = {
struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
{
.id = "10EC5682",
- .drv_name = "cml_rt1011_rt5682",
+ .drv_name = "cml_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rt1011_spk_codecs,
.sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
},
{
.id = "10EC5682",
- .drv_name = "cml_rt1015_rt5682",
+ .drv_name = "cml_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rt1015_spk_codecs,
.sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg",
},
{
.id = "10EC5682",
- .drv_name = "sof_rt5682",
+ .drv_name = "cml_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &max98357a_spk_codecs,
.sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg",
},
{
.id = "10EC5682",
- .drv_name = "sof_rt5682",
+ .drv_name = "cml_rt5682_def",
.sof_tplg_filename = "sof-cml-rt5682.tplg",
},
{
.id = "DLGS7219",
- .drv_name = "cml_da7219_mx98357a",
+ .drv_name = "cml_da7219_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &max98357a_spk_codecs,
.sof_tplg_filename = "sof-cml-da7219-max98357a.tplg",
},
{
.id = "DLGS7219",
- .drv_name = "cml_da7219_mx98357a",
+ .drv_name = "cml_da7219_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &max98390_spk_codecs,
.sof_tplg_filename = "sof-cml-da7219-max98390.tplg",
diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
index 3df89e4511da..8bbb1052faf2 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
@@ -8,7 +8,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-#include "../skylake/skl.h"
#include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs essx_83x6 = {
@@ -16,16 +15,11 @@ static const struct snd_soc_acpi_codecs essx_83x6 = {
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static struct skl_machine_pdata cnl_pdata = {
- .use_tplg_pcm = true,
-};
-
struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
{
.id = "INT34C2",
.drv_name = "cnl_rt274",
.fw_filename = "intel/dsp_fw_cnl.bin",
- .pdata = &cnl_pdata,
.sof_tplg_filename = "sof-cnl-rt274.tplg",
},
{
diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
index 84639c41a268..78255d56b08c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c
@@ -8,7 +8,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-#include "../skylake/skl.h"
struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = {
{
diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
index 387e73100884..c82c8c93d200 100644
--- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
@@ -19,6 +19,11 @@ static const struct snd_soc_acpi_codecs glk_codecs = {
.codecs = {"MX98357A"}
};
+static const struct snd_soc_acpi_codecs glk_rt5682_rt5682s_hp = {
+ .num_codecs = 2,
+ .codecs = {"10EC5682", "RTL5682"},
+};
+
struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
{
.id = "INT343A",
@@ -28,28 +33,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
},
{
.id = "DLGS7219",
- .drv_name = "glk_da7219_mx98357a",
+ .drv_name = "glk_da7219_def",
.fw_filename = "intel/dsp_fw_glk.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &glk_codecs,
.sof_tplg_filename = "sof-glk-da7219.tplg",
},
{
- .id = "10EC5682",
- .drv_name = "glk_rt5682_mx98357a",
+ .comp_ids = &glk_rt5682_rt5682s_hp,
+ .drv_name = "glk_rt5682_def",
.fw_filename = "intel/dsp_fw_glk.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &glk_codecs,
.sof_tplg_filename = "sof-glk-rt5682.tplg",
},
{
- .id = "RTL5682",
- .drv_name = "glk_rt5682_max98357a",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &glk_codecs,
- .sof_tplg_filename = "sof-glk-rt5682.tplg",
- },
- {
.id = "10134242",
.drv_name = "glk_cs4242_mx98357a",
.fw_filename = "intel/dsp_fw_glk.bin",
diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c
index 2017fd0d676f..e93336e27beb 100644
--- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c
@@ -8,27 +8,13 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-#include "../skylake/skl.h"
-
-static struct skl_machine_pdata hda_pdata = {
- .use_tplg_pcm = true,
-};
struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = {
{
/* .id is not used in this file */
.drv_name = "skl_hda_dsp_generic",
-
- /* .fw_filename is dynamically set in skylake driver */
-
- .sof_tplg_filename = "sof-hda-generic.tplg",
-
- /*
- * .machine_quirk and .quirk_data are not used here but
- * can be used if we need a more complicated machine driver
- * combining HDA+other device (e.g. DMIC).
- */
- .pdata = &hda_pdata,
+ .sof_tplg_filename = "sof-hda-generic", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
index d0062f2cd256..6ce75fbb842e 100644
--- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -8,28 +8,22 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-#include "../skylake/skl.h"
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static struct skl_machine_pdata icl_pdata = {
- .use_tplg_pcm = true,
-};
-
struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
{
.id = "INT34C2",
.drv_name = "icl_rt274",
.fw_filename = "intel/dsp_fw_icl.bin",
- .pdata = &icl_pdata,
.sof_tplg_filename = "sof-icl-rt274.tplg",
},
{
.id = "10EC5682",
- .drv_name = "sof_rt5682",
+ .drv_name = "icl_rt5682_def",
.sof_tplg_filename = "sof-icl-rt5682.tplg",
},
{
diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
index f5c7e1bbded0..d4b397c53bcc 100644
--- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c
@@ -14,7 +14,7 @@ static const struct snd_soc_acpi_codecs essx_83x6 = {
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static const struct snd_soc_acpi_codecs jsl_7219_98373_codecs = {
+static const struct snd_soc_acpi_codecs mx98373_spk = {
.num_codecs = 1,
.codecs = {"MX98373"}
};
@@ -34,6 +34,11 @@ static const struct snd_soc_acpi_codecs mx98360a_spk = {
.codecs = {"MX98360A"}
};
+static struct snd_soc_acpi_codecs rt5650_spk = {
+ .num_codecs = 1,
+ .codecs = {"10EC5650"}
+};
+
static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = {
.num_codecs = 2,
.codecs = {"10EC5682", "RTL5682"},
@@ -47,40 +52,42 @@ static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = {
struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
{
.id = "DLGS7219",
- .drv_name = "sof_da7219_mx98373",
- .sof_tplg_filename = "sof-jsl-da7219.tplg",
+ .drv_name = "jsl_da7219_def",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &jsl_7219_98373_codecs,
+ .quirk_data = &mx98373_spk,
+ .sof_tplg_filename = "sof-jsl-da7219.tplg",
},
{
.id = "DLGS7219",
- .drv_name = "sof_da7219_mx98360a",
+ .drv_name = "jsl_da7219_def",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &mx98360a_spk,
.sof_tplg_filename = "sof-jsl-da7219-mx98360a.tplg",
},
{
.comp_ids = &rt5682_rt5682s_hp,
- .drv_name = "jsl_rt5682_rt1015",
+ .drv_name = "jsl_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rt1015_spk,
.sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg",
},
{
.comp_ids = &rt5682_rt5682s_hp,
- .drv_name = "jsl_rt5682_rt1015p",
+ .drv_name = "jsl_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rt1015p_spk,
.sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg",
},
{
.comp_ids = &rt5682_rt5682s_hp,
- .drv_name = "jsl_rt5682_mx98360",
+ .drv_name = "jsl_rt5682_def",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &mx98360a_spk,
.sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg",
},
{
.comp_ids = &rt5682_rt5682s_hp,
- .drv_name = "jsl_rt5682",
+ .drv_name = "jsl_rt5682_def",
.sof_tplg_filename = "sof-jsl-rt5682.tplg",
},
{
@@ -98,6 +105,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
+ {
+ .id = "10EC5650",
+ .drv_name = "jsl_rt5682_def",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rt5650_spk,
+ .sof_tplg_filename = "sof-jsl-rt5650.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
index 4e817f559d38..d4c158d8441b 100644
--- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
@@ -8,9 +8,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-#include "../skylake/skl.h"
-
-static struct skl_machine_pdata skl_dmic_data;
static const struct snd_soc_acpi_codecs kbl_codecs = {
.num_codecs = 1,
@@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_codecs,
- .pdata = &skl_dmic_data,
},
{
.id = "MX98357A",
@@ -62,7 +58,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_codecs,
- .pdata = &skl_dmic_data,
},
{
.id = "MX98927",
@@ -70,7 +65,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_5663_5514_codecs,
- .pdata = &skl_dmic_data,
},
{
.id = "MX98927",
@@ -78,7 +72,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_poppy_codecs,
- .pdata = &skl_dmic_data,
},
{
.id = "10EC5663",
@@ -91,7 +84,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_7219_98357_codecs,
- .pdata = &skl_dmic_data,
},
{
.id = "DLGS7219",
@@ -99,7 +91,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_7219_98927_codecs,
- .pdata = &skl_dmic_data
},
{
.id = "10EC5660",
@@ -117,13 +108,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.fw_filename = "intel/dsp_fw_kbl.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_7219_98373_codecs,
- .pdata = &skl_dmic_data
},
{
.id = "MX98373",
.drv_name = "kbl_max98373",
.fw_filename = "intel/dsp_fw_kbl.bin",
- .pdata = &skl_dmic_data
},
{},
};
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 9f35b77deb11..937a74a5d523 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -2,12 +2,14 @@
/*
* soc-acpi-intel-lnl-match.c - tables and support for LNL ACPI enumeration.
*
- * Copyright (c) 2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2023, Intel Corporation
*
*/
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include "sof-function-topology-lib.h"
+#include "soc-acpi-intel-sdca-quirks.h"
#include "soc-acpi-intel-sdw-mockup-match.h"
struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[] = {
@@ -22,6 +24,302 @@ 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,
+};
+
+static const struct snd_soc_acpi_endpoint rt712_endpoints[] = {
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ {
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
+/*
+ * RT722 is a multi-function codec, three endpoints are created for
+ * its headset, amp and dmic functions.
+ */
+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_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[] = {
+ /* 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_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_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,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00023101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_r_adr[] = {
+ {
+ .adr = 0x00033201fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00033301fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = {
+ {
+ .adr = 0x00033001fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00033101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+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,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+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,
@@ -31,6 +329,220 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt712_2_single_adr[] = {
+ {
+ .adr = 0x000230025D071201ull,
+ .num_endpoints = ARRAY_SIZE(rt712_endpoints),
+ .endpoints = rt712_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = {
+ {
+ .adr = 0x000330025D171201ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt712-dmic"
+ }
+};
+
+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 = jack_amp_g1_dmic_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
+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 rt1316_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
+ {
+ .adr = 0x000331025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_adr[] = {
+ {
+ .adr = 0x000133025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+ {
+ .adr = 0x000130025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+ {
+ .adr = 0x000232025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1318-2"
+ }
+};
+
+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_2_group2_adr[] = {
+ {
+ .adr = 0x000231025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-2"
+ }
+};
+
+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,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt713"
+ }
+};
+
+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,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
+ {
+ .adr = 0x000130025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_lr_adr),
+ .adr_d = cs35l56_3_lr_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_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_l_adr),
+ .adr_d = cs35l56_2_l_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_r_adr),
+ .adr_d = cs35l56_3_r_adr,
+ },
+ {}
+};
+
+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),
@@ -40,6 +552,139 @@ static const struct snd_soc_acpi_link_adr lnl_rvp[] = {
{}
};
+static const struct snd_soc_acpi_link_adr lnl_712_only[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt712_2_single_adr),
+ .adr_d = rt712_2_single_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1712_3_single_adr),
+ .adr_d = rt1712_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr lnl_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 lnl_3_in_1_sdca[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+ .adr_d = rt1316_2_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1316_3_group1_adr),
+ .adr_d = rt1316_3_group1_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt714_1_adr),
+ .adr_d = rt714_1_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr lnl_sdw_rt1318_l12_rt714_l0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr lnl_sdw_rt1320_l12_rt714_l0[] = {
+ {
+ .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,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_adr),
+ .adr_d = rt713_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_adr),
+ .adr_d = rt1318_1_adr,
+ },
+ {}
+};
+
+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),
+ .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,
+ },
+ {}
+};
+
+/* this table is used when there is no I2S codec present */
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -63,10 +708,94 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
},
{
.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",
+ .sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = lnl_cs42l43_l0_cs35l56_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg",
+ },
+ {
+ .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",
+ .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = lnl_cs42l43_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-cs42l43-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0),
.links = lnl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt711.tplg",
},
+ {
+ .link_mask = BIT(2) | BIT(3),
+ .links = lnl_712_only,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt712-l2-rt1712-l3.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = lnl_rt722_only,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt722-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = lnl_sdw_rt1318_l12_rt714_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg"
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = lnl_sdw_rt1320_l12_rt714_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg"
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = lnl_sdw_rt713_l0_rt1318_l1,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg"
+ },
+ {
+ .link_mask = BIT(1) | BIT(2),
+ .links = lnl_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-lnl-rt712-l2-rt1320-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
{},
};
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 3d5cf8867926..ec9fd8486c05 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -6,39 +6,96 @@
*
*/
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/sdca.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+#include "sof-function-topology-lib.h"
+#include "soc-acpi-intel-sdca-quirks.h"
#include "soc-acpi-intel-sdw-mockup-match.h"
-static const struct snd_soc_acpi_codecs mtl_max98357a_amp = {
- .num_codecs = 1,
- .codecs = {"MX98357A"}
+static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
+ .num_codecs = 2,
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
-static const struct snd_soc_acpi_codecs mtl_max98360a_amp = {
- .num_codecs = 1,
- .codecs = {"MX98360A"}
+static const struct snd_soc_acpi_codecs mtl_essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
- .num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
+static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
};
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
{
- .comp_ids = &mtl_rt5682_rt5682s_hp,
- .drv_name = "mtl_mx98357_rt5682",
+ .comp_ids = &mtl_essx_83x6,
+ .drv_name = "mtl_es83x6_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &mtl_max98357a_amp,
- .sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg",
+ .quirk_data = &mtl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-mtl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &mtl_essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-mtl-es8336", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
{
.comp_ids = &mtl_rt5682_rt5682s_hp,
- .drv_name = "mtl_mx98360_rt5682",
+ .drv_name = "mtl_rt5682_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &mtl_max98360a_amp,
- .sof_tplg_filename = "sof-mtl-max98360a-rt5682.tplg",
+ .quirk_data = &mtl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-mtl-rt5682-ssp1-hdmi-ssp02.tplg",
+ },
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .id = CS42L42_ACPI_HID,
+ .drv_name = "mtl_cs42l42_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = DA7219_ACPI_HID,
+ .drv_name = "mtl_da7219_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = NAU8825_ACPI_HID,
+ .drv_name = "mtl_nau8825_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = RT5650_ACPI_HID,
+ .drv_name = "mtl_rt5682_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &mtl_rt5682_rt5682s_hp,
+ .drv_name = "mtl_rt5682_def",
+ .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ /* place amp-only boards in the end of table */
+ {
+ .id = "INTC10B0",
+ .drv_name = "mtl_lt6911_hdmi_ssp",
+ .sof_tplg_filename = "sof-mtl-hdmi-ssp02.tplg",
},
{},
};
@@ -80,6 +137,66 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = {
},
};
+static const struct snd_soc_acpi_endpoint rt712_vb_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,
+ },
+};
+
+/*
+ * RT722 is a multi-function codec, three endpoints are created for
+ * its headset, amp and dmic functions.
+ */
+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_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_adr_device rt711_sdca_0_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -98,6 +215,15 @@ static const struct snd_soc_acpi_adr_device rt712_0_single_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = {
+ {
+ .adr = 0x000030025D071201ull,
+ .num_endpoints = ARRAY_SIZE(rt712_vb_endpoints),
+ .endpoints = rt712_vb_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = {
{
.adr = 0x000330025D171201ull,
@@ -107,6 +233,33 @@ static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = {
}
};
+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 rt713_0_single_adr[] = {
+ {
+ .adr = 0x000031025D071301ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt713"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1713_3_single_adr[] = {
+ {
+ .adr = 0x000331025D171301ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt713-dmic"
+ }
+};
+
static const struct snd_soc_acpi_adr_device mx8373_0_adr[] = {
{
.adr = 0x000023019F837300ull,
@@ -149,6 +302,69 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
+ {
+ .adr = 0x000131025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = {
+ {
+ .adr = 0x000230025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
+ {
+ .adr = 0x000330025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1316-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_single_adr[] = {
+ {
+ .adr = 0x000130025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+ {
+ .adr = 0x000130025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+ {
+ .adr = 0x000232025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1318-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+ {
+ .adr = 0x000030025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
{
.adr = 0x000130025D071401ull,
@@ -158,7 +374,7 @@ static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
}
};
-static const struct snd_soc_acpi_link_adr mtl_712_only[] = {
+static const struct snd_soc_acpi_link_adr mtl_712_l0_1712_l3[] = {
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt712_0_single_adr),
@@ -172,6 +388,366 @@ static const struct snd_soc_acpi_link_adr mtl_712_only[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_712_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt712_0_single_adr),
+ .adr_d = rt712_0_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt712_vb_0_single_adr),
+ .adr_d = rt712_vb_0_single_adr,
+ },
+ {}
+};
+
+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_0_adr[] = {
+ {
+ .adr = 0x00003001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+/* 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,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00013601FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_2_adr[] = {
+ {
+ .adr = 0x00023301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00023201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+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 = ARRAY_SIZE(cs35l56_r_fb_endpoints),
+ .endpoints = cs35l56_r_fb_endpoints,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00023301FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints),
+ .endpoints = cs35l56_3_fb_endpoints,
+ .name_prefix = "AMP4"
+ }
+
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = {
+ {
+ .adr = 0x00033001fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints),
+ .endpoints = cs35l56_l_fb_endpoints,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00033101fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints),
+ .endpoints = cs35l56_2_fb_endpoints,
+ .name_prefix = "AMP2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l63_1_fb_adr[] = {
+ {
+ .adr = 0x00013001FA356301ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints),
+ .endpoints = cs35l56_l_fb_endpoints,
+ .name_prefix = "AMP1"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l63_3_fb_adr[] = {
+ {
+ .adr = 0x00033101FA356301ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints),
+ .endpoints = cs35l56_r_fb_endpoints,
+ .name_prefix = "AMP2"
+ },
+};
+
static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = {
/* Expected order: jack -> amp */
{
@@ -196,6 +772,15 @@ static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_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 mtl_3_in_1_sdca[] = {
{
.mask = BIT(0),
@@ -220,6 +805,125 @@ static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_sdw_rt1318_l12_rt714_l0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12_rt1713_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_single_adr),
+ .adr_d = rt713_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+ .adr_d = rt1316_1_group2_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group2_adr),
+ .adr_d = rt1316_2_group2_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1713_3_single_adr),
+ .adr_d = rt1713_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1318_l1_rt1713_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_single_adr),
+ .adr_d = rt713_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_single_adr),
+ .adr_d = rt1318_1_single_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1713_3_single_adr),
+ .adr_d = rt1713_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1318_l12_rt1713_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_single_adr),
+ .adr_d = rt713_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1713_3_single_adr),
+ .adr_d = rt1713_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_single_adr),
+ .adr_d = rt713_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+ .adr_d = rt1316_1_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_link_adr mtl_rt711_l0_rt1316_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1316_3_single_adr),
+ .adr_d = rt1316_3_single_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = {
{
.adr = 0x000230019F836300ull,
@@ -244,6 +948,30 @@ static const struct snd_soc_acpi_adr_device cs42l42_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device tas2783_0_adr[] = {
+ {
+ .adr = 0x0000380102000001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "tas2783-1"
+ },
+ {
+ .adr = 0x0000390102000001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "tas2783-2"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr tas2783_link0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(tas2783_0_adr),
+ .adr_d = tas2783_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr cs42l42_link0_max98363_link2[] = {
/* Expected order: jack -> amp */
{
@@ -259,6 +987,102 @@ static const struct snd_soc_acpi_link_adr cs42l42_link0_max98363_link2[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_cs42l43_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_cs42l43_cs35l56[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56_1_adr),
+ .adr_d = cs35l56_1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs35l56_2_adr),
+ .adr_d = cs35l56_2_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr cs42l43_link0_cs35l56_link2_link3[] = {
+ /* Expected order: jack -> amp */
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs35l56_2_r_adr),
+ .adr_d = cs35l56_2_r_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_l_adr),
+ .adr_d = cs35l56_3_l_adr,
+ },
+ {}
+};
+
+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,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_cs35l63_x2_link1_link3_fb[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l63_3_fb_adr),
+ .adr_d = cs35l63_3_fb_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l63_1_fb_adr),
+ .adr_d = cs35l63_1_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 */
@@ -281,18 +1105,123 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg",
},
{
+ .link_mask = BIT(0),
+ .links = tas2783_link0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-tas2783.tplg",
+ },
+ {
+ .link_mask = GENMASK(3, 0),
+ .links = mtl_rt713_l0_rt1316_l12_rt1713_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg",
+ },
+ {
+ .link_mask = GENMASK(3, 0),
+ .links = mtl_rt713_l0_rt1318_l12_rt1713_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = mtl_rt713_l0_rt1318_l1_rt1713_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg",
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = mtl_rt713_l0_rt1316_l12,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12.tplg",
+ },
+ {
.link_mask = BIT(3) | BIT(0),
- .links = mtl_712_only,
+ .links = mtl_712_l0_1712_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
},
{
+ .link_mask = BIT(0),
+ .links = mtl_712_vb_l0,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0),
+ .links = mtl_712_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt712-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = mtl_sdw_rt1318_l12_rt714_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg"
+ },
+ {
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = cs42l43_link0_cs35l56_link2_link3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = mtl_cs42l43_cs35l56,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l12.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0),
+ .links = mtl_cs42l43_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-cs42l43-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(1) | BIT(3),
+ .links = mtl_cs35l63_x2_link1_link3_fb,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg",
+ },
+ {
.link_mask = GENMASK(3, 0),
.links = mtl_3_in_1_sdca,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg",
},
{
+ .link_mask = 0x9, /* 2 active links required */
+ .links = mtl_rt711_l0_rt1316_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l3.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = mtl_rt722_only,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt722-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
.link_mask = BIT(0),
.links = mtl_rvp,
.drv_name = "sof_sdw",
@@ -313,3 +1242,5 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
+
+MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
new file mode 100644
index 000000000000..2768dd10aaa0
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-nvl-match.c - tables and support for NVL ACPI enumeration.
+ *
+ * Copyright (c) 2025, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "soc-acpi-intel-sdw-mockup-match.h"
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = {
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_machines);
+
+/*
+ * Multi-function codecs with three endpoints created for
+ * headset, amp and dmic functions.
+ */
+static const struct snd_soc_acpi_endpoint rt_mf_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_3_single_adr[] = {
+ {
+ .adr = 0x000330025d072201ull,
+ .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
+ .endpoints = rt_mf_endpoints,
+ .name_prefix = "rt722"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr nvl_rt722_l3[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt722_3_single_adr),
+ .adr_d = rt722_3_single_adr,
+ },
+ {}
+};
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_sdw_machines[] = {
+ /* mockup tests need to be first */
+ {
+ .link_mask = GENMASK(3, 0),
+ .links = sdw_mockup_headset_2amps_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-nvl-rt711-rt1308-rt715.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = sdw_mockup_headset_1amp_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-nvl-rt711-rt1308-mono-rt715.tplg",
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = sdw_mockup_mic_headset_1amp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-nvl-rt715-rt711-rt1308-mono.tplg",
+ },
+ {
+ .link_mask = BIT(3),
+ .links = nvl_rt722_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-nvl-rt722.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
new file mode 100644
index 000000000000..060955825fe0
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -0,0 +1,773 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-ptl-match.c - tables and support for PTL ACPI enumeration.
+ *
+ * Copyright (c) 2024, Intel Corporation.
+ *
+ * Order of entries in snd_soc_acpi_intel_ptl_sdw_machines[] matters.
+ * Check subset of link mask when matching the machine driver, rule is
+ * superset match should be ordered before subset matches.
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "sof-function-topology-lib.h"
+#include "soc-acpi-intel-sdca-quirks.h"
+#include "soc-acpi-intel-sdw-mockup-match.h"
+#include <sound/soc-acpi-intel-ssp-common.h>
+
+static const struct snd_soc_acpi_codecs ptl_rt5682_rt5682s_hp = {
+ .num_codecs = 2,
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
+};
+
+static const struct snd_soc_acpi_codecs ptl_essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
+static const struct snd_soc_acpi_codecs ptl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = {
+ {
+ .comp_ids = &ptl_rt5682_rt5682s_hp,
+ .drv_name = "ptl_rt5682_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &ptl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-ptl-rt5682-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &ptl_rt5682_rt5682s_hp,
+ .drv_name = "ptl_rt5682_def",
+ .sof_tplg_filename = "sof-ptl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &ptl_essx_83x6,
+ .drv_name = "ptl_es83x6_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &ptl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-ptl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &ptl_essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-ptl-es8336", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
+ /* place amp-only boards in the end of table */
+ {
+ .id = "INTC10B0",
+ .drv_name = "ptl_lt6911_hdmi_ssp",
+ .sof_tplg_filename = "sof-ptl-hdmi-ssp02.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines);
+
+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_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.
+ */
+static const struct snd_soc_acpi_endpoint rt_mf_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_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[] = {
+ /* 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_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 cs42l43_3_agg_adr[] = {
+ {
+ .adr = 0x00033001FA424301ull,
+ .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_2_lr_adr[] = {
+ {
+ .adr = 0x00023001fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00023101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
+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 rt711_sdca_0_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ }
+};
+
+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 = jack_amp_g1_dmic_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 = jack_amp_g1_dmic_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 rt1320_3_group1_adr[] = {
+ {
+ .adr = 0x000330025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt721_0_single_adr[] = {
+ {
+ .adr = 0x000030025d072101ull,
+ .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
+ .endpoints = rt_mf_endpoints,
+ .name_prefix = "rt721"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = {
+ {
+ .adr = 0x000330025d072101ull,
+ .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
+ .endpoints = rt_mf_endpoints,
+ .name_prefix = "rt721"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr ptl_rt721_l3[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt721_3_single_adr),
+ .adr_d = rt721_3_single_adr,
+ },
+ {},
+};
+
+static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = {
+ {
+ .adr = 0x000030025d072201ull,
+ .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
+ .endpoints = rt_mf_endpoints,
+ .name_prefix = "rt722"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt722_1_single_adr[] = {
+ {
+ .adr = 0x000130025d072201ull,
+ .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
+ .endpoints = rt_mf_endpoints,
+ .name_prefix = "rt722"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = {
+ {
+ .adr = 0x000330025d072201ull,
+ .num_endpoints = ARRAY_SIZE(rt_mf_endpoints),
+ .endpoints = rt_mf_endpoints,
+ .name_prefix = "rt722"
+ }
+};
+
+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_2_group2_l_adr[] = {
+ {
+ .adr = 0x000230025D132001ull,
+ .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_link_adr ptl_cs42l43_agg_l3_cs35l56_l2[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs42l43_3_agg_adr),
+ .adr_d = cs42l43_3_agg_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs35l56_2_lr_adr),
+ .adr_d = cs35l56_2_lr_adr,
+ },
+ {}
+};
+
+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_rt721_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt721_0_single_adr),
+ .adr_d = rt721_0_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_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 ptl_rt722_l1[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt722_1_single_adr),
+ .adr_d = rt722_1_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt722_3_single_adr),
+ .adr_d = rt722_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_rt722_l0_rt1320_l23[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt722_0_single_adr),
+ .adr_d = rt722_0_single_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1320_2_group2_l_adr),
+ .adr_d = rt1320_2_group2_l_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_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
+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,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l3[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt712_vb_3_group1_adr),
+ .adr_d = rt712_vb_3_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1320_3_group1_adr),
+ .adr_d = rt1320_3_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[] = {
+/* Order Priority: mockup > most links > most bit link-mask > alphabetical */
+ {
+ .link_mask = GENMASK(3, 0),
+ .links = sdw_mockup_headset_2amps_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt711-rt1308-rt715.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = sdw_mockup_headset_1amp_mic,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt711-rt1308-mono-rt715.tplg",
+ },
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = sdw_mockup_mic_headset_1amp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt715-rt711-rt1308-mono.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(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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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) | BIT(2) | BIT(3),
+ .links = ptl_rt722_l0_rt1320_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt722-l0-rt1320-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .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",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(2) | BIT(3),
+ .links = ptl_cs42l43_agg_l3_cs35l56_l2,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-cs42l43-agg-l3-cs35l56-l2.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = ptl_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt711.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = ptl_rt721_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt721.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(0),
+ .links = ptl_rt722_only,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt722.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(1),
+ .links = ptl_rt722_l1,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt722.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(3),
+ .links = ptl_sdw_rt712_vb_l3_rt1320_l3,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(3),
+ .links = ptl_rt721_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt721.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {
+ .link_mask = BIT(3),
+ .links = ptl_rt722_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt722.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index 302a08018572..b83ac2e6337c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -7,6 +7,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
@@ -29,6 +30,42 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
.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_0_adr[] = {
+ {
+ .adr = 0x00003001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt711_0_adr[] = {
{
.adr = 0x000020025D071100ull,
@@ -155,6 +192,15 @@ static const struct snd_soc_acpi_adr_device rt714_3_adr[] = {
}
};
+static const struct snd_soc_acpi_link_adr rpl_cs42l43_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = {
{
.mask = BIT(0),
@@ -246,6 +292,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01[] =
{}
};
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1316_link12[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1316_1_group1_adr),
+ .adr_d = rt1316_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+ .adr_d = rt1316_2_group1_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
{
.mask = BIT(0),
@@ -308,6 +373,15 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] =
{}
};
+static const struct snd_soc_acpi_link_adr rpl_sdca_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr rplp_crb[] = {
{
.mask = BIT(2),
@@ -319,45 +393,97 @@ static const struct snd_soc_acpi_link_adr rplp_crb[] = {
static const struct snd_soc_acpi_codecs rpl_rt5682_hp = {
.num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
};
-static const struct snd_soc_acpi_codecs rpl_max98360a_amp = {
- .num_codecs = 1,
- .codecs = {"MX98360A"},
+static const struct snd_soc_acpi_codecs rpl_essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static const struct snd_soc_acpi_codecs rpl_max98373_amp = {
+static const struct snd_soc_acpi_codecs rpl_max98357a_amp = {
.num_codecs = 1,
- .codecs = {"MX98373"}
+ .codecs = {"MX98357A"}
};
-static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = {
+static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = {
.num_codecs = 1,
- .codecs = {"RTL1019"}
+ .codecs = {"INTC10B0"}
};
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
{
.comp_ids = &rpl_rt5682_hp,
- .drv_name = "rpl_mx98360_rt5682",
+ .drv_name = "rpl_mx98357_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_max98360a_amp,
- .sof_tplg_filename = "sof-rpl-max98360a-rt5682.tplg",
+ .quirk_data = &rpl_max98357a_amp,
+ .sof_tplg_filename = "sof-rpl-max98357a-rt5682.tplg",
},
{
- .id = "10508825",
- .drv_name = "rpl_max98373_8825",
+ .comp_ids = &rpl_rt5682_hp,
+ .drv_name = "rpl_rt5682_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_max98373_amp,
- .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg",
+ .quirk_data = &rpl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-rpl-rt5682-ssp1-hdmi-ssp02.tplg",
},
{
- .comp_ids = &rpl_rt5682_hp,
- .drv_name = "rpl_rt1019_rt5682",
+ .comp_ids = &rpl_essx_83x6,
+ .drv_name = "rpl_es83x6_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &rpl_rt1019p_amp,
- .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg",
+ .quirk_data = &rpl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-rpl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &rpl_essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-rpl-es83x6", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .id = CS42L42_ACPI_HID,
+ .drv_name = "rpl_cs42l42_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = DA7219_ACPI_HID,
+ .drv_name = "rpl_da7219_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = NAU8825_ACPI_HID,
+ .drv_name = "rpl_nau8825_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .id = RT5650_ACPI_HID,
+ .drv_name = "rpl_rt5682_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ {
+ .comp_ids = &rpl_rt5682_hp,
+ .drv_name = "rpl_rt5682_def",
+ .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ /* place amp-only boards in the end of table */
+ {
+ .id = "INTC10B0",
+ .drv_name = "rpl_lt6911_hdmi_ssp",
+ .sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg"
},
{},
};
@@ -366,6 +492,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines);
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
{
+ .link_mask = BIT(0),
+ .links = rpl_cs42l43_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-cs42l43-l0.tplg",
+ },
+ {
.link_mask = 0xF, /* 4 active links required */
.links = rpl_sdca_3_in_1,
.drv_name = "sof_sdw",
@@ -390,6 +522,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
},
{
+ .link_mask = 0x7, /* rt711 on link0 & two rt1316s on link1 and link2 */
+ .links = rpl_sdw_rt711_link0_rt1316_link12,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l0-rt1316-l12.tplg",
+ },
+ {
.link_mask = 0x7, /* rt711 on link0 & two rt1318s on link1 and link2 */
.links = rpl_sdw_rt711_link0_rt1318_link12,
.drv_name = "sof_sdw",
@@ -414,6 +552,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
.sof_tplg_filename = "sof-rpl-rt711-l0.tplg",
},
{
+ .link_mask = 0x1, /* link0 required */
+ .links = rpl_sdca_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l0.tplg",
+ },
+ {
.link_mask = 0x4, /* link2 required */
.links = rplp_crb,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
new file mode 100644
index 000000000000..3eaa058f8460
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks
+ *
+ * Copyright (c) 2024, Intel Corporation.
+ *
+ */
+
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/sdca.h>
+#include <sound/soc-acpi.h>
+#include "soc-acpi-intel-sdca-quirks.h"
+
+/*
+ * Pretend machine quirk. The argument type is not the traditional
+ * 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx
+ * which contains the peripheral information required for the
+ * SoundWire/SDCA filter on the SMART_MIC setup and interface
+ * revision. When the return value is false, the entry in the
+ * 'snd_soc_acpi_mach' table needs to be skipped.
+ */
+bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg)
+{
+ struct sdw_intel_ctx *ctx = arg;
+ int i;
+
+ if (!ctx)
+ return false;
+
+ for (i = 0; i < ctx->peripherals->num_peripherals; i++) {
+ if (sdca_device_quirk_match(ctx->peripherals->array[i],
+ SDCA_QUIRKS_RT712_VB))
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+
+MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
new file mode 100644
index 000000000000..bead5ec6243f
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks
+ *
+ * Copyright (c) 2024, Intel Corporation.
+ *
+ */
+
+#ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
+#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
+
+bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg);
+
+#endif
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-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
index 75302e956742..ee6463202918 100644
--- a/sound/soc/intel/common/soc-acpi-intel-skl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
@@ -8,9 +8,6 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
-#include "../skylake/skl.h"
-
-static struct skl_machine_pdata skl_dmic_data;
static const struct snd_soc_acpi_codecs skl_codecs = {
.num_codecs = 1,
@@ -29,7 +26,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = {
.fw_filename = "intel/dsp_fw_release.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &skl_codecs,
- .pdata = &skl_dmic_data,
},
{
.id = "MX98357A",
@@ -37,7 +33,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = {
.fw_filename = "intel/dsp_fw_release.bin",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &skl_codecs,
- .pdata = &skl_dmic_data,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-ssp-common.c b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c
new file mode 100644
index 000000000000..f56f4bfa5187
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2023 Intel Corporation
+
+#include <linux/device.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+
+/*
+ * Codec probe function
+ */
+#define CODEC_MAP_ENTRY(n, s, h, t) \
+ { \
+ .name = n, \
+ .tplg_suffix = s, \
+ .acpi_hid = h, \
+ .codec_type = t, \
+ }
+
+struct codec_map {
+ const char *name;
+ const char *tplg_suffix;
+ const char *acpi_hid;
+ enum snd_soc_acpi_intel_codec codec_type;
+};
+
+static const struct codec_map codecs[] = {
+ /* Cirrus Logic */
+ CODEC_MAP_ENTRY("CS42L42", "cs42l42", CS42L42_ACPI_HID, CODEC_CS42L42),
+
+ /* Dialog */
+ CODEC_MAP_ENTRY("DA7219", "da7219", DA7219_ACPI_HID, CODEC_DA7219),
+
+ /* Everest */
+ CODEC_MAP_ENTRY("ES8316", "es8336", ES8316_ACPI_HID, CODEC_ES8316),
+ CODEC_MAP_ENTRY("ES8326", "es8336", ES8326_ACPI_HID, CODEC_ES8326),
+ CODEC_MAP_ENTRY("ES8336", "es8336", ES8336_ACPI_HID, CODEC_ES8336),
+
+ /* Nuvoton */
+ CODEC_MAP_ENTRY("NAU8825", "nau8825", NAU8825_ACPI_HID, CODEC_NAU8825),
+
+ /* Realtek */
+ CODEC_MAP_ENTRY("RT5650", "rt5650", RT5650_ACPI_HID, CODEC_RT5650),
+ CODEC_MAP_ENTRY("RT5682", "rt5682", RT5682_ACPI_HID, CODEC_RT5682),
+ CODEC_MAP_ENTRY("RT5682S", "rt5682", RT5682S_ACPI_HID, CODEC_RT5682S),
+};
+
+static const struct codec_map amps[] = {
+ /* Cirrus Logic */
+ CODEC_MAP_ENTRY("CS35L41", "cs35l41", CS35L41_ACPI_HID, CODEC_CS35L41),
+
+ /* Maxim */
+ CODEC_MAP_ENTRY("MAX98357A", "max98357a", MAX_98357A_ACPI_HID, CODEC_MAX98357A),
+ CODEC_MAP_ENTRY("MAX98360A", "max98360a", MAX_98360A_ACPI_HID, CODEC_MAX98360A),
+ CODEC_MAP_ENTRY("MAX98373", "max98373", MAX_98373_ACPI_HID, CODEC_MAX98373),
+ CODEC_MAP_ENTRY("MAX98390", "max98390", MAX_98390_ACPI_HID, CODEC_MAX98390),
+
+ /* Nuvoton */
+ CODEC_MAP_ENTRY("NAU8318", "nau8318", NAU8318_ACPI_HID, CODEC_NAU8318),
+
+ /* Realtek */
+ CODEC_MAP_ENTRY("RT1011", "rt1011", RT1011_ACPI_HID, CODEC_RT1011),
+ CODEC_MAP_ENTRY("RT1015", "rt1015", RT1015_ACPI_HID, CODEC_RT1015),
+ CODEC_MAP_ENTRY("RT1015P", "rt1015", RT1015P_ACPI_HID, CODEC_RT1015P),
+ CODEC_MAP_ENTRY("RT1019P", "rt1019", RT1019P_ACPI_HID, CODEC_RT1019P),
+ CODEC_MAP_ENTRY("RT1308", "rt1308", RT1308_ACPI_HID, CODEC_RT1308),
+
+ /*
+ * Monolithic components
+ *
+ * Only put components that can serve as both the amp and the codec below this line.
+ * This will ensure that if the part is used just as a codec and there is an amp as well
+ * then the amp will be selected properly.
+ */
+ CODEC_MAP_ENTRY("RT5650", "rt5650", RT5650_ACPI_HID, CODEC_RT5650),
+};
+
+enum snd_soc_acpi_intel_codec
+snd_soc_acpi_intel_detect_codec_type(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codecs); i++) {
+ if (!acpi_dev_present(codecs[i].acpi_hid, NULL, -1))
+ continue;
+
+ dev_dbg(dev, "codec %s found\n", codecs[i].name);
+ return codecs[i].codec_type;
+ }
+
+ return CODEC_NONE;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_codec_type, "SND_SOC_ACPI_INTEL_MATCH");
+
+enum snd_soc_acpi_intel_codec
+snd_soc_acpi_intel_detect_amp_type(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(amps); i++) {
+ if (!acpi_dev_present(amps[i].acpi_hid, NULL, -1))
+ continue;
+
+ dev_dbg(dev, "amp %s found\n", amps[i].name);
+ return amps[i].codec_type;
+ }
+
+ return CODEC_NONE;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_amp_type, "SND_SOC_ACPI_INTEL_MATCH");
+
+const char *
+snd_soc_acpi_intel_get_codec_name(enum snd_soc_acpi_intel_codec codec_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codecs); i++) {
+ if (codecs[i].codec_type != codec_type)
+ continue;
+
+ return codecs[i].name;
+ }
+ for (i = 0; i < ARRAY_SIZE(amps); i++) {
+ if (amps[i].codec_type != codec_type)
+ continue;
+
+ return amps[i].name;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_name, "SND_SOC_ACPI_INTEL_MATCH");
+
+const char *
+snd_soc_acpi_intel_get_codec_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codecs); i++) {
+ if (codecs[i].codec_type != codec_type)
+ continue;
+
+ return codecs[i].tplg_suffix;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_tplg_suffix, "SND_SOC_ACPI_INTEL_MATCH");
+
+const char *
+snd_soc_acpi_intel_get_amp_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(amps); i++) {
+ if (amps[i].codec_type != codec_type)
+ continue;
+
+ return amps[i].tplg_suffix;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_amp_tplg_suffix, "SND_SOC_ACPI_INTEL_MATCH");
+
+MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
+MODULE_LICENSE("GPL");
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 5804926c8b56..b77aafb0bfb6 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -8,6 +8,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
#include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs essx_83x6 = {
@@ -15,11 +16,6 @@ static const struct snd_soc_acpi_codecs essx_83x6 = {
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
-static const struct snd_soc_acpi_codecs tgl_codecs = {
- .num_codecs = 1,
- .codecs = {"MX98357A"}
-};
-
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
.aggregated = 0,
@@ -41,6 +37,20 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
.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 rt712_endpoints[] = {
{
.num = 0,
@@ -400,48 +410,102 @@ static const struct snd_soc_acpi_link_adr tgl_712_only[] = {
{}
};
-static const struct snd_soc_acpi_codecs tgl_max98373_amp = {
- .num_codecs = 1,
- .codecs = {"MX98373"}
+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_codecs tgl_rt1011_amp = {
- .num_codecs = 1,
- .codecs = {"10EC1011"}
+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_codecs tgl_rt5682_rt5682s_hp = {
- .num_codecs = 2,
- .codecs = {"10EC5682", "RTL5682"},
+static const struct snd_soc_acpi_adr_device cs35l56_0_adr[] = {
+ {
+ .adr = 0x00003301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00003201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP2"
+ }
};
-static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = {
- .num_codecs = 1,
- .codecs = {"INTC10B0"}
+static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = {
+ {
+ .adr = 0x00013701FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00013601FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP4"
+ }
};
-struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
+static const struct snd_soc_acpi_link_adr tgl_cs42l43_cs35l56[] = {
{
- .comp_ids = &tgl_rt5682_rt5682s_hp,
- .drv_name = "tgl_mx98357_rt5682",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &tgl_codecs,
- .sof_tplg_filename = "sof-tgl-max98357a-rt5682.tplg",
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs42l43_3_adr),
+ .adr_d = cs42l43_3_adr,
},
{
- .comp_ids = &tgl_rt5682_rt5682s_hp,
- .drv_name = "tgl_mx98373_rt5682",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &tgl_max98373_amp,
- .sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg",
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs35l56_0_adr),
+ .adr_d = cs35l56_0_adr,
},
{
- .comp_ids = &tgl_rt5682_rt5682s_hp,
- .drv_name = "tgl_rt1011_rt5682",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &tgl_rt1011_amp,
- .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg",
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56_1_adr),
+ .adr_d = cs35l56_1_adr,
},
+ {}
+};
+
+static const struct snd_soc_acpi_codecs tgl_rt5682_rt5682s_hp = {
+ .num_codecs = 2,
+ .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID},
+};
+
+static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
{
.comp_ids = &essx_83x6,
.drv_name = "sof-essx8336",
@@ -450,6 +514,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
+ /* place boards for each headphone codec: sof driver will complete the
+ * tplg name and machine driver will detect the amp type
+ */
+ {
+ .comp_ids = &tgl_rt5682_rt5682s_hp,
+ .drv_name = "tgl_rt5682_def",
+ .sof_tplg_filename = "sof-tgl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
+ },
+ /* place amp-only boards in the end of table */
{
.id = "10EC1308",
.drv_name = "tgl_rt1308_hdmi_ssp",
@@ -461,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 */
@@ -495,6 +758,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
.sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg",
},
{
+ .link_mask = 0xB,
+ .links = tgl_cs42l43_cs35l56,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-tgl-cs42l43-l3-cs35l56-l01.tplg",
+ },
+ {
.link_mask = 0xF, /* 4 active links required */
.links = tgl_3_in_1_default,
.drv_name = "sof_sdw",
@@ -554,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/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h
index de4e550c5b34..42bd51456b94 100644
--- a/sound/soc/intel/common/soc-intel-quirks.h
+++ b/sound/soc/intel/common/soc-intel-quirks.h
@@ -11,7 +11,7 @@
#include <linux/platform_data/x86/soc.h>
-#if IS_ENABLED(CONFIG_X86)
+#if IS_REACHABLE(CONFIG_IOSF_MBI)
#include <linux/dmi.h>
#include <asm/iosf_mbi.h>
diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c
new file mode 100644
index 000000000000..b10d4794159a
--- /dev/null
+++ b/sound/soc/intel/common/sof-function-topology-lib.c
@@ -0,0 +1,140 @@
+// 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.
+//
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "sof-function-topology-lib.h"
+
+enum tplg_device_id {
+ TPLG_DEVICE_SDCA_JACK,
+ TPLG_DEVICE_SDCA_AMP,
+ TPLG_DEVICE_SDCA_MIC,
+ TPLG_DEVICE_INTEL_PCH_DMIC,
+ TPLG_DEVICE_HDMI,
+ TPLG_DEVICE_MAX
+};
+
+#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \
+ BIT(TPLG_DEVICE_SDCA_MIC))
+
+#define SOF_INTEL_PLATFORM_NAME_MAX 4
+
+int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
+ const char *prefix, const char ***tplg_files)
+{
+ struct snd_soc_acpi_mach_params mach_params = mach->mach_params;
+ struct snd_soc_dai_link *dai_link;
+ const struct firmware *fw;
+ char platform[SOF_INTEL_PLATFORM_NAME_MAX];
+ unsigned long tplg_mask = 0;
+ int tplg_num = 0;
+ int tplg_dev;
+ int ret;
+ int i;
+
+ ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
+ if (ret != 1) {
+ dev_err(card->dev, "Invalid platform name %s of tplg %s\n",
+ platform, mach->sof_tplg_filename);
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ char *tplg_dev_name;
+
+ dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
+ if (strstr(dai_link->name, "SimpleJack")) {
+ tplg_dev = TPLG_DEVICE_SDCA_JACK;
+ tplg_dev_name = "sdca-jack";
+ } else if (strstr(dai_link->name, "SmartAmp")) {
+ tplg_dev = TPLG_DEVICE_SDCA_AMP;
+ tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL,
+ "sdca-%damp", dai_link->num_cpus);
+ if (!tplg_dev_name)
+ return -ENOMEM;
+ } else if (strstr(dai_link->name, "SmartMic")) {
+ tplg_dev = TPLG_DEVICE_SDCA_MIC;
+ tplg_dev_name = "sdca-mic";
+ } else if (strstr(dai_link->name, "dmic")) {
+ switch (mach_params.dmic_num) {
+ case 2:
+ tplg_dev_name = "dmic-2ch";
+ break;
+ case 4:
+ tplg_dev_name = "dmic-4ch";
+ break;
+ default:
+ dev_warn(card->dev,
+ "unsupported number of dmics: %d\n",
+ mach_params.dmic_num);
+ continue;
+ }
+ tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
+ } else if (strstr(dai_link->name, "iDisp")) {
+ tplg_dev = TPLG_DEVICE_HDMI;
+ tplg_dev_name = "hdmi-pcm5";
+
+ } else {
+ /* The dai link is not supported by separated tplg yet */
+ dev_dbg(card->dev,
+ "dai_link %s is not supported by separated tplg yet\n",
+ dai_link->name);
+ return 0;
+ }
+ if (tplg_mask & BIT(tplg_dev))
+ continue;
+
+ tplg_mask |= BIT(tplg_dev);
+
+ /*
+ * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
+ * where <platform> is only required for the DMIC function as the nhlt blob
+ * is platform dependent.
+ */
+ switch (tplg_dev) {
+ case TPLG_DEVICE_INTEL_PCH_DMIC:
+ (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s/sof-%s-%s-id%d.tplg",
+ prefix, platform,
+ tplg_dev_name, dai_link->id);
+ break;
+ default:
+ (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s/sof-%s-id%d.tplg",
+ prefix, tplg_dev_name,
+ dai_link->id);
+ break;
+ }
+ if (!(*tplg_files)[tplg_num])
+ return -ENOMEM;
+ tplg_num++;
+ }
+
+ dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
+
+ /* Check presence of sub-topologies */
+ for (i = 0; i < tplg_num; i++) {
+ ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
+ if (!ret) {
+ release_firmware(fw);
+ } else {
+ dev_warn(card->dev,
+ "Failed to open topology file: %s, you might need to\n",
+ (*tplg_files)[i]);
+ dev_warn(card->dev,
+ "download it from https://github.com/thesofproject/sof-bin/\n");
+ return 0;
+ }
+ }
+
+ return tplg_num;
+}
+EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files);
diff --git a/sound/soc/intel/common/sof-function-topology-lib.h b/sound/soc/intel/common/sof-function-topology-lib.h
new file mode 100644
index 000000000000..e7d0c39d0788
--- /dev/null
+++ b/sound/soc/intel/common/sof-function-topology-lib.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * soc-acpi-intel-get-tplg.h - get-tplg-files ops
+ *
+ * Copyright (c) 2025, Intel Corporation.
+ *
+ */
+
+#ifndef _SND_SOC_ACPI_INTEL_GET_TPLG_H
+#define _SND_SOC_ACPI_INTEL_GET_TPLG_H
+
+int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
+ const char *prefix, const char ***tplg_files);
+
+#endif
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
deleted file mode 100644
index de2b44568feb..000000000000
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel Smart Sound Technology
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#ifndef __SOUND_SOC_SST_DSP_PRIV_H
-#define __SOUND_SOC_SST_DSP_PRIV_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/firmware.h>
-
-#include "../skylake/skl-sst-dsp.h"
-
-/*
- * DSP Operations exported by platform Audio DSP driver.
- */
-struct sst_ops {
- /* Shim IO */
- void (*write)(void __iomem *addr, u32 offset, u32 value);
- u32 (*read)(void __iomem *addr, u32 offset);
-
- /* IRQ handlers */
- irqreturn_t (*irq_handler)(int irq, void *context);
-
- /* SST init and free */
- int (*init)(struct sst_dsp *sst);
- void (*free)(struct sst_dsp *sst);
-};
-
-/*
- * Audio DSP memory offsets and addresses.
- */
-struct sst_addr {
- u32 sram0_base;
- u32 sram1_base;
- u32 w0_stat_sz;
- u32 w0_up_sz;
- void __iomem *lpe;
- void __iomem *shim;
-};
-
-/*
- * Audio DSP Mailbox configuration.
- */
-struct sst_mailbox {
- void __iomem *in_base;
- void __iomem *out_base;
- size_t in_size;
- size_t out_size;
-};
-
-/*
- * Generic SST Shim Interface.
- */
-struct sst_dsp {
-
- /* Shared for all platforms */
-
- /* runtime */
- struct sst_dsp_device *sst_dev;
- spinlock_t spinlock; /* IPC locking */
- struct mutex mutex; /* DSP FW lock */
- struct device *dev;
- void *thread_context;
- int irq;
- u32 id;
-
- /* operations */
- struct sst_ops *ops;
-
- /* debug FS */
- struct dentry *debugfs_root;
-
- /* base addresses */
- struct sst_addr addr;
-
- /* mailbox */
- struct sst_mailbox mailbox;
-
- /* SST FW files loaded and their modules */
- struct list_head module_list;
-
- /* SKL data */
-
- const char *fw_name;
-
- /* To allocate CL dma buffers */
- struct skl_dsp_loader_ops dsp_ops;
- struct skl_dsp_fw_ops fw_ops;
- int sst_state;
- struct skl_cl_dev cl_dev;
- u32 intr_status;
- const struct firmware *fw;
- struct snd_dma_buffer dmab;
-};
-
-#endif
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
deleted file mode 100644
index 229d09d61afb..000000000000
--- a/sound/soc/intel/common/sst-dsp.c
+++ /dev/null
@@ -1,250 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Smart Sound Technology (SST) DSP Core Driver
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/delay.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/intel-sst.h>
-
-/* Internal generic low-level SST IO functions - can be overidden */
-void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
-{
- writel(value, addr + offset);
-}
-EXPORT_SYMBOL_GPL(sst_shim32_write);
-
-u32 sst_shim32_read(void __iomem *addr, u32 offset)
-{
- return readl(addr + offset);
-}
-EXPORT_SYMBOL_GPL(sst_shim32_read);
-
-void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
-{
- writeq(value, addr + offset);
-}
-EXPORT_SYMBOL_GPL(sst_shim32_write64);
-
-u64 sst_shim32_read64(void __iomem *addr, u32 offset)
-{
- return readq(addr + offset);
-}
-EXPORT_SYMBOL_GPL(sst_shim32_read64);
-
-/* Public API */
-void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sst->spinlock, flags);
- sst->ops->write(sst->addr.shim, offset, value);
- spin_unlock_irqrestore(&sst->spinlock, flags);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
-
-u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
-{
- unsigned long flags;
- u32 val;
-
- spin_lock_irqsave(&sst->spinlock, flags);
- val = sst->ops->read(sst->addr.shim, offset);
- spin_unlock_irqrestore(&sst->spinlock, flags);
-
- return val;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
-
-void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
-{
- sst->ops->write(sst->addr.shim, offset, value);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
-
-u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
-{
- return sst->ops->read(sst->addr.shim, offset);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
-
-int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value)
-{
- bool change;
- unsigned int old, new;
- u32 ret;
-
- ret = sst_dsp_shim_read_unlocked(sst, offset);
-
- old = ret;
- new = (old & (~mask)) | (value & mask);
-
- change = (old != new);
- if (change)
- sst_dsp_shim_write_unlocked(sst, offset, new);
-
- return change;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
-
-/* This is for registers bits with attribute RWC */
-void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value)
-{
- unsigned int old, new;
- u32 ret;
-
- ret = sst_dsp_shim_read_unlocked(sst, offset);
-
- old = ret;
- new = (old & (~mask)) | (value & mask);
-
- sst_dsp_shim_write_unlocked(sst, offset, new);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked);
-
-int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value)
-{
- unsigned long flags;
- bool change;
-
- spin_lock_irqsave(&sst->spinlock, flags);
- change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
- spin_unlock_irqrestore(&sst->spinlock, flags);
- return change;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
-
-/* This is for registers bits with attribute RWC */
-void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sst->spinlock, flags);
- sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value);
- spin_unlock_irqrestore(&sst->spinlock, flags);
-}
-EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
-
-int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
- u32 target, u32 time, char *operation)
-{
- u32 reg;
- unsigned long timeout;
- int k = 0, s = 500;
-
- /*
- * split the loop into sleeps of varying resolution. more accurately,
- * the range of wakeups are:
- * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
- * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms
- * (usleep_range (500, 1000) and usleep_range(5000, 10000) are
- * both possible in this phase depending on whether k > 10 or not).
- * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms.
- */
-
- timeout = jiffies + msecs_to_jiffies(time);
- while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
- && time_before(jiffies, timeout)) {
- k++;
- if (k > 10)
- s = 5000;
-
- usleep_range(s, 2*s);
- }
-
- if ((reg & mask) == target) {
- dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
- reg, operation);
-
- return 0;
- }
-
- dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n",
- reg, operation);
- return -ETIME;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
-
-int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
- u32 outbox_offset, size_t outbox_size)
-{
- sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
- sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
- sst->mailbox.in_size = inbox_size;
- sst->mailbox.out_size = outbox_size;
- return 0;
-}
-EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
-
-void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
-{
- u32 i;
-
- trace_sst_ipc_outbox_write(bytes);
-
- memcpy_toio(sst->mailbox.out_base, message, bytes);
-
- for (i = 0; i < bytes; i += 4)
- trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
-
-void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
-{
- u32 i;
-
- trace_sst_ipc_outbox_read(bytes);
-
- memcpy_fromio(message, sst->mailbox.out_base, bytes);
-
- for (i = 0; i < bytes; i += 4)
- trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
-
-void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
-{
- u32 i;
-
- trace_sst_ipc_inbox_write(bytes);
-
- memcpy_toio(sst->mailbox.in_base, message, bytes);
-
- for (i = 0; i < bytes; i += 4)
- trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
-
-void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
-{
- u32 i;
-
- trace_sst_ipc_inbox_read(bytes);
-
- memcpy_fromio(message, sst->mailbox.in_base, bytes);
-
- for (i = 0; i < bytes; i += 4)
- trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
-}
-EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood");
-MODULE_DESCRIPTION("Intel SST Core");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h
deleted file mode 100644
index f111fd3f334b..000000000000
--- a/sound/soc/intel/common/sst-dsp.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel Smart Sound Technology (SST) Core
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#ifndef __SOUND_SOC_SST_DSP_H
-#define __SOUND_SOC_SST_DSP_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-
-struct sst_dsp;
-
-/*
- * SST Device.
- *
- * This structure is populated by the SST core driver.
- */
-struct sst_dsp_device {
- /* Mandatory fields */
- struct sst_ops *ops;
- irqreturn_t (*thread)(int irq, void *context);
- void *thread_context;
-};
-
-/* SHIM Read / Write */
-void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
-u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
-int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value);
-void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value);
-
-/* SHIM Read / Write Unlocked for callers already holding sst lock */
-void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
-u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
-int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value);
-void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
- u32 mask, u32 value);
-
-/* Internal generic low-level SST IO functions - can be overidden */
-void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
-u32 sst_shim32_read(void __iomem *addr, u32 offset);
-void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
-u64 sst_shim32_read64(void __iomem *addr, u32 offset);
-
-/* Mailbox management */
-int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset,
- size_t inbox_size, u32 outbox_offset, size_t outbox_size);
-void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes);
-void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes);
-void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes);
-void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes);
-int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
- u32 target, u32 time, char *operation);
-
-#endif
diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c
deleted file mode 100644
index 89c10724d2a3..000000000000
--- a/sound/soc/intel/common/sst-ipc.c
+++ /dev/null
@@ -1,294 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel SST generic IPC Support
- *
- * Copyright (C) 2015, Intel Corporation. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <sound/asound.h>
-
-#include "sst-dsp.h"
-#include "sst-dsp-priv.h"
-#include "sst-ipc.h"
-
-/* IPC message timeout (msecs) */
-#define IPC_TIMEOUT_MSECS 300
-
-#define IPC_EMPTY_LIST_SIZE 8
-
-/* locks held by caller */
-static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc)
-{
- struct ipc_message *msg = NULL;
-
- if (!list_empty(&ipc->empty_list)) {
- msg = list_first_entry(&ipc->empty_list, struct ipc_message,
- list);
- list_del(&msg->list);
- }
-
- return msg;
-}
-
-static int tx_wait_done(struct sst_generic_ipc *ipc,
- struct ipc_message *msg, struct sst_ipc_message *reply)
-{
- unsigned long flags;
- int ret;
-
- /* wait for DSP completion (in all cases atm inc pending) */
- ret = wait_event_timeout(msg->waitq, msg->complete,
- msecs_to_jiffies(IPC_TIMEOUT_MSECS));
-
- spin_lock_irqsave(&ipc->dsp->spinlock, flags);
- if (ret == 0) {
- if (ipc->ops.shim_dbg != NULL)
- ipc->ops.shim_dbg(ipc, "message timeout");
-
- list_del(&msg->list);
- ret = -ETIMEDOUT;
- } else {
-
- /* copy the data returned from DSP */
- if (reply) {
- reply->header = msg->rx.header;
- if (reply->data)
- memcpy(reply->data, msg->rx.data, msg->rx.size);
- }
- ret = msg->errno;
- }
-
- list_add_tail(&msg->list, &ipc->empty_list);
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
- return ret;
-}
-
-static int ipc_tx_message(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request,
- struct sst_ipc_message *reply, int wait)
-{
- struct ipc_message *msg;
- unsigned long flags;
-
- spin_lock_irqsave(&ipc->dsp->spinlock, flags);
-
- msg = msg_get_empty(ipc);
- if (msg == NULL) {
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
- return -EBUSY;
- }
-
- msg->tx.header = request.header;
- msg->tx.size = request.size;
- msg->rx.header = 0;
- msg->rx.size = reply ? reply->size : 0;
- msg->wait = wait;
- msg->errno = 0;
- msg->pending = false;
- msg->complete = false;
-
- if ((request.size) && (ipc->ops.tx_data_copy != NULL))
- ipc->ops.tx_data_copy(msg, request.data, request.size);
-
- list_add_tail(&msg->list, &ipc->tx_list);
- schedule_work(&ipc->kwork);
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
-
- if (wait)
- return tx_wait_done(ipc, msg, reply);
- else
- return 0;
-}
-
-static int msg_empty_list_init(struct sst_generic_ipc *ipc)
-{
- int i;
-
- ipc->msg = kcalloc(IPC_EMPTY_LIST_SIZE, sizeof(struct ipc_message),
- GFP_KERNEL);
- if (ipc->msg == NULL)
- return -ENOMEM;
-
- for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
- ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL);
- if (ipc->msg[i].tx.data == NULL)
- goto free_mem;
-
- ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL);
- if (ipc->msg[i].rx.data == NULL) {
- kfree(ipc->msg[i].tx.data);
- goto free_mem;
- }
-
- init_waitqueue_head(&ipc->msg[i].waitq);
- list_add(&ipc->msg[i].list, &ipc->empty_list);
- }
-
- return 0;
-
-free_mem:
- while (i > 0) {
- kfree(ipc->msg[i-1].tx.data);
- kfree(ipc->msg[i-1].rx.data);
- --i;
- }
- kfree(ipc->msg);
-
- return -ENOMEM;
-}
-
-static void ipc_tx_msgs(struct work_struct *work)
-{
- struct sst_generic_ipc *ipc =
- container_of(work, struct sst_generic_ipc, kwork);
- struct ipc_message *msg;
-
- spin_lock_irq(&ipc->dsp->spinlock);
-
- while (!list_empty(&ipc->tx_list) && !ipc->pending) {
- /* if the DSP is busy, we will TX messages after IRQ.
- * also postpone if we are in the middle of processing
- * completion irq
- */
- if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
- dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n");
- break;
- }
-
- msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
- list_move(&msg->list, &ipc->rx_list);
-
- if (ipc->ops.tx_msg != NULL)
- ipc->ops.tx_msg(ipc, msg);
- }
-
- spin_unlock_irq(&ipc->dsp->spinlock);
-}
-
-int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request, struct sst_ipc_message *reply)
-{
- int ret;
-
- /*
- * DSP maybe in lower power active state, so
- * check if the DSP supports DSP lp On method
- * if so invoke that before sending IPC
- */
- if (ipc->ops.check_dsp_lp_on)
- if (ipc->ops.check_dsp_lp_on(ipc->dsp, true))
- return -EIO;
-
- ret = ipc_tx_message(ipc, request, reply, 1);
-
- if (ipc->ops.check_dsp_lp_on)
- if (ipc->ops.check_dsp_lp_on(ipc->dsp, false))
- return -EIO;
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait);
-
-int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request)
-{
- return ipc_tx_message(ipc, request, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait);
-
-int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request, struct sst_ipc_message *reply)
-{
- return ipc_tx_message(ipc, request, reply, 1);
-}
-EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm);
-
-struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
- u64 header)
-{
- struct ipc_message *msg;
- u64 mask;
-
- if (ipc->ops.reply_msg_match != NULL)
- header = ipc->ops.reply_msg_match(header, &mask);
- else
- mask = (u64)-1;
-
- if (list_empty(&ipc->rx_list)) {
- dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n",
- header);
- return NULL;
- }
-
- list_for_each_entry(msg, &ipc->rx_list, list) {
- if ((msg->tx.header & mask) == header)
- return msg;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg);
-
-/* locks held by caller */
-void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc,
- struct ipc_message *msg)
-{
- msg->complete = true;
-
- if (!msg->wait)
- list_add_tail(&msg->list, &ipc->empty_list);
- else
- wake_up(&msg->waitq);
-}
-EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete);
-
-int sst_ipc_init(struct sst_generic_ipc *ipc)
-{
- int ret;
-
- INIT_LIST_HEAD(&ipc->tx_list);
- INIT_LIST_HEAD(&ipc->rx_list);
- INIT_LIST_HEAD(&ipc->empty_list);
- init_waitqueue_head(&ipc->wait_txq);
-
- ret = msg_empty_list_init(ipc);
- if (ret < 0)
- return -ENOMEM;
-
- INIT_WORK(&ipc->kwork, ipc_tx_msgs);
- return 0;
-}
-EXPORT_SYMBOL_GPL(sst_ipc_init);
-
-void sst_ipc_fini(struct sst_generic_ipc *ipc)
-{
- int i;
-
- cancel_work_sync(&ipc->kwork);
-
- if (ipc->msg) {
- for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
- kfree(ipc->msg[i].tx.data);
- kfree(ipc->msg[i].rx.data);
- }
- kfree(ipc->msg);
- }
-}
-EXPORT_SYMBOL_GPL(sst_ipc_fini);
-
-/* Module information */
-MODULE_AUTHOR("Jin Yao");
-MODULE_DESCRIPTION("Intel SST IPC generic");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h
deleted file mode 100644
index 77d651e888f9..000000000000
--- a/sound/soc/intel/common/sst-ipc.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel SST generic IPC Support
- *
- * Copyright (C) 2015, Intel Corporation. All rights reserved.
- */
-
-#ifndef __SST_GENERIC_IPC_H
-#define __SST_GENERIC_IPC_H
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-
-struct sst_ipc_message {
- u64 header;
- void *data;
- size_t size;
-};
-
-struct ipc_message {
- struct list_head list;
- struct sst_ipc_message tx;
- struct sst_ipc_message rx;
-
- wait_queue_head_t waitq;
- bool pending;
- bool complete;
- bool wait;
- int errno;
-};
-
-struct sst_generic_ipc;
-struct sst_dsp;
-
-struct sst_plat_ipc_ops {
- void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *);
- void (*shim_dbg)(struct sst_generic_ipc *, const char *);
- void (*tx_data_copy)(struct ipc_message *, char *, size_t);
- u64 (*reply_msg_match)(u64 header, u64 *mask);
- bool (*is_dsp_busy)(struct sst_dsp *dsp);
- int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state);
-};
-
-/* SST generic IPC data */
-struct sst_generic_ipc {
- struct device *dev;
- struct sst_dsp *dsp;
-
- /* IPC messaging */
- struct list_head tx_list;
- struct list_head rx_list;
- struct list_head empty_list;
- wait_queue_head_t wait_txq;
- struct task_struct *tx_thread;
- struct work_struct kwork;
- bool pending;
- struct ipc_message *msg;
- int tx_data_max_size;
- int rx_data_max_size;
-
- struct sst_plat_ipc_ops ops;
-};
-
-int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request, struct sst_ipc_message *reply);
-
-int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request);
-
-int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc,
- struct sst_ipc_message request, struct sst_ipc_message *reply);
-
-struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
- u64 header);
-
-void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc,
- struct ipc_message *msg);
-
-int sst_ipc_init(struct sst_generic_ipc *ipc);
-void sst_ipc_fini(struct sst_generic_ipc *ipc);
-
-#endif
diff --git a/sound/soc/intel/keembay/Makefile b/sound/soc/intel/keembay/Makefile
index 9084e8c63854..3da9a6f9ba2a 100644
--- a/sound/soc/intel/keembay/Makefile
+++ b/sound/soc/intel/keembay/Makefile
@@ -1,4 +1,4 @@
-snd-soc-kmb_platform-objs := \
+snd-soc-kmb_platform-y := \
kmb_platform.o
obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += snd-soc-kmb_platform.o
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index b4893365d01d..4ed71d11ad77 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -11,7 +11,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -252,10 +251,10 @@ static int kmb_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct kmb_i2s_info *kmb_i2s;
- kmb_i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ kmb_i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
snd_soc_set_runtime_hwparams(substream, &kmb_pcm_hardware);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
runtime->private_data = kmb_i2s;
@@ -733,6 +732,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops kmb_dai_ops = {
+ .probe = kmb_probe,
.startup = kmb_dai_startup,
.trigger = kmb_dai_trigger,
.hw_params = kmb_dai_hw_params,
@@ -755,7 +755,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
},
.ops = &kmb_dai_ops,
- .probe = kmb_probe,
},
};
@@ -787,7 +786,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
SNDRV_PCM_FMTBIT_S16_LE),
},
.ops = &kmb_dai_ops,
- .probe = kmb_probe,
},
};
@@ -807,7 +805,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S16_LE),
},
.ops = &kmb_dai_ops,
- .probe = kmb_probe,
},
};
@@ -817,12 +814,12 @@ static const struct of_device_id kmb_plat_of_match[] = {
{ .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai},
{}
};
+MODULE_DEVICE_TABLE(of, kmb_plat_of_match);
static int kmb_plat_dai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct snd_soc_dai_driver *kmb_i2s_dai;
- const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct kmb_i2s_info *kmb_i2s;
struct resource *res;
@@ -833,16 +830,7 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
if (!kmb_i2s)
return -ENOMEM;
- kmb_i2s_dai = devm_kzalloc(dev, sizeof(*kmb_i2s_dai), GFP_KERNEL);
- if (!kmb_i2s_dai)
- return -ENOMEM;
-
- match = of_match_device(kmb_plat_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Error: No device match found\n");
- return -ENODEV;
- }
- kmb_i2s_dai = (struct snd_soc_dai_driver *) match->data;
+ kmb_i2s_dai = (struct snd_soc_dai_driver *)device_get_match_data(&pdev->dev);
/* Prepare the related clocks */
kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk");
@@ -881,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/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile
deleted file mode 100644
index 1c4649bccec5..000000000000
--- a/sound/soc/intel/skylake/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o skl-topology.o \
- skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o skl-sst-cldma.o \
- skl-sst.o bxt-sst.o cnl-sst.o skl-sst-utils.o
-
-ifdef CONFIG_DEBUG_FS
- snd-soc-skl-objs += skl-debug.o
-endif
-
-obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += snd-soc-skl.o
-
-#Skylake Clock device support
-snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o
-
-obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK) += snd-soc-skl-ssp-clk.o
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
deleted file mode 100644
index fd4fdcb95224..000000000000
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ /dev/null
@@ -1,629 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * bxt-sst.c - DSP library functions for BXT platform
- *
- * Copyright (C) 2015-16 Intel Corp
- * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
- * Jeeja KP <jeeja.kp@intel.com>
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/device.h>
-
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-#include "skl.h"
-
-#define BXT_BASEFW_TIMEOUT 3000
-#define BXT_ROM_INIT_TIMEOUT 70
-#define BXT_IPC_PURGE_FW 0x01004000
-
-#define BXT_ROM_INIT 0x5
-#define BXT_ADSP_SRAM0_BASE 0x80000
-
-/* Firmware status window */
-#define BXT_ADSP_FW_STATUS BXT_ADSP_SRAM0_BASE
-#define BXT_ADSP_ERROR_CODE (BXT_ADSP_FW_STATUS + 0x4)
-
-#define BXT_ADSP_SRAM1_BASE 0xA0000
-
-#define BXT_INSTANCE_ID 0
-#define BXT_BASE_FW_MODULE_ID 0
-
-#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
-
-/* Delay before scheduling D0i3 entry */
-#define BXT_D0I3_DELAY 5000
-
-static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
-{
- return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
-}
-
-static int
-bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
-{
- struct snd_dma_buffer dmab;
- struct skl_dev *skl = ctx->thread_context;
- struct firmware stripped_fw;
- int ret = 0, i, dma_id, stream_tag;
-
- /* library indices start from 1 to N. 0 represents base FW */
- for (i = 1; i < lib_count; i++) {
- ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw,
- BXT_ADSP_FW_BIN_HDR_OFFSET, i);
- if (ret < 0)
- goto load_library_failed;
-
- stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40,
- stripped_fw.size, &dmab);
- if (stream_tag <= 0) {
- dev_err(ctx->dev, "Lib prepare DMA err: %x\n",
- stream_tag);
- ret = stream_tag;
- goto load_library_failed;
- }
-
- dma_id = stream_tag - 1;
- memcpy(dmab.area, stripped_fw.data, stripped_fw.size);
-
- ctx->dsp_ops.trigger(ctx->dev, true, stream_tag);
- ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i, true);
- if (ret < 0)
- dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n",
- linfo[i].name, ret);
-
- ctx->dsp_ops.trigger(ctx->dev, false, stream_tag);
- ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag);
- }
-
- return ret;
-
-load_library_failed:
- skl_release_library(linfo, lib_count);
- return ret;
-}
-
-/*
- * First boot sequence has some extra steps. Core 0 waits for power
- * status on core 1, so power up core 1 also momentarily, keep it in
- * reset/stall and then turn it off
- */
-static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
- const void *fwdata, u32 fwsize)
-{
- int stream_tag, ret;
-
- stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
- if (stream_tag <= 0) {
- dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n",
- stream_tag);
- return stream_tag;
- }
-
- ctx->dsp_ops.stream_tag = stream_tag;
- memcpy(ctx->dmab.area, fwdata, fwsize);
-
- /* Step 1: Power up core 0 and core1 */
- ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK |
- SKL_DSP_CORE_MASK(1));
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core0/1 power up failed\n");
- goto base_fw_load_failed;
- }
-
- /* Step 2: Purge FW request */
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY |
- (BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9)));
-
- /* Step 3: Unset core0 reset state & unstall/run core0 */
- ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
- if (ret < 0) {
- dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret);
- ret = -EIO;
- goto base_fw_load_failed;
- }
-
- /* Step 4: Wait for DONE Bit */
- ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE,
- SKL_ADSP_REG_HIPCIE_DONE,
- SKL_ADSP_REG_HIPCIE_DONE,
- BXT_INIT_TIMEOUT, "HIPCIE Done");
- if (ret < 0) {
- dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret);
- goto base_fw_load_failed;
- }
-
- /* Step 5: power down core1 */
- ret = skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core1 power down failed\n");
- goto base_fw_load_failed;
- }
-
- /* Step 6: Enable Interrupt */
- skl_ipc_int_enable(ctx);
- skl_ipc_op_int_enable(ctx);
-
- /* Step 7: Wait for ROM init */
- ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
- SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load");
- if (ret < 0) {
- dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret);
- goto base_fw_load_failed;
- }
-
- return ret;
-
-base_fw_load_failed:
- ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
- skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
- skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- return ret;
-}
-
-static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
-{
- int ret;
-
- ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
- ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
- BXT_ROM_INIT, BXT_BASEFW_TIMEOUT, "Firmware boot");
-
- ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
- ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
-
- return ret;
-}
-
-static int bxt_load_base_firmware(struct sst_dsp *ctx)
-{
- struct firmware stripped_fw;
- struct skl_dev *skl = ctx->thread_context;
- int ret, i;
-
- if (ctx->fw == NULL) {
- ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
- if (ret < 0) {
- dev_err(ctx->dev, "Request firmware failed %d\n", ret);
- return ret;
- }
- }
-
- /* prase uuids on first boot */
- if (skl->is_first_boot) {
- ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0);
- if (ret < 0)
- goto sst_load_base_firmware_failed;
- }
-
- stripped_fw.data = ctx->fw->data;
- stripped_fw.size = ctx->fw->size;
- skl_dsp_strip_extended_manifest(&stripped_fw);
-
-
- for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) {
- ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
- if (ret == 0)
- break;
- }
-
- if (ret < 0) {
- dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
- sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
- sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
-
- dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
- goto sst_load_base_firmware_failed;
- }
-
- ret = sst_transfer_fw_host_dma(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "Transfer firmware failed %d\n", ret);
- dev_info(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
- sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
- sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
-
- skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- } else {
- dev_dbg(ctx->dev, "Firmware download successful\n");
- ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
- msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
- if (ret == 0) {
- dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n");
- skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- ret = -EIO;
- } else {
- ret = 0;
- skl->fw_loaded = true;
- }
- }
-
- return ret;
-
-sst_load_base_firmware_failed:
- release_firmware(ctx->fw);
- ctx->fw = NULL;
- return ret;
-}
-
-/*
- * Decide the D0i3 state that can be targeted based on the usecase
- * ref counts and DSP state
- *
- * Decision Matrix: (X= dont care; state = target state)
- *
- * DSP state != SKL_DSP_RUNNING ; state = no d0i3
- *
- * DSP state == SKL_DSP_RUNNING , the following matrix applies
- * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3
- * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3
- * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3
- * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3
- */
-static int bxt_d0i3_target_state(struct sst_dsp *ctx)
-{
- struct skl_dev *skl = ctx->thread_context;
- struct skl_d0i3_data *d0i3 = &skl->d0i3;
-
- if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING)
- return SKL_DSP_D0I3_NONE;
-
- if (d0i3->non_d0i3)
- return SKL_DSP_D0I3_NONE;
- else if (d0i3->streaming)
- return SKL_DSP_D0I3_STREAMING;
- else if (d0i3->non_streaming)
- return SKL_DSP_D0I3_NON_STREAMING;
- else
- return SKL_DSP_D0I3_NONE;
-}
-
-static void bxt_set_dsp_D0i3(struct work_struct *work)
-{
- int ret;
- struct skl_ipc_d0ix_msg msg;
- struct skl_dev *skl = container_of(work,
- struct skl_dev, d0i3.work.work);
- struct sst_dsp *ctx = skl->dsp;
- struct skl_d0i3_data *d0i3 = &skl->d0i3;
- int target_state;
-
- dev_dbg(ctx->dev, "In %s:\n", __func__);
-
- /* D0i3 entry allowed only if core 0 alone is running */
- if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) {
- dev_warn(ctx->dev,
- "D0i3 allowed when only core0 running:Exit\n");
- return;
- }
-
- target_state = bxt_d0i3_target_state(ctx);
- if (target_state == SKL_DSP_D0I3_NONE)
- return;
-
- msg.instance_id = 0;
- msg.module_id = 0;
- msg.wake = 1;
- msg.streaming = 0;
- if (target_state == SKL_DSP_D0I3_STREAMING)
- msg.streaming = 1;
-
- ret = skl_ipc_set_d0ix(&skl->ipc, &msg);
-
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n");
- return;
- }
-
- /* Set Vendor specific register D0I3C.I3 to enable D0i3*/
- if (skl->update_d0i3c)
- skl->update_d0i3c(skl->dev, true);
-
- d0i3->state = target_state;
- skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3;
-}
-
-static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx)
-{
- struct skl_dev *skl = ctx->thread_context;
- struct skl_d0i3_data *d0i3 = &skl->d0i3;
-
- /* Schedule D0i3 only if the usecase ref counts are appropriate */
- if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) {
-
- dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__);
-
- schedule_delayed_work(&d0i3->work,
- msecs_to_jiffies(BXT_D0I3_DELAY));
- }
-
- return 0;
-}
-
-static int bxt_set_dsp_D0i0(struct sst_dsp *ctx)
-{
- int ret;
- struct skl_ipc_d0ix_msg msg;
- struct skl_dev *skl = ctx->thread_context;
-
- dev_dbg(ctx->dev, "In %s:\n", __func__);
-
- /* First Cancel any pending attempt to put DSP to D0i3 */
- cancel_delayed_work_sync(&skl->d0i3.work);
-
- /* If DSP is currently in D0i3, bring it to D0i0 */
- if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3)
- return 0;
-
- dev_dbg(ctx->dev, "Set DSP to D0i0\n");
-
- msg.instance_id = 0;
- msg.module_id = 0;
- msg.streaming = 0;
- msg.wake = 0;
-
- if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING)
- msg.streaming = 1;
-
- /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/
- if (skl->update_d0i3c)
- skl->update_d0i3c(skl->dev, false);
-
- ret = skl_ipc_set_d0ix(&skl->ipc, &msg);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to set DSP to D0i0\n");
- return ret;
- }
-
- skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
- skl->d0i3.state = SKL_DSP_D0I3_NONE;
-
- return 0;
-}
-
-static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
-{
- struct skl_dev *skl = ctx->thread_context;
- int ret;
- struct skl_ipc_dxstate_info dx;
- unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
-
- if (skl->fw_loaded == false) {
- skl->boot_complete = false;
- ret = bxt_load_base_firmware(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "reload fw failed: %d\n", ret);
- return ret;
- }
-
- if (skl->lib_count > 1) {
- ret = bxt_load_library(ctx, skl->lib_info,
- skl->lib_count);
- if (ret < 0) {
- dev_err(ctx->dev, "reload libs failed: %d\n", ret);
- return ret;
- }
- }
- skl->cores.state[core_id] = SKL_DSP_RUNNING;
- return ret;
- }
-
- /* If core 0 is being turned on, turn on core 1 as well */
- if (core_id == SKL_DSP_CORE0_ID)
- ret = skl_dsp_core_power_up(ctx, core_mask |
- SKL_DSP_CORE_MASK(1));
- else
- ret = skl_dsp_core_power_up(ctx, core_mask);
-
- if (ret < 0)
- goto err;
-
- if (core_id == SKL_DSP_CORE0_ID) {
-
- /*
- * Enable interrupt after SPA is set and before
- * DSP is unstalled
- */
- skl_ipc_int_enable(ctx);
- skl_ipc_op_int_enable(ctx);
- skl->boot_complete = false;
- }
-
- ret = skl_dsp_start_core(ctx, core_mask);
- if (ret < 0)
- goto err;
-
- if (core_id == SKL_DSP_CORE0_ID) {
- ret = wait_event_timeout(skl->boot_wait,
- skl->boot_complete,
- msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
-
- /* If core 1 was turned on for booting core 0, turn it off */
- skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
- if (ret == 0) {
- dev_err(ctx->dev, "%s: DSP boot timeout\n", __func__);
- dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
- sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
- sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
- dev_err(ctx->dev, "Failed to set core0 to D0 state\n");
- ret = -EIO;
- goto err;
- }
- }
-
- /* Tell FW if additional core in now On */
-
- if (core_id != SKL_DSP_CORE0_ID) {
- dx.core_mask = core_mask;
- dx.dx_mask = core_mask;
-
- ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
- BXT_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev, "IPC set_dx for core %d fail: %d\n",
- core_id, ret);
- goto err;
- }
- }
-
- skl->cores.state[core_id] = SKL_DSP_RUNNING;
- return 0;
-err:
- if (core_id == SKL_DSP_CORE0_ID)
- core_mask |= SKL_DSP_CORE_MASK(1);
- skl_dsp_disable_core(ctx, core_mask);
-
- return ret;
-}
-
-static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
-{
- int ret;
- struct skl_ipc_dxstate_info dx;
- struct skl_dev *skl = ctx->thread_context;
- unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
-
- dx.core_mask = core_mask;
- dx.dx_mask = SKL_IPC_D3_MASK;
-
- dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n",
- dx.core_mask, dx.dx_mask);
-
- ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
- BXT_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev,
- "Failed to set DSP to D3:core id = %d;Continue reset\n",
- core_id);
- /*
- * In case of D3 failure, re-download the firmware, so set
- * fw_loaded to false.
- */
- skl->fw_loaded = false;
- }
-
- if (core_id == SKL_DSP_CORE0_ID) {
- /* disable Interrupt */
- skl_ipc_op_int_disable(ctx);
- skl_ipc_int_disable(ctx);
- }
- ret = skl_dsp_disable_core(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to disable core %d\n", ret);
- return ret;
- }
- skl->cores.state[core_id] = SKL_DSP_RESET;
- return 0;
-}
-
-static const struct skl_dsp_fw_ops bxt_fw_ops = {
- .set_state_D0 = bxt_set_dsp_D0,
- .set_state_D3 = bxt_set_dsp_D3,
- .set_state_D0i3 = bxt_schedule_dsp_D0i3,
- .set_state_D0i0 = bxt_set_dsp_D0i0,
- .load_fw = bxt_load_base_firmware,
- .get_fw_errcode = bxt_get_errorcode,
- .load_library = bxt_load_library,
-};
-
-static struct sst_ops skl_ops = {
- .irq_handler = skl_dsp_sst_interrupt,
- .write = sst_shim32_write,
- .read = sst_shim32_read,
- .free = skl_dsp_free,
-};
-
-static struct sst_dsp_device skl_dev = {
- .thread = skl_dsp_irq_thread_handler,
- .ops = &skl_ops,
-};
-
-int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
- struct skl_dev **dsp)
-{
- struct skl_dev *skl;
- struct sst_dsp *sst;
- int ret;
-
- ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
- if (ret < 0) {
- dev_err(dev, "%s: no device\n", __func__);
- return ret;
- }
-
- skl = *dsp;
- sst = skl->dsp;
- sst->fw_ops = bxt_fw_ops;
- sst->addr.lpe = mmio_base;
- sst->addr.shim = mmio_base;
- sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE;
- sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE;
- sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
- sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
-
- sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
- SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
-
- ret = skl_ipc_init(dev, skl);
- if (ret) {
- skl_dsp_free(sst);
- return ret;
- }
-
- /* set the D0i3 check */
- skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
-
- skl->boot_complete = false;
- init_waitqueue_head(&skl->boot_wait);
- INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
- skl->d0i3.state = SKL_DSP_D0I3_NONE;
-
- return skl_dsp_acquire_irq(sst);
-}
-EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
-
-int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl)
-{
- int ret;
- struct sst_dsp *sst = skl->dsp;
-
- ret = sst->fw_ops.load_fw(sst);
- if (ret < 0) {
- dev_err(dev, "Load base fw failed: %x\n", ret);
- return ret;
- }
-
- skl_dsp_init_core_state(sst);
-
- if (skl->lib_count > 1) {
- ret = sst->fw_ops.load_library(sst, skl->lib_info,
- skl->lib_count);
- if (ret < 0) {
- dev_err(dev, "Load Library failed : %x\n", ret);
- return ret;
- }
- }
- skl->is_first_boot = false;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(bxt_sst_init_fw);
-
-void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl)
-{
-
- skl_release_library(skl->lib_info, skl->lib_count);
- if (skl->dsp->fw)
- release_firmware(skl->dsp->fw);
- skl_freeup_uuid_list(skl);
- skl_ipc_free(&skl->ipc);
- skl->dsp->ops->free(skl->dsp);
-}
-EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Broxton IPC driver");
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c
deleted file mode 100644
index 3ef1b194add1..000000000000
--- a/sound/soc/intel/skylake/cnl-sst-dsp.c
+++ /dev/null
@@ -1,266 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cnl-sst-dsp.c - CNL SST library generic function
- *
- * Copyright (C) 2016-17, Intel Corporation.
- * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
- *
- * Modified from:
- * SKL SST library generic function
- * Copyright (C) 2014-15, Intel Corporation.
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/device.h>
-#include "../common/sst-dsp.h"
-#include "../common/sst-ipc.h"
-#include "../common/sst-dsp-priv.h"
-#include "cnl-sst-dsp.h"
-
-/* various timeout values */
-#define CNL_DSP_PU_TO 50
-#define CNL_DSP_PD_TO 50
-#define CNL_DSP_RESET_TO 50
-
-static int
-cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx,
- CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
- CNL_ADSPCS_CRST(core_mask));
-
- /* poll with timeout to check if operation successful */
- return sst_dsp_register_poll(ctx,
- CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CRST(core_mask),
- CNL_ADSPCS_CRST(core_mask),
- CNL_DSP_RESET_TO,
- "Set reset");
-}
-
-static int
-cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CRST(core_mask), 0);
-
- /* poll with timeout to check if operation successful */
- return sst_dsp_register_poll(ctx,
- CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CRST(core_mask),
- 0,
- CNL_DSP_RESET_TO,
- "Unset reset");
-}
-
-static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int val;
- bool is_enable;
-
- val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
-
- is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
- (val & CNL_ADSPCS_SPA(core_mask)) &&
- !(val & CNL_ADSPCS_CRST(core_mask)) &&
- !(val & CNL_ADSPCS_CSTALL(core_mask));
-
- dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
- is_enable, core_mask);
-
- return is_enable;
-}
-
-static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* stall core */
- sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CSTALL(core_mask),
- CNL_ADSPCS_CSTALL(core_mask));
-
- /* set reset state */
- return cnl_dsp_core_set_reset_state(ctx, core_mask);
-}
-
-static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- /* unset reset state */
- ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
- if (ret < 0)
- return ret;
-
- /* run core */
- sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CSTALL(core_mask), 0);
-
- if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
- cnl_dsp_reset_core(ctx, core_mask);
- dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
- core_mask);
- ret = -EIO;
- }
-
- return ret;
-}
-
-static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_SPA(core_mask),
- CNL_ADSPCS_SPA(core_mask));
-
- /* poll with timeout to check if operation successful */
- return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CPA(core_mask),
- CNL_ADSPCS_CPA(core_mask),
- CNL_DSP_PU_TO,
- "Power up");
-}
-
-static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_SPA(core_mask), 0);
-
- /* poll with timeout to check if operation successful */
- return sst_dsp_register_poll(ctx,
- CNL_ADSP_REG_ADSPCS,
- CNL_ADSPCS_CPA(core_mask),
- 0,
- CNL_DSP_PD_TO,
- "Power down");
-}
-
-int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- /* power up */
- ret = cnl_dsp_core_power_up(ctx, core_mask);
- if (ret < 0) {
- dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
- core_mask);
- return ret;
- }
-
- return cnl_dsp_start_core(ctx, core_mask);
-}
-
-int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- ret = cnl_dsp_reset_core(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
- core_mask);
- return ret;
- }
-
- /* power down core*/
- ret = cnl_dsp_core_power_down(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
- core_mask);
- return ret;
- }
-
- if (is_cnl_dsp_core_enable(ctx, core_mask)) {
- dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
- core_mask);
- ret = -EIO;
- }
-
- return ret;
-}
-
-irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
-{
- struct sst_dsp *ctx = dev_id;
- u32 val;
- irqreturn_t ret = IRQ_NONE;
-
- spin_lock(&ctx->spinlock);
-
- val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
- ctx->intr_status = val;
-
- if (val == 0xffffffff) {
- spin_unlock(&ctx->spinlock);
- return IRQ_NONE;
- }
-
- if (val & CNL_ADSPIS_IPC) {
- cnl_ipc_int_disable(ctx);
- ret = IRQ_WAKE_THREAD;
- }
-
- spin_unlock(&ctx->spinlock);
-
- return ret;
-}
-
-void cnl_dsp_free(struct sst_dsp *dsp)
-{
- cnl_ipc_int_disable(dsp);
-
- free_irq(dsp->irq, dsp);
- cnl_ipc_op_int_disable(dsp);
- cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
-}
-EXPORT_SYMBOL_GPL(cnl_dsp_free);
-
-void cnl_ipc_int_enable(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
- CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
-}
-
-void cnl_ipc_int_disable(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
- CNL_ADSPIC_IPC, 0);
-}
-
-void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
-{
- /* enable IPC DONE interrupt */
- sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
- CNL_ADSP_REG_HIPCCTL_DONE,
- CNL_ADSP_REG_HIPCCTL_DONE);
-
- /* enable IPC BUSY interrupt */
- sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
- CNL_ADSP_REG_HIPCCTL_BUSY,
- CNL_ADSP_REG_HIPCCTL_BUSY);
-}
-
-void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
-{
- /* disable IPC DONE interrupt */
- sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
- CNL_ADSP_REG_HIPCCTL_DONE, 0);
-
- /* disable IPC BUSY interrupt */
- sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
- CNL_ADSP_REG_HIPCCTL_BUSY, 0);
-}
-
-bool cnl_ipc_int_status(struct sst_dsp *ctx)
-{
- return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
- CNL_ADSPIS_IPC;
-}
-
-void cnl_ipc_free(struct sst_generic_ipc *ipc)
-{
- cnl_ipc_op_int_disable(ipc->dsp);
- sst_ipc_fini(ipc);
-}
diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h
deleted file mode 100644
index d3cf4bd1a070..000000000000
--- a/sound/soc/intel/skylake/cnl-sst-dsp.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Cannonlake SST DSP Support
- *
- * Copyright (C) 2016-17, Intel Corporation.
- */
-
-#ifndef __CNL_SST_DSP_H__
-#define __CNL_SST_DSP_H__
-
-struct sst_dsp;
-struct sst_dsp_device;
-struct sst_generic_ipc;
-
-/* Intel HD Audio General DSP Registers */
-#define CNL_ADSP_GEN_BASE 0x0
-#define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04)
-#define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08)
-#define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c)
-
-/* Intel HD Audio Inter-Processor Communication Registers */
-#define CNL_ADSP_IPC_BASE 0xc0
-#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00)
-#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04)
-#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08)
-#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10)
-#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14)
-#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18)
-#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28)
-
-/* HIPCTDR */
-#define CNL_ADSP_REG_HIPCTDR_BUSY BIT(31)
-
-/* HIPCTDA */
-#define CNL_ADSP_REG_HIPCTDA_DONE BIT(31)
-
-/* HIPCIDR */
-#define CNL_ADSP_REG_HIPCIDR_BUSY BIT(31)
-
-/* HIPCIDA */
-#define CNL_ADSP_REG_HIPCIDA_DONE BIT(31)
-
-/* CNL HIPCCTL */
-#define CNL_ADSP_REG_HIPCCTL_DONE BIT(1)
-#define CNL_ADSP_REG_HIPCCTL_BUSY BIT(0)
-
-/* CNL HIPCT */
-#define CNL_ADSP_REG_HIPCT_BUSY BIT(31)
-
-/* Intel HD Audio SRAM Window 1 */
-#define CNL_ADSP_SRAM1_BASE 0xa0000
-
-#define CNL_ADSP_MMIO_LEN 0x10000
-
-#define CNL_ADSP_W0_STAT_SZ 0x1000
-
-#define CNL_ADSP_W0_UP_SZ 0x1000
-
-#define CNL_ADSP_W1_SZ 0x1000
-
-#define CNL_FW_STS_MASK 0xf
-
-#define CNL_ADSPIC_IPC 0x1
-#define CNL_ADSPIS_IPC 0x1
-
-#define CNL_DSP_CORES 4
-#define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1)
-
-/* core reset - asserted high */
-#define CNL_ADSPCS_CRST_SHIFT 0
-#define CNL_ADSPCS_CRST(x) (x << CNL_ADSPCS_CRST_SHIFT)
-
-/* core run/stall - when set to 1 core is stalled */
-#define CNL_ADSPCS_CSTALL_SHIFT 8
-#define CNL_ADSPCS_CSTALL(x) (x << CNL_ADSPCS_CSTALL_SHIFT)
-
-/* set power active - when set to 1 turn core on */
-#define CNL_ADSPCS_SPA_SHIFT 16
-#define CNL_ADSPCS_SPA(x) (x << CNL_ADSPCS_SPA_SHIFT)
-
-/* current power active - power status of cores, set by hardware */
-#define CNL_ADSPCS_CPA_SHIFT 24
-#define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT)
-
-int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask);
-int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask);
-irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id);
-void cnl_dsp_free(struct sst_dsp *dsp);
-
-void cnl_ipc_int_enable(struct sst_dsp *ctx);
-void cnl_ipc_int_disable(struct sst_dsp *ctx);
-void cnl_ipc_op_int_enable(struct sst_dsp *ctx);
-void cnl_ipc_op_int_disable(struct sst_dsp *ctx);
-bool cnl_ipc_int_status(struct sst_dsp *ctx);
-void cnl_ipc_free(struct sst_generic_ipc *ipc);
-
-int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
- struct skl_dev **dsp);
-int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl);
-void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl);
-
-#endif /*__CNL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
deleted file mode 100644
index 1275c149acc0..000000000000
--- a/sound/soc/intel/skylake/cnl-sst.c
+++ /dev/null
@@ -1,508 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cnl-sst.c - DSP library functions for CNL platform
- *
- * Copyright (C) 2016-17, Intel Corporation.
- *
- * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
- *
- * Modified from:
- * HDA DSP library functions for SKL platform
- * Copyright (C) 2014-15, Intel Corporation.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/device.h>
-
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-#include "../common/sst-ipc.h"
-#include "cnl-sst-dsp.h"
-#include "skl.h"
-
-#define CNL_FW_ROM_INIT 0x1
-#define CNL_FW_INIT 0x5
-#define CNL_IPC_PURGE 0x01004000
-#define CNL_INIT_TIMEOUT 300
-#define CNL_BASEFW_TIMEOUT 3000
-
-#define CNL_ADSP_SRAM0_BASE 0x80000
-
-/* Firmware status window */
-#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE
-#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4)
-
-#define CNL_INSTANCE_ID 0
-#define CNL_BASE_FW_MODULE_ID 0
-#define CNL_ADSP_FW_HDR_OFFSET 0x2000
-#define CNL_ROM_CTRL_DMA_ID 0x9
-
-static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize)
-{
-
- int ret, stream_tag;
-
- stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
- if (stream_tag <= 0) {
- dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag);
- return stream_tag;
- }
-
- ctx->dsp_ops.stream_tag = stream_tag;
- memcpy(ctx->dmab.area, fwdata, fwsize);
-
- ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core0 power up failed\n");
- ret = -EIO;
- goto base_fw_load_failed;
- }
-
- /* purge FW request */
- sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR,
- CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE |
- ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID)));
-
- ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
- if (ret < 0) {
- dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret);
- ret = -EIO;
- goto base_fw_load_failed;
- }
-
- ret = sst_dsp_register_poll(ctx, CNL_ADSP_REG_HIPCIDA,
- CNL_ADSP_REG_HIPCIDA_DONE,
- CNL_ADSP_REG_HIPCIDA_DONE,
- BXT_INIT_TIMEOUT, "HIPCIDA Done");
- if (ret < 0) {
- dev_err(ctx->dev, "timeout for purge request: %d\n", ret);
- goto base_fw_load_failed;
- }
-
- /* enable interrupt */
- cnl_ipc_int_enable(ctx);
- cnl_ipc_op_int_enable(ctx);
-
- ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
- CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT,
- "rom load");
- if (ret < 0) {
- dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret);
- goto base_fw_load_failed;
- }
-
- return 0;
-
-base_fw_load_failed:
- ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
- cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
-
- return ret;
-}
-
-static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
-{
- int ret;
-
- ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
- ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
- CNL_FW_INIT, CNL_BASEFW_TIMEOUT,
- "firmware boot");
-
- ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
- ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
-
- return ret;
-}
-
-static int cnl_load_base_firmware(struct sst_dsp *ctx)
-{
- struct firmware stripped_fw;
- struct skl_dev *cnl = ctx->thread_context;
- int ret, i;
-
- if (!ctx->fw) {
- ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
- if (ret < 0) {
- dev_err(ctx->dev, "request firmware failed: %d\n", ret);
- goto cnl_load_base_firmware_failed;
- }
- }
-
- /* parse uuids if first boot */
- if (cnl->is_first_boot) {
- ret = snd_skl_parse_uuids(ctx, ctx->fw,
- CNL_ADSP_FW_HDR_OFFSET, 0);
- if (ret < 0)
- goto cnl_load_base_firmware_failed;
- }
-
- stripped_fw.data = ctx->fw->data;
- stripped_fw.size = ctx->fw->size;
- skl_dsp_strip_extended_manifest(&stripped_fw);
-
- for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) {
- ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
- if (!ret)
- break;
- dev_dbg(ctx->dev, "prepare firmware failed: %d\n", ret);
- }
-
- if (ret < 0)
- goto cnl_load_base_firmware_failed;
-
- ret = sst_transfer_fw_host_dma(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "transfer firmware failed: %d\n", ret);
- cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- goto cnl_load_base_firmware_failed;
- }
-
- ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
- msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
- if (ret == 0) {
- dev_err(ctx->dev, "FW ready timed-out\n");
- cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- ret = -EIO;
- goto cnl_load_base_firmware_failed;
- }
-
- cnl->fw_loaded = true;
-
- return 0;
-
-cnl_load_base_firmware_failed:
- dev_err(ctx->dev, "firmware load failed: %d\n", ret);
- release_firmware(ctx->fw);
- ctx->fw = NULL;
-
- return ret;
-}
-
-static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
-{
- struct skl_dev *cnl = ctx->thread_context;
- unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
- struct skl_ipc_dxstate_info dx;
- int ret;
-
- if (!cnl->fw_loaded) {
- cnl->boot_complete = false;
- ret = cnl_load_base_firmware(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "fw reload failed: %d\n", ret);
- return ret;
- }
-
- cnl->cores.state[core_id] = SKL_DSP_RUNNING;
- return ret;
- }
-
- ret = cnl_dsp_enable_core(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "enable dsp core %d failed: %d\n",
- core_id, ret);
- goto err;
- }
-
- if (core_id == SKL_DSP_CORE0_ID) {
- /* enable interrupt */
- cnl_ipc_int_enable(ctx);
- cnl_ipc_op_int_enable(ctx);
- cnl->boot_complete = false;
-
- ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
- msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
- if (ret == 0) {
- dev_err(ctx->dev,
- "dsp boot timeout, status=%#x error=%#x\n",
- sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
- sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
- ret = -ETIMEDOUT;
- goto err;
- }
- } else {
- dx.core_mask = core_mask;
- dx.dx_mask = core_mask;
-
- ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
- CNL_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n",
- core_id, ret);
- goto err;
- }
- }
- cnl->cores.state[core_id] = SKL_DSP_RUNNING;
-
- return 0;
-err:
- cnl_dsp_disable_core(ctx, core_mask);
-
- return ret;
-}
-
-static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
-{
- struct skl_dev *cnl = ctx->thread_context;
- unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
- struct skl_ipc_dxstate_info dx;
- int ret;
-
- dx.core_mask = core_mask;
- dx.dx_mask = SKL_IPC_D3_MASK;
-
- ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
- CNL_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev,
- "dsp core %d to d3 failed; continue reset\n",
- core_id);
- cnl->fw_loaded = false;
- }
-
- /* disable interrupts if core 0 */
- if (core_id == SKL_DSP_CORE0_ID) {
- skl_ipc_op_int_disable(ctx);
- skl_ipc_int_disable(ctx);
- }
-
- ret = cnl_dsp_disable_core(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "disable dsp core %d failed: %d\n",
- core_id, ret);
- return ret;
- }
-
- cnl->cores.state[core_id] = SKL_DSP_RESET;
-
- return ret;
-}
-
-static unsigned int cnl_get_errno(struct sst_dsp *ctx)
-{
- return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE);
-}
-
-static const struct skl_dsp_fw_ops cnl_fw_ops = {
- .set_state_D0 = cnl_set_dsp_D0,
- .set_state_D3 = cnl_set_dsp_D3,
- .load_fw = cnl_load_base_firmware,
- .get_fw_errcode = cnl_get_errno,
-};
-
-static struct sst_ops cnl_ops = {
- .irq_handler = cnl_dsp_sst_interrupt,
- .write = sst_shim32_write,
- .read = sst_shim32_read,
- .free = cnl_dsp_free,
-};
-
-#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29
-#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1
-#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \
- & CNL_IPC_GLB_NOTIFY_RSP_MASK)
-
-static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context)
-{
- struct sst_dsp *dsp = context;
- struct skl_dev *cnl = dsp->thread_context;
- struct sst_generic_ipc *ipc = &cnl->ipc;
- struct skl_ipc_header header = {0};
- u32 hipcida, hipctdr, hipctdd;
- int ipc_irq = 0;
-
- /* here we handle ipc interrupts only */
- if (!(dsp->intr_status & CNL_ADSPIS_IPC))
- return IRQ_NONE;
-
- hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA);
- hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR);
- hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD);
-
- /* reply message from dsp */
- if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) {
- sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
- CNL_ADSP_REG_HIPCCTL_DONE, 0);
-
- /* clear done bit - tell dsp operation is complete */
- sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA,
- CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE);
-
- ipc_irq = 1;
-
- /* unmask done interrupt */
- sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
- CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE);
- }
-
- /* new message from dsp */
- if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) {
- header.primary = hipctdr;
- header.extension = hipctdd;
- dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
- header.primary);
- dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
- header.extension);
-
- if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
- /* Handle Immediate reply from DSP Core */
- skl_ipc_process_reply(ipc, header);
- } else {
- dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
- skl_ipc_process_notification(ipc, header);
- }
- /* clear busy interrupt */
- sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR,
- CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY);
-
- /* set done bit to ack dsp */
- sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA,
- CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE);
- ipc_irq = 1;
- }
-
- if (ipc_irq == 0)
- return IRQ_NONE;
-
- cnl_ipc_int_enable(dsp);
-
- /* continue to send any remaining messages */
- schedule_work(&ipc->kwork);
-
- return IRQ_HANDLED;
-}
-
-static struct sst_dsp_device cnl_dev = {
- .thread = cnl_dsp_irq_thread_handler,
- .ops = &cnl_ops,
-};
-
-static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
-{
- struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header);
-
- if (msg->tx.size)
- sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size);
- sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD,
- header->extension);
- sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR,
- header->primary | CNL_ADSP_REG_HIPCIDR_BUSY);
-}
-
-static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp)
-{
- u32 hipcidr;
-
- hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR);
-
- return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY);
-}
-
-static int cnl_ipc_init(struct device *dev, struct skl_dev *cnl)
-{
- struct sst_generic_ipc *ipc;
- int err;
-
- ipc = &cnl->ipc;
- ipc->dsp = cnl->dsp;
- ipc->dev = dev;
-
- ipc->tx_data_max_size = CNL_ADSP_W1_SZ;
- ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ;
-
- err = sst_ipc_init(ipc);
- if (err)
- return err;
-
- /*
- * overriding tx_msg and is_dsp_busy since
- * ipc registers are different for cnl
- */
- ipc->ops.tx_msg = cnl_ipc_tx_msg;
- ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
- ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy;
-
- return 0;
-}
-
-int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
- struct skl_dev **dsp)
-{
- struct skl_dev *cnl;
- struct sst_dsp *sst;
- int ret;
-
- ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev);
- if (ret < 0) {
- dev_err(dev, "%s: no device\n", __func__);
- return ret;
- }
-
- cnl = *dsp;
- sst = cnl->dsp;
- sst->fw_ops = cnl_fw_ops;
- sst->addr.lpe = mmio_base;
- sst->addr.shim = mmio_base;
- sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE;
- sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE;
- sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ;
- sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ;
-
- sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ),
- CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE,
- CNL_ADSP_W1_SZ);
-
- ret = cnl_ipc_init(dev, cnl);
- if (ret) {
- skl_dsp_free(sst);
- return ret;
- }
-
- cnl->boot_complete = false;
- init_waitqueue_head(&cnl->boot_wait);
-
- return skl_dsp_acquire_irq(sst);
-}
-EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
-
-int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl)
-{
- int ret;
- struct sst_dsp *sst = skl->dsp;
-
- ret = skl->dsp->fw_ops.load_fw(sst);
- if (ret < 0) {
- dev_err(dev, "load base fw failed: %d", ret);
- return ret;
- }
-
- skl_dsp_init_core_state(sst);
-
- skl->is_first_boot = false;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(cnl_sst_init_fw);
-
-void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl)
-{
- if (skl->dsp->fw)
- release_firmware(skl->dsp->fw);
-
- skl_freeup_uuid_list(skl);
- cnl_ipc_free(&skl->ipc);
-
- skl->dsp->ops->free(skl->dsp);
-}
-EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Cannonlake IPC driver");
diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c
deleted file mode 100644
index a15aa2ffa681..000000000000
--- a/sound/soc/intel/skylake/skl-debug.c
+++ /dev/null
@@ -1,248 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-debug.c - Debugfs for skl driver
- *
- * Copyright (C) 2016-17 Intel Corp
- */
-
-#include <linux/pci.h>
-#include <linux/debugfs.h>
-#include <uapi/sound/skl-tplg-interface.h>
-#include "skl.h"
-#include "skl-sst-dsp.h"
-#include "skl-sst-ipc.h"
-#include "skl-topology.h"
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-
-#define MOD_BUF PAGE_SIZE
-#define FW_REG_BUF PAGE_SIZE
-#define FW_REG_SIZE 0x60
-
-struct skl_debug {
- struct skl_dev *skl;
- struct device *dev;
-
- struct dentry *fs;
- struct dentry *modules;
- u8 fw_read_buff[FW_REG_BUF];
-};
-
-static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
- int max_pin, ssize_t size, bool direction)
-{
- int i;
- ssize_t ret = 0;
-
- for (i = 0; i < max_pin; i++) {
- ret += scnprintf(buf + size, MOD_BUF - size,
- "%s %d\n\tModule %d\n\tInstance %d\n\t"
- "In-used %s\n\tType %s\n"
- "\tState %d\n\tIndex %d\n",
- direction ? "Input Pin:" : "Output Pin:",
- i, m_pin[i].id.module_id,
- m_pin[i].id.instance_id,
- m_pin[i].in_use ? "Used" : "Unused",
- m_pin[i].is_dynamic ? "Dynamic" : "Static",
- m_pin[i].pin_state, i);
- size += ret;
- }
- return ret;
-}
-
-static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf,
- ssize_t size, bool direction)
-{
- return scnprintf(buf + size, MOD_BUF - size,
- "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t"
- "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t"
- "Sample Type %d\n\tCh Map %#x\n",
- direction ? "Input Format:" : "Output Format:",
- fmt->channels, fmt->s_freq, fmt->bit_depth,
- fmt->valid_bit_depth, fmt->ch_cfg,
- fmt->interleaving_style, fmt->sample_type,
- fmt->ch_map);
-}
-
-static ssize_t module_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct skl_module_cfg *mconfig = file->private_data;
- struct skl_module *module = mconfig->module;
- struct skl_module_res *res = &module->resources[mconfig->res_idx];
- char *buf;
- ssize_t ret;
-
- buf = kzalloc(MOD_BUF, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = scnprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
- "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid,
- mconfig->id.module_id, mconfig->id.instance_id,
- mconfig->id.pvt_id);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n",
- res->cpc, res->ibs, res->obs);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "Module data:\n\tCore %d\n\tIn queue %d\n\t"
- "Out queue %d\n\tType %s\n",
- mconfig->core_id, mconfig->max_in_queue,
- mconfig->max_out_queue,
- mconfig->is_loadable ? "loadable" : "inbuilt");
-
- ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true);
- ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "Fixup:\n\tParams %#x\n\tConverter %#x\n",
- mconfig->params_fixup, mconfig->converter);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n",
- mconfig->dev_type, mconfig->vbus_id,
- mconfig->hw_conn_type, mconfig->time_slot);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t"
- "Pages %#x\n", mconfig->pipe->ppl_id,
- mconfig->pipe->pipe_priority, mconfig->pipe->conn_type,
- mconfig->pipe->memory_pages);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n",
- mconfig->pipe->p_params->host_dma_id,
- mconfig->pipe->p_params->link_dma_id);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n",
- mconfig->pipe->p_params->ch,
- mconfig->pipe->p_params->s_freq,
- mconfig->pipe->p_params->s_fmt);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "\tLink %#x\n\tStream %#x\n",
- mconfig->pipe->p_params->linktype,
- mconfig->pipe->p_params->stream);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "\tState %d\n\tPassthru %s\n",
- mconfig->pipe->state,
- mconfig->pipe->passthru ? "true" : "false");
-
- ret += skl_print_pins(mconfig->m_in_pin, buf,
- mconfig->max_in_queue, ret, true);
- ret += skl_print_pins(mconfig->m_out_pin, buf,
- mconfig->max_out_queue, ret, false);
-
- ret += scnprintf(buf + ret, MOD_BUF - ret,
- "Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t"
- "Homogeneous Output %s\n\tIn Queue Mask %d\n\t"
- "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
- "Module Type %d\n\tModule State %d\n",
- mconfig->domain,
- mconfig->homogenous_inputs ? "true" : "false",
- mconfig->homogenous_outputs ? "true" : "false",
- mconfig->in_queue_mask, mconfig->out_queue_mask,
- mconfig->dma_id, mconfig->mem_pages, mconfig->m_state,
- mconfig->m_type);
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- kfree(buf);
- return ret;
-}
-
-static const struct file_operations mcfg_fops = {
- .open = simple_open,
- .read = module_read,
- .llseek = default_llseek,
-};
-
-
-void skl_debug_init_module(struct skl_debug *d,
- struct snd_soc_dapm_widget *w,
- struct skl_module_cfg *mconfig)
-{
- debugfs_create_file(w->name, 0444, d->modules, mconfig,
- &mcfg_fops);
-}
-
-static ssize_t fw_softreg_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct skl_debug *d = file->private_data;
- struct sst_dsp *sst = d->skl->dsp;
- size_t w0_stat_sz = sst->addr.w0_stat_sz;
- void __iomem *in_base = sst->mailbox.in_base;
- void __iomem *fw_reg_addr;
- unsigned int offset;
- char *tmp;
- ssize_t ret = 0;
-
- tmp = kzalloc(FW_REG_BUF, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- fw_reg_addr = in_base - w0_stat_sz;
- memset(d->fw_read_buff, 0, FW_REG_BUF);
-
- if (w0_stat_sz > 0)
- __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2);
-
- for (offset = 0; offset < FW_REG_SIZE; offset += 16) {
- ret += scnprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
- hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4,
- tmp + ret, FW_REG_BUF - ret, 0);
- ret += strlen(tmp + ret);
-
- /* print newline for each offset */
- if (FW_REG_BUF - ret > 0)
- tmp[ret++] = '\n';
- }
-
- ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret);
- kfree(tmp);
-
- return ret;
-}
-
-static const struct file_operations soft_regs_ctrl_fops = {
- .open = simple_open,
- .read = fw_softreg_read,
- .llseek = default_llseek,
-};
-
-struct skl_debug *skl_debugfs_init(struct skl_dev *skl)
-{
- struct skl_debug *d;
-
- d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL);
- if (!d)
- return NULL;
-
- /* create the debugfs dir with platform component's debugfs as parent */
- d->fs = debugfs_create_dir("dsp", skl->component->debugfs_root);
-
- d->skl = skl;
- d->dev = &skl->pci->dev;
-
- /* now create the module dir */
- d->modules = debugfs_create_dir("modules", d->fs);
-
- debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d,
- &soft_regs_ctrl_fops);
-
- return d;
-}
-
-void skl_debugfs_exit(struct skl_dev *skl)
-{
- struct skl_debug *d = skl->debugfs;
-
- debugfs_remove_recursive(d->fs);
-
- d = NULL;
-}
diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h
deleted file mode 100644
index dfce91e11be1..000000000000
--- a/sound/soc/intel/skylake/skl-i2s.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * skl-i2s.h - i2s blob mapping
- *
- * Copyright (C) 2017 Intel Corp
- * Author: Subhransu S. Prusty < subhransu.s.prusty@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#ifndef __SOUND_SOC_SKL_I2S_H
-#define __SOUND_SOC_SKL_I2S_H
-
-#define SKL_I2S_MAX_TIME_SLOTS 8
-#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16)
-
-#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20)
-#define SKL_SHIFT(x) (ffs(x) - 1)
-#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0)
-
-#define is_legacy_blob(x) (x.signature != 0xEE)
-#define ext_to_legacy_blob(i2s_config_blob_ext) \
- ((struct skl_i2s_config_blob_legacy *) i2s_config_blob_ext)
-
-#define get_clk_src(mclk, mask) \
- ((mclk.mdivctrl & mask) >> SKL_SHIFT(mask))
-struct skl_i2s_config {
- u32 ssc0;
- u32 ssc1;
- u32 sscto;
- u32 sspsp;
- u32 sstsa;
- u32 ssrsa;
- u32 ssc2;
- u32 sspsp2;
- u32 ssc3;
- u32 ssioc;
-} __packed;
-
-struct skl_i2s_config_mclk {
- u32 mdivctrl;
- u32 mdivr;
-};
-
-struct skl_i2s_config_mclk_ext {
- u32 mdivctrl;
- u32 mdivr_count;
- u32 mdivr[];
-} __packed;
-
-struct skl_i2s_config_blob_signature {
- u32 minor_ver : 8;
- u32 major_ver : 8;
- u32 resvdz : 8;
- u32 signature : 8;
-} __packed;
-
-struct skl_i2s_config_blob_header {
- struct skl_i2s_config_blob_signature sig;
- u32 size;
-};
-
-/**
- * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway
- * configuration legacy blob
- *
- * @gtw_attr: Gateway attribute for the I2S Gateway
- * @tdm_ts_group: TDM slot mapping against channels in the Gateway.
- * @i2s_cfg: I2S HW registers
- * @mclk: MCLK clock source and divider values
- */
-struct skl_i2s_config_blob_legacy {
- u32 gtw_attr;
- u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
- struct skl_i2s_config i2s_cfg;
- struct skl_i2s_config_mclk mclk;
-};
-
-struct skl_i2s_config_blob_ext {
- u32 gtw_attr;
- struct skl_i2s_config_blob_header hdr;
- u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
- struct skl_i2s_config i2s_cfg;
- struct skl_i2s_config_mclk_ext mclk;
-} __packed;
-#endif /* __SOUND_SOC_SKL_I2S_H */
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
deleted file mode 100644
index d31509298a0a..000000000000
--- a/sound/soc/intel/skylake/skl-messages.c
+++ /dev/null
@@ -1,1419 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-message.c - HDA DSP interface for FW registration, Pipe and Module
- * configurations
- *
- * Copyright (C) 2015 Intel Corp
- * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
- * Jeeja KP <jeeja.kp@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <uapi/sound/skl-tplg-interface.h>
-#include "skl-sst-dsp.h"
-#include "cnl-sst-dsp.h"
-#include "skl-sst-ipc.h"
-#include "skl.h"
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-#include "skl-topology.h"
-
-static int skl_alloc_dma_buf(struct device *dev,
- struct snd_dma_buffer *dmab, size_t size)
-{
- return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab);
-}
-
-static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
-{
- snd_dma_free_pages(dmab);
- return 0;
-}
-
-#define SKL_ASTATE_PARAM_ID 4
-
-void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data)
-{
- struct skl_ipc_large_config_msg msg = {0};
-
- msg.large_param_id = SKL_ASTATE_PARAM_ID;
- msg.param_data_size = (cnt * sizeof(struct skl_astate_param) +
- sizeof(cnt));
-
- skl_ipc_set_large_config(&skl->ipc, &msg, data);
-}
-
-static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
- int stream_tag, int enable)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct hdac_stream *stream = snd_hdac_get_stream(bus,
- SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
-
- if (!stream)
- return -EINVAL;
-
- /* enable/disable SPIB for this hdac stream */
- snd_hdac_stream_spbcap_enable(bus, enable, stream->index);
-
- /* set the spib value */
- snd_hdac_stream_set_spib(bus, stream, size);
-
- return 0;
-}
-
-static int skl_dsp_prepare(struct device *dev, unsigned int format,
- unsigned int size, struct snd_dma_buffer *dmab)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct hdac_ext_stream *estream;
- struct hdac_stream *stream;
- struct snd_pcm_substream substream;
- int ret;
-
- if (!bus)
- return -ENODEV;
-
- memset(&substream, 0, sizeof(substream));
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
-
- estream = snd_hdac_ext_stream_assign(bus, &substream,
- HDAC_EXT_STREAM_TYPE_HOST);
- if (!estream)
- return -ENODEV;
-
- stream = hdac_stream(estream);
-
- /* assign decouple host dma channel */
- ret = snd_hdac_dsp_prepare(stream, format, size, dmab);
- if (ret < 0)
- return ret;
-
- skl_dsp_setup_spib(dev, size, stream->stream_tag, true);
-
- return stream->stream_tag;
-}
-
-static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct hdac_stream *stream;
-
- if (!bus)
- return -ENODEV;
-
- stream = snd_hdac_get_stream(bus,
- SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
- if (!stream)
- return -EINVAL;
-
- snd_hdac_dsp_trigger(stream, start);
-
- return 0;
-}
-
-static int skl_dsp_cleanup(struct device *dev,
- struct snd_dma_buffer *dmab, int stream_tag)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct hdac_stream *stream;
- struct hdac_ext_stream *estream;
-
- if (!bus)
- return -ENODEV;
-
- stream = snd_hdac_get_stream(bus,
- SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
- if (!stream)
- return -EINVAL;
-
- estream = stream_to_hdac_ext_stream(stream);
- skl_dsp_setup_spib(dev, 0, stream_tag, false);
- snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST);
-
- snd_hdac_dsp_cleanup(stream, dmab);
-
- return 0;
-}
-
-static struct skl_dsp_loader_ops skl_get_loader_ops(void)
-{
- struct skl_dsp_loader_ops loader_ops;
-
- memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops));
-
- loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
- loader_ops.free_dma_buf = skl_free_dma_buf;
-
- return loader_ops;
-};
-
-static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
-{
- struct skl_dsp_loader_ops loader_ops;
-
- memset(&loader_ops, 0, sizeof(loader_ops));
-
- loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
- loader_ops.free_dma_buf = skl_free_dma_buf;
- loader_ops.prepare = skl_dsp_prepare;
- loader_ops.trigger = skl_dsp_trigger;
- loader_ops.cleanup = skl_dsp_cleanup;
-
- return loader_ops;
-};
-
-static const struct skl_dsp_ops dsp_ops[] = {
- {
- .id = 0x9d70,
- .num_cores = 2,
- .loader_ops = skl_get_loader_ops,
- .init = skl_sst_dsp_init,
- .init_fw = skl_sst_init_fw,
- .cleanup = skl_sst_dsp_cleanup
- },
- {
- .id = 0x9d71,
- .num_cores = 2,
- .loader_ops = skl_get_loader_ops,
- .init = skl_sst_dsp_init,
- .init_fw = skl_sst_init_fw,
- .cleanup = skl_sst_dsp_cleanup
- },
- {
- .id = 0x5a98,
- .num_cores = 2,
- .loader_ops = bxt_get_loader_ops,
- .init = bxt_sst_dsp_init,
- .init_fw = bxt_sst_init_fw,
- .cleanup = bxt_sst_dsp_cleanup
- },
- {
- .id = 0x3198,
- .num_cores = 2,
- .loader_ops = bxt_get_loader_ops,
- .init = bxt_sst_dsp_init,
- .init_fw = bxt_sst_init_fw,
- .cleanup = bxt_sst_dsp_cleanup
- },
- {
- .id = 0x9dc8,
- .num_cores = 4,
- .loader_ops = bxt_get_loader_ops,
- .init = cnl_sst_dsp_init,
- .init_fw = cnl_sst_init_fw,
- .cleanup = cnl_sst_dsp_cleanup
- },
- {
- .id = 0xa348,
- .num_cores = 4,
- .loader_ops = bxt_get_loader_ops,
- .init = cnl_sst_dsp_init,
- .init_fw = cnl_sst_init_fw,
- .cleanup = cnl_sst_dsp_cleanup
- },
- {
- .id = 0x02c8,
- .num_cores = 4,
- .loader_ops = bxt_get_loader_ops,
- .init = cnl_sst_dsp_init,
- .init_fw = cnl_sst_init_fw,
- .cleanup = cnl_sst_dsp_cleanup
- },
- {
- .id = 0x06c8,
- .num_cores = 4,
- .loader_ops = bxt_get_loader_ops,
- .init = cnl_sst_dsp_init,
- .init_fw = cnl_sst_init_fw,
- .cleanup = cnl_sst_dsp_cleanup
- },
-};
-
-const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) {
- if (dsp_ops[i].id == pci_id)
- return &dsp_ops[i];
- }
-
- return NULL;
-}
-
-int skl_init_dsp(struct skl_dev *skl)
-{
- void __iomem *mmio_base;
- struct hdac_bus *bus = skl_to_bus(skl);
- struct skl_dsp_loader_ops loader_ops;
- int irq = bus->irq;
- const struct skl_dsp_ops *ops;
- struct skl_dsp_cores *cores;
- int ret;
-
- /* enable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_enable(bus, true);
- snd_hdac_ext_bus_ppcap_int_enable(bus, true);
-
- /* read the BAR of the ADSP MMIO */
- mmio_base = pci_ioremap_bar(skl->pci, 4);
- if (mmio_base == NULL) {
- dev_err(bus->dev, "ioremap error\n");
- return -ENXIO;
- }
-
- ops = skl_get_dsp_ops(skl->pci->device);
- if (!ops) {
- ret = -EIO;
- goto unmap_mmio;
- }
-
- loader_ops = ops->loader_ops();
- ret = ops->init(bus->dev, mmio_base, irq,
- skl->fw_name, loader_ops,
- &skl);
-
- if (ret < 0)
- goto unmap_mmio;
-
- skl->dsp_ops = ops;
- cores = &skl->cores;
- cores->count = ops->num_cores;
-
- cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL);
- if (!cores->state) {
- ret = -ENOMEM;
- goto unmap_mmio;
- }
-
- cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count),
- GFP_KERNEL);
- if (!cores->usage_count) {
- ret = -ENOMEM;
- goto free_core_state;
- }
-
- dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
-
- return 0;
-
-free_core_state:
- kfree(cores->state);
-
-unmap_mmio:
- iounmap(mmio_base);
-
- return ret;
-}
-
-int skl_free_dsp(struct skl_dev *skl)
-{
- struct hdac_bus *bus = skl_to_bus(skl);
-
- /* disable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_int_enable(bus, false);
-
- skl->dsp_ops->cleanup(bus->dev, skl);
-
- kfree(skl->cores.state);
- kfree(skl->cores.usage_count);
-
- if (skl->dsp->addr.lpe)
- iounmap(skl->dsp->addr.lpe);
-
- return 0;
-}
-
-/*
- * In the case of "suspend_active" i.e, the Audio IP being active
- * during system suspend, immediately excecute any pending D0i3 work
- * before suspending. This is needed for the IP to work in low power
- * mode during system suspend. In the case of normal suspend, cancel
- * any pending D0i3 work.
- */
-int skl_suspend_late_dsp(struct skl_dev *skl)
-{
- struct delayed_work *dwork;
-
- if (!skl)
- return 0;
-
- dwork = &skl->d0i3.work;
-
- if (dwork->work.func) {
- if (skl->supend_active)
- flush_delayed_work(dwork);
- else
- cancel_delayed_work_sync(dwork);
- }
-
- return 0;
-}
-
-int skl_suspend_dsp(struct skl_dev *skl)
-{
- struct hdac_bus *bus = skl_to_bus(skl);
- int ret;
-
- /* if ppcap is not supported return 0 */
- if (!bus->ppcap)
- return 0;
-
- ret = skl_dsp_sleep(skl->dsp);
- if (ret < 0)
- return ret;
-
- /* disable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_int_enable(bus, false);
- snd_hdac_ext_bus_ppcap_enable(bus, false);
-
- return 0;
-}
-
-int skl_resume_dsp(struct skl_dev *skl)
-{
- struct hdac_bus *bus = skl_to_bus(skl);
- int ret;
-
- /* if ppcap is not supported return 0 */
- if (!bus->ppcap)
- return 0;
-
- /* enable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_enable(bus, true);
- snd_hdac_ext_bus_ppcap_int_enable(bus, true);
-
- /* check if DSP 1st boot is done */
- if (skl->is_first_boot)
- return 0;
-
- /*
- * Disable dynamic clock and power gating during firmware
- * and library download
- */
- skl->enable_miscbdcge(skl->dev, false);
- skl->clock_power_gating(skl->dev, false);
-
- ret = skl_dsp_wake(skl->dsp);
- skl->enable_miscbdcge(skl->dev, true);
- skl->clock_power_gating(skl->dev, true);
- if (ret < 0)
- return ret;
-
- if (skl->cfg.astate_cfg != NULL) {
- skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count,
- skl->cfg.astate_cfg);
- }
- return ret;
-}
-
-enum skl_bitdepth skl_get_bit_depth(int params)
-{
- switch (params) {
- case 8:
- return SKL_DEPTH_8BIT;
-
- case 16:
- return SKL_DEPTH_16BIT;
-
- case 24:
- return SKL_DEPTH_24BIT;
-
- case 32:
- return SKL_DEPTH_32BIT;
-
- default:
- return SKL_DEPTH_INVALID;
-
- }
-}
-
-/*
- * Each module in DSP expects a base module configuration, which consists of
- * PCM format information, which we calculate in driver and resource values
- * which are read from widget information passed through topology binary
- * This is send when we create a module with INIT_INSTANCE IPC msg
- */
-static void skl_set_base_module_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_base_cfg *base_cfg)
-{
- struct skl_module *module = mconfig->module;
- struct skl_module_res *res = &module->resources[mconfig->res_idx];
- struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
- struct skl_module_fmt *format = &fmt->inputs[0].fmt;
-
- base_cfg->audio_fmt.number_of_channels = format->channels;
-
- base_cfg->audio_fmt.s_freq = format->s_freq;
- base_cfg->audio_fmt.bit_depth = format->bit_depth;
- base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth;
- base_cfg->audio_fmt.ch_cfg = format->ch_cfg;
- base_cfg->audio_fmt.sample_type = format->sample_type;
-
- dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n",
- format->bit_depth, format->valid_bit_depth,
- format->ch_cfg);
-
- base_cfg->audio_fmt.channel_map = format->ch_map;
-
- base_cfg->audio_fmt.interleaving = format->interleaving_style;
-
- base_cfg->cpc = res->cpc;
- base_cfg->ibs = res->ibs;
- base_cfg->obs = res->obs;
- base_cfg->is_pages = res->is_pages;
-}
-
-static void fill_pin_params(struct skl_audio_data_format *pin_fmt,
- struct skl_module_fmt *format)
-{
- pin_fmt->number_of_channels = format->channels;
- pin_fmt->s_freq = format->s_freq;
- pin_fmt->bit_depth = format->bit_depth;
- pin_fmt->valid_bit_depth = format->valid_bit_depth;
- pin_fmt->ch_cfg = format->ch_cfg;
- pin_fmt->sample_type = format->sample_type;
- pin_fmt->channel_map = format->ch_map;
- pin_fmt->interleaving = format->interleaving_style;
-}
-
-/*
- * Any module configuration begins with a base module configuration but
- * can be followed by a generic extension containing audio format for all
- * module's pins that are in use.
- */
-static void skl_set_base_ext_module_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_base_cfg_ext *base_cfg_ext)
-{
- struct skl_module *module = mconfig->module;
- struct skl_module_pin_resources *pin_res;
- struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
- struct skl_module_res *res = &module->resources[mconfig->res_idx];
- struct skl_module_fmt *format;
- struct skl_pin_format *pin_fmt;
- char *params;
- int i;
-
- base_cfg_ext->nr_input_pins = res->nr_input_pins;
- base_cfg_ext->nr_output_pins = res->nr_output_pins;
- base_cfg_ext->priv_param_length =
- mconfig->formats_config[SKL_PARAM_INIT].caps_size;
-
- for (i = 0; i < res->nr_input_pins; i++) {
- pin_res = &res->input[i];
- pin_fmt = &base_cfg_ext->pins_fmt[i];
-
- pin_fmt->pin_idx = pin_res->pin_index;
- pin_fmt->buf_size = pin_res->buf_size;
-
- format = &fmt->inputs[pin_res->pin_index].fmt;
- fill_pin_params(&pin_fmt->audio_fmt, format);
- }
-
- for (i = 0; i < res->nr_output_pins; i++) {
- pin_res = &res->output[i];
- pin_fmt = &base_cfg_ext->pins_fmt[res->nr_input_pins + i];
-
- pin_fmt->pin_idx = pin_res->pin_index;
- pin_fmt->buf_size = pin_res->buf_size;
-
- format = &fmt->outputs[pin_res->pin_index].fmt;
- fill_pin_params(&pin_fmt->audio_fmt, format);
- }
-
- if (!base_cfg_ext->priv_param_length)
- return;
-
- params = (char *)base_cfg_ext + sizeof(struct skl_base_cfg_ext);
- params += (base_cfg_ext->nr_input_pins + base_cfg_ext->nr_output_pins) *
- sizeof(struct skl_pin_format);
-
- memcpy(params, mconfig->formats_config[SKL_PARAM_INIT].caps,
- mconfig->formats_config[SKL_PARAM_INIT].caps_size);
-}
-
-/*
- * Copies copier capabilities into copier module and updates copier module
- * config size.
- */
-static void skl_copy_copier_caps(struct skl_module_cfg *mconfig,
- struct skl_cpr_cfg *cpr_mconfig)
-{
- if (mconfig->formats_config[SKL_PARAM_INIT].caps_size == 0)
- return;
-
- memcpy(&cpr_mconfig->gtw_cfg.config_data,
- mconfig->formats_config[SKL_PARAM_INIT].caps,
- mconfig->formats_config[SKL_PARAM_INIT].caps_size);
-
- cpr_mconfig->gtw_cfg.config_length =
- (mconfig->formats_config[SKL_PARAM_INIT].caps_size) / 4;
-}
-
-#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF
-/*
- * Calculate the gatewat settings required for copier module, type of
- * gateway and index of gateway to use
- */
-static u32 skl_get_node_id(struct skl_dev *skl,
- struct skl_module_cfg *mconfig)
-{
- union skl_connector_node_id node_id = {0};
- union skl_ssp_dma_node ssp_node = {0};
- struct skl_pipe_params *params = mconfig->pipe->p_params;
-
- switch (mconfig->dev_type) {
- case SKL_DEVICE_BT:
- node_id.node.dma_type =
- (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
- SKL_DMA_I2S_LINK_OUTPUT_CLASS :
- SKL_DMA_I2S_LINK_INPUT_CLASS;
- node_id.node.vindex = params->host_dma_id +
- (mconfig->vbus_id << 3);
- break;
-
- case SKL_DEVICE_I2S:
- node_id.node.dma_type =
- (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
- SKL_DMA_I2S_LINK_OUTPUT_CLASS :
- SKL_DMA_I2S_LINK_INPUT_CLASS;
- ssp_node.dma_node.time_slot_index = mconfig->time_slot;
- ssp_node.dma_node.i2s_instance = mconfig->vbus_id;
- node_id.node.vindex = ssp_node.val;
- break;
-
- case SKL_DEVICE_DMIC:
- node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS;
- node_id.node.vindex = mconfig->vbus_id +
- (mconfig->time_slot);
- break;
-
- case SKL_DEVICE_HDALINK:
- node_id.node.dma_type =
- (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
- SKL_DMA_HDA_LINK_OUTPUT_CLASS :
- SKL_DMA_HDA_LINK_INPUT_CLASS;
- node_id.node.vindex = params->link_dma_id;
- break;
-
- case SKL_DEVICE_HDAHOST:
- node_id.node.dma_type =
- (SKL_CONN_SOURCE == mconfig->hw_conn_type) ?
- SKL_DMA_HDA_HOST_OUTPUT_CLASS :
- SKL_DMA_HDA_HOST_INPUT_CLASS;
- node_id.node.vindex = params->host_dma_id;
- break;
-
- default:
- node_id.val = 0xFFFFFFFF;
- break;
- }
-
- return node_id.val;
-}
-
-static void skl_setup_cpr_gateway_cfg(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_cpr_cfg *cpr_mconfig)
-{
- u32 dma_io_buf;
- struct skl_module_res *res;
- int res_idx = mconfig->res_idx;
-
- cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig);
-
- if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) {
- cpr_mconfig->cpr_feature_mask = 0;
- return;
- }
-
- if (skl->nr_modules) {
- res = &mconfig->module->resources[mconfig->res_idx];
- cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size;
- goto skip_buf_size_calc;
- } else {
- res = &mconfig->module->resources[res_idx];
- }
-
- switch (mconfig->hw_conn_type) {
- case SKL_CONN_SOURCE:
- if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
- dma_io_buf = res->ibs;
- else
- dma_io_buf = res->obs;
- break;
-
- case SKL_CONN_SINK:
- if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
- dma_io_buf = res->obs;
- else
- dma_io_buf = res->ibs;
- break;
-
- default:
- dev_warn(skl->dev, "wrong connection type: %d\n",
- mconfig->hw_conn_type);
- return;
- }
-
- cpr_mconfig->gtw_cfg.dma_buffer_size =
- mconfig->dma_buffer_size * dma_io_buf;
-
- /* fallback to 2ms default value */
- if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
- if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
- cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs;
- else
- cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs;
- }
-
-skip_buf_size_calc:
- cpr_mconfig->cpr_feature_mask = 0;
- cpr_mconfig->gtw_cfg.config_length = 0;
-
- skl_copy_copier_caps(mconfig, cpr_mconfig);
-}
-
-#define DMA_CONTROL_ID 5
-#define DMA_I2S_BLOB_SIZE 21
-
-int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps,
- u32 caps_size, u32 node_id)
-{
- struct skl_dma_control *dma_ctrl;
- struct skl_ipc_large_config_msg msg = {0};
- int err = 0;
-
-
- /*
- * if blob size zero, then return
- */
- if (caps_size == 0)
- return 0;
-
- msg.large_param_id = DMA_CONTROL_ID;
- msg.param_data_size = sizeof(struct skl_dma_control) + caps_size;
-
- dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL);
- if (dma_ctrl == NULL)
- return -ENOMEM;
-
- dma_ctrl->node_id = node_id;
-
- /*
- * NHLT blob may contain additional configs along with i2s blob.
- * firmware expects only the i2s blob size as the config_length.
- * So fix to i2s blob size.
- * size in dwords.
- */
- dma_ctrl->config_length = DMA_I2S_BLOB_SIZE;
-
- memcpy(dma_ctrl->config_data, caps, caps_size);
-
- err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl);
-
- kfree(dma_ctrl);
- return err;
-}
-EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control);
-
-static void skl_setup_out_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_audio_data_format *out_fmt)
-{
- struct skl_module *module = mconfig->module;
- struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
- struct skl_module_fmt *format = &fmt->outputs[0].fmt;
-
- out_fmt->number_of_channels = (u8)format->channels;
- out_fmt->s_freq = format->s_freq;
- out_fmt->bit_depth = format->bit_depth;
- out_fmt->valid_bit_depth = format->valid_bit_depth;
- out_fmt->ch_cfg = format->ch_cfg;
-
- out_fmt->channel_map = format->ch_map;
- out_fmt->interleaving = format->interleaving_style;
- out_fmt->sample_type = format->sample_type;
-
- dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
- out_fmt->number_of_channels, format->s_freq, format->bit_depth);
-}
-
-/*
- * DSP needs SRC module for frequency conversion, SRC takes base module
- * configuration and the target frequency as extra parameter passed as src
- * config
- */
-static void skl_set_src_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_src_module_cfg *src_mconfig)
-{
- struct skl_module *module = mconfig->module;
- struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
- struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
-
- skl_set_base_module_format(skl, mconfig,
- (struct skl_base_cfg *)src_mconfig);
-
- src_mconfig->src_cfg = fmt->s_freq;
-}
-
-/*
- * DSP needs updown module to do channel conversion. updown module take base
- * module configuration and channel configuration
- * It also take coefficients and now we have defaults applied here
- */
-static void skl_set_updown_mixer_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_up_down_mixer_cfg *mixer_mconfig)
-{
- struct skl_module *module = mconfig->module;
- struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
- struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
-
- skl_set_base_module_format(skl, mconfig,
- (struct skl_base_cfg *)mixer_mconfig);
- mixer_mconfig->out_ch_cfg = fmt->ch_cfg;
- mixer_mconfig->ch_map = fmt->ch_map;
-}
-
-/*
- * 'copier' is DSP internal module which copies data from Host DMA (HDA host
- * dma) or link (hda link, SSP, PDM)
- * Here we calculate the copier module parameters, like PCM format, output
- * format, gateway settings
- * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg
- */
-static void skl_set_copier_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_cpr_cfg *cpr_mconfig)
-{
- struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt;
- struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig;
-
- skl_set_base_module_format(skl, mconfig, base_cfg);
-
- skl_setup_out_format(skl, mconfig, out_fmt);
- skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig);
-}
-
-/*
- * Mic select module allows selecting one or many input channels, thus
- * acting as a demux.
- *
- * Mic select module take base module configuration and out-format
- * configuration
- */
-static void skl_set_base_outfmt_format(struct skl_dev *skl,
- struct skl_module_cfg *mconfig,
- struct skl_base_outfmt_cfg *base_outfmt_mcfg)
-{
- struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt;
- struct skl_base_cfg *base_cfg =
- (struct skl_base_cfg *)base_outfmt_mcfg;
-
- skl_set_base_module_format(skl, mconfig, base_cfg);
- skl_setup_out_format(skl, mconfig, out_fmt);
-}
-
-static u16 skl_get_module_param_size(struct skl_dev *skl,
- struct skl_module_cfg *mconfig)
-{
- struct skl_module_res *res;
- struct skl_module *module = mconfig->module;
- u16 param_size;
-
- switch (mconfig->m_type) {
- case SKL_MODULE_TYPE_COPIER:
- param_size = sizeof(struct skl_cpr_cfg);
- param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size;
- return param_size;
-
- case SKL_MODULE_TYPE_SRCINT:
- return sizeof(struct skl_src_module_cfg);
-
- case SKL_MODULE_TYPE_UPDWMIX:
- return sizeof(struct skl_up_down_mixer_cfg);
-
- case SKL_MODULE_TYPE_BASE_OUTFMT:
- case SKL_MODULE_TYPE_MIC_SELECT:
- return sizeof(struct skl_base_outfmt_cfg);
-
- case SKL_MODULE_TYPE_MIXER:
- case SKL_MODULE_TYPE_KPB:
- return sizeof(struct skl_base_cfg);
-
- case SKL_MODULE_TYPE_ALGO:
- default:
- res = &module->resources[mconfig->res_idx];
-
- param_size = sizeof(struct skl_base_cfg) + sizeof(struct skl_base_cfg_ext);
- param_size += (res->nr_input_pins + res->nr_output_pins) *
- sizeof(struct skl_pin_format);
- param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size;
-
- return param_size;
- }
-
- return 0;
-}
-
-/*
- * DSP firmware supports various modules like copier, SRC, updown etc.
- * These modules required various parameters to be calculated and sent for
- * the module initialization to DSP. By default a generic module needs only
- * base module format configuration
- */
-
-static int skl_set_module_format(struct skl_dev *skl,
- struct skl_module_cfg *module_config,
- u16 *module_config_size,
- void **param_data)
-{
- u16 param_size;
-
- param_size = skl_get_module_param_size(skl, module_config);
-
- *param_data = kzalloc(param_size, GFP_KERNEL);
- if (NULL == *param_data)
- return -ENOMEM;
-
- *module_config_size = param_size;
-
- switch (module_config->m_type) {
- case SKL_MODULE_TYPE_COPIER:
- skl_set_copier_format(skl, module_config, *param_data);
- break;
-
- case SKL_MODULE_TYPE_SRCINT:
- skl_set_src_format(skl, module_config, *param_data);
- break;
-
- case SKL_MODULE_TYPE_UPDWMIX:
- skl_set_updown_mixer_format(skl, module_config, *param_data);
- break;
-
- case SKL_MODULE_TYPE_BASE_OUTFMT:
- case SKL_MODULE_TYPE_MIC_SELECT:
- skl_set_base_outfmt_format(skl, module_config, *param_data);
- break;
-
- case SKL_MODULE_TYPE_MIXER:
- case SKL_MODULE_TYPE_KPB:
- skl_set_base_module_format(skl, module_config, *param_data);
- break;
-
- case SKL_MODULE_TYPE_ALGO:
- default:
- skl_set_base_module_format(skl, module_config, *param_data);
- skl_set_base_ext_module_format(skl, module_config,
- *param_data +
- sizeof(struct skl_base_cfg));
- break;
- }
-
- dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n",
- module_config->m_type, module_config->id.module_id,
- param_size);
- print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4,
- *param_data, param_size, false);
- return 0;
-}
-
-static int skl_get_queue_index(struct skl_module_pin *mpin,
- struct skl_module_inst_id id, int max)
-{
- int i;
-
- for (i = 0; i < max; i++) {
- if (mpin[i].id.module_id == id.module_id &&
- mpin[i].id.instance_id == id.instance_id)
- return i;
- }
-
- return -EINVAL;
-}
-
-/*
- * Allocates queue for each module.
- * if dynamic, the pin_index is allocated 0 to max_pin.
- * In static, the pin_index is fixed based on module_id and instance id
- */
-static int skl_alloc_queue(struct skl_module_pin *mpin,
- struct skl_module_cfg *tgt_cfg, int max)
-{
- int i;
- struct skl_module_inst_id id = tgt_cfg->id;
- /*
- * if pin in dynamic, find first free pin
- * otherwise find match module and instance id pin as topology will
- * ensure a unique pin is assigned to this so no need to
- * allocate/free
- */
- for (i = 0; i < max; i++) {
- if (mpin[i].is_dynamic) {
- if (!mpin[i].in_use &&
- mpin[i].pin_state == SKL_PIN_UNBIND) {
-
- mpin[i].in_use = true;
- mpin[i].id.module_id = id.module_id;
- mpin[i].id.instance_id = id.instance_id;
- mpin[i].id.pvt_id = id.pvt_id;
- mpin[i].tgt_mcfg = tgt_cfg;
- return i;
- }
- } else {
- if (mpin[i].id.module_id == id.module_id &&
- mpin[i].id.instance_id == id.instance_id &&
- mpin[i].pin_state == SKL_PIN_UNBIND) {
-
- mpin[i].tgt_mcfg = tgt_cfg;
- return i;
- }
- }
- }
-
- return -EINVAL;
-}
-
-static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
-{
- if (mpin[q_index].is_dynamic) {
- mpin[q_index].in_use = false;
- mpin[q_index].id.module_id = 0;
- mpin[q_index].id.instance_id = 0;
- mpin[q_index].id.pvt_id = 0;
- }
- mpin[q_index].pin_state = SKL_PIN_UNBIND;
- mpin[q_index].tgt_mcfg = NULL;
-}
-
-/* Module state will be set to unint, if all the out pin state is UNBIND */
-
-static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
- struct skl_module_cfg *mcfg)
-{
- int i;
- bool found = false;
-
- for (i = 0; i < max; i++) {
- if (mpin[i].pin_state == SKL_PIN_UNBIND)
- continue;
- found = true;
- break;
- }
-
- if (!found)
- mcfg->m_state = SKL_MODULE_INIT_DONE;
- return;
-}
-
-/*
- * A module needs to be instanataited in DSP. A mdoule is present in a
- * collection of module referred as a PIPE.
- * We first calculate the module format, based on module type and then
- * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper
- */
-int skl_init_module(struct skl_dev *skl,
- struct skl_module_cfg *mconfig)
-{
- u16 module_config_size = 0;
- void *param_data = NULL;
- int ret;
- struct skl_ipc_init_instance_msg msg;
-
- dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__,
- mconfig->id.module_id, mconfig->id.pvt_id);
-
- if (mconfig->pipe->state != SKL_PIPE_CREATED) {
- dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n",
- mconfig->pipe->state, mconfig->pipe->ppl_id);
- return -EIO;
- }
-
- ret = skl_set_module_format(skl, mconfig,
- &module_config_size, &param_data);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to set module format ret=%d\n", ret);
- return ret;
- }
-
- msg.module_id = mconfig->id.module_id;
- msg.instance_id = mconfig->id.pvt_id;
- msg.ppl_instance_id = mconfig->pipe->ppl_id;
- msg.param_data_size = module_config_size;
- msg.core_id = mconfig->core_id;
- msg.domain = mconfig->domain;
-
- ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to init instance ret=%d\n", ret);
- kfree(param_data);
- return ret;
- }
- mconfig->m_state = SKL_MODULE_INIT_DONE;
- kfree(param_data);
- return ret;
-}
-
-static void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg
- *src_module, struct skl_module_cfg *dst_module)
-{
- dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n",
- __func__, src_module->id.module_id, src_module->id.pvt_id);
- dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__,
- dst_module->id.module_id, dst_module->id.pvt_id);
-
- dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n",
- src_module->m_state, dst_module->m_state);
-}
-
-/*
- * On module freeup, we need to unbind the module with modules
- * it is already bind.
- * Find the pin allocated and unbind then using bind_unbind IPC
- */
-int skl_unbind_modules(struct skl_dev *skl,
- struct skl_module_cfg *src_mcfg,
- struct skl_module_cfg *dst_mcfg)
-{
- int ret;
- struct skl_ipc_bind_unbind_msg msg;
- struct skl_module_inst_id src_id = src_mcfg->id;
- struct skl_module_inst_id dst_id = dst_mcfg->id;
- int in_max = dst_mcfg->module->max_input_pins;
- int out_max = src_mcfg->module->max_output_pins;
- int src_index, dst_index, src_pin_state, dst_pin_state;
-
- skl_dump_bind_info(skl, src_mcfg, dst_mcfg);
-
- /* get src queue index */
- src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
- if (src_index < 0)
- return 0;
-
- msg.src_queue = src_index;
-
- /* get dst queue index */
- dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
- if (dst_index < 0)
- return 0;
-
- msg.dst_queue = dst_index;
-
- src_pin_state = src_mcfg->m_out_pin[src_index].pin_state;
- dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state;
-
- if (src_pin_state != SKL_PIN_BIND_DONE ||
- dst_pin_state != SKL_PIN_BIND_DONE)
- return 0;
-
- msg.module_id = src_mcfg->id.module_id;
- msg.instance_id = src_mcfg->id.pvt_id;
- msg.dst_module_id = dst_mcfg->id.module_id;
- msg.dst_instance_id = dst_mcfg->id.pvt_id;
- msg.bind = false;
-
- ret = skl_ipc_bind_unbind(&skl->ipc, &msg);
- if (!ret) {
- /* free queue only if unbind is success */
- skl_free_queue(src_mcfg->m_out_pin, src_index);
- skl_free_queue(dst_mcfg->m_in_pin, dst_index);
-
- /*
- * check only if src module bind state, bind is
- * always from src -> sink
- */
- skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg);
- }
-
- return ret;
-}
-
-#define CPR_SINK_FMT_PARAM_ID 2
-
-/*
- * Once a module is instantiated it need to be 'bind' with other modules in
- * the pipeline. For binding we need to find the module pins which are bind
- * together
- * This function finds the pins and then sends bund_unbind IPC message to
- * DSP using IPC helper
- */
-int skl_bind_modules(struct skl_dev *skl,
- struct skl_module_cfg *src_mcfg,
- struct skl_module_cfg *dst_mcfg)
-{
- int ret = 0;
- struct skl_ipc_bind_unbind_msg msg;
- int in_max = dst_mcfg->module->max_input_pins;
- int out_max = src_mcfg->module->max_output_pins;
- int src_index, dst_index;
- struct skl_module_fmt *format;
- struct skl_cpr_pin_fmt pin_fmt;
- struct skl_module *module;
- struct skl_module_iface *fmt;
-
- skl_dump_bind_info(skl, src_mcfg, dst_mcfg);
-
- if (src_mcfg->m_state < SKL_MODULE_INIT_DONE ||
- dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
- return 0;
-
- src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max);
- if (src_index < 0)
- return -EINVAL;
-
- msg.src_queue = src_index;
- dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max);
- if (dst_index < 0) {
- skl_free_queue(src_mcfg->m_out_pin, src_index);
- return -EINVAL;
- }
-
- /*
- * Copier module requires the separate large_config_set_ipc to
- * configure the pins other than 0
- */
- if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) {
- pin_fmt.sink_id = src_index;
- module = src_mcfg->module;
- fmt = &module->formats[src_mcfg->fmt_idx];
-
- /* Input fmt is same as that of src module input cfg */
- format = &fmt->inputs[0].fmt;
- fill_pin_params(&(pin_fmt.src_fmt), format);
-
- format = &fmt->outputs[src_index].fmt;
- fill_pin_params(&(pin_fmt.dst_fmt), format);
- ret = skl_set_module_params(skl, (void *)&pin_fmt,
- sizeof(struct skl_cpr_pin_fmt),
- CPR_SINK_FMT_PARAM_ID, src_mcfg);
-
- if (ret < 0)
- goto out;
- }
-
- msg.dst_queue = dst_index;
-
- dev_dbg(skl->dev, "src queue = %d dst queue =%d\n",
- msg.src_queue, msg.dst_queue);
-
- msg.module_id = src_mcfg->id.module_id;
- msg.instance_id = src_mcfg->id.pvt_id;
- msg.dst_module_id = dst_mcfg->id.module_id;
- msg.dst_instance_id = dst_mcfg->id.pvt_id;
- msg.bind = true;
-
- ret = skl_ipc_bind_unbind(&skl->ipc, &msg);
-
- if (!ret) {
- src_mcfg->m_state = SKL_MODULE_BIND_DONE;
- src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
- dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
- return ret;
- }
-out:
- /* error case , if IPC fails, clear the queue index */
- skl_free_queue(src_mcfg->m_out_pin, src_index);
- skl_free_queue(dst_mcfg->m_in_pin, dst_index);
-
- return ret;
-}
-
-static int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe,
- enum skl_ipc_pipeline_state state)
-{
- dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state);
-
- return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state);
-}
-
-/*
- * A pipeline is a collection of modules. Before a module in instantiated a
- * pipeline needs to be created for it.
- * This function creates pipeline, by sending create pipeline IPC messages
- * to FW
- */
-int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- int ret;
-
- dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id);
-
- ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages,
- pipe->pipe_priority, pipe->ppl_id,
- pipe->lp_mode);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to create pipeline\n");
- return ret;
- }
-
- pipe->state = SKL_PIPE_CREATED;
-
- return 0;
-}
-
-/*
- * A pipeline needs to be deleted on cleanup. If a pipeline is running,
- * then pause it first. Before actual deletion, pipeline should enter
- * reset state. Finish the procedure by sending delete pipeline IPC.
- * DSP will stop the DMA engines and release resources
- */
-int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- int ret;
-
- dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
-
- /* If pipe was not created in FW, do not try to delete it */
- if (pipe->state < SKL_PIPE_CREATED)
- return 0;
-
- /* If pipe is started, do stop the pipe in FW. */
- if (pipe->state >= SKL_PIPE_STARTED) {
- ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to stop pipeline\n");
- return ret;
- }
-
- pipe->state = SKL_PIPE_PAUSED;
- }
-
- /* reset pipe state before deletion */
- ret = skl_set_pipe_state(skl, pipe, PPL_RESET);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret);
- return ret;
- }
-
- pipe->state = SKL_PIPE_RESET;
-
- ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to delete pipeline\n");
- return ret;
- }
-
- pipe->state = SKL_PIPE_INVALID;
-
- return ret;
-}
-
-/*
- * A pipeline is also a scheduling entity in DSP which can be run, stopped
- * For processing data the pipe need to be run by sending IPC set pipe state
- * to DSP
- */
-int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- int ret;
-
- dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
-
- /* If pipe was not created in FW, do not try to pause or delete */
- if (pipe->state < SKL_PIPE_CREATED)
- return 0;
-
- /* Pipe has to be paused before it is started */
- ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to pause pipe\n");
- return ret;
- }
-
- pipe->state = SKL_PIPE_PAUSED;
-
- ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to start pipe\n");
- return ret;
- }
-
- pipe->state = SKL_PIPE_STARTED;
-
- return 0;
-}
-
-/*
- * Stop the pipeline by sending set pipe state IPC
- * DSP doesnt implement stop so we always send pause message
- */
-int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- int ret;
-
- dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id);
-
- /* If pipe was not created in FW, do not try to pause or delete */
- if (pipe->state < SKL_PIPE_PAUSED)
- return 0;
-
- ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED);
- if (ret < 0) {
- dev_dbg(skl->dev, "Failed to stop pipe\n");
- return ret;
- }
-
- pipe->state = SKL_PIPE_PAUSED;
-
- return 0;
-}
-
-/*
- * Reset the pipeline by sending set pipe state IPC this will reset the DMA
- * from the DSP side
- */
-int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- int ret;
-
- /* If pipe was not created in FW, do not try to pause or delete */
- if (pipe->state < SKL_PIPE_PAUSED)
- return 0;
-
- ret = skl_set_pipe_state(skl, pipe, PPL_RESET);
- if (ret < 0) {
- dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret);
- return ret;
- }
-
- pipe->state = SKL_PIPE_RESET;
-
- return 0;
-}
-
-/* Algo parameter set helper function */
-int skl_set_module_params(struct skl_dev *skl, u32 *params, int size,
- u32 param_id, struct skl_module_cfg *mcfg)
-{
- struct skl_ipc_large_config_msg msg;
-
- msg.module_id = mcfg->id.module_id;
- msg.instance_id = mcfg->id.pvt_id;
- msg.param_data_size = size;
- msg.large_param_id = param_id;
-
- return skl_ipc_set_large_config(&skl->ipc, &msg, params);
-}
-
-int skl_get_module_params(struct skl_dev *skl, u32 *params, int size,
- u32 param_id, struct skl_module_cfg *mcfg)
-{
- struct skl_ipc_large_config_msg msg;
- size_t bytes = size;
-
- msg.module_id = mcfg->id.module_id;
- msg.instance_id = mcfg->id.pvt_id;
- msg.param_data_size = size;
- msg.large_param_id = param_id;
-
- return skl_ipc_get_large_config(&skl->ipc, &msg, &params, &bytes);
-}
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
deleted file mode 100644
index e617b4c335a4..000000000000
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ /dev/null
@@ -1,269 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-nhlt.c - Intel SKL Platform NHLT parsing
- *
- * Copyright (C) 2015 Intel Corp
- * Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/pci.h>
-#include <sound/intel-nhlt.h>
-#include "skl.h"
-#include "skl-i2s.h"
-
-static void skl_nhlt_trim_space(char *trim)
-{
- char *s = trim;
- int cnt;
- int i;
-
- cnt = 0;
- for (i = 0; s[i]; i++) {
- if (!isspace(s[i]))
- s[cnt++] = s[i];
- }
-
- s[cnt] = '\0';
-}
-
-int skl_nhlt_update_topology_bin(struct skl_dev *skl)
-{
- struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
- struct hdac_bus *bus = skl_to_bus(skl);
- struct device *dev = bus->dev;
-
- dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n",
- nhlt->header.oem_id, nhlt->header.oem_table_id,
- nhlt->header.oem_revision);
-
- snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s",
- skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
- nhlt->header.oem_revision, "-tplg.bin");
-
- skl_nhlt_trim_space(skl->tplg_name);
-
- return 0;
-}
-
-static ssize_t platform_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
- struct skl_dev *skl = bus_to_skl(bus);
- struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
- char platform_id[32];
-
- sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id,
- nhlt->header.oem_id, nhlt->header.oem_table_id,
- nhlt->header.oem_revision);
-
- skl_nhlt_trim_space(platform_id);
- return sysfs_emit(buf, "%s\n", platform_id);
-}
-
-static DEVICE_ATTR_RO(platform_id);
-
-int skl_nhlt_create_sysfs(struct skl_dev *skl)
-{
- struct device *dev = &skl->pci->dev;
-
- if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr))
- dev_warn(dev, "Error creating sysfs entry\n");
-
- return 0;
-}
-
-void skl_nhlt_remove_sysfs(struct skl_dev *skl)
-{
- struct device *dev = &skl->pci->dev;
-
- if (skl->nhlt)
- sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
-}
-
-/*
- * Queries NHLT for all the fmt configuration for a particular endpoint and
- * stores all possible rates supported in a rate table for the corresponding
- * sclk/sclkfs.
- */
-static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
- struct nhlt_fmt *fmt, u8 id)
-{
- struct skl_i2s_config_blob_ext *i2s_config_ext;
- struct skl_i2s_config_blob_legacy *i2s_config;
- struct skl_clk_parent_src *parent;
- struct skl_ssp_clk *sclk, *sclkfs;
- struct nhlt_fmt_cfg *fmt_cfg;
- struct wav_fmt_ext *wav_fmt;
- unsigned long rate;
- int rate_index = 0;
- u16 channels, bps;
- u8 clk_src;
- int i, j;
- u32 fs;
-
- sclk = &ssp_clks[SKL_SCLK_OFS];
- sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
-
- if (fmt->fmt_count == 0)
- return;
-
- fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
- for (i = 0; i < fmt->fmt_count; i++) {
- struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
- bool present = false;
-
- wav_fmt = &saved_fmt_cfg->fmt_ext;
-
- channels = wav_fmt->fmt.channels;
- bps = wav_fmt->fmt.bits_per_sample;
- fs = wav_fmt->fmt.samples_per_sec;
-
- /*
- * In case of TDM configuration on a ssp, there can
- * be more than one blob in which channel masks are
- * different for each usecase for a specific rate and bps.
- * But the sclk rate will be generated for the total
- * number of channels used for that endpoint.
- *
- * So for the given fs and bps, choose blob which has
- * the superset of all channels for that endpoint and
- * derive the rate.
- */
- for (j = i; j < fmt->fmt_count; j++) {
- struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
-
- wav_fmt = &tmp_fmt_cfg->fmt_ext;
- if ((fs == wav_fmt->fmt.samples_per_sec) &&
- (bps == wav_fmt->fmt.bits_per_sample)) {
- channels = max_t(u16, channels,
- wav_fmt->fmt.channels);
- saved_fmt_cfg = tmp_fmt_cfg;
- }
- /* Move to the next nhlt_fmt_cfg */
- tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
- tmp_fmt_cfg->config.size);
- }
-
- rate = channels * bps * fs;
-
- /* check if the rate is added already to the given SSP's sclk */
- for (j = 0; (j < SKL_MAX_CLK_RATES) &&
- (sclk[id].rate_cfg[j].rate != 0); j++) {
- if (sclk[id].rate_cfg[j].rate == rate) {
- present = true;
- break;
- }
- }
-
- /* Fill rate and parent for sclk/sclkfs */
- if (!present) {
- struct nhlt_fmt_cfg *first_fmt_cfg;
-
- first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
- i2s_config_ext = (struct skl_i2s_config_blob_ext *)
- first_fmt_cfg->config.caps;
-
- /* MCLK Divider Source Select */
- if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
- i2s_config = ext_to_legacy_blob(i2s_config_ext);
- clk_src = get_clk_src(i2s_config->mclk,
- SKL_MNDSS_DIV_CLK_SRC_MASK);
- } else {
- clk_src = get_clk_src(i2s_config_ext->mclk,
- SKL_MNDSS_DIV_CLK_SRC_MASK);
- }
-
- parent = skl_get_parent_clk(clk_src);
-
- /* Move to the next nhlt_fmt_cfg */
- fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
- fmt_cfg->config.size);
- /*
- * Do not copy the config data if there is no parent
- * clock available for this clock source select
- */
- if (!parent)
- continue;
-
- sclk[id].rate_cfg[rate_index].rate = rate;
- sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
- sclkfs[id].rate_cfg[rate_index].rate = rate;
- sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
- sclk[id].parent_name = parent->name;
- sclkfs[id].parent_name = parent->name;
-
- rate_index++;
- }
- }
-}
-
-static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
- struct nhlt_fmt *fmt, u8 id)
-{
- struct skl_i2s_config_blob_ext *i2s_config_ext;
- struct skl_i2s_config_blob_legacy *i2s_config;
- struct nhlt_fmt_cfg *fmt_cfg;
- struct skl_clk_parent_src *parent;
- u32 clkdiv, div_ratio;
- u8 clk_src;
-
- fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
- i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
-
- /* MCLK Divider Source Select and divider */
- if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
- i2s_config = ext_to_legacy_blob(i2s_config_ext);
- clk_src = get_clk_src(i2s_config->mclk,
- SKL_MCLK_DIV_CLK_SRC_MASK);
- clkdiv = i2s_config->mclk.mdivr &
- SKL_MCLK_DIV_RATIO_MASK;
- } else {
- clk_src = get_clk_src(i2s_config_ext->mclk,
- SKL_MCLK_DIV_CLK_SRC_MASK);
- clkdiv = i2s_config_ext->mclk.mdivr[0] &
- SKL_MCLK_DIV_RATIO_MASK;
- }
-
- /* bypass divider */
- div_ratio = 1;
-
- if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
- /* Divider is 2 + clkdiv */
- div_ratio = clkdiv + 2;
-
- /* Calculate MCLK rate from source using div value */
- parent = skl_get_parent_clk(clk_src);
- if (!parent)
- return;
-
- mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
- mclk[id].rate_cfg[0].config = fmt_cfg;
- mclk[id].parent_name = parent->name;
-}
-
-void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks)
-{
- struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
- struct nhlt_endpoint *epnt;
- struct nhlt_fmt *fmt;
- int i;
- u8 id;
-
- epnt = (struct nhlt_endpoint *)nhlt->desc;
- for (i = 0; i < nhlt->endpoint_count; i++) {
- if (epnt->linktype == NHLT_LINK_SSP) {
- id = epnt->virtual_bus_id;
-
- fmt = (struct nhlt_fmt *)(epnt->config.caps
- + epnt->config.size);
-
- skl_get_ssp_clks(skl, ssp_clks, fmt, id);
- skl_get_mclk(skl, ssp_clks, fmt, id);
- }
- epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
- }
-}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
deleted file mode 100644
index a4209d88b0c6..000000000000
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ /dev/null
@@ -1,1505 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality
- *
- * Copyright (C) 2014-2015 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/pci.h>
-#include <linux/pm_runtime.h>
-#include <linux/delay.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include "skl.h"
-#include "skl-topology.h"
-#include "skl-sst-dsp.h"
-#include "skl-sst-ipc.h"
-
-#define HDA_MONO 1
-#define HDA_STEREO 2
-#define HDA_QUAD 4
-#define HDA_MAX 8
-
-static const struct snd_pcm_hardware azx_pcm_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
- SNDRV_PCM_INFO_HAS_LINK_ATIME |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_8000,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 8,
- .buffer_bytes_max = AZX_MAX_BUF_SIZE,
- .period_bytes_min = 128,
- .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
- .periods_min = 2,
- .periods_max = AZX_MAX_FRAG,
- .fifo_size = 0,
-};
-
-static inline
-struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream)
-{
- return substream->runtime->private_data;
-}
-
-static struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream)
-{
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
- struct hdac_stream *hstream = hdac_stream(stream);
- struct hdac_bus *bus = hstream->bus;
- return bus;
-}
-
-static int skl_substream_alloc_pages(struct hdac_bus *bus,
- struct snd_pcm_substream *substream,
- size_t size)
-{
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
-
- hdac_stream(stream)->bufsize = 0;
- hdac_stream(stream)->period_bytes = 0;
- hdac_stream(stream)->format_val = 0;
-
- return 0;
-}
-
-static void skl_set_pcm_constrains(struct hdac_bus *bus,
- struct snd_pcm_runtime *runtime)
-{
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-
- /* avoid wrap-around with wall-clock */
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
- 20, 178000000);
-}
-
-static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus)
-{
- if (bus->ppcap)
- return HDAC_EXT_STREAM_TYPE_HOST;
- else
- return HDAC_EXT_STREAM_TYPE_COUPLED;
-}
-
-/*
- * check if the stream opened is marked as ignore_suspend by machine, if so
- * then enable suspend_active refcount
- *
- * The count supend_active does not need lock as it is used in open/close
- * and suspend context
- */
-static void skl_set_suspend_active(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai, bool enable)
-{
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct snd_soc_dapm_widget *w;
- struct skl_dev *skl = bus_to_skl(bus);
-
- w = snd_soc_dai_get_widget(dai, substream->stream);
-
- if (w->ignore_suspend && enable)
- skl->supend_active++;
- else if (w->ignore_suspend && !enable)
- skl->supend_active--;
-}
-
-int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct skl_dev *skl = bus_to_skl(bus);
- unsigned int format_val;
- struct hdac_stream *hstream;
- struct hdac_ext_stream *stream;
- int err;
-
- hstream = snd_hdac_get_stream(bus, params->stream,
- params->host_dma_id + 1);
- if (!hstream)
- return -EINVAL;
-
- stream = stream_to_hdac_ext_stream(hstream);
- snd_hdac_ext_stream_decouple(bus, stream, true);
-
- format_val = snd_hdac_calc_stream_format(params->s_freq,
- params->ch, params->format, params->host_bps, 0);
-
- dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
- format_val, params->s_freq, params->ch, params->format);
-
- snd_hdac_stream_reset(hdac_stream(stream));
- err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
- if (err < 0)
- return err;
-
- /*
- * The recommended SDxFMT programming sequence for BXT
- * platforms is to couple the stream before writing the format
- */
- if (IS_BXT(skl->pci)) {
- snd_hdac_ext_stream_decouple(bus, stream, false);
- err = snd_hdac_stream_setup(hdac_stream(stream));
- snd_hdac_ext_stream_decouple(bus, stream, true);
- } else {
- err = snd_hdac_stream_setup(hdac_stream(stream));
- }
-
- if (err < 0)
- return err;
-
- hdac_stream(stream)->prepared = 1;
-
- return 0;
-}
-
-int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- unsigned int format_val;
- struct hdac_stream *hstream;
- struct hdac_ext_stream *stream;
- struct hdac_ext_link *link;
- unsigned char stream_tag;
-
- hstream = snd_hdac_get_stream(bus, params->stream,
- params->link_dma_id + 1);
- if (!hstream)
- return -EINVAL;
-
- stream = stream_to_hdac_ext_stream(hstream);
- snd_hdac_ext_stream_decouple(bus, stream, true);
- format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
- params->format, params->link_bps, 0);
-
- dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
- format_val, params->s_freq, params->ch, params->format);
-
- snd_hdac_ext_stream_reset(stream);
-
- snd_hdac_ext_stream_setup(stream, format_val);
-
- stream_tag = hstream->stream_tag;
- if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
- list_for_each_entry(link, &bus->hlink_list, list) {
- if (link->index == params->link_index)
- snd_hdac_ext_bus_link_set_stream_id(link,
- stream_tag);
- }
- }
-
- stream->link_prepared = 1;
-
- return 0;
-}
-
-static int skl_pcm_open(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct hdac_ext_stream *stream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct skl_dma_params *dma_params;
- struct skl_dev *skl = get_skl_ctx(dai->dev);
- struct skl_module_cfg *mconfig;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-
- stream = snd_hdac_ext_stream_assign(bus, substream,
- skl_get_host_stream_type(bus));
- if (stream == NULL)
- return -EBUSY;
-
- skl_set_pcm_constrains(bus, runtime);
-
- /*
- * disable WALLCLOCK timestamps for capture streams
- * until we figure out how to handle digital inputs
- */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */
- runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME;
- }
-
- runtime->private_data = stream;
-
- dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL);
- if (!dma_params)
- return -ENOMEM;
-
- dma_params->stream_tag = hdac_stream(stream)->stream_tag;
- snd_soc_dai_set_dma_data(dai, substream, dma_params);
-
- dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
- dma_params->stream_tag);
- skl_set_suspend_active(substream, dai, true);
- snd_pcm_set_sync(substream);
-
- mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
- if (!mconfig)
- return -EINVAL;
-
- skl_tplg_d0i3_get(skl, mconfig->d0i3_caps);
-
- return 0;
-}
-
-static int skl_pcm_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct skl_dev *skl = get_skl_ctx(dai->dev);
- struct skl_module_cfg *mconfig;
- int ret;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-
- mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
-
- /*
- * In case of XRUN recovery or in the case when the application
- * calls prepare another time, reset the FW pipe to clean state
- */
- if (mconfig &&
- (substream->runtime->state == SNDRV_PCM_STATE_XRUN ||
- mconfig->pipe->state == SKL_PIPE_CREATED ||
- mconfig->pipe->state == SKL_PIPE_PAUSED)) {
-
- ret = skl_reset_pipe(skl, mconfig->pipe);
-
- if (ret < 0)
- return ret;
-
- ret = skl_pcm_host_dma_prepare(dai->dev,
- mconfig->pipe->p_params);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct skl_pipe_params p_params = {0};
- struct skl_module_cfg *m_cfg;
- int ret, dma_id;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- ret = skl_substream_alloc_pages(bus, substream,
- params_buffer_bytes(params));
- if (ret < 0)
- return ret;
-
- dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n",
- runtime->rate, runtime->channels, runtime->format);
-
- dma_id = hdac_stream(stream)->stream_tag - 1;
- dev_dbg(dai->dev, "dma_id=%d\n", dma_id);
-
- p_params.s_fmt = snd_pcm_format_width(params_format(params));
- p_params.s_cont = snd_pcm_format_physical_width(params_format(params));
- p_params.ch = params_channels(params);
- p_params.s_freq = params_rate(params);
- p_params.host_dma_id = dma_id;
- p_params.stream = substream->stream;
- p_params.format = params_format(params);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- p_params.host_bps = dai->driver->playback.sig_bits;
- else
- p_params.host_bps = dai->driver->capture.sig_bits;
-
-
- m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream);
- if (m_cfg)
- skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params);
-
- return 0;
-}
-
-static void skl_pcm_close(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct skl_dma_params *dma_params = NULL;
- struct skl_dev *skl = bus_to_skl(bus);
- struct skl_module_cfg *mconfig;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-
- snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus));
-
- dma_params = snd_soc_dai_get_dma_data(dai, substream);
- /*
- * now we should set this to NULL as we are freeing by the
- * dma_params
- */
- snd_soc_dai_set_dma_data(dai, substream, NULL);
- skl_set_suspend_active(substream, dai, false);
-
- /*
- * check if close is for "Reference Pin" and set back the
- * CGCTL.MISCBDCGE if disabled by driver
- */
- if (!strncmp(dai->name, "Reference Pin", 13) &&
- skl->miscbdcg_disabled) {
- skl->enable_miscbdcge(dai->dev, true);
- skl->miscbdcg_disabled = false;
- }
-
- mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
- if (mconfig)
- skl_tplg_d0i3_put(skl, mconfig->d0i3_caps);
-
- kfree(dma_params);
-}
-
-static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
- struct skl_dev *skl = get_skl_ctx(dai->dev);
- struct skl_module_cfg *mconfig;
- int ret;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-
- mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
-
- if (mconfig) {
- ret = skl_reset_pipe(skl, mconfig->pipe);
- if (ret < 0)
- dev_err(dai->dev, "%s:Reset failed ret =%d",
- __func__, ret);
- }
-
- snd_hdac_stream_cleanup(hdac_stream(stream));
- hdac_stream(stream)->prepared = 0;
-
- return 0;
-}
-
-static int skl_be_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct skl_pipe_params p_params = {0};
-
- p_params.s_fmt = snd_pcm_format_width(params_format(params));
- p_params.s_cont = snd_pcm_format_physical_width(params_format(params));
- p_params.ch = params_channels(params);
- p_params.s_freq = params_rate(params);
- p_params.stream = substream->stream;
-
- return skl_tplg_be_update_params(dai, &p_params);
-}
-
-static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct hdac_bus *bus = get_bus_ctx(substream);
- struct hdac_ext_stream *stream;
- int start;
- unsigned long cookie;
- struct hdac_stream *hstr;
-
- stream = get_hdac_ext_stream(substream);
- hstr = hdac_stream(stream);
-
- if (!hstr->prepared)
- return -EPIPE;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- start = 1;
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- start = 0;
- break;
-
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&bus->reg_lock, cookie);
-
- if (start) {
- snd_hdac_stream_start(hdac_stream(stream));
- snd_hdac_stream_timecounter_init(hstr, 0);
- } else {
- snd_hdac_stream_stop(hdac_stream(stream));
- }
-
- spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
- return 0;
-}
-
-static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct skl_dev *skl = get_skl_ctx(dai->dev);
- struct skl_module_cfg *mconfig;
- struct hdac_bus *bus = get_bus_ctx(substream);
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
- struct hdac_stream *hstream = hdac_stream(stream);
- struct snd_soc_dapm_widget *w;
- int ret;
-
- mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
- if (!mconfig)
- return -EIO;
-
- w = snd_soc_dai_get_widget(dai, substream->stream);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_RESUME:
- if (!w->ignore_suspend) {
- /*
- * enable DMA Resume enable bit for the stream, set the
- * dpib & lpib position to resume before starting the
- * DMA
- */
- snd_hdac_stream_drsm_enable(bus, true, hstream->index);
- snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);
- snd_hdac_stream_set_lpib(hstream, hstream->lpib);
- }
- fallthrough;
-
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- /*
- * Start HOST DMA and Start FE Pipe.This is to make sure that
- * there are no underrun/overrun in the case when the FE
- * pipeline is started but there is a delay in starting the
- * DMA channel on the host.
- */
- ret = skl_decoupled_trigger(substream, cmd);
- if (ret < 0)
- return ret;
- return skl_run_pipe(skl, mconfig->pipe);
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- /*
- * Stop FE Pipe first and stop DMA. This is to make sure that
- * there are no underrun/overrun in the case if there is a delay
- * between the two operations.
- */
- ret = skl_stop_pipe(skl, mconfig->pipe);
- if (ret < 0)
- return ret;
-
- ret = skl_decoupled_trigger(substream, cmd);
- if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
- /* save the dpib and lpib positions */
- hstream->dpib = readl(bus->remap_addr +
- AZX_REG_VS_SDXDPIB_XBASE +
- (AZX_REG_VS_SDXDPIB_XINTERVAL *
- hstream->index));
-
- hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream);
-
- snd_hdac_ext_stream_decouple(bus, stream, false);
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-static int skl_link_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct hdac_ext_stream *link_dev;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct skl_pipe_params p_params = {0};
- struct hdac_ext_link *link;
- int stream_tag;
-
- link_dev = snd_hdac_ext_stream_assign(bus, substream,
- HDAC_EXT_STREAM_TYPE_LINK);
- if (!link_dev)
- return -EBUSY;
-
- snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
-
- link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
- if (!link)
- return -EINVAL;
-
- stream_tag = hdac_stream(link_dev)->stream_tag;
-
- /* set the hdac_stream in the codec dai */
- snd_soc_dai_set_stream(codec_dai, hdac_stream(link_dev), substream->stream);
-
- p_params.s_fmt = snd_pcm_format_width(params_format(params));
- p_params.s_cont = snd_pcm_format_physical_width(params_format(params));
- p_params.ch = params_channels(params);
- p_params.s_freq = params_rate(params);
- p_params.stream = substream->stream;
- p_params.link_dma_id = stream_tag - 1;
- p_params.link_index = link->index;
- p_params.format = params_format(params);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- p_params.link_bps = codec_dai->driver->playback.sig_bits;
- else
- p_params.link_bps = codec_dai->driver->capture.sig_bits;
-
- return skl_tplg_be_update_params(dai, &p_params);
-}
-
-static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct skl_dev *skl = get_skl_ctx(dai->dev);
- struct skl_module_cfg *mconfig = NULL;
-
- /* In case of XRUN recovery, reset the FW pipe to clean state */
- mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
- if (mconfig && !mconfig->pipe->passthru &&
- (substream->runtime->state == SNDRV_PCM_STATE_XRUN))
- skl_reset_pipe(skl, mconfig->pipe);
-
- return 0;
-}
-
-static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
-{
- struct hdac_ext_stream *link_dev =
- snd_soc_dai_get_dma_data(dai, substream);
- struct hdac_bus *bus = get_bus_ctx(substream);
- struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
-
- dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_hdac_ext_stream_start(link_dev);
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- snd_hdac_ext_stream_clear(link_dev);
- if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
- snd_hdac_ext_stream_decouple(bus, stream, false);
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int skl_link_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct hdac_ext_stream *link_dev =
- snd_soc_dai_get_dma_data(dai, substream);
- struct hdac_ext_link *link;
- unsigned char stream_tag;
-
- dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-
- link_dev->link_prepared = 0;
-
- link = snd_hdac_ext_bus_get_hlink_by_name(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
- if (!link)
- return -EINVAL;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag);
- }
-
- snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
- return 0;
-}
-
-static const struct snd_soc_dai_ops skl_pcm_dai_ops = {
- .startup = skl_pcm_open,
- .shutdown = skl_pcm_close,
- .prepare = skl_pcm_prepare,
- .hw_params = skl_pcm_hw_params,
- .hw_free = skl_pcm_hw_free,
- .trigger = skl_pcm_trigger,
-};
-
-static const struct snd_soc_dai_ops skl_dmic_dai_ops = {
- .hw_params = skl_be_hw_params,
-};
-
-static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
- .hw_params = skl_be_hw_params,
-};
-
-static const struct snd_soc_dai_ops skl_link_dai_ops = {
- .prepare = skl_link_pcm_prepare,
- .hw_params = skl_link_hw_params,
- .hw_free = skl_link_hw_free,
- .trigger = skl_link_pcm_trigger,
-};
-
-static struct snd_soc_dai_driver skl_fe_dai[] = {
-{
- .name = "System Pin",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "System Playback",
- .channels_min = HDA_MONO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
- .sig_bits = 32,
- },
- .capture = {
- .stream_name = "System Capture",
- .channels_min = HDA_MONO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "System Pin2",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "Headset Playback",
- .channels_min = HDA_MONO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
- },
-},
-{
- .name = "Echoref Pin",
- .ops = &skl_pcm_dai_ops,
- .capture = {
- .stream_name = "Echoreference Capture",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
- },
-},
-{
- .name = "Reference Pin",
- .ops = &skl_pcm_dai_ops,
- .capture = {
- .stream_name = "Reference Capture",
- .channels_min = HDA_MONO,
- .channels_max = HDA_QUAD,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "Deepbuffer Pin",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "Deepbuffer Playback",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "LowLatency Pin",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "Low Latency Playback",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "DMIC Pin",
- .ops = &skl_pcm_dai_ops,
- .capture = {
- .stream_name = "DMIC Capture",
- .channels_min = HDA_MONO,
- .channels_max = HDA_QUAD,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "HDMI1 Pin",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "HDMI1 Playback",
- .channels_min = HDA_STEREO,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
- SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "HDMI2 Pin",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "HDMI2 Playback",
- .channels_min = HDA_STEREO,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
- SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- .sig_bits = 32,
- },
-},
-{
- .name = "HDMI3 Pin",
- .ops = &skl_pcm_dai_ops,
- .playback = {
- .stream_name = "HDMI3 Playback",
- .channels_min = HDA_STEREO,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
- SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- .sig_bits = 32,
- },
-},
-};
-
-/* BE CPU Dais */
-static struct snd_soc_dai_driver skl_platform_dai[] = {
-{
- .name = "SSP0 Pin",
- .ops = &skl_be_ssp_dai_ops,
- .playback = {
- .stream_name = "ssp0 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "ssp0 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "SSP1 Pin",
- .ops = &skl_be_ssp_dai_ops,
- .playback = {
- .stream_name = "ssp1 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "ssp1 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "SSP2 Pin",
- .ops = &skl_be_ssp_dai_ops,
- .playback = {
- .stream_name = "ssp2 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "ssp2 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "SSP3 Pin",
- .ops = &skl_be_ssp_dai_ops,
- .playback = {
- .stream_name = "ssp3 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "ssp3 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "SSP4 Pin",
- .ops = &skl_be_ssp_dai_ops,
- .playback = {
- .stream_name = "ssp4 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "ssp4 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "SSP5 Pin",
- .ops = &skl_be_ssp_dai_ops,
- .playback = {
- .stream_name = "ssp5 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "ssp5 Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "iDisp1 Pin",
- .ops = &skl_link_dai_ops,
- .playback = {
- .stream_name = "iDisp1 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "iDisp2 Pin",
- .ops = &skl_link_dai_ops,
- .playback = {
- .stream_name = "iDisp2 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
- SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "iDisp3 Pin",
- .ops = &skl_link_dai_ops,
- .playback = {
- .stream_name = "iDisp3 Tx",
- .channels_min = HDA_STEREO,
- .channels_max = 8,
- .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
- SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "DMIC01 Pin",
- .ops = &skl_dmic_dai_ops,
- .capture = {
- .stream_name = "DMIC01 Rx",
- .channels_min = HDA_MONO,
- .channels_max = HDA_QUAD,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "DMIC16k Pin",
- .ops = &skl_dmic_dai_ops,
- .capture = {
- .stream_name = "DMIC16k Rx",
- .channels_min = HDA_MONO,
- .channels_max = HDA_QUAD,
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-{
- .name = "Analog CPU DAI",
- .ops = &skl_link_dai_ops,
- .playback = {
- .stream_name = "Analog CPU Playback",
- .channels_min = HDA_MONO,
- .channels_max = HDA_MAX,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
- .capture = {
- .stream_name = "Analog CPU Capture",
- .channels_min = HDA_MONO,
- .channels_max = HDA_MAX,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
-},
-{
- .name = "Alt Analog CPU DAI",
- .ops = &skl_link_dai_ops,
- .playback = {
- .stream_name = "Alt Analog CPU Playback",
- .channels_min = HDA_MONO,
- .channels_max = HDA_MAX,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
- .capture = {
- .stream_name = "Alt Analog CPU Capture",
- .channels_min = HDA_MONO,
- .channels_max = HDA_MAX,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
-},
-{
- .name = "Digital CPU DAI",
- .ops = &skl_link_dai_ops,
- .playback = {
- .stream_name = "Digital CPU Playback",
- .channels_min = HDA_MONO,
- .channels_max = HDA_MAX,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
- .capture = {
- .stream_name = "Digital CPU Capture",
- .channels_min = HDA_MONO,
- .channels_max = HDA_MAX,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
-},
-};
-
-int skl_dai_load(struct snd_soc_component *cmp, int index,
- struct snd_soc_dai_driver *dai_drv,
- struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
-{
- dai_drv->ops = &skl_pcm_dai_ops;
-
- return 0;
-}
-
-static int skl_platform_soc_open(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai_link *dai_link = rtd->dai_link;
-
- dev_dbg(asoc_rtd_to_cpu(rtd, 0)->dev, "In %s:%s\n", __func__,
- dai_link->cpus->dai_name);
-
- snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw);
-
- return 0;
-}
-
-static int skl_coupled_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct hdac_bus *bus = get_bus_ctx(substream);
- struct hdac_ext_stream *stream;
- struct snd_pcm_substream *s;
- bool start;
- int sbits = 0;
- unsigned long cookie;
- struct hdac_stream *hstr;
-
- stream = get_hdac_ext_stream(substream);
- hstr = hdac_stream(stream);
-
- dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd);
-
- if (!hstr->prepared)
- return -EPIPE;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- start = true;
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- start = false;
- break;
-
- default:
- return -EINVAL;
- }
-
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- stream = get_hdac_ext_stream(s);
- sbits |= 1 << hdac_stream(stream)->index;
- snd_pcm_trigger_done(s, substream);
- }
-
- spin_lock_irqsave(&bus->reg_lock, cookie);
-
- /* first, set SYNC bits of corresponding streams */
- snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC);
-
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- stream = get_hdac_ext_stream(s);
- if (start)
- snd_hdac_stream_start(hdac_stream(stream));
- else
- snd_hdac_stream_stop(hdac_stream(stream));
- }
- spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
- snd_hdac_stream_sync(hstr, start, sbits);
-
- spin_lock_irqsave(&bus->reg_lock, cookie);
-
- /* reset SYNC bits */
- snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC);
- if (start)
- snd_hdac_stream_timecounter_init(hstr, sbits);
- spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
- return 0;
-}
-
-static int skl_platform_soc_trigger(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- int cmd)
-{
- struct hdac_bus *bus = get_bus_ctx(substream);
-
- if (!bus->ppcap)
- return skl_coupled_trigger(substream, cmd);
-
- return 0;
-}
-
-static snd_pcm_uframes_t skl_platform_soc_pointer(
- struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
- struct hdac_bus *bus = get_bus_ctx(substream);
- unsigned int pos;
-
- /*
- * Use DPIB for Playback stream as the periodic DMA Position-in-
- * Buffer Writes may be scheduled at the same time or later than
- * the MSI and does not guarantee to reflect the Position of the
- * last buffer that was transferred. Whereas DPIB register in
- * HAD space reflects the actual data that is transferred.
- * Use the position buffer for capture, as DPIB write gets
- * completed earlier than the actual data written to the DDR.
- *
- * For capture stream following workaround is required to fix the
- * incorrect position reporting.
- *
- * 1. Wait for 20us before reading the DMA position in buffer once
- * the interrupt is generated for stream completion as update happens
- * on the HDA frame boundary i.e. 20.833uSec.
- * 2. Read DPIB register to flush the DMA position value. This dummy
- * read is required to flush DMA position value.
- * 3. Read the DMA Position-in-Buffer. This value now will be equal to
- * or greater than period boundary.
- */
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
- (AZX_REG_VS_SDXDPIB_XINTERVAL *
- hdac_stream(hstream)->index));
- } else {
- udelay(20);
- readl(bus->remap_addr +
- AZX_REG_VS_SDXDPIB_XBASE +
- (AZX_REG_VS_SDXDPIB_XINTERVAL *
- hdac_stream(hstream)->index));
- pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
- }
-
- if (pos >= hdac_stream(hstream)->bufsize)
- pos = 0;
-
- return bytes_to_frames(substream->runtime, pos);
-}
-
-static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream,
- u64 nsec)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- u64 codec_frames, codec_nsecs;
-
- if (!codec_dai->driver->ops->delay)
- return nsec;
-
- codec_frames = codec_dai->driver->ops->delay(substream, codec_dai);
- codec_nsecs = div_u64(codec_frames * 1000000000LL,
- substream->runtime->rate);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- return nsec + codec_nsecs;
-
- return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
-}
-
-static int skl_platform_soc_get_time_info(
- struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- struct timespec64 *system_ts, struct timespec64 *audio_ts,
- struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
- struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
-{
- struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream);
- struct hdac_stream *hstr = hdac_stream(sstream);
- u64 nsec;
-
- if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
- (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) {
-
- snd_pcm_gettime(substream->runtime, system_ts);
-
- nsec = timecounter_read(&hstr->tc);
- if (audio_tstamp_config->report_delay)
- nsec = skl_adjust_codec_delay(substream, nsec);
-
- *audio_ts = ns_to_timespec64(nsec);
-
- audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
- audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */
- audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */
-
- } else {
- audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
- }
-
- return 0;
-}
-
-#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
-
-static int skl_platform_soc_new(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
- struct hdac_bus *bus = dev_get_drvdata(dai->dev);
- struct snd_pcm *pcm = rtd->pcm;
- unsigned int size;
- struct skl_dev *skl = bus_to_skl(bus);
-
- if (dai->driver->playback.channels_min ||
- dai->driver->capture.channels_min) {
- /* buffer pre-allocation */
- size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
- if (size > MAX_PREALLOC_SIZE)
- size = MAX_PREALLOC_SIZE;
- snd_pcm_set_managed_buffer_all(pcm,
- SNDRV_DMA_TYPE_DEV_SG,
- &skl->pci->dev,
- size, MAX_PREALLOC_SIZE);
- }
-
- return 0;
-}
-
-static int skl_get_module_info(struct skl_dev *skl,
- struct skl_module_cfg *mconfig)
-{
- struct skl_module_inst_id *pin_id;
- guid_t *uuid_mod, *uuid_tplg;
- struct skl_module *skl_module;
- struct uuid_module *module;
- int i, ret = -EIO;
-
- uuid_mod = (guid_t *)mconfig->guid;
-
- if (list_empty(&skl->uuid_list)) {
- dev_err(skl->dev, "Module list is empty\n");
- return -EIO;
- }
-
- for (i = 0; i < skl->nr_modules; i++) {
- skl_module = skl->modules[i];
- uuid_tplg = &skl_module->uuid;
- if (guid_equal(uuid_mod, uuid_tplg)) {
- mconfig->module = skl_module;
- ret = 0;
- break;
- }
- }
-
- if (skl->nr_modules && ret)
- return ret;
-
- ret = -EIO;
- list_for_each_entry(module, &skl->uuid_list, list) {
- if (guid_equal(uuid_mod, &module->uuid)) {
- mconfig->id.module_id = module->id;
- mconfig->module->loadable = module->is_loadable;
- ret = 0;
- }
-
- for (i = 0; i < MAX_IN_QUEUE; i++) {
- pin_id = &mconfig->m_in_pin[i].id;
- if (guid_equal(&pin_id->mod_uuid, &module->uuid))
- pin_id->module_id = module->id;
- }
-
- for (i = 0; i < MAX_OUT_QUEUE; i++) {
- pin_id = &mconfig->m_out_pin[i].id;
- if (guid_equal(&pin_id->mod_uuid, &module->uuid))
- pin_id->module_id = module->id;
- }
- }
-
- return ret;
-}
-
-static int skl_populate_modules(struct skl_dev *skl)
-{
- struct skl_pipeline *p;
- struct skl_pipe_module *m;
- struct snd_soc_dapm_widget *w;
- struct skl_module_cfg *mconfig;
- int ret = 0;
-
- list_for_each_entry(p, &skl->ppl_list, node) {
- list_for_each_entry(m, &p->pipe->w_list, node) {
- w = m->w;
- mconfig = w->priv;
-
- ret = skl_get_module_info(skl, mconfig);
- if (ret < 0) {
- dev_err(skl->dev,
- "query module info failed\n");
- return ret;
- }
-
- skl_tplg_add_moduleid_in_bind_params(skl, w);
- }
- }
-
- return ret;
-}
-
-static int skl_platform_soc_probe(struct snd_soc_component *component)
-{
- struct hdac_bus *bus = dev_get_drvdata(component->dev);
- struct skl_dev *skl = bus_to_skl(bus);
- const struct skl_dsp_ops *ops;
- int ret;
-
- ret = pm_runtime_resume_and_get(component->dev);
- if (ret < 0 && ret != -EACCES)
- return ret;
-
- if (bus->ppcap) {
- skl->component = component;
-
- /* init debugfs */
- skl->debugfs = skl_debugfs_init(skl);
-
- ret = skl_tplg_init(component, bus);
- if (ret < 0) {
- dev_err(component->dev, "Failed to init topology!\n");
- return ret;
- }
-
- /* load the firmwares, since all is set */
- ops = skl_get_dsp_ops(skl->pci->device);
- if (!ops)
- return -EIO;
-
- /*
- * Disable dynamic clock and power gating during firmware
- * and library download
- */
- skl->enable_miscbdcge(component->dev, false);
- skl->clock_power_gating(component->dev, false);
-
- ret = ops->init_fw(component->dev, skl);
- skl->enable_miscbdcge(component->dev, true);
- skl->clock_power_gating(component->dev, true);
- if (ret < 0) {
- dev_err(component->dev, "Failed to boot first fw: %d\n", ret);
- return ret;
- }
- skl_populate_modules(skl);
- skl->update_d0i3c = skl_update_d0i3c;
-
- if (skl->cfg.astate_cfg != NULL) {
- skl_dsp_set_astate_cfg(skl,
- skl->cfg.astate_cfg->count,
- skl->cfg.astate_cfg);
- }
- }
- pm_runtime_mark_last_busy(component->dev);
- pm_runtime_put_autosuspend(component->dev);
-
- return 0;
-}
-
-static void skl_platform_soc_remove(struct snd_soc_component *component)
-{
- struct hdac_bus *bus = dev_get_drvdata(component->dev);
- struct skl_dev *skl = bus_to_skl(bus);
-
- skl_tplg_exit(component, bus);
-
- skl_debugfs_exit(skl);
-}
-
-static const struct snd_soc_component_driver skl_component = {
- .name = "pcm",
- .probe = skl_platform_soc_probe,
- .remove = skl_platform_soc_remove,
- .open = skl_platform_soc_open,
- .trigger = skl_platform_soc_trigger,
- .pointer = skl_platform_soc_pointer,
- .get_time_info = skl_platform_soc_get_time_info,
- .pcm_construct = skl_platform_soc_new,
- .module_get_upon_open = 1, /* increment refcount when a pcm is opened */
-};
-
-int skl_platform_register(struct device *dev)
-{
- int ret;
- struct snd_soc_dai_driver *dais;
- int num_dais = ARRAY_SIZE(skl_platform_dai);
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct skl_dev *skl = bus_to_skl(bus);
-
- skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai),
- GFP_KERNEL);
- if (!skl->dais) {
- ret = -ENOMEM;
- goto err;
- }
-
- if (!skl->use_tplg_pcm) {
- dais = krealloc(skl->dais, sizeof(skl_fe_dai) +
- sizeof(skl_platform_dai), GFP_KERNEL);
- if (!dais) {
- ret = -ENOMEM;
- goto err;
- }
-
- skl->dais = dais;
- memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai,
- sizeof(skl_fe_dai));
- num_dais += ARRAY_SIZE(skl_fe_dai);
- }
-
- ret = devm_snd_soc_register_component(dev, &skl_component,
- skl->dais, num_dais);
- if (ret)
- dev_err(dev, "soc component registration failed %d\n", ret);
-err:
- return ret;
-}
-
-int skl_platform_unregister(struct device *dev)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
- struct skl_dev *skl = bus_to_skl(bus);
- struct skl_module_deferred_bind *modules, *tmp;
-
- list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
- list_del(&modules->node);
- kfree(modules);
- }
-
- kfree(skl->dais);
-
- return 0;
-}
diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c
deleted file mode 100644
index 50e93c3707e8..000000000000
--- a/sound/soc/intel/skylake/skl-ssp-clk.c
+++ /dev/null
@@ -1,428 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright(c) 2015-17 Intel Corporation
-
-/*
- * skl-ssp-clk.c - ASoC skylake ssp clock driver
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <sound/intel-nhlt.h>
-#include "skl.h"
-#include "skl-ssp-clk.h"
-#include "skl-topology.h"
-
-#define to_skl_clk(_hw) container_of(_hw, struct skl_clk, hw)
-
-struct skl_clk_parent {
- struct clk_hw *hw;
- struct clk_lookup *lookup;
-};
-
-struct skl_clk {
- struct clk_hw hw;
- struct clk_lookup *lookup;
- unsigned long rate;
- struct skl_clk_pdata *pdata;
- u32 id;
-};
-
-struct skl_clk_data {
- struct skl_clk_parent parent[SKL_MAX_CLK_SRC];
- struct skl_clk *clk[SKL_MAX_CLK_CNT];
- u8 avail_clk_cnt;
-};
-
-static int skl_get_clk_type(u32 index)
-{
- switch (index) {
- case 0 ... (SKL_SCLK_OFS - 1):
- return SKL_MCLK;
-
- case SKL_SCLK_OFS ... (SKL_SCLKFS_OFS - 1):
- return SKL_SCLK;
-
- case SKL_SCLKFS_OFS ... (SKL_MAX_CLK_CNT - 1):
- return SKL_SCLK_FS;
-
- default:
- return -EINVAL;
- }
-}
-
-static int skl_get_vbus_id(u32 index, u8 clk_type)
-{
- switch (clk_type) {
- case SKL_MCLK:
- return index;
-
- case SKL_SCLK:
- return index - SKL_SCLK_OFS;
-
- case SKL_SCLK_FS:
- return index - SKL_SCLKFS_OFS;
-
- default:
- return -EINVAL;
- }
-}
-
-static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type)
-{
- struct nhlt_fmt_cfg *fmt_cfg;
- union skl_clk_ctrl_ipc *ipc;
- struct wav_fmt *wfmt;
-
- if (!rcfg)
- return;
-
- ipc = &rcfg->dma_ctl_ipc;
- if (clk_type == SKL_SCLK_FS) {
- fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config;
- wfmt = &fmt_cfg->fmt_ext.fmt;
-
- /* Remove TLV Header size */
- ipc->sclk_fs.hdr.size = sizeof(struct skl_dmactrl_sclkfs_cfg) -
- sizeof(struct skl_tlv_hdr);
- ipc->sclk_fs.sampling_frequency = wfmt->samples_per_sec;
- ipc->sclk_fs.bit_depth = wfmt->bits_per_sample;
- ipc->sclk_fs.valid_bit_depth =
- fmt_cfg->fmt_ext.sample.valid_bits_per_sample;
- ipc->sclk_fs.number_of_channels = wfmt->channels;
- } else {
- ipc->mclk.hdr.type = DMA_CLK_CONTROLS;
- /* Remove TLV Header size */
- ipc->mclk.hdr.size = sizeof(struct skl_dmactrl_mclk_cfg) -
- sizeof(struct skl_tlv_hdr);
- }
-}
-
-/* Sends dma control IPC to turn the clock ON/OFF */
-static int skl_send_clk_dma_control(struct skl_dev *skl,
- struct skl_clk_rate_cfg_table *rcfg,
- u32 vbus_id, u8 clk_type,
- bool enable)
-{
- struct nhlt_specific_cfg *sp_cfg;
- u32 i2s_config_size, node_id = 0;
- struct nhlt_fmt_cfg *fmt_cfg;
- union skl_clk_ctrl_ipc *ipc;
- void *i2s_config = NULL;
- u8 *data, size;
- int ret;
-
- if (!rcfg)
- return -EIO;
-
- ipc = &rcfg->dma_ctl_ipc;
- fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config;
- sp_cfg = &fmt_cfg->config;
-
- if (clk_type == SKL_SCLK_FS) {
- ipc->sclk_fs.hdr.type =
- enable ? DMA_TRANSMITION_START : DMA_TRANSMITION_STOP;
- data = (u8 *)&ipc->sclk_fs;
- size = sizeof(struct skl_dmactrl_sclkfs_cfg);
- } else {
- /* 1 to enable mclk, 0 to enable sclk */
- if (clk_type == SKL_SCLK)
- ipc->mclk.mclk = 0;
- else
- ipc->mclk.mclk = 1;
-
- ipc->mclk.keep_running = enable;
- ipc->mclk.warm_up_over = enable;
- ipc->mclk.clk_stop_over = !enable;
- data = (u8 *)&ipc->mclk;
- size = sizeof(struct skl_dmactrl_mclk_cfg);
- }
-
- i2s_config_size = sp_cfg->size + size;
- i2s_config = kzalloc(i2s_config_size, GFP_KERNEL);
- if (!i2s_config)
- return -ENOMEM;
-
- /* copy blob */
- memcpy(i2s_config, sp_cfg->caps, sp_cfg->size);
-
- /* copy additional dma controls information */
- memcpy(i2s_config + sp_cfg->size, data, size);
-
- node_id = ((SKL_DMA_I2S_LINK_INPUT_CLASS << 8) | (vbus_id << 4));
- ret = skl_dsp_set_dma_control(skl, (u32 *)i2s_config,
- i2s_config_size, node_id);
- kfree(i2s_config);
-
- return ret;
-}
-
-static struct skl_clk_rate_cfg_table *skl_get_rate_cfg(
- struct skl_clk_rate_cfg_table *rcfg,
- unsigned long rate)
-{
- int i;
-
- for (i = 0; (i < SKL_MAX_CLK_RATES) && rcfg[i].rate; i++) {
- if (rcfg[i].rate == rate)
- return &rcfg[i];
- }
-
- return NULL;
-}
-
-static int skl_clk_change_status(struct skl_clk *clkdev,
- bool enable)
-{
- struct skl_clk_rate_cfg_table *rcfg;
- int vbus_id, clk_type;
-
- clk_type = skl_get_clk_type(clkdev->id);
- if (clk_type < 0)
- return clk_type;
-
- vbus_id = skl_get_vbus_id(clkdev->id, clk_type);
- if (vbus_id < 0)
- return vbus_id;
-
- rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg,
- clkdev->rate);
- if (!rcfg)
- return -EINVAL;
-
- return skl_send_clk_dma_control(clkdev->pdata->pvt_data, rcfg,
- vbus_id, clk_type, enable);
-}
-
-static int skl_clk_prepare(struct clk_hw *hw)
-{
- struct skl_clk *clkdev = to_skl_clk(hw);
-
- return skl_clk_change_status(clkdev, true);
-}
-
-static void skl_clk_unprepare(struct clk_hw *hw)
-{
- struct skl_clk *clkdev = to_skl_clk(hw);
-
- skl_clk_change_status(clkdev, false);
-}
-
-static int skl_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct skl_clk *clkdev = to_skl_clk(hw);
- struct skl_clk_rate_cfg_table *rcfg;
- int clk_type;
-
- if (!rate)
- return -EINVAL;
-
- rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg,
- rate);
- if (!rcfg)
- return -EINVAL;
-
- clk_type = skl_get_clk_type(clkdev->id);
- if (clk_type < 0)
- return clk_type;
-
- skl_fill_clk_ipc(rcfg, clk_type);
- clkdev->rate = rate;
-
- return 0;
-}
-
-static unsigned long skl_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct skl_clk *clkdev = to_skl_clk(hw);
-
- if (clkdev->rate)
- return clkdev->rate;
-
- return 0;
-}
-
-/* Not supported by clk driver. Implemented to satisfy clk fw */
-static long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
-{
- return rate;
-}
-
-/*
- * prepare/unprepare are used instead of enable/disable as IPC will be sent
- * in non-atomic context.
- */
-static const struct clk_ops skl_clk_ops = {
- .prepare = skl_clk_prepare,
- .unprepare = skl_clk_unprepare,
- .set_rate = skl_clk_set_rate,
- .round_rate = skl_clk_round_rate,
- .recalc_rate = skl_clk_recalc_rate,
-};
-
-static void unregister_parent_src_clk(struct skl_clk_parent *pclk,
- unsigned int id)
-{
- while (id--) {
- clkdev_drop(pclk[id].lookup);
- clk_hw_unregister_fixed_rate(pclk[id].hw);
- }
-}
-
-static void unregister_src_clk(struct skl_clk_data *dclk)
-{
- while (dclk->avail_clk_cnt--)
- clkdev_drop(dclk->clk[dclk->avail_clk_cnt]->lookup);
-}
-
-static int skl_register_parent_clks(struct device *dev,
- struct skl_clk_parent *parent,
- struct skl_clk_parent_src *pclk)
-{
- int i, ret;
-
- for (i = 0; i < SKL_MAX_CLK_SRC; i++) {
-
- /* Register Parent clock */
- parent[i].hw = clk_hw_register_fixed_rate(dev, pclk[i].name,
- pclk[i].parent_name, 0, pclk[i].rate);
- if (IS_ERR(parent[i].hw)) {
- ret = PTR_ERR(parent[i].hw);
- goto err;
- }
-
- parent[i].lookup = clkdev_hw_create(parent[i].hw, pclk[i].name,
- NULL);
- if (!parent[i].lookup) {
- clk_hw_unregister_fixed_rate(parent[i].hw);
- ret = -ENOMEM;
- goto err;
- }
- }
-
- return 0;
-err:
- unregister_parent_src_clk(parent, i);
- return ret;
-}
-
-/* Assign fmt_config to clk_data */
-static struct skl_clk *register_skl_clk(struct device *dev,
- struct skl_ssp_clk *clk,
- struct skl_clk_pdata *clk_pdata, int id)
-{
- struct clk_init_data init;
- struct skl_clk *clkdev;
- int ret;
-
- clkdev = devm_kzalloc(dev, sizeof(*clkdev), GFP_KERNEL);
- if (!clkdev)
- return ERR_PTR(-ENOMEM);
-
- init.name = clk->name;
- init.ops = &skl_clk_ops;
- init.flags = CLK_SET_RATE_GATE;
- init.parent_names = &clk->parent_name;
- init.num_parents = 1;
- clkdev->hw.init = &init;
- clkdev->pdata = clk_pdata;
-
- clkdev->id = id;
- ret = devm_clk_hw_register(dev, &clkdev->hw);
- if (ret) {
- clkdev = ERR_PTR(ret);
- return clkdev;
- }
-
- clkdev->lookup = clkdev_hw_create(&clkdev->hw, init.name, NULL);
- if (!clkdev->lookup)
- clkdev = ERR_PTR(-ENOMEM);
-
- return clkdev;
-}
-
-static int skl_clk_dev_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device *parent_dev = dev->parent;
- struct skl_clk_parent_src *parent_clks;
- struct skl_clk_pdata *clk_pdata;
- struct skl_clk_data *data;
- struct skl_ssp_clk *clks;
- int ret, i;
-
- clk_pdata = dev_get_platdata(&pdev->dev);
- parent_clks = clk_pdata->parent_clks;
- clks = clk_pdata->ssp_clks;
- if (!parent_clks || !clks)
- return -EIO;
-
- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- /* Register Parent clock */
- ret = skl_register_parent_clks(parent_dev, data->parent, parent_clks);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < clk_pdata->num_clks; i++) {
- /*
- * Only register valid clocks
- * i.e. for which nhlt entry is present.
- */
- if (clks[i].rate_cfg[0].rate == 0)
- continue;
-
- data->clk[data->avail_clk_cnt] = register_skl_clk(dev,
- &clks[i], clk_pdata, i);
-
- if (IS_ERR(data->clk[data->avail_clk_cnt])) {
- ret = PTR_ERR(data->clk[data->avail_clk_cnt]);
- goto err_unreg_skl_clk;
- }
-
- data->avail_clk_cnt++;
- }
-
- platform_set_drvdata(pdev, data);
-
- return 0;
-
-err_unreg_skl_clk:
- unregister_src_clk(data);
- unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC);
-
- return ret;
-}
-
-static void skl_clk_dev_remove(struct platform_device *pdev)
-{
- struct skl_clk_data *data;
-
- data = platform_get_drvdata(pdev);
- unregister_src_clk(data);
- unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC);
-}
-
-static struct platform_driver skl_clk_driver = {
- .driver = {
- .name = "skl-ssp-clk",
- },
- .probe = skl_clk_dev_probe,
- .remove_new = skl_clk_dev_remove,
-};
-
-module_platform_driver(skl_clk_driver);
-
-MODULE_DESCRIPTION("Skylake clock driver");
-MODULE_AUTHOR("Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>");
-MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:skl-ssp-clk");
diff --git a/sound/soc/intel/skylake/skl-ssp-clk.h b/sound/soc/intel/skylake/skl-ssp-clk.h
deleted file mode 100644
index b7852c7f277b..000000000000
--- a/sound/soc/intel/skylake/skl-ssp-clk.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * skl-ssp-clk.h - Skylake ssp clock information and ipc structure
- *
- * Copyright (C) 2017 Intel Corp
- * Author: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
- * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#ifndef SOUND_SOC_SKL_SSP_CLK_H
-#define SOUND_SOC_SKL_SSP_CLK_H
-
-#define SKL_MAX_SSP 6
-/* xtal/cardinal/pll, parent of ssp clocks and mclk */
-#define SKL_MAX_CLK_SRC 3
-#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */
-
-#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES)
-
-/* Max number of configurations supported for each clock */
-#define SKL_MAX_CLK_RATES 10
-
-#define SKL_SCLK_OFS SKL_MAX_SSP
-#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP)
-
-enum skl_clk_type {
- SKL_MCLK,
- SKL_SCLK,
- SKL_SCLK_FS,
-};
-
-enum skl_clk_src_type {
- SKL_XTAL,
- SKL_CARDINAL,
- SKL_PLL,
-};
-
-struct skl_clk_parent_src {
- u8 clk_id;
- const char *name;
- unsigned long rate;
- const char *parent_name;
-};
-
-struct skl_tlv_hdr {
- u32 type;
- u32 size;
-};
-
-struct skl_dmactrl_mclk_cfg {
- struct skl_tlv_hdr hdr;
- /* DMA Clk TLV params */
- u32 clk_warm_up:16;
- u32 mclk:1;
- u32 warm_up_over:1;
- u32 rsvd0:14;
- u32 clk_stop_delay:16;
- u32 keep_running:1;
- u32 clk_stop_over:1;
- u32 rsvd1:14;
-};
-
-struct skl_dmactrl_sclkfs_cfg {
- struct skl_tlv_hdr hdr;
- /* DMA SClk&FS TLV params */
- u32 sampling_frequency;
- u32 bit_depth;
- u32 channel_map;
- u32 channel_config;
- u32 interleaving_style;
- u32 number_of_channels : 8;
- u32 valid_bit_depth : 8;
- u32 sample_type : 8;
- u32 reserved : 8;
-};
-
-union skl_clk_ctrl_ipc {
- struct skl_dmactrl_mclk_cfg mclk;
- struct skl_dmactrl_sclkfs_cfg sclk_fs;
-};
-
-struct skl_clk_rate_cfg_table {
- unsigned long rate;
- union skl_clk_ctrl_ipc dma_ctl_ipc;
- void *config;
-};
-
-/*
- * rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store
- * all possible clocks ssp can generate for that platform.
- */
-struct skl_ssp_clk {
- const char *name;
- const char *parent_name;
- struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES];
-};
-
-struct skl_clk_pdata {
- struct skl_clk_parent_src *parent_clks;
- int num_clks;
- struct skl_ssp_clk *ssp_clks;
- void *pvt_data;
-};
-
-#endif /* SOUND_SOC_SKL_SSP_CLK_H */
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
deleted file mode 100644
index b0204ea00f07..000000000000
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ /dev/null
@@ -1,373 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-sst-cldma.c - Code Loader DMA handler
- *
- * Copyright (C) 2015, Intel Corporation.
- * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <sound/hda_register.h>
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-
-static void skl_cldma_int_enable(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC,
- SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA);
-}
-
-void skl_cldma_int_disable(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0);
-}
-
-static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable)
-{
- unsigned char val;
- int timeout;
-
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable));
-
- udelay(3);
- timeout = 300;
- do {
- /* waiting for hardware to report that the stream Run bit set */
- val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) &
- CL_SD_CTL_RUN_MASK;
- if (enable && val)
- break;
- else if (!enable && !val)
- break;
- udelay(3);
- } while (--timeout);
-
- if (timeout == 0)
- dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable);
-}
-
-static void skl_cldma_stream_clear(struct sst_dsp *ctx)
-{
- /* make sure Run bit is cleared before setting stream register */
- skl_cldma_stream_run(ctx, 0);
-
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
-
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
-
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
-}
-
-/* Code loader helper APIs */
-static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
- struct snd_dma_buffer *dmab_data,
- __le32 **bdlp, int size, int with_ioc)
-{
- __le32 *bdl = *bdlp;
- int remaining = ctx->cl_dev.bufsize;
- int offset = 0;
-
- ctx->cl_dev.frags = 0;
- while (remaining > 0) {
- phys_addr_t addr;
- int chunk;
-
- addr = snd_sgbuf_get_addr(dmab_data, offset);
- bdl[0] = cpu_to_le32(lower_32_bits(addr));
- bdl[1] = cpu_to_le32(upper_32_bits(addr));
- chunk = snd_sgbuf_get_chunk_size(dmab_data, offset, size);
- bdl[2] = cpu_to_le32(chunk);
-
- remaining -= chunk;
- bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01);
-
- bdl += 4;
- offset += chunk;
- ctx->cl_dev.frags++;
- }
-}
-
-/*
- * Setup controller
- * Configure the registers to update the dma buffer address and
- * enable interrupts.
- * Note: Using the channel 1 for transfer
- */
-static void skl_cldma_setup_controller(struct sst_dsp *ctx,
- struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
- u32 count)
-{
- skl_cldma_stream_clear(ctx);
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL,
- CL_SD_BDLPLBA(dmab_bdl->addr));
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU,
- CL_SD_BDLPUBA(dmab_bdl->addr));
-
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size);
- sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1);
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1));
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
- CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER));
-}
-
-static void skl_cldma_setup_spb(struct sst_dsp *ctx,
- unsigned int size, bool enable)
-{
- if (enable)
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL,
- CL_SPBFIFO_SPBFCCTL_SPIBE_MASK,
- CL_SPBFIFO_SPBFCCTL_SPIBE(1));
-
- sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size);
-}
-
-static void skl_cldma_cleanup_spb(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL,
- CL_SPBFIFO_SPBFCCTL_SPIBE_MASK,
- CL_SPBFIFO_SPBFCCTL_SPIBE(0));
-
- sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0);
-}
-
-static void skl_cldma_cleanup(struct sst_dsp *ctx)
-{
- skl_cldma_cleanup_spb(ctx);
- skl_cldma_stream_clear(ctx);
-
- ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
- ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl);
-}
-
-int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
-{
- int ret = 0;
-
- if (!wait_event_timeout(ctx->cl_dev.wait_queue,
- ctx->cl_dev.wait_condition,
- msecs_to_jiffies(SKL_WAIT_TIMEOUT))) {
- dev_err(ctx->dev, "%s: Wait timeout\n", __func__);
- ret = -EIO;
- goto cleanup;
- }
-
- dev_dbg(ctx->dev, "%s: Event wake\n", __func__);
- if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) {
- dev_err(ctx->dev, "%s: DMA Error\n", __func__);
- ret = -EIO;
- }
-
-cleanup:
- ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE;
- return ret;
-}
-
-static void skl_cldma_stop(struct sst_dsp *ctx)
-{
- skl_cldma_stream_run(ctx, false);
-}
-
-static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
- const void *curr_pos, bool intr_enable, bool trigger)
-{
- dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable);
- dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n",
- ctx->cl_dev.dma_buffer_offset, trigger);
- dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
-
- /*
- * Check if the size exceeds buffer boundary. If it exceeds
- * max_buffer size, then copy till buffer size and then copy
- * remaining buffer from the start of ring buffer.
- */
- if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) {
- unsigned int size_b = ctx->cl_dev.bufsize -
- ctx->cl_dev.dma_buffer_offset;
- memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
- curr_pos, size_b);
- size -= size_b;
- curr_pos += size_b;
- ctx->cl_dev.dma_buffer_offset = 0;
- }
-
- memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
- curr_pos, size);
-
- if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize)
- ctx->cl_dev.dma_buffer_offset = 0;
- else
- ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos;
-
- ctx->cl_dev.wait_condition = false;
-
- if (intr_enable)
- skl_cldma_int_enable(ctx);
-
- ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger);
- if (trigger)
- ctx->cl_dev.ops.cl_trigger(ctx, true);
-}
-
-/*
- * The CL dma doesn't have any way to update the transfer status until a BDL
- * buffer is fully transferred
- *
- * So Copying is divided in two parts.
- * 1. Interrupt on buffer done where the size to be transferred is more than
- * ring buffer size.
- * 2. Polling on fw register to identify if data left to transferred doesn't
- * fill the ring buffer. Caller takes care of polling the required status
- * register to identify the transfer status.
- * 3. if wait flag is set, waits for DBL interrupt to copy the next chunk till
- * bytes_left is 0.
- * if wait flag is not set, doesn't wait for BDL interrupt. after ccopying
- * the first chunk return the no of bytes_left to be copied.
- */
-static int
-skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin,
- u32 total_size, bool wait)
-{
- int ret;
- bool start = true;
- unsigned int excess_bytes;
- u32 size;
- unsigned int bytes_left = total_size;
- const void *curr_pos = bin;
-
- if (total_size <= 0)
- return -EINVAL;
-
- dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left);
-
- while (bytes_left) {
- if (bytes_left > ctx->cl_dev.bufsize) {
-
- /*
- * dma transfers only till the write pointer as
- * updated in spib
- */
- if (ctx->cl_dev.curr_spib_pos == 0)
- ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize;
-
- size = ctx->cl_dev.bufsize;
- skl_cldma_fill_buffer(ctx, size, curr_pos, true, start);
-
- if (wait) {
- start = false;
- ret = skl_cldma_wait_interruptible(ctx);
- if (ret < 0) {
- skl_cldma_stop(ctx);
- return ret;
- }
- }
- } else {
- skl_cldma_int_disable(ctx);
-
- if ((ctx->cl_dev.curr_spib_pos + bytes_left)
- <= ctx->cl_dev.bufsize) {
- ctx->cl_dev.curr_spib_pos += bytes_left;
- } else {
- excess_bytes = bytes_left -
- (ctx->cl_dev.bufsize -
- ctx->cl_dev.curr_spib_pos);
- ctx->cl_dev.curr_spib_pos = excess_bytes;
- }
-
- size = bytes_left;
- skl_cldma_fill_buffer(ctx, size,
- curr_pos, false, start);
- }
- bytes_left -= size;
- curr_pos = curr_pos + size;
- if (!wait)
- return bytes_left;
- }
-
- return bytes_left;
-}
-
-void skl_cldma_process_intr(struct sst_dsp *ctx)
-{
- u8 cl_dma_intr_status;
-
- cl_dma_intr_status =
- sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS);
-
- if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE))
- ctx->cl_dev.wake_status = SKL_CL_DMA_ERR;
- else
- ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE;
-
- ctx->cl_dev.wait_condition = true;
- wake_up(&ctx->cl_dev.wait_queue);
-}
-
-int skl_cldma_prepare(struct sst_dsp *ctx)
-{
- int ret;
- __le32 *bdl;
-
- ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE;
-
- /* Allocate cl ops */
- ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle;
- ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller;
- ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb;
- ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb;
- ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run;
- ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup;
- ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf;
- ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
-
- /* Allocate buffer*/
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize,
- &ctx->cl_dev.dmab_data);
- if (ret < 0) {
- dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret);
- return ret;
- }
-
- /* Setup Code loader BDL */
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl);
- if (ret < 0) {
- dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret);
- ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
- return ret;
- }
- bdl = (__le32 *)ctx->cl_dev.dmab_bdl.area;
-
- /* Allocate BDLs */
- ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data,
- &bdl, ctx->cl_dev.bufsize, 1);
- ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl,
- ctx->cl_dev.bufsize, ctx->cl_dev.frags);
-
- ctx->cl_dev.curr_spib_pos = 0;
- ctx->cl_dev.dma_buffer_offset = 0;
- init_waitqueue_head(&ctx->cl_dev.wait_queue);
-
- return ret;
-}
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h
deleted file mode 100644
index d5e285a69baa..000000000000
--- a/sound/soc/intel/skylake/skl-sst-cldma.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel Code Loader DMA support
- *
- * Copyright (C) 2015, Intel Corporation.
- */
-
-#ifndef SKL_SST_CLDMA_H_
-#define SKL_SST_CLDMA_H_
-
-#define FW_CL_STREAM_NUMBER 0x1
-
-#define DMA_ADDRESS_128_BITS_ALIGNMENT 7
-#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT)
-
-#define SKL_ADSPIC_CL_DMA 0x2
-#define SKL_ADSPIS_CL_DMA 0x2
-#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */
-#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
-#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */
-
-/* Intel HD Audio Code Loader DMA Registers */
-
-#define HDA_ADSP_LOADER_BASE 0x80
-
-/* Stream Registers */
-#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00)
-#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03)
-#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04)
-#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08)
-#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c)
-#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e)
-#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10)
-#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12)
-#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14)
-#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18)
-#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c)
-
-/* CL: Software Position Based FIFO Capability Registers */
-#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20)
-#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0)
-#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4)
-#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8)
-#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc)
-
-/* CL: Stream Descriptor x Control */
-
-/* Stream Reset */
-#define CL_SD_CTL_SRST_SHIFT 0
-#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT)
-#define CL_SD_CTL_SRST(x) \
- ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK)
-
-/* Stream Run */
-#define CL_SD_CTL_RUN_SHIFT 1
-#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT)
-#define CL_SD_CTL_RUN(x) \
- ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK)
-
-/* Interrupt On Completion Enable */
-#define CL_SD_CTL_IOCE_SHIFT 2
-#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT)
-#define CL_SD_CTL_IOCE(x) \
- ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK)
-
-/* FIFO Error Interrupt Enable */
-#define CL_SD_CTL_FEIE_SHIFT 3
-#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT)
-#define CL_SD_CTL_FEIE(x) \
- ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK)
-
-/* Descriptor Error Interrupt Enable */
-#define CL_SD_CTL_DEIE_SHIFT 4
-#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT)
-#define CL_SD_CTL_DEIE(x) \
- ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK)
-
-/* FIFO Limit Change */
-#define CL_SD_CTL_FIFOLC_SHIFT 5
-#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT)
-#define CL_SD_CTL_FIFOLC(x) \
- ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK)
-
-/* Stripe Control */
-#define CL_SD_CTL_STRIPE_SHIFT 16
-#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT)
-#define CL_SD_CTL_STRIPE(x) \
- ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK)
-
-/* Traffic Priority */
-#define CL_SD_CTL_TP_SHIFT 18
-#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT)
-#define CL_SD_CTL_TP(x) \
- ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK)
-
-/* Bidirectional Direction Control */
-#define CL_SD_CTL_DIR_SHIFT 19
-#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT)
-#define CL_SD_CTL_DIR(x) \
- ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK)
-
-/* Stream Number */
-#define CL_SD_CTL_STRM_SHIFT 20
-#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT)
-#define CL_SD_CTL_STRM(x) \
- ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK)
-
-/* CL: Stream Descriptor x Status */
-
-/* Buffer Completion Interrupt Status */
-#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x)
-
-/* FIFO Error */
-#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x)
-
-/* Descriptor Error */
-#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x)
-
-/* FIFO Ready */
-#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x)
-
-
-/* CL: Stream Descriptor x Last Valid Index */
-#define CL_SD_LVI_SHIFT 0
-#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT)
-#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK)
-
-/* CL: Stream Descriptor x FIFO Eviction Watermark */
-#define CL_SD_FIFOW_SHIFT 0
-#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT)
-#define CL_SD_FIFOW(x) \
- ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK)
-
-/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */
-
-/* Protect Bits */
-#define CL_SD_BDLPLBA_PROT_SHIFT 0
-#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT)
-#define CL_SD_BDLPLBA_PROT(x) \
- ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK)
-
-/* Buffer Descriptor List Lower Base Address */
-#define CL_SD_BDLPLBA_SHIFT 7
-#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT)
-#define CL_SD_BDLPLBA(x) \
- ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK)
-
-/* Buffer Descriptor List Upper Base Address */
-#define CL_SD_BDLPUBA_SHIFT 0
-#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT)
-#define CL_SD_BDLPUBA(x) \
- ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK)
-
-/*
- * Code Loader - Software Position Based FIFO
- * Capability Registers x Software Position Based FIFO Header
- */
-
-/* Next Capability Pointer */
-#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0
-#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT)
-#define CL_SPBFIFO_SPBFCH_PTR(x) \
- ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK)
-
-/* Capability Identifier */
-#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16
-#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT)
-#define CL_SPBFIFO_SPBFCH_ID(x) \
- ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK)
-
-/* Capability Version */
-#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28
-#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT)
-#define CL_SPBFIFO_SPBFCH_VER(x) \
- ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK)
-
-/* Software Position in Buffer Enable */
-#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0
-#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT)
-#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \
- ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK)
-
-/* SST IPC SKL defines */
-#define SKL_WAIT_TIMEOUT 500 /* 500 msec */
-#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE)
-
-enum skl_cl_dma_wake_states {
- SKL_CL_DMA_STATUS_NONE = 0,
- SKL_CL_DMA_BUF_COMPLETE,
- SKL_CL_DMA_ERR, /* TODO: Expand the error states */
-};
-
-struct sst_dsp;
-
-struct skl_cl_dev_ops {
- void (*cl_setup_bdle)(struct sst_dsp *ctx,
- struct snd_dma_buffer *dmab_data,
- __le32 **bdlp, int size, int with_ioc);
- void (*cl_setup_controller)(struct sst_dsp *ctx,
- struct snd_dma_buffer *dmab_bdl,
- unsigned int max_size, u32 page_count);
- void (*cl_setup_spb)(struct sst_dsp *ctx,
- unsigned int size, bool enable);
- void (*cl_cleanup_spb)(struct sst_dsp *ctx);
- void (*cl_trigger)(struct sst_dsp *ctx, bool enable);
- void (*cl_cleanup_controller)(struct sst_dsp *ctx);
- int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx,
- const void *bin, u32 size, bool wait);
- void (*cl_stop_dma)(struct sst_dsp *ctx);
-};
-
-/**
- * skl_cl_dev - holds information for code loader dma transfer
- *
- * @dmab_data: buffer pointer
- * @dmab_bdl: buffer descriptor list
- * @bufsize: ring buffer size
- * @frags: Last valid buffer descriptor index in the BDL
- * @curr_spib_pos: Current position in ring buffer
- * @dma_buffer_offset: dma buffer offset
- * @ops: operations supported on CL dma
- * @wait_queue: wait queue to wake for wake event
- * @wake_status: DMA wake status
- * @wait_condition: condition to wait on wait queue
- * @cl_dma_lock: for synchronized access to cldma
- */
-struct skl_cl_dev {
- struct snd_dma_buffer dmab_data;
- struct snd_dma_buffer dmab_bdl;
-
- unsigned int bufsize;
- unsigned int frags;
-
- unsigned int curr_spib_pos;
- unsigned int dma_buffer_offset;
- struct skl_cl_dev_ops ops;
-
- wait_queue_head_t wait_queue;
- int wake_status;
- bool wait_condition;
-};
-
-#endif /* SKL_SST_CLDMA_H_ */
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c
deleted file mode 100644
index 4ae3eae0d1fd..000000000000
--- a/sound/soc/intel/skylake/skl-sst-dsp.c
+++ /dev/null
@@ -1,462 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-sst-dsp.c - SKL SST library generic function
- *
- * Copyright (C) 2014-15, Intel Corporation.
- * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
- * Jeeja KP <jeeja.kp@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <sound/pcm.h>
-
-#include "../common/sst-dsp.h"
-#include "../common/sst-ipc.h"
-#include "../common/sst-dsp-priv.h"
-#include "skl.h"
-
-/* various timeout values */
-#define SKL_DSP_PU_TO 50
-#define SKL_DSP_PD_TO 50
-#define SKL_DSP_RESET_TO 50
-
-void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
-{
- mutex_lock(&ctx->mutex);
- ctx->sst_state = state;
- mutex_unlock(&ctx->mutex);
-}
-
-/*
- * Initialize core power state and usage count. To be called after
- * successful first boot. Hence core 0 will be running and other cores
- * will be reset
- */
-void skl_dsp_init_core_state(struct sst_dsp *ctx)
-{
- struct skl_dev *skl = ctx->thread_context;
- int i;
-
- skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
- skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
-
- for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
- skl->cores.state[i] = SKL_DSP_RESET;
- skl->cores.usage_count[i] = 0;
- }
-}
-
-/* Get the mask for all enabled cores */
-unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx)
-{
- struct skl_dev *skl = ctx->thread_context;
- unsigned int core_mask, en_cores_mask;
- u32 val;
-
- core_mask = SKL_DSP_CORES_MASK(skl->cores.count);
-
- val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
-
- /* Cores having CPA bit set */
- en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >>
- SKL_ADSPCS_CPA_SHIFT;
-
- /* And cores having CRST bit cleared */
- en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >>
- SKL_ADSPCS_CRST_SHIFT;
-
- /* And cores having CSTALL bit cleared */
- en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >>
- SKL_ADSPCS_CSTALL_SHIFT;
- en_cores_mask &= core_mask;
-
- dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask);
-
- return en_cores_mask;
-}
-
-static int
-skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx,
- SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask),
- SKL_ADSPCS_CRST_MASK(core_mask));
-
- /* poll with timeout to check if operation successful */
- ret = sst_dsp_register_poll(ctx,
- SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CRST_MASK(core_mask),
- SKL_ADSPCS_CRST_MASK(core_mask),
- SKL_DSP_RESET_TO,
- "Set reset");
- if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
- SKL_ADSPCS_CRST_MASK(core_mask)) !=
- SKL_ADSPCS_CRST_MASK(core_mask)) {
- dev_err(ctx->dev, "Set reset state failed: core_mask %x\n",
- core_mask);
- ret = -EIO;
- }
-
- return ret;
-}
-
-int skl_dsp_core_unset_reset_state(
- struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- dev_dbg(ctx->dev, "In %s\n", __func__);
-
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CRST_MASK(core_mask), 0);
-
- /* poll with timeout to check if operation successful */
- ret = sst_dsp_register_poll(ctx,
- SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CRST_MASK(core_mask),
- 0,
- SKL_DSP_RESET_TO,
- "Unset reset");
-
- if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
- SKL_ADSPCS_CRST_MASK(core_mask)) != 0) {
- dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n",
- core_mask);
- ret = -EIO;
- }
-
- return ret;
-}
-
-static bool
-is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int val;
- bool is_enable;
-
- val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
-
- is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) &&
- (val & SKL_ADSPCS_SPA_MASK(core_mask)) &&
- !(val & SKL_ADSPCS_CRST_MASK(core_mask)) &&
- !(val & SKL_ADSPCS_CSTALL_MASK(core_mask)));
-
- dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n",
- is_enable, core_mask);
-
- return is_enable;
-}
-
-static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* stall core */
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CSTALL_MASK(core_mask),
- SKL_ADSPCS_CSTALL_MASK(core_mask));
-
- /* set reset state */
- return skl_dsp_core_set_reset_state(ctx, core_mask);
-}
-
-int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- /* unset reset state */
- ret = skl_dsp_core_unset_reset_state(ctx, core_mask);
- if (ret < 0)
- return ret;
-
- /* run core */
- dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask);
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CSTALL_MASK(core_mask), 0);
-
- if (!is_skl_dsp_core_enable(ctx, core_mask)) {
- skl_dsp_reset_core(ctx, core_mask);
- dev_err(ctx->dev, "DSP start core failed: core_mask %x\n",
- core_mask);
- ret = -EIO;
- }
-
- return ret;
-}
-
-int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_SPA_MASK(core_mask),
- SKL_ADSPCS_SPA_MASK(core_mask));
-
- /* poll with timeout to check if operation successful */
- ret = sst_dsp_register_poll(ctx,
- SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CPA_MASK(core_mask),
- SKL_ADSPCS_CPA_MASK(core_mask),
- SKL_DSP_PU_TO,
- "Power up");
-
- if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
- SKL_ADSPCS_CPA_MASK(core_mask)) !=
- SKL_ADSPCS_CPA_MASK(core_mask)) {
- dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n",
- core_mask);
- ret = -EIO;
- }
-
- return ret;
-}
-
-int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
-{
- /* update bits */
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_SPA_MASK(core_mask), 0);
-
- /* poll with timeout to check if operation successful */
- return sst_dsp_register_poll(ctx,
- SKL_ADSP_REG_ADSPCS,
- SKL_ADSPCS_CPA_MASK(core_mask),
- 0,
- SKL_DSP_PD_TO,
- "Power down");
-}
-
-int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- /* power up */
- ret = skl_dsp_core_power_up(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n",
- core_mask);
- return ret;
- }
-
- return skl_dsp_start_core(ctx, core_mask);
-}
-
-int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
-{
- int ret;
-
- ret = skl_dsp_reset_core(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n",
- core_mask);
- return ret;
- }
-
- /* power down core*/
- ret = skl_dsp_core_power_down(ctx, core_mask);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n",
- core_mask, ret);
- return ret;
- }
-
- if (is_skl_dsp_core_enable(ctx, core_mask)) {
- dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n",
- core_mask, ret);
- ret = -EIO;
- }
-
- return ret;
-}
-
-int skl_dsp_boot(struct sst_dsp *ctx)
-{
- int ret;
-
- if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) {
- ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret);
- return ret;
- }
-
- ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret);
- return ret;
- }
- } else {
- ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- if (ret < 0) {
- dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret);
- return ret;
- }
- ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
- }
-
- return ret;
-}
-
-irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
-{
- struct sst_dsp *ctx = dev_id;
- u32 val;
- irqreturn_t result = IRQ_NONE;
-
- spin_lock(&ctx->spinlock);
-
- val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS);
- ctx->intr_status = val;
-
- if (val == 0xffffffff) {
- spin_unlock(&ctx->spinlock);
- return IRQ_NONE;
- }
-
- if (val & SKL_ADSPIS_IPC) {
- skl_ipc_int_disable(ctx);
- result = IRQ_WAKE_THREAD;
- }
-
- if (val & SKL_ADSPIS_CL_DMA) {
- skl_cldma_int_disable(ctx);
- result = IRQ_WAKE_THREAD;
- }
-
- spin_unlock(&ctx->spinlock);
-
- return result;
-}
-/*
- * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context
- * within the dapm mutex. Hence no separate lock is used.
- */
-int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
-{
- struct skl_dev *skl = ctx->thread_context;
- int ret = 0;
-
- if (core_id >= skl->cores.count) {
- dev_err(ctx->dev, "invalid core id: %d\n", core_id);
- return -EINVAL;
- }
-
- skl->cores.usage_count[core_id]++;
-
- if (skl->cores.state[core_id] == SKL_DSP_RESET) {
- ret = ctx->fw_ops.set_state_D0(ctx, core_id);
- if (ret < 0) {
- dev_err(ctx->dev, "unable to get core%d\n", core_id);
- goto out;
- }
- }
-
-out:
- dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
- core_id, skl->cores.state[core_id],
- skl->cores.usage_count[core_id]);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_dsp_get_core);
-
-int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id)
-{
- struct skl_dev *skl = ctx->thread_context;
- int ret = 0;
-
- if (core_id >= skl->cores.count) {
- dev_err(ctx->dev, "invalid core id: %d\n", core_id);
- return -EINVAL;
- }
-
- if ((--skl->cores.usage_count[core_id] == 0) &&
- (skl->cores.state[core_id] != SKL_DSP_RESET)) {
- ret = ctx->fw_ops.set_state_D3(ctx, core_id);
- if (ret < 0) {
- dev_err(ctx->dev, "unable to put core %d: %d\n",
- core_id, ret);
- skl->cores.usage_count[core_id]++;
- }
- }
-
- dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
- core_id, skl->cores.state[core_id],
- skl->cores.usage_count[core_id]);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_dsp_put_core);
-
-int skl_dsp_wake(struct sst_dsp *ctx)
-{
- return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID);
-}
-EXPORT_SYMBOL_GPL(skl_dsp_wake);
-
-int skl_dsp_sleep(struct sst_dsp *ctx)
-{
- return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID);
-}
-EXPORT_SYMBOL_GPL(skl_dsp_sleep);
-
-struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
- struct sst_dsp_device *sst_dev, int irq)
-{
- int ret;
- struct sst_dsp *sst;
-
- sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
- if (sst == NULL)
- return NULL;
-
- spin_lock_init(&sst->spinlock);
- mutex_init(&sst->mutex);
- sst->dev = dev;
- sst->sst_dev = sst_dev;
- sst->irq = irq;
- sst->ops = sst_dev->ops;
- sst->thread_context = sst_dev->thread_context;
-
- /* Initialise SST Audio DSP */
- if (sst->ops->init) {
- ret = sst->ops->init(sst);
- if (ret < 0)
- return NULL;
- }
-
- return sst;
-}
-
-int skl_dsp_acquire_irq(struct sst_dsp *sst)
-{
- struct sst_dsp_device *sst_dev = sst->sst_dev;
- int ret;
-
- /* Register the ISR */
- ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
- sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
- if (ret)
- dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
- sst->irq);
-
- return ret;
-}
-
-void skl_dsp_free(struct sst_dsp *dsp)
-{
- skl_ipc_int_disable(dsp);
-
- free_irq(dsp->irq, dsp);
- skl_ipc_op_int_disable(dsp);
- skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
-}
-EXPORT_SYMBOL_GPL(skl_dsp_free);
-
-bool is_skl_dsp_running(struct sst_dsp *ctx)
-{
- return (ctx->sst_state == SKL_DSP_RUNNING);
-}
-EXPORT_SYMBOL_GPL(is_skl_dsp_running);
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
deleted file mode 100644
index 1df9ef422f61..000000000000
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Skylake SST DSP Support
- *
- * Copyright (C) 2014-15, Intel Corporation.
- */
-
-#ifndef __SKL_SST_DSP_H__
-#define __SKL_SST_DSP_H__
-
-#include <linux/interrupt.h>
-#include <linux/uuid.h>
-#include <linux/firmware.h>
-#include <sound/memalloc.h>
-#include "skl-sst-cldma.h"
-
-struct sst_dsp;
-struct sst_dsp_device;
-struct skl_lib_info;
-struct skl_dev;
-
-/* Intel HD Audio General DSP Registers */
-#define SKL_ADSP_GEN_BASE 0x0
-#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04)
-#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08)
-#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C)
-#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10)
-#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14)
-
-/* Intel HD Audio Inter-Processor Communication Registers */
-#define SKL_ADSP_IPC_BASE 0x40
-#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00)
-#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04)
-#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08)
-#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C)
-#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10)
-
-/* HIPCI */
-#define SKL_ADSP_REG_HIPCI_BUSY BIT(31)
-
-/* HIPCIE */
-#define SKL_ADSP_REG_HIPCIE_DONE BIT(30)
-
-/* HIPCCTL */
-#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1)
-#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0)
-
-/* HIPCT */
-#define SKL_ADSP_REG_HIPCT_BUSY BIT(31)
-
-/* FW base IDs */
-#define SKL_INSTANCE_ID 0
-#define SKL_BASE_FW_MODULE_ID 0
-
-/* Intel HD Audio SRAM Window 1 */
-#define SKL_ADSP_SRAM1_BASE 0xA000
-
-#define SKL_ADSP_MMIO_LEN 0x10000
-
-#define SKL_ADSP_W0_STAT_SZ 0x1000
-
-#define SKL_ADSP_W0_UP_SZ 0x1000
-
-#define SKL_ADSP_W1_SZ 0x1000
-
-#define SKL_FW_STS_MASK 0xf
-
-#define SKL_FW_INIT 0x1
-#define SKL_FW_RFW_START 0xf
-#define BXT_FW_ROM_INIT_RETRY 3
-#define BXT_INIT_TIMEOUT 300
-
-#define SKL_ADSPIC_IPC 1
-#define SKL_ADSPIS_IPC 1
-
-/* Core ID of core0 */
-#define SKL_DSP_CORE0_ID 0
-
-/* Mask for a given core index, c = 0.. number of supported cores - 1 */
-#define SKL_DSP_CORE_MASK(c) BIT(c)
-
-/*
- * Core 0 mask = SKL_DSP_CORE_MASK(0); Defined separately
- * since Core0 is primary core and it is used often
- */
-#define SKL_DSP_CORE0_MASK BIT(0)
-
-/*
- * Mask for a given number of cores
- * nc = number of supported cores
- */
-#define SKL_DSP_CORES_MASK(nc) GENMASK((nc - 1), 0)
-
-/* ADSPCS - Audio DSP Control & Status */
-
-/*
- * Core Reset - asserted high
- * CRST Mask for a given core mask pattern, cm
- */
-#define SKL_ADSPCS_CRST_SHIFT 0
-#define SKL_ADSPCS_CRST_MASK(cm) ((cm) << SKL_ADSPCS_CRST_SHIFT)
-
-/*
- * Core run/stall - when set to '1' core is stalled
- * CSTALL Mask for a given core mask pattern, cm
- */
-#define SKL_ADSPCS_CSTALL_SHIFT 8
-#define SKL_ADSPCS_CSTALL_MASK(cm) ((cm) << SKL_ADSPCS_CSTALL_SHIFT)
-
-/*
- * Set Power Active - when set to '1' turn cores on
- * SPA Mask for a given core mask pattern, cm
- */
-#define SKL_ADSPCS_SPA_SHIFT 16
-#define SKL_ADSPCS_SPA_MASK(cm) ((cm) << SKL_ADSPCS_SPA_SHIFT)
-
-/*
- * Current Power Active - power status of cores, set by hardware
- * CPA Mask for a given core mask pattern, cm
- */
-#define SKL_ADSPCS_CPA_SHIFT 24
-#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT)
-
-/* DSP Core state */
-enum skl_dsp_states {
- SKL_DSP_RUNNING = 1,
- /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */
- SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/
- SKL_DSP_RESET,
-};
-
-/* D0i3 substates */
-enum skl_dsp_d0i3_states {
- SKL_DSP_D0I3_NONE = -1, /* No D0i3 */
- SKL_DSP_D0I3_NON_STREAMING = 0,
- SKL_DSP_D0I3_STREAMING = 1,
-};
-
-struct skl_dsp_fw_ops {
- int (*load_fw)(struct sst_dsp *ctx);
- /* FW module parser/loader */
- int (*load_library)(struct sst_dsp *ctx,
- struct skl_lib_info *linfo, int lib_count);
- int (*parse_fw)(struct sst_dsp *ctx);
- int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
- int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
- int (*set_state_D0i3)(struct sst_dsp *ctx);
- int (*set_state_D0i0)(struct sst_dsp *ctx);
- unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
- int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name);
- int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
-
-};
-
-struct skl_dsp_loader_ops {
- int stream_tag;
-
- int (*alloc_dma_buf)(struct device *dev,
- struct snd_dma_buffer *dmab, size_t size);
- int (*free_dma_buf)(struct device *dev,
- struct snd_dma_buffer *dmab);
- int (*prepare)(struct device *dev, unsigned int format,
- unsigned int byte_size,
- struct snd_dma_buffer *bufp);
- int (*trigger)(struct device *dev, bool start, int stream_tag);
-
- int (*cleanup)(struct device *dev, struct snd_dma_buffer *dmab,
- int stream_tag);
-};
-
-#define MAX_INSTANCE_BUFF 2
-
-struct uuid_module {
- guid_t uuid;
- int id;
- int is_loadable;
- int max_instance;
- u64 pvt_id[MAX_INSTANCE_BUFF];
- int *instance_id;
-
- struct list_head list;
-};
-
-struct skl_load_module_info {
- u16 mod_id;
- const struct firmware *fw;
-};
-
-struct skl_module_table {
- struct skl_load_module_info *mod_info;
- unsigned int usage_cnt;
- struct list_head list;
-};
-
-void skl_cldma_process_intr(struct sst_dsp *ctx);
-void skl_cldma_int_disable(struct sst_dsp *ctx);
-int skl_cldma_prepare(struct sst_dsp *ctx);
-int skl_cldma_wait_interruptible(struct sst_dsp *ctx);
-
-void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
-struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
- struct sst_dsp_device *sst_dev, int irq);
-int skl_dsp_acquire_irq(struct sst_dsp *sst);
-bool is_skl_dsp_running(struct sst_dsp *ctx);
-
-unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
-void skl_dsp_init_core_state(struct sst_dsp *ctx);
-int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask);
-int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask);
-int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask);
-int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask);
-int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx,
- unsigned int core_mask);
-int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask);
-
-irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id);
-int skl_dsp_wake(struct sst_dsp *ctx);
-int skl_dsp_sleep(struct sst_dsp *ctx);
-void skl_dsp_free(struct sst_dsp *dsp);
-
-int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id);
-int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id);
-
-int skl_dsp_boot(struct sst_dsp *ctx);
-int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
- struct skl_dev **dsp);
-int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
- struct skl_dev **dsp);
-int skl_sst_init_fw(struct device *dev, struct skl_dev *skl);
-int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl);
-void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl);
-void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl);
-
-int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
- unsigned int offset, int index);
-int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id);
-int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id);
-int skl_get_pvt_instance_id_map(struct skl_dev *skl,
- int module_id, int instance_id);
-void skl_freeup_uuid_list(struct skl_dev *skl);
-
-int skl_dsp_strip_extended_manifest(struct firmware *fw);
-
-void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data);
-
-int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
- struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp,
- struct sst_dsp_device *skl_dev);
-int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo,
- struct firmware *stripped_fw,
- unsigned int hdr_offset, int index);
-void skl_release_library(struct skl_lib_info *linfo, int lib_count);
-
-#endif /*__SKL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
deleted file mode 100644
index 7a425271b08b..000000000000
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-sst-ipc.c - Intel skl IPC Support
- *
- * Copyright (C) 2014-15, Intel Corporation.
- */
-#include <linux/device.h>
-
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-#include "skl.h"
-#include "skl-sst-dsp.h"
-#include "skl-sst-ipc.h"
-#include "sound/hdaudio_ext.h"
-
-
-#define IPC_IXC_STATUS_BITS 24
-
-/* Global Message - Generic */
-#define IPC_GLB_TYPE_SHIFT 24
-#define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT)
-#define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT)
-
-/* Global Message - Reply */
-#define IPC_GLB_REPLY_STATUS_SHIFT 24
-#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1)
-#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT)
-
-#define IPC_GLB_REPLY_TYPE_SHIFT 29
-#define IPC_GLB_REPLY_TYPE_MASK 0x1F
-#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \
- & IPC_GLB_RPLY_TYPE_MASK)
-
-#define IPC_TIMEOUT_MSECS 3000
-
-#define IPC_EMPTY_LIST_SIZE 8
-
-#define IPC_MSG_TARGET_SHIFT 30
-#define IPC_MSG_TARGET_MASK 0x1
-#define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \
- << IPC_MSG_TARGET_SHIFT)
-
-#define IPC_MSG_DIR_SHIFT 29
-#define IPC_MSG_DIR_MASK 0x1
-#define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \
- << IPC_MSG_DIR_SHIFT)
-/* Global Notification Message */
-#define IPC_GLB_NOTIFY_TYPE_SHIFT 16
-#define IPC_GLB_NOTIFY_TYPE_MASK 0xFF
-#define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \
- & IPC_GLB_NOTIFY_TYPE_MASK)
-
-#define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24
-#define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F
-#define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \
- & IPC_GLB_NOTIFY_MSG_TYPE_MASK)
-
-#define IPC_GLB_NOTIFY_RSP_SHIFT 29
-#define IPC_GLB_NOTIFY_RSP_MASK 0x1
-#define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \
- & IPC_GLB_NOTIFY_RSP_MASK)
-
-/* Pipeline operations */
-
-/* Create pipeline message */
-#define IPC_PPL_MEM_SIZE_SHIFT 0
-#define IPC_PPL_MEM_SIZE_MASK 0x7FF
-#define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \
- << IPC_PPL_MEM_SIZE_SHIFT)
-
-#define IPC_PPL_TYPE_SHIFT 11
-#define IPC_PPL_TYPE_MASK 0x1F
-#define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \
- << IPC_PPL_TYPE_SHIFT)
-
-#define IPC_INSTANCE_ID_SHIFT 16
-#define IPC_INSTANCE_ID_MASK 0xFF
-#define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \
- << IPC_INSTANCE_ID_SHIFT)
-
-#define IPC_PPL_LP_MODE_SHIFT 0
-#define IPC_PPL_LP_MODE_MASK 0x1
-#define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \
- << IPC_PPL_LP_MODE_SHIFT)
-
-/* Set pipeline state message */
-#define IPC_PPL_STATE_SHIFT 0
-#define IPC_PPL_STATE_MASK 0x1F
-#define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \
- << IPC_PPL_STATE_SHIFT)
-
-/* Module operations primary register */
-#define IPC_MOD_ID_SHIFT 0
-#define IPC_MOD_ID_MASK 0xFFFF
-#define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \
- << IPC_MOD_ID_SHIFT)
-
-#define IPC_MOD_INSTANCE_ID_SHIFT 16
-#define IPC_MOD_INSTANCE_ID_MASK 0xFF
-#define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \
- << IPC_MOD_INSTANCE_ID_SHIFT)
-
-/* Init instance message extension register */
-#define IPC_PARAM_BLOCK_SIZE_SHIFT 0
-#define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF
-#define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \
- << IPC_PARAM_BLOCK_SIZE_SHIFT)
-
-#define IPC_PPL_INSTANCE_ID_SHIFT 16
-#define IPC_PPL_INSTANCE_ID_MASK 0xFF
-#define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \
- << IPC_PPL_INSTANCE_ID_SHIFT)
-
-#define IPC_CORE_ID_SHIFT 24
-#define IPC_CORE_ID_MASK 0x1F
-#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \
- << IPC_CORE_ID_SHIFT)
-
-#define IPC_DOMAIN_SHIFT 28
-#define IPC_DOMAIN_MASK 0x1
-#define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \
- << IPC_DOMAIN_SHIFT)
-
-/* Bind/Unbind message extension register */
-#define IPC_DST_MOD_ID_SHIFT 0
-#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \
- << IPC_DST_MOD_ID_SHIFT)
-
-#define IPC_DST_MOD_INSTANCE_ID_SHIFT 16
-#define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \
- << IPC_DST_MOD_INSTANCE_ID_SHIFT)
-
-#define IPC_DST_QUEUE_SHIFT 24
-#define IPC_DST_QUEUE_MASK 0x7
-#define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \
- << IPC_DST_QUEUE_SHIFT)
-
-#define IPC_SRC_QUEUE_SHIFT 27
-#define IPC_SRC_QUEUE_MASK 0x7
-#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \
- << IPC_SRC_QUEUE_SHIFT)
-/* Load Module count */
-#define IPC_LOAD_MODULE_SHIFT 0
-#define IPC_LOAD_MODULE_MASK 0xFF
-#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \
- << IPC_LOAD_MODULE_SHIFT)
-
-/* Save pipeline messgae extension register */
-#define IPC_DMA_ID_SHIFT 0
-#define IPC_DMA_ID_MASK 0x1F
-#define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \
- << IPC_DMA_ID_SHIFT)
-/* Large Config message extension register */
-#define IPC_DATA_OFFSET_SZ_SHIFT 0
-#define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF
-#define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \
- << IPC_DATA_OFFSET_SZ_SHIFT)
-#define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \
- << IPC_DATA_OFFSET_SZ_SHIFT)
-
-#define IPC_LARGE_PARAM_ID_SHIFT 20
-#define IPC_LARGE_PARAM_ID_MASK 0xFF
-#define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \
- << IPC_LARGE_PARAM_ID_SHIFT)
-
-#define IPC_FINAL_BLOCK_SHIFT 28
-#define IPC_FINAL_BLOCK_MASK 0x1
-#define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \
- << IPC_FINAL_BLOCK_SHIFT)
-
-#define IPC_INITIAL_BLOCK_SHIFT 29
-#define IPC_INITIAL_BLOCK_MASK 0x1
-#define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \
- << IPC_INITIAL_BLOCK_SHIFT)
-#define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \
- << IPC_INITIAL_BLOCK_SHIFT)
-/* Set D0ix IPC extension register */
-#define IPC_D0IX_WAKE_SHIFT 0
-#define IPC_D0IX_WAKE_MASK 0x1
-#define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \
- << IPC_D0IX_WAKE_SHIFT)
-
-#define IPC_D0IX_STREAMING_SHIFT 1
-#define IPC_D0IX_STREAMING_MASK 0x1
-#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \
- << IPC_D0IX_STREAMING_SHIFT)
-
-
-enum skl_ipc_msg_target {
- IPC_FW_GEN_MSG = 0,
- IPC_MOD_MSG = 1
-};
-
-enum skl_ipc_msg_direction {
- IPC_MSG_REQUEST = 0,
- IPC_MSG_REPLY = 1
-};
-
-/* Global Message Types */
-enum skl_ipc_glb_type {
- IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */
- IPC_GLB_LOAD_MULTIPLE_MODS = 15,
- IPC_GLB_UNLOAD_MULTIPLE_MODS = 16,
- IPC_GLB_CREATE_PPL = 17,
- IPC_GLB_DELETE_PPL = 18,
- IPC_GLB_SET_PPL_STATE = 19,
- IPC_GLB_GET_PPL_STATE = 20,
- IPC_GLB_GET_PPL_CONTEXT_SIZE = 21,
- IPC_GLB_SAVE_PPL = 22,
- IPC_GLB_RESTORE_PPL = 23,
- IPC_GLB_LOAD_LIBRARY = 24,
- IPC_GLB_NOTIFY = 26,
- IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */
-};
-
-enum skl_ipc_glb_reply {
- IPC_GLB_REPLY_SUCCESS = 0,
-
- IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1,
- IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2,
-
- IPC_GLB_REPLY_BUSY = 3,
- IPC_GLB_REPLY_PENDING = 4,
- IPC_GLB_REPLY_FAILURE = 5,
- IPC_GLB_REPLY_INVALID_REQUEST = 6,
-
- IPC_GLB_REPLY_OUT_OF_MEMORY = 7,
- IPC_GLB_REPLY_OUT_OF_MIPS = 8,
-
- IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9,
- IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10,
-
- IPC_GLB_REPLY_MOD_MGMT_ERROR = 100,
- IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101,
- IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102,
-
- IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103,
- IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104,
-
- IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120,
- IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
- IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
- IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
- IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150,
- IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151,
-
- IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
- IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
- IPC_GLB_REPLY_PPL_SAVE_FAILED = 162,
- IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163,
-
- IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1)
-};
-
-enum skl_ipc_notification_type {
- IPC_GLB_NOTIFY_GLITCH = 0,
- IPC_GLB_NOTIFY_OVERRUN = 1,
- IPC_GLB_NOTIFY_UNDERRUN = 2,
- IPC_GLB_NOTIFY_END_STREAM = 3,
- IPC_GLB_NOTIFY_PHRASE_DETECTED = 4,
- IPC_GLB_NOTIFY_RESOURCE_EVENT = 5,
- IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6,
- IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7,
- IPC_GLB_NOTIFY_FW_READY = 8
-};
-
-/* Module Message Types */
-enum skl_ipc_module_msg {
- IPC_MOD_INIT_INSTANCE = 0,
- IPC_MOD_CONFIG_GET = 1,
- IPC_MOD_CONFIG_SET = 2,
- IPC_MOD_LARGE_CONFIG_GET = 3,
- IPC_MOD_LARGE_CONFIG_SET = 4,
- IPC_MOD_BIND = 5,
- IPC_MOD_UNBIND = 6,
- IPC_MOD_SET_DX = 7,
- IPC_MOD_SET_D0IX = 8
-};
-
-void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
- size_t tx_size)
-{
- if (tx_size)
- memcpy(msg->tx.data, tx_data, tx_size);
-}
-
-static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp)
-{
- u32 hipci;
-
- hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI);
- return (hipci & SKL_ADSP_REG_HIPCI_BUSY);
-}
-
-/* Lock to be held by caller */
-static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
-{
- struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header);
-
- if (msg->tx.size)
- sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size);
- sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE,
- header->extension);
- sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI,
- header->primary | SKL_ADSP_REG_HIPCI_BUSY);
-}
-
-int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state)
-{
- int ret;
-
- /* check D0i3 support */
- if (!dsp->fw_ops.set_state_D0i0)
- return 0;
-
- /* Attempt D0i0 or D0i3 based on state */
- if (state)
- ret = dsp->fw_ops.set_state_D0i0(dsp);
- else
- ret = dsp->fw_ops.set_state_D0i3(dsp);
-
- return ret;
-}
-
-static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
- u64 ipc_header)
-{
- struct ipc_message *msg = NULL;
- struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header);
-
- if (list_empty(&ipc->rx_list)) {
- dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n",
- header->primary);
- goto out;
- }
-
- msg = list_first_entry(&ipc->rx_list, struct ipc_message, list);
-
- list_del(&msg->list);
-out:
- return msg;
-
-}
-
-int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
- struct skl_ipc_header header)
-{
- struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc);
-
- if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
- switch (IPC_GLB_NOTIFY_TYPE(header.primary)) {
-
- case IPC_GLB_NOTIFY_UNDERRUN:
- dev_err(ipc->dev, "FW Underrun %x\n", header.primary);
- break;
-
- case IPC_GLB_NOTIFY_RESOURCE_EVENT:
- dev_err(ipc->dev, "MCPS Budget Violation: %x\n",
- header.primary);
- break;
-
- case IPC_GLB_NOTIFY_FW_READY:
- skl->boot_complete = true;
- wake_up(&skl->boot_wait);
- break;
-
- case IPC_GLB_NOTIFY_PHRASE_DETECTED:
- dev_dbg(ipc->dev, "***** Phrase Detected **********\n");
-
- /*
- * Per HW recomendation, After phrase detection,
- * clear the CGCTL.MISCBDCGE.
- *
- * This will be set back on stream closure
- */
- skl->enable_miscbdcge(ipc->dev, false);
- skl->miscbdcg_disabled = true;
- break;
-
- default:
- dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n",
- header.primary);
- break;
- }
- }
-
- return 0;
-}
-
-struct skl_ipc_err_map {
- const char *msg;
- enum skl_ipc_glb_reply reply;
- int err;
-};
-
-static struct skl_ipc_err_map skl_err_map[] = {
- {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM},
- {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY},
- {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING,
- IPC_GLB_REPLY_SCLK_ALREADY_RUNNING},
- {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING,
- IPC_GLB_REPLY_MCLK_ALREADY_RUNNING},
-};
-
-static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) {
- if (skl_err_map[i].reply == reply)
- break;
- }
-
- if (i == ARRAY_SIZE(skl_err_map)) {
- dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n",
- reply,
- ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
- return -EINVAL;
- }
-
- if (skl_err_map[i].err < 0)
- dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
- skl_err_map[i].msg,
- ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
- else
- dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
- skl_err_map[i].msg,
- ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
-
- return skl_err_map[i].err;
-}
-
-void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
- struct skl_ipc_header header)
-{
- struct ipc_message *msg;
- u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK;
- u64 *ipc_header = (u64 *)(&header);
- struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&ipc->dsp->spinlock, flags);
- msg = skl_ipc_reply_get_msg(ipc, *ipc_header);
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
- if (msg == NULL) {
- dev_dbg(ipc->dev, "ipc: rx list is empty\n");
- return;
- }
-
- msg->rx.header = *ipc_header;
- /* first process the header */
- if (reply == IPC_GLB_REPLY_SUCCESS) {
- dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary);
- /* copy the rx data from the mailbox */
- sst_dsp_inbox_read(ipc->dsp, msg->rx.data, msg->rx.size);
- switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
- case IPC_GLB_LOAD_MULTIPLE_MODS:
- case IPC_GLB_LOAD_LIBRARY:
- skl->mod_load_complete = true;
- skl->mod_load_status = true;
- wake_up(&skl->mod_load_wait);
- break;
-
- default:
- break;
-
- }
- } else {
- msg->errno = skl_ipc_set_reply_error_code(ipc, reply);
- switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
- case IPC_GLB_LOAD_MULTIPLE_MODS:
- case IPC_GLB_LOAD_LIBRARY:
- skl->mod_load_complete = true;
- skl->mod_load_status = false;
- wake_up(&skl->mod_load_wait);
- break;
-
- default:
- break;
-
- }
- }
-
- spin_lock_irqsave(&ipc->dsp->spinlock, flags);
- sst_ipc_tx_msg_reply_complete(ipc, msg);
- spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
-}
-
-irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)
-{
- struct sst_dsp *dsp = context;
- struct skl_dev *skl = dsp->thread_context;
- struct sst_generic_ipc *ipc = &skl->ipc;
- struct skl_ipc_header header = {0};
- u32 hipcie, hipct, hipcte;
- int ipc_irq = 0;
-
- if (dsp->intr_status & SKL_ADSPIS_CL_DMA)
- skl_cldma_process_intr(dsp);
-
- /* Here we handle IPC interrupts only */
- if (!(dsp->intr_status & SKL_ADSPIS_IPC))
- return IRQ_NONE;
-
- hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE);
- hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT);
- hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE);
-
- /* reply message from DSP */
- if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) {
- sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_DONE, 0);
-
- /* clear DONE bit - tell DSP we have completed the operation */
- sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE,
- SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE);
-
- ipc_irq = 1;
-
- /* unmask Done interrupt */
- sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE);
- }
-
- /* New message from DSP */
- if (hipct & SKL_ADSP_REG_HIPCT_BUSY) {
- header.primary = hipct;
- header.extension = hipcte;
- dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n",
- header.primary);
- dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n",
- header.extension);
-
- if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
- /* Handle Immediate reply from DSP Core */
- skl_ipc_process_reply(ipc, header);
- } else {
- dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
- skl_ipc_process_notification(ipc, header);
- }
- /* clear busy interrupt */
- sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT,
- SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY);
- ipc_irq = 1;
- }
-
- if (ipc_irq == 0)
- return IRQ_NONE;
-
- skl_ipc_int_enable(dsp);
-
- /* continue to send any remaining messages... */
- schedule_work(&ipc->kwork);
-
- return IRQ_HANDLED;
-}
-
-void skl_ipc_int_enable(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC,
- SKL_ADSPIC_IPC, SKL_ADSPIC_IPC);
-}
-
-void skl_ipc_int_disable(struct sst_dsp *ctx)
-{
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC,
- SKL_ADSPIC_IPC, 0);
-}
-
-void skl_ipc_op_int_enable(struct sst_dsp *ctx)
-{
- /* enable IPC DONE interrupt */
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE);
-
- /* Enable IPC BUSY interrupt */
- sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY);
-}
-
-void skl_ipc_op_int_disable(struct sst_dsp *ctx)
-{
- /* disable IPC DONE interrupt */
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_DONE, 0);
-
- /* Disable IPC BUSY interrupt */
- sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_BUSY, 0);
-
-}
-
-bool skl_ipc_int_status(struct sst_dsp *ctx)
-{
- return sst_dsp_shim_read_unlocked(ctx,
- SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC;
-}
-
-int skl_ipc_init(struct device *dev, struct skl_dev *skl)
-{
- struct sst_generic_ipc *ipc;
- int err;
-
- ipc = &skl->ipc;
- ipc->dsp = skl->dsp;
- ipc->dev = dev;
-
- ipc->tx_data_max_size = SKL_ADSP_W1_SZ;
- ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ;
-
- err = sst_ipc_init(ipc);
- if (err)
- return err;
-
- ipc->ops.tx_msg = skl_ipc_tx_msg;
- ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
- ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy;
-
- return 0;
-}
-
-void skl_ipc_free(struct sst_generic_ipc *ipc)
-{
- /* Disable IPC DONE interrupt */
- sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_DONE, 0);
-
- /* Disable IPC BUSY interrupt */
- sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL,
- SKL_ADSP_REG_HIPCCTL_BUSY, 0);
-
- sst_ipc_fini(ipc);
-}
-
-int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
- u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL);
- header.primary |= IPC_INSTANCE_ID(instance_id);
- header.primary |= IPC_PPL_TYPE(ppl_type);
- header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size);
-
- header.extension = IPC_PPL_LP_MODE(lp_mode);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline);
-
-int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL);
- header.primary |= IPC_INSTANCE_ID(instance_id);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline);
-
-int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc,
- u8 instance_id, enum skl_ipc_pipeline_state state)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE);
- header.primary |= IPC_INSTANCE_ID(instance_id);
- header.primary |= IPC_PPL_STATE(state);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret);
- return ret;
- }
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state);
-
-int
-skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL);
- header.primary |= IPC_INSTANCE_ID(instance_id);
-
- header.extension = IPC_DMA_ID(dma_id);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline);
-
-int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL);
- header.primary |= IPC_INSTANCE_ID(instance_id);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline);
-
-int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
- u16 module_id, struct skl_ipc_dxstate_info *dx)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request;
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX);
- header.primary |= IPC_MOD_INSTANCE_ID(instance_id);
- header.primary |= IPC_MOD_ID(module_id);
-
- request.header = *(u64 *)(&header);
- request.data = dx;
- request.size = sizeof(*dx);
-
- dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
- header.primary, header.extension);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_set_dx);
-
-int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
- struct skl_ipc_init_instance_msg *msg, void *param_data)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request;
- int ret;
- u32 *buffer = (u32 *)param_data;
- /* param_block_size must be in dwords */
- u16 param_block_size = msg->param_data_size / sizeof(u32);
-
- print_hex_dump_debug("Param data:", DUMP_PREFIX_NONE,
- 16, 4, buffer, param_block_size, false);
-
- header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE);
- header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
- header.primary |= IPC_MOD_ID(msg->module_id);
-
- header.extension = IPC_CORE_ID(msg->core_id);
- header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id);
- header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size);
- header.extension |= IPC_DOMAIN(msg->domain);
-
- request.header = *(u64 *)(&header);
- request.data = param_data;
- request.size = msg->param_data_size;
-
- dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
- header.primary, header.extension);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
-
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: init instance failed\n");
- return ret;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_init_instance);
-
-int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
- struct skl_ipc_bind_unbind_msg *msg)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND;
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(bind_unbind);
- header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
- header.primary |= IPC_MOD_ID(msg->module_id);
-
- header.extension = IPC_DST_MOD_ID(msg->dst_module_id);
- header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id);
- header.extension |= IPC_DST_QUEUE(msg->dst_queue);
- header.extension |= IPC_SRC_QUEUE(msg->src_queue);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary,
- header.extension);
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev, "ipc: bind/unbind failed\n");
- return ret;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
-
-/*
- * In order to load a module we need to send IPC to initiate that. DMA will
- * performed to load the module memory. The FW supports multiple module load
- * at single shot, so we can send IPC with N modules represented by
- * module_cnt
- */
-int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
- u8 module_cnt, void *data)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request;
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
- header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
-
- request.header = *(u64 *)(&header);
- request.data = data;
- request.size = sizeof(u16) * module_cnt;
-
- ret = sst_ipc_tx_message_nowait(ipc, request);
- if (ret < 0)
- dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_load_modules);
-
-int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt,
- void *data)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request;
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS);
- header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
-
- request.header = *(u64 *)(&header);
- request.data = data;
- request.size = sizeof(u16) * module_cnt;
-
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0)
- dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_unload_modules);
-
-int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
- struct skl_ipc_large_config_msg *msg, u32 *param)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request;
- int ret = 0;
- size_t sz_remaining, tx_size, data_offset;
-
- header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET);
- header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
- header.primary |= IPC_MOD_ID(msg->module_id);
-
- header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
- header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
- header.extension |= IPC_FINAL_BLOCK(0);
- header.extension |= IPC_INITIAL_BLOCK(1);
-
- sz_remaining = msg->param_data_size;
- data_offset = 0;
- while (sz_remaining != 0) {
- tx_size = sz_remaining > SKL_ADSP_W1_SZ
- ? SKL_ADSP_W1_SZ : sz_remaining;
- if (tx_size == sz_remaining)
- header.extension |= IPC_FINAL_BLOCK(1);
-
- dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__,
- header.primary, header.extension);
- dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n",
- (unsigned)data_offset, (unsigned)tx_size);
-
- request.header = *(u64 *)(&header);
- request.data = ((char *)param) + data_offset;
- request.size = tx_size;
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- if (ret < 0) {
- dev_err(ipc->dev,
- "ipc: set large config fail, err: %d\n", ret);
- return ret;
- }
- sz_remaining -= tx_size;
- data_offset = msg->param_data_size - sz_remaining;
-
- /* clear the fields */
- header.extension &= IPC_INITIAL_BLOCK_CLEAR;
- header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
- /* fill the fields */
- header.extension |= IPC_INITIAL_BLOCK(0);
- header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
-
-int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
- struct skl_ipc_large_config_msg *msg,
- u32 **payload, size_t *bytes)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request, reply = {0};
- unsigned int *buf;
- int ret;
-
- reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL);
- if (!reply.data)
- return -ENOMEM;
-
- header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET);
- header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
- header.primary |= IPC_MOD_ID(msg->module_id);
-
- header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
- header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
- header.extension |= IPC_FINAL_BLOCK(1);
- header.extension |= IPC_INITIAL_BLOCK(1);
-
- request.header = *(u64 *)&header;
- request.data = *payload;
- request.size = *bytes;
- reply.size = SKL_ADSP_W1_SZ;
-
- ret = sst_ipc_tx_message_wait(ipc, request, &reply);
- if (ret < 0)
- dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret);
-
- reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK;
- buf = krealloc(reply.data, reply.size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- *payload = buf;
- *bytes = reply.size;
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
-
-int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
- u8 dma_id, u8 table_id, bool wait)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret = 0;
-
- header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY);
- header.primary |= IPC_MOD_INSTANCE_ID(table_id);
- header.primary |= IPC_MOD_ID(dma_id);
- request.header = *(u64 *)(&header);
-
- if (wait)
- ret = sst_ipc_tx_message_wait(ipc, request, NULL);
- else
- ret = sst_ipc_tx_message_nowait(ipc, request);
-
- if (ret < 0)
- dev_err(ipc->dev, "ipc: load lib failed\n");
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library);
-
-int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg)
-{
- struct skl_ipc_header header = {0};
- struct sst_ipc_message request = {0};
- int ret;
-
- header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
- header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
- header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX);
- header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
- header.primary |= IPC_MOD_ID(msg->module_id);
-
- header.extension = IPC_D0IX_WAKE(msg->wake);
- header.extension |= IPC_D0IX_STREAMING(msg->streaming);
- request.header = *(u64 *)(&header);
-
- dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__,
- header.primary, header.extension);
-
- /*
- * Use the nopm IPC here as we dont want it checking for D0iX
- */
- ret = sst_ipc_tx_message_nopm(ipc, request, NULL);
- if (ret < 0)
- dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
deleted file mode 100644
index aaaab3b3ec42..000000000000
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel SKL IPC Support
- *
- * Copyright (C) 2014-15, Intel Corporation.
- */
-
-#ifndef __SKL_IPC_H
-#define __SKL_IPC_H
-
-#include <linux/irqreturn.h>
-#include "../common/sst-ipc.h"
-#include "skl-sst-dsp.h"
-
-struct sst_dsp;
-struct sst_generic_ipc;
-
-enum skl_ipc_pipeline_state {
- PPL_INVALID_STATE = 0,
- PPL_UNINITIALIZED = 1,
- PPL_RESET = 2,
- PPL_PAUSED = 3,
- PPL_RUNNING = 4,
- PPL_ERROR_STOP = 5,
- PPL_SAVED = 6,
- PPL_RESTORED = 7
-};
-
-struct skl_ipc_dxstate_info {
- u32 core_mask;
- u32 dx_mask;
-};
-
-struct skl_ipc_header {
- u32 primary;
- u32 extension;
-};
-
-struct skl_dsp_cores {
- unsigned int count;
- enum skl_dsp_states *state;
- int *usage_count;
-};
-
-/**
- * skl_d0i3_data: skl D0i3 counters data struct
- *
- * @streaming: Count of usecases that can attempt streaming D0i3
- * @non_streaming: Count of usecases that can attempt non-streaming D0i3
- * @non_d0i3: Count of usecases that cannot attempt D0i3
- * @state: current state
- * @work: D0i3 worker thread
- */
-struct skl_d0i3_data {
- int streaming;
- int non_streaming;
- int non_d0i3;
- enum skl_dsp_d0i3_states state;
- struct delayed_work work;
-};
-
-#define SKL_LIB_NAME_LENGTH 128
-#define SKL_MAX_LIB 16
-
-struct skl_lib_info {
- char name[SKL_LIB_NAME_LENGTH];
- const struct firmware *fw;
-};
-
-struct skl_ipc_init_instance_msg {
- u32 module_id;
- u32 instance_id;
- u16 param_data_size;
- u8 ppl_instance_id;
- u8 core_id;
- u8 domain;
-};
-
-struct skl_ipc_bind_unbind_msg {
- u32 module_id;
- u32 instance_id;
- u32 dst_module_id;
- u32 dst_instance_id;
- u8 src_queue;
- u8 dst_queue;
- bool bind;
-};
-
-struct skl_ipc_large_config_msg {
- u32 module_id;
- u32 instance_id;
- u32 large_param_id;
- u32 param_data_size;
-};
-
-struct skl_ipc_d0ix_msg {
- u32 module_id;
- u32 instance_id;
- u8 streaming;
- u8 wake;
-};
-
-#define SKL_IPC_BOOT_MSECS 3000
-
-#define SKL_IPC_D3_MASK 0
-#define SKL_IPC_D0_MASK 3
-
-irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context);
-
-int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
- u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode);
-
-int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id);
-
-int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc,
- u8 instance_id, enum skl_ipc_pipeline_state state);
-
-int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc,
- u8 instance_id, int dma_id);
-
-int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id);
-
-int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
- struct skl_ipc_init_instance_msg *msg, void *param_data);
-
-int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
- struct skl_ipc_bind_unbind_msg *msg);
-
-int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
- u8 module_cnt, void *data);
-
-int skl_ipc_unload_modules(struct sst_generic_ipc *ipc,
- u8 module_cnt, void *data);
-
-int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
- u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
-
-int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
- struct skl_ipc_large_config_msg *msg, u32 *param);
-
-int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
- struct skl_ipc_large_config_msg *msg,
- u32 **payload, size_t *bytes);
-
-int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
- u8 dma_id, u8 table_id, bool wait);
-
-int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc,
- struct skl_ipc_d0ix_msg *msg);
-
-int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state);
-
-void skl_ipc_int_enable(struct sst_dsp *ctx);
-void skl_ipc_op_int_enable(struct sst_dsp *ctx);
-void skl_ipc_op_int_disable(struct sst_dsp *ctx);
-void skl_ipc_int_disable(struct sst_dsp *ctx);
-
-bool skl_ipc_int_status(struct sst_dsp *ctx);
-void skl_ipc_free(struct sst_generic_ipc *ipc);
-int skl_ipc_init(struct device *dev, struct skl_dev *skl);
-void skl_clear_module_cnt(struct sst_dsp *ctx);
-
-void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
- struct skl_ipc_header header);
-int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
- struct skl_ipc_header header);
-void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
- size_t tx_size);
-#endif /* __SKL_IPC_H */
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
deleted file mode 100644
index 57ea815d3f04..000000000000
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ /dev/null
@@ -1,424 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-sst-utils.c - SKL sst utils functions
- *
- * Copyright (C) 2016 Intel Corp
- */
-
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/uuid.h>
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-#include "skl.h"
-
-#define DEFAULT_HASH_SHA256_LEN 32
-
-/* FW Extended Manifest Header id = $AE1 */
-#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
-
-union seg_flags {
- u32 ul;
- struct {
- u32 contents : 1;
- u32 alloc : 1;
- u32 load : 1;
- u32 read_only : 1;
- u32 code : 1;
- u32 data : 1;
- u32 _rsvd0 : 2;
- u32 type : 4;
- u32 _rsvd1 : 4;
- u32 length : 16;
- } r;
-} __packed;
-
-struct segment_desc {
- union seg_flags flags;
- u32 v_base_addr;
- u32 file_offset;
-};
-
-struct module_type {
- u32 load_type : 4;
- u32 auto_start : 1;
- u32 domain_ll : 1;
- u32 domain_dp : 1;
- u32 rsvd : 25;
-} __packed;
-
-struct adsp_module_entry {
- u32 struct_id;
- u8 name[8];
- u8 uuid[16];
- struct module_type type;
- u8 hash1[DEFAULT_HASH_SHA256_LEN];
- u32 entry_point;
- u16 cfg_offset;
- u16 cfg_count;
- u32 affinity_mask;
- u16 instance_max_count;
- u16 instance_bss_size;
- struct segment_desc segments[3];
-} __packed;
-
-struct adsp_fw_hdr {
- u32 id;
- u32 len;
- u8 name[8];
- u32 preload_page_count;
- u32 fw_image_flags;
- u32 feature_mask;
- u16 major;
- u16 minor;
- u16 hotfix;
- u16 build;
- u32 num_modules;
- u32 hw_buf_base;
- u32 hw_buf_length;
- u32 load_offset;
-} __packed;
-
-struct skl_ext_manifest_hdr {
- u32 id;
- u32 len;
- u16 version_major;
- u16 version_minor;
- u32 entries;
-};
-
-static int skl_get_pvtid_map(struct uuid_module *module, int instance_id)
-{
- int pvt_id;
-
- for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) {
- if (module->instance_id[pvt_id] == instance_id)
- return pvt_id;
- }
- return -EINVAL;
-}
-
-int skl_get_pvt_instance_id_map(struct skl_dev *skl,
- int module_id, int instance_id)
-{
- struct uuid_module *module;
-
- list_for_each_entry(module, &skl->uuid_list, list) {
- if (module->id == module_id)
- return skl_get_pvtid_map(module, instance_id);
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map);
-
-static inline int skl_getid_32(struct uuid_module *module, u64 *val,
- int word1_mask, int word2_mask)
-{
- int index, max_inst, pvt_id;
- u32 mask_val;
-
- max_inst = module->max_instance;
- mask_val = (u32)(*val >> word1_mask);
-
- if (mask_val != 0xffffffff) {
- index = ffz(mask_val);
- pvt_id = index + word1_mask + word2_mask;
- if (pvt_id <= (max_inst - 1)) {
- *val |= 1ULL << (index + word1_mask);
- return pvt_id;
- }
- }
-
- return -EINVAL;
-}
-
-static inline int skl_pvtid_128(struct uuid_module *module)
-{
- int j, i, word1_mask, word2_mask = 0, pvt_id;
-
- for (j = 0; j < MAX_INSTANCE_BUFF; j++) {
- word1_mask = 0;
-
- for (i = 0; i < 2; i++) {
- pvt_id = skl_getid_32(module, &module->pvt_id[j],
- word1_mask, word2_mask);
- if (pvt_id >= 0)
- return pvt_id;
-
- word1_mask += 32;
- if ((word1_mask + word2_mask) >= module->max_instance)
- return -EINVAL;
- }
-
- word2_mask += 64;
- if (word2_mask >= module->max_instance)
- return -EINVAL;
- }
-
- return -EINVAL;
-}
-
-/**
- * skl_get_pvt_id: generate a private id for use as module id
- *
- * @skl: driver context
- * @uuid_mod: module's uuid
- * @instance_id: module's instance id
- *
- * This generates a 128 bit private unique id for a module TYPE so that
- * module instance is unique
- */
-int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id)
-{
- struct uuid_module *module;
- int pvt_id;
-
- list_for_each_entry(module, &skl->uuid_list, list) {
- if (guid_equal(uuid_mod, &module->uuid)) {
-
- pvt_id = skl_pvtid_128(module);
- if (pvt_id >= 0) {
- module->instance_id[pvt_id] = instance_id;
-
- return pvt_id;
- }
- }
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(skl_get_pvt_id);
-
-/**
- * skl_put_pvt_id: free up the private id allocated
- *
- * @skl: driver context
- * @uuid_mod: module's uuid
- * @pvt_id: module pvt id
- *
- * This frees a 128 bit private unique id previously generated
- */
-int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id)
-{
- int i;
- struct uuid_module *module;
-
- list_for_each_entry(module, &skl->uuid_list, list) {
- if (guid_equal(uuid_mod, &module->uuid)) {
-
- if (*pvt_id != 0)
- i = (*pvt_id) / 64;
- else
- i = 0;
-
- module->pvt_id[i] &= ~(1 << (*pvt_id));
- *pvt_id = -1;
- return 0;
- }
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(skl_put_pvt_id);
-
-/*
- * Parse the firmware binary to get the UUID, module id
- * and loadable flags
- */
-int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
- unsigned int offset, int index)
-{
- struct adsp_fw_hdr *adsp_hdr;
- struct adsp_module_entry *mod_entry;
- int i, num_entry, size;
- const char *buf;
- struct skl_dev *skl = ctx->thread_context;
- struct uuid_module *module;
- struct firmware stripped_fw;
- unsigned int safe_file;
- int ret;
-
- /* Get the FW pointer to derive ADSP header */
- stripped_fw.data = fw->data;
- stripped_fw.size = fw->size;
-
- skl_dsp_strip_extended_manifest(&stripped_fw);
-
- buf = stripped_fw.data;
-
- /* check if we have enough space in file to move to header */
- safe_file = sizeof(*adsp_hdr) + offset;
- if (stripped_fw.size <= safe_file) {
- dev_err(ctx->dev, "Small fw file size, No space for hdr\n");
- return -EINVAL;
- }
-
- adsp_hdr = (struct adsp_fw_hdr *)(buf + offset);
-
- /* check 1st module entry is in file */
- safe_file += adsp_hdr->len + sizeof(*mod_entry);
- if (stripped_fw.size <= safe_file) {
- dev_err(ctx->dev, "Small fw file size, No module entry\n");
- return -EINVAL;
- }
-
- mod_entry = (struct adsp_module_entry *)(buf + offset + adsp_hdr->len);
-
- num_entry = adsp_hdr->num_modules;
-
- /* check all entries are in file */
- safe_file += num_entry * sizeof(*mod_entry);
- if (stripped_fw.size <= safe_file) {
- dev_err(ctx->dev, "Small fw file size, No modules\n");
- return -EINVAL;
- }
-
-
- /*
- * Read the UUID(GUID) from FW Manifest.
- *
- * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX
- * Populate the UUID table to store module_id and loadable flags
- * for the module.
- */
-
- for (i = 0; i < num_entry; i++, mod_entry++) {
- module = kzalloc(sizeof(*module), GFP_KERNEL);
- if (!module) {
- ret = -ENOMEM;
- goto free_uuid_list;
- }
-
- import_guid(&module->uuid, mod_entry->uuid);
-
- module->id = (i | (index << 12));
- module->is_loadable = mod_entry->type.load_type;
- module->max_instance = mod_entry->instance_max_count;
- size = sizeof(int) * mod_entry->instance_max_count;
- module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
- if (!module->instance_id) {
- ret = -ENOMEM;
- goto free_uuid_list;
- }
-
- list_add_tail(&module->list, &skl->uuid_list);
-
- dev_dbg(ctx->dev,
- "Adding uuid :%pUL mod id: %d Loadable: %d\n",
- &module->uuid, module->id, module->is_loadable);
- }
-
- return 0;
-
-free_uuid_list:
- skl_freeup_uuid_list(skl);
- return ret;
-}
-
-void skl_freeup_uuid_list(struct skl_dev *skl)
-{
- struct uuid_module *uuid, *_uuid;
-
- list_for_each_entry_safe(uuid, _uuid, &skl->uuid_list, list) {
- list_del(&uuid->list);
- kfree(uuid);
- }
-}
-
-/*
- * some firmware binary contains some extended manifest. This needs
- * to be stripped in that case before we load and use that image.
- *
- * Get the module id for the module by checking
- * the table for the UUID for the module
- */
-int skl_dsp_strip_extended_manifest(struct firmware *fw)
-{
- struct skl_ext_manifest_hdr *hdr;
-
- /* check if fw file is greater than header we are looking */
- if (fw->size < sizeof(hdr)) {
- pr_err("%s: Firmware file small, no hdr\n", __func__);
- return -EINVAL;
- }
-
- hdr = (struct skl_ext_manifest_hdr *)fw->data;
-
- if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) {
- fw->size -= hdr->len;
- fw->data += hdr->len;
- }
-
- return 0;
-}
-
-int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
- struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp,
- struct sst_dsp_device *skl_dev)
-{
- struct skl_dev *skl = *dsp;
- struct sst_dsp *sst;
-
- skl->dev = dev;
- skl_dev->thread_context = skl;
- INIT_LIST_HEAD(&skl->uuid_list);
- skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq);
- if (!skl->dsp) {
- dev_err(skl->dev, "%s: no device\n", __func__);
- return -ENODEV;
- }
-
- sst = skl->dsp;
- sst->fw_name = fw_name;
- sst->dsp_ops = dsp_ops;
- init_waitqueue_head(&skl->mod_load_wait);
- INIT_LIST_HEAD(&sst->module_list);
-
- skl->is_first_boot = true;
-
- return 0;
-}
-
-int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo,
- struct firmware *stripped_fw,
- unsigned int hdr_offset, int index)
-{
- int ret;
- struct sst_dsp *dsp = skl->dsp;
-
- if (linfo->fw == NULL) {
- ret = request_firmware(&linfo->fw, linfo->name,
- skl->dev);
- if (ret < 0) {
- dev_err(skl->dev, "Request lib %s failed:%d\n",
- linfo->name, ret);
- return ret;
- }
- }
-
- if (skl->is_first_boot) {
- ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index);
- if (ret < 0)
- return ret;
- }
-
- stripped_fw->data = linfo->fw->data;
- stripped_fw->size = linfo->fw->size;
- skl_dsp_strip_extended_manifest(stripped_fw);
-
- return 0;
-}
-
-void skl_release_library(struct skl_lib_info *linfo, int lib_count)
-{
- int i;
-
- /* library indices start from 1 to N. 0 represents base FW */
- for (i = 1; i < lib_count; i++) {
- if (linfo[i].fw) {
- release_firmware(linfo[i].fw);
- linfo[i].fw = NULL;
- }
- }
-}
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
deleted file mode 100644
index 39d027ac16ec..000000000000
--- a/sound/soc/intel/skylake/skl-sst.c
+++ /dev/null
@@ -1,599 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-sst.c - HDA DSP library functions for SKL platform
- *
- * Copyright (C) 2014-15, Intel Corporation.
- * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
- * Jeeja KP <jeeja.kp@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/uuid.h>
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-#include "../common/sst-ipc.h"
-#include "skl.h"
-
-#define SKL_BASEFW_TIMEOUT 300
-#define SKL_INIT_TIMEOUT 1000
-
-/* Intel HD Audio SRAM Window 0*/
-#define SKL_ADSP_SRAM0_BASE 0x8000
-
-/* Firmware status window */
-#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
-#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4)
-
-#define SKL_NUM_MODULES 1
-
-static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
-{
- u32 cur_sts;
-
- cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK;
-
- return (cur_sts == status);
-}
-
-static int skl_transfer_firmware(struct sst_dsp *ctx,
- const void *basefw, u32 base_fw_size)
-{
- int ret = 0;
-
- ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size,
- true);
- if (ret < 0)
- return ret;
-
- ret = sst_dsp_register_poll(ctx,
- SKL_ADSP_FW_STATUS,
- SKL_FW_STS_MASK,
- SKL_FW_RFW_START,
- SKL_BASEFW_TIMEOUT,
- "Firmware boot");
-
- ctx->cl_dev.ops.cl_stop_dma(ctx);
-
- return ret;
-}
-
-#define SKL_ADSP_FW_BIN_HDR_OFFSET 0x284
-
-static int skl_load_base_firmware(struct sst_dsp *ctx)
-{
- int ret = 0, i;
- struct skl_dev *skl = ctx->thread_context;
- struct firmware stripped_fw;
- u32 reg;
-
- skl->boot_complete = false;
- init_waitqueue_head(&skl->boot_wait);
-
- if (ctx->fw == NULL) {
- ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
- if (ret < 0) {
- dev_err(ctx->dev, "Request firmware failed %d\n", ret);
- return -EIO;
- }
- }
-
- /* prase uuids on first boot */
- if (skl->is_first_boot) {
- ret = snd_skl_parse_uuids(ctx, ctx->fw, SKL_ADSP_FW_BIN_HDR_OFFSET, 0);
- if (ret < 0) {
- dev_err(ctx->dev, "UUID parsing err: %d\n", ret);
- release_firmware(ctx->fw);
- skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- return ret;
- }
- }
-
- /* check for extended manifest */
- stripped_fw.data = ctx->fw->data;
- stripped_fw.size = ctx->fw->size;
-
- skl_dsp_strip_extended_manifest(&stripped_fw);
-
- ret = skl_dsp_boot(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret);
- goto skl_load_base_firmware_failed;
- }
-
- ret = skl_cldma_prepare(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "CL dma prepare failed : %d\n", ret);
- goto skl_load_base_firmware_failed;
- }
-
- /* enable Interrupt */
- skl_ipc_int_enable(ctx);
- skl_ipc_op_int_enable(ctx);
-
- /* check ROM Status */
- for (i = SKL_INIT_TIMEOUT; i > 0; --i) {
- if (skl_check_fw_status(ctx, SKL_FW_INIT)) {
- dev_dbg(ctx->dev,
- "ROM loaded, we can continue with FW loading\n");
- break;
- }
- mdelay(1);
- }
- if (!i) {
- reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS);
- dev_err(ctx->dev,
- "Timeout waiting for ROM init done, reg:0x%x\n", reg);
- ret = -EIO;
- goto transfer_firmware_failed;
- }
-
- ret = skl_transfer_firmware(ctx, stripped_fw.data, stripped_fw.size);
- if (ret < 0) {
- dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
- goto transfer_firmware_failed;
- } else {
- ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
- msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
- if (ret == 0) {
- dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
- ret = -EIO;
- goto transfer_firmware_failed;
- }
-
- dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
- skl->fw_loaded = true;
- }
- return 0;
-transfer_firmware_failed:
- ctx->cl_dev.ops.cl_cleanup_controller(ctx);
-skl_load_base_firmware_failed:
- skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
- release_firmware(ctx->fw);
- ctx->fw = NULL;
- return ret;
-}
-
-static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
-{
- int ret;
- struct skl_ipc_dxstate_info dx;
- struct skl_dev *skl = ctx->thread_context;
- unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
-
- /* If core0 is being turned on, we need to load the FW */
- if (core_id == SKL_DSP_CORE0_ID) {
- ret = skl_load_base_firmware(ctx);
- if (ret < 0) {
- dev_err(ctx->dev, "unable to load firmware\n");
- return ret;
- }
-
- /* load libs as they are also lost on D3 */
- if (skl->lib_count > 1) {
- ret = ctx->fw_ops.load_library(ctx, skl->lib_info,
- skl->lib_count);
- if (ret < 0) {
- dev_err(ctx->dev, "reload libs failed: %d\n",
- ret);
- return ret;
- }
-
- }
- }
-
- /*
- * If any core other than core 0 is being moved to D0, enable the
- * core and send the set dx IPC for the core.
- */
- if (core_id != SKL_DSP_CORE0_ID) {
- ret = skl_dsp_enable_core(ctx, core_mask);
- if (ret < 0)
- return ret;
-
- dx.core_mask = core_mask;
- dx.dx_mask = core_mask;
-
- ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID,
- SKL_BASE_FW_MODULE_ID, &dx);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to set dsp to D0:core id= %d\n",
- core_id);
- skl_dsp_disable_core(ctx, core_mask);
- }
- }
-
- skl->cores.state[core_id] = SKL_DSP_RUNNING;
-
- return 0;
-}
-
-static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
-{
- int ret;
- struct skl_ipc_dxstate_info dx;
- struct skl_dev *skl = ctx->thread_context;
- unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
-
- dx.core_mask = core_mask;
- dx.dx_mask = SKL_IPC_D3_MASK;
-
- ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
- if (ret < 0)
- dev_err(ctx->dev, "set Dx core %d fail: %d\n", core_id, ret);
-
- if (core_id == SKL_DSP_CORE0_ID) {
- /* disable Interrupt */
- ctx->cl_dev.ops.cl_cleanup_controller(ctx);
- skl_cldma_int_disable(ctx);
- skl_ipc_op_int_disable(ctx);
- skl_ipc_int_disable(ctx);
- }
-
- ret = skl_dsp_disable_core(ctx, core_mask);
- if (ret < 0)
- return ret;
-
- skl->cores.state[core_id] = SKL_DSP_RESET;
- return ret;
-}
-
-static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
-{
- return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
-}
-
-/*
- * since get/set_module are called from DAPM context,
- * we don't need lock for usage count
- */
-static int skl_get_module(struct sst_dsp *ctx, u16 mod_id)
-{
- struct skl_module_table *module;
-
- list_for_each_entry(module, &ctx->module_list, list) {
- if (module->mod_info->mod_id == mod_id)
- return ++module->usage_cnt;
- }
-
- return -EINVAL;
-}
-
-static int skl_put_module(struct sst_dsp *ctx, u16 mod_id)
-{
- struct skl_module_table *module;
-
- list_for_each_entry(module, &ctx->module_list, list) {
- if (module->mod_info->mod_id == mod_id)
- return --module->usage_cnt;
- }
-
- return -EINVAL;
-}
-
-static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx,
- char *mod_name, int mod_id)
-{
- const struct firmware *fw;
- struct skl_module_table *skl_module;
- unsigned int size;
- int ret;
-
- ret = request_firmware(&fw, mod_name, ctx->dev);
- if (ret < 0) {
- dev_err(ctx->dev, "Request Module %s failed :%d\n",
- mod_name, ret);
- return NULL;
- }
-
- skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL);
- if (skl_module == NULL) {
- release_firmware(fw);
- return NULL;
- }
-
- size = sizeof(*skl_module->mod_info);
- skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
- if (skl_module->mod_info == NULL) {
- release_firmware(fw);
- return NULL;
- }
-
- skl_module->mod_info->mod_id = mod_id;
- skl_module->mod_info->fw = fw;
- list_add(&skl_module->list, &ctx->module_list);
-
- return skl_module;
-}
-
-/* get a module from it's unique ID */
-static struct skl_module_table *skl_module_get_from_id(
- struct sst_dsp *ctx, u16 mod_id)
-{
- struct skl_module_table *module;
-
- if (list_empty(&ctx->module_list)) {
- dev_err(ctx->dev, "Module list is empty\n");
- return NULL;
- }
-
- list_for_each_entry(module, &ctx->module_list, list) {
- if (module->mod_info->mod_id == mod_id)
- return module;
- }
-
- return NULL;
-}
-
-static int skl_transfer_module(struct sst_dsp *ctx, const void *data,
- u32 size, u16 mod_id, u8 table_id, bool is_module)
-{
- int ret, bytes_left, curr_pos;
- struct skl_dev *skl = ctx->thread_context;
- skl->mod_load_complete = false;
-
- bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false);
- if (bytes_left < 0)
- return bytes_left;
-
- /* check is_module flag to load module or library */
- if (is_module)
- ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id);
- else
- ret = skl_sst_ipc_load_library(&skl->ipc, 0, table_id, false);
-
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to Load %s with err %d\n",
- is_module ? "module" : "lib", ret);
- goto out;
- }
-
- /*
- * if bytes_left > 0 then wait for BDL complete interrupt and
- * copy the next chunk till bytes_left is 0. if bytes_left is
- * zero, then wait for load module IPC reply
- */
- while (bytes_left > 0) {
- curr_pos = size - bytes_left;
-
- ret = skl_cldma_wait_interruptible(ctx);
- if (ret < 0)
- goto out;
-
- bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx,
- data + curr_pos,
- bytes_left, false);
- }
-
- ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete,
- msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
- if (ret == 0 || !skl->mod_load_status) {
- dev_err(ctx->dev, "Module Load failed\n");
- ret = -EIO;
- }
-
-out:
- ctx->cl_dev.ops.cl_stop_dma(ctx);
-
- return ret;
-}
-
-static int
-skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count)
-{
- struct skl_dev *skl = ctx->thread_context;
- struct firmware stripped_fw;
- int ret, i;
-
- /* library indices start from 1 to N. 0 represents base FW */
- for (i = 1; i < lib_count; i++) {
- ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw,
- SKL_ADSP_FW_BIN_HDR_OFFSET, i);
- if (ret < 0)
- goto load_library_failed;
- ret = skl_transfer_module(ctx, stripped_fw.data,
- stripped_fw.size, 0, i, false);
- if (ret < 0)
- goto load_library_failed;
- }
-
- return 0;
-
-load_library_failed:
- skl_release_library(linfo, lib_count);
- return ret;
-}
-
-static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
-{
- struct skl_module_table *module_entry = NULL;
- int ret = 0;
- char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
-
- snprintf(mod_name, sizeof(mod_name), "intel/dsp_fw_%pUL.bin", guid);
-
- module_entry = skl_module_get_from_id(ctx, mod_id);
- if (module_entry == NULL) {
- module_entry = skl_fill_module_table(ctx, mod_name, mod_id);
- if (module_entry == NULL) {
- dev_err(ctx->dev, "Failed to Load module\n");
- return -EINVAL;
- }
- }
-
- if (!module_entry->usage_cnt) {
- ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data,
- module_entry->mod_info->fw->size,
- mod_id, 0, true);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to Load module\n");
- return ret;
- }
- }
-
- ret = skl_get_module(ctx, mod_id);
-
- return ret;
-}
-
-static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
-{
- int usage_cnt;
- struct skl_dev *skl = ctx->thread_context;
- int ret = 0;
-
- usage_cnt = skl_put_module(ctx, mod_id);
- if (usage_cnt < 0) {
- dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
- return -EIO;
- }
-
- /* if module is used by others return, no need to unload */
- if (usage_cnt > 0)
- return 0;
-
- ret = skl_ipc_unload_modules(&skl->ipc,
- SKL_NUM_MODULES, &mod_id);
- if (ret < 0) {
- dev_err(ctx->dev, "Failed to UnLoad module\n");
- skl_get_module(ctx, mod_id);
- return ret;
- }
-
- return ret;
-}
-
-void skl_clear_module_cnt(struct sst_dsp *ctx)
-{
- struct skl_module_table *module;
-
- if (list_empty(&ctx->module_list))
- return;
-
- list_for_each_entry(module, &ctx->module_list, list) {
- module->usage_cnt = 0;
- }
-}
-EXPORT_SYMBOL_GPL(skl_clear_module_cnt);
-
-static void skl_clear_module_table(struct sst_dsp *ctx)
-{
- struct skl_module_table *module, *tmp;
-
- if (list_empty(&ctx->module_list))
- return;
-
- list_for_each_entry_safe(module, tmp, &ctx->module_list, list) {
- list_del(&module->list);
- release_firmware(module->mod_info->fw);
- }
-}
-
-static const struct skl_dsp_fw_ops skl_fw_ops = {
- .set_state_D0 = skl_set_dsp_D0,
- .set_state_D3 = skl_set_dsp_D3,
- .load_fw = skl_load_base_firmware,
- .get_fw_errcode = skl_get_errorcode,
- .load_library = skl_load_library,
- .load_mod = skl_load_module,
- .unload_mod = skl_unload_module,
-};
-
-static struct sst_ops skl_ops = {
- .irq_handler = skl_dsp_sst_interrupt,
- .write = sst_shim32_write,
- .read = sst_shim32_read,
- .free = skl_dsp_free,
-};
-
-static struct sst_dsp_device skl_dev = {
- .thread = skl_dsp_irq_thread_handler,
- .ops = &skl_ops,
-};
-
-int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
- const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
- struct skl_dev **dsp)
-{
- struct skl_dev *skl;
- struct sst_dsp *sst;
- int ret;
-
- ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev);
- if (ret < 0) {
- dev_err(dev, "%s: no device\n", __func__);
- return ret;
- }
-
- skl = *dsp;
- sst = skl->dsp;
- sst->addr.lpe = mmio_base;
- sst->addr.shim = mmio_base;
- sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE;
- sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE;
- sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ;
- sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ;
-
- sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
- SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
-
- ret = skl_ipc_init(dev, skl);
- if (ret) {
- skl_dsp_free(sst);
- return ret;
- }
-
- sst->fw_ops = skl_fw_ops;
-
- return skl_dsp_acquire_irq(sst);
-}
-EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
-
-int skl_sst_init_fw(struct device *dev, struct skl_dev *skl)
-{
- int ret;
- struct sst_dsp *sst = skl->dsp;
-
- ret = sst->fw_ops.load_fw(sst);
- if (ret < 0) {
- dev_err(dev, "Load base fw failed : %d\n", ret);
- return ret;
- }
-
- skl_dsp_init_core_state(sst);
-
- if (skl->lib_count > 1) {
- ret = sst->fw_ops.load_library(sst, skl->lib_info,
- skl->lib_count);
- if (ret < 0) {
- dev_err(dev, "Load Library failed : %x\n", ret);
- return ret;
- }
- }
- skl->is_first_boot = false;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(skl_sst_init_fw);
-
-void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl)
-{
-
- if (skl->dsp->fw)
- release_firmware(skl->dsp->fw);
- skl_clear_module_table(skl->dsp);
- skl_freeup_uuid_list(skl);
- skl_ipc_free(&skl->ipc);
- skl->dsp->ops->free(skl->dsp);
- if (skl->boot_complete) {
- skl->dsp->cl_dev.ops.cl_cleanup_controller(skl->dsp);
- skl_cldma_int_disable(skl->dsp);
- }
-}
-EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Skylake IPC driver");
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
deleted file mode 100644
index 96cfebded072..000000000000
--- a/sound/soc/intel/skylake/skl-topology.c
+++ /dev/null
@@ -1,3774 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl-topology.c - Implements Platform component ALSA controls/widget
- * handlers.
- *
- * Copyright (C) 2014-2015 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/firmware.h>
-#include <linux/uuid.h>
-#include <sound/intel-nhlt.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/soc-topology.h>
-#include <uapi/sound/snd_sst_tokens.h>
-#include <uapi/sound/skl-tplg-interface.h>
-#include "skl-sst-dsp.h"
-#include "skl-sst-ipc.h"
-#include "skl-topology.h"
-#include "skl.h"
-#include "../common/sst-dsp.h"
-#include "../common/sst-dsp-priv.h"
-
-#define SKL_CH_FIXUP_MASK (1 << 0)
-#define SKL_RATE_FIXUP_MASK (1 << 1)
-#define SKL_FMT_FIXUP_MASK (1 << 2)
-#define SKL_IN_DIR_BIT_MASK BIT(0)
-#define SKL_PIN_COUNT_MASK GENMASK(7, 4)
-
-static const int mic_mono_list[] = {
-0, 1, 2, 3,
-};
-static const int mic_stereo_list[][SKL_CH_STEREO] = {
-{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
-};
-static const int mic_trio_list[][SKL_CH_TRIO] = {
-{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
-};
-static const int mic_quatro_list[][SKL_CH_QUATRO] = {
-{0, 1, 2, 3},
-};
-
-#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
- ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
-
-void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
-{
- struct skl_d0i3_data *d0i3 = &skl->d0i3;
-
- switch (caps) {
- case SKL_D0I3_NONE:
- d0i3->non_d0i3++;
- break;
-
- case SKL_D0I3_STREAMING:
- d0i3->streaming++;
- break;
-
- case SKL_D0I3_NON_STREAMING:
- d0i3->non_streaming++;
- break;
- }
-}
-
-void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
-{
- struct skl_d0i3_data *d0i3 = &skl->d0i3;
-
- switch (caps) {
- case SKL_D0I3_NONE:
- d0i3->non_d0i3--;
- break;
-
- case SKL_D0I3_STREAMING:
- d0i3->streaming--;
- break;
-
- case SKL_D0I3_NON_STREAMING:
- d0i3->non_streaming--;
- break;
- }
-}
-
-/*
- * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
- * ignore. This helpers checks if the SKL driver handles this widget type
- */
-static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
- struct device *dev)
-{
- if (w->dapm->dev != dev)
- return false;
-
- switch (w->id) {
- case snd_soc_dapm_dai_link:
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_aif_out:
- case snd_soc_dapm_dai_out:
- case snd_soc_dapm_switch:
- case snd_soc_dapm_output:
- case snd_soc_dapm_mux:
-
- return false;
- default:
- return true;
- }
-}
-
-static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
-{
- struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx];
-
- dev_dbg(skl->dev, "Dumping config\n");
- dev_dbg(skl->dev, "Input Format:\n");
- dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
- dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
- dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
- dev_dbg(skl->dev, "valid bit depth = %d\n",
- iface->inputs[0].fmt.valid_bit_depth);
- dev_dbg(skl->dev, "Output Format:\n");
- dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
- dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
- dev_dbg(skl->dev, "valid bit depth = %d\n",
- iface->outputs[0].fmt.valid_bit_depth);
- dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
-}
-
-static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
-{
- int slot_map = 0xFFFFFFFF;
- int start_slot = 0;
- int i;
-
- for (i = 0; i < chs; i++) {
- /*
- * For 2 channels with starting slot as 0, slot map will
- * look like 0xFFFFFF10.
- */
- slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
- start_slot++;
- }
- fmt->ch_map = slot_map;
-}
-
-static void skl_tplg_update_params(struct skl_module_fmt *fmt,
- struct skl_pipe_params *params, int fixup)
-{
- if (fixup & SKL_RATE_FIXUP_MASK)
- fmt->s_freq = params->s_freq;
- if (fixup & SKL_CH_FIXUP_MASK) {
- fmt->channels = params->ch;
- skl_tplg_update_chmap(fmt, fmt->channels);
- }
- if (fixup & SKL_FMT_FIXUP_MASK) {
- fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
-
- /*
- * 16 bit is 16 bit container whereas 24 bit is in 32 bit
- * container so update bit depth accordingly
- */
- switch (fmt->valid_bit_depth) {
- case SKL_DEPTH_16BIT:
- fmt->bit_depth = fmt->valid_bit_depth;
- break;
-
- default:
- fmt->bit_depth = SKL_DEPTH_32BIT;
- break;
- }
- }
-
-}
-
-/*
- * A pipeline may have modules which impact the pcm parameters, like SRC,
- * channel converter, format converter.
- * We need to calculate the output params by applying the 'fixup'
- * Topology will tell driver which type of fixup is to be applied by
- * supplying the fixup mask, so based on that we calculate the output
- *
- * Now In FE the pcm hw_params is source/target format. Same is applicable
- * for BE with its hw_params invoked.
- * here based on FE, BE pipeline and direction we calculate the input and
- * outfix and then apply that for a module
- */
-static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
- struct skl_pipe_params *params, bool is_fe)
-{
- int in_fixup, out_fixup;
- struct skl_module_fmt *in_fmt, *out_fmt;
-
- /* Fixups will be applied to pin 0 only */
- in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt;
- out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt;
-
- if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (is_fe) {
- in_fixup = m_cfg->params_fixup;
- out_fixup = (~m_cfg->converter) &
- m_cfg->params_fixup;
- } else {
- out_fixup = m_cfg->params_fixup;
- in_fixup = (~m_cfg->converter) &
- m_cfg->params_fixup;
- }
- } else {
- if (is_fe) {
- out_fixup = m_cfg->params_fixup;
- in_fixup = (~m_cfg->converter) &
- m_cfg->params_fixup;
- } else {
- in_fixup = m_cfg->params_fixup;
- out_fixup = (~m_cfg->converter) &
- m_cfg->params_fixup;
- }
- }
-
- skl_tplg_update_params(in_fmt, params, in_fixup);
- skl_tplg_update_params(out_fmt, params, out_fixup);
-}
-
-/*
- * A module needs input and output buffers, which are dependent upon pcm
- * params, so once we have calculate params, we need buffer calculation as
- * well.
- */
-static void skl_tplg_update_buffer_size(struct skl_dev *skl,
- struct skl_module_cfg *mcfg)
-{
- int multiplier = 1;
- struct skl_module_fmt *in_fmt, *out_fmt;
- struct skl_module_res *res;
-
- /* Since fixups is applied to pin 0 only, ibs, obs needs
- * change for pin 0 only
- */
- res = &mcfg->module->resources[mcfg->res_idx];
- in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt;
- out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt;
-
- if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
- multiplier = 5;
-
- res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
- in_fmt->channels * (in_fmt->bit_depth >> 3) *
- multiplier;
-
- res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
- out_fmt->channels * (out_fmt->bit_depth >> 3) *
- multiplier;
-}
-
-static u8 skl_tplg_be_dev_type(int dev_type)
-{
- int ret;
-
- switch (dev_type) {
- case SKL_DEVICE_BT:
- ret = NHLT_DEVICE_BT;
- break;
-
- case SKL_DEVICE_DMIC:
- ret = NHLT_DEVICE_DMIC;
- break;
-
- case SKL_DEVICE_I2S:
- ret = NHLT_DEVICE_I2S;
- break;
-
- default:
- ret = NHLT_DEVICE_INVALID;
- break;
- }
-
- return ret;
-}
-
-static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- struct skl_module_cfg *m_cfg = w->priv;
- int link_type, dir;
- u32 ch, s_freq, s_fmt, s_cont;
- struct nhlt_specific_cfg *cfg;
- u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
- int fmt_idx = m_cfg->fmt_idx;
- struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
-
- /* check if we already have blob */
- if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0)
- return 0;
-
- dev_dbg(skl->dev, "Applying default cfg blob\n");
- switch (m_cfg->dev_type) {
- case SKL_DEVICE_DMIC:
- link_type = NHLT_LINK_DMIC;
- dir = SNDRV_PCM_STREAM_CAPTURE;
- s_freq = m_iface->inputs[0].fmt.s_freq;
- s_fmt = m_iface->inputs[0].fmt.valid_bit_depth;
- s_cont = m_iface->inputs[0].fmt.bit_depth;
- ch = m_iface->inputs[0].fmt.channels;
- break;
-
- case SKL_DEVICE_I2S:
- link_type = NHLT_LINK_SSP;
- if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
- dir = SNDRV_PCM_STREAM_PLAYBACK;
- s_freq = m_iface->outputs[0].fmt.s_freq;
- s_fmt = m_iface->outputs[0].fmt.valid_bit_depth;
- s_cont = m_iface->outputs[0].fmt.bit_depth;
- ch = m_iface->outputs[0].fmt.channels;
- } else {
- dir = SNDRV_PCM_STREAM_CAPTURE;
- s_freq = m_iface->inputs[0].fmt.s_freq;
- s_fmt = m_iface->inputs[0].fmt.valid_bit_depth;
- s_cont = m_iface->inputs[0].fmt.bit_depth;
- ch = m_iface->inputs[0].fmt.channels;
- }
- break;
-
- default:
- return -EINVAL;
- }
-
- /* update the blob based on virtual bus_id and default params */
- cfg = intel_nhlt_get_endpoint_blob(skl->dev, skl->nhlt, m_cfg->vbus_id,
- link_type, s_fmt, s_cont, ch,
- s_freq, dir, dev_type);
- if (cfg) {
- m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
- m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
- } else {
- dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
- m_cfg->vbus_id, link_type, dir);
- dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d/%d\n",
- ch, s_freq, s_fmt, s_cont);
- return -EIO;
- }
-
- return 0;
-}
-
-static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- struct skl_module_cfg *m_cfg = w->priv;
- struct skl_pipe_params *params = m_cfg->pipe->p_params;
- int p_conn_type = m_cfg->pipe->conn_type;
- bool is_fe;
-
- if (!m_cfg->params_fixup)
- return;
-
- dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
- w->name);
-
- skl_dump_mconfig(skl, m_cfg);
-
- if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
- is_fe = true;
- else
- is_fe = false;
-
- skl_tplg_update_params_fixup(m_cfg, params, is_fe);
- skl_tplg_update_buffer_size(skl, m_cfg);
-
- dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
- w->name);
-
- skl_dump_mconfig(skl, m_cfg);
-}
-
-/*
- * some modules can have multiple params set from user control and
- * need to be set after module is initialized. If set_param flag is
- * set module params will be done after module is initialised.
- */
-static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- int i, ret;
- struct skl_module_cfg *mconfig = w->priv;
- const struct snd_kcontrol_new *k;
- struct soc_bytes_ext *sb;
- struct skl_algo_data *bc;
- struct skl_specific_cfg *sp_cfg;
-
- if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 &&
- mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) {
- sp_cfg = &mconfig->formats_config[SKL_PARAM_SET];
- ret = skl_set_module_params(skl, sp_cfg->caps,
- sp_cfg->caps_size,
- sp_cfg->param_id, mconfig);
- if (ret < 0)
- return ret;
- }
-
- for (i = 0; i < w->num_kcontrols; i++) {
- k = &w->kcontrol_news[i];
- if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
- sb = (void *) k->private_value;
- bc = (struct skl_algo_data *)sb->dobj.private;
-
- if (bc->set_params == SKL_PARAM_SET) {
- ret = skl_set_module_params(skl,
- (u32 *)bc->params, bc->size,
- bc->param_id, mconfig);
- if (ret < 0)
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-/*
- * some module param can set from user control and this is required as
- * when module is initailzed. if module param is required in init it is
- * identifed by set_param flag. if set_param flag is not set, then this
- * parameter needs to set as part of module init.
- */
-static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
-{
- const struct snd_kcontrol_new *k;
- struct soc_bytes_ext *sb;
- struct skl_algo_data *bc;
- struct skl_module_cfg *mconfig = w->priv;
- int i;
-
- for (i = 0; i < w->num_kcontrols; i++) {
- k = &w->kcontrol_news[i];
- if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
- sb = (struct soc_bytes_ext *)k->private_value;
- bc = (struct skl_algo_data *)sb->dobj.private;
-
- if (bc->set_params != SKL_PARAM_INIT)
- continue;
-
- mconfig->formats_config[SKL_PARAM_INIT].caps =
- (u32 *)bc->params;
- mconfig->formats_config[SKL_PARAM_INIT].caps_size =
- bc->size;
-
- break;
- }
- }
-
- return 0;
-}
-
-static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
- struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
-{
- switch (mcfg->dev_type) {
- case SKL_DEVICE_HDAHOST:
- return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
-
- case SKL_DEVICE_HDALINK:
- return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
- }
-
- return 0;
-}
-
-/*
- * Inside a pipe instance, we can have various modules. These modules need
- * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
- * skl_init_module() routine, so invoke that for all modules in a pipeline
- */
-static int
-skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- struct skl_pipe_module *w_module;
- struct snd_soc_dapm_widget *w;
- struct skl_module_cfg *mconfig;
- u8 cfg_idx;
- int ret = 0;
-
- list_for_each_entry(w_module, &pipe->w_list, node) {
- guid_t *uuid_mod;
- w = w_module->w;
- mconfig = w->priv;
-
- /* check if module ids are populated */
- if (mconfig->id.module_id < 0) {
- dev_err(skl->dev,
- "module %pUL id not populated\n",
- (guid_t *)mconfig->guid);
- return -EIO;
- }
-
- cfg_idx = mconfig->pipe->cur_config_idx;
- mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
- mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
-
- if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
- ret = skl->dsp->fw_ops.load_mod(skl->dsp,
- mconfig->id.module_id, mconfig->guid);
- if (ret < 0)
- return ret;
- }
-
- /* prepare the DMA if the module is gateway cpr */
- ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
- if (ret < 0)
- return ret;
-
- /* update blob if blob is null for be with default value */
- skl_tplg_update_be_blob(w, skl);
-
- /*
- * apply fix/conversion to module params based on
- * FE/BE params
- */
- skl_tplg_update_module_params(w, skl);
- uuid_mod = (guid_t *)mconfig->guid;
- mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
- mconfig->id.instance_id);
- if (mconfig->id.pvt_id < 0)
- return ret;
- skl_tplg_set_module_init_data(w);
-
- ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
- if (ret < 0) {
- dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
- mconfig->core_id, ret);
- return ret;
- }
-
- ret = skl_init_module(skl, mconfig);
- if (ret < 0) {
- skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
- goto err;
- }
-
- ret = skl_tplg_set_module_params(w, skl);
- if (ret < 0)
- goto err;
- }
-
- return 0;
-err:
- skl_dsp_put_core(skl->dsp, mconfig->core_id);
- return ret;
-}
-
-static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
- struct skl_pipe *pipe)
-{
- int ret = 0;
- struct skl_pipe_module *w_module;
- struct skl_module_cfg *mconfig;
-
- list_for_each_entry(w_module, &pipe->w_list, node) {
- guid_t *uuid_mod;
- mconfig = w_module->w->priv;
- uuid_mod = (guid_t *)mconfig->guid;
-
- if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) {
- ret = skl->dsp->fw_ops.unload_mod(skl->dsp,
- mconfig->id.module_id);
- if (ret < 0)
- return -EIO;
- }
- skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
-
- ret = skl_dsp_put_core(skl->dsp, mconfig->core_id);
- if (ret < 0) {
- /* don't return; continue with other modules */
- dev_err(skl->dev, "Failed to sleep core %d ret=%d\n",
- mconfig->core_id, ret);
- }
- }
-
- /* no modules to unload in this path, so return */
- return ret;
-}
-
-static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx)
-{
- pipe->cur_config_idx = idx;
- pipe->memory_pages = pipe->configs[idx].mem_pages;
-}
-
-/*
- * Here, we select pipe format based on the pipe type and pipe
- * direction to determine the current config index for the pipeline.
- * The config index is then used to select proper module resources.
- * Intermediate pipes currently have a fixed format hence we select the
- * 0th configuratation by default for such pipes.
- */
-static int
-skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
-{
- struct skl_pipe *pipe = mconfig->pipe;
- struct skl_pipe_params *params = pipe->p_params;
- struct skl_path_config *pconfig = &pipe->configs[0];
- struct skl_pipe_fmt *fmt = NULL;
- bool in_fmt = false;
- int i;
-
- if (pipe->nr_cfgs == 0) {
- skl_tplg_set_pipe_config_idx(pipe, 0);
- return 0;
- }
-
- if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) {
- dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
- pipe->ppl_id);
- skl_tplg_set_pipe_config_idx(pipe, 0);
- return 0;
- }
-
- if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
- pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
- (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
- pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
- in_fmt = true;
-
- for (i = 0; i < pipe->nr_cfgs; i++) {
- pconfig = &pipe->configs[i];
- if (in_fmt)
- fmt = &pconfig->in_fmt;
- else
- fmt = &pconfig->out_fmt;
-
- if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
- fmt->channels, fmt->freq, fmt->bps)) {
- skl_tplg_set_pipe_config_idx(pipe, i);
- dev_dbg(skl->dev, "Using pipe config: %d\n", i);
- return 0;
- }
- }
-
- dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
- params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
- return -EINVAL;
-}
-
-/*
- * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
- * need create the pipeline. So we do following:
- * - Create the pipeline
- * - Initialize the modules in pipeline
- * - finally bind all modules together
- */
-static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- int ret;
- struct skl_module_cfg *mconfig = w->priv;
- struct skl_pipe_module *w_module;
- struct skl_pipe *s_pipe = mconfig->pipe;
- struct skl_module_cfg *src_module = NULL, *dst_module, *module;
- struct skl_module_deferred_bind *modules;
-
- ret = skl_tplg_get_pipe_config(skl, mconfig);
- if (ret < 0)
- return ret;
-
- /*
- * Create a list of modules for pipe.
- * This list contains modules from source to sink
- */
- ret = skl_create_pipeline(skl, mconfig->pipe);
- if (ret < 0)
- return ret;
-
- /* Init all pipe modules from source to sink */
- ret = skl_tplg_init_pipe_modules(skl, s_pipe);
- if (ret < 0)
- return ret;
-
- /* Bind modules from source to sink */
- list_for_each_entry(w_module, &s_pipe->w_list, node) {
- dst_module = w_module->w->priv;
-
- if (src_module == NULL) {
- src_module = dst_module;
- continue;
- }
-
- ret = skl_bind_modules(skl, src_module, dst_module);
- if (ret < 0)
- return ret;
-
- src_module = dst_module;
- }
-
- /*
- * When the destination module is initialized, check for these modules
- * in deferred bind list. If found, bind them.
- */
- list_for_each_entry(w_module, &s_pipe->w_list, node) {
- if (list_empty(&skl->bind_list))
- break;
-
- list_for_each_entry(modules, &skl->bind_list, node) {
- module = w_module->w->priv;
- if (modules->dst == module)
- skl_bind_modules(skl, modules->src,
- modules->dst);
- }
- }
-
- return 0;
-}
-
-static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
- int size, struct skl_module_cfg *mcfg)
-{
- int i, pvt_id;
-
- if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
- struct skl_kpb_params *kpb_params =
- (struct skl_kpb_params *)params;
- struct skl_mod_inst_map *inst = kpb_params->u.map;
-
- for (i = 0; i < kpb_params->num_modules; i++) {
- pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
- inst->inst_id);
- if (pvt_id < 0)
- return -EINVAL;
-
- inst->inst_id = pvt_id;
- inst++;
- }
- }
-
- return 0;
-}
-/*
- * Some modules require params to be set after the module is bound to
- * all pins connected.
- *
- * The module provider initializes set_param flag for such modules and we
- * send params after binding
- */
-static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
- struct skl_module_cfg *mcfg, struct skl_dev *skl)
-{
- int i, ret;
- struct skl_module_cfg *mconfig = w->priv;
- const struct snd_kcontrol_new *k;
- struct soc_bytes_ext *sb;
- struct skl_algo_data *bc;
- struct skl_specific_cfg *sp_cfg;
- u32 *params;
-
- /*
- * check all out/in pins are in bind state.
- * if so set the module param
- */
- for (i = 0; i < mcfg->module->max_output_pins; i++) {
- if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
- return 0;
- }
-
- for (i = 0; i < mcfg->module->max_input_pins; i++) {
- if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
- return 0;
- }
-
- if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 &&
- mconfig->formats_config[SKL_PARAM_BIND].set_params ==
- SKL_PARAM_BIND) {
- sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND];
- ret = skl_set_module_params(skl, sp_cfg->caps,
- sp_cfg->caps_size,
- sp_cfg->param_id, mconfig);
- if (ret < 0)
- return ret;
- }
-
- for (i = 0; i < w->num_kcontrols; i++) {
- k = &w->kcontrol_news[i];
- if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
- sb = (void *) k->private_value;
- bc = (struct skl_algo_data *)sb->dobj.private;
-
- if (bc->set_params == SKL_PARAM_BIND) {
- params = kmemdup(bc->params, bc->max, GFP_KERNEL);
- if (!params)
- return -ENOMEM;
-
- skl_fill_sink_instance_id(skl, params, bc->max,
- mconfig);
-
- ret = skl_set_module_params(skl, params,
- bc->max, bc->param_id, mconfig);
- kfree(params);
-
- if (ret < 0)
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
-{
- struct uuid_module *module;
-
- list_for_each_entry(module, &skl->uuid_list, list) {
- if (guid_equal(uuid, &module->uuid))
- return module->id;
- }
-
- return -EINVAL;
-}
-
-static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
- const struct snd_kcontrol_new *k)
-{
- struct soc_bytes_ext *sb = (void *) k->private_value;
- struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
- struct skl_kpb_params *uuid_params, *params;
- struct hdac_bus *bus = skl_to_bus(skl);
- int i, size, module_id;
-
- if (bc->set_params == SKL_PARAM_BIND && bc->max) {
- uuid_params = (struct skl_kpb_params *)bc->params;
- size = struct_size(params, u.map, uuid_params->num_modules);
-
- params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
- if (!params)
- return -ENOMEM;
-
- params->num_modules = uuid_params->num_modules;
-
- for (i = 0; i < uuid_params->num_modules; i++) {
- module_id = skl_get_module_id(skl,
- &uuid_params->u.map_uuid[i].mod_uuid);
- if (module_id < 0) {
- devm_kfree(bus->dev, params);
- return -EINVAL;
- }
-
- params->u.map[i].mod_id = module_id;
- params->u.map[i].inst_id =
- uuid_params->u.map_uuid[i].inst_id;
- }
-
- devm_kfree(bus->dev, bc->params);
- bc->params = (char *)params;
- bc->max = size;
- }
-
- return 0;
-}
-
-/*
- * Retrieve the module id from UUID mentioned in the
- * post bind params
- */
-void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
- struct snd_soc_dapm_widget *w)
-{
- struct skl_module_cfg *mconfig = w->priv;
- int i;
-
- /*
- * Post bind params are used for only for KPB
- * to set copier instances to drain the data
- * in fast mode
- */
- if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
- return;
-
- for (i = 0; i < w->num_kcontrols; i++)
- if ((w->kcontrol_news[i].access &
- SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
- (skl_tplg_find_moduleid_from_uuid(skl,
- &w->kcontrol_news[i]) < 0))
- dev_err(skl->dev,
- "%s: invalid kpb post bind params\n",
- __func__);
-}
-
-static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
- struct skl_module_cfg *src, struct skl_module_cfg *dst)
-{
- struct skl_module_deferred_bind *m_list, *modules;
- int i;
-
- /* only supported for module with static pin connection */
- for (i = 0; i < dst->module->max_input_pins; i++) {
- struct skl_module_pin *pin = &dst->m_in_pin[i];
-
- if (pin->is_dynamic)
- continue;
-
- if ((pin->id.module_id == src->id.module_id) &&
- (pin->id.instance_id == src->id.instance_id)) {
-
- if (!list_empty(&skl->bind_list)) {
- list_for_each_entry(modules, &skl->bind_list, node) {
- if (modules->src == src && modules->dst == dst)
- return 0;
- }
- }
-
- m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
- if (!m_list)
- return -ENOMEM;
-
- m_list->src = src;
- m_list->dst = dst;
-
- list_add(&m_list->node, &skl->bind_list);
- }
- }
-
- return 0;
-}
-
-static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl,
- struct snd_soc_dapm_widget *src_w,
- struct skl_module_cfg *src_mconfig)
-{
- struct snd_soc_dapm_path *p;
- struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
- struct skl_module_cfg *sink_mconfig;
- int ret;
-
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (!p->connect)
- continue;
-
- dev_dbg(skl->dev,
- "%s: src widget=%s\n", __func__, w->name);
- dev_dbg(skl->dev,
- "%s: sink widget=%s\n", __func__, p->sink->name);
-
- next_sink = p->sink;
-
- if (!is_skl_dsp_widget_type(p->sink, skl->dev))
- return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
-
- /*
- * here we will check widgets in sink pipelines, so that
- * can be any widgets type and we are only interested if
- * they are ones used for SKL so check that first
- */
- if ((p->sink->priv != NULL) &&
- is_skl_dsp_widget_type(p->sink, skl->dev)) {
-
- sink = p->sink;
- sink_mconfig = sink->priv;
-
- /*
- * Modules other than PGA leaf can be connected
- * directly or via switch to a module in another
- * pipeline. EX: reference path
- * when the path is enabled, the dst module that needs
- * to be bound may not be initialized. if the module is
- * not initialized, add these modules in the deferred
- * bind list and when the dst module is initialised,
- * bind this module to the dst_module in deferred list.
- */
- if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
- && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
-
- ret = skl_tplg_module_add_deferred_bind(skl,
- src_mconfig, sink_mconfig);
-
- if (ret < 0)
- return ret;
-
- }
-
-
- if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
- sink_mconfig->m_state == SKL_MODULE_UNINIT)
- continue;
-
- /* Bind source to sink, mixin is always source */
- ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
- if (ret)
- return ret;
-
- /* set module params after bind */
- skl_tplg_set_module_bind_params(src_w,
- src_mconfig, skl);
- skl_tplg_set_module_bind_params(sink,
- sink_mconfig, skl);
-
- /* Start sinks pipe first */
- if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
- if (sink_mconfig->pipe->conn_type !=
- SKL_PIPE_CONN_TYPE_FE)
- ret = skl_run_pipe(skl,
- sink_mconfig->pipe);
- if (ret)
- return ret;
- }
- }
- }
-
- if (!sink && next_sink)
- return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
-
- return 0;
-}
-
-/*
- * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
- * we need to do following:
- * - Bind to sink pipeline
- * Since the sink pipes can be running and we don't get mixer event on
- * connect for already running mixer, we need to find the sink pipes
- * here and bind to them. This way dynamic connect works.
- * - Start sink pipeline, if not running
- * - Then run current pipe
- */
-static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- struct skl_module_cfg *src_mconfig;
- int ret = 0;
-
- src_mconfig = w->priv;
-
- /*
- * find which sink it is connected to, bind with the sink,
- * if sink is not started, start sink pipe first, then start
- * this pipe
- */
- ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
- if (ret)
- return ret;
-
- /* Start source pipe last after starting all sinks */
- if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
- return skl_run_pipe(skl, src_mconfig->pipe);
-
- return 0;
-}
-
-static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
- struct snd_soc_dapm_widget *w, struct skl_dev *skl)
-{
- struct snd_soc_dapm_path *p;
- struct snd_soc_dapm_widget *src_w = NULL;
-
- snd_soc_dapm_widget_for_each_source_path(w, p) {
- src_w = p->source;
- if (!p->connect)
- continue;
-
- dev_dbg(skl->dev, "sink widget=%s\n", w->name);
- dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
-
- /*
- * here we will check widgets in sink pipelines, so that can
- * be any widgets type and we are only interested if they are
- * ones used for SKL so check that first
- */
- if ((p->source->priv != NULL) &&
- is_skl_dsp_widget_type(p->source, skl->dev)) {
- return p->source;
- }
- }
-
- if (src_w != NULL)
- return skl_get_src_dsp_widget(src_w, skl);
-
- return NULL;
-}
-
-/*
- * in the Post-PMU event of mixer we need to do following:
- * - Check if this pipe is running
- * - if not, then
- * - bind this pipeline to its source pipeline
- * if source pipe is already running, this means it is a dynamic
- * connection and we need to bind only to that pipe
- * - start this pipeline
- */
-static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- int ret = 0;
- struct snd_soc_dapm_widget *source, *sink;
- struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int src_pipe_started = 0;
-
- sink = w;
- sink_mconfig = sink->priv;
-
- /*
- * If source pipe is already started, that means source is driving
- * one more sink before this sink got connected, Since source is
- * started, bind this sink to source and start this pipe.
- */
- source = skl_get_src_dsp_widget(w, skl);
- if (source != NULL) {
- src_mconfig = source->priv;
- sink_mconfig = sink->priv;
- src_pipe_started = 1;
-
- /*
- * check pipe state, then no need to bind or start the
- * pipe
- */
- if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
- src_pipe_started = 0;
- }
-
- if (src_pipe_started) {
- ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
- if (ret)
- return ret;
-
- /* set module params after bind */
- skl_tplg_set_module_bind_params(source, src_mconfig, skl);
- skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
-
- if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
- ret = skl_run_pipe(skl, sink_mconfig->pipe);
- }
-
- return ret;
-}
-
-/*
- * in the Pre-PMD event of mixer we need to do following:
- * - Stop the pipe
- * - find the source connections and remove that from dapm_path_list
- * - unbind with source pipelines if still connected
- */
-static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int ret = 0, i;
-
- sink_mconfig = w->priv;
-
- /* Stop the pipe */
- ret = skl_stop_pipe(skl, sink_mconfig->pipe);
- if (ret)
- return ret;
-
- for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
- if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
- src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
- if (!src_mconfig)
- continue;
-
- ret = skl_unbind_modules(skl,
- src_mconfig, sink_mconfig);
- }
- }
-
- return ret;
-}
-
-/*
- * in the Post-PMD event of mixer we need to do following:
- * - Unbind the modules within the pipeline
- * - Delete the pipeline (modules are not required to be explicitly
- * deleted, pipeline delete is enough here
- */
-static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- struct skl_module_cfg *mconfig = w->priv;
- struct skl_pipe_module *w_module;
- struct skl_module_cfg *src_module = NULL, *dst_module;
- struct skl_pipe *s_pipe = mconfig->pipe;
- struct skl_module_deferred_bind *modules, *tmp;
-
- if (s_pipe->state == SKL_PIPE_INVALID)
- return -EINVAL;
-
- list_for_each_entry(w_module, &s_pipe->w_list, node) {
- if (list_empty(&skl->bind_list))
- break;
-
- src_module = w_module->w->priv;
-
- list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
- /*
- * When the destination module is deleted, Unbind the
- * modules from deferred bind list.
- */
- if (modules->dst == src_module) {
- skl_unbind_modules(skl, modules->src,
- modules->dst);
- }
-
- /*
- * When the source module is deleted, remove this entry
- * from the deferred bind list.
- */
- if (modules->src == src_module) {
- list_del(&modules->node);
- modules->src = NULL;
- modules->dst = NULL;
- kfree(modules);
- }
- }
- }
-
- list_for_each_entry(w_module, &s_pipe->w_list, node) {
- dst_module = w_module->w->priv;
-
- if (src_module == NULL) {
- src_module = dst_module;
- continue;
- }
-
- skl_unbind_modules(skl, src_module, dst_module);
- src_module = dst_module;
- }
-
- skl_delete_pipe(skl, mconfig->pipe);
-
- list_for_each_entry(w_module, &s_pipe->w_list, node) {
- src_module = w_module->w->priv;
- src_module->m_state = SKL_MODULE_UNINIT;
- }
-
- return skl_tplg_unload_pipe_modules(skl, s_pipe);
-}
-
-/*
- * in the Post-PMD event of PGA we need to do following:
- * - Stop the pipeline
- * - In source pipe is connected, unbind with source pipelines
- */
-static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
- struct skl_dev *skl)
-{
- struct skl_module_cfg *src_mconfig, *sink_mconfig;
- int ret = 0, i;
-
- src_mconfig = w->priv;
-
- /* Stop the pipe since this is a mixin module */
- ret = skl_stop_pipe(skl, src_mconfig->pipe);
- if (ret)
- return ret;
-
- for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
- if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
- sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
- if (!sink_mconfig)
- continue;
- /*
- * This is a connecter and if path is found that means
- * unbind between source and sink has not happened yet
- */
- ret = skl_unbind_modules(skl, src_mconfig,
- sink_mconfig);
- }
- }
-
- return ret;
-}
-
-/*
- * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
- * second one is required that is created as another pipe entity.
- * The mixer is responsible for pipe management and represent a pipeline
- * instance
- */
-static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct skl_dev *skl = get_skl_ctx(dapm->dev);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
-
- case SND_SOC_DAPM_POST_PMU:
- return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
-
- case SND_SOC_DAPM_PRE_PMD:
- return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
-
- case SND_SOC_DAPM_POST_PMD:
- return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
- }
-
- return 0;
-}
-
-/*
- * In modelling, we assumed rest of the modules in pipeline are PGA. But we
- * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
- * the sink when it is running (two FE to one BE or one FE to two BE)
- * scenarios
- */
-static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
-
-{
- struct snd_soc_dapm_context *dapm = w->dapm;
- struct skl_dev *skl = get_skl_ctx(dapm->dev);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
-
- case SND_SOC_DAPM_POST_PMD:
- return skl_tplg_pga_dapm_post_pmd_event(w, skl);
- }
-
- return 0;
-}
-
-static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol,
- bool is_set)
-{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
- struct hdac_bus *bus = snd_soc_component_get_drvdata(component);
- struct skl_dev *skl = bus_to_skl(bus);
- struct skl_pipeline *ppl;
- struct skl_pipe *pipe = NULL;
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- u32 *pipe_id;
-
- if (!ec)
- return -EINVAL;
-
- if (is_set && ucontrol->value.enumerated.item[0] > ec->items)
- return -EINVAL;
-
- pipe_id = ec->dobj.private;
-
- list_for_each_entry(ppl, &skl->ppl_list, node) {
- if (ppl->pipe->ppl_id == *pipe_id) {
- pipe = ppl->pipe;
- break;
- }
- }
- if (!pipe)
- return -EIO;
-
- if (is_set)
- skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]);
- else
- ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
-
- return 0;
-}
-
-static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
-}
-
-static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
-}
-
-static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
-}
-
-static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
-}
-
-static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
- unsigned int __user *data, unsigned int size)
-{
- struct soc_bytes_ext *sb =
- (struct soc_bytes_ext *)kcontrol->private_value;
- struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
- struct skl_module_cfg *mconfig = w->priv;
- struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
-
- if (w->power)
- skl_get_module_params(skl, (u32 *)bc->params,
- bc->size, bc->param_id, mconfig);
-
- /* decrement size for TLV header */
- size -= 2 * sizeof(u32);
-
- /* check size as we don't want to send kernel data */
- if (size > bc->max)
- size = bc->max;
-
- if (bc->params) {
- if (copy_to_user(data, &bc->param_id, sizeof(u32)))
- return -EFAULT;
- if (copy_to_user(data + 1, &size, sizeof(u32)))
- return -EFAULT;
- if (copy_to_user(data + 2, bc->params, size))
- return -EFAULT;
- }
-
- return 0;
-}
-
-#define SKL_PARAM_VENDOR_ID 0xff
-
-static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
- const unsigned int __user *data, unsigned int size)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
- struct skl_module_cfg *mconfig = w->priv;
- struct soc_bytes_ext *sb =
- (struct soc_bytes_ext *)kcontrol->private_value;
- struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
- struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
-
- if (ac->params) {
- if (size > ac->max)
- return -EINVAL;
- ac->size = size;
-
- if (copy_from_user(ac->params, data, size))
- return -EFAULT;
-
- if (w->power)
- return skl_set_module_params(skl,
- (u32 *)ac->params, ac->size,
- ac->param_id, mconfig);
- }
-
- return 0;
-}
-
-static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
- struct skl_module_cfg *mconfig = w->priv;
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- u32 ch_type = *((u32 *)ec->dobj.private);
-
- if (mconfig->dmic_ch_type == ch_type)
- ucontrol->value.enumerated.item[0] =
- mconfig->dmic_ch_combo_index;
- else
- ucontrol->value.enumerated.item[0] = 0;
-
- return 0;
-}
-
-static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
- struct skl_mic_sel_config *mic_cfg, struct device *dev)
-{
- struct skl_specific_cfg *sp_cfg =
- &mconfig->formats_config[SKL_PARAM_INIT];
-
- sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
- sp_cfg->set_params = SKL_PARAM_SET;
- sp_cfg->param_id = 0x00;
- if (!sp_cfg->caps) {
- sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
- if (!sp_cfg->caps)
- return -ENOMEM;
- }
-
- mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
- mic_cfg->flags = 0;
- memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
-
- return 0;
-}
-
-static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
- struct skl_module_cfg *mconfig = w->priv;
- struct skl_mic_sel_config mic_cfg = {0};
- struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- u32 ch_type = *((u32 *)ec->dobj.private);
- const int *list;
- u8 in_ch, out_ch, index;
-
- mconfig->dmic_ch_type = ch_type;
- mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
-
- /* enum control index 0 is INVALID, so no channels to be set */
- if (mconfig->dmic_ch_combo_index == 0)
- return 0;
-
- /* No valid channel selection map for index 0, so offset by 1 */
- index = mconfig->dmic_ch_combo_index - 1;
-
- switch (ch_type) {
- case SKL_CH_MONO:
- if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
- return -EINVAL;
-
- list = &mic_mono_list[index];
- break;
-
- case SKL_CH_STEREO:
- if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
- return -EINVAL;
-
- list = mic_stereo_list[index];
- break;
-
- case SKL_CH_TRIO:
- if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
- return -EINVAL;
-
- list = mic_trio_list[index];
- break;
-
- case SKL_CH_QUATRO:
- if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
- return -EINVAL;
-
- list = mic_quatro_list[index];
- break;
-
- default:
- dev_err(w->dapm->dev,
- "Invalid channel %d for mic_select module\n",
- ch_type);
- return -EINVAL;
-
- }
-
- /* channel type enum map to number of chanels for that type */
- for (out_ch = 0; out_ch < ch_type; out_ch++) {
- in_ch = list[out_ch];
- mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
- }
-
- return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
-}
-
-/*
- * Fill the dma id for host and link. In case of passthrough
- * pipeline, this will both host and link in the same
- * pipeline, so need to copy the link and host based on dev_type
- */
-static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
- struct skl_pipe_params *params)
-{
- struct skl_pipe *pipe = mcfg->pipe;
-
- if (pipe->passthru) {
- switch (mcfg->dev_type) {
- case SKL_DEVICE_HDALINK:
- pipe->p_params->link_dma_id = params->link_dma_id;
- pipe->p_params->link_index = params->link_index;
- pipe->p_params->link_bps = params->link_bps;
- break;
-
- case SKL_DEVICE_HDAHOST:
- pipe->p_params->host_dma_id = params->host_dma_id;
- pipe->p_params->host_bps = params->host_bps;
- break;
-
- default:
- break;
- }
- pipe->p_params->s_fmt = params->s_fmt;
- pipe->p_params->ch = params->ch;
- pipe->p_params->s_freq = params->s_freq;
- pipe->p_params->stream = params->stream;
- pipe->p_params->format = params->format;
-
- } else {
- memcpy(pipe->p_params, params, sizeof(*params));
- }
-}
-
-/*
- * The FE params are passed by hw_params of the DAI.
- * On hw_params, the params are stored in Gateway module of the FE and we
- * need to calculate the format in DSP module configuration, that
- * conversion is done here
- */
-int skl_tplg_update_pipe_params(struct device *dev,
- struct skl_module_cfg *mconfig,
- struct skl_pipe_params *params)
-{
- struct skl_module_res *res;
- struct skl_dev *skl = get_skl_ctx(dev);
- struct skl_module_fmt *format = NULL;
- u8 cfg_idx = mconfig->pipe->cur_config_idx;
-
- res = &mconfig->module->resources[mconfig->res_idx];
- skl_tplg_fill_dma_id(mconfig, params);
- mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
- mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
-
- if (skl->nr_modules)
- return 0;
-
- if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
- format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt;
- else
- format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt;
-
- /* set the hw_params */
- format->s_freq = params->s_freq;
- format->channels = params->ch;
- format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
-
- /*
- * 16 bit is 16 bit container whereas 24 bit is in 32 bit
- * container so update bit depth accordingly
- */
- switch (format->valid_bit_depth) {
- case SKL_DEPTH_16BIT:
- format->bit_depth = format->valid_bit_depth;
- break;
-
- case SKL_DEPTH_24BIT:
- case SKL_DEPTH_32BIT:
- format->bit_depth = SKL_DEPTH_32BIT;
- break;
-
- default:
- dev_err(dev, "Invalid bit depth %x for pipe\n",
- format->valid_bit_depth);
- return -EINVAL;
- }
-
- if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- res->ibs = (format->s_freq / 1000) *
- (format->channels) *
- (format->bit_depth >> 3);
- } else {
- res->obs = (format->s_freq / 1000) *
- (format->channels) *
- (format->bit_depth >> 3);
- }
-
- return 0;
-}
-
-/*
- * Query the module config for the FE DAI
- * This is used to find the hw_params set for that DAI and apply to FE
- * pipeline
- */
-struct skl_module_cfg *
-skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
- struct snd_soc_dapm_path *p = NULL;
-
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (p->connect && p->sink->power &&
- !is_skl_dsp_widget_type(p->sink, dai->dev))
- continue;
-
- if (p->sink->priv) {
- dev_dbg(dai->dev, "set params for %s\n",
- p->sink->name);
- return p->sink->priv;
- }
- }
- } else {
- snd_soc_dapm_widget_for_each_source_path(w, p) {
- if (p->connect && p->source->power &&
- !is_skl_dsp_widget_type(p->source, dai->dev))
- continue;
-
- if (p->source->priv) {
- dev_dbg(dai->dev, "set params for %s\n",
- p->source->name);
- return p->source->priv;
- }
- }
- }
-
- return NULL;
-}
-
-static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
- struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
-{
- struct snd_soc_dapm_path *p;
- struct skl_module_cfg *mconfig = NULL;
-
- snd_soc_dapm_widget_for_each_source_path(w, p) {
- if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
- if (p->connect &&
- (p->sink->id == snd_soc_dapm_aif_out) &&
- p->source->priv) {
- mconfig = p->source->priv;
- return mconfig;
- }
- mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
- if (mconfig)
- return mconfig;
- }
- }
- return mconfig;
-}
-
-static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
- struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
-{
- struct snd_soc_dapm_path *p;
- struct skl_module_cfg *mconfig = NULL;
-
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
- if (p->connect &&
- (p->source->id == snd_soc_dapm_aif_in) &&
- p->sink->priv) {
- mconfig = p->sink->priv;
- return mconfig;
- }
- mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
- if (mconfig)
- return mconfig;
- }
- }
- return mconfig;
-}
-
-struct skl_module_cfg *
-skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
- struct skl_module_cfg *mconfig;
-
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mconfig = skl_get_mconfig_pb_cpr(dai, w);
- } else {
- mconfig = skl_get_mconfig_cap_cpr(dai, w);
- }
- return mconfig;
-}
-
-static u8 skl_tplg_be_link_type(int dev_type)
-{
- int ret;
-
- switch (dev_type) {
- case SKL_DEVICE_BT:
- ret = NHLT_LINK_SSP;
- break;
-
- case SKL_DEVICE_DMIC:
- ret = NHLT_LINK_DMIC;
- break;
-
- case SKL_DEVICE_I2S:
- ret = NHLT_LINK_SSP;
- break;
-
- case SKL_DEVICE_HDALINK:
- ret = NHLT_LINK_HDA;
- break;
-
- default:
- ret = NHLT_LINK_INVALID;
- break;
- }
-
- return ret;
-}
-
-/*
- * Fill the BE gateway parameters
- * The BE gateway expects a blob of parameters which are kept in the ACPI
- * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
- * The port can have multiple settings so pick based on the pipeline
- * parameters
- */
-static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
- struct skl_module_cfg *mconfig,
- struct skl_pipe_params *params)
-{
- struct nhlt_specific_cfg *cfg;
- struct skl_pipe *pipe = mconfig->pipe;
- struct skl_pipe_params save = *pipe->p_params;
- struct skl_pipe_fmt *pipe_fmt;
- struct skl_dev *skl = get_skl_ctx(dai->dev);
- int link_type = skl_tplg_be_link_type(mconfig->dev_type);
- u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
- int ret;
-
- skl_tplg_fill_dma_id(mconfig, params);
-
- if (link_type == NHLT_LINK_HDA)
- return 0;
-
- *pipe->p_params = *params;
- ret = skl_tplg_get_pipe_config(skl, mconfig);
- if (ret)
- goto err;
-
- dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx);
- if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
- pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt;
- else
- pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt;
-
- /* update the blob based on virtual bus_id*/
- cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt,
- mconfig->vbus_id, link_type,
- pipe_fmt->bps, params->s_cont,
- pipe_fmt->channels, pipe_fmt->freq,
- pipe->direction, dev_type);
- if (cfg) {
- mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
- mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
- } else {
- dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
- mconfig->vbus_id, link_type, params->stream,
- params->ch, params->s_freq, params->s_fmt);
- ret = -EINVAL;
- goto err;
- }
-
- return 0;
-
-err:
- *pipe->p_params = save;
- return ret;
-}
-
-static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
- struct snd_soc_dapm_widget *w,
- struct skl_pipe_params *params)
-{
- struct snd_soc_dapm_path *p;
- int ret = -EIO;
-
- snd_soc_dapm_widget_for_each_source_path(w, p) {
- if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
- p->source->priv) {
-
- ret = skl_tplg_be_fill_pipe_params(dai,
- p->source->priv, params);
- if (ret < 0)
- return ret;
- } else {
- ret = skl_tplg_be_set_src_pipe_params(dai,
- p->source, params);
- if (ret < 0)
- return ret;
- }
- }
-
- return ret;
-}
-
-static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
- struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
-{
- struct snd_soc_dapm_path *p;
- int ret = -EIO;
-
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
- p->sink->priv) {
-
- ret = skl_tplg_be_fill_pipe_params(dai,
- p->sink->priv, params);
- if (ret < 0)
- return ret;
- } else {
- ret = skl_tplg_be_set_sink_pipe_params(
- dai, p->sink, params);
- if (ret < 0)
- return ret;
- }
- }
-
- return ret;
-}
-
-/*
- * BE hw_params can be a source parameters (capture) or sink parameters
- * (playback). Based on sink and source we need to either find the source
- * list or the sink list and set the pipeline parameters
- */
-int skl_tplg_be_update_params(struct snd_soc_dai *dai,
- struct skl_pipe_params *params)
-{
- struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, params->stream);
-
- if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- return skl_tplg_be_set_src_pipe_params(dai, w, params);
- } else {
- return skl_tplg_be_set_sink_pipe_params(dai, w, params);
- }
-}
-
-static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
- {SKL_MIXER_EVENT, skl_tplg_mixer_event},
- {SKL_VMIXER_EVENT, skl_tplg_mixer_event},
- {SKL_PGA_EVENT, skl_tplg_pga_event},
-};
-
-static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
- {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
- skl_tplg_tlv_control_set},
-};
-
-static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
- {
- .id = SKL_CONTROL_TYPE_MIC_SELECT,
- .get = skl_tplg_mic_control_get,
- .put = skl_tplg_mic_control_set,
- },
- {
- .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
- .get = skl_tplg_multi_config_get,
- .put = skl_tplg_multi_config_set,
- },
- {
- .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC,
- .get = skl_tplg_multi_config_get_dmic,
- .put = skl_tplg_multi_config_set_dmic,
- }
-};
-
-static int skl_tplg_fill_pipe_cfg(struct device *dev,
- struct skl_pipe *pipe, u32 tkn,
- u32 tkn_val, int conf_idx, int dir)
-{
- struct skl_pipe_fmt *fmt;
- struct skl_path_config *config;
-
- switch (dir) {
- case SKL_DIR_IN:
- fmt = &pipe->configs[conf_idx].in_fmt;
- break;
-
- case SKL_DIR_OUT:
- fmt = &pipe->configs[conf_idx].out_fmt;
- break;
-
- default:
- dev_err(dev, "Invalid direction: %d\n", dir);
- return -EINVAL;
- }
-
- config = &pipe->configs[conf_idx];
-
- switch (tkn) {
- case SKL_TKN_U32_CFG_FREQ:
- fmt->freq = tkn_val;
- break;
-
- case SKL_TKN_U8_CFG_CHAN:
- fmt->channels = tkn_val;
- break;
-
- case SKL_TKN_U8_CFG_BPS:
- fmt->bps = tkn_val;
- break;
-
- case SKL_TKN_U32_PATH_MEM_PGS:
- config->mem_pages = tkn_val;
- break;
-
- default:
- dev_err(dev, "Invalid token config: %d\n", tkn);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int skl_tplg_fill_pipe_tkn(struct device *dev,
- struct skl_pipe *pipe, u32 tkn,
- u32 tkn_val)
-{
-
- switch (tkn) {
- case SKL_TKN_U32_PIPE_CONN_TYPE:
- pipe->conn_type = tkn_val;
- break;
-
- case SKL_TKN_U32_PIPE_PRIORITY:
- pipe->pipe_priority = tkn_val;
- break;
-
- case SKL_TKN_U32_PIPE_MEM_PGS:
- pipe->memory_pages = tkn_val;
- break;
-
- case SKL_TKN_U32_PMODE:
- pipe->lp_mode = tkn_val;
- break;
-
- case SKL_TKN_U32_PIPE_DIRECTION:
- pipe->direction = tkn_val;
- break;
-
- case SKL_TKN_U32_NUM_CONFIGS:
- pipe->nr_cfgs = tkn_val;
- break;
-
- default:
- dev_err(dev, "Token not handled %d\n", tkn);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * Add pipeline by parsing the relevant tokens
- * Return an existing pipe if the pipe already exists.
- */
-static int skl_tplg_add_pipe(struct device *dev,
- struct skl_module_cfg *mconfig, struct skl_dev *skl,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem)
-{
- struct skl_pipeline *ppl;
- struct skl_pipe *pipe;
- struct skl_pipe_params *params;
-
- list_for_each_entry(ppl, &skl->ppl_list, node) {
- if (ppl->pipe->ppl_id == tkn_elem->value) {
- mconfig->pipe = ppl->pipe;
- return -EEXIST;
- }
- }
-
- ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
- if (!ppl)
- return -ENOMEM;
-
- pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
- if (!pipe)
- return -ENOMEM;
-
- params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
- if (!params)
- return -ENOMEM;
-
- pipe->p_params = params;
- pipe->ppl_id = tkn_elem->value;
- INIT_LIST_HEAD(&pipe->w_list);
-
- ppl->pipe = pipe;
- list_add(&ppl->node, &skl->ppl_list);
-
- mconfig->pipe = pipe;
- mconfig->pipe->state = SKL_PIPE_INVALID;
-
- return 0;
-}
-
-static int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
- struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
-{
- if (uuid_tkn->token == SKL_TKN_UUID) {
- import_guid(guid, uuid_tkn->uuid);
- return 0;
- }
-
- dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
-
- return -EINVAL;
-}
-
-static int skl_tplg_fill_pin(struct device *dev,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- struct skl_module_pin *m_pin,
- int pin_index)
-{
- int ret;
-
- switch (tkn_elem->token) {
- case SKL_TKN_U32_PIN_MOD_ID:
- m_pin[pin_index].id.module_id = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_PIN_INST_ID:
- m_pin[pin_index].id.instance_id = tkn_elem->value;
- break;
-
- case SKL_TKN_UUID:
- ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
- (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
- if (ret < 0)
- return ret;
-
- break;
-
- default:
- dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * Parse for pin config specific tokens to fill up the
- * module private data
- */
-static int skl_tplg_fill_pins_info(struct device *dev,
- struct skl_module_cfg *mconfig,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- int dir, int pin_count)
-{
- int ret;
- struct skl_module_pin *m_pin;
-
- switch (dir) {
- case SKL_DIR_IN:
- m_pin = mconfig->m_in_pin;
- break;
-
- case SKL_DIR_OUT:
- m_pin = mconfig->m_out_pin;
- break;
-
- default:
- dev_err(dev, "Invalid direction value\n");
- return -EINVAL;
- }
-
- ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
- if (ret < 0)
- return ret;
-
- m_pin[pin_count].in_use = false;
- m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
-
- return 0;
-}
-
-/*
- * Fill up input/output module config format based
- * on the direction
- */
-static int skl_tplg_fill_fmt(struct device *dev,
- struct skl_module_fmt *dst_fmt,
- u32 tkn, u32 value)
-{
- switch (tkn) {
- case SKL_TKN_U32_FMT_CH:
- dst_fmt->channels = value;
- break;
-
- case SKL_TKN_U32_FMT_FREQ:
- dst_fmt->s_freq = value;
- break;
-
- case SKL_TKN_U32_FMT_BIT_DEPTH:
- dst_fmt->bit_depth = value;
- break;
-
- case SKL_TKN_U32_FMT_SAMPLE_SIZE:
- dst_fmt->valid_bit_depth = value;
- break;
-
- case SKL_TKN_U32_FMT_CH_CONFIG:
- dst_fmt->ch_cfg = value;
- break;
-
- case SKL_TKN_U32_FMT_INTERLEAVE:
- dst_fmt->interleaving_style = value;
- break;
-
- case SKL_TKN_U32_FMT_SAMPLE_TYPE:
- dst_fmt->sample_type = value;
- break;
-
- case SKL_TKN_U32_FMT_CH_MAP:
- dst_fmt->ch_map = value;
- break;
-
- default:
- dev_err(dev, "Invalid token %d\n", tkn);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int skl_tplg_widget_fill_fmt(struct device *dev,
- struct skl_module_iface *fmt,
- u32 tkn, u32 val, u32 dir, int fmt_idx)
-{
- struct skl_module_fmt *dst_fmt;
-
- if (!fmt)
- return -EINVAL;
-
- switch (dir) {
- case SKL_DIR_IN:
- dst_fmt = &fmt->inputs[fmt_idx].fmt;
- break;
-
- case SKL_DIR_OUT:
- dst_fmt = &fmt->outputs[fmt_idx].fmt;
- break;
-
- default:
- dev_err(dev, "Invalid direction: %d\n", dir);
- return -EINVAL;
- }
-
- return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
-}
-
-static void skl_tplg_fill_pin_dynamic_val(
- struct skl_module_pin *mpin, u32 pin_count, u32 value)
-{
- int i;
-
- for (i = 0; i < pin_count; i++)
- mpin[i].is_dynamic = value;
-}
-
-/*
- * Resource table in the manifest has pin specific resources
- * like pin and pin buffer size
- */
-static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- struct skl_module_res *res, int pin_idx, int dir)
-{
- struct skl_module_pin_resources *m_pin;
-
- switch (dir) {
- case SKL_DIR_IN:
- m_pin = &res->input[pin_idx];
- break;
-
- case SKL_DIR_OUT:
- m_pin = &res->output[pin_idx];
- break;
-
- default:
- dev_err(dev, "Invalid pin direction: %d\n", dir);
- return -EINVAL;
- }
-
- switch (tkn_elem->token) {
- case SKL_TKN_MM_U32_RES_PIN_ID:
- m_pin->pin_index = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U32_PIN_BUF:
- m_pin->buf_size = tkn_elem->value;
- break;
-
- default:
- dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * Fill module specific resources from the manifest's resource
- * table like CPS, DMA size, mem_pages.
- */
-static int skl_tplg_fill_res_tkn(struct device *dev,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- struct skl_module_res *res,
- int pin_idx, int dir)
-{
- int ret, tkn_count = 0;
-
- if (!res)
- return -EINVAL;
-
- switch (tkn_elem->token) {
- case SKL_TKN_MM_U32_DMA_SIZE:
- res->dma_buffer_size = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U32_CPC:
- res->cpc = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_MEM_PAGES:
- res->is_pages = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_OBS:
- res->obs = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_IBS:
- res->ibs = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U32_RES_PIN_ID:
- case SKL_TKN_MM_U32_PIN_BUF:
- ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
- pin_idx, dir);
- if (ret < 0)
- return ret;
- break;
-
- case SKL_TKN_MM_U32_CPS:
- case SKL_TKN_U32_MAX_MCPS:
- /* ignore unused tokens */
- break;
-
- default:
- dev_err(dev, "Not a res type token: %d", tkn_elem->token);
- return -EINVAL;
-
- }
- tkn_count++;
-
- return tkn_count;
-}
-
-/*
- * Parse tokens to fill up the module private data
- */
-static int skl_tplg_get_token(struct device *dev,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- struct skl_dev *skl, struct skl_module_cfg *mconfig)
-{
- int tkn_count = 0;
- int ret;
- static int is_pipe_exists;
- static int pin_index, dir, conf_idx;
- struct skl_module_iface *iface = NULL;
- struct skl_module_res *res = NULL;
- int res_idx = mconfig->res_idx;
- int fmt_idx = mconfig->fmt_idx;
-
- /*
- * If the manifest structure contains no modules, fill all
- * the module data to 0th index.
- * res_idx and fmt_idx are default set to 0.
- */
- if (skl->nr_modules == 0) {
- res = &mconfig->module->resources[res_idx];
- iface = &mconfig->module->formats[fmt_idx];
- }
-
- if (tkn_elem->token > SKL_TKN_MAX)
- return -EINVAL;
-
- switch (tkn_elem->token) {
- case SKL_TKN_U8_IN_QUEUE_COUNT:
- mconfig->module->max_input_pins = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_OUT_QUEUE_COUNT:
- mconfig->module->max_output_pins = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_DYN_IN_PIN:
- if (!mconfig->m_in_pin)
- mconfig->m_in_pin =
- devm_kcalloc(dev, MAX_IN_QUEUE,
- sizeof(*mconfig->m_in_pin),
- GFP_KERNEL);
- if (!mconfig->m_in_pin)
- return -ENOMEM;
-
- skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
- tkn_elem->value);
- break;
-
- case SKL_TKN_U8_DYN_OUT_PIN:
- if (!mconfig->m_out_pin)
- mconfig->m_out_pin =
- devm_kcalloc(dev, MAX_IN_QUEUE,
- sizeof(*mconfig->m_in_pin),
- GFP_KERNEL);
- if (!mconfig->m_out_pin)
- return -ENOMEM;
-
- skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
- tkn_elem->value);
- break;
-
- case SKL_TKN_U8_TIME_SLOT:
- mconfig->time_slot = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_CORE_ID:
- mconfig->core_id = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_MOD_TYPE:
- mconfig->m_type = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_DEV_TYPE:
- mconfig->dev_type = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_HW_CONN_TYPE:
- mconfig->hw_conn_type = tkn_elem->value;
- break;
-
- case SKL_TKN_U16_MOD_INST_ID:
- mconfig->id.instance_id =
- tkn_elem->value;
- break;
-
- case SKL_TKN_U32_MEM_PAGES:
- case SKL_TKN_U32_MAX_MCPS:
- case SKL_TKN_U32_OBS:
- case SKL_TKN_U32_IBS:
- ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
- if (ret < 0)
- return ret;
-
- break;
-
- case SKL_TKN_U32_VBUS_ID:
- mconfig->vbus_id = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_PARAMS_FIXUP:
- mconfig->params_fixup = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_CONVERTER:
- mconfig->converter = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_D0I3_CAPS:
- mconfig->d0i3_caps = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_PIPE_ID:
- ret = skl_tplg_add_pipe(dev,
- mconfig, skl, tkn_elem);
-
- if (ret < 0) {
- if (ret == -EEXIST) {
- is_pipe_exists = 1;
- break;
- }
- return is_pipe_exists;
- }
-
- break;
-
- case SKL_TKN_U32_PIPE_CONFIG_ID:
- conf_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_PIPE_CONN_TYPE:
- case SKL_TKN_U32_PIPE_PRIORITY:
- case SKL_TKN_U32_PIPE_MEM_PGS:
- case SKL_TKN_U32_PMODE:
- case SKL_TKN_U32_PIPE_DIRECTION:
- case SKL_TKN_U32_NUM_CONFIGS:
- if (is_pipe_exists) {
- ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
- tkn_elem->token, tkn_elem->value);
- if (ret < 0)
- return ret;
- }
-
- break;
-
- case SKL_TKN_U32_PATH_MEM_PGS:
- case SKL_TKN_U32_CFG_FREQ:
- case SKL_TKN_U8_CFG_CHAN:
- case SKL_TKN_U8_CFG_BPS:
- if (mconfig->pipe->nr_cfgs) {
- ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
- tkn_elem->token, tkn_elem->value,
- conf_idx, dir);
- if (ret < 0)
- return ret;
- }
- break;
-
- case SKL_TKN_CFG_MOD_RES_ID:
- mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_CFG_MOD_FMT_ID:
- mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
- break;
-
- /*
- * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
- * direction and the pin count. The first four bits represent
- * direction and next four the pin count.
- */
- case SKL_TKN_U32_DIR_PIN_COUNT:
- dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
- pin_index = (tkn_elem->value &
- SKL_PIN_COUNT_MASK) >> 4;
-
- break;
-
- case SKL_TKN_U32_FMT_CH:
- case SKL_TKN_U32_FMT_FREQ:
- case SKL_TKN_U32_FMT_BIT_DEPTH:
- case SKL_TKN_U32_FMT_SAMPLE_SIZE:
- case SKL_TKN_U32_FMT_CH_CONFIG:
- case SKL_TKN_U32_FMT_INTERLEAVE:
- case SKL_TKN_U32_FMT_SAMPLE_TYPE:
- case SKL_TKN_U32_FMT_CH_MAP:
- ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
- tkn_elem->value, dir, pin_index);
-
- if (ret < 0)
- return ret;
-
- break;
-
- case SKL_TKN_U32_PIN_MOD_ID:
- case SKL_TKN_U32_PIN_INST_ID:
- case SKL_TKN_UUID:
- ret = skl_tplg_fill_pins_info(dev,
- mconfig, tkn_elem, dir,
- pin_index);
- if (ret < 0)
- return ret;
-
- break;
-
- case SKL_TKN_U32_FMT_CFG_IDX:
- if (tkn_elem->value > SKL_MAX_PARAMS_TYPES)
- return -EINVAL;
-
- mconfig->fmt_cfg_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_CAPS_SIZE:
- mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size =
- tkn_elem->value;
-
- break;
-
- case SKL_TKN_U32_CAPS_SET_PARAMS:
- mconfig->formats_config[mconfig->fmt_cfg_idx].set_params =
- tkn_elem->value;
- break;
-
- case SKL_TKN_U32_CAPS_PARAMS_ID:
- mconfig->formats_config[mconfig->fmt_cfg_idx].param_id =
- tkn_elem->value;
- break;
-
- case SKL_TKN_U32_PROC_DOMAIN:
- mconfig->domain =
- tkn_elem->value;
-
- break;
-
- case SKL_TKN_U32_DMA_BUF_SIZE:
- mconfig->dma_buffer_size = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_IN_PIN_TYPE:
- case SKL_TKN_U8_OUT_PIN_TYPE:
- case SKL_TKN_U8_CONN_TYPE:
- break;
-
- default:
- dev_err(dev, "Token %d not handled\n",
- tkn_elem->token);
- return -EINVAL;
- }
-
- tkn_count++;
-
- return tkn_count;
-}
-
-/*
- * Parse the vendor array for specific tokens to construct
- * module private data
- */
-static int skl_tplg_get_tokens(struct device *dev,
- char *pvt_data, struct skl_dev *skl,
- struct skl_module_cfg *mconfig, int block_size)
-{
- struct snd_soc_tplg_vendor_array *array;
- struct snd_soc_tplg_vendor_value_elem *tkn_elem;
- int tkn_count = 0, ret;
- int off = 0, tuple_size = 0;
- bool is_module_guid = true;
-
- if (block_size <= 0)
- return -EINVAL;
-
- while (tuple_size < block_size) {
- array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
-
- off += array->size;
-
- switch (array->type) {
- case SND_SOC_TPLG_TUPLE_TYPE_STRING:
- dev_warn(dev, "no string tokens expected for skl tplg\n");
- continue;
-
- case SND_SOC_TPLG_TUPLE_TYPE_UUID:
- if (is_module_guid) {
- ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
- array->uuid);
- is_module_guid = false;
- } else {
- ret = skl_tplg_get_token(dev, array->value, skl,
- mconfig);
- }
-
- if (ret < 0)
- return ret;
-
- tuple_size += sizeof(*array->uuid);
-
- continue;
-
- default:
- tkn_elem = array->value;
- tkn_count = 0;
- break;
- }
-
- while (tkn_count <= (array->num_elems - 1)) {
- ret = skl_tplg_get_token(dev, tkn_elem,
- skl, mconfig);
-
- if (ret < 0)
- return ret;
-
- tkn_count = tkn_count + ret;
- tkn_elem++;
- }
-
- tuple_size += tkn_count * sizeof(*tkn_elem);
- }
-
- return off;
-}
-
-/*
- * Every data block is preceded by a descriptor to read the number
- * of data blocks, they type of the block and it's size
- */
-static int skl_tplg_get_desc_blocks(struct device *dev,
- struct snd_soc_tplg_vendor_array *array)
-{
- struct snd_soc_tplg_vendor_value_elem *tkn_elem;
-
- tkn_elem = array->value;
-
- switch (tkn_elem->token) {
- case SKL_TKN_U8_NUM_BLOCKS:
- case SKL_TKN_U8_BLOCK_TYPE:
- case SKL_TKN_U16_BLOCK_SIZE:
- return tkn_elem->value;
-
- default:
- dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
- break;
- }
-
- return -EINVAL;
-}
-
-/* Functions to parse private data from configuration file format v4 */
-
-/*
- * Add pipeline from topology binary into driver pipeline list
- *
- * If already added we return that instance
- * Otherwise we create a new instance and add into driver list
- */
-static int skl_tplg_add_pipe_v4(struct device *dev,
- struct skl_module_cfg *mconfig, struct skl_dev *skl,
- struct skl_dfw_v4_pipe *dfw_pipe)
-{
- struct skl_pipeline *ppl;
- struct skl_pipe *pipe;
- struct skl_pipe_params *params;
-
- list_for_each_entry(ppl, &skl->ppl_list, node) {
- if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
- mconfig->pipe = ppl->pipe;
- return 0;
- }
- }
-
- ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
- if (!ppl)
- return -ENOMEM;
-
- pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
- if (!pipe)
- return -ENOMEM;
-
- params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
- if (!params)
- return -ENOMEM;
-
- pipe->ppl_id = dfw_pipe->pipe_id;
- pipe->memory_pages = dfw_pipe->memory_pages;
- pipe->pipe_priority = dfw_pipe->pipe_priority;
- pipe->conn_type = dfw_pipe->conn_type;
- pipe->state = SKL_PIPE_INVALID;
- pipe->p_params = params;
- INIT_LIST_HEAD(&pipe->w_list);
-
- ppl->pipe = pipe;
- list_add(&ppl->node, &skl->ppl_list);
-
- mconfig->pipe = pipe;
-
- return 0;
-}
-
-static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
- struct skl_module_pin *m_pin,
- bool is_dynamic, int max_pin)
-{
- int i;
-
- for (i = 0; i < max_pin; i++) {
- m_pin[i].id.module_id = dfw_pin[i].module_id;
- m_pin[i].id.instance_id = dfw_pin[i].instance_id;
- m_pin[i].in_use = false;
- m_pin[i].is_dynamic = is_dynamic;
- m_pin[i].pin_state = SKL_PIN_UNBIND;
- }
-}
-
-static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
- struct skl_dfw_v4_module_fmt *src_fmt,
- int pins)
-{
- int i;
-
- for (i = 0; i < pins; i++) {
- dst_fmt[i].fmt.channels = src_fmt[i].channels;
- dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
- dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
- dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
- dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
- dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
- dst_fmt[i].fmt.interleaving_style =
- src_fmt[i].interleaving_style;
- dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
- }
-}
-
-static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
- struct skl_dev *skl, struct device *dev,
- struct skl_module_cfg *mconfig)
-{
- struct skl_dfw_v4_module *dfw =
- (struct skl_dfw_v4_module *)tplg_w->priv.data;
- int ret;
- int idx = mconfig->fmt_cfg_idx;
-
- dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
-
- ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
- if (ret)
- return ret;
- mconfig->id.module_id = -1;
- mconfig->id.instance_id = dfw->instance_id;
- mconfig->module->resources[0].cpc = dfw->max_mcps / 1000;
- mconfig->module->resources[0].ibs = dfw->ibs;
- mconfig->module->resources[0].obs = dfw->obs;
- mconfig->core_id = dfw->core_id;
- mconfig->module->max_input_pins = dfw->max_in_queue;
- mconfig->module->max_output_pins = dfw->max_out_queue;
- mconfig->module->loadable = dfw->is_loadable;
- skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
- MAX_IN_QUEUE);
- skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
- MAX_OUT_QUEUE);
-
- mconfig->params_fixup = dfw->params_fixup;
- mconfig->converter = dfw->converter;
- mconfig->m_type = dfw->module_type;
- mconfig->vbus_id = dfw->vbus_id;
- mconfig->module->resources[0].is_pages = dfw->mem_pages;
-
- ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
- if (ret)
- return ret;
-
- mconfig->dev_type = dfw->dev_type;
- mconfig->hw_conn_type = dfw->hw_conn_type;
- mconfig->time_slot = dfw->time_slot;
- mconfig->formats_config[idx].caps_size = dfw->caps.caps_size;
-
- mconfig->m_in_pin = devm_kcalloc(dev,
- MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
- GFP_KERNEL);
- if (!mconfig->m_in_pin)
- return -ENOMEM;
-
- mconfig->m_out_pin = devm_kcalloc(dev,
- MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
- GFP_KERNEL);
- if (!mconfig->m_out_pin)
- return -ENOMEM;
-
- skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
- dfw->is_dynamic_in_pin,
- mconfig->module->max_input_pins);
- skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
- dfw->is_dynamic_out_pin,
- mconfig->module->max_output_pins);
-
- if (mconfig->formats_config[idx].caps_size) {
- mconfig->formats_config[idx].set_params = dfw->caps.set_params;
- mconfig->formats_config[idx].param_id = dfw->caps.param_id;
- mconfig->formats_config[idx].caps =
- devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
- GFP_KERNEL);
- if (!mconfig->formats_config[idx].caps)
- return -ENOMEM;
- memcpy(mconfig->formats_config[idx].caps, dfw->caps.caps,
- dfw->caps.caps_size);
- }
-
- return 0;
-}
-
-static int skl_tplg_get_caps_data(struct device *dev, char *data,
- struct skl_module_cfg *mconfig)
-{
- int idx = mconfig->fmt_cfg_idx;
-
- if (mconfig->formats_config[idx].caps_size > 0) {
- mconfig->formats_config[idx].caps =
- devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
- GFP_KERNEL);
- if (!mconfig->formats_config[idx].caps)
- return -ENOMEM;
- memcpy(mconfig->formats_config[idx].caps, data,
- mconfig->formats_config[idx].caps_size);
- }
-
- return mconfig->formats_config[idx].caps_size;
-}
-
-/*
- * Parse the private data for the token and corresponding value.
- * The private data can have multiple data blocks. So, a data block
- * is preceded by a descriptor for number of blocks and a descriptor
- * for the type and size of the suceeding data block.
- */
-static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
- struct skl_dev *skl, struct device *dev,
- struct skl_module_cfg *mconfig)
-{
- struct snd_soc_tplg_vendor_array *array;
- int num_blocks, block_size, block_type, off = 0;
- char *data;
- int ret;
-
- /*
- * v4 configuration files have a valid UUID at the start of
- * the widget's private data.
- */
- if (uuid_is_valid((char *)tplg_w->priv.data))
- return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
-
- /* Read the NUM_DATA_BLOCKS descriptor */
- array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
- ret = skl_tplg_get_desc_blocks(dev, array);
- if (ret < 0)
- return ret;
- num_blocks = ret;
-
- off += array->size;
- /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
- while (num_blocks > 0) {
- array = (struct snd_soc_tplg_vendor_array *)
- (tplg_w->priv.data + off);
-
- ret = skl_tplg_get_desc_blocks(dev, array);
-
- if (ret < 0)
- return ret;
- block_type = ret;
- off += array->size;
-
- array = (struct snd_soc_tplg_vendor_array *)
- (tplg_w->priv.data + off);
-
- ret = skl_tplg_get_desc_blocks(dev, array);
-
- if (ret < 0)
- return ret;
- block_size = ret;
- off += array->size;
-
- data = (tplg_w->priv.data + off);
-
- if (block_type == SKL_TYPE_TUPLE) {
- ret = skl_tplg_get_tokens(dev, data,
- skl, mconfig, block_size);
- } else {
- ret = skl_tplg_get_caps_data(dev, data, mconfig);
- }
-
- if (ret < 0)
- return ret;
-
- --num_blocks;
- off += ret;
- }
-
- return 0;
-}
-
-static void skl_clear_pin_config(struct snd_soc_component *component,
- struct snd_soc_dapm_widget *w)
-{
- int i;
- struct skl_module_cfg *mconfig;
- struct skl_pipe *pipe;
-
- if (!strncmp(w->dapm->component->name, component->name,
- strlen(component->name))) {
- mconfig = w->priv;
- pipe = mconfig->pipe;
- for (i = 0; i < mconfig->module->max_input_pins; i++) {
- mconfig->m_in_pin[i].in_use = false;
- mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
- }
- for (i = 0; i < mconfig->module->max_output_pins; i++) {
- mconfig->m_out_pin[i].in_use = false;
- mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
- }
- pipe->state = SKL_PIPE_INVALID;
- mconfig->m_state = SKL_MODULE_UNINIT;
- }
-}
-
-void skl_cleanup_resources(struct skl_dev *skl)
-{
- struct snd_soc_component *soc_component = skl->component;
- struct snd_soc_dapm_widget *w;
- struct snd_soc_card *card;
-
- if (soc_component == NULL)
- return;
-
- card = soc_component->card;
- if (!snd_soc_card_is_instantiated(card))
- return;
-
- list_for_each_entry(w, &card->widgets, list) {
- if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
- skl_clear_pin_config(soc_component, w);
- }
-
- skl_clear_module_cnt(skl->dsp);
-}
-
-/*
- * Topology core widget load callback
- *
- * This is used to save the private data for each widget which gives
- * information to the driver about module and pipeline parameters which DSP
- * FW expects like ids, resource values, formats etc
- */
-static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
- struct snd_soc_dapm_widget *w,
- struct snd_soc_tplg_dapm_widget *tplg_w)
-{
- int ret;
- struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
- struct skl_dev *skl = bus_to_skl(bus);
- struct skl_module_cfg *mconfig;
-
- if (!tplg_w->priv.size)
- goto bind_event;
-
- mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
-
- if (!mconfig)
- return -ENOMEM;
-
- if (skl->nr_modules == 0) {
- mconfig->module = devm_kzalloc(bus->dev,
- sizeof(*mconfig->module), GFP_KERNEL);
- if (!mconfig->module)
- return -ENOMEM;
- }
-
- w->priv = mconfig;
-
- /*
- * module binary can be loaded later, so set it to query when
- * module is load for a use case
- */
- mconfig->id.module_id = -1;
-
- /* To provide backward compatibility, set default as SKL_PARAM_INIT */
- mconfig->fmt_cfg_idx = SKL_PARAM_INIT;
-
- /* Parse private data for tuples */
- ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
- if (ret < 0)
- return ret;
-
- skl_debug_init_module(skl->debugfs, w, mconfig);
-
-bind_event:
- if (tplg_w->event_type == 0) {
- dev_dbg(bus->dev, "ASoC: No event handler required\n");
- return 0;
- }
-
- ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
- ARRAY_SIZE(skl_tplg_widget_ops),
- tplg_w->event_type);
-
- if (ret) {
- dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
- __func__, tplg_w->event_type);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
- struct snd_soc_tplg_bytes_control *bc)
-{
- struct skl_algo_data *ac;
- struct skl_dfw_algo_data *dfw_ac =
- (struct skl_dfw_algo_data *)bc->priv.data;
-
- ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
- if (!ac)
- return -ENOMEM;
-
- /* Fill private data */
- ac->max = dfw_ac->max;
- ac->param_id = dfw_ac->param_id;
- ac->set_params = dfw_ac->set_params;
- ac->size = dfw_ac->max;
-
- if (ac->max) {
- ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
- if (!ac->params)
- return -ENOMEM;
-
- memcpy(ac->params, dfw_ac->params, ac->max);
- }
-
- be->dobj.private = ac;
- return 0;
-}
-
-static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
- struct snd_soc_tplg_enum_control *ec)
-{
-
- void *data;
-
- if (ec->priv.size) {
- data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- memcpy(data, ec->priv.data, ec->priv.size);
- se->dobj.private = data;
- }
-
- return 0;
-
-}
-
-static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
- int index,
- struct snd_kcontrol_new *kctl,
- struct snd_soc_tplg_ctl_hdr *hdr)
-{
- struct soc_bytes_ext *sb;
- struct snd_soc_tplg_bytes_control *tplg_bc;
- struct snd_soc_tplg_enum_control *tplg_ec;
- struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
- struct soc_enum *se;
-
- switch (hdr->ops.info) {
- case SND_SOC_TPLG_CTL_BYTES:
- tplg_bc = container_of(hdr,
- struct snd_soc_tplg_bytes_control, hdr);
- if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
- sb = (struct soc_bytes_ext *)kctl->private_value;
- if (tplg_bc->priv.size)
- return skl_init_algo_data(
- bus->dev, sb, tplg_bc);
- }
- break;
-
- case SND_SOC_TPLG_CTL_ENUM:
- tplg_ec = container_of(hdr,
- struct snd_soc_tplg_enum_control, hdr);
- if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) {
- se = (struct soc_enum *)kctl->private_value;
- if (tplg_ec->priv.size)
- skl_init_enum_data(bus->dev, se, tplg_ec);
- }
-
- /*
- * now that the control initializations are done, remove
- * write permission for the DMIC configuration enums to
- * avoid conflicts between NHLT settings and user interaction
- */
-
- if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC)
- kctl->access = SNDRV_CTL_ELEM_ACCESS_READ;
-
- break;
-
- default:
- dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
- hdr->ops.get, hdr->ops.put, hdr->ops.info);
- break;
- }
-
- return 0;
-}
-
-static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
- struct snd_soc_tplg_vendor_string_elem *str_elem,
- struct skl_dev *skl)
-{
- int tkn_count = 0;
- static int ref_count;
-
- switch (str_elem->token) {
- case SKL_TKN_STR_LIB_NAME:
- if (ref_count > skl->lib_count - 1) {
- ref_count = 0;
- return -EINVAL;
- }
-
- strncpy(skl->lib_info[ref_count].name,
- str_elem->string,
- ARRAY_SIZE(skl->lib_info[ref_count].name));
- ref_count++;
- break;
-
- default:
- dev_err(dev, "Not a string token %d\n", str_elem->token);
- break;
- }
- tkn_count++;
-
- return tkn_count;
-}
-
-static int skl_tplg_get_str_tkn(struct device *dev,
- struct snd_soc_tplg_vendor_array *array,
- struct skl_dev *skl)
-{
- int tkn_count = 0, ret;
- struct snd_soc_tplg_vendor_string_elem *str_elem;
-
- str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
- while (tkn_count < array->num_elems) {
- ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
- str_elem++;
-
- if (ret < 0)
- return ret;
-
- tkn_count = tkn_count + ret;
- }
-
- return tkn_count;
-}
-
-static int skl_tplg_manifest_fill_fmt(struct device *dev,
- struct skl_module_iface *fmt,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- u32 dir, int fmt_idx)
-{
- struct skl_module_pin_fmt *dst_fmt;
- struct skl_module_fmt *mod_fmt;
- int ret;
-
- if (!fmt)
- return -EINVAL;
-
- switch (dir) {
- case SKL_DIR_IN:
- dst_fmt = &fmt->inputs[fmt_idx];
- break;
-
- case SKL_DIR_OUT:
- dst_fmt = &fmt->outputs[fmt_idx];
- break;
-
- default:
- dev_err(dev, "Invalid direction: %d\n", dir);
- return -EINVAL;
- }
-
- mod_fmt = &dst_fmt->fmt;
-
- switch (tkn_elem->token) {
- case SKL_TKN_MM_U32_INTF_PIN_ID:
- dst_fmt->id = tkn_elem->value;
- break;
-
- default:
- ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
- tkn_elem->value);
- if (ret < 0)
- return ret;
- break;
- }
-
- return 0;
-}
-
-static int skl_tplg_fill_mod_info(struct device *dev,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- struct skl_module *mod)
-{
-
- if (!mod)
- return -EINVAL;
-
- switch (tkn_elem->token) {
- case SKL_TKN_U8_IN_PIN_TYPE:
- mod->input_pin_type = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_OUT_PIN_TYPE:
- mod->output_pin_type = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_IN_QUEUE_COUNT:
- mod->max_input_pins = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_OUT_QUEUE_COUNT:
- mod->max_output_pins = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U8_NUM_RES:
- mod->nr_resources = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U8_NUM_INTF:
- mod->nr_interfaces = tkn_elem->value;
- break;
-
- default:
- dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-static int skl_tplg_get_int_tkn(struct device *dev,
- struct snd_soc_tplg_vendor_value_elem *tkn_elem,
- struct skl_dev *skl)
-{
- int tkn_count = 0, ret;
- static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
- struct skl_module_res *res = NULL;
- struct skl_module_iface *fmt = NULL;
- struct skl_module *mod = NULL;
- static struct skl_astate_param *astate_table;
- static int astate_cfg_idx, count;
- int i;
- size_t size;
-
- if (skl->modules) {
- mod = skl->modules[mod_idx];
- res = &mod->resources[res_val_idx];
- fmt = &mod->formats[intf_val_idx];
- }
-
- switch (tkn_elem->token) {
- case SKL_TKN_U32_LIB_COUNT:
- skl->lib_count = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_NUM_MOD:
- skl->nr_modules = tkn_elem->value;
- skl->modules = devm_kcalloc(dev, skl->nr_modules,
- sizeof(*skl->modules), GFP_KERNEL);
- if (!skl->modules)
- return -ENOMEM;
-
- for (i = 0; i < skl->nr_modules; i++) {
- skl->modules[i] = devm_kzalloc(dev,
- sizeof(struct skl_module), GFP_KERNEL);
- if (!skl->modules[i])
- return -ENOMEM;
- }
- break;
-
- case SKL_TKN_MM_U8_MOD_IDX:
- mod_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_ASTATE_COUNT:
- if (astate_table != NULL) {
- dev_err(dev, "More than one entry for A-State count");
- return -EINVAL;
- }
-
- if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
- dev_err(dev, "Invalid A-State count %d\n",
- tkn_elem->value);
- return -EINVAL;
- }
-
- size = struct_size(skl->cfg.astate_cfg, astate_table,
- tkn_elem->value);
- skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
- if (!skl->cfg.astate_cfg)
- return -ENOMEM;
-
- astate_table = skl->cfg.astate_cfg->astate_table;
- count = skl->cfg.astate_cfg->count = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_ASTATE_IDX:
- if (tkn_elem->value >= count) {
- dev_err(dev, "Invalid A-State index %d\n",
- tkn_elem->value);
- return -EINVAL;
- }
-
- astate_cfg_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_ASTATE_KCPS:
- astate_table[astate_cfg_idx].kcps = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_ASTATE_CLK_SRC:
- astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
- break;
-
- case SKL_TKN_U8_IN_PIN_TYPE:
- case SKL_TKN_U8_OUT_PIN_TYPE:
- case SKL_TKN_U8_IN_QUEUE_COUNT:
- case SKL_TKN_U8_OUT_QUEUE_COUNT:
- case SKL_TKN_MM_U8_NUM_RES:
- case SKL_TKN_MM_U8_NUM_INTF:
- ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
- if (ret < 0)
- return ret;
- break;
-
- case SKL_TKN_U32_DIR_PIN_COUNT:
- dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
- pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
- break;
-
- case SKL_TKN_MM_U32_RES_ID:
- if (!res)
- return -EINVAL;
-
- res->id = tkn_elem->value;
- res_val_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U32_FMT_ID:
- if (!fmt)
- return -EINVAL;
-
- fmt->fmt_idx = tkn_elem->value;
- intf_val_idx = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U32_CPS:
- case SKL_TKN_MM_U32_DMA_SIZE:
- case SKL_TKN_MM_U32_CPC:
- case SKL_TKN_U32_MEM_PAGES:
- case SKL_TKN_U32_OBS:
- case SKL_TKN_U32_IBS:
- case SKL_TKN_MM_U32_RES_PIN_ID:
- case SKL_TKN_MM_U32_PIN_BUF:
- ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
- if (ret < 0)
- return ret;
-
- break;
-
- case SKL_TKN_MM_U32_NUM_IN_FMT:
- if (!fmt)
- return -EINVAL;
-
- res->nr_input_pins = tkn_elem->value;
- break;
-
- case SKL_TKN_MM_U32_NUM_OUT_FMT:
- if (!fmt)
- return -EINVAL;
-
- res->nr_output_pins = tkn_elem->value;
- break;
-
- case SKL_TKN_U32_FMT_CH:
- case SKL_TKN_U32_FMT_FREQ:
- case SKL_TKN_U32_FMT_BIT_DEPTH:
- case SKL_TKN_U32_FMT_SAMPLE_SIZE:
- case SKL_TKN_U32_FMT_CH_CONFIG:
- case SKL_TKN_U32_FMT_INTERLEAVE:
- case SKL_TKN_U32_FMT_SAMPLE_TYPE:
- case SKL_TKN_U32_FMT_CH_MAP:
- case SKL_TKN_MM_U32_INTF_PIN_ID:
- ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
- dir, pin_idx);
- if (ret < 0)
- return ret;
- break;
-
- default:
- dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
- return -EINVAL;
- }
- tkn_count++;
-
- return tkn_count;
-}
-
-/*
- * Fill the manifest structure by parsing the tokens based on the
- * type.
- */
-static int skl_tplg_get_manifest_tkn(struct device *dev,
- char *pvt_data, struct skl_dev *skl,
- int block_size)
-{
- int tkn_count = 0, ret;
- int off = 0, tuple_size = 0;
- u8 uuid_index = 0;
- struct snd_soc_tplg_vendor_array *array;
- struct snd_soc_tplg_vendor_value_elem *tkn_elem;
-
- if (block_size <= 0)
- return -EINVAL;
-
- while (tuple_size < block_size) {
- array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
- off += array->size;
- switch (array->type) {
- case SND_SOC_TPLG_TUPLE_TYPE_STRING:
- ret = skl_tplg_get_str_tkn(dev, array, skl);
-
- if (ret < 0)
- return ret;
- tkn_count = ret;
-
- tuple_size += tkn_count *
- sizeof(struct snd_soc_tplg_vendor_string_elem);
- continue;
-
- case SND_SOC_TPLG_TUPLE_TYPE_UUID:
- if (array->uuid->token != SKL_TKN_UUID) {
- dev_err(dev, "Not an UUID token: %d\n",
- array->uuid->token);
- return -EINVAL;
- }
- if (uuid_index >= skl->nr_modules) {
- dev_err(dev, "Too many UUID tokens\n");
- return -EINVAL;
- }
- import_guid(&skl->modules[uuid_index++]->uuid,
- array->uuid->uuid);
-
- tuple_size += sizeof(*array->uuid);
- continue;
-
- default:
- tkn_elem = array->value;
- tkn_count = 0;
- break;
- }
-
- while (tkn_count <= array->num_elems - 1) {
- ret = skl_tplg_get_int_tkn(dev,
- tkn_elem, skl);
- if (ret < 0)
- return ret;
-
- tkn_count = tkn_count + ret;
- tkn_elem++;
- }
- tuple_size += (tkn_count * sizeof(*tkn_elem));
- tkn_count = 0;
- }
-
- return off;
-}
-
-/*
- * Parse manifest private data for tokens. The private data block is
- * preceded by descriptors for type and size of data block.
- */
-static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
- struct device *dev, struct skl_dev *skl)
-{
- struct snd_soc_tplg_vendor_array *array;
- int num_blocks, block_size = 0, block_type, off = 0;
- char *data;
- int ret;
-
- /* Read the NUM_DATA_BLOCKS descriptor */
- array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
- ret = skl_tplg_get_desc_blocks(dev, array);
- if (ret < 0)
- return ret;
- num_blocks = ret;
-
- off += array->size;
- /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
- while (num_blocks > 0) {
- array = (struct snd_soc_tplg_vendor_array *)
- (manifest->priv.data + off);
- ret = skl_tplg_get_desc_blocks(dev, array);
-
- if (ret < 0)
- return ret;
- block_type = ret;
- off += array->size;
-
- array = (struct snd_soc_tplg_vendor_array *)
- (manifest->priv.data + off);
-
- ret = skl_tplg_get_desc_blocks(dev, array);
-
- if (ret < 0)
- return ret;
- block_size = ret;
- off += array->size;
-
- data = (manifest->priv.data + off);
-
- if (block_type == SKL_TYPE_TUPLE) {
- ret = skl_tplg_get_manifest_tkn(dev, data, skl,
- block_size);
-
- if (ret < 0)
- return ret;
-
- --num_blocks;
- } else {
- return -EINVAL;
- }
- off += ret;
- }
-
- return 0;
-}
-
-static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
- struct snd_soc_tplg_manifest *manifest)
-{
- struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
- struct skl_dev *skl = bus_to_skl(bus);
-
- /* proceed only if we have private data defined */
- if (manifest->priv.size == 0)
- return 0;
-
- skl_tplg_get_manifest_data(manifest, bus->dev, skl);
-
- if (skl->lib_count > SKL_MAX_LIB) {
- dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
- skl->lib_count);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int skl_tplg_complete(struct snd_soc_component *component)
-{
- struct snd_soc_dobj *dobj;
- struct snd_soc_acpi_mach *mach;
- struct snd_ctl_elem_value *val;
- int i;
-
- val = kmalloc(sizeof(*val), GFP_KERNEL);
- if (!val)
- return -ENOMEM;
-
- mach = dev_get_platdata(component->card->dev);
- list_for_each_entry(dobj, &component->dobj_list, list) {
- struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
- struct soc_enum *se;
- char **texts;
- char chan_text[4];
-
- if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol ||
- kcontrol->put != skl_tplg_multi_config_set_dmic)
- continue;
-
- se = (struct soc_enum *)kcontrol->private_value;
- texts = dobj->control.dtexts;
- sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
-
- for (i = 0; i < se->items; i++) {
- if (strstr(texts[i], chan_text)) {
- memset(val, 0, sizeof(*val));
- val->value.enumerated.item[0] = i;
- kcontrol->put(kcontrol, val);
- }
- }
- }
-
- kfree(val);
- return 0;
-}
-
-static struct snd_soc_tplg_ops skl_tplg_ops = {
- .widget_load = skl_tplg_widget_load,
- .control_load = skl_tplg_control_load,
- .bytes_ext_ops = skl_tlv_ops,
- .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
- .io_ops = skl_tplg_kcontrol_ops,
- .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
- .manifest = skl_manifest_load,
- .dai_load = skl_dai_load,
- .complete = skl_tplg_complete,
-};
-
-/*
- * A pipe can have multiple modules, each of them will be a DAPM widget as
- * well. While managing a pipeline we need to get the list of all the
- * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
- * helps to get the SKL type widgets in that pipeline
- */
-static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
-{
- struct snd_soc_dapm_widget *w;
- struct skl_module_cfg *mcfg = NULL;
- struct skl_pipe_module *p_module = NULL;
- struct skl_pipe *pipe;
-
- list_for_each_entry(w, &component->card->widgets, list) {
- if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
- mcfg = w->priv;
- pipe = mcfg->pipe;
-
- p_module = devm_kzalloc(component->dev,
- sizeof(*p_module), GFP_KERNEL);
- if (!p_module)
- return -ENOMEM;
-
- p_module->w = w;
- list_add_tail(&p_module->node, &pipe->w_list);
- }
- }
-
- return 0;
-}
-
-static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
-{
- struct skl_pipe_module *w_module;
- struct snd_soc_dapm_widget *w;
- struct skl_module_cfg *mconfig;
- bool host_found = false, link_found = false;
-
- list_for_each_entry(w_module, &pipe->w_list, node) {
- w = w_module->w;
- mconfig = w->priv;
-
- if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
- host_found = true;
- else if (mconfig->dev_type != SKL_DEVICE_NONE)
- link_found = true;
- }
-
- if (host_found && link_found)
- pipe->passthru = true;
- else
- pipe->passthru = false;
-}
-
-/*
- * SKL topology init routine
- */
-int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
-{
- int ret;
- const struct firmware *fw;
- struct skl_dev *skl = bus_to_skl(bus);
- struct skl_pipeline *ppl;
-
- ret = request_firmware(&fw, skl->tplg_name, bus->dev);
- if (ret < 0) {
- char alt_tplg_name[64];
-
- snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin",
- skl->mach->drv_name);
- dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s",
- skl->tplg_name, ret, alt_tplg_name);
-
- ret = request_firmware(&fw, alt_tplg_name, bus->dev);
- if (!ret)
- goto component_load;
-
- dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin",
- alt_tplg_name, ret);
-
- ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
- if (ret < 0) {
- dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
- "dfw_sst.bin", ret);
- return ret;
- }
- }
-
-component_load:
- ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw);
- if (ret < 0) {
- dev_err(bus->dev, "tplg component load failed%d\n", ret);
- goto err;
- }
-
- ret = skl_tplg_create_pipe_widget_list(component);
- if (ret < 0) {
- dev_err(bus->dev, "tplg create pipe widget list failed%d\n",
- ret);
- goto err;
- }
-
- list_for_each_entry(ppl, &skl->ppl_list, node)
- skl_tplg_set_pipe_type(skl, ppl->pipe);
-
-err:
- release_firmware(fw);
- return ret;
-}
-
-void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
-{
- struct skl_dev *skl = bus_to_skl(bus);
- struct skl_pipeline *ppl, *tmp;
-
- list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
- list_del(&ppl->node);
-
- /* clean up topology */
- snd_soc_tplg_component_remove(component);
-}
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
deleted file mode 100644
index 30a0977af943..000000000000
--- a/sound/soc/intel/skylake/skl-topology.h
+++ /dev/null
@@ -1,524 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * skl_topology.h - Intel HDA Platform topology header file
- *
- * Copyright (C) 2014-15 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#ifndef __SKL_TOPOLOGY_H__
-#define __SKL_TOPOLOGY_H__
-
-#include <linux/types.h>
-
-#include <sound/hdaudio_ext.h>
-#include <sound/soc.h>
-#include <uapi/sound/skl-tplg-interface.h>
-#include "skl.h"
-
-#define BITS_PER_BYTE 8
-#define MAX_TS_GROUPS 8
-#define MAX_DMIC_TS_GROUPS 4
-#define MAX_FIXED_DMIC_PARAMS_SIZE 727
-
-/* Maximum number of coefficients up down mixer module */
-#define UP_DOWN_MIXER_MAX_COEFF 8
-
-#define MODULE_MAX_IN_PINS 8
-#define MODULE_MAX_OUT_PINS 8
-
-#define SKL_MIC_CH_SUPPORT 4
-#define SKL_MIC_MAX_CH_SUPPORT 8
-#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF
-#define SKL_MIC_SEL_SWITCH 0x3
-
-#define SKL_OUTPUT_PIN 0
-#define SKL_INPUT_PIN 1
-#define SKL_MAX_PATH_CONFIGS 8
-#define SKL_MAX_MODULES_IN_PIPE 8
-#define SKL_MAX_MODULE_FORMATS 32
-#define SKL_MAX_MODULE_RESOURCES 32
-
-enum skl_channel_index {
- SKL_CHANNEL_LEFT = 0,
- SKL_CHANNEL_RIGHT = 1,
- SKL_CHANNEL_CENTER = 2,
- SKL_CHANNEL_LEFT_SURROUND = 3,
- SKL_CHANNEL_CENTER_SURROUND = 3,
- SKL_CHANNEL_RIGHT_SURROUND = 4,
- SKL_CHANNEL_LFE = 7,
- SKL_CHANNEL_INVALID = 0xF,
-};
-
-enum skl_bitdepth {
- SKL_DEPTH_8BIT = 8,
- SKL_DEPTH_16BIT = 16,
- SKL_DEPTH_24BIT = 24,
- SKL_DEPTH_32BIT = 32,
- SKL_DEPTH_INVALID
-};
-
-
-enum skl_s_freq {
- SKL_FS_8000 = 8000,
- SKL_FS_11025 = 11025,
- SKL_FS_12000 = 12000,
- SKL_FS_16000 = 16000,
- SKL_FS_22050 = 22050,
- SKL_FS_24000 = 24000,
- SKL_FS_32000 = 32000,
- SKL_FS_44100 = 44100,
- SKL_FS_48000 = 48000,
- SKL_FS_64000 = 64000,
- SKL_FS_88200 = 88200,
- SKL_FS_96000 = 96000,
- SKL_FS_128000 = 128000,
- SKL_FS_176400 = 176400,
- SKL_FS_192000 = 192000,
- SKL_FS_INVALID
-};
-
-#define SKL_MAX_PARAMS_TYPES 4
-
-enum skl_widget_type {
- SKL_WIDGET_VMIXER = 1,
- SKL_WIDGET_MIXER = 2,
- SKL_WIDGET_PGA = 3,
- SKL_WIDGET_MUX = 4
-};
-
-struct skl_audio_data_format {
- enum skl_s_freq s_freq;
- enum skl_bitdepth bit_depth;
- u32 channel_map;
- enum skl_ch_cfg ch_cfg;
- enum skl_interleaving interleaving;
- u8 number_of_channels;
- u8 valid_bit_depth;
- u8 sample_type;
- u8 reserved;
-} __packed;
-
-struct skl_base_cfg {
- u32 cpc;
- u32 ibs;
- u32 obs;
- u32 is_pages;
- struct skl_audio_data_format audio_fmt;
-};
-
-struct skl_cpr_gtw_cfg {
- u32 node_id;
- u32 dma_buffer_size;
- u32 config_length;
- /* not mandatory; required only for DMIC/I2S */
- struct {
- u32 gtw_attrs;
- u32 data[];
- } config_data;
-} __packed;
-
-struct skl_dma_control {
- u32 node_id;
- u32 config_length;
- u32 config_data[];
-} __packed;
-
-struct skl_cpr_cfg {
- struct skl_base_cfg base_cfg;
- struct skl_audio_data_format out_fmt;
- u32 cpr_feature_mask;
- struct skl_cpr_gtw_cfg gtw_cfg;
-} __packed;
-
-struct skl_cpr_pin_fmt {
- u32 sink_id;
- struct skl_audio_data_format src_fmt;
- struct skl_audio_data_format dst_fmt;
-} __packed;
-
-struct skl_src_module_cfg {
- struct skl_base_cfg base_cfg;
- enum skl_s_freq src_cfg;
-} __packed;
-
-struct skl_up_down_mixer_cfg {
- struct skl_base_cfg base_cfg;
- enum skl_ch_cfg out_ch_cfg;
- /* This should be set to 1 if user coefficients are required */
- u32 coeff_sel;
- /* Pass the user coeff in this array */
- s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
- u32 ch_map;
-} __packed;
-
-struct skl_pin_format {
- u32 pin_idx;
- u32 buf_size;
- struct skl_audio_data_format audio_fmt;
-} __packed;
-
-struct skl_base_cfg_ext {
- u16 nr_input_pins;
- u16 nr_output_pins;
- u8 reserved[8];
- u32 priv_param_length;
- /* Input pin formats followed by output ones. */
- struct skl_pin_format pins_fmt[];
-} __packed;
-
-struct skl_algo_cfg {
- struct skl_base_cfg base_cfg;
- char params[];
-} __packed;
-
-struct skl_base_outfmt_cfg {
- struct skl_base_cfg base_cfg;
- struct skl_audio_data_format out_fmt;
-} __packed;
-
-enum skl_dma_type {
- SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0,
- SKL_DMA_HDA_HOST_INPUT_CLASS = 1,
- SKL_DMA_HDA_HOST_INOUT_CLASS = 2,
- SKL_DMA_HDA_LINK_OUTPUT_CLASS = 8,
- SKL_DMA_HDA_LINK_INPUT_CLASS = 9,
- SKL_DMA_HDA_LINK_INOUT_CLASS = 0xA,
- SKL_DMA_DMIC_LINK_INPUT_CLASS = 0xB,
- SKL_DMA_I2S_LINK_OUTPUT_CLASS = 0xC,
- SKL_DMA_I2S_LINK_INPUT_CLASS = 0xD,
-};
-
-union skl_ssp_dma_node {
- u8 val;
- struct {
- u8 time_slot_index:4;
- u8 i2s_instance:4;
- } dma_node;
-};
-
-union skl_connector_node_id {
- u32 val;
- struct {
- u32 vindex:8;
- u32 dma_type:4;
- u32 rsvd:20;
- } node;
-};
-
-struct skl_module_fmt {
- u32 channels;
- u32 s_freq;
- u32 bit_depth;
- u32 valid_bit_depth;
- u32 ch_cfg;
- u32 interleaving_style;
- u32 sample_type;
- u32 ch_map;
-};
-
-struct skl_module_cfg;
-
-struct skl_mod_inst_map {
- u16 mod_id;
- u16 inst_id;
-};
-
-struct skl_uuid_inst_map {
- u16 inst_id;
- u16 reserved;
- guid_t mod_uuid;
-} __packed;
-
-struct skl_kpb_params {
- u32 num_modules;
- union {
- DECLARE_FLEX_ARRAY(struct skl_mod_inst_map, map);
- DECLARE_FLEX_ARRAY(struct skl_uuid_inst_map, map_uuid);
- } u;
-};
-
-struct skl_module_inst_id {
- guid_t mod_uuid;
- int module_id;
- u32 instance_id;
- int pvt_id;
-};
-
-enum skl_module_pin_state {
- SKL_PIN_UNBIND = 0,
- SKL_PIN_BIND_DONE = 1,
-};
-
-struct skl_module_pin {
- struct skl_module_inst_id id;
- bool is_dynamic;
- bool in_use;
- enum skl_module_pin_state pin_state;
- struct skl_module_cfg *tgt_mcfg;
-};
-
-struct skl_specific_cfg {
- u32 set_params;
- u32 param_id;
- u32 caps_size;
- u32 *caps;
-};
-
-enum skl_pipe_state {
- SKL_PIPE_INVALID = 0,
- SKL_PIPE_CREATED = 1,
- SKL_PIPE_PAUSED = 2,
- SKL_PIPE_STARTED = 3,
- SKL_PIPE_RESET = 4
-};
-
-struct skl_pipe_module {
- struct snd_soc_dapm_widget *w;
- struct list_head node;
-};
-
-struct skl_pipe_params {
- u8 host_dma_id;
- u8 link_dma_id;
- u32 ch;
- u32 s_freq;
- u32 s_fmt;
- u32 s_cont;
- u8 linktype;
- snd_pcm_format_t format;
- int link_index;
- int stream;
- unsigned int host_bps;
- unsigned int link_bps;
-};
-
-struct skl_pipe_fmt {
- u32 freq;
- u8 channels;
- u8 bps;
-};
-
-struct skl_pipe_mcfg {
- u8 res_idx;
- u8 fmt_idx;
-};
-
-struct skl_path_config {
- u8 mem_pages;
- struct skl_pipe_fmt in_fmt;
- struct skl_pipe_fmt out_fmt;
-};
-
-struct skl_pipe {
- u8 ppl_id;
- u8 pipe_priority;
- u16 conn_type;
- u32 memory_pages;
- u8 lp_mode;
- struct skl_pipe_params *p_params;
- enum skl_pipe_state state;
- u8 direction;
- u8 cur_config_idx;
- u8 nr_cfgs;
- struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
- struct list_head w_list;
- bool passthru;
-};
-
-enum skl_module_state {
- SKL_MODULE_UNINIT = 0,
- SKL_MODULE_INIT_DONE = 1,
- SKL_MODULE_BIND_DONE = 2,
-};
-
-enum d0i3_capability {
- SKL_D0I3_NONE = 0,
- SKL_D0I3_STREAMING = 1,
- SKL_D0I3_NON_STREAMING = 2,
-};
-
-struct skl_module_pin_fmt {
- u8 id;
- struct skl_module_fmt fmt;
-};
-
-struct skl_module_iface {
- u8 fmt_idx;
- u8 nr_in_fmt;
- u8 nr_out_fmt;
- struct skl_module_pin_fmt inputs[MAX_IN_QUEUE];
- struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE];
-};
-
-struct skl_module_pin_resources {
- u8 pin_index;
- u32 buf_size;
-};
-
-struct skl_module_res {
- u8 id;
- u32 is_pages;
- u32 ibs;
- u32 obs;
- u32 dma_buffer_size;
- u32 cpc;
- u8 nr_input_pins;
- u8 nr_output_pins;
- struct skl_module_pin_resources input[MAX_IN_QUEUE];
- struct skl_module_pin_resources output[MAX_OUT_QUEUE];
-};
-
-struct skl_module {
- guid_t uuid;
- u8 loadable;
- u8 input_pin_type;
- u8 output_pin_type;
- u8 max_input_pins;
- u8 max_output_pins;
- u8 nr_resources;
- u8 nr_interfaces;
- struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES];
- struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS];
-};
-
-struct skl_module_cfg {
- u8 guid[16];
- struct skl_module_inst_id id;
- struct skl_module *module;
- int res_idx;
- int fmt_idx;
- int fmt_cfg_idx;
- u8 domain;
- bool homogenous_inputs;
- bool homogenous_outputs;
- struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS];
- struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS];
- u8 max_in_queue;
- u8 max_out_queue;
- u8 in_queue_mask;
- u8 out_queue_mask;
- u8 in_queue;
- u8 out_queue;
- u8 is_loadable;
- u8 core_id;
- u8 dev_type;
- u8 dma_id;
- u8 time_slot;
- u8 dmic_ch_combo_index;
- u32 dmic_ch_type;
- u32 params_fixup;
- u32 converter;
- u32 vbus_id;
- u32 mem_pages;
- enum d0i3_capability d0i3_caps;
- u32 dma_buffer_size; /* in milli seconds */
- struct skl_module_pin *m_in_pin;
- struct skl_module_pin *m_out_pin;
- enum skl_module_type m_type;
- enum skl_hw_conn_type hw_conn_type;
- enum skl_module_state m_state;
- struct skl_pipe *pipe;
- struct skl_specific_cfg formats_config[SKL_MAX_PARAMS_TYPES];
- struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
-};
-
-struct skl_algo_data {
- u32 param_id;
- u32 set_params;
- u32 max;
- u32 size;
- char *params;
-};
-
-struct skl_pipeline {
- struct skl_pipe *pipe;
- struct list_head node;
-};
-
-struct skl_module_deferred_bind {
- struct skl_module_cfg *src;
- struct skl_module_cfg *dst;
- struct list_head node;
-};
-
-struct skl_mic_sel_config {
- u16 mic_switch;
- u16 flags;
- u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT];
-} __packed;
-
-enum skl_channel {
- SKL_CH_MONO = 1,
- SKL_CH_STEREO = 2,
- SKL_CH_TRIO = 3,
- SKL_CH_QUATRO = 4,
-};
-
-static inline struct skl_dev *get_skl_ctx(struct device *dev)
-{
- struct hdac_bus *bus = dev_get_drvdata(dev);
-
- return bus_to_skl(bus);
-}
-
-int skl_tplg_be_update_params(struct snd_soc_dai *dai,
- struct skl_pipe_params *params);
-int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps,
- u32 caps_size, u32 node_id);
-void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
- struct skl_pipe_params *params, int stream);
-int skl_tplg_init(struct snd_soc_component *component,
- struct hdac_bus *bus);
-void skl_tplg_exit(struct snd_soc_component *component,
- struct hdac_bus *bus);
-struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
- struct snd_soc_dai *dai, int stream);
-int skl_tplg_update_pipe_params(struct device *dev,
- struct skl_module_cfg *mconfig, struct skl_pipe_params *params);
-
-void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps);
-void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps);
-
-int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe);
-
-int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe);
-
-int skl_pause_pipe(struct skl_dev *skl, struct skl_pipe *pipe);
-
-int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe);
-
-int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe);
-
-int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe);
-
-int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *mconfig);
-
-int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg
- *src_mcfg, struct skl_module_cfg *dst_mcfg);
-
-int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg
- *src_mcfg, struct skl_module_cfg *dst_mcfg);
-
-int skl_set_module_params(struct skl_dev *skl, u32 *params, int size,
- u32 param_id, struct skl_module_cfg *mcfg);
-int skl_get_module_params(struct skl_dev *skl, u32 *params, int size,
- u32 param_id, struct skl_module_cfg *mcfg);
-
-struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai,
- int stream);
-enum skl_bitdepth skl_get_bit_depth(int params);
-int skl_pcm_host_dma_prepare(struct device *dev,
- struct skl_pipe_params *params);
-int skl_pcm_link_dma_prepare(struct device *dev,
- struct skl_pipe_params *params);
-
-int skl_dai_load(struct snd_soc_component *cmp, int index,
- struct snd_soc_dai_driver *dai_drv,
- struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai);
-void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
- struct snd_soc_dapm_widget *w);
-#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
deleted file mode 100644
index 998bd0232cf1..000000000000
--- a/sound/soc/intel/skylake/skl.c
+++ /dev/null
@@ -1,1205 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * skl.c - Implementation of ASoC Intel SKL HD Audio driver
- *
- * Copyright (C) 2014-2015 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- *
- * Derived mostly from Intel HDA driver with following copyrights:
- * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
- * PeiSen Hou <pshou@realtek.com.tw>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_device.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-#include <sound/pcm.h>
-#include <sound/soc-acpi.h>
-#include <sound/soc-acpi-intel-match.h>
-#include <sound/hda_register.h>
-#include <sound/hdaudio.h>
-#include <sound/hda_i915.h>
-#include <sound/hda_codec.h>
-#include <sound/intel-nhlt.h>
-#include <sound/intel-dsp-config.h>
-#include "skl.h"
-#include "skl-sst-dsp.h"
-#include "skl-sst-ipc.h"
-
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
-#include "../../../soc/codecs/hdac_hda.h"
-#endif
-static int skl_pci_binding;
-module_param_named(pci_binding, skl_pci_binding, int, 0444);
-MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
-
-/*
- * initialize the PCI registers
- */
-static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg,
- unsigned char mask, unsigned char val)
-{
- unsigned char data;
-
- pci_read_config_byte(pci, reg, &data);
- data &= ~mask;
- data |= (val & mask);
- pci_write_config_byte(pci, reg, data);
-}
-
-static void skl_init_pci(struct skl_dev *skl)
-{
- struct hdac_bus *bus = skl_to_bus(skl);
-
- /*
- * Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
- * TCSEL == Traffic Class Select Register, which sets PCI express QOS
- * Ensuring these bits are 0 clears playback static on some HD Audio
- * codecs.
- * The PCI register TCSEL is defined in the Intel manuals.
- */
- dev_dbg(bus->dev, "Clearing TCSEL\n");
- skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
-}
-
-static void update_pci_dword(struct pci_dev *pci,
- unsigned int reg, u32 mask, u32 val)
-{
- u32 data = 0;
-
- pci_read_config_dword(pci, reg, &data);
- data &= ~mask;
- data |= (val & mask);
- pci_write_config_dword(pci, reg, data);
-}
-
-/*
- * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits
- *
- * @dev: device pointer
- * @enable: enable/disable flag
- */
-static void skl_enable_miscbdcge(struct device *dev, bool enable)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- u32 val;
-
- val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
-
- update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val);
-}
-
-/**
- * skl_clock_power_gating: Enable/Disable clock and power gating
- *
- * @dev: Device pointer
- * @enable: Enable/Disable flag
- */
-static void skl_clock_power_gating(struct device *dev, bool enable)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
- u32 val;
-
- /* Update PDCGE bit of CGCTL register */
- val = enable ? AZX_CGCTL_ADSPDCGE : 0;
- update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_ADSPDCGE, val);
-
- /* Update L1SEN bit of EM2 register */
- val = enable ? AZX_REG_VS_EM2_L1SEN : 0;
- snd_hdac_chip_updatel(bus, VS_EM2, AZX_REG_VS_EM2_L1SEN, val);
-
- /* Update ADSPPGD bit of PGCTL register */
- val = enable ? 0 : AZX_PGCTL_ADSPPGD;
- update_pci_dword(pci, AZX_PCIREG_PGCTL, AZX_PGCTL_ADSPPGD, val);
-}
-
-/*
- * While performing reset, controller may not come back properly causing
- * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
- * (init chip) and then again set CGCTL.MISCBDCGE to 1
- */
-static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
-{
- struct hdac_ext_link *hlink;
- int ret;
-
- snd_hdac_set_codec_wakeup(bus, true);
- skl_enable_miscbdcge(bus->dev, false);
- ret = snd_hdac_bus_init_chip(bus, full_reset);
-
- /* Reset stream-to-link mapping */
- list_for_each_entry(hlink, &bus->hlink_list, list)
- writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
-
- skl_enable_miscbdcge(bus->dev, true);
- snd_hdac_set_codec_wakeup(bus, false);
-
- return ret;
-}
-
-void skl_update_d0i3c(struct device *dev, bool enable)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
- u8 reg;
- int timeout = 50;
-
- reg = snd_hdac_chip_readb(bus, VS_D0I3C);
- /* Do not write to D0I3C until command in progress bit is cleared */
- while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) {
- udelay(10);
- reg = snd_hdac_chip_readb(bus, VS_D0I3C);
- }
-
- /* Highly unlikely. But if it happens, flag error explicitly */
- if (!timeout) {
- dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n");
- return;
- }
-
- if (enable)
- reg = reg | AZX_REG_VS_D0I3C_I3;
- else
- reg = reg & (~AZX_REG_VS_D0I3C_I3);
-
- snd_hdac_chip_writeb(bus, VS_D0I3C, reg);
-
- timeout = 50;
- /* Wait for cmd in progress to be cleared before exiting the function */
- reg = snd_hdac_chip_readb(bus, VS_D0I3C);
- while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) {
- udelay(10);
- reg = snd_hdac_chip_readb(bus, VS_D0I3C);
- }
-
- /* Highly unlikely. But if it happens, flag error explicitly */
- if (!timeout) {
- dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n");
- return;
- }
-
- dev_dbg(bus->dev, "D0I3C register = 0x%x\n",
- snd_hdac_chip_readb(bus, VS_D0I3C));
-}
-
-/**
- * skl_dum_set - set DUM bit in EM2 register
- * @bus: HD-audio core bus
- *
- * Addresses incorrect position reporting for capture streams.
- * Used on device power up.
- */
-static void skl_dum_set(struct hdac_bus *bus)
-{
- /* For the DUM bit to be set, CRST needs to be out of reset state */
- if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) {
- skl_enable_miscbdcge(bus->dev, false);
- snd_hdac_bus_exit_link_reset(bus);
- skl_enable_miscbdcge(bus->dev, true);
- }
-
- snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
-}
-
-/* called from IRQ */
-static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
-{
- snd_pcm_period_elapsed(hstr->substream);
-}
-
-static irqreturn_t skl_interrupt(int irq, void *dev_id)
-{
- struct hdac_bus *bus = dev_id;
- u32 status;
-
- if (!pm_runtime_active(bus->dev))
- return IRQ_NONE;
-
- spin_lock(&bus->reg_lock);
-
- status = snd_hdac_chip_readl(bus, INTSTS);
- if (status == 0 || status == 0xffffffff) {
- spin_unlock(&bus->reg_lock);
- return IRQ_NONE;
- }
-
- /* clear rirb int */
- status = snd_hdac_chip_readb(bus, RIRBSTS);
- if (status & RIRB_INT_MASK) {
- if (status & RIRB_INT_RESPONSE)
- snd_hdac_bus_update_rirb(bus);
- snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
- }
-
- spin_unlock(&bus->reg_lock);
-
- return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
-}
-
-static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
-{
- struct hdac_bus *bus = dev_id;
- u32 status;
-
- status = snd_hdac_chip_readl(bus, INTSTS);
-
- snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update);
-
- return IRQ_HANDLED;
-}
-
-static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect)
-{
- struct skl_dev *skl = bus_to_skl(bus);
- int ret;
-
- ret = request_threaded_irq(skl->pci->irq, skl_interrupt,
- skl_threaded_handler,
- IRQF_SHARED,
- KBUILD_MODNAME, bus);
- if (ret) {
- dev_err(bus->dev,
- "unable to grab IRQ %d, disabling device\n",
- skl->pci->irq);
- return ret;
- }
-
- bus->irq = skl->pci->irq;
- pci_intx(skl->pci, 1);
-
- return 0;
-}
-
-static int skl_suspend_late(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
- struct skl_dev *skl = bus_to_skl(bus);
-
- return skl_suspend_late_dsp(skl);
-}
-
-#ifdef CONFIG_PM
-static int _skl_suspend(struct hdac_bus *bus)
-{
- struct skl_dev *skl = bus_to_skl(bus);
- struct pci_dev *pci = to_pci_dev(bus->dev);
- int ret;
-
- snd_hdac_ext_bus_link_power_down_all(bus);
-
- ret = skl_suspend_dsp(skl);
- if (ret < 0)
- return ret;
-
- snd_hdac_bus_stop_chip(bus);
- update_pci_dword(pci, AZX_PCIREG_PGCTL,
- AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK);
- skl_enable_miscbdcge(bus->dev, false);
- snd_hdac_bus_enter_link_reset(bus);
- skl_enable_miscbdcge(bus->dev, true);
- skl_cleanup_resources(skl);
-
- return 0;
-}
-
-static int _skl_resume(struct hdac_bus *bus)
-{
- struct skl_dev *skl = bus_to_skl(bus);
-
- skl_init_pci(skl);
- skl_dum_set(bus);
- skl_init_chip(bus, true);
-
- return skl_resume_dsp(skl);
-}
-#endif
-
-#ifdef CONFIG_PM_SLEEP
-/*
- * power management
- */
-static int skl_suspend(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
- struct skl_dev *skl = bus_to_skl(bus);
- int ret;
-
- /*
- * Do not suspend if streams which are marked ignore suspend are
- * running, we need to save the state for these and continue
- */
- if (skl->supend_active) {
- /* turn off the links and stop the CORB/RIRB DMA if it is On */
- snd_hdac_ext_bus_link_power_down_all(bus);
-
- if (bus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(bus);
-
- enable_irq_wake(bus->irq);
- pci_save_state(pci);
- } else {
- ret = _skl_suspend(bus);
- if (ret < 0)
- return ret;
- skl->fw_loaded = false;
- }
-
- return 0;
-}
-
-static int skl_resume(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
- struct skl_dev *skl = bus_to_skl(bus);
- struct hdac_ext_link *hlink;
- int ret;
-
- /*
- * resume only when we are not in suspend active, otherwise need to
- * restore the device
- */
- if (skl->supend_active) {
- pci_restore_state(pci);
- snd_hdac_ext_bus_link_power_up_all(bus);
- disable_irq_wake(bus->irq);
- /*
- * turn On the links which are On before active suspend
- * and start the CORB/RIRB DMA if On before
- * active suspend.
- */
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- if (hlink->ref_count)
- snd_hdac_ext_bus_link_power_up(hlink);
- }
-
- ret = 0;
- if (bus->cmd_dma_state)
- snd_hdac_bus_init_cmd_io(bus);
- } else {
- ret = _skl_resume(bus);
- }
-
- return ret;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-#ifdef CONFIG_PM
-static int skl_runtime_suspend(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
-
- dev_dbg(bus->dev, "in %s\n", __func__);
-
- return _skl_suspend(bus);
-}
-
-static int skl_runtime_resume(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_bus *bus = pci_get_drvdata(pci);
-
- dev_dbg(bus->dev, "in %s\n", __func__);
-
- return _skl_resume(bus);
-}
-#endif /* CONFIG_PM */
-
-static const struct dev_pm_ops skl_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume)
- SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL)
- .suspend_late = skl_suspend_late,
-};
-
-/*
- * destructor
- */
-static int skl_free(struct hdac_bus *bus)
-{
- struct skl_dev *skl = bus_to_skl(bus);
-
- skl->init_done = 0; /* to be sure */
-
- snd_hdac_stop_streams_and_chip(bus);
-
- if (bus->irq >= 0)
- free_irq(bus->irq, (void *)bus);
- snd_hdac_bus_free_stream_pages(bus);
- snd_hdac_ext_stream_free_all(bus);
- snd_hdac_ext_link_free_all(bus);
-
- if (bus->remap_addr)
- iounmap(bus->remap_addr);
-
- pci_release_regions(skl->pci);
- pci_disable_device(skl->pci);
-
- snd_hdac_ext_bus_exit(bus);
-
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
- snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
- snd_hdac_i915_exit(bus);
- }
-
- return 0;
-}
-
-/*
- * For each ssp there are 3 clocks (mclk/sclk/sclkfs).
- * e.g. for ssp0, clocks will be named as
- * "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs"
- * So for skl+, there are 6 ssps, so 18 clocks will be created.
- */
-static struct skl_ssp_clk skl_ssp_clks[] = {
- {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"},
- {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"},
- {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"},
- {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"},
- {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"},
- {.name = "ssp2_sclkfs"},
- {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"},
- {.name = "ssp5_sclkfs"},
-};
-
-static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl,
- struct snd_soc_acpi_mach *machines)
-{
- struct snd_soc_acpi_mach *mach;
-
- /* point to common table */
- mach = snd_soc_acpi_intel_hda_machines;
-
- /* all entries in the machine table use the same firmware */
- mach->fw_filename = machines->fw_filename;
-
- return mach;
-}
-
-static int skl_find_machine(struct skl_dev *skl, void *driver_data)
-{
- struct hdac_bus *bus = skl_to_bus(skl);
- struct snd_soc_acpi_mach *mach = driver_data;
- struct skl_machine_pdata *pdata;
-
- mach = snd_soc_acpi_find_machine(mach);
- if (!mach) {
- dev_dbg(bus->dev, "No matching I2S machine driver found\n");
- mach = skl_find_hda_machine(skl, driver_data);
- if (!mach) {
- dev_err(bus->dev, "No matching machine driver found\n");
- return -ENODEV;
- }
- }
-
- skl->mach = mach;
- skl->fw_name = mach->fw_filename;
- pdata = mach->pdata;
-
- if (pdata) {
- skl->use_tplg_pcm = pdata->use_tplg_pcm;
- mach->mach_params.dmic_num =
- intel_nhlt_get_dmic_geo(&skl->pci->dev,
- skl->nhlt);
- }
-
- return 0;
-}
-
-static int skl_machine_device_register(struct skl_dev *skl)
-{
- struct snd_soc_acpi_mach *mach = skl->mach;
- struct hdac_bus *bus = skl_to_bus(skl);
- struct platform_device *pdev;
- int ret;
-
- pdev = platform_device_alloc(mach->drv_name, -1);
- if (pdev == NULL) {
- dev_err(bus->dev, "platform device alloc failed\n");
- return -EIO;
- }
-
- mach->mach_params.platform = dev_name(bus->dev);
- mach->mach_params.codec_mask = bus->codec_mask;
-
- ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
- if (ret) {
- dev_err(bus->dev, "failed to add machine device platform data\n");
- platform_device_put(pdev);
- return ret;
- }
-
- ret = platform_device_add(pdev);
- if (ret) {
- dev_err(bus->dev, "failed to add machine device\n");
- platform_device_put(pdev);
- return -EIO;
- }
-
-
- skl->i2s_dev = pdev;
-
- return 0;
-}
-
-static void skl_machine_device_unregister(struct skl_dev *skl)
-{
- if (skl->i2s_dev)
- platform_device_unregister(skl->i2s_dev);
-}
-
-static int skl_dmic_device_register(struct skl_dev *skl)
-{
- struct hdac_bus *bus = skl_to_bus(skl);
- struct platform_device *pdev;
- int ret;
-
- /* SKL has one dmic port, so allocate dmic device for this */
- pdev = platform_device_alloc("dmic-codec", -1);
- if (!pdev) {
- dev_err(bus->dev, "failed to allocate dmic device\n");
- return -ENOMEM;
- }
-
- ret = platform_device_add(pdev);
- if (ret) {
- dev_err(bus->dev, "failed to add dmic device: %d\n", ret);
- platform_device_put(pdev);
- return ret;
- }
- skl->dmic_dev = pdev;
-
- return 0;
-}
-
-static void skl_dmic_device_unregister(struct skl_dev *skl)
-{
- if (skl->dmic_dev)
- platform_device_unregister(skl->dmic_dev);
-}
-
-static struct skl_clk_parent_src skl_clk_src[] = {
- { .clk_id = SKL_XTAL, .name = "xtal" },
- { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 },
- { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 },
-};
-
-struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) {
- if (skl_clk_src[i].clk_id == clk_id)
- return &skl_clk_src[i];
- }
-
- return NULL;
-}
-
-static void init_skl_xtal_rate(int pci_id)
-{
- switch (pci_id) {
- case 0x9d70:
- case 0x9d71:
- skl_clk_src[0].rate = 24000000;
- return;
-
- default:
- skl_clk_src[0].rate = 19200000;
- return;
- }
-}
-
-static int skl_clock_device_register(struct skl_dev *skl)
-{
- struct platform_device_info pdevinfo = {NULL};
- struct skl_clk_pdata *clk_pdata;
-
- if (!skl->nhlt)
- return 0;
-
- clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
- GFP_KERNEL);
- if (!clk_pdata)
- return -ENOMEM;
-
- init_skl_xtal_rate(skl->pci->device);
-
- clk_pdata->parent_clks = skl_clk_src;
- clk_pdata->ssp_clks = skl_ssp_clks;
- clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks);
-
- /* Query NHLT to fill the rates and parent */
- skl_get_clks(skl, clk_pdata->ssp_clks);
- clk_pdata->pvt_data = skl;
-
- /* Register Platform device */
- pdevinfo.parent = &skl->pci->dev;
- pdevinfo.id = -1;
- pdevinfo.name = "skl-ssp-clk";
- pdevinfo.data = clk_pdata;
- pdevinfo.size_data = sizeof(*clk_pdata);
- skl->clk_dev = platform_device_register_full(&pdevinfo);
- return PTR_ERR_OR_ZERO(skl->clk_dev);
-}
-
-static void skl_clock_device_unregister(struct skl_dev *skl)
-{
- if (skl->clk_dev)
- platform_device_unregister(skl->clk_dev);
-}
-
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
-
-#define IDISP_INTEL_VENDOR_ID 0x80860000
-
-/*
- * load the legacy codec driver
- */
-static void load_codec_module(struct hda_codec *codec)
-{
-#ifdef MODULE
- char modalias[MODULE_NAME_LEN];
- const char *mod = NULL;
-
- snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias));
- mod = modalias;
- dev_dbg(&codec->core.dev, "loading %s codec module\n", mod);
- request_module(mod);
-#endif
-}
-
-#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */
-
-static struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr)
-{
- struct hda_codec *codec;
- int ret;
-
- codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr);
- if (IS_ERR(codec)) {
- dev_err(bus->dev, "device init failed for hdac device\n");
- return codec;
- }
-
- codec->core.type = HDA_DEV_ASOC;
-
- ret = snd_hdac_device_register(&codec->core);
- if (ret) {
- dev_err(bus->dev, "failed to register hdac device\n");
- put_device(&codec->core.dev);
- return ERR_PTR(ret);
- }
-
- return codec;
-}
-
-/*
- * Probe the given codec address
- */
-static int probe_codec(struct hdac_bus *bus, int addr)
-{
- unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
- (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
- unsigned int res = -1;
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
- struct skl_dev *skl = bus_to_skl(bus);
- struct hdac_hda_priv *hda_codec;
-#endif
- struct hda_codec *codec;
-
- mutex_lock(&bus->cmd_mutex);
- snd_hdac_bus_send_cmd(bus, cmd);
- snd_hdac_bus_get_response(bus, addr, &res);
- mutex_unlock(&bus->cmd_mutex);
- if (res == -1)
- return -EIO;
- dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res);
-
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
- hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec),
- GFP_KERNEL);
- if (!hda_codec)
- return -ENOMEM;
-
- codec = skl_codec_device_init(bus, addr);
- if (IS_ERR(codec))
- return PTR_ERR(codec);
-
- hda_codec->codec = codec;
- dev_set_drvdata(&codec->core.dev, hda_codec);
-
- /* use legacy bus only for HDA codecs, idisp uses ext bus */
- if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) {
- codec->core.type = HDA_DEV_LEGACY;
- load_codec_module(hda_codec->codec);
- }
- return 0;
-#else
- codec = skl_codec_device_init(bus, addr);
- return PTR_ERR_OR_ZERO(codec);
-#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */
-}
-
-/* Codec initialization */
-static void skl_codec_create(struct hdac_bus *bus)
-{
- int c, max_slots;
-
- max_slots = HDA_MAX_CODECS;
-
- /* First try to probe all given codec slots */
- for (c = 0; c < max_slots; c++) {
- if ((bus->codec_mask & (1 << c))) {
- if (probe_codec(bus, c) < 0) {
- /*
- * Some BIOSen give you wrong codec addresses
- * that don't exist
- */
- dev_warn(bus->dev,
- "Codec #%d probe error; disabling it...\n", c);
- bus->codec_mask &= ~(1 << c);
- /*
- * More badly, accessing to a non-existing
- * codec often screws up the controller bus,
- * and disturbs the further communications.
- * Thus if an error occurs during probing,
- * better to reset the controller bus to get
- * back to the sanity state.
- */
- snd_hdac_bus_stop_chip(bus);
- skl_init_chip(bus, true);
- }
- }
- }
-}
-
-static int skl_i915_init(struct hdac_bus *bus)
-{
- int err;
-
- /*
- * The HDMI codec is in GPU so we need to ensure that it is powered
- * up and ready for probe
- */
- err = snd_hdac_i915_init(bus);
- if (err < 0)
- return err;
-
- snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
-
- return 0;
-}
-
-static void skl_probe_work(struct work_struct *work)
-{
- struct skl_dev *skl = container_of(work, struct skl_dev, probe_work);
- struct hdac_bus *bus = skl_to_bus(skl);
- struct hdac_ext_link *hlink;
- int err;
-
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
- err = skl_i915_init(bus);
- if (err < 0)
- return;
- }
-
- skl_init_pci(skl);
- skl_dum_set(bus);
-
- err = skl_init_chip(bus, true);
- if (err < 0) {
- dev_err(bus->dev, "Init chip failed with err: %d\n", err);
- goto out_err;
- }
-
- /* codec detection */
- if (!bus->codec_mask)
- dev_info(bus->dev, "no hda codecs found!\n");
-
- /* create codec instances */
- skl_codec_create(bus);
-
- /* register platform dai and controls */
- err = skl_platform_register(bus->dev);
- if (err < 0) {
- dev_err(bus->dev, "platform register failed: %d\n", err);
- goto out_err;
- }
-
- err = skl_machine_device_register(skl);
- if (err < 0) {
- dev_err(bus->dev, "machine register failed: %d\n", err);
- goto out_err;
- }
-
- /*
- * we are done probing so decrement link counts
- */
- list_for_each_entry(hlink, &bus->hlink_list, list)
- snd_hdac_ext_bus_link_put(bus, hlink);
-
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
- snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
-
- /* configure PM */
- pm_runtime_put_noidle(bus->dev);
- pm_runtime_allow(bus->dev);
- skl->init_done = 1;
-
- return;
-
-out_err:
- if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
- snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
-}
-
-/*
- * constructor
- */
-static int skl_create(struct pci_dev *pci,
- struct skl_dev **rskl)
-{
- struct hdac_ext_bus_ops *ext_ops = NULL;
- struct skl_dev *skl;
- struct hdac_bus *bus;
- struct hda_bus *hbus;
- int err;
-
- *rskl = NULL;
-
- err = pci_enable_device(pci);
- if (err < 0)
- return err;
-
- skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL);
- if (!skl) {
- pci_disable_device(pci);
- return -ENOMEM;
- }
-
- hbus = skl_to_hbus(skl);
- bus = skl_to_bus(skl);
-
- INIT_LIST_HEAD(&skl->ppl_list);
- INIT_LIST_HEAD(&skl->bind_list);
-
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
- ext_ops = snd_soc_hdac_hda_get_ops();
-#endif
- snd_hdac_ext_bus_init(bus, &pci->dev, NULL, ext_ops);
- bus->use_posbuf = 1;
- skl->pci = pci;
- INIT_WORK(&skl->probe_work, skl_probe_work);
- bus->bdl_pos_adj = 0;
-
- mutex_init(&hbus->prepare_mutex);
- hbus->pci = pci;
- hbus->mixer_assigned = -1;
- hbus->modelname = "sklbus";
-
- *rskl = skl;
-
- return 0;
-}
-
-static int skl_first_init(struct hdac_bus *bus)
-{
- struct skl_dev *skl = bus_to_skl(bus);
- struct pci_dev *pci = skl->pci;
- int err;
- unsigned short gcap;
- int cp_streams, pb_streams, start_idx;
-
- err = pci_request_regions(pci, "Skylake HD audio");
- if (err < 0)
- return err;
-
- bus->addr = pci_resource_start(pci, 0);
- bus->remap_addr = pci_ioremap_bar(pci, 0);
- if (bus->remap_addr == NULL) {
- dev_err(bus->dev, "ioremap error\n");
- return -ENXIO;
- }
-
- snd_hdac_bus_parse_capabilities(bus);
-
- /* check if PPCAP exists */
- if (!bus->ppcap) {
- dev_err(bus->dev, "bus ppcap not set, HDAudio or DSP not present?\n");
- return -ENODEV;
- }
-
- if (skl_acquire_irq(bus, 0) < 0)
- return -EBUSY;
-
- pci_set_master(pci);
- synchronize_irq(bus->irq);
-
- gcap = snd_hdac_chip_readw(bus, GCAP);
- dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
-
- /* read number of streams from GCAP register */
- cp_streams = (gcap >> 8) & 0x0f;
- pb_streams = (gcap >> 12) & 0x0f;
-
- if (!pb_streams && !cp_streams) {
- dev_err(bus->dev, "no streams found in GCAP definitions?\n");
- return -EIO;
- }
-
- bus->num_streams = cp_streams + pb_streams;
-
- /* allow 64bit DMA address if supported by H/W */
- if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64)))
- dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32));
- dma_set_max_seg_size(bus->dev, UINT_MAX);
-
- /* initialize streams */
- snd_hdac_ext_stream_init_all
- (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
- start_idx = cp_streams;
- snd_hdac_ext_stream_init_all
- (bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
-
- err = snd_hdac_bus_alloc_stream_pages(bus);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int skl_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
-{
- struct skl_dev *skl;
- struct hdac_bus *bus = NULL;
- int err;
-
- switch (skl_pci_binding) {
- case SND_SKL_PCI_BIND_AUTO:
- err = snd_intel_dsp_driver_probe(pci);
- if (err != SND_INTEL_DSP_DRIVER_ANY &&
- err != SND_INTEL_DSP_DRIVER_SST)
- return -ENODEV;
- break;
- case SND_SKL_PCI_BIND_LEGACY:
- dev_info(&pci->dev, "Module parameter forced binding with HDAudio legacy, aborting probe\n");
- return -ENODEV;
- case SND_SKL_PCI_BIND_ASOC:
- dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n");
- break;
- default:
- dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
- break;
- }
-
- /* we use ext core ops, so provide NULL for ops here */
- err = skl_create(pci, &skl);
- if (err < 0)
- return err;
-
- bus = skl_to_bus(skl);
-
- err = skl_first_init(bus);
- if (err < 0) {
- dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
- goto out_free;
- }
-
- skl->pci_id = pci->device;
-
- device_disable_async_suspend(bus->dev);
-
- skl->nhlt = intel_nhlt_init(bus->dev);
-
- if (skl->nhlt == NULL) {
-#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
- dev_err(bus->dev, "no nhlt info found\n");
- err = -ENODEV;
- goto out_free;
-#else
- dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDAudio codec\n");
-#endif
- } else {
-
- err = skl_nhlt_create_sysfs(skl);
- if (err < 0) {
- dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
- goto out_nhlt_free;
- }
-
- skl_nhlt_update_topology_bin(skl);
-
- /* create device for dsp clk */
- err = skl_clock_device_register(skl);
- if (err < 0) {
- dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
- goto out_clk_free;
- }
- }
-
- pci_set_drvdata(skl->pci, bus);
-
-
- err = skl_find_machine(skl, (void *)pci_id->driver_data);
- if (err < 0) {
- dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
- goto out_nhlt_free;
- }
-
- err = skl_init_dsp(skl);
- if (err < 0) {
- dev_dbg(bus->dev, "error failed to register dsp\n");
- goto out_nhlt_free;
- }
- skl->enable_miscbdcge = skl_enable_miscbdcge;
- skl->clock_power_gating = skl_clock_power_gating;
-
- if (bus->mlcap)
- snd_hdac_ext_bus_get_ml_capabilities(bus);
-
- /* create device for soc dmic */
- err = skl_dmic_device_register(skl);
- if (err < 0) {
- dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
- goto out_dsp_free;
- }
-
- schedule_work(&skl->probe_work);
-
- return 0;
-
-out_dsp_free:
- skl_free_dsp(skl);
-out_clk_free:
- skl_clock_device_unregister(skl);
-out_nhlt_free:
- if (skl->nhlt)
- intel_nhlt_free(skl->nhlt);
-out_free:
- skl_free(bus);
-
- return err;
-}
-
-static void skl_shutdown(struct pci_dev *pci)
-{
- struct hdac_bus *bus = pci_get_drvdata(pci);
- struct hdac_stream *s;
- struct hdac_ext_stream *stream;
- struct skl_dev *skl;
-
- if (!bus)
- return;
-
- skl = bus_to_skl(bus);
-
- if (!skl->init_done)
- return;
-
- snd_hdac_stop_streams(bus);
- snd_hdac_ext_bus_link_power_down_all(bus);
- skl_dsp_sleep(skl->dsp);
-
- list_for_each_entry(s, &bus->stream_list, list) {
- stream = stream_to_hdac_ext_stream(s);
- snd_hdac_ext_stream_decouple(bus, stream, false);
- }
-
- snd_hdac_bus_stop_chip(bus);
-}
-
-static void skl_remove(struct pci_dev *pci)
-{
- struct hdac_bus *bus = pci_get_drvdata(pci);
- struct skl_dev *skl = bus_to_skl(bus);
-
- cancel_work_sync(&skl->probe_work);
-
- pm_runtime_get_noresume(&pci->dev);
-
- /* codec removal, invoke bus_device_remove */
- snd_hdac_ext_bus_device_remove(bus);
-
- skl_platform_unregister(&pci->dev);
- skl_free_dsp(skl);
- skl_machine_device_unregister(skl);
- skl_dmic_device_unregister(skl);
- skl_clock_device_unregister(skl);
- skl_nhlt_remove_sysfs(skl);
- if (skl->nhlt)
- intel_nhlt_free(skl->nhlt);
- skl_free(bus);
-}
-
-/* PCI IDs */
-static const struct pci_device_id skl_ids[] = {
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
- /* Sunrise Point-LP */
- { PCI_DEVICE(0x8086, 0x9d70),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
- /* BXT-P */
- { PCI_DEVICE(0x8086, 0x5a98),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
- /* KBL */
- { PCI_DEVICE(0x8086, 0x9D71),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
- /* GLK */
- { PCI_DEVICE(0x8086, 0x3198),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
- /* CNL */
- { PCI_DEVICE(0x8086, 0x9dc8),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
- /* CFL */
- { PCI_DEVICE(0x8086, 0xa348),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP)
- /* CML-LP */
- { PCI_DEVICE(0x8086, 0x02c8),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
-#endif
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H)
- /* CML-H */
- { PCI_DEVICE(0x8086, 0x06c8),
- .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
-#endif
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, skl_ids);
-
-/* pci_driver definition */
-static struct pci_driver skl_driver = {
- .name = KBUILD_MODNAME,
- .id_table = skl_ids,
- .probe = skl_probe,
- .remove = skl_remove,
- .shutdown = skl_shutdown,
- .driver = {
- .pm = &skl_pm,
- },
-};
-module_pci_driver(skl_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver");
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
deleted file mode 100644
index f55f8b3dbdc3..000000000000
--- a/sound/soc/intel/skylake/skl.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * skl.h - HD Audio skylake definitions.
- *
- * Copyright (C) 2015 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#ifndef __SOUND_SOC_SKL_H
-#define __SOUND_SOC_SKL_H
-
-#include <sound/hda_register.h>
-#include <sound/hdaudio_ext.h>
-#include <sound/hda_codec.h>
-#include <sound/soc.h>
-#include "skl-ssp-clk.h"
-#include "skl-sst-ipc.h"
-
-#define SKL_SUSPEND_DELAY 2000
-
-#define SKL_MAX_ASTATE_CFG 3
-
-#define AZX_PCIREG_PGCTL 0x44
-#define AZX_PGCTL_LSRMD_MASK (1 << 4)
-#define AZX_PGCTL_ADSPPGD BIT(2)
-#define AZX_PCIREG_CGCTL 0x48
-#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6)
-#define AZX_CGCTL_ADSPDCGE BIT(1)
-/* D0I3C Register fields */
-#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */
-#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */
-#define SKL_MAX_DMACTRL_CFG 18
-#define DMA_CLK_CONTROLS 1
-#define DMA_TRANSMITION_START 2
-#define DMA_TRANSMITION_STOP 3
-
-#define AZX_VS_EM2_DUM BIT(23)
-#define AZX_REG_VS_EM2_L1SEN BIT(13)
-
-struct skl_debug;
-
-struct skl_astate_param {
- u32 kcps;
- u32 clk_src;
-};
-
-struct skl_astate_config {
- u32 count;
- struct skl_astate_param astate_table[];
-};
-
-struct skl_fw_config {
- struct skl_astate_config *astate_cfg;
-};
-
-struct skl_dev {
- struct hda_bus hbus;
- struct pci_dev *pci;
-
- unsigned int init_done:1; /* delayed init status */
- struct platform_device *dmic_dev;
- struct platform_device *i2s_dev;
- struct platform_device *clk_dev;
- struct snd_soc_component *component;
- struct snd_soc_dai_driver *dais;
-
- struct nhlt_acpi_table *nhlt; /* nhlt ptr */
-
- struct list_head ppl_list;
- struct list_head bind_list;
-
- const char *fw_name;
- char tplg_name[64];
- unsigned short pci_id;
-
- int supend_active;
-
- struct work_struct probe_work;
-
- struct skl_debug *debugfs;
- u8 nr_modules;
- struct skl_module **modules;
- bool use_tplg_pcm;
- struct skl_fw_config cfg;
- struct snd_soc_acpi_mach *mach;
-
- struct device *dev;
- struct sst_dsp *dsp;
-
- /* boot */
- wait_queue_head_t boot_wait;
- bool boot_complete;
-
- /* module load */
- wait_queue_head_t mod_load_wait;
- bool mod_load_complete;
- bool mod_load_status;
-
- /* IPC messaging */
- struct sst_generic_ipc ipc;
-
- /* callback for miscbdge */
- void (*enable_miscbdcge)(struct device *dev, bool enable);
- /* Is CGCTL.MISCBDCGE disabled */
- bool miscbdcg_disabled;
-
- /* Populate module information */
- struct list_head uuid_list;
-
- /* Is firmware loaded */
- bool fw_loaded;
-
- /* first boot ? */
- bool is_first_boot;
-
- /* multi-core */
- struct skl_dsp_cores cores;
-
- /* library info */
- struct skl_lib_info lib_info[SKL_MAX_LIB];
- int lib_count;
-
- /* Callback to update D0i3C register */
- void (*update_d0i3c)(struct device *dev, bool enable);
-
- struct skl_d0i3_data d0i3;
-
- const struct skl_dsp_ops *dsp_ops;
-
- /* Callback to update dynamic clock and power gating registers */
- void (*clock_power_gating)(struct device *dev, bool enable);
-};
-
-#define skl_to_bus(s) (&(s)->hbus.core)
-#define bus_to_skl(bus) container_of(bus, struct skl_dev, hbus.core)
-
-#define skl_to_hbus(s) (&(s)->hbus)
-#define hbus_to_skl(hbus) container_of((hbus), struct skl_dev, (hbus))
-
-/* to pass dai dma data */
-struct skl_dma_params {
- u32 format;
- u8 stream_tag;
-};
-
-struct skl_machine_pdata {
- bool use_tplg_pcm; /* use dais and dai links from topology */
-};
-
-struct skl_dsp_ops {
- int id;
- unsigned int num_cores;
- struct skl_dsp_loader_ops (*loader_ops)(void);
- int (*init)(struct device *dev, void __iomem *mmio_base,
- int irq, const char *fw_name,
- struct skl_dsp_loader_ops loader_ops,
- struct skl_dev **skl_sst);
- int (*init_fw)(struct device *dev, struct skl_dev *skl);
- void (*cleanup)(struct device *dev, struct skl_dev *skl);
-};
-
-int skl_platform_unregister(struct device *dev);
-int skl_platform_register(struct device *dev);
-
-int skl_nhlt_update_topology_bin(struct skl_dev *skl);
-int skl_init_dsp(struct skl_dev *skl);
-int skl_free_dsp(struct skl_dev *skl);
-int skl_suspend_late_dsp(struct skl_dev *skl);
-int skl_suspend_dsp(struct skl_dev *skl);
-int skl_resume_dsp(struct skl_dev *skl);
-void skl_cleanup_resources(struct skl_dev *skl);
-const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
-void skl_update_d0i3c(struct device *dev, bool enable);
-int skl_nhlt_create_sysfs(struct skl_dev *skl);
-void skl_nhlt_remove_sysfs(struct skl_dev *skl);
-void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks);
-struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id);
-int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps,
- u32 caps_size, u32 node_id);
-
-struct skl_module_cfg;
-
-#ifdef CONFIG_DEBUG_FS
-struct skl_debug *skl_debugfs_init(struct skl_dev *skl);
-void skl_debugfs_exit(struct skl_dev *skl);
-void skl_debug_init_module(struct skl_debug *d,
- struct snd_soc_dapm_widget *w,
- struct skl_module_cfg *mconfig);
-#else
-static inline struct skl_debug *skl_debugfs_init(struct skl_dev *skl)
-{
- return NULL;
-}
-
-static inline void skl_debugfs_exit(struct skl_dev *skl)
-{}
-
-static inline void skl_debug_init_module(struct skl_debug *d,
- struct snd_soc_dapm_widget *w,
- struct skl_module_cfg *mconfig)
-{}
-#endif
-
-#endif /* __SOUND_SOC_SKL_H */
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
index dd3b4507fbe6..f3ff3fb49239 100644
--- a/sound/soc/jz4740/Kconfig
+++ b/sound/soc/jz4740/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "JZ4740"
+
config SND_JZ4740_SOC_I2S
tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST
@@ -8,3 +10,5 @@ config SND_JZ4740_SOC_I2S
help
Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
based boards.
+
+endmenu
diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile
index f8701c9b09fe..1c7f3f375318 100644
--- a/sound/soc/jz4740/Makefile
+++ b/sound/soc/jz4740/Makefile
@@ -2,6 +2,6 @@
#
# Jz4740 Platform Support
#
-snd-soc-jz4740-i2s-objs := jz4740-i2s.o
+snd-soc-jz4740-i2s-y := jz4740-i2s.o
obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 578af21769c9..517619531615 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
+ .probe = jz4740_i2s_dai_probe,
.startup = jz4740_i2s_startup,
.shutdown = jz4740_i2s_shutdown,
.trigger = jz4740_i2s_trigger,
@@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver jz4740_i2s_dai = {
- .probe = jz4740_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = {
};
static struct snd_soc_dai_driver jz4770_i2s_dai = {
- .probe = jz4740_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
index 5d8a86b26fa2..924072e402c8 100644
--- a/sound/soc/kirkwood/Kconfig
+++ b/sound/soc/kirkwood/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Kirkwood"
+
config SND_KIRKWOOD_SOC
tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
@@ -16,3 +18,4 @@ config SND_KIRKWOOD_SOC_ARMADA370_DB
Say Y if you want to add support for SoC audio on
the Armada 370 Development Board.
+endmenu
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
index e2d279f16a46..9be1eb8203a1 100644
--- a/sound/soc/kirkwood/Makefile
+++ b/sound/soc/kirkwood/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-kirkwood-objs := kirkwood-dma.o kirkwood-i2s.o
+snd-soc-kirkwood-y := kirkwood-dma.o kirkwood-i2s.o
obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
-snd-soc-armada-370-db-objs := armada-370-db.o
+snd-soc-armada-370-db-y := armada-370-db.o
obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
index 81326426da33..77a5f440364e 100644
--- a/sound/soc/kirkwood/armada-370-db.c
+++ b/sound/soc/kirkwood/armada-370-db.c
@@ -18,8 +18,8 @@
static int a370db_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int freq;
switch (params_rate(params)) {
@@ -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/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index 640cebd2983e..036b42058272 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -19,8 +19,8 @@
static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
{
- struct snd_soc_pcm_runtime *soc_runtime = subs->private_data;
- return snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(soc_runtime, 0));
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(subs);
+ return snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(soc_runtime, 0));
}
static const struct snd_pcm_hardware kirkwood_dma_snd_hw = {
@@ -182,6 +182,9 @@ static int kirkwood_dma_hw_params(struct snd_soc_component *component,
const struct mbus_dram_target_info *dram = mv_mbus_dram_info();
unsigned long addr = substream->runtime->dma_addr;
+ if (!dram)
+ return 0;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
kirkwood_dma_conf_mbus_windows(priv->io,
KIRKWOOD_PLAYBACK_WIN, addr, dram);
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index d1eb90310afa..99bd066c7309 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -759,7 +759,7 @@ MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
static struct platform_driver kirkwood_i2s_driver = {
.probe = kirkwood_i2s_dev_probe,
- .remove_new = kirkwood_i2s_dev_remove,
+ .remove = kirkwood_i2s_dev_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(mvebu_audio_of_match),
diff --git a/sound/soc/loongson/Kconfig b/sound/soc/loongson/Kconfig
index b8d7e2bade24..2e06670e4d7e 100644
--- a/sound/soc/loongson/Kconfig
+++ b/sound/soc/loongson/Kconfig
@@ -1,11 +1,23 @@
# SPDX-License-Identifier: GPL-2.0
-menu "SoC Audio for Loongson CPUs"
+menu "Loongson"
+
+config SND_SOC_LOONGSON_CARD
+ tristate "Loongson Sound Card Driver"
depends on LOONGARCH || COMPILE_TEST
+ select SND_SOC_LOONGSON_I2S_PCI if PCI
+ select SND_SOC_LOONGSON_I2S_PLATFORM if OF
+ help
+ Say Y or M if you want to add support for SoC audio using
+ loongson I2S controller.
+
+ The driver add support for ALSA SoC Audio support using
+ loongson I2S controller.
config SND_SOC_LOONGSON_I2S_PCI
tristate "Loongson I2S-PCI Device Driver"
- select REGMAP_MMIO
+ depends on LOONGARCH || COMPILE_TEST
depends on PCI
+ select REGMAP_MMIO
help
Say Y or M if you want to add support for I2S driver for
Loongson I2S controller.
@@ -13,15 +25,25 @@ config SND_SOC_LOONGSON_I2S_PCI
The controller is found in loongson bridge chips or SoCs,
and work as a PCI device.
-config SND_SOC_LOONGSON_CARD
- tristate "Loongson Sound Card Driver"
- select SND_SOC_LOONGSON_I2S_PCI
- depends on PCI
+config SND_SOC_LOONGSON_I2S_PLATFORM
+ tristate "Loongson I2S-PLAT Device Driver"
+ depends on LOONGARCH || COMPILE_TEST
+ select REGMAP_MMIO
+ select SND_SOC_GENERIC_DMAENGINE_PCM
help
- Say Y or M if you want to add support for SoC audio using
- loongson I2S controller.
-
- The driver add support for ALSA SoC Audio support using
- loongson I2S controller.
+ Say Y or M if you want to add support for I2S driver for
+ Loongson I2S controller.
+ The controller work as a platform device, we can found it in
+ Loongson-2K1000 SoCs.
endmenu
+
+config SND_LOONGSON1_AC97
+ tristate "Loongson1 AC97 Support"
+ depends on LOONGSON1_APB_DMA
+ select SND_SOC_AC97_CODEC
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Loongson1 AC97 controller.
diff --git a/sound/soc/loongson/Makefile b/sound/soc/loongson/Makefile
index 601a905a4860..4c6d3130bcee 100644
--- a/sound/soc/loongson/Makefile
+++ b/sound/soc/loongson/Makefile
@@ -1,8 +1,15 @@
# SPDX-License-Identifier: GPL-2.0
#Platform Support
-snd-soc-loongson-i2s-pci-objs := loongson_i2s_pci.o loongson_i2s.o loongson_dma.o
-obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o
+snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_dma.o
+obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o snd-soc-loongson-i2s.o
+
+snd-soc-loongson-i2s-plat-y := loongson_i2s_plat.o
+obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PLATFORM) += snd-soc-loongson-i2s-plat.o snd-soc-loongson-i2s.o
+
+snd-soc-loongson-i2s-y := loongson_i2s.o
+
+obj-$(CONFIG_SND_LOONGSON1_AC97) += loongson1_ac97.o
#Machine Support
-snd-soc-loongson-card-objs := loongson_card.o
+snd-soc-loongson-card-y := loongson_card.o
obj-$(CONFIG_SND_SOC_LOONGSON_CARD) += snd-soc-loongson-card.o
diff --git a/sound/soc/loongson/loongson1_ac97.c b/sound/soc/loongson/loongson1_ac97.c
new file mode 100644
index 000000000000..84901900ad43
--- /dev/null
+++ b/sound/soc/loongson/loongson1_ac97.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AC97 Controller Driver for Loongson-1 SoC
+ *
+ * Copyright (C) 2025 Keguang Zhang <keguang.zhang@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+/* Loongson-1 AC97 Controller Registers */
+#define AC97_CSR 0x0
+#define AC97_OCC0 0x4
+#define AC97_ICC 0x10
+#define AC97_CRAC 0x18
+#define AC97_INTRAW 0x54
+#define AC97_INTM 0x58
+#define AC97_INT_CW_CLR 0x68
+#define AC97_INT_CR_CLR 0x6c
+
+/* Control Status Register Bits (CSR) */
+#define CSR_RESUME BIT(1)
+#define CSR_RST_FORCE BIT(0)
+
+/* MIC Channel Configuration Bits */
+#define M_DMA_EN BIT(22)
+#define M_FIFO_THRES GENMASK(21, 20)
+#define M_FIFO_THRES_FULL FIELD_PREP(M_FIFO_THRES, 3)
+#define M_FIFO_THRES_HALF FIELD_PREP(M_FIFO_THRES, 1)
+#define M_FIFO_THRES_QUARTER FIELD_PREP(M_FIFO_THRES, 0)
+#define M_SW GENMASK(19, 18)
+#define M_SW_16_BITS FIELD_PREP(M_SW, 2)
+#define M_SW_8_BITS FIELD_PREP(M_SW, 0)
+#define M_VSR BIT(17)
+#define M_CH_EN BIT(16)
+/* Right Channel Configuration Bits */
+#define R_DMA_EN BIT(14)
+#define R_FIFO_THRES GENMASK(13, 12)
+#define R_FIFO_THRES_EMPTY FIELD_PREP(R_FIFO_THRES, 3)
+#define R_FIFO_THRES_HALF FIELD_PREP(R_FIFO_THRES, 1)
+#define R_FIFO_THRES_QUARTER FIELD_PREP(R_FIFO_THRES, 0)
+#define R_SW GENMASK(11, 10)
+#define R_SW_16_BITS FIELD_PREP(R_SW, 2)
+#define R_SW_8_BITS FIELD_PREP(R_SW, 0)
+#define R_VSR BIT(9)
+#define R_CH_EN BIT(8)
+/* Left Channel Configuration Bits */
+#define L_DMA_EN BIT(6)
+#define L_FIFO_THRES GENMASK(5, 4)
+#define L_FIFO_THRES_EMPTY FIELD_PREP(L_FIFO_THRES, 3)
+#define L_FIFO_THRES_HALF FIELD_PREP(L_FIFO_THRES, 1)
+#define L_FIFO_THRES_QUARTER FIELD_PREP(L_FIFO_THRES, 0)
+#define L_SW GENMASK(3, 2)
+#define L_SW_16_BITS FIELD_PREP(L_SW, 2)
+#define L_SW_8_BITS FIELD_PREP(L_SW, 0)
+#define L_VSR BIT(1)
+#define L_CH_EN BIT(0)
+
+/* Codec Register Access Command Bits (CRAC) */
+#define CODEC_WR BIT(31)
+#define CODEC_ADR GENMASK(22, 16)
+#define CODEC_DAT GENMASK(15, 0)
+
+/* Interrupt Register (INTRAW) */
+#define CW_DONE BIT(1)
+#define CR_DONE BIT(0)
+
+#define LS1X_AC97_DMA_TX_EN BIT(31)
+#define LS1X_AC97_DMA_STEREO BIT(30)
+#define LS1X_AC97_DMA_TX_BYTES GENMASK(29, 28)
+#define LS1X_AC97_DMA_TX_4_BYTES FIELD_PREP(LS1X_AC97_DMA_TX_BYTES, 2)
+#define LS1X_AC97_DMA_TX_2_BYTES FIELD_PREP(LS1X_AC97_DMA_TX_BYTES, 1)
+#define LS1X_AC97_DMA_TX_1_BYTE FIELD_PREP(LS1X_AC97_DMA_TX_BYTES, 0)
+#define LS1X_AC97_DMA_DADDR_MASK GENMASK(27, 0)
+
+#define LS1X_AC97_DMA_FIFO_SIZE 128
+
+#define LS1X_AC97_TIMEOUT 3000
+
+struct ls1x_ac97 {
+ void __iomem *reg_base;
+ struct regmap *regmap;
+ dma_addr_t tx_dma_base;
+ dma_addr_t rx_dma_base;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+};
+
+static struct ls1x_ac97 *ls1x_ac97;
+
+static const struct regmap_config ls1x_ac97_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static void ls1x_ac97_reset(struct snd_ac97 *ac97)
+{
+ int val;
+
+ regmap_write(ls1x_ac97->regmap, AC97_CSR, CSR_RST_FORCE);
+ regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
+ !(val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
+}
+
+static void ls1x_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
+{
+ int tmp, ret;
+
+ tmp = FIELD_PREP(CODEC_ADR, reg) | FIELD_PREP(CODEC_DAT, val);
+ regmap_write(ls1x_ac97->regmap, AC97_CRAC, tmp);
+ ret = regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_INTRAW, tmp,
+ (tmp & CW_DONE), 0, LS1X_AC97_TIMEOUT);
+ if (ret)
+ pr_err("timeout on AC97 write! %d\n", ret);
+
+ regmap_read(ls1x_ac97->regmap, AC97_INT_CW_CLR, &ret);
+}
+
+static unsigned short ls1x_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+ int val, ret;
+
+ val = CODEC_WR | FIELD_PREP(CODEC_ADR, reg);
+ regmap_write(ls1x_ac97->regmap, AC97_CRAC, val);
+ ret = regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_INTRAW, val,
+ (val & CR_DONE), 0, LS1X_AC97_TIMEOUT);
+ if (ret) {
+ pr_err("timeout on AC97 read! %d\n", ret);
+ return ret;
+ }
+
+ regmap_read(ls1x_ac97->regmap, AC97_INT_CR_CLR, &ret);
+ regmap_read(ls1x_ac97->regmap, AC97_CRAC, &ret);
+
+ return (ret & CODEC_DAT);
+}
+
+static void ls1x_ac97_init(struct snd_ac97 *ac97)
+{
+ writel(0, ls1x_ac97->reg_base + AC97_INTRAW);
+ writel(0, ls1x_ac97->reg_base + AC97_INTM);
+
+ /* Config output channels */
+ regmap_update_bits(ls1x_ac97->regmap, AC97_OCC0,
+ R_DMA_EN | R_FIFO_THRES | R_CH_EN |
+ L_DMA_EN | L_FIFO_THRES | L_CH_EN,
+ R_DMA_EN | R_FIFO_THRES_EMPTY | R_CH_EN |
+ L_DMA_EN | L_FIFO_THRES_EMPTY | L_CH_EN);
+
+ /* Config inputs channel */
+ regmap_update_bits(ls1x_ac97->regmap, AC97_ICC,
+ M_DMA_EN | M_FIFO_THRES | M_CH_EN |
+ R_DMA_EN | R_FIFO_THRES | R_CH_EN |
+ L_DMA_EN | L_FIFO_THRES | L_CH_EN,
+ M_DMA_EN | M_FIFO_THRES_FULL | M_CH_EN |
+ R_DMA_EN | R_FIFO_THRES_EMPTY | R_CH_EN |
+ L_DMA_EN | L_FIFO_THRES_EMPTY | L_CH_EN);
+
+ if (ac97->ext_id & AC97_EI_VRA) {
+ regmap_update_bits(ls1x_ac97->regmap, AC97_OCC0, R_VSR | L_VSR, R_VSR | L_VSR);
+ regmap_update_bits(ls1x_ac97->regmap, AC97_ICC, M_VSR, M_VSR);
+ }
+}
+
+static struct snd_ac97_bus_ops ls1x_ac97_ops = {
+ .reset = ls1x_ac97_reset,
+ .write = ls1x_ac97_write,
+ .read = ls1x_ac97_read,
+ .init = ls1x_ac97_init,
+};
+
+static int ls1x_ac97_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct ls1x_ac97 *ac97 = dev_get_drvdata(cpu_dai->dev);
+ struct snd_dmaengine_dai_dma_data *dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ switch (params_channels(params)) {
+ case 1:
+ dma_data->addr &= ~LS1X_AC97_DMA_STEREO;
+ break;
+ case 2:
+ dma_data->addr |= LS1X_AC97_DMA_STEREO;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "unsupported channels! %d\n", params_channels(params));
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ case SNDRV_PCM_FORMAT_U8:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(ac97->regmap, AC97_OCC0,
+ R_SW | L_SW,
+ R_SW_8_BITS | L_SW_8_BITS);
+ else
+ regmap_update_bits(ac97->regmap, AC97_ICC,
+ M_SW | R_SW | L_SW,
+ M_SW_8_BITS | R_SW_8_BITS | L_SW_8_BITS);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ case SNDRV_PCM_FORMAT_U16_BE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(ac97->regmap, AC97_OCC0,
+ R_SW | L_SW,
+ R_SW_16_BITS | L_SW_16_BITS);
+ else
+ regmap_update_bits(ac97->regmap, AC97_ICC,
+ M_SW | R_SW | L_SW,
+ M_SW_16_BITS | R_SW_16_BITS | L_SW_16_BITS);
+ break;
+ default:
+ dev_err(cpu_dai->dev, "unsupported format! %d\n", params_format(params));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ls1x_ac97_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct ls1x_ac97 *ac97 = dev_get_drvdata(cpu_dai->dev);
+
+ ac97->capture_dma_data.addr = ac97->rx_dma_base & LS1X_AC97_DMA_DADDR_MASK;
+ ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ ac97->capture_dma_data.fifo_size = LS1X_AC97_DMA_FIFO_SIZE;
+
+ ac97->playback_dma_data.addr = ac97->tx_dma_base & LS1X_AC97_DMA_DADDR_MASK;
+ ac97->playback_dma_data.addr |= LS1X_AC97_DMA_TX_4_BYTES;
+ ac97->playback_dma_data.addr |= LS1X_AC97_DMA_TX_EN;
+ ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ ac97->playback_dma_data.fifo_size = LS1X_AC97_DMA_FIFO_SIZE;
+
+ snd_soc_dai_init_dma_data(cpu_dai, &ac97->playback_dma_data, &ac97->capture_dma_data);
+ snd_soc_dai_set_drvdata(cpu_dai, ac97);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops ls1x_ac97_dai_ops = {
+ .probe = ls1x_ac97_dai_probe,
+ .hw_params = ls1x_ac97_hw_params,
+};
+
+#define LS1X_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |\
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
+ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE)
+
+static struct snd_soc_dai_driver ls1x_ac97_dai[] = {
+ {
+ .name = "ls1x-ac97",
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = LS1X_AC97_FMTS,
+ },
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = LS1X_AC97_FMTS,
+ },
+ .ops = &ls1x_ac97_dai_ops,
+ },
+};
+
+static const struct snd_soc_component_driver ls1x_ac97_component = {
+ .name = KBUILD_MODNAME,
+ .legacy_dai_naming = 1,
+};
+
+static int ls1x_ac97_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ls1x_ac97 *ac97;
+ struct resource *res;
+ int ret;
+
+ ac97 = devm_kzalloc(dev, sizeof(struct ls1x_ac97), GFP_KERNEL);
+ if (!ac97)
+ return -ENOMEM;
+ ls1x_ac97 = ac97;
+ platform_set_drvdata(pdev, ac97);
+
+ ac97->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ac97->reg_base))
+ return PTR_ERR(ac97->reg_base);
+
+ ac97->regmap = devm_regmap_init_mmio(dev, ac97->reg_base, &ls1x_ac97_regmap_config);
+ if (IS_ERR(ac97->regmap))
+ return dev_err_probe(dev, PTR_ERR(ac97->regmap), "devm_regmap_init_mmio failed\n");
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audio-tx");
+ if (!res)
+ return dev_err_probe(dev, -EINVAL, "Missing 'audio-tx' in reg-names property\n");
+
+ ac97->tx_dma_base = dma_map_resource(dev, res->start, resource_size(res),
+ DMA_TO_DEVICE, 0);
+ if (dma_mapping_error(dev, ac97->tx_dma_base))
+ return -ENXIO;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audio-rx");
+ if (!res)
+ return dev_err_probe(dev, -EINVAL, "Missing 'audio-rx' in reg-names property\n");
+
+ ac97->rx_dma_base = dma_map_resource(dev, res->start, resource_size(res),
+ DMA_FROM_DEVICE, 0);
+ if (dma_mapping_error(dev, ac97->rx_dma_base))
+ return -ENXIO;
+
+ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
+ if (ret)
+ dev_err_probe(dev, ret, "failed to register PCM\n");
+
+ ret = devm_snd_soc_register_component(dev, &ls1x_ac97_component,
+ ls1x_ac97_dai, ARRAY_SIZE(ls1x_ac97_dai));
+ if (ret)
+ dev_err_probe(dev, ret, "failed to register DAI\n");
+
+ return snd_soc_set_ac97_ops(&ls1x_ac97_ops);
+}
+
+static void ls1x_ac97_remove(struct platform_device *pdev)
+{
+ ls1x_ac97 = NULL;
+ snd_soc_set_ac97_ops(NULL);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ls1x_ac97_suspend(struct device *dev)
+{
+ int val;
+
+ regmap_clear_bits(ls1x_ac97->regmap, AC97_OCC0, R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
+ regmap_clear_bits(ls1x_ac97->regmap, AC97_ICC,
+ M_DMA_EN | M_CH_EN | R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
+ regmap_set_bits(ls1x_ac97->regmap, AC97_CSR, CSR_RESUME);
+
+ return regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
+ (val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
+}
+
+static int ls1x_ac97_resume(struct device *dev)
+{
+ int val;
+
+ regmap_set_bits(ls1x_ac97->regmap, AC97_OCC0, R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
+ regmap_set_bits(ls1x_ac97->regmap, AC97_ICC,
+ M_DMA_EN | M_CH_EN | R_DMA_EN | R_CH_EN | L_DMA_EN | L_CH_EN);
+ regmap_set_bits(ls1x_ac97->regmap, AC97_CSR, CSR_RESUME);
+
+ return regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
+ !(val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
+}
+#endif
+
+static const struct dev_pm_ops ls1x_ac97_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ls1x_ac97_suspend, ls1x_ac97_resume)
+};
+
+static const struct of_device_id ls1x_ac97_match[] = {
+ { .compatible = "loongson,ls1b-ac97" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ls1x_ac97_match);
+
+static struct platform_driver ls1x_ac97_driver = {
+ .probe = ls1x_ac97_probe,
+ .remove = ls1x_ac97_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = ls1x_ac97_match,
+ .pm = &ls1x_ac97_pm_ops,
+ },
+};
+
+module_platform_driver(ls1x_ac97_driver);
+
+MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
+MODULE_DESCRIPTION("Loongson-1 AC97 Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index 965eaf4e9109..7910d5d9ac4f 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -23,28 +23,28 @@ struct loongson_card_data {
static int loongson_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct loongson_card_data *ls_card = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret, mclk;
- if (ls_card->mclk_fs) {
- mclk = ls_card->mclk_fs * params_rate(params);
- ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
- SND_SOC_CLOCK_OUT);
- if (ret < 0) {
- dev_err(codec_dai->dev, "cpu_dai clock not set\n");
- return ret;
- }
+ if (!ls_card->mclk_fs)
+ return 0;
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(codec_dai->dev, "codec_dai clock not set\n");
- return ret;
- }
+ mclk = ls_card->mclk_fs * params_rate(params);
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "cpu_dai clock not set\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "codec_dai clock not set\n");
+ return ret;
}
+
return 0;
}
@@ -68,57 +68,62 @@ static struct snd_soc_dai_link loongson_dai_links[] = {
},
};
-static int loongson_card_parse_acpi(struct loongson_card_data *data)
+static struct acpi_device *loongson_card_acpi_find_device(struct snd_soc_card *card,
+ const char *name)
{
- struct snd_soc_card *card = &data->snd_card;
struct fwnode_handle *fwnode = card->dev->fwnode;
struct fwnode_reference_args args;
+ int status;
+
+ memset(&args, 0, sizeof(args));
+ status = acpi_node_get_property_reference(fwnode, name, 0, &args);
+ if (status || !is_acpi_device_node(args.fwnode)) {
+ dev_err(card->dev, "No matching phy in ACPI table\n");
+ return NULL;
+ }
+
+ return to_acpi_device_node(args.fwnode);
+}
+
+static int loongson_card_parse_acpi(struct loongson_card_data *data)
+{
+ struct snd_soc_card *card = &data->snd_card;
const char *codec_dai_name;
struct acpi_device *adev;
struct device *phy_dev;
- int ret, i;
+ int i;
/* fixup platform name based on reference node */
- memset(&args, 0, sizeof(args));
- ret = acpi_node_get_property_reference(fwnode, "cpu", 0, &args);
- if (ACPI_FAILURE(ret) || !is_acpi_device_node(args.fwnode)) {
- dev_err(card->dev, "No matching phy in ACPI table\n");
- return ret;
- }
- adev = to_acpi_device_node(args.fwnode);
+ adev = loongson_card_acpi_find_device(card, "cpu");
+ if (!adev)
+ return -ENOENT;
+
phy_dev = acpi_get_first_physical_node(adev);
if (!phy_dev)
return -EPROBE_DEFER;
- for (i = 0; i < card->num_links; i++)
- loongson_dai_links[i].platforms->name = dev_name(phy_dev);
/* fixup codec name based on reference node */
- memset(&args, 0, sizeof(args));
- ret = acpi_node_get_property_reference(fwnode, "codec", 0, &args);
- if (ACPI_FAILURE(ret) || !is_acpi_device_node(args.fwnode)) {
- dev_err(card->dev, "No matching phy in ACPI table\n");
- return ret;
- }
- adev = to_acpi_device_node(args.fwnode);
+ adev = loongson_card_acpi_find_device(card, "codec");
+ if (!adev)
+ return -ENOENT;
snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev));
- for (i = 0; i < card->num_links; i++)
- loongson_dai_links[i].codecs->name = codec_name;
- device_property_read_string(card->dev, "codec-dai-name",
- &codec_dai_name);
- for (i = 0; i < card->num_links; i++)
+ device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+
+ for (i = 0; i < card->num_links; i++) {
+ loongson_dai_links[i].platforms->name = dev_name(phy_dev);
+ loongson_dai_links[i].codecs->name = codec_name;
loongson_dai_links[i].codecs->dai_name = codec_dai_name;
+ }
return 0;
}
static int loongson_card_parse_of(struct loongson_card_data *data)
{
- const char *cpu_dai_name, *codec_dai_name;
struct device_node *cpu, *codec;
struct snd_soc_card *card = &data->snd_card;
struct device *dev = card->dev;
- struct of_phandle_args args;
int ret, i;
cpu = of_get_child_by_name(dev->of_node, "cpu");
@@ -129,34 +134,25 @@ static int loongson_card_parse_of(struct loongson_card_data *data)
codec = of_get_child_by_name(dev->of_node, "codec");
if (!codec) {
dev_err(dev, "audio-codec property missing or invalid\n");
- ret = -EINVAL;
- goto err;
- }
-
- ret = of_parse_phandle_with_args(cpu, "sound-dai",
- "#sound-dai-cells", 0, &args);
- if (ret) {
- dev_err(dev, "codec node missing #sound-dai-cells\n");
- goto err;
- }
- for (i = 0; i < card->num_links; i++)
- loongson_dai_links[i].cpus->of_node = args.np;
-
- ret = of_parse_phandle_with_args(codec, "sound-dai",
- "#sound-dai-cells", 0, &args);
- if (ret) {
- dev_err(dev, "codec node missing #sound-dai-cells\n");
- goto err;
+ of_node_put(cpu);
+ return -EINVAL;
}
- for (i = 0; i < card->num_links; i++)
- loongson_dai_links[i].codecs->of_node = args.np;
- snd_soc_of_get_dai_name(cpu, &cpu_dai_name);
- snd_soc_of_get_dai_name(codec, &codec_dai_name);
for (i = 0; i < card->num_links; i++) {
- loongson_dai_links[i].cpus->dai_name = cpu_dai_name;
- loongson_dai_links[i].codecs->dai_name = codec_dai_name;
+ ret = snd_soc_of_get_dlc(cpu, NULL, loongson_dai_links[i].cpus, 0);
+ if (ret < 0) {
+ dev_err(dev, "getting cpu dlc error (%d)\n", ret);
+ goto err;
+ }
+ loongson_dai_links[i].platforms->of_node = loongson_dai_links[i].cpus->of_node;
+
+ ret = snd_soc_of_get_dlc(codec, NULL, loongson_dai_links[i].codecs, 0);
+ if (ret < 0) {
+ dev_err(dev, "getting codec dlc error (%d)\n", ret);
+ goto err;
+ }
}
+
of_node_put(cpu);
of_node_put(codec);
@@ -171,42 +167,36 @@ err:
static int loongson_asoc_card_probe(struct platform_device *pdev)
{
struct loongson_card_data *ls_priv;
+ struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int ret;
- ls_priv = devm_kzalloc(&pdev->dev, sizeof(*ls_priv), GFP_KERNEL);
+ ls_priv = devm_kzalloc(dev, sizeof(*ls_priv), GFP_KERNEL);
if (!ls_priv)
return -ENOMEM;
card = &ls_priv->snd_card;
- card->dev = &pdev->dev;
+ card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = loongson_dai_links;
card->num_links = ARRAY_SIZE(loongson_dai_links);
snd_soc_card_set_drvdata(card, ls_priv);
- ret = device_property_read_string(&pdev->dev, "model", &card->name);
- if (ret) {
- dev_err(&pdev->dev, "Error parsing card name: %d\n", ret);
- return ret;
- }
- ret = device_property_read_u32(&pdev->dev, "mclk-fs", &ls_priv->mclk_fs);
- if (ret) {
- dev_err(&pdev->dev, "Error parsing mclk-fs: %d\n", ret);
- return ret;
- }
+ ret = device_property_read_string(dev, "model", &card->name);
+ if (ret)
+ return dev_err_probe(dev, ret, "Error parsing card name\n");
- if (has_acpi_companion(&pdev->dev))
- ret = loongson_card_parse_acpi(ls_priv);
- else
- ret = loongson_card_parse_of(ls_priv);
- if (ret < 0)
- return ret;
+ ret = device_property_read_u32(dev, "mclk-fs", &ls_priv->mclk_fs);
+ if (ret)
+ return dev_err_probe(dev, ret, "Error parsing mclk-fs\n");
- ret = devm_snd_soc_register_card(&pdev->dev, card);
+ ret = has_acpi_companion(dev) ? loongson_card_parse_acpi(ls_priv)
+ : loongson_card_parse_of(ls_priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Error parsing acpi/of properties\n");
- return ret;
+ return devm_snd_soc_register_card(dev, card);
}
static const struct of_device_id loongson_asoc_dt_ids[] = {
@@ -220,7 +210,7 @@ static struct platform_driver loongson_audio_driver = {
.driver = {
.name = "loongson-asoc-card",
.pm = &snd_soc_pm_ops,
- .of_match_table = of_match_ptr(loongson_asoc_dt_ids),
+ .of_match_table = loongson_asoc_dt_ids,
},
};
module_platform_driver(loongson_audio_driver);
diff --git a/sound/soc/loongson/loongson_dma.c b/sound/soc/loongson/loongson_dma.c
index 65b6719e61c5..20e4a0641340 100644
--- a/sound/soc/loongson/loongson_dma.c
+++ b/sound/soc/loongson/loongson_dma.c
@@ -17,11 +17,11 @@
#include "loongson_i2s.h"
/* DMA dma_order Register */
-#define DMA_ORDER_STOP (1 << 4) /* DMA stop */
-#define DMA_ORDER_START (1 << 3) /* DMA start */
-#define DMA_ORDER_ASK_VALID (1 << 2) /* DMA ask valid flag */
-#define DMA_ORDER_AXI_UNCO (1 << 1) /* Uncache access */
-#define DMA_ORDER_ADDR_64 (1 << 0) /* 64bits address support */
+#define DMA_ORDER_STOP BIT(4) /* DMA stop */
+#define DMA_ORDER_START BIT(3) /* DMA start */
+#define DMA_ORDER_ASK_VALID BIT(2) /* DMA ask valid flag */
+#define DMA_ORDER_AXI_UNCO BIT(1) /* Uncache access */
+#define DMA_ORDER_ADDR_64 BIT(0) /* 64bits address support */
#define DMA_ORDER_ASK_MASK (~0x1fUL) /* Ask addr mask */
#define DMA_ORDER_CTRL_MASK (0x0fUL) /* Control mask */
@@ -95,7 +95,6 @@ static int loongson_pcm_trigger(struct snd_soc_component *component,
struct device *dev = substream->pcm->card->dev;
void __iomem *order_reg = prtd->dma_data->order_addr;
u64 val;
- int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -129,7 +128,7 @@ static int loongson_pcm_trigger(struct snd_soc_component *component,
return -EINVAL;
}
- return ret;
+ return 0;
}
static int loongson_pcm_hw_params(struct snd_soc_component *component,
@@ -226,11 +225,10 @@ static int loongson_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_card *card = substream->pcm->card;
struct loongson_runtime_data *prtd;
struct loongson_dma_data *dma_data;
- int ret;
/*
* For mysterious reasons (and despite what the manual says)
@@ -252,22 +250,19 @@ static int loongson_pcm_open(struct snd_soc_component *component,
prtd->dma_desc_arr = dma_alloc_coherent(card->dev, PAGE_SIZE,
&prtd->dma_desc_arr_phy,
GFP_KERNEL);
- if (!prtd->dma_desc_arr) {
- ret = -ENOMEM;
+ if (!prtd->dma_desc_arr)
goto desc_err;
- }
+
prtd->dma_desc_arr_size = PAGE_SIZE / sizeof(*prtd->dma_desc_arr);
prtd->dma_pos_desc = dma_alloc_coherent(card->dev,
sizeof(*prtd->dma_pos_desc),
&prtd->dma_pos_desc_phy,
GFP_KERNEL);
- if (!prtd->dma_pos_desc) {
- ret = -ENOMEM;
+ if (!prtd->dma_pos_desc)
goto pos_err;
- }
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
prtd->dma_data = dma_data;
substream->runtime->private_data = prtd;
@@ -279,7 +274,7 @@ pos_err:
desc_err:
kfree(prtd);
- return ret;
+ return -ENOMEM;
}
static int loongson_pcm_close(struct snd_soc_component *component,
@@ -321,7 +316,7 @@ static int loongson_pcm_new(struct snd_soc_component *component,
if (!substream)
continue;
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0),
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0),
substream);
ret = devm_request_irq(card->dev, dma_data->irq,
loongson_pcm_dma_irq,
diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c
index f73b6d6f16c2..e336656e13eb 100644
--- a/sound/soc/loongson/loongson_i2s.c
+++ b/sound/soc/loongson/loongson_i2s.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
#include <sound/soc.h>
@@ -21,34 +22,33 @@
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE)
+#define LOONGSON_I2S_TX_ENABLE (I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN)
+#define LOONGSON_I2S_RX_ENABLE (I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN)
+
+#define LOONGSON_I2S_DEF_DELAY 10
+#define LOONGSON_I2S_DEF_TIMEOUT 500000
+
static int loongson_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct loongson_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int mask;
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
- I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN,
- I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN);
- else
- regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
- I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN,
- I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN);
+ mask = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ LOONGSON_I2S_TX_ENABLE : LOONGSON_I2S_RX_ENABLE;
+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, mask, mask);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
- I2S_CTRL_TX_EN | I2S_CTRL_TX_DMA_EN, 0);
- else
- regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
- I2S_CTRL_RX_EN | I2S_CTRL_RX_DMA_EN, 0);
+ mask = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ LOONGSON_I2S_TX_ENABLE : LOONGSON_I2S_RX_ENABLE;
+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, mask, 0);
break;
default:
ret = -EINVAL;
@@ -89,7 +89,7 @@ static int loongson_i2s_hw_params(struct snd_pcm_substream *substream,
bclk_ratio = DIV_ROUND_CLOSEST(sysclk,
(bits * chans * fs * 2)) - 1;
mclk_ratio = clk_rate / sysclk;
- mclk_ratio_frac = DIV_ROUND_CLOSEST(((u64)clk_rate << 16),
+ mclk_ratio_frac = DIV_ROUND_CLOSEST_ULL(((u64)clk_rate << 16),
sysclk) - (mclk_ratio << 16);
regmap_read(i2s->regmap, LS_I2S_CFG, &val);
@@ -123,10 +123,40 @@ static int loongson_i2s_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}
+static int loongson_i2s_enable_mclk(struct loongson_i2s *i2s)
+{
+ u32 val;
+
+ if (i2s->rev_id == 0)
+ return 0;
+
+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
+ I2S_CTRL_MCLK_EN, I2S_CTRL_MCLK_EN);
+
+ return regmap_read_poll_timeout_atomic(i2s->regmap,
+ LS_I2S_CTRL, val,
+ val & I2S_CTRL_MCLK_READY,
+ LOONGSON_I2S_DEF_DELAY,
+ LOONGSON_I2S_DEF_TIMEOUT);
+}
+
+static int loongson_i2s_enable_bclk(struct loongson_i2s *i2s)
+{
+ u32 val;
+
+ if (i2s->rev_id == 0)
+ return 0;
+
+ return regmap_read_poll_timeout_atomic(i2s->regmap,
+ LS_I2S_CTRL, val,
+ val & I2S_CTRL_CLK_READY,
+ LOONGSON_I2S_DEF_DELAY,
+ LOONGSON_I2S_DEF_TIMEOUT);
+}
+
static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct loongson_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- u32 val;
int ret;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -148,54 +178,29 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* Enable master mode */
regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_MASTER,
I2S_CTRL_MASTER);
- if (i2s->rev_id == 1) {
- ret = regmap_read_poll_timeout_atomic(i2s->regmap,
- LS_I2S_CTRL, val,
- val & I2S_CTRL_CLK_READY,
- 10, 500000);
- if (ret < 0)
- dev_warn(dai->dev, "wait BCLK ready timeout\n");
- }
+ ret = loongson_i2s_enable_bclk(i2s);
+ if (ret < 0)
+ dev_warn(dai->dev, "wait BCLK ready timeout\n");
break;
case SND_SOC_DAIFMT_BC_FP:
/* Enable MCLK */
- if (i2s->rev_id == 1) {
- regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
- I2S_CTRL_MCLK_EN,
- I2S_CTRL_MCLK_EN);
- ret = regmap_read_poll_timeout_atomic(i2s->regmap,
- LS_I2S_CTRL, val,
- val & I2S_CTRL_MCLK_READY,
- 10, 500000);
- if (ret < 0)
- dev_warn(dai->dev, "wait MCLK ready timeout\n");
- }
+ ret = loongson_i2s_enable_mclk(i2s);
+ if (ret < 0)
+ dev_warn(dai->dev, "wait MCLK ready timeout\n");
break;
case SND_SOC_DAIFMT_BP_FP:
/* Enable MCLK */
- if (i2s->rev_id == 1) {
- regmap_update_bits(i2s->regmap, LS_I2S_CTRL,
- I2S_CTRL_MCLK_EN,
- I2S_CTRL_MCLK_EN);
- ret = regmap_read_poll_timeout_atomic(i2s->regmap,
- LS_I2S_CTRL, val,
- val & I2S_CTRL_MCLK_READY,
- 10, 500000);
- if (ret < 0)
- dev_warn(dai->dev, "wait MCLK ready timeout\n");
- }
+ ret = loongson_i2s_enable_mclk(i2s);
+ if (ret < 0)
+ dev_warn(dai->dev, "wait MCLK ready timeout\n");
/* Enable master mode */
regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_MASTER,
I2S_CTRL_MASTER);
- if (i2s->rev_id == 1) {
- ret = regmap_read_poll_timeout_atomic(i2s->regmap,
- LS_I2S_CTRL, val,
- val & I2S_CTRL_CLK_READY,
- 10, 500000);
- if (ret < 0)
- dev_warn(dai->dev, "wait BCLK ready timeout\n");
- }
+
+ ret = loongson_i2s_enable_bclk(i2s);
+ if (ret < 0)
+ dev_warn(dai->dev, "wait BCLK ready timeout\n");
break;
default:
return -EINVAL;
@@ -204,13 +209,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
- .trigger = loongson_i2s_trigger,
- .hw_params = loongson_i2s_hw_params,
- .set_sysclk = loongson_i2s_set_dai_sysclk,
- .set_fmt = loongson_i2s_set_fmt,
-};
-
static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
@@ -222,9 +220,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
+ .probe = loongson_i2s_dai_probe,
+ .trigger = loongson_i2s_trigger,
+ .hw_params = loongson_i2s_hw_params,
+ .set_sysclk = loongson_i2s_set_dai_sysclk,
+ .set_fmt = loongson_i2s_set_fmt,
+};
+
struct snd_soc_dai_driver loongson_i2s_dai = {
.name = "loongson-i2s",
- .probe = loongson_i2s_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
@@ -242,6 +247,7 @@ struct snd_soc_dai_driver loongson_i2s_dai = {
.ops = &loongson_i2s_dai_ops,
.symmetric_rate = 1,
};
+EXPORT_SYMBOL_GPL(loongson_i2s_dai);
static int i2s_suspend(struct device *dev)
{
@@ -255,15 +261,16 @@ static int i2s_suspend(struct device *dev)
static int i2s_resume(struct device *dev)
{
struct loongson_i2s *i2s = dev_get_drvdata(dev);
- int ret;
regcache_cache_only(i2s->regmap, false);
regcache_mark_dirty(i2s->regmap);
- ret = regcache_sync(i2s->regmap);
-
- return ret;
+ return regcache_sync(i2s->regmap);
}
const struct dev_pm_ops loongson_i2s_pm = {
SYSTEM_SLEEP_PM_OPS(i2s_suspend, i2s_resume)
};
+EXPORT_SYMBOL_GPL(loongson_i2s_pm);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Common functions for loongson I2S controller driver");
diff --git a/sound/soc/loongson/loongson_i2s.h b/sound/soc/loongson/loongson_i2s.h
index 52788f6a94ad..c8052a762c1b 100644
--- a/sound/soc/loongson/loongson_i2s.h
+++ b/sound/soc/loongson/loongson_i2s.h
@@ -27,25 +27,25 @@
#define LS_I2S_RX_ORDER 0x110 /* RX DMA Order */
/* Loongson I2S Control Register */
-#define I2S_CTRL_MCLK_READY (1 << 16) /* MCLK ready */
-#define I2S_CTRL_MASTER (1 << 15) /* Master mode */
-#define I2S_CTRL_MSB (1 << 14) /* MSB bit order */
-#define I2S_CTRL_RX_EN (1 << 13) /* RX enable */
-#define I2S_CTRL_TX_EN (1 << 12) /* TX enable */
-#define I2S_CTRL_RX_DMA_EN (1 << 11) /* DMA RX enable */
-#define I2S_CTRL_CLK_READY (1 << 8) /* BCLK ready */
-#define I2S_CTRL_TX_DMA_EN (1 << 7) /* DMA TX enable */
-#define I2S_CTRL_RESET (1 << 4) /* Controller soft reset */
-#define I2S_CTRL_MCLK_EN (1 << 3) /* Enable MCLK */
-#define I2S_CTRL_RX_INT_EN (1 << 1) /* RX interrupt enable */
-#define I2S_CTRL_TX_INT_EN (1 << 0) /* TX interrupt enable */
+#define I2S_CTRL_MCLK_READY BIT(16) /* MCLK ready */
+#define I2S_CTRL_MASTER BIT(15) /* Master mode */
+#define I2S_CTRL_MSB BIT(14) /* MSB bit order */
+#define I2S_CTRL_RX_EN BIT(13) /* RX enable */
+#define I2S_CTRL_TX_EN BIT(12) /* TX enable */
+#define I2S_CTRL_RX_DMA_EN BIT(11) /* DMA RX enable */
+#define I2S_CTRL_CLK_READY BIT(8) /* BCLK ready */
+#define I2S_CTRL_TX_DMA_EN BIT(7) /* DMA TX enable */
+#define I2S_CTRL_RESET BIT(4) /* Controller soft reset */
+#define I2S_CTRL_MCLK_EN BIT(3) /* Enable MCLK */
+#define I2S_CTRL_RX_INT_EN BIT(1) /* RX interrupt enable */
+#define I2S_CTRL_TX_INT_EN BIT(0) /* TX interrupt enable */
#define LS_I2S_DRVNAME "loongson-i2s"
struct loongson_dma_data {
dma_addr_t dev_addr; /* device physical address for DMA */
void __iomem *order_addr; /* DMA order register */
- u32 irq; /* DMA irq */
+ int irq; /* DMA irq */
};
struct loongson_i2s {
diff --git a/sound/soc/loongson/loongson_i2s_pci.c b/sound/soc/loongson/loongson_i2s_pci.c
index 6dcfb17d3276..1ea5501a97f8 100644
--- a/sound/soc/loongson/loongson_i2s_pci.c
+++ b/sound/soc/loongson/loongson_i2s_pci.c
@@ -16,6 +16,8 @@
#include "loongson_i2s.h"
#include "loongson_dma.h"
+#define DRIVER_NAME "loongson-i2s-pci"
+
static bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -75,76 +77,66 @@ static int loongson_i2s_pci_probe(struct pci_dev *pdev,
{
const struct fwnode_handle *fwnode = pdev->dev.fwnode;
struct loongson_dma_data *tx_data, *rx_data;
+ struct device *dev = &pdev->dev;
struct loongson_i2s *i2s;
int ret;
if (pcim_enable_device(pdev)) {
- dev_err(&pdev->dev, "pci_enable_device failed\n");
+ dev_err(dev, "pci_enable_device failed\n");
return -ENODEV;
}
- i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
return -ENOMEM;
i2s->rev_id = pdev->revision;
- i2s->dev = &pdev->dev;
+ i2s->dev = dev;
pci_set_drvdata(pdev, i2s);
- ret = pcim_iomap_regions(pdev, 1 << 0, dev_name(&pdev->dev));
- if (ret < 0) {
- dev_err(&pdev->dev, "iomap_regions failed\n");
- return ret;
+ i2s->reg_base = pcim_iomap_region(pdev, 0, DRIVER_NAME);
+ if (IS_ERR(i2s->reg_base)) {
+ dev_err(dev, "iomap_region failed\n");
+ return PTR_ERR(i2s->reg_base);
}
- i2s->reg_base = pcim_iomap_table(pdev)[0];
- i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->reg_base,
+
+ i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base,
&loongson_i2s_regmap_config);
- if (IS_ERR(i2s->regmap)) {
- dev_err(&pdev->dev, "regmap_init_mmio failed\n");
- return PTR_ERR(i2s->regmap);
- }
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(dev, PTR_ERR(i2s->regmap), "regmap_init_mmio failed\n");
tx_data = &i2s->tx_dma_data;
rx_data = &i2s->rx_dma_data;
- tx_data->dev_addr = (dma_addr_t)i2s->reg_base + LS_I2S_TX_DATA;
+ tx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_TX_DATA;
tx_data->order_addr = i2s->reg_base + LS_I2S_TX_ORDER;
- rx_data->dev_addr = (dma_addr_t)i2s->reg_base + LS_I2S_RX_DATA;
+ rx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_RX_DATA;
rx_data->order_addr = i2s->reg_base + LS_I2S_RX_ORDER;
tx_data->irq = fwnode_irq_get_byname(fwnode, "tx");
- if (tx_data->irq < 0) {
- dev_err(&pdev->dev, "dma tx irq invalid\n");
- return tx_data->irq;
- }
+ if (tx_data->irq < 0)
+ return dev_err_probe(dev, tx_data->irq, "dma tx irq invalid\n");
rx_data->irq = fwnode_irq_get_byname(fwnode, "rx");
- if (rx_data->irq < 0) {
- dev_err(&pdev->dev, "dma rx irq invalid\n");
- return rx_data->irq;
- }
+ if (rx_data->irq < 0)
+ return dev_err_probe(dev, rx_data->irq, "dma rx irq invalid\n");
- device_property_read_u32(&pdev->dev, "clock-frequency", &i2s->clk_rate);
- if (!i2s->clk_rate) {
- dev_err(&pdev->dev, "clock-frequency property invalid\n");
- return -EINVAL;
- }
+ ret = device_property_read_u32(dev, "clock-frequency", &i2s->clk_rate);
+ if (ret)
+ return dev_err_probe(dev, ret, "clock-frequency property invalid\n");
- dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (i2s->rev_id == 1) {
regmap_write(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET);
udelay(200);
}
- ret = devm_snd_soc_register_component(&pdev->dev,
- &loongson_i2s_component,
+ ret = devm_snd_soc_register_component(dev, &loongson_i2s_component,
&loongson_i2s_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "register DAI failed %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "register DAI failed\n");
return 0;
}
@@ -156,11 +148,10 @@ static const struct pci_device_id loongson_i2s_ids[] = {
MODULE_DEVICE_TABLE(pci, loongson_i2s_ids);
static struct pci_driver loongson_i2s_driver = {
- .name = "loongson-i2s-pci",
+ .name = DRIVER_NAME,
.id_table = loongson_i2s_ids,
.probe = loongson_i2s_pci_probe,
.driver = {
- .owner = THIS_MODULE,
.pm = pm_sleep_ptr(&loongson_i2s_pm),
},
};
diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c
new file mode 100644
index 000000000000..fa2e450ff618
--- /dev/null
+++ b/sound/soc/loongson/loongson_i2s_plat.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Loongson I2S controller master mode dirver(platform device)
+//
+// Copyright (C) 2023-2024 Loongson Technology Corporation Limited
+//
+// Author: Yingkun Meng <mengyingkun@loongson.cn>
+// Binbin Zhou <zhoubinbin@loongson.cn>
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "loongson_i2s.h"
+
+#define LOONGSON_I2S_RX_DMA_OFFSET 21
+#define LOONGSON_I2S_TX_DMA_OFFSET 18
+
+#define LOONGSON_DMA0_CONF 0x0
+#define LOONGSON_DMA1_CONF 0x1
+#define LOONGSON_DMA2_CONF 0x2
+#define LOONGSON_DMA3_CONF 0x3
+#define LOONGSON_DMA4_CONF 0x4
+
+/* periods_max = PAGE_SIZE / sizeof(struct ls_dma_chan_reg) */
+static const struct snd_pcm_hardware loongson_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_PAUSE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .period_bytes_min = 128,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 1,
+ .periods_max = 64,
+ .buffer_bytes_max = 1024 * 1024,
+};
+
+static const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
+ .pcm_hardware = &loongson_pcm_hardware,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .prealloc_buffer_size = 128 * 1024,
+};
+
+static int loongson_pcm_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (substream->pcm->device & 1) {
+ runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
+ runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
+ }
+
+ if (substream->pcm->device & 2)
+ runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID);
+ /*
+ * For mysterious reasons (and despite what the manual says)
+ * playback samples are lost if the DMA count is not a multiple
+ * of the DMA burst size. Let's add a rule to enforce that.
+ */
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
+ snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
+ snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver loongson_i2s_component_driver = {
+ .name = LS_I2S_DRVNAME,
+ .open = loongson_pcm_open,
+};
+
+static const struct regmap_config loongson_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x14,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int loongson_i2s_apbdma_config(struct platform_device *pdev)
+{
+ int val;
+ void __iomem *regs;
+
+ regs = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ val = readl(regs);
+ val |= LOONGSON_DMA2_CONF << LOONGSON_I2S_TX_DMA_OFFSET;
+ val |= LOONGSON_DMA3_CONF << LOONGSON_I2S_RX_DMA_OFFSET;
+ writel(val, regs);
+
+ return 0;
+}
+
+static int loongson_i2s_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct loongson_i2s *i2s;
+ struct resource *res;
+ struct clk *i2s_clk;
+ int ret;
+
+ i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+ if (!i2s)
+ return -ENOMEM;
+
+ ret = loongson_i2s_apbdma_config(pdev);
+ if (ret)
+ return ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2s->reg_base))
+ return dev_err_probe(dev, PTR_ERR(i2s->reg_base),
+ "devm_ioremap_resource failed\n");
+
+ i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base,
+ &loongson_i2s_regmap_config);
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(dev, PTR_ERR(i2s->regmap),
+ "devm_regmap_init_mmio failed\n");
+
+ i2s->playback_dma_data.addr = res->start + LS_I2S_TX_DATA;
+ i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->playback_dma_data.maxburst = 4;
+
+ i2s->capture_dma_data.addr = res->start + LS_I2S_RX_DATA;
+ i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->capture_dma_data.maxburst = 4;
+
+ i2s_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(i2s_clk))
+ return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n");
+ i2s->clk_rate = clk_get_rate(i2s_clk);
+
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ dev_set_name(dev, LS_I2S_DRVNAME);
+ dev_set_drvdata(dev, i2s);
+
+ ret = devm_snd_soc_register_component(dev, &loongson_i2s_component_driver,
+ &loongson_i2s_dai, 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register DAI\n");
+
+ return devm_snd_dmaengine_pcm_register(dev, &loongson_dmaengine_pcm_config,
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+
+static const struct of_device_id loongson_i2s_ids[] = {
+ { .compatible = "loongson,ls2k1000-i2s" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, loongson_i2s_ids);
+
+static struct platform_driver loongson_i2s_driver = {
+ .probe = loongson_i2s_plat_probe,
+ .driver = {
+ .name = "loongson-i2s-plat",
+ .pm = pm_sleep_ptr(&loongson_i2s_pm),
+ .of_match_table = loongson_i2s_ids,
+ },
+};
+module_platform_driver(loongson_i2s_driver);
+
+MODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 90db67e0ce4f..3a1e1fa3fe5c 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "Mediatek"
+
config SND_SOC_MEDIATEK
tristate
select REGMAP_MMIO
@@ -54,6 +56,26 @@ config SND_SOC_MT6797_MT6351
Select Y if you have such device.
If unsure select "N".
+config SND_SOC_MT7986
+ tristate "ASoC support for Mediatek MT7986 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC platform driver support for MediaTek MT7986 chip
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT7986_WM8960
+ tristate "ASoc Audio driver for MT7986 with WM8960 codec"
+ depends on SND_SOC_MT7986 && I2C
+ select SND_SOC_WM8960
+ help
+ This adds support for ASoC machine driver for MediaTek MT7986
+ boards with the WM8960 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
config SND_SOC_MT8173
tristate "ASoC support for Mediatek MT8173 chip"
depends on ARCH_MEDIATEK
@@ -165,37 +187,22 @@ config SND_SOC_MT8186
Select Y if you have such device.
If unsure select "N".
-config SND_SOC_MT8186_MT6366_DA7219_MAX98357
- tristate "ASoC Audio driver for MT8186 with DA7219 MAX98357A codec"
+config SND_SOC_MT8186_MT6366
+ tristate "ASoC Audio driver for MT8186 with MT6366 and I2S codecs"
depends on I2C && GPIOLIB
depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
- select SND_SOC_MT6358
- select SND_SOC_MAX98357A
select SND_SOC_DA7219
- select SND_SOC_BT_SCO
- select SND_SOC_DMIC
- select SND_SOC_HDMI_CODEC
- help
- This adds ASoC driver for Mediatek MT8186 boards
- with the MT6366(MT6358) DA7219 MAX98357A codecs.
- Select Y if you have such device.
- If unsure select "N".
-
-config SND_SOC_MT8186_MT6366_RT1019_RT5682S
- tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S MAX98357A/MAX98360 codec"
- depends on I2C && GPIOLIB
- depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
- select SND_SOC_MAX98357A
select SND_SOC_MT6358
select SND_SOC_MAX98357A
select SND_SOC_RT1015P
select SND_SOC_RT5682S
+ select SND_SOC_RT5645
select SND_SOC_BT_SCO
select SND_SOC_DMIC
select SND_SOC_HDMI_CODEC
help
- This adds ASoC driver for Mediatek MT8186 boards
- with the MT6366(MT6358) RT1019 RT5682S codecs.
+ This adds the ASoC machine driver for Mediatek MT8186 boards
+ with the MT6366(MT6358) and other I2S audio codecs.
Select Y if you have such device.
If unsure select "N".
@@ -223,6 +230,7 @@ config SND_SOC_MT8188
config SND_SOC_MT8188_MT6359
tristate "ASoC Audio driver for MT8188 with MT6359 and I2S codecs"
depends on SND_SOC_MT8188 && MTK_PMIC_WRAP
+ depends on SND_SOC_MT6359_ACCDET || !SND_SOC_MT6359_ACCDET
depends on I2C
select SND_SOC_MT6359
select SND_SOC_HDMI_CODEC
@@ -230,12 +238,45 @@ config SND_SOC_MT8188_MT6359
select SND_SOC_MAX98390
select SND_SOC_NAU8315
select SND_SOC_NAU8825
+ select SND_SOC_RT5682S
+ select SND_SOC_ES8326
help
This adds support for ASoC machine driver for MediaTek MT8188
boards with the MT6359 and other I2S audio codecs.
Select Y if you have such device.
If unsure select "N".
+config SND_SOC_MT8189
+ tristate "ASoC support for Mediatek MT8189 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC driver for Mediatek MT8189 boards
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8189_NAU8825
+ tristate "ASoc Audio driver for MT8189 with NAU8825 and I2S codec"
+ depends on SND_SOC_MT8189
+ depends on I2C
+ select SND_SOC_DMIC
+ select SND_SOC_HDMI_CODEC
+ select SND_SOC_NAU8825
+ select SND_SOC_RT5645
+ select SND_SOC_RT9123P
+ select SND_SOC_RT1015P
+ select SND_SOC_RT5682S
+ select SND_SOC_RT5682_I2C
+ select SND_SOC_CS35L41_I2C
+ select SND_SOC_AW88081
+ select SND_SOC_ES8326
+ help
+ This adds support for ASoC machine driver for MediaTek MT8189
+ boards with the NAU8828 and other I2S audio codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
config SND_SOC_MT8192
tristate "ASoC support for Mediatek MT8192 chip"
depends on ARCH_MEDIATEK
@@ -291,3 +332,25 @@ config SND_SOC_MT8195_MT6359
boards with the MT6359 and other I2S audio codecs.
Select Y if you have such device.
If unsure select "N".
+
+config SND_SOC_MT8365
+ tristate "ASoC support for MediaTek MT8365 chip"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC platform driver support for MediaTek MT8365 chip
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT8365_MT6357
+ tristate "ASoC Audio driver for MT8365 with MT6357 codec"
+ depends on SND_SOC_MT8365 && MTK_PMIC_WRAP
+ select SND_SOC_MT6357
+ help
+ This adds support for ASoC machine driver for MediaTek MT8365
+ boards with the MT6357 PMIC codec.
+ Select Y if you have such device.
+ If unsure select "N".
+
+endmenu
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 3de38cfc69e5..7cd67bce92e9 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -2,9 +2,12 @@
obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
+obj-$(CONFIG_SND_SOC_MT7986) += mt7986/
obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
obj-$(CONFIG_SND_SOC_MT8188) += mt8188/
obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
+obj-$(CONFIG_SND_SOC_MT8365) += mt8365/
+obj-$(CONFIG_SND_SOC_MT8189) += mt8189/
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile
index 42e636c10c1e..c90d276cf4ed 100644
--- a/sound/soc/mediatek/common/Makefile
+++ b/sound/soc/mediatek/common/Makefile
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o mtk-soundcard-driver.o
+snd-soc-mtk-common-y := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o mtk-soundcard-driver.o
+snd-soc-mtk-common-y += mtk-dai-adda-common.o
+
obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index 395be97f13ae..3809068f5620 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -37,10 +37,10 @@ static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
- int memif_num = asoc_rtd_to_cpu(rtd, 0)->id;
+ int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
int ret;
@@ -98,9 +98,9 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);
void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];
int irq_id;
irq_id = memif->irq_usage;
@@ -120,9 +120,9 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
int ret;
unsigned int channels = params_channels(params);
@@ -196,10 +196,10 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
const struct mtk_base_irq_data *irq_data = irqs->irq_data;
@@ -263,9 +263,9 @@ EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);
int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int pbuf_size;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -500,30 +500,10 @@ 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)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
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-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 01501d5747a7..938dd3d46b00 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -48,6 +48,7 @@ EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mtk_base_afe_dai *dai;
@@ -58,19 +59,19 @@ int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
dai->num_controls);
if (dai->dapm_widgets)
- snd_soc_dapm_new_controls(&component->dapm,
+ snd_soc_dapm_new_controls(dapm,
dai->dapm_widgets,
dai->num_dapm_widgets);
}
/* add routes after all widgets are added */
list_for_each_entry(dai, &afe->sub_dais, list) {
if (dai->dapm_routes)
- snd_soc_dapm_add_routes(&component->dapm,
+ snd_soc_dapm_add_routes(dapm,
dai->dapm_routes,
dai->num_dapm_routes);
}
- snd_soc_dapm_new_widgets(component->dapm.card);
+ snd_soc_dapm_new_widgets(component->card);
return 0;
@@ -80,9 +81,9 @@ EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];
const struct mtk_base_memif_data *memif_data = memif->data;
struct regmap *regmap = afe->regmap;
struct device *dev = afe->dev;
@@ -120,16 +121,36 @@ int mtk_afe_pcm_new(struct snd_soc_component *component,
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
size = afe->mtk_afe_hardware->buffer_bytes_max;
- snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
- afe->dev, size, size);
+ snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev,
+ afe->preallocate_buffers ? size : 0,
+ size);
+
return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
+static int mtk_afe_component_probe(struct snd_soc_component *component)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ snd_soc_component_init_regmap(component, afe->regmap);
+
+ /* If the list was never initialized there are no sub-DAIs */
+ if (afe->sub_dais.next && afe->sub_dais.prev) {
+ ret = mtk_afe_add_sub_dai_control(component);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
.name = AFE_PCM_NAME,
.pointer = mtk_afe_pcm_pointer,
.pcm_construct = mtk_afe_pcm_new,
+ .probe = mtk_afe_component_probe,
};
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index f51578b6c50a..a406f2e3e7a8 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -117,6 +117,7 @@ struct mtk_base_afe {
struct mtk_base_afe_irq *irqs;
int irqs_size;
int memif_32bit_supported;
+ bool preallocate_buffers;
struct list_head sub_dais;
struct snd_soc_dai_driver *dai_drivers;
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
index 1ba0633e542f..5e7e85b4c98a 100644
--- a/sound/soc/mediatek/common/mtk-btcvsd.c
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -696,11 +696,10 @@ static int wait_for_bt_irq(struct mtk_btcvsd_snd *bt,
}
static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt,
- char __user *buf,
+ struct iov_iter *buf,
size_t count)
{
ssize_t read_size = 0, read_count = 0, cur_read_idx, cont;
- unsigned int cur_buf_ofs = 0;
unsigned long avail;
unsigned long flags;
unsigned int packet_size = bt->rx->packet_size;
@@ -743,10 +742,9 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt,
if (read_size > cont)
read_size = cont;
- if (copy_to_user(buf + cur_buf_ofs,
- bt->rx_packet_buf + cur_read_idx,
- read_size)) {
- dev_warn(bt->dev, "%s(), copy_to_user fail\n",
+ if (copy_to_iter(bt->rx_packet_buf + cur_read_idx,
+ read_size, buf) != read_size) {
+ dev_warn(bt->dev, "%s(), copy_to_iter fail\n",
__func__);
return -EFAULT;
}
@@ -756,7 +754,6 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt,
spin_unlock_irqrestore(&bt->rx_lock, flags);
read_count += read_size;
- cur_buf_ofs += read_size;
count -= read_size;
}
@@ -777,11 +774,10 @@ static ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt,
}
static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt,
- char __user *buf,
+ struct iov_iter *buf,
size_t count)
{
int written_size = count, avail, cur_write_idx, write_size, cont;
- unsigned int cur_buf_ofs = 0;
unsigned long flags;
unsigned int packet_size = bt->tx->packet_size;
@@ -835,11 +831,9 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt,
if (write_size > cont)
write_size = cont;
- if (copy_from_user(bt->tx_packet_buf +
- cur_write_idx,
- buf + cur_buf_ofs,
- write_size)) {
- dev_warn(bt->dev, "%s(), copy_from_user fail\n",
+ if (copy_from_iter(bt->tx_packet_buf + cur_write_idx,
+ write_size, buf) != write_size) {
+ dev_warn(bt->dev, "%s(), copy_from_iter fail\n",
__func__);
return -EFAULT;
}
@@ -847,7 +841,6 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt,
spin_lock_irqsave(&bt->tx_lock, flags);
bt->tx->packet_w += write_size / packet_size;
spin_unlock_irqrestore(&bt->tx_lock, flags);
- cur_buf_ofs += write_size;
count -= write_size;
}
@@ -1033,7 +1026,7 @@ static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer(
static int mtk_pcm_btcvsd_copy(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
int channel, unsigned long pos,
- void __user *buf, unsigned long count)
+ struct iov_iter *buf, unsigned long count)
{
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component);
@@ -1053,7 +1046,7 @@ static const struct soc_enum btcvsd_enum[] = {
static int btcvsd_band_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
ucontrol->value.integer.value[0] = bt->band;
@@ -1063,7 +1056,7 @@ static int btcvsd_band_get(struct snd_kcontrol *kcontrol,
static int btcvsd_band_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -1078,7 +1071,7 @@ static int btcvsd_band_set(struct snd_kcontrol *kcontrol,
static int btcvsd_loopback_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
bool lpbk_en = bt->tx->state == BT_SCO_STATE_LOOPBACK;
@@ -1089,7 +1082,7 @@ static int btcvsd_loopback_get(struct snd_kcontrol *kcontrol,
static int btcvsd_loopback_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
if (ucontrol->value.integer.value[0]) {
@@ -1105,7 +1098,7 @@ static int btcvsd_loopback_set(struct snd_kcontrol *kcontrol,
static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
if (!bt->tx) {
@@ -1120,7 +1113,7 @@ static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol,
static int btcvsd_tx_mute_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
if (!bt->tx)
@@ -1133,7 +1126,7 @@ static int btcvsd_tx_mute_set(struct snd_kcontrol *kcontrol,
static int btcvsd_rx_irq_received_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
if (!bt->rx)
@@ -1146,7 +1139,7 @@ static int btcvsd_rx_irq_received_get(struct snd_kcontrol *kcontrol,
static int btcvsd_rx_timeout_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
if (!bt->rx)
@@ -1160,7 +1153,7 @@ static int btcvsd_rx_timeout_get(struct snd_kcontrol *kcontrol,
static int btcvsd_rx_timestamp_get(struct snd_kcontrol *kcontrol,
unsigned int __user *data, unsigned int size)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
int ret = 0;
struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_rx;
@@ -1187,7 +1180,7 @@ static int btcvsd_rx_timestamp_get(struct snd_kcontrol *kcontrol,
static int btcvsd_tx_irq_received_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
if (!bt->tx)
@@ -1200,7 +1193,7 @@ static int btcvsd_tx_irq_received_get(struct snd_kcontrol *kcontrol,
static int btcvsd_tx_timeout_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
ucontrol->value.integer.value[0] = bt->tx->timeout;
@@ -1210,7 +1203,7 @@ static int btcvsd_tx_timeout_get(struct snd_kcontrol *kcontrol,
static int btcvsd_tx_timestamp_get(struct snd_kcontrol *kcontrol,
unsigned int __user *data, unsigned int size)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt);
int ret = 0;
struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_tx;
@@ -1274,7 +1267,7 @@ static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = {
.prepare = mtk_pcm_btcvsd_prepare,
.trigger = mtk_pcm_btcvsd_trigger,
.pointer = mtk_pcm_btcvsd_pointer,
- .copy_user = mtk_pcm_btcvsd_copy,
+ .copy = mtk_pcm_btcvsd_copy,
};
static int mtk_btcvsd_snd_probe(struct platform_device *pdev)
@@ -1407,7 +1400,7 @@ static struct platform_driver mtk_btcvsd_snd_driver = {
.of_match_table = mtk_btcvsd_snd_dt_match,
},
.probe = mtk_btcvsd_snd_probe,
- .remove_new = mtk_btcvsd_snd_remove,
+ .remove = mtk_btcvsd_snd_remove,
};
module_platform_driver(mtk_btcvsd_snd_driver);
diff --git a/sound/soc/mediatek/common/mtk-dai-adda-common.c b/sound/soc/mediatek/common/mtk-dai-adda-common.c
new file mode 100644
index 000000000000..4dc1412489d6
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-dai-adda-common.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Common
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2024 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+
+#include "mtk-base-afe.h"
+#include "mtk-dai-adda-common.h"
+
+unsigned int mtk_adda_dl_rate_transform(struct mtk_base_afe *afe, u32 rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_adda_dl_rate_transform);
+
+unsigned int mtk_adda_ul_rate_transform(struct mtk_base_afe *afe, u32 rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_adda_ul_rate_transform);
diff --git a/sound/soc/mediatek/common/mtk-dai-adda-common.h b/sound/soc/mediatek/common/mtk-dai-adda-common.h
new file mode 100644
index 000000000000..208b0dd89f57
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-dai-adda-common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2024 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#ifndef _MTK_DAI_ADDA_COMMON_H_
+#define _MTK_DAI_ADDA_COMMON_H_
+
+struct mtk_base_afe;
+
+enum adda_input_mode_rate {
+ MTK_AFE_ADDA_DL_RATE_8K = 0,
+ MTK_AFE_ADDA_DL_RATE_11K = 1,
+ MTK_AFE_ADDA_DL_RATE_12K = 2,
+ MTK_AFE_ADDA_DL_RATE_16K = 3,
+ MTK_AFE_ADDA_DL_RATE_22K = 4,
+ MTK_AFE_ADDA_DL_RATE_24K = 5,
+ MTK_AFE_ADDA_DL_RATE_32K = 6,
+ MTK_AFE_ADDA_DL_RATE_44K = 7,
+ MTK_AFE_ADDA_DL_RATE_48K = 8,
+ MTK_AFE_ADDA_DL_RATE_96K = 9,
+ MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum adda_voice_mode_rate {
+ MTK_AFE_ADDA_UL_RATE_8K = 0,
+ MTK_AFE_ADDA_UL_RATE_16K = 1,
+ MTK_AFE_ADDA_UL_RATE_32K = 2,
+ MTK_AFE_ADDA_UL_RATE_48K = 3,
+ MTK_AFE_ADDA_UL_RATE_96K = 4,
+ MTK_AFE_ADDA_UL_RATE_192K = 5,
+ MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+enum adda_rxif_delay_data {
+ DELAY_DATA_MISO1 = 0,
+ DELAY_DATA_MISO0 = 1,
+ DELAY_DATA_MISO2 = 1,
+};
+
+unsigned int mtk_adda_dl_rate_transform(struct mtk_base_afe *afe, u32 rate);
+unsigned int mtk_adda_ul_rate_transform(struct mtk_base_afe *afe, u32 rate);
+#endif
diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
index 6fef16306f74..fd10616a08a0 100644
--- a/sound/soc/mediatek/common/mtk-dsp-sof-common.c
+++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
@@ -15,7 +15,7 @@ int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_card *card = rtd->card;
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
- struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+ const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
int i, j, ret = 0;
for (i = 0; i < sof_priv->num_streams; i++) {
@@ -24,7 +24,7 @@ int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai_link *sof_dai_link = NULL;
const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
- if (strcmp(rtd->dai_link->name, conn->normal_link))
+ if (conn->normal_link && strcmp(rtd->dai_link->name, conn->normal_link))
continue;
for_each_card_rtds(card, runtime) {
@@ -54,6 +54,7 @@ int mtk_sof_card_probe(struct snd_soc_card *card)
{
int i;
struct snd_soc_dai_link *dai_link;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
/* Set stream_name to help sof bind widgets */
for_each_card_prelinks(card, i, dai_link) {
@@ -61,17 +62,91 @@ int mtk_sof_card_probe(struct snd_soc_card *card)
dai_link->stream_name = dai_link->name;
}
+ INIT_LIST_HEAD(&soc_card_data->sof_dai_link_list);
+
return 0;
}
EXPORT_SYMBOL_GPL(mtk_sof_card_probe);
+static struct snd_soc_pcm_runtime *mtk_sof_find_tplg_be(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+ struct snd_soc_pcm_runtime *fe;
+ struct snd_soc_pcm_runtime *be;
+ struct snd_soc_dpcm *dpcm;
+ int i, stream;
+
+ for_each_pcm_streams(stream) {
+ fe = NULL;
+ for_each_dpcm_fe(rtd, stream, dpcm) {
+ fe = dpcm->fe;
+ if (fe)
+ break;
+ }
+
+ if (!fe)
+ continue;
+
+ for_each_dpcm_be(fe, stream, dpcm) {
+ be = dpcm->be;
+ if (be == rtd)
+ continue;
+
+ for (i = 0; i < sof_priv->num_streams; i++) {
+ const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
+
+ if (!strcmp(be->dai_link->name, conn->sof_link))
+ return be;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* fixup the BE DAI link to match any values from topology */
+static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+ struct snd_soc_pcm_runtime *sof_be;
+ struct mtk_dai_link *dai_link;
+ int ret = 0;
+
+ sof_be = mtk_sof_find_tplg_be(rtd);
+ if (sof_be) {
+ if (sof_priv->sof_dai_link_fixup)
+ ret = sof_priv->sof_dai_link_fixup(rtd, params);
+ else if (sof_be->dai_link->be_hw_params_fixup)
+ ret = sof_be->dai_link->be_hw_params_fixup(sof_be, params);
+ } else {
+ list_for_each_entry(dai_link, &soc_card_data->sof_dai_link_list, list) {
+ if (strcmp(dai_link->name, rtd->dai_link->name) == 0) {
+ if (dai_link->be_hw_params_fixup)
+ ret = dai_link->be_hw_params_fixup(rtd, params);
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
int mtk_sof_card_late_probe(struct snd_soc_card *card)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *sof_comp = NULL;
struct mtk_soc_card_data *soc_card_data =
snd_soc_card_get_drvdata(card);
- struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+ const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+ struct snd_soc_dai_link *dai_link;
+ struct mtk_dai_link *mtk_dai_link;
int i;
/* 1. find sof component */
@@ -86,25 +161,37 @@ int mtk_sof_card_late_probe(struct snd_soc_card *card)
return 0;
}
- /* 2. add route path and fixup callback */
+ /* 2. overwrite all BE fixups, and backup the existing fixup */
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->be_hw_params_fixup) {
+ mtk_dai_link = devm_kzalloc(card->dev,
+ sizeof(*mtk_dai_link),
+ GFP_KERNEL);
+ if (!mtk_dai_link)
+ return -ENOMEM;
+
+ mtk_dai_link->be_hw_params_fixup = dai_link->be_hw_params_fixup;
+ mtk_dai_link->name = dai_link->name;
+
+ list_add(&mtk_dai_link->list, &soc_card_data->sof_dai_link_list);
+ }
+
+ if (dai_link->no_pcm)
+ dai_link->be_hw_params_fixup = mtk_sof_check_tplg_be_dai_link_fixup;
+ }
+
+ /* 3. add route path and SOF_BE fixup callback */
for (i = 0; i < sof_priv->num_streams; i++) {
const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
struct snd_soc_pcm_runtime *sof_rtd = NULL;
- struct snd_soc_pcm_runtime *normal_rtd = NULL;
for_each_card_rtds(card, rtd) {
if (!strcmp(rtd->dai_link->name, conn->sof_link)) {
sof_rtd = rtd;
- continue;
- }
- if (!strcmp(rtd->dai_link->name, conn->normal_link)) {
- normal_rtd = rtd;
- continue;
- }
- if (normal_rtd && sof_rtd)
break;
+ }
}
- if (normal_rtd && sof_rtd) {
+ if (sof_rtd) {
int j;
struct snd_soc_dai *cpu_dai;
@@ -118,26 +205,22 @@ int mtk_sof_card_late_probe(struct snd_soc_card *card)
snd_soc_dapm_widget_for_each_sink_path(widget, p) {
route.source = conn->sof_dma;
route.sink = p->sink->name;
- snd_soc_dapm_add_routes(&card->dapm, &route, 1);
+ snd_soc_dapm_add_routes(dapm, &route, 1);
}
} else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && widget) {
snd_soc_dapm_widget_for_each_source_path(widget, p) {
route.source = p->source->name;
route.sink = conn->sof_dma;
- snd_soc_dapm_add_routes(&card->dapm, &route, 1);
+ snd_soc_dapm_add_routes(dapm, &route, 1);
}
} else {
dev_err(cpu_dai->dev, "stream dir and widget not pair\n");
}
}
+ /* overwrite SOF BE fixup */
sof_rtd->dai_link->be_hw_params_fixup =
sof_comp->driver->be_hw_params_fixup;
- if (sof_priv->sof_dai_link_fixup)
- normal_rtd->dai_link->be_hw_params_fixup =
- sof_priv->sof_dai_link_fixup;
- else
- normal_rtd->dai_link->be_hw_params_fixup = mtk_sof_dai_link_fixup;
}
}
diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.h b/sound/soc/mediatek/common/mtk-dsp-sof-common.h
index dd38c4a93574..8784ee471132 100644
--- a/sound/soc/mediatek/common/mtk-dsp-sof-common.h
+++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.h
@@ -18,6 +18,13 @@ struct sof_conn_stream {
int stream_dir;
};
+struct mtk_dai_link {
+ const char *name;
+ int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+ struct list_head list;
+};
+
struct mtk_sof_priv {
const struct sof_conn_stream *conn_streams;
int num_streams;
diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h
index eeda79370049..a1d2794ac1f7 100644
--- a/sound/soc/mediatek/common/mtk-soc-card.h
+++ b/sound/soc/mediatek/common/mtk-soc-card.h
@@ -9,9 +9,15 @@
#ifndef _MTK_SOC_CARD_H_
#define _MTK_SOC_CARD_H_
+struct mtk_platform_card_data;
+struct mtk_sof_priv;
+
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;
- void *sof_priv;
};
#endif
diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c
index a58e1e3674de..a2a30a87a359 100644
--- a/sound/soc/mediatek/common/mtk-soundcard-driver.c
+++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c
@@ -8,8 +8,11 @@
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <sound/soc.h>
+#include "mtk-dsp-sof-common.h"
+#include "mtk-soc-card.h"
#include "mtk-soundcard-driver.h"
static int set_card_codec_info(struct snd_soc_card *card,
@@ -22,7 +25,11 @@ static int set_card_codec_info(struct snd_soc_card *card,
codec_node = of_get_child_by_name(sub_node, "codec");
if (!codec_node) {
- dev_dbg(dev, "%s no specified codec\n", dai_link->name);
+ dev_dbg(dev, "%s no specified codec: setting dummy.\n", dai_link->name);
+
+ dai_link->codecs = &snd_soc_dummy_dlc;
+ dai_link->num_codecs = 1;
+ dai_link->dynamic = 1;
return 0;
}
@@ -82,40 +89,31 @@ static int set_dailink_daifmt(struct snd_soc_card *card,
int parse_dai_link_info(struct snd_soc_card *card)
{
struct device *dev = card->dev;
- struct device_node *sub_node;
struct snd_soc_dai_link *dai_link;
const char *dai_link_name;
int ret, i;
/* Loop over all the dai link sub nodes */
- for_each_available_child_of_node(dev->of_node, sub_node) {
+ for_each_available_child_of_node_scoped(dev->of_node, sub_node) {
if (of_property_read_string(sub_node, "link-name",
- &dai_link_name)) {
- of_node_put(sub_node);
+ &dai_link_name))
return -EINVAL;
- }
for_each_card_prelinks(card, i, dai_link) {
if (!strcmp(dai_link_name, dai_link->name))
break;
}
- if (i >= card->num_links) {
- of_node_put(sub_node);
+ if (i >= card->num_links)
return -EINVAL;
- }
ret = set_card_codec_info(card, sub_node, dai_link);
- if (ret < 0) {
- of_node_put(sub_node);
+ if (ret < 0)
return ret;
- }
ret = set_dailink_daifmt(card, sub_node, dai_link);
- if (ret < 0) {
- of_node_put(sub_node);
+ if (ret < 0)
return ret;
- }
}
return 0;
@@ -132,3 +130,220 @@ void clean_card_reference(struct snd_soc_card *card)
snd_soc_of_put_dai_link_codecs(dai_link);
}
EXPORT_SYMBOL_GPL(clean_card_reference);
+
+int mtk_soundcard_startup(struct snd_pcm_substream *substream,
+ enum mtk_pcm_constraint_type ctype)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_soc_card_data *soc_card = snd_soc_card_get_drvdata(rtd->card);
+ const struct mtk_pcm_constraints_data *mpc = &soc_card->card_data->pcm_constraints[ctype];
+ int ret;
+
+ if (unlikely(!mpc))
+ return -EINVAL;
+
+ ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ mpc->rates);
+ if (ret < 0) {
+ dev_err(rtd->dev, "hw_constraint_list rate failed\n");
+ return ret;
+ }
+
+ ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ mpc->channels);
+ if (ret < 0) {
+ dev_err(rtd->dev, "hw_constraint_list channel failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_soundcard_startup);
+
+static int mtk_soundcard_playback_startup(struct snd_pcm_substream *substream)
+{
+ return mtk_soundcard_startup(substream, MTK_CONSTRAINT_PLAYBACK);
+}
+
+const struct snd_soc_ops mtk_soundcard_common_playback_ops = {
+ .startup = mtk_soundcard_playback_startup,
+};
+EXPORT_SYMBOL_GPL(mtk_soundcard_common_playback_ops);
+
+static int mtk_soundcard_capture_startup(struct snd_pcm_substream *substream)
+{
+ return mtk_soundcard_startup(substream, MTK_CONSTRAINT_CAPTURE);
+}
+
+const struct snd_soc_ops mtk_soundcard_common_capture_ops = {
+ .startup = mtk_soundcard_capture_startup,
+};
+EXPORT_SYMBOL_GPL(mtk_soundcard_common_capture_ops);
+
+int mtk_soundcard_common_probe(struct platform_device *pdev)
+{
+ 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;
+ struct snd_soc_jack *jacks;
+ struct snd_soc_card *card;
+ int i, orig_num_links, ret;
+ bool needs_legacy_probe;
+
+ pdata = device_get_match_data(&pdev->dev);
+ if (!pdata)
+ return -EINVAL;
+
+ card = pdata->card_data->card;
+ card->dev = &pdev->dev;
+ orig_dai_link = card->dai_link;
+ orig_num_links = card->num_links;
+
+ ret = snd_soc_of_parse_card_name(card, "model");
+ if (ret)
+ return ret;
+
+ if (!card->name) {
+ if (!pdata->card_name)
+ return -EINVAL;
+
+ card->name = pdata->card_name;
+ }
+
+ 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
+ * any legacy probe mechanism, as that cannot not be generic.
+ */
+ if (!pdata->soc_probe)
+ return -EINVAL;
+
+ dev_info_once(&pdev->dev, "audio-routing not found: using legacy probe\n");
+ } else {
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret)
+ return ret;
+ }
+
+ soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*soc_card_data), GFP_KERNEL);
+ if (!soc_card_data)
+ return -ENOMEM;
+
+ soc_card_data->card_data = pdata->card_data;
+
+ jacks = devm_kcalloc(card->dev, soc_card_data->card_data->num_jacks,
+ sizeof(*jacks), GFP_KERNEL);
+ if (!jacks)
+ return -ENOMEM;
+
+ 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");
+
+ put_device(&accdet_pdev->dev);
+ } else {
+ dev_err(&pdev->dev, "No device found from mediatek,accdet property\n");
+ }
+
+ of_node_put(accdet_node);
+ }
+
+ platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
+ if (!platform_node)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Property mediatek,platform missing or invalid\n");
+
+ /* Check if this SoC has an Audio DSP */
+ if (pdata->sof_priv)
+ adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
+ else
+ adsp_node = NULL;
+
+ if (adsp_node) {
+ 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);
+ if (ret) {
+ of_node_put(adsp_node);
+ of_node_put(platform_node);
+ return dev_err_probe(&pdev->dev, ret,
+ "Cannot parse mediatek,dai-link\n");
+ }
+ }
+
+ soc_card_data->sof_priv = pdata->sof_priv;
+ card->probe = mtk_sof_card_probe;
+ card->late_probe = mtk_sof_card_late_probe;
+ if (!card->topology_shortname_created) {
+ snprintf(card->topology_shortname, 32, "sof-%s", card->name);
+ card->topology_shortname_created = true;
+ }
+ card->name = card->topology_shortname;
+ }
+
+ /*
+ * Regardless of whether the ADSP is wanted and/or present in a machine
+ * specific device tree or not and regardless of whether any AFE_SOF
+ * link is present, we have to make sure that the platforms->of_node
+ * is not NULL, and set to either ADSP (adsp_node) or AFE (platform_node).
+ */
+ for_each_card_prelinks(card, i, dai_link) {
+ if (adsp_node && !strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")))
+ dai_link->platforms->of_node = adsp_node;
+ else if (!dai_link->platforms->name && !dai_link->platforms->of_node)
+ dai_link->platforms->of_node = platform_node;
+ }
+
+ if (!needs_legacy_probe) {
+ ret = parse_dai_link_info(card);
+ if (ret)
+ goto err_restore_dais;
+ } else {
+ if (adsp_node)
+ of_node_put(adsp_node);
+ of_node_put(platform_node);
+ }
+
+ if (pdata->soc_probe) {
+ ret = pdata->soc_probe(soc_card_data, needs_legacy_probe);
+ if (ret) {
+ if (!needs_legacy_probe)
+ clean_card_reference(card);
+ goto err_restore_dais;
+ }
+ }
+ snd_soc_card_set_drvdata(card, soc_card_data);
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+ if (!needs_legacy_probe)
+ clean_card_reference(card);
+
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "Cannot register card\n");
+ goto err_restore_dais;
+ }
+
+ return 0;
+
+err_restore_dais:
+ card->dai_link = orig_dai_link;
+ card->num_links = orig_num_links;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mtk_soundcard_common_probe);
diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.h b/sound/soc/mediatek/common/mtk-soundcard-driver.h
index d92cac1d7b72..f6c275b54025 100644
--- a/sound/soc/mediatek/common/mtk-soundcard-driver.h
+++ b/sound/soc/mediatek/common/mtk-soundcard-driver.h
@@ -9,6 +9,48 @@
#ifndef _MTK_SOUNDCARD_DRIVER_H_
#define _MTK_SOUNDCARD_DRIVER_H_
+struct mtk_sof_priv;
+struct mtk_soc_card_data;
+struct snd_pcm_hw_constraint_list;
+
+enum mtk_pcm_constraint_type {
+ MTK_CONSTRAINT_PLAYBACK,
+ MTK_CONSTRAINT_CAPTURE,
+ MTK_CONSTRAINT_HDMIDP,
+ MTK_CONSTRAINT_MAX
+};
+
+struct mtk_pcm_constraints_data {
+ const struct snd_pcm_hw_constraint_list *channels;
+ const struct snd_pcm_hw_constraint_list *rates;
+};
+
+struct mtk_platform_card_data {
+ struct snd_soc_card *card;
+ struct snd_soc_jack *jacks;
+ const struct mtk_pcm_constraints_data *pcm_constraints;
+ u8 num_jacks;
+ u8 num_pcm_constraints;
+ u8 flags;
+};
+
+struct mtk_soundcard_pdata {
+ const char *card_name;
+ struct mtk_platform_card_data *card_data;
+ const struct mtk_sof_priv *sof_priv;
+
+ int (*soc_probe)(struct mtk_soc_card_data *card_data, bool legacy);
+};
+
+/* Common playback/capture card startup ops */
+extern const struct snd_soc_ops mtk_soundcard_common_playback_ops;
+extern const struct snd_soc_ops mtk_soundcard_common_capture_ops;
+
+/* Exported for custom/extended soundcard startup ops */
+int mtk_soundcard_startup(struct snd_pcm_substream *substream,
+ enum mtk_pcm_constraint_type ctype);
+
int parse_dai_link_info(struct snd_soc_card *card);
void clean_card_reference(struct snd_soc_card *card);
+int mtk_soundcard_common_probe(struct platform_device *pdev);
#endif
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
index 21d5e697cfa7..507fa26c3945 100644
--- a/sound/soc/mediatek/mt2701/Makefile
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
+snd-soc-mt2701-afe-y := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
# machine driver
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index c9d4420e9b4c..fcae38135d93 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -12,8 +12,6 @@
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include "mt2701-afe-common.h"
@@ -494,10 +492,10 @@ static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream,
static int mt2701_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int fs;
- if (asoc_rtd_to_cpu(rtd, 0)->id != MT2701_MEMIF_ULBT)
+ if (snd_soc_rtd_to_cpu(rtd, 0)->id != MT2701_MEMIF_ULBT)
fs = mt2701_afe_i2s_fs(rate);
else
fs = (rate == 16000 ? 1 : 0);
@@ -1464,18 +1462,18 @@ 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_new = mt2701_afe_pcm_dev_remove,
+ .remove = mt2701_afe_pcm_dev_remove,
};
module_platform_driver(mt2701_afe_pcm_driver);
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
index 08ef109744c7..778a9dccfcaa 100644
--- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -10,16 +10,15 @@
#include <linux/module.h>
#include <sound/soc.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/of_gpio.h>
#include "mt2701-afe-common.h"
struct mt2701_cs42448_private {
int i2s1_in_mux;
- int i2s1_in_mux_gpio_sel_1;
- int i2s1_in_mux_gpio_sel_2;
+ struct gpio_desc *i2s1_in_mux_sel_1;
+ struct gpio_desc *i2s1_in_mux_sel_2;
};
static const char * const i2sin_mux_switch_text[] = {
@@ -53,20 +52,20 @@ static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol,
switch (ucontrol->value.integer.value[0]) {
case 0:
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+ gpiod_set_value(priv->i2s1_in_mux_sel_1, 0);
+ gpiod_set_value(priv->i2s1_in_mux_sel_2, 0);
break;
case 1:
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+ gpiod_set_value(priv->i2s1_in_mux_sel_1, 1);
+ gpiod_set_value(priv->i2s1_in_mux_sel_2, 0);
break;
case 2:
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+ gpiod_set_value(priv->i2s1_in_mux_sel_1, 0);
+ gpiod_set_value(priv->i2s1_in_mux_sel_2, 1);
break;
case 3:
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
- gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+ gpiod_set_value(priv->i2s1_in_mux_sel_1, 1);
+ gpiod_set_value(priv->i2s1_in_mux_sel_2, 1);
break;
default:
dev_warn(card->dev, "%s invalid setting\n", __func__);
@@ -127,9 +126,9 @@ static const struct snd_soc_ops mt2701_cs42448_48k_fe_ops = {
static int mt2701_cs42448_be_ops_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int mclk_rate;
unsigned int rate = params_rate(params);
unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
@@ -222,7 +221,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST},
.ops = &mt2701_cs42448_48k_fe_ops,
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(fe_multi_ch_out),
},
[DAI_LINK_FE_PCM0_IN] = {
@@ -232,7 +231,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST},
.ops = &mt2701_cs42448_48k_fe_ops,
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(fe_pcm0_in),
},
[DAI_LINK_FE_PCM1_IN] = {
@@ -242,7 +241,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST},
.ops = &mt2701_cs42448_48k_fe_ops,
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(fe_pcm1_in),
},
[DAI_LINK_FE_BT_OUT] = {
@@ -251,7 +250,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(fe_bt_out),
},
[DAI_LINK_FE_BT_IN] = {
@@ -260,55 +259,45 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(fe_bt_in),
},
/* BE */
[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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(be_i2s0),
},
[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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(be_i2s1),
},
[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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(be_i2s2),
},
[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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(be_i2s3),
},
[DAI_LINK_BE_MRG_BT] = {
.name = "mt2701-cs42448-MRG-BT",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(be_mrg_bt),
},
};
@@ -330,10 +319,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
int ret;
int i;
struct device_node *platform_node, *codec_node, *codec_node_bt_mrg;
+ struct device *dev = &pdev->dev;
struct mt2701_cs42448_private *priv =
- devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private),
+ devm_kzalloc(dev, sizeof(struct mt2701_cs42448_private),
GFP_KERNEL);
- struct device *dev = &pdev->dev;
struct snd_soc_dai_link *dai_link;
if (!priv)
@@ -342,7 +331,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
platform_node = of_parse_phandle(pdev->dev.of_node,
"mediatek,platform", 0);
if (!platform_node) {
- dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ dev_err(dev, "Property 'platform' missing or invalid\n");
return -EINVAL;
}
for_each_card_prelinks(card, i, dai_link) {
@@ -356,7 +345,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
codec_node = of_parse_phandle(pdev->dev.of_node,
"mediatek,audio-codec", 0);
if (!codec_node) {
- dev_err(&pdev->dev,
+ dev_err(dev,
"Property 'audio-codec' missing or invalid\n");
return -EINVAL;
}
@@ -369,7 +358,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node,
"mediatek,audio-codec-bt-mrg", 0);
if (!codec_node_bt_mrg) {
- dev_err(&pdev->dev,
+ dev_err(dev,
"Property 'audio-codec-bt-mrg' missing or invalid\n");
return -EINVAL;
}
@@ -378,37 +367,28 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret) {
- dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+ dev_err(dev, "failed to parse audio-routing: %d\n", ret);
return ret;
}
- priv->i2s1_in_mux_gpio_sel_1 =
- of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0);
- if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) {
- ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1,
- "i2s1_in_mux_gpio_sel_1");
- if (ret)
- dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n",
- __func__, ret);
- gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0);
- }
+ priv->i2s1_in_mux_sel_1 = devm_gpiod_get_optional(dev, "i2s1-in-sel-gpio1",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->i2s1_in_mux_sel_1))
+ return dev_err_probe(dev, PTR_ERR(priv->i2s1_in_mux_sel_1),
+ "error getting mux 1 selector\n");
+
+ priv->i2s1_in_mux_sel_2 = devm_gpiod_get_optional(dev, "i2s1-in-sel-gpio2",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->i2s1_in_mux_sel_2))
+ return dev_err_probe(dev, PTR_ERR(priv->i2s1_in_mux_sel_2),
+ "error getting mux 2 selector\n");
- priv->i2s1_in_mux_gpio_sel_2 =
- of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0);
- if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) {
- ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2,
- "i2s1_in_mux_gpio_sel_2");
- if (ret)
- dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n",
- __func__, ret);
- gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0);
- }
snd_soc_card_set_drvdata(card, priv);
- ret = devm_snd_soc_register_card(&pdev->dev, card);
+ ret = devm_snd_soc_register_card(dev, card);
if (ret)
- dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+ dev_err(dev, "%s snd_soc_register_card fail %d\n",
__func__, ret);
return ret;
}
diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
index a184032c15b6..84b3d6cd77a5 100644
--- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c
+++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
@@ -24,9 +24,9 @@ static const struct snd_kcontrol_new mt2701_wm8960_controls[] = {
static int mt2701_wm8960_be_ops_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned int mclk_rate;
unsigned int rate = params_rate(params);
unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
@@ -67,7 +67,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback),
},
{
@@ -76,18 +76,16 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture),
},
/* BE */
{
.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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(codec),
},
};
diff --git a/sound/soc/mediatek/mt6797/Makefile b/sound/soc/mediatek/mt6797/Makefile
index bf6e179ea93f..150021495e94 100644
--- a/sound/soc/mediatek/mt6797/Makefile
+++ b/sound/soc/mediatek/mt6797/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt6797-afe-objs := \
+snd-soc-mt6797-afe-y := \
mt6797-afe-pcm.o \
mt6797-afe-clk.o \
mt6797-dai-pcm.o \
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 43038444c43d..f62a32f2f2b6 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -139,18 +139,18 @@ static const struct snd_pcm_hardware mt6797_afe_hardware = {
static int mt6797_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
return mt6797_rate_transform(afe->dev, rate, id);
}
static int mt6797_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
@@ -704,18 +704,6 @@ static int mt6797_afe_runtime_resume(struct device *dev)
return 0;
}
-static int mt6797_afe_component_probe(struct snd_soc_component *component)
-{
- return mtk_afe_add_sub_dai_control(component);
-}
-
-static const struct snd_soc_component_driver mt6797_afe_component = {
- .name = AFE_PCM_NAME,
- .probe = mt6797_afe_component_probe,
- .pointer = mtk_afe_pcm_pointer,
- .pcm_construct = mtk_afe_pcm_new,
-};
-
static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
@@ -852,7 +840,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
/* register component */
- ret = devm_snd_soc_register_component(dev, &mt6797_afe_component,
+ ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
NULL, 0);
if (ret) {
dev_warn(dev, "err_platform\n");
@@ -891,18 +879,18 @@ 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_new = mt6797_afe_pcm_dev_remove,
+ .remove = mt6797_afe_pcm_dev_remove,
};
module_platform_driver(mt6797_afe_pcm_driver);
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
index 0ac6409c6d61..78f3ad758c12 100644
--- a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
@@ -10,86 +10,7 @@
#include "mt6797-afe-common.h"
#include "mt6797-interconnection.h"
#include "mt6797-reg.h"
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
+#include "../common/mtk-dai-adda-common.h"
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
@@ -246,7 +167,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
/* set input sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) << 28;
/* set output mode */
switch (rate) {
@@ -296,7 +217,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
0x1 << 0,
0x0 << 0);
- voice_mode = adda_ul_rate_transform(afe, rate);
+ voice_mode = mtk_adda_ul_rate_transform(afe, rate);
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
index 784c201b8fd4..daad9544a8d4 100644
--- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c
+++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c
@@ -78,7 +78,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback_1),
},
{
@@ -87,7 +87,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback_2),
},
{
@@ -96,7 +96,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback_3),
},
{
@@ -105,7 +105,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_1),
},
{
@@ -114,7 +114,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_2),
},
{
@@ -123,7 +123,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_3),
},
{
@@ -132,7 +132,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_mono_1),
},
{
@@ -141,8 +141,6 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_lpbk),
},
@@ -152,8 +150,6 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_speech),
},
@@ -161,24 +157,18 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = {
{
.name = "Primary Codec",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(primary_codec),
},
{
.name = "PCM 1",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm1),
},
{
.name = "PCM 2",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm2),
},
diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile
new file mode 100644
index 000000000000..4b54bbe88683
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt7986-afe-y := \
+ mt7986-afe-pcm.o \
+ mt7986-dai-etdm.o
+
+obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
+obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
new file mode 100644
index 000000000000..fc3bb31e5167
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt7986-afe-common.h -- MediaTek 7986 audio driver definitions
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#ifndef _MT_7986_AFE_COMMON_H_
+#define _MT_7986_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+ MT7986_MEMIF_DL1,
+ MT7986_MEMIF_VUL12,
+ MT7986_MEMIF_NUM,
+ MT7986_DAI_ETDM = MT7986_MEMIF_NUM,
+ MT7986_DAI_NUM,
+};
+
+enum {
+ MT7986_IRQ_0,
+ MT7986_IRQ_1,
+ MT7986_IRQ_2,
+ MT7986_IRQ_NUM,
+};
+
+struct mt7986_afe_private {
+ struct clk_bulk_data *clks;
+ int num_clks;
+
+ int pm_runtime_bypass_reg_ctl;
+
+ /* dai */
+ void *dai_priv[MT7986_DAI_NUM];
+};
+
+unsigned int mt7986_afe_rate_transform(struct device *dev,
+ unsigned int rate);
+
+/* dai register */
+int mt7986_dai_etdm_register(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
new file mode 100644
index 000000000000..7a6ad9116e55
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC AFE platform driver for MT7986
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+ MTK_AFE_RATE_8K = 0,
+ MTK_AFE_RATE_11K = 1,
+ MTK_AFE_RATE_12K = 2,
+ MTK_AFE_RATE_16K = 4,
+ MTK_AFE_RATE_22K = 5,
+ MTK_AFE_RATE_24K = 6,
+ MTK_AFE_RATE_32K = 8,
+ MTK_AFE_RATE_44K = 9,
+ MTK_AFE_RATE_48K = 10,
+ MTK_AFE_RATE_88K = 13,
+ MTK_AFE_RATE_96K = 14,
+ MTK_AFE_RATE_176K = 17,
+ MTK_AFE_RATE_192K = 18,
+};
+
+enum {
+ CLK_INFRA_AUD_BUS_CK = 0,
+ CLK_INFRA_AUD_26M_CK,
+ CLK_INFRA_AUD_L_CK,
+ CLK_INFRA_AUD_AUD_CK,
+ CLK_INFRA_AUD_EG2_CK,
+ CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+ [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
+ [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck",
+ [CLK_INFRA_AUD_L_CK] = "aud_l_ck",
+ [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
+ [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
+};
+
+unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_RATE_8K;
+ case 11025:
+ return MTK_AFE_RATE_11K;
+ case 12000:
+ return MTK_AFE_RATE_12K;
+ case 16000:
+ return MTK_AFE_RATE_16K;
+ case 22050:
+ return MTK_AFE_RATE_22K;
+ case 24000:
+ return MTK_AFE_RATE_24K;
+ case 32000:
+ return MTK_AFE_RATE_32K;
+ case 44100:
+ return MTK_AFE_RATE_44K;
+ case 48000:
+ return MTK_AFE_RATE_48K;
+ case 88200:
+ return MTK_AFE_RATE_88K;
+ case 96000:
+ return MTK_AFE_RATE_96K;
+ case 176400:
+ return MTK_AFE_RATE_176K;
+ case 192000:
+ return MTK_AFE_RATE_192K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
+ __func__, rate, MTK_AFE_RATE_48K);
+ return MTK_AFE_RATE_48K;
+ }
+}
+
+static const struct snd_pcm_hardware mt7986_afe_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 256,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 8 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+static int mt7986_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ return mt7986_afe_rate_transform(afe->dev, rate);
+}
+
+static int mt7986_irq_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ return mt7986_afe_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1",
+ .id = MT7986_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL1",
+ .id = MT7986_MEMIF_VUL12,
+ .capture = {
+ .stream_name = "UL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+};
+
+static const struct snd_kcontrol_new o018_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new o019_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = {
+ /* DL */
+ SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* UL */
+ SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
+ o018_mix, ARRAY_SIZE(o018_mix)),
+ SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
+ o019_mix, ARRAY_SIZE(o019_mix)),
+};
+
+static const struct snd_soc_dapm_route mt7986_memif_routes[] = {
+ {"I032", NULL, "DL1"},
+ {"I033", NULL, "DL1"},
+ {"UL1", NULL, "O018"},
+ {"UL1", NULL, "O019"},
+ {"O018", "I150_Switch", "I150"},
+ {"O019", "I151_Switch", "I151"},
+};
+
+static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = {
+ .name = "mt7986-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = {
+ [MT7986_MEMIF_DL1] = {
+ .name = "DL1",
+ .id = MT7986_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL0_BASE,
+ .reg_ofs_cur = AFE_DL0_CUR,
+ .reg_ofs_end = AFE_DL0_END,
+ .reg_ofs_base_msb = AFE_DL0_BASE_MSB,
+ .reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
+ .reg_ofs_end_msb = AFE_DL0_END_MSB,
+ .fs_reg = AFE_DL0_CON0,
+ .fs_shift = DL0_MODE_SFT,
+ .fs_maskbit = DL0_MODE_MASK,
+ .mono_reg = AFE_DL0_CON0,
+ .mono_shift = DL0_MONO_SFT,
+ .enable_reg = AFE_DL0_CON0,
+ .enable_shift = DL0_ON_SFT,
+ .hd_reg = AFE_DL0_CON0,
+ .hd_shift = DL0_HD_MODE_SFT,
+ .hd_align_reg = AFE_DL0_CON0,
+ .hd_align_mshift = DL0_HALIGN_SFT,
+ .pbuf_reg = AFE_DL0_CON0,
+ .pbuf_shift = DL0_PBUF_SIZE_SFT,
+ .minlen_reg = AFE_DL0_CON0,
+ .minlen_shift = DL0_MINLEN_SFT,
+ },
+ [MT7986_MEMIF_VUL12] = {
+ .name = "VUL12",
+ .id = MT7986_MEMIF_VUL12,
+ .reg_ofs_base = AFE_VUL0_BASE,
+ .reg_ofs_cur = AFE_VUL0_CUR,
+ .reg_ofs_end = AFE_VUL0_END,
+ .reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
+ .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
+ .reg_ofs_end_msb = AFE_VUL0_END_MSB,
+ .fs_reg = AFE_VUL0_CON0,
+ .fs_shift = VUL0_MODE_SFT,
+ .fs_maskbit = VUL0_MODE_MASK,
+ .mono_reg = AFE_VUL0_CON0,
+ .mono_shift = VUL0_MONO_SFT,
+ .enable_reg = AFE_VUL0_CON0,
+ .enable_shift = VUL0_ON_SFT,
+ .hd_reg = AFE_VUL0_CON0,
+ .hd_shift = VUL0_HD_MODE_SFT,
+ .hd_align_reg = AFE_VUL0_CON0,
+ .hd_align_mshift = VUL0_HALIGN_SFT,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = {
+ [MT7986_IRQ_0] = {
+ .id = MT7986_IRQ_0,
+ .irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+ .irq_fs_reg = AFE_IRQ0_MCU_CFG0,
+ .irq_fs_shift = IRQ_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ0_MCU_CFG0,
+ .irq_en_shift = IRQ_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ0_MCU_CLR_SFT,
+ },
+ [MT7986_IRQ_1] = {
+ .id = MT7986_IRQ_1,
+ .irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+ .irq_fs_reg = AFE_IRQ1_MCU_CFG0,
+ .irq_fs_shift = IRQ_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ1_MCU_CFG0,
+ .irq_en_shift = IRQ_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+ },
+ [MT7986_IRQ_2] = {
+ .id = MT7986_IRQ_2,
+ .irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+ .irq_fs_reg = AFE_IRQ2_MCU_CFG0,
+ .irq_fs_shift = IRQ_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ2_MCU_CFG0,
+ .irq_en_shift = IRQ_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+ },
+};
+
+static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /*
+ * Those auto-gen regs are read-only, so put it as volatile because
+ * volatile registers cannot be cached, which means that they cannot
+ * be set when power is off
+ */
+
+ switch (reg) {
+ case AFE_DL0_CUR_MSB:
+ case AFE_DL0_CUR:
+ case AFE_DL0_RCH_MON:
+ case AFE_DL0_LCH_MON:
+ case AFE_VUL0_CUR_MSB:
+ case AFE_VUL0_CUR:
+ case AFE_IRQ_MCU_STATUS:
+ case AFE_MEMIF_RD_MON:
+ case AFE_MEMIF_WR_MON:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config mt7986_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .volatile_reg = mt7986_is_volatile_reg,
+ .max_register = AFE_MAX_REGISTER,
+ .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
+};
+
+static int mt7986_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret, i;
+
+ afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM,
+ sizeof(*afe_priv->clks), GFP_KERNEL);
+ if (!afe_priv->clks)
+ return -ENOMEM;
+ afe_priv->num_clks = CLK_NUM;
+
+ for (i = 0; i < afe_priv->num_clks; i++)
+ afe_priv->clks[i].id = aud_clks[i];
+
+ ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "Failed to get clocks\n");
+
+ return 0;
+}
+
+static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev)
+{
+ struct mtk_base_afe *afe = dev;
+ struct mtk_base_afe_irq *irq;
+ u32 mcu_en, status, status_mcu;
+ int i, ret;
+ irqreturn_t irq_ret = IRQ_HANDLED;
+
+ /* get irq that is sent to MCU */
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+ /* only care IRQ which is sent to MCU */
+ status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+ if (ret || status_mcu == 0) {
+ dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+ __func__, ret, status, mcu_en);
+
+ irq_ret = IRQ_NONE;
+ goto err_irq;
+ }
+
+ for (i = 0; i < MT7986_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+ if (!memif->substream)
+ continue;
+
+ if (memif->irq_usage < 0)
+ continue;
+
+ irq = &afe->irqs[memif->irq_usage];
+
+ if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
+
+ return irq_ret;
+}
+
+static int mt7986_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+
+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+ goto skip_regmap;
+
+ /* disable clk*/
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0);
+
+ /* make sure all irq status are cleared, twice intended */
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+skip_regmap:
+ clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
+
+ return 0;
+}
+
+static int mt7986_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+
+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+ return 0;
+
+ /* enable clk*/
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+ AUD_APLL2_EN);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+ AUD_26M_EN);
+
+ return 0;
+}
+
+static int mt7986_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt7986_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver);
+
+ dai->dapm_widgets = mt7986_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets);
+ dai->dapm_routes = mt7986_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes);
+
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt7986_dai_etdm_register,
+ mt7986_dai_memif_register,
+};
+
+static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt7986_afe_private *afe_priv;
+ struct device *dev;
+ int i, irq_id, ret;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, afe);
+
+ afe->platform_priv = devm_kzalloc(&pdev->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->base_addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(afe->base_addr))
+ return PTR_ERR(afe->base_addr);
+
+ /* initial audio related clock */
+ ret = mt7986_init_clock(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot initialize clocks\n");
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ /* enable clock for regcache get default value from hw */
+ afe_priv->pm_runtime_bypass_reg_ctl = true;
+ pm_runtime_get_sync(&pdev->dev);
+
+ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+ &mt7986_afe_regmap_config);
+
+ pm_runtime_put_sync(&pdev->dev);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+ /* init memif */
+ afe->memif_size = MT7986_MEMIF_NUM;
+ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+ GFP_KERNEL);
+ if (!afe->memif)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->memif_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ afe->memif[i].irq_usage = -1;
+ }
+
+ mutex_init(&afe->irq_alloc_lock);
+
+ /* irq initialize */
+ afe->irqs_size = MT7986_IRQ_NUM;
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ /* request irq */
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id < 0)
+ return irq_id;
+
+ ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler,
+ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n");
+
+ /* init sub_dais */
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i);
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+ afe->mtk_afe_hardware = &mt7986_afe_hardware;
+ afe->memif_fs = mt7986_memif_fs;
+ afe->irq_fs = mt7986_irq_fs;
+
+ afe->runtime_resume = mt7986_afe_runtime_resume;
+ afe->runtime_suspend = mt7986_afe_runtime_suspend;
+
+ /* register component */
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mtk_afe_pcm_platform,
+ NULL, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot register AFE component\n");
+
+ ret = devm_snd_soc_register_component(afe->dev,
+ &mt7986_afe_pcm_dai_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n");
+
+ return 0;
+}
+
+static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt7986_afe_runtime_suspend(&pdev->dev);
+}
+
+static const struct of_device_id mt7986_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt7986-afe" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt7986_afe_pm_ops = {
+ 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 = pm_ptr(&mt7986_afe_pm_ops),
+ },
+ .probe = mt7986_afe_pcm_dev_probe,
+ .remove = mt7986_afe_pcm_dev_remove,
+};
+module_platform_driver(mt7986_afe_pcm_driver);
+
+MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
new file mode 100644
index 000000000000..fc55ff47b7bc
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI eTDM Control
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+
+#define HOPPING_CLK 0
+#define APLL_CLK 1
+#define MTK_DAI_ETDM_FORMAT_I2S 0
+#define MTK_DAI_ETDM_FORMAT_DSPA 4
+#define MTK_DAI_ETDM_FORMAT_DSPB 5
+
+enum {
+ MTK_ETDM_RATE_8K = 0,
+ MTK_ETDM_RATE_12K = 1,
+ MTK_ETDM_RATE_16K = 2,
+ MTK_ETDM_RATE_24K = 3,
+ MTK_ETDM_RATE_32K = 4,
+ MTK_ETDM_RATE_48K = 5,
+ MTK_ETDM_RATE_96K = 7,
+ MTK_ETDM_RATE_192K = 9,
+ MTK_ETDM_RATE_11K = 16,
+ MTK_ETDM_RATE_22K = 17,
+ MTK_ETDM_RATE_44K = 18,
+ MTK_ETDM_RATE_88K = 19,
+ MTK_ETDM_RATE_176K = 20,
+};
+
+struct mtk_dai_etdm_priv {
+ bool bck_inv;
+ bool lrck_inv;
+ bool slave_mode;
+ unsigned int format;
+};
+
+static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_ETDM_RATE_8K;
+ case 11025:
+ return MTK_ETDM_RATE_11K;
+ case 12000:
+ return MTK_ETDM_RATE_12K;
+ case 16000:
+ return MTK_ETDM_RATE_16K;
+ case 22050:
+ return MTK_ETDM_RATE_22K;
+ case 24000:
+ return MTK_ETDM_RATE_24K;
+ case 32000:
+ return MTK_ETDM_RATE_32K;
+ case 44100:
+ return MTK_ETDM_RATE_44K;
+ case 48000:
+ return MTK_ETDM_RATE_48K;
+ case 88200:
+ return MTK_ETDM_RATE_88K;
+ case 96000:
+ return MTK_ETDM_RATE_96K;
+ case 176400:
+ return MTK_ETDM_RATE_176K;
+ case 192000:
+ return MTK_ETDM_RATE_192K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
+ __func__, rate, MTK_ETDM_RATE_48K);
+ return MTK_ETDM_RATE_48K;
+ }
+}
+
+static int get_etdm_wlen(unsigned int bitwidth)
+{
+ return bitwidth <= 16 ? 16 : 32;
+}
+
+/* dai component */
+/* interconnection */
+
+static const struct snd_kcontrol_new o124_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new o125_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
+
+ /* DL */
+ SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /* UL */
+ SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)),
+ SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
+ {"I150", NULL, "ETDM Capture"},
+ {"I151", NULL, "ETDM Capture"},
+ {"ETDM Playback", NULL, "O124"},
+ {"ETDM Playback", NULL, "O125"},
+ {"O124", "I032_Switch", "I032"},
+ {"O125", "I033_Switch", "I033"},
+};
+
+/* dai ops */
+static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
+
+ return 0;
+}
+
+static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
+ CLK_OUT5_PDN);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
+ CLK_IN5_PDN);
+
+ clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
+}
+
+static unsigned int get_etdm_ch_fixup(unsigned int channels)
+{
+ if (channels > 16)
+ return 24;
+ else if (channels > 8)
+ return 16;
+ else if (channels > 4)
+ return 8;
+ else if (channels > 2)
+ return 4;
+ else
+ return 2;
+}
+
+static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai,
+ int stream)
+{
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
+ unsigned int rate = params_rate(params);
+ unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate);
+ unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate);
+ unsigned int channels = params_channels(params);
+ unsigned int bit_width = params_width(params);
+ unsigned int wlen = get_etdm_wlen(bit_width);
+ unsigned int val = 0;
+ unsigned int mask = 0;
+
+ dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
+ __func__, stream, rate, bit_width);
+
+ /* CON0 */
+ mask |= ETDM_BIT_LEN_MASK;
+ val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1);
+ mask |= ETDM_WRD_LEN_MASK;
+ val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1);
+ mask |= ETDM_FMT_MASK;
+ val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format);
+ mask |= ETDM_CH_NUM_MASK;
+ val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1);
+ mask |= RELATCH_SRC_MASK;
+ val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK);
+
+ switch (stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ /* set ETDM_OUT5_CON0 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
+
+ /* set ETDM_OUT5_CON4 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+ OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+ OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+ OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
+
+ /* set ETDM_OUT5_CON5 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
+ ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ /* set ETDM_IN5_CON0 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
+ ETDM_SYNC_MASK, ETDM_SYNC);
+
+ /* set ETDM_IN5_CON2 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
+ IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
+
+ /* set ETDM_IN5_CON3 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
+ IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
+
+ /* set ETDM_IN5_CON4 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
+ IN_RELATCH_MASK, IN_RELATCH(afe_rate));
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ unsigned int rate = params_rate(params);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ switch (rate) {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ case 96000:
+ case 192000:
+ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
+ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
+ return 0;
+ default:
+ dev_err(afe->dev,
+ "Sample rate %d invalid. Supported rates: 8/12/16/24/32/48/96/192 kHz\n",
+ rate);
+ return -EINVAL;
+ }
+}
+
+static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+ ETDM_EN);
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+ ETDM_EN);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+ 0);
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+ 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ void *priv_data;
+
+ switch (dai->id) {
+ case MT7986_DAI_ETDM:
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), id %d not support\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
+ GFP_KERNEL);
+ if (!priv_data)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[dai->id] = priv_data;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ etdm_data->bck_inv = false;
+ etdm_data->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ etdm_data->bck_inv = false;
+ etdm_data->lrck_inv = true;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ etdm_data->bck_inv = true;
+ etdm_data->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ etdm_data->bck_inv = true;
+ etdm_data->lrck_inv = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ etdm_data->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ etdm_data->slave_mode = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+ .startup = mtk_dai_etdm_startup,
+ .shutdown = mtk_dai_etdm_shutdown,
+ .hw_params = mtk_dai_etdm_hw_params,
+ .trigger = mtk_dai_etdm_trigger,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
+ {
+ .name = "ETDM",
+ .id = MT7986_DAI_ETDM,
+ .capture = {
+ .stream_name = "ETDM Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .playback = {
+ .stream_name = "ETDM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_etdm_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+int mt7986_dai_etdm_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_etdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
+
+ dai->dapm_widgets = mtk_dai_etdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
+ dai->dapm_routes = mtk_dai_etdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h
new file mode 100644
index 000000000000..c2b200743c3f
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-reg.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt7986-reg.h -- MediaTek 7986 audio driver reg definition
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#ifndef _MT7986_REG_H_
+#define _MT7986_REG_H_
+
+#define AUDIO_TOP_CON2 0x0008
+#define AUDIO_TOP_CON4 0x0010
+#define AUDIO_ENGEN_CON0 0x0014
+#define AFE_IRQ_MCU_EN 0x0100
+#define AFE_IRQ_MCU_STATUS 0x0120
+#define AFE_IRQ_MCU_CLR 0x0128
+#define AFE_IRQ0_MCU_CFG0 0x0140
+#define AFE_IRQ0_MCU_CFG1 0x0144
+#define AFE_IRQ1_MCU_CFG0 0x0148
+#define AFE_IRQ1_MCU_CFG1 0x014c
+#define AFE_IRQ2_MCU_CFG0 0x0150
+#define AFE_IRQ2_MCU_CFG1 0x0154
+#define ETDM_IN5_CON0 0x13f0
+#define ETDM_IN5_CON1 0x13f4
+#define ETDM_IN5_CON2 0x13f8
+#define ETDM_IN5_CON3 0x13fc
+#define ETDM_IN5_CON4 0x1400
+#define ETDM_OUT5_CON0 0x1570
+#define ETDM_OUT5_CON4 0x1580
+#define ETDM_OUT5_CON5 0x1584
+#define ETDM_4_7_COWORK_CON0 0x15e0
+#define ETDM_4_7_COWORK_CON1 0x15e4
+#define AFE_CONN018_1 0x1b44
+#define AFE_CONN018_4 0x1b50
+#define AFE_CONN019_1 0x1b64
+#define AFE_CONN019_4 0x1b70
+#define AFE_CONN124_1 0x2884
+#define AFE_CONN124_4 0x2890
+#define AFE_CONN125_1 0x28a4
+#define AFE_CONN125_4 0x28b0
+#define AFE_CONN_RS_0 0x3920
+#define AFE_CONN_RS_3 0x392c
+#define AFE_CONN_16BIT_0 0x3960
+#define AFE_CONN_16BIT_3 0x396c
+#define AFE_CONN_24BIT_0 0x3980
+#define AFE_CONN_24BIT_3 0x398c
+#define AFE_MEMIF_CON0 0x3d98
+#define AFE_MEMIF_RD_MON 0x3da0
+#define AFE_MEMIF_WR_MON 0x3da4
+#define AFE_DL0_BASE_MSB 0x3e40
+#define AFE_DL0_BASE 0x3e44
+#define AFE_DL0_CUR_MSB 0x3e48
+#define AFE_DL0_CUR 0x3e4c
+#define AFE_DL0_END_MSB 0x3e50
+#define AFE_DL0_END 0x3e54
+#define AFE_DL0_RCH_MON 0x3e58
+#define AFE_DL0_LCH_MON 0x3e5c
+#define AFE_DL0_CON0 0x3e60
+#define AFE_VUL0_BASE_MSB 0x4220
+#define AFE_VUL0_BASE 0x4224
+#define AFE_VUL0_CUR_MSB 0x4228
+#define AFE_VUL0_CUR 0x422c
+#define AFE_VUL0_END_MSB 0x4230
+#define AFE_VUL0_END 0x4234
+#define AFE_VUL0_CON0 0x4238
+
+#define AFE_MAX_REGISTER AFE_VUL0_CON0
+#define AFE_IRQ_STATUS_BITS 0x7
+#define AFE_IRQ_CNT_SHIFT 0
+#define AFE_IRQ_CNT_MASK 0xffffff
+
+/* AUDIO_TOP_CON2 */
+#define CLK_OUT5_PDN BIT(14)
+#define CLK_OUT5_PDN_MASK BIT(14)
+#define CLK_IN5_PDN BIT(7)
+#define CLK_IN5_PDN_MASK BIT(7)
+
+/* AUDIO_TOP_CON4 */
+#define PDN_APLL_TUNER2 BIT(12)
+#define PDN_APLL_TUNER2_MASK BIT(12)
+
+/* AUDIO_ENGEN_CON0 */
+#define AUD_APLL2_EN BIT(3)
+#define AUD_APLL2_EN_MASK BIT(3)
+#define AUD_26M_EN BIT(0)
+#define AUD_26M_EN_MASK BIT(0)
+
+/* AFE_DL0_CON0 */
+#define DL0_ON_SFT 28
+#define DL0_ON_MASK 0x1
+#define DL0_ON_MASK_SFT BIT(28)
+#define DL0_MINLEN_SFT 20
+#define DL0_MINLEN_MASK 0xf
+#define DL0_MINLEN_MASK_SFT (0xf << 20)
+#define DL0_MODE_SFT 8
+#define DL0_MODE_MASK 0x1f
+#define DL0_MODE_MASK_SFT (0x1f << 8)
+#define DL0_PBUF_SIZE_SFT 5
+#define DL0_PBUF_SIZE_MASK 0x3
+#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL0_MONO_SFT 4
+#define DL0_MONO_MASK 0x1
+#define DL0_MONO_MASK_SFT BIT(4)
+#define DL0_HALIGN_SFT 2
+#define DL0_HALIGN_MASK 0x1
+#define DL0_HALIGN_MASK_SFT BIT(2)
+#define DL0_HD_MODE_SFT 0
+#define DL0_HD_MODE_MASK 0x3
+#define DL0_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL0_CON0 */
+#define VUL0_ON_SFT 28
+#define VUL0_ON_MASK 0x1
+#define VUL0_ON_MASK_SFT BIT(28)
+#define VUL0_MODE_SFT 8
+#define VUL0_MODE_MASK 0x1f
+#define VUL0_MODE_MASK_SFT (0x1f << 8)
+#define VUL0_MONO_SFT 4
+#define VUL0_MONO_MASK 0x1
+#define VUL0_MONO_MASK_SFT BIT(4)
+#define VUL0_HALIGN_SFT 2
+#define VUL0_HALIGN_MASK 0x1
+#define VUL0_HALIGN_MASK_SFT BIT(2)
+#define VUL0_HD_MODE_SFT 0
+#define VUL0_HD_MODE_MASK 0x3
+#define VUL0_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_IRQ_MCU_CON */
+#define IRQ_MCU_MODE_SFT 4
+#define IRQ_MCU_MODE_MASK 0x1f
+#define IRQ_MCU_MODE_MASK_SFT (0x1f << 4)
+#define IRQ_MCU_ON_SFT 0
+#define IRQ_MCU_ON_MASK 0x1
+#define IRQ_MCU_ON_MASK_SFT BIT(0)
+#define IRQ0_MCU_CLR_SFT 0
+#define IRQ0_MCU_CLR_MASK 0x1
+#define IRQ0_MCU_CLR_MASK_SFT BIT(0)
+#define IRQ1_MCU_CLR_SFT 1
+#define IRQ1_MCU_CLR_MASK 0x1
+#define IRQ1_MCU_CLR_MASK_SFT BIT(1)
+#define IRQ2_MCU_CLR_SFT 2
+#define IRQ2_MCU_CLR_MASK 0x1
+#define IRQ2_MCU_CLR_MASK_SFT BIT(2)
+
+/* ETDM_IN5_CON2 */
+#define IN_CLK_SRC(x) ((x) << 10)
+#define IN_CLK_SRC_SFT 10
+#define IN_CLK_SRC_MASK GENMASK(12, 10)
+
+/* ETDM_IN5_CON3 */
+#define IN_SEL_FS(x) ((x) << 26)
+#define IN_SEL_FS_SFT 26
+#define IN_SEL_FS_MASK GENMASK(30, 26)
+
+/* ETDM_IN5_CON4 */
+#define IN_RELATCH(x) ((x) << 20)
+#define IN_RELATCH_SFT 20
+#define IN_RELATCH_MASK GENMASK(24, 20)
+#define IN_CLK_INV BIT(18)
+#define IN_CLK_INV_MASK BIT(18)
+
+/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
+#define RELATCH_SRC_MASK GENMASK(30, 28)
+#define ETDM_CH_NUM_MASK GENMASK(27, 23)
+#define ETDM_WRD_LEN_MASK GENMASK(20, 16)
+#define ETDM_BIT_LEN_MASK GENMASK(15, 11)
+#define ETDM_FMT_MASK GENMASK(8, 6)
+#define ETDM_SYNC BIT(1)
+#define ETDM_SYNC_MASK BIT(1)
+#define ETDM_EN BIT(0)
+#define ETDM_EN_MASK BIT(0)
+
+/* ETDM_OUT5_CON4 */
+#define OUT_RELATCH(x) ((x) << 24)
+#define OUT_RELATCH_SFT 24
+#define OUT_RELATCH_MASK GENMASK(28, 24)
+#define OUT_CLK_SRC(x) ((x) << 6)
+#define OUT_CLK_SRC_SFT 6
+#define OUT_CLK_SRC_MASK GENMASK(8, 6)
+#define OUT_SEL_FS(x) (x)
+#define OUT_SEL_FS_SFT 0
+#define OUT_SEL_FS_MASK GENMASK(4, 0)
+
+/* ETDM_OUT5_CON5 */
+#define ETDM_CLK_DIV BIT(12)
+#define ETDM_CLK_DIV_MASK BIT(12)
+#define OUT_CLK_INV BIT(9)
+#define OUT_CLK_INV_MASK BIT(9)
+
+/* ETDM_4_7_COWORK_CON0 */
+#define OUT_SEL(x) ((x) << 12)
+#define OUT_SEL_SFT 12
+#define OUT_SEL_MASK GENMASK(15, 12)
+#endif
diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
new file mode 100644
index 000000000000..f1dc18222be7
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt7986-afe-common.h"
+
+static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
+};
+
+static const struct snd_kcontrol_new mt7986_wm8960_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("AMIC"),
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
+ /* FE */
+ {
+ .name = "wm8960-playback",
+ .stream_name = "wm8960-playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ {
+ .name = "wm8960-capture",
+ .stream_name = "wm8960-capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ /* BE */
+ {
+ .name = "wm8960-codec",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC |
+ SND_SOC_DAIFMT_GATED,
+ SND_SOC_DAILINK_REG(codec),
+ },
+};
+
+static struct snd_soc_card mt7986_wm8960_card = {
+ .name = "mt7986-wm8960",
+ .owner = THIS_MODULE,
+ .dai_link = mt7986_wm8960_dai_links,
+ .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links),
+ .controls = mt7986_wm8960_controls,
+ .num_controls = ARRAY_SIZE(mt7986_wm8960_controls),
+ .dapm_widgets = mt7986_wm8960_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets),
+};
+
+static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt7986_wm8960_card;
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *platform, *codec;
+ struct device_node *platform_dai_node, *codec_dai_node;
+ int ret, i;
+
+ card->dev = &pdev->dev;
+
+ platform = of_get_child_by_name(pdev->dev.of_node, "platform");
+
+ if (platform) {
+ platform_dai_node = of_parse_phandle(platform, "sound-dai", 0);
+ of_node_put(platform);
+
+ if (!platform_dai_node) {
+ dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_dai_node;
+ }
+
+ codec = of_get_child_by_name(pdev->dev.of_node, "codec");
+
+ if (codec) {
+ codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
+ of_node_put(codec);
+
+ if (!codec_dai_node) {
+ of_node_put(platform_dai_node);
+ dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+ of_node_put(platform_dai_node);
+ dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = codec_dai_node;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
+ goto err_of_node_put;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
+ goto err_of_node_put;
+ }
+
+err_of_node_put:
+ of_node_put(platform_dai_node);
+ of_node_put(codec_dai_node);
+ return ret;
+}
+
+static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
+ {.compatible = "mediatek,mt7986-wm8960-sound"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match);
+
+static struct platform_driver mt7986_wm8960_machine = {
+ .driver = {
+ .name = "mt7986-wm8960",
+ .of_match_table = mt7986_wm8960_machine_dt_match,
+ },
+ .probe = mt7986_wm8960_machine_probe,
+};
+
+module_platform_driver(mt7986_wm8960_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt7986 wm8960 soc card");
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 06269f7e3756..c0fa623e0b17 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
@@ -480,10 +481,10 @@ static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
static int mt8173_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];
int fs;
if (memif->data->id == MT8173_AFE_MEMIF_DAI ||
@@ -1053,22 +1054,28 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
struct mtk_base_afe *afe;
struct mt8173_afe_private *afe_priv;
struct snd_soc_component *comp_pcm, *comp_hdmi;
+ struct device *dev = &pdev->dev;
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
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;
- afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
- GFP_KERNEL);
+ afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv), GFP_KERNEL);
afe_priv = afe->platform_priv;
if (!afe_priv)
return -ENOMEM;
- afe->dev = &pdev->dev;
+ afe->dev = dev;
+
+ ret = of_reserved_mem_device_init(dev);
+ if (ret) {
+ dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
+ afe->preallocate_buffers = true;
+ }
irq_id = platform_get_irq(pdev, 0);
if (irq_id <= 0)
@@ -1078,27 +1085,27 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
if (IS_ERR(afe->base_addr))
return PTR_ERR(afe->base_addr);
- afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
- &mt8173_afe_regmap_config);
+ afe->regmap = devm_regmap_init_mmio(dev, afe->base_addr,
+ &mt8173_afe_regmap_config);
if (IS_ERR(afe->regmap))
return PTR_ERR(afe->regmap);
/* initial audio related clock */
ret = mt8173_afe_init_audio_clk(afe);
if (ret) {
- dev_err(afe->dev, "mt8173_afe_init_audio_clk fail\n");
+ dev_err(dev, "mt8173_afe_init_audio_clk fail\n");
return ret;
}
/* memif % irq initialize*/
afe->memif_size = MT8173_AFE_MEMIF_NUM;
- afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
+ afe->memif = devm_kcalloc(dev, afe->memif_size,
sizeof(*afe->memif), GFP_KERNEL);
if (!afe->memif)
return -ENOMEM;
afe->irqs_size = MT8173_AFE_IRQ_NUM;
- afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size,
sizeof(*afe->irqs), GFP_KERNEL);
if (!afe->irqs)
return -ENOMEM;
@@ -1117,9 +1124,9 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, afe);
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
- ret = mt8173_afe_runtime_resume(&pdev->dev);
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = mt8173_afe_runtime_resume(dev);
if (ret)
goto err_pm_disable;
}
@@ -1129,13 +1136,12 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
afe->runtime_resume = mt8173_afe_runtime_resume;
afe->runtime_suspend = mt8173_afe_runtime_suspend;
- ret = devm_snd_soc_register_component(&pdev->dev,
- &mtk_afe_pcm_platform,
- NULL, 0);
+ ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
+ NULL, 0);
if (ret)
goto err_pm_disable;
- comp_pcm = devm_kzalloc(&pdev->dev, sizeof(*comp_pcm), GFP_KERNEL);
+ comp_pcm = devm_kzalloc(dev, sizeof(*comp_pcm), GFP_KERNEL);
if (!comp_pcm) {
ret = -ENOMEM;
goto err_pm_disable;
@@ -1143,7 +1149,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
ret = snd_soc_component_initialize(comp_pcm,
&mt8173_afe_pcm_dai_component,
- &pdev->dev);
+ dev);
if (ret)
goto err_pm_disable;
@@ -1157,7 +1163,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
if (ret)
goto err_pm_disable;
- comp_hdmi = devm_kzalloc(&pdev->dev, sizeof(*comp_hdmi), GFP_KERNEL);
+ comp_hdmi = devm_kzalloc(dev, sizeof(*comp_hdmi), GFP_KERNEL);
if (!comp_hdmi) {
ret = -ENOMEM;
goto err_cleanup_components;
@@ -1165,7 +1171,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
ret = snd_soc_component_initialize(comp_hdmi,
&mt8173_afe_hdmi_dai_component,
- &pdev->dev);
+ dev);
if (ret)
goto err_cleanup_components;
@@ -1179,30 +1185,32 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
if (ret)
goto err_cleanup_components;
- ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
+ ret = devm_request_irq(dev, irq_id, mt8173_afe_irq_handler,
0, "Afe_ISR_Handle", (void *)afe);
if (ret) {
- dev_err(afe->dev, "could not request_irq\n");
+ dev_err(dev, "could not request_irq\n");
goto err_cleanup_components;
}
- dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n");
+ dev_info(dev, "MT8173 AFE driver initialized.\n");
return 0;
err_cleanup_components:
- snd_soc_unregister_component(&pdev->dev);
+ snd_soc_unregister_component(dev);
err_pm_disable:
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(dev);
return ret;
}
static void mt8173_afe_pcm_dev_remove(struct platform_device *pdev)
{
- snd_soc_unregister_component(&pdev->dev);
+ struct device *dev = &pdev->dev;
+
+ snd_soc_unregister_component(dev);
- pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- mt8173_afe_runtime_suspend(&pdev->dev);
+ pm_runtime_disable(dev);
+ if (!pm_runtime_status_suspended(dev))
+ mt8173_afe_runtime_suspend(dev);
}
static const struct of_device_id mt8173_afe_pcm_dt_match[] = {
@@ -1212,18 +1220,18 @@ 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_new = mt8173_afe_pcm_dev_remove,
+ .remove = mt8173_afe_pcm_dev_remove,
};
module_platform_driver(mt8173_afe_pcm_driver);
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c
index c2b0619b6158..49ebb67c818a 100644
--- a/sound/soc/mediatek/mt8173/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include "../../codecs/max98090.h"
static struct snd_soc_jack mt8173_max98090_jack;
@@ -52,8 +51,8 @@ static const struct snd_kcontrol_new mt8173_max98090_controls[] = {
static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
return snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256,
SND_SOC_CLOCK_IN);
@@ -67,10 +66,10 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
struct snd_soc_card *card = runtime->card;
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
/* enable jack detection */
- ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE,
+ ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET,
&mt8173_max98090_jack,
mt8173_max98090_jack_pins,
ARRAY_SIZE(mt8173_max98090_jack_pins));
@@ -105,7 +104,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
.stream_name = "MAX98090 Playback",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback),
},
{
@@ -113,7 +112,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
.stream_name = "MAX98090 Capture",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture),
},
/* Back End DAI links */
@@ -123,9 +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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
+ 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 f803f121659d..dc063d85e62f 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -7,8 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../../codecs/rt5645.h"
@@ -40,10 +38,21 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
+static struct snd_soc_jack_pin mt8173_rt5650_rt5514_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int i, ret;
@@ -73,7 +82,7 @@ static struct snd_soc_jack mt8173_rt5650_rt5514_jack;
static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
int ret;
rt5645_sel_asrc_clk_src(component,
@@ -82,11 +91,13 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
RT5645_CLK_SEL_I2S1_ASRC);
/* enable jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &mt8173_rt5650_rt5514_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_rt5514_jack,
+ mt8173_rt5650_rt5514_jack_pins,
+ ARRAY_SIZE(mt8173_rt5650_rt5514_jack_pins));
if (ret) {
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
return ret;
@@ -128,7 +139,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = {
.stream_name = "rt5650_rt5514 Playback",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback),
},
[DAI_LINK_CAPTURE] = {
@@ -136,7 +147,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = {
.stream_name = "rt5650_rt5514 Capture",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture),
},
/* Back End DAI links */
@@ -145,11 +156,9 @@ 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,
- .dpcm_playback = 1,
- .dpcm_capture = 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 8794720cea3a..a1ba5df87e1e 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -7,8 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../../codecs/rt5645.h"
@@ -44,10 +42,21 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
+static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int i, ret;
@@ -77,8 +86,8 @@ static struct snd_soc_jack mt8173_rt5650_rt5676_jack;
static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
- struct snd_soc_component *component_sub = asoc_rtd_to_codec(runtime, 1)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component_sub = snd_soc_rtd_to_codec(runtime, 1)->component;
int ret;
rt5645_sel_asrc_clk_src(component,
@@ -95,11 +104,13 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
RT5677_CLK_SEL_I2S2_ASRC);
/* enable jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &mt8173_rt5650_rt5676_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_rt5676_jack,
+ mt8173_rt5650_rt5676_jack_pins,
+ ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins));
if (ret) {
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
return ret;
@@ -160,7 +171,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.stream_name = "rt5650_rt5676 Playback",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback),
},
[DAI_LINK_CAPTURE] = {
@@ -168,7 +179,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.stream_name = "rt5650_rt5676 Capture",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture),
},
[DAI_LINK_HDMI] = {
@@ -176,7 +187,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.stream_name = "HDMI PCM",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(hdmi_pcm),
},
@@ -186,17 +197,15 @@ 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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(codec),
},
[DAI_LINK_HDMI_I2S] = {
.name = "HDMI BE",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(hdmi_be),
},
/* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
@@ -205,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 e05f2b0231fe..3d6d7bc05b87 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -7,8 +7,6 @@
*/
#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../../codecs/rt5645.h"
@@ -54,10 +52,21 @@ static const struct snd_kcontrol_new mt8173_rt5650_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
+static struct snd_soc_jack_pin mt8173_rt5650_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int mclk_clock;
struct snd_soc_dai *codec_dai;
int i, ret;
@@ -103,8 +112,8 @@ static struct snd_soc_jack mt8173_rt5650_jack, mt8173_rt5650_hdmi_jack;
static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
- const char *codec_capture_dai = asoc_rtd_to_codec(runtime, 1)->name;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
+ const char *codec_capture_dai = snd_soc_rtd_to_codec(runtime, 1)->name;
int ret;
rt5645_sel_asrc_clk_src(component,
@@ -128,11 +137,13 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
}
/* enable jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &mt8173_rt5650_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_jack,
+ mt8173_rt5650_jack_pins,
+ ARRAY_SIZE(mt8173_rt5650_jack_pins));
if (ret) {
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
return ret;
@@ -148,12 +159,12 @@ static int mt8173_rt5650_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT,
&mt8173_rt5650_hdmi_jack);
if (ret)
return ret;
- return snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component,
+ return snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component,
&mt8173_rt5650_hdmi_jack, NULL);
}
@@ -199,7 +210,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
.stream_name = "rt5650 Playback",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback),
},
[DAI_LINK_CAPTURE] = {
@@ -207,7 +218,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
.stream_name = "rt5650 Capture",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture),
},
[DAI_LINK_HDMI] = {
@@ -215,7 +226,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
.stream_name = "HDMI PCM",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(hdmi_pcm),
},
/* Back End DAI links */
@@ -224,17 +235,15 @@ 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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(codec),
},
[DAI_LINK_HDMI_I2S] = {
.name = "HDMI BE",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.init = mt8173_rt5650_hdmi_init,
SND_SOC_DAILINK_REG(hdmi_be),
},
@@ -288,7 +297,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
np = of_get_child_by_name(pdev->dev.of_node, "codec-capture");
if (np) {
- ret = snd_soc_of_get_dai_name(np, &codec_capture_dai);
+ ret = snd_soc_of_get_dai_name(np, &codec_capture_dai, 0);
of_node_put(np);
if (ret < 0) {
dev_err(&pdev->dev,
diff --git a/sound/soc/mediatek/mt8183/Makefile b/sound/soc/mediatek/mt8183/Makefile
index c0a3bbc2c1f6..0d0dcdde00fc 100644
--- a/sound/soc/mediatek/mt8183/Makefile
+++ b/sound/soc/mediatek/mt8183/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt8183-afe-objs := \
+snd-soc-mt8183-afe-y := \
mt8183-afe-pcm.o \
mt8183-afe-clk.o \
mt8183-dai-i2s.o \
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
index 90422ed2bbcc..a7fef772760a 100644
--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
@@ -6,10 +6,12 @@
// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -142,18 +144,18 @@ static const struct snd_pcm_hardware mt8183_afe_hardware = {
static int mt8183_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
return mt8183_rate_transform(afe->dev, rate, id);
}
static int mt8183_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
@@ -424,342 +426,106 @@ static const struct snd_soc_component_driver mt8183_afe_pcm_dai_component = {
.name = "mt8183-afe-pcm-dai",
};
+#define MT8183_MEMIF_BASE(_id, _en_reg, _fs_reg, _mono_reg) \
+ [MT8183_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8183_MEMIF_##_id, \
+ .reg_ofs_base = AFE_##_id##_BASE, \
+ .reg_ofs_cur = AFE_##_id##_CUR, \
+ .reg_ofs_end = AFE_##_id##_END, \
+ .reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+ .reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+ .reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+ .fs_reg = (_fs_reg), \
+ .fs_shift = _id##_MODE_SFT, \
+ .fs_maskbit = _id##_MODE_MASK, \
+ .mono_reg = (_mono_reg), \
+ .mono_shift = _id##_DATA_SFT, \
+ .enable_reg = (_en_reg), \
+ .enable_shift = _id##_ON_SFT, \
+ .hd_reg = AFE_MEMIF_HD_MODE, \
+ .hd_align_reg = AFE_MEMIF_HDALIGN, \
+ .hd_shift = _id##_HD_SFT, \
+ .hd_align_mshift = _id##_HD_ALIGN_SFT, \
+ .agent_disable_reg = -1, \
+ .agent_disable_shift = -1, \
+ .msb_reg = -1, \
+ .msb_shift = -1, \
+ }
+
+#define MT8183_MEMIF(_id, _fs_reg, _mono_reg) \
+ MT8183_MEMIF_BASE(_id, AFE_DAC_CON0, _fs_reg, _mono_reg)
+
+/* For convenience with macros: missing register fields */
+#define MOD_DAI_DATA_SFT -1
+#define HDMI_MODE_SFT -1
+#define HDMI_MODE_MASK -1
+#define HDMI_DATA_SFT -1
+#define HDMI_ON_SFT -1
+
+/* For convenience with macros: register name differences */
+#define AFE_VUL12_BASE AFE_VUL_D2_BASE
+#define AFE_VUL12_CUR AFE_VUL_D2_CUR
+#define AFE_VUL12_END AFE_VUL_D2_END
+#define AFE_VUL12_BASE_MSB AFE_VUL_D2_BASE_MSB
+#define AFE_VUL12_CUR_MSB AFE_VUL_D2_CUR_MSB
+#define AFE_VUL12_END_MSB AFE_VUL_D2_END_MSB
+#define AWB2_HD_ALIGN_SFT AWB2_ALIGN_SFT
+#define VUL12_DATA_SFT VUL12_MONO_SFT
+#define AFE_HDMI_BASE AFE_HDMI_OUT_BASE
+#define AFE_HDMI_CUR AFE_HDMI_OUT_CUR
+#define AFE_HDMI_END AFE_HDMI_OUT_END
+#define AFE_HDMI_BASE_MSB AFE_HDMI_OUT_BASE_MSB
+#define AFE_HDMI_CUR_MSB AFE_HDMI_OUT_CUR_MSB
+#define AFE_HDMI_END_MSB AFE_HDMI_OUT_END_MSB
+
static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = {
- [MT8183_MEMIF_DL1] = {
- .name = "DL1",
- .id = MT8183_MEMIF_DL1,
- .reg_ofs_base = AFE_DL1_BASE,
- .reg_ofs_cur = AFE_DL1_CUR,
- .fs_reg = AFE_DAC_CON1,
- .fs_shift = DL1_MODE_SFT,
- .fs_maskbit = DL1_MODE_MASK,
- .mono_reg = AFE_DAC_CON1,
- .mono_shift = DL1_DATA_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = DL1_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = DL1_HD_SFT,
- .hd_align_mshift = DL1_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_DL2] = {
- .name = "DL2",
- .id = MT8183_MEMIF_DL2,
- .reg_ofs_base = AFE_DL2_BASE,
- .reg_ofs_cur = AFE_DL2_CUR,
- .fs_reg = AFE_DAC_CON1,
- .fs_shift = DL2_MODE_SFT,
- .fs_maskbit = DL2_MODE_MASK,
- .mono_reg = AFE_DAC_CON1,
- .mono_shift = DL2_DATA_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = DL2_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = DL2_HD_SFT,
- .hd_align_mshift = DL2_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_DL3] = {
- .name = "DL3",
- .id = MT8183_MEMIF_DL3,
- .reg_ofs_base = AFE_DL3_BASE,
- .reg_ofs_cur = AFE_DL3_CUR,
- .fs_reg = AFE_DAC_CON2,
- .fs_shift = DL3_MODE_SFT,
- .fs_maskbit = DL3_MODE_MASK,
- .mono_reg = AFE_DAC_CON1,
- .mono_shift = DL3_DATA_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = DL3_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = DL3_HD_SFT,
- .hd_align_mshift = DL3_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_VUL2] = {
- .name = "VUL2",
- .id = MT8183_MEMIF_VUL2,
- .reg_ofs_base = AFE_VUL2_BASE,
- .reg_ofs_cur = AFE_VUL2_CUR,
- .fs_reg = AFE_DAC_CON2,
- .fs_shift = VUL2_MODE_SFT,
- .fs_maskbit = VUL2_MODE_MASK,
- .mono_reg = AFE_DAC_CON2,
- .mono_shift = VUL2_DATA_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = VUL2_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = VUL2_HD_SFT,
- .hd_align_mshift = VUL2_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_AWB] = {
- .name = "AWB",
- .id = MT8183_MEMIF_AWB,
- .reg_ofs_base = AFE_AWB_BASE,
- .reg_ofs_cur = AFE_AWB_CUR,
- .fs_reg = AFE_DAC_CON1,
- .fs_shift = AWB_MODE_SFT,
- .fs_maskbit = AWB_MODE_MASK,
- .mono_reg = AFE_DAC_CON1,
- .mono_shift = AWB_DATA_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = AWB_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = AWB_HD_SFT,
- .hd_align_mshift = AWB_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_AWB2] = {
- .name = "AWB2",
- .id = MT8183_MEMIF_AWB2,
- .reg_ofs_base = AFE_AWB2_BASE,
- .reg_ofs_cur = AFE_AWB2_CUR,
- .fs_reg = AFE_DAC_CON2,
- .fs_shift = AWB2_MODE_SFT,
- .fs_maskbit = AWB2_MODE_MASK,
- .mono_reg = AFE_DAC_CON2,
- .mono_shift = AWB2_DATA_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = AWB2_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = AWB2_HD_SFT,
- .hd_align_mshift = AWB2_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_VUL12] = {
- .name = "VUL12",
- .id = MT8183_MEMIF_VUL12,
- .reg_ofs_base = AFE_VUL_D2_BASE,
- .reg_ofs_cur = AFE_VUL_D2_CUR,
- .fs_reg = AFE_DAC_CON0,
- .fs_shift = VUL12_MODE_SFT,
- .fs_maskbit = VUL12_MODE_MASK,
- .mono_reg = AFE_DAC_CON0,
- .mono_shift = VUL12_MONO_SFT,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = VUL12_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = VUL12_HD_SFT,
- .hd_align_mshift = VUL12_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_MOD_DAI] = {
- .name = "MOD_DAI",
- .id = MT8183_MEMIF_MOD_DAI,
- .reg_ofs_base = AFE_MOD_DAI_BASE,
- .reg_ofs_cur = AFE_MOD_DAI_CUR,
- .fs_reg = AFE_DAC_CON1,
- .fs_shift = MOD_DAI_MODE_SFT,
- .fs_maskbit = MOD_DAI_MODE_MASK,
- .mono_reg = -1,
- .mono_shift = 0,
- .enable_reg = AFE_DAC_CON0,
- .enable_shift = MOD_DAI_ON_SFT,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = MOD_DAI_HD_SFT,
- .hd_align_mshift = MOD_DAI_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
- [MT8183_MEMIF_HDMI] = {
- .name = "HDMI",
- .id = MT8183_MEMIF_HDMI,
- .reg_ofs_base = AFE_HDMI_OUT_BASE,
- .reg_ofs_cur = AFE_HDMI_OUT_CUR,
- .fs_reg = -1,
- .fs_shift = -1,
- .fs_maskbit = -1,
- .mono_reg = -1,
- .mono_shift = -1,
- .enable_reg = -1, /* control in tdm for sync start */
- .enable_shift = -1,
- .hd_reg = AFE_MEMIF_HD_MODE,
- .hd_align_reg = AFE_MEMIF_HDALIGN,
- .hd_shift = HDMI_HD_SFT,
- .hd_align_mshift = HDMI_HD_ALIGN_SFT,
- .agent_disable_reg = -1,
- .agent_disable_shift = -1,
- .msb_reg = -1,
- .msb_shift = -1,
- },
+ MT8183_MEMIF(DL1, AFE_DAC_CON1, AFE_DAC_CON1),
+ MT8183_MEMIF(DL2, AFE_DAC_CON1, AFE_DAC_CON1),
+ MT8183_MEMIF(DL3, AFE_DAC_CON2, AFE_DAC_CON1),
+ MT8183_MEMIF(VUL2, AFE_DAC_CON2, AFE_DAC_CON2),
+ MT8183_MEMIF(AWB, AFE_DAC_CON1, AFE_DAC_CON1),
+ MT8183_MEMIF(AWB2, AFE_DAC_CON2, AFE_DAC_CON2),
+ MT8183_MEMIF(VUL12, AFE_DAC_CON0, AFE_DAC_CON0),
+ MT8183_MEMIF(MOD_DAI, AFE_DAC_CON1, -1),
+ /* enable control in tdm for sync start */
+ MT8183_MEMIF_BASE(HDMI, -1, -1, -1),
};
+#define MT8183_AFE_IRQ_BASE(_id, _fs_reg, _fs_shift, _fs_maskbit) \
+ [MT8183_IRQ_##_id] = { \
+ .id = MT8183_IRQ_##_id, \
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT##_id, \
+ .irq_cnt_shift = 0, \
+ .irq_cnt_maskbit = 0x3ffff, \
+ .irq_fs_reg = _fs_reg, \
+ .irq_fs_shift = _fs_shift, \
+ .irq_fs_maskbit = _fs_maskbit, \
+ .irq_en_reg = AFE_IRQ_MCU_CON0, \
+ .irq_en_shift = IRQ##_id##_MCU_ON_SFT, \
+ .irq_clr_reg = AFE_IRQ_MCU_CLR, \
+ .irq_clr_shift = IRQ##_id##_MCU_CLR_SFT, \
+ }
+
+#define MT8183_AFE_IRQ(_id) \
+ MT8183_AFE_IRQ_BASE(_id, AFE_IRQ_MCU_CON1 + _id / 8 * 4, \
+ IRQ##_id##_MCU_MODE_SFT, \
+ IRQ##_id##_MCU_MODE_MASK)
+
+#define MT8183_AFE_IRQ_NOFS(_id) MT8183_AFE_IRQ_BASE(_id, -1, -1, -1)
+
static const struct mtk_base_irq_data irq_data[MT8183_IRQ_NUM] = {
- [MT8183_IRQ_0] = {
- .id = MT8183_IRQ_0,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT0,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ0_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ0_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ0_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ0_MCU_CLR_SFT,
- },
- [MT8183_IRQ_1] = {
- .id = MT8183_IRQ_1,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ1_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ1_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ1_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ1_MCU_CLR_SFT,
- },
- [MT8183_IRQ_2] = {
- .id = MT8183_IRQ_2,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ2_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ2_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ2_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ2_MCU_CLR_SFT,
- },
- [MT8183_IRQ_3] = {
- .id = MT8183_IRQ_3,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ3_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ3_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ3_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ3_MCU_CLR_SFT,
- },
- [MT8183_IRQ_4] = {
- .id = MT8183_IRQ_4,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ4_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ4_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ4_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ4_MCU_CLR_SFT,
- },
- [MT8183_IRQ_5] = {
- .id = MT8183_IRQ_5,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT5,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ5_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ5_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ5_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ5_MCU_CLR_SFT,
- },
- [MT8183_IRQ_6] = {
- .id = MT8183_IRQ_6,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT6,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ6_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ6_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ6_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ6_MCU_CLR_SFT,
- },
- [MT8183_IRQ_7] = {
- .id = MT8183_IRQ_7,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON1,
- .irq_fs_shift = IRQ7_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ7_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ7_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ7_MCU_CLR_SFT,
- },
- [MT8183_IRQ_8] = {
- .id = MT8183_IRQ_8,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT8,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = -1,
- .irq_fs_shift = -1,
- .irq_fs_maskbit = -1,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ8_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ8_MCU_CLR_SFT,
- },
- [MT8183_IRQ_11] = {
- .id = MT8183_IRQ_11,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT11,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON2,
- .irq_fs_shift = IRQ11_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ11_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ11_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ11_MCU_CLR_SFT,
- },
- [MT8183_IRQ_12] = {
- .id = MT8183_IRQ_12,
- .irq_cnt_reg = AFE_IRQ_MCU_CNT12,
- .irq_cnt_shift = 0,
- .irq_cnt_maskbit = 0x3ffff,
- .irq_fs_reg = AFE_IRQ_MCU_CON2,
- .irq_fs_shift = IRQ12_MCU_MODE_SFT,
- .irq_fs_maskbit = IRQ12_MCU_MODE_MASK,
- .irq_en_reg = AFE_IRQ_MCU_CON0,
- .irq_en_shift = IRQ12_MCU_ON_SFT,
- .irq_clr_reg = AFE_IRQ_MCU_CLR,
- .irq_clr_shift = IRQ12_MCU_CLR_SFT,
- },
+ MT8183_AFE_IRQ(0),
+ MT8183_AFE_IRQ(1),
+ MT8183_AFE_IRQ(2),
+ MT8183_AFE_IRQ(3),
+ MT8183_AFE_IRQ(4),
+ MT8183_AFE_IRQ(5),
+ MT8183_AFE_IRQ(6),
+ MT8183_AFE_IRQ(7),
+ MT8183_AFE_IRQ_NOFS(8),
+ MT8183_AFE_IRQ(11),
+ MT8183_AFE_IRQ(12),
};
static bool mt8183_is_volatile_reg(struct device *dev, unsigned int reg)
@@ -767,86 +533,46 @@ static bool mt8183_is_volatile_reg(struct device *dev, unsigned int reg)
/* these auto-gen reg has read-only bit, so put it as volatile */
/* volatile reg cannot be cached, so cannot be set when power off */
switch (reg) {
- case AUDIO_TOP_CON0: /* reg bit controlled by CCF */
- case AUDIO_TOP_CON1: /* reg bit controlled by CCF */
+ case AUDIO_TOP_CON0 ... AUDIO_TOP_CON1: /* reg bit controlled by CCF */
case AUDIO_TOP_CON3:
- case AFE_DL1_CUR:
- case AFE_DL1_END:
- case AFE_DL2_CUR:
- case AFE_DL2_END:
- case AFE_AWB_END:
- case AFE_AWB_CUR:
- case AFE_VUL_END:
- case AFE_VUL_CUR:
- case AFE_MEMIF_MON0:
- case AFE_MEMIF_MON1:
- case AFE_MEMIF_MON2:
- case AFE_MEMIF_MON3:
- case AFE_MEMIF_MON4:
- case AFE_MEMIF_MON5:
- case AFE_MEMIF_MON6:
- case AFE_MEMIF_MON7:
- case AFE_MEMIF_MON8:
- case AFE_MEMIF_MON9:
- case AFE_ADDA_SRC_DEBUG_MON0:
- case AFE_ADDA_SRC_DEBUG_MON1:
- case AFE_ADDA_UL_SRC_MON0:
- case AFE_ADDA_UL_SRC_MON1:
+ case AFE_DL1_CUR ... AFE_DL1_END:
+ case AFE_DL2_CUR ... AFE_DL2_END:
+ case AFE_AWB_END ... AFE_AWB_CUR:
+ case AFE_VUL_END ... AFE_VUL_CUR:
+ case AFE_MEMIF_MON0 ... AFE_MEMIF_MON9:
+ case AFE_ADDA_SRC_DEBUG_MON0 ... AFE_ADDA_SRC_DEBUG_MON1:
+ case AFE_ADDA_UL_SRC_MON0 ... AFE_ADDA_UL_SRC_MON1:
case AFE_SIDETONE_MON:
- case AFE_SIDETONE_CON0:
- case AFE_SIDETONE_COEFF:
+ case AFE_SIDETONE_CON0 ... AFE_SIDETONE_COEFF:
case AFE_BUS_MON0:
- case AFE_MRGIF_MON0:
- case AFE_MRGIF_MON1:
- case AFE_MRGIF_MON2:
- case AFE_I2S_MON:
+ case AFE_MRGIF_MON0 ... AFE_I2S_MON:
case AFE_DAC_MON:
- case AFE_VUL2_END:
- case AFE_VUL2_CUR:
- case AFE_IRQ0_MCU_CNT_MON:
- case AFE_IRQ6_MCU_CNT_MON:
- case AFE_MOD_DAI_END:
- case AFE_MOD_DAI_CUR:
- case AFE_VUL_D2_END:
- case AFE_VUL_D2_CUR:
- case AFE_DL3_CUR:
- case AFE_DL3_END:
+ case AFE_VUL2_END ... AFE_VUL2_CUR:
+ case AFE_IRQ0_MCU_CNT_MON ... AFE_IRQ6_MCU_CNT_MON:
+ case AFE_MOD_DAI_END ... AFE_MOD_DAI_CUR:
+ case AFE_VUL_D2_END ... AFE_VUL_D2_CUR:
+ case AFE_DL3_CUR ... AFE_DL3_END:
case AFE_HDMI_OUT_CON0:
- case AFE_HDMI_OUT_CUR:
- case AFE_HDMI_OUT_END:
- case AFE_IRQ3_MCU_CNT_MON:
- case AFE_IRQ4_MCU_CNT_MON:
- case AFE_IRQ_MCU_STATUS:
- case AFE_IRQ_MCU_CLR:
+ case AFE_HDMI_OUT_CUR ... AFE_HDMI_OUT_END:
+ case AFE_IRQ3_MCU_CNT_MON... AFE_IRQ4_MCU_CNT_MON:
+ case AFE_IRQ_MCU_STATUS ... AFE_IRQ_MCU_CLR:
case AFE_IRQ_MCU_MON2:
- case AFE_IRQ1_MCU_CNT_MON:
- case AFE_IRQ2_MCU_CNT_MON:
- case AFE_IRQ1_MCU_EN_CNT_MON:
- case AFE_IRQ5_MCU_CNT_MON:
+ case AFE_IRQ1_MCU_CNT_MON ... AFE_IRQ5_MCU_CNT_MON:
case AFE_IRQ7_MCU_CNT_MON:
case AFE_GAIN1_CUR:
case AFE_GAIN2_CUR:
case AFE_SRAM_DELSEL_CON0:
- case AFE_SRAM_DELSEL_CON2:
- case AFE_SRAM_DELSEL_CON3:
- case AFE_ASRC_2CH_CON12:
- case AFE_ASRC_2CH_CON13:
+ case AFE_SRAM_DELSEL_CON2 ... AFE_SRAM_DELSEL_CON3:
+ case AFE_ASRC_2CH_CON12 ... AFE_ASRC_2CH_CON13:
case PCM_INTF_CON2:
- case FPGA_CFG0:
- case FPGA_CFG1:
- case FPGA_CFG2:
- case FPGA_CFG3:
- case AUDIO_TOP_DBG_MON0:
- case AUDIO_TOP_DBG_MON1:
- case AFE_IRQ8_MCU_CNT_MON:
- case AFE_IRQ11_MCU_CNT_MON:
- case AFE_IRQ12_MCU_CNT_MON:
+ case FPGA_CFG0 ... FPGA_CFG1:
+ case FPGA_CFG2 ... FPGA_CFG3:
+ case AUDIO_TOP_DBG_MON0 ... AUDIO_TOP_DBG_MON1:
+ case AFE_IRQ8_MCU_CNT_MON ... AFE_IRQ12_MCU_CNT_MON:
case AFE_CBIP_MON0:
- case AFE_CBIP_SLV_MUX_MON0:
- case AFE_CBIP_SLV_DECODER_MON0:
+ case AFE_CBIP_SLV_MUX_MON0 ... AFE_CBIP_SLV_DECODER_MON0:
case AFE_ADDA6_SRC_DEBUG_MON0:
- case AFE_ADD6A_UL_SRC_MON0:
- case AFE_ADDA6_UL_SRC_MON1:
+ case AFE_ADD6A_UL_SRC_MON0... AFE_ADDA6_UL_SRC_MON1:
case AFE_DL1_CUR_MSB:
case AFE_DL2_CUR_MSB:
case AFE_AWB_CUR_MSB:
@@ -856,55 +582,23 @@ static bool mt8183_is_volatile_reg(struct device *dev, unsigned int reg)
case AFE_VUL_D2_CUR_MSB:
case AFE_DL3_CUR_MSB:
case AFE_HDMI_OUT_CUR_MSB:
- case AFE_AWB2_END:
- case AFE_AWB2_CUR:
+ case AFE_AWB2_END ... AFE_AWB2_CUR:
case AFE_AWB2_CUR_MSB:
- case AFE_ADDA_DL_SDM_FIFO_MON:
- case AFE_ADDA_DL_SRC_LCH_MON:
- case AFE_ADDA_DL_SRC_RCH_MON:
- case AFE_ADDA_DL_SDM_OUT_MON:
- case AFE_CONNSYS_I2S_MON:
- case AFE_ASRC_2CH_CON0:
- case AFE_ASRC_2CH_CON2:
- case AFE_ASRC_2CH_CON3:
- case AFE_ASRC_2CH_CON4:
- case AFE_ASRC_2CH_CON5:
- case AFE_ASRC_2CH_CON7:
- case AFE_ASRC_2CH_CON8:
- case AFE_MEMIF_MON12:
- case AFE_MEMIF_MON13:
- case AFE_MEMIF_MON14:
- case AFE_MEMIF_MON15:
- case AFE_MEMIF_MON16:
- case AFE_MEMIF_MON17:
- case AFE_MEMIF_MON18:
- case AFE_MEMIF_MON19:
- case AFE_MEMIF_MON20:
- case AFE_MEMIF_MON21:
- case AFE_MEMIF_MON22:
- case AFE_MEMIF_MON23:
- case AFE_MEMIF_MON24:
- case AFE_ADDA_MTKAIF_MON0:
- case AFE_ADDA_MTKAIF_MON1:
+ case AFE_ADDA_DL_SDM_FIFO_MON ... AFE_ADDA_DL_SDM_OUT_MON:
+ case AFE_CONNSYS_I2S_MON ... AFE_ASRC_2CH_CON0:
+ case AFE_ASRC_2CH_CON2 ... AFE_ASRC_2CH_CON5:
+ case AFE_ASRC_2CH_CON7 ... AFE_ASRC_2CH_CON8:
+ case AFE_MEMIF_MON12 ... AFE_MEMIF_MON24:
+ case AFE_ADDA_MTKAIF_MON0 ... AFE_ADDA_MTKAIF_MON1:
case AFE_AUD_PAD_TOP:
case AFE_GENERAL1_ASRC_2CH_CON0:
- case AFE_GENERAL1_ASRC_2CH_CON2:
- case AFE_GENERAL1_ASRC_2CH_CON3:
- case AFE_GENERAL1_ASRC_2CH_CON4:
- case AFE_GENERAL1_ASRC_2CH_CON5:
- case AFE_GENERAL1_ASRC_2CH_CON7:
- case AFE_GENERAL1_ASRC_2CH_CON8:
- case AFE_GENERAL1_ASRC_2CH_CON12:
- case AFE_GENERAL1_ASRC_2CH_CON13:
+ case AFE_GENERAL1_ASRC_2CH_CON2 ... AFE_GENERAL1_ASRC_2CH_CON5:
+ case AFE_GENERAL1_ASRC_2CH_CON7 ... AFE_GENERAL1_ASRC_2CH_CON8:
+ case AFE_GENERAL1_ASRC_2CH_CON12 ... AFE_GENERAL1_ASRC_2CH_CON13:
case AFE_GENERAL2_ASRC_2CH_CON0:
- case AFE_GENERAL2_ASRC_2CH_CON2:
- case AFE_GENERAL2_ASRC_2CH_CON3:
- case AFE_GENERAL2_ASRC_2CH_CON4:
- case AFE_GENERAL2_ASRC_2CH_CON5:
- case AFE_GENERAL2_ASRC_2CH_CON7:
- case AFE_GENERAL2_ASRC_2CH_CON8:
- case AFE_GENERAL2_ASRC_2CH_CON12:
- case AFE_GENERAL2_ASRC_2CH_CON13:
+ case AFE_GENERAL2_ASRC_2CH_CON2 ... AFE_GENERAL2_ASRC_2CH_CON5:
+ case AFE_GENERAL2_ASRC_2CH_CON7 ... AFE_GENERAL2_ASRC_2CH_CON8:
+ case AFE_GENERAL2_ASRC_2CH_CON12 ... AFE_GENERAL2_ASRC_2CH_CON13:
return true;
default:
return false;
@@ -1042,18 +736,6 @@ skip_regmap:
return 0;
}
-static int mt8183_afe_component_probe(struct snd_soc_component *component)
-{
- return mtk_afe_add_sub_dai_control(component);
-}
-
-static const struct snd_soc_component_driver mt8183_afe_component = {
- .name = AFE_PCM_NAME,
- .probe = mt8183_afe_component_probe,
- .pointer = mtk_afe_pcm_pointer,
- .pcm_construct = mtk_afe_pcm_new,
-};
-
static int mt8183_dai_memif_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
@@ -1088,23 +770,31 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
{
struct mtk_base_afe *afe;
struct mt8183_afe_private *afe_priv;
- struct device *dev;
+ struct device *dev = &pdev->dev;
struct reset_control *rstc;
int i, irq_id, ret;
- afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
+ if (ret)
+ return ret;
+
+ 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),
- GFP_KERNEL);
+ 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;
+
+ ret = of_reserved_mem_device_init(dev);
+ if (ret) {
+ dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
+ afe->preallocate_buffers = true;
+ }
/* initial audio related clock */
ret = mt8183_init_clock(afe);
@@ -1143,7 +833,7 @@ static int mt8183_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, &mt8183_afe_regmap_config);
if (ret) {
@@ -1151,7 +841,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
goto err_pm_disable;
}
- 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);
@@ -1209,7 +899,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
ret = dai_register_cbs[i](afe);
if (ret) {
- dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+ dev_warn(dev, "dai register i %d fail, ret %d\n",
i, ret);
goto err_pm_disable;
}
@@ -1218,8 +908,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
/* init dai_driver and component_driver */
ret = mtk_afe_combine_sub_dai(afe);
if (ret) {
- dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
- ret);
+ dev_warn(dev, "mtk_afe_combine_sub_dai fail, ret %d\n", ret);
goto err_pm_disable;
}
@@ -1231,16 +920,14 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
afe->runtime_suspend = mt8183_afe_runtime_suspend;
/* register component */
- ret = devm_snd_soc_register_component(&pdev->dev,
- &mt8183_afe_component,
+ ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
NULL, 0);
if (ret) {
dev_warn(dev, "err_platform\n");
goto err_pm_disable;
}
- ret = devm_snd_soc_register_component(afe->dev,
- &mt8183_afe_pcm_dai_component,
+ ret = devm_snd_soc_register_component(dev, &mt8183_afe_pcm_dai_component,
afe->dai_drivers,
afe->num_dai_drivers);
if (ret) {
@@ -1251,15 +938,17 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
return ret;
err_pm_disable:
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(dev);
return ret;
}
static void mt8183_afe_pcm_dev_remove(struct platform_device *pdev)
{
- pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- mt8183_afe_runtime_suspend(&pdev->dev);
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_disable(dev);
+ if (!pm_runtime_status_suspended(dev))
+ mt8183_afe_runtime_suspend(dev);
}
static const struct of_device_id mt8183_afe_pcm_dt_match[] = {
@@ -1269,18 +958,18 @@ 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_new = mt8183_afe_pcm_dev_remove,
+ .remove = mt8183_afe_pcm_dev_remove,
};
module_platform_driver(mt8183_afe_pcm_driver);
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 87bb04846991..983f3b91119a 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -8,7 +8,7 @@
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
@@ -29,15 +29,30 @@ struct mt8183_da7219_max98357_priv {
struct snd_soc_jack headset_jack, hdmi_jack;
};
+static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
- return snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
+ return snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0),
0, mclk_fs, SND_SOC_CLOCK_OUT);
}
@@ -48,7 +63,7 @@ static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 256;
@@ -56,7 +71,7 @@ static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
unsigned int freq;
int ret = 0, j;
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0,
mclk_fs, SND_SOC_CLOCK_OUT);
if (ret < 0)
dev_err(rtd->dev, "failed to set cpu dai sysclk\n");
@@ -89,7 +104,7 @@ static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
static int mt8183_da7219_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
int ret = 0, j;
@@ -117,7 +132,7 @@ static int
mt8183_da7219_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int rate = params_rate(params);
struct snd_soc_dai *codec_dai;
int ret = 0, i;
@@ -363,12 +378,12 @@ static int mt8183_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_card_get_drvdata(rtd->card);
int ret;
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT,
&priv->hdmi_jack);
if (ret)
return ret;
- return snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component,
+ return snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component,
&priv->hdmi_jack, NULL);
}
@@ -410,7 +425,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8183_da7219_max98357_ops,
SND_SOC_DAILINK_REG(playback1),
},
@@ -420,7 +435,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8183_da7219_max98357_bt_sco_ops,
SND_SOC_DAILINK_REG(playback2),
},
@@ -430,7 +445,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback3),
},
{
@@ -439,7 +454,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &mt8183_da7219_max98357_bt_sco_ops,
SND_SOC_DAILINK_REG(capture1),
},
@@ -449,7 +464,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture2),
},
{
@@ -458,7 +473,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &mt8183_da7219_max98357_ops,
SND_SOC_DAILINK_REG(capture3),
},
@@ -468,7 +483,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_mono),
},
{
@@ -477,38 +492,32 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback_hdmi),
},
/* BE */
{
.name = "Primary Codec",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(primary_codec),
},
{
.name = "PCM 1",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm1),
},
{
.name = "PCM 2",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm2),
},
{
.name = "I2S0",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_i2s_ops,
@@ -517,7 +526,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
{
.name = "I2S1",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_i2s_ops,
@@ -526,7 +535,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
{
.name = "I2S2",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_da7219_i2s_ops,
@@ -536,13 +545,13 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
{
.name = "I2S3",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
},
{
.name = "I2S5",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_i2s_ops,
@@ -554,8 +563,8 @@ 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,
- .dpcm_playback = 1,
+ SND_SOC_DAIFMT_CBP_CFP,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ignore = 1,
@@ -572,13 +581,15 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
snd_soc_card_get_drvdata(component->card);
/* Enable Headset and 4 Buttons Jack detection */
- ret = snd_soc_card_jack_new(component->card,
- "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_LINEOUT,
- &priv->headset_jack);
+ ret = snd_soc_card_jack_new_pins(component->card,
+ "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_LINEOUT,
+ &priv->headset_jack,
+ mt8183_da7219_max98357_jack_pins,
+ ARRAY_SIZE(mt8183_da7219_max98357_jack_pins));
if (ret)
return ret;
@@ -609,12 +620,18 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = {
};
static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphones"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const
struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_SPK("Line Out", NULL),
SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
"aud_tdm_out_on", "aud_tdm_out_off"),
};
@@ -657,14 +674,20 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = {
};
static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphones"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const
struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
"aud_tdm_out_on", "aud_tdm_out_off"),
};
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
index 5b8a274419ed..1f55d9e342ba 100644
--- a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c
@@ -10,6 +10,7 @@
#include "mt8183-afe-common.h"
#include "mt8183-interconnection.h"
#include "mt8183-reg.h"
+#include "../common/mtk-dai-adda-common.h"
enum {
AUDIO_SDM_LEVEL_MUTE = 0,
@@ -18,91 +19,6 @@ enum {
/* you need to change formula of hp impedance and dc trim too */
};
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO2,
-};
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
@@ -197,7 +113,7 @@ static const struct soc_enum mt8183_adda_enum[] = {
static int mt8183_adda_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8183_afe_private *afe_priv = afe->platform_priv;
@@ -209,7 +125,7 @@ static int mt8183_adda_dmic_get(struct snd_kcontrol *kcontrol,
static int mt8183_adda_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8183_afe_private *afe_priv = afe->platform_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -369,7 +285,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
/* set sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28;
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) << 28;
/* set output mode */
switch (rate) {
@@ -420,7 +336,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
0x1 << 0,
0x0 << 0);
- voice_mode = adda_ul_rate_transform(afe, rate);
+ voice_mode = mtk_adda_ul_rate_transform(afe, rate);
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c
index 8645ab686970..3709100a8865 100644
--- a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c
+++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c
@@ -118,7 +118,7 @@ static const struct soc_enum mt8183_i2s_enum[] = {
static int mt8183_i2s_hd_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mtk_afe_i2s_priv *i2s_priv;
@@ -137,7 +137,7 @@ static int mt8183_i2s_hd_get(struct snd_kcontrol *kcontrol,
static int mt8183_i2s_hd_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mtk_afe_i2s_priv *i2s_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -276,13 +276,13 @@ static int mtk_apll_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8183_apll1_enable(afe);
else
mt8183_apll2_enable(afe);
break;
case SND_SOC_DAPM_POST_PMD:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8183_apll1_disable(afe);
else
mt8183_apll2_disable(afe);
@@ -1036,7 +1036,6 @@ static int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe)
int mt8183_dai_i2s_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
- int ret;
dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
if (!dai)
@@ -1055,9 +1054,5 @@ int mt8183_dai_i2s_register(struct mtk_base_afe *afe)
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
/* set all dai i2s private data */
- ret = mt8183_dai_i2s_set_priv(afe);
- if (ret)
- return ret;
-
- return 0;
+ return mt8183_dai_i2s_set_priv(afe);
}
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index ce9aedde7e1e..0bc1f11e17aa 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -7,7 +7,7 @@
// Author: Shunli Wang <shunli.wang@mediatek.com>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
@@ -43,12 +43,12 @@ struct mt8183_mt6358_ts3a227_max98357_priv {
static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
- return snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
+ return snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0),
0, mclk_fs, SND_SOC_CLOCK_OUT);
}
@@ -60,7 +60,7 @@ static int
mt8183_mt6358_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
@@ -84,7 +84,7 @@ mt8183_mt6358_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
}
}
- return snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0),
+ return snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0),
0, mclk_fs, SND_SOC_CLOCK_OUT);
}
@@ -302,7 +302,7 @@ SND_SOC_DAILINK_DEFS(tdm,
static int mt8183_mt6358_tdm_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mt8183_mt6358_ts3a227_max98357_priv *priv =
snd_soc_card_get_drvdata(rtd->card);
int ret;
@@ -321,7 +321,7 @@ static int mt8183_mt6358_tdm_startup(struct snd_pcm_substream *substream)
static void mt8183_mt6358_tdm_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mt8183_mt6358_ts3a227_max98357_priv *priv =
snd_soc_card_get_drvdata(rtd->card);
int ret;
@@ -345,7 +345,7 @@ static int
mt8183_mt6358_ts3a227_max98357_wov_startup(
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct mt8183_mt6358_ts3a227_max98357_priv *priv =
snd_soc_card_get_drvdata(card);
@@ -358,7 +358,7 @@ static void
mt8183_mt6358_ts3a227_max98357_wov_shutdown(
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct mt8183_mt6358_ts3a227_max98357_priv *priv =
snd_soc_card_get_drvdata(card);
@@ -383,12 +383,12 @@ mt8183_mt6358_ts3a227_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_card_get_drvdata(rtd->card);
int ret;
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT,
&priv->hdmi_jack);
if (ret)
return ret;
- return snd_soc_component_set_jack(asoc_rtd_to_codec(rtd, 0)->component,
+ return snd_soc_component_set_jack(snd_soc_rtd_to_codec(rtd, 0)->component,
&priv->hdmi_jack, NULL);
}
@@ -430,7 +430,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8183_mt6358_ops,
SND_SOC_DAILINK_REG(playback1),
},
@@ -440,7 +440,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops,
SND_SOC_DAILINK_REG(playback2),
},
@@ -450,7 +450,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback3),
},
{
@@ -459,7 +459,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops,
SND_SOC_DAILINK_REG(capture1),
},
@@ -469,7 +469,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture2),
},
{
@@ -478,7 +478,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &mt8183_mt6358_ops,
SND_SOC_DAILINK_REG(capture3),
},
@@ -488,7 +488,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_mono),
},
{
@@ -497,7 +497,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback_hdmi),
},
{
@@ -513,31 +513,25 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
{
.name = "Primary Codec",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(primary_codec),
},
{
.name = "PCM 1",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm1),
},
{
.name = "PCM 2",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm2),
},
{
.name = "I2S0",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.ops = &mt8183_mt6358_i2s_ops,
SND_SOC_DAILINK_REG(i2s0),
@@ -545,7 +539,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
{
.name = "I2S1",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_i2s_ops,
@@ -554,7 +548,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
{
.name = "I2S2",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_i2s_ops,
@@ -564,13 +558,13 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
{
.name = "I2S3",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
},
{
.name = "I2S5",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.ops = &mt8183_mt6358_i2s_ops,
.init = &mt8183_bt_init,
@@ -581,8 +575,8 @@ 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,
- .dpcm_playback = 1,
+ SND_SOC_DAIFMT_CBP_CFP,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_tdm_ops,
@@ -592,11 +586,38 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
},
};
+static const
+struct snd_kcontrol_new mt8183_mt6358_ts3a227_max98357_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const
+struct snd_soc_dapm_widget mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static struct snd_soc_jack_pin mt8183_mt6358_ts3a227_max98357_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = {
.name = "mt8183_mt6358_ts3a227_max98357",
.owner = THIS_MODULE,
.dai_link = mt8183_mt6358_ts3a227_dai_links,
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
@@ -604,6 +625,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
.owner = THIS_MODULE,
.dai_link = mt8183_mt6358_ts3a227_dai_links,
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = {
@@ -624,6 +649,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = {
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
.codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf,
.num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = {
@@ -631,6 +660,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = {
.owner = THIS_MODULE,
.dai_link = mt8183_mt6358_ts3a227_dai_links,
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static int
@@ -641,12 +674,14 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component)
snd_soc_card_get_drvdata(component->card);
/* Enable Headset and 4 Buttons Jack detection */
- ret = snd_soc_card_jack_new(component->card,
- "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &priv->headset_jack);
+ ret = snd_soc_card_jack_new_pins(component->card,
+ "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &priv->headset_jack,
+ mt8183_mt6358_ts3a227_max98357_jack_pins,
+ ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_jack_pins));
if (ret)
return ret;
@@ -748,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/Makefile b/sound/soc/mediatek/mt8186/Makefile
index 49b0026628a0..ab3f5b763df8 100644
--- a/sound/soc/mediatek/mt8186/Makefile
+++ b/sound/soc/mediatek/mt8186/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt8186-afe-objs := \
+snd-soc-mt8186-afe-y := \
mt8186-afe-pcm.o \
mt8186-audsys-clk.o \
mt8186-afe-clk.o \
@@ -18,5 +18,4 @@ snd-soc-mt8186-afe-objs := \
mt8186-mt6366-common.o
obj-$(CONFIG_SND_SOC_MT8186) += snd-soc-mt8186-afe.o
-obj-$(CONFIG_SND_SOC_MT8186_MT6366_DA7219_MAX98357) += mt8186-mt6366-da7219-max98357.o
-obj-$(CONFIG_SND_SOC_MT8186_MT6366_RT1019_RT5682S) += mt8186-mt6366-rt1019-rt5682s.o
+obj-$(CONFIG_SND_SOC_MT8186_MT6366) += mt8186-mt6366.o
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
index 539e3a023bc4..daaca36a2d08 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
@@ -13,8 +13,6 @@
#include "mt8186-afe-clk.h"
#include "mt8186-audsys-clk.h"
-static DEFINE_MUTEX(mutex_request_dram);
-
static const char *aud_clks[CLK_NUM] = {
[CLK_AFE] = "aud_afe_clk",
[CLK_DAC] = "aud_dac_clk",
@@ -331,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-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
index f12e91cc4fcf..9e86e7079718 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
@@ -5,7 +5,6 @@
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
-#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include "mt8186-afe-common.h"
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
index a868a04ed4e7..085e993c650d 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <sound/soc.h>
@@ -40,10 +41,10 @@ static const struct snd_pcm_hardware mt8186_afe_hardware = {
static int mt8186_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
int ret;
@@ -82,10 +83,10 @@ static int mt8186_fe_startup(struct snd_pcm_substream *substream,
static void mt8186_fe_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
int irq_id = memif->irq_usage;
@@ -104,9 +105,9 @@ static int mt8186_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
unsigned int channels = params_channels(params);
unsigned int rate = params_rate(params);
int ret;
@@ -153,11 +154,11 @@ static int mt8186_fe_hw_free(struct snd_pcm_substream *substream,
static int mt8186_fe_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
int irq_id = memif->irq_usage;
struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
@@ -252,11 +253,11 @@ static int mt8186_fe_trigger(struct snd_pcm_substream *substream, int cmd,
static int mt8186_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
return mt8186_rate_transform(afe->dev, rate, id);
}
@@ -269,7 +270,7 @@ static int mt8186_get_dai_fs(struct mtk_base_afe *afe,
static int mt8186_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
@@ -290,10 +291,10 @@ static int mt8186_get_memif_pbuf_size(struct snd_pcm_substream *substream)
static int mt8186_fe_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
int irq_id = memif->irq_usage;
struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
@@ -563,7 +564,7 @@ static struct snd_soc_dai_driver mt8186_memif_dai_driver[] = {
static int mt8186_irq_cnt1_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
@@ -576,7 +577,7 @@ static int mt8186_irq_cnt1_get(struct snd_kcontrol *kcontrol,
static int mt8186_irq_cnt1_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int memif_num = MT8186_PRIMARY_MEMIF;
@@ -612,7 +613,7 @@ static int mt8186_irq_cnt1_set(struct snd_kcontrol *kcontrol,
static int mt8186_irq_cnt2_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
@@ -625,7 +626,7 @@ static int mt8186_irq_cnt2_get(struct snd_kcontrol *kcontrol,
static int mt8186_irq_cnt2_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int memif_num = MT8186_RECORD_MEMIF;
@@ -661,7 +662,7 @@ static int mt8186_irq_cnt2_set(struct snd_kcontrol *kcontrol,
static int mt8186_record_xrun_assert_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int xrun_assert = afe_priv->xrun_assert[MT8186_RECORD_MEMIF];
@@ -674,7 +675,7 @@ static int mt8186_record_xrun_assert_get(struct snd_kcontrol *kcontrol,
static int mt8186_record_xrun_assert_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int xrun_assert = ucontrol->value.integer.value[0];
@@ -2815,7 +2816,6 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
{
struct mtk_base_afe *afe;
struct mt8186_afe_private *afe_priv;
- struct resource *res;
struct reset_control *rstc;
struct device *dev = &pdev->dev;
int i, ret, irq_id;
@@ -2836,8 +2836,13 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
afe_priv = afe->platform_priv;
afe->dev = &pdev->dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- afe->base_addr = devm_ioremap_resource(dev, res);
+ ret = of_reserved_mem_device_init(dev);
+ if (ret) {
+ dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
+ afe->preallocate_buffers = true;
+ }
+
+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(afe->base_addr))
return PTR_ERR(afe->base_addr);
@@ -2980,15 +2985,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-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
index 247ab8df941f..e74174ae8873 100644
--- a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
@@ -11,6 +11,7 @@
#include "mt8186-afe-common.h"
#include "mt8186-afe-gpio.h"
#include "mt8186-interconnection.h"
+#include "../common/mtk-dai-adda-common.h"
enum {
UL_IIR_SW = 0,
@@ -33,35 +34,6 @@ enum {
AUDIO_SDM_3RD,
};
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO2,
-};
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
#define SDM_AUTO_RESET_THRESHOLD 0x190000
struct mtk_afe_adda_priv {
@@ -83,64 +55,6 @@ static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
return afe_priv->dai_priv[dai_id];
}
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_dbg(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- }
-
- return MTK_AFE_ADDA_DL_RATE_48K;
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_dbg(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- }
-
- return MTK_AFE_ADDA_UL_RATE_48K;
-}
-
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0),
@@ -321,7 +235,7 @@ static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
BIT(MTKAIF_RXIF_CLKINV_ADC_SFT));
- if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0) {
+ if (snd_soc_dapm_widget_name_cmp(w, "ADDA_MTKAIF_CFG") == 0) {
if (afe_priv->mtkaif_chosen_phase[0] < 0 &&
afe_priv->mtkaif_chosen_phase[1] < 0) {
dev_err(afe->dev,
@@ -410,7 +324,7 @@ static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
@@ -422,7 +336,7 @@ static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol,
static int mt8186_adda_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int dmic_on;
@@ -499,7 +413,7 @@ static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
- 0, 0, 0,
+ AFE_AUD_PAD_TOP, RG_RX_FIFO_ON_SFT, 0,
mtk_adda_pad_top_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
@@ -658,7 +572,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
adda_priv->dl_rate = rate;
/* set sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) <<
DL_2_INPUT_MODE_CTL_SFT;
/* set output mode, UP_SAMPLING_RATE_X8 */
@@ -721,7 +635,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
}
} else {
unsigned int ul_src_con0 = 0;
- unsigned int voice_mode = adda_ul_rate_transform(afe, rate);
+ unsigned int voice_mode = mtk_adda_ul_rate_transform(afe, rate);
adda_priv->ul_rate = rate;
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c
index 33edd6cbde12..75cb30790b1b 100644
--- a/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c
@@ -47,7 +47,7 @@ static int mtk_hw_gain_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) {
+ if (snd_soc_dapm_widget_name_cmp(w, HW_GAIN_1_EN_W_NAME) == 0) {
gain_cur = AFE_GAIN1_CUR;
gain_con1 = AFE_GAIN1_CON1;
} else {
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c
index f07181be4370..f890e9173a07 100644
--- a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c
@@ -113,7 +113,7 @@ static const struct soc_enum mt8186_i2s_enum[] = {
static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mtk_afe_i2s_priv *i2s_priv;
@@ -126,7 +126,7 @@ static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol,
static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mtk_afe_i2s_priv *i2s_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -393,13 +393,13 @@ static int mtk_apll_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8186_apll1_enable(afe);
else
mt8186_apll2_enable(afe);
break;
case SND_SOC_DAPM_POST_PMD:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8186_apll1_disable(afe);
else
mt8186_apll2_disable(afe);
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-src.c b/sound/soc/mediatek/mt8186/mt8186-dai-src.c
index 67989ffd67ca..e475f4591aef 100644
--- a/sound/soc/mediatek/mt8186/mt8186-dai-src.c
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-src.c
@@ -322,7 +322,7 @@ static int mtk_hw_src_event(struct snd_soc_dapm_widget *w,
struct mtk_afe_src_priv *src_priv;
unsigned int reg;
- if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, HW_SRC_1_EN_W_NAME) == 0)
id = MT8186_DAI_SRC_1;
else
id = MT8186_DAI_SRC_2;
@@ -487,7 +487,7 @@ static int mtk_afe_src_en_connect(struct snd_soc_dapm_widget *source,
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_src_priv *src_priv;
- if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, HW_SRC_1_EN_W_NAME) == 0)
src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_1];
else
src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_2];
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c
index 4148dceb3a4c..7a8890d7122f 100644
--- a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c
+++ b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c
@@ -272,7 +272,7 @@ static const struct soc_enum mt8186_tdm_enum[] = {
static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(kcontrol->id.name);
@@ -286,7 +286,7 @@ static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol,
static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id = get_tdm_id_by_name(kcontrol->id.name);
@@ -416,12 +416,10 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON3 */
- tdm_con = 0;
tdm_con = ETDM_IN_CON3_FS(tran_rate);
regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con);
/* ETDM_IN1_CON4 */
- tdm_con = 0;
tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate);
if (slave_mode) {
if (lrck_inv)
diff --git a/sound/soc/mediatek/mt8186/mt8186-misc-control.c b/sound/soc/mediatek/mt8186/mt8186-misc-control.c
index 2317de8c44c0..3b569786306a 100644
--- a/sound/soc/mediatek/mt8186/mt8186-misc-control.c
+++ b/sound/soc/mediatek/mt8186/mt8186-misc-control.c
@@ -74,7 +74,7 @@ static const char * const mt8186_sgen_amp_str[] = {
static int mt8186_sgen_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
@@ -86,7 +86,7 @@ static int mt8186_sgen_get(struct snd_kcontrol *kcontrol,
static int mt8186_sgen_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -128,7 +128,7 @@ static int mt8186_sgen_set(struct snd_kcontrol *kcontrol,
static int mt8186_sgen_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
@@ -140,7 +140,7 @@ static int mt8186_sgen_rate_get(struct snd_kcontrol *kcontrol,
static int mt8186_sgen_rate_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -172,7 +172,7 @@ static int mt8186_sgen_rate_set(struct snd_kcontrol *kcontrol,
static int mt8186_sgen_amplitude_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
@@ -183,7 +183,7 @@ static int mt8186_sgen_amplitude_get(struct snd_kcontrol *kcontrol,
static int mt8186_sgen_amplitude_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c
index 4e66603d4cdb..e325d216c008 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c
@@ -18,10 +18,10 @@ int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
- struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(rtd->card);
int ret;
/* set mtkaif protocol */
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
deleted file mode 100644
index 0432f9d89020..000000000000
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
+++ /dev/null
@@ -1,1183 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// mt8186-mt6366-da7219-max98357.c
-// -- MT8186-MT6366-DA7219-MAX98357 ALSA SoC machine driver
-//
-// Copyright (c) 2022 MediaTek Inc.
-// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
-//
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "../../codecs/da7219.h"
-#include "../../codecs/mt6358.h"
-#include "../common/mtk-afe-platform-driver.h"
-#include "../common/mtk-dsp-sof-common.h"
-#include "../common/mtk-soc-card.h"
-#include "mt8186-afe-common.h"
-#include "mt8186-afe-clk.h"
-#include "mt8186-afe-gpio.h"
-#include "mt8186-mt6366-common.h"
-
-#define DA7219_CODEC_DAI "da7219-hifi"
-#define DA7219_DEV_NAME "da7219.5-001a"
-
-#define SOF_DMA_DL1 "SOF_DMA_DL1"
-#define SOF_DMA_DL2 "SOF_DMA_DL2"
-#define SOF_DMA_UL1 "SOF_DMA_UL1"
-#define SOF_DMA_UL2 "SOF_DMA_UL2"
-
-struct mt8186_mt6366_da7219_max98357_priv {
- struct snd_soc_jack headset_jack, hdmi_jack;
-};
-
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin mt8186_jack_pins[] = {
- {
- .pin = "Headphones",
- .mask = SND_JACK_HEADPHONE,
- },
- {
- .pin = "Headset Mic",
- .mask = SND_JACK_MICROPHONE,
- },
-};
-
-static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = {
- {
- .dlc = COMP_CODEC_CONF("mt6358-sound"),
- .name_prefix = "Mt6366",
- },
- {
- .dlc = COMP_CODEC_CONF("bt-sco"),
- .name_prefix = "Mt8186 bt",
- },
- {
- .dlc = COMP_CODEC_CONF("hdmi-audio-codec"),
- .name_prefix = "Mt8186 hdmi",
- },
-};
-
-static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *cmpnt_afe =
- snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
- struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
- struct mtk_soc_card_data *soc_card_data =
- snd_soc_card_get_drvdata(rtd->card);
- struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv;
- struct snd_soc_jack *jack = &priv->headset_jack;
- struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
- int ret;
-
- ret = mt8186_dai_i2s_set_share(afe, "I2S1", "I2S0");
- if (ret) {
- dev_err(rtd->dev, "Failed to set up shared clocks\n");
- return ret;
- }
-
- /* Enable Headset and 4 Buttons Jack detection */
- 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 | SND_JACK_LINEOUT,
- jack, mt8186_jack_pins,
- ARRAY_SIZE(mt8186_jack_pins));
- if (ret) {
- dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
- return ret;
- }
-
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
-
- snd_soc_component_set_jack(cmpnt_codec, &priv->headset_jack, NULL);
-
- return 0;
-}
-
-static int mt8186_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- unsigned int rate = params_rate(params);
- unsigned int mclk_fs_ratio = 256;
- unsigned int mclk_fs = rate * mclk_fs_ratio;
- unsigned int freq;
- int ret, j;
-
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0,
- mclk_fs, SND_SOC_CLOCK_OUT);
- if (ret < 0) {
- dev_err(rtd->dev, "failed to set cpu dai sysclk: %d\n", ret);
- return ret;
- }
-
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) {
- ret = snd_soc_dai_set_sysclk(codec_dai,
- DA7219_CLKSRC_MCLK,
- mclk_fs,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(rtd->dev, "failed to set sysclk: %d\n",
- ret);
- return ret;
- }
-
- if ((rate % 8000) == 0)
- freq = DA7219_PLL_FREQ_OUT_98304;
- else
- freq = DA7219_PLL_FREQ_OUT_90316;
-
- ret = snd_soc_dai_set_pll(codec_dai, 0,
- DA7219_SYSCLK_PLL_SRM,
- 0, freq);
- if (ret) {
- dev_err(rtd->dev, "failed to start PLL: %d\n",
- ret);
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static int mt8186_da7219_i2s_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai;
- int ret = 0, j;
-
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) {
- ret = snd_soc_dai_set_pll(codec_dai,
- 0, DA7219_SYSCLK_MCLK, 0, 0);
- if (ret < 0) {
- dev_err(rtd->dev, "failed to stop PLL: %d\n",
- ret);
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8186_da7219_i2s_ops = {
- .hw_params = mt8186_da7219_i2s_hw_params,
- .hw_free = mt8186_da7219_i2s_hw_free,
-};
-
-static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *cmpnt_afe =
- snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
- struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
- struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
- struct mtk_soc_card_data *soc_card_data =
- snd_soc_card_get_drvdata(rtd->card);
- struct mt8186_mt6366_da7219_max98357_priv *priv = soc_card_data->mach_priv;
- int ret;
-
- ret = mt8186_dai_i2s_set_share(afe, "I2S2", "I2S3");
- if (ret) {
- dev_err(rtd->dev, "Failed to set up shared clocks\n");
- return ret;
- }
-
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack);
- if (ret) {
- dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
- return ret;
- }
-
- return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
-}
-
-static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params,
- snd_pcm_format_t fmt)
-{
- struct snd_interval *channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
-
- dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt);
-
- /* fix BE i2s channel to 2 channel */
- channels->min = 2;
- channels->max = 2;
-
- /* clean param mask first */
- snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
-
- params_set_format(params, fmt);
-
- return 0;
-}
-
-static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE);
-}
-
-static int mt8186_anx7625_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
-}
-
-/* fixup the BE DAI link to match any values from topology */
-static int mt8186_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
-{
- int ret;
-
- ret = mtk_sof_dai_link_fixup(rtd, params);
-
- if (!strcmp(rtd->dai_link->name, "I2S0") ||
- !strcmp(rtd->dai_link->name, "I2S1") ||
- !strcmp(rtd->dai_link->name, "I2S2"))
- mt8186_i2s_hw_params_fixup(rtd, params);
- else if (!strcmp(rtd->dai_link->name, "I2S3"))
- mt8186_anx7625_i2s_hw_params_fixup(rtd, params);
-
- return ret;
-}
-
-static int mt8186_mt6366_da7219_max98357_playback_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8186_mt6366_da7219_max98357_playback_ops = {
- .startup = mt8186_mt6366_da7219_max98357_playback_startup,
-};
-
-static int mt8186_mt6366_da7219_max98357_capture_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 1, 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8186_mt6366_da7219_max98357_capture_ops = {
- .startup = mt8186_mt6366_da7219_max98357_capture_startup,
-};
-
-/* FE */
-SND_SOC_DAILINK_DEFS(playback1,
- DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback12,
- DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback2,
- DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback3,
- DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback4,
- DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback5,
- DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback6,
- DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback7,
- DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(playback8,
- DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture1,
- DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture2,
- DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture3,
- DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture4,
- DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture5,
- DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture6,
- DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture7,
- DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-/* hostless */
-SND_SOC_DAILINK_DEFS(hostless_lpbk,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_fm,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_src1,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_src_bargein,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-/* BE */
-SND_SOC_DAILINK_DEFS(adda,
- DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
- DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound",
- "mt6358-snd-codec-aif1"),
- COMP_CODEC("dmic-codec",
- "dmic-hifi")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(i2s0,
- DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(i2s1,
- DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(i2s2,
- DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(i2s3,
- DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hw_gain1,
- DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hw_gain2,
- DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hw_src1,
- DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hw_src2,
- DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(connsys_i2s,
- DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(pcm1,
- DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
- DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(tdm_in,
- DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-/* hostless */
-SND_SOC_DAILINK_DEFS(hostless_ul1,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_ul2,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_ul3,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_ul5,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_ul6,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(hostless_src_aaudio,
- DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-SND_SOC_DAILINK_DEFS(AFE_SOF_DL1,
- DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL1")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(AFE_SOF_DL2,
- DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(AFE_SOF_UL1,
- DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL1")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(AFE_SOF_UL2,
- DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL2")),
- DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-static const struct sof_conn_stream g_sof_conn_streams[] = {
- { "I2S1", "AFE_SOF_DL1", SOF_DMA_DL1, SNDRV_PCM_STREAM_PLAYBACK},
- { "I2S3", "AFE_SOF_DL2", SOF_DMA_DL2, SNDRV_PCM_STREAM_PLAYBACK},
- { "Primary Codec", "AFE_SOF_UL1", SOF_DMA_UL1, SNDRV_PCM_STREAM_CAPTURE},
- { "I2S0", "AFE_SOF_UL2", SOF_DMA_UL2, SNDRV_PCM_STREAM_CAPTURE},
-};
-
-static struct snd_soc_dai_link mt8186_mt6366_da7219_max98357_dai_links[] = {
- /* Front End DAI links */
- {
- .name = "Playback_1",
- .stream_name = "Playback_1",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_merged_format = 1,
- .dpcm_merged_chan = 1,
- .dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_da7219_max98357_playback_ops,
- SND_SOC_DAILINK_REG(playback1),
- },
- {
- .name = "Playback_12",
- .stream_name = "Playback_12",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(playback12),
- },
- {
- .name = "Playback_2",
- .stream_name = "Playback_2",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_merged_format = 1,
- .dpcm_merged_chan = 1,
- .dpcm_merged_rate = 1,
- SND_SOC_DAILINK_REG(playback2),
- },
- {
- .name = "Playback_3",
- .stream_name = "Playback_3",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_merged_format = 1,
- .dpcm_merged_chan = 1,
- .dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_da7219_max98357_playback_ops,
- SND_SOC_DAILINK_REG(playback3),
- },
- {
- .name = "Playback_4",
- .stream_name = "Playback_4",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(playback4),
- },
- {
- .name = "Playback_5",
- .stream_name = "Playback_5",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(playback5),
- },
- {
- .name = "Playback_6",
- .stream_name = "Playback_6",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(playback6),
- },
- {
- .name = "Playback_7",
- .stream_name = "Playback_7",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(playback7),
- },
- {
- .name = "Playback_8",
- .stream_name = "Playback_8",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(playback8),
- },
- {
- .name = "Capture_1",
- .stream_name = "Capture_1",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(capture1),
- },
- {
- .name = "Capture_2",
- .stream_name = "Capture_2",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- .dpcm_merged_format = 1,
- .dpcm_merged_chan = 1,
- .dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_da7219_max98357_capture_ops,
- SND_SOC_DAILINK_REG(capture2),
- },
- {
- .name = "Capture_3",
- .stream_name = "Capture_3",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(capture3),
- },
- {
- .name = "Capture_4",
- .stream_name = "Capture_4",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- .dpcm_merged_format = 1,
- .dpcm_merged_chan = 1,
- .dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_da7219_max98357_capture_ops,
- SND_SOC_DAILINK_REG(capture4),
- },
- {
- .name = "Capture_5",
- .stream_name = "Capture_5",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(capture5),
- },
- {
- .name = "Capture_6",
- .stream_name = "Capture_6",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- .dpcm_merged_format = 1,
- .dpcm_merged_chan = 1,
- .dpcm_merged_rate = 1,
- SND_SOC_DAILINK_REG(capture6),
- },
- {
- .name = "Capture_7",
- .stream_name = "Capture_7",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(capture7),
- },
- {
- .name = "Hostless_LPBK",
- .stream_name = "Hostless_LPBK",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_lpbk),
- },
- {
- .name = "Hostless_FM",
- .stream_name = "Hostless_FM",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_fm),
- },
- {
- .name = "Hostless_SRC_1",
- .stream_name = "Hostless_SRC_1",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_src1),
- },
- {
- .name = "Hostless_SRC_Bargein",
- .stream_name = "Hostless_SRC_Bargein",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_src_bargein),
- },
- {
- .name = "Hostless_HW_Gain_AAudio",
- .stream_name = "Hostless_HW_Gain_AAudio",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio),
- },
- {
- .name = "Hostless_SRC_AAudio",
- .stream_name = "Hostless_SRC_AAudio",
- .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
- SND_SOC_DPCM_TRIGGER_PRE},
- .dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_src_aaudio),
- },
- /* Back End DAI links */
- {
- .name = "Primary Codec",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- .init = mt8186_mt6366_init,
- SND_SOC_DAILINK_REG(adda),
- },
- {
- .name = "I2S3",
- .no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_IB_IF |
- SND_SOC_DAIFMT_CBM_CFM,
- .dpcm_playback = 1,
- .ignore_suspend = 1,
- .init = mt8186_mt6366_da7219_max98357_hdmi_init,
- .be_hw_params_fixup = mt8186_anx7625_i2s_hw_params_fixup,
- SND_SOC_DAILINK_REG(i2s3),
- },
- {
- .name = "I2S0",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
- .ops = &mt8186_da7219_i2s_ops,
- SND_SOC_DAILINK_REG(i2s0),
- },
- {
- .name = "I2S1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .ignore_suspend = 1,
- .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
- .init = mt8186_da7219_init,
- .ops = &mt8186_da7219_i2s_ops,
- SND_SOC_DAILINK_REG(i2s1),
- },
- {
- .name = "I2S2",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
- SND_SOC_DAILINK_REG(i2s2),
- },
- {
- .name = "HW Gain 1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hw_gain1),
- },
- {
- .name = "HW Gain 2",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hw_gain2),
- },
- {
- .name = "HW_SRC_1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hw_src1),
- },
- {
- .name = "HW_SRC_2",
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hw_src2),
- },
- {
- .name = "CONNSYS_I2S",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(connsys_i2s),
- },
- {
- .name = "PCM 1",
- .dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_IF,
- .no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(pcm1),
- },
- {
- .name = "TDM IN",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(tdm_in),
- },
- /* dummy BE for ul memif to record from dl memif */
- {
- .name = "Hostless_UL1",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_ul1),
- },
- {
- .name = "Hostless_UL2",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_ul2),
- },
- {
- .name = "Hostless_UL3",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_ul3),
- },
- {
- .name = "Hostless_UL5",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_ul5),
- },
- {
- .name = "Hostless_UL6",
- .no_pcm = 1,
- .dpcm_capture = 1,
- .ignore_suspend = 1,
- SND_SOC_DAILINK_REG(hostless_ul6),
- },
- /* SOF BE */
- {
- .name = "AFE_SOF_DL1",
- .no_pcm = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(AFE_SOF_DL1),
- },
- {
- .name = "AFE_SOF_DL2",
- .no_pcm = 1,
- .dpcm_playback = 1,
- SND_SOC_DAILINK_REG(AFE_SOF_DL2),
- },
- {
- .name = "AFE_SOF_UL1",
- .no_pcm = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(AFE_SOF_UL1),
- },
- {
- .name = "AFE_SOF_UL2",
- .no_pcm = 1,
- .dpcm_capture = 1,
- SND_SOC_DAILINK_REG(AFE_SOF_UL2),
- },
-};
-
-static const struct snd_soc_dapm_widget
-mt8186_mt6366_da7219_max98357_widgets[] = {
- SND_SOC_DAPM_SPK("Speakers", NULL),
- SND_SOC_DAPM_HP("Headphones", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_OUTPUT("HDMI1"),
- SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER(SOF_DMA_UL1, SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER(SOF_DMA_UL2, SND_SOC_NOPM, 0, 0, NULL, 0),
-};
-
-static const struct snd_soc_dapm_route
-mt8186_mt6366_da7219_max98357_routes[] = {
- /* SPK */
- { "Speakers", NULL, "Speaker"},
- /* Headset */
- { "Headphones", NULL, "HPL" },
- { "Headphones", NULL, "HPR" },
- { "MIC", NULL, "Headset Mic" },
- /* HDMI */
- { "HDMI1", NULL, "TX"},
- /* SOF Uplink */
- {SOF_DMA_UL1, NULL, "UL1_CH1"},
- {SOF_DMA_UL1, NULL, "UL1_CH2"},
- {SOF_DMA_UL2, NULL, "UL2_CH1"},
- {SOF_DMA_UL2, NULL, "UL2_CH2"},
- /* SOF Downlink */
- {"DSP_DL1_VIRT", NULL, SOF_DMA_DL1},
- {"DSP_DL2_VIRT", NULL, SOF_DMA_DL2},
-};
-
-static const struct snd_kcontrol_new
-mt8186_mt6366_da7219_max98357_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speakers"),
- SOC_DAPM_PIN_SWITCH("Headphones"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("HDMI1"),
-};
-
-static struct snd_soc_card mt8186_mt6366_da7219_max98357_soc_card = {
- .name = "mt8186_da7219_max98357",
- .owner = THIS_MODULE,
- .dai_link = mt8186_mt6366_da7219_max98357_dai_links,
- .num_links = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links),
- .controls = mt8186_mt6366_da7219_max98357_controls,
- .num_controls = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_controls),
- .dapm_widgets = mt8186_mt6366_da7219_max98357_widgets,
- .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_widgets),
- .dapm_routes = mt8186_mt6366_da7219_max98357_routes,
- .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_routes),
- .codec_conf = mt8186_mt6366_da7219_max98357_codec_conf,
- .num_configs = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_codec_conf),
-};
-
-static int mt8186_mt6366_da7219_max98357_dev_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card;
- struct snd_soc_dai_link *dai_link;
- struct mtk_soc_card_data *soc_card_data;
- struct mt8186_mt6366_da7219_max98357_priv *mach_priv;
- struct device_node *platform_node, *headset_codec, *playback_codec, *adsp_node;
- int sof_on = 0;
- int ret, i;
-
- card = (struct snd_soc_card *)device_get_match_data(&pdev->dev);
- if (!card)
- return -EINVAL;
- card->dev = &pdev->dev;
-
- soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*soc_card_data), GFP_KERNEL);
- if (!soc_card_data)
- return -ENOMEM;
- mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL);
- if (!mach_priv)
- return -ENOMEM;
-
- soc_card_data->mach_priv = mach_priv;
-
- adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
- if (adsp_node) {
- struct mtk_sof_priv *sof_priv;
-
- sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL);
- if (!sof_priv) {
- ret = -ENOMEM;
- goto err_adsp_node;
- }
- sof_priv->conn_streams = g_sof_conn_streams;
- sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams);
- sof_priv->sof_dai_link_fixup = mt8186_sof_dai_link_fixup;
- soc_card_data->sof_priv = sof_priv;
- card->probe = mtk_sof_card_probe;
- card->late_probe = mtk_sof_card_late_probe;
- if (!card->topology_shortname_created) {
- snprintf(card->topology_shortname, 32, "sof-%s", card->name);
- card->topology_shortname_created = true;
- }
- card->name = card->topology_shortname;
- sof_on = 1;
- } else {
- dev_dbg(&pdev->dev, "Probe without adsp\n");
- }
-
- if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) {
- ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node,
- "mediatek,dai-link",
- mt8186_mt6366_da7219_max98357_dai_links,
- ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links));
- if (ret) {
- dev_dbg(&pdev->dev, "Parse dai-link fail\n");
- goto err_adsp_node;
- }
- } else {
- if (!sof_on)
- card->num_links = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links)
- - ARRAY_SIZE(g_sof_conn_streams);
- }
-
- platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
- if (!platform_node) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
- goto err_platform_node;
- }
-
- playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs");
- if (!playback_codec) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n");
- goto err_playback_codec;
- }
-
- headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec");
- if (!headset_codec) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n");
- goto err_headset_codec;
- }
-
- for_each_card_prelinks(card, i, dai_link) {
- ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3");
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n",
- dai_link->name);
- goto err_probe;
- }
-
- ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0");
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
- dai_link->name);
- goto err_probe;
- }
-
- ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1");
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
- dai_link->name);
- goto err_probe;
- }
-
- if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on)
- dai_link->platforms->of_node = adsp_node;
-
- if (!dai_link->platforms->name && !dai_link->platforms->of_node)
- dai_link->platforms->of_node = platform_node;
- }
-
- snd_soc_card_set_drvdata(card, soc_card_data);
-
- ret = mt8186_afe_gpio_init(&pdev->dev);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__);
- goto err_probe;
- }
-
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret)
- dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
-
-err_probe:
- of_node_put(headset_codec);
-err_headset_codec:
- of_node_put(playback_codec);
-err_playback_codec:
- of_node_put(platform_node);
-err_platform_node:
-err_adsp_node:
- of_node_put(adsp_node);
-
- return ret;
-}
-
-#if IS_ENABLED(CONFIG_OF)
-static const struct of_device_id mt8186_mt6366_da7219_max98357_dt_match[] = {
- { .compatible = "mediatek,mt8186-mt6366-da7219-max98357-sound",
- .data = &mt8186_mt6366_da7219_max98357_soc_card,
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, mt8186_mt6366_da7219_max98357_dt_match);
-#endif
-
-static struct platform_driver mt8186_mt6366_da7219_max98357_driver = {
- .driver = {
- .name = "mt8186_mt6366_da7219_max98357",
-#if IS_ENABLED(CONFIG_OF)
- .of_match_table = mt8186_mt6366_da7219_max98357_dt_match,
-#endif
- .pm = &snd_soc_pm_ops,
- },
- .probe = mt8186_mt6366_da7219_max98357_dev_probe,
-};
-
-module_platform_driver(mt8186_mt6366_da7219_max98357_driver);
-
-/* Module information */
-MODULE_DESCRIPTION("MT8186-MT6366-DA7219-MAX98357 ALSA SoC machine driver");
-MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("mt8186_mt6366_da7219_max98357 soc card");
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
index 9c11016f032c..2c3033f305ea 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
@@ -1,27 +1,31 @@
// SPDX-License-Identifier: GPL-2.0
//
-// mt8186-mt6366-rt1019-rt5682s.c
-// -- MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver
+// mt8186-mt6366.c
+// -- MT8186-MT6366 ALSA SoC machine driver
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
//
+// Copyright (c) 2024 Collabora Ltd.
+// AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+//
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/rt5682.h>
#include <sound/soc.h>
+#include "../../codecs/da7219.h"
#include "../../codecs/mt6358.h"
#include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-dsp-sof-common.h"
#include "../common/mtk-soc-card.h"
+#include "../common/mtk-soundcard-driver.h"
#include "mt8186-afe-common.h"
#include "mt8186-afe-clk.h"
#include "mt8186-afe-gpio.h"
@@ -33,17 +37,27 @@
#define RT5682S_CODEC_DAI "rt5682s-aif1"
#define RT5682S_DEV0_NAME "rt5682s.5-001a"
+#define DA7219_CODEC_DAI "da7219-hifi"
+#define DA7219_DEV_NAME "da7219.5-001a"
+
#define SOF_DMA_DL1 "SOF_DMA_DL1"
#define SOF_DMA_DL2 "SOF_DMA_DL2"
#define SOF_DMA_UL1 "SOF_DMA_UL1"
#define SOF_DMA_UL2 "SOF_DMA_UL2"
+#define DA7219_CODEC_PRESENT BIT(0)
+
struct mt8186_mt6366_rt1019_rt5682s_priv {
- struct snd_soc_jack headset_jack, hdmi_jack;
struct gpio_desc *dmic_sel;
int dmic_switch;
};
+enum mt8186_jacks {
+ MT8186_JACK_HEADSET,
+ MT8186_JACK_HDMI,
+ MT8186_JACK_MAX,
+};
+
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin mt8186_jack_pins[] = {
{
@@ -74,9 +88,9 @@ static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = {
static int dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct mtk_soc_card_data *soc_card_data =
- snd_soc_card_get_drvdata(dapm->card);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
ucontrol->value.integer.value[0] = priv->dmic_switch;
@@ -86,15 +100,15 @@ static int dmic_get(struct snd_kcontrol *kcontrol,
static int dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct mtk_soc_card_data *soc_card_data =
- snd_soc_card_get_drvdata(dapm->card);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
priv->dmic_switch = ucontrol->value.integer.value[0];
if (priv->dmic_sel) {
gpiod_set_value(priv->dmic_sel, priv->dmic_switch);
- dev_dbg(dapm->card->dev, "dmic_set_value %d\n",
+ dev_dbg(card->dev, "dmic_set_value %d\n",
priv->dmic_switch);
}
return 0;
@@ -126,6 +140,7 @@ static const struct snd_soc_dapm_route dmic_map[] = {
static int primary_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
int ret;
@@ -142,7 +157,7 @@ static int primary_codec_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, dmic_widgets,
ARRAY_SIZE(dmic_widgets));
if (ret) {
dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
@@ -150,7 +165,7 @@ static int primary_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+ ret = snd_soc_dapm_add_routes(dapm, dmic_map,
ARRAY_SIZE(dmic_map));
if (ret)
@@ -159,18 +174,25 @@ static int primary_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
+static int mt8186_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mtk_soc_card_data *soc_card_data =
snd_soc_card_get_drvdata(rtd->card);
- struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
- struct snd_soc_jack *jack = &priv->headset_jack;
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8186_JACK_HEADSET];
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
+ const int hs_keys_rt5682[] = {
+ KEY_PLAYPAUSE, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_VOICECOMMAND
+ };
+ const int hs_keys_da7219[] = {
+ KEY_PLAYPAUSE, KEY_VOICECOMMAND, KEY_VOLUMEUP, KEY_VOLUMEDOWN
+ };
+ const int *hs_keys;
int ret;
+ int type;
ret = mt8186_dai_i2s_set_share(afe, "I2S1", "I2S0");
if (ret) {
@@ -189,21 +211,97 @@ static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ if (soc_card_data->card_data->flags & DA7219_CODEC_PRESENT)
+ hs_keys = hs_keys_da7219;
+ else
+ hs_keys = hs_keys_rt5682;
- return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, hs_keys[0]);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, hs_keys[1]);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, hs_keys[2]);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, hs_keys[3]);
+
+ type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3;
+ return snd_soc_component_set_jack(cmpnt_codec, jack, (void *)&type);
}
+static int mt8186_da7219_i2s_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 = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 256;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ unsigned int freq;
+ int ret, j;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to set cpu dai sysclk: %d\n", ret);
+ return ret;
+ }
+
+ for_each_rtd_codec_dais(rtd, j, codec_dai) {
+ if (strcmp(codec_dai->component->name, DA7219_DEV_NAME))
+ continue;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK,
+ mclk_fs, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to set sysclk: %d\n", ret);
+ return ret;
+ }
+
+ if ((rate % 8000) == 0)
+ freq = DA7219_PLL_FREQ_OUT_98304;
+ else
+ freq = DA7219_PLL_FREQ_OUT_90316;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+ 0, freq);
+ if (ret) {
+ dev_err(rtd->dev, "failed to start PLL: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mt8186_da7219_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ int j, ret;
+
+ for_each_rtd_codec_dais(rtd, j, codec_dai) {
+ if (strcmp(codec_dai->component->name, DA7219_DEV_NAME))
+ continue;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to stop PLL: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8186_da7219_i2s_ops = {
+ .hw_params = mt8186_da7219_i2s_hw_params,
+ .hw_free = mt8186_da7219_i2s_hw_free,
+};
+
static int mt8186_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
@@ -253,10 +351,10 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
struct mtk_soc_card_data *soc_card_data =
snd_soc_card_get_drvdata(rtd->card);
- struct mt8186_mt6366_rt1019_rt5682s_priv *priv = soc_card_data->mach_priv;
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8186_JACK_HDMI];
int ret;
ret = mt8186_dai_i2s_set_share(afe, "I2S2", "I2S3");
@@ -265,13 +363,13 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt
return ret;
}
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack);
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack);
if (ret) {
dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
return ret;
}
- return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+ return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
}
static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -296,14 +394,14 @@ static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
+static int mt8186_i2s_hw_params_24le_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
{
return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
}
-static int mt8186_it6505_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
+static int mt8186_i2s_hw_params_32le_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
{
return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE);
}
@@ -312,112 +410,28 @@ static int mt8186_it6505_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int mt8186_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
int ret;
ret = mtk_sof_dai_link_fixup(rtd, params);
if (!strcmp(rtd->dai_link->name, "I2S0") ||
!strcmp(rtd->dai_link->name, "I2S1") ||
- !strcmp(rtd->dai_link->name, "I2S2"))
- mt8186_i2s_hw_params_fixup(rtd, params);
- else if (!strcmp(rtd->dai_link->name, "I2S3"))
- mt8186_it6505_i2s_hw_params_fixup(rtd, params);
-
- return ret;
-}
-
-static int mt8186_mt6366_rt1019_rt5682s_playback_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
+ !strcmp(rtd->dai_link->name, "I2S2")) {
+ if (soc_card_data->card_data->flags & DA7219_CODEC_PRESENT)
+ mt8186_i2s_hw_params_32le_fixup(rtd, params);
+ else
+ mt8186_i2s_hw_params_24le_fixup(rtd, params);
+ } else if (!strcmp(rtd->dai_link->name, "I2S3")) {
+ if (soc_card_data->card_data->flags & DA7219_CODEC_PRESENT)
+ mt8186_i2s_hw_params_24le_fixup(rtd, params);
+ else
+ mt8186_i2s_hw_params_32le_fixup(rtd, params);
}
- return 0;
-}
-
-static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_playback_ops = {
- .startup = mt8186_mt6366_rt1019_rt5682s_playback_startup,
-};
-
-static int mt8186_mt6366_rt1019_rt5682s_capture_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 1, 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
- }
-
- return 0;
+ return ret;
}
-static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_capture_ops = {
- .startup = mt8186_mt6366_rt1019_rt5682s_capture_startup,
-};
-
/* FE */
SND_SOC_DAILINK_DEFS(playback1,
DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
@@ -634,11 +648,11 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(playback1),
},
{
@@ -647,7 +661,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback12),
},
{
@@ -656,7 +670,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
@@ -668,11 +682,11 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(playback3),
},
{
@@ -681,7 +695,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback4),
},
{
@@ -690,7 +704,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback5),
},
{
@@ -699,7 +713,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback6),
},
{
@@ -708,7 +722,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback7),
},
{
@@ -717,7 +731,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback8),
},
{
@@ -726,7 +740,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture1),
},
{
@@ -735,11 +749,11 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(capture2),
},
{
@@ -748,7 +762,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture3),
},
{
@@ -757,11 +771,11 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
- .ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(capture4),
},
{
@@ -770,7 +784,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture5),
},
{
@@ -779,7 +793,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
@@ -791,7 +805,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture7),
},
{
@@ -800,8 +814,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_lpbk),
},
@@ -811,8 +823,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_fm),
},
@@ -822,8 +832,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_src1),
},
@@ -833,8 +841,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_src_bargein),
},
@@ -844,7 +850,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio),
},
@@ -854,8 +860,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_src_aaudio),
},
@@ -863,8 +867,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
{
.name = "Primary Codec",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
.init = primary_codec_init,
SND_SOC_DAILINK_REG(adda),
@@ -874,76 +876,63 @@ 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,
- .dpcm_playback = 1,
+ SND_SOC_DAIFMT_CBP_CFP,
+ .playback_only = 1,
.ignore_suspend = 1,
.init = mt8186_mt6366_rt1019_rt5682s_hdmi_init,
- .be_hw_params_fixup = mt8186_it6505_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s3),
},
{
.name = "I2S0",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
- .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
.ops = &mt8186_rt5682s_i2s_ops,
SND_SOC_DAILINK_REG(i2s0),
},
{
.name = "I2S1",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
- .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
- .init = mt8186_rt5682s_init,
- .ops = &mt8186_rt5682s_i2s_ops,
+ .init = mt8186_headset_codec_init,
SND_SOC_DAILINK_REG(i2s1),
},
{
.name = "I2S2",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
- .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s2),
},
{
.name = "HW Gain 1",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_gain1),
},
{
.name = "HW Gain 2",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_gain2),
},
{
.name = "HW_SRC_1",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_src1),
},
{
.name = "HW_SRC_2",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_src2),
},
{
.name = "CONNSYS_I2S",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(connsys_i2s),
},
@@ -952,15 +941,13 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_IF,
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm1),
},
{
.name = "TDM IN",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(tdm_in),
},
@@ -968,35 +955,35 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
{
.name = "Hostless_UL1",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul1),
},
{
.name = "Hostless_UL2",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul2),
},
{
.name = "Hostless_UL3",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul3),
},
{
.name = "Hostless_UL5",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul5),
},
{
.name = "Hostless_UL6",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul6),
},
@@ -1004,30 +991,43 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
{
.name = "AFE_SOF_DL1",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(AFE_SOF_DL1),
},
{
.name = "AFE_SOF_DL2",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(AFE_SOF_DL2),
},
{
.name = "AFE_SOF_UL1",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(AFE_SOF_UL1),
},
{
.name = "AFE_SOF_UL2",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(AFE_SOF_UL2),
},
};
static const struct snd_soc_dapm_widget
+mt8186_mt6366_da7219_max98357_widgets[] = {
+ SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_LINE("HDMI1", NULL),
+ SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER(SOF_DMA_UL1, SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER(SOF_DMA_UL2, SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget
mt8186_mt6366_rt1019_rt5682s_widgets[] = {
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_HP("Headphone", NULL),
@@ -1059,6 +1059,35 @@ mt8186_mt6366_rt1019_rt5682s_routes[] = {
{"DSP_DL2_VIRT", NULL, SOF_DMA_DL2},
};
+static const struct snd_soc_dapm_route mt8186_mt6366_rt5650_routes[] = {
+ /* SPK */
+ {"Speakers", NULL, "SPOL"},
+ {"Speakers", NULL, "SPOR"},
+ /* Headset */
+ { "Headphone", NULL, "HPOL" },
+ { "Headphone", NULL, "HPOR" },
+ { "IN1P", NULL, "Headset Mic" },
+ { "IN1N", NULL, "Headset Mic"},
+ /* HDMI */
+ { "HDMI1", NULL, "TX" },
+ /* SOF Uplink */
+ {SOF_DMA_UL1, NULL, "UL1_CH1"},
+ {SOF_DMA_UL1, NULL, "UL1_CH2"},
+ {SOF_DMA_UL2, NULL, "UL2_CH1"},
+ {SOF_DMA_UL2, NULL, "UL2_CH2"},
+ /* SOF Downlink */
+ {"DSP_DL1_VIRT", NULL, SOF_DMA_DL1},
+ {"DSP_DL2_VIRT", NULL, SOF_DMA_DL2},
+};
+
+static const struct snd_kcontrol_new mt8186_mt6366_da7219_max98357_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Headphones"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
+ SOC_DAPM_PIN_SWITCH("HDMI1"),
+};
+
static const struct snd_kcontrol_new
mt8186_mt6366_rt1019_rt5682s_controls[] = {
SOC_DAPM_PIN_SWITCH("Speakers"),
@@ -1067,6 +1096,21 @@ mt8186_mt6366_rt1019_rt5682s_controls[] = {
SOC_DAPM_PIN_SWITCH("HDMI1"),
};
+static struct snd_soc_card mt8186_mt6366_da7219_max98357_soc_card = {
+ .name = "mt8186_da7219_max98357",
+ .owner = THIS_MODULE,
+ .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
+ .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
+ .controls = mt8186_mt6366_da7219_max98357_controls,
+ .num_controls = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_controls),
+ .dapm_widgets = mt8186_mt6366_da7219_max98357_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_widgets),
+ .dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes),
+ .codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
+ .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
+};
+
static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = {
.name = "mt8186_rt1019_rt5682s",
.owner = THIS_MODULE,
@@ -1097,183 +1141,237 @@ static struct snd_soc_card mt8186_mt6366_rt5682s_max98360_soc_card = {
.num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
};
-static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
+static struct snd_soc_card mt8186_mt6366_rt5650_soc_card = {
+ .name = "mt8186_rt5650",
+ .owner = THIS_MODULE,
+ .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
+ .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
+ .controls = mt8186_mt6366_rt1019_rt5682s_controls,
+ .num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls),
+ .dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets),
+ .dapm_routes = mt8186_mt6366_rt5650_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt5650_routes),
+ .codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
+ .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
+};
+
+static int mt8186_mt6366_legacy_probe(struct mtk_soc_card_data *soc_card_data)
{
- struct snd_soc_card *card;
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ struct device *dev = card->dev;
struct snd_soc_dai_link *dai_link;
- struct mtk_soc_card_data *soc_card_data;
- struct mt8186_mt6366_rt1019_rt5682s_priv *mach_priv;
- struct device_node *platform_node, *headset_codec, *playback_codec, *adsp_node;
- int sof_on = 0;
+ struct device_node *headset_codec, *playback_codec;
int ret, i;
- card = (struct snd_soc_card *)device_get_match_data(&pdev->dev);
- if (!card)
- return -EINVAL;
- card->dev = &pdev->dev;
-
- soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*soc_card_data), GFP_KERNEL);
- if (!soc_card_data)
- return -ENOMEM;
- mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL);
- if (!mach_priv)
- return -ENOMEM;
-
- soc_card_data->mach_priv = mach_priv;
-
- mach_priv->dmic_sel = devm_gpiod_get_optional(&pdev->dev,
- "dmic", GPIOD_OUT_LOW);
- if (IS_ERR(mach_priv->dmic_sel)) {
- dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n",
- PTR_ERR(mach_priv->dmic_sel));
- return PTR_ERR(mach_priv->dmic_sel);
- }
-
- adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
- if (adsp_node) {
- struct mtk_sof_priv *sof_priv;
-
- sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL);
- if (!sof_priv) {
- ret = -ENOMEM;
- goto err_adsp_node;
- }
- sof_priv->conn_streams = g_sof_conn_streams;
- sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams);
- sof_priv->sof_dai_link_fixup = mt8186_sof_dai_link_fixup;
- soc_card_data->sof_priv = sof_priv;
- card->probe = mtk_sof_card_probe;
- card->late_probe = mtk_sof_card_late_probe;
- if (!card->topology_shortname_created) {
- snprintf(card->topology_shortname, 32, "sof-%s", card->name);
- card->topology_shortname_created = true;
- }
- card->name = card->topology_shortname;
- sof_on = 1;
- } else {
- dev_dbg(&pdev->dev, "Probe without adsp\n");
- }
-
- if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) {
- ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node,
- "mediatek,dai-link",
- mt8186_mt6366_rt1019_rt5682s_dai_links,
- ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links));
- if (ret) {
- dev_dbg(&pdev->dev, "Parse dai-link fail\n");
- goto err_adsp_node;
- }
- } else {
- if (!sof_on)
- card->num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links)
- - ARRAY_SIZE(g_sof_conn_streams);
- }
-
- platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
- if (!platform_node) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
- goto err_platform_node;
- }
-
- playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs");
- if (!playback_codec) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n");
- goto err_playback_codec;
- }
+ playback_codec = of_get_child_by_name(dev->of_node, "playback-codecs");
+ if (!playback_codec)
+ return dev_err_probe(dev, -EINVAL,
+ "Property 'playback-codecs' missing or invalid\n");
- headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec");
+ headset_codec = of_get_child_by_name(dev->of_node, "headset-codec");
if (!headset_codec) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n");
- goto err_headset_codec;
+ of_node_put(playback_codec);
+ return dev_err_probe(dev, -EINVAL,
+ "Property 'headset-codec' missing or invalid\n");
}
for_each_card_prelinks(card, i, dai_link) {
ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3");
if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n",
+ dev_err_probe(dev, ret, "%s set playback_codec fail\n",
dai_link->name);
- goto err_probe;
+ break;
}
ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0");
if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+ dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
- goto err_probe;
+ break;
}
ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1");
if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+ dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
- goto err_probe;
+ break;
}
+ }
+ of_node_put(headset_codec);
+ of_node_put(playback_codec);
- if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on)
- dai_link->platforms->of_node = adsp_node;
+ return ret;
+}
- if (!dai_link->platforms->name && !dai_link->platforms->of_node)
- dai_link->platforms->of_node = platform_node;
- }
+static int mt8186_mt6366_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ struct snd_soc_dai_link *dai_link;
+ struct mt8186_mt6366_rt1019_rt5682s_priv *mach_priv;
+ int i, ret;
- snd_soc_card_set_drvdata(card, soc_card_data);
+ mach_priv = devm_kzalloc(card->dev, sizeof(*mach_priv), GFP_KERNEL);
+ if (!mach_priv)
+ return -ENOMEM;
- ret = mt8186_afe_gpio_init(&pdev->dev);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__);
- goto err_probe;
+ soc_card_data->mach_priv = mach_priv;
+
+ mach_priv->dmic_sel = devm_gpiod_get_optional(card->dev,
+ "dmic", GPIOD_OUT_LOW);
+ if (IS_ERR(mach_priv->dmic_sel))
+ return dev_err_probe(card->dev, PTR_ERR(mach_priv->dmic_sel),
+ "DMIC gpio failed\n");
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (strcmp(dai_link->name, "I2S0") == 0 ||
+ strcmp(dai_link->name, "I2S1") == 0 ||
+ strcmp(dai_link->name, "I2S2") == 0) {
+ if (card_data->flags & DA7219_CODEC_PRESENT) {
+ dai_link->be_hw_params_fixup = mt8186_i2s_hw_params_32le_fixup;
+ dai_link->ops = &mt8186_da7219_i2s_ops;
+ } else {
+ dai_link->be_hw_params_fixup = mt8186_i2s_hw_params_24le_fixup;
+ dai_link->ops = &mt8186_rt5682s_i2s_ops;
+ }
+ } else if (strcmp(dai_link->name, "I2S3") == 0) {
+ if (card_data->flags & DA7219_CODEC_PRESENT)
+ dai_link->be_hw_params_fixup = mt8186_i2s_hw_params_24le_fixup;
+ else
+ dai_link->be_hw_params_fixup = mt8186_i2s_hw_params_32le_fixup;
+ }
}
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret)
- dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
+ if (legacy) {
+ ret = mt8186_mt6366_legacy_probe(soc_card_data);
+ if (ret)
+ return ret;
+ }
-err_probe:
- of_node_put(headset_codec);
-err_headset_codec:
- of_node_put(playback_codec);
-err_playback_codec:
- of_node_put(platform_node);
-err_platform_node:
-err_adsp_node:
- of_node_put(adsp_node);
+ ret = mt8186_afe_gpio_init(card->dev);
+ if (ret)
+ return dev_err_probe(card->dev, ret, "init AFE gpio error\n");
- return ret;
+ return 0;
}
+static const unsigned int mt8186_pcm_playback_channels[] = { 2 };
+static const unsigned int mt8186_pcm_capture_channels[] = { 1, 2 };
+static const unsigned int mt8186_pcm_rates[] = { 48000 };
+
+static const struct snd_pcm_hw_constraint_list mt8186_rate_constraint = {
+ .list = mt8186_pcm_rates,
+ .count = ARRAY_SIZE(mt8186_pcm_rates)
+};
+
+static const struct mtk_pcm_constraints_data mt8186_pcm_constraints[MTK_CONSTRAINT_CAPTURE + 1] = {
+ [MTK_CONSTRAINT_PLAYBACK] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8186_pcm_playback_channels,
+ .count = ARRAY_SIZE(mt8186_pcm_playback_channels)
+ },
+ .rates = &mt8186_rate_constraint,
+ },
+ [MTK_CONSTRAINT_CAPTURE] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8186_pcm_capture_channels,
+ .count = ARRAY_SIZE(mt8186_pcm_capture_channels)
+ },
+ .rates = &mt8186_rate_constraint,
+ }
+};
+
+static const struct mtk_sof_priv mt8186_sof_priv = {
+ .conn_streams = g_sof_conn_streams,
+ .num_streams = ARRAY_SIZE(g_sof_conn_streams),
+ .sof_dai_link_fixup = mt8186_sof_dai_link_fixup
+};
+
+static const struct mtk_soundcard_pdata mt8186_mt6366_da7219_max98357_pdata = {
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8186_mt6366_da7219_max98357_soc_card,
+ .num_jacks = MT8186_JACK_MAX,
+ .pcm_constraints = mt8186_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8186_pcm_constraints),
+ .flags = DA7219_CODEC_PRESENT,
+ },
+ .sof_priv = &mt8186_sof_priv,
+ .soc_probe = mt8186_mt6366_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8186_mt6366_rt1019_rt5682s_pdata = {
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8186_mt6366_rt1019_rt5682s_soc_card,
+ .num_jacks = MT8186_JACK_MAX,
+ .pcm_constraints = mt8186_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8186_pcm_constraints),
+ },
+ .sof_priv = &mt8186_sof_priv,
+ .soc_probe = mt8186_mt6366_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8186_mt6366_rt5682s_max98360_pdata = {
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8186_mt6366_rt5682s_max98360_soc_card,
+ .num_jacks = MT8186_JACK_MAX,
+ .pcm_constraints = mt8186_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8186_pcm_constraints),
+ },
+ .sof_priv = &mt8186_sof_priv,
+ .soc_probe = mt8186_mt6366_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8186_mt6366_rt5650_pdata = {
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8186_mt6366_rt5650_soc_card,
+ .num_jacks = MT8186_JACK_MAX,
+ .pcm_constraints = mt8186_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8186_pcm_constraints),
+ },
+ .sof_priv = &mt8186_sof_priv,
+ .soc_probe = mt8186_mt6366_soc_card_probe
+};
+
#if IS_ENABLED(CONFIG_OF)
-static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
+static const struct of_device_id mt8186_mt6366_dt_match[] = {
{
.compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
- .data = &mt8186_mt6366_rt1019_rt5682s_soc_card,
+ .data = &mt8186_mt6366_rt1019_rt5682s_pdata,
},
{
.compatible = "mediatek,mt8186-mt6366-rt5682s-max98360-sound",
- .data = &mt8186_mt6366_rt5682s_max98360_soc_card,
+ .data = &mt8186_mt6366_rt5682s_max98360_pdata,
+ },
+ {
+ .compatible = "mediatek,mt8186-mt6366-rt5650-sound",
+ .data = &mt8186_mt6366_rt5650_pdata,
+ },
+ {
+ .compatible = "mediatek,mt8186-mt6366-da7219-max98357-sound",
+ .data = &mt8186_mt6366_da7219_max98357_pdata,
},
- {}
+ { /* sentinel */ }
};
-MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match);
+MODULE_DEVICE_TABLE(of, mt8186_mt6366_dt_match);
#endif
-static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = {
+static struct platform_driver mt8186_mt6366_driver = {
.driver = {
- .name = "mt8186_mt6366_rt1019_rt5682s",
+ .name = "mt8186_mt6366",
#if IS_ENABLED(CONFIG_OF)
- .of_match_table = mt8186_mt6366_rt1019_rt5682s_dt_match,
+ .of_match_table = mt8186_mt6366_dt_match,
#endif
.pm = &snd_soc_pm_ops,
},
- .probe = mt8186_mt6366_rt1019_rt5682s_dev_probe,
+ .probe = mtk_soundcard_common_probe,
};
-module_platform_driver(mt8186_mt6366_rt1019_rt5682s_driver);
+module_platform_driver(mt8186_mt6366_driver);
/* Module information */
-MODULE_DESCRIPTION("MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver");
+MODULE_DESCRIPTION("MT8186-MT6366 ALSA SoC machine driver");
MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("mt8186_mt6366_rt1019_rt5682s soc card");
+MODULE_ALIAS("mt8186_mt6366 soc card");
diff --git a/sound/soc/mediatek/mt8188/Makefile b/sound/soc/mediatek/mt8188/Makefile
index 781e61cbb22b..b9f3e4ad7b07 100644
--- a/sound/soc/mediatek/mt8188/Makefile
+++ b/sound/soc/mediatek/mt8188/Makefile
@@ -1,11 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt8188-afe-objs := \
+snd-soc-mt8188-afe-y := \
mt8188-afe-clk.o \
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 4c24d0b9e90d..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",
@@ -436,13 +444,6 @@ int mt8188_afe_init_clock(struct mtk_base_afe *afe)
return 0;
}
-void mt8188_afe_deinit_clock(void *priv)
-{
- struct mtk_base_afe *afe = priv;
-
- mt8188_audsys_clk_unregister(afe);
-}
-
int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
{
int ret;
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
index 904505d10841..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,
@@ -111,7 +119,6 @@ int mt8188_afe_get_default_mclk_source_by_rate(int rate);
int mt8188_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
int mt8188_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
int mt8188_afe_init_clock(struct mtk_base_afe *afe);
-void mt8188_afe_deinit_clock(void *priv);
int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
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 c3fd32764da0..7b1f5d05f4d6 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/infracfg.h>
#include <linux/reset.h>
@@ -90,14 +91,14 @@ int mt8188_afe_fs_timing(unsigned int rate)
static int mt8188_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component = NULL;
struct mtk_base_afe *afe = NULL;
struct mt8188_afe_private *afe_priv = NULL;
struct mtk_base_afe_memif *memif = NULL;
struct mtk_dai_memif_priv *memif_priv = NULL;
int fs = mt8188_afe_fs_timing(rate);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
if (id < 0)
return -EINVAL;
@@ -299,10 +300,10 @@ static int mt8188_afe_enable_cm(struct mtk_base_afe *afe,
static int mt8188_afe_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int ret;
ret = mtk_afe_fe_startup(substream, dai);
@@ -333,9 +334,9 @@ static int mt8188_afe_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
const struct mtk_base_memif_data *data = memif->data;
const struct mt8188_afe_channel_merge *cm = mt8188_afe_found_cm(dai);
@@ -357,9 +358,9 @@ static int mt8188_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
const struct mt8188_afe_channel_merge *cm = mt8188_afe_found_cm(dai);
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime * const runtime = substream->runtime;
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
const struct mtk_base_irq_data *irq_data = irqs->irq_data;
@@ -651,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),
@@ -661,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),
@@ -671,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),
@@ -678,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),
@@ -685,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),
@@ -692,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),
@@ -1274,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"},
@@ -1599,8 +1623,7 @@ static SOC_VALUE_ENUM_SINGLE_DECL(ul10_fs_timing_sel_enum,
static int mt8188_memif_1x_en_sel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8188_afe_private *afe_priv = afe->platform_priv;
struct mtk_dai_memif_priv *memif_priv;
@@ -1623,8 +1646,7 @@ static int mt8188_memif_1x_en_sel_put(struct snd_kcontrol *kcontrol,
static int mt8188_asys_irq_1x_en_sel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8188_afe_private *afe_priv = afe->platform_priv;
unsigned int id = kcontrol->id.device;
@@ -1644,7 +1666,7 @@ static int mt8188_asys_irq_1x_en_sel_put(struct snd_kcontrol *kcontrol,
static int mt8188_memif_fs_timing_sel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8188_afe_private *afe_priv = afe->platform_priv;
struct mtk_dai_memif_priv *memif_priv;
@@ -1662,7 +1684,7 @@ static int mt8188_memif_fs_timing_sel_get(struct snd_kcontrol *kcontrol,
static int mt8188_memif_fs_timing_sel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8188_afe_private *afe_priv = afe->platform_priv;
struct mtk_dai_memif_priv *memif_priv;
@@ -2747,6 +2769,7 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg)
case AFE_ASRC12_NEW_CON9:
case AFE_LRCK_CNT:
case AFE_DAC_MON0:
+ case AFE_DAC_CON0:
case AFE_DL2_CUR:
case AFE_DL3_CUR:
case AFE_DL6_CUR:
@@ -2853,10 +2876,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:
@@ -3029,25 +3048,6 @@ skip_regmap:
return 0;
}
-static int mt8188_afe_component_probe(struct snd_soc_component *component)
-{
- struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int ret;
-
- snd_soc_component_init_regmap(component, afe->regmap);
-
- ret = mtk_afe_add_sub_dai_control(component);
-
- return ret;
-}
-
-static const struct snd_soc_component_driver mt8188_afe_component = {
- .name = AFE_PCM_NAME,
- .pointer = mtk_afe_pcm_pointer,
- .pcm_construct = mtk_afe_pcm_new,
- .probe = mt8188_afe_component_probe,
-};
-
static int init_memif_priv_data(struct mtk_base_afe *afe)
{
struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -3093,6 +3093,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,
@@ -3193,11 +3194,15 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
{
struct mtk_base_afe *afe;
struct mt8188_afe_private *afe_priv;
- struct device *dev;
+ struct device *dev = &pdev->dev;
struct reset_control *rstc;
struct regmap *infra_ao;
int i, irq_id, ret;
+ ret = of_reserved_mem_device_init(dev);
+ if (ret)
+ dev_dbg(dev, "failed to assign memory region: %d\n", ret);
+
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
if (ret)
return ret;
@@ -3213,7 +3218,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
afe_priv = afe->platform_priv;
afe->dev = &pdev->dev;
- dev = afe->dev;
afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(afe->base_addr))
@@ -3256,10 +3260,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "init clock error");
- ret = devm_add_action_or_reset(dev, mt8188_afe_deinit_clock, (void *)afe);
- if (ret)
- return ret;
-
spin_lock_init(&afe_priv->afe_ctrl_lock);
mutex_init(&afe->irq_alloc_lock);
@@ -3350,7 +3350,7 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
}
/* register component */
- ret = devm_snd_soc_register_component(dev, &mt8188_afe_component,
+ ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
afe->dai_drivers, afe->num_dai_drivers);
if (ret) {
dev_warn(dev, "err_platform\n");
@@ -3379,15 +3379,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 be1c53bf4729..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),
@@ -138,6 +142,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
};
+static void mt8188_audsys_clk_unregister(void *data)
+{
+ struct mtk_base_afe *afe = data;
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
+
int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -179,27 +206,5 @@ int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
afe_priv->lookup[i] = cl;
}
- return 0;
-}
-
-void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe)
-{
- struct mt8188_afe_private *afe_priv = afe->platform_priv;
- struct clk *clk;
- struct clk_lookup *cl;
- int i;
-
- if (!afe_priv)
- return;
-
- for (i = 0; i < CLK_AUD_NR_CLK; i++) {
- cl = afe_priv->lookup[i];
- if (!cl)
- continue;
-
- clk = cl->clk;
- clk_unregister_gate(clk);
-
- clkdev_drop(cl);
- }
+ return devm_add_action_or_reset(afe->dev, mt8188_audsys_clk_unregister, afe);
}
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
index 6c5f463ad7e4..45b0948c4a06 100644
--- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
@@ -10,6 +10,5 @@
#define _MT8188_AUDSYS_CLK_H_
int mt8188_audsys_clk_register(struct mtk_base_afe *afe);
-void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe);
#endif
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-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
index 7dc029f2b428..ac547fc864a6 100644
--- a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c
@@ -14,6 +14,7 @@
#include "mt8188-afe-clk.h"
#include "mt8188-afe-common.h"
#include "mt8188-reg.h"
+#include "../common/mtk-dai-adda-common.h"
#define ADDA_HIRES_THRES 48000
@@ -24,94 +25,10 @@ enum {
SUPPLY_SEQ_ADDA_AFE_ON,
};
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
-};
-
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO0 = 1,
-};
-
struct mtk_dai_adda_priv {
bool hires_required;
};
-static unsigned int afe_adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %u invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int afe_adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %u invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe)
{
struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -146,7 +63,6 @@ static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe)
param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0];
}
- val = 0;
mask = (MTKAIF_RXIF_DELAY_DATA | MTKAIF_RXIF_DELAY_CYCLE_MASK);
val |= FIELD_PREP(MTKAIF_RXIF_DELAY_CYCLE_MASK, delay_cycle);
val |= FIELD_PREP(MTKAIF_RXIF_DELAY_DATA, delay_data);
@@ -394,7 +310,7 @@ static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
static int mt8188_adda_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8188_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -406,7 +322,7 @@ static int mt8188_adda_dmic_get(struct snd_kcontrol *kcontrol,
static int mt8188_adda_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8188_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -440,7 +356,7 @@ static int mtk_dai_da_configure(struct mtk_base_afe *afe,
/* set sampling rate */
mask |= DL_2_INPUT_MODE_CTL_MASK;
val |= FIELD_PREP(DL_2_INPUT_MODE_CTL_MASK,
- afe_adda_dl_rate_transform(afe, rate));
+ mtk_adda_dl_rate_transform(afe, rate));
/* turn off saturation */
mask |= DL_2_CH1_SATURATION_EN_CTL;
@@ -474,7 +390,7 @@ static int mtk_dai_ad_configure(struct mtk_base_afe *afe,
mask = UL_VOICE_MODE_CTL_MASK;
val = FIELD_PREP(UL_VOICE_MODE_CTL_MASK,
- afe_adda_ul_rate_transform(afe, rate));
+ mtk_adda_ul_rate_transform(afe, rate));
regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
mask, val);
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..a9515d7fb70a
--- /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_kcontrol_chip(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-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
index 16440dd0a89c..4dfaa761f9f7 100644
--- a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c
@@ -576,13 +576,13 @@ static int mtk_apll_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8188_apll1_enable(afe);
else
mt8188_apll2_enable(afe);
break;
case SND_SOC_DAPM_POST_PMD:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8188_apll1_disable(afe);
else
mt8188_apll2_disable(afe);
@@ -1061,8 +1061,7 @@ static int mt8188_etdm_clk_src_sel_put(struct snd_kcontrol *kcontrol,
static int mt8188_etdm_clk_src_sel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value;
unsigned int reg;
@@ -2422,7 +2421,6 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream,
unsigned int channels = params_channels(params);
snd_pcm_format_t format = params_format(params);
int width = snd_pcm_format_physical_width(format);
- int ret;
if (!is_valid_etdm_dai(dai->id))
return -EINVAL;
@@ -2450,9 +2448,7 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream,
etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN;
}
- ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id);
-
- return ret;
+ return mtk_dai_etdm_configure(afe, rate, channels, width, dai->id);
}
static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai,
diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
index 5bc854a8f3df..8ca7cc75e21d 100644
--- a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c
@@ -128,7 +128,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,
unsigned int lrck_inv;
unsigned int bck_inv;
unsigned int fmt;
- unsigned int bit_width = dai->sample_bits;
+ unsigned int bit_width = dai->symmetric_sample_bits;
unsigned int val = 0;
unsigned int mask = 0;
int fs = 0;
diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
index ac69c23e0da1..55ebac0c3cef 100644
--- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c
+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
@@ -9,7 +9,7 @@
#include <linux/bitfield.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
@@ -17,8 +17,12 @@
#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"
+#include "../common/mtk-dsp-sof-common.h"
+#include "../common/mtk-soc-card.h"
#define CKSYS_AUD_TOP_CFG 0x032c
#define RG_TEST_ON BIT(0)
@@ -30,7 +34,9 @@
#define TEST_MISO_DONE_2 BIT(29)
#define NAU8825_HS_PRESENT BIT(0)
-
+#define RT5682S_HS_PRESENT BIT(1)
+#define ES8326_HS_PRESENT BIT(2)
+#define MAX98390_TWO_AMP BIT(3)
/*
* Maxim MAX98390
*/
@@ -45,6 +51,18 @@
*/
#define NAU8825_CODEC_DAI "nau8825-hifi"
+/*
+ * ES8326
+ */
+#define ES8326_CODEC_DAI "ES8326 HiFi"
+
+#define SOF_DMA_DL2 "SOF_DMA_DL2"
+#define SOF_DMA_DL3 "SOF_DMA_DL3"
+#define SOF_DMA_UL4 "SOF_DMA_UL4"
+#define SOF_DMA_UL5 "SOF_DMA_UL5"
+
+#define RT5682S_CODEC_DAI "rt5682s-aif1"
+
/* FE */
SND_SOC_DAILINK_DEFS(playback2,
DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
@@ -133,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()),
@@ -171,29 +194,70 @@ SND_SOC_DAILINK_DEFS(pcm1,
SND_SOC_DAILINK_DEFS(ul_src,
DAILINK_COMP_ARRAY(COMP_CPU("UL_SRC")),
DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound",
- "mt6359-snd-codec-aif1"),
- COMP_CODEC("dmic-codec",
- "dmic-hifi")),
+ "mt6359-snd-codec-aif1")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
-struct mt8188_mt6359_priv {
- struct snd_soc_jack dp_jack;
- struct snd_soc_jack hdmi_jack;
- struct snd_soc_jack headset_jack;
- void *private_data;
+SND_SOC_DAILINK_DEFS(AFE_SOF_DL2,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(AFE_SOF_DL3,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_DL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL4,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL4")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(AFE_SOF_UL5,
+ DAILINK_COMP_ARRAY(COMP_CPU("SOF_UL5")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static const struct sof_conn_stream g_sof_conn_streams[] = {
+ {
+ .sof_link = "AFE_SOF_DL2",
+ .sof_dma = SOF_DMA_DL2,
+ .stream_dir = SNDRV_PCM_STREAM_PLAYBACK
+ },
+ {
+ .sof_link = "AFE_SOF_DL3",
+ .sof_dma = SOF_DMA_DL3,
+ .stream_dir = SNDRV_PCM_STREAM_PLAYBACK
+ },
+ {
+ .sof_link = "AFE_SOF_UL4",
+ .sof_dma = SOF_DMA_UL4,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+ {
+ .sof_link = "AFE_SOF_UL5",
+ .sof_dma = SOF_DMA_UL5,
+ .stream_dir = SNDRV_PCM_STREAM_CAPTURE
+ },
+};
+
+enum mt8188_jacks {
+ MT8188_JACK_HEADSET,
+ MT8188_JACK_DP,
+ MT8188_JACK_HDMI,
+ MT8188_JACK_MAX,
};
static struct snd_soc_jack_pin mt8188_hdmi_jack_pins[] = {
{
.pin = "HDMI",
- .mask = SND_JACK_LINEOUT,
+ .mask = SND_JACK_AVOUT,
},
};
static struct snd_soc_jack_pin mt8188_dp_jack_pins[] = {
{
.pin = "DP",
- .mask = SND_JACK_LINEOUT,
+ .mask = SND_JACK_AVOUT,
},
};
@@ -208,9 +272,15 @@ static struct snd_soc_jack_pin nau8825_jack_pins[] = {
},
};
-struct mt8188_card_data {
- const char *name;
- unsigned long quirk;
+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[] = {
@@ -244,8 +314,18 @@ 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),
+ SND_SOC_DAPM_MIXER(SOF_DMA_DL3, SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER(SOF_DMA_UL4, SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER(SOF_DMA_UL5, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* dynamic pinctrl */
+ SND_SOC_DAPM_PINCTRL("ETDM_SPK_PIN", "aud_etdm_spk_on", "aud_etdm_spk_off"),
+ SND_SOC_DAPM_PINCTRL("ETDM_HP_PIN", "aud_etdm_hp_on", "aud_etdm_hp_off"),
+ SND_SOC_DAPM_PINCTRL("MTKAIF_PIN", "aud_mtkaif_on", "aud_mtkaif_off"),
};
static const struct snd_kcontrol_new mt8188_mt6359_controls[] = {
@@ -261,12 +341,26 @@ static const struct snd_kcontrol_new mt8188_nau8825_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
};
+static const struct snd_soc_dapm_route mt8188_mt6359_routes[] = {
+ /* SOF Uplink */
+ {SOF_DMA_UL4, NULL, "O034"},
+ {SOF_DMA_UL4, NULL, "O035"},
+ {SOF_DMA_UL5, NULL, "O036"},
+ {SOF_DMA_UL5, NULL, "O037"},
+ /* SOF Downlink */
+ {"I070", NULL, SOF_DMA_DL2},
+ {"I071", NULL, SOF_DMA_DL2},
+ {"I020", NULL, SOF_DMA_DL3},
+ {"I021", NULL, SOF_DMA_DL3},
+};
+
static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_dapm_widget *pin_w = NULL, *w;
struct mtk_base_afe *afe;
struct mt8188_afe_private *afe_priv;
struct mtkaif_param *param;
@@ -306,6 +400,18 @@ static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+ for_each_card_widgets(rtd->card, w) {
+ if (!strcmp(w->name, "MTKAIF_PIN")) {
+ pin_w = w;
+ break;
+ }
+ }
+
+ if (pin_w)
+ snd_soc_dapm_pinctrl_event(pin_w, NULL, SND_SOC_DAPM_PRE_PMU);
+ else
+ dev_dbg(afe->dev, "%s(), no pinmux widget, please check if default on\n", __func__);
+
pm_runtime_get_sync(afe->dev);
mt6359_mtkaif_calibration_enable(cmpnt_codec);
@@ -403,16 +509,48 @@ static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
for (i = 0; i < MT8188_MTKAIF_MISO_NUM; i++)
param->mtkaif_phase_cycle[i] = mtkaif_phase_cycle[i];
+ if (pin_w)
+ snd_soc_dapm_pinctrl_event(pin_w, NULL, SND_SOC_DAPM_POST_PMD);
+
dev_dbg(afe->dev, "%s(), end, calibration ok %d\n",
__func__, param->mtkaif_calibration_ok);
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 =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
/* set mtkaif protocol */
mt6359_set_mtkaif_protocol(cmpnt_codec,
@@ -421,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;
}
@@ -442,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,
@@ -450,16 +591,25 @@ enum {
DAI_LINK_ETDM3_OUT_BE,
DAI_LINK_PCM1_BE,
DAI_LINK_UL_SRC_BE,
+ DAI_LINK_REGULAR_LAST = DAI_LINK_UL_SRC_BE,
+ DAI_LINK_SOF_START,
+ DAI_LINK_SOF_DL2_BE = DAI_LINK_SOF_START,
+ DAI_LINK_SOF_DL3_BE,
+ DAI_LINK_SOF_UL4_BE,
+ DAI_LINK_SOF_UL5_BE,
+ DAI_LINK_SOF_END = DAI_LINK_SOF_UL5_BE,
};
+#define DAI_LINK_REGULAR_NUM (DAI_LINK_REGULAR_LAST + 1)
+
static int mt8188_dptx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 256;
unsigned int mclk_fs = rate * mclk_fs_ratio;
- struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
}
@@ -482,12 +632,13 @@ static int mt8188_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int mt8188_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
{
- struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ 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_HDMI];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret = 0;
ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack",
- SND_JACK_LINEOUT, &priv->hdmi_jack,
+ SND_JACK_AVOUT, jack,
mt8188_hdmi_jack_pins,
ARRAY_SIZE(mt8188_hdmi_jack_pins));
if (ret) {
@@ -495,7 +646,7 @@ static int mt8188_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_component_set_jack(component, &priv->hdmi_jack, NULL);
+ ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {
dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
__func__, component->name, ret);
@@ -507,19 +658,20 @@ static int mt8188_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
static int mt8188_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
{
- struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ 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_DP];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret = 0;
- ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT,
- &priv->dp_jack, mt8188_dp_jack_pins,
+ ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_AVOUT,
+ jack, mt8188_dp_jack_pins,
ARRAY_SIZE(mt8188_dp_jack_pins));
if (ret) {
dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
return ret;
}
- ret = snd_soc_component_set_jack(component, &priv->dp_jack, NULL);
+ ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {
dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
__func__, component->name, ret);
@@ -532,9 +684,10 @@ static int mt8188_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
static int mt8188_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret = 0;
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_dumb_spk_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8188_dumb_spk_widgets,
ARRAY_SIZE(mt8188_dumb_spk_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
@@ -554,9 +707,9 @@ static int mt8188_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
static int mt8188_max98390_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int bit_width = params_width(params);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai;
int i;
@@ -585,10 +738,11 @@ static const struct snd_soc_ops mt8188_max98390_ops = {
static int mt8188_max98390_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
/* add regular speakers dapm route */
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_dual_spk_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8188_dual_spk_widgets,
ARRAY_SIZE(mt8188_dual_spk_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add Left/Right Speaker widget, ret %d\n", ret);
@@ -606,7 +760,7 @@ static int mt8188_max98390_codec_init(struct snd_soc_pcm_runtime *rtd)
return 0;
/* add widgets/controls/dapm for rear speakers */
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_rear_spk_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8188_rear_spk_widgets,
ARRAY_SIZE(mt8188_rear_spk_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add Rear Speaker widget, ret %d\n", ret);
@@ -624,15 +778,17 @@ static int mt8188_max98390_codec_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int mt8188_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+static int mt8188_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
- struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_jack *jack = &priv->headset_jack;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ 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];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_nau8825_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8188_nau8825_widgets,
ARRAY_SIZE(mt8188_nau8825_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
@@ -658,10 +814,18 @@ static int mt8188_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ if (card_data->flags & ES8326_HS_PRESENT) {
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+ } else {
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ }
+
ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {
@@ -672,18 +836,19 @@ static int mt8188_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
return 0;
};
-static void mt8188_nau8825_codec_exit(struct snd_soc_pcm_runtime *rtd)
+static void mt8188_headset_codec_exit(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
snd_soc_component_set_jack(component, NULL, NULL);
}
+
static int mt8188_nau8825_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int rate = params_rate(params);
unsigned int bit_width = params_width(params);
int clk_freq, ret;
@@ -712,6 +877,102 @@ static int mt8188_nau8825_hw_params(struct snd_pcm_substream *substream,
static const struct snd_soc_ops mt8188_nau8825_ops = {
.hw_params = mt8188_nau8825_hw_params,
};
+
+static int mt8188_rt5682s_i2s_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_card *card = rtd->card;
+ 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);
+ unsigned int rate = params_rate(params);
+ int bitwidth;
+ int ret;
+
+ bitwidth = snd_pcm_format_width(params_format(params));
+ if (bitwidth < 0) {
+ dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+ return bitwidth;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+ if (ret) {
+ dev_err(card->dev, "failed to set tdm slot\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_BCLK1,
+ rate * 32, rate * 512);
+ if (ret) {
+ dev_err(card->dev, "failed to set pll\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
+ rate * 512, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(card->dev, "failed to set sysclk\n");
+ return ret;
+ }
+
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 128,
+ SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8188_rt5682s_i2s_ops = {
+ .hw_params = mt8188_rt5682s_i2s_hw_params,
+};
+
+static int mt8188_sof_be_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_component *cmpnt_afe = NULL;
+ struct snd_soc_pcm_runtime *runtime;
+
+ /* find afe component */
+ for_each_card_rtds(rtd->card, runtime) {
+ cmpnt_afe = snd_soc_rtdcom_lookup(runtime, AFE_PCM_NAME);
+ if (cmpnt_afe)
+ break;
+ }
+
+ if (cmpnt_afe && !pm_runtime_active(cmpnt_afe->dev)) {
+ dev_err(rtd->dev, "afe pm runtime is not active!!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8188_sof_be_ops = {
+ .hw_params = mt8188_sof_be_hw_params,
+};
+
+static int mt8188_es8326_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 = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ int ret;
+
+ /* Configure MCLK for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, rate * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set MCLK %d\n", ret);
+ return ret;
+ }
+
+ /* Configure MCLK for cpu */
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 256, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8188_es8326_ops = {
+ .hw_params = mt8188_es8326_hw_params,
+};
+
static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
/* FE */
[DAI_LINK_DL2_FE] = {
@@ -722,7 +983,10 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_format = 1,
SND_SOC_DAILINK_REG(playback2),
},
[DAI_LINK_DL3_FE] = {
@@ -733,7 +997,10 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_format = 1,
SND_SOC_DAILINK_REG(playback3),
},
[DAI_LINK_DL6_FE] = {
@@ -744,7 +1011,10 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_format = 1,
SND_SOC_DAILINK_REG(playback6),
},
[DAI_LINK_DL7_FE] = {
@@ -755,7 +1025,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback7),
},
[DAI_LINK_DL8_FE] = {
@@ -766,7 +1036,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback8),
},
[DAI_LINK_DL10_FE] = {
@@ -777,7 +1047,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback10),
},
[DAI_LINK_DL11_FE] = {
@@ -788,7 +1058,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback11),
},
[DAI_LINK_UL1_FE] = {
@@ -799,7 +1069,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture1),
},
[DAI_LINK_UL2_FE] = {
@@ -810,7 +1080,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture2),
},
[DAI_LINK_UL3_FE] = {
@@ -821,7 +1091,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture3),
},
[DAI_LINK_UL4_FE] = {
@@ -832,7 +1102,10 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_format = 1,
SND_SOC_DAILINK_REG(capture4),
},
[DAI_LINK_UL5_FE] = {
@@ -843,7 +1116,10 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
+ .dpcm_merged_chan = 1,
+ .dpcm_merged_rate = 1,
+ .dpcm_merged_format = 1,
SND_SOC_DAILINK_REG(capture5),
},
[DAI_LINK_UL6_FE] = {
@@ -854,7 +1130,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture6),
},
[DAI_LINK_UL8_FE] = {
@@ -865,7 +1141,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture8),
},
[DAI_LINK_UL9_FE] = {
@@ -876,7 +1152,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture9),
},
[DAI_LINK_UL10_FE] = {
@@ -887,22 +1163,29 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture10),
},
/* BE */
[DAI_LINK_DL_SRC_BE] = {
.name = "DL_SRC_BE",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .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,
.be_hw_params_fixup = mt8188_dptx_hw_params_fixup,
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(dptx),
},
[DAI_LINK_ETDM1_IN_BE] = {
@@ -911,7 +1194,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(etdm1_in),
},
@@ -921,7 +1204,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBP_CFP,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(etdm2_in),
},
[DAI_LINK_ETDM1_OUT_BE] = {
@@ -930,7 +1213,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(etdm1_out),
},
[DAI_LINK_ETDM2_OUT_BE] = {
@@ -939,7 +1222,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(etdm2_out),
},
[DAI_LINK_ETDM3_OUT_BE] = {
@@ -948,7 +1231,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(etdm3_out),
},
[DAI_LINK_PCM1_BE] = {
@@ -957,35 +1240,53 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(pcm1),
},
[DAI_LINK_UL_SRC_BE] = {
.name = "UL_SRC_BE",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(ul_src),
},
-};
-
-static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
-{
- struct snd_ctl_elem_id sid;
- memset(&sid, 0, sizeof(sid));
- strcpy(sid.name, name);
- sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- return snd_ctl_find_id(card, &sid);
-}
+ /* SOF BE */
+ [DAI_LINK_SOF_DL2_BE] = {
+ .name = "AFE_SOF_DL2",
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ops = &mt8188_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_DL2),
+ },
+ [DAI_LINK_SOF_DL3_BE] = {
+ .name = "AFE_SOF_DL3",
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ops = &mt8188_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_DL3),
+ },
+ [DAI_LINK_SOF_UL4_BE] = {
+ .name = "AFE_SOF_UL4",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8188_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL4),
+ },
+ [DAI_LINK_SOF_UL5_BE] = {
+ .name = "AFE_SOF_UL5",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ops = &mt8188_sof_be_ops,
+ SND_SOC_DAILINK_REG(AFE_SOF_UL5),
+ },
+};
static void mt8188_fixup_controls(struct snd_soc_card *card)
{
- struct mt8188_mt6359_priv *priv = snd_soc_card_get_drvdata(card);
- struct mt8188_card_data *card_data = (struct mt8188_card_data *)priv->private_data;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
struct snd_kcontrol *kctl;
- if (card_data->quirk & NAU8825_HS_PRESENT) {
+ if (card_data->flags & (NAU8825_HS_PRESENT | RT5682S_HS_PRESENT | ES8326_HS_PRESENT)) {
struct snd_soc_dapm_widget *w, *next_w;
for_each_card_widgets_safe(card, w, next_w) {
@@ -995,7 +1296,7 @@ static void mt8188_fixup_controls(struct snd_soc_card *card)
snd_soc_dapm_free_widget(w);
}
- kctl = ctl_find(card->snd_card, "Headphone Switch");
+ kctl = snd_ctl_find_id_mixer(card->snd_card, "Headphone Switch");
if (kctl)
snd_ctl_remove(card->snd_card, kctl);
else
@@ -1009,65 +1310,37 @@ static struct snd_soc_card mt8188_mt6359_soc_card = {
.num_links = ARRAY_SIZE(mt8188_mt6359_dai_links),
.dapm_widgets = mt8188_mt6359_widgets,
.num_dapm_widgets = ARRAY_SIZE(mt8188_mt6359_widgets),
+ .dapm_routes = mt8188_mt6359_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8188_mt6359_routes),
.controls = mt8188_mt6359_controls,
.num_controls = ARRAY_SIZE(mt8188_mt6359_controls),
.fixup_controls = mt8188_fixup_controls,
};
-static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
+static int mt8188_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
{
- struct snd_soc_card *card = &mt8188_mt6359_soc_card;
- struct device_node *platform_node;
- struct mt8188_mt6359_priv *priv;
- struct mt8188_card_data *card_data;
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = soc_card_data->card_data->card;
struct snd_soc_dai_link *dai_link;
bool init_mt6359 = false;
+ bool init_es8326 = false;
bool init_nau8825 = false;
+ bool init_rt5682s = false;
bool init_max98390 = false;
bool init_dumb = false;
- int ret, i;
-
- card_data = (struct mt8188_card_data *)of_device_get_match_data(&pdev->dev);
- card->dev = &pdev->dev;
-
- ret = snd_soc_of_parse_card_name(card, "model");
- if (ret)
- return dev_err_probe(&pdev->dev, ret, "%s new card name parsing error\n",
- __func__);
-
- if (!card->name)
- card->name = card_data->name;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- if (of_property_read_bool(pdev->dev.of_node, "audio-routing")) {
- ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
- if (ret)
- return ret;
- }
-
- platform_node = of_parse_phandle(pdev->dev.of_node,
- "mediatek,platform", 0);
- if (!platform_node) {
- ret = -EINVAL;
- return dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
- }
+ int i;
- ret = parse_dai_link_info(card);
- if (ret)
- goto err;
+ if (legacy)
+ return -EINVAL;
for_each_card_prelinks(card, i, dai_link) {
- if (!dai_link->platforms->name)
- dai_link->platforms->of_node = platform_node;
-
if (strcmp(dai_link->name, "DPTX_BE") == 0) {
- if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ if (dai_link->num_codecs &&
+ !snd_soc_dlc_is_dummy(dai_link->codecs))
dai_link->init = mt8188_dptx_codec_init;
} else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) {
- if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ if (dai_link->num_codecs &&
+ !snd_soc_dlc_is_dummy(dai_link->codecs))
dai_link->init = mt8188_hdmi_codec_init;
} else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 ||
strcmp(dai_link->name, "UL_SRC_BE") == 0) {
@@ -1079,8 +1352,18 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
strcmp(dai_link->name, "ETDM2_OUT_BE") == 0 ||
strcmp(dai_link->name, "ETDM1_IN_BE") == 0 ||
strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
+ if (!dai_link->num_codecs)
+ continue;
+
if (!strcmp(dai_link->codecs->dai_name, MAX98390_CODEC_DAI)) {
- dai_link->ops = &mt8188_max98390_ops;
+ /*
+ * The TDM protocol settings with fixed 4 slots are defined in
+ * mt8188_max98390_ops. Two amps is I2S mode,
+ * SOC and codec don't require TDM settings.
+ */
+ if (!(card_data->flags & MAX98390_TWO_AMP)) {
+ dai_link->ops = &mt8188_max98390_ops;
+ }
if (!init_max98390) {
dai_link->init = mt8188_max98390_codec_init;
init_max98390 = true;
@@ -1088,12 +1371,26 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
} else if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
dai_link->ops = &mt8188_nau8825_ops;
if (!init_nau8825) {
- dai_link->init = mt8188_nau8825_codec_init;
- dai_link->exit = mt8188_nau8825_codec_exit;
+ dai_link->init = mt8188_headset_codec_init;
+ dai_link->exit = mt8188_headset_codec_exit;
init_nau8825 = true;
}
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
+ dai_link->ops = &mt8188_rt5682s_i2s_ops;
+ if (!init_rt5682s) {
+ dai_link->init = mt8188_headset_codec_init;
+ dai_link->exit = mt8188_headset_codec_exit;
+ init_rt5682s = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, ES8326_CODEC_DAI)) {
+ dai_link->ops = &mt8188_es8326_ops;
+ if (!init_es8326) {
+ dai_link->init = mt8188_headset_codec_init;
+ dai_link->exit = mt8188_headset_codec_exit;
+ init_es8326 = true;
+ }
} else {
- if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
+ if (!snd_soc_dlc_is_dummy(dai_link->codecs)) {
if (!init_dumb) {
dai_link->init = mt8188_dumb_amp_init;
init_dumb = true;
@@ -1103,31 +1400,62 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev)
}
}
- priv->private_data = card_data;
- snd_soc_card_set_drvdata(card, priv);
-
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret)
- dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n",
- __func__);
-err:
- of_node_put(platform_node);
- clean_card_reference(card);
- return ret;
+ return 0;
}
-static struct mt8188_card_data mt8188_evb_card = {
- .name = "mt8188_mt6359",
+static const struct mtk_sof_priv mt8188_sof_priv = {
+ .conn_streams = g_sof_conn_streams,
+ .num_streams = ARRAY_SIZE(g_sof_conn_streams),
};
-static struct mt8188_card_data mt8188_nau8825_card = {
- .name = "mt8188_nau8825",
- .quirk = NAU8825_HS_PRESENT,
+static const struct mtk_soundcard_pdata mt8188_evb_card = {
+ .card_name = "mt8188_mt6359",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8188_mt6359_soc_card,
+ .num_jacks = MT8188_JACK_MAX,
+ },
+ .sof_priv = &mt8188_sof_priv,
+ .soc_probe = mt8188_mt6359_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8188_nau8825_card = {
+ .card_name = "mt8188_nau8825",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8188_mt6359_soc_card,
+ .num_jacks = MT8188_JACK_MAX,
+ .flags = NAU8825_HS_PRESENT
+ },
+ .sof_priv = &mt8188_sof_priv,
+ .soc_probe = mt8188_mt6359_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8188_rt5682s_card = {
+ .card_name = "mt8188_rt5682s",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8188_mt6359_soc_card,
+ .num_jacks = MT8188_JACK_MAX,
+ .flags = RT5682S_HS_PRESENT | MAX98390_TWO_AMP
+ },
+ .sof_priv = &mt8188_sof_priv,
+ .soc_probe = mt8188_mt6359_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8188_es8326_card = {
+ .card_name = "mt8188_es8326",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8188_mt6359_soc_card,
+ .num_jacks = MT8188_JACK_MAX,
+ .flags = ES8326_HS_PRESENT | MAX98390_TWO_AMP
+ },
+ .sof_priv = &mt8188_sof_priv,
+ .soc_probe = mt8188_mt6359_soc_card_probe,
};
static const struct of_device_id mt8188_mt6359_dt_match[] = {
{ .compatible = "mediatek,mt8188-mt6359-evb", .data = &mt8188_evb_card, },
{ .compatible = "mediatek,mt8188-nau8825", .data = &mt8188_nau8825_card, },
+ { .compatible = "mediatek,mt8188-rt5682s", .data = &mt8188_rt5682s_card, },
+ { .compatible = "mediatek,mt8188-es8326", .data = &mt8188_es8326_card, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mt8188_mt6359_dt_match);
@@ -1138,7 +1466,7 @@ static struct platform_driver mt8188_mt6359_driver = {
.of_match_table = mt8188_mt6359_dt_match,
.pm = &snd_soc_pm_ops,
},
- .probe = mt8188_mt6359_dev_probe,
+ .probe = mtk_soundcard_common_probe,
};
module_platform_driver(mt8188_mt6359_driver);
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/mt8189/Makefile b/sound/soc/mediatek/mt8189/Makefile
new file mode 100644
index 000000000000..83a033284182
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/Makefile
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# common include path
+subdir-ccflags-y += -I$(srctree)/sound/soc/mediatek/common
+
+# platform driver
+snd-soc-mt8189-afe-objs += \
+ mt8189-afe-pcm.o \
+ mt8189-afe-clk.o \
+ mt8189-dai-adda.o \
+ mt8189-dai-i2s.o \
+ mt8189-dai-pcm.o \
+ mt8189-dai-tdm.o
+
+obj-$(CONFIG_SND_SOC_MT8189) += snd-soc-mt8189-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT8189_NAU8825) += mt8189-nau8825.o
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-clk.c b/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
new file mode 100644
index 000000000000..fc7a7a73b0cf
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-clk.c
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8189-afe-clk.c -- Mediatek 8189 afe clock ctrl
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "mt8189-afe-common.h"
+#include "mt8189-afe-clk.h"
+
+/* mck */
+struct mt8189_mck_div {
+ int m_sel_id;
+ int div_clk_id;
+};
+
+static const struct mt8189_mck_div mck_div[MT8189_MCK_NUM] = {
+ [MT8189_I2SIN0_MCK] = {
+ .m_sel_id = MT8189_CLK_TOP_I2SIN0_M_SEL,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_I2SIN0,
+ },
+ [MT8189_I2SIN1_MCK] = {
+ .m_sel_id = MT8189_CLK_TOP_I2SIN1_M_SEL,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_I2SIN1,
+ },
+ [MT8189_I2SOUT0_MCK] = {
+ .m_sel_id = MT8189_CLK_TOP_I2SOUT0_M_SEL,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_I2SOUT0,
+ },
+ [MT8189_I2SOUT1_MCK] = {
+ .m_sel_id = MT8189_CLK_TOP_I2SOUT1_M_SEL,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_I2SOUT1,
+ },
+ [MT8189_FMI2S_MCK] = {
+ .m_sel_id = MT8189_CLK_TOP_FMI2S_M_SEL,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_FMI2S,
+ },
+ [MT8189_TDMOUT_MCK] = {
+ .m_sel_id = MT8189_CLK_TOP_TDMOUT_M_SEL,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_TDMOUT_M,
+ },
+ [MT8189_TDMOUT_BCK] = {
+ .m_sel_id = -1,
+ .div_clk_id = MT8189_CLK_TOP_APLL12_DIV_TDMOUT_B,
+ },
+};
+
+static const char *aud_clks[MT8189_CLK_NUM] = {
+ [MT8189_CLK_TOP_MUX_AUDIOINTBUS] = "top_aud_intbus",
+ [MT8189_CLK_TOP_MUX_AUD_ENG1] = "top_aud_eng1",
+ [MT8189_CLK_TOP_MUX_AUD_ENG2] = "top_aud_eng2",
+ [MT8189_CLK_TOP_MUX_AUDIO_H] = "top_aud_h",
+ /* pll */
+ [MT8189_CLK_TOP_APLL1_CK] = "apll1",
+ [MT8189_CLK_TOP_APLL2_CK] = "apll2",
+ /* divider */
+ [MT8189_CLK_TOP_APLL1_D4] = "apll1_d4",
+ [MT8189_CLK_TOP_APLL2_D4] = "apll2_d4",
+ [MT8189_CLK_TOP_APLL12_DIV_I2SIN0] = "apll12_div_i2sin0",
+ [MT8189_CLK_TOP_APLL12_DIV_I2SIN1] = "apll12_div_i2sin1",
+ [MT8189_CLK_TOP_APLL12_DIV_I2SOUT0] = "apll12_div_i2sout0",
+ [MT8189_CLK_TOP_APLL12_DIV_I2SOUT1] = "apll12_div_i2sout1",
+ [MT8189_CLK_TOP_APLL12_DIV_FMI2S] = "apll12_div_fmi2s",
+ [MT8189_CLK_TOP_APLL12_DIV_TDMOUT_M] = "apll12_div_tdmout_m",
+ [MT8189_CLK_TOP_APLL12_DIV_TDMOUT_B] = "apll12_div_tdmout_b",
+ /* mux */
+ [MT8189_CLK_TOP_MUX_AUD_1] = "top_apll1",
+ [MT8189_CLK_TOP_MUX_AUD_2] = "top_apll2",
+ [MT8189_CLK_TOP_I2SIN0_M_SEL] = "top_i2sin0",
+ [MT8189_CLK_TOP_I2SIN1_M_SEL] = "top_i2sin1",
+ [MT8189_CLK_TOP_I2SOUT0_M_SEL] = "top_i2sout0",
+ [MT8189_CLK_TOP_I2SOUT1_M_SEL] = "top_i2sout1",
+ [MT8189_CLK_TOP_FMI2S_M_SEL] = "top_fmi2s",
+ [MT8189_CLK_TOP_TDMOUT_M_SEL] = "top_dptx",
+ /* top 26m*/
+ [MT8189_CLK_TOP_CLK26M] = "clk26m",
+ /* peri */
+ [MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI] = "aud_slv_ck_peri",
+ [MT8189_CLK_PERAO_AUDIO_MST_CK_PERI] = "aud_mst_ck_peri",
+ [MT8189_CLK_PERAO_INTBUS_CK_PERI] = "aud_intbus_ck_peri",
+};
+
+int mt8189_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ int ret;
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(afe->dev, "failed to enable clk\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt8189_afe_enable_clk);
+
+void mt8189_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ if (clk)
+ clk_disable_unprepare(clk);
+ else
+ dev_dbg(afe->dev, "NULL clk\n");
+}
+EXPORT_SYMBOL_GPL(mt8189_afe_disable_clk);
+
+static int mt8189_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+ unsigned int rate)
+{
+ int ret;
+
+ if (clk) {
+ ret = clk_set_rate(clk, rate);
+ if (ret) {
+ dev_err(afe->dev, "failed to set clk rate\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mt8189_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+ struct clk *parent)
+{
+ int ret;
+
+ if (clk && parent) {
+ ret = clk_set_parent(clk, parent);
+ if (ret) {
+ dev_dbg(afe->dev, "failed to set clk parent %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int get_top_cg_reg(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8189_AUDIO_26M_EN_ON:
+ case MT8189_AUDIO_F3P25M_EN_ON:
+ case MT8189_AUDIO_APLL1_EN_ON:
+ case MT8189_AUDIO_APLL2_EN_ON:
+ return AUDIO_ENGEN_CON0;
+ case MT8189_CG_AUDIO_HOPPING_CK:
+ case MT8189_CG_AUDIO_F26M_CK:
+ case MT8189_CG_APLL1_CK:
+ case MT8189_CG_APLL2_CK:
+ case MT8189_PDN_APLL_TUNER2:
+ case MT8189_PDN_APLL_TUNER1:
+ return AUDIO_TOP_CON4;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8189_AUDIO_26M_EN_ON:
+ return AUDIO_26M_EN_ON_MASK_SFT;
+ case MT8189_AUDIO_F3P25M_EN_ON:
+ return AUDIO_F3P25M_EN_ON_MASK_SFT;
+ case MT8189_AUDIO_APLL1_EN_ON:
+ return AUDIO_APLL1_EN_ON_MASK_SFT;
+ case MT8189_AUDIO_APLL2_EN_ON:
+ return AUDIO_APLL2_EN_ON_MASK_SFT;
+ case MT8189_CG_AUDIO_HOPPING_CK:
+ return CG_AUDIO_HOPPING_CK_MASK_SFT;
+ case MT8189_CG_AUDIO_F26M_CK:
+ return CG_AUDIO_F26M_CK_MASK_SFT;
+ case MT8189_CG_APLL1_CK:
+ return CG_APLL1_CK_MASK_SFT;
+ case MT8189_CG_APLL2_CK:
+ return CG_APLL2_CK_MASK_SFT;
+ case MT8189_PDN_APLL_TUNER2:
+ return PDN_APLL_TUNER2_MASK_SFT;
+ case MT8189_PDN_APLL_TUNER1:
+ return PDN_APLL_TUNER1_MASK_SFT;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8189_AUDIO_26M_EN_ON:
+ case MT8189_AUDIO_F3P25M_EN_ON:
+ case MT8189_AUDIO_APLL1_EN_ON:
+ case MT8189_AUDIO_APLL2_EN_ON:
+ return get_top_cg_mask(cg_type);
+ case MT8189_CG_AUDIO_HOPPING_CK:
+ case MT8189_CG_AUDIO_F26M_CK:
+ case MT8189_CG_APLL1_CK:
+ case MT8189_CG_APLL2_CK:
+ case MT8189_PDN_APLL_TUNER2:
+ case MT8189_PDN_APLL_TUNER1:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8189_AUDIO_26M_EN_ON:
+ case MT8189_AUDIO_F3P25M_EN_ON:
+ case MT8189_AUDIO_APLL1_EN_ON:
+ case MT8189_AUDIO_APLL2_EN_ON:
+ return 0;
+ case MT8189_CG_AUDIO_HOPPING_CK:
+ case MT8189_CG_AUDIO_F26M_CK:
+ case MT8189_CG_APLL1_CK:
+ case MT8189_CG_APLL2_CK:
+ case MT8189_PDN_APLL_TUNER2:
+ case MT8189_PDN_APLL_TUNER1:
+ return get_top_cg_mask(cg_type);
+ default:
+ return get_top_cg_mask(cg_type);
+ }
+}
+
+static int mt8189_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_on_val(cg_type);
+
+ if (!afe->regmap) {
+ dev_err(afe->dev, "afe regmap is null !!!\n");
+ return 0;
+ }
+
+ dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
+
+ return regmap_update_bits(afe->regmap, reg, mask, val);
+}
+
+static void mt8189_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_off_val(cg_type);
+
+ if (!afe->regmap) {
+ dev_warn(afe->dev, "skip regmap\n");
+ return;
+ }
+
+ dev_dbg(afe->dev, "reg: 0x%x, mask: 0x%x, val: 0x%x\n", reg, mask, val);
+ regmap_update_bits(afe->regmap, reg, mask, val);
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ dev_dbg(afe->dev, "enable: %d\n", enable);
+
+ if (enable) {
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8189_CLK_TOP_APLL1_CK]);
+ if (ret)
+ goto clk_ck_mux_aud1_parent_err;
+
+ /* 180.6336 / 4 = 45.1584MHz */
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1]);
+ if (ret)
+ goto clk_ck_mux_eng1_err;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[MT8189_CLK_TOP_APLL1_D4]);
+ if (ret)
+ goto clk_ck_mux_eng1_parent_err;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ if (ret)
+ goto clk_ck_mux_audio_h_err;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[MT8189_CLK_TOP_APLL1_CK]);
+ if (ret)
+ goto clk_ck_mux_audio_h_parent_err;
+ } else {
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1]);
+
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ }
+
+ return 0;
+
+clk_ck_mux_audio_h_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+clk_ck_mux_audio_h_err:
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_eng1_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG1]);
+clk_ck_mux_eng1_err:
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_aud1_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+
+ return ret;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ dev_dbg(afe->dev, "enable: %d\n", enable);
+
+ if (enable) {
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8189_CLK_TOP_APLL2_CK]);
+ if (ret)
+ goto clk_ck_mux_aud2_parent_err;
+
+ /* 196.608 / 4 = 49.152MHz */
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2]);
+ if (ret)
+ goto clk_ck_mux_eng2_err;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[MT8189_CLK_TOP_APLL2_D4]);
+ if (ret)
+ goto clk_ck_mux_eng2_parent_err;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ if (ret)
+ goto clk_ck_mux_audio_h_err;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[MT8189_CLK_TOP_APLL2_CK]);
+ if (ret)
+ goto clk_ck_mux_audio_h_parent_err;
+ } else {
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2]);
+
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ }
+
+ return 0;
+
+clk_ck_mux_audio_h_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+clk_ck_mux_audio_h_err:
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_eng2_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_ENG2]);
+clk_ck_mux_eng2_err:
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+clk_ck_mux_aud2_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+
+ return ret;
+}
+
+static int mt8189_afe_disable_apll(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+ if (ret)
+ goto clk_ck_mux_aud1_err;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+ if (ret)
+ goto clk_ck_mux_aud1_parent_err;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+ if (ret)
+ goto clk_ck_mux_aud2_err;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+ if (ret)
+ goto clk_ck_mux_aud2_parent_err;
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+
+ return 0;
+
+clk_ck_mux_aud2_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_2]);
+clk_ck_mux_aud2_err:
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1],
+ afe_priv->clk[MT8189_CLK_TOP_APLL1_CK]);
+clk_ck_mux_aud1_parent_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUD_1]);
+clk_ck_mux_aud1_err:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+
+ return ret;
+}
+
+int mt8189_apll1_enable(struct mtk_base_afe *afe)
+{
+ int ret;
+
+ /* setting for APLL */
+ ret = apll1_mux_setting(afe, true);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_top_cg(afe, MT8189_CG_APLL1_CK);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_top_cg(afe, MT8189_PDN_APLL_TUNER1);
+ if (ret)
+ return ret;
+
+ /* sel 44.1kHz:1, apll_div:7, upper bound:3 */
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+ XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT |
+ UPPER_BOUND_MASK_SFT,
+ (0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
+ (3 << UPPER_BOUND_SFT));
+
+ /* apll1 freq tuner enable */
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+ FREQ_TUNER_EN_MASK_SFT,
+ 0x1 << FREQ_TUNER_EN_SFT);
+
+ /* audio apll1 on */
+ ret = mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_APLL1_EN_ON);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void mt8189_apll1_disable(struct mtk_base_afe *afe)
+{
+ /* audio apll1 off */
+ mt8189_afe_disable_top_cg(afe, MT8189_AUDIO_APLL1_EN_ON);
+
+ /* apll1 freq tuner disable */
+ regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
+ FREQ_TUNER_EN_MASK_SFT,
+ 0x0);
+
+ mt8189_afe_disable_top_cg(afe, MT8189_PDN_APLL_TUNER1);
+ mt8189_afe_disable_top_cg(afe, MT8189_CG_APLL1_CK);
+ apll1_mux_setting(afe, false);
+}
+
+int mt8189_apll2_enable(struct mtk_base_afe *afe)
+{
+ int ret;
+
+ /* setting for APLL */
+ ret = apll2_mux_setting(afe, true);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_top_cg(afe, MT8189_CG_APLL2_CK);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_top_cg(afe, MT8189_PDN_APLL_TUNER2);
+ if (ret)
+ return ret;
+
+ /* sel 48kHz: 2, apll_div: 7, upper bound: 3*/
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+ XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT |
+ UPPER_BOUND_MASK_SFT,
+ (0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
+ (3 << UPPER_BOUND_SFT));
+
+ /* apll2 freq tuner enable */
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+ FREQ_TUNER_EN_MASK_SFT,
+ 0x1 << FREQ_TUNER_EN_SFT);
+
+ /* audio apll2 on */
+ ret = mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_APLL2_EN_ON);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void mt8189_apll2_disable(struct mtk_base_afe *afe)
+{
+ /* audio apll2 off */
+ mt8189_afe_disable_top_cg(afe, MT8189_AUDIO_APLL2_EN_ON);
+
+ /* apll2 freq tuner disable */
+ regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
+ FREQ_TUNER_EN_MASK_SFT,
+ 0x0);
+
+ mt8189_afe_disable_top_cg(afe, MT8189_PDN_APLL_TUNER2);
+ mt8189_afe_disable_top_cg(afe, MT8189_CG_APLL2_CK);
+ apll2_mux_setting(afe, false);
+}
+
+int mt8189_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int clk_id;
+
+ if (apll < MT8189_APLL1 || apll > MT8189_APLL2) {
+ dev_warn(afe->dev, "invalid clk id %d\n", apll);
+ return 0;
+ }
+
+ if (apll == MT8189_APLL1)
+ clk_id = MT8189_CLK_TOP_APLL1_CK;
+ else
+ clk_id = MT8189_CLK_TOP_APLL2_CK;
+
+ return clk_get_rate(afe_priv->clk[clk_id]);
+}
+
+int mt8189_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+ return (rate % 8000) ? MT8189_APLL1 : MT8189_APLL2;
+}
+
+int mt8189_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+ if (strcmp(name, APLL1_W_NAME) == 0)
+ return MT8189_APLL1;
+
+ return MT8189_APLL2;
+}
+
+int mt8189_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int apll = mt8189_get_apll_by_rate(afe, rate);
+ int apll_clk_id = apll == MT8189_APLL1 ?
+ MT8189_CLK_TOP_MUX_AUD_1 : MT8189_CLK_TOP_MUX_AUD_2;
+ int m_sel_id;
+ int div_clk_id;
+ int ret;
+
+ dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
+
+ if (mck_id >= MT8189_MCK_NUM || mck_id < 0)
+ return -EINVAL;
+
+ m_sel_id = mck_div[mck_id].m_sel_id;
+ div_clk_id = mck_div[mck_id].div_clk_id;
+
+ /* select apll */
+ if (m_sel_id >= 0) {
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[m_sel_id]);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_set_clk_parent(afe, afe_priv->clk[m_sel_id],
+ afe_priv->clk[apll_clk_id]);
+ if (ret)
+ return ret;
+ }
+
+ /* enable div, set rate */
+ if (div_clk_id < 0) {
+ dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id);
+ return -EINVAL;
+ }
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int m_sel_id;
+ int div_clk_id;
+
+ dev_dbg(afe->dev, "mck_id: %d.\n", mck_id);
+
+ if (mck_id < 0) {
+ dev_err(afe->dev, "mck_id = %d < 0\n", mck_id);
+ return -EINVAL;
+ }
+
+ m_sel_id = mck_div[mck_id].m_sel_id;
+ div_clk_id = mck_div[mck_id].div_clk_id;
+
+ if (div_clk_id < 0) {
+ dev_err(afe->dev, "div_clk_id = %d < 0\n",
+ div_clk_id);
+ return -EINVAL;
+ }
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
+
+ if (m_sel_id >= 0)
+ mt8189_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
+
+ return 0;
+}
+
+int mt8189_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ /* bus clock for AFE internal access, like AFE SRAM */
+ mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+ /* enable audio clock source */
+ mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ mt8189_afe_set_clk_parent(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H],
+ afe_priv->clk[MT8189_CLK_TOP_CLK26M]);
+
+ return 0;
+}
+
+int mt8189_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIO_H]);
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_TOP_MUX_AUDIOINTBUS]);
+
+ return 0;
+}
+
+int mt8189_afe_enable_main_clock(struct mtk_base_afe *afe)
+{
+ return mt8189_afe_enable_top_cg(afe, MT8189_AUDIO_26M_EN_ON);
+}
+
+void mt8189_afe_disable_main_clock(struct mtk_base_afe *afe)
+{
+ mt8189_afe_disable_top_cg(afe, MT8189_AUDIO_26M_EN_ON);
+}
+
+static int mt8189_afe_enable_ao_clock(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* Peri clock AO enable */
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_INTBUS_CK_PERI]);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI]);
+ if (ret)
+ goto err_clk_perao_slv;
+
+ ret = mt8189_afe_enable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_AUDIO_MST_CK_PERI]);
+ if (ret)
+ goto err_clk_perao_mst;
+
+ return 0;
+
+err_clk_perao_mst:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI]);
+err_clk_perao_slv:
+ mt8189_afe_disable_clk(afe, afe_priv->clk[MT8189_CLK_PERAO_INTBUS_CK_PERI]);
+
+ return ret;
+}
+
+int mt8189_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+ int i;
+
+ afe_priv->clk = devm_kcalloc(afe->dev, MT8189_CLK_NUM, sizeof(*afe_priv->clk),
+ GFP_KERNEL);
+ if (!afe_priv->clk)
+ return -ENOMEM;
+
+ for (i = 0; i < MT8189_CLK_NUM; i++) {
+ afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clk[i])) {
+ dev_err(afe->dev, "devm_clk_get %s fail\n", aud_clks[i]);
+ return PTR_ERR(afe_priv->clk[i]);
+ }
+ }
+
+ ret = mt8189_afe_disable_apll(afe);
+ if (ret)
+ return ret;
+
+ ret = mt8189_afe_enable_ao_clock(afe);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-clk.h b/sound/soc/mediatek/mt8189/mt8189-afe-clk.h
new file mode 100644
index 000000000000..9ce5d1043feb
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-clk.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8189-afe-clk.h -- Mediatek 8189 afe clock ctrl definition
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8189_AFE_CLOCK_CTRL_H_
+#define _MT8189_AFE_CLOCK_CTRL_H_
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+
+enum {
+ MT8189_APLL1,
+ MT8189_APLL2,
+};
+
+enum {
+ MT8189_CLK_TOP_MUX_AUDIOINTBUS,
+ MT8189_CLK_TOP_MUX_AUD_ENG1,
+ MT8189_CLK_TOP_MUX_AUD_ENG2,
+ MT8189_CLK_TOP_MUX_AUDIO_H,
+ /* pll */
+ MT8189_CLK_TOP_APLL1_CK,
+ MT8189_CLK_TOP_APLL2_CK,
+ /* divider */
+ MT8189_CLK_TOP_APLL1_D4,
+ MT8189_CLK_TOP_APLL2_D4,
+ MT8189_CLK_TOP_APLL12_DIV_I2SIN0,
+ MT8189_CLK_TOP_APLL12_DIV_I2SIN1,
+ MT8189_CLK_TOP_APLL12_DIV_I2SOUT0,
+ MT8189_CLK_TOP_APLL12_DIV_I2SOUT1,
+ MT8189_CLK_TOP_APLL12_DIV_FMI2S,
+ MT8189_CLK_TOP_APLL12_DIV_TDMOUT_M,
+ MT8189_CLK_TOP_APLL12_DIV_TDMOUT_B,
+ /* mux */
+ MT8189_CLK_TOP_MUX_AUD_1,
+ MT8189_CLK_TOP_MUX_AUD_2,
+ MT8189_CLK_TOP_I2SIN0_M_SEL,
+ MT8189_CLK_TOP_I2SIN1_M_SEL,
+ MT8189_CLK_TOP_I2SOUT0_M_SEL,
+ MT8189_CLK_TOP_I2SOUT1_M_SEL,
+ MT8189_CLK_TOP_FMI2S_M_SEL,
+ MT8189_CLK_TOP_TDMOUT_M_SEL,
+ /* top 26m */
+ MT8189_CLK_TOP_CLK26M,
+ /* peri */
+ MT8189_CLK_PERAO_AUDIO_SLV_CK_PERI,
+ MT8189_CLK_PERAO_AUDIO_MST_CK_PERI,
+ MT8189_CLK_PERAO_INTBUS_CK_PERI,
+ MT8189_CLK_NUM,
+};
+
+struct mtk_base_afe;
+
+int mt8189_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+int mt8189_mck_disable(struct mtk_base_afe *afe, int mck_id);
+int mt8189_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8189_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8189_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+int mt8189_init_clock(struct mtk_base_afe *afe);
+int mt8189_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
+void mt8189_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+int mt8189_apll1_enable(struct mtk_base_afe *afe);
+void mt8189_apll1_disable(struct mtk_base_afe *afe);
+int mt8189_apll2_enable(struct mtk_base_afe *afe);
+void mt8189_apll2_disable(struct mtk_base_afe *afe);
+int mt8189_afe_enable_main_clock(struct mtk_base_afe *afe);
+void mt8189_afe_disable_main_clock(struct mtk_base_afe *afe);
+int mt8189_afe_enable_reg_rw_clk(struct mtk_base_afe *afe);
+int mt8189_afe_disable_reg_rw_clk(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-common.h b/sound/soc/mediatek/mt8189/mt8189-afe-common.h
new file mode 100644
index 000000000000..910d90d3d146
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-common.h
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8189-afe-common.h -- Mediatek 8189 audio driver definitions
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT_8189_AFE_COMMON_H_
+#define _MT_8189_AFE_COMMON_H_
+
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "mt8189-reg.h"
+#include "../common/mtk-base-afe.h"
+
+enum {
+ MTK_AFE_RATE_8K,
+ MTK_AFE_RATE_11K,
+ MTK_AFE_RATE_12K,
+ MTK_AFE_RATE_384K,
+ MTK_AFE_RATE_16K,
+ MTK_AFE_RATE_22K,
+ MTK_AFE_RATE_24K,
+ MTK_AFE_RATE_352K,
+ MTK_AFE_RATE_32K,
+ MTK_AFE_RATE_44K,
+ MTK_AFE_RATE_48K,
+ MTK_AFE_RATE_88K,
+ MTK_AFE_RATE_96K,
+ MTK_AFE_RATE_176K,
+ MTK_AFE_RATE_192K,
+ MTK_AFE_RATE_260K,
+};
+
+/* HW IPM 2.0 */
+enum {
+ MTK_AFE_IPM2P0_RATE_8K = 0x0,
+ MTK_AFE_IPM2P0_RATE_11K = 0x1,
+ MTK_AFE_IPM2P0_RATE_12K = 0x2,
+ MTK_AFE_IPM2P0_RATE_16K = 0x4,
+ MTK_AFE_IPM2P0_RATE_22K = 0x5,
+ MTK_AFE_IPM2P0_RATE_24K = 0x6,
+ MTK_AFE_IPM2P0_RATE_32K = 0x8,
+ MTK_AFE_IPM2P0_RATE_44K = 0x9,
+ MTK_AFE_IPM2P0_RATE_48K = 0xa,
+ MTK_AFE_IPM2P0_RATE_88K = 0xd,
+ MTK_AFE_IPM2P0_RATE_96K = 0xe,
+ MTK_AFE_IPM2P0_RATE_176K = 0x11,
+ MTK_AFE_IPM2P0_RATE_192K = 0x12,
+ MTK_AFE_IPM2P0_RATE_352K = 0x15,
+ MTK_AFE_IPM2P0_RATE_384K = 0x16,
+};
+
+enum {
+ MTK_AFE_DAI_MEMIF_RATE_8K,
+ MTK_AFE_DAI_MEMIF_RATE_16K,
+ MTK_AFE_DAI_MEMIF_RATE_32K,
+ MTK_AFE_DAI_MEMIF_RATE_48K,
+};
+
+enum {
+ MTK_AFE_PCM_RATE_8K,
+ MTK_AFE_PCM_RATE_16K,
+ MTK_AFE_PCM_RATE_32K,
+ MTK_AFE_PCM_RATE_48K,
+};
+
+enum {
+ MTKAIF_PROTOCOL_1,
+ MTKAIF_PROTOCOL_2,
+ MTKAIF_PROTOCOL_2_CLK_P2,
+};
+
+enum {
+ MT8189_MEMIF_DL0,
+ MT8189_MEMIF_DL1,
+ MT8189_MEMIF_DL2,
+ MT8189_MEMIF_DL3,
+ MT8189_MEMIF_DL4,
+ MT8189_MEMIF_DL5,
+ MT8189_MEMIF_DL6,
+ MT8189_MEMIF_DL7,
+ MT8189_MEMIF_DL8,
+ MT8189_MEMIF_DL23,
+ MT8189_MEMIF_DL24,
+ MT8189_MEMIF_DL25,
+ MT8189_MEMIF_DL_24CH,
+ MT8189_MEMIF_VUL0,
+ MT8189_MEMIF_VUL1,
+ MT8189_MEMIF_VUL2,
+ MT8189_MEMIF_VUL3,
+ MT8189_MEMIF_VUL4,
+ MT8189_MEMIF_VUL5,
+ MT8189_MEMIF_VUL6,
+ MT8189_MEMIF_VUL7,
+ MT8189_MEMIF_VUL8,
+ MT8189_MEMIF_VUL9,
+ MT8189_MEMIF_VUL10,
+ MT8189_MEMIF_VUL24,
+ MT8189_MEMIF_VUL25,
+ MT8189_MEMIF_VUL_CM0,
+ MT8189_MEMIF_VUL_CM1,
+ MT8189_MEMIF_ETDM_IN0,
+ MT8189_MEMIF_ETDM_IN1,
+ MT8189_MEMIF_HDMI,
+ MT8189_MEMIF_NUM,
+ MT8189_DAI_ADDA = MT8189_MEMIF_NUM,
+ MT8189_DAI_ADDA_CH34,
+ MT8189_DAI_ADDA_CH56,
+ MT8189_DAI_AP_DMIC,
+ MT8189_DAI_AP_DMIC_CH34,
+ MT8189_DAI_I2S_IN0,
+ MT8189_DAI_I2S_IN1,
+ MT8189_DAI_I2S_OUT0,
+ MT8189_DAI_I2S_OUT1,
+ MT8189_DAI_I2S_OUT4,
+ MT8189_DAI_PCM_0,
+ MT8189_DAI_TDM,
+ MT8189_DAI_TDM_DPTX,
+ MT8189_DAI_NUM,
+};
+
+/* update irq ID (= enum) from AFE_IRQ_MCU_STATUS */
+enum {
+ MT8189_IRQ_0,
+ MT8189_IRQ_1,
+ MT8189_IRQ_2,
+ MT8189_IRQ_3,
+ MT8189_IRQ_4,
+ MT8189_IRQ_5,
+ MT8189_IRQ_6,
+ MT8189_IRQ_7,
+ MT8189_IRQ_8,
+ MT8189_IRQ_9,
+ MT8189_IRQ_10,
+ MT8189_IRQ_11,
+ MT8189_IRQ_12,
+ MT8189_IRQ_13,
+ MT8189_IRQ_14,
+ MT8189_IRQ_15,
+ MT8189_IRQ_16,
+ MT8189_IRQ_17,
+ MT8189_IRQ_18,
+ MT8189_IRQ_19,
+ MT8189_IRQ_20,
+ MT8189_IRQ_21,
+ MT8189_IRQ_22,
+ MT8189_IRQ_23,
+ MT8189_IRQ_24,
+ MT8189_IRQ_25,
+ MT8189_IRQ_26,
+ MT8189_IRQ_31,
+ MT8189_IRQ_NUM,
+};
+
+/* update irq ID (= enum) from AFE_IRQ_MCU_STATUS */
+enum {
+ MT8189_CUS_IRQ_TDM, /* used only for TDM */
+ MT8189_CUS_IRQ_NUM,
+};
+
+enum {
+ /* AUDIO_ENGEN_CON0 */
+ MT8189_AUDIO_26M_EN_ON,
+ MT8189_AUDIO_F3P25M_EN_ON,
+ MT8189_AUDIO_APLL1_EN_ON,
+ MT8189_AUDIO_APLL2_EN_ON,
+ MT8189_AUDIO_F26M_EN_RST,
+ MT8189_MULTI_USER_RST,
+ MT8189_MULTI_USER_BYPASS,
+ /* AUDIO_TOP_CON4 */
+ MT8189_CG_AUDIO_HOPPING_CK,
+ MT8189_CG_AUDIO_F26M_CK,
+ MT8189_CG_APLL1_CK,
+ MT8189_CG_APLL2_CK,
+ MT8189_PDN_APLL_TUNER2,
+ MT8189_PDN_APLL_TUNER1,
+ MT8189_AUDIO_CG_NUM,
+};
+
+/* MCLK */
+enum {
+ MT8189_I2SIN0_MCK,
+ MT8189_I2SIN1_MCK,
+ MT8189_I2SOUT0_MCK,
+ MT8189_I2SOUT1_MCK,
+ MT8189_FMI2S_MCK,
+ MT8189_TDMOUT_MCK,
+ MT8189_TDMOUT_BCK,
+ MT8189_MCK_NUM,
+};
+
+enum {
+ CM0,
+ CM1,
+ CM_NUM,
+};
+
+struct clk;
+
+struct mt8189_afe_private {
+ struct clk **clk;
+ struct regmap *pmic_regmap;
+
+ /* dai */
+ void *dai_priv[MT8189_DAI_NUM];
+
+ /* adda */
+ int mtkaif_protocol;
+ int mtkaif_chosen_phase[4];
+ int mtkaif_phase_cycle[4];
+ int mtkaif_calibration_num_phase;
+ int mtkaif_dmic;
+ int mtkaif_dmic_ch34;
+
+ /* add for vs1 voter */
+ bool is_adda_dl_on;
+ bool is_adda_ul_on;
+ /* adda dl vol idx is at maximum */
+ bool is_adda_dl_max_vol;
+ /* current vote status of vs1 */
+ bool is_mt6363_vote;
+
+ /* mck */
+ int mck_rate[MT8189_MCK_NUM];
+
+ /* channel merge */
+ unsigned int cm_rate[CM_NUM];
+ unsigned int cm_channels;
+};
+
+int mt8189_dai_adda_register(struct mtk_base_afe *afe);
+int mt8189_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8189_dai_pcm_register(struct mtk_base_afe *afe);
+int mt8189_dai_tdm_register(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
new file mode 100644
index 000000000000..166ece74270e
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-afe-pcm.c
@@ -0,0 +1,2615 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek ALSA SoC AFE platform driver for 8189
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+#include "../common/mtk-afe-fe-dai.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+static const struct snd_pcm_hardware mt8189_afe_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .period_bytes_min = 96,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 256 * 1024,
+ .fifo_size = 0,
+};
+
+static unsigned int mt8189_rate_transform(struct device *dev, unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_IPM2P0_RATE_8K;
+ case 11025:
+ return MTK_AFE_IPM2P0_RATE_11K;
+ case 12000:
+ return MTK_AFE_IPM2P0_RATE_12K;
+ case 16000:
+ return MTK_AFE_IPM2P0_RATE_16K;
+ case 22050:
+ return MTK_AFE_IPM2P0_RATE_22K;
+ case 24000:
+ return MTK_AFE_IPM2P0_RATE_24K;
+ case 32000:
+ return MTK_AFE_IPM2P0_RATE_32K;
+ case 44100:
+ return MTK_AFE_IPM2P0_RATE_44K;
+ case 48000:
+ return MTK_AFE_IPM2P0_RATE_48K;
+ case 88200:
+ return MTK_AFE_IPM2P0_RATE_88K;
+ case 96000:
+ return MTK_AFE_IPM2P0_RATE_96K;
+ case 176400:
+ return MTK_AFE_IPM2P0_RATE_176K;
+ case 192000:
+ return MTK_AFE_IPM2P0_RATE_192K;
+ /* not support 260K */
+ case 352800:
+ return MTK_AFE_IPM2P0_RATE_352K;
+ case 384000:
+ return MTK_AFE_IPM2P0_RATE_384K;
+ default:
+ dev_warn(dev, "rate %u invalid, use %d!!!\n",
+ rate, MTK_AFE_IPM2P0_RATE_48K);
+ return MTK_AFE_IPM2P0_RATE_48K;
+ }
+}
+
+static inline unsigned int calculate_cm_update(unsigned int rate,
+ unsigned int ch)
+{
+ return (((26000000 / rate) - 10) / (ch / 2)) - 1;
+}
+
+static int mt8189_set_cm(struct mtk_base_afe *afe, int id,
+ bool update, bool swap, unsigned int ch)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = afe_priv->cm_rate[id];
+ unsigned int rate_val = mt8189_rate_transform(afe->dev, rate);
+ unsigned int update_val = update ? calculate_cm_update(rate, ch) : 0x64;
+ int reg = AFE_CM0_CON0 + 0x10 * id;
+
+ dev_dbg(afe->dev, "%s()-0, CM%d, rate %d, update %d, swap %d, ch %d\n",
+ __func__, id, rate, update, swap, ch);
+
+ /* update cnt */
+ regmap_update_bits(afe->regmap, reg,
+ AFE_CM_UPDATE_CNT_MASK << AFE_CM_UPDATE_CNT_SFT,
+ update_val << AFE_CM_UPDATE_CNT_SFT);
+
+ /* rate */
+ regmap_update_bits(afe->regmap, reg,
+ AFE_CM_1X_EN_SEL_FS_MASK << AFE_CM_1X_EN_SEL_FS_SFT,
+ rate_val << AFE_CM_1X_EN_SEL_FS_SFT);
+
+ /* ch num */
+ regmap_update_bits(afe->regmap, reg,
+ AFE_CM_CH_NUM_MASK << AFE_CM_CH_NUM_SFT,
+ (ch - 1) << AFE_CM_CH_NUM_SFT);
+
+ /* swap */
+ regmap_update_bits(afe->regmap, reg,
+ AFE_CM_BYTE_SWAP_MASK << AFE_CM_BYTE_SWAP_SFT,
+ swap << AFE_CM_BYTE_SWAP_SFT);
+
+ return 0;
+}
+
+static int mt8189_enable_cm_bypass(struct mtk_base_afe *afe, int id, bool en)
+{
+ return regmap_update_bits(afe->regmap, AFE_CM0_CON0 + 0x10 * id,
+ AFE_CM_BYPASS_MODE_MASK <<
+ AFE_CM_BYPASS_MODE_SFT,
+ en << AFE_CM_BYPASS_MODE_SFT);
+}
+
+static int mt8189_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ int memif_num = cpu_dai->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+ const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
+ int ret;
+
+ dev_dbg(afe->dev, "%s(), memif_num: %d.\n", __func__, memif_num);
+
+ memif->substream = substream;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
+ snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ dev_warn(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+ /* dynamic allocate irq to memif */
+ if (memif->irq_usage < 0) {
+ int irq_id = mtk_dynamic_irq_acquire(afe);
+
+ if (irq_id != afe->irqs_size) {
+ /* link */
+ memif->irq_usage = irq_id;
+ } else {
+ dev_err(afe->dev, "%s() error: no more asys irq\n",
+ __func__);
+ ret = -EBUSY;
+ }
+ }
+
+ return ret;
+}
+
+static void mt8189_fe_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ int memif_num = cpu_dai->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+ int irq_id = memif->irq_usage;
+
+ dev_dbg(afe->dev, "%s(), memif_num: %d.\n", __func__, memif_num);
+
+ memif->substream = NULL;
+
+ if (!memif->const_irq) {
+ mtk_dynamic_irq_release(afe, irq_id);
+ memif->irq_usage = -1;
+ memif->substream = NULL;
+ }
+}
+
+static int mt8189_fe_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ int id = dai->id;
+ int cm;
+
+ switch (id) {
+ case MT8189_MEMIF_VUL8:
+ case MT8189_MEMIF_VUL_CM0:
+ cm = CM0;
+ break;
+ case MT8189_MEMIF_VUL9:
+ case MT8189_MEMIF_VUL_CM1:
+ cm = CM1;
+ break;
+ default:
+ cm = CM0;
+ break;
+ }
+
+ afe_priv->cm_rate[cm] = params_rate(params);
+ afe_priv->cm_channels = params_channels(params);
+
+ return mtk_afe_fe_hw_params(substream, params, dai);
+}
+
+static int mt8189_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_pcm_runtime *const runtime = substream->runtime;
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ int id = cpu_dai->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[id];
+ int irq_id = memif->irq_usage;
+ struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
+ const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+ unsigned int counter = runtime->period_size;
+ unsigned int rate = runtime->rate;
+ unsigned int tmp_reg;
+ int fs;
+ int ret;
+
+ dev_dbg(afe->dev, "%s(), %s cmd %d, irq_id %d, dai_id %d\n", __func__,
+ memif->data->name, cmd, irq_id, id);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = mtk_memif_set_enable(afe, id);
+ if (ret) {
+ dev_err(afe->dev, "id %d, memif enable fail.\n", id);
+ return ret;
+ }
+
+ /*
+ * for small latency record
+ * ul memif need read some data before irq enable
+ * the context of this triger ops is atmoic, so it cannot sleep
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ if ((runtime->period_size * 1000) / rate <= 10)
+ udelay(300);
+
+ regmap_update_bits(afe->regmap,
+ irq_data->irq_cnt_reg,
+ irq_data->irq_cnt_maskbit <<
+ irq_data->irq_cnt_shift,
+ counter << irq_data->irq_cnt_shift);
+
+ /* set irq fs */
+ fs = afe->irq_fs(substream, rate);
+ if (fs < 0)
+ return -EINVAL;
+
+ if (irq_data->irq_fs_reg >= 0)
+ regmap_update_bits(afe->regmap,
+ irq_data->irq_fs_reg,
+ irq_data->irq_fs_maskbit <<
+ irq_data->irq_fs_shift,
+ fs << irq_data->irq_fs_shift);
+
+ /* enable interrupt */
+ regmap_update_bits(afe->regmap,
+ irq_data->irq_en_reg,
+ 1 << irq_data->irq_en_shift,
+ 1 << irq_data->irq_en_shift);
+
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ret = mtk_memif_set_disable(afe, id);
+ if (ret)
+ dev_warn(afe->dev, "id %d, memif disable fail\n", id);
+
+ /* disable interrupt */
+ regmap_update_bits(afe->regmap,
+ irq_data->irq_en_reg,
+ 1 << irq_data->irq_en_shift,
+ 0 << irq_data->irq_en_shift);
+
+ /*
+ * clear pending IRQ, if the register read as one, there is no
+ * need to write one to clear operation.
+ */
+ regmap_read(afe->regmap, irq_data->irq_clr_reg, &tmp_reg);
+ regmap_update_bits(afe->regmap, irq_data->irq_clr_reg,
+ AFE_IRQ_CLR_CFG_MASK_SFT |
+ AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
+ tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
+ AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt8189_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = NULL;
+
+ if (!component)
+ return -EINVAL;
+
+ afe = snd_soc_component_get_drvdata(component);
+ if (!afe)
+ return -EINVAL;
+
+ return mt8189_rate_transform(afe->dev, rate);
+}
+
+static int mt8189_get_dai_fs(struct mtk_base_afe *afe,
+ int dai_id, unsigned int rate)
+{
+ return mt8189_rate_transform(afe->dev, rate);
+}
+
+static int mt8189_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = NULL;
+
+ if (!component)
+ return -EINVAL;
+ afe = snd_soc_component_get_drvdata(component);
+
+ return mt8189_rate_transform(afe->dev, rate);
+}
+
+static int mt8189_get_memif_pbuf_size(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if ((runtime->period_size * 1000) / runtime->rate > 10)
+ return MT8189_MEMIF_PBUF_SIZE_256_BYTES;
+
+ return MT8189_MEMIF_PBUF_SIZE_32_BYTES;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8189_memif_dai_ops = {
+ .startup = mt8189_fe_startup,
+ .shutdown = mt8189_fe_shutdown,
+ .hw_params = mt8189_fe_hw_params,
+ .hw_free = mtk_afe_fe_hw_free,
+ .prepare = mtk_afe_fe_prepare,
+ .trigger = mt8189_fe_trigger,
+};
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 | \
+ SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000 | \
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define MT8189_FE_DAI_PLAYBACK(_name, _id, max_ch) \
+{ \
+ .name = #_name, \
+ .id = _id, \
+ .playback = { \
+ .stream_name = #_name, \
+ .channels_min = 1, \
+ .channels_max = max_ch, \
+ .rates = MTK_PCM_RATES, \
+ .formats = MTK_PCM_FORMATS, \
+ }, \
+ .ops = &mt8189_memif_dai_ops, \
+}
+
+#define MT8189_FE_DAI_CAPTURE(_name, _id, max_ch) \
+{ \
+ .name = #_name, \
+ .id = _id, \
+ .capture = { \
+ .stream_name = #_name, \
+ .channels_min = 1, \
+ .channels_max = max_ch, \
+ .rates = MTK_PCM_RATES, \
+ .formats = MTK_PCM_FORMATS, \
+ }, \
+ .ops = &mt8189_memif_dai_ops, \
+}
+
+static struct snd_soc_dai_driver mt8189_memif_dai_driver[] = {
+ /* FE DAIs: memory interfaces to CPU */
+ /* Playback */
+ MT8189_FE_DAI_PLAYBACK(DL0, MT8189_MEMIF_DL0, 2),
+ MT8189_FE_DAI_PLAYBACK(DL1, MT8189_MEMIF_DL1, 2),
+ MT8189_FE_DAI_PLAYBACK(DL2, MT8189_MEMIF_DL2, 2),
+ MT8189_FE_DAI_PLAYBACK(DL3, MT8189_MEMIF_DL3, 2),
+ MT8189_FE_DAI_PLAYBACK(DL4, MT8189_MEMIF_DL4, 2),
+ MT8189_FE_DAI_PLAYBACK(DL5, MT8189_MEMIF_DL5, 2),
+ MT8189_FE_DAI_PLAYBACK(DL6, MT8189_MEMIF_DL6, 2),
+ MT8189_FE_DAI_PLAYBACK(DL7, MT8189_MEMIF_DL7, 2),
+ MT8189_FE_DAI_PLAYBACK(DL8, MT8189_MEMIF_DL8, 2),
+ MT8189_FE_DAI_PLAYBACK(DL23, MT8189_MEMIF_DL23, 2),
+ MT8189_FE_DAI_PLAYBACK(DL24, MT8189_MEMIF_DL24, 2),
+ MT8189_FE_DAI_PLAYBACK(DL25, MT8189_MEMIF_DL25, 2),
+ MT8189_FE_DAI_PLAYBACK(DL_24CH, MT8189_MEMIF_DL_24CH, 8),
+ MT8189_FE_DAI_PLAYBACK(HDMI, MT8189_MEMIF_HDMI, 8),
+ /* Capture */
+ MT8189_FE_DAI_CAPTURE(UL0, MT8189_MEMIF_VUL0, 2),
+ MT8189_FE_DAI_CAPTURE(UL1, MT8189_MEMIF_VUL1, 2),
+ MT8189_FE_DAI_CAPTURE(UL2, MT8189_MEMIF_VUL2, 2),
+ MT8189_FE_DAI_CAPTURE(UL3, MT8189_MEMIF_VUL3, 2),
+ MT8189_FE_DAI_CAPTURE(UL4, MT8189_MEMIF_VUL4, 2),
+ MT8189_FE_DAI_CAPTURE(UL5, MT8189_MEMIF_VUL5, 2),
+ MT8189_FE_DAI_CAPTURE(UL6, MT8189_MEMIF_VUL6, 2),
+ MT8189_FE_DAI_CAPTURE(UL7, MT8189_MEMIF_VUL7, 2),
+ MT8189_FE_DAI_CAPTURE(UL8, MT8189_MEMIF_VUL8, 2),
+ MT8189_FE_DAI_CAPTURE(UL9, MT8189_MEMIF_VUL9, 16),
+ MT8189_FE_DAI_CAPTURE(UL10, MT8189_MEMIF_VUL10, 2),
+ MT8189_FE_DAI_CAPTURE(UL24, MT8189_MEMIF_VUL24, 2),
+ MT8189_FE_DAI_CAPTURE(UL25, MT8189_MEMIF_VUL25, 2),
+ MT8189_FE_DAI_CAPTURE(UL_CM0, MT8189_MEMIF_VUL_CM0, 8),
+ MT8189_FE_DAI_CAPTURE(UL_CM1, MT8189_MEMIF_VUL_CM1, 16),
+ MT8189_FE_DAI_CAPTURE(UL_ETDM_IN0, MT8189_MEMIF_ETDM_IN0, 2),
+ MT8189_FE_DAI_CAPTURE(UL_ETDM_IN1, MT8189_MEMIF_ETDM_IN1, 2),
+};
+
+static int ul_cm0_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ unsigned int channels = afe_priv->cm_channels;
+
+ dev_dbg(afe->dev, "%s(), event 0x%x, name %s, channels %d\n",
+ __func__, event, w->name, channels);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8189_enable_cm_bypass(afe, CM0, false);
+ mt8189_set_cm(afe, CM0, true, false, channels);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM0_MASK_SFT, 0 << PDN_CM0_SFT);
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ mt8189_enable_cm_bypass(afe, CM0, true);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM0_MASK_SFT, 1 << PDN_CM0_SFT);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ul_cm1_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ unsigned int channels = afe_priv->cm_channels;
+
+ dev_dbg(afe->dev, "%s(), event 0x%x, name %s, channels %d\n",
+ __func__, event, w->name, channels);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8189_enable_cm_bypass(afe, CM1, false);
+ mt8189_set_cm(afe, CM1, true, false, channels);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM1_MASK_SFT, 0 << PDN_CM1_SFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8189_enable_cm_bypass(afe, CM1, true);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+ PDN_CM1_MASK_SFT, 1 << PDN_CM1_SFT);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * dma widget & routes
+ * The mixer controls and routes are by no means fully implemented,
+ * only the ones that are intended to be used are, as other wise a fully
+ * interconnected switch bar mixer would introduce way too many unused
+ * controls.
+ */
+static const struct snd_kcontrol_new memif_ul0_ch1_mix[] = {
+ /* Normal record */
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN018_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN018_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN018_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN018_0,
+ I_ADDA_UL_CH4, 1, 0),
+ /* AP DMIC */
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH1", AFE_CONN018_0,
+ I_DMIC0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN018_0,
+ I_DMIC0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN018_1,
+ I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN018_1,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN018_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN018_1,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN018_1,
+ I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN018_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN018_1,
+ I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH1", AFE_CONN018_2,
+ I_DL23_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN018_1,
+ I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN018_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN018_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN018_4,
+ I_I2SIN1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN018_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN018_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul0_ch2_mix[] = {
+ /* Normal record */
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN019_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN019_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN019_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN019_0,
+ I_ADDA_UL_CH4, 1, 0),
+ /* AP DMIC */
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN019_0,
+ I_DMIC0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN019_1,
+ I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN019_1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN019_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN019_1,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN019_1,
+ I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN019_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN019_1,
+ I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH2", AFE_CONN018_2,
+ I_DL23_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN019_1,
+ I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN019_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN019_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN019_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN019_4,
+ I_I2SIN1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN019_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN019_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN020_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN020_1,
+ I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN020_1,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN020_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN020_1,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN020_1,
+ I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN020_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN020_1,
+ I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH1", AFE_CONN020_2,
+ I_DL23_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN020_1,
+ I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN020_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN020_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN020_4,
+ I_I2SIN1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN020_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN020_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN021_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN021_1,
+ I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN021_1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN021_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN021_1,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN021_1,
+ I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN021_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN021_1,
+ I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL23_CH2", AFE_CONN021_2,
+ I_DL23_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN021_1,
+ I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN021_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN021_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN021_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN021_4,
+ I_I2SIN1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN021_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN021_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN022_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN022_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN022_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN022_0,
+ I_ADDA_UL_CH4, 1, 0),
+ /* AP DMIC */
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH3", AFE_CONN022_0,
+ I_DMIC1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH1", AFE_CONN022_0,
+ I_GAIN1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN022_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN023_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN023_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN023_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN023_0,
+ I_ADDA_UL_CH4, 1, 0),
+ /* AP DMIC */
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH4", AFE_CONN023_0,
+ I_DMIC1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH2", AFE_CONN023_0,
+ I_GAIN1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN023_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN024_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN024_4,
+ I_I2SIN1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN024_6,
+ I_SRC_3_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN025_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN025_4,
+ I_I2SIN1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN025_6,
+ I_SRC_3_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN026_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN026_1,
+ I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN026_1,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN026_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN026_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN026_1,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN026_1,
+ I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN026_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN026_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN026_6,
+ I_SRC_3_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN027_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN027_1,
+ I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN027_1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN027_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN027_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN027_1,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN027_1,
+ I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN027_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN027_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN027_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN027_6,
+ I_SRC_3_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN028_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN028_1,
+ I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN028_1,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN028_1,
+ I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN028_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN028_1,
+ I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN028_1,
+ I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN0_OUT_CH1", AFE_CONN028_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN028_6,
+ I_SRC_3_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN029_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN029_1,
+ I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN029_1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN029_1,
+ I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN029_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN029_1,
+ I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN029_1,
+ I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN029_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN029_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN0_OUT_CH2", AFE_CONN029_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN029_6,
+ I_SRC_3_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN030_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH1", AFE_CONN030_0,
+ I_DMIC0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN030_1,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN030_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN030_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH1", AFE_CONN030_6,
+ I_SRC_4_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN031_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN031_0,
+ I_DMIC0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN031_1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN031_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN031_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH2", AFE_CONN031_6,
+ I_SRC_4_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN032_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN032_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH3", AFE_CONN032_0,
+ I_DMIC1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN032_1,
+ I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN032_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH1", AFE_CONN032_4,
+ I_I2SIN0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH1", AFE_CONN032_6,
+ I_SRC_4_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN033_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN033_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH4", AFE_CONN033_0,
+ I_DMIC1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN033_1,
+ I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN033_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN0_CH2", AFE_CONN033_4,
+ I_I2SIN0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH2", AFE_CONN033_6,
+ I_SRC_4_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN034_0,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN035_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN035_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN035_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul9_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN036_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN036_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN036_0,
+ I_ADDA_UL_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul9_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN037_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN037_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN037_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN037_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul24_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN066_0,
+ I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul24_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN067_0,
+ I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN040_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN040_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN040_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN040_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH1", AFE_CONN040_0,
+ I_DMIC0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH1", AFE_CONN040_0,
+ I_GAIN1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN040_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN040_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN041_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN041_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN041_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN041_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH2", AFE_CONN041_0,
+ I_DMIC0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN1_OUT_CH2", AFE_CONN041_0,
+ I_GAIN1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN041_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN041_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN042_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN042_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN042_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN042_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH3", AFE_CONN042_0,
+ I_DMIC1_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN043_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN043_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN043_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN043_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("AP_DMIC_UL_CH4", AFE_CONN043_0,
+ I_DMIC1_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch5_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN044_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN044_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN044_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN044_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch6_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN045_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN045_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN045_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN045_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch7_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN046_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN046_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN046_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN046_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm0_ch8_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN047_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN047_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN047_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN047_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN048_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN048_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN048_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN048_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN048_0,
+ I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN048_0,
+ I_ADDA_UL_CH6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN048_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH1", AFE_CONN048_6,
+ I_SRC_3_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH1", AFE_CONN048_6,
+ I_SRC_4_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN049_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN049_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN049_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN049_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN049_0,
+ I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN049_0,
+ I_ADDA_UL_CH6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN049_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_3_OUT_CH2", AFE_CONN049_6,
+ I_SRC_3_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_4_OUT_CH2", AFE_CONN049_6,
+ I_SRC_4_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN050_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN050_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN050_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN050_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN050_0,
+ I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN050_0,
+ I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN051_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN051_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN051_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN051_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN051_0,
+ I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN051_0,
+ I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch5_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN052_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN052_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN052_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN052_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN052_0,
+ I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN052_0,
+ I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch6_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN053_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN053_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN053_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN053_0,
+ I_ADDA_UL_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH5", AFE_CONN053_0,
+ I_ADDA_UL_CH5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH6", AFE_CONN053_0,
+ I_ADDA_UL_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch7_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN054_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN054_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN054_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN054_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch8_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN055_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN055_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN055_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN055_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch9_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN056_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN056_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN056_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN056_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch10_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN057_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN057_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN057_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN057_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch11_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN058_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN058_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN058_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN058_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch12_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN059_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN059_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN059_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN059_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch13_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN060_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN060_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN060_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN060_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch14_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN061_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN061_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN061_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN061_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch15_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN062_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN062_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN062_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN062_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul_cm1_ch16_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN063_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN063_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN063_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN063_0,
+ I_ADDA_UL_CH4, 1, 0),
+};
+
+static const char * const cm0_mux_texts[] = {
+ "CM0_2CH_PATH",
+ "CM0_8CH_PATH",
+};
+
+static const char * const cm1_mux_map_texts[] = {
+ "CM1_2CH_PATH",
+ "CM1_16CH_PATH",
+};
+
+static SOC_ENUM_SINGLE_DECL(ul_cm0_mux_map_enum,
+ AFE_CM0_CON0,
+ AFE_CM0_OUTPUT_MUX_SFT,
+ cm0_mux_texts);
+static SOC_ENUM_SINGLE_DECL(ul_cm1_mux_map_enum,
+ AFE_CM1_CON0,
+ AFE_CM1_OUTPUT_MUX_SFT,
+ cm1_mux_map_texts);
+
+static const struct snd_kcontrol_new ul_cm0_mux_control =
+ SOC_DAPM_ENUM("CM0_UL_MUX Route", ul_cm0_mux_map_enum);
+static const struct snd_kcontrol_new ul_cm1_mux_control =
+ SOC_DAPM_ENUM("CM1_UL_MUX Route", ul_cm1_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mt8189_memif_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("UL0_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul0_ch1_mix, ARRAY_SIZE(memif_ul0_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL0_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul0_ch2_mix, ARRAY_SIZE(memif_ul0_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL9_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul9_ch1_mix, ARRAY_SIZE(memif_ul9_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL9_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul9_ch2_mix, ARRAY_SIZE(memif_ul9_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL24_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul24_ch1_mix, ARRAY_SIZE(memif_ul24_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL24_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul24_ch2_mix, ARRAY_SIZE(memif_ul24_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("UL_CM0_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch1_mix, ARRAY_SIZE(memif_ul_cm0_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch2_mix, ARRAY_SIZE(memif_ul_cm0_ch2_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH3", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch3_mix, ARRAY_SIZE(memif_ul_cm0_ch3_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH4", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch4_mix, ARRAY_SIZE(memif_ul_cm0_ch4_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH5", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch5_mix, ARRAY_SIZE(memif_ul_cm0_ch5_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH6", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch6_mix, ARRAY_SIZE(memif_ul_cm0_ch6_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH7", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch7_mix, ARRAY_SIZE(memif_ul_cm0_ch7_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM0_CH8", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm0_ch8_mix, ARRAY_SIZE(memif_ul_cm0_ch8_mix)),
+ SND_SOC_DAPM_MUX_E("CM0_UL_MUX", SND_SOC_NOPM, 0, 0,
+ &ul_cm0_mux_control,
+ ul_cm0_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MIXER("UL_CM1_CH1", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch1_mix, ARRAY_SIZE(memif_ul_cm1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH2", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch2_mix, ARRAY_SIZE(memif_ul_cm1_ch2_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH3", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch3_mix, ARRAY_SIZE(memif_ul_cm1_ch3_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH4", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch4_mix, ARRAY_SIZE(memif_ul_cm1_ch4_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH5", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch5_mix, ARRAY_SIZE(memif_ul_cm1_ch5_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH6", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch6_mix, ARRAY_SIZE(memif_ul_cm1_ch6_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH7", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch7_mix, ARRAY_SIZE(memif_ul_cm1_ch7_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH8", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch8_mix, ARRAY_SIZE(memif_ul_cm1_ch8_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH9", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch9_mix, ARRAY_SIZE(memif_ul_cm1_ch9_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH10", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch10_mix, ARRAY_SIZE(memif_ul_cm1_ch10_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH11", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch11_mix, ARRAY_SIZE(memif_ul_cm1_ch11_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH12", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch12_mix, ARRAY_SIZE(memif_ul_cm1_ch12_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH13", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch13_mix, ARRAY_SIZE(memif_ul_cm1_ch13_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH14", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch14_mix, ARRAY_SIZE(memif_ul_cm1_ch14_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH15", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch15_mix, ARRAY_SIZE(memif_ul_cm1_ch15_mix)),
+ SND_SOC_DAPM_MIXER("UL_CM1_CH16", SND_SOC_NOPM, 0, 0,
+ memif_ul_cm1_ch16_mix, ARRAY_SIZE(memif_ul_cm1_ch16_mix)),
+ SND_SOC_DAPM_MUX("CM1_UL_MUX", SND_SOC_NOPM, 0, 0,
+ &ul_cm1_mux_control),
+ SND_SOC_DAPM_SUPPLY("CM0_Enable",
+ AFE_CM0_CON0, AFE_CM0_ON_SFT, 0,
+ ul_cm0_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("CM1_Enable",
+ AFE_CM1_CON0, AFE_CM0_ON_SFT, 0,
+ ul_cm1_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ /* dynamic pinctrl */
+ SND_SOC_DAPM_PINCTRL("I2S0_PIN", "aud-gpio-i2s0-on", "aud-gpio-i2s0-off"),
+ SND_SOC_DAPM_PINCTRL("I2S1_PIN", "aud-gpio-i2s1-on", "aud-gpio-i2s1-off"),
+ SND_SOC_DAPM_PINCTRL("PCM0_PIN", "aud-gpio-pcm-on", "aud-gpio-pcm-off"),
+ SND_SOC_DAPM_PINCTRL("AP_DMIC0_PIN", "aud-gpio-ap-dmic-on", "aud-gpio-ap-dmic-off"),
+ SND_SOC_DAPM_PINCTRL("AP_DMIC1_PIN", "aud-gpio-ap-dmic1-on", "aud-gpio-ap-dmic1-off"),
+};
+
+static const struct snd_soc_dapm_route mt8189_memif_routes[] = {
+ {"UL0", NULL, "UL0_CH1"},
+ {"UL0", NULL, "UL0_CH2"},
+ /* Normal record */
+ {"UL0_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL0_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL0_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL0_CH1", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+ {"UL0_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL0_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL0_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL0_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+ {"UL0_CH1", "AP_DMIC_UL_CH1", "AP DMIC Capture"},
+ {"UL0_CH1", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+ {"UL0_CH2", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+
+ {"UL0_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL0_CH2", "I2SIN0_CH2", "I2SIN0"},
+ {"UL0_CH1", "I2SIN1_CH1", "I2SIN1"},
+ {"UL0_CH2", "I2SIN1_CH2", "I2SIN1"},
+
+ {"UL0_CH1", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+ {"UL0_CH2", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+
+ {"UL1", NULL, "UL1_CH1"},
+ {"UL1", NULL, "UL1_CH2"},
+
+ {"UL1_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL1_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+
+ {"UL1_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL1_CH2", "I2SIN0_CH2", "I2SIN0"},
+ {"UL1_CH1", "I2SIN1_CH1", "I2SIN1"},
+ {"UL1_CH2", "I2SIN1_CH2", "I2SIN1"},
+
+ {"UL1_CH1", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+ {"UL1_CH2", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+
+ {"UL2", NULL, "UL2_CH1"},
+ {"UL2", NULL, "UL2_CH2"},
+
+ {"UL2_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL2_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL2_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL2_CH1", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+ {"UL2_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"},
+ {"UL2_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"},
+ {"UL2_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"},
+ {"UL2_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"},
+
+ {"UL2_CH1", "AP_DMIC_UL_CH3", "AP DMIC CH34 Capture"},
+ {"UL2_CH2", "AP_DMIC_UL_CH4", "AP DMIC CH34 Capture"},
+
+ {"UL3", NULL, "UL3_CH1"},
+ {"UL3", NULL, "UL3_CH2"},
+
+ {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL3_CH1", "I2SIN1_CH1", "I2SIN1"},
+ {"UL3_CH2", "I2SIN1_CH2", "I2SIN1"},
+
+ {"UL4", NULL, "UL4_CH1"},
+ {"UL4", NULL, "UL4_CH2"},
+ {"UL4_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL4_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL4_CH1", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+ {"UL4_CH2", "PCM_0_CAP_CH1", "PCM 0 Capture"},
+
+ {"UL5", NULL, "UL5_CH1"},
+ {"UL5", NULL, "UL5_CH2"},
+
+ {"UL5_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL5_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL6", NULL, "UL6_CH1"},
+ {"UL6", NULL, "UL6_CH2"},
+ {"UL6_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL6_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL6_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL6_CH2", "I2SIN0_CH2", "I2SIN0"},
+ {"UL6_CH1", "AP_DMIC_UL_CH1", "AP DMIC Capture"},
+ {"UL6_CH2", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+
+ {"UL7", NULL, "UL7_CH1"},
+ {"UL7", NULL, "UL7_CH2"},
+ {"UL7_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL7_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL7_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL7_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL7_CH1", "I2SIN0_CH1", "I2SIN0"},
+ {"UL7_CH2", "I2SIN0_CH2", "I2SIN0"},
+ {"UL7_CH1", "AP_DMIC_UL_CH3", "AP DMIC CH34 Capture"},
+ {"UL7_CH2", "AP_DMIC_UL_CH4", "AP DMIC CH34 Capture"},
+
+ {"UL8", NULL, "CM0_UL_MUX"},
+ {"CM0_UL_MUX", "CM0_2CH_PATH", "UL8_CH1"},
+ {"CM0_UL_MUX", "CM0_2CH_PATH", "UL8_CH2"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH1"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH2"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH3"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH4"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH5"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH6"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH7"},
+ {"CM0_UL_MUX", "CM0_8CH_PATH", "UL_CM0_CH8"},
+
+ {"UL_CM0", NULL, "CM0_Enable"},
+
+ {"UL9", NULL, "CM1_UL_MUX"},
+ {"CM1_UL_MUX", "CM1_2CH_PATH", "UL9_CH1"},
+ {"CM1_UL_MUX", "CM1_2CH_PATH", "UL9_CH2"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH1"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH2"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH3"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH4"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH5"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH6"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH7"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH8"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH9"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH10"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH11"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH12"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH13"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH14"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH15"},
+ {"CM1_UL_MUX", "CM1_16CH_PATH", "UL_CM1_CH16"},
+
+ {"UL_CM1", NULL, "CM1_Enable"},
+
+ /* UL9 o36o37 <- ADDA */
+ {"UL9_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL9_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL9_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL9_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+
+ {"UL24", NULL, "UL24_CH1"},
+ {"UL24", NULL, "UL24_CH2"},
+ {"UL24_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+
+ {"UL_CM0", NULL, "UL_CM0_CH1"},
+ {"UL_CM0", NULL, "UL_CM0_CH2"},
+ {"UL_CM0", NULL, "UL_CM0_CH3"},
+ {"UL_CM0", NULL, "UL_CM0_CH4"},
+ {"UL_CM0", NULL, "UL_CM0_CH5"},
+ {"UL_CM0", NULL, "UL_CM0_CH6"},
+ {"UL_CM0", NULL, "UL_CM0_CH7"},
+ {"UL_CM0", NULL, "UL_CM0_CH8"},
+ {"UL_CM0_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM0_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM0_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM0_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM0_CH3", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM0_CH3", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM0_CH4", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM0_CH4", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM0_CH1", "AP_DMIC_UL_CH1", "AP DMIC Capture"},
+ {"UL_CM0_CH2", "AP_DMIC_UL_CH2", "AP DMIC Capture"},
+ {"UL_CM0_CH3", "AP_DMIC_UL_CH3", "AP DMIC CH34 Capture"},
+ {"UL_CM0_CH4", "AP_DMIC_UL_CH4", "AP DMIC CH34 Capture"},
+
+ {"UL_CM1", NULL, "UL_CM1_CH1"},
+ {"UL_CM1", NULL, "UL_CM1_CH2"},
+ {"UL_CM1", NULL, "UL_CM1_CH3"},
+ {"UL_CM1", NULL, "UL_CM1_CH4"},
+ {"UL_CM1", NULL, "UL_CM1_CH5"},
+ {"UL_CM1", NULL, "UL_CM1_CH6"},
+ {"UL_CM1", NULL, "UL_CM1_CH7"},
+ {"UL_CM1", NULL, "UL_CM1_CH8"},
+ {"UL_CM1", NULL, "UL_CM1_CH9"},
+ {"UL_CM1", NULL, "UL_CM1_CH10"},
+ {"UL_CM1", NULL, "UL_CM1_CH11"},
+ {"UL_CM1", NULL, "UL_CM1_CH12"},
+ {"UL_CM1", NULL, "UL_CM1_CH13"},
+ {"UL_CM1", NULL, "UL_CM1_CH14"},
+ {"UL_CM1", NULL, "UL_CM1_CH15"},
+ {"UL_CM1", NULL, "UL_CM1_CH16"},
+ {"UL_CM1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM1_CH1", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM1_CH2", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM1_CH2", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM1_CH3", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM1_CH3", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM1_CH4", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM1_CH4", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM1_CH5", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM1_CH5", "ADDA_UL_CH2", "ADDA Capture"},
+ {"UL_CM1_CH6", "ADDA_UL_CH1", "ADDA Capture"},
+ {"UL_CM1_CH6", "ADDA_UL_CH2", "ADDA Capture"},
+
+ /* Audio Pin */
+ {"I2SOUT0", NULL, "I2S0_PIN"},
+ {"I2SIN0", NULL, "I2S0_PIN"},
+ {"I2SOUT1", NULL, "I2S1_PIN"},
+ {"I2SIN1", NULL, "I2S1_PIN"},
+ {"PCM 0 Playback", NULL, "PCM0_PIN"},
+ {"AP DMIC Capture", NULL, "AP_DMIC0_PIN"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC1_PIN"},
+};
+
+#define MT8189_DL_MEMIF(_id) \
+ [MT8189_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8189_MEMIF_##_id, \
+ .reg_ofs_base = AFE_##_id##_BASE, \
+ .reg_ofs_cur = AFE_##_id##_CUR, \
+ .reg_ofs_end = AFE_##_id##_END, \
+ .reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+ .reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+ .reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+ .fs_reg = AFE_##_id##_CON0, \
+ .fs_shift = _id##_SEL_FS_SFT, \
+ .fs_maskbit = _id##_SEL_FS_MASK, \
+ .mono_reg = AFE_##_id##_CON0, \
+ .mono_shift = _id##_MONO_SFT, \
+ .enable_reg = AFE_##_id##_CON0, \
+ .enable_shift = _id##_ON_SFT, \
+ .hd_reg = AFE_##_id##_CON0, \
+ .hd_shift = _id##_HD_MODE_SFT, \
+ .hd_align_reg = AFE_##_id##_CON0, \
+ .hd_align_mshift = _id##_HALIGN_SFT, \
+ .agent_disable_reg = -1, \
+ .agent_disable_shift = -1, \
+ .msb_reg = -1, \
+ .msb_shift = -1, \
+ .pbuf_reg = AFE_##_id##_CON0, \
+ .pbuf_mask = _id##_PBUF_SIZE_MASK, \
+ .pbuf_shift = _id##_PBUF_SIZE_SFT, \
+ .minlen_reg = AFE_##_id##_CON0, \
+ .minlen_mask = _id##_MINLEN_MASK, \
+ .minlen_shift = _id##_MINLEN_SFT, \
+}
+
+#define MT8189_MULTI_DL_MEMIF(_id) \
+ [MT8189_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8189_MEMIF_##_id, \
+ .reg_ofs_base = AFE_##_id##_BASE, \
+ .reg_ofs_cur = AFE_##_id##_CUR, \
+ .reg_ofs_end = AFE_##_id##_END, \
+ .reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+ .reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+ .reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+ .fs_reg = AFE_##_id##_CON0, \
+ .fs_shift = _id##_SEL_FS_SFT, \
+ .fs_maskbit = _id##_SEL_FS_MASK, \
+ .mono_reg = -1, \
+ .mono_shift = -1, \
+ .enable_reg = AFE_##_id##_CON0, \
+ .enable_shift = _id##_ON_SFT, \
+ .hd_reg = AFE_##_id##_CON0, \
+ .hd_shift = _id##_HD_MODE_SFT, \
+ .hd_align_reg = AFE_##_id##_CON0, \
+ .hd_align_mshift = _id##_HALIGN_SFT, \
+ .agent_disable_reg = -1, \
+ .agent_disable_shift = -1, \
+ .msb_reg = -1, \
+ .msb_shift = -1, \
+ .pbuf_reg = AFE_##_id##_CON0, \
+ .pbuf_mask = _id##_PBUF_SIZE_MASK, \
+ .pbuf_shift = _id##_PBUF_SIZE_SFT, \
+ .minlen_reg = AFE_##_id##_CON0, \
+ .minlen_mask = _id##_MINLEN_MASK, \
+ .minlen_shift = _id##_MINLEN_SFT, \
+ .ch_num_reg = AFE_##_id##_CON0, \
+ .ch_num_maskbit = _id##_NUM_MASK, \
+ .ch_num_shift = _id##_NUM_SFT, \
+}
+
+#define MT8189_UL_MEMIF(_id, _fs_shift, _fs_maskbit, _mono_shift) \
+ [MT8189_MEMIF_##_id] = { \
+ .name = #_id, \
+ .id = MT8189_MEMIF_##_id, \
+ .reg_ofs_base = AFE_##_id##_BASE, \
+ .reg_ofs_cur = AFE_##_id##_CUR, \
+ .reg_ofs_end = AFE_##_id##_END, \
+ .reg_ofs_base_msb = AFE_##_id##_BASE_MSB, \
+ .reg_ofs_cur_msb = AFE_##_id##_CUR_MSB, \
+ .reg_ofs_end_msb = AFE_##_id##_END_MSB, \
+ .fs_reg = AFE_##_id##_CON0, \
+ .fs_shift = _fs_shift, \
+ .fs_maskbit = _fs_maskbit, \
+ .mono_reg = AFE_##_id##_CON0, \
+ .mono_shift = _mono_shift, \
+ .enable_reg = AFE_##_id##_CON0, \
+ .enable_shift = _id##_ON_SFT, \
+ .hd_reg = AFE_##_id##_CON0, \
+ .hd_shift = _id##_HD_MODE_SFT, \
+ .hd_align_reg = AFE_##_id##_CON0, \
+ .hd_align_mshift = _id##_HALIGN_SFT, \
+ .agent_disable_reg = -1, \
+ .agent_disable_shift = -1, \
+ .msb_reg = -1, \
+ .msb_shift = -1, \
+ }
+
+/* For convenience with macros: missing register fields */
+#define HDMI_SEL_FS_SFT -1
+#define HDMI_SEL_FS_MASK -1
+
+/* For convenience with macros: register name differences */
+#define AFE_HDMI_BASE AFE_HDMI_OUT_BASE
+#define AFE_HDMI_CUR AFE_HDMI_OUT_CUR
+#define AFE_HDMI_END AFE_HDMI_OUT_END
+#define AFE_HDMI_BASE_MSB AFE_HDMI_OUT_BASE_MSB
+#define AFE_HDMI_CUR_MSB AFE_HDMI_OUT_CUR_MSB
+#define AFE_HDMI_END_MSB AFE_HDMI_OUT_END_MSB
+#define AFE_HDMI_CON0 AFE_HDMI_OUT_CON0
+#define HDMI_ON_SFT HDMI_OUT_ON_SFT
+#define HDMI_HD_MODE_SFT HDMI_OUT_HD_MODE_SFT
+#define HDMI_HALIGN_SFT HDMI_OUT_HALIGN_SFT
+#define HDMI_PBUF_SIZE_MASK HDMI_OUT_PBUF_SIZE_MASK
+#define HDMI_PBUF_SIZE_SFT HDMI_OUT_PBUF_SIZE_SFT
+#define HDMI_MINLEN_MASK HDMI_OUT_MINLEN_MASK
+#define HDMI_MINLEN_SFT HDMI_OUT_MINLEN_SFT
+#define HDMI_NUM_MASK HDMI_CH_NUM_MASK
+#define HDMI_NUM_SFT HDMI_CH_NUM_SFT
+
+static const struct mtk_base_memif_data memif_data[MT8189_MEMIF_NUM] = {
+ MT8189_DL_MEMIF(DL0),
+ MT8189_DL_MEMIF(DL1),
+ MT8189_DL_MEMIF(DL2),
+ MT8189_DL_MEMIF(DL3),
+ MT8189_DL_MEMIF(DL4),
+ MT8189_DL_MEMIF(DL5),
+ MT8189_DL_MEMIF(DL6),
+ MT8189_DL_MEMIF(DL7),
+ MT8189_DL_MEMIF(DL8),
+ MT8189_DL_MEMIF(DL23),
+ MT8189_DL_MEMIF(DL24),
+ MT8189_DL_MEMIF(DL25),
+ MT8189_MULTI_DL_MEMIF(DL_24CH),
+ MT8189_MULTI_DL_MEMIF(HDMI),
+ MT8189_UL_MEMIF(VUL0, VUL0_SEL_FS_SFT, VUL0_SEL_FS_MASK, VUL0_MONO_SFT),
+ MT8189_UL_MEMIF(VUL1, VUL1_SEL_FS_SFT, VUL1_SEL_FS_MASK, VUL1_MONO_SFT),
+ MT8189_UL_MEMIF(VUL2, VUL2_SEL_FS_SFT, VUL2_SEL_FS_MASK, VUL2_MONO_SFT),
+ MT8189_UL_MEMIF(VUL3, VUL3_SEL_FS_SFT, VUL3_SEL_FS_MASK, VUL3_MONO_SFT),
+ MT8189_UL_MEMIF(VUL4, VUL4_SEL_FS_SFT, VUL4_SEL_FS_MASK, VUL4_MONO_SFT),
+ MT8189_UL_MEMIF(VUL5, VUL5_SEL_FS_SFT, VUL5_SEL_FS_MASK, VUL5_MONO_SFT),
+ MT8189_UL_MEMIF(VUL6, VUL6_SEL_FS_SFT, VUL6_SEL_FS_MASK, VUL6_MONO_SFT),
+ MT8189_UL_MEMIF(VUL7, VUL7_SEL_FS_SFT, VUL7_SEL_FS_MASK, VUL7_MONO_SFT),
+ MT8189_UL_MEMIF(VUL8, VUL8_SEL_FS_SFT, VUL8_SEL_FS_MASK, VUL8_MONO_SFT),
+ MT8189_UL_MEMIF(VUL9, VUL9_SEL_FS_SFT, VUL9_SEL_FS_MASK, VUL9_MONO_SFT),
+ MT8189_UL_MEMIF(VUL10, VUL10_SEL_FS_SFT, VUL10_SEL_FS_MASK, VUL10_MONO_SFT),
+ MT8189_UL_MEMIF(VUL24, VUL24_SEL_FS_SFT, VUL24_SEL_FS_MASK, VUL24_MONO_SFT),
+ MT8189_UL_MEMIF(VUL25, VUL25_SEL_FS_SFT, VUL25_SEL_FS_MASK, VUL25_MONO_SFT),
+ MT8189_UL_MEMIF(VUL_CM0, -1, -1, -1),
+ MT8189_UL_MEMIF(VUL_CM1, -1, -1, -1),
+ MT8189_UL_MEMIF(ETDM_IN0, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+ MT8189_UL_MEMIF(ETDM_IN1, REG_FS_TIMING_SEL_SFT, REG_FS_TIMING_SEL_MASK, -1),
+};
+
+#define MT8189_AFE_IRQ(_id) \
+ [MT8189_IRQ_##_id] = { \
+ .id = MT8189_IRQ_##_id, \
+ .irq_cnt_reg = AFE_IRQ##_id##_MCU_CFG1, \
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, \
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, \
+ .irq_fs_reg = AFE_IRQ##_id##_MCU_CFG0, \
+ .irq_fs_shift = AFE_IRQ##_id##_MCU_FS_SFT, \
+ .irq_fs_maskbit = AFE_IRQ##_id##_MCU_FS_MASK, \
+ .irq_en_reg = AFE_IRQ##_id##_MCU_CFG0, \
+ .irq_en_shift = AFE_IRQ##_id##_MCU_ON_SFT, \
+ .irq_clr_reg = AFE_IRQ##_id##_MCU_CFG1, \
+ .irq_clr_shift = AFE_IRQ##_id##_CLR_CFG_SFT, \
+ }
+
+#define MT8189_AFE_TDM_IRQ(_id) \
+ [MT8189_IRQ_##_id] = { \
+ .id = MT8189_CUS_IRQ_TDM, \
+ .irq_cnt_reg = AFE_CUSTOM_IRQ0_MCU_CFG1, \
+ .irq_cnt_shift = AFE_CUSTOM_IRQ0_MCU_CNT_SFT, \
+ .irq_cnt_maskbit = AFE_CUSTOM_IRQ0_MCU_CNT_MASK, \
+ .irq_fs_reg = -1, \
+ .irq_fs_shift = -1, \
+ .irq_fs_maskbit = -1, \
+ .irq_en_reg = AFE_CUSTOM_IRQ0_MCU_CFG0, \
+ .irq_en_shift = AFE_CUSTOM_IRQ0_MCU_ON_SFT, \
+ .irq_clr_reg = AFE_CUSTOM_IRQ0_MCU_CFG1, \
+ .irq_clr_shift = AFE_CUSTOM_IRQ0_CLR_CFG_SFT, \
+ }
+
+static const struct mtk_base_irq_data irq_data[MT8189_IRQ_NUM] = {
+ MT8189_AFE_IRQ(0),
+ MT8189_AFE_IRQ(1),
+ MT8189_AFE_IRQ(2),
+ MT8189_AFE_IRQ(3),
+ MT8189_AFE_IRQ(4),
+ MT8189_AFE_IRQ(5),
+ MT8189_AFE_IRQ(6),
+ MT8189_AFE_IRQ(7),
+ MT8189_AFE_IRQ(8),
+ MT8189_AFE_IRQ(9),
+ MT8189_AFE_IRQ(10),
+ MT8189_AFE_IRQ(11),
+ MT8189_AFE_IRQ(12),
+ MT8189_AFE_IRQ(13),
+ MT8189_AFE_IRQ(14),
+ MT8189_AFE_IRQ(15),
+ MT8189_AFE_IRQ(16),
+ MT8189_AFE_IRQ(17),
+ MT8189_AFE_IRQ(18),
+ MT8189_AFE_IRQ(19),
+ MT8189_AFE_IRQ(20),
+ MT8189_AFE_IRQ(21),
+ MT8189_AFE_IRQ(22),
+ MT8189_AFE_IRQ(23),
+ MT8189_AFE_IRQ(24),
+ MT8189_AFE_IRQ(25),
+ MT8189_AFE_IRQ(26),
+ MT8189_AFE_TDM_IRQ(31),
+};
+
+static const int memif_irq_usage[MT8189_MEMIF_NUM] = {
+ /* TODO: verify each memif & irq */
+ [MT8189_MEMIF_DL0] = MT8189_IRQ_0,
+ [MT8189_MEMIF_DL1] = MT8189_IRQ_1,
+ [MT8189_MEMIF_DL2] = MT8189_IRQ_2,
+ [MT8189_MEMIF_DL3] = MT8189_IRQ_3,
+ [MT8189_MEMIF_DL4] = MT8189_IRQ_4,
+ [MT8189_MEMIF_DL5] = MT8189_IRQ_5,
+ [MT8189_MEMIF_DL6] = MT8189_IRQ_6,
+ [MT8189_MEMIF_DL7] = MT8189_IRQ_7,
+ [MT8189_MEMIF_DL8] = MT8189_IRQ_8,
+ [MT8189_MEMIF_DL23] = MT8189_IRQ_9,
+ [MT8189_MEMIF_DL24] = MT8189_IRQ_10,
+ [MT8189_MEMIF_DL25] = MT8189_IRQ_11,
+ [MT8189_MEMIF_DL_24CH] = MT8189_IRQ_12,
+ [MT8189_MEMIF_VUL0] = MT8189_IRQ_13,
+ [MT8189_MEMIF_VUL1] = MT8189_IRQ_14,
+ [MT8189_MEMIF_VUL2] = MT8189_IRQ_15,
+ [MT8189_MEMIF_VUL3] = MT8189_IRQ_16,
+ [MT8189_MEMIF_VUL4] = MT8189_IRQ_17,
+ [MT8189_MEMIF_VUL5] = MT8189_IRQ_18,
+ [MT8189_MEMIF_VUL6] = MT8189_IRQ_19,
+ [MT8189_MEMIF_VUL7] = MT8189_IRQ_20,
+ [MT8189_MEMIF_VUL8] = MT8189_IRQ_21,
+ [MT8189_MEMIF_VUL9] = MT8189_IRQ_22,
+ [MT8189_MEMIF_VUL10] = MT8189_IRQ_23,
+ [MT8189_MEMIF_VUL24] = MT8189_IRQ_24,
+ [MT8189_MEMIF_VUL25] = MT8189_IRQ_25,
+ [MT8189_MEMIF_VUL_CM0] = MT8189_IRQ_26,
+ [MT8189_MEMIF_VUL_CM1] = MT8189_IRQ_0,
+ [MT8189_MEMIF_ETDM_IN0] = MT8189_IRQ_0,
+ [MT8189_MEMIF_ETDM_IN1] = MT8189_IRQ_0,
+ [MT8189_MEMIF_HDMI] = MT8189_IRQ_31
+};
+
+static bool mt8189_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /* these auto-gen reg has read-only bit, so put it as volatile */
+ /* volatile reg cannot be cached, so cannot be set when power off */
+ switch (reg) {
+ case AUDIO_TOP_CON0:
+ case AUDIO_TOP_CON1:
+ case AUDIO_TOP_CON2:
+ case AUDIO_TOP_CON3:
+ case AUDIO_TOP_CON4:
+ case AFE_APLL1_TUNER_MON0:
+ case AFE_APLL2_TUNER_MON0:
+ case AFE_SPM_CONTROL_ACK:
+ case AUDIO_TOP_IP_VERSION:
+ case AUDIO_ENGEN_CON0_MON:
+ case AFE_CONNSYS_I2S_IPM_VER_MON:
+ case AFE_CONNSYS_I2S_MON:
+ case AFE_PCM_INTF_MON:
+ case AFE_PCM_TOP_IP_VERSION:
+ case AFE_IRQ_MCU_STATUS:
+ case AFE_CUSTOM_IRQ_MCU_STATUS:
+ case AFE_IRQ_MCU_MON0:
+ case AFE_IRQ_MCU_MON1:
+ case AFE_IRQ_MCU_MON2:
+ case AFE_IRQ0_CNT_MON:
+ case AFE_IRQ1_CNT_MON:
+ case AFE_IRQ2_CNT_MON:
+ case AFE_IRQ3_CNT_MON:
+ case AFE_IRQ4_CNT_MON:
+ case AFE_IRQ5_CNT_MON:
+ case AFE_IRQ6_CNT_MON:
+ case AFE_IRQ7_CNT_MON:
+ case AFE_IRQ8_CNT_MON:
+ case AFE_IRQ9_CNT_MON:
+ case AFE_IRQ10_CNT_MON:
+ case AFE_IRQ11_CNT_MON:
+ case AFE_IRQ12_CNT_MON:
+ case AFE_IRQ13_CNT_MON:
+ case AFE_IRQ14_CNT_MON:
+ case AFE_IRQ15_CNT_MON:
+ case AFE_IRQ16_CNT_MON:
+ case AFE_IRQ17_CNT_MON:
+ case AFE_IRQ18_CNT_MON:
+ case AFE_IRQ19_CNT_MON:
+ case AFE_IRQ20_CNT_MON:
+ case AFE_IRQ21_CNT_MON:
+ case AFE_IRQ22_CNT_MON:
+ case AFE_IRQ23_CNT_MON:
+ case AFE_IRQ24_CNT_MON:
+ case AFE_IRQ25_CNT_MON:
+ case AFE_IRQ26_CNT_MON:
+ case AFE_CM0_MON:
+ case AFE_CM0_IP_VERSION:
+ case AFE_CM1_MON:
+ case AFE_CM1_IP_VERSION:
+ case AFE_ADDA_UL0_SRC_DEBUG_MON0:
+ case AFE_ADDA_UL0_SRC_MON0:
+ case AFE_ADDA_UL0_SRC_MON1:
+ case AFE_ADDA_UL0_IP_VERSION:
+ case AFE_ADDA_DMIC0_SRC_DEBUG_MON0:
+ case AFE_ADDA_DMIC0_SRC_MON0:
+ case AFE_ADDA_DMIC0_SRC_MON1:
+ case AFE_ADDA_DMIC0_IP_VERSION:
+ case AFE_ADDA_DMIC1_SRC_DEBUG_MON0:
+ case AFE_ADDA_DMIC1_SRC_MON0:
+ case AFE_ADDA_DMIC1_SRC_MON1:
+ case AFE_ADDA_DMIC1_IP_VERSION:
+ case AFE_MTKAIF_IPM_VER_MON:
+ case AFE_MTKAIF_MON:
+ case AFE_AUD_PAD_TOP_MON:
+ case AFE_ADDA_MTKAIFV4_MON0:
+ case AFE_ADDA_MTKAIFV4_MON1:
+ case AFE_ADDA6_MTKAIFV4_MON0:
+ case ETDM_IN0_MON:
+ case ETDM_IN1_MON:
+ case ETDM_OUT0_MON:
+ case ETDM_OUT1_MON:
+ case ETDM_OUT4_MON:
+ case AFE_CONN_MON0:
+ case AFE_CONN_MON1:
+ case AFE_CONN_MON2:
+ case AFE_CONN_MON3:
+ case AFE_CONN_MON4:
+ case AFE_CONN_MON5:
+ case AFE_CBIP_SLV_DECODER_MON0:
+ case AFE_CBIP_SLV_DECODER_MON1:
+ case AFE_CBIP_SLV_MUX_MON0:
+ case AFE_CBIP_SLV_MUX_MON1:
+ case AFE_DL0_CUR_MSB:
+ case AFE_DL0_CUR:
+ case AFE_DL0_RCH_MON:
+ case AFE_DL0_LCH_MON:
+ case AFE_DL1_CUR_MSB:
+ case AFE_DL1_CUR:
+ case AFE_DL1_RCH_MON:
+ case AFE_DL1_LCH_MON:
+ case AFE_DL2_CUR_MSB:
+ case AFE_DL2_CUR:
+ case AFE_DL2_RCH_MON:
+ case AFE_DL2_LCH_MON:
+ case AFE_DL3_CUR_MSB:
+ case AFE_DL3_CUR:
+ case AFE_DL3_RCH_MON:
+ case AFE_DL3_LCH_MON:
+ case AFE_DL4_CUR_MSB:
+ case AFE_DL4_CUR:
+ case AFE_DL4_RCH_MON:
+ case AFE_DL4_LCH_MON:
+ case AFE_DL5_CUR_MSB:
+ case AFE_DL5_CUR:
+ case AFE_DL5_RCH_MON:
+ case AFE_DL5_LCH_MON:
+ case AFE_DL6_CUR_MSB:
+ case AFE_DL6_CUR:
+ case AFE_DL6_RCH_MON:
+ case AFE_DL6_LCH_MON:
+ case AFE_DL7_CUR_MSB:
+ case AFE_DL7_CUR:
+ case AFE_DL7_RCH_MON:
+ case AFE_DL7_LCH_MON:
+ case AFE_DL8_CUR_MSB:
+ case AFE_DL8_CUR:
+ case AFE_DL8_RCH_MON:
+ case AFE_DL8_LCH_MON:
+ case AFE_DL_24CH_CUR_MSB:
+ case AFE_DL_24CH_CUR:
+ case AFE_DL23_CUR_MSB:
+ case AFE_DL23_CUR:
+ case AFE_DL23_RCH_MON:
+ case AFE_DL23_LCH_MON:
+ case AFE_DL24_CUR_MSB:
+ case AFE_DL24_CUR:
+ case AFE_DL24_RCH_MON:
+ case AFE_DL24_LCH_MON:
+ case AFE_DL25_CUR_MSB:
+ case AFE_DL25_CUR:
+ case AFE_DL25_RCH_MON:
+ case AFE_DL25_LCH_MON:
+ case AFE_VUL0_CUR_MSB:
+ case AFE_VUL0_CUR:
+ case AFE_VUL1_CUR_MSB:
+ case AFE_VUL1_CUR:
+ case AFE_VUL2_CUR_MSB:
+ case AFE_VUL2_CUR:
+ case AFE_VUL3_CUR_MSB:
+ case AFE_VUL3_CUR:
+ case AFE_VUL4_CUR_MSB:
+ case AFE_VUL4_CUR:
+ case AFE_VUL5_CUR_MSB:
+ case AFE_VUL5_CUR:
+ case AFE_VUL6_CUR_MSB:
+ case AFE_VUL6_CUR:
+ case AFE_VUL7_CUR_MSB:
+ case AFE_VUL7_CUR:
+ case AFE_VUL8_CUR_MSB:
+ case AFE_VUL8_CUR:
+ case AFE_VUL9_CUR_MSB:
+ case AFE_VUL9_CUR:
+ case AFE_VUL10_CUR_MSB:
+ case AFE_VUL10_CUR:
+ case AFE_VUL24_CUR_MSB:
+ case AFE_VUL24_CUR:
+ case AFE_VUL25_CUR_MSB:
+ case AFE_VUL25_CUR:
+ case AFE_VUL_CM0_CUR_MSB:
+ case AFE_VUL_CM0_CUR:
+ case AFE_VUL_CM1_CUR_MSB:
+ case AFE_VUL_CM1_CUR:
+ case AFE_ETDM_IN0_CUR_MSB:
+ case AFE_ETDM_IN0_CUR:
+ case AFE_ETDM_IN1_CUR_MSB:
+ case AFE_ETDM_IN1_CUR:
+ case AFE_HDMI_OUT_CUR_MSB:
+ case AFE_HDMI_OUT_CUR:
+ case AFE_HDMI_OUT_END:
+ case AFE_HDMI_OUT_MON0:
+ case AFE_PROT_SIDEBAND0_MON:
+ case AFE_PROT_SIDEBAND1_MON:
+ case AFE_PROT_SIDEBAND2_MON:
+ case AFE_PROT_SIDEBAND3_MON:
+ case AFE_DOMAIN_SIDEBAND0_MON:
+ case AFE_DOMAIN_SIDEBAND1_MON:
+ case AFE_DOMAIN_SIDEBAND2_MON:
+ case AFE_DOMAIN_SIDEBAND3_MON:
+ case AFE_DOMAIN_SIDEBAND4_MON:
+ case AFE_DOMAIN_SIDEBAND5_MON:
+ case AFE_DOMAIN_SIDEBAND6_MON:
+ case AFE_DOMAIN_SIDEBAND7_MON:
+ case AFE_DOMAIN_SIDEBAND8_MON:
+ case AFE_DOMAIN_SIDEBAND9_MON:
+ case AFE_PCM0_INTF_CON1_MASK_MON:
+ case AFE_CONNSYS_I2S_CON_MASK_MON:
+ case AFE_MTKAIF0_CFG0_MASK_MON:
+ case AFE_MTKAIF1_CFG0_MASK_MON:
+ case AFE_ADDA_UL0_SRC_CON0_MASK_MON:
+ case AFE_ASRC_NEW_CON0:
+ case AFE_ASRC_NEW_CON6:
+ case AFE_ASRC_NEW_CON8:
+ case AFE_ASRC_NEW_CON9:
+ case AFE_ASRC_NEW_CON12:
+ case AFE_ASRC_NEW_IP_VERSION:
+ case AFE_GASRC0_NEW_CON0:
+ case AFE_GASRC0_NEW_CON6:
+ case AFE_GASRC0_NEW_CON8:
+ case AFE_GASRC0_NEW_CON9:
+ case AFE_GASRC0_NEW_CON10:
+ case AFE_GASRC0_NEW_CON11:
+ case AFE_GASRC0_NEW_CON12:
+ case AFE_GASRC0_NEW_IP_VERSION:
+ case AFE_GASRC1_NEW_CON0:
+ case AFE_GASRC1_NEW_CON6:
+ case AFE_GASRC1_NEW_CON8:
+ case AFE_GASRC1_NEW_CON9:
+ case AFE_GASRC1_NEW_CON12:
+ case AFE_GASRC1_NEW_IP_VERSION:
+ case AFE_GASRC2_NEW_CON0:
+ case AFE_GASRC2_NEW_CON6:
+ case AFE_GASRC2_NEW_CON8:
+ case AFE_GASRC2_NEW_CON9:
+ case AFE_GASRC2_NEW_CON12:
+ case AFE_GASRC2_NEW_IP_VERSION:
+ case AFE_GAIN0_CUR_L:
+ case AFE_GAIN0_CUR_R:
+ case AFE_GAIN1_CUR_L:
+ case AFE_GAIN1_CUR_R:
+ case AFE_GAIN2_CUR_L:
+ case AFE_GAIN2_CUR_R:
+ case AFE_GAIN3_CUR_L:
+ case AFE_GAIN3_CUR_R:
+ case AFE_IRQ_MCU_EN:
+ case AFE_CUSTOM_IRQ_MCU_EN:
+ case AFE_IRQ_MCU_DSP_EN:
+ case AFE_IRQ_MCU_DSP2_EN:
+ case AFE_DL5_CON0:
+ case AFE_DL6_CON0:
+ case AFE_DL23_CON0:
+ case AFE_DL_24CH_CON0:
+ case AFE_VUL1_CON0:
+ case AFE_VUL3_CON0:
+ case AFE_VUL4_CON0:
+ case AFE_VUL5_CON0:
+ case AFE_VUL9_CON0:
+ case AFE_VUL25_CON0:
+ case AFE_IRQ0_MCU_CFG0:
+ case AFE_IRQ1_MCU_CFG0:
+ case AFE_IRQ2_MCU_CFG0:
+ case AFE_IRQ3_MCU_CFG0:
+ case AFE_IRQ4_MCU_CFG0:
+ case AFE_IRQ5_MCU_CFG0:
+ case AFE_IRQ6_MCU_CFG0:
+ case AFE_IRQ7_MCU_CFG0:
+ case AFE_IRQ8_MCU_CFG0:
+ case AFE_IRQ9_MCU_CFG0:
+ case AFE_IRQ10_MCU_CFG0:
+ case AFE_IRQ11_MCU_CFG0:
+ case AFE_IRQ12_MCU_CFG0:
+ case AFE_IRQ13_MCU_CFG0:
+ case AFE_IRQ14_MCU_CFG0:
+ case AFE_IRQ15_MCU_CFG0:
+ case AFE_IRQ16_MCU_CFG0:
+ case AFE_IRQ17_MCU_CFG0:
+ case AFE_IRQ18_MCU_CFG0:
+ case AFE_IRQ19_MCU_CFG0:
+ case AFE_IRQ20_MCU_CFG0:
+ case AFE_IRQ21_MCU_CFG0:
+ case AFE_IRQ22_MCU_CFG0:
+ case AFE_IRQ23_MCU_CFG0:
+ case AFE_IRQ24_MCU_CFG0:
+ case AFE_IRQ25_MCU_CFG0:
+ case AFE_IRQ26_MCU_CFG0:
+ case AFE_CUSTOM_IRQ0_MCU_CFG0:
+ case AFE_IRQ0_MCU_CFG1:
+ case AFE_IRQ1_MCU_CFG1:
+ case AFE_IRQ2_MCU_CFG1:
+ case AFE_IRQ3_MCU_CFG1:
+ case AFE_IRQ4_MCU_CFG1:
+ case AFE_IRQ5_MCU_CFG1:
+ case AFE_IRQ6_MCU_CFG1:
+ case AFE_IRQ7_MCU_CFG1:
+ case AFE_IRQ8_MCU_CFG1:
+ case AFE_IRQ9_MCU_CFG1:
+ case AFE_IRQ10_MCU_CFG1:
+ case AFE_IRQ11_MCU_CFG1:
+ case AFE_IRQ12_MCU_CFG1:
+ case AFE_IRQ13_MCU_CFG1:
+ case AFE_IRQ14_MCU_CFG1:
+ case AFE_IRQ15_MCU_CFG1:
+ case AFE_IRQ16_MCU_CFG1:
+ case AFE_IRQ17_MCU_CFG1:
+ case AFE_IRQ18_MCU_CFG1:
+ case AFE_IRQ19_MCU_CFG1:
+ case AFE_IRQ20_MCU_CFG1:
+ case AFE_IRQ21_MCU_CFG1:
+ case AFE_IRQ22_MCU_CFG1:
+ case AFE_IRQ23_MCU_CFG1:
+ case AFE_IRQ24_MCU_CFG1:
+ case AFE_IRQ25_MCU_CFG1:
+ case AFE_IRQ26_MCU_CFG1:
+ case AFE_CUSTOM_IRQ0_MCU_CFG1:
+ /* for vow using */
+ case AFE_IRQ_MCU_SCP_EN:
+ case AFE_VUL_CM0_BASE_MSB:
+ case AFE_VUL_CM0_BASE:
+ case AFE_VUL_CM0_END_MSB:
+ case AFE_VUL_CM0_END:
+ case AFE_VUL_CM0_CON0:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config mt8189_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .volatile_reg = mt8189_is_volatile_reg,
+
+ .max_register = AFE_MAX_REGISTER,
+ .num_reg_defaults_raw = AFE_MAX_REGISTER,
+
+ .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8189_afe_irq_handler(int irq_id, void *dev)
+{
+ struct mtk_base_afe *afe = dev;
+ struct mtk_base_afe_irq *irq;
+ u32 status;
+ u32 status_mcu;
+ u32 mcu_en;
+ u32 cus_status;
+ u32 cus_status_mcu;
+ u32 cus_mcu_en;
+ u32 tmp_reg;
+ int ret, cus_ret;
+ int i;
+ struct timespec64 ts64;
+ u64 t1, t2;
+ /* one interrupt period = 5ms */
+ const u64 timeout_limit = 5000000;
+
+ /* get irq that is sent to MCU */
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+ regmap_read(afe->regmap, AFE_CUSTOM_IRQ_MCU_EN, &cus_mcu_en);
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+ cus_ret = regmap_read(afe->regmap, AFE_CUSTOM_IRQ_MCU_STATUS, &cus_status);
+ /* only care IRQ which is sent to MCU */
+ status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+ cus_status_mcu = cus_status & cus_mcu_en & AFE_IRQ_STATUS_BITS;
+ if ((ret || status_mcu == 0) && (cus_ret || cus_status_mcu == 0)) {
+ dev_err(afe->dev, "%s(), irq status err, ret %d, 0x%x:0x%x:0x%x:0x%x\n",
+ __func__, ret, status, mcu_en, cus_status_mcu, cus_mcu_en);
+ return IRQ_NONE;
+ }
+
+ ktime_get_ts64(&ts64);
+ t1 = ktime_get_ns();
+
+ for (i = 0; i < MT8189_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+ if (!memif->substream)
+ continue;
+
+ if (memif->irq_usage < 0)
+ continue;
+ irq = &afe->irqs[memif->irq_usage];
+
+ if (i == MT8189_MEMIF_HDMI) {
+ if (cus_status_mcu & BIT(irq->irq_data->id))
+ snd_pcm_period_elapsed(memif->substream);
+ } else if (status_mcu & BIT(irq->irq_data->id)) {
+ snd_pcm_period_elapsed(memif->substream);
+ }
+ }
+
+ ktime_get_ts64(&ts64);
+ t2 = ktime_get_ns();
+ t2 = t2 - t1; /* in ns (10^9) */
+
+ if (t2 > timeout_limit)
+ dev_warn(afe->dev, "IRQ handler exceeded time limit by %llu ns\n",
+ t2 - timeout_limit);
+
+ /* clear irq */
+ for (i = 0; i < MT8189_IRQ_NUM; ++i) {
+ if (((cus_status_mcu & BIT(irq_data[i].id)) && i == MT8189_IRQ_31) ||
+ ((status_mcu & BIT(irq_data[i].id)) && i != MT8189_IRQ_31)) {
+ regmap_read(afe->regmap, irq_data[i].irq_clr_reg, &tmp_reg);
+ regmap_update_bits(afe->regmap, irq_data[i].irq_clr_reg,
+ AFE_IRQ_CLR_CFG_MASK_SFT |
+ AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
+ tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
+ AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mt8189_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ unsigned int value;
+ unsigned int tmp_reg;
+ int ret, i;
+
+ if (!afe->regmap) {
+ dev_warn(afe->dev, "%s() skip regmap\n", __func__);
+ goto skip_regmap;
+ }
+
+ /* disable AFE */
+ mt8189_afe_disable_main_clock(afe);
+
+ ret = regmap_read_poll_timeout(afe->regmap,
+ AUDIO_ENGEN_CON0_MON,
+ value,
+ (value & AUDIO_ENGEN_MON_SFT) == 0,
+ 20,
+ 1 * 1000 * 1000);
+ dev_dbg(afe->dev, "%s() read_poll ret %d\n", __func__, ret);
+ if (ret)
+ dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret);
+
+ /* make sure all irq status are cleared */
+ for (i = 0; i < MT8189_IRQ_NUM; i++) {
+ regmap_read(afe->regmap, irq_data[i].irq_clr_reg, &tmp_reg);
+ regmap_update_bits(afe->regmap, irq_data[i].irq_clr_reg,
+ AFE_IRQ_CLR_CFG_MASK_SFT |
+ AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT,
+ tmp_reg ^ (AFE_IRQ_CLR_CFG_MASK_SFT |
+ AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT));
+ }
+
+ /* reset audio 26M request */
+ regmap_update_bits(afe->regmap,
+ AFE_SPM_CONTROL_REQ, 0x1, 0x0);
+
+ /* cache only */
+ regcache_cache_only(afe->regmap, true);
+ regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+ mt8189_afe_disable_reg_rw_clk(afe);
+ return 0;
+}
+
+static int mt8189_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ int ret;
+
+ ret = mt8189_afe_enable_reg_rw_clk(afe);
+ if (ret)
+ return ret;
+
+ if (!afe->regmap) {
+ dev_warn(afe->dev, "skip regmap\n");
+ return 0;
+ }
+
+ regcache_cache_only(afe->regmap, false);
+ regcache_sync(afe->regmap);
+
+ /* set audio 26M request */
+ regmap_update_bits(afe->regmap, AFE_SPM_CONTROL_REQ, 0x1, 0x1);
+ regmap_update_bits(afe->regmap, AFE_CBIP_CFG0, 0x1, 0x1);
+
+ /* force cpu use 8_24 format when writing 32bit data */
+ regmap_update_bits(afe->regmap, AFE_MEMIF_CON0,
+ CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT);
+
+ /* enable AFE */
+ mt8189_afe_enable_main_clock(afe);
+
+ return 0;
+}
+
+static int mt8189_afe_component_probe(struct snd_soc_component *component)
+{
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ /* enable clock for regcache get default value from hw */
+ pm_runtime_get_sync(afe->dev);
+ mtk_afe_add_sub_dai_control(component);
+ pm_runtime_put_sync(afe->dev);
+
+ return 0;
+}
+
+static int mt8189_afe_pcm_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ /* set the wait_for_avail to 2 sec*/
+ substream->wait_time = msecs_to_jiffies(2 * 1000);
+
+ return 0;
+}
+
+static void mt8189_afe_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static const struct snd_soc_component_driver mt8189_afe_component = {
+ .name = AFE_PCM_NAME,
+ .probe = mt8189_afe_component_probe,
+ .pcm_construct = mtk_afe_pcm_new,
+ .pcm_destruct = mt8189_afe_pcm_free,
+ .open = mt8189_afe_pcm_open,
+ .pointer = mtk_afe_pcm_pointer,
+};
+
+static int mt8189_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt8189_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt8189_memif_dai_driver);
+ dai->dapm_widgets = mt8189_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt8189_memif_widgets);
+ dai->dapm_routes = mt8189_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt8189_memif_routes);
+
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt8189_dai_adda_register,
+ mt8189_dai_i2s_register,
+ mt8189_dai_pcm_register,
+ mt8189_dai_tdm_register,
+ mt8189_dai_memif_register,
+};
+
+static const struct reg_sequence mt8189_cg_patch[] = {
+ { AUDIO_TOP_CON4, 0x361c },
+};
+
+static int mt8189_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ int ret, i;
+ unsigned int tmp_reg;
+ int irq_id;
+ struct mtk_base_afe *afe;
+ struct mt8189_afe_private *afe_priv;
+ struct device *dev = &pdev->dev;
+
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
+ if (ret)
+ return ret;
+
+ ret = of_reserved_mem_device_init(dev);
+ if (ret)
+ dev_warn(dev, "failed to assign memory region: %d\n", ret);
+
+ afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, afe);
+
+ afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv),
+ GFP_KERNEL);
+ if (!afe->platform_priv)
+ return -ENOMEM;
+
+ afe_priv = afe->platform_priv;
+ afe->dev = dev;
+
+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(afe->base_addr))
+ return dev_err_probe(dev, PTR_ERR(afe->base_addr),
+ "AFE base_addr not found\n");
+
+ /* init audio related clock */
+ ret = mt8189_init_clock(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "init clock error.\n");
+
+ /* init memif */
+ /* IPM2.0 no need banding */
+ afe->memif_32bit_supported = 1;
+ afe->memif_size = MT8189_MEMIF_NUM;
+ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+ GFP_KERNEL);
+
+ if (!afe->memif)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->memif_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ afe->memif[i].irq_usage = memif_irq_usage[i];
+ afe->memif[i].const_irq = 1;
+ }
+
+ mutex_init(&afe->irq_alloc_lock);
+
+ /* init irq */
+ afe->irqs_size = MT8189_IRQ_NUM;
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ GFP_KERNEL);
+
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ /* request irq */
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id < 0)
+ return dev_err_probe(dev, irq_id, "no irq found");
+
+ ret = devm_request_irq(dev, irq_id, mt8189_afe_irq_handler,
+ IRQF_TRIGGER_NONE,
+ "Afe_ISR_Handle", afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+
+ /* init sub_dais */
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "dai register i %d fail\n", i);
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+ /* others */
+ afe->mtk_afe_hardware = &mt8189_afe_hardware;
+ afe->memif_fs = mt8189_memif_fs;
+ afe->irq_fs = mt8189_irq_fs;
+ afe->get_dai_fs = mt8189_get_dai_fs;
+ afe->get_memif_pbuf_size = mt8189_get_memif_pbuf_size;
+
+ afe->runtime_resume = mt8189_afe_runtime_resume;
+ afe->runtime_suspend = mt8189_afe_runtime_suspend;
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Audio device is part of genpd. Registering it as a syscore device
+ * ensure the proper power-on sequence of the AFE device.
+ */
+ dev_pm_syscore_device(dev, true);
+
+ /* enable clock for regcache get default value from hw */
+ pm_runtime_get_sync(dev);
+
+ afe->regmap = devm_regmap_init_mmio(dev, afe->base_addr,
+ &mt8189_afe_regmap_config);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ ret = regmap_register_patch(afe->regmap, mt8189_cg_patch,
+ ARRAY_SIZE(mt8189_cg_patch));
+ if (ret < 0) {
+ dev_err(dev, "Failed to apply cg patch\n");
+ goto err_pm_disable;
+ }
+
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
+ regmap_write(afe->regmap, AFE_IRQ_MCU_EN, 0xffffffff);
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &tmp_reg);
+
+ pm_runtime_put_sync(dev);
+
+ regcache_cache_only(afe->regmap, true);
+ regcache_mark_dirty(afe->regmap);
+
+ /* register component */
+ ret = devm_snd_soc_register_component(dev,
+ &mt8189_afe_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_err(dev, "afe component err: %d\n", ret);
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_put_sync(dev);
+ return ret;
+}
+
+static void mt8189_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_put_sync(dev);
+ if (!pm_runtime_status_suspended(dev))
+ mt8189_afe_runtime_suspend(dev);
+
+ mt8189_afe_disable_main_clock(afe);
+ /* disable afe clock */
+ mt8189_afe_disable_reg_rw_clk(afe);
+ of_reserved_mem_device_release(dev);
+}
+
+static const struct of_device_id mt8189_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8189-afe-pcm", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt8189_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8189_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt8189_afe_runtime_suspend,
+ mt8189_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8189_afe_pcm_driver = {
+ .driver = {
+ .name = "mt8189-afe-pcm",
+ .of_match_table = mt8189_afe_pcm_dt_match,
+ .pm = &mt8189_afe_pm_ops,
+ },
+ .probe = mt8189_afe_pcm_dev_probe,
+ .remove = mt8189_afe_pcm_dev_remove,
+};
+module_platform_driver(mt8189_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8189");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
new file mode 100644
index 000000000000..ad5b9546ff63
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
@@ -0,0 +1,1228 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+/* mt6363 vs1 voter */
+#define VS1_MT6338_MASK_SFT 0x1
+#define RG_BUCK_VS1_VOTER_EN_LO 0x189a
+#define RG_BUCK_VS1_VOTER_EN_LO_SET 0x189b
+#define RG_BUCK_VS1_VOTER_EN_LO_CLR 0x189c
+
+#define AUDIO_SDM_LEVEL_NORMAL 0x1d
+#define MTK_AFE_ADDA_DL_GAIN_NORMAL 0xf74f
+#define SDM_AUTO_RESET_THRESHOLD 0x190000
+
+enum {
+ SUPPLY_SEQ_ADDA_AFE_ON,
+ SUPPLY_SEQ_ADDA_DL_ON,
+ SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+ SUPPLY_SEQ_ADDA_FIFO,
+ SUPPLY_SEQ_ADDA_AP_DMIC,
+ SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+enum {
+ UL_IIR_SW,
+ UL_IIR_5HZ,
+ UL_IIR_10HZ,
+ UL_IIR_25HZ,
+ UL_IIR_50HZ,
+ UL_IIR_75HZ,
+};
+
+enum {
+ AUDIO_SDM_2ND,
+ AUDIO_SDM_3RD,
+};
+
+enum {
+ DELAY_DATA_MISO1,
+ DELAY_DATA_MISO2,
+};
+
+enum {
+ MTK_AFE_ADDA_DL_RATE_8K,
+ MTK_AFE_ADDA_DL_RATE_11K,
+ MTK_AFE_ADDA_DL_RATE_12K,
+ MTK_AFE_ADDA_DL_RATE_16K = 4,
+ MTK_AFE_ADDA_DL_RATE_22K,
+ MTK_AFE_ADDA_DL_RATE_24K,
+ MTK_AFE_ADDA_DL_RATE_32K = 8,
+ MTK_AFE_ADDA_DL_RATE_44K,
+ MTK_AFE_ADDA_DL_RATE_48K,
+ MTK_AFE_ADDA_DL_RATE_88K = 13,
+ MTK_AFE_ADDA_DL_RATE_96K,
+ MTK_AFE_ADDA_DL_RATE_176K = 17,
+ MTK_AFE_ADDA_DL_RATE_192K,
+ MTK_AFE_ADDA_DL_RATE_352K = 21,
+ MTK_AFE_ADDA_DL_RATE_384K,
+};
+
+enum {
+ MTK_AFE_ADDA_UL_RATE_8K,
+ MTK_AFE_ADDA_UL_RATE_16K,
+ MTK_AFE_ADDA_UL_RATE_32K,
+ MTK_AFE_ADDA_UL_RATE_48K,
+ MTK_AFE_ADDA_UL_RATE_96K,
+ MTK_AFE_ADDA_UL_RATE_192K,
+ MTK_AFE_ADDA_UL_RATE_48K_HD,
+};
+
+struct mtk_afe_adda_priv {
+ int dl_rate;
+ int ul_rate;
+};
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_DL_RATE_8K;
+ case 11025:
+ return MTK_AFE_ADDA_DL_RATE_11K;
+ case 12000:
+ return MTK_AFE_ADDA_DL_RATE_12K;
+ case 16000:
+ return MTK_AFE_ADDA_DL_RATE_16K;
+ case 22050:
+ return MTK_AFE_ADDA_DL_RATE_22K;
+ case 24000:
+ return MTK_AFE_ADDA_DL_RATE_24K;
+ case 32000:
+ return MTK_AFE_ADDA_DL_RATE_32K;
+ case 44100:
+ return MTK_AFE_ADDA_DL_RATE_44K;
+ case 48000:
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_DL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_DL_RATE_192K;
+ default:
+ dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_DL_RATE_48K;
+ }
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_ADDA_UL_RATE_8K;
+ case 16000:
+ return MTK_AFE_ADDA_UL_RATE_16K;
+ case 32000:
+ return MTK_AFE_ADDA_UL_RATE_32K;
+ case 48000:
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ case 96000:
+ return MTK_AFE_ADDA_UL_RATE_96K;
+ case 192000:
+ return MTK_AFE_ADDA_UL_RATE_192K;
+ default:
+ dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+ __func__, rate);
+ return MTK_AFE_ADDA_UL_RATE_48K;
+ }
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN014_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN014_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN014_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN014_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN014_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN014_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN014_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN014_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN014_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN014_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN014_2, I_DL24_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN014_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN014_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN014_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN014_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN014_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN014_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN014_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN014_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN015_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN015_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN015_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN015_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN015_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN015_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN015_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN015_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN015_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN015_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN015_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN015_2, I_DL24_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN015_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN015_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN015_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN015_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN015_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN015_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN015_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN015_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN015_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN016_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN016_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN016_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN016_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN016_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN016_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN016_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN016_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN016_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN016_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN016_1, I_DL_24CH_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN016_2, I_DL24_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN016_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN016_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN016_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN016_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN016_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH1", AFE_CONN016_6,
+ I_SRC_0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH1", AFE_CONN016_6,
+ I_SRC_1_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN016_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN017_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN017_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN017_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN017_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN017_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN017_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN017_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN017_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN017_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN017_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN017_1, I_DL_24CH_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN017_2, I_DL24_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN017_0,
+ I_ADDA_UL_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN017_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN017_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN017_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN017_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN017_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_0_OUT_CH2", AFE_CONN017_6,
+ I_SRC_0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_1_OUT_CH2", AFE_CONN017_6,
+ I_SRC_1_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN017_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static int mtk_adda_ul_src_enable_dmic(struct mtk_base_afe *afe, int id)
+{
+ unsigned int reg, reg1;
+
+ switch (id) {
+ case MT8189_DAI_ADDA:
+ reg = AFE_ADDA_UL0_SRC_CON0;
+ reg1 = AFE_ADDA_UL0_SRC_CON1;
+ break;
+ case MT8189_DAI_AP_DMIC:
+ reg = AFE_ADDA_DMIC0_SRC_CON0;
+ reg1 = AFE_ADDA_DMIC0_SRC_CON1;
+ break;
+ case MT8189_DAI_AP_DMIC_CH34:
+ reg = AFE_ADDA_DMIC1_SRC_CON0;
+ reg1 = AFE_ADDA_DMIC1_SRC_CON1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* choose Phase */
+ regmap_update_bits(afe->regmap, reg,
+ UL_DMIC_PHASE_SEL_CH1_MASK_SFT,
+ 0x0 << UL_DMIC_PHASE_SEL_CH1_SFT);
+ regmap_update_bits(afe->regmap, reg,
+ UL_DMIC_PHASE_SEL_CH2_MASK_SFT,
+ 0x4 << UL_DMIC_PHASE_SEL_CH2_SFT);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, reg,
+ DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT,
+ 0x0);
+ regmap_update_bits(afe->regmap, reg,
+ DMIC_LOW_POWER_MODE_CTL_MASK_SFT,
+ 0x0);
+
+ /* turn on dmic, ch1, ch2 */
+ regmap_update_bits(afe->regmap, reg,
+ UL_SDM_3_LEVEL_CTL_MASK_SFT,
+ 0x1 << UL_SDM_3_LEVEL_CTL_SFT);
+ regmap_update_bits(afe->regmap, reg,
+ UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+ 0x1 << UL_MODE_3P25M_CH1_CTL_SFT);
+ regmap_update_bits(afe->regmap, reg,
+ UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+ 0x1 << UL_MODE_3P25M_CH2_CTL_SFT);
+
+ /* ul gain: gain = 0x7fff/positive_gain = 0x0/gain_mode = 0x10 */
+ regmap_update_bits(afe->regmap, reg1,
+ ADDA_UL_GAIN_VALUE_MASK_SFT,
+ 0x7fff << ADDA_UL_GAIN_VALUE_SFT);
+ regmap_update_bits(afe->regmap, reg1,
+ ADDA_UL_POSTIVEGAIN_MASK_SFT,
+ 0x0 << ADDA_UL_POSTIVEGAIN_SFT);
+ /* gain_mode = 0x02: Add 0.5 gain at CIC output */
+ regmap_update_bits(afe->regmap, reg1,
+ GAIN_MODE_MASK_SFT,
+ 0x02 << GAIN_MODE_SFT);
+
+ return 0;
+}
+
+static int mtk_adda_ul_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+ __func__, w->name, event, mtkaif_dmic);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* update setting to dmic */
+ if (mtkaif_dmic) {
+ /* mtkaif_rxif_data_mode = 1, dmic */
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0,
+ RG_MTKAIF0_RXIF_DATA_MODE_MASK_SFT,
+ 0x1);
+
+ /* dmic mode, 3.25M*/
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_RX_CFG0,
+ RG_MTKAIF0_RXIF_VOICE_MODE_MASK_SFT,
+ 0x0);
+ mtk_adda_ul_src_enable_dmic(afe, MT8189_DAI_ADDA);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(120, 130);
+
+ /* reset dmic */
+ afe_priv->mtkaif_dmic = 0;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_pad_top_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ if (event == SND_SOC_DAPM_PRE_PMU) {
+ if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8);
+ else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
+ else
+ regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
+ }
+
+ return 0;
+}
+
+static bool is_adda_mtkaif_need_phase_delay(struct mt8189_afe_private *afe_priv)
+{
+ return afe_priv->mtkaif_chosen_phase[0] >= 0 &&
+ afe_priv->mtkaif_chosen_phase[1] >= 0;
+}
+
+static int mtk_adda_mtkaif_cfg_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ int delay_data;
+ int delay_cycle;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+ /* set protocol 2 */
+ regmap_write(afe->regmap, AFE_MTKAIF0_CFG0,
+ 0x00010000);
+ regmap_write(afe->regmap, AFE_MTKAIF1_CFG0,
+ 0x00010000);
+
+ /* mtkaif_rxif_clkinv_adc inverse for calibration */
+ regmap_update_bits(afe->regmap, AFE_MTKAIF0_CFG0,
+ RG_MTKAIF0_RXIF_CLKINV_MASK_SFT,
+ 0x1 << RG_MTKAIF0_RXIF_CLKINV_SFT);
+ regmap_update_bits(afe->regmap, AFE_MTKAIF1_CFG0,
+ RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT,
+ 0x1 << RG_MTKAIF1_RXIF_CLKINV_ADC_SFT);
+
+ /* This event align the phase of every miso pin */
+ /* If only 1 miso is used, there is no need to do phase delay. */
+ if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 &&
+ !is_adda_mtkaif_need_phase_delay(afe_priv)) {
+ dev_dbg(afe->dev,
+ "%s(), check adda mtkaif_chosen_phase[0/1]:%d/%d\n",
+ __func__,
+ afe_priv->mtkaif_chosen_phase[0],
+ afe_priv->mtkaif_chosen_phase[1]);
+ break;
+ } else if (strcmp(w->name, "ADDA6_MTKAIF_CFG") == 0 &&
+ afe_priv->mtkaif_chosen_phase[2] < 0) {
+ dev_dbg(afe->dev,
+ "%s(), check adda6 mtkaif_chosen_phase[2]:%d\n",
+ __func__,
+ afe_priv->mtkaif_chosen_phase[2]);
+ break;
+ }
+
+ /* set delay for ch12 to align phase of miso0 and miso1 */
+ if (afe_priv->mtkaif_phase_cycle[0] >=
+ afe_priv->mtkaif_phase_cycle[1]) {
+ delay_data = DELAY_DATA_MISO1;
+ delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
+ afe_priv->mtkaif_phase_cycle[1];
+ } else {
+ delay_data = DELAY_DATA_MISO2;
+ delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+ afe_priv->mtkaif_phase_cycle[0];
+ }
+
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG2,
+ RG_MTKAIF0_RXIF_DELAY_DATA_MASK_SFT,
+ delay_data <<
+ RG_MTKAIF0_RXIF_DELAY_DATA_SFT);
+
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG2,
+ RG_MTKAIF0_RXIF_DELAY_CYCLE_MASK_SFT,
+ delay_cycle <<
+ RG_MTKAIF0_RXIF_DELAY_CYCLE_SFT);
+
+ /* set delay between ch3 and ch2 */
+ if (afe_priv->mtkaif_phase_cycle[2] >=
+ afe_priv->mtkaif_phase_cycle[1]) {
+ delay_data = DELAY_DATA_MISO1; /* ch3 */
+ delay_cycle = afe_priv->mtkaif_phase_cycle[2] -
+ afe_priv->mtkaif_phase_cycle[1];
+ } else {
+ delay_data = DELAY_DATA_MISO2; /* ch2 */
+ delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+ afe_priv->mtkaif_phase_cycle[2];
+ }
+
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG2,
+ RG_MTKAIF1_RXIF_DELAY_DATA_MASK_SFT,
+ delay_data <<
+ RG_MTKAIF1_RXIF_DELAY_DATA_SFT);
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF1_RX_CFG2,
+ RG_MTKAIF1_RXIF_DELAY_CYCLE_MASK_SFT,
+ delay_cycle <<
+ RG_MTKAIF1_RXIF_DELAY_CYCLE_SFT);
+ } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+ regmap_write(afe->regmap, AFE_MTKAIF0_CFG0,
+ 0x00010000);
+ regmap_write(afe->regmap, AFE_MTKAIF1_CFG0,
+ 0x00010000);
+ } else {
+ regmap_write(afe->regmap, AFE_MTKAIF0_CFG0, 0x0);
+ regmap_write(afe->regmap, AFE_MTKAIF1_CFG0, 0x0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_adda_dl_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);
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ if (event == SND_SOC_DAPM_POST_PMD)
+ usleep_range(120, 130);
+
+ return 0;
+}
+
+static void mt6363_vs1_vote(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ bool pre_enable = afe_priv->is_mt6363_vote;
+ bool enable;
+
+ if (!afe_priv->pmic_regmap)
+ return;
+
+ enable = (afe_priv->is_adda_dl_on && afe_priv->is_adda_dl_max_vol) ||
+ (afe_priv->is_adda_ul_on);
+ if (enable == pre_enable) {
+ dev_dbg(afe->dev, "%s() enable == pre_enable = %d\n",
+ __func__, enable);
+ return;
+ }
+
+ afe_priv->is_mt6363_vote = enable;
+ dev_dbg(afe->dev, "%s() enable = %d\n", __func__, enable);
+
+ if (enable)
+ regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_SET,
+ VS1_MT6338_MASK_SFT, 0x1);
+ else
+ regmap_update_bits(afe_priv->pmic_regmap, RG_BUCK_VS1_VOTER_EN_LO_CLR,
+ VS1_MT6338_MASK_SFT, 0x1);
+}
+
+static int mt_vs1_voter_dl_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ afe_priv->is_adda_dl_on = true;
+ mt6363_vs1_vote(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ afe_priv->is_adda_dl_on = false;
+ mt6363_vs1_vote(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt_vs1_voter_ul_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ dev_dbg(afe->dev, "%s(), event = 0x%x\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ afe_priv->is_adda_ul_on = true;
+ mt6363_vs1_vote(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ afe_priv->is_adda_ul_on = false;
+ mt6363_vs1_vote(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mt8189_adda_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+
+ return 0;
+}
+
+static int mt8189_adda_dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int dmic_on;
+
+ dmic_on = !!ucontrol->value.integer.value[0];
+
+ dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+ __func__, kcontrol->id.name, dmic_on);
+
+ afe_priv->mtkaif_dmic = dmic_on;
+ afe_priv->mtkaif_dmic_ch34 = dmic_on;
+
+ return 0;
+}
+
+static int mt8189_adda_dl_max_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+
+ ucontrol->value.integer.value[0] = afe_priv->is_adda_dl_max_vol;
+
+ return 0;
+}
+
+static int mt8189_adda_dl_max_vol_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ bool is_adda_dl_max_vol = ucontrol->value.integer.value[0];
+
+ afe_priv->is_adda_dl_max_vol = is_adda_dl_max_vol;
+ mt6363_vs1_vote(afe);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+ SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC_CON1,
+ AFE_DL_GAIN1_CTL_PRE_SFT, AFE_DL_GAIN1_CTL_PRE_MASK, 0),
+ SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+ mt8189_adda_dmic_get, mt8189_adda_dmic_set),
+ SOC_SINGLE_BOOL_EXT("ADDA_DL_MAX_VOL Switch", 0,
+ mt8189_adda_dl_max_vol_get,
+ mt8189_adda_dl_max_vol_set),
+};
+
+static const char *const adda_ul_mux_texts[] = {
+ "MTKAIF", "AP_DMIC", "AP_DMIC_MULTI_CH",
+};
+
+static SOC_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ adda_ul_mux_texts);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_kcontrol_new adda_ch34_ul_mux_control =
+ SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch1_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch2_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch3_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch3_mix)),
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch4_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch4_mix)),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+ AUDIO_ENGEN_CON0, AUDIO_F3P25M_EN_ON_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_DL0_CG", SUPPLY_SEQ_ADDA_DL_ON,
+ AUDIO_TOP_CON0,
+ PDN_DL0_DAC_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_UL0_CG", SUPPLY_SEQ_ADDA_UL_ON,
+ AUDIO_TOP_CON1,
+ PDN_UL0_ADC_SFT, 1,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+ AFE_ADDA_DL_SRC_CON0,
+ AFE_DL_SRC_ON_TMP_CTL_PRE_SFT, 0,
+ mtk_adda_dl_event,
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_UL0_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ mtk_adda_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("AP DMIC Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_DMIC0_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("AP DMIC CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+ AFE_ADDA_DMIC1_SRC_CON0,
+ UL_SRC_ON_TMP_CTL_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+ AFE_AUD_PAD_TOP_CFG0,
+ RG_RX_FIFO_ON_SFT, 0,
+ mtk_adda_pad_top_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+ SND_SOC_NOPM, 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG,
+ SND_SOC_NOPM, 0, 0,
+ mtk_adda_mtkaif_cfg_event,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_DMIC0_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC0_CG", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AUDIO_TOP_CON1,
+ PDN_DMIC0_ADC_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AFE_ADDA_DMIC1_SRC_CON0,
+ UL_AP_DMIC_ON_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC1_CG", SUPPLY_SEQ_ADDA_AP_DMIC,
+ AUDIO_TOP_CON1,
+ PDN_DMIC1_ADC_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_UL0_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_DMIC0_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+ AFE_ADDA_DMIC1_SRC_CON1,
+ FIFO_SOFT_RST_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_DL", SUPPLY_SEQ_ADDA_AFE_ON,
+ SND_SOC_NOPM, 0, 0,
+ mt_vs1_voter_dl_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("VS1_VOTER_UL", SUPPLY_SEQ_ADDA_AFE_ON,
+ SND_SOC_NOPM, 0, 0,
+ mt_vs1_voter_ul_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+ &adda_ul_mux_control),
+ SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0,
+ &adda_ch34_ul_mux_control),
+
+ SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ /* playback */
+ {"ADDA_DL_CH1", "DL0_CH1", "DL0"},
+ {"ADDA_DL_CH2", "DL0_CH1", "DL0"},
+ {"ADDA_DL_CH2", "DL0_CH2", "DL0"},
+
+ {"ADDA_DL_CH1", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH2", "DL1_CH2", "DL1"},
+
+ {"ADDA_DL_CH1", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH2", "DL2_CH2", "DL2"},
+
+ {"ADDA_DL_CH1", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH2", "DL3_CH2", "DL3"},
+
+ {"ADDA_DL_CH1", "DL4_CH1", "DL4"},
+ {"ADDA_DL_CH2", "DL4_CH2", "DL4"},
+
+ {"ADDA_DL_CH1", "DL5_CH1", "DL5"},
+ {"ADDA_DL_CH2", "DL5_CH2", "DL5"},
+
+ {"ADDA_DL_CH1", "DL6_CH1", "DL6"},
+ {"ADDA_DL_CH2", "DL6_CH2", "DL6"},
+
+ {"ADDA_DL_CH1", "DL7_CH1", "DL7"},
+ {"ADDA_DL_CH2", "DL7_CH2", "DL7"},
+
+ {"ADDA_DL_CH1", "DL8_CH1", "DL8"},
+ {"ADDA_DL_CH2", "DL8_CH2", "DL8"},
+
+ {"ADDA_DL_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"ADDA_DL_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"ADDA_DL_CH1", "DL24_CH1", "DL24"},
+ {"ADDA_DL_CH2", "DL24_CH2", "DL24"},
+
+ {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+ {"ADDA Playback", NULL, "ADDA Enable"},
+ {"ADDA Playback", NULL, "ADDA Playback Enable"},
+ {"ADDA Playback", NULL, "AUD_PAD_TOP"},
+ {"ADDA Playback", NULL, "VS1_VOTER_DL"},
+ {"ADDA Playback", NULL, "ADDA_DL0_CG"},
+
+ {"ADDA_DL_CH3", "DL0_CH1", "DL0"},
+ {"ADDA_DL_CH4", "DL0_CH2", "DL0"},
+
+ {"ADDA_DL_CH3", "DL1_CH1", "DL1"},
+ {"ADDA_DL_CH4", "DL1_CH2", "DL1"},
+
+ {"ADDA_DL_CH3", "DL2_CH1", "DL2"},
+ {"ADDA_DL_CH4", "DL2_CH2", "DL2"},
+
+ {"ADDA_DL_CH3", "DL3_CH1", "DL3"},
+ {"ADDA_DL_CH4", "DL3_CH2", "DL3"},
+
+ {"ADDA_DL_CH3", "DL4_CH1", "DL4"},
+ {"ADDA_DL_CH4", "DL4_CH2", "DL4"},
+
+ {"ADDA_DL_CH3", "DL5_CH1", "DL5"},
+ {"ADDA_DL_CH4", "DL5_CH2", "DL5"},
+
+ {"ADDA_DL_CH3", "DL6_CH1", "DL6"},
+ {"ADDA_DL_CH4", "DL6_CH2", "DL6"},
+
+ {"ADDA_DL_CH3", "DL7_CH1", "DL7"},
+ {"ADDA_DL_CH4", "DL7_CH2", "DL7"},
+
+ {"ADDA_DL_CH3", "DL8_CH1", "DL8"},
+ {"ADDA_DL_CH4", "DL8_CH2", "DL8"},
+
+ {"ADDA_DL_CH3", "DL_24CH_CH1", "DL_24CH"},
+ {"ADDA_DL_CH4", "DL_24CH_CH2", "DL_24CH"},
+ {"ADDA_DL_CH3", "DL_24CH_CH3", "DL_24CH"},
+ {"ADDA_DL_CH4", "DL_24CH_CH4", "DL_24CH"},
+
+ {"ADDA_DL_CH3", "DL24_CH1", "DL24"},
+ {"ADDA_DL_CH4", "DL24_CH2", "DL24"},
+
+ {"ADDA Capture", NULL, "ADDA Enable"},
+ {"ADDA Capture", NULL, "ADDA Capture Enable"},
+ {"ADDA Capture", NULL, "AUD_PAD_TOP"},
+ {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+ {"ADDA Capture", NULL, "VS1_VOTER_UL"},
+ {"ADDA Capture", NULL, "ADDA_UL0_CG"},
+
+ /* capture */
+ {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+ {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+ {"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"},
+
+ {"AP DMIC Capture", NULL, "ADDA Enable"},
+ {"AP DMIC Capture", NULL, "AP DMIC Capture Enable"},
+ {"AP DMIC Capture", NULL, "AP_DMIC_FIFO"},
+ {"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+ {"AP DMIC Capture", NULL, "AP_DMIC0_CG"},
+
+ {"AP DMIC CH34 Capture", NULL, "ADDA Enable"},
+ {"AP DMIC CH34 Capture", NULL, "AP DMIC CH34 Capture Enable"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_FIFO"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC1_CG"},
+
+ {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+ {"AP DMIC CH34 Capture", NULL, "AP_DMIC_INPUT"},
+};
+
+/* dai ops */
+static int set_playback_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = params_rate(params);
+ struct mtk_afe_adda_priv *adda_priv;
+ unsigned int dl_src_con0;
+ unsigned int dl_src_con1;
+ int id = dai->id;
+
+ adda_priv = afe_priv->dai_priv[id];
+ if (!adda_priv)
+ return -EINVAL;
+
+ adda_priv->dl_rate = rate;
+
+ /* set sampling rate */
+ dl_src_con0 = adda_dl_rate_transform(afe, rate) <<
+ AFE_DL_INPUT_MODE_CTL_SFT;
+
+ /* set output mode, UP_SAMPLING_RATE_X8 */
+ dl_src_con0 |= (0x3 << AFE_DL_OUTPUT_SEL_CTL_SFT);
+
+ /* turn off mute function */
+ dl_src_con0 |= (0x01 << AFE_DL_MUTE_CH2_OFF_CTL_PRE_SFT);
+ dl_src_con0 |= (0x01 << AFE_DL_MUTE_CH1_OFF_CTL_PRE_SFT);
+
+ /* set voice input data if input sample rate is 8k or 16k */
+ if (rate == 8000 || rate == 16000)
+ dl_src_con0 |= 0x01 << AFE_DL_VOICE_MODE_CTL_PRE_SFT;
+
+ /* SA suggest apply -0.3db to audio/speech path */
+ dl_src_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+ AFE_DL_GAIN1_CTL_PRE_SFT;
+ dl_src_con1 |= MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+ AFE_DL_GAIN2_CTL_PRE_SFT;
+
+ /* turn on down-link gain */
+ dl_src_con0 |= (0x01 << AFE_DL_GAIN_ON_CTL_PRE_SFT);
+
+ if (id == MT8189_DAI_ADDA) {
+ /* clean predistortion */
+ regmap_write(afe->regmap, AFE_ADDA_DL_PREDIS_CON0, 0);
+ regmap_write(afe->regmap, AFE_ADDA_DL_PREDIS_CON1, 0);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_DL_SRC_CON0, dl_src_con0);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DL_SRC_CON1, dl_src_con1);
+
+ /* set sdm gain */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_DCCOMP_CON,
+ AFE_DL_ATTGAIN_CTL_MASK_SFT,
+ AUDIO_SDM_LEVEL_NORMAL <<
+ AFE_DL_ATTGAIN_CTL_SFT);
+
+ /* 2nd sdm */
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_DCCOMP_CON,
+ AFE_DL_USE_3RD_SDM_MASK_SFT,
+ AUDIO_SDM_2ND << AFE_DL_USE_3RD_SDM_SFT);
+
+ /* sdm auto reset */
+ regmap_write(afe->regmap,
+ AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+ SDM_AUTO_RESET_THRESHOLD);
+ regmap_update_bits(afe->regmap,
+ AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+ AFE_DL_SDM_AUTO_RESET_TEST_ON_SFT,
+ 0x1 << AFE_DL_SDM_AUTO_RESET_TEST_ON_SFT);
+ }
+
+ return 0;
+}
+
+static int set_capture_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ unsigned int rate = params_rate(params);
+ struct mtk_afe_adda_priv *adda_priv;
+ unsigned int voice_mode;
+ unsigned int ul_src_con0;
+ int id = dai->id;
+
+ adda_priv = afe_priv->dai_priv[id];
+ if (!adda_priv)
+ return -EINVAL;
+
+ adda_priv->ul_rate = rate;
+
+ voice_mode = adda_ul_rate_transform(afe, rate);
+
+ ul_src_con0 = (voice_mode << UL_VOICE_MODE_CH1_CH2_CTL_SFT) &
+ UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT;
+
+ /* enable iir */
+ ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+ UL_IIR_ON_TMP_CTL_MASK_SFT;
+ ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+ UL_IIRMODE_CTL_MASK_SFT;
+
+ switch (id) {
+ case MT8189_DAI_ADDA:
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_UL0_SRC_CON0, ul_src_con0);
+
+ /* mtkaif_rxif_data_mode = 0, amic */
+ regmap_update_bits(afe->regmap,
+ AFE_MTKAIF0_RX_CFG0,
+ RG_MTKAIF0_RXIF_DATA_MODE_MASK_SFT,
+ 0x0 << RG_MTKAIF0_RXIF_DATA_MODE_SFT);
+ break;
+ case MT8189_DAI_AP_DMIC:
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC0_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC0_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC0_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC0_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC0_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC0_SRC_CON0, ul_src_con0);
+ break;
+ case MT8189_DAI_AP_DMIC_CH34:
+ /* 35Hz @ 48k */
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC1_IIR_COEF_02_01, 0x00000000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC1_IIR_COEF_04_03, 0x00003FB8);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC1_IIR_COEF_06_05, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC1_IIR_COEF_08_07, 0x3FB80000);
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC1_IIR_COEF_10_09, 0x0000C048);
+
+ regmap_write(afe->regmap,
+ AFE_ADDA_DMIC1_SRC_CON0, ul_src_con0);
+ break;
+ default:
+ break;
+ }
+
+ /* ap dmic */
+ if (id == MT8189_DAI_AP_DMIC || id == MT8189_DAI_AP_DMIC_CH34)
+ mtk_adda_ul_src_enable_dmic(afe, id);
+
+ return 0;
+}
+
+static int mtk_dai_adda_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);
+ int id = dai->id;
+
+ if (id >= MT8189_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+ __func__, id, substream->stream, params_rate(params));
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return set_playback_hw_params(params, dai);
+ else
+ return set_capture_hw_params(params, dai);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+ .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "ADDA",
+ .id = MT8189_DAI_ADDA,
+ .playback = {
+ .stream_name = "ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "ADDA_CH34",
+ .id = MT8189_DAI_ADDA_CH34,
+ .playback = {
+ .stream_name = "ADDA CH34 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_PLAYBACK_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC",
+ .id = MT8189_DAI_AP_DMIC,
+ .capture = {
+ .stream_name = "AP DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+ {
+ .name = "AP_DMIC_CH34",
+ .id = MT8189_DAI_AP_DMIC_CH34,
+ .capture = {
+ .stream_name = "AP DMIC CH34 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ADDA_CAPTURE_RATES,
+ .formats = MTK_ADDA_FORMATS,
+ },
+ .ops = &mtk_dai_adda_ops,
+ },
+};
+
+static int init_adda_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_adda_priv *adda_priv;
+ static const int adda_dai_list[] = {
+ MT8189_DAI_ADDA,
+ MT8189_DAI_ADDA_CH34,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(adda_dai_list); i++) {
+ adda_priv = devm_kzalloc(afe->dev,
+ sizeof(struct mtk_afe_adda_priv),
+ GFP_KERNEL);
+ if (!adda_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[adda_dai_list[i]] = adda_priv;
+ }
+
+ /* ap dmic priv share with adda */
+ afe_priv->dai_priv[MT8189_DAI_AP_DMIC] =
+ afe_priv->dai_priv[MT8189_DAI_ADDA];
+ afe_priv->dai_priv[MT8189_DAI_AP_DMIC_CH34] =
+ afe_priv->dai_priv[MT8189_DAI_ADDA_CH34];
+
+ return 0;
+}
+
+int mt8189_dai_adda_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+ dai->controls = mtk_adda_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+ ret = init_adda_priv_data(afe);
+ if (ret)
+ return ret;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c b/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
new file mode 100644
index 000000000000..94c49a662e2d
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-i2s.c
@@ -0,0 +1,1463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI I2S Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+
+#include <sound/pcm_params.h>
+
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+#include "../common/mtk-afe-fe-dai.h"
+
+#define I2SIN0_MCLK_EN_W_NAME "I2SIN0_MCLK_EN"
+#define I2SIN1_MCLK_EN_W_NAME "I2SIN1_MCLK_EN"
+#define I2SOUT0_MCLK_EN_W_NAME "I2SOUT0_MCLK_EN"
+#define I2SOUT1_MCLK_EN_W_NAME "I2SOUT1_MCLK_EN"
+#define I2SOUT4_MCLK_EN_W_NAME "I2SOUT4_MCLK_EN"
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_I2S_MCLK_EN,
+ SUPPLY_SEQ_I2S_CG_EN,
+ SUPPLY_SEQ_I2S_EN,
+};
+
+/* this enum is merely for mtk_afe_i2s_priv declare */
+enum {
+ DAI_I2SIN0,
+ DAI_I2SIN1,
+ DAI_I2SOUT0,
+ DAI_I2SOUT1,
+ DAI_I2SOUT4,
+ DAI_I2S_NUM,
+};
+
+enum {
+ ETDM_CLK_SOURCE_H26M,
+ ETDM_CLK_SOURCE_APLL,
+ ETDM_CLK_SOURCE_SPDIF,
+ ETDM_CLK_SOURCE_HDMI,
+ ETDM_CLK_SOURCE_EARC,
+ ETDM_CLK_SOURCE_LINEIN,
+};
+
+enum {
+ ETDM_RELATCH_SEL_H26M,
+ ETDM_RELATCH_SEL_APLL,
+};
+
+enum {
+ ETDM_RATE_8K,
+ ETDM_RATE_12K,
+ ETDM_RATE_16K,
+ ETDM_RATE_24K,
+ ETDM_RATE_32K,
+ ETDM_RATE_48K,
+ ETDM_RATE_64K,
+ ETDM_RATE_96K,
+ ETDM_RATE_128K,
+ ETDM_RATE_192K,
+ ETDM_RATE_256K,
+ ETDM_RATE_384K,
+ ETDM_RATE_11025 = 16,
+ ETDM_RATE_22050,
+ ETDM_RATE_44100,
+ ETDM_RATE_88200,
+ ETDM_RATE_176400,
+ ETDM_RATE_352800,
+};
+
+enum {
+ ETDM_CONN_8K,
+ ETDM_CONN_11K,
+ ETDM_CONN_12K,
+ ETDM_CONN_16K = 4,
+ ETDM_CONN_22K,
+ ETDM_CONN_24K,
+ ETDM_CONN_32K = 8,
+ ETDM_CONN_44K,
+ ETDM_CONN_48K,
+ ETDM_CONN_88K = 13,
+ ETDM_CONN_96K,
+ ETDM_CONN_176K = 17,
+ ETDM_CONN_192K,
+ ETDM_CONN_352K = 21,
+ ETDM_CONN_384K,
+};
+
+enum {
+ ETDM_WLEN_8_BIT = 0x7,
+ ETDM_WLEN_16_BIT = 0xf,
+ ETDM_WLEN_32_BIT = 0x1f,
+};
+
+enum {
+ ETDM_SLAVE_SEL_ETDMIN0_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN0_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN1_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN1_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN2_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN2_SLAVE,
+ ETDM_SLAVE_SEL_ETDMIN3_MASTER,
+ ETDM_SLAVE_SEL_ETDMIN3_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT0_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT0_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT1_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT1_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT2_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT2_SLAVE,
+ ETDM_SLAVE_SEL_ETDMOUT3_MASTER,
+ ETDM_SLAVE_SEL_ETDMOUT3_SLAVE,
+};
+
+struct mtk_afe_i2s_priv {
+ int id;
+ int rate; /* for determine which apll to use */
+ int low_jitter_en;
+ unsigned int i2s_low_power_mask;
+ const char *share_property_name;
+ int share_i2s_id;
+
+ int mclk_id;
+ int mclk_rate;
+ int mclk_apll;
+
+ int ch_num;
+ int sync;
+ int ip_mode;
+ int slave_mode;
+ int lpbk_mode;
+};
+
+static unsigned int get_etdm_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ ETDM_WLEN_16_BIT : ETDM_WLEN_32_BIT;
+}
+
+static unsigned int get_etdm_lrck_width(snd_pcm_format_t format)
+{
+ if (snd_pcm_format_physical_width(format) <= 1)
+ return 0;
+
+ /* The valid data bit number should be larger than 7 due to hardware limitation. */
+ return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_etdm_rate(unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return ETDM_RATE_8K;
+ case 12000:
+ return ETDM_RATE_12K;
+ case 16000:
+ return ETDM_RATE_16K;
+ case 24000:
+ return ETDM_RATE_24K;
+ case 32000:
+ return ETDM_RATE_32K;
+ case 48000:
+ return ETDM_RATE_48K;
+ case 64000:
+ return ETDM_RATE_64K;
+ case 96000:
+ return ETDM_RATE_96K;
+ case 128000:
+ return ETDM_RATE_128K;
+ case 192000:
+ return ETDM_RATE_192K;
+ case 256000:
+ return ETDM_RATE_256K;
+ case 384000:
+ return ETDM_RATE_384K;
+ case 11025:
+ return ETDM_RATE_11025;
+ case 22050:
+ return ETDM_RATE_22050;
+ case 44100:
+ return ETDM_RATE_44100;
+ case 88200:
+ return ETDM_RATE_88200;
+ case 176400:
+ return ETDM_RATE_176400;
+ case 352800:
+ return ETDM_RATE_352800;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_etdm_inconn_rate(unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return ETDM_CONN_8K;
+ case 12000:
+ return ETDM_CONN_12K;
+ case 16000:
+ return ETDM_CONN_16K;
+ case 24000:
+ return ETDM_CONN_24K;
+ case 32000:
+ return ETDM_CONN_32K;
+ case 48000:
+ return ETDM_CONN_48K;
+ case 96000:
+ return ETDM_CONN_96K;
+ case 192000:
+ return ETDM_CONN_192K;
+ case 384000:
+ return ETDM_CONN_384K;
+ case 11025:
+ return ETDM_CONN_11K;
+ case 22050:
+ return ETDM_CONN_22K;
+ case 44100:
+ return ETDM_CONN_44K;
+ case 88200:
+ return ETDM_CONN_88K;
+ case 176400:
+ return ETDM_CONN_176K;
+ case 352800:
+ return ETDM_CONN_352K;
+ default:
+ return 0;
+ }
+}
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ if (strncmp(name, "I2SIN0", 6) == 0)
+ return MT8189_DAI_I2S_IN0;
+ else if (strncmp(name, "I2SIN1", 6) == 0)
+ return MT8189_DAI_I2S_IN1;
+ else if (strncmp(name, "I2SOUT0", 7) == 0)
+ return MT8189_DAI_I2S_OUT0;
+ else if (strncmp(name, "I2SOUT1", 7) == 0)
+ return MT8189_DAI_I2S_OUT1;
+ else if (strncmp(name, "I2SOUT4", 7) == 0)
+ return MT8189_DAI_I2S_OUT4;
+ else
+ return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+ const char *name)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_i2s_id_by_name(afe, name);
+
+ if (dai_id < 0)
+ return NULL;
+
+ return afe_priv->dai_priv[dai_id];
+}
+
+static const char * const etdm_0_3_loopback_texts[] = {
+ "etdmin0", "etdmin1", "etdmout0", "etdmout1"
+};
+
+static const u32 etdm_loopback_values[] = {
+ 0, 2, 8, 10
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2sin0_loopback_enum,
+ ETDM_0_3_COWORK_CON1,
+ ETDM_IN0_SDATA0_SEL_SFT,
+ ETDM_IN0_SDATA0_SEL_MASK,
+ etdm_0_3_loopback_texts,
+ etdm_loopback_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(i2sin1_loopback_enum,
+ ETDM_0_3_COWORK_CON1,
+ ETDM_IN1_SDATA0_SEL_SFT,
+ ETDM_IN1_SDATA0_SEL_MASK,
+ etdm_0_3_loopback_texts,
+ etdm_loopback_values);
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+ SOC_ENUM("I2SIN0 Loopback", i2sin0_loopback_enum),
+ SOC_ENUM("I2SIN1 Loopback", i2sin1_loopback_enum),
+};
+
+/*
+ * I2S virtual mux to output widget
+ * If the I2S interface is required but not connected to an actual codec dai,
+ * a Dummy_Widget must be used to establish the connection.
+ */
+static const char *const i2s_mux_map[] = {
+ "Normal", "Dummy_Widget",
+};
+
+static int i2s_mux_map_value[] = {
+ 0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum,
+ SND_SOC_NOPM,
+ 0,
+ 1,
+ i2s_mux_map,
+ i2s_mux_map_value);
+
+static const struct snd_kcontrol_new i2s_in0_mux_control =
+ SOC_DAPM_ENUM("I2S IN0 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_in1_mux_control =
+ SOC_DAPM_ENUM("I2S IN1 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_out0_mux_control =
+ SOC_DAPM_ENUM("I2S OUT0 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_out1_mux_control =
+ SOC_DAPM_ENUM("I2S OUT1 Select", i2s_mux_map_enum);
+static const struct snd_kcontrol_new i2s_out4_mux_control =
+ SOC_DAPM_ENUM("I2S OUT4 Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new mtk_i2sout0_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN108_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN108_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN108_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN108_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN108_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN108_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN108_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN108_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN108_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN108_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN108_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN108_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN108_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout0_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN109_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN109_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN109_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN109_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN109_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN109_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN109_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN109_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN109_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN109_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN109_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN109_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN109_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN109_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout1_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN110_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN110_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN110_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN110_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN110_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN110_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN110_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN110_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN110_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN110_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN110_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN110_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN110_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout1_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN111_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN111_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN111_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN111_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN111_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN111_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN111_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN111_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN111_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN111_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN111_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN111_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN111_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN111_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN116_1, I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN116_1, I_DL1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN116_1, I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN116_1, I_DL3_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN116_1, I_DL4_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN116_1, I_DL5_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN116_1, I_DL6_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH1", AFE_CONN116_1, I_DL7_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN116_1, I_DL8_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN116_1, I_DL_24CH_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH1", AFE_CONN116_2, I_DL24_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH1", AFE_CONN116_0,
+ I_GAIN0_OUT_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN116_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN116_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN116_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1", AFE_CONN116_6,
+ I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH2", AFE_CONN117_1, I_DL0_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN117_1, I_DL1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN117_1, I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN117_1, I_DL3_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN117_1, I_DL4_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN117_1, I_DL5_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN117_1, I_DL6_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL7_CH2", AFE_CONN117_1, I_DL7_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN117_1, I_DL8_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN117_1, I_DL_24CH_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL24_CH2", AFE_CONN117_2, I_DL24_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN0_OUT_CH2", AFE_CONN117_0,
+ I_GAIN0_OUT_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN117_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN117_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN117_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH2", AFE_CONN117_4,
+ I_PCM_0_CAP_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2", AFE_CONN117_6,
+ I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch3_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH3", AFE_CONN118_1, I_DL_24CH_CH3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN118_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH4", AFE_CONN119_1, I_DL_24CH_CH4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("PCM_0_CAP_CH1", AFE_CONN118_4,
+ I_PCM_0_CAP_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch5_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH5", AFE_CONN120_1, I_DL_24CH_CH5, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch6_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH6", AFE_CONN121_1, I_DL_24CH_CH6, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch7_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH7", AFE_CONN122_1, I_DL_24CH_CH7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2sout4_ch8_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH8", AFE_CONN123_1, I_DL_24CH_CH8, 1, 0),
+};
+
+static int mtk_apll_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);
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8189_apll1_enable(afe);
+ else
+ mt8189_apll2_enable(afe);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (strcmp(w->name, APLL1_W_NAME) == 0)
+ mt8189_apll1_disable(afe);
+ else
+ mt8189_apll2_disable(afe);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_mclk_en_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 mtk_afe_i2s_priv *i2s_priv;
+
+ dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+ if (!i2s_priv)
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8189_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ i2s_priv->mclk_rate = 0;
+ mt8189_mck_disable(afe, i2s_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+ SND_SOC_DAPM_MIXER("I2SOUT0_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout0_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout0_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT0_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout0_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout0_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT1_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout1_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout1_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT1_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout1_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout1_ch2_mix)),
+
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch1_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch1_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch2_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch2_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH3", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch3_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch3_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch4_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch4_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH5", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch5_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch5_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH6", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch6_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch6_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH7", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch7_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch7_mix)),
+ SND_SOC_DAPM_MIXER("I2SOUT4_CH8", SND_SOC_NOPM, 0, 0,
+ mtk_i2sout4_ch8_mix,
+ ARRAY_SIZE(mtk_i2sout4_ch8_mix)),
+
+ /* i2s en*/
+ SND_SOC_DAPM_SUPPLY_S("I2SIN0_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN0_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN1_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_IN1_CON0, REG_ETDM_IN_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT0_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT0_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT1_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT1_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT4_EN", SUPPLY_SEQ_I2S_EN,
+ ETDM_OUT4_CON0, OUT_REG_ETDM_OUT_EN_SFT, 0,
+ NULL, 0),
+
+ /* i2s mclk en */
+ SND_SOC_DAPM_SUPPLY_S(I2SIN0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SIN1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(I2SOUT4_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_mclk_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* cg */
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT0_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT0_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT1_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT1_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SOUT4_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_OUT4_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN0_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN0_SFT, 1,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2SIN1_CG", SUPPLY_SEQ_I2S_CG_EN,
+ AUDIO_TOP_CON2, PDN_ETDM_IN1_SFT, 1,
+ NULL, 0),
+
+ /* apll */
+ SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+ SND_SOC_NOPM, 0, 0,
+ mtk_apll_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* allow i2s on without codec on */
+ SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"),
+ SND_SOC_DAPM_MUX("I2S_OUT0_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s_out0_mux_control),
+ SND_SOC_DAPM_MUX("I2S_OUT1_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s_out1_mux_control),
+ SND_SOC_DAPM_MUX("I2S_OUT4_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s_out4_mux_control),
+
+ SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"),
+ SND_SOC_DAPM_MUX("I2S_IN0_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s_in0_mux_control),
+ SND_SOC_DAPM_MUX("I2S_IN1_Mux",
+ SND_SOC_NOPM, 0, 0, &i2s_in1_mux_control),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name);
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+ int needed_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ /* which apll */
+ cur_apll = mt8189_get_apll_by_name(afe, source->name);
+
+ /* choose APLL from i2s rate */
+ needed_apll = mt8189_get_apll_by_rate(afe, i2s_priv->rate);
+
+ return needed_apll == cur_apll;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int i2s_num;
+
+ i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+ if (!i2s_priv)
+ return 0;
+
+ i2s_num = get_i2s_id_by_name(afe, source->name);
+ if (get_i2s_id_by_name(afe, sink->name) == i2s_num)
+ return i2s_priv->mclk_rate > 0;
+
+ /* check if share i2s need mclk */
+ if (i2s_priv->share_i2s_id < 0)
+ return 0;
+
+ if (i2s_priv->share_i2s_id == i2s_num)
+ return i2s_priv->mclk_rate > 0;
+
+ return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget *w = sink;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int cur_apll;
+
+ i2s_priv = get_i2s_priv_by_name(afe, w->name);
+ if (!i2s_priv)
+ return 0;
+
+ /* which apll */
+ cur_apll = mt8189_get_apll_by_name(afe, source->name);
+
+ return i2s_priv->mclk_apll == cur_apll;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+ /* I2SIN0 */
+ {"I2SIN0", NULL, "I2SIN0_EN"},
+ {"I2SIN0", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN0", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN0", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN0", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN0", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN0", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN0", NULL, "I2SOUT0_CG"},
+ {"I2SIN0", NULL, "I2SIN0_CG"},
+
+ /* i2sin1 */
+ {"I2SIN1", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SIN1_EN"},
+ {"I2SIN1", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SIN1", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SIN1", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SIN1", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SIN1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SIN1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SIN1", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN1", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SIN1", NULL, "I2SIN1_CG"},
+ {"I2SIN1", NULL, "I2SOUT1_CG"},
+
+ /* i2sout0 */
+ {"I2SOUT0_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT0_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT0_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT0_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT0_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT0_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT0_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT0_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT0_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT0_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT0_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT0_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT0_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT0_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT0_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT0_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT0_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT0_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT0_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT0_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"I2SOUT0", NULL, "I2SOUT0_CH1"},
+ {"I2SOUT0", NULL, "I2SOUT0_CH2"},
+
+ {"I2SOUT0", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT0_EN"},
+ {"I2SOUT0", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT0", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT0", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT0", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT0", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT0", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT0", NULL, "I2SOUT0_CG"},
+ {"I2SOUT0", NULL, "I2SIN0_CG"},
+
+ /* i2sout1 */
+ {"I2SOUT1_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT1_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT1_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT1_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT1_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT1_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT1_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT1_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT1_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT1_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT1_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT1_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT1_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT1_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT1_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT1_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT1_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT1_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT1_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT1_CH2", "DL_24CH_CH2", "DL_24CH"},
+
+ {"I2SOUT1", NULL, "I2SOUT1_CH1"},
+ {"I2SOUT1", NULL, "I2SOUT1_CH2"},
+
+ {"I2SOUT1", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT1", NULL, "I2SOUT1_EN"},
+ {"I2SOUT1", NULL, "I2SOUT4_EN", mtk_afe_i2s_share_connect},
+
+ {"I2SOUT1", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT1", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT1", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT1", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT1", NULL, "I2SOUT1_CG"},
+ {"I2SOUT1", NULL, "I2SIN1_CG"},
+
+ /* i2sout4 */
+ {"I2SOUT4_CH1", "DL0_CH1", "DL0"},
+ {"I2SOUT4_CH2", "DL0_CH2", "DL0"},
+ {"I2SOUT4_CH1", "DL1_CH1", "DL1"},
+ {"I2SOUT4_CH2", "DL1_CH2", "DL1"},
+ {"I2SOUT4_CH1", "DL2_CH1", "DL2"},
+ {"I2SOUT4_CH2", "DL2_CH2", "DL2"},
+ {"I2SOUT4_CH1", "DL3_CH1", "DL3"},
+ {"I2SOUT4_CH2", "DL3_CH2", "DL3"},
+ {"I2SOUT4_CH1", "DL4_CH1", "DL4"},
+ {"I2SOUT4_CH2", "DL4_CH2", "DL4"},
+ {"I2SOUT4_CH1", "DL5_CH1", "DL5"},
+ {"I2SOUT4_CH2", "DL5_CH2", "DL5"},
+ {"I2SOUT4_CH1", "DL6_CH1", "DL6"},
+ {"I2SOUT4_CH2", "DL6_CH2", "DL6"},
+ {"I2SOUT4_CH1", "DL7_CH1", "DL7"},
+ {"I2SOUT4_CH2", "DL7_CH2", "DL7"},
+ {"I2SOUT4_CH1", "DL8_CH1", "DL8"},
+ {"I2SOUT4_CH2", "DL8_CH2", "DL8"},
+ {"I2SOUT4_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"I2SOUT4_CH2", "DL_24CH_CH2", "DL_24CH"},
+ {"I2SOUT4_CH3", "DL_24CH_CH3", "DL_24CH"},
+ {"I2SOUT4_CH4", "DL_24CH_CH4", "DL_24CH"},
+ {"I2SOUT4_CH5", "DL_24CH_CH5", "DL_24CH"},
+ {"I2SOUT4_CH6", "DL_24CH_CH6", "DL_24CH"},
+ {"I2SOUT4_CH7", "DL_24CH_CH7", "DL_24CH"},
+ {"I2SOUT4_CH8", "DL_24CH_CH8", "DL_24CH"},
+ {"I2SOUT4_CH1", "DL24_CH1", "DL24"},
+ {"I2SOUT4_CH2", "DL24_CH2", "DL24"},
+
+ {"I2SOUT4", NULL, "I2SOUT4_CH1"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH2"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH3"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH4"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH5"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH6"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH7"},
+ {"I2SOUT4", NULL, "I2SOUT4_CH8"},
+
+ {"I2SOUT4", NULL, "I2SIN0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SIN1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT0_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT1_EN", mtk_afe_i2s_share_connect},
+ {"I2SOUT4", NULL, "I2SOUT4_EN"},
+
+ {"I2SOUT4", NULL, I2SIN0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SIN1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {"I2SOUT4", NULL, I2SOUT4_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+ {I2SOUT4_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+ {I2SOUT4_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+ {"I2SOUT4", NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+ {"I2SOUT4", NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+ /* CG */
+ {"I2SOUT4", NULL, "I2SOUT4_CG"},
+
+ /* allow i2s on without codec on */
+ {"I2SIN0", NULL, "I2S_IN0_Mux"},
+ {"I2S_IN0_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+ {"I2SIN1", NULL, "I2S_IN1_Mux"},
+ {"I2S_IN1_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+ {"I2S_OUT0_Mux", "Dummy_Widget", "I2SOUT0"},
+ {"I2S_DUMMY_OUT", NULL, "I2S_OUT0_Mux"},
+
+ {"I2S_OUT1_Mux", "Dummy_Widget", "I2SOUT1"},
+ {"I2S_DUMMY_OUT", NULL, "I2S_OUT1_Mux"},
+
+ {"I2S_OUT4_Mux", "Dummy_Widget", "I2SOUT4"},
+ {"I2S_DUMMY_OUT", NULL, "I2S_OUT4_Mux"},
+};
+
+/* i2s dai ops*/
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+ struct snd_pcm_hw_params *params,
+ int i2s_id)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+ unsigned int rate = params_rate(params);
+ snd_pcm_format_t format = params_format(params);
+ int ret;
+
+ if (i2s_id >= MT8189_DAI_NUM || i2s_id < 0)
+ return -EINVAL;
+
+ i2s_priv = afe_priv->dai_priv[i2s_id];
+ if (!i2s_priv)
+ return -EINVAL;
+
+ i2s_priv->rate = rate;
+
+ dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
+ __func__, i2s_id, rate, format);
+
+ switch (i2s_id) {
+ case MT8189_DAI_I2S_IN0:
+ /* ---etdm in --- */
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON1,
+ REG_INITIAL_COUNT_MASK_SFT,
+ 0x5 << REG_INITIAL_COUNT_SFT);
+ /* 3: pad top 5: no pad top */
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON1,
+ REG_INITIAL_POINT_MASK_SFT,
+ 0x5 << REG_INITIAL_POINT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON1,
+ REG_LRCK_RESET_MASK_SFT,
+ 0x1 << REG_LRCK_RESET_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON2,
+ REG_CLOCK_SOURCE_SEL_MASK_SFT,
+ ETDM_CLK_SOURCE_APLL <<
+ REG_CLOCK_SOURCE_SEL_SFT);
+ /* 0: manual 1: auto */
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON2,
+ REG_CK_EN_SEL_AUTO_MASK_SFT,
+ 0x1 << REG_CK_EN_SEL_AUTO_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON3,
+ REG_FS_TIMING_SEL_MASK_SFT,
+ get_etdm_rate(rate) <<
+ REG_FS_TIMING_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON4,
+ REG_RELATCH_1X_EN_SEL_MASK_SFT,
+ get_etdm_inconn_rate(rate) <<
+ REG_RELATCH_1X_EN_SEL_SFT);
+
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON8,
+ REG_ETDM_USE_AFIFO_MASK_SFT,
+ 0x0 << REG_ETDM_USE_AFIFO_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON8,
+ REG_AFIFO_MODE_MASK_SFT,
+ 0x0 << REG_AFIFO_MODE_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON9,
+ REG_ALMOST_END_CH_COUNT_MASK_SFT,
+ 0x0 << REG_ALMOST_END_CH_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON9,
+ REG_ALMOST_END_BIT_COUNT_MASK_SFT,
+ 0x0 << REG_ALMOST_END_BIT_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON9,
+ REG_OUT2LATCH_TIME_MASK_SFT,
+ 0x6 << REG_OUT2LATCH_TIME_SFT);
+
+ /* 5: TDM Mode */
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+ REG_FMT_MASK_SFT, 0x0 << REG_FMT_SFT);
+
+ /* APLL */
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+ REG_RELATCH_1X_EN_DOMAIN_SEL_MASK_SFT,
+ ETDM_RELATCH_SEL_APLL
+ << REG_RELATCH_1X_EN_DOMAIN_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+ REG_BIT_LENGTH_MASK_SFT,
+ get_etdm_lrck_width(format) <<
+ REG_BIT_LENGTH_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN0_CON0,
+ REG_WORD_LENGTH_MASK_SFT,
+ get_etdm_wlen(format) <<
+ REG_WORD_LENGTH_SFT);
+
+ /* ---etdm cowork --- */
+ regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
+ ETDM_IN0_SLAVE_SEL_MASK_SFT,
+ ETDM_SLAVE_SEL_ETDMOUT0_MASTER
+ << ETDM_IN0_SLAVE_SEL_SFT);
+ break;
+ case MT8189_DAI_I2S_IN1:
+ /* ---etdm in --- */
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
+ REG_INITIAL_COUNT_MASK_SFT,
+ 0x5 << REG_INITIAL_COUNT_SFT);
+ /* 3: pad top 5: no pad top */
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
+ REG_INITIAL_POINT_MASK_SFT,
+ 0x5 << REG_INITIAL_POINT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON1,
+ REG_LRCK_RESET_MASK_SFT,
+ 0x1 << REG_LRCK_RESET_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
+ REG_CLOCK_SOURCE_SEL_MASK_SFT,
+ ETDM_CLK_SOURCE_APLL <<
+ REG_CLOCK_SOURCE_SEL_SFT);
+ /* 0: manual 1: auto */
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON2,
+ REG_CK_EN_SEL_AUTO_MASK_SFT,
+ 0x1 << REG_CK_EN_SEL_AUTO_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON3,
+ REG_FS_TIMING_SEL_MASK_SFT,
+ get_etdm_rate(rate) <<
+ REG_FS_TIMING_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON4,
+ REG_RELATCH_1X_EN_SEL_MASK_SFT,
+ get_etdm_inconn_rate(rate) <<
+ REG_RELATCH_1X_EN_SEL_SFT);
+
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON8,
+ REG_ETDM_USE_AFIFO_MASK_SFT,
+ 0x0 << REG_ETDM_USE_AFIFO_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON8,
+ REG_AFIFO_MODE_MASK_SFT,
+ 0x0 << REG_AFIFO_MODE_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
+ REG_ALMOST_END_CH_COUNT_MASK_SFT,
+ 0x0 << REG_ALMOST_END_CH_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
+ REG_ALMOST_END_BIT_COUNT_MASK_SFT,
+ 0x0 << REG_ALMOST_END_BIT_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON9,
+ REG_OUT2LATCH_TIME_MASK_SFT,
+ 0x6 << REG_OUT2LATCH_TIME_SFT);
+
+ /* 5: TDM Mode */
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+ REG_FMT_MASK_SFT, 0x0 << REG_FMT_SFT);
+
+ /* APLL */
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+ REG_RELATCH_1X_EN_DOMAIN_SEL_MASK_SFT,
+ ETDM_RELATCH_SEL_APLL
+ << REG_RELATCH_1X_EN_DOMAIN_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+ REG_BIT_LENGTH_MASK_SFT,
+ get_etdm_lrck_width(format) <<
+ REG_BIT_LENGTH_SFT);
+ regmap_update_bits(afe->regmap, ETDM_IN1_CON0,
+ REG_WORD_LENGTH_MASK_SFT,
+ get_etdm_wlen(format) <<
+ REG_WORD_LENGTH_SFT);
+
+ /* ---etdm cowork --- */
+ regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON1,
+ ETDM_IN1_SLAVE_SEL_MASK_SFT,
+ ETDM_SLAVE_SEL_ETDMOUT1_MASTER
+ << ETDM_IN1_SLAVE_SEL_SFT);
+ break;
+ case MT8189_DAI_I2S_OUT0:
+ /* ---etdm out --- */
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON1,
+ OUT_REG_INITIAL_COUNT_MASK_SFT,
+ 0x5 << OUT_REG_INITIAL_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON1,
+ OUT_REG_INITIAL_POINT_MASK_SFT,
+ 0x6 << OUT_REG_INITIAL_POINT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON1,
+ OUT_REG_LRCK_RESET_MASK_SFT,
+ 0x1 << OUT_REG_LRCK_RESET_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON4,
+ OUT_REG_FS_TIMING_SEL_MASK_SFT,
+ get_etdm_rate(rate) <<
+ OUT_REG_FS_TIMING_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON4,
+ OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
+ ETDM_CLK_SOURCE_APLL <<
+ OUT_REG_CLOCK_SOURCE_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON4,
+ OUT_REG_RELATCH_EN_SEL_MASK_SFT,
+ get_etdm_inconn_rate(rate) <<
+ OUT_REG_RELATCH_EN_SEL_SFT);
+ /* 5: TDM Mode */
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+ OUT_REG_FMT_MASK_SFT,
+ 0x0 << OUT_REG_FMT_SFT);
+
+ /* APLL */
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+ OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT,
+ ETDM_RELATCH_SEL_APLL
+ << OUT_REG_RELATCH_DOMAIN_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+ OUT_REG_BIT_LENGTH_MASK_SFT,
+ get_etdm_lrck_width(format) <<
+ OUT_REG_BIT_LENGTH_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT0_CON0,
+ OUT_REG_WORD_LENGTH_MASK_SFT,
+ get_etdm_wlen(format) <<
+ OUT_REG_WORD_LENGTH_SFT);
+
+ /* ---etdm cowork --- */
+ regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
+ ETDM_OUT0_SLAVE_SEL_MASK_SFT,
+ ETDM_SLAVE_SEL_ETDMIN0_MASTER
+ << ETDM_OUT0_SLAVE_SEL_SFT);
+ break;
+ case MT8189_DAI_I2S_OUT1:
+ /* ---etdm out --- */
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
+ OUT_REG_INITIAL_COUNT_MASK_SFT,
+ 0x5 << OUT_REG_INITIAL_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
+ OUT_REG_INITIAL_POINT_MASK_SFT,
+ 0x6 << OUT_REG_INITIAL_POINT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON1,
+ OUT_REG_LRCK_RESET_MASK_SFT,
+ 0x1 << OUT_REG_LRCK_RESET_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
+ OUT_REG_FS_TIMING_SEL_MASK_SFT,
+ get_etdm_rate(rate) <<
+ OUT_REG_FS_TIMING_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
+ OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
+ ETDM_CLK_SOURCE_APLL <<
+ OUT_REG_CLOCK_SOURCE_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON4,
+ OUT_REG_RELATCH_EN_SEL_MASK_SFT,
+ get_etdm_inconn_rate(rate) <<
+ OUT_REG_RELATCH_EN_SEL_SFT);
+ /* 5: TDM Mode */
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+ OUT_REG_FMT_MASK_SFT,
+ 0x0 << OUT_REG_FMT_SFT);
+
+ /* APLL */
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+ OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT,
+ ETDM_RELATCH_SEL_APLL
+ << OUT_REG_RELATCH_DOMAIN_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+ OUT_REG_BIT_LENGTH_MASK_SFT,
+ get_etdm_lrck_width(format) <<
+ OUT_REG_BIT_LENGTH_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT1_CON0,
+ OUT_REG_WORD_LENGTH_MASK_SFT,
+ get_etdm_wlen(format) <<
+ OUT_REG_WORD_LENGTH_SFT);
+
+ /* ---etdm cowork --- */
+ regmap_update_bits(afe->regmap, ETDM_0_3_COWORK_CON0,
+ ETDM_OUT1_SLAVE_SEL_MASK_SFT,
+ ETDM_SLAVE_SEL_ETDMIN1_MASTER
+ << ETDM_OUT1_SLAVE_SEL_SFT);
+ break;
+ case MT8189_DAI_I2S_OUT4:
+ /* ---etdm out --- */
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON1,
+ OUT_REG_INITIAL_COUNT_MASK_SFT,
+ 0x5 << OUT_REG_INITIAL_COUNT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON1,
+ OUT_REG_INITIAL_POINT_MASK_SFT,
+ 0x6 << OUT_REG_INITIAL_POINT_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON1,
+ OUT_REG_LRCK_RESET_MASK_SFT,
+ 0x1 << OUT_REG_LRCK_RESET_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON4,
+ OUT_REG_FS_TIMING_SEL_MASK_SFT,
+ get_etdm_rate(rate) <<
+ OUT_REG_FS_TIMING_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON4,
+ OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT,
+ ETDM_CLK_SOURCE_APLL <<
+ OUT_REG_CLOCK_SOURCE_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON4,
+ OUT_REG_RELATCH_EN_SEL_MASK_SFT,
+ get_etdm_inconn_rate(rate) <<
+ OUT_REG_RELATCH_EN_SEL_SFT);
+ /* 5: TDM Mode */
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+ OUT_REG_FMT_MASK_SFT,
+ 0x0 << OUT_REG_FMT_SFT);
+
+ /* APLL */
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+ OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT,
+ ETDM_RELATCH_SEL_APLL
+ << OUT_REG_RELATCH_DOMAIN_SEL_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+ OUT_REG_BIT_LENGTH_MASK_SFT,
+ get_etdm_lrck_width(format) <<
+ OUT_REG_BIT_LENGTH_SFT);
+ regmap_update_bits(afe->regmap, ETDM_OUT4_CON0,
+ OUT_REG_WORD_LENGTH_MASK_SFT,
+ get_etdm_wlen(format) <<
+ OUT_REG_WORD_LENGTH_SFT);
+ break;
+ default:
+ dev_err(afe->dev, "%s(), id %d not support\n",
+ __func__, i2s_id);
+ return -EINVAL;
+ }
+
+ /* set share i2s */
+ if (i2s_priv->share_i2s_id >= 0) {
+ ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_i2s_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);
+
+ return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+ int apll;
+ int apll_rate;
+
+ if (dai->id >= MT8189_DAI_NUM || dai->id < 0 ||
+ dir != SND_SOC_CLOCK_OUT)
+ return -EINVAL;
+
+ i2s_priv = afe_priv->dai_priv[dai->id];
+ if (!i2s_priv)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ apll = mt8189_get_apll_by_rate(afe, freq);
+ apll_rate = mt8189_get_apll_rate(afe, apll);
+
+ if (freq > apll_rate || apll_rate % freq) {
+ dev_err(afe->dev, "%s(), freq %d, apll_rate %d\n",
+ __func__, freq, apll_rate);
+ return -EINVAL;
+ }
+
+ i2s_priv->mclk_rate = freq;
+ i2s_priv->mclk_apll = apll;
+
+ if (i2s_priv->share_i2s_id > 0) {
+ struct mtk_afe_i2s_priv *share_i2s_priv;
+
+ share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+ if (!share_i2s_priv)
+ return -EINVAL;
+
+ share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+ share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+ .hw_params = mtk_dai_i2s_hw_params,
+ .set_sysclk = mtk_dai_i2s_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_192000)
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define MT8189_I2S_DAI(_name, _id, max_ch, dir) \
+{ \
+ .name = #_name, \
+ .id = _id, \
+ .dir = { \
+ .stream_name = #_name, \
+ .channels_min = 1, \
+ .channels_max = max_ch, \
+ .rates = MTK_ETDM_RATES, \
+ .formats = MTK_ETDM_FORMATS, \
+ }, \
+ .ops = &mtk_dai_i2s_ops, \
+}
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+ /* capture */
+ MT8189_I2S_DAI(I2SIN0, MT8189_DAI_I2S_IN0, 2, capture),
+ MT8189_I2S_DAI(I2SIN1, MT8189_DAI_I2S_IN1, 2, capture),
+ /* playback */
+ MT8189_I2S_DAI(I2SOUT0, MT8189_DAI_I2S_OUT0, 2, playback),
+ MT8189_I2S_DAI(I2SOUT1, MT8189_DAI_I2S_OUT1, 2, playback),
+ MT8189_I2S_DAI(I2SOUT4, MT8189_DAI_I2S_OUT4, 8, playback),
+};
+
+static const struct mtk_afe_i2s_priv mt8189_i2s_priv[DAI_I2S_NUM] = {
+ [DAI_I2SIN0] = {
+ .id = MT8189_DAI_I2S_IN0,
+ .mclk_id = MT8189_I2SIN0_MCK,
+ .share_property_name = "i2sin0-share",
+ .share_i2s_id = MT8189_DAI_I2S_OUT0,
+ },
+ [DAI_I2SIN1] = {
+ .id = MT8189_DAI_I2S_IN1,
+ .mclk_id = MT8189_I2SIN1_MCK,
+ .share_property_name = "i2sin1-share",
+ .share_i2s_id = MT8189_DAI_I2S_OUT1,
+ },
+ [DAI_I2SOUT0] = {
+ .id = MT8189_DAI_I2S_OUT0,
+ .mclk_id = MT8189_I2SOUT0_MCK,
+ .share_property_name = "i2sout0-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SOUT1] = {
+ .id = MT8189_DAI_I2S_OUT1,
+ .mclk_id = MT8189_I2SOUT1_MCK,
+ .share_property_name = "i2sout1-share",
+ .share_i2s_id = -1,
+ },
+ [DAI_I2SOUT4] = {
+ .id = MT8189_DAI_I2S_OUT4,
+ .mclk_id = MT8189_I2SIN1_MCK,
+ .share_property_name = "i2sout4-share",
+ .share_i2s_id = -1,
+ },
+};
+
+static int mt8189_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ const struct device_node *of_node = afe->dev->of_node;
+
+ for (int i = 0; i < DAI_I2S_NUM; i++) {
+ const char *of_str;
+ struct mtk_afe_i2s_priv *i2s_priv =
+ afe_priv->dai_priv[mt8189_i2s_priv[i].id];
+ const char *property_name =
+ mt8189_i2s_priv[i].share_property_name;
+
+ if (of_property_read_string(of_node, property_name, &of_str))
+ continue;
+
+ i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str);
+ }
+
+ return 0;
+}
+
+static int init_i2s_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_priv;
+
+ for (int i = 0; i < DAI_I2S_NUM; i++) {
+ int id = mt8189_i2s_priv[i].id;
+ size_t size = sizeof(struct mtk_afe_i2s_priv);
+
+ if (id >= MT8189_DAI_NUM || id < 0)
+ return -EINVAL;
+
+ i2s_priv = devm_kzalloc(afe->dev, size, GFP_KERNEL);
+ if (!i2s_priv)
+ return -ENOMEM;
+
+ memcpy(i2s_priv, &mt8189_i2s_priv[i], size);
+
+ afe_priv->dai_priv[id] = i2s_priv;
+ }
+
+ return 0;
+}
+
+int mt8189_dai_i2s_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+ int ret;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ dai->dai_drivers = mtk_dai_i2s_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+ dai->controls = mtk_dai_i2s_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+ dai->dapm_widgets = mtk_dai_i2s_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+ dai->dapm_routes = mtk_dai_i2s_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+ /* set all dai i2s private data */
+ ret = init_i2s_priv_data(afe);
+ if (ret)
+ return ret;
+
+ /* parse share i2s */
+ ret = mt8189_dai_i2s_get_share(afe);
+ if (ret)
+ return ret;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-pcm.c b/sound/soc/mediatek/mt8189/mt8189-dai-pcm.c
new file mode 100644
index 000000000000..21317c0413e5
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-pcm.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI I2S Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+
+#include <sound/pcm_params.h>
+
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+#include "mt8189-afe-clk.h"
+
+enum AUD_TX_LCH_RPT {
+ AUD_TX_LCH_RPT_NO_REPEAT,
+ AUD_TX_LCH_RPT_REPEAT
+};
+
+enum AUD_VBT_16K_MODE {
+ AUD_VBT_16K_MODE_DISABLE,
+ AUD_VBT_16K_MODE_ENABLE
+};
+
+enum AUD_EXT_MODEM {
+ AUD_EXT_MODEM_SELECT_INTERNAL,
+ AUD_EXT_MODEM_SELECT_EXTERNAL
+};
+
+enum AUD_PCM_SYNC_TYPE {
+ /* bck sync length = 1 */
+ AUD_PCM_ONE_BCK_CYCLE_SYNC,
+ /* bck sync length = PCM_INTF_CON1[9:13] */
+ AUD_PCM_EXTENDED_BCK_CYCLE_SYNC
+};
+
+enum AUD_BT_MODE {
+ AUD_BT_MODE_DUAL_MIC_ON_TX,
+ AUD_BT_MODE_SINGLE_MIC_ON_TX
+};
+
+enum AUD_PCM_AFIFO_SRC {
+ /* slave mode & external modem uses different crystal */
+ AUD_PCM_AFIFO_ASRC,
+ /* slave mode & external modem uses the same crystal */
+ AUD_PCM_AFIFO_AFIFO
+};
+
+enum AUD_PCM_CLOCK_SOURCE {
+ AUD_PCM_CLOCK_MASTER_MODE,
+ AUD_PCM_CLOCK_SLAVE_MODE
+};
+
+enum AUD_PCM_WLEN {
+ AUD_PCM_WLEN_PCM_32_BCK_CYCLES,
+ AUD_PCM_WLEN_PCM_64_BCK_CYCLES
+};
+
+enum AUD_PCM_MODE {
+ AUD_PCM_MODE_PCM_MODE_8K,
+ AUD_PCM_MODE_PCM_MODE_16K,
+ AUD_PCM_MODE_PCM_MODE_32K,
+ AUD_PCM_MODE_PCM_MODE_48K
+};
+
+enum AUD_PCM_FMT {
+ AUD_PCM_FMT_I2S,
+ AUD_PCM_FMT_EIAJ,
+ AUD_PCM_FMT_PCM_MODE_A,
+ AUD_PCM_FMT_PCM_MODE_B
+};
+
+enum AUD_BCLK_OUT_INV {
+ AUD_BCLK_OUT_INV_NO_INVERSE,
+ AUD_BCLK_OUT_INV_INVERSE
+};
+
+enum AUD_PCM_EN {
+ AUD_PCM_EN_DISABLE,
+ AUD_PCM_EN_ENABLE
+};
+
+enum AUD_PCM1_1X_EN_DOMAIN {
+ HOPPING_26M,
+ APLL,
+ SLAVE = 6
+};
+
+enum AUD_PCM1_1X_EN_SLAVE_MODE {
+ PCM0_SLAVE_1X_EN,
+ PCM1_SLAVE_1X_EN
+};
+
+enum {
+ PCM_8K,
+ PCM_16K = 4,
+ PCM_32K = 8,
+ PCM_48K = 10
+};
+
+static unsigned int pcm_1x_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return PCM_8K;
+ case 16000:
+ return PCM_16K;
+ case 32000:
+ return PCM_32K;
+ case 48000:
+ return PCM_48K;
+ default:
+ dev_warn(dev, "rate %u invalid, use %d!!!\n",
+ rate, PCM_48K);
+ return PCM_48K;
+ }
+}
+
+static unsigned int pcm_rate_transform(struct device *dev,
+ unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_PCM_RATE_8K;
+ case 16000:
+ return MTK_AFE_PCM_RATE_16K;
+ case 32000:
+ return MTK_AFE_PCM_RATE_32K;
+ case 48000:
+ return MTK_AFE_PCM_RATE_48K;
+ default:
+ dev_warn(dev, "rate %u invalid, use %d\n",
+ rate, MTK_AFE_PCM_RATE_48K);
+ return MTK_AFE_PCM_RATE_48K;
+ }
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_0_playback_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN096_0,
+ I_ADDA_UL_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN096_1,
+ I_DL2_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN096_1,
+ I_DL_24CH_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_0_playback_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN097_0,
+ I_ADDA_UL_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN097_1,
+ I_DL2_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH2", AFE_CONN097_1,
+ I_DL_24CH_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_0_playback_ch4_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH1", AFE_CONN099_4,
+ I_I2SIN1_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I2SIN1_CH2", AFE_CONN099_4,
+ I_I2SIN1_CH2, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL0_CH1", AFE_CONN099_1,
+ I_DL0_CH1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("DL_24CH_CH1", AFE_CONN099_1,
+ I_DL_24CH_CH1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("PCM_0_PB_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_0_playback_ch1_mix,
+ ARRAY_SIZE(mtk_pcm_0_playback_ch1_mix)),
+ SND_SOC_DAPM_MIXER("PCM_0_PB_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_0_playback_ch2_mix,
+ ARRAY_SIZE(mtk_pcm_0_playback_ch2_mix)),
+ SND_SOC_DAPM_MIXER("PCM_0_PB_CH4", SND_SOC_NOPM, 0, 0,
+ mtk_pcm_0_playback_ch4_mix,
+ ARRAY_SIZE(mtk_pcm_0_playback_ch4_mix)),
+
+ SND_SOC_DAPM_SUPPLY("PCM_0_EN",
+ AFE_PCM0_INTF_CON0, PCM0_EN_SFT, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("PCM0_CG", AUDIO_TOP_CON0, PDN_PCM0_SFT, 1,
+ NULL, 0),
+
+ SND_SOC_DAPM_INPUT("AFE_PCM_INPUT"),
+ SND_SOC_DAPM_OUTPUT("AFE_PCM_OUTPUT"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"PCM 0 Playback", NULL, "PCM_0_PB_CH1"},
+ {"PCM 0 Playback", NULL, "PCM_0_PB_CH2"},
+ {"PCM 0 Playback", NULL, "PCM_0_PB_CH4"},
+
+ {"PCM 0 Playback", NULL, "PCM_0_EN"},
+ {"PCM 0 Capture", NULL, "PCM_0_EN"},
+ {"PCM 0 Playback", NULL, "PCM0_CG"},
+ {"PCM 0 Capture", NULL, "PCM0_CG"},
+
+ {"AFE_PCM_OUTPUT", NULL, "PCM 0 Playback"},
+ {"PCM 0 Capture", NULL, "AFE_PCM_INPUT"},
+
+ {"PCM_0_PB_CH1", "DL2_CH1", "DL2"},
+ {"PCM_0_PB_CH2", "DL2_CH2", "DL2"},
+ {"PCM_0_PB_CH4", "DL0_CH1", "DL0"},
+
+ {"PCM_0_PB_CH1", "DL_24CH_CH1", "DL_24CH"},
+ {"PCM_0_PB_CH2", "DL_24CH_CH2", "DL_24CH"},
+ {"PCM_0_PB_CH4", "DL_24CH_CH1", "DL_24CH"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_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);
+ unsigned int rate = params_rate(params);
+ unsigned int rate_reg = pcm_rate_transform(afe->dev, rate);
+ unsigned int x_rate_reg = pcm_1x_rate_transform(afe->dev, rate);
+ unsigned int pcm_con0;
+ unsigned int pcm_con1;
+ unsigned int playback_active = 0;
+ unsigned int capture_active = 0;
+ struct snd_soc_dapm_widget *playback_widget =
+ snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_PLAYBACK);
+ struct snd_soc_dapm_widget *capture_widget =
+ snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_CAPTURE);
+
+ if (playback_widget)
+ playback_active = playback_widget->active;
+ if (capture_widget)
+ capture_active = capture_widget->active;
+ dev_dbg(afe->dev,
+ "id %d, stream %d, rate %d, rate_reg %d, active p %d, c %d\n",
+ dai->id, substream->stream, rate, rate_reg,
+ playback_active, capture_active);
+
+ if (playback_active || capture_active)
+ return 0;
+ switch (dai->id) {
+ case MT8189_DAI_PCM_0:
+ pcm_con0 = AUD_BCLK_OUT_INV_NO_INVERSE << PCM0_BCLK_OUT_INV_SFT;
+ pcm_con0 |= AUD_TX_LCH_RPT_NO_REPEAT << PCM0_TX_LCH_RPT_SFT;
+ pcm_con0 |= AUD_VBT_16K_MODE_DISABLE << PCM0_VBT_16K_MODE_SFT;
+ pcm_con0 |= 0 << PCM0_SYNC_LENGTH_SFT;
+ pcm_con0 |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM0_SYNC_TYPE_SFT;
+ pcm_con0 |= AUD_PCM_AFIFO_AFIFO << PCM0_BYP_ASRC_SFT;
+ pcm_con0 |= AUD_PCM_CLOCK_MASTER_MODE << PCM0_SLAVE_SFT;
+ pcm_con0 |= rate_reg << PCM0_MODE_SFT;
+ pcm_con0 |= AUD_PCM_FMT_I2S << PCM0_FMT_SFT;
+
+ pcm_con1 = AUD_EXT_MODEM_SELECT_INTERNAL << PCM0_EXT_MODEM_SFT;
+ pcm_con1 |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM0_BT_MODE_SFT;
+ pcm_con1 |= HOPPING_26M << PCM0_1X_EN_DOMAIN_SFT;
+ pcm_con1 |= x_rate_reg << PCM0_1X_EN_MODE_SFT;
+
+ regmap_update_bits(afe->regmap, AFE_PCM0_INTF_CON0,
+ ~(unsigned int)PCM0_EN_MASK_SFT, pcm_con0);
+ regmap_update_bits(afe->regmap, AFE_PCM0_INTF_CON1,
+ AFE_PCM0_INTF_CON1_MASK_MON_MASK_SFT,
+ pcm_con1);
+ break;
+ default:
+ dev_err(afe->dev, "%s(), id %d not support\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+ .hw_params = mtk_dai_pcm_hw_params,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM 0",
+ .id = MT8189_DAI_PCM_0,
+ .playback = {
+ .stream_name = "PCM 0 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "PCM 0 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_dai_pcm_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+int mt8189_dai_pcm_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;
+
+ dai->dai_drivers = mtk_dai_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c b/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
new file mode 100644
index 000000000000..5d68a55ccc45
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI TDM Control
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/regmap.h>
+
+#include <sound/pcm_params.h>
+
+#include "mt8189-afe-clk.h"
+#include "mt8189-afe-common.h"
+#include "mt8189-interconnection.h"
+
+#define DPTX_CH_EN_MASK_2CH (0x3)
+#define DPTX_CH_EN_MASK_4CH (0xf)
+#define DPTX_CH_EN_MASK_6CH (0x3f)
+#define DPTX_CH_EN_MASK_8CH (0xff)
+
+enum {
+ SUPPLY_SEQ_APLL,
+ SUPPLY_SEQ_TDM_MCK_EN,
+ SUPPLY_SEQ_TDM_BCK_EN,
+ SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+ SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+ SUPPLY_SEQ_TDM_CG_EN,
+};
+
+enum {
+ TDM_WLEN_8_BIT,
+ TDM_WLEN_16_BIT,
+ TDM_WLEN_24_BIT,
+ TDM_WLEN_32_BIT,
+};
+
+enum {
+ TDM_CHANNEL_BCK_16,
+ TDM_CHANNEL_BCK_24,
+ TDM_CHANNEL_BCK_32
+};
+
+enum {
+ TDM_CHANNEL_NUM_2,
+ TDM_CHANNEL_NUM_4,
+ TDM_CHANNEL_NUM_8
+};
+
+enum {
+ TDM_CH_START_O30_O31,
+ TDM_CH_START_O32_O33,
+ TDM_CH_START_O34_O35,
+ TDM_CH_START_O36_O37,
+ TDM_CH_ZERO,
+};
+
+enum {
+ DPTX_CHANNEL_2,
+ DPTX_CHANNEL_8,
+};
+
+enum {
+ DPTX_WLEN_24_BIT,
+ DPTX_WLEN_16_BIT,
+};
+
+struct mtk_afe_tdm_priv {
+ int bck_id;
+ int bck_rate;
+
+ int mclk_id;
+ int mclk_multiple; /* according to sample rate */
+ int mclk_rate;
+ int mclk_apll;
+};
+
+static unsigned int get_tdm_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
+}
+
+static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
+}
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch(unsigned int ch)
+{
+ switch (ch) {
+ case 1:
+ case 2:
+ return TDM_CHANNEL_NUM_2;
+ case 3:
+ case 4:
+ return TDM_CHANNEL_NUM_4;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ default:
+ return TDM_CHANNEL_NUM_8;
+ }
+}
+
+static unsigned int get_dptx_ch_enable_mask(unsigned int ch)
+{
+ switch (ch) {
+ case 1:
+ case 2:
+ return DPTX_CH_EN_MASK_2CH;
+ case 3:
+ case 4:
+ return DPTX_CH_EN_MASK_4CH;
+ case 5:
+ case 6:
+ return DPTX_CH_EN_MASK_6CH;
+ case 7:
+ case 8:
+ return DPTX_CH_EN_MASK_8CH;
+ default:
+ return DPTX_CH_EN_MASK_2CH;
+ }
+}
+
+static unsigned int get_dptx_ch(unsigned int ch)
+{
+ if (ch == 2)
+ return DPTX_CHANNEL_2;
+
+ return DPTX_CHANNEL_8;
+}
+
+static unsigned int get_dptx_wlen(snd_pcm_format_t format)
+{
+ return snd_pcm_format_physical_width(format) <= 16 ?
+ DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT;
+}
+
+/* interconnection */
+enum {
+ HDMI_CONN_CH0,
+ HDMI_CONN_CH1,
+ HDMI_CONN_CH2,
+ HDMI_CONN_CH3,
+ HDMI_CONN_CH4,
+ HDMI_CONN_CH5,
+ HDMI_CONN_CH6,
+ HDMI_CONN_CH7,
+};
+
+static const char *const hdmi_conn_mux_map[] = {
+ "CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7",
+};
+
+static int hdmi_conn_mux_map_value[] = {
+ HDMI_CONN_CH0, HDMI_CONN_CH1, HDMI_CONN_CH2, HDMI_CONN_CH3,
+ HDMI_CONN_CH4, HDMI_CONN_CH5, HDMI_CONN_CH6, HDMI_CONN_CH7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_0_SFT,
+ HDMI_O_0_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_1_SFT,
+ HDMI_O_1_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_2_SFT,
+ HDMI_O_2_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_3_SFT,
+ HDMI_O_3_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_4_SFT,
+ HDMI_O_4_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_5_SFT,
+ HDMI_O_5_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_6_SFT,
+ HDMI_O_6_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
+ AFE_HDMI_CONN0,
+ HDMI_O_7_SFT,
+ HDMI_O_7_MASK,
+ hdmi_conn_mux_map,
+ hdmi_conn_mux_map_value);
+
+static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = {
+ SOC_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum),
+ SOC_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum),
+ SOC_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum),
+ SOC_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum),
+ SOC_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum),
+ SOC_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum),
+ SOC_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum),
+ SOC_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum),
+};
+
+static const char *const tdm_out_demux_texts[] = {
+ "NONE", "TDMOUT", "DPTXOUT",
+};
+
+static SOC_ENUM_SINGLE_DECL(tdm_out_demux_enum,
+ SND_SOC_NOPM,
+ 0,
+ tdm_out_demux_texts);
+
+static const struct snd_kcontrol_new tdm_out_demux_control =
+ SOC_DAPM_ENUM("TDM Playback Route", tdm_out_demux_enum);
+
+static int get_tdm_id_by_name(const char *name)
+{
+ if (strstr(name, "DPTX"))
+ return MT8189_DAI_TDM_DPTX;
+
+ return MT8189_DAI_TDM;
+}
+
+static int mtk_tdm_bck_en_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, bck: %d\n",
+ w->name, event, dai_id, tdm_priv->bck_rate);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8189_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mt8189_mck_disable(afe, tdm_priv->bck_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_tdm_mck_en_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(w->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+ dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, mclk %d\n",
+ w->name, event, dai_id, tdm_priv->mclk_rate);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mt8189_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tdm_priv->mclk_rate = 0;
+ mt8189_mck_disable(afe, tdm_priv->mclk_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+ SND_SOC_DAPM_DEMUX("TDM Playback Route", SND_SOC_NOPM, 0, 0,
+ &tdm_out_demux_control),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_bck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_mck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_BCK", SUPPLY_SEQ_TDM_DPTX_BCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_bck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_MCK", SUPPLY_SEQ_TDM_DPTX_MCK_EN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_tdm_mck_en_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SUPPLY_S("TDM_CG", SUPPLY_SEQ_TDM_CG_EN,
+ AUDIO_TOP_CON2, PDN_TDM_OUT_SFT, 1,
+ NULL, 0),
+};
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = get_tdm_id_by_name(sink->name);
+ struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+ int cur_apll;
+
+ /* which apll */
+ cur_apll = mt8189_get_apll_by_name(afe, source->name);
+
+ return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+ {"TDM Playback Route", NULL, "HDMI"},
+
+ {"TDM", "TDMOUT", "TDM Playback Route"},
+ {"TDM", NULL, "TDM_BCK"},
+ {"TDM", NULL, "TDM_CG"},
+
+ {"TDM_DPTX", "DPTXOUT", "TDM Playback Route"},
+ {"TDM_DPTX", NULL, "TDM_DPTX_BCK"},
+ {"TDM_DPTX", NULL, "TDM_CG"},
+
+ {"TDM_BCK", NULL, "TDM_MCK"},
+ {"TDM_DPTX_BCK", NULL, "TDM_DPTX_MCK"},
+ {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_DPTX_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+ {"TDM_DPTX_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+ struct mtk_afe_tdm_priv *tdm_priv,
+ int freq)
+{
+ int apll;
+ int apll_rate;
+
+ apll = mt8189_get_apll_by_rate(afe, freq);
+ apll_rate = mt8189_get_apll_rate(afe, apll);
+
+ if (freq > apll_rate)
+ return -EINVAL;
+
+ if (apll_rate % freq != 0)
+ return -EINVAL;
+
+ tdm_priv->mclk_rate = freq;
+ tdm_priv->mclk_apll = apll;
+
+ return 0;
+}
+
+static int mtk_dai_tdm_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 mt8189_afe_private *afe_priv = afe->platform_priv;
+ int tdm_id = dai->id;
+ struct mtk_afe_tdm_priv *tdm_priv;
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ snd_pcm_format_t format = params_format(params);
+ unsigned int tdm_con;
+
+ if (tdm_id >= MT8189_DAI_NUM || tdm_id < 0)
+ return -EINVAL;
+
+ tdm_priv = afe_priv->dai_priv[tdm_id];
+
+ /* calculate mclk_rate, if not set explicitly */
+ if (!tdm_priv->mclk_rate) {
+ tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
+ mtk_dai_tdm_cal_mclk(afe,
+ tdm_priv,
+ tdm_priv->mclk_rate);
+ }
+
+ /* calculate bck */
+ tdm_priv->bck_rate = rate *
+ channels *
+ snd_pcm_format_physical_width(format);
+
+ if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
+ return -EINVAL;
+
+ if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "id %d, rate %d, ch %d, fmt %d, mclk %d, bck %d\n",
+ tdm_id, rate, channels, format,
+ tdm_priv->mclk_rate, tdm_priv->bck_rate);
+
+ /* set tdm */
+ tdm_con = 1 << LEFT_ALIGN_SFT;
+ tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
+ tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT;
+ tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
+ tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
+ regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
+
+ /* set dptx */
+ if (tdm_id == MT8189_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_CHANNEL_ENABLE_MASK_SFT,
+ get_dptx_ch_enable_mask(channels) <<
+ DPTX_CHANNEL_ENABLE_SFT);
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_CHANNEL_NUMBER_MASK_SFT,
+ get_dptx_ch(channels) <<
+ DPTX_CHANNEL_NUMBER_SFT);
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_16BIT_MASK_SFT,
+ get_dptx_wlen(format) << DPTX_16BIT_SFT);
+ }
+ switch (channels) {
+ case 1:
+ case 2:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 3:
+ case 4:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 5:
+ case 6:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ case 7:
+ case 8:
+ tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
+ tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
+ tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
+ tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
+ break;
+ default:
+ tdm_con = 0;
+ }
+ regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_CH_NUM_MASK_SFT,
+ channels << HDMI_CH_NUM_SFT);
+
+ return 0;
+}
+
+static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int tdm_id = dai->id;
+
+ dev_dbg(afe->dev, "%s(), cmd %d, tdm_id %d\n", __func__, cmd, tdm_id);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* enable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_OUT_ON_MASK_SFT,
+ 0x1 << HDMI_OUT_ON_SFT);
+
+ /* enable dptx */
+ if (tdm_id == MT8189_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_ON_MASK_SFT, 0x1 <<
+ DPTX_ON_SFT);
+ }
+
+ /* enable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+ TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* disable tdm */
+ regmap_update_bits(afe->regmap, AFE_TDM_CON1,
+ TDM_EN_MASK_SFT, 0);
+
+ /* disable dptx */
+ if (tdm_id == MT8189_DAI_TDM_DPTX) {
+ regmap_update_bits(afe->regmap, AFE_DPTX_CON,
+ DPTX_ON_MASK_SFT, 0);
+ }
+
+ /* disable Out control */
+ regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+ HDMI_OUT_ON_MASK_SFT, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ if (dai->id >= MT8189_DAI_NUM || dai->id < 0)
+ return -EINVAL;
+
+ tdm_priv = afe_priv->dai_priv[dai->id];
+
+ if (!tdm_priv)
+ return -EINVAL;
+
+ if (dir != SND_SOC_CLOCK_OUT)
+ return -EINVAL;
+
+ dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+ return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+ .hw_params = mtk_dai_tdm_hw_params,
+ .trigger = mtk_dai_tdm_trigger,
+ .set_sysclk = mtk_dai_tdm_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+ {
+ .name = "TDM",
+ .id = MT8189_DAI_TDM,
+ .playback = {
+ .stream_name = "TDM",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+ {
+ .name = "TDM_DPTX",
+ .id = MT8189_DAI_TDM_DPTX,
+ .playback = {
+ .stream_name = "TDM_DPTX",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = MTK_TDM_RATES,
+ .formats = MTK_TDM_FORMATS,
+ },
+ .ops = &mtk_dai_tdm_ops,
+ },
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe,
+ int id)
+{
+ struct mtk_afe_tdm_priv *tdm_priv;
+
+ tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+ GFP_KERNEL);
+ if (!tdm_priv)
+ return NULL;
+
+ if (id == MT8189_DAI_TDM_DPTX)
+ tdm_priv->mclk_multiple = 256;
+ else
+ tdm_priv->mclk_multiple = 128;
+
+ tdm_priv->bck_id = MT8189_TDMOUT_BCK;
+ tdm_priv->mclk_id = MT8189_TDMOUT_MCK;
+
+ return tdm_priv;
+}
+
+int mt8189_dai_tdm_register(struct mtk_base_afe *afe)
+{
+ struct mt8189_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv;
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ dai->dai_drivers = mtk_dai_tdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+ dai->controls = mtk_dai_tdm_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
+ dai->dapm_widgets = mtk_dai_tdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+ dai->dapm_routes = mtk_dai_tdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+ tdm_priv = init_tdm_priv_data(afe, MT8189_DAI_TDM);
+ if (!tdm_priv)
+ return -ENOMEM;
+
+ tdm_dptx_priv = init_tdm_priv_data(afe, MT8189_DAI_TDM_DPTX);
+ if (!tdm_dptx_priv)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ afe_priv->dai_priv[MT8189_DAI_TDM] = tdm_priv;
+ afe_priv->dai_priv[MT8189_DAI_TDM_DPTX] = tdm_dptx_priv;
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8189/mt8189-interconnection.h b/sound/soc/mediatek/mt8189/mt8189-interconnection.h
new file mode 100644
index 000000000000..a244a2599fa2
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-interconnection.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Mediatek MT8189 audio driver interconnection definition
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8189_INTERCONNECTION_H_
+#define _MT8189_INTERCONNECTION_H_
+
+/* in port define */
+#define I_CONNSYS_I2S_CH1 0
+#define I_CONNSYS_I2S_CH2 1
+#define I_GAIN0_OUT_CH1 6
+#define I_GAIN0_OUT_CH2 7
+#define I_GAIN1_OUT_CH1 8
+#define I_GAIN1_OUT_CH2 9
+#define I_GAIN2_OUT_CH1 10
+#define I_GAIN2_OUT_CH2 11
+#define I_GAIN3_OUT_CH1 12
+#define I_GAIN3_OUT_CH2 13
+#define I_STF_CH1 14
+#define I_ADDA_UL_CH1 16
+#define I_ADDA_UL_CH2 17
+#define I_ADDA_UL_CH3 18
+#define I_ADDA_UL_CH4 19
+#define I_UL_PROX_CH1 20
+#define I_UL_PROX_CH2 21
+#define I_ADDA_UL_CH5 24
+#define I_ADDA_UL_CH6 25
+#define I_DMIC0_CH1 28
+#define I_DMIC0_CH2 29
+#define I_DMIC1_CH1 30
+#define I_DMIC1_CH2 31
+
+/* in port define >= 32 */
+#define I_32_OFFSET 32
+#define I_DL0_CH1 (32 - I_32_OFFSET)
+#define I_DL0_CH2 (33 - I_32_OFFSET)
+#define I_DL1_CH1 (34 - I_32_OFFSET)
+#define I_DL1_CH2 (35 - I_32_OFFSET)
+#define I_DL2_CH1 (36 - I_32_OFFSET)
+#define I_DL2_CH2 (37 - I_32_OFFSET)
+#define I_DL3_CH1 (38 - I_32_OFFSET)
+#define I_DL3_CH2 (39 - I_32_OFFSET)
+#define I_DL4_CH1 (40 - I_32_OFFSET)
+#define I_DL4_CH2 (41 - I_32_OFFSET)
+#define I_DL5_CH1 (42 - I_32_OFFSET)
+#define I_DL5_CH2 (43 - I_32_OFFSET)
+#define I_DL6_CH1 (44 - I_32_OFFSET)
+#define I_DL6_CH2 (45 - I_32_OFFSET)
+#define I_DL7_CH1 (46 - I_32_OFFSET)
+#define I_DL7_CH2 (47 - I_32_OFFSET)
+#define I_DL8_CH1 (48 - I_32_OFFSET)
+#define I_DL8_CH2 (49 - I_32_OFFSET)
+#define I_DL_24CH_CH1 (54 - I_32_OFFSET)
+#define I_DL_24CH_CH2 (55 - I_32_OFFSET)
+#define I_DL_24CH_CH3 (56 - I_32_OFFSET)
+#define I_DL_24CH_CH4 (57 - I_32_OFFSET)
+#define I_DL_24CH_CH5 (58 - I_32_OFFSET)
+#define I_DL_24CH_CH6 (59 - I_32_OFFSET)
+#define I_DL_24CH_CH7 (60 - I_32_OFFSET)
+#define I_DL_24CH_CH8 (61 - I_32_OFFSET)
+
+/* in port define >= 64 */
+#define I_64_OFFSET 64
+#define I_DL23_CH1 (78 - I_64_OFFSET)
+#define I_DL23_CH2 (79 - I_64_OFFSET)
+#define I_DL24_CH1 (80 - I_64_OFFSET)
+#define I_DL24_CH2 (81 - I_64_OFFSET)
+#define I_DL25_CH1 (82 - I_64_OFFSET)
+#define I_DL25_CH2 (83 - I_64_OFFSET)
+
+/* in port define >= 128 */
+#define I_128_OFFSET 128
+#define I_PCM_0_CAP_CH1 (130 - I_128_OFFSET)
+#define I_PCM_0_CAP_CH2 (131 - I_128_OFFSET)
+#define I_I2SIN0_CH1 (134 - I_128_OFFSET)
+#define I_I2SIN0_CH2 (135 - I_128_OFFSET)
+#define I_I2SIN1_CH1 (136 - I_128_OFFSET)
+#define I_I2SIN1_CH2 (137 - I_128_OFFSET)
+
+/* in port define >= 192 */
+#define I_192_OFFSET 192
+#define I_SRC_0_OUT_CH1 (198 - I_192_OFFSET)
+#define I_SRC_0_OUT_CH2 (199 - I_192_OFFSET)
+#define I_SRC_1_OUT_CH1 (200 - I_192_OFFSET)
+#define I_SRC_1_OUT_CH2 (201 - I_192_OFFSET)
+#define I_SRC_2_OUT_CH1 (202 - I_192_OFFSET)
+#define I_SRC_2_OUT_CH2 (203 - I_192_OFFSET)
+#define I_SRC_3_OUT_CH1 (204 - I_192_OFFSET)
+#define I_SRC_3_OUT_CH2 (205 - I_192_OFFSET)
+#define I_SRC_4_OUT_CH1 (206 - I_192_OFFSET)
+#define I_SRC_4_OUT_CH2 (207 - I_192_OFFSET)
+
+#endif
diff --git a/sound/soc/mediatek/mt8189/mt8189-nau8825.c b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
new file mode 100644
index 000000000000..5ef15ec988be
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
@@ -0,0 +1,1178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt8189-nau8825.c -- mt8189 nau8825 ALSA SoC machine driver
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+
+#include "mt8189-afe-common.h"
+
+#include "../common/mtk-soc-card.h"
+#include "../common/mtk-soundcard-driver.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+#include "../../codecs/cs35l41.h"
+#include "../../codecs/nau8825.h"
+#include "../../codecs/rt5682s.h"
+#include "../../codecs/rt5682.h"
+
+#define NAU8825_HS_PRESENT BIT(0)
+#define RT5682S_HS_PRESENT BIT(1)
+#define RT5650_HS_PRESENT BIT(2)
+#define RT5682I_HS_PRESENT BIT(3)
+#define ES8326_HS_PRESENT BIT(4)
+
+/*
+ * Nau88l25
+ */
+#define NAU8825_CODEC_DAI "nau8825-hifi"
+
+/*
+ * Rt5682s
+ */
+#define RT5682S_CODEC_DAI "rt5682s-aif1"
+
+/*
+ * Rt5650
+ */
+#define RT5650_CODEC_DAI "rt5645-aif1"
+
+/*
+ * Rt5682i
+ */
+#define RT5682I_CODEC_DAI "rt5682-aif1"
+
+/*
+ * Cs35l41
+ */
+#define CS35L41_CODEC_DAI "cs35l41-pcm"
+#define CS35L41_DEV0_NAME "cs35l41.7-0040"
+#define CS35L41_DEV1_NAME "cs35l41.7-0042"
+
+/*
+ * ES8326
+ */
+#define ES8326_CODEC_DAI "ES8326 HiFi"
+
+enum mt8189_jacks {
+ MT8189_JACK_HEADSET,
+ MT8189_JACK_DP,
+ MT8189_JACK_HDMI,
+ MT8189_JACK_MAX,
+};
+
+static struct snd_soc_jack_pin mt8189_dp_jack_pins[] = {
+ {
+ .pin = "DP",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static struct snd_soc_jack_pin mt8189_hdmi_jack_pins[] = {
+ {
+ .pin = "HDMI",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
+static struct snd_soc_jack_pin mt8189_headset_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new mt8189_dumb_spk_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget mt8189_dumb_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_widget mt8189_headset_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_kcontrol_new mt8189_headset_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget mt8189_nau8825_card_widgets[] = {
+ SND_SOC_DAPM_SINK("DP"),
+};
+
+static int mt8189_common_i2s_startup(struct snd_pcm_substream *substream)
+{
+ static const unsigned int rates[] = {
+ 48000,
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ };
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+}
+
+static int mt8189_common_i2s_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);
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 128;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(cpu_dai,
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_common_i2s_ops = {
+ .startup = mt8189_common_i2s_startup,
+ .hw_params = mt8189_common_i2s_hw_params,
+};
+
+static int mt8189_dptx_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);
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs_ratio = 256;
+ unsigned int mclk_fs = rate * mclk_fs_ratio;
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return snd_soc_dai_set_sysclk(dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_dptx_ops = {
+ .hw_params = mt8189_dptx_hw_params,
+};
+
+static int mt8189_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__);
+
+ /* fix BE i2s format to 32bit, clean param mask first */
+ snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+ 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+
+ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8189_pcm_ops = {
+ .startup = mt8189_common_i2s_startup,
+};
+
+static int mt8189_nau8825_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ unsigned int bit_width = params_width(params);
+ int clk_freq, ret;
+
+ clk_freq = rate * 2 * bit_width;
+ dev_dbg(codec_dai->dev, "clk_freq %d, rate: %d, bit_width: %d\n",
+ clk_freq, rate, bit_width);
+
+ /* Configure clock for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_BLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set BCLK clock %d\n", ret);
+ return ret;
+ }
+
+ /* Configure pll for codec */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_freq,
+ rate * 256);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set BCLK: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8189_nau8825_ops = {
+ .startup = mt8189_common_i2s_startup,
+ .hw_params = mt8189_nau8825_hw_params,
+};
+
+static int mt8189_rtxxxx_i2s_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_card *card = rtd->card;
+ 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);
+ unsigned int rate = params_rate(params);
+ int bitwidth;
+ int ret;
+
+ bitwidth = snd_pcm_format_width(params_format(params));
+ if (bitwidth < 0) {
+ dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+ return bitwidth;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+ if (ret) {
+ dev_err(card->dev, "failed to set tdm slot\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 1, rate * 32, rate * 512);
+ if (ret) {
+ dev_err(card->dev, "failed to set pll\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1, rate * 512, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(card->dev, "failed to set sysclk\n");
+ return ret;
+ }
+
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 512,
+ SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_rtxxxx_i2s_ops = {
+ .startup = mt8189_common_i2s_startup,
+ .hw_params = mt8189_rtxxxx_i2s_hw_params,
+};
+
+static int mt8189_cs35l41_i2s_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);
+ unsigned int rate = params_rate(params);
+ unsigned int mclk_fs = rate * 128;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ int clk_freq = rate * 32;
+ int rx_slot[] = {0, 1};
+ int i, ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_component_set_sysclk(codec_dai->component,
+ CS35L41_CLKID_SCLK, 0,
+ clk_freq, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "set component sysclk fail: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, CS35L41_CLKID_SCLK,
+ clk_freq, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "set sysclk fail: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, NULL,
+ 1, &rx_slot[i]);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "set channel map fail: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return snd_soc_dai_set_sysclk(cpu_dai,
+ 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_cs35l41_i2s_ops = {
+ .startup = mt8189_common_i2s_startup,
+ .hw_params = mt8189_cs35l41_i2s_hw_params,
+};
+
+static int mt8189_es8326_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 = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ unsigned int rate = params_rate(params);
+ int ret;
+
+ /* Configure MCLK for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, rate * 256, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set MCLK %d\n", ret);
+ return ret;
+ }
+
+ /* Configure MCLK for cpu */
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 256, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8189_es8326_ops = {
+ .startup = mt8189_common_i2s_startup,
+ .hw_params = mt8189_es8326_hw_params,
+};
+
+static int mt8189_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, mt8189_dumb_spk_widgets,
+ ARRAY_SIZE(mt8189_dumb_spk_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add Dumb Speaker dapm, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, mt8189_dumb_spk_controls,
+ ARRAY_SIZE(mt8189_dumb_spk_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add Dumb card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8189_dptx_codec_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[MT8189_JACK_DP];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "DP Jack", SND_JACK_LINEOUT,
+ jack, mt8189_dp_jack_pins,
+ ARRAY_SIZE(mt8189_dp_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+ __func__, component->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8189_hdmi_codec_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[MT8189_JACK_HDMI];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ jack, mt8189_hdmi_jack_pins,
+ ARRAY_SIZE(mt8189_hdmi_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "%s, new jack failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(rtd->dev, "%s, set jack failed on %s (ret=%d)\n",
+ __func__, component->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt8189_headset_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8189_JACK_HEADSET];
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ int ret;
+ int type;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, mt8189_headset_widgets,
+ ARRAY_SIZE(mt8189_headset_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add nau8825 card widget, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, mt8189_headset_controls,
+ ARRAY_SIZE(mt8189_headset_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add nau8825 card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ 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,
+ mt8189_headset_jack_pins,
+ ARRAY_SIZE(mt8189_headset_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ if (card_data->flags & ES8326_HS_PRESENT) {
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+ } else {
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ }
+
+ type = SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3;
+ ret = snd_soc_component_set_jack(component, jack, (void *)&type);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+};
+
+static void mt8189_headset_codec_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+
+ snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback0,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback1,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback3,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback4,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback5,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback6,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback7,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback8,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback23,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL23")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback24,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL24")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback25,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL25")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_24ch,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL_24CH")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture2,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture3,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture4,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture5,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture6,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture7,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture8,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL8")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture9,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL9")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture10,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL10")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture24,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL24")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture25,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL25")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_cm0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_CM0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_cm1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_CM1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_etdm_in0,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_ETDM_IN0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(capture_etdm_in1,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL_ETDM_IN1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback_hdmi,
+ DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+/* BE */
+SND_SOC_DAILINK_DEFS(ap_dmic,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(ap_dmic_ch34,
+ DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sin0,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SIN0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sin1,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SIN1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout0,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2sout1,
+ DAILINK_COMP_ARRAY(COMP_CPU("I2SOUT1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(pcm0,
+ DAILINK_COMP_ARRAY(COMP_CPU("PCM 0")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(tdm_dptx,
+ DAILINK_COMP_ARRAY(COMP_CPU("TDM_DPTX")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt8189_nau8825_dai_links[] = {
+ /* Front End DAI links */
+ {
+ .name = "DL0_FE",
+ .stream_name = "DL0 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ .dpcm_merged_format = 1,
+ SND_SOC_DAILINK_REG(playback0),
+ },
+ {
+ .name = "DL1_FE",
+ .stream_name = "DL1 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ .dpcm_merged_format = 1,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ {
+ .name = "UL0_FE",
+ .stream_name = "UL0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ .dpcm_merged_format = 1,
+ SND_SOC_DAILINK_REG(capture0),
+ },
+ {
+ .name = "UL1_FE",
+ .stream_name = "UL1 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ .dpcm_merged_format = 1,
+ SND_SOC_DAILINK_REG(capture1),
+ },
+ {
+ .name = "UL2_FE",
+ .stream_name = "UL2 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ .dpcm_merged_format = 1,
+ SND_SOC_DAILINK_REG(capture2),
+ },
+ {
+ .name = "HDMI_FE",
+ .stream_name = "HDMI Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback_hdmi),
+ },
+ {
+ .name = "DL2_FE",
+ .stream_name = "DL2 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ {
+ .name = "DL3_FE",
+ .stream_name = "DL3 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback3),
+ },
+ {
+ .name = "DL4_FE",
+ .stream_name = "DL4 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback4),
+ },
+ {
+ .name = "DL5_FE",
+ .stream_name = "DL5 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback5),
+ },
+ {
+ .name = "DL6_FE",
+ .stream_name = "DL6 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback6),
+ },
+ {
+ .name = "DL7_FE",
+ .stream_name = "DL7 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback7),
+ },
+ {
+ .name = "DL8 FE",
+ .stream_name = "DL8 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback8),
+ },
+ {
+ .name = "DL23 FE",
+ .stream_name = "DL23 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback23),
+ },
+ {
+ .name = "DL24 FE",
+ .stream_name = "DL24 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback24),
+ },
+ {
+ .name = "DL25 FE",
+ .stream_name = "DL25 Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback25),
+ },
+ {
+ .name = "DL_24CH_FE",
+ .stream_name = "DL_24CH Playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .playback_only = 1,
+ SND_SOC_DAILINK_REG(playback_24ch),
+ },
+ {
+ .name = "UL9_FE",
+ .stream_name = "UL9 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture9),
+ },
+ {
+ .name = "UL3_FE",
+ .stream_name = "UL3 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture3),
+ },
+ {
+ .name = "UL7_FE",
+ .stream_name = "UL7 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture7),
+ },
+ {
+ .name = "UL4_FE",
+ .stream_name = "UL4 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture4),
+ },
+ {
+ .name = "UL5_FE",
+ .stream_name = "UL5 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture5),
+ },
+ {
+ .name = "UL_CM0_FE",
+ .stream_name = "UL_CM0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture_cm0),
+ },
+ {
+ .name = "UL_CM1_FE",
+ .stream_name = "UL_CM1 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture_cm1),
+ },
+ {
+ .name = "UL10_FE",
+ .stream_name = "UL10 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture10),
+ },
+ {
+ .name = "UL6_FE",
+ .stream_name = "UL6 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture6),
+ },
+ {
+ .name = "UL25_FE",
+ .stream_name = "UL25 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture25),
+ },
+ {
+ .name = "UL8_FE",
+ .stream_name = "UL8 Capture_Mono_1",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture8),
+ },
+ {
+ .name = "UL24_FE",
+ .stream_name = "UL24 Capture_Mono_2",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture24),
+ },
+ {
+ .name = "UL_ETDM_In0_FE",
+ .stream_name = "UL_ETDM_In0 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture_etdm_in0),
+ },
+ {
+ .name = "UL_ETDM_In1_FE",
+ .stream_name = "UL_ETDM_In1 Capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+ SND_SOC_DPCM_TRIGGER_PRE},
+ .dynamic = 1,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(capture_etdm_in1),
+ },
+ /* Back End DAI links */
+ {
+ .name = "I2SIN0_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8189_common_i2s_ops,
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(i2sin0),
+ },
+ {
+ .name = "I2SIN1_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8189_common_i2s_ops,
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(i2sin1),
+ },
+ {
+ .name = "I2SOUT0_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8189_common_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(i2sout0),
+ },
+ {
+ .name = "I2SOUT1_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8189_common_i2s_ops,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(i2sout1),
+ },
+ {
+ .name = "AP_DMIC_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic),
+ },
+ {
+ .name = "AP_DMIC_CH34_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(ap_dmic_ch34),
+ },
+ {
+ .name = "TDM_DPTX_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .ops = &mt8189_dptx_ops,
+ .be_hw_params_fixup = mt8189_dptx_hw_params_fixup,
+ .no_pcm = 1,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(tdm_dptx),
+ },
+ {
+ .name = "PCM_0_BE",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
+ | SND_SOC_DAIFMT_GATED,
+ .no_pcm = 1,
+ .ops = &mt8189_pcm_ops,
+ .playback_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(pcm0),
+ },
+};
+
+static struct snd_soc_codec_conf mt8189_cs35l41_codec_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(CS35L41_DEV0_NAME),
+ .name_prefix = "Right",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(CS35L41_DEV1_NAME),
+ .name_prefix = "Left",
+ },
+};
+
+static int mt8189_nau8825_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+ struct snd_soc_card *card = soc_card_data->card_data->card;
+ struct snd_soc_dai_link *dai_link;
+ bool init_nau8825 = false;
+ bool init_rt5682s = false;
+ bool init_rt5650 = false;
+ bool init_rt5682i = false;
+ bool init_es8326 = false;
+ bool init_dumb = false;
+ int i;
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (strcmp(dai_link->name, "TDM_DPTX_BE") == 0) {
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ dai_link->init = mt8189_dptx_codec_init;
+ } else if (strcmp(dai_link->name, "PCM_0_BE") == 0) {
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai"))
+ dai_link->init = mt8189_hdmi_codec_init;
+ } else if (strcmp(dai_link->name, "I2SOUT0_BE") == 0 ||
+ strcmp(dai_link->name, "I2SIN0_BE") == 0) {
+ if (!strcmp(dai_link->codecs->dai_name, NAU8825_CODEC_DAI)) {
+ dai_link->ops = &mt8189_nau8825_ops;
+ if (!init_nau8825) {
+ dai_link->init = mt8189_headset_codec_init;
+ dai_link->exit = mt8189_headset_codec_exit;
+ init_nau8825 = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
+ dai_link->ops = &mt8189_rtxxxx_i2s_ops;
+ if (!init_rt5682s) {
+ dai_link->init = mt8189_headset_codec_init;
+ dai_link->exit = mt8189_headset_codec_exit;
+ init_rt5682s = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5650_CODEC_DAI)) {
+ dai_link->ops = &mt8189_rtxxxx_i2s_ops;
+ if (!init_rt5650) {
+ dai_link->init = mt8189_headset_codec_init;
+ dai_link->exit = mt8189_headset_codec_exit;
+ init_rt5650 = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5682I_CODEC_DAI)) {
+ dai_link->ops = &mt8189_rtxxxx_i2s_ops;
+ if (!init_rt5682i) {
+ dai_link->init = mt8189_headset_codec_init;
+ dai_link->exit = mt8189_headset_codec_exit;
+ init_rt5682i = true;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, ES8326_CODEC_DAI)) {
+ dai_link->ops = &mt8189_es8326_ops;
+ if (!init_es8326) {
+ dai_link->init = mt8189_headset_codec_init;
+ dai_link->exit = mt8189_headset_codec_exit;
+ init_es8326 = true;
+ }
+ } else {
+ if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) {
+ if (!init_dumb) {
+ dai_link->init = mt8189_dumb_amp_init;
+ init_dumb = true;
+ }
+ }
+ }
+ } else if (strcmp(dai_link->name, "I2SOUT1_BE") == 0) {
+ if (!strcmp(dai_link->codecs->dai_name, CS35L41_CODEC_DAI)) {
+ dai_link->ops = &mt8189_cs35l41_i2s_ops;
+ card->num_configs = ARRAY_SIZE(mt8189_cs35l41_codec_conf);
+ card->codec_conf = mt8189_cs35l41_codec_conf;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_card mt8189_nau8825_soc_card = {
+ .owner = THIS_MODULE,
+ .dai_link = mt8189_nau8825_dai_links,
+ .num_links = ARRAY_SIZE(mt8189_nau8825_dai_links),
+ .dapm_widgets = mt8189_nau8825_card_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8189_nau8825_card_widgets),
+};
+
+static const struct mtk_soundcard_pdata mt8189_nau8825_card = {
+ .card_name = "mt8189_nau8825",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8189_nau8825_soc_card,
+ .num_jacks = MT8189_JACK_MAX,
+ .flags = NAU8825_HS_PRESENT
+ },
+ .sof_priv = NULL,
+ .soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8189_rt5650_card = {
+ .card_name = "mt8189_rt5650",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8189_nau8825_soc_card,
+ .num_jacks = MT8189_JACK_MAX,
+ .flags = RT5650_HS_PRESENT
+ },
+ .sof_priv = NULL,
+ .soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8189_rt5682s_card = {
+ .card_name = "mt8189_rt5682s",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8189_nau8825_soc_card,
+ .num_jacks = MT8189_JACK_MAX,
+ .flags = RT5682S_HS_PRESENT
+ },
+ .sof_priv = NULL,
+ .soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8189_rt5682i_card = {
+ .card_name = "mt8189_rt5682i",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8189_nau8825_soc_card,
+ .num_jacks = MT8189_JACK_MAX,
+ .flags = RT5682I_HS_PRESENT
+ },
+ .sof_priv = NULL,
+ .soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct mtk_soundcard_pdata mt8188_es8326_card = {
+ .card_name = "mt8188_es8326",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8189_nau8825_soc_card,
+ .num_jacks = MT8189_JACK_MAX,
+ .flags = ES8326_HS_PRESENT
+ },
+ .sof_priv = NULL,
+ .soc_probe = mt8189_nau8825_soc_card_probe,
+};
+
+static const struct of_device_id mt8189_nau8825_dt_match[] = {
+ {.compatible = "mediatek,mt8189-nau8825", .data = &mt8189_nau8825_card,},
+ {.compatible = "mediatek,mt8189-rt5650", .data = &mt8189_rt5650_card,},
+ {.compatible = "mediatek,mt8189-rt5682s", .data = &mt8189_rt5682s_card,},
+ {.compatible = "mediatek,mt8189-rt5682i", .data = &mt8189_rt5682i_card,},
+ {.compatible = "mediatek,mt8189-es8326", .data = &mt8188_es8326_card,},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt8189_nau8825_dt_match);
+
+static struct platform_driver mt8189_nau8825_driver = {
+ .driver = {
+ .name = "mt8189-nau8825",
+ .of_match_table = mt8189_nau8825_dt_match,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mtk_soundcard_common_probe,
+};
+module_platform_driver(mt8189_nau8825_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8189 NAU8825 ALSA SoC machine driver");
+MODULE_AUTHOR("Darren Ye <darren.ye@mediatek.com>");
+MODULE_AUTHOR("Cyril Chao <cyril.chao@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt8189/mt8189-reg.h b/sound/soc/mediatek/mt8189/mt8189-reg.h
new file mode 100644
index 000000000000..25f9658b6eae
--- /dev/null
+++ b/sound/soc/mediatek/mt8189/mt8189-reg.h
@@ -0,0 +1,10773 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8189-reg.h -- Mediatek 8189 audio driver reg definition
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Author: Darren Ye <darren.ye@mediatek.com>
+ */
+
+#ifndef _MT8189_REG_H_
+#define _MT8189_REG_H_
+
+ /* reg bit enum */
+enum {
+ MT8189_MEMIF_PBUF_SIZE_32_BYTES,
+ MT8189_MEMIF_PBUF_SIZE_64_BYTES,
+ MT8189_MEMIF_PBUF_SIZE_128_BYTES,
+ MT8189_MEMIF_PBUF_SIZE_256_BYTES,
+ MT8189_MEMIF_PBUF_SIZE_NUM,
+};
+
+/*****************************************************************************
+ * R E G I S T E R D E F I N I T I O N
+ *****************************************************************************/
+/* AUDIO_TOP_CON0 */
+#define PDN_MTKAIFV4_SFT 25
+#define PDN_MTKAIFV4_MASK 0x1
+#define PDN_MTKAIFV4_MASK_SFT (0x1 << 25)
+#define PDN_FM_I2S_SFT 24
+#define PDN_FM_I2S_MASK 0x1
+#define PDN_FM_I2S_MASK_SFT (0x1 << 24)
+#define PDN_HW_GAIN01_SFT 21
+#define PDN_HW_GAIN01_MASK 0x1
+#define PDN_HW_GAIN01_MASK_SFT (0x1 << 21)
+#define PDN_HW_GAIN23_SFT 20
+#define PDN_HW_GAIN23_MASK 0x1
+#define PDN_HW_GAIN23_MASK_SFT (0x1 << 20)
+#define PDN_STF_SFT 19
+#define PDN_STF_MASK 0x1
+#define PDN_STF_MASK_SFT (0x1 << 19)
+#define PDN_CM0_SFT 18
+#define PDN_CM0_MASK 0x1
+#define PDN_CM0_MASK_SFT (0x1 << 18)
+#define PDN_CM1_SFT 17
+#define PDN_CM1_MASK 0x1
+#define PDN_CM1_MASK_SFT (0x1 << 17)
+#define PDN_PCM0_SFT 14
+#define PDN_PCM0_MASK 0x1
+#define PDN_PCM0_MASK_SFT (0x1 << 14)
+#define PDN_DL0_NLE_SFT 11
+#define PDN_DL0_NLE_MASK 0x1
+#define PDN_DL0_NLE_MASK_SFT (0x1 << 11)
+#define PDN_DL0_PREDIS_SFT 10
+#define PDN_DL0_PREDIS_MASK 0x1
+#define PDN_DL0_PREDIS_MASK_SFT (0x1 << 10)
+#define PDN_DL0_DAC_SFT 9
+#define PDN_DL0_DAC_MASK 0x1
+#define PDN_DL0_DAC_MASK_SFT (0x1 << 9)
+#define PDN_DL0_DAC_HIRES_SFT 8
+#define PDN_DL0_DAC_HIRES_MASK 0x1
+#define PDN_DL0_DAC_HIRES_MASK_SFT (0x1 << 8)
+#define PDN_DL0_DAC_TML_SFT 7
+#define PDN_DL0_DAC_TML_MASK 0x1
+#define PDN_DL0_DAC_TML_MASK_SFT (0x1 << 7)
+
+/* AUDIO_TOP_CON1 */
+#define PDN_UL0_ADC_SFT 23
+#define PDN_UL0_ADC_MASK 0x1
+#define PDN_UL0_ADC_MASK_SFT (0x1 << 23)
+#define PDN_UL0_TML_SFT 22
+#define PDN_UL0_TML_MASK 0x1
+#define PDN_UL0_TML_MASK_SFT (0x1 << 22)
+#define PDN_UL0_ADC_HIRES_SFT 21
+#define PDN_UL0_ADC_HIRES_MASK 0x1
+#define PDN_UL0_ADC_HIRES_MASK_SFT (0x1 << 21)
+#define PDN_UL0_ADC_HIRES_TML_SFT 20
+#define PDN_UL0_ADC_HIRES_TML_MASK 0x1
+#define PDN_UL0_ADC_HIRES_TML_MASK_SFT (0x1 << 20)
+#define PDN_UL1_ADC_SFT 19
+#define PDN_UL1_ADC_MASK 0x1
+#define PDN_UL1_ADC_MASK_SFT (0x1 << 19)
+#define PDN_UL1_TML_SFT 18
+#define PDN_UL1_TML_MASK 0x1
+#define PDN_UL1_TML_MASK_SFT (0x1 << 18)
+#define PDN_UL1_ADC_HIRES_SFT 17
+#define PDN_UL1_ADC_HIRES_MASK 0x1
+#define PDN_UL1_ADC_HIRES_MASK_SFT (0x1 << 17)
+#define PDN_UL1_ADC_HIRES_TML_SFT 16
+#define PDN_UL1_ADC_HIRES_TML_MASK 0x1
+#define PDN_UL1_ADC_HIRES_TML_MASK_SFT (0x1 << 16)
+#define PDN_DMIC0_ADC_SFT 7
+#define PDN_DMIC0_ADC_MASK 0x1
+#define PDN_DMIC0_ADC_MASK_SFT (0x1 << 7)
+#define PDN_DMIC1_ADC_SFT 3
+#define PDN_DMIC1_ADC_MASK 0x1
+#define PDN_DMIC1_ADC_MASK_SFT (0x1 << 3)
+
+/* AUDIO_TOP_CON2 */
+#define PDN_TDM_OUT_SFT 24
+#define PDN_TDM_OUT_MASK 0x1
+#define PDN_TDM_OUT_MASK_SFT (0x1 << 24)
+#define PDN_ETDM_OUT0_SFT 21
+#define PDN_ETDM_OUT0_MASK 0x1
+#define PDN_ETDM_OUT0_MASK_SFT (0x1 << 21)
+#define PDN_ETDM_OUT1_SFT 20
+#define PDN_ETDM_OUT1_MASK 0x1
+#define PDN_ETDM_OUT1_MASK_SFT (0x1 << 20)
+#define PDN_ETDM_OUT4_SFT 17
+#define PDN_ETDM_OUT4_MASK 0x1
+#define PDN_ETDM_OUT4_MASK_SFT (0x1 << 17)
+#define PDN_ETDM_IN0_SFT 13
+#define PDN_ETDM_IN0_MASK 0x1
+#define PDN_ETDM_IN0_MASK_SFT (0x1 << 13)
+#define PDN_ETDM_IN1_SFT 12
+#define PDN_ETDM_IN1_MASK 0x1
+#define PDN_ETDM_IN1_MASK_SFT (0x1 << 12)
+
+/* AUDIO_TOP_CON3 */
+#define PDN_CONNSYS_I2S_ASRC_SFT 25
+#define PDN_CONNSYS_I2S_ASRC_MASK 0x1
+#define PDN_CONNSYS_I2S_ASRC_MASK_SFT (0x1 << 25)
+#define PDN_GENERAL0_ASRC_SFT 24
+#define PDN_GENERAL0_ASRC_MASK 0x1
+#define PDN_GENERAL0_ASRC_MASK_SFT (0x1 << 24)
+#define PDN_GENERAL1_ASRC_SFT 23
+#define PDN_GENERAL1_ASRC_MASK 0x1
+#define PDN_GENERAL1_ASRC_MASK_SFT (0x1 << 23)
+#define PDN_GENERAL2_ASRC_SFT 22
+#define PDN_GENERAL2_ASRC_MASK 0x1
+#define PDN_GENERAL2_ASRC_MASK_SFT (0x1 << 22)
+#define PDN_GENERAL3_ASRC_SFT 21
+#define PDN_GENERAL3_ASRC_MASK 0x1
+#define PDN_GENERAL3_ASRC_MASK_SFT (0x1 << 21)
+#define PDN_GENERAL4_ASRC_SFT 20
+#define PDN_GENERAL4_ASRC_MASK 0x1
+#define PDN_GENERAL4_ASRC_MASK_SFT (0x1 << 20)
+
+/* AUDIO_TOP_CON4 */
+#define PDN_APLL_TUNER1_SFT 13
+#define PDN_APLL_TUNER1_MASK 0x1
+#define PDN_APLL_TUNER1_MASK_SFT (0x1 << 13)
+#define PDN_APLL_TUNER2_SFT 12
+#define PDN_APLL_TUNER2_MASK 0x1
+#define PDN_APLL_TUNER2_MASK_SFT (0x1 << 12)
+#define CG_H208M_CK_SFT 4
+#define CG_H208M_CK_MASK 0x1
+#define CG_H208M_CK_MASK_SFT (0x1 << 4)
+#define CG_APLL2_CK_SFT 3
+#define CG_APLL2_CK_MASK 0x1
+#define CG_APLL2_CK_MASK_SFT (0x1 << 3)
+#define CG_APLL1_CK_SFT 2
+#define CG_APLL1_CK_MASK 0x1
+#define CG_APLL1_CK_MASK_SFT (0x1 << 2)
+#define CG_AUDIO_F26M_CK_SFT 1
+#define CG_AUDIO_F26M_CK_MASK 0x1
+#define CG_AUDIO_F26M_CK_MASK_SFT (0x1 << 1)
+#define CG_AUDIO_HOPPING_CK_SFT 0
+#define CG_AUDIO_HOPPING_CK_MASK 0x1
+#define CG_AUDIO_HOPPING_CK_MASK_SFT (0x1 << 0)
+
+/* AUDIO_ENGEN_CON0 */
+/* AUDIO_ENGEN_CON0_USER1 */
+/* AUDIO_ENGEN_CON0_USER2 */
+#define MULTI_USER_BYPASS_SFT 17
+#define MULTI_USER_BYPASS_MASK 0x1
+#define MULTI_USER_BYPASS_MASK_SFT (0x1 << 17)
+#define MULTI_USER_RST_SFT 16
+#define MULTI_USER_RST_MASK 0x1
+#define MULTI_USER_RST_MASK_SFT (0x1 << 16)
+#define AUDIO_F26M_EN_RST_SFT 8
+#define AUDIO_F26M_EN_RST_MASK 0x1
+#define AUDIO_F26M_EN_RST_MASK_SFT (0x1 << 8)
+#define AUDIO_APLL2_EN_ON_SFT 3
+#define AUDIO_APLL2_EN_ON_MASK 0x1
+#define AUDIO_APLL2_EN_ON_MASK_SFT (0x1 << 3)
+#define AUDIO_APLL1_EN_ON_SFT 2
+#define AUDIO_APLL1_EN_ON_MASK 0x1
+#define AUDIO_APLL1_EN_ON_MASK_SFT (0x1 << 2)
+#define AUDIO_F3P25M_EN_ON_SFT 1
+#define AUDIO_F3P25M_EN_ON_MASK 0x1
+#define AUDIO_F3P25M_EN_ON_MASK_SFT (0x1 << 1)
+#define AUDIO_26M_EN_ON_SFT 0
+#define AUDIO_26M_EN_ON_MASK 0x1
+#define AUDIO_26M_EN_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_SINEGEN_CON0 */
+#define DAC_EN_SFT 26
+#define DAC_EN_MASK 0x1
+#define DAC_EN_MASK_SFT (0x1 << 26)
+#define TIE_SW_CH2_SFT 25
+#define TIE_SW_CH2_MASK 0x1
+#define TIE_SW_CH2_MASK_SFT (0x1 << 25)
+#define TIE_SW_CH1_SFT 24
+#define TIE_SW_CH1_MASK 0x1
+#define TIE_SW_CH1_MASK_SFT (0x1 << 24)
+#define AMP_DIV_CH2_SFT 20
+#define AMP_DIV_CH2_MASK 0xf
+#define AMP_DIV_CH2_MASK_SFT (0xf << 20)
+#define FREQ_DIV_CH2_SFT 12
+#define FREQ_DIV_CH2_MASK 0x1f
+#define FREQ_DIV_CH2_MASK_SFT (0x1f << 12)
+#define AMP_DIV_CH1_SFT 8
+#define AMP_DIV_CH1_MASK 0xf
+#define AMP_DIV_CH1_MASK_SFT (0xf << 8)
+#define FREQ_DIV_CH1_SFT 0
+#define FREQ_DIV_CH1_MASK 0x1f
+#define FREQ_DIV_CH1_MASK_SFT (0x1f << 0)
+
+/* AFE_SINEGEN_CON1 */
+#define SINE_DOMAIN_SFT 20
+#define SINE_DOMAIN_MASK 0x7
+#define SINE_DOMAIN_MASK_SFT (0x7 << 20)
+#define SINE_MODE_SFT 12
+#define SINE_MODE_MASK 0x1f
+#define SINE_MODE_MASK_SFT (0x1f << 12)
+#define INNER_LOOP_BACKI_SEL_SFT 8
+#define INNER_LOOP_BACKI_SEL_MASK 0x1
+#define INNER_LOOP_BACKI_SEL_MASK_SFT (0x1 << 8)
+#define INNER_LOOP_BACK_MODE_SFT 0
+#define INNER_LOOP_BACK_MODE_MASK 0xff
+#define INNER_LOOP_BACK_MODE_MASK_SFT (0xff << 0)
+
+/* AFE_SINEGEN_CON2 */
+#define TIE_CH1_CONSTANT_SFT 0
+#define TIE_CH1_CONSTANT_MASK 0xffffffff
+#define TIE_CH1_CONSTANT_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SINEGEN_CON3 */
+#define TIE_CH2_CONSTANT_SFT 0
+#define TIE_CH2_CONSTANT_MASK 0xffffffff
+#define TIE_CH2_CONSTANT_MASK_SFT (0xffffffff << 0)
+
+/* AFE_APLL1_TUNER_CFG */
+#define UPPER_BOUND_SFT 8
+#define UPPER_BOUND_MASK 0xff
+#define UPPER_BOUND_MASK_SFT (0xff << 8)
+#define APLL_DIV_SFT 4
+#define APLL_DIV_MASK 0xf
+#define APLL_DIV_MASK_SFT (0xf << 4)
+#define XTAL_EN_128FS_SEL_SFT 1
+#define XTAL_EN_128FS_SEL_MASK 0x3
+#define XTAL_EN_128FS_SEL_MASK_SFT (0x3 << 1)
+#define FREQ_TUNER_EN_SFT 0
+#define FREQ_TUNER_EN_MASK 0x1
+#define FREQ_TUNER_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_APLL1_TUNER_MON0 */
+#define TUNER_MON_SFT 0
+#define TUNER_MON_MASK 0xffffffff
+#define TUNER_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_APLL2_TUNER_CFG */
+#define UPPER_BOUND_SFT 8
+#define UPPER_BOUND_MASK 0xff
+#define UPPER_BOUND_MASK_SFT (0xff << 8)
+#define APLL_DIV_SFT 4
+#define APLL_DIV_MASK 0xf
+#define APLL_DIV_MASK_SFT (0xf << 4)
+#define XTAL_EN_128FS_SEL_SFT 1
+#define XTAL_EN_128FS_SEL_MASK 0x3
+#define XTAL_EN_128FS_SEL_MASK_SFT (0x3 << 1)
+#define FREQ_TUNER_EN_SFT 0
+#define FREQ_TUNER_EN_MASK 0x1
+#define FREQ_TUNER_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_APLL2_TUNER_MON0 */
+#define TUNER_MON_SFT 0
+#define TUNER_MON_MASK 0xffffffff
+#define TUNER_MON_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_TOP_RG0 */
+#define RESERVE_RG_SFT 0
+#define RESERVE_RG_MASK 0xffffffff
+#define RESERVE_RG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_TOP_RG1 */
+#define RESERVE_RG_SFT 0
+#define RESERVE_RG_MASK 0xffffffff
+#define RESERVE_RG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_TOP_RG2 */
+#define RESERVE_RG_SFT 0
+#define RESERVE_RG_MASK 0xffffffff
+#define RESERVE_RG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_TOP_RG3 */
+#define RESERVE_RG_SFT 0
+#define RESERVE_RG_MASK 0xffffffff
+#define RESERVE_RG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_TOP_RG4 */
+#define RESERVE_RG_SFT 0
+#define RESERVE_RG_MASK 0xffffffff
+#define RESERVE_RG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SPM_CONTROL_REQ */
+#define AFE_DDREN_REQ_SFT 4
+#define AFE_DDREN_REQ_MASK 0x1
+#define AFE_DDREN_REQ_MASK_SFT (0x1 << 4)
+#define AFE_INFRA_REQ_SFT 3
+#define AFE_INFRA_REQ_MASK 0x1
+#define AFE_INFRA_REQ_MASK_SFT (0x1 << 3)
+#define AFE_VRF18_REQ_SFT 2
+#define AFE_VRF18_REQ_MASK 0x1
+#define AFE_VRF18_REQ_MASK_SFT (0x1 << 2)
+#define AFE_APSRC_REQ_SFT 1
+#define AFE_APSRC_REQ_MASK 0x1
+#define AFE_APSRC_REQ_MASK_SFT (0x1 << 1)
+#define AFE_SRCCLKENA_REQ_SFT 0
+#define AFE_SRCCLKENA_REQ_MASK 0x1
+#define AFE_SRCCLKENA_REQ_MASK_SFT (0x1 << 0)
+
+/* AFE_SPM_CONTROL_ACK */
+#define SPM_RESOURCE_CONTROL_ACK_SFT 0
+#define SPM_RESOURCE_CONTROL_ACK_MASK 0xffffffff
+#define SPM_RESOURCE_CONTROL_ACK_MASK_SFT (0xffffffff << 0)
+
+/* AUD_TOP_CFG_VCORE_RG */
+#define AUD_TOP_CFG_SFT 0
+#define AUD_TOP_CFG_MASK 0xffffffff
+#define AUD_TOP_CFG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_TOP_IP_VERSION */
+#define AUDIO_TOP_IP_VERSION_SFT 0
+#define AUDIO_TOP_IP_VERSION_MASK 0xffffffff
+#define AUDIO_TOP_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_ENGEN_CON0_MON */
+#define AUDIO_ENGEN_MON_SFT 0
+#define AUDIO_ENGEN_MON_MASK 0xffffffff
+#define AUDIO_ENGEN_MON_MASK_SFT (0xffffffff << 0)
+
+/* AUD_TOP_CFG_VLP_RG */
+#define AUD_TOP_CFG_SFT 0
+#define AUD_TOP_CFG_MASK 0xffffffff
+#define AUD_TOP_CFG_MASK_SFT (0xffffffff << 0)
+
+/* AUD_TOP_MON_RG */
+#define AUD_TOP_MON_SFT 0
+#define AUD_TOP_MON_MASK 0xffffffff
+#define AUD_TOP_MON_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_USE_DEFAULT_DELSEL0 */
+#define USE_DEFAULT_DELSEL_RG_SFT 0
+#define USE_DEFAULT_DELSEL_RG_MASK 0xffffffff
+#define USE_DEFAULT_DELSEL_RG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_USE_DEFAULT_DELSEL1 */
+#define USE_DEFAULT_DELSEL_RG_SFT 0
+#define USE_DEFAULT_DELSEL_RG_MASK 0xffffffff
+#define USE_DEFAULT_DELSEL_RG_MASK_SFT (0xffffffff << 0)
+
+/* AUDIO_USE_DEFAULT_DELSEL2 */
+#define USE_DEFAULT_DELSEL_RG_SFT 0
+#define USE_DEFAULT_DELSEL_RG_MASK 0xffffffff
+#define USE_DEFAULT_DELSEL_RG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CONNSYS_I2S_IPM_VER_MON */
+#define RG_CONNSYS_I2S_IPM_VER_MON_SFT 0
+#define RG_CONNSYS_I2S_IPM_VER_MON_MASK 0xffffffff
+#define RG_CONNSYS_I2S_IPM_VER_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CONNSYS_I2S_MON_SEL */
+#define RG_CONNSYS_I2S_MON_SEL_SFT 0
+#define RG_CONNSYS_I2S_MON_SEL_MASK 0xff
+#define RG_CONNSYS_I2S_MON_SEL_MASK_SFT (0xff << 0)
+
+/* AFE_CONNSYS_I2S_MON */
+#define RG_CONNSYS_I2S_MON_SFT 0
+#define RG_CONNSYS_I2S_MON_MASK 0xffffffff
+#define RG_CONNSYS_I2S_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CONNSYS_I2S_CON */
+#define I2S_SOFT_RST_SFT 31
+#define I2S_SOFT_RST_MASK 0x1
+#define I2S_SOFT_RST_MASK_SFT (0x1 << 31)
+#define BCK_NEG_EG_LATCH_SFT 30
+#define BCK_NEG_EG_LATCH_MASK 0x1
+#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30)
+#define BCK_INV_SFT 29
+#define BCK_INV_MASK 0x1
+#define BCK_INV_MASK_SFT (0x1 << 29)
+#define I2SIN_PAD_SEL_SFT 28
+#define I2SIN_PAD_SEL_MASK 0x1
+#define I2SIN_PAD_SEL_MASK_SFT (0x1 << 28)
+#define I2S_LOOPBACK_SFT 20
+#define I2S_LOOPBACK_MASK 0x1
+#define I2S_LOOPBACK_MASK_SFT (0x1 << 20)
+#define I2S_HDEN_SFT 12
+#define I2S_HDEN_MASK 0x1
+#define I2S_HDEN_MASK_SFT (0x1 << 12)
+#define I2S_MODE_SFT 8
+#define I2S_MODE_MASK 0xf
+#define I2S_MODE_MASK_SFT (0xf << 8)
+#define I2S_BYPSRC_SFT 6
+#define I2S_BYPSRC_MASK 0x1
+#define I2S_BYPSRC_MASK_SFT (0x1 << 6)
+#define INV_LRCK_SFT 5
+#define INV_LRCK_MASK 0x1
+#define INV_LRCK_MASK_SFT (0x1 << 5)
+#define I2S_FMT_SFT 3
+#define I2S_FMT_MASK 0x1
+#define I2S_FMT_MASK_SFT (0x1 << 3)
+#define I2S_SRC_SFT 2
+#define I2S_SRC_MASK 0x1
+#define I2S_SRC_MASK_SFT (0x1 << 2)
+#define I2S_WLEN_SFT 1
+#define I2S_WLEN_MASK 0x1
+#define I2S_WLEN_MASK_SFT (0x1 << 1)
+#define I2S_EN_SFT 0
+#define I2S_EN_MASK 0x1
+#define I2S_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_PCM0_INTF_CON0 */
+#define PCM0_HDEN_SFT 26
+#define PCM0_HDEN_MASK 0x1
+#define PCM0_HDEN_MASK_SFT (0x1 << 26)
+#define PCM0_SYNC_DELSEL_SFT 25
+#define PCM0_SYNC_DELSEL_MASK 0x1
+#define PCM0_SYNC_DELSEL_MASK_SFT (0x1 << 25)
+#define PCM0_TX_LR_SWAP_SFT 24
+#define PCM0_TX_LR_SWAP_MASK 0x1
+#define PCM0_TX_LR_SWAP_MASK_SFT (0x1 << 24)
+#define PCM0_SYNC_OUT_INV_SFT 23
+#define PCM0_SYNC_OUT_INV_MASK 0x1
+#define PCM0_SYNC_OUT_INV_MASK_SFT (0x1 << 23)
+#define PCM0_BCLK_OUT_INV_SFT 22
+#define PCM0_BCLK_OUT_INV_MASK 0x1
+#define PCM0_BCLK_OUT_INV_MASK_SFT (0x1 << 22)
+#define PCM0_SYNC_IN_INV_SFT 21
+#define PCM0_SYNC_IN_INV_MASK 0x1
+#define PCM0_SYNC_IN_INV_MASK_SFT (0x1 << 21)
+#define PCM0_BCLK_IN_INV_SFT 20
+#define PCM0_BCLK_IN_INV_MASK 0x1
+#define PCM0_BCLK_IN_INV_MASK_SFT (0x1 << 20)
+#define PCM0_TX_LCH_RPT_SFT 19
+#define PCM0_TX_LCH_RPT_MASK 0x1
+#define PCM0_TX_LCH_RPT_MASK_SFT (0x1 << 19)
+#define PCM0_VBT_16K_MODE_SFT 18
+#define PCM0_VBT_16K_MODE_MASK 0x1
+#define PCM0_VBT_16K_MODE_MASK_SFT (0x1 << 18)
+#define PCM0_BIT_LENGTH_SFT 16
+#define PCM0_BIT_LENGTH_MASK 0x3
+#define PCM0_BIT_LENGTH_MASK_SFT (0x3 << 16)
+#define PCM0_WLEN_SFT 14
+#define PCM0_WLEN_MASK 0x3
+#define PCM0_WLEN_MASK_SFT (0x3 << 14)
+#define PCM0_SYNC_LENGTH_SFT 9
+#define PCM0_SYNC_LENGTH_MASK 0x1f
+#define PCM0_SYNC_LENGTH_MASK_SFT (0x1f << 9)
+#define PCM0_SYNC_TYPE_SFT 8
+#define PCM0_SYNC_TYPE_MASK 0x1
+#define PCM0_SYNC_TYPE_MASK_SFT (0x1 << 8)
+#define PCM0_BYP_ASRC_SFT 7
+#define PCM0_BYP_ASRC_MASK 0x1
+#define PCM0_BYP_ASRC_MASK_SFT (0x1 << 7)
+#define PCM0_SLAVE_SFT 6
+#define PCM0_SLAVE_MASK 0x1
+#define PCM0_SLAVE_MASK_SFT (0x1 << 6)
+#define PCM0_MODE_SFT 3
+#define PCM0_MODE_MASK 0x7
+#define PCM0_MODE_MASK_SFT (0x7 << 3)
+#define PCM0_FMT_SFT 1
+#define PCM0_FMT_MASK 0x3
+#define PCM0_FMT_MASK_SFT (0x3 << 1)
+#define PCM0_EN_SFT 0
+#define PCM0_EN_MASK 0x1
+#define PCM0_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_PCM0_INTF_CON1 */
+#define PCM0_TX_RX_LOOPBACK_SFT 31
+#define PCM0_TX_RX_LOOPBACK_MASK 0x1
+#define PCM0_TX_RX_LOOPBACK_MASK_SFT (0x1 << 31)
+#define PCM0_BUFFER_LOOPBACK_SFT 30
+#define PCM0_BUFFER_LOOPBACK_MASK 0x1
+#define PCM0_BUFFER_LOOPBACK_MASK_SFT (0x1 << 30)
+#define PCM0_PARALLEL_LOOPBACK_SFT 29
+#define PCM0_PARALLEL_LOOPBACK_MASK 0x1
+#define PCM0_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 29)
+#define PCM0_SERIAL_LOOPBACK_SFT 28
+#define PCM0_SERIAL_LOOPBACK_MASK 0x1
+#define PCM0_SERIAL_LOOPBACK_MASK_SFT (0x1 << 28)
+#define PCM0_DAI_LOOPBACK_SFT 27
+#define PCM0_DAI_LOOPBACK_MASK 0x1
+#define PCM0_DAI_LOOPBACK_MASK_SFT (0x1 << 27)
+#define PCM0_I2S_LOOPBACK_SFT 26
+#define PCM0_I2S_LOOPBACK_MASK 0x1
+#define PCM0_I2S_LOOPBACK_MASK_SFT (0x1 << 26)
+#define PCM0_1X_EN_DOMAIN_SFT 23
+#define PCM0_1X_EN_DOMAIN_MASK 0x7
+#define PCM0_1X_EN_DOMAIN_MASK_SFT (0x7 << 23)
+#define PCM0_1X_EN_MODE_SFT 18
+#define PCM0_1X_EN_MODE_MASK 0x1f
+#define PCM0_1X_EN_MODE_MASK_SFT (0x1f << 18)
+#define PCM0_TX3_RCH_DBG_MODE_SFT 17
+#define PCM0_TX3_RCH_DBG_MODE_MASK 0x1
+#define PCM0_TX3_RCH_DBG_MODE_MASK_SFT (0x1 << 17)
+#define PCM0_PCM1_LOOPBACK_SFT 16
+#define PCM0_PCM1_LOOPBACK_MASK 0x1
+#define PCM0_PCM1_LOOPBACK_MASK_SFT (0x1 << 16)
+#define PCM0_LOOPBACK_CH_SEL_SFT 12
+#define PCM0_LOOPBACK_CH_SEL_MASK 0x3
+#define PCM0_LOOPBACK_CH_SEL_MASK_SFT (0x3 << 12)
+#define PCM0_BT_MODE_SFT 11
+#define PCM0_BT_MODE_MASK 0x1
+#define PCM0_BT_MODE_MASK_SFT (0x1 << 11)
+#define PCM0_EXT_MODEM_SFT 10
+#define PCM0_EXT_MODEM_MASK 0x1
+#define PCM0_EXT_MODEM_MASK_SFT (0x1 << 10)
+#define PCM0_USE_MD3_SFT 9
+#define PCM0_USE_MD3_MASK 0x1
+#define PCM0_USE_MD3_MASK_SFT (0x1 << 9)
+#define PCM0_FIX_VALUE_SEL_SFT 8
+#define PCM0_FIX_VALUE_SEL_MASK 0x1
+#define PCM0_FIX_VALUE_SEL_MASK_SFT (0x1 << 8)
+#define PCM0_TX_FIX_VALUE_SFT 0
+#define PCM0_TX_FIX_VALUE_MASK 0xff
+#define PCM0_TX_FIX_VALUE_MASK_SFT (0xff << 0)
+
+/* AFE_PCM_INTF_MON */
+#define PCM0_TX_FIFO_OV_SFT 5
+#define PCM0_TX_FIFO_OV_MASK 0x1
+#define PCM0_TX_FIFO_OV_MASK_SFT (0x1 << 5)
+#define PCM0_RX_FIFO_OV_SFT 4
+#define PCM0_RX_FIFO_OV_MASK 0x1
+#define PCM0_RX_FIFO_OV_MASK_SFT (0x1 << 4)
+#define PCM1_TX_FIFO_OV_SFT 3
+#define PCM1_TX_FIFO_OV_MASK 0x1
+#define PCM1_TX_FIFO_OV_MASK_SFT (0x1 << 3)
+#define PCM1_RX_FIFO_OV_SFT 2
+#define PCM1_RX_FIFO_OV_MASK 0x1
+#define PCM1_RX_FIFO_OV_MASK_SFT (0x1 << 2)
+#define PCM0_SYNC_GLITCH_SFT 1
+#define PCM0_SYNC_GLITCH_MASK 0x1
+#define PCM0_SYNC_GLITCH_MASK_SFT (0x1 << 1)
+#define PCM1_SYNC_GLITCH_SFT 0
+#define PCM1_SYNC_GLITCH_MASK 0x1
+#define PCM1_SYNC_GLITCH_MASK_SFT (0x1 << 0)
+
+/* AFE_PCM_TOP_IP_VERSION */
+#define AFE_PCM_TOP_IP_VERSION_SFT 0
+#define AFE_PCM_TOP_IP_VERSION_MASK 0xffffffff
+#define AFE_PCM_TOP_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_IRQ_MCU_EN */
+#define AFE_IRQ_MCU_EN_SFT 0
+#define AFE_IRQ_MCU_EN_MASK 0xffffffff
+#define AFE_IRQ_MCU_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_IRQ_MCU_DSP_EN */
+#define AFE_IRQ_DSP_EN_SFT 0
+#define AFE_IRQ_DSP_EN_MASK 0xffffffff
+#define AFE_IRQ_DSP_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_IRQ_MCU_DSP2_EN */
+#define AFE_IRQ_DSP2_EN_SFT 0
+#define AFE_IRQ_DSP2_EN_MASK 0xffffffff
+#define AFE_IRQ_DSP2_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_IRQ_MCU_SCP_EN */
+#define IRQ31_MCU_SCP_EN_SFT 31
+#define IRQ30_MCU_SCP_EN_SFT 30
+#define IRQ29_MCU_SCP_EN_SFT 29
+#define IRQ28_MCU_SCP_EN_SFT 28
+#define IRQ27_MCU_SCP_EN_SFT 27
+#define IRQ26_MCU_SCP_EN_SFT 26
+#define IRQ25_MCU_SCP_EN_SFT 25
+#define IRQ24_MCU_SCP_EN_SFT 24
+#define IRQ23_MCU_SCP_EN_SFT 23
+#define IRQ22_MCU_SCP_EN_SFT 22
+#define IRQ21_MCU_SCP_EN_SFT 21
+#define IRQ20_MCU_SCP_EN_SFT 20
+#define IRQ19_MCU_SCP_EN_SFT 19
+#define IRQ18_MCU_SCP_EN_SFT 18
+#define IRQ17_MCU_SCP_EN_SFT 17
+#define IRQ16_MCU_SCP_EN_SFT 16
+#define IRQ15_MCU_SCP_EN_SFT 15
+#define IRQ14_MCU_SCP_EN_SFT 14
+#define IRQ13_MCU_SCP_EN_SFT 13
+#define IRQ12_MCU_SCP_EN_SFT 12
+#define IRQ11_MCU_SCP_EN_SFT 11
+#define IRQ10_MCU_SCP_EN_SFT 10
+#define IRQ9_MCU_SCP_EN_SFT 9
+#define IRQ8_MCU_SCP_EN_SFT 8
+#define IRQ7_MCU_SCP_EN_SFT 7
+#define IRQ6_MCU_SCP_EN_SFT 6
+#define IRQ5_MCU_SCP_EN_SFT 5
+#define IRQ4_MCU_SCP_EN_SFT 4
+#define IRQ3_MCU_SCP_EN_SFT 3
+#define IRQ2_MCU_SCP_EN_SFT 2
+#define IRQ1_MCU_SCP_EN_SFT 1
+#define IRQ0_MCU_SCP_EN_SFT 0
+
+/* AFE_CUSTOM_IRQ_MCU_EN */
+#define AFE_CUSTOM_IRQ_MCU_EN_SFT 0
+#define AFE_CUSTOM_IRQ_MCU_EN_MASK 0xffffffff
+#define AFE_CUSTOM_IRQ_MCU_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CUSTOM_IRQ_MCU_DSP_EN */
+#define AFE_CUSTOM_IRQ_DSP_EN_SFT 0
+#define AFE_CUSTOM_IRQ_DSP_EN_MASK 0xffffffff
+#define AFE_CUSTOM_IRQ_DSP_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CUSTOM_IRQ_MCU_DSP2_EN */
+#define AFE_CUSTOM_IRQ_DSP2_EN_SFT 0
+#define AFE_CUSTOM_IRQ_DSP2_EN_MASK 0xffffffff
+#define AFE_CUSTOM_IRQ_DSP2_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CUSTOM_IRQ_MCU_SCP_EN */
+#define AFE_CUSTOM_IRQ_SCP_EN_SFT 0
+#define AFE_CUSTOM_IRQ_SCP_EN_MASK 0xffffffff
+#define AFE_CUSTOM_IRQ_SCP_EN_MASK_SFT (0xffffffff << 0)
+
+/* AFE_IRQ_MCU_STATUS */
+#define IRQ26_MCU_SFT 26
+#define IRQ26_MCU_MASK 0x1
+#define IRQ26_MCU_MASK_SFT (0x1 << 26)
+#define IRQ25_MCU_SFT 25
+#define IRQ25_MCU_MASK 0x1
+#define IRQ25_MCU_MASK_SFT (0x1 << 25)
+#define IRQ24_MCU_SFT 24
+#define IRQ24_MCU_MASK 0x1
+#define IRQ24_MCU_MASK_SFT (0x1 << 24)
+#define IRQ23_MCU_SFT 23
+#define IRQ23_MCU_MASK 0x1
+#define IRQ23_MCU_MASK_SFT (0x1 << 23)
+#define IRQ22_MCU_SFT 22
+#define IRQ22_MCU_MASK 0x1
+#define IRQ22_MCU_MASK_SFT (0x1 << 22)
+#define IRQ21_MCU_SFT 21
+#define IRQ21_MCU_MASK 0x1
+#define IRQ21_MCU_MASK_SFT (0x1 << 21)
+#define IRQ20_MCU_SFT 20
+#define IRQ20_MCU_MASK 0x1
+#define IRQ20_MCU_MASK_SFT (0x1 << 20)
+#define IRQ19_MCU_SFT 19
+#define IRQ19_MCU_MASK 0x1
+#define IRQ19_MCU_MASK_SFT (0x1 << 19)
+#define IRQ18_MCU_SFT 18
+#define IRQ18_MCU_MASK 0x1
+#define IRQ18_MCU_MASK_SFT (0x1 << 18)
+#define IRQ17_MCU_SFT 17
+#define IRQ17_MCU_MASK 0x1
+#define IRQ17_MCU_MASK_SFT (0x1 << 17)
+#define IRQ16_MCU_SFT 16
+#define IRQ16_MCU_MASK 0x1
+#define IRQ16_MCU_MASK_SFT (0x1 << 16)
+#define IRQ15_MCU_SFT 15
+#define IRQ15_MCU_MASK 0x1
+#define IRQ15_MCU_MASK_SFT (0x1 << 15)
+#define IRQ14_MCU_SFT 14
+#define IRQ14_MCU_MASK 0x1
+#define IRQ14_MCU_MASK_SFT (0x1 << 14)
+#define IRQ13_MCU_SFT 13
+#define IRQ13_MCU_MASK 0x1
+#define IRQ13_MCU_MASK_SFT (0x1 << 13)
+#define IRQ12_MCU_SFT 12
+#define IRQ12_MCU_MASK 0x1
+#define IRQ12_MCU_MASK_SFT (0x1 << 12)
+#define IRQ11_MCU_SFT 11
+#define IRQ11_MCU_MASK 0x1
+#define IRQ11_MCU_MASK_SFT (0x1 << 11)
+#define IRQ10_MCU_SFT 10
+#define IRQ10_MCU_MASK 0x1
+#define IRQ10_MCU_MASK_SFT (0x1 << 10)
+#define IRQ9_MCU_SFT 9
+#define IRQ9_MCU_MASK 0x1
+#define IRQ9_MCU_MASK_SFT (0x1 << 9)
+#define IRQ8_MCU_SFT 8
+#define IRQ8_MCU_MASK 0x1
+#define IRQ8_MCU_MASK_SFT (0x1 << 8)
+#define IRQ7_MCU_SFT 7
+#define IRQ7_MCU_MASK 0x1
+#define IRQ7_MCU_MASK_SFT (0x1 << 7)
+#define IRQ6_MCU_SFT 6
+#define IRQ6_MCU_MASK 0x1
+#define IRQ6_MCU_MASK_SFT (0x1 << 6)
+#define IRQ5_MCU_SFT 5
+#define IRQ5_MCU_MASK 0x1
+#define IRQ5_MCU_MASK_SFT (0x1 << 5)
+#define IRQ4_MCU_SFT 4
+#define IRQ4_MCU_MASK 0x1
+#define IRQ4_MCU_MASK_SFT (0x1 << 4)
+#define IRQ3_MCU_SFT 3
+#define IRQ3_MCU_MASK 0x1
+#define IRQ3_MCU_MASK_SFT (0x1 << 3)
+#define IRQ2_MCU_SFT 2
+#define IRQ2_MCU_MASK 0x1
+#define IRQ2_MCU_MASK_SFT (0x1 << 2)
+#define IRQ1_MCU_SFT 1
+#define IRQ1_MCU_MASK 0x1
+#define IRQ1_MCU_MASK_SFT (0x1 << 1)
+#define IRQ0_MCU_SFT 0
+#define IRQ0_MCU_MASK 0x1
+#define IRQ0_MCU_MASK_SFT (0x1 << 0)
+
+/* AFE_CUSTOM_IRQ_MCU_STATUS */
+#define CUSTOM_IRQ21_MCU_SFT 21
+#define CUSTOM_IRQ21_MCU_MASK 0x1
+#define CUSTOM_IRQ21_MCU_MASK_SFT (0x1 << 21)
+#define CUSTOM_IRQ20_MCU_SFT 20
+#define CUSTOM_IRQ20_MCU_MASK 0x1
+#define CUSTOM_IRQ20_MCU_MASK_SFT (0x1 << 20)
+#define CUSTOM_IRQ19_MCU_SFT 19
+#define CUSTOM_IRQ19_MCU_MASK 0x1
+#define CUSTOM_IRQ19_MCU_MASK_SFT (0x1 << 19)
+#define CUSTOM_IRQ18_MCU_SFT 18
+#define CUSTOM_IRQ18_MCU_MASK 0x1
+#define CUSTOM_IRQ18_MCU_MASK_SFT (0x1 << 18)
+#define CUSTOM_IRQ17_MCU_SFT 17
+#define CUSTOM_IRQ17_MCU_MASK 0x1
+#define CUSTOM_IRQ17_MCU_MASK_SFT (0x1 << 17)
+#define CUSTOM_IRQ16_MCU_SFT 16
+#define CUSTOM_IRQ16_MCU_MASK 0x1
+#define CUSTOM_IRQ16_MCU_MASK_SFT (0x1 << 16)
+#define CUSTOM_IRQ9_MCU_SFT 9
+#define CUSTOM_IRQ9_MCU_MASK 0x1
+#define CUSTOM_IRQ9_MCU_MASK_SFT (0x1 << 9)
+#define CUSTOM_IRQ8_MCU_SFT 8
+#define CUSTOM_IRQ8_MCU_MASK 0x1
+#define CUSTOM_IRQ8_MCU_MASK_SFT (0x1 << 8)
+#define CUSTOM_IRQ7_MCU_SFT 7
+#define CUSTOM_IRQ7_MCU_MASK 0x1
+#define CUSTOM_IRQ7_MCU_MASK_SFT (0x1 << 7)
+#define CUSTOM_IRQ6_MCU_SFT 6
+#define CUSTOM_IRQ6_MCU_MASK 0x1
+#define CUSTOM_IRQ6_MCU_MASK_SFT (0x1 << 6)
+#define CUSTOM_IRQ5_MCU_SFT 5
+#define CUSTOM_IRQ5_MCU_MASK 0x1
+#define CUSTOM_IRQ5_MCU_MASK_SFT (0x1 << 5)
+#define CUSTOM_IRQ4_MCU_SFT 4
+#define CUSTOM_IRQ4_MCU_MASK 0x1
+#define CUSTOM_IRQ4_MCU_MASK_SFT (0x1 << 4)
+#define CUSTOM_IRQ3_MCU_SFT 3
+#define CUSTOM_IRQ3_MCU_MASK 0x1
+#define CUSTOM_IRQ3_MCU_MASK_SFT (0x1 << 3)
+#define CUSTOM_IRQ2_MCU_SFT 2
+#define CUSTOM_IRQ2_MCU_MASK 0x1
+#define CUSTOM_IRQ2_MCU_MASK_SFT (0x1 << 2)
+#define CUSTOM_IRQ1_MCU_SFT 1
+#define CUSTOM_IRQ1_MCU_MASK 0x1
+#define CUSTOM_IRQ1_MCU_MASK_SFT (0x1 << 1)
+#define CUSTOM_IRQ0_MCU_SFT 0
+#define CUSTOM_IRQ0_MCU_MASK 0x1
+#define CUSTOM_IRQ0_MCU_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_CFG */
+#define AFE_IRQ_CLR_CFG_SFT 31
+#define AFE_IRQ_CLR_CFG_MASK 0x1
+#define AFE_IRQ_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ_MCU_CNT_SFT 0
+#define AFE_IRQ_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ0_MCU_CFG0 */
+#define AFE_IRQ0_MCU_DOMAIN_SFT 9
+#define AFE_IRQ0_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ0_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ0_MCU_FS_SFT 4
+#define AFE_IRQ0_MCU_FS_MASK 0x1f
+#define AFE_IRQ0_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ0_MCU_ON_SFT 0
+#define AFE_IRQ0_MCU_ON_MASK 0x1
+#define AFE_IRQ0_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ0_MCU_CFG1 */
+#define AFE_IRQ0_CLR_CFG_SFT 31
+#define AFE_IRQ0_CLR_CFG_MASK 0x1
+#define AFE_IRQ0_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ0_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ0_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ0_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ0_MCU_CNT_SFT 0
+#define AFE_IRQ0_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ0_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ1_MCU_CFG0 */
+#define AFE_IRQ1_MCU_DOMAIN_SFT 9
+#define AFE_IRQ1_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ1_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ1_MCU_FS_SFT 4
+#define AFE_IRQ1_MCU_FS_MASK 0x1f
+#define AFE_IRQ1_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ1_MCU_ON_SFT 0
+#define AFE_IRQ1_MCU_ON_MASK 0x1
+#define AFE_IRQ1_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ1_MCU_CFG1 */
+#define AFE_IRQ1_CLR_CFG_SFT 31
+#define AFE_IRQ1_CLR_CFG_MASK 0x1
+#define AFE_IRQ1_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ1_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ1_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ1_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ1_MCU_CNT_SFT 0
+#define AFE_IRQ1_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ1_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ2_MCU_CFG0 */
+#define AFE_IRQ2_MCU_DOMAIN_SFT 9
+#define AFE_IRQ2_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ2_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ2_MCU_FS_SFT 4
+#define AFE_IRQ2_MCU_FS_MASK 0x1f
+#define AFE_IRQ2_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ2_MCU_ON_SFT 0
+#define AFE_IRQ2_MCU_ON_MASK 0x1
+#define AFE_IRQ2_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ2_MCU_CFG1 */
+#define AFE_IRQ2_CLR_CFG_SFT 31
+#define AFE_IRQ2_CLR_CFG_MASK 0x1
+#define AFE_IRQ2_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ2_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ2_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ2_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ2_MCU_CNT_SFT 0
+#define AFE_IRQ2_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ2_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ3_MCU_CFG0 */
+#define AFE_IRQ3_MCU_DOMAIN_SFT 9
+#define AFE_IRQ3_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ3_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ3_MCU_FS_SFT 4
+#define AFE_IRQ3_MCU_FS_MASK 0x1f
+#define AFE_IRQ3_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ3_MCU_ON_SFT 0
+#define AFE_IRQ3_MCU_ON_MASK 0x1
+#define AFE_IRQ3_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ3_MCU_CFG1 */
+#define AFE_IRQ3_CLR_CFG_SFT 31
+#define AFE_IRQ3_CLR_CFG_MASK 0x1
+#define AFE_IRQ3_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ3_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ3_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ3_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ3_MCU_CNT_SFT 0
+#define AFE_IRQ3_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ3_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ4_MCU_CFG0 */
+#define AFE_IRQ4_MCU_DOMAIN_SFT 9
+#define AFE_IRQ4_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ4_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ4_MCU_FS_SFT 4
+#define AFE_IRQ4_MCU_FS_MASK 0x1f
+#define AFE_IRQ4_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ4_MCU_ON_SFT 0
+#define AFE_IRQ4_MCU_ON_MASK 0x1
+#define AFE_IRQ4_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ4_MCU_CFG1 */
+#define AFE_IRQ4_CLR_CFG_SFT 31
+#define AFE_IRQ4_CLR_CFG_MASK 0x1
+#define AFE_IRQ4_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ4_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ4_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ4_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ4_MCU_CNT_SFT 0
+#define AFE_IRQ4_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ4_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ5_MCU_CFG0 */
+#define AFE_IRQ5_MCU_DOMAIN_SFT 9
+#define AFE_IRQ5_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ5_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ5_MCU_FS_SFT 4
+#define AFE_IRQ5_MCU_FS_MASK 0x1f
+#define AFE_IRQ5_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ5_MCU_ON_SFT 0
+#define AFE_IRQ5_MCU_ON_MASK 0x1
+#define AFE_IRQ5_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ5_MCU_CFG1 */
+#define AFE_IRQ5_CLR_CFG_SFT 31
+#define AFE_IRQ5_CLR_CFG_MASK 0x1
+#define AFE_IRQ5_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ5_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ5_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ5_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ5_MCU_CNT_SFT 0
+#define AFE_IRQ5_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ5_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ6_MCU_CFG0 */
+#define AFE_IRQ6_MCU_DOMAIN_SFT 9
+#define AFE_IRQ6_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ6_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ6_MCU_FS_SFT 4
+#define AFE_IRQ6_MCU_FS_MASK 0x1f
+#define AFE_IRQ6_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ6_MCU_ON_SFT 0
+#define AFE_IRQ6_MCU_ON_MASK 0x1
+#define AFE_IRQ6_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ6_MCU_CFG1 */
+#define AFE_IRQ6_CLR_CFG_SFT 31
+#define AFE_IRQ6_CLR_CFG_MASK 0x1
+#define AFE_IRQ6_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ6_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ6_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ6_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ6_MCU_CNT_SFT 0
+#define AFE_IRQ6_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ6_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ7_MCU_CFG0 */
+#define AFE_IRQ7_MCU_DOMAIN_SFT 9
+#define AFE_IRQ7_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ7_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ7_MCU_FS_SFT 4
+#define AFE_IRQ7_MCU_FS_MASK 0x1f
+#define AFE_IRQ7_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ7_MCU_ON_SFT 0
+#define AFE_IRQ7_MCU_ON_MASK 0x1
+#define AFE_IRQ7_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ7_MCU_CFG1 */
+#define AFE_IRQ7_CLR_CFG_SFT 31
+#define AFE_IRQ7_CLR_CFG_MASK 0x1
+#define AFE_IRQ7_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ7_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ7_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ7_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ7_MCU_CNT_SFT 0
+#define AFE_IRQ7_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ7_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ8_MCU_CFG0 */
+#define AFE_IRQ8_MCU_DOMAIN_SFT 9
+#define AFE_IRQ8_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ8_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ8_MCU_FS_SFT 4
+#define AFE_IRQ8_MCU_FS_MASK 0x1f
+#define AFE_IRQ8_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ8_MCU_ON_SFT 0
+#define AFE_IRQ8_MCU_ON_MASK 0x1
+#define AFE_IRQ8_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ8_MCU_CFG1 */
+#define AFE_IRQ8_CLR_CFG_SFT 31
+#define AFE_IRQ8_CLR_CFG_MASK 0x1
+#define AFE_IRQ8_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ8_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ8_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ8_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ8_MCU_CNT_SFT 0
+#define AFE_IRQ8_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ8_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ9_MCU_CFG0 */
+#define AFE_IRQ9_MCU_DOMAIN_SFT 9
+#define AFE_IRQ9_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ9_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ9_MCU_FS_SFT 4
+#define AFE_IRQ9_MCU_FS_MASK 0x1f
+#define AFE_IRQ9_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ9_MCU_ON_SFT 0
+#define AFE_IRQ9_MCU_ON_MASK 0x1
+#define AFE_IRQ9_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ9_MCU_CFG1 */
+#define AFE_IRQ9_CLR_CFG_SFT 31
+#define AFE_IRQ9_CLR_CFG_MASK 0x1
+#define AFE_IRQ9_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ9_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ9_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ9_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ9_MCU_CNT_SFT 0
+#define AFE_IRQ9_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ9_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ10_MCU_CFG0 */
+#define AFE_IRQ10_MCU_DOMAIN_SFT 9
+#define AFE_IRQ10_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ10_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ10_MCU_FS_SFT 4
+#define AFE_IRQ10_MCU_FS_MASK 0x1f
+#define AFE_IRQ10_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ10_MCU_ON_SFT 0
+#define AFE_IRQ10_MCU_ON_MASK 0x1
+#define AFE_IRQ10_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ10_MCU_CFG1 */
+#define AFE_IRQ10_CLR_CFG_SFT 31
+#define AFE_IRQ10_CLR_CFG_MASK 0x1
+#define AFE_IRQ10_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ10_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ10_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ10_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ10_MCU_CNT_SFT 0
+#define AFE_IRQ10_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ10_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ11_MCU_CFG0 */
+#define AFE_IRQ11_MCU_DOMAIN_SFT 9
+#define AFE_IRQ11_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ11_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ11_MCU_FS_SFT 4
+#define AFE_IRQ11_MCU_FS_MASK 0x1f
+#define AFE_IRQ11_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ11_MCU_ON_SFT 0
+#define AFE_IRQ11_MCU_ON_MASK 0x1
+#define AFE_IRQ11_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ11_MCU_CFG1 */
+#define AFE_IRQ11_CLR_CFG_SFT 31
+#define AFE_IRQ11_CLR_CFG_MASK 0x1
+#define AFE_IRQ11_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ11_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ11_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ11_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ11_MCU_CNT_SFT 0
+#define AFE_IRQ11_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ11_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ12_MCU_CFG0 */
+#define AFE_IRQ12_MCU_DOMAIN_SFT 9
+#define AFE_IRQ12_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ12_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ12_MCU_FS_SFT 4
+#define AFE_IRQ12_MCU_FS_MASK 0x1f
+#define AFE_IRQ12_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ12_MCU_ON_SFT 0
+#define AFE_IRQ12_MCU_ON_MASK 0x1
+#define AFE_IRQ12_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ12_MCU_CFG1 */
+#define AFE_IRQ12_CLR_CFG_SFT 31
+#define AFE_IRQ12_CLR_CFG_MASK 0x1
+#define AFE_IRQ12_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ12_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ12_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ12_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ12_MCU_CNT_SFT 0
+#define AFE_IRQ12_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ12_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ13_MCU_CFG0 */
+#define AFE_IRQ13_MCU_DOMAIN_SFT 9
+#define AFE_IRQ13_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ13_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ13_MCU_FS_SFT 4
+#define AFE_IRQ13_MCU_FS_MASK 0x1f
+#define AFE_IRQ13_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ13_MCU_ON_SFT 0
+#define AFE_IRQ13_MCU_ON_MASK 0x1
+#define AFE_IRQ13_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ13_MCU_CFG1 */
+#define AFE_IRQ13_CLR_CFG_SFT 31
+#define AFE_IRQ13_CLR_CFG_MASK 0x1
+#define AFE_IRQ13_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ13_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ13_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ13_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ13_MCU_CNT_SFT 0
+#define AFE_IRQ13_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ13_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ14_MCU_CFG0 */
+#define AFE_IRQ14_MCU_DOMAIN_SFT 9
+#define AFE_IRQ14_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ14_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ14_MCU_FS_SFT 4
+#define AFE_IRQ14_MCU_FS_MASK 0x1f
+#define AFE_IRQ14_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ14_MCU_ON_SFT 0
+#define AFE_IRQ14_MCU_ON_MASK 0x1
+#define AFE_IRQ14_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ14_MCU_CFG1 */
+#define AFE_IRQ14_CLR_CFG_SFT 31
+#define AFE_IRQ14_CLR_CFG_MASK 0x1
+#define AFE_IRQ14_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ14_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ14_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ14_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ14_MCU_CNT_SFT 0
+#define AFE_IRQ14_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ14_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ15_MCU_CFG0 */
+#define AFE_IRQ15_MCU_DOMAIN_SFT 9
+#define AFE_IRQ15_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ15_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ15_MCU_FS_SFT 4
+#define AFE_IRQ15_MCU_FS_MASK 0x1f
+#define AFE_IRQ15_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ15_MCU_ON_SFT 0
+#define AFE_IRQ15_MCU_ON_MASK 0x1
+#define AFE_IRQ15_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ15_MCU_CFG1 */
+#define AFE_IRQ15_CLR_CFG_SFT 31
+#define AFE_IRQ15_CLR_CFG_MASK 0x1
+#define AFE_IRQ15_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ15_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ15_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ15_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ15_MCU_CNT_SFT 0
+#define AFE_IRQ15_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ15_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ16_MCU_CFG0 */
+#define AFE_IRQ16_MCU_DOMAIN_SFT 9
+#define AFE_IRQ16_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ16_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ16_MCU_FS_SFT 4
+#define AFE_IRQ16_MCU_FS_MASK 0x1f
+#define AFE_IRQ16_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ16_MCU_ON_SFT 0
+#define AFE_IRQ16_MCU_ON_MASK 0x1
+#define AFE_IRQ16_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ16_MCU_CFG1 */
+#define AFE_IRQ16_CLR_CFG_SFT 31
+#define AFE_IRQ16_CLR_CFG_MASK 0x1
+#define AFE_IRQ16_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ16_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ16_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ16_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ16_MCU_CNT_SFT 0
+#define AFE_IRQ16_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ16_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ17_MCU_CFG0 */
+#define AFE_IRQ17_MCU_DOMAIN_SFT 9
+#define AFE_IRQ17_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ17_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ17_MCU_FS_SFT 4
+#define AFE_IRQ17_MCU_FS_MASK 0x1f
+#define AFE_IRQ17_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ17_MCU_ON_SFT 0
+#define AFE_IRQ17_MCU_ON_MASK 0x1
+#define AFE_IRQ17_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ17_MCU_CFG1 */
+#define AFE_IRQ17_CLR_CFG_SFT 31
+#define AFE_IRQ17_CLR_CFG_MASK 0x1
+#define AFE_IRQ17_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ17_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ17_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ17_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ17_MCU_CNT_SFT 0
+#define AFE_IRQ17_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ17_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ18_MCU_CFG0 */
+#define AFE_IRQ18_MCU_DOMAIN_SFT 9
+#define AFE_IRQ18_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ18_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ18_MCU_FS_SFT 4
+#define AFE_IRQ18_MCU_FS_MASK 0x1f
+#define AFE_IRQ18_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ18_MCU_ON_SFT 0
+#define AFE_IRQ18_MCU_ON_MASK 0x1
+#define AFE_IRQ18_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ18_MCU_CFG1 */
+#define AFE_IRQ18_CLR_CFG_SFT 31
+#define AFE_IRQ18_CLR_CFG_MASK 0x1
+#define AFE_IRQ18_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ18_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ18_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ18_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ18_MCU_CNT_SFT 0
+#define AFE_IRQ18_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ18_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ19_MCU_CFG0 */
+#define AFE_IRQ19_MCU_DOMAIN_SFT 9
+#define AFE_IRQ19_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ19_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ19_MCU_FS_SFT 4
+#define AFE_IRQ19_MCU_FS_MASK 0x1f
+#define AFE_IRQ19_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ19_MCU_ON_SFT 0
+#define AFE_IRQ19_MCU_ON_MASK 0x1
+#define AFE_IRQ19_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ19_MCU_CFG1 */
+#define AFE_IRQ19_CLR_CFG_SFT 31
+#define AFE_IRQ19_CLR_CFG_MASK 0x1
+#define AFE_IRQ19_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ19_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ19_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ19_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ19_MCU_CNT_SFT 0
+#define AFE_IRQ19_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ19_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ20_MCU_CFG0 */
+#define AFE_IRQ20_MCU_DOMAIN_SFT 9
+#define AFE_IRQ20_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ20_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ20_MCU_FS_SFT 4
+#define AFE_IRQ20_MCU_FS_MASK 0x1f
+#define AFE_IRQ20_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ20_MCU_ON_SFT 0
+#define AFE_IRQ20_MCU_ON_MASK 0x1
+#define AFE_IRQ20_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ20_MCU_CFG1 */
+#define AFE_IRQ20_CLR_CFG_SFT 31
+#define AFE_IRQ20_CLR_CFG_MASK 0x1
+#define AFE_IRQ20_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ20_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ20_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ20_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ20_MCU_CNT_SFT 0
+#define AFE_IRQ20_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ20_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ21_MCU_CFG0 */
+#define AFE_IRQ21_MCU_DOMAIN_SFT 9
+#define AFE_IRQ21_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ21_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ21_MCU_FS_SFT 4
+#define AFE_IRQ21_MCU_FS_MASK 0x1f
+#define AFE_IRQ21_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ21_MCU_ON_SFT 0
+#define AFE_IRQ21_MCU_ON_MASK 0x1
+#define AFE_IRQ21_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ21_MCU_CFG1 */
+#define AFE_IRQ21_CLR_CFG_SFT 31
+#define AFE_IRQ21_CLR_CFG_MASK 0x1
+#define AFE_IRQ21_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ21_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ21_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ21_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ21_MCU_CNT_SFT 0
+#define AFE_IRQ21_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ21_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ22_MCU_CFG0 */
+#define AFE_IRQ22_MCU_DOMAIN_SFT 9
+#define AFE_IRQ22_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ22_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ22_MCU_FS_SFT 4
+#define AFE_IRQ22_MCU_FS_MASK 0x1f
+#define AFE_IRQ22_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ22_MCU_ON_SFT 0
+#define AFE_IRQ22_MCU_ON_MASK 0x1
+#define AFE_IRQ22_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ22_MCU_CFG1 */
+#define AFE_IRQ22_CLR_CFG_SFT 31
+#define AFE_IRQ22_CLR_CFG_MASK 0x1
+#define AFE_IRQ22_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ22_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ22_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ22_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ22_MCU_CNT_SFT 0
+#define AFE_IRQ22_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ22_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ23_MCU_CFG0 */
+#define AFE_IRQ23_MCU_DOMAIN_SFT 9
+#define AFE_IRQ23_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ23_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ23_MCU_FS_SFT 4
+#define AFE_IRQ23_MCU_FS_MASK 0x1f
+#define AFE_IRQ23_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ23_MCU_ON_SFT 0
+#define AFE_IRQ23_MCU_ON_MASK 0x1
+#define AFE_IRQ23_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ23_MCU_CFG1 */
+#define AFE_IRQ23_CLR_CFG_SFT 31
+#define AFE_IRQ23_CLR_CFG_MASK 0x1
+#define AFE_IRQ23_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ23_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ23_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ23_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ23_MCU_CNT_SFT 0
+#define AFE_IRQ23_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ23_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ24_MCU_CFG0 */
+#define AFE_IRQ24_MCU_DOMAIN_SFT 9
+#define AFE_IRQ24_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ24_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ24_MCU_FS_SFT 4
+#define AFE_IRQ24_MCU_FS_MASK 0x1f
+#define AFE_IRQ24_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ24_MCU_ON_SFT 0
+#define AFE_IRQ24_MCU_ON_MASK 0x1
+#define AFE_IRQ24_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ24_MCU_CFG1 */
+#define AFE_IRQ24_CLR_CFG_SFT 31
+#define AFE_IRQ24_CLR_CFG_MASK 0x1
+#define AFE_IRQ24_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ24_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ24_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ24_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ24_MCU_CNT_SFT 0
+#define AFE_IRQ24_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ24_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ25_MCU_CFG0 */
+#define AFE_IRQ25_MCU_DOMAIN_SFT 9
+#define AFE_IRQ25_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ25_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ25_MCU_FS_SFT 4
+#define AFE_IRQ25_MCU_FS_MASK 0x1f
+#define AFE_IRQ25_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ25_MCU_ON_SFT 0
+#define AFE_IRQ25_MCU_ON_MASK 0x1
+#define AFE_IRQ25_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ25_MCU_CFG1 */
+#define AFE_IRQ25_CLR_CFG_SFT 31
+#define AFE_IRQ25_CLR_CFG_MASK 0x1
+#define AFE_IRQ25_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ25_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ25_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ25_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ25_MCU_CNT_SFT 0
+#define AFE_IRQ25_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ25_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ26_MCU_CFG0 */
+#define AFE_IRQ26_MCU_DOMAIN_SFT 9
+#define AFE_IRQ26_MCU_DOMAIN_MASK 0x7
+#define AFE_IRQ26_MCU_DOMAIN_MASK_SFT (0x7 << 9)
+#define AFE_IRQ26_MCU_FS_SFT 4
+#define AFE_IRQ26_MCU_FS_MASK 0x1f
+#define AFE_IRQ26_MCU_FS_MASK_SFT (0x1f << 4)
+#define AFE_IRQ26_MCU_ON_SFT 0
+#define AFE_IRQ26_MCU_ON_MASK 0x1
+#define AFE_IRQ26_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ26_MCU_CFG1 */
+#define AFE_IRQ26_CLR_CFG_SFT 31
+#define AFE_IRQ26_CLR_CFG_MASK 0x1
+#define AFE_IRQ26_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_IRQ26_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_IRQ26_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_IRQ26_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_IRQ26_MCU_CNT_SFT 0
+#define AFE_IRQ26_MCU_CNT_MASK 0xffffff
+#define AFE_IRQ26_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_CUSTOM_IRQ0_MCU_CFG0 */
+#define AFE_CUSTOM_IRQ0_MCU_ON_SFT 0
+#define AFE_CUSTOM_IRQ0_MCU_ON_MASK 0x1
+#define AFE_CUSTOM_IRQ0_MCU_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_CUSTOM_IRQ0_CNT_MON */
+#define AFE_CUSTOM_IRQ0_CNT_MON_SFT 0
+#define AFE_CUSTOM_IRQ0_CNT_MON_MASK 0xffffff
+#define AFE_CUSTOM_IRQ0_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_CUSTOM_IRQ0_MCU_CFG1 */
+#define AFE_CUSTOM_IRQ0_CLR_CFG_SFT 31
+#define AFE_CUSTOM_IRQ0_CLR_CFG_MASK 0x1
+#define AFE_CUSTOM_IRQ0_CLR_CFG_MASK_SFT (0x1 << 31)
+#define AFE_CUSTOM_IRQ0_MISS_FLAG_CLR_CFG_SFT 30
+#define AFE_CUSTOM_IRQ0_MISS_FLAG_CLR_CFG_MASK 0x1
+#define AFE_CUSTOM_IRQ0_MISS_FLAG_CLR_CFG_MASK_SFT (0x1 << 30)
+#define AFE_CUSTOM_IRQ0_MCU_CNT_SFT 0
+#define AFE_CUSTOM_IRQ0_MCU_CNT_MASK 0xffffff
+#define AFE_CUSTOM_IRQ0_MCU_CNT_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ_MCU_MON0 */
+#define AFE_IRQ26_MISS_FLAG_SFT 26
+#define AFE_IRQ26_MISS_FLAG_MASK 0x1
+#define AFE_IRQ26_MISS_FLAG_MASK_SFT (0x1 << 26)
+#define AFE_IRQ25_MISS_FLAG_SFT 25
+#define AFE_IRQ25_MISS_FLAG_MASK 0x1
+#define AFE_IRQ25_MISS_FLAG_MASK_SFT (0x1 << 25)
+#define AFE_IRQ24_MISS_FLAG_SFT 24
+#define AFE_IRQ24_MISS_FLAG_MASK 0x1
+#define AFE_IRQ24_MISS_FLAG_MASK_SFT (0x1 << 24)
+#define AFE_IRQ23_MISS_FLAG_SFT 23
+#define AFE_IRQ23_MISS_FLAG_MASK 0x1
+#define AFE_IRQ23_MISS_FLAG_MASK_SFT (0x1 << 23)
+#define AFE_IRQ22_MISS_FLAG_SFT 22
+#define AFE_IRQ22_MISS_FLAG_MASK 0x1
+#define AFE_IRQ22_MISS_FLAG_MASK_SFT (0x1 << 22)
+#define AFE_IRQ21_MISS_FLAG_SFT 21
+#define AFE_IRQ21_MISS_FLAG_MASK 0x1
+#define AFE_IRQ21_MISS_FLAG_MASK_SFT (0x1 << 21)
+#define AFE_IRQ20_MISS_FLAG_SFT 20
+#define AFE_IRQ20_MISS_FLAG_MASK 0x1
+#define AFE_IRQ20_MISS_FLAG_MASK_SFT (0x1 << 20)
+#define AFE_IRQ19_MISS_FLAG_SFT 19
+#define AFE_IRQ19_MISS_FLAG_MASK 0x1
+#define AFE_IRQ19_MISS_FLAG_MASK_SFT (0x1 << 19)
+#define AFE_IRQ18_MISS_FLAG_SFT 18
+#define AFE_IRQ18_MISS_FLAG_MASK 0x1
+#define AFE_IRQ18_MISS_FLAG_MASK_SFT (0x1 << 18)
+#define AFE_IRQ17_MISS_FLAG_SFT 17
+#define AFE_IRQ17_MISS_FLAG_MASK 0x1
+#define AFE_IRQ17_MISS_FLAG_MASK_SFT (0x1 << 17)
+#define AFE_IRQ16_MISS_FLAG_SFT 16
+#define AFE_IRQ16_MISS_FLAG_MASK 0x1
+#define AFE_IRQ16_MISS_FLAG_MASK_SFT (0x1 << 16)
+#define AFE_IRQ15_MISS_FLAG_SFT 15
+#define AFE_IRQ15_MISS_FLAG_MASK 0x1
+#define AFE_IRQ15_MISS_FLAG_MASK_SFT (0x1 << 15)
+#define AFE_IRQ14_MISS_FLAG_SFT 14
+#define AFE_IRQ14_MISS_FLAG_MASK 0x1
+#define AFE_IRQ14_MISS_FLAG_MASK_SFT (0x1 << 14)
+#define AFE_IRQ13_MISS_FLAG_SFT 13
+#define AFE_IRQ13_MISS_FLAG_MASK 0x1
+#define AFE_IRQ13_MISS_FLAG_MASK_SFT (0x1 << 13)
+#define AFE_IRQ12_MISS_FLAG_SFT 12
+#define AFE_IRQ12_MISS_FLAG_MASK 0x1
+#define AFE_IRQ12_MISS_FLAG_MASK_SFT (0x1 << 12)
+#define AFE_IRQ11_MISS_FLAG_SFT 11
+#define AFE_IRQ11_MISS_FLAG_MASK 0x1
+#define AFE_IRQ11_MISS_FLAG_MASK_SFT (0x1 << 11)
+#define AFE_IRQ10_MISS_FLAG_SFT 10
+#define AFE_IRQ10_MISS_FLAG_MASK 0x1
+#define AFE_IRQ10_MISS_FLAG_MASK_SFT (0x1 << 10)
+#define AFE_IRQ9_MISS_FLAG_SFT 9
+#define AFE_IRQ9_MISS_FLAG_MASK 0x1
+#define AFE_IRQ9_MISS_FLAG_MASK_SFT (0x1 << 9)
+#define AFE_IRQ8_MISS_FLAG_SFT 8
+#define AFE_IRQ8_MISS_FLAG_MASK 0x1
+#define AFE_IRQ8_MISS_FLAG_MASK_SFT (0x1 << 8)
+#define AFE_IRQ7_MISS_FLAG_SFT 7
+#define AFE_IRQ7_MISS_FLAG_MASK 0x1
+#define AFE_IRQ7_MISS_FLAG_MASK_SFT (0x1 << 7)
+#define AFE_IRQ6_MISS_FLAG_SFT 6
+#define AFE_IRQ6_MISS_FLAG_MASK 0x1
+#define AFE_IRQ6_MISS_FLAG_MASK_SFT (0x1 << 6)
+#define AFE_IRQ5_MISS_FLAG_SFT 5
+#define AFE_IRQ5_MISS_FLAG_MASK 0x1
+#define AFE_IRQ5_MISS_FLAG_MASK_SFT (0x1 << 5)
+#define AFE_IRQ4_MISS_FLAG_SFT 4
+#define AFE_IRQ4_MISS_FLAG_MASK 0x1
+#define AFE_IRQ4_MISS_FLAG_MASK_SFT (0x1 << 4)
+#define AFE_IRQ3_MISS_FLAG_SFT 3
+#define AFE_IRQ3_MISS_FLAG_MASK 0x1
+#define AFE_IRQ3_MISS_FLAG_MASK_SFT (0x1 << 3)
+#define AFE_IRQ2_MISS_FLAG_SFT 2
+#define AFE_IRQ2_MISS_FLAG_MASK 0x1
+#define AFE_IRQ2_MISS_FLAG_MASK_SFT (0x1 << 2)
+#define AFE_IRQ1_MISS_FLAG_SFT 1
+#define AFE_IRQ1_MISS_FLAG_MASK 0x1
+#define AFE_IRQ1_MISS_FLAG_MASK_SFT (0x1 << 1)
+#define AFE_IRQ0_MISS_FLAG_SFT 0
+#define AFE_IRQ0_MISS_FLAG_MASK 0x1
+#define AFE_IRQ0_MISS_FLAG_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_MON1 */
+#define AFE_CUSTOM_IRQ21_MISS_FLAG_SFT 21
+#define AFE_CUSTOM_IRQ21_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ21_MISS_FLAG_MASK_SFT (0x1 << 21)
+#define AFE_CUSTOM_IRQ20_MISS_FLAG_SFT 20
+#define AFE_CUSTOM_IRQ20_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ20_MISS_FLAG_MASK_SFT (0x1 << 20)
+#define AFE_CUSTOM_IRQ19_MISS_FLAG_SFT 19
+#define AFE_CUSTOM_IRQ19_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ19_MISS_FLAG_MASK_SFT (0x1 << 19)
+#define AFE_CUSTOM_IRQ18_MISS_FLAG_SFT 18
+#define AFE_CUSTOM_IRQ18_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ18_MISS_FLAG_MASK_SFT (0x1 << 18)
+#define AFE_CUSTOM_IRQ17_MISS_FLAG_SFT 17
+#define AFE_CUSTOM_IRQ17_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ17_MISS_FLAG_MASK_SFT (0x1 << 17)
+#define AFE_CUSTOM_IRQ16_MISS_FLAG_SFT 16
+#define AFE_CUSTOM_IRQ16_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ16_MISS_FLAG_MASK_SFT (0x1 << 16)
+#define AFE_CUSTOM_IRQ9_MISS_FLAG_SFT 9
+#define AFE_CUSTOM_IRQ9_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ9_MISS_FLAG_MASK_SFT (0x1 << 9)
+#define AFE_CUSTOM_IRQ8_MISS_FLAG_SFT 8
+#define AFE_CUSTOM_IRQ8_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ8_MISS_FLAG_MASK_SFT (0x1 << 8)
+#define AFE_CUSTOM_IRQ7_MISS_FLAG_SFT 7
+#define AFE_CUSTOM_IRQ7_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ7_MISS_FLAG_MASK_SFT (0x1 << 7)
+#define AFE_CUSTOM_IRQ6_MISS_FLAG_SFT 6
+#define AFE_CUSTOM_IRQ6_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ6_MISS_FLAG_MASK_SFT (0x1 << 6)
+#define AFE_CUSTOM_IRQ5_MISS_FLAG_SFT 5
+#define AFE_CUSTOM_IRQ5_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ5_MISS_FLAG_MASK_SFT (0x1 << 5)
+#define AFE_CUSTOM_IRQ4_MISS_FLAG_SFT 4
+#define AFE_CUSTOM_IRQ4_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ4_MISS_FLAG_MASK_SFT (0x1 << 4)
+#define AFE_CUSTOM_IRQ3_MISS_FLAG_SFT 3
+#define AFE_CUSTOM_IRQ3_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ3_MISS_FLAG_MASK_SFT (0x1 << 3)
+#define AFE_CUSTOM_IRQ2_MISS_FLAG_SFT 2
+#define AFE_CUSTOM_IRQ2_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ2_MISS_FLAG_MASK_SFT (0x1 << 2)
+#define AFE_CUSTOM_IRQ1_MISS_FLAG_SFT 1
+#define AFE_CUSTOM_IRQ1_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ1_MISS_FLAG_MASK_SFT (0x1 << 1)
+#define AFE_CUSTOM_IRQ0_MISS_FLAG_SFT 0
+#define AFE_CUSTOM_IRQ0_MISS_FLAG_MASK 0x1
+#define AFE_CUSTOM_IRQ0_MISS_FLAG_MASK_SFT (0x1 << 0)
+
+/* AFE_IRQ_MCU_MON2 */
+#define AFE_IRQ_B_R_CNT_SFT 8
+#define AFE_IRQ_B_R_CNT_MASK 0xff
+#define AFE_IRQ_B_R_CNT_MASK_SFT (0xff << 8)
+#define AFE_IRQ_B_F_CNT_SFT 0
+#define AFE_IRQ_B_F_CNT_MASK 0xff
+#define AFE_IRQ_B_F_CNT_MASK_SFT (0xff << 0)
+
+/* AFE_IRQ0_CNT_MON */
+#define AFE_IRQ0_CNT_MON_SFT 0
+#define AFE_IRQ0_CNT_MON_MASK 0xffffff
+#define AFE_IRQ0_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ1_CNT_MON */
+#define AFE_IRQ1_CNT_MON_SFT 0
+#define AFE_IRQ1_CNT_MON_MASK 0xffffff
+#define AFE_IRQ1_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ2_CNT_MON */
+#define AFE_IRQ2_CNT_MON_SFT 0
+#define AFE_IRQ2_CNT_MON_MASK 0xffffff
+#define AFE_IRQ2_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ3_CNT_MON */
+#define AFE_IRQ3_CNT_MON_SFT 0
+#define AFE_IRQ3_CNT_MON_MASK 0xffffff
+#define AFE_IRQ3_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ4_CNT_MON */
+#define AFE_IRQ4_CNT_MON_SFT 0
+#define AFE_IRQ4_CNT_MON_MASK 0xffffff
+#define AFE_IRQ4_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ5_CNT_MON */
+#define AFE_IRQ5_CNT_MON_SFT 0
+#define AFE_IRQ5_CNT_MON_MASK 0xffffff
+#define AFE_IRQ5_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ6_CNT_MON */
+#define AFE_IRQ6_CNT_MON_SFT 0
+#define AFE_IRQ6_CNT_MON_MASK 0xffffff
+#define AFE_IRQ6_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ7_CNT_MON */
+#define AFE_IRQ7_CNT_MON_SFT 0
+#define AFE_IRQ7_CNT_MON_MASK 0xffffff
+#define AFE_IRQ7_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ8_CNT_MON */
+#define AFE_IRQ8_CNT_MON_SFT 0
+#define AFE_IRQ8_CNT_MON_MASK 0xffffff
+#define AFE_IRQ8_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ9_CNT_MON */
+#define AFE_IRQ9_CNT_MON_SFT 0
+#define AFE_IRQ9_CNT_MON_MASK 0xffffff
+#define AFE_IRQ9_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ10_CNT_MON */
+#define AFE_IRQ10_CNT_MON_SFT 0
+#define AFE_IRQ10_CNT_MON_MASK 0xffffff
+#define AFE_IRQ10_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ11_CNT_MON */
+#define AFE_IRQ11_CNT_MON_SFT 0
+#define AFE_IRQ11_CNT_MON_MASK 0xffffff
+#define AFE_IRQ11_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ12_CNT_MON */
+#define AFE_IRQ12_CNT_MON_SFT 0
+#define AFE_IRQ12_CNT_MON_MASK 0xffffff
+#define AFE_IRQ12_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ13_CNT_MON */
+#define AFE_IRQ13_CNT_MON_SFT 0
+#define AFE_IRQ13_CNT_MON_MASK 0xffffff
+#define AFE_IRQ13_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ14_CNT_MON */
+#define AFE_IRQ14_CNT_MON_SFT 0
+#define AFE_IRQ14_CNT_MON_MASK 0xffffff
+#define AFE_IRQ14_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ15_CNT_MON */
+#define AFE_IRQ15_CNT_MON_SFT 0
+#define AFE_IRQ15_CNT_MON_MASK 0xffffff
+#define AFE_IRQ15_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ16_CNT_MON */
+#define AFE_IRQ16_CNT_MON_SFT 0
+#define AFE_IRQ16_CNT_MON_MASK 0xffffff
+#define AFE_IRQ16_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ17_CNT_MON */
+#define AFE_IRQ17_CNT_MON_SFT 0
+#define AFE_IRQ17_CNT_MON_MASK 0xffffff
+#define AFE_IRQ17_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ18_CNT_MON */
+#define AFE_IRQ18_CNT_MON_SFT 0
+#define AFE_IRQ18_CNT_MON_MASK 0xffffff
+#define AFE_IRQ18_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ19_CNT_MON */
+#define AFE_IRQ19_CNT_MON_SFT 0
+#define AFE_IRQ19_CNT_MON_MASK 0xffffff
+#define AFE_IRQ19_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ20_CNT_MON */
+#define AFE_IRQ20_CNT_MON_SFT 0
+#define AFE_IRQ20_CNT_MON_MASK 0xffffff
+#define AFE_IRQ20_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ21_CNT_MON */
+#define AFE_IRQ21_CNT_MON_SFT 0
+#define AFE_IRQ21_CNT_MON_MASK 0xffffff
+#define AFE_IRQ21_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ22_CNT_MON */
+#define AFE_IRQ22_CNT_MON_SFT 0
+#define AFE_IRQ22_CNT_MON_MASK 0xffffff
+#define AFE_IRQ22_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ23_CNT_MON */
+#define AFE_IRQ23_CNT_MON_SFT 0
+#define AFE_IRQ23_CNT_MON_MASK 0xffffff
+#define AFE_IRQ23_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ24_CNT_MON */
+#define AFE_IRQ24_CNT_MON_SFT 0
+#define AFE_IRQ24_CNT_MON_MASK 0xffffff
+#define AFE_IRQ24_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ25_CNT_MON */
+#define AFE_IRQ25_CNT_MON_SFT 0
+#define AFE_IRQ25_CNT_MON_MASK 0xffffff
+#define AFE_IRQ25_CNT_MON_MASK_SFT (0xffffff << 0)
+
+/* AFE_IRQ26_CNT_MON */
+#define AFE_IRQ26_CNT_MON_SFT 0
+#define AFE_IRQ26_CNT_MON_MASK 0xffffff
+#define AFE_IRQ26_CNT_MON_MASK_SFT (0xffffff << 0)
+
+ /* AFE_GAIN0_CON0 */
+ /* AFE_GAIN1_CON0 */
+ /* AFE_GAIN2_CON0 */
+ /* AFE_GAIN3_CON0 */
+#define GAIN_TARGET_SYNC_ON_SFT 24
+#define GAIN_TARGET_SYNC_ON_MASK 0x1
+#define GAIN_TARGET_SYNC_ON_MASK_SFT (0x1 << 24)
+#define GAIN_TIMEOUT_SFT 18
+#define GAIN_TIMEOUT_MASK 0x3f
+#define GAIN_TIMEOUT_MASK_SFT (0x3f << 18)
+#define GAIN_TRIG_SFT 17
+#define GAIN_TRIG_MASK 0x1
+#define GAIN_TRIG_MASK_SFT (0x1 << 17)
+#define GAIN_ON_SFT 16
+#define GAIN_ON_MASK 0x1
+#define GAIN_ON_MASK_SFT (0x1 << 16)
+#define GAIN_SAMPLE_PER_STEP_SFT 8
+#define GAIN_SAMPLE_PER_STEP_MASK 0xff
+#define GAIN_SAMPLE_PER_STEP_MASK_SFT (0xff << 8)
+#define GAIN_SEL_DOMAIN_SFT 5
+#define GAIN_SEL_DOMAIN_MASK 0x7
+#define GAIN_SEL_DOMAIN_MASK_SFT (0x7 << 5)
+#define GAIN_SEL_FS_SFT 0
+#define GAIN_SEL_FS_MASK 0x1f
+#define GAIN_SEL_FS_MASK_SFT (0x1f << 0)
+
+ /* AFE_GAIN0_CON1_R */
+ /* AFE_GAIN1_CON1_R */
+ /* AFE_GAIN2_CON1_R */
+ /* AFE_GAIN3_CON1_R */
+#define GAIN_TARGET_R_SFT 0
+#define GAIN_TARGET_R_MASK 0xffffffff
+#define GAIN_TARGET_R_MASK_SFT (0xffffffff << 0)
+
+ /* AFE_GAIN0_CON1_L */
+ /* AFE_GAIN1_CON1_L */
+ /* AFE_GAIN2_CON1_L */
+ /* AFE_GAIN3_CON1_L */
+#define GAIN_TARGET_L_SFT 0
+#define GAIN_TARGET_L_MASK 0xffffffff
+#define GAIN_TARGET_L_MASK_SFT (0xffffffff << 0)
+
+ /* AFE_GAIN0_CON2 */
+ /* AFE_GAIN1_CON2 */
+ /* AFE_GAIN2_CON2 */
+ /* AFE_GAIN3_CON2 */
+#define GAIN_DOWN_STEP_SFT 0
+#define GAIN_DOWN_STEP_MASK 0x3fffff
+#define GAIN_DOWN_STEP_MASK_SFT (0x3fffff << 0)
+
+ /* AFE_GAIN0_CON3 */
+ /* AFE_GAIN1_CON3 */
+ /* AFE_GAIN2_CON3 */
+ /* AFE_GAIN3_CON3 */
+#define GAIN_UP_STEP_SFT 0
+#define GAIN_UP_STEP_MASK 0x3fffff
+#define GAIN_UP_STEP_MASK_SFT (0x3fffff << 0)
+
+ /* AFE_GAIN0_CUR_R */
+ /* AFE_GAIN1_CUR_R */
+ /* AFE_GAIN2_CUR_R */
+ /* AFE_GAIN3_CUR_R */
+#define AFE_GAIN_CUR_R_SFT 0
+#define AFE_GAIN_CUR_R_MASK 0xffffffff
+#define AFE_GAIN_CUR_R_MASK_SFT (0xffffffff << 0)
+
+ /* AFE_GAIN0_CUR_L */
+ /* AFE_GAIN1_CUR_L */
+ /* AFE_GAIN2_CUR_L */
+ /* AFE_GAIN3_CUR_L */
+#define AFE_GAIN_CUR_L_SFT 0
+#define AFE_GAIN_CUR_L_MASK 0xffffffff
+#define AFE_GAIN_CUR_L_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_IPM_VER_MON */
+#define RG_DL_IPM_VER_MON_SFT 0
+#define RG_DL_IPM_VER_MON_MASK 0xffffffff
+#define RG_DL_IPM_VER_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_SRC_CON0 */
+#define AFE_DL_INPUT_MODE_CTL_SFT 24
+#define AFE_DL_INPUT_MODE_CTL_MASK 0x1f
+#define AFE_DL_INPUT_MODE_CTL_MASK_SFT (0x1f << 24)
+#define AFE_DL_CH1_SATURATION_EN_CTL_SFT 21
+#define AFE_DL_CH1_SATURATION_EN_CTL_MASK 0x1
+#define AFE_DL_CH1_SATURATION_EN_CTL_MASK_SFT (0x1 << 21)
+#define AFE_DL_CH2_SATURATION_EN_CTL_SFT 20
+#define AFE_DL_CH2_SATURATION_EN_CTL_MASK 0x1
+#define AFE_DL_CH2_SATURATION_EN_CTL_MASK_SFT (0x1 << 20)
+#define AFE_DL_OUTPUT_SEL_CTL_SFT 18
+#define AFE_DL_OUTPUT_SEL_CTL_MASK 0x3
+#define AFE_DL_OUTPUT_SEL_CTL_MASK_SFT (0x3 << 18)
+#define AFE_DL_FADEIN_0START_EN_SFT 16
+#define AFE_DL_FADEIN_0START_EN_MASK 0x3
+#define AFE_DL_FADEIN_0START_EN_MASK_SFT (0x3 << 16)
+#define AFE_DL_DISABLE_HW_CG_CTL_SFT 15
+#define AFE_DL_DISABLE_HW_CG_CTL_MASK 0x1
+#define AFE_DL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 15)
+#define AFE_DL_MUTE_CH1_OFF_CTL_PRE_SFT 12
+#define AFE_DL_MUTE_CH1_OFF_CTL_PRE_MASK 0x1
+#define AFE_DL_MUTE_CH1_OFF_CTL_PRE_MASK_SFT (0x1 << 12)
+#define AFE_DL_MUTE_CH2_OFF_CTL_PRE_SFT 11
+#define AFE_DL_MUTE_CH2_OFF_CTL_PRE_MASK 0x1
+#define AFE_DL_MUTE_CH2_OFF_CTL_PRE_MASK_SFT (0x1 << 11)
+#define AFE_DL_ARAMPSP_CTL_PRE_SFT 9
+#define AFE_DL_ARAMPSP_CTL_PRE_MASK 0x3
+#define AFE_DL_ARAMPSP_CTL_PRE_MASK_SFT (0x3 << 9)
+#define AFE_DL_VOICE_MODE_CTL_PRE_SFT 5
+#define AFE_DL_VOICE_MODE_CTL_PRE_MASK 0x1
+#define AFE_DL_VOICE_MODE_CTL_PRE_MASK_SFT (0x1 << 5)
+#define AFE_DL_MUTE_CH1_ON_CTL_PRE_SFT 4
+#define AFE_DL_MUTE_CH1_ON_CTL_PRE_MASK 0x1
+#define AFE_DL_MUTE_CH1_ON_CTL_PRE_MASK_SFT (0x1 << 4)
+#define AFE_DL_MUTE_CH2_ON_CTL_PRE_SFT 3
+#define AFE_DL_MUTE_CH2_ON_CTL_PRE_MASK 0x1
+#define AFE_DL_MUTE_CH2_ON_CTL_PRE_MASK_SFT (0x1 << 3)
+#define AFE_DL_GAIN_ON_CTL_PRE_SFT 1
+#define AFE_DL_GAIN_ON_CTL_PRE_MASK 0x1
+#define AFE_DL_GAIN_ON_CTL_PRE_MASK_SFT (0x1 << 1)
+#define AFE_DL_SRC_ON_TMP_CTL_PRE_SFT 0
+#define AFE_DL_SRC_ON_TMP_CTL_PRE_MASK 0x1
+#define AFE_DL_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_DL_SRC_CON1 */
+#define AFE_DL_GAIN1_CTL_PRE_SFT 16
+#define AFE_DL_GAIN1_CTL_PRE_MASK 0xffff
+#define AFE_DL_GAIN1_CTL_PRE_MASK_SFT (0xffff << 16)
+#define AFE_DL_GAIN2_CTL_PRE_SFT 0
+#define AFE_DL_GAIN2_CTL_PRE_MASK 0xffff
+#define AFE_DL_GAIN2_CTL_PRE_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_DL_SRC_DEBUG_MON0 */
+#define AFE_DL_SLT_CNT_FLAG_CTL_SFT 15
+#define AFE_DL_SLT_CNT_FLAG_CTL_MASK 0x1
+#define AFE_DL_SLT_CNT_FLAG_CTL_MASK_SFT (0x1 << 15)
+#define AFE_DL_INI_SRAM_FINISH_CTL_SFT 12
+#define AFE_DL_INI_SRAM_FINISH_CTL_MASK 0x1
+#define AFE_DL_INI_SRAM_FINISH_CTL_MASK_SFT (0x1 << 12)
+#define AFE_DL_SLT_COUNTER_CTL_SFT 0
+#define AFE_DL_SLT_COUNTER_CTL_MASK 0xfff
+#define AFE_DL_SLT_COUNTER_CTL_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_DL_PREDIS_CON0 */
+#define AFE_DL_PREDIS_ON_CH1_CTL_SFT 31
+#define AFE_DL_PREDIS_ON_CH1_CTL_MASK 0x1
+#define AFE_DL_PREDIS_ON_CH1_CTL_MASK_SFT (0x1 << 31)
+#define AFE_DL_PREDIS_A2_CH1_CTL_SFT 16
+#define AFE_DL_PREDIS_A2_CH1_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A2_CH1_CTL_MASK_SFT (0xfff << 16)
+#define AFE_DL_PREDIS_A3_CH1_CTL_SFT 0
+#define AFE_DL_PREDIS_A3_CH1_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A3_CH1_CTL_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_DL_PREDIS_CON1 */
+#define AFE_DL_PREDIS_ON_CH2_CTL_SFT 31
+#define AFE_DL_PREDIS_ON_CH2_CTL_MASK 0x1
+#define AFE_DL_PREDIS_ON_CH2_CTL_MASK_SFT (0x1 << 31)
+#define AFE_DL_PREDIS_A2_CH2_CTL_SFT 16
+#define AFE_DL_PREDIS_A2_CH2_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A2_CH2_CTL_MASK_SFT (0xfff << 16)
+#define AFE_DL_PREDIS_A3_CH2_CTL_SFT 0
+#define AFE_DL_PREDIS_A3_CH2_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A3_CH2_CTL_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_DL_PREDIS_CON2 */
+#define AFE_DL_PREDIS_A4_CH1_CTL_SFT 16
+#define AFE_DL_PREDIS_A4_CH1_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A4_CH1_CTL_MASK_SFT (0xfff << 16)
+#define AFE_DL_PREDIS_A5_CH1_CTL_SFT 0
+#define AFE_DL_PREDIS_A5_CH1_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A5_CH1_CTL_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_DL_PREDIS_CON3 */
+#define AFE_DL_PREDIS_A4_CH2_CTL_SFT 16
+#define AFE_DL_PREDIS_A4_CH2_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A4_CH2_CTL_MASK_SFT (0xfff << 16)
+#define AFE_DL_PREDIS_A5_CH2_CTL_SFT 0
+#define AFE_DL_PREDIS_A5_CH2_CTL_MASK 0xfff
+#define AFE_DL_PREDIS_A5_CH2_CTL_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_DL_SDM_DCCOMP_CON */
+#define AFE_DL_USE_NEW_2ND_12BIT_SDM_SFT 31
+#define AFE_DL_USE_NEW_2ND_12BIT_SDM_MASK 0x1
+#define AFE_DL_USE_NEW_2ND_12BIT_SDM_MASK_SFT (0x1 << 31)
+#define AFE_DL_USE_NEW_2ND_SDM_SFT 30
+#define AFE_DL_USE_NEW_2ND_SDM_MASK 0x1
+#define AFE_DL_USE_NEW_2ND_SDM_MASK_SFT (0x1 << 30)
+#define AFE_DL_USE_3RD_SDM_SFT 28
+#define AFE_DL_USE_3RD_SDM_MASK 0x1
+#define AFE_DL_USE_3RD_SDM_MASK_SFT (0x1 << 28)
+#define AFE_DL_DCM_AUTO_IDLE_EN_SFT 14
+#define AFE_DL_DCM_AUTO_IDLE_EN_MASK 0x1
+#define AFE_DL_DCM_AUTO_IDLE_EN_MASK_SFT (0x1 << 14)
+#define AFE_DL_SRC_DCM_EN_SFT 13
+#define AFE_DL_SRC_DCM_EN_MASK 0x1
+#define AFE_DL_SRC_DCM_EN_MASK_SFT (0x1 << 13)
+#define AFE_DL_POST_SRC_DCM_EN_SFT 12
+#define AFE_DL_POST_SRC_DCM_EN_MASK 0x1
+#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT (0x1 << 12)
+#define AFE_DL_DCCOMP_SYNC_TOGGLE_SFT 11
+#define AFE_DL_DCCOMP_SYNC_TOGGLE_MASK 0x1
+#define AFE_DL_DCCOMP_SYNC_TOGGLE_MASK_SFT (0x1 << 11)
+#define AFE_DL_AUD_SDM_MONO_SFT 9
+#define AFE_DL_AUD_SDM_MONO_MASK 0x1
+#define AFE_DL_AUD_SDM_MONO_MASK_SFT (0x1 << 9)
+#define AFE_DL_AUD_DC_COMP_EN_SFT 8
+#define AFE_DL_AUD_DC_COMP_EN_MASK 0x1
+#define AFE_DL_AUD_DC_COMP_EN_MASK_SFT (0x1 << 8)
+#define AFE_DL_ATTGAIN_CTL_SFT 0
+#define AFE_DL_ATTGAIN_CTL_MASK 0x3f
+#define AFE_DL_ATTGAIN_CTL_MASK_SFT (0x3f << 0)
+
+/* AFE_ADDA_DL_SDM_TEST */
+#define AFE_DL_TRI_AMP_DIV_SFT 12
+#define AFE_DL_TRI_AMP_DIV_MASK 0x7
+#define AFE_DL_TRI_AMP_DIV_MASK_SFT (0x7 << 12)
+#define AFE_DL_TRI_FREQ_DIV_SFT 4
+#define AFE_DL_TRI_FREQ_DIV_MASK 0x3f
+#define AFE_DL_TRI_FREQ_DIV_MASK_SFT (0x3f << 4)
+#define AFE_DL_RG_DL_LEFT_SAT_RSTN_SFT 3
+#define AFE_DL_RG_DL_LEFT_SAT_RSTN_MASK 0x1
+#define AFE_DL_RG_DL_LEFT_SAT_RSTN_MASK_SFT (0x1 << 3)
+#define AFE_DL_RG_DL_RIGHT_SAT_RSTN_SFT 2
+#define AFE_DL_RG_DL_RIGHT_SAT_RSTN_MASK 0x1
+#define AFE_DL_RG_DL_RIGHT_SAT_RSTN_MASK_SFT (0x1 << 2)
+#define AFE_DL_TRI_MUTE_SW_SFT 1
+#define AFE_DL_TRI_MUTE_SW_MASK 0x1
+#define AFE_DL_TRI_MUTE_SW_MASK_SFT (0x1 << 1)
+#define AFE_DL_TRI_DAC_EN_SFT 0
+#define AFE_DL_TRI_DAC_EN_MASK 0x1
+#define AFE_DL_TRI_DAC_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_DL_DC_COMP_CFG0 */
+#define AFE_DL_AUD_DC_COMP_LCH_H_SFT 16
+#define AFE_DL_AUD_DC_COMP_LCH_H_MASK 0xffff
+#define AFE_DL_AUD_DC_COMP_LCH_H_MASK_SFT (0xffff << 16)
+#define AFE_DL_AUD_DC_COMP_LCH_L_SFT 0
+#define AFE_DL_AUD_DC_COMP_LCH_L_MASK 0xffff
+#define AFE_DL_AUD_DC_COMP_LCH_L_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_DL_DC_COMP_CFG1 */
+#define AFE_DL_AUD_DC_COMP_RCH_H_SFT 16
+#define AFE_DL_AUD_DC_COMP_RCH_H_MASK 0xffff
+#define AFE_DL_AUD_DC_COMP_RCH_H_MASK_SFT (0xffff << 16)
+#define AFE_DL_AUD_DC_COMP_RCH_L_SFT 0
+#define AFE_DL_AUD_DC_COMP_RCH_L_MASK 0xffff
+#define AFE_DL_AUD_DC_COMP_RCH_L_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_DL_SDM_OUT_MON */
+#define AFE_DL_SDM_DITHER_MON_SFT 28
+#define AFE_DL_SDM_DITHER_MON_MASK 0x3
+#define AFE_DL_SDM_DITHER_MON_MASK_SFT (0x3 << 28)
+#define AFE_DL_BF_SDM_LEFT_SAT_SFT 21
+#define AFE_DL_BF_SDM_LEFT_SAT_MASK 0x1
+#define AFE_DL_BF_SDM_LEFT_SAT_MASK_SFT (0x1 << 21)
+#define AFE_DL_BF_SDM_RIGHT_SAT_SFT 20
+#define AFE_DL_BF_SDM_RIGHT_SAT_MASK 0x1
+#define AFE_DL_BF_SDM_RIGHT_SAT_MASK_SFT (0x1 << 20)
+#define AFE_DL_3RD_SDM_AUTO_RESET_R_SFT 19
+#define AFE_DL_3RD_SDM_AUTO_RESET_R_MASK 0x1
+#define AFE_DL_3RD_SDM_AUTO_RESET_R_MASK_SFT (0x1 << 19)
+#define AFE_DL_3RD_SDM_AUTO_RESET_L_SFT 18
+#define AFE_DL_3RD_SDM_AUTO_RESET_L_MASK 0x1
+#define AFE_DL_3RD_SDM_AUTO_RESET_L_MASK_SFT (0x1 << 18)
+#define AFE_DL_2ND_SDM_AUTO_RESET_R_SFT 17
+#define AFE_DL_2ND_SDM_AUTO_RESET_R_MASK 0x1
+#define AFE_DL_2ND_SDM_AUTO_RESET_R_MASK_SFT (0x1 << 17)
+#define AFE_DL_2ND_SDM_AUTO_RESET_L_SFT 16
+#define AFE_DL_2ND_SDM_AUTO_RESET_L_MASK 0x1
+#define AFE_DL_2ND_SDM_AUTO_RESET_L_MASK_SFT (0x1 << 16)
+#define AFE_DL_AUD_SDM_OUT_L_SFT 8
+#define AFE_DL_AUD_SDM_OUT_L_MASK 0xff
+#define AFE_DL_AUD_SDM_OUT_L_MASK_SFT (0xff << 8)
+#define AFE_DL_AUD_SDM_OUT_R_SFT 0
+#define AFE_DL_AUD_SDM_OUT_R_MASK 0xff
+#define AFE_DL_AUD_SDM_OUT_R_MASK_SFT (0xff << 0)
+
+/* AFE_ADDA_DL_SRC_LCH_MON */
+#define AFE_DL_ASDM_LEFT_SFT 0
+#define AFE_DL_ASDM_LEFT_MASK 0xffffff
+#define AFE_DL_ASDM_LEFT_MASK_SFT (0xffffff << 0)
+
+/* AFE_ADDA_DL_SRC_RCH_MON */
+#define AFE_DL_ASDM_RIGHT_SFT 0
+#define AFE_DL_ASDM_RIGHT_MASK 0xffffff
+#define AFE_DL_ASDM_RIGHT_MASK_SFT (0xffffff << 0)
+
+/* AFE_ADDA_DL_SRC_DEBUG */
+#define AFE_DL_SLT_CNT_FLAG_RESET_CTL_SFT 12
+#define AFE_DL_SLT_CNT_FLAG_RESET_CTL_MASK 0x1
+#define AFE_DL_SLT_CNT_FLAG_RESET_CTL_MASK_SFT (0x1 << 12)
+#define AFE_DL_SLT_CNT_THD_CTL_SFT 0
+#define AFE_DL_SLT_CNT_THD_CTL_MASK 0xfff
+#define AFE_DL_SLT_CNT_THD_CTL_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_DL_SDM_DITHER_CON */
+#define AFE_DL_SDM_DITHER_64TAP_EN_SFT 20
+#define AFE_DL_SDM_DITHER_64TAP_EN_MASK 0x1
+#define AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT (0x1 << 20)
+#define AFE_DL_SDM_DITHER_EN_SFT 16
+#define AFE_DL_SDM_DITHER_EN_MASK 0x1
+#define AFE_DL_SDM_DITHER_EN_MASK_SFT (0x1 << 16)
+#define AFE_DL_SDM_DITHER_GAIN_SFT 0
+#define AFE_DL_SDM_DITHER_GAIN_MASK 0xff
+#define AFE_DL_SDM_DITHER_GAIN_MASK_SFT (0xff << 0)
+
+/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */
+#define AFE_DL_SDM_AUTO_RESET_TEST_ON_SFT 31
+#define AFE_DL_SDM_AUTO_RESET_TEST_ON_MASK 0x1
+#define AFE_DL_SDM_AUTO_RESET_TEST_ON_MASK_SFT (0x1 << 31)
+#define AFE_DL_SDM_AUTO_RESET_SOURCE_SEL_SFT 24
+#define AFE_DL_SDM_AUTO_RESET_SOURCE_SEL_MASK 0x1
+#define AFE_DL_SDM_AUTO_RESET_SOURCE_SEL_MASK_SFT (0x1 << 24)
+#define AFE_DL_SDM_AUTO_RESET_COUNT_TH_SFT 0
+#define AFE_DL_SDM_AUTO_RESET_COUNT_TH_MASK 0xffffff
+#define AFE_DL_SDM_AUTO_RESET_COUNT_TH_MASK_SFT (0xffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_CONFIG */
+#define AFE_DL_HBF1_SW_CONFIG_SFT 31
+#define AFE_DL_HBF1_SW_CONFIG_MASK 0x1
+#define AFE_DL_HBF1_SW_CONFIG_MASK_SFT (0x1 << 31)
+#define AFE_DL_HBF1_TAPNUM_CONFIG_SFT 16
+#define AFE_DL_HBF1_TAPNUM_CONFIG_MASK 0x7f
+#define AFE_DL_HBF1_TAPNUM_CONFIG_MASK_SFT (0x7f << 16)
+#define AFE_DL_SCF1_SW_CONFIG_SFT 8
+#define AFE_DL_SCF1_SW_CONFIG_MASK 0x1
+#define AFE_DL_SCF1_SW_CONFIG_MASK_SFT (0x1 << 8)
+#define AFE_DL_SCF1_TAPNUM_CONFIG_SFT 0
+#define AFE_DL_SCF1_TAPNUM_CONFIG_MASK 0xff
+#define AFE_DL_SCF1_TAPNUM_CONFIG_MASK_SFT (0xff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP1_TAP2_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP1_TAP2_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP1_TAP2_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP1_TAP2_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP3_TAP4_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP3_TAP4_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP3_TAP4_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP3_TAP4_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP5_TAP6_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP5_TAP6_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP5_TAP6_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP5_TAP6_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP7_TAP8_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP7_TAP8_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP7_TAP8_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP7_TAP8_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP9_TAP10_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP9_TAP10_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP9_TAP10_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP9_TAP10_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP11_TAP12_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP11_TAP12_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP11_TAP12_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP11_TAP12_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP13_TAP14_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP13_TAP14_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP13_TAP14_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP13_TAP14_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP15_TAP16_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP15_TAP16_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP15_TAP16_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP15_TAP16_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP17_TAP18_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP17_TAP18_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP17_TAP18_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP17_TAP18_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP19_TAP20_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP19_TAP20_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP19_TAP20_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP19_TAP20_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP21_TAP22_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP21_TAP22_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP21_TAP22_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP21_TAP22_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP23_TAP24_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP23_TAP24_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP23_TAP24_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP23_TAP24_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP25_TAP26_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP25_TAP26_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP25_TAP26_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP25_TAP26_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP27_TAP28_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP27_TAP28_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP27_TAP28_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP27_TAP28_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP29_TAP30_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP29_TAP30_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP29_TAP30_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP29_TAP30_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP31_TAP32_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP31_TAP32_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP31_TAP32_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP31_TAP32_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP33_TAP34_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP33_TAP34_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP33_TAP34_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP33_TAP34_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP35_TAP36_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP35_TAP36_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP35_TAP36_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP35_TAP36_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP37_TAP38_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP37_TAP38_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP37_TAP38_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP37_TAP38_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP39_TAP40_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP39_TAP40_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP39_TAP40_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP39_TAP40_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP41_TAP42_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP41_TAP42_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP41_TAP42_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP41_TAP42_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP43_TAP44_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP43_TAP44_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP43_TAP44_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP43_TAP44_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP45_TAP46_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP45_TAP46_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP45_TAP46_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP45_TAP46_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP47_TAP48_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP47_TAP48_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP47_TAP48_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP47_TAP48_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP49_TAP50_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP49_TAP50_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP49_TAP50_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP49_TAP50_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP51_TAP52_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP51_TAP52_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP51_TAP52_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP51_TAP52_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP53_TAP54_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP53_TAP54_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP53_TAP54_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP53_TAP54_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_DL_HBF1_SCF1_TAP55_TAP56_CONFIG */
+#define AFE_DL_HBF1_SCF1_TAP55_TAP56_CONFIG_SFT 0
+#define AFE_DL_HBF1_SCF1_TAP55_TAP56_CONFIG_MASK 0xffffffff
+#define AFE_DL_HBF1_SCF1_TAP55_TAP56_CONFIG_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_NLE_R_CFG0 */
+#define RG_NLE_R_GAIN_DIG_TAR_SFT 24
+#define RG_NLE_R_GAIN_DIG_TAR_MASK 0x3f
+#define RG_NLE_R_GAIN_DIG_TAR_MASK_SFT (0x3f << 24)
+#define RG_NLE_R_GAIN_ANA_TAR_SFT 16
+#define RG_NLE_R_GAIN_ANA_TAR_MASK 0x3f
+#define RG_NLE_R_GAIN_ANA_TAR_MASK_SFT (0x3f << 16)
+#define RG_NLE_R_NO_ZCE_SFT 15
+#define RG_NLE_R_NO_ZCE_MASK 0x1
+#define RG_NLE_R_NO_ZCE_MASK_SFT (0x1 << 15)
+#define RG_NLE_R_HP_MODE_SFT 14
+#define RG_NLE_R_HP_MODE_MASK 0x1
+#define RG_NLE_R_HP_MODE_MASK_SFT (0x1 << 14)
+#define RG_NLE_R_GAIN_STEP_SFT 8
+#define RG_NLE_R_GAIN_STEP_MASK 0x7
+#define RG_NLE_R_GAIN_STEP_MASK_SFT (0x7 << 8)
+#define RG_NLE_R_TOGGLE_NUM_SFT 0
+#define RG_NLE_R_TOGGLE_NUM_MASK 0x3f
+#define RG_NLE_R_TOGGLE_NUM_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_NLE_R_CFG1 */
+#define RG_NLE_R_INITIATE_SFT 24
+#define RG_NLE_R_INITIATE_MASK 0x1
+#define RG_NLE_R_INITIATE_MASK_SFT (0x1 << 24)
+#define RG_NLE_R_READY_SFT 16
+#define RG_NLE_R_READY_MASK 0x1
+#define RG_NLE_R_READY_MASK_SFT (0x1 << 16)
+#define RG_NLE_R_TIMEOUT_SCALE_SFT 12
+#define RG_NLE_R_TIMEOUT_SCALE_MASK 0x7
+#define RG_NLE_R_TIMEOUT_SCALE_MASK_SFT (0x7 << 12)
+#define RG_NLE_R_ANC_ON_SFT 11
+#define RG_NLE_R_ANC_ON_MASK 0x1
+#define RG_NLE_R_ANC_ON_MASK_SFT (0x1 << 11)
+#define RG_NLE_R_GTIME_SFT 8
+#define RG_NLE_R_GTIME_MASK 0x7
+#define RG_NLE_R_GTIME_MASK_SFT (0x7 << 8)
+#define RG_NLE_R_ON_SFT 7
+#define RG_NLE_R_ON_MASK 0x1
+#define RG_NLE_R_ON_MASK_SFT (0x1 << 7)
+#define RG_PDN_NLE_CTL_SFT 6
+#define RG_PDN_NLE_CTL_MASK 0x1
+#define RG_PDN_NLE_CTL_MASK_SFT (0x1 << 6)
+#define RG_NLE_R_DELAY_ANA_SFT 0
+#define RG_NLE_R_DELAY_ANA_MASK 0x3f
+#define RG_NLE_R_DELAY_ANA_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_NLE_L_CFG0 */
+#define RG_NLE_L_GAIN_DIG_TAR_SFT 24
+#define RG_NLE_L_GAIN_DIG_TAR_MASK 0x3f
+#define RG_NLE_L_GAIN_DIG_TAR_MASK_SFT (0x3f << 24)
+#define RG_NLE_L_GAIN_ANA_TAR_SFT 16
+#define RG_NLE_L_GAIN_ANA_TAR_MASK 0x3f
+#define RG_NLE_L_GAIN_ANA_TAR_MASK_SFT (0x3f << 16)
+#define RG_NLE_L_NO_ZCE_SFT 15
+#define RG_NLE_L_NO_ZCE_MASK 0x1
+#define RG_NLE_L_NO_ZCE_MASK_SFT (0x1 << 15)
+#define RG_NLE_L_HP_MODE_SFT 14
+#define RG_NLE_L_HP_MODE_MASK 0x1
+#define RG_NLE_L_HP_MODE_MASK_SFT (0x1 << 14)
+#define RG_NLE_L_GAIN_STEP_SFT 8
+#define RG_NLE_L_GAIN_STEP_MASK 0x7
+#define RG_NLE_L_GAIN_STEP_MASK_SFT (0x7 << 8)
+#define RG_NLE_L_TOGGLE_NUM_SFT 0
+#define RG_NLE_L_TOGGLE_NUM_MASK 0x3f
+#define RG_NLE_L_TOGGLE_NUM_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_NLE_L_CFG1 */
+#define RG_NLE_L_INITIATE_SFT 24
+#define RG_NLE_L_INITIATE_MASK 0x1
+#define RG_NLE_L_INITIATE_MASK_SFT (0x1 << 24)
+#define RG_NLE_L_READY_SFT 16
+#define RG_NLE_L_READY_MASK 0x1
+#define RG_NLE_L_READY_MASK_SFT (0x1 << 16)
+#define RG_NLE_L_TIMEOUT_SCALE_SFT 12
+#define RG_NLE_L_TIMEOUT_SCALE_MASK 0x7
+#define RG_NLE_L_TIMEOUT_SCALE_MASK_SFT (0x7 << 12)
+#define RG_NLE_L_ANC_ON_SFT 11
+#define RG_NLE_L_ANC_ON_MASK 0x1
+#define RG_NLE_L_ANC_ON_MASK_SFT (0x1 << 11)
+#define RG_NLE_L_GTIME_SFT 8
+#define RG_NLE_L_GTIME_MASK 0x7
+#define RG_NLE_L_GTIME_MASK_SFT (0x7 << 8)
+#define RG_NLE_L_ON_SFT 7
+#define RG_NLE_L_ON_MASK 0x1
+#define RG_NLE_L_ON_MASK_SFT (0x1 << 7)
+#define RG_PDN_NLE_CTL_SFT 6
+#define RG_PDN_NLE_CTL_MASK 0x1
+#define RG_PDN_NLE_CTL_MASK_SFT (0x1 << 6)
+#define RG_NLE_L_DELAY_ANA_SFT 0
+#define RG_NLE_L_DELAY_ANA_MASK 0x3f
+#define RG_NLE_L_DELAY_ANA_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_NLE_R_MON0 */
+#define NLE_R_GAIN_DIG_CUR_SFT 24
+#define NLE_R_GAIN_DIG_CUR_MASK 0x3f
+#define NLE_R_GAIN_DIG_CUR_MASK_SFT (0x3f << 24)
+#define NLE_R_ANC_MASK_SFT 23
+#define NLE_R_ANC_MASK_MASK 0x1
+#define NLE_R_ANC_MASK_MASK_SFT (0x1 << 23)
+#define NLE_R_GAIN_ANA_CUR_SFT 16
+#define NLE_R_GAIN_ANA_CUR_MASK 0x3f
+#define NLE_R_GAIN_ANA_CUR_MASK_SFT (0x3f << 16)
+#define NLE_R_GAIN_DIG_TAR_CUR_SFT 8
+#define NLE_R_GAIN_DIG_TAR_CUR_MASK 0x3f
+#define NLE_R_GAIN_DIG_TAR_CUR_MASK_SFT (0x3f << 8)
+#define NLE_R_GAIN_ANA_TAR_CUR_SFT 0
+#define NLE_R_GAIN_ANA_TAR_CUR_MASK 0x3f
+#define NLE_R_GAIN_ANA_TAR_CUR_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_NLE_R_MON1 */
+#define NLE_R_STATE_CUR_SFT 28
+#define NLE_R_STATE_CUR_MASK 0x7
+#define NLE_R_STATE_CUR_MASK_SFT (0x7 << 28)
+#define NLE_R_GAIN_STEP_CUR_SFT 24
+#define NLE_R_GAIN_STEP_CUR_MASK 0xf
+#define NLE_R_GAIN_STEP_CUR_MASK_SFT (0xf << 24)
+#define NLE_R_TOGGLE_NUM_CUR_SFT 16
+#define NLE_R_TOGGLE_NUM_CUR_MASK 0x3f
+#define NLE_R_TOGGLE_NUM_CUR_MASK_SFT (0x3f << 16)
+#define NLE_R_DIG_GAIN_TARGETED_SFT 15
+#define NLE_R_DIG_GAIN_TARGETED_MASK 0x1
+#define NLE_R_DIG_GAIN_TARGETED_MASK_SFT (0x1 << 15)
+#define NLE_R_DIG_GAIN_INCREASE_SFT 14
+#define NLE_R_DIG_GAIN_INCREASE_MASK 0x1
+#define NLE_R_DIG_GAIN_INCREASE_MASK_SFT (0x1 << 14)
+#define NLE_R_DIG_GAIN_DECREASE_SFT 13
+#define NLE_R_DIG_GAIN_DECREASE_MASK 0x1
+#define NLE_R_DIG_GAIN_DECREASE_MASK_SFT (0x1 << 13)
+#define NLE_R_ANA_GAIN_TARGETED_SFT 12
+#define NLE_R_ANA_GAIN_TARGETED_MASK 0x1
+#define NLE_R_ANA_GAIN_TARGETED_MASK_SFT (0x1 << 12)
+#define NLE_R_ANA_GAIN_INCREASE_SFT 11
+#define NLE_R_ANA_GAIN_INCREASE_MASK 0x1
+#define NLE_R_ANA_GAIN_INCREASE_MASK_SFT (0x1 << 11)
+#define NLE_R_ANA_GAIN_DECREASE_SFT 10
+#define NLE_R_ANA_GAIN_DECREASE_MASK 0x1
+#define NLE_R_ANA_GAIN_DECREASE_MASK_SFT (0x1 << 10)
+#define NLE_R_TIME_COUNTER_CUR_SFT 0
+#define NLE_R_TIME_COUNTER_CUR_MASK 0x1ff
+#define NLE_R_TIME_COUNTER_CUR_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL_NLE_R_MON2 */
+#define NLE_R_ANA_GAIN_SFT 8
+#define NLE_R_ANA_GAIN_MASK 0x1f
+#define NLE_R_ANA_GAIN_MASK_SFT (0x1f << 8)
+#define NLE_MOSI2_ANA_GAIN_SFT 0
+#define NLE_MOSI2_ANA_GAIN_MASK 0x7f
+#define NLE_MOSI2_ANA_GAIN_MASK_SFT (0x7f << 0)
+
+/* AFE_DL_NLE_L_MON0 */
+#define NLE_L_GAIN_DIG_CUR_SFT 24
+#define NLE_L_GAIN_DIG_CUR_MASK 0x3f
+#define NLE_L_GAIN_DIG_CUR_MASK_SFT (0x3f << 24)
+#define NLE_L_ANC_MASK_SFT 23
+#define NLE_L_ANC_MASK_MASK 0x1
+#define NLE_L_ANC_MASK_MASK_SFT (0x1 << 23)
+#define NLE_L_GAIN_ANA_CUR_SFT 16
+#define NLE_L_GAIN_ANA_CUR_MASK 0x3f
+#define NLE_L_GAIN_ANA_CUR_MASK_SFT (0x3f << 16)
+#define NLE_L_GAIN_DIG_TAR_CUR_SFT 8
+#define NLE_L_GAIN_DIG_TAR_CUR_MASK 0x3f
+#define NLE_L_GAIN_DIG_TAR_CUR_MASK_SFT (0x3f << 8)
+#define NLE_L_GAIN_ANA_TAR_CUR_SFT 0
+#define NLE_L_GAIN_ANA_TAR_CUR_MASK 0x3f
+#define NLE_L_GAIN_ANA_TAR_CUR_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_NLE_L_MON1 */
+#define NLE_L_STATE_CUR_SFT 28
+#define NLE_L_STATE_CUR_MASK 0x7
+#define NLE_L_STATE_CUR_MASK_SFT (0x7 << 28)
+#define NLE_L_GAIN_STEP_CUR_SFT 24
+#define NLE_L_GAIN_STEP_CUR_MASK 0xf
+#define NLE_L_GAIN_STEP_CUR_MASK_SFT (0xf << 24)
+#define NLE_L_TOGGLE_NUM_CUR_SFT 16
+#define NLE_L_TOGGLE_NUM_CUR_MASK 0x3f
+#define NLE_L_TOGGLE_NUM_CUR_MASK_SFT (0x3f << 16)
+#define NLE_L_DIG_GAIN_TARGETED_SFT 15
+#define NLE_L_DIG_GAIN_TARGETED_MASK 0x1
+#define NLE_L_DIG_GAIN_TARGETED_MASK_SFT (0x1 << 15)
+#define NLE_L_DIG_GAIN_INCREASE_SFT 14
+#define NLE_L_DIG_GAIN_INCREASE_MASK 0x1
+#define NLE_L_DIG_GAIN_INCREASE_MASK_SFT (0x1 << 14)
+#define NLE_L_DIG_GAIN_DECREASE_SFT 13
+#define NLE_L_DIG_GAIN_DECREASE_MASK 0x1
+#define NLE_L_DIG_GAIN_DECREASE_MASK_SFT (0x1 << 13)
+#define NLE_L_ANA_GAIN_TARGETED_SFT 12
+#define NLE_L_ANA_GAIN_TARGETED_MASK 0x1
+#define NLE_L_ANA_GAIN_TARGETED_MASK_SFT (0x1 << 12)
+#define NLE_L_ANA_GAIN_INCREASE_SFT 11
+#define NLE_L_ANA_GAIN_INCREASE_MASK 0x1
+#define NLE_L_ANA_GAIN_INCREASE_MASK_SFT (0x1 << 11)
+#define NLE_L_ANA_GAIN_DECREASE_SFT 10
+#define NLE_L_ANA_GAIN_DECREASE_MASK 0x1
+#define NLE_L_ANA_GAIN_DECREASE_MASK_SFT (0x1 << 10)
+#define NLE_L_TIME_COUNTER_CUR_SFT 0
+#define NLE_L_TIME_COUNTER_CUR_MASK 0x1ff
+#define NLE_L_TIME_COUNTER_CUR_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL_NLE_L_MON2 */
+#define NLE_L_ANA_GAIN_SFT 8
+#define NLE_L_ANA_GAIN_MASK 0x1f
+#define NLE_L_ANA_GAIN_MASK_SFT (0x1f << 8)
+#define NLE_MOSI1_ANA_GAIN_SFT 0
+#define NLE_MOSI1_ANA_GAIN_MASK 0x7f
+#define NLE_MOSI1_ANA_GAIN_MASK_SFT (0x7f << 0)
+
+/* AFE_DL_NLE_GAIN_CFG0 */
+#define MISO2_SEL_SFT 4
+#define MISO2_SEL_MASK 0x3
+#define MISO2_SEL_MASK_SFT (0x3 << 4)
+#define MISO1_SEL_SFT 0
+#define MISO1_SEL_MASK 0x3
+#define MISO1_SEL_MASK_SFT (0x3 << 0)
+
+/* AFE_DEM_IDWA_CON0 */
+#define RG_IDWA_SDM_MAV_EN_SFT 31
+#define RG_IDWA_SDM_MAV_EN_MASK 0x1
+#define RG_IDWA_SDM_MAV_EN_MASK_SFT (0x1 << 31)
+#define RG_IDWA_SDM_ADITHON_SFT 30
+#define RG_IDWA_SDM_ADITHON_MASK 0x1
+#define RG_IDWA_SDM_ADITHON_MASK_SFT (0x1 << 30)
+#define RG_IDWA_SDM_ADITHVAL_SFT 28
+#define RG_IDWA_SDM_ADITHVAL_MASK 0x3
+#define RG_IDWA_SDM_ADITHVAL_MASK_SFT (0x3 << 28)
+#define RG_IDWA_SDM_LOOPBACK_SFT 27
+#define RG_IDWA_SDM_LOOPBACK_MASK 0x1
+#define RG_IDWA_SDM_LOOPBACK_MASK_SFT (0x1 << 27)
+#define RG_IDWA_SEL_SFT 26
+#define RG_IDWA_SEL_MASK 0x1
+#define RG_IDWA_SEL_MASK_SFT (0x1 << 26)
+#define RG_IDWA_ON_SFT 25
+#define RG_IDWA_ON_MASK 0x1
+#define RG_IDWA_ON_MASK_SFT (0x1 << 25)
+#define RG_DEM_IN_LR_SWAP_SFT 24
+#define RG_DEM_IN_LR_SWAP_MASK 0x1
+#define RG_DEM_IN_LR_SWAP_MASK_SFT (0x1 << 24)
+#define RG_DEM_IN_L_INV_SFT 23
+#define RG_DEM_IN_L_INV_MASK 0x1
+#define RG_DEM_IN_L_INV_MASK_SFT (0x1 << 23)
+#define RG_DEM_IN_R_EQ_L_SFT 22
+#define RG_DEM_IN_R_EQ_L_MASK 0x1
+#define RG_DEM_IN_R_EQ_L_MASK_SFT (0x1 << 22)
+#define RG_DEM_IN_L_MUTE_SFT 21
+#define RG_DEM_IN_L_MUTE_MASK 0x1
+#define RG_DEM_IN_L_MUTE_MASK_SFT (0x1 << 21)
+#define RG_DEM_IN_R_MUTE_SFT 20
+#define RG_DEM_IN_R_MUTE_MASK 0x1
+#define RG_DEM_IN_R_MUTE_MASK_SFT (0x1 << 20)
+#define RG_DEM_IN_SOURCE_SFT 19
+#define RG_DEM_IN_SOURCE_MASK 0x1
+#define RG_DEM_IN_SOURCE_MASK_SFT (0x1 << 19)
+#define RG_DEM_SPLITTER_TRUNC_RND_SFT 18
+#define RG_DEM_SPLITTER_TRUNC_RND_MASK 0x1
+#define RG_DEM_SPLITTER_TRUNC_RND_MASK_SFT (0x1 << 18)
+#define RG_DEM_SCRAMBLER_CG_EN_SFT 17
+#define RG_DEM_SCRAMBLER_CG_EN_MASK 0x1
+#define RG_DEM_SCRAMBLER_CG_EN_MASK_SFT (0x1 << 17)
+#define RG_DEM_SCRAMBLER_EN_SFT 16
+#define RG_DEM_SCRAMBLER_EN_MASK 0x1
+#define RG_DEM_SCRAMBLER_EN_MASK_SFT (0x1 << 16)
+#define RG_DEM_AUD_SDM_7BIT_SEL_SFT 15
+#define RG_DEM_AUD_SDM_7BIT_SEL_MASK 0x1
+#define RG_DEM_AUD_SDM_7BIT_SEL_MASK_SFT (0x1 << 15)
+#define RG_DEM_ZERO_PAD_DISABLE_SFT 14
+#define RG_DEM_ZERO_PAD_DISABLE_MASK 0x1
+#define RG_DEM_ZERO_PAD_DISABLE_MASK_SFT (0x1 << 14)
+#define RG_DEM_SPLITTER_TEST_EN_SFT 13
+#define RG_DEM_SPLITTER_TEST_EN_MASK 0x1
+#define RG_DEM_SPLITTER_TEST_EN_MASK_SFT (0x1 << 13)
+#define RG_DEM_IDAC_TEST_EN_SFT 12
+#define RG_DEM_IDAC_TEST_EN_MASK 0x1
+#define RG_DEM_IDAC_TEST_EN_MASK_SFT (0x1 << 12)
+#define RG_DEM_SPLIT_SCRAM_ON_SFT 11
+#define RG_DEM_SPLIT_SCRAM_ON_MASK 0x1
+#define RG_DEM_SPLIT_SCRAM_ON_MASK_SFT (0x1 << 11)
+#define RG_DEM_RAND_EN_SFT 10
+#define RG_DEM_RAND_EN_MASK 0x1
+#define RG_DEM_RAND_EN_MASK_SFT (0x1 << 10)
+#define RG_DEM_SPLITTER2_DITHER_EN_SFT 9
+#define RG_DEM_SPLITTER2_DITHER_EN_MASK 0x1
+#define RG_DEM_SPLITTER2_DITHER_EN_MASK_SFT (0x1 << 9)
+#define RG_DEM_SPLITTER1_DITHER_EN_SFT 8
+#define RG_DEM_SPLITTER1_DITHER_EN_MASK 0x1
+#define RG_DEM_SPLITTER1_DITHER_EN_MASK_SFT (0x1 << 8)
+#define RG_DEM_SPLITTER2_DITHER_GAIN_SFT 4
+#define RG_DEM_SPLITTER2_DITHER_GAIN_MASK 0xf
+#define RG_DEM_SPLITTER2_DITHER_GAIN_MASK_SFT (0xf << 4)
+#define RG_DEM_SPLITTER1_DITHER_GAIN_SFT 0
+#define RG_DEM_SPLITTER1_DITHER_GAIN_MASK 0xf
+#define RG_DEM_SPLITTER1_DITHER_GAIN_MASK_SFT (0xf << 0)
+
+/* DEM_RECONSTRUCT_MON */
+#define DEM_RECONSTRUCT_L_MON_SFT 8
+#define DEM_RECONSTRUCT_L_MON_MASK 0xff
+#define DEM_RECONSTRUCT_L_MON_MASK_SFT (0xff << 8)
+#define DEM_RECONSTRUCT_R_MON_SFT 0
+#define DEM_RECONSTRUCT_R_MON_MASK 0xff
+#define DEM_RECONSTRUCT_R_MON_MASK_SFT (0xff << 0)
+
+/* AFE_STF_CON0 */
+#define SLT_CNT_FLAG_RESET_SFT 28
+#define SLT_CNT_FLAG_RESET_MASK 0x1
+#define SLT_CNT_FLAG_RESET_MASK_SFT (0x1 << 28)
+#define SLT_CNT_THD_SFT 16
+#define SLT_CNT_THD_MASK 0xfff
+#define SLT_CNT_THD_MASK_SFT (0xfff << 16)
+#define SIDE_TONE_HALF_TAP_NUM_SFT 4
+#define SIDE_TONE_HALF_TAP_NUM_MASK 0x7f
+#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT (0x7f << 4)
+#define SIDE_TONE_ODD_MODE_SFT 1
+#define SIDE_TONE_ODD_MODE_MASK 0x1
+#define SIDE_TONE_ODD_MODE_MASK_SFT (0x1 << 1)
+#define SIDE_TONE_ON_SFT 0
+#define SIDE_TONE_ON_MASK 0x1
+#define SIDE_TONE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_STF_CON1 */
+#define SIDE_TONE_IN_EN_SEL_DOMAIN_SFT 5
+#define SIDE_TONE_IN_EN_SEL_DOMAIN_MASK 0x7
+#define SIDE_TONE_IN_EN_SEL_DOMAIN_MASK_SFT (0x7 << 5)
+#define SIDE_TONE_IN_EN_SEL_FS_SFT 0
+#define SIDE_TONE_IN_EN_SEL_FS_MASK 0x1f
+#define SIDE_TONE_IN_EN_SEL_FS_MASK_SFT (0x1f << 0)
+
+/* AFE_STF_COEFF */
+#define SIDE_TONE_COEFFICIENT_R_W_SEL_SFT 24
+#define SIDE_TONE_COEFFICIENT_R_W_SEL_MASK 0x1
+#define SIDE_TONE_COEFFICIENT_R_W_SEL_MASK_SFT (0x1 << 24)
+#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK 0x1f
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT (0x1f << 16)
+#define SIDE_TONE_COEFFICIENT_SFT 0
+#define SIDE_TONE_COEFFICIENT_MASK 0xffff
+#define SIDE_TONE_COEFFICIENT_MASK_SFT (0xffff << 0)
+
+/* AFE_STF_GAIN */
+#define SIDE_TONE_POSITIVE_GAIN_SFT 16
+#define SIDE_TONE_POSITIVE_GAIN_MASK 0x7
+#define SIDE_TONE_POSITIVE_GAIN_MASK_SFT (0x7 << 16)
+#define SIDE_TONE_GAIN_SFT 0
+#define SIDE_TONE_GAIN_MASK 0xffff
+#define SIDE_TONE_GAIN_MASK_SFT (0xffff << 0)
+
+/* AFE_STF_MON */
+#define SIDE_TONE_R_RDY_SFT 30
+#define SIDE_TONE_R_RDY_MASK 0x1
+#define SIDE_TONE_R_RDY_MASK_SFT (0x1 << 30)
+#define SIDE_TONE_W_RDY_SFT 29
+#define SIDE_TONE_W_RDY_MASK 0x1
+#define SIDE_TONE_W_RDY_MASK_SFT (0x1 << 29)
+#define SLT_CNT_FLAG_SFT 28
+#define SLT_CNT_FLAG_MASK 0x1
+#define SLT_CNT_FLAG_MASK_SFT (0x1 << 28)
+#define SLT_CNT_SFT 16
+#define SLT_CNT_MASK 0xfff
+#define SLT_CNT_MASK_SFT (0xfff << 16)
+#define SIDE_TONE_COEFF_SFT 0
+#define SIDE_TONE_COEFF_MASK 0xffff
+#define SIDE_TONE_COEFF_MASK_SFT (0xffff << 0)
+
+/* AFE_STF_IP_VERSION */
+#define SIDE_TONE_IP_VERSION_SFT 0
+#define SIDE_TONE_IP_VERSION_MASK 0xffffffff
+#define SIDE_TONE_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CM_REG */
+#define AFE_CM_UPDATE_CNT_SFT 16
+#define AFE_CM_UPDATE_CNT_MASK 0x7fff
+#define AFE_CM_UPDATE_CNT_MASK_SFT (0x7fff << 16)
+#define AFE_CM_1X_EN_SEL_FS_SFT 8
+#define AFE_CM_1X_EN_SEL_FS_MASK 0x1f
+#define AFE_CM_1X_EN_SEL_FS_MASK_SFT (0x1f << 8)
+#define AFE_CM_CH_NUM_SFT 2
+#define AFE_CM_CH_NUM_MASK 0x1f
+#define AFE_CM_CH_NUM_MASK_SFT (0x1f << 2)
+#define AFE_CM_BYTE_SWAP_SFT 1
+#define AFE_CM_BYTE_SWAP_MASK 0x1
+#define AFE_CM_BYTE_SWAP_MASK_SFT (0x1 << 1)
+#define AFE_CM_BYPASS_MODE_SFT 31
+#define AFE_CM_BYPASS_MODE_MASK 0x1
+#define AFE_CM_BYPASS_MODE_MASK_SFT (0x1 << 31)
+
+/* AFE_CM0_CON0 */
+#define AFE_CM0_BYPASS_MODE_SFT 31
+#define AFE_CM0_BYPASS_MODE_MASK 0x1
+#define AFE_CM0_BYPASS_MODE_MASK_SFT (0x1 << 31)
+#define AFE_CM0_UPDATE_CNT_SFT 16
+#define AFE_CM0_UPDATE_CNT_MASK 0x7fff
+#define AFE_CM0_UPDATE_CNT_MASK_SFT (0x7fff << 16)
+#define AFE_CM0_1X_EN_SEL_DOMAIN_SFT 13
+#define AFE_CM0_1X_EN_SEL_DOMAIN_MASK 0x7
+#define AFE_CM0_1X_EN_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define AFE_CM0_1X_EN_SEL_FS_SFT 8
+#define AFE_CM0_1X_EN_SEL_FS_MASK 0x1f
+#define AFE_CM0_1X_EN_SEL_FS_MASK_SFT (0x1f << 8)
+#define AFE_CM0_OUTPUT_MUX_SFT 7
+#define AFE_CM0_OUTPUT_MUX_MASK 0x1
+#define AFE_CM0_OUTPUT_MUX_MASK_SFT (0x1 << 7)
+#define AFE_CM0_CH_NUM_SFT 2
+#define AFE_CM0_CH_NUM_MASK 0x1f
+#define AFE_CM0_CH_NUM_MASK_SFT (0x1f << 2)
+#define AFE_CM0_BYTE_SWAP_SFT 1
+#define AFE_CM0_BYTE_SWAP_MASK 0x1
+#define AFE_CM0_BYTE_SWAP_MASK_SFT (0x1 << 1)
+#define AFE_CM0_ON_SFT 0
+#define AFE_CM0_ON_MASK 0x1
+#define AFE_CM0_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_CM0_MON */
+#define AFE_CM0_BYPASS_MODE_MON_SFT 31
+#define AFE_CM0_BYPASS_MODE_MON_MASK 0x1
+#define AFE_CM0_BYPASS_MODE_MON_MASK_SFT (0x1 << 31)
+#define AFE_CM0_OUTPUT_CNT_MON_SFT 16
+#define AFE_CM0_OUTPUT_CNT_MON_MASK 0x7fff
+#define AFE_CM0_OUTPUT_CNT_MON_MASK_SFT (0x7fff << 16)
+#define AFE_CM0_CUR_CHSET_MON_SFT 5
+#define AFE_CM0_CUR_CHSET_MON_MASK 0xf
+#define AFE_CM0_CUR_CHSET_MON_MASK_SFT (0xf << 5)
+#define AFE_CM0_ODD_FLAG_MON_SFT 4
+#define AFE_CM0_ODD_FLAG_MON_MASK 0x1
+#define AFE_CM0_ODD_FLAG_MON_MASK_SFT (0x1 << 4)
+#define AFE_CM0_BYTE_SWAP_MON_SFT 1
+#define AFE_CM0_BYTE_SWAP_MON_MASK 0x1
+#define AFE_CM0_BYTE_SWAP_MON_MASK_SFT (0x1 << 1)
+#define AFE_CM0_ON_MON_SFT 0
+#define AFE_CM0_ON_MON_MASK 0x1
+#define AFE_CM0_ON_MON_MASK_SFT (0x1 << 0)
+
+/* AFE_CM0_IP_VERSION */
+#define AFE_CM0_IP_VERSION_SFT 0
+#define AFE_CM0_IP_VERSION_MASK 0xffffffff
+#define AFE_CM0_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CM1_CON0 */
+#define AFE_CM1_BYPASS_MODE_SFT 31
+#define AFE_CM1_BYPASS_MODE_MASK 0x1
+#define AFE_CM1_BYPASS_MODE_MASK_SFT (0x1 << 31)
+#define AFE_CM1_UPDATE_CNT_SFT 16
+#define AFE_CM1_UPDATE_CNT_MASK 0x7fff
+#define AFE_CM1_UPDATE_CNT_MASK_SFT (0x7fff << 16)
+#define AFE_CM1_1X_EN_SEL_DOMAIN_SFT 13
+#define AFE_CM1_1X_EN_SEL_DOMAIN_MASK 0x7
+#define AFE_CM1_1X_EN_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define AFE_CM1_1X_EN_SEL_FS_SFT 8
+#define AFE_CM1_1X_EN_SEL_FS_MASK 0x1f
+#define AFE_CM1_1X_EN_SEL_FS_MASK_SFT (0x1f << 8)
+#define AFE_CM1_OUTPUT_MUX_SFT 7
+#define AFE_CM1_OUTPUT_MUX_MASK 0x1
+#define AFE_CM1_OUTPUT_MUX_MASK_SFT (0x1 << 7)
+#define AFE_CM1_CH_NUM_SFT 2
+#define AFE_CM1_CH_NUM_MASK 0x1f
+#define AFE_CM1_CH_NUM_MASK_SFT (0x1f << 2)
+#define AFE_CM1_BYTE_SWAP_SFT 1
+#define AFE_CM1_BYTE_SWAP_MASK 0x1
+#define AFE_CM1_BYTE_SWAP_MASK_SFT (0x1 << 1)
+#define AFE_CM1_ON_SFT 0
+#define AFE_CM1_ON_MASK 0x1
+#define AFE_CM1_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_CM1_MON */
+#define AFE_CM1_BYPASS_MODE_MON_SFT 31
+#define AFE_CM1_BYPASS_MODE_MON_MASK 0x1
+#define AFE_CM1_BYPASS_MODE_MON_MASK_SFT (0x1 << 31)
+#define AFE_CM1_OUTPUT_CNT_MON_SFT 16
+#define AFE_CM1_OUTPUT_CNT_MON_MASK 0x7fff
+#define AFE_CM1_OUTPUT_CNT_MON_MASK_SFT (0x7fff << 16)
+#define AFE_CM1_CUR_CHSET_MON_SFT 5
+#define AFE_CM1_CUR_CHSET_MON_MASK 0xf
+#define AFE_CM1_CUR_CHSET_MON_MASK_SFT (0xf << 5)
+#define AFE_CM1_ODD_FLAG_MON_SFT 4
+#define AFE_CM1_ODD_FLAG_MON_MASK 0x1
+#define AFE_CM1_ODD_FLAG_MON_MASK_SFT (0x1 << 4)
+#define AFE_CM1_BYTE_SWAP_MON_SFT 1
+#define AFE_CM1_BYTE_SWAP_MON_MASK 0x1
+#define AFE_CM1_BYTE_SWAP_MON_MASK_SFT (0x1 << 1)
+#define AFE_CM1_ON_MON_SFT 0
+#define AFE_CM1_ON_MON_MASK 0x1
+#define AFE_CM1_ON_MON_MASK_SFT (0x1 << 0)
+
+/* AFE_CM1_IP_VERSION */
+#define AFE_CM1_IP_VERSION_SFT 0
+#define AFE_CM1_IP_VERSION_MASK 0xffffffff
+#define AFE_CM1_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_SRC_CON0 */
+#define ULCF_CFG_EN_CTL_SFT 31
+#define ULCF_CFG_EN_CTL_MASK 0x1
+#define ULCF_CFG_EN_CTL_MASK_SFT (0x1 << 31)
+#define UL_DMIC_PHASE_SEL_CH1_SFT 27
+#define UL_DMIC_PHASE_SEL_CH1_MASK 0x7
+#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT (0x7 << 27)
+#define UL_DMIC_PHASE_SEL_CH2_SFT 24
+#define UL_DMIC_PHASE_SEL_CH2_MASK 0x7
+#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT (0x7 << 24)
+#define UL_DMIC_TWO_WIRE_CTL_SFT 23
+#define UL_DMIC_TWO_WIRE_CTL_MASK 0x1
+#define UL_DMIC_TWO_WIRE_CTL_MASK_SFT (0x1 << 23)
+#define UL_MODE_3P25M_CH2_CTL_SFT 22
+#define UL_MODE_3P25M_CH2_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22)
+#define UL_MODE_3P25M_CH1_CTL_SFT 21
+#define UL_MODE_3P25M_CH1_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17)
+#define UL_AP_DMIC_ON_SFT 16
+#define UL_AP_DMIC_ON_MASK 0x1
+#define UL_AP_DMIC_ON_MASK_SFT (0x1 << 16)
+#define DMIC_LOW_POWER_MODE_CTL_SFT 14
+#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3
+#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14)
+#define UL_DISABLE_HW_CG_CTL_SFT 12
+#define UL_DISABLE_HW_CG_CTL_MASK 0x1
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12)
+#define AMIC_26M_SEL_CTL_SFT 11
+#define AMIC_26M_SEL_CTL_MASK 0x1
+#define AMIC_26M_SEL_CTL_MASK_SFT (0x1 << 11)
+#define UL_IIR_ON_TMP_CTL_SFT 10
+#define UL_IIR_ON_TMP_CTL_MASK 0x1
+#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10)
+#define UL_IIRMODE_CTL_SFT 7
+#define UL_IIRMODE_CTL_MASK 0x7
+#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7)
+#define DIGMIC_4P33M_SEL_SFT 6
+#define DIGMIC_4P33M_SEL_MASK 0x1
+#define DIGMIC_4P33M_SEL_MASK_SFT (0x1 << 6)
+#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5)
+#define AMIC_6P5M_SEL_CTL_SFT 4
+#define AMIC_6P5M_SEL_CTL_MASK 0x1
+#define AMIC_6P5M_SEL_CTL_MASK_SFT (0x1 << 4)
+#define AMIC_1P625M_SEL_CTL_SFT 3
+#define AMIC_1P625M_SEL_CTL_MASK 0x1
+#define AMIC_1P625M_SEL_CTL_MASK_SFT (0x1 << 3)
+#define UL_LOOP_BACK_MODE_CTL_SFT 2
+#define UL_LOOP_BACK_MODE_CTL_MASK 0x1
+#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2)
+#define UL_SDM_3_LEVEL_CTL_SFT 1
+#define UL_SDM_3_LEVEL_CTL_MASK 0x1
+#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1)
+#define UL_SRC_ON_TMP_CTL_SFT 0
+#define UL_SRC_ON_TMP_CTL_MASK 0x1
+#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL0_SRC_CON1 */
+#define ADDA_UL_GAIN_VALUE_SFT 16
+#define ADDA_UL_GAIN_VALUE_MASK 0xffff
+#define ADDA_UL_GAIN_VALUE_MASK_SFT (0xffff << 16)
+#define ADDA_UL_POSTIVEGAIN_SFT 12
+#define ADDA_UL_POSTIVEGAIN_MASK 0x7
+#define ADDA_UL_POSTIVEGAIN_MASK_SFT (0x7 << 12)
+#define ADDA_UL_ODDTAP_MODE_SFT 11
+#define ADDA_UL_ODDTAP_MODE_MASK 0x1
+#define ADDA_UL_ODDTAP_MODE_MASK_SFT (0x1 << 11)
+#define ADDA_UL_HALF_TAP_NUM_SFT 5
+#define ADDA_UL_HALF_TAP_NUM_MASK 0x3f
+#define ADDA_UL_HALF_TAP_NUM_MASK_SFT (0x3f << 5)
+#define FIFO_SOFT_RST_SFT 4
+#define FIFO_SOFT_RST_MASK 0x1
+#define FIFO_SOFT_RST_MASK_SFT (0x1 << 4)
+#define FIFO_SOFT_RST_EN_SFT 3
+#define FIFO_SOFT_RST_EN_MASK 0x1
+#define FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 3)
+#define LR_SWAP_SFT 2
+#define LR_SWAP_MASK 0x1
+#define LR_SWAP_MASK_SFT (0x1 << 2)
+#define GAIN_MODE_SFT 0
+#define GAIN_MODE_MASK 0x3
+#define GAIN_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_ADDA_UL0_SRC_CON2 */
+#define C_DAC_EN_CTL_SFT 27
+#define C_DAC_EN_CTL_MASK 0x1
+#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27)
+#define C_MUTE_SW_CTL_SFT 26
+#define C_MUTE_SW_CTL_MASK 0x1
+#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26)
+#define C_AMP_DIV_CH2_CTL_SFT 21
+#define C_AMP_DIV_CH2_CTL_MASK 0x7
+#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21)
+#define C_FREQ_DIV_CH2_CTL_SFT 16
+#define C_FREQ_DIV_CH2_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16)
+#define C_SINE_MODE_CH2_CTL_SFT 12
+#define C_SINE_MODE_CH2_CTL_MASK 0xf
+#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12)
+#define C_AMP_DIV_CH1_CTL_SFT 9
+#define C_AMP_DIV_CH1_CTL_MASK 0x7
+#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9)
+#define C_FREQ_DIV_CH1_CTL_SFT 4
+#define C_FREQ_DIV_CH1_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4)
+#define C_SINE_MODE_CH1_CTL_SFT 0
+#define C_SINE_MODE_CH1_CTL_MASK 0xf
+#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0)
+
+/* AFE_ADDA_UL0_SRC_DEBUG */
+#define UL_SLT_CNT_FLAG_RESET_CTL_SFT 16
+#define UL_SLT_CNT_FLAG_RESET_CTL_MASK 0x1
+#define UL_SLT_CNT_FLAG_RESET_CTL_MASK_SFT (0x1 << 16)
+#define FIFO_DIGMIC_TESTIN_SFT 12
+#define FIFO_DIGMIC_TESTIN_MASK 0x3
+#define FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 12)
+#define FIFO_DIGMIC_WDATA_TESTEN_SFT 11
+#define FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1
+#define FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 11)
+#define SLT_CNT_THD_CTL_SFT 0
+#define SLT_CNT_THD_CTL_MASK 0x7ff
+#define SLT_CNT_THD_CTL_MASK_SFT (0x7ff << 0)
+
+/* AFE_ADDA_UL0_SRC_DEBUG_MON0 */
+#define SLT_CNT_FLAG_CTL_SFT 16
+#define SLT_CNT_FLAG_CTL_MASK 0x1
+#define SLT_CNT_FLAG_CTL_MASK_SFT (0x1 << 16)
+#define SLT_COUNTER_CTL_SFT 0
+#define SLT_COUNTER_CTL_MASK 0x7ff
+#define SLT_COUNTER_CTL_MASK_SFT (0x7ff << 0)
+
+/* AFE_ADDA_UL0_SRC_MON1 */
+#define UL_VOICE_MODE_CTL_SFT 29
+#define UL_VOICE_MODE_CTL_MASK 0x7
+#define UL_VOICE_MODE_CTL_MASK_SFT (0x7 << 29)
+#define DATA_COMB_IN_CH2_SFT 24
+#define DATA_COMB_IN_CH2_MASK 0x1f
+#define DATA_COMB_IN_CH2_MASK_SFT (0x1f << 24)
+#define DATA_COMB_OUT_CH2_SFT 0
+#define DATA_COMB_OUT_CH2_MASK 0xffffff
+#define DATA_COMB_OUT_CH2_MASK_SFT (0xffffff << 0)
+
+/* AFE_ADDA_UL0_IIR_COEF_02_01 */
+#define ADDA_IIR_COEF_02_01_SFT 0
+#define ADDA_IIR_COEF_02_01_MASK 0xffffffff
+#define ADDA_IIR_COEF_02_01_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_IIR_COEF_04_03 */
+#define ADDA_IIR_COEF_04_03_SFT 0
+#define ADDA_IIR_COEF_04_03_MASK 0xffffffff
+#define ADDA_IIR_COEF_04_03_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_IIR_COEF_06_05 */
+#define ADDA_IIR_COEF_06_05_SFT 0
+#define ADDA_IIR_COEF_06_05_MASK 0xffffffff
+#define ADDA_IIR_COEF_06_05_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_IIR_COEF_08_07 */
+#define ADDA_IIR_COEF_08_07_SFT 0
+#define ADDA_IIR_COEF_08_07_MASK 0xffffffff
+#define ADDA_IIR_COEF_08_07_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_IIR_COEF_10_09 */
+#define ADDA_IIR_COEF_10_09_SFT 0
+#define ADDA_IIR_COEF_10_09_MASK 0xffffffff
+#define ADDA_IIR_COEF_10_09_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_02_01 */
+#define ADDA_ULCF_CFG_02_01_SFT 0
+#define ADDA_ULCF_CFG_02_01_MASK 0xffffffff
+#define ADDA_ULCF_CFG_02_01_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_04_03 */
+#define ADDA_ULCF_CFG_04_03_SFT 0
+#define ADDA_ULCF_CFG_04_03_MASK 0xffffffff
+#define ADDA_ULCF_CFG_04_03_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_06_05 */
+#define ADDA_ULCF_CFG_06_05_SFT 0
+#define ADDA_ULCF_CFG_06_05_MASK 0xffffffff
+#define ADDA_ULCF_CFG_06_05_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_08_07 */
+#define ADDA_ULCF_CFG_08_07_SFT 0
+#define ADDA_ULCF_CFG_08_07_MASK 0xffffffff
+#define ADDA_ULCF_CFG_08_07_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_10_09 */
+#define ADDA_ULCF_CFG_10_09_SFT 0
+#define ADDA_ULCF_CFG_10_09_MASK 0xffffffff
+#define ADDA_ULCF_CFG_10_09_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_12_11 */
+#define ADDA_ULCF_CFG_12_11_SFT 0
+#define ADDA_ULCF_CFG_12_11_MASK 0xffffffff
+#define ADDA_ULCF_CFG_12_11_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_14_13 */
+#define ADDA_ULCF_CFG_14_13_SFT 0
+#define ADDA_ULCF_CFG_14_13_MASK 0xffffffff
+#define ADDA_ULCF_CFG_14_13_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_16_15 */
+#define ADDA_ULCF_CFG_16_15_SFT 0
+#define ADDA_ULCF_CFG_16_15_MASK 0xffffffff
+#define ADDA_ULCF_CFG_16_15_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_18_17 */
+#define ADDA_ULCF_CFG_18_17_SFT 0
+#define ADDA_ULCF_CFG_18_17_MASK 0xffffffff
+#define ADDA_ULCF_CFG_18_17_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_20_19 */
+#define ADDA_ULCF_CFG_20_19_SFT 0
+#define ADDA_ULCF_CFG_20_19_MASK 0xffffffff
+#define ADDA_ULCF_CFG_20_19_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_22_21 */
+#define ADDA_ULCF_CFG_22_21_SFT 0
+#define ADDA_ULCF_CFG_22_21_MASK 0xffffffff
+#define ADDA_ULCF_CFG_22_21_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_24_23 */
+#define ADDA_ULCF_CFG_24_23_SFT 0
+#define ADDA_ULCF_CFG_24_23_MASK 0xffffffff
+#define ADDA_ULCF_CFG_24_23_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_26_25 */
+#define ADDA_ULCF_CFG_26_25_SFT 0
+#define ADDA_ULCF_CFG_26_25_MASK 0xffffffff
+#define ADDA_ULCF_CFG_26_25_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_28_27 */
+#define ADDA_ULCF_CFG_28_27_SFT 0
+#define ADDA_ULCF_CFG_28_27_MASK 0xffffffff
+#define ADDA_ULCF_CFG_28_27_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_30_29 */
+#define ADDA_ULCF_CFG_30_29_SFT 0
+#define ADDA_ULCF_CFG_30_29_MASK 0xffffffff
+#define ADDA_ULCF_CFG_30_29_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_ULCF_CFG_32_31 */
+#define ADDA_ULCF_CFG_32_31_SFT 0
+#define ADDA_ULCF_CFG_32_31_MASK 0xffffffff
+#define ADDA_ULCF_CFG_32_31_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_IP_VERSION */
+#define ADDA_ULCF_IP_VERSION_SFT 0
+#define ADDA_ULCF_IP_VERSION_MASK 0xffffffff
+#define ADDA_ULCF_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_SRC_CON0 */
+#define ULCF_CFG_EN_CTL_SFT 31
+#define ULCF_CFG_EN_CTL_MASK 0x1
+#define ULCF_CFG_EN_CTL_MASK_SFT (0x1 << 31)
+#define UL_DMIC_PHASE_SEL_CH1_SFT 27
+#define UL_DMIC_PHASE_SEL_CH1_MASK 0x7
+#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT (0x7 << 27)
+#define UL_DMIC_PHASE_SEL_CH2_SFT 24
+#define UL_DMIC_PHASE_SEL_CH2_MASK 0x7
+#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT (0x7 << 24)
+#define UL_DMIC_TWO_WIRE_CTL_SFT 23
+#define UL_DMIC_TWO_WIRE_CTL_MASK 0x1
+#define UL_DMIC_TWO_WIRE_CTL_MASK_SFT (0x1 << 23)
+#define UL_MODE_3P25M_CH2_CTL_SFT 22
+#define UL_MODE_3P25M_CH2_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22)
+#define UL_MODE_3P25M_CH1_CTL_SFT 21
+#define UL_MODE_3P25M_CH1_CTL_MASK 0x1
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17)
+#define UL_AP_DMIC_ON_SFT 16
+#define UL_AP_DMIC_ON_MASK 0x1
+#define UL_AP_DMIC_ON_MASK_SFT (0x1 << 16)
+#define DMIC_LOW_POWER_MODE_CTL_SFT 14
+#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3
+#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14)
+#define UL_DISABLE_HW_CG_CTL_SFT 12
+#define UL_DISABLE_HW_CG_CTL_MASK 0x1
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12)
+#define AMIC_26M_SEL_CTL_SFT 11
+#define AMIC_26M_SEL_CTL_MASK 0x1
+#define AMIC_26M_SEL_CTL_MASK_SFT (0x1 << 11)
+#define UL_IIR_ON_TMP_CTL_SFT 10
+#define UL_IIR_ON_TMP_CTL_MASK 0x1
+#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10)
+#define UL_IIRMODE_CTL_SFT 7
+#define UL_IIRMODE_CTL_MASK 0x7
+#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7)
+#define DIGMIC_4P33M_SEL_SFT 6
+#define DIGMIC_4P33M_SEL_MASK 0x1
+#define DIGMIC_4P33M_SEL_MASK_SFT (0x1 << 6)
+#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1
+#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5)
+#define AMIC_6P5M_SEL_CTL_SFT 4
+#define AMIC_6P5M_SEL_CTL_MASK 0x1
+#define AMIC_6P5M_SEL_CTL_MASK_SFT (0x1 << 4)
+#define AMIC_1P625M_SEL_CTL_SFT 3
+#define AMIC_1P625M_SEL_CTL_MASK 0x1
+#define AMIC_1P625M_SEL_CTL_MASK_SFT (0x1 << 3)
+#define UL_LOOP_BACK_MODE_CTL_SFT 2
+#define UL_LOOP_BACK_MODE_CTL_MASK 0x1
+#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2)
+#define UL_SDM_3_LEVEL_CTL_SFT 1
+#define UL_SDM_3_LEVEL_CTL_MASK 0x1
+#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1)
+#define UL_SRC_ON_TMP_CTL_SFT 0
+#define UL_SRC_ON_TMP_CTL_MASK 0x1
+#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_UL1_SRC_CON1 */
+#define ADDA_UL_GAIN_VALUE_SFT 16
+#define ADDA_UL_GAIN_VALUE_MASK 0xffff
+#define ADDA_UL_GAIN_VALUE_MASK_SFT (0xffff << 16)
+#define ADDA_UL_POSTIVEGAIN_SFT 12
+#define ADDA_UL_POSTIVEGAIN_MASK 0x7
+#define ADDA_UL_POSTIVEGAIN_MASK_SFT (0x7 << 12)
+#define ADDA_UL_ODDTAP_MODE_SFT 11
+#define ADDA_UL_ODDTAP_MODE_MASK 0x1
+#define ADDA_UL_ODDTAP_MODE_MASK_SFT (0x1 << 11)
+#define ADDA_UL_HALF_TAP_NUM_SFT 5
+#define ADDA_UL_HALF_TAP_NUM_MASK 0x3f
+#define ADDA_UL_HALF_TAP_NUM_MASK_SFT (0x3f << 5)
+#define FIFO_SOFT_RST_SFT 4
+#define FIFO_SOFT_RST_MASK 0x1
+#define FIFO_SOFT_RST_MASK_SFT (0x1 << 4)
+#define FIFO_SOFT_RST_EN_SFT 3
+#define FIFO_SOFT_RST_EN_MASK 0x1
+#define FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 3)
+#define LR_SWAP_SFT 2
+#define LR_SWAP_MASK 0x1
+#define LR_SWAP_MASK_SFT (0x1 << 2)
+#define GAIN_MODE_SFT 0
+#define GAIN_MODE_MASK 0x3
+#define GAIN_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_ADDA_UL1_SRC_CON2 */
+#define C_DAC_EN_CTL_SFT 27
+#define C_DAC_EN_CTL_MASK 0x1
+#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27)
+#define C_MUTE_SW_CTL_SFT 26
+#define C_MUTE_SW_CTL_MASK 0x1
+#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26)
+#define C_AMP_DIV_CH2_CTL_SFT 21
+#define C_AMP_DIV_CH2_CTL_MASK 0x7
+#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21)
+#define C_FREQ_DIV_CH2_CTL_SFT 16
+#define C_FREQ_DIV_CH2_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16)
+#define C_SINE_MODE_CH2_CTL_SFT 12
+#define C_SINE_MODE_CH2_CTL_MASK 0xf
+#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12)
+#define C_AMP_DIV_CH1_CTL_SFT 9
+#define C_AMP_DIV_CH1_CTL_MASK 0x7
+#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9)
+#define C_FREQ_DIV_CH1_CTL_SFT 4
+#define C_FREQ_DIV_CH1_CTL_MASK 0x1f
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4)
+#define C_SINE_MODE_CH1_CTL_SFT 0
+#define C_SINE_MODE_CH1_CTL_MASK 0xf
+#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0)
+
+/* AFE_ADDA_UL1_SRC_DEBUG */
+#define UL_SLT_CNT_FLAG_RESET_CTL_SFT 16
+#define UL_SLT_CNT_FLAG_RESET_CTL_MASK 0x1
+#define UL_SLT_CNT_FLAG_RESET_CTL_MASK_SFT (0x1 << 16)
+#define FIFO_DIGMIC_TESTIN_SFT 12
+#define FIFO_DIGMIC_TESTIN_MASK 0x3
+#define FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 12)
+#define FIFO_DIGMIC_WDATA_TESTEN_SFT 11
+#define FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1
+#define FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 11)
+#define SLT_CNT_THD_CTL_SFT 0
+#define SLT_CNT_THD_CTL_MASK 0x7ff
+#define SLT_CNT_THD_CTL_MASK_SFT (0x7ff << 0)
+
+/* AFE_ADDA_UL1_SRC_DEBUG_MON0 */
+#define SLT_CNT_FLAG_CTL_SFT 16
+#define SLT_CNT_FLAG_CTL_MASK 0x1
+#define SLT_CNT_FLAG_CTL_MASK_SFT (0x1 << 16)
+#define SLT_COUNTER_CTL_SFT 0
+#define SLT_COUNTER_CTL_MASK 0x7ff
+#define SLT_COUNTER_CTL_MASK_SFT (0x7ff << 0)
+
+/* AFE_ADDA_UL1_SRC_MON1 */
+#define UL_VOICE_MODE_CTL_SFT 29
+#define UL_VOICE_MODE_CTL_MASK 0x7
+#define UL_VOICE_MODE_CTL_MASK_SFT (0x7 << 29)
+#define DATA_COMB_IN_CH2_SFT 24
+#define DATA_COMB_IN_CH2_MASK 0x1f
+#define DATA_COMB_IN_CH2_MASK_SFT (0x1f << 24)
+#define DATA_COMB_OUT_CH2_SFT 0
+#define DATA_COMB_OUT_CH2_MASK 0xffffff
+#define DATA_COMB_OUT_CH2_MASK_SFT (0xffffff << 0)
+
+/* AFE_ADDA_UL1_IIR_COEF_02_01 */
+#define ADDA_IIR_COEF_02_01_SFT 0
+#define ADDA_IIR_COEF_02_01_MASK 0xffffffff
+#define ADDA_IIR_COEF_02_01_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_IIR_COEF_04_03 */
+#define ADDA_IIR_COEF_04_03_SFT 0
+#define ADDA_IIR_COEF_04_03_MASK 0xffffffff
+#define ADDA_IIR_COEF_04_03_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_IIR_COEF_06_05 */
+#define ADDA_IIR_COEF_06_05_SFT 0
+#define ADDA_IIR_COEF_06_05_MASK 0xffffffff
+#define ADDA_IIR_COEF_06_05_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_IIR_COEF_08_07 */
+#define ADDA_IIR_COEF_08_07_SFT 0
+#define ADDA_IIR_COEF_08_07_MASK 0xffffffff
+#define ADDA_IIR_COEF_08_07_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_IIR_COEF_10_09 */
+#define ADDA_IIR_COEF_10_09_SFT 0
+#define ADDA_IIR_COEF_10_09_MASK 0xffffffff
+#define ADDA_IIR_COEF_10_09_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_02_01 */
+#define ADDA_ULCF_CFG_02_01_SFT 0
+#define ADDA_ULCF_CFG_02_01_MASK 0xffffffff
+#define ADDA_ULCF_CFG_02_01_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_04_03 */
+#define ADDA_ULCF_CFG_04_03_SFT 0
+#define ADDA_ULCF_CFG_04_03_MASK 0xffffffff
+#define ADDA_ULCF_CFG_04_03_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_06_05 */
+#define ADDA_ULCF_CFG_06_05_SFT 0
+#define ADDA_ULCF_CFG_06_05_MASK 0xffffffff
+#define ADDA_ULCF_CFG_06_05_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_08_07 */
+#define ADDA_ULCF_CFG_08_07_SFT 0
+#define ADDA_ULCF_CFG_08_07_MASK 0xffffffff
+#define ADDA_ULCF_CFG_08_07_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_10_09 */
+#define ADDA_ULCF_CFG_10_09_SFT 0
+#define ADDA_ULCF_CFG_10_09_MASK 0xffffffff
+#define ADDA_ULCF_CFG_10_09_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_12_11 */
+#define ADDA_ULCF_CFG_12_11_SFT 0
+#define ADDA_ULCF_CFG_12_11_MASK 0xffffffff
+#define ADDA_ULCF_CFG_12_11_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_14_13 */
+#define ADDA_ULCF_CFG_14_13_SFT 0
+#define ADDA_ULCF_CFG_14_13_MASK 0xffffffff
+#define ADDA_ULCF_CFG_14_13_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_16_15 */
+#define ADDA_ULCF_CFG_16_15_SFT 0
+#define ADDA_ULCF_CFG_16_15_MASK 0xffffffff
+#define ADDA_ULCF_CFG_16_15_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_18_17 */
+#define ADDA_ULCF_CFG_18_17_SFT 0
+#define ADDA_ULCF_CFG_18_17_MASK 0xffffffff
+#define ADDA_ULCF_CFG_18_17_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_20_19 */
+#define ADDA_ULCF_CFG_20_19_SFT 0
+#define ADDA_ULCF_CFG_20_19_MASK 0xffffffff
+#define ADDA_ULCF_CFG_20_19_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_22_21 */
+#define ADDA_ULCF_CFG_22_21_SFT 0
+#define ADDA_ULCF_CFG_22_21_MASK 0xffffffff
+#define ADDA_ULCF_CFG_22_21_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_24_23 */
+#define ADDA_ULCF_CFG_24_23_SFT 0
+#define ADDA_ULCF_CFG_24_23_MASK 0xffffffff
+#define ADDA_ULCF_CFG_24_23_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_26_25 */
+#define ADDA_ULCF_CFG_26_25_SFT 0
+#define ADDA_ULCF_CFG_26_25_MASK 0xffffffff
+#define ADDA_ULCF_CFG_26_25_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_28_27 */
+#define ADDA_ULCF_CFG_28_27_SFT 0
+#define ADDA_ULCF_CFG_28_27_MASK 0xffffffff
+#define ADDA_ULCF_CFG_28_27_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_30_29 */
+#define ADDA_ULCF_CFG_30_29_SFT 0
+#define ADDA_ULCF_CFG_30_29_MASK 0xffffffff
+#define ADDA_ULCF_CFG_30_29_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_ULCF_CFG_32_31 */
+#define ADDA_ULCF_CFG_32_31_SFT 0
+#define ADDA_ULCF_CFG_32_31_MASK 0xffffffff
+#define ADDA_ULCF_CFG_32_31_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_IP_VERSION */
+#define ADDA_ULCF_IP_VERSION_SFT 0
+#define ADDA_ULCF_IP_VERSION_MASK 0xffffffff
+#define ADDA_ULCF_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_PROXIMITY_CON0 */
+#define PROXIMITY_CH1_ON_SFT 12
+#define PROXIMITY_CH1_ON_MASK 0x1
+#define PROXIMITY_CH1_ON_MASK_SFT (0x1 << 12)
+#define PROXIMITY_CH1_SEL_SFT 8
+#define PROXIMITY_CH1_SEL_MASK 0xf
+#define PROXIMITY_CH1_SEL_MASK_SFT (0xf << 8)
+#define PROXIMITY_CH2_ON_SFT 4
+#define PROXIMITY_CH2_ON_MASK 0x1
+#define PROXIMITY_CH2_ON_MASK_SFT (0x1 << 4)
+#define PROXIMITY_CH2_SEL_SFT 0
+#define PROXIMITY_CH2_SEL_MASK 0xf
+#define PROXIMITY_CH2_SEL_MASK_SFT (0xf << 0)
+
+/* AFE_ADDA_ULSRC_PHASE_CON0 */
+#define DMIC1_PHASE_FCLK_SEL_SFT 30
+#define DMIC1_PHASE_FCLK_SEL_MASK 0x3
+#define DMIC1_PHASE_FCLK_SEL_MASK_SFT (0x3 << 30)
+#define DMIC0_PHASE_FCLK_SEL_SFT 28
+#define DMIC0_PHASE_FCLK_SEL_MASK 0x3
+#define DMIC0_PHASE_FCLK_SEL_MASK_SFT (0x3 << 28)
+#define UL3_PHASE_FCLK_SEL_SFT 26
+#define UL3_PHASE_FCLK_SEL_MASK 0x3
+#define UL3_PHASE_FCLK_SEL_MASK_SFT (0x3 << 26)
+#define UL2_PHASE_FCLK_SEL_SFT 24
+#define UL2_PHASE_FCLK_SEL_MASK 0x3
+#define UL2_PHASE_FCLK_SEL_MASK_SFT (0x3 << 24)
+#define UL1_PHASE_FCLK_SEL_SFT 22
+#define UL1_PHASE_FCLK_SEL_MASK 0x3
+#define UL1_PHASE_FCLK_SEL_MASK_SFT (0x3 << 22)
+#define UL0_PHASE_FCLK_SEL_SFT 20
+#define UL0_PHASE_FCLK_SEL_MASK 0x3
+#define UL0_PHASE_FCLK_SEL_MASK_SFT (0x3 << 20)
+#define UL_PHASE_SYNC_FCLK_2_ON_SFT 18
+#define UL_PHASE_SYNC_FCLK_2_ON_MASK 0x1
+#define UL_PHASE_SYNC_FCLK_2_ON_MASK_SFT (0x1 << 18)
+#define UL_PHASE_SYNC_FCLK_1_ON_SFT 17
+#define UL_PHASE_SYNC_FCLK_1_ON_MASK 0x1
+#define UL_PHASE_SYNC_FCLK_1_ON_MASK_SFT (0x1 << 17)
+#define UL_PHASE_SYNC_FCLK_0_ON_SFT 16
+#define UL_PHASE_SYNC_FCLK_0_ON_MASK 0x1
+#define UL_PHASE_SYNC_FCLK_0_ON_MASK_SFT (0x1 << 16)
+#define DMIC1_PHASE_HCLK_SEL_SFT 14
+#define DMIC1_PHASE_HCLK_SEL_MASK 0x3
+#define DMIC1_PHASE_HCLK_SEL_MASK_SFT (0x3 << 14)
+#define DMIC0_PHASE_HCLK_SEL_SFT 12
+#define DMIC0_PHASE_HCLK_SEL_MASK 0x3
+#define DMIC0_PHASE_HCLK_SEL_MASK_SFT (0x3 << 12)
+#define UL3_PHASE_HCLK_SEL_SFT 10
+#define UL3_PHASE_HCLK_SEL_MASK 0x3
+#define UL3_PHASE_HCLK_SEL_MASK_SFT (0x3 << 10)
+#define UL2_PHASE_HCLK_SEL_SFT 8
+#define UL2_PHASE_HCLK_SEL_MASK 0x3
+#define UL2_PHASE_HCLK_SEL_MASK_SFT (0x3 << 8)
+#define UL1_PHASE_HCLK_SEL_SFT 6
+#define UL1_PHASE_HCLK_SEL_MASK 0x3
+#define UL1_PHASE_HCLK_SEL_MASK_SFT (0x3 << 6)
+#define UL0_PHASE_HCLK_SEL_SFT 4
+#define UL0_PHASE_HCLK_SEL_MASK 0x3
+#define UL0_PHASE_HCLK_SEL_MASK_SFT (0x3 << 4)
+#define UL_PHASE_SYNC_HCLK_2_ON_SFT 2
+#define UL_PHASE_SYNC_HCLK_2_ON_MASK 0x1
+#define UL_PHASE_SYNC_HCLK_2_ON_MASK_SFT (0x1 << 2)
+#define UL_PHASE_SYNC_HCLK_1_ON_SFT 1
+#define UL_PHASE_SYNC_HCLK_1_ON_MASK 0x1
+#define UL_PHASE_SYNC_HCLK_1_ON_MASK_SFT (0x1 << 1)
+#define UL_PHASE_SYNC_HCLK_0_ON_SFT 0
+#define UL_PHASE_SYNC_HCLK_0_ON_MASK 0x1
+#define UL_PHASE_SYNC_HCLK_0_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_ULSRC_PHASE_CON1 */
+#define DMIC_CLK_PHASE_SYNC_SET_SFT 31
+#define DMIC_CLK_PHASE_SYNC_SET_MASK 0x1
+#define DMIC_CLK_PHASE_SYNC_SET_MASK_SFT (0x1 << 31)
+#define DMIC1_PHASE_SYNC_FCLK_SET_SFT 11
+#define DMIC1_PHASE_SYNC_FCLK_SET_MASK 0x1
+#define DMIC1_PHASE_SYNC_FCLK_SET_MASK_SFT (0x1 << 11)
+#define DMIC1_PHASE_SYNC_HCLK_SET_SFT 10
+#define DMIC1_PHASE_SYNC_HCLK_SET_MASK 0x1
+#define DMIC1_PHASE_SYNC_HCLK_SET_MASK_SFT (0x1 << 10)
+#define DMIC0_PHASE_SYNC_FCLK_SET_SFT 9
+#define DMIC0_PHASE_SYNC_FCLK_SET_MASK 0x1
+#define DMIC0_PHASE_SYNC_FCLK_SET_MASK_SFT (0x1 << 9)
+#define DMIC0_PHASE_SYNC_HCLK_SET_SFT 8
+#define DMIC0_PHASE_SYNC_HCLK_SET_MASK 0x1
+#define DMIC0_PHASE_SYNC_HCLK_SET_MASK_SFT (0x1 << 8)
+#define UL3_PHASE_SYNC_FCLK_SET_SFT 7
+#define UL3_PHASE_SYNC_FCLK_SET_MASK 0x1
+#define UL3_PHASE_SYNC_FCLK_SET_MASK_SFT (0x1 << 7)
+#define UL3_PHASE_SYNC_HCLK_SET_SFT 6
+#define UL3_PHASE_SYNC_HCLK_SET_MASK 0x1
+#define UL3_PHASE_SYNC_HCLK_SET_MASK_SFT (0x1 << 6)
+#define UL2_PHASE_SYNC_FCLK_SET_SFT 5
+#define UL2_PHASE_SYNC_FCLK_SET_MASK 0x1
+#define UL2_PHASE_SYNC_FCLK_SET_MASK_SFT (0x1 << 5)
+#define UL2_PHASE_SYNC_HCLK_SET_SFT 4
+#define UL2_PHASE_SYNC_HCLK_SET_MASK 0x1
+#define UL2_PHASE_SYNC_HCLK_SET_MASK_SFT (0x1 << 4)
+#define UL1_PHASE_SYNC_FCLK_SET_SFT 3
+#define UL1_PHASE_SYNC_FCLK_SET_MASK 0x1
+#define UL1_PHASE_SYNC_FCLK_SET_MASK_SFT (0x1 << 3)
+#define UL1_PHASE_SYNC_HCLK_SET_SFT 2
+#define UL1_PHASE_SYNC_HCLK_SET_MASK 0x1
+#define UL1_PHASE_SYNC_HCLK_SET_MASK_SFT (0x1 << 2)
+#define UL0_PHASE_SYNC_FCLK_SET_SFT 1
+#define UL0_PHASE_SYNC_FCLK_SET_MASK 0x1
+#define UL0_PHASE_SYNC_FCLK_SET_MASK_SFT (0x1 << 1)
+#define UL0_PHASE_SYNC_HCLK_SET_SFT 0
+#define UL0_PHASE_SYNC_HCLK_SET_MASK 0x1
+#define UL0_PHASE_SYNC_HCLK_SET_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_ULSRC_PHASE_CON2 */
+#define DMIC1_PHASE_SYNC_1X_EN_SEL_SFT 26
+#define DMIC1_PHASE_SYNC_1X_EN_SEL_MASK 0x3
+#define DMIC1_PHASE_SYNC_1X_EN_SEL_MASK_SFT (0x3 << 26)
+#define DMIC0_PHASE_SYNC_1X_EN_SEL_SFT 24
+#define DMIC0_PHASE_SYNC_1X_EN_SEL_MASK 0x3
+#define DMIC0_PHASE_SYNC_1X_EN_SEL_MASK_SFT (0x3 << 24)
+#define UL3_PHASE_SYNC_1X_EN_SEL_SFT 22
+#define UL3_PHASE_SYNC_1X_EN_SEL_MASK 0x3
+#define UL3_PHASE_SYNC_1X_EN_SEL_MASK_SFT (0x3 << 22)
+#define UL2_PHASE_SYNC_1X_EN_SEL_SFT 20
+#define UL2_PHASE_SYNC_1X_EN_SEL_MASK 0x3
+#define UL2_PHASE_SYNC_1X_EN_SEL_MASK_SFT (0x3 << 20)
+#define UL1_PHASE_SYNC_1X_EN_SEL_SFT 18
+#define UL1_PHASE_SYNC_1X_EN_SEL_MASK 0x3
+#define UL1_PHASE_SYNC_1X_EN_SEL_MASK_SFT (0x3 << 18)
+#define UL0_PHASE_SYNC_1X_EN_SEL_SFT 16
+#define UL0_PHASE_SYNC_1X_EN_SEL_MASK 0x3
+#define UL0_PHASE_SYNC_1X_EN_SEL_MASK_SFT (0x3 << 16)
+#define UL_PHASE_SYNC_FCLK_1X_EN_2_ON_SFT 5
+#define UL_PHASE_SYNC_FCLK_1X_EN_2_ON_MASK 0x1
+#define UL_PHASE_SYNC_FCLK_1X_EN_2_ON_MASK_SFT (0x1 << 5)
+#define UL_PHASE_SYNC_FCLK_1X_EN_1_ON_SFT 4
+#define UL_PHASE_SYNC_FCLK_1X_EN_1_ON_MASK 0x1
+#define UL_PHASE_SYNC_FCLK_1X_EN_1_ON_MASK_SFT (0x1 << 4)
+#define UL_PHASE_SYNC_FCLK_1X_EN_0_ON_SFT 3
+#define UL_PHASE_SYNC_FCLK_1X_EN_0_ON_MASK 0x1
+#define UL_PHASE_SYNC_FCLK_1X_EN_0_ON_MASK_SFT (0x1 << 3)
+#define UL_PHASE_SYNC_HCLK_1X_EN_2_ON_SFT 2
+#define UL_PHASE_SYNC_HCLK_1X_EN_2_ON_MASK 0x1
+#define UL_PHASE_SYNC_HCLK_1X_EN_2_ON_MASK_SFT (0x1 << 2)
+#define UL_PHASE_SYNC_HCLK_1X_EN_1_ON_SFT 1
+#define UL_PHASE_SYNC_HCLK_1X_EN_1_ON_MASK 0x1
+#define UL_PHASE_SYNC_HCLK_1X_EN_1_ON_MASK_SFT (0x1 << 1)
+#define UL_PHASE_SYNC_HCLK_1X_EN_0_ON_SFT 0
+#define UL_PHASE_SYNC_HCLK_1X_EN_0_ON_MASK 0x1
+#define UL_PHASE_SYNC_HCLK_1X_EN_0_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_ULSRC_PHASE_CON3 */
+#define DMIC1_PHASE_SYNC_SOFT_RST_SEL_SFT 26
+#define DMIC1_PHASE_SYNC_SOFT_RST_SEL_MASK 0x3
+#define DMIC1_PHASE_SYNC_SOFT_RST_SEL_MASK_SFT (0x3 << 26)
+#define DMIC0_PHASE_SYNC_SOFT_RST_SEL_SFT 24
+#define DMIC0_PHASE_SYNC_SOFT_RST_SEL_MASK 0x3
+#define DMIC0_PHASE_SYNC_SOFT_RST_SEL_MASK_SFT (0x3 << 24)
+#define UL3_PHASE_SYNC_SOFT_RST_SEL_SFT 22
+#define UL3_PHASE_SYNC_SOFT_RST_SEL_MASK 0x3
+#define UL3_PHASE_SYNC_SOFT_RST_SEL_MASK_SFT (0x3 << 22)
+#define UL2_PHASE_SYNC_SOFT_RST_SEL_SFT 20
+#define UL2_PHASE_SYNC_SOFT_RST_SEL_MASK 0x3
+#define UL2_PHASE_SYNC_SOFT_RST_SEL_MASK_SFT (0x3 << 20)
+#define UL1_PHASE_SYNC_SOFT_RST_SEL_SFT 18
+#define UL1_PHASE_SYNC_SOFT_RST_SEL_MASK 0x3
+#define UL1_PHASE_SYNC_SOFT_RST_SEL_MASK_SFT (0x3 << 18)
+#define UL0_PHASE_SYNC_SOFT_RST_SEL_SFT 16
+#define UL0_PHASE_SYNC_SOFT_RST_SEL_MASK 0x3
+#define UL0_PHASE_SYNC_SOFT_RST_SEL_MASK_SFT (0x3 << 16)
+#define DMIC1_PHASE_SYNC_CH1_FIFO_SEL_SFT 13
+#define DMIC1_PHASE_SYNC_CH1_FIFO_SEL_MASK 0x1
+#define DMIC1_PHASE_SYNC_CH1_FIFO_SEL_MASK_SFT (0x1 << 13)
+#define DMIC0_PHASE_SYNC_CH1_FIFO_SEL_SFT 12
+#define DMIC0_PHASE_SYNC_CH1_FIFO_SEL_MASK 0x1
+#define DMIC0_PHASE_SYNC_CH1_FIFO_SEL_MASK_SFT (0x1 << 12)
+#define UL3_PHASE_SYNC_CH1_FIFO_SEL_SFT 11
+#define UL3_PHASE_SYNC_CH1_FIFO_SEL_MASK 0x1
+#define UL3_PHASE_SYNC_CH1_FIFO_SEL_MASK_SFT (0x1 << 11)
+#define UL2_PHASE_SYNC_CH1_FIFO_SEL_SFT 10
+#define UL2_PHASE_SYNC_CH1_FIFO_SEL_MASK 0x1
+#define UL2_PHASE_SYNC_CH1_FIFO_SEL_MASK_SFT (0x1 << 10)
+#define UL1_PHASE_SYNC_CH1_FIFO_SEL_SFT 9
+#define UL1_PHASE_SYNC_CH1_FIFO_SEL_MASK 0x1
+#define UL1_PHASE_SYNC_CH1_FIFO_SEL_MASK_SFT (0x1 << 9)
+#define UL0_PHASE_SYNC_CH1_FIFO_SEL_SFT 8
+#define UL0_PHASE_SYNC_CH1_FIFO_SEL_MASK 0x1
+#define UL0_PHASE_SYNC_CH1_FIFO_SEL_MASK_SFT (0x1 << 8)
+#define UL_PHASE_SYNC_SOFT_RST_EN_2_ON_SFT 5
+#define UL_PHASE_SYNC_SOFT_RST_EN_2_ON_MASK 0x1
+#define UL_PHASE_SYNC_SOFT_RST_EN_2_ON_MASK_SFT (0x1 << 5)
+#define UL_PHASE_SYNC_SOFT_RST_EN_1_ON_SFT 4
+#define UL_PHASE_SYNC_SOFT_RST_EN_1_ON_MASK 0x1
+#define UL_PHASE_SYNC_SOFT_RST_EN_1_ON_MASK_SFT (0x1 << 4)
+#define UL_PHASE_SYNC_SOFT_RST_EN_0_ON_SFT 3
+#define UL_PHASE_SYNC_SOFT_RST_EN_0_ON_MASK 0x1
+#define UL_PHASE_SYNC_SOFT_RST_EN_0_ON_MASK_SFT (0x1 << 3)
+#define UL_PHASE_SYNC_SOFT_RST_2_ON_SFT 2
+#define UL_PHASE_SYNC_SOFT_RST_2_ON_MASK 0x1
+#define UL_PHASE_SYNC_SOFT_RST_2_ON_MASK_SFT (0x1 << 2)
+#define UL_PHASE_SYNC_SOFT_RST_1_ON_SFT 1
+#define UL_PHASE_SYNC_SOFT_RST_1_ON_MASK 0x1
+#define UL_PHASE_SYNC_SOFT_RST_1_ON_MASK_SFT (0x1 << 1)
+#define UL_PHASE_SYNC_SOFT_RST_0_ON_SFT 0
+#define UL_PHASE_SYNC_SOFT_RST_0_ON_MASK 0x1
+#define UL_PHASE_SYNC_SOFT_RST_0_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_MTKAIF_IPM_VER_MON */
+#define RG_MTKAIF_IPM_VER_MON_SFT 0
+#define RG_MTKAIF_IPM_VER_MON_MASK 0xffffffff
+#define RG_MTKAIF_IPM_VER_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_MTKAIF_MON_SEL */
+#define RG_MTKAIF_MON_SEL_SFT 0
+#define RG_MTKAIF_MON_SEL_MASK 0xff
+#define RG_MTKAIF_MON_SEL_MASK_SFT (0xff << 0)
+
+/* AFE_MTKAIF_MON */
+#define RG_MTKAIF_MON_SFT 0
+#define RG_MTKAIF_MON_MASK 0xffffffff
+#define RG_MTKAIF_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_MTKAIF0_CFG0 */
+#define RG_MTKAIF0_RXIF_CLKINV_SFT 31
+#define RG_MTKAIF0_RXIF_CLKINV_MASK 0x1
+#define RG_MTKAIF0_RXIF_CLKINV_MASK_SFT (0x1 << 31)
+#define RG_MTKAIF0_RXIF_BYPASS_SRC_SFT 17
+#define RG_MTKAIF0_RXIF_BYPASS_SRC_MASK 0x1
+#define RG_MTKAIF0_RXIF_BYPASS_SRC_MASK_SFT (0x1 << 17)
+#define RG_MTKAIF0_RXIF_PROTOCOL2_SFT 16
+#define RG_MTKAIF0_RXIF_PROTOCOL2_MASK 0x1
+#define RG_MTKAIF0_RXIF_PROTOCOL2_MASK_SFT (0x1 << 16)
+#define RG_MTKAIF0_TXIF_NLE_DEBUG_SFT 8
+#define RG_MTKAIF0_TXIF_NLE_DEBUG_MASK 0x1
+#define RG_MTKAIF0_TXIF_NLE_DEBUG_MASK_SFT (0x1 << 8)
+#define RG_MTKAIF0_TXIF_BYPASS_SRC_SFT 5
+#define RG_MTKAIF0_TXIF_BYPASS_SRC_MASK 0x1
+#define RG_MTKAIF0_TXIF_BYPASS_SRC_MASK_SFT (0x1 << 5)
+#define RG_MTKAIF0_TXIF_PROTOCOL2_SFT 4
+#define RG_MTKAIF0_TXIF_PROTOCOL2_MASK 0x1
+#define RG_MTKAIF0_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4)
+#define RG_MTKAIF0_TXIF_8TO5_SFT 2
+#define RG_MTKAIF0_TXIF_8TO5_MASK 0x1
+#define RG_MTKAIF0_TXIF_8TO5_MASK_SFT (0x1 << 2)
+#define RG_MTKAIF0_RXIF_8TO5_SFT 1
+#define RG_MTKAIF0_RXIF_8TO5_MASK 0x1
+#define RG_MTKAIF0_RXIF_8TO5_MASK_SFT (0x1 << 1)
+#define RG_MTKAIF0_TX2RX_LOOPBACK1_SFT 0
+#define RG_MTKAIF0_TX2RX_LOOPBACK1_MASK 0x1
+#define RG_MTKAIF0_TX2RX_LOOPBACK1_MASK_SFT (0x1 << 0)
+
+/* AFE_MTKAIF0_TX_CFG0 */
+#define RG_MTKAIF0_TXIF_NLE_FIFO_SWAP_SFT 23
+#define RG_MTKAIF0_TXIF_NLE_FIFO_SWAP_MASK 0x1
+#define RG_MTKAIF0_TXIF_NLE_FIFO_SWAP_MASK_SFT (0x1 << 23)
+#define RG_MTKAIF0_TXIF_NLE_FIFO_RSP_SFT 20
+#define RG_MTKAIF0_TXIF_NLE_FIFO_RSP_MASK 0x7
+#define RG_MTKAIF0_TXIF_NLE_FIFO_RSP_MASK_SFT (0x7 << 20)
+#define RG_MTKAIF0_TXIF_FIFO_SWAP_SFT 15
+#define RG_MTKAIF0_TXIF_FIFO_SWAP_MASK 0x1
+#define RG_MTKAIF0_TXIF_FIFO_SWAP_MASK_SFT (0x1 << 15)
+#define RG_MTKAIF0_TXIF_FIFO_RSP_SFT 12
+#define RG_MTKAIF0_TXIF_FIFO_RSP_MASK 0x7
+#define RG_MTKAIF0_TXIF_FIFO_RSP_MASK_SFT (0x7 << 12)
+#define RG_MTKAIF0_TXIF_SYNC_WORD1_SFT 4
+#define RG_MTKAIF0_TXIF_SYNC_WORD1_MASK 0x7
+#define RG_MTKAIF0_TXIF_SYNC_WORD1_MASK_SFT (0x7 << 4)
+#define RG_MTKAIF0_TXIF_SYNC_WORD0_SFT 0
+#define RG_MTKAIF0_TXIF_SYNC_WORD0_MASK 0x7
+#define RG_MTKAIF0_TXIF_SYNC_WORD0_MASK_SFT (0x7 << 0)
+
+/* AFE_MTKAIF0_RX_CFG0 */
+#define RG_MTKAIF0_RXIF_VOICE_MODE_SFT 20
+#define RG_MTKAIF0_RXIF_VOICE_MODE_MASK 0xf
+#define RG_MTKAIF0_RXIF_VOICE_MODE_MASK_SFT (0xf << 20)
+#define RG_MTKAIF0_RXIF_DETECT_ON_SFT 16
+#define RG_MTKAIF0_RXIF_DETECT_ON_MASK 0x1
+#define RG_MTKAIF0_RXIF_DETECT_ON_MASK_SFT (0x1 << 16)
+#define RG_MTKAIF0_RXIF_DATA_BIT_SFT 8
+#define RG_MTKAIF0_RXIF_DATA_BIT_MASK 0x7
+#define RG_MTKAIF0_RXIF_DATA_BIT_MASK_SFT (0x7 << 8)
+#define RG_MTKAIF0_RXIF_FIFO_RSP_SFT 4
+#define RG_MTKAIF0_RXIF_FIFO_RSP_MASK 0x7
+#define RG_MTKAIF0_RXIF_FIFO_RSP_MASK_SFT (0x7 << 4)
+#define RG_MTKAIF0_RXIF_DATA_MODE_SFT 0
+#define RG_MTKAIF0_RXIF_DATA_MODE_MASK 0x1
+#define RG_MTKAIF0_RXIF_DATA_MODE_MASK_SFT (0x1 << 0)
+
+/* AFE_MTKAIF0_RX_CFG1 */
+#define RG_MTKAIF0_RXIF_CLEAR_SYNC_FAIL_SFT 28
+#define RG_MTKAIF0_RXIF_CLEAR_SYNC_FAIL_MASK 0x1
+#define RG_MTKAIF0_RXIF_CLEAR_SYNC_FAIL_MASK_SFT (0x1 << 28)
+#define RG_MTKAIF0_RXIF_SYNC_CNT_TABLE_SFT 16
+#define RG_MTKAIF0_RXIF_SYNC_CNT_TABLE_MASK 0xfff
+#define RG_MTKAIF0_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 16)
+#define RG_MTKAIF0_RXIF_SYNC_SEARCH_TABLE_SFT 12
+#define RG_MTKAIF0_RXIF_SYNC_SEARCH_TABLE_MASK 0xf
+#define RG_MTKAIF0_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0xf << 12)
+#define RG_MTKAIF0_RXIF_INVALID_SYNC_CHECK_ROUND_SFT 8
+#define RG_MTKAIF0_RXIF_INVALID_SYNC_CHECK_ROUND_MASK 0xf
+#define RG_MTKAIF0_RXIF_INVALID_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8)
+#define RG_MTKAIF0_RXIF_SYNC_CHECK_ROUND_SFT 4
+#define RG_MTKAIF0_RXIF_SYNC_CHECK_ROUND_MASK 0xf
+#define RG_MTKAIF0_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4)
+
+/* AFE_MTKAIF0_RX_CFG2 */
+#define RG_MTKAIF0_RXIF_SYNC_WORD1_DISABLE_SFT 27
+#define RG_MTKAIF0_RXIF_SYNC_WORD1_DISABLE_MASK 0x1
+#define RG_MTKAIF0_RXIF_SYNC_WORD1_DISABLE_MASK_SFT (0x1 << 27)
+#define RG_MTKAIF0_RXIF_SYNC_WORD1_SFT 24
+#define RG_MTKAIF0_RXIF_SYNC_WORD1_MASK 0x7
+#define RG_MTKAIF0_RXIF_SYNC_WORD1_MASK_SFT (0x7 << 24)
+#define RG_MTKAIF0_RXIF_SYNC_WORD0_DISABLE_SFT 23
+#define RG_MTKAIF0_RXIF_SYNC_WORD0_DISABLE_MASK 0x1
+#define RG_MTKAIF0_RXIF_SYNC_WORD0_DISABLE_MASK_SFT (0x1 << 23)
+#define RG_MTKAIF0_RXIF_SYNC_WORD0_SFT 20
+#define RG_MTKAIF0_RXIF_SYNC_WORD0_MASK 0x7
+#define RG_MTKAIF0_RXIF_SYNC_WORD0_MASK_SFT (0x7 << 20)
+#define RG_MTKAIF0_RXIF_DELAY_CYCLE_SFT 12
+#define RG_MTKAIF0_RXIF_DELAY_CYCLE_MASK 0xf
+#define RG_MTKAIF0_RXIF_DELAY_CYCLE_MASK_SFT (0xf << 12)
+#define RG_MTKAIF0_RXIF_DELAY_DATA_SFT 8
+#define RG_MTKAIF0_RXIF_DELAY_DATA_MASK 0x1
+#define RG_MTKAIF0_RXIF_DELAY_DATA_MASK_SFT (0x1 << 8)
+
+/* AFE_MTKAIF1_CFG0 */
+#define RG_MTKAIF1_RXIF_CLKINV_ADC_SFT 31
+#define RG_MTKAIF1_RXIF_CLKINV_ADC_MASK 0x1
+#define RG_MTKAIF1_RXIF_CLKINV_ADC_MASK_SFT (0x1 << 31)
+#define RG_MTKAIF1_RXIF_BYPASS_SRC_SFT 17
+#define RG_MTKAIF1_RXIF_BYPASS_SRC_MASK 0x1
+#define RG_MTKAIF1_RXIF_BYPASS_SRC_MASK_SFT (0x1 << 17)
+#define RG_MTKAIF1_RXIF_PROTOCOL2_SFT 16
+#define RG_MTKAIF1_RXIF_PROTOCOL2_MASK 0x1
+#define RG_MTKAIF1_RXIF_PROTOCOL2_MASK_SFT (0x1 << 16)
+#define RG_MTKAIF1_TXIF_NLE_DEBUG_SFT 8
+#define RG_MTKAIF1_TXIF_NLE_DEBUG_MASK 0x1
+#define RG_MTKAIF1_TXIF_NLE_DEBUG_MASK_SFT (0x1 << 8)
+#define RG_MTKAIF1_TXIF_BYPASS_SRC_SFT 5
+#define RG_MTKAIF1_TXIF_BYPASS_SRC_MASK 0x1
+#define RG_MTKAIF1_TXIF_BYPASS_SRC_MASK_SFT (0x1 << 5)
+#define RG_MTKAIF1_TXIF_PROTOCOL2_SFT 4
+#define RG_MTKAIF1_TXIF_PROTOCOL2_MASK 0x1
+#define RG_MTKAIF1_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4)
+#define RG_MTKAIF1_TXIF_8TO5_SFT 2
+#define RG_MTKAIF1_TXIF_8TO5_MASK 0x1
+#define RG_MTKAIF1_TXIF_8TO5_MASK_SFT (0x1 << 2)
+#define RG_MTKAIF1_RXIF_8TO5_SFT 1
+#define RG_MTKAIF1_RXIF_8TO5_MASK 0x1
+#define RG_MTKAIF1_RXIF_8TO5_MASK_SFT (0x1 << 1)
+#define RG_MTKAIF1_IF_LOOPBACK1_SFT 0
+#define RG_MTKAIF1_IF_LOOPBACK1_MASK 0x1
+#define RG_MTKAIF1_IF_LOOPBACK1_MASK_SFT (0x1 << 0)
+
+/* AFE_MTKAIF1_TX_CFG0 */
+#define RG_MTKAIF1_TXIF_NLE_FIFO_SWAP_SFT 23
+#define RG_MTKAIF1_TXIF_NLE_FIFO_SWAP_MASK 0x1
+#define RG_MTKAIF1_TXIF_NLE_FIFO_SWAP_MASK_SFT (0x1 << 23)
+#define RG_MTKAIF1_TXIF_NLE_FIFO_RSP_SFT 20
+#define RG_MTKAIF1_TXIF_NLE_FIFO_RSP_MASK 0x7
+#define RG_MTKAIF1_TXIF_NLE_FIFO_RSP_MASK_SFT (0x7 << 20)
+#define RG_MTKAIF1_TXIF_FIFO_SWAP_SFT 15
+#define RG_MTKAIF1_TXIF_FIFO_SWAP_MASK 0x1
+#define RG_MTKAIF1_TXIF_FIFO_SWAP_MASK_SFT (0x1 << 15)
+#define RG_MTKAIF1_TXIF_FIFO_RSP_SFT 12
+#define RG_MTKAIF1_TXIF_FIFO_RSP_MASK 0x7
+#define RG_MTKAIF1_TXIF_FIFO_RSP_MASK_SFT (0x7 << 12)
+#define RG_MTKAIF1_TXIF_SYNC_WORD1_SFT 4
+#define RG_MTKAIF1_TXIF_SYNC_WORD1_MASK 0x7
+#define RG_MTKAIF1_TXIF_SYNC_WORD1_MASK_SFT (0x7 << 4)
+#define RG_MTKAIF1_TXIF_SYNC_WORD0_SFT 0
+#define RG_MTKAIF1_TXIF_SYNC_WORD0_MASK 0x7
+#define RG_MTKAIF1_TXIF_SYNC_WORD0_MASK_SFT (0x7 << 0)
+
+/* AFE_MTKAIF1_RX_CFG0 */
+#define RG_MTKAIF1_RXIF_VOICE_MODE_SFT 20
+#define RG_MTKAIF1_RXIF_VOICE_MODE_MASK 0xf
+#define RG_MTKAIF1_RXIF_VOICE_MODE_MASK_SFT (0xf << 20)
+#define RG_MTKAIF1_RXIF_DETECT_ON_SFT 16
+#define RG_MTKAIF1_RXIF_DETECT_ON_MASK 0x1
+#define RG_MTKAIF1_RXIF_DETECT_ON_MASK_SFT (0x1 << 16)
+#define RG_MTKAIF1_RXIF_DATA_BIT_SFT 8
+#define RG_MTKAIF1_RXIF_DATA_BIT_MASK 0x7
+#define RG_MTKAIF1_RXIF_DATA_BIT_MASK_SFT (0x7 << 8)
+#define RG_MTKAIF1_RXIF_FIFO_RSP_SFT 4
+#define RG_MTKAIF1_RXIF_FIFO_RSP_MASK 0x7
+#define RG_MTKAIF1_RXIF_FIFO_RSP_MASK_SFT (0x7 << 4)
+#define RG_MTKAIF1_RXIF_DATA_MODE_SFT 0
+#define RG_MTKAIF1_RXIF_DATA_MODE_MASK 0x1
+#define RG_MTKAIF1_RXIF_DATA_MODE_MASK_SFT (0x1 << 0)
+
+/* AFE_MTKAIF1_RX_CFG1 */
+#define RG_MTKAIF1_RXIF_CLEAR_SYNC_FAIL_SFT 28
+#define RG_MTKAIF1_RXIF_CLEAR_SYNC_FAIL_MASK 0x1
+#define RG_MTKAIF1_RXIF_CLEAR_SYNC_FAIL_MASK_SFT (0x1 << 28)
+#define RG_MTKAIF1_RXIF_SYNC_CNT_TABLE_SFT 16
+#define RG_MTKAIF1_RXIF_SYNC_CNT_TABLE_MASK 0xfff
+#define RG_MTKAIF1_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 16)
+#define RG_MTKAIF1_RXIF_SYNC_SEARCH_TABLE_SFT 12
+#define RG_MTKAIF1_RXIF_SYNC_SEARCH_TABLE_MASK 0xf
+#define RG_MTKAIF1_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0xf << 12)
+#define RG_MTKAIF1_RXIF_INVALID_SYNC_CHECK_ROUND_SFT 8
+#define RG_MTKAIF1_RXIF_INVALID_SYNC_CHECK_ROUND_MASK 0xf
+#define RG_MTKAIF1_RXIF_INVALID_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8)
+#define RG_MTKAIF1_RXIF_SYNC_CHECK_ROUND_SFT 4
+#define RG_MTKAIF1_RXIF_SYNC_CHECK_ROUND_MASK 0xf
+#define RG_MTKAIF1_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4)
+
+/* AFE_MTKAIF1_RX_CFG2 */
+#define RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_SFT 27
+#define RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_MASK 0x1
+#define RG_MTKAIF1_RXIF_SYNC_WORD1_DISABLE_MASK_SFT (0x1 << 27)
+#define RG_MTKAIF1_RXIF_SYNC_WORD1_SFT 24
+#define RG_MTKAIF1_RXIF_SYNC_WORD1_MASK 0x7
+#define RG_MTKAIF1_RXIF_SYNC_WORD1_MASK_SFT (0x7 << 24)
+#define RG_MTKAIF1_RXIF_SYNC_WORD0_DISABLE_SFT 23
+#define RG_MTKAIF1_RXIF_SYNC_WORD0_DISABLE_MASK 0x1
+#define RG_MTKAIF1_RXIF_SYNC_WORD0_DISABLE_MASK_SFT (0x1 << 23)
+#define RG_MTKAIF1_RXIF_SYNC_WORD0_SFT 20
+#define RG_MTKAIF1_RXIF_SYNC_WORD0_MASK 0x7
+#define RG_MTKAIF1_RXIF_SYNC_WORD0_MASK_SFT (0x7 << 20)
+#define RG_MTKAIF1_RXIF_DELAY_CYCLE_SFT 12
+#define RG_MTKAIF1_RXIF_DELAY_CYCLE_MASK 0xf
+#define RG_MTKAIF1_RXIF_DELAY_CYCLE_MASK_SFT (0xf << 12)
+#define RG_MTKAIF1_RXIF_DELAY_DATA_SFT 8
+#define RG_MTKAIF1_RXIF_DELAY_DATA_MASK 0x1
+#define RG_MTKAIF1_RXIF_DELAY_DATA_MASK_SFT (0x1 << 8)
+
+/* AFE_AUD_PAD_TOP_CFG0 */
+#define AUD_PAD_TOP_FIFO_RSP_SFT 4
+#define AUD_PAD_TOP_FIFO_RSP_MASK 0xf
+#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT (0xf << 4)
+#define RG_RX_PROTOCOL2_SFT 3
+#define RG_RX_PROTOCOL2_MASK 0x1
+#define RG_RX_PROTOCOL2_MASK_SFT (0x1 << 3)
+#define RG_RX_FIFO_ON_SFT 0
+#define RG_RX_FIFO_ON_MASK 0x1
+#define RG_RX_FIFO_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_AUD_PAD_TOP_MON */
+#define AUD_PAD_TOP_MON_SFT 0
+#define AUD_PAD_TOP_MON_MASK 0xffff
+#define AUD_PAD_TOP_MON_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_MTKAIFV4_TX_CFG0 */
+#define MTKAIFV4_TXIF_EN_SEL_SFT 12
+#define MTKAIFV4_TXIF_EN_SEL_MASK 0x1
+#define MTKAIFV4_TXIF_EN_SEL_MASK_SFT (0x1 << 12)
+#define MTKAIFV4_TXIF_V4_SFT 11
+#define MTKAIFV4_TXIF_V4_MASK 0x1
+#define MTKAIFV4_TXIF_V4_MASK_SFT (0x1 << 11)
+#define MTKAIFV4_ADDA6_OUT_EN_SEL_SFT 10
+#define MTKAIFV4_ADDA6_OUT_EN_SEL_MASK 0x1
+#define MTKAIFV4_ADDA6_OUT_EN_SEL_MASK_SFT (0x1 << 10)
+#define MTKAIFV4_ADDA_OUT_EN_SEL_SFT 9
+#define MTKAIFV4_ADDA_OUT_EN_SEL_MASK 0x1
+#define MTKAIFV4_ADDA_OUT_EN_SEL_MASK_SFT (0x1 << 9)
+#define MTKAIFV4_TXIF_INPUT_MODE_SFT 4
+#define MTKAIFV4_TXIF_INPUT_MODE_MASK 0x1f
+#define MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT (0x1f << 4)
+#define MTKAIFV4_TXIF_FOUR_CHANNEL_SFT 1
+#define MTKAIFV4_TXIF_FOUR_CHANNEL_MASK 0x1
+#define MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT (0x1 << 1)
+#define MTKAIFV4_TXIF_AFE_ON_SFT 0
+#define MTKAIFV4_TXIF_AFE_ON_MASK 0x1
+#define MTKAIFV4_TXIF_AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA6_MTKAIFV4_TX_CFG0 */
+#define ADDA6_MTKAIFV4_TXIF_EN_SEL_SFT 12
+#define ADDA6_MTKAIFV4_TXIF_EN_SEL_MASK 0x1
+#define ADDA6_MTKAIFV4_TXIF_EN_SEL_MASK_SFT (0x1 << 12)
+#define ADDA6_MTKAIFV4_TXIF_INPUT_MODE_SFT 4
+#define ADDA6_MTKAIFV4_TXIF_INPUT_MODE_MASK 0x1f
+#define ADDA6_MTKAIFV4_TXIF_INPUT_MODE_MASK_SFT (0x1f << 4)
+#define ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_SFT 1
+#define ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_MASK 0x1
+#define ADDA6_MTKAIFV4_TXIF_FOUR_CHANNEL_MASK_SFT (0x1 << 1)
+#define ADDA6_MTKAIFV4_TXIF_AFE_ON_SFT 0
+#define ADDA6_MTKAIFV4_TXIF_AFE_ON_MASK 0x1
+#define ADDA6_MTKAIFV4_TXIF_AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_MTKAIFV4_RX_CFG0 */
+#define MTKAIFV4_RXIF_CLKINV_SFT 31
+#define MTKAIFV4_RXIF_CLKINV_MASK 0x1
+#define MTKAIFV4_RXIF_CLKINV_MASK_SFT (0x1 << 31)
+#define MTKAIFV4_RXIF_LOOPBACK_MODE_SFT 28
+#define MTKAIFV4_RXIF_LOOPBACK_MODE_MASK 0x1
+#define MTKAIFV4_RXIF_LOOPBACK_MODE_MASK_SFT (0x1 << 28)
+#define MTKAIFV4_UL_CH7CH8_IN_EN_SEL_SFT 19
+#define MTKAIFV4_UL_CH7CH8_IN_EN_SEL_MASK 0x1
+#define MTKAIFV4_UL_CH7CH8_IN_EN_SEL_MASK_SFT (0x1 << 19)
+#define MTKAIFV4_UL_CH5CH6_IN_EN_SEL_SFT 18
+#define MTKAIFV4_UL_CH5CH6_IN_EN_SEL_MASK 0x1
+#define MTKAIFV4_UL_CH5CH6_IN_EN_SEL_MASK_SFT (0x1 << 18)
+#define MTKAIFV4_UL_CH3CH4_IN_EN_SEL_SFT 17
+#define MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK 0x1
+#define MTKAIFV4_UL_CH3CH4_IN_EN_SEL_MASK_SFT (0x1 << 17)
+#define MTKAIFV4_UL_CH1CH2_IN_EN_SEL_SFT 16
+#define MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK 0x1
+#define MTKAIFV4_UL_CH1CH2_IN_EN_SEL_MASK_SFT (0x1 << 16)
+#define MTKAIFV4_RXIF_EN_SEL_SFT 12
+#define MTKAIFV4_RXIF_EN_SEL_MASK 0x1
+#define MTKAIFV4_RXIF_EN_SEL_MASK_SFT (0x1 << 12)
+#define MTKAIFV4_RXIF_INPUT_MODE_SFT 4
+#define MTKAIFV4_RXIF_INPUT_MODE_MASK 0x1f
+#define MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT (0x1f << 4)
+#define MTKAIFV4_RXIF_FOUR_CHANNEL_SFT 1
+#define MTKAIFV4_RXIF_FOUR_CHANNEL_MASK 0x1
+#define MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT (0x1 << 1)
+#define MTKAIFV4_RXIF_AFE_ON_SFT 0
+#define MTKAIFV4_RXIF_AFE_ON_MASK 0x1
+#define MTKAIFV4_RXIF_AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_MTKAIFV4_RX_CFG1 */
+#define MTKAIFV4_RXIF_SYNC_CNT_TABLE_SFT 17
+#define MTKAIFV4_RXIF_SYNC_CNT_TABLE_MASK 0xfff
+#define MTKAIFV4_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 17)
+#define MTKAIFV4_RXIF_SYNC_SEARCH_TABLE_SFT 12
+#define MTKAIFV4_RXIF_SYNC_SEARCH_TABLE_MASK 0x1f
+#define MTKAIFV4_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0x1f << 12)
+#define MTKAIFV4_RXIF_INVAILD_SYNC_CHECK_ROUND_SFT 8
+#define MTKAIFV4_RXIF_INVAILD_SYNC_CHECK_ROUND_MASK 0xf
+#define MTKAIFV4_RXIF_INVAILD_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8)
+#define MTKAIFV4_RXIF_SYNC_CHECK_ROUND_SFT 4
+#define MTKAIFV4_RXIF_SYNC_CHECK_ROUND_MASK 0xf
+#define MTKAIFV4_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4)
+#define MTKAIFV4_RXIF_FIFO_RSP_SFT 1
+#define MTKAIFV4_RXIF_FIFO_RSP_MASK 0x7
+#define MTKAIFV4_RXIF_FIFO_RSP_MASK_SFT (0x7 << 1)
+#define MTKAIFV4_RXIF_SELF_DEFINE_TABLE_SFT 0
+#define MTKAIFV4_RXIF_SELF_DEFINE_TABLE_MASK 0x1
+#define MTKAIFV4_RXIF_SELF_DEFINE_TABLE_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA6_MTKAIFV4_RX_CFG0 */
+#define ADDA6_MTKAIFV4_RXIF_CLKINV_SFT 31
+#define ADDA6_MTKAIFV4_RXIF_CLKINV_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_CLKINV_MASK_SFT (0x1 << 31)
+#define ADDA6_MTKAIFV4_RXIF_LOOPBACK_MODE_SFT 28
+#define ADDA6_MTKAIFV4_RXIF_LOOPBACK_MODE_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_LOOPBACK_MODE_MASK_SFT (0x1 << 28)
+#define ADDA6_MTKAIFV4_RXIF_EN_SEL_SFT 12
+#define ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_EN_SEL_MASK_SFT (0x1 << 12)
+#define ADDA6_MTKAIFV4_RXIF_INPUT_MODE_SFT 4
+#define ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK 0x1f
+#define ADDA6_MTKAIFV4_RXIF_INPUT_MODE_MASK_SFT (0x1f << 4)
+#define ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_SFT 1
+#define ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_FOUR_CHANNEL_MASK_SFT (0x1 << 1)
+#define ADDA6_MTKAIFV4_RXIF_AFE_ON_SFT 0
+#define ADDA6_MTKAIFV4_RXIF_AFE_ON_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_AFE_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA6_MTKAIFV4_RX_CFG1 */
+#define ADDA6_MTKAIFV4_RXIF_SYNC_CNT_TABLE_SFT 17
+#define ADDA6_MTKAIFV4_RXIF_SYNC_CNT_TABLE_MASK 0xfff
+#define ADDA6_MTKAIFV4_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 17)
+#define ADDA6_MTKAIFV4_RXIF_SYNC_SEARCH_TABLE_SFT 12
+#define ADDA6_MTKAIFV4_RXIF_SYNC_SEARCH_TABLE_MASK 0x1f
+#define ADDA6_MTKAIFV4_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0x1f << 12)
+#define ADDA6_MTKAIFV4_RXIF_INVAILD_SYNC_CHECK_ROUND_SFT 8
+#define ADDA6_MTKAIFV4_RXIF_INVAILD_SYNC_CHECK_ROUND_MASK 0xf
+#define ADDA6_MTKAIFV4_RXIF_INVAILD_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8)
+#define ADDA6_MTKAIFV4_RXIF_SYNC_CHECK_ROUND_SFT 4
+#define ADDA6_MTKAIFV4_RXIF_SYNC_CHECK_ROUND_MASK 0xf
+#define ADDA6_MTKAIFV4_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4)
+#define ADDA6_MTKAIFV4_RXIF_FIFO_RSP_SFT 1
+#define ADDA6_MTKAIFV4_RXIF_FIFO_RSP_MASK 0x7
+#define ADDA6_MTKAIFV4_RXIF_FIFO_RSP_MASK_SFT (0x7 << 1)
+#define ADDA6_MTKAIFV4_RXIF_SELF_DEFINE_TABLE_SFT 0
+#define ADDA6_MTKAIFV4_RXIF_SELF_DEFINE_TABLE_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_SELF_DEFINE_TABLE_MASK_SFT (0x1 << 0)
+
+/* AFE_ADDA_MTKAIFV4_TX_SYNCWORD_CFG */
+#define ADDA6_MTKAIFV4_TXIF_SYNCWORD_SFT 16
+#define ADDA6_MTKAIFV4_TXIF_SYNCWORD_MASK 0xffff
+#define ADDA6_MTKAIFV4_TXIF_SYNCWORD_MASK_SFT (0xffff << 16)
+#define ADDA_MTKAIFV4_TXIF_SYNCWORD_SFT 0
+#define ADDA_MTKAIFV4_TXIF_SYNCWORD_MASK 0xffff
+#define ADDA_MTKAIFV4_TXIF_SYNCWORD_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_MTKAIFV4_RX_SYNCWORD_CFG */
+#define ADDA6_MTKAIFV4_RXIF_SYNCWORD_SFT 16
+#define ADDA6_MTKAIFV4_RXIF_SYNCWORD_MASK 0xffff
+#define ADDA6_MTKAIFV4_RXIF_SYNCWORD_MASK_SFT (0xffff << 16)
+#define ADDA_MTKAIFV4_RXIF_SYNCWORD_SFT 0
+#define ADDA_MTKAIFV4_RXIF_SYNCWORD_MASK 0xffff
+#define ADDA_MTKAIFV4_RXIF_SYNCWORD_MASK_SFT (0xffff << 0)
+
+/* AFE_ADDA_MTKAIFV4_MON0 */
+#define MTKAIFV4_TXIF_SDATA_OUT_SFT 23
+#define MTKAIFV4_TXIF_SDATA_OUT_MASK 0x1
+#define MTKAIFV4_TXIF_SDATA_OUT_MASK_SFT (0x1 << 23)
+#define MTKAIFV4_RXIF_SDATA_IN_SFT 22
+#define MTKAIFV4_RXIF_SDATA_IN_MASK 0x1
+#define MTKAIFV4_RXIF_SDATA_IN_MASK_SFT (0x1 << 22)
+#define MTKAIFV4_RXIF_SEARCH_FAIL_FLAG_SFT 21
+#define MTKAIFV4_RXIF_SEARCH_FAIL_FLAG_MASK 0x1
+#define MTKAIFV4_RXIF_SEARCH_FAIL_FLAG_MASK_SFT (0x1 << 21)
+#define MTKAIFV4_RXIF_ADC_FIFO_STATUS_SFT 0
+#define MTKAIFV4_RXIF_ADC_FIFO_STATUS_MASK 0xfff
+#define MTKAIFV4_RXIF_ADC_FIFO_STATUS_MASK_SFT (0xfff << 0)
+
+/* AFE_ADDA_MTKAIFV4_MON1 */
+#define MTKAIFV4_RXIF_OUT_CH4_SFT 24
+#define MTKAIFV4_RXIF_OUT_CH4_MASK 0xff
+#define MTKAIFV4_RXIF_OUT_CH4_MASK_SFT (0xff << 24)
+#define MTKAIFV4_RXIF_OUT_CH3_SFT 16
+#define MTKAIFV4_RXIF_OUT_CH3_MASK 0xff
+#define MTKAIFV4_RXIF_OUT_CH3_MASK_SFT (0xff << 16)
+#define MTKAIFV4_RXIF_OUT_CH2_SFT 8
+#define MTKAIFV4_RXIF_OUT_CH2_MASK 0xff
+#define MTKAIFV4_RXIF_OUT_CH2_MASK_SFT (0xff << 8)
+#define MTKAIFV4_RXIF_OUT_CH1_SFT 0
+#define MTKAIFV4_RXIF_OUT_CH1_MASK 0xff
+#define MTKAIFV4_RXIF_OUT_CH1_MASK_SFT (0xff << 0)
+
+/* AFE_ADDA6_MTKAIFV4_MON0 */
+#define ADDA6_MTKAIFV4_TXIF_SDATA_OUT_SFT 23
+#define ADDA6_MTKAIFV4_TXIF_SDATA_OUT_MASK 0x1
+#define ADDA6_MTKAIFV4_TXIF_SDATA_OUT_MASK_SFT (0x1 << 23)
+#define ADDA6_MTKAIFV4_RXIF_SDATA_IN_SFT 22
+#define ADDA6_MTKAIFV4_RXIF_SDATA_IN_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_SDATA_IN_MASK_SFT (0x1 << 22)
+#define ADDA6_MTKAIFV4_RXIF_SEARCH_FAIL_FLAG_SFT 21
+#define ADDA6_MTKAIFV4_RXIF_SEARCH_FAIL_FLAG_MASK 0x1
+#define ADDA6_MTKAIFV4_RXIF_SEARCH_FAIL_FLAG_MASK_SFT (0x1 << 21)
+#define ADDA6_MTKAIFV3P3_RXIF_ADC_FIFO_STATUS_SFT 0
+#define ADDA6_MTKAIFV3P3_RXIF_ADC_FIFO_STATUS_MASK 0xfff
+#define ADDA6_MTKAIFV3P3_RXIF_ADC_FIFO_STATUS_MASK_SFT (0xfff << 0)
+
+/* ETDM_IN0_CON0 */
+/* ETDM_IN1_CON0 */
+#define REG_ETDM_IN_EN_SFT 0
+#define REG_ETDM_IN_EN_MASK 0x1
+#define REG_ETDM_IN_EN_MASK_SFT (0x1 << 0)
+#define REG_SYNC_MODE_SFT 1
+#define REG_SYNC_MODE_MASK 0x1
+#define REG_SYNC_MODE_MASK_SFT (0x1 << 1)
+#define REG_LSB_FIRST_SFT 3
+#define REG_LSB_FIRST_MASK 0x1
+#define REG_LSB_FIRST_MASK_SFT (0x1 << 3)
+#define REG_SOFT_RST_SFT 4
+#define REG_SOFT_RST_MASK 0x1
+#define REG_SOFT_RST_MASK_SFT (0x1 << 4)
+#define REG_SLAVE_MODE_SFT 5
+#define REG_SLAVE_MODE_MASK 0x1
+#define REG_SLAVE_MODE_MASK_SFT (0x1 << 5)
+#define REG_FMT_SFT 6
+#define REG_FMT_MASK 0x7
+#define REG_FMT_MASK_SFT (0x7 << 6)
+#define REG_LRCK_EDGE_SEL_SFT 10
+#define REG_LRCK_EDGE_SEL_MASK 0x1
+#define REG_LRCK_EDGE_SEL_MASK_SFT (0x1 << 10)
+#define REG_BIT_LENGTH_SFT 11
+#define REG_BIT_LENGTH_MASK 0x1f
+#define REG_BIT_LENGTH_MASK_SFT (0x1f << 11)
+#define REG_WORD_LENGTH_SFT 16
+#define REG_WORD_LENGTH_MASK 0x1f
+#define REG_WORD_LENGTH_MASK_SFT (0x1f << 16)
+#define REG_CH_NUM_SFT 23
+#define REG_CH_NUM_MASK 0x1f
+#define REG_CH_NUM_MASK_SFT (0x1f << 23)
+#define REG_RELATCH_1X_EN_DOMAIN_SEL_SFT 28
+#define REG_RELATCH_1X_EN_DOMAIN_SEL_MASK 0x7
+#define REG_RELATCH_1X_EN_DOMAIN_SEL_MASK_SFT (0x7 << 28)
+#define REG_VALID_TOGETHER_SFT 31
+#define REG_VALID_TOGETHER_MASK 0x1
+#define REG_VALID_TOGETHER_MASK_SFT (0x1 << 31)
+
+/* ETDM_IN0_CON1 */
+/* ETDM_IN1_CON1 */
+#define REG_INITIAL_COUNT_SFT 0
+#define REG_INITIAL_COUNT_MASK 0x1f
+#define REG_INITIAL_COUNT_MASK_SFT (0x1f << 0)
+#define REG_INITIAL_POINT_SFT 5
+#define REG_INITIAL_POINT_MASK 0x1f
+#define REG_INITIAL_POINT_MASK_SFT (0x1f << 5)
+#define REG_LRCK_AUTO_OFF_SFT 10
+#define REG_LRCK_AUTO_OFF_MASK 0x1
+#define REG_LRCK_AUTO_OFF_MASK_SFT (0x1 << 10)
+#define REG_BCK_AUTO_OFF_SFT 11
+#define REG_BCK_AUTO_OFF_MASK 0x1
+#define REG_BCK_AUTO_OFF_MASK_SFT (0x1 << 11)
+#define REG_INITIAL_LRCK_SFT 13
+#define REG_INITIAL_LRCK_MASK 0x1
+#define REG_INITIAL_LRCK_MASK_SFT (0x1 << 13)
+#define REG_NO_ALIGN_1X_EN_SFT 14
+#define REG_NO_ALIGN_1X_EN_MASK 0x1
+#define REG_NO_ALIGN_1X_EN_MASK_SFT (0x1 << 14)
+#define REG_LRCK_RESET_SFT 15
+#define REG_LRCK_RESET_MASK 0x1
+#define REG_LRCK_RESET_MASK_SFT (0x1 << 15)
+#define PINMUX_MCLK_CTRL_OE_SFT 16
+#define PINMUX_MCLK_CTRL_OE_MASK 0x1
+#define PINMUX_MCLK_CTRL_OE_MASK_SFT (0x1 << 16)
+#define REG_OUTPUT_CR_EN_SFT 18
+#define REG_OUTPUT_CR_EN_MASK 0x1
+#define REG_OUTPUT_CR_EN_MASK_SFT (0x1 << 18)
+#define REG_LR_ALIGN_SFT 19
+#define REG_LR_ALIGN_MASK 0x1
+#define REG_LR_ALIGN_MASK_SFT (0x1 << 19)
+#define REG_LRCK_WIDTH_SFT 20
+#define REG_LRCK_WIDTH_MASK 0x3ff
+#define REG_LRCK_WIDTH_MASK_SFT (0x3ff << 20)
+#define REG_DIRECT_INPUT_MASTER_BCK_SFT 30
+#define REG_DIRECT_INPUT_MASTER_BCK_MASK 0x1
+#define REG_DIRECT_INPUT_MASTER_BCK_MASK_SFT (0x1 << 30)
+#define REG_LRCK_AUTO_MODE_SFT 31
+#define REG_LRCK_AUTO_MODE_MASK 0x1
+#define REG_LRCK_AUTO_MODE_MASK_SFT (0x1 << 31)
+
+/* ETDM_IN0_CON2 */
+/* ETDM_IN1_CON2 */
+#define REG_UPDATE_POINT_SFT 0
+#define REG_UPDATE_POINT_MASK 0x1f
+#define REG_UPDATE_POINT_MASK_SFT (0x1f << 0)
+#define REG_UPDATE_GAP_SFT 5
+#define REG_UPDATE_GAP_MASK 0x1f
+#define REG_UPDATE_GAP_MASK_SFT (0x1f << 5)
+#define REG_CLOCK_SOURCE_SEL_SFT 10
+#define REG_CLOCK_SOURCE_SEL_MASK 0x7
+#define REG_CLOCK_SOURCE_SEL_MASK_SFT (0x7 << 10)
+#define REG_CK_EN_SEL_AUTO_SFT 14
+#define REG_CK_EN_SEL_AUTO_MASK 0x1
+#define REG_CK_EN_SEL_AUTO_MASK_SFT (0x1 << 14)
+#define REG_MULTI_IP_TOTAL_CHNUM_SFT 15
+#define REG_MULTI_IP_TOTAL_CHNUM_MASK 0x1f
+#define REG_MULTI_IP_TOTAL_CHNUM_MASK_SFT (0x1f << 15)
+#define REG_MASK_AUTO_SFT 20
+#define REG_MASK_AUTO_MASK 0x1
+#define REG_MASK_AUTO_MASK_SFT (0x1 << 20)
+#define REG_MASK_NUM_SFT 21
+#define REG_MASK_NUM_MASK 0x1f
+#define REG_MASK_NUM_MASK_SFT (0x1f << 21)
+#define REG_UPDATE_POINT_AUTO_SFT 26
+#define REG_UPDATE_POINT_AUTO_MASK 0x1
+#define REG_UPDATE_POINT_AUTO_MASK_SFT (0x1 << 26)
+#define REG_SDATA_DELAY_0P5T_EN_SFT 27
+#define REG_SDATA_DELAY_0P5T_EN_MASK 0x1
+#define REG_SDATA_DELAY_0P5T_EN_MASK_SFT (0x1 << 27)
+#define REG_SDATA_DELAY_BCK_INV_SFT 28
+#define REG_SDATA_DELAY_BCK_INV_MASK 0x1
+#define REG_SDATA_DELAY_BCK_INV_MASK_SFT (0x1 << 28)
+#define REG_LRCK_DELAY_0P5T_EN_SFT 29
+#define REG_LRCK_DELAY_0P5T_EN_MASK 0x1
+#define REG_LRCK_DELAY_0P5T_EN_MASK_SFT (0x1 << 29)
+#define REG_LRCK_DELAY_BCK_INV_SFT 30
+#define REG_LRCK_DELAY_BCK_INV_MASK 0x1
+#define REG_LRCK_DELAY_BCK_INV_MASK_SFT (0x1 << 30)
+#define REG_MULTI_IP_MODE_SFT 31
+#define REG_MULTI_IP_MODE_MASK 0x1
+#define REG_MULTI_IP_MODE_MASK_SFT (0x1 << 31)
+
+/* ETDM_IN0_CON3 */
+/* ETDM_IN1_CON3 */
+#define REG_DISABLE_OUT_SFT 0
+#define REG_DISABLE_OUT_MASK 0xffff
+#define REG_DISABLE_OUT_MASK_SFT (0xffff << 0)
+#define REG_RJ_DATA_RIGHT_ALIGN_SFT 16
+#define REG_RJ_DATA_RIGHT_ALIGN_MASK 0x1
+#define REG_RJ_DATA_RIGHT_ALIGN_MASK_SFT (0x1 << 16)
+#define REG_MONITOR_SEL_SFT 17
+#define REG_MONITOR_SEL_MASK 0x3
+#define REG_MONITOR_SEL_MASK_SFT (0x3 << 17)
+#define REG_CNT_UPPER_LIMIT_SFT 19
+#define REG_CNT_UPPER_LIMIT_MASK 0x3f
+#define REG_CNT_UPPER_LIMIT_MASK_SFT (0x3f << 19)
+#define REG_COMPACT_SAMPLE_END_DIS_SFT 25
+#define REG_COMPACT_SAMPLE_END_DIS_MASK 0x1
+#define REG_COMPACT_SAMPLE_END_DIS_MASK_SFT (0x1 << 25)
+#define REG_FS_TIMING_SEL_SFT 26
+#define REG_FS_TIMING_SEL_MASK 0x1f
+#define REG_FS_TIMING_SEL_MASK_SFT (0x1f << 26)
+#define REG_SAMPLE_END_MODE_SFT 31
+#define REG_SAMPLE_END_MODE_MASK 0x1
+#define REG_SAMPLE_END_MODE_MASK_SFT (0x1 << 31)
+
+/* ETDM_IN0_CON4 */
+/* ETDM_IN1_CON4 */
+#define REG_ALWAYS_OPEN_1X_EN_SFT 31
+#define REG_ALWAYS_OPEN_1X_EN_MASK 0x1
+#define REG_ALWAYS_OPEN_1X_EN_MASK_SFT (0x1 << 31)
+#define REG_WAIT_LAST_SAMPLE_SFT 30
+#define REG_WAIT_LAST_SAMPLE_MASK 0x1
+#define REG_WAIT_LAST_SAMPLE_MASK_SFT (0x1 << 30)
+#define REG_SAMPLE_END_POINT_SFT 25
+#define REG_SAMPLE_END_POINT_MASK 0x1f
+#define REG_SAMPLE_END_POINT_MASK_SFT (0x1f << 25)
+#define REG_RELATCH_1X_EN_SEL_SFT 20
+#define REG_RELATCH_1X_EN_SEL_MASK 0x1f
+#define REG_RELATCH_1X_EN_SEL_MASK_SFT (0x1f << 20)
+#define REG_MASTER_WS_INV_SFT 19
+#define REG_MASTER_WS_INV_MASK 0x1
+#define REG_MASTER_WS_INV_MASK_SFT (0x1 << 19)
+#define REG_MASTER_BCK_INV_SFT 18
+#define REG_MASTER_BCK_INV_MASK 0x1
+#define REG_MASTER_BCK_INV_MASK_SFT (0x1 << 18)
+#define REG_SLAVE_LRCK_INV_SFT 17
+#define REG_SLAVE_LRCK_INV_MASK 0x1
+#define REG_SLAVE_LRCK_INV_MASK_SFT (0x1 << 17)
+#define REG_SLAVE_BCK_INV_SFT 16
+#define REG_SLAVE_BCK_INV_MASK 0x1
+#define REG_SLAVE_BCK_INV_MASK_SFT (0x1 << 16)
+#define REG_REPACK_CHNUM_SFT 12
+#define REG_REPACK_CHNUM_MASK 0xf
+#define REG_REPACK_CHNUM_MASK_SFT (0xf << 12)
+#define REG_ASYNC_RESET_SFT 11
+#define REG_ASYNC_RESET_MASK 0x1
+#define REG_ASYNC_RESET_MASK_SFT (0x1 << 11)
+#define REG_REPACK_WORD_LENGTH_SFT 9
+#define REG_REPACK_WORD_LENGTH_MASK 0x3
+#define REG_REPACK_WORD_LENGTH_MASK_SFT (0x3 << 9)
+#define REG_REPACK_AUTO_MODE_SFT 8
+#define REG_REPACK_AUTO_MODE_MASK 0x1
+#define REG_REPACK_AUTO_MODE_MASK_SFT (0x1 << 8)
+#define REG_REPACK_MODE_SFT 0
+#define REG_REPACK_MODE_MASK 0x3f
+#define REG_REPACK_MODE_MASK_SFT (0x3f << 0)
+
+/* ETDM_IN0_CON5 */
+/* ETDM_IN1_CON5 */
+#define REG_LR_SWAP_SFT 16
+#define REG_LR_SWAP_MASK 0xffff
+#define REG_LR_SWAP_MASK_SFT (0xffff << 16)
+#define REG_ODD_FLAG_EN_SFT 0
+#define REG_ODD_FLAG_EN_MASK 0xffff
+#define REG_ODD_FLAG_EN_MASK_SFT (0xffff << 0)
+
+/* ETDM_IN0_CON6 */
+/* ETDM_IN1_CON6 */
+#define LCH_DATA_REG_SFT 0
+#define LCH_DATA_REG_MASK 0xffffffff
+#define LCH_DATA_REG_MASK_SFT (0xffffffff << 0)
+
+/* ETDM_IN0_CON7 */
+/* ETDM_IN1_CON7 */
+#define RCH_DATA_REG_SFT 0
+#define RCH_DATA_REG_MASK 0xffffffff
+#define RCH_DATA_REG_MASK_SFT (0xffffffff << 0)
+
+/* ETDM_IN0_CON8 */
+/* ETDM_IN1_CON8 */
+#define REG_AFIFO_THRESHOLD_SFT 29
+#define REG_AFIFO_THRESHOLD_MASK 0x3
+#define REG_AFIFO_THRESHOLD_MASK_SFT (0x3 << 29)
+#define REG_CK_EN_SEL_MANUAL_SFT 16
+#define REG_CK_EN_SEL_MANUAL_MASK 0x3ff
+#define REG_CK_EN_SEL_MANUAL_MASK_SFT (0x3ff << 16)
+#define REG_AFIFO_SW_RESET_SFT 15
+#define REG_AFIFO_SW_RESET_MASK 0x1
+#define REG_AFIFO_SW_RESET_MASK_SFT (0x1 << 15)
+#define REG_AFIFO_RESET_SEL_SFT 14
+#define REG_AFIFO_RESET_SEL_MASK 0x1
+#define REG_AFIFO_RESET_SEL_MASK_SFT (0x1 << 14)
+#define REG_AFIFO_AUTO_RESET_DIS_SFT 9
+#define REG_AFIFO_AUTO_RESET_DIS_MASK 0x1
+#define REG_AFIFO_AUTO_RESET_DIS_MASK_SFT (0x1 << 9)
+#define REG_ETDM_USE_AFIFO_SFT 8
+#define REG_ETDM_USE_AFIFO_MASK 0x1
+#define REG_ETDM_USE_AFIFO_MASK_SFT (0x1 << 8)
+#define REG_AFIFO_CLOCK_DOMAIN_SEL_SFT 5
+#define REG_AFIFO_CLOCK_DOMAIN_SEL_MASK 0x7
+#define REG_AFIFO_CLOCK_DOMAIN_SEL_MASK_SFT (0x7 << 5)
+#define REG_AFIFO_MODE_SFT 0
+#define REG_AFIFO_MODE_MASK 0x1f
+#define REG_AFIFO_MODE_MASK_SFT (0x1f << 0)
+
+/* ETDM_IN0_CON9 */
+/* ETDM_IN1_CON9 */
+#define REG_OUT2LATCH_TIME_SFT 10
+#define REG_OUT2LATCH_TIME_MASK 0x1f
+#define REG_OUT2LATCH_TIME_MASK_SFT (0x1f << 10)
+#define REG_ALMOST_END_BIT_COUNT_SFT 5
+#define REG_ALMOST_END_BIT_COUNT_MASK 0x1f
+#define REG_ALMOST_END_BIT_COUNT_MASK_SFT (0x1f << 5)
+#define REG_ALMOST_END_CH_COUNT_SFT 0
+#define REG_ALMOST_END_CH_COUNT_MASK 0x1f
+#define REG_ALMOST_END_CH_COUNT_MASK_SFT (0x1f << 0)
+
+/* ETDM_IN0_MON */
+/* ETDM_IN1_MON */
+#define LRCK_INV_SFT 30
+#define LRCK_INV_MASK 0x1
+#define LRCK_INV_MASK_SFT (0x1 << 30)
+#define EN_SYNC_OUT_SFT 29
+#define EN_SYNC_OUT_MASK 0x1
+#define EN_SYNC_OUT_MASK_SFT (0x1 << 29)
+#define HOPPING_EN_SYNC_OUT_PRE_SFT 28
+#define HOPPING_EN_SYNC_OUT_PRE_MASK 0x1
+#define HOPPING_EN_SYNC_OUT_PRE_MASK_SFT (0x1 << 28)
+#define WFULL_SFT 27
+#define WFULL_MASK 0x1
+#define WFULL_MASK_SFT (0x1 << 27)
+#define REMPTY_SFT 26
+#define REMPTY_MASK 0x1
+#define REMPTY_MASK_SFT (0x1 << 26)
+#define ETDM_2X_CK_EN_SFT 25
+#define ETDM_2X_CK_EN_MASK 0x1
+#define ETDM_2X_CK_EN_MASK_SFT (0x1 << 25)
+#define ETDM_1X_CK_EN_SFT 24
+#define ETDM_1X_CK_EN_MASK 0x1
+#define ETDM_1X_CK_EN_MASK_SFT (0x1 << 24)
+#define SDATA0_SFT 23
+#define SDATA0_MASK 0x1
+#define SDATA0_MASK_SFT (0x1 << 23)
+#define CURRENT_STATUS_SFT 21
+#define CURRENT_STATUS_MASK 0x3
+#define CURRENT_STATUS_MASK_SFT (0x3 << 21)
+#define BIT_POINT_SFT 16
+#define BIT_POINT_MASK 0x1f
+#define BIT_POINT_MASK_SFT (0x1f << 16)
+#define BIT_CH_COUNT_SFT 10
+#define BIT_CH_COUNT_MASK 0x3f
+#define BIT_CH_COUNT_MASK_SFT (0x3f << 10)
+#define BIT_COUNT_SFT 5
+#define BIT_COUNT_MASK 0x1f
+#define BIT_COUNT_MASK_SFT (0x1f << 5)
+#define CH_COUNT_SFT 0
+#define CH_COUNT_MASK 0x1f
+#define CH_COUNT_MASK_SFT (0x1f << 0)
+
+/* ETDM_OUT0_CON0 */
+/* ETDM_OUT1_CON0 */
+/* ETDM_OUT4_CON0 */
+#define OUT_REG_ETDM_OUT_EN_SFT 0
+#define OUT_REG_ETDM_OUT_EN_MASK 0x1
+#define OUT_REG_ETDM_OUT_EN_MASK_SFT (0x1 << 0)
+#define OUT_REG_SYNC_MODE_SFT 1
+#define OUT_REG_SYNC_MODE_MASK 0x1
+#define OUT_REG_SYNC_MODE_MASK_SFT (0x1 << 1)
+#define OUT_REG_LSB_FIRST_SFT 3
+#define OUT_REG_LSB_FIRST_MASK 0x1
+#define OUT_REG_LSB_FIRST_MASK_SFT (0x1 << 3)
+#define OUT_REG_SOFT_RST_SFT 4
+#define OUT_REG_SOFT_RST_MASK 0x1
+#define OUT_REG_SOFT_RST_MASK_SFT (0x1 << 4)
+#define OUT_REG_SLAVE_MODE_SFT 5
+#define OUT_REG_SLAVE_MODE_MASK 0x1
+#define OUT_REG_SLAVE_MODE_MASK_SFT (0x1 << 5)
+#define OUT_REG_FMT_SFT 6
+#define OUT_REG_FMT_MASK 0x7
+#define OUT_REG_FMT_MASK_SFT (0x7 << 6)
+#define OUT_REG_LRCK_EDGE_SEL_SFT 10
+#define OUT_REG_LRCK_EDGE_SEL_MASK 0x1
+#define OUT_REG_LRCK_EDGE_SEL_MASK_SFT (0x1 << 10)
+#define OUT_REG_BIT_LENGTH_SFT 11
+#define OUT_REG_BIT_LENGTH_MASK 0x1f
+#define OUT_REG_BIT_LENGTH_MASK_SFT (0x1f << 11)
+#define OUT_REG_WORD_LENGTH_SFT 16
+#define OUT_REG_WORD_LENGTH_MASK 0x1f
+#define OUT_REG_WORD_LENGTH_MASK_SFT (0x1f << 16)
+#define OUT_REG_CH_NUM_SFT 23
+#define OUT_REG_CH_NUM_MASK 0x1f
+#define OUT_REG_CH_NUM_MASK_SFT (0x1f << 23)
+#define OUT_REG_RELATCH_DOMAIN_SEL_SFT 28
+#define OUT_REG_RELATCH_DOMAIN_SEL_MASK 0x7
+#define OUT_REG_RELATCH_DOMAIN_SEL_MASK_SFT (0x7 << 28)
+#define OUT_REG_VALID_TOGETHER_SFT 31
+#define OUT_REG_VALID_TOGETHER_MASK 0x1
+#define OUT_REG_VALID_TOGETHER_MASK_SFT (0x1 << 31)
+
+/* ETDM_OUT0_CON1 */
+/* ETDM_OUT1_CON1 */
+/* ETDM_OUT4_CON1 */
+#define OUT_REG_INITIAL_COUNT_SFT 0
+#define OUT_REG_INITIAL_COUNT_MASK 0x1f
+#define OUT_REG_INITIAL_COUNT_MASK_SFT (0x1f << 0)
+#define OUT_REG_INITIAL_POINT_SFT 5
+#define OUT_REG_INITIAL_POINT_MASK 0x1f
+#define OUT_REG_INITIAL_POINT_MASK_SFT (0x1f << 5)
+#define OUT_REG_LRCK_AUTO_OFF_SFT 10
+#define OUT_REG_LRCK_AUTO_OFF_MASK 0x1
+#define OUT_REG_LRCK_AUTO_OFF_MASK_SFT (0x1 << 10)
+#define OUT_REG_BCK_AUTO_OFF_SFT 11
+#define OUT_REG_BCK_AUTO_OFF_MASK 0x1
+#define OUT_REG_BCK_AUTO_OFF_MASK_SFT (0x1 << 11)
+#define OUT_REG_INITIAL_LRCK_SFT 13
+#define OUT_REG_INITIAL_LRCK_MASK 0x1
+#define OUT_REG_INITIAL_LRCK_MASK_SFT (0x1 << 13)
+#define OUT_REG_NO_ALIGN_1X_EN_SFT 14
+#define OUT_REG_NO_ALIGN_1X_EN_MASK 0x1
+#define OUT_REG_NO_ALIGN_1X_EN_MASK_SFT (0x1 << 14)
+#define OUT_REG_LRCK_RESET_SFT 15
+#define OUT_REG_LRCK_RESET_MASK 0x1
+#define OUT_REG_LRCK_RESET_MASK_SFT (0x1 << 15)
+#define OUT_PINMUX_MCLK_CTRL_OE_SFT 16
+#define OUT_PINMUX_MCLK_CTRL_OE_MASK 0x1
+#define OUT_PINMUX_MCLK_CTRL_OE_MASK_SFT (0x1 << 16)
+#define OUT_REG_OUTPUT_CR_EN_SFT 18
+#define OUT_REG_OUTPUT_CR_EN_MASK 0x1
+#define OUT_REG_OUTPUT_CR_EN_MASK_SFT (0x1 << 18)
+#define OUT_REG_LRCK_WIDTH_SFT 19
+#define OUT_REG_LRCK_WIDTH_MASK 0x3ff
+#define OUT_REG_LRCK_WIDTH_MASK_SFT (0x3ff << 19)
+#define OUT_REG_LRCK_AUTO_MODE_SFT 29
+#define OUT_REG_LRCK_AUTO_MODE_MASK 0x1
+#define OUT_REG_LRCK_AUTO_MODE_MASK_SFT (0x1 << 29)
+#define OUT_REG_DIRECT_INPUT_MASTER_BCK_SFT 30
+#define OUT_REG_DIRECT_INPUT_MASTER_BCK_MASK 0x1
+#define OUT_REG_DIRECT_INPUT_MASTER_BCK_MASK_SFT (0x1 << 30)
+#define OUT_REG_16B_COMPACT_MODE_SFT 31
+#define OUT_REG_16B_COMPACT_MODE_MASK 0x1
+#define OUT_REG_16B_COMPACT_MODE_MASK_SFT (0x1 << 31)
+
+/* ETDM_OUT0_CON2 */
+/* ETDM_OUT1_CON2 */
+/* ETDM_OUT4_CON2 */
+#define OUT_REG_IN2LATCH_TIME_SFT 0
+#define OUT_REG_IN2LATCH_TIME_MASK 0x1f
+#define OUT_REG_IN2LATCH_TIME_MASK_SFT (0x1f << 0)
+#define OUT_REG_MASK_NUM_SFT 5
+#define OUT_REG_MASK_NUM_MASK 0x1f
+#define OUT_REG_MASK_NUM_MASK_SFT (0x1f << 5)
+#define OUT_REG_MASK_AUTO_SFT 10
+#define OUT_REG_MASK_AUTO_MASK 0x1
+#define OUT_REG_MASK_AUTO_MASK_SFT (0x1 << 10)
+#define OUT_REG_SDATA_SHIFT_SFT 11
+#define OUT_REG_SDATA_SHIFT_MASK 0x3
+#define OUT_REG_SDATA_SHIFT_MASK_SFT (0x3 << 11)
+#define OUT_REG_ALMOST_END_BIT_COUNT_SFT 13
+#define OUT_REG_ALMOST_END_BIT_COUNT_MASK 0x1f
+#define OUT_REG_ALMOST_END_BIT_COUNT_MASK_SFT (0x1f << 13)
+#define OUT_REG_SDATA_CON_SFT 18
+#define OUT_REG_SDATA_CON_MASK 0x3
+#define OUT_REG_SDATA_CON_MASK_SFT (0x3 << 18)
+#define OUT_REG_REDUNDANT_0_SFT 20
+#define OUT_REG_REDUNDANT_0_MASK 0x1
+#define OUT_REG_REDUNDANT_0_MASK_SFT (0x1 << 20)
+#define OUT_REG_SDATA_AUTO_OFF_SFT 21
+#define OUT_REG_SDATA_AUTO_OFF_MASK 0x1
+#define OUT_REG_SDATA_AUTO_OFF_MASK_SFT (0x1 << 21)
+#define OUT_REG_BCK_OFF_TIME_SFT 22
+#define OUT_REG_BCK_OFF_TIME_MASK 0x3
+#define OUT_REG_BCK_OFF_TIME_MASK_SFT (0x3 << 22)
+#define OUT_REG_MONITOR_SEL_SFT 24
+#define OUT_REG_MONITOR_SEL_MASK 0x3
+#define OUT_REG_MONITOR_SEL_MASK_SFT (0x3 << 24)
+#define OUT_REG_SHIFT_AUTO_SFT 26
+#define OUT_REG_SHIFT_AUTO_MASK 0x1
+#define OUT_REG_SHIFT_AUTO_MASK_SFT (0x1 << 26)
+#define OUT_REG_SDATA_DELAY_0P5T_EN_SFT 27
+#define OUT_REG_SDATA_DELAY_0P5T_EN_MASK 0x1
+#define OUT_REG_SDATA_DELAY_0P5T_EN_MASK_SFT (0x1 << 27)
+#define OUT_REG_SDATA_DELAY_BCK_INV_SFT 28
+#define OUT_REG_SDATA_DELAY_BCK_INV_MASK 0x1
+#define OUT_REG_SDATA_DELAY_BCK_INV_MASK_SFT (0x1 << 28)
+#define OUT_REG_LRCK_DELAY_0P5T_EN_SFT 29
+#define OUT_REG_LRCK_DELAY_0P5T_EN_MASK 0x1
+#define OUT_REG_LRCK_DELAY_0P5T_EN_MASK_SFT (0x1 << 29)
+#define OUT_REG_LRCK_DELAY_BCK_INV_SFT 30
+#define OUT_REG_LRCK_DELAY_BCK_INV_MASK 0x1
+#define OUT_REG_LRCK_DELAY_BCK_INV_MASK_SFT (0x1 << 30)
+#define OUT_REG_OFF_CR_EN_SFT 31
+#define OUT_REG_OFF_CR_EN_MASK 0x1
+#define OUT_REG_OFF_CR_EN_MASK_SFT (0x1 << 31)
+
+/* ETDM_OUT0_CON3 */
+/* ETDM_OUT1_CON3 */
+/* ETDM_OUT4_CON3 */
+#define OUT_REG_START_CH_PAIR0_SFT 0
+#define OUT_REG_START_CH_PAIR0_MASK 0xf
+#define OUT_REG_START_CH_PAIR0_MASK_SFT (0xf << 0)
+#define OUT_REG_START_CH_PAIR1_SFT 4
+#define OUT_REG_START_CH_PAIR1_MASK 0xf
+#define OUT_REG_START_CH_PAIR1_MASK_SFT (0xf << 4)
+#define OUT_REG_START_CH_PAIR2_SFT 8
+#define OUT_REG_START_CH_PAIR2_MASK 0xf
+#define OUT_REG_START_CH_PAIR2_MASK_SFT (0xf << 8)
+#define OUT_REG_START_CH_PAIR3_SFT 12
+#define OUT_REG_START_CH_PAIR3_MASK 0xf
+#define OUT_REG_START_CH_PAIR3_MASK_SFT (0xf << 12)
+#define OUT_REG_START_CH_PAIR4_SFT 16
+#define OUT_REG_START_CH_PAIR4_MASK 0xf
+#define OUT_REG_START_CH_PAIR4_MASK_SFT (0xf << 16)
+#define OUT_REG_START_CH_PAIR5_SFT 20
+#define OUT_REG_START_CH_PAIR5_MASK 0xf
+#define OUT_REG_START_CH_PAIR5_MASK_SFT (0xf << 20)
+#define OUT_REG_START_CH_PAIR6_SFT 24
+#define OUT_REG_START_CH_PAIR6_MASK 0xf
+#define OUT_REG_START_CH_PAIR6_MASK_SFT (0xf << 24)
+#define OUT_REG_START_CH_PAIR7_SFT 28
+#define OUT_REG_START_CH_PAIR7_MASK 0xf
+#define OUT_REG_START_CH_PAIR7_MASK_SFT (0xf << 28)
+
+/* ETDM_OUT0_CON4 */
+/* ETDM_OUT1_CON4 */
+/* ETDM_OUT4_CON4 */
+#define OUT_REG_FS_TIMING_SEL_SFT 0
+#define OUT_REG_FS_TIMING_SEL_MASK 0x1f
+#define OUT_REG_FS_TIMING_SEL_MASK_SFT (0x1f << 0)
+#define OUT_REG_CLOCK_SOURCE_SEL_SFT 6
+#define OUT_REG_CLOCK_SOURCE_SEL_MASK 0x7
+#define OUT_REG_CLOCK_SOURCE_SEL_MASK_SFT (0x7 << 6)
+#define OUT_REG_CK_EN_SEL_AUTO_SFT 10
+#define OUT_REG_CK_EN_SEL_AUTO_MASK 0x1
+#define OUT_REG_CK_EN_SEL_AUTO_MASK_SFT (0x1 << 10)
+#define OUT_REG_ASYNC_RESET_SFT 11
+#define OUT_REG_ASYNC_RESET_MASK 0x1
+#define OUT_REG_ASYNC_RESET_MASK_SFT (0x1 << 11)
+#define OUT_REG_CK_EN_SEL_MANUAL_SFT 14
+#define OUT_REG_CK_EN_SEL_MANUAL_MASK 0x3ff
+#define OUT_REG_CK_EN_SEL_MANUAL_MASK_SFT (0x3ff << 14)
+#define OUT_REG_RELATCH_EN_SEL_SFT 24
+#define OUT_REG_RELATCH_EN_SEL_MASK 0x1f
+#define OUT_REG_RELATCH_EN_SEL_MASK_SFT (0x1f << 24)
+#define OUT_REG_WAIT_LAST_SAMPLE_SFT 30
+#define OUT_REG_WAIT_LAST_SAMPLE_MASK 0x1
+#define OUT_REG_WAIT_LAST_SAMPLE_MASK_SFT (0x1 << 30)
+#define OUT_REG_ALWAYS_OPEN_1X_EN_SFT 31
+#define OUT_REG_ALWAYS_OPEN_1X_EN_MASK 0x1
+#define OUT_REG_ALWAYS_OPEN_1X_EN_MASK_SFT (0x1 << 31)
+
+/* ETDM_OUT0_CON5 */
+/* ETDM_OUT1_CON5 */
+/* ETDM_OUT4_CON5 */
+#define OUT_REG_REPACK_BITNUM_SFT 0
+#define OUT_REG_REPACK_BITNUM_MASK 0x3
+#define OUT_REG_REPACK_BITNUM_MASK_SFT (0x3 << 0)
+#define OUT_REG_REPACK_CHNUM_SFT 2
+#define OUT_REG_REPACK_CHNUM_MASK 0xf
+#define OUT_REG_REPACK_CHNUM_MASK_SFT (0xf << 2)
+#define OUT_REG_SLAVE_BCK_INV_SFT 7
+#define OUT_REG_SLAVE_BCK_INV_MASK 0x1
+#define OUT_REG_SLAVE_BCK_INV_MASK_SFT (0x1 << 7)
+#define OUT_REG_SLAVE_LRCK_INV_SFT 8
+#define OUT_REG_SLAVE_LRCK_INV_MASK 0x1
+#define OUT_REG_SLAVE_LRCK_INV_MASK_SFT (0x1 << 8)
+#define OUT_REG_MASTER_BCK_INV_SFT 9
+#define OUT_REG_MASTER_BCK_INV_MASK 0x1
+#define OUT_REG_MASTER_BCK_INV_MASK_SFT (0x1 << 9)
+#define OUT_REG_MASTER_WS_INV_SFT 10
+#define OUT_REG_MASTER_WS_INV_MASK 0x1
+#define OUT_REG_MASTER_WS_INV_MASK_SFT (0x1 << 10)
+#define OUT_REG_REPACK_24B_MSB_ALIGN_SFT 11
+#define OUT_REG_REPACK_24B_MSB_ALIGN_MASK 0x1
+#define OUT_REG_REPACK_24B_MSB_ALIGN_MASK_SFT (0x1 << 11)
+#define OUT_REG_LR_SWAP_SFT 16
+#define OUT_REG_LR_SWAP_MASK 0xffff
+#define OUT_REG_LR_SWAP_MASK_SFT (0xffff << 16)
+
+/* ETDM_OUT0_CON6 */
+/* ETDM_OUT1_CON6 */
+/* ETDM_OUT4_CON6 */
+#define OUT_LCH_DATA_REG_SFT 0
+#define OUT_LCH_DATA_REG_MASK 0xffffffff
+#define OUT_LCH_DATA_REG_MASK_SFT (0xffffffff << 0)
+
+/* ETDM_OUT0_CON7 */
+/* ETDM_OUT1_CON7 */
+/* ETDM_OUT4_CON7 */
+#define OUT_RCH_DATA_REG_SFT 0
+#define OUT_RCH_DATA_REG_MASK 0xffffffff
+#define OUT_RCH_DATA_REG_MASK_SFT (0xffffffff << 0)
+
+/* ETDM_OUT0_CON8 */
+/* ETDM_OUT1_CON8 */
+/* ETDM_OUT4_CON8 */
+#define OUT_REG_START_CH_PAIR8_SFT 0
+#define OUT_REG_START_CH_PAIR8_MASK 0xf
+#define OUT_REG_START_CH_PAIR8_MASK_SFT (0xf << 0)
+#define OUT_REG_START_CH_PAIR9_SFT 4
+#define OUT_REG_START_CH_PAIR9_MASK 0xf
+#define OUT_REG_START_CH_PAIR9_MASK_SFT (0xf << 4)
+#define OUT_REG_START_CH_PAIR10_SFT 8
+#define OUT_REG_START_CH_PAIR10_MASK 0xf
+#define OUT_REG_START_CH_PAIR10_MASK_SFT (0xf << 8)
+#define OUT_REG_START_CH_PAIR11_SFT 12
+#define OUT_REG_START_CH_PAIR11_MASK 0xf
+#define OUT_REG_START_CH_PAIR11_MASK_SFT (0xf << 12)
+#define OUT_REG_START_CH_PAIR12_SFT 16
+#define OUT_REG_START_CH_PAIR12_MASK 0xf
+#define OUT_REG_START_CH_PAIR12_MASK_SFT (0xf << 16)
+#define OUT_REG_START_CH_PAIR13_SFT 20
+#define OUT_REG_START_CH_PAIR13_MASK 0xf
+#define OUT_REG_START_CH_PAIR13_MASK_SFT (0xf << 20)
+#define OUT_REG_START_CH_PAIR14_SFT 24
+#define OUT_REG_START_CH_PAIR14_MASK 0xf
+#define OUT_REG_START_CH_PAIR14_MASK_SFT (0xf << 24)
+#define OUT_REG_START_CH_PAIR15_SFT 28
+#define OUT_REG_START_CH_PAIR15_MASK 0xf
+#define OUT_REG_START_CH_PAIR15_MASK_SFT (0xf << 28)
+
+/* ETDM_OUT0_CON9 */
+/* ETDM_OUT1_CON9 */
+/* ETDM_OUT4_CON9 */
+#define OUT_REG_AFIFO_THRESHOLD_SFT 29
+#define OUT_REG_AFIFO_THRESHOLD_MASK 0x3
+#define OUT_REG_AFIFO_THRESHOLD_MASK_SFT (0x3 << 29)
+#define OUT_REG_AFIFO_SW_RESET_SFT 15
+#define OUT_REG_AFIFO_SW_RESET_MASK 0x1
+#define OUT_REG_AFIFO_SW_RESET_MASK_SFT (0x1 << 15)
+#define OUT_REG_AFIFO_RESET_SEL_SFT 14
+#define OUT_REG_AFIFO_RESET_SEL_MASK 0x1
+#define OUT_REG_AFIFO_RESET_SEL_MASK_SFT (0x1 << 14)
+#define OUT_REG_AFIFO_AUTO_RESET_DIS_SFT 9
+#define OUT_REG_AFIFO_AUTO_RESET_DIS_MASK 0x1
+#define OUT_REG_AFIFO_AUTO_RESET_DIS_MASK_SFT (0x1 << 9)
+#define OUT_REG_ETDM_USE_AFIFO_SFT 8
+#define OUT_REG_ETDM_USE_AFIFO_MASK 0x1
+#define OUT_REG_ETDM_USE_AFIFO_MASK_SFT (0x1 << 8)
+#define OUT_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT 5
+#define OUT_REG_AFIFO_CLOCK_DOMAIN_SEL_MASK 0x7
+#define OUT_REG_AFIFO_CLOCK_DOMAIN_SEL_MASK_SFT (0x7 << 5)
+#define OUT_REG_AFIFO_MODE_SFT 0
+#define OUT_REG_AFIFO_MODE_MASK 0x1f
+#define OUT_REG_AFIFO_MODE_MASK_SFT (0x1f << 0)
+
+/* ETDM_OUT0_MON */
+/* ETDM_OUT1_MON */
+/* ETDM_OUT4_MON */
+#define LRCK_INV_SFT 30
+#define LRCK_INV_MASK 0x1
+#define LRCK_INV_MASK_SFT (0x1 << 30)
+#define EN_SYNC_OUT_SFT 29
+#define EN_SYNC_OUT_MASK 0x1
+#define EN_SYNC_OUT_MASK_SFT (0x1 << 29)
+#define HOPPING_EN_SYNC_OUT_PRE_SFT 28
+#define HOPPING_EN_SYNC_OUT_PRE_MASK 0x1
+#define HOPPING_EN_SYNC_OUT_PRE_MASK_SFT (0x1 << 28)
+#define ETDM_2X_CK_EN_SFT 25
+#define ETDM_2X_CK_EN_MASK 0x1
+#define ETDM_2X_CK_EN_MASK_SFT (0x1 << 25)
+#define ETDM_1X_CK_EN_SFT 24
+#define ETDM_1X_CK_EN_MASK 0x1
+#define ETDM_1X_CK_EN_MASK_SFT (0x1 << 24)
+#define SDATA0_SFT 23
+#define SDATA0_MASK 0x1
+#define SDATA0_MASK_SFT (0x1 << 23)
+#define CURRENT_STATUS_SFT 21
+#define CURRENT_STATUS_MASK 0x3
+#define CURRENT_STATUS_MASK_SFT (0x3 << 21)
+#define BIT_POINT_SFT 16
+#define BIT_POINT_MASK 0x1f
+#define BIT_POINT_MASK_SFT (0x1f << 16)
+#define BIT_CH_COUNT_SFT 10
+#define BIT_CH_COUNT_MASK 0x3f
+#define BIT_CH_COUNT_MASK_SFT (0x3f << 10)
+#define BIT_COUNT_SFT 5
+#define BIT_COUNT_MASK 0x1f
+#define BIT_COUNT_MASK_SFT (0x1f << 5)
+#define CH_COUNT_SFT 0
+#define CH_COUNT_MASK 0x1f
+#define CH_COUNT_MASK_SFT (0x1f << 0)
+
+/* ETDM_0_3_COWORK_CON0 */
+#define ETDM_OUT0_DATA_SEL_SFT 0
+#define ETDM_OUT0_DATA_SEL_MASK 0xf
+#define ETDM_OUT0_DATA_SEL_MASK_SFT (0xf << 0)
+#define ETDM_OUT0_SYNC_SEL_SFT 4
+#define ETDM_OUT0_SYNC_SEL_MASK 0xf
+#define ETDM_OUT0_SYNC_SEL_MASK_SFT (0xf << 4)
+#define ETDM_OUT0_SLAVE_SEL_SFT 8
+#define ETDM_OUT0_SLAVE_SEL_MASK 0xf
+#define ETDM_OUT0_SLAVE_SEL_MASK_SFT (0xf << 8)
+#define ETDM_OUT1_DATA_SEL_SFT 12
+#define ETDM_OUT1_DATA_SEL_MASK 0xf
+#define ETDM_OUT1_DATA_SEL_MASK_SFT (0xf << 12)
+#define ETDM_OUT1_SYNC_SEL_SFT 16
+#define ETDM_OUT1_SYNC_SEL_MASK 0xf
+#define ETDM_OUT1_SYNC_SEL_MASK_SFT (0xf << 16)
+#define ETDM_OUT1_SLAVE_SEL_SFT 20
+#define ETDM_OUT1_SLAVE_SEL_MASK 0xf
+#define ETDM_OUT1_SLAVE_SEL_MASK_SFT (0xf << 20)
+#define ETDM_IN0_SLAVE_SEL_SFT 24
+#define ETDM_IN0_SLAVE_SEL_MASK 0xf
+#define ETDM_IN0_SLAVE_SEL_MASK_SFT (0xf << 24)
+#define ETDM_IN0_SYNC_SEL_SFT 28
+#define ETDM_IN0_SYNC_SEL_MASK 0xf
+#define ETDM_IN0_SYNC_SEL_MASK_SFT (0xf << 28)
+
+/* ETDM_0_3_COWORK_CON1 */
+#define ETDM_IN0_SDATA0_SEL_SFT 0
+#define ETDM_IN0_SDATA0_SEL_MASK 0xf
+#define ETDM_IN0_SDATA0_SEL_MASK_SFT (0xf << 0)
+#define ETDM_IN0_SDATA1_15_SEL_SFT 4
+#define ETDM_IN0_SDATA1_15_SEL_MASK 0xf
+#define ETDM_IN0_SDATA1_15_SEL_MASK_SFT (0xf << 4)
+#define ETDM_IN1_SLAVE_SEL_SFT 8
+#define ETDM_IN1_SLAVE_SEL_MASK 0xf
+#define ETDM_IN1_SLAVE_SEL_MASK_SFT (0xf << 8)
+#define ETDM_IN1_SYNC_SEL_SFT 12
+#define ETDM_IN1_SYNC_SEL_MASK 0xf
+#define ETDM_IN1_SYNC_SEL_MASK_SFT (0xf << 12)
+#define ETDM_IN1_SDATA0_SEL_SFT 16
+#define ETDM_IN1_SDATA0_SEL_MASK 0xf
+#define ETDM_IN1_SDATA0_SEL_MASK_SFT (0xf << 16)
+#define ETDM_IN1_SDATA1_15_SEL_SFT 20
+#define ETDM_IN1_SDATA1_15_SEL_MASK 0xf
+#define ETDM_IN1_SDATA1_15_SEL_MASK_SFT (0xf << 20)
+
+/* ETDM_4_7_COWORK_CON0 */
+#define ETDM_OUT4_DATA_SEL_SFT 0
+#define ETDM_OUT4_DATA_SEL_MASK 0xf
+#define ETDM_OUT4_DATA_SEL_MASK_SFT (0xf << 0)
+#define ETDM_OUT4_SYNC_SEL_SFT 4
+#define ETDM_OUT4_SYNC_SEL_MASK 0xf
+#define ETDM_OUT4_SYNC_SEL_MASK_SFT (0xf << 4)
+#define ETDM_OUT4_SLAVE_SEL_SFT 8
+#define ETDM_OUT4_SLAVE_SEL_MASK 0xf
+#define ETDM_OUT4_SLAVE_SEL_MASK_SFT (0xf << 8)
+
+/* AFE_DPTX_CON */
+#define DPTX_CHANNEL_ENABLE_SFT 8
+#define DPTX_CHANNEL_ENABLE_MASK 0xff
+#define DPTX_CHANNEL_ENABLE_MASK_SFT (0xff << 8)
+#define DPTX_REGISTER_MONITOR_SELECT_SFT 3
+#define DPTX_REGISTER_MONITOR_SELECT_MASK 0xf
+#define DPTX_REGISTER_MONITOR_SELECT_MASK_SFT (0xf << 3)
+#define DPTX_16BIT_SFT 2
+#define DPTX_16BIT_MASK 0x1
+#define DPTX_16BIT_MASK_SFT (0x1 << 2)
+#define DPTX_CHANNEL_NUMBER_SFT 1
+#define DPTX_CHANNEL_NUMBER_MASK 0x1
+#define DPTX_CHANNEL_NUMBER_MASK_SFT (0x1 << 1)
+#define DPTX_ON_SFT 0
+#define DPTX_ON_MASK 0x1
+#define DPTX_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_DPTX_MON */
+#define AFE_DPTX_MON0_SFT 0
+#define AFE_DPTX_MON0_MASK 0xffffffff
+#define AFE_DPTX_MON0_MASK_SFT (0xffffffff << 0)
+
+/* AFE_TDM_CON1 */
+#define TDM_EN_SFT 0
+#define TDM_EN_MASK 0x1
+#define TDM_EN_MASK_SFT (0x1 << 0)
+#define BCK_INVERSE_SFT 1
+#define BCK_INVERSE_MASK 0x1
+#define BCK_INVERSE_MASK_SFT (0x1 << 1)
+#define LRCK_INVERSE_SFT 2
+#define LRCK_INVERSE_MASK 0x1
+#define LRCK_INVERSE_MASK_SFT (0x1 << 2)
+#define DELAY_DATA_SFT 3
+#define DELAY_DATA_MASK 0x1
+#define DELAY_DATA_MASK_SFT (0x1 << 3)
+#define LEFT_ALIGN_SFT 4
+#define LEFT_ALIGN_MASK 0x1
+#define LEFT_ALIGN_MASK_SFT (0x1 << 4)
+#define TDM_LRCK_D0P5T_SFT 5
+#define TDM_LRCK_D0P5T_MASK 0x1
+#define TDM_LRCK_D0P5T_MASK_SFT (0x1 << 5)
+#define TDM_SDATA_D0P5T_SFT 6
+#define TDM_SDATA_D0P5T_MASK 0x1
+#define TDM_SDATA_D0P5T_MASK_SFT (0x1 << 6)
+#define WLEN_SFT 8
+#define WLEN_MASK 0x3
+#define WLEN_MASK_SFT (0x3 << 8)
+#define CHANNEL_NUM_SFT 10
+#define CHANNEL_NUM_MASK 0x3
+#define CHANNEL_NUM_MASK_SFT (0x3 << 10)
+#define CHANNEL_BCK_CYCLES_SFT 12
+#define CHANNEL_BCK_CYCLES_MASK 0x3
+#define CHANNEL_BCK_CYCLES_MASK_SFT (0x3 << 12)
+#define HDMI_CLK_INV_SEL_SFT 15
+#define HDMI_CLK_INV_SEL_MASK 0x1
+#define HDMI_CLK_INV_SEL_MASK_SFT (0x1 << 15)
+#define DAC_BIT_NUM_SFT 16
+#define DAC_BIT_NUM_MASK 0x1f
+#define DAC_BIT_NUM_MASK_SFT (0x1f << 16)
+#define LRCK_TDM_WIDTH_SFT 24
+#define LRCK_TDM_WIDTH_MASK 0xff
+#define LRCK_TDM_WIDTH_MASK_SFT (0xff << 24)
+
+/* AFE_TDM_CON2 */
+#define ST_CH_PAIR_SOUT0_SFT 0
+#define ST_CH_PAIR_SOUT0_MASK 0x7
+#define ST_CH_PAIR_SOUT0_MASK_SFT (0x7 << 0)
+#define ST_CH_PAIR_SOUT1_SFT 4
+#define ST_CH_PAIR_SOUT1_MASK 0x7
+#define ST_CH_PAIR_SOUT1_MASK_SFT (0x7 << 4)
+#define ST_CH_PAIR_SOUT2_SFT 8
+#define ST_CH_PAIR_SOUT2_MASK 0x7
+#define ST_CH_PAIR_SOUT2_MASK_SFT (0x7 << 8)
+#define ST_CH_PAIR_SOUT3_SFT 12
+#define ST_CH_PAIR_SOUT3_MASK 0x7
+#define ST_CH_PAIR_SOUT3_MASK_SFT (0x7 << 12)
+#define TDM_FIX_VALUE_SEL_SFT 16
+#define TDM_FIX_VALUE_SEL_MASK 0x1
+#define TDM_FIX_VALUE_SEL_MASK_SFT (0x1 << 16)
+#define TDM_I2S_LOOPBACK_SFT 20
+#define TDM_I2S_LOOPBACK_MASK 0x1
+#define TDM_I2S_LOOPBACK_MASK_SFT (0x1 << 20)
+#define TDM_I2S_LOOPBACK_CH_SFT 21
+#define TDM_I2S_LOOPBACK_CH_MASK 0x3
+#define TDM_I2S_LOOPBACK_CH_MASK_SFT (0x3 << 21)
+#define TDM_USE_SINEGEN_INPUT_SFT 23
+#define TDM_USE_SINEGEN_INPUT_MASK 0x1
+#define TDM_USE_SINEGEN_INPUT_MASK_SFT (0x1 << 23)
+#define TDM_FIX_VALUE_SFT 24
+#define TDM_FIX_VALUE_MASK 0xff
+#define TDM_FIX_VALUE_MASK_SFT (0xff << 24)
+
+/* AFE_TDM_CON3 */
+#define TDM_OUT_SEL_DOMAIN_SFT 29
+#define TDM_OUT_SEL_DOMAIN_MASK 0x7
+#define TDM_OUT_SEL_DOMAIN_MASK_SFT (0x7 << 29)
+#define TDM_OUT_SEL_FS_SFT 24
+#define TDM_OUT_SEL_FS_MASK 0x1f
+#define TDM_OUT_SEL_FS_MASK_SFT (0x1f << 24)
+#define TDM_OUT_MON_SEL_SFT 3
+#define TDM_OUT_MON_SEL_MASK 0x1
+#define TDM_OUT_MON_SEL_MASK_SFT (0x1 << 3)
+#define RG_TDM_OUT_ASYNC_FIFO_SOFT_RST_EN_SFT 2
+#define RG_TDM_OUT_ASYNC_FIFO_SOFT_RST_EN_MASK 0x1
+#define RG_TDM_OUT_ASYNC_FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 2)
+#define RG_TDM_OUT_ASYNC_FIFO_SOFT_RST_SFT 1
+#define RG_TDM_OUT_ASYNC_FIFO_SOFT_RST_MASK 0x1
+#define RG_TDM_OUT_ASYNC_FIFO_SOFT_RST_MASK_SFT (0x1 << 1)
+#define TDM_UPDATE_EN_SEL_SFT 0
+#define TDM_UPDATE_EN_SEL_MASK 0x1
+#define TDM_UPDATE_EN_SEL_MASK_SFT (0x1 << 0)
+
+/* AFE_TDM_OUT_MON */
+#define AFE_TDM_OUT_MON_SFT 0
+#define AFE_TDM_OUT_MON_MASK 0xffffffff
+#define AFE_TDM_OUT_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_HDMI_CONN0 */
+#define HDMI_O_7_SFT 21
+#define HDMI_O_7_MASK 0x7
+#define HDMI_O_7_MASK_SFT (0x7 << 21)
+#define HDMI_O_6_SFT 18
+#define HDMI_O_6_MASK 0x7
+#define HDMI_O_6_MASK_SFT (0x7 << 18)
+#define HDMI_O_5_SFT 15
+#define HDMI_O_5_MASK 0x7
+#define HDMI_O_5_MASK_SFT (0x7 << 15)
+#define HDMI_O_4_SFT 12
+#define HDMI_O_4_MASK 0x7
+#define HDMI_O_4_MASK_SFT (0x7 << 12)
+#define HDMI_O_3_SFT 9
+#define HDMI_O_3_MASK 0x7
+#define HDMI_O_3_MASK_SFT (0x7 << 9)
+#define HDMI_O_2_SFT 6
+#define HDMI_O_2_MASK 0x7
+#define HDMI_O_2_MASK_SFT (0x7 << 6)
+#define HDMI_O_1_SFT 3
+#define HDMI_O_1_MASK 0x7
+#define HDMI_O_1_MASK_SFT (0x7 << 3)
+#define HDMI_O_0_SFT 0
+#define HDMI_O_0_MASK 0x7
+#define HDMI_O_0_MASK_SFT (0x7 << 0)
+
+/* AFE_TDM_TOP_IP_VERSION */
+#define AFE_TDM_TOP_IP_VERSION_SFT 0
+#define AFE_TDM_TOP_IP_VERSION_MASK 0xffffffff
+#define AFE_TDM_TOP_IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+/* AFE_HDMI_OUT_BASE_MSB */
+#define AFE_HDMI_OUT_BASE_MSB_SFT 0
+#define AFE_HDMI_OUT_BASE_MSB_MASK 0x1ff
+#define AFE_HDMI_OUT_BASE_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_HDMI_OUT_BASE */
+#define AFE_HDMI_OUT_BASE_SFT 4
+#define AFE_HDMI_OUT_BASE_MASK 0xfffffff
+#define AFE_HDMI_OUT_BASE_MASK_SFT (0xfffffff << 4)
+
+/* AFE_HDMI_OUT_CUR_MSB */
+#define AFE_HDMI_OUT_CUR_MSB_SFT 0
+#define AFE_HDMI_OUT_CUR_MSB_MASK 0x1ff
+#define AFE_HDMI_OUT_CUR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_HDMI_OUT_CUR */
+#define AFE_HDMI_OUT_CUR_SFT 0
+#define AFE_HDMI_OUT_CUR_MASK 0xffffffff
+#define AFE_HDMI_OUT_CUR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_HDMI_OUT_END_MSB */
+#define AFE_HDMI_OUT_END_MSB_SFT 0
+#define AFE_HDMI_OUT_END_MSB_MASK 0x1ff
+#define AFE_HDMI_OUT_END_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_HDMI_OUT_END */
+#define AFE_HDMI_OUT_END_SFT 4
+#define AFE_HDMI_OUT_END_MASK 0xfffffff
+#define AFE_HDMI_OUT_END_MASK_SFT (0xfffffff << 4)
+#define AFE_HDMI_OUT_END_LSB_SFT 0
+#define AFE_HDMI_OUT_END_LSB_MASK 0xf
+#define AFE_HDMI_OUT_END_LSB_MASK_SFT (0xf << 0)
+
+/* AFE_HDMI_OUT_CON0 */
+#define HDMI_OUT_ON_SFT 28
+#define HDMI_OUT_ON_MASK 0x1
+#define HDMI_OUT_ON_MASK_SFT (0x1 << 28)
+#define HDMI_CH_NUM_SFT 24
+#define HDMI_CH_NUM_MASK 0xf
+#define HDMI_CH_NUM_MASK_SFT (0xf << 24)
+#define HDMI_OUT_ONE_HEART_SEL_SFT 22
+#define HDMI_OUT_ONE_HEART_SEL_MASK 0x3
+#define HDMI_OUT_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define HDMI_OUT_MINLEN_SFT 20
+#define HDMI_OUT_MINLEN_MASK 0x3
+#define HDMI_OUT_MINLEN_MASK_SFT (0x3 << 20)
+#define HDMI_OUT_MAXLEN_SFT 16
+#define HDMI_OUT_MAXLEN_MASK 0x3
+#define HDMI_OUT_MAXLEN_MASK_SFT (0x3 << 16)
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_SFT 15
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15)
+#define HDMI_OUT_PBUF_SIZE_SFT 12
+#define HDMI_OUT_PBUF_SIZE_MASK 0x3
+#define HDMI_OUT_PBUF_SIZE_MASK_SFT (0x3 << 12)
+#define HDMI_OUT_SW_CLEAR_HDMI_BUF_EMPTY_SFT 7
+#define HDMI_OUT_SW_CLEAR_HDMI_BUF_EMPTY_MASK 0x1
+#define HDMI_OUT_SW_CLEAR_HDMI_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define HDMI_OUT_NORMAL_MODE_SFT 5
+#define HDMI_OUT_NORMAL_MODE_MASK 0x1
+#define HDMI_OUT_NORMAL_MODE_MASK_SFT (0x1 << 5)
+#define HDMI_OUT_HALIGN_SFT 4
+#define HDMI_OUT_HALIGN_MASK 0x1
+#define HDMI_OUT_HALIGN_MASK_SFT (0x1 << 4)
+#define HDMI_OUT_HD_MODE_SFT 0
+#define HDMI_OUT_HD_MODE_MASK 0x3
+#define HDMI_OUT_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_CBIP_CFG0 */
+#define CBIP_TOP_SLV_MUX_WAY_EN_SFT 16
+#define CBIP_TOP_SLV_MUX_WAY_EN_MASK 0xffff
+#define CBIP_TOP_SLV_MUX_WAY_EN_MASK_SFT (0xffff << 16)
+#define RESERVED_04_SFT 15
+#define RESERVED_04_MASK 0x1
+#define RESERVED_04_MASK_SFT (0x1 << 15)
+#define CBIP_ASYNC_MST_RG_FIFO_THRE_SFT 13
+#define CBIP_ASYNC_MST_RG_FIFO_THRE_MASK 0x3
+#define CBIP_ASYNC_MST_RG_FIFO_THRE_MASK_SFT (0x3 << 13)
+#define CBIP_ASYNC_MST_POSTWRITE_DIS_SFT 12
+#define CBIP_ASYNC_MST_POSTWRITE_DIS_MASK 0x1
+#define CBIP_ASYNC_MST_POSTWRITE_DIS_MASK_SFT (0x1 << 12)
+#define RESERVED_03_SFT 11
+#define RESERVED_03_MASK 0x1
+#define RESERVED_03_MASK_SFT (0x1 << 11)
+#define CBIP_ASYNC_SLV_RG_FIFO_THRE_SFT 9
+#define CBIP_ASYNC_SLV_RG_FIFO_THRE_MASK 0x3
+#define CBIP_ASYNC_SLV_RG_FIFO_THRE_MASK_SFT (0x3 << 9)
+#define CBIP_ASYNC_SLV_POSTWRITE_DIS_SFT 8
+#define CBIP_ASYNC_SLV_POSTWRITE_DIS_MASK 0x1
+#define CBIP_ASYNC_SLV_POSTWRITE_DIS_MASK_SFT (0x1 << 8)
+#define AUDIOSYS_BUSY_SFT 7
+#define AUDIOSYS_BUSY_MASK 0x1
+#define AUDIOSYS_BUSY_MASK_SFT (0x1 << 7)
+#define CBIP_SLV_DECODER_ERR_FLAG_EN_SFT 6
+#define CBIP_SLV_DECODER_ERR_FLAG_EN_MASK 0x1
+#define CBIP_SLV_DECODER_ERR_FLAG_EN_MASK_SFT (0x1 << 6)
+#define CBIP_SLV_DECODER_SLAVE_WAY_EN_SFT 5
+#define CBIP_SLV_DECODER_SLAVE_WAY_EN_MASK 0x1
+#define CBIP_SLV_DECODER_SLAVE_WAY_EN_MASK_SFT (0x1 << 5)
+#define APB_R2T_SFT 3
+#define APB_R2T_MASK 0x1
+#define APB_R2T_MASK_SFT (0x1 << 3)
+#define APB_W2T_SFT 2
+#define APB_W2T_MASK 0x1
+#define APB_W2T_MASK_SFT (0x1 << 2)
+#define AHB_IDLE_EN_INT_SFT 1
+#define AHB_IDLE_EN_INT_MASK 0x1
+#define AHB_IDLE_EN_INT_MASK_SFT (0x1 << 1)
+#define AHB_IDLE_EN_EXT_SFT 0
+#define AHB_IDLE_EN_EXT_MASK 0x1
+#define AHB_IDLE_EN_EXT_MASK_SFT (0x1 << 0)
+
+/* AFE_CBIP_SLV_DECODER_MON0 */
+#define CBIP_SLV_DECODER_ERR_DOMAIN_SFT 4
+#define CBIP_SLV_DECODER_ERR_DOMAIN_MASK 0x1
+#define CBIP_SLV_DECODER_ERR_DOMAIN_MASK_SFT (0x1 << 4)
+#define CBIP_SLV_DECODER_ERR_ID_SFT 3
+#define CBIP_SLV_DECODER_ERR_ID_MASK 0x1
+#define CBIP_SLV_DECODER_ERR_ID_MASK_SFT (0x1 << 3)
+#define CBIP_SLV_DECODER_ERR_RW_SFT 2
+#define CBIP_SLV_DECODER_ERR_RW_MASK 0x1
+#define CBIP_SLV_DECODER_ERR_RW_MASK_SFT (0x1 << 2)
+#define CBIP_SLV_DECODER_ERR_DECERR_SFT 1
+#define CBIP_SLV_DECODER_ERR_DECERR_MASK 0x1
+#define CBIP_SLV_DECODER_ERR_DECERR_MASK_SFT (0x1 << 1)
+#define CBIP_SLV_DECODER_CTRL_UPDATE_STATUS_SFT 0
+#define CBIP_SLV_DECODER_CTRL_UPDATE_STATUS_MASK 0x1
+#define CBIP_SLV_DECODER_CTRL_UPDATE_STATUS_MASK_SFT (0x1 << 0)
+
+/* AFE_CBIP_SLV_DECODER_MON1 */
+#define CBIP_SLV_DECODER_ERR_ADDR_SFT 0
+#define CBIP_SLV_DECODER_ERR_ADDR_MASK 0xffffffff
+#define CBIP_SLV_DECODER_ERR_ADDR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CBIP_SLV_MUX_MON_CFG */
+#define CBIP_SLV_MUX_ERR_FLAG_EN_SFT 3
+#define CBIP_SLV_MUX_ERR_FLAG_EN_MASK 0x1
+#define CBIP_SLV_MUX_ERR_FLAG_EN_MASK_SFT (0x1 << 3)
+#define CBIP_SLV_MUX_REG_SLAVE_WAY_EN_SFT 2
+#define CBIP_SLV_MUX_REG_SLAVE_WAY_EN_MASK 0x1
+#define CBIP_SLV_MUX_REG_SLAVE_WAY_EN_MASK_SFT (0x1 << 2)
+#define CBIP_SLV_MUX_REG_LAYER_WAY_EN_SFT 0
+#define CBIP_SLV_MUX_REG_LAYER_WAY_EN_MASK 0x3
+#define CBIP_SLV_MUX_REG_LAYER_WAY_EN_MASK_SFT (0x3 << 0)
+
+/* AFE_CBIP_SLV_MUX_MON0 */
+#define CBIP_SLV_MUX_ERR_DOMAIN_SFT 8
+#define CBIP_SLV_MUX_ERR_DOMAIN_MASK 0x1
+#define CBIP_SLV_MUX_ERR_DOMAIN_MASK_SFT (0x1 << 8)
+#define CBIP_SLV_MUX_ERR_ID_SFT 7
+#define CBIP_SLV_MUX_ERR_ID_MASK 0x1
+#define CBIP_SLV_MUX_ERR_ID_MASK_SFT (0x1 << 7)
+#define CBIP_SLV_MUX_ERR_RD_SFT 6
+#define CBIP_SLV_MUX_ERR_RD_MASK 0x1
+#define CBIP_SLV_MUX_ERR_RD_MASK_SFT (0x1 << 6)
+#define CBIP_SLV_MUX_ERR_WR_SFT 5
+#define CBIP_SLV_MUX_ERR_WR_MASK 0x1
+#define CBIP_SLV_MUX_ERR_WR_MASK_SFT (0x1 << 5)
+#define CBIP_SLV_MUX_ERR_EN_SLV_SFT 4
+#define CBIP_SLV_MUX_ERR_EN_SLV_MASK 0x1
+#define CBIP_SLV_MUX_ERR_EN_SLV_MASK_SFT (0x1 << 4)
+#define CBIP_SLV_MUX_ERR_EN_MST_SFT 2
+#define CBIP_SLV_MUX_ERR_EN_MST_MASK 0x3
+#define CBIP_SLV_MUX_ERR_EN_MST_MASK_SFT (0x3 << 2)
+#define CBIP_SLV_MUX_CTRL_UPDATE_STATUS_SFT 0
+#define CBIP_SLV_MUX_CTRL_UPDATE_STATUS_MASK 0x3
+#define CBIP_SLV_MUX_CTRL_UPDATE_STATUS_MASK_SFT (0x3 << 0)
+
+/* AFE_CBIP_SLV_MUX_MON1 */
+#define CBIP_SLV_MUX_ERR_ADDR_SFT 0
+#define CBIP_SLV_MUX_ERR_ADDR_MASK 0xffffffff
+#define CBIP_SLV_MUX_ERR_ADDR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_MEMIF_CON0 */
+#define CPU_COMPACT_MODE_SFT 2
+#define CPU_COMPACT_MODE_MASK 0x1
+#define CPU_COMPACT_MODE_MASK_SFT (0x1 << 2)
+#define CPU_HD_ALIGN_SFT 1
+#define CPU_HD_ALIGN_MASK 0x1
+#define CPU_HD_ALIGN_MASK_SFT (0x1 << 1)
+#define SYSRAM_SIGN_SFT 0
+#define SYSRAM_SIGN_MASK 0x1
+#define SYSRAM_SIGN_MASK_SFT (0x1 << 0)
+
+/* AFE_MEMIF_ONE_HEART */
+#define DL_ONE_HEART_ON_2_SFT 2
+#define DL_ONE_HEART_ON_2_MASK 0x1
+#define DL_ONE_HEART_ON_2_MASK_SFT (0x1 << 2)
+#define DL_ONE_HEART_ON_1_SFT 1
+#define DL_ONE_HEART_ON_1_MASK 0x1
+#define DL_ONE_HEART_ON_1_MASK_SFT (0x1 << 1)
+#define DL_ONE_HEART_ON_0_SFT 0
+#define DL_ONE_HEART_ON_0_MASK 0x1
+#define DL_ONE_HEART_ON_0_MASK_SFT (0x1 << 0)
+
+/* AFE_DL0_BASE_MSB */
+#define DL0_BASE_ADDR_MSB_SFT 0
+#define DL0_BASE_ADDR_MSB_MASK 0x1ff
+#define DL0_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL0_BASE */
+#define DL0_BASE_ADDR_SFT 4
+#define DL0_BASE_ADDR_MASK 0xfffffff
+#define DL0_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL0_CUR_MSB */
+#define DL0_CUR_PTR_MSB_SFT 0
+#define DL0_CUR_PTR_MSB_MASK 0x1ff
+#define DL0_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL0_CUR */
+#define DL0_CUR_PTR_SFT 0
+#define DL0_CUR_PTR_MASK 0xffffffff
+#define DL0_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL0_END_MSB */
+#define DL0_END_ADDR_MSB_SFT 0
+#define DL0_END_ADDR_MSB_MASK 0x1ff
+#define DL0_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL0_END */
+#define DL0_END_ADDR_SFT 4
+#define DL0_END_ADDR_MASK 0xfffffff
+#define DL0_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL0_RCH_MON */
+#define DL0_RCH_DATA_SFT 0
+#define DL0_RCH_DATA_MASK 0xffffffff
+#define DL0_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL0_LCH_MON */
+#define DL0_LCH_DATA_SFT 0
+#define DL0_LCH_DATA_MASK 0xffffffff
+#define DL0_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL0_CON0 */
+#define DL0_ON_SFT 28
+#define DL0_ON_MASK 0x1
+#define DL0_ON_MASK_SFT (0x1 << 28)
+#define DL0_ONE_HEART_SEL_SFT 22
+#define DL0_ONE_HEART_SEL_MASK 0x3
+#define DL0_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL0_MINLEN_SFT 20
+#define DL0_MINLEN_MASK 0x3
+#define DL0_MINLEN_MASK_SFT (0x3 << 20)
+#define DL0_MAXLEN_SFT 16
+#define DL0_MAXLEN_MASK 0x3
+#define DL0_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL0_SEL_DOMAIN_SFT 13
+#define DL0_SEL_DOMAIN_MASK 0x7
+#define DL0_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL0_SEL_FS_SFT 8
+#define DL0_SEL_FS_MASK 0x1f
+#define DL0_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL0_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL0_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL0_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL0_PBUF_SIZE_SFT 5
+#define DL0_PBUF_SIZE_MASK 0x3
+#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL0_MONO_SFT 4
+#define DL0_MONO_MASK 0x1
+#define DL0_MONO_MASK_SFT (0x1 << 4)
+#define DL0_NORMAL_MODE_SFT 3
+#define DL0_NORMAL_MODE_MASK 0x1
+#define DL0_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL0_HALIGN_SFT 2
+#define DL0_HALIGN_MASK 0x1
+#define DL0_HALIGN_MASK_SFT (0x1 << 2)
+#define DL0_HD_MODE_SFT 0
+#define DL0_HD_MODE_MASK 0x3
+#define DL0_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL0_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL1_BASE_MSB */
+#define DL1_BASE_ADDR_MSB_SFT 0
+#define DL1_BASE_ADDR_MSB_MASK 0x1ff
+#define DL1_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL1_BASE */
+#define DL1_BASE_ADDR_SFT 4
+#define DL1_BASE_ADDR_MASK 0xfffffff
+#define DL1_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL1_CUR_MSB */
+#define DL1_CUR_PTR_MSB_SFT 0
+#define DL1_CUR_PTR_MSB_MASK 0x1ff
+#define DL1_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL1_CUR */
+#define DL1_CUR_PTR_SFT 0
+#define DL1_CUR_PTR_MASK 0xffffffff
+#define DL1_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL1_END_MSB */
+#define DL1_END_ADDR_MSB_SFT 0
+#define DL1_END_ADDR_MSB_MASK 0x1ff
+#define DL1_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL1_END */
+#define DL1_END_ADDR_SFT 4
+#define DL1_END_ADDR_MASK 0xfffffff
+#define DL1_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL1_RCH_MON */
+#define DL1_RCH_DATA_SFT 0
+#define DL1_RCH_DATA_MASK 0xffffffff
+#define DL1_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL1_LCH_MON */
+#define DL1_LCH_DATA_SFT 0
+#define DL1_LCH_DATA_MASK 0xffffffff
+#define DL1_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL1_CON0 */
+#define DL1_ON_SFT 28
+#define DL1_ON_MASK 0x1
+#define DL1_ON_MASK_SFT (0x1 << 28)
+#define DL1_ONE_HEART_SEL_SFT 22
+#define DL1_ONE_HEART_SEL_MASK 0x3
+#define DL1_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL1_MINLEN_SFT 20
+#define DL1_MINLEN_MASK 0x3
+#define DL1_MINLEN_MASK_SFT (0x3 << 20)
+#define DL1_MAXLEN_SFT 16
+#define DL1_MAXLEN_MASK 0x3
+#define DL1_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL1_SEL_DOMAIN_SFT 13
+#define DL1_SEL_DOMAIN_MASK 0x7
+#define DL1_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL1_SEL_FS_SFT 8
+#define DL1_SEL_FS_MASK 0x1f
+#define DL1_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL1_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL1_PBUF_SIZE_SFT 5
+#define DL1_PBUF_SIZE_MASK 0x3
+#define DL1_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL1_MONO_SFT 4
+#define DL1_MONO_MASK 0x1
+#define DL1_MONO_MASK_SFT (0x1 << 4)
+#define DL1_NORMAL_MODE_SFT 3
+#define DL1_NORMAL_MODE_MASK 0x1
+#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL1_HALIGN_SFT 2
+#define DL1_HALIGN_MASK 0x1
+#define DL1_HALIGN_MASK_SFT (0x1 << 2)
+#define DL1_HD_MODE_SFT 0
+#define DL1_HD_MODE_MASK 0x3
+#define DL1_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL1_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL2_BASE_MSB */
+#define DL2_BASE__ADDR_MSB_SFT 0
+#define DL2_BASE__ADDR_MSB_MASK 0x1ff
+#define DL2_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL2_BASE */
+#define DL2_BASE_ADDR_SFT 4
+#define DL2_BASE_ADDR_MASK 0xfffffff
+#define DL2_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL2_CUR_MSB */
+#define DL2_CUR_PTR_MSB_SFT 0
+#define DL2_CUR_PTR_MSB_MASK 0x1ff
+#define DL2_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL2_CUR */
+#define DL2_CUR_PTR_SFT 0
+#define DL2_CUR_PTR_MASK 0xffffffff
+#define DL2_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL2_END_MSB */
+#define DL2_END_ADDR_MSB_SFT 0
+#define DL2_END_ADDR_MSB_MASK 0x1ff
+#define DL2_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL2_END */
+#define DL2_END_ADDR_SFT 4
+#define DL2_END_ADDR_MASK 0xfffffff
+#define DL2_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL2_RCH_MON */
+#define DL2_RCH_DATA_SFT 0
+#define DL2_RCH_DATA_MASK 0xffffffff
+#define DL2_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL2_LCH_MON */
+#define DL2_LCH_DATA_SFT 0
+#define DL2_LCH_DATA_MASK 0xffffffff
+#define DL2_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL2_CON0 */
+#define DL2_ON_SFT 28
+#define DL2_ON_MASK 0x1
+#define DL2_ON_MASK_SFT (0x1 << 28)
+#define DL2_ONE_HEART_SEL_SFT 22
+#define DL2_ONE_HEART_SEL_MASK 0x3
+#define DL2_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL2_MINLEN_SFT 20
+#define DL2_MINLEN_MASK 0x3
+#define DL2_MINLEN_MASK_SFT (0x3 << 20)
+#define DL2_MAXLEN_SFT 16
+#define DL2_MAXLEN_MASK 0x3
+#define DL2_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL2_SEL_DOMAIN_SFT 13
+#define DL2_SEL_DOMAIN_MASK 0x7
+#define DL2_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL2_SEL_FS_SFT 8
+#define DL2_SEL_FS_MASK 0x1f
+#define DL2_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL2_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL2_PBUF_SIZE_SFT 5
+#define DL2_PBUF_SIZE_MASK 0x3
+#define DL2_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL2_MONO_SFT 4
+#define DL2_MONO_MASK 0x1
+#define DL2_MONO_MASK_SFT (0x1 << 4)
+#define DL2_NORMAL_MODE_SFT 3
+#define DL2_NORMAL_MODE_MASK 0x1
+#define DL2_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL2_HALIGN_SFT 2
+#define DL2_HALIGN_MASK 0x1
+#define DL2_HALIGN_MASK_SFT (0x1 << 2)
+#define DL2_HD_MODE_SFT 0
+#define DL2_HD_MODE_MASK 0x3
+#define DL2_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL2_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL3_BASE_MSB */
+#define DL3_BASE__ADDR_MSB_SFT 0
+#define DL3_BASE__ADDR_MSB_MASK 0x1ff
+#define DL3_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL3_BASE */
+#define DL3_BASE_ADDR_SFT 4
+#define DL3_BASE_ADDR_MASK 0xfffffff
+#define DL3_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL3_CUR_MSB */
+#define DL3_CUR_PTR_MSB_SFT 0
+#define DL3_CUR_PTR_MSB_MASK 0x1ff
+#define DL3_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL3_CUR */
+#define DL3_CUR_PTR_SFT 0
+#define DL3_CUR_PTR_MASK 0xffffffff
+#define DL3_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL3_END_MSB */
+#define DL3_END_ADDR_MSB_SFT 0
+#define DL3_END_ADDR_MSB_MASK 0x1ff
+#define DL3_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL3_END */
+#define DL3_END_ADDR_SFT 4
+#define DL3_END_ADDR_MASK 0xfffffff
+#define DL3_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL3_RCH_MON */
+#define DL3_RCH_DATA_SFT 0
+#define DL3_RCH_DATA_MASK 0xffffffff
+#define DL3_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL3_LCH_MON */
+#define DL3_LCH_DATA_SFT 0
+#define DL3_LCH_DATA_MASK 0xffffffff
+#define DL3_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL3_CON0 */
+#define DL3_ON_SFT 28
+#define DL3_ON_MASK 0x1
+#define DL3_ON_MASK_SFT (0x1 << 28)
+#define DL3_ONE_HEART_SEL_SFT 22
+#define DL3_ONE_HEART_SEL_MASK 0x3
+#define DL3_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL3_MINLEN_SFT 20
+#define DL3_MINLEN_MASK 0x3
+#define DL3_MINLEN_MASK_SFT (0x3 << 20)
+#define DL3_MAXLEN_SFT 16
+#define DL3_MAXLEN_MASK 0x3
+#define DL3_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL3_SEL_DOMAIN_SFT 13
+#define DL3_SEL_DOMAIN_MASK 0x7
+#define DL3_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL3_SEL_FS_SFT 8
+#define DL3_SEL_FS_MASK 0x1f
+#define DL3_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL3_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL3_PBUF_SIZE_SFT 5
+#define DL3_PBUF_SIZE_MASK 0x3
+#define DL3_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL3_MONO_SFT 4
+#define DL3_MONO_MASK 0x1
+#define DL3_MONO_MASK_SFT (0x1 << 4)
+#define DL3_NORMAL_MODE_SFT 3
+#define DL3_NORMAL_MODE_MASK 0x1
+#define DL3_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL3_HALIGN_SFT 2
+#define DL3_HALIGN_MASK 0x1
+#define DL3_HALIGN_MASK_SFT (0x1 << 2)
+#define DL3_HD_MODE_SFT 0
+#define DL3_HD_MODE_MASK 0x3
+#define DL3_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL3_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL4_BASE_MSB */
+#define DL4_BASE__ADDR_MSB_SFT 0
+#define DL4_BASE__ADDR_MSB_MASK 0x1ff
+#define DL4_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL4_BASE */
+#define DL4_BASE_ADDR_SFT 4
+#define DL4_BASE_ADDR_MASK 0xfffffff
+#define DL4_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL4_CUR_MSB */
+#define DL4_CUR_PTR_MSB_SFT 0
+#define DL4_CUR_PTR_MSB_MASK 0x1ff
+#define DL4_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL4_CUR */
+#define DL4_CUR_PTR_SFT 0
+#define DL4_CUR_PTR_MASK 0xffffffff
+#define DL4_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL4_END_MSB */
+#define DL4_END_ADDR_MSB_SFT 0
+#define DL4_END_ADDR_MSB_MASK 0x1ff
+#define DL4_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL4_END */
+#define DL4_END_ADDR_SFT 4
+#define DL4_END_ADDR_MASK 0xfffffff
+#define DL4_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL4_RCH_MON */
+#define DL4_RCH_DATA_SFT 0
+#define DL4_RCH_DATA_MASK 0xffffffff
+#define DL4_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL4_LCH_MON */
+#define DL4_LCH_DATA_SFT 0
+#define DL4_LCH_DATA_MASK 0xffffffff
+#define DL4_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL4_CON0 */
+#define DL4_ON_SFT 28
+#define DL4_ON_MASK 0x1
+#define DL4_ON_MASK_SFT (0x1 << 28)
+#define DL4_ONE_HEART_SEL_SFT 22
+#define DL4_ONE_HEART_SEL_MASK 0x3
+#define DL4_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL4_MINLEN_SFT 20
+#define DL4_MINLEN_MASK 0x3
+#define DL4_MINLEN_MASK_SFT (0x3 << 20)
+#define DL4_MAXLEN_SFT 16
+#define DL4_MAXLEN_MASK 0x3
+#define DL4_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL4_SEL_DOMAIN_SFT 13
+#define DL4_SEL_DOMAIN_MASK 0x7
+#define DL4_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL4_SEL_FS_SFT 8
+#define DL4_SEL_FS_MASK 0x1f
+#define DL4_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL4_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL4_PBUF_SIZE_SFT 5
+#define DL4_PBUF_SIZE_MASK 0x3
+#define DL4_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL4_MONO_SFT 4
+#define DL4_MONO_MASK 0x1
+#define DL4_MONO_MASK_SFT (0x1 << 4)
+#define DL4_NORMAL_MODE_SFT 3
+#define DL4_NORMAL_MODE_MASK 0x1
+#define DL4_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL4_HALIGN_SFT 2
+#define DL4_HALIGN_MASK 0x1
+#define DL4_HALIGN_MASK_SFT (0x1 << 2)
+#define DL4_HD_MODE_SFT 0
+#define DL4_HD_MODE_MASK 0x3
+#define DL4_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL4_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL5_BASE_MSB */
+#define DL5_BASE__ADDR_MSB_SFT 0
+#define DL5_BASE__ADDR_MSB_MASK 0x1ff
+#define DL5_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL5_BASE */
+#define DL5_BASE_ADDR_SFT 4
+#define DL5_BASE_ADDR_MASK 0xfffffff
+#define DL5_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL5_CUR_MSB */
+#define DL5_CUR_PTR_MSB_SFT 0
+#define DL5_CUR_PTR_MSB_MASK 0x1ff
+#define DL5_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL5_CUR */
+#define DL5_CUR_PTR_SFT 0
+#define DL5_CUR_PTR_MASK 0xffffffff
+#define DL5_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL5_END_MSB */
+#define DL5_END_ADDR_MSB_SFT 0
+#define DL5_END_ADDR_MSB_MASK 0x1ff
+#define DL5_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL5_END */
+#define DL5_END_ADDR_SFT 4
+#define DL5_END_ADDR_MASK 0xfffffff
+#define DL5_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL5_RCH_MON */
+#define DL5_RCH_DATA_SFT 0
+#define DL5_RCH_DATA_MASK 0xffffffff
+#define DL5_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL5_LCH_MON */
+#define DL5_LCH_DATA_SFT 0
+#define DL5_LCH_DATA_MASK 0xffffffff
+#define DL5_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL5_CON0 */
+#define DL5_ON_SFT 28
+#define DL5_ON_MASK 0x1
+#define DL5_ON_MASK_SFT (0x1 << 28)
+#define DL5_ONE_HEART_SEL_SFT 22
+#define DL5_ONE_HEART_SEL_MASK 0x3
+#define DL5_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL5_MINLEN_SFT 20
+#define DL5_MINLEN_MASK 0x3
+#define DL5_MINLEN_MASK_SFT (0x3 << 20)
+#define DL5_MAXLEN_SFT 16
+#define DL5_MAXLEN_MASK 0x3
+#define DL5_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL5_SEL_DOMAIN_SFT 13
+#define DL5_SEL_DOMAIN_MASK 0x7
+#define DL5_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL5_SEL_FS_SFT 8
+#define DL5_SEL_FS_MASK 0x1f
+#define DL5_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL5_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL5_PBUF_SIZE_SFT 5
+#define DL5_PBUF_SIZE_MASK 0x3
+#define DL5_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL5_MONO_SFT 4
+#define DL5_MONO_MASK 0x1
+#define DL5_MONO_MASK_SFT (0x1 << 4)
+#define DL5_NORMAL_MODE_SFT 3
+#define DL5_NORMAL_MODE_MASK 0x1
+#define DL5_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL5_HALIGN_SFT 2
+#define DL5_HALIGN_MASK 0x1
+#define DL5_HALIGN_MASK_SFT (0x1 << 2)
+#define DL5_HD_MODE_SFT 0
+#define DL5_HD_MODE_MASK 0x3
+#define DL5_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL5_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL6_BASE_MSB */
+#define DL6_BASE__ADDR_MSB_SFT 0
+#define DL6_BASE__ADDR_MSB_MASK 0x1ff
+#define DL6_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL6_BASE */
+#define DL6_BASE_ADDR_SFT 4
+#define DL6_BASE_ADDR_MASK 0xfffffff
+#define DL6_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL6_CUR_MSB */
+#define DL6_CUR_PTR_MSB_SFT 0
+#define DL6_CUR_PTR_MSB_MASK 0x1ff
+#define DL6_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL6_CUR */
+#define DL6_CUR_PTR_SFT 0
+#define DL6_CUR_PTR_MASK 0xffffffff
+#define DL6_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL6_END_MSB */
+#define DL6_END_ADDR_MSB_SFT 0
+#define DL6_END_ADDR_MSB_MASK 0x1ff
+#define DL6_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL6_END */
+#define DL6_END_ADDR_SFT 4
+#define DL6_END_ADDR_MASK 0xfffffff
+#define DL6_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL6_RCH_MON */
+#define DL6_RCH_DATA_SFT 0
+#define DL6_RCH_DATA_MASK 0xffffffff
+#define DL6_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL6_LCH_MON */
+#define DL6_LCH_DATA_SFT 0
+#define DL6_LCH_DATA_MASK 0xffffffff
+#define DL6_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL6_CON0 */
+#define DL6_ON_SFT 28
+#define DL6_ON_MASK 0x1
+#define DL6_ON_MASK_SFT (0x1 << 28)
+#define DL6_ONE_HEART_SEL_SFT 22
+#define DL6_ONE_HEART_SEL_MASK 0x3
+#define DL6_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL6_MINLEN_SFT 20
+#define DL6_MINLEN_MASK 0x3
+#define DL6_MINLEN_MASK_SFT (0x3 << 20)
+#define DL6_MAXLEN_SFT 16
+#define DL6_MAXLEN_MASK 0x3
+#define DL6_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL6_SEL_DOMAIN_SFT 13
+#define DL6_SEL_DOMAIN_MASK 0x7
+#define DL6_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL6_SEL_FS_SFT 8
+#define DL6_SEL_FS_MASK 0x1f
+#define DL6_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL6_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL6_PBUF_SIZE_SFT 5
+#define DL6_PBUF_SIZE_MASK 0x3
+#define DL6_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL6_MONO_SFT 4
+#define DL6_MONO_MASK 0x1
+#define DL6_MONO_MASK_SFT (0x1 << 4)
+#define DL6_NORMAL_MODE_SFT 3
+#define DL6_NORMAL_MODE_MASK 0x1
+#define DL6_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL6_HALIGN_SFT 2
+#define DL6_HALIGN_MASK 0x1
+#define DL6_HALIGN_MASK_SFT (0x1 << 2)
+#define DL6_HD_MODE_SFT 0
+#define DL6_HD_MODE_MASK 0x3
+#define DL6_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL6_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL7_BASE_MSB */
+#define DL7_BASE__ADDR_MSB_SFT 0
+#define DL7_BASE__ADDR_MSB_MASK 0x1ff
+#define DL7_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL7_BASE */
+#define DL7_BASE_ADDR_SFT 4
+#define DL7_BASE_ADDR_MASK 0xfffffff
+#define DL7_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL7_CUR_MSB */
+#define DL7_CUR_PTR_MSB_SFT 0
+#define DL7_CUR_PTR_MSB_MASK 0x1ff
+#define DL7_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL7_CUR */
+#define DL7_CUR_PTR_SFT 0
+#define DL7_CUR_PTR_MASK 0xffffffff
+#define DL7_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL7_END_MSB */
+#define DL7_END_ADDR_MSB_SFT 0
+#define DL7_END_ADDR_MSB_MASK 0x1ff
+#define DL7_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL7_END */
+#define DL7_END_ADDR_SFT 4
+#define DL7_END_ADDR_MASK 0xfffffff
+#define DL7_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL7_RCH_MON */
+#define DL7_RCH_DATA_SFT 0
+#define DL7_RCH_DATA_MASK 0xffffffff
+#define DL7_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL7_LCH_MON */
+#define DL7_LCH_DATA_SFT 0
+#define DL7_LCH_DATA_MASK 0xffffffff
+#define DL7_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL7_CON0 */
+#define DL7_ON_SFT 28
+#define DL7_ON_MASK 0x1
+#define DL7_ON_MASK_SFT (0x1 << 28)
+#define DL7_ONE_HEART_SEL_SFT 22
+#define DL7_ONE_HEART_SEL_MASK 0x3
+#define DL7_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL7_MINLEN_SFT 20
+#define DL7_MINLEN_MASK 0x3
+#define DL7_MINLEN_MASK_SFT (0x3 << 20)
+#define DL7_MAXLEN_SFT 16
+#define DL7_MAXLEN_MASK 0x3
+#define DL7_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL7_SEL_DOMAIN_SFT 13
+#define DL7_SEL_DOMAIN_MASK 0x7
+#define DL7_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL7_SEL_FS_SFT 8
+#define DL7_SEL_FS_MASK 0x1f
+#define DL7_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL7_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL7_PBUF_SIZE_SFT 5
+#define DL7_PBUF_SIZE_MASK 0x3
+#define DL7_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL7_MONO_SFT 4
+#define DL7_MONO_MASK 0x1
+#define DL7_MONO_MASK_SFT (0x1 << 4)
+#define DL7_NORMAL_MODE_SFT 3
+#define DL7_NORMAL_MODE_MASK 0x1
+#define DL7_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL7_HALIGN_SFT 2
+#define DL7_HALIGN_MASK 0x1
+#define DL7_HALIGN_MASK_SFT (0x1 << 2)
+#define DL7_HD_MODE_SFT 0
+#define DL7_HD_MODE_MASK 0x3
+#define DL7_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL7_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL8_BASE_MSB */
+#define DL8_BASE__ADDR_MSB_SFT 0
+#define DL8_BASE__ADDR_MSB_MASK 0x1ff
+#define DL8_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL8_BASE */
+#define DL8_BASE_ADDR_SFT 4
+#define DL8_BASE_ADDR_MASK 0xfffffff
+#define DL8_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL8_CUR_MSB */
+#define DL8_CUR_PTR_MSB_SFT 0
+#define DL8_CUR_PTR_MSB_MASK 0x1ff
+#define DL8_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL8_CUR */
+#define DL8_CUR_PTR_SFT 0
+#define DL8_CUR_PTR_MASK 0xffffffff
+#define DL8_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL8_END_MSB */
+#define DL8_END_ADDR_MSB_SFT 0
+#define DL8_END_ADDR_MSB_MASK 0x1ff
+#define DL8_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL8_END */
+#define DL8_END_ADDR_SFT 4
+#define DL8_END_ADDR_MASK 0xfffffff
+#define DL8_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL8_RCH_MON */
+#define DL8_RCH_DATA_SFT 0
+#define DL8_RCH_DATA_MASK 0xffffffff
+#define DL8_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL8_LCH_MON */
+#define DL8_LCH_DATA_SFT 0
+#define DL8_LCH_DATA_MASK 0xffffffff
+#define DL8_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL8_CON0 */
+#define DL8_ON_SFT 28
+#define DL8_ON_MASK 0x1
+#define DL8_ON_MASK_SFT (0x1 << 28)
+#define DL8_ONE_HEART_SEL_SFT 22
+#define DL8_ONE_HEART_SEL_MASK 0x3
+#define DL8_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL8_MINLEN_SFT 20
+#define DL8_MINLEN_MASK 0x3
+#define DL8_MINLEN_MASK_SFT (0x3 << 20)
+#define DL8_MAXLEN_SFT 16
+#define DL8_MAXLEN_MASK 0x3
+#define DL8_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL8_SEL_DOMAIN_SFT 13
+#define DL8_SEL_DOMAIN_MASK 0x7
+#define DL8_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL8_SEL_FS_SFT 8
+#define DL8_SEL_FS_MASK 0x1f
+#define DL8_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL8_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL8_PBUF_SIZE_SFT 5
+#define DL8_PBUF_SIZE_MASK 0x3
+#define DL8_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL8_MONO_SFT 4
+#define DL8_MONO_MASK 0x1
+#define DL8_MONO_MASK_SFT (0x1 << 4)
+#define DL8_NORMAL_MODE_SFT 3
+#define DL8_NORMAL_MODE_MASK 0x1
+#define DL8_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL8_HALIGN_SFT 2
+#define DL8_HALIGN_MASK 0x1
+#define DL8_HALIGN_MASK_SFT (0x1 << 2)
+#define DL8_HD_MODE_SFT 0
+#define DL8_HD_MODE_MASK 0x3
+#define DL8_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL8_MON0 */
+#define RESERVED_01_SFT 20
+#define RESERVED_01_MASK 0xfff
+#define RESERVED_01_MASK_SFT (0xfff << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_EMPTY_SFT 18
+#define BUF_EMPTY_MASK 0x1
+#define BUF_EMPTY_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_DL_24CH_BASE_MSB */
+#define DL_24CH_BASE__ADDR_MSB_SFT 0
+#define DL_24CH_BASE__ADDR_MSB_MASK 0x1ff
+#define DL_24CH_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL_24CH_BASE */
+#define DL_24CH_BASE_ADDR_SFT 4
+#define DL_24CH_BASE_ADDR_MASK 0xfffffff
+#define DL_24CH_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL_24CH_CUR_MSB */
+#define DL_24CH_CUR_PTR_MSB_SFT 0
+#define DL_24CH_CUR_PTR_MSB_MASK 0x1ff
+#define DL_24CH_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL_24CH_CUR */
+#define DL_24CH_CUR_PTR_SFT 0
+#define DL_24CH_CUR_PTR_MASK 0xffffffff
+#define DL_24CH_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_END_MSB */
+#define DL_24CH_END_ADDR_MSB_SFT 0
+#define DL_24CH_END_ADDR_MSB_MASK 0x1ff
+#define DL_24CH_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL_24CH_END */
+#define DL_24CH_END_ADDR_SFT 4
+#define DL_24CH_END_ADDR_MASK 0xfffffff
+#define DL_24CH_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL_24CH_CON0 */
+#define DL_24CH_ON_SFT 31
+#define DL_24CH_ON_MASK 0x1
+#define DL_24CH_ON_MASK_SFT (0x1 << 31)
+#define DL_24CH_NUM_SFT 24
+#define DL_24CH_NUM_MASK 0x3f
+#define DL_24CH_NUM_MASK_SFT (0x3f << 24)
+#define DL_24CH_ONE_HEART_SEL_SFT 22
+#define DL_24CH_ONE_HEART_SEL_MASK 0x3
+#define DL_24CH_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL_24CH_MINLEN_SFT 20
+#define DL_24CH_MINLEN_MASK 0x3
+#define DL_24CH_MINLEN_MASK_SFT (0x3 << 20)
+#define DL_24CH_MAXLEN_SFT 16
+#define DL_24CH_MAXLEN_MASK 0x3
+#define DL_24CH_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL_24CH_SEL_DOMAIN_SFT 13
+#define DL_24CH_SEL_DOMAIN_MASK 0x7
+#define DL_24CH_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL_24CH_SEL_FS_SFT 8
+#define DL_24CH_SEL_FS_MASK 0x1f
+#define DL_24CH_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL_24CH_BUF_EMPTY_CLR_SFT 7
+#define DL_24CH_BUF_EMPTY_CLR_MASK 0x1
+#define DL_24CH_BUF_EMPTY_CLR_MASK_SFT (0x1 << 7)
+#define DL_24CH_PBUF_SIZE_SFT 5
+#define DL_24CH_PBUF_SIZE_MASK 0x3
+#define DL_24CH_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL_24CH_HANG_CLR_SFT 4
+#define DL_24CH_HANG_CLR_MASK 0x1
+#define DL_24CH_HANG_CLR_MASK_SFT (0x1 << 4)
+#define DL_24CH_NORMAL_MODE_SFT 3
+#define DL_24CH_NORMAL_MODE_MASK 0x1
+#define DL_24CH_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL_24CH_HALIGN_SFT 2
+#define DL_24CH_HALIGN_MASK 0x1
+#define DL_24CH_HALIGN_MASK_SFT (0x1 << 2)
+#define DL_24CH_HD_MODE_SFT 0
+#define DL_24CH_HD_MODE_MASK 0x3
+#define DL_24CH_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL23_BASE_MSB */
+#define DL23_BASE__ADDR_MSB_SFT 0
+#define DL23_BASE__ADDR_MSB_MASK 0x1ff
+#define DL23_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL23_BASE */
+#define DL23_BASE_ADDR_SFT 4
+#define DL23_BASE_ADDR_MASK 0xfffffff
+#define DL23_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL23_CUR_MSB */
+#define DL23_CUR_PTR_MSB_SFT 0
+#define DL23_CUR_PTR_MSB_MASK 0x1ff
+#define DL23_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL23_CUR */
+#define DL23_CUR_PTR_SFT 0
+#define DL23_CUR_PTR_MASK 0xffffffff
+#define DL23_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL23_END_MSB */
+#define DL23_END_ADDR_MSB_SFT 0
+#define DL23_END_ADDR_MSB_MASK 0x1ff
+#define DL23_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL23_END */
+#define DL23_END_ADDR_SFT 4
+#define DL23_END_ADDR_MASK 0xfffffff
+#define DL23_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL23_RCH_MON */
+#define DL23_RCH_DATA_SFT 0
+#define DL23_RCH_DATA_MASK 0xffffffff
+#define DL23_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL23_LCH_MON */
+#define DL23_LCH_DATA_SFT 0
+#define DL23_LCH_DATA_MASK 0xffffffff
+#define DL23_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL23_CON0 */
+#define DL23_ON_SFT 28
+#define DL23_ON_MASK 0x1
+#define DL23_ON_MASK_SFT (0x1 << 28)
+#define DL23_ONE_HEART_SEL_SFT 22
+#define DL23_ONE_HEART_SEL_MASK 0x3
+#define DL23_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL23_MINLEN_SFT 20
+#define DL23_MINLEN_MASK 0x3
+#define DL23_MINLEN_MASK_SFT (0x3 << 20)
+#define DL23_MAXLEN_SFT 16
+#define DL23_MAXLEN_MASK 0x3
+#define DL23_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL23_SEL_DOMAIN_SFT 13
+#define DL23_SEL_DOMAIN_MASK 0x7
+#define DL23_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL23_SEL_FS_SFT 8
+#define DL23_SEL_FS_MASK 0x1f
+#define DL23_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL23_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL23_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL23_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL23_PBUF_SIZE_SFT 5
+#define DL23_PBUF_SIZE_MASK 0x3
+#define DL23_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL23_MONO_SFT 4
+#define DL23_MONO_MASK 0x1
+#define DL23_MONO_MASK_SFT (0x1 << 4)
+#define DL23_NORMAL_MODE_SFT 3
+#define DL23_NORMAL_MODE_MASK 0x1
+#define DL23_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL23_HALIGN_SFT 2
+#define DL23_HALIGN_MASK 0x1
+#define DL23_HALIGN_MASK_SFT (0x1 << 2)
+#define DL23_HD_MODE_SFT 0
+#define DL23_HD_MODE_MASK 0x3
+#define DL23_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL24_BASE_MSB */
+#define DL24_BASE__ADDR_MSB_SFT 0
+#define DL24_BASE__ADDR_MSB_MASK 0x1ff
+#define DL24_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL24_BASE */
+#define DL24_BASE_ADDR_SFT 4
+#define DL24_BASE_ADDR_MASK 0xfffffff
+#define DL24_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL24_CUR_MSB */
+#define DL24_CUR_PTR_MSB_SFT 0
+#define DL24_CUR_PTR_MSB_MASK 0x1ff
+#define DL24_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL24_CUR */
+#define DL24_CUR_PTR_SFT 0
+#define DL24_CUR_PTR_MASK 0xffffffff
+#define DL24_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL24_END_MSB */
+#define DL24_END_ADDR_MSB_SFT 0
+#define DL24_END_ADDR_MSB_MASK 0x1ff
+#define DL24_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL24_END */
+#define DL24_END_ADDR_SFT 4
+#define DL24_END_ADDR_MASK 0xfffffff
+#define DL24_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL24_RCH_MON */
+#define DL24_RCH_DATA_SFT 0
+#define DL24_RCH_DATA_MASK 0xffffffff
+#define DL24_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL24_LCH_MON */
+#define DL24_LCH_DATA_SFT 0
+#define DL24_LCH_DATA_MASK 0xffffffff
+#define DL24_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL24_CON0 */
+#define DL24_ON_SFT 28
+#define DL24_ON_MASK 0x1
+#define DL24_ON_MASK_SFT (0x1 << 28)
+#define DL24_ONE_HEART_SEL_SFT 22
+#define DL24_ONE_HEART_SEL_MASK 0x3
+#define DL24_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL24_MINLEN_SFT 20
+#define DL24_MINLEN_MASK 0x3
+#define DL24_MINLEN_MASK_SFT (0x3 << 20)
+#define DL24_MAXLEN_SFT 16
+#define DL24_MAXLEN_MASK 0x3
+#define DL24_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL24_SEL_DOMAIN_SFT 13
+#define DL24_SEL_DOMAIN_MASK 0x7
+#define DL24_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL24_SEL_FS_SFT 8
+#define DL24_SEL_FS_MASK 0x1f
+#define DL24_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL24_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL24_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL24_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL24_PBUF_SIZE_SFT 5
+#define DL24_PBUF_SIZE_MASK 0x3
+#define DL24_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL24_MONO_SFT 4
+#define DL24_MONO_MASK 0x1
+#define DL24_MONO_MASK_SFT (0x1 << 4)
+#define DL24_NORMAL_MODE_SFT 3
+#define DL24_NORMAL_MODE_MASK 0x1
+#define DL24_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL24_HALIGN_SFT 2
+#define DL24_HALIGN_MASK 0x1
+#define DL24_HALIGN_MASK_SFT (0x1 << 2)
+#define DL24_HD_MODE_SFT 0
+#define DL24_HD_MODE_MASK 0x3
+#define DL24_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_DL25_BASE_MSB */
+#define DL25_BASE__ADDR_MSB_SFT 0
+#define DL25_BASE__ADDR_MSB_MASK 0x1ff
+#define DL25_BASE__ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL25_BASE */
+#define DL25_BASE_ADDR_SFT 4
+#define DL25_BASE_ADDR_MASK 0xfffffff
+#define DL25_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL25_CUR_MSB */
+#define DL25_CUR_PTR_MSB_SFT 0
+#define DL25_CUR_PTR_MSB_MASK 0x1ff
+#define DL25_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL25_CUR */
+#define DL25_CUR_PTR_SFT 0
+#define DL25_CUR_PTR_MASK 0xffffffff
+#define DL25_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL25_END_MSB */
+#define DL25_END_ADDR_MSB_SFT 0
+#define DL25_END_ADDR_MSB_MASK 0x1ff
+#define DL25_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_DL25_END */
+#define DL25_END_ADDR_SFT 4
+#define DL25_END_ADDR_MASK 0xfffffff
+#define DL25_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_DL25_RCH_MON */
+#define DL25_RCH_DATA_SFT 0
+#define DL25_RCH_DATA_MASK 0xffffffff
+#define DL25_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL25_LCH_MON */
+#define DL25_LCH_DATA_SFT 0
+#define DL25_LCH_DATA_MASK 0xffffffff
+#define DL25_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL25_CON0 */
+#define DL25_ON_SFT 28
+#define DL25_ON_MASK 0x1
+#define DL25_ON_MASK_SFT (0x1 << 28)
+#define DL25_ONE_HEART_SEL_SFT 22
+#define DL25_ONE_HEART_SEL_MASK 0x3
+#define DL25_ONE_HEART_SEL_MASK_SFT (0x3 << 22)
+#define DL25_MINLEN_SFT 20
+#define DL25_MINLEN_MASK 0x3
+#define DL25_MINLEN_MASK_SFT (0x3 << 20)
+#define DL25_MAXLEN_SFT 16
+#define DL25_MAXLEN_MASK 0x3
+#define DL25_MAXLEN_MASK_SFT (0x3 << 16)
+#define DL25_SEL_DOMAIN_SFT 13
+#define DL25_SEL_DOMAIN_MASK 0x7
+#define DL25_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define DL25_SEL_FS_SFT 8
+#define DL25_SEL_FS_MASK 0x1f
+#define DL25_SEL_FS_MASK_SFT (0x1f << 8)
+#define DL25_SW_CLEAR_BUF_EMPTY_SFT 7
+#define DL25_SW_CLEAR_BUF_EMPTY_MASK 0x1
+#define DL25_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 7)
+#define DL25_PBUF_SIZE_SFT 5
+#define DL25_PBUF_SIZE_MASK 0x3
+#define DL25_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL25_MONO_SFT 4
+#define DL25_MONO_MASK 0x1
+#define DL25_MONO_MASK_SFT (0x1 << 4)
+#define DL25_NORMAL_MODE_SFT 3
+#define DL25_NORMAL_MODE_MASK 0x1
+#define DL25_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define DL25_HALIGN_SFT 2
+#define DL25_HALIGN_MASK 0x1
+#define DL25_HALIGN_MASK_SFT (0x1 << 2)
+#define DL25_HD_MODE_SFT 0
+#define DL25_HD_MODE_MASK 0x3
+#define DL25_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL0_BASE_MSB */
+#define VUL0_BASE_ADDR_MSB_SFT 0
+#define VUL0_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL0_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL0_BASE */
+#define VUL0_BASE_ADDR_SFT 4
+#define VUL0_BASE_ADDR_MASK 0xfffffff
+#define VUL0_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL0_CUR_MSB */
+#define VUL0_CUR_PTR_MSB_SFT 0
+#define VUL0_CUR_PTR_MSB_MASK 0x1ff
+#define VUL0_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL0_CUR */
+#define VUL0_CUR_PTR_SFT 0
+#define VUL0_CUR_PTR_MASK 0xffffffff
+#define VUL0_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL0_END_MSB */
+#define VUL0_END_ADDR_MSB_SFT 0
+#define VUL0_END_ADDR_MSB_MASK 0x1ff
+#define VUL0_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL0_END */
+#define VUL0_END_ADDR_SFT 4
+#define VUL0_END_ADDR_MASK 0xfffffff
+#define VUL0_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL0_RCH_MON */
+#define VUL0_RCH_DATA_SFT 0
+#define VUL0_RCH_DATA_MASK 0xffffffff
+#define VUL0_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL0_LCH_MON */
+#define VUL0_LCH_DATA_SFT 0
+#define VUL0_LCH_DATA_MASK 0xffffffff
+#define VUL0_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL0_CON0 */
+#define VUL0_ON_SFT 28
+#define VUL0_ON_MASK 0x1
+#define VUL0_ON_MASK_SFT (0x1 << 28)
+#define VUL0_MINLEN_SFT 20
+#define VUL0_MINLEN_MASK 0x3
+#define VUL0_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL0_MAXLEN_SFT 16
+#define VUL0_MAXLEN_MASK 0x3
+#define VUL0_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL0_SEL_DOMAIN_SFT 13
+#define VUL0_SEL_DOMAIN_MASK 0x7
+#define VUL0_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL0_SEL_FS_SFT 8
+#define VUL0_SEL_FS_MASK 0x1f
+#define VUL0_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL0_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL0_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL0_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL0_WR_SIGN_SFT 6
+#define VUL0_WR_SIGN_MASK 0x1
+#define VUL0_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL0_R_MONO_SFT 5
+#define VUL0_R_MONO_MASK 0x1
+#define VUL0_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL0_MONO_SFT 4
+#define VUL0_MONO_MASK 0x1
+#define VUL0_MONO_MASK_SFT (0x1 << 4)
+#define VUL0_NORMAL_MODE_SFT 3
+#define VUL0_NORMAL_MODE_MASK 0x1
+#define VUL0_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL0_HALIGN_SFT 2
+#define VUL0_HALIGN_MASK 0x1
+#define VUL0_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL0_HD_MODE_SFT 0
+#define VUL0_HD_MODE_MASK 0x3
+#define VUL0_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL1_BASE_MSB */
+#define VUL1_BASE_ADDR_MSB_SFT 0
+#define VUL1_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL1_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL1_BASE */
+#define VUL1_BASE_ADDR_SFT 4
+#define VUL1_BASE_ADDR_MASK 0xfffffff
+#define VUL1_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL1_CUR_MSB */
+#define VUL1_CUR_PTR_MSB_SFT 0
+#define VUL1_CUR_PTR_MSB_MASK 0x1ff
+#define VUL1_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL1_CUR */
+#define VUL1_CUR_PTR_SFT 0
+#define VUL1_CUR_PTR_MASK 0xffffffff
+#define VUL1_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL1_END_MSB */
+#define VUL1_END_ADDR_MSB_SFT 0
+#define VUL1_END_ADDR_MSB_MASK 0x1ff
+#define VUL1_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL1_END */
+#define VUL1_END_ADDR_SFT 4
+#define VUL1_END_ADDR_MASK 0xfffffff
+#define VUL1_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL1_RCH_MON */
+#define VUL1_RCH_DATA_SFT 0
+#define VUL1_RCH_DATA_MASK 0xffffffff
+#define VUL1_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL1_LCH_MON */
+#define VUL1_LCH_DATA_SFT 0
+#define VUL1_LCH_DATA_MASK 0xffffffff
+#define VUL1_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL1_CON0 */
+#define VUL1_ON_SFT 28
+#define VUL1_ON_MASK 0x1
+#define VUL1_ON_MASK_SFT (0x1 << 28)
+#define VUL1_MINLEN_SFT 20
+#define VUL1_MINLEN_MASK 0x3
+#define VUL1_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL1_MAXLEN_SFT 16
+#define VUL1_MAXLEN_MASK 0x3
+#define VUL1_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL1_SEL_DOMAIN_SFT 13
+#define VUL1_SEL_DOMAIN_MASK 0x7
+#define VUL1_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL1_SEL_FS_SFT 8
+#define VUL1_SEL_FS_MASK 0x1f
+#define VUL1_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL1_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL1_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL1_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL1_WR_SIGN_SFT 6
+#define VUL1_WR_SIGN_MASK 0x1
+#define VUL1_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL1_R_MONO_SFT 5
+#define VUL1_R_MONO_MASK 0x1
+#define VUL1_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL1_MONO_SFT 4
+#define VUL1_MONO_MASK 0x1
+#define VUL1_MONO_MASK_SFT (0x1 << 4)
+#define VUL1_NORMAL_MODE_SFT 3
+#define VUL1_NORMAL_MODE_MASK 0x1
+#define VUL1_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL1_HALIGN_SFT 2
+#define VUL1_HALIGN_MASK 0x1
+#define VUL1_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL1_HD_MODE_SFT 0
+#define VUL1_HD_MODE_MASK 0x3
+#define VUL1_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL1_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL2_BASE_MSB */
+#define VUL2_BASE_ADDR_MSB_SFT 0
+#define VUL2_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL2_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL2_BASE */
+#define VUL2_BASE_ADDR_SFT 4
+#define VUL2_BASE_ADDR_MASK 0xfffffff
+#define VUL2_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL2_CUR_MSB */
+#define VUL2_CUR_PTR_MSB_SFT 0
+#define VUL2_CUR_PTR_MSB_MASK 0x1ff
+#define VUL2_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL2_CUR */
+#define VUL2_CUR_PTR_SFT 0
+#define VUL2_CUR_PTR_MASK 0xffffffff
+#define VUL2_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL2_END_MSB */
+#define VUL2_END_ADDR_MSB_SFT 0
+#define VUL2_END_ADDR_MSB_MASK 0x1ff
+#define VUL2_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL2_END */
+#define VUL2_END_ADDR_SFT 4
+#define VUL2_END_ADDR_MASK 0xfffffff
+#define VUL2_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL2_RCH_MON */
+#define VUL2_RCH_DATA_SFT 0
+#define VUL2_RCH_DATA_MASK 0xffffffff
+#define VUL2_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL2_LCH_MON */
+#define VUL2_LCH_DATA_SFT 0
+#define VUL2_LCH_DATA_MASK 0xffffffff
+#define VUL2_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL2_CON0 */
+#define VUL2_ON_SFT 28
+#define VUL2_ON_MASK 0x1
+#define VUL2_ON_MASK_SFT (0x1 << 28)
+#define VUL2_MINLEN_SFT 20
+#define VUL2_MINLEN_MASK 0x3
+#define VUL2_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL2_MAXLEN_SFT 16
+#define VUL2_MAXLEN_MASK 0x3
+#define VUL2_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL2_SEL_DOMAIN_SFT 13
+#define VUL2_SEL_DOMAIN_MASK 0x7
+#define VUL2_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL2_SEL_FS_SFT 8
+#define VUL2_SEL_FS_MASK 0x1f
+#define VUL2_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL2_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL2_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL2_WR_SIGN_SFT 6
+#define VUL2_WR_SIGN_MASK 0x1
+#define VUL2_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL2_R_MONO_SFT 5
+#define VUL2_R_MONO_MASK 0x1
+#define VUL2_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL2_MONO_SFT 4
+#define VUL2_MONO_MASK 0x1
+#define VUL2_MONO_MASK_SFT (0x1 << 4)
+#define VUL2_NORMAL_MODE_SFT 3
+#define VUL2_NORMAL_MODE_MASK 0x1
+#define VUL2_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL2_HALIGN_SFT 2
+#define VUL2_HALIGN_MASK 0x1
+#define VUL2_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL2_HD_MODE_SFT 0
+#define VUL2_HD_MODE_MASK 0x3
+#define VUL2_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL2_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL3_BASE_MSB */
+#define VUL3_BASE_ADDR_MSB_SFT 0
+#define VUL3_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL3_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL3_BASE */
+#define VUL3_BASE_ADDR_SFT 4
+#define VUL3_BASE_ADDR_MASK 0xfffffff
+#define VUL3_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL3_CUR_MSB */
+#define VUL3_CUR_PTR_MSB_SFT 0
+#define VUL3_CUR_PTR_MSB_MASK 0x1ff
+#define VUL3_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL3_CUR */
+#define VUL3_CUR_PTR_SFT 0
+#define VUL3_CUR_PTR_MASK 0xffffffff
+#define VUL3_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL3_END_MSB */
+#define VUL3_END_ADDR_MSB_SFT 0
+#define VUL3_END_ADDR_MSB_MASK 0x1ff
+#define VUL3_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL3_END */
+#define VUL3_END_ADDR_SFT 4
+#define VUL3_END_ADDR_MASK 0xfffffff
+#define VUL3_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL3_RCH_MON */
+#define VUL3_RCH_DATA_SFT 0
+#define VUL3_RCH_DATA_MASK 0xffffffff
+#define VUL3_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL3_LCH_MON */
+#define VUL3_LCH_DATA_SFT 0
+#define VUL3_LCH_DATA_MASK 0xffffffff
+#define VUL3_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL3_CON0 */
+#define VUL3_ON_SFT 28
+#define VUL3_ON_MASK 0x1
+#define VUL3_ON_MASK_SFT (0x1 << 28)
+#define VUL3_MINLEN_SFT 20
+#define VUL3_MINLEN_MASK 0x3
+#define VUL3_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL3_MAXLEN_SFT 16
+#define VUL3_MAXLEN_MASK 0x3
+#define VUL3_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL3_SEL_DOMAIN_SFT 13
+#define VUL3_SEL_DOMAIN_MASK 0x7
+#define VUL3_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL3_SEL_FS_SFT 8
+#define VUL3_SEL_FS_MASK 0x1f
+#define VUL3_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL3_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL3_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL3_WR_SIGN_SFT 6
+#define VUL3_WR_SIGN_MASK 0x1
+#define VUL3_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL3_R_MONO_SFT 5
+#define VUL3_R_MONO_MASK 0x1
+#define VUL3_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL3_MONO_SFT 4
+#define VUL3_MONO_MASK 0x1
+#define VUL3_MONO_MASK_SFT (0x1 << 4)
+#define VUL3_NORMAL_MODE_SFT 3
+#define VUL3_NORMAL_MODE_MASK 0x1
+#define VUL3_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL3_HALIGN_SFT 2
+#define VUL3_HALIGN_MASK 0x1
+#define VUL3_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL3_HD_MODE_SFT 0
+#define VUL3_HD_MODE_MASK 0x3
+#define VUL3_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL3_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL4_BASE_MSB */
+#define VUL4_BASE_ADDR_MSB_SFT 0
+#define VUL4_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL4_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL4_BASE */
+#define VUL4_BASE_ADDR_SFT 4
+#define VUL4_BASE_ADDR_MASK 0xfffffff
+#define VUL4_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL4_CUR_MSB */
+#define VUL4_CUR_PTR_MSB_SFT 0
+#define VUL4_CUR_PTR_MSB_MASK 0x1ff
+#define VUL4_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL4_CUR */
+#define VUL4_CUR_PTR_SFT 0
+#define VUL4_CUR_PTR_MASK 0xffffffff
+#define VUL4_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL4_END_MSB */
+#define VUL4_END_ADDR_MSB_SFT 0
+#define VUL4_END_ADDR_MSB_MASK 0x1ff
+#define VUL4_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL4_END */
+#define VUL4_END_ADDR_SFT 4
+#define VUL4_END_ADDR_MASK 0xfffffff
+#define VUL4_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL4_RCH_MON */
+#define VUL4_RCH_DATA_SFT 0
+#define VUL4_RCH_DATA_MASK 0xffffffff
+#define VUL4_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL4_LCH_MON */
+#define VUL4_LCH_DATA_SFT 0
+#define VUL4_LCH_DATA_MASK 0xffffffff
+#define VUL4_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL4_CON0 */
+#define VUL4_ON_SFT 28
+#define VUL4_ON_MASK 0x1
+#define VUL4_ON_MASK_SFT (0x1 << 28)
+#define VUL4_MINLEN_SFT 20
+#define VUL4_MINLEN_MASK 0x3
+#define VUL4_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL4_MAXLEN_SFT 16
+#define VUL4_MAXLEN_MASK 0x3
+#define VUL4_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL4_SEL_DOMAIN_SFT 13
+#define VUL4_SEL_DOMAIN_MASK 0x7
+#define VUL4_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL4_SEL_FS_SFT 8
+#define VUL4_SEL_FS_MASK 0x1f
+#define VUL4_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL4_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL4_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL4_WR_SIGN_SFT 6
+#define VUL4_WR_SIGN_MASK 0x1
+#define VUL4_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL4_R_MONO_SFT 5
+#define VUL4_R_MONO_MASK 0x1
+#define VUL4_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL4_MONO_SFT 4
+#define VUL4_MONO_MASK 0x1
+#define VUL4_MONO_MASK_SFT (0x1 << 4)
+#define VUL4_NORMAL_MODE_SFT 3
+#define VUL4_NORMAL_MODE_MASK 0x1
+#define VUL4_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL4_HALIGN_SFT 2
+#define VUL4_HALIGN_MASK 0x1
+#define VUL4_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL4_HD_MODE_SFT 0
+#define VUL4_HD_MODE_MASK 0x3
+#define VUL4_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL4_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL5_BASE_MSB */
+#define VUL5_BASE_ADDR_MSB_SFT 0
+#define VUL5_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL5_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL5_BASE */
+#define VUL5_BASE_ADDR_SFT 4
+#define VUL5_BASE_ADDR_MASK 0xfffffff
+#define VUL5_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL5_CUR_MSB */
+#define VUL5_CUR_PTR_MSB_SFT 0
+#define VUL5_CUR_PTR_MSB_MASK 0x1ff
+#define VUL5_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL5_CUR */
+#define VUL5_CUR_PTR_SFT 0
+#define VUL5_CUR_PTR_MASK 0xffffffff
+#define VUL5_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL5_END_MSB */
+#define VUL5_END_ADDR_MSB_SFT 0
+#define VUL5_END_ADDR_MSB_MASK 0x1ff
+#define VUL5_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL5_END */
+#define VUL5_END_ADDR_SFT 4
+#define VUL5_END_ADDR_MASK 0xfffffff
+#define VUL5_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL5_RCH_MON */
+#define VUL5_RCH_DATA_SFT 0
+#define VUL5_RCH_DATA_MASK 0xffffffff
+#define VUL5_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL5_LCH_MON */
+#define VUL5_LCH_DATA_SFT 0
+#define VUL5_LCH_DATA_MASK 0xffffffff
+#define VUL5_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL5_CON0 */
+#define VUL5_ON_SFT 28
+#define VUL5_ON_MASK 0x1
+#define VUL5_ON_MASK_SFT (0x1 << 28)
+#define VUL5_MINLEN_SFT 20
+#define VUL5_MINLEN_MASK 0x3
+#define VUL5_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL5_MAXLEN_SFT 16
+#define VUL5_MAXLEN_MASK 0x3
+#define VUL5_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL5_SEL_DOMAIN_SFT 13
+#define VUL5_SEL_DOMAIN_MASK 0x7
+#define VUL5_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL5_SEL_FS_SFT 8
+#define VUL5_SEL_FS_MASK 0x1f
+#define VUL5_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL5_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL5_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL5_WR_SIGN_SFT 6
+#define VUL5_WR_SIGN_MASK 0x1
+#define VUL5_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL5_R_MONO_SFT 5
+#define VUL5_R_MONO_MASK 0x1
+#define VUL5_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL5_MONO_SFT 4
+#define VUL5_MONO_MASK 0x1
+#define VUL5_MONO_MASK_SFT (0x1 << 4)
+#define VUL5_NORMAL_MODE_SFT 3
+#define VUL5_NORMAL_MODE_MASK 0x1
+#define VUL5_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL5_HALIGN_SFT 2
+#define VUL5_HALIGN_MASK 0x1
+#define VUL5_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL5_HD_MODE_SFT 0
+#define VUL5_HD_MODE_MASK 0x3
+#define VUL5_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL5_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL6_BASE_MSB */
+#define VUL6_BASE_ADDR_MSB_SFT 0
+#define VUL6_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL6_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL6_BASE */
+#define VUL6_BASE_ADDR_SFT 4
+#define VUL6_BASE_ADDR_MASK 0xfffffff
+#define VUL6_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL6_CUR_MSB */
+#define VUL6_CUR_PTR_MSB_SFT 0
+#define VUL6_CUR_PTR_MSB_MASK 0x1ff
+#define VUL6_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL6_CUR */
+#define VUL6_CUR_PTR_SFT 0
+#define VUL6_CUR_PTR_MASK 0xffffffff
+#define VUL6_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL6_END_MSB */
+#define VUL6_END_ADDR_MSB_SFT 0
+#define VUL6_END_ADDR_MSB_MASK 0x1ff
+#define VUL6_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL6_END */
+#define VUL6_END_ADDR_SFT 4
+#define VUL6_END_ADDR_MASK 0xfffffff
+#define VUL6_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL6_RCH_MON */
+#define VUL6_RCH_DATA_SFT 0
+#define VUL6_RCH_DATA_MASK 0xffffffff
+#define VUL6_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL6_LCH_MON */
+#define VUL6_LCH_DATA_SFT 0
+#define VUL6_LCH_DATA_MASK 0xffffffff
+#define VUL6_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL6_CON0 */
+#define VUL6_ON_SFT 28
+#define VUL6_ON_MASK 0x1
+#define VUL6_ON_MASK_SFT (0x1 << 28)
+#define VUL6_MINLEN_SFT 20
+#define VUL6_MINLEN_MASK 0x3
+#define VUL6_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL6_MAXLEN_SFT 16
+#define VUL6_MAXLEN_MASK 0x3
+#define VUL6_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL6_SEL_DOMAIN_SFT 13
+#define VUL6_SEL_DOMAIN_MASK 0x7
+#define VUL6_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL6_SEL_FS_SFT 8
+#define VUL6_SEL_FS_MASK 0x1f
+#define VUL6_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL6_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL6_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL6_WR_SIGN_SFT 6
+#define VUL6_WR_SIGN_MASK 0x1
+#define VUL6_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL6_R_MONO_SFT 5
+#define VUL6_R_MONO_MASK 0x1
+#define VUL6_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL6_MONO_SFT 4
+#define VUL6_MONO_MASK 0x1
+#define VUL6_MONO_MASK_SFT (0x1 << 4)
+#define VUL6_NORMAL_MODE_SFT 3
+#define VUL6_NORMAL_MODE_MASK 0x1
+#define VUL6_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL6_HALIGN_SFT 2
+#define VUL6_HALIGN_MASK 0x1
+#define VUL6_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL6_HD_MODE_SFT 0
+#define VUL6_HD_MODE_MASK 0x3
+#define VUL6_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL6_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL7_BASE_MSB */
+#define VUL7_BASE_ADDR_MSB_SFT 0
+#define VUL7_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL7_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL7_BASE */
+#define VUL7_BASE_ADDR_SFT 4
+#define VUL7_BASE_ADDR_MASK 0xfffffff
+#define VUL7_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL7_CUR_MSB */
+#define VUL7_CUR_PTR_MSB_SFT 0
+#define VUL7_CUR_PTR_MSB_MASK 0x1ff
+#define VUL7_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL7_CUR */
+#define VUL7_CUR_PTR_SFT 0
+#define VUL7_CUR_PTR_MASK 0xffffffff
+#define VUL7_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL7_END_MSB */
+#define VUL7_END_ADDR_MSB_SFT 0
+#define VUL7_END_ADDR_MSB_MASK 0x1ff
+#define VUL7_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL7_END */
+#define VUL7_END_ADDR_SFT 4
+#define VUL7_END_ADDR_MASK 0xfffffff
+#define VUL7_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL7_RCH_MON */
+#define VUL7_RCH_DATA_SFT 0
+#define VUL7_RCH_DATA_MASK 0xffffffff
+#define VUL7_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL7_LCH_MON */
+#define VUL7_LCH_DATA_SFT 0
+#define VUL7_LCH_DATA_MASK 0xffffffff
+#define VUL7_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL7_CON0 */
+#define VUL7_ON_SFT 28
+#define VUL7_ON_MASK 0x1
+#define VUL7_ON_MASK_SFT (0x1 << 28)
+#define VUL7_MINLEN_SFT 20
+#define VUL7_MINLEN_MASK 0x3
+#define VUL7_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL7_MAXLEN_SFT 16
+#define VUL7_MAXLEN_MASK 0x3
+#define VUL7_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL7_SEL_DOMAIN_SFT 13
+#define VUL7_SEL_DOMAIN_MASK 0x7
+#define VUL7_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL7_SEL_FS_SFT 8
+#define VUL7_SEL_FS_MASK 0x1f
+#define VUL7_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL7_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL7_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL7_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL7_WR_SIGN_SFT 6
+#define VUL7_WR_SIGN_MASK 0x1
+#define VUL7_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL7_R_MONO_SFT 5
+#define VUL7_R_MONO_MASK 0x1
+#define VUL7_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL7_MONO_SFT 4
+#define VUL7_MONO_MASK 0x1
+#define VUL7_MONO_MASK_SFT (0x1 << 4)
+#define VUL7_NORMAL_MODE_SFT 3
+#define VUL7_NORMAL_MODE_MASK 0x1
+#define VUL7_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL7_HALIGN_SFT 2
+#define VUL7_HALIGN_MASK 0x1
+#define VUL7_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL7_HD_MODE_SFT 0
+#define VUL7_HD_MODE_MASK 0x3
+#define VUL7_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL7_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL8_BASE_MSB */
+#define VUL8_BASE_ADDR_MSB_SFT 0
+#define VUL8_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL8_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL8_BASE */
+#define VUL8_BASE_ADDR_SFT 4
+#define VUL8_BASE_ADDR_MASK 0xfffffff
+#define VUL8_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL8_CUR_MSB */
+#define VUL8_CUR_PTR_MSB_SFT 0
+#define VUL8_CUR_PTR_MSB_MASK 0x1ff
+#define VUL8_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL8_CUR */
+#define VUL8_CUR_PTR_SFT 0
+#define VUL8_CUR_PTR_MASK 0xffffffff
+#define VUL8_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL8_END_MSB */
+#define VUL8_END_ADDR_MSB_SFT 0
+#define VUL8_END_ADDR_MSB_MASK 0x1ff
+#define VUL8_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL8_END */
+#define VUL8_END_ADDR_SFT 4
+#define VUL8_END_ADDR_MASK 0xfffffff
+#define VUL8_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL8_RCH_MON */
+#define VUL8_RCH_DATA_SFT 0
+#define VUL8_RCH_DATA_MASK 0xffffffff
+#define VUL8_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL8_LCH_MON */
+#define VUL8_LCH_DATA_SFT 0
+#define VUL8_LCH_DATA_MASK 0xffffffff
+#define VUL8_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL8_CON0 */
+#define VUL8_ON_SFT 28
+#define VUL8_ON_MASK 0x1
+#define VUL8_ON_MASK_SFT (0x1 << 28)
+#define VUL8_MINLEN_SFT 20
+#define VUL8_MINLEN_MASK 0x3
+#define VUL8_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL8_MAXLEN_SFT 16
+#define VUL8_MAXLEN_MASK 0x3
+#define VUL8_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL8_SEL_DOMAIN_SFT 13
+#define VUL8_SEL_DOMAIN_MASK 0x7
+#define VUL8_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL8_SEL_FS_SFT 8
+#define VUL8_SEL_FS_MASK 0x1f
+#define VUL8_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL8_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL8_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL8_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL8_WR_SIGN_SFT 6
+#define VUL8_WR_SIGN_MASK 0x1
+#define VUL8_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL8_R_MONO_SFT 5
+#define VUL8_R_MONO_MASK 0x1
+#define VUL8_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL8_MONO_SFT 4
+#define VUL8_MONO_MASK 0x1
+#define VUL8_MONO_MASK_SFT (0x1 << 4)
+#define VUL8_NORMAL_MODE_SFT 3
+#define VUL8_NORMAL_MODE_MASK 0x1
+#define VUL8_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL8_HALIGN_SFT 2
+#define VUL8_HALIGN_MASK 0x1
+#define VUL8_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL8_HD_MODE_SFT 0
+#define VUL8_HD_MODE_MASK 0x3
+#define VUL8_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL8_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL9_BASE_MSB */
+#define VUL9_BASE_ADDR_MSB_SFT 0
+#define VUL9_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL9_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL9_BASE */
+#define VUL9_BASE_ADDR_SFT 4
+#define VUL9_BASE_ADDR_MASK 0xfffffff
+#define VUL9_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL9_CUR_MSB */
+#define VUL9_CUR_PTR_MSB_SFT 0
+#define VUL9_CUR_PTR_MSB_MASK 0x1ff
+#define VUL9_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL9_CUR */
+#define VUL9_CUR_PTR_SFT 0
+#define VUL9_CUR_PTR_MASK 0xffffffff
+#define VUL9_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL9_END_MSB */
+#define VUL9_END_ADDR_MSB_SFT 0
+#define VUL9_END_ADDR_MSB_MASK 0x1ff
+#define VUL9_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL9_END */
+#define VUL9_END_ADDR_SFT 4
+#define VUL9_END_ADDR_MASK 0xfffffff
+#define VUL9_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL9_RCH_MON */
+#define VUL9_RCH_DATA_SFT 0
+#define VUL9_RCH_DATA_MASK 0xffffffff
+#define VUL9_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL9_LCH_MON */
+#define VUL9_LCH_DATA_SFT 0
+#define VUL9_LCH_DATA_MASK 0xffffffff
+#define VUL9_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL9_CON0 */
+#define VUL9_ON_SFT 28
+#define VUL9_ON_MASK 0x1
+#define VUL9_ON_MASK_SFT (0x1 << 28)
+#define VUL9_MINLEN_SFT 20
+#define VUL9_MINLEN_MASK 0x3
+#define VUL9_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL9_MAXLEN_SFT 16
+#define VUL9_MAXLEN_MASK 0x3
+#define VUL9_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL9_SEL_DOMAIN_SFT 13
+#define VUL9_SEL_DOMAIN_MASK 0x7
+#define VUL9_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL9_SEL_FS_SFT 8
+#define VUL9_SEL_FS_MASK 0x1f
+#define VUL9_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL9_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL9_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL9_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL9_WR_SIGN_SFT 6
+#define VUL9_WR_SIGN_MASK 0x1
+#define VUL9_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL9_R_MONO_SFT 5
+#define VUL9_R_MONO_MASK 0x1
+#define VUL9_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL9_MONO_SFT 4
+#define VUL9_MONO_MASK 0x1
+#define VUL9_MONO_MASK_SFT (0x1 << 4)
+#define VUL9_NORMAL_MODE_SFT 3
+#define VUL9_NORMAL_MODE_MASK 0x1
+#define VUL9_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL9_HALIGN_SFT 2
+#define VUL9_HALIGN_MASK 0x1
+#define VUL9_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL9_HD_MODE_SFT 0
+#define VUL9_HD_MODE_MASK 0x3
+#define VUL9_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL9_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL10_BASE_MSB */
+#define VUL10_BASE_ADDR_MSB_SFT 0
+#define VUL10_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL10_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL10_BASE */
+#define VUL10_BASE_ADDR_SFT 4
+#define VUL10_BASE_ADDR_MASK 0xfffffff
+#define VUL10_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL10_CUR_MSB */
+#define VUL10_CUR_PTR_MSB_SFT 0
+#define VUL10_CUR_PTR_MSB_MASK 0x1ff
+#define VUL10_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL10_CUR */
+#define VUL10_CUR_PTR_SFT 0
+#define VUL10_CUR_PTR_MASK 0xffffffff
+#define VUL10_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL10_END_MSB */
+#define VUL10_END_ADDR_MSB_SFT 0
+#define VUL10_END_ADDR_MSB_MASK 0x1ff
+#define VUL10_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL10_END */
+#define VUL10_END_ADDR_SFT 4
+#define VUL10_END_ADDR_MASK 0xfffffff
+#define VUL10_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL10_RCH_MON */
+#define VUL10_RCH_DATA_SFT 0
+#define VUL10_RCH_DATA_MASK 0xffffffff
+#define VUL10_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL10_LCH_MON */
+#define VUL10_LCH_DATA_SFT 0
+#define VUL10_LCH_DATA_MASK 0xffffffff
+#define VUL10_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL10_CON0 */
+#define VUL10_ON_SFT 28
+#define VUL10_ON_MASK 0x1
+#define VUL10_ON_MASK_SFT (0x1 << 28)
+#define VUL10_MINLEN_SFT 20
+#define VUL10_MINLEN_MASK 0x3
+#define VUL10_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL10_MAXLEN_SFT 16
+#define VUL10_MAXLEN_MASK 0x3
+#define VUL10_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL10_SEL_DOMAIN_SFT 13
+#define VUL10_SEL_DOMAIN_MASK 0x7
+#define VUL10_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL10_SEL_FS_SFT 8
+#define VUL10_SEL_FS_MASK 0x1f
+#define VUL10_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL10_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL10_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL10_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL10_WR_SIGN_SFT 6
+#define VUL10_WR_SIGN_MASK 0x1
+#define VUL10_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL10_R_MONO_SFT 5
+#define VUL10_R_MONO_MASK 0x1
+#define VUL10_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL10_MONO_SFT 4
+#define VUL10_MONO_MASK 0x1
+#define VUL10_MONO_MASK_SFT (0x1 << 4)
+#define VUL10_NORMAL_MODE_SFT 3
+#define VUL10_NORMAL_MODE_MASK 0x1
+#define VUL10_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL10_HALIGN_SFT 2
+#define VUL10_HALIGN_MASK 0x1
+#define VUL10_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL10_HD_MODE_SFT 0
+#define VUL10_HD_MODE_MASK 0x3
+#define VUL10_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL10_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL24_BASE_MSB */
+#define VUL24_BASE_ADDR_MSB_SFT 0
+#define VUL24_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL24_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL24_BASE */
+#define VUL24_BASE_ADDR_SFT 4
+#define VUL24_BASE_ADDR_MASK 0xfffffff
+#define VUL24_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL24_CUR_MSB */
+#define VUL24_CUR_PTR_MSB_SFT 0
+#define VUL24_CUR_PTR_MSB_MASK 0x1ff
+#define VUL24_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL24_CUR */
+#define VUL24_CUR_PTR_SFT 0
+#define VUL24_CUR_PTR_MASK 0xffffffff
+#define VUL24_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL24_END_MSB */
+#define VUL24_END_ADDR_MSB_SFT 0
+#define VUL24_END_ADDR_MSB_MASK 0x1ff
+#define VUL24_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL24_END */
+#define VUL24_END_ADDR_SFT 4
+#define VUL24_END_ADDR_MASK 0xfffffff
+#define VUL24_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL24_CON0 */
+#define OUT_ON_USE_VUL24_SFT 29
+#define OUT_ON_USE_VUL24_MASK 0x1
+#define OUT_ON_USE_VUL24_MASK_SFT (0x1 << 29)
+#define VUL24_ON_SFT 28
+#define VUL24_ON_MASK 0x1
+#define VUL24_ON_MASK_SFT (0x1 << 28)
+#define VUL24_MINLEN_SFT 20
+#define VUL24_MINLEN_MASK 0x3
+#define VUL24_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL24_MAXLEN_SFT 16
+#define VUL24_MAXLEN_MASK 0x3
+#define VUL24_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL24_SEL_DOMAIN_SFT 13
+#define VUL24_SEL_DOMAIN_MASK 0x7
+#define VUL24_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL24_SEL_FS_SFT 8
+#define VUL24_SEL_FS_MASK 0x1f
+#define VUL24_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL24_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL24_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL24_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL24_WR_SIGN_SFT 6
+#define VUL24_WR_SIGN_MASK 0x1
+#define VUL24_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL24_R_MONO_SFT 5
+#define VUL24_R_MONO_MASK 0x1
+#define VUL24_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL24_MONO_SFT 4
+#define VUL24_MONO_MASK 0x1
+#define VUL24_MONO_MASK_SFT (0x1 << 4)
+#define VUL24_NORMAL_MODE_SFT 3
+#define VUL24_NORMAL_MODE_MASK 0x1
+#define VUL24_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL24_HALIGN_SFT 2
+#define VUL24_HALIGN_MASK 0x1
+#define VUL24_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL24_HD_MODE_SFT 0
+#define VUL24_HD_MODE_MASK 0x3
+#define VUL24_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL24_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL25_BASE_MSB */
+#define VUL25_BASE_ADDR_MSB_SFT 0
+#define VUL25_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL25_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL25_BASE */
+#define VUL25_BASE_ADDR_SFT 4
+#define VUL25_BASE_ADDR_MASK 0xfffffff
+#define VUL25_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL25_CUR_MSB */
+#define VUL25_CUR_PTR_MSB_SFT 0
+#define VUL25_CUR_PTR_MSB_MASK 0x1ff
+#define VUL25_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL25_CUR */
+#define VUL25_CUR_PTR_SFT 0
+#define VUL25_CUR_PTR_MASK 0xffffffff
+#define VUL25_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL25_END_MSB */
+#define VUL25_END_ADDR_MSB_SFT 0
+#define VUL25_END_ADDR_MSB_MASK 0x1ff
+#define VUL25_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL25_END */
+#define VUL25_END_ADDR_SFT 4
+#define VUL25_END_ADDR_MASK 0xfffffff
+#define VUL25_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL25_CON0 */
+#define OUT_ON_USE_VUL25_SFT 29
+#define OUT_ON_USE_VUL25_MASK 0x1
+#define OUT_ON_USE_VUL25_MASK_SFT (0x1 << 29)
+#define VUL25_ON_SFT 28
+#define VUL25_ON_MASK 0x1
+#define VUL25_ON_MASK_SFT (0x1 << 28)
+#define VUL25_MINLEN_SFT 20
+#define VUL25_MINLEN_MASK 0x3
+#define VUL25_MINLEN_MASK_SFT (0x3 << 20)
+#define VUL25_MAXLEN_SFT 16
+#define VUL25_MAXLEN_MASK 0x3
+#define VUL25_MAXLEN_MASK_SFT (0x3 << 16)
+#define VUL25_SEL_DOMAIN_SFT 13
+#define VUL25_SEL_DOMAIN_MASK 0x7
+#define VUL25_SEL_DOMAIN_MASK_SFT (0x7 << 13)
+#define VUL25_SEL_FS_SFT 8
+#define VUL25_SEL_FS_MASK 0x1f
+#define VUL25_SEL_FS_MASK_SFT (0x1f << 8)
+#define VUL25_SW_CLEAR_BUF_FULL_SFT 7
+#define VUL25_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL25_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 7)
+#define VUL25_WR_SIGN_SFT 6
+#define VUL25_WR_SIGN_MASK 0x1
+#define VUL25_WR_SIGN_MASK_SFT (0x1 << 6)
+#define VUL25_R_MONO_SFT 5
+#define VUL25_R_MONO_MASK 0x1
+#define VUL25_R_MONO_MASK_SFT (0x1 << 5)
+#define VUL25_MONO_SFT 4
+#define VUL25_MONO_MASK 0x1
+#define VUL25_MONO_MASK_SFT (0x1 << 4)
+#define VUL25_NORMAL_MODE_SFT 3
+#define VUL25_NORMAL_MODE_MASK 0x1
+#define VUL25_NORMAL_MODE_MASK_SFT (0x1 << 3)
+#define VUL25_HALIGN_SFT 2
+#define VUL25_HALIGN_MASK 0x1
+#define VUL25_HALIGN_MASK_SFT (0x1 << 2)
+#define VUL25_HD_MODE_SFT 0
+#define VUL25_HD_MODE_MASK 0x3
+#define VUL25_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL25_MON0 */
+#define MEM_HW_WEN_SFT 20
+#define MEM_HW_WEN_MASK 0xf
+#define MEM_HW_WEN_MASK_SFT (0xf << 20)
+#define MEM_REQ_PENDING_SFT 19
+#define MEM_REQ_PENDING_MASK 0x1
+#define MEM_REQ_PENDING_MASK_SFT (0x1 << 19)
+#define BUF_FULL_SFT 18
+#define BUF_FULL_MASK 0x1
+#define BUF_FULL_MASK_SFT (0x1 << 18)
+#define ENABLE_SYNC_MEM_SFT 17
+#define ENABLE_SYNC_MEM_MASK 0x1
+#define ENABLE_SYNC_MEM_MASK_SFT (0x1 << 17)
+#define ENABLE_SYNC_AGENT_SFT 16
+#define ENABLE_SYNC_AGENT_MASK 0x1
+#define ENABLE_SYNC_AGENT_MASK_SFT (0x1 << 16)
+#define RESERVED_02_SFT 6
+#define RESERVED_02_MASK 0x3ff
+#define RESERVED_02_MASK_SFT (0x3ff << 6)
+#define MEM_ADDR_DIFF_SFT 0
+#define MEM_ADDR_DIFF_MASK 0x3f
+#define MEM_ADDR_DIFF_MASK_SFT (0x3f << 0)
+
+/* AFE_VUL_CM0_BASE_MSB */
+#define VUL_CM0_BASE_ADDR_MSB_SFT 0
+#define VUL_CM0_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL_CM0_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL_CM0_BASE */
+#define VUL_CM0_BASE_ADDR_SFT 4
+#define VUL_CM0_BASE_ADDR_MASK 0xfffffff
+#define VUL_CM0_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL_CM0_CUR_MSB */
+#define VUL_CM0_CUR_PTR_MSB_SFT 0
+#define VUL_CM0_CUR_PTR_MSB_MASK 0x1ff
+#define VUL_CM0_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL_CM0_CUR */
+#define VUL_CM0_CUR_PTR_SFT 0
+#define VUL_CM0_CUR_PTR_MASK 0xffffffff
+#define VUL_CM0_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL_CM0_END_MSB */
+#define VUL_CM0_END_ADDR_MSB_SFT 0
+#define VUL_CM0_END_ADDR_MSB_MASK 0x1ff
+#define VUL_CM0_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL_CM0_END */
+#define VUL_CM0_END_ADDR_SFT 4
+#define VUL_CM0_END_ADDR_MASK 0xfffffff
+#define VUL_CM0_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL_CM0_CON0 */
+#define VUL_CM0_ON_SFT 28
+#define VUL_CM0_ON_MASK 0x1
+#define VUL_CM0_ON_MASK_SFT (0x1 << 28)
+#define VUL_CM0_REG_CH_SHIFT_MODE_SFT 26
+#define VUL_CM0_REG_CH_SHIFT_MODE_MASK 0x1
+#define VUL_CM0_REG_CH_SHIFT_MODE_MASK_SFT (0x1 << 26)
+#define VUL_CM0_RG_FORCE_NO_MASK_EXTRA_SFT 25
+#define VUL_CM0_RG_FORCE_NO_MASK_EXTRA_MASK 0x1
+#define VUL_CM0_RG_FORCE_NO_MASK_EXTRA_MASK_SFT (0x1 << 25)
+#define VUL_CM0_SW_CLEAR_BUF_FULL_SFT 24
+#define VUL_CM0_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL_CM0_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 24)
+#define VUL_CM0_ULTRA_TH_SFT 20
+#define VUL_CM0_ULTRA_TH_MASK 0xf
+#define VUL_CM0_ULTRA_TH_MASK_SFT (0xf << 20)
+#define VUL_CM0_NORMAL_MODE_SFT 17
+#define VUL_CM0_NORMAL_MODE_MASK 0x1
+#define VUL_CM0_NORMAL_MODE_MASK_SFT (0x1 << 17)
+#define VUL_CM0_ODD_USE_EVEN_SFT 16
+#define VUL_CM0_ODD_USE_EVEN_MASK 0x1
+#define VUL_CM0_ODD_USE_EVEN_MASK_SFT (0x1 << 16)
+#define VUL_CM0_AXI_REQ_MAXLEN_SFT 12
+#define VUL_CM0_AXI_REQ_MAXLEN_MASK 0x3
+#define VUL_CM0_AXI_REQ_MAXLEN_MASK_SFT (0x3 << 12)
+#define VUL_CM0_AXI_REQ_MINLEN_SFT 8
+#define VUL_CM0_AXI_REQ_MINLEN_MASK 0x3
+#define VUL_CM0_AXI_REQ_MINLEN_MASK_SFT (0x3 << 8)
+#define VUL_CM0_HALIGN_SFT 7
+#define VUL_CM0_HALIGN_MASK 0x1
+#define VUL_CM0_HALIGN_MASK_SFT (0x1 << 7)
+#define VUL_CM0_SIGN_EXT_SFT 6
+#define VUL_CM0_SIGN_EXT_MASK 0x1
+#define VUL_CM0_SIGN_EXT_MASK_SFT (0x1 << 6)
+#define VUL_CM0_HD_MODE_SFT 4
+#define VUL_CM0_HD_MODE_MASK 0x3
+#define VUL_CM0_HD_MODE_MASK_SFT (0x3 << 4)
+#define VUL_CM0_MAKE_EXTRA_UPDATE_SFT 3
+#define VUL_CM0_MAKE_EXTRA_UPDATE_MASK 0x1
+#define VUL_CM0_MAKE_EXTRA_UPDATE_MASK_SFT (0x1 << 3)
+#define VUL_CM0_AGENT_FREE_RUN_SFT 2
+#define VUL_CM0_AGENT_FREE_RUN_MASK 0x1
+#define VUL_CM0_AGENT_FREE_RUN_MASK_SFT (0x1 << 2)
+#define VUL_CM0_USE_INT_ODD_SFT 1
+#define VUL_CM0_USE_INT_ODD_MASK 0x1
+#define VUL_CM0_USE_INT_ODD_MASK_SFT (0x1 << 1)
+#define VUL_CM0_INT_ODD_FLAG_SFT 0
+#define VUL_CM0_INT_ODD_FLAG_MASK 0x1
+#define VUL_CM0_INT_ODD_FLAG_MASK_SFT (0x1 << 0)
+
+/* AFE_VUL_CM1_BASE_MSB */
+#define VUL_CM1_BASE_ADDR_MSB_SFT 0
+#define VUL_CM1_BASE_ADDR_MSB_MASK 0x1ff
+#define VUL_CM1_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL_CM1_BASE */
+#define VUL_CM1_BASE_ADDR_SFT 4
+#define VUL_CM1_BASE_ADDR_MASK 0xfffffff
+#define VUL_CM1_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL_CM1_CUR_MSB */
+#define VUL_CM1_CUR_PTR_MSB_SFT 0
+#define VUL_CM1_CUR_PTR_MSB_MASK 0x1ff
+#define VUL_CM1_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL_CM1_CUR */
+#define VUL_CM1_CUR_PTR_SFT 0
+#define VUL_CM1_CUR_PTR_MASK 0xffffffff
+#define VUL_CM1_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL_CM1_END_MSB */
+#define VUL_CM1_END_ADDR_MSB_SFT 0
+#define VUL_CM1_END_ADDR_MSB_MASK 0x1ff
+#define VUL_CM1_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_VUL_CM1_END */
+#define VUL_CM1_END_ADDR_SFT 4
+#define VUL_CM1_END_ADDR_MASK 0xfffffff
+#define VUL_CM1_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_VUL_CM1_CON0 */
+#define VUL_CM1_ON_SFT 28
+#define VUL_CM1_ON_MASK 0x1
+#define VUL_CM1_ON_MASK_SFT (0x1 << 28)
+#define VUL_CM1_REG_CH_SHIFT_MODE_SFT 26
+#define VUL_CM1_REG_CH_SHIFT_MODE_MASK 0x1
+#define VUL_CM1_REG_CH_SHIFT_MODE_MASK_SFT (0x1 << 26)
+#define VUL_CM1_RG_FORCE_NO_MASK_EXTRA_SFT 25
+#define VUL_CM1_RG_FORCE_NO_MASK_EXTRA_MASK 0x1
+#define VUL_CM1_RG_FORCE_NO_MASK_EXTRA_MASK_SFT (0x1 << 25)
+#define VUL_CM1_SW_CLEAR_BUF_FULL_SFT 24
+#define VUL_CM1_SW_CLEAR_BUF_FULL_MASK 0x1
+#define VUL_CM1_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 24)
+#define VUL_CM1_ULTRA_TH_SFT 20
+#define VUL_CM1_ULTRA_TH_MASK 0xf
+#define VUL_CM1_ULTRA_TH_MASK_SFT (0xf << 20)
+#define VUL_CM1_NORMAL_MODE_SFT 17
+#define VUL_CM1_NORMAL_MODE_MASK 0x1
+#define VUL_CM1_NORMAL_MODE_MASK_SFT (0x1 << 17)
+#define VUL_CM1_ODD_USE_EVEN_SFT 16
+#define VUL_CM1_ODD_USE_EVEN_MASK 0x1
+#define VUL_CM1_ODD_USE_EVEN_MASK_SFT (0x1 << 16)
+#define VUL_CM1_AXI_REQ_MAXLEN_SFT 12
+#define VUL_CM1_AXI_REQ_MAXLEN_MASK 0x3
+#define VUL_CM1_AXI_REQ_MAXLEN_MASK_SFT (0x3 << 12)
+#define VUL_CM1_AXI_REQ_MINLEN_SFT 8
+#define VUL_CM1_AXI_REQ_MINLEN_MASK 0x3
+#define VUL_CM1_AXI_REQ_MINLEN_MASK_SFT (0x3 << 8)
+#define VUL_CM1_HALIGN_SFT 7
+#define VUL_CM1_HALIGN_MASK 0x1
+#define VUL_CM1_HALIGN_MASK_SFT (0x1 << 7)
+#define VUL_CM1_SIGN_EXT_SFT 6
+#define VUL_CM1_SIGN_EXT_MASK 0x1
+#define VUL_CM1_SIGN_EXT_MASK_SFT (0x1 << 6)
+#define VUL_CM1_HD_MODE_SFT 4
+#define VUL_CM1_HD_MODE_MASK 0x3
+#define VUL_CM1_HD_MODE_MASK_SFT (0x3 << 4)
+#define VUL_CM1_MAKE_EXTRA_UPDATE_SFT 3
+#define VUL_CM1_MAKE_EXTRA_UPDATE_MASK 0x1
+#define VUL_CM1_MAKE_EXTRA_UPDATE_MASK_SFT (0x1 << 3)
+#define VUL_CM1_AGENT_FREE_RUN_SFT 2
+#define VUL_CM1_AGENT_FREE_RUN_MASK 0x1
+#define VUL_CM1_AGENT_FREE_RUN_MASK_SFT (0x1 << 2)
+#define VUL_CM1_USE_INT_ODD_SFT 1
+#define VUL_CM1_USE_INT_ODD_MASK 0x1
+#define VUL_CM1_USE_INT_ODD_MASK_SFT (0x1 << 1)
+#define VUL_CM1_INT_ODD_FLAG_SFT 0
+#define VUL_CM1_INT_ODD_FLAG_MASK 0x1
+#define VUL_CM1_INT_ODD_FLAG_MASK_SFT (0x1 << 0)
+
+/* AFE_ETDM_IN0_BASE_MSB */
+#define ETDM_IN0_BASE_ADDR_MSB_SFT 0
+#define ETDM_IN0_BASE_ADDR_MSB_MASK 0x1ff
+#define ETDM_IN0_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_ETDM_IN0_BASE */
+#define ETDM_IN0_BASE_ADDR_SFT 4
+#define ETDM_IN0_BASE_ADDR_MASK 0xfffffff
+#define ETDM_IN0_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_ETDM_IN0_CUR_MSB */
+#define ETDM_IN0_CUR_PTR_MSB_SFT 0
+#define ETDM_IN0_CUR_PTR_MSB_MASK 0x1ff
+#define ETDM_IN0_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_ETDM_IN0_CUR */
+#define ETDM_IN0_CUR_PTR_SFT 0
+#define ETDM_IN0_CUR_PTR_MASK 0xffffffff
+#define ETDM_IN0_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ETDM_IN0_END_MSB */
+#define ETDM_IN0_END_ADDR_MSB_SFT 0
+#define ETDM_IN0_END_ADDR_MSB_MASK 0x1ff
+#define ETDM_IN0_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_ETDM_IN0_END */
+#define ETDM_IN0_END_ADDR_SFT 4
+#define ETDM_IN0_END_ADDR_MASK 0xfffffff
+#define ETDM_IN0_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_ETDM_IN0_CON0 */
+#define ETDM_IN0_CH_NUM_SFT 28
+#define ETDM_IN0_CH_NUM_MASK 0xf
+#define ETDM_IN0_CH_NUM_MASK_SFT (0xf << 28)
+#define ETDM_IN0_ON_SFT 27
+#define ETDM_IN0_ON_MASK 0x1
+#define ETDM_IN0_ON_MASK_SFT (0x1 << 27)
+#define ETDM_IN0_REG_CH_SHIFT_MODE_SFT 26
+#define ETDM_IN0_REG_CH_SHIFT_MODE_MASK 0x1
+#define ETDM_IN0_REG_CH_SHIFT_MODE_MASK_SFT (0x1 << 26)
+#define ETDM_IN0_RG_FORCE_NO_MASK_EXTRA_SFT 25
+#define ETDM_IN0_RG_FORCE_NO_MASK_EXTRA_MASK 0x1
+#define ETDM_IN0_RG_FORCE_NO_MASK_EXTRA_MASK_SFT (0x1 << 25)
+#define ETDM_IN0_SW_CLEAR_BUF_FULL_SFT 24
+#define ETDM_IN0_SW_CLEAR_BUF_FULL_MASK 0x1
+#define ETDM_IN0_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 24)
+#define ETDM_IN0_ULTRA_TH_SFT 20
+#define ETDM_IN0_ULTRA_TH_MASK 0xf
+#define ETDM_IN0_ULTRA_TH_MASK_SFT (0xf << 20)
+#define ETDM_IN0_NORMAL_MODE_SFT 17
+#define ETDM_IN0_NORMAL_MODE_MASK 0x1
+#define ETDM_IN0_NORMAL_MODE_MASK_SFT (0x1 << 17)
+#define ETDM_IN0_ODD_USE_EVEN_SFT 16
+#define ETDM_IN0_ODD_USE_EVEN_MASK 0x1
+#define ETDM_IN0_ODD_USE_EVEN_MASK_SFT (0x1 << 16)
+#define ETDM_IN0_AXI_REQ_MAXLEN_SFT 12
+#define ETDM_IN0_AXI_REQ_MAXLEN_MASK 0x3
+#define ETDM_IN0_AXI_REQ_MAXLEN_MASK_SFT (0x3 << 12)
+#define ETDM_IN0_AXI_REQ_MINLEN_SFT 8
+#define ETDM_IN0_AXI_REQ_MINLEN_MASK 0x3
+#define ETDM_IN0_AXI_REQ_MINLEN_MASK_SFT (0x3 << 8)
+#define ETDM_IN0_HALIGN_SFT 7
+#define ETDM_IN0_HALIGN_MASK 0x1
+#define ETDM_IN0_HALIGN_MASK_SFT (0x1 << 7)
+#define ETDM_IN0_SIGN_EXT_SFT 6
+#define ETDM_IN0_SIGN_EXT_MASK 0x1
+#define ETDM_IN0_SIGN_EXT_MASK_SFT (0x1 << 6)
+#define ETDM_IN0_HD_MODE_SFT 4
+#define ETDM_IN0_HD_MODE_MASK 0x3
+#define ETDM_IN0_HD_MODE_MASK_SFT (0x3 << 4)
+#define ETDM_IN0_MAKE_EXTRA_UPDATE_SFT 3
+#define ETDM_IN0_MAKE_EXTRA_UPDATE_MASK 0x1
+#define ETDM_IN0_MAKE_EXTRA_UPDATE_MASK_SFT (0x1 << 3)
+#define ETDM_IN0_AGENT_FREE_RUN_SFT 2
+#define ETDM_IN0_AGENT_FREE_RUN_MASK 0x1
+#define ETDM_IN0_AGENT_FREE_RUN_MASK_SFT (0x1 << 2)
+#define ETDM_IN0_USE_INT_ODD_SFT 1
+#define ETDM_IN0_USE_INT_ODD_MASK 0x1
+#define ETDM_IN0_USE_INT_ODD_MASK_SFT (0x1 << 1)
+#define ETDM_IN0_INT_ODD_FLAG_SFT 0
+#define ETDM_IN0_INT_ODD_FLAG_MASK 0x1
+#define ETDM_IN0_INT_ODD_FLAG_MASK_SFT (0x1 << 0)
+
+/* AFE_ETDM_IN1_BASE_MSB */
+#define ETDM_IN1_BASE_ADDR_MSB_SFT 0
+#define ETDM_IN1_BASE_ADDR_MSB_MASK 0x1ff
+#define ETDM_IN1_BASE_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_ETDM_IN1_BASE */
+#define ETDM_IN1_BASE_ADDR_SFT 4
+#define ETDM_IN1_BASE_ADDR_MASK 0xfffffff
+#define ETDM_IN1_BASE_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_ETDM_IN1_CUR_MSB */
+#define ETDM_IN1_CUR_PTR_MSB_SFT 0
+#define ETDM_IN1_CUR_PTR_MSB_MASK 0x1ff
+#define ETDM_IN1_CUR_PTR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_ETDM_IN1_CUR */
+#define ETDM_IN1_CUR_PTR_SFT 0
+#define ETDM_IN1_CUR_PTR_MASK 0xffffffff
+#define ETDM_IN1_CUR_PTR_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ETDM_IN1_END_MSB */
+#define ETDM_IN1_END_ADDR_MSB_SFT 0
+#define ETDM_IN1_END_ADDR_MSB_MASK 0x1ff
+#define ETDM_IN1_END_ADDR_MSB_MASK_SFT (0x1ff << 0)
+
+/* AFE_ETDM_IN1_END */
+#define ETDM_IN1_END_ADDR_SFT 4
+#define ETDM_IN1_END_ADDR_MASK 0xfffffff
+#define ETDM_IN1_END_ADDR_MASK_SFT (0xfffffff << 4)
+
+/* AFE_ETDM_IN1_CON0 */
+#define ETDM_IN1_CH_NUM_SFT 28
+#define ETDM_IN1_CH_NUM_MASK 0xf
+#define ETDM_IN1_CH_NUM_MASK_SFT (0xf << 28)
+#define ETDM_IN1_ON_SFT 27
+#define ETDM_IN1_ON_MASK 0x1
+#define ETDM_IN1_ON_MASK_SFT (0x1 << 27)
+#define ETDM_IN1_REG_CH_SHIFT_MODE_SFT 26
+#define ETDM_IN1_REG_CH_SHIFT_MODE_MASK 0x1
+#define ETDM_IN1_REG_CH_SHIFT_MODE_MASK_SFT (0x1 << 26)
+#define ETDM_IN1_RG_FORCE_NO_MASK_EXTRA_SFT 25
+#define ETDM_IN1_RG_FORCE_NO_MASK_EXTRA_MASK 0x1
+#define ETDM_IN1_RG_FORCE_NO_MASK_EXTRA_MASK_SFT (0x1 << 25)
+#define ETDM_IN1_SW_CLEAR_BUF_FULL_SFT 24
+#define ETDM_IN1_SW_CLEAR_BUF_FULL_MASK 0x1
+#define ETDM_IN1_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 24)
+#define ETDM_IN1_ULTRA_TH_SFT 20
+#define ETDM_IN1_ULTRA_TH_MASK 0xf
+#define ETDM_IN1_ULTRA_TH_MASK_SFT (0xf << 20)
+#define ETDM_IN1_NORMAL_MODE_SFT 17
+#define ETDM_IN1_NORMAL_MODE_MASK 0x1
+#define ETDM_IN1_NORMAL_MODE_MASK_SFT (0x1 << 17)
+#define ETDM_IN1_ODD_USE_EVEN_SFT 16
+#define ETDM_IN1_ODD_USE_EVEN_MASK 0x1
+#define ETDM_IN1_ODD_USE_EVEN_MASK_SFT (0x1 << 16)
+#define ETDM_IN1_AXI_REQ_MAXLEN_SFT 12
+#define ETDM_IN1_AXI_REQ_MAXLEN_MASK 0x3
+#define ETDM_IN1_AXI_REQ_MAXLEN_MASK_SFT (0x3 << 12)
+#define ETDM_IN1_AXI_REQ_MINLEN_SFT 8
+#define ETDM_IN1_AXI_REQ_MINLEN_MASK 0x3
+#define ETDM_IN1_AXI_REQ_MINLEN_MASK_SFT (0x3 << 8)
+#define ETDM_IN1_HALIGN_SFT 7
+#define ETDM_IN1_HALIGN_MASK 0x1
+#define ETDM_IN1_HALIGN_MASK_SFT (0x1 << 7)
+#define ETDM_IN1_SIGN_EXT_SFT 6
+#define ETDM_IN1_SIGN_EXT_MASK 0x1
+#define ETDM_IN1_SIGN_EXT_MASK_SFT (0x1 << 6)
+#define ETDM_IN1_HD_MODE_SFT 4
+#define ETDM_IN1_HD_MODE_MASK 0x3
+#define ETDM_IN1_HD_MODE_MASK_SFT (0x3 << 4)
+#define ETDM_IN1_MAKE_EXTRA_UPDATE_SFT 3
+#define ETDM_IN1_MAKE_EXTRA_UPDATE_MASK 0x1
+#define ETDM_IN1_MAKE_EXTRA_UPDATE_MASK_SFT (0x1 << 3)
+#define ETDM_IN1_AGENT_FREE_RUN_SFT 2
+#define ETDM_IN1_AGENT_FREE_RUN_MASK 0x1
+#define ETDM_IN1_AGENT_FREE_RUN_MASK_SFT (0x1 << 2)
+#define ETDM_IN1_USE_INT_ODD_SFT 1
+#define ETDM_IN1_USE_INT_ODD_MASK 0x1
+#define ETDM_IN1_USE_INT_ODD_MASK_SFT (0x1 << 1)
+#define ETDM_IN1_INT_ODD_FLAG_SFT 0
+#define ETDM_IN1_INT_ODD_FLAG_MASK 0x1
+#define ETDM_IN1_INT_ODD_FLAG_MASK_SFT (0x1 << 0)
+
+/* AFE_VUL24_RCH_MON */
+#define VUL24_RCH_DATA_SFT 0
+#define VUL24_RCH_DATA_MASK 0xffffffff
+#define VUL24_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL24_LCH_MON */
+#define VUL24_LCH_DATA_SFT 0
+#define VUL24_LCH_DATA_MASK 0xffffffff
+#define VUL24_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL25_RCH_MON */
+#define VUL25_RCH_DATA_SFT 0
+#define VUL25_RCH_DATA_MASK 0xffffffff
+#define VUL25_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL25_LCH_MON */
+#define VUL25_LCH_DATA_SFT 0
+#define VUL25_LCH_DATA_MASK 0xffffffff
+#define VUL25_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL_CM0_RCH_MON */
+#define VUL_CM0_RCH_DATA_SFT 0
+#define VUL_CM0_RCH_DATA_MASK 0xffffffff
+#define VUL_CM0_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL_CM0_LCH_MON */
+#define VUL_CM0_LCH_DATA_SFT 0
+#define VUL_CM0_LCH_DATA_MASK 0xffffffff
+#define VUL_CM0_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL_CM1_RCH_MON */
+#define VUL_CM1_RCH_DATA_SFT 0
+#define VUL_CM1_RCH_DATA_MASK 0xffffffff
+#define VUL_CM1_RCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_VUL_CM1_LCH_MON */
+#define VUL_CM1_LCH_DATA_SFT 0
+#define VUL_CM1_LCH_DATA_MASK 0xffffffff
+#define VUL_CM1_LCH_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH0_MON */
+#define DL_24CH_CH0_DATA_SFT 0
+#define DL_24CH_CH0_DATA_MASK 0xffffffff
+#define DL_24CH_CH0_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH1_MON */
+#define DL_24CH_CH1_DATA_SFT 0
+#define DL_24CH_CH1_DATA_MASK 0xffffffff
+#define DL_24CH_CH1_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH2_MON */
+#define DL_24CH_CH2_DATA_SFT 0
+#define DL_24CH_CH2_DATA_MASK 0xffffffff
+#define DL_24CH_CH2_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH3_MON */
+#define DL_24CH_CH3_DATA_SFT 0
+#define DL_24CH_CH3_DATA_MASK 0xffffffff
+#define DL_24CH_CH3_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH4_MON */
+#define DL_24CH_CH4_DATA_SFT 0
+#define DL_24CH_CH4_DATA_MASK 0xffffffff
+#define DL_24CH_CH4_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH5_MON */
+#define DL_24CH_CH5_DATA_SFT 0
+#define DL_24CH_CH5_DATA_MASK 0xffffffff
+#define DL_24CH_CH5_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH6_MON */
+#define DL_24CH_CH6_DATA_SFT 0
+#define DL_24CH_CH6_DATA_MASK 0xffffffff
+#define DL_24CH_CH6_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DL_24CH_CH7_MON */
+#define DL_24CH_CH7_DATA_SFT 0
+#define DL_24CH_CH7_DATA_MASK 0xffffffff
+#define DL_24CH_CH7_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SRAM_BOUND */
+#define SECURE_BIT_SFT 19
+#define SECURE_BIT_MASK 0x1
+#define SECURE_BIT_MASK_SFT (0x1 << 19)
+#define SECURE_SRAM_BOUND_SFT 0
+#define SECURE_SRAM_BOUND_MASK 0x7ffff
+#define SECURE_SRAM_BOUND_MASK_SFT (0x7ffff << 0)
+
+/* AFE_SECURE_CON0 */
+#define READ_EN15_NS_SFT 31
+#define READ_EN15_NS_MASK 0x1
+#define READ_EN15_NS_MASK_SFT (0x1 << 31)
+#define WRITE_EN15_NS_SFT 30
+#define WRITE_EN15_NS_MASK 0x1
+#define WRITE_EN15_NS_MASK_SFT (0x1 << 30)
+#define READ_EN14_NS_SFT 29
+#define READ_EN14_NS_MASK 0x1
+#define READ_EN14_NS_MASK_SFT (0x1 << 29)
+#define WRITE_EN14_NS_SFT 28
+#define WRITE_EN14_NS_MASK 0x1
+#define WRITE_EN14_NS_MASK_SFT (0x1 << 28)
+#define READ_EN13_NS_SFT 27
+#define READ_EN13_NS_MASK 0x1
+#define READ_EN13_NS_MASK_SFT (0x1 << 27)
+#define WRITE_EN13_NS_SFT 26
+#define WRITE_EN13_NS_MASK 0x1
+#define WRITE_EN13_NS_MASK_SFT (0x1 << 26)
+#define READ_EN12_NS_SFT 25
+#define READ_EN12_NS_MASK 0x1
+#define READ_EN12_NS_MASK_SFT (0x1 << 25)
+#define WRITE_EN12_NS_SFT 24
+#define WRITE_EN12_NS_MASK 0x1
+#define WRITE_EN12_NS_MASK_SFT (0x1 << 24)
+#define READ_EN11_NS_SFT 23
+#define READ_EN11_NS_MASK 0x1
+#define READ_EN11_NS_MASK_SFT (0x1 << 23)
+#define WRITE_EN11_NS_SFT 22
+#define WRITE_EN11_NS_MASK 0x1
+#define WRITE_EN11_NS_MASK_SFT (0x1 << 22)
+#define READ_EN10_NS_SFT 21
+#define READ_EN10_NS_MASK 0x1
+#define READ_EN10_NS_MASK_SFT (0x1 << 21)
+#define WRITE_EN10_NS_SFT 20
+#define WRITE_EN10_NS_MASK 0x1
+#define WRITE_EN10_NS_MASK_SFT (0x1 << 20)
+#define READ_EN9_NS_SFT 19
+#define READ_EN9_NS_MASK 0x1
+#define READ_EN9_NS_MASK_SFT (0x1 << 19)
+#define WRITE_EN9_NS_SFT 18
+#define WRITE_EN9_NS_MASK 0x1
+#define WRITE_EN9_NS_MASK_SFT (0x1 << 18)
+#define READ_EN8_NS_SFT 17
+#define READ_EN8_NS_MASK 0x1
+#define READ_EN8_NS_MASK_SFT (0x1 << 17)
+#define WRITE_EN8_NS_SFT 16
+#define WRITE_EN8_NS_MASK 0x1
+#define WRITE_EN8_NS_MASK_SFT (0x1 << 16)
+#define READ_EN7_NS_SFT 15
+#define READ_EN7_NS_MASK 0x1
+#define READ_EN7_NS_MASK_SFT (0x1 << 15)
+#define WRITE_EN7_NS_SFT 14
+#define WRITE_EN7_NS_MASK 0x1
+#define WRITE_EN7_NS_MASK_SFT (0x1 << 14)
+#define READ_EN6_NS_SFT 13
+#define READ_EN6_NS_MASK 0x1
+#define READ_EN6_NS_MASK_SFT (0x1 << 13)
+#define WRITE_EN6_NS_SFT 12
+#define WRITE_EN6_NS_MASK 0x1
+#define WRITE_EN6_NS_MASK_SFT (0x1 << 12)
+#define READ_EN5_NS_SFT 11
+#define READ_EN5_NS_MASK 0x1
+#define READ_EN5_NS_MASK_SFT (0x1 << 11)
+#define WRITE_EN5_NS_SFT 10
+#define WRITE_EN5_NS_MASK 0x1
+#define WRITE_EN5_NS_MASK_SFT (0x1 << 10)
+#define READ_EN4_NS_SFT 9
+#define READ_EN4_NS_MASK 0x1
+#define READ_EN4_NS_MASK_SFT (0x1 << 9)
+#define WRITE_EN4_NS_SFT 8
+#define WRITE_EN4_NS_MASK 0x1
+#define WRITE_EN4_NS_MASK_SFT (0x1 << 8)
+#define READ_EN3_NS_SFT 7
+#define READ_EN3_NS_MASK 0x1
+#define READ_EN3_NS_MASK_SFT (0x1 << 7)
+#define WRITE_EN3_NS_SFT 6
+#define WRITE_EN3_NS_MASK 0x1
+#define WRITE_EN3_NS_MASK_SFT (0x1 << 6)
+#define READ_EN2_NS_SFT 5
+#define READ_EN2_NS_MASK 0x1
+#define READ_EN2_NS_MASK_SFT (0x1 << 5)
+#define WRITE_EN2_NS_SFT 4
+#define WRITE_EN2_NS_MASK 0x1
+#define WRITE_EN2_NS_MASK_SFT (0x1 << 4)
+#define READ_EN1_NS_SFT 3
+#define READ_EN1_NS_MASK 0x1
+#define READ_EN1_NS_MASK_SFT (0x1 << 3)
+#define WRITE_EN1_NS_SFT 2
+#define WRITE_EN1_NS_MASK 0x1
+#define WRITE_EN1_NS_MASK_SFT (0x1 << 2)
+#define READ_EN0_NS_SFT 1
+#define READ_EN0_NS_MASK 0x1
+#define READ_EN0_NS_MASK_SFT (0x1 << 1)
+#define WRITE_EN0_NS_SFT 0
+#define WRITE_EN0_NS_MASK 0x1
+#define WRITE_EN0_NS_MASK_SFT (0x1 << 0)
+
+/* AFE_SECURE_CON1 */
+#define READ_EN15_S_SFT 31
+#define READ_EN15_S_MASK 0x1
+#define READ_EN15_S_MASK_SFT (0x1 << 31)
+#define WRITE_EN15_S_SFT 30
+#define WRITE_EN15_S_MASK 0x1
+#define WRITE_EN15_S_MASK_SFT (0x1 << 30)
+#define READ_EN14_S_SFT 29
+#define READ_EN14_S_MASK 0x1
+#define READ_EN14_S_MASK_SFT (0x1 << 29)
+#define WRITE_EN14_S_SFT 28
+#define WRITE_EN14_S_MASK 0x1
+#define WRITE_EN14_S_MASK_SFT (0x1 << 28)
+#define READ_EN13_S_SFT 27
+#define READ_EN13_S_MASK 0x1
+#define READ_EN13_S_MASK_SFT (0x1 << 27)
+#define WRITE_EN13_S_SFT 26
+#define WRITE_EN13_S_MASK 0x1
+#define WRITE_EN13_S_MASK_SFT (0x1 << 26)
+#define READ_EN12_S_SFT 25
+#define READ_EN12_S_MASK 0x1
+#define READ_EN12_S_MASK_SFT (0x1 << 25)
+#define WRITE_EN12_S_SFT 24
+#define WRITE_EN12_S_MASK 0x1
+#define WRITE_EN12_S_MASK_SFT (0x1 << 24)
+#define READ_EN11_S_SFT 23
+#define READ_EN11_S_MASK 0x1
+#define READ_EN11_S_MASK_SFT (0x1 << 23)
+#define WRITE_EN11_S_SFT 22
+#define WRITE_EN11_S_MASK 0x1
+#define WRITE_EN11_S_MASK_SFT (0x1 << 22)
+#define READ_EN10_S_SFT 21
+#define READ_EN10_S_MASK 0x1
+#define READ_EN10_S_MASK_SFT (0x1 << 21)
+#define WRITE_EN10_S_SFT 20
+#define WRITE_EN10_S_MASK 0x1
+#define WRITE_EN10_S_MASK_SFT (0x1 << 20)
+#define READ_EN9_S_SFT 19
+#define READ_EN9_S_MASK 0x1
+#define READ_EN9_S_MASK_SFT (0x1 << 19)
+#define WRITE_EN9_S_SFT 18
+#define WRITE_EN9_S_MASK 0x1
+#define WRITE_EN9_S_MASK_SFT (0x1 << 18)
+#define READ_EN8_S_SFT 17
+#define READ_EN8_S_MASK 0x1
+#define READ_EN8_S_MASK_SFT (0x1 << 17)
+#define WRITE_EN8_S_SFT 16
+#define WRITE_EN8_S_MASK 0x1
+#define WRITE_EN8_S_MASK_SFT (0x1 << 16)
+#define READ_EN7_S_SFT 15
+#define READ_EN7_S_MASK 0x1
+#define READ_EN7_S_MASK_SFT (0x1 << 15)
+#define WRITE_EN7_S_SFT 14
+#define WRITE_EN7_S_MASK 0x1
+#define WRITE_EN7_S_MASK_SFT (0x1 << 14)
+#define READ_EN6_S_SFT 13
+#define READ_EN6_S_MASK 0x1
+#define READ_EN6_S_MASK_SFT (0x1 << 13)
+#define WRITE_EN6_S_SFT 12
+#define WRITE_EN6_S_MASK 0x1
+#define WRITE_EN6_S_MASK_SFT (0x1 << 12)
+#define READ_EN5_S_SFT 11
+#define READ_EN5_S_MASK 0x1
+#define READ_EN5_S_MASK_SFT (0x1 << 11)
+#define WRITE_EN5_S_SFT 10
+#define WRITE_EN5_S_MASK 0x1
+#define WRITE_EN5_S_MASK_SFT (0x1 << 10)
+#define READ_EN4_S_SFT 9
+#define READ_EN4_S_MASK 0x1
+#define READ_EN4_S_MASK_SFT (0x1 << 9)
+#define WRITE_EN4_S_SFT 8
+#define WRITE_EN4_S_MASK 0x1
+#define WRITE_EN4_S_MASK_SFT (0x1 << 8)
+#define READ_EN3_S_SFT 7
+#define READ_EN3_S_MASK 0x1
+#define READ_EN3_S_MASK_SFT (0x1 << 7)
+#define WRITE_EN3_S_SFT 6
+#define WRITE_EN3_S_MASK 0x1
+#define WRITE_EN3_S_MASK_SFT (0x1 << 6)
+#define READ_EN2_S_SFT 5
+#define READ_EN2_S_MASK 0x1
+#define READ_EN2_S_MASK_SFT (0x1 << 5)
+#define WRITE_EN2_S_SFT 4
+#define WRITE_EN2_S_MASK 0x1
+#define WRITE_EN2_S_MASK_SFT (0x1 << 4)
+#define READ_EN1_S_SFT 3
+#define READ_EN1_S_MASK 0x1
+#define READ_EN1_S_MASK_SFT (0x1 << 3)
+#define WRITE_EN1_S_SFT 2
+#define WRITE_EN1_S_MASK 0x1
+#define WRITE_EN1_S_MASK_SFT (0x1 << 2)
+#define READ_EN0_S_SFT 1
+#define READ_EN0_S_MASK 0x1
+#define READ_EN0_S_MASK_SFT (0x1 << 1)
+#define WRITE_EN0_S_SFT 0
+#define WRITE_EN0_S_MASK 0x1
+#define WRITE_EN0_S_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_SECURE_CON0 */
+#define AFE_HDMI_SE_SECURE_BIT_SFT 11
+#define AFE_HDMI_SE_SECURE_BIT_MASK 0x1
+#define AFE_HDMI_SE_SECURE_BIT_MASK_SFT (0x1 << 11)
+#define AFE_SPDIF2_OUT_SE_SECURE_BIT_SFT 10
+#define AFE_SPDIF2_OUT_SE_SECURE_BIT_MASK 0x1
+#define AFE_SPDIF2_OUT_SE_SECURE_BIT_MASK_SFT (0x1 << 10)
+#define AFE_SPDIF_OUT_SE_SECURE_BIT_SFT 9
+#define AFE_SPDIF_OUT_SE_SECURE_BIT_MASK 0x1
+#define AFE_SPDIF_OUT_SE_SECURE_BIT_MASK_SFT (0x1 << 9)
+#define AFE_DL8_SE_SECURE_BIT_SFT 8
+#define AFE_DL8_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL8_SE_SECURE_BIT_MASK_SFT (0x1 << 8)
+#define AFE_DL7_SE_SECURE_BIT_SFT 7
+#define AFE_DL7_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL7_SE_SECURE_BIT_MASK_SFT (0x1 << 7)
+#define AFE_DL6_SE_SECURE_BIT_SFT 6
+#define AFE_DL6_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL6_SE_SECURE_BIT_MASK_SFT (0x1 << 6)
+#define AFE_DL5_SE_SECURE_BIT_SFT 5
+#define AFE_DL5_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL5_SE_SECURE_BIT_MASK_SFT (0x1 << 5)
+#define AFE_DL4_SE_SECURE_BIT_SFT 4
+#define AFE_DL4_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL4_SE_SECURE_BIT_MASK_SFT (0x1 << 4)
+#define AFE_DL3_SE_SECURE_BIT_SFT 3
+#define AFE_DL3_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL3_SE_SECURE_BIT_MASK_SFT (0x1 << 3)
+#define AFE_DL2_SE_SECURE_BIT_SFT 2
+#define AFE_DL2_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL2_SE_SECURE_BIT_MASK_SFT (0x1 << 2)
+#define AFE_DL1_SE_SECURE_BIT_SFT 1
+#define AFE_DL1_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL1_SE_SECURE_BIT_MASK_SFT (0x1 << 1)
+#define AFE_DL0_SE_SECURE_BIT_SFT 0
+#define AFE_DL0_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL0_SE_SECURE_BIT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_SECURE_CON1 */
+#define AFE_DL46_SE_SECURE_BIT_SFT 26
+#define AFE_DL46_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL46_SE_SECURE_BIT_MASK_SFT (0x1 << 26)
+#define AFE_DL45_SE_SECURE_BIT_SFT 25
+#define AFE_DL45_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL45_SE_SECURE_BIT_MASK_SFT (0x1 << 25)
+#define AFE_DL44_SE_SECURE_BIT_SFT 24
+#define AFE_DL44_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL44_SE_SECURE_BIT_MASK_SFT (0x1 << 24)
+#define AFE_DL43_SE_SECURE_BIT_SFT 23
+#define AFE_DL43_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL43_SE_SECURE_BIT_MASK_SFT (0x1 << 23)
+#define AFE_DL42_SE_SECURE_BIT_SFT 22
+#define AFE_DL42_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL42_SE_SECURE_BIT_MASK_SFT (0x1 << 22)
+#define AFE_DL41_SE_SECURE_BIT_SFT 21
+#define AFE_DL41_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL41_SE_SECURE_BIT_MASK_SFT (0x1 << 21)
+#define AFE_DL40_SE_SECURE_BIT_SFT 20
+#define AFE_DL40_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL40_SE_SECURE_BIT_MASK_SFT (0x1 << 20)
+#define AFE_DL39_SE_SECURE_BIT_SFT 19
+#define AFE_DL39_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL39_SE_SECURE_BIT_MASK_SFT (0x1 << 19)
+#define AFE_DL38_SE_SECURE_BIT_SFT 18
+#define AFE_DL38_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL38_SE_SECURE_BIT_MASK_SFT (0x1 << 18)
+#define AFE_DL37_SE_SECURE_BIT_SFT 17
+#define AFE_DL37_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL37_SE_SECURE_BIT_MASK_SFT (0x1 << 17)
+#define AFE_DL36_SE_SECURE_BIT_SFT 16
+#define AFE_DL36_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL36_SE_SECURE_BIT_MASK_SFT (0x1 << 16)
+#define AFE_DL35_SE_SECURE_BIT_SFT 15
+#define AFE_DL35_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL35_SE_SECURE_BIT_MASK_SFT (0x1 << 15)
+#define AFE_DL34_SE_SECURE_BIT_SFT 14
+#define AFE_DL34_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL34_SE_SECURE_BIT_MASK_SFT (0x1 << 14)
+#define AFE_DL33_SE_SECURE_BIT_SFT 13
+#define AFE_DL33_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL33_SE_SECURE_BIT_MASK_SFT (0x1 << 13)
+#define AFE_DL32_SE_SECURE_BIT_SFT 12
+#define AFE_DL32_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL32_SE_SECURE_BIT_MASK_SFT (0x1 << 12)
+#define AFE_DL31_SE_SECURE_BIT_SFT 11
+#define AFE_DL31_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL31_SE_SECURE_BIT_MASK_SFT (0x1 << 11)
+#define AFE_DL30_SE_SECURE_BIT_SFT 10
+#define AFE_DL30_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL30_SE_SECURE_BIT_MASK_SFT (0x1 << 10)
+#define AFE_DL29_SE_SECURE_BIT_SFT 9
+#define AFE_DL29_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL29_SE_SECURE_BIT_MASK_SFT (0x1 << 9)
+#define AFE_DL28_SE_SECURE_BIT_SFT 8
+#define AFE_DL28_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL28_SE_SECURE_BIT_MASK_SFT (0x1 << 8)
+#define AFE_DL27_SE_SECURE_BIT_SFT 7
+#define AFE_DL27_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL27_SE_SECURE_BIT_MASK_SFT (0x1 << 7)
+#define AFE_DL26_SE_SECURE_BIT_SFT 6
+#define AFE_DL26_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL26_SE_SECURE_BIT_MASK_SFT (0x1 << 6)
+#define AFE_DL25_SE_SECURE_BIT_SFT 5
+#define AFE_DL25_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL25_SE_SECURE_BIT_MASK_SFT (0x1 << 5)
+#define AFE_DL24_SE_SECURE_BIT_SFT 4
+#define AFE_DL24_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL24_SE_SECURE_BIT_MASK_SFT (0x1 << 4)
+#define AFE_DL23_SE_SECURE_BIT_SFT 3
+#define AFE_DL23_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL23_SE_SECURE_BIT_MASK_SFT (0x1 << 3)
+#define AFE_DL_48CH_SE_SECURE_BIT_SFT 2
+#define AFE_DL_48CH_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL_48CH_SE_SECURE_BIT_MASK_SFT (0x1 << 2)
+#define AFE_DL_24CH_SE_SECURE_BIT_SFT 1
+#define AFE_DL_24CH_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL_24CH_SE_SECURE_BIT_MASK_SFT (0x1 << 1)
+#define AFE_DL_4CH_SE_SECURE_BIT_SFT 0
+#define AFE_DL_4CH_SE_SECURE_BIT_MASK 0x1
+#define AFE_DL_4CH_SE_SECURE_BIT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_SECURE_CON2 */
+#define AFE_VUL38_SE_SECURE_BIT_SFT 28
+#define AFE_VUL38_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL38_SE_SECURE_BIT_MASK_SFT (0x1 << 28)
+#define AFE_VUL37_SE_SECURE_BIT_SFT 27
+#define AFE_VUL37_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL37_SE_SECURE_BIT_MASK_SFT (0x1 << 27)
+#define AFE_VUL36_SE_SECURE_BIT_SFT 26
+#define AFE_VUL36_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL36_SE_SECURE_BIT_MASK_SFT (0x1 << 26)
+#define AFE_VUL35_SE_SECURE_BIT_SFT 25
+#define AFE_VUL35_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL35_SE_SECURE_BIT_MASK_SFT (0x1 << 25)
+#define AFE_VUL34_SE_SECURE_BIT_SFT 24
+#define AFE_VUL34_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL34_SE_SECURE_BIT_MASK_SFT (0x1 << 24)
+#define AFE_VUL33_SE_SECURE_BIT_SFT 23
+#define AFE_VUL33_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL33_SE_SECURE_BIT_MASK_SFT (0x1 << 23)
+#define AFE_VUL32_SE_SECURE_BIT_SFT 22
+#define AFE_VUL32_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL32_SE_SECURE_BIT_MASK_SFT (0x1 << 22)
+#define AFE_VUL31_SE_SECURE_BIT_SFT 21
+#define AFE_VUL31_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL31_SE_SECURE_BIT_MASK_SFT (0x1 << 21)
+#define AFE_VUL30_SE_SECURE_BIT_SFT 20
+#define AFE_VUL30_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL30_SE_SECURE_BIT_MASK_SFT (0x1 << 20)
+#define AFE_VUL29_SE_SECURE_BIT_SFT 19
+#define AFE_VUL29_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL29_SE_SECURE_BIT_MASK_SFT (0x1 << 19)
+#define AFE_VUL28_SE_SECURE_BIT_SFT 18
+#define AFE_VUL28_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL28_SE_SECURE_BIT_MASK_SFT (0x1 << 18)
+#define AFE_VUL27_SE_SECURE_BIT_SFT 17
+#define AFE_VUL27_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL27_SE_SECURE_BIT_MASK_SFT (0x1 << 17)
+#define AFE_VUL26_SE_SECURE_BIT_SFT 16
+#define AFE_VUL26_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL26_SE_SECURE_BIT_MASK_SFT (0x1 << 16)
+#define AFE_VUL25_SE_SECURE_BIT_SFT 15
+#define AFE_VUL25_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL25_SE_SECURE_BIT_MASK_SFT (0x1 << 15)
+#define AFE_VUL24_SE_SECURE_BIT_SFT 14
+#define AFE_VUL24_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL24_SE_SECURE_BIT_MASK_SFT (0x1 << 14)
+#define AFE_VUL_CM2_SE_SECURE_BIT_SFT 13
+#define AFE_VUL_CM2_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL_CM2_SE_SECURE_BIT_MASK_SFT (0x1 << 13)
+#define AFE_VUL_CM1_SE_SECURE_BIT_SFT 12
+#define AFE_VUL_CM1_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL_CM1_SE_SECURE_BIT_MASK_SFT (0x1 << 12)
+#define AFE_VUL_CM0_SE_SECURE_BIT_SFT 11
+#define AFE_VUL_CM0_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL_CM0_SE_SECURE_BIT_MASK_SFT (0x1 << 11)
+#define AFE_VUL10_SE_SECURE_BIT_SFT 10
+#define AFE_VUL10_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL10_SE_SECURE_BIT_MASK_SFT (0x1 << 10)
+#define AFE_VUL9_SE_SECURE_BIT_SFT 9
+#define AFE_VUL9_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL9_SE_SECURE_BIT_MASK_SFT (0x1 << 9)
+#define AFE_VUL8_SE_SECURE_BIT_SFT 8
+#define AFE_VUL8_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL8_SE_SECURE_BIT_MASK_SFT (0x1 << 8)
+#define AFE_VUL7_SE_SECURE_BIT_SFT 7
+#define AFE_VUL7_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL7_SE_SECURE_BIT_MASK_SFT (0x1 << 7)
+#define AFE_VUL6_SE_SECURE_BIT_SFT 6
+#define AFE_VUL6_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL6_SE_SECURE_BIT_MASK_SFT (0x1 << 6)
+#define AFE_VUL5_SE_SECURE_BIT_SFT 5
+#define AFE_VUL5_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL5_SE_SECURE_BIT_MASK_SFT (0x1 << 5)
+#define AFE_VUL4_SE_SECURE_BIT_SFT 4
+#define AFE_VUL4_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL4_SE_SECURE_BIT_MASK_SFT (0x1 << 4)
+#define AFE_VUL3_SE_SECURE_BIT_SFT 3
+#define AFE_VUL3_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL3_SE_SECURE_BIT_MASK_SFT (0x1 << 3)
+#define AFE_VUL2_SE_SECURE_BIT_SFT 2
+#define AFE_VUL2_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL2_SE_SECURE_BIT_MASK_SFT (0x1 << 2)
+#define AFE_VUL1_SE_SECURE_BIT_SFT 1
+#define AFE_VUL1_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL1_SE_SECURE_BIT_MASK_SFT (0x1 << 1)
+#define AFE_VUL0_SE_SECURE_BIT_SFT 0
+#define AFE_VUL0_SE_SECURE_BIT_MASK 0x1
+#define AFE_VUL0_SE_SECURE_BIT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_SECURE_CON3 */
+#define AFE_SPDIFIN_SE_SECURE_BIT_SFT 10
+#define AFE_SPDIFIN_SE_SECURE_BIT_MASK 0x1
+#define AFE_SPDIFIN_SE_SECURE_BIT_MASK_SFT (0x1 << 10)
+#define AFE_TDM_IN_SE_SECURE_BIT_SFT 9
+#define AFE_TDM_IN_SE_SECURE_BIT_MASK 0x1
+#define AFE_TDM_IN_SE_SECURE_BIT_MASK_SFT (0x1 << 9)
+#define AFE_MPHONE_EARC_SE_SECURE_BIT_SFT 8
+#define AFE_MPHONE_EARC_SE_SECURE_BIT_MASK 0x1
+#define AFE_MPHONE_EARC_SE_SECURE_BIT_MASK_SFT (0x1 << 8)
+#define AFE_MPHONE_SPDIF_SE_SECURE_BIT_SFT 7
+#define AFE_MPHONE_SPDIF_SE_SECURE_BIT_MASK 0x1
+#define AFE_MPHONE_SPDIF_SE_SECURE_BIT_MASK_SFT (0x1 << 7)
+#define AFE_ETDM_IN1_SE_SECURE_BIT_SFT 1
+#define AFE_ETDM_IN1_SE_SECURE_BIT_MASK 0x1
+#define AFE_ETDM_IN1_SE_SECURE_BIT_MASK_SFT (0x1 << 1)
+#define AFE_ETDM_IN0_SE_SECURE_BIT_SFT 0
+#define AFE_ETDM_IN0_SE_SECURE_BIT_MASK 0x1
+#define AFE_ETDM_IN0_SE_SECURE_BIT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_PROT_SIDEBAND0 */
+#define HDMI_HPROT_SFT 11
+#define HDMI_HPROT_MASK 0x1
+#define HDMI_HPROT_MASK_SFT (0x1 << 11)
+#define SPDIF2_OUT_HPROT_SFT 10
+#define SPDIF2_OUT_HPROT_MASK 0x1
+#define SPDIF2_OUT_HPROT_MASK_SFT (0x1 << 10)
+#define SPDIF_OUT_HPROT_SFT 9
+#define SPDIF_OUT_HPROT_MASK 0x1
+#define SPDIF_OUT_HPROT_MASK_SFT (0x1 << 9)
+#define DL8_HPROT_SFT 8
+#define DL8_HPROT_MASK 0x1
+#define DL8_HPROT_MASK_SFT (0x1 << 8)
+#define DL7_HPROT_SFT 7
+#define DL7_HPROT_MASK 0x1
+#define DL7_HPROT_MASK_SFT (0x1 << 7)
+#define DL6_HPROT_SFT 6
+#define DL6_HPROT_MASK 0x1
+#define DL6_HPROT_MASK_SFT (0x1 << 6)
+#define DL5_HPROT_SFT 5
+#define DL5_HPROT_MASK 0x1
+#define DL5_HPROT_MASK_SFT (0x1 << 5)
+#define DL4_HPROT_SFT 4
+#define DL4_HPROT_MASK 0x1
+#define DL4_HPROT_MASK_SFT (0x1 << 4)
+#define DL3_HPROT_SFT 3
+#define DL3_HPROT_MASK 0x1
+#define DL3_HPROT_MASK_SFT (0x1 << 3)
+#define DL2_HPROT_SFT 2
+#define DL2_HPROT_MASK 0x1
+#define DL2_HPROT_MASK_SFT (0x1 << 2)
+#define DL1_HPROT_SFT 1
+#define DL1_HPROT_MASK 0x1
+#define DL1_HPROT_MASK_SFT (0x1 << 1)
+#define DL0_HPROT_SFT 0
+#define DL0_HPROT_MASK 0x1
+#define DL0_HPROT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_PROT_SIDEBAND1 */
+#define DL46_HPROT_SFT 26
+#define DL46_HPROT_MASK 0x1
+#define DL46_HPROT_MASK_SFT (0x1 << 26)
+#define DL45_HPROT_SFT 25
+#define DL45_HPROT_MASK 0x1
+#define DL45_HPROT_MASK_SFT (0x1 << 25)
+#define DL44_HPROT_SFT 24
+#define DL44_HPROT_MASK 0x1
+#define DL44_HPROT_MASK_SFT (0x1 << 24)
+#define DL43_HPROT_SFT 23
+#define DL43_HPROT_MASK 0x1
+#define DL43_HPROT_MASK_SFT (0x1 << 23)
+#define DL42_HPROT_SFT 22
+#define DL42_HPROT_MASK 0x1
+#define DL42_HPROT_MASK_SFT (0x1 << 22)
+#define DL41_HPROT_SFT 21
+#define DL41_HPROT_MASK 0x1
+#define DL41_HPROT_MASK_SFT (0x1 << 21)
+#define DL40_HPROT_SFT 20
+#define DL40_HPROT_MASK 0x1
+#define DL40_HPROT_MASK_SFT (0x1 << 20)
+#define DL39_HPROT_SFT 19
+#define DL39_HPROT_MASK 0x1
+#define DL39_HPROT_MASK_SFT (0x1 << 19)
+#define DL38_HPROT_SFT 18
+#define DL38_HPROT_MASK 0x1
+#define DL38_HPROT_MASK_SFT (0x1 << 18)
+#define DL37_HPROT_SFT 17
+#define DL37_HPROT_MASK 0x1
+#define DL37_HPROT_MASK_SFT (0x1 << 17)
+#define DL36_HPROT_SFT 16
+#define DL36_HPROT_MASK 0x1
+#define DL36_HPROT_MASK_SFT (0x1 << 16)
+#define DL35_HPROT_SFT 15
+#define DL35_HPROT_MASK 0x1
+#define DL35_HPROT_MASK_SFT (0x1 << 15)
+#define DL34_HPROT_SFT 14
+#define DL34_HPROT_MASK 0x1
+#define DL34_HPROT_MASK_SFT (0x1 << 14)
+#define DL33_HPROT_SFT 13
+#define DL33_HPROT_MASK 0x1
+#define DL33_HPROT_MASK_SFT (0x1 << 13)
+#define DL32_HPROT_SFT 12
+#define DL32_HPROT_MASK 0x1
+#define DL32_HPROT_MASK_SFT (0x1 << 12)
+#define DL31_HPROT_SFT 11
+#define DL31_HPROT_MASK 0x1
+#define DL31_HPROT_MASK_SFT (0x1 << 11)
+#define DL30_HPROT_SFT 10
+#define DL30_HPROT_MASK 0x1
+#define DL30_HPROT_MASK_SFT (0x1 << 10)
+#define DL29_HPROT_SFT 9
+#define DL29_HPROT_MASK 0x1
+#define DL29_HPROT_MASK_SFT (0x1 << 9)
+#define DL28_HPROT_SFT 8
+#define DL28_HPROT_MASK 0x1
+#define DL28_HPROT_MASK_SFT (0x1 << 8)
+#define DL27_HPROT_SFT 7
+#define DL27_HPROT_MASK 0x1
+#define DL27_HPROT_MASK_SFT (0x1 << 7)
+#define DL26_HPROT_SFT 6
+#define DL26_HPROT_MASK 0x1
+#define DL26_HPROT_MASK_SFT (0x1 << 6)
+#define DL25_HPROT_SFT 5
+#define DL25_HPROT_MASK 0x1
+#define DL25_HPROT_MASK_SFT (0x1 << 5)
+#define DL24_HPROT_SFT 4
+#define DL24_HPROT_MASK 0x1
+#define DL24_HPROT_MASK_SFT (0x1 << 4)
+#define DL23_HPROT_SFT 3
+#define DL23_HPROT_MASK 0x1
+#define DL23_HPROT_MASK_SFT (0x1 << 3)
+#define DL_48CH_PROT_SFT 2
+#define DL_48CH_PROT_MASK 0x1
+#define DL_48CH_PROT_MASK_SFT (0x1 << 2)
+#define DL_24CH_PROT_SFT 1
+#define DL_24CH_PROT_MASK 0x1
+#define DL_24CH_PROT_MASK_SFT (0x1 << 1)
+#define DL_4CH_PROT_SFT 0
+#define DL_4CH_PROT_MASK 0x1
+#define DL_4CH_PROT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_PROT_SIDEBAND2 */
+#define VUL38_HPROT_SFT 28
+#define VUL38_HPROT_MASK 0x1
+#define VUL38_HPROT_MASK_SFT (0x1 << 28)
+#define VUL37_HPROT_SFT 27
+#define VUL37_HPROT_MASK 0x1
+#define VUL37_HPROT_MASK_SFT (0x1 << 27)
+#define VUL36_HPROT_SFT 26
+#define VUL36_HPROT_MASK 0x1
+#define VUL36_HPROT_MASK_SFT (0x1 << 26)
+#define VUL35_HPROT_SFT 25
+#define VUL35_HPROT_MASK 0x1
+#define VUL35_HPROT_MASK_SFT (0x1 << 25)
+#define VUL34_HPROT_SFT 24
+#define VUL34_HPROT_MASK 0x1
+#define VUL34_HPROT_MASK_SFT (0x1 << 24)
+#define VUL33_HPROT_SFT 23
+#define VUL33_HPROT_MASK 0x1
+#define VUL33_HPROT_MASK_SFT (0x1 << 23)
+#define VUL32_HPROT_SFT 22
+#define VUL32_HPROT_MASK 0x1
+#define VUL32_HPROT_MASK_SFT (0x1 << 22)
+#define VUL31_HPROT_SFT 21
+#define VUL31_HPROT_MASK 0x1
+#define VUL31_HPROT_MASK_SFT (0x1 << 21)
+#define VUL30_HPROT_SFT 20
+#define VUL30_HPROT_MASK 0x1
+#define VUL30_HPROT_MASK_SFT (0x1 << 20)
+#define VUL29_HPROT_SFT 19
+#define VUL29_HPROT_MASK 0x1
+#define VUL29_HPROT_MASK_SFT (0x1 << 19)
+#define VUL28_HPROT_SFT 18
+#define VUL28_HPROT_MASK 0x1
+#define VUL28_HPROT_MASK_SFT (0x1 << 18)
+#define VUL27_HPROT_SFT 17
+#define VUL27_HPROT_MASK 0x1
+#define VUL27_HPROT_MASK_SFT (0x1 << 17)
+#define VUL26_HPROT_SFT 16
+#define VUL26_HPROT_MASK 0x1
+#define VUL26_HPROT_MASK_SFT (0x1 << 16)
+#define VUL25_HPROT_SFT 15
+#define VUL25_HPROT_MASK 0x1
+#define VUL25_HPROT_MASK_SFT (0x1 << 15)
+#define VUL24_HPROT_SFT 14
+#define VUL24_HPROT_MASK 0x1
+#define VUL24_HPROT_MASK_SFT (0x1 << 14)
+#define VUL_CM2_HPROT_SFT 13
+#define VUL_CM2_HPROT_MASK 0x1
+#define VUL_CM2_HPROT_MASK_SFT (0x1 << 13)
+#define VUL_CM1_HPROT_SFT 12
+#define VUL_CM1_HPROT_MASK 0x1
+#define VUL_CM1_HPROT_MASK_SFT (0x1 << 12)
+#define VUL_CM0_HPROT_SFT 11
+#define VUL_CM0_HPROT_MASK 0x1
+#define VUL_CM0_HPROT_MASK_SFT (0x1 << 11)
+#define VUL10_HPROT_SFT 10
+#define VUL10_HPROT_MASK 0x1
+#define VUL10_HPROT_MASK_SFT (0x1 << 10)
+#define VUL9_HPROT_SFT 9
+#define VUL9_HPROT_MASK 0x1
+#define VUL9_HPROT_MASK_SFT (0x1 << 9)
+#define VUL8_HPROT_SFT 8
+#define VUL8_HPROT_MASK 0x1
+#define VUL8_HPROT_MASK_SFT (0x1 << 8)
+#define VUL7_HPROT_SFT 7
+#define VUL7_HPROT_MASK 0x1
+#define VUL7_HPROT_MASK_SFT (0x1 << 7)
+#define VUL6_HPROT_SFT 6
+#define VUL6_HPROT_MASK 0x1
+#define VUL6_HPROT_MASK_SFT (0x1 << 6)
+#define VUL5_HPROT_SFT 5
+#define VUL5_HPROT_MASK 0x1
+#define VUL5_HPROT_MASK_SFT (0x1 << 5)
+#define VUL4_HPROT_SFT 4
+#define VUL4_HPROT_MASK 0x1
+#define VUL4_HPROT_MASK_SFT (0x1 << 4)
+#define VUL3_HPROT_SFT 3
+#define VUL3_HPROT_MASK 0x1
+#define VUL3_HPROT_MASK_SFT (0x1 << 3)
+#define VUL2_HPROT_SFT 2
+#define VUL2_HPROT_MASK 0x1
+#define VUL2_HPROT_MASK_SFT (0x1 << 2)
+#define VUL1_HPROT_SFT 1
+#define VUL1_HPROT_MASK 0x1
+#define VUL1_HPROT_MASK_SFT (0x1 << 1)
+#define VUL0_HPROT_SFT 0
+#define VUL0_HPROT_MASK 0x1
+#define VUL0_HPROT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_PROT_SIDEBAND3 */
+#define MPHONE_EARC_HPROT_SFT 10
+#define MPHONE_EARC_HPROT_MASK 0x1
+#define MPHONE_EARC_HPROT_MASK_SFT (0x1 << 10)
+#define MPHONE_SPDIF_HPROT_SFT 9
+#define MPHONE_SPDIF_HPROT_MASK 0x1
+#define MPHONE_SPDIF_HPROT_MASK_SFT (0x1 << 9)
+#define SPDIFIN_HPROT_SFT 8
+#define SPDIFIN_HPROT_MASK 0x1
+#define SPDIFIN_HPROT_MASK_SFT (0x1 << 8)
+#define TDMIN_HPROT_SFT 7
+#define TDMIN_HPROT_MASK 0x1
+#define TDMIN_HPROT_MASK_SFT (0x1 << 7)
+#define ETDM_IN1_HPROT_SFT 1
+#define ETDM_IN1_HPROT_MASK 0x1
+#define ETDM_IN1_HPROT_MASK_SFT (0x1 << 1)
+#define ETDM_IN0_HPROT_SFT 0
+#define ETDM_IN0_HPROT_MASK 0x1
+#define ETDM_IN0_HPROT_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND0 */
+#define DL7_HDOMAIN_SFT 28
+#define DL7_HDOMAIN_MASK 0xf
+#define DL7_HDOMAIN_MASK_SFT (0xf << 28)
+#define DL6_HDOMAIN_SFT 24
+#define DL6_HDOMAIN_MASK 0xf
+#define DL6_HDOMAIN_MASK_SFT (0xf << 24)
+#define DL5_HDOMAIN_SFT 20
+#define DL5_HDOMAIN_MASK 0xf
+#define DL5_HDOMAIN_MASK_SFT (0xf << 20)
+#define DL4_HDOMAIN_SFT 16
+#define DL4_HDOMAIN_MASK 0xf
+#define DL4_HDOMAIN_MASK_SFT (0xf << 16)
+#define DL3_HDOMAIN_SFT 12
+#define DL3_HDOMAIN_MASK 0xf
+#define DL3_HDOMAIN_MASK_SFT (0xf << 12)
+#define DL2_HDOMAIN_SFT 8
+#define DL2_HDOMAIN_MASK 0xf
+#define DL2_HDOMAIN_MASK_SFT (0xf << 8)
+#define DL1_HDOMAIN_SFT 4
+#define DL1_HDOMAIN_MASK 0xf
+#define DL1_HDOMAIN_MASK_SFT (0xf << 4)
+#define DL0_HDOMAIN_SFT 0
+#define DL0_HDOMAIN_MASK 0xf
+#define DL0_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND1 */
+#define DL_48CH_HDOMAIN_SFT 24
+#define DL_48CH_HDOMAIN_MASK 0xf
+#define DL_48CH_HDOMAIN_MASK_SFT (0xf << 24)
+#define DL_24CH_HDOMAIN_SFT 20
+#define DL_24CH_HDOMAIN_MASK 0xf
+#define DL_24CH_HDOMAIN_MASK_SFT (0xf << 20)
+#define DL_4CH_HDOMAIN_SFT 16
+#define DL_4CH_HDOMAIN_MASK 0xf
+#define DL_4CH_HDOMAIN_MASK_SFT (0xf << 16)
+#define HDMI_HDOMAIN_SFT 12
+#define HDMI_HDOMAIN_MASK 0xf
+#define HDMI_HDOMAIN_MASK_SFT (0xf << 12)
+#define SPDIF2_OUT_HDOMAIN_SFT 8
+#define SPDIF2_OUT_HDOMAIN_MASK 0xf
+#define SPDIF2_OUT_HDOMAIN_MASK_SFT (0xf << 8)
+#define SPDIF_OUT_HDOMAIN_SFT 4
+#define SPDIF_OUT_HDOMAIN_MASK 0xf
+#define SPDIF_OUT_HDOMAIN_MASK_SFT (0xf << 4)
+#define DL8_HDOMAIN_SFT 0
+#define DL8_HDOMAIN_MASK 0xf
+#define DL8_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND2 */
+#define DL30_HDOMAIN_SFT 28
+#define DL30_HDOMAIN_MASK 0xf
+#define DL30_HDOMAIN_MASK_SFT (0xf << 28)
+#define DL29_HDOMAIN_SFT 24
+#define DL29_HDOMAIN_MASK 0xf
+#define DL29_HDOMAIN_MASK_SFT (0xf << 24)
+#define DL28_HDOMAIN_SFT 20
+#define DL28_HDOMAIN_MASK 0xf
+#define DL28_HDOMAIN_MASK_SFT (0xf << 20)
+#define DL27_HDOMAIN_SFT 16
+#define DL27_HDOMAIN_MASK 0xf
+#define DL27_HDOMAIN_MASK_SFT (0xf << 16)
+#define DL26_HDOMAIN_SFT 12
+#define DL26_HDOMAIN_MASK 0xf
+#define DL26_HDOMAIN_MASK_SFT (0xf << 12)
+#define DL25_HDOMAIN_SFT 8
+#define DL25_HDOMAIN_MASK 0xf
+#define DL25_HDOMAIN_MASK_SFT (0xf << 8)
+#define DL24_HDOMAIN_SFT 4
+#define DL24_HDOMAIN_MASK 0xf
+#define DL24_HDOMAIN_MASK_SFT (0xf << 4)
+#define DL23_HDOMAIN_SFT 0
+#define DL23_HDOMAIN_MASK 0xf
+#define DL23_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND3 */
+#define DL38_HDOMAIN_SFT 28
+#define DL38_HDOMAIN_MASK 0xf
+#define DL38_HDOMAIN_MASK_SFT (0xf << 28)
+#define DL37_HDOMAIN_SFT 24
+#define DL37_HDOMAIN_MASK 0xf
+#define DL37_HDOMAIN_MASK_SFT (0xf << 24)
+#define DL36_HDOMAIN_SFT 20
+#define DL36_HDOMAIN_MASK 0xf
+#define DL36_HDOMAIN_MASK_SFT (0xf << 20)
+#define DL35_HDOMAIN_SFT 16
+#define DL35_HDOMAIN_MASK 0xf
+#define DL35_HDOMAIN_MASK_SFT (0xf << 16)
+#define DL34_HDOMAIN_SFT 12
+#define DL34_HDOMAIN_MASK 0xf
+#define DL34_HDOMAIN_MASK_SFT (0xf << 12)
+#define DL33_HDOMAIN_SFT 8
+#define DL33_HDOMAIN_MASK 0xf
+#define DL33_HDOMAIN_MASK_SFT (0xf << 8)
+#define DL32_HDOMAIN_SFT 4
+#define DL32_HDOMAIN_MASK 0xf
+#define DL32_HDOMAIN_MASK_SFT (0xf << 4)
+#define DL31_HDOMAIN_SFT 0
+#define DL31_HDOMAIN_MASK 0xf
+#define DL31_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND4 */
+#define DL46_HDOMAIN_SFT 28
+#define DL46_HDOMAIN_MASK 0xf
+#define DL46_HDOMAIN_MASK_SFT (0xf << 28)
+#define DL45_HDOMAIN_SFT 24
+#define DL45_HDOMAIN_MASK 0xf
+#define DL45_HDOMAIN_MASK_SFT (0xf << 24)
+#define DL44_HDOMAIN_SFT 20
+#define DL44_HDOMAIN_MASK 0xf
+#define DL44_HDOMAIN_MASK_SFT (0xf << 20)
+#define DL43_HDOMAIN_SFT 16
+#define DL43_HDOMAIN_MASK 0xf
+#define DL43_HDOMAIN_MASK_SFT (0xf << 16)
+#define DL42_HDOMAIN_SFT 12
+#define DL42_HDOMAIN_MASK 0xf
+#define DL42_HDOMAIN_MASK_SFT (0xf << 12)
+#define DL41_HDOMAIN_SFT 8
+#define DL41_HDOMAIN_MASK 0xf
+#define DL41_HDOMAIN_MASK_SFT (0xf << 8)
+#define DL40_HDOMAIN_SFT 4
+#define DL40_HDOMAIN_MASK 0xf
+#define DL40_HDOMAIN_MASK_SFT (0xf << 4)
+#define DL39_HDOMAIN_SFT 0
+#define DL39_HDOMAIN_MASK 0xf
+#define DL39_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND5 */
+#define VUL7_HDOMAIN_SFT 28
+#define VUL7_HDOMAIN_MASK 0xf
+#define VUL7_HDOMAIN_MASK_SFT (0xf << 28)
+#define VUL6_HDOMAIN_SFT 24
+#define VUL6_HDOMAIN_MASK 0xf
+#define VUL6_HDOMAIN_MASK_SFT (0xf << 24)
+#define VUL5_HDOMAIN_SFT 20
+#define VUL5_HDOMAIN_MASK 0xf
+#define VUL5_HDOMAIN_MASK_SFT (0xf << 20)
+#define VUL4_HDOMAIN_SFT 16
+#define VUL4_HDOMAIN_MASK 0xf
+#define VUL4_HDOMAIN_MASK_SFT (0xf << 16)
+#define VUL3_HDOMAIN_SFT 12
+#define VUL3_HDOMAIN_MASK 0xf
+#define VUL3_HDOMAIN_MASK_SFT (0xf << 12)
+#define VUL2_HDOMAIN_SFT 8
+#define VUL2_HDOMAIN_MASK 0xf
+#define VUL2_HDOMAIN_MASK_SFT (0xf << 8)
+#define VUL1_HDOMAIN_SFT 4
+#define VUL1_HDOMAIN_MASK 0xf
+#define VUL1_HDOMAIN_MASK_SFT (0xf << 4)
+#define VUL0_HDOMAIN_SFT 0
+#define VUL0_HDOMAIN_MASK 0xf
+#define VUL0_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND6 */
+#define VU25_HDOMAIN_SFT 28
+#define VU25_HDOMAIN_MASK 0xf
+#define VU25_HDOMAIN_MASK_SFT (0xf << 28)
+#define VUL24_HDOMAIN_SFT 24
+#define VUL24_HDOMAIN_MASK 0xf
+#define VUL24_HDOMAIN_MASK_SFT (0xf << 24)
+#define VUL_CM2_HDOMAIN_SFT 20
+#define VUL_CM2_HDOMAIN_MASK 0xf
+#define VUL_CM2_HDOMAIN_MASK_SFT (0xf << 20)
+#define VUL_CM1_HDOMAIN_SFT 16
+#define VUL_CM1_HDOMAIN_MASK 0xf
+#define VUL_CM1_HDOMAIN_MASK_SFT (0xf << 16)
+#define VUL_CM0_HDOMAIN_SFT 12
+#define VUL_CM0_HDOMAIN_MASK 0xf
+#define VUL_CM0_HDOMAIN_MASK_SFT (0xf << 12)
+#define VUL10_HDOMAIN_SFT 8
+#define VUL10_HDOMAIN_MASK 0xf
+#define VUL10_HDOMAIN_MASK_SFT (0xf << 8)
+#define VUL9_HDOMAIN_SFT 4
+#define VUL9_HDOMAIN_MASK 0xf
+#define VUL9_HDOMAIN_MASK_SFT (0xf << 4)
+#define VUL8_HDOMAIN_SFT 0
+#define VUL8_HDOMAIN_MASK 0xf
+#define VUL8_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND7 */
+#define VUL33_HDOMAIN_SFT 28
+#define VUL33_HDOMAIN_MASK 0xf
+#define VUL33_HDOMAIN_MASK_SFT (0xf << 28)
+#define VUL32_HDOMAIN_SFT 24
+#define VUL32_HDOMAIN_MASK 0xf
+#define VUL32_HDOMAIN_MASK_SFT (0xf << 24)
+#define VUL31_HDOMAIN_SFT 20
+#define VUL31_HDOMAIN_MASK 0xf
+#define VUL31_HDOMAIN_MASK_SFT (0xf << 20)
+#define VUL30_HDOMAIN_SFT 16
+#define VUL30_HDOMAIN_MASK 0xf
+#define VUL30_HDOMAIN_MASK_SFT (0xf << 16)
+#define VUL29_HDOMAIN_SFT 12
+#define VUL29_HDOMAIN_MASK 0xf
+#define VUL29_HDOMAIN_MASK_SFT (0xf << 12)
+#define VUL28_HDOMAIN_SFT 8
+#define VUL28_HDOMAIN_MASK 0xf
+#define VUL28_HDOMAIN_MASK_SFT (0xf << 8)
+#define VUL27_HDOMAIN_SFT 4
+#define VUL27_HDOMAIN_MASK 0xf
+#define VUL27_HDOMAIN_MASK_SFT (0xf << 4)
+#define VUL26_HDOMAIN_SFT 0
+#define VUL26_HDOMAIN_MASK 0xf
+#define VUL26_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND8 */
+#define ETDM_IN1_HDOMAIN_SFT 24
+#define ETDM_IN1_HDOMAIN_MASK 0xf
+#define ETDM_IN1_HDOMAIN_MASK_SFT (0xf << 24)
+#define ETDM_IN0_HDOMAIN_SFT 20
+#define ETDM_IN0_HDOMAIN_MASK 0xf
+#define ETDM_IN0_HDOMAIN_MASK_SFT (0xf << 20)
+#define VUL38_HDOMAIN_SFT 16
+#define VUL38_HDOMAIN_MASK 0xf
+#define VUL38_HDOMAIN_MASK_SFT (0xf << 16)
+#define VUL37_HDOMAIN_SFT 12
+#define VUL37_HDOMAIN_MASK 0xf
+#define VUL37_HDOMAIN_MASK_SFT (0xf << 12)
+#define VUL36_HDOMAIN_SFT 8
+#define VUL36_HDOMAIN_MASK 0xf
+#define VUL36_HDOMAIN_MASK_SFT (0xf << 8)
+#define VUL35_HDOMAIN_SFT 4
+#define VUL35_HDOMAIN_MASK 0xf
+#define VUL35_HDOMAIN_MASK_SFT (0xf << 4)
+#define VUL34_HDOMAIN_SFT 0
+#define VUL34_HDOMAIN_MASK 0xf
+#define VUL34_HDOMAIN_MASK_SFT (0xf << 0)
+
+/* AFE_SE_DOMAIN_SIDEBAND9 */
+#define MPHONE_EARC_HDOMAIN_SFT 28
+#define MPHONE_EARC_HDOMAIN_MASK 0xf
+#define MPHONE_EARC_HDOMAIN_MASK_SFT (0xf << 28)
+#define MPHONE_SPDIF_HDOMAIN_SFT 24
+#define MPHONE_SPDIF_HDOMAIN_MASK 0xf
+#define MPHONE_SPDIF_HDOMAIN_MASK_SFT (0xf << 24)
+#define SPDIFIN_HDOMAIN_SFT 20
+#define SPDIFIN_HDOMAIN_MASK 0xf
+#define SPDIFIN_HDOMAIN_MASK_SFT (0xf << 20)
+#define TDMIN_HDOMAIN_SFT 16
+#define TDMIN_HDOMAIN_MASK 0xf
+#define TDMIN_HDOMAIN_MASK_SFT (0xf << 16)
+
+/* AFE_PROT_SIDEBAND0_MON */
+#define AFE_DOMAIN_SIDEBAN0_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN0_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN0_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_PROT_SIDEBAND1_MON */
+#define AFE_DOMAIN_SIDEBAN1_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN1_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN1_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_PROT_SIDEBAND2_MON */
+#define AFE_DOMAIN_SIDEBAN2_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_PROT_SIDEBAND3_MON */
+#define AFE_DOMAIN_SIDEBAN3_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND0_MON */
+#define AFE_DOMAIN_SIDEBAN0_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN0_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN0_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND1_MON */
+#define AFE_DOMAIN_SIDEBAN1_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN1_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN1_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND2_MON */
+#define AFE_DOMAIN_SIDEBAN2_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND3_MON */
+#define AFE_DOMAIN_SIDEBAN3_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND4_MON */
+#define AFE_DOMAIN_SIDEBAN0_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN0_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN0_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND5_MON */
+#define AFE_DOMAIN_SIDEBAN1_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN1_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN1_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND6_MON */
+#define AFE_DOMAIN_SIDEBAN2_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND7_MON */
+#define AFE_DOMAIN_SIDEBAN3_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND8_MON */
+#define AFE_DOMAIN_SIDEBAN2_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN2_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_DOMAIN_SIDEBAND9_MON */
+#define AFE_DOMAIN_SIDEBAN3_MON_SFT 0
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK 0xffffffff
+#define AFE_DOMAIN_SIDEBAN3_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SECURE_CONN0 */
+#define AFE_SPDIFIN_LPBK_CON_MASK_S_SFT 26
+#define AFE_SPDIFIN_LPBK_CON_MASK_S_MASK 0x3
+#define AFE_SPDIFIN_LPBK_CON_MASK_S_MASK_SFT (0x3 << 26)
+#define AFE_ADDA_DMIC1_SRC_CON0_MASK_S_SFT 25
+#define AFE_ADDA_DMIC1_SRC_CON0_MASK_S_MASK 0x1
+#define AFE_ADDA_DMIC1_SRC_CON0_MASK_S_MASK_SFT (0x1 << 25)
+#define AFE_ADDA_DMIC0_SRC_CON0_MASK_S_SFT 24
+#define AFE_ADDA_DMIC0_SRC_CON0_MASK_S_MASK 0x1
+#define AFE_ADDA_DMIC0_SRC_CON0_MASK_S_MASK_SFT (0x1 << 24)
+#define AFE_ADDA_UL3_SRC_CON0_MASK_S_SFT 23
+#define AFE_ADDA_UL3_SRC_CON0_MASK_S_MASK 0x1
+#define AFE_ADDA_UL3_SRC_CON0_MASK_S_MASK_SFT (0x1 << 23)
+#define AFE_ADDA_UL2_SRC_CON0_MASK_S_SFT 22
+#define AFE_ADDA_UL2_SRC_CON0_MASK_S_MASK 0x1
+#define AFE_ADDA_UL2_SRC_CON0_MASK_S_MASK_SFT (0x1 << 22)
+#define AFE_ADDA_UL1_SRC_CON0_MASK_S_SFT 21
+#define AFE_ADDA_UL1_SRC_CON0_MASK_S_MASK 0x1
+#define AFE_ADDA_UL1_SRC_CON0_MASK_S_MASK_SFT (0x1 << 21)
+#define AFE_ADDA_UL0_SRC_CON0_MASK_S_SFT 20
+#define AFE_ADDA_UL0_SRC_CON0_MASK_S_MASK 0x1
+#define AFE_ADDA_UL0_SRC_CON0_MASK_S_MASK_SFT (0x1 << 20)
+#define AFE_MRKAIF1_CFG0_MASK_S_SFT 19
+#define AFE_MRKAIF1_CFG0_MASK_S_MASK 0x1
+#define AFE_MRKAIF1_CFG0_MASK_S_MASK_SFT (0x1 << 19)
+#define AFE_MRKAIF0_CFG0_MASK_S_SFT 18
+#define AFE_MRKAIF0_CFG0_MASK_S_MASK 0x1
+#define AFE_MRKAIF0_CFG0_MASK_S_MASK_SFT (0x1 << 18)
+#define AFE_TDMIN_CON1_MASK_S_SFT 17
+#define AFE_TDMIN_CON1_MASK_S_MASK 0x1
+#define AFE_TDMIN_CON1_MASK_S_MASK_SFT (0x1 << 17)
+#define AFE_TDM_CON2_MASK_S_SFT 16
+#define AFE_TDM_CON2_MASK_S_MASK 0x1
+#define AFE_TDM_CON2_MASK_S_MASK_SFT (0x1 << 16)
+#define AFE_DAIBT_CON_MASK_S_SFT 14
+#define AFE_DAIBT_CON_MASK_S_MASK 0x3
+#define AFE_DAIBT_CON_MASK_S_MASK_SFT (0x3 << 14)
+#define AFE_MRGIF_CON_MASK_S_SFT 12
+#define AFE_MRGIF_CON_MASK_S_MASK 0x3
+#define AFE_MRGIF_CON_MASK_S_MASK_SFT (0x3 << 12)
+#define AFE_CONNSYS_I2S_CON_MASK_S_SFT 11
+#define AFE_CONNSYS_I2S_CON_MASK_S_MASK 0x1
+#define AFE_CONNSYS_I2S_CON_MASK_S_MASK_SFT (0x1 << 11)
+#define AFE_PCM1_INFT_CON0_MASK_S_SFT 6
+#define AFE_PCM1_INFT_CON0_MASK_S_MASK 0x1f
+#define AFE_PCM1_INFT_CON0_MASK_S_MASK_SFT (0x1f << 6)
+#define AFE_PCM0_INTF_CON1_MASK_S_SFT 0
+#define AFE_PCM0_INTF_CON1_MASK_S_MASK 0x3f
+#define AFE_PCM0_INTF_CON1_MASK_S_MASK_SFT (0x3f << 0)
+
+/* AFE_SECURE_CONN_ETDM1 */
+#define ETDM1_4_7_COWORK_CON1_MASK_S_0_SFT 24
+#define ETDM1_4_7_COWORK_CON1_MASK_S_0_MASK 0xff
+#define ETDM1_4_7_COWORK_CON1_MASK_S_0_MASK_SFT (0xff << 24)
+#define ETDM1_4_7_COWORK_CON0_MASK_S_0_SFT 20
+#define ETDM1_4_7_COWORK_CON0_MASK_S_0_MASK 0xf
+#define ETDM1_4_7_COWORK_CON0_MASK_S_0_MASK_SFT (0xf << 20)
+#define ETDM1_4_7_COWORK_CON0_MASK_S_1_SFT 16
+#define ETDM1_4_7_COWORK_CON0_MASK_S_1_MASK 0xf
+#define ETDM1_4_7_COWORK_CON0_MASK_S_1_MASK_SFT (0xf << 16)
+#define ETDM1_0_3_COWORK_CON3_MASK_S_0_SFT 8
+#define ETDM1_0_3_COWORK_CON3_MASK_S_0_MASK 0xff
+#define ETDM1_0_3_COWORK_CON3_MASK_S_0_MASK_SFT (0xff << 8)
+#define ETDM1_0_3_COWORK_CON3_MASK_S_1_SFT 0
+#define ETDM1_0_3_COWORK_CON3_MASK_S_1_MASK 0xff
+#define ETDM1_0_3_COWORK_CON3_MASK_S_1_MASK_SFT (0xff << 0)
+
+/* AFE_SECURE_CONN_ETDM2 */
+#define ETDM2_4_7_COWORK_CON3_MASK_S_0_SFT 24
+#define ETDM2_4_7_COWORK_CON3_MASK_S_0_MASK 0xff
+#define ETDM2_4_7_COWORK_CON3_MASK_S_0_MASK_SFT (0xff << 24)
+#define ETDM2_4_7_COWORK_CON3_MASK_S_1_SFT 16
+#define ETDM2_4_7_COWORK_CON3_MASK_S_1_MASK 0xff
+#define ETDM2_4_7_COWORK_CON3_MASK_S_1_MASK_SFT (0xff << 16)
+#define ETDM2_4_7_COWORK_CON2_MASK_S_0_SFT 12
+#define ETDM2_4_7_COWORK_CON2_MASK_S_0_MASK 0xf
+#define ETDM2_4_7_COWORK_CON2_MASK_S_0_MASK_SFT (0xf << 12)
+#define ETDM2_4_7_COWORK_CON2_MASK_S_1_SFT 8
+#define ETDM2_4_7_COWORK_CON2_MASK_S_1_MASK 0xf
+#define ETDM2_4_7_COWORK_CON2_MASK_S_1_MASK_SFT (0xf << 8)
+#define ETDM2_4_7_COWORK_CON1_MASK_S_0_SFT 0
+#define ETDM2_4_7_COWORK_CON1_MASK_S_0_MASK 0xff
+#define ETDM2_4_7_COWORK_CON1_MASK_S_0_MASK_SFT (0xff << 0)
+
+/* AFE_SECURE_SRAM_CON0 */
+#define SRAM_READ_EN15_NS_SFT 31
+#define SRAM_READ_EN15_NS_MASK 0x1
+#define SRAM_READ_EN15_NS_MASK_SFT (0x1 << 31)
+#define SRAM_WRITE_EN15_NS_SFT 30
+#define SRAM_WRITE_EN15_NS_MASK 0x1
+#define SRAM_WRITE_EN15_NS_MASK_SFT (0x1 << 30)
+#define SRAM_READ_EN14_NS_SFT 29
+#define SRAM_READ_EN14_NS_MASK 0x1
+#define SRAM_READ_EN14_NS_MASK_SFT (0x1 << 29)
+#define SRAM_WRITE_EN14_NS_SFT 28
+#define SRAM_WRITE_EN14_NS_MASK 0x1
+#define SRAM_WRITE_EN14_NS_MASK_SFT (0x1 << 28)
+#define SRAM_READ_EN13_NS_SFT 27
+#define SRAM_READ_EN13_NS_MASK 0x1
+#define SRAM_READ_EN13_NS_MASK_SFT (0x1 << 27)
+#define SRAM_WRITE_EN13_NS_SFT 26
+#define SRAM_WRITE_EN13_NS_MASK 0x1
+#define SRAM_WRITE_EN13_NS_MASK_SFT (0x1 << 26)
+#define SRAM_READ_EN12_NS_SFT 25
+#define SRAM_READ_EN12_NS_MASK 0x1
+#define SRAM_READ_EN12_NS_MASK_SFT (0x1 << 25)
+#define SRAM_WRITE_EN12_NS_SFT 24
+#define SRAM_WRITE_EN12_NS_MASK 0x1
+#define SRAM_WRITE_EN12_NS_MASK_SFT (0x1 << 24)
+#define SRAM_READ_EN11_NS_SFT 23
+#define SRAM_READ_EN11_NS_MASK 0x1
+#define SRAM_READ_EN11_NS_MASK_SFT (0x1 << 23)
+#define SRAM_WRITE_EN11_NS_SFT 22
+#define SRAM_WRITE_EN11_NS_MASK 0x1
+#define SRAM_WRITE_EN11_NS_MASK_SFT (0x1 << 22)
+#define SRAM_READ_EN10_NS_SFT 21
+#define SRAM_READ_EN10_NS_MASK 0x1
+#define SRAM_READ_EN10_NS_MASK_SFT (0x1 << 21)
+#define SRAM_WRITE_EN10_NS_SFT 20
+#define SRAM_WRITE_EN10_NS_MASK 0x1
+#define SRAM_WRITE_EN10_NS_MASK_SFT (0x1 << 20)
+#define SRAM_READ_EN9_NS_SFT 19
+#define SRAM_READ_EN9_NS_MASK 0x1
+#define SRAM_READ_EN9_NS_MASK_SFT (0x1 << 19)
+#define SRAM_WRITE_EN9_NS_SFT 18
+#define SRAM_WRITE_EN9_NS_MASK 0x1
+#define SRAM_WRITE_EN9_NS_MASK_SFT (0x1 << 18)
+#define SRAM_READ_EN8_NS_SFT 17
+#define SRAM_READ_EN8_NS_MASK 0x1
+#define SRAM_READ_EN8_NS_MASK_SFT (0x1 << 17)
+#define SRAM_WRITE_EN8_NS_SFT 16
+#define SRAM_WRITE_EN8_NS_MASK 0x1
+#define SRAM_WRITE_EN8_NS_MASK_SFT (0x1 << 16)
+#define SRAM_READ_EN7_NS_SFT 15
+#define SRAM_READ_EN7_NS_MASK 0x1
+#define SRAM_READ_EN7_NS_MASK_SFT (0x1 << 15)
+#define SRAM_WRITE_EN7_NS_SFT 14
+#define SRAM_WRITE_EN7_NS_MASK 0x1
+#define SRAM_WRITE_EN7_NS_MASK_SFT (0x1 << 14)
+#define SRAM_READ_EN6_NS_SFT 13
+#define SRAM_READ_EN6_NS_MASK 0x1
+#define SRAM_READ_EN6_NS_MASK_SFT (0x1 << 13)
+#define SRAM_WRITE_EN6_NS_SFT 12
+#define SRAM_WRITE_EN6_NS_MASK 0x1
+#define SRAM_WRITE_EN6_NS_MASK_SFT (0x1 << 12)
+#define SRAM_READ_EN5_NS_SFT 11
+#define SRAM_READ_EN5_NS_MASK 0x1
+#define SRAM_READ_EN5_NS_MASK_SFT (0x1 << 11)
+#define SRAM_WRITE_EN5_NS_SFT 10
+#define SRAM_WRITE_EN5_NS_MASK 0x1
+#define SRAM_WRITE_EN5_NS_MASK_SFT (0x1 << 10)
+#define SRAM_READ_EN4_NS_SFT 9
+#define SRAM_READ_EN4_NS_MASK 0x1
+#define SRAM_READ_EN4_NS_MASK_SFT (0x1 << 9)
+#define SRAM_WRITE_EN4_NS_SFT 8
+#define SRAM_WRITE_EN4_NS_MASK 0x1
+#define SRAM_WRITE_EN4_NS_MASK_SFT (0x1 << 8)
+#define SRAM_READ_EN3_NS_SFT 7
+#define SRAM_READ_EN3_NS_MASK 0x1
+#define SRAM_READ_EN3_NS_MASK_SFT (0x1 << 7)
+#define SRAM_WRITE_EN3_NS_SFT 6
+#define SRAM_WRITE_EN3_NS_MASK 0x1
+#define SRAM_WRITE_EN3_NS_MASK_SFT (0x1 << 6)
+#define SRAM_READ_EN2_NS_SFT 5
+#define SRAM_READ_EN2_NS_MASK 0x1
+#define SRAM_READ_EN2_NS_MASK_SFT (0x1 << 5)
+#define SRAM_WRITE_EN2_NS_SFT 4
+#define SRAM_WRITE_EN2_NS_MASK 0x1
+#define SRAM_WRITE_EN2_NS_MASK_SFT (0x1 << 4)
+#define SRAM_READ_EN1_NS_SFT 3
+#define SRAM_READ_EN1_NS_MASK 0x1
+#define SRAM_READ_EN1_NS_MASK_SFT (0x1 << 3)
+#define SRAM_WRITE_EN1_NS_SFT 2
+#define SRAM_WRITE_EN1_NS_MASK 0x1
+#define SRAM_WRITE_EN1_NS_MASK_SFT (0x1 << 2)
+#define SRAM_READ_EN0_NS_SFT 1
+#define SRAM_READ_EN0_NS_MASK 0x1
+#define SRAM_READ_EN0_NS_MASK_SFT (0x1 << 1)
+#define SRAM_WRITE_EN0_NS_SFT 0
+#define SRAM_WRITE_EN0_NS_MASK 0x1
+#define SRAM_WRITE_EN0_NS_MASK_SFT (0x1 << 0)
+
+/* AFE_SECURE_SRAM_CON1 */
+#define SRAM_READ_EN15_S_SFT 31
+#define SRAM_READ_EN15_S_MASK 0x1
+#define SRAM_READ_EN15_S_MASK_SFT (0x1 << 31)
+#define SRAM_WRITE_EN15_S_SFT 30
+#define SRAM_WRITE_EN15_S_MASK 0x1
+#define SRAM_WRITE_EN15_S_MASK_SFT (0x1 << 30)
+#define SRAM_READ_EN14_S_SFT 29
+#define SRAM_READ_EN14_S_MASK 0x1
+#define SRAM_READ_EN14_S_MASK_SFT (0x1 << 29)
+#define SRAM_WRITE_EN14_S_SFT 28
+#define SRAM_WRITE_EN14_S_MASK 0x1
+#define SRAM_WRITE_EN14_S_MASK_SFT (0x1 << 28)
+#define SRAM_READ_EN13_S_SFT 27
+#define SRAM_READ_EN13_S_MASK 0x1
+#define SRAM_READ_EN13_S_MASK_SFT (0x1 << 27)
+#define SRAM_WRITE_EN13_S_SFT 26
+#define SRAM_WRITE_EN13_S_MASK 0x1
+#define SRAM_WRITE_EN13_S_MASK_SFT (0x1 << 26)
+#define SRAM_READ_EN12_S_SFT 25
+#define SRAM_READ_EN12_S_MASK 0x1
+#define SRAM_READ_EN12_S_MASK_SFT (0x1 << 25)
+#define SRAM_WRITE_EN12_S_SFT 24
+#define SRAM_WRITE_EN12_S_MASK 0x1
+#define SRAM_WRITE_EN12_S_MASK_SFT (0x1 << 24)
+#define SRAM_READ_EN11_S_SFT 23
+#define SRAM_READ_EN11_S_MASK 0x1
+#define SRAM_READ_EN11_S_MASK_SFT (0x1 << 23)
+#define SRAM_WRITE_EN11_S_SFT 22
+#define SRAM_WRITE_EN11_S_MASK 0x1
+#define SRAM_WRITE_EN11_S_MASK_SFT (0x1 << 22)
+#define SRAM_READ_EN10_S_SFT 21
+#define SRAM_READ_EN10_S_MASK 0x1
+#define SRAM_READ_EN10_S_MASK_SFT (0x1 << 21)
+#define SRAM_WRITE_EN10_S_SFT 20
+#define SRAM_WRITE_EN10_S_MASK 0x1
+#define SRAM_WRITE_EN10_S_MASK_SFT (0x1 << 20)
+#define SRAM_READ_EN9_S_SFT 19
+#define SRAM_READ_EN9_S_MASK 0x1
+#define SRAM_READ_EN9_S_MASK_SFT (0x1 << 19)
+#define SRAM_WRITE_EN9_S_SFT 18
+#define SRAM_WRITE_EN9_S_MASK 0x1
+#define SRAM_WRITE_EN9_S_MASK_SFT (0x1 << 18)
+#define SRAM_READ_EN8_S_SFT 17
+#define SRAM_READ_EN8_S_MASK 0x1
+#define SRAM_READ_EN8_S_MASK_SFT (0x1 << 17)
+#define SRAM_WRITE_EN8_S_SFT 16
+#define SRAM_WRITE_EN8_S_MASK 0x1
+#define SRAM_WRITE_EN8_S_MASK_SFT (0x1 << 16)
+#define SRAM_READ_EN7_S_SFT 15
+#define SRAM_READ_EN7_S_MASK 0x1
+#define SRAM_READ_EN7_S_MASK_SFT (0x1 << 15)
+#define SRAM_WRITE_EN7_S_SFT 14
+#define SRAM_WRITE_EN7_S_MASK 0x1
+#define SRAM_WRITE_EN7_S_MASK_SFT (0x1 << 14)
+#define SRAM_READ_EN6_S_SFT 13
+#define SRAM_READ_EN6_S_MASK 0x1
+#define SRAM_READ_EN6_S_MASK_SFT (0x1 << 13)
+#define SRAM_WRITE_EN6_S_SFT 12
+#define SRAM_WRITE_EN6_S_MASK 0x1
+#define SRAM_WRITE_EN6_S_MASK_SFT (0x1 << 12)
+#define SRAM_READ_EN5_S_SFT 11
+#define SRAM_READ_EN5_S_MASK 0x1
+#define SRAM_READ_EN5_S_MASK_SFT (0x1 << 11)
+#define SRAM_WRITE_EN5_S_SFT 10
+#define SRAM_WRITE_EN5_S_MASK 0x1
+#define SRAM_WRITE_EN5_S_MASK_SFT (0x1 << 10)
+#define SRAM_READ_EN4_S_SFT 9
+#define SRAM_READ_EN4_S_MASK 0x1
+#define SRAM_READ_EN4_S_MASK_SFT (0x1 << 9)
+#define SRAM_WRITE_EN4_S_SFT 8
+#define SRAM_WRITE_EN4_S_MASK 0x1
+#define SRAM_WRITE_EN4_S_MASK_SFT (0x1 << 8)
+#define SRAM_READ_EN3_S_SFT 7
+#define SRAM_READ_EN3_S_MASK 0x1
+#define SRAM_READ_EN3_S_MASK_SFT (0x1 << 7)
+#define SRAM_WRITE_EN3_S_SFT 6
+#define SRAM_WRITE_EN3_S_MASK 0x1
+#define SRAM_WRITE_EN3_S_MASK_SFT (0x1 << 6)
+#define SRAM_READ_EN2_S_SFT 5
+#define SRAM_READ_EN2_S_MASK 0x1
+#define SRAM_READ_EN2_S_MASK_SFT (0x1 << 5)
+#define SRAM_WRITE_EN2_S_SFT 4
+#define SRAM_WRITE_EN2_S_MASK 0x1
+#define SRAM_WRITE_EN2_S_MASK_SFT (0x1 << 4)
+#define SRAM_READ_EN1_S_SFT 3
+#define SRAM_READ_EN1_S_MASK 0x1
+#define SRAM_READ_EN1_S_MASK_SFT (0x1 << 3)
+#define SRAM_WRITE_EN1_S_SFT 2
+#define SRAM_WRITE_EN1_S_MASK 0x1
+#define SRAM_WRITE_EN1_S_MASK_SFT (0x1 << 2)
+#define SRAM_READ_EN0_S_SFT 1
+#define SRAM_READ_EN0_S_MASK 0x1
+#define SRAM_READ_EN0_S_MASK_SFT (0x1 << 1)
+#define SRAM_WRITE_EN0_S_SFT 0
+#define SRAM_WRITE_EN0_S_MASK 0x1
+#define SRAM_WRITE_EN0_S_MASK_SFT (0x1 << 0)
+
+/* AFE_SE_CONN_INPUT_MASK0 */
+#define SECURE_INTRCONN_I0_I31_S_SFT 0
+#define SECURE_INTRCONN_I0_I31_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I0_I31_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK1 */
+#define SECURE_INTRCONN_I32_I63_S_SFT 0
+#define SECURE_INTRCONN_I32_I63_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I32_I63_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK2 */
+#define SECURE_INTRCONN_I64_I95_S_SFT 0
+#define SECURE_INTRCONN_I64_I95_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I64_I95_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK3 */
+#define SECURE_INTRCONN_I96_I127_S_SFT 0
+#define SECURE_INTRCONN_I96_I127_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I96_I127_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK4 */
+#define SECURE_INTRCONN_I128_I159_S_SFT 0
+#define SECURE_INTRCONN_I128_I159_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I128_I159_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK5 */
+#define SECURE_INTRCONN_I160_I191_S_SFT 0
+#define SECURE_INTRCONN_I160_I191_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I160_I191_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK6 */
+#define SECURE_INTRCONN_I192_I223_S_SFT 0
+#define SECURE_INTRCONN_I192_I223_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I192_I223_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_INPUT_MASK7 */
+#define SECURE_INTRCONN_I224_I256_S_SFT 0
+#define SECURE_INTRCONN_I224_I256_S_MASK 0xffffffff
+#define SECURE_INTRCONN_I224_I256_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK0 */
+#define NORMAL_INTRCONN_I0_I31_S_SFT 0
+#define NORMAL_INTRCONN_I0_I31_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I0_I31_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK1 */
+#define NORMAL_INTRCONN_I32_I63_S_SFT 0
+#define NORMAL_INTRCONN_I32_I63_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I32_I63_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK2 */
+#define NORMAL_INTRCONN_I64_I95_S_SFT 0
+#define NORMAL_INTRCONN_I64_I95_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I64_I95_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK3 */
+#define NORMAL_INTRCONN_I96_I127_S_SFT 0
+#define NORMAL_INTRCONN_I96_I127_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I96_I127_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK4 */
+#define NORMAL_INTRCONN_I128_I159_S_SFT 0
+#define NORMAL_INTRCONN_I128_I159_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I128_I159_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK5 */
+#define NORMAL_INTRCONN_I160_I191_S_SFT 0
+#define NORMAL_INTRCONN_I160_I191_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I160_I191_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK6 */
+#define NORMAL_INTRCONN_I192_I223_S_SFT 0
+#define NORMAL_INTRCONN_I192_I223_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I192_I223_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_NON_SE_CONN_INPUT_MASK7 */
+#define NORMAL_INTRCONN_I224_I256_S_SFT 0
+#define NORMAL_INTRCONN_I224_I256_S_MASK 0xffffffff
+#define NORMAL_INTRCONN_I224_I256_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL0 */
+#define SECURE_INTRCONN_O0_O31_S_SFT 0
+#define SECURE_INTRCONN_O0_O31_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O0_O31_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL1 */
+#define SECURE_INTRCONN_O32_O63_S_SFT 0
+#define SECURE_INTRCONN_O32_O63_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O32_O63_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL2 */
+#define SECURE_INTRCONN_O64_O95_S_SFT 0
+#define SECURE_INTRCONN_O64_O95_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O64_O95_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL3 */
+#define SECURE_INTRCONN_O96_O127_S_SFT 0
+#define SECURE_INTRCONN_O96_O127_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O96_O127_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL4 */
+#define SECURE_INTRCONN_O128_O159_S_SFT 0
+#define SECURE_INTRCONN_O128_O159_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O128_O159_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL5 */
+#define SECURE_INTRCONN_O160_O191_S_SFT 0
+#define SECURE_INTRCONN_O160_O191_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O160_O191_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL6 */
+#define SECURE_INTRCONN_O192_O223_S_SFT 0
+#define SECURE_INTRCONN_O192_O223_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O192_O223_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_SE_CONN_OUTPUT_SEL7 */
+#define SECURE_INTRCONN_O224_O256_S_SFT 0
+#define SECURE_INTRCONN_O224_O256_S_MASK 0xffffffff
+#define SECURE_INTRCONN_O224_O256_S_MASK_SFT (0xffffffff << 0)
+
+/* AFE_PCM0_INTF_CON1_MASK_MON */
+#define AFE_PCM0_INTF_CON1_MASK_MON_SFT 0
+#define AFE_PCM0_INTF_CON1_MASK_MON_MASK 0xffffffff
+#define AFE_PCM0_INTF_CON1_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_PCM0_INTF_CON0_MASK_MON */
+#define AFE_PCM0_INTF_CON0_MASK_MON_SFT 0
+#define AFE_PCM0_INTF_CON0_MASK_MON_MASK 0xffffffff
+#define AFE_PCM0_INTF_CON0_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_CONNSYS_I2S_CON_MASK_MON */
+#define AFE_CONNSYS_I2S_CON_MASK_MON_SFT 0
+#define AFE_CONNSYS_I2S_CON_MASK_MON_MASK 0xffffffff
+#define AFE_CONNSYS_I2S_CON_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_MTKAIF0_CFG0_MASK_MON */
+#define AFE_MTKAIF0_CFG0_MASK_MON_SFT 0
+#define AFE_MTKAIF0_CFG0_MASK_MON_MASK 0xffffffff
+#define AFE_MTKAIF0_CFG0_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_MTKAIF1_CFG0_MASK_MON */
+#define AFE_MTKAIF1_CFG0_MASK_MON_SFT 0
+#define AFE_MTKAIF1_CFG0_MASK_MON_MASK 0xffffffff
+#define AFE_MTKAIF1_CFG0_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL0_SRC_CON0_MASK_MON */
+#define AFE_ADDA_UL0_SRC_CON0_MASK_MON_SFT 0
+#define AFE_ADDA_UL0_SRC_CON0_MASK_MON_MASK 0xffffffff
+#define AFE_ADDA_UL0_SRC_CON0_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_ADDA_UL1_SRC_CON0_MASK_MON */
+#define AFE_ADDA_UL1_SRC_CON0_MASK_MON_SFT 0
+#define AFE_ADDA_UL1_SRC_CON0_MASK_MON_MASK 0xffffffff
+#define AFE_ADDA_UL1_SRC_CON0_MASK_MON_MASK_SFT (0xffffffff << 0)
+
+/* AFE_GASRC0_NEW_CON0 */
+#define ONE_HEART_SFT 31
+#define ONE_HEART_MASK 0x1
+#define ONE_HEART_MASK_SFT (0x1 << 31)
+#define CHSET0_OFS_ONE_HEART_DISABLE_SFT 30
+#define CHSET0_OFS_ONE_HEART_DISABLE_MASK 0x1
+#define CHSET0_OFS_ONE_HEART_DISABLE_MASK_SFT (0x1 << 30)
+#define USE_SHORT_DELAY_COEFF_SFT 29
+#define USE_SHORT_DELAY_COEFF_MASK 0x1
+#define USE_SHORT_DELAY_COEFF_MASK_SFT (0x1 << 29)
+#define CHSET0_O16BIT_SFT 19
+#define CHSET0_O16BIT_MASK 0x1
+#define CHSET0_O16BIT_MASK_SFT (0x1 << 19)
+#define CHSET0_CLR_IIR_HISTORY_SFT 17
+#define CHSET0_CLR_IIR_HISTORY_MASK 0x1
+#define CHSET0_CLR_IIR_HISTORY_MASK_SFT (0x1 << 17)
+#define CHSET0_IS_MONO_SFT 16
+#define CHSET0_IS_MONO_MASK 0x1
+#define CHSET0_IS_MONO_MASK_SFT (0x1 << 16)
+#define CHSET0_OFS_SEL_SFT 14
+#define CHSET0_OFS_SEL_MASK 0x3
+#define CHSET0_OFS_SEL_MASK_SFT (0x3 << 14)
+#define CHSET0_IFS_SEL_SFT 12
+#define CHSET0_IFS_SEL_MASK 0x3
+#define CHSET0_IFS_SEL_MASK_SFT (0x3 << 12)
+#define CHSET0_IIR_EN_SFT 11
+#define CHSET0_IIR_EN_MASK 0x1
+#define CHSET0_IIR_EN_MASK_SFT (0x1 << 11)
+#define CHSET0_IIR_STAGE_SFT 8
+#define CHSET0_IIR_STAGE_MASK 0x7
+#define CHSET0_IIR_STAGE_MASK_SFT (0x7 << 8)
+#define ASM_ON_MOD_SFT 7
+#define ASM_ON_MOD_MASK 0x1
+#define ASM_ON_MOD_MASK_SFT (0x1 << 7)
+#define CHSET_STR_CLR_SFT 4
+#define CHSET_STR_CLR_MASK 0x1
+#define CHSET_STR_CLR_MASK_SFT (0x1 << 4)
+#define CHSET_ON_SFT 2
+#define CHSET_ON_MASK 0x1
+#define CHSET_ON_MASK_SFT (0x1 << 2)
+#define COEFF_SRAM_CTRL_SFT 1
+#define COEFF_SRAM_CTRL_MASK 0x1
+#define COEFF_SRAM_CTRL_MASK_SFT (0x1 << 1)
+#define ASM_ON_SFT 0
+#define ASM_ON_MASK 0x1
+#define ASM_ON_MASK_SFT (0x1 << 0)
+
+/* AFE_GASRC0_NEW_CON1 */
+#define ASM_FREQ_0_SFT 0
+#define ASM_FREQ_0_MASK 0xffffff
+#define ASM_FREQ_0_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON2 */
+#define ASM_FREQ_1_SFT 0
+#define ASM_FREQ_1_MASK 0xffffff
+#define ASM_FREQ_1_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON3 */
+#define ASM_FREQ_2_SFT 0
+#define ASM_FREQ_2_MASK 0xffffff
+#define ASM_FREQ_2_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON4 */
+#define ASM_FREQ_3_SFT 0
+#define ASM_FREQ_3_MASK 0xffffff
+#define ASM_FREQ_3_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON5 */
+#define OUT_EN_SEL_DOMAIN_SFT 29
+#define OUT_EN_SEL_DOMAIN_MASK 0x7
+#define OUT_EN_SEL_DOMAIN_MASK_SFT (0x7 << 29)
+#define OUT_EN_SEL_FS_SFT 24
+#define OUT_EN_SEL_FS_MASK 0x1f
+#define OUT_EN_SEL_FS_MASK_SFT (0x1f << 24)
+#define IN_EN_SEL_DOMAIN_SFT 21
+#define IN_EN_SEL_DOMAIN_MASK 0x7
+#define IN_EN_SEL_DOMAIN_MASK_SFT (0x7 << 21)
+#define IN_EN_SEL_FS_SFT 16
+#define IN_EN_SEL_FS_MASK 0x1f
+#define IN_EN_SEL_FS_MASK_SFT (0x1f << 16)
+#define RESULT_SEL_SFT 8
+#define RESULT_SEL_MASK 0x7
+#define RESULT_SEL_MASK_SFT (0x7 << 8)
+#define CALI_CK_SEL_SFT 4
+#define CALI_CK_SEL_MASK 0x7
+#define CALI_CK_SEL_MASK_SFT (0x7 << 4)
+#define CALI_LRCK_SEL_SFT 1
+#define CALI_LRCK_SEL_MASK 0x7
+#define CALI_LRCK_SEL_MASK_SFT (0x7 << 1)
+#define SOFT_RESET_SFT 0
+#define SOFT_RESET_MASK 0x1
+#define SOFT_RESET_MASK_SFT (0x1 << 0)
+
+/* AFE_GASRC0_NEW_CON6 */
+#define FREQ_CALI_CYCLE_SFT 16
+#define FREQ_CALI_CYCLE_MASK 0xffff
+#define FREQ_CALI_CYCLE_MASK_SFT (0xffff << 16)
+#define FREQ_CALI_AUTORST_EN_SFT 15
+#define FREQ_CALI_AUTORST_EN_MASK 0x1
+#define FREQ_CALI_AUTORST_EN_MASK_SFT (0x1 << 15)
+#define CALI_AUTORST_DETECT_SFT 14
+#define CALI_AUTORST_DETECT_MASK 0x1
+#define CALI_AUTORST_DETECT_MASK_SFT (0x1 << 14)
+#define FREQ_CALC_RUNNING_SFT 13
+#define FREQ_CALC_RUNNING_MASK 0x1
+#define FREQ_CALC_RUNNING_MASK_SFT (0x1 << 13)
+#define AUTO_TUNE_FREQ3_SFT 12
+#define AUTO_TUNE_FREQ3_MASK 0x1
+#define AUTO_TUNE_FREQ3_MASK_SFT (0x1 << 12)
+#define COMP_FREQ_RES_EN_SFT 11
+#define COMP_FREQ_RES_EN_MASK 0x1
+#define COMP_FREQ_RES_EN_MASK_SFT (0x1 << 11)
+#define FREQ_CALI_SEL_SFT 8
+#define FREQ_CALI_SEL_MASK 0x3
+#define FREQ_CALI_SEL_MASK_SFT (0x3 << 8)
+#define FREQ_CALI_BP_DGL_SFT 7
+#define FREQ_CALI_BP_DGL_MASK 0x1
+#define FREQ_CALI_BP_DGL_MASK_SFT (0x1 << 7)
+#define FREQ_CALI_MAX_GWIDTH_SFT 4
+#define FREQ_CALI_MAX_GWIDTH_MASK 0x7
+#define FREQ_CALI_MAX_GWIDTH_MASK_SFT (0x7 << 4)
+#define AUTO_TUNE_FREQ2_SFT 3
+#define AUTO_TUNE_FREQ2_MASK 0x1
+#define AUTO_TUNE_FREQ2_MASK_SFT (0x1 << 3)
+#define FREQ_CALI_AUTO_RESTART_SFT 2
+#define FREQ_CALI_AUTO_RESTART_MASK 0x1
+#define FREQ_CALI_AUTO_RESTART_MASK_SFT (0x1 << 2)
+#define CALI_USE_FREQ_OUT_SFT 1
+#define CALI_USE_FREQ_OUT_MASK 0x1
+#define CALI_USE_FREQ_OUT_MASK_SFT (0x1 << 1)
+#define CALI_EN_SFT 0
+#define CALI_EN_MASK 0x1
+#define CALI_EN_MASK_SFT (0x1 << 0)
+
+/* AFE_GASRC0_NEW_CON7 */
+#define FREQ_CALC_DENOMINATOR_SFT 0
+#define FREQ_CALC_DENOMINATOR_MASK 0xffffff
+#define FREQ_CALC_DENOMINATOR_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON8 */
+#define PRD_CALI_RESULT_RECORD_SFT 0
+#define PRD_CALI_RESULT_RECORD_MASK 0xffffff
+#define PRD_CALI_RESULT_RECORD_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON9 */
+#define FREQ_CALI_RESULT_SFT 0
+#define FREQ_CALI_RESULT_MASK 0xffffff
+#define FREQ_CALI_RESULT_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON10 */
+#define COEFF_SRAM_DATA_SFT 0
+#define COEFF_SRAM_DATA_MASK 0xffffffff
+#define COEFF_SRAM_DATA_MASK_SFT (0xffffffff << 0)
+
+/* AFE_GASRC0_NEW_CON11 */
+#define COEFF_SRAM_ADR_SFT 0
+#define COEFF_SRAM_ADR_MASK 0x3f
+#define COEFF_SRAM_ADR_MASK_SFT (0x3f << 0)
+
+/* AFE_GASRC0_NEW_CON12 */
+#define RING_DBG_RD_SFT 0
+#define RING_DBG_RD_MASK 0x3ffffff
+#define RING_DBG_RD_MASK_SFT (0x3ffffff << 0)
+
+/* AFE_GASRC0_NEW_CON13 */
+#define FREQ_CALI_AUTORST_TH_HIGH_SFT 0
+#define FREQ_CALI_AUTORST_TH_HIGH_MASK 0xffffff
+#define FREQ_CALI_AUTORST_TH_HIGH_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_CON14 */
+#define FREQ_CALI_AUTORST_TH_LOW_SFT 0
+#define FREQ_CALI_AUTORST_TH_LOW_MASK 0xffffff
+#define FREQ_CALI_AUTORST_TH_LOW_MASK_SFT (0xffffff << 0)
+
+/* AFE_GASRC0_NEW_IP_VERSION */
+#define IP_VERSION_SFT 0
+#define IP_VERSION_MASK 0xffffffff
+#define IP_VERSION_MASK_SFT (0xffffffff << 0)
+
+#define AUDIO_TOP_CON0 0x0
+#define AUDIO_TOP_CON1 0x4
+#define AUDIO_TOP_CON2 0x8
+#define AUDIO_TOP_CON3 0xc
+#define AUDIO_TOP_CON4 0x10
+#define AUDIO_ENGEN_CON0 0x14
+#define AUDIO_ENGEN_CON0_USER1 0x18
+#define AUDIO_ENGEN_CON0_USER2 0x1c
+#define AFE_SINEGEN_CON0 0x20
+#define AFE_SINEGEN_CON1 0x24
+#define AFE_SINEGEN_CON2 0x28
+#define AFE_SINEGEN_CON3 0x2c
+#define AFE_APLL1_TUNER_CFG 0x30
+#define AFE_APLL1_TUNER_MON0 0x34
+#define AFE_APLL2_TUNER_CFG 0x38
+#define AFE_APLL2_TUNER_MON0 0x3c
+#define AUDIO_TOP_RG0 0x4c
+#define AUDIO_TOP_RG1 0x50
+#define AUDIO_TOP_RG2 0x54
+#define AUDIO_TOP_RG3 0x58
+#define AUDIO_TOP_RG4 0x5c
+#define AFE_SPM_CONTROL_REQ 0x60
+#define AFE_SPM_CONTROL_ACK 0x64
+#define AUD_TOP_CFG_VCORE_RG 0x68
+#define AUDIO_TOP_IP_VERSION 0x6c
+#define AUDIO_ENGEN_CON0_MON 0x7c
+#define AUDIO_PROJECT_MON 0x80
+#define AUD_TOP_CFG_VLP_RG 0x98
+#define AUD_TOP_MON_RG 0x9c
+#define AUDIO_USE_DEFAULT_DELSEL0 0xa0
+#define AUDIO_USE_DEFAULT_DELSEL1 0xa4
+#define AUDIO_USE_DEFAULT_DELSEL2 0xa8
+#define AFE_CONNSYS_I2S_IPM_VER_MON 0xb0
+#define AFE_CONNSYS_I2S_MON_SEL 0xb4
+#define AFE_CONNSYS_I2S_MON 0xb8
+#define AFE_CONNSYS_I2S_CON 0xbc
+#define AFE_PCM0_INTF_CON0 0xc0
+#define AFE_PCM0_INTF_CON1 0xc4
+#define AFE_PCM_INTF_MON 0xc8
+#define AFE_PCM_TOP_IP_VERSION 0xe8
+#define AFE_GAIN0_CON0 0x400
+#define AFE_GAIN0_CON1_R 0x404
+#define AFE_GAIN0_CON1_L 0x408
+#define AFE_GAIN0_CON2 0x40c
+#define AFE_GAIN0_CON3 0x410
+#define AFE_GAIN0_CUR_R 0x414
+#define AFE_GAIN0_CUR_L 0x418
+#define AFE_GAIN1_CON0 0x41c
+#define AFE_GAIN1_CON1_R 0x420
+#define AFE_GAIN1_CON1_L 0x424
+#define AFE_GAIN1_CON2 0x428
+#define AFE_GAIN1_CON3 0x42c
+#define AFE_GAIN1_CUR_R 0x430
+#define AFE_GAIN1_CUR_L 0x434
+#define AFE_GAIN2_CON0 0x438
+#define AFE_GAIN2_CON1_R 0x43c
+#define AFE_GAIN2_CON1_L 0x440
+#define AFE_GAIN2_CON2 0x444
+#define AFE_GAIN2_CON3 0x448
+#define AFE_GAIN2_CUR_R 0x44c
+#define AFE_GAIN2_CUR_L 0x450
+#define AFE_GAIN3_CON0 0x454
+#define AFE_GAIN3_CON1_R 0x458
+#define AFE_GAIN3_CON1_L 0x45c
+#define AFE_GAIN3_CON2 0x460
+#define AFE_GAIN3_CON3 0x464
+#define AFE_GAIN3_CUR_R 0x468
+#define AFE_GAIN3_CUR_L 0x46c
+#define AFE_GAIN_0_1_IP_VERSION 0x474
+#define AFE_GAIN_2_3_IP_VERSION 0x478
+#define AFE_ADDA_DL_IPM_VER_MON 0x4c0
+#define AFE_ADDA_DL_SRC_CON0 0x4d0
+#define AFE_ADDA_DL_SRC_CON1 0x4d4
+#define AFE_ADDA_DL_SRC_DEBUG_MON0 0x4d8
+#define AFE_ADDA_DL_PREDIS_CON0 0x4dc
+#define AFE_ADDA_DL_PREDIS_CON1 0x4e0
+#define AFE_ADDA_DL_PREDIS_CON2 0x4e4
+#define AFE_ADDA_DL_PREDIS_CON3 0x4e8
+#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x4ec
+#define AFE_ADDA_DL_SDM_TEST 0x4f0
+#define AFE_ADDA_DL_DC_COMP_CFG0 0x4f4
+#define AFE_ADDA_DL_DC_COMP_CFG1 0x4f8
+#define AFE_ADDA_DL_SDM_OUT_MON 0x4fc
+#define AFE_ADDA_DL_SRC_LCH_MON 0x500
+#define AFE_ADDA_DL_SRC_RCH_MON 0x504
+#define AFE_ADDA_DL_SRC_DEBUG 0x508
+#define AFE_ADDA_DL_SDM_DITHER_CON 0x50c
+#define AFE_ADDA_DL_SDM_AUTO_RESET_CON 0x510
+#define AFE_ADDA_DL_HBF1_SCF1_CONFIG 0x514
+#define AFE_ADDA_DL_HBF1_SCF1_TAP1_TAP2_CONFIG 0x518
+#define AFE_ADDA_DL_HBF1_SCF1_TAP3_TAP4_CONFIG 0x51c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP5_TAP6_CONFIG 0x520
+#define AFE_ADDA_DL_HBF1_SCF1_TAP7_TAP8_CONFIG 0x524
+#define AFE_ADDA_DL_HBF1_SCF1_TAP9_TAP10_CONFIG 0x528
+#define AFE_ADDA_DL_HBF1_SCF1_TAP11_TAP12_CONFIG 0x52c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP13_TAP14_CONFIG 0x530
+#define AFE_ADDA_DL_HBF1_SCF1_TAP15_TAP16_CONFIG 0x534
+#define AFE_ADDA_DL_HBF1_SCF1_TAP17_TAP18_CONFIG 0x538
+#define AFE_ADDA_DL_HBF1_SCF1_TAP19_TAP20_CONFIG 0x53c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP21_TAP22_CONFIG 0x540
+#define AFE_ADDA_DL_HBF1_SCF1_TAP23_TAP24_CONFIG 0x544
+#define AFE_ADDA_DL_HBF1_SCF1_TAP25_TAP26_CONFIG 0x548
+#define AFE_ADDA_DL_HBF1_SCF1_TAP27_TAP28_CONFIG 0x54c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP29_TAP30_CONFIG 0x550
+#define AFE_ADDA_DL_HBF1_SCF1_TAP31_TAP32_CONFIG 0x554
+#define AFE_ADDA_DL_HBF1_SCF1_TAP33_TAP34_CONFIG 0x558
+#define AFE_ADDA_DL_HBF1_SCF1_TAP35_TAP36_CONFIG 0x55c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP37_TAP38_CONFIG 0x560
+#define AFE_ADDA_DL_HBF1_SCF1_TAP39_TAP40_CONFIG 0x564
+#define AFE_ADDA_DL_HBF1_SCF1_TAP41_TAP42_CONFIG 0x568
+#define AFE_ADDA_DL_HBF1_SCF1_TAP43_TAP44_CONFIG 0x56c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP45_TAP46_CONFIG 0x570
+#define AFE_ADDA_DL_HBF1_SCF1_TAP47_TAP48_CONFIG 0x574
+#define AFE_ADDA_DL_HBF1_SCF1_TAP49_TAP50_CONFIG 0x578
+#define AFE_ADDA_DL_HBF1_SCF1_TAP51_TAP52_CONFIG 0x57c
+#define AFE_ADDA_DL_HBF1_SCF1_TAP53_TAP54_CONFIG 0x580
+#define AFE_ADDA_DL_HBF1_SCF1_TAP55_TAP56_CONFIG 0x584
+#define AFE_DEM_IDWA_CON0 0xa1c
+#define DEM_RECONSTRUCT_MON 0xa20
+#define AFE_CM0_CON0 0xba0
+#define AFE_CM0_MON 0xba4
+#define AFE_CM0_IP_VERSION 0xba8
+#define AFE_CM1_CON0 0xbb0
+#define AFE_CM1_MON 0xbb4
+#define AFE_CM1_IP_VERSION 0xbb8
+#define AFE_ADDA_UL0_SRC_CON0 0xbd0
+#define AFE_ADDA_UL0_SRC_CON1 0xbd4
+#define AFE_ADDA_UL0_SRC_CON2 0xbd8
+#define AFE_ADDA_UL0_SRC_DEBUG 0xbdc
+#define AFE_ADDA_UL0_SRC_DEBUG_MON0 0xbe0
+#define AFE_ADDA_UL0_SRC_MON0 0xbe4
+#define AFE_ADDA_UL0_SRC_MON1 0xbe8
+#define AFE_ADDA_UL0_IIR_COEF_02_01 0xbec
+#define AFE_ADDA_UL0_IIR_COEF_04_03 0xbf0
+#define AFE_ADDA_UL0_IIR_COEF_06_05 0xbf4
+#define AFE_ADDA_UL0_IIR_COEF_08_07 0xbf8
+#define AFE_ADDA_UL0_IIR_COEF_10_09 0xbfc
+#define AFE_ADDA_UL0_ULCF_CFG_02_01 0xc00
+#define AFE_ADDA_UL0_ULCF_CFG_04_03 0xc04
+#define AFE_ADDA_UL0_ULCF_CFG_06_05 0xc08
+#define AFE_ADDA_UL0_ULCF_CFG_08_07 0xc0c
+#define AFE_ADDA_UL0_ULCF_CFG_10_09 0xc10
+#define AFE_ADDA_UL0_ULCF_CFG_12_11 0xc14
+#define AFE_ADDA_UL0_ULCF_CFG_14_13 0xc18
+#define AFE_ADDA_UL0_ULCF_CFG_16_15 0xc1c
+#define AFE_ADDA_UL0_ULCF_CFG_18_17 0xc20
+#define AFE_ADDA_UL0_ULCF_CFG_20_19 0xc24
+#define AFE_ADDA_UL0_ULCF_CFG_22_21 0xc28
+#define AFE_ADDA_UL0_ULCF_CFG_24_23 0xc2c
+#define AFE_ADDA_UL0_ULCF_CFG_26_25 0xc30
+#define AFE_ADDA_UL0_ULCF_CFG_28_27 0xc34
+#define AFE_ADDA_UL0_ULCF_CFG_30_29 0xc38
+#define AFE_ADDA_UL0_ULCF_CFG_32_31 0xc3c
+#define AFE_ADDA_UL0_IP_VERSION 0xc4c
+#define AFE_ADDA_DMIC0_SRC_CON0 0xdd0
+#define AFE_ADDA_DMIC0_SRC_CON1 0xdd4
+#define AFE_ADDA_DMIC0_SRC_CON2 0xdd8
+#define AFE_ADDA_DMIC0_SRC_DEBUG 0xddc
+#define AFE_ADDA_DMIC0_SRC_DEBUG_MON0 0xde0
+#define AFE_ADDA_DMIC0_SRC_MON0 0xde4
+#define AFE_ADDA_DMIC0_SRC_MON1 0xde8
+#define AFE_ADDA_DMIC0_IIR_COEF_02_01 0xdec
+#define AFE_ADDA_DMIC0_IIR_COEF_04_03 0xdf0
+#define AFE_ADDA_DMIC0_IIR_COEF_06_05 0xdf4
+#define AFE_ADDA_DMIC0_IIR_COEF_08_07 0xdf8
+#define AFE_ADDA_DMIC0_IIR_COEF_10_09 0xdfc
+#define AFE_ADDA_DMIC0_ULCF_CFG_02_01 0xe00
+#define AFE_ADDA_DMIC0_ULCF_CFG_04_03 0xe04
+#define AFE_ADDA_DMIC0_ULCF_CFG_06_05 0xe08
+#define AFE_ADDA_DMIC0_ULCF_CFG_08_07 0xe0c
+#define AFE_ADDA_DMIC0_ULCF_CFG_10_09 0xe10
+#define AFE_ADDA_DMIC0_ULCF_CFG_12_11 0xe14
+#define AFE_ADDA_DMIC0_ULCF_CFG_14_13 0xe18
+#define AFE_ADDA_DMIC0_ULCF_CFG_16_15 0xe1c
+#define AFE_ADDA_DMIC0_ULCF_CFG_18_17 0xe20
+#define AFE_ADDA_DMIC0_ULCF_CFG_20_19 0xe24
+#define AFE_ADDA_DMIC0_ULCF_CFG_22_21 0xe28
+#define AFE_ADDA_DMIC0_ULCF_CFG_24_23 0xe2c
+#define AFE_ADDA_DMIC0_ULCF_CFG_26_25 0xe30
+#define AFE_ADDA_DMIC0_ULCF_CFG_28_27 0xe34
+#define AFE_ADDA_DMIC0_ULCF_CFG_30_29 0xe38
+#define AFE_ADDA_DMIC0_ULCF_CFG_32_31 0xe3c
+#define AFE_ADDA_DMIC0_IP_VERSION 0xe4c
+#define AFE_ADDA_DMIC1_SRC_CON0 0xe50
+#define AFE_ADDA_DMIC1_SRC_CON1 0xe54
+#define AFE_ADDA_DMIC1_SRC_CON2 0xe58
+#define AFE_ADDA_DMIC1_SRC_DEBUG 0xe5c
+#define AFE_ADDA_DMIC1_SRC_DEBUG_MON0 0xe60
+#define AFE_ADDA_DMIC1_SRC_MON0 0xe64
+#define AFE_ADDA_DMIC1_SRC_MON1 0xe68
+#define AFE_ADDA_DMIC1_IIR_COEF_02_01 0xe6c
+#define AFE_ADDA_DMIC1_IIR_COEF_04_03 0xe70
+#define AFE_ADDA_DMIC1_IIR_COEF_06_05 0xe74
+#define AFE_ADDA_DMIC1_IIR_COEF_08_07 0xe78
+#define AFE_ADDA_DMIC1_IIR_COEF_10_09 0xe7c
+#define AFE_ADDA_DMIC1_ULCF_CFG_02_01 0xe80
+#define AFE_ADDA_DMIC1_ULCF_CFG_04_03 0xe84
+#define AFE_ADDA_DMIC1_ULCF_CFG_06_05 0xe88
+#define AFE_ADDA_DMIC1_ULCF_CFG_08_07 0xe8c
+#define AFE_ADDA_DMIC1_ULCF_CFG_10_09 0xe90
+#define AFE_ADDA_DMIC1_ULCF_CFG_12_11 0xe94
+#define AFE_ADDA_DMIC1_ULCF_CFG_14_13 0xe98
+#define AFE_ADDA_DMIC1_ULCF_CFG_16_15 0xe9c
+#define AFE_ADDA_DMIC1_ULCF_CFG_18_17 0xea0
+#define AFE_ADDA_DMIC1_ULCF_CFG_20_19 0xea4
+#define AFE_ADDA_DMIC1_ULCF_CFG_22_21 0xea8
+#define AFE_ADDA_DMIC1_ULCF_CFG_24_23 0xeac
+#define AFE_ADDA_DMIC1_ULCF_CFG_26_25 0xeb0
+#define AFE_ADDA_DMIC1_ULCF_CFG_28_27 0xeb4
+#define AFE_ADDA_DMIC1_ULCF_CFG_30_29 0xeb8
+#define AFE_ADDA_DMIC1_ULCF_CFG_32_31 0xebc
+#define AFE_ADDA_DMIC1_IP_VERSION 0xecc
+#define AFE_ADDA_ULSRC_PHASE_CLK_CON0 0xf00
+#define AFE_ADDA_ULSRC_PHASE_CLK_CON1 0xf04
+#define AFE_ADDA_ULSRC_PHASE_CLK_CON2 0xf08
+#define AFE_ADDA_ULSRC_PHASE_CLK_CON3 0xf0c
+#define AFE_ADDA_ULSRC_PHASE_CLK_CON4 0xf10
+#define AFE_ADDA_ULSRC_PHASE_ENGEN_CON0 0xf14
+#define AFE_ADDA_ULSRC_PHASE_ENGEN_CON1 0xf18
+#define AFE_ADDA_ULSRC_PHASE_RST_CON0 0xf1c
+#define AFE_MTKAIF_IPM_VER_MON 0x1180
+#define AFE_MTKAIF_MON_SEL 0x1184
+#define AFE_MTKAIF_MON 0x1188
+#define AFE_MTKAIF0_CFG0 0x1190
+#define AFE_MTKAIF0_TX_CFG0 0x1194
+#define AFE_MTKAIF0_RX_CFG0 0x1198
+#define AFE_MTKAIF0_RX_CFG1 0x119c
+#define AFE_MTKAIF0_RX_CFG2 0x11a0
+#define AFE_MTKAIF1_CFG0 0x11f0
+#define AFE_MTKAIF1_TX_CFG0 0x11f4
+#define AFE_MTKAIF1_RX_CFG0 0x11f8
+#define AFE_MTKAIF1_RX_CFG1 0x11fc
+#define AFE_MTKAIF1_RX_CFG2 0x1200
+#define AFE_AUD_PAD_TOP_CFG0 0x1204
+#define AFE_AUD_PAD_TOP_MON 0x1208
+#define AFE_ADDA_MTKAIFV4_TX_CFG0 0x1280
+#define AFE_ADDA6_MTKAIFV4_TX_CFG0 0x1284
+#define AFE_ADDA_MTKAIFV4_RX_CFG0 0x1288
+#define AFE_ADDA_MTKAIFV4_RX_CFG1 0x128c
+#define AFE_ADDA6_MTKAIFV4_RX_CFG0 0x1290
+#define AFE_ADDA6_MTKAIFV4_RX_CFG1 0x1294
+#define AFE_ADDA_MTKAIFV4_TX_SYNCWORD_CFG 0x1298
+#define AFE_ADDA_MTKAIFV4_RX_SYNCWORD_CFG 0x129c
+#define AFE_ADDA_MTKAIFV4_MON0 0x12a0
+#define AFE_ADDA_MTKAIFV4_MON1 0x12a4
+#define AFE_ADDA6_MTKAIFV4_MON0 0x12a8
+#define ETDM_IN0_CON0 0x1300
+#define ETDM_IN0_CON1 0x1304
+#define ETDM_IN0_CON2 0x1308
+#define ETDM_IN0_CON3 0x130c
+#define ETDM_IN0_CON4 0x1310
+#define ETDM_IN0_CON5 0x1314
+#define ETDM_IN0_CON6 0x1318
+#define ETDM_IN0_CON7 0x131c
+#define ETDM_IN0_CON8 0x1320
+#define ETDM_IN0_CON9 0x1324
+#define ETDM_IN0_MON 0x1328
+#define ETDM_IN1_CON0 0x1330
+#define ETDM_IN1_CON1 0x1334
+#define ETDM_IN1_CON2 0x1338
+#define ETDM_IN1_CON3 0x133c
+#define ETDM_IN1_CON4 0x1340
+#define ETDM_IN1_CON5 0x1344
+#define ETDM_IN1_CON6 0x1348
+#define ETDM_IN1_CON7 0x134c
+#define ETDM_IN1_CON8 0x1350
+#define ETDM_IN1_CON9 0x1354
+#define ETDM_IN1_MON 0x1358
+#define ETDM_OUT0_CON0 0x1480
+#define ETDM_OUT0_CON1 0x1484
+#define ETDM_OUT0_CON2 0x1488
+#define ETDM_OUT0_CON3 0x148c
+#define ETDM_OUT0_CON4 0x1490
+#define ETDM_OUT0_CON5 0x1494
+#define ETDM_OUT0_CON6 0x1498
+#define ETDM_OUT0_CON7 0x149c
+#define ETDM_OUT0_CON8 0x14a0
+#define ETDM_OUT0_CON9 0x14a4
+#define ETDM_OUT0_MON 0x14a8
+#define ETDM_OUT1_CON0 0x14c0
+#define ETDM_OUT1_CON1 0x14c4
+#define ETDM_OUT1_CON2 0x14c8
+#define ETDM_OUT1_CON3 0x14cc
+#define ETDM_OUT1_CON4 0x14d0
+#define ETDM_OUT1_CON5 0x14d4
+#define ETDM_OUT1_CON6 0x14d8
+#define ETDM_OUT1_CON7 0x14dc
+#define ETDM_OUT1_CON8 0x14e0
+#define ETDM_OUT1_CON9 0x14e4
+#define ETDM_OUT1_MON 0x14e8
+#define ETDM_OUT4_CON0 0x1580
+#define ETDM_OUT4_CON1 0x1584
+#define ETDM_OUT4_CON2 0x1588
+#define ETDM_OUT4_CON3 0x158c
+#define ETDM_OUT4_CON4 0x1590
+#define ETDM_OUT4_CON5 0x1594
+#define ETDM_OUT4_CON6 0x1598
+#define ETDM_OUT4_CON7 0x159c
+#define ETDM_OUT4_CON8 0x15a0
+#define ETDM_OUT4_CON9 0x15a4
+#define ETDM_OUT4_MON 0x15a8
+#define ETDM_0_3_COWORK_CON0 0x1680
+#define ETDM_0_3_COWORK_CON1 0x1684
+#define ETDM_0_3_COWORK_CON2 0x1688
+#define ETDM_0_3_COWORK_CON3 0x168c
+#define ETDM_4_7_COWORK_CON0 0x1690
+#define ETDM_4_7_COWORK_CON1 0x1694
+#define ETDM_4_7_COWORK_CON2 0x1698
+#define ETDM_4_7_COWORK_CON3 0x169c
+#define ETDM_IP_VERSION 0x1c4c
+#define AFE_DPTX_CON 0x2040
+#define AFE_DPTX_MON 0x2044
+#define AFE_TDM_CON1 0x2048
+#define AFE_TDM_CON2 0x204c
+#define AFE_TDM_CON3 0x2050
+#define AFE_TDM_OUT_MON 0x2054
+#define AFE_HDMI_CONN0 0x2078
+#define AFE_TDM_TOP_IP_VERSION 0x207c
+#define AFE_CONN004_0 0x2100
+#define AFE_CONN004_1 0x2104
+#define AFE_CONN004_2 0x2108
+#define AFE_CONN004_4 0x2110
+#define AFE_CONN004_6 0x2118
+#define AFE_CONN005_0 0x2120
+#define AFE_CONN005_1 0x2124
+#define AFE_CONN005_2 0x2128
+#define AFE_CONN005_4 0x2130
+#define AFE_CONN005_6 0x2138
+#define AFE_CONN006_0 0x2140
+#define AFE_CONN006_1 0x2144
+#define AFE_CONN006_2 0x2148
+#define AFE_CONN006_4 0x2150
+#define AFE_CONN006_6 0x2158
+#define AFE_CONN007_0 0x2160
+#define AFE_CONN007_1 0x2164
+#define AFE_CONN007_2 0x2168
+#define AFE_CONN007_4 0x2170
+#define AFE_CONN007_6 0x2178
+#define AFE_CONN008_0 0x2180
+#define AFE_CONN008_1 0x2184
+#define AFE_CONN008_2 0x2188
+#define AFE_CONN008_4 0x2190
+#define AFE_CONN008_6 0x2198
+#define AFE_CONN009_0 0x21a0
+#define AFE_CONN009_1 0x21a4
+#define AFE_CONN009_2 0x21a8
+#define AFE_CONN009_4 0x21b0
+#define AFE_CONN009_6 0x21b8
+#define AFE_CONN010_0 0x21c0
+#define AFE_CONN010_1 0x21c4
+#define AFE_CONN010_2 0x21c8
+#define AFE_CONN010_4 0x21d0
+#define AFE_CONN010_6 0x21d8
+#define AFE_CONN011_0 0x21e0
+#define AFE_CONN011_1 0x21e4
+#define AFE_CONN011_2 0x21e8
+#define AFE_CONN011_4 0x21f0
+#define AFE_CONN011_6 0x21f8
+#define AFE_CONN014_0 0x2240
+#define AFE_CONN014_1 0x2244
+#define AFE_CONN014_2 0x2248
+#define AFE_CONN014_4 0x2250
+#define AFE_CONN014_6 0x2258
+#define AFE_CONN015_0 0x2260
+#define AFE_CONN015_1 0x2264
+#define AFE_CONN015_2 0x2268
+#define AFE_CONN015_4 0x2270
+#define AFE_CONN015_6 0x2278
+#define AFE_CONN016_0 0x2280
+#define AFE_CONN016_1 0x2284
+#define AFE_CONN016_2 0x2288
+#define AFE_CONN016_4 0x2290
+#define AFE_CONN016_6 0x2298
+#define AFE_CONN017_0 0x22a0
+#define AFE_CONN017_1 0x22a4
+#define AFE_CONN017_2 0x22a8
+#define AFE_CONN017_4 0x22b0
+#define AFE_CONN017_6 0x22b8
+#define AFE_CONN018_0 0x22c0
+#define AFE_CONN018_1 0x22c4
+#define AFE_CONN018_2 0x22c8
+#define AFE_CONN018_4 0x22d0
+#define AFE_CONN018_6 0x22d8
+#define AFE_CONN019_0 0x22e0
+#define AFE_CONN019_1 0x22e4
+#define AFE_CONN019_2 0x22e8
+#define AFE_CONN019_4 0x22f0
+#define AFE_CONN019_6 0x22f8
+#define AFE_CONN020_0 0x2300
+#define AFE_CONN020_1 0x2304
+#define AFE_CONN020_2 0x2308
+#define AFE_CONN020_4 0x2310
+#define AFE_CONN020_6 0x2318
+#define AFE_CONN021_0 0x2320
+#define AFE_CONN021_1 0x2324
+#define AFE_CONN021_2 0x2328
+#define AFE_CONN021_4 0x2330
+#define AFE_CONN021_6 0x2338
+#define AFE_CONN022_0 0x2340
+#define AFE_CONN022_1 0x2344
+#define AFE_CONN022_2 0x2348
+#define AFE_CONN022_4 0x2350
+#define AFE_CONN022_6 0x2358
+#define AFE_CONN023_0 0x2360
+#define AFE_CONN023_1 0x2364
+#define AFE_CONN023_2 0x2368
+#define AFE_CONN023_4 0x2370
+#define AFE_CONN023_6 0x2378
+#define AFE_CONN024_0 0x2380
+#define AFE_CONN024_1 0x2384
+#define AFE_CONN024_2 0x2388
+#define AFE_CONN024_4 0x2390
+#define AFE_CONN024_6 0x2398
+#define AFE_CONN025_0 0x23a0
+#define AFE_CONN025_1 0x23a4
+#define AFE_CONN025_2 0x23a8
+#define AFE_CONN025_4 0x23b0
+#define AFE_CONN025_6 0x23b8
+#define AFE_CONN026_0 0x23c0
+#define AFE_CONN026_1 0x23c4
+#define AFE_CONN026_2 0x23c8
+#define AFE_CONN026_4 0x23d0
+#define AFE_CONN026_6 0x23d8
+#define AFE_CONN027_0 0x23e0
+#define AFE_CONN027_1 0x23e4
+#define AFE_CONN027_2 0x23e8
+#define AFE_CONN027_4 0x23f0
+#define AFE_CONN027_6 0x23f8
+#define AFE_CONN028_0 0x2400
+#define AFE_CONN028_1 0x2404
+#define AFE_CONN028_2 0x2408
+#define AFE_CONN028_4 0x2410
+#define AFE_CONN028_6 0x2418
+#define AFE_CONN029_0 0x2420
+#define AFE_CONN029_1 0x2424
+#define AFE_CONN029_2 0x2428
+#define AFE_CONN029_4 0x2430
+#define AFE_CONN029_6 0x2438
+#define AFE_CONN030_0 0x2440
+#define AFE_CONN030_1 0x2444
+#define AFE_CONN030_2 0x2448
+#define AFE_CONN030_4 0x2450
+#define AFE_CONN030_6 0x2458
+#define AFE_CONN031_0 0x2460
+#define AFE_CONN031_1 0x2464
+#define AFE_CONN031_2 0x2468
+#define AFE_CONN031_4 0x2470
+#define AFE_CONN031_6 0x2478
+#define AFE_CONN032_0 0x2480
+#define AFE_CONN032_1 0x2484
+#define AFE_CONN032_2 0x2488
+#define AFE_CONN032_4 0x2490
+#define AFE_CONN032_6 0x2498
+#define AFE_CONN033_0 0x24a0
+#define AFE_CONN033_1 0x24a4
+#define AFE_CONN033_2 0x24a8
+#define AFE_CONN033_4 0x24b0
+#define AFE_CONN033_6 0x24b8
+#define AFE_CONN034_0 0x24c0
+#define AFE_CONN034_1 0x24c4
+#define AFE_CONN034_2 0x24c8
+#define AFE_CONN034_4 0x24d0
+#define AFE_CONN034_6 0x24d8
+#define AFE_CONN035_0 0x24e0
+#define AFE_CONN035_1 0x24e4
+#define AFE_CONN035_2 0x24e8
+#define AFE_CONN035_4 0x24f0
+#define AFE_CONN035_6 0x24f8
+#define AFE_CONN036_0 0x2500
+#define AFE_CONN036_1 0x2504
+#define AFE_CONN036_2 0x2508
+#define AFE_CONN036_4 0x2510
+#define AFE_CONN036_6 0x2518
+#define AFE_CONN037_0 0x2520
+#define AFE_CONN037_1 0x2524
+#define AFE_CONN037_2 0x2528
+#define AFE_CONN037_4 0x2530
+#define AFE_CONN037_6 0x2538
+#define AFE_CONN038_0 0x2540
+#define AFE_CONN038_1 0x2544
+#define AFE_CONN038_2 0x2548
+#define AFE_CONN038_4 0x2550
+#define AFE_CONN038_6 0x2558
+#define AFE_CONN039_0 0x2560
+#define AFE_CONN039_1 0x2564
+#define AFE_CONN039_2 0x2568
+#define AFE_CONN039_4 0x2570
+#define AFE_CONN039_6 0x2578
+#define AFE_CONN040_0 0x2580
+#define AFE_CONN040_1 0x2584
+#define AFE_CONN040_2 0x2588
+#define AFE_CONN040_4 0x2590
+#define AFE_CONN040_6 0x2598
+#define AFE_CONN041_0 0x25a0
+#define AFE_CONN041_1 0x25a4
+#define AFE_CONN041_2 0x25a8
+#define AFE_CONN041_4 0x25b0
+#define AFE_CONN041_6 0x25b8
+#define AFE_CONN042_0 0x25c0
+#define AFE_CONN042_1 0x25c4
+#define AFE_CONN042_2 0x25c8
+#define AFE_CONN042_4 0x25d0
+#define AFE_CONN042_6 0x25d8
+#define AFE_CONN043_0 0x25e0
+#define AFE_CONN043_1 0x25e4
+#define AFE_CONN043_2 0x25e8
+#define AFE_CONN043_4 0x25f0
+#define AFE_CONN043_6 0x25f8
+#define AFE_CONN044_0 0x2600
+#define AFE_CONN044_1 0x2604
+#define AFE_CONN044_2 0x2608
+#define AFE_CONN044_4 0x2610
+#define AFE_CONN044_6 0x2618
+#define AFE_CONN045_0 0x2620
+#define AFE_CONN045_1 0x2624
+#define AFE_CONN045_2 0x2628
+#define AFE_CONN045_4 0x2630
+#define AFE_CONN045_6 0x2638
+#define AFE_CONN046_0 0x2640
+#define AFE_CONN046_1 0x2644
+#define AFE_CONN046_2 0x2648
+#define AFE_CONN046_4 0x2650
+#define AFE_CONN046_6 0x2658
+#define AFE_CONN047_0 0x2660
+#define AFE_CONN047_1 0x2664
+#define AFE_CONN047_2 0x2668
+#define AFE_CONN047_4 0x2670
+#define AFE_CONN047_6 0x2678
+#define AFE_CONN048_0 0x2680
+#define AFE_CONN048_1 0x2684
+#define AFE_CONN048_2 0x2688
+#define AFE_CONN048_4 0x2690
+#define AFE_CONN048_6 0x2698
+#define AFE_CONN049_0 0x26a0
+#define AFE_CONN049_1 0x26a4
+#define AFE_CONN049_2 0x26a8
+#define AFE_CONN049_4 0x26b0
+#define AFE_CONN049_6 0x26b8
+#define AFE_CONN050_0 0x26c0
+#define AFE_CONN050_1 0x26c4
+#define AFE_CONN050_2 0x26c8
+#define AFE_CONN050_4 0x26d0
+#define AFE_CONN050_6 0x26d8
+#define AFE_CONN051_0 0x26e0
+#define AFE_CONN051_1 0x26e4
+#define AFE_CONN051_2 0x26e8
+#define AFE_CONN051_4 0x26f0
+#define AFE_CONN051_6 0x26f8
+#define AFE_CONN052_0 0x2700
+#define AFE_CONN052_1 0x2704
+#define AFE_CONN052_2 0x2708
+#define AFE_CONN052_4 0x2710
+#define AFE_CONN052_6 0x2718
+#define AFE_CONN053_0 0x2720
+#define AFE_CONN053_1 0x2724
+#define AFE_CONN053_2 0x2728
+#define AFE_CONN053_4 0x2730
+#define AFE_CONN053_6 0x2738
+#define AFE_CONN054_0 0x2740
+#define AFE_CONN054_1 0x2744
+#define AFE_CONN054_2 0x2748
+#define AFE_CONN054_4 0x2750
+#define AFE_CONN054_6 0x2758
+#define AFE_CONN055_0 0x2760
+#define AFE_CONN055_1 0x2764
+#define AFE_CONN055_2 0x2768
+#define AFE_CONN055_4 0x2770
+#define AFE_CONN055_6 0x2778
+#define AFE_CONN056_0 0x2780
+#define AFE_CONN056_1 0x2784
+#define AFE_CONN056_2 0x2788
+#define AFE_CONN056_4 0x2790
+#define AFE_CONN056_6 0x2798
+#define AFE_CONN057_0 0x27a0
+#define AFE_CONN057_1 0x27a4
+#define AFE_CONN057_2 0x27a8
+#define AFE_CONN057_4 0x27b0
+#define AFE_CONN057_6 0x27b8
+#define AFE_CONN058_0 0x27c0
+#define AFE_CONN058_1 0x27c4
+#define AFE_CONN058_2 0x27c8
+#define AFE_CONN058_4 0x27d0
+#define AFE_CONN058_6 0x27d8
+#define AFE_CONN059_0 0x27e0
+#define AFE_CONN059_1 0x27e4
+#define AFE_CONN059_2 0x27e8
+#define AFE_CONN059_4 0x27f0
+#define AFE_CONN059_6 0x27f8
+#define AFE_CONN060_0 0x2800
+#define AFE_CONN060_1 0x2804
+#define AFE_CONN060_2 0x2808
+#define AFE_CONN060_4 0x2810
+#define AFE_CONN060_6 0x2818
+#define AFE_CONN061_0 0x2820
+#define AFE_CONN061_1 0x2824
+#define AFE_CONN061_2 0x2828
+#define AFE_CONN061_4 0x2830
+#define AFE_CONN061_6 0x2838
+#define AFE_CONN062_0 0x2840
+#define AFE_CONN062_1 0x2844
+#define AFE_CONN062_2 0x2848
+#define AFE_CONN062_4 0x2850
+#define AFE_CONN062_6 0x2858
+#define AFE_CONN063_0 0x2860
+#define AFE_CONN063_1 0x2864
+#define AFE_CONN063_2 0x2868
+#define AFE_CONN063_4 0x2870
+#define AFE_CONN063_6 0x2878
+#define AFE_CONN066_0 0x28c0
+#define AFE_CONN066_1 0x28c4
+#define AFE_CONN066_2 0x28c8
+#define AFE_CONN066_4 0x28d0
+#define AFE_CONN066_6 0x28d8
+#define AFE_CONN067_0 0x28e0
+#define AFE_CONN067_1 0x28e4
+#define AFE_CONN067_2 0x28e8
+#define AFE_CONN067_4 0x28f0
+#define AFE_CONN067_6 0x28f8
+#define AFE_CONN068_0 0x2900
+#define AFE_CONN068_1 0x2904
+#define AFE_CONN068_2 0x2908
+#define AFE_CONN068_4 0x2910
+#define AFE_CONN068_6 0x2918
+#define AFE_CONN069_0 0x2920
+#define AFE_CONN069_1 0x2924
+#define AFE_CONN069_2 0x2928
+#define AFE_CONN069_4 0x2930
+#define AFE_CONN069_6 0x2938
+#define AFE_CONN096_0 0x2c80
+#define AFE_CONN096_1 0x2c84
+#define AFE_CONN096_2 0x2c88
+#define AFE_CONN096_4 0x2c90
+#define AFE_CONN096_6 0x2c98
+#define AFE_CONN097_0 0x2ca0
+#define AFE_CONN097_1 0x2ca4
+#define AFE_CONN097_2 0x2ca8
+#define AFE_CONN097_4 0x2cb0
+#define AFE_CONN097_6 0x2cb8
+#define AFE_CONN098_0 0x2cc0
+#define AFE_CONN098_1 0x2cc4
+#define AFE_CONN098_2 0x2cc8
+#define AFE_CONN098_4 0x2cd0
+#define AFE_CONN098_6 0x2cd8
+#define AFE_CONN099_0 0x2ce0
+#define AFE_CONN099_1 0x2ce4
+#define AFE_CONN099_2 0x2ce8
+#define AFE_CONN099_4 0x2cf0
+#define AFE_CONN099_6 0x2cf8
+#define AFE_CONN100_0 0x2d00
+#define AFE_CONN100_1 0x2d04
+#define AFE_CONN100_2 0x2d08
+#define AFE_CONN100_4 0x2d10
+#define AFE_CONN100_6 0x2d18
+#define AFE_CONN108_0 0x2e00
+#define AFE_CONN108_1 0x2e04
+#define AFE_CONN108_2 0x2e08
+#define AFE_CONN108_4 0x2e10
+#define AFE_CONN108_6 0x2e18
+#define AFE_CONN109_0 0x2e20
+#define AFE_CONN109_1 0x2e24
+#define AFE_CONN109_2 0x2e28
+#define AFE_CONN109_4 0x2e30
+#define AFE_CONN109_6 0x2e38
+#define AFE_CONN110_0 0x2e40
+#define AFE_CONN110_1 0x2e44
+#define AFE_CONN110_2 0x2e48
+#define AFE_CONN110_4 0x2e50
+#define AFE_CONN110_6 0x2e58
+#define AFE_CONN111_0 0x2e60
+#define AFE_CONN111_1 0x2e64
+#define AFE_CONN111_2 0x2e68
+#define AFE_CONN111_4 0x2e70
+#define AFE_CONN111_6 0x2e78
+#define AFE_CONN116_0 0x2f00
+#define AFE_CONN116_1 0x2f04
+#define AFE_CONN116_2 0x2f08
+#define AFE_CONN116_4 0x2f10
+#define AFE_CONN116_6 0x2f18
+#define AFE_CONN117_0 0x2f20
+#define AFE_CONN117_1 0x2f24
+#define AFE_CONN117_2 0x2f28
+#define AFE_CONN117_4 0x2f30
+#define AFE_CONN117_6 0x2f38
+#define AFE_CONN118_0 0x2f40
+#define AFE_CONN118_1 0x2f44
+#define AFE_CONN118_2 0x2f48
+#define AFE_CONN118_4 0x2f50
+#define AFE_CONN118_6 0x2f58
+#define AFE_CONN119_0 0x2f60
+#define AFE_CONN119_1 0x2f64
+#define AFE_CONN119_2 0x2f68
+#define AFE_CONN119_4 0x2f70
+#define AFE_CONN119_6 0x2f78
+#define AFE_CONN120_0 0x2f80
+#define AFE_CONN120_1 0x2f84
+#define AFE_CONN120_2 0x2f88
+#define AFE_CONN120_4 0x2f90
+#define AFE_CONN120_6 0x2f98
+#define AFE_CONN121_0 0x2fa0
+#define AFE_CONN121_1 0x2fa4
+#define AFE_CONN121_2 0x2fa8
+#define AFE_CONN121_4 0x2fb0
+#define AFE_CONN121_6 0x2fb8
+#define AFE_CONN122_0 0x2fc0
+#define AFE_CONN122_1 0x2fc4
+#define AFE_CONN122_2 0x2fc8
+#define AFE_CONN122_4 0x2fd0
+#define AFE_CONN122_6 0x2fd8
+#define AFE_CONN123_0 0x2fe0
+#define AFE_CONN123_1 0x2fe4
+#define AFE_CONN123_2 0x2fe8
+#define AFE_CONN123_4 0x2ff0
+#define AFE_CONN123_6 0x2ff8
+#define AFE_CONN180_0 0x3700
+#define AFE_CONN180_1 0x3704
+#define AFE_CONN180_2 0x3708
+#define AFE_CONN180_4 0x3710
+#define AFE_CONN180_6 0x3718
+#define AFE_CONN181_0 0x3720
+#define AFE_CONN181_1 0x3724
+#define AFE_CONN181_2 0x3728
+#define AFE_CONN181_4 0x3730
+#define AFE_CONN181_6 0x3738
+#define AFE_CONN182_0 0x3740
+#define AFE_CONN182_1 0x3744
+#define AFE_CONN182_2 0x3748
+#define AFE_CONN182_4 0x3750
+#define AFE_CONN182_6 0x3758
+#define AFE_CONN183_0 0x3760
+#define AFE_CONN183_1 0x3764
+#define AFE_CONN183_2 0x3768
+#define AFE_CONN183_4 0x3770
+#define AFE_CONN183_6 0x3778
+#define AFE_CONN184_0 0x3780
+#define AFE_CONN184_1 0x3784
+#define AFE_CONN184_2 0x3788
+#define AFE_CONN184_4 0x3790
+#define AFE_CONN184_6 0x3798
+#define AFE_CONN185_0 0x37a0
+#define AFE_CONN185_1 0x37a4
+#define AFE_CONN185_2 0x37a8
+#define AFE_CONN185_4 0x37b0
+#define AFE_CONN185_6 0x37b8
+#define AFE_CONN186_0 0x37c0
+#define AFE_CONN186_1 0x37c4
+#define AFE_CONN186_2 0x37c8
+#define AFE_CONN186_4 0x37d0
+#define AFE_CONN186_6 0x37d8
+#define AFE_CONN187_0 0x37e0
+#define AFE_CONN187_1 0x37e4
+#define AFE_CONN187_2 0x37e8
+#define AFE_CONN187_4 0x37f0
+#define AFE_CONN187_6 0x37f8
+#define AFE_CONN188_0 0x3800
+#define AFE_CONN188_1 0x3804
+#define AFE_CONN188_2 0x3808
+#define AFE_CONN188_4 0x3810
+#define AFE_CONN188_6 0x3818
+#define AFE_CONN189_0 0x3820
+#define AFE_CONN189_1 0x3824
+#define AFE_CONN189_2 0x3828
+#define AFE_CONN189_4 0x3830
+#define AFE_CONN189_6 0x3838
+#define AFE_CONN_MON_CFG 0x4080
+#define AFE_CONN_MON0 0x4084
+#define AFE_CONN_MON1 0x4088
+#define AFE_CONN_MON2 0x408c
+#define AFE_CONN_MON3 0x4090
+#define AFE_CONN_MON4 0x4094
+#define AFE_CONN_MON5 0x4098
+#define AFE_CONN_RS_0 0x40a0
+#define AFE_CONN_RS_1 0x40a4
+#define AFE_CONN_RS_2 0x40a8
+#define AFE_CONN_RS_3 0x40ac
+#define AFE_CONN_RS_5 0x40b4
+#define AFE_CONN_DI_0 0x40c0
+#define AFE_CONN_DI_1 0x40c4
+#define AFE_CONN_DI_2 0x40c8
+#define AFE_CONN_DI_3 0x40cc
+#define AFE_CONN_DI_5 0x40d4
+#define AFE_CONN_16BIT_0 0x40e0
+#define AFE_CONN_16BIT_1 0x40e4
+#define AFE_CONN_16BIT_2 0x40e8
+#define AFE_CONN_16BIT_3 0x40ec
+#define AFE_CONN_16BIT_5 0x40f4
+#define AFE_CONN_24BIT_0 0x4100
+#define AFE_CONN_24BIT_1 0x4104
+#define AFE_CONN_24BIT_2 0x4108
+#define AFE_CONN_24BIT_3 0x410c
+#define AFE_CONN_24BIT_5 0x4114
+#define AFE_CONN_TOP_IP_VERSION 0x4120
+#define AFE_CBIP_CFG0 0x4380
+#define AFE_CBIP_SLV_DECODER_MON0 0x4384
+#define AFE_CBIP_SLV_DECODER_MON1 0x4388
+#define AFE_CBIP_SLV_MUX_MON_CFG 0x438c
+#define AFE_CBIP_SLV_MUX_MON0 0x4390
+#define AFE_CBIP_SLV_MUX_MON1 0x4394
+#define AFE_MEMIF_IP_VERSION 0x4398
+#define AFE_MEMIF_CON0 0x4400
+#define AFE_MEMIF_RD_MON 0x4408
+#define AFE_MEMIF_WR_MON 0x440c
+#define AFE_MEMIF_CFG_MON0 0x4410
+#define AFE_BUS_CFG0 0x4414
+#define AFE_BUS_MON1 0x4418
+#define AFE_BUS_MON2 0x441c
+#define AFE_MEMIF_ONE_HEART 0x4420
+#define AFE_DL0_BASE_MSB 0x4440
+#define AFE_DL0_BASE 0x4444
+#define AFE_DL0_CUR_MSB 0x4448
+#define AFE_DL0_CUR 0x444c
+#define AFE_DL0_END_MSB 0x4450
+#define AFE_DL0_END 0x4454
+#define AFE_DL0_RCH_MON 0x4458
+#define AFE_DL0_LCH_MON 0x445c
+#define AFE_DL0_CON0 0x4460
+#define AFE_DL0_MON0 0x4464
+#define AFE_DL0_MEM_UP_MSB 0x4468
+#define AFE_DL0_MEM_UP 0x446c
+#define AFE_DL1_BASE_MSB 0x4470
+#define AFE_DL1_BASE 0x4474
+#define AFE_DL1_CUR_MSB 0x4478
+#define AFE_DL1_CUR 0x447c
+#define AFE_DL1_END_MSB 0x4480
+#define AFE_DL1_END 0x4484
+#define AFE_DL1_RCH_MON 0x4488
+#define AFE_DL1_LCH_MON 0x448c
+#define AFE_DL1_CON0 0x4490
+#define AFE_DL1_MON0 0x4494
+#define AFE_DL1_MEM_UP_MSB 0x4498
+#define AFE_DL1_MEM_UP 0x449c
+#define AFE_DL2_BASE_MSB 0x44a0
+#define AFE_DL2_BASE 0x44a4
+#define AFE_DL2_CUR_MSB 0x44a8
+#define AFE_DL2_CUR 0x44ac
+#define AFE_DL2_END_MSB 0x44b0
+#define AFE_DL2_END 0x44b4
+#define AFE_DL2_RCH_MON 0x44b8
+#define AFE_DL2_LCH_MON 0x44bc
+#define AFE_DL2_CON0 0x44c0
+#define AFE_DL2_MON0 0x44c4
+#define AFE_DL2_MEM_UP_MSB 0x44c8
+#define AFE_DL2_MEM_UP 0x44cc
+#define AFE_DL3_BASE_MSB 0x44d0
+#define AFE_DL3_BASE 0x44d4
+#define AFE_DL3_CUR_MSB 0x44d8
+#define AFE_DL3_CUR 0x44dc
+#define AFE_DL3_END_MSB 0x44e0
+#define AFE_DL3_END 0x44e4
+#define AFE_DL3_RCH_MON 0x44e8
+#define AFE_DL3_LCH_MON 0x44ec
+#define AFE_DL3_CON0 0x44f0
+#define AFE_DL3_MON0 0x44f4
+#define AFE_DL3_MEM_UP_MSB 0x44f8
+#define AFE_DL3_MEM_UP 0x44fc
+#define AFE_DL4_BASE_MSB 0x4500
+#define AFE_DL4_BASE 0x4504
+#define AFE_DL4_CUR_MSB 0x4508
+#define AFE_DL4_CUR 0x450c
+#define AFE_DL4_END_MSB 0x4510
+#define AFE_DL4_END 0x4514
+#define AFE_DL4_RCH_MON 0x4518
+#define AFE_DL4_LCH_MON 0x451c
+#define AFE_DL4_CON0 0x4520
+#define AFE_DL4_MON0 0x4524
+#define AFE_DL4_MEM_UP_MSB 0x4528
+#define AFE_DL4_MEM_UP 0x452c
+#define AFE_DL5_BASE_MSB 0x4530
+#define AFE_DL5_BASE 0x4534
+#define AFE_DL5_CUR_MSB 0x4538
+#define AFE_DL5_CUR 0x453c
+#define AFE_DL5_END_MSB 0x4540
+#define AFE_DL5_END 0x4544
+#define AFE_DL5_RCH_MON 0x4548
+#define AFE_DL5_LCH_MON 0x454c
+#define AFE_DL5_CON0 0x4550
+#define AFE_DL5_MON0 0x4554
+#define AFE_DL5_MEM_UP_MSB 0x4558
+#define AFE_DL5_MEM_UP 0x455c
+#define AFE_DL6_BASE_MSB 0x4560
+#define AFE_DL6_BASE 0x4564
+#define AFE_DL6_CUR_MSB 0x4568
+#define AFE_DL6_CUR 0x456c
+#define AFE_DL6_END_MSB 0x4570
+#define AFE_DL6_END 0x4574
+#define AFE_DL6_RCH_MON 0x4578
+#define AFE_DL6_LCH_MON 0x457c
+#define AFE_DL6_CON0 0x4580
+#define AFE_DL6_MON0 0x4584
+#define AFE_DL6_MEM_UP_MSB 0x4588
+#define AFE_DL6_MEM_UP 0x458c
+#define AFE_DL7_BASE_MSB 0x4590
+#define AFE_DL7_BASE 0x4594
+#define AFE_DL7_CUR_MSB 0x4598
+#define AFE_DL7_CUR 0x459c
+#define AFE_DL7_END_MSB 0x45a0
+#define AFE_DL7_END 0x45a4
+#define AFE_DL7_RCH_MON 0x45a8
+#define AFE_DL7_LCH_MON 0x45ac
+#define AFE_DL7_CON0 0x45b0
+#define AFE_DL7_MON0 0x45b4
+#define AFE_DL7_MEM_UP_MSB 0x45b8
+#define AFE_DL7_MEM_UP 0x45bc
+#define AFE_DL8_BASE_MSB 0x45c0
+#define AFE_DL8_BASE 0x45c4
+#define AFE_DL8_CUR_MSB 0x45c8
+#define AFE_DL8_CUR 0x45cc
+#define AFE_DL8_END_MSB 0x45d0
+#define AFE_DL8_END 0x45d4
+#define AFE_DL8_RCH_MON 0x45d8
+#define AFE_DL8_LCH_MON 0x45dc
+#define AFE_DL8_CON0 0x45e0
+#define AFE_DL8_MON0 0x45e4
+#define AFE_DL8_MEM_UP_MSB 0x45e8
+#define AFE_DL8_MEM_UP 0x45ec
+#define AFE_DL_24CH_BASE_MSB 0x4620
+#define AFE_DL_24CH_BASE 0x4624
+#define AFE_DL_24CH_CUR_MSB 0x4628
+#define AFE_DL_24CH_CUR 0x462c
+#define AFE_DL_24CH_END_MSB 0x4630
+#define AFE_DL_24CH_END 0x4634
+#define AFE_DL_24CH_CON0 0x4640
+#define AFE_DL_24CH_MON0 0x4644
+#define AFE_DL_24CH_MEM_UP_MSB 0x4648
+#define AFE_DL_24CH_MEM_UP 0x464c
+#define AFE_DL23_BASE_MSB 0x4680
+#define AFE_DL23_BASE 0x4684
+#define AFE_DL23_CUR_MSB 0x4688
+#define AFE_DL23_CUR 0x468c
+#define AFE_DL23_END_MSB 0x4690
+#define AFE_DL23_END 0x4694
+#define AFE_DL23_RCH_MON 0x4698
+#define AFE_DL23_LCH_MON 0x469c
+#define AFE_DL23_CON0 0x46a0
+#define AFE_DL23_MON0 0x46a4
+#define AFE_DL23_MEM_UP_MSB 0x46a8
+#define AFE_DL23_MEM_UP 0x46ac
+#define AFE_DL24_BASE_MSB 0x46b0
+#define AFE_DL24_BASE 0x46b4
+#define AFE_DL24_CUR_MSB 0x46b8
+#define AFE_DL24_CUR 0x46bc
+#define AFE_DL24_END_MSB 0x46c0
+#define AFE_DL24_END 0x46c4
+#define AFE_DL24_RCH_MON 0x46c8
+#define AFE_DL24_LCH_MON 0x46cc
+#define AFE_DL24_CON0 0x46d0
+#define AFE_DL24_MON0 0x46d4
+#define AFE_DL24_MEM_UP_MSB 0x46d8
+#define AFE_DL24_MEM_UP 0x46dc
+#define AFE_DL25_BASE_MSB 0x46e0
+#define AFE_DL25_BASE 0x46e4
+#define AFE_DL25_CUR_MSB 0x46e8
+#define AFE_DL25_CUR 0x46ec
+#define AFE_DL25_END_MSB 0x46f0
+#define AFE_DL25_END 0x46f4
+#define AFE_DL25_RCH_MON 0x46f8
+#define AFE_DL25_LCH_MON 0x46fc
+#define AFE_DL25_CON0 0x4700
+#define AFE_DL25_MON0 0x4704
+#define AFE_DL25_MEM_UP_MSB 0x4708
+#define AFE_DL25_MEM_UP 0x470c
+#define AFE_VUL0_BASE_MSB 0x4d60
+#define AFE_VUL0_BASE 0x4d64
+#define AFE_VUL0_CUR_MSB 0x4d68
+#define AFE_VUL0_CUR 0x4d6c
+#define AFE_VUL0_END_MSB 0x4d70
+#define AFE_VUL0_END 0x4d74
+#define AFE_VUL0_RCH_MON 0x4d78
+#define AFE_VUL0_LCH_MON 0x4d7c
+#define AFE_VUL0_CON0 0x4d80
+#define AFE_VUL0_MON0 0x4d84
+#define AFE_VUL1_BASE_MSB 0x4d90
+#define AFE_VUL1_BASE 0x4d94
+#define AFE_VUL1_CUR_MSB 0x4d98
+#define AFE_VUL1_CUR 0x4d9c
+#define AFE_VUL1_END_MSB 0x4da0
+#define AFE_VUL1_END 0x4da4
+#define AFE_VUL1_RCH_MON 0x4da8
+#define AFE_VUL1_LCH_MON 0x4dac
+#define AFE_VUL1_CON0 0x4db0
+#define AFE_VUL1_MON0 0x4db4
+#define AFE_VUL2_BASE_MSB 0x4dc0
+#define AFE_VUL2_BASE 0x4dc4
+#define AFE_VUL2_CUR_MSB 0x4dc8
+#define AFE_VUL2_CUR 0x4dcc
+#define AFE_VUL2_END_MSB 0x4dd0
+#define AFE_VUL2_END 0x4dd4
+#define AFE_VUL2_RCH_MON 0x4dd8
+#define AFE_VUL2_LCH_MON 0x4ddc
+#define AFE_VUL2_CON0 0x4de0
+#define AFE_VUL2_MON0 0x4de4
+#define AFE_VUL3_BASE_MSB 0x4df0
+#define AFE_VUL3_BASE 0x4df4
+#define AFE_VUL3_CUR_MSB 0x4df8
+#define AFE_VUL3_CUR 0x4dfc
+#define AFE_VUL3_END_MSB 0x4e00
+#define AFE_VUL3_END 0x4e04
+#define AFE_VUL3_RCH_MON 0x4e08
+#define AFE_VUL3_LCH_MON 0x4e0c
+#define AFE_VUL3_CON0 0x4e10
+#define AFE_VUL3_MON0 0x4e14
+#define AFE_VUL4_BASE_MSB 0x4e20
+#define AFE_VUL4_BASE 0x4e24
+#define AFE_VUL4_CUR_MSB 0x4e28
+#define AFE_VUL4_CUR 0x4e2c
+#define AFE_VUL4_END_MSB 0x4e30
+#define AFE_VUL4_END 0x4e34
+#define AFE_VUL4_RCH_MON 0x4e38
+#define AFE_VUL4_LCH_MON 0x4e3c
+#define AFE_VUL4_CON0 0x4e40
+#define AFE_VUL4_MON0 0x4e44
+#define AFE_VUL5_BASE_MSB 0x4e50
+#define AFE_VUL5_BASE 0x4e54
+#define AFE_VUL5_CUR_MSB 0x4e58
+#define AFE_VUL5_CUR 0x4e5c
+#define AFE_VUL5_END_MSB 0x4e60
+#define AFE_VUL5_END 0x4e64
+#define AFE_VUL5_RCH_MON 0x4e68
+#define AFE_VUL5_LCH_MON 0x4e6c
+#define AFE_VUL5_CON0 0x4e70
+#define AFE_VUL5_MON0 0x4e74
+#define AFE_VUL6_BASE_MSB 0x4e80
+#define AFE_VUL6_BASE 0x4e84
+#define AFE_VUL6_CUR_MSB 0x4e88
+#define AFE_VUL6_CUR 0x4e8c
+#define AFE_VUL6_END_MSB 0x4e90
+#define AFE_VUL6_END 0x4e94
+#define AFE_VUL6_RCH_MON 0x4e98
+#define AFE_VUL6_LCH_MON 0x4e9c
+#define AFE_VUL6_CON0 0x4ea0
+#define AFE_VUL6_MON0 0x4ea4
+#define AFE_VUL7_BASE_MSB 0x4eb0
+#define AFE_VUL7_BASE 0x4eb4
+#define AFE_VUL7_CUR_MSB 0x4eb8
+#define AFE_VUL7_CUR 0x4ebc
+#define AFE_VUL7_END_MSB 0x4ec0
+#define AFE_VUL7_END 0x4ec4
+#define AFE_VUL7_RCH_MON 0x4ec8
+#define AFE_VUL7_LCH_MON 0x4ecc
+#define AFE_VUL7_CON0 0x4ed0
+#define AFE_VUL7_MON0 0x4ed4
+#define AFE_VUL8_BASE_MSB 0x4ee0
+#define AFE_VUL8_BASE 0x4ee4
+#define AFE_VUL8_CUR_MSB 0x4ee8
+#define AFE_VUL8_CUR 0x4eec
+#define AFE_VUL8_END_MSB 0x4ef0
+#define AFE_VUL8_END 0x4ef4
+#define AFE_VUL8_RCH_MON 0x4ef8
+#define AFE_VUL8_LCH_MON 0x4efc
+#define AFE_VUL8_CON0 0x4f00
+#define AFE_VUL8_MON0 0x4f04
+#define AFE_VUL9_BASE_MSB 0x4f10
+#define AFE_VUL9_BASE 0x4f14
+#define AFE_VUL9_CUR_MSB 0x4f18
+#define AFE_VUL9_CUR 0x4f1c
+#define AFE_VUL9_END_MSB 0x4f20
+#define AFE_VUL9_END 0x4f24
+#define AFE_VUL9_RCH_MON 0x4f28
+#define AFE_VUL9_LCH_MON 0x4f2c
+#define AFE_VUL9_CON0 0x4f30
+#define AFE_VUL9_MON0 0x4f34
+#define AFE_VUL10_BASE_MSB 0x4f40
+#define AFE_VUL10_BASE 0x4f44
+#define AFE_VUL10_CUR_MSB 0x4f48
+#define AFE_VUL10_CUR 0x4f4c
+#define AFE_VUL10_END_MSB 0x4f50
+#define AFE_VUL10_END 0x4f54
+#define AFE_VUL10_RCH_MON 0x4f58
+#define AFE_VUL10_LCH_MON 0x4f5c
+#define AFE_VUL10_CON0 0x4f60
+#define AFE_VUL10_MON0 0x4f64
+#define AFE_VUL24_BASE_MSB 0x4fa0
+#define AFE_VUL24_BASE 0x4fa4
+#define AFE_VUL24_CUR_MSB 0x4fa8
+#define AFE_VUL24_CUR 0x4fac
+#define AFE_VUL24_END_MSB 0x4fb0
+#define AFE_VUL24_END 0x4fb4
+#define AFE_VUL24_CON0 0x4fb8
+#define AFE_VUL24_MON0 0x4fbc
+#define AFE_VUL25_BASE_MSB 0x4fc0
+#define AFE_VUL25_BASE 0x4fc4
+#define AFE_VUL25_CUR_MSB 0x4fc8
+#define AFE_VUL25_CUR 0x4fcc
+#define AFE_VUL25_END_MSB 0x4fd0
+#define AFE_VUL25_END 0x4fd4
+#define AFE_VUL25_CON0 0x4fd8
+#define AFE_VUL25_MON0 0x4fdc
+#define AFE_VUL_CM0_BASE_MSB 0x51c0
+#define AFE_VUL_CM0_BASE 0x51c4
+#define AFE_VUL_CM0_CUR_MSB 0x51c8
+#define AFE_VUL_CM0_CUR 0x51cc
+#define AFE_VUL_CM0_END_MSB 0x51d0
+#define AFE_VUL_CM0_END 0x51d4
+#define AFE_VUL_CM0_CON0 0x51d8
+#define AFE_VUL_CM0_MON0 0x51dc
+#define AFE_VUL_CM1_BASE_MSB 0x51e0
+#define AFE_VUL_CM1_BASE 0x51e4
+#define AFE_VUL_CM1_CUR_MSB 0x51e8
+#define AFE_VUL_CM1_CUR 0x51ec
+#define AFE_VUL_CM1_END_MSB 0x51f0
+#define AFE_VUL_CM1_END 0x51f4
+#define AFE_VUL_CM1_CON0 0x51f8
+#define AFE_VUL_CM1_MON0 0x51fc
+#define AFE_ETDM_IN0_BASE_MSB 0x5220
+#define AFE_ETDM_IN0_BASE 0x5224
+#define AFE_ETDM_IN0_CUR_MSB 0x5228
+#define AFE_ETDM_IN0_CUR 0x522c
+#define AFE_ETDM_IN0_END_MSB 0x5230
+#define AFE_ETDM_IN0_END 0x5234
+#define AFE_ETDM_IN0_CON0 0x5238
+#define AFE_ETDM_IN1_BASE_MSB 0x5240
+#define AFE_ETDM_IN1_BASE 0x5244
+#define AFE_ETDM_IN1_CUR_MSB 0x5248
+#define AFE_ETDM_IN1_CUR 0x524c
+#define AFE_ETDM_IN1_END_MSB 0x5250
+#define AFE_ETDM_IN1_END 0x5254
+#define AFE_ETDM_IN1_CON0 0x5258
+#define AFE_HDMI_OUT_BASE_MSB 0x5360
+#define AFE_HDMI_OUT_BASE 0x5364
+#define AFE_HDMI_OUT_CUR_MSB 0x5368
+#define AFE_HDMI_OUT_CUR 0x536c
+#define AFE_HDMI_OUT_END_MSB 0x5370
+#define AFE_HDMI_OUT_END 0x5374
+#define AFE_HDMI_OUT_CON0 0x5378
+#define AFE_HDMI_OUT_MON0 0x537c
+#define AFE_VUL24_RCH_MON 0x53e0
+#define AFE_VUL24_LCH_MON 0x53e4
+#define AFE_VUL25_RCH_MON 0x53e8
+#define AFE_VUL25_LCH_MON 0x53ec
+#define AFE_VUL_CM0_RCH_MON 0x5458
+#define AFE_VUL_CM0_LCH_MON 0x545c
+#define AFE_VUL_CM1_RCH_MON 0x5460
+#define AFE_VUL_CM1_LCH_MON 0x5464
+#define AFE_DL_24CH_CH0_MON 0x5504
+#define AFE_DL_24CH_CH1_MON 0x5508
+#define AFE_DL_24CH_CH2_MON 0x550c
+#define AFE_DL_24CH_CH3_MON 0x5510
+#define AFE_DL_24CH_CH4_MON 0x5514
+#define AFE_DL_24CH_CH5_MON 0x5518
+#define AFE_DL_24CH_CH6_MON 0x551c
+#define AFE_DL_24CH_CH7_MON 0x5520
+#define AFE_HDMI_OUT_MEM_UP_MSB 0x55b0
+#define AFE_HDMI_OUT_MEM_UP 0x55b4
+#define AFE_SRAM_BOUND 0x5620
+#define AFE_SECURE_CON0 0x5624
+#define AFE_SECURE_CON1 0x5628
+#define AFE_SE_SECURE_CON0 0x5630
+#define AFE_SE_SECURE_CON1 0x5634
+#define AFE_SE_SECURE_CON2 0x5638
+#define AFE_SE_SECURE_CON3 0x563c
+#define AFE_SE_PROT_SIDEBAND0 0x5640
+#define AFE_SE_PROT_SIDEBAND1 0x5644
+#define AFE_SE_PROT_SIDEBAND2 0x5648
+#define AFE_SE_PROT_SIDEBAND3 0x564c
+#define AFE_SE_DOMAIN_SIDEBAND0 0x5650
+#define AFE_SE_DOMAIN_SIDEBAND1 0x5654
+#define AFE_SE_DOMAIN_SIDEBAND2 0x5658
+#define AFE_SE_DOMAIN_SIDEBAND3 0x565c
+#define AFE_SE_DOMAIN_SIDEBAND4 0x5660
+#define AFE_SE_DOMAIN_SIDEBAND5 0x5664
+#define AFE_SE_DOMAIN_SIDEBAND6 0x5668
+#define AFE_SE_DOMAIN_SIDEBAND7 0x566c
+#define AFE_SE_DOMAIN_SIDEBAND8 0x5670
+#define AFE_SE_DOMAIN_SIDEBAND9 0x5674
+#define AFE_PROT_SIDEBAND0_MON 0x5678
+#define AFE_PROT_SIDEBAND1_MON 0x567c
+#define AFE_PROT_SIDEBAND2_MON 0x5680
+#define AFE_PROT_SIDEBAND3_MON 0x5684
+#define AFE_DOMAIN_SIDEBAND0_MON 0x5688
+#define AFE_DOMAIN_SIDEBAND1_MON 0x568c
+#define AFE_DOMAIN_SIDEBAND2_MON 0x5690
+#define AFE_DOMAIN_SIDEBAND3_MON 0x5694
+#define AFE_DOMAIN_SIDEBAND4_MON 0x5698
+#define AFE_DOMAIN_SIDEBAND5_MON 0x569c
+#define AFE_DOMAIN_SIDEBAND6_MON 0x56a0
+#define AFE_DOMAIN_SIDEBAND7_MON 0x56a4
+#define AFE_DOMAIN_SIDEBAND8_MON 0x56a8
+#define AFE_DOMAIN_SIDEBAND9_MON 0x56ac
+#define AFE_SECURE_CONN0 0x56b0
+#define AFE_SECURE_CONN_ETDM0 0x56b4
+#define AFE_SECURE_CONN_ETDM1 0x56b8
+#define AFE_SECURE_CONN_ETDM2 0x56bc
+#define AFE_SECURE_SRAM_CON0 0x56c0
+#define AFE_SECURE_SRAM_CON1 0x56c4
+#define AFE_SE_CONN_INPUT_MASK0 0x56d0
+#define AFE_SE_CONN_INPUT_MASK1 0x56d4
+#define AFE_SE_CONN_INPUT_MASK2 0x56d8
+#define AFE_SE_CONN_INPUT_MASK3 0x56dc
+#define AFE_SE_CONN_INPUT_MASK4 0x56e0
+#define AFE_SE_CONN_INPUT_MASK5 0x56e4
+#define AFE_SE_CONN_INPUT_MASK6 0x56e8
+#define AFE_SE_CONN_INPUT_MASK7 0x56ec
+#define AFE_NON_SE_CONN_INPUT_MASK0 0x56f0
+#define AFE_NON_SE_CONN_INPUT_MASK1 0x56f4
+#define AFE_NON_SE_CONN_INPUT_MASK2 0x56f8
+#define AFE_NON_SE_CONN_INPUT_MASK3 0x56fc
+#define AFE_NON_SE_CONN_INPUT_MASK4 0x5700
+#define AFE_NON_SE_CONN_INPUT_MASK5 0x5704
+#define AFE_NON_SE_CONN_INPUT_MASK6 0x5708
+#define AFE_NON_SE_CONN_INPUT_MASK7 0x570c
+#define AFE_SE_CONN_OUTPUT_SEL0 0x5710
+#define AFE_SE_CONN_OUTPUT_SEL1 0x5714
+#define AFE_SE_CONN_OUTPUT_SEL2 0x5718
+#define AFE_SE_CONN_OUTPUT_SEL3 0x571c
+#define AFE_SE_CONN_OUTPUT_SEL4 0x5720
+#define AFE_SE_CONN_OUTPUT_SEL5 0x5724
+#define AFE_SE_CONN_OUTPUT_SEL6 0x5728
+#define AFE_SE_CONN_OUTPUT_SEL7 0x572c
+#define AFE_PCM0_INTF_CON1_MASK_MON 0x5730
+#define AFE_CONNSYS_I2S_CON_MASK_MON 0x5738
+#define AFE_TDM_CON2_MASK_MON 0x5744
+#define AFE_MTKAIF0_CFG0_MASK_MON 0x574c
+#define AFE_MTKAIF1_CFG0_MASK_MON 0x5750
+#define AFE_ADDA_UL0_SRC_CON0_MASK_MON 0x5754
+#define AFE_ADDA_DMIC0_SRC_CON0_MASK_MON 0x5764
+#define AFE_ADDA_DMIC1_SRC_CON0_MASK_MON 0x5768
+#define AFE_MON_SECURE_CON0 0x5840
+#define AFE_SECURE_CONN_ETDM3 0x5850
+#define AFE_ASRC_NEW_CON0 0x7800
+#define AFE_ASRC_NEW_CON1 0x7804
+#define AFE_ASRC_NEW_CON2 0x7808
+#define AFE_ASRC_NEW_CON3 0x780c
+#define AFE_ASRC_NEW_CON4 0x7810
+#define AFE_ASRC_NEW_CON5 0x7814
+#define AFE_ASRC_NEW_CON6 0x7818
+#define AFE_ASRC_NEW_CON7 0x781c
+#define AFE_ASRC_NEW_CON8 0x7820
+#define AFE_ASRC_NEW_CON9 0x7824
+#define AFE_ASRC_NEW_CON10 0x7828
+#define AFE_ASRC_NEW_CON11 0x782c
+#define AFE_ASRC_NEW_CON12 0x7830
+#define AFE_ASRC_NEW_CON13 0x7834
+#define AFE_ASRC_NEW_CON14 0x7838
+#define AFE_ASRC_NEW_IP_VERSION 0x783c
+#define AFE_GASRC0_NEW_CON0 0x7840
+#define AFE_GASRC0_NEW_CON1 0x7844
+#define AFE_GASRC0_NEW_CON2 0x7848
+#define AFE_GASRC0_NEW_CON3 0x784c
+#define AFE_GASRC0_NEW_CON4 0x7850
+#define AFE_GASRC0_NEW_CON5 0x7854
+#define AFE_GASRC0_NEW_CON6 0x7858
+#define AFE_GASRC0_NEW_CON7 0x785c
+#define AFE_GASRC0_NEW_CON8 0x7860
+#define AFE_GASRC0_NEW_CON9 0x7864
+#define AFE_GASRC0_NEW_CON10 0x7868
+#define AFE_GASRC0_NEW_CON11 0x786c
+#define AFE_GASRC0_NEW_CON12 0x7870
+#define AFE_GASRC0_NEW_CON13 0x7874
+#define AFE_GASRC0_NEW_CON14 0x7878
+#define AFE_GASRC0_NEW_IP_VERSION 0x787c
+#define AFE_GASRC1_NEW_CON0 0x7880
+#define AFE_GASRC1_NEW_CON1 0x7884
+#define AFE_GASRC1_NEW_CON2 0x7888
+#define AFE_GASRC1_NEW_CON3 0x788c
+#define AFE_GASRC1_NEW_CON4 0x7890
+#define AFE_GASRC1_NEW_CON5 0x7894
+#define AFE_GASRC1_NEW_CON6 0x7898
+#define AFE_GASRC1_NEW_CON7 0x789c
+#define AFE_GASRC1_NEW_CON8 0x78a0
+#define AFE_GASRC1_NEW_CON9 0x78a4
+#define AFE_GASRC1_NEW_CON10 0x78a8
+#define AFE_GASRC1_NEW_CON11 0x78ac
+#define AFE_GASRC1_NEW_CON12 0x78b0
+#define AFE_GASRC1_NEW_CON13 0x78b4
+#define AFE_GASRC1_NEW_CON14 0x78b8
+#define AFE_GASRC1_NEW_IP_VERSION 0x78bc
+#define AFE_GASRC2_NEW_CON0 0x78c0
+#define AFE_GASRC2_NEW_CON1 0x78c4
+#define AFE_GASRC2_NEW_CON2 0x78c8
+#define AFE_GASRC2_NEW_CON3 0x78cc
+#define AFE_GASRC2_NEW_CON4 0x78d0
+#define AFE_GASRC2_NEW_CON5 0x78d4
+#define AFE_GASRC2_NEW_CON6 0x78d8
+#define AFE_GASRC2_NEW_CON7 0x78dc
+#define AFE_GASRC2_NEW_CON8 0x78e0
+#define AFE_GASRC2_NEW_CON9 0x78e4
+#define AFE_GASRC2_NEW_CON10 0x78e8
+#define AFE_GASRC2_NEW_CON11 0x78ec
+#define AFE_GASRC2_NEW_CON12 0x78f0
+#define AFE_GASRC2_NEW_CON13 0x78f4
+#define AFE_GASRC2_NEW_CON14 0x78f8
+#define AFE_GASRC2_NEW_IP_VERSION 0x78fc
+#define AFE_GASRC3_NEW_CON0 0x7900
+#define AFE_GASRC3_NEW_CON1 0x7904
+#define AFE_GASRC3_NEW_CON2 0x7908
+#define AFE_GASRC3_NEW_CON3 0x790c
+#define AFE_GASRC3_NEW_CON4 0x7910
+#define AFE_GASRC3_NEW_CON5 0x7914
+#define AFE_GASRC3_NEW_CON6 0x7918
+#define AFE_GASRC3_NEW_CON7 0x791c
+#define AFE_GASRC3_NEW_CON8 0x7920
+#define AFE_GASRC3_NEW_CON9 0x7924
+#define AFE_GASRC3_NEW_CON10 0x7928
+#define AFE_GASRC3_NEW_CON11 0x792c
+#define AFE_GASRC3_NEW_CON12 0x7930
+#define AFE_GASRC3_NEW_CON13 0x7934
+#define AFE_GASRC3_NEW_CON14 0x7938
+#define AFE_GASRC3_NEW_IP_VERSION 0x793c
+#define AFE_GASRC4_NEW_CON0 0x7940
+#define AFE_GASRC4_NEW_CON1 0x7944
+#define AFE_GASRC4_NEW_CON2 0x7948
+#define AFE_GASRC4_NEW_CON3 0x794c
+#define AFE_GASRC4_NEW_CON4 0x7950
+#define AFE_GASRC4_NEW_CON5 0x7954
+#define AFE_GASRC4_NEW_CON6 0x7958
+#define AFE_GASRC4_NEW_CON7 0x795c
+#define AFE_GASRC4_NEW_CON8 0x7960
+#define AFE_GASRC4_NEW_CON9 0x7964
+#define AFE_GASRC4_NEW_CON10 0x7968
+#define AFE_GASRC4_NEW_CON11 0x796c
+#define AFE_GASRC4_NEW_CON12 0x7970
+#define AFE_GASRC4_NEW_CON13 0x7974
+#define AFE_GASRC4_NEW_CON14 0x7978
+#define AFE_GASRC4_NEW_IP_VERSION 0x797c
+#define AFE_SOUNDWIRE_ULSRC_PHASE_CLK_CON0 0x9400
+#define AFE_SOUNDWIRE_ULSRC_PHASE_CLK_CON1 0x9404
+#define AFE_SOUNDWIRE_ULSRC_PHASE_CLK_CON2 0x9408
+#define AFE_SOUNDWIRE_ULSRC_PHASE_CLK_CON3 0x940c
+#define AFE_SOUNDWIRE_ULSRC_PHASE_CLK_CON4 0x9410
+#define AFE_SOUNDWIRE_ULSRC_PHASE_ENGEN_CON0 0x9414
+#define AFE_SOUNDWIRE_ULSRC_PHASE_ENGEN_CON1 0x9418
+#define AFE_SOUNDWIRE_ULSRC_PHASE_RST_CON0 0x941c
+#define AFE_IRQ_MCU_EN 0x9d00
+#define AFE_IRQ_MCU_DSP_EN 0x9d04
+#define AFE_IRQ_MCU_DSP2_EN 0x9d08
+#define AFE_IRQ_MCU_SCP_EN 0x9d0c
+#define AFE_CUSTOM_IRQ_MCU_EN 0x9d10
+#define AFE_CUSTOM_IRQ_MCU_DSP_EN 0x9d14
+#define AFE_CUSTOM_IRQ_MCU_DSP2_EN 0x9d18
+#define AFE_CUSTOM_IRQ_MCU_SCP_EN 0x9d1c
+#define AFE_IRQ_MCU_STATUS 0x9d20
+#define AFE_CUSTOM_IRQ_MCU_STATUS 0x9d24
+#define AFE_IRQ0_MCU_CFG0 0x9d40
+#define AFE_IRQ0_MCU_CFG1 0x9d44
+#define AFE_IRQ1_MCU_CFG0 0x9d48
+#define AFE_IRQ1_MCU_CFG1 0x9d4c
+#define AFE_IRQ2_MCU_CFG0 0x9d50
+#define AFE_IRQ2_MCU_CFG1 0x9d54
+#define AFE_IRQ3_MCU_CFG0 0x9d58
+#define AFE_IRQ3_MCU_CFG1 0x9d5c
+#define AFE_IRQ4_MCU_CFG0 0x9d60
+#define AFE_IRQ4_MCU_CFG1 0x9d64
+#define AFE_IRQ5_MCU_CFG0 0x9d68
+#define AFE_IRQ5_MCU_CFG1 0x9d6c
+#define AFE_IRQ6_MCU_CFG0 0x9d70
+#define AFE_IRQ6_MCU_CFG1 0x9d74
+#define AFE_IRQ7_MCU_CFG0 0x9d78
+#define AFE_IRQ7_MCU_CFG1 0x9d7c
+#define AFE_IRQ8_MCU_CFG0 0x9d80
+#define AFE_IRQ8_MCU_CFG1 0x9d84
+#define AFE_IRQ9_MCU_CFG0 0x9d88
+#define AFE_IRQ9_MCU_CFG1 0x9d8c
+#define AFE_IRQ10_MCU_CFG0 0x9d90
+#define AFE_IRQ10_MCU_CFG1 0x9d94
+#define AFE_IRQ11_MCU_CFG0 0x9d98
+#define AFE_IRQ11_MCU_CFG1 0x9d9c
+#define AFE_IRQ12_MCU_CFG0 0x9da0
+#define AFE_IRQ12_MCU_CFG1 0x9da4
+#define AFE_IRQ13_MCU_CFG0 0x9da8
+#define AFE_IRQ13_MCU_CFG1 0x9dac
+#define AFE_IRQ14_MCU_CFG0 0x9db0
+#define AFE_IRQ14_MCU_CFG1 0x9db4
+#define AFE_IRQ15_MCU_CFG0 0x9db8
+#define AFE_IRQ15_MCU_CFG1 0x9dbc
+#define AFE_IRQ16_MCU_CFG0 0x9dc0
+#define AFE_IRQ16_MCU_CFG1 0x9dc4
+#define AFE_IRQ17_MCU_CFG0 0x9dc8
+#define AFE_IRQ17_MCU_CFG1 0x9dcc
+#define AFE_IRQ18_MCU_CFG0 0x9dd0
+#define AFE_IRQ18_MCU_CFG1 0x9dd4
+#define AFE_IRQ19_MCU_CFG0 0x9dd8
+#define AFE_IRQ19_MCU_CFG1 0x9ddc
+#define AFE_IRQ20_MCU_CFG0 0x9de0
+#define AFE_IRQ20_MCU_CFG1 0x9de4
+#define AFE_IRQ21_MCU_CFG0 0x9de8
+#define AFE_IRQ21_MCU_CFG1 0x9dec
+#define AFE_IRQ22_MCU_CFG0 0x9df0
+#define AFE_IRQ22_MCU_CFG1 0x9df4
+#define AFE_IRQ23_MCU_CFG0 0x9df8
+#define AFE_IRQ23_MCU_CFG1 0x9dfc
+#define AFE_IRQ24_MCU_CFG0 0x9e00
+#define AFE_IRQ24_MCU_CFG1 0x9e04
+#define AFE_IRQ25_MCU_CFG0 0x9e08
+#define AFE_IRQ25_MCU_CFG1 0x9e0c
+#define AFE_IRQ26_MCU_CFG0 0x9e10
+#define AFE_IRQ26_MCU_CFG1 0x9e14
+#define AFE_CUSTOM_IRQ0_MCU_CFG0 0x9e68
+#define AFE_CUSTOM_IRQ22_MCU_CFG0 0x9ec8
+#define AFE_CUSTOM_IRQ22_MCU_CFG1 0x9ecc
+#define AFE_CUSTOM_IRQ23_MCU_CFG0 0x9ed0
+#define AFE_CUSTOM_IRQ23_MCU_CFG1 0x9ed4
+#define AFE_IRQ0_CNT_MON 0x9f10
+#define AFE_IRQ1_CNT_MON 0x9f14
+#define AFE_IRQ2_CNT_MON 0x9f18
+#define AFE_IRQ3_CNT_MON 0x9f1c
+#define AFE_IRQ4_CNT_MON 0x9f20
+#define AFE_IRQ5_CNT_MON 0x9f24
+#define AFE_IRQ6_CNT_MON 0x9f28
+#define AFE_IRQ7_CNT_MON 0x9f2c
+#define AFE_IRQ8_CNT_MON 0x9f30
+#define AFE_IRQ9_CNT_MON 0x9f34
+#define AFE_IRQ10_CNT_MON 0x9f38
+#define AFE_IRQ11_CNT_MON 0x9f3c
+#define AFE_IRQ12_CNT_MON 0x9f40
+#define AFE_IRQ13_CNT_MON 0x9f44
+#define AFE_IRQ14_CNT_MON 0x9f48
+#define AFE_IRQ15_CNT_MON 0x9f4c
+#define AFE_IRQ16_CNT_MON 0x9f50
+#define AFE_IRQ17_CNT_MON 0x9f54
+#define AFE_IRQ18_CNT_MON 0x9f58
+#define AFE_IRQ19_CNT_MON 0x9f5c
+#define AFE_IRQ20_CNT_MON 0x9f60
+#define AFE_IRQ21_CNT_MON 0x9f64
+#define AFE_IRQ22_CNT_MON 0x9f68
+#define AFE_IRQ23_CNT_MON 0x9f6c
+#define AFE_IRQ24_CNT_MON 0x9f70
+#define AFE_IRQ25_CNT_MON 0x9f74
+#define AFE_IRQ26_CNT_MON 0x9f78
+#define AFE_CUSTOM_IRQ0_CNT_MON 0x9f90
+#define AFE_CUSTOM_IRQ0_MCU_CFG1 0x9fdc
+#define AFE_IRQ_MCU_DSP3_EN 0xa000
+#define AFE_CUSTOM_IRQ_MCU_DSP3_EN 0xa004
+#define AFE_CUSTOM2_IRQ_MCU_EN 0xa008
+#define AFE_CUSTOM2_IRQ_MCU_DSP_EN 0xa00c
+#define AFE_CUSTOM2_IRQ_MCU_DSP2_EN 0xa010
+#define AFE_CUSTOM2_IRQ_MCU_DSP3_EN 0xa014
+#define AFE_CUSTOM2_IRQ_MCU_SCP_EN 0xa018
+#define AFE_IRQ_MCU_MON3 0xa01c
+#define AFE_IRQ_MCU_MON0 0xa024
+#define AFE_IRQ_MCU_MON1 0xa028
+#define AFE_IRQ_MCU_MON2 0xa02c
+#define AFE_CUSTOM2_IRQ_MISS_FLAG_MCU_MON 0xa034
+#define AFE_CUSTOM2_IRQ_DELAY_EN 0xa038
+#define AFE_CUSTOM2_IRQ_MCU_STATUS 0xa03c
+#define AFE_CUSTOM2_IRQ0_MCU_CFG0 0xa040
+#define AFE_CUSTOM2_IRQ0_MCU_CFG1 0xa044
+#define AFE_CUSTOM2_IRQ0_CNT_MON 0xa048
+#define AFE_CUSTOM2_IRQ0_MCU_DELAY_CNT_CFG0 0xa04c
+#define AFE_CUSTOM2_IRQ1_MCU_CFG0 0xa050
+#define AFE_CUSTOM2_IRQ1_MCU_CFG1 0xa054
+#define AFE_CUSTOM2_IRQ1_CNT_MON 0xa058
+#define AFE_CUSTOM2_IRQ1_MCU_DELAY_CNT_CFG0 0xa05c
+#define AFE_CUSTOM2_IRQ2_MCU_CFG0 0xa060
+#define AFE_CUSTOM2_IRQ2_MCU_CFG1 0xa064
+#define AFE_CUSTOM2_IRQ2_CNT_MON 0xa068
+#define AFE_CUSTOM2_IRQ2_MCU_DELAY_CNT_CFG0 0xa06c
+#define AFE_CUSTOM2_IRQ3_MCU_CFG0 0xa070
+#define AFE_CUSTOM2_IRQ3_MCU_CFG1 0xa074
+#define AFE_CUSTOM2_IRQ3_CNT_MON 0xa078
+#define AFE_CUSTOM2_IRQ3_MCU_DELAY_CNT_CFG0 0xa07c
+#define AFE_CUSTOM2_IRQ4_MCU_CFG0 0xa080
+#define AFE_CUSTOM2_IRQ4_MCU_CFG1 0xa084
+#define AFE_CUSTOM2_IRQ4_CNT_MON 0xa088
+#define AFE_CUSTOM2_IRQ4_MCU_DELAY_CNT_CFG0 0xa08c
+#define AFE_CUSTOM2_IRQ5_MCU_CFG0 0xa090
+#define AFE_CUSTOM2_IRQ5_MCU_CFG1 0xa094
+#define AFE_CUSTOM2_IRQ5_CNT_MON 0xa098
+#define AFE_CUSTOM2_IRQ5_MCU_DELAY_CNT_CFG0 0xa09c
+#define AFE_CUSTOM2_IRQ6_MCU_CFG0 0xa0a0
+#define AFE_CUSTOM2_IRQ6_MCU_CFG1 0xa0a4
+#define AFE_CUSTOM2_IRQ6_CNT_MON 0xa0a8
+#define AFE_CUSTOM2_IRQ6_MCU_DELAY_CNT_CFG0 0xa0ac
+#define AFE_CUSTOM2_IRQ7_MCU_CFG0 0xa0b0
+#define AFE_CUSTOM2_IRQ7_MCU_CFG1 0xa0b4
+#define AFE_CUSTOM2_IRQ7_CNT_MON 0xa0b8
+#define AFE_CUSTOM2_IRQ7_MCU_DELAY_CNT_CFG0 0xa0bc
+#define AFE_CUSTOM2_IRQ8_MCU_CFG0 0xa0c0
+#define AFE_CUSTOM2_IRQ8_MCU_CFG1 0xa0c4
+#define AFE_CUSTOM2_IRQ8_CNT_MON 0xa0c8
+#define AFE_CUSTOM2_IRQ8_MCU_DELAY_CNT_CFG0 0xa0cc
+#define AFE_CUSTOM2_IRQ9_MCU_CFG0 0xa0d0
+#define AFE_CUSTOM2_IRQ9_MCU_CFG1 0xa0d4
+#define AFE_CUSTOM2_IRQ9_CNT_MON 0xa0d8
+#define AFE_CUSTOM2_IRQ9_MCU_DELAY_CNT_CFG0 0xa0dc
+#define AFE_CUSTOM2_IRQ10_MCU_CFG0 0xa0e0
+#define AFE_CUSTOM2_IRQ10_MCU_CFG1 0xa0e4
+#define AFE_CUSTOM2_IRQ10_CNT_MON 0xa0e8
+#define AFE_CUSTOM2_IRQ10_MCU_DELAY_CNT_CFG0 0xa0ec
+#define AFE_CUSTOM2_IRQ11_MCU_CFG0 0xa0f0
+#define AFE_CUSTOM2_IRQ11_MCU_CFG1 0xa0f4
+#define AFE_CUSTOM2_IRQ11_CNT_MON 0xa0f8
+#define AFE_CUSTOM2_IRQ11_MCU_DELAY_CNT_CFG0 0xa0fc
+#define AFE_CUSTOM2_IRQ12_MCU_CFG0 0xa100
+#define AFE_CUSTOM2_IRQ12_MCU_CFG1 0xa104
+#define AFE_CUSTOM2_IRQ12_CNT_MON 0xa108
+#define AFE_CUSTOM2_IRQ12_MCU_DELAY_CNT_CFG0 0xa10c
+#define AFE_CUSTOM2_IRQ30_MCU_CFG0 0xa220
+#define AFE_CUSTOM2_IRQ30_MCU_CFG1 0xa224
+#define AFE_CUSTOM2_IRQ30_CNT_MON 0xa228
+#define AFE_CUSTOM2_IRQ30_MCU_DELAY_CNT_CFG0 0xa22c
+#define AFE_CUSTOM2_IRQ31_MCU_CFG0 0xa230
+#define AFE_CUSTOM2_IRQ31_MCU_CFG1 0xa234
+#define AFE_CUSTOM2_IRQ31_CNT_MON 0xa238
+#define AFE_CUSTOM2_IRQ31_MCU_DELAY_CNT_CFG0 0xa23c
+#define AFE_CUSTOM3_IRQ8_MCU_CFG0 0xa2c0
+#define AFE_CUSTOM3_IRQ8_MCU_CFG1 0xa2c4
+#define AFE_CUSTOM3_IRQ8_CNT_MON 0xa2c8
+#define AFE_CUSTOM3_IRQ8_MCU_DELAY_CNT_CFG0 0xa2cc
+#define AFE_CUSTOM3_IRQ9_MCU_CFG0 0xa2d0
+#define AFE_CUSTOM3_IRQ9_MCU_CFG1 0xa2d4
+#define AFE_CUSTOM3_IRQ9_CNT_MON 0xa2d8
+#define AFE_CUSTOM3_IRQ9_MCU_DELAY_CNT_CFG0 0xa2dc
+#define AFE_CUSTOM3_IRQ_MISS_FLAG_MCU_MON 0xa440
+#define AFE_CUSTOM3_IRQ_DELAY_EN 0xa444
+#define AFE_CUSTOM3_IRQ_MCU_STATUS 0xa448
+#define AFE_CUSTOM3_IRQ_MCU_EN 0xa44c
+#define AFE_CUSTOM3_IRQ_MCU_DSP_EN 0xa450
+#define AFE_CUSTOM3_IRQ_MCU_DSP2_EN 0xa454
+#define AFE_CUSTOM3_IRQ_MCU_DSP3_EN 0xa458
+#define AFE_CUSTOM3_IRQ_MCU_DSP_WLA_EN 0xa45c
+#define AFE_CUSTOM3_IRQ_MCU_SCP_EN 0xa460
+#define AFE_CUSTOM2_IRQ_MCU_DSP_WLA_EN 0xa464
+#define AFE_IRQ_MCU_DSP_WLA_EN 0xa468
+#define AFE_COMMON2_IRQ_MCU_STATUS 0xa46c
+#define AFE_COMMON2_IRQ_MCU_EN 0xa470
+#define AFE_COMMON2_IRQ_MCU_DSP_EN 0xa474
+#define AFE_COMMON2_IRQ_MCU_DSP2_EN 0xa478
+#define AFE_COMMON2_IRQ_MCU_DSP3_EN 0xa47c
+#define AFE_COMMON2_IRQ_MCU_DSP_WLA_EN 0xa480
+#define AFE_COMMON2_IRQ_MCU_SCP_EN 0xa484
+#define AFE_CUSTOM_IRQ_MCU_DSP_WLA_EN 0xa508
+
+#define AFE_MAX_REGISTER AFE_CUSTOM_IRQ_MCU_DSP_WLA_EN
+
+#define AFE_IRQ_STATUS_BITS 0x7FFFFFF
+#define AFE_IRQ_CNT_SHIFT 0
+#define AFE_IRQ_CNT_MASK 0xffffff
+
+#endif
diff --git a/sound/soc/mediatek/mt8192/Makefile b/sound/soc/mediatek/mt8192/Makefile
index 8b27d82626ea..d60c36bcdcce 100644
--- a/sound/soc/mediatek/mt8192/Makefile
+++ b/sound/soc/mediatek/mt8192/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt8192-afe-objs := \
+snd-soc-mt8192-afe-y := \
mt8192-afe-pcm.o \
mt8192-afe-clk.o \
mt8192-afe-gpio.o \
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c
index 165663a78e36..de5e1deaa167 100644
--- a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c
@@ -6,7 +6,6 @@
// Author: Shane Chien <shane.chien@mediatek.com>
//
-#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include "mt8192-afe-common.h"
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
index d0520e7e1d79..3d32fe46118e 100644
--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
@@ -12,6 +12,7 @@
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <sound/soc.h>
@@ -42,11 +43,11 @@ static const struct snd_pcm_hardware mt8192_afe_hardware = {
static int mt8192_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
return mt8192_rate_transform(afe->dev, rate, id);
}
@@ -59,7 +60,7 @@ static int mt8192_get_dai_fs(struct mtk_base_afe *afe,
static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
@@ -2125,22 +2126,6 @@ skip_regmap:
return 0;
}
-static int mt8192_afe_component_probe(struct snd_soc_component *component)
-{
- return mtk_afe_add_sub_dai_control(component);
-}
-
-static const struct snd_soc_component_driver mt8192_afe_component = {
- .name = AFE_PCM_NAME,
- .probe = mt8192_afe_component_probe,
- .pointer = mtk_afe_pcm_pointer,
- .pcm_construct = mtk_afe_pcm_new,
-};
-
-static const struct snd_soc_component_driver mt8192_afe_pcm_component = {
- .name = "mt8192-afe-pcm-dai",
-};
-
static int mt8192_dai_memif_register(struct mtk_base_afe *afe)
{
struct mtk_base_afe_dai *dai;
@@ -2174,27 +2159,32 @@ 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;
+
+ ret = of_reserved_mem_device_init(dev);
+ if (ret) {
+ dev_info(dev, "no reserved memory found, pre-allocating buffers instead\n");
+ afe->preallocate_buffers = true;
+ }
/* init audio related clock */
ret = mt8192_init_clock(afe);
@@ -2205,46 +2195,36 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
/* reset controller to reset audio regs before regmap cache */
rstc = devm_reset_control_get_exclusive(dev, "audiosys");
- if (IS_ERR(rstc)) {
- ret = PTR_ERR(rstc);
- dev_err(dev, "could not get audiosys reset:%d\n", ret);
- return ret;
- }
+ if (IS_ERR(rstc))
+ return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n");
ret = reset_control_reset(rstc);
- if (ret) {
- dev_err(dev, "failed to trigger audio reset:%d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to trigger audio reset\n");
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev))
- goto err_pm_disable;
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
/* regmap init */
afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
- if (IS_ERR(afe->regmap)) {
- dev_err(dev, "could not get regmap from parent\n");
- ret = PTR_ERR(afe->regmap);
- goto err_pm_disable;
- }
+ if (IS_ERR(afe->regmap))
+ return dev_err_probe(dev, PTR_ERR(afe->regmap),
+ "could not get regmap from parent");
+
ret = regmap_attach_dev(dev, afe->regmap, &mt8192_afe_regmap_config);
- if (ret) {
- dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "regmap_attach_dev fail\n");
/* 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) {
- dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
- goto err_pm_disable;
- }
+ 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);
@@ -2254,10 +2234,8 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
afe->memif_size = MT8192_MEMIF_NUM;
afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
GFP_KERNEL);
- if (!afe->memif) {
- ret = -ENOMEM;
- goto err_pm_disable;
- }
+ if (!afe->memif)
+ return -ENOMEM;
for (i = 0; i < afe->memif_size; i++) {
afe->memif[i].data = &memif_data[i];
@@ -2271,47 +2249,35 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
afe->irqs_size = MT8192_IRQ_NUM;
afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
GFP_KERNEL);
- if (!afe->irqs) {
- ret = -ENOMEM;
- goto err_pm_disable;
- }
+ if (!afe->irqs)
+ return -ENOMEM;
for (i = 0; i < afe->irqs_size; i++)
afe->irqs[i].irq_data = &irq_data[i];
/* request irq */
irq_id = platform_get_irq(pdev, 0);
- if (irq_id < 0) {
- ret = irq_id;
- goto err_pm_disable;
- }
+ if (irq_id < 0)
+ return irq_id;
ret = devm_request_irq(dev, irq_id, mt8192_afe_irq_handler,
IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
- if (ret) {
- dev_err(dev, "could not request_irq for Afe_ISR_Handle\n");
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
/* init sub_dais */
INIT_LIST_HEAD(&afe->sub_dais);
for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
ret = dai_register_cbs[i](afe);
- if (ret) {
- dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
- i, ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "dai %d register fail", i);
}
/* init dai_driver and component_driver */
ret = mtk_afe_combine_sub_dai(afe);
- if (ret) {
- dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
- ret);
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "mtk_afe_combine_sub_dai fail\n");
/* others */
afe->mtk_afe_hardware = &mt8192_afe_hardware;
@@ -2325,28 +2291,14 @@ 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,
- &mt8192_afe_component, NULL, 0);
- if (ret) {
- dev_warn(dev, "err_platform\n");
- goto err_pm_disable;
- }
-
- ret = devm_snd_soc_register_component(&pdev->dev,
- &mt8192_afe_pcm_component,
+ ret = devm_snd_soc_register_component(dev,
+ &mtk_afe_pcm_platform,
afe->dai_drivers,
afe->num_dai_drivers);
- if (ret) {
- dev_warn(dev, "err_dai_component\n");
- goto err_pm_disable;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Couldn't register AFE component\n");
return 0;
-
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static void mt8192_afe_pcm_dev_remove(struct platform_device *pdev)
@@ -2368,18 +2320,18 @@ 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_new = mt8192_afe_pcm_dev_remove,
+ .remove = mt8192_afe_pcm_dev_remove,
};
module_platform_driver(mt8192_afe_pcm_driver);
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
index 4919535e2759..f8cb84621d38 100644
--- a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c
@@ -13,6 +13,7 @@
#include "mt8192-afe-common.h"
#include "mt8192-afe-gpio.h"
#include "mt8192-interconnection.h"
+#include "../common/mtk-dai-adda-common.h"
enum {
UL_IIR_SW = 0,
@@ -35,93 +36,8 @@ enum {
AUDIO_SDM_3RD,
};
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO2,
-};
-
-enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
- MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
-};
-
#define SDM_AUTO_RESET_THRESHOLD 0x190000
-static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
/* dai component */
static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0),
@@ -435,7 +351,7 @@ static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0,
0x00010000);
- if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 &&
+ if (snd_soc_dapm_widget_name_cmp(w, "ADDA_MTKAIF_CFG") == 0 &&
(afe_priv->mtkaif_chosen_phase[0] < 0 ||
afe_priv->mtkaif_chosen_phase[1] < 0)) {
dev_warn(afe->dev,
@@ -444,7 +360,7 @@ static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
afe_priv->mtkaif_chosen_phase[0],
afe_priv->mtkaif_chosen_phase[1]);
break;
- } else if (strcmp(w->name, "ADDA6_MTKAIF_CFG") == 0 &&
+ } else if (snd_soc_dapm_widget_name_cmp(w, "ADDA6_MTKAIF_CFG") == 0 &&
afe_priv->mtkaif_chosen_phase[2] < 0) {
dev_warn(afe->dev,
"%s(), mtkaif_chosen_phase[2]:%d\n",
@@ -576,7 +492,7 @@ static int mtk_adda_ch34_dl_event(struct snd_soc_dapm_widget *w,
static int stf_positive_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
@@ -587,7 +503,7 @@ static int stf_positive_gain_get(struct snd_kcontrol *kcontrol,
static int stf_positive_gain_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
int gain_db = ucontrol->value.integer.value[0];
@@ -611,7 +527,7 @@ static int stf_positive_gain_set(struct snd_kcontrol *kcontrol,
static int mt8192_adda_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
@@ -622,7 +538,7 @@ static int mt8192_adda_dmic_get(struct snd_kcontrol *kcontrol,
static int mt8192_adda_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
int dmic_on;
@@ -642,7 +558,7 @@ static int mt8192_adda_dmic_set(struct snd_kcontrol *kcontrol,
static int mt8192_adda6_only_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
@@ -653,7 +569,7 @@ static int mt8192_adda6_only_get(struct snd_kcontrol *kcontrol,
static int mt8192_adda6_only_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
int mtkaif_adda6_only;
@@ -1156,7 +1072,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
unsigned int dl_src2_con1 = 0;
/* set sampling rate */
- dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+ dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) <<
DL_2_INPUT_MODE_CTL_SFT;
/* set output mode, UP_SAMPLING_RATE_X8 */
@@ -1246,7 +1162,7 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
unsigned int voice_mode = 0;
unsigned int ul_src_con0 = 0; /* default value */
- voice_mode = adda_ul_rate_transform(afe, rate);
+ voice_mode = mtk_adda_ul_rate_transform(afe, rate);
ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c
index ea516d63d94d..1632fc94776d 100644
--- a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c
@@ -135,7 +135,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(mt8192_i2s_enum, mt8192_i2s_hd_str);
static int mt8192_i2s_hd_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mtk_afe_i2s_priv *i2s_priv;
@@ -154,7 +154,7 @@ static int mt8192_i2s_hd_get(struct snd_kcontrol *kcontrol,
static int mt8192_i2s_hd_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mtk_afe_i2s_priv *i2s_priv;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -623,13 +623,13 @@ static int mtk_apll_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8192_apll1_enable(afe);
else
mt8192_apll2_enable(afe);
break;
case SND_SOC_DAPM_POST_PMD:
- if (strcmp(w->name, APLL1_W_NAME) == 0)
+ if (snd_soc_dapm_widget_name_cmp(w, APLL1_W_NAME) == 0)
mt8192_apll1_disable(afe);
else
mt8192_apll2_disable(afe);
diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
index 9ce06821c7d0..49440db370af 100644
--- a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
@@ -566,10 +566,10 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
tdm_con |= 1 << DELAY_DATA_SFT;
tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
} else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_A) {
- tdm_con |= 0 << DELAY_DATA_SFT;
+ tdm_con |= 1 << DELAY_DATA_SFT;
tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
} else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_B) {
- tdm_con |= 1 << DELAY_DATA_SFT;
+ tdm_con |= 0 << DELAY_DATA_SFT;
tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
}
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index 5e163e23a207..91c57765ab57 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -9,7 +9,7 @@
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
@@ -20,6 +20,8 @@
#include "../../codecs/rt1015.h"
#include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-soc-card.h"
+#include "../common/mtk-soundcard-driver.h"
#include "mt8192-afe-common.h"
#include "mt8192-afe-clk.h"
#include "mt8192-afe-gpio.h"
@@ -38,9 +40,10 @@
#define RT1015P_RT5682_OF_NAME "mediatek,mt8192_mt6359_rt1015p_rt5682"
#define RT1015P_RT5682S_OF_NAME "mediatek,mt8192_mt6359_rt1015p_rt5682s"
-struct mt8192_mt6359_priv {
- struct snd_soc_jack headset_jack;
- struct snd_soc_jack hdmi_jack;
+enum mt8192_jacks {
+ MT8192_JACK_HEADSET,
+ MT8192_JACK_HDMI,
+ MT8192_JACK_MAX,
};
/* Headset jack detection DAPM pins */
@@ -58,9 +61,9 @@ static struct snd_soc_jack_pin mt8192_jack_pins[] = {
static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai;
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
@@ -93,10 +96,10 @@ static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream,
static int mt8192_rt5682x_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
@@ -149,7 +152,7 @@ static int mt8192_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
int phase;
@@ -306,7 +309,7 @@ static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8192_afe_private *afe_priv = afe->platform_priv;
@@ -323,13 +326,13 @@ static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd)
static int mt8192_rt5682_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[MT8192_JACK_HEADSET];
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
- struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_jack *jack = &priv->headset_jack;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
ret = mt8192_dai_i2s_set_share(afe, "I2S8", "I2S9");
@@ -359,19 +362,19 @@ static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd)
static int mt8192_mt6359_hdmi_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[MT8192_JACK_HDMI];
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
- struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
- &priv->hdmi_jack);
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack);
if (ret) {
dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
return ret;
}
- return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+ return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
}
static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -386,100 +389,6 @@ static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int
-mt8192_mt6359_cap1_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int channels[] = {
- 1, 2, 4
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
- static const unsigned int rates[] = {
- 8000, 16000, 32000, 48000, 96000, 192000
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channels failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8192_mt6359_capture1_ops = {
- .startup = mt8192_mt6359_cap1_startup,
-};
-
-static int
-mt8192_mt6359_rt5682_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int channels[] = {
- 1, 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
- static const unsigned int rates[] = {
- 48000
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channels failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8192_mt6359_rt5682_ops = {
- .startup = mt8192_mt6359_rt5682_startup,
-};
-
/* FE */
SND_SOC_DAILINK_DEFS(playback1,
DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
@@ -689,7 +598,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback1),
},
{
@@ -698,7 +607,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback12),
},
{
@@ -707,7 +616,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback2),
},
{
@@ -716,8 +625,8 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
- .ops = &mt8192_mt6359_rt5682_ops,
+ .playback_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(playback3),
},
{
@@ -726,7 +635,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback4),
},
{
@@ -735,7 +644,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback5),
},
{
@@ -744,7 +653,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback6),
},
{
@@ -753,7 +662,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback7),
},
{
@@ -762,7 +671,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback8),
},
{
@@ -771,7 +680,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback9),
},
{
@@ -780,8 +689,8 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8192_mt6359_capture1_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(capture1),
},
{
@@ -790,8 +699,8 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8192_mt6359_rt5682_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(capture2),
},
{
@@ -800,7 +709,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture3),
},
{
@@ -809,7 +718,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture4),
},
{
@@ -818,7 +727,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture5),
},
{
@@ -827,7 +736,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture6),
},
{
@@ -836,7 +745,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture7),
},
{
@@ -845,7 +754,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture8),
},
{
@@ -854,7 +763,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_mono1),
},
{
@@ -863,7 +772,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_mono2),
},
{
@@ -872,7 +781,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(capture_mono3),
},
{
@@ -881,15 +790,13 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(playback_hdmi),
},
/* Back End DAI links */
{
.name = "Primary Codec",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
.init = mt8192_mt6359_init,
SND_SOC_DAILINK_REG(primary_codec),
@@ -897,29 +804,27 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "Primary Codec CH34",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(primary_codec_ch34),
},
{
.name = "AP_DMIC",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(ap_dmic),
},
{
.name = "AP_DMIC_CH34",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(ap_dmic_ch34),
},
{
.name = "I2S0",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s0),
@@ -927,7 +832,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S1",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s1),
@@ -935,7 +840,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S2",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s2),
@@ -943,7 +848,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S3",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s3),
@@ -951,7 +856,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S5",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s5),
@@ -959,7 +864,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S6",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s6),
@@ -967,7 +872,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S7",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s7),
@@ -975,7 +880,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S8",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
.init = mt8192_rt5682_init,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
@@ -985,7 +890,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "I2S9",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s9),
@@ -994,23 +899,19 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
{
.name = "CONNSYS_I2S",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(connsys_i2s),
},
{
.name = "PCM 1",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm1),
},
{
.name = "PCM 2",
.no_pcm = 1,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm2),
},
@@ -1019,8 +920,8 @@ 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,
- .dpcm_playback = 1,
+ SND_SOC_DAIFMT_CBP_CFP,
+ .playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
.ignore = 1,
@@ -1136,71 +1037,53 @@ static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card,
return 0;
}
-static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
+static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data)
{
- struct snd_soc_card *card;
- struct device_node *platform_node, *hdmi_codec, *headset_codec, *speaker_codec;
- int ret, i;
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ struct device *dev = card->dev;
+ struct device_node *hdmi_codec, *headset_codec, *speaker_codec;
struct snd_soc_dai_link *dai_link;
- struct mt8192_mt6359_priv *priv;
-
- card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
- if (!card)
- return -EINVAL;
- card->dev = &pdev->dev;
+ int i, ret = 0;
- if (of_device_is_compatible(pdev->dev.of_node, RT1015P_RT5682_OF_NAME))
- card->name = RT1015P_RT5682_CARD_NAME;
- else if (of_device_is_compatible(pdev->dev.of_node, RT1015P_RT5682S_OF_NAME))
- card->name = RT1015P_RT5682S_CARD_NAME;
- else
- dev_dbg(&pdev->dev, "No need to set card name\n");
-
- hdmi_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,hdmi-codec", 0);
+ hdmi_codec = of_parse_phandle(dev->of_node, "mediatek,hdmi-codec", 0);
if (!hdmi_codec)
- dev_dbg(&pdev->dev, "The machine has no hdmi-codec\n");
+ dev_dbg(dev, "The machine has no hdmi-codec\n");
- platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
- if (!platform_node) {
- ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
- goto err_platform_node;
- }
-
- speaker_codec = of_get_child_by_name(pdev->dev.of_node, "speaker-codecs");
+ speaker_codec = of_get_child_by_name(dev->of_node, "speaker-codecs");
if (!speaker_codec) {
ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n");
+ dev_err_probe(dev, ret, "Property 'speaker-codecs' missing or invalid\n");
goto err_speaker_codec;
}
- headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec");
+ headset_codec = of_get_child_by_name(dev->of_node, "headset-codec");
if (!headset_codec) {
ret = -EINVAL;
- dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n");
+ dev_err_probe(dev, ret, "Property 'headset-codec' missing or invalid\n");
goto err_headset_codec;
}
for_each_card_prelinks(card, i, dai_link) {
ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3");
if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n",
+ dev_err_probe(dev, ret, "%s set speaker_codec fail\n",
dai_link->name);
- goto err_probe;
+ break;
}
ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8");
if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+ dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
- goto err_probe;
+ break;
}
ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9");
if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+ dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
- goto err_probe;
+ break;
}
if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
@@ -1208,54 +1091,123 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev)
dai_link->ignore = 0;
}
- if (strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0)
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0)
dai_link->ops = &mt8192_rt1015_i2s_ops;
-
- if (!dai_link->platforms->name)
- dai_link->platforms->of_node = platform_node;
- }
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto err_probe;
- }
- snd_soc_card_set_drvdata(card, priv);
-
- ret = mt8192_afe_gpio_init(&pdev->dev);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__);
- goto err_probe;
}
- ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret)
- dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
-
-err_probe:
of_node_put(headset_codec);
err_headset_codec:
of_node_put(speaker_codec);
err_speaker_codec:
- of_node_put(platform_node);
-err_platform_node:
of_node_put(hdmi_codec);
return ret;
}
+static int mt8192_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ int ret;
+
+ if (legacy) {
+ ret = mt8192_mt6359_legacy_probe(soc_card_data);
+ if (ret)
+ return ret;
+ } else {
+ struct snd_soc_dai_link *dai_link;
+ int i;
+
+ for_each_card_prelinks(card, i, dai_link)
+ if (dai_link->num_codecs &&
+ strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0)
+ dai_link->ops = &mt8192_rt1015_i2s_ops;
+ }
+
+ ret = mt8192_afe_gpio_init(card->dev);
+ if (ret)
+ return dev_err_probe(card->dev, ret, "%s init gpio error\n", __func__);
+
+ return 0;
+}
+
+static const unsigned int mt8192_pcm_playback_channels[] = { 1, 2 };
+static const unsigned int mt8192_pcm_playback_rates[] = { 48000 };
+
+static const unsigned int mt8192_pcm_capture_channels[] = { 1, 2, 4 };
+static const unsigned int mt8192_pcm_capture_rates[] = {
+ 8000, 16000, 32000, 48000, 96000, 192000
+};
+
+static const struct mtk_pcm_constraints_data mt8192_pcm_constraints[MTK_CONSTRAINT_CAPTURE + 1] = {
+ [MTK_CONSTRAINT_PLAYBACK] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8192_pcm_playback_channels,
+ .count = ARRAY_SIZE(mt8192_pcm_playback_channels)
+ },
+ .rates = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8192_pcm_playback_rates,
+ .count = ARRAY_SIZE(mt8192_pcm_playback_rates)
+ }
+ },
+ [MTK_CONSTRAINT_CAPTURE] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8192_pcm_capture_channels,
+ .count = ARRAY_SIZE(mt8192_pcm_capture_channels)
+ },
+ .rates = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8192_pcm_capture_rates,
+ .count = ARRAY_SIZE(mt8192_pcm_capture_rates)
+ }
+ }
+};
+
+static const struct mtk_soundcard_pdata mt8192_mt6359_rt1015_rt5682_pdata = {
+ .card_name = RT1015_RT5682_CARD_NAME,
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8192_mt6359_rt1015_rt5682_card,
+ .num_jacks = MT8192_JACK_MAX,
+ .pcm_constraints = mt8192_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8192_pcm_constraints),
+ },
+ .soc_probe = mt8192_mt6359_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8192_mt6359_rt1015p_rt5682_pdata = {
+ .card_name = RT1015P_RT5682_CARD_NAME,
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8192_mt6359_rt1015p_rt5682x_card,
+ .num_jacks = MT8192_JACK_MAX,
+ .pcm_constraints = mt8192_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8192_pcm_constraints),
+ },
+ .soc_probe = mt8192_mt6359_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8192_mt6359_rt1015p_rt5682s_pdata = {
+ .card_name = RT1015P_RT5682S_CARD_NAME,
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8192_mt6359_rt1015p_rt5682x_card,
+ .num_jacks = MT8192_JACK_MAX,
+ .pcm_constraints = mt8192_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8192_pcm_constraints),
+ },
+ .soc_probe = mt8192_mt6359_soc_card_probe
+};
+
#ifdef CONFIG_OF
static const struct of_device_id mt8192_mt6359_dt_match[] = {
{
.compatible = RT1015_RT5682_OF_NAME,
- .data = &mt8192_mt6359_rt1015_rt5682_card,
+ .data = &mt8192_mt6359_rt1015_rt5682_pdata,
},
{
.compatible = RT1015P_RT5682_OF_NAME,
- .data = &mt8192_mt6359_rt1015p_rt5682x_card,
+ .data = &mt8192_mt6359_rt1015p_rt5682_pdata,
},
{
.compatible = RT1015P_RT5682S_OF_NAME,
- .data = &mt8192_mt6359_rt1015p_rt5682x_card,
+ .data = &mt8192_mt6359_rt1015p_rt5682s_pdata,
},
{}
};
@@ -1275,7 +1227,7 @@ static struct platform_driver mt8192_mt6359_driver = {
#endif
.pm = &mt8192_mt6359_pm_ops,
},
- .probe = mt8192_mt6359_dev_probe,
+ .probe = mtk_soundcard_common_probe,
};
module_platform_driver(mt8192_mt6359_driver);
diff --git a/sound/soc/mediatek/mt8195/Makefile b/sound/soc/mediatek/mt8195/Makefile
index aae673ec751b..014e93dace26 100644
--- a/sound/soc/mediatek/mt8195/Makefile
+++ b/sound/soc/mediatek/mt8195/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
-snd-soc-mt8195-afe-objs := \
+snd-soc-mt8195-afe-y := \
mt8195-audsys-clk.o \
mt8195-afe-clk.o \
mt8195-afe-pcm.o \
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
index 9ca2cb8c8a9c..f35318ae0739 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
@@ -410,11 +410,6 @@ int mt8195_afe_init_clock(struct mtk_base_afe *afe)
return 0;
}
-void mt8195_afe_deinit_clock(struct mtk_base_afe *afe)
-{
- mt8195_audsys_clk_unregister(afe);
-}
-
int mt8195_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
{
int ret;
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.h b/sound/soc/mediatek/mt8195/mt8195-afe-clk.h
index 40663e31becd..a08c0ee6c860 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.h
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.h
@@ -101,7 +101,6 @@ int mt8195_afe_get_mclk_source_clk_id(int sel);
int mt8195_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll);
int mt8195_afe_get_default_mclk_source_by_rate(int rate);
int mt8195_afe_init_clock(struct mtk_base_afe *afe);
-void mt8195_afe_deinit_clock(struct mtk_base_afe *afe);
int mt8195_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
void mt8195_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
int mt8195_afe_prepare_clk(struct mtk_base_afe *afe, struct clk *clk);
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
index d22cf1664d8a..bc0a63457cd7 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
@@ -84,11 +84,11 @@ int mt8195_afe_fs_timing(unsigned int rate)
static int mt8195_memif_fs(struct snd_pcm_substream *substream,
unsigned int rate)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
int fs = mt8195_afe_fs_timing(rate);
@@ -281,10 +281,10 @@ mt8195_afe_paired_memif_clk_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai,
int enable)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int clk_id;
if (id != MT8195_AFE_MEMIF_DL8 && id != MT8195_AFE_MEMIF_DL10)
@@ -310,10 +310,10 @@ mt8195_afe_paired_memif_clk_enable(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai,
int enable)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int clk_id;
if (id != MT8195_AFE_MEMIF_DL8 && id != MT8195_AFE_MEMIF_DL10)
@@ -342,10 +342,10 @@ mt8195_afe_paired_memif_clk_enable(struct snd_pcm_substream *substream,
static int mt8195_afe_fe_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int ret = 0;
mt8195_afe_paired_memif_clk_prepare(substream, dai, 1);
@@ -380,9 +380,9 @@ static int mt8195_afe_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
- int id = asoc_rtd_to_cpu(rtd, 0)->id;
+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct mtk_base_afe_memif *memif = &afe->memif[id];
const struct mtk_base_memif_data *data = memif->data;
const struct mt8195_afe_channel_merge *cm = mt8195_afe_found_cm(dai);
@@ -1460,8 +1460,7 @@ static const unsigned int mt8195_afe_1x_en_sel_values[] = {
static int mt8195_memif_1x_en_sel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtk_dai_memif_priv *memif_priv;
@@ -1484,8 +1483,7 @@ static int mt8195_memif_1x_en_sel_put(struct snd_kcontrol *kcontrol,
static int mt8195_asys_irq_1x_en_sel_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
unsigned int id = kcontrol->id.device;
@@ -1795,10 +1793,6 @@ static const struct snd_kcontrol_new mt8195_memif_controls[] = {
MT8195_AFE_IRQ_28),
};
-static const struct snd_soc_component_driver mt8195_afe_pcm_dai_component = {
- .name = "mt8195-afe-pcm-dai",
-};
-
static const struct mtk_base_memif_data memif_data[MT8195_AFE_MEMIF_NUM] = {
[MT8195_AFE_MEMIF_DL2] = {
.name = "DL2",
@@ -2948,25 +2942,6 @@ skip_regmap:
return 0;
}
-static int mt8195_afe_component_probe(struct snd_soc_component *component)
-{
- struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int ret = 0;
-
- snd_soc_component_init_regmap(component, afe->regmap);
-
- ret = mtk_afe_add_sub_dai_control(component);
-
- return ret;
-}
-
-static const struct snd_soc_component_driver mt8195_afe_component = {
- .name = AFE_PCM_NAME,
- .pointer = mtk_afe_pcm_pointer,
- .pcm_construct = mtk_afe_pcm_new,
- .probe = mt8195_afe_component_probe,
-};
-
static int init_memif_priv_data(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -3037,7 +3012,6 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct reset_control *rstc;
int i, irq_id, ret;
- struct snd_soc_component *component;
ret = of_reserved_mem_device_init(dev);
if (ret)
@@ -3169,37 +3143,13 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
}
/* register component */
- ret = devm_snd_soc_register_component(dev, &mt8195_afe_component,
- NULL, 0);
+ ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
+ afe->dai_drivers, afe->num_dai_drivers);
if (ret) {
dev_warn(dev, "err_platform\n");
goto err_pm_put;
}
- component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
- if (!component) {
- ret = -ENOMEM;
- goto err_pm_put;
- }
-
- ret = snd_soc_component_initialize(component,
- &mt8195_afe_pcm_dai_component,
- dev);
- if (ret)
- goto err_pm_put;
-
-#ifdef CONFIG_DEBUG_FS
- component->debugfs_prefix = "pcm";
-#endif
-
- ret = snd_soc_add_component(component,
- afe->dai_drivers,
- afe->num_dai_drivers);
- if (ret) {
- dev_warn(dev, "err_dai_component\n");
- goto err_pm_put;
- }
-
ret = regmap_multi_reg_write(afe->regmap, mt8195_afe_reg_defaults,
ARRAY_SIZE(mt8195_afe_reg_defaults));
if (ret)
@@ -3224,15 +3174,8 @@ err_pm_put:
static void mt8195_afe_pcm_dev_remove(struct platform_device *pdev)
{
- struct mtk_base_afe *afe = platform_get_drvdata(pdev);
-
- snd_soc_unregister_component(&pdev->dev);
-
- pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
mt8195_afe_runtime_suspend(&pdev->dev);
-
- mt8195_afe_deinit_clock(afe);
}
static const struct of_device_id mt8195_afe_pcm_dt_match[] = {
@@ -3242,18 +3185,18 @@ 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_new = mt8195_afe_pcm_dev_remove,
+ .remove = mt8195_afe_pcm_dev_remove,
};
module_platform_driver(mt8195_afe_pcm_driver);
diff --git a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
index e0670e0dbd5b..38594bc3f2f7 100644
--- a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
+++ b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
@@ -148,6 +148,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
GATE_AUD6(CLK_AUD_GASRC19, "aud_gasrc19", "top_asm_h", 19),
};
+static void mt8195_audsys_clk_unregister(void *data)
+{
+ struct mtk_base_afe *afe = data;
+ struct mt8195_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
+
int mt8195_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -188,27 +211,5 @@ int mt8195_audsys_clk_register(struct mtk_base_afe *afe)
afe_priv->lookup[i] = cl;
}
- return 0;
-}
-
-void mt8195_audsys_clk_unregister(struct mtk_base_afe *afe)
-{
- struct mt8195_afe_private *afe_priv = afe->platform_priv;
- struct clk *clk;
- struct clk_lookup *cl;
- int i;
-
- if (!afe_priv)
- return;
-
- for (i = 0; i < CLK_AUD_NR_CLK; i++) {
- cl = afe_priv->lookup[i];
- if (!cl)
- continue;
-
- clk = cl->clk;
- clk_unregister_gate(clk);
-
- clkdev_drop(cl);
- }
+ return devm_add_action_or_reset(afe->dev, mt8195_audsys_clk_unregister, afe);
}
diff --git a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
index 239d31016ba7..69db2dd1c9e0 100644
--- a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
+++ b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
@@ -10,6 +10,5 @@
#define _MT8195_AUDSYS_CLK_H_
int mt8195_audsys_clk_register(struct mtk_base_afe *afe);
-void mt8195_audsys_clk_unregister(struct mtk_base_afe *afe);
#endif
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c
index 0dd35255066b..94abde15ea09 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c
@@ -12,6 +12,7 @@
#include "mt8195-afe-clk.h"
#include "mt8195-afe-common.h"
#include "mt8195-reg.h"
+#include "../common/mtk-dai-adda-common.h"
#define ADDA_DL_GAIN_LOOPBACK 0x1800
#define ADDA_HIRES_THRES 48000
@@ -26,35 +27,6 @@ enum {
};
enum {
- MTK_AFE_ADDA_DL_RATE_8K = 0,
- MTK_AFE_ADDA_DL_RATE_11K = 1,
- MTK_AFE_ADDA_DL_RATE_12K = 2,
- MTK_AFE_ADDA_DL_RATE_16K = 3,
- MTK_AFE_ADDA_DL_RATE_22K = 4,
- MTK_AFE_ADDA_DL_RATE_24K = 5,
- MTK_AFE_ADDA_DL_RATE_32K = 6,
- MTK_AFE_ADDA_DL_RATE_44K = 7,
- MTK_AFE_ADDA_DL_RATE_48K = 8,
- MTK_AFE_ADDA_DL_RATE_96K = 9,
- MTK_AFE_ADDA_DL_RATE_192K = 10,
-};
-
-enum {
- MTK_AFE_ADDA_UL_RATE_8K = 0,
- MTK_AFE_ADDA_UL_RATE_16K = 1,
- MTK_AFE_ADDA_UL_RATE_32K = 2,
- MTK_AFE_ADDA_UL_RATE_48K = 3,
- MTK_AFE_ADDA_UL_RATE_96K = 4,
- MTK_AFE_ADDA_UL_RATE_192K = 5,
-};
-
-enum {
- DELAY_DATA_MISO1 = 0,
- DELAY_DATA_MISO0 = 1,
- DELAY_DATA_MISO2 = 1,
-};
-
-enum {
MTK_AFE_ADDA,
MTK_AFE_ADDA6,
};
@@ -63,62 +35,6 @@ struct mtk_dai_adda_priv {
bool hires_required;
};
-static unsigned int afe_adda_dl_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_DL_RATE_8K;
- case 11025:
- return MTK_AFE_ADDA_DL_RATE_11K;
- case 12000:
- return MTK_AFE_ADDA_DL_RATE_12K;
- case 16000:
- return MTK_AFE_ADDA_DL_RATE_16K;
- case 22050:
- return MTK_AFE_ADDA_DL_RATE_22K;
- case 24000:
- return MTK_AFE_ADDA_DL_RATE_24K;
- case 32000:
- return MTK_AFE_ADDA_DL_RATE_32K;
- case 44100:
- return MTK_AFE_ADDA_DL_RATE_44K;
- case 48000:
- return MTK_AFE_ADDA_DL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_DL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_DL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_DL_RATE_48K;
- }
-}
-
-static unsigned int afe_adda_ul_rate_transform(struct mtk_base_afe *afe,
- unsigned int rate)
-{
- switch (rate) {
- case 8000:
- return MTK_AFE_ADDA_UL_RATE_8K;
- case 16000:
- return MTK_AFE_ADDA_UL_RATE_16K;
- case 32000:
- return MTK_AFE_ADDA_UL_RATE_32K;
- case 48000:
- return MTK_AFE_ADDA_UL_RATE_48K;
- case 96000:
- return MTK_AFE_ADDA_UL_RATE_96K;
- case 192000:
- return MTK_AFE_ADDA_UL_RATE_192K;
- default:
- dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
- __func__, rate);
- return MTK_AFE_ADDA_UL_RATE_48K;
- }
-}
-
static int mt8195_adda_mtkaif_init(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -568,7 +484,7 @@ static int mt8195_adda_dl_gain_get(struct snd_kcontrol *kcontrol,
static int mt8195_adda6_only_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -580,7 +496,7 @@ static int mt8195_adda6_only_get(struct snd_kcontrol *kcontrol,
static int mt8195_adda6_only_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -599,7 +515,7 @@ static int mt8195_adda6_only_set(struct snd_kcontrol *kcontrol,
static int mt8195_adda_dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -611,7 +527,7 @@ static int mt8195_adda_dmic_get(struct snd_kcontrol *kcontrol,
static int mt8195_adda_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -644,7 +560,7 @@ static int mtk_dai_da_configure(struct mtk_base_afe *afe,
/* set sampling rate */
mask |= DL_2_INPUT_MODE_CTL_MASK;
- val |= DL_2_INPUT_MODE_CTL(afe_adda_dl_rate_transform(afe, rate));
+ val |= DL_2_INPUT_MODE_CTL(mtk_adda_dl_rate_transform(afe, rate));
/* turn off saturation */
mask |= DL_2_CH1_SATURATION_EN_CTL;
@@ -681,7 +597,7 @@ static int mtk_dai_ad_configure(struct mtk_base_afe *afe,
unsigned int mask = 0;
mask |= UL_VOICE_MODE_CTL_MASK;
- val |= UL_VOICE_MODE_CTL(afe_adda_ul_rate_transform(afe, rate));
+ val |= UL_VOICE_MODE_CTL(mtk_adda_ul_rate_transform(afe, rate));
switch (id) {
case MT8195_AFE_IO_UL_SRC1:
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
index eedb9165f911..723cab01e72e 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
@@ -738,8 +738,7 @@ static int mt8195_etdm_clk_src_sel_put(struct snd_kcontrol *kcontrol,
static int mt8195_etdm_clk_src_sel_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
unsigned int value = 0;
unsigned int reg = 0;
@@ -2456,25 +2455,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai,
return mtk_dai_etdm_cal_mclk(afe, freq, dai->id);
}
-static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
- .startup = mtk_dai_etdm_startup,
- .shutdown = mtk_dai_etdm_shutdown,
- .hw_params = mtk_dai_etdm_hw_params,
- .trigger = mtk_dai_etdm_trigger,
- .set_sysclk = mtk_dai_etdm_set_sysclk,
- .set_fmt = mtk_dai_etdm_set_fmt,
- .set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
-};
-
-static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
- .startup = mtk_dai_hdmitx_dptx_startup,
- .shutdown = mtk_dai_hdmitx_dptx_shutdown,
- .hw_params = mtk_dai_hdmitx_dptx_hw_params,
- .trigger = mtk_dai_hdmitx_dptx_trigger,
- .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
- .set_fmt = mtk_dai_etdm_set_fmt,
-};
-
/* dai driver */
#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000)
@@ -2505,6 +2485,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
+ .startup = mtk_dai_hdmitx_dptx_startup,
+ .shutdown = mtk_dai_hdmitx_dptx_shutdown,
+ .hw_params = mtk_dai_hdmitx_dptx_hw_params,
+ .trigger = mtk_dai_hdmitx_dptx_trigger,
+ .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = {
+ .probe = mtk_dai_etdm_probe,
+ .startup = mtk_dai_hdmitx_dptx_startup,
+ .shutdown = mtk_dai_hdmitx_dptx_shutdown,
+ .hw_params = mtk_dai_hdmitx_dptx_hw_params,
+ .trigger = mtk_dai_hdmitx_dptx_trigger,
+ .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+ .probe = mtk_dai_etdm_probe,
+ .startup = mtk_dai_etdm_startup,
+ .shutdown = mtk_dai_etdm_shutdown,
+ .hw_params = mtk_dai_etdm_hw_params,
+ .trigger = mtk_dai_etdm_trigger,
+ .set_sysclk = mtk_dai_etdm_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+ .set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
+};
+
static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
{
.name = "DPTX",
@@ -2529,7 +2539,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM2_IN",
@@ -2542,7 +2551,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM1_OUT",
@@ -2555,7 +2563,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM2_OUT",
@@ -2568,7 +2575,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM3_OUT",
@@ -2580,8 +2586,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.rates = MTK_ETDM_RATES,
.formats = MTK_ETDM_FORMATS,
},
- .ops = &mtk_dai_hdmitx_dptx_ops,
- .probe = mtk_dai_etdm_probe,
+ .ops = &mtk_dai_hdmitx_dptx_ops2,
},
};
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
index 6d6d79300d51..cdc16057d50e 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
@@ -127,7 +127,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,
unsigned int lrck_inv;
unsigned int bck_inv;
unsigned int fmt;
- unsigned int bit_width = dai->sample_bits;
+ unsigned int bit_width = dai->symmetric_sample_bits;
unsigned int val = 0;
unsigned int mask = 0;
int fs = 0;
diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
index ceca882ecff7..4d62bc654a58 100644
--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
@@ -10,7 +10,7 @@
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
@@ -22,6 +22,7 @@
#include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-dsp-sof-common.h"
#include "../common/mtk-soc-card.h"
+#include "../common/mtk-soundcard-driver.h"
#include "mt8195-afe-clk.h"
#include "mt8195-afe-common.h"
@@ -29,6 +30,13 @@
#define RT1019_SPEAKER_AMP_PRESENT BIT(1)
#define MAX98390_SPEAKER_AMP_PRESENT BIT(2)
+#define DUMB_CODEC_INIT BIT(0)
+#define MT6359_CODEC_INIT BIT(1)
+#define RT1011_CODEC_INIT BIT(2)
+#define RT1019_CODEC_INIT BIT(3)
+#define MAX98390_CODEC_INIT BIT(4)
+#define RT5682_CODEC_INIT BIT(5)
+
#define RT1011_CODEC_DAI "rt1011-aif"
#define RT1011_DEV0_NAME "rt1011.2-0038"
#define RT1011_DEV1_NAME "rt1011.2-0039"
@@ -51,18 +59,17 @@
#define SOF_DMA_UL4 "SOF_DMA_UL4"
#define SOF_DMA_UL5 "SOF_DMA_UL5"
-struct mt8195_card_data {
- const char *name;
- unsigned long quirk;
-};
-
struct mt8195_mt6359_priv {
- struct snd_soc_jack headset_jack;
- struct snd_soc_jack dp_jack;
- struct snd_soc_jack hdmi_jack;
struct clk *i2so1_mclk;
};
+enum mt8195_jacks {
+ MT8195_JACK_HEADSET,
+ MT8195_JACK_DP,
+ MT8195_JACK_HDMI,
+ MT8195_JACK_MAX,
+};
+
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin mt8195_jack_pins[] = {
{
@@ -85,10 +92,6 @@ static const struct snd_soc_dapm_widget mt8195_mt6359_widgets[] = {
};
static const struct snd_soc_dapm_route mt8195_mt6359_routes[] = {
- /* headset */
- { "Headphone", NULL, "HPOL" },
- { "Headphone", NULL, "HPOR" },
- { "IN1P", NULL, "Headset Mic" },
/* SOF Uplink */
{SOF_DMA_UL4, NULL, "O034"},
{SOF_DMA_UL4, NULL, "O035"},
@@ -124,6 +127,13 @@ static const struct snd_kcontrol_new mt8195_speaker_controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
+static const struct snd_soc_dapm_route mt8195_rt5682_routes[] = {
+ /* headset */
+ { "Headphone", NULL, "HPOL" },
+ { "Headphone", NULL, "HPOR" },
+ { "IN1P", NULL, "Headset Mic" },
+};
+
static const struct snd_soc_dapm_route mt8195_rt1011_routes[] = {
{ "Left Spk", NULL, "Left SPO" },
{ "Right Spk", NULL, "Right SPO" },
@@ -146,7 +156,7 @@ static int mt8195_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtkaif_param *param = &afe_priv->mtkaif_params;
@@ -307,7 +317,7 @@ static int mt8195_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
static int mt8195_mt6359_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
/* set mtkaif protocol */
mt6359_set_mtkaif_protocol(cmpnt_codec,
@@ -321,44 +331,7 @@ static int mt8195_mt6359_init(struct snd_soc_pcm_runtime *rtd)
static int mt8195_hdmitx_dptx_startup(struct snd_pcm_substream *substream)
{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 2, 4, 6, 8
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
- }
-
- return 0;
+ return mtk_soundcard_startup(substream, MTK_CONSTRAINT_HDMIDP);
}
static const struct snd_soc_ops mt8195_hdmitx_dptx_playback_ops = {
@@ -368,8 +341,8 @@ static const struct snd_soc_ops mt8195_hdmitx_dptx_playback_ops = {
static int mt8195_dptx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
return snd_soc_dai_set_sysclk(cpu_dai, 0, params_rate(params) * 256,
SND_SOC_CLOCK_OUT);
@@ -382,33 +355,31 @@ static const struct snd_soc_ops mt8195_dptx_ops = {
static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
- struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8195_JACK_DP];
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
- ret = snd_soc_card_jack_new(rtd->card, "DP Jack", SND_JACK_LINEOUT,
- &priv->dp_jack);
+ ret = snd_soc_card_jack_new(rtd->card, "DP Jack", SND_JACK_AVOUT, jack);
if (ret)
return ret;
- return snd_soc_component_set_jack(cmpnt_codec, &priv->dp_jack, NULL);
+ return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
}
static int mt8195_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
- struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8195_JACK_HDMI];
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
- ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
- &priv->hdmi_jack);
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_AVOUT, jack);
if (ret)
return ret;
- return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+ return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
}
static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -423,105 +394,13 @@ static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int mt8195_playback_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8195_playback_ops = {
- .startup = mt8195_playback_startup,
-};
-
-static int mt8195_capture_startup(struct snd_pcm_substream *substream)
-{
- static const unsigned int rates[] = {
- 48000
- };
- static const unsigned int channels[] = {
- 1, 2
- };
- static const struct snd_pcm_hw_constraint_list constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
- };
- static const struct snd_pcm_hw_constraint_list constraints_channels = {
- .count = ARRAY_SIZE(channels),
- .list = channels,
- .mask = 0,
- };
-
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_rates);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list rate failed\n");
- return ret;
- }
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &constraints_channels);
- if (ret < 0) {
- dev_err(rtd->dev, "hw_constraint_list channel failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mt8195_capture_ops = {
- .startup = mt8195_capture_startup,
-};
-
static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
unsigned int rate = params_rate(params);
int bitwidth;
int ret;
@@ -563,14 +442,16 @@ static const struct snd_soc_ops mt8195_rt5682_etdm_ops = {
static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_codec =
- asoc_rtd_to_codec(rtd, 0)->component;
+ snd_soc_rtd_to_codec(rtd, 0)->component;
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
- struct snd_soc_jack *jack = &priv->headset_jack;
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8195_JACK_HEADSET];
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
priv->i2so1_mclk = afe_priv->clk[MT8195_CLK_TOP_APLL12_DIV2];
@@ -597,13 +478,18 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- return 0;
+ ret = snd_soc_dapm_add_routes(dapm, mt8195_rt5682_routes,
+ ARRAY_SIZE(mt8195_rt5682_routes));
+ if (ret)
+ dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
+
+ return ret;
};
static int mt8195_rt1011_etdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
struct snd_soc_card *card = rtd->card;
int srate, i, ret;
@@ -636,7 +522,7 @@ static const struct snd_soc_ops mt8195_rt1011_etdm_ops = {
static int mt8195_sof_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *cmpnt_afe = NULL;
struct snd_soc_pcm_runtime *runtime;
@@ -662,9 +548,10 @@ static const struct snd_soc_ops mt8195_sof_be_ops = {
static int mt8195_rt1011_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8195_dual_speaker_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8195_dual_speaker_widgets,
ARRAY_SIZE(mt8195_dual_speaker_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
@@ -679,7 +566,7 @@ static int mt8195_rt1011_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, mt8195_rt1011_routes,
+ ret = snd_soc_dapm_add_routes(dapm, mt8195_rt1011_routes,
ARRAY_SIZE(mt8195_rt1011_routes));
if (ret)
dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
@@ -687,12 +574,13 @@ static int mt8195_rt1011_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static int mt8195_rt1019_init(struct snd_soc_pcm_runtime *rtd)
+static int mt8195_dumb_amp_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8195_speaker_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8195_speaker_widgets,
ARRAY_SIZE(mt8195_speaker_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
@@ -707,7 +595,20 @@ static int mt8195_rt1019_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, mt8195_rt1019_routes,
+ return 0;
+}
+
+static int mt8195_rt1019_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ ret = mt8195_dumb_amp_init(rtd);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, mt8195_rt1019_routes,
ARRAY_SIZE(mt8195_rt1019_routes));
if (ret)
dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
@@ -718,9 +619,10 @@ static int mt8195_rt1019_init(struct snd_soc_pcm_runtime *rtd)
static int mt8195_max98390_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, mt8195_dual_speaker_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, mt8195_dual_speaker_widgets,
ARRAY_SIZE(mt8195_dual_speaker_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
@@ -735,7 +637,7 @@ static int mt8195_max98390_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, mt8195_max98390_routes,
+ ret = snd_soc_dapm_add_routes(dapm, mt8195_max98390_routes,
ARRAY_SIZE(mt8195_max98390_routes));
if (ret)
dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
@@ -758,7 +660,7 @@ static int mt8195_etdm_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int mt8195_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
- struct snd_soc_component *component = dapm->component;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
int ret;
@@ -1025,8 +927,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
- .ops = &mt8195_playback_ops,
+ .playback_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(DL2_FE),
},
[DAI_LINK_DL3_FE] = {
@@ -1037,8 +939,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
- .ops = &mt8195_playback_ops,
+ .playback_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(DL3_FE),
},
[DAI_LINK_DL6_FE] = {
@@ -1049,8 +951,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
- .ops = &mt8195_playback_ops,
+ .playback_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(DL6_FE),
},
[DAI_LINK_DL7_FE] = {
@@ -1061,7 +963,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(DL7_FE),
},
[DAI_LINK_DL8_FE] = {
@@ -1072,8 +974,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
- .ops = &mt8195_playback_ops,
+ .playback_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(DL8_FE),
},
[DAI_LINK_DL10_FE] = {
@@ -1084,7 +986,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8195_hdmitx_dptx_playback_ops,
SND_SOC_DAILINK_REG(DL10_FE),
},
@@ -1096,8 +998,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_playback = 1,
- .ops = &mt8195_playback_ops,
+ .playback_only = 1,
+ .ops = &mtk_soundcard_common_playback_ops,
SND_SOC_DAILINK_REG(DL11_FE),
},
[DAI_LINK_UL1_FE] = {
@@ -1108,7 +1010,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(UL1_FE),
},
[DAI_LINK_UL2_FE] = {
@@ -1119,8 +1021,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL2_FE),
},
[DAI_LINK_UL3_FE] = {
@@ -1131,8 +1033,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL3_FE),
},
[DAI_LINK_UL4_FE] = {
@@ -1143,8 +1045,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL4_FE),
},
[DAI_LINK_UL5_FE] = {
@@ -1155,8 +1057,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL5_FE),
},
[DAI_LINK_UL6_FE] = {
@@ -1167,7 +1069,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE,
},
.dynamic = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(UL6_FE),
},
[DAI_LINK_UL8_FE] = {
@@ -1178,8 +1080,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL8_FE),
},
[DAI_LINK_UL9_FE] = {
@@ -1190,8 +1092,8 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL9_FE),
},
[DAI_LINK_UL10_FE] = {
@@ -1202,21 +1104,21 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_POST,
},
.dynamic = 1,
- .dpcm_capture = 1,
- .ops = &mt8195_capture_ops,
+ .capture_only = 1,
+ .ops = &mtk_soundcard_common_capture_ops,
SND_SOC_DAILINK_REG(UL10_FE),
},
/* BE */
[DAI_LINK_DL_SRC_BE] = {
.name = "DL_SRC_BE",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(DL_SRC_BE),
},
[DAI_LINK_DPTX_BE] = {
.name = "DPTX_BE",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8195_dptx_ops,
.be_hw_params_fixup = mt8195_dptx_hw_params_fixup,
SND_SOC_DAILINK_REG(DPTX_BE),
@@ -1226,8 +1128,8 @@ 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,
- .dpcm_capture = 1,
+ SND_SOC_DAIFMT_CBC_CFC,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(ETDM1_IN_BE),
},
[DAI_LINK_ETDM2_IN_BE] = {
@@ -1235,10 +1137,8 @@ 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,
- .dpcm_capture = 1,
- .init = mt8195_rt5682_init,
- .ops = &mt8195_rt5682_etdm_ops,
+ SND_SOC_DAIFMT_CBC_CFC,
+ .capture_only = 1,
.be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
SND_SOC_DAILINK_REG(ETDM2_IN_BE),
},
@@ -1247,9 +1147,8 @@ 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,
- .dpcm_playback = 1,
- .ops = &mt8195_rt5682_etdm_ops,
+ SND_SOC_DAIFMT_CBC_CFC,
+ .playback_only = 1,
.be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
SND_SOC_DAILINK_REG(ETDM1_OUT_BE),
},
@@ -1258,8 +1157,8 @@ 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,
- .dpcm_playback = 1,
+ SND_SOC_DAIFMT_CBC_CFC,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(ETDM2_OUT_BE),
},
[DAI_LINK_ETDM3_OUT_BE] = {
@@ -1267,8 +1166,8 @@ 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,
- .dpcm_playback = 1,
+ SND_SOC_DAIFMT_CBC_CFC,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(ETDM3_OUT_BE),
},
[DAI_LINK_PCM1_BE] = {
@@ -1276,49 +1175,47 @@ 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,
- .dpcm_playback = 1,
- .dpcm_capture = 1,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(PCM1_BE),
},
[DAI_LINK_UL_SRC1_BE] = {
.name = "UL_SRC1_BE",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(UL_SRC1_BE),
},
[DAI_LINK_UL_SRC2_BE] = {
.name = "UL_SRC2_BE",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(UL_SRC2_BE),
},
/* SOF BE */
[DAI_LINK_SOF_DL2_BE] = {
.name = "AFE_SOF_DL2",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8195_sof_be_ops,
SND_SOC_DAILINK_REG(AFE_SOF_DL2),
},
[DAI_LINK_SOF_DL3_BE] = {
.name = "AFE_SOF_DL3",
.no_pcm = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
.ops = &mt8195_sof_be_ops,
SND_SOC_DAILINK_REG(AFE_SOF_DL3),
},
[DAI_LINK_SOF_UL4_BE] = {
.name = "AFE_SOF_UL4",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &mt8195_sof_be_ops,
SND_SOC_DAILINK_REG(AFE_SOF_UL4),
},
[DAI_LINK_SOF_UL5_BE] = {
.name = "AFE_SOF_UL5",
.no_pcm = 1,
- .dpcm_capture = 1,
+ .capture_only = 1,
.ops = &mt8195_sof_be_ops,
SND_SOC_DAILINK_REG(AFE_SOF_UL5),
},
@@ -1375,104 +1272,31 @@ static int mt8195_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
-static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
+static int mt8195_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data)
{
- struct snd_soc_card *card = &mt8195_mt6359_soc_card;
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ struct device_node *codec_node, *dp_node, *hdmi_node;
struct snd_soc_dai_link *dai_link;
- struct mtk_soc_card_data *soc_card_data;
- struct mt8195_mt6359_priv *mach_priv;
- struct device_node *platform_node, *adsp_node, *dp_node, *hdmi_node;
- struct mt8195_card_data *card_data;
- int is5682s = 0;
- int init6359 = 0;
- int sof_on = 0;
- int ret, i;
-
- card_data = (struct mt8195_card_data *)of_device_get_match_data(&pdev->dev);
- card->dev = &pdev->dev;
-
- ret = snd_soc_of_parse_card_name(card, "model");
- if (ret) {
- dev_err(&pdev->dev, "%s new card name parsing error %d\n",
- __func__, ret);
- return ret;
- }
-
- if (!card->name)
- card->name = card_data->name;
-
- if (strstr(card->name, "_5682s"))
- is5682s = 1;
- soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL);
- if (!soc_card_data)
- return -ENOMEM;
-
- mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL);
- if (!mach_priv)
- return -ENOMEM;
-
- soc_card_data->mach_priv = mach_priv;
-
- adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
- if (adsp_node) {
- struct mtk_sof_priv *sof_priv;
-
- sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL);
- if (!sof_priv) {
- ret = -ENOMEM;
- goto err_kzalloc;
- }
- sof_priv->conn_streams = g_sof_conn_streams;
- sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams);
- sof_priv->sof_dai_link_fixup = mt8195_dai_link_fixup;
- soc_card_data->sof_priv = sof_priv;
- card->probe = mtk_sof_card_probe;
- card->late_probe = mtk_sof_card_late_probe;
- if (!card->topology_shortname_created) {
- snprintf(card->topology_shortname, 32, "sof-%s", card->name);
- card->topology_shortname_created = true;
- }
- card->name = card->topology_shortname;
- sof_on = 1;
- }
+ struct device *dev = card->dev;
+ bool is5682s, init6359 = false;
+ int i;
- if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) {
- ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node,
- "mediatek,dai-link",
- mt8195_mt6359_dai_links,
- ARRAY_SIZE(mt8195_mt6359_dai_links));
- if (ret) {
- dev_dbg(&pdev->dev, "Parse dai-link fail\n");
- goto err_parse_of;
- }
+ if (strstr(card->name, "_5682s")) {
+ codec_node = of_find_compatible_node(NULL, NULL, "realtek,rt5682s");
+ is5682s = true;
} else {
- if (!sof_on)
- card->num_links = DAI_LINK_REGULAR_NUM;
- }
-
- platform_node = of_parse_phandle(pdev->dev.of_node,
- "mediatek,platform", 0);
- if (!platform_node) {
- dev_dbg(&pdev->dev, "Property 'platform' missing or invalid\n");
- ret = -EINVAL;
- goto err_platform_node;
+ codec_node = of_find_compatible_node(NULL, NULL, "realtek,rt5682i");
+ is5682s = false;
}
- dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0);
- hdmi_node = of_parse_phandle(pdev->dev.of_node,
- "mediatek,hdmi-codec", 0);
+ dp_node = of_parse_phandle(dev->of_node, "mediatek,dptx-codec", 0);
+ hdmi_node = of_parse_phandle(dev->of_node, "mediatek,hdmi-codec", 0);
for_each_card_prelinks(card, i, dai_link) {
- if (!dai_link->platforms->name) {
- if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && sof_on)
- dai_link->platforms->of_node = adsp_node;
- else
- dai_link->platforms->of_node = platform_node;
- }
-
if (strcmp(dai_link->name, "DPTX_BE") == 0) {
if (!dp_node) {
- dev_dbg(&pdev->dev, "No property 'dptx-codec'\n");
+ dev_dbg(dev, "No property 'dptx-codec'\n");
} else {
dai_link->codecs->of_node = dp_node;
dai_link->codecs->name = NULL;
@@ -1481,28 +1305,43 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
}
} else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) {
if (!hdmi_node) {
- dev_dbg(&pdev->dev, "No property 'hdmi-codec'\n");
+ dev_dbg(dev, "No property 'hdmi-codec'\n");
} else {
dai_link->codecs->of_node = hdmi_node;
dai_link->codecs->name = NULL;
dai_link->codecs->dai_name = "i2s-hifi";
dai_link->init = mt8195_hdmi_codec_init;
}
- } else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0 ||
- strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
- dai_link->codecs->name =
- is5682s ? RT5682S_DEV0_NAME : RT5682_DEV0_NAME;
- dai_link->codecs->dai_name =
- is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI;
+ } else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0) {
+ if (!codec_node) {
+ dev_err(dev, "Codec not found!\n");
+ } else {
+ dai_link->codecs->of_node = codec_node;
+ dai_link->codecs->name = NULL;
+ dai_link->codecs->dai_name =
+ is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI;
+ dai_link->init = mt8195_rt5682_init;
+ dai_link->ops = &mt8195_rt5682_etdm_ops;
+ }
+ } else if (strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
+ if (!codec_node) {
+ dev_err(dev, "Codec not found!\n");
+ } else {
+ dai_link->codecs->of_node = codec_node;
+ dai_link->codecs->name = NULL;
+ dai_link->codecs->dai_name =
+ is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI;
+ dai_link->ops = &mt8195_rt5682_etdm_ops;
+ }
} else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 ||
strcmp(dai_link->name, "UL_SRC1_BE") == 0 ||
strcmp(dai_link->name, "UL_SRC2_BE") == 0) {
if (!init6359) {
dai_link->init = mt8195_mt6359_init;
- init6359 = 1;
+ init6359 = true;
}
} else if (strcmp(dai_link->name, "ETDM2_OUT_BE") == 0) {
- switch (card_data->quirk) {
+ switch (card_data->flags) {
case RT1011_SPEAKER_AMP_PRESENT:
dai_link->codecs = rt1011_comps;
dai_link->num_codecs = ARRAY_SIZE(rt1011_comps);
@@ -1530,33 +1369,176 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
}
}
- snd_soc_card_set_drvdata(card, soc_card_data);
+ return 0;
+}
+
+static int mt8195_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ struct mt8195_mt6359_priv *mach_priv;
+ struct snd_soc_dai_link *dai_link;
+ u8 codec_init = 0;
+ int i;
+
+ mach_priv = devm_kzalloc(card->dev, sizeof(*mach_priv), GFP_KERNEL);
+ if (!mach_priv)
+ return -ENOMEM;
+
+ soc_card_data->mach_priv = mach_priv;
- ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (legacy)
+ return mt8195_mt6359_legacy_probe(soc_card_data);
- of_node_put(platform_node);
- of_node_put(dp_node);
- of_node_put(hdmi_node);
-err_kzalloc:
-err_parse_of:
-err_platform_node:
- of_node_put(adsp_node);
- return ret;
+ for_each_card_prelinks(card, i, dai_link) {
+ if (strcmp(dai_link->name, "DPTX_BE") == 0) {
+ if (dai_link->num_codecs &&
+ !snd_soc_dlc_is_dummy(dai_link->codecs))
+ dai_link->init = mt8195_dptx_codec_init;
+ } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) {
+ if (dai_link->num_codecs &&
+ !snd_soc_dlc_is_dummy(dai_link->codecs))
+ dai_link->init = mt8195_hdmi_codec_init;
+ } else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 ||
+ strcmp(dai_link->name, "UL_SRC1_BE") == 0 ||
+ strcmp(dai_link->name, "UL_SRC2_BE") == 0) {
+ if (!(codec_init & MT6359_CODEC_INIT)) {
+ dai_link->init = mt8195_mt6359_init;
+ codec_init |= MT6359_CODEC_INIT;
+ }
+ } else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0 ||
+ strcmp(dai_link->name, "ETDM2_OUT_BE") == 0 ||
+ strcmp(dai_link->name, "ETDM1_IN_BE") == 0 ||
+ strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
+ if (!dai_link->num_codecs)
+ continue;
+
+ if (!strcmp(dai_link->codecs->dai_name, MAX98390_CODEC_DAI)) {
+ if (!(codec_init & MAX98390_CODEC_INIT)) {
+ dai_link->init = mt8195_max98390_init;
+ codec_init |= MAX98390_CODEC_INIT;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT1011_CODEC_DAI)) {
+ dai_link->ops = &mt8195_rt1011_etdm_ops;
+ if (!(codec_init & RT1011_CODEC_INIT)) {
+ dai_link->init = mt8195_rt1011_init;
+ codec_init |= RT1011_CODEC_INIT;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT1019_CODEC_DAI)) {
+ if (!(codec_init & RT1019_CODEC_INIT)) {
+ dai_link->init = mt8195_rt1019_init;
+ codec_init |= RT1019_CODEC_INIT;
+ }
+ } else if (!strcmp(dai_link->codecs->dai_name, RT5682_CODEC_DAI) ||
+ !strcmp(dai_link->codecs->dai_name, RT5682S_CODEC_DAI)) {
+ dai_link->ops = &mt8195_rt5682_etdm_ops;
+ if (!(codec_init & RT5682_CODEC_INIT)) {
+ dai_link->init = mt8195_rt5682_init;
+ codec_init |= RT5682_CODEC_INIT;
+ }
+ } else {
+ if (!snd_soc_dlc_is_dummy(dai_link->codecs)) {
+ if (!(codec_init & DUMB_CODEC_INIT)) {
+ dai_link->init = mt8195_dumb_amp_init;
+ codec_init |= DUMB_CODEC_INIT;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
}
-static struct mt8195_card_data mt8195_mt6359_rt1019_rt5682_card = {
- .name = "mt8195_r1019_5682",
- .quirk = RT1019_SPEAKER_AMP_PRESENT,
+static const unsigned int mt8195_pcm_playback_channels[] = { 2 };
+static const unsigned int mt8195_pcm_capture_channels[] = { 1, 2 };
+static const unsigned int mt8195_pcm_hdmidp_channels[] = { 2, 4, 6, 8 };
+static const unsigned int mt8195_pcm_rates[] = { 48000 };
+
+static const struct snd_pcm_hw_constraint_list mt8195_rate_constraint = {
+ .list = mt8195_pcm_rates,
+ .count = ARRAY_SIZE(mt8195_pcm_rates)
};
-static struct mt8195_card_data mt8195_mt6359_rt1011_rt5682_card = {
- .name = "mt8195_r1011_5682",
- .quirk = RT1011_SPEAKER_AMP_PRESENT,
+static const struct mtk_pcm_constraints_data mt8195_pcm_constraints[MTK_CONSTRAINT_HDMIDP + 1] = {
+ [MTK_CONSTRAINT_PLAYBACK] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8195_pcm_playback_channels,
+ .count = ARRAY_SIZE(mt8195_pcm_playback_channels)
+ },
+ .rates = &mt8195_rate_constraint,
+ },
+ [MTK_CONSTRAINT_CAPTURE] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8195_pcm_capture_channels,
+ .count = ARRAY_SIZE(mt8195_pcm_capture_channels)
+ },
+ .rates = &mt8195_rate_constraint,
+ },
+ [MTK_CONSTRAINT_HDMIDP] = {
+ .channels = &(const struct snd_pcm_hw_constraint_list) {
+ .list = mt8195_pcm_hdmidp_channels,
+ .count = ARRAY_SIZE(mt8195_pcm_hdmidp_channels)
+ },
+ .rates = &mt8195_rate_constraint,
+ },
};
-static struct mt8195_card_data mt8195_mt6359_max98390_rt5682_card = {
- .name = "mt8195_m98390_r5682",
- .quirk = MAX98390_SPEAKER_AMP_PRESENT,
+static const struct mtk_sof_priv mt8195_sof_priv = {
+ .conn_streams = g_sof_conn_streams,
+ .num_streams = ARRAY_SIZE(g_sof_conn_streams),
+ .sof_dai_link_fixup = mt8195_dai_link_fixup
+};
+
+static const struct mtk_soundcard_pdata mt8195_mt6359_rt1019_rt5682_card = {
+ .card_name = "mt8195_r1019_5682",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8195_mt6359_soc_card,
+ .num_jacks = MT8195_JACK_MAX,
+ .pcm_constraints = mt8195_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8195_pcm_constraints),
+ .flags = RT1019_SPEAKER_AMP_PRESENT
+ },
+ .sof_priv = &mt8195_sof_priv,
+ .soc_probe = mt8195_mt6359_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8195_mt6359_rt1011_rt5682_card = {
+ .card_name = "mt8195_r1011_5682",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8195_mt6359_soc_card,
+ .num_jacks = MT8195_JACK_MAX,
+ .pcm_constraints = mt8195_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8195_pcm_constraints),
+ .flags = RT1011_SPEAKER_AMP_PRESENT
+ },
+ .sof_priv = &mt8195_sof_priv,
+ .soc_probe = mt8195_mt6359_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8195_mt6359_max98390_rt5682_card = {
+ .card_name = "mt8195_m98390_r5682",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8195_mt6359_soc_card,
+ .num_jacks = MT8195_JACK_MAX,
+ .pcm_constraints = mt8195_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8195_pcm_constraints),
+ .flags = MAX98390_SPEAKER_AMP_PRESENT
+ },
+ .sof_priv = &mt8195_sof_priv,
+ .soc_probe = mt8195_mt6359_soc_card_probe
+};
+
+static const struct mtk_soundcard_pdata mt8195_mt6359_card = {
+ .card_name = "mt8195_mt6359",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8195_mt6359_soc_card,
+ .num_jacks = MT8195_JACK_MAX,
+ .pcm_constraints = mt8195_pcm_constraints,
+ .num_pcm_constraints = ARRAY_SIZE(mt8195_pcm_constraints),
+ },
+ .sof_priv = &mt8195_sof_priv,
+ .soc_probe = mt8195_mt6359_soc_card_probe
};
static const struct of_device_id mt8195_mt6359_dt_match[] = {
@@ -1572,6 +1554,10 @@ static const struct of_device_id mt8195_mt6359_dt_match[] = {
.compatible = "mediatek,mt8195_mt6359_max98390_rt5682",
.data = &mt8195_mt6359_max98390_rt5682_card,
},
+ {
+ .compatible = "mediatek,mt8195_mt6359",
+ .data = &mt8195_mt6359_card,
+ },
{},
};
MODULE_DEVICE_TABLE(of, mt8195_mt6359_dt_match);
@@ -1582,7 +1568,7 @@ static struct platform_driver mt8195_mt6359_driver = {
.of_match_table = mt8195_mt6359_dt_match,
.pm = &snd_soc_pm_ops,
},
- .probe = mt8195_mt6359_dev_probe,
+ .probe = mtk_soundcard_common_probe,
};
module_platform_driver(mt8195_mt6359_driver);
diff --git a/sound/soc/mediatek/mt8365/Makefile b/sound/soc/mediatek/mt8365/Makefile
new file mode 100644
index 000000000000..b197025e34bb
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# MTK Platform driver
+snd-soc-mt8365-pcm-y := \
+ mt8365-afe-clk.o \
+ mt8365-afe-pcm.o \
+ mt8365-dai-adda.o \
+ mt8365-dai-dmic.o \
+ mt8365-dai-i2s.o \
+ mt8365-dai-pcm.o
+
+obj-$(CONFIG_SND_SOC_MT8365) += snd-soc-mt8365-pcm.o
+
+# Machine driver
+obj-$(CONFIG_SND_SOC_MT8365_MT6357) += mt8365-mt6357.o
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
new file mode 100644
index 000000000000..7078c01ba19b
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek 8365 AFE clock control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+#include "mt8365-reg.h"
+#include "../common/mtk-base-afe.h"
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+
+static const char *aud_clks[MT8365_CLK_NUM] = {
+ [MT8365_CLK_TOP_AUD_SEL] = "top_audio_sel",
+ [MT8365_CLK_AUD_I2S0_M] = "audio_i2s0_m",
+ [MT8365_CLK_AUD_I2S1_M] = "audio_i2s1_m",
+ [MT8365_CLK_AUD_I2S2_M] = "audio_i2s2_m",
+ [MT8365_CLK_AUD_I2S3_M] = "audio_i2s3_m",
+ [MT8365_CLK_ENGEN1] = "engen1",
+ [MT8365_CLK_ENGEN2] = "engen2",
+ [MT8365_CLK_AUD1] = "aud1",
+ [MT8365_CLK_AUD2] = "aud2",
+ [MT8365_CLK_I2S0_M_SEL] = "i2s0_m_sel",
+ [MT8365_CLK_I2S1_M_SEL] = "i2s1_m_sel",
+ [MT8365_CLK_I2S2_M_SEL] = "i2s2_m_sel",
+ [MT8365_CLK_I2S3_M_SEL] = "i2s3_m_sel",
+ [MT8365_CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe)
+{
+ size_t i;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+ afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
+ if (IS_ERR(afe_priv->clocks[i])) {
+ dev_err(afe->dev, "%s devm_clk_get %s fail\n",
+ __func__, aud_clks[i]);
+ return PTR_ERR(afe_priv->clocks[i]);
+ }
+ }
+ return 0;
+}
+
+void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
+{
+ clk_disable_unprepare(clk);
+}
+
+int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
+ unsigned int rate)
+{
+ int ret;
+
+ if (clk) {
+ ret = clk_set_rate(clk, rate);
+ if (ret) {
+ dev_err(afe->dev, "Failed to set rate\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int mt8365_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk,
+ struct clk *parent)
+{
+ int ret;
+
+ if (clk && parent) {
+ ret = clk_set_parent(clk, parent);
+ if (ret) {
+ dev_err(afe->dev, "Failed to set parent\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static unsigned int get_top_cg_reg(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8365_TOP_CG_AFE:
+ case MT8365_TOP_CG_I2S_IN:
+ case MT8365_TOP_CG_22M:
+ case MT8365_TOP_CG_24M:
+ case MT8365_TOP_CG_INTDIR_CK:
+ case MT8365_TOP_CG_APLL2_TUNER:
+ case MT8365_TOP_CG_APLL_TUNER:
+ case MT8365_TOP_CG_SPDIF:
+ case MT8365_TOP_CG_TDM_OUT:
+ case MT8365_TOP_CG_TDM_IN:
+ case MT8365_TOP_CG_ADC:
+ case MT8365_TOP_CG_DAC:
+ case MT8365_TOP_CG_DAC_PREDIS:
+ case MT8365_TOP_CG_TML:
+ return AUDIO_TOP_CON0;
+ case MT8365_TOP_CG_I2S1_BCLK:
+ case MT8365_TOP_CG_I2S2_BCLK:
+ case MT8365_TOP_CG_I2S3_BCLK:
+ case MT8365_TOP_CG_I2S4_BCLK:
+ case MT8365_TOP_CG_DMIC0_ADC:
+ case MT8365_TOP_CG_DMIC1_ADC:
+ case MT8365_TOP_CG_DMIC2_ADC:
+ case MT8365_TOP_CG_DMIC3_ADC:
+ case MT8365_TOP_CG_CONNSYS_I2S_ASRC:
+ case MT8365_TOP_CG_GENERAL1_ASRC:
+ case MT8365_TOP_CG_GENERAL2_ASRC:
+ case MT8365_TOP_CG_TDM_ASRC:
+ return AUDIO_TOP_CON1;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_mask(unsigned int cg_type)
+{
+ switch (cg_type) {
+ case MT8365_TOP_CG_AFE:
+ return AUD_TCON0_PDN_AFE;
+ case MT8365_TOP_CG_I2S_IN:
+ return AUD_TCON0_PDN_I2S_IN;
+ case MT8365_TOP_CG_22M:
+ return AUD_TCON0_PDN_22M;
+ case MT8365_TOP_CG_24M:
+ return AUD_TCON0_PDN_24M;
+ case MT8365_TOP_CG_INTDIR_CK:
+ return AUD_TCON0_PDN_INTDIR;
+ case MT8365_TOP_CG_APLL2_TUNER:
+ return AUD_TCON0_PDN_APLL2_TUNER;
+ case MT8365_TOP_CG_APLL_TUNER:
+ return AUD_TCON0_PDN_APLL_TUNER;
+ case MT8365_TOP_CG_SPDIF:
+ return AUD_TCON0_PDN_SPDIF;
+ case MT8365_TOP_CG_TDM_OUT:
+ return AUD_TCON0_PDN_TDM_OUT;
+ case MT8365_TOP_CG_TDM_IN:
+ return AUD_TCON0_PDN_TDM_IN;
+ case MT8365_TOP_CG_ADC:
+ return AUD_TCON0_PDN_ADC;
+ case MT8365_TOP_CG_DAC:
+ return AUD_TCON0_PDN_DAC;
+ case MT8365_TOP_CG_DAC_PREDIS:
+ return AUD_TCON0_PDN_DAC_PREDIS;
+ case MT8365_TOP_CG_TML:
+ return AUD_TCON0_PDN_TML;
+ case MT8365_TOP_CG_I2S1_BCLK:
+ return AUD_TCON1_PDN_I2S1_BCLK;
+ case MT8365_TOP_CG_I2S2_BCLK:
+ return AUD_TCON1_PDN_I2S2_BCLK;
+ case MT8365_TOP_CG_I2S3_BCLK:
+ return AUD_TCON1_PDN_I2S3_BCLK;
+ case MT8365_TOP_CG_I2S4_BCLK:
+ return AUD_TCON1_PDN_I2S4_BCLK;
+ case MT8365_TOP_CG_DMIC0_ADC:
+ return AUD_TCON1_PDN_DMIC0_ADC;
+ case MT8365_TOP_CG_DMIC1_ADC:
+ return AUD_TCON1_PDN_DMIC1_ADC;
+ case MT8365_TOP_CG_DMIC2_ADC:
+ return AUD_TCON1_PDN_DMIC2_ADC;
+ case MT8365_TOP_CG_DMIC3_ADC:
+ return AUD_TCON1_PDN_DMIC3_ADC;
+ case MT8365_TOP_CG_CONNSYS_I2S_ASRC:
+ return AUD_TCON1_PDN_CONNSYS_I2S_ASRC;
+ case MT8365_TOP_CG_GENERAL1_ASRC:
+ return AUD_TCON1_PDN_GENERAL1_ASRC;
+ case MT8365_TOP_CG_GENERAL2_ASRC:
+ return AUD_TCON1_PDN_GENERAL2_ASRC;
+ case MT8365_TOP_CG_TDM_ASRC:
+ return AUD_TCON1_PDN_TDM_ASRC;
+ default:
+ return 0;
+ }
+}
+
+static unsigned int get_top_cg_on_val(unsigned int cg_type)
+{
+ return 0;
+}
+
+static unsigned int get_top_cg_off_val(unsigned int cg_type)
+{
+ return get_top_cg_mask(cg_type);
+}
+
+int mt8365_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_on_val(cg_type);
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->top_cg_ref_cnt[cg_type]++;
+ if (afe_priv->top_cg_ref_cnt[cg_type] == 1)
+ regmap_update_bits(afe->regmap, reg, mask, val);
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned int reg = get_top_cg_reg(cg_type);
+ unsigned int mask = get_top_cg_mask(cg_type);
+ unsigned int val = get_top_cg_off_val(cg_type);
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->top_cg_ref_cnt[cg_type]--;
+ if (afe_priv->top_cg_ref_cnt[cg_type] == 0)
+ regmap_update_bits(afe->regmap, reg, mask, val);
+ else if (afe_priv->top_cg_ref_cnt[cg_type] < 0)
+ afe_priv->top_cg_ref_cnt[cg_type] = 0;
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_enable_main_clk(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ clk_prepare_enable(afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL]);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE);
+ mt8365_afe_enable_afe_on(afe);
+
+ return 0;
+}
+
+int mt8365_afe_disable_main_clk(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mt8365_afe_disable_afe_on(afe);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE);
+ mt8365_afe_disable_clk(afe, afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL]);
+
+ return 0;
+}
+
+int mt8365_afe_emi_clk_on(struct mtk_base_afe *afe)
+{
+ return 0;
+}
+
+int mt8365_afe_emi_clk_off(struct mtk_base_afe *afe)
+{
+ return 0;
+}
+
+int mt8365_afe_enable_afe_on(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->afe_on_ref_cnt++;
+ if (afe_priv->afe_on_ref_cnt == 1)
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_afe_disable_afe_on(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ afe_priv->afe_on_ref_cnt--;
+ if (afe_priv->afe_on_ref_cnt == 0)
+ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0);
+ else if (afe_priv->afe_on_ref_cnt < 0)
+ afe_priv->afe_on_ref_cnt = 0;
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+static int mt8365_afe_hd_engen_enable(struct mtk_base_afe *afe, bool apll1)
+{
+ if (apll1)
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_PLL_EN, AFE_22M_PLL_EN);
+ else
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_PLL_EN, AFE_24M_PLL_EN);
+
+ return 0;
+}
+
+static int mt8365_afe_hd_engen_disable(struct mtk_base_afe *afe, bool apll1)
+{
+ if (apll1)
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_22M_PLL_EN, ~AFE_22M_PLL_EN);
+ else
+ regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+ AFE_24M_PLL_EN, ~AFE_24M_PLL_EN);
+
+ return 0;
+}
+
+int mt8365_afe_enable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mutex_lock(&afe_priv->afe_clk_mutex);
+
+ afe_priv->apll_tuner_ref_cnt[apll]++;
+ if (afe_priv->apll_tuner_ref_cnt[apll] != 1) {
+ mutex_unlock(&afe_priv->afe_clk_mutex);
+ return 0;
+ }
+
+ if (apll == MT8365_AFE_APLL1) {
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG,
+ AFE_APLL_TUNER_CFG_MASK, 0x432);
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG,
+ AFE_APLL_TUNER_CFG_EN_MASK, 0x1);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1,
+ AFE_APLL_TUNER_CFG1_MASK, 0x434);
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1,
+ AFE_APLL_TUNER_CFG1_EN_MASK, 0x1);
+ }
+
+ mutex_unlock(&afe_priv->afe_clk_mutex);
+ return 0;
+}
+
+int mt8365_afe_disable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ mutex_lock(&afe_priv->afe_clk_mutex);
+
+ afe_priv->apll_tuner_ref_cnt[apll]--;
+ if (afe_priv->apll_tuner_ref_cnt[apll] == 0) {
+ if (apll == MT8365_AFE_APLL1)
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG,
+ AFE_APLL_TUNER_CFG_EN_MASK, 0x0);
+ else
+ regmap_update_bits(afe->regmap, AFE_APLL_TUNER_CFG1,
+ AFE_APLL_TUNER_CFG1_EN_MASK, 0x0);
+
+ } else if (afe_priv->apll_tuner_ref_cnt[apll] < 0) {
+ afe_priv->apll_tuner_ref_cnt[apll] = 0;
+ }
+
+ mutex_unlock(&afe_priv->afe_clk_mutex);
+ return 0;
+}
+
+int mt8365_afe_enable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ if (apll == MT8365_AFE_APLL1) {
+ if (clk_prepare_enable(afe_priv->clocks[MT8365_CLK_ENGEN1])) {
+ dev_info(afe->dev, "%s Failed to enable ENGEN1 clk\n",
+ __func__);
+ return 0;
+ }
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_22M);
+ mt8365_afe_hd_engen_enable(afe, true);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_APLL_TUNER);
+ mt8365_afe_enable_apll_tuner_cfg(afe, MT8365_AFE_APLL1);
+ } else {
+ if (clk_prepare_enable(afe_priv->clocks[MT8365_CLK_ENGEN2])) {
+ dev_info(afe->dev, "%s Failed to enable ENGEN2 clk\n",
+ __func__);
+ return 0;
+ }
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_24M);
+ mt8365_afe_hd_engen_enable(afe, false);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_APLL2_TUNER);
+ mt8365_afe_enable_apll_tuner_cfg(afe, MT8365_AFE_APLL2);
+ }
+
+ return 0;
+}
+
+int mt8365_afe_disable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ if (apll == MT8365_AFE_APLL1) {
+ mt8365_afe_disable_apll_tuner_cfg(afe, MT8365_AFE_APLL1);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_APLL_TUNER);
+ mt8365_afe_hd_engen_disable(afe, true);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_22M);
+ clk_disable_unprepare(afe_priv->clocks[MT8365_CLK_ENGEN1]);
+ } else {
+ mt8365_afe_disable_apll_tuner_cfg(afe, MT8365_AFE_APLL2);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_APLL2_TUNER);
+ mt8365_afe_hd_engen_disable(afe, false);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_24M);
+ clk_disable_unprepare(afe_priv->clocks[MT8365_CLK_ENGEN2]);
+ }
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.h b/sound/soc/mediatek/mt8365/mt8365-afe-clk.h
new file mode 100644
index 000000000000..a6fa653f2183
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * MediaTek 8365 AFE clock control definitions
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#ifndef _MT8365_AFE_UTILS_H_
+#define _MT8365_AFE_UTILS_H_
+
+struct mtk_base_afe;
+struct clk;
+
+int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe);
+void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
+int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, unsigned int rate);
+int mt8365_afe_set_clk_parent(struct mtk_base_afe *afe, struct clk *clk, struct clk *parent);
+int mt8365_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type);
+int mt8365_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_type);
+int mt8365_afe_enable_main_clk(struct mtk_base_afe *afe);
+int mt8365_afe_disable_main_clk(struct mtk_base_afe *afe);
+int mt8365_afe_emi_clk_on(struct mtk_base_afe *afe);
+int mt8365_afe_emi_clk_off(struct mtk_base_afe *afe);
+int mt8365_afe_enable_afe_on(struct mtk_base_afe *afe);
+int mt8365_afe_disable_afe_on(struct mtk_base_afe *afe);
+int mt8365_afe_enable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll);
+int mt8365_afe_disable_apll_tuner_cfg(struct mtk_base_afe *afe, unsigned int apll);
+int mt8365_afe_enable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll);
+int mt8365_afe_disable_apll_associated_cfg(struct mtk_base_afe *afe, unsigned int apll);
+#endif
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-common.h b/sound/soc/mediatek/mt8365/mt8365-afe-common.h
new file mode 100644
index 000000000000..731406e15ac7
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-common.h
@@ -0,0 +1,448 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * MediaTek 8365 audio driver common definitions
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#ifndef _MT8365_AFE_COMMON_H_
+#define _MT8365_AFE_COMMON_H_
+
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/asound.h>
+#include "../common/mtk-base-afe.h"
+#include "mt8365-reg.h"
+
+enum {
+ MT8365_AFE_MEMIF_DL1,
+ MT8365_AFE_MEMIF_DL2,
+ MT8365_AFE_MEMIF_TDM_OUT,
+ /*
+ * MT8365_AFE_MEMIF_SPDIF_OUT,
+ */
+ MT8365_AFE_MEMIF_AWB,
+ MT8365_AFE_MEMIF_VUL,
+ MT8365_AFE_MEMIF_VUL2,
+ MT8365_AFE_MEMIF_VUL3,
+ MT8365_AFE_MEMIF_TDM_IN,
+ /*
+ * MT8365_AFE_MEMIF_SPDIF_IN,
+ */
+ MT8365_AFE_MEMIF_NUM,
+ MT8365_AFE_BACKEND_BASE = MT8365_AFE_MEMIF_NUM,
+ MT8365_AFE_IO_TDM_OUT = MT8365_AFE_BACKEND_BASE,
+ MT8365_AFE_IO_TDM_IN,
+ MT8365_AFE_IO_I2S,
+ MT8365_AFE_IO_2ND_I2S,
+ MT8365_AFE_IO_PCM1,
+ MT8365_AFE_IO_VIRTUAL_DL_SRC,
+ MT8365_AFE_IO_VIRTUAL_TDM_OUT_SRC,
+ MT8365_AFE_IO_VIRTUAL_FM,
+ MT8365_AFE_IO_DMIC,
+ MT8365_AFE_IO_INT_ADDA,
+ MT8365_AFE_IO_GASRC1,
+ MT8365_AFE_IO_GASRC2,
+ MT8365_AFE_IO_TDM_ASRC,
+ MT8365_AFE_IO_HW_GAIN1,
+ MT8365_AFE_IO_HW_GAIN2,
+ MT8365_AFE_BACKEND_END,
+ MT8365_AFE_BACKEND_NUM = (MT8365_AFE_BACKEND_END -
+ MT8365_AFE_BACKEND_BASE),
+};
+
+enum {
+ MT8365_AFE_IRQ1,
+ MT8365_AFE_IRQ2,
+ MT8365_AFE_IRQ3,
+ MT8365_AFE_IRQ4,
+ MT8365_AFE_IRQ5,
+ MT8365_AFE_IRQ6,
+ MT8365_AFE_IRQ7,
+ MT8365_AFE_IRQ8,
+ MT8365_AFE_IRQ9,
+ MT8365_AFE_IRQ10,
+ MT8365_AFE_IRQ_NUM,
+};
+
+enum {
+ MT8365_TOP_CG_AFE,
+ MT8365_TOP_CG_I2S_IN,
+ MT8365_TOP_CG_22M,
+ MT8365_TOP_CG_24M,
+ MT8365_TOP_CG_INTDIR_CK,
+ MT8365_TOP_CG_APLL2_TUNER,
+ MT8365_TOP_CG_APLL_TUNER,
+ MT8365_TOP_CG_SPDIF,
+ MT8365_TOP_CG_TDM_OUT,
+ MT8365_TOP_CG_TDM_IN,
+ MT8365_TOP_CG_ADC,
+ MT8365_TOP_CG_DAC,
+ MT8365_TOP_CG_DAC_PREDIS,
+ MT8365_TOP_CG_TML,
+ MT8365_TOP_CG_I2S1_BCLK,
+ MT8365_TOP_CG_I2S2_BCLK,
+ MT8365_TOP_CG_I2S3_BCLK,
+ MT8365_TOP_CG_I2S4_BCLK,
+ MT8365_TOP_CG_DMIC0_ADC,
+ MT8365_TOP_CG_DMIC1_ADC,
+ MT8365_TOP_CG_DMIC2_ADC,
+ MT8365_TOP_CG_DMIC3_ADC,
+ MT8365_TOP_CG_CONNSYS_I2S_ASRC,
+ MT8365_TOP_CG_GENERAL1_ASRC,
+ MT8365_TOP_CG_GENERAL2_ASRC,
+ MT8365_TOP_CG_TDM_ASRC,
+ MT8365_TOP_CG_NUM
+};
+
+enum {
+ MT8365_CLK_TOP_AUD_SEL,
+ MT8365_CLK_AUD_I2S0_M,
+ MT8365_CLK_AUD_I2S1_M,
+ MT8365_CLK_AUD_I2S2_M,
+ MT8365_CLK_AUD_I2S3_M,
+ MT8365_CLK_ENGEN1,
+ MT8365_CLK_ENGEN2,
+ MT8365_CLK_AUD1,
+ MT8365_CLK_AUD2,
+ MT8365_CLK_I2S0_M_SEL,
+ MT8365_CLK_I2S1_M_SEL,
+ MT8365_CLK_I2S2_M_SEL,
+ MT8365_CLK_I2S3_M_SEL,
+ MT8365_CLK_CLK26M,
+ MT8365_CLK_NUM
+};
+
+enum {
+ MT8365_AFE_APLL1 = 0,
+ MT8365_AFE_APLL2,
+ MT8365_AFE_APLL_NUM,
+};
+
+enum {
+ MT8365_AFE_1ST_I2S = 0,
+ MT8365_AFE_2ND_I2S,
+ MT8365_AFE_I2S_SETS,
+};
+
+enum {
+ MT8365_AFE_I2S_SEPARATE_CLOCK = 0,
+ MT8365_AFE_I2S_SHARED_CLOCK,
+};
+
+enum {
+ MT8365_AFE_TDM_OUT_I2S = 0,
+ MT8365_AFE_TDM_OUT_TDM,
+ MT8365_AFE_TDM_OUT_I2S_32BITS,
+};
+
+enum mt8365_afe_tdm_ch_start {
+ AFE_TDM_CH_START_O28_O29 = 0,
+ AFE_TDM_CH_START_O30_O31,
+ AFE_TDM_CH_START_O32_O33,
+ AFE_TDM_CH_START_O34_O35,
+ AFE_TDM_CH_ZERO,
+};
+
+enum {
+ MT8365_PCM_FORMAT_I2S = 0,
+ MT8365_PCM_FORMAT_EIAJ,
+ MT8365_PCM_FORMAT_PCMA,
+ MT8365_PCM_FORMAT_PCMB,
+};
+
+enum {
+ MT8365_FS_8K = 0,
+ MT8365_FS_11D025K,
+ MT8365_FS_12K,
+ MT8365_FS_384K,
+ MT8365_FS_16K,
+ MT8365_FS_22D05K,
+ MT8365_FS_24K,
+ MT8365_FS_130K,
+ MT8365_FS_32K,
+ MT8365_FS_44D1K,
+ MT8365_FS_48K,
+ MT8365_FS_88D2K,
+ MT8365_FS_96K,
+ MT8365_FS_176D4K,
+ MT8365_FS_192K,
+};
+
+enum {
+ FS_8000HZ = 0, /* 0000b */
+ FS_11025HZ = 1, /* 0001b */
+ FS_12000HZ = 2, /* 0010b */
+ FS_384000HZ = 3, /* 0011b */
+ FS_16000HZ = 4, /* 0100b */
+ FS_22050HZ = 5, /* 0101b */
+ FS_24000HZ = 6, /* 0110b */
+ FS_130000HZ = 7, /* 0111b */
+ FS_32000HZ = 8, /* 1000b */
+ FS_44100HZ = 9, /* 1001b */
+ FS_48000HZ = 10, /* 1010b */
+ FS_88200HZ = 11, /* 1011b */
+ FS_96000HZ = 12, /* 1100b */
+ FS_176400HZ = 13, /* 1101b */
+ FS_192000HZ = 14, /* 1110b */
+ FS_260000HZ = 15, /* 1111b */
+};
+
+enum {
+ MT8365_AFE_DEBUGFS_AFE,
+ MT8365_AFE_DEBUGFS_MEMIF,
+ MT8365_AFE_DEBUGFS_IRQ,
+ MT8365_AFE_DEBUGFS_CONN,
+ MT8365_AFE_DEBUGFS_DBG,
+ MT8365_AFE_DEBUGFS_NUM,
+};
+
+enum {
+ MT8365_AFE_IRQ_DIR_MCU = 0,
+ MT8365_AFE_IRQ_DIR_DSP,
+ MT8365_AFE_IRQ_DIR_BOTH,
+};
+
+/* MCLK */
+enum {
+ MT8365_I2S0_MCK = 0,
+ MT8365_I2S3_MCK,
+ MT8365_MCK_NUM,
+};
+
+struct mt8365_fe_dai_data {
+ bool use_sram;
+ unsigned int sram_phy_addr;
+ void __iomem *sram_vir_addr;
+ unsigned int sram_size;
+};
+
+struct mt8365_be_dai_data {
+ bool prepared[SNDRV_PCM_STREAM_LAST + 1];
+ unsigned int fmt_mode;
+};
+
+#define MT8365_CLK_26M 26000000
+#define MT8365_CLK_24M 24000000
+#define MT8365_CLK_22M 22000000
+#define MT8365_CM_UPDATA_CNT_SET 8
+
+enum mt8365_cm_num {
+ MT8365_CM1 = 0,
+ MT8365_CM2,
+ MT8365_CM_NUM,
+};
+
+enum mt8365_cm2_mux_in {
+ MT8365_FROM_GASRC1 = 1,
+ MT8365_FROM_GASRC2,
+ MT8365_FROM_TDM_ASRC,
+ MT8365_CM_MUX_NUM,
+};
+
+enum cm2_mux_conn_in {
+ GENERAL2_ASRC_OUT_LCH = 0,
+ GENERAL2_ASRC_OUT_RCH = 1,
+ TDM_IN_CH0 = 2,
+ TDM_IN_CH1 = 3,
+ TDM_IN_CH2 = 4,
+ TDM_IN_CH3 = 5,
+ TDM_IN_CH4 = 6,
+ TDM_IN_CH5 = 7,
+ TDM_IN_CH6 = 8,
+ TDM_IN_CH7 = 9,
+ GENERAL1_ASRC_OUT_LCH = 10,
+ GENERAL1_ASRC_OUT_RCH = 11,
+ TDM_OUT_ASRC_CH0 = 12,
+ TDM_OUT_ASRC_CH1 = 13,
+ TDM_OUT_ASRC_CH2 = 14,
+ TDM_OUT_ASRC_CH3 = 15,
+ TDM_OUT_ASRC_CH4 = 16,
+ TDM_OUT_ASRC_CH5 = 17,
+ TDM_OUT_ASRC_CH6 = 18,
+ TDM_OUT_ASRC_CH7 = 19
+};
+
+struct mt8365_cm_ctrl_reg {
+ unsigned int con0;
+ unsigned int con1;
+ unsigned int con2;
+ unsigned int con3;
+ unsigned int con4;
+};
+
+struct mt8365_control_data {
+ bool bypass_cm1;
+ bool bypass_cm2;
+ unsigned int loopback_type;
+};
+
+enum dmic_input_mode {
+ DMIC_MODE_3P25M = 0,
+ DMIC_MODE_1P625M,
+ DMIC_MODE_812P5K,
+ DMIC_MODE_406P25K,
+};
+
+enum iir_mode {
+ IIR_MODE0 = 0,
+ IIR_MODE1,
+ IIR_MODE2,
+ IIR_MODE3,
+ IIR_MODE4,
+ IIR_MODE5,
+};
+
+enum {
+ MT8365_GASRC1 = 0,
+ MT8365_GASRC2,
+ MT8365_GASRC_NUM,
+ MT8365_TDM_ASRC1 = MT8365_GASRC_NUM,
+ MT8365_TDM_ASRC2,
+ MT8365_TDM_ASRC3,
+ MT8365_TDM_ASRC4,
+ MT8365_TDM_ASRC_NUM,
+};
+
+struct mt8365_gasrc_ctrl_reg {
+ unsigned int con0;
+ unsigned int con2;
+ unsigned int con3;
+ unsigned int con4;
+ unsigned int con5;
+ unsigned int con6;
+ unsigned int con9;
+ unsigned int con10;
+ unsigned int con12;
+ unsigned int con13;
+};
+
+struct mt8365_gasrc_data {
+ bool duplex;
+ bool tx_mode;
+ bool cali_on;
+ bool tdm_asrc_out_cm2;
+ bool iir_on;
+};
+
+struct mt8365_afe_private {
+ struct clk *clocks[MT8365_CLK_NUM];
+ struct regmap *topckgen;
+ struct mt8365_fe_dai_data fe_data[MT8365_AFE_MEMIF_NUM];
+ struct mt8365_be_dai_data be_data[MT8365_AFE_BACKEND_NUM];
+ struct mt8365_control_data ctrl_data;
+ struct mt8365_gasrc_data gasrc_data[MT8365_TDM_ASRC_NUM];
+ int afe_on_ref_cnt;
+ int top_cg_ref_cnt[MT8365_TOP_CG_NUM];
+ void __iomem *afe_sram_vir_addr;
+ unsigned int afe_sram_phy_addr;
+ unsigned int afe_sram_size;
+ /* locks */
+ spinlock_t afe_ctrl_lock;
+ struct mutex afe_clk_mutex; /* Protect & sync APLL TUNER registers access*/
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_dentry[MT8365_AFE_DEBUGFS_NUM];
+#endif
+ int apll_tuner_ref_cnt[MT8365_AFE_APLL_NUM];
+ unsigned int tdm_out_mode;
+ unsigned int cm2_mux_input;
+
+ /* dai */
+ bool dai_on[MT8365_AFE_BACKEND_END];
+ void *dai_priv[MT8365_AFE_BACKEND_END];
+};
+
+static inline u32 rx_frequency_palette(unsigned int fs)
+{
+ /* *
+ * A = (26M / fs) * 64
+ * B = 8125 / A
+ * return = DEC2HEX(B * 2^23)
+ */
+ switch (fs) {
+ case FS_8000HZ: return 0x050000;
+ case FS_11025HZ: return 0x06E400;
+ case FS_12000HZ: return 0x078000;
+ case FS_16000HZ: return 0x0A0000;
+ case FS_22050HZ: return 0x0DC800;
+ case FS_24000HZ: return 0x0F0000;
+ case FS_32000HZ: return 0x140000;
+ case FS_44100HZ: return 0x1B9000;
+ case FS_48000HZ: return 0x1E0000;
+ case FS_88200HZ: return 0x372000;
+ case FS_96000HZ: return 0x3C0000;
+ case FS_176400HZ: return 0x6E4000;
+ case FS_192000HZ: return 0x780000;
+ default: return 0x0;
+ }
+}
+
+static inline u32 AutoRstThHi(unsigned int fs)
+{
+ switch (fs) {
+ case FS_8000HZ: return 0x36000;
+ case FS_11025HZ: return 0x27000;
+ case FS_12000HZ: return 0x24000;
+ case FS_16000HZ: return 0x1B000;
+ case FS_22050HZ: return 0x14000;
+ case FS_24000HZ: return 0x12000;
+ case FS_32000HZ: return 0x0D800;
+ case FS_44100HZ: return 0x09D00;
+ case FS_48000HZ: return 0x08E00;
+ case FS_88200HZ: return 0x04E00;
+ case FS_96000HZ: return 0x04800;
+ case FS_176400HZ: return 0x02700;
+ case FS_192000HZ: return 0x02400;
+ default: return 0x0;
+ }
+}
+
+static inline u32 AutoRstThLo(unsigned int fs)
+{
+ switch (fs) {
+ case FS_8000HZ: return 0x30000;
+ case FS_11025HZ: return 0x23000;
+ case FS_12000HZ: return 0x20000;
+ case FS_16000HZ: return 0x18000;
+ case FS_22050HZ: return 0x11000;
+ case FS_24000HZ: return 0x0FE00;
+ case FS_32000HZ: return 0x0BE00;
+ case FS_44100HZ: return 0x08A00;
+ case FS_48000HZ: return 0x07F00;
+ case FS_88200HZ: return 0x04500;
+ case FS_96000HZ: return 0x04000;
+ case FS_176400HZ: return 0x02300;
+ case FS_192000HZ: return 0x02000;
+ default: return 0x0;
+ }
+}
+
+bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id);
+bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id);
+
+int mt8365_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8365_dai_set_priv(struct mtk_base_afe *afe,
+ int id,
+ int priv_size,
+ const void *priv_data);
+
+int mt8365_afe_fs_timing(unsigned int rate);
+
+void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable);
+int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe, unsigned int rate, int bit_width);
+
+int mt8365_dai_adda_register(struct mtk_base_afe *afe);
+int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe);
+int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe);
+
+int mt8365_dai_dmic_register(struct mtk_base_afe *afe);
+
+int mt8365_dai_pcm_register(struct mtk_base_afe *afe);
+
+int mt8365_dai_tdm_register(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
new file mode 100644
index 000000000000..d01793394f22
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
@@ -0,0 +1,2271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek 8365 ALSA SoC AFE platform driver
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-common.h"
+#include "mt8365-afe-clk.h"
+#include "mt8365-reg.h"
+#include "../common/mtk-base-afe.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#define AFE_BASE_END_OFFSET 8
+
+static unsigned int mCM2Input;
+
+static const unsigned int mt8365_afe_backup_list[] = {
+ AUDIO_TOP_CON0,
+ AFE_CONN0,
+ AFE_CONN1,
+ AFE_CONN3,
+ AFE_CONN4,
+ AFE_CONN5,
+ AFE_CONN6,
+ AFE_CONN7,
+ AFE_CONN8,
+ AFE_CONN9,
+ AFE_CONN10,
+ AFE_CONN11,
+ AFE_CONN12,
+ AFE_CONN13,
+ AFE_CONN14,
+ AFE_CONN15,
+ AFE_CONN16,
+ AFE_CONN17,
+ AFE_CONN18,
+ AFE_CONN19,
+ AFE_CONN20,
+ AFE_CONN21,
+ AFE_CONN26,
+ AFE_CONN27,
+ AFE_CONN28,
+ AFE_CONN29,
+ AFE_CONN30,
+ AFE_CONN31,
+ AFE_CONN32,
+ AFE_CONN33,
+ AFE_CONN34,
+ AFE_CONN35,
+ AFE_CONN36,
+ AFE_CONN_24BIT,
+ AFE_CONN_24BIT_1,
+ AFE_DAC_CON0,
+ AFE_DAC_CON1,
+ AFE_DL1_BASE,
+ AFE_DL1_END,
+ AFE_DL2_BASE,
+ AFE_DL2_END,
+ AFE_VUL_BASE,
+ AFE_VUL_END,
+ AFE_AWB_BASE,
+ AFE_AWB_END,
+ AFE_VUL3_BASE,
+ AFE_VUL3_END,
+ AFE_HDMI_OUT_BASE,
+ AFE_HDMI_OUT_END,
+ AFE_HDMI_IN_2CH_BASE,
+ AFE_HDMI_IN_2CH_END,
+ AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_DL_SRC2_CON0,
+ AFE_ADDA_DL_SRC2_CON1,
+ AFE_I2S_CON,
+ AFE_I2S_CON1,
+ AFE_I2S_CON2,
+ AFE_I2S_CON3,
+ AFE_ADDA_UL_SRC_CON0,
+ AFE_AUD_PAD_TOP,
+ AFE_HD_ENGEN_ENABLE,
+};
+
+static const struct snd_pcm_hardware mt8365_afe_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .buffer_bytes_max = 256 * 1024,
+ .period_bytes_min = 512,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .fifo_size = 0,
+};
+
+struct mt8365_afe_rate {
+ unsigned int rate;
+ unsigned int reg_val;
+};
+
+static const struct mt8365_afe_rate mt8365_afe_fs_rates[] = {
+ { .rate = 8000, .reg_val = MT8365_FS_8K },
+ { .rate = 11025, .reg_val = MT8365_FS_11D025K },
+ { .rate = 12000, .reg_val = MT8365_FS_12K },
+ { .rate = 16000, .reg_val = MT8365_FS_16K },
+ { .rate = 22050, .reg_val = MT8365_FS_22D05K },
+ { .rate = 24000, .reg_val = MT8365_FS_24K },
+ { .rate = 32000, .reg_val = MT8365_FS_32K },
+ { .rate = 44100, .reg_val = MT8365_FS_44D1K },
+ { .rate = 48000, .reg_val = MT8365_FS_48K },
+ { .rate = 88200, .reg_val = MT8365_FS_88D2K },
+ { .rate = 96000, .reg_val = MT8365_FS_96K },
+ { .rate = 176400, .reg_val = MT8365_FS_176D4K },
+ { .rate = 192000, .reg_val = MT8365_FS_192K },
+};
+
+int mt8365_afe_fs_timing(unsigned int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mt8365_afe_fs_rates); i++)
+ if (mt8365_afe_fs_rates[i].rate == rate)
+ return mt8365_afe_fs_rates[i].reg_val;
+
+ return -EINVAL;
+}
+
+bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id)
+{
+ switch (id) {
+ case MT8365_AFE_IO_TDM_IN:
+ if (rate >= 8000 && rate <= 192000)
+ return true;
+ break;
+ case MT8365_AFE_IO_DMIC:
+ if (rate >= 8000 && rate <= 48000)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id)
+{
+ switch (id) {
+ case MT8365_AFE_IO_TDM_IN:
+ if (channel >= 1 && channel <= 8)
+ return true;
+ break;
+ case MT8365_AFE_IO_DMIC:
+ if (channel >= 1 && channel <= 8)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool mt8365_afe_clk_group_44k(int sample_rate)
+{
+ if (sample_rate == 11025 ||
+ sample_rate == 22050 ||
+ sample_rate == 44100 ||
+ sample_rate == 88200 ||
+ sample_rate == 176400)
+ return true;
+ else
+ return false;
+}
+
+static bool mt8365_afe_clk_group_48k(int sample_rate)
+{
+ return (!mt8365_afe_clk_group_44k(sample_rate));
+}
+
+int mt8365_dai_set_priv(struct mtk_base_afe *afe, int id,
+ int priv_size, const void *priv_data)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ void *temp_data;
+
+ temp_data = devm_kzalloc(afe->dev, priv_size, GFP_KERNEL);
+ if (!temp_data)
+ return -ENOMEM;
+
+ if (priv_data)
+ memcpy(temp_data, priv_data, priv_size);
+
+ afe_priv->dai_priv[id] = temp_data;
+
+ return 0;
+}
+
+static int mt8365_afe_irq_direction_enable(struct mtk_base_afe *afe,
+ int irq_id, int direction)
+{
+ struct mtk_base_afe_irq *irq;
+
+ if (irq_id >= MT8365_AFE_IRQ_NUM)
+ return -1;
+
+ irq = &afe->irqs[irq_id];
+
+ if (direction == MT8365_AFE_IRQ_DIR_MCU) {
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ 0);
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ } else if (direction == MT8365_AFE_IRQ_DIR_DSP) {
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ 0);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+ (1 << irq->irq_data->irq_clr_shift),
+ (1 << irq->irq_data->irq_clr_shift));
+ }
+ return 0;
+}
+
+static int mt8365_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ return mt8365_afe_fs_timing(rate);
+}
+
+static int mt8365_irq_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ return mt8365_memif_fs(substream, rate);
+}
+
+static const struct mt8365_cm_ctrl_reg cm_ctrl_reg[MT8365_CM_NUM] = {
+ [MT8365_CM1] = {
+ .con0 = AFE_CM1_CON0,
+ .con1 = AFE_CM1_CON1,
+ .con2 = AFE_CM1_CON2,
+ .con3 = AFE_CM1_CON3,
+ .con4 = AFE_CM1_CON4,
+ },
+ [MT8365_CM2] = {
+ .con0 = AFE_CM2_CON0,
+ .con1 = AFE_CM2_CON1,
+ .con2 = AFE_CM2_CON2,
+ .con3 = AFE_CM2_CON3,
+ .con4 = AFE_CM2_CON4,
+ }
+};
+
+static int mt8365_afe_cm2_mux_conn(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ unsigned int input = afe_priv->cm2_mux_input;
+
+ /* TDM_IN interconnect to CM2 */
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG1_MASK,
+ CM2_AFE_CM2_CONN_CFG1(TDM_IN_CH0));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG2_MASK,
+ CM2_AFE_CM2_CONN_CFG2(TDM_IN_CH1));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG3_MASK,
+ CM2_AFE_CM2_CONN_CFG3(TDM_IN_CH2));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG4_MASK,
+ CM2_AFE_CM2_CONN_CFG4(TDM_IN_CH3));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG5_MASK,
+ CM2_AFE_CM2_CONN_CFG5(TDM_IN_CH4));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+ CM2_AFE_CM2_CONN_CFG6_MASK,
+ CM2_AFE_CM2_CONN_CFG6(TDM_IN_CH5));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG7_MASK,
+ CM2_AFE_CM2_CONN_CFG7(TDM_IN_CH6));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG8_MASK,
+ CM2_AFE_CM2_CONN_CFG8(TDM_IN_CH7));
+
+ /* ref data interconnect to CM2 */
+ if (input == MT8365_FROM_GASRC1) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG9_MASK,
+ CM2_AFE_CM2_CONN_CFG9(GENERAL1_ASRC_OUT_LCH));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG10_MASK,
+ CM2_AFE_CM2_CONN_CFG10(GENERAL1_ASRC_OUT_RCH));
+ } else if (input == MT8365_FROM_GASRC2) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG9_MASK,
+ CM2_AFE_CM2_CONN_CFG9(GENERAL2_ASRC_OUT_LCH));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG10_MASK,
+ CM2_AFE_CM2_CONN_CFG10(GENERAL2_ASRC_OUT_RCH));
+ } else if (input == MT8365_FROM_TDM_ASRC) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG9_MASK,
+ CM2_AFE_CM2_CONN_CFG9(TDM_OUT_ASRC_CH0));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG10_MASK,
+ CM2_AFE_CM2_CONN_CFG10(TDM_OUT_ASRC_CH1));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG11_MASK,
+ CM2_AFE_CM2_CONN_CFG11(TDM_OUT_ASRC_CH2));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+ CM2_AFE_CM2_CONN_CFG12_MASK,
+ CM2_AFE_CM2_CONN_CFG12(TDM_OUT_ASRC_CH3));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG13_MASK,
+ CM2_AFE_CM2_CONN_CFG13(TDM_OUT_ASRC_CH4));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG14_MASK,
+ CM2_AFE_CM2_CONN_CFG14(TDM_OUT_ASRC_CH5));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG15_MASK,
+ CM2_AFE_CM2_CONN_CFG15(TDM_OUT_ASRC_CH6));
+ regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+ CM2_AFE_CM2_CONN_CFG16_MASK,
+ CM2_AFE_CM2_CONN_CFG16(TDM_OUT_ASRC_CH7));
+ } else {
+ dev_err(afe->dev, "%s wrong CM2 input %d\n", __func__, input);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mt8365_afe_get_cm_update_cnt(struct mtk_base_afe *afe,
+ enum mt8365_cm_num cmNum,
+ unsigned int rate, unsigned int channel)
+{
+ unsigned int total_cnt, div_cnt, ch_pair, best_cnt;
+ unsigned int ch_update_cnt[MT8365_CM_UPDATA_CNT_SET];
+ int i;
+
+ /* calculate cm update cnt
+ * total_cnt = clk / fs, clk is 26m or 24m or 22m
+ * div_cnt = total_cnt / ch_pair, max ch 16ch ,2ch is a set
+ * best_cnt < div_cnt ,we set best_cnt = div_cnt -10
+ * ch01 = best_cnt, ch23 = 2* ch01_up_cnt
+ * ch45 = 3* ch01_up_cnt ...ch1415 = 8* ch01_up_cnt
+ */
+
+ if (cmNum == MT8365_CM1) {
+ total_cnt = MT8365_CLK_26M / rate;
+ } else if (cmNum == MT8365_CM2) {
+ if (mt8365_afe_clk_group_48k(rate))
+ total_cnt = MT8365_CLK_24M / rate;
+ else
+ total_cnt = MT8365_CLK_22M / rate;
+ } else {
+ return -1;
+ }
+
+ if (channel % 2)
+ ch_pair = (channel / 2) + 1;
+ else
+ ch_pair = channel / 2;
+
+ div_cnt = total_cnt / ch_pair;
+ best_cnt = div_cnt - 10;
+
+ if (best_cnt <= 0)
+ return -1;
+
+ for (i = 0; i < ch_pair; i++)
+ ch_update_cnt[i] = (i + 1) * best_cnt;
+
+ switch (channel) {
+ case 16:
+ fallthrough;
+ case 15:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[7]));
+ fallthrough;
+ case 14:
+ fallthrough;
+ case 13:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[6]));
+ fallthrough;
+ case 12:
+ fallthrough;
+ case 11:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[5]));
+ fallthrough;
+ case 10:
+ fallthrough;
+ case 9:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[4]));
+ fallthrough;
+ case 8:
+ fallthrough;
+ case 7:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[3]));
+ fallthrough;
+ case 6:
+ fallthrough;
+ case 5:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[2]));
+ fallthrough;
+ case 4:
+ fallthrough;
+ case 3:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1,
+ CM_AFE_CM_UPDATE_CNT2_MASK,
+ CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[1]));
+ fallthrough;
+ case 2:
+ fallthrough;
+ case 1:
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1,
+ CM_AFE_CM_UPDATE_CNT1_MASK,
+ CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[0]));
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mt8365_afe_configure_cm(struct mtk_base_afe *afe,
+ enum mt8365_cm_num cmNum,
+ unsigned int channels,
+ unsigned int rate)
+{
+ unsigned int val, mask;
+ unsigned int fs = mt8365_afe_fs_timing(rate);
+
+ val = FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, (channels - 1)) |
+ FIELD_PREP(CM_AFE_CM_START_DATA_MASK, 0);
+
+ mask = CM_AFE_CM_CH_NUM_MASK |
+ CM_AFE_CM_START_DATA_MASK;
+
+ if (cmNum == MT8365_CM1) {
+ val |= FIELD_PREP(CM_AFE_CM1_IN_MODE_MASK, fs);
+
+ mask |= CM_AFE_CM1_VUL_SEL |
+ CM_AFE_CM1_IN_MODE_MASK;
+ } else if (cmNum == MT8365_CM2) {
+ if (mt8365_afe_clk_group_48k(rate))
+ val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 0);
+ else
+ val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 1);
+
+ val |= FIELD_PREP(CM_AFE_CM2_TDM_SEL, 1);
+
+ mask |= CM_AFE_CM2_TDM_SEL |
+ CM_AFE_CM1_IN_MODE_MASK |
+ CM_AFE_CM2_CLK_SEL;
+
+ mt8365_afe_cm2_mux_conn(afe);
+ } else {
+ return -1;
+ }
+
+ regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con0, mask, val);
+
+ mt8365_afe_get_cm_update_cnt(afe, cmNum, rate, channels);
+
+ return 0;
+}
+
+static int mt8365_afe_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+ int ret;
+
+ memif->substream = substream;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
+ snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+ mt8365_afe_enable_main_clk(afe);
+ return ret;
+}
+
+static void mt8365_afe_fe_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+
+ memif->substream = NULL;
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_afe_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+ struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
+ size_t request_size = params_buffer_bytes(params);
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+ unsigned int base_end_offset = 8;
+ int ret, fs;
+
+ dev_info(afe->dev, "%s %s period = %d rate = %d channels = %d\n",
+ __func__, memif->data->name, params_period_size(params),
+ rate, channels);
+
+ if (dai_id == MT8365_AFE_MEMIF_VUL2) {
+ if (!ctrl_data->bypass_cm1)
+ /* configure cm1 */
+ mt8365_afe_configure_cm(afe, MT8365_CM1,
+ channels, rate);
+ else
+ regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+ CM_AFE_CM1_VUL_SEL,
+ CM_AFE_CM1_VUL_SEL);
+ } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
+ if (!ctrl_data->bypass_cm2)
+ /* configure cm2 */
+ mt8365_afe_configure_cm(afe, MT8365_CM2,
+ channels, rate);
+ else
+ regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+ CM_AFE_CM2_TDM_SEL,
+ ~CM_AFE_CM2_TDM_SEL);
+
+ base_end_offset = 4;
+ }
+
+ if (request_size > fe_data->sram_size) {
+ ret = snd_pcm_lib_malloc_pages(substream, request_size);
+ if (ret < 0) {
+ dev_err(afe->dev,
+ "%s %s malloc pages %zu bytes failed %d\n",
+ __func__, memif->data->name, request_size, ret);
+ return ret;
+ }
+
+ fe_data->use_sram = false;
+
+ mt8365_afe_emi_clk_on(afe);
+ } else {
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->area = (unsigned char *)fe_data->sram_vir_addr;
+ dma_buf->addr = fe_data->sram_phy_addr;
+ dma_buf->bytes = request_size;
+ snd_pcm_set_runtime_buffer(substream, dma_buf);
+
+ fe_data->use_sram = true;
+ }
+
+ memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
+ memif->buffer_size = substream->runtime->dma_bytes;
+
+ /* start */
+ regmap_write(afe->regmap, memif->data->reg_ofs_base,
+ memif->phys_buf_addr);
+ /* end */
+ regmap_write(afe->regmap,
+ memif->data->reg_ofs_base + base_end_offset,
+ memif->phys_buf_addr + memif->buffer_size - 1);
+
+ /* set channel */
+ if (memif->data->mono_shift >= 0) {
+ unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
+
+ if (memif->data->mono_reg < 0)
+ dev_info(afe->dev, "%s mono_reg is NULL\n", __func__);
+ else
+ regmap_update_bits(afe->regmap, memif->data->mono_reg,
+ 1 << memif->data->mono_shift,
+ mono << memif->data->mono_shift);
+ }
+
+ /* set rate */
+ if (memif->data->fs_shift < 0)
+ return 0;
+
+ fs = afe->memif_fs(substream, params_rate(params));
+
+ if (fs < 0)
+ return -EINVAL;
+
+ if (memif->data->fs_reg < 0)
+ dev_info(afe->dev, "%s fs_reg is NULL\n", __func__);
+ else
+ regmap_update_bits(afe->regmap, memif->data->fs_reg,
+ memif->data->fs_maskbit << memif->data->fs_shift,
+ fs << memif->data->fs_shift);
+
+ return 0;
+}
+
+static int mt8365_afe_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
+ int ret = 0;
+
+ if (fe_data->use_sram) {
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ } else {
+ ret = snd_pcm_lib_free_pages(substream);
+
+ mt8365_afe_emi_clk_off(afe);
+ }
+
+ return ret;
+}
+
+static int mt8365_afe_fe_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+
+ /* set format */
+ if (memif->data->hd_reg >= 0) {
+ switch (substream->runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 0 << memif->data->hd_shift);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 3 << memif->data->hd_shift);
+
+ if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
+ regmap_update_bits(afe->regmap,
+ memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 1 << memif->data->hd_shift);
+ regmap_update_bits(afe->regmap,
+ memif->data->hd_reg,
+ 1 << memif->data->hd_align_mshift,
+ 1 << memif->data->hd_align_mshift);
+ }
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ regmap_update_bits(afe->regmap, memif->data->hd_reg,
+ 3 << memif->data->hd_shift,
+ 1 << memif->data->hd_shift);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ mt8365_afe_irq_direction_enable(afe, memif->irq_usage,
+ MT8365_AFE_IRQ_DIR_MCU);
+
+ return 0;
+}
+
+static int mt8365_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+ struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* enable channel merge */
+ if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
+ !ctrl_data->bypass_cm1) {
+ regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+ CM_AFE_CM_ON, CM_AFE_CM_ON);
+ } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
+ !ctrl_data->bypass_cm2) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+ CM_AFE_CM_ON, CM_AFE_CM_ON);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* disable channel merge */
+ if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
+ !ctrl_data->bypass_cm1) {
+ regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+ CM_AFE_CM_ON, ~CM_AFE_CM_ON);
+ } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
+ !ctrl_data->bypass_cm2) {
+ regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+ CM_AFE_CM_ON, ~CM_AFE_CM_ON);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return mtk_afe_fe_trigger(substream, cmd, dai);
+}
+
+static int mt8365_afe_hw_gain1_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_afe_enable_main_clk(afe);
+ return 0;
+}
+
+static void mt8365_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+ if (be->prepared[substream->stream]) {
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+ AFE_GAIN1_CON0_EN_MASK, 0);
+ be->prepared[substream->stream] = false;
+ }
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_afe_hw_gain1_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+ int fs;
+ unsigned int val1 = 0, val2 = 0;
+
+ if (be->prepared[substream->stream]) {
+ dev_info(afe->dev, "%s prepared already\n", __func__);
+ return 0;
+ }
+
+ fs = mt8365_afe_fs_timing(substream->runtime->rate);
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+ AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs << 4);
+
+ regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1);
+ regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2);
+ if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK))
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CUR,
+ AFE_GAIN1_CUR_MASK, val1);
+
+ regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+ AFE_GAIN1_CON0_EN_MASK, 1);
+ be->prepared[substream->stream] = true;
+
+ return 0;
+}
+
+static const struct snd_pcm_hardware mt8365_hostless_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .period_bytes_min = 256,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 8 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+
+ snd_soc_set_runtime_hwparams(substream, &mt8365_hostless_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+ return ret;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8365_afe_fe_dai_ops = {
+ .startup = mt8365_afe_fe_startup,
+ .shutdown = mt8365_afe_fe_shutdown,
+ .hw_params = mt8365_afe_fe_hw_params,
+ .hw_free = mt8365_afe_fe_hw_free,
+ .prepare = mt8365_afe_fe_prepare,
+ .trigger = mt8365_afe_fe_trigger,
+};
+
+static const struct snd_soc_dai_ops mt8365_dai_hostless_ops = {
+ .startup = mtk_dai_hostless_startup,
+};
+
+static const struct snd_soc_dai_ops mt8365_afe_hw_gain1_ops = {
+ .startup = mt8365_afe_hw_gain1_startup,
+ .shutdown = mt8365_afe_hw_gain1_shutdown,
+ .prepare = mt8365_afe_hw_gain1_prepare,
+};
+
+static struct snd_soc_dai_driver mt8365_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1",
+ .id = MT8365_AFE_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "DL2",
+ .id = MT8365_AFE_MEMIF_DL2,
+ .playback = {
+ .stream_name = "DL2",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "TDM_OUT",
+ .id = MT8365_AFE_MEMIF_TDM_OUT,
+ .playback = {
+ .stream_name = "TDM_OUT",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "AWB",
+ .id = MT8365_AFE_MEMIF_AWB,
+ .capture = {
+ .stream_name = "AWB",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "VUL",
+ .id = MT8365_AFE_MEMIF_VUL,
+ .capture = {
+ .stream_name = "VUL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "VUL2",
+ .id = MT8365_AFE_MEMIF_VUL2,
+ .capture = {
+ .stream_name = "VUL2",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "VUL3",
+ .id = MT8365_AFE_MEMIF_VUL3,
+ .capture = {
+ .stream_name = "VUL3",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "TDM_IN",
+ .id = MT8365_AFE_MEMIF_TDM_IN,
+ .capture = {
+ .stream_name = "TDM_IN",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_fe_dai_ops,
+ }, {
+ .name = "Hostless FM DAI",
+ .id = MT8365_AFE_IO_VIRTUAL_FM,
+ .playback = {
+ .stream_name = "Hostless FM DL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "Hostless FM UL",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_dai_hostless_ops,
+ }, {
+ .name = "HW_GAIN1",
+ .id = MT8365_AFE_IO_HW_GAIN1,
+ .playback = {
+ .stream_name = "HW Gain 1 In",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "HW Gain 1 Out",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_hw_gain1_ops,
+ .symmetric_rate = 1,
+ .symmetric_channels = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o00_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN0, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN0, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o01_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN1, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o03_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN3, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN3, 7, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN3, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I10 Switch", AFE_CONN3, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o04_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN4, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN4, 8, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN4, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I11 Switch", AFE_CONN4, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o05_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN5, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN5, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN5, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN5, 7, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN5, 9, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN5, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN5, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN5, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN5, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN5, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I10L Switch", AFE_CONN5, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o06_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN6, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN6, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN6, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN6, 8, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN6, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN6, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN6, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN6, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN6, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN6, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I11L Switch", AFE_CONN6, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o07_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN7, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN7, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o08_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN8, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN8, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o09_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN9, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN9, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN9, 9, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN9, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN9, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN9, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN9, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o10_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN10, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN10, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN10, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN10, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN10, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN10, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN10, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o11_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN11, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN11, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN11, 9, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN11, 14, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN11, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN11, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN11, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o12_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN12, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN12, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN12, 22, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN12, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN12, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN12, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN12, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o13_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN13, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o14_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN14, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o15_mix[] = {
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o16_mix[] = {
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o17_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN17, 3, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o18_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN18, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN18, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN18, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o19_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN19, 4, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN19, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN19, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN19, 25, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN19, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o20_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN20, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN20, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o21_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN21, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN21, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o22_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN22, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN22, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o23_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN23, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN23, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o24_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN24, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN24, 26, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN24, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN24, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o25_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I27 Switch", AFE_CONN25, 27, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN25, 23, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN25, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o26_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I28 Switch", AFE_CONN26, 28, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN26, 24, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN26, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o27_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN27, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN27, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o28_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN28, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN28, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o29_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN29, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN29, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o30_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN30, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN30, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o31_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I29 Switch", AFE_CONN31, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o32_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I30 Switch", AFE_CONN32, 30, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o33_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I31 Switch", AFE_CONN33, 31, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o34_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I32 Switch", AFE_CONN34_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o35_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I33 Switch", AFE_CONN35_1, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o36_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I34 Switch", AFE_CONN36_1, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13,
+ 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14,
+ 1, 1, 0),
+};
+
+static int mt8365_afe_cm2_io_input_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = mCM2Input;
+
+ return 0;
+}
+
+static int mt8365_afe_cm2_io_input_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(comp);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ mCM2Input = ucontrol->value.enumerated.item[0];
+
+ afe_priv->cm2_mux_input = mCM2Input;
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ return ret;
+}
+
+static const char * const fmhwgain_text[] = {
+ "OPEN", "FM_HW_GAIN_IO"
+};
+
+static const char * const ain_text[] = {
+ "INT ADC", "EXT ADC",
+};
+
+static const char * const vul2_in_input_text[] = {
+ "VUL2_IN_FROM_O17O18", "VUL2_IN_FROM_CM1",
+};
+
+static const char * const mt8365_afe_cm2_mux_text[] = {
+ "OPEN", "FROM_GASRC1_OUT", "FROM_GASRC2_OUT", "FROM_TDM_ASRC_OUT",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(fmhwgain_enum, fmhwgain_text);
+static SOC_ENUM_SINGLE_DECL(ain_enum, AFE_ADDA_TOP_CON0, 0, ain_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(vul2_in_input_enum, vul2_in_input_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(mt8365_afe_cm2_mux_input_enum,
+ mt8365_afe_cm2_mux_text);
+
+static const struct snd_kcontrol_new fmhwgain_mux =
+ SOC_DAPM_ENUM("FM HW Gain Source", fmhwgain_enum);
+
+static const struct snd_kcontrol_new ain_mux =
+ SOC_DAPM_ENUM("AIN Source", ain_enum);
+
+static const struct snd_kcontrol_new vul2_in_input_mux =
+ SOC_DAPM_ENUM("VUL2 Input", vul2_in_input_enum);
+
+static const struct snd_kcontrol_new mt8365_afe_cm2_mux_input_mux =
+ SOC_DAPM_ENUM_EXT("CM2_MUX Source", mt8365_afe_cm2_mux_input_enum,
+ mt8365_afe_cm2_io_input_mux_get,
+ mt8365_afe_cm2_io_input_mux_put);
+
+static const struct snd_soc_dapm_widget mt8365_memif_widgets[] = {
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I07", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I08", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I05L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I06L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I07L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I08L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I09", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I10", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I11", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I10L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I11L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I20", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I21", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I22", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I23", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I24", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I25", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I27", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I28", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I29", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I30", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I31", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I32", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I33", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I34", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o00_mix, ARRAY_SIZE(mt8365_afe_o00_mix)),
+ SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o01_mix, ARRAY_SIZE(mt8365_afe_o01_mix)),
+ SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o03_mix, ARRAY_SIZE(mt8365_afe_o03_mix)),
+ SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o04_mix, ARRAY_SIZE(mt8365_afe_o04_mix)),
+ SND_SOC_DAPM_MIXER("O05", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o05_mix, ARRAY_SIZE(mt8365_afe_o05_mix)),
+ SND_SOC_DAPM_MIXER("O06", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o06_mix, ARRAY_SIZE(mt8365_afe_o06_mix)),
+ SND_SOC_DAPM_MIXER("O07", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o07_mix, ARRAY_SIZE(mt8365_afe_o07_mix)),
+ SND_SOC_DAPM_MIXER("O08", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o08_mix, ARRAY_SIZE(mt8365_afe_o08_mix)),
+ SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o09_mix, ARRAY_SIZE(mt8365_afe_o09_mix)),
+ SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o10_mix, ARRAY_SIZE(mt8365_afe_o10_mix)),
+ SND_SOC_DAPM_MIXER("O11", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o11_mix, ARRAY_SIZE(mt8365_afe_o11_mix)),
+ SND_SOC_DAPM_MIXER("O12", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o12_mix, ARRAY_SIZE(mt8365_afe_o12_mix)),
+ SND_SOC_DAPM_MIXER("O13", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o13_mix, ARRAY_SIZE(mt8365_afe_o13_mix)),
+ SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o14_mix, ARRAY_SIZE(mt8365_afe_o14_mix)),
+ SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o15_mix, ARRAY_SIZE(mt8365_afe_o15_mix)),
+ SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o16_mix, ARRAY_SIZE(mt8365_afe_o16_mix)),
+ SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o17_mix, ARRAY_SIZE(mt8365_afe_o17_mix)),
+ SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o18_mix, ARRAY_SIZE(mt8365_afe_o18_mix)),
+ SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o19_mix, ARRAY_SIZE(mt8365_afe_o19_mix)),
+ SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o20_mix, ARRAY_SIZE(mt8365_afe_o20_mix)),
+ SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o21_mix, ARRAY_SIZE(mt8365_afe_o21_mix)),
+ SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o22_mix, ARRAY_SIZE(mt8365_afe_o22_mix)),
+ SND_SOC_DAPM_MIXER("O23", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o23_mix, ARRAY_SIZE(mt8365_afe_o23_mix)),
+ SND_SOC_DAPM_MIXER("O24", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o24_mix, ARRAY_SIZE(mt8365_afe_o24_mix)),
+ SND_SOC_DAPM_MIXER("O25", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o25_mix, ARRAY_SIZE(mt8365_afe_o25_mix)),
+ SND_SOC_DAPM_MIXER("O26", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o26_mix, ARRAY_SIZE(mt8365_afe_o26_mix)),
+ SND_SOC_DAPM_MIXER("O27", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o27_mix, ARRAY_SIZE(mt8365_afe_o27_mix)),
+ SND_SOC_DAPM_MIXER("O28", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o28_mix, ARRAY_SIZE(mt8365_afe_o28_mix)),
+ SND_SOC_DAPM_MIXER("O29", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o29_mix, ARRAY_SIZE(mt8365_afe_o29_mix)),
+ SND_SOC_DAPM_MIXER("O30", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o30_mix, ARRAY_SIZE(mt8365_afe_o30_mix)),
+ SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o31_mix, ARRAY_SIZE(mt8365_afe_o31_mix)),
+ SND_SOC_DAPM_MIXER("O32", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o32_mix, ARRAY_SIZE(mt8365_afe_o32_mix)),
+ SND_SOC_DAPM_MIXER("O33", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o33_mix, ARRAY_SIZE(mt8365_afe_o33_mix)),
+ SND_SOC_DAPM_MIXER("O34", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o34_mix, ARRAY_SIZE(mt8365_afe_o34_mix)),
+ SND_SOC_DAPM_MIXER("O35", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o35_mix, ARRAY_SIZE(mt8365_afe_o35_mix)),
+ SND_SOC_DAPM_MIXER("O36", SND_SOC_NOPM, 0, 0,
+ mt8365_afe_o36_mix, ARRAY_SIZE(mt8365_afe_o36_mix)),
+ SND_SOC_DAPM_MIXER("CM2_Mux IO", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("CM1_IO", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("O17O18", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_hw_gain1_in_ch1_mix,
+ ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)),
+ SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_hw_gain1_in_ch2_mix,
+ ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)),
+
+ SND_SOC_DAPM_INPUT("DL Source"),
+
+ SND_SOC_DAPM_MUX("CM2_Mux_IO Input Mux", SND_SOC_NOPM, 0, 0,
+ &mt8365_afe_cm2_mux_input_mux),
+
+ SND_SOC_DAPM_MUX("AIN Mux", SND_SOC_NOPM, 0, 0, &ain_mux),
+ SND_SOC_DAPM_MUX("VUL2 Input Mux", SND_SOC_NOPM, 0, 0,
+ &vul2_in_input_mux),
+
+ SND_SOC_DAPM_MUX("FM HW Gain Mux", SND_SOC_NOPM, 0, 0, &fmhwgain_mux),
+
+ SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
+ SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
+};
+
+static const struct snd_soc_dapm_route mt8365_memif_routes[] = {
+ /* downlink */
+ {"I00", NULL, "2ND I2S Capture"},
+ {"I01", NULL, "2ND I2S Capture"},
+ {"I05", NULL, "DL1"},
+ {"I06", NULL, "DL1"},
+ {"I07", NULL, "DL2"},
+ {"I08", NULL, "DL2"},
+
+ {"O03", "I05 Switch", "I05"},
+ {"O04", "I06 Switch", "I06"},
+ {"O00", "I05 Switch", "I05"},
+ {"O01", "I06 Switch", "I06"},
+ {"O07", "I05 Switch", "I05"},
+ {"O08", "I06 Switch", "I06"},
+ {"O27", "I05 Switch", "I05"},
+ {"O28", "I06 Switch", "I06"},
+ {"O29", "I05 Switch", "I05"},
+ {"O30", "I06 Switch", "I06"},
+
+ {"O03", "I07 Switch", "I07"},
+ {"O04", "I08 Switch", "I08"},
+ {"O00", "I07 Switch", "I07"},
+ {"O01", "I08 Switch", "I08"},
+ {"O07", "I07 Switch", "I07"},
+ {"O08", "I08 Switch", "I08"},
+
+ /* uplink */
+ {"AWB", NULL, "O05"},
+ {"AWB", NULL, "O06"},
+ {"VUL", NULL, "O09"},
+ {"VUL", NULL, "O10"},
+ {"VUL3", NULL, "O11"},
+ {"VUL3", NULL, "O12"},
+
+ {"AIN Mux", "EXT ADC", "I2S Capture"},
+ {"I03", NULL, "AIN Mux"},
+ {"I04", NULL, "AIN Mux"},
+
+ {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1", "Hostless FM DL"},
+ {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2", "Hostless FM DL"},
+
+ {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
+ {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
+ {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
+ {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
+
+ {"FM HW Gain Mux", "FM_HW_GAIN_IO", "HW Gain 1 Out"},
+ {"Hostless FM UL", NULL, "FM HW Gain Mux"},
+ {"Hostless FM UL", NULL, "FM 2ND I2S Mux"},
+
+ {"O05", "I05 Switch", "I05L"},
+ {"O06", "I06 Switch", "I06L"},
+ {"O05", "I07 Switch", "I07L"},
+ {"O06", "I08 Switch", "I08L"},
+
+ {"O05", "I03 Switch", "I03"},
+ {"O06", "I04 Switch", "I04"},
+ {"O05", "I00 Switch", "I00"},
+ {"O06", "I01 Switch", "I01"},
+ {"O05", "I09 Switch", "I09"},
+ {"O06", "I22 Switch", "I22"},
+ {"O05", "I14 Switch", "I14"},
+ {"O06", "I15 Switch", "I15"},
+ {"O05", "I16 Switch", "I16"},
+ {"O06", "I17 Switch", "I17"},
+ {"O05", "I18 Switch", "I18"},
+ {"O06", "I19 Switch", "I19"},
+ {"O05", "I20 Switch", "I20"},
+ {"O06", "I21 Switch", "I21"},
+ {"O05", "I23 Switch", "I23"},
+ {"O06", "I24 Switch", "I24"},
+
+ {"O09", "I03 Switch", "I03"},
+ {"O10", "I04 Switch", "I04"},
+ {"O09", "I00 Switch", "I00"},
+ {"O10", "I01 Switch", "I01"},
+ {"O09", "I09 Switch", "I09"},
+ {"O10", "I22 Switch", "I22"},
+ {"O09", "I14 Switch", "I14"},
+ {"O10", "I15 Switch", "I15"},
+ {"O09", "I16 Switch", "I16"},
+ {"O10", "I17 Switch", "I17"},
+ {"O09", "I18 Switch", "I18"},
+ {"O10", "I19 Switch", "I19"},
+ {"O09", "I20 Switch", "I20"},
+ {"O10", "I21 Switch", "I21"},
+
+ {"O11", "I03 Switch", "I03"},
+ {"O12", "I04 Switch", "I04"},
+ {"O11", "I00 Switch", "I00"},
+ {"O12", "I01 Switch", "I01"},
+ {"O11", "I09 Switch", "I09"},
+ {"O12", "I22 Switch", "I22"},
+ {"O11", "I14 Switch", "I14"},
+ {"O12", "I15 Switch", "I15"},
+ {"O11", "I16 Switch", "I16"},
+ {"O12", "I17 Switch", "I17"},
+ {"O11", "I18 Switch", "I18"},
+ {"O12", "I19 Switch", "I19"},
+ {"O11", "I20 Switch", "I20"},
+ {"O12", "I21 Switch", "I21"},
+
+ /* CM2_Mux*/
+ {"CM2_Mux IO", NULL, "CM2_Mux_IO Input Mux"},
+
+ /* VUL2 */
+ {"VUL2", NULL, "VUL2 Input Mux"},
+ {"VUL2 Input Mux", "VUL2_IN_FROM_O17O18", "O17O18"},
+ {"VUL2 Input Mux", "VUL2_IN_FROM_CM1", "CM1_IO"},
+
+ {"O17O18", NULL, "O17"},
+ {"O17O18", NULL, "O18"},
+ {"CM1_IO", NULL, "O17"},
+ {"CM1_IO", NULL, "O18"},
+ {"CM1_IO", NULL, "O19"},
+ {"CM1_IO", NULL, "O20"},
+ {"CM1_IO", NULL, "O21"},
+ {"CM1_IO", NULL, "O22"},
+ {"CM1_IO", NULL, "O23"},
+ {"CM1_IO", NULL, "O24"},
+ {"CM1_IO", NULL, "O25"},
+ {"CM1_IO", NULL, "O26"},
+ {"CM1_IO", NULL, "O31"},
+ {"CM1_IO", NULL, "O32"},
+ {"CM1_IO", NULL, "O33"},
+ {"CM1_IO", NULL, "O34"},
+ {"CM1_IO", NULL, "O35"},
+ {"CM1_IO", NULL, "O36"},
+
+ {"O17", "I14 Switch", "I14"},
+ {"O18", "I15 Switch", "I15"},
+ {"O19", "I16 Switch", "I16"},
+ {"O20", "I17 Switch", "I17"},
+ {"O21", "I18 Switch", "I18"},
+ {"O22", "I19 Switch", "I19"},
+ {"O23", "I20 Switch", "I20"},
+ {"O24", "I21 Switch", "I21"},
+ {"O25", "I23 Switch", "I23"},
+ {"O26", "I24 Switch", "I24"},
+ {"O25", "I25 Switch", "I25"},
+ {"O26", "I26 Switch", "I26"},
+
+ {"O17", "I03 Switch", "I03"},
+ {"O18", "I04 Switch", "I04"},
+ {"O18", "I23 Switch", "I23"},
+ {"O18", "I25 Switch", "I25"},
+ {"O19", "I04 Switch", "I04"},
+ {"O19", "I23 Switch", "I23"},
+ {"O19", "I24 Switch", "I24"},
+ {"O19", "I25 Switch", "I25"},
+ {"O19", "I26 Switch", "I26"},
+ {"O20", "I24 Switch", "I24"},
+ {"O20", "I26 Switch", "I26"},
+ {"O21", "I23 Switch", "I23"},
+ {"O21", "I25 Switch", "I25"},
+ {"O22", "I24 Switch", "I24"},
+ {"O22", "I26 Switch", "I26"},
+
+ {"O23", "I23 Switch", "I23"},
+ {"O23", "I25 Switch", "I25"},
+ {"O24", "I24 Switch", "I24"},
+ {"O24", "I26 Switch", "I26"},
+ {"O24", "I23 Switch", "I23"},
+ {"O24", "I25 Switch", "I25"},
+ {"O13", "I00 Switch", "I00"},
+ {"O14", "I01 Switch", "I01"},
+ {"O03", "I10 Switch", "I10"},
+ {"O04", "I11 Switch", "I11"},
+};
+
+static const struct mtk_base_memif_data memif_data[MT8365_AFE_MEMIF_NUM] = {
+ {
+ .name = "DL1",
+ .id = MT8365_AFE_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL1_BASE,
+ .reg_ofs_cur = AFE_DL1_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 0,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 21,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 16,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 1,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "DL2",
+ .id = MT8365_AFE_MEMIF_DL2,
+ .reg_ofs_base = AFE_DL2_BASE,
+ .reg_ofs_cur = AFE_DL2_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 4,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 22,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 18,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 2,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "TDM OUT",
+ .id = MT8365_AFE_MEMIF_TDM_OUT,
+ .reg_ofs_base = AFE_HDMI_OUT_BASE,
+ .reg_ofs_cur = AFE_HDMI_OUT_CUR,
+ .fs_reg = -1,
+ .fs_shift = -1,
+ .fs_maskbit = -1,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 28,
+ .enable_reg = AFE_HDMI_OUT_CON0,
+ .enable_shift = 0,
+ .msb_reg = -1,
+ .msb_shift = -1,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "AWB",
+ .id = MT8365_AFE_MEMIF_AWB,
+ .reg_ofs_base = AFE_AWB_BASE,
+ .reg_ofs_cur = AFE_AWB_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 12,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 24,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 20,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 6,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 17,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "VUL",
+ .id = MT8365_AFE_MEMIF_VUL,
+ .reg_ofs_base = AFE_VUL_BASE,
+ .reg_ofs_cur = AFE_VUL_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 16,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON1,
+ .mono_shift = 27,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 22,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 3,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 20,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "VUL2",
+ .id = MT8365_AFE_MEMIF_VUL2,
+ .reg_ofs_base = AFE_VUL_D2_BASE,
+ .reg_ofs_cur = AFE_VUL_D2_CUR,
+ .fs_reg = AFE_DAC_CON0,
+ .fs_shift = 20,
+ .fs_maskbit = 0xf,
+ .mono_reg = -1,
+ .mono_shift = -1,
+ .hd_reg = AFE_MEMIF_PBUF_SIZE,
+ .hd_shift = 14,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 9,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 21,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "VUL3",
+ .id = MT8365_AFE_MEMIF_VUL3,
+ .reg_ofs_base = AFE_VUL3_BASE,
+ .reg_ofs_cur = AFE_VUL3_CUR,
+ .fs_reg = AFE_DAC_CON1,
+ .fs_shift = 8,
+ .fs_maskbit = 0xf,
+ .mono_reg = AFE_DAC_CON0,
+ .mono_shift = 13,
+ .hd_reg = AFE_MEMIF_PBUF2_SIZE,
+ .hd_shift = 10,
+ .enable_reg = AFE_DAC_CON0,
+ .enable_shift = 12,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 27,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ }, {
+ .name = "TDM IN",
+ .id = MT8365_AFE_MEMIF_TDM_IN,
+ .reg_ofs_base = AFE_HDMI_IN_2CH_BASE,
+ .reg_ofs_cur = AFE_HDMI_IN_2CH_CUR,
+ .fs_reg = -1,
+ .fs_shift = -1,
+ .fs_maskbit = -1,
+ .mono_reg = AFE_HDMI_IN_2CH_CON0,
+ .mono_shift = 1,
+ .hd_reg = AFE_MEMIF_PBUF2_SIZE,
+ .hd_shift = 8,
+ .hd_align_mshift = 5,
+ .enable_reg = AFE_HDMI_IN_2CH_CON0,
+ .enable_shift = 0,
+ .msb_reg = AFE_MEMIF_MSB,
+ .msb_shift = 28,
+ .agent_disable_reg = -1,
+ .agent_disable_shift = -1,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT8365_AFE_IRQ_NUM] = {
+ {
+ .id = MT8365_AFE_IRQ1,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 0,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 4,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 0,
+ }, {
+ .id = MT8365_AFE_IRQ2,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 1,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 8,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 1,
+ }, {
+ .id = MT8365_AFE_IRQ3,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 2,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 16,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 2,
+ }, {
+ .id = MT8365_AFE_IRQ4,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 3,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 20,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 3,
+ }, {
+ .id = MT8365_AFE_IRQ5,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON2,
+ .irq_en_shift = 3,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 4,
+ }, {
+ .id = MT8365_AFE_IRQ6,
+ .irq_cnt_reg = -1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x0,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 13,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 5,
+ }, {
+ .id = MT8365_AFE_IRQ7,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 14,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 24,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 6,
+ }, {
+ .id = MT8365_AFE_IRQ8,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON,
+ .irq_en_shift = 15,
+ .irq_fs_reg = AFE_IRQ_MCU_CON,
+ .irq_fs_shift = 28,
+ .irq_fs_maskbit = 0xf,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 7,
+ }, {
+ .id = MT8365_AFE_IRQ9,
+ .irq_cnt_reg = -1,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x0,
+ .irq_en_reg = AFE_IRQ_MCU_CON2,
+ .irq_en_shift = 2,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 8,
+ }, {
+ .id = MT8365_AFE_IRQ10,
+ .irq_cnt_reg = AFE_IRQ_MCU_CNT10,
+ .irq_cnt_shift = 0,
+ .irq_cnt_maskbit = 0x3ffff,
+ .irq_en_reg = AFE_IRQ_MCU_CON2,
+ .irq_en_shift = 4,
+ .irq_fs_reg = -1,
+ .irq_fs_shift = 0,
+ .irq_fs_maskbit = 0x0,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = 9,
+ },
+};
+
+static int memif_specified_irqs[MT8365_AFE_MEMIF_NUM] = {
+ [MT8365_AFE_MEMIF_DL1] = MT8365_AFE_IRQ1,
+ [MT8365_AFE_MEMIF_DL2] = MT8365_AFE_IRQ2,
+ [MT8365_AFE_MEMIF_TDM_OUT] = MT8365_AFE_IRQ5,
+ [MT8365_AFE_MEMIF_AWB] = MT8365_AFE_IRQ3,
+ [MT8365_AFE_MEMIF_VUL] = MT8365_AFE_IRQ4,
+ [MT8365_AFE_MEMIF_VUL2] = MT8365_AFE_IRQ7,
+ [MT8365_AFE_MEMIF_VUL3] = MT8365_AFE_IRQ8,
+ [MT8365_AFE_MEMIF_TDM_IN] = MT8365_AFE_IRQ10,
+};
+
+static const struct regmap_config mt8365_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = MAX_REGISTER,
+ .cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mt8365_afe_irq_handler(int irq, void *dev_id)
+{
+ struct mtk_base_afe *afe = dev_id;
+ unsigned int reg_value;
+ unsigned int mcu_irq_mask;
+ int i, ret;
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &reg_value);
+ if (ret) {
+ dev_err_ratelimited(afe->dev, "%s irq status err\n", __func__);
+ reg_value = AFE_IRQ_STATUS_BITS;
+ goto err_irq;
+ }
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_mask);
+ if (ret) {
+ dev_err_ratelimited(afe->dev, "%s irq mcu_en err\n", __func__);
+ reg_value = AFE_IRQ_STATUS_BITS;
+ goto err_irq;
+ }
+
+ /* only clr cpu irq */
+ reg_value &= mcu_irq_mask;
+
+ for (i = 0; i < MT8365_AFE_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+ struct mtk_base_afe_irq *mcu_irq;
+
+ if (memif->irq_usage < 0)
+ continue;
+
+ mcu_irq = &afe->irqs[memif->irq_usage];
+
+ if (!(reg_value & (1 << mcu_irq->irq_data->irq_clr_shift)))
+ continue;
+
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap, AFE_IRQ_MCU_CLR,
+ reg_value & AFE_IRQ_STATUS_BITS);
+
+ return IRQ_HANDLED;
+}
+
+static int mt8365_afe_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int mt8365_afe_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+
+static int mt8365_afe_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct regmap *regmap = afe->regmap;
+ int i;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ if (!afe->reg_back_up)
+ afe->reg_back_up =
+ devm_kcalloc(dev, afe->reg_back_up_list_num,
+ sizeof(unsigned int), GFP_KERNEL);
+
+ for (i = 0; i < afe->reg_back_up_list_num; i++)
+ regmap_read(regmap, afe->reg_back_up_list[i],
+ &afe->reg_back_up[i]);
+
+ mt8365_afe_disable_main_clk(afe);
+
+ return 0;
+}
+
+static int mt8365_afe_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct regmap *regmap = afe->regmap;
+ int i = 0;
+
+ if (!afe->reg_back_up)
+ return 0;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ for (i = 0; i < afe->reg_back_up_list_num; i++)
+ regmap_write(regmap, afe->reg_back_up_list[i],
+ afe->reg_back_up[i]);
+
+ mt8365_afe_disable_main_clk(afe);
+
+ return 0;
+}
+
+static int mt8365_afe_dev_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+ if (pm_runtime_status_suspended(dev) || afe->suspended)
+ return 0;
+
+ mt8365_afe_suspend(dev);
+ afe->suspended = true;
+ return 0;
+}
+
+static int mt8365_afe_dev_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+ if (pm_runtime_status_suspended(dev) || !afe->suspended)
+ return 0;
+
+ mt8365_afe_resume(dev);
+ afe->suspended = false;
+ return 0;
+}
+
+static int mt8365_afe_init_registers(struct mtk_base_afe *afe)
+{
+ size_t i;
+
+ static struct {
+ unsigned int reg;
+ unsigned int mask;
+ unsigned int val;
+ } init_regs[] = {
+ { AFE_CONN_24BIT, GENMASK(31, 0), GENMASK(31, 0) },
+ { AFE_CONN_24BIT_1, GENMASK(21, 0), GENMASK(21, 0) },
+ };
+
+ mt8365_afe_enable_main_clk(afe);
+
+ for (i = 0; i < ARRAY_SIZE(init_regs); i++)
+ regmap_update_bits(afe->regmap, init_regs[i].reg,
+ init_regs[i].mask, init_regs[i].val);
+
+ mt8365_afe_disable_main_clk(afe);
+
+ return 0;
+}
+
+static int mt8365_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt8365_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt8365_memif_dai_driver);
+
+ dai->dapm_widgets = mt8365_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt8365_memif_widgets);
+ dai->dapm_routes = mt8365_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt8365_memif_routes);
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt8365_dai_pcm_register,
+ mt8365_dai_i2s_register,
+ mt8365_dai_adda_register,
+ mt8365_dai_dmic_register,
+ mt8365_dai_memif_register,
+};
+
+static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt8365_afe_private *afe_priv;
+ struct device *dev;
+ int ret, i, sel_irq;
+ unsigned int irq_id;
+ struct resource *res;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, afe);
+
+ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+ GFP_KERNEL);
+ if (!afe->platform_priv)
+ return -ENOMEM;
+
+ afe_priv = afe->platform_priv;
+ afe->dev = &pdev->dev;
+ dev = afe->dev;
+
+ spin_lock_init(&afe_priv->afe_ctrl_lock);
+ mutex_init(&afe_priv->afe_clk_mutex);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(afe->base_addr))
+ return PTR_ERR(afe->base_addr);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ afe_priv->afe_sram_vir_addr =
+ devm_ioremap_resource(&pdev->dev, res);
+ if (!IS_ERR(afe_priv->afe_sram_vir_addr)) {
+ afe_priv->afe_sram_phy_addr = res->start;
+ afe_priv->afe_sram_size = resource_size(res);
+ }
+ }
+
+ /* initial audio related clock */
+ ret = mt8365_afe_init_audio_clk(afe);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "mt8365_afe_init_audio_clk fail\n");
+
+ afe->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "top_audio_sel",
+ afe->base_addr,
+ &mt8365_afe_regmap_config);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ /* memif % irq initialize*/
+ afe->memif_size = MT8365_AFE_MEMIF_NUM;
+ afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
+ sizeof(*afe->memif), GFP_KERNEL);
+ if (!afe->memif)
+ return -ENOMEM;
+
+ afe->irqs_size = MT8365_AFE_IRQ_NUM;
+ afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
+ sizeof(*afe->irqs), GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+
+ irq_id = ret;
+ ret = devm_request_irq(afe->dev, irq_id, mt8365_afe_irq_handler,
+ 0, "Afe_ISR_Handle", (void *)afe);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "could not request_irq\n");
+
+ /* init sub_dais */
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret) {
+ dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret) {
+ dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 0; i < afe->memif_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ sel_irq = memif_specified_irqs[i];
+ if (sel_irq >= 0) {
+ afe->memif[i].irq_usage = sel_irq;
+ afe->memif[i].const_irq = 1;
+ afe->irqs[sel_irq].irq_occupyed = true;
+ } else {
+ afe->memif[i].irq_usage = -1;
+ }
+ }
+
+ afe->mtk_afe_hardware = &mt8365_afe_hardware;
+ afe->memif_fs = mt8365_memif_fs;
+ afe->irq_fs = mt8365_irq_fs;
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_sync(&pdev->dev);
+ afe->reg_back_up_list = mt8365_afe_backup_list;
+ afe->reg_back_up_list_num = ARRAY_SIZE(mt8365_afe_backup_list);
+ afe->runtime_resume = mt8365_afe_runtime_resume;
+ afe->runtime_suspend = mt8365_afe_runtime_suspend;
+
+ /* open afe pdn for dapm read/write audio register */
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE);
+
+ /* Set 26m parent clk */
+ mt8365_afe_set_clk_parent(afe,
+ afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL],
+ afe_priv->clocks[MT8365_CLK_CLK26M]);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mtk_afe_pcm_platform,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret) {
+ dev_warn(dev, "err_platform\n");
+ return ret;
+ }
+
+ mt8365_afe_init_registers(afe);
+
+ return 0;
+}
+
+static void mt8365_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE);
+
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt8365_afe_runtime_suspend(&pdev->dev);
+}
+
+static const struct of_device_id mt8365_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt8365-afe-pcm", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8365_afe_pm_ops = {
+ 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 = pm_ptr(&mt8365_afe_pm_ops),
+ },
+ .probe = mt8365_afe_pcm_dev_probe,
+ .remove = mt8365_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8365_afe_pcm_driver);
+
+MODULE_DESCRIPTION("MediaTek ALSA SoC AFE platform driver");
+MODULE_AUTHOR("Jia Zeng <jia.zeng@mediatek.com>");
+MODULE_AUTHOR("Alexandre Mergnat <amergnat@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-adda.c b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
new file mode 100644
index 000000000000..a04c24bbfcff
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek 8365 ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+#include "../common/mtk-dai-adda-common.h"
+
+static int adda_afe_on_ref_cnt;
+
+/* DAI Drivers */
+
+static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate)
+{
+ unsigned int val;
+
+ if (rate == 8000 || rate == 16000)
+ val = AFE_ADDA_DL_VOICE_DATA;
+ else
+ val = 0;
+
+ val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE,
+ mtk_adda_dl_rate_transform(afe, rate));
+ val |= AFE_ADDA_DL_8X_UPSAMPLE |
+ AFE_ADDA_DL_MUTE_OFF_CH1 |
+ AFE_ADDA_DL_MUTE_OFF_CH2 |
+ AFE_ADDA_DL_DEGRADE_GAIN;
+
+ regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);
+ regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);
+ /* SA suggest apply -0.3db to audio/speech path */
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1,
+ 0xffffffff, 0xf74f0000);
+ /* SA suggest use default value for sdm */
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,
+ 0xffffffff, 0x0700701e);
+
+ return 0;
+}
+
+static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate)
+{
+ unsigned int val;
+
+ val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE,
+ mtk_adda_ul_rate_transform(afe, rate));
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+ AFE_ADDA_UL_SAMPLING_RATE, val);
+ /* Using Internal ADC */
+ regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);
+
+ return 0;
+}
+
+int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe)
+{
+ unsigned long flags;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ adda_afe_on_ref_cnt++;
+ if (adda_afe_on_ref_cnt == 1)
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_ADDA_AFE_ON,
+ AFE_ADDA_UL_DL_ADDA_AFE_ON);
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe)
+{
+ unsigned long flags;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ adda_afe_on_ref_cnt--;
+ if (adda_afe_on_ref_cnt == 0)
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_ADDA_AFE_ON,
+ ~AFE_ADDA_UL_DL_ADDA_AFE_ON);
+ else if (adda_afe_on_ref_cnt < 0) {
+ adda_afe_on_ref_cnt = 0;
+ dev_warn(afe->dev, "Abnormal adda_on ref count. Force it to 0\n");
+ }
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+ return 0;
+}
+
+static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe,
+ bool enable)
+{
+ regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);
+
+ if (enable)
+ mt8365_dai_enable_adda_on(afe);
+ else
+ mt8365_dai_disable_adda_on(afe);
+}
+
+static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe, bool enable)
+{
+ if (enable) {
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1);
+ mt8365_dai_enable_adda_on(afe);
+ /* enable aud_pad_top fifo */
+ regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
+ 0xffffffff, 0x31);
+ } else {
+ /* disable aud_pad_top fifo */
+ regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
+ 0xffffffff, 0x30);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0);
+ /* de suggest disable ADDA_UL_SRC at least wait 125us */
+ usleep_range(150, 300);
+ mt8365_dai_disable_adda_on(afe);
+ }
+}
+
+static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ unsigned int stream = substream->stream;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
+ } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC);
+ }
+
+ return 0;
+}
+
+static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ unsigned int stream = substream->stream;
+
+ if (be->prepared[stream]) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mt8365_dai_set_adda_out_enable(afe, false);
+ mt8365_afe_set_i2s_out_enable(afe, false);
+ } else {
+ mt8365_dai_set_adda_in_enable(afe, false);
+ }
+ be->prepared[stream] = false;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC);
+ } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC);
+ }
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ unsigned int rate = substream->runtime->rate;
+ int bit_width = snd_pcm_format_width(substream->runtime->format);
+ int ret;
+
+ dev_info(afe->dev, "%s '%s' rate = %u\n", __func__,
+ snd_pcm_stream_str(substream), rate);
+
+ if (be->prepared[substream->stream]) {
+ dev_info(afe->dev, "%s '%s' prepared already\n",
+ __func__, snd_pcm_stream_str(substream));
+ return 0;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = mt8365_dai_set_adda_out(afe, rate);
+ if (ret)
+ return ret;
+
+ ret = mt8365_afe_set_i2s_out(afe, rate, bit_width);
+ if (ret)
+ return ret;
+
+ mt8365_dai_set_adda_out_enable(afe, true);
+ mt8365_afe_set_i2s_out_enable(afe, true);
+ } else {
+ ret = mt8365_dai_set_adda_in(afe, rate);
+ if (ret)
+ return ret;
+
+ mt8365_dai_set_adda_in_enable(afe, true);
+ }
+ be->prepared[substream->stream] = true;
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = {
+ .startup = mt8365_dai_int_adda_startup,
+ .shutdown = mt8365_dai_int_adda_shutdown,
+ .prepare = mt8365_dai_int_adda_prepare,
+};
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+ {
+ .name = "INT ADDA",
+ .id = MT8365_AFE_IO_INT_ADDA,
+ .playback = {
+ .stream_name = "INT ADDA Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "INT ADDA Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_int_adda_ops,
+ }
+};
+
+/* DAI Controls */
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,
+ 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,
+ 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+ SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0,
+ &int_adda_o03_o04_enable_ctl),
+ /* inter-connections */
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch1_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+ SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+ mtk_adda_dl_ch2_mix,
+ ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+ {"INT ADDA O03_O04", "Switch", "O03"},
+ {"INT ADDA O03_O04", "Switch", "O04"},
+ {"INT ADDA Playback", NULL, "INT ADDA O03_O04"},
+ {"INT ADDA Playback", NULL, "ADDA_DL_CH1"},
+ {"INT ADDA Playback", NULL, "ADDA_DL_CH2"},
+ {"AIN Mux", "INT ADC", "INT ADDA Capture"},
+ {"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"},
+ {"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"},
+};
+
+int mt8365_dai_adda_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_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
new file mode 100644
index 000000000000..0bac143b48bf
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek 8365 ALSA SoC Audio DAI DMIC Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mt8365_dmic_data {
+ bool two_wire_mode;
+ unsigned int clk_phase_sel_ch1;
+ unsigned int clk_phase_sel_ch2;
+ bool iir_on;
+ unsigned int irr_mode;
+ unsigned int dmic_mode;
+ unsigned int dmic_channel;
+};
+
+static int get_chan_reg(unsigned int channel)
+{
+ switch (channel) {
+ case 8:
+ fallthrough;
+ case 7:
+ return AFE_DMIC3_UL_SRC_CON0;
+ case 6:
+ fallthrough;
+ case 5:
+ return AFE_DMIC2_UL_SRC_CON0;
+ case 4:
+ fallthrough;
+ case 3:
+ return AFE_DMIC1_UL_SRC_CON0;
+ case 2:
+ fallthrough;
+ case 1:
+ return AFE_DMIC0_UL_SRC_CON0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* DAI Drivers */
+
+static void audio_dmic_adda_enable(struct mtk_base_afe *afe)
+{
+ mt8365_dai_enable_adda_on(afe);
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,
+ AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);
+}
+
+static void audio_dmic_adda_disable(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+ AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,
+ ~AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);
+ mt8365_dai_disable_adda_on(afe);
+}
+
+static void mt8365_dai_enable_dmic(struct mtk_base_afe *afe,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+ unsigned int val_mask;
+ int reg = get_chan_reg(dmic_data->dmic_channel);
+
+ if (reg < 0)
+ return;
+
+ /* val and mask will be always same to enable */
+ val_mask = DMIC_TOP_CON_CH1_ON |
+ DMIC_TOP_CON_CH2_ON |
+ DMIC_TOP_CON_SRC_ON;
+
+ regmap_update_bits(afe->regmap, reg, val_mask, val_mask);
+}
+
+static void mt8365_dai_disable_dmic(struct mtk_base_afe *afe,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+ unsigned int mask;
+ int reg = get_chan_reg(dmic_data->dmic_channel);
+
+ if (reg < 0)
+ return;
+
+ dev_dbg(afe->dev, "%s dmic_channel %d\n", __func__, dmic_data->dmic_channel);
+
+ mask = DMIC_TOP_CON_CH1_ON |
+ DMIC_TOP_CON_CH2_ON |
+ DMIC_TOP_CON_SRC_ON |
+ DMIC_TOP_CON_SDM3_LEVEL_MODE;
+
+ /* Set all masked values to 0 */
+ regmap_update_bits(afe->regmap, reg, mask, 0);
+}
+
+static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+ bool two_wire_mode = dmic_data->two_wire_mode;
+ unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1;
+ unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2;
+ unsigned int val = 0;
+ unsigned int rate = dai->symmetric_rate;
+ int reg = get_chan_reg(dai->symmetric_channels);
+
+ if (reg < 0)
+ return -EINVAL;
+
+ dmic_data->dmic_channel = dai->symmetric_channels;
+
+ val |= DMIC_TOP_CON_SDM3_LEVEL_MODE;
+
+ if (two_wire_mode) {
+ val |= DMIC_TOP_CON_TWO_WIRE_MODE;
+ } else {
+ val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH1,
+ clk_phase_sel_ch1);
+ val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH2,
+ clk_phase_sel_ch2);
+ }
+
+ switch (rate) {
+ case 48000:
+ val |= DMIC_TOP_CON_VOICE_MODE_48K;
+ break;
+ case 32000:
+ val |= DMIC_TOP_CON_VOICE_MODE_32K;
+ break;
+ case 16000:
+ val |= DMIC_TOP_CON_VOICE_MODE_16K;
+ break;
+ case 8000:
+ val |= DMIC_TOP_CON_VOICE_MODE_8K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(afe->regmap, reg, DMIC_TOP_CON_CONFIG_MASK, val);
+
+ return 0;
+}
+
+static int mt8365_dai_dmic_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_afe_enable_main_clk(afe);
+
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);
+
+ audio_dmic_adda_enable(afe);
+
+ return 0;
+}
+
+static void mt8365_dai_dmic_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_dai_disable_dmic(afe, substream, dai);
+ audio_dmic_adda_disable(afe);
+ /* HW Request delay 125us before CG off */
+ usleep_range(125, 300);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_dmic_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mt8365_dai_configure_dmic(afe, substream, dai);
+ mt8365_dai_enable_dmic(afe, substream, dai);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_dmic_ops = {
+ .startup = mt8365_dai_dmic_startup,
+ .shutdown = mt8365_dai_dmic_shutdown,
+ .prepare = mt8365_dai_dmic_prepare,
+};
+
+static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {
+ {
+ .name = "DMIC",
+ .id = MT8365_AFE_IO_DMIC,
+ .capture = {
+ .stream_name = "DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_dmic_ops,
+ }
+};
+
+/* DAI Controls */
+
+/* Values for 48kHz mode */
+static const char * const iir_mode_src[] = {
+ "SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src);
+
+static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {
+ SOC_SINGLE("DMIC IIR Switch", AFE_DMIC0_UL_SRC_CON0, DMIC_TOP_CON_IIR_ON, 1, 0),
+ SOC_ENUM("DMIC IIR Mode", iir_mode),
+};
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {
+ SND_SOC_DAPM_INPUT("DMIC In"),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {
+ {"I14", NULL, "DMIC Capture"},
+ {"I15", NULL, "DMIC Capture"},
+ {"I16", NULL, "DMIC Capture"},
+ {"I17", NULL, "DMIC Capture"},
+ {"I18", NULL, "DMIC Capture"},
+ {"I19", NULL, "DMIC Capture"},
+ {"I20", NULL, "DMIC Capture"},
+ {"I21", NULL, "DMIC Capture"},
+ {"DMIC Capture", NULL, "DMIC In"},
+};
+
+static int init_dmic_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_dmic_data *dmic_priv;
+ struct device_node *np = afe->dev->of_node;
+ unsigned int temps[4];
+ int ret;
+
+ dmic_priv = devm_kzalloc(afe->dev, sizeof(*dmic_priv), GFP_KERNEL);
+ if (!dmic_priv)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "mediatek,dmic-mode",
+ &temps[0],
+ 1);
+ if (ret == 0)
+ dmic_priv->two_wire_mode = !!temps[0];
+
+ if (!dmic_priv->two_wire_mode) {
+ dmic_priv->clk_phase_sel_ch1 = 0;
+ dmic_priv->clk_phase_sel_ch2 = 4;
+ }
+
+ afe_priv->dai_priv[MT8365_AFE_IO_DMIC] = dmic_priv;
+ return 0;
+}
+
+int mt8365_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->controls = mtk_dai_dmic_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);
+ 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);
+ return init_dmic_priv_data(afe);
+}
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
new file mode 100644
index 000000000000..cb9beb172ed5
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek 8365 ALSA SoC Audio DAI I2S Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+#define IIR_RATIOVER 9
+#define IIR_INV_COEF 10
+#define IIR_NO_NEED 11
+
+struct mtk_afe_i2s_priv {
+ bool adda_link;
+ int i2s_out_on_ref_cnt;
+ int id;
+ int low_jitter_en;
+ int mclk_id;
+ int share_i2s_id;
+ unsigned int clk_id_in;
+ unsigned int clk_id_in_m_sel;
+ unsigned int clk_id_out;
+ unsigned int clk_id_out_m_sel;
+ unsigned int clk_in_mult;
+ unsigned int clk_out_mult;
+ unsigned int config_val_in;
+ unsigned int config_val_out;
+ unsigned int dynamic_bck;
+ unsigned int reg_off_in;
+ unsigned int reg_off_out;
+};
+
+/* This enum is merely for mtk_afe_i2s_priv declare */
+enum {
+ DAI_I2S0 = 0,
+ DAI_I2S3,
+ DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8365_i2s_priv[DAI_I2S_NUM] = {
+ [DAI_I2S0] = {
+ .id = MT8365_AFE_IO_I2S,
+ .mclk_id = MT8365_I2S0_MCK,
+ .share_i2s_id = -1,
+ .clk_id_in = MT8365_CLK_AUD_I2S2_M,
+ .clk_id_out = MT8365_CLK_AUD_I2S1_M,
+ .clk_id_in_m_sel = MT8365_CLK_I2S2_M_SEL,
+ .clk_id_out_m_sel = MT8365_CLK_I2S1_M_SEL,
+ .clk_in_mult = 256,
+ .clk_out_mult = 256,
+ .adda_link = true,
+ .config_val_out = AFE_I2S_CON1_I2S2_TO_PAD,
+ .reg_off_in = AFE_I2S_CON2,
+ .reg_off_out = AFE_I2S_CON1,
+ },
+ [DAI_I2S3] = {
+ .id = MT8365_AFE_IO_2ND_I2S,
+ .mclk_id = MT8365_I2S3_MCK,
+ .share_i2s_id = -1,
+ .clk_id_in = MT8365_CLK_AUD_I2S0_M,
+ .clk_id_out = MT8365_CLK_AUD_I2S3_M,
+ .clk_id_in_m_sel = MT8365_CLK_I2S0_M_SEL,
+ .clk_id_out_m_sel = MT8365_CLK_I2S3_M_SEL,
+ .clk_in_mult = 256,
+ .clk_out_mult = 256,
+ .adda_link = false,
+ .config_val_in = AFE_I2S_CON_FROM_IO_MUX,
+ .reg_off_in = AFE_I2S_CON,
+ .reg_off_out = AFE_I2S_CON3,
+ },
+};
+
+static const u32 *get_iir_coef(unsigned int input_fs,
+ unsigned int output_fs, unsigned int *count)
+{
+ static const u32 IIR_COEF_48_TO_44p1[30] = {
+ 0x061fb0, 0x0bd256, 0x061fb0, 0xe3a3e6, 0xf0a300, 0x000003,
+ 0x0e416d, 0x1bb577, 0x0e416d, 0xe59178, 0xf23637, 0x000003,
+ 0x0c7d72, 0x189060, 0x0c7d72, 0xe96f09, 0xf505b2, 0x000003,
+ 0x126054, 0x249143, 0x126054, 0xe1fc0c, 0xf4b20a, 0x000002,
+ 0x000000, 0x323c85, 0x323c85, 0xf76d4e, 0x000000, 0x000002,
+ };
+
+ static const u32 IIR_COEF_44p1_TO_32[42] = {
+ 0x0a6074, 0x0d237a, 0x0a6074, 0xdd8d6c, 0xe0b3f6, 0x000002,
+ 0x0e41f8, 0x128d48, 0x0e41f8, 0xefc14e, 0xf12d7a, 0x000003,
+ 0x0cfa60, 0x11e89c, 0x0cfa60, 0xf1b09e, 0xf27205, 0x000003,
+ 0x15b69c, 0x20e7e4, 0x15b69c, 0xea799a, 0xe9314a, 0x000002,
+ 0x0f79e2, 0x1a7064, 0x0f79e2, 0xf65e4a, 0xf03d8e, 0x000002,
+ 0x10c34f, 0x1ffe4b, 0x10c34f, 0x0bbecb, 0xf2bc4b, 0x000001,
+ 0x000000, 0x23b063, 0x23b063, 0x07335f, 0x000000, 0x000002,
+ };
+
+ static const u32 IIR_COEF_48_TO_32[42] = {
+ 0x0a2a9b, 0x0a2f05, 0x0a2a9b, 0xe73873, 0xe0c525, 0x000002,
+ 0x0dd4ad, 0x0e765a, 0x0dd4ad, 0xf49808, 0xf14844, 0x000003,
+ 0x18a8cd, 0x1c40d0, 0x18a8cd, 0xed2aab, 0xe542ec, 0x000002,
+ 0x13e044, 0x1a47c4, 0x13e044, 0xf44aed, 0xe9acc7, 0x000002,
+ 0x1abd9c, 0x2a5429, 0x1abd9c, 0xff3441, 0xe0fc5f, 0x000001,
+ 0x0d86db, 0x193e2e, 0x0d86db, 0x1a6f15, 0xf14507, 0x000001,
+ 0x000000, 0x1f820c, 0x1f820c, 0x0a1b1f, 0x000000, 0x000002,
+ };
+
+ static const u32 IIR_COEF_32_TO_16[48] = {
+ 0x122893, 0xffadd4, 0x122893, 0x0bc205, 0xc0ee1c, 0x000001,
+ 0x1bab8a, 0x00750d, 0x1bab8a, 0x06a983, 0xe18a5c, 0x000002,
+ 0x18f68e, 0x02706f, 0x18f68e, 0x0886a9, 0xe31bcb, 0x000002,
+ 0x149c05, 0x054487, 0x149c05, 0x0bec31, 0xe5973e, 0x000002,
+ 0x0ea303, 0x07f24a, 0x0ea303, 0x115ff9, 0xe967b6, 0x000002,
+ 0x0823fd, 0x085531, 0x0823fd, 0x18d5b4, 0xee8d21, 0x000002,
+ 0x06888e, 0x0acbbb, 0x06888e, 0x40b55c, 0xe76dce, 0x000001,
+ 0x000000, 0x2d31a9, 0x2d31a9, 0x23ba4f, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_96_TO_44p1[48] = {
+ 0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002,
+ 0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002,
+ 0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002,
+ 0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002,
+ 0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002,
+ 0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002,
+ 0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001,
+ 0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_44p1_TO_16[48] = {
+ 0x0998fb, 0xf7f925, 0x0998fb, 0x1e54a0, 0xe06605, 0x000002,
+ 0x0d828e, 0xf50f97, 0x0d828e, 0x0f41b5, 0xf0a999, 0x000003,
+ 0x17ebeb, 0xee30d8, 0x17ebeb, 0x1f48ca, 0xe2ae88, 0x000002,
+ 0x12fab5, 0xf46ddc, 0x12fab5, 0x20cc51, 0xe4d068, 0x000002,
+ 0x0c7ac6, 0xfbd00e, 0x0c7ac6, 0x2337da, 0xe8028c, 0x000002,
+ 0x060ddc, 0x015b3e, 0x060ddc, 0x266754, 0xec21b6, 0x000002,
+ 0x0407b5, 0x04f827, 0x0407b5, 0x52e3d0, 0xe0149f, 0x000001,
+ 0x000000, 0x1f9521, 0x1f9521, 0x2ac116, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_48_TO_16[48] = {
+ 0x0955ff, 0xf6544a, 0x0955ff, 0x2474e5, 0xe062e6, 0x000002,
+ 0x0d4180, 0xf297f4, 0x0d4180, 0x12415b, 0xf0a3b0, 0x000003,
+ 0x0ba079, 0xf4f0b0, 0x0ba079, 0x1285d3, 0xf1488b, 0x000003,
+ 0x12247c, 0xf1033c, 0x12247c, 0x2625be, 0xe48e0d, 0x000002,
+ 0x0b98e0, 0xf96d1a, 0x0b98e0, 0x27e79c, 0xe7798a, 0x000002,
+ 0x055e3b, 0xffed09, 0x055e3b, 0x2a2e2d, 0xeb2854, 0x000002,
+ 0x01a934, 0x01ca03, 0x01a934, 0x2c4fea, 0xee93ab, 0x000002,
+ 0x000000, 0x1c46c5, 0x1c46c5, 0x2d37dc, 0x000000, 0x000001,
+ };
+
+ static const u32 IIR_COEF_96_TO_16[48] = {
+ 0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002,
+ 0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003,
+ 0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003,
+ 0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003,
+ 0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002,
+ 0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002,
+ 0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002,
+ 0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001,
+ };
+
+ static const struct {
+ const u32 *coef;
+ unsigned int cnt;
+ } iir_coef_tbl_list[8] = {
+ /* 0: 0.9188 */
+ { IIR_COEF_48_TO_44p1, ARRAY_SIZE(IIR_COEF_48_TO_44p1) },
+ /* 1: 0.7256 */
+ { IIR_COEF_44p1_TO_32, ARRAY_SIZE(IIR_COEF_44p1_TO_32) },
+ /* 2: 0.6667 */
+ { IIR_COEF_48_TO_32, ARRAY_SIZE(IIR_COEF_48_TO_32) },
+ /* 3: 0.5 */
+ { IIR_COEF_32_TO_16, ARRAY_SIZE(IIR_COEF_32_TO_16) },
+ /* 4: 0.4594 */
+ { IIR_COEF_96_TO_44p1, ARRAY_SIZE(IIR_COEF_96_TO_44p1) },
+ /* 5: 0.3628 */
+ { IIR_COEF_44p1_TO_16, ARRAY_SIZE(IIR_COEF_44p1_TO_16) },
+ /* 6: 0.3333 */
+ { IIR_COEF_48_TO_16, ARRAY_SIZE(IIR_COEF_48_TO_16) },
+ /* 7: 0.1667 */
+ { IIR_COEF_96_TO_16, ARRAY_SIZE(IIR_COEF_96_TO_16) },
+ };
+
+ static const u32 freq_new_index[16] = {
+ 0, 1, 2, 99, 3, 4, 5, 99, 6, 7, 8, 9, 10, 11, 12, 99
+ };
+
+ static const u32 iir_coef_tbl_matrix[13][13] = {
+ {/*0*/
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*1*/
+ 1, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*2*/
+ 2, 0, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*3*/
+ 3, IIR_INV_COEF, IIR_INV_COEF, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*4*/
+ 5, 3, IIR_INV_COEF, 2, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*5*/
+ 6, 4, 3, 2, 0, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*6*/
+ IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, 3, IIR_INV_COEF,
+ IIR_INV_COEF, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*7*/
+ IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, 5, 3,
+ IIR_INV_COEF, 1, IIR_NO_NEED, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*8*/
+ 7, IIR_INV_COEF, IIR_INV_COEF, 6, 4, 3, 2, 0, IIR_NO_NEED,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*9*/
+ IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF,
+ IIR_INV_COEF, IIR_INV_COEF, 5, 3, IIR_INV_COEF,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*10*/
+ IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, 7, IIR_INV_COEF,
+ IIR_INV_COEF, 6, 4, 3, 0,
+ IIR_NO_NEED, IIR_NO_NEED, IIR_NO_NEED
+ },
+ { /*11*/
+ IIR_RATIOVER, IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF,
+ IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF, IIR_INV_COEF,
+ IIR_INV_COEF, 3, IIR_INV_COEF, IIR_NO_NEED, IIR_NO_NEED
+ },
+ {/*12*/
+ IIR_RATIOVER, IIR_RATIOVER, IIR_INV_COEF, IIR_INV_COEF,
+ IIR_INV_COEF, IIR_INV_COEF, 7, IIR_INV_COEF,
+ IIR_INV_COEF, 4, 3, 0, IIR_NO_NEED
+ },
+ };
+
+ const u32 *coef = NULL;
+ unsigned int cnt = 0;
+ u32 i = freq_new_index[input_fs];
+ u32 j = freq_new_index[output_fs];
+
+ if (i < 13 && j < 13) {
+ u32 k = iir_coef_tbl_matrix[i][j];
+
+ if (k >= IIR_NO_NEED) {
+ } else if (k == IIR_RATIOVER) {
+ } else if (k == IIR_INV_COEF) {
+ } else {
+ coef = iir_coef_tbl_list[k].coef;
+ cnt = iir_coef_tbl_list[k].cnt;
+ }
+ }
+ *count = cnt;
+ return coef;
+}
+
+static int mt8365_dai_set_config(struct mtk_base_afe *afe,
+ struct mtk_afe_i2s_priv *i2s_data,
+ bool is_input, unsigned int rate,
+ int bit_width)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be =
+ &afe_priv->be_data[i2s_data->id - MT8365_AFE_BACKEND_BASE];
+ unsigned int val, reg_off;
+ int fs = mt8365_afe_fs_timing(rate);
+
+ if (fs < 0)
+ return -EINVAL;
+
+ val = AFE_I2S_CON_LOW_JITTER_CLK | AFE_I2S_CON_FORMAT_I2S;
+ val |= FIELD_PREP(AFE_I2S_CON_RATE_MASK, fs);
+
+ if (is_input) {
+ reg_off = i2s_data->reg_off_in;
+ if (i2s_data->adda_link)
+ val |= i2s_data->config_val_in;
+ } else {
+ reg_off = i2s_data->reg_off_out;
+ val |= i2s_data->config_val_in;
+ }
+
+ /* 1:bck=32lrck(16bit) or bck=64lrck(32bit) 0:fix bck=64lrck */
+ if (i2s_data->dynamic_bck) {
+ if (bit_width > 16)
+ val |= AFE_I2S_CON_WLEN_32BIT;
+ else
+ val &= ~(u32)AFE_I2S_CON_WLEN_32BIT;
+ } else {
+ val |= AFE_I2S_CON_WLEN_32BIT;
+ }
+
+ if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
+ SND_SOC_DAIFMT_CBP_CFP) {
+ val |= AFE_I2S_CON_SRC_SLAVE;
+ val &= ~(u32)AFE_I2S_CON_FROM_IO_MUX;//from consys
+ }
+
+ regmap_update_bits(afe->regmap, reg_off, ~(u32)AFE_I2S_CON_EN, val);
+
+ if (i2s_data->adda_link && is_input)
+ regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1);
+
+ return 0;
+}
+
+int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe,
+ unsigned int rate, int bit_width)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data =
+ afe_priv->dai_priv[MT8365_AFE_IO_I2S];
+
+ return mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width);
+}
+
+static int mt8365_afe_set_2nd_i2s_asrc(struct mtk_base_afe *afe,
+ unsigned int rate_in,
+ unsigned int rate_out,
+ unsigned int width,
+ unsigned int mono,
+ int o16bit, int tracking)
+{
+ int ifs, ofs = 0;
+ unsigned int val = 0;
+ unsigned int mask = 0;
+ const u32 *coef;
+ u32 iir_stage;
+ unsigned int coef_count = 0;
+
+ ifs = mt8365_afe_fs_timing(rate_in);
+
+ if (ifs < 0)
+ return -EINVAL;
+
+ ofs = mt8365_afe_fs_timing(rate_out);
+
+ if (ofs < 0)
+ return -EINVAL;
+
+ val = FIELD_PREP(O16BIT, o16bit) | FIELD_PREP(IS_MONO, mono);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+ O16BIT | IS_MONO, val);
+
+ coef = get_iir_coef(ifs, ofs, &coef_count);
+ iir_stage = ((u32)coef_count / 6) - 1;
+
+ if (coef) {
+ unsigned int i;
+
+ /* CPU control IIR coeff SRAM */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ COEFF_SRAM_CTRL, COEFF_SRAM_CTRL);
+
+ /* set to 0, IIR coeff SRAM addr */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON13,
+ 0xffffffff, 0x0);
+
+ for (i = 0; i < coef_count; ++i)
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON12,
+ 0xffffffff, coef[i]);
+
+ /* disable IIR coeff SRAM access */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ COEFF_SRAM_CTRL,
+ ~COEFF_SRAM_CTRL);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+ CLR_IIR_HISTORY | IIR_EN | IIR_STAGE_MASK,
+ CLR_IIR_HISTORY | IIR_EN |
+ FIELD_PREP(IIR_STAGE_MASK, iir_stage));
+ } else {
+ /* disable IIR */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+ IIR_EN, ~IIR_EN);
+ }
+
+ /* CON3 setting (RX OFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON3,
+ 0x00FFFFFF, rx_frequency_palette(ofs));
+ /* CON4 setting (RX IFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON4,
+ 0x00FFFFFF, rx_frequency_palette(ifs));
+
+ /* CON5 setting */
+ if (tracking) {
+ val = CALI_64_CYCLE |
+ CALI_AUTORST |
+ AUTO_TUNE_FREQ5 |
+ COMP_FREQ_RES |
+ CALI_BP_DGL |
+ CALI_AUTO_RESTART |
+ CALI_USE_FREQ_OUT |
+ CALI_SEL_01;
+
+ mask = CALI_CYCLE_MASK |
+ CALI_AUTORST |
+ AUTO_TUNE_FREQ5 |
+ COMP_FREQ_RES |
+ CALI_SEL_MASK |
+ CALI_BP_DGL |
+ AUTO_TUNE_FREQ4 |
+ CALI_AUTO_RESTART |
+ CALI_USE_FREQ_OUT |
+ CALI_ON;
+
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ mask, val);
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ CALI_ON, CALI_ON);
+ } else {
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+ 0xffffffff, 0x0);
+ }
+ /* CON6 setting fix 8125 */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON6,
+ 0x0000ffff, 0x1FBD);
+ /* CON9 setting (RX IFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON9,
+ 0x000fffff, AutoRstThHi(ifs));
+ /* CON10 setting (RX IFS) */
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON10,
+ 0x000fffff, AutoRstThLo(ifs));
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ CHSET_STR_CLR, CHSET_STR_CLR);
+
+ return 0;
+}
+
+static int mt8365_afe_set_2nd_i2s_asrc_enable(struct mtk_base_afe *afe,
+ bool enable)
+{
+ if (enable)
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ ASM_ON, ASM_ON);
+ else
+ regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+ ASM_ON, ~ASM_ON);
+ return 0;
+}
+
+void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable)
+{
+ int i;
+ unsigned long flags;
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = NULL;
+
+ for (i = 0; i < DAI_I2S_NUM; i++) {
+ if (mt8365_i2s_priv[i].adda_link)
+ i2s_data = afe_priv->dai_priv[mt8365_i2s_priv[i].id];
+ }
+
+ if (!i2s_data)
+ return;
+
+ spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+ if (enable) {
+ i2s_data->i2s_out_on_ref_cnt++;
+ if (i2s_data->i2s_out_on_ref_cnt == 1)
+ regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+ 0x1, enable);
+ } else {
+ i2s_data->i2s_out_on_ref_cnt--;
+ if (i2s_data->i2s_out_on_ref_cnt == 0)
+ regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+ 0x1, enable);
+ else if (i2s_data->i2s_out_on_ref_cnt < 0)
+ i2s_data->i2s_out_on_ref_cnt = 0;
+ }
+
+ spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+}
+
+static void mt8365_dai_set_enable(struct mtk_base_afe *afe,
+ struct mtk_afe_i2s_priv *i2s_data,
+ bool is_input, bool enable)
+{
+ unsigned int reg_off;
+
+ if (is_input) {
+ reg_off = i2s_data->reg_off_in;
+ } else {
+ if (i2s_data->adda_link) {
+ mt8365_afe_set_i2s_out_enable(afe, enable);
+ return;
+ }
+ reg_off = i2s_data->reg_off_out;
+ }
+ regmap_update_bits(afe->regmap, reg_off,
+ 0x1, enable);
+}
+
+static int mt8365_dai_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ bool i2s_in_slave =
+ (substream->stream == SNDRV_PCM_STREAM_CAPTURE) &&
+ ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
+ SND_SOC_DAIFMT_CBP_CFP);
+
+ mt8365_afe_enable_main_clk(afe);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ clk_prepare_enable(afe_priv->clocks[i2s_data->clk_id_out]);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && !i2s_in_slave)
+ clk_prepare_enable(afe_priv->clocks[i2s_data->clk_id_in]);
+
+ if (i2s_in_slave)
+ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_I2S_IN);
+
+ return 0;
+}
+
+static void mt8365_dai_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ bool reset_i2s_out_change = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ bool reset_i2s_in_change = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+ bool i2s_in_slave =
+ (substream->stream == SNDRV_PCM_STREAM_CAPTURE) &&
+ ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
+ SND_SOC_DAIFMT_CBP_CFP);
+
+ if (be->prepared[substream->stream]) {
+ if (reset_i2s_out_change)
+ mt8365_dai_set_enable(afe, i2s_data, false, false);
+
+ if (reset_i2s_in_change)
+ mt8365_dai_set_enable(afe, i2s_data, true, false);
+
+ if (substream->runtime->rate % 8000)
+ mt8365_afe_disable_apll_associated_cfg(afe, MT8365_AFE_APLL1);
+ else
+ mt8365_afe_disable_apll_associated_cfg(afe, MT8365_AFE_APLL2);
+
+ if (reset_i2s_out_change)
+ be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = false;
+
+ if (reset_i2s_in_change)
+ be->prepared[SNDRV_PCM_STREAM_CAPTURE] = false;
+ }
+
+ if (reset_i2s_out_change)
+ mt8365_afe_disable_clk(afe,
+ afe_priv->clocks[i2s_data->clk_id_out]);
+
+ if (reset_i2s_in_change && !i2s_in_slave)
+ mt8365_afe_disable_clk(afe,
+ afe_priv->clocks[i2s_data->clk_id_in]);
+
+ if (i2s_in_slave)
+ mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_I2S_IN);
+
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+ struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+ bool apply_i2s_out_change = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ bool apply_i2s_in_change = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+ unsigned int rate = substream->runtime->rate;
+ int bit_width = snd_pcm_format_width(substream->runtime->format);
+ int ret;
+
+ if (be->prepared[substream->stream]) {
+ dev_info(afe->dev, "%s '%s' prepared already\n",
+ __func__, snd_pcm_stream_str(substream));
+ return 0;
+ }
+
+ if (apply_i2s_out_change) {
+ ret = mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width);
+ if (ret)
+ return ret;
+ }
+
+ if (apply_i2s_in_change) {
+ if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBP_CFP) {
+ ret = mt8365_afe_set_2nd_i2s_asrc(afe, 32000, rate,
+ (unsigned int)bit_width,
+ 0, 0, 1);
+ if (ret < 0)
+ return ret;
+ }
+ ret = mt8365_dai_set_config(afe, i2s_data, true, rate, bit_width);
+ if (ret)
+ return ret;
+ }
+
+ if (rate % 8000)
+ mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL1);
+ else
+ mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL2);
+
+ if (apply_i2s_out_change) {
+ mt8365_afe_set_clk_parent(afe,
+ afe_priv->clocks[i2s_data->clk_id_out_m_sel],
+ ((rate % 8000) ?
+ afe_priv->clocks[MT8365_CLK_AUD1] :
+ afe_priv->clocks[MT8365_CLK_AUD2]));
+
+ mt8365_afe_set_clk_rate(afe,
+ afe_priv->clocks[i2s_data->clk_id_out],
+ rate * i2s_data->clk_out_mult);
+
+ mt8365_dai_set_enable(afe, i2s_data, false, true);
+ be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = true;
+ }
+
+ if (apply_i2s_in_change) {
+ mt8365_afe_set_clk_parent(afe,
+ afe_priv->clocks[i2s_data->clk_id_in_m_sel],
+ ((rate % 8000) ?
+ afe_priv->clocks[MT8365_CLK_AUD1] :
+ afe_priv->clocks[MT8365_CLK_AUD2]));
+
+ mt8365_afe_set_clk_rate(afe,
+ afe_priv->clocks[i2s_data->clk_id_in],
+ rate * i2s_data->clk_in_mult);
+
+ mt8365_dai_set_enable(afe, i2s_data, true, true);
+
+ if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+ == SND_SOC_DAIFMT_CBP_CFP)
+ mt8365_afe_set_2nd_i2s_asrc_enable(afe, true);
+
+ be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true;
+ }
+ return 0;
+}
+
+static int mt8365_afe_2nd_i2s_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);
+ unsigned int width_val = params_width(params) > 16 ?
+ (AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01) : 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+ AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01, width_val);
+
+ return 0;
+}
+
+static int mt8365_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+ be->fmt_mode = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ be->fmt_mode |= SND_SOC_DAIFMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ be->fmt_mode |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ default:
+ dev_err(afe->dev, "invalid audio format for 2nd i2s!\n");
+ return -EINVAL;
+ }
+
+ if (((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) &&
+ ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_IF) &&
+ ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_NF) &&
+ ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_IF)) {
+ dev_err(afe->dev, "invalid audio format for 2nd i2s!\n");
+ return -EINVAL;
+ }
+
+ be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK);
+
+ if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP))
+ be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_i2s_ops = {
+ .startup = mt8365_dai_i2s_startup,
+ .shutdown = mt8365_dai_i2s_shutdown,
+ .prepare = mt8365_dai_i2s_prepare,
+};
+
+static const struct snd_soc_dai_ops mt8365_afe_2nd_i2s_ops = {
+ .startup = mt8365_dai_i2s_startup,
+ .shutdown = mt8365_dai_i2s_shutdown,
+ .hw_params = mt8365_afe_2nd_i2s_hw_params,
+ .prepare = mt8365_dai_i2s_prepare,
+ .set_fmt = mt8365_afe_2nd_i2s_set_fmt,
+};
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+ {
+ .name = "I2S",
+ .id = MT8365_AFE_IO_I2S,
+ .playback = {
+ .stream_name = "I2S Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "I2S Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_i2s_ops,
+ }, {
+ .name = "2ND I2S",
+ .id = MT8365_AFE_IO_2ND_I2S,
+ .playback = {
+ .stream_name = "2ND I2S Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "2ND I2S Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_afe_2nd_i2s_ops,
+ }
+};
+
+static const char * const fmi2sin_text[] = {
+ "OPEN", "FM_2ND_I2S_IN"
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(fmi2sin_enum, fmi2sin_text);
+
+static const struct snd_kcontrol_new fmi2sin_mux =
+ SOC_DAPM_ENUM("FM 2ND I2S Source", fmi2sin_enum);
+
+static const struct snd_kcontrol_new i2s_o03_o04_enable_ctl =
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+ SND_SOC_DAPM_SWITCH("I2S O03_O04", SND_SOC_NOPM, 0, 0,
+ &i2s_o03_o04_enable_ctl),
+ SND_SOC_DAPM_MUX("FM 2ND I2S Mux", SND_SOC_NOPM, 0, 0, &fmi2sin_mux),
+ SND_SOC_DAPM_INPUT("2ND I2S In"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+ {"I2S O03_O04", "Switch", "O03"},
+ {"I2S O03_O04", "Switch", "O04"},
+ {"I2S Playback", NULL, "I2S O03_O04"},
+ {"2ND I2S Playback", NULL, "O00"},
+ {"2ND I2S Playback", NULL, "O01"},
+ {"2ND I2S Capture", NULL, "2ND I2S In"},
+ {"FM 2ND I2S Mux", "FM_2ND_I2S_IN", "2ND I2S Capture"},
+};
+
+static int mt8365_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+ int i, ret;
+
+ for (i = 0; i < DAI_I2S_NUM; i++) {
+ ret = mt8365_dai_set_priv(afe, mt8365_i2s_priv[i].id,
+ sizeof(mt8365_i2s_priv[i]),
+ &mt8365_i2s_priv[i]);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int mt8365_dai_i2s_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_i2s_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+ dai->dapm_widgets = mtk_dai_i2s_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+ dai->dapm_routes = mtk_dai_i2s_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+ /* set all dai i2s private data */
+ return mt8365_dai_i2s_set_priv(afe);
+}
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
new file mode 100644
index 000000000000..0ec114a566ad
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek 8365 ALSA SoC Audio DAI PCM Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mt8365_pcm_intf_data {
+ bool slave_mode;
+ bool lrck_inv;
+ bool bck_inv;
+ unsigned int format;
+};
+
+/* DAI Drivers */
+
+static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);
+}
+
+static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)
+{
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ PCM_INTF_CON1_EN, 0x0);
+}
+
+static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
+ bool slave_mode = pcm_priv->slave_mode;
+ bool lrck_inv = pcm_priv->lrck_inv;
+ bool bck_inv = pcm_priv->bck_inv;
+ unsigned int fmt = pcm_priv->format;
+ unsigned int bit_width = dai->symmetric_sample_bits;
+ unsigned int val = 0;
+
+ if (!slave_mode) {
+ val |= PCM_INTF_CON1_MASTER_MODE |
+ PCM_INTF_CON1_BYPASS_ASRC;
+
+ if (lrck_inv)
+ val |= PCM_INTF_CON1_SYNC_OUT_INV;
+ if (bck_inv)
+ val |= PCM_INTF_CON1_BCLK_OUT_INV;
+ } else {
+ val |= PCM_INTF_CON1_SLAVE_MODE;
+
+ if (lrck_inv)
+ val |= PCM_INTF_CON1_SYNC_IN_INV;
+ if (bck_inv)
+ val |= PCM_INTF_CON1_BCLK_IN_INV;
+
+ /* TODO: add asrc setting */
+ }
+
+ val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);
+
+ if (fmt == MT8365_PCM_FORMAT_PCMA ||
+ fmt == MT8365_PCM_FORMAT_PCMB)
+ val |= PCM_INTF_CON1_SYNC_LEN(1);
+ else
+ val |= PCM_INTF_CON1_SYNC_LEN(bit_width);
+
+ switch (substream->runtime->rate) {
+ case 48000:
+ val |= PCM_INTF_CON1_FS_48K;
+ break;
+ case 32000:
+ val |= PCM_INTF_CON1_FS_32K;
+ break;
+ case 16000:
+ val |= PCM_INTF_CON1_FS_16K;
+ break;
+ case 8000:
+ val |= PCM_INTF_CON1_FS_8K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (bit_width > 16)
+ val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;
+ else
+ val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;
+
+ val |= PCM_INTF_CON1_EXT_MODEM;
+
+ regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+ PCM_INTF_CON1_CONFIG_MASK, val);
+
+ return 0;
+}
+
+static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (snd_soc_dai_active(dai))
+ return 0;
+
+ mt8365_afe_enable_main_clk(afe);
+
+ return 0;
+}
+
+static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ if (snd_soc_dai_active(dai))
+ return;
+
+ mt8365_dai_disable_pcm1(afe);
+ mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ if ((snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) +
+ snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) > 1) {
+ dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",
+ __func__, snd_pcm_stream_str(substream),
+ snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK),
+ snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE));
+ return 0;
+ }
+
+ ret = mt8365_dai_configure_pcm1(substream, dai);
+ if (ret)
+ return ret;
+
+ mt8365_dai_enable_pcm1(afe);
+
+ return 0;
+}
+
+static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ pcm_priv->format = MT8365_PCM_FORMAT_I2S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ pcm_priv->bck_inv = false;
+ pcm_priv->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ pcm_priv->bck_inv = false;
+ pcm_priv->lrck_inv = true;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ pcm_priv->bck_inv = true;
+ pcm_priv->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ pcm_priv->bck_inv = true;
+ pcm_priv->lrck_inv = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBP_CFP:
+ pcm_priv->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ pcm_priv->slave_mode = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {
+ .startup = mt8365_dai_pcm1_startup,
+ .shutdown = mt8365_dai_pcm1_shutdown,
+ .prepare = mt8365_dai_pcm1_prepare,
+ .set_fmt = mt8365_dai_pcm1_set_fmt,
+};
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+ {
+ .name = "PCM1",
+ .id = MT8365_AFE_IO_PCM1,
+ .playback = {
+ .stream_name = "PCM1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "PCM1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &mt8365_dai_pcm1_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ }
+};
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("PCM1 Out"),
+ SND_SOC_DAPM_INPUT("PCM1 In"),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+ {"PCM1 Playback", NULL, "O07"},
+ {"PCM1 Playback", NULL, "O08"},
+ {"PCM1 Out", NULL, "PCM1 Playback"},
+
+ {"I09", NULL, "PCM1 Capture"},
+ {"I22", NULL, "PCM1 Capture"},
+ {"PCM1 Capture", NULL, "PCM1 In"},
+};
+
+static int init_pcmif_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8365_afe_private *afe_priv = afe->platform_priv;
+ struct mt8365_pcm_intf_data *pcmif_priv;
+
+ pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),
+ GFP_KERNEL);
+ if (!pcmif_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;
+ return 0;
+}
+
+int mt8365_dai_pcm_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_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+ return init_pcmif_priv_data(afe);
+}
diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
new file mode 100644
index 000000000000..a998fba82bfe
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek MT8365 Sound Card driver
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * 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/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 "../common/mtk-soc-card.h"
+#include "../common/mtk-soundcard-driver.h"
+
+enum pinctrl_pin_state {
+ PIN_STATE_DEFAULT,
+ PIN_STATE_DMIC,
+ PIN_STATE_MISO_OFF,
+ PIN_STATE_MISO_ON,
+ PIN_STATE_MOSI_OFF,
+ PIN_STATE_MOSI_ON,
+ PIN_STATE_MAX
+};
+
+static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = {
+ "default",
+ "dmic",
+ "miso_off",
+ "miso_on",
+ "mosi_off",
+ "mosi_on",
+};
+
+struct mt8365_mt6357_priv {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pin_states[PIN_STATE_MAX];
+};
+
+enum {
+ /* FE */
+ DAI_LINK_DL1_PLAYBACK = 0,
+ DAI_LINK_DL2_PLAYBACK,
+ DAI_LINK_AWB_CAPTURE,
+ DAI_LINK_VUL_CAPTURE,
+ /* BE */
+ DAI_LINK_2ND_I2S_INTF,
+ DAI_LINK_DMIC,
+ DAI_LINK_INT_ADDA,
+ DAI_LINK_NUM
+};
+
+static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HDMI Out"),
+};
+
+static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {
+ {"HDMI Out", NULL, "2ND I2S Playback"},
+ {"DMIC In", NULL, "MICBIAS0"},
+};
+
+static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON]))
+ return ret;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MOSI_ON]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON]))
+ return ret;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MISO_ON]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ return 0;
+}
+
+static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF]))
+ return;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MOSI_OFF]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF]))
+ return;
+
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[PIN_STATE_MISO_OFF]);
+ if (ret)
+ dev_err(rtd->card->dev, "%s failed to select state %d\n",
+ __func__, ret);
+ }
+}
+
+static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = {
+ .startup = mt8365_mt6357_int_adda_startup,
+ .shutdown = mt8365_mt6357_int_adda_shutdown,
+};
+
+SND_SOC_DAILINK_DEFS(playback1,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(playback2,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(awb_capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("AWB")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(vul,
+ DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3,
+ DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(dmic,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(primary_codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
+ /* Front End DAI links */
+ [DAI_LINK_DL1_PLAYBACK] = {
+ .name = "DL1_FE",
+ .stream_name = "MultiMedia1_PLayback",
+ .id = DAI_LINK_DL1_PLAYBACK,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .playback_only = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(playback1),
+ },
+ [DAI_LINK_DL2_PLAYBACK] = {
+ .name = "DL2_FE",
+ .stream_name = "MultiMedia2_PLayback",
+ .id = DAI_LINK_DL2_PLAYBACK,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .playback_only = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(playback2),
+ },
+ [DAI_LINK_AWB_CAPTURE] = {
+ .name = "AWB_FE",
+ .stream_name = "DL1_AWB_Record",
+ .id = DAI_LINK_AWB_CAPTURE,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .capture_only = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(awb_capture),
+ },
+ [DAI_LINK_VUL_CAPTURE] = {
+ .name = "VUL_FE",
+ .stream_name = "MultiMedia1_Capture",
+ .id = DAI_LINK_VUL_CAPTURE,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST
+ },
+ .dynamic = 1,
+ .capture_only = 1,
+ .dpcm_merged_rate = 1,
+ SND_SOC_DAILINK_REG(vul),
+ },
+ /* Back End DAI links */
+ [DAI_LINK_2ND_I2S_INTF] = {
+ .name = "I2S_OUT_BE",
+ .no_pcm = 1,
+ .id = DAI_LINK_2ND_I2S_INTF,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC,
+ SND_SOC_DAILINK_REG(i2s3),
+ },
+ [DAI_LINK_DMIC] = {
+ .name = "DMIC_BE",
+ .no_pcm = 1,
+ .id = DAI_LINK_DMIC,
+ .capture_only = 1,
+ SND_SOC_DAILINK_REG(dmic),
+ },
+ [DAI_LINK_INT_ADDA] = {
+ .name = "MTK_Codec",
+ .no_pcm = 1,
+ .id = DAI_LINK_INT_ADDA,
+ .ops = &mt8365_mt6357_int_adda_ops,
+ SND_SOC_DAILINK_REG(primary_codec),
+ },
+};
+
+static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)
+{
+ struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);
+ int ret, i;
+
+ priv->pinctrl = devm_pinctrl_get(card->dev);
+ if (IS_ERR(priv->pinctrl)) {
+ ret = PTR_ERR(priv->pinctrl);
+ return dev_err_probe(card->dev, ret,
+ "Failed to get pinctrl\n");
+ }
+
+ for (i = PIN_STATE_DEFAULT ; i < PIN_STATE_MAX ; i++) {
+ priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl,
+ mt8365_mt6357_pin_str[i]);
+ if (IS_ERR(priv->pin_states[i])) {
+ dev_info(card->dev, "No pin state for %s\n",
+ mt8365_mt6357_pin_str[i]);
+ } else {
+ ret = pinctrl_select_state(priv->pinctrl,
+ priv->pin_states[i]);
+ if (ret) {
+ dev_err_probe(card->dev, ret,
+ "Failed to select pin state %s\n",
+ mt8365_mt6357_pin_str[i]);
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+static struct snd_soc_card mt8365_mt6357_soc_card = {
+ .name = "mt8365-evk",
+ .owner = THIS_MODULE,
+ .dai_link = mt8365_mt6357_dais,
+ .num_links = ARRAY_SIZE(mt8365_mt6357_dais),
+ .dapm_widgets = mt8365_mt6357_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets),
+ .dapm_routes = mt8365_mt6357_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes),
+};
+
+static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+ struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+ struct snd_soc_card *card = card_data->card;
+ struct device *dev = card->dev;
+ struct mt8365_mt6357_priv *mach_priv;
+ int ret;
+
+ card->dev = dev;
+ ret = parse_dai_link_info(card);
+ if (ret)
+ goto err;
+
+ mach_priv = devm_kzalloc(dev, sizeof(*mach_priv),
+ GFP_KERNEL);
+ if (!mach_priv)
+ return -ENOMEM;
+ soc_card_data->mach_priv = mach_priv;
+ snd_soc_card_set_drvdata(card, soc_card_data);
+ mt8365_mt6357_gpio_probe(card);
+ return 0;
+
+err:
+ clean_card_reference(card);
+ return ret;
+}
+
+static const struct mtk_soundcard_pdata mt8365_mt6357_card = {
+ .card_name = "mt8365-mt6357",
+ .card_data = &(struct mtk_platform_card_data) {
+ .card = &mt8365_mt6357_soc_card,
+ },
+ .soc_probe = mt8365_mt6357_dev_probe
+};
+
+static const struct of_device_id mt8365_mt6357_dt_match[] = {
+ { .compatible = "mediatek,mt8365-mt6357", .data = &mt8365_mt6357_card },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match);
+
+static struct platform_driver mt8365_mt6357_driver = {
+ .driver = {
+ .name = "mt8365_mt6357",
+ .of_match_table = mt8365_mt6357_dt_match,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = mtk_soundcard_common_probe,
+};
+
+module_platform_driver(mt8365_mt6357_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8365 EVK SoC machine driver");
+MODULE_AUTHOR("Nicolas Belin <nbelin@baylibre.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform: mt8365_mt6357");
diff --git a/sound/soc/mediatek/mt8365/mt8365-reg.h b/sound/soc/mediatek/mt8365/mt8365-reg.h
new file mode 100644
index 000000000000..4ebbb94ff02e
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-reg.h
@@ -0,0 +1,993 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * MediaTek 8365 audio driver reg definition
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ * Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#ifndef _MT8365_REG_H_
+#define _MT8365_REG_H_
+
+#include <linux/bitfield.h>
+
+#define AUDIO_TOP_CON0 (0x0000)
+#define AUDIO_TOP_CON1 (0x0004)
+#define AUDIO_TOP_CON2 (0x0008)
+#define AUDIO_TOP_CON3 (0x000c)
+
+#define AFE_DAC_CON0 (0x0010)
+#define AFE_DAC_CON1 (0x0014)
+#define AFE_I2S_CON (0x0018)
+#define AFE_CONN0 (0x0020)
+#define AFE_CONN1 (0x0024)
+#define AFE_CONN2 (0x0028)
+#define AFE_CONN3 (0x002c)
+#define AFE_CONN4 (0x0030)
+#define AFE_I2S_CON1 (0x0034)
+#define AFE_I2S_CON2 (0x0038)
+#define AFE_MRGIF_CON (0x003c)
+#define AFE_DL1_BASE (0x0040)
+#define AFE_DL1_CUR (0x0044)
+#define AFE_DL1_END (0x0048)
+#define AFE_I2S_CON3 (0x004c)
+#define AFE_DL2_BASE (0x0050)
+#define AFE_DL2_CUR (0x0054)
+#define AFE_DL2_END (0x0058)
+#define AFE_CONN5 (0x005c)
+#define AFE_AWB_BASE (0x0070)
+#define AFE_AWB_END (0x0078)
+#define AFE_AWB_CUR (0x007c)
+#define AFE_VUL_BASE (0x0080)
+#define AFE_VUL_END (0x0088)
+#define AFE_VUL_CUR (0x008c)
+#define AFE_CONN6 (0x00bc)
+#define AFE_MEMIF_MSB (0x00cc)
+#define AFE_MEMIF_MON0 (0x00d0)
+#define AFE_MEMIF_MON1 (0x00d4)
+#define AFE_MEMIF_MON2 (0x00d8)
+#define AFE_MEMIF_MON3 (0x00dc)
+#define AFE_MEMIF_MON4 (0x00e0)
+#define AFE_MEMIF_MON5 (0x00e4)
+#define AFE_MEMIF_MON6 (0x00e8)
+#define AFE_MEMIF_MON7 (0x00ec)
+#define AFE_MEMIF_MON8 (0x00f0)
+#define AFE_MEMIF_MON9 (0x00f4)
+#define AFE_MEMIF_MON10 (0x00f8)
+#define AFE_MEMIF_MON11 (0x00fc)
+#define AFE_ADDA_DL_SRC2_CON0 (0x0108)
+#define AFE_ADDA_DL_SRC2_CON1 (0x010c)
+#define AFE_ADDA_UL_SRC_CON0 (0x0114)
+#define AFE_ADDA_UL_SRC_CON1 (0x0118)
+#define AFE_ADDA_TOP_CON0 (0x0120)
+#define AFE_ADDA_UL_DL_CON0 (0x0124)
+#define AFE_ADDA_SRC_DEBUG (0x012c)
+#define AFE_ADDA_SRC_DEBUG_MON0 (0x0130)
+#define AFE_ADDA_SRC_DEBUG_MON1 (0x0134)
+#define AFE_ADDA_UL_SRC_MON0 (0x0148)
+#define AFE_ADDA_UL_SRC_MON1 (0x014c)
+#define AFE_SRAM_BOUND (0x0170)
+#define AFE_SECURE_CON (0x0174)
+#define AFE_SECURE_CONN0 (0x0178)
+#define AFE_SIDETONE_DEBUG (0x01d0)
+#define AFE_SIDETONE_MON (0x01d4)
+#define AFE_SIDETONE_CON0 (0x01e0)
+#define AFE_SIDETONE_COEFF (0x01e4)
+#define AFE_SIDETONE_CON1 (0x01e8)
+#define AFE_SIDETONE_GAIN (0x01ec)
+#define AFE_SGEN_CON0 (0x01f0)
+#define AFE_SINEGEN_CON_TDM (0x01f8)
+#define AFE_SINEGEN_CON_TDM_IN (0x01fc)
+#define AFE_TOP_CON0 (0x0200)
+#define AFE_BUS_CFG (0x0240)
+#define AFE_BUS_MON0 (0x0244)
+#define AFE_ADDA_PREDIS_CON0 (0x0260)
+#define AFE_ADDA_PREDIS_CON1 (0x0264)
+#define AFE_CONN_MON0 (0x0280)
+#define AFE_CONN_MON1 (0x0284)
+#define AFE_CONN_MON2 (0x0288)
+#define AFE_CONN_MON3 (0x028c)
+#define AFE_ADDA_IIR_COEF_02_01 (0x0290)
+#define AFE_ADDA_IIR_COEF_04_03 (0x0294)
+#define AFE_ADDA_IIR_COEF_06_05 (0x0298)
+#define AFE_ADDA_IIR_COEF_08_07 (0x029c)
+#define AFE_ADDA_IIR_COEF_10_09 (0x02a0)
+#define AFE_VUL_D2_BASE (0x0350)
+#define AFE_VUL_D2_END (0x0358)
+#define AFE_VUL_D2_CUR (0x035c)
+#define AFE_HDMI_OUT_CON0 (0x0370)
+#define AFE_HDMI_OUT_BASE (0x0374)
+#define AFE_HDMI_OUT_CUR (0x0378)
+#define AFE_HDMI_OUT_END (0x037c)
+#define AFE_SPDIF_OUT_CON0 (0x0380)
+#define AFE_SPDIF_OUT_BASE (0x0384)
+#define AFE_SPDIF_OUT_CUR (0x0388)
+#define AFE_SPDIF_OUT_END (0x038c)
+#define AFE_HDMI_CONN0 (0x0390)
+#define AFE_HDMI_CONN1 (0x0398)
+#define AFE_CONN_TDMIN_CON (0x039c)
+#define AFE_IRQ_MCU_CON (0x03a0)
+#define AFE_IRQ_MCU_STATUS (0x03a4)
+#define AFE_IRQ_MCU_CLR (0x03a8)
+#define AFE_IRQ_MCU_CNT1 (0x03ac)
+#define AFE_IRQ_MCU_CNT2 (0x03b0)
+#define AFE_IRQ_MCU_EN (0x03b4)
+#define AFE_IRQ_MCU_MON2 (0x03b8)
+#define AFE_IRQ_MCU_CNT5 (0x03bc)
+#define AFE_IRQ1_MCU_CNT_MON (0x03c0)
+#define AFE_IRQ2_MCU_CNT_MON (0x03c4)
+#define AFE_IRQ1_MCU_EN_CNT_MON (0x03c8)
+#define AFE_IRQ5_MCU_CNT_MON (0x03cc)
+#define AFE_MEMIF_MINLEN (0x03d0)
+#define AFE_MEMIF_MAXLEN (0x03d4)
+#define AFE_MEMIF_PBUF_SIZE (0x03d8)
+#define AFE_IRQ_MCU_CNT7 (0x03dc)
+#define AFE_IRQ7_MCU_CNT_MON (0x03e0)
+#define AFE_MEMIF_PBUF2_SIZE (0x03ec)
+#define AFE_APLL_TUNER_CFG (0x03f0)
+#define AFE_APLL_TUNER_CFG1 (0x03f4)
+#define AFE_IRQ_MCU_CON2 (0x03f8)
+#define IRQ13_MCU_CNT (0x0408)
+#define IRQ13_MCU_CNT_MON (0x040c)
+#define AFE_GAIN1_CON0 (0x0410)
+#define AFE_GAIN1_CON1 (0x0414)
+#define AFE_GAIN1_CON2 (0x0418)
+#define AFE_GAIN1_CON3 (0x041c)
+#define AFE_GAIN2_CON0 (0x0428)
+#define AFE_GAIN2_CON1 (0x042c)
+#define AFE_GAIN2_CON2 (0x0430)
+#define AFE_GAIN2_CON3 (0x0434)
+#define AFE_GAIN2_CUR (0x043c)
+#define AFE_CONN11 (0x0448)
+#define AFE_CONN12 (0x044c)
+#define AFE_CONN13 (0x0450)
+#define AFE_CONN14 (0x0454)
+#define AFE_CONN15 (0x0458)
+#define AFE_CONN16 (0x045c)
+#define AFE_CONN7 (0x0460)
+#define AFE_CONN8 (0x0464)
+#define AFE_CONN9 (0x0468)
+#define AFE_CONN10 (0x046c)
+#define AFE_CONN21 (0x0470)
+#define AFE_CONN22 (0x0474)
+#define AFE_CONN23 (0x0478)
+#define AFE_CONN24 (0x047c)
+#define AFE_IEC_CFG (0x0480)
+#define AFE_IEC_NSNUM (0x0484)
+#define AFE_IEC_BURST_INFO (0x0488)
+#define AFE_IEC_BURST_LEN (0x048c)
+#define AFE_IEC_NSADR (0x0490)
+#define AFE_CONN_RS (0x0494)
+#define AFE_CONN_DI (0x0498)
+#define AFE_IEC_CHL_STAT0 (0x04a0)
+#define AFE_IEC_CHL_STAT1 (0x04a4)
+#define AFE_IEC_CHR_STAT0 (0x04a8)
+#define AFE_IEC_CHR_STAT1 (0x04ac)
+#define AFE_CONN25 (0x04b0)
+#define AFE_CONN26 (0x04b4)
+#define FPGA_CFG2 (0x04b8)
+#define FPGA_CFG3 (0x04bc)
+#define FPGA_CFG0 (0x04c0)
+#define FPGA_CFG1 (0x04c4)
+#define AFE_SRAM_DELSEL_CON0 (0x04f0)
+#define AFE_SRAM_DELSEL_CON1 (0x04f4)
+#define AFE_SRAM_DELSEL_CON2 (0x04f8)
+#define FPGA_CFG4 (0x04fc)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON0 (0x0500)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON1 (0x0504)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON2 (0x0508)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON3 (0x050c)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON4 (0x0510)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON5 (0x0514)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON6 (0x0518)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON7 (0x051c)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON8 (0x0520)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON9 (0x0524)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON10 (0x0528)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON12 (0x0530)
+#define AFE_TDM_GASRC4_ASRC_2CH_CON13 (0x0534)
+#define PCM_INTF_CON2 (0x0538)
+#define PCM2_INTF_CON (0x053c)
+#define AFE_APB_MON (0x0540)
+#define AFE_CONN34 (0x0544)
+#define AFE_TDM_CON1 (0x0548)
+#define AFE_TDM_CON2 (0x054c)
+#define PCM_INTF_CON1 (0x0550)
+#define AFE_SECURE_MASK_CONN47_1 (0x0554)
+#define AFE_SECURE_MASK_CONN48_1 (0x0558)
+#define AFE_SECURE_MASK_CONN49_1 (0x055c)
+#define AFE_SECURE_MASK_CONN50_1 (0x0560)
+#define AFE_SECURE_MASK_CONN51_1 (0x0564)
+#define AFE_SECURE_MASK_CONN52_1 (0x0568)
+#define AFE_SECURE_MASK_CONN53_1 (0x056c)
+#define AFE_SE_SECURE_CON (0x0570)
+#define AFE_TDM_IN_CON1 (0x0588)
+#define AFE_TDM_IN_CON2 (0x058c)
+#define AFE_TDM_IN_MON1 (0x0590)
+#define AFE_TDM_IN_MON2 (0x0594)
+#define AFE_TDM_IN_MON3 (0x0598)
+#define AFE_DMIC0_UL_SRC_CON0 (0x05b4)
+#define AFE_DMIC0_UL_SRC_CON1 (0x05b8)
+#define AFE_DMIC0_SRC_DEBUG (0x05bc)
+#define AFE_DMIC0_SRC_DEBUG_MON0 (0x05c0)
+#define AFE_DMIC0_UL_SRC_MON0 (0x05c8)
+#define AFE_DMIC0_UL_SRC_MON1 (0x05cc)
+#define AFE_DMIC0_IIR_COEF_02_01 (0x05d0)
+#define AFE_DMIC0_IIR_COEF_04_03 (0x05d4)
+#define AFE_DMIC0_IIR_COEF_06_05 (0x05d8)
+#define AFE_DMIC0_IIR_COEF_08_07 (0x05dc)
+#define AFE_DMIC0_IIR_COEF_10_09 (0x05e0)
+#define AFE_DMIC1_UL_SRC_CON0 (0x0620)
+#define AFE_DMIC1_UL_SRC_CON1 (0x0624)
+#define AFE_DMIC1_SRC_DEBUG (0x0628)
+#define AFE_DMIC1_SRC_DEBUG_MON0 (0x062c)
+#define AFE_DMIC1_UL_SRC_MON0 (0x0634)
+#define AFE_DMIC1_UL_SRC_MON1 (0x0638)
+#define AFE_DMIC1_IIR_COEF_02_01 (0x063c)
+#define AFE_DMIC1_IIR_COEF_04_03 (0x0640)
+#define AFE_DMIC1_IIR_COEF_06_05 (0x0644)
+#define AFE_DMIC1_IIR_COEF_08_07 (0x0648)
+#define AFE_DMIC1_IIR_COEF_10_09 (0x064c)
+#define AFE_SECURE_MASK_CONN39_1 (0x068c)
+#define AFE_SECURE_MASK_CONN40_1 (0x0690)
+#define AFE_SECURE_MASK_CONN41_1 (0x0694)
+#define AFE_SECURE_MASK_CONN42_1 (0x0698)
+#define AFE_SECURE_MASK_CONN43_1 (0x069c)
+#define AFE_SECURE_MASK_CONN44_1 (0x06a0)
+#define AFE_SECURE_MASK_CONN45_1 (0x06a4)
+#define AFE_SECURE_MASK_CONN46_1 (0x06a8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON0 (0x06c0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON1 (0x06c4)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON2 (0x06c8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON3 (0x06cc)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON4 (0x06d0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON5 (0x06d4)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON6 (0x06d8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON7 (0x06dc)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON8 (0x06e0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON9 (0x06e4)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON10 (0x06e8)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON12 (0x06f0)
+#define AFE_TDM_GASRC1_ASRC_2CH_CON13 (0x06f4)
+#define AFE_TDM_ASRC_CON0 (0x06f8)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON0 (0x0700)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON1 (0x0704)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON2 (0x0708)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON3 (0x070c)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON4 (0x0710)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON5 (0x0714)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON6 (0x0718)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON7 (0x071c)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON8 (0x0720)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON9 (0x0724)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON10 (0x0728)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON12 (0x0730)
+#define AFE_TDM_GASRC2_ASRC_2CH_CON13 (0x0734)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON0 (0x0740)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON1 (0x0744)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON2 (0x0748)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON3 (0x074c)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON4 (0x0750)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON5 (0x0754)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON6 (0x0758)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON7 (0x075c)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON8 (0x0760)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON9 (0x0764)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON10 (0x0768)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON12 (0x0770)
+#define AFE_TDM_GASRC3_ASRC_2CH_CON13 (0x0774)
+#define AFE_DMIC2_UL_SRC_CON0 (0x0780)
+#define AFE_DMIC2_UL_SRC_CON1 (0x0784)
+#define AFE_DMIC2_SRC_DEBUG (0x0788)
+#define AFE_DMIC2_SRC_DEBUG_MON0 (0x078c)
+#define AFE_DMIC2_UL_SRC_MON0 (0x0794)
+#define AFE_DMIC2_UL_SRC_MON1 (0x0798)
+#define AFE_DMIC2_IIR_COEF_02_01 (0x079c)
+#define AFE_DMIC2_IIR_COEF_04_03 (0x07a0)
+#define AFE_DMIC2_IIR_COEF_06_05 (0x07a4)
+#define AFE_DMIC2_IIR_COEF_08_07 (0x07a8)
+#define AFE_DMIC2_IIR_COEF_10_09 (0x07ac)
+#define AFE_DMIC3_UL_SRC_CON0 (0x07ec)
+#define AFE_DMIC3_UL_SRC_CON1 (0x07f0)
+#define AFE_DMIC3_SRC_DEBUG (0x07f4)
+#define AFE_DMIC3_SRC_DEBUG_MON0 (0x07f8)
+#define AFE_DMIC3_UL_SRC_MON0 (0x0800)
+#define AFE_DMIC3_UL_SRC_MON1 (0x0804)
+#define AFE_DMIC3_IIR_COEF_02_01 (0x0808)
+#define AFE_DMIC3_IIR_COEF_04_03 (0x080c)
+#define AFE_DMIC3_IIR_COEF_06_05 (0x0810)
+#define AFE_DMIC3_IIR_COEF_08_07 (0x0814)
+#define AFE_DMIC3_IIR_COEF_10_09 (0x0818)
+#define AFE_SECURE_MASK_CONN25_1 (0x0858)
+#define AFE_SECURE_MASK_CONN26_1 (0x085c)
+#define AFE_SECURE_MASK_CONN27_1 (0x0860)
+#define AFE_SECURE_MASK_CONN28_1 (0x0864)
+#define AFE_SECURE_MASK_CONN29_1 (0x0868)
+#define AFE_SECURE_MASK_CONN30_1 (0x086c)
+#define AFE_SECURE_MASK_CONN31_1 (0x0870)
+#define AFE_SECURE_MASK_CONN32_1 (0x0874)
+#define AFE_SECURE_MASK_CONN33_1 (0x0878)
+#define AFE_SECURE_MASK_CONN34_1 (0x087c)
+#define AFE_SECURE_MASK_CONN35_1 (0x0880)
+#define AFE_SECURE_MASK_CONN36_1 (0x0884)
+#define AFE_SECURE_MASK_CONN37_1 (0x0888)
+#define AFE_SECURE_MASK_CONN38_1 (0x088c)
+#define AFE_IRQ_MCU_SCP_EN (0x0890)
+#define AFE_IRQ_MCU_DSP_EN (0x0894)
+#define AFE_IRQ3_MCU_CNT_MON (0x0898)
+#define AFE_IRQ4_MCU_CNT_MON (0x089c)
+#define AFE_IRQ8_MCU_CNT_MON (0x08a0)
+#define AFE_IRQ_MCU_CNT3 (0x08a4)
+#define AFE_IRQ_MCU_CNT4 (0x08a8)
+#define AFE_IRQ_MCU_CNT8 (0x08ac)
+#define AFE_IRQ_MCU_CNT11 (0x08b0)
+#define AFE_IRQ_MCU_CNT12 (0x08b4)
+#define AFE_IRQ11_MCU_CNT_MON (0x08b8)
+#define AFE_IRQ12_MCU_CNT_MON (0x08bc)
+#define AFE_VUL3_BASE (0x08c0)
+#define AFE_VUL3_CUR (0x08c4)
+#define AFE_VUL3_END (0x08c8)
+#define AFE_VUL3_BASE_MSB (0x08d0)
+#define AFE_VUL3_END_MSB (0x08d4)
+#define AFE_IRQ10_MCU_CNT_MON (0x08d8)
+#define AFE_IRQ_MCU_CNT10 (0x08dc)
+#define AFE_IRQ_ACC1_CNT (0x08e0)
+#define AFE_IRQ_ACC2_CNT (0x08e4)
+#define AFE_IRQ_ACC1_CNT_MON1 (0x08e8)
+#define AFE_IRQ_ACC2_CNT_MON (0x08ec)
+#define AFE_TSF_CON (0x08f0)
+#define AFE_TSF_MON (0x08f4)
+#define AFE_IRQ_ACC1_CNT_MON2 (0x08f8)
+#define AFE_SPDIFIN_CFG0 (0x0900)
+#define AFE_SPDIFIN_CFG1 (0x0904)
+#define AFE_SPDIFIN_CHSTS1 (0x0908)
+#define AFE_SPDIFIN_CHSTS2 (0x090c)
+#define AFE_SPDIFIN_CHSTS3 (0x0910)
+#define AFE_SPDIFIN_CHSTS4 (0x0914)
+#define AFE_SPDIFIN_CHSTS5 (0x0918)
+#define AFE_SPDIFIN_CHSTS6 (0x091c)
+#define AFE_SPDIFIN_DEBUG1 (0x0920)
+#define AFE_SPDIFIN_DEBUG2 (0x0924)
+#define AFE_SPDIFIN_DEBUG3 (0x0928)
+#define AFE_SPDIFIN_DEBUG4 (0x092c)
+#define AFE_SPDIFIN_EC (0x0930)
+#define AFE_SPDIFIN_CKLOCK_CFG (0x0934)
+#define AFE_SPDIFIN_BR (0x093c)
+#define AFE_SPDIFIN_BR_DBG1 (0x0940)
+#define AFE_SPDIFIN_INT_EXT (0x0948)
+#define AFE_SPDIFIN_INT_EXT2 (0x094c)
+#define SPDIFIN_FREQ_INFO (0x0950)
+#define SPDIFIN_FREQ_INFO_2 (0x0954)
+#define SPDIFIN_FREQ_INFO_3 (0x0958)
+#define SPDIFIN_FREQ_STATUS (0x095c)
+#define SPDIFIN_USERCODE1 (0x0960)
+#define SPDIFIN_USERCODE2 (0x0964)
+#define SPDIFIN_USERCODE3 (0x0968)
+#define SPDIFIN_USERCODE4 (0x096c)
+#define SPDIFIN_USERCODE5 (0x0970)
+#define SPDIFIN_USERCODE6 (0x0974)
+#define SPDIFIN_USERCODE7 (0x0978)
+#define SPDIFIN_USERCODE8 (0x097c)
+#define SPDIFIN_USERCODE9 (0x0980)
+#define SPDIFIN_USERCODE10 (0x0984)
+#define SPDIFIN_USERCODE11 (0x0988)
+#define SPDIFIN_USERCODE12 (0x098c)
+#define SPDIFIN_MEMIF_CON0 (0x0990)
+#define SPDIFIN_BASE_ADR (0x0994)
+#define SPDIFIN_END_ADR (0x0998)
+#define SPDIFIN_APLL_TUNER_CFG (0x09a0)
+#define SPDIFIN_APLL_TUNER_CFG1 (0x09a4)
+#define SPDIFIN_APLL2_TUNER_CFG (0x09a8)
+#define SPDIFIN_APLL2_TUNER_CFG1 (0x09ac)
+#define SPDIFIN_TYPE_DET (0x09b0)
+#define MPHONE_MULTI_CON0 (0x09b4)
+#define SPDIFIN_CUR_ADR (0x09b8)
+#define AFE_SINEGEN_CON_SPDIFIN (0x09bc)
+#define AFE_HDMI_IN_2CH_CON0 (0x09c0)
+#define AFE_HDMI_IN_2CH_BASE (0x09c4)
+#define AFE_HDMI_IN_2CH_END (0x09c8)
+#define AFE_HDMI_IN_2CH_CUR (0x09cc)
+#define AFE_MEMIF_BUF_MON0 (0x09d0)
+#define AFE_MEMIF_BUF_MON1 (0x09d4)
+#define AFE_MEMIF_BUF_MON2 (0x09d8)
+#define AFE_MEMIF_BUF_MON3 (0x09dc)
+#define AFE_MEMIF_BUF_MON6 (0x09e8)
+#define AFE_MEMIF_BUF_MON7 (0x09ec)
+#define AFE_MEMIF_BUF_MON8 (0x09f0)
+#define AFE_MEMIF_BUF_MON10 (0x09f8)
+#define AFE_MEMIF_BUF_MON11 (0x09fc)
+#define SYSTOP_STC_CONFIG (0x0a00)
+#define AUDIO_STC_STATUS (0x0a04)
+#define SYSTOP_W_STC_H (0x0a08)
+#define SYSTOP_W_STC_L (0x0a0c)
+#define SYSTOP_R_STC_H (0x0a10)
+#define SYSTOP_R_STC_L (0x0a14)
+#define AUDIO_W_STC_H (0x0a18)
+#define AUDIO_W_STC_L (0x0a1c)
+#define AUDIO_R_STC_H (0x0a20)
+#define AUDIO_R_STC_L (0x0a24)
+#define SYSTOP_W_STC2_H (0x0a28)
+#define SYSTOP_W_STC2_L (0x0a2c)
+#define SYSTOP_R_STC2_H (0x0a30)
+#define SYSTOP_R_STC2_L (0x0a34)
+#define AUDIO_W_STC2_H (0x0a38)
+#define AUDIO_W_STC2_L (0x0a3c)
+#define AUDIO_R_STC2_H (0x0a40)
+#define AUDIO_R_STC2_L (0x0a44)
+
+#define AFE_CONN17 (0x0a48)
+#define AFE_CONN18 (0x0a4c)
+#define AFE_CONN19 (0x0a50)
+#define AFE_CONN20 (0x0a54)
+#define AFE_CONN27 (0x0a58)
+#define AFE_CONN28 (0x0a5c)
+#define AFE_CONN29 (0x0a60)
+#define AFE_CONN30 (0x0a64)
+#define AFE_CONN31 (0x0a68)
+#define AFE_CONN32 (0x0a6c)
+#define AFE_CONN33 (0x0a70)
+#define AFE_CONN35 (0x0a74)
+#define AFE_CONN36 (0x0a78)
+#define AFE_CONN37 (0x0a7c)
+#define AFE_CONN38 (0x0a80)
+#define AFE_CONN39 (0x0a84)
+#define AFE_CONN40 (0x0a88)
+#define AFE_CONN41 (0x0a8c)
+#define AFE_CONN42 (0x0a90)
+#define AFE_CONN44 (0x0a94)
+#define AFE_CONN45 (0x0a98)
+#define AFE_CONN46 (0x0a9c)
+#define AFE_CONN47 (0x0aa0)
+#define AFE_CONN_24BIT (0x0aa4)
+#define AFE_CONN0_1 (0x0aa8)
+#define AFE_CONN1_1 (0x0aac)
+#define AFE_CONN2_1 (0x0ab0)
+#define AFE_CONN3_1 (0x0ab4)
+#define AFE_CONN4_1 (0x0ab8)
+#define AFE_CONN5_1 (0x0abc)
+#define AFE_CONN6_1 (0x0ac0)
+#define AFE_CONN7_1 (0x0ac4)
+#define AFE_CONN8_1 (0x0ac8)
+#define AFE_CONN9_1 (0x0acc)
+#define AFE_CONN10_1 (0x0ad0)
+#define AFE_CONN11_1 (0x0ad4)
+#define AFE_CONN12_1 (0x0ad8)
+#define AFE_CONN13_1 (0x0adc)
+#define AFE_CONN14_1 (0x0ae0)
+#define AFE_CONN15_1 (0x0ae4)
+#define AFE_CONN16_1 (0x0ae8)
+#define AFE_CONN17_1 (0x0aec)
+#define AFE_CONN18_1 (0x0af0)
+#define AFE_CONN19_1 (0x0af4)
+#define AFE_CONN43 (0x0af8)
+#define AFE_CONN43_1 (0x0afc)
+#define AFE_CONN21_1 (0x0b00)
+#define AFE_CONN22_1 (0x0b04)
+#define AFE_CONN23_1 (0x0b08)
+#define AFE_CONN24_1 (0x0b0c)
+#define AFE_CONN25_1 (0x0b10)
+#define AFE_CONN26_1 (0x0b14)
+#define AFE_CONN27_1 (0x0b18)
+#define AFE_CONN28_1 (0x0b1c)
+#define AFE_CONN29_1 (0x0b20)
+#define AFE_CONN30_1 (0x0b24)
+#define AFE_CONN31_1 (0x0b28)
+#define AFE_CONN32_1 (0x0b2c)
+#define AFE_CONN33_1 (0x0b30)
+#define AFE_CONN34_1 (0x0b34)
+#define AFE_CONN35_1 (0x0b38)
+#define AFE_CONN36_1 (0x0b3c)
+#define AFE_CONN37_1 (0x0b40)
+#define AFE_CONN38_1 (0x0b44)
+#define AFE_CONN39_1 (0x0b48)
+#define AFE_CONN40_1 (0x0b4c)
+#define AFE_CONN41_1 (0x0b50)
+#define AFE_CONN42_1 (0x0b54)
+#define AFE_CONN44_1 (0x0b58)
+#define AFE_CONN45_1 (0x0b5c)
+#define AFE_CONN46_1 (0x0b60)
+#define AFE_CONN47_1 (0x0b64)
+#define AFE_CONN_RS_1 (0x0b68)
+#define AFE_CONN_DI_1 (0x0b6c)
+#define AFE_CONN_24BIT_1 (0x0b70)
+#define AFE_GAIN1_CUR (0x0b78)
+#define AFE_CONN20_1 (0x0b7c)
+#define AFE_DL1_BASE_MSB (0x0b80)
+#define AFE_DL1_END_MSB (0x0b84)
+#define AFE_DL2_BASE_MSB (0x0b88)
+#define AFE_DL2_END_MSB (0x0b8c)
+#define AFE_AWB_BASE_MSB (0x0b90)
+#define AFE_AWB_END_MSB (0x0b94)
+#define AFE_VUL_BASE_MSB (0x0ba0)
+#define AFE_VUL_END_MSB (0x0ba4)
+#define AFE_VUL_D2_BASE_MSB (0x0ba8)
+#define AFE_VUL_D2_END_MSB (0x0bac)
+#define AFE_HDMI_OUT_BASE_MSB (0x0bb8)
+#define AFE_HDMI_OUT_END_MSB (0x0bbc)
+#define AFE_HDMI_IN_2CH_BASE_MSB (0x0bc0)
+#define AFE_HDMI_IN_2CH_END_MSB (0x0bc4)
+#define AFE_SPDIF_OUT_BASE_MSB (0x0bc8)
+#define AFE_SPDIF_OUT_END_MSB (0x0bcc)
+#define SPDIFIN_BASE_MSB (0x0bd0)
+#define SPDIFIN_END_MSB (0x0bd4)
+#define AFE_DL1_CUR_MSB (0x0bd8)
+#define AFE_DL2_CUR_MSB (0x0bdc)
+#define AFE_AWB_CUR_MSB (0x0be8)
+#define AFE_VUL_CUR_MSB (0x0bf8)
+#define AFE_VUL_D2_CUR_MSB (0x0c04)
+#define AFE_HDMI_OUT_CUR_MSB (0x0c0c)
+#define AFE_HDMI_IN_2CH_CUR_MSB (0x0c10)
+#define AFE_SPDIF_OUT_CUR_MSB (0x0c14)
+#define SPDIFIN_CUR_MSB (0x0c18)
+#define AFE_CONN_REG (0x0c20)
+#define AFE_SECURE_MASK_CONN14_1 (0x0c24)
+#define AFE_SECURE_MASK_CONN15_1 (0x0c28)
+#define AFE_SECURE_MASK_CONN16_1 (0x0c2c)
+#define AFE_SECURE_MASK_CONN17_1 (0x0c30)
+#define AFE_SECURE_MASK_CONN18_1 (0x0c34)
+#define AFE_SECURE_MASK_CONN19_1 (0x0c38)
+#define AFE_SECURE_MASK_CONN20_1 (0x0c3c)
+#define AFE_SECURE_MASK_CONN21_1 (0x0c40)
+#define AFE_SECURE_MASK_CONN22_1 (0x0c44)
+#define AFE_SECURE_MASK_CONN23_1 (0x0c48)
+#define AFE_SECURE_MASK_CONN24_1 (0x0c4c)
+#define AFE_ADDA_DL_SDM_DCCOMP_CON (0x0c50)
+#define AFE_ADDA_DL_SDM_TEST (0x0c54)
+#define AFE_ADDA_DL_DC_COMP_CFG0 (0x0c58)
+#define AFE_ADDA_DL_DC_COMP_CFG1 (0x0c5c)
+#define AFE_ADDA_DL_SDM_FIFO_MON (0x0c60)
+#define AFE_ADDA_DL_SRC_LCH_MON (0x0c64)
+#define AFE_ADDA_DL_SRC_RCH_MON (0x0c68)
+#define AFE_ADDA_DL_SDM_OUT_MON (0x0c6c)
+#define AFE_ADDA_DL_SDM_DITHER_CON (0x0c70)
+
+#define AFE_VUL3_CUR_MSB (0x0c78)
+#define AFE_ASRC_2CH_CON0 (0x0c80)
+#define AFE_ASRC_2CH_CON1 (0x0c84)
+#define AFE_ASRC_2CH_CON2 (0x0c88)
+#define AFE_ASRC_2CH_CON3 (0x0c8c)
+#define AFE_ASRC_2CH_CON4 (0x0c90)
+#define AFE_ASRC_2CH_CON5 (0x0c94)
+#define AFE_ASRC_2CH_CON6 (0x0c98)
+#define AFE_ASRC_2CH_CON7 (0x0c9c)
+#define AFE_ASRC_2CH_CON8 (0x0ca0)
+#define AFE_ASRC_2CH_CON9 (0x0ca4)
+#define AFE_ASRC_2CH_CON10 (0x0ca8)
+#define AFE_ASRC_2CH_CON12 (0x0cb0)
+#define AFE_ASRC_2CH_CON13 (0x0cb4)
+
+#define AFE_PCM_TX_ASRC_2CH_CON0 (0x0cc0)
+#define AFE_PCM_TX_ASRC_2CH_CON1 (0x0cc4)
+#define AFE_PCM_TX_ASRC_2CH_CON2 (0x0cc8)
+#define AFE_PCM_TX_ASRC_2CH_CON3 (0x0ccc)
+#define AFE_PCM_TX_ASRC_2CH_CON4 (0x0cd0)
+#define AFE_PCM_TX_ASRC_2CH_CON5 (0x0cd4)
+#define AFE_PCM_TX_ASRC_2CH_CON6 (0x0cd8)
+#define AFE_PCM_TX_ASRC_2CH_CON7 (0x0cdc)
+#define AFE_PCM_TX_ASRC_2CH_CON8 (0x0ce0)
+#define AFE_PCM_TX_ASRC_2CH_CON9 (0x0ce4)
+#define AFE_PCM_TX_ASRC_2CH_CON10 (0x0ce8)
+#define AFE_PCM_TX_ASRC_2CH_CON12 (0x0cf0)
+#define AFE_PCM_TX_ASRC_2CH_CON13 (0x0cf4)
+#define AFE_PCM_RX_ASRC_2CH_CON0 (0x0d00)
+#define AFE_PCM_RX_ASRC_2CH_CON1 (0x0d04)
+#define AFE_PCM_RX_ASRC_2CH_CON2 (0x0d08)
+#define AFE_PCM_RX_ASRC_2CH_CON3 (0x0d0c)
+#define AFE_PCM_RX_ASRC_2CH_CON4 (0x0d10)
+#define AFE_PCM_RX_ASRC_2CH_CON5 (0x0d14)
+#define AFE_PCM_RX_ASRC_2CH_CON6 (0x0d18)
+#define AFE_PCM_RX_ASRC_2CH_CON7 (0x0d1c)
+#define AFE_PCM_RX_ASRC_2CH_CON8 (0x0d20)
+#define AFE_PCM_RX_ASRC_2CH_CON9 (0x0d24)
+#define AFE_PCM_RX_ASRC_2CH_CON10 (0x0d28)
+#define AFE_PCM_RX_ASRC_2CH_CON12 (0x0d30)
+#define AFE_PCM_RX_ASRC_2CH_CON13 (0x0d34)
+
+#define AFE_ADDA_PREDIS_CON2 (0x0d40)
+#define AFE_ADDA_PREDIS_CON3 (0x0d44)
+#define AFE_SECURE_MASK_CONN4_1 (0x0d48)
+#define AFE_SECURE_MASK_CONN5_1 (0x0d4c)
+#define AFE_SECURE_MASK_CONN6_1 (0x0d50)
+#define AFE_SECURE_MASK_CONN7_1 (0x0d54)
+#define AFE_SECURE_MASK_CONN8_1 (0x0d58)
+#define AFE_SECURE_MASK_CONN9_1 (0x0d5c)
+#define AFE_SECURE_MASK_CONN10_1 (0x0d60)
+#define AFE_SECURE_MASK_CONN11_1 (0x0d64)
+#define AFE_SECURE_MASK_CONN12_1 (0x0d68)
+#define AFE_SECURE_MASK_CONN13_1 (0x0d6c)
+#define AFE_MEMIF_MON12 (0x0d70)
+#define AFE_MEMIF_MON13 (0x0d74)
+#define AFE_MEMIF_MON14 (0x0d78)
+#define AFE_MEMIF_MON15 (0x0d7c)
+#define AFE_SECURE_MASK_CONN42 (0x0dbc)
+#define AFE_SECURE_MASK_CONN43 (0x0dc0)
+#define AFE_SECURE_MASK_CONN44 (0x0dc4)
+#define AFE_SECURE_MASK_CONN45 (0x0dc8)
+#define AFE_SECURE_MASK_CONN46 (0x0dcc)
+#define AFE_HD_ENGEN_ENABLE (0x0dd0)
+#define AFE_SECURE_MASK_CONN47 (0x0dd4)
+#define AFE_SECURE_MASK_CONN48 (0x0dd8)
+#define AFE_SECURE_MASK_CONN49 (0x0ddc)
+#define AFE_SECURE_MASK_CONN50 (0x0de0)
+#define AFE_SECURE_MASK_CONN51 (0x0de4)
+#define AFE_SECURE_MASK_CONN52 (0x0de8)
+#define AFE_SECURE_MASK_CONN53 (0x0dec)
+#define AFE_SECURE_MASK_CONN0_1 (0x0df0)
+#define AFE_SECURE_MASK_CONN1_1 (0x0df4)
+#define AFE_SECURE_MASK_CONN2_1 (0x0df8)
+#define AFE_SECURE_MASK_CONN3_1 (0x0dfc)
+
+#define AFE_ADDA_MTKAIF_CFG0 (0x0e00)
+#define AFE_ADDA_MTKAIF_SYNCWORD_CFG (0x0e14)
+#define AFE_ADDA_MTKAIF_RX_CFG0 (0x0e20)
+#define AFE_ADDA_MTKAIF_RX_CFG1 (0x0e24)
+#define AFE_ADDA_MTKAIF_RX_CFG2 (0x0e28)
+#define AFE_ADDA_MTKAIF_MON0 (0x0e34)
+#define AFE_ADDA_MTKAIF_MON1 (0x0e38)
+#define AFE_AUD_PAD_TOP (0x0e40)
+
+#define AFE_CM1_CON4 (0x0e48)
+#define AFE_CM2_CON4 (0x0e4c)
+#define AFE_CM1_CON0 (0x0e50)
+#define AFE_CM1_CON1 (0x0e54)
+#define AFE_CM1_CON2 (0x0e58)
+#define AFE_CM1_CON3 (0x0e5c)
+#define AFE_CM2_CON0 (0x0e60)
+#define AFE_CM2_CON1 (0x0e64)
+#define AFE_CM2_CON2 (0x0e68)
+#define AFE_CM2_CON3 (0x0e6c)
+#define AFE_CM2_CONN0 (0x0e70)
+#define AFE_CM2_CONN1 (0x0e74)
+#define AFE_CM2_CONN2 (0x0e78)
+
+#define AFE_GENERAL1_ASRC_2CH_CON0 (0x0e80)
+#define AFE_GENERAL1_ASRC_2CH_CON1 (0x0e84)
+#define AFE_GENERAL1_ASRC_2CH_CON2 (0x0e88)
+#define AFE_GENERAL1_ASRC_2CH_CON3 (0x0e8c)
+#define AFE_GENERAL1_ASRC_2CH_CON4 (0x0e90)
+#define AFE_GENERAL1_ASRC_2CH_CON5 (0x0e94)
+#define AFE_GENERAL1_ASRC_2CH_CON6 (0x0e98)
+#define AFE_GENERAL1_ASRC_2CH_CON7 (0x0e9c)
+#define AFE_GENERAL1_ASRC_2CH_CON8 (0x0ea0)
+#define AFE_GENERAL1_ASRC_2CH_CON9 (0x0ea4)
+#define AFE_GENERAL1_ASRC_2CH_CON10 (0x0ea8)
+#define AFE_GENERAL1_ASRC_2CH_CON12 (0x0eb0)
+#define AFE_GENERAL1_ASRC_2CH_CON13 (0x0eb4)
+#define GENERAL_ASRC_MODE (0x0eb8)
+#define GENERAL_ASRC_EN_ON (0x0ebc)
+
+#define AFE_CONN48 (0x0ec0)
+#define AFE_CONN49 (0x0ec4)
+#define AFE_CONN50 (0x0ec8)
+#define AFE_CONN51 (0x0ecc)
+#define AFE_CONN52 (0x0ed0)
+#define AFE_CONN53 (0x0ed4)
+#define AFE_CONN48_1 (0x0ee0)
+#define AFE_CONN49_1 (0x0ee4)
+#define AFE_CONN50_1 (0x0ee8)
+#define AFE_CONN51_1 (0x0eec)
+#define AFE_CONN52_1 (0x0ef0)
+#define AFE_CONN53_1 (0x0ef4)
+
+#define AFE_GENERAL2_ASRC_2CH_CON0 (0x0f00)
+#define AFE_GENERAL2_ASRC_2CH_CON1 (0x0f04)
+#define AFE_GENERAL2_ASRC_2CH_CON2 (0x0f08)
+#define AFE_GENERAL2_ASRC_2CH_CON3 (0x0f0c)
+#define AFE_GENERAL2_ASRC_2CH_CON4 (0x0f10)
+#define AFE_GENERAL2_ASRC_2CH_CON5 (0x0f14)
+#define AFE_GENERAL2_ASRC_2CH_CON6 (0x0f18)
+#define AFE_GENERAL2_ASRC_2CH_CON7 (0x0f1c)
+#define AFE_GENERAL2_ASRC_2CH_CON8 (0x0f20)
+#define AFE_GENERAL2_ASRC_2CH_CON9 (0x0f24)
+#define AFE_GENERAL2_ASRC_2CH_CON10 (0x0f28)
+#define AFE_GENERAL2_ASRC_2CH_CON12 (0x0f30)
+#define AFE_GENERAL2_ASRC_2CH_CON13 (0x0f34)
+
+#define AFE_SECURE_MASK_CONN28 (0x0f48)
+#define AFE_SECURE_MASK_CONN29 (0x0f4c)
+#define AFE_SECURE_MASK_CONN30 (0x0f50)
+#define AFE_SECURE_MASK_CONN31 (0x0f54)
+#define AFE_SECURE_MASK_CONN32 (0x0f58)
+#define AFE_SECURE_MASK_CONN33 (0x0f5c)
+#define AFE_SECURE_MASK_CONN34 (0x0f60)
+#define AFE_SECURE_MASK_CONN35 (0x0f64)
+#define AFE_SECURE_MASK_CONN36 (0x0f68)
+#define AFE_SECURE_MASK_CONN37 (0x0f6c)
+#define AFE_SECURE_MASK_CONN38 (0x0f70)
+#define AFE_SECURE_MASK_CONN39 (0x0f74)
+#define AFE_SECURE_MASK_CONN40 (0x0f78)
+#define AFE_SECURE_MASK_CONN41 (0x0f7c)
+#define AFE_SIDEBAND0 (0x0f80)
+#define AFE_SIDEBAND1 (0x0f84)
+#define AFE_SECURE_SIDEBAND0 (0x0f88)
+#define AFE_SECURE_SIDEBAND1 (0x0f8c)
+#define AFE_SECURE_MASK_CONN0 (0x0f90)
+#define AFE_SECURE_MASK_CONN1 (0x0f94)
+#define AFE_SECURE_MASK_CONN2 (0x0f98)
+#define AFE_SECURE_MASK_CONN3 (0x0f9c)
+#define AFE_SECURE_MASK_CONN4 (0x0fa0)
+#define AFE_SECURE_MASK_CONN5 (0x0fa4)
+#define AFE_SECURE_MASK_CONN6 (0x0fa8)
+#define AFE_SECURE_MASK_CONN7 (0x0fac)
+#define AFE_SECURE_MASK_CONN8 (0x0fb0)
+#define AFE_SECURE_MASK_CONN9 (0x0fb4)
+#define AFE_SECURE_MASK_CONN10 (0x0fb8)
+#define AFE_SECURE_MASK_CONN11 (0x0fbc)
+#define AFE_SECURE_MASK_CONN12 (0x0fc0)
+#define AFE_SECURE_MASK_CONN13 (0x0fc4)
+#define AFE_SECURE_MASK_CONN14 (0x0fc8)
+#define AFE_SECURE_MASK_CONN15 (0x0fcc)
+#define AFE_SECURE_MASK_CONN16 (0x0fd0)
+#define AFE_SECURE_MASK_CONN17 (0x0fd4)
+#define AFE_SECURE_MASK_CONN18 (0x0fd8)
+#define AFE_SECURE_MASK_CONN19 (0x0fdc)
+#define AFE_SECURE_MASK_CONN20 (0x0fe0)
+#define AFE_SECURE_MASK_CONN21 (0x0fe4)
+#define AFE_SECURE_MASK_CONN22 (0x0fe8)
+#define AFE_SECURE_MASK_CONN23 (0x0fec)
+#define AFE_SECURE_MASK_CONN24 (0x0ff0)
+#define AFE_SECURE_MASK_CONN25 (0x0ff4)
+#define AFE_SECURE_MASK_CONN26 (0x0ff8)
+#define AFE_SECURE_MASK_CONN27 (0x0ffc)
+
+#define MAX_REGISTER AFE_SECURE_MASK_CONN27
+
+#define AFE_IRQ_STATUS_BITS 0x3ff
+
+/* AUDIO_TOP_CON0 (0x0000) */
+#define AUD_TCON0_PDN_TML (1U << 27)
+#define AUD_TCON0_PDN_DAC_PREDIS (1U << 26)
+#define AUD_TCON0_PDN_DAC (1U << 25)
+#define AUD_TCON0_PDN_ADC (1U << 24)
+#define AUD_TCON0_PDN_TDM_IN (1U << 23)
+#define AUD_TCON0_PDN_TDM_OUT (1U << 22)
+#define AUD_TCON0_PDN_SPDIF (1U << 21)
+#define AUD_TCON0_PDN_APLL_TUNER (1U << 19)
+#define AUD_TCON0_PDN_APLL2_TUNER (1U << 18)
+#define AUD_TCON0_PDN_INTDIR (1U << 15)
+#define AUD_TCON0_PDN_24M (1U << 9)
+#define AUD_TCON0_PDN_22M (1U << 8)
+#define AUD_TCON0_PDN_I2S_IN (1U << 6)
+#define AUD_TCON0_PDN_AFE (1U << 2)
+
+/* AUDIO_TOP_CON1 (0x0004) */
+#define AUD_TCON1_PDN_TDM_ASRC (1U << 15)
+#define AUD_TCON1_PDN_GENERAL2_ASRC (1U << 14)
+#define AUD_TCON1_PDN_GENERAL1_ASRC (1U << 13)
+#define AUD_TCON1_PDN_CONNSYS_I2S_ASRC (1U << 12)
+#define AUD_TCON1_PDN_DMIC3_ADC (1U << 11)
+#define AUD_TCON1_PDN_DMIC2_ADC (1U << 10)
+#define AUD_TCON1_PDN_DMIC1_ADC (1U << 9)
+#define AUD_TCON1_PDN_DMIC0_ADC (1U << 8)
+#define AUD_TCON1_PDN_I2S4_BCLK (1U << 7)
+#define AUD_TCON1_PDN_I2S3_BCLK (1U << 6)
+#define AUD_TCON1_PDN_I2S2_BCLK (1U << 5)
+#define AUD_TCON1_PDN_I2S1_BCLK (1U << 4)
+
+/* AUDIO_TOP_CON3 (0x000C) */
+#define AUD_TCON3_HDMI_BCK_INV (1U << 3)
+
+/* AFE_I2S_CON (0x0018) */
+#define AFE_I2S_CON_PHASE_SHIFT_FIX (1U << 31)
+#define AFE_I2S_CON_FROM_IO_MUX (1U << 28)
+#define AFE_I2S_CON_LOW_JITTER_CLK (1U << 12)
+#define AFE_I2S_CON_RATE_MASK GENMASK(11, 8)
+#define AFE_I2S_CON_FORMAT_I2S (1U << 3)
+#define AFE_I2S_CON_SRC_SLAVE (1U << 2)
+
+/* AFE_ASRC_2CH_CON0 */
+#define ONE_HEART (1U << 31)
+#define CHSET_STR_CLR (1U << 4)
+#define COEFF_SRAM_CTRL (1U << 1)
+#define ASM_ON (1U << 0)
+
+/* CON2 */
+#define O16BIT (1U << 19)
+#define CLR_IIR_HISTORY (1U << 17)
+#define IS_MONO (1U << 16)
+#define IIR_EN (1U << 11)
+#define IIR_STAGE_MASK GENMASK(10, 8)
+
+/* CON5 */
+#define CALI_CYCLE_MASK GENMASK(31, 16)
+#define CALI_64_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x3F)
+#define CALI_96_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x5F)
+#define CALI_441_CYCLE FIELD_PREP(CALI_CYCLE_MASK, 0x1B8)
+
+#define CALI_AUTORST (1U << 15)
+#define AUTO_TUNE_FREQ5 (1U << 12)
+#define COMP_FREQ_RES (1U << 11)
+
+#define CALI_SEL_MASK GENMASK(9, 8)
+#define CALI_SEL_00 FIELD_PREP(CALI_SEL_MASK, 0)
+#define CALI_SEL_01 FIELD_PREP(CALI_SEL_MASK, 1)
+
+#define CALI_BP_DGL (1U << 7) /* Bypass the deglitch circuit */
+#define AUTO_TUNE_FREQ4 (1U << 3)
+#define CALI_AUTO_RESTART (1U << 2)
+#define CALI_USE_FREQ_OUT (1U << 1)
+#define CALI_ON (1U << 0)
+
+#define AFE_I2S_CON_WLEN_32BIT (1U << 1)
+#define AFE_I2S_CON_EN (1U << 0)
+
+#define AFE_CONN3_I03_O03_S (1U << 3)
+#define AFE_CONN4_I04_O04_S (1U << 4)
+#define AFE_CONN4_I03_O04_S (1U << 3)
+
+/* AFE_I2S_CON1 (0x0034) */
+#define AFE_I2S_CON1_I2S2_TO_PAD (1U << 18)
+#define AFE_I2S_CON1_TDMOUT_TO_PAD (0 << 18)
+#define AFE_I2S_CON1_RATE GENMASK(11, 8)
+#define AFE_I2S_CON1_FORMAT_I2S (1U << 3)
+#define AFE_I2S_CON1_WLEN_32BIT (1U << 1)
+#define AFE_I2S_CON1_EN (1U << 0)
+
+/* AFE_I2S_CON2 (0x0038) */
+#define AFE_I2S_CON2_LOW_JITTER_CLK (1U << 12)
+#define AFE_I2S_CON2_RATE GENMASK(11, 8)
+#define AFE_I2S_CON2_FORMAT_I2S (1U << 3)
+#define AFE_I2S_CON2_WLEN_32BIT (1U << 1)
+#define AFE_I2S_CON2_EN (1U << 0)
+
+/* AFE_I2S_CON3 (0x004C) */
+#define AFE_I2S_CON3_LOW_JITTER_CLK (1U << 12)
+#define AFE_I2S_CON3_RATE GENMASK(11, 8)
+#define AFE_I2S_CON3_FORMAT_I2S (1U << 3)
+#define AFE_I2S_CON3_WLEN_32BIT (1U << 1)
+#define AFE_I2S_CON3_EN (1U << 0)
+
+/* AFE_ADDA_DL_SRC2_CON0 (0x0108) */
+#define AFE_ADDA_DL_SAMPLING_RATE GENMASK(31, 28)
+#define AFE_ADDA_DL_8X_UPSAMPLE GENMASK(25, 24)
+#define AFE_ADDA_DL_MUTE_OFF_CH1 (1U << 12)
+#define AFE_ADDA_DL_MUTE_OFF_CH2 (1U << 11)
+#define AFE_ADDA_DL_VOICE_DATA (1U << 5)
+#define AFE_ADDA_DL_DEGRADE_GAIN (1U << 1)
+
+/* AFE_ADDA_UL_SRC_CON0 (0x0114) */
+#define AFE_ADDA_UL_SAMPLING_RATE GENMASK(19, 17)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_ADDA_UL_DL_ADDA_AFE_ON (1U << 0)
+#define AFE_ADDA_UL_DL_DMIC_CLKDIV_ON (1U << 1)
+
+/* AFE_APLL_TUNER_CFG (0x03f0) */
+#define AFE_APLL_TUNER_CFG_MASK GENMASK(15, 1)
+#define AFE_APLL_TUNER_CFG_EN_MASK (1U << 0)
+
+/* AFE_APLL_TUNER_CFG1 (0x03f4) */
+#define AFE_APLL_TUNER_CFG1_MASK GENMASK(15, 1)
+#define AFE_APLL_TUNER_CFG1_EN_MASK (1U << 0)
+
+/* PCM_INTF_CON1 (0x0550) */
+#define PCM_INTF_CON1_EXT_MODEM (1U << 17)
+#define PCM_INTF_CON1_16BIT (0 << 16)
+#define PCM_INTF_CON1_24BIT (1U << 16)
+#define PCM_INTF_CON1_32BCK (0 << 14)
+#define PCM_INTF_CON1_64BCK (1U << 14)
+#define PCM_INTF_CON1_MASTER_MODE (0 << 5)
+#define PCM_INTF_CON1_SLAVE_MODE (1U << 5)
+#define PCM_INTF_CON1_FS_MASK GENMASK(4, 3)
+#define PCM_INTF_CON1_FS_8K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 0)
+#define PCM_INTF_CON1_FS_16K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 1)
+#define PCM_INTF_CON1_FS_32K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 2)
+#define PCM_INTF_CON1_FS_48K FIELD_PREP(PCM_INTF_CON1_FS_MASK, 3)
+#define PCM_INTF_CON1_SYNC_LEN_MASK GENMASK(13, 9)
+#define PCM_INTF_CON1_SYNC_LEN(x) FIELD_PREP(PCM_INTF_CON1_SYNC_LEN_MASK, ((x) - 1))
+#define PCM_INTF_CON1_FORMAT_MASK GENMASK(2, 1)
+#define PCM_INTF_CON1_SYNC_OUT_INV (1U << 23)
+#define PCM_INTF_CON1_BCLK_OUT_INV (1U << 22)
+#define PCM_INTF_CON1_SYNC_IN_INV (1U << 21)
+#define PCM_INTF_CON1_BCLK_IN_INV (1U << 20)
+#define PCM_INTF_CON1_BYPASS_ASRC (1U << 6)
+#define PCM_INTF_CON1_EN (1U << 0)
+#define PCM_INTF_CON1_CONFIG_MASK (0xf3fffe)
+
+/* AFE_DMIC0_UL_SRC_CON0 (0x05b4)
+ * AFE_DMIC1_UL_SRC_CON0 (0x0620)
+ * AFE_DMIC2_UL_SRC_CON0 (0x0780)
+ * AFE_DMIC3_UL_SRC_CON0 (0x07ec)
+ */
+#define DMIC_TOP_CON_CK_PHASE_SEL_CH1 GENMASK(29, 27)
+#define DMIC_TOP_CON_CK_PHASE_SEL_CH2 GENMASK(26, 24)
+#define DMIC_TOP_CON_TWO_WIRE_MODE (1U << 23)
+#define DMIC_TOP_CON_CH2_ON (1U << 22)
+#define DMIC_TOP_CON_CH1_ON (1U << 21)
+#define DMIC_TOP_CON_VOICE_MODE_MASK GENMASK(19, 17)
+#define DMIC_TOP_CON_VOICE_MODE_8K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 0)
+#define DMIC_TOP_CON_VOICE_MODE_16K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 1)
+#define DMIC_TOP_CON_VOICE_MODE_32K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 2)
+#define DMIC_TOP_CON_VOICE_MODE_48K FIELD_PREP(DMIC_TOP_CON_VOICE_MODE_MASK, 3)
+#define DMIC_TOP_CON_LOW_POWER_MODE_MASK GENMASK(15, 14)
+#define DMIC_TOP_CON_LOW_POWER_MODE(x) FIELD_PREP(DMIC_TOP_CON_LOW_POWER_MODE_MASK, (x))
+#define DMIC_TOP_CON_IIR_ON (1U << 10)
+#define DMIC_TOP_CON_IIR_MODE GENMASK(9, 7)
+#define DMIC_TOP_CON_INPUT_MODE (1U << 5)
+#define DMIC_TOP_CON_SDM3_LEVEL_MODE (1U << 1)
+#define DMIC_TOP_CON_SRC_ON (1U << 0)
+#define DMIC_TOP_CON_SDM3_DE_SELECT (0 << 1)
+#define DMIC_TOP_CON_CONFIG_MASK (0x3f8ed7a6)
+
+/* AFE_CONN_24BIT (0x0AA4) */
+#define AFE_CONN_24BIT_O10 (1U << 10)
+#define AFE_CONN_24BIT_O09 (1U << 9)
+#define AFE_CONN_24BIT_O06 (1U << 6)
+#define AFE_CONN_24BIT_O05 (1U << 5)
+#define AFE_CONN_24BIT_O04 (1U << 4)
+#define AFE_CONN_24BIT_O03 (1U << 3)
+#define AFE_CONN_24BIT_O02 (1U << 2)
+#define AFE_CONN_24BIT_O01 (1U << 1)
+#define AFE_CONN_24BIT_O00 (1U << 0)
+
+/* AFE_HD_ENGEN_ENABLE */
+#define AFE_22M_PLL_EN (1U << 0)
+#define AFE_24M_PLL_EN (1U << 1)
+
+/* AFE_GAIN1_CON0 (0x0410) */
+#define AFE_GAIN1_CON0_EN_MASK GENMASK(0, 0)
+#define AFE_GAIN1_CON0_MODE_MASK GENMASK(7, 4)
+#define AFE_GAIN1_CON0_SAMPLE_PER_STEP_MASK GENMASK(15, 8)
+
+/* AFE_GAIN1_CON1 (0x0414) */
+#define AFE_GAIN1_CON1_MASK GENMASK(19, 0)
+
+/* AFE_GAIN1_CUR (0x0B78) */
+#define AFE_GAIN1_CUR_MASK GENMASK(19, 0)
+
+/* AFE_CM1_CON0 (0x0e50) */
+/* AFE_CM2_CON0 (0x0e60) */
+#define CM_AFE_CM_CH_NUM_MASK GENMASK(3, 0)
+#define CM_AFE_CM_CH_NUM(x) FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, ((x) - 1))
+#define CM_AFE_CM_ON (1U << 4)
+#define CM_AFE_CM_START_DATA_MASK GENMASK(11, 8)
+
+#define CM_AFE_CM1_VUL_SEL (1U << 12)
+#define CM_AFE_CM1_IN_MODE_MASK GENMASK(19, 16)
+#define CM_AFE_CM2_TDM_SEL (1U << 12)
+#define CM_AFE_CM2_CLK_SEL (1U << 13)
+#define CM_AFE_CM2_GASRC1_OUT_SEL (1U << 17)
+#define CM_AFE_CM2_GASRC2_OUT_SEL (1U << 16)
+
+/* AFE_CM2_CONN* */
+#define CM2_AFE_CM2_CONN_CFG1(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG1_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG1_MASK GENMASK(4, 0)
+#define CM2_AFE_CM2_CONN_CFG2(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG2_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG2_MASK GENMASK(9, 5)
+#define CM2_AFE_CM2_CONN_CFG3(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG3_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG3_MASK GENMASK(14, 10)
+#define CM2_AFE_CM2_CONN_CFG4(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG4_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG4_MASK GENMASK(19, 15)
+#define CM2_AFE_CM2_CONN_CFG5(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG5_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG5_MASK GENMASK(24, 20)
+#define CM2_AFE_CM2_CONN_CFG6(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG6_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG6_MASK GENMASK(29, 25)
+#define CM2_AFE_CM2_CONN_CFG7(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG7_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG7_MASK GENMASK(4, 0)
+#define CM2_AFE_CM2_CONN_CFG8(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG8_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG8_MASK GENMASK(9, 5)
+#define CM2_AFE_CM2_CONN_CFG9(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG9_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG9_MASK GENMASK(14, 10)
+#define CM2_AFE_CM2_CONN_CFG10(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG10_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG10_MASK GENMASK(19, 15)
+#define CM2_AFE_CM2_CONN_CFG11(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG11_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG11_MASK GENMASK(24, 20)
+#define CM2_AFE_CM2_CONN_CFG12(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG12_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG12_MASK GENMASK(29, 25)
+#define CM2_AFE_CM2_CONN_CFG13(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG13_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG13_MASK GENMASK(4, 0)
+#define CM2_AFE_CM2_CONN_CFG14(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG14_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG14_MASK GENMASK(9, 5)
+#define CM2_AFE_CM2_CONN_CFG15(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG15_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG15_MASK GENMASK(14, 10)
+#define CM2_AFE_CM2_CONN_CFG16(x) FIELD_PREP(CM2_AFE_CM2_CONN_CFG16_MASK, (x))
+#define CM2_AFE_CM2_CONN_CFG16_MASK GENMASK(19, 15)
+
+/* AFE_CM1_CON* */
+#define CM_AFE_CM_UPDATE_CNT1_MASK GENMASK(15, 0)
+#define CM_AFE_CM_UPDATE_CNT1(x) FIELD_PREP(CM_AFE_CM_UPDATE_CNT1_MASK, (x))
+#define CM_AFE_CM_UPDATE_CNT2_MASK GENMASK(31, 16)
+#define CM_AFE_CM_UPDATE_CNT2(x) FIELD_PREP(CM_AFE_CM_UPDATE_CNT2_MASK, (x))
+
+#endif
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index b93ea33739f2..d9a730994a2a 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-menu "ASoC support for Amlogic platforms"
+menu "Amlogic"
depends on ARCH_MESON || (COMPILE_TEST && COMMON_CLK)
config SND_MESON_AIU
@@ -99,6 +99,7 @@ config SND_MESON_AXG_PDM
config SND_MESON_CARD_UTILS
tristate
+ select SND_DYNAMIC_MINORS
config SND_MESON_CODEC_GLUE
tristate
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index e446bc980481..24078e4396b0 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -1,30 +1,30 @@
# SPDX-License-Identifier: (GPL-2.0 OR MIT)
-snd-soc-meson-aiu-objs := aiu.o
-snd-soc-meson-aiu-objs += aiu-acodec-ctrl.o
-snd-soc-meson-aiu-objs += aiu-codec-ctrl.o
-snd-soc-meson-aiu-objs += aiu-encoder-i2s.o
-snd-soc-meson-aiu-objs += aiu-encoder-spdif.o
-snd-soc-meson-aiu-objs += aiu-fifo.o
-snd-soc-meson-aiu-objs += aiu-fifo-i2s.o
-snd-soc-meson-aiu-objs += aiu-fifo-spdif.o
-snd-soc-meson-axg-fifo-objs := axg-fifo.o
-snd-soc-meson-axg-frddr-objs := axg-frddr.o
-snd-soc-meson-axg-toddr-objs := axg-toddr.o
-snd-soc-meson-axg-tdm-formatter-objs := axg-tdm-formatter.o
-snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o
-snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
-snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
-snd-soc-meson-axg-sound-card-objs := axg-card.o
-snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
-snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
-snd-soc-meson-axg-pdm-objs := axg-pdm.o
-snd-soc-meson-card-utils-objs := meson-card-utils.o
-snd-soc-meson-codec-glue-objs := meson-codec-glue.o
-snd-soc-meson-gx-sound-card-objs := gx-card.o
-snd-soc-meson-g12a-toacodec-objs := g12a-toacodec.o
-snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
-snd-soc-meson-t9015-objs := t9015.o
+snd-soc-meson-aiu-y := aiu.o
+snd-soc-meson-aiu-y += aiu-acodec-ctrl.o
+snd-soc-meson-aiu-y += aiu-codec-ctrl.o
+snd-soc-meson-aiu-y += aiu-encoder-i2s.o
+snd-soc-meson-aiu-y += aiu-encoder-spdif.o
+snd-soc-meson-aiu-y += aiu-fifo.o
+snd-soc-meson-aiu-y += aiu-fifo-i2s.o
+snd-soc-meson-aiu-y += aiu-fifo-spdif.o
+snd-soc-meson-axg-fifo-y := axg-fifo.o
+snd-soc-meson-axg-frddr-y := axg-frddr.o
+snd-soc-meson-axg-toddr-y := axg-toddr.o
+snd-soc-meson-axg-tdm-formatter-y := axg-tdm-formatter.o
+snd-soc-meson-axg-tdm-interface-y := axg-tdm-interface.o
+snd-soc-meson-axg-tdmin-y := axg-tdmin.o
+snd-soc-meson-axg-tdmout-y := axg-tdmout.o
+snd-soc-meson-axg-sound-card-y := axg-card.o
+snd-soc-meson-axg-spdifin-y := axg-spdifin.o
+snd-soc-meson-axg-spdifout-y := axg-spdifout.o
+snd-soc-meson-axg-pdm-y := axg-pdm.o
+snd-soc-meson-card-utils-y := meson-card-utils.o
+snd-soc-meson-codec-glue-y := meson-codec-glue.o
+snd-soc-meson-gx-sound-card-y := gx-card.o
+snd-soc-meson-g12a-toacodec-y := g12a-toacodec.o
+snd-soc-meson-g12a-tohdmitx-y := g12a-tohdmitx.o
+snd-soc-meson-t9015-y := t9015.o
obj-$(CONFIG_SND_MESON_AIU) += snd-soc-meson-aiu.o
obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c
index d0f0ada5f4bc..483772ba69cd 100644
--- a/sound/soc/meson/aiu-acodec-ctrl.c
+++ b/sound/soc/meson/aiu-acodec-ctrl.c
@@ -31,10 +31,8 @@ static const char * const aiu_acodec_ctrl_mux_texts[] = {
static int aiu_acodec_ctrl_mux_put_enum(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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mux, changed;
@@ -103,6 +101,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = aiu_acodec_ctrl_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -130,8 +130,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = {
.name = "ACODEC CTRL " xname, \
.playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \
.ops = &aiu_acodec_ctrl_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define AIU_ACODEC_OUTPUT(xname) { \
diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c
index 84c10956c241..396f815077e2 100644
--- a/sound/soc/meson/aiu-codec-ctrl.c
+++ b/sound/soc/meson/aiu-codec-ctrl.c
@@ -23,10 +23,8 @@ static const char * const aiu_codec_ctrl_mux_texts[] = {
static int aiu_codec_ctrl_mux_put_enum(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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mux, changed;
@@ -75,6 +73,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = {
};
static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = meson_codec_glue_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -102,8 +102,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = {
.name = "CODEC CTRL " xname, \
.playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \
.ops = &aiu_codec_ctrl_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define AIU_CODEC_CTRL_OUTPUT(xname) { \
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
index a0dd914c8ed1..3b4061508c18 100644
--- a/sound/soc/meson/aiu-encoder-i2s.c
+++ b/sound/soc/meson/aiu-encoder-i2s.c
@@ -236,8 +236,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
inv == SND_SOC_DAIFMT_IB_IF)
val |= AIU_CLK_CTRL_LRCLK_INVERT;
- if (inv == SND_SOC_DAIFMT_IB_NF ||
- inv == SND_SOC_DAIFMT_IB_IF)
+ /*
+ * The SoC changes data on the rising edge of the bitclock
+ * so an inversion of the bitclock is required in normal mode
+ */
+ if (inv == SND_SOC_DAIFMT_NB_NF ||
+ inv == SND_SOC_DAIFMT_NB_IF)
val |= AIU_CLK_CTRL_AOCLK_INVERT;
/* Signal skew */
@@ -328,4 +332,3 @@ const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
.startup = aiu_encoder_i2s_startup,
.shutdown = aiu_encoder_i2s_shutdown,
};
-
diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c
index 59e00a74b5f8..eccbc16b293a 100644
--- a/sound/soc/meson/aiu-fifo-i2s.c
+++ b/sound/soc/meson/aiu-fifo-i2s.c
@@ -25,7 +25,7 @@
#define AIU_FIFO_I2S_BLOCK 256
-static struct snd_pcm_hardware fifo_i2s_pcm = {
+static const struct snd_pcm_hardware fifo_i2s_pcm = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
}
const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = {
+ .pcm_new = aiu_fifo_pcm_new,
+ .probe = aiu_fifo_i2s_dai_probe,
+ .remove = aiu_fifo_dai_remove,
.trigger = aiu_fifo_i2s_trigger,
.prepare = aiu_fifo_i2s_prepare,
.hw_params = aiu_fifo_i2s_hw_params,
diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c
index ddbd2fc40185..e0e00ec026dc 100644
--- a/sound/soc/meson/aiu-fifo-spdif.c
+++ b/sound/soc/meson/aiu-fifo-spdif.c
@@ -27,7 +27,7 @@
#define AIU_FIFO_SPDIF_BLOCK 8
-static struct snd_pcm_hardware fifo_spdif_pcm = {
+static const struct snd_pcm_hardware fifo_spdif_pcm = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream,
}
const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
+ .pcm_new = aiu_fifo_pcm_new,
+ .probe = aiu_fifo_spdif_dai_probe,
+ .remove = aiu_fifo_dai_remove,
.trigger = fifo_spdif_trigger,
.prepare = fifo_spdif_prepare,
.hw_params = fifo_spdif_hw_params,
diff --git a/sound/soc/meson/aiu-fifo.c b/sound/soc/meson/aiu-fifo.c
index 543d41856c12..b222bde1f61b 100644
--- a/sound/soc/meson/aiu-fifo.c
+++ b/sound/soc/meson/aiu-fifo.c
@@ -25,9 +25,9 @@
static struct snd_soc_dai *aiu_fifo_dai(struct snd_pcm_substream *ss)
{
- struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss);
- return asoc_rtd_to_cpu(rtd, 0);
+ return snd_soc_rtd_to_cpu(rtd, 0);
}
snd_pcm_uframes_t aiu_fifo_pointer(struct snd_soc_component *component,
diff --git a/sound/soc/meson/aiu-fifo.h b/sound/soc/meson/aiu-fifo.h
index 42ce266677cc..b02cfcc4de7f 100644
--- a/sound/soc/meson/aiu-fifo.h
+++ b/sound/soc/meson/aiu-fifo.h
@@ -18,7 +18,7 @@ struct snd_pcm_hw_params;
struct platform_device;
struct aiu_fifo {
- struct snd_pcm_hardware *pcm;
+ const struct snd_pcm_hardware *pcm;
unsigned int mem_offset;
unsigned int fifo_block;
struct clk *pclk;
@@ -38,8 +38,6 @@ int aiu_fifo_prepare(struct snd_pcm_substream *substream,
int aiu_fifo_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai);
-int aiu_fifo_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai);
int aiu_fifo_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai);
void aiu_fifo_shutdown(struct snd_pcm_substream *substream,
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
index da351a60df0c..f2890111c1d2 100644
--- a/sound/soc/meson/aiu.c
+++ b/sound/soc/meson/aiu.c
@@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
.formats = AIU_FORMATS,
},
.ops = &aiu_fifo_i2s_dai_ops,
- .pcm_new = aiu_fifo_pcm_new,
- .probe = aiu_fifo_i2s_dai_probe,
- .remove = aiu_fifo_dai_remove,
},
[CPU_SPDIF_FIFO] = {
.name = "SPDIF FIFO",
@@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
.formats = AIU_FORMATS,
},
.ops = &aiu_fifo_spdif_dai_ops,
- .pcm_new = aiu_fifo_pcm_new,
- .probe = aiu_fifo_spdif_dai_probe,
- .remove = aiu_fifo_dai_remove,
},
[CPU_I2S_ENCODER] = {
.name = "I2S Encoder",
@@ -218,11 +212,12 @@ static const char * const aiu_spdif_ids[] = {
static int aiu_clk_get(struct device *dev)
{
struct aiu *aiu = dev_get_drvdata(dev);
+ struct clk *pclk;
int ret;
- aiu->pclk = devm_clk_get(dev, "pclk");
- if (IS_ERR(aiu->pclk))
- return dev_err_probe(dev, PTR_ERR(aiu->pclk), "Can't get the aiu pclk\n");
+ pclk = devm_clk_get_enabled(dev, "pclk");
+ if (IS_ERR(pclk))
+ return dev_err_probe(dev, PTR_ERR(pclk), "Can't get the aiu pclk\n");
aiu->spdif_mclk = devm_clk_get(dev, "spdif_mclk");
if (IS_ERR(aiu->spdif_mclk))
@@ -239,18 +234,6 @@ static int aiu_clk_get(struct device *dev)
if (ret)
return dev_err_probe(dev, ret, "Can't get the spdif clocks\n");
- ret = clk_prepare_enable(aiu->pclk);
- if (ret) {
- dev_err(dev, "peripheral clock enable failed\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev,
- (void(*)(void *))clk_disable_unprepare,
- aiu->pclk);
- if (ret)
- dev_err(dev, "failed to add reset action on pclk");
-
return ret;
}
@@ -362,7 +345,7 @@ MODULE_DEVICE_TABLE(of, aiu_of_match);
static struct platform_driver aiu_pdrv = {
.probe = aiu_probe,
- .remove_new = aiu_remove,
+ .remove = aiu_remove,
.driver = {
.name = "meson-aiu",
.of_match_table = aiu_of_match,
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
index 393b6c2307e4..0f94c8bf6081 100644
--- a/sound/soc/meson/aiu.h
+++ b/sound/soc/meson/aiu.h
@@ -33,7 +33,6 @@ struct aiu_platform_data {
};
struct aiu {
- struct clk *pclk;
struct clk *spdif_mclk;
struct aiu_interface i2s;
struct aiu_interface spdif;
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
index 74e7cf0ef8d5..b4dca80e15e4 100644
--- a/sound/soc/meson/axg-card.c
+++ b/sound/soc/meson/axg-card.c
@@ -40,10 +40,10 @@ static const struct snd_soc_pcm_stream codec_params = {
static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
struct axg_dai_link_tdm_data *be =
- (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+ (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id];
return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs);
}
@@ -56,7 +56,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
struct axg_dai_link_tdm_data *be =
- (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+ (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id];
struct snd_soc_dai *codec_dai;
int ret, i;
@@ -72,10 +72,10 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
}
}
- ret = axg_tdm_set_tdm_slots(asoc_rtd_to_cpu(rtd, 0), be->tx_mask, be->rx_mask,
+ ret = axg_tdm_set_tdm_slots(snd_soc_rtd_to_cpu(rtd, 0), be->tx_mask, be->rx_mask,
be->slots, be->slot_width);
if (ret) {
- dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n");
+ dev_err(snd_soc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n");
return ret;
}
@@ -86,14 +86,14 @@ static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd)
{
struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
struct axg_dai_link_tdm_data *be =
- (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+ (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id];
int ret;
/* The loopback rx_mask is the pad tx_mask */
- ret = axg_tdm_set_tdm_slots(asoc_rtd_to_cpu(rtd, 0), NULL, be->tx_mask,
+ ret = axg_tdm_set_tdm_slots(snd_soc_rtd_to_cpu(rtd, 0), NULL, be->tx_mask,
be->slots, be->slot_width);
if (ret) {
- dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n");
+ dev_err(snd_soc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n");
return ret;
}
@@ -104,7 +104,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
int *index)
{
struct meson_card *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai_link *pad = &card->dai_link[*index];
+ struct snd_soc_dai_link *pad;
struct snd_soc_dai_link *lb;
struct snd_soc_dai_link_component *dlc;
int ret;
@@ -114,6 +114,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
if (ret)
return ret;
+ pad = &card->dai_link[*index];
lb = &card->dai_link[*index + 1];
lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name);
@@ -125,14 +126,14 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
return -ENOMEM;
lb->cpus = dlc;
- lb->codecs = &asoc_dummy_dlc;
+ lb->codecs = &snd_soc_dummy_dlc;
lb->num_cpus = 1;
lb->num_codecs = 1;
lb->stream_name = lb->name;
lb->cpus->of_node = pad->cpus->of_node;
lb->cpus->dai_name = "TDM Loopback";
- lb->dpcm_capture = 1;
+ lb->capture_only = 1;
lb->no_pcm = 1;
lb->ops = &axg_card_tdm_be_ops;
lb->init = axg_card_tdm_dai_lb_init;
@@ -176,7 +177,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
/* Disable playback is the interface has no tx slots */
if (!tx)
- link->dpcm_playback = 0;
+ link->capture_only = 1;
for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) {
snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i);
@@ -186,9 +187,9 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
/* Disable capture is the interface has no rx slots */
if (!rx)
- link->dpcm_capture = 0;
+ link->playback_only = 1;
- /* ... but the interface should at least have one of them */
+ /* ... but the interface should at least have one direction */
if (!tx && !rx) {
dev_err(card->dev, "tdm link has no cpu slots\n");
return -EINVAL;
@@ -221,7 +222,6 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
struct axg_dai_link_tdm_data *be)
{
struct axg_dai_link_tdm_mask *codec_mask;
- struct device_node *np;
codec_mask = devm_kcalloc(card->dev, link->num_codecs,
sizeof(*codec_mask), GFP_KERNEL);
@@ -230,7 +230,7 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
be->codec_masks = codec_mask;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask",
&codec_mask->rx);
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask",
@@ -275,7 +275,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
return ret;
/* Add loopback if the pad dai has playback */
- if (link->dpcm_playback) {
+ if (!link->capture_only) {
ret = axg_card_add_tdm_loopback(card, index);
if (ret)
return ret;
@@ -318,9 +318,9 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
dai_link->cpus = cpu;
dai_link->num_cpus = 1;
+ dai_link->nonatomic = true;
- ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node,
- &dai_link->cpus->dai_name);
+ ret = meson_card_parse_dai(card, np, dai_link->cpus);
if (ret)
return ret;
@@ -339,7 +339,6 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
dai_link->num_c2c_params = 1;
} else {
dai_link->no_pcm = 1;
- snd_soc_dai_link_set_capabilities(dai_link);
if (axg_card_cpu_is_tdm_iface(dai_link->cpus->of_node))
ret = axg_card_parse_tdm(card, np, index);
}
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
index bccfb770b339..75909196b769 100644
--- a/sound/soc/meson/axg-fifo.c
+++ b/sound/soc/meson/axg-fifo.c
@@ -3,6 +3,7 @@
// Copyright (c) 2018 BayLibre, SAS.
// Author: Jerome Brunet <jbrunet@baylibre.com>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -22,7 +23,7 @@
* These differences are handled in the respective DAI drivers
*/
-static struct snd_pcm_hardware axg_fifo_hw = {
+static const struct snd_pcm_hardware axg_fifo_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -31,7 +32,7 @@ static struct snd_pcm_hardware axg_fifo_hw = {
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
.formats = AXG_FIFO_FORMATS,
.rate_min = 5512,
- .rate_max = 192000,
+ .rate_max = 768000,
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
.period_bytes_min = AXG_FIFO_BURST,
@@ -45,9 +46,9 @@ static struct snd_pcm_hardware axg_fifo_hw = {
static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss)
{
- struct snd_soc_pcm_runtime *rtd = ss->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss);
- return asoc_rtd_to_cpu(rtd, 0);
+ return snd_soc_rtd_to_cpu(rtd, 0);
}
static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss)
@@ -145,8 +146,8 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
/* Enable irq if necessary */
irq_en = runtime->no_period_wakeup ? 0 : FIFO_INT_COUNT_REPEAT;
regmap_update_bits(fifo->map, FIFO_CTRL0,
- CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
- CTRL0_INT_EN(irq_en));
+ CTRL0_INT_EN,
+ FIELD_PREP(CTRL0_INT_EN, irq_en));
return 0;
}
@@ -176,9 +177,9 @@ int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
{
struct axg_fifo *fifo = axg_fifo_data(ss);
- /* Disable the block count irq */
+ /* Disable irqs */
regmap_update_bits(fifo->map, FIFO_CTRL0,
- CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
+ CTRL0_INT_EN, 0);
return 0;
}
@@ -187,13 +188,13 @@ EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
{
regmap_update_bits(fifo->map, FIFO_CTRL1,
- CTRL1_INT_CLR(FIFO_INT_MASK),
- CTRL1_INT_CLR(mask));
+ CTRL1_INT_CLR,
+ FIELD_PREP(CTRL1_INT_CLR, mask));
/* Clear must also be cleared */
regmap_update_bits(fifo->map, FIFO_CTRL1,
- CTRL1_INT_CLR(FIFO_INT_MASK),
- 0);
+ CTRL1_INT_CLR,
+ FIELD_PREP(CTRL1_INT_CLR, 0));
}
static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
@@ -203,18 +204,19 @@ static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
unsigned int status;
regmap_read(fifo->map, FIFO_STATUS1, &status);
+ status = FIELD_GET(STATUS1_INT_STS, status);
+ axg_fifo_ack_irq(fifo, status);
- status = STATUS1_INT_STS(status) & FIFO_INT_MASK;
- if (status & FIFO_INT_COUNT_REPEAT)
- snd_pcm_period_elapsed(ss);
- else
+ if (status & ~FIFO_INT_COUNT_REPEAT)
dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
status);
- /* Ack irqs */
- axg_fifo_ack_irq(fifo, status);
+ if (status & FIFO_INT_COUNT_REPEAT) {
+ snd_pcm_period_elapsed(ss);
+ return IRQ_HANDLED;
+ }
- return IRQ_RETVAL(status);
+ return IRQ_NONE;
}
int axg_fifo_pcm_open(struct snd_soc_component *component,
@@ -242,8 +244,10 @@ int axg_fifo_pcm_open(struct snd_soc_component *component,
if (ret)
return ret;
- ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
- dev_name(dev), ss);
+ /* Use the threaded irq handler only with non-atomic links */
+ ret = request_threaded_irq(fifo->irq, NULL,
+ axg_fifo_pcm_irq_block,
+ IRQF_ONESHOT, dev_name(dev), ss);
if (ret)
return ret;
@@ -254,15 +258,15 @@ int axg_fifo_pcm_open(struct snd_soc_component *component,
/* Setup status2 so it reports the memory pointer */
regmap_update_bits(fifo->map, FIFO_CTRL1,
- CTRL1_STATUS2_SEL_MASK,
- CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ));
+ CTRL1_STATUS2_SEL,
+ FIELD_PREP(CTRL1_STATUS2_SEL, STATUS2_SEL_DDR_READ));
/* Make sure the dma is initially disabled */
__dma_enable(fifo, false);
/* Disable irqs until params are ready */
regmap_update_bits(fifo->map, FIFO_CTRL0,
- CTRL0_INT_EN(FIFO_INT_MASK), 0);
+ CTRL0_INT_EN, 0);
/* Clear any pending interrupt */
axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
index b63acd723c87..4c48c0a08481 100644
--- a/sound/soc/meson/axg-fifo.h
+++ b/sound/soc/meson/axg-fifo.h
@@ -21,8 +21,6 @@ struct snd_soc_dai_driver;
struct snd_soc_pcm_runtime;
#define AXG_FIFO_CH_MAX 128
-#define AXG_FIFO_RATES (SNDRV_PCM_RATE_5512 | \
- SNDRV_PCM_RATE_8000_192000)
#define AXG_FIFO_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
@@ -42,21 +40,19 @@ struct snd_soc_pcm_runtime;
#define FIFO_CTRL0 0x00
#define CTRL0_DMA_EN BIT(31)
-#define CTRL0_INT_EN(x) ((x) << 16)
+#define CTRL0_INT_EN GENMASK(23, 16)
#define CTRL0_SEL_MASK GENMASK(2, 0)
#define CTRL0_SEL_SHIFT 0
#define FIFO_CTRL1 0x04
-#define CTRL1_INT_CLR(x) ((x) << 0)
-#define CTRL1_STATUS2_SEL_MASK GENMASK(11, 8)
-#define CTRL1_STATUS2_SEL(x) ((x) << 8)
+#define CTRL1_INT_CLR GENMASK(7, 0)
+#define CTRL1_STATUS2_SEL GENMASK(11, 8)
#define STATUS2_SEL_DDR_READ 0
-#define CTRL1_FRDDR_DEPTH_MASK GENMASK(31, 24)
-#define CTRL1_FRDDR_DEPTH(x) ((x) << 24)
+#define CTRL1_FRDDR_DEPTH GENMASK(31, 24)
#define FIFO_START_ADDR 0x08
#define FIFO_FINISH_ADDR 0x0c
#define FIFO_INT_ADDR 0x10
#define FIFO_STATUS1 0x14
-#define STATUS1_INT_STS(x) ((x) << 0)
+#define STATUS1_INT_STS GENMASK(7, 0)
#define FIFO_STATUS2 0x18
#define FIFO_INIT_ADDR 0x24
#define FIFO_CTRL2 0x28
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
index 61f9d417fd60..e70c8c34c7db 100644
--- a/sound/soc/meson/axg-frddr.c
+++ b/sound/soc/meson/axg-frddr.c
@@ -7,6 +7,7 @@
* This driver implements the frontend playback DAI of AXG and G12A based SoCs
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/module.h>
@@ -59,8 +60,8 @@ static int axg_frddr_dai_hw_params(struct snd_pcm_substream *substream,
/* Trim the FIFO depth if the period is small to improve latency */
depth = min(period, fifo->depth);
val = (depth / AXG_FIFO_BURST) - 1;
- regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
- CTRL1_FRDDR_DEPTH(val));
+ regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH,
+ FIELD_PREP(CTRL1_FRDDR_DEPTH, val));
return 0;
}
@@ -100,6 +101,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = {
.hw_params = axg_frddr_dai_hw_params,
.startup = axg_frddr_dai_startup,
.shutdown = axg_frddr_dai_shutdown,
+ .pcm_new = axg_frddr_pcm_new,
};
static struct snd_soc_dai_driver axg_frddr_dai_drv = {
@@ -108,11 +110,12 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
- .rates = AXG_FIFO_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5515,
+ .rate_max = 768000,
.formats = AXG_FIFO_FORMATS,
},
.ops = &axg_frddr_ops,
- .pcm_new = axg_frddr_pcm_new,
};
static const char * const axg_frddr_sel_texts[] = {
@@ -175,6 +178,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = {
.hw_params = axg_frddr_dai_hw_params,
.startup = axg_frddr_dai_startup,
.shutdown = axg_frddr_dai_shutdown,
+ .pcm_new = axg_frddr_pcm_new,
};
static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
@@ -183,11 +187,12 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
- .rates = AXG_FIFO_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5515,
+ .rate_max = 768000,
.formats = AXG_FIFO_FORMATS,
},
.ops = &g12a_frddr_ops,
- .pcm_new = axg_frddr_pcm_new,
};
static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c
index ad43cb2a1e3f..d59050914d3c 100644
--- a/sound/soc/meson/axg-pdm.c
+++ b/sound/soc/meson/axg-pdm.c
@@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream,
clk_disable_unprepare(priv->dclk);
}
-static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
- .trigger = axg_pdm_trigger,
- .hw_params = axg_pdm_hw_params,
- .startup = axg_pdm_startup,
- .shutdown = axg_pdm_shutdown,
-};
-
static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv)
{
const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic;
@@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
+ .probe = axg_pdm_dai_probe,
+ .remove = axg_pdm_dai_remove,
+ .trigger = axg_pdm_trigger,
+ .hw_params = axg_pdm_hw_params,
+ .startup = axg_pdm_startup,
+ .shutdown = axg_pdm_shutdown,
+};
+
static struct snd_soc_dai_driver axg_pdm_dai_drv = {
.name = "PDM",
.capture = {
@@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = {
SNDRV_PCM_FMTBIT_S32_LE),
},
.ops = &axg_pdm_dai_ops,
- .probe = axg_pdm_dai_probe,
- .remove = axg_pdm_dai_remove,
};
static const struct snd_soc_component_driver axg_pdm_component_drv = {
diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c
index e2cc4c4be758..e721f579321e 100644
--- a/sound/soc/meson/axg-spdifin.c
+++ b/sound/soc/meson/axg-spdifin.c
@@ -112,34 +112,6 @@ static int axg_spdifin_prepare(struct snd_pcm_substream *substream,
return 0;
}
-static int axg_spdifin_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
- int ret;
-
- ret = clk_prepare_enable(priv->refclk);
- if (ret) {
- dev_err(dai->dev,
- "failed to enable spdifin reference clock\n");
- return ret;
- }
-
- regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
- SPDIFIN_CTRL0_EN);
-
- return 0;
-}
-
-static void axg_spdifin_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
-
- regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
- clk_disable_unprepare(priv->refclk);
-}
-
static void axg_spdifin_write_mode_param(struct regmap *map, int mode,
unsigned int val,
unsigned int num_per_reg,
@@ -207,9 +179,9 @@ static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,
SPDIFIN_CTRL1_BASE_TIMER,
FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));
- /* Threshold based on the minimum width between two edges */
+ /* Threshold based on the maximum width between two edges */
regmap_update_bits(priv->map, SPDIFIN_CTRL0,
- SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL);
+ SPDIFIN_CTRL0_WIDTH_SEL, 0);
/* Calculate the last timer which has no threshold */
t_next = axg_spdifin_mode_timer(priv, i, rate);
@@ -227,7 +199,7 @@ static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,
axg_spdifin_write_timer(priv->map, i, t);
/* Set the threshold value */
- axg_spdifin_write_threshold(priv->map, i, t + t_next);
+ axg_spdifin_write_threshold(priv->map, i, 3 * (t + t_next));
/* Save the current timer for the next threshold calculation */
t_next = t;
@@ -251,25 +223,40 @@ static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)
ret = axg_spdifin_sample_mode_config(dai, priv);
if (ret) {
dev_err(dai->dev, "mode configuration failed\n");
- clk_disable_unprepare(priv->pclk);
- return ret;
+ goto pclk_err;
}
+ ret = clk_prepare_enable(priv->refclk);
+ if (ret) {
+ dev_err(dai->dev,
+ "failed to enable spdifin reference clock\n");
+ goto pclk_err;
+ }
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
+ SPDIFIN_CTRL0_EN);
+
return 0;
+
+pclk_err:
+ clk_disable_unprepare(priv->pclk);
+ return ret;
}
static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
{
struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
+ clk_disable_unprepare(priv->refclk);
clk_disable_unprepare(priv->pclk);
return 0;
}
static const struct snd_soc_dai_ops axg_spdifin_ops = {
+ .probe = axg_spdifin_dai_probe,
+ .remove = axg_spdifin_dai_remove,
.prepare = axg_spdifin_prepare,
- .startup = axg_spdifin_startup,
- .shutdown = axg_spdifin_shutdown,
};
static int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol,
@@ -429,8 +416,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
drv->name = "SPDIF Input";
drv->ops = &axg_spdifin_ops;
- drv->probe = axg_spdifin_dai_probe;
- drv->remove = axg_spdifin_dai_remove;
drv->capture.stream_name = "Capture";
drv->capture.channels_min = 1;
drv->capture.channels_max = 2;
diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c
index e8a12f15f3b4..84868fe574e0 100644
--- a/sound/soc/meson/axg-spdifout.c
+++ b/sound/soc/meson/axg-spdifout.c
@@ -352,8 +352,8 @@ static int axg_spdifout_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct axg_spdifout *priv = snd_soc_component_get_drvdata(component);
- enum snd_soc_bias_level now =
- snd_soc_component_get_bias_level(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ enum snd_soc_bias_level now = snd_soc_dapm_get_bias_level(dapm);
int ret = 0;
switch (level) {
diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
index 9883dc777f63..a6579efd3775 100644
--- a/sound/soc/meson/axg-tdm-formatter.c
+++ b/sound/soc/meson/axg-tdm-formatter.c
@@ -30,27 +30,32 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map,
struct axg_tdm_stream *ts,
unsigned int offset)
{
- unsigned int val, ch = ts->channels;
- unsigned long mask;
- int i, j;
+ unsigned int ch = ts->channels;
+ u32 val[AXG_TDM_NUM_LANES];
+ int i, j, k;
+
+ /*
+ * We need to mimick the slot distribution used by the HW to keep the
+ * channel placement consistent regardless of the number of channel
+ * in the stream. This is why the odd algorithm below is used.
+ */
+ memset(val, 0, sizeof(*val) * AXG_TDM_NUM_LANES);
/*
* Distribute the channels of the stream over the available slots
- * of each TDM lane
+ * of each TDM lane. We need to go over the 32 slots ...
*/
- for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
- val = 0;
- mask = ts->mask[i];
-
- for (j = find_first_bit(&mask, 32);
- (j < 32) && ch;
- j = find_next_bit(&mask, 32, j + 1)) {
- val |= 1 << j;
- ch -= 1;
+ for (i = 0; (i < 32) && ch; i += 2) {
+ /* ... of all the lanes ... */
+ for (j = 0; j < AXG_TDM_NUM_LANES; j++) {
+ /* ... then distribute the channels in pairs */
+ for (k = 0; k < 2; k++) {
+ if ((BIT(i + k) & ts->mask[j]) && ch) {
+ val[j] |= BIT(i + k);
+ ch -= 1;
+ }
+ }
}
-
- regmap_write(map, offset, val);
- offset += regmap_get_reg_stride(map);
}
/*
@@ -63,6 +68,11 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map,
return -EINVAL;
}
+ for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
+ regmap_write(map, offset, val[i]);
+ offset += regmap_get_reg_stride(map);
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
@@ -382,6 +392,46 @@ void axg_tdm_stream_free(struct axg_tdm_stream *ts)
}
EXPORT_SYMBOL_GPL(axg_tdm_stream_free);
+int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts,
+ unsigned int fmt)
+{
+ int ret = 0;
+
+ if (fmt & SND_SOC_DAIFMT_CONT) {
+ /* Clock are already enabled - skipping */
+ if (ts->clk_enabled)
+ return 0;
+
+ ret = clk_prepare_enable(ts->iface->mclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(ts->iface->sclk);
+ if (ret)
+ goto err_sclk;
+
+ ret = clk_prepare_enable(ts->iface->lrclk);
+ if (ret)
+ goto err_lrclk;
+
+ ts->clk_enabled = true;
+ return 0;
+ }
+
+ /* Clocks are already disabled - skipping */
+ if (!ts->clk_enabled)
+ return 0;
+
+ clk_disable_unprepare(ts->iface->lrclk);
+err_lrclk:
+ clk_disable_unprepare(ts->iface->sclk);
+err_sclk:
+ clk_disable_unprepare(ts->iface->mclk);
+ ts->clk_enabled = false;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_set_cont_clocks);
+
MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
index 5e5e4c56d505..d5287d78f53b 100644
--- a/sound/soc/meson/axg-tdm-interface.c
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -12,6 +12,9 @@
#include "axg-tdm.h"
+/* Maximum bit clock frequency according the datasheets */
+#define MAX_SCLK 100000000 /* Hz */
+
enum {
TDM_IFACE_PAD,
TDM_IFACE_LOOPBACK,
@@ -130,7 +133,7 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_BP_FC:
case SND_SOC_DAIFMT_BC_FP:
- dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
+ dev_err(dai->dev, "only BP_FP and BC_FC are supported\n");
fallthrough;
default:
return -EINVAL;
@@ -153,19 +156,27 @@ static int axg_tdm_iface_startup(struct snd_pcm_substream *substream,
return -EINVAL;
}
- /* Apply component wide rate symmetry */
if (snd_soc_component_active(dai->component)) {
+ /* Apply component wide rate symmetry */
ret = snd_pcm_hw_constraint_single(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
iface->rate);
- if (ret < 0) {
- dev_err(dai->dev,
- "can't set iface rate constraint\n");
- return ret;
- }
+
+ } else {
+ /* Limit rate according to the slot number and width */
+ unsigned int max_rate =
+ MAX_SCLK / (iface->slots * iface->slot_width);
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ 0, max_rate);
}
- return 0;
+ if (ret < 0)
+ dev_err(dai->dev, "can't set iface rate constraint\n");
+ else
+ ret = 0;
+
+ return ret;
}
static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream,
@@ -264,8 +275,8 @@ static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai,
srate = iface->slots * iface->slot_width * params_rate(params);
if (!iface->mclk_rate) {
- /* If no specific mclk is requested, default to bit clock * 4 */
- clk_set_rate(iface->mclk, 4 * srate);
+ /* If no specific mclk is requested, default to bit clock * 2 */
+ clk_set_rate(iface->mclk, 2 * srate);
} else {
/* Check if we can actually get the bit clock from mclk */
if (iface->mclk_rate % srate) {
@@ -298,6 +309,7 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
int ret;
switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -335,7 +347,11 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- return 0;
+ ret = axg_tdm_stream_set_cont_clocks(ts, iface->fmt);
+ if (ret)
+ dev_err(dai->dev, "failed to apply continuous clock setting\n");
+
+ return ret;
}
static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
@@ -343,19 +359,32 @@ static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
{
struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
- /* Stop all attached formatters */
- axg_tdm_stream_stop(ts);
-
- return 0;
+ return axg_tdm_stream_set_cont_clocks(ts, 0);
}
-static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream,
+static int axg_tdm_iface_trigger(struct snd_pcm_substream *substream,
+ int cmd,
struct snd_soc_dai *dai)
{
- struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ struct axg_tdm_stream *ts =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ axg_tdm_stream_start(ts);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ axg_tdm_stream_stop(ts);
+ break;
+ default:
+ return -EINVAL;
+ }
- /* Force all attached formatters to update */
- return axg_tdm_stream_reset(ts);
+ return 0;
}
static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai)
@@ -395,12 +424,14 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
+ .probe = axg_tdm_iface_probe_dai,
+ .remove = axg_tdm_iface_remove_dai,
.set_sysclk = axg_tdm_iface_set_sysclk,
.set_fmt = axg_tdm_iface_set_fmt,
.startup = axg_tdm_iface_startup,
.hw_params = axg_tdm_iface_hw_params,
- .prepare = axg_tdm_iface_prepare,
.hw_free = axg_tdm_iface_hw_free,
+ .trigger = axg_tdm_iface_trigger,
};
/* TDM Backend DAIs */
@@ -411,20 +442,22 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = AXG_TDM_CHANNEL_MAX,
- .rates = AXG_TDM_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 768000,
.formats = AXG_TDM_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = AXG_TDM_CHANNEL_MAX,
- .rates = AXG_TDM_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 768000,
.formats = AXG_TDM_FORMATS,
},
.id = TDM_IFACE_PAD,
.ops = &axg_tdm_iface_ops,
- .probe = axg_tdm_iface_probe_dai,
- .remove = axg_tdm_iface_remove_dai,
},
[TDM_IFACE_LOOPBACK] = {
.name = "TDM Loopback",
@@ -432,13 +465,13 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
.stream_name = "Loopback",
.channels_min = 1,
.channels_max = AXG_TDM_CHANNEL_MAX,
- .rates = AXG_TDM_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 768000,
.formats = AXG_TDM_FORMATS,
},
.id = TDM_IFACE_LOOPBACK,
.ops = &axg_tdm_iface_ops,
- .probe = axg_tdm_iface_probe_dai,
- .remove = axg_tdm_iface_remove_dai,
},
};
@@ -446,8 +479,8 @@ static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct axg_tdm_iface *iface = snd_soc_component_get_drvdata(component);
- enum snd_soc_bias_level now =
- snd_soc_component_get_bias_level(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ enum snd_soc_bias_level now = snd_soc_dapm_get_bias_level(dapm);
int ret = 0;
switch (level) {
@@ -496,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)
@@ -508,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/axg-tdm.h b/sound/soc/meson/axg-tdm.h
index 5774ce0916d4..acfcd48f8a00 100644
--- a/sound/soc/meson/axg-tdm.h
+++ b/sound/soc/meson/axg-tdm.h
@@ -15,8 +15,6 @@
#define AXG_TDM_NUM_LANES 4
#define AXG_TDM_CHANNEL_MAX 128
-#define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \
- SNDRV_PCM_RATE_8000_192000)
#define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
@@ -58,12 +56,17 @@ struct axg_tdm_stream {
unsigned int physical_width;
u32 *mask;
bool ready;
+
+ /* For continuous clock tracking */
+ bool clk_enabled;
};
struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
void axg_tdm_stream_free(struct axg_tdm_stream *ts);
int axg_tdm_stream_start(struct axg_tdm_stream *ts);
void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
+int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts,
+ unsigned int fmt);
static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
{
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
index e9208e74e965..03512da4092b 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -5,6 +5,7 @@
/* This driver implements the frontend capture DAI of AXG based SoCs */
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/module.h>
@@ -19,12 +20,9 @@
#define CTRL0_TODDR_EXT_SIGNED BIT(29)
#define CTRL0_TODDR_PP_MODE BIT(28)
#define CTRL0_TODDR_SYNC_CH BIT(27)
-#define CTRL0_TODDR_TYPE_MASK GENMASK(15, 13)
-#define CTRL0_TODDR_TYPE(x) ((x) << 13)
-#define CTRL0_TODDR_MSB_POS_MASK GENMASK(12, 8)
-#define CTRL0_TODDR_MSB_POS(x) ((x) << 8)
-#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
-#define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
+#define CTRL0_TODDR_TYPE GENMASK(15, 13)
+#define CTRL0_TODDR_MSB_POS GENMASK(12, 8)
+#define CTRL0_TODDR_LSB_POS GENMASK(7, 3)
#define CTRL1_TODDR_FORCE_FINISH BIT(25)
#define CTRL1_SEL_SHIFT 28
@@ -76,12 +74,12 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
width = params_width(params);
regmap_update_bits(fifo->map, FIFO_CTRL0,
- CTRL0_TODDR_TYPE_MASK |
- CTRL0_TODDR_MSB_POS_MASK |
- CTRL0_TODDR_LSB_POS_MASK,
- CTRL0_TODDR_TYPE(type) |
- CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) |
- CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1)));
+ CTRL0_TODDR_TYPE |
+ CTRL0_TODDR_MSB_POS |
+ CTRL0_TODDR_LSB_POS,
+ FIELD_PREP(CTRL0_TODDR_TYPE, type) |
+ FIELD_PREP(CTRL0_TODDR_MSB_POS, TODDR_MSB_POS) |
+ FIELD_PREP(CTRL0_TODDR_LSB_POS, TODDR_MSB_POS - (width - 1)));
return 0;
}
@@ -122,6 +120,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = {
.hw_params = axg_toddr_dai_hw_params,
.startup = axg_toddr_dai_startup,
.shutdown = axg_toddr_dai_shutdown,
+ .pcm_new = axg_toddr_pcm_new,
};
static struct snd_soc_dai_driver axg_toddr_dai_drv = {
@@ -130,11 +129,12 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
- .rates = AXG_FIFO_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5515,
+ .rate_max = 768000,
.formats = AXG_FIFO_FORMATS,
},
.ops = &axg_toddr_ops,
- .pcm_new = axg_toddr_pcm_new,
};
static const char * const axg_toddr_sel_texts[] = {
@@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = {
.hw_params = axg_toddr_dai_hw_params,
.startup = g12a_toddr_dai_startup,
.shutdown = axg_toddr_dai_shutdown,
+ .pcm_new = axg_toddr_pcm_new,
};
static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
@@ -225,11 +226,12 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
- .rates = AXG_FIFO_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5515,
+ .rate_max = 768000,
.formats = AXG_FIFO_FORMATS,
},
.ops = &g12a_toddr_ops,
- .pcm_new = axg_toddr_pcm_new,
};
static const struct snd_soc_component_driver g12a_toddr_component_drv = {
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
index ddc667956cf5..a95375b53f0a 100644
--- a/sound/soc/meson/g12a-toacodec.c
+++ b/sound/soc/meson/g12a-toacodec.c
@@ -63,14 +63,15 @@ static const char * const g12a_toacodec_mux_texts[] = {
static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
struct g12a_toacodec *priv = snd_soc_component_get_drvdata(component);
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mux, reg;
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
regmap_field_read(priv->field_dat_sel, &reg);
@@ -101,7 +102,7 @@ static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol,
snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
- return 0;
+ return 1;
}
static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0,
@@ -162,6 +163,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops g12a_toacodec_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = g12a_toacodec_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -185,8 +188,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = {
.id = (xid), \
.playback = TOACODEC_STREAM(xname, "Playback", 8), \
.ops = &g12a_toacodec_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define TOACODEC_OUTPUT(xname, xid) { \
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
index 579a04ad4d19..d541ca4acfaf 100644
--- a/sound/soc/meson/g12a-tohdmitx.c
+++ b/sound/soc/meson/g12a-tohdmitx.c
@@ -38,13 +38,14 @@ static const char * const g12a_tohdmitx_i2s_mux_texts[] = {
static int g12a_tohdmitx_i2s_mux_put_enum(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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mux, changed;
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
changed = snd_soc_component_test_bits(component, e->reg,
CTRL0_I2S_DAT_SEL,
@@ -86,13 +87,14 @@ static const char * const g12a_tohdmitx_spdif_mux_texts[] = {
static int g12a_tohdmitx_spdif_mux_put_enum(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 snd_soc_component *component = snd_soc_dapm_kcontrol_to_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mux, changed;
+ if (ucontrol->value.enumerated.item[0] >= e->items)
+ return -EINVAL;
+
mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
changed = snd_soc_component_test_bits(component, TOHDMITX_CTRL0,
CTRL0_SPDIF_SEL,
@@ -112,7 +114,7 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol,
snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
- return 0;
+ return 1;
}
static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_spdif_mux_enum, TOHDMITX_CTRL0,
@@ -140,6 +142,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = {
};
static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = meson_codec_glue_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -172,8 +176,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = {
.id = (xid), \
.playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \
.ops = &g12a_tohdmitx_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \
diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c
index 58c411d3c489..b408cc2bbc91 100644
--- a/sound/soc/meson/gx-card.c
+++ b/sound/soc/meson/gx-card.c
@@ -29,10 +29,10 @@ static const struct snd_soc_pcm_stream codec_params = {
static int gx_card_i2s_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
struct gx_dai_link_i2s_data *be =
- (struct gx_dai_link_i2s_data *)priv->link_data[rtd->num];
+ (struct gx_dai_link_i2s_data *)priv->link_data[rtd->id];
return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs);
}
@@ -90,8 +90,7 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np,
dai_link->cpus = cpu;
dai_link->num_cpus = 1;
- ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node,
- &dai_link->cpus->dai_name);
+ ret = meson_card_parse_dai(card, np, dai_link->cpus);
if (ret)
return ret;
@@ -108,7 +107,6 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np,
dai_link->num_c2c_params = 1;
} else {
dai_link->no_pcm = 1;
- snd_soc_dai_link_set_capabilities(dai_link);
/* Check if the cpu is the i2s encoder and parse i2s data */
if (gx_card_cpu_identify(dai_link->cpus, "I2S Encoder"))
ret = gx_card_parse_i2s(card, np, index);
diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
index ffc5111f9e3c..cdb759b466ad 100644
--- a/sound/soc/meson/meson-card-utils.c
+++ b/sound/soc/meson/meson-card-utils.c
@@ -13,7 +13,7 @@ int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
unsigned int mclk_fs)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
unsigned int mclk;
int ret, i;
@@ -30,7 +30,7 @@ int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream,
return ret;
}
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk,
SND_SOC_CLOCK_OUT);
if (ret && ret != -ENOTSUPP)
return ret;
@@ -74,23 +74,18 @@ EXPORT_SYMBOL_GPL(meson_card_reallocate_links);
int meson_card_parse_dai(struct snd_soc_card *card,
struct device_node *node,
- struct device_node **dai_of_node,
- const char **dai_name)
+ struct snd_soc_dai_link_component *dlc)
{
- struct of_phandle_args args;
int ret;
- if (!dai_name || !dai_of_node || !node)
+ if (!dlc || !node)
return -EINVAL;
- ret = of_parse_phandle_with_args(node, "sound-dai",
- "#sound-dai-cells", 0, &args);
+ ret = snd_soc_of_get_dlc(node, NULL, dlc, 0);
if (ret)
return dev_err_probe(card->dev, ret, "can't parse dai\n");
- *dai_of_node = args.np;
-
- return snd_soc_get_dai_name(&args, dai_name);
+ return ret;
}
EXPORT_SYMBOL_GPL(meson_card_parse_dai);
@@ -124,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);
@@ -142,7 +137,6 @@ int meson_card_set_be_link(struct snd_soc_card *card,
struct device_node *node)
{
struct snd_soc_dai_link_component *codec;
- struct device_node *np;
int ret, num_codecs;
num_codecs = of_get_child_count(node);
@@ -159,20 +153,17 @@ int meson_card_set_be_link(struct snd_soc_card *card,
link->codecs = codec;
link->num_codecs = num_codecs;
- for_each_child_of_node(node, np) {
- ret = meson_card_parse_dai(card, np, &codec->of_node,
- &codec->dai_name);
- if (ret) {
- of_node_put(np);
+ for_each_child_of_node_scoped(node, np) {
+ ret = meson_card_parse_dai(card, np, codec);
+ if (ret)
return ret;
- }
codec++;
}
ret = meson_card_set_link_name(card, link, node, "be");
if (ret)
- dev_err(card->dev, "error setting %pOFn link name\n", np);
+ dev_err(card->dev, "error setting %pOFn link name\n", node);
return ret;
}
@@ -183,7 +174,7 @@ int meson_card_set_fe_link(struct snd_soc_card *card,
struct device_node *node,
bool is_playback)
{
- link->codecs = &asoc_dummy_dlc;
+ link->codecs = &snd_soc_dummy_dlc;
link->num_codecs = 1;
link->dynamic = 1;
@@ -192,9 +183,9 @@ int meson_card_set_fe_link(struct snd_soc_card *card,
link->dpcm_merged_rate = 1;
if (is_playback)
- link->dpcm_playback = 1;
+ link->playback_only = 1;
else
- link->dpcm_capture = 1;
+ link->capture_only = 1;
return meson_card_set_link_name(card, link, node, "fe");
}
@@ -204,7 +195,6 @@ static int meson_card_add_links(struct snd_soc_card *card)
{
struct meson_card *priv = snd_soc_card_get_drvdata(card);
struct device_node *node = card->dev->of_node;
- struct device_node *np;
int num, i, ret;
num = of_get_child_count(node);
@@ -218,12 +208,10 @@ static int meson_card_add_links(struct snd_soc_card *card)
return ret;
i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
ret = priv->match_data->add_link(card, np, &i);
- if (ret) {
- of_node_put(np);
+ if (ret)
return ret;
- }
i++;
}
@@ -237,7 +225,7 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card,
const char *p))
{
/* If property is not provided, don't fail ... */
- if (!of_property_read_bool(card->dev->of_node, propname))
+ if (!of_property_present(card->dev->of_node, propname))
return 0;
/* ... but do fail if it is provided and the parsing fails */
@@ -333,13 +321,11 @@ out_err:
}
EXPORT_SYMBOL_GPL(meson_card_probe);
-int meson_card_remove(struct platform_device *pdev)
+void meson_card_remove(struct platform_device *pdev)
{
struct meson_card *priv = platform_get_drvdata(pdev);
meson_card_clean_references(priv);
-
- return 0;
}
EXPORT_SYMBOL_GPL(meson_card_remove);
diff --git a/sound/soc/meson/meson-card.h b/sound/soc/meson/meson-card.h
index 74314071c80d..a0d693e4f460 100644
--- a/sound/soc/meson/meson-card.h
+++ b/sound/soc/meson/meson-card.h
@@ -39,8 +39,7 @@ int meson_card_reallocate_links(struct snd_soc_card *card,
unsigned int num_links);
int meson_card_parse_dai(struct snd_soc_card *card,
struct device_node *node,
- struct device_node **dai_of_node,
- const char **dai_name);
+ struct snd_soc_dai_link_component *dlc);
int meson_card_set_be_link(struct snd_soc_card *card,
struct snd_soc_dai_link *link,
struct device_node *node);
@@ -50,6 +49,6 @@ int meson_card_set_fe_link(struct snd_soc_card *card,
bool is_playback);
int meson_card_probe(struct platform_device *pdev);
-int meson_card_remove(struct platform_device *pdev);
+void meson_card_remove(struct platform_device *pdev);
#endif /* _MESON_SND_CARD_H */
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
index e702d408ee96..f8c5643f3cfe 100644
--- a/sound/soc/meson/meson-codec-glue.c
+++ b/sound/soc/meson/meson-codec-glue.c
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget_capture(dai);
struct meson_codec_glue_input *in_data = meson_codec_glue_output_get_input_data(w);
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index 9c6b4dac6893..da1a93946d67 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -48,7 +48,6 @@
#define POWER_CFG 0x10
struct t9015 {
- struct clk *pclk;
struct regulator *avdd;
};
@@ -58,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;
@@ -178,8 +177,8 @@ static int t9015_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct t9015 *priv = snd_soc_component_get_drvdata(component);
- enum snd_soc_bias_level now =
- snd_soc_component_get_bias_level(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ enum snd_soc_bias_level now = snd_soc_dapm_get_bias_level(dapm);
int ret;
switch (level) {
@@ -249,6 +248,7 @@ static int t9015_probe(struct platform_device *pdev)
struct t9015 *priv;
void __iomem *regs;
struct regmap *regmap;
+ struct clk *pclk;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -256,26 +256,14 @@ static int t9015_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
- priv->pclk = devm_clk_get(dev, "pclk");
- if (IS_ERR(priv->pclk))
- return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get core clock\n");
+ pclk = devm_clk_get_enabled(dev, "pclk");
+ if (IS_ERR(pclk))
+ return dev_err_probe(dev, PTR_ERR(pclk), "failed to get core clock\n");
priv->avdd = devm_regulator_get(dev, "AVDD");
if (IS_ERR(priv->avdd))
return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n");
- ret = clk_prepare_enable(priv->pclk);
- if (ret) {
- dev_err(dev, "core clock enable failed\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev,
- (void(*)(void *))clk_disable_unprepare,
- priv->pclk);
- if (ret)
- return ret;
-
ret = device_reset(dev);
if (ret) {
dev_err(dev, "reset failed\n");
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
index 402ef1ee7a32..2fb1ca711f71 100644
--- a/sound/soc/mxs/Kconfig
+++ b/sound/soc/mxs/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SND_MXS_SOC
- tristate "SoC Audio for Freescale MXS CPUs"
+ tristate "Freescale MXS"
depends on ARCH_MXS || COMPILE_TEST
depends on COMMON_CLK
select SND_SOC_GENERIC_DMAENGINE_PCM
diff --git a/sound/soc/mxs/Makefile b/sound/soc/mxs/Makefile
index ab0a9a553702..474bdd75513f 100644
--- a/sound/soc/mxs/Makefile
+++ b/sound/soc/mxs/Makefile
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
# MXS Platform Support
-snd-soc-mxs-objs := mxs-saif.o
-snd-soc-mxs-pcm-objs := mxs-pcm.o
+snd-soc-mxs-y := mxs-saif.o
+snd-soc-mxs-pcm-y := mxs-pcm.o
obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs.o snd-soc-mxs-pcm.o
# i.MX Machine Support
-snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o
+snd-soc-mxs-sgtl5000-y := mxs-sgtl5000.o
obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index df2e4be992d2..9bb08cadeb18 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -43,4 +43,5 @@ int mxs_pcm_platform_register(struct device *dev)
}
EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
+MODULE_DESCRIPTION("MXS ASoC PCM driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index ac761d3a01c0..a01a680ad4d7 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
@@ -25,9 +24,80 @@
#define MXS_SET_ADDR 0x4
#define MXS_CLR_ADDR 0x8
+#define MXS_SAIF_BUSY_TIMEOUT_US 10000
+
static struct mxs_saif *mxs_saif[2];
/*
+ * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
+ * is provided by other SAIF, we provide a interface here to get its master
+ * from its master_id.
+ * Note that the master could be itself.
+ */
+static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif *saif)
+{
+ return mxs_saif[saif->master_id];
+}
+
+static int __mxs_saif_put_mclk(struct mxs_saif *saif)
+{
+ u32 stat;
+ int ret;
+
+ ret = readx_poll_timeout(__raw_readl, saif->base + SAIF_STAT, stat,
+ (stat & BM_SAIF_STAT_BUSY) == 0,
+ MXS_SAIF_BUSY_TIMEOUT_US,
+ USEC_PER_SEC);
+ if (ret) {
+ dev_err(saif->dev, "error: busy\n");
+ return -EBUSY;
+ }
+
+ /* disable MCLK output */
+ __raw_writel(BM_SAIF_CTRL_CLKGATE,
+ saif->base + SAIF_CTRL + MXS_SET_ADDR);
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ saif->mclk_in_use = 0;
+
+ return 0;
+}
+
+static int __mxs_saif_get_mclk(struct mxs_saif *saif)
+{
+ u32 stat;
+ struct mxs_saif *master_saif;
+
+ if (!saif)
+ return -EINVAL;
+
+ /* Clear Reset */
+ __raw_writel(BM_SAIF_CTRL_SFTRST,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ /* FIXME: need clear clk gate for register r/w */
+ __raw_writel(BM_SAIF_CTRL_CLKGATE,
+ saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+ master_saif = mxs_saif_get_master(saif);
+ if (saif != master_saif) {
+ dev_err(saif->dev, "can not get mclk from a non-master saif\n");
+ return -EINVAL;
+ }
+
+ stat = __raw_readl(saif->base + SAIF_STAT);
+ if (stat & BM_SAIF_STAT_BUSY) {
+ dev_err(saif->dev, "error: busy\n");
+ return -EBUSY;
+ }
+
+ saif->mclk_in_use = 1;
+
+ return 0;
+}
+
+/*
* SAIF is a little different with other normal SOC DAIs on clock using.
*
* For MXS, two SAIF modules are instantiated on-chip.
@@ -49,6 +119,7 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
switch (clk_id) {
case MXS_SAIF_MCLK:
@@ -57,18 +128,22 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
- return 0;
-}
-/*
- * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
- * is provided by other SAIF, we provide a interface here to get its master
- * from its master_id.
- * Note that the master could be itself.
- */
-static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif)
-{
- return mxs_saif[saif->master_id];
+ if (!saif->mclk_in_use && freq) {
+ ret = __mxs_saif_get_mclk(saif);
+ if (ret)
+ return ret;
+
+ /* enable MCLK output */
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ saif->base + SAIF_CTRL + MXS_SET_ADDR);
+ } else if (saif->mclk_in_use && freq == 0) {
+ ret = __mxs_saif_put_mclk(saif);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
/*
@@ -239,34 +314,15 @@ int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
unsigned int rate)
{
struct mxs_saif *saif = mxs_saif[saif_id];
- u32 stat;
int ret;
- struct mxs_saif *master_saif;
if (!saif)
return -EINVAL;
- /* Clear Reset */
- __raw_writel(BM_SAIF_CTRL_SFTRST,
- saif->base + SAIF_CTRL + MXS_CLR_ADDR);
-
- /* FIXME: need clear clk gate for register r/w */
- __raw_writel(BM_SAIF_CTRL_CLKGATE,
- saif->base + SAIF_CTRL + MXS_CLR_ADDR);
-
- master_saif = mxs_saif_get_master(saif);
- if (saif != master_saif) {
- dev_err(saif->dev, "can not get mclk from a non-master saif\n");
- return -EINVAL;
- }
-
- stat = __raw_readl(saif->base + SAIF_STAT);
- if (stat & BM_SAIF_STAT_BUSY) {
- dev_err(saif->dev, "error: busy\n");
- return -EBUSY;
- }
+ ret = __mxs_saif_get_mclk(saif);
+ if (ret)
+ return ret;
- saif->mclk_in_use = 1;
ret = mxs_saif_set_clk(saif, mclk, rate);
if (ret)
return ret;
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 457c3a72a414..245f17411638 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -19,9 +18,9 @@
static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned int rate = params_rate(params);
u32 mclk;
int ret;
@@ -60,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,
@@ -186,7 +185,7 @@ static struct platform_driver mxs_sgtl5000_audio_driver = {
.of_match_table = mxs_sgtl5000_dt_ids,
},
.probe = mxs_sgtl5000_probe,
- .remove_new = mxs_sgtl5000_remove,
+ .remove = mxs_sgtl5000_remove,
};
module_platform_driver(mxs_sgtl5000_audio_driver);
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index e6bca9070953..e54abcd39f79 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,16 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
+menu "PXA"
+
config SND_PXA2XX_SOC
tristate "SoC Audio for the Intel PXA2xx chip"
- depends on ARCH_PXA || COMPILE_TEST
+ depends on ARCH_PXA || (COMPILE_TEST && GPIOLIB_LEGACY)
select SND_PXA2XX_LIB
help
Say Y or M if you want to add support for codecs attached to
the PXA2xx AC97, I2S or SSP interface. You will also need
to select the audio interfaces to support below.
-config SND_PXA2XX_AC97
- tristate
-
config SND_PXA2XX_SOC_AC97
tristate "SoC AC97 support for PXA2xx"
depends on SND_PXA2XX_SOC
@@ -27,7 +26,7 @@ config SND_PXA2XX_SOC_I2S
config SND_PXA_SOC_SSP
tristate "Soc Audio via PXA2xx/PXA3xx SSP ports"
- depends on PLAT_PXA
+ depends on ARCH_PXA
select PXA_SSP
select SND_PXA2XX_LIB
@@ -35,7 +34,6 @@ config SND_MMP_SOC_SSPA
tristate "SoC Audio via MMP SSPA ports"
depends on ARCH_MMP
select SND_SOC_GENERIC_DMAENGINE_PCM
- select SND_ARM
help
Say Y if you want to add support for codecs attached to
the MMP SSPA interface.
@@ -56,3 +54,5 @@ config SND_PXA910_SOC
help
Say Y if you want to add support for SoC audio on the
Marvell PXA910 reference platform.
+
+endmenu
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 406605fc7414..93b4e57eaa5c 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
# PXA Platform Support
-snd-soc-pxa2xx-objs := pxa2xx-pcm.o
-snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
-snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
-snd-soc-pxa-ssp-objs := pxa-ssp.o
-snd-soc-mmp-sspa-objs := mmp-sspa.o
+snd-soc-pxa2xx-y := pxa2xx-pcm.o
+snd-soc-pxa2xx-ac97-y := pxa2xx-ac97.o
+snd-soc-pxa2xx-i2s-y := pxa2xx-i2s.o
+snd-soc-pxa-ssp-y := pxa-ssp.o
+snd-soc-mmp-sspa-y := mmp-sspa.o
obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
@@ -13,5 +13,5 @@ obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o
# PXA Machine Support
-snd-soc-spitz-objs := spitz.o
+snd-soc-spitz-y := spitz.o
obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index a1ed141b8795..73f36c9dd35c 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+ .probe = mmp_sspa_probe,
.startup = mmp_sspa_startup,
.shutdown = mmp_sspa_shutdown,
.trigger = mmp_sspa_trigger,
@@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
};
static struct snd_soc_dai_driver mmp_sspa_dai = {
- .probe = mmp_sspa_probe,
.playback = {
.channels_min = 1,
.channels_max = 128,
@@ -574,7 +574,7 @@ static struct platform_driver asoc_mmp_sspa_driver = {
.of_match_table = of_match_ptr(mmp_sspa_of_match),
},
.probe = asoc_mmp_sspa_probe,
- .remove_new = asoc_mmp_sspa_remove,
+ .remove = asoc_mmp_sspa_remove,
};
module_platform_driver(asoc_mmp_sspa_driver);
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 430dd446321e..b8a3cb8b7597 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -591,7 +591,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
if (ret < 0) {
const struct pxa_ssp_clock_mode *m;
- int ssacd, acds;
+ int ssacd;
for (m = pxa_ssp_clock_modes; m->rate; m++) {
if (m->rate == rate)
@@ -601,12 +601,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
if (!m->rate)
return -EINVAL;
- acds = m->acds;
-
- /* The values in the table are for 16 bits */
- if (width == 32)
- acds--;
-
ret = pxa_ssp_set_pll(priv, bclk);
if (ret < 0)
return ret;
@@ -779,7 +773,7 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai)
if (IS_ERR(priv->extclk)) {
ret = PTR_ERR(priv->extclk);
if (ret == -EPROBE_DEFER)
- return ret;
+ goto err_priv;
priv->extclk = NULL;
}
@@ -819,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+ .probe = pxa_ssp_probe,
+ .remove = pxa_ssp_remove,
.startup = pxa_ssp_startup,
.shutdown = pxa_ssp_shutdown,
.trigger = pxa_ssp_trigger,
@@ -830,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
};
static struct snd_soc_dai_driver pxa_ssp_dai = {
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
.playback = {
.channels_min = 1,
.channels_max = 8,
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index e73bd62c033c..78f50032afc5 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -271,7 +271,6 @@ static void pxa2xx_ac97_dev_remove(struct platform_device *pdev)
pxa2xx_ac97_hw_remove(pdev);
}
-#ifdef CONFIG_PM_SLEEP
static int pxa2xx_ac97_dev_suspend(struct device *dev)
{
return pxa2xx_ac97_hw_suspend();
@@ -282,18 +281,15 @@ static int pxa2xx_ac97_dev_resume(struct device *dev)
return pxa2xx_ac97_hw_resume();
}
-static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,
pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume);
-#endif
static struct platform_driver pxa2xx_ac97_driver = {
.probe = pxa2xx_ac97_dev_probe,
- .remove_new = pxa2xx_ac97_dev_remove,
+ .remove = pxa2xx_ac97_dev_remove,
.driver = {
.name = "pxa2xx-ac97",
-#ifdef CONFIG_PM_SLEEP
.pm = &pxa2xx_ac97_pm_ops,
-#endif
.of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids),
},
};
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 3e4c70403672..849fbf176a70 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -93,8 +93,8 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
if (IS_ERR(clk_i2s))
return PTR_ERR(clk_i2s);
@@ -329,6 +329,8 @@ static int pxa2xx_i2s_remove(struct snd_soc_dai *dai)
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+ .probe = pxa2xx_i2s_probe,
+ .remove = pxa2xx_i2s_remove,
.startup = pxa2xx_i2s_startup,
.shutdown = pxa2xx_i2s_shutdown,
.trigger = pxa2xx_i2s_trigger,
@@ -338,8 +340,6 @@ static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
};
static struct snd_soc_dai_driver pxa_i2s_dai = {
- .probe = pxa2xx_i2s_probe,
- .remove = pxa2xx_i2s_remove,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -370,18 +370,11 @@ static const struct snd_soc_component_driver pxa_i2s_component = {
static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
{
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *res;
- if (!res) {
- dev_err(&pdev->dev, "missing MMIO resource\n");
- return -ENXIO;
- }
-
- i2s_reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(i2s_reg_base)) {
- dev_err(&pdev->dev, "ioremap failed\n");
+ i2s_reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(i2s_reg_base))
return PTR_ERR(i2s_reg_base);
- }
pxa2xx_i2s_pcm_stereo_out.addr = res->start + SADR;
pxa2xx_i2s_pcm_stereo_in.addr = res->start + SADR;
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 70442315f5c5..2ea21a2091ee 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -104,10 +104,11 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
static int spitz_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(rtd->card);
/* check the jack status at stream startup */
- spitz_ext_control(&rtd->card->dapm);
+ spitz_ext_control(dapm);
return 0;
}
@@ -115,9 +116,9 @@ static int spitz_startup(struct snd_pcm_substream *substream)
static int spitz_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned int clk = 0;
int ret = 0;
@@ -166,12 +167,13 @@ static int spitz_set_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
if (spitz_jack_func == ucontrol->value.enumerated.item[0])
return 0;
spitz_jack_func = ucontrol->value.enumerated.item[0];
- spitz_ext_control(&card->dapm);
+ spitz_ext_control(dapm);
return 1;
}
@@ -186,12 +188,13 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
if (spitz_spk_func == ucontrol->value.enumerated.item[0])
return 0;
spitz_spk_func = ucontrol->value.enumerated.item[0];
- spitz_ext_control(&card->dapm);
+ spitz_ext_control(dapm);
return 1;
}
@@ -260,7 +263,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/Kconfig b/sound/soc/qcom/Kconfig
index e7b00d1d9e99..e6e24f3b9922 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SND_SOC_QCOM
- tristate "ASoC support for QCOM platforms"
+ tristate "Qualcomm"
depends on ARCH_QCOM || COMPILE_TEST
help
Say Y or M if you want to add support to use audio devices
@@ -118,6 +118,22 @@ config SND_SOC_QDSP6_PRM
tristate
select SND_SOC_QDSP6_PRM_LPASS_CLOCKS
+config SND_SOC_QCOM_OFFLOAD_UTILS
+ tristate
+
+config SND_SOC_QDSP6_USB
+ tristate "SoC ALSA USB offloading backing for QDSP6"
+ depends on SND_SOC_USB
+ select AUXILIARY_BUS
+ select SND_SOC_QCOM_OFFLOAD_UTILS
+
+ help
+ Adds support for USB offloading for QDSP6 ASoC
+ based platform sound cards. This will enable the
+ Q6USB DPCM backend DAI link, which will interact
+ with the SoC USB framework to initialize a session
+ with active USB SND devices.
+
config SND_SOC_QDSP6
tristate "SoC ALSA audio driver for QDSP6"
depends on QCOM_APR
@@ -157,6 +173,7 @@ config SND_SOC_SDM845
depends on COMMON_CLK
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
+ select SND_SOC_QCOM_SDW
select SND_SOC_RT5663
select SND_SOC_MAX98927
imply SND_SOC_CROS_EC_CODEC
@@ -169,6 +186,7 @@ config SND_SOC_SM8250
tristate "SoC Machine driver for SM8250 boards"
depends on QCOM_APR && SOUNDWIRE
depends on COMMON_CLK
+ depends on SND_SOC_QCOM_OFFLOAD_UTILS || !SND_SOC_QCOM_OFFLOAD_UTILS
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
select SND_SOC_QCOM_SDW
@@ -208,6 +226,7 @@ config SND_SOC_SC7280
tristate "SoC Machine driver for SC7280 boards"
depends on I2C && SOUNDWIRE
select SND_SOC_QCOM_COMMON
+ select SND_SOC_QCOM_SDW
select SND_SOC_LPASS_SC7280
select SND_SOC_MAX98357A
select SND_SOC_WCD938X_SDW
@@ -221,4 +240,16 @@ config SND_SOC_SC7280
SC7280 SoC-based systems.
Say Y or M if you want to use audio device on this SoCs.
+config SND_SOC_X1E80100
+ tristate "SoC Machine driver for X1E80100 boards"
+ depends on QCOM_APR && SOUNDWIRE
+ depends on COMMON_CLK
+ select SND_SOC_QDSP6
+ select SND_SOC_QCOM_COMMON
+ select SND_SOC_QCOM_SDW
+ help
+ Add support for audio on Qualcomm Technologies Inc.
+ X1E80100 SoC-based systems.
+ Say Y or M if you want to use audio device on this SoCs.
+
endif #SND_SOC_QCOM
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 254350d9dc06..985ce2ae286b 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
# Platform
-snd-soc-lpass-cpu-objs := lpass-cpu.o
-snd-soc-lpass-cdc-dma-objs := lpass-cdc-dma.o
-snd-soc-lpass-hdmi-objs := lpass-hdmi.o
-snd-soc-lpass-platform-objs := lpass-platform.o
-snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
-snd-soc-lpass-apq8016-objs := lpass-apq8016.o
-snd-soc-lpass-sc7180-objs := lpass-sc7180.o
-snd-soc-lpass-sc7280-objs := lpass-sc7280.o
+snd-soc-lpass-cpu-y := lpass-cpu.o
+snd-soc-lpass-cdc-dma-y := lpass-cdc-dma.o
+snd-soc-lpass-hdmi-y := lpass-hdmi.o
+snd-soc-lpass-platform-y := lpass-platform.o
+snd-soc-lpass-ipq806x-y := lpass-ipq806x.o
+snd-soc-lpass-apq8016-y := lpass-apq8016.o
+snd-soc-lpass-sc7180-y := lpass-sc7180.o
+snd-soc-lpass-sc7280-y := lpass-sc7280.o
obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
obj-$(CONFIG_SND_SOC_LPASS_CDC_DMA) += snd-soc-lpass-cdc-dma.o
@@ -19,16 +19,18 @@ obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
obj-$(CONFIG_SND_SOC_LPASS_SC7280) += snd-soc-lpass-sc7280.o
# Machine
-snd-soc-storm-objs := storm.o
-snd-soc-apq8016-sbc-objs := apq8016_sbc.o
-snd-soc-apq8096-objs := apq8096.o
-snd-soc-sc7180-objs := sc7180.o
-snd-soc-sc7280-objs := sc7280.o
-snd-soc-sdm845-objs := sdm845.o
-snd-soc-sm8250-objs := sm8250.o
-snd-soc-sc8280xp-objs := sc8280xp.o
-snd-soc-qcom-common-objs := common.o
-snd-soc-qcom-sdw-objs := sdw.o
+snd-soc-storm-y := storm.o
+snd-soc-apq8016-sbc-y := apq8016_sbc.o
+snd-soc-apq8096-y := apq8096.o
+snd-soc-sc7180-y := sc7180.o
+snd-soc-sc7280-y := sc7280.o
+snd-soc-sdm845-y := sdm845.o
+snd-soc-sm8250-y := sm8250.o
+snd-soc-sc8280xp-y := sc8280xp.o
+snd-soc-qcom-common-y := common.o
+snd-soc-qcom-sdw-y := sdw.o
+snd-soc-x1e80100-y := x1e80100.o
+snd-soc-qcom-offload-utils-objs := usb_offload_utils.o
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
@@ -40,6 +42,8 @@ obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o
+obj-$(CONFIG_SND_SOC_X1E80100) += snd-soc-x1e80100.o
+obj-$(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) += snd-soc-qcom-offload-utils.o
#DSP lib
obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index e54b8961112f..3023cf180a75 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -16,6 +16,7 @@
#include <sound/soc.h>
#include <uapi/linux/input-event-codes.h>
#include <dt-bindings/sound/apq8016-lpass.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include "common.h"
#include "qdsp6/q6afe.h"
@@ -44,6 +45,17 @@ struct apq8016_sbc_data {
#define DEFAULT_MCLK_RATE 9600000
#define MI2S_BCLK_RATE 1536000
+static struct snd_soc_jack_pin apq8016_sbc_jack_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
{
struct snd_soc_dai *codec_dai;
@@ -90,13 +102,15 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
if (!pdata->jack_setup) {
struct snd_jack *jack;
- rval = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_HEADPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4,
- &pdata->jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4,
+ &pdata->jack,
+ apq8016_sbc_jack_pins,
+ ARRAY_SIZE(apq8016_sbc_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headphone Jack\n");
@@ -134,7 +148,7 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
return apq8016_dai_init(rtd, cpu_dai->id);
}
@@ -170,7 +184,7 @@ static int qdsp6_dai_get_lpass_id(struct snd_soc_dai *cpu_dai)
static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai));
@@ -178,10 +192,10 @@ static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd)
static int msm8916_qdsp6_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int mi2s, ret;
mi2s = qdsp6_dai_get_lpass_id(cpu_dai);
@@ -199,10 +213,10 @@ static int msm8916_qdsp6_startup(struct snd_pcm_substream *substream)
static void msm8916_qdsp6_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct apq8016_sbc_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int mi2s, ret;
mi2s = qdsp6_dai_get_lpass_id(cpu_dai);
@@ -255,8 +269,14 @@ static void msm8916_qdsp6_add_ops(struct snd_soc_card *card)
}
}
-static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+static const struct snd_kcontrol_new apq8016_sbc_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
@@ -285,6 +305,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
card->owner = THIS_MODULE;
card->dapm_widgets = apq8016_sbc_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets);
+ card->controls = apq8016_sbc_snd_controls;
+ card->num_controls = ARRAY_SIZE(apq8016_sbc_snd_controls);
ret = qcom_snd_parse_of(card);
if (ret)
@@ -322,4 +344,4 @@ module_platform_driver(apq8016_sbc_platform_driver);
MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 5d07b38f6d72..4f6594cc723c 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, Linaro Limited
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
@@ -30,9 +30,9 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
static int msm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
int ret = 0;
@@ -66,7 +66,7 @@ static const struct snd_soc_ops apq8096_ops = {
static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
/*
* Codec SLIMBUS configuration
@@ -142,4 +142,4 @@ static struct platform_driver msm_snd_apq8096_driver = {
module_platform_driver(msm_snd_apq8096_driver);
MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
MODULE_DESCRIPTION("APQ8096 ASoC Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index cab5a7937a57..7ee60a58a336 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -2,12 +2,27 @@
// Copyright (c) 2018, Linaro Limited.
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/module.h>
#include <sound/jack.h>
#include <linux/input-event-codes.h>
-#include "qdsp6/q6afe.h"
#include "common.h"
+#define NAME_SIZE 32
+
+static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("DP0 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP1 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP2 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP3 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP4 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP5 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP6 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP7 Jack", NULL),
+};
+
int qcom_snd_parse_of(struct snd_soc_card *card)
{
struct device_node *np;
@@ -29,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;
@@ -68,7 +83,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
link = card->dai_link;
for_each_available_child_of_node(dev->of_node, np) {
- dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
+ dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL);
if (!dlc) {
ret = -ENOMEM;
goto err_put_np;
@@ -96,22 +111,15 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
goto err;
}
- ret = of_parse_phandle_with_args(cpu, "sound-dai",
- "#sound-dai-cells", 0, &args);
- if (ret) {
- dev_err(card->dev, "%s: error getting cpu phandle\n", link->name);
- goto err;
- }
- link->cpus->of_node = args.np;
- link->id = args.args[0];
-
- ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name);
+ ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0);
if (ret) {
dev_err_probe(card->dev, ret,
"%s: error getting cpu dai name\n", link->name);
goto err;
}
+ link->id = args.args[0];
+
if (platform) {
link->platforms->of_node = of_parse_phandle(platform,
"sound-dai",
@@ -140,14 +148,13 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
}
} else {
/* DPCM frontend */
- link->codecs = &asoc_dummy_dlc;
+ link->codecs = &snd_soc_dummy_dlc;
link->num_codecs = 1;
link->dynamic = 1;
}
if (platform || !codec) {
/* DPCM */
- snd_soc_dai_link_set_capabilities(link);
link->ignore_suspend = 1;
link->nonatomic = 1;
}
@@ -160,6 +167,11 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
of_node_put(platform);
}
+ if (!card->dapm_widgets) {
+ card->dapm_widgets = qcom_jack_snd_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(qcom_jack_snd_widgets);
+ }
+
return 0;
err:
of_node_put(cpu);
@@ -186,8 +198,8 @@ static struct snd_soc_jack_pin qcom_headset_jack_pins[] = {
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
struct snd_soc_card *card = rtd->card;
int rval, i;
@@ -236,4 +248,31 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup);
-MODULE_LICENSE("GPL v2");
+
+int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_jack *dp_jack, int dp_pcm_id)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ char jack_name[NAME_SIZE];
+ int rval, i;
+
+ snprintf(jack_name, sizeof(jack_name), "DP%d Jack", dp_pcm_id);
+ rval = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, dp_jack);
+ if (rval)
+ return rval;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ rval = snd_soc_component_set_jack(codec_dai->component, dp_jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_dp_jack_setup);
+
+MODULE_DESCRIPTION("ASoC Qualcomm helper functions");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index d7f80ee5ae26..1b8d3f90bffa 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -9,5 +9,8 @@
int qcom_snd_parse_of(struct snd_soc_card *card);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup);
+int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_jack *dp_jack, int id);
+
#endif
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index abaf694ee9a3..b8f23414eb77 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
[MI2S_SECONDARY] = {
@@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
[MI2S_TERTIARY] = {
@@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
[MI2S_QUATERNARY] = {
@@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
};
@@ -127,7 +123,7 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
int direction, unsigned int dai_id)
{
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int chan = 0;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -161,7 +157,7 @@ static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan,
static int apq8016_lpass_init(struct platform_device *pdev)
{
struct lpass_data *drvdata = platform_get_drvdata(pdev);
- struct lpass_variant *variant = drvdata->variant;
+ const struct lpass_variant *variant = drvdata->variant;
struct device *dev = &pdev->dev;
int ret, i;
@@ -227,7 +223,7 @@ static int apq8016_lpass_exit(struct platform_device *pdev)
}
-static struct lpass_variant apq8016_data = {
+static const struct lpass_variant apq8016_data = {
.i2sctrl_reg_base = 0x1000,
.i2sctrl_reg_stride = 0x1000,
.i2s_ports = 4,
@@ -304,10 +300,10 @@ static struct platform_driver apq8016_lpass_cpu_platform_driver = {
.of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id),
},
.probe = asoc_qcom_lpass_cpu_platform_probe,
- .remove = asoc_qcom_lpass_cpu_platform_remove,
+ .remove = asoc_qcom_lpass_cpu_platform_remove,
};
module_platform_driver(apq8016_lpass_cpu_platform_driver);
MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass-cdc-dma.c b/sound/soc/qcom/lpass-cdc-dma.c
index 31b9f1c22bee..2dc8c75c4bf0 100644
--- a/sound/soc/qcom/lpass-cdc-dma.c
+++ b/sound/soc/qcom/lpass-cdc-dma.c
@@ -5,6 +5,7 @@
* lpass-cdc-dma.c -- ALSA SoC CDC DMA CPU DAI driver for QTi LPASS
*/
+#include <dt-bindings/sound/qcom,lpass.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/export.h>
@@ -32,12 +33,12 @@ enum codec_dma_interfaces {
static void __lpass_get_dmactl_handle(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
struct lpaif_dmactl **dmactl, int *id)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int dai_id = cpu_dai->driver->id;
switch (dai_id) {
@@ -122,8 +123,8 @@ static int __lpass_get_codec_dma_intf_type(int dai_id)
static int __lpass_platform_codec_intf_init(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpaif_dmactl *dmactl = NULL;
struct device *dev = soc_runtime->dev;
int ret, id, codec_intf;
@@ -171,7 +172,7 @@ static int lpass_cdc_dma_daiops_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
switch (dai->id) {
case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
@@ -194,7 +195,7 @@ static void lpass_cdc_dma_daiops_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
switch (dai->id) {
case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
@@ -214,10 +215,11 @@ static int lpass_cdc_dma_daiops_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
struct lpaif_dmactl *dmactl = NULL;
- unsigned int ret, regval;
+ unsigned int regval;
unsigned int channels = params_channels(params);
+ int ret;
int id;
switch (channels) {
@@ -257,8 +259,8 @@ static int lpass_cdc_dma_daiops_hw_params(struct snd_pcm_substream *substream,
static int lpass_cdc_dma_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct lpaif_dmactl *dmactl;
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct lpaif_dmactl *dmactl = NULL;
int ret = 0, id;
switch (cmd) {
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index dbdaaa85ce48..242bc16da36d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -5,11 +5,11 @@
* lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
*/
+#include <dt-bindings/sound/qcom,lpass.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -44,7 +44,7 @@ static int lpass_cpu_init_i2sctl_bitfields(struct device *dev,
struct lpaif_i2sctl *i2sctl, struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback);
i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken);
@@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
return 0;
}
-const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
- .set_sysclk = lpass_cpu_daiops_set_sysclk,
- .startup = lpass_cpu_daiops_startup,
- .shutdown = lpass_cpu_daiops_shutdown,
- .hw_params = lpass_cpu_daiops_hw_params,
- .trigger = lpass_cpu_daiops_trigger,
- .prepare = lpass_cpu_daiops_prepare,
-};
-EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
-
-int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai)
+static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
int ret;
struct snd_soc_dai_driver *drv = dai->driver;
@@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new);
-int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai)
{
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
int ret;
@@ -446,14 +434,36 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
return ret;
}
-EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
+ .probe = lpass_cpu_daiops_probe,
+ .set_sysclk = lpass_cpu_daiops_set_sysclk,
+ .startup = lpass_cpu_daiops_startup,
+ .shutdown = lpass_cpu_daiops_shutdown,
+ .hw_params = lpass_cpu_daiops_hw_params,
+ .trigger = lpass_cpu_daiops_trigger,
+ .prepare = lpass_cpu_daiops_prepare,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = {
+ .pcm_new = lpass_cpu_daiops_pcm_new,
+ .probe = lpass_cpu_daiops_probe,
+ .set_sysclk = lpass_cpu_daiops_set_sysclk,
+ .startup = lpass_cpu_daiops_startup,
+ .shutdown = lpass_cpu_daiops_shutdown,
+ .hw_params = lpass_cpu_daiops_hw_params,
+ .trigger = lpass_cpu_daiops_trigger,
+ .prepare = lpass_cpu_daiops_prepare,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2);
static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
const struct of_phandle_args *args,
const char **dai_name)
{
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
- struct lpass_variant *variant = drvdata->variant;
+ const struct lpass_variant *variant = drvdata->variant;
int id = args->args[0];
int ret = -EINVAL;
int i;
@@ -478,7 +488,7 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->i2s_ports; ++i)
@@ -520,7 +530,7 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->i2s_ports; ++i)
@@ -568,7 +578,7 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->irq_ports; ++i) {
@@ -603,7 +613,7 @@ static struct regmap_config lpass_cpu_regmap_config = {
static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int i;
struct lpass_hdmi_tx_ctl *tx_ctl;
struct regmap_field *legacy_en;
@@ -681,7 +691,7 @@ static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
@@ -726,7 +736,7 @@ static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
@@ -775,7 +785,7 @@ static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
@@ -814,7 +824,7 @@ static struct regmap_config lpass_hdmi_regmap_config = {
static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->rxtx_irq_ports; ++i) {
@@ -880,7 +890,7 @@ static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->rxtx_irq_ports; ++i) {
@@ -905,7 +915,7 @@ static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->va_irq_ports; ++i) {
@@ -955,7 +965,7 @@ static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int i;
for (i = 0; i < v->va_irq_ports; ++i) {
@@ -1094,9 +1104,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
struct lpass_data *drvdata;
struct device_node *dsp_of_node;
struct resource *res;
- struct lpass_variant *variant;
+ const struct lpass_variant *variant;
struct device *dev = &pdev->dev;
- const struct of_device_id *match;
int ret, i, dai_id;
dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
@@ -1111,17 +1120,14 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, drvdata);
- match = of_match_device(dev->driver->of_match_table, dev);
- if (!match || !match->data)
+ variant = device_get_match_data(dev);
+ if (!variant)
return -EINVAL;
- if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) {
- dev_warn(dev, "%s compatible is deprecated\n",
- match->compatible);
- }
+ if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016"))
+ dev_warn(dev, "qcom,lpass-cpu-apq8016 compatible is deprecated\n");
- drvdata->variant = (struct lpass_variant *)match->data;
- variant = drvdata->variant;
+ drvdata->variant = variant;
of_lpass_cpu_parse_dai_data(dev, drvdata);
@@ -1160,9 +1166,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
+ if (!res)
+ return -EINVAL;
drvdata->rxtx_cdc_dma_lpm_buf = res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
+ if (!res)
+ return -EINVAL;
drvdata->va_cdc_dma_lpm_buf = res->start;
}
@@ -1232,6 +1242,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
/* Allocation for i2sctl regmap fields */
drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
GFP_KERNEL);
+ if (!drvdata->i2sctl)
+ return -ENOMEM;
/* Initialize bitfields for dai I2SCTL register */
ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
@@ -1268,15 +1280,12 @@ err:
}
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
-int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
+void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
{
struct lpass_data *drvdata = platform_get_drvdata(pdev);
if (drvdata->variant->exit)
drvdata->variant->exit(pdev);
-
-
- return 0;
}
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
@@ -1291,4 +1300,4 @@ void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown);
MODULE_DESCRIPTION("QTi LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c
index 24b1a7523adb..6d9795306cfa 100644
--- a/sound/soc/qcom/lpass-hdmi.c
+++ b/sound/soc/qcom/lpass-hdmi.c
@@ -23,7 +23,6 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
snd_pcm_format_t format = params_format(params);
unsigned int rate = params_rate(params);
unsigned int channels = params_channels(params);
- unsigned int ret;
int bitwidth;
unsigned int word_length;
unsigned int ch_sts_buf0;
@@ -33,6 +32,7 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
unsigned int ch = 0;
struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;
struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;
+ int ret;
bitwidth = snd_pcm_format_width(format);
if (bitwidth < 0) {
@@ -251,4 +251,4 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index ef8a7984f232..e57d29ea4ce7 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
};
@@ -109,7 +108,7 @@ static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan,
return 0;
}
-static struct lpass_variant ipq806x_data = {
+static const struct lpass_variant ipq806x_data = {
.i2sctrl_reg_base = 0x0010,
.i2sctrl_reg_stride = 0x04,
.i2s_ports = 5,
@@ -173,9 +172,9 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
.of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id),
},
.probe = asoc_qcom_lpass_cpu_platform_probe,
- .remove = asoc_qcom_lpass_cpu_platform_remove,
+ .remove = asoc_qcom_lpass_cpu_platform_remove,
};
module_platform_driver(ipq806x_lpass_cpu_platform_driver);
MODULE_DESCRIPTION("QTi LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index ef5cb40b2d9b..b456e096f138 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -5,6 +5,7 @@
* lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
*/
+#include <dt-bindings/sound/qcom,lpass.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/kernel.h>
@@ -100,7 +101,7 @@ static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
int rval;
@@ -128,7 +129,7 @@ static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpaif_dmactl *wr_dmactl;
wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
@@ -145,7 +146,7 @@ static int lpass_platform_alloc_dmactl_fields(struct device *dev,
struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
int rval;
@@ -175,7 +176,7 @@ static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,
struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpaif_dmactl *rd_dmactl;
rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL);
@@ -192,16 +193,15 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int ret, dma_ch, dir = substream->stream;
struct lpass_pcm_data *data;
struct regmap *map;
unsigned int dai_id = cpu_dai->driver->id;
- component->id = dai_id;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -284,10 +284,10 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpass_pcm_data *data;
unsigned int dai_id = cpu_dai->driver->id;
@@ -321,8 +321,8 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
static struct lpaif_dmactl *__lpass_get_dmactl_handle(const struct snd_pcm_substream *substream,
struct snd_soc_component *component)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct lpaif_dmactl *dmactl = NULL;
@@ -353,12 +353,12 @@ static struct lpaif_dmactl *__lpass_get_dmactl_handle(const struct snd_pcm_subst
static int __lpass_get_id(const struct snd_pcm_substream *substream,
struct snd_soc_component *component)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int id;
switch (cpu_dai->driver->id) {
@@ -388,8 +388,8 @@ static int __lpass_get_id(const struct snd_pcm_substream *substream,
static struct regmap *__lpass_get_regmap_handle(const struct snd_pcm_substream *substream,
struct snd_soc_component *component)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct regmap *map = NULL;
@@ -416,12 +416,12 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
snd_pcm_format_t format = params_format(params);
unsigned int channels = params_channels(params);
unsigned int regval;
@@ -569,12 +569,12 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int reg;
int ret;
struct regmap *map;
@@ -597,12 +597,12 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpaif_dmactl *dmactl;
struct regmap *map;
int ret, id, ch, dir = substream->stream;
@@ -660,12 +660,12 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
int cmd)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
struct lpaif_dmactl *dmactl;
struct regmap *map;
int ret, ch, id;
@@ -859,12 +859,12 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int base_addr, curr_addr;
int ret, ch, dir = substream->stream;
struct regmap *map;
@@ -911,8 +911,8 @@ static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
unsigned int dai_id = cpu_dai->driver->id;
if (is_cdc_dma_port(dai_id))
@@ -926,9 +926,9 @@ static irqreturn_t lpass_dma_interrupt_handler(
struct lpass_data *drvdata,
int chan, u32 interrupts)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
- struct lpass_variant *v = drvdata->variant;
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ const struct lpass_variant *v = drvdata->variant;
irqreturn_t ret = IRQ_NONE;
int rv;
unsigned int reg, val, mask;
@@ -1020,7 +1020,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
{
struct lpass_data *drvdata = data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int irqs;
int rv, chan;
@@ -1048,7 +1048,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
{
struct lpass_data *drvdata = data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int irqs;
int rv, chan;
@@ -1078,7 +1078,7 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
{
struct lpass_data *drvdata = data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int irqs;
irqreturn_t rv;
int chan;
@@ -1103,7 +1103,7 @@ static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
{
struct lpass_data *drvdata = data;
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
unsigned int irqs;
irqreturn_t rv;
int chan;
@@ -1169,7 +1169,7 @@ static int lpass_platform_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *soc_runtime)
{
struct snd_pcm *pcm = soc_runtime->pcm;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
unsigned int dai_id = cpu_dai->driver->id;
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
@@ -1189,13 +1189,14 @@ static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
{
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct regmap *map;
- unsigned int dai_id = component->id;
- if (dai_id == LPASS_DP_RX)
+ if (drvdata->hdmi_port_enable) {
map = drvdata->hdmiif_map;
- else
- map = drvdata->lpaif_map;
+ regcache_cache_only(map, true);
+ regcache_mark_dirty(map);
+ }
+ map = drvdata->lpaif_map;
regcache_cache_only(map, true);
regcache_mark_dirty(map);
@@ -1206,23 +1207,31 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
{
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct regmap *map;
- unsigned int dai_id = component->id;
+ int ret;
- if (dai_id == LPASS_DP_RX)
+ if (drvdata->hdmi_port_enable) {
map = drvdata->hdmiif_map;
- else
- map = drvdata->lpaif_map;
+ regcache_cache_only(map, false);
+ ret = regcache_sync(map);
+ if (ret)
+ return ret;
+ }
+ map = drvdata->lpaif_map;
regcache_cache_only(map, false);
+
return regcache_sync(map);
}
static int lpass_platform_copy(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int channel,
- unsigned long pos, void __user *buf, unsigned long bytes)
+ unsigned long pos, struct iov_iter *buf,
+ unsigned long bytes)
{
struct snd_pcm_runtime *rt = substream->runtime;
- unsigned int dai_id = component->id;
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ unsigned int dai_id = cpu_dai->driver->id;
int ret = 0;
void __iomem *dma_buf = (void __iomem *) (rt->dma_area + pos +
@@ -1230,16 +1239,18 @@ 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_user_toio(dma_buf, buf, bytes);
+ if (copy_from_iter_toio(dma_buf, bytes, buf) != bytes)
+ ret = -EFAULT;
} else {
- if (copy_from_user((void __force *)dma_buf, buf, bytes))
+ 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_user_fromio(buf, dma_buf, bytes);
+ if (copy_to_iter_fromio(dma_buf, bytes, buf) != bytes)
+ ret = -EFAULT;
} else {
- if (copy_to_user(buf, (void __force *)dma_buf, bytes))
+ if (copy_to_iter((void __force *)dma_buf, bytes, buf) != bytes)
ret = -EFAULT;
}
}
@@ -1260,14 +1271,14 @@ static const struct snd_soc_component_driver lpass_component_driver = {
.pcm_construct = lpass_platform_pcm_new,
.suspend = lpass_platform_pcmops_suspend,
.resume = lpass_platform_pcmops_resume,
- .copy_user = lpass_platform_copy,
+ .copy = lpass_platform_copy,
};
int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
{
struct lpass_data *drvdata = platform_get_drvdata(pdev);
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int ret;
drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
@@ -1382,4 +1393,4 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
MODULE_DESCRIPTION("QTi LPASS Platform Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index 56db852f4eab..7c6a9b0fda89 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
}, {
.id = MI2S_SECONDARY,
@@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
- .ops = &asoc_qcom_lpass_cpu_dai_ops,
- .pcm_new = lpass_cpu_pcm_new,
+ .ops = &asoc_qcom_lpass_cpu_dai_ops2,
}, {
.id = LPASS_DP_RX,
.name = "Hdmi",
@@ -79,7 +76,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
static int sc7180_lpass_alloc_dma_channel(struct lpass_data *drvdata,
int direction, unsigned int dai_id)
{
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int chan = 0;
if (dai_id == LPASS_DP_RX) {
@@ -126,7 +123,7 @@ static int sc7180_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, u
static int sc7180_lpass_init(struct platform_device *pdev)
{
struct lpass_data *drvdata = platform_get_drvdata(pdev);
- struct lpass_variant *variant = drvdata->variant;
+ const struct lpass_variant *variant = drvdata->variant;
struct device *dev = &pdev->dev;
int ret, i;
@@ -163,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);
@@ -179,10 +176,10 @@ 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 struct lpass_variant sc7180_data = {
+static const struct lpass_variant sc7180_data = {
.i2sctrl_reg_base = 0x1000,
.i2sctrl_reg_stride = 0x1000,
.i2s_ports = 3,
@@ -315,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,
@@ -325,4 +322,4 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = {
module_platform_driver(sc7180_lpass_cpu_platform_driver);
MODULE_DESCRIPTION("SC7180 LPASS CPU DRIVER");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
index bcf18fe8e14d..817c824f9179 100644
--- a/sound/soc/qcom/lpass-sc7280.c
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
}, {
.id = MI2S_SECONDARY,
@@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
}, {
.id = LPASS_DP_RX,
@@ -112,7 +110,7 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
static int sc7280_lpass_alloc_dma_channel(struct lpass_data *drvdata,
int direction, unsigned int dai_id)
{
- struct lpass_variant *v = drvdata->variant;
+ const struct lpass_variant *v = drvdata->variant;
int chan = 0;
switch (dai_id) {
@@ -198,7 +196,7 @@ static int sc7280_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, u
static int sc7280_lpass_init(struct platform_device *pdev)
{
struct lpass_data *drvdata = platform_get_drvdata(pdev);
- struct lpass_variant *variant = drvdata->variant;
+ const struct lpass_variant *variant = drvdata->variant;
struct device *dev = &pdev->dev;
int ret, i;
@@ -235,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);
@@ -251,10 +249,10 @@ 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 struct lpass_variant sc7280_data = {
+static const struct lpass_variant sc7280_data = {
.i2sctrl_reg_base = 0x1000,
.i2sctrl_reg_stride = 0x1000,
.i2s_ports = 3,
@@ -444,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/lpass.h b/sound/soc/qcom/lpass.h
index dd78600fc7b0..de3ec6f594c1 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -13,10 +13,11 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <dt-bindings/sound/qcom,lpass.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include "lpass-hdmi.h"
#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
-#define LPASS_MAX_PORTS (LPASS_CDC_DMA_VA_TX8 + 1)
+#define LPASS_MAX_PORTS (DISPLAY_PORT_RX_7 + 1)
#define LPASS_MAX_MI2S_PORTS (8)
#define LPASS_MAX_DMA_CHANNELS (8)
#define LPASS_MAX_HDMI_DMA_CHANNELS (4)
@@ -139,7 +140,7 @@ struct lpass_data {
int vaif_irq;
/* SOC specific variations in the LPASS IP integration */
- struct lpass_variant *variant;
+ const struct lpass_variant *variant;
/* bit map to keep track of static channel allocations */
unsigned long dma_ch_bit_map;
@@ -398,14 +399,12 @@ struct lpass_pcm_data {
};
/* register the platform driver from the CPU DAI driver */
-int asoc_qcom_lpass_platform_register(struct platform_device *);
-int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
+int asoc_qcom_lpass_platform_register(struct platform_device *pdev);
+void asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev);
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
-int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
-int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai);
+extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2;
extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops;
#endif /* __LPASS_H__ */
diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile
index 3963bf234664..67267304e7e9 100644
--- a/sound/soc/qcom/qdsp6/Makefile
+++ b/sound/soc/qcom/qdsp6/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-q6dsp-common-objs := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o
-snd-q6apm-objs := q6apm.o audioreach.o topology.o
+snd-q6dsp-common-y := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o
+snd-q6apm-y := q6apm.o audioreach.o topology.o
obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += snd-q6dsp-common.o
obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o
@@ -17,3 +17,4 @@ obj-$(CONFIG_SND_SOC_QDSP6_APM_DAI) += q6apm-dai.o
obj-$(CONFIG_SND_SOC_QDSP6_APM_LPASS_DAI) += q6apm-lpass-dais.o
obj-$(CONFIG_SND_SOC_QDSP6_PRM) += q6prm.o
obj-$(CONFIG_SND_SOC_QDSP6_PRM_LPASS_CLOCKS) += q6prm-clocks.o
+obj-$(CONFIG_SND_SOC_QDSP6_USB) += q6usb.o
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 8d9410dcbd45..ded49124581b 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -267,6 +267,22 @@ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token
}
EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt);
+void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels)
+{
+ if (num_channels == 1) {
+ ch_map[0] = PCM_CHANNEL_FL;
+ } else if (num_channels == 2) {
+ ch_map[0] = PCM_CHANNEL_FL;
+ ch_map[1] = PCM_CHANNEL_FR;
+ } else if (num_channels == 4) {
+ ch_map[0] = PCM_CHANNEL_FL;
+ ch_map[1] = PCM_CHANNEL_FR;
+ ch_map[2] = PCM_CHANNEL_LS;
+ ch_map[3] = PCM_CHANNEL_RS;
+ }
+}
+EXPORT_SYMBOL_GPL(audioreach_set_default_channel_mapping);
+
static void apm_populate_container_config(struct apm_container_obj *cfg,
struct audioreach_container *cont)
{
@@ -596,19 +612,12 @@ static int audioreach_display_port_set_media_format(struct q6apm_graph *graph,
struct apm_module_frame_size_factor_cfg *fs_cfg;
struct apm_module_param_data *param_data;
struct apm_module_hw_ep_mf_cfg *hw_cfg;
- int ic_sz, ep_sz, fs_sz, dl_sz;
- int rc, payload_size;
- struct gpr_pkt *pkt;
+ int ic_sz = APM_DP_INTF_CFG_PSIZE;
+ int ep_sz = APM_HW_EP_CFG_PSIZE;
+ int fs_sz = APM_FS_CFG_PSIZE;
+ int size = ic_sz + ep_sz + fs_sz;
void *p;
-
- ic_sz = APM_DP_INTF_CFG_PSIZE;
- ep_sz = APM_HW_EP_CFG_PSIZE;
- fs_sz = APM_FS_CFG_PSIZE;
- dl_sz = 0;
-
- payload_size = ic_sz + ep_sz + fs_sz + dl_sz;
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -647,11 +656,7 @@ static int audioreach_display_port_set_media_format(struct q6apm_graph *graph,
intf_cfg->cfg.mst_idx = 0;
intf_cfg->cfg.dptx_idx = cfg->dp_idx;
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
/* LPASS Codec DMA port Module Media Format Setup */
@@ -664,20 +669,13 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
struct apm_module_hw_ep_power_mode_cfg *pm_cfg;
struct apm_module_param_data *param_data;
struct apm_module_hw_ep_mf_cfg *hw_cfg;
- int ic_sz, ep_sz, fs_sz, pm_sz, dl_sz;
- int rc, payload_size;
- struct gpr_pkt *pkt;
+ int ic_sz = APM_CDMA_INTF_CFG_PSIZE;
+ int ep_sz = APM_HW_EP_CFG_PSIZE;
+ int fs_sz = APM_FS_CFG_PSIZE;
+ int pm_sz = APM_HW_EP_PMODE_CFG_PSIZE;
+ int size = ic_sz + ep_sz + fs_sz + pm_sz;
void *p;
-
- ic_sz = APM_CDMA_INTF_CFG_PSIZE;
- ep_sz = APM_HW_EP_CFG_PSIZE;
- fs_sz = APM_FS_CFG_PSIZE;
- pm_sz = APM_HW_EP_PMODE_CFG_PSIZE;
- dl_sz = 0;
-
- payload_size = ic_sz + ep_sz + fs_sz + pm_sz + dl_sz;
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -725,118 +723,80 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
param_data->param_size = pm_sz - APM_MODULE_PARAM_DATA_SIZE;
pm_cfg->power_mode.power_mode = 0;
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
-static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
- struct audioreach_module *module, bool enable)
+int audioreach_send_u32_param(struct q6apm_graph *graph, struct audioreach_module *module,
+ uint32_t param_id, uint32_t param_val)
{
struct apm_module_param_data *param_data;
- struct param_id_sal_limiter_enable *limiter_enable;
- int payload_size;
- struct gpr_pkt *pkt;
- int rc;
- void *p;
-
- payload_size = sizeof(*limiter_enable) + APM_MODULE_PARAM_DATA_SIZE;
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
- if (IS_ERR(pkt))
- return PTR_ERR(pkt);
+ struct gpr_pkt *pkt __free(kfree) = NULL;
+ uint32_t *param;
+ int payload_size = sizeof(uint32_t) + APM_MODULE_PARAM_DATA_SIZE;
+ void *p = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(p))
+ return -ENOMEM;
- p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+ pkt = p;
+ p = p + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
param_data = p;
param_data->module_instance_id = module->instance_id;
param_data->error_code = 0;
- param_data->param_id = PARAM_ID_SAL_LIMITER_ENABLE;
- param_data->param_size = sizeof(*limiter_enable);
- p = p + APM_MODULE_PARAM_DATA_SIZE;
- limiter_enable = p;
+ param_data->param_id = param_id;
+ param_data->param_size = sizeof(uint32_t);
- limiter_enable->enable_lim = enable;
-
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ param = p;
+ *param = param_val;
- kfree(pkt);
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
+}
+EXPORT_SYMBOL_GPL(audioreach_send_u32_param);
- return rc;
+static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
+ struct audioreach_module *module, bool enable)
+{
+ return audioreach_send_u32_param(graph, module, PARAM_ID_SAL_LIMITER_ENABLE, enable);
}
static int audioreach_sal_set_media_format(struct q6apm_graph *graph,
struct audioreach_module *module,
struct audioreach_module_config *cfg)
{
- struct apm_module_param_data *param_data;
- struct param_id_sal_output_config *media_format;
- int payload_size;
- struct gpr_pkt *pkt;
- int rc;
- void *p;
-
- payload_size = sizeof(*media_format) + APM_MODULE_PARAM_DATA_SIZE;
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
- if (IS_ERR(pkt))
- return PTR_ERR(pkt);
-
- p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
-
- param_data = p;
- param_data->module_instance_id = module->instance_id;
- param_data->error_code = 0;
- param_data->param_id = PARAM_ID_SAL_OUTPUT_CFG;
- param_data->param_size = sizeof(*media_format);
- p = p + APM_MODULE_PARAM_DATA_SIZE;
- media_format = p;
-
- media_format->bits_per_sample = cfg->bit_width;
-
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return audioreach_send_u32_param(graph, module, PARAM_ID_SAL_OUTPUT_CFG, cfg->bit_width);
}
static int audioreach_module_enable(struct q6apm_graph *graph,
struct audioreach_module *module,
bool enable)
{
- struct apm_module_param_data *param_data;
- struct param_id_module_enable *param;
- int payload_size;
- struct gpr_pkt *pkt;
- int rc;
- void *p;
+ return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, enable);
+}
- payload_size = sizeof(*param) + APM_MODULE_PARAM_DATA_SIZE;
+static int audioreach_gapless_set_media_format(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ struct audioreach_module_config *cfg)
+{
+ return audioreach_send_u32_param(graph, module, PARAM_ID_EARLY_EOS_DELAY,
+ EARLY_EOS_DELAY_MS);
+}
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+static int audioreach_set_module_config(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ struct audioreach_module_config *cfg)
+{
+ int size = le32_to_cpu(module->data->size);
+ void *p;
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
- param_data = p;
- param_data->module_instance_id = module->instance_id;
- param_data->error_code = 0;
- param_data->param_id = PARAM_ID_MODULE_ENABLE;
- param_data->param_size = sizeof(*param);
- p = p + APM_MODULE_PARAM_DATA_SIZE;
- param = p;
-
- param->enable = enable;
+ memcpy(p, module->data->data, size);
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
@@ -846,15 +806,11 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
struct apm_module_param_data *param_data;
struct param_id_mfc_media_format *media_format;
uint32_t num_channels = cfg->num_channels;
- int payload_size;
- struct gpr_pkt *pkt;
- int rc;
+ int payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
+ APM_MODULE_PARAM_DATA_SIZE;
+ int i;
void *p;
-
- payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
- APM_MODULE_PARAM_DATA_SIZE;
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -871,20 +827,117 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
media_format->sample_rate = cfg->sample_rate;
media_format->bit_width = cfg->bit_width;
media_format->num_channels = cfg->num_channels;
+ for (i = 0; i < num_channels; i++)
+ media_format->channel_mapping[i] = cfg->channel_map[i];
- if (num_channels == 1) {
- media_format->channel_mapping[0] = PCM_CHANNEL_L;
- } else if (num_channels == 2) {
- media_format->channel_mapping[0] = PCM_CHANNEL_L;
- media_format->channel_mapping[1] = PCM_CHANNEL_R;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
+}
+
+static int audioreach_set_compr_media_format(struct media_format *media_fmt_hdr,
+ void *p, struct audioreach_module_config *mcfg)
+{
+ struct payload_media_fmt_aac_t *aac_cfg;
+ struct payload_media_fmt_pcm *mp3_cfg;
+ struct payload_media_fmt_flac_t *flac_cfg;
+ struct payload_media_fmt_opus_t *opus_cfg;
+
+ switch (mcfg->fmt) {
+ case SND_AUDIOCODEC_MP3:
+ media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
+ media_fmt_hdr->fmt_id = MEDIA_FMT_ID_MP3;
+ media_fmt_hdr->payload_size = 0;
+ p = p + sizeof(*media_fmt_hdr);
+ mp3_cfg = p;
+ mp3_cfg->sample_rate = mcfg->sample_rate;
+ mp3_cfg->bit_width = mcfg->bit_width;
+ mp3_cfg->alignment = PCM_LSB_ALIGNED;
+ mp3_cfg->bits_per_sample = mcfg->bit_width;
+ mp3_cfg->q_factor = mcfg->bit_width - 1;
+ mp3_cfg->endianness = PCM_LITTLE_ENDIAN;
+ mp3_cfg->num_channels = mcfg->num_channels;
+ break;
+ case SND_AUDIOCODEC_AAC:
+ media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
+ media_fmt_hdr->fmt_id = MEDIA_FMT_ID_AAC;
+ media_fmt_hdr->payload_size = sizeof(struct payload_media_fmt_aac_t);
+ p = p + sizeof(*media_fmt_hdr);
+ aac_cfg = p;
+ aac_cfg->aac_fmt_flag = 0;
+ aac_cfg->audio_obj_type = 5;
+ aac_cfg->num_channels = mcfg->num_channels;
+ aac_cfg->total_size_of_PCE_bits = 0;
+ aac_cfg->sample_rate = mcfg->sample_rate;
+ break;
+ case SND_AUDIOCODEC_FLAC:
+ media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
+ media_fmt_hdr->fmt_id = MEDIA_FMT_ID_FLAC;
+ media_fmt_hdr->payload_size = sizeof(struct payload_media_fmt_flac_t);
+ p = p + sizeof(*media_fmt_hdr);
+ flac_cfg = p;
+ flac_cfg->sample_size = mcfg->codec.options.flac_d.sample_size;
+ flac_cfg->num_channels = mcfg->num_channels;
+ flac_cfg->min_blk_size = mcfg->codec.options.flac_d.min_blk_size;
+ flac_cfg->max_blk_size = mcfg->codec.options.flac_d.max_blk_size;
+ flac_cfg->sample_rate = mcfg->sample_rate;
+ flac_cfg->min_frame_size = mcfg->codec.options.flac_d.min_frame_size;
+ flac_cfg->max_frame_size = mcfg->codec.options.flac_d.max_frame_size;
+ break;
+ case SND_AUDIOCODEC_OPUS_RAW:
+ media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED;
+ media_fmt_hdr->fmt_id = MEDIA_FMT_ID_OPUS;
+ media_fmt_hdr->payload_size = sizeof(*opus_cfg);
+ p = p + sizeof(*media_fmt_hdr);
+ opus_cfg = p;
+ /* raw opus packets prepended with 4 bytes of length */
+ opus_cfg->bitstream_format = 1;
+ /*
+ * payload_type:
+ * 0 -- read metadata from opus stream;
+ * 1 -- metadata is provided by filling in the struct here.
+ */
+ opus_cfg->payload_type = 1;
+ opus_cfg->version = mcfg->codec.options.opus_d.version;
+ opus_cfg->num_channels = mcfg->codec.options.opus_d.num_channels;
+ opus_cfg->pre_skip = mcfg->codec.options.opus_d.pre_skip;
+ opus_cfg->sample_rate = mcfg->codec.options.opus_d.sample_rate;
+ opus_cfg->output_gain = mcfg->codec.options.opus_d.output_gain;
+ opus_cfg->mapping_family = mcfg->codec.options.opus_d.mapping_family;
+ opus_cfg->stream_count = mcfg->codec.options.opus_d.chan_map.stream_count;
+ opus_cfg->coupled_count = mcfg->codec.options.opus_d.chan_map.coupled_count;
+ memcpy(opus_cfg->channel_mapping, mcfg->codec.options.opus_d.chan_map.channel_map,
+ sizeof(opus_cfg->channel_mapping));
+ opus_cfg->reserved[0] = opus_cfg->reserved[1] = opus_cfg->reserved[2] = 0;
+ break;
+ default:
+ return -EINVAL;
}
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+ return 0;
+}
- kfree(pkt);
+int audioreach_compr_set_param(struct q6apm_graph *graph, struct audioreach_module_config *mcfg)
+{
+ struct media_format *header;
+ int rc;
+ void *p;
+ int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
+ int payload_size = sizeof(struct apm_sh_module_media_fmt_cmd);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_cmd_pkt(payload_size,
+ DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT,
+ 0, graph->port->id, iid);
+ if (IS_ERR(pkt))
+ return -ENOMEM;
- return rc;
+
+ p = (void *)pkt + GPR_HDR_SIZE;
+ header = p;
+ rc = audioreach_set_compr_media_format(header, p, mcfg);
+ if (rc)
+ return rc;
+
+ return gpr_send_port_pkt(graph->port, pkt);
}
+EXPORT_SYMBOL_GPL(audioreach_compr_set_param);
static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
struct audioreach_module *module,
@@ -894,18 +947,12 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
struct apm_module_param_data *param_data;
struct apm_i2s_module_intf_cfg *intf_cfg;
struct apm_module_hw_ep_mf_cfg *hw_cfg;
- int ic_sz, ep_sz, fs_sz;
- int rc, payload_size;
- struct gpr_pkt *pkt;
+ int ic_sz = APM_I2S_INTF_CFG_PSIZE;
+ int ep_sz = APM_HW_EP_CFG_PSIZE;
+ int fs_sz = APM_FS_CFG_PSIZE;
+ int size = ic_sz + ep_sz + fs_sz;
void *p;
-
- ic_sz = APM_I2S_INTF_CFG_PSIZE;
- ep_sz = APM_HW_EP_CFG_PSIZE;
- fs_sz = APM_FS_CFG_PSIZE;
-
- payload_size = ic_sz + ep_sz + fs_sz;
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -918,6 +965,7 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
param_data->param_id = PARAM_ID_I2S_INTF_CFG;
param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE;
+ intf_cfg->cfg.lpaif_type = module->hw_interface_type;
intf_cfg->cfg.intf_idx = module->hw_interface_idx;
intf_cfg->cfg.sd_line_idx = module->sd_line_idx;
@@ -955,11 +1003,7 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE;
fs_cfg->frame_size_factor = 1;
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
static int audioreach_logging_set_media_format(struct q6apm_graph *graph,
@@ -967,12 +1011,9 @@ static int audioreach_logging_set_media_format(struct q6apm_graph *graph,
{
struct apm_module_param_data *param_data;
struct data_logging_config *cfg;
- int rc, payload_size;
- struct gpr_pkt *pkt;
+ int size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
void *p;
-
- payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -982,7 +1023,7 @@ static int audioreach_logging_set_media_format(struct q6apm_graph *graph,
param_data->module_instance_id = module->instance_id;
param_data->error_code = 0;
param_data->param_id = PARAM_ID_DATA_LOGGING_CONFIG;
- param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
+ param_data->param_size = size - APM_MODULE_PARAM_DATA_SIZE;
p = p + APM_MODULE_PARAM_DATA_SIZE;
cfg = p;
@@ -990,11 +1031,7 @@ static int audioreach_logging_set_media_format(struct q6apm_graph *graph,
cfg->log_tap_point_id = module->log_tap_point_id;
cfg->mode = module->log_mode;
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
@@ -1005,10 +1042,10 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
uint32_t num_channels = mcfg->num_channels;
struct apm_pcm_module_media_fmt_cmd *cfg;
struct apm_module_param_data *param_data;
- int rc, payload_size;
- struct gpr_pkt *pkt;
+ int payload_size;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
- if (num_channels > 2) {
+ if (num_channels > 4) {
dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels);
return -EINVAL;
}
@@ -1039,20 +1076,9 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
media_cfg->num_channels = mcfg->num_channels;
media_cfg->q_factor = mcfg->bit_width - 1;
media_cfg->bits_per_sample = mcfg->bit_width;
+ memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
- if (num_channels == 1) {
- media_cfg->channel_mapping[0] = PCM_CHANNEL_L;
- } else if (num_channels == 2) {
- media_cfg->channel_mapping[0] = PCM_CHANNEL_L;
- media_cfg->channel_mapping[1] = PCM_CHANNEL_R;
-
- }
-
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
@@ -1064,10 +1090,10 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
struct payload_media_fmt_pcm *cfg;
struct media_format *header;
int rc, payload_size;
- struct gpr_pkt *pkt;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
void *p;
- if (num_channels > 2) {
+ if (num_channels > 4) {
dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels);
return -EINVAL;
}
@@ -1089,44 +1115,37 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
p = p + APM_MODULE_PARAM_DATA_SIZE;
header = p;
- header->data_format = DATA_FORMAT_FIXED_POINT;
- header->fmt_id = MEDIA_FMT_ID_PCM;
- header->payload_size = payload_size - sizeof(*header);
-
- p = p + sizeof(*header);
- cfg = p;
- cfg->sample_rate = mcfg->sample_rate;
- cfg->bit_width = mcfg->bit_width;
- cfg->alignment = PCM_LSB_ALIGNED;
- cfg->bits_per_sample = mcfg->bit_width;
- cfg->q_factor = mcfg->bit_width - 1;
- cfg->endianness = PCM_LITTLE_ENDIAN;
- cfg->num_channels = mcfg->num_channels;
-
- if (mcfg->num_channels == 1) {
- cfg->channel_mapping[0] = PCM_CHANNEL_L;
- } else if (num_channels == 2) {
- cfg->channel_mapping[0] = PCM_CHANNEL_L;
- cfg->channel_mapping[1] = PCM_CHANNEL_R;
+ if (mcfg->fmt == SND_AUDIOCODEC_PCM) {
+ header->data_format = DATA_FORMAT_FIXED_POINT;
+ header->fmt_id = MEDIA_FMT_ID_PCM;
+ header->payload_size = payload_size - sizeof(*header);
+
+ p = p + sizeof(*header);
+ cfg = p;
+ cfg->sample_rate = mcfg->sample_rate;
+ cfg->bit_width = mcfg->bit_width;
+ cfg->alignment = PCM_LSB_ALIGNED;
+ cfg->bits_per_sample = mcfg->bit_width;
+ cfg->q_factor = mcfg->bit_width - 1;
+ cfg->endianness = PCM_LITTLE_ENDIAN;
+ cfg->num_channels = mcfg->num_channels;
+ memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
+ } else {
+ rc = audioreach_set_compr_media_format(header, p, mcfg);
+ if (rc)
+ return rc;
}
- rc = audioreach_graph_send_cmd_sync(graph, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return audioreach_graph_send_cmd_sync(graph, pkt, 0);
}
int audioreach_gain_set_vol_ctrl(struct q6apm *apm, struct audioreach_module *module, int vol)
{
struct param_id_vol_ctrl_master_gain *cfg;
struct apm_module_param_data *param_data;
- int rc, payload_size;
- struct gpr_pkt *pkt;
+ int size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
void *p;
-
- payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -1136,16 +1155,12 @@ int audioreach_gain_set_vol_ctrl(struct q6apm *apm, struct audioreach_module *mo
param_data->module_instance_id = module->instance_id;
param_data->error_code = 0;
param_data->param_id = PARAM_ID_VOL_CTRL_MASTER_GAIN;
- param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
+ param_data->param_size = size - APM_MODULE_PARAM_DATA_SIZE;
p = p + APM_MODULE_PARAM_DATA_SIZE;
cfg = p;
cfg->master_gain = vol;
- rc = q6apm_send_cmd_sync(apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(apm, pkt, 0);
}
EXPORT_SYMBOL_GPL(audioreach_gain_set_vol_ctrl);
@@ -1153,11 +1168,8 @@ static int audioreach_gain_set(struct q6apm_graph *graph, struct audioreach_modu
{
struct apm_module_param_data *param_data;
struct apm_gain_module_cfg *cfg;
- int rc, payload_size;
- struct gpr_pkt *pkt;
-
- payload_size = APM_GAIN_CFG_PSIZE;
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ int size = APM_GAIN_CFG_PSIZE;
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -1167,15 +1179,11 @@ static int audioreach_gain_set(struct q6apm_graph *graph, struct audioreach_modu
param_data->module_instance_id = module->instance_id;
param_data->error_code = 0;
param_data->param_id = APM_PARAM_ID_GAIN;
- param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
+ param_data->param_size = size - APM_MODULE_PARAM_DATA_SIZE;
cfg->gain_cfg.gain = module->gain;
- rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_module *module,
@@ -1192,11 +1200,16 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
case MODULE_ID_PCM_DEC:
case MODULE_ID_PCM_ENC:
case MODULE_ID_PCM_CNV:
+ case MODULE_ID_PLACEHOLDER_DECODER:
+ case MODULE_ID_PLACEHOLDER_ENCODER:
rc = audioreach_pcm_set_media_format(graph, module, cfg);
break;
case MODULE_ID_DISPLAY_PORT_SINK:
rc = audioreach_display_port_set_media_format(graph, module, cfg);
break;
+ case MODULE_ID_SMECNS_V2:
+ rc = audioreach_set_module_config(graph, module, cfg);
+ break;
case MODULE_ID_I2S_SOURCE:
case MODULE_ID_I2S_SINK:
rc = audioreach_i2s_set_media_format(graph, module, cfg);
@@ -1219,6 +1232,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
case MODULE_ID_MFC:
rc = audioreach_mfc_set_media_format(graph, module, cfg);
break;
+ case MODULE_ID_GAPLESS:
+ rc = audioreach_gapless_set_media_format(graph, module, cfg);
+ break;
default:
rc = 0;
}
@@ -1252,9 +1268,9 @@ int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, s
struct apm_cmd_shared_mem_map_regions *cmd;
uint32_t num_regions, buf_sz, payload_size;
struct audioreach_graph_data *data;
- struct gpr_pkt *pkt;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
void *p;
- int rc, i;
+ int i;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
data = &graph->rx_data;
@@ -1301,23 +1317,16 @@ int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, s
}
mutex_unlock(&graph->lock);
- rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
-
- kfree(pkt);
-
- return rc;
+ return audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
}
EXPORT_SYMBOL_GPL(audioreach_map_memory_regions);
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph)
{
struct data_cmd_wr_sh_mem_ep_eos *eos;
- struct gpr_pkt *pkt;
- int rc = 0, iid;
-
- iid = q6apm_graph_get_rx_shmem_module_iid(graph);
- pkt = audioreach_alloc_cmd_pkt(sizeof(*eos), DATA_CMD_WR_SH_MEM_EP_EOS, 0,
- graph->port->id, iid);
+ int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_cmd_pkt(sizeof(*eos),
+ DATA_CMD_WR_SH_MEM_EP_EOS, 0, graph->port->id, iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -1325,9 +1334,6 @@ int audioreach_shared_memory_send_eos(struct q6apm_graph *graph)
eos->policy = WR_SH_MEM_EP_EOS_POLICY_LAST;
- rc = gpr_send_port_pkt(graph->port, pkt);
- kfree(pkt);
-
- return rc;
+ return gpr_send_port_pkt(graph->port, pkt);
}
EXPORT_SYMBOL_GPL(audioreach_shared_memory_send_eos);
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 3ebb81cd7cb0..d1b60b36468a 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -4,6 +4,7 @@
#define __AUDIOREACH_H__
#include <linux/types.h>
#include <linux/soc/qcom/apr.h>
+#include <uapi/sound/snd_ar_tokens.h>
#include <sound/soc.h>
struct q6apm;
struct q6apm_graph;
@@ -15,14 +16,22 @@ struct q6apm_graph;
#define MODULE_ID_PCM_CNV 0x07001003
#define MODULE_ID_PCM_ENC 0x07001004
#define MODULE_ID_PCM_DEC 0x07001005
+#define MODULE_ID_PLACEHOLDER_ENCODER 0x07001008
+#define MODULE_ID_PLACEHOLDER_DECODER 0x07001009
+#define MODULE_ID_I2S_SINK 0x0700100A
+#define MODULE_ID_I2S_SOURCE 0x0700100B
#define MODULE_ID_SAL 0x07001010
#define MODULE_ID_MFC 0x07001015
+#define MODULE_ID_DATA_LOGGING 0x0700101A
+#define MODULE_ID_AAC_DEC 0x0700101F
#define MODULE_ID_CODEC_DMA_SINK 0x07001023
#define MODULE_ID_CODEC_DMA_SOURCE 0x07001024
-#define MODULE_ID_I2S_SINK 0x0700100A
-#define MODULE_ID_I2S_SOURCE 0x0700100B
-#define MODULE_ID_DATA_LOGGING 0x0700101A
+#define MODULE_ID_FLAC_DEC 0x0700102F
+#define MODULE_ID_SMECNS_V2 0x07001031
+#define MODULE_ID_MP3_DECODE 0x0700103B
+#define MODULE_ID_GAPLESS 0x0700104D
#define MODULE_ID_DISPLAY_PORT_SINK 0x07001069
+#define MODULE_ID_OPUS_DEC 0x07001174
#define APM_CMD_GET_SPF_STATE 0x01001021
#define APM_CMD_RSP_GET_SPF_STATE 0x02001007
@@ -143,14 +152,15 @@ struct param_id_enc_bitrate_param {
} __packed;
#define DATA_FORMAT_FIXED_POINT 1
+#define DATA_FORMAT_GENERIC_COMPRESSED 5
+#define DATA_FORMAT_RAW_COMPRESSED 6
#define PCM_LSB_ALIGNED 1
#define PCM_MSB_ALIGNED 2
#define PCM_LITTLE_ENDIAN 1
#define PCM_BIT_ENDIAN 2
#define MEDIA_FMT_ID_PCM 0x09001000
-#define PCM_CHANNEL_L 1
-#define PCM_CHANNEL_R 2
+#define MEDIA_FMT_ID_MP3 0x09001009
#define SAMPLE_RATE_48K 48000
#define BIT_WIDTH_16 16
@@ -226,6 +236,44 @@ struct apm_media_format {
uint32_t payload_size;
} __packed;
+#define MEDIA_FMT_ID_FLAC 0x09001004
+
+struct payload_media_fmt_flac_t {
+ uint16_t num_channels;
+ uint16_t sample_size;
+ uint16_t min_blk_size;
+ uint16_t max_blk_size;
+ uint32_t sample_rate;
+ uint32_t min_frame_size;
+ uint32_t max_frame_size;
+} __packed;
+
+#define MEDIA_FMT_ID_AAC 0x09001001
+
+struct payload_media_fmt_aac_t {
+ uint16_t aac_fmt_flag;
+ uint16_t audio_obj_type;
+ uint16_t num_channels;
+ uint16_t total_size_of_PCE_bits;
+ uint32_t sample_rate;
+} __packed;
+
+#define MEDIA_FMT_ID_OPUS 0x09001039
+struct payload_media_fmt_opus_t {
+ uint16_t bitstream_format;
+ uint16_t payload_type;
+ uint8_t version;
+ uint8_t num_channels;
+ uint16_t pre_skip;
+ uint32_t sample_rate;
+ uint16_t output_gain;
+ uint8_t mapping_family;
+ uint8_t stream_count;
+ uint8_t coupled_count;
+ uint8_t channel_mapping[8];
+ uint8_t reserved[3];
+} __packed;
+
#define DATA_CMD_WR_SH_MEM_EP_EOS 0x04001002
#define WR_SH_MEM_EP_EOS_POLICY_LAST 1
#define WR_SH_MEM_EP_EOS_POLICY_EACH 2
@@ -432,8 +480,8 @@ struct param_id_i2s_intf_cfg {
} __packed;
#define I2S_INTF_TYPE_PRIMARY 0
-#define I2S_INTF_TYPE_SECOINDARY 1
-#define I2S_INTF_TYPE_TERTINARY 2
+#define I2S_INTF_TYPE_SECONDARY 1
+#define I2S_INTF_TYPE_TERTIARY 2
#define I2S_INTF_TYPE_QUATERNARY 3
#define I2S_INTF_TYPE_QUINARY 4
#define I2S_SD0 1
@@ -522,6 +570,8 @@ struct param_id_sal_limiter_enable {
} __packed;
#define PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT 0x08001024
+#define PARAM_ID_EARLY_EOS_DELAY 0x0800114C
+#define EARLY_EOS_DELAY_MS 150
struct param_id_mfc_media_format {
uint32_t sample_rate;
@@ -530,6 +580,10 @@ struct param_id_mfc_media_format {
uint16_t channel_mapping[];
} __packed;
+struct param_id_gapless_early_eos_delay_t {
+ uint32_t early_eos_delay_ms;
+} __packed;
+
struct media_format {
uint32_t data_format;
uint32_t fmt_id;
@@ -608,6 +662,15 @@ struct param_id_vol_ctrl_master_gain {
} __packed;
+#define PARAM_ID_REMOVE_INITIAL_SILENCE 0x0800114B
+#define PARAM_ID_REMOVE_TRAILING_SILENCE 0x0800115D
+
+#define PARAM_ID_REAL_MODULE_ID 0x0800100B
+
+struct param_id_placeholder_real_module_id {
+ uint32_t real_module_id;
+} __packed;
+
/* Graph */
struct audioreach_connection {
/* Connections */
@@ -663,9 +726,6 @@ struct audioreach_module {
uint32_t max_ip_port;
uint32_t max_op_port;
- uint32_t in_port;
- uint32_t out_port;
-
uint32_t num_connections;
/* Connections */
uint32_t src_mod_inst_id;
@@ -701,6 +761,7 @@ struct audioreach_module {
struct list_head node;
struct audioreach_container *container;
struct snd_soc_dapm_widget *widget;
+ struct audioreach_module_priv_data *data;
};
struct audioreach_module_config {
@@ -711,17 +772,18 @@ struct audioreach_module_config {
u16 data_format;
u16 num_channels;
- u16 active_channels_mask;
u16 dp_idx;
u32 channel_allocation;
u32 sd_line_mask;
int fmt;
+ struct snd_codec codec;
u8 channel_map[AR_PCM_MAX_NUM_CHANNEL];
};
/* Packet Allocation routines */
void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t
token);
+void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels);
void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode,
uint32_t token, uint32_t src_port,
uint32_t dest_port);
@@ -752,4 +814,8 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph);
int audioreach_gain_set_vol_ctrl(struct q6apm *apm,
struct audioreach_module *module, int vol);
+int audioreach_send_u32_param(struct q6apm_graph *graph, struct audioreach_module *module,
+ uint32_t param_id, uint32_t param_val);
+int audioreach_compr_set_param(struct q6apm_graph *graph, struct audioreach_module_config *mcfg);
+
#endif /* __AUDIOREACH_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
index 1530e98df165..0b8d06ec8b26 100644
--- a/sound/soc/qcom/qdsp6/q6adm.c
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -109,11 +109,75 @@ static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx,
}
+static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp,
+ struct apr_pkt *pkt, uint32_t rsp_opcode)
+{
+ struct device *dev = adm->dev;
+ uint32_t opcode = pkt->hdr.opcode;
+ int ret;
+
+ mutex_lock(&adm->lock);
+ copp->result.opcode = 0;
+ copp->result.status = 0;
+ ret = apr_send_pkt(adm->apr, pkt);
+ if (ret < 0) {
+ dev_err(dev, "Failed to send APR packet\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Wait for the callback with copp id */
+ if (rsp_opcode)
+ ret = wait_event_timeout(copp->wait,
+ (copp->result.opcode == opcode) ||
+ (copp->result.opcode == rsp_opcode),
+ msecs_to_jiffies(TIMEOUT_MS));
+ else
+ ret = wait_event_timeout(copp->wait,
+ (copp->result.opcode == opcode),
+ msecs_to_jiffies(TIMEOUT_MS));
+
+ if (!ret) {
+ dev_err(dev, "ADM copp cmd timedout\n");
+ ret = -ETIMEDOUT;
+ } else if (copp->result.status > 0) {
+ dev_err(dev, "DSP returned error[%d]\n",
+ copp->result.status);
+ ret = -EINVAL;
+ }
+
+err:
+ mutex_unlock(&adm->lock);
+ return ret;
+}
+
+static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp,
+ int port_id, int copp_idx)
+{
+ struct apr_pkt close;
+
+ close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ close.hdr.pkt_size = sizeof(close);
+ close.hdr.src_port = port_id;
+ close.hdr.dest_port = copp->id;
+ close.hdr.token = port_id << 16 | copp_idx;
+ close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5;
+
+ return q6adm_apr_send_copp_pkt(adm, copp, &close, 0);
+}
+
static void q6adm_free_copp(struct kref *ref)
{
struct q6copp *c = container_of(ref, struct q6copp, refcount);
struct q6adm *adm = c->adm;
unsigned long flags;
+ int ret;
+
+ ret = q6adm_device_close(adm, c, c->afe_port, c->copp_idx);
+ if (ret < 0)
+ dev_err(adm->dev, "Failed to close copp %d\n", ret);
spin_lock_irqsave(&adm->copps_list_lock, flags);
clear_bit(c->copp_idx, &adm->copp_bitmap[c->afe_port]);
@@ -155,13 +219,13 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data)
switch (result->opcode) {
case ADM_CMD_DEVICE_OPEN_V5:
case ADM_CMD_DEVICE_CLOSE_V5:
- copp = q6adm_find_copp(adm, port_idx, copp_idx);
- if (!copp)
- return 0;
-
- copp->result = *result;
- wake_up(&copp->wait);
- kref_put(&copp->refcount, q6adm_free_copp);
+ list_for_each_entry(copp, &adm->copps_list, node) {
+ if ((port_idx == copp->afe_port) && (copp_idx == copp->copp_idx)) {
+ copp->result = *result;
+ wake_up(&copp->wait);
+ break;
+ }
+ }
break;
case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
adm->result = *result;
@@ -234,65 +298,6 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx)
return c;
}
-static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp,
- struct apr_pkt *pkt, uint32_t rsp_opcode)
-{
- struct device *dev = adm->dev;
- uint32_t opcode = pkt->hdr.opcode;
- int ret;
-
- mutex_lock(&adm->lock);
- copp->result.opcode = 0;
- copp->result.status = 0;
- ret = apr_send_pkt(adm->apr, pkt);
- if (ret < 0) {
- dev_err(dev, "Failed to send APR packet\n");
- ret = -EINVAL;
- goto err;
- }
-
- /* Wait for the callback with copp id */
- if (rsp_opcode)
- ret = wait_event_timeout(copp->wait,
- (copp->result.opcode == opcode) ||
- (copp->result.opcode == rsp_opcode),
- msecs_to_jiffies(TIMEOUT_MS));
- else
- ret = wait_event_timeout(copp->wait,
- (copp->result.opcode == opcode),
- msecs_to_jiffies(TIMEOUT_MS));
-
- if (!ret) {
- dev_err(dev, "ADM copp cmd timedout\n");
- ret = -ETIMEDOUT;
- } else if (copp->result.status > 0) {
- dev_err(dev, "DSP returned error[%d]\n",
- copp->result.status);
- ret = -EINVAL;
- }
-
-err:
- mutex_unlock(&adm->lock);
- return ret;
-}
-
-static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp,
- int port_id, int copp_idx)
-{
- struct apr_pkt close;
-
- close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- close.hdr.pkt_size = sizeof(close);
- close.hdr.src_port = port_id;
- close.hdr.dest_port = copp->id;
- close.hdr.token = port_id << 16 | copp_idx;
- close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5;
-
- return q6adm_apr_send_copp_pkt(adm, copp, &close, 0);
-}
-
static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm,
int port_id, int topology,
int mode, int rate,
@@ -325,11 +330,8 @@ static int q6adm_device_open(struct q6adm *adm, struct q6copp *copp,
struct q6adm_cmd_device_open_v5 *open;
int afe_port = q6afe_get_port_id(port_id);
struct apr_pkt *pkt;
- void *p;
- int ret, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*open);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int ret, pkt_size = APR_HDR_SIZE + sizeof(*open);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -354,14 +356,9 @@ static int q6adm_device_open(struct q6adm *adm, struct q6copp *copp,
ret = q6dsp_map_channels(&open->dev_channel_mapping[0],
channel_mode);
if (ret)
- goto err;
-
- ret = q6adm_apr_send_copp_pkt(adm, copp, pkt,
- ADM_CMDRSP_DEVICE_OPEN_V5);
+ return ret;
-err:
- kfree(pkt);
- return ret;
+ return q6adm_apr_send_copp_pkt(adm, copp, pkt, ADM_CMDRSP_DEVICE_OPEN_V5);
}
/**
@@ -464,15 +461,12 @@ int q6adm_matrix_map(struct device *dev, int path,
struct q6adm_session_map_node_v5 *node;
struct apr_pkt *pkt;
uint16_t *copps_list;
- int pkt_size, ret, i, copp_idx;
- void *matrix_map;
- struct q6copp *copp;
-
+ int ret, i, copp_idx;
/* Assumes port_ids have already been validated during adm_open */
- pkt_size = (APR_HDR_SIZE + sizeof(*route) + sizeof(*node) +
+ struct q6copp *copp;
+ int pkt_size = (APR_HDR_SIZE + sizeof(*route) + sizeof(*node) +
(sizeof(uint32_t) * payload_map.num_copps));
-
- matrix_map = kzalloc(pkt_size, GFP_KERNEL);
+ void *matrix_map __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!matrix_map)
return -ENOMEM;
@@ -510,16 +504,13 @@ int q6adm_matrix_map(struct device *dev, int path,
if (port_idx < 0) {
dev_err(dev, "Invalid port_id %d\n",
payload_map.port_id[i]);
- kfree(pkt);
return -EINVAL;
}
copp_idx = payload_map.copp_idx[i];
copp = q6adm_find_copp(adm, port_idx, copp_idx);
- if (!copp) {
- kfree(pkt);
+ if (!copp)
return -EINVAL;
- }
copps_list[i] = copp->id;
kref_put(&copp->refcount, q6adm_free_copp);
@@ -552,7 +543,6 @@ int q6adm_matrix_map(struct device *dev, int path,
fail_cmd:
mutex_unlock(&adm->lock);
- kfree(pkt);
return ret;
}
EXPORT_SYMBOL_GPL(q6adm_matrix_map);
@@ -567,15 +557,6 @@ EXPORT_SYMBOL_GPL(q6adm_matrix_map);
*/
int q6adm_close(struct device *dev, struct q6copp *copp)
{
- struct q6adm *adm = dev_get_drvdata(dev->parent);
- int ret = 0;
-
- ret = q6adm_device_close(adm, copp, copp->afe_port, copp->copp_idx);
- if (ret < 0) {
- dev_err(adm->dev, "Failed to close copp %d\n", ret);
- return ret;
- }
-
kref_put(&copp->refcount, q6adm_free_copp);
return 0;
diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c
index 1ccab64ff00b..84b9018c36ba 100644
--- a/sound/soc/qcom/qdsp6/q6afe-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020, Linaro Limited
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/clk-provider.h>
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 31e0bad71e95..0f47aadaabe1 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -2,6 +2,7 @@
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -91,6 +92,39 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int q6afe_usb_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int channels = params_channels(params);
+ int rate = params_rate(params);
+ struct q6afe_usb_cfg *usb = &dai_data->port_config[dai->id].usb_audio;
+
+ usb->sample_rate = rate;
+ usb->num_channels = channels;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ usb->bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ usb->bit_width = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ usb->bit_width = 32;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int q6i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -171,8 +205,8 @@ static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
}
static int q6tdm_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num, const unsigned int *tx_slot,
+ unsigned int rx_num, const unsigned int *rx_slot)
{
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -249,8 +283,10 @@ static int q6tdm_hw_params(struct snd_pcm_substream *substream,
}
static int q6dma_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_ch_mask,
- unsigned int rx_num, unsigned int *rx_ch_mask)
+ unsigned int tx_num,
+ const unsigned int *tx_ch_mask,
+ unsigned int rx_num,
+ const unsigned int *rx_ch_mask)
{
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -391,6 +427,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
q6afe_cdc_dma_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].dma_cfg);
break;
+ case USB_RX:
+ q6afe_usb_port_prepare(dai_data->port[dai->id],
+ &dai_data->port_config[dai->id].usb_audio);
+ break;
default:
return -EINVAL;
}
@@ -406,8 +446,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
}
static int q6slim_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num,
+ const unsigned int *tx_slot,
+ unsigned int rx_num,
+ const unsigned int *rx_slot)
{
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
@@ -476,7 +518,7 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"HDMI Playback", NULL, "HDMI_RX"},
- {"Display Port Playback", NULL, "DISPLAY_PORT_RX"},
+ {"DISPLAY_PORT_RX_0 Playback", NULL, "DISPLAY_PORT_RX"},
{"Slimbus Playback", NULL, "SLIMBUS_0_RX"},
{"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
{"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
@@ -617,44 +659,9 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"TX_CODEC_DMA_TX_5", NULL, "TX_CODEC_DMA_TX_5 Capture"},
{"RX_CODEC_DMA_RX_6 Playback", NULL, "RX_CODEC_DMA_RX_6"},
{"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"},
-};
-
-static const struct snd_soc_dai_ops q6hdmi_ops = {
- .prepare = q6afe_dai_prepare,
- .hw_params = q6hdmi_hw_params,
- .shutdown = q6afe_dai_shutdown,
-};
-static const struct snd_soc_dai_ops q6i2s_ops = {
- .prepare = q6afe_dai_prepare,
- .hw_params = q6i2s_hw_params,
- .set_fmt = q6i2s_set_fmt,
- .shutdown = q6afe_dai_shutdown,
- .set_sysclk = q6afe_mi2s_set_sysclk,
-};
-
-static const struct snd_soc_dai_ops q6slim_ops = {
- .prepare = q6afe_dai_prepare,
- .hw_params = q6slim_hw_params,
- .shutdown = q6afe_dai_shutdown,
- .set_channel_map = q6slim_set_channel_map,
-};
-
-static const struct snd_soc_dai_ops q6tdm_ops = {
- .prepare = q6afe_dai_prepare,
- .shutdown = q6afe_dai_shutdown,
- .set_sysclk = q6afe_mi2s_set_sysclk,
- .set_tdm_slot = q6tdm_set_tdm_slot,
- .set_channel_map = q6tdm_set_channel_map,
- .hw_params = q6tdm_hw_params,
-};
-
-static const struct snd_soc_dai_ops q6dma_ops = {
- .prepare = q6afe_dai_prepare,
- .shutdown = q6afe_dai_shutdown,
- .set_sysclk = q6afe_mi2s_set_sysclk,
- .set_channel_map = q6dma_set_channel_map,
- .hw_params = q6dma_hw_params,
+ /* USB playback AFE port receives data for playback, hence use the RX port */
+ {"USB Playback", NULL, "USB_RX"},
};
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
@@ -682,6 +689,71 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops q6afe_usb_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6afe_usb_hw_params,
+ /*
+ * Shutdown callback required to stop the USB AFE port, which is enabled
+ * by the prepare() stage. This stops the audio traffic on the USB AFE
+ * port on the Q6DSP.
+ */
+ .shutdown = q6afe_dai_shutdown,
+ /*
+ * Startup callback not needed, as AFE port start command passes the PCM
+ * parameters within the AFE command, which is provided by the PCM core
+ * during the prepare() stage.
+ */
+};
+
+static const struct snd_soc_dai_ops q6hdmi_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6hdmi_hw_params,
+ .shutdown = q6afe_dai_shutdown,
+};
+
+static const struct snd_soc_dai_ops q6i2s_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6i2s_hw_params,
+ .set_fmt = q6i2s_set_fmt,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops q6slim_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6slim_hw_params,
+ .shutdown = q6afe_dai_shutdown,
+ .set_channel_map = q6slim_set_channel_map,
+};
+
+static const struct snd_soc_dai_ops q6tdm_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+ .set_tdm_slot = q6tdm_set_tdm_slot,
+ .set_channel_map = q6tdm_set_channel_map,
+ .hw_params = q6tdm_hw_params,
+};
+
+static const struct snd_soc_dai_ops q6dma_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+ .set_channel_map = q6dma_set_channel_map,
+ .hw_params = q6dma_hw_params,
+};
+
static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
@@ -932,6 +1004,8 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_7", "NULL",
0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("USB_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
@@ -1041,13 +1115,12 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev)
dev_set_drvdata(dev, dai_data);
of_q6afe_parse_dai_data(dev, dai_data);
- cfg.probe = msm_dai_q6_dai_probe;
- cfg.remove = msm_dai_q6_dai_remove;
cfg.q6hdmi_ops = &q6hdmi_ops;
cfg.q6slim_ops = &q6slim_ops;
cfg.q6i2s_ops = &q6i2s_ops;
cfg.q6tdm_ops = &q6tdm_ops;
cfg.q6dma_ops = &q6dma_ops;
+ cfg.q6usb_ops = &q6afe_usb_ops;
dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais);
return devm_snd_soc_register_component(dev, &q6afe_dai_component, dais, num_dais);
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 919e326b9462..980851a12976 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -2,6 +2,7 @@
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
@@ -34,6 +35,8 @@
#define AFE_MODULE_TDM 0x0001028A
#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG 0x00010235
+#define AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS 0x000102A5
+#define AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT 0x000102AA
#define AFE_PARAM_ID_LPAIF_CLK_CONFIG 0x00010238
#define AFE_PARAM_ID_INT_DIGITAL_CDC_CLK_CONFIG 0x00010239
@@ -43,6 +46,7 @@
#define AFE_PARAM_ID_TDM_CONFIG 0x0001029D
#define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297
#define AFE_PARAM_ID_CODEC_DMA_CONFIG 0x000102B8
+#define AFE_PARAM_ID_USB_AUDIO_CONFIG 0x000102A4
#define AFE_CMD_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f4
#define AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST 0x000100f5
#define AFE_CMD_REMOTE_LPASS_CORE_HW_DEVOTE_REQUEST 0x000100f6
@@ -71,12 +75,16 @@
#define AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL 0x1
#define AFE_LINEAR_PCM_DATA 0x0
+#define AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG 0x1
/* Port IDs */
#define AFE_API_VERSION_HDMI_CONFIG 0x1
#define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E
#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020
+/* USB AFE port */
+#define AFE_PORT_ID_USB_RX 0x7000
+
#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
/* Clock set API version */
#define AFE_API_VERSION_CLOCK_SET 1
@@ -358,7 +366,7 @@
#define AFE_API_VERSION_SLOT_MAPPING_CONFIG 1
#define AFE_API_VERSION_CODEC_DMA_CONFIG 1
-#define TIMEOUT_MS 1000
+#define TIMEOUT_MS 3000
#define AFE_CMD_RESP_AVAIL 0
#define AFE_CMD_RESP_NONE 1
#define AFE_CLK_TOKEN 1024
@@ -512,12 +520,96 @@ struct afe_param_id_cdc_dma_cfg {
u16 active_channels_mask;
} __packed;
+struct afe_param_id_usb_cfg {
+/* Minor version used for tracking USB audio device configuration.
+ * Supported values: AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG
+ */
+ u32 cfg_minor_version;
+/* Sampling rate of the port.
+ * Supported values:
+ * - AFE_PORT_SAMPLE_RATE_8K
+ * - AFE_PORT_SAMPLE_RATE_11025
+ * - AFE_PORT_SAMPLE_RATE_12K
+ * - AFE_PORT_SAMPLE_RATE_16K
+ * - AFE_PORT_SAMPLE_RATE_22050
+ * - AFE_PORT_SAMPLE_RATE_24K
+ * - AFE_PORT_SAMPLE_RATE_32K
+ * - AFE_PORT_SAMPLE_RATE_44P1K
+ * - AFE_PORT_SAMPLE_RATE_48K
+ * - AFE_PORT_SAMPLE_RATE_96K
+ * - AFE_PORT_SAMPLE_RATE_192K
+ */
+ u32 sample_rate;
+/* Bit width of the sample.
+ * Supported values: 16, 24
+ */
+ u16 bit_width;
+/* Number of channels.
+ * Supported values: 1 and 2
+ */
+ u16 num_channels;
+/* Data format supported by the USB. The supported value is
+ * 0 (#AFE_USB_AUDIO_DATA_FORMAT_LINEAR_PCM).
+ */
+ u16 data_format;
+/* this field must be 0 */
+ u16 reserved;
+/* device token of actual end USB audio device */
+ u32 dev_token;
+/* endianness of this interface */
+ u32 endian;
+/* service interval */
+ u32 service_interval;
+} __packed;
+
+/**
+ * struct afe_param_id_usb_audio_dev_params
+ * @cfg_minor_version: Minor version used for tracking USB audio device
+ * configuration.
+ * Supported values:
+ * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG
+ * @dev_token: device token of actual end USB audio device
+ **/
+struct afe_param_id_usb_audio_dev_params {
+ u32 cfg_minor_version;
+ u32 dev_token;
+} __packed;
+
+/**
+ * struct afe_param_id_usb_audio_dev_lpcm_fmt
+ * @cfg_minor_version: Minor version used for tracking USB audio device
+ * configuration.
+ * Supported values:
+ * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG
+ * @endian: endianness of this interface
+ **/
+struct afe_param_id_usb_audio_dev_lpcm_fmt {
+ u32 cfg_minor_version;
+ u32 endian;
+} __packed;
+
+#define AFE_PARAM_ID_USB_AUDIO_SVC_INTERVAL 0x000102B7
+
+/**
+ * struct afe_param_id_usb_audio_svc_interval
+ * @cfg_minor_version: Minor version used for tracking USB audio device
+ * configuration.
+ * Supported values:
+ * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG
+ * @svc_interval: service interval
+ **/
+struct afe_param_id_usb_audio_svc_interval {
+ u32 cfg_minor_version;
+ u32 svc_interval;
+} __packed;
+
union afe_port_config {
struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
struct afe_param_id_slimbus_cfg slim_cfg;
struct afe_param_id_i2s_cfg i2s_cfg;
struct afe_param_id_tdm_cfg tdm_cfg;
struct afe_param_id_cdc_dma_cfg dma_cfg;
+ struct afe_param_id_usb_cfg usb_cfg;
} __packed;
@@ -552,13 +644,13 @@ struct q6afe_port {
};
struct afe_cmd_remote_lpass_core_hw_vote_request {
- uint32_t hw_block_id;
- char client_name[8];
+ uint32_t hw_block_id;
+ char client_name[8];
} __packed;
struct afe_cmd_remote_lpass_core_hw_devote_request {
- uint32_t hw_block_id;
- uint32_t client_handle;
+ uint32_t hw_block_id;
+ uint32_t client_handle;
} __packed;
@@ -832,6 +924,7 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
RX_CODEC_DMA_RX_6, 1, 1},
[RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7,
RX_CODEC_DMA_RX_7, 1, 1},
+ [USB_RX] = { AFE_PORT_ID_USB_RX, USB_RX, 1, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -853,9 +946,8 @@ static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token)
{
struct q6afe_port *p;
struct q6afe_port *ret = NULL;
- unsigned long flags;
- spin_lock_irqsave(&afe->port_list_lock, flags);
+ guard(spinlock)(&afe->port_list_lock);
list_for_each_entry(p, &afe->port_list, node)
if (p->token == token) {
ret = p;
@@ -863,7 +955,6 @@ static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token)
break;
}
- spin_unlock_irqrestore(&afe->port_list_lock, flags);
return ret;
}
@@ -984,11 +1075,9 @@ static int q6afe_set_param(struct q6afe *afe, struct q6afe_port *port,
struct afe_svc_cmd_set_param *param;
struct afe_port_param_data_v2 *pdata;
struct apr_pkt *pkt;
- int ret, pkt_size;
- void *p, *pl;
-
- pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int ret, pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
+ void *pl;
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1019,7 +1108,6 @@ static int q6afe_set_param(struct q6afe *afe, struct q6afe_port *port,
if (ret)
dev_err(afe->dev, "AFE set params failed %d\n", ret);
- kfree(pkt);
return ret;
}
@@ -1038,11 +1126,9 @@ static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
struct q6afe *afe = port->afe;
struct apr_pkt *pkt;
u16 port_id = port->id;
- int ret, pkt_size;
- void *p, *pl;
-
- pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int ret, pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize;
+ void *pl;
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1075,7 +1161,6 @@ static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data,
dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
port_id, ret);
- kfree(pkt);
return ret;
}
@@ -1192,7 +1277,7 @@ int q6afe_port_stop(struct q6afe_port *port)
int port_id = port->id;
int ret = 0;
int index, pkt_size;
- void *p;
+ void *p __free(kfree) = NULL;
index = port->token;
if (index < 0 || index >= AFE_PORT_MAX) {
@@ -1223,7 +1308,6 @@ int q6afe_port_stop(struct q6afe_port *port)
if (ret)
dev_err(afe->dev, "AFE close failed %d\n", ret);
- kfree(pkt);
return ret;
}
EXPORT_SYMBOL_GPL(q6afe_port_stop);
@@ -1290,6 +1374,99 @@ void q6afe_tdm_port_prepare(struct q6afe_port *port,
EXPORT_SYMBOL_GPL(q6afe_tdm_port_prepare);
/**
+ * afe_port_send_usb_dev_param() - Send USB dev token
+ *
+ * @port: Instance of afe port
+ * @cardidx: USB SND card index to reference
+ * @pcmidx: USB SND PCM device index to reference
+ *
+ * The USB dev token carries information about which USB SND card instance and
+ * PCM device to execute the offload on. This information is carried through
+ * to the stream enable QMI request, which is handled by the offload class
+ * driver. The information is parsed to determine which USB device to query
+ * the required resources for.
+ */
+int afe_port_send_usb_dev_param(struct q6afe_port *port, int cardidx, int pcmidx)
+{
+ struct afe_param_id_usb_audio_dev_params usb_dev;
+ int ret;
+
+ memset(&usb_dev, 0, sizeof(usb_dev));
+
+ usb_dev.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG;
+ usb_dev.dev_token = (cardidx << 16) | (pcmidx << 8);
+ ret = q6afe_port_set_param_v2(port, &usb_dev,
+ AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS,
+ AFE_MODULE_AUDIO_DEV_INTERFACE,
+ sizeof(usb_dev));
+ if (ret)
+ dev_err(port->afe->dev, "%s: AFE device param cmd failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(afe_port_send_usb_dev_param);
+
+static int afe_port_send_usb_params(struct q6afe_port *port, struct q6afe_usb_cfg *cfg)
+{
+ union afe_port_config *pcfg = &port->port_cfg;
+ struct afe_param_id_usb_audio_dev_lpcm_fmt lpcm_fmt;
+ struct afe_param_id_usb_audio_svc_interval svc_int;
+ int ret;
+
+ if (!pcfg) {
+ dev_err(port->afe->dev, "%s: Error, no configuration data\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&lpcm_fmt, 0, sizeof(lpcm_fmt));
+ memset(&svc_int, 0, sizeof(svc_int));
+
+ lpcm_fmt.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG;
+ lpcm_fmt.endian = pcfg->usb_cfg.endian;
+ ret = q6afe_port_set_param_v2(port, &lpcm_fmt,
+ AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT,
+ AFE_MODULE_AUDIO_DEV_INTERFACE, sizeof(lpcm_fmt));
+ if (ret) {
+ dev_err(port->afe->dev, "%s: AFE device param cmd LPCM_FMT failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ svc_int.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG;
+ svc_int.svc_interval = pcfg->usb_cfg.service_interval;
+ ret = q6afe_port_set_param_v2(port, &svc_int,
+ AFE_PARAM_ID_USB_AUDIO_SVC_INTERVAL,
+ AFE_MODULE_AUDIO_DEV_INTERFACE, sizeof(svc_int));
+ if (ret)
+ dev_err(port->afe->dev, "%s: AFE device param cmd svc_interval failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+/**
+ * q6afe_usb_port_prepare() - Prepare usb afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: USB configuration for the afe port
+ *
+ */
+void q6afe_usb_port_prepare(struct q6afe_port *port,
+ struct q6afe_usb_cfg *cfg)
+{
+ union afe_port_config *pcfg = &port->port_cfg;
+
+ pcfg->usb_cfg.cfg_minor_version = AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG;
+ pcfg->usb_cfg.sample_rate = cfg->sample_rate;
+ pcfg->usb_cfg.num_channels = cfg->num_channels;
+ pcfg->usb_cfg.bit_width = cfg->bit_width;
+
+ afe_port_send_usb_params(port, cfg);
+}
+EXPORT_SYMBOL_GPL(q6afe_usb_port_prepare);
+
+/**
* q6afe_hdmi_port_prepare() - Prepare hdmi afe port.
*
* @port: Instance of afe port
@@ -1490,7 +1667,7 @@ int q6afe_port_start(struct q6afe_port *port)
int ret, param_id = port->cfg_type;
struct apr_pkt *pkt;
int pkt_size;
- void *p;
+ void *p __free(kfree) = NULL;
ret = q6afe_port_set_param_v2(port, &port->port_cfg, param_id,
AFE_MODULE_AUDIO_DEV_INTERFACE,
@@ -1536,7 +1713,6 @@ int q6afe_port_start(struct q6afe_port *port)
dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
port_id, ret);
- kfree(pkt);
return ret;
}
EXPORT_SYMBOL_GPL(q6afe_port_start);
@@ -1555,7 +1731,6 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
int port_id;
struct q6afe *afe = dev_get_drvdata(dev->parent);
struct q6afe_port *port;
- unsigned long flags;
int cfg_type;
if (id < 0 || id >= AFE_PORT_MAX) {
@@ -1611,7 +1786,10 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
break;
case AFE_PORT_ID_WSA_CODEC_DMA_RX_0 ... AFE_PORT_ID_RX_CODEC_DMA_RX_7:
cfg_type = AFE_PARAM_ID_CODEC_DMA_CONFIG;
- break;
+ break;
+ case AFE_PORT_ID_USB_RX:
+ cfg_type = AFE_PARAM_ID_USB_AUDIO_CONFIG;
+ break;
default:
dev_err(dev, "Invalid port id 0x%x\n", port_id);
return ERR_PTR(-EINVAL);
@@ -1629,9 +1807,8 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
port->cfg_type = cfg_type;
kref_init(&port->refcount);
- spin_lock_irqsave(&afe->port_list_lock, flags);
+ guard(spinlock)(&afe->port_list_lock);
list_add_tail(&port->node, &afe->port_list);
- spin_unlock_irqrestore(&afe->port_list_lock, flags);
return port;
@@ -1656,11 +1833,8 @@ int q6afe_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
struct afe_cmd_remote_lpass_core_hw_devote_request *vote_cfg;
struct apr_pkt *pkt;
int ret = 0;
- int pkt_size;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*vote_cfg);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*vote_cfg);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1682,7 +1856,6 @@ int q6afe_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
if (ret < 0)
dev_err(afe->dev, "AFE failed to unvote (%d)\n", hw_block_id);
- kfree(pkt);
return ret;
}
EXPORT_SYMBOL(q6afe_unvote_lpass_core_hw);
@@ -1694,11 +1867,8 @@ int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
struct afe_cmd_remote_lpass_core_hw_vote_request *vote_cfg;
struct apr_pkt *pkt;
int ret = 0;
- int pkt_size;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*vote_cfg);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*vote_cfg);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1722,8 +1892,6 @@ int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
if (ret)
dev_err(afe->dev, "AFE failed to vote (%d)\n", hw_block_id);
-
- kfree(pkt);
return ret;
}
EXPORT_SYMBOL(q6afe_vote_lpass_core_hw);
diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h
index 30fd77e2f458..a29abe4ce436 100644
--- a/sound/soc/qcom/qdsp6/q6afe.h
+++ b/sound/soc/qcom/qdsp6/q6afe.h
@@ -3,9 +3,7 @@
#ifndef __Q6AFE_H__
#define __Q6AFE_H__
-#include <dt-bindings/sound/qcom,q6afe.h>
-
-#define AFE_PORT_MAX 129
+#define AFE_PORT_MAX 137
#define MSM_AFE_PORT_TYPE_RX 0
#define MSM_AFE_PORT_TYPE_TX 1
@@ -205,6 +203,36 @@ struct q6afe_cdc_dma_cfg {
u16 active_channels_mask;
};
+/**
+ * struct q6afe_usb_cfg
+ * @cfg_minor_version: Minor version used for tracking USB audio device
+ * configuration.
+ * Supported values:
+ * AFE_API_MINOR_VERSION_USB_AUDIO_CONFIG
+ * @sample_rate: Sampling rate of the port
+ * Supported values:
+ * AFE_PORT_SAMPLE_RATE_8K
+ * AFE_PORT_SAMPLE_RATE_11025
+ * AFE_PORT_SAMPLE_RATE_12K
+ * AFE_PORT_SAMPLE_RATE_16K
+ * AFE_PORT_SAMPLE_RATE_22050
+ * AFE_PORT_SAMPLE_RATE_24K
+ * AFE_PORT_SAMPLE_RATE_32K
+ * AFE_PORT_SAMPLE_RATE_44P1K
+ * AFE_PORT_SAMPLE_RATE_48K
+ * AFE_PORT_SAMPLE_RATE_96K
+ * AFE_PORT_SAMPLE_RATE_192K
+ * @bit_width: Bit width of the sample.
+ * Supported values: 16, 24
+ * @num_channels: Number of channels
+ * Supported values: 1, 2
+ **/
+struct q6afe_usb_cfg {
+ u32 cfg_minor_version;
+ u32 sample_rate;
+ u16 bit_width;
+ u16 num_channels;
+};
struct q6afe_port_config {
struct q6afe_hdmi_cfg hdmi;
@@ -212,6 +240,7 @@ struct q6afe_port_config {
struct q6afe_i2s_cfg i2s_cfg;
struct q6afe_tdm_cfg tdm;
struct q6afe_cdc_dma_cfg dma_cfg;
+ struct q6afe_usb_cfg usb_audio;
};
struct q6afe_port;
@@ -221,6 +250,8 @@ int q6afe_port_start(struct q6afe_port *port);
int q6afe_port_stop(struct q6afe_port *port);
void q6afe_port_put(struct q6afe_port *port);
int q6afe_get_port_id(int index);
+void q6afe_usb_port_prepare(struct q6afe_port *port,
+ struct q6afe_usb_cfg *cfg);
void q6afe_hdmi_port_prepare(struct q6afe_port *port,
struct q6afe_hdmi_cfg *cfg);
void q6afe_slim_port_prepare(struct q6afe_port *port,
@@ -230,6 +261,7 @@ void q6afe_tdm_port_prepare(struct q6afe_port *port, struct q6afe_tdm_cfg *cfg);
void q6afe_cdc_dma_port_prepare(struct q6afe_port *port,
struct q6afe_cdc_dma_cfg *cfg);
+int afe_port_send_usb_dev_param(struct q6afe_port *port, int cardidx, int pcmidx);
int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
int clk_src, int clk_root,
unsigned int freq, int dir);
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c
index 7f02f5b2c33f..aaeeadded7aa 100644
--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
@@ -4,15 +4,16 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <linux/spinlock.h>
#include <sound/pcm.h>
+#include <asm/div64.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include "q6apm.h"
@@ -24,12 +25,31 @@
#define PLAYBACK_MIN_PERIOD_SIZE 128
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
-#define CAPTURE_MAX_PERIOD_SIZE 4096
-#define CAPTURE_MIN_PERIOD_SIZE 320
+#define CAPTURE_MAX_PERIOD_SIZE 65536
+#define CAPTURE_MIN_PERIOD_SIZE 6144
#define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE)
#define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE)
+#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
+#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
+#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
+#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
#define SID_MASK_DEFAULT 0xF
+static const struct snd_compr_codec_caps q6apm_compr_caps = {
+ .num_descriptors = 1,
+ .descriptor[0].max_ch = 2,
+ .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
+ 24000, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000 },
+ .descriptor[0].num_sample_rates = 13,
+ .descriptor[0].bit_rate[0] = 320,
+ .descriptor[0].bit_rate[1] = 128,
+ .descriptor[0].num_bitrates = 2,
+ .descriptor[0].profiles = 0,
+ .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+ .descriptor[0].formats = 0,
+};
+
enum stream_state {
Q6APM_STREAM_IDLE = 0,
Q6APM_STREAM_STOPPED,
@@ -39,32 +59,34 @@ enum stream_state {
struct q6apm_dai_rtd {
struct snd_pcm_substream *substream;
struct snd_compr_stream *cstream;
+ struct snd_codec codec;
struct snd_compr_params codec_param;
struct snd_dma_buffer dma_buffer;
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
- unsigned int pos; /* Buffer position */
unsigned int periods;
- unsigned int bytes_sent;
- unsigned int bytes_received;
- unsigned int copied_total;
+ uint64_t bytes_sent;
+ uint64_t bytes_received;
+ uint64_t copied_total;
uint16_t bits_per_sample;
- uint16_t source; /* Encoding source bit mask */
- uint16_t session_id;
+ snd_pcm_uframes_t queue_ptr;
+ bool next_track;
enum stream_state state;
struct q6apm_graph *graph;
spinlock_t lock;
+ bool notify_on_drain;
};
struct q6apm_dai_data {
long long sid;
};
-static struct snd_pcm_hardware q6apm_dai_hardware_capture = {
+static const struct snd_pcm_hardware q6apm_dai_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR |
SNDRV_PCM_INFO_BATCH),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
.rates = SNDRV_PCM_RATE_8000_48000,
@@ -80,10 +102,11 @@ static struct snd_pcm_hardware q6apm_dai_hardware_capture = {
.fifo_size = 0,
};
-static struct snd_pcm_hardware q6apm_dai_hardware_playback = {
+static const struct snd_pcm_hardware q6apm_dai_hardware_playback = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR |
SNDRV_PCM_INFO_BATCH),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
.rates = SNDRV_PCM_RATE_8000_192000,
@@ -99,29 +122,20 @@ static struct snd_pcm_hardware q6apm_dai_hardware_playback = {
.fifo_size = 0,
};
-static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv)
+static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv)
{
struct q6apm_dai_rtd *prtd = priv;
struct snd_pcm_substream *substream = prtd->substream;
- unsigned long flags;
switch (opcode) {
case APM_CLIENT_EVENT_CMD_EOS_DONE:
prtd->state = Q6APM_STREAM_STOPPED;
break;
case APM_CLIENT_EVENT_DATA_WRITE_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
- prtd->pos += prtd->pcm_count;
- spin_unlock_irqrestore(&prtd->lock, flags);
snd_pcm_period_elapsed(substream);
- if (prtd->state == Q6APM_STREAM_RUNNING)
- q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);
break;
case APM_CLIENT_EVENT_DATA_READ_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
- prtd->pos += prtd->pcm_count;
- spin_unlock_irqrestore(&prtd->lock, flags);
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6APM_STREAM_RUNNING)
q6apm_read(prtd->graph);
@@ -132,6 +146,63 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo
}
}
+static void event_handler_compr(uint32_t opcode, uint32_t token,
+ void *payload, void *priv)
+{
+ struct q6apm_dai_rtd *prtd = priv;
+ struct snd_compr_stream *substream = prtd->cstream;
+ uint32_t wflags = 0;
+ uint64_t avail;
+ uint32_t bytes_written, bytes_to_write;
+ bool is_last_buffer = false;
+
+ guard(spinlock_irqsave)(&prtd->lock);
+ switch (opcode) {
+ case APM_CLIENT_EVENT_CMD_EOS_DONE:
+ if (prtd->notify_on_drain) {
+ snd_compr_drain_notify(prtd->cstream);
+ prtd->notify_on_drain = false;
+ } else {
+ prtd->state = Q6APM_STREAM_STOPPED;
+ }
+ break;
+ case APM_CLIENT_EVENT_DATA_WRITE_DONE:
+ bytes_written = token >> APM_WRITE_TOKEN_LEN_SHIFT;
+ prtd->copied_total += bytes_written;
+ snd_compr_fragment_elapsed(substream);
+
+ if (prtd->state != Q6APM_STREAM_RUNNING)
+ break;
+
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail > prtd->pcm_count) {
+ bytes_to_write = prtd->pcm_count;
+ } else {
+ if (substream->partial_drain || prtd->notify_on_drain)
+ is_last_buffer = true;
+ bytes_to_write = avail;
+ }
+
+ if (bytes_to_write) {
+ if (substream->partial_drain && is_last_buffer)
+ wflags |= APM_LAST_BUFFER_FLAG;
+
+ q6apm_write_async(prtd->graph,
+ bytes_to_write, 0, 0, wflags);
+
+ prtd->bytes_sent += bytes_to_write;
+
+ if (prtd->notify_on_drain && is_last_buffer)
+ audioreach_shared_memory_send_eos(prtd->graph);
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
static int q6apm_dai_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -155,6 +226,8 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
cfg.sample_rate = runtime->rate;
cfg.num_channels = runtime->channels;
cfg.bit_width = prtd->bits_per_sample;
+ cfg.fmt = SND_AUDIOCODEC_PCM;
+ audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels);
if (prtd->state) {
/* clear the previous setup if any */
@@ -163,7 +236,6 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
}
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pos = 0;
/* rate and channels are sent to audio driver */
ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
if (ret < 0) {
@@ -209,6 +281,27 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
return 0;
}
+static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ int i, ret = 0, avail_periods;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size;
+ for (i = 0; i < avail_periods; i++) {
+ ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ if (ret < 0) {
+ dev_err(component->dev, "Error queuing playback buffer %d\n", ret);
+ return ret;
+ }
+ prtd->queue_ptr += runtime->period_size;
+ }
+ }
+
+ return ret;
+}
+
static int q6apm_dai_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
@@ -220,9 +313,6 @@ static int q6apm_dai_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- /* start writing buffers for playback only as we already queued capture buffers */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
/* TODO support be handled via SoftPause Module */
@@ -243,8 +333,8 @@ static int q6apm_dai_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0);
+ struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0);
struct device *dev = component->dev;
struct q6apm_dai_data *pdata;
struct q6apm_dai_rtd *prtd;
@@ -264,7 +354,7 @@ static int q6apm_dai_open(struct snd_soc_component *component,
spin_lock_init(&prtd->lock);
prtd->substream = substream;
- prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id);
+ prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id);
if (IS_ERR(prtd->graph)) {
dev_err(dev, "%s: Could not allocate memory\n", __func__);
ret = PTR_ERR(prtd->graph);
@@ -292,13 +382,14 @@ static int q6apm_dai_open(struct snd_soc_component *component,
}
}
- ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ /* setup 10ms latency to accommodate DSP restrictions */
+ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);
if (ret < 0) {
dev_err(dev, "constraint for period bytes step ret = %d\n", ret);
goto err;
}
- ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);
if (ret < 0) {
dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret);
goto err;
@@ -343,16 +434,12 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct q6apm_dai_rtd *prtd = runtime->private_data;
snd_pcm_uframes_t ptr;
- unsigned long flags;
-
- spin_lock_irqsave(&prtd->lock, flags);
- if (prtd->pos == prtd->pcm_size)
- prtd->pos = 0;
- ptr = bytes_to_frames(runtime, prtd->pos);
- spin_unlock_irqrestore(&prtd->lock, flags);
+ ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size;
+ if (ptr)
+ return ptr - 1;
- return ptr;
+ return 0;
}
static int q6apm_dai_hw_params(struct snd_soc_component *component,
@@ -386,6 +473,359 @@ static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc
return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size);
}
+static int q6apm_dai_compr_open(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd;
+ struct q6apm_dai_data *pdata;
+ struct device *dev = component->dev;
+ int ret, size;
+ int graph_id;
+
+ graph_id = cpu_dai->driver->id;
+ pdata = snd_soc_component_get_drvdata(component);
+ if (!pdata)
+ return -EINVAL;
+
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ prtd->cstream = stream;
+ prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id);
+ if (IS_ERR(prtd->graph)) {
+ ret = PTR_ERR(prtd->graph);
+ kfree(prtd);
+ return ret;
+ }
+
+ runtime->private_data = prtd;
+ runtime->dma_bytes = BUFFER_BYTES_MAX;
+ size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE * COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &prtd->dma_buffer);
+ if (ret)
+ return ret;
+
+ if (pdata->sid < 0)
+ prtd->phys = prtd->dma_buffer.addr;
+ else
+ prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
+
+ snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
+ spin_lock_init(&prtd->lock);
+
+ q6apm_enable_compress_module(dev, prtd->graph, true);
+ return 0;
+}
+
+static int q6apm_dai_compr_free(struct snd_soc_component *component,
+ struct snd_compr_stream *stream)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+
+ q6apm_graph_stop(prtd->graph);
+ q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK);
+ q6apm_graph_close(prtd->graph);
+ snd_dma_free_pages(&prtd->dma_buffer);
+ prtd->graph = NULL;
+ kfree(prtd);
+ runtime->private_data = NULL;
+
+ return 0;
+}
+
+static int q6apm_dai_compr_get_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps)
+{
+ caps->direction = SND_COMPRESS_PLAYBACK;
+ caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
+ caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
+ caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
+ caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ caps->num_codecs = 4;
+ caps->codecs[0] = SND_AUDIOCODEC_MP3;
+ caps->codecs[1] = SND_AUDIOCODEC_AAC;
+ caps->codecs[2] = SND_AUDIOCODEC_FLAC;
+ caps->codecs[3] = SND_AUDIOCODEC_OPUS_RAW;
+
+ return 0;
+}
+
+static int q6apm_dai_compr_get_codec_caps(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec)
+{
+ switch (codec->codec) {
+ case SND_AUDIOCODEC_MP3:
+ *codec = q6apm_compr_caps;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int q6apm_dai_compr_pointer(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_tstamp64 *tstamp)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ uint64_t temp_copied_total;
+
+ guard(spinlock_irqsave)(&prtd->lock);
+ tstamp->copied_total = prtd->copied_total;
+ temp_copied_total = tstamp->copied_total;
+ tstamp->byte_offset = do_div(temp_copied_total, prtd->pcm_size);
+
+ return 0;
+}
+
+static int q6apm_dai_compr_trigger(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, int cmd)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SND_COMPR_TRIGGER_NEXT_TRACK:
+ prtd->next_track = true;
+ break;
+ case SND_COMPR_TRIGGER_DRAIN:
+ case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+ prtd->notify_on_drain = true;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int q6apm_dai_compr_ack(struct snd_soc_component *component, struct snd_compr_stream *stream,
+ size_t count)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+
+ guard(spinlock_irqsave)(&prtd->lock);
+ prtd->bytes_received += count;
+
+ return count;
+}
+
+static int q6apm_dai_compr_set_params(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ struct q6apm_dai_data *pdata;
+ struct audioreach_module_config cfg;
+ struct snd_codec *codec = &params->codec;
+ int dir = stream->direction;
+ int ret;
+
+ pdata = snd_soc_component_get_drvdata(component);
+ if (!pdata)
+ return -EINVAL;
+
+ prtd->periods = runtime->fragments;
+ prtd->pcm_count = runtime->fragment_size;
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+ prtd->bits_per_sample = 16;
+
+ if (prtd->next_track != true) {
+ memcpy(&prtd->codec, codec, sizeof(*codec));
+
+ ret = q6apm_set_real_module_id(component->dev, prtd->graph, codec->id);
+ if (ret)
+ return ret;
+
+ cfg.direction = dir;
+ cfg.sample_rate = codec->sample_rate;
+ cfg.num_channels = 2;
+ cfg.bit_width = prtd->bits_per_sample;
+ cfg.fmt = codec->id;
+ audioreach_set_default_channel_mapping(cfg.channel_map,
+ cfg.num_channels);
+ memcpy(&cfg.codec, codec, sizeof(*codec));
+
+ ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
+ if (ret < 0)
+ return ret;
+
+ ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg);
+ if (ret)
+ return ret;
+
+ ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK,
+ prtd->phys, (prtd->pcm_size / prtd->periods),
+ prtd->periods);
+ if (ret < 0)
+ return -ENOMEM;
+
+ ret = q6apm_graph_prepare(prtd->graph);
+ if (ret)
+ return ret;
+
+ ret = q6apm_graph_start(prtd->graph);
+ if (ret)
+ return ret;
+
+ } else {
+ cfg.direction = dir;
+ cfg.sample_rate = codec->sample_rate;
+ cfg.num_channels = 2;
+ cfg.bit_width = prtd->bits_per_sample;
+ cfg.fmt = codec->id;
+ memcpy(&cfg.codec, codec, sizeof(*codec));
+
+ ret = audioreach_compr_set_param(prtd->graph, &cfg);
+ if (ret < 0)
+ return ret;
+ }
+ prtd->state = Q6APM_STREAM_RUNNING;
+
+ return 0;
+}
+
+static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct snd_compr_metadata *metadata)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ int ret = 0;
+
+ switch (metadata->key) {
+ case SNDRV_COMPRESS_ENCODER_PADDING:
+ q6apm_remove_trailing_silence(component->dev, prtd->graph,
+ metadata->value[0]);
+ break;
+ case SNDRV_COMPRESS_ENCODER_DELAY:
+ q6apm_remove_initial_silence(component->dev, prtd->graph,
+ metadata->value[0]);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int q6apm_dai_compr_mmap(struct snd_soc_component *component,
+ struct snd_compr_stream *stream,
+ struct vm_area_struct *vma)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ struct device *dev = component->dev;
+
+ return dma_mmap_coherent(dev, vma, prtd->dma_buffer.area, prtd->dma_buffer.addr,
+ prtd->dma_buffer.bytes);
+}
+
+static int q6apm_compr_copy(struct snd_soc_component *component,
+ struct snd_compr_stream *stream, char __user *buf,
+ size_t count)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6apm_dai_rtd *prtd = runtime->private_data;
+ void *dstn;
+ size_t copy;
+ u32 wflags = 0;
+ u32 app_pointer;
+ uint64_t bytes_received;
+ uint64_t temp_bytes_received;
+ uint32_t bytes_to_write;
+ uint64_t avail, bytes_in_flight = 0;
+
+ bytes_received = prtd->bytes_received;
+ temp_bytes_received = bytes_received;
+
+ /**
+ * Make sure that next track data pointer is aligned at 32 bit boundary
+ * This is a Mandatory requirement from DSP data buffers alignment
+ */
+ if (prtd->next_track) {
+ bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
+ temp_bytes_received = bytes_received;
+ }
+
+ app_pointer = do_div(temp_bytes_received, prtd->pcm_size);
+ dstn = prtd->dma_buffer.area + app_pointer;
+
+ if (count < prtd->pcm_size - app_pointer) {
+ if (copy_from_user(dstn, buf, count))
+ return -EFAULT;
+ } else {
+ copy = prtd->pcm_size - app_pointer;
+ if (copy_from_user(dstn, buf, copy))
+ return -EFAULT;
+ if (copy_from_user(prtd->dma_buffer.area, buf + copy, count - copy))
+ return -EFAULT;
+ }
+
+ guard(spinlock_irqsave)(&prtd->lock);
+ bytes_in_flight = prtd->bytes_received - prtd->copied_total;
+
+ if (prtd->next_track) {
+ prtd->next_track = false;
+ prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
+ prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
+ }
+
+ prtd->bytes_received = bytes_received + count;
+
+ /* Kick off the data to dsp if its starving!! */
+ if (prtd->state == Q6APM_STREAM_RUNNING && (bytes_in_flight == 0)) {
+ bytes_to_write = prtd->pcm_count;
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail < prtd->pcm_count)
+ bytes_to_write = avail;
+
+ q6apm_write_async(prtd->graph, bytes_to_write, 0, 0, wflags);
+ prtd->bytes_sent += bytes_to_write;
+ }
+
+ return count;
+}
+
+static const struct snd_compress_ops q6apm_dai_compress_ops = {
+ .open = q6apm_dai_compr_open,
+ .free = q6apm_dai_compr_free,
+ .get_caps = q6apm_dai_compr_get_caps,
+ .get_codec_caps = q6apm_dai_compr_get_codec_caps,
+ .pointer = q6apm_dai_compr_pointer,
+ .trigger = q6apm_dai_compr_trigger,
+ .ack = q6apm_dai_compr_ack,
+ .set_params = q6apm_dai_compr_set_params,
+ .set_metadata = q6apm_dai_compr_set_metadata,
+ .mmap = q6apm_dai_compr_mmap,
+ .copy = q6apm_compr_copy,
+};
+
static const struct snd_soc_component_driver q6apm_fe_dai_component = {
.name = DRV_NAME,
.open = q6apm_dai_open,
@@ -395,6 +835,9 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = {
.hw_params = q6apm_dai_hw_params,
.pointer = q6apm_dai_pointer,
.trigger = q6apm_dai_trigger,
+ .ack = q6apm_dai_ack,
+ .compress_ops = &q6apm_dai_compress_ops,
+ .use_dai_pcm_id = true,
};
static int q6apm_dai_probe(struct platform_device *pdev)
diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
index 7ad604b80e25..528756f1332b 100644
--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2021, Linaro Limited
+#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -24,13 +25,15 @@ struct q6apm_lpass_dai_data {
};
static int q6dma_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_ch_mask,
- unsigned int rx_num, unsigned int *rx_ch_mask)
+ unsigned int tx_num,
+ const unsigned int *tx_ch_mask,
+ unsigned int rx_num,
+ const unsigned int *rx_ch_mask)
{
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct audioreach_module_config *cfg = &dai_data->module_config[dai->id];
- int ch_mask;
+ int i;
switch (dai->id) {
case WSA_CODEC_DMA_TX_0:
@@ -55,7 +58,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai,
tx_num);
return -EINVAL;
}
- ch_mask = *tx_ch_mask;
+ for (i = 0; i < tx_num; i++)
+ cfg->channel_map[i] = tx_ch_mask[i];
break;
case WSA_CODEC_DMA_RX_0:
@@ -78,7 +82,8 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai,
rx_num);
return -EINVAL;
}
- ch_mask = *rx_ch_mask;
+ for (i = 0; i < rx_num; i++)
+ cfg->channel_map[i] = rx_ch_mask[i];
break;
default:
@@ -87,8 +92,6 @@ static int q6dma_set_channel_map(struct snd_soc_dai *dai,
return -EINVAL;
}
- cfg->active_channels_mask = ch_mask;
-
return 0;
}
@@ -97,12 +100,13 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream,
{
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct audioreach_module_config *cfg = &dai_data->module_config[dai->id];
- int channels = params_channels(params);
+ int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max;
int ret;
cfg->bit_width = params_width(params);
cfg->sample_rate = params_rate(params);
cfg->num_channels = channels;
+ audioreach_set_default_channel_mapping(cfg->channel_map, channels);
switch (dai->id) {
case DISPLAY_PORT_RX_0:
@@ -127,10 +131,12 @@ static int q6dma_hw_params(struct snd_pcm_substream *substream,
{
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct audioreach_module_config *cfg = &dai_data->module_config[dai->id];
+ int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max;
cfg->bit_width = params_width(params);
cfg->sample_rate = params_rate(params);
- cfg->num_channels = params_channels(params);
+ cfg->num_channels = channels;
+ audioreach_set_default_channel_mapping(cfg->channel_map, channels);
return 0;
}
@@ -140,14 +146,17 @@ static void q6apm_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc;
- if (!dai_data->is_port_started[dai->id])
- return;
- rc = q6apm_graph_stop(dai_data->graph[dai->id]);
- if (rc < 0)
- dev_err(dai->dev, "fail to close APM port (%d)\n", rc);
+ if (dai_data->is_port_started[dai->id]) {
+ rc = q6apm_graph_stop(dai_data->graph[dai->id]);
+ dai_data->is_port_started[dai->id] = false;
+ if (rc < 0)
+ dev_err(dai->dev, "fail to close APM port (%d)\n", rc);
+ }
- q6apm_graph_close(dai_data->graph[dai->id]);
- dai_data->is_port_started[dai->id] = false;
+ if (dai_data->graph[dai->id]) {
+ q6apm_graph_close(dai_data->graph[dai->id]);
+ dai_data->graph[dai->id] = NULL;
+ }
}
static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@@ -162,8 +171,10 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
q6apm_graph_stop(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
q6apm_graph_close(dai_data->graph[dai->id]);
+ dai_data->graph[dai->id] = NULL;
+ }
}
/**
@@ -182,26 +193,31 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
cfg->direction = substream->stream;
rc = q6apm_graph_media_format_pcm(dai_data->graph[dai->id], cfg);
-
if (rc) {
dev_err(dai->dev, "Failed to set media format %d\n", rc);
- return rc;
+ goto err;
}
rc = q6apm_graph_prepare(dai_data->graph[dai->id]);
if (rc) {
dev_err(dai->dev, "Failed to prepare Graph %d\n", rc);
- return rc;
+ goto err;
}
rc = q6apm_graph_start(dai_data->graph[dai->id]);
if (rc < 0) {
- dev_err(dai->dev, "fail to start APM port %x\n", dai->id);
- return rc;
+ dev_err(dai->dev, "Failed to start APM port %d\n", dai->id);
+ goto err;
}
dai_data->is_port_started[dai->id] = true;
return 0;
+err:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ q6apm_graph_close(dai_data->graph[dai->id]);
+ dai_data->graph[dai->id] = NULL;
+ }
+ return rc;
}
static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@@ -246,6 +262,7 @@ static const struct snd_soc_dai_ops q6i2s_ops = {
.shutdown = q6apm_lpass_dai_shutdown,
.set_channel_map = q6dma_set_channel_map,
.hw_params = q6dma_hw_params,
+ .set_fmt = q6i2s_set_fmt,
};
static const struct snd_soc_dai_ops q6hdmi_ops = {
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index a7a3f973eb6d..94cc6376a367 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -27,7 +27,7 @@ struct apm_graph_mgmt_cmd {
#define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8)
-struct q6apm *g_apm;
+static struct q6apm *g_apm;
int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
{
@@ -99,12 +99,8 @@ static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t op
struct apm_graph_mgmt_cmd *mgmt_cmd;
struct audioreach_sub_graph *sg;
struct q6apm *apm = graph->apm;
- int i = 0, rc, payload_size;
- struct gpr_pkt *pkt;
-
- payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs);
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0);
+ int i = 0, payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -120,11 +116,7 @@ static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t op
list_for_each_entry(sg, &info->sg_list, node)
mgmt_cmd->sub_graph_id_list[i++] = sg->sub_graph_id;
- rc = q6apm_send_cmd_sync(apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(apm, pkt, 0);
}
static void q6apm_put_audioreach_graph(struct kref *ref)
@@ -148,16 +140,13 @@ static void q6apm_put_audioreach_graph(struct kref *ref)
static int q6apm_get_apm_state(struct q6apm *apm)
{
- struct gpr_pkt *pkt;
-
- pkt = audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(0,
+ APM_CMD_GET_SPF_STATE, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_GET_SPF_STATE);
- kfree(pkt);
-
return apm->state;
}
@@ -230,7 +219,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;
@@ -270,7 +259,7 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
{
struct apm_cmd_shared_mem_unmap_regions *cmd;
struct audioreach_graph_data *data;
- struct gpr_pkt *pkt;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
int rc;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
@@ -290,7 +279,6 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
cmd->mem_map_handle = data->mem_map_handle;
rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
- kfree(pkt);
audioreach_graph_free_buf(graph);
@@ -298,6 +286,74 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
}
EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions);
+int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
+{
+ struct audioreach_module *module;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_INITIAL_SILENCE, samples);
+}
+EXPORT_SYMBOL_GPL(q6apm_remove_initial_silence);
+
+int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
+{
+ struct audioreach_module *module;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_TRAILING_SILENCE, samples);
+}
+EXPORT_SYMBOL_GPL(q6apm_remove_trailing_silence);
+
+int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en)
+{
+ struct audioreach_module *module;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, en);
+}
+EXPORT_SYMBOL_GPL(q6apm_enable_compress_module);
+
+int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph,
+ uint32_t codec_id)
+{
+ struct audioreach_module *module;
+ uint32_t module_id;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ switch (codec_id) {
+ case SND_AUDIOCODEC_MP3:
+ module_id = MODULE_ID_MP3_DECODE;
+ break;
+ case SND_AUDIOCODEC_AAC:
+ module_id = MODULE_ID_AAC_DEC;
+ break;
+ case SND_AUDIOCODEC_FLAC:
+ module_id = MODULE_ID_FLAC_DEC;
+ break;
+ case SND_AUDIOCODEC_OPUS_RAW:
+ module_id = MODULE_ID_OPUS_DEC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_REAL_MODULE_ID,
+ module_id);
+}
+EXPORT_SYMBOL_GPL(q6apm_set_real_module_id);
+
int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, struct audioreach_module_config *cfg)
{
struct audioreach_graph_info *info = graph->info;
@@ -352,13 +408,11 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
{
struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
struct audio_buffer *ab;
- struct gpr_pkt *pkt;
- int rc, iid;
-
- iid = q6apm_graph_get_rx_shmem_module_iid(graph);
- pkt = audioreach_alloc_pkt(sizeof(*write_buffer), DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
- graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
- graph->port->id, iid);
+ int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*write_buffer),
+ DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
+ graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
+ graph->port->id, iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -382,11 +436,7 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
mutex_unlock(&graph->lock);
- rc = gpr_send_port_pkt(graph->port, pkt);
-
- kfree(pkt);
-
- return rc;
+ return gpr_send_port_pkt(graph->port, pkt);
}
EXPORT_SYMBOL_GPL(q6apm_write_async);
@@ -395,12 +445,10 @@ int q6apm_read(struct q6apm_graph *graph)
struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
struct audioreach_graph_data *port;
struct audio_buffer *ab;
- struct gpr_pkt *pkt;
- int rc, iid;
-
- iid = q6apm_graph_get_tx_shmem_module_iid(graph);
- pkt = audioreach_alloc_pkt(sizeof(*read_buffer), DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
- graph->tx_data.dsp_buf, graph->port->id, iid);
+ int iid = q6apm_graph_get_tx_shmem_module_iid(graph);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*read_buffer),
+ DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
+ graph->tx_data.dsp_buf, graph->port->id, iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -422,13 +470,23 @@ int q6apm_read(struct q6apm_graph *graph)
mutex_unlock(&graph->lock);
- rc = gpr_send_port_pkt(graph->port, pkt);
- kfree(pkt);
-
- return rc;
+ return gpr_send_port_pkt(graph->port, pkt);
}
EXPORT_SYMBOL_GPL(q6apm_read);
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
+{
+ struct audioreach_graph_data *data;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ data = &graph->rx_data;
+ else
+ data = &graph->tx_data;
+
+ return (int)atomic_read(&data->hw_ptr);
+}
+EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
+
static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
{
struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
@@ -446,6 +504,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
switch (hdr->opcode) {
case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2:
+ if (!graph->ar_graph)
+ break;
client_event = APM_CLIENT_EVENT_DATA_WRITE_DONE;
mutex_lock(&graph->lock);
token = hdr->token & APM_WRITE_TOKEN_MASK;
@@ -453,7 +513,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
done = data->payload;
phys = graph->rx_data.buf[token].phys;
mutex_unlock(&graph->lock);
-
+ /* token numbering starts at 0 */
+ atomic_set(&graph->rx_data.hw_ptr, token + 1);
if (lower_32_bits(phys) == done->buf_addr_lsw &&
upper_32_bits(phys) == done->buf_addr_msw) {
graph->result.opcode = hdr->opcode;
@@ -479,11 +540,15 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
wake_up(&graph->cmd_wait);
break;
case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
+ if (!graph->ar_graph)
+ break;
client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
mutex_lock(&graph->lock);
rd_done = data->payload;
phys = graph->tx_data.buf[hdr->token].phys;
mutex_unlock(&graph->lock);
+ /* token numbering starts at 0 */
+ atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
lower_32_bits(phys) == rd_done->buf_addr_lsw) {
@@ -497,6 +562,9 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
}
break;
case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
+ client_event = APM_CLIENT_EVENT_CMD_EOS_DONE;
+ if (graph->cb)
+ graph->cb(client_event, hdr->token, data->payload, graph->priv);
break;
case GPR_BASIC_RSP_RESULT:
switch (result->opcode) {
@@ -581,8 +649,9 @@ int q6apm_graph_close(struct q6apm_graph *graph)
{
struct audioreach_graph *ar_graph = graph->ar_graph;
- gpr_free_port(graph->port);
+ graph->ar_graph = NULL;
kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
+ gpr_free_port(graph->port);
kfree(graph);
return 0;
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index 7005be9b63e3..7ce08b401e31 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -2,6 +2,7 @@
#ifndef __Q6APM_H__
#define __Q6APM_H__
#include <linux/types.h>
+#include <linux/atomic.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/kernel.h>
@@ -13,7 +14,6 @@
#include <linux/of_platform.h>
#include <linux/jiffies.h>
#include <linux/soc/qcom/apr.h>
-#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include "audioreach.h"
#define APM_PORT_MAX 127
@@ -45,6 +45,8 @@
#define APM_WRITE_TOKEN_LEN_SHIFT 16
#define APM_MAX_SESSIONS 8
+#define APM_LAST_BUFFER_FLAG BIT(30)
+#define NO_TIMESTAMP 0xFF00
struct q6apm {
struct device *dev;
@@ -76,6 +78,7 @@ struct audioreach_graph_data {
uint32_t num_periods;
uint32_t dsp_buf;
uint32_t mem_map_handle;
+ atomic_t hw_ptr;
};
struct audioreach_graph {
@@ -124,7 +127,6 @@ int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
struct audioreach_module_config *cfg);
/* read/write related */
-int q6apm_send_eos_nowait(struct q6apm_graph *graph);
int q6apm_read(struct q6apm_graph *graph);
int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t wflags);
@@ -142,9 +144,13 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
/* Callback for graph specific */
struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph,
uint32_t mid);
-void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv);
int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);
bool q6apm_is_adsp_ready(void);
+int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en);
+int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
+int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);
+int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id);
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir);
#endif /* __APM_GRAPH_ */
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 5fc8088e63c8..709b4f3318ff 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -2,9 +2,11 @@
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
+#include <dt-bindings/sound/qcom,q6asm.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
@@ -12,9 +14,9 @@
#include <sound/pcm.h>
#include <linux/spinlock.h>
#include <sound/compress_driver.h>
+#include <asm/div64.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include "q6asm.h"
#include "q6routing.h"
@@ -56,12 +58,12 @@ struct q6asm_dai_rtd {
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
- unsigned int pcm_irq_pos; /* IRQ position */
unsigned int periods;
- unsigned int bytes_sent;
- unsigned int bytes_received;
- unsigned int copied_total;
+ uint64_t bytes_sent;
+ uint64_t bytes_received;
+ uint64_t copied_total;
uint16_t bits_per_sample;
+ snd_pcm_uframes_t queue_ptr;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
uint32_t next_track_stream_id;
@@ -83,6 +85,7 @@ struct q6asm_dai_data {
static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
@@ -102,10 +105,11 @@ static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
.fifo_size = 0,
};
-static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
+static const struct snd_pcm_hardware q6asm_dai_hardware_playback = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_NO_REWINDS | SNDRV_PCM_INFO_SYNC_APPLPTR |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -127,8 +131,13 @@ static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
#define Q6ASM_FEDAI_DRIVER(num) { \
.playback = { \
.stream_name = "MultiMedia"#num" Playback", \
- .rates = (SNDRV_PCM_RATE_8000_192000| \
- SNDRV_PCM_RATE_KNOT), \
+ .rates = (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_12000 | \
+ SNDRV_PCM_RATE_24000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000), \
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE), \
.channels_min = 1, \
@@ -138,8 +147,9 @@ static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
}, \
.capture = { \
.stream_name = "MultiMedia"#num" Capture", \
- .rates = (SNDRV_PCM_RATE_8000_48000| \
- SNDRV_PCM_RATE_KNOT), \
+ .rates = (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_12000 | \
+ SNDRV_PCM_RATE_24000), \
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE), \
.channels_min = 1, \
@@ -151,18 +161,6 @@ static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
.id = MSM_FRONTEND_DAI_MULTIMEDIA##num, \
}
-/* Conventional and unconventional sample rate supported */
-static unsigned int supported_sample_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
- 88200, 96000, 176400, 192000
-};
-
-static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
- .count = ARRAY_SIZE(supported_sample_rates),
- .list = supported_sample_rates,
- .mask = 0,
-};
-
static const struct snd_compr_codec_caps q6asm_compr_caps = {
.num_descriptors = 1,
.descriptor[0].max_ch = 2,
@@ -186,24 +184,15 @@ static void event_handler(uint32_t opcode, uint32_t token,
switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
prtd->state = Q6ASM_STREAM_STOPPED;
break;
case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
- prtd->pcm_irq_pos += prtd->pcm_count;
snd_pcm_period_elapsed(substream);
- if (prtd->state == Q6ASM_STREAM_RUNNING)
- q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
-
break;
}
case ASM_CLIENT_EVENT_DATA_READ_DONE:
- prtd->pcm_irq_pos += prtd->pcm_count;
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING)
q6asm_read(prtd->audio_client, prtd->stream_id);
@@ -218,7 +207,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
struct q6asm_dai_rtd *prtd = runtime->private_data;
struct q6asm_dai_data *pdata;
struct device *dev = component->dev;
@@ -235,15 +224,15 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
}
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pcm_irq_pos = 0;
/* rate and channels are sent to audio driver */
- if (prtd->state) {
+ if (prtd->state == Q6ASM_STREAM_RUNNING) {
/* clear the previous setup if any */
q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
q6asm_unmap_memory_regions(substream->stream,
prtd->audio_client);
q6routing_stream_close(soc_prtd->dai_link->id,
substream->stream);
+ prtd->state = Q6ASM_STREAM_STOPPED;
}
ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
@@ -314,6 +303,29 @@ open_err:
return ret;
}
+static int q6asm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ int i, ret = 0, avail_periods;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && prtd->state == Q6ASM_STREAM_RUNNING) {
+ avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size;
+ for (i = 0; i < avail_periods; i++) {
+ ret = q6asm_write_async(prtd->audio_client, prtd->stream_id,
+ prtd->pcm_count, 0, 0, 0);
+
+ if (ret < 0) {
+ dev_err(component->dev, "Error queuing playback buffer %d\n", ret);
+ return ret;
+ }
+ prtd->queue_ptr += runtime->period_size;
+ }
+ }
+
+ return ret;
+}
+
static int q6asm_dai_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
@@ -350,8 +362,8 @@ static int q6asm_dai_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0);
+ struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0);
struct q6asm_dai_rtd *prtd;
struct q6asm_dai_data *pdata;
struct device *dev = component->dev;
@@ -389,11 +401,6 @@ static int q6asm_dai_open(struct snd_soc_component *component,
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
runtime->hw = q6asm_dai_hardware_capture;
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_sample_rates);
- if (ret < 0)
- dev_info(dev, "snd_pcm_hw_constraint_list failed\n");
/* Ensure that buffer size is a multiple of period size */
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
@@ -412,13 +419,13 @@ static int q6asm_dai_open(struct snd_soc_component *component,
}
ret = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);
if (ret < 0) {
dev_err(dev, "constraint for period bytes step ret = %d\n",
ret);
}
ret = snd_pcm_hw_constraint_step(runtime, 0,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);
if (ret < 0) {
dev_err(dev, "constraint for buffer bytes step ret = %d\n",
ret);
@@ -426,10 +433,13 @@ static int q6asm_dai_open(struct snd_soc_component *component,
runtime->private_data = prtd;
- snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
-
- runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
-
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
+ runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
+ } else {
+ snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_capture);
+ runtime->dma_bytes = q6asm_dai_hardware_capture.buffer_bytes_max;
+ }
if (pdata->sid < 0)
prtd->phys = substream->dma_buffer.addr;
@@ -443,7 +453,7 @@ static int q6asm_dai_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
struct q6asm_dai_rtd *prtd = runtime->private_data;
if (prtd->audio_client) {
@@ -468,11 +478,13 @@ static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
+ snd_pcm_uframes_t ptr;
- if (prtd->pcm_irq_pos >= prtd->pcm_size)
- prtd->pcm_irq_pos = 0;
+ ptr = q6asm_get_hw_pointer(prtd->audio_client, substream->stream) * runtime->period_size;
+ if (ptr)
+ return ptr - 1;
- return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+ return 0;
}
static int q6asm_dai_hw_params(struct snd_soc_component *component,
@@ -502,15 +514,15 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
{
struct q6asm_dai_rtd *prtd = priv;
struct snd_compr_stream *substream = prtd->cstream;
- unsigned long flags;
u32 wflags = 0;
uint64_t avail;
uint32_t bytes_written, bytes_to_write;
bool is_last_buffer = false;
+ guard(spinlock_irqsave)(&prtd->lock);
+
switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
if (!prtd->bytes_sent) {
q6asm_stream_remove_initial_silence(prtd->audio_client,
prtd->stream_id,
@@ -521,11 +533,9 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
prtd->bytes_sent += prtd->pcm_count;
}
- spin_unlock_irqrestore(&prtd->lock, flags);
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
if (prtd->notify_on_drain) {
if (substream->partial_drain) {
/*
@@ -548,20 +558,16 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
} else {
prtd->state = Q6ASM_STREAM_STOPPED;
}
- spin_unlock_irqrestore(&prtd->lock, flags);
break;
case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
- spin_lock_irqsave(&prtd->lock, flags);
bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
prtd->copied_total += bytes_written;
snd_compr_fragment_elapsed(substream);
- if (prtd->state != Q6ASM_STREAM_RUNNING) {
- spin_unlock_irqrestore(&prtd->lock, flags);
+ if (prtd->state != Q6ASM_STREAM_RUNNING)
break;
- }
avail = prtd->bytes_received - prtd->bytes_sent;
if (avail > prtd->pcm_count) {
@@ -590,7 +596,6 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
q6asm_cmd_nowait(prtd->audio_client,
prtd->stream_id, CMD_EOS);
- spin_unlock_irqrestore(&prtd->lock, flags);
break;
default:
@@ -603,7 +608,7 @@ static int q6asm_dai_compr_open(struct snd_soc_component *component,
{
struct snd_soc_pcm_runtime *rtd = stream->private_data;
struct snd_compr_runtime *runtime = stream->runtime;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct q6asm_dai_data *pdata;
struct device *dev = component->dev;
struct q6asm_dai_rtd *prtd;
@@ -902,9 +907,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
if (ret < 0) {
dev_err(dev, "q6asm_open_write failed\n");
- q6asm_audio_client_free(prtd->audio_client);
- prtd->audio_client = NULL;
- return ret;
+ goto open_err;
}
}
@@ -913,7 +916,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
prtd->session_id, dir);
if (ret) {
dev_err(dev, "Stream reg failed ret:%d\n", ret);
- return ret;
+ goto q6_err;
}
ret = __q6asm_dai_compr_set_codec_params(component, stream,
@@ -921,7 +924,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
prtd->stream_id);
if (ret) {
dev_err(dev, "codec param setup failed ret:%d\n", ret);
- return ret;
+ goto q6_err;
}
ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
@@ -930,12 +933,21 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
if (ret < 0) {
dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto q6_err;
}
prtd->state = Q6ASM_STREAM_RUNNING;
return 0;
+
+q6_err:
+ q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
+
+open_err:
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
}
static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
@@ -1029,18 +1041,17 @@ static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
struct snd_compr_stream *stream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
- unsigned long flags;
+ uint64_t temp_copied_total;
- spin_lock_irqsave(&prtd->lock, flags);
+ guard(spinlock_irqsave)(&prtd->lock);
tstamp->copied_total = prtd->copied_total;
- tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
-
- spin_unlock_irqrestore(&prtd->lock, flags);
+ temp_copied_total = tstamp->copied_total;
+ tstamp->byte_offset = do_div(temp_copied_total, prtd->pcm_size);
return 0;
}
@@ -1051,25 +1062,27 @@ static int q6asm_compr_copy(struct snd_soc_component *component,
{
struct snd_compr_runtime *runtime = stream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
- unsigned long flags;
u32 wflags = 0;
- int avail, bytes_in_flight = 0;
+ uint64_t avail, bytes_in_flight = 0;
void *dstn;
size_t copy;
u32 app_pointer;
- u32 bytes_received;
+ uint64_t bytes_received;
+ uint64_t temp_bytes_received;
bytes_received = prtd->bytes_received;
+ temp_bytes_received = bytes_received;
/**
* Make sure that next track data pointer is aligned at 32 bit boundary
* This is a Mandatory requirement from DSP data buffers alignment
*/
- if (prtd->next_track)
+ if (prtd->next_track) {
bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
+ temp_bytes_received = bytes_received;
+ }
- app_pointer = bytes_received/prtd->pcm_size;
- app_pointer = bytes_received - (app_pointer * prtd->pcm_size);
+ app_pointer = do_div(temp_bytes_received, prtd->pcm_size);
dstn = prtd->dma_buffer.area + app_pointer;
if (count < prtd->pcm_size - app_pointer) {
@@ -1084,7 +1097,7 @@ static int q6asm_compr_copy(struct snd_soc_component *component,
return -EFAULT;
}
- spin_lock_irqsave(&prtd->lock, flags);
+ guard(spinlock_irqsave)(&prtd->lock);
bytes_in_flight = prtd->bytes_received - prtd->copied_total;
@@ -1110,8 +1123,6 @@ static int q6asm_compr_copy(struct snd_soc_component *component,
prtd->bytes_sent += bytes_to_write;
}
- spin_unlock_irqrestore(&prtd->lock, flags);
-
return count;
}
@@ -1211,6 +1222,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.close = q6asm_dai_close,
.prepare = q6asm_dai_prepare,
.trigger = q6asm_dai_trigger,
+ .ack = q6asm_dai_ack,
.pointer = q6asm_dai_pointer,
.pcm_construct = q6asm_dai_pcm_new,
.compress_ops = &q6asm_dai_compress_ops,
@@ -1230,6 +1242,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
Q6ASM_FEDAI_DRIVER(8),
};
+static const struct snd_soc_dai_ops q6asm_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static int of_q6asm_parse_dai_data(struct device *dev,
struct q6asm_dai_data *pdata)
{
@@ -1272,7 +1288,7 @@ static int of_q6asm_parse_dai_data(struct device *dev,
dai_drv->playback = empty_stream;
if (of_property_read_bool(node, "is-compress-dai"))
- dai_drv->compress_new = snd_soc_new_compress;
+ dai_drv->ops = &q6asm_dai_ops;
}
return 0;
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 195780f75d05..e7295b7b2461 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -2,9 +2,11 @@
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
+#include <dt-bindings/sound/qcom,q6asm.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/module.h>
+#include <linux/atomic.h>
#include <linux/soc/qcom/apr.h>
#include <linux/device.h>
#include <linux/of_platform.h>
@@ -247,6 +249,7 @@ struct audio_port_data {
uint32_t num_periods;
uint32_t dsp_buf;
uint32_t mem_map_handle;
+ atomic_t hw_ptr;
};
struct q6asm {
@@ -332,7 +335,7 @@ static int __q6asm_memory_unmap(struct audio_client *ac,
struct q6asm *a = dev_get_drvdata(ac->dev->parent);
struct apr_pkt *pkt;
int rc, pkt_size;
- void *p;
+ void *p __free(kfree) = NULL;
if (ac->port[dir].mem_map_handle == 0) {
dev_err(ac->dev, "invalid mem handle\n");
@@ -357,14 +360,11 @@ static int __q6asm_memory_unmap(struct audio_client *ac,
mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle;
rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0);
- if (rc < 0) {
- kfree(pkt);
+ if (rc < 0)
return rc;
- }
ac->port[dir].mem_map_handle = 0;
- kfree(pkt);
return 0;
}
@@ -376,9 +376,9 @@ static void q6asm_audio_client_free_buf(struct audio_client *ac,
spin_lock_irqsave(&ac->lock, flags);
port->num_periods = 0;
+ spin_unlock_irqrestore(&ac->lock, flags);
kfree(port->buf);
port->buf = NULL;
- spin_unlock_irqrestore(&ac->lock, flags);
}
/**
@@ -428,10 +428,10 @@ static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
struct audio_port_data *port = NULL;
struct audio_buffer *ab = NULL;
struct apr_pkt *pkt;
- void *p;
+ void *p __free(kfree) = NULL;
unsigned long flags;
uint32_t num_regions, buf_sz;
- int rc, i, pkt_size;
+ int i, pkt_size;
if (is_contiguous) {
num_regions = 1;
@@ -478,12 +478,7 @@ static int __q6asm_memory_map_regions(struct audio_client *ac, int dir,
}
spin_unlock_irqrestore(&ac->lock, flags);
- rc = q6asm_apr_send_session_pkt(a, ac, pkt,
- ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
-
- kfree(pkt);
-
- return rc;
+ return q6asm_apr_send_session_pkt(a, ac, pkt, ASM_CMDRSP_SHARED_MEM_MAP_REGIONS);
}
/**
@@ -576,9 +571,8 @@ static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
int session_id)
{
struct audio_client *ac = NULL;
- unsigned long flags;
- spin_lock_irqsave(&a->slock, flags);
+ guard(spinlock_irqsave)(&a->slock);
if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
dev_err(a->dev, "invalid session: %d\n", session_id);
goto err;
@@ -593,10 +587,17 @@ static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
ac = a->session[session_id];
kref_get(&ac->refcount);
err:
- spin_unlock_irqrestore(&a->slock, flags);
return ac;
}
+int q6asm_get_hw_pointer(struct audio_client *ac, unsigned int dir)
+{
+ struct audio_port_data *data = &ac->port[dir];
+
+ return (int)atomic_read(&data->hw_ptr);
+}
+EXPORT_SYMBOL_GPL(q6asm_get_hw_pointer);
+
static int32_t q6asm_stream_callback(struct apr_device *adev,
struct apr_resp_pkt *data,
int session_id)
@@ -637,6 +638,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
break;
case ASM_STREAM_CMD_OPEN_WRITE_V3:
+ case ASM_DATA_CMD_WRITE_V2:
case ASM_STREAM_CMD_OPEN_READ_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
@@ -653,6 +655,10 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
goto done;
}
break;
+ case ASM_DATA_CMD_EOS:
+ case ASM_DATA_CMD_READ_V2:
+ /* response as result of close stream */
+ break;
default:
dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
result->opcode);
@@ -673,15 +679,13 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE;
if (ac->io_mode & ASM_SYNC_IO_MODE) {
phys_addr_t phys;
- unsigned long flags;
int token = hdr->token & ASM_WRITE_TOKEN_MASK;
- spin_lock_irqsave(&ac->lock, flags);
+ guard(spinlock_irqsave)(&ac->lock);
port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
if (!port->buf) {
- spin_unlock_irqrestore(&ac->lock, flags);
ret = 0;
goto done;
}
@@ -692,29 +696,27 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
upper_32_bits(phys) != result->status) {
dev_err(ac->dev, "Expected addr %pa\n",
&port->buf[token].phys);
- spin_unlock_irqrestore(&ac->lock, flags);
ret = -EINVAL;
goto done;
}
- spin_unlock_irqrestore(&ac->lock, flags);
+ atomic_set(&port->hw_ptr, token + 1);
}
break;
case ASM_DATA_EVENT_READ_DONE_V2:
client_event = ASM_CLIENT_EVENT_DATA_READ_DONE;
if (ac->io_mode & ASM_SYNC_IO_MODE) {
struct asm_data_cmd_read_v2_done *done = data->payload;
- unsigned long flags;
phys_addr_t phys;
- spin_lock_irqsave(&ac->lock, flags);
+ guard(spinlock_irqsave)(&ac->lock);
port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
if (!port->buf) {
- spin_unlock_irqrestore(&ac->lock, flags);
ret = 0;
goto done;
}
phys = port->buf[hdr->token].phys;
+ atomic_set(&port->hw_ptr, hdr->token + 1);
if (upper_32_bits(phys) != done->buf_addr_msw ||
lower_32_bits(phys) != done->buf_addr_lsw) {
@@ -722,11 +724,9 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
&port->buf[hdr->token].phys,
done->buf_addr_lsw,
done->buf_addr_msw);
- spin_unlock_irqrestore(&ac->lock, flags);
ret = -EINVAL;
goto done;
}
- spin_unlock_irqrestore(&ac->lock, flags);
}
break;
@@ -929,12 +929,8 @@ int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
{
struct asm_stream_cmd_open_write_v3 *open;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*open);
-
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int rc, pkt_size = APR_HDR_SIZE + sizeof(*open);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1000,7 +996,6 @@ int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
ac->io_mode |= ASM_TUN_WRITE_IO_MODE;
err:
- kfree(pkt);
return rc;
}
EXPORT_SYMBOL_GPL(q6asm_open_write);
@@ -1011,11 +1006,8 @@ static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
{
struct asm_session_cmd_run_v2 *run;
struct apr_pkt *pkt;
- int pkt_size, rc;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*run);
- p = kzalloc(pkt_size, GFP_ATOMIC);
+ int rc, pkt_size = APR_HDR_SIZE + sizeof(*run);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC);
if (!p)
return -ENOMEM;
@@ -1036,7 +1028,6 @@ static int __q6asm_run(struct audio_client *ac, uint32_t stream_id,
rc = 0;
}
- kfree(pkt);
return rc;
}
@@ -1097,11 +1088,8 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
struct asm_multi_channel_pcm_fmt_blk_v2 *fmt;
struct apr_pkt *pkt;
u8 *channel_mapping;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*fmt);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1124,16 +1112,11 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
} else {
if (q6dsp_map_channels(channel_mapping, channels)) {
dev_err(ac->dev, " map channels failed %d\n", channels);
- rc = -EINVAL;
- goto err;
+ return -EINVAL;
}
}
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
-
-err:
- kfree(pkt);
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
@@ -1143,11 +1126,8 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
{
struct asm_flac_fmt_blk_v2 *fmt;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*fmt);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1167,10 +1147,7 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
fmt->max_frame_size = cfg->max_frame_size;
fmt->sample_size = cfg->sample_size;
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
- kfree(pkt);
-
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
@@ -1180,11 +1157,8 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
{
struct asm_wmastdv9_fmt_blk_v2 *fmt;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*fmt);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1205,10 +1179,7 @@ int q6asm_stream_media_format_block_wma_v9(struct audio_client *ac,
fmt->enc_options = cfg->enc_options;
fmt->reserved = 0;
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
- kfree(pkt);
-
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v9);
@@ -1218,11 +1189,8 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
{
struct asm_wmaprov10_fmt_blk_v2 *fmt;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*fmt);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1244,10 +1212,7 @@ int q6asm_stream_media_format_block_wma_v10(struct audio_client *ac,
fmt->advanced_enc_options1 = cfg->adv_enc_options;
fmt->advanced_enc_options2 = cfg->adv_enc_options2;
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
- kfree(pkt);
-
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_wma_v10);
@@ -1257,11 +1222,8 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac,
{
struct asm_alac_fmt_blk_v2 *fmt;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*fmt);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1286,10 +1248,7 @@ int q6asm_stream_media_format_block_alac(struct audio_client *ac,
fmt->mb = cfg->mb;
fmt->kb = cfg->kb;
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
- kfree(pkt);
-
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_alac);
@@ -1299,11 +1258,8 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac,
{
struct asm_ape_fmt_blk_v2 *fmt;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(*fmt);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1326,10 +1282,7 @@ int q6asm_stream_media_format_block_ape(struct audio_client *ac,
fmt->sample_rate = cfg->sample_rate;
fmt->seek_table_present = cfg->seek_table_present;
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
- kfree(pkt);
-
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_ape);
@@ -1339,11 +1292,8 @@ static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_
{
uint32_t *samples;
struct apr_pkt *pkt;
- void *p;
- int rc, pkt_size;
-
- pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
- p = kzalloc(pkt_size, GFP_ATOMIC);
+ int rc, pkt_size = APR_HDR_SIZE + sizeof(uint32_t);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC);
if (!p)
return -ENOMEM;
@@ -1358,8 +1308,6 @@ static int q6asm_stream_remove_silence(struct audio_client *ac, uint32_t stream_
if (rc == pkt_size)
rc = 0;
- kfree(pkt);
-
return rc;
}
@@ -1402,11 +1350,8 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
struct apr_pkt *pkt;
u8 *channel_mapping;
u32 frames_per_buf = 0;
- int pkt_size, rc;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1427,15 +1372,10 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac,
enc_cfg->is_signed = 1;
channel_mapping = enc_cfg->channel_mapping;
- if (q6dsp_map_channels(channel_mapping, channels)) {
- rc = -EINVAL;
- goto err;
- }
+ if (q6dsp_map_channels(channel_mapping, channels))
+ return -EINVAL;
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
-err:
- kfree(pkt);
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
@@ -1455,12 +1395,9 @@ int q6asm_read(struct audio_client *ac, uint32_t stream_id)
struct audio_buffer *ab;
struct apr_pkt *pkt;
unsigned long flags;
- int pkt_size;
+ int pkt_size = APR_HDR_SIZE + sizeof(*read);
int rc = 0;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*read);
- p = kzalloc(pkt_size, GFP_ATOMIC);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC);
if (!p)
return -ENOMEM;
@@ -1492,7 +1429,6 @@ int q6asm_read(struct audio_client *ac, uint32_t stream_id)
else
pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc);
- kfree(pkt);
return rc;
}
EXPORT_SYMBOL_GPL(q6asm_read);
@@ -1502,11 +1438,8 @@ static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
{
struct asm_stream_cmd_open_read_v3 *open;
struct apr_pkt *pkt;
- int pkt_size, rc;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*open);
- p = kzalloc(pkt_size, GFP_KERNEL);
+ int pkt_size = APR_HDR_SIZE + sizeof(*open);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
return -ENOMEM;
@@ -1534,10 +1467,7 @@ static int __q6asm_open_read(struct audio_client *ac, uint32_t stream_id,
pr_err("Invalid format[%d]\n", format);
}
- rc = q6asm_ac_send_cmd_sync(ac, pkt);
-
- kfree(pkt);
- return rc;
+ return q6asm_ac_send_cmd_sync(ac, pkt);
}
/**
@@ -1577,12 +1507,9 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
struct audio_buffer *ab;
unsigned long flags;
struct apr_pkt *pkt;
- int pkt_size;
+ int pkt_size = APR_HDR_SIZE + sizeof(*write);
int rc = 0;
- void *p;
-
- pkt_size = APR_HDR_SIZE + sizeof(*write);
- p = kzalloc(pkt_size, GFP_ATOMIC);
+ void *p __free(kfree) = kzalloc(pkt_size, GFP_ATOMIC);
if (!p)
return -ENOMEM;
@@ -1617,7 +1544,6 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
if (rc == pkt_size)
rc = 0;
- kfree(pkt);
return rc;
}
EXPORT_SYMBOL_GPL(q6asm_write_async);
@@ -1625,14 +1551,12 @@ EXPORT_SYMBOL_GPL(q6asm_write_async);
static void q6asm_reset_buf_state(struct audio_client *ac)
{
struct audio_port_data *port;
- unsigned long flags;
- spin_lock_irqsave(&ac->lock, flags);
+ guard(spinlock_irqsave)(&ac->lock);
port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK];
port->dsp_buf = 0;
port = &ac->port[SNDRV_PCM_STREAM_CAPTURE];
port->dsp_buf = 0;
- spin_unlock_irqrestore(&ac->lock, flags);
}
static int __q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd,
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 394604c34943..6fafda5bd849 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -2,7 +2,6 @@
#ifndef __Q6_ASM_H__
#define __Q6_ASM_H__
#include "q6dsp-common.h"
-#include <dt-bindings/sound/qcom,q6asm.h>
/* ASM client callback events */
#define CMD_PAUSE 0x0001
@@ -36,16 +35,16 @@ enum {
#define ASM_LAST_BUFFER_FLAG BIT(30)
struct q6asm_flac_cfg {
- u32 sample_rate;
- u32 ext_sample_rate;
- u32 min_frame_size;
- u32 max_frame_size;
- u16 stream_info_present;
- u16 min_blk_size;
- u16 max_blk_size;
- u16 ch_cfg;
- u16 sample_size;
- u16 md5_sum;
+ u32 sample_rate;
+ u32 ext_sample_rate;
+ u32 min_frame_size;
+ u32 max_frame_size;
+ u16 stream_info_present;
+ u16 min_blk_size;
+ u16 max_blk_size;
+ u16 ch_cfg;
+ u16 sample_size;
+ u16 md5_sum;
};
struct q6asm_wma_cfg {
@@ -149,4 +148,5 @@ int q6asm_map_memory_regions(unsigned int dir,
phys_addr_t phys,
size_t period_sz, unsigned int periods);
int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac);
+int q6asm_get_hw_pointer(struct audio_client *ac, unsigned int dir);
#endif /* __Q6_ASM_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6dsp-common.c b/sound/soc/qcom/qdsp6/q6dsp-common.c
index 95585dea2b36..f74585d88bd6 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-common.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-common.c
@@ -98,4 +98,6 @@ int q6dsp_get_channel_allocation(int channels)
return channel_allocation;
}
EXPORT_SYMBOL_GPL(q6dsp_get_channel_allocation);
+
+MODULE_DESCRIPTION("ASoC MSM QDSP6 helper functions");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
index 4613867d1133..03838582aead 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
@@ -8,7 +8,6 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include "q6dsp-lpass-clocks.h"
@@ -70,17 +69,17 @@ static unsigned long clk_q6dsp_recalc_rate(struct clk_hw *hw,
return clk->rate;
}
-static long clk_q6dsp_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int clk_q6dsp_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- return rate;
+ return 0;
}
static const struct clk_ops clk_q6dsp_ops = {
.prepare = clk_q6dsp_prepare,
.unprepare = clk_q6dsp_unprepare,
.set_rate = clk_q6dsp_set_rate,
- .round_rate = clk_q6dsp_round_rate,
+ .determine_rate = clk_q6dsp_determine_rate,
.recalc_rate = clk_q6dsp_recalc_rate,
};
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
index ac937a6bf909..4eed54b071a5 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
@@ -99,6 +99,26 @@
static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = {
{
.playback = {
+ .stream_name = "USB Playback",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |
+ SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ .id = USB_RX,
+ .name = "USB_RX",
+ },
+ {
+ .playback = {
.stream_name = "HDMI Playback",
.rates = SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_96000 |
@@ -603,9 +623,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
int i;
for (i = 0; i < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) {
- q6dsp_audio_fe_dais[i].probe = cfg->probe;
- q6dsp_audio_fe_dais[i].remove = cfg->remove;
-
switch (q6dsp_audio_fe_dais[i].id) {
case HDMI_RX:
case DISPLAY_PORT_RX:
@@ -627,6 +644,9 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
case WSA_CODEC_DMA_RX_0 ... RX_CODEC_DMA_RX_7:
q6dsp_audio_fe_dais[i].ops = cfg->q6dma_ops;
break;
+ case USB_RX:
+ q6dsp_audio_fe_dais[i].ops = cfg->q6usb_ops;
+ break;
default:
break;
}
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h
index 7f052c8a1257..d8dde6dd0aca 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.h
@@ -11,6 +11,7 @@ struct q6dsp_audio_port_dai_driver_config {
const struct snd_soc_dai_ops *q6i2s_ops;
const struct snd_soc_dai_ops *q6tdm_ops;
const struct snd_soc_dai_ops *q6dma_ops;
+ const struct snd_soc_dai_ops *q6usb_ops;
};
struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c
index 73b0cbac73d4..4c574b48ab00 100644
--- a/sound/soc/qcom/qdsp6/q6prm-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2021, Linaro Limited
+#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include "q6dsp-lpass-clocks.h"
#include "q6prm.h"
diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c
index 81554d202658..0b8fad0bc832 100644
--- a/sound/soc/qcom/qdsp6/q6prm.c
+++ b/sound/soc/qcom/qdsp6/q6prm.c
@@ -62,8 +62,7 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool
struct prm_cmd_request_hw_core *req;
gpr_device_t *gdev = prm->gdev;
uint32_t opcode, rsp_opcode;
- struct gpr_pkt *pkt;
- int rc;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
if (enable) {
opcode = PRM_CMD_REQUEST_HW_RSC;
@@ -88,11 +87,7 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool
req->hw_clk_id = hw_block_id;
- rc = q6prm_send_cmd_sync(prm, pkt, rsp_opcode);
-
- kfree(pkt);
-
- return rc;
+ return q6prm_send_cmd_sync(prm, pkt, rsp_opcode);
}
int q6prm_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
@@ -116,8 +111,7 @@ static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_att
struct apm_module_param_data *param_data;
struct prm_cmd_request_rsc *req;
gpr_device_t *gdev = prm->gdev;
- struct gpr_pkt *pkt;
- int rc;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
pkt = audioreach_alloc_cmd_pkt(sizeof(*req), PRM_CMD_REQUEST_HW_RSC, 0, gdev->svc.id,
GPR_PRM_MODULE_IID);
@@ -139,11 +133,7 @@ static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_att
req->clock_id.clock_attri = clk_attr;
req->clock_id.clock_root = clk_root;
- rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_REQUEST_HW_RSC);
-
- kfree(pkt);
-
- return rc;
+ return q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_REQUEST_HW_RSC);
}
static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
@@ -153,8 +143,7 @@ static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_att
struct apm_module_param_data *param_data;
struct prm_cmd_release_rsc *rel;
gpr_device_t *gdev = prm->gdev;
- struct gpr_pkt *pkt;
- int rc;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
pkt = audioreach_alloc_cmd_pkt(sizeof(*rel), PRM_CMD_RELEASE_HW_RSC, 0, gdev->svc.id,
GPR_PRM_MODULE_IID);
@@ -173,11 +162,7 @@ static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_att
rel->num_clk_id = 1;
rel->clock_id.clock_id = clk_id;
- rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_RELEASE_HW_RSC);
-
- kfree(pkt);
-
- return rc;
+ return q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_RELEASE_HW_RSC);
}
int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index bba07899f8fc..aaa3af9f1993 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -2,14 +2,15 @@
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
+#include <dt-bindings/sound/qcom,q6asm.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/of_platform.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/soc.h>
@@ -434,6 +435,7 @@ static struct session_data *get_session_from_id(struct msm_routing_data *data,
return NULL;
}
+
/**
* q6routing_stream_close() - Deregister a stream
*
@@ -466,8 +468,7 @@ EXPORT_SYMBOL_GPL(q6routing_stream_close);
static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int session_id = mc->shift;
@@ -486,8 +487,7 @@ static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
struct msm_routing_data *data = dev_get_drvdata(c->dev);
struct soc_mixer_control *mc =
@@ -514,6 +514,9 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
return 1;
}
+static const struct snd_kcontrol_new usb_rx_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(USB_RX) };
+
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(HDMI_RX) };
@@ -932,6 +935,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("RX_CODEC_DMA_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
rx_codec_dma_rx_7_mixer_controls,
ARRAY_SIZE(rx_codec_dma_rx_7_mixer_controls)),
+ SND_SOC_DAPM_MIXER("USB_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ usb_rx_mixer_controls,
+ ARRAY_SIZE(usb_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -948,7 +954,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
mmul7_mixer_controls, ARRAY_SIZE(mmul7_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
-
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -1025,6 +1030,7 @@ static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_5 Audio Mixer", "RX_CODEC_DMA_RX_5"),
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"),
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"),
+ Q6ROUTING_RX_DAPM_ROUTE("USB_RX Audio Mixer", "USB_RX"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
@@ -1048,9 +1054,9 @@ static int routing_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct msm_routing_data *data = dev_get_drvdata(component->dev);
- unsigned int be_id = asoc_rtd_to_cpu(rtd, 0)->id;
+ unsigned int be_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
struct session_data *session;
int path_type;
@@ -1160,7 +1166,7 @@ static struct platform_driver q6pcm_routing_platform_driver = {
.of_match_table = of_match_ptr(q6pcm_routing_device_id),
},
.probe = q6pcm_routing_probe,
- .remove_new = q6pcm_routing_remove,
+ .remove = q6pcm_routing_remove,
};
module_platform_driver(q6pcm_routing_platform_driver);
diff --git a/sound/soc/qcom/qdsp6/q6usb.c b/sound/soc/qcom/qdsp6/q6usb.c
new file mode 100644
index 000000000000..6381b289c55c
--- /dev/null
+++ b/sound/soc/qcom/qdsp6/q6usb.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-map-ops.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/asound.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/q6usboffload.h>
+#include <sound/soc.h>
+#include <sound/soc-usb.h>
+
+#include <dt-bindings/sound/qcom,q6afe.h>
+
+#include "q6afe.h"
+#include "q6dsp-lpass-ports.h"
+
+#define Q6_USB_SID_MASK 0xF
+
+struct q6usb_port_data {
+ struct auxiliary_device uauxdev;
+ struct q6afe_usb_cfg usb_cfg;
+ struct snd_soc_usb *usb;
+ struct snd_soc_jack *hs_jack;
+ struct q6usb_offload priv;
+
+ /* Protects against operations between SOC USB and ASoC */
+ struct mutex mutex;
+ struct list_head devices;
+};
+
+static const struct snd_soc_dapm_widget q6usb_dai_widgets[] = {
+ SND_SOC_DAPM_HP("USB_RX_BE", NULL),
+};
+
+static const struct snd_soc_dapm_route q6usb_dapm_routes[] = {
+ {"USB Playback", NULL, "USB_RX_BE"},
+};
+
+static int q6usb_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct q6usb_port_data *data = dev_get_drvdata(dai->dev);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ int direction = substream->stream;
+ struct q6afe_port *q6usb_afe;
+ struct snd_soc_usb_device *sdev;
+ int ret = -EINVAL;
+
+ mutex_lock(&data->mutex);
+
+ /* No active chip index */
+ if (list_empty(&data->devices))
+ goto out;
+
+ sdev = list_last_entry(&data->devices, struct snd_soc_usb_device, list);
+
+ ret = snd_soc_usb_find_supported_format(sdev->chip_idx, params, direction);
+ if (ret < 0)
+ goto out;
+
+ q6usb_afe = q6afe_port_get_from_id(cpu_dai->dev, USB_RX);
+ if (IS_ERR(q6usb_afe)) {
+ ret = PTR_ERR(q6usb_afe);
+ goto out;
+ }
+
+ /* Notify audio DSP about the devices being offloaded */
+ ret = afe_port_send_usb_dev_param(q6usb_afe, sdev->card_idx,
+ sdev->ppcm_idx[sdev->num_playback - 1]);
+
+out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct snd_soc_dai_ops q6usb_ops = {
+ .hw_params = q6usb_hw_params,
+};
+
+static struct snd_soc_dai_driver q6usb_be_dais[] = {
+ {
+ .playback = {
+ .stream_name = "USB BE RX",
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |
+ SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ },
+ .id = USB_RX,
+ .name = "USB_RX_BE",
+ .ops = &q6usb_ops,
+ },
+};
+
+static int q6usb_audio_ports_of_xlate_dai_name(struct snd_soc_component *component,
+ const struct of_phandle_args *args,
+ const char **dai_name)
+{
+ int id = args->args[0];
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(q6usb_be_dais); i++) {
+ if (q6usb_be_dais[i].id == id) {
+ *dai_name = q6usb_be_dais[i].name;
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int q6usb_get_pcm_id_from_widget(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *dai;
+
+ for_each_card_rtds(card, rtd) {
+ dai = snd_soc_rtd_to_cpu(rtd, 0);
+ /*
+ * Only look for playback widget. RTD number carries the assigned
+ * PCM index.
+ */
+ if (dai->stream[0].widget == w)
+ return rtd->id;
+ }
+
+ return -1;
+}
+
+static int q6usb_usb_mixer_enabled(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+
+ /* Checks to ensure USB path is enabled/connected */
+ snd_soc_dapm_widget_for_each_sink_path(w, p)
+ if (!strcmp(p->sink->name, "USB Mixer") && p->connect)
+ return 1;
+
+ return 0;
+}
+
+static int q6usb_get_pcm_id(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_path *p;
+ int pidx;
+
+ /*
+ * Traverse widgets to find corresponding FE widget. The DAI links are
+ * built like the following:
+ * MultiMedia* <-> MM_DL* <-> USB Mixer*
+ */
+ for_each_card_widgets(component->card, w) {
+ if (!strncmp(w->name, "MultiMedia", 10)) {
+ /*
+ * Look up all paths associated with the FE widget to see if
+ * the USB BE is enabled. The sink widget is responsible to
+ * link with the USB mixers.
+ */
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (q6usb_usb_mixer_enabled(p->sink)) {
+ pidx = q6usb_get_pcm_id_from_widget(w);
+ return pidx;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int q6usb_update_offload_route(struct snd_soc_component *component, int card,
+ int pcm, int direction, enum snd_soc_usb_kctl path,
+ long *route)
+{
+ struct q6usb_port_data *data = dev_get_drvdata(component->dev);
+ struct snd_soc_usb_device *sdev;
+ int ret = 0;
+ int idx = -1;
+
+ mutex_lock(&data->mutex);
+
+ if (list_empty(&data->devices) ||
+ direction == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ sdev = list_last_entry(&data->devices, struct snd_soc_usb_device, list);
+
+ /*
+ * Will always look for last PCM device discovered/probed as the
+ * active offload index.
+ */
+ if (card == sdev->card_idx &&
+ pcm == sdev->ppcm_idx[sdev->num_playback - 1]) {
+ idx = path == SND_SOC_USB_KCTL_CARD_ROUTE ?
+ component->card->snd_card->number :
+ q6usb_get_pcm_id(component);
+ }
+
+out:
+ route[0] = idx;
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int q6usb_alsa_connection_cb(struct snd_soc_usb *usb,
+ struct snd_soc_usb_device *sdev, bool connected)
+{
+ struct q6usb_port_data *data;
+
+ if (!usb->component)
+ return -ENODEV;
+
+ data = dev_get_drvdata(usb->component->dev);
+
+ mutex_lock(&data->mutex);
+ if (connected) {
+ if (data->hs_jack)
+ snd_jack_report(data->hs_jack->jack, SND_JACK_USB);
+
+ /* Selects the latest USB headset plugged in for offloading */
+ list_add_tail(&sdev->list, &data->devices);
+ } else {
+ list_del(&sdev->list);
+
+ if (data->hs_jack)
+ snd_jack_report(data->hs_jack->jack, 0);
+ }
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static void q6usb_component_disable_jack(struct q6usb_port_data *data)
+{
+ /* Offload jack has already been disabled */
+ if (!data->hs_jack)
+ return;
+
+ snd_jack_report(data->hs_jack->jack, 0);
+ data->hs_jack = NULL;
+}
+
+static void q6usb_component_enable_jack(struct q6usb_port_data *data,
+ struct snd_soc_jack *jack)
+{
+ snd_jack_report(jack->jack, !list_empty(&data->devices) ? SND_JACK_USB : 0);
+ data->hs_jack = jack;
+}
+
+static int q6usb_component_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *priv)
+{
+ struct q6usb_port_data *data = dev_get_drvdata(component->dev);
+
+ mutex_lock(&data->mutex);
+ if (jack)
+ q6usb_component_enable_jack(data, jack);
+ else
+ q6usb_component_disable_jack(data);
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static void q6usb_dai_aux_release(struct device *dev) {}
+
+static int q6usb_dai_add_aux_device(struct q6usb_port_data *data,
+ struct auxiliary_device *auxdev)
+{
+ int ret;
+
+ auxdev->dev.parent = data->priv.dev;
+ auxdev->dev.release = q6usb_dai_aux_release;
+ auxdev->name = "qc-usb-audio-offload";
+
+ ret = auxiliary_device_init(auxdev);
+ if (ret)
+ return ret;
+
+ ret = auxiliary_device_add(auxdev);
+ if (ret)
+ auxiliary_device_uninit(auxdev);
+
+ return ret;
+}
+
+static int q6usb_component_probe(struct snd_soc_component *component)
+{
+ struct q6usb_port_data *data = dev_get_drvdata(component->dev);
+ struct snd_soc_usb *usb;
+ int ret;
+
+ /* Add the QC USB SND aux device */
+ ret = q6usb_dai_add_aux_device(data, &data->uauxdev);
+ if (ret < 0)
+ return ret;
+
+ usb = snd_soc_usb_allocate_port(component, &data->priv);
+ if (IS_ERR(usb))
+ return -ENOMEM;
+
+ usb->connection_status_cb = q6usb_alsa_connection_cb;
+ usb->update_offload_route_info = q6usb_update_offload_route;
+
+ snd_soc_usb_add_port(usb);
+ data->usb = usb;
+
+ return 0;
+}
+
+static void q6usb_component_remove(struct snd_soc_component *component)
+{
+ struct q6usb_port_data *data = dev_get_drvdata(component->dev);
+
+ snd_soc_usb_remove_port(data->usb);
+ auxiliary_device_delete(&data->uauxdev);
+ auxiliary_device_uninit(&data->uauxdev);
+ snd_soc_usb_free_port(data->usb);
+}
+
+static const struct snd_soc_component_driver q6usb_dai_component = {
+ .probe = q6usb_component_probe,
+ .set_jack = q6usb_component_set_jack,
+ .remove = q6usb_component_remove,
+ .name = "q6usb-dai-component",
+ .dapm_widgets = q6usb_dai_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(q6usb_dai_widgets),
+ .dapm_routes = q6usb_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(q6usb_dapm_routes),
+ .of_xlate_dai_name = q6usb_audio_ports_of_xlate_dai_name,
+};
+
+static int q6usb_dai_dev_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct q6usb_port_data *data;
+ struct device *dev = &pdev->dev;
+ struct of_phandle_args args;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = of_property_read_u16(node, "qcom,usb-audio-intr-idx",
+ &data->priv.intr_num);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read intr idx.\n");
+ return ret;
+ }
+
+ ret = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
+ if (!ret)
+ data->priv.sid = args.args[0] & Q6_USB_SID_MASK;
+
+ ret = devm_mutex_init(dev, &data->mutex);
+ if (ret < 0)
+ return ret;
+
+ data->priv.domain = iommu_get_domain_for_dev(&pdev->dev);
+
+ data->priv.dev = dev;
+ INIT_LIST_HEAD(&data->devices);
+ dev_set_drvdata(dev, data);
+
+ return devm_snd_soc_register_component(dev, &q6usb_dai_component,
+ q6usb_be_dais, ARRAY_SIZE(q6usb_be_dais));
+}
+
+static const struct of_device_id q6usb_dai_device_id[] = {
+ { .compatible = "qcom,q6usb" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, q6usb_dai_device_id);
+
+static struct platform_driver q6usb_dai_platform_driver = {
+ .driver = {
+ .name = "q6usb-dai",
+ .of_match_table = q6usb_dai_device_id,
+ },
+ .probe = q6usb_dai_dev_probe,
+ /*
+ * Remove not required as resources are cleaned up as part of
+ * component removal. Others are device managed resources.
+ */
+};
+module_platform_driver(q6usb_dai_platform_driver);
+
+MODULE_DESCRIPTION("Q6 USB backend dai driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index cccc59b570b9..5ce6edf3305e 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020, Linaro Limited
+#include <linux/cleanup.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
@@ -304,6 +305,34 @@ static struct snd_soc_tplg_vendor_array *audioreach_get_module_array(
return NULL;
}
+static struct audioreach_module_priv_data *audioreach_get_module_priv_data(
+ struct snd_soc_tplg_private *private)
+{
+ int sz;
+
+ for (sz = 0; sz < le32_to_cpu(private->size); ) {
+ struct snd_soc_tplg_vendor_array *mod_array;
+
+ mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
+ if (le32_to_cpu(mod_array->type) == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) {
+ struct audioreach_module_priv_data *pdata;
+
+ pdata = kzalloc(struct_size(pdata, data, le32_to_cpu(mod_array->size)),
+ GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(pdata, ((u8 *)private->data + sz), struct_size(pdata, data,
+ le32_to_cpu(mod_array->size)));
+ return pdata;
+ }
+
+ sz = sz + le32_to_cpu(mod_array->size);
+ }
+
+ return NULL;
+}
+
static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm,
struct snd_soc_tplg_private *private)
{
@@ -411,7 +440,7 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
struct snd_soc_tplg_private *private,
struct snd_soc_dapm_widget *w)
{
- uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
+ uint32_t max_ip_port = 0, max_op_port = 0;
uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
@@ -454,12 +483,6 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
case AR_TKN_U32_MODULE_MAX_OP_PORTS:
max_op_port = le32_to_cpu(mod_elem->value);
break;
- case AR_TKN_U32_MODULE_IN_PORTS:
- in_port = le32_to_cpu(mod_elem->value);
- break;
- case AR_TKN_U32_MODULE_OUT_PORTS:
- out_port = le32_to_cpu(mod_elem->value);
- break;
case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
src_mod_inst_id = le32_to_cpu(mod_elem->value);
break;
@@ -545,11 +568,10 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
if (mod) {
int pn, id = 0;
+
mod->module_id = module_id;
mod->max_ip_port = max_ip_port;
mod->max_op_port = max_op_port;
- mod->in_port = in_port;
- mod->out_port = out_port;
mod->src_mod_inst_id = src_mod_inst_id;
for (pn = 0; pn < mod->max_op_port; pn++) {
if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
@@ -585,8 +607,10 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon
return PTR_ERR(cont);
mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
- if (IS_ERR(mod))
- return PTR_ERR(mod);
+ if (IS_ERR_OR_NULL(mod))
+ return mod ? PTR_ERR(mod) : -ENODEV;
+
+ mod->data = audioreach_get_module_priv_data(&tplg_w->priv);
dobj = &w->dobj;
dobj->private = mod;
@@ -729,6 +753,29 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
return 0;
}
+static int audioreach_widget_dp_module_load(struct audioreach_module *mod,
+ struct snd_soc_tplg_vendor_array *mod_array)
+{
+ struct snd_soc_tplg_vendor_value_elem *mod_elem;
+ int tkn_count = 0;
+
+ mod_elem = mod_array->value;
+
+ while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
+ switch (le32_to_cpu(mod_elem->token)) {
+ case AR_TKN_U32_MODULE_FMT_DATA:
+ mod->data_format = le32_to_cpu(mod_elem->value);
+ break;
+ default:
+ break;
+ }
+ tkn_count++;
+ mod_elem++;
+ }
+
+ return 0;
+}
+
static int audioreach_widget_load_buffer(struct snd_soc_component *component,
int index, struct snd_soc_dapm_widget *w,
struct snd_soc_tplg_dapm_widget *tplg_w)
@@ -759,6 +806,9 @@ static int audioreach_widget_load_buffer(struct snd_soc_component *component,
case MODULE_ID_I2S_SOURCE:
audioreach_widget_i2s_module_load(mod, mod_array);
break;
+ case MODULE_ID_DISPLAY_PORT_SINK:
+ audioreach_widget_dp_module_load(mod, mod_array);
+ break;
default:
return -EINVAL;
}
@@ -919,6 +969,7 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
cont->num_modules--;
list_del(&mod->node);
+ kfree(mod->data);
kfree(mod);
/* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */
if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */
@@ -1092,8 +1143,8 @@ static int audioreach_get_audio_mixer(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_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
struct snd_ar_control *dapm_scontrol = dw->dobj.private;
struct snd_ar_control *scontrol = mc->dobj.private;
@@ -1113,8 +1164,8 @@ static int audioreach_put_audio_mixer(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_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
struct snd_ar_control *dapm_scontrol = dw->dobj.private;
struct snd_ar_control *scontrol = mc->dobj.private;
@@ -1133,7 +1184,7 @@ static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct audioreach_module *mod = dw->dobj.private;
ucontrol->value.integer.value[0] = mod->gain;
@@ -1144,7 +1195,7 @@ static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_to_widget(kcontrol);
struct audioreach_module *mod = dw->dobj.private;
mod->gain = ucontrol->value.integer.value[0];
@@ -1239,7 +1290,7 @@ static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
};
-static struct snd_soc_tplg_ops audioreach_tplg_ops = {
+static const struct snd_soc_tplg_ops audioreach_tplg_ops = {
.io_ops = audioreach_io_ops,
.io_ops_count = ARRAY_SIZE(audioreach_io_ops),
@@ -1261,29 +1312,28 @@ int audioreach_tplg_init(struct snd_soc_component *component)
struct snd_soc_card *card = component->card;
struct device *dev = component->dev;
const struct firmware *fw;
- char *tplg_fw_name;
int ret;
/* Inline with Qualcomm UCM configs and linux-firmware path */
- tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name);
+ char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin",
+ card->driver_name,
+ card->name);
if (!tplg_fw_name)
return -ENOMEM;
ret = request_firmware(&fw, tplg_fw_name, dev);
if (ret < 0) {
- dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret);
- goto err;
+ dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
+ return ret;
}
ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
if (ret < 0) {
- dev_err(dev, "tplg component load failed%d\n", ret);
- ret = -EINVAL;
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "tplg component load failed: %d\n", ret);
}
release_firmware(fw);
-err:
- kfree(tplg_fw_name);
return ret;
}
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c
index f5f7c64b23a2..bc5a18883479 100644
--- a/sound/soc/qcom/sc7180.c
+++ b/sound/soc/qcom/sc7180.c
@@ -5,10 +5,10 @@
// sc7180.c -- ALSA SoC Machine driver for SC7180
#include <dt-bindings/sound/sc7180-lpass.h>
-#include <linux/gpio.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -19,9 +19,10 @@
#include "../codecs/rt5682.h"
#include "../codecs/rt5682s.h"
#include "common.h"
-#include "lpass.h"
+#include "qdsp6/q6afe.h"
#define DEFAULT_MCLK_RATE 19200000
+#define MI2S_BCLK_RATE 1536000
#define RT5682_PLL1_FREQ (48000 * 512)
#define DRIVER_NAME "SC7180"
@@ -42,22 +43,34 @@ static void sc7180_jack_free(struct snd_jack *jack)
snd_soc_component_set_jack(component, NULL, NULL);
}
+static struct snd_soc_jack_pin sc7180_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_jack *jack;
int rval;
- rval = snd_soc_card_jack_new(
- card, "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_HEADPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pdata->hs_jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pdata->hs_jack,
+ sc7180_jack_pins,
+ ARRAY_SIZE(sc7180_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -81,7 +94,7 @@ static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_jack *jack;
int rval;
@@ -105,7 +118,7 @@ static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd)
static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -122,13 +135,29 @@ static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static int sc7180_snd_startup(struct snd_pcm_substream *substream)
+static int sc7180_qdsp_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_card *card = rtd->card;
- struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ return sc7180_headset_init(rtd);
+ case PRIMARY_MI2S_TX:
+ case TERTIARY_MI2S_RX:
+ return 0;
+ case DISPLAY_PORT_RX:
+ return sc7180_hdmi_init(rtd);
+ default:
+ dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+ cpu_dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sc7180_startup_realtek_codec(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int pll_id, pll_source, pll_in, pll_out, clk_id, ret;
if (!strcmp(codec_dai->name, "rt5682-aif1")) {
@@ -143,8 +172,40 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
clk_id = RT5682S_SCLK_S_PLL2;
pll_out = RT5682_PLL1_FREQ;
pll_in = DEFAULT_MCLK_RATE;
+ } else {
+ return 0;
+ }
+ snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S);
+
+ /* Configure PLL1 for codec */
+ ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source,
+ pll_in, pll_out);
+ if (ret) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
}
+ /* Configure sysclk for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out,
+ SND_SOC_CLOCK_IN);
+ if (ret)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",
+ ret);
+
+ return ret;
+}
+
+static int sc7180_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ int ret;
+
switch (cpu_dai->id) {
case MI2S_PRIMARY:
if (++data->pri_mi2s_clk_count == 1) {
@@ -154,30 +215,66 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
SNDRV_PCM_STREAM_PLAYBACK);
}
- snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_BC_FC |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_I2S);
-
- /* Configure PLL1 for codec */
- ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source,
- pll_in, pll_out);
- if (ret) {
- dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ ret = sc7180_startup_realtek_codec(rtd);
+ if (ret)
return ret;
+
+ break;
+ case MI2S_SECONDARY:
+ break;
+ case LPASS_DP_RX:
+ break;
+ default:
+ dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+ cpu_dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sc7180_qdsp_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+ 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);
+ int ret;
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ if (++data->pri_mi2s_clk_count == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_MCLK_1,
+ DEFAULT_MCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ MI2S_BCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
}
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out,
- SND_SOC_CLOCK_IN);
+ snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
+
+ ret = sc7180_startup_realtek_codec(rtd);
if (ret)
- dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",
- ret);
+ return ret;
break;
- case MI2S_SECONDARY:
+ case TERTIARY_MI2S_RX:
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ MI2S_BCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
+
+ snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S);
+ snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
break;
- case LPASS_DP_RX:
+ case DISPLAY_PORT_RX:
break;
default:
dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
@@ -190,8 +287,9 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
static int dmic_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
+ struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
ucontrol->value.integer.value[0] = data->dmic_switch;
return 0;
@@ -200,8 +298,9 @@ static int dmic_get(struct snd_kcontrol *kcontrol,
static int dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
+ struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
data->dmic_switch = ucontrol->value.integer.value[0];
gpiod_set_value(data->dmic_sel, data->dmic_switch);
@@ -210,10 +309,10 @@ static int dmic_set(struct snd_kcontrol *kcontrol,
static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -235,9 +334,45 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
}
}
+static void sc7180_qdsp_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ if (--data->pri_mi2s_clk_count == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_MCLK_1,
+ 0,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ 0,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ break;
+ case TERTIARY_MI2S_RX:
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
+ 0,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ break;
+ case DISPLAY_PORT_RX:
+ break;
+ default:
+ dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
+ cpu_dai->id);
+ break;
+ }
+}
+
static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -256,15 +391,15 @@ static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd)
static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_pcm_runtime *runtime = substream->runtime;
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;
@@ -283,11 +418,30 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
return 0;
}
+static int sc7180_qdsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
static const struct snd_soc_ops sc7180_ops = {
.startup = sc7180_snd_startup,
.shutdown = sc7180_snd_shutdown,
};
+static const struct snd_soc_ops sc7180_qdsp_ops = {
+ .startup = sc7180_qdsp_snd_startup,
+ .shutdown = sc7180_qdsp_snd_shutdown,
+};
+
static const struct snd_soc_ops sc7180_adau7002_ops = {
.startup = sc7180_adau7002_snd_startup,
};
@@ -297,6 +451,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
+static const struct snd_kcontrol_new sc7180_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = {
SND_SOC_DAPM_MIC("DMIC", NULL),
};
@@ -320,6 +479,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = {
SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control),
};
+static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = {
{"Dmic Mux", "Front Mic", "DMIC"},
{"Dmic Mux", "Rear Mic", "DMIC"},
@@ -333,7 +497,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
struct snd_soc_dai_link *link;
int ret;
int i;
- bool no_headphone = false;
+ bool qdsp = false, no_headphone = false;
/* Allocate the private data */
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
@@ -348,10 +512,14 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
card->dev = dev;
card->dapm_widgets = sc7180_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets);
+ 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,
+ card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls),
card->dapm_routes = sc7180_snd_dual_mic_audio_route,
card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route),
data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
@@ -365,6 +533,8 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
no_headphone = true;
card->dapm_widgets = sc7180_adau7002_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets);
+ } else if (of_device_is_compatible(dev->of_node, "qcom,sc7180-qdsp6-sndcard")) {
+ qdsp = true;
}
ret = qcom_snd_parse_of(card);
@@ -375,6 +545,12 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
if (no_headphone) {
link->ops = &sc7180_adau7002_ops;
link->init = sc7180_adau7002_init;
+ } else if (qdsp) {
+ if (link->no_pcm == 1) {
+ link->ops = &sc7180_qdsp_ops;
+ link->be_hw_params_fixup = sc7180_qdsp_be_hw_params_fixup;
+ link->init = sc7180_qdsp_init;
+ }
} else {
link->ops = &sc7180_ops;
link->init = sc7180_init;
@@ -387,6 +563,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
static const struct of_device_id sc7180_snd_device_id[] = {
{.compatible = "google,sc7180-trogdor"},
{.compatible = "google,sc7180-coachz"},
+ {.compatible = "qcom,sc7180-qdsp6-sndcard"},
{},
};
MODULE_DEVICE_TABLE(of, sc7180_snd_device_id);
@@ -402,4 +579,4 @@ static struct platform_driver sc7180_snd_driver = {
module_platform_driver(sc7180_snd_driver);
MODULE_DESCRIPTION("sc7180 ASoC Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c
index da7469a6a267..abdd58c1d0a4 100644
--- a/sound/soc/qcom/sc7280.c
+++ b/sound/soc/qcom/sc7280.c
@@ -4,9 +4,11 @@
//
// ALSA SoC Machine driver for sc7280
+#include <dt-bindings/sound/qcom,lpass.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/input.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -14,12 +16,14 @@
#include <sound/soc.h>
#include <sound/rt5682s.h>
#include <linux/soundwire/sdw.h>
+#include <sound/pcm_params.h>
#include "../codecs/rt5682.h"
#include "../codecs/rt5682s.h"
#include "common.h"
#include "lpass.h"
#include "qdsp6/q6afe.h"
+#include "sdw.h"
#define DEFAULT_MCLK_RATE 19200000
#define RT5682_PLL_FREQ (48000 * 512)
@@ -27,7 +31,6 @@
struct sc7280_snd_data {
struct snd_soc_card card;
- struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS];
u32 pri_mi2s_clk_count;
struct snd_soc_jack hs_jack;
struct snd_soc_jack hdmi_jack;
@@ -42,24 +45,37 @@ static void sc7280_jack_free(struct snd_jack *jack)
snd_soc_component_set_jack(component, NULL, NULL);
}
+static struct snd_soc_jack_pin sc7280_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_jack *jack;
int rval, i;
if (!pdata->jack_setup) {
- rval = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_MECHANICAL |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &pdata->hs_jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_MECHANICAL |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4 | SND_JACK_BTN_5,
+ &pdata->hs_jack,
+ sc7280_jack_pins,
+ ARRAY_SIZE(sc7280_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -101,7 +117,7 @@ static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_jack *jack;
int rval;
@@ -123,8 +139,8 @@ static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd)
static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
struct snd_soc_card *card = rtd->card;
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
int ret;
@@ -162,7 +178,7 @@ static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd)
static int sc7280_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -189,29 +205,11 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai;
- const struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
- struct sdw_stream_runtime *sruntime;
- int i;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 48000, 48000);
-
- switch (cpu_dai->id) {
- case LPASS_CDC_DMA_TX3:
- case LPASS_CDC_DMA_RX0:
- case RX_CODEC_DMA_RX_0:
- case SECONDARY_MI2S_RX:
- case TX_CODEC_DMA_TX_3:
- case VA_CODEC_DMA_TX_0:
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
- if (sruntime != ERR_PTR(-ENOTSUPP))
- pdata->sruntime[cpu_dai->id] = sruntime;
- }
- break;
+ if (!rtd->dai_link->no_pcm) {
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 48000, 48000);
}
return 0;
@@ -219,39 +217,17 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream,
static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- const struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
- int ret;
-
- if (!sruntime)
- return 0;
-
- if (data->stream_prepared[cpu_dai->id]) {
- sdw_disable_stream(sruntime);
- sdw_deprepare_stream(sruntime);
- data->stream_prepared[cpu_dai->id] = false;
- }
-
- ret = sdw_prepare_stream(sruntime);
- if (ret)
- return ret;
- ret = sdw_enable_stream(sruntime);
- if (ret) {
- sdw_deprepare_stream(sruntime);
- return ret;
- }
- data->stream_prepared[cpu_dai->id] = true;
-
- return ret;
+ return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
}
static int sc7280_snd_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- const struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case LPASS_CDC_DMA_RX0:
@@ -269,35 +245,19 @@ static int sc7280_snd_prepare(struct snd_pcm_substream *substream)
static int sc7280_snd_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- const struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+ const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
- switch (cpu_dai->id) {
- case LPASS_CDC_DMA_RX0:
- case LPASS_CDC_DMA_TX3:
- case RX_CODEC_DMA_RX_0:
- case TX_CODEC_DMA_TX_3:
- case VA_CODEC_DMA_TX_0:
- if (sruntime && data->stream_prepared[cpu_dai->id]) {
- sdw_disable_stream(sruntime);
- sdw_deprepare_stream(sruntime);
- data->stream_prepared[cpu_dai->id] = false;
- }
- break;
- default:
- break;
- }
- return 0;
+ return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
}
static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -315,20 +275,24 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
default:
break;
}
+
+ qcom_snd_sdw_shutdown(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;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
int ret = 0;
switch (cpu_dai->id) {
case MI2S_PRIMARY:
ret = sc7280_rt5682_init(rtd);
+ if (ret)
+ return ret;
break;
case SECONDARY_MI2S_RX:
codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
@@ -342,7 +306,8 @@ static int sc7280_snd_startup(struct snd_pcm_substream *substream)
default:
break;
}
- return ret;
+
+ return qcom_snd_sdw_startup(substream);
}
static const struct snd_soc_ops sc7280_ops = {
@@ -358,6 +323,25 @@ static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
+static const struct snd_kcontrol_new sc7280_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+
+ return 0;
+}
+
static int sc7280_snd_platform_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
@@ -379,6 +363,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev)
card->dapm_widgets = sc7280_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets);
+ card->controls = sc7280_snd_controls;
+ card->num_controls = ARRAY_SIZE(sc7280_snd_controls);
ret = qcom_snd_parse_of(card);
if (ret)
@@ -387,6 +373,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev)
for_each_card_prelinks(card, i, link) {
link->init = sc7280_init;
link->ops = &sc7280_ops;
+ if (link->no_pcm == 1)
+ link->be_hw_params_fixup = sc7280_snd_be_hw_params_fixup;
}
return devm_snd_soc_register_card(dev, card);
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
index 14d9fea33d16..7925aa3f63ba 100644
--- a/sound/soc/qcom/sc8280xp.c
+++ b/sound/soc/qcom/sc8280xp.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2022, Linaro Limited
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <linux/soundwire/sdw.h>
#include <sound/jack.h>
#include <linux/input-event-codes.h>
@@ -14,19 +15,54 @@
#include "common.h"
#include "sdw.h"
-#define DRIVER_NAME "sc8280xp"
-
struct sc8280xp_snd_data {
bool stream_prepared[AFE_PORT_MAX];
struct snd_soc_card *card;
- struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
struct snd_soc_jack jack;
+ struct snd_soc_jack dp_jack[8];
bool jack_setup;
};
static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_jack *dp_jack = NULL;
+ int dp_pcm_id = 0;
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX:
+ case QUINARY_MI2S_RX...QUINARY_MI2S_TX:
+ snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
+ break;
+ case WSA_CODEC_DMA_RX_0:
+ case WSA_CODEC_DMA_RX_1:
+ /*
+ * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume
+ * to reduce the risk of speaker damage until we have active
+ * speaker protection in place.
+ */
+ snd_soc_limit_volume(card, "WSA_RX0 Digital Volume", 81);
+ snd_soc_limit_volume(card, "WSA_RX1 Digital Volume", 81);
+ snd_soc_limit_volume(card, "SpkrLeft PA Volume", 17);
+ snd_soc_limit_volume(card, "SpkrRight PA Volume", 17);
+ break;
+ case DISPLAY_PORT_RX_0:
+ /* DISPLAY_PORT dai ids are not contiguous */
+ dp_pcm_id = 0;
+ dp_jack = &data->dp_jack[dp_pcm_id];
+ break;
+ case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7:
+ dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1;
+ dp_jack = &data->dp_jack[dp_pcm_id];
+ break;
+ default:
+ break;
+ }
+
+ if (dp_jack)
+ return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
}
@@ -34,13 +70,15 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
rate->min = rate->max = 48000;
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
channels->min = 2;
channels->max = 2;
switch (cpu_dai->id) {
@@ -58,40 +96,27 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
-
- return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
-}
-
static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
- return qcom_snd_sdw_prepare(substream, sruntime,
- &data->stream_prepared[cpu_dai->id]);
+ return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
}
static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
- return qcom_snd_sdw_hw_free(substream, sruntime,
- &data->stream_prepared[cpu_dai->id]);
+ return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
}
static const struct snd_soc_ops sc8280xp_be_ops = {
- .hw_params = sc8280xp_snd_hw_params,
+ .startup = qcom_snd_sdw_startup,
+ .shutdown = qcom_snd_sdw_shutdown,
.hw_free = sc8280xp_snd_hw_free,
.prepare = sc8280xp_snd_prepare,
};
@@ -133,13 +158,24 @@ static int sc8280xp_platform_probe(struct platform_device *pdev)
if (ret)
return ret;
- card->driver_name = DRIVER_NAME;
+ card->driver_name = of_device_get_match_data(dev);
sc8280xp_add_be_ops(card);
return devm_snd_soc_register_card(dev, card);
}
static const struct of_device_id snd_sc8280xp_dt_match[] = {
- {.compatible = "qcom,sc8280xp-sndcard",},
+ {.compatible = "qcom,kaanapali-sndcard", "kaanapali"},
+ {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"},
+ {.compatible = "qcom,qcs615-sndcard", "qcs615"},
+ {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"},
+ {.compatible = "qcom,qcs8275-sndcard", "qcs8300"},
+ {.compatible = "qcom,qcs9075-sndcard", "sa8775p"},
+ {.compatible = "qcom,qcs9100-sndcard", "sa8775p"},
+ {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"},
+ {.compatible = "qcom,sm8450-sndcard", "sm8450"},
+ {.compatible = "qcom,sm8550-sndcard", "sm8550"},
+ {.compatible = "qcom,sm8650-sndcard", "sm8650"},
+ {.compatible = "qcom,sm8750-sndcard", "sm8750"},
{}
};
@@ -155,4 +191,4 @@ static struct platform_driver snd_sc8280xp_driver = {
module_platform_driver(snd_sc8280xp_driver);
MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
MODULE_DESCRIPTION("SC8280XP ASoC Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 02612af714a8..e18a8e44f2db 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -3,9 +3,9 @@
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -15,6 +15,7 @@
#include <uapi/linux/input-event-codes.h>
#include "common.h"
#include "qdsp6/q6afe.h"
+#include "sdw.h"
#include "../codecs/rt5663.h"
#define DRIVER_NAME "sdm845"
@@ -39,7 +40,17 @@ struct sdm845_snd_data {
uint32_t pri_mi2s_clk_count;
uint32_t sec_mi2s_clk_count;
uint32_t quat_tdm_clk_count;
- struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
+};
+
+static struct snd_soc_jack_pin sdm845_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
};
static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
@@ -47,21 +58,14 @@ static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai;
- struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
- struct sdw_stream_runtime *sruntime;
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
int ret = 0, i;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- sruntime = snd_soc_dai_get_stream(codec_dai,
- substream->stream);
- if (sruntime != ERR_PTR(-ENOTSUPP))
- pdata->sruntime[cpu_dai->id] = sruntime;
-
ret = snd_soc_dai_get_channel_map(codec_dai,
&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
@@ -79,6 +83,10 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
else
ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
tx_ch, 0, NULL);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret);
+ return ret;
+ }
}
return 0;
@@ -87,8 +95,8 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai;
int ret = 0, j;
int channels, slot_width;
@@ -172,9 +180,9 @@ end:
static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret = 0;
switch (cpu_dai->id) {
@@ -203,6 +211,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);
@@ -222,8 +231,8 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *component;
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link *link = rtd->dai_link;
struct snd_jack *jack;
@@ -242,12 +251,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
if (!pdata->jack_setup) {
- rval = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_HEADPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pdata->jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pdata->jack,
+ sdm845_jack_pins,
+ ARRAY_SIZE(sdm845_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headphone Jack\n");
@@ -318,11 +329,11 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
{
unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
int j;
int ret;
@@ -342,6 +353,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) {
@@ -357,8 +369,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:
@@ -403,15 +413,15 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
break;
}
- return 0;
+ return qcom_snd_sdw_startup(substream);
}
static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX:
@@ -426,6 +436,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,
@@ -450,61 +461,26 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
break;
}
+
+ qcom_snd_sdw_shutdown(substream);
}
static int sdm845_snd_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
- int ret;
-
- if (!sruntime)
- return 0;
-
- if (data->stream_prepared[cpu_dai->id]) {
- sdw_disable_stream(sruntime);
- sdw_deprepare_stream(sruntime);
- data->stream_prepared[cpu_dai->id] = false;
- }
-
- ret = sdw_prepare_stream(sruntime);
- if (ret)
- return ret;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
- /**
- * NOTE: there is a strict hw requirement about the ordering of port
- * enables and actual WSA881x PA enable. PA enable should only happen
- * after soundwire ports are enabled if not DC on the line is
- * accumulated resulting in Click/Pop Noise
- * PA enable/mute are handled as part of codec DAPM and digital mute.
- */
-
- ret = sdw_enable_stream(sruntime);
- if (ret) {
- sdw_deprepare_stream(sruntime);
- return ret;
- }
- data->stream_prepared[cpu_dai->id] = true;
-
- return ret;
+ return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
}
static int sdm845_snd_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
-
- if (sruntime && data->stream_prepared[cpu_dai->id]) {
- sdw_disable_stream(sruntime);
- sdw_deprepare_stream(sruntime);
- data->stream_prepared[cpu_dai->id] = false;
- }
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
- return 0;
+ return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
}
static const struct snd_soc_ops sdm845_be_ops = {
@@ -539,6 +515,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
SND_SOC_DAPM_MIC("Int Mic", NULL),
};
+static const struct snd_kcontrol_new sdm845_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static void sdm845_add_ops(struct snd_soc_card *card)
{
struct snd_soc_dai_link *link;
@@ -572,6 +553,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
card->driver_name = DRIVER_NAME;
card->dapm_widgets = sdm845_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
+ card->controls = sdm845_snd_controls;
+ card->num_controls = ARRAY_SIZE(sdm845_snd_controls);
card->dev = dev;
card->owner = THIS_MODULE;
dev_set_drvdata(dev, card);
@@ -605,4 +588,4 @@ static struct platform_driver sdm845_snd_driver = {
module_platform_driver(sdm845_snd_driver);
MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c
index 1a41419c7eb8..6576b47a4c8c 100644
--- a/sound/soc/qcom/sdw.c
+++ b/sound/soc/qcom/sdw.c
@@ -1,37 +1,144 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018, Linaro Limited.
+// Copyright (c) 2018-2023, Linaro Limited.
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+#include <dt-bindings/sound/qcom,lpass.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/module.h>
#include <sound/soc.h>
-#include "qdsp6/q6afe.h"
#include "sdw.h"
-int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
- struct sdw_stream_runtime *sruntime,
- bool *stream_prepared)
+static bool qcom_snd_is_sdw_dai(int id)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- int ret;
-
- if (!sruntime)
- return 0;
-
- switch (cpu_dai->id) {
+ switch (id) {
case WSA_CODEC_DMA_RX_0:
+ case WSA_CODEC_DMA_TX_0:
case WSA_CODEC_DMA_RX_1:
+ case WSA_CODEC_DMA_TX_1:
+ case WSA_CODEC_DMA_TX_2:
case RX_CODEC_DMA_RX_0:
- case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
+ case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_1:
+ case RX_CODEC_DMA_RX_2:
case TX_CODEC_DMA_TX_2:
+ case RX_CODEC_DMA_RX_3:
case TX_CODEC_DMA_TX_3:
+ case RX_CODEC_DMA_RX_4:
+ case TX_CODEC_DMA_TX_4:
+ case RX_CODEC_DMA_RX_5:
+ case TX_CODEC_DMA_TX_5:
+ case RX_CODEC_DMA_RX_6:
+ case RX_CODEC_DMA_RX_7:
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ return true;
+ default:
break;
+ }
+
+ /* DSP Bypass usecase, cpu dai index overlaps with DSP dai ids,
+ * DO NOT MERGE into top switch case */
+ switch (id) {
+ case LPASS_CDC_DMA_TX3:
+ case LPASS_CDC_DMA_RX0:
+ return true;
default:
+ break;
+ }
+
+ return false;
+}
+
+/**
+ * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card
+ * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup()
+ *
+ * Helper for the SoC audio card (snd_soc_ops->startup()) to allocate and set
+ * Soundwire stream runtime to each codec DAI.
+ *
+ * The shutdown() callback should call sdw_release_stream() on the same
+ * sdw_stream_runtime.
+ *
+ * Return: 0 or errno
+ */
+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;
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret, i, j;
+
+ if (!qcom_snd_is_sdw_dai(cpu_dai->id))
return 0;
+
+ sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM);
+ if (!sruntime)
+ return -ENOMEM;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ 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);
+ 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;
+ }
+ }
}
+ return 0;
+
+err_set_stream:
+ sdw_release_stream(sruntime);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup);
+
+int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+ bool *stream_prepared)
+{
+ 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 sdw_stream_runtime *sruntime;
+ int ret;
+
+
+ if (!qcom_snd_is_sdw_dai(cpu_dai->id))
+ return 0;
+
+ sruntime = qcom_snd_sdw_get_stream(substream);
+ if (!sruntime)
+ return 0;
+
if (*stream_prepared)
return 0;
@@ -58,63 +165,52 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct sdw_stream_runtime **psruntime)
+struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sdw_stream_runtime *sruntime;
int i;
- switch (cpu_dai->id) {
- case WSA_CODEC_DMA_RX_0:
- case RX_CODEC_DMA_RX_0:
- case RX_CODEC_DMA_RX_1:
- case TX_CODEC_DMA_TX_0:
- case TX_CODEC_DMA_TX_1:
- case TX_CODEC_DMA_TX_2:
- case TX_CODEC_DMA_TX_3:
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
- if (sruntime != ERR_PTR(-ENOTSUPP))
- *psruntime = sruntime;
- }
- break;
+ if (!qcom_snd_is_sdw_dai(cpu_dai->id))
+ return NULL;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
+ if (sruntime != ERR_PTR(-ENOTSUPP))
+ return sruntime;
}
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_get_stream);
- return 0;
+void qcom_snd_sdw_shutdown(struct snd_pcm_substream *substream)
+{
+ struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream);
+ sdw_release_stream(sruntime);
}
-EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_shutdown);
-int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
- struct sdw_stream_runtime *sruntime, bool *stream_prepared)
+int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, bool *stream_prepared)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct sdw_stream_runtime *sruntime;
- switch (cpu_dai->id) {
- case WSA_CODEC_DMA_RX_0:
- case WSA_CODEC_DMA_RX_1:
- case RX_CODEC_DMA_RX_0:
- case RX_CODEC_DMA_RX_1:
- case TX_CODEC_DMA_TX_0:
- case TX_CODEC_DMA_TX_1:
- case TX_CODEC_DMA_TX_2:
- case TX_CODEC_DMA_TX_3:
- if (sruntime && *stream_prepared) {
- sdw_disable_stream(sruntime);
- sdw_deprepare_stream(sruntime);
- *stream_prepared = false;
- }
- break;
- default:
- break;
+ if (!qcom_snd_is_sdw_dai(cpu_dai->id))
+ return 0;
+
+ sruntime = qcom_snd_sdw_get_stream(substream);
+ if (sruntime && *stream_prepared) {
+ sdw_disable_stream(sruntime);
+ sdw_deprepare_stream(sruntime);
+ *stream_prepared = false;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
-MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/sdw.h b/sound/soc/qcom/sdw.h
index d74cbb84da13..061a63f1ac52 100644
--- a/sound/soc/qcom/sdw.h
+++ b/sound/soc/qcom/sdw.h
@@ -6,13 +6,11 @@
#include <linux/soundwire/sdw.h>
+int qcom_snd_sdw_startup(struct snd_pcm_substream *substream);
+void qcom_snd_sdw_shutdown(struct snd_pcm_substream *substream);
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
- struct sdw_stream_runtime *runtime,
bool *stream_prepared);
-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct sdw_stream_runtime **psruntime);
+struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *stream);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
- struct sdw_stream_runtime *sruntime,
bool *stream_prepared);
#endif
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index 9626a9ef78c2..05a8b04e50e0 100644
--- a/sound/soc/qcom/sm8250.c
+++ b/sound/soc/qcom/sm8250.c
@@ -1,35 +1,58 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020, Linaro Limited
+#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <linux/soundwire/sdw.h>
#include <sound/jack.h>
#include <linux/input-event-codes.h>
#include "qdsp6/q6afe.h"
#include "common.h"
+#include "usb_offload_utils.h"
#include "sdw.h"
-#define DRIVER_NAME "sm8250"
#define MI2S_BCLK_RATE 1536000
struct sm8250_snd_data {
bool stream_prepared[AFE_PORT_MAX];
struct snd_soc_card *card;
- struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
struct snd_soc_jack jack;
+ struct snd_soc_jack usb_offload_jack;
+ bool usb_offload_jack_setup;
+ struct snd_soc_jack dp_jack;
bool jack_setup;
};
static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ switch (cpu_dai->id) {
+ case DISPLAY_PORT_RX:
+ return qcom_snd_dp_jack_setup(rtd, &data->dp_jack, 0);
+ case USB_RX:
+ return qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack,
+ &data->usb_offload_jack_setup);
+ default:
+ return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+ }
+}
+
+static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd)
+{
+ struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ if (cpu_dai->id == USB_RX)
+ qcom_snd_usb_offload_jack_remove(rtd,
+ &data->usb_offload_jack_setup);
- return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
}
static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -39,9 +62,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;
}
@@ -50,11 +75,27 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
{
unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
+ case SECONDARY_MI2S_RX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
case TERTIARY_MI2S_RX:
codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
snd_soc_dai_set_sysclk(cpu_dai,
@@ -66,44 +107,31 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
default:
break;
}
- return 0;
-}
-
-static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
- return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
+ return qcom_snd_sdw_startup(substream);
}
static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
- return qcom_snd_sdw_prepare(substream, sruntime,
- &data->stream_prepared[cpu_dai->id]);
+ return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
}
static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
- return qcom_snd_sdw_hw_free(substream, sruntime,
- &data->stream_prepared[cpu_dai->id]);
+ return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
}
static const struct snd_soc_ops sm8250_be_ops = {
.startup = sm8250_snd_startup,
- .hw_params = sm8250_snd_hw_params,
+ .shutdown = qcom_snd_sdw_shutdown,
.hw_free = sm8250_snd_hw_free,
.prepare = sm8250_snd_prepare,
};
@@ -116,6 +144,7 @@ static void sm8250_add_be_ops(struct snd_soc_card *card)
for_each_card_prelinks(card, i, link) {
if (link->no_pcm == 1) {
link->init = sm8250_snd_init;
+ link->exit = sm8250_snd_exit;
link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
link->ops = &sm8250_be_ops;
}
@@ -146,14 +175,18 @@ static int sm8250_platform_probe(struct platform_device *pdev)
if (ret)
return ret;
- card->driver_name = DRIVER_NAME;
+ card->driver_name = of_device_get_match_data(dev);
sm8250_add_be_ops(card);
return devm_snd_soc_register_card(dev, card);
}
static const struct of_device_id snd_sm8250_dt_match[] = {
- {.compatible = "qcom,sm8250-sndcard"},
- {.compatible = "qcom,qrb5165-rb5-sndcard"},
+ { .compatible = "fairphone,fp4-sndcard", .data = "sm7225" },
+ { .compatible = "fairphone,fp5-sndcard", .data = "qcm6490" },
+ { .compatible = "qcom,qrb2210-sndcard", .data = "qcm2290" },
+ { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" },
+ { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" },
+ { .compatible = "qcom,sm8250-sndcard", .data = "sm8250" },
{}
};
@@ -169,4 +202,4 @@ static struct platform_driver snd_sm8250_driver = {
module_platform_driver(snd_sm8250_driver);
MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c
index 80c9cf2f254a..c8d5ac43a176 100644
--- a/sound/soc/qcom/storm.c
+++ b/sound/soc/qcom/storm.c
@@ -19,7 +19,7 @@
static int storm_ops_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = soc_runtime->card;
snd_pcm_format_t format = params_format(params);
unsigned int rate = params_rate(params);
@@ -39,7 +39,7 @@ static int storm_ops_hw_params(struct snd_pcm_substream *substream,
*/
sysclk_freq = rate * bitwidth * 2 * STORM_SYSCLK_MULT;
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(soc_runtime, 0), 0, sysclk_freq, 0);
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(soc_runtime, 0), 0, sysclk_freq, 0);
if (ret) {
dev_err(card->dev, "error setting sysclk to %u: %d\n",
sysclk_freq, ret);
@@ -140,4 +140,4 @@ static struct platform_driver storm_platform_driver = {
module_platform_driver(storm_platform_driver);
MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/usb_offload_utils.c b/sound/soc/qcom/usb_offload_utils.c
new file mode 100644
index 000000000000..0a24b278fcdf
--- /dev/null
+++ b/sound/soc/qcom/usb_offload_utils.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/soc-usb.h>
+
+#include "usb_offload_utils.h"
+
+int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_jack *jack, bool *jack_setup)
+{
+ 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);
+ int ret = 0;
+
+ if (cpu_dai->id != USB_RX)
+ return -EINVAL;
+
+ if (!*jack_setup) {
+ ret = snd_soc_usb_setup_offload_jack(codec_dai->component, jack);
+ if (ret)
+ return ret;
+ }
+
+ *jack_setup = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_usb_offload_jack_setup);
+
+int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd,
+ bool *jack_setup)
+{
+ 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);
+ int ret = 0;
+
+ if (cpu_dai->id != USB_RX)
+ return -EINVAL;
+
+ if (*jack_setup) {
+ ret = snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+ if (ret)
+ return ret;
+ }
+
+ *jack_setup = false;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_usb_offload_jack_remove);
+MODULE_DESCRIPTION("ASoC Q6 USB offload controls");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/usb_offload_utils.h b/sound/soc/qcom/usb_offload_utils.h
new file mode 100644
index 000000000000..c3f411f565b0
--- /dev/null
+++ b/sound/soc/qcom/usb_offload_utils.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#ifndef __QCOM_SND_USB_OFFLOAD_UTILS_H__
+#define __QCOM_SND_USB_OFFLOAD_UTILS_H__
+
+#include <sound/soc.h>
+
+#if IS_ENABLED(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS)
+int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_jack *jack, bool *jack_setup);
+
+int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd,
+ bool *jack_setup);
+#else
+static inline int qcom_snd_usb_offload_jack_setup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_jack *jack,
+ bool *jack_setup)
+{
+ return -ENODEV;
+}
+
+static inline int qcom_snd_usb_offload_jack_remove(struct snd_soc_pcm_runtime *rtd,
+ bool *jack_setup)
+{
+ return -ENODEV;
+}
+#endif /* IS_ENABLED(CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS) */
+#endif /* __QCOM_SND_USB_OFFLOAD_UTILS_H__ */
diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c
new file mode 100644
index 000000000000..a3f4785c4bbe
--- /dev/null
+++ b/sound/soc/qcom/x1e80100.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2023, Linaro Limited
+
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "common.h"
+#include "qdsp6/q6afe.h"
+#include "qdsp6/q6dsp-common.h"
+#include "sdw.h"
+
+struct x1e80100_snd_data {
+ bool stream_prepared[AFE_PORT_MAX];
+ struct snd_soc_card *card;
+ struct snd_soc_jack jack;
+ struct snd_soc_jack dp_jack[8];
+ bool jack_setup;
+};
+
+static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_jack *dp_jack = NULL;
+ int dp_pcm_id = 0;
+
+ switch (cpu_dai->id) {
+ case DISPLAY_PORT_RX_0:
+ dp_pcm_id = 0;
+ dp_jack = &data->dp_jack[dp_pcm_id];
+ break;
+ case DISPLAY_PORT_RX_1 ... DISPLAY_PORT_RX_7:
+ dp_pcm_id = cpu_dai->id - DISPLAY_PORT_RX_1 + 1;
+ dp_jack = &data->dp_jack[dp_pcm_id];
+ break;
+ default:
+ break;
+ }
+
+ if (dp_jack)
+ return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
+
+ return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+}
+
+static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ 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);
+
+ rate->min = rate->max = 48000;
+ switch (cpu_dai->id) {
+ case TX_CODEC_DMA_TX_0:
+ case TX_CODEC_DMA_TX_1:
+ case TX_CODEC_DMA_TX_2:
+ case TX_CODEC_DMA_TX_3:
+ channels->min = 1;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int x1e80100_snd_hw_map_channels(unsigned int *ch_map, int num)
+{
+ switch (num) {
+ case 1:
+ ch_map[0] = PCM_CHANNEL_FC;
+ break;
+ case 2:
+ ch_map[0] = PCM_CHANNEL_FL;
+ ch_map[1] = PCM_CHANNEL_FR;
+ break;
+ case 3:
+ ch_map[0] = PCM_CHANNEL_FL;
+ ch_map[1] = PCM_CHANNEL_FR;
+ ch_map[2] = PCM_CHANNEL_FC;
+ break;
+ case 4:
+ ch_map[0] = PCM_CHANNEL_FL;
+ ch_map[1] = PCM_CHANNEL_LB;
+ ch_map[2] = PCM_CHANNEL_FR;
+ ch_map[3] = PCM_CHANNEL_RB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int x1e80100_snd_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ unsigned int channels = substream->runtime->channels;
+ unsigned int rx_slot[4];
+ int ret;
+
+ switch (cpu_dai->id) {
+ case WSA_CODEC_DMA_RX_0:
+ case WSA_CODEC_DMA_RX_1:
+ ret = x1e80100_snd_hw_map_channels(rx_slot, channels);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ channels, rx_slot);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
+}
+
+static int x1e80100_snd_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
+}
+
+static const struct snd_soc_ops x1e80100_be_ops = {
+ .startup = qcom_snd_sdw_startup,
+ .shutdown = qcom_snd_sdw_shutdown,
+ .hw_free = x1e80100_snd_hw_free,
+ .prepare = x1e80100_snd_prepare,
+};
+
+static void x1e80100_add_be_ops(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *link;
+ int i;
+
+ for_each_card_prelinks(card, i, link) {
+ if (link->no_pcm == 1) {
+ link->init = x1e80100_snd_init;
+ link->be_hw_params_fixup = x1e80100_be_hw_params_fixup;
+ link->ops = &x1e80100_be_ops;
+ }
+ }
+}
+
+static int x1e80100_platform_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct x1e80100_snd_data *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+ /* Allocate the private data */
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+ dev_set_drvdata(dev, card);
+ snd_soc_card_set_drvdata(card, data);
+
+ ret = qcom_snd_parse_of(card);
+ if (ret)
+ return ret;
+
+ card->driver_name = of_device_get_match_data(dev);
+ x1e80100_add_be_ops(card);
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id snd_x1e80100_dt_match[] = {
+ { .compatible = "qcom,x1e80100-sndcard", .data = "x1e80100" },
+ { .compatible = "qcom,glymur-sndcard", .data = "glymur" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, snd_x1e80100_dt_match);
+
+static struct platform_driver snd_x1e80100_driver = {
+ .probe = x1e80100_platform_probe,
+ .driver = {
+ .name = "snd-x1e80100",
+ .of_match_table = snd_x1e80100_dt_match,
+ },
+};
+module_platform_driver(snd_x1e80100_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm X1E80100 ASoC Machine Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/renesas/Kconfig
index 7bddfd5e38d6..11c2027c88a7 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/renesas/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-menu "SoC Audio support for Renesas SoCs"
+menu "Renesas"
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
config SND_SOC_PCM_SH7760
@@ -41,10 +41,18 @@ config SND_SOC_RCAR
depends on COMMON_CLK
depends on OF
select SND_SIMPLE_CARD_UTILS
+ select SND_DMAENGINE_PCM
select REGMAP_MMIO
help
This option enables R-Car SRU/SCU/SSIU/SSI sound support
+config SND_SOC_MSIOF
+ tristate "R-Car series MSIOF support"
+ depends on OF
+ select SND_DMAENGINE_PCM
+ help
+ This option enables R-Car MSIOF sound support
+
config SND_SOC_RZ
tristate "RZ/G2L series SSIF-2 support"
depends on ARCH_RZG2L || COMPILE_TEST
@@ -66,7 +74,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/sh/Makefile b/sound/soc/renesas/Makefile
index f6fd79948f6a..f0e19cbd1581 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/renesas/Makefile
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
## DMA engines
-snd-soc-dma-sh7760-objs := dma-sh7760.o
+snd-soc-dma-sh7760-y := dma-sh7760.o
obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o
## audio units found on some SH-4
-snd-soc-hac-objs := hac.o
-snd-soc-ssi-objs := ssi.o
-snd-soc-fsi-objs := fsi.o
-snd-soc-siu-objs := siu_pcm.o siu_dai.o
+snd-soc-hac-y := hac.o
+snd-soc-ssi-y := ssi.o
+snd-soc-fsi-y := fsi.o
+snd-soc-siu-y := siu_pcm.o siu_dai.o
obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o
obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o
@@ -17,12 +17,12 @@ obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o
obj-$(CONFIG_SND_SOC_RCAR) += rcar/
## boards
-snd-soc-sh7760-ac97-objs := sh7760-ac97.o
-snd-soc-migor-objs := migor.o
+snd-soc-sh7760-ac97-y := sh7760-ac97.o
+snd-soc-migor-y := migor.o
obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o
# RZ/G2L
-snd-soc-rz-ssi-objs := rz-ssi.o
+snd-soc-rz-ssi-y := rz-ssi.o
obj-$(CONFIG_SND_SOC_RZ) += snd-soc-rz-ssi.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/renesas/dma-sh7760.c
index 121e48f984c5..c53539482c20 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/renesas/dma-sh7760.c
@@ -118,8 +118,8 @@ static void camelot_rxdma(void *data)
static int camelot_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int ret, dmairq;
@@ -132,7 +132,7 @@ static int camelot_pcm_open(struct snd_soc_component *component,
ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
if (unlikely(ret)) {
pr_debug("audio unit %d irqs already taken!\n",
- asoc_rtd_to_cpu(rtd, 0)->id);
+ snd_soc_rtd_to_cpu(rtd, 0)->id);
return -EBUSY;
}
(void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
@@ -141,7 +141,7 @@ static int camelot_pcm_open(struct snd_soc_component *component,
ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
if (unlikely(ret)) {
pr_debug("audio unit %d irqs already taken!\n",
- asoc_rtd_to_cpu(rtd, 0)->id);
+ snd_soc_rtd_to_cpu(rtd, 0)->id);
return -EBUSY;
}
(void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
@@ -152,8 +152,8 @@ static int camelot_pcm_open(struct snd_soc_component *component,
static int camelot_pcm_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
int dmairq;
@@ -174,8 +174,8 @@ static int camelot_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
if (recv) {
@@ -192,12 +192,12 @@ static int camelot_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+
+ pr_debug("PCM data: addr %pad len %zu\n", &runtime->dma_addr,
+ runtime->dma_bytes);
- pr_debug("PCM data: addr 0x%08lx len %d\n",
- (u32)runtime->dma_addr, runtime->dma_bytes);
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
BRGREG(BRGATXTCR) = runtime->dma_bytes;
@@ -240,8 +240,8 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
static int camelot_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
switch (cmd) {
@@ -268,8 +268,8 @@ static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
unsigned long pos;
diff --git a/sound/soc/sh/fsi.c b/sound/soc/renesas/fsi.c
index 1051c306292f..1491c2f2cc96 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/renesas/fsi.c
@@ -13,7 +13,6 @@
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/scatterlist.h>
#include <linux/sh_dma.h>
#include <linux/slab.h>
@@ -221,7 +220,7 @@ struct fsi_stream {
/*
* these are initialized by fsi_handler_init()
*/
- struct fsi_stream_handler *handler;
+ const struct fsi_stream_handler *handler;
struct fsi_priv *priv;
/*
@@ -344,14 +343,9 @@ static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data)
#define fsi_core_read(p, r) _fsi_master_read(p, p->core->r)
static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
{
- u32 ret;
- unsigned long flags;
+ guard(spinlock_irqsave)(&master->lock);
- spin_lock_irqsave(&master->lock, flags);
- ret = __fsi_reg_read(master->base + reg);
- spin_unlock_irqrestore(&master->lock, flags);
-
- return ret;
+ return __fsi_reg_read(master->base + reg);
}
#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d)
@@ -359,11 +353,9 @@ static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
static void _fsi_master_mask_set(struct fsi_master *master,
u32 reg, u32 mask, u32 data)
{
- unsigned long flags;
+ guard(spinlock_irqsave)(&master->lock);
- spin_lock_irqsave(&master->lock, flags);
__fsi_reg_mask_set(master->base + reg, mask, data);
- spin_unlock_irqrestore(&master->lock, flags);
}
/*
@@ -406,9 +398,9 @@ static int fsi_is_play(struct snd_pcm_substream *substream)
static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- return asoc_rtd_to_cpu(rtd, 0);
+ return snd_soc_rtd_to_cpu(rtd, 0);
}
static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai)
@@ -500,14 +492,10 @@ static int fsi_stream_is_working(struct fsi_priv *fsi,
struct fsi_stream *io)
{
struct fsi_master *master = fsi_get_master(fsi);
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&master->lock, flags);
- ret = !!(io->substream && io->substream->runtime);
- spin_unlock_irqrestore(&master->lock, flags);
+ guard(spinlock_irqsave)(&master->lock);
- return ret;
+ return !!(io->substream && io->substream->runtime);
}
static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io)
@@ -521,9 +509,9 @@ static void fsi_stream_init(struct fsi_priv *fsi,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsi_master *master = fsi_get_master(fsi);
- unsigned long flags;
- spin_lock_irqsave(&master->lock, flags);
+ guard(spinlock_irqsave)(&master->lock);
+
io->substream = substream;
io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size);
io->buff_sample_pos = 0;
@@ -534,16 +522,14 @@ static void fsi_stream_init(struct fsi_priv *fsi,
io->oerr_num = -1; /* ignore 1st err */
io->uerr_num = -1; /* ignore 1st err */
fsi_stream_handler_call(io, init, fsi, io);
- spin_unlock_irqrestore(&master->lock, flags);
}
static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
{
struct snd_soc_dai *dai = fsi_get_dai(io->substream);
struct fsi_master *master = fsi_get_master(fsi);
- unsigned long flags;
- spin_lock_irqsave(&master->lock, flags);
+ guard(spinlock_irqsave)(&master->lock);
if (io->oerr_num > 0)
dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
@@ -561,7 +547,6 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
io->bus_option = 0;
io->oerr_num = 0;
io->uerr_num = 0;
- spin_unlock_irqrestore(&master->lock, flags);
}
static int fsi_stream_transfer(struct fsi_stream *io)
@@ -1230,13 +1215,13 @@ static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
return 0;
}
-static struct fsi_stream_handler fsi_pio_push_handler = {
+static const struct fsi_stream_handler fsi_pio_push_handler = {
.init = fsi_pio_push_init,
.transfer = fsi_pio_push,
.start_stop = fsi_pio_start_stop,
};
-static struct fsi_stream_handler fsi_pio_pop_handler = {
+static const struct fsi_stream_handler fsi_pio_pop_handler = {
.init = fsi_pio_pop_init,
.transfer = fsi_pio_pop,
.start_stop = fsi_pio_start_stop,
@@ -1380,7 +1365,9 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev
io->chan = dma_request_channel(mask, shdma_chan_filter,
(void *)io->dma_id);
#else
- io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx");
+ io->chan = dma_request_chan(dev, is_play ? "tx" : "rx");
+ if (IS_ERR(io->chan))
+ io->chan = NULL;
#endif
if (io->chan) {
struct dma_slave_config cfg = {};
@@ -1431,7 +1418,7 @@ static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
return 0;
}
-static struct fsi_stream_handler fsi_dma_push_handler = {
+static const struct fsi_stream_handler fsi_dma_push_handler = {
.init = fsi_dma_init,
.probe = fsi_dma_probe,
.transfer = fsi_dma_transfer,
@@ -1712,7 +1699,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
-static u64 fsi_dai_formats =
+static const u64 fsi_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
@@ -2106,7 +2093,7 @@ static struct platform_driver fsi_driver = {
.of_match_table = fsi_of_match,
},
.probe = fsi_probe,
- .remove_new = fsi_remove,
+ .remove = fsi_remove,
.id_table = fsi_id_table,
};
diff --git a/sound/soc/sh/hac.c b/sound/soc/renesas/hac.c
index cc200f45826c..db618c09d1e0 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/renesas/hac.c
@@ -334,7 +334,7 @@ static struct platform_driver hac_pcm_driver = {
},
.probe = hac_soc_platform_probe,
- .remove_new = hac_soc_platform_remove,
+ .remove = hac_soc_platform_remove,
};
module_platform_driver(hac_pcm_driver);
diff --git a/sound/soc/sh/migor.c b/sound/soc/renesas/migor.c
index 7082c12d3bf2..45fc594d331b 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/renesas/migor.c
@@ -45,8 +45,8 @@ static struct clk_lookup *siumckb_lookup;
static int migor_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
unsigned int rate = params_rate(params);
@@ -67,7 +67,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
clk_set_rate(&siumckb_clk, codec_freq);
dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT,
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT,
codec_freq / 2, SND_SOC_CLOCK_IN);
if (!ret)
@@ -78,8 +78,8 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
static int migor_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
if (use_count) {
use_count--;
@@ -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/Makefile b/sound/soc/renesas/rcar/Makefile
new file mode 100644
index 000000000000..3a2c875595bd
--- /dev/null
+++ b/sound/soc/renesas/rcar/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-soc-rcar-y := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o
+obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
+
+snd-soc-msiof-y := msiof.o
+obj-$(CONFIG_SND_SOC_MSIOF) += snd-soc-msiof.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/renesas/rcar/adg.c
index 0b8926600d90..8641b73d1f77 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/renesas/rcar/adg.c
@@ -19,6 +19,7 @@
#define CLKOUT3 3
#define CLKOUTMAX 4
+#define BRGCKR_31 (1 << 31)
#define BRRx_MASK(x) (0x3FF & x)
static struct rsnd_mod_ops adg_ops = {
@@ -30,6 +31,7 @@ static struct rsnd_mod_ops adg_ops = {
#define ADG_HZ_SIZE 2
struct rsnd_adg {
+ struct clk *adg;
struct clk *clkin[CLKINMAX];
struct clk *clkout[CLKOUTMAX];
struct clk *null_clk;
@@ -111,6 +113,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
ws = 7;
break;
}
+ } else {
+ /*
+ * SSI8 is not connected to ADG.
+ * Thus SSI9 is using ws = 8
+ */
+ if (id == 9)
+ ws = 8;
}
return (0x6 + ws) << 8;
@@ -255,7 +264,7 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
int id = rsnd_mod_id(src_mod);
int shift = (id % 2) ? 16 : 0;
- rsnd_mod_confirm_src(src_mod);
+ rsnd_mod_make_sure(src_mod, RSND_MOD_SRC);
rsnd_adg_get_timesel_ratio(priv, io,
in_rate, out_rate,
@@ -284,7 +293,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
int shift = (id % 4) * 8;
u32 mask = 0xFF << shift;
- rsnd_mod_confirm_ssi(ssi_mod);
+ rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI);
val = val << shift;
@@ -354,12 +363,13 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_adg_set_ssi_clk(ssi_mod, data);
+ ckr = adg->ckr & ~BRGCKR_31;
if (0 == (rate % 8000))
- ckr = 0x80000000; /* BRGB output = 48kHz */
-
- rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
- rsnd_mod_write(adg_mod, BRRA, adg->brga);
- rsnd_mod_write(adg_mod, BRRB, adg->brgb);
+ ckr |= BRGCKR_31; /* use BRGB output = 48kHz */
+ if (ckr != adg->ckr) {
+ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr);
+ adg->ckr = ckr;
+ }
dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
(ckr) ? 'B' : 'A',
@@ -369,26 +379,56 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
return 0;
}
-void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
+int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct clk *clk;
- int i;
+ int ret = 0, i;
+
+ if (enable) {
+ ret = clk_prepare_enable(adg->adg);
+ if (ret < 0)
+ return ret;
+
+ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr);
+ rsnd_mod_write(adg_mod, BRRA, adg->brga);
+ rsnd_mod_write(adg_mod, BRRB, adg->brgb);
+ }
for_each_rsnd_clkin(clk, adg, i) {
if (enable) {
- clk_prepare_enable(clk);
+ ret = clk_prepare_enable(clk);
/*
* We shouldn't use clk_get_rate() under
* atomic context. Let's keep it when
* rsnd_adg_clk_enable() was called
*/
+ if (ret < 0)
+ break;
+
adg->clkin_rate[i] = clk_get_rate(clk);
} else {
- clk_disable_unprepare(clk);
+ if (adg->clkin_rate[i])
+ clk_disable_unprepare(clk);
+
+ adg->clkin_rate[i] = 0;
}
}
+
+ /*
+ * rsnd_adg_clk_enable() might return error (_disable() will not).
+ * We need to rollback in such case
+ */
+ if (ret < 0)
+ rsnd_adg_clk_disable(priv);
+
+ /* disable adg */
+ if (!enable)
+ clk_disable_unprepare(adg->adg);
+
+ return ret;
}
static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
@@ -444,6 +484,16 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
clkin_size = ARRAY_SIZE(clkin_name_gen4);
}
+ /*
+ * get adg
+ * No "adg" is not error
+ */
+ clk = devm_clk_get(dev, "adg");
+ if (IS_ERR_OR_NULL(clk))
+ clk = rsnd_adg_null_clk_get(priv);
+ adg->adg = clk;
+
+ /* get clkin */
for (i = 0; i < clkin_size; i++) {
clk = devm_clk_get(dev, clkin_name[i]);
@@ -485,12 +535,12 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
struct device_node *np = dev->of_node;
struct property *prop;
u32 ckr, brgx, brga, brgb;
- u32 rate, div;
u32 req_rate[ADG_HZ_SIZE] = {};
uint32_t count = 0;
unsigned long req_Hz[ADG_HZ_SIZE];
int clkout_size;
int i, req_size;
+ int approximate = 0;
const char *parent_clk_name = NULL;
const char * const *clkout_name;
int brg_table[] = {
@@ -501,8 +551,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
};
ckr = 0;
- brga = 2; /* default 1/6 */
- brgb = 2; /* default 1/6 */
+ brga = 0xff; /* default */
+ brgb = 0xff; /* default */
/*
* ADG supports BRRA/BRRB output only
@@ -537,17 +587,41 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
* rsnd_adg_ssi_clk_try_start()
* rsnd_ssi_master_clk_start()
*/
+
+ /*
+ * [APPROXIMATE]
+ *
+ * clk_i (internal clock) can't create accurate rate, it will be approximate rate.
+ *
+ * <Note>
+ *
+ * clk_i needs x2 of required maximum rate.
+ * see
+ * - Minimum division of BRRA/BRRB
+ * - rsnd_ssi_clk_query()
+ *
+ * Sample Settings for TDM 8ch, 32bit width
+ *
+ * 8(ch) x 32(bit) x 44100(Hz) x 2<Note> = 22579200
+ * 8(ch) x 32(bit) x 48000(Hz) x 2<Note> = 24576000
+ *
+ * clock-frequency = <22579200 24576000>;
+ */
for_each_rsnd_clkin(clk, adg, i) {
+ u32 rate, div;
+
rate = clk_get_rate(clk);
if (0 == rate) /* not used */
continue;
/* BRGA */
- if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) {
- div = 6;
- if (req_Hz[ADG_HZ_441])
- div = rate / req_Hz[ADG_HZ_441];
+
+ if (i == CLKI)
+ /* see [APPROXIMATE] */
+ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441];
+ if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) {
+ div = rate / req_Hz[ADG_HZ_441];
brgx = rsnd_adg_calculate_brgx(div);
if (BRRx_MASK(brgx) == brgx) {
brga = brgx;
@@ -555,14 +629,18 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
ckr |= brg_table[i] << 20;
if (req_Hz[ADG_HZ_441])
parent_clk_name = __clk_get_name(clk);
+ if (i == CLKI)
+ approximate = 1;
}
}
/* BRGB */
- if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) {
- div = 6;
- if (req_Hz[ADG_HZ_48])
- div = rate / req_Hz[ADG_HZ_48];
+
+ if (i == CLKI)
+ /* see [APPROXIMATE] */
+ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48];
+ if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) {
+ div = rate / req_Hz[ADG_HZ_48];
brgx = rsnd_adg_calculate_brgx(div);
if (BRRx_MASK(brgx) == brgx) {
brgb = brgx;
@@ -570,10 +648,19 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
ckr |= brg_table[i] << 16;
if (req_Hz[ADG_HZ_48])
parent_clk_name = __clk_get_name(clk);
+ if (i == CLKI)
+ approximate = 1;
}
}
}
+ if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) &&
+ !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441]))
+ goto rsnd_adg_get_clkout_end;
+
+ if (approximate)
+ dev_info(dev, "It uses CLK_I as approximate rate");
+
clkout_name = clkout_name_gen2;
clkout_size = ARRAY_SIZE(clkout_name_gen2);
if (rsnd_is_gen4(priv))
@@ -619,6 +706,9 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
}
rsnd_adg_get_clkout_end:
+ if (0 == (req_rate[0] % 8000))
+ ckr |= BRGCKR_31; /* use BRGB output = 48kHz */
+
adg->ckr = ckr;
adg->brga = brga;
adg->brgb = brgb;
@@ -704,7 +794,10 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
if (ret)
return ret;
- rsnd_adg_clk_enable(priv);
+ ret = rsnd_adg_clk_enable(priv);
+ if (ret)
+ return ret;
+
rsnd_adg_clk_dbg_info(priv, NULL);
return 0;
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/renesas/rcar/cmd.c
index 329e6ab1b222..8d9a1e345a22 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/renesas/rcar/cmd.c
@@ -119,7 +119,7 @@ static void rsnd_cmd_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30);
}
#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info
@@ -157,10 +157,6 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
struct rsnd_cmd *cmd;
int i, nr;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
/* same number as DVC */
nr = priv->dvc_nr;
if (!nr)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/renesas/rcar/core.c
index 6a522e6dd85a..69fb19964a71 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/renesas/rcar/core.c
@@ -91,6 +91,7 @@
*/
#include <linux/pm_runtime.h>
+#include <linux/of_graph.h>
#include "rsnd.h"
#define RSND_RATES SNDRV_PCM_RATE_8000_192000
@@ -659,23 +660,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
return rsnd_rdai_get(priv, dai->id);
}
-/*
- * rsnd_soc_dai functions
- */
-void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
-{
- struct snd_pcm_substream *substream = io->substream;
-
- /*
- * this function should be called...
- *
- * - if rsnd_dai_pointer_update() returns true
- * - without spin lock
- */
-
- snd_pcm_period_elapsed(substream);
-}
-
static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
struct snd_pcm_substream *substream)
{
@@ -690,9 +674,9 @@ static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
static
struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- return asoc_rtd_to_cpu(rtd, 0);
+ return snd_soc_rtd_to_cpu(rtd, 0);
}
static
@@ -712,25 +696,21 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
int ret;
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
+ guard(spinlock_irqsave)(&priv->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
ret = rsnd_dai_call(init, io, priv);
if (ret < 0)
- goto dai_trigger_end;
+ break;
ret = rsnd_dai_call(start, io, priv);
if (ret < 0)
- goto dai_trigger_end;
+ break;
ret = rsnd_dai_call(irq, io, priv, 1);
- if (ret < 0)
- goto dai_trigger_end;
-
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -745,9 +725,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
ret = -EINVAL;
}
-dai_trigger_end:
- spin_unlock_irqrestore(&priv->lock, flags);
-
return ret;
}
@@ -1060,7 +1037,7 @@ static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
return rsnd_dai_call(prepare, io, priv);
}
-static u64 rsnd_soc_dai_formats[] = {
+static const u64 rsnd_soc_dai_formats[] = {
/*
* 1st Priority
*
@@ -1085,24 +1062,12 @@ static u64 rsnd_soc_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
- .startup = rsnd_soc_dai_startup,
- .shutdown = rsnd_soc_dai_shutdown,
- .trigger = rsnd_soc_dai_trigger,
- .set_fmt = rsnd_soc_dai_set_fmt,
- .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
- .prepare = rsnd_soc_dai_prepare,
- .auto_selectable_formats = rsnd_soc_dai_formats,
- .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats),
-};
-
static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct device_node *dai_np)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
- struct device_node *np;
int is_play = rsnd_io_is_play(io);
int i;
@@ -1121,7 +1086,7 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
if (!node)
break;
- for_each_child_of_node(ssiu_np, np) {
+ for_each_child_of_node_scoped(ssiu_np, np) {
if (np == node) {
rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
dev_dbg(dev, "%s is part of TDM Split\n", io->name);
@@ -1181,21 +1146,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
- struct device_node *np;
int i;
if (!node)
return;
i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
struct rsnd_mod *mod;
i = rsnd_node_fixed_index(dev, np, name, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
break;
- }
mod = mod_get(priv, i);
@@ -1244,29 +1206,39 @@ int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *na
int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name)
{
struct device *dev = rsnd_priv_to_dev(priv);
- struct device_node *np;
int i;
i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
i = rsnd_node_fixed_index(dev, np, name, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
return 0;
- }
i++;
}
return i;
}
-static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
- int *is_graph)
+static struct device_node*
+ rsnd_pick_endpoint_node_for_ports(struct device_node *e_ports,
+ struct device_node *e_port)
+{
+ if (of_node_name_eq(e_ports, "ports"))
+ return e_ports;
+
+ if (of_node_name_eq(e_ports, "port"))
+ return e_port;
+
+ return NULL;
+}
+
+static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
- struct device_node *dai_node;
- struct device_node *ret;
+ struct device_node *node;
+ int nr = 0;
+ int i = 0;
*is_graph = 0;
@@ -1274,26 +1246,51 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
* parse both previous dai (= rcar_sound,dai), and
* graph dai (= ports/port)
*/
- dai_node = of_get_child_by_name(np, RSND_NODE_DAI);
- if (dai_node) {
- ret = dai_node;
- goto of_node_compatible;
- }
- ret = np;
+ /*
+ * Simple-Card
+ */
+ node = of_get_child_by_name(np, RSND_NODE_DAI);
+ if (!node)
+ goto audio_graph;
- dai_node = of_graph_get_next_endpoint(np, NULL);
- if (dai_node)
- goto of_node_graph;
+ of_node_put(node);
- return NULL;
+ for_each_child_of_node_scoped(np, node) {
+ if (!of_node_name_eq(node, RSND_NODE_DAI))
+ continue;
+
+ priv->component_dais[i] = of_get_child_count(node);
+ nr += priv->component_dais[i];
+ i++;
+ if (i >= RSND_MAX_COMPONENT) {
+ dev_info(dev, "reach to max component\n");
+ break;
+ }
+ }
+
+ return nr;
+
+audio_graph:
+ /*
+ * Audio-Graph-Card
+ */
+ for_each_child_of_node_scoped(np, ports) {
+ node = rsnd_pick_endpoint_node_for_ports(ports, np);
+ if (!node)
+ continue;
+ priv->component_dais[i] = of_graph_get_endpoint_count(node);
+ nr += priv->component_dais[i];
+ i++;
+ if (i >= RSND_MAX_COMPONENT) {
+ dev_info(dev, "reach to max component\n");
+ break;
+ }
+ }
-of_node_graph:
*is_graph = 1;
-of_node_compatible:
- of_node_put(dai_node);
- return ret;
+ return nr;
}
@@ -1328,8 +1325,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai)
+static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
int ret;
@@ -1355,8 +1351,22 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+ .pcm_new = rsnd_soc_dai_pcm_new,
+ .startup = rsnd_soc_dai_startup,
+ .shutdown = rsnd_soc_dai_shutdown,
+ .trigger = rsnd_soc_dai_trigger,
+ .set_fmt = rsnd_soc_dai_set_fmt,
+ .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
+ .prepare = rsnd_soc_dai_prepare,
+ .auto_selectable_formats = rsnd_soc_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats),
+};
+
static void __rsnd_dai_probe(struct rsnd_priv *priv,
struct device_node *dai_np,
+ struct device_node *node_np,
+ uint32_t node_arg,
int dai_i)
{
struct rsnd_dai_stream *io_playback;
@@ -1374,10 +1384,16 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
+ /* for multi Component */
+ rdai->dai_args.np = node_np;
+ rdai->dai_args.args_count = 1;
+ rdai->dai_args.args[0] = node_arg;
+
rdai->priv = priv;
drv->name = rdai->name;
drv->ops = &rsnd_soc_dai_ops;
- drv->pcm_new = rsnd_pcm_new;
+ drv->id = dai_i;
+ drv->dai_args = &rdai->dai_args;
io_playback->rdai = rdai;
io_capture->rdai = rdai;
@@ -1441,23 +1457,22 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
static int rsnd_dai_probe(struct rsnd_priv *priv)
{
- struct device_node *dai_node;
- struct device_node *dai_np;
struct snd_soc_dai_driver *rdrv;
struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *np = dev->of_node;
struct rsnd_dai *rdai;
- int nr;
+ int nr = 0;
int is_graph;
int dai_i;
- dai_node = rsnd_dai_of_node(priv, &is_graph);
- if (is_graph)
- nr = of_graph_get_endpoint_count(dai_node);
- else
- nr = of_get_child_count(dai_node);
+ nr = rsnd_dai_of_node(priv, &is_graph);
+ /*
+ * There is a case that it is used only for ADG (Sound Clock).
+ * No DAI is not error
+ */
if (!nr)
- return -EINVAL;
+ return 0;
rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL);
rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL);
@@ -1473,26 +1488,40 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
*/
dai_i = 0;
if (is_graph) {
- for_each_endpoint_of_node(dai_node, dai_np) {
- __rsnd_dai_probe(priv, dai_np, dai_i);
- if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
- rdai = rsnd_rdai_get(priv, dai_i);
+ struct device_node *dai_np_port;
+ struct device_node *dai_np;
+
+ for_each_child_of_node_scoped(np, ports) {
+ dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np);
+ if (!dai_np_port)
+ continue;
- rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
- rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
+ for_each_endpoint_of_node(dai_np_port, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
+ if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
+ rdai = rsnd_rdai_get(priv, dai_i);
+
+ rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+ rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
+ }
+ dai_i++;
}
- dai_i++;
}
} else {
- for_each_child_of_node(dai_node, dai_np) {
- __rsnd_dai_probe(priv, dai_np, dai_i);
- if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
- rdai = rsnd_rdai_get(priv, dai_i);
+ for_each_child_of_node_scoped(np, node) {
+ if (!of_node_name_eq(node, RSND_NODE_DAI))
+ continue;
+
+ for_each_child_of_node_scoped(node, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i);
+ if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
+ rdai = rsnd_rdai_get(priv, dai_i);
- rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
- rsnd_parse_connect_simple(priv, &rdai->capture, dai_np);
+ rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
+ rsnd_parse_connect_simple(priv, &rdai->capture, dai_np);
+ }
+ dai_i++;
}
- dai_i++;
}
}
@@ -1509,15 +1538,14 @@ static int rsnd_hw_update(struct snd_pcm_substream *substream,
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
struct rsnd_priv *priv = rsnd_io_to_priv(io);
- unsigned long flags;
int ret;
- spin_lock_irqsave(&priv->lock, flags);
+ guard(spinlock_irqsave)(&priv->lock);
+
if (hw_params)
ret = rsnd_dai_call(hw_params, io, substream, hw_params);
else
ret = rsnd_dai_call(hw_free, io, substream);
- spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
@@ -1529,7 +1557,7 @@ static int rsnd_hw_params(struct snd_soc_component *component,
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
/*
* rsnd assumes that it might be used under DPCM if user want to use
@@ -1726,20 +1754,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;
@@ -1799,7 +1813,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = name,
.info = rsnd_kctrl_info,
- .index = rtd->num,
+ .index = rtd->id,
.get = rsnd_kctrl_get,
.put = rsnd_kctrl_put,
};
@@ -1922,6 +1936,7 @@ static int rsnd_probe(struct platform_device *pdev)
rsnd_dai_probe,
};
int ret, i;
+ int ci;
/*
* init priv data
@@ -1958,11 +1973,18 @@ static int rsnd_probe(struct platform_device *pdev)
/*
* asoc register
*/
- ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
- priv->daidrv, rsnd_rdai_nr(priv));
- if (ret < 0) {
- dev_err(dev, "cannot snd dai register\n");
- goto exit_snd_probe;
+ ci = 0;
+ for (i = 0; priv->component_dais[i] > 0; i++) {
+ int nr = priv->component_dais[i];
+
+ ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
+ priv->daidrv + ci, nr);
+ if (ret < 0) {
+ dev_err(dev, "cannot snd component register\n");
+ goto exit_snd_probe;
+ }
+
+ ci += nr;
}
pm_runtime_enable(dev);
@@ -2021,7 +2043,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);
@@ -2030,27 +2052,25 @@ 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);
- rsnd_adg_clk_enable(priv);
-
- return 0;
+ return rsnd_adg_clk_enable(priv);
}
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,
- .remove_new = rsnd_remove,
+ .remove = rsnd_remove,
};
module_platform_driver(rsnd_driver);
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/renesas/rcar/ctu.c
index e39eb2ac7e95..bd4c61f9fb3c 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/renesas/rcar/ctu.c
@@ -284,7 +284,7 @@ static void rsnd_ctu_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100);
}
#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info
@@ -316,17 +316,12 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
int rsnd_ctu_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ctu *ctu;
struct clk *clk;
char name[CTU_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_ctu_of_node(priv);
if (!node)
return 0; /* not used is not error */
@@ -348,7 +343,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
i = 0;
ret = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
ctu = rsnd_ctu_get(priv, i);
/*
@@ -361,16 +356,13 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(np);
goto rsnd_ctu_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
clk, RSND_MOD_CTU, i);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto rsnd_ctu_probe_done;
- }
i++;
}
diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/renesas/rcar/debugfs.c
index 26d3b310b9db..26d3b310b9db 100644
--- a/sound/soc/sh/rcar/debugfs.c
+++ b/sound/soc/renesas/rcar/debugfs.c
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/renesas/rcar/dma.c
index 1c494e521463..2035ce06fe4c 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/renesas/rcar/dma.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/of_dma.h>
+#include <sound/dmaengine_pcm.h>
#include "rsnd.h"
/*
@@ -22,8 +23,6 @@
struct rsnd_dmaen {
struct dma_chan *chan;
- dma_cookie_t cookie;
- unsigned int dma_len;
};
struct rsnd_dmapp {
@@ -66,20 +65,6 @@ static struct rsnd_mod mem = {
/*
* Audio DMAC
*/
-static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
-{
- if (rsnd_io_is_working(io))
- rsnd_dai_period_elapsed(io);
-}
-
-static void rsnd_dmaen_complete(void *data)
-{
- struct rsnd_mod *mod = data;
-
- rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
-}
-
static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
struct rsnd_mod *mod_from,
struct rsnd_mod *mod_to)
@@ -98,13 +83,7 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
- struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
- if (dmaen->chan)
- dmaengine_terminate_async(dmaen->chan);
-
- return 0;
+ return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP);
}
static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
@@ -120,7 +99,7 @@ static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
* Let's call it under prepare
*/
if (dmaen->chan)
- dma_release_channel(dmaen->chan);
+ snd_dmaengine_pcm_close_release_chan(io->substream);
dmaen->chan = NULL;
@@ -153,7 +132,7 @@ static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
return -EIO;
}
- return 0;
+ return snd_dmaengine_pcm_open(io->substream, dmaen->chan);
}
static int rsnd_dmaen_start(struct rsnd_mod *mod,
@@ -162,12 +141,9 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv);
- struct dma_async_tx_descriptor *desc;
struct dma_slave_config cfg = {};
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
- int is_play = rsnd_io_is_play(io);
int ret;
/*
@@ -195,7 +171,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
}
}
- cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ cfg.direction = snd_pcm_substream_to_dma_direction(io->substream);
cfg.src_addr = dma->src_addr;
cfg.dst_addr = dma->dst_addr;
cfg.src_addr_width = buswidth;
@@ -209,32 +185,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
if (ret < 0)
return ret;
- desc = dmaengine_prep_dma_cyclic(dmaen->chan,
- substream->runtime->dma_addr,
- snd_pcm_lib_buffer_bytes(substream),
- snd_pcm_lib_period_bytes(substream),
- is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
- if (!desc) {
- dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
- return -EIO;
- }
-
- desc->callback = rsnd_dmaen_complete;
- desc->callback_param = rsnd_mod_get(dma);
-
- dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream);
-
- dmaen->cookie = dmaengine_submit(desc);
- if (dmaen->cookie < 0) {
- dev_err(dev, "dmaengine_submit() fail\n");
- return -EIO;
- }
-
- dma_async_issue_pending(dmaen->chan);
-
- return 0;
+ return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START);
}
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
@@ -243,14 +194,12 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *nam
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_chan *chan = NULL;
- struct device_node *np;
int i = 0;
- for_each_child_of_node(of_node, np) {
+ for_each_child_of_node_scoped(of_node, np) {
i = rsnd_node_fixed_index(dev, np, name, i);
if (i < 0) {
chan = NULL;
- of_node_put(np);
break;
}
@@ -307,19 +256,7 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
snd_pcm_uframes_t *pointer)
{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
- struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- struct dma_tx_state state;
- enum dma_status status;
- unsigned int pos = 0;
-
- status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state);
- if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
- if (state.residue > 0 && state.residue <= dmaen->dma_len)
- pos = dmaen->dma_len - state.residue;
- }
- *pointer = bytes_to_frames(runtime, pos);
+ *pointer = snd_dmaengine_pcm_pointer(io->substream);
return 0;
}
@@ -585,8 +522,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct device *dev = rsnd_priv_to_dev(priv);
- phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
- phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
+ phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
+ phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
!!(rsnd_io_to_mod_ssiu(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
@@ -666,7 +603,7 @@ rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
int is_play, int is_from)
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
- phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_GEN4_SDMC);
+ phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC);
int id = rsnd_mod_id(mod);
int busif = rsnd_mod_id_sub(mod);
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/renesas/rcar/dvc.c
index 16befcbc312c..988cbddbc611 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/renesas/rcar/dvc.c
@@ -294,7 +294,7 @@ static void rsnd_dvc_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);
}
#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info
@@ -324,17 +324,12 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
int rsnd_dvc_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_dvc *dvc;
struct clk *clk;
char name[RSND_DVC_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_dvc_of_node(priv);
if (!node)
return 0; /* not used is not error */
@@ -356,7 +351,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
i = 0;
ret = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
dvc = rsnd_dvc_get(priv, i);
snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
@@ -365,16 +360,13 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(np);
goto rsnd_dvc_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
clk, RSND_MOD_DVC, i);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto rsnd_dvc_probe_done;
- }
i++;
}
diff --git a/sound/soc/renesas/rcar/gen.c b/sound/soc/renesas/rcar/gen.c
new file mode 100644
index 000000000000..d1f20cde66be
--- /dev/null
+++ b/sound/soc/renesas/rcar/gen.c
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Gen1 SRU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+/*
+ * #define DEBUG
+ *
+ * you can also add below in
+ * ${LINUX}/drivers/base/regmap/regmap.c
+ * for regmap debug
+ *
+ * #define LOG_DEVICE "xxxx.rcar_sound"
+ */
+
+#include "rsnd.h"
+
+struct rsnd_gen {
+ struct rsnd_gen_ops *ops;
+
+ /* RSND_BASE_MAX base */
+ void __iomem *base[RSND_BASE_MAX];
+ phys_addr_t res[RSND_BASE_MAX];
+ struct regmap *regmap[RSND_BASE_MAX];
+
+ /* RSND_REG_MAX base */
+ struct regmap_field *regs[REG_MAX];
+ const char *reg_name[REG_MAX];
+};
+
+#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
+#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
+
+struct rsnd_regmap_field_conf {
+ int idx;
+ unsigned int reg_offset;
+ unsigned int id_offset;
+ const char *reg_name;
+};
+
+#define RSND_REG_SET(id, offset, _id_offset, n) \
+{ \
+ .idx = id, \
+ .reg_offset = offset, \
+ .id_offset = _id_offset, \
+ .reg_name = n, \
+}
+/* single address mapping */
+#define RSND_GEN_S_REG(id, offset) \
+ RSND_REG_SET(id, offset, 0, #id)
+
+/* multi address mapping */
+#define RSND_GEN_M_REG(id, offset, _id_offset) \
+ RSND_REG_SET(id, offset, _id_offset, #id)
+
+/*
+ * basic function
+ */
+static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
+ struct rsnd_gen *gen, enum rsnd_reg reg)
+{
+ if (!gen->regs[reg]) {
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_err(dev, "unsupported register access %x\n", reg);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
+{
+ if (mod->ops->id_cmd)
+ return mod->ops->id_cmd(mod);
+
+ return rsnd_mod_id(mod);
+}
+
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+ u32 val;
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return 0;
+
+ regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
+
+ dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod),
+ rsnd_reg_name(gen, reg), reg, val);
+
+ return val;
+}
+
+void rsnd_mod_write(struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 data)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return;
+
+ regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
+
+ dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod),
+ rsnd_reg_name(gen, reg), reg, data);
+}
+
+void rsnd_mod_bset(struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 mask, u32 data)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return;
+
+ regmap_fields_force_update_bits(gen->regs[reg],
+ rsnd_mod_id_cmd(mod), mask, data);
+
+ dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
+ rsnd_mod_name(mod),
+ rsnd_reg_name(gen, reg), reg, data, mask);
+
+}
+
+phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
+{
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ return gen->res[reg_id];
+}
+
+#ifdef CONFIG_DEBUG_FS
+void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id)
+{
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ return gen->base[reg_id];
+}
+#endif
+
+#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \
+ _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
+static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
+ int id_size,
+ int reg_id,
+ const char *name,
+ const struct rsnd_regmap_field_conf *conf,
+ int conf_size)
+{
+ struct platform_device *pdev = rsnd_priv_to_pdev(priv);
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct resource *res;
+ struct regmap_config regc;
+ struct regmap_field *regs;
+ struct regmap *regmap;
+ struct reg_field regf;
+ void __iomem *base;
+ int i;
+
+ memset(&regc, 0, sizeof(regc));
+ regc.reg_bits = 32;
+ regc.val_bits = 32;
+ regc.reg_stride = 4;
+ regc.name = name;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ if (!res)
+ return -ENODEV;
+
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &regc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* RSND_BASE_MAX base */
+ gen->base[reg_id] = base;
+ gen->regmap[reg_id] = regmap;
+ gen->res[reg_id] = res->start;
+
+ for (i = 0; i < conf_size; i++) {
+
+ regf.reg = conf[i].reg_offset;
+ regf.id_offset = conf[i].id_offset;
+ regf.lsb = 0;
+ regf.msb = 31;
+ regf.id_size = id_size;
+
+ regs = devm_regmap_field_alloc(dev, regmap, regf);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ /* RSND_REG_MAX base */
+ gen->regs[conf[i].idx] = regs;
+ gen->reg_name[conf[i].idx] = conf[i].reg_name;
+ }
+
+ return 0;
+}
+
+/*
+ * (A) : Gen4 is 0xa0c, but it is not used.
+ * see
+ * rsnd_ssiu_init()
+ */
+static const struct rsnd_regmap_field_conf conf_common_ssiu[] = {
+ RSND_GEN_S_REG(SSI_MODE0, 0x800),
+ RSND_GEN_S_REG(SSI_MODE1, 0x804),
+ RSND_GEN_S_REG(SSI_MODE2, 0x808), // (A)
+ RSND_GEN_S_REG(SSI_CONTROL, 0x810),
+ RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
+ RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
+ RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
+ RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
+ RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
+ RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
+ RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
+ RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
+ RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c),
+ RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
+ RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
+ RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80),
+ RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
+ RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
+ RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
+ RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c),
+ RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484),
+ RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488),
+ RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0),
+ RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4),
+ RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8),
+ RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0),
+ RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4),
+ RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8),
+ RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0),
+ RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4),
+ RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8),
+ RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80),
+ RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84),
+ RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88),
+ RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0),
+ RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4),
+ RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8),
+ RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0),
+ RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4),
+ RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8),
+ RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0),
+ RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4),
+ RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_scu[] = {
+ RSND_GEN_M_REG(SRC_I_BUSIF_MODE, 0x0, 0x20),
+ RSND_GEN_M_REG(SRC_O_BUSIF_MODE, 0x4, 0x20),
+ RSND_GEN_M_REG(SRC_BUSIF_DALIGN, 0x8, 0x20),
+ RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
+ RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
+ RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
+ RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20),
+ RSND_GEN_M_REG(CMD_BUSIF_DALIGN, 0x188, 0x20),
+ RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
+ RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
+ RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
+ RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
+ RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
+ RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
+ RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
+ RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
+ RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
+ RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
+ RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
+ RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
+ RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
+ RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
+ RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
+ RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
+ RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
+ RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
+ RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
+ RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
+ RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
+ RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
+ RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
+ RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
+ RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
+ RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
+ RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
+ RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
+ RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
+ RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
+ RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
+ RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
+ RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
+ RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
+ RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
+ RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
+ RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
+ RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
+ RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
+ RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
+ RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
+ RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
+ RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
+ RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
+ RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
+ RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
+ RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
+ RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
+ RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
+ RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
+ RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
+ RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
+ RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
+ RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
+ RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40),
+ RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40),
+ RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40),
+ RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40),
+ RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40),
+ RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40),
+ RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40),
+ RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
+ RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
+ RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
+ RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
+ RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
+ RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
+ RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
+ RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
+ RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
+ RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
+ RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
+ RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
+ RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
+ RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
+ RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
+ RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
+ RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_adg[] = {
+ RSND_GEN_S_REG(BRRA, 0x00),
+ RSND_GEN_S_REG(BRRB, 0x04),
+ RSND_GEN_S_REG(BRGCKR, 0x08),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
+ RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
+ RSND_GEN_S_REG(DIV_EN, 0x30),
+ RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34),
+ RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38),
+ RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c),
+ RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40),
+ RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54),
+ RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
+ RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_ssi[] = {
+ RSND_GEN_M_REG(SSICR, 0x00, 0x40),
+ RSND_GEN_M_REG(SSISR, 0x04, 0x40),
+ RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
+ RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
+ RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
+};
+
+/*
+ * Gen4
+ */
+static int rsnd_gen4_probe(struct rsnd_priv *priv)
+{
+ struct rsnd_regmap_field_conf conf_null[] = { };
+
+ /*
+ * ssiu: SSIU0
+ * ssi : SSI0
+ */
+ int ret_ssiu = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
+ int ret_ssi = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSI, "ssi", conf_common_ssi);
+ int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
+ int ret_sdmc = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SDMC, "sdmc", conf_null);
+
+ return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
+}
+
+/*
+ * Gen2
+ */
+static int rsnd_gen2_probe(struct rsnd_priv *priv)
+{
+ /*
+ * ssi : SSI0 - SSI9
+ * ssiu: SSIU0 - SSIU9
+ * scu : SRC0 - SRC9 etc
+ */
+ int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI, "ssi", conf_common_ssi);
+ int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
+ int ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU, "scu", conf_common_scu);
+ int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
+
+ return ret_ssi | ret_ssiu | ret_scu | ret_adg;
+}
+
+/*
+ * Gen1
+ */
+
+static int rsnd_gen1_probe(struct rsnd_priv *priv)
+{
+ /*
+ * ssi : SSI0 - SSI8
+ */
+ int ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_BASE_SSI, "ssi", conf_common_ssi);
+ int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
+
+ return ret_adg | ret_ssi;
+}
+
+/*
+ * Gen
+ */
+int rsnd_gen_probe(struct rsnd_priv *priv)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_gen *gen;
+ int ret;
+
+ gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
+ if (!gen)
+ return -ENOMEM;
+
+ priv->gen = gen;
+
+ ret = -ENODEV;
+ if (rsnd_is_gen1(priv))
+ ret = rsnd_gen1_probe(priv);
+ else if (rsnd_is_gen2(priv) ||
+ rsnd_is_gen3(priv))
+ ret = rsnd_gen2_probe(priv);
+ else if (rsnd_is_gen4(priv))
+ ret = rsnd_gen4_probe(priv);
+
+ if (ret < 0)
+ dev_err(dev, "unknown generation R-Car sound device\n");
+
+ return ret;
+}
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/renesas/rcar/mix.c
index 1de0e085804c..aea74e703305 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/renesas/rcar/mix.c
@@ -259,7 +259,7 @@ static void rsnd_mix_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
}
#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
@@ -288,17 +288,12 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
int rsnd_mix_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mix *mix;
struct clk *clk;
char name[MIX_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_mix_of_node(priv);
if (!node)
return 0; /* not used is not error */
@@ -320,7 +315,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
i = 0;
ret = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
mix = rsnd_mix_get(priv, i);
snprintf(name, MIX_NAME_SIZE, "%s.%d",
@@ -329,16 +324,13 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(np);
goto rsnd_mix_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
clk, RSND_MOD_MIX, i);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto rsnd_mix_probe_done;
- }
i++;
}
diff --git a/sound/soc/renesas/rcar/msiof.c b/sound/soc/renesas/rcar/msiof.c
new file mode 100644
index 000000000000..f2addfbac923
--- /dev/null
+++ b/sound/soc/renesas/rcar/msiof.c
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car MSIOF (Clock-Synchronized Serial Interface with FIFO) I2S driver
+//
+// Copyright (C) 2025 Renesas Solutions Corp.
+// Author: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+
+/*
+ * [NOTE-CLOCK-MODE]
+ *
+ * This driver doesn't support Clock/Frame Provider Mode
+ *
+ * Basically MSIOF is created for SPI, but we can use it as I2S (Sound), etc. Because of it, when
+ * we use it as I2S (Sound) with Provider Mode, we need to send dummy TX data even though it was
+ * used for RX. Because SPI HW needs TX Clock/Frame output for RX purpose.
+ * But it makes driver code complex in I2S (Sound).
+ *
+ * And when we use it as I2S (Sound) as Provider Mode, the clock source is [MSO clock] (= 133.33MHz)
+ * SoC internal clock. It is not for 48kHz/44.1kHz base clock. Thus the output/input will not be
+ * accurate sound.
+ *
+ * Because of these reasons, this driver doesn't support Clock/Frame Provider Mode. Use it as
+ * Clock/Frame Consumer Mode.
+ */
+
+/*
+ * [NOTE-RESET]
+ *
+ * MSIOF has TXRST/RXRST to reset FIFO, but it shouldn't be used during SYNC signal was asserted,
+ * because it will be cause of HW issue.
+ *
+ * When MSIOF is used as Sound driver, this driver is assuming it is used as clock consumer mode
+ * (= Codec is clock provider). This means, it can't control SYNC signal by itself.
+ *
+ * We need to use SW reset (= reset_control_xxx()) instead of TXRST/RXRST.
+ */
+
+/*
+ * [NOTE-BOTH-SETTING]
+ *
+ * SITMDRn / SIRMDRn and some other registers should not be updated during working even though it
+ * was not related the target direction (for example, do TX settings during RX is working),
+ * otherwise it cause a FSERR.
+ *
+ * Setup both direction (Playback/Capture) in the same time.
+ */
+
+/*
+ * [NOTE-R/L]
+ *
+ * The data of Captured might be R/L opposite.
+ *
+ * This driver is assuming MSIOF is used as Clock/Frame Consumer Mode, and there is a case that some
+ * Codec (= Clock/Frame Provider) might output Clock/Frame before setup MSIOF. It depends on Codec
+ * driver implementation.
+ *
+ * MSIOF will capture data without checking SYNC signal Hi/Low (= R/L).
+ *
+ * This means, if MSIOF RXE bit was set as 1 in case of SYNC signal was Hi (= R) timing, it will
+ * start capture data since next SYNC low singla (= L). Because Linux assumes sound data is lined
+ * up as R->L->R->L->..., the data R/L will be opposite.
+ *
+ * The only solution in this case is start CLK/SYNC *after* MSIOF settings, but it depends when and
+ * how Codec driver start it.
+ */
+
+/*
+ * [NOTE-FSERR]
+ *
+ * We can't remove all FSERR.
+ *
+ * Renesas have tried to minimize the occurrence of FSERR errors as much as possible, but
+ * unfortunately we cannot remove them completely, because MSIOF might setup its register during
+ * CLK/SYNC are inputed. It can be happen because MSIOF is working as Clock/Frame Consumer.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/spi/sh_msiof.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+
+/* SISTR */
+#define SISTR_ERR_TX (SISTR_TFSERR | SISTR_TFOVF | SISTR_TFUDF)
+#define SISTR_ERR_RX (SISTR_RFSERR | SISTR_RFOVF | SISTR_RFUDF)
+
+/*
+ * The data on memory in 24bit case is located at <right> side
+ * [ xxxxxx]
+ * [ xxxxxx]
+ * [ xxxxxx]
+ *
+ * HW assuming signal in 24bit case is located at <left> side
+ * ---+ +---------+
+ * +---------+ +---------+...
+ * [xxxxxx ][xxxxxx ][xxxxxx ]
+ *
+ * When we use 24bit data, it will be transferred via 32bit width via DMA,
+ * and MSIOF/DMA doesn't support data shift, we can't use 24bit data correctly.
+ * There is no such issue on 16/32bit data case.
+ */
+#define MSIOF_RATES SNDRV_PCM_RATE_8000_192000
+#define MSIOF_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct msiof_priv {
+ struct device *dev;
+ struct snd_pcm_substream *substream[SNDRV_PCM_STREAM_LAST + 1];
+ struct reset_control *reset;
+ spinlock_t lock;
+ void __iomem *base;
+ resource_size_t phy_addr;
+
+ int count;
+
+ /* for error */
+ int err_syc[SNDRV_PCM_STREAM_LAST + 1];
+ int err_ovf[SNDRV_PCM_STREAM_LAST + 1];
+ int err_udf[SNDRV_PCM_STREAM_LAST + 1];
+
+ /* bit field */
+ u32 flags;
+#define MSIOF_FLAGS_NEED_DELAY (1 << 0)
+};
+#define msiof_flag_has(priv, flag) (priv->flags & flag)
+#define msiof_flag_set(priv, flag) (priv->flags |= flag)
+
+#define msiof_is_play(substream) ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK)
+#define msiof_read(priv, reg) ioread32((priv)->base + reg)
+#define msiof_write(priv, reg, val) iowrite32(val, (priv)->base + reg)
+
+static int msiof_update(struct msiof_priv *priv, u32 reg, u32 mask, u32 val)
+{
+ u32 old = msiof_read(priv, reg);
+ u32 new = (old & ~mask) | (val & mask);
+ int updated = false;
+
+ if (old != new) {
+ msiof_write(priv, reg, new);
+ updated = true;
+ }
+
+ return updated;
+}
+
+static void msiof_update_and_wait(struct msiof_priv *priv, u32 reg, u32 mask, u32 val, u32 expect)
+{
+ u32 data;
+ int ret;
+
+ ret = msiof_update(priv, reg, mask, val);
+ if (!ret) /* no update */
+ return;
+
+ ret = readl_poll_timeout_atomic(priv->base + reg, data,
+ (data & mask) == expect, 1, 128);
+ if (ret)
+ dev_warn(priv->dev, "write timeout [0x%02x] 0x%08x / 0x%08x\n",
+ reg, data, expect);
+}
+
+static int msiof_hw_start(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ struct msiof_priv *priv = snd_soc_component_get_drvdata(component);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int is_play = msiof_is_play(substream);
+ int width = snd_pcm_format_width(runtime->format);
+ u32 val;
+
+ /*
+ * see
+ * [NOTE-CLOCK-MODE] on top of this driver
+ */
+ /*
+ * see
+ * Datasheet 109.3.6 [Transmit and Receive Procedures]
+ *
+ * TX: Fig 109.14 - Fig 109.23
+ * RX: Fig 109.15
+ */
+
+ /*
+ * Use reset_control_xx() instead of TXRST/RXRST.
+ * see
+ * [NOTE-RESET]
+ */
+ if (!priv->count)
+ reset_control_deassert(priv->reset);
+
+ priv->count++;
+
+ /*
+ * Reset errors. ignore 1st FSERR
+ *
+ * see
+ * [NOTE-FSERR]
+ */
+ priv->err_syc[substream->stream] = -1;
+ priv->err_ovf[substream->stream] =
+ priv->err_udf[substream->stream] = 0;
+
+ /* Start DMAC */
+ snd_dmaengine_pcm_trigger(substream, cmd);
+
+ /*
+ * setup both direction (Playback/Capture) in the same time.
+ * see
+ * above [NOTE-BOTH-SETTING]
+ */
+
+ /* SITMDRx */
+ val = SITMDR1_PCON | SIMDR1_SYNCAC | SIMDR1_XXSTP |
+ FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR);
+ if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
+ val |= FIELD_PREP(SIMDR1_DTDL, 1);
+
+ msiof_write(priv, SITMDR1, val);
+
+ val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
+ msiof_write(priv, SITMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
+ msiof_write(priv, SITMDR3, val);
+
+ /* SIRMDRx */
+ val = SIMDR1_SYNCAC |
+ FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_LR);
+ if (msiof_flag_has(priv, MSIOF_FLAGS_NEED_DELAY))
+ val |= FIELD_PREP(SIMDR1_DTDL, 1);
+
+ msiof_write(priv, SIRMDR1, val);
+
+ val = FIELD_PREP(SIMDR2_BITLEN1, width - 1);
+ msiof_write(priv, SIRMDR2, val | FIELD_PREP(SIMDR2_GRP, 1));
+ msiof_write(priv, SIRMDR3, val);
+
+ /* SIFCTR */
+ msiof_write(priv, SIFCTR,
+ FIELD_PREP(SIFCTR_TFWM, SIFCTR_TFWM_1) |
+ FIELD_PREP(SIFCTR_RFWM, SIFCTR_RFWM_1));
+
+ /* SIIER */
+ if (is_play)
+ val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX;
+ else
+ val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX;
+ msiof_update(priv, SIIER, val, val);
+
+ /* clear status */
+ if (is_play)
+ val = SISTR_ERR_TX;
+ else
+ val = SISTR_ERR_RX;
+ msiof_update(priv, SISTR, val, val);
+
+ /* SICTR */
+ val = SICTR_TEDG | SICTR_REDG;
+ if (is_play)
+ val |= SICTR_TXE;
+ else
+ val |= SICTR_RXE;
+ msiof_update_and_wait(priv, SICTR, val, val, val);
+
+ return 0;
+}
+
+static int msiof_hw_stop(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ struct msiof_priv *priv = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+ int is_play = msiof_is_play(substream);
+ u32 val;
+
+ /* SIIER */
+ if (is_play)
+ val = SIIER_TDREQE | SIIER_TDMAE | SISTR_ERR_TX;
+ else
+ val = SIIER_RDREQE | SIIER_RDMAE | SISTR_ERR_RX;
+ msiof_update(priv, SIIER, val, 0);
+
+ /* SICTR */
+ if (is_play)
+ val = SICTR_TXE;
+ else
+ val = SICTR_RXE;
+ msiof_update_and_wait(priv, SICTR, val, 0, 0);
+
+ /* Stop DMAC */
+ snd_dmaengine_pcm_trigger(substream, cmd);
+
+ /*
+ * Ignore 1st FSERR
+ *
+ * see
+ * [NOTE-FSERR]
+ */
+ if (priv->err_syc[substream->stream] < 0)
+ priv->err_syc[substream->stream] = 0;
+
+ /* indicate error status if exist */
+ if (priv->err_syc[substream->stream] ||
+ priv->err_ovf[substream->stream] ||
+ priv->err_udf[substream->stream])
+ dev_warn(dev, "%s: FSERR = %d, FOVF = %d, FUDF = %d\n",
+ snd_pcm_direction_name(substream->stream),
+ priv->err_syc[substream->stream],
+ priv->err_ovf[substream->stream],
+ priv->err_udf[substream->stream]);
+
+ priv->count--;
+
+ if (!priv->count)
+ reset_control_assert(priv->reset);
+
+ return 0;
+}
+
+static int msiof_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct msiof_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ /*
+ * It supports Clock/Frame Consumer Mode only
+ * see
+ * [NOTE] on top of this driver
+ */
+ case SND_SOC_DAIFMT_BC_FC:
+ break;
+ /* others are error */
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ /* it supports NB_NF only */
+ case SND_SOC_DAIFMT_NB_NF:
+ default:
+ break;
+ /* others are error */
+ case SND_SOC_DAIFMT_NB_IF:
+ case SND_SOC_DAIFMT_IB_NF:
+ case SND_SOC_DAIFMT_IB_IF:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ msiof_flag_set(priv, MSIOF_FLAGS_NEED_DELAY);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Select below from Sound Card, not auto
+ * SND_SOC_DAIFMT_CBC_CFC
+ * SND_SOC_DAIFMT_CBP_CFP
+ */
+static const u64 msiof_dai_formats = SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
+static const struct snd_soc_dai_ops msiof_dai_ops = {
+ .set_fmt = msiof_dai_set_fmt,
+ .auto_selectable_formats = &msiof_dai_formats,
+ .num_auto_selectable_formats = 1,
+};
+
+static struct snd_soc_dai_driver msiof_dai_driver = {
+ .name = "msiof-dai",
+ .playback = {
+ .rates = MSIOF_RATES,
+ .formats = MSIOF_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = MSIOF_RATES,
+ .formats = MSIOF_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = &msiof_dai_ops,
+ .symmetric_rate = 1,
+ .symmetric_channels = 1,
+ .symmetric_sample_bits = 1,
+};
+
+static struct snd_pcm_hardware msiof_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .buffer_bytes_max = 64 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 32,
+ .fifo_size = 64,
+};
+
+static int msiof_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct device *dev = component->dev;
+ struct dma_chan *chan;
+ static const char * const dma_names[] = {"rx", "tx"};
+ int is_play = msiof_is_play(substream);
+ int ret;
+
+ chan = of_dma_request_slave_channel(dev->of_node, dma_names[is_play]);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+
+ ret = snd_dmaengine_pcm_open(substream, chan);
+ if (ret < 0)
+ goto open_err_dma;
+
+ snd_soc_set_runtime_hwparams(substream, &msiof_pcm_hardware);
+
+ ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+open_err_dma:
+ if (ret < 0)
+ dma_release_channel(chan);
+
+ return ret;
+}
+
+static int msiof_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ return snd_dmaengine_pcm_close_release_chan(substream);
+}
+
+static snd_pcm_uframes_t msiof_pointer(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ return snd_dmaengine_pcm_pointer(substream);
+}
+
+#define PREALLOC_BUFFER (32 * 1024)
+#define PREALLOC_BUFFER_MAX (32 * 1024)
+static int msiof_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+ rtd->card->snd_card->dev,
+ PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+ return 0;
+}
+
+static int msiof_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ struct device *dev = component->dev;
+ struct msiof_priv *priv = dev_get_drvdata(dev);
+ int ret = -EINVAL;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ priv->substream[substream->stream] = substream;
+ fallthrough;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = msiof_hw_start(component, substream, cmd);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ priv->substream[substream->stream] = NULL;
+ fallthrough;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ret = msiof_hw_stop(component, substream, cmd);
+ break;
+ }
+
+ return ret;
+}
+
+static int msiof_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct msiof_priv *priv = dev_get_drvdata(component->dev);
+ struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+ struct dma_slave_config cfg = {};
+ int ret;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ ret = snd_hwparams_to_dma_slave_config(substream, params, &cfg);
+ if (ret < 0)
+ return ret;
+
+ cfg.dst_addr = priv->phy_addr + SITFDR;
+ cfg.src_addr = priv->phy_addr + SIRFDR;
+
+ return dmaengine_slave_config(chan, &cfg);
+}
+
+static const struct snd_soc_component_driver msiof_component_driver = {
+ .name = "msiof",
+ .open = msiof_open,
+ .close = msiof_close,
+ .pointer = msiof_pointer,
+ .pcm_construct = msiof_new,
+ .trigger = msiof_trigger,
+ .hw_params = msiof_hw_params,
+};
+
+static irqreturn_t msiof_interrupt(int irq, void *data)
+{
+ struct msiof_priv *priv = data;
+ struct snd_pcm_substream *substream;
+ u32 sistr;
+
+ scoped_guard(spinlock, &priv->lock) {
+ sistr = msiof_read(priv, SISTR);
+ msiof_write(priv, SISTR, SISTR_ERR_TX | SISTR_ERR_RX);
+ }
+
+ /* overflow/underflow error */
+ substream = priv->substream[SNDRV_PCM_STREAM_PLAYBACK];
+ if (substream && (sistr & SISTR_ERR_TX)) {
+ // snd_pcm_stop_xrun(substream);
+ if (sistr & SISTR_TFSERR)
+ priv->err_syc[SNDRV_PCM_STREAM_PLAYBACK]++;
+ if (sistr & SISTR_TFOVF)
+ priv->err_ovf[SNDRV_PCM_STREAM_PLAYBACK]++;
+ if (sistr & SISTR_TFUDF)
+ priv->err_udf[SNDRV_PCM_STREAM_PLAYBACK]++;
+ }
+
+ substream = priv->substream[SNDRV_PCM_STREAM_CAPTURE];
+ if (substream && (sistr & SISTR_ERR_RX)) {
+ // snd_pcm_stop_xrun(substream);
+ if (sistr & SISTR_RFSERR)
+ priv->err_syc[SNDRV_PCM_STREAM_CAPTURE]++;
+ if (sistr & SISTR_RFOVF)
+ priv->err_ovf[SNDRV_PCM_STREAM_CAPTURE]++;
+ if (sistr & SISTR_RFUDF)
+ priv->err_udf[SNDRV_PCM_STREAM_CAPTURE]++;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int msiof_probe(struct platform_device *pdev)
+{
+ struct msiof_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int irq, ret;
+
+ /* Check MSIOF as Sound mode or SPI mode */
+ struct device_node *port __free(device_node) = of_graph_get_next_port(dev->of_node, NULL);
+ if (!port)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return irq;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+
+ reset_control_assert(priv->reset);
+
+ ret = devm_request_irq(dev, irq, msiof_interrupt, 0, dev_name(dev), priv);
+ if (ret)
+ return ret;
+
+ priv->dev = dev;
+ priv->phy_addr = res->start;
+ priv->count = 0;
+
+ spin_lock_init(&priv->lock);
+ platform_set_drvdata(pdev, priv);
+
+ devm_pm_runtime_enable(dev);
+
+ ret = devm_snd_soc_register_component(dev, &msiof_component_driver,
+ &msiof_dai_driver, 1);
+
+ return ret;
+}
+
+static const struct of_device_id msiof_of_match[] = {
+ { .compatible = "renesas,rcar-gen4-msiof", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, msiof_of_match);
+
+static struct platform_driver msiof_driver = {
+ .driver = {
+ .name = "msiof-pcm-audio",
+ .of_match_table = msiof_of_match,
+ },
+ .probe = msiof_probe,
+};
+module_platform_driver(msiof_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car MSIOF I2S audio driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/renesas/rcar/rsnd.h
index 239705d52517..04c70690f7a2 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/renesas/rcar/rsnd.h
@@ -14,28 +14,17 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_graph.h>
-#include <linux/of_irq.h>
+#include <linux/of.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#define RSND_GEN1_SRU 0
-#define RSND_GEN1_ADG 1
-#define RSND_GEN1_SSI 2
-
-#define RSND_GEN2_SCU 0
-#define RSND_GEN2_ADG 1
-#define RSND_GEN2_SSIU 2
-#define RSND_GEN2_SSI 3
-
-#define RSND_GEN4_ADG 0
-#define RSND_GEN4_SSIU 1
-#define RSND_GEN4_SSI 2
-#define RSND_GEN4_SDMC 3
-
+#define RSND_BASE_ADG 0
+#define RSND_BASE_SSI 1
+#define RSND_BASE_SSIU 2
+#define RSND_BASE_SCU 3 // for Gen2/Gen3
+#define RSND_BASE_SDMC 3 // for Gen4 reuse
#define RSND_BASE_MAX 4
/*
@@ -202,7 +191,6 @@ enum rsnd_reg {
SSI_SYS_INT_ENABLE5,
SSI_SYS_INT_ENABLE6,
SSI_SYS_INT_ENABLE7,
- SSI_BUSIF,
HDMI0_SEL,
HDMI1_SEL,
SSI9_BUSIF0_MODE,
@@ -545,6 +533,7 @@ struct rsnd_dai {
struct rsnd_dai_stream capture;
struct rsnd_priv *priv;
struct snd_pcm_hw_constraint_list constraint;
+ struct of_phandle_args dai_args;
int max_channels; /* 2ch - 16ch */
int ssi_lane; /* 1lane - 4lane */
@@ -587,7 +576,6 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
#define rsnd_rdai_width_get(rdai) \
rsnd_rdai_width_ctrl(rdai, 0)
int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
-void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
enum rsnd_mod_type type);
@@ -620,7 +608,7 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
struct rsnd_dai_stream *io);
#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1)
#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0)
-void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
+int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m);
/*
@@ -702,6 +690,9 @@ struct rsnd_priv {
struct snd_soc_dai_driver *daidrv;
struct rsnd_dai *rdai;
int rdai_nr;
+
+#define RSND_MAX_COMPONENT 3
+ int component_dais[RSND_MAX_COMPONENT];
};
#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
@@ -711,7 +702,7 @@ struct rsnd_priv {
#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4)
-#define rsnd_is_e3(priv) (((priv)->flags & \
+#define rsnd_is_gen3_e3(priv) (((priv)->flags & \
(RSND_GEN_MASK | RSND_SOC_MASK)) == \
(RSND_GEN3 | RSND_SOC_E))
@@ -751,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,
@@ -879,15 +869,6 @@ void rsnd_cmd_remove(struct rsnd_priv *priv);
int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
-#ifdef DEBUG
-#define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI)
-#define rsnd_mod_confirm_src(msrc) rsnd_mod_make_sure(msrc, RSND_MOD_SRC)
-#define rsnd_mod_confirm_dvc(mdvc) rsnd_mod_make_sure(mdvc, RSND_MOD_DVC)
-#else
-#define rsnd_mod_confirm_ssi(mssi)
-#define rsnd_mod_confirm_src(msrc)
-#define rsnd_mod_confirm_dvc(mdvc)
-#endif
/*
* If you don't need interrupt status debug message,
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/renesas/rcar/src.c
index f832165e46bc..6a3dbc84f474 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/renesas/rcar/src.c
@@ -22,6 +22,7 @@
* #define RSND_DEBUG_NO_IRQ_STATUS 1
*/
+#include <linux/of_irq.h>
#include "rsnd.h"
#define SRC_NAME "src"
@@ -34,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;
};
@@ -99,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);
@@ -200,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;
@@ -244,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;
@@ -309,7 +360,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
/*
* E3 need to overwrite
*/
- if (rsnd_is_e3(priv))
+ if (rsnd_is_gen3_e3(priv))
switch (rsnd_mod_id(mod)) {
case 0:
case 4:
@@ -334,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]);
@@ -347,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:
@@ -466,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)
@@ -474,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);
@@ -492,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;
}
@@ -503,19 +558,16 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
bool stop = false;
- spin_lock(&priv->lock);
-
- /* ignore all cases if not working */
- if (!rsnd_io_is_working(io))
- goto rsnd_src_interrupt_out;
+ scoped_guard(spinlock, &priv->lock) {
+ /* ignore all cases if not working */
+ if (!rsnd_io_is_working(io))
+ break;
- if (rsnd_src_error_occurred(mod))
- stop = true;
+ if (rsnd_src_error_occurred(mod))
+ stop = true;
- rsnd_src_status_clear(mod);
-rsnd_src_interrupt_out:
-
- spin_unlock(&priv->lock);
+ rsnd_src_status_clear(mod);
+ }
if (stop)
snd_pcm_stop_xrun(io->substream);
@@ -530,6 +582,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)
@@ -584,7 +652,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;
@@ -593,7 +661,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);
@@ -605,13 +673,13 @@ static void rsnd_src_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
rsnd_mod_id(mod) * 0x20, 0x20);
seq_puts(m, "\n");
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x1c0, 0x20);
seq_puts(m, "\n");
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
0x200 + rsnd_mod_id(mod) * 0x40, 0x40);
}
#define DEBUG_INFO .debug_info = rsnd_src_debug_info
@@ -644,17 +712,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
int rsnd_src_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_src *src;
struct clk *clk;
char name[RSND_SRC_NAME_SIZE];
int i, nr, ret;
- /* This driver doesn't support Gen1 at this point */
- if (rsnd_is_gen1(priv))
- return 0;
-
node = rsnd_src_of_node(priv);
if (!node)
return 0; /* not used is not error */
@@ -675,14 +738,13 @@ int rsnd_src_probe(struct rsnd_priv *priv)
priv->src = src;
i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
if (!of_device_is_available(np))
goto skip;
i = rsnd_node_fixed_index(dev, np, SRC_NAME, i);
if (i < 0) {
ret = -EINVAL;
- of_node_put(np);
goto rsnd_src_probe_done;
}
@@ -694,23 +756,19 @@ int rsnd_src_probe(struct rsnd_priv *priv)
src->irq = irq_of_parse_and_map(np, 0);
if (!src->irq) {
ret = -EINVAL;
- of_node_put(np);
goto rsnd_src_probe_done;
}
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(np);
goto rsnd_src_probe_done;
}
ret = rsnd_mod_init(priv, rsnd_mod_get(src),
&rsnd_src_ops, clk, RSND_MOD_SRC, i);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto rsnd_src_probe_done;
- }
skip:
i++;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c
index 690ac0d6ef41..0420041e282c 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/renesas/rcar/ssi.c
@@ -17,6 +17,8 @@
*/
#include <sound/simple_card_utils.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/delay.h>
#include "rsnd.h"
#define RSND_SSI_NAME_SIZE 16
@@ -334,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;
}
@@ -677,34 +680,33 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
bool elapsed = false;
bool stop = false;
- spin_lock(&priv->lock);
+ scoped_guard(spinlock, &priv->lock) {
- /* ignore all cases if not working */
- if (!rsnd_io_is_working(io))
- goto rsnd_ssi_interrupt_out;
+ /* ignore all cases if not working */
+ if (!rsnd_io_is_working(io))
+ break;
- status = rsnd_ssi_status_get(mod);
+ status = rsnd_ssi_status_get(mod);
- /* PIO only */
- if (!is_dma && (status & DIRQ))
- elapsed = rsnd_ssi_pio_interrupt(mod, io);
+ /* PIO only */
+ if (!is_dma && (status & DIRQ))
+ elapsed = rsnd_ssi_pio_interrupt(mod, io);
- /* DMA only */
- if (is_dma && (status & (UIRQ | OIRQ))) {
- rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
- rsnd_mod_name(mod), status);
+ /* DMA only */
+ if (is_dma && (status & (UIRQ | OIRQ))) {
+ rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
- stop = true;
- }
+ stop = true;
+ }
- stop |= rsnd_ssiu_busif_err_status_clear(mod);
+ stop |= rsnd_ssiu_busif_err_status_clear(mod);
- rsnd_ssi_status_clear(mod);
-rsnd_ssi_interrupt_out:
- spin_unlock(&priv->lock);
+ rsnd_ssi_status_clear(mod);
+ }
if (elapsed)
- rsnd_dai_period_elapsed(io);
+ snd_pcm_period_elapsed(io->substream);
if (stop)
snd_pcm_stop_xrun(io->substream);
@@ -1047,7 +1049,7 @@ static void rsnd_ssi_debug_info(struct seq_file *m,
seq_printf(m, "chan: %d\n", ssi->chan);
seq_printf(m, "user: %d\n", ssi->usrcnt);
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSI,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSI,
rsnd_mod_id(mod) * 0x40, 0x40);
}
#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info
@@ -1112,7 +1114,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node;
- struct device_node *np;
int i;
node = rsnd_ssi_of_node(priv);
@@ -1120,14 +1121,12 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
return;
i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
struct rsnd_mod *mod;
i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
break;
- }
mod = rsnd_ssi_mod_get(priv, i);
@@ -1160,7 +1159,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
int rsnd_ssi_probe(struct rsnd_priv *priv)
{
struct device_node *node;
- struct device_node *np;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod_ops *ops;
struct clk *clk;
@@ -1188,14 +1186,13 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
priv->ssi_nr = nr;
i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
if (!of_device_is_available(np))
goto skip;
i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
if (i < 0) {
ret = -EINVAL;
- of_node_put(np);
goto rsnd_ssi_probe_done;
}
@@ -1207,7 +1204,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(np);
goto rsnd_ssi_probe_done;
}
@@ -1220,7 +1216,6 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
ssi->irq = irq_of_parse_and_map(np, 0);
if (!ssi->irq) {
ret = -EINVAL;
- of_node_put(np);
goto rsnd_ssi_probe_done;
}
@@ -1231,10 +1226,9 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
RSND_MOD_SSI, i);
- if (ret) {
- of_node_put(np);
+ if (ret)
goto rsnd_ssi_probe_done;
- }
+
skip:
i++;
}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/renesas/rcar/ssiu.c
index 17bd8cc86dd0..244fb833292a 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/renesas/rcar/ssiu.c
@@ -413,7 +413,7 @@ static void rsnd_ssiu_debug_info(struct seq_file *m,
struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSIU,
+ rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU,
rsnd_mod_id(mod) * 0x80, 0x80);
}
#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
@@ -478,17 +478,14 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
/* use rcar_sound,ssiu if exist */
if (node) {
- struct device_node *np;
int i = 0;
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
struct rsnd_mod *mod;
i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
- if (i < 0) {
- of_node_put(np);
+ if (i < 0)
break;
- }
mod = rsnd_ssiu_mod_get(priv, i);
@@ -512,7 +509,7 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
int rsnd_ssiu_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
- struct device_node *node;
+ struct device_node *node __free(device_node) = rsnd_ssiu_of_node(priv);
struct rsnd_ssiu *ssiu;
struct rsnd_mod_ops *ops;
const int *list = NULL;
@@ -525,7 +522,6 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
* see
* rsnd_ssiu_bufsif_to_id()
*/
- node = rsnd_ssiu_of_node(priv);
if (node)
nr = rsnd_node_count(priv, node, SSIU_NAME);
else
diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
index fe79eb90e1e5..f4dc2f68dead 100644
--- a/sound/soc/sh/rz-ssi.c
+++ b/sound/soc/renesas/rz-ssi.c
@@ -9,10 +9,11 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
+#include <sound/pcm_params.h>
#include <sound/soc.h>
/* REGISTER OFFSET */
@@ -53,6 +54,7 @@
#define SSIFCR_RIE BIT(2)
#define SSIFCR_TFRST BIT(1)
#define SSIFCR_RFRST BIT(0)
+#define SSIFCR_FIFO_RST (SSIFCR_TFRST | SSIFCR_RFRST)
#define SSIFSR_TDC_MASK 0x3f
#define SSIFSR_TDC_SHIFT 24
@@ -71,7 +73,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
@@ -84,8 +86,8 @@ struct rz_ssi_stream {
struct snd_pcm_substream *substream;
int fifo_sample_size; /* sample capacity of SSI FIFO */
int dma_buffer_pos; /* The address for the next DMA descriptor */
+ int completed_dma_buf_pos; /* The address of the last completed DMA descriptor. */
int period_counter; /* for keeping track of periods transferred */
- int sample_width;
int buffer_pos; /* current frame position in the buffer */
int running; /* 0=stopped, 1=running */
@@ -99,7 +101,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;
@@ -131,6 +132,20 @@ struct rz_ssi_priv {
bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */
bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */
bool dma_rt;
+
+ struct {
+ bool tx_active;
+ bool rx_active;
+ bool one_stream_triggered;
+ } dup;
+
+ /* Full duplex communication support */
+ struct {
+ unsigned int rate;
+ unsigned int channels;
+ unsigned int sample_width;
+ unsigned int sample_bits;
+ } hw_params_cache;
};
static void rz_ssi_dma_complete(void *data);
@@ -155,16 +170,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 = asoc_substream_to_rtd(substream);
-
- return asoc_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;
}
@@ -189,34 +195,31 @@ static void rz_ssi_set_substream(struct rz_ssi_stream *strm,
struct snd_pcm_substream *substream)
{
struct rz_ssi_priv *ssi = strm->priv;
- unsigned long flags;
- spin_lock_irqsave(&ssi->lock, flags);
+ guard(spinlock_irqsave)(&ssi->lock);
+
strm->substream = substream;
- spin_unlock_irqrestore(&ssi->lock, flags);
}
static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi,
struct rz_ssi_stream *strm)
{
- unsigned long flags;
- bool ret;
+ guard(spinlock_irqsave)(&ssi->lock);
- spin_lock_irqsave(&ssi->lock, flags);
- ret = strm->substream && strm->substream->runtime;
- spin_unlock_irqrestore(&ssi->lock, flags);
+ return strm->substream && strm->substream->runtime;
+}
- return ret;
+static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm)
+{
+ return strm->substream && strm->running;
}
static void rz_ssi_stream_init(struct rz_ssi_stream *strm,
struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
rz_ssi_set_substream(strm, substream);
- strm->sample_width = samples_to_bytes(runtime, 1);
strm->dma_buffer_pos = 0;
+ strm->completed_dma_buf_pos = 0;
strm->period_counter = 0;
strm->buffer_pos = 0;
@@ -231,22 +234,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;
@@ -298,19 +300,51 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
ssicr |= SSICR_CKDV(clk_ckdv);
ssicr |= SSICR_DWL(1) | SSICR_SWL(3);
rz_ssi_reg_writel(ssi, SSICR, ssicr);
- rz_ssi_reg_writel(ssi, SSIFCR,
- (SSIFCR_AUCKE | SSIFCR_TFRST | SSIFCR_RFRST));
+ rz_ssi_reg_writel(ssi, SSIFCR, SSIFCR_AUCKE | SSIFCR_FIFO_RST);
return 0;
}
+static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
+{
+ u32 tmp;
+ int ret;
+
+ /* Disable irqs */
+ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
+ SSICR_RUIEN | SSICR_ROIEN, 0);
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0);
+
+ /* Clear all error flags */
+ rz_ssi_reg_mask_setl(ssi, SSISR,
+ (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
+ SSISR_RUIRQ), 0);
+
+ /* Wait for idle */
+ 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);
+}
+
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;
+ is_full_duplex = ssi->dup.tx_active && ssi->dup.rx_active;
ssicr = rz_ssi_reg_readl(ssi, SSICR);
- ssifcr = rz_ssi_reg_readl(ssi, SSIFCR) & ~0xF;
+ ssifcr = rz_ssi_reg_readl(ssi, SSIFCR);
+ if (!is_full_duplex) {
+ ssifcr &= ~0xF;
+ } else if (ssi->dup.one_stream_triggered) {
+ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
+ rz_ssi_set_idle(ssi);
+ ssifcr &= ~SSIFCR_FIFO_RST;
+ }
/* FIFO interrupt thresholds */
if (rz_ssi_is_dma_enabled(ssi))
@@ -323,10 +357,14 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
/* enable IRQ */
if (is_play) {
ssicr |= SSICR_TUIEN | SSICR_TOIEN;
- ssifcr |= SSIFCR_TIE | SSIFCR_RFRST;
+ ssifcr |= SSIFCR_TIE;
+ if (!is_full_duplex)
+ ssifcr |= SSIFCR_RFRST;
} else {
ssicr |= SSICR_RUIEN | SSICR_ROIEN;
- ssifcr |= SSIFCR_RIE | SSIFCR_TFRST;
+ ssifcr |= SSIFCR_RIE;
+ if (!is_full_duplex)
+ ssifcr |= SSIFCR_TFRST;
}
rz_ssi_reg_writel(ssi, SSICR, ssicr);
@@ -338,49 +376,49 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
SSISR_RUIRQ), 0);
strm->running = 1;
- ssicr |= is_play ? SSICR_TEN : SSICR_REN;
- rz_ssi_reg_writel(ssi, SSICR, ssicr);
+ if (!is_full_duplex) {
+ ssicr |= is_play ? SSICR_TEN : SSICR_REN;
+ rz_ssi_reg_writel(ssi, SSICR, ssicr);
+ } else if (ssi->dup.one_stream_triggered) {
+ ssicr |= SSICR_TEN | SSICR_REN;
+ rz_ssi_reg_writel(ssi, SSICR, ssicr);
+ ssi->dup.one_stream_triggered = false;
+ } else {
+ ssi->dup.one_stream_triggered = true;
+ }
return 0;
}
-static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
+static int rz_ssi_swreset(struct rz_ssi_priv *ssi)
{
- int timeout;
+ 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;
+ if (rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture))
+ return 0;
+
/* Disable TX/RX */
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);
-
- /* Disable irqs */
- rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
- SSICR_RUIEN | SSICR_ROIEN, 0);
- rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0);
-
- /* Clear all error flags */
- rz_ssi_reg_mask_setl(ssi, SSISR,
- (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
- SSISR_RUIRQ), 0);
-
- /* Wait for idle */
- timeout = 100;
- while (--timeout) {
- if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ)
- break;
- udelay(1);
+ 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);
}
- if (!timeout)
- dev_info(ssi->dev, "timeout waiting for SSI idle\n");
-
- /* Hold FIFOs in reset */
- rz_ssi_reg_mask_setl(ssi, SSIFCR, 0,
- SSIFCR_TFRST | SSIFCR_RFRST);
+ rz_ssi_set_idle(ssi);
return 0;
}
@@ -407,6 +445,10 @@ static void rz_ssi_pointer_update(struct rz_ssi_stream *strm, int frames)
snd_pcm_period_elapsed(strm->substream);
strm->period_counter = current_period;
}
+
+ strm->completed_dma_buf_pos += runtime->period_size;
+ if (strm->completed_dma_buf_pos >= runtime->buffer_size)
+ strm->completed_dma_buf_pos = 0;
}
static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
@@ -485,6 +527,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)) {
@@ -513,66 +557,90 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
static irqreturn_t rz_ssi_interrupt(int irq, void *data)
{
- struct rz_ssi_stream *strm = NULL;
+ struct rz_ssi_stream *strm_playback = NULL;
+ struct rz_ssi_stream *strm_capture = NULL;
struct rz_ssi_priv *ssi = data;
u32 ssisr = rz_ssi_reg_readl(ssi, SSISR);
if (ssi->playback.substream)
- strm = &ssi->playback;
- else if (ssi->capture.substream)
- strm = &ssi->capture;
- else
+ strm_playback = &ssi->playback;
+ if (ssi->capture.substream)
+ strm_capture = &ssi->capture;
+
+ if (!strm_playback && !strm_capture)
return IRQ_HANDLED; /* Left over TX/RX interrupt */
if (irq == ssi->irq_int) { /* error or idle */
- if (ssisr & SSISR_TUIRQ)
- strm->uerr_num++;
- if (ssisr & SSISR_TOIRQ)
- strm->oerr_num++;
- if (ssisr & SSISR_RUIRQ)
- strm->uerr_num++;
- if (ssisr & SSISR_ROIRQ)
- strm->oerr_num++;
-
- if (ssisr & (SSISR_TUIRQ | SSISR_TOIRQ | SSISR_RUIRQ |
- SSISR_ROIRQ)) {
- /* Error handling */
- /* You must reset (stop/restart) after each interrupt */
- rz_ssi_stop(ssi, strm);
-
- /* Clear all flags */
- rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ |
- SSISR_TUIRQ | SSISR_ROIRQ |
- SSISR_RUIRQ, 0);
-
- /* Add/remove more data */
- strm->transfer(ssi, strm);
-
- /* Resume */
- rz_ssi_start(ssi, strm);
+ bool is_stopped = false;
+ int i, count;
+
+ if (rz_ssi_is_dma_enabled(ssi))
+ count = 4;
+ else
+ count = 1;
+
+ if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ))
+ is_stopped = true;
+
+ if (ssi->capture.substream && is_stopped) {
+ if (ssisr & SSISR_RUIRQ)
+ strm_capture->uerr_num++;
+ if (ssisr & SSISR_ROIRQ)
+ strm_capture->oerr_num++;
+
+ rz_ssi_stop(ssi, strm_capture);
+ }
+
+ if (ssi->playback.substream && is_stopped) {
+ if (ssisr & SSISR_TUIRQ)
+ strm_playback->uerr_num++;
+ if (ssisr & SSISR_TOIRQ)
+ strm_playback->oerr_num++;
+
+ rz_ssi_stop(ssi, strm_playback);
+ }
+
+ /* Clear all flags */
+ rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ |
+ SSISR_ROIRQ | SSISR_RUIRQ, 0);
+
+ /* Add/remove more data */
+ if (ssi->capture.substream && is_stopped) {
+ for (i = 0; i < count; i++)
+ strm_capture->transfer(ssi, strm_capture);
}
+
+ if (ssi->playback.substream && is_stopped) {
+ for (i = 0; i < count; i++)
+ strm_playback->transfer(ssi, strm_playback);
+ }
+
+ /* Resume */
+ if (ssi->playback.substream && is_stopped)
+ rz_ssi_start(ssi, &ssi->playback);
+ if (ssi->capture.substream && is_stopped)
+ rz_ssi_start(ssi, &ssi->capture);
}
- if (!strm->running)
+ if (!rz_ssi_is_stream_running(&ssi->playback) &&
+ !rz_ssi_is_stream_running(&ssi->capture))
return IRQ_HANDLED;
/* tx data empty */
- if (irq == ssi->irq_tx)
- strm->transfer(ssi, &ssi->playback);
+ if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback))
+ strm_playback->transfer(ssi, &ssi->playback);
/* rx data full */
- if (irq == ssi->irq_rx) {
- strm->transfer(ssi, &ssi->capture);
+ if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) {
+ strm_capture->transfer(ssi, &ssi->capture);
rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
}
if (irq == ssi->irq_rt) {
- struct snd_pcm_substream *substream = strm->substream;
-
- if (rz_ssi_stream_is_play(ssi, substream)) {
- strm->transfer(ssi, &ssi->playback);
+ if (ssi->playback.substream) {
+ strm_playback->transfer(ssi, &ssi->playback);
} else {
- strm->transfer(ssi, &ssi->capture);
+ strm_capture->transfer(ssi, &ssi->capture);
rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
}
}
@@ -618,7 +686,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;
@@ -722,6 +790,26 @@ no_dma:
return -ENODEV;
}
+static int rz_ssi_trigger_resume(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
+{
+ struct snd_pcm_substream *substream = strm->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+
+ strm->dma_buffer_pos = strm->completed_dma_buf_pos + runtime->period_size;
+
+ 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 int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
@@ -730,18 +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 */
- 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, strm);
+ 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 */
@@ -764,6 +855,11 @@ 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);
+ break;
+
case SNDRV_PCM_TRIGGER_STOP:
rz_ssi_stop(ssi, strm);
rz_ssi_stream_quit(ssi, strm);
@@ -825,6 +921,55 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int rz_ssi_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ssi->dup.tx_active = true;
+ else
+ ssi->dup.rx_active = true;
+
+ return 0;
+}
+
+static void rz_ssi_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ssi->dup.tx_active = false;
+ else
+ ssi->dup.rx_active = false;
+}
+
+static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
+ unsigned int channels,
+ unsigned int sample_width,
+ unsigned int sample_bits)
+{
+ if (ssi->hw_params_cache.rate != rate ||
+ ssi->hw_params_cache.channels != channels ||
+ ssi->hw_params_cache.sample_width != sample_width ||
+ ssi->hw_params_cache.sample_bits != sample_bits)
+ return false;
+
+ return true;
+}
+
+static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
+ unsigned int channels,
+ unsigned int sample_width,
+ unsigned int sample_bits)
+{
+ ssi->hw_params_cache.rate = rate;
+ ssi->hw_params_cache.channels = channels;
+ ssi->hw_params_cache.sample_width = sample_width;
+ ssi->hw_params_cache.sample_bits = sample_bits;
+}
+
static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -832,7 +977,10 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
unsigned int sample_bits = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+ unsigned int sample_width = params_width(params);
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",
@@ -846,11 +994,27 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- return rz_ssi_clk_setup(ssi, params_rate(params),
- params_channels(params));
+ if (rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture)) {
+ if (rz_ssi_is_valid_hw_params(ssi, rate, channels, sample_width, sample_bits))
+ return 0;
+
+ dev_err(ssi->dev, "Full duplex needs same HW params\n");
+ return -EINVAL;
+ }
+
+ rz_ssi_cache_hw_params(ssi, rate, channels, sample_width, sample_bits);
+
+ ret = rz_ssi_swreset(ssi);
+ if (ret)
+ return ret;
+
+ return rz_ssi_clk_setup(ssi, rate, channels);
}
static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
+ .startup = rz_ssi_startup,
+ .shutdown = rz_ssi_shutdown,
.trigger = rz_ssi_dai_trigger,
.set_fmt = rz_ssi_dai_set_fmt,
.hw_params = rz_ssi_dai_hw_params,
@@ -859,7 +1023,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,
@@ -882,7 +1047,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);
@@ -927,37 +1093,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");
@@ -970,13 +1136,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;
}
@@ -985,21 +1151,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)) {
@@ -1011,12 +1176,12 @@ 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,
- "irq request error (dma_tx)\n");
+ return dev_err_probe(dev, ret,
+ "irq request error (dma_rt)\n");
} else {
if (ssi->irq_tx < 0)
return ssi->irq_tx;
@@ -1024,52 +1189,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;
@@ -1081,8 +1242,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);
}
@@ -1092,13 +1251,33 @@ 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)
+ NOIRQ_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_new = rz_ssi_remove,
+ .remove = rz_ssi_remove,
};
module_platform_driver(rz_ssi_driver);
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/renesas/sh7760-ac97.c
index d267243a159b..d267243a159b 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/renesas/sh7760-ac97.c
diff --git a/sound/soc/sh/siu.h b/sound/soc/renesas/siu.h
index a675c36fc9d9..a675c36fc9d9 100644
--- a/sound/soc/sh/siu.h
+++ b/sound/soc/renesas/siu.h
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/renesas/siu_dai.c
index d0b5c543fd2f..7e771a164a80 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/renesas/siu_dai.c
@@ -788,7 +788,7 @@ static struct platform_driver siu_driver = {
.name = "siu-pcm-audio",
},
.probe = siu_probe,
- .remove_new = siu_remove,
+ .remove = siu_remove,
};
module_platform_driver(siu_driver);
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/renesas/siu_pcm.c
index f15ff36e7934..f15ff36e7934 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/renesas/siu_pcm.c
diff --git a/sound/soc/sh/ssi.c b/sound/soc/renesas/ssi.c
index 96cf523c2273..96cf523c2273 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/renesas/ssi.c
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f98a2fa85edd..bd210fafe9fe 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -1,15 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
-config SND_SOC_ROCKCHIP
- tristate "ASoC support for Rockchip"
+menu "Rockchip"
depends on COMPILE_TEST || ARCH_ROCKCHIP
- help
- Say Y or M if you want to add support for codecs attached to
- the Rockchip SoCs' Audio interfaces. You will also need to
- select the audio interfaces to support below.
+ depends on HAVE_CLK
config SND_SOC_ROCKCHIP_I2S
tristate "Rockchip I2S Device Driver"
- depends on HAVE_CLK && SND_SOC_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for I2S driver for
@@ -18,7 +13,6 @@ config SND_SOC_ROCKCHIP_I2S
config SND_SOC_ROCKCHIP_I2S_TDM
tristate "Rockchip I2S/TDM Device Driver"
- depends on HAVE_CLK && SND_SOC_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for the I2S/TDM driver for
@@ -29,7 +23,6 @@ config SND_SOC_ROCKCHIP_I2S_TDM
config SND_SOC_ROCKCHIP_PDM
tristate "Rockchip PDM Controller Driver"
- depends on HAVE_CLK && SND_SOC_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
select RATIONAL
help
@@ -37,9 +30,17 @@ config SND_SOC_ROCKCHIP_PDM
Rockchip PDM Controller. The Controller supports up to maximum of
8 channels record.
+config SND_SOC_ROCKCHIP_SAI
+ tristate "Rockchip SAI Controller Driver"
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for the Rockchip Serial Audio
+ Interface controller found on Rockchip SoCs such as the RK3576. The
+ controller may support both playback and recording, with up to 4 lanes
+ for each and up to 128 channels per lane in TDM mode.
+
config SND_SOC_ROCKCHIP_SPDIF
tristate "Rockchip SPDIF Device Driver"
- depends on HAVE_CLK && SND_SOC_ROCKCHIP
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for SPDIF driver for
@@ -47,7 +48,7 @@ config SND_SOC_ROCKCHIP_SPDIF
config SND_SOC_ROCKCHIP_MAX98090
tristate "ASoC support for Rockchip boards using a MAX98090 codec"
- depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK
+ depends on I2C && GPIOLIB
select SND_SOC_ROCKCHIP_I2S
select SND_SOC_MAX98090
select SND_SOC_TS3A227E
@@ -58,7 +59,7 @@ config SND_SOC_ROCKCHIP_MAX98090
config SND_SOC_ROCKCHIP_RT5645
tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec"
- depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK
+ depends on I2C && GPIOLIB
select SND_SOC_ROCKCHIP_I2S
select SND_SOC_RT5645
help
@@ -67,7 +68,7 @@ config SND_SOC_ROCKCHIP_RT5645
config SND_SOC_RK3288_HDMI_ANALOG
tristate "ASoC support multiple codecs for Rockchip RK3288 boards"
- depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK
+ depends on I2C && GPIOLIB
select SND_SOC_ROCKCHIP_I2S
select SND_SOC_HDMI_CODEC
select SND_SOC_ES8328_I2C
@@ -79,7 +80,7 @@ config SND_SOC_RK3288_HDMI_ANALOG
config SND_SOC_RK3399_GRU_SOUND
tristate "ASoC support multiple codecs for Rockchip RK3399 GRU boards"
- depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK && SPI
+ depends on I2C && GPIOLIB && SPI
select SND_SOC_ROCKCHIP_I2S
select SND_SOC_MAX98357A
select SND_SOC_RT5514
@@ -90,3 +91,5 @@ config SND_SOC_RK3399_GRU_SOUND
help
Say Y or M here if you want to add support multiple codecs for SoC
audio on Rockchip RK3399 GRU boards.
+
+endmenu
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index 30c57c0d7660..af6dc1165347 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -1,19 +1,21 @@
# SPDX-License-Identifier: GPL-2.0
# ROCKCHIP Platform Support
-snd-soc-rockchip-i2s-objs := rockchip_i2s.o
-snd-soc-rockchip-i2s-tdm-objs := rockchip_i2s_tdm.o
-snd-soc-rockchip-pdm-objs := rockchip_pdm.o
-snd-soc-rockchip-spdif-objs := rockchip_spdif.o
+snd-soc-rockchip-i2s-y := rockchip_i2s.o
+snd-soc-rockchip-i2s-tdm-y := rockchip_i2s_tdm.o
+snd-soc-rockchip-pdm-y := rockchip_pdm.o
+snd-soc-rockchip-sai-y := rockchip_sai.o
+snd-soc-rockchip-spdif-y := rockchip_spdif.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_PDM) += snd-soc-rockchip-pdm.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_SAI) += snd-soc-rockchip-sai.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S_TDM) += snd-soc-rockchip-i2s-tdm.o
-snd-soc-rockchip-max98090-objs := rockchip_max98090.o
-snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
-snd-soc-rk3288-hdmi-analog-objs := rk3288_hdmi_analog.o
-snd-soc-rk3399-gru-sound-objs := rk3399_gru_sound.o
+snd-soc-rockchip-max98090-y := rockchip_max98090.o
+snd-soc-rockchip-rt5645-y := rockchip_rt5645.o
+snd-soc-rk3288-hdmi-analog-y := rk3288_hdmi_analog.o
+snd-soc-rk3399-gru-sound-y := rk3399_gru_sound.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index 0c6bd9a019db..cf642a23c38a 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -12,8 +12,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -26,20 +25,17 @@
#define DRV_NAME "rk3288-snd-hdmi-analog"
struct rk_drvdata {
- int gpio_hp_en;
- int gpio_hp_det;
+ struct gpio_desc *gpio_hp_en;
};
static int rk_hp_power(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct rk_drvdata *machine = snd_soc_card_get_drvdata(w->dapm->card);
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct rk_drvdata *machine = snd_soc_card_get_drvdata(card);
- if (!gpio_is_valid(machine->gpio_hp_en))
- return 0;
-
- gpio_set_value_cansleep(machine->gpio_hp_en,
- SND_SOC_DAPM_EVENT_ON(event));
+ gpiod_set_value_cansleep(machine->gpio_hp_en,
+ SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
@@ -66,9 +62,9 @@ static int rk_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int mclk;
switch (params_rate(params)) {
@@ -113,22 +109,23 @@ static int rk_hw_params(struct snd_pcm_substream *substream,
}
static struct snd_soc_jack_gpio rk_hp_jack_gpio = {
- .name = "Headphone detection",
+ .name = "rockchip,hp-det",
.report = SND_JACK_HEADPHONE,
.debounce_time = 150
};
static int rk_init(struct snd_soc_pcm_runtime *runtime)
{
- struct rk_drvdata *machine = snd_soc_card_get_drvdata(runtime->card);
+ struct snd_soc_card *card = runtime->card;
+ struct device *dev = card->dev;
- /* Enable Headset Jack detection */
- if (gpio_is_valid(machine->gpio_hp_det)) {
+ /* Enable optional Headset Jack detection */
+ if (of_property_present(dev->of_node, "rockchip,hp-det-gpios")) {
+ rk_hp_jack_gpio.gpiod_dev = dev;
snd_soc_card_jack_new_pins(runtime->card, "Headphone Jack",
SND_JACK_HEADPHONE, &headphone_jack,
headphone_jack_pins,
ARRAY_SIZE(headphone_jack_pins));
- rk_hp_jack_gpio.gpio = machine->gpio_hp_det;
snd_soc_jack_add_gpios(&headphone_jack, 1, &rk_hp_jack_gpio);
}
@@ -152,7 +149,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),
};
@@ -182,24 +179,10 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- machine->gpio_hp_det = of_get_named_gpio(np,
- "rockchip,hp-det-gpios", 0);
- if (!gpio_is_valid(machine->gpio_hp_det) && machine->gpio_hp_det != -ENODEV)
- return machine->gpio_hp_det;
-
- machine->gpio_hp_en = of_get_named_gpio(np,
- "rockchip,hp-en-gpios", 0);
- if (!gpio_is_valid(machine->gpio_hp_en) && machine->gpio_hp_en != -ENODEV)
- return machine->gpio_hp_en;
-
- if (gpio_is_valid(machine->gpio_hp_en)) {
- ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_en,
- GPIOF_OUT_INIT_LOW, "hp_en");
- if (ret) {
- dev_err(card->dev, "cannot get hp_en gpio\n");
- return ret;
- }
- }
+ machine->gpio_hp_en = devm_gpiod_get_optional(&pdev->dev, "rockchip,hp-en", GPIOD_OUT_LOW);
+ if (IS_ERR(machine->gpio_hp_en))
+ return PTR_ERR(machine->gpio_hp_en);
+ gpiod_set_consumer_name(machine->gpio_hp_en, "hp_en");
ret = snd_soc_of_parse_card_name(card, "rockchip,model");
if (ret) {
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 5e52e9d60d44..c8137e8883c4 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -8,8 +8,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
@@ -41,13 +39,17 @@ static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
-
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_LINE("HDMI", NULL),
};
@@ -56,6 +58,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
SOC_DAPM_PIN_SWITCH("HDMI"),
};
@@ -63,13 +66,13 @@ static const struct snd_kcontrol_new rockchip_controls[] = {
static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int mclk;
int ret;
mclk = params_rate(params) * SOUND_FS;
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
if (ret) {
dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
__func__, mclk, ret);
@@ -82,9 +85,9 @@ static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substrea
static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int mclk;
int ret;
@@ -114,9 +117,9 @@ static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int mclk, ret;
/* in bypass mode, the mclk has to be one of the frequencies below */
@@ -167,7 +170,7 @@ static struct snd_soc_jack cdn_dp_card_jack;
static int rockchip_sound_cdndp_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
struct snd_soc_card *card = rtd->card;
int ret;
@@ -184,8 +187,8 @@ static int rockchip_sound_cdndp_init(struct snd_soc_pcm_runtime *rtd)
static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
/* We need default MCLK and PLL settings for the accessory detection */
@@ -233,13 +236,13 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int mclk;
int ret;
mclk = params_rate(params) * SOUND_FS;
- ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
if (ret) {
dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
__func__, mclk, ret);
@@ -335,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] = {
@@ -345,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] = {
@@ -353,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] = {
@@ -362,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] = {
@@ -371,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 */
@@ -443,7 +446,7 @@ static const struct rockchip_sound_route rockchip_routes[] = {
struct dailink_match_data {
const char *compatible;
- struct bus_type *bus_type;
+ const struct bus_type *bus_type;
};
static const struct dailink_match_data dailink_match[] = {
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 575a0b9b01e9..0a0a95b4f520 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -10,8 +10,7 @@
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/delay.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
@@ -352,7 +351,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_i2s_dev *i2s = to_info(dai);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int val = 0;
unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck;
@@ -539,6 +538,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
+ .probe = rockchip_i2s_dai_probe,
.hw_params = rockchip_i2s_hw_params,
.set_bclk_ratio = rockchip_i2s_set_bclk_ratio,
.set_sysclk = rockchip_i2s_set_sysclk,
@@ -547,7 +547,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
};
static struct snd_soc_dai_driver rockchip_i2s_dai = {
- .probe = rockchip_i2s_dai_probe,
.ops = &rockchip_i2s_dai_ops,
.symmetric_rate = 1,
};
@@ -736,7 +735,6 @@ static int rockchip_i2s_init_dai(struct rk_i2s_dev *i2s, struct resource *res,
static int rockchip_i2s_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- const struct of_device_id *of_id;
struct rk_i2s_dev *i2s;
struct snd_soc_dai_driver *dai;
struct resource *res;
@@ -752,11 +750,10 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
if (!IS_ERR(i2s->grf)) {
- of_id = of_match_device(rockchip_i2s_match, &pdev->dev);
- if (!of_id || !of_id->data)
+ i2s->pins = device_get_match_data(&pdev->dev);
+ if (!i2s->pins)
return -EINVAL;
- i2s->pins = of_id->data;
}
/* try to prepare related clocks */
@@ -863,17 +860,16 @@ 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 = {
.probe = rockchip_i2s_probe,
- .remove_new = rockchip_i2s_remove,
+ .remove = rockchip_i2s_remove,
.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 166257c6ae14..770b9bfbb384 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -10,9 +10,7 @@
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -24,11 +22,8 @@
#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
-#define CLK_PPM_MIN -1000
-#define CLK_PPM_MAX 1000
#define TRCM_TXRX 0
#define TRCM_TX 1
@@ -55,47 +50,27 @@ struct rk_i2s_tdm_dev {
struct clk *hclk;
struct clk *mclk_tx;
struct clk *mclk_rx;
- /* The mclk_tx_src is parent of mclk_tx */
- struct clk *mclk_tx_src;
- /* The mclk_rx_src is parent of mclk_rx */
- struct clk *mclk_rx_src;
- /*
- * The mclk_root0 and mclk_root1 are root parent and supplies for
- * the different FS.
- *
- * e.g:
- * mclk_root0 is VPLL0, used for FS=48000Hz
- * mclk_root1 is VPLL1, used for FS=44100Hz
- */
- struct clk *mclk_root0;
- struct clk *mclk_root1;
struct regmap *regmap;
struct regmap *grf;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct reset_control *tx_reset;
struct reset_control *rx_reset;
- struct rk_i2s_soc_data *soc_data;
+ const struct rk_i2s_soc_data *soc_data;
bool is_master_mode;
bool io_multiplex;
- bool mclk_calibrate;
bool tdm_mode;
- unsigned int mclk_rx_freq;
- unsigned int mclk_tx_freq;
- unsigned int mclk_root0_freq;
- unsigned int mclk_root1_freq;
- unsigned int mclk_root0_initial_freq;
- unsigned int mclk_root1_initial_freq;
unsigned int frame_width;
unsigned int clk_trcm;
unsigned int i2s_sdis[CH_GRP_MAX];
unsigned int i2s_sdos[CH_GRP_MAX];
- int clk_ppm;
int refcount;
spinlock_t lock; /* xfer lock */
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)
@@ -116,12 +91,6 @@ static void i2s_tdm_disable_unprepare_mclk(struct rk_i2s_tdm_dev *i2s_tdm)
{
clk_disable_unprepare(i2s_tdm->mclk_tx);
clk_disable_unprepare(i2s_tdm->mclk_rx);
- if (i2s_tdm->mclk_calibrate) {
- clk_disable_unprepare(i2s_tdm->mclk_tx_src);
- clk_disable_unprepare(i2s_tdm->mclk_rx_src);
- clk_disable_unprepare(i2s_tdm->mclk_root0);
- clk_disable_unprepare(i2s_tdm->mclk_root1);
- }
}
/**
@@ -144,36 +113,16 @@ static int i2s_tdm_prepare_enable_mclk(struct rk_i2s_tdm_dev *i2s_tdm)
ret = clk_prepare_enable(i2s_tdm->mclk_rx);
if (ret)
goto err_mclk_rx;
- if (i2s_tdm->mclk_calibrate) {
- ret = clk_prepare_enable(i2s_tdm->mclk_tx_src);
- if (ret)
- goto err_mclk_rx;
- ret = clk_prepare_enable(i2s_tdm->mclk_rx_src);
- if (ret)
- goto err_mclk_rx_src;
- ret = clk_prepare_enable(i2s_tdm->mclk_root0);
- if (ret)
- goto err_mclk_root0;
- ret = clk_prepare_enable(i2s_tdm->mclk_root1);
- if (ret)
- goto err_mclk_root1;
- }
return 0;
-err_mclk_root1:
- clk_disable_unprepare(i2s_tdm->mclk_root0);
-err_mclk_root0:
- clk_disable_unprepare(i2s_tdm->mclk_rx_src);
-err_mclk_rx_src:
- clk_disable_unprepare(i2s_tdm->mclk_tx_src);
err_mclk_rx:
clk_disable_unprepare(i2s_tdm->mclk_tx);
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);
@@ -185,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;
@@ -502,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;
@@ -566,186 +515,6 @@ static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream,
I2S_XFER_RXS_START);
}
-static int rockchip_i2s_tdm_clk_set_rate(struct rk_i2s_tdm_dev *i2s_tdm,
- struct clk *clk, unsigned long rate,
- int ppm)
-{
- unsigned long rate_target;
- int delta, ret;
-
- if (ppm == i2s_tdm->clk_ppm)
- return 0;
-
- if (ppm < 0)
- delta = -1;
- else
- delta = 1;
-
- delta *= (int)div64_u64((u64)rate * (u64)abs(ppm) + 500000,
- 1000000);
-
- rate_target = rate + delta;
-
- if (!rate_target)
- return -EINVAL;
-
- ret = clk_set_rate(clk, rate_target);
- if (ret)
- return ret;
-
- i2s_tdm->clk_ppm = ppm;
-
- return 0;
-}
-
-static int rockchip_i2s_tdm_calibrate_mclk(struct rk_i2s_tdm_dev *i2s_tdm,
- struct snd_pcm_substream *substream,
- unsigned int lrck_freq)
-{
- struct clk *mclk_root;
- struct clk *mclk_parent;
- unsigned int mclk_root_freq;
- unsigned int mclk_root_initial_freq;
- unsigned int mclk_parent_freq;
- unsigned int div, delta;
- u64 ppm;
- int ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- mclk_parent = i2s_tdm->mclk_tx_src;
- else
- mclk_parent = i2s_tdm->mclk_rx_src;
-
- switch (lrck_freq) {
- case 8000:
- case 16000:
- case 24000:
- case 32000:
- case 48000:
- case 64000:
- case 96000:
- case 192000:
- mclk_root = i2s_tdm->mclk_root0;
- mclk_root_freq = i2s_tdm->mclk_root0_freq;
- mclk_root_initial_freq = i2s_tdm->mclk_root0_initial_freq;
- mclk_parent_freq = DEFAULT_MCLK_FS * 192000;
- break;
- case 11025:
- case 22050:
- case 44100:
- case 88200:
- case 176400:
- mclk_root = i2s_tdm->mclk_root1;
- mclk_root_freq = i2s_tdm->mclk_root1_freq;
- mclk_root_initial_freq = i2s_tdm->mclk_root1_initial_freq;
- mclk_parent_freq = DEFAULT_MCLK_FS * 176400;
- break;
- default:
- dev_err(i2s_tdm->dev, "Invalid LRCK frequency: %u Hz\n",
- lrck_freq);
- return -EINVAL;
- }
-
- ret = clk_set_parent(mclk_parent, mclk_root);
- if (ret)
- return ret;
-
- ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, mclk_root,
- mclk_root_freq, 0);
- if (ret)
- return ret;
-
- delta = abs(mclk_root_freq % mclk_parent_freq - mclk_parent_freq);
- ppm = div64_u64((uint64_t)delta * 1000000, (uint64_t)mclk_root_freq);
-
- if (ppm) {
- div = DIV_ROUND_CLOSEST(mclk_root_initial_freq, mclk_parent_freq);
- if (!div)
- return -EINVAL;
-
- mclk_root_freq = mclk_parent_freq * round_up(div, 2);
-
- ret = clk_set_rate(mclk_root, mclk_root_freq);
- if (ret)
- return ret;
-
- i2s_tdm->mclk_root0_freq = clk_get_rate(i2s_tdm->mclk_root0);
- i2s_tdm->mclk_root1_freq = clk_get_rate(i2s_tdm->mclk_root1);
- }
-
- return clk_set_rate(mclk_parent, mclk_parent_freq);
-}
-
-static int rockchip_i2s_tdm_set_mclk(struct rk_i2s_tdm_dev *i2s_tdm,
- struct snd_pcm_substream *substream,
- struct clk **mclk)
-{
- unsigned int mclk_freq;
- int ret;
-
- if (i2s_tdm->clk_trcm) {
- if (i2s_tdm->mclk_tx_freq != i2s_tdm->mclk_rx_freq) {
- dev_err(i2s_tdm->dev,
- "clk_trcm, tx: %d and rx: %d should be the same\n",
- i2s_tdm->mclk_tx_freq,
- i2s_tdm->mclk_rx_freq);
- return -EINVAL;
- }
-
- ret = clk_set_rate(i2s_tdm->mclk_tx, i2s_tdm->mclk_tx_freq);
- if (ret)
- return ret;
-
- ret = clk_set_rate(i2s_tdm->mclk_rx, i2s_tdm->mclk_rx_freq);
- if (ret)
- return ret;
-
- /* mclk_rx is also ok. */
- *mclk = i2s_tdm->mclk_tx;
- } else {
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- *mclk = i2s_tdm->mclk_tx;
- mclk_freq = i2s_tdm->mclk_tx_freq;
- } else {
- *mclk = i2s_tdm->mclk_rx;
- mclk_freq = i2s_tdm->mclk_rx_freq;
- }
-
- ret = clk_set_rate(*mclk, mclk_freq);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-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)
{
@@ -782,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];
@@ -850,24 +618,56 @@ 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)
{
struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
- struct clk *mclk;
- int ret = 0;
unsigned int val = 0;
unsigned int mclk_rate, bclk_rate, div_bclk = 4, div_lrck = 64;
+ int err;
if (i2s_tdm->is_master_mode) {
- if (i2s_tdm->mclk_calibrate)
- rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream,
- params_rate(params));
+ struct clk *mclk;
+
+ 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;
+ }
- ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk);
- if (ret)
- return ret;
+ err = clk_set_rate(mclk, mclk_rate);
+ if (err)
+ return err;
mclk_rate = clk_get_rate(mclk);
bclk_rate = i2s_tdm->frame_width * params_rate(params);
@@ -975,96 +775,6 @@ static int rockchip_i2s_tdm_trigger(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);
-
- /* Put set mclk rate into rockchip_i2s_tdm_set_mclk() */
- 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_clk_compensation_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = CLK_PPM_MIN;
- uinfo->value.integer.max = CLK_PPM_MAX;
- uinfo->value.integer.step = 1;
-
- return 0;
-}
-
-static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
- struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
-
- ucontrol->value.integer.value[0] = i2s_tdm->clk_ppm;
-
- return 0;
-}
-
-static int rockchip_i2s_tdm_clk_compensation_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
- struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
- int ret = 0, ppm = 0;
- int changed = 0;
- unsigned long old_rate;
-
- if (ucontrol->value.integer.value[0] < CLK_PPM_MIN ||
- ucontrol->value.integer.value[0] > CLK_PPM_MAX)
- return -EINVAL;
-
- ppm = ucontrol->value.integer.value[0];
-
- old_rate = clk_get_rate(i2s_tdm->mclk_root0);
- ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root0,
- i2s_tdm->mclk_root0_freq, ppm);
- if (ret)
- return ret;
- if (old_rate != clk_get_rate(i2s_tdm->mclk_root0))
- changed = 1;
-
- if (clk_is_match(i2s_tdm->mclk_root0, i2s_tdm->mclk_root1))
- return changed;
-
- old_rate = clk_get_rate(i2s_tdm->mclk_root1);
- ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root1,
- i2s_tdm->mclk_root1_freq, ppm);
- if (ret)
- return ret;
- if (old_rate != clk_get_rate(i2s_tdm->mclk_root1))
- changed = 1;
-
- return changed;
-}
-
-static struct snd_kcontrol_new rockchip_i2s_tdm_compensation_control = {
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = "PCM Clock Compensation in PPM",
- .info = rockchip_i2s_tdm_clk_compensation_info,
- .get = rockchip_i2s_tdm_clk_compensation_get,
- .put = rockchip_i2s_tdm_clk_compensation_put,
-};
-
static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)
{
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
@@ -1074,9 +784,6 @@ static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)
if (i2s_tdm->has_playback)
snd_soc_dai_dma_data_set_playback(dai, &i2s_tdm->playback_dma_data);
- if (i2s_tdm->mclk_calibrate)
- snd_soc_add_dai_controls(dai, &rockchip_i2s_tdm_compensation_control, 1);
-
return 0;
}
@@ -1114,10 +821,11 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai,
}
static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
+ .probe = rockchip_i2s_tdm_dai_probe,
.hw_params = rockchip_i2s_tdm_hw_params,
.set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio,
- .set_sysclk = rockchip_i2s_tdm_set_sysclk,
.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,
};
@@ -1276,21 +984,21 @@ static const struct txrx_config rv1126_txrx_config[] = {
{ 0xff800000, 0x10260, RV1126_I2S0_CLK_TXONLY, RV1126_I2S0_CLK_RXONLY },
};
-static struct rk_i2s_soc_data px30_i2s_soc_data = {
+static const struct rk_i2s_soc_data px30_i2s_soc_data = {
.softrst_offset = 0x0300,
.configs = px30_txrx_config,
.config_count = ARRAY_SIZE(px30_txrx_config),
.init = common_soc_init,
};
-static struct rk_i2s_soc_data rk1808_i2s_soc_data = {
+static const struct rk_i2s_soc_data rk1808_i2s_soc_data = {
.softrst_offset = 0x0300,
.configs = rk1808_txrx_config,
.config_count = ARRAY_SIZE(rk1808_txrx_config),
.init = common_soc_init,
};
-static struct rk_i2s_soc_data rk3308_i2s_soc_data = {
+static const struct rk_i2s_soc_data rk3308_i2s_soc_data = {
.softrst_offset = 0x0400,
.grf_reg_offset = 0x0308,
.grf_shift = 5,
@@ -1299,14 +1007,14 @@ static struct rk_i2s_soc_data rk3308_i2s_soc_data = {
.init = common_soc_init,
};
-static struct rk_i2s_soc_data rk3568_i2s_soc_data = {
+static const struct rk_i2s_soc_data rk3568_i2s_soc_data = {
.softrst_offset = 0x0400,
.configs = rk3568_txrx_config,
.config_count = ARRAY_SIZE(rk3568_txrx_config),
.init = common_soc_init,
};
-static struct rk_i2s_soc_data rv1126_i2s_soc_data = {
+static const struct rk_i2s_soc_data rv1126_i2s_soc_data = {
.softrst_offset = 0x0300,
.configs = rv1126_txrx_config,
.config_count = ARRAY_SIZE(rv1126_txrx_config),
@@ -1324,7 +1032,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = {
};
static const struct snd_soc_dai_driver i2s_tdm_dai = {
- .probe = rockchip_i2s_tdm_dai_probe,
.ops = &rockchip_i2s_tdm_dai_ops,
};
@@ -1446,35 +1153,6 @@ static void rockchip_i2s_tdm_path_config(struct rk_i2s_tdm_dev *i2s_tdm,
rockchip_i2s_tdm_tx_path_config(i2s_tdm, num);
}
-static int rockchip_i2s_tdm_get_calibrate_mclks(struct rk_i2s_tdm_dev *i2s_tdm)
-{
- int num_mclks = 0;
-
- i2s_tdm->mclk_tx_src = devm_clk_get(i2s_tdm->dev, "mclk_tx_src");
- if (!IS_ERR(i2s_tdm->mclk_tx_src))
- num_mclks++;
-
- i2s_tdm->mclk_rx_src = devm_clk_get(i2s_tdm->dev, "mclk_rx_src");
- if (!IS_ERR(i2s_tdm->mclk_rx_src))
- num_mclks++;
-
- i2s_tdm->mclk_root0 = devm_clk_get(i2s_tdm->dev, "mclk_root0");
- if (!IS_ERR(i2s_tdm->mclk_root0))
- num_mclks++;
-
- i2s_tdm->mclk_root1 = devm_clk_get(i2s_tdm->dev, "mclk_root1");
- if (!IS_ERR(i2s_tdm->mclk_root1))
- num_mclks++;
-
- if (num_mclks < 4 && num_mclks != 0)
- return -ENOENT;
-
- if (num_mclks == 4)
- i2s_tdm->mclk_calibrate = 1;
-
- return 0;
-}
-
static int rockchip_i2s_tdm_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm,
struct device_node *np,
bool is_rx_path)
@@ -1544,7 +1222,6 @@ static int rockchip_i2s_tdm_rx_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm,
static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- const struct of_device_id *of_id;
struct rk_i2s_tdm_dev *i2s_tdm;
struct resource *res;
void __iomem *regs;
@@ -1556,13 +1233,8 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
i2s_tdm->dev = &pdev->dev;
- of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev);
- if (!of_id)
- return -EINVAL;
-
spin_lock_init(&i2s_tdm->lock);
- i2s_tdm->soc_data = (struct rk_i2s_soc_data *)of_id->data;
-
+ i2s_tdm->soc_data = device_get_match_data(&pdev->dev);
i2s_tdm->frame_width = 64;
i2s_tdm->clk_trcm = TRCM_TXRX;
@@ -1618,11 +1290,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
i2s_tdm->io_multiplex =
of_property_read_bool(node, "rockchip,io-multiplex");
- ret = rockchip_i2s_tdm_get_calibrate_mclks(i2s_tdm);
- if (ret)
- return dev_err_probe(i2s_tdm->dev, ret,
- "mclk-calibrate clocks missing");
-
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(regs)) {
return dev_err_probe(i2s_tdm->dev, PTR_ERR(regs),
@@ -1670,18 +1337,10 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
ret = i2s_tdm_prepare_enable_mclk(i2s_tdm);
if (ret) {
- ret = dev_err_probe(i2s_tdm->dev, ret,
- "Failed to enable one or more mclks\n");
+ dev_err_probe(i2s_tdm->dev, ret, "Failed to enable one or more mclks\n");
goto err_disable_hclk;
}
- if (i2s_tdm->mclk_calibrate) {
- i2s_tdm->mclk_root0_initial_freq = clk_get_rate(i2s_tdm->mclk_root0);
- i2s_tdm->mclk_root1_initial_freq = clk_get_rate(i2s_tdm->mclk_root1);
- i2s_tdm->mclk_root0_freq = i2s_tdm->mclk_root0_initial_freq;
- i2s_tdm->mclk_root1_freq = i2s_tdm->mclk_root1_initial_freq;
- }
-
pm_runtime_enable(&pdev->dev);
regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
@@ -1722,17 +1381,15 @@ err_disable_hclk:
return ret;
}
-static int rockchip_i2s_tdm_remove(struct platform_device *pdev)
+static void rockchip_i2s_tdm_remove(struct platform_device *pdev)
{
if (!pm_runtime_status_suspended(&pdev->dev))
i2s_tdm_runtime_suspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
-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);
@@ -1741,7 +1398,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;
@@ -1756,10 +1413,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 = {
@@ -1767,8 +1422,8 @@ static struct platform_driver rockchip_i2s_tdm_driver = {
.remove = rockchip_i2s_tdm_remove,
.driver = {
.name = DRV_NAME,
- .of_match_table = of_match_ptr(rockchip_i2s_tdm_match),
- .pm = &rockchip_i2s_tdm_pm_ops,
+ .of_match_table = rockchip_i2s_tdm_match,
+ .pm = pm_ptr(&rockchip_i2s_tdm_pm_ops),
},
};
module_platform_driver(rockchip_i2s_tdm_driver);
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.h b/sound/soc/rockchip/rockchip_i2s_tdm.h
index 0aa1c6da1e2c..0171e05ee886 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.h
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.h
@@ -10,6 +10,8 @@
#ifndef _ROCKCHIP_I2S_TDM_H
#define _ROCKCHIP_I2S_TDM_H
+#include <linux/hw_bitfield.h>
+
/*
* TXCR
* transmit operation control register
@@ -285,7 +287,7 @@ enum {
#define I2S_TDM_RXCR (0x0034)
#define I2S_CLKDIV (0x0038)
-#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16))
+#define HIWORD_UPDATE(v, h, l) (FIELD_PREP_WM16_CONST(GENMASK((h), (l)), (v)))
/* PX30 GRF CONFIGS */
#define PX30_I2S0_CLK_IN_SRC_FROM_TX HIWORD_UPDATE(1, 13, 12)
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 150ac524a590..075d0990a126 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -6,11 +6,9 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -110,7 +108,7 @@ static int rk_jack_event(struct notifier_block *nb, unsigned long event,
void *data)
{
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
- struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(jack->card);
if (event & SND_JACK_MICROPHONE) {
snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
@@ -144,9 +142,9 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int mclk;
switch (params_rate(params)) {
@@ -226,7 +224,7 @@ static struct snd_soc_jack rk_hdmi_jack;
static int rk_hdmi_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_card *card = runtime->card;
- struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
int ret;
/* enable jack detection */
@@ -249,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),
},
};
@@ -262,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),
}
};
@@ -276,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] = {
@@ -285,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 52f9aae60be8..c1ee470ec607 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/rational.h>
#include <linux/regmap.h>
@@ -379,6 +378,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
+ .probe = rockchip_pdm_dai_probe,
.set_fmt = rockchip_pdm_set_fmt,
.trigger = rockchip_pdm_trigger,
.hw_params = rockchip_pdm_hw_params,
@@ -391,7 +391,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver rockchip_pdm_dai = {
- .probe = rockchip_pdm_dai_probe,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
@@ -572,7 +571,6 @@ static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *n
static int rockchip_pdm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- const struct of_device_id *match;
struct rk_pdm_dev *pdm;
struct resource *res;
void __iomem *regs;
@@ -582,10 +580,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
if (!pdm)
return -ENOMEM;
- match = of_match_device(rockchip_pdm_match, &pdev->dev);
- if (match)
- pdm->version = (enum rk_pdm_version)match->data;
-
+ pdm->version = (enum rk_pdm_version)device_get_match_data(&pdev->dev);
if (pdm->version == RK_PDM_RK3308) {
pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
if (IS_ERR(pdm->reset))
@@ -673,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);
@@ -698,21 +692,20 @@ 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 = {
.probe = rockchip_pdm_probe,
- .remove_new = rockchip_pdm_remove,
+ .remove = rockchip_pdm_remove,
.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 e73a342b7953..590b64b362f6 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -8,8 +8,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -22,6 +20,16 @@
#define DRV_NAME "rockchip-snd-rt5645"
static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
@@ -55,9 +63,9 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int ret = 0;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int mclk;
switch (params_rate(params)) {
@@ -103,17 +111,19 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
int ret;
/* Enable Headset and 4 Buttons Jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &headset_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
if (ret) {
dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
return ret;
}
- return rt5645_set_jack_detect(asoc_rtd_to_codec(runtime, 0)->component,
+ return rt5645_set_jack_detect(snd_soc_rtd_to_codec(runtime, 0)->component,
&headset_jack,
&headset_jack,
&headset_jack);
@@ -135,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),
};
@@ -223,7 +233,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match);
static struct platform_driver snd_rk_mc_driver = {
.probe = snd_rk_mc_probe,
- .remove_new = snd_rk_mc_remove,
+ .remove = snd_rk_mc_remove,
.driver = {
.name = DRV_NAME,
.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
new file mode 100644
index 000000000000..ebdf0056065b
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -0,0 +1,1529 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ALSA SoC Audio Layer - Rockchip SAI Controller driver
+ *
+ * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
+ * Copyright (c) 2025 Collabora Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/tlv.h>
+
+#include "rockchip_sai.h"
+
+#define DRV_NAME "rockchip-sai"
+
+#define CLK_SHIFT_RATE_HZ_MAX 5
+#define FW_RATIO_MAX 8
+#define FW_RATIO_MIN 1
+#define MAXBURST_PER_FIFO 8
+
+#define TIMEOUT_US 1000
+#define WAIT_TIME_MS_MAX 10000
+
+#define MAX_LANES 4
+
+enum fpw_mode {
+ FPW_ONE_BCLK_WIDTH,
+ FPW_ONE_SLOT_WIDTH,
+ FPW_HALF_FRAME_WIDTH,
+};
+
+struct rk_sai_dev {
+ struct device *dev;
+ struct clk *hclk;
+ struct clk *mclk;
+ struct regmap *regmap;
+ struct reset_control *rst_h;
+ struct reset_control *rst_m;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+ struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1];
+ unsigned int mclk_rate;
+ unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1];
+ unsigned int tx_lanes;
+ unsigned int rx_lanes;
+ unsigned int sdi[MAX_LANES];
+ unsigned int sdo[MAX_LANES];
+ unsigned int version;
+ enum fpw_mode fpw;
+ int fw_ratio;
+ bool has_capture;
+ bool has_playback;
+ bool is_master_mode;
+ bool is_tdm;
+ bool initialized;
+ /* protects register writes that depend on the state of XFER[1:0] */
+ spinlock_t xfer_lock;
+};
+
+static bool rockchip_sai_stream_valid(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+
+ if (!substream)
+ return false;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ sai->has_playback)
+ return true;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+ sai->has_capture)
+ return true;
+
+ return false;
+}
+
+static int rockchip_sai_fsync_lost_detect(struct rk_sai_dev *sai, bool en)
+{
+ unsigned int fw, cnt;
+
+ if (sai->is_master_mode || sai->version < SAI_VER_2311)
+ return 0;
+
+ regmap_read(sai->regmap, SAI_FSCR, &fw);
+ cnt = SAI_FSCR_FW_V(fw) << 1; /* two fsync lost */
+
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSLOSTC, SAI_INTCR_FSLOSTC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSLOST_MASK,
+ SAI_INTCR_FSLOST(en));
+ /*
+ * The `cnt` is the number of SCLK cycles of the CRU's SCLK signal that
+ * should be used as timeout. Consequently, in slave mode, this value
+ * is only correct if the CRU SCLK is equal to the external SCLK.
+ */
+ regmap_update_bits(sai->regmap, SAI_FS_TIMEOUT,
+ SAI_FS_TIMEOUT_VAL_MASK | SAI_FS_TIMEOUT_EN_MASK,
+ SAI_FS_TIMEOUT_VAL(cnt) | SAI_FS_TIMEOUT_EN(en));
+
+ return 0;
+}
+
+static int rockchip_sai_fsync_err_detect(struct rk_sai_dev *sai,
+ bool en)
+{
+ if (sai->is_master_mode || sai->version < SAI_VER_2311)
+ return 0;
+
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSERRC, SAI_INTCR_FSERRC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSERR_MASK,
+ SAI_INTCR_FSERR(en));
+
+ return 0;
+}
+
+static int rockchip_sai_poll_clk_idle(struct rk_sai_dev *sai)
+{
+ unsigned int reg, idle, val;
+ int ret;
+
+ if (sai->version >= SAI_VER_2307) {
+ reg = SAI_STATUS;
+ idle = SAI_STATUS_FS_IDLE;
+ idle = sai->version >= SAI_VER_2311 ? idle >> 1 : idle;
+ } else {
+ reg = SAI_XFER;
+ idle = SAI_XFER_FS_IDLE;
+ }
+
+ ret = regmap_read_poll_timeout_atomic(sai->regmap, reg, val,
+ (val & idle), 10, TIMEOUT_US);
+ if (ret < 0)
+ dev_warn(sai->dev, "Failed to idle FS\n");
+
+ return ret;
+}
+
+static int rockchip_sai_poll_stream_idle(struct rk_sai_dev *sai, bool playback, bool capture)
+{
+ unsigned int reg, val;
+ unsigned int idle = 0;
+ int ret;
+
+ if (sai->version >= SAI_VER_2307) {
+ reg = SAI_STATUS;
+ if (playback)
+ idle |= SAI_STATUS_TX_IDLE;
+ if (capture)
+ idle |= SAI_STATUS_RX_IDLE;
+ idle = sai->version >= SAI_VER_2311 ? idle >> 1 : idle;
+ } else {
+ reg = SAI_XFER;
+ if (playback)
+ idle |= SAI_XFER_TX_IDLE;
+ if (capture)
+ idle |= SAI_XFER_RX_IDLE;
+ }
+
+ ret = regmap_read_poll_timeout_atomic(sai->regmap, reg, val,
+ (val & idle), 10, TIMEOUT_US);
+ if (ret < 0)
+ dev_warn(sai->dev, "Failed to idle stream\n");
+
+ return ret;
+}
+
+/**
+ * rockchip_sai_xfer_clk_stop_and_wait() - stop the xfer clock and wait for it to be idle
+ * @sai: pointer to the driver instance's rk_sai_dev struct
+ * @to_restore: pointer to store the CLK/FSS register values in as they were
+ * found before they were cleared, or NULL.
+ *
+ * Clear the XFER_CLK and XFER_FSS registers if needed, then busy-waits for the
+ * XFER clocks to be idle. Before clearing the bits, it stores the state of the
+ * registers as it encountered them in to_restore if it isn't NULL.
+ *
+ * Context: Any context. Expects sai->xfer_lock to be held by caller.
+ */
+static void rockchip_sai_xfer_clk_stop_and_wait(struct rk_sai_dev *sai, unsigned int *to_restore)
+{
+ unsigned int mask = SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK;
+ unsigned int disable = SAI_XFER_CLK_DIS | SAI_XFER_FSS_DIS;
+ unsigned int val;
+
+ assert_spin_locked(&sai->xfer_lock);
+
+ regmap_read(sai->regmap, SAI_XFER, &val);
+ if ((val & mask) == disable)
+ goto wait_for_idle;
+
+ if (sai->is_master_mode)
+ regmap_update_bits(sai->regmap, SAI_XFER, mask, disable);
+
+wait_for_idle:
+ rockchip_sai_poll_clk_idle(sai);
+
+ if (to_restore)
+ *to_restore = val;
+}
+
+static int rockchip_sai_runtime_suspend(struct device *dev)
+{
+ struct rk_sai_dev *sai = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ rockchip_sai_fsync_lost_detect(sai, 0);
+ rockchip_sai_fsync_err_detect(sai, 0);
+
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+
+ regcache_cache_only(sai->regmap, true);
+ /*
+ * After FS is idle, we should wait at least 2 BCLK cycles to make sure
+ * the CLK gate operation has completed, and only then disable mclk.
+ *
+ * Otherwise, the BCLK is still ungated, and once the mclk is enabled,
+ * there is a risk that a few BCLK cycles leak. This is true especially
+ * at low speeds, such as with a samplerate of 8k.
+ *
+ * Ideally we'd adjust the delay based on the samplerate, but it's such
+ * a tiny value that we can just delay for the maximum clock period
+ * for the sake of simplicity.
+ *
+ * The maximum BCLK period is 31us @ 8K-8Bit (64kHz BCLK). We wait for
+ * 40us to give ourselves a safety margin in case udelay falls short.
+ */
+ udelay(40);
+ clk_disable_unprepare(sai->mclk);
+ clk_disable_unprepare(sai->hclk);
+
+ return 0;
+}
+
+static int rockchip_sai_runtime_resume(struct device *dev)
+{
+ struct rk_sai_dev *sai = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(sai->hclk);
+ if (ret)
+ goto err_hclk;
+
+ ret = clk_prepare_enable(sai->mclk);
+ if (ret)
+ goto err_mclk;
+
+ regcache_cache_only(sai->regmap, false);
+ regcache_mark_dirty(sai->regmap);
+ ret = regcache_sync(sai->regmap);
+ if (ret)
+ goto err_regmap;
+
+ return 0;
+
+err_regmap:
+ clk_disable_unprepare(sai->mclk);
+err_mclk:
+ clk_disable_unprepare(sai->hclk);
+err_hclk:
+ return ret;
+}
+
+static void rockchip_sai_fifo_xrun_detect(struct rk_sai_dev *sai,
+ int stream, bool en)
+{
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* clear irq status which was asserted before TXUIE enabled */
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_TXUIC, SAI_INTCR_TXUIC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_TXUIE_MASK,
+ SAI_INTCR_TXUIE(en));
+ } else {
+ /* clear irq status which was asserted before RXOIE enabled */
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_RXOIC, SAI_INTCR_RXOIC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_RXOIE_MASK,
+ SAI_INTCR_RXOIE(en));
+ }
+}
+
+static void rockchip_sai_dma_ctrl(struct rk_sai_dev *sai,
+ int stream, bool en)
+{
+ if (!en)
+ rockchip_sai_fifo_xrun_detect(sai, stream, 0);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(sai->regmap, SAI_DMACR,
+ SAI_DMACR_TDE_MASK,
+ SAI_DMACR_TDE(en));
+ } else {
+ regmap_update_bits(sai->regmap, SAI_DMACR,
+ SAI_DMACR_RDE_MASK,
+ SAI_DMACR_RDE(en));
+ }
+
+ if (en)
+ rockchip_sai_fifo_xrun_detect(sai, stream, 1);
+}
+
+static void rockchip_sai_reset(struct rk_sai_dev *sai)
+{
+ /*
+ * It is advised to reset the hclk domain before resetting the mclk
+ * domain, especially in slave mode without a clock input.
+ *
+ * To deal with the aforementioned case of slave mode without a clock
+ * input, we work around a potential issue by resetting the whole
+ * controller, bringing it back into master mode, and then recovering
+ * the controller configuration in the regmap.
+ */
+ reset_control_assert(sai->rst_h);
+ udelay(10);
+ reset_control_deassert(sai->rst_h);
+ udelay(10);
+ reset_control_assert(sai->rst_m);
+ udelay(10);
+ reset_control_deassert(sai->rst_m);
+ udelay(10);
+
+ /* recover regmap config */
+ regcache_mark_dirty(sai->regmap);
+ regcache_sync(sai->regmap);
+}
+
+static int rockchip_sai_clear(struct rk_sai_dev *sai, unsigned int clr)
+{
+ unsigned int val = 0;
+ int ret = 0;
+
+ regmap_update_bits(sai->regmap, SAI_CLR, clr, clr);
+ ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_CLR, val,
+ !(val & clr), 10, TIMEOUT_US);
+ if (ret < 0) {
+ dev_warn(sai->dev, "Failed to clear %u\n", clr);
+ rockchip_sai_reset(sai);
+ }
+
+ return ret;
+}
+
+static void rockchip_sai_xfer_start(struct rk_sai_dev *sai, int stream)
+{
+ unsigned int msk, val;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ msk = SAI_XFER_TXS_MASK;
+ val = SAI_XFER_TXS_EN;
+
+ } else {
+ msk = SAI_XFER_RXS_MASK;
+ val = SAI_XFER_RXS_EN;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_XFER, msk, val);
+}
+
+static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream)
+{
+ unsigned int msk = 0, val = 0, clr = 0;
+ bool capture = stream == SNDRV_PCM_STREAM_CAPTURE || stream < 0;
+ bool playback = stream == SNDRV_PCM_STREAM_PLAYBACK || stream < 0;
+ /* could be <= 0 but we don't want to depend on enum values */
+
+ if (playback) {
+ msk |= SAI_XFER_TXS_MASK;
+ val |= SAI_XFER_TXS_DIS;
+ clr |= SAI_CLR_TXC;
+ }
+ if (capture) {
+ msk |= SAI_XFER_RXS_MASK;
+ val |= SAI_XFER_RXS_DIS;
+ clr |= SAI_CLR_RXC;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_XFER, msk, val);
+ rockchip_sai_poll_stream_idle(sai, playback, capture);
+
+ rockchip_sai_clear(sai, clr);
+}
+
+static void rockchip_sai_start(struct rk_sai_dev *sai, int stream)
+{
+ rockchip_sai_dma_ctrl(sai, stream, 1);
+ rockchip_sai_xfer_start(sai, stream);
+}
+
+static void rockchip_sai_stop(struct rk_sai_dev *sai, int stream)
+{
+ rockchip_sai_dma_ctrl(sai, stream, 0);
+ rockchip_sai_xfer_stop(sai, stream);
+}
+
+static void rockchip_sai_fmt_create(struct rk_sai_dev *sai, unsigned int fmt)
+{
+ unsigned int xcr_mask = 0, xcr_val = 0, xsft_mask = 0, xsft_val = 0;
+ unsigned int fscr_mask = 0, fscr_val = 0;
+
+ assert_spin_locked(&sai->xfer_lock);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ xcr_mask = SAI_XCR_VDJ_MASK | SAI_XCR_EDGE_SHIFT_MASK;
+ xcr_val = SAI_XCR_VDJ_R | SAI_XCR_EDGE_SHIFT_0;
+ xsft_mask = SAI_XSHIFT_RIGHT_MASK;
+ xsft_val = SAI_XSHIFT_RIGHT(0);
+ fscr_mask = SAI_FSCR_EDGE_MASK;
+ fscr_val = SAI_FSCR_EDGE_DUAL;
+ sai->fpw = FPW_HALF_FRAME_WIDTH;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ xcr_mask = SAI_XCR_VDJ_MASK | SAI_XCR_EDGE_SHIFT_MASK;
+ xcr_val = SAI_XCR_VDJ_L | SAI_XCR_EDGE_SHIFT_0;
+ xsft_mask = SAI_XSHIFT_RIGHT_MASK;
+ xsft_val = SAI_XSHIFT_RIGHT(0);
+ fscr_mask = SAI_FSCR_EDGE_MASK;
+ fscr_val = SAI_FSCR_EDGE_DUAL;
+ sai->fpw = FPW_HALF_FRAME_WIDTH;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ xcr_mask = SAI_XCR_VDJ_MASK | SAI_XCR_EDGE_SHIFT_MASK;
+ xcr_val = SAI_XCR_VDJ_L | SAI_XCR_EDGE_SHIFT_1;
+ xsft_mask = SAI_XSHIFT_RIGHT_MASK;
+ if (sai->is_tdm)
+ xsft_val = SAI_XSHIFT_RIGHT(1);
+ else
+ xsft_val = SAI_XSHIFT_RIGHT(2);
+ fscr_mask = SAI_FSCR_EDGE_MASK;
+ fscr_val = SAI_FSCR_EDGE_DUAL;
+ sai->fpw = FPW_HALF_FRAME_WIDTH;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ xcr_mask = SAI_XCR_VDJ_MASK | SAI_XCR_EDGE_SHIFT_MASK;
+ xcr_val = SAI_XCR_VDJ_L | SAI_XCR_EDGE_SHIFT_0;
+ xsft_mask = SAI_XSHIFT_RIGHT_MASK;
+ xsft_val = SAI_XSHIFT_RIGHT(2);
+ fscr_mask = SAI_FSCR_EDGE_MASK;
+ fscr_val = SAI_FSCR_EDGE_RISING;
+ sai->fpw = FPW_ONE_BCLK_WIDTH;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ xcr_mask = SAI_XCR_VDJ_MASK | SAI_XCR_EDGE_SHIFT_MASK;
+ xcr_val = SAI_XCR_VDJ_L | SAI_XCR_EDGE_SHIFT_0;
+ xsft_mask = SAI_XSHIFT_RIGHT_MASK;
+ xsft_val = SAI_XSHIFT_RIGHT(0);
+ fscr_mask = SAI_FSCR_EDGE_MASK;
+ fscr_val = SAI_FSCR_EDGE_RISING;
+ sai->fpw = FPW_ONE_BCLK_WIDTH;
+ break;
+ default:
+ dev_err(sai->dev, "Unsupported fmt %u\n", fmt);
+ break;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_TXCR, xcr_mask, xcr_val);
+ regmap_update_bits(sai->regmap, SAI_RXCR, xcr_mask, xcr_val);
+ regmap_update_bits(sai->regmap, SAI_TX_SHIFT, xsft_mask, xsft_val);
+ regmap_update_bits(sai->regmap, SAI_RX_SHIFT, xsft_mask, xsft_val);
+ regmap_update_bits(sai->regmap, SAI_FSCR, fscr_mask, fscr_val);
+}
+
+static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ unsigned int mask = 0, val = 0;
+ unsigned int clk_gates;
+ unsigned long flags;
+ int ret = 0;
+
+ pm_runtime_get_sync(dai->dev);
+
+ mask = SAI_CKR_MSS_MASK;
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
+ val = SAI_CKR_MSS_MASTER;
+ sai->is_master_mode = true;
+ break;
+ case SND_SOC_DAIFMT_BC_FC:
+ val = SAI_CKR_MSS_SLAVE;
+ sai->is_master_mode = false;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_pm_put;
+ }
+
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+ if (sai->initialized) {
+ if (sai->has_capture && sai->has_playback)
+ rockchip_sai_xfer_stop(sai, -1);
+ else if (sai->has_capture)
+ rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
+ else
+ rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
+ } else {
+ rockchip_sai_clear(sai, 0);
+ sai->initialized = true;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+
+ mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_xfer_unlock;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+
+ rockchip_sai_fmt_create(sai, fmt);
+
+err_xfer_unlock:
+ if (clk_gates)
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+ clk_gates);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+err_pm_put:
+ pm_runtime_put(dai->dev);
+
+ return ret;
+}
+
+static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ unsigned int mclk_rate, mclk_req_rate, bclk_rate, div_bclk;
+ unsigned int ch_per_lane, slot_width;
+ unsigned int val, fscr, reg;
+ unsigned int lanes, req_lanes;
+ unsigned long flags;
+ int ret = 0;
+
+ if (!rockchip_sai_stream_valid(substream, dai))
+ return 0;
+
+ dma_data = snd_soc_dai_get_dma_data(dai, substream);
+ dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2;
+
+ pm_runtime_get_sync(sai->dev);
+
+ regmap_read(sai->regmap, SAI_DMACR, &val);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ reg = SAI_TXCR;
+ lanes = sai->tx_lanes;
+ } else {
+ reg = SAI_RXCR;
+ lanes = sai->rx_lanes;
+ }
+
+ if (!sai->is_tdm) {
+ req_lanes = DIV_ROUND_UP(params_channels(params), 2);
+ if (lanes < req_lanes) {
+ dev_err(sai->dev, "not enough lanes (%d) for requested number of %s channels (%d)\n",
+ lanes, reg == SAI_TXCR ? "playback" : "capture",
+ params_channels(params));
+ ret = -EINVAL;
+ goto err_pm_put;
+ } else {
+ lanes = req_lanes;
+ }
+ }
+
+ dev_dbg(sai->dev, "using %d lanes totalling %d%s channels for %s\n",
+ lanes, params_channels(params), sai->is_tdm ? " (TDM)" : "",
+ reg == SAI_TXCR ? "playback" : "capture");
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ case SNDRV_PCM_FORMAT_U8:
+ val = SAI_XCR_VDW(8);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ val = SAI_XCR_VDW(16);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ val = SAI_XCR_VDW(24);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ val = SAI_XCR_VDW(32);
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_pm_put;
+ }
+
+ val |= SAI_XCR_CSR(lanes);
+
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
+
+ regmap_read(sai->regmap, reg, &val);
+
+ slot_width = SAI_XCR_SBW_V(val);
+ ch_per_lane = params_channels(params) / lanes;
+
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
+ SAI_XCR_SNB(ch_per_lane));
+
+ fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
+
+ switch (sai->fpw) {
+ case FPW_ONE_BCLK_WIDTH:
+ fscr |= SAI_FSCR_FPW(1);
+ break;
+ case FPW_ONE_SLOT_WIDTH:
+ fscr |= SAI_FSCR_FPW(slot_width);
+ break;
+ case FPW_HALF_FRAME_WIDTH:
+ fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
+ break;
+ default:
+ dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
+ ret = -EINVAL;
+ goto err_xfer_unlock;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_FSCR,
+ SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
+
+ if (sai->is_master_mode) {
+ bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
+ ret = clk_set_rate(sai->mclk, sai->mclk_rate);
+ if (ret) {
+ dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
+ sai->mclk_rate, ERR_PTR(ret));
+ goto err_xfer_unlock;
+ }
+
+ mclk_rate = clk_get_rate(sai->mclk);
+ if (mclk_rate < bclk_rate) {
+ dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
+ mclk_rate, bclk_rate);
+ ret = -EINVAL;
+ goto err_xfer_unlock;
+ }
+
+ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
+ mclk_req_rate = bclk_rate * div_bclk;
+
+ if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
+ mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
+ dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
+ mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
+ ret = -EINVAL;
+ goto err_xfer_unlock;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
+ SAI_CKR_MDIV(div_bclk));
+ }
+
+err_xfer_unlock:
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+err_pm_put:
+ pm_runtime_put(sai->dev);
+
+ return ret;
+}
+
+static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ unsigned long flags;
+
+ if (!rockchip_sai_stream_valid(substream, dai))
+ return 0;
+
+ if (sai->is_master_mode) {
+ /*
+ * We should wait for the first BCLK pulse to have definitely
+ * occurred after any DIV settings have potentially been
+ * changed in order to guarantee a clean clock signal once we
+ * ungate the clock.
+ *
+ * Ideally, this would be done depending on the samplerate, but
+ * for the sake of simplicity, we'll just delay for the maximum
+ * possible clock offset time, which is quite a small value.
+ *
+ * The maximum BCLK offset is 15.6us @ 8K-8Bit (64kHz BCLK). We
+ * wait for 20us in order to give us a safety margin in case
+ * udelay falls short.
+ */
+ udelay(20);
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK |
+ SAI_XFER_FSS_MASK,
+ SAI_XFER_CLK_EN |
+ SAI_XFER_FSS_EN);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+ }
+
+ rockchip_sai_fsync_lost_detect(sai, 1);
+ rockchip_sai_fsync_err_detect(sai, 1);
+
+ return 0;
+}
+
+static void rockchip_sai_path_config(struct rk_sai_dev *sai,
+ int num, bool is_rx)
+{
+ int i;
+
+ if (is_rx)
+ for (i = 0; i < num; i++)
+ regmap_update_bits(sai->regmap, SAI_PATH_SEL,
+ SAI_RX_PATH_MASK(i),
+ SAI_RX_PATH(i, sai->sdi[i]));
+ else
+ for (i = 0; i < num; i++)
+ regmap_update_bits(sai->regmap, SAI_PATH_SEL,
+ SAI_TX_PATH_MASK(i),
+ SAI_TX_PATH(i, sai->sdo[i]));
+}
+
+static int rockchip_sai_path_prepare(struct rk_sai_dev *sai,
+ struct device_node *np,
+ bool is_rx)
+{
+ const char *path_prop;
+ unsigned int *data;
+ unsigned int *lanes;
+ int i, num, ret;
+
+ if (is_rx) {
+ path_prop = "rockchip,sai-rx-route";
+ data = sai->sdi;
+ lanes = &sai->rx_lanes;
+ } else {
+ path_prop = "rockchip,sai-tx-route";
+ data = sai->sdo;
+ lanes = &sai->tx_lanes;
+ }
+
+ num = of_count_phandle_with_args(np, path_prop, NULL);
+ if (num == -ENOENT) {
+ return 0;
+ } else if (num > MAX_LANES || num == 0) {
+ dev_err(sai->dev, "found %d entries in %s, outside of range 1 to %d\n",
+ num, path_prop, MAX_LANES);
+ return -EINVAL;
+ } else if (num < 0) {
+ dev_err(sai->dev, "error in %s property: %pe\n", path_prop,
+ ERR_PTR(num));
+ return num;
+ }
+
+ *lanes = num;
+ ret = device_property_read_u32_array(sai->dev, path_prop, data, num);
+ if (ret < 0) {
+ dev_err(sai->dev, "failed to read property '%s': %pe\n",
+ path_prop, ERR_PTR(ret));
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (data[i] >= MAX_LANES) {
+ dev_err(sai->dev, "%s[%d] is %d, should be less than %d\n",
+ path_prop, i, data[i], MAX_LANES);
+ return -EINVAL;
+ }
+ }
+
+ rockchip_sai_path_config(sai, num, is_rx);
+
+ return 0;
+}
+
+static int rockchip_sai_parse_paths(struct rk_sai_dev *sai,
+ struct device_node *np)
+{
+ int ret;
+
+ if (sai->has_playback) {
+ sai->tx_lanes = 1;
+ ret = rockchip_sai_path_prepare(sai, np, false);
+ if (ret < 0) {
+ dev_err(sai->dev, "Failed to prepare TX path: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ if (sai->has_capture) {
+ sai->rx_lanes = 1;
+ ret = rockchip_sai_path_prepare(sai, np, true);
+ if (ret < 0) {
+ dev_err(sai->dev, "Failed to prepare RX path: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int rockchip_sai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ int ret = 0;
+
+ if (!rockchip_sai_stream_valid(substream, dai))
+ return 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ rockchip_sai_start(sai, substream->stream);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ rockchip_sai_stop(sai, substream->stream);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int rockchip_sai_dai_probe(struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai,
+ sai->has_playback ? &sai->playback_dma_data : NULL,
+ sai->has_capture ? &sai->capture_dma_data : NULL);
+
+ return 0;
+}
+
+static int rockchip_sai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ int stream = substream->stream;
+
+ if (!rockchip_sai_stream_valid(substream, dai))
+ return 0;
+
+ if (sai->substreams[stream])
+ return -EBUSY;
+
+ if (sai->wait_time[stream])
+ substream->wait_time = sai->wait_time[stream];
+
+ sai->substreams[stream] = substream;
+
+ return 0;
+}
+
+static void rockchip_sai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+
+ if (!rockchip_sai_stream_valid(substream, dai))
+ return;
+
+ sai->substreams[substream->stream] = NULL;
+}
+
+static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ unsigned long flags;
+ unsigned int clk_gates;
+ int sw = slot_width;
+
+ if (!slots) {
+ /* Disabling TDM, set slot width back to 32 bits */
+ sai->is_tdm = false;
+ sw = 32;
+ } else {
+ sai->is_tdm = true;
+ }
+
+ if (sw < 16 || sw > 32)
+ return -EINVAL;
+
+ pm_runtime_get_sync(dai->dev);
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+ regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(sw));
+ regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(sw));
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+ clk_gates);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+ pm_runtime_put(dai->dev);
+
+ return 0;
+}
+
+static int rockchip_sai_set_sysclk(struct snd_soc_dai *dai, int stream,
+ unsigned int freq, int dir)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+
+ sai->mclk_rate = freq;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops rockchip_sai_dai_ops = {
+ .probe = rockchip_sai_dai_probe,
+ .startup = rockchip_sai_startup,
+ .shutdown = rockchip_sai_shutdown,
+ .hw_params = rockchip_sai_hw_params,
+ .set_fmt = rockchip_sai_set_fmt,
+ .set_sysclk = rockchip_sai_set_sysclk,
+ .prepare = rockchip_sai_prepare,
+ .trigger = rockchip_sai_trigger,
+ .set_tdm_slot = rockchip_sai_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_driver rockchip_sai_dai = {
+ .ops = &rockchip_sai_dai_ops,
+ .symmetric_rate = 1,
+};
+
+static bool rockchip_sai_wr_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SAI_TXCR:
+ case SAI_FSCR:
+ case SAI_RXCR:
+ case SAI_MONO_CR:
+ case SAI_XFER:
+ case SAI_CLR:
+ case SAI_CKR:
+ case SAI_DMACR:
+ case SAI_INTCR:
+ case SAI_TXDR:
+ case SAI_PATH_SEL:
+ case SAI_TX_SLOT_MASK0:
+ case SAI_TX_SLOT_MASK1:
+ case SAI_TX_SLOT_MASK2:
+ case SAI_TX_SLOT_MASK3:
+ case SAI_RX_SLOT_MASK0:
+ case SAI_RX_SLOT_MASK1:
+ case SAI_RX_SLOT_MASK2:
+ case SAI_RX_SLOT_MASK3:
+ case SAI_TX_SHIFT:
+ case SAI_RX_SHIFT:
+ case SAI_FSXN:
+ case SAI_FS_TIMEOUT:
+ case SAI_LOOPBACK_LR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rockchip_sai_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SAI_TXCR:
+ case SAI_FSCR:
+ case SAI_RXCR:
+ case SAI_MONO_CR:
+ case SAI_XFER:
+ case SAI_CLR:
+ case SAI_CKR:
+ case SAI_TXFIFOLR:
+ case SAI_RXFIFOLR:
+ case SAI_DMACR:
+ case SAI_INTCR:
+ case SAI_INTSR:
+ case SAI_TXDR:
+ case SAI_RXDR:
+ case SAI_PATH_SEL:
+ case SAI_TX_SLOT_MASK0:
+ case SAI_TX_SLOT_MASK1:
+ case SAI_TX_SLOT_MASK2:
+ case SAI_TX_SLOT_MASK3:
+ case SAI_RX_SLOT_MASK0:
+ case SAI_RX_SLOT_MASK1:
+ case SAI_RX_SLOT_MASK2:
+ case SAI_RX_SLOT_MASK3:
+ case SAI_TX_DATA_CNT:
+ case SAI_RX_DATA_CNT:
+ case SAI_TX_SHIFT:
+ case SAI_RX_SHIFT:
+ case SAI_STATUS:
+ case SAI_VERSION:
+ case SAI_FSXN:
+ case SAI_FS_TIMEOUT:
+ case SAI_LOOPBACK_LR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rockchip_sai_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SAI_XFER:
+ case SAI_INTCR:
+ case SAI_INTSR:
+ case SAI_CLR:
+ case SAI_TXFIFOLR:
+ case SAI_RXFIFOLR:
+ case SAI_TXDR:
+ case SAI_RXDR:
+ case SAI_TX_DATA_CNT:
+ case SAI_RX_DATA_CNT:
+ case SAI_STATUS:
+ case SAI_VERSION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rockchip_sai_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SAI_RXDR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct reg_default rockchip_sai_reg_defaults[] = {
+ { SAI_TXCR, 0x00000bff },
+ { SAI_FSCR, 0x0001f03f },
+ { SAI_RXCR, 0x00000bff },
+ { SAI_PATH_SEL, 0x0000e4e4 },
+};
+
+static const struct regmap_config rockchip_sai_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SAI_LOOPBACK_LR,
+ .reg_defaults = rockchip_sai_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rockchip_sai_reg_defaults),
+ .writeable_reg = rockchip_sai_wr_reg,
+ .readable_reg = rockchip_sai_rd_reg,
+ .volatile_reg = rockchip_sai_volatile_reg,
+ .precious_reg = rockchip_sai_precious_reg,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
+ struct snd_soc_dai_driver **dp)
+{
+ struct device_node *node = sai->dev->of_node;
+ struct snd_soc_dai_driver *dai;
+ struct property *dma_names;
+ const char *dma_name;
+
+ of_property_for_each_string(node, "dma-names", dma_names, dma_name) {
+ if (!strcmp(dma_name, "tx"))
+ sai->has_playback = true;
+ if (!strcmp(dma_name, "rx"))
+ sai->has_capture = true;
+ }
+
+ dai = devm_kmemdup(sai->dev, &rockchip_sai_dai,
+ sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ if (sai->has_playback) {
+ dai->playback.stream_name = "Playback";
+ dai->playback.channels_min = 1;
+ dai->playback.channels_max = 512;
+ dai->playback.rates = SNDRV_PCM_RATE_8000_384000;
+ dai->playback.formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+
+ sai->playback_dma_data.addr = res->start + SAI_TXDR;
+ sai->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ sai->playback_dma_data.maxburst = MAXBURST_PER_FIFO;
+ }
+
+ if (sai->has_capture) {
+ dai->capture.stream_name = "Capture";
+ dai->capture.channels_min = 1;
+ dai->capture.channels_max = 512;
+ dai->capture.rates = SNDRV_PCM_RATE_8000_384000;
+ dai->capture.formats = SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+
+ sai->capture_dma_data.addr = res->start + SAI_RXDR;
+ sai->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ sai->capture_dma_data.maxburst = MAXBURST_PER_FIFO;
+ }
+
+ regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_TDL_MASK,
+ SAI_DMACR_TDL(16));
+ regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_RDL_MASK,
+ SAI_DMACR_RDL(16));
+
+ if (dp)
+ *dp = dai;
+
+ return 0;
+}
+
+static const char * const mono_text[] = { "Disable", "Enable" };
+
+static DECLARE_TLV_DB_SCALE(rmss_tlv, 0, 128, 0);
+
+static const char * const lplrc_text[] = { "L:MIC R:LP", "L:LP R:MIC" };
+static const char * const lplr_text[] = { "Disable", "Enable" };
+
+static const char * const lpx_text[] = {
+ "From SDO0", "From SDO1", "From SDO2", "From SDO3" };
+
+static const char * const lps_text[] = { "Disable", "Enable" };
+static const char * const sync_out_text[] = { "From CRU", "From IO" };
+static const char * const sync_in_text[] = { "From IO", "From Sync Port" };
+
+static const char * const rpaths_text[] = {
+ "From SDI0", "From SDI1", "From SDI2", "From SDI3" };
+
+static const char * const tpaths_text[] = {
+ "From PATH0", "From PATH1", "From PATH2", "From PATH3" };
+
+/* MONO_CR */
+static SOC_ENUM_SINGLE_DECL(rmono_switch, SAI_MONO_CR, 1, mono_text);
+static SOC_ENUM_SINGLE_DECL(tmono_switch, SAI_MONO_CR, 0, mono_text);
+
+/* PATH_SEL */
+static SOC_ENUM_SINGLE_DECL(lp3_enum, SAI_PATH_SEL, 28, lpx_text);
+static SOC_ENUM_SINGLE_DECL(lp2_enum, SAI_PATH_SEL, 26, lpx_text);
+static SOC_ENUM_SINGLE_DECL(lp1_enum, SAI_PATH_SEL, 24, lpx_text);
+static SOC_ENUM_SINGLE_DECL(lp0_enum, SAI_PATH_SEL, 22, lpx_text);
+static SOC_ENUM_SINGLE_DECL(lp3_switch, SAI_PATH_SEL, 21, lps_text);
+static SOC_ENUM_SINGLE_DECL(lp2_switch, SAI_PATH_SEL, 20, lps_text);
+static SOC_ENUM_SINGLE_DECL(lp1_switch, SAI_PATH_SEL, 19, lps_text);
+static SOC_ENUM_SINGLE_DECL(lp0_switch, SAI_PATH_SEL, 18, lps_text);
+static SOC_ENUM_SINGLE_DECL(sync_out_switch, SAI_PATH_SEL, 17, sync_out_text);
+static SOC_ENUM_SINGLE_DECL(sync_in_switch, SAI_PATH_SEL, 16, sync_in_text);
+static SOC_ENUM_SINGLE_DECL(rpath3_enum, SAI_PATH_SEL, 14, rpaths_text);
+static SOC_ENUM_SINGLE_DECL(rpath2_enum, SAI_PATH_SEL, 12, rpaths_text);
+static SOC_ENUM_SINGLE_DECL(rpath1_enum, SAI_PATH_SEL, 10, rpaths_text);
+static SOC_ENUM_SINGLE_DECL(rpath0_enum, SAI_PATH_SEL, 8, rpaths_text);
+static SOC_ENUM_SINGLE_DECL(tpath3_enum, SAI_PATH_SEL, 6, tpaths_text);
+static SOC_ENUM_SINGLE_DECL(tpath2_enum, SAI_PATH_SEL, 4, tpaths_text);
+static SOC_ENUM_SINGLE_DECL(tpath1_enum, SAI_PATH_SEL, 2, tpaths_text);
+static SOC_ENUM_SINGLE_DECL(tpath0_enum, SAI_PATH_SEL, 0, tpaths_text);
+
+/* LOOPBACK_LR */
+static SOC_ENUM_SINGLE_DECL(lp3lrc_enum, SAI_LOOPBACK_LR, 7, lplrc_text);
+static SOC_ENUM_SINGLE_DECL(lp2lrc_enum, SAI_LOOPBACK_LR, 6, lplrc_text);
+static SOC_ENUM_SINGLE_DECL(lp1lrc_enum, SAI_LOOPBACK_LR, 5, lplrc_text);
+static SOC_ENUM_SINGLE_DECL(lp0lrc_enum, SAI_LOOPBACK_LR, 4, lplrc_text);
+static SOC_ENUM_SINGLE_DECL(lp3lr_switch, SAI_LOOPBACK_LR, 3, lplr_text);
+static SOC_ENUM_SINGLE_DECL(lp2lr_switch, SAI_LOOPBACK_LR, 2, lplr_text);
+static SOC_ENUM_SINGLE_DECL(lp1lr_switch, SAI_LOOPBACK_LR, 1, lplr_text);
+static SOC_ENUM_SINGLE_DECL(lp0lr_switch, SAI_LOOPBACK_LR, 0, lplr_text);
+
+static int rockchip_sai_wait_time_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = WAIT_TIME_MS_MAX;
+ uinfo->value.integer.step = 1;
+
+ return 0;
+}
+
+static int rockchip_sai_rd_wait_time_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = sai->wait_time[SNDRV_PCM_STREAM_CAPTURE];
+
+ return 0;
+}
+
+static int rockchip_sai_rd_wait_time_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+
+ if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
+ return -EINVAL;
+
+ sai->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+static int rockchip_sai_wr_wait_time_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = sai->wait_time[SNDRV_PCM_STREAM_PLAYBACK];
+
+ return 0;
+}
+
+static int rockchip_sai_wr_wait_time_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+
+ if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
+ return -EINVAL;
+
+ sai->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \
+ .info = rockchip_sai_wait_time_info, \
+ .get = xhandler_get, .put = xhandler_put }
+
+static const struct snd_kcontrol_new rockchip_sai_controls[] = {
+ SOC_SINGLE_TLV("Receive Mono Slot Select", SAI_MONO_CR,
+ 2, 128, 0, rmss_tlv),
+ SOC_ENUM("Receive Mono Switch", rmono_switch),
+ SOC_ENUM("Transmit Mono Switch", tmono_switch),
+
+ SOC_ENUM("SDI3 Loopback I2S LR Channel Sel", lp3lrc_enum),
+ SOC_ENUM("SDI2 Loopback I2S LR Channel Sel", lp2lrc_enum),
+ SOC_ENUM("SDI1 Loopback I2S LR Channel Sel", lp1lrc_enum),
+ SOC_ENUM("SDI0 Loopback I2S LR Channel Sel", lp0lrc_enum),
+ SOC_ENUM("SDI3 Loopback I2S LR Switch", lp3lr_switch),
+ SOC_ENUM("SDI2 Loopback I2S LR Switch", lp2lr_switch),
+ SOC_ENUM("SDI1 Loopback I2S LR Switch", lp1lr_switch),
+ SOC_ENUM("SDI0 Loopback I2S LR Switch", lp0lr_switch),
+
+ SOC_ENUM("SDI3 Loopback Src Select", lp3_enum),
+ SOC_ENUM("SDI2 Loopback Src Select", lp2_enum),
+ SOC_ENUM("SDI1 Loopback Src Select", lp1_enum),
+ SOC_ENUM("SDI0 Loopback Src Select", lp0_enum),
+ SOC_ENUM("SDI3 Loopback Switch", lp3_switch),
+ SOC_ENUM("SDI2 Loopback Switch", lp2_switch),
+ SOC_ENUM("SDI1 Loopback Switch", lp1_switch),
+ SOC_ENUM("SDI0 Loopback Switch", lp0_switch),
+ SOC_ENUM("Sync Out Switch", sync_out_switch),
+ SOC_ENUM("Sync In Switch", sync_in_switch),
+ SOC_ENUM("Receive PATH3 Source Select", rpath3_enum),
+ SOC_ENUM("Receive PATH2 Source Select", rpath2_enum),
+ SOC_ENUM("Receive PATH1 Source Select", rpath1_enum),
+ SOC_ENUM("Receive PATH0 Source Select", rpath0_enum),
+ SOC_ENUM("Transmit SDO3 Source Select", tpath3_enum),
+ SOC_ENUM("Transmit SDO2 Source Select", tpath2_enum),
+ SOC_ENUM("Transmit SDO1 Source Select", tpath1_enum),
+ SOC_ENUM("Transmit SDO0 Source Select", tpath0_enum),
+
+ SAI_PCM_WAIT_TIME("PCM Read Wait Time MS",
+ rockchip_sai_rd_wait_time_get,
+ rockchip_sai_rd_wait_time_put),
+ SAI_PCM_WAIT_TIME("PCM Write Wait Time MS",
+ rockchip_sai_wr_wait_time_get,
+ rockchip_sai_wr_wait_time_put),
+};
+
+static const struct snd_soc_component_driver rockchip_sai_component = {
+ .name = DRV_NAME,
+ .controls = rockchip_sai_controls,
+ .num_controls = ARRAY_SIZE(rockchip_sai_controls),
+ .legacy_dai_naming = 1,
+};
+
+static irqreturn_t rockchip_sai_isr(int irq, void *devid)
+{
+ struct rk_sai_dev *sai = (struct rk_sai_dev *)devid;
+ struct snd_pcm_substream *substream;
+ u32 val;
+
+ regmap_read(sai->regmap, SAI_INTSR, &val);
+ if (val & SAI_INTSR_TXUI_ACT) {
+ dev_warn_ratelimited(sai->dev, "TX FIFO Underrun\n");
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_TXUIC, SAI_INTCR_TXUIC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_TXUIE_MASK,
+ SAI_INTCR_TXUIE(0));
+ substream = sai->substreams[SNDRV_PCM_STREAM_PLAYBACK];
+ if (substream)
+ snd_pcm_stop_xrun(substream);
+ }
+
+ if (val & SAI_INTSR_RXOI_ACT) {
+ dev_warn_ratelimited(sai->dev, "RX FIFO Overrun\n");
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_RXOIC, SAI_INTCR_RXOIC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_RXOIE_MASK,
+ SAI_INTCR_RXOIE(0));
+ substream = sai->substreams[SNDRV_PCM_STREAM_CAPTURE];
+ if (substream)
+ snd_pcm_stop_xrun(substream);
+ }
+
+ if (val & SAI_INTSR_FSERRI_ACT) {
+ dev_warn_ratelimited(sai->dev, "Frame Sync Error\n");
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSERRC, SAI_INTCR_FSERRC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSERR_MASK,
+ SAI_INTCR_FSERR(0));
+ }
+
+ if (val & SAI_INTSR_FSLOSTI_ACT) {
+ dev_warn_ratelimited(sai->dev, "Frame Sync Lost\n");
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSLOSTC, SAI_INTCR_FSLOSTC);
+ regmap_update_bits(sai->regmap, SAI_INTCR,
+ SAI_INTCR_FSLOST_MASK,
+ SAI_INTCR_FSLOST(0));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int rockchip_sai_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct rk_sai_dev *sai;
+ struct snd_soc_dai_driver *dai;
+ struct resource *res;
+ void __iomem *regs;
+ int ret, irq;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ sai->dev = &pdev->dev;
+ sai->fw_ratio = 1;
+ /* match to register default */
+ sai->is_master_mode = true;
+ dev_set_drvdata(&pdev->dev, sai);
+
+ spin_lock_init(&sai->xfer_lock);
+
+ sai->rst_h = devm_reset_control_get_optional_exclusive(&pdev->dev, "h");
+ if (IS_ERR(sai->rst_h))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sai->rst_h),
+ "Error in 'h' reset control\n");
+
+ sai->rst_m = devm_reset_control_get_optional_exclusive(&pdev->dev, "m");
+ if (IS_ERR(sai->rst_m))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sai->rst_m),
+ "Error in 'm' reset control\n");
+
+ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(regs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regs),
+ "Failed to get and ioremap resource\n");
+
+ sai->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &rockchip_sai_regmap_config);
+ if (IS_ERR(sai->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sai->regmap),
+ "Failed to initialize regmap\n");
+
+ irq = platform_get_irq_optional(pdev, 0);
+ if (irq > 0) {
+ ret = devm_request_irq(&pdev->dev, irq, rockchip_sai_isr,
+ IRQF_SHARED, node->name, sai);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to request irq %d\n", irq);
+ } else {
+ dev_dbg(&pdev->dev, "Asked for an IRQ but got %d\n", irq);
+ }
+
+ sai->mclk = devm_clk_get(&pdev->dev, "mclk");
+ if (IS_ERR(sai->mclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sai->mclk),
+ "Failed to get mclk\n");
+
+ sai->hclk = devm_clk_get_enabled(&pdev->dev, "hclk");
+ if (IS_ERR(sai->hclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sai->hclk),
+ "Failed to get hclk\n");
+
+ regmap_read(sai->regmap, SAI_VERSION, &sai->version);
+
+ ret = rockchip_sai_init_dai(sai, res, &dai);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to initialize DAI\n");
+
+ ret = rockchip_sai_parse_paths(sai, node);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to parse paths\n");
+
+ /*
+ * From here on, all register accesses need to be wrapped in
+ * pm_runtime_get_sync/pm_runtime_put calls
+ *
+ * NB: we don't rely on _resume_and_get in case of !CONFIG_PM
+ */
+ devm_pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+ ret = rockchip_sai_runtime_resume(&pdev->dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to resume device\n");
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register PCM: %d\n", ret);
+ goto err_runtime_suspend;
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &rockchip_sai_component,
+ dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+ goto err_runtime_suspend;
+ }
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
+
+ clk_disable_unprepare(sai->hclk);
+
+ return 0;
+
+err_runtime_suspend:
+ /* If we're !CONFIG_PM, we get -ENOSYS and disable manually */
+ if (pm_runtime_put(&pdev->dev))
+ rockchip_sai_runtime_suspend(&pdev->dev);
+
+ return ret;
+}
+
+static void rockchip_sai_remove(struct platform_device *pdev)
+{
+#ifndef CONFIG_PM
+ rockchip_sai_runtime_suspend(&pdev->dev);
+#endif
+}
+
+static const struct dev_pm_ops rockchip_sai_pm_ops = {
+ SET_RUNTIME_PM_OPS(rockchip_sai_runtime_suspend, rockchip_sai_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
+
+static const struct of_device_id rockchip_sai_match[] = {
+ { .compatible = "rockchip,rk3576-sai", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rockchip_sai_match);
+
+static struct platform_driver rockchip_sai_driver = {
+ .probe = rockchip_sai_probe,
+ .remove = rockchip_sai_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = rockchip_sai_match,
+ .pm = &rockchip_sai_pm_ops,
+ },
+};
+module_platform_driver(rockchip_sai_driver);
+
+MODULE_DESCRIPTION("Rockchip SAI ASoC Interface");
+MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
+MODULE_AUTHOR("Nicolas Frattaroli <nicolas.frattaroli@collabora.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/rockchip/rockchip_sai.h b/sound/soc/rockchip/rockchip_sai.h
new file mode 100644
index 000000000000..c359c5d0311c
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_sai.h
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * ALSA SoC Audio Layer - Rockchip SAI Controller driver
+ *
+ * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
+ */
+
+#ifndef _ROCKCHIP_SAI_H
+#define _ROCKCHIP_SAI_H
+
+/* XCR Transmit / Receive Control Register */
+#define SAI_XCR_START_SEL_MASK BIT(23)
+#define SAI_XCR_START_SEL_CHAINED BIT(23)
+#define SAI_XCR_START_SEL_STANDALONE 0
+#define SAI_XCR_EDGE_SHIFT_MASK BIT(22)
+#define SAI_XCR_EDGE_SHIFT_1 BIT(22)
+#define SAI_XCR_EDGE_SHIFT_0 0
+#define SAI_XCR_CSR_MASK GENMASK(21, 20)
+#define SAI_XCR_CSR(x) ((x - 1) << 20)
+#define SAI_XCR_CSR_V(v) ((((v) & SAI_XCR_CSR_MASK) >> 20) + 1)
+#define SAI_XCR_SJM_MASK BIT(19)
+#define SAI_XCR_SJM_L BIT(19)
+#define SAI_XCR_SJM_R 0
+#define SAI_XCR_FBM_MASK BIT(18)
+#define SAI_XCR_FBM_LSB BIT(18)
+#define SAI_XCR_FBM_MSB 0
+#define SAI_XCR_SNB_MASK GENMASK(17, 11)
+#define SAI_XCR_SNB(x) ((x - 1) << 11)
+#define SAI_XCR_VDJ_MASK BIT(10)
+#define SAI_XCR_VDJ_L BIT(10)
+#define SAI_XCR_VDJ_R 0
+#define SAI_XCR_SBW_MASK GENMASK(9, 5)
+#define SAI_XCR_SBW(x) ((x - 1) << 5)
+#define SAI_XCR_SBW_V(v) ((((v) & SAI_XCR_SBW_MASK) >> 5) + 1)
+#define SAI_XCR_VDW_MASK GENMASK(4, 0)
+#define SAI_XCR_VDW(x) ((x - 1) << 0)
+
+/* FSCR Frame Sync Control Register */
+#define SAI_FSCR_EDGE_MASK BIT(24)
+#define SAI_FSCR_EDGE_DUAL BIT(24)
+#define SAI_FSCR_EDGE_RISING 0
+#define SAI_FSCR_FPW_MASK GENMASK(23, 12)
+#define SAI_FSCR_FPW(x) ((x - 1) << 12)
+#define SAI_FSCR_FW_MASK GENMASK(11, 0)
+#define SAI_FSCR_FW(x) ((x - 1) << 0)
+#define SAI_FSCR_FW_V(v) ((((v) & SAI_FSCR_FW_MASK) >> 0) + 1)
+
+/* MONO_CR Mono Control Register */
+#define SAI_MCR_RX_MONO_SLOT_MASK GENMASK(8, 2)
+#define SAI_MCR_RX_MONO_SLOT_SEL(x) ((x - 1) << 2)
+#define SAI_MCR_RX_MONO_MASK BIT(1)
+#define SAI_MCR_RX_MONO_EN BIT(1)
+#define SAI_MCR_RX_MONO_DIS 0
+#define SAI_MCR_TX_MONO_MASK BIT(0)
+#define SAI_MCR_TX_MONO_EN BIT(0)
+#define SAI_MCR_TX_MONO_DIS 0
+
+/* XFER Transfer Start Register */
+#define SAI_XFER_RX_IDLE BIT(8)
+#define SAI_XFER_TX_IDLE BIT(7)
+#define SAI_XFER_FS_IDLE BIT(6)
+/*
+ * Used for TX only (VERSION >= SAI_VER_2311)
+ *
+ * SCLK/FSYNC auto gated when TX FIFO empty.
+ */
+#define SAI_XFER_TX_AUTO_MASK BIT(6)
+#define SAI_XFER_TX_AUTO_EN BIT(6)
+#define SAI_XFER_TX_AUTO_DIS 0
+#define SAI_XFER_RX_CNT_MASK BIT(5)
+#define SAI_XFER_RX_CNT_EN BIT(5)
+#define SAI_XFER_RX_CNT_DIS 0
+#define SAI_XFER_TX_CNT_MASK BIT(4)
+#define SAI_XFER_TX_CNT_EN BIT(4)
+#define SAI_XFER_TX_CNT_DIS 0
+#define SAI_XFER_RXS_MASK BIT(3)
+#define SAI_XFER_RXS_EN BIT(3)
+#define SAI_XFER_RXS_DIS 0
+#define SAI_XFER_TXS_MASK BIT(2)
+#define SAI_XFER_TXS_EN BIT(2)
+#define SAI_XFER_TXS_DIS 0
+#define SAI_XFER_FSS_MASK BIT(1)
+#define SAI_XFER_FSS_EN BIT(1)
+#define SAI_XFER_FSS_DIS 0
+#define SAI_XFER_CLK_MASK BIT(0)
+#define SAI_XFER_CLK_EN BIT(0)
+#define SAI_XFER_CLK_DIS 0
+
+/* CLR Clear Logic Register */
+#define SAI_CLR_FCR BIT(3) /* TODO: what is this? */
+#define SAI_CLR_FSC BIT(2)
+#define SAI_CLR_RXC BIT(1)
+#define SAI_CLR_TXC BIT(0)
+
+/* CKR Clock Generation Register */
+#define SAI_CKR_MDIV_MASK GENMASK(14, 3)
+#define SAI_CKR_MDIV(x) ((x - 1) << 3)
+#define SAI_CKR_MSS_MASK BIT(2)
+#define SAI_CKR_MSS_SLAVE BIT(2)
+#define SAI_CKR_MSS_MASTER 0
+#define SAI_CKR_CKP_MASK BIT(1)
+#define SAI_CKR_CKP_INVERTED BIT(1)
+#define SAI_CKR_CKP_NORMAL 0
+#define SAI_CKR_FSP_MASK BIT(0)
+#define SAI_CKR_FSP_INVERTED BIT(0)
+#define SAI_CKR_FSP_NORMAL 0
+
+/* DMACR DMA Control Register */
+#define SAI_DMACR_RDE_MASK BIT(24)
+#define SAI_DMACR_RDE(x) ((x) << 24)
+#define SAI_DMACR_RDL_MASK GENMASK(20, 16)
+#define SAI_DMACR_RDL(x) ((x - 1) << 16)
+#define SAI_DMACR_RDL_V(v) ((((v) & SAI_DMACR_RDL_MASK) >> 16) + 1)
+#define SAI_DMACR_TDE_MASK BIT(8)
+#define SAI_DMACR_TDE(x) ((x) << 8)
+#define SAI_DMACR_TDL_MASK GENMASK(4, 0)
+#define SAI_DMACR_TDL(x) ((x) << 0)
+#define SAI_DMACR_TDL_V(v) (((v) & SAI_DMACR_TDL_MASK) >> 0)
+
+/* INTCR Interrupt Ctrl Register */
+#define SAI_INTCR_FSLOSTC BIT(28)
+#define SAI_INTCR_FSLOST_MASK BIT(27)
+#define SAI_INTCR_FSLOST(x) ((x) << 27)
+#define SAI_INTCR_FSERRC BIT(26)
+#define SAI_INTCR_FSERR_MASK BIT(25)
+#define SAI_INTCR_FSERR(x) ((x) << 25)
+#define SAI_INTCR_RXOIC BIT(18)
+#define SAI_INTCR_RXOIE_MASK BIT(17)
+#define SAI_INTCR_RXOIE(x) ((x) << 17)
+#define SAI_INTCR_TXUIC BIT(2)
+#define SAI_INTCR_TXUIE_MASK BIT(1)
+#define SAI_INTCR_TXUIE(x) ((x) << 1)
+
+/* INTSR Interrupt Status Register */
+#define SAI_INTSR_FSLOSTI_INA 0
+#define SAI_INTSR_FSLOSTI_ACT BIT(19)
+#define SAI_INTSR_FSERRI_INA 0
+#define SAI_INTSR_FSERRI_ACT BIT(18)
+#define SAI_INTSR_RXOI_INA 0
+#define SAI_INTSR_RXOI_ACT BIT(17)
+#define SAI_INTSR_TXUI_INA 0
+#define SAI_INTSR_TXUI_ACT BIT(1)
+
+/* PATH_SEL: Transfer / Receive Path Select Register */
+#define SAI_RX_PATH_SHIFT(x) (8 + (x) * 2)
+#define SAI_RX_PATH_MASK(x) (0x3 << SAI_RX_PATH_SHIFT(x))
+#define SAI_RX_PATH(x, v) ((v) << SAI_RX_PATH_SHIFT(x))
+#define SAI_TX_PATH_SHIFT(x) (0 + (x) * 2)
+#define SAI_TX_PATH_MASK(x) (0x3 << SAI_TX_PATH_SHIFT(x))
+#define SAI_TX_PATH(x, v) ((v) << SAI_TX_PATH_SHIFT(x))
+
+/* XSHIFT: Transfer / Receive Frame Sync Shift Register */
+
+/*
+ * TX-ONLY: LEFT Direction Feature
+ * +------------------------------------------------+
+ * | DATA LEFTx (step: 0.5 cycle) | FSYNC Edge |
+ * +------------------------------------------------+
+ */
+#define SAI_XSHIFT_LEFT_MASK GENMASK(25, 24)
+#define SAI_XSHIFT_LEFT(x) ((x) << 24)
+/*
+ * +------------------------------------------------+
+ * | FSYNC Edge | DATA RIGHTx (step: 0.5 cycle) |
+ * +------------------------------------------------+
+ */
+#define SAI_XSHIFT_RIGHT_MASK GENMASK(23, 0)
+#define SAI_XSHIFT_RIGHT(x) (x)
+
+/* XFIFOLR: Transfer / Receive FIFO Level Register */
+#define SAI_FIFOLR_XFL3_SHIFT 18
+#define SAI_FIFOLR_XFL3_MASK GENMASK(23, 18)
+#define SAI_FIFOLR_XFL2_SHIFT 12
+#define SAI_FIFOLR_XFL2_MASK GENMASK(17, 12)
+#define SAI_FIFOLR_XFL1_SHIFT 6
+#define SAI_FIFOLR_XFL1_MASK GENMASK(11, 6)
+#define SAI_FIFOLR_XFL0_SHIFT 0
+#define SAI_FIFOLR_XFL0_MASK GENMASK(5, 0)
+
+/* STATUS Status Register (VERSION >= SAI_VER_2307) */
+#define SAI_STATUS_RX_IDLE BIT(3)
+#define SAI_STATUS_TX_IDLE BIT(2)
+#define SAI_STATUS_FS_IDLE BIT(1)
+
+/* VERSION */
+/*
+ * Updates:
+ *
+ * VERSION >= SAI_VER_2311
+ *
+ * Support Frame Sync xN (FSXN)
+ * Support Frame Sync Error Detect (FSE)
+ * Support Frame Sync Lost Detect (FSLOST)
+ * Support Force Clear (FCR)
+ * Support SAIn-Chained (e.g. SAI0-CLK-DATA + SAI3-DATA +...)
+ * Support Transmit Auto Gate Mode
+ * Support Timing Shift Left for TX
+ *
+ * Optimize SCLK/FSYNC Timing Alignment
+ *
+ * VERSION >= SAI_VER_2403
+ *
+ * Support Loopback LR Select (e.g. L:MIC R:LP)
+ *
+ */
+#define SAI_VER_2307 0x23073576
+#define SAI_VER_2311 0x23112118
+#define SAI_VER_2401 0x24013506
+#define SAI_VER_2403 0x24031103
+
+/* FS_TIMEOUT: Frame Sync Timeout Register */
+#define SAI_FS_TIMEOUT_VAL_MASK GENMASK(31, 1)
+#define SAI_FS_TIMEOUT_VAL(x) ((x) << 1)
+#define SAI_FS_TIMEOUT_EN_MASK BIT(0)
+#define SAI_FS_TIMEOUT_EN(x) ((x) << 0)
+
+/* SAI Registers */
+#define SAI_TXCR (0x0000)
+#define SAI_FSCR (0x0004)
+#define SAI_RXCR (0x0008)
+#define SAI_MONO_CR (0x000c)
+#define SAI_XFER (0x0010)
+#define SAI_CLR (0x0014)
+#define SAI_CKR (0x0018)
+#define SAI_TXFIFOLR (0x001c)
+#define SAI_RXFIFOLR (0x0020)
+#define SAI_DMACR (0x0024)
+#define SAI_INTCR (0x0028)
+#define SAI_INTSR (0x002c)
+#define SAI_TXDR (0x0030)
+#define SAI_RXDR (0x0034)
+#define SAI_PATH_SEL (0x0038)
+#define SAI_TX_SLOT_MASK0 (0x003c)
+#define SAI_TX_SLOT_MASK1 (0x0040)
+#define SAI_TX_SLOT_MASK2 (0x0044)
+#define SAI_TX_SLOT_MASK3 (0x0048)
+#define SAI_RX_SLOT_MASK0 (0x004c)
+#define SAI_RX_SLOT_MASK1 (0x0050)
+#define SAI_RX_SLOT_MASK2 (0x0054)
+#define SAI_RX_SLOT_MASK3 (0x0058)
+#define SAI_TX_DATA_CNT (0x005c)
+#define SAI_RX_DATA_CNT (0x0060)
+#define SAI_TX_SHIFT (0x0064)
+#define SAI_RX_SHIFT (0x0068)
+#define SAI_STATUS (0x006c)
+#define SAI_VERSION (0x0070)
+#define SAI_FSXN (0x0074)
+#define SAI_FS_TIMEOUT (0x0078)
+#define SAI_LOOPBACK_LR (0x007c)
+
+#endif /* _ROCKCHIP_SAI_H */
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 0b73fe94e4bb..d365168934dc 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/mfd/syscon.h>
@@ -64,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);
@@ -75,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;
@@ -202,12 +201,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops rk_spdif_dai_ops = {
+ .probe = rk_spdif_dai_probe,
.hw_params = rk_spdif_hw_params,
.trigger = rk_spdif_trigger,
};
static struct snd_soc_dai_driver rk_spdif_dai = {
- .probe = rk_spdif_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -375,17 +374,16 @@ 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 = {
.probe = rk_spdif_probe,
- .remove_new = rk_spdif_remove,
+ .remove = rk_spdif_remove,
.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/Kconfig b/sound/soc/samsung/Kconfig
index 93c2b1b08d0a..ec7204f57fd4 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SND_SOC_SAMSUNG
- tristate "ASoC support for Samsung"
+ tristate "Samsung"
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
depends on COMMON_CLK
select SND_SOC_GENERIC_DMAENGINE_PCM
@@ -127,8 +127,9 @@ config SND_SOC_SAMSUNG_TM2_WM5110
config SND_SOC_SAMSUNG_ARIES_WM8994
tristate "SoC I2S Audio support for WM8994 on Aries"
- depends on SND_SOC_SAMSUNG && MFD_WM8994 && IIO && EXTCON
+ depends on SND_SOC_SAMSUNG && I2C && IIO && EXTCON
select SND_SOC_BT_SCO
+ select MFD_WM8994
select SND_SOC_WM8994
select SND_SAMSUNG_I2S
help
@@ -140,8 +141,9 @@ config SND_SOC_SAMSUNG_ARIES_WM8994
config SND_SOC_SAMSUNG_MIDAS_WM1811
tristate "SoC I2S Audio support for Midas boards"
- depends on SND_SOC_SAMSUNG
+ depends on SND_SOC_SAMSUNG && I2C && IIO
select SND_SAMSUNG_I2S
+ select MFD_WM8994
select SND_SOC_WM8994
help
Say Y if you want to add support for SoC audio on the Midas boards.
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index f5d327b90a4e..8d5f09147900 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
# S3c24XX Platform Support
-snd-soc-s3c-dma-objs := dmaengine.o
-snd-soc-idma-objs := idma.o
-snd-soc-samsung-spdif-objs := spdif.o
-snd-soc-pcm-objs := pcm.o
-snd-soc-i2s-objs := i2s.o
+snd-soc-s3c-dma-y := dmaengine.o
+snd-soc-idma-y := idma.o
+snd-soc-samsung-spdif-y := spdif.o
+snd-soc-pcm-y := pcm.o
+snd-soc-i2s-y := i2s.o
obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o
obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
@@ -13,20 +13,20 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
# S3C24XX Machine Support
-snd-soc-smdk-wm8994-objs := smdk_wm8994.o
-snd-soc-snow-objs := snow.o
-snd-soc-smdk-spdif-objs := smdk_spdif.o
-snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
-snd-soc-speyside-objs := speyside.o
-snd-soc-tobermory-objs := tobermory.o
-snd-soc-lowland-objs := lowland.o
-snd-soc-littlemill-objs := littlemill.o
-snd-soc-bells-objs := bells.o
-snd-soc-odroid-objs := odroid.o
-snd-soc-arndale-objs := arndale.o
-snd-soc-tm2-wm5110-objs := tm2_wm5110.o
-snd-soc-aries-wm8994-objs := aries_wm8994.o
-snd-soc-midas-wm1811-objs := midas_wm1811.o
+snd-soc-smdk-wm8994-y := smdk_wm8994.o
+snd-soc-snow-y := snow.o
+snd-soc-smdk-spdif-y := smdk_spdif.o
+snd-soc-smdk-wm8994pcm-y := smdk_wm8994pcm.o
+snd-soc-speyside-y := speyside.o
+snd-soc-tobermory-y := tobermory.o
+snd-soc-lowland-y := lowland.o
+snd-soc-littlemill-y := littlemill.o
+snd-soc-bells-y := bells.o
+snd-soc-odroid-y := odroid.o
+snd-soc-arndale-y := arndale.o
+snd-soc-tm2-wm5110-y := tm2_wm5110.o
+snd-soc-aries-wm8994-y := aries_wm8994.o
+snd-soc-midas-wm1811-y := midas_wm1811.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 7492bb41456c..48ccc1d1854b 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/extcon.h>
+#include <linux/gpio/consumer.h>
#include <linux/iio/consumer.h>
#include <linux/input-event-codes.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
@@ -160,13 +159,13 @@ static struct snd_soc_jack_gpio headset_button_gpio[] = {
static int aries_spk_cfg(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *component;
int ret = 0;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- component = asoc_rtd_to_codec(rtd, 0)->component;
+ component = snd_soc_rtd_to_codec(rtd, 0)->component;
/**
* We have an odd setup - the SPKMODE pin is pulled up so
@@ -195,7 +194,7 @@ static int aries_spk_cfg(struct snd_soc_dapm_widget *w,
static int aries_main_bias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
int ret = 0;
@@ -214,7 +213,7 @@ static int aries_main_bias(struct snd_soc_dapm_widget *w,
static int aries_headset_bias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
int ret = 0;
@@ -259,8 +258,8 @@ static const struct snd_soc_dapm_widget aries_dapm_widgets[] = {
static int aries_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int pll_out;
int ret;
@@ -287,8 +286,8 @@ static int aries_hw_params(struct snd_pcm_substream *substream,
static int aries_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
/* Switch sysclk to MCLK1 */
@@ -316,7 +315,7 @@ static const struct snd_soc_ops aries_ops = {
static int aries_baseband_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int pll_out;
int ret;
@@ -475,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),
},
@@ -511,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,
};
@@ -620,10 +619,14 @@ static int aries_audio_probe(struct platform_device *pdev)
/* Update card-name if provided through DT, else use default name */
snd_soc_of_parse_card_name(card, "model");
- ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret < 0) {
- dev_err(dev, "Audio routing invalid/unspecified\n");
- return ret;
+ /* Backwards compatible way */
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0) {
+ dev_err(dev, "Audio routing invalid/unspecified\n");
+ return ret;
+ }
}
aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt;
diff --git a/sound/soc/samsung/arndale.c b/sound/soc/samsung/arndale.c
index fdff83e72d29..172943bb3b24 100644
--- a/sound/soc/samsung/arndale.c
+++ b/sound/soc/samsung/arndale.c
@@ -5,7 +5,7 @@
// Author: Claude <claude@insginal.co.kr>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -20,9 +20,9 @@
static int arndale_rt5631_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int rfs, ret;
unsigned long rclk;
@@ -55,8 +55,8 @@ static const struct snd_soc_ops arndale_rt5631_ops = {
static int arndale_wm1811_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int rfs, rclk;
/* Ensure AIF1CLK is >= 3 MHz for optimal performance */
@@ -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),
},
@@ -207,7 +207,7 @@ static struct platform_driver arndale_audio_driver = {
.of_match_table = arndale_audio_of_match,
},
.probe = arndale_audio_probe,
- .remove_new = arndale_audio_remove,
+ .remove = arndale_audio_remove,
};
module_platform_driver(arndale_audio_driver);
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 70b63d4faa99..fc4963d3b99b 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"
@@ -60,15 +59,15 @@ static int bells_set_bias_level(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
component = codec_dai->component;
- if (dapm->dev != codec_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != codec_dai->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
+ if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_STANDBY)
break;
ret = snd_soc_component_set_pll(component, WM5102_FLL1,
@@ -106,10 +105,10 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
component = codec_dai->component;
- if (dapm->dev != codec_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != codec_dai->dev)
return 0;
switch (level) {
@@ -134,8 +133,6 @@ static int bells_set_bias_level_post(struct snd_soc_card *card,
break;
}
- dapm->bias_level = level;
-
return 0;
}
@@ -152,11 +149,11 @@ static int bells_late_probe(struct snd_soc_card *card)
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_AP_DSP]);
- wm0010 = asoc_rtd_to_codec(rtd, 0)->component;
+ wm0010 = snd_soc_rtd_to_codec(rtd, 0)->component;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]);
- component = asoc_rtd_to_codec(rtd, 0)->component;
- aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
ARIZONA_CLK_SRC_FLL1,
@@ -195,7 +192,7 @@ static int bells_late_probe(struct snd_soc_card *card)
}
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_CODEC_CP]);
- aif2_dai = asoc_rtd_to_cpu(rtd, 0);
+ aif2_dai = snd_soc_rtd_to_cpu(rtd, 0);
ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
if (ret != 0) {
@@ -207,8 +204,8 @@ static int bells_late_probe(struct snd_soc_card *card)
return 0;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_CODEC_SUB]);
- aif3_dai = asoc_rtd_to_cpu(rtd, 0);
- wm9081_dai = asoc_rtd_to_codec(rtd, 0);
+ aif3_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ wm9081_dai = snd_soc_rtd_to_codec(rtd, 0);
ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
if (ret != 0) {
@@ -256,14 +253,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 +290,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 +307,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 +317,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 +348,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 +365,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 +375,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 f3d98abd5f0d..e9964f0e010a 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -13,8 +13,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
@@ -939,8 +937,8 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
{
struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct i2s_dai *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct i2s_dai *i2s = to_info(snd_soc_rtd_to_cpu(rtd, 0));
unsigned long flags;
switch (cmd) {
@@ -1120,6 +1118,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+ .probe = samsung_i2s_dai_probe,
+ .remove = samsung_i2s_dai_remove,
.trigger = i2s_trigger,
.hw_params = i2s_hw_params,
.set_fmt = i2s_set_fmt,
@@ -1188,9 +1188,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
for (i = 0; i < num_dais; i++) {
dai_drv = &priv->dai_drv[i];
- dai_drv->probe = samsung_i2s_dai_probe;
- dai_drv->remove = samsung_i2s_dai_remove;
-
dai_drv->symmetric_rate = 1;
dai_drv->ops = &samsung_i2s_dai_ops;
@@ -1219,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);
@@ -1257,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)
{
@@ -1581,8 +1576,8 @@ static void samsung_i2s_remove(struct platform_device *pdev)
static void fsd_i2s_fixup_early(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct i2s_dai *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct i2s_dai *i2s = to_info(snd_soc_rtd_to_cpu(rtd, 0));
struct i2s_dai *other = get_other_dai(i2s);
if (!is_opened(other)) {
@@ -1594,9 +1589,9 @@ static void fsd_i2s_fixup_early(struct snd_pcm_substream *substream,
static void fsd_i2s_fixup_late(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
- struct i2s_dai *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
+ struct i2s_dai *i2s = to_info(snd_soc_rtd_to_cpu(rtd, 0));
struct i2s_dai *other = get_other_dai(i2s);
if (!is_opened(other))
@@ -1736,20 +1731,18 @@ 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 = {
.probe = samsung_i2s_probe,
- .remove_new = samsung_i2s_remove,
+ .remove = samsung_i2s_remove,
.id_table = samsung_i2s_driver_ids,
.driver = {
.name = "samsung-i2s",
.of_match_table = of_match_ptr(exynos_i2s_match),
- .pm = &samsung_i2s_pm,
+ .pm = pm_ptr(&samsung_i2s_pm),
},
};
@@ -1758,5 +1751,4 @@ module_platform_driver(samsung_i2s_driver);
/* Module information */
MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
MODULE_DESCRIPTION("Samsung I2S Interface");
-MODULE_ALIAS("platform:samsung-i2s");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 5d8118e69359..d0d1b1ee326e 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"
@@ -23,9 +22,9 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != aif1_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != aif1_dai->dev)
return 0;
switch (level) {
@@ -34,7 +33,7 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
* If we've not already clocked things via hw_params()
* then do so now, otherwise these are noops.
*/
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
WM8994_FLL_SRC_MCLK2, 32768,
sample_rate * 512);
@@ -70,9 +69,9 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != aif1_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != aif1_dai->dev)
return 0;
switch (level) {
@@ -96,16 +95,14 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
break;
}
- dapm->bias_level = level;
-
return 0;
}
static int littlemill_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
sample_rate = params_rate(params);
@@ -157,7 +154,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 +162,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,
@@ -176,13 +173,13 @@ static struct snd_soc_dai_link littlemill_dai[] = {
static int bbclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai *aif2_dai;
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
- aif2_dai = asoc_rtd_to_cpu(rtd, 0);
+ aif2_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -225,12 +222,15 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
}
static const struct snd_kcontrol_new controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("WM1250 Input"),
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
};
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_HP("Headset Mic", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
@@ -255,6 +255,16 @@ static const struct snd_soc_dapm_route audio_paths[] = {
};
static struct snd_soc_jack littlemill_headset;
+static struct snd_soc_jack_pin littlemill_headset_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static int littlemill_late_probe(struct snd_soc_card *card)
{
@@ -265,11 +275,11 @@ static int littlemill_late_probe(struct snd_soc_card *card)
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- component = asoc_rtd_to_codec(rtd, 0)->component;
- aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
- aif2_dai = asoc_rtd_to_cpu(rtd, 0);
+ aif2_dai = snd_soc_rtd_to_cpu(rtd, 0);
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
32768, SND_SOC_CLOCK_IN);
@@ -281,12 +291,14 @@ static int littlemill_late_probe(struct snd_soc_card *card)
if (ret < 0)
return ret;
- ret = snd_soc_card_jack_new(card, "Headset",
- SND_JACK_HEADSET | SND_JACK_MECHANICAL |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &littlemill_headset);
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4 | SND_JACK_BTN_5,
+ &littlemill_headset,
+ littlemill_headset_pins,
+ ARRAY_SIZE(littlemill_headset_pins));
if (ret)
return ret;
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 106770be6fc5..ca9b78007dfe 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"
@@ -22,17 +21,21 @@ static struct snd_soc_jack lowland_headset;
static struct snd_soc_jack_pin lowland_headset_pins[] = {
{
.pin = "Headphone",
- .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
+ .mask = SND_JACK_HEADPHONE,
},
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
ret = snd_soc_component_set_sysclk(component, WM5100_CLK_SYSCLK,
@@ -66,9 +69,10 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(rtd->card);
- snd_soc_dapm_nc_pin(&rtd->card->dapm, "LINEOUT");
+ snd_soc_dapm_disable_pin(dapm, "LINEOUT");
/* At any time the WM9081 is active it will have this clock */
return snd_soc_component_set_sysclk(component, WM9081_SYSCLK_MCLK, 0,
@@ -101,7 +105,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),
},
@@ -109,7 +113,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),
},
@@ -117,7 +121,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,
@@ -140,11 +144,13 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("WM1250 Input"),
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SPK("Main Speaker", NULL),
diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index 6931b9a45b3e..bc34dbbb50c9 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -7,12 +7,11 @@
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
+#include <linux/iio/consumer.h>
#include <linux/mfd/wm8994/registers.h>
+#include <linux/input-event-codes.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/regulator/consumer.h>
#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -29,21 +28,144 @@
#define DEFAULT_FLL1_RATE 11289600U
struct midas_priv {
- struct regulator *reg_mic_bias;
- struct regulator *reg_submic_bias;
struct gpio_desc *gpio_fm_sel;
struct gpio_desc *gpio_lineout_sel;
+ struct gpio_desc *gpio_headset_detect;
+ struct gpio_desc *gpio_headset_key;
+ struct iio_channel *adc_headset_detect;
unsigned int fll1_rate;
struct snd_soc_jack headset_jack;
};
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+/*
+ * min_mv/max_mv values in this struct are set up based on DT values.
+ */
+static struct snd_soc_jack_zone headset_jack_zones[] = {
+ { .jack_type = SND_JACK_HEADPHONE, },
+ { .jack_type = SND_JACK_HEADSET, },
+ { .jack_type = SND_JACK_HEADPHONE, },
+};
+
+/*
+ * This is used for manual detection in headset_key_check, we reuse the
+ * structure since it's convenient.
+ *
+ * min_mv/max_mv values in this struct are set up based on DT values.
+ */
+static struct snd_soc_jack_zone headset_key_zones[] = {
+ { .jack_type = SND_JACK_BTN_0, }, /* Media */
+ { .jack_type = SND_JACK_BTN_1, }, /* Volume Up */
+ { .jack_type = SND_JACK_BTN_2, }, /* Volume Down */
+};
+
+static int headset_jack_check(void *data)
+{
+ struct snd_soc_component *codec = data;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(codec);
+ struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card);
+ int adc, ret;
+ int jack_type = 0;
+
+ if (!gpiod_get_value_cansleep(priv->gpio_headset_detect))
+ return 0;
+
+ /* Enable headset mic bias regulator so that the ADC reading works */
+ ret = snd_soc_dapm_force_enable_pin(dapm, "headset-mic-bias");
+ if (ret < 0) {
+ pr_err("%s: Failed to enable headset mic bias regulator (%d), assuming headphones\n",
+ __func__, ret);
+ return SND_JACK_HEADPHONE;
+ }
+ snd_soc_dapm_sync(dapm);
+
+ /* Sleep for a small amount of time to get the value to stabilize */
+ msleep(20);
+
+ ret = iio_read_channel_processed(priv->adc_headset_detect, &adc);
+ if (ret) {
+ pr_err("%s: Failed to read ADC (%d), assuming headphones\n",
+ __func__, ret);
+ jack_type = SND_JACK_HEADPHONE;
+ goto out;
+ }
+ pr_debug("%s: ADC value is %d\n", __func__, adc);
+
+ jack_type = snd_soc_jack_get_type(&priv->headset_jack, adc);
+
+out:
+ ret = snd_soc_dapm_disable_pin(dapm, "headset-mic-bias");
+ if (ret < 0)
+ pr_err("%s: Failed to disable headset mic bias regulator (%d)\n",
+ __func__, ret);
+ snd_soc_dapm_sync(dapm);
+
+ return jack_type;
+}
+
+static int headset_key_check(void *data)
+{
+ struct snd_soc_component *codec = data;
+ struct midas_priv *priv = snd_soc_card_get_drvdata(codec->card);
+ int adc, i, ret;
+
+ if (!gpiod_get_value_cansleep(priv->gpio_headset_key))
+ return 0;
+
+ /* Filter out keypresses when 4 pole jack not detected */
+ if (!(priv->headset_jack.status & SND_JACK_MICROPHONE))
+ return 0;
+
+ ret = iio_read_channel_processed(priv->adc_headset_detect, &adc);
+ if (ret) {
+ pr_err("%s: Failed to read ADC (%d), can't detect key type\n",
+ __func__, ret);
+ return 0;
+ }
+ pr_debug("%s: ADC value is %d\n", __func__, adc);
+
+ for (i = 0; i < ARRAY_SIZE(headset_key_zones); i++) {
+ if (adc >= headset_key_zones[i].min_mv &&
+ adc <= headset_key_zones[i].max_mv) {
+ return headset_key_zones[i].jack_type;
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_jack_gpio headset_gpio[] = {
+ {
+ .name = "Headset Jack",
+ .report = SND_JACK_HEADSET,
+ .debounce_time = 150,
+ .jack_status_check = headset_jack_check,
+ },
+ {
+ .name = "Headset Key",
+ .report = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+ .debounce_time = 30,
+ .jack_status_check = headset_key_check,
+ },
+};
+
static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
{
struct snd_soc_card *card = rtd->card;
struct midas_priv *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
if (!rate)
@@ -94,7 +216,7 @@ static int midas_stop_fll1(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct midas_priv *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
@@ -118,7 +240,7 @@ static int midas_stop_fll1(struct snd_soc_pcm_runtime *rtd)
static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
unsigned int pll_out;
/* AIF1CLK should be at least 3MHz for "optimal performance" */
@@ -160,42 +282,10 @@ static int midas_ext_spkmode(struct snd_soc_dapm_widget *w,
return ret;
}
-static int midas_mic_bias(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_card *card = w->dapm->card;
- struct midas_priv *priv = snd_soc_card_get_drvdata(card);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- return regulator_enable(priv->reg_mic_bias);
- case SND_SOC_DAPM_POST_PMD:
- return regulator_disable(priv->reg_mic_bias);
- }
-
- return 0;
-}
-
-static int midas_submic_bias(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_card *card = w->dapm->card;
- struct midas_priv *priv = snd_soc_card_get_drvdata(card);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- return regulator_enable(priv->reg_submic_bias);
- case SND_SOC_DAPM_POST_PMD:
- return regulator_disable(priv->reg_submic_bias);
- }
-
- return 0;
-}
-
static int midas_fm_set(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct midas_priv *priv = snd_soc_card_get_drvdata(card);
if (!priv->gpio_fm_sel)
@@ -216,7 +306,7 @@ static int midas_fm_set(struct snd_soc_dapm_widget *w,
static int midas_line_set(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct midas_priv *priv = snd_soc_card_get_drvdata(card);
if (!priv->gpio_lineout_sel)
@@ -261,9 +351,21 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
SND_SOC_DAPM_LINE("HDMI", NULL),
SND_SOC_DAPM_LINE("FM In", midas_fm_set),
+ SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
- SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("headset-mic-bias", 0, 0),
+ SND_SOC_DAPM_MIC("Main Mic", NULL),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("mic-bias", 0, 0),
+ SND_SOC_DAPM_MIC("Sub Mic", NULL),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("submic-bias", 0, 0),
+};
+
+/* Default routing; supplemented by audio-routing DT property */
+static const struct snd_soc_dapm_route midas_dapm_routes[] = {
+ /* Bind microphones with their respective regulator supplies */
+ {"Main Mic", NULL, "mic-bias"},
+ {"Sub Mic", NULL, "submic-bias"},
+ {"Headset Mic", NULL, "headset-mic-bias"},
};
static int midas_set_bias_level(struct snd_soc_card *card,
@@ -272,9 +374,9 @@ static int midas_set_bias_level(struct snd_soc_card *card,
{
struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
&card->dai_link[0]);
- struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != aif1_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != aif1_dai->dev)
return 0;
switch (level) {
@@ -293,7 +395,7 @@ static int midas_late_probe(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
&card->dai_link[0]);
- struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
struct midas_priv *priv = snd_soc_card_get_drvdata(card);
int ret;
@@ -305,16 +407,67 @@ static int midas_late_probe(struct snd_soc_card *card)
return ret;
}
- ret = snd_soc_card_jack_new(card, "Headset",
- SND_JACK_HEADSET | SND_JACK_MECHANICAL |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &priv->headset_jack);
- if (ret)
+ if (!priv->gpio_headset_detect) {
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4 | SND_JACK_BTN_5,
+ &priv->headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
+ if (ret)
+ return ret;
+
+ wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
+ NULL, NULL, NULL, NULL);
+ } else {
+ /* Some devices (n8000, t310) use a GPIO to detect the jack. */
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2,
+ &priv->headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
+ if (ret) {
+ dev_err(card->dev,
+ "Failed to set up headset pins: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_jack_add_zones(&priv->headset_jack,
+ ARRAY_SIZE(headset_jack_zones),
+ headset_jack_zones);
+ if (ret) {
+ dev_err(card->dev,
+ "Failed to set up headset zones: %d\n", ret);
+ return ret;
+ }
+
+ headset_gpio[0].data = aif1_dai->component;
+ headset_gpio[0].desc = priv->gpio_headset_detect;
+
+ headset_gpio[1].data = aif1_dai->component;
+ headset_gpio[1].desc = priv->gpio_headset_key;
+
+ snd_jack_set_key(priv->headset_jack.jack,
+ SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(priv->headset_jack.jack,
+ SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(priv->headset_jack.jack,
+ SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+
+ ret = snd_soc_jack_add_gpios(&priv->headset_jack,
+ ARRAY_SIZE(headset_gpio),
+ headset_gpio);
+ if (ret)
+ dev_err(card->dev,
+ "Failed to set up headset jack GPIOs: %d\n",
+ ret);
+
return ret;
+ }
- wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
- NULL, NULL, NULL, NULL);
return 0;
}
@@ -384,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",
@@ -409,6 +562,8 @@ static struct snd_soc_card midas_card = {
.num_controls = ARRAY_SIZE(midas_controls),
.dapm_widgets = midas_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets),
+ .dapm_routes = midas_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(midas_dapm_routes),
.set_bias_level = midas_set_bias_level,
.late_probe = midas_late_probe,
@@ -421,6 +576,9 @@ static int midas_probe(struct platform_device *pdev)
struct snd_soc_card *card = &midas_card;
struct device *dev = &pdev->dev;
static struct snd_soc_dai_link *dai_link;
+ enum iio_chan_type channel_type;
+ u32 fourpole_threshold[2];
+ u32 button_threshold[3];
struct midas_priv *priv;
int ret, i;
@@ -431,29 +589,99 @@ static int midas_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, priv);
card->dev = dev;
- priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias");
- if (IS_ERR(priv->reg_mic_bias)) {
- dev_err(dev, "Failed to get mic bias regulator\n");
- return PTR_ERR(priv->reg_mic_bias);
- }
-
- priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias");
- if (IS_ERR(priv->reg_submic_bias)) {
- dev_err(dev, "Failed to get submic bias regulator\n");
- return PTR_ERR(priv->reg_submic_bias);
- }
-
priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH);
- if (IS_ERR(priv->gpio_fm_sel)) {
- dev_err(dev, "Failed to get FM selection GPIO\n");
- return PTR_ERR(priv->gpio_fm_sel);
- }
+ if (IS_ERR(priv->gpio_fm_sel))
+ return dev_err_probe(dev, PTR_ERR(priv->gpio_fm_sel),
+ "Failed to get FM selection GPIO\n");
priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel",
GPIOD_OUT_HIGH);
- if (IS_ERR(priv->gpio_lineout_sel)) {
- dev_err(dev, "Failed to get line out selection GPIO\n");
- return PTR_ERR(priv->gpio_lineout_sel);
+ if (IS_ERR(priv->gpio_lineout_sel))
+ return dev_err_probe(dev, PTR_ERR(priv->gpio_lineout_sel),
+ "Failed to get line out selection GPIO\n");
+
+ priv->gpio_headset_detect = devm_gpiod_get_optional(dev,
+ "headset-detect", GPIOD_IN);
+ if (IS_ERR(priv->gpio_headset_detect))
+ return dev_err_probe(dev, PTR_ERR(priv->gpio_headset_detect),
+ "Failed to get headset jack detect GPIO\n");
+
+ if (priv->gpio_headset_detect) {
+ priv->adc_headset_detect = devm_iio_channel_get(dev,
+ "headset-detect");
+ if (IS_ERR(priv->adc_headset_detect))
+ return dev_err_probe(dev,
+ PTR_ERR(priv->adc_headset_detect),
+ "Failed to get ADC channel\n");
+
+ ret = iio_get_channel_type(priv->adc_headset_detect,
+ &channel_type);
+ if (ret) {
+ dev_err(dev, "Failed to get ADC channel type\n");
+ return ret;
+ }
+
+ if (channel_type != IIO_VOLTAGE) {
+ dev_err(dev, "ADC channel is not voltage\n");
+ return -EINVAL;
+ }
+
+ priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key",
+ GPIOD_IN);
+ if (IS_ERR(priv->gpio_headset_key))
+ return dev_err_probe(dev,
+ PTR_ERR(priv->gpio_headset_key),
+ "Failed to get headset key GPIO\n");
+
+ ret = of_property_read_u32_array(dev->of_node,
+ "samsung,headset-4pole-threshold-microvolt",
+ fourpole_threshold,
+ ARRAY_SIZE(fourpole_threshold));
+ if (ret) {
+ dev_err(dev, "Failed to get 4-pole jack detection threshold\n");
+ return ret;
+ }
+
+ if (fourpole_threshold[0] > fourpole_threshold[1]) {
+ dev_err(dev, "Invalid 4-pole jack detection threshold value\n");
+ return -EINVAL;
+ }
+
+ headset_jack_zones[0].max_mv = (fourpole_threshold[0]);
+ headset_jack_zones[1].min_mv = (fourpole_threshold[0] + 1);
+
+ headset_jack_zones[1].max_mv = (fourpole_threshold[1]);
+ headset_jack_zones[2].min_mv = (fourpole_threshold[1] + 1);
+
+ ret = of_property_read_u32_array(dev->of_node,
+ "samsung,headset-button-threshold-microvolt",
+ button_threshold,
+ ARRAY_SIZE(button_threshold));
+ if (ret) {
+ dev_err(dev, "Failed to get headset button detection threshold\n");
+ return ret;
+ }
+
+ if (button_threshold[0] > button_threshold[1] ||
+ button_threshold[1] > button_threshold[2]) {
+ dev_err(dev, "Invalid headset button detection threshold value\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (i != 0 && button_threshold[i] <= 0) {
+ dev_err(dev, "Invalid headset button detection threshold value\n");
+ return -EINVAL;
+ }
+
+ headset_key_zones[i].min_mv = button_threshold[i];
+
+ if (i == 2)
+ headset_key_zones[i].max_mv = UINT_MAX;
+ else
+ headset_key_zones[i].max_mv = \
+ (button_threshold[i+1] - 1);
+ }
}
ret = snd_soc_of_parse_card_name(card, "model");
@@ -462,10 +690,14 @@ static int midas_probe(struct platform_device *pdev)
return ret;
}
- ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret < 0) {
- dev_err(dev, "Audio routing invalid/unspecified\n");
- return ret;
+ /* Backwards compatible way */
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0) {
+ dev_err(dev, "Audio routing invalid/unspecified\n");
+ return ret;
+ }
}
cpu = of_get_child_by_name(dev->of_node, "cpu");
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index fd95a79cc9fa..ab3398f39f4a 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -5,7 +5,6 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -35,7 +34,7 @@ static int odroid_card_fe_startup(struct snd_pcm_substream *substream)
static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
unsigned long flags;
int ret = 0;
@@ -56,7 +55,7 @@ static const struct snd_soc_ops odroid_card_fe_ops = {
static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
unsigned int pll_freq, rclk_freq, rfs;
unsigned long flags;
@@ -98,7 +97,7 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
return ret;
if (rtd->dai_link->num_codecs > 1) {
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 1);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 1);
ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq,
SND_SOC_CLOCK_IN);
@@ -115,7 +114,7 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
static int odroid_card_be_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
unsigned long flags;
@@ -158,8 +157,7 @@ SND_SOC_DAILINK_DEFS(primary,
SND_SOC_DAILINK_DEFS(mixer,
DAILINK_COMP_ARRAY(COMP_DUMMY()),
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_DUMMY()));
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(secondary,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
@@ -173,25 +171,24 @@ static struct snd_soc_dai_link odroid_card_dais[] = {
.name = "Primary",
.stream_name = "Primary",
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(primary),
}, {
/* BE <-> CODECs link */
.name = "I2S Mixer",
.ops = &odroid_card_be_ops,
.no_pcm = 1,
- .dpcm_playback = 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 */
- .playback_only = 1,
.ops = &odroid_card_fe_ops,
.name = "Secondary",
.stream_name = "Secondary",
.dynamic = 1,
- .dpcm_playback = 1,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(secondary),
}
};
@@ -205,7 +202,6 @@ static int odroid_audio_probe(struct platform_device *pdev)
struct snd_soc_card *card;
struct snd_soc_dai_link *link, *codec_link;
int num_pcms, ret, i;
- struct of_phandle_args args = {};
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -224,19 +220,20 @@ static int odroid_audio_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) {
+ if (of_property_present(dev->of_node, "samsung,audio-widgets")) {
ret = snd_soc_of_parse_audio_simple_widgets(card,
"samsung,audio-widgets");
if (ret < 0)
return ret;
}
- if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) {
- ret = snd_soc_of_parse_audio_routing(card,
- "samsung,audio-routing");
- if (ret < 0)
- return ret;
- }
+ ret = 0;
+ if (of_property_present(dev->of_node, "audio-routing"))
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ else if (of_property_present(dev->of_node, "samsung,audio-routing"))
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0)
+ return ret;
card->dai_link = odroid_card_dais;
card->num_links = ARRAY_SIZE(odroid_card_dais);
@@ -260,20 +257,7 @@ static int odroid_audio_probe(struct platform_device *pdev)
}
for (i = 0; i < num_pcms; i++, link += 2) {
- ret = of_parse_phandle_with_args(cpu, "sound-dai",
- "#sound-dai-cells", i, &args);
- if (ret < 0)
- break;
-
- if (!args.np) {
- dev_err(dev, "sound-dai property parse error: %d\n", ret);
- ret = -EINVAL;
- break;
- }
-
- ret = snd_soc_get_dai_name(&args, &link->cpus->dai_name);
- of_node_put(args.np);
-
+ ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name, i);
if (ret < 0)
break;
}
@@ -293,8 +277,8 @@ static int odroid_audio_probe(struct platform_device *pdev)
/* Set capture capability only for boards with the MAX98090 CODEC */
if (codec_link->num_codecs > 1) {
- card->dai_link[0].dpcm_capture = 1;
- card->dai_link[1].dpcm_capture = 1;
+ card->dai_link[0].playback_only = 0;
+ card->dai_link[1].playback_only = 0;
}
priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1");
@@ -356,7 +340,7 @@ static struct platform_driver odroid_audio_driver = {
.pm = &snd_soc_pm_ops,
},
.probe = odroid_audio_probe,
- .remove_new = odroid_audio_remove,
+ .remove = odroid_audio_remove,
};
module_platform_driver(odroid_audio_driver);
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 335fe5cb9cfc..a03ba9374c2e 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -216,8 +216,8 @@ static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
unsigned long flags;
dev_dbg(pcm->dev, "Entered %s\n", __func__);
@@ -260,8 +260,8 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *socdai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
void __iomem *regs = pcm->regs;
struct clk *clk;
int sclk_div, sync_div;
@@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
return 0;
}
-static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
- .set_sysclk = s3c_pcm_set_sysclk,
- .set_clkdiv = s3c_pcm_set_clkdiv,
- .trigger = s3c_pcm_trigger,
- .hw_params = s3c_pcm_hw_params,
- .set_fmt = s3c_pcm_set_fmt,
-};
-
static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
{
struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai);
@@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+ .probe = s3c_pcm_dai_probe,
+ .set_sysclk = s3c_pcm_set_sysclk,
+ .set_clkdiv = s3c_pcm_set_clkdiv,
+ .trigger = s3c_pcm_trigger,
+ .hw_params = s3c_pcm_hw_params,
+ .set_fmt = s3c_pcm_set_fmt,
+};
+
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
#define S3C_PCM_DAI_DECLARE \
.symmetric_rate = 1, \
- .probe = s3c_pcm_dai_probe, \
.ops = &s3c_pcm_dai_ops, \
.playback = { \
.channels_min = 2, \
@@ -590,7 +590,7 @@ static void s3c_pcm_dev_remove(struct platform_device *pdev)
static struct platform_driver s3c_pcm_driver = {
.probe = s3c_pcm_dev_probe,
- .remove_new = s3c_pcm_dev_remove,
+ .remove = s3c_pcm_dev_remove,
.driver = {
.name = "samsung-pcm",
},
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index 6f3eeb7bc834..2474eb619882 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -100,8 +100,8 @@ static int set_audio_clock_rate(unsigned long epll_rate,
static int smdk_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned long pll_out, rclk_rate;
int ret, ratio;
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 821ad1eb1b79..911f56b12f0a 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -5,7 +5,6 @@
#include <sound/soc.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
/*
* Default CFG switch settings to use this driver:
@@ -32,20 +31,11 @@
/* SMDK has a 16.934MHZ crystal attached to WM8994 */
#define SMDK_WM8994_FREQ 16934000
-struct smdk_wm8994_data {
- int mclk1_rate;
-};
-
-/* Default SMDKs */
-static struct smdk_wm8994_data smdk_board_data = {
- .mclk1_rate = SMDK_WM8994_FREQ,
-};
-
static int smdk_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int pll_out;
int ret;
@@ -79,23 +69,23 @@ static const struct snd_soc_ops smdk_ops = {
static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(rtd->card);
/* Other pins NC */
- snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
- snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
- snd_soc_dapm_nc_pin(dapm, "SPKOUTLN");
- snd_soc_dapm_nc_pin(dapm, "SPKOUTLP");
- snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
- snd_soc_dapm_nc_pin(dapm, "SPKOUTRN");
- snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
- snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
- snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
- snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
- snd_soc_dapm_nc_pin(dapm, "IN1LP");
- snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
- snd_soc_dapm_nc_pin(dapm, "IN1RP");
- snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
+ snd_soc_dapm_disable_pin(dapm, "HPOUT2P");
+ snd_soc_dapm_disable_pin(dapm, "HPOUT2N");
+ snd_soc_dapm_disable_pin(dapm, "SPKOUTLN");
+ snd_soc_dapm_disable_pin(dapm, "SPKOUTLP");
+ snd_soc_dapm_disable_pin(dapm, "SPKOUTRP");
+ snd_soc_dapm_disable_pin(dapm, "SPKOUTRN");
+ snd_soc_dapm_disable_pin(dapm, "LINEOUT1N");
+ snd_soc_dapm_disable_pin(dapm, "LINEOUT1P");
+ snd_soc_dapm_disable_pin(dapm, "LINEOUT2N");
+ snd_soc_dapm_disable_pin(dapm, "LINEOUT2P");
+ snd_soc_dapm_disable_pin(dapm, "IN1LP");
+ snd_soc_dapm_disable_pin(dapm, "IN2LP:VXRN");
+ snd_soc_dapm_disable_pin(dapm, "IN1RP");
+ snd_soc_dapm_disable_pin(dapm, "IN2RP:VXRP");
return 0;
}
@@ -116,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),
},
@@ -136,8 +126,8 @@ static struct snd_soc_card smdk = {
.num_links = ARRAY_SIZE(smdk_dai),
};
-static const struct of_device_id samsung_wm8994_of_match[] __maybe_unused = {
- { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
+static const struct of_device_id samsung_wm8994_of_match[] = {
+ { .compatible = "samsung,smdk-wm8994" },
{},
};
MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
@@ -147,15 +137,9 @@ static int smdk_audio_probe(struct platform_device *pdev)
int ret;
struct device_node *np = pdev->dev.of_node;
struct snd_soc_card *card = &smdk;
- struct smdk_wm8994_data *board;
- const struct of_device_id *id;
card->dev = &pdev->dev;
- board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
- if (!board)
- return -ENOMEM;
-
if (np) {
smdk_dai[0].cpus->dai_name = NULL;
smdk_dai[0].cpus->of_node = of_parse_phandle(np,
@@ -171,12 +155,6 @@ static int smdk_audio_probe(struct platform_device *pdev)
smdk_dai[0].platforms->of_node = smdk_dai[0].cpus->of_node;
}
- id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
- if (id)
- *board = *((struct smdk_wm8994_data *)id->data);
-
- platform_set_drvdata(pdev, board);
-
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
@@ -188,7 +166,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
static struct platform_driver smdk_audio_driver = {
.driver = {
.name = "smdk-audio-wm8994",
- .of_match_table = of_match_ptr(samsung_wm8994_of_match),
+ .of_match_table = samsung_wm8994_of_match,
.pm = &snd_soc_pm_ops,
},
.probe = smdk_audio_probe,
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
index d77dc54cae9c..a3f539fbde5f 100644
--- a/sound/soc/samsung/smdk_wm8994pcm.c
+++ b/sound/soc/samsung/smdk_wm8994pcm.c
@@ -43,9 +43,9 @@
static int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned long mclk_freq;
int rfs, ret;
@@ -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 334080e631af..66ef49dff1ba 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -30,7 +29,7 @@ static int snow_card_hw_params(struct snd_pcm_substream *substream,
static const unsigned int pll_rate[] = {
73728000U, 67737602U, 49152000U, 45158401U, 32768001U
};
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snow_priv *priv = snd_soc_card_get_drvdata(rtd->card);
int bfs, psr, rfs, bitwidth;
unsigned long int rclk;
@@ -109,7 +108,7 @@ static int snow_late_probe(struct snd_soc_card *card)
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
/* In the multi-codec case codec_dais 0 is MAX98095 and 1 is HDMI. */
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
/* Set the MCLK rate for the codec */
return snd_soc_dai_set_sysclk(codec_dai, 0,
@@ -138,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;
@@ -246,7 +245,7 @@ static struct platform_driver snow_driver = {
.of_match_table = snow_of_match,
},
.probe = snow_probe,
- .remove_new = snow_remove,
+ .remove = snow_remove,
};
module_platform_driver(snow_driver);
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 28dc1bbfc8e7..235d0063d1b3 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -141,8 +141,8 @@ static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct samsung_spdif_info *spdif = to_info(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct samsung_spdif_info *spdif = to_info(snd_soc_rtd_to_cpu(rtd, 0));
unsigned long flags;
dev_dbg(spdif->dev, "Entered %s\n", __func__);
@@ -177,8 +177,8 @@ static int spdif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *socdai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct samsung_spdif_info *spdif = to_info(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct samsung_spdif_info *spdif = to_info(snd_soc_rtd_to_cpu(rtd, 0));
void __iomem *regs = spdif->regs;
struct snd_dmaengine_dai_dma_data *dma_data;
u32 con, clkcon, cstas;
@@ -194,7 +194,7 @@ static int spdif_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- snd_soc_dai_set_dma_data(asoc_rtd_to_cpu(rtd, 0), substream, dma_data);
+ snd_soc_dai_set_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream, dma_data);
spin_lock_irqsave(&spdif->lock, flags);
@@ -279,8 +279,8 @@ err:
static void spdif_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct samsung_spdif_info *spdif = to_info(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct samsung_spdif_info *spdif = to_info(snd_soc_rtd_to_cpu(rtd, 0));
void __iomem *regs = spdif->regs;
u32 con, clkcon;
@@ -476,7 +476,7 @@ static void spdif_remove(struct platform_device *pdev)
static struct platform_driver samsung_spdif_driver = {
.probe = spdif_probe,
- .remove_new = spdif_remove,
+ .remove = spdif_remove,
.driver = {
.name = "samsung-spdif",
},
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 22e2ad63d64d..26701a55fe0a 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,
@@ -25,9 +25,9 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != codec_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != codec_dai->dev)
return 0;
switch (level) {
@@ -61,14 +61,14 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != codec_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != codec_dai->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
ret = snd_soc_dai_set_pll(codec_dai, 0,
WM8996_FLL_MCLK2,
32768, MCLK_AUDIO_RATE);
@@ -90,8 +90,6 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
break;
}
- card->dapm.bias_level = level;
-
return 0;
}
@@ -105,15 +103,16 @@ 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;
static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
- if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
+ if (speyside_jack_polarity && (snd_soc_dapm_widget_name_cmp(source, "MICB1") == 0))
return 1;
- if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
+ if (!speyside_jack_polarity && (snd_soc_dapm_widget_name_cmp(source, "MICB2") == 0))
return 1;
return 0;
@@ -123,15 +122,15 @@ 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));
+ snd_soc_dapm_sync(snd_soc_component_to_dapm(component));
}
static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
int ret;
ret = snd_soc_dai_set_sysclk(dai, 0, MCLK_AUDIO_RATE, 0);
@@ -143,18 +142,24 @@ static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+ 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 |
@@ -172,13 +177,15 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
static int speyside_late_probe(struct snd_soc_card *card)
{
- snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
- snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
- snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC");
- snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC");
- snd_soc_dapm_ignore_suspend(&card->dapm, "Main Speaker");
- snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output");
- snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input");
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+
+ snd_soc_dapm_ignore_suspend(dapm, "Headphone");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Main AMIC");
+ snd_soc_dapm_ignore_suspend(dapm, "Main DMIC");
+ snd_soc_dapm_ignore_suspend(dapm, "Main Speaker");
+ snd_soc_dapm_ignore_suspend(dapm, "WM1250 Output");
+ snd_soc_dapm_ignore_suspend(dapm, "WM1250 Input");
return 0;
}
@@ -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 d611ec9e5325..f1f59e059f5d 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>
@@ -92,8 +91,8 @@ static int tm2_stop_sysclk(struct snd_soc_card *card)
static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
switch (params_rate(params)) {
@@ -133,8 +132,8 @@ static const struct snd_soc_ops tm2_aif1_ops = {
static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
unsigned int asyncclk_rate;
int ret;
@@ -187,8 +186,8 @@ static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
int ret;
/* disable FLL2 */
@@ -208,8 +207,8 @@ static const struct snd_soc_ops tm2_aif2_ops = {
static int tm2_hdmi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
unsigned int bfs;
int bitwidth, ret;
@@ -261,7 +260,7 @@ static const struct snd_soc_ops tm2_hdmi_ops = {
static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
switch (event) {
@@ -280,16 +279,17 @@ static int tm2_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
+ struct snd_soc_dapm_context *card_dapm = snd_soc_card_to_dapm(card);
struct snd_soc_pcm_runtime *rtd;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- if (dapm->dev != asoc_rtd_to_codec(rtd, 0)->dev)
+ if (snd_soc_dapm_to_dev(dapm) != snd_soc_rtd_to_codec(rtd, 0)->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_STANDBY:
- if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
+ if (snd_soc_dapm_get_bias_level(card_dapm) == SND_SOC_BIAS_OFF)
tm2_start_sysclk(card);
break;
case SND_SOC_BIAS_OFF:
@@ -315,8 +315,8 @@ static int tm2_late_probe(struct snd_soc_card *card)
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF1]);
- aif1_dai = asoc_rtd_to_codec(rtd, 0);
- priv->component = asoc_rtd_to_codec(rtd, 0)->component;
+ aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
+ priv->component = snd_soc_rtd_to_codec(rtd, 0)->component;
ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
if (ret < 0) {
@@ -325,7 +325,7 @@ static int tm2_late_probe(struct snd_soc_card *card)
}
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF2]);
- aif2_dai = asoc_rtd_to_codec(rtd, 0);
+ aif2_dai = snd_soc_rtd_to_codec(rtd, 0);
ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
if (ret < 0) {
@@ -451,21 +451,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 +473,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),
}
};
@@ -523,10 +523,14 @@ static int tm2_probe(struct platform_device *pdev)
return ret;
}
- ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret < 0) {
- dev_err(dev, "Audio routing is not specified or invalid\n");
- return ret;
+ /* Backwards compatible way */
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0) {
+ dev_err(dev, "Audio routing is not specified or invalid\n");
+ return ret;
+ }
}
card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node,
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 9287a1d0eef1..5448c16199bd 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"
@@ -23,14 +22,14 @@ static int tobermory_set_bias_level(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != codec_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != codec_dai->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_PREPARE:
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+ if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_STANDBY) {
ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
WM8962_FLL_MCLK, 32768,
sample_rate * 512);
@@ -66,9 +65,9 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card,
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
- if (dapm->dev != codec_dai->dev)
+ if (snd_soc_dapm_to_dev(dapm) != codec_dai->dev)
return 0;
switch (level) {
@@ -92,8 +91,6 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card,
break;
}
- dapm->bias_level = level;
-
return 0;
}
@@ -119,7 +116,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),
},
@@ -181,8 +178,8 @@ static int tobermory_late_probe(struct snd_soc_card *card)
int ret;
rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
- component = asoc_rtd_to_codec(rtd, 0)->component;
- codec_dai = asoc_rtd_to_codec(rtd, 0);
+ component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
32768, SND_SOC_CLOCK_IN);
diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig
new file mode 100644
index 000000000000..fabb69a3450d
--- /dev/null
+++ b/sound/soc/sdca/Kconfig
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "SoundWire (SDCA)"
+
+config SND_SOC_SDCA
+ tristate
+ depends on ACPI
+ select AUXILIARY_BUS
+ help
+ This option enables support for the MIPI SoundWire Device
+ Class for Audio (SDCA).
+
+config SND_SOC_SDCA_HID
+ bool "SDCA HID support"
+ depends on SND_SOC_SDCA
+ depends on HID=y || HID=SND_SOC_SDCA
+ default y
+ help
+ This option enables support for audio jack button reporting using HID.
+
+config SND_SOC_SDCA_IRQ
+ bool "SDCA IRQ support"
+ select REGMAP
+ select REGMAP_IRQ
+ depends on SND_SOC_SDCA
+ default y
+ help
+ This option enables support for SDCA IRQs.
+
+config SND_SOC_SDCA_FDL
+ bool "SDCA FDL (File DownLoad) support"
+ depends on SND_SOC_SDCA
+ default y
+ help
+ This option enables support for the File Download using UMP,
+ typically used for downloading firmware to devices.
+
+config SND_SOC_SDCA_OPTIONAL
+ def_tristate SND_SOC_SDCA || !SND_SOC_SDCA
+
+config SND_SOC_SDCA_CLASS
+ tristate "SDCA Class Driver"
+ depends on SOUNDWIRE
+ depends on HID=y || HID=SND_SOC_SDCA
+ depends on SND_SOC_SDCA
+ select SND_SOC_SDCA_CLASS_FUNCTION
+ select SND_SOC_SDCA_FDL
+ select SND_SOC_SDCA_HID
+ select SND_SOC_SDCA_IRQ
+ help
+ This option enables support for the SDCA Class driver which should
+ support any class compliant SDCA part.
+
+config SND_SOC_SDCA_CLASS_FUNCTION
+ tristate
+ help
+ This option enables support for the SDCA Class Function drivers,
+ these implement the individual functions of the SDCA Class driver.
+
+endmenu
diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile
new file mode 100644
index 000000000000..f6b73275d964
--- /dev/null
+++ b/sound/soc/sdca/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_function_device.o \
+ sdca_regmap.o sdca_asoc.o sdca_ump.o
+snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_HID) += sdca_hid.o
+snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_IRQ) += sdca_interrupts.o
+snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_FDL) += sdca_fdl.o
+
+snd-soc-sdca-class-y := sdca_class.o
+snd-soc-sdca-class-function-y := sdca_class_function.o
+
+obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o
+
+obj-$(CONFIG_SND_SOC_SDCA_CLASS) += snd-soc-sdca-class.o
+obj-$(CONFIG_SND_SOC_SDCA_CLASS_FUNCTION) += snd-soc-sdca-class-function.o
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
new file mode 100644
index 000000000000..2d328bbb95b9
--- /dev/null
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -0,0 +1,1559 @@
+// 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/bits.h>
+#include <linux/bitmap.h>
+#include <linux/build_bug.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/string_helpers.h>
+#include <linux/types.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/sdca.h>
+#include <sound/sdca_asoc.h>
+#include <sound/sdca_function.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+static bool exported_control(struct sdca_entity *entity, struct sdca_control *control)
+{
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ return true;
+ default:
+ break;
+ }
+
+ return control->layers & (SDCA_ACCESS_LAYER_USER |
+ SDCA_ACCESS_LAYER_APPLICATION);
+}
+
+static bool readonly_control(struct sdca_control *control)
+{
+ return control->has_fixed || control->mode == SDCA_ACCESS_MODE_RO;
+}
+
+/**
+ * sdca_asoc_count_component - count the various component parts
+ * @dev: Pointer to the device against which allocations will be done.
+ * @function: Pointer to the Function information.
+ * @num_widgets: Output integer pointer, will be filled with the
+ * required number of DAPM widgets for the Function.
+ * @num_routes: Output integer pointer, will be filled with the
+ * required number of DAPM routes for the Function.
+ * @num_controls: Output integer pointer, will be filled with the
+ * required number of ALSA controls for the Function.
+ * @num_dais: Output integer pointer, will be filled with the
+ * required number of ASoC DAIs for the Function.
+ *
+ * This function counts various things within the SDCA Function such
+ * that the calling driver can allocate appropriate space before
+ * calling the appropriate population functions.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *function,
+ int *num_widgets, int *num_routes, int *num_controls,
+ int *num_dais)
+{
+ int i, j;
+
+ *num_widgets = function->num_entities - 1;
+ *num_routes = 0;
+ *num_controls = 0;
+ *num_dais = 0;
+
+ for (i = 0; i < function->num_entities - 1; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ /* Add supply/DAI widget connections */
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ case SDCA_ENTITY_TYPE_OT:
+ *num_routes += !!entity->iot.clock;
+ *num_routes += !!entity->iot.is_dataport;
+ *num_controls += !entity->iot.is_dataport;
+ *num_dais += !!entity->iot.is_dataport;
+ break;
+ case SDCA_ENTITY_TYPE_PDE:
+ *num_routes += entity->pde.num_managed;
+ break;
+ default:
+ break;
+ }
+
+ if (entity->group)
+ (*num_routes)++;
+
+ /* Add primary entity connections from DisCo */
+ *num_routes += entity->num_sources;
+
+ for (j = 0; j < entity->num_controls; j++) {
+ if (exported_control(entity, &entity->controls[j]))
+ (*num_controls)++;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_count_component, "SND_SOC_SDCA");
+
+static int entity_early_parse_ge(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity)
+{
+ struct sdca_control_range *range;
+ struct sdca_control *control;
+ struct snd_kcontrol_new *kctl;
+ struct soc_enum *soc_enum;
+ const char *control_name;
+ unsigned int *values;
+ const char **texts;
+ int i;
+
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_GE_SELECTED_MODE);
+ if (!control)
+ return -EINVAL;
+
+ if (control->layers != SDCA_ACCESS_LAYER_CLASS)
+ dev_warn(dev, "%s: unexpected access layer: %x\n",
+ entity->label, control->layers);
+
+ range = sdca_control_find_range(dev, entity, control, SDCA_SELECTED_MODE_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ control_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+ entity->label, control->label);
+ if (!control_name)
+ return -ENOMEM;
+
+ kctl = devm_kzalloc(dev, sizeof(*kctl), GFP_KERNEL);
+ if (!kctl)
+ return -ENOMEM;
+
+ soc_enum = devm_kzalloc(dev, sizeof(*soc_enum), GFP_KERNEL);
+ if (!soc_enum)
+ return -ENOMEM;
+
+ texts = devm_kcalloc(dev, range->rows + 3, sizeof(*texts), GFP_KERNEL);
+ if (!texts)
+ return -ENOMEM;
+
+ values = devm_kcalloc(dev, range->rows + 3, sizeof(*values), GFP_KERNEL);
+ if (!values)
+ return -ENOMEM;
+
+ texts[0] = "Jack Unplugged";
+ texts[1] = "Jack Unknown";
+ texts[2] = "Detection in Progress";
+ values[0] = SDCA_DETECTED_MODE_JACK_UNPLUGGED;
+ values[1] = SDCA_DETECTED_MODE_JACK_UNKNOWN;
+ values[2] = SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS;
+ for (i = 0; i < range->rows; i++) {
+ enum sdca_terminal_type type;
+
+ type = sdca_range(range, SDCA_SELECTED_MODE_TERM_TYPE, i);
+
+ values[i + 3] = sdca_range(range, SDCA_SELECTED_MODE_INDEX, i);
+ texts[i + 3] = sdca_find_terminal_name(type);
+ if (!texts[i + 3]) {
+ dev_err(dev, "%s: unrecognised terminal type: %#x\n",
+ entity->label, type);
+ return -EINVAL;
+ }
+ }
+
+ soc_enum->reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, 0);
+ soc_enum->items = range->rows + 3;
+ soc_enum->mask = roundup_pow_of_two(soc_enum->items) - 1;
+ soc_enum->texts = texts;
+ soc_enum->values = values;
+
+ kctl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kctl->name = control_name;
+ kctl->info = snd_soc_info_enum_double;
+ kctl->get = snd_soc_dapm_get_enum_double;
+ kctl->put = snd_soc_dapm_put_enum_double;
+ kctl->private_value = (unsigned long)soc_enum;
+
+ entity->ge.kctl = kctl;
+
+ return 0;
+}
+
+static void add_route(struct snd_soc_dapm_route **route, const char *sink,
+ const char *control, const char *source)
+{
+ (*route)->sink = sink;
+ (*route)->control = control;
+ (*route)->source = source;
+ (*route)++;
+}
+
+static int entity_parse_simple(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route,
+ enum snd_soc_dapm_type id)
+{
+ int i;
+
+ (*widget)->id = id;
+ (*widget)++;
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, NULL, entity->sources[i]->label);
+
+ return 0;
+}
+
+static int entity_parse_it(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ int i;
+
+ if (entity->iot.is_dataport) {
+ const char *aif_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+ entity->label, "Playback");
+ if (!aif_name)
+ return -ENOMEM;
+
+ (*widget)->id = snd_soc_dapm_aif_in;
+
+ add_route(route, entity->label, NULL, aif_name);
+ } else {
+ (*widget)->id = snd_soc_dapm_mic;
+ }
+
+ if (entity->iot.clock)
+ add_route(route, entity->label, NULL, entity->iot.clock->label);
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, NULL, entity->sources[i]->label);
+
+ (*widget)++;
+
+ return 0;
+}
+
+static int entity_parse_ot(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ int i;
+
+ if (entity->iot.is_dataport) {
+ const char *aif_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+ entity->label, "Capture");
+ if (!aif_name)
+ return -ENOMEM;
+
+ (*widget)->id = snd_soc_dapm_aif_out;
+
+ add_route(route, aif_name, NULL, entity->label);
+ } else {
+ (*widget)->id = snd_soc_dapm_spk;
+ }
+
+ if (entity->iot.clock)
+ add_route(route, entity->label, NULL, entity->iot.clock->label);
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, NULL, entity->sources[i]->label);
+
+ (*widget)++;
+
+ return 0;
+}
+
+static int entity_pde_event(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kctl, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+ struct sdca_entity *entity = widget->priv;
+ static const int polls = 100;
+ unsigned int reg, val;
+ int from, to, i;
+ int poll_us;
+ int ret;
+
+ if (!component)
+ return -EIO;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ from = widget->on_val;
+ to = widget->off_val;
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ from = widget->off_val;
+ to = widget->on_val;
+ break;
+ default:
+ return 0;
+ }
+
+ for (i = 0; i < entity->pde.num_max_delay; i++) {
+ struct sdca_pde_delay *delay = &entity->pde.max_delay[i];
+
+ if (delay->from_ps == from && delay->to_ps == to) {
+ poll_us = delay->us / polls;
+ break;
+ }
+ }
+
+ reg = SDW_SDCA_CTL(SDW_SDCA_CTL_FUNC(widget->reg),
+ SDW_SDCA_CTL_ENT(widget->reg),
+ SDCA_CTL_PDE_ACTUAL_PS, 0);
+
+ for (i = 0; i < polls; i++) {
+ if (i)
+ fsleep(poll_us);
+
+ ret = regmap_read(component->regmap, reg, &val);
+ if (ret)
+ return ret;
+ else if (val == to)
+ return 0;
+ }
+
+ dev_err(component->dev, "%s: power transition failed: %x\n",
+ entity->label, val);
+ return -ETIMEDOUT;
+}
+
+static int entity_parse_pde(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ unsigned int target = (1 << SDCA_PDE_PS0) | (1 << SDCA_PDE_PS3);
+ struct sdca_control_range *range;
+ struct sdca_control *control;
+ unsigned int mask = 0;
+ int i;
+
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_PDE_REQUESTED_PS);
+ if (!control)
+ return -EINVAL;
+
+ /* Power should only be controlled by the driver */
+ if (control->layers != SDCA_ACCESS_LAYER_CLASS)
+ dev_warn(dev, "%s: unexpected access layer: %x\n",
+ entity->label, control->layers);
+
+ range = sdca_control_find_range(dev, entity, control, SDCA_REQUESTED_PS_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++)
+ mask |= 1 << sdca_range(range, SDCA_REQUESTED_PS_STATE, i);
+
+ if ((mask & target) != target) {
+ dev_err(dev, "%s: power control missing states\n", entity->label);
+ return -EINVAL;
+ }
+
+ (*widget)->id = snd_soc_dapm_supply;
+ (*widget)->reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, 0);
+ (*widget)->mask = GENMASK(control->nbits - 1, 0);
+ (*widget)->on_val = SDCA_PDE_PS0;
+ (*widget)->off_val = SDCA_PDE_PS3;
+ (*widget)->event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD;
+ (*widget)->event = entity_pde_event;
+ (*widget)->priv = entity;
+ (*widget)++;
+
+ for (i = 0; i < entity->pde.num_managed; i++)
+ add_route(route, entity->pde.managed[i]->label, NULL, entity->label);
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, NULL, entity->sources[i]->label);
+
+ return 0;
+}
+
+/* Device selector units are controlled through a group entity */
+static int entity_parse_su_device(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ struct sdca_control_range *range;
+ int num_routes = 0;
+ int i, j;
+
+ if (!entity->group) {
+ dev_err(dev, "%s: device selector unit missing group\n", entity->label);
+ return -EINVAL;
+ }
+
+ range = sdca_selector_find_range(dev, entity->group, SDCA_CTL_GE_SELECTED_MODE,
+ SDCA_SELECTED_MODE_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ (*widget)->id = snd_soc_dapm_mux;
+ (*widget)->kcontrol_news = entity->group->ge.kctl;
+ (*widget)->num_kcontrols = 1;
+ (*widget)++;
+
+ for (i = 0; i < entity->group->ge.num_modes; i++) {
+ struct sdca_ge_mode *mode = &entity->group->ge.modes[i];
+
+ for (j = 0; j < mode->num_controls; j++) {
+ struct sdca_ge_control *affected = &mode->controls[j];
+ int term;
+
+ if (affected->id != entity->id ||
+ affected->sel != SDCA_CTL_SU_SELECTOR ||
+ !affected->val)
+ continue;
+
+ if (affected->val - 1 >= entity->num_sources) {
+ dev_err(dev, "%s: bad control value: %#x\n",
+ entity->label, affected->val);
+ return -EINVAL;
+ }
+
+ if (++num_routes > entity->num_sources) {
+ dev_err(dev, "%s: too many input routes\n", entity->label);
+ return -EINVAL;
+ }
+
+ term = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX,
+ mode->val, SDCA_SELECTED_MODE_TERM_TYPE);
+ if (!term) {
+ dev_err(dev, "%s: mode not found: %#x\n",
+ entity->label, mode->val);
+ return -EINVAL;
+ }
+
+ add_route(route, entity->label, sdca_find_terminal_name(term),
+ entity->sources[affected->val - 1]->label);
+ }
+ }
+
+ return 0;
+}
+
+/* Class selector units will be exported as an ALSA control */
+static int entity_parse_su_class(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct sdca_control *control,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ struct snd_kcontrol_new *kctl;
+ struct soc_enum *soc_enum;
+ const char **texts;
+ int i;
+
+ kctl = devm_kzalloc(dev, sizeof(*kctl), GFP_KERNEL);
+ if (!kctl)
+ return -ENOMEM;
+
+ soc_enum = devm_kzalloc(dev, sizeof(*soc_enum), GFP_KERNEL);
+ if (!soc_enum)
+ return -ENOMEM;
+
+ texts = devm_kcalloc(dev, entity->num_sources + 1, sizeof(*texts), GFP_KERNEL);
+ if (!texts)
+ return -ENOMEM;
+
+ texts[0] = "No Signal";
+ for (i = 0; i < entity->num_sources; i++)
+ texts[i + 1] = entity->sources[i]->label;
+
+ soc_enum->reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, 0);
+ soc_enum->items = entity->num_sources + 1;
+ soc_enum->mask = roundup_pow_of_two(soc_enum->items) - 1;
+ soc_enum->texts = texts;
+
+ kctl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kctl->name = "Route";
+ kctl->info = snd_soc_info_enum_double;
+ kctl->get = snd_soc_dapm_get_enum_double;
+ kctl->put = snd_soc_dapm_put_enum_double;
+ kctl->private_value = (unsigned long)soc_enum;
+
+ (*widget)->id = snd_soc_dapm_mux;
+ (*widget)->kcontrol_news = kctl;
+ (*widget)->num_kcontrols = 1;
+ (*widget)++;
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, texts[i + 1], entity->sources[i]->label);
+
+ return 0;
+}
+
+static int entity_parse_su(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ struct sdca_control *control;
+
+ if (!entity->num_sources) {
+ dev_err(dev, "%s: selector with no inputs\n", entity->label);
+ return -EINVAL;
+ }
+
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR);
+ if (!control)
+ return -EINVAL;
+
+ if (control->layers == SDCA_ACCESS_LAYER_DEVICE)
+ return entity_parse_su_device(dev, function, entity, widget, route);
+
+ if (control->layers != SDCA_ACCESS_LAYER_CLASS)
+ dev_warn(dev, "%s: unexpected access layer: %x\n",
+ entity->label, control->layers);
+
+ return entity_parse_su_class(dev, function, entity, control, widget, route);
+}
+
+static int entity_parse_mu(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ struct sdca_control *control;
+ struct snd_kcontrol_new *kctl;
+ int i;
+
+ if (!entity->num_sources) {
+ dev_err(dev, "%s: selector 1 or more inputs\n", entity->label);
+ return -EINVAL;
+ }
+
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_MU_MIXER);
+ if (!control)
+ return -EINVAL;
+
+ /* MU control should be through DAPM */
+ if (control->layers != SDCA_ACCESS_LAYER_CLASS)
+ dev_warn(dev, "%s: unexpected access layer: %x\n",
+ entity->label, control->layers);
+
+ kctl = devm_kcalloc(dev, entity->num_sources, sizeof(*kctl), GFP_KERNEL);
+ if (!kctl)
+ return -ENOMEM;
+
+ for (i = 0; i < entity->num_sources; i++) {
+ const char *control_name;
+ struct soc_mixer_control *mc;
+
+ control_name = devm_kasprintf(dev, GFP_KERNEL, "%s %d",
+ control->label, i + 1);
+ if (!control_name)
+ return -ENOMEM;
+
+ mc = devm_kzalloc(dev, sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+
+ mc->reg = SND_SOC_NOPM;
+ mc->rreg = SND_SOC_NOPM;
+ mc->invert = 1; // Ensure default is connected
+ mc->min = 0;
+ mc->max = 1;
+
+ kctl[i].name = control_name;
+ kctl[i].private_value = (unsigned long)mc;
+ kctl[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kctl[i].info = snd_soc_info_volsw;
+ kctl[i].get = snd_soc_dapm_get_volsw;
+ kctl[i].put = snd_soc_dapm_put_volsw;
+ }
+
+ (*widget)->id = snd_soc_dapm_mixer;
+ (*widget)->kcontrol_news = kctl;
+ (*widget)->num_kcontrols = entity->num_sources;
+ (*widget)++;
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, kctl[i].name, entity->sources[i]->label);
+
+ return 0;
+}
+
+static int entity_cs_event(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kctl, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+ struct sdca_entity *entity = widget->priv;
+
+ if (!component)
+ return -EIO;
+
+ if (entity->cs.max_delay)
+ fsleep(entity->cs.max_delay);
+
+ return 0;
+}
+
+static int entity_parse_cs(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_dapm_widget **widget,
+ struct snd_soc_dapm_route **route)
+{
+ int i;
+
+ (*widget)->id = snd_soc_dapm_supply;
+ (*widget)->subseq = 1; /* Ensure these run after PDEs */
+ (*widget)->event_flags = SND_SOC_DAPM_POST_PMU;
+ (*widget)->event = entity_cs_event;
+ (*widget)->priv = entity;
+ (*widget)++;
+
+ for (i = 0; i < entity->num_sources; i++)
+ add_route(route, entity->label, NULL, entity->sources[i]->label);
+
+ return 0;
+}
+
+/**
+ * sdca_asoc_populate_dapm - fill in arrays of DAPM widgets and routes
+ * @dev: Pointer to the device against which allocations will be done.
+ * @function: Pointer to the Function information.
+ * @widget: Array of DAPM widgets to be populated.
+ * @route: Array of DAPM routes to be populated.
+ *
+ * This function populates arrays of DAPM widgets and routes from the
+ * DisCo information for a particular SDCA Function. Typically,
+ * snd_soc_asoc_count_component will be used to allocate appropriately
+ * sized arrays before calling this function.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_populate_dapm(struct device *dev, struct sdca_function_data *function,
+ struct snd_soc_dapm_widget *widget,
+ struct snd_soc_dapm_route *route)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < function->num_entities - 1; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ /*
+ * Some entities need to add controls "early" as they are
+ * referenced by other entities.
+ */
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_GE:
+ ret = entity_early_parse_ge(dev, function, entity);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < function->num_entities - 1; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ widget->name = entity->label;
+ widget->reg = SND_SOC_NOPM;
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ ret = entity_parse_it(dev, function, entity, &widget, &route);
+ break;
+ case SDCA_ENTITY_TYPE_OT:
+ ret = entity_parse_ot(dev, function, entity, &widget, &route);
+ break;
+ case SDCA_ENTITY_TYPE_PDE:
+ ret = entity_parse_pde(dev, function, entity, &widget, &route);
+ break;
+ case SDCA_ENTITY_TYPE_SU:
+ ret = entity_parse_su(dev, function, entity, &widget, &route);
+ break;
+ case SDCA_ENTITY_TYPE_MU:
+ ret = entity_parse_mu(dev, function, entity, &widget, &route);
+ break;
+ case SDCA_ENTITY_TYPE_CS:
+ ret = entity_parse_cs(dev, function, entity, &widget, &route);
+ break;
+ case SDCA_ENTITY_TYPE_CX:
+ /*
+ * FIXME: For now we will just treat these as a supply,
+ * meaning all options are enabled.
+ */
+ dev_warn(dev, "%s: clock selectors not fully supported yet\n",
+ entity->label);
+ ret = entity_parse_simple(dev, function, entity, &widget,
+ &route, snd_soc_dapm_supply);
+ break;
+ case SDCA_ENTITY_TYPE_TG:
+ ret = entity_parse_simple(dev, function, entity, &widget,
+ &route, snd_soc_dapm_siggen);
+ break;
+ case SDCA_ENTITY_TYPE_GE:
+ ret = entity_parse_simple(dev, function, entity, &widget,
+ &route, snd_soc_dapm_supply);
+ break;
+ default:
+ ret = entity_parse_simple(dev, function, entity, &widget,
+ &route, snd_soc_dapm_pga);
+ break;
+ }
+ if (ret)
+ return ret;
+
+ if (entity->group)
+ add_route(&route, entity->label, NULL, entity->group->label);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_populate_dapm, "SND_SOC_SDCA");
+
+static int control_limit_kctl(struct device *dev,
+ struct sdca_entity *entity,
+ struct sdca_control *control,
+ struct snd_kcontrol_new *kctl)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct sdca_control_range *range;
+ int min, max, step;
+ unsigned int *tlv;
+
+ if (control->type != SDCA_CTL_DATATYPE_Q7P8DB)
+ return 0;
+
+ /*
+ * FIXME: For now only handle the simple case of a single linear range
+ */
+ range = sdca_control_find_range(dev, entity, control, SDCA_VOLUME_LINEAR_NCOLS, 1);
+ if (!range)
+ return -EINVAL;
+
+ min = sdca_range(range, SDCA_VOLUME_LINEAR_MIN, 0);
+ max = sdca_range(range, SDCA_VOLUME_LINEAR_MAX, 0);
+ step = sdca_range(range, SDCA_VOLUME_LINEAR_STEP, 0);
+
+ min = sign_extend32(min, control->nbits - 1);
+ max = sign_extend32(max, control->nbits - 1);
+
+ tlv = devm_kcalloc(dev, 4, sizeof(*tlv), GFP_KERNEL);
+ if (!tlv)
+ return -ENOMEM;
+
+ tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
+ tlv[1] = 2 * sizeof(*tlv);
+ tlv[2] = (min * 100) >> 8;
+ tlv[3] = (max * 100) >> 8;
+
+ step = (step * 100) >> 8;
+
+ mc->min = ((int)tlv[2] / step);
+ mc->max = ((int)tlv[3] / step);
+ mc->shift = step;
+ mc->sign_bit = 15;
+ mc->sdca_q78 = 1;
+
+ kctl->tlv.p = tlv;
+ kctl->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+
+ return 0;
+}
+
+static int populate_control(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct sdca_control *control,
+ struct snd_kcontrol_new **kctl)
+{
+ const char *control_suffix = "";
+ const char *control_name;
+ struct soc_mixer_control *mc;
+ int index = 0;
+ int ret;
+ int cn;
+
+ if (!exported_control(entity, control))
+ return 0;
+
+ if (control->type == SDCA_CTL_DATATYPE_ONEBIT)
+ control_suffix = " Switch";
+
+ control_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s%s", entity->label,
+ control->label, control_suffix);
+ if (!control_name)
+ return -ENOMEM;
+
+ mc = devm_kzalloc(dev, sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+
+ for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+ BITS_PER_TYPE(control->cn_list)) {
+ switch (index++) {
+ case 0:
+ mc->reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
+ control->sel, cn);
+ mc->rreg = mc->reg;
+ break;
+ case 1:
+ mc->rreg = SDW_SDCA_CTL(function->desc->adr, entity->id,
+ control->sel, cn);
+ break;
+ default:
+ dev_err(dev, "%s: %s: only mono/stereo controls supported\n",
+ entity->label, control->label);
+ return -EINVAL;
+ }
+ }
+
+ mc->min = 0;
+ mc->max = clamp((0x1ull << control->nbits) - 1, 0, type_max(mc->max));
+
+ if (SDCA_CTL_TYPE(entity->type, control->sel) == SDCA_CTL_TYPE_S(FU, MUTE))
+ mc->invert = true;
+
+ (*kctl)->name = control_name;
+ (*kctl)->private_value = (unsigned long)mc;
+ (*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ (*kctl)->info = snd_soc_info_volsw;
+ (*kctl)->get = snd_soc_get_volsw;
+ (*kctl)->put = snd_soc_put_volsw;
+
+ if (readonly_control(control))
+ (*kctl)->access = SNDRV_CTL_ELEM_ACCESS_READ;
+ else
+ (*kctl)->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+
+ ret = control_limit_kctl(dev, entity, control, *kctl);
+ if (ret)
+ return ret;
+
+ (*kctl)++;
+
+ return 0;
+}
+
+static int populate_pin_switch(struct device *dev,
+ struct sdca_entity *entity,
+ struct snd_kcontrol_new **kctl)
+{
+ const char *control_name;
+
+ control_name = devm_kasprintf(dev, GFP_KERNEL, "%s Switch", entity->label);
+ if (!control_name)
+ return -ENOMEM;
+
+ (*kctl)->name = control_name;
+ (*kctl)->private_value = (unsigned long)entity->label;
+ (*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ (*kctl)->info = snd_soc_dapm_info_pin_switch;
+ (*kctl)->get = snd_soc_dapm_get_component_pin_switch;
+ (*kctl)->put = snd_soc_dapm_put_component_pin_switch;
+ (*kctl)++;
+
+ return 0;
+}
+
+/**
+ * sdca_asoc_populate_controls - fill in an array of ALSA controls for a Function
+ * @dev: Pointer to the device against which allocations will be done.
+ * @function: Pointer to the Function information.
+ * @kctl: Array of ALSA controls to be populated.
+ *
+ * This function populates an array of ALSA controls from the DisCo
+ * information for a particular SDCA Function. Typically,
+ * snd_soc_asoc_count_component will be used to allocate an
+ * appropriately sized array before calling this function.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_populate_controls(struct device *dev,
+ struct sdca_function_data *function,
+ struct snd_kcontrol_new *kctl)
+{
+ int i, j;
+ int ret;
+
+ for (i = 0; i < function->num_entities; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ case SDCA_ENTITY_TYPE_OT:
+ if (!entity->iot.is_dataport) {
+ ret = populate_pin_switch(dev, entity, &kctl);
+ if (ret)
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (j = 0; j < entity->num_controls; j++) {
+ ret = populate_control(dev, function, entity,
+ &entity->controls[j], &kctl);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_populate_controls, "SND_SOC_SDCA");
+
+static unsigned int rate_find_mask(unsigned int rate)
+{
+ switch (rate) {
+ case 0:
+ return SNDRV_PCM_RATE_8000_768000;
+ case 5512:
+ return SNDRV_PCM_RATE_5512;
+ case 8000:
+ return SNDRV_PCM_RATE_8000;
+ case 11025:
+ return SNDRV_PCM_RATE_11025;
+ case 16000:
+ return SNDRV_PCM_RATE_16000;
+ case 22050:
+ return SNDRV_PCM_RATE_22050;
+ case 32000:
+ return SNDRV_PCM_RATE_32000;
+ case 44100:
+ return SNDRV_PCM_RATE_44100;
+ case 48000:
+ return SNDRV_PCM_RATE_48000;
+ case 64000:
+ return SNDRV_PCM_RATE_64000;
+ case 88200:
+ return SNDRV_PCM_RATE_88200;
+ case 96000:
+ return SNDRV_PCM_RATE_96000;
+ case 176400:
+ return SNDRV_PCM_RATE_176400;
+ case 192000:
+ return SNDRV_PCM_RATE_192000;
+ case 352800:
+ return SNDRV_PCM_RATE_352800;
+ case 384000:
+ return SNDRV_PCM_RATE_384000;
+ case 705600:
+ return SNDRV_PCM_RATE_705600;
+ case 768000:
+ return SNDRV_PCM_RATE_768000;
+ case 12000:
+ return SNDRV_PCM_RATE_12000;
+ case 24000:
+ return SNDRV_PCM_RATE_24000;
+ case 128000:
+ return SNDRV_PCM_RATE_128000;
+ default:
+ return 0;
+ }
+}
+
+static u64 width_find_mask(unsigned int bits)
+{
+ switch (bits) {
+ case 0:
+ return SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE;
+ case 8:
+ return SNDRV_PCM_FMTBIT_S8;
+ case 16:
+ return SNDRV_PCM_FMTBIT_S16_LE;
+ case 20:
+ return SNDRV_PCM_FMTBIT_S20_LE;
+ case 24:
+ return SNDRV_PCM_FMTBIT_S24_LE;
+ case 32:
+ return SNDRV_PCM_FMTBIT_S32_LE;
+ default:
+ return 0;
+ }
+}
+
+static int populate_rate_format(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_pcm_stream *stream)
+{
+ struct sdca_control_range *range;
+ unsigned int sample_rate, sample_width;
+ unsigned int clock_rates = 0;
+ unsigned int rates = 0;
+ u64 formats = 0;
+ int sel, i;
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ sel = SDCA_CTL_IT_USAGE;
+ break;
+ case SDCA_ENTITY_TYPE_OT:
+ sel = SDCA_CTL_OT_USAGE;
+ break;
+ default:
+ dev_err(dev, "%s: entity type has no usage control\n",
+ entity->label);
+ return -EINVAL;
+ }
+
+ if (entity->iot.clock) {
+ range = sdca_selector_find_range(dev, entity->iot.clock,
+ SDCA_CTL_CS_SAMPLERATEINDEX,
+ SDCA_SAMPLERATEINDEX_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++) {
+ sample_rate = sdca_range(range, SDCA_SAMPLERATEINDEX_RATE, i);
+ clock_rates |= rate_find_mask(sample_rate);
+ }
+ } else {
+ clock_rates = UINT_MAX;
+ }
+
+ range = sdca_selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++) {
+ sample_rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i);
+ sample_rate = rate_find_mask(sample_rate);
+
+ if (sample_rate & clock_rates) {
+ rates |= sample_rate;
+
+ sample_width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i);
+ formats |= width_find_mask(sample_width);
+ }
+ }
+
+ stream->formats = formats;
+ stream->rates = rates;
+
+ return 0;
+}
+
+/**
+ * sdca_asoc_populate_dais - fill in an array of DAI drivers for a Function
+ * @dev: Pointer to the device against which allocations will be done.
+ * @function: Pointer to the Function information.
+ * @dais: Array of DAI drivers to be populated.
+ * @ops: DAI ops to be attached to each of the created DAI drivers.
+ *
+ * This function populates an array of ASoC DAI drivers from the DisCo
+ * information for a particular SDCA Function. Typically,
+ * snd_soc_asoc_count_component will be used to allocate an
+ * appropriately sized array before calling this function.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *function,
+ struct snd_soc_dai_driver *dais,
+ const struct snd_soc_dai_ops *ops)
+{
+ int i, j;
+ int ret;
+
+ for (i = 0, j = 0; i < function->num_entities - 1; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+ struct snd_soc_pcm_stream *stream;
+ const char *stream_suffix;
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ stream = &dais[j].playback;
+ stream_suffix = "Playback";
+ break;
+ case SDCA_ENTITY_TYPE_OT:
+ stream = &dais[j].capture;
+ stream_suffix = "Capture";
+ break;
+ default:
+ continue;
+ }
+
+ /* Can't check earlier as only terminals have an iot member. */
+ if (!entity->iot.is_dataport)
+ continue;
+
+ stream->stream_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+ entity->label, stream_suffix);
+ if (!stream->stream_name)
+ return -ENOMEM;
+ /* Channels will be further limited by constraints */
+ stream->channels_min = 1;
+ stream->channels_max = SDCA_MAX_CHANNEL_COUNT;
+
+ ret = populate_rate_format(dev, function, entity, stream);
+ if (ret)
+ return ret;
+
+ dais[j].id = i;
+ dais[j].name = entity->label;
+ dais[j].ops = ops;
+ j++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_populate_dais, "SND_SOC_SDCA");
+
+/**
+ * sdca_asoc_populate_component - fill in a component driver for a Function
+ * @dev: Pointer to the device against which allocations will be done.
+ * @function: Pointer to the Function information.
+ * @component_drv: Pointer to the component driver to be populated.
+ * @dai_drv: Pointer to the DAI driver array to be allocated and populated.
+ * @num_dai_drv: Pointer to integer that will be populated with the number of
+ * DAI drivers.
+ * @ops: DAI ops pointer that will be used for each DAI driver.
+ *
+ * This function populates a snd_soc_component_driver structure based
+ * on the DisCo information for a particular SDCA Function. It does
+ * all allocation internally.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_populate_component(struct device *dev,
+ struct sdca_function_data *function,
+ struct snd_soc_component_driver *component_drv,
+ struct snd_soc_dai_driver **dai_drv, int *num_dai_drv,
+ const struct snd_soc_dai_ops *ops)
+{
+ struct snd_soc_dapm_widget *widgets;
+ struct snd_soc_dapm_route *routes;
+ struct snd_kcontrol_new *controls;
+ struct snd_soc_dai_driver *dais;
+ int num_widgets, num_routes, num_controls, num_dais;
+ int ret;
+
+ ret = sdca_asoc_count_component(dev, function, &num_widgets, &num_routes,
+ &num_controls, &num_dais);
+ if (ret)
+ return ret;
+
+ widgets = devm_kcalloc(dev, num_widgets, sizeof(*widgets), GFP_KERNEL);
+ if (!widgets)
+ return -ENOMEM;
+
+ routes = devm_kcalloc(dev, num_routes, sizeof(*routes), GFP_KERNEL);
+ if (!routes)
+ return -ENOMEM;
+
+ controls = devm_kcalloc(dev, num_controls, sizeof(*controls), GFP_KERNEL);
+ if (!controls)
+ return -ENOMEM;
+
+ dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL);
+ if (!dais)
+ return -ENOMEM;
+
+ ret = sdca_asoc_populate_dapm(dev, function, widgets, routes);
+ if (ret)
+ return ret;
+
+ ret = sdca_asoc_populate_controls(dev, function, controls);
+ if (ret)
+ return ret;
+
+ ret = sdca_asoc_populate_dais(dev, function, dais, ops);
+ if (ret)
+ return ret;
+
+ component_drv->dapm_widgets = widgets;
+ component_drv->num_dapm_widgets = num_widgets;
+ component_drv->dapm_routes = routes;
+ component_drv->num_dapm_routes = num_routes;
+ component_drv->controls = controls;
+ component_drv->num_controls = num_controls;
+
+ *dai_drv = dais;
+ *num_dai_drv = num_dais;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_populate_component, "SND_SOC_SDCA");
+
+/**
+ * sdca_asoc_set_constraints - constrain channels available on a DAI
+ * @dev: Pointer to the device, used for error messages.
+ * @regmap: Pointer to the Function register map.
+ * @function: Pointer to the Function information.
+ * @substream: Pointer to the PCM substream.
+ * @dai: Pointer to the ASoC DAI.
+ *
+ * Typically called from startup().
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ static const unsigned int channel_list[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ };
+ struct sdca_entity *entity = &function->entities[dai->id];
+ struct snd_pcm_hw_constraint_list *constraint;
+ struct sdca_control_range *range;
+ struct sdca_control *control;
+ unsigned int channel_mask = 0;
+ int i, ret;
+
+ static_assert(ARRAY_SIZE(channel_list) == SDCA_MAX_CHANNEL_COUNT);
+ static_assert(sizeof(channel_mask) * BITS_PER_BYTE >= SDCA_MAX_CHANNEL_COUNT);
+
+ if (entity->type != SDCA_ENTITY_TYPE_IT)
+ return 0;
+
+ control = sdca_selector_find_control(dev, entity, SDCA_CTL_IT_CLUSTERINDEX);
+ if (!control)
+ return -EINVAL;
+
+ range = sdca_control_find_range(dev, entity, control, SDCA_CLUSTER_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++) {
+ int clusterid = sdca_range(range, SDCA_CLUSTER_CLUSTERID, i);
+ struct sdca_cluster *cluster;
+
+ cluster = sdca_id_find_cluster(dev, function, clusterid);
+ if (!cluster)
+ return -ENODEV;
+
+ channel_mask |= (1 << (cluster->num_channels - 1));
+ }
+
+ dev_dbg(dev, "%s: set channel constraint mask: %#x\n",
+ entity->label, channel_mask);
+
+ constraint = kzalloc(sizeof(*constraint), GFP_KERNEL);
+ if (!constraint)
+ return -ENOMEM;
+
+ constraint->count = ARRAY_SIZE(channel_list);
+ constraint->list = channel_list;
+ constraint->mask = channel_mask;
+
+ ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ constraint);
+ if (ret) {
+ dev_err(dev, "%s: failed to add constraint: %d\n", entity->label, ret);
+ kfree(constraint);
+ return ret;
+ }
+
+ dai->priv = constraint;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_set_constraints, "SND_SOC_SDCA");
+
+/**
+ * sdca_asoc_free_constraints - free constraint allocations
+ * @substream: Pointer to the PCM substream.
+ * @dai: Pointer to the ASoC DAI.
+ *
+ * Typically called from shutdown().
+ */
+void sdca_asoc_free_constraints(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_hw_constraint_list *constraint = dai->priv;
+
+ kfree(constraint);
+}
+EXPORT_SYMBOL_NS(sdca_asoc_free_constraints, "SND_SOC_SDCA");
+
+/**
+ * sdca_asoc_get_port - return SoundWire port for a DAI
+ * @dev: Pointer to the device, used for error messages.
+ * @regmap: Pointer to the Function register map.
+ * @function: Pointer to the Function information.
+ * @dai: Pointer to the ASoC DAI.
+ *
+ * Typically called from hw_params().
+ *
+ * Return: Returns a positive port number on success, and a negative error
+ * code on failure.
+ */
+int sdca_asoc_get_port(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct snd_soc_dai *dai)
+{
+ struct sdca_entity *entity = &function->entities[dai->id];
+ struct sdca_control_range *range;
+ unsigned int reg, val;
+ int sel = -EINVAL;
+ int i, ret;
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ sel = SDCA_CTL_IT_DATAPORT_SELECTOR;
+ break;
+ case SDCA_ENTITY_TYPE_OT:
+ sel = SDCA_CTL_OT_DATAPORT_SELECTOR;
+ break;
+ default:
+ break;
+ }
+
+ if (sel < 0 || !entity->iot.is_dataport) {
+ dev_err(dev, "%s: port number only available for dataports\n",
+ entity->label);
+ return -EINVAL;
+ }
+
+ range = sdca_selector_find_range(dev, entity, sel, SDCA_DATAPORT_SELECTOR_NCOLS,
+ SDCA_DATAPORT_SELECTOR_NROWS);
+ if (!range)
+ return -EINVAL;
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, sel, 0);
+
+ ret = regmap_read(regmap, reg, &val);
+ if (ret) {
+ dev_err(dev, "%s: failed to read dataport selector: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ for (i = 0; i < range->rows; i++) {
+ static const u8 port_mask = 0xF;
+
+ sel = sdca_range(range, val & port_mask, i);
+
+ /*
+ * FIXME: Currently only a single dataport is supported, so
+ * return the first one found, technically up to 4 dataports
+ * could be linked, but this is not yet supported.
+ */
+ if (sel != 0xFF)
+ return sel;
+
+ val >>= hweight8(port_mask);
+ }
+
+ dev_err(dev, "%s: no dataport found\n", entity->label);
+ return -ENODEV;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_get_port, "SND_SOC_SDCA");
+
+static int set_cluster(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity, unsigned int channels)
+{
+ int sel = SDCA_CTL_IT_CLUSTERINDEX;
+ struct sdca_control_range *range;
+ int i, ret;
+
+ range = sdca_selector_find_range(dev, entity, sel, SDCA_CLUSTER_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++) {
+ int cluster_id = sdca_range(range, SDCA_CLUSTER_CLUSTERID, i);
+ struct sdca_cluster *cluster;
+
+ cluster = sdca_id_find_cluster(dev, function, cluster_id);
+ if (!cluster)
+ return -ENODEV;
+
+ if (cluster->num_channels == channels) {
+ int index = sdca_range(range, SDCA_CLUSTER_BYTEINDEX, i);
+ unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
+ entity->id, sel, 0);
+
+ ret = regmap_update_bits(regmap, reg, 0xFF, index);
+ if (ret) {
+ dev_err(dev, "%s: failed to write cluster index: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%s: set cluster to %d (%d channels)\n",
+ entity->label, index, channels);
+
+ return 0;
+ }
+ }
+
+ dev_err(dev, "%s: no cluster for %d channels\n", entity->label, channels);
+ return -EINVAL;
+}
+
+static int set_clock(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity, int target_rate)
+{
+ int sel = SDCA_CTL_CS_SAMPLERATEINDEX;
+ struct sdca_control_range *range;
+ int i, ret;
+
+ range = sdca_selector_find_range(dev, entity, sel, SDCA_SAMPLERATEINDEX_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++) {
+ unsigned int rate = sdca_range(range, SDCA_SAMPLERATEINDEX_RATE, i);
+
+ if (rate == target_rate) {
+ unsigned int index = sdca_range(range,
+ SDCA_SAMPLERATEINDEX_INDEX,
+ i);
+ unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
+ entity->id, sel, 0);
+
+ ret = regmap_update_bits(regmap, reg, 0xFF, index);
+ if (ret) {
+ dev_err(dev, "%s: failed to write clock rate: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%s: set clock rate to %d (%dHz)\n",
+ entity->label, index, rate);
+
+ return 0;
+ }
+ }
+
+ dev_err(dev, "%s: no clock rate for %dHz\n", entity->label, target_rate);
+ return -EINVAL;
+}
+
+static int set_usage(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity, int sel,
+ int target_rate, int target_width)
+{
+ struct sdca_control_range *range;
+ int i, ret;
+
+ range = sdca_selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0);
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < range->rows; i++) {
+ unsigned int rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i);
+ unsigned int width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i);
+
+ if ((!rate || rate == target_rate) && width == target_width) {
+ unsigned int usage = sdca_range(range, SDCA_USAGE_NUMBER, i);
+ unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
+ entity->id, sel, 0);
+
+ ret = regmap_update_bits(regmap, reg, 0xFF, usage);
+ if (ret) {
+ dev_err(dev, "%s: failed to write usage: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%s: set usage to %#x (%dHz, %d bits)\n",
+ entity->label, usage, target_rate, target_width);
+
+ return 0;
+ }
+ }
+
+ dev_err(dev, "%s: no usage for %dHz, %dbits\n",
+ entity->label, target_rate, target_width);
+ return -EINVAL;
+}
+
+/**
+ * sdca_asoc_hw_params - set SDCA channels, sample rate and bit depth
+ * @dev: Pointer to the device, used for error messages.
+ * @regmap: Pointer to the Function register map.
+ * @function: Pointer to the Function information.
+ * @substream: Pointer to the PCM substream.
+ * @params: Pointer to the hardware parameters.
+ * @dai: Pointer to the ASoC DAI.
+ *
+ * Typically called from hw_params().
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct sdca_entity *entity = &function->entities[dai->id];
+ int channels = params_channels(params);
+ int width = params_width(params);
+ int rate = params_rate(params);
+ int usage_sel;
+ int ret;
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ ret = set_cluster(dev, regmap, function, entity, channels);
+ if (ret)
+ return ret;
+
+ usage_sel = SDCA_CTL_IT_USAGE;
+ break;
+ case SDCA_ENTITY_TYPE_OT:
+ usage_sel = SDCA_CTL_OT_USAGE;
+ break;
+ default:
+ dev_err(dev, "%s: hw_params on non-terminal entity\n", entity->label);
+ return -EINVAL;
+ }
+
+ if (entity->iot.clock) {
+ ret = set_clock(dev, regmap, function, entity->iot.clock, rate);
+ if (ret)
+ return ret;
+ }
+
+ ret = set_usage(dev, regmap, function, entity, usage_sel, rate, width);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_hw_params, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c
new file mode 100644
index 000000000000..349d32933ba8
--- /dev/null
+++ b/sound/soc/sdca/sdca_class.c
@@ -0,0 +1,304 @@
+// 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/device.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_interrupts.h>
+#include <sound/sdca_regmap.h>
+#include "sdca_class.h"
+
+#define CLASS_SDW_ATTACH_TIMEOUT_MS 5000
+
+static int class_read_prop(struct sdw_slave *sdw)
+{
+ struct sdw_slave_prop *prop = &sdw->prop;
+
+ sdw_slave_read_prop(sdw);
+
+ prop->use_domain_irq = true;
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY |
+ SDW_SCP_INT1_IMPL_DEF;
+
+ return 0;
+}
+
+static int class_sdw_update_status(struct sdw_slave *sdw, enum sdw_slave_status status)
+{
+ struct sdca_class_drv *drv = dev_get_drvdata(&sdw->dev);
+
+ switch (status) {
+ case SDW_SLAVE_ATTACHED:
+ dev_dbg(drv->dev, "device attach\n");
+
+ drv->attached = true;
+
+ complete(&drv->device_attach);
+ break;
+ case SDW_SLAVE_UNATTACHED:
+ dev_dbg(drv->dev, "device detach\n");
+
+ drv->attached = false;
+
+ reinit_completion(&drv->device_attach);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct sdw_slave_ops class_sdw_ops = {
+ .read_prop = class_read_prop,
+ .update_status = class_sdw_update_status,
+};
+
+static void class_regmap_lock(void *data)
+{
+ struct mutex *lock = data;
+
+ mutex_lock(lock);
+}
+
+static void class_regmap_unlock(void *data)
+{
+ struct mutex *lock = data;
+
+ mutex_unlock(lock);
+}
+
+static int class_wait_for_attach(struct sdca_class_drv *drv)
+{
+ if (!drv->attached) {
+ unsigned long timeout = msecs_to_jiffies(CLASS_SDW_ATTACH_TIMEOUT_MS);
+ unsigned long time;
+
+ time = wait_for_completion_timeout(&drv->device_attach, timeout);
+ if (!time) {
+ dev_err(drv->dev, "timed out waiting for device re-attach\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ regcache_cache_only(drv->dev_regmap, false);
+
+ return 0;
+}
+
+static bool class_dev_regmap_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SCP_SDCA_INTMASK1 ... SDW_SCP_SDCA_INTMASK4:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool class_dev_regmap_precious(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INT4:
+ case SDW_SCP_SDCA_INTMASK1 ... SDW_SCP_SDCA_INTMASK4:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config class_dev_regmap_config = {
+ .name = "sdca-device",
+ .reg_bits = 32,
+ .val_bits = 8,
+
+ .max_register = SDW_SDCA_MAX_REGISTER,
+ .volatile_reg = class_dev_regmap_volatile,
+ .precious_reg = class_dev_regmap_precious,
+
+ .cache_type = REGCACHE_MAPLE,
+
+ .lock = class_regmap_lock,
+ .unlock = class_regmap_unlock,
+};
+
+static void class_boot_work(struct work_struct *work)
+{
+ struct sdca_class_drv *drv = container_of(work,
+ struct sdca_class_drv,
+ boot_work);
+ int ret;
+
+ ret = class_wait_for_attach(drv);
+ if (ret)
+ goto err;
+
+ drv->irq_info = sdca_irq_allocate(drv->dev, drv->dev_regmap,
+ drv->sdw->irq);
+ if (IS_ERR(drv->irq_info))
+ goto err;
+
+ ret = sdca_dev_register_functions(drv->sdw);
+ if (ret)
+ goto err;
+
+ dev_dbg(drv->dev, "boot work complete\n");
+
+ pm_runtime_mark_last_busy(drv->dev);
+ pm_runtime_put_autosuspend(drv->dev);
+
+ return;
+
+err:
+ pm_runtime_put_sync(drv->dev);
+}
+
+static void class_dev_remove(void *data)
+{
+ struct sdca_class_drv *drv = data;
+
+ cancel_work_sync(&drv->boot_work);
+
+ sdca_dev_unregister_functions(drv->sdw);
+}
+
+static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id)
+{
+ struct device *dev = &sdw->dev;
+ struct sdca_device_data *data = &sdw->sdca_data;
+ struct regmap_config *dev_config;
+ struct sdca_class_drv *drv;
+ int ret;
+
+ sdca_lookup_swft(sdw);
+
+ drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ dev_config = devm_kmemdup(dev, &class_dev_regmap_config,
+ sizeof(*dev_config), GFP_KERNEL);
+ if (!dev_config)
+ return -ENOMEM;
+
+ drv->functions = devm_kcalloc(dev, data->num_functions,
+ sizeof(*drv->functions),
+ GFP_KERNEL);
+ if (!drv->functions)
+ return -ENOMEM;
+
+ drv->dev = dev;
+ drv->sdw = sdw;
+ mutex_init(&drv->regmap_lock);
+
+ dev_set_drvdata(drv->dev, drv);
+
+ INIT_WORK(&drv->boot_work, class_boot_work);
+ init_completion(&drv->device_attach);
+
+ dev_config->lock_arg = &drv->regmap_lock;
+
+ drv->dev_regmap = devm_regmap_init_sdw(sdw, dev_config);
+ if (IS_ERR(drv->dev_regmap))
+ return dev_err_probe(drv->dev, PTR_ERR(drv->dev_regmap),
+ "failed to create device regmap\n");
+
+ regcache_cache_only(drv->dev_regmap, true);
+
+ pm_runtime_set_autosuspend_delay(dev, 250);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, class_dev_remove, drv);
+ if (ret)
+ return ret;
+
+ queue_work(system_long_wq, &drv->boot_work);
+
+ return 0;
+}
+
+static int class_runtime_suspend(struct device *dev)
+{
+ struct sdca_class_drv *drv = dev_get_drvdata(dev);
+
+ /*
+ * Whilst the driver doesn't power the chip down here, going into runtime
+ * suspend lets the SoundWire bus power down, which means the driver
+ * can't communicate with the device any more.
+ */
+ regcache_cache_only(drv->dev_regmap, true);
+
+ return 0;
+}
+
+static int class_runtime_resume(struct device *dev)
+{
+ struct sdca_class_drv *drv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = class_wait_for_attach(drv);
+ if (ret)
+ goto err;
+
+ regcache_mark_dirty(drv->dev_regmap);
+
+ ret = regcache_sync(drv->dev_regmap);
+ if (ret) {
+ dev_err(drv->dev, "failed to restore cache: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regcache_cache_only(drv->dev_regmap, true);
+
+ return ret;
+}
+
+static const struct dev_pm_ops class_pm_ops = {
+ RUNTIME_PM_OPS(class_runtime_suspend, class_runtime_resume, NULL)
+};
+
+static const struct sdw_device_id class_sdw_id[] = {
+ SDW_SLAVE_ENTRY(0x01FA, 0x4245, 0),
+ {}
+};
+MODULE_DEVICE_TABLE(sdw, class_sdw_id);
+
+static struct sdw_driver class_sdw_driver = {
+ .driver = {
+ .name = "sdca_class",
+ .pm = pm_ptr(&class_pm_ops),
+ },
+
+ .probe = class_sdw_probe,
+ .id_table = class_sdw_id,
+ .ops = &class_sdw_ops,
+};
+module_sdw_driver(class_sdw_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SDCA Class Driver");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_class.h b/sound/soc/sdca/sdca_class.h
new file mode 100644
index 000000000000..bb4c9dd12429
--- /dev/null
+++ b/sound/soc/sdca/sdca_class.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ *
+ * Copyright (C) 2025 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __SDCA_CLASS_H__
+#define __SDCA_CLASS_H__
+
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+struct device;
+struct regmap;
+struct sdw_slave;
+struct sdca_function_data;
+
+struct sdca_class_drv {
+ struct device *dev;
+ struct regmap *dev_regmap;
+ struct sdw_slave *sdw;
+
+ struct sdca_function_data *functions;
+ struct sdca_interrupt_info *irq_info;
+
+ struct mutex regmap_lock;
+ struct work_struct boot_work;
+ struct completion device_attach;
+
+ bool attached;
+};
+
+#endif /* __SDCA_CLASS_H__ */
diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c
new file mode 100644
index 000000000000..0028482a1e75
--- /dev/null
+++ b/sound/soc/sdca/sdca_class_function.c
@@ -0,0 +1,460 @@
+// 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/auxiliary_bus.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/pcm.h>
+#include <sound/sdca_asoc.h>
+#include <sound/sdca_fdl.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_interrupts.h>
+#include <sound/sdca_regmap.h>
+#include <sound/sdw.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+#include "sdca_class.h"
+
+struct class_function_drv {
+ struct device *dev;
+ struct regmap *regmap;
+ struct sdca_class_drv *core;
+
+ struct sdca_function_data *function;
+};
+
+static void class_function_regmap_lock(void *data)
+{
+ struct mutex *lock = data;
+
+ mutex_lock(lock);
+}
+
+static void class_function_regmap_unlock(void *data)
+{
+ struct mutex *lock = data;
+
+ mutex_unlock(lock);
+}
+
+static bool class_function_regmap_writeable(struct device *dev, unsigned int reg)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+
+ return sdca_regmap_writeable(drv->function, reg);
+}
+
+static bool class_function_regmap_readable(struct device *dev, unsigned int reg)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+
+ return sdca_regmap_readable(drv->function, reg);
+}
+
+static bool class_function_regmap_volatile(struct device *dev, unsigned int reg)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+
+ return sdca_regmap_volatile(drv->function, reg);
+}
+
+static const struct regmap_config class_function_regmap_config = {
+ .name = "sdca",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+
+ .max_register = SDW_SDCA_MAX_REGISTER,
+ .readable_reg = class_function_regmap_readable,
+ .writeable_reg = class_function_regmap_writeable,
+ .volatile_reg = class_function_regmap_volatile,
+
+ .cache_type = REGCACHE_MAPLE,
+
+ .lock = class_function_regmap_lock,
+ .unlock = class_function_regmap_unlock,
+};
+
+static int class_function_regmap_mbq_size(struct device *dev, unsigned int reg)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+
+ return sdca_regmap_mbq_size(drv->function, reg);
+}
+
+static bool class_function_regmap_deferrable(struct device *dev, unsigned int reg)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+
+ return sdca_regmap_deferrable(drv->function, reg);
+}
+
+static const struct regmap_sdw_mbq_cfg class_function_mbq_config = {
+ .mbq_size = class_function_regmap_mbq_size,
+ .deferrable = class_function_regmap_deferrable,
+ .retry_us = 1000,
+ .timeout_us = 10000,
+};
+
+static int class_function_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct class_function_drv *drv = snd_soc_component_get_drvdata(dai->component);
+
+ return sdca_asoc_set_constraints(drv->dev, drv->regmap, drv->function,
+ substream, dai);
+}
+
+static int class_function_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct class_function_drv *drv = snd_soc_component_get_drvdata(dai->component);
+ struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct sdw_slave *sdw = dev_to_sdw_dev(drv->dev->parent);
+ struct sdw_stream_config sconfig = {0};
+ struct sdw_port_config pconfig = {0};
+ int ret;
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ snd_sdw_params_to_config(substream, params, &sconfig, &pconfig);
+
+ /*
+ * FIXME: As also noted in sdca_asoc_get_port(), currently only
+ * a single unshared port is supported for each DAI.
+ */
+ ret = sdca_asoc_get_port(drv->dev, drv->regmap, drv->function, dai);
+ if (ret < 0)
+ return ret;
+
+ pconfig.num = ret;
+
+ ret = sdw_stream_add_slave(sdw, &sconfig, &pconfig, 1, sdw_stream);
+ if (ret) {
+ dev_err(drv->dev, "failed to add sdw stream: %d\n", ret);
+ return ret;
+ }
+
+ return sdca_asoc_hw_params(drv->dev, drv->regmap, drv->function,
+ substream, params, dai);
+}
+
+static int class_function_sdw_remove_peripheral(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct class_function_drv *drv = snd_soc_component_get_drvdata(dai->component);
+ struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct sdw_slave *sdw = dev_to_sdw_dev(drv->dev->parent);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ return sdw_stream_remove_slave(sdw, sdw_stream);
+}
+
+static int class_function_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops class_function_sdw_ops = {
+ .startup = class_function_startup,
+ .shutdown = sdca_asoc_free_constraints,
+ .set_stream = class_function_sdw_set_stream,
+ .hw_params = class_function_sdw_add_peripheral,
+ .hw_free = class_function_sdw_remove_peripheral,
+};
+
+static int class_function_component_probe(struct snd_soc_component *component)
+{
+ struct class_function_drv *drv = snd_soc_component_get_drvdata(component);
+ struct sdca_class_drv *core = drv->core;
+
+ return sdca_irq_populate(drv->function, component, core->irq_info);
+}
+
+static const struct snd_soc_component_driver class_function_component_drv = {
+ .probe = class_function_component_probe,
+ .endianness = 1,
+};
+
+static int class_function_boot(struct class_function_drv *drv)
+{
+ unsigned int reg = SDW_SDCA_CTL(drv->function->desc->adr,
+ SDCA_ENTITY_TYPE_ENTITY_0,
+ SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(drv->regmap, reg, &val);
+ if (ret < 0) {
+ dev_err(drv->dev, "failed to read function status: %d\n", ret);
+ return ret;
+ }
+
+ if (!(val & SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET)) {
+ dev_dbg(drv->dev, "reset function device\n");
+
+ ret = sdca_reset_function(drv->dev, drv->function, drv->regmap);
+ if (ret)
+ return ret;
+ }
+
+ if (val & SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION) {
+ dev_dbg(drv->dev, "write initialisation\n");
+
+ ret = sdca_regmap_write_init(drv->dev, drv->core->dev_regmap,
+ drv->function);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv->regmap, reg,
+ SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION);
+ if (ret < 0) {
+ dev_err(drv->dev,
+ "failed to clear function init status: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /* Start FDL process */
+ ret = sdca_irq_populate_early(drv->dev, drv->regmap, drv->function,
+ drv->core->irq_info);
+ if (ret)
+ return ret;
+
+ ret = sdca_fdl_sync(drv->dev, drv->function, drv->core->irq_info);
+ if (ret)
+ return ret;
+
+ ret = sdca_regmap_write_defaults(drv->dev, drv->regmap, drv->function);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv->regmap, reg, 0xFF);
+ if (ret < 0) {
+ dev_err(drv->dev, "failed to clear function status: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int class_function_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *aux_dev_id)
+{
+ struct device *dev = &auxdev->dev;
+ struct sdca_class_drv *core = dev_get_drvdata(dev->parent);
+ struct sdca_device_data *data = &core->sdw->sdca_data;
+ struct sdca_function_desc *desc;
+ struct snd_soc_component_driver *cmp_drv;
+ struct snd_soc_dai_driver *dais;
+ struct class_function_drv *drv;
+ struct regmap_sdw_mbq_cfg *mbq_config;
+ struct regmap_config *config;
+ struct reg_default *defaults;
+ int ndefaults;
+ int num_dais;
+ int ret;
+ int i;
+
+ drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ cmp_drv = devm_kmemdup(dev, &class_function_component_drv, sizeof(*cmp_drv),
+ GFP_KERNEL);
+ if (!cmp_drv)
+ return -ENOMEM;
+
+ config = devm_kmemdup(dev, &class_function_regmap_config, sizeof(*config),
+ GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+
+ mbq_config = devm_kmemdup(dev, &class_function_mbq_config, sizeof(*mbq_config),
+ GFP_KERNEL);
+ if (!mbq_config)
+ return -ENOMEM;
+
+ drv->dev = dev;
+ drv->core = core;
+
+ for (i = 0; i < data->num_functions; i++) {
+ desc = &data->function[i];
+
+ if (desc->type == aux_dev_id->driver_data)
+ break;
+ }
+ if (i == core->sdw->sdca_data.num_functions) {
+ dev_err(dev, "failed to locate function\n");
+ return -EINVAL;
+ }
+
+ drv->function = &core->functions[i];
+
+ ret = sdca_parse_function(dev, core->sdw, desc, drv->function);
+ if (ret)
+ return ret;
+
+ ndefaults = sdca_regmap_count_constants(dev, drv->function);
+ if (ndefaults < 0)
+ return ndefaults;
+
+ defaults = devm_kcalloc(dev, ndefaults, sizeof(*defaults), GFP_KERNEL);
+ if (!defaults)
+ return -ENOMEM;
+
+ ret = sdca_regmap_populate_constants(dev, drv->function, defaults);
+ if (ret < 0)
+ return ret;
+
+ regcache_sort_defaults(defaults, ndefaults);
+
+ auxiliary_set_drvdata(auxdev, drv);
+
+ config->reg_defaults = defaults;
+ config->num_reg_defaults = ndefaults;
+ config->lock_arg = &core->regmap_lock;
+
+ if (drv->function->busy_max_delay) {
+ mbq_config->timeout_us = drv->function->busy_max_delay;
+ mbq_config->retry_us = umax(drv->function->busy_max_delay / 10,
+ mbq_config->retry_us);
+ }
+
+ drv->regmap = devm_regmap_init_sdw_mbq_cfg(dev, core->sdw, config, mbq_config);
+ if (IS_ERR(drv->regmap))
+ return dev_err_probe(dev, PTR_ERR(drv->regmap),
+ "failed to create regmap");
+
+ ret = sdca_asoc_populate_component(dev, drv->function, cmp_drv,
+ &dais, &num_dais,
+ &class_function_sdw_ops);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 200);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = class_function_boot(drv);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_soc_register_component(dev, cmp_drv, dais, num_dais);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register component\n");
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+
+static int class_function_runtime_suspend(struct device *dev)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+
+ /*
+ * Whilst the driver doesn't power the chip down here, going into
+ * runtime suspend means the driver can't be sure the bus won't
+ * power down which would prevent communication with the device.
+ */
+ regcache_cache_only(drv->regmap, true);
+
+ return 0;
+}
+
+static int class_function_runtime_resume(struct device *dev)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
+ int ret;
+
+ regcache_mark_dirty(drv->regmap);
+ regcache_cache_only(drv->regmap, false);
+
+ ret = regcache_sync(drv->regmap);
+ if (ret) {
+ dev_err(drv->dev, "failed to restore register cache: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regcache_cache_only(drv->regmap, true);
+
+ return ret;
+}
+
+static const struct dev_pm_ops class_function_pm_ops = {
+ RUNTIME_PM_OPS(class_function_runtime_suspend,
+ class_function_runtime_resume, NULL)
+};
+
+static const struct auxiliary_device_id class_function_id_table[] = {
+ {
+ .name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_SMART_AMP_NAME,
+ .driver_data = SDCA_FUNCTION_TYPE_SMART_AMP,
+ },
+ {
+ .name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_SMART_MIC_NAME,
+ .driver_data = SDCA_FUNCTION_TYPE_SMART_MIC,
+ },
+ {
+ .name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_UAJ_NAME,
+ .driver_data = SDCA_FUNCTION_TYPE_UAJ,
+ },
+ {
+ .name = "snd_soc_sdca." SDCA_FUNCTION_TYPE_HID_NAME,
+ .driver_data = SDCA_FUNCTION_TYPE_HID,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, class_function_id_table);
+
+static struct auxiliary_driver class_function_drv = {
+ .driver = {
+ .name = "sdca_function",
+ .pm = pm_ptr(&class_function_pm_ops),
+ },
+
+ .probe = class_function_probe,
+ .id_table = class_function_id_table
+};
+module_auxiliary_driver(class_function_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SDCA Class Function Driver");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c
new file mode 100644
index 000000000000..405e80b979de
--- /dev/null
+++ b/sound/soc/sdca/sdca_device.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2024 Intel Corporation
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+
+void sdca_lookup_interface_revision(struct sdw_slave *slave)
+{
+ struct fwnode_handle *fwnode = slave->dev.fwnode;
+
+ /*
+ * if this property is not present, then the sdca_interface_revision will
+ * remain zero, which will be considered as 'not defined' or 'invalid'.
+ */
+ fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision",
+ &slave->sdca_data.interface_revision);
+}
+EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, "SND_SOC_SDCA");
+
+static void devm_acpi_table_put(void *ptr)
+{
+ acpi_put_table((struct acpi_table_header *)ptr);
+}
+
+void sdca_lookup_swft(struct sdw_slave *slave)
+{
+ acpi_status status;
+
+ status = acpi_get_table(ACPI_SIG_SWFT, 0,
+ (struct acpi_table_header **)&slave->sdca_data.swft);
+ if (ACPI_FAILURE(status))
+ dev_info(&slave->dev, "SWFT not available\n");
+ else
+ devm_add_action_or_reset(&slave->dev, devm_acpi_table_put,
+ &slave->sdca_data.swft);
+}
+EXPORT_SYMBOL_NS(sdca_lookup_swft, "SND_SOC_SDCA");
+
+static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave)
+{
+ struct sdw_slave_id *id = &slave->id;
+ int i;
+
+ /*
+ * The RT712_VA relies on the v06r04 draft, and the
+ * RT712_VB on a more recent v08r01 draft.
+ */
+ if (slave->sdca_data.interface_revision < 0x0801)
+ return false;
+
+ if (id->mfg_id != 0x025d)
+ return false;
+
+ if (id->part_id != 0x712 &&
+ id->part_id != 0x713 &&
+ id->part_id != 0x716 &&
+ id->part_id != 0x717)
+ return false;
+
+ for (i = 0; i < slave->sdca_data.num_functions; i++) {
+ if (slave->sdca_data.function[i].type == SDCA_FUNCTION_TYPE_SMART_MIC)
+ return true;
+ }
+
+ return false;
+}
+
+static bool sdca_device_quirk_skip_func_type_patching(struct sdw_slave *slave)
+{
+ const char *vendor, *sku;
+
+ vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+ sku = dmi_get_system_info(DMI_PRODUCT_SKU);
+
+ if (vendor && sku &&
+ !strcmp(vendor, "Dell Inc.") &&
+ (!strcmp(sku, "0C62") || !strcmp(sku, "0C63") || !strcmp(sku, "0C6B")) &&
+ slave->sdca_data.interface_revision == 0x061c &&
+ slave->id.mfg_id == 0x01fa && slave->id.part_id == 0x4243)
+ return true;
+
+ return false;
+}
+
+bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
+{
+ switch (quirk) {
+ case SDCA_QUIRKS_RT712_VB:
+ return sdca_device_quirk_rt712_vb(slave);
+ case SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING:
+ return sdca_device_quirk_skip_func_type_patching(slave);
+ default:
+ break;
+ }
+ return false;
+}
+EXPORT_SYMBOL_NS(sdca_device_quirk_match, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c
new file mode 100644
index 000000000000..3180ebd07c40
--- /dev/null
+++ b/sound/soc/sdca/sdca_fdl.c
@@ -0,0 +1,504 @@
+// 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/acpi.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/dmi.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/sprintf.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/sdca.h>
+#include <sound/sdca_fdl.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_interrupts.h>
+#include <sound/sdca_ump.h>
+
+/**
+ * sdca_reset_function - send an SDCA function reset
+ * @dev: Device pointer for error messages.
+ * @function: Pointer to the SDCA Function.
+ * @regmap: Pointer to the SDCA Function regmap.
+ *
+ * Return: Zero on success or a negative error code.
+ */
+int sdca_reset_function(struct device *dev, struct sdca_function_data *function,
+ struct regmap *regmap)
+{
+ unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
+ SDCA_ENTITY_TYPE_ENTITY_0,
+ SDCA_CTL_ENTITY_0_FUNCTION_ACTION, 0);
+ unsigned int val, poll_us;
+ int ret;
+
+ ret = regmap_write(regmap, reg, SDCA_CTL_ENTITY_0_RESET_FUNCTION_NOW);
+ if (ret) // Allowed for function reset to not be implemented
+ return 0;
+
+ if (!function->reset_max_delay) {
+ dev_err(dev, "No reset delay specified in DisCo\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Poll up to 16 times but no more than once per ms, these are just
+ * arbitrarily selected values, so may be fine tuned in future.
+ */
+ poll_us = umin(function->reset_max_delay >> 4, 1000);
+
+ ret = regmap_read_poll_timeout(regmap, reg, val, !val, poll_us,
+ function->reset_max_delay);
+ if (ret) {
+ dev_err(dev, "Failed waiting for function reset: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_reset_function, "SND_SOC_SDCA");
+
+/**
+ * sdca_fdl_sync - wait for a function to finish FDL
+ * @dev: Device pointer for error messages.
+ * @function: Pointer to the SDCA Function.
+ * @info: Pointer to the SDCA interrupt info for this device.
+ *
+ * Return: Zero on success or a negative error code.
+ */
+int sdca_fdl_sync(struct device *dev, struct sdca_function_data *function,
+ struct sdca_interrupt_info *info)
+{
+ static const int fdl_retries = 6;
+ unsigned long begin_timeout = msecs_to_jiffies(100);
+ unsigned long done_timeout = msecs_to_jiffies(4000);
+ int nfdl;
+ int i, j;
+
+ for (i = 0; i < fdl_retries; i++) {
+ nfdl = 0;
+
+ for (j = 0; j < SDCA_MAX_INTERRUPTS; j++) {
+ struct sdca_interrupt *interrupt = &info->irqs[j];
+ struct fdl_state *fdl_state;
+ unsigned long time;
+
+ if (interrupt->function != function ||
+ !interrupt->entity || !interrupt->control ||
+ interrupt->entity->type != SDCA_ENTITY_TYPE_XU ||
+ interrupt->control->sel != SDCA_CTL_XU_FDL_CURRENTOWNER)
+ continue;
+
+ fdl_state = interrupt->priv;
+ nfdl++;
+
+ /*
+ * Looking for timeout without any new FDL requests
+ * to imply the device has completed initial
+ * firmware setup. Alas the specification doesn't
+ * have any mechanism to detect this.
+ */
+ time = wait_for_completion_timeout(&fdl_state->begin,
+ begin_timeout);
+ if (!time) {
+ dev_dbg(dev, "no new FDL starts\n");
+ nfdl--;
+ continue;
+ }
+
+ time = wait_for_completion_timeout(&fdl_state->done,
+ done_timeout);
+ if (!time) {
+ dev_err(dev, "timed out waiting for FDL to complete\n");
+ goto error;
+ }
+ }
+
+ if (!nfdl)
+ return 0;
+ }
+
+ dev_err(dev, "too many FDL requests\n");
+
+error:
+ for (j = 0; j < SDCA_MAX_INTERRUPTS; j++) {
+ struct sdca_interrupt *interrupt = &info->irqs[j];
+ struct fdl_state *fdl_state;
+
+ if (interrupt->function != function ||
+ !interrupt->entity || !interrupt->control ||
+ interrupt->entity->type != SDCA_ENTITY_TYPE_XU ||
+ interrupt->control->sel != SDCA_CTL_XU_FDL_CURRENTOWNER)
+ continue;
+
+ disable_irq(interrupt->irq);
+
+ fdl_state = interrupt->priv;
+
+ sdca_ump_cancel_timeout(&fdl_state->timeout);
+ }
+
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_fdl_sync, "SND_SOC_SDCA");
+
+static char *fdl_get_sku_filename(struct device *dev,
+ struct sdca_fdl_file *fdl_file)
+{
+ struct device *parent = dev;
+ const char *product_vendor;
+ const char *product_sku;
+
+ /*
+ * Try to find pci_dev manually because the card may not be ready to be
+ * used for snd_soc_card_get_pci_ssid yet
+ */
+ while (parent) {
+ if (dev_is_pci(parent)) {
+ struct pci_dev *pci_dev = to_pci_dev(parent);
+
+ return kasprintf(GFP_KERNEL, "sdca/%x/%x/%x/%x.bin",
+ fdl_file->vendor_id,
+ pci_dev->subsystem_vendor,
+ pci_dev->subsystem_device,
+ fdl_file->file_id);
+ } else {
+ parent = parent->parent;
+ }
+ }
+
+ product_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+ if (!product_vendor || !strcmp(product_vendor, "Default string"))
+ product_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+ if (!product_vendor || !strcmp(product_vendor, "Default string"))
+ product_vendor = dmi_get_system_info(DMI_CHASSIS_VENDOR);
+ if (!product_vendor)
+ product_vendor = "unknown";
+
+ product_sku = dmi_get_system_info(DMI_PRODUCT_SKU);
+ if (!product_sku || !strcmp(product_sku, "Default string"))
+ product_sku = dmi_get_system_info(DMI_PRODUCT_NAME);
+ if (!product_sku)
+ product_sku = "unknown";
+
+ return kasprintf(GFP_KERNEL, "sdca/%x/%s/%s/%x.bin", fdl_file->vendor_id,
+ product_vendor, product_sku, fdl_file->file_id);
+}
+
+static int fdl_load_file(struct sdca_interrupt *interrupt,
+ struct sdca_fdl_set *set, int file_index)
+{
+ struct device *dev = interrupt->dev;
+ struct sdca_fdl_data *fdl_data = &interrupt->function->fdl_data;
+ const struct firmware *firmware = NULL;
+ struct acpi_sw_file *swf = NULL, *tmp;
+ struct sdca_fdl_file *fdl_file;
+ char *disk_filename;
+ int ret;
+ int i;
+
+ if (!set) {
+ dev_err(dev, "request to load SWF with no set\n");
+ return -EINVAL;
+ }
+
+ fdl_file = &set->files[file_index];
+
+ if (fdl_data->swft) {
+ tmp = fdl_data->swft->files;
+ for (i = 0; i < fdl_data->swft->header.length; i += tmp->file_length,
+ tmp = ACPI_ADD_PTR(struct acpi_sw_file, tmp, tmp->file_length)) {
+ if (tmp->vendor_id == fdl_file->vendor_id &&
+ tmp->file_id == fdl_file->file_id) {
+ dev_dbg(dev, "located SWF in ACPI: %x-%x-%x\n",
+ tmp->vendor_id, tmp->file_id,
+ tmp->file_version);
+ swf = tmp;
+ break;
+ }
+ }
+ }
+
+ disk_filename = fdl_get_sku_filename(dev, fdl_file);
+ if (!disk_filename)
+ return -ENOMEM;
+
+ dev_dbg(dev, "FDL disk filename: %s\n", disk_filename);
+
+ ret = firmware_request_nowarn(&firmware, disk_filename, dev);
+ kfree(disk_filename);
+ if (ret) {
+ disk_filename = kasprintf(GFP_KERNEL, "sdca/%x/%x.bin",
+ fdl_file->vendor_id, fdl_file->file_id);
+ if (!disk_filename)
+ return -ENOMEM;
+
+ dev_dbg(dev, "FDL disk filename: %s\n", disk_filename);
+
+ ret = firmware_request_nowarn(&firmware, disk_filename, dev);
+ kfree(disk_filename);
+ }
+
+ if (!ret) {
+ tmp = (struct acpi_sw_file *)&firmware->data[0];
+
+ if (firmware->size < sizeof(*tmp) ||
+ tmp->file_length != firmware->size) {
+ dev_err(dev, "bad disk SWF size\n");
+ } else if (!swf || swf->file_version <= tmp->file_version) {
+ dev_dbg(dev, "using SWF from disk: %x-%x-%x\n",
+ tmp->vendor_id, tmp->file_id, tmp->file_version);
+ swf = tmp;
+ }
+ }
+
+ if (!swf) {
+ dev_err(dev, "failed to locate SWF\n");
+ return -ENOENT;
+ }
+
+ ret = sdca_ump_write_message(dev, interrupt->device_regmap,
+ interrupt->function_regmap,
+ interrupt->function, interrupt->entity,
+ SDCA_CTL_XU_FDL_MESSAGEOFFSET, fdl_file->fdl_offset,
+ SDCA_CTL_XU_FDL_MESSAGELENGTH, swf->data,
+ swf->file_length - offsetof(struct acpi_sw_file, data));
+ release_firmware(firmware);
+ return ret;
+}
+
+static struct sdca_fdl_set *fdl_get_set(struct sdca_interrupt *interrupt)
+{
+ struct device *dev = interrupt->dev;
+ struct sdca_fdl_data *fdl_data = &interrupt->function->fdl_data;
+ struct sdca_entity *xu = interrupt->entity;
+ struct sdca_control_range *range;
+ unsigned int val;
+ int i, ret;
+
+ ret = regmap_read(interrupt->function_regmap,
+ SDW_SDCA_CTL(interrupt->function->desc->adr, xu->id,
+ SDCA_CTL_XU_FDL_SET_INDEX, 0),
+ &val);
+ if (ret < 0) {
+ dev_err(dev, "failed to read FDL set index: %d\n", ret);
+ return NULL;
+ }
+
+ range = sdca_selector_find_range(dev, xu, SDCA_CTL_XU_FDL_SET_INDEX,
+ SDCA_FDL_SET_INDEX_NCOLS, 0);
+
+ val = sdca_range_search(range, SDCA_FDL_SET_INDEX_SET_NUMBER,
+ val, SDCA_FDL_SET_INDEX_FILE_SET_ID);
+
+ for (i = 0; i < fdl_data->num_sets; i++) {
+ if (fdl_data->sets[i].id == val)
+ return &fdl_data->sets[i];
+ }
+
+ dev_err(dev, "invalid fileset id: %d\n", val);
+ return NULL;
+}
+
+static void fdl_end(struct sdca_interrupt *interrupt)
+{
+ struct fdl_state *fdl_state = interrupt->priv;
+
+ if (!fdl_state->set)
+ return;
+
+ fdl_state->set = NULL;
+
+ pm_runtime_put(interrupt->dev);
+ complete(&fdl_state->done);
+
+ dev_dbg(interrupt->dev, "completed FDL process\n");
+}
+
+static void sdca_fdl_timeout_work(struct work_struct *work)
+{
+ struct fdl_state *fdl_state = container_of(work, struct fdl_state,
+ timeout.work);
+ struct sdca_interrupt *interrupt = fdl_state->interrupt;
+ struct device *dev = interrupt->dev;
+
+ dev_err(dev, "FDL transaction timed out\n");
+
+ guard(mutex)(&fdl_state->lock);
+
+ fdl_end(interrupt);
+ sdca_reset_function(dev, interrupt->function, interrupt->function_regmap);
+}
+
+static int fdl_status_process(struct sdca_interrupt *interrupt, unsigned int status)
+{
+ struct fdl_state *fdl_state = interrupt->priv;
+ int ret;
+
+ switch (status) {
+ case SDCA_CTL_XU_FDLD_NEEDS_SET:
+ dev_dbg(interrupt->dev, "starting FDL process...\n");
+
+ pm_runtime_get(interrupt->dev);
+ complete(&fdl_state->begin);
+
+ fdl_state->file_index = 0;
+ fdl_state->set = fdl_get_set(interrupt);
+ fallthrough;
+ case SDCA_CTL_XU_FDLD_MORE_FILES_OK:
+ ret = fdl_load_file(interrupt, fdl_state->set, fdl_state->file_index);
+ if (ret) {
+ fdl_end(interrupt);
+ return SDCA_CTL_XU_FDLH_REQ_ABORT;
+ }
+
+ return SDCA_CTL_XU_FDLH_FILE_AVAILABLE;
+ case SDCA_CTL_XU_FDLD_FILE_OK:
+ if (!fdl_state->set) {
+ fdl_end(interrupt);
+ return SDCA_CTL_XU_FDLH_REQ_ABORT;
+ }
+
+ fdl_state->file_index++;
+
+ if (fdl_state->file_index < fdl_state->set->num_files)
+ return SDCA_CTL_XU_FDLH_MORE_FILES;
+ fallthrough;
+ case SDCA_CTL_XU_FDLD_COMPLETE:
+ fdl_end(interrupt);
+ return SDCA_CTL_XU_FDLH_COMPLETE;
+ default:
+ fdl_end(interrupt);
+
+ if (status & SDCA_CTL_XU_FDLD_REQ_RESET)
+ return SDCA_CTL_XU_FDLH_RESET_ACK;
+ else if (status & SDCA_CTL_XU_FDLD_REQ_ABORT)
+ return SDCA_CTL_XU_FDLH_COMPLETE;
+
+ dev_err(interrupt->dev, "invalid FDL status: %x\n", status);
+ return -EINVAL;
+ }
+}
+
+/**
+ * sdca_fdl_process - Process the FDL state machine
+ * @interrupt: SDCA interrupt structure
+ *
+ * Based on section 13.2.5 Flow Diagram for File Download, Host side.
+ *
+ * Return: Zero on success or a negative error code.
+ */
+int sdca_fdl_process(struct sdca_interrupt *interrupt)
+{
+ struct device *dev = interrupt->dev;
+ struct sdca_entity_xu *xu = &interrupt->entity->xu;
+ struct fdl_state *fdl_state = interrupt->priv;
+ unsigned int reg, status;
+ int response, ret;
+
+ ret = sdca_ump_get_owner_host(dev, interrupt->function_regmap,
+ interrupt->function, interrupt->entity,
+ interrupt->control);
+ if (ret)
+ goto reset_function;
+
+ sdca_ump_cancel_timeout(&fdl_state->timeout);
+
+ scoped_guard(mutex, &fdl_state->lock) {
+ reg = SDW_SDCA_CTL(interrupt->function->desc->adr,
+ interrupt->entity->id, SDCA_CTL_XU_FDL_STATUS, 0);
+ ret = regmap_read(interrupt->function_regmap, reg, &status);
+ if (ret < 0) {
+ dev_err(dev, "failed to read FDL status: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "FDL status: %#x\n", status);
+
+ ret = fdl_status_process(interrupt, status);
+ if (ret < 0)
+ goto reset_function;
+
+ response = ret;
+
+ dev_dbg(dev, "FDL response: %#x\n", response);
+
+ ret = regmap_write(interrupt->function_regmap, reg,
+ response | (status & ~SDCA_CTL_XU_FDLH_MASK));
+ if (ret < 0) {
+ dev_err(dev, "failed to set FDL status signal: %d\n", ret);
+ return ret;
+ }
+
+ ret = sdca_ump_set_owner_device(dev, interrupt->function_regmap,
+ interrupt->function,
+ interrupt->entity,
+ interrupt->control);
+ if (ret)
+ return ret;
+
+ switch (response) {
+ case SDCA_CTL_XU_FDLH_RESET_ACK:
+ dev_dbg(dev, "FDL request reset\n");
+
+ switch (xu->reset_mechanism) {
+ default:
+ dev_warn(dev, "Requested reset mechanism not implemented\n");
+ fallthrough;
+ case SDCA_XU_RESET_FUNCTION:
+ goto reset_function;
+ }
+ case SDCA_CTL_XU_FDLH_COMPLETE:
+ if (status & SDCA_CTL_XU_FDLD_REQ_ABORT ||
+ status == SDCA_CTL_XU_FDLD_COMPLETE)
+ return 0;
+ fallthrough;
+ default:
+ sdca_ump_schedule_timeout(&fdl_state->timeout, xu->max_delay);
+ return 0;
+ }
+ }
+
+reset_function:
+ sdca_reset_function(dev, interrupt->function, interrupt->function_regmap);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_fdl_process, "SND_SOC_SDCA");
+
+/**
+ * sdca_fdl_alloc_state - allocate state for an FDL interrupt
+ * @interrupt: SDCA interrupt structure.
+ *
+ * Return: Zero on success or a negative error code.
+ */
+int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt)
+{
+ struct device *dev = interrupt->dev;
+ struct fdl_state *fdl_state;
+
+ fdl_state = devm_kzalloc(dev, sizeof(struct fdl_state), GFP_KERNEL);
+ if (!fdl_state)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&fdl_state->timeout, sdca_fdl_timeout_work);
+ init_completion(&fdl_state->begin);
+ init_completion(&fdl_state->done);
+ mutex_init(&fdl_state->lock);
+ fdl_state->interrupt = interrupt;
+
+ interrupt->priv = fdl_state;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_fdl_alloc_state, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c
new file mode 100644
index 000000000000..c6cc880a150e
--- /dev/null
+++ b/sound/soc/sdca/sdca_function_device.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2024 Intel Corporation.
+
+/*
+ * SDCA Function Device management
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include "sdca_function_device.h"
+
+/*
+ * A SoundWire device can have multiple SDCA functions identified by
+ * their type and ADR. there can be multiple SoundWire devices per
+ * link, or multiple devices spread across multiple links. An IDA is
+ * required to identify each instance.
+ */
+static DEFINE_IDA(sdca_function_ida);
+
+static void sdca_dev_release(struct device *dev)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct sdca_dev *sdev = auxiliary_dev_to_sdca_dev(auxdev);
+
+ ida_free(&sdca_function_ida, auxdev->id);
+ kfree(sdev);
+}
+
+/* alloc, init and add link devices */
+static struct sdca_dev *sdca_dev_register(struct device *parent,
+ struct sdca_function_desc *function_desc)
+{
+ struct sdca_dev *sdev;
+ struct auxiliary_device *auxdev;
+ int ret;
+ int rc;
+
+ sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+ if (!sdev)
+ return ERR_PTR(-ENOMEM);
+
+ auxdev = &sdev->auxdev;
+ auxdev->name = function_desc->name;
+ auxdev->dev.parent = parent;
+ auxdev->dev.fwnode = function_desc->node;
+ auxdev->dev.release = sdca_dev_release;
+
+ sdev->function.desc = function_desc;
+
+ rc = ida_alloc(&sdca_function_ida, GFP_KERNEL);
+ if (rc < 0) {
+ kfree(sdev);
+ return ERR_PTR(rc);
+ }
+ auxdev->id = rc;
+
+ /* now follow the two-step init/add sequence */
+ ret = auxiliary_device_init(auxdev);
+ if (ret < 0) {
+ dev_err(parent, "failed to initialize SDCA function dev %s\n",
+ function_desc->name);
+ ida_free(&sdca_function_ida, auxdev->id);
+ kfree(sdev);
+ return ERR_PTR(ret);
+ }
+
+ ret = auxiliary_device_add(auxdev);
+ if (ret < 0) {
+ dev_err(parent, "failed to add SDCA function dev %s\n",
+ sdev->auxdev.name);
+ /* sdev will be freed with the put_device() and .release sequence */
+ auxiliary_device_uninit(&sdev->auxdev);
+ return ERR_PTR(ret);
+ }
+
+ return sdev;
+}
+
+static void sdca_dev_unregister(struct sdca_dev *sdev)
+{
+ auxiliary_device_delete(&sdev->auxdev);
+ auxiliary_device_uninit(&sdev->auxdev);
+}
+
+int sdca_dev_register_functions(struct sdw_slave *slave)
+{
+ struct sdca_device_data *sdca_data = &slave->sdca_data;
+ int i;
+
+ for (i = 0; i < sdca_data->num_functions; i++) {
+ struct sdca_dev *func_dev;
+
+ func_dev = sdca_dev_register(&slave->dev,
+ &sdca_data->function[i]);
+ if (IS_ERR(func_dev))
+ return PTR_ERR(func_dev);
+
+ sdca_data->function[i].func_dev = func_dev;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_dev_register_functions, "SND_SOC_SDCA");
+
+void sdca_dev_unregister_functions(struct sdw_slave *slave)
+{
+ struct sdca_device_data *sdca_data = &slave->sdca_data;
+ int i;
+
+ for (i = 0; i < sdca_data->num_functions; i++)
+ sdca_dev_unregister(sdca_data->function[i].func_dev);
+}
+EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_function_device.h b/sound/soc/sdca/sdca_function_device.h
new file mode 100644
index 000000000000..5adf7551d3a4
--- /dev/null
+++ b/sound/soc/sdca/sdca_function_device.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* Copyright(c) 2024 Intel Corporation. */
+
+#ifndef __SDCA_FUNCTION_DEVICE_H
+#define __SDCA_FUNCTION_DEVICE_H
+
+struct sdca_dev {
+ struct auxiliary_device auxdev;
+ struct sdca_function_data function;
+};
+
+#define auxiliary_dev_to_sdca_dev(auxiliary_dev) \
+ container_of(auxiliary_dev, struct sdca_dev, auxdev)
+
+#endif
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
new file mode 100644
index 000000000000..5a1f120487ef
--- /dev/null
+++ b/sound/soc/sdca/sdca_functions.c
@@ -0,0 +1,2282 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2024 Intel Corporation
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#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/string.h>
+#include <linux/types.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_hid.h>
+
+/*
+ * Should be long enough to encompass all the MIPI DisCo properties.
+ */
+#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.
+ */
+ 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;
+ }
+ }
+
+ return 0;
+}
+
+static const char *get_sdca_function_name(u32 function_type)
+{
+ switch (function_type) {
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ return SDCA_FUNCTION_TYPE_SMART_AMP_NAME;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ return SDCA_FUNCTION_TYPE_SMART_MIC_NAME;
+ case SDCA_FUNCTION_TYPE_UAJ:
+ return SDCA_FUNCTION_TYPE_UAJ_NAME;
+ case SDCA_FUNCTION_TYPE_HID:
+ 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_COMPANION_AMP:
+ return SDCA_FUNCTION_TYPE_COMPANION_AMP_NAME;
+ case SDCA_FUNCTION_TYPE_IMP_DEF:
+ return SDCA_FUNCTION_TYPE_IMP_DEF_NAME;
+ default:
+ return NULL;
+ }
+}
+
+static int find_sdca_function(struct acpi_device *adev, void *data)
+{
+ struct fwnode_handle *function_node = acpi_fwnode_handle(adev);
+ struct sdca_device_data *sdca_data = data;
+ struct sdw_slave *slave = container_of(sdca_data, struct sdw_slave, sdca_data);
+ struct device *dev = &adev->dev;
+ struct fwnode_handle *control5; /* used to identify function type */
+ const char *function_name;
+ u32 function_type;
+ int function_index;
+ u64 addr;
+ int ret;
+
+ if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) {
+ dev_err(dev, "maximum number of functions exceeded\n");
+ return -EINVAL;
+ }
+
+ ret = acpi_get_local_u64_address(adev->handle, &addr);
+ if (ret < 0)
+ return ret;
+
+ if (!addr || addr > 0x7) {
+ dev_err(dev, "invalid addr: 0x%llx\n", addr);
+ return -ENODEV;
+ }
+
+ /*
+ * Extracting the topology type for an SDCA function is a
+ * convoluted process.
+ * The Function type is only visible as a result of a read
+ * from a control. In theory this would mean reading from the hardware,
+ * but the SDCA/DisCo specs defined the notion of "DC value" - a constant
+ * represented with a DSD subproperty.
+ * Drivers have to query the properties for the control
+ * SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05)
+ */
+ control5 = fwnode_get_named_child_node(function_node,
+ "mipi-sdca-control-0x5-subproperties");
+ if (!control5)
+ return -ENODEV;
+
+ ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value",
+ &function_type);
+
+ fwnode_handle_put(control5);
+
+ if (ret < 0) {
+ dev_err(dev, "function type only supported as DisCo constant\n");
+ return ret;
+ }
+
+ if (!sdca_device_quirk_match(slave, SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING)) {
+ 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 */
+ 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 *sdev = &slave->dev;
+ struct acpi_device *adev = to_acpi_device_node(sdev->fwnode);
+
+ if (!adev) {
+ dev_info(sdev, "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 / sizeof(*raw)) > 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 bool find_sdca_control_volatile(const struct sdca_entity *entity,
+ const struct sdca_control *control)
+{
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_DC:
+ return false;
+ case SDCA_ACCESS_MODE_RO:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ return true;
+ default:
+ break;
+ }
+
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(XU, FDL_STATUS):
+ case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH):
+ return true;
+ default:
+ return false;
+ }
+}
+
+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;
+}
+
+static int find_sdca_control_value(struct device *dev, struct sdca_entity *entity,
+ struct fwnode_handle *control_node,
+ struct sdca_control *control,
+ const char * const label)
+{
+ char property[SDCA_PROPERTY_LENGTH];
+ bool global = true;
+ int ret, cn, i;
+ u32 tmp;
+
+ snprintf(property, sizeof(property), "mipi-sdca-control-%s", label);
+
+ ret = fwnode_property_read_u32(control_node, property, &tmp);
+ if (ret == -EINVAL)
+ global = false;
+ else if (ret)
+ return ret;
+
+ i = 0;
+ for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+ BITS_PER_TYPE(control->cn_list)) {
+ if (!global) {
+ snprintf(property, sizeof(property),
+ "mipi-sdca-control-cn-%d-%s", cn, label);
+
+ ret = fwnode_property_read_u32(control_node, property, &tmp);
+ if (ret)
+ return ret;
+ }
+
+ control->values[i] = tmp;
+ 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;
+
+ 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;
+ }
+
+ control->values = devm_kcalloc(dev, hweight64(control->cn_list),
+ sizeof(int), GFP_KERNEL);
+ if (!control->values)
+ return -ENOMEM;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_DC:
+ ret = find_sdca_control_value(dev, entity, control_node, control,
+ "dc-value");
+ if (ret) {
+ dev_err(dev, "%s: control %#x: dc value missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ control->has_fixed = true;
+ break;
+ case SDCA_ACCESS_MODE_RW:
+ case SDCA_ACCESS_MODE_DUAL:
+ ret = find_sdca_control_value(dev, entity, control_node, control,
+ "default-value");
+ if (!ret)
+ control->has_default = true;
+
+ ret = find_sdca_control_value(dev, entity, control_node, control,
+ "fixed-value");
+ if (!ret)
+ control->has_fixed = true;
+ fallthrough;
+ case SDCA_ACCESS_MODE_RO:
+ control->deferrable = fwnode_property_read_bool(control_node,
+ "mipi-sdca-control-deferrable");
+ break;
+ default:
+ break;
+ }
+
+ control->is_volatile = find_sdca_control_volatile(entity, control);
+
+ 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_u32(control_node,
+ "mipi-sdca-control-interrupt-position",
+ &tmp);
+ if (!ret)
+ control->interrupt_position = tmp;
+ else
+ control->interrupt_position = SDCA_NO_INTERRUPT;
+
+ 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_dbg(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n",
+ entity->label, control->label, control->sel,
+ control->mode, control->layers, control->cn_list,
+ control->interrupt_position, 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);
+
+ if (!terminal->is_dataport) {
+ const char *type_name = sdca_find_terminal_name(terminal->type);
+
+ if (type_name)
+ entity->label = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+ entity->label, type_name);
+ }
+
+ 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_dbg(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_dbg(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;
+ }
+
+ 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;
+
+ delays = devm_kcalloc(dev, num_delays, sizeof(*delays), GFP_KERNEL);
+ if (!delays)
+ return -ENOMEM;
+
+ 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_dbg(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_hide(struct device *dev, struct sdw_slave *sdw,
+ struct fwnode_handle *function_node,
+ struct fwnode_handle *entity_node, struct sdca_entity *entity)
+{
+ struct sdca_entity_hide *hide = &entity->hide;
+ unsigned int delay, *af_list = hide->af_number_list;
+ int nval, ret;
+ unsigned char *report_desc = NULL;
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay);
+ if (!ret)
+ hide->max_delay = delay;
+
+ nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDTx-supported-report-ids");
+ if (nval > 0) {
+ hide->num_hidtx_ids = nval;
+ hide->hidtx_ids = devm_kcalloc(dev, hide->num_hidtx_ids,
+ sizeof(*hide->hidtx_ids), GFP_KERNEL);
+ if (!hide->hidtx_ids)
+ return -ENOMEM;
+
+ ret = fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-HIDTx-supported-report-ids",
+ hide->hidtx_ids,
+ hide->num_hidtx_ids);
+ if (ret < 0)
+ return ret;
+ }
+
+ nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDRx-supported-report-ids");
+ if (nval > 0) {
+ hide->num_hidrx_ids = nval;
+ hide->hidrx_ids = devm_kcalloc(dev, hide->num_hidrx_ids,
+ sizeof(*hide->hidrx_ids), GFP_KERNEL);
+ if (!hide->hidrx_ids)
+ return -ENOMEM;
+
+ ret = fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-HIDRx-supported-report-ids",
+ hide->hidrx_ids,
+ hide->num_hidrx_ids);
+ if (ret < 0)
+ return ret;
+ }
+
+ nval = fwnode_property_count_u32(entity_node, "mipi-sdca-hide-related-audio-function-list");
+ if (nval <= 0) {
+ dev_err(dev, "%pfwP: audio function numbers list missing: %d\n",
+ entity_node, nval);
+ return -EINVAL;
+ } else if (nval > SDCA_MAX_FUNCTION_COUNT) {
+ dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", entity_node);
+ return -EINVAL;
+ }
+
+ hide->hide_reside_function_num = nval;
+ fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-hide-related-audio-function-list", af_list, nval);
+
+ nval = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor");
+ if (nval)
+ fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor",
+ (u8 *)&hide->hid_desc, nval);
+
+ if (hide->hid_desc.bNumDescriptors) {
+ nval = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor");
+ if (nval) {
+ report_desc = devm_kzalloc(dev, nval, GFP_KERNEL);
+ if (!report_desc)
+ return -ENOMEM;
+ hide->hid_report_desc = report_desc;
+ fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor",
+ report_desc, nval);
+
+ /* add HID device */
+ ret = sdca_add_hid_device(dev, sdw, entity);
+ if (ret) {
+ dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int find_sdca_entity_xu(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_xu *xu = &entity->xu;
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-RxUMP-ownership-transition-max-delay",
+ &tmp);
+ if (!ret)
+ xu->max_delay = tmp;
+
+ ret = fwnode_property_read_u32(entity_node, "mipi-sdca-FDL-reset-mechanism",
+ &tmp);
+ if (!ret)
+ xu->reset_mechanism = tmp;
+
+ return 0;
+}
+
+static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
+ 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_dbg(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_XU:
+ ret = find_sdca_entity_xu(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;
+ case SDCA_ENTITY_TYPE_HIDE:
+ ret = find_sdca_entity_hide(dev, sdw, function_node,
+ 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 sdw_slave *sdw,
+ 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, sdw, 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 (!strncmp(entity->label, entity_label, strlen(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_dbg(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_dbg(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. */
+ 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_dbg(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_dbg(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;
+}
+
+static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
+ struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ static const int mult_fileset = 3;
+ char fileset_name[SDCA_PROPERTY_LENGTH];
+ u32 *filesets_list __free(kfree) = NULL;
+ struct sdca_fdl_set *sets;
+ int num_sets;
+ int i, j;
+
+ num_sets = fwnode_property_count_u32(function_node,
+ "mipi-sdca-file-set-id-list");
+ if (num_sets == 0 || num_sets == -EINVAL) {
+ return 0;
+ } else if (num_sets < 0) {
+ dev_err(dev, "%pfwP: failed to read file set list: %d\n",
+ function_node, num_sets);
+ return num_sets;
+ }
+
+ filesets_list = kcalloc(num_sets, sizeof(u32), GFP_KERNEL);
+ if (!filesets_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(function_node, "mipi-sdca-file-set-id-list",
+ filesets_list, num_sets);
+
+ sets = devm_kcalloc(dev, num_sets, sizeof(struct sdca_fdl_set), GFP_KERNEL);
+ if (!sets)
+ return -ENOMEM;
+
+ for (i = 0; i < num_sets; i++) {
+ u32 *fileset_entries __free(kfree) = NULL;
+ struct sdca_fdl_set *set = &sets[i];
+ struct sdca_fdl_file *files;
+ int num_files, num_entries;
+
+ snprintf(fileset_name, sizeof(fileset_name),
+ "mipi-sdca-file-set-id-0x%X", filesets_list[i]);
+
+ num_entries = fwnode_property_count_u32(function_node, fileset_name);
+ if (num_entries <= 0) {
+ dev_err(dev, "%pfwP: file set %d missing entries: %d\n",
+ function_node, filesets_list[i], num_entries);
+ return -EINVAL;
+ } else if (num_entries % mult_fileset != 0) {
+ dev_err(dev, "%pfwP: file set %d files not multiple of %d\n",
+ function_node, filesets_list[i], mult_fileset);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "fileset: %#x\n", filesets_list[i]);
+
+ files = devm_kcalloc(dev, num_entries / mult_fileset,
+ sizeof(struct sdca_fdl_file), GFP_KERNEL);
+ if (!files)
+ return -ENOMEM;
+
+ fileset_entries = kcalloc(num_entries, sizeof(u32), GFP_KERNEL);
+ if (!fileset_entries)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(function_node, fileset_name,
+ fileset_entries, num_entries);
+
+ for (j = 0, num_files = 0; j < num_entries; num_files++) {
+ struct sdca_fdl_file *file = &files[num_files];
+
+ file->vendor_id = fileset_entries[j++];
+ file->file_id = fileset_entries[j++];
+ file->fdl_offset = fileset_entries[j++];
+
+ dev_dbg(dev, "file: %#x, vendor: %#x, offset: %#x\n",
+ file->file_id, file->vendor_id, file->fdl_offset);
+ }
+
+ set->id = filesets_list[i];
+ set->num_files = num_files;
+ set->files = files;
+ }
+
+ function->fdl_data.swft = sdw->sdca_data.swft;
+ function->fdl_data.num_sets = num_sets;
+ function->fdl_data.sets = sets;
+
+ return 0;
+}
+
+/**
+ * sdca_parse_function - parse ACPI DisCo for a Function
+ * @dev: Pointer to device against which function data will be allocated.
+ * @sdw: SoundWire slave device to be processed.
+ * @function_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 sdw_slave *sdw,
+ 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;
+
+ ret = fwnode_property_read_u32(function_desc->node,
+ "mipi-sdca-function-reset-max-delay", &tmp);
+ if (!ret)
+ function->reset_max_delay = tmp;
+
+ dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n",
+ function->desc->node, function->desc->name,
+ function->busy_max_delay, function->reset_max_delay);
+
+ ret = find_sdca_init_table(dev, function_desc->node, function);
+ if (ret)
+ return ret;
+
+ ret = find_sdca_entities(dev, sdw, 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;
+
+ ret = find_sdca_filesets(dev, sdw, function_desc->node, function);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA");
+
+const char *sdca_find_terminal_name(enum sdca_terminal_type type)
+{
+ switch (type) {
+ case SDCA_TERM_TYPE_LINEIN_STEREO:
+ return SDCA_TERM_TYPE_LINEIN_STEREO_NAME;
+ case SDCA_TERM_TYPE_LINEIN_FRONT_LR:
+ return SDCA_TERM_TYPE_LINEIN_FRONT_LR_NAME;
+ case SDCA_TERM_TYPE_LINEIN_CENTER_LFE:
+ return SDCA_TERM_TYPE_LINEIN_CENTER_LFE_NAME;
+ case SDCA_TERM_TYPE_LINEIN_SURROUND_LR:
+ return SDCA_TERM_TYPE_LINEIN_SURROUND_LR_NAME;
+ case SDCA_TERM_TYPE_LINEIN_REAR_LR:
+ return SDCA_TERM_TYPE_LINEIN_REAR_LR_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_STEREO:
+ return SDCA_TERM_TYPE_LINEOUT_STEREO_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_FRONT_LR:
+ return SDCA_TERM_TYPE_LINEOUT_FRONT_LR_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE:
+ return SDCA_TERM_TYPE_LINEOUT_CENTER_LFE_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR:
+ return SDCA_TERM_TYPE_LINEOUT_SURROUND_LR_NAME;
+ case SDCA_TERM_TYPE_LINEOUT_REAR_LR:
+ return SDCA_TERM_TYPE_LINEOUT_REAR_LR_NAME;
+ case SDCA_TERM_TYPE_MIC_JACK:
+ return SDCA_TERM_TYPE_MIC_JACK_NAME;
+ case SDCA_TERM_TYPE_STEREO_JACK:
+ return SDCA_TERM_TYPE_STEREO_JACK_NAME;
+ case SDCA_TERM_TYPE_FRONT_LR_JACK:
+ return SDCA_TERM_TYPE_FRONT_LR_JACK_NAME;
+ case SDCA_TERM_TYPE_CENTER_LFE_JACK:
+ return SDCA_TERM_TYPE_CENTER_LFE_JACK_NAME;
+ case SDCA_TERM_TYPE_SURROUND_LR_JACK:
+ return SDCA_TERM_TYPE_SURROUND_LR_JACK_NAME;
+ case SDCA_TERM_TYPE_REAR_LR_JACK:
+ return SDCA_TERM_TYPE_REAR_LR_JACK_NAME;
+ case SDCA_TERM_TYPE_HEADPHONE_JACK:
+ return SDCA_TERM_TYPE_HEADPHONE_JACK_NAME;
+ case SDCA_TERM_TYPE_HEADSET_JACK:
+ return SDCA_TERM_TYPE_HEADSET_JACK_NAME;
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL_NS(sdca_find_terminal_name, "SND_SOC_SDCA");
+
+struct sdca_control *sdca_selector_find_control(struct device *dev,
+ struct sdca_entity *entity,
+ const int sel)
+{
+ int i;
+
+ for (i = 0; i < entity->num_controls; i++) {
+ struct sdca_control *control = &entity->controls[i];
+
+ if (control->sel == sel)
+ return control;
+ }
+
+ dev_err(dev, "%s: control %#x: missing\n", entity->label, sel);
+ return NULL;
+}
+EXPORT_SYMBOL_NS(sdca_selector_find_control, "SND_SOC_SDCA");
+
+struct sdca_control_range *sdca_control_find_range(struct device *dev,
+ struct sdca_entity *entity,
+ struct sdca_control *control,
+ int cols, int rows)
+{
+ struct sdca_control_range *range = &control->range;
+
+ if ((cols && range->cols != cols) || (rows && range->rows != rows) ||
+ !range->data) {
+ dev_err(dev, "%s: control %#x: ranges invalid (%d,%d)\n",
+ entity->label, control->sel, range->cols, range->rows);
+ return NULL;
+ }
+
+ return range;
+}
+EXPORT_SYMBOL_NS(sdca_control_find_range, "SND_SOC_SDCA");
+
+struct sdca_control_range *sdca_selector_find_range(struct device *dev,
+ struct sdca_entity *entity,
+ int sel, int cols, int rows)
+{
+ struct sdca_control *control;
+
+ control = sdca_selector_find_control(dev, entity, sel);
+ if (!control)
+ return NULL;
+
+ return sdca_control_find_range(dev, entity, control, cols, rows);
+}
+EXPORT_SYMBOL_NS(sdca_selector_find_range, "SND_SOC_SDCA");
+
+struct sdca_cluster *sdca_id_find_cluster(struct device *dev,
+ struct sdca_function_data *function,
+ const int id)
+{
+ int i;
+
+ for (i = 0; i < function->num_clusters; i++) {
+ struct sdca_cluster *cluster = &function->clusters[i];
+
+ if (cluster->id == id)
+ return cluster;
+ }
+
+ dev_err(dev, "%s: cluster %#x: missing\n", function->desc->name, id);
+ return NULL;
+}
+EXPORT_SYMBOL_NS(sdca_id_find_cluster, "SND_SOC_SDCA");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SDCA library");
diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c
new file mode 100644
index 000000000000..abbd56a3d297
--- /dev/null
+++ b/sound/soc/sdca/sdca_hid.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/acpi.h>
+#include <linux/byteorder/generic.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/hid.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>
+#include <sound/sdca_hid.h>
+#include <sound/sdca_interrupts.h>
+#include <sound/sdca_ump.h>
+
+static int sdwhid_parse(struct hid_device *hid)
+{
+ struct sdca_entity *entity = hid->driver_data;
+ unsigned int rsize;
+ int ret;
+
+ rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength);
+
+ if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+ dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize);
+ return -EINVAL;
+ }
+
+ ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize);
+
+ if (!ret)
+ return 0;
+
+ dev_err(&hid->dev, "parsing report descriptor failed\n");
+ return ret;
+}
+
+static int sdwhid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void sdwhid_stop(struct hid_device *hid)
+{
+}
+
+static int sdwhid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype, int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ /* not implemented yet */
+ return 0;
+ case HID_REQ_SET_REPORT:
+ /* not implemented yet */
+ return 0;
+ default:
+ return -EIO;
+ }
+}
+
+static int sdwhid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void sdwhid_close(struct hid_device *hid)
+{
+}
+
+static const struct hid_ll_driver sdw_hid_driver = {
+ .parse = sdwhid_parse,
+ .start = sdwhid_start,
+ .stop = sdwhid_stop,
+ .open = sdwhid_open,
+ .close = sdwhid_close,
+ .raw_request = sdwhid_raw_request,
+};
+
+int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
+ struct sdca_entity *entity)
+{
+ struct sdw_bus *bus = sdw->bus;
+ struct hid_device *hid;
+ int ret;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid))
+ return PTR_ERR(hid);
+
+ hid->ll_driver = &sdw_hid_driver;
+
+ hid->dev.parent = dev;
+ hid->bus = BUS_SDW;
+ hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID);
+
+ snprintf(hid->name, sizeof(hid->name),
+ "HID sdw:%01x:%01x:%04x:%04x:%02x",
+ bus->controller_id, bus->link_id, sdw->id.mfg_id,
+ sdw->id.part_id, sdw->id.class_id);
+
+ snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name);
+
+ hid->driver_data = entity;
+
+ ret = hid_add_device(hid);
+ if (ret && ret != -ENODEV) {
+ dev_err(dev, "can't add hid device: %d\n", ret);
+ hid_destroy_device(hid);
+ return ret;
+ }
+
+ entity->hide.hid = hid;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA");
+
+/**
+ * sdca_hid_process_report - read a HID event from the device and report
+ * @interrupt: Pointer to the SDCA interrupt information structure.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+int sdca_hid_process_report(struct sdca_interrupt *interrupt)
+{
+ struct device *dev = interrupt->dev;
+ struct hid_device *hid = interrupt->entity->hide.hid;
+ void *val __free(kfree) = NULL;
+ int len, ret;
+
+ ret = sdca_ump_get_owner_host(dev, interrupt->function_regmap,
+ interrupt->function, interrupt->entity,
+ interrupt->control);
+ if (ret)
+ return ret;
+
+ len = sdca_ump_read_message(dev, interrupt->device_regmap,
+ interrupt->function_regmap,
+ interrupt->function, interrupt->entity,
+ SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET,
+ SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH, &val);
+ if (len < 0)
+ return len;
+
+ ret = sdca_ump_set_owner_device(dev, interrupt->function_regmap,
+ interrupt->function, interrupt->entity,
+ interrupt->control);
+ if (ret)
+ return ret;
+
+ ret = hid_input_report(hid, HID_INPUT_REPORT, val, len, true);
+ if (ret < 0) {
+ dev_err(dev, "failed to report hid event: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_hid_process_report, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c
new file mode 100644
index 000000000000..8f6a2adfb6fb
--- /dev/null
+++ b/sound/soc/sdca/sdca_interrupts.c
@@ -0,0 +1,612 @@
+// 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/bitmap.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/sdca.h>
+#include <sound/sdca_fdl.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_hid.h>
+#include <sound/sdca_interrupts.h>
+#include <sound/sdca_ump.h>
+#include <sound/soc-component.h>
+#include <sound/soc.h>
+
+#define IRQ_SDCA(number) REGMAP_IRQ_REG(number, ((number) / BITS_PER_BYTE), \
+ SDW_SCP_SDCA_INTMASK_SDCA_##number)
+
+static const struct regmap_irq regmap_irqs[SDCA_MAX_INTERRUPTS] = {
+ IRQ_SDCA(0),
+ IRQ_SDCA(1),
+ IRQ_SDCA(2),
+ IRQ_SDCA(3),
+ IRQ_SDCA(4),
+ IRQ_SDCA(5),
+ IRQ_SDCA(6),
+ IRQ_SDCA(7),
+ IRQ_SDCA(8),
+ IRQ_SDCA(9),
+ IRQ_SDCA(10),
+ IRQ_SDCA(11),
+ IRQ_SDCA(12),
+ IRQ_SDCA(13),
+ IRQ_SDCA(14),
+ IRQ_SDCA(15),
+ IRQ_SDCA(16),
+ IRQ_SDCA(17),
+ IRQ_SDCA(18),
+ IRQ_SDCA(19),
+ IRQ_SDCA(20),
+ IRQ_SDCA(21),
+ IRQ_SDCA(22),
+ IRQ_SDCA(23),
+ IRQ_SDCA(24),
+ IRQ_SDCA(25),
+ IRQ_SDCA(26),
+ IRQ_SDCA(27),
+ IRQ_SDCA(28),
+ IRQ_SDCA(29),
+ IRQ_SDCA(30),
+};
+
+static const struct regmap_irq_chip sdca_irq_chip = {
+ .name = "sdca_irq",
+
+ .status_base = SDW_SCP_SDCA_INT1,
+ .unmask_base = SDW_SCP_SDCA_INTMASK1,
+ .ack_base = SDW_SCP_SDCA_INT1,
+ .num_regs = 4,
+
+ .irqs = regmap_irqs,
+ .num_irqs = SDCA_MAX_INTERRUPTS,
+
+ .runtime_pm = true,
+};
+
+static irqreturn_t base_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct device *dev = interrupt->dev;
+
+ dev_info(dev, "%s irq without full handling\n", interrupt->name);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t function_status_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct device *dev = interrupt->dev;
+ irqreturn_t irqret = IRQ_NONE;
+ unsigned int reg, val;
+ unsigned long status;
+ unsigned int mask;
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to resume for function status: %d\n", ret);
+ goto error;
+ }
+
+ reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
+ interrupt->control->sel, 0);
+
+ ret = regmap_read(interrupt->function_regmap, reg, &val);
+ if (ret < 0) {
+ dev_err(dev, "failed to read function status: %d\n", ret);
+ goto error;
+ }
+
+ dev_dbg(dev, "function status: %#x\n", val);
+
+ status = val;
+ for_each_set_bit(mask, &status, BITS_PER_BYTE) {
+ mask = 1 << mask;
+
+ switch (mask) {
+ case SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION:
+ //FIXME: Add init writes
+ break;
+ case SDCA_CTL_ENTITY_0_FUNCTION_FAULT:
+ dev_err(dev, "function fault\n");
+ break;
+ case SDCA_CTL_ENTITY_0_UMP_SEQUENCE_FAULT:
+ dev_err(dev, "ump sequence fault\n");
+ break;
+ case SDCA_CTL_ENTITY_0_FUNCTION_BUSY:
+ dev_info(dev, "unexpected function busy\n");
+ break;
+ case SDCA_CTL_ENTITY_0_DEVICE_NEWLY_ATTACHED:
+ case SDCA_CTL_ENTITY_0_INTS_DISABLED_ABNORMALLY:
+ case SDCA_CTL_ENTITY_0_STREAMING_STOPPED_ABNORMALLY:
+ case SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET:
+ break;
+ }
+ }
+
+ ret = regmap_write(interrupt->function_regmap, reg, val);
+ if (ret < 0) {
+ dev_err(dev, "failed to clear function status: %d\n", ret);
+ goto error;
+ }
+
+ irqret = IRQ_HANDLED;
+error:
+ pm_runtime_put(dev);
+ return irqret;
+}
+
+static irqreturn_t detected_mode_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct device *dev = interrupt->dev;
+ struct snd_soc_component *component = interrupt->component;
+ struct snd_soc_card *card = component->card;
+ struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem;
+ struct snd_kcontrol *kctl = interrupt->priv;
+ struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL;
+ struct soc_enum *soc_enum;
+ irqreturn_t irqret = IRQ_NONE;
+ unsigned int reg, val;
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to resume for detected mode: %d\n", ret);
+ goto error;
+ }
+
+ if (!kctl) {
+ const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s",
+ interrupt->entity->label,
+ SDCA_CTL_SELECTED_MODE_NAME);
+
+ if (!name)
+ goto error;
+
+ kctl = snd_soc_component_get_kcontrol(component, name);
+ if (!kctl) {
+ dev_dbg(dev, "control not found: %s\n", name);
+ goto error;
+ }
+
+ interrupt->priv = kctl;
+ }
+
+ soc_enum = (struct soc_enum *)kctl->private_value;
+
+ reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
+ interrupt->control->sel, 0);
+
+ ret = regmap_read(interrupt->function_regmap, reg, &val);
+ if (ret < 0) {
+ dev_err(dev, "failed to read detected mode: %d\n", ret);
+ goto error;
+ }
+
+ switch (val) {
+ case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS:
+ case SDCA_DETECTED_MODE_JACK_UNKNOWN:
+ reg = SDW_SDCA_CTL(interrupt->function->desc->adr,
+ interrupt->entity->id,
+ SDCA_CTL_GE_SELECTED_MODE, 0);
+
+ /*
+ * Selected mode is not normally marked as volatile register
+ * (RW), but here force a read from the hardware. If the
+ * detected mode is unknown we need to see what the device
+ * selected as a "safe" option.
+ */
+ regcache_drop_region(interrupt->function_regmap, reg, reg);
+
+ ret = regmap_read(interrupt->function_regmap, reg, &val);
+ if (ret) {
+ dev_err(dev, "failed to re-check selected mode: %d\n", ret);
+ goto error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ dev_dbg(dev, "%s: %#x\n", interrupt->name, val);
+
+ ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL);
+ if (!ucontrol)
+ goto error;
+
+ ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val);
+
+ down_write(rwsem);
+ ret = kctl->put(kctl, ucontrol);
+ up_write(rwsem);
+ if (ret < 0) {
+ dev_err(dev, "failed to update selected mode: %d\n", ret);
+ goto error;
+ }
+
+ snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+
+ irqret = IRQ_HANDLED;
+error:
+ pm_runtime_put(dev);
+ return irqret;
+}
+
+static irqreturn_t hid_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct device *dev = interrupt->dev;
+ irqreturn_t irqret = IRQ_NONE;
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to resume for hid: %d\n", ret);
+ goto error;
+ }
+
+ ret = sdca_hid_process_report(interrupt);
+ if (ret)
+ goto error;
+
+ irqret = IRQ_HANDLED;
+error:
+ pm_runtime_put(dev);
+ return irqret;
+}
+
+static irqreturn_t fdl_owner_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct device *dev = interrupt->dev;
+ irqreturn_t irqret = IRQ_NONE;
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "failed to resume for fdl: %d\n", ret);
+ goto error;
+ }
+
+ ret = sdca_fdl_process(interrupt);
+ if (ret)
+ goto error;
+
+ irqret = IRQ_HANDLED;
+error:
+ pm_runtime_put(dev);
+ return irqret;
+}
+
+static int sdca_irq_request_locked(struct device *dev,
+ struct sdca_interrupt_info *info,
+ int sdca_irq, const char *name,
+ irq_handler_t handler, void *data)
+{
+ int irq;
+ int ret;
+
+ irq = regmap_irq_get_virq(info->irq_data, sdca_irq);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, handler,
+ IRQF_ONESHOT, name, data);
+ if (ret)
+ return ret;
+
+ info->irqs[sdca_irq].irq = irq;
+
+ dev_dbg(dev, "requested irq %d for %s\n", irq, name);
+
+ return 0;
+}
+
+/**
+ * sdca_request_irq - request an individual SDCA interrupt
+ * @dev: Pointer to the struct device against which things should be allocated.
+ * @interrupt_info: Pointer to the interrupt information structure.
+ * @sdca_irq: SDCA interrupt position.
+ * @name: Name to be given to the IRQ.
+ * @handler: A callback thread function to be called for the IRQ.
+ * @data: Private data pointer that will be passed to the handler.
+ *
+ * Typically this is handled internally by sdca_irq_populate, however if
+ * a device requires custom IRQ handling this can be called manually before
+ * calling sdca_irq_populate, which will then skip that IRQ whilst processing.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *info,
+ int sdca_irq, const char *name, irq_handler_t handler,
+ void *data)
+{
+ int ret;
+
+ if (sdca_irq < 0 || sdca_irq >= SDCA_MAX_INTERRUPTS) {
+ dev_err(dev, "bad irq request: %d\n", sdca_irq);
+ return -EINVAL;
+ }
+
+ guard(mutex)(&info->irq_lock);
+
+ ret = sdca_irq_request_locked(dev, info, sdca_irq, name, handler, data);
+ if (ret) {
+ dev_err(dev, "failed to request irq %s: %d\n", name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_irq_request, "SND_SOC_SDCA");
+
+/**
+ * sdca_irq_data_populate - Populate common interrupt data
+ * @dev: Pointer to the Function device.
+ * @regmap: Pointer to the Function regmap.
+ * @component: Pointer to the ASoC component for the Function.
+ * @function: Pointer to the SDCA Function.
+ * @entity: Pointer to the SDCA Entity.
+ * @control: Pointer to the SDCA Control.
+ * @interrupt: Pointer to the SDCA interrupt for this IRQ.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+int sdca_irq_data_populate(struct device *dev, struct regmap *regmap,
+ struct snd_soc_component *component,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct sdca_control *control,
+ struct sdca_interrupt *interrupt)
+{
+ const char *name;
+
+ if (!dev && component)
+ dev = component->dev;
+ if (!dev)
+ return -ENODEV;
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s %s %s", function->desc->name,
+ entity->label, control->label);
+ if (!name)
+ return -ENOMEM;
+
+ interrupt->name = name;
+ interrupt->dev = dev;
+ if (!regmap && component)
+ interrupt->function_regmap = component->regmap;
+ else
+ interrupt->function_regmap = regmap;
+ interrupt->component = component;
+ interrupt->function = function;
+ interrupt->entity = entity;
+ interrupt->control = control;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_irq_data_populate, "SND_SOC_SDCA");
+
+static struct sdca_interrupt *get_interrupt_data(struct device *dev, int irq,
+ struct sdca_interrupt_info *info)
+{
+ if (irq == SDCA_NO_INTERRUPT) {
+ return NULL;
+ } else if (irq < 0 || irq >= SDCA_MAX_INTERRUPTS) {
+ dev_err(dev, "bad irq position: %d\n", irq);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (info->irqs[irq].irq) {
+ dev_dbg(dev, "skipping irq %d, already requested\n", irq);
+ return NULL;
+ }
+
+ return &info->irqs[irq];
+}
+
+/**
+ * sdca_irq_populate_early - process pre-audio card IRQ registrations
+ * @dev: Device pointer for SDCA Function.
+ * @regmap: Regmap pointer for the SDCA Function.
+ * @function: Pointer to the SDCA Function.
+ * @info: Pointer to the SDCA interrupt info for this device.
+ *
+ * This is intended to be used as part of the Function boot process. It
+ * can be called before the soundcard is registered (ie. doesn't depend
+ * on component) and will register the FDL interrupts.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct sdca_interrupt_info *info)
+{
+ int i, j;
+
+ guard(mutex)(&info->irq_lock);
+
+ 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 irq = control->interrupt_position;
+ struct sdca_interrupt *interrupt;
+ int ret;
+
+ interrupt = get_interrupt_data(dev, irq, info);
+ if (IS_ERR(interrupt))
+ return PTR_ERR(interrupt);
+ else if (!interrupt)
+ continue;
+
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
+ ret = sdca_irq_data_populate(dev, regmap, NULL,
+ function, entity,
+ control, interrupt);
+ if (ret)
+ return ret;
+
+ ret = sdca_fdl_alloc_state(interrupt);
+ if (ret)
+ return ret;
+
+ ret = sdca_irq_request_locked(dev, info, irq,
+ interrupt->name,
+ fdl_owner_handler,
+ interrupt);
+ if (ret) {
+ dev_err(dev, "failed to request irq %s: %d\n",
+ interrupt->name, ret);
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_irq_populate_early, "SND_SOC_SDCA");
+
+/**
+ * sdca_irq_populate - Request all the individual IRQs for an SDCA Function
+ * @function: Pointer to the SDCA Function.
+ * @component: Pointer to the ASoC component for the Function.
+ * @info: Pointer to the SDCA interrupt info for this device.
+ *
+ * Typically this would be called from the driver for a single SDCA Function.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+int sdca_irq_populate(struct sdca_function_data *function,
+ struct snd_soc_component *component,
+ struct sdca_interrupt_info *info)
+{
+ struct device *dev = component->dev;
+ int i, j;
+
+ guard(mutex)(&info->irq_lock);
+
+ 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 irq = control->interrupt_position;
+ struct sdca_interrupt *interrupt;
+ irq_handler_t handler;
+ int ret;
+
+ interrupt = get_interrupt_data(dev, irq, info);
+ if (IS_ERR(interrupt))
+ return PTR_ERR(interrupt);
+ else if (!interrupt)
+ continue;
+
+ ret = sdca_irq_data_populate(dev, NULL, component,
+ function, entity, control,
+ interrupt);
+ if (ret)
+ return ret;
+
+ handler = base_handler;
+
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS):
+ handler = function_status_handler;
+ break;
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ handler = detected_mode_handler;
+ break;
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
+ ret = sdca_fdl_alloc_state(interrupt);
+ if (ret)
+ return ret;
+
+ handler = fdl_owner_handler;
+ break;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ handler = hid_handler;
+ break;
+ default:
+ break;
+ }
+
+ ret = sdca_irq_request_locked(dev, info, irq, interrupt->name,
+ handler, interrupt);
+ if (ret) {
+ dev_err(dev, "failed to request irq %s: %d\n",
+ interrupt->name, ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA");
+
+/**
+ * sdca_irq_allocate - allocate an SDCA interrupt structure for a device
+ * @sdev: Device pointer against which things should be allocated.
+ * @regmap: regmap to be used for accessing the SDCA IRQ registers.
+ * @irq: The interrupt number.
+ *
+ * Typically this would be called from the top level driver for the whole
+ * SDCA device, as only a single instance is required across all Functions
+ * on the device.
+ *
+ * Return: A pointer to the allocated sdca_interrupt_info struct, or an
+ * error code.
+ */
+struct sdca_interrupt_info *sdca_irq_allocate(struct device *sdev,
+ struct regmap *regmap, int irq)
+{
+ struct sdca_interrupt_info *info;
+ int ret, i;
+
+ info = devm_kzalloc(sdev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->irq_chip = sdca_irq_chip;
+
+ for (i = 0; i < ARRAY_SIZE(info->irqs); i++)
+ info->irqs[i].device_regmap = regmap;
+
+ ret = devm_mutex_init(sdev, &info->irq_lock);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = devm_regmap_add_irq_chip(sdev, regmap, irq, IRQF_ONESHOT, 0,
+ &info->irq_chip, &info->irq_data);
+ if (ret) {
+ dev_err(sdev, "failed to register irq chip: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ dev_dbg(sdev, "registered on irq %d\n", irq);
+
+ return info;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c
new file mode 100644
index 000000000000..2cca9a9c71ea
--- /dev/null
+++ b/sound/soc/sdca/sdca_regmap.c
@@ -0,0 +1,373 @@
+// 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;
+
+ if (!(BIT(SDW_SDCA_CTL_CNUM(reg)) & control->cn_list))
+ return false;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_RW:
+ case SDCA_ACCESS_MODE_RO:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ if (SDW_SDCA_NEXT_CTL(0) & reg)
+ return false;
+ fallthrough;
+ case SDCA_ACCESS_MODE_DUAL:
+ /* 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;
+
+ if (!(BIT(SDW_SDCA_CTL_CNUM(reg)) & control->cn_list))
+ return false;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_RW:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ if (SDW_SDCA_NEXT_CTL(0) & reg)
+ return false;
+ fallthrough;
+ case SDCA_ACCESS_MODE_DUAL:
+ /* 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;
+
+ return control->is_volatile;
+}
+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 -EINVAL;
+
+ 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, l;
+
+ 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;
+
+ l = 0;
+ 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->values[l];
+ k++;
+ l++;
+ }
+ }
+ }
+
+ return k;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
+
+static int populate_control_defaults(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct sdca_control *control)
+{
+ int i, ret;
+ int cn;
+
+ if (control->mode == SDCA_ACCESS_MODE_DC)
+ return 0;
+
+ if (control->layers & SDCA_ACCESS_LAYER_DEVICE)
+ return 0;
+
+ i = 0;
+ for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+ BITS_PER_TYPE(control->cn_list)) {
+ unsigned int reg, val;
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, cn);
+
+ if (control->has_default || control->has_fixed) {
+ ret = regmap_write(regmap, reg, control->values[i]);
+ if (ret) {
+ dev_err(dev, "Failed to write default %#x: %d\n",
+ reg, ret);
+ return ret;
+ }
+
+ i++;
+ } else if (!control->is_volatile) {
+ ret = regmap_read(regmap, reg, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read initial %#x: %d\n",
+ reg, ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * 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. It will also
+ * read any non-volatile registers that don't have defaults/fixed values to
+ * populate those into the cache, this ensures they are available for reads
+ * even when the device is runtime suspended.
+ *
+ * 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];
+
+ ret = populate_control_defaults(dev, regmap, function,
+ entity, control);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_write_defaults, "SND_SOC_SDCA");
+
+int sdca_regmap_write_init(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function)
+{
+ struct sdca_init_write *init = function->init_table;
+ int ret, i;
+
+ for (i = 0; i < function->num_init_table; i++) {
+ ret = regmap_write(regmap, init[i].addr, init[i].val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_write_init, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_ump.c b/sound/soc/sdca/sdca_ump.c
new file mode 100644
index 000000000000..8aba3ff16872
--- /dev/null
+++ b/sound/soc/sdca/sdca_ump.c
@@ -0,0 +1,262 @@
+// 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/dev_printk.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_ump.h>
+#include <sound/soc-component.h>
+#include <linux/soundwire/sdw_registers.h>
+
+/**
+ * sdca_ump_get_owner_host - check a UMP buffer is owned by the host
+ * @dev: Pointer to the struct device used for error messages.
+ * @function_regmap: Pointer to the regmap for the SDCA Function.
+ * @function: Pointer to the Function information.
+ * @entity: Pointer to the SDCA Entity.
+ * @control: Pointer to the SDCA Control for the UMP Owner.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_ump_get_owner_host(struct device *dev,
+ struct regmap *function_regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct sdca_control *control)
+{
+ unsigned int reg, owner;
+ int ret;
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, 0);
+ ret = regmap_read(function_regmap, reg, &owner);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to read UMP owner: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ if (owner != SDCA_UMP_OWNER_HOST) {
+ dev_err(dev, "%s: host is not the UMP owner\n", entity->label);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_ump_get_owner_host, "SND_SOC_SDCA");
+
+/**
+ * sdca_ump_set_owner_device - set a UMP buffer's ownership back to the device
+ * @dev: Pointer to the struct device used for error messages.
+ * @function_regmap: Pointer to the regmap for the SDCA Function.
+ * @function: Pointer to the Function information.
+ * @entity: Pointer to the SDCA Entity.
+ * @control: Pointer to the SDCA Control for the UMP Owner.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_ump_set_owner_device(struct device *dev,
+ struct regmap *function_regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct sdca_control *control)
+{
+ unsigned int reg;
+ int ret;
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, control->sel, 0);
+ ret = regmap_write(function_regmap, reg, SDCA_UMP_OWNER_DEVICE);
+ if (ret < 0)
+ dev_err(dev, "%s: failed to write UMP owner: %d\n",
+ entity->label, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_ump_set_owner_device, "SND_SOC_SDCA");
+
+/**
+ * sdca_ump_read_message - read a UMP message from the device
+ * @dev: Pointer to the struct device used for error messages.
+ * @device_regmap: Pointer to the Device register map.
+ * @function_regmap: Pointer to the regmap for the SDCA Function.
+ * @function: Pointer to the Function information.
+ * @entity: Pointer to the SDCA Entity.
+ * @offset_sel: Control Selector for the UMP Offset Control.
+ * @length_sel: Control Selector for the UMP Length Control.
+ * @msg: Pointer that will be populated with an dynamically buffer
+ * containing the UMP message. Note this needs to be freed by the
+ * caller.
+ *
+ * The caller should first call sdca_ump_get_owner_host() to ensure the host
+ * currently owns the UMP buffer, and then this function can be used to
+ * retrieve a message. It is the callers responsibility to free the
+ * message once it is finished with it. Finally sdca_ump_set_owner_device()
+ * should be called to return the buffer to the device.
+ *
+ * Return: Returns the message length on success, and a negative error
+ * code on failure.
+ */
+int sdca_ump_read_message(struct device *dev,
+ struct regmap *device_regmap,
+ struct regmap *function_regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ unsigned int offset_sel, unsigned int length_sel,
+ void **msg)
+{
+ struct sdca_control_range *range;
+ unsigned int msg_offset, msg_len;
+ unsigned int buf_addr, buf_len;
+ unsigned int reg;
+ int ret;
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, offset_sel, 0);
+ ret = regmap_read(function_regmap, reg, &msg_offset);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to read UMP offset: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ range = sdca_selector_find_range(dev, entity, offset_sel,
+ SDCA_MESSAGEOFFSET_NCOLS, 1);
+ if (!range)
+ return -ENOENT;
+
+ buf_addr = sdca_range(range, SDCA_MESSAGEOFFSET_BUFFER_START_ADDRESS, 0);
+ buf_len = sdca_range(range, SDCA_MESSAGEOFFSET_BUFFER_LENGTH, 0);
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, length_sel, 0);
+ ret = regmap_read(function_regmap, reg, &msg_len);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to read UMP length: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ if (msg_len > buf_len - msg_offset) {
+ dev_err(dev, "%s: message too big for UMP buffer: %d\n",
+ entity->label, msg_len);
+ return -EINVAL;
+ }
+
+ *msg = kmalloc(msg_len, GFP_KERNEL);
+ if (!*msg)
+ return -ENOMEM;
+
+ ret = regmap_raw_read(device_regmap, buf_addr + msg_offset, *msg, msg_len);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to read UMP message: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ return msg_len;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_ump_read_message, "SND_SOC_SDCA");
+
+/**
+ * sdca_ump_write_message - write a UMP message to the device
+ * @dev: Pointer to the struct device used for error messages.
+ * @device_regmap: Pointer to the Device register map.
+ * @function_regmap: Pointer to the regmap for the SDCA Function.
+ * @function: Pointer to the Function information.
+ * @entity: Pointer to the SDCA Entity.
+ * @offset_sel: Control Selector for the UMP Offset Control.
+ * @msg_offset: Offset within the UMP buffer at which the message should
+ * be written.
+ * @length_sel: Control Selector for the UMP Length Control.
+ * @msg: Pointer to the data that should be written to the UMP buffer.
+ * @msg_len: Length of the message data in bytes.
+ *
+ * The caller should first call sdca_ump_get_owner_host() to ensure the host
+ * currently owns the UMP buffer, and then this function can be used to
+ * write a message. Finally sdca_ump_set_owner_device() should be called to
+ * return the buffer to the device, allowing the device to access the
+ * message.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_ump_write_message(struct device *dev,
+ struct regmap *device_regmap,
+ struct regmap *function_regmap,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ unsigned int offset_sel, unsigned int msg_offset,
+ unsigned int length_sel,
+ void *msg, int msg_len)
+{
+ struct sdca_control_range *range;
+ unsigned int buf_addr, buf_len, ump_mode;
+ unsigned int reg;
+ int ret;
+
+ range = sdca_selector_find_range(dev, entity, offset_sel,
+ SDCA_MESSAGEOFFSET_NCOLS, 1);
+ if (!range)
+ return -ENOENT;
+
+ buf_addr = sdca_range(range, SDCA_MESSAGEOFFSET_BUFFER_START_ADDRESS, 0);
+ buf_len = sdca_range(range, SDCA_MESSAGEOFFSET_BUFFER_LENGTH, 0);
+ ump_mode = sdca_range(range, SDCA_MESSAGEOFFSET_UMP_MODE, 0);
+
+ if (msg_len > buf_len - msg_offset) {
+ dev_err(dev, "%s: message too big for UMP buffer: %d\n",
+ entity->label, msg_len);
+ return -EINVAL;
+ }
+
+ if (ump_mode != SDCA_UMP_MODE_DIRECT) {
+ dev_err(dev, "%s: only direct mode currently supported\n",
+ entity->label);
+ return -EINVAL;
+ }
+
+ ret = regmap_raw_write(device_regmap, buf_addr + msg_offset, msg, msg_len);
+ if (ret) {
+ dev_err(dev, "%s: failed to write UMP message: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, offset_sel, 0);
+ ret = regmap_write(function_regmap, reg, msg_offset);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to write UMP offset: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id, length_sel, 0);
+ ret = regmap_write(function_regmap, reg, msg_len);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to write UMP length: %d\n",
+ entity->label, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_ump_write_message, "SND_SOC_SDCA");
+
+void sdca_ump_cancel_timeout(struct delayed_work *work)
+{
+ cancel_delayed_work_sync(work);
+}
+EXPORT_SYMBOL_NS_GPL(sdca_ump_cancel_timeout, "SND_SOC_SDCA");
+
+void sdca_ump_schedule_timeout(struct delayed_work *work, unsigned int timeout_us)
+{
+ if (!timeout_us)
+ return;
+
+ queue_delayed_work(system_wq, work, usecs_to_jiffies(timeout_us));
+}
+EXPORT_SYMBOL_NS_GPL(sdca_ump_schedule_timeout, "SND_SOC_SDCA");
diff --git a/sound/soc/sdw_utils/Kconfig b/sound/soc/sdw_utils/Kconfig
new file mode 100644
index 000000000000..d915083c3889
--- /dev/null
+++ b/sound/soc/sdw_utils/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_SOC_SDW_UTILS
+ tristate
+ help
+ This option enables to use SoundWire common helper functions and
+ SoundWire codec helper functions in machine driver.
diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile
new file mode 100644
index 000000000000..e8bd5ffb1a6a
--- /dev/null
+++ b/sound/soc/sdw_utils/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+snd-soc-sdw-utils-y := soc_sdw_utils.o soc_sdw_dmic.o soc_sdw_rt_dmic.o \
+ soc_sdw_rt700.o soc_sdw_rt711.o \
+ soc_sdw_rt5682.o soc_sdw_rt_sdca_jack_common.o \
+ soc_sdw_rt_amp.o soc_sdw_rt_mf_sdca.o \
+ soc_sdw_bridge_cs35l56.o \
+ soc_sdw_cs42l42.o soc_sdw_cs42l43.o \
+ soc_sdw_cs42l45.o \
+ soc_sdw_cs_amp.o \
+ soc_sdw_maxim.o \
+ soc_sdw_ti_amp.o
+obj-$(CONFIG_SND_SOC_SDW_UTILS) += snd-soc-sdw-utils.o
diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
new file mode 100644
index 000000000000..2a7109d53cbe
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2024 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * soc_sdw_bridge_cs35l56 - codec helper functions for handling CS35L56 Smart AMP
+ */
+
+#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>
+#include <sound/soc-acpi.h>
+#include <sound/soc_sdw_utils.h>
+
+static const struct snd_soc_dapm_widget bridge_widgets[] = {
+ SND_SOC_DAPM_SPK("Bridge Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route bridge_map[] = {
+ {"Bridge Speaker", NULL, "AMPL SPK"},
+ {"Bridge Speaker", NULL, "AMPR SPK"},
+};
+
+static const char * const bridge_cs35l56_name_prefixes[] = {
+ "AMPL",
+ "AMPR",
+};
+
+static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int i, ret;
+ unsigned int rx_mask = 3; // ASP RX1, RX2
+ unsigned int tx_mask = 3; // ASP TX1, TX2
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:cs35l56-bridge",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_dapm_new_controls(dapm, bridge_widgets,
+ ARRAY_SIZE(bridge_widgets));
+ if (ret) {
+ dev_err(card->dev, "widgets addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, bridge_map, ARRAY_SIZE(bridge_map));
+ if (ret) {
+ dev_err(card->dev, "map addition failed: %d\n", ret);
+ return ret;
+ }
+
+ /* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = asoc_sdw_cs35l56_volume_limit(card, codec_dai->component->name_prefix);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 3072000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+ }
+
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, 4, 16);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_pcm_stream asoc_sdw_bridge_params = {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+SND_SOC_DAILINK_DEFS(asoc_sdw_bridge_dai,
+ DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"),
+ COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")),
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("cs42l43-codec")));
+
+static const struct snd_soc_dai_link bridge_dai_template = {
+ .name = "cs42l43-cs35l56",
+ .init = asoc_sdw_bridge_cs35l56_asp_init,
+ .c2c_params = &asoc_sdw_bridge_params,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC,
+ SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai),
+};
+
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+ int *num_dais, int *num_devs)
+{
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
+ (*num_dais)++;
+ (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_count_sidecar, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links,
+ struct snd_soc_codec_conf **codec_conf)
+{
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
+ **dai_links = bridge_dai_template;
+
+ for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) {
+ (*codec_conf)->dlc.name = (*dai_links)->codecs[i].name;
+ (*codec_conf)->name_prefix = bridge_cs35l56_name_prefixes[i];
+ (*codec_conf)++;
+ }
+
+ (*dai_links)++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_add_sidecar, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
+{
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)
+ info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_spk_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/sdw_utils/soc_sdw_cs42l42.c
index c4a16e4c9f69..ff1bdf52d483 100644
--- a/sound/soc/intel/boards/sof_sdw_cs42l42.c
+++ b/sound/soc/sdw_utils/soc_sdw_cs42l42.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2023 Intel Corporation
-
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver
+ * soc_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver
*/
#include <linux/device.h>
@@ -15,12 +16,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_sdw_common.h"
-
-static const struct snd_soc_dapm_widget cs42l42_widgets[] = {
- SND_SOC_DAPM_HP("Headphone", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
-};
+#include <sound/soc_sdw_utils.h>
static const struct snd_soc_dapm_route cs42l42_map[] = {
/* HP jack connectors - unknown if we have jack detection */
@@ -30,11 +26,6 @@ static const struct snd_soc_dapm_route cs42l42_map[] = {
{"cs42l42 HS", NULL, "Headset Mic"},
};
-static const struct snd_kcontrol_new cs42l42_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
-};
-
static struct snd_soc_jack_pin cs42l42_jack_pins[] = {
{
.pin = "Headphone",
@@ -46,36 +37,23 @@ static struct snd_soc_jack_pin cs42l42_jack_pins[] = {
},
};
-static int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd)
+int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component;
struct snd_soc_jack *jack;
int ret;
+ component = dai->component;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s hs:cs42l42",
card->components);
if (!card->components)
return -ENOMEM;
- ret = snd_soc_add_card_controls(card, cs42l42_controls,
- ARRAY_SIZE(cs42l42_controls));
- if (ret) {
- dev_err(card->dev, "cs42l42 control addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, cs42l42_widgets,
- ARRAY_SIZE(cs42l42_widgets));
- if (ret) {
- dev_err(card->dev, "cs42l42 widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, cs42l42_map,
+ ret = snd_soc_dapm_add_routes(dapm, cs42l42_map,
ARRAY_SIZE(cs42l42_map));
if (ret) {
@@ -99,9 +77,9 @@ static int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd)
jack = &ctx->sdw_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
ret = snd_soc_component_set_jack(component, jack, NULL);
@@ -111,21 +89,4 @@ static int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-
-int sof_sdw_cs42l42_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- /*
- * headset should be initialized once.
- * Do it with dai link for playback.
- */
- if (!playback)
- return 0;
-
- dai_links->init = cs42l42_rtd_init;
-
- return 0;
-}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l42_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
new file mode 100644
index 000000000000..4c954501e500
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Based on sof_sdw_rt5682.c
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2023 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * soc_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <sound/jack.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/cs42l43.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc_sdw_utils.h>
+
+#define CS42L43_SPK_VOLUME_0DB 128 /* 0dB Max */
+
+static const struct snd_soc_dapm_route cs42l43_hs_map[] = {
+ { "Headphone", NULL, "cs42l43 AMP3_OUT" },
+ { "Headphone", NULL, "cs42l43 AMP4_OUT" },
+ { "cs42l43 ADC1_IN1_P", NULL, "Headset Mic" },
+ { "cs42l43 ADC1_IN1_N", NULL, "Headset Mic" },
+};
+
+static const struct snd_soc_dapm_route cs42l43_spk_map[] = {
+ { "Speaker", NULL, "cs42l43 AMP1_OUT_P", },
+ { "Speaker", NULL, "cs42l43 AMP1_OUT_N", },
+ { "Speaker", NULL, "cs42l43 AMP2_OUT_P", },
+ { "Speaker", NULL, "cs42l43 AMP2_OUT_N", },
+};
+
+static const struct snd_soc_dapm_route cs42l43_dmic_map[] = {
+ { "cs42l43 PDM1_DIN", NULL, "DMIC" },
+ { "cs42l43 PDM2_DIN", NULL, "DMIC" },
+};
+
+static struct snd_soc_jack_pin soc_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_jack *jack = &ctx->sdw_headset;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs42l43",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_dapm_add_routes(dapm, cs42l43_hs_map,
+ ARRAY_SIZE(cs42l43_hs_map));
+ if (ret) {
+ dev_err(card->dev, "cs42l43 hs map addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Jack",
+ SND_JACK_MECHANICAL | SND_JACK_AVOUT |
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ jack, soc_jack_pins,
+ ARRAY_SIZE(soc_jack_pins));
+ if (ret) {
+ dev_err(card->dev, "Failed to create jack: %d\n", ret);
+ return ret;
+ }
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(card->dev, "Failed to register jack: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_sysclk(component, CS42L43_SYSCLK, CS42L43_SYSCLK_SDW,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret)
+ dev_err(card->dev, "Failed to set sysclk: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (!(ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)) {
+ /* Will be set by the bridge code in this case */
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:cs42l43-spk",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+ }
+
+ ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume",
+ CS42L43_SPK_VOLUME_0DB);
+ if (ret)
+ dev_err(card->dev, "cs42l43 speaker volume limit failed: %d\n", ret);
+ else
+ dev_info(card->dev, "Setting CS42L43 Speaker volume limit to %d\n",
+ CS42L43_SPK_VOLUME_0DB);
+
+ ret = snd_soc_dapm_add_routes(dapm, cs42l43_spk_map,
+ ARRAY_SIZE(cs42l43_spk_map));
+ if (ret)
+ dev_err(card->dev, "cs42l43 speaker map addition failed: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_rtd_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
+{
+ /* Do init on playback link only. */
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+
+ return asoc_sdw_bridge_cs35l56_spk_init(card, dai_links, info, playback);
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:cs42l43-dmic",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_dapm_add_routes(dapm, cs42l43_dmic_map,
+ ARRAY_SIZE(cs42l43_dmic_map));
+ if (ret)
+ dev_err(card->dev, "cs42l43 dmic map addition failed: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_dmic_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l45.c b/sound/soc/sdw_utils/soc_sdw_cs42l45.c
new file mode 100644
index 000000000000..647923d9669f
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_cs42l45.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Based on sof_sdw_rt5682.c
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2023 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * soc_sdw_cs42l45 - Helpers to handle CS42L45 from generic machine driver
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-card.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc_sdw_utils.h>
+
+static struct snd_soc_jack_pin soc_jack_pins[] = {
+ {
+ .pin = "cs42l45 OT 43 Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "cs42l45 OT 45 Headset",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "cs42l45 IT 31 Microphone",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "cs42l45 IT 33 Headset",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+int asoc_sdw_cs42l45_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack *jack = &ctx->sdw_headset;
+ int ret;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs42l45",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Jack", SND_JACK_MECHANICAL |
+ SND_JACK_HEADSET | SND_JACK_LINEOUT, jack,
+ soc_jack_pins, ARRAY_SIZE(soc_jack_pins));
+ if (ret) {
+ dev_err(card->dev, "Failed to create jack: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(card->dev, "Failed to register jack: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l45_hs_rtd_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_cs42l45_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:cs42l45-dmic",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs42l45_dmic_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c
new file mode 100644
index 000000000000..325ab7230481
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2023 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * soc_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dai.h>
+#include <sound/soc_sdw_utils.h>
+
+#define CS_AMP_CHANNELS_PER_AMP 4
+#define CS35L56_SPK_VOLUME_0DB 400 /* 0dB Max */
+
+int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix)
+{
+ char *volume_ctl_name;
+ int ret;
+
+ volume_ctl_name = kasprintf(GFP_KERNEL, "%s Speaker Volume", name_prefix);
+ if (!volume_ctl_name)
+ return -ENOMEM;
+
+ ret = snd_soc_limit_volume(card, volume_ctl_name, CS35L56_SPK_VOLUME_0DB);
+ if (ret)
+ dev_err(card->dev, "%s limit set failed: %d\n", volume_ctl_name, ret);
+
+ kfree(volume_ctl_name);
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs35l56_volume_limit, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ char widget_name[16];
+ struct snd_soc_dapm_route route = { "Speaker", NULL, widget_name };
+ struct snd_soc_dai *codec_dai;
+ int i, ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ if (!strstr(codec_dai->name, "cs35l56"))
+ continue;
+
+ snprintf(widget_name, sizeof(widget_name), "%s SPK",
+ codec_dai->component->name_prefix);
+
+ ret = asoc_sdw_cs35l56_volume_limit(card, codec_dai->component->name_prefix);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, &route, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+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,
+ bool playback)
+{
+ /* Do init on playback link only. */
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs_amp_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/sdw_utils/soc_sdw_dmic.c
index 19df0f7a1d85..6075cd235452 100644
--- a/sound/soc/intel/boards/sof_sdw_dmic.c
+++ b/sound/soc/sdw_utils/soc_sdw_dmic.c
@@ -1,14 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_dmic - Helpers to handle dmic from generic machine driver
+ * soc_sdw_dmic - Helpers to handle dmic from generic machine driver
*/
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
-#include "sof_sdw_common.h"
+#include <sound/soc_sdw_utils.h>
static const struct snd_soc_dapm_widget dmic_widgets[] = {
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
@@ -19,12 +21,13 @@ static const struct snd_soc_dapm_route dmic_map[] = {
{"DMic", NULL, "SoC DMIC"},
};
-int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd)
+int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, dmic_widgets,
ARRAY_SIZE(dmic_widgets));
if (ret) {
dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
@@ -32,7 +35,7 @@ int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
+ ret = snd_soc_dapm_add_routes(dapm, dmic_map,
ARRAY_SIZE(dmic_map));
if (ret)
@@ -40,4 +43,4 @@ int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-
+EXPORT_SYMBOL_NS(asoc_sdw_dmic_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_maxim.c b/sound/soc/sdw_utils/soc_sdw_maxim.c
new file mode 100644
index 000000000000..14090b032cb6
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_maxim.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+//
+// soc_sdw_maxim - Helpers to handle maxim codecs
+// codec devices from generic machine driver
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc_sdw_utils.h>
+
+static int maxim_part_id;
+#define SOC_SDW_PART_ID_MAX98363 0x8363
+#define SOC_SDW_PART_ID_MAX98373 0x8373
+
+static const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ int ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, max_98373_dapm_routes, 2);
+ if (ret)
+ dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_maxim_spk_rtd_init, "SND_SOC_SDW_UTILS");
+
+static int asoc_sdw_mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
+ int ret;
+ int j;
+
+ /* set spk pin by playback only */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return 0;
+
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ for_each_rtd_codec_dais(rtd, j, codec_dai) {
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cpu_dai->component);
+ char pin_name[16];
+
+ snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
+ codec_dai->component->name_prefix);
+
+ if (enable)
+ ret = snd_soc_dapm_enable_pin(dapm, pin_name);
+ else
+ ret = snd_soc_dapm_disable_pin(dapm, pin_name);
+
+ if (!ret)
+ snd_soc_dapm_sync(dapm);
+ }
+
+ return 0;
+}
+
+static int asoc_sdw_mx8373_prepare(struct snd_pcm_substream *substream)
+{
+ int ret;
+
+ /* according to soc_pcm_prepare dai link prepare is called first */
+ ret = asoc_sdw_prepare(substream);
+ if (ret < 0)
+ return ret;
+
+ return asoc_sdw_mx8373_enable_spk_pin(substream, true);
+}
+
+static int asoc_sdw_mx8373_hw_free(struct snd_pcm_substream *substream)
+{
+ int ret;
+
+ /* according to soc_pcm_hw_free dai link free is called first */
+ ret = asoc_sdw_hw_free(substream);
+ if (ret < 0)
+ return ret;
+
+ return asoc_sdw_mx8373_enable_spk_pin(substream, false);
+}
+
+static const struct snd_soc_ops max_98373_sdw_ops = {
+ .startup = asoc_sdw_startup,
+ .prepare = asoc_sdw_mx8373_prepare,
+ .trigger = asoc_sdw_trigger,
+ .hw_params = asoc_sdw_hw_params,
+ .hw_free = asoc_sdw_mx8373_hw_free,
+ .shutdown = asoc_sdw_shutdown,
+};
+
+static int asoc_sdw_mx8373_sdw_late_probe(struct snd_soc_card *card)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+
+ /* Disable Left and Right Spk pin after boot */
+ snd_soc_dapm_disable_pin(dapm, "Left Spk");
+ snd_soc_dapm_disable_pin(dapm, "Right Spk");
+ return snd_soc_dapm_sync(dapm);
+}
+
+int asoc_sdw_maxim_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
+{
+ info->amp_num++;
+
+ maxim_part_id = info->part_id;
+ switch (maxim_part_id) {
+ case SOC_SDW_PART_ID_MAX98363:
+ /* Default ops are set in function init_dai_link.
+ * called as part of function create_sdw_dailink
+ */
+ break;
+ case SOC_SDW_PART_ID_MAX98373:
+ info->codec_card_late_probe = asoc_sdw_mx8373_sdw_late_probe;
+ dai_links->ops = &max_98373_sdw_ops;
+ break;
+ default:
+ dev_err(card->dev, "Invalid maxim_part_id %#x\n", maxim_part_id);
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_maxim_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/sdw_utils/soc_sdw_rt5682.c
index 3a9be8211586..641362835b4e 100644
--- a/sound/soc/intel/boards/sof_sdw_rt5682.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt5682.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver
+ * soc_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver
*/
#include <linux/device.h>
@@ -15,12 +17,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_sdw_common.h"
-
-static const struct snd_soc_dapm_widget rt5682_widgets[] = {
- SND_SOC_DAPM_HP("Headphone", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
-};
+#include <sound/soc_sdw_utils.h>
static const struct snd_soc_dapm_route rt5682_map[] = {
/*Headphones*/
@@ -29,11 +26,6 @@ static const struct snd_soc_dapm_route rt5682_map[] = {
{ "rt5682 IN1P", NULL, "Headset Mic" },
};
-static const struct snd_kcontrol_new rt5682_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
-};
-
static struct snd_soc_jack_pin rt5682_jack_pins[] = {
{
.pin = "Headphone",
@@ -45,36 +37,23 @@ static struct snd_soc_jack_pin rt5682_jack_pins[] = {
},
};
-static int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd)
+int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component;
struct snd_soc_jack *jack;
int ret;
+ component = dai->component;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s hs:rt5682",
card->components);
if (!card->components)
return -ENOMEM;
- ret = snd_soc_add_card_controls(card, rt5682_controls,
- ARRAY_SIZE(rt5682_controls));
- if (ret) {
- dev_err(card->dev, "rt5682 control addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets,
- ARRAY_SIZE(rt5682_widgets));
- if (ret) {
- dev_err(card->dev, "rt5682 widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt5682_map,
+ ret = snd_soc_dapm_add_routes(dapm, rt5682_map,
ARRAY_SIZE(rt5682_map));
if (ret) {
@@ -110,21 +89,4 @@ static int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-
-int sof_sdw_rt5682_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- /*
- * headset should be initialized once.
- * Do it with dai link for playback.
- */
- if (!playback)
- return 0;
-
- dai_links->init = rt5682_rtd_init;
-
- return 0;
-}
+EXPORT_SYMBOL_NS(asoc_sdw_rt5682_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/sdw_utils/soc_sdw_rt700.c
index c93b1f5b9440..ffedfde955d0 100644
--- a/sound/soc/intel/boards/sof_sdw_rt700.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt700.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_rt700 - Helpers to handle RT700 from generic machine driver
+ * soc_sdw_rt700 - Helpers to handle RT700 from generic machine driver
*/
#include <linux/device.h>
@@ -13,13 +15,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_sdw_common.h"
-
-static const struct snd_soc_dapm_widget rt700_widgets[] = {
- SND_SOC_DAPM_HP("Headphones", NULL),
- SND_SOC_DAPM_MIC("AMIC", NULL),
- SND_SOC_DAPM_SPK("Speaker", NULL),
-};
+#include <sound/soc_sdw_utils.h>
static const struct snd_soc_dapm_route rt700_map[] = {
/* Headphones */
@@ -28,12 +24,6 @@ static const struct snd_soc_dapm_route rt700_map[] = {
{ "rt700 MIC2", NULL, "AMIC" },
};
-static const struct snd_kcontrol_new rt700_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphones"),
- SOC_DAPM_PIN_SWITCH("AMIC"),
- SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
static struct snd_soc_jack_pin rt700_jack_pins[] = {
{
.pin = "Headphones",
@@ -45,36 +35,23 @@ static struct snd_soc_jack_pin rt700_jack_pins[] = {
},
};
-static int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd)
+int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component;
struct snd_soc_jack *jack;
int ret;
+ component = dai->component;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s hs:rt700",
card->components);
if (!card->components)
return -ENOMEM;
- ret = snd_soc_add_card_controls(card, rt700_controls,
- ARRAY_SIZE(rt700_controls));
- if (ret) {
- dev_err(card->dev, "rt700 controls addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt700_widgets,
- ARRAY_SIZE(rt700_widgets));
- if (ret) {
- dev_err(card->dev, "rt700 widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt700_map,
+ ret = snd_soc_dapm_add_routes(dapm, rt700_map,
ARRAY_SIZE(rt700_map));
if (ret) {
@@ -109,21 +86,4 @@ static int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-
-int sof_sdw_rt700_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
-{
- /*
- * headset should be initialized once.
- * Do it with dai link for playback.
- */
- if (!playback)
- return 0;
-
- dai_links->init = rt700_rtd_init;
-
- return 0;
-}
+EXPORT_SYMBOL_NS(asoc_sdw_rt700_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/sdw_utils/soc_sdw_rt711.c
index 2b05e2a707de..3a3a66b4b737 100644
--- a/sound/soc/intel/boards/sof_sdw_rt711.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt711.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_rt711 - Helpers to handle RT711 from generic machine driver
+ * soc_sdw_rt711 - Helpers to handle RT711 from generic machine driver
*/
#include <linux/device.h>
@@ -15,21 +17,21 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_sdw_common.h"
+#include <sound/soc_sdw_utils.h>
/*
* Note this MUST be called before snd_soc_register_card(), so that the props
* are in place before the codec component driver's probe function parses them.
*/
-static int rt711_add_codec_device_props(struct device *sdw_dev)
+static int rt711_add_codec_device_props(struct device *sdw_dev, unsigned long quirk)
{
- struct property_entry props[MAX_NO_PROPS] = {};
+ struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {};
struct fwnode_handle *fwnode;
int ret;
- if (!SOF_JACK_JDSRC(sof_sdw_quirk))
+ if (!SOC_SDW_JACK_JDSRC(quirk))
return 0;
- props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk));
+ props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk));
fwnode = fwnode_create_software_node(props, NULL);
if (IS_ERR(fwnode))
@@ -42,22 +44,12 @@ static int rt711_add_codec_device_props(struct device *sdw_dev)
return ret;
}
-static const struct snd_soc_dapm_widget rt711_widgets[] = {
- SND_SOC_DAPM_HP("Headphone", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
-};
-
static const struct snd_soc_dapm_route rt711_map[] = {
/* Headphones */
{ "Headphone", NULL, "rt711 HP" },
{ "rt711 MIC2", NULL, "Headset Mic" },
};
-static const struct snd_kcontrol_new rt711_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
-};
-
static struct snd_soc_jack_pin rt711_jack_pins[] = {
{
.pin = "Headphone",
@@ -69,36 +61,23 @@ static struct snd_soc_jack_pin rt711_jack_pins[] = {
},
};
-static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd)
+int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component;
struct snd_soc_jack *jack;
int ret;
+ component = dai->component;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
"%s hs:rt711",
card->components);
if (!card->components)
return -ENOMEM;
- ret = snd_soc_add_card_controls(card, rt711_controls,
- ARRAY_SIZE(rt711_controls));
- if (ret) {
- dev_err(card->dev, "rt711 controls addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt711_widgets,
- ARRAY_SIZE(rt711_widgets));
- if (ret) {
- dev_err(card->dev, "rt711 widgets addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt711_map,
+ ret = snd_soc_dapm_add_routes(dapm, rt711_map,
ARRAY_SIZE(rt711_map));
if (ret) {
@@ -134,10 +113,11 @@ static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt711_rtd_init, "SND_SOC_SDW_UTILS");
-int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
if (!ctx->headset_codec_dev)
return 0;
@@ -147,14 +127,14 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l
return 0;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt711_exit, "SND_SOC_SDW_UTILS");
-int sof_sdw_rt711_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
+int asoc_sdw_rt711_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct device *sdw_dev;
int ret;
@@ -169,14 +149,13 @@ int sof_sdw_rt711_init(struct snd_soc_card *card,
if (!sdw_dev)
return -EPROBE_DEFER;
- ret = rt711_add_codec_device_props(sdw_dev);
+ ret = rt711_add_codec_device_props(sdw_dev, ctx->mc_quirk);
if (ret < 0) {
put_device(sdw_dev);
return ret;
}
ctx->headset_codec_dev = sdw_dev;
- dai_links->init = rt711_rtd_init;
-
return 0;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt711_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c
index 26bf9e0dd3d2..4e9b08cb653d 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_amp.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2022 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
+ * soc_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
*/
#include <linux/device.h>
@@ -14,9 +16,9 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/dmi.h>
-#include "sof_sdw_common.h"
-#include "sof_sdw_amp_coeff_tables.h"
-#include "../../codecs/rt1308.h"
+#include <sound/soc_sdw_utils.h>
+#include "soc_sdw_rt_amp_coeff_tables.h"
+#include "../codecs/rt1308.h"
#define CODEC_NAME_SIZE 7
@@ -131,14 +133,6 @@ static int rt_amp_add_device_props(struct device *sdw_dev)
return ret;
}
-static const struct snd_kcontrol_new rt_amp_controls[] = {
- SOC_DAPM_PIN_SWITCH("Speaker"),
-};
-
-static const struct snd_soc_dapm_widget rt_amp_widgets[] = {
- SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
/*
* dapm routes for rt1308/rt1316/rt1318 will be registered dynamically
* according to the number of rt1308/rt1316/rt1318 used. The first two
@@ -166,94 +160,59 @@ static const struct snd_soc_dapm_route rt1318_map[] = {
{ "Speaker", NULL, "rt1318-2 SPOR" },
};
-static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_pcm_runtime *rtd,
+static const struct snd_soc_dapm_route rt1320_map[] = {
+ { "Speaker", NULL, "rt1320-1 SPOL" },
+ { "Speaker", NULL, "rt1320-1 SPOR" },
+ { "Speaker", NULL, "rt1320-2 SPOL" },
+ { "Speaker", NULL, "rt1320-2 SPOR" },
+};
+
+static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_dai *dai,
char *codec_name)
{
- const char *dai_name;
-
- dai_name = rtd->dai_link->codecs->dai_name;
-
/* get the codec name */
- snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name);
+ snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai->name);
/* choose the right codec's map */
if (strcmp(codec_name, "rt1308") == 0)
return rt1308_map;
else if (strcmp(codec_name, "rt1316") == 0)
return rt1316_map;
- else
+ else if (strcmp(codec_name, "rt1318") == 0)
return rt1318_map;
+ else
+ return rt1320_map;
}
-static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
+int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
const struct snd_soc_dapm_route *rt_amp_map;
char codec_name[CODEC_NAME_SIZE];
- int ret;
-
- rt_amp_map = get_codec_name_and_route(rtd, codec_name);
-
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s spk:%s",
- card->components, codec_name);
- if (!card->components)
- return -ENOMEM;
+ struct snd_soc_dai *codec_dai;
+ int ret = -EINVAL;
+ int i;
- ret = snd_soc_add_card_controls(card, rt_amp_controls,
- ARRAY_SIZE(rt_amp_controls));
- if (ret) {
- dev_err(card->dev, "%s controls addition failed: %d\n", codec_name, ret);
- return ret;
- }
+ rt_amp_map = get_codec_name_and_route(dai, codec_name);
- ret = snd_soc_dapm_new_controls(&card->dapm, rt_amp_widgets,
- ARRAY_SIZE(rt_amp_widgets));
- if (ret) {
- dev_err(card->dev, "%s widgets addition failed: %d\n", codec_name, ret);
- return ret;
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ if (strstr(codec_dai->component->name_prefix, "-1"))
+ ret = snd_soc_dapm_add_routes(dapm, rt_amp_map, 2);
+ else if (strstr(codec_dai->component->name_prefix, "-2"))
+ ret = snd_soc_dapm_add_routes(dapm, rt_amp_map + 2, 2);
}
- ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
-
return ret;
}
-
-static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_card *card = rtd->card;
- const struct snd_soc_dapm_route *rt_amp_map;
- char codec_name[CODEC_NAME_SIZE];
- int ret;
-
- rt_amp_map = get_codec_name_and_route(rtd, codec_name);
-
- ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map + 2, 2);
- if (ret)
- dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
-
- return ret;
-}
-
-static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
-{
- int ret;
-
- ret = first_spk_init(rtd);
- if (ret)
- return ret;
-
- return second_spk_init(rtd);
-}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_spk_rtd_init, "SND_SOC_SDW_UTILS");
static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int clk_id, clk_freq, pll_out;
int err;
@@ -281,13 +240,14 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream,
}
/* machine stream operations */
-struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
+const struct snd_soc_ops soc_sdw_rt1308_i2s_ops = {
.hw_params = rt1308_i2s_hw_params,
};
+EXPORT_SYMBOL_NS(soc_sdw_rt1308_i2s_ops, "SND_SOC_SDW_UTILS");
-int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
if (ctx->amp_dev1) {
device_remove_software_node(ctx->amp_dev1);
@@ -301,14 +261,14 @@ int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_
return 0;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_exit, "SND_SOC_SDW_UTILS");
-int sof_sdw_rt_amp_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
+int asoc_sdw_rt_amp_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct device *sdw_dev1, *sdw_dev2;
int ret;
@@ -317,8 +277,6 @@ int sof_sdw_rt_amp_init(struct snd_soc_card *card,
return 0;
info->amp_num++;
- if (info->amp_num == 1)
- dai_links->init = first_spk_init;
if (info->amp_num == 2) {
sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
@@ -342,18 +300,8 @@ int sof_sdw_rt_amp_init(struct snd_soc_card *card,
return ret;
}
ctx->amp_dev2 = sdw_dev2;
-
- /*
- * if two amps are in one dai link, the init function
- * in this dai link will be first set for the first speaker,
- * and it should be reset to initialize all speakers when
- * the second speaker is found.
- */
- if (dai_links->init)
- dai_links->init = all_spk_init;
- else
- dai_links->init = second_spk_init;
}
return 0;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h
index 4a3e6fdbd623..4803d134d071 100644
--- a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h
+++ b/sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h
@@ -2,11 +2,11 @@
*/
/*
- * sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters
+ * soc_sdw_rt_amp_coeff_tables.h - related coefficients for RTK amplifier parameters
*/
-#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H
-#define SND_SOC_SOF_SDW_AMP_COEFF_H
+#ifndef SND_SOC_SDW_RT_SDW_AMP_COEFF_H
+#define SND_SOC_SDW_RT_SDW_AMP_COEFF_H
#define RT1308_MAX_BQ_REG 480
#define RT1316_MAX_BQ_REG 580
diff --git a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
new file mode 100644
index 000000000000..97be110a59b6
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2024 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
+
+/*
+ * soc_sdw_rt_dmic - Helpers to handle Realtek SDW DMIC from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc_sdw_utils.h>
+
+int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_component *component;
+ char *mic_name;
+
+ component = dai->component;
+
+ /*
+ * rt715-sdca (aka rt714) is a special case that uses different name in card->components
+ * and component->name_prefix.
+ */
+ if (!strcmp(component->name_prefix, "rt714"))
+ mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "rt715-sdca");
+ else
+ mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s", component->name_prefix);
+ if (!mic_name)
+ return -ENOMEM;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s mic:%s", card->components,
+ mic_name);
+ if (!card->components)
+ return -ENOMEM;
+
+ dev_dbg(card->dev, "card->components: %s\n", card->components);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_dmic_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c
new file mode 100644
index 000000000000..5bf3627a97a0
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2024 Intel Corporation.
+
+/*
+ * soc_sdw_rt_mf_sdca
+ * - Helpers to handle RT Multifunction Codec from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc_sdw_utils.h>
+
+#define CODEC_NAME_SIZE 6
+
+/* dapm routes for RT-SPK will be registered dynamically */
+static const struct snd_soc_dapm_route rt712_spk_map[] = {
+ { "Speaker", NULL, "rt712 SPOL" },
+ { "Speaker", NULL, "rt712 SPOR" },
+};
+
+static const struct snd_soc_dapm_route rt721_spk_map[] = {
+ { "Speaker", NULL, "rt721 SPK" },
+};
+
+static const struct snd_soc_dapm_route rt722_spk_map[] = {
+ { "Speaker", NULL, "rt722 SPK" },
+};
+
+/* Structure to map codec names to respective route arrays and sizes */
+struct codec_route_map {
+ const char *codec_name;
+ const struct snd_soc_dapm_route *route_map;
+ size_t route_size;
+};
+
+/* Codec route maps array */
+static const struct codec_route_map codec_routes[] = {
+ { "rt712", rt712_spk_map, ARRAY_SIZE(rt712_spk_map) },
+ { "rt721", rt721_spk_map, ARRAY_SIZE(rt721_spk_map) },
+ { "rt722", rt722_spk_map, ARRAY_SIZE(rt722_spk_map) },
+};
+
+static const struct codec_route_map *get_codec_route_map(const char *codec_name)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(codec_routes); i++) {
+ if (strcmp(codec_routes[i].codec_name, codec_name) == 0)
+ return &codec_routes[i];
+ }
+ return NULL;
+}
+
+int asoc_sdw_rt_mf_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ char codec_name[CODEC_NAME_SIZE];
+ int ret;
+
+ /* acquire codec name */
+ snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai->name);
+
+ /* acquire corresponding route map and size */
+ const struct codec_route_map *route_map = get_codec_route_map(codec_name);
+
+ if (!route_map) {
+ dev_err(rtd->dev, "failed to get codec name and route map\n");
+ return -EINVAL;
+ }
+
+ /* Add routes */
+ ret = snd_soc_dapm_add_routes(dapm, route_map->route_map, route_map->route_size);
+ if (ret)
+ dev_err(rtd->dev, "failed to add rt sdca spk map: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_mf_sdca_spk_rtd_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c
index 623e3bebb888..2547b5b3fdd7 100644
--- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c
+++ b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
// Copyright (c) 2020 Intel Corporation
+// Copyright (c) 2024 Advanced Micro Devices, Inc.
/*
- * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver
+ * soc_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver
*/
#include <linux/device.h>
@@ -15,22 +17,22 @@
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include "sof_sdw_common.h"
+#include <sound/soc_sdw_utils.h>
/*
* Note this MUST be called before snd_soc_register_card(), so that the props
* are in place before the codec component driver's probe function parses them.
*/
-static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev)
+static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev, unsigned long quirk)
{
- struct property_entry props[MAX_NO_PROPS] = {};
+ struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {};
struct fwnode_handle *fwnode;
int ret;
- if (!SOF_JACK_JDSRC(sof_sdw_quirk))
+ if (!SOC_SDW_JACK_JDSRC(quirk))
return 0;
- props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk));
+ props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk));
fwnode = fwnode_create_software_node(props, NULL);
if (IS_ERR(fwnode))
@@ -43,11 +45,6 @@ static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev)
return ret;
}
-static const struct snd_soc_dapm_widget rt_sdca_jack_widgets[] = {
- SND_SOC_DAPM_HP("Headphone", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
-};
-
static const struct snd_soc_dapm_route rt711_sdca_map[] = {
{ "Headphone", NULL, "rt711 HP" },
{ "rt711 MIC2", NULL, "Headset Mic" },
@@ -58,9 +55,19 @@ static const struct snd_soc_dapm_route rt712_sdca_map[] = {
{ "rt712 MIC2", NULL, "Headset Mic" },
};
-static const struct snd_kcontrol_new rt_sdca_jack_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
+static const struct snd_soc_dapm_route rt713_sdca_map[] = {
+ { "Headphone", NULL, "rt713 HP" },
+ { "rt713 MIC2", NULL, "Headset Mic" },
+};
+
+static const struct snd_soc_dapm_route rt721_sdca_map[] = {
+ { "Headphone", NULL, "rt721 HP" },
+ { "rt721 MIC2", NULL, "Headset Mic" },
+};
+
+static const struct snd_soc_dapm_route rt722_sdca_map[] = {
+ { "Headphone", NULL, "rt722 HP" },
+ { "rt722 MIC2", NULL, "Headset Mic" },
};
static struct snd_soc_jack_pin rt_sdca_jack_pins[] = {
@@ -74,41 +81,58 @@ static struct snd_soc_jack_pin rt_sdca_jack_pins[] = {
},
};
-static int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd)
+/*
+ * The sdca suffix is required for rt711 since there are two generations of the same chip.
+ * RT713 is an SDCA device but the sdca suffix is required for backwards-compatibility with
+ * previous UCM definitions.
+ */
+static const char * const need_sdca_suffix[] = {
+ "rt711", "rt713"
+};
+
+int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct snd_soc_card *card = rtd->card;
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component;
struct snd_soc_jack *jack;
int ret;
+ int i;
+ component = dai->component;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s hs:%s-sdca",
+ "%s hs:%s",
card->components, component->name_prefix);
if (!card->components)
return -ENOMEM;
- ret = snd_soc_add_card_controls(card, rt_sdca_jack_controls,
- ARRAY_SIZE(rt_sdca_jack_controls));
- if (ret) {
- dev_err(card->dev, "rt sdca jack controls addition failed: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dapm_new_controls(&card->dapm, rt_sdca_jack_widgets,
- ARRAY_SIZE(rt_sdca_jack_widgets));
- if (ret) {
- dev_err(card->dev, "rt sdca jack widgets addition failed: %d\n", ret);
- return ret;
+ for (i = 0; i < ARRAY_SIZE(need_sdca_suffix); i++) {
+ if (strstr(component->name_prefix, need_sdca_suffix[i])) {
+ /* Add -sdca suffix for existing UCMs */
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s-sdca", card->components);
+ if (!card->components)
+ return -ENOMEM;
+ break;
+ }
}
if (strstr(component->name_prefix, "rt711")) {
- ret = snd_soc_dapm_add_routes(&card->dapm, rt711_sdca_map,
+ ret = snd_soc_dapm_add_routes(dapm, rt711_sdca_map,
ARRAY_SIZE(rt711_sdca_map));
} else if (strstr(component->name_prefix, "rt712")) {
- ret = snd_soc_dapm_add_routes(&card->dapm, rt712_sdca_map,
+ ret = snd_soc_dapm_add_routes(dapm, rt712_sdca_map,
ARRAY_SIZE(rt712_sdca_map));
+ } else if (strstr(component->name_prefix, "rt713")) {
+ ret = snd_soc_dapm_add_routes(dapm, rt713_sdca_map,
+ ARRAY_SIZE(rt713_sdca_map));
+ } else if (strstr(component->name_prefix, "rt721")) {
+ ret = snd_soc_dapm_add_routes(dapm, rt721_sdca_map,
+ ARRAY_SIZE(rt721_sdca_map));
+ } else if (strstr(component->name_prefix, "rt722")) {
+ ret = snd_soc_dapm_add_routes(dapm, rt722_sdca_map,
+ ARRAY_SIZE(rt722_sdca_map));
} else {
dev_err(card->dev, "%s is not supported\n", component->name_prefix);
return -EINVAL;
@@ -147,52 +171,53 @@ static int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init, "SND_SOC_SDW_UTILS");
-int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
if (!ctx->headset_codec_dev)
return 0;
- if (!SOF_JACK_JDSRC(sof_sdw_quirk))
+ if (!SOC_SDW_JACK_JDSRC(ctx->mc_quirk))
return 0;
device_remove_software_node(ctx->headset_codec_dev);
put_device(ctx->headset_codec_dev);
+ ctx->headset_codec_dev = NULL;
return 0;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit, "SND_SOC_SDW_UTILS");
-int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link *dai_links,
- struct sof_sdw_codec_info *info,
- bool playback)
+int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
{
- struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct device *sdw_dev;
int ret;
/*
- * headset should be initialized once.
- * Do it with dai link for playback.
+ * Jack detection should be only initialized once for headsets since
+ * the playback/capture is sharing the same jack
*/
- if (!playback)
+ if (ctx->headset_codec_dev)
return 0;
sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
if (!sdw_dev)
return -EPROBE_DEFER;
- ret = rt_sdca_jack_add_codec_device_props(sdw_dev);
+ ret = rt_sdca_jack_add_codec_device_props(sdw_dev, ctx->mc_quirk);
if (ret < 0) {
put_device(sdw_dev);
return ret;
}
ctx->headset_codec_dev = sdw_dev;
- dai_links->init = rt_sdca_jack_rtd_init;
-
return 0;
}
+EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_ti_amp.c b/sound/soc/sdw_utils/soc_sdw_ti_amp.c
new file mode 100644
index 000000000000..cbd60faecd09
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_ti_amp.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2025 Texas Instruments Inc.
+
+/*
+ * soc_sdw_ti_amp - Helpers to handle TI's soundwire based codecs
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dai.h>
+#include <sound/soc_sdw_utils.h>
+
+#define TIAMP_SPK_VOLUME_0DB 200
+
+int asoc_sdw_ti_amp_initial_settings(struct snd_soc_card *card,
+ const char *name_prefix)
+{
+ char *volume_ctl_name;
+ int ret;
+
+ volume_ctl_name = kasprintf(GFP_KERNEL, "%s Speaker Volume",
+ name_prefix);
+ if (!volume_ctl_name)
+ return -ENOMEM;
+
+ ret = snd_soc_limit_volume(card, volume_ctl_name,
+ TIAMP_SPK_VOLUME_0DB);
+ if (ret)
+ dev_err(card->dev,
+ "%s update failed %d\n",
+ volume_ctl_name, ret);
+
+ kfree(volume_ctl_name);
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_ti_amp_initial_settings, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_ti_spk_rtd_init(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ char widget_name[16];
+ char speaker[16];
+ struct snd_soc_dapm_route route = {speaker, NULL, widget_name};
+ struct snd_soc_dai *codec_dai;
+ const char *prefix;
+ int i, ret = 0;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ if (!strstr(codec_dai->name, "tas2783"))
+ continue;
+
+ prefix = codec_dai->component->name_prefix;
+ if (!strncmp(prefix, "tas2783-1", strlen("tas2783-1"))) {
+ strscpy(speaker, "Left Spk", sizeof(speaker));
+ } else if (!strncmp(prefix, "tas2783-2", strlen("tas2783-2"))) {
+ strscpy(speaker, "Right Spk", sizeof(speaker));
+ } else {
+ ret = -EINVAL;
+ dev_err(card->dev, "unhandled prefix %s", prefix);
+ break;
+ }
+
+ snprintf(widget_name, sizeof(widget_name), "%s SPK", prefix);
+ ret = asoc_sdw_ti_amp_initial_settings(card, prefix);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, &route, 1);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_ti_spk_rtd_init, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_ti_amp_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct asoc_sdw_codec_info *info,
+ bool playback)
+{
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_ti_amp_init, "SND_SOC_SDW_UTILS");
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
new file mode 100644
index 000000000000..6c656b2f7f3a
--- /dev/null
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -0,0 +1,1612 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// This file incorporates work covered by the following copyright notice:
+// Copyright (c) 2020 Intel Corporation
+// Copyright(c) 2024 Advanced Micro Devices, Inc.
+/*
+ * soc-sdw-utils.c - common SoundWire machine driver helper functions
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/sdca_function.h>
+#include <sound/soc_sdw_utils.h>
+
+static const struct snd_soc_dapm_widget generic_dmic_widgets[] = {
+ SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_widget generic_jack_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_kcontrol_new generic_jack_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget generic_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_kcontrol_new generic_spk_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget lr_spk_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_kcontrol_new lr_spk_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget rt700_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_kcontrol_new rt700_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphones"),
+ SOC_DAPM_PIN_SWITCH("AMIC"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+struct asoc_sdw_codec_info codec_info_list[] = {
+ {
+ .part_id = 0x0000, /* TAS2783A */
+ .name_prefix = "tas2783",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "tas2783-codec",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .init = asoc_sdw_ti_amp_init,
+ .rtd_init = asoc_sdw_ti_spk_rtd_init,
+ .controls = lr_spk_controls,
+ .num_controls = ARRAY_SIZE(lr_spk_controls),
+ .widgets = lr_spk_widgets,
+ .num_widgets = ARRAY_SIZE(lr_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x700,
+ .name_prefix = "rt700",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt700-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .rtd_init = asoc_sdw_rt700_rtd_init,
+ .controls = rt700_controls,
+ .num_controls = ARRAY_SIZE(rt700_controls),
+ .widgets = rt700_widgets,
+ .num_widgets = ARRAY_SIZE(rt700_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x711,
+ .name_prefix = "rt711",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt711-sdca-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .init = asoc_sdw_rt_sdca_jack_init,
+ .exit = asoc_sdw_rt_sdca_jack_exit,
+ .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x711,
+ .name_prefix = "rt711",
+ .version_id = 2,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt711-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .init = asoc_sdw_rt711_init,
+ .exit = asoc_sdw_rt711_exit,
+ .rtd_init = asoc_sdw_rt711_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x712,
+ .name_prefix = "rt712",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt712-sdca-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .init = asoc_sdw_rt_sdca_jack_init,
+ .exit = asoc_sdw_rt_sdca_jack_exit,
+ .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ {
+ .direction = {true, false},
+ .dai_name = "rt712-sdca-aif2",
+ .component_name = "rt712",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "rt712-sdca-aif3",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 3,
+ },
+ {
+ .part_id = 0x1712,
+ .name_prefix = "rt712-dmic",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {false, true},
+ .dai_name = "rt712-sdca-dmic-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x713,
+ .name_prefix = "rt713",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt712-sdca-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .init = asoc_sdw_rt_sdca_jack_init,
+ .exit = asoc_sdw_rt_sdca_jack_exit,
+ .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "rt712-sdca-aif3",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 2,
+ },
+ {
+ .part_id = 0x1713,
+ .name_prefix = "rt713-dmic",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {false, true},
+ .dai_name = "rt712-sdca-dmic-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x1308,
+ .name_prefix = "rt1308",
+ .acpi_id = "10EC1308",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "rt1308-aif",
+ .component_name = "rt1308",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ .ops = &soc_sdw_rt1308_i2s_ops,
+ },
+ {
+ .part_id = 0x1316,
+ .name_prefix = "rt1316",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt1316-aif",
+ .component_name = "rt1316",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x1318,
+ .name_prefix = "rt1318",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt1318-aif",
+ .component_name = "rt1318",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x1320,
+ .name_prefix = "rt1320",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "rt1320-aif1",
+ .component_name = "rt1320",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x1321,
+ .name_prefix = "rt1320",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "rt1320-aif1",
+ .component_name = "rt1320",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x714,
+ .name_prefix = "rt714",
+ .version_id = 3,
+ .ignore_internal_dmic = true,
+ .dais = {
+ {
+ .direction = {false, true},
+ .dai_name = "rt715-sdca-aif2",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x715,
+ .name_prefix = "rt715",
+ .version_id = 3,
+ .ignore_internal_dmic = true,
+ .dais = {
+ {
+ .direction = {false, true},
+ .dai_name = "rt715-sdca-aif2",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x714,
+ .name_prefix = "rt714",
+ .version_id = 2,
+ .ignore_internal_dmic = true,
+ .dais = {
+ {
+ .direction = {false, true},
+ .dai_name = "rt715-aif2",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x715,
+ .name_prefix = "rt715",
+ .version_id = 2,
+ .ignore_internal_dmic = true,
+ .dais = {
+ {
+ .direction = {false, true},
+ .dai_name = "rt715-aif2",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x721,
+ .name_prefix = "rt721",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt721-sdca-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .init = asoc_sdw_rt_sdca_jack_init,
+ .exit = asoc_sdw_rt_sdca_jack_exit,
+ .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ {
+ .direction = {true, false},
+ .dai_name = "rt721-sdca-aif2",
+ .component_name = "rt721",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ /* No feedback capability is provided by rt721-sdca codec driver*/
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "rt721-sdca-aif3",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 3,
+ },
+ {
+ .part_id = 0x722,
+ .name_prefix = "rt722",
+ .version_id = 3,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt722-sdca-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .init = asoc_sdw_rt_sdca_jack_init,
+ .exit = asoc_sdw_rt_sdca_jack_exit,
+ .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ {
+ .direction = {true, false},
+ .dai_name = "rt722-sdca-aif2",
+ .component_name = "rt722",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ /* No feedback capability is provided by rt722-sdca codec driver*/
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_rt_amp_init,
+ .exit = asoc_sdw_rt_amp_exit,
+ .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ .quirk = SOC_SDW_CODEC_SPKR,
+ .quirk_exclude = true,
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "rt722-sdca-aif3",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
+ },
+ .dai_num = 3,
+ },
+ {
+ .part_id = 0x8373,
+ .name_prefix = "Left",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "max98373-aif1",
+ .component_name = "mx8373",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .init = asoc_sdw_maxim_init,
+ .rtd_init = asoc_sdw_maxim_spk_rtd_init,
+ .controls = lr_spk_controls,
+ .num_controls = ARRAY_SIZE(lr_spk_controls),
+ .widgets = lr_spk_widgets,
+ .num_widgets = ARRAY_SIZE(lr_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x8363,
+ .name_prefix = "Left",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "max98363-aif1",
+ .component_name = "mx8363",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_maxim_init,
+ .rtd_init = asoc_sdw_maxim_spk_rtd_init,
+ .controls = lr_spk_controls,
+ .num_controls = ARRAY_SIZE(lr_spk_controls),
+ .widgets = lr_spk_widgets,
+ .num_widgets = ARRAY_SIZE(lr_spk_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x5682,
+ .name_prefix = "rt5682",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "rt5682-sdw",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .rtd_init = asoc_sdw_rt5682_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x3556,
+ .name_prefix = "AMP",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "cs35l56-sdw1",
+ .component_name = "cs35l56",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs_amp_init,
+ .rtd_init = asoc_sdw_cs_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "cs35l56-sdw1c",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
+ },
+ },
+ .dai_num = 2,
+ },
+ {
+ .part_id = 0x3557,
+ .name_prefix = "AMP",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "cs35l56-sdw1",
+ .component_name = "cs35l56",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs_amp_init,
+ .rtd_init = asoc_sdw_cs_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "cs35l56-sdw1c",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
+ },
+ },
+ .dai_num = 2,
+ },
+ {
+ .part_id = 0x3563,
+ .name_prefix = "AMP",
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "cs35l56-sdw1",
+ .component_name = "cs35l56",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs_amp_init,
+ .rtd_init = asoc_sdw_cs_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "cs35l56-sdw1c",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
+ },
+ },
+ .dai_num = 2,
+ },
+ {
+ .part_id = 0x4242,
+ .name_prefix = "cs42l42",
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "cs42l42-sdw",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l42_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x4243,
+ .name_prefix = "cs42l43",
+ .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
+ .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar,
+ .dais = {
+ {
+ .direction = {true, false},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp5",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l43_hs_rtd_init,
+ .controls = generic_jack_controls,
+ .num_controls = ARRAY_SIZE(generic_jack_controls),
+ .widgets = generic_jack_widgets,
+ .num_widgets = ARRAY_SIZE(generic_jack_widgets),
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp1",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init,
+ .widgets = generic_dmic_widgets,
+ .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
+ .quirk = SOC_SDW_CODEC_MIC,
+ .quirk_exclude = true,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp2",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ },
+ {
+ .direction = {true, false},
+ .codec_name = "cs42l43-codec",
+ .dai_name = "cs42l43-dp6",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs42l43_spk_init,
+ .rtd_init = asoc_sdw_cs42l43_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS,
+ },
+ },
+ .dai_num = 4,
+ },
+ {
+ .part_id = 0x4245,
+ .name_prefix = "cs42l45",
+ .dais = {
+ {
+ .direction = {true, false},
+ .codec_name = "snd_soc_sdca.UAJ.1",
+ .dai_name = "IT 41",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l45_hs_rtd_init,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "snd_soc_sdca.SmartMic.0",
+ .dai_name = "OT 113",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init,
+ },
+ {
+ .direction = {false, true},
+ .codec_name = "snd_soc_sdca.UAJ.1",
+ .dai_name = "OT 36",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ },
+ },
+ .dai_num = 3,
+ .auxs = {
+ {
+ .codec_name = "snd_soc_sdca.HID.2",
+ },
+ },
+ .aux_num = 1,
+ },
+ {
+ .part_id = 0xaaaa, /* generic codec mockup */
+ .name_prefix = "sdw_mockup_mmulti-function",
+ .version_id = 0,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "sdw-mockup-aif1",
+ .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 = 3,
+ },
+ {
+ .part_id = 0xaa55, /* headset codec mockup */
+ .name_prefix = "sdw_mockup_headset0",
+ .version_id = 0,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "sdw-mockup-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_JACK,
+ .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x55aa, /* amplifier mockup */
+ .name_prefix = "sdw_mockup_amp1",
+ .version_id = 0,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "sdw-mockup-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ },
+ },
+ .dai_num = 1,
+ },
+ {
+ .part_id = 0x5555,
+ .name_prefix = "sdw_mockup_mic0",
+ .version_id = 0,
+ .dais = {
+ {
+ .dai_name = "sdw-mockup-aif1",
+ .direction = {false, true},
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ },
+ },
+ .dai_num = 1,
+ },
+};
+EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_get_codec_info_list_count(void)
+{
+ return ARRAY_SIZE(codec_info_list);
+};
+EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS");
+
+struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr)
+{
+ unsigned int part_id, sdw_version;
+ int i;
+
+ part_id = SDW_PART_ID(adr);
+ sdw_version = SDW_VERSION(adr);
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
+ /*
+ * A codec info is for all sdw version with the part id if
+ * version_id is not specified in the codec info.
+ */
+ if (part_id == codec_info_list[i].part_id &&
+ (!codec_info_list[i].version_id ||
+ sdw_version == codec_info_list[i].version_id))
+ return &codec_info_list[i];
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS");
+
+struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id)
+{
+ int i;
+
+ if (!acpi_id[0])
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
+ if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
+ return &codec_info_list[i];
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS");
+
+struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+ for (j = 0; j < codec_info_list[i].dai_num; j++) {
+ if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
+ *dai_index = j;
+ return &codec_info_list[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct asoc_sdw_codec_info *codec_info;
+ struct snd_soc_dai *dai;
+ const char *spk_components="";
+ int dai_index;
+ int ret;
+ int i;
+
+ for_each_rtd_codec_dais(rtd, i, dai) {
+ codec_info = asoc_sdw_find_codec_info_dai(dai->name, &dai_index);
+ if (!codec_info)
+ return -EINVAL;
+
+ /*
+ * A codec dai can be connected to different dai links for capture and playback,
+ * but we only need to call the rtd_init function once.
+ * The rtd_init for each codec dai is independent. So, the order of rtd_init
+ * doesn't matter.
+ */
+ if (codec_info->dais[dai_index].rtd_init_done)
+ continue;
+
+ /*
+ * Add card controls and dapm widgets for the first codec dai.
+ * The controls and widgets will be used for all codec dais.
+ */
+
+ if (i > 0)
+ goto skip_add_controls_widgets;
+
+ if (codec_info->dais[dai_index].controls) {
+ ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls,
+ codec_info->dais[dai_index].num_controls);
+ if (ret) {
+ dev_err(card->dev, "%#x controls addition failed: %d\n",
+ codec_info->part_id, ret);
+ return ret;
+ }
+ }
+ if (codec_info->dais[dai_index].widgets) {
+ ret = snd_soc_dapm_new_controls(dapm,
+ codec_info->dais[dai_index].widgets,
+ codec_info->dais[dai_index].num_widgets);
+ if (ret) {
+ dev_err(card->dev, "%#x widgets addition failed: %d\n",
+ codec_info->part_id, ret);
+ return ret;
+ }
+ }
+
+skip_add_controls_widgets:
+ if (codec_info->dais[dai_index].rtd_init) {
+ ret = codec_info->dais[dai_index].rtd_init(rtd, dai);
+ if (ret)
+ return ret;
+ }
+
+ /* Generate the spk component string for card->components string */
+ if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP &&
+ codec_info->dais[dai_index].component_name) {
+ if (strlen (spk_components) == 0)
+ spk_components =
+ devm_kasprintf(card->dev, GFP_KERNEL, "%s",
+ codec_info->dais[dai_index].component_name);
+ else
+ /* Append component name to spk_components */
+ spk_components =
+ devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s+%s", spk_components,
+ codec_info->dais[dai_index].component_name);
+ }
+
+ codec_info->dais[dai_index].rtd_init_done = true;
+
+ }
+
+ if (strlen (spk_components) > 0) {
+ /* Update card components for speaker components */
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s",
+ card->components, spk_components);
+ if (!card->components)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS");
+
+/* these wrappers are only needed to avoid typecast compilation errors */
+int asoc_sdw_startup(struct snd_pcm_substream *substream)
+{
+ return sdw_startup_stream(substream);
+}
+EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sdw_stream_runtime *sdw_stream;
+ struct snd_soc_dai *dai;
+
+ /* Find stream from first CPU DAI */
+ dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
+ if (IS_ERR(sdw_stream)) {
+ dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
+ return PTR_ERR(sdw_stream);
+ }
+
+ return sdw_prepare_stream(sdw_stream);
+}
+EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sdw_stream_runtime *sdw_stream;
+ struct snd_soc_dai *dai;
+ int ret;
+
+ /* Find stream from first CPU DAI */
+ dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
+ if (IS_ERR(sdw_stream)) {
+ dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
+ return PTR_ERR(sdw_stream);
+ }
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = sdw_enable_stream(sdw_stream);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ ret = sdw_disable_stream(sdw_stream);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret)
+ dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_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_link_ch_map *ch_maps;
+ int ch = params_channels(params);
+ unsigned int ch_mask;
+ int num_codecs;
+ int step;
+ int i;
+
+ if (!rtd->dai_link->ch_maps)
+ return 0;
+
+ /* Identical data will be sent to all codecs in playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ch_mask = GENMASK(ch - 1, 0);
+ step = 0;
+ } else {
+ num_codecs = rtd->dai_link->num_codecs;
+
+ if (ch < num_codecs || ch % num_codecs != 0) {
+ dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
+ ch, num_codecs);
+ return -EINVAL;
+ }
+
+ ch_mask = GENMASK(ch / num_codecs - 1, 0);
+ step = hweight_long(ch_mask);
+ }
+
+ /*
+ * The captured data will be combined from each cpu DAI if the dai
+ * link has more than one codec DAIs. Set codec channel mask and
+ * ASoC will set the corresponding channel numbers for each cpu dai.
+ */
+ for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
+ ch_maps->ch_mask = ch_mask << (i * step);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sdw_stream_runtime *sdw_stream;
+ struct snd_soc_dai *dai;
+
+ /* Find stream from first CPU DAI */
+ dai = snd_soc_rtd_to_cpu(rtd, 0);
+
+ sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
+ if (IS_ERR(sdw_stream)) {
+ dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
+ return PTR_ERR(sdw_stream);
+ }
+
+ return sdw_deprepare_stream(sdw_stream);
+}
+EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS");
+
+void asoc_sdw_shutdown(struct snd_pcm_substream *substream)
+{
+ sdw_shutdown_stream(substream);
+}
+EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS");
+
+static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
+ unsigned int sdw_version,
+ unsigned int mfg_id,
+ unsigned int part_id,
+ unsigned int class_id,
+ int index_in_link)
+{
+ int i;
+
+ for (i = 0; i < adr_link->num_adr; i++) {
+ unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
+ u64 adr;
+
+ /* skip itself */
+ if (i == index_in_link)
+ continue;
+
+ adr = adr_link->adr_d[i].adr;
+
+ sdw1_version = SDW_VERSION(adr);
+ mfg1_id = SDW_MFG_ID(adr);
+ part1_id = SDW_PART_ID(adr);
+ class1_id = SDW_CLASS_ID(adr);
+
+ if (sdw_version == sdw1_version &&
+ mfg_id == mfg1_id &&
+ part_id == part1_id &&
+ class_id == class1_id)
+ return false;
+ }
+
+ return true;
+}
+
+static const char *_asoc_sdw_get_codec_name(struct device *dev,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int adr_index)
+{
+ u64 adr = adr_link->adr_d[adr_index].adr;
+ unsigned int sdw_version = SDW_VERSION(adr);
+ unsigned int link_id = SDW_DISCO_LINK_ID(adr);
+ unsigned int unique_id = SDW_UNIQUE_ID(adr);
+ unsigned int mfg_id = SDW_MFG_ID(adr);
+ unsigned int part_id = SDW_PART_ID(adr);
+ unsigned int class_id = SDW_CLASS_ID(adr);
+
+ if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id,
+ class_id, adr_index))
+ return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x",
+ link_id, mfg_id, part_id, class_id);
+
+ return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x",
+ link_id, mfg_id, part_id, class_id, unique_id);
+}
+
+const char *asoc_sdw_get_codec_name(struct device *dev,
+ const struct asoc_sdw_dai_info *dai_info,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int adr_index)
+{
+ if (dai_info->codec_name)
+ return devm_kstrdup(dev, dai_info->codec_name, GFP_KERNEL);
+
+ return _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
+}
+EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS");
+
+/* helper to get the link that the codec DAI is used */
+struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card,
+ const char *dai_name)
+{
+ struct snd_soc_dai_link *dai_link;
+ int i;
+ int j;
+
+ for_each_card_prelinks(card, i, dai_link) {
+ for (j = 0; j < dai_link->num_codecs; j++) {
+ /* Check each codec in a link */
+ if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
+ return dai_link;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS");
+
+void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret;
+ int i, j;
+
+ for (i = 0; i < ctx->codec_info_list_count; i++) {
+ for (j = 0; j < codec_info_list[i].dai_num; j++) {
+ codec_info_list[i].dais[j].rtd_init_done = false;
+ /* Check each dai in codec_info_lis to see if it is used in the link */
+ if (!codec_info_list[i].dais[j].exit)
+ continue;
+ /*
+ * We don't need to call .exit function if there is no matched
+ * dai link found.
+ */
+ dai_link = asoc_sdw_mc_find_codec_dai_used(card,
+ codec_info_list[i].dais[j].dai_name);
+ if (dai_link) {
+ /* Do the .exit function if the codec dai is used in the link */
+ ret = codec_info_list[i].dais[j].exit(card, dai_link);
+ if (ret)
+ dev_warn(card->dev,
+ "codec exit failed %d\n",
+ ret);
+ break;
+ }
+ }
+ }
+}
+EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_card_late_probe(struct snd_soc_card *card)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+ if (codec_info_list[i].codec_card_late_probe) {
+ ret = codec_info_list[i].codec_card_late_probe(card);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ return ret;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS");
+
+void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
+ int *be_id, char *name, int playback, int capture,
+ struct snd_soc_dai_link_component *cpus, int cpus_num,
+ struct snd_soc_dai_link_component *platform_component,
+ int num_platforms, struct snd_soc_dai_link_component *codecs,
+ int codecs_num, int no_pcm,
+ int (*init)(struct snd_soc_pcm_runtime *rtd),
+ const struct snd_soc_ops *ops)
+{
+ dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id);
+ dai_links->id = (*be_id)++;
+ dai_links->name = name;
+ dai_links->stream_name = name;
+ dai_links->platforms = platform_component;
+ dai_links->num_platforms = num_platforms;
+ dai_links->no_pcm = no_pcm;
+ dai_links->cpus = cpus;
+ dai_links->num_cpus = cpus_num;
+ dai_links->codecs = codecs;
+ dai_links->num_codecs = codecs_num;
+ dai_links->playback_only = playback && !capture;
+ dai_links->capture_only = !playback && capture;
+ dai_links->init = init;
+ dai_links->ops = ops;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
+ int *be_id, char *name, int playback, int capture,
+ const char *cpu_dai_name, const char *platform_comp_name,
+ const char *codec_name, const char *codec_dai_name,
+ int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd),
+ const struct snd_soc_ops *ops)
+{
+ struct snd_soc_dai_link_component *dlc;
+
+ /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */
+ dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL);
+ if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name)
+ return -ENOMEM;
+
+ dlc[0].dai_name = cpu_dai_name;
+ dlc[1].name = platform_comp_name;
+
+ dlc[2].name = codec_name;
+ dlc[2].dai_name = codec_dai_name;
+
+ asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture,
+ &dlc[0], 1, &dlc[1], 1, &dlc[2], 1,
+ no_pcm, init, ops);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card,
+ int *num_devs, int *num_ends, int *num_aux)
+{
+ struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ const struct snd_soc_acpi_link_adr *adr_link;
+ int i;
+
+ for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
+ *num_devs += adr_link->num_adr;
+
+ for (i = 0; i < adr_link->num_adr; i++) {
+ const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
+ struct asoc_sdw_codec_info *codec_info;
+
+ *num_ends += adr_dev->num_endpoints;
+
+ codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
+ if (!codec_info)
+ return -EINVAL;
+
+ *num_aux += codec_info->aux_num;
+ }
+ }
+
+ dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS");
+
+struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
+ const struct snd_soc_acpi_endpoint *new)
+{
+ while (dailinks->initialised) {
+ if (new->aggregated && dailinks->group_id == new->group_id)
+ return dailinks;
+
+ dailinks++;
+ }
+
+ INIT_LIST_HEAD(&dailinks->endpoints);
+ dailinks->group_id = new->group_id;
+ dailinks->initialised = true;
+
+ return dailinks;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS");
+
+int asoc_sdw_get_dai_type(u32 type)
+{
+ switch (type) {
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
+ return SOC_SDW_DAI_TYPE_AMP;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
+ case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
+ return SOC_SDW_DAI_TYPE_MIC;
+ case SDCA_FUNCTION_TYPE_UAJ:
+ case SDCA_FUNCTION_TYPE_RJ:
+ case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
+ return SOC_SDW_DAI_TYPE_JACK;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_NS(asoc_sdw_get_dai_type, "SND_SOC_SDW_UTILS");
+
+/*
+ * Check if the SDCA endpoint is present by the SDW peripheral
+ *
+ * @dev: Device pointer
+ * @codec_info: Codec info pointer
+ * @adr_link: ACPI link address
+ * @adr_index: Index of the ACPI link address
+ * @end_index: Index of the endpoint
+ *
+ * Return: 1 if the endpoint is present,
+ * 0 if the endpoint is not present,
+ * negative error code.
+ */
+
+static int is_sdca_endpoint_present(struct device *dev,
+ struct asoc_sdw_codec_info *codec_info,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int adr_index, int end_index)
+{
+ const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index];
+ const struct snd_soc_acpi_endpoint *adr_end;
+ const struct asoc_sdw_dai_info *dai_info;
+ struct snd_soc_dai_link_component *dlc;
+ struct snd_soc_dai *codec_dai;
+ struct sdw_slave *slave;
+ struct device *sdw_dev;
+ const char *sdw_codec_name;
+ int ret, i;
+
+ dlc = kzalloc(sizeof(*dlc), GFP_KERNEL);
+ if (!dlc)
+ return -ENOMEM;
+
+ adr_end = &adr_dev->endpoints[end_index];
+ dai_info = &codec_info->dais[adr_end->num];
+
+ dlc->dai_name = dai_info->dai_name;
+ codec_dai = snd_soc_find_dai_with_mutex(dlc);
+ if (!codec_dai) {
+ dev_warn(dev, "codec dai %s not registered yet\n", dlc->dai_name);
+ kfree(dlc);
+ return -EPROBE_DEFER;
+ }
+ kfree(dlc);
+
+ sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
+ if (!sdw_codec_name)
+ return -ENOMEM;
+
+ sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
+ if (!sdw_dev) {
+ dev_err(dev, "codec %s not found\n", sdw_codec_name);
+ return -EINVAL;
+ }
+
+ slave = dev_to_sdw_dev(sdw_dev);
+ if (!slave) {
+ ret = -EINVAL;
+ goto put_device;
+ }
+
+ /* Make sure BIOS provides SDCA properties */
+ if (!slave->sdca_data.interface_revision) {
+ dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
+ ret = 1;
+ goto put_device;
+ }
+
+ for (i = 0; i < slave->sdca_data.num_functions; i++) {
+ int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type);
+
+ if (dai_type == dai_info->dai_type) {
+ dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
+ dai_type, slave->sdca_data.function[i].name);
+ ret = 1;
+ goto put_device;
+ }
+ }
+
+ dev_dbg(&slave->dev,
+ "SDCA device function for DAI type %d not supported, skip endpoint\n",
+ dai_info->dai_type);
+
+ ret = 0;
+
+put_device:
+ put_device(sdw_dev);
+ return ret;
+}
+
+int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+ struct snd_soc_aux_dev *soc_aux,
+ struct asoc_sdw_dailink *soc_dais,
+ struct asoc_sdw_endpoint *soc_ends,
+ int *num_devs)
+{
+ struct device *dev = card->dev;
+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ const struct snd_soc_acpi_link_adr *adr_link;
+ struct asoc_sdw_endpoint *soc_end = soc_ends;
+ int num_dais = 0;
+ int i, j;
+ int ret;
+
+ for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
+ int num_link_dailinks = 0;
+
+ if (!is_power_of_2(adr_link->mask)) {
+ dev_err(dev, "link with multiple mask bits: 0x%x\n",
+ adr_link->mask);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < adr_link->num_adr; i++) {
+ const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
+ struct asoc_sdw_codec_info *codec_info;
+ const char *codec_name;
+ bool check_sdca = false;
+
+ if (!adr_dev->name_prefix) {
+ dev_err(dev, "codec 0x%llx does not have a name prefix\n",
+ adr_dev->adr);
+ return -EINVAL;
+ }
+
+ codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
+ if (!codec_info)
+ return -EINVAL;
+
+ for (j = 0; j < codec_info->aux_num; j++) {
+ soc_aux->dlc.name = codec_info->auxs[j].codec_name;
+ soc_aux++;
+ }
+
+ ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
+
+ if (codec_info->count_sidecar && codec_info->add_sidecar) {
+ ret = codec_info->count_sidecar(card, &num_dais, num_devs);
+ if (ret)
+ return ret;
+
+ soc_end->include_sidecar = true;
+ }
+
+ if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
+ check_sdca = true;
+
+ for (j = 0; j < adr_dev->num_endpoints; j++) {
+ const struct snd_soc_acpi_endpoint *adr_end;
+ const struct asoc_sdw_dai_info *dai_info;
+ struct asoc_sdw_dailink *soc_dai;
+ int stream;
+
+ adr_end = &adr_dev->endpoints[j];
+ dai_info = &codec_info->dais[adr_end->num];
+ soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
+
+ /*
+ * quirk should have higher priority than the sdca properties
+ * in the BIOS. We can't always check the DAI quirk because we
+ * will set the mc_quirk when the BIOS doesn't provide the right
+ * information. The endpoint will be skipped if the dai_info->
+ * quirk_exclude and mc_quirk are both not set if we always skip
+ * the endpoint according to the quirk information. We need to
+ * keep the endpoint if it is present in the BIOS. So, only
+ * check the DAI quirk when the mc_quirk is set or SDCA endpoint
+ * present check is not needed.
+ */
+ if (dai_info->quirk & ctx->mc_quirk || !check_sdca) {
+ /*
+ * Check the endpoint if a matching quirk is set or SDCA
+ * endpoint check is not necessary
+ */
+ if (dai_info->quirk &&
+ !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk)))
+ continue;
+ } else {
+ /* Check SDCA codec endpoint if there is no matching quirk */
+ ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j);
+ if (ret < 0)
+ return ret;
+
+ /* The endpoint is not present, skip */
+ if (!ret)
+ continue;
+ }
+
+ dev_dbg(dev,
+ "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
+ ffs(adr_link->mask) - 1, adr_dev->adr,
+ adr_end->num, dai_info->dai_type,
+ dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
+ dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
+ adr_end->aggregated ? "group" : "solo",
+ adr_end->group_id);
+
+ if (adr_end->num >= codec_info->dai_num) {
+ dev_err(dev,
+ "%d is too many endpoints for codec: 0x%x\n",
+ adr_end->num, codec_info->part_id);
+ return -EINVAL;
+ }
+
+ for_each_pcm_streams(stream) {
+ if (dai_info->direction[stream] &&
+ dai_info->dailink[stream] < 0) {
+ dev_err(dev,
+ "Invalid dailink id %d for codec: 0x%x\n",
+ dai_info->dailink[stream],
+ codec_info->part_id);
+ return -EINVAL;
+ }
+
+ if (dai_info->direction[stream]) {
+ num_dais += !soc_dai->num_devs[stream];
+ soc_dai->num_devs[stream]++;
+ soc_dai->link_mask[stream] |= adr_link->mask;
+ }
+ }
+
+ num_link_dailinks += !!list_empty(&soc_dai->endpoints);
+ list_add_tail(&soc_end->list, &soc_dai->endpoints);
+
+ codec_name = asoc_sdw_get_codec_name(dev, dai_info,
+ adr_link, i);
+ if (!codec_name)
+ return -ENOMEM;
+
+ dev_dbg(dev, "Adding prefix %s for %s\n",
+ adr_dev->name_prefix, codec_name);
+
+ soc_end->name_prefix = adr_dev->name_prefix;
+
+ soc_end->link_mask = adr_link->mask;
+ soc_end->codec_name = codec_name;
+ soc_end->codec_info = codec_info;
+ soc_end->dai_info = dai_info;
+ soc_end++;
+ }
+ }
+
+ ctx->append_dai_type |= (num_link_dailinks > 1);
+ }
+
+ return num_dais;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SoundWire ASoC helpers");
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
deleted file mode 100644
index d07eccfa3ac2..000000000000
--- a/sound/soc/sh/rcar/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o
-obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
deleted file mode 100644
index 86bdecc24956..000000000000
--- a/sound/soc/sh/rcar/gen.c
+++ /dev/null
@@ -1,562 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car Gen1 SRU/SSI support
-//
-// Copyright (C) 2013 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-/*
- * #define DEBUG
- *
- * you can also add below in
- * ${LINUX}/drivers/base/regmap/regmap.c
- * for regmap debug
- *
- * #define LOG_DEVICE "xxxx.rcar_sound"
- */
-
-#include "rsnd.h"
-
-struct rsnd_gen {
- struct rsnd_gen_ops *ops;
-
- /* RSND_BASE_MAX base */
- void __iomem *base[RSND_BASE_MAX];
- phys_addr_t res[RSND_BASE_MAX];
- struct regmap *regmap[RSND_BASE_MAX];
-
- /* RSND_REG_MAX base */
- struct regmap_field *regs[REG_MAX];
- const char *reg_name[REG_MAX];
-};
-
-#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
-#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
-
-struct rsnd_regmap_field_conf {
- int idx;
- unsigned int reg_offset;
- unsigned int id_offset;
- const char *reg_name;
-};
-
-#define RSND_REG_SET(id, offset, _id_offset, n) \
-{ \
- .idx = id, \
- .reg_offset = offset, \
- .id_offset = _id_offset, \
- .reg_name = n, \
-}
-/* single address mapping */
-#define RSND_GEN_S_REG(id, offset) \
- RSND_REG_SET(id, offset, 0, #id)
-
-/* multi address mapping */
-#define RSND_GEN_M_REG(id, offset, _id_offset) \
- RSND_REG_SET(id, offset, _id_offset, #id)
-
-/*
- * basic function
- */
-static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
- struct rsnd_gen *gen, enum rsnd_reg reg)
-{
- if (!gen->regs[reg]) {
- struct device *dev = rsnd_priv_to_dev(priv);
-
- dev_err(dev, "unsupported register access %x\n", reg);
- return 0;
- }
-
- return 1;
-}
-
-static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
-{
- if (mod->ops->id_cmd)
- return mod->ops->id_cmd(mod);
-
- return rsnd_mod_id(mod);
-}
-
-u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
- u32 val;
-
- if (!rsnd_is_accessible_reg(priv, gen, reg))
- return 0;
-
- regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
-
- dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
- rsnd_mod_name(mod),
- rsnd_reg_name(gen, reg), reg, val);
-
- return val;
-}
-
-void rsnd_mod_write(struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
- if (!rsnd_is_accessible_reg(priv, gen, reg))
- return;
-
- regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
-
- dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
- rsnd_mod_name(mod),
- rsnd_reg_name(gen, reg), reg, data);
-}
-
-void rsnd_mod_bset(struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 mask, u32 data)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
- if (!rsnd_is_accessible_reg(priv, gen, reg))
- return;
-
- regmap_fields_force_update_bits(gen->regs[reg],
- rsnd_mod_id_cmd(mod), mask, data);
-
- dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
- rsnd_mod_name(mod),
- rsnd_reg_name(gen, reg), reg, data, mask);
-
-}
-
-phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
-{
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
- return gen->res[reg_id];
-}
-
-#ifdef CONFIG_DEBUG_FS
-void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id)
-{
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
- return gen->base[reg_id];
-}
-#endif
-
-#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \
- _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
-static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
- int id_size,
- int reg_id,
- const char *name,
- const struct rsnd_regmap_field_conf *conf,
- int conf_size)
-{
- struct platform_device *pdev = rsnd_priv_to_pdev(priv);
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct resource *res;
- struct regmap_config regc;
- struct regmap_field *regs;
- struct regmap *regmap;
- struct reg_field regf;
- void __iomem *base;
- int i;
-
- memset(&regc, 0, sizeof(regc));
- regc.reg_bits = 32;
- regc.val_bits = 32;
- regc.reg_stride = 4;
- regc.name = name;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
- if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
- if (!res)
- return -ENODEV;
-
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &regc);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- /* RSND_BASE_MAX base */
- gen->base[reg_id] = base;
- gen->regmap[reg_id] = regmap;
- gen->res[reg_id] = res->start;
-
- for (i = 0; i < conf_size; i++) {
-
- regf.reg = conf[i].reg_offset;
- regf.id_offset = conf[i].id_offset;
- regf.lsb = 0;
- regf.msb = 31;
- regf.id_size = id_size;
-
- regs = devm_regmap_field_alloc(dev, regmap, regf);
- if (IS_ERR(regs))
- return PTR_ERR(regs);
-
- /* RSND_REG_MAX base */
- gen->regs[conf[i].idx] = regs;
- gen->reg_name[conf[i].idx] = conf[i].reg_name;
- }
-
- return 0;
-}
-
-/*
- * Gen4
- */
-static int rsnd_gen4_probe(struct rsnd_priv *priv)
-{
- static const struct rsnd_regmap_field_conf conf_ssiu[] = {
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
- RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
- RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
- RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
- RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
-
- RSND_GEN_S_REG(SSI_BUSIF0_MODE, 0x0),
- RSND_GEN_S_REG(SSI_BUSIF0_ADINR, 0x4),
- RSND_GEN_S_REG(SSI_BUSIF0_DALIGN, 0x8),
- RSND_GEN_S_REG(SSI_BUSIF1_MODE, 0x20),
- RSND_GEN_S_REG(SSI_BUSIF1_ADINR, 0x24),
- RSND_GEN_S_REG(SSI_BUSIF1_DALIGN, 0x28),
- RSND_GEN_S_REG(SSI_BUSIF2_MODE, 0x40),
- RSND_GEN_S_REG(SSI_BUSIF2_ADINR, 0x44),
- RSND_GEN_S_REG(SSI_BUSIF2_DALIGN, 0x48),
- RSND_GEN_S_REG(SSI_BUSIF3_MODE, 0x60),
- RSND_GEN_S_REG(SSI_BUSIF3_ADINR, 0x64),
- RSND_GEN_S_REG(SSI_BUSIF3_DALIGN, 0x68),
- RSND_GEN_S_REG(SSI_BUSIF4_MODE, 0x500),
- RSND_GEN_S_REG(SSI_BUSIF4_ADINR, 0x504),
- RSND_GEN_S_REG(SSI_BUSIF4_DALIGN, 0x508),
- RSND_GEN_S_REG(SSI_BUSIF5_MODE, 0x520),
- RSND_GEN_S_REG(SSI_BUSIF5_ADINR, 0x524),
- RSND_GEN_S_REG(SSI_BUSIF5_DALIGN, 0x528),
- RSND_GEN_S_REG(SSI_BUSIF6_MODE, 0x540),
- RSND_GEN_S_REG(SSI_BUSIF6_ADINR, 0x544),
- RSND_GEN_S_REG(SSI_BUSIF6_DALIGN, 0x548),
- RSND_GEN_S_REG(SSI_BUSIF7_MODE, 0x560),
- RSND_GEN_S_REG(SSI_BUSIF7_ADINR, 0x564),
- RSND_GEN_S_REG(SSI_BUSIF7_DALIGN, 0x568),
- RSND_GEN_S_REG(SSI_CTRL, 0x010),
- RSND_GEN_S_REG(SSI_INT_ENABLE, 0x018),
- RSND_GEN_S_REG(SSI_MODE, 0x00c),
- RSND_GEN_S_REG(SSI_MODE2, 0xa0c),
- };
- static const struct rsnd_regmap_field_conf conf_adg[] = {
- RSND_GEN_S_REG(BRRA, 0x00),
- RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(BRGCKR, 0x08),
- RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
- };
- static const struct rsnd_regmap_field_conf conf_ssi[] = {
- RSND_GEN_S_REG(SSICR, 0x00),
- RSND_GEN_S_REG(SSISR, 0x04),
- RSND_GEN_S_REG(SSITDR, 0x08),
- RSND_GEN_S_REG(SSIRDR, 0x0c),
- RSND_GEN_S_REG(SSIWSR, 0x20),
- };
- static const struct rsnd_regmap_field_conf conf_sdmc[] = {
- RSND_GEN_M_REG(SSI_BUSIF, 0x0, 0x8000),
- };
- int ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_ADG, "adg", conf_adg);
- int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSIU, "ssiu", conf_ssiu);
- int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSI, "ssi", conf_ssi);
- int ret_sdmc = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SDMC, "sdmc", conf_sdmc);
-
- return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
-}
-
-/*
- * Gen2
- */
-static int rsnd_gen2_probe(struct rsnd_priv *priv)
-{
- static const struct rsnd_regmap_field_conf conf_ssiu[] = {
- RSND_GEN_S_REG(SSI_MODE0, 0x800),
- RSND_GEN_S_REG(SSI_MODE1, 0x804),
- RSND_GEN_S_REG(SSI_MODE2, 0x808),
- RSND_GEN_S_REG(SSI_CONTROL, 0x810),
- RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
- RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
- RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
- RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
- RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
- RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
- RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
- RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
- RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c),
- RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
- RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
-
- /* FIXME: it needs SSI_MODE2/3 in the future */
- RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80),
- RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
- RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
- RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
- RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c),
- RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484),
- RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488),
- RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0),
- RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4),
- RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8),
- RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0),
- RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4),
- RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8),
- RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0),
- RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4),
- RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8),
- RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80),
- RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84),
- RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88),
- RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0),
- RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4),
- RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8),
- RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0),
- RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4),
- RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8),
- RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0),
- RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4),
- RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8),
- };
-
- static const struct rsnd_regmap_field_conf conf_scu[] = {
- RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20),
- RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20),
- RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20),
- RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
- RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
- RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
- RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20),
- RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20),
- RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
- RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
- RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
- RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
- RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
- RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
- RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
- RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
- RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
- RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
- RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
- RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
- RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
- RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
- RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
- RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
- RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
- RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
- RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
- RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
- RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
- RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
- RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
- RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
- RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
- RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
- RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
- RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
- RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
- RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
- RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
- RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
- RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
- RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
- RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
- RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
- RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
- RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
- RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
- RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
- RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
- RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
- RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
- RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
- RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
- RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
- RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
- RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
- RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
- RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
- RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
- RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
- RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
- RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
- RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40),
- RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40),
- RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40),
- RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40),
- RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40),
- RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40),
- RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40),
- RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
- RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
- RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
- RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
- RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
- RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
- RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
- RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
- RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
- RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
- RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100),
- RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100),
- RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100),
- RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100),
- RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100),
- RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100),
- RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
- };
- static const struct rsnd_regmap_field_conf conf_adg[] = {
- RSND_GEN_S_REG(BRRA, 0x00),
- RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(BRGCKR, 0x08),
- RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
- RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
- RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
- RSND_GEN_S_REG(DIV_EN, 0x30),
- RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34),
- RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38),
- RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c),
- RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40),
- RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44),
- RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48),
- RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c),
- RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50),
- RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54),
- RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58),
- RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c),
- };
- static const struct rsnd_regmap_field_conf conf_ssi[] = {
- RSND_GEN_M_REG(SSICR, 0x00, 0x40),
- RSND_GEN_M_REG(SSISR, 0x04, 0x40),
- RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
- RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
- RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
- };
- int ret_ssiu;
- int ret_scu;
- int ret_adg;
- int ret_ssi;
-
- ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu);
- ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, "scu", conf_scu);
- ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, "adg", conf_adg);
- ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, "ssi", conf_ssi);
- if (ret_ssiu < 0 ||
- ret_scu < 0 ||
- ret_adg < 0 ||
- ret_ssi < 0)
- return ret_ssiu | ret_scu | ret_adg | ret_ssi;
-
- return 0;
-}
-
-/*
- * Gen1
- */
-
-static int rsnd_gen1_probe(struct rsnd_priv *priv)
-{
- static const struct rsnd_regmap_field_conf conf_adg[] = {
- RSND_GEN_S_REG(BRRA, 0x00),
- RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(BRGCKR, 0x08),
- RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
- RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
- };
- static const struct rsnd_regmap_field_conf conf_ssi[] = {
- RSND_GEN_M_REG(SSICR, 0x00, 0x40),
- RSND_GEN_M_REG(SSISR, 0x04, 0x40),
- RSND_GEN_M_REG(SSITDR, 0x08, 0x40),
- RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40),
- RSND_GEN_M_REG(SSIWSR, 0x20, 0x40),
- };
- int ret_adg;
- int ret_ssi;
-
- ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
- ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
- if (ret_adg < 0 ||
- ret_ssi < 0)
- return ret_adg | ret_ssi;
-
- return 0;
-}
-
-/*
- * Gen
- */
-int rsnd_gen_probe(struct rsnd_priv *priv)
-{
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_gen *gen;
- int ret;
-
- gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
- if (!gen)
- return -ENOMEM;
-
- priv->gen = gen;
-
- ret = -ENODEV;
- if (rsnd_is_gen1(priv))
- ret = rsnd_gen1_probe(priv);
- else if (rsnd_is_gen2(priv) ||
- rsnd_is_gen3(priv))
- ret = rsnd_gen2_probe(priv);
- else if (rsnd_is_gen4(priv))
- ret = rsnd_gen4_probe(priv);
-
- if (ret < 0)
- dev_err(dev, "unknown generation R-Car sound device\n");
-
- return ret;
-}
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index 4e4fe29ade50..37486d6a438e 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -87,8 +87,8 @@ static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(ret & (1 << offset));
}
-static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip);
struct snd_soc_component *component = gpio_to_component(chip);
@@ -98,15 +98,22 @@ static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned int offset,
snd_soc_component_write(component, AC97_GPIO_STATUS,
gpio_priv->gpios_set);
dev_dbg(component->dev, "set gpio %d to %d\n", offset, !!value);
+
+ return 0;
}
static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
struct snd_soc_component *component = gpio_to_component(chip);
+ int ret;
dev_dbg(component->dev, "set gpio %d to output\n", offset);
- snd_soc_ac97_gpio_set(chip, offset, value);
+
+ ret = snd_soc_ac97_gpio_set(chip, offset, value);
+ if (ret)
+ return ret;
+
return snd_soc_component_update_bits(component, AC97_GPIO_CFG,
1 << offset, 0);
}
@@ -168,7 +175,7 @@ static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
* it. The caller is responsible to either call device_add(&ac97->dev) to
* register the device, or to call put_device(&ac97->dev) to free the device.
*
- * Returns: A snd_ac97 device or a PTR_ERR in case of an error.
+ * Returns: A snd_ac97 device or an ERR_PTR in case of an error.
*/
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component)
{
@@ -207,7 +214,7 @@ EXPORT_SYMBOL(snd_soc_alloc_ac97_component);
* the device and check if it matches the expected ID. If it doesn't match an
* error will be returned and device will not be registered.
*
- * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success.
+ * Returns: An ERR_PTR on failure or a valid snd_ac97 struct on success.
*/
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
unsigned int id, unsigned int id_mask)
diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c
index 142476f1396f..270f9777942f 100644
--- a/sound/soc/soc-acpi.c
+++ b/sound/soc/soc-acpi.c
@@ -125,5 +125,80 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
}
EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
+#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
+ SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
+
+/* Check if all Slaves defined on the link can be found */
+bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
+ const struct snd_soc_acpi_link_adr *link,
+ struct sdw_peripherals *peripherals)
+{
+ unsigned int part_id, link_id, unique_id, mfg_id, version;
+ int i, j, k;
+
+ for (i = 0; i < link->num_adr; i++) {
+ u64 adr = link->adr_d[i].adr;
+ int reported_part_count = 0;
+
+ mfg_id = SDW_MFG_ID(adr);
+ part_id = SDW_PART_ID(adr);
+ link_id = SDW_DISCO_LINK_ID(adr);
+ version = SDW_VERSION(adr);
+
+ for (j = 0; j < peripherals->num_peripherals; j++) {
+ struct sdw_slave *peripheral = peripherals->array[j];
+
+ /* find out how many identical parts were reported on that link */
+ if (peripheral->bus->link_id == link_id &&
+ peripheral->id.part_id == part_id &&
+ peripheral->id.mfg_id == mfg_id &&
+ peripheral->id.sdw_version == version)
+ reported_part_count++;
+ }
+
+ for (j = 0; j < peripherals->num_peripherals; j++) {
+ struct sdw_slave *peripheral = peripherals->array[j];
+ int expected_part_count = 0;
+
+ if (peripheral->bus->link_id != link_id ||
+ peripheral->id.part_id != part_id ||
+ peripheral->id.mfg_id != mfg_id ||
+ peripheral->id.sdw_version != version)
+ continue;
+
+ /* find out how many identical parts are expected */
+ for (k = 0; k < link->num_adr; k++) {
+ u64 adr2 = link->adr_d[k].adr;
+
+ if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
+ expected_part_count++;
+ }
+
+ if (reported_part_count == expected_part_count) {
+ /*
+ * we have to check unique id
+ * if there is more than one
+ * Slave on the link
+ */
+ unique_id = SDW_UNIQUE_ID(adr);
+ if (reported_part_count == 1 ||
+ peripheral->id.unique_id == unique_id) {
+ dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id);
+ break;
+ }
+ } else {
+ dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n",
+ part_id, reported_part_count, expected_part_count, link_id);
+ }
+ }
+ if (j == peripherals->num_peripherals) {
+ dev_dbg(dev, "Slave part_id %#x not found\n", part_id);
+ return false;
+ }
+ }
+ return true;
+}
+EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ALSA SoC ACPI module");
diff --git a/sound/soc/soc-card-test.c b/sound/soc/soc-card-test.c
new file mode 100644
index 000000000000..47dfd8b1babc
--- /dev/null
+++ b/sound/soc/soc-card-test.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2024 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/device.h>
+#include <kunit/test.h>
+#include <linux/module.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-card.h>
+
+struct soc_card_test_priv {
+ struct device *card_dev;
+ struct snd_soc_card *card;
+};
+
+static const struct snd_kcontrol_new test_card_controls[] = {
+ SOC_SINGLE("Fee", SND_SOC_NOPM, 0, 1, 0),
+ SOC_SINGLE("Fi", SND_SOC_NOPM, 1, 1, 0),
+ SOC_SINGLE("Fo", SND_SOC_NOPM, 2, 1, 0),
+ SOC_SINGLE("Fum", SND_SOC_NOPM, 3, 1, 0),
+ SOC_SINGLE("Left Fee", SND_SOC_NOPM, 4, 1, 0),
+ SOC_SINGLE("Right Fee", SND_SOC_NOPM, 5, 1, 0),
+ SOC_SINGLE("Left Fi", SND_SOC_NOPM, 6, 1, 0),
+ SOC_SINGLE("Right Fi", SND_SOC_NOPM, 7, 1, 0),
+ SOC_SINGLE("Left Fo", SND_SOC_NOPM, 8, 1, 0),
+ SOC_SINGLE("Right Fo", SND_SOC_NOPM, 9, 1, 0),
+ SOC_SINGLE("Left Fum", SND_SOC_NOPM, 10, 1, 0),
+ SOC_SINGLE("Right Fum", SND_SOC_NOPM, 11, 1, 0),
+};
+
+static void test_snd_soc_card_get_kcontrol(struct kunit *test)
+{
+ struct soc_card_test_priv *priv = test->priv;
+ struct snd_soc_card *card = priv->card;
+ struct snd_kcontrol *kc;
+ struct soc_mixer_control *mc;
+ int i, ret;
+
+ ret = snd_soc_add_card_controls(card, test_card_controls, ARRAY_SIZE(test_card_controls));
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ /* Look up every control */
+ for (i = 0; i < ARRAY_SIZE(test_card_controls); ++i) {
+ kc = snd_soc_card_get_kcontrol(card, test_card_controls[i].name);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kc, "Failed to find '%s'\n",
+ test_card_controls[i].name);
+ if (!kc)
+ continue;
+
+ /* Test that it is the correct control */
+ mc = (struct soc_mixer_control *)kc->private_value;
+ KUNIT_EXPECT_EQ_MSG(test, mc->shift, i, "For '%s'\n", test_card_controls[i].name);
+ }
+
+ /* Test some names that should not be found */
+ kc = snd_soc_card_get_kcontrol(card, "None");
+ KUNIT_EXPECT_NULL(test, kc);
+
+ kc = snd_soc_card_get_kcontrol(card, "Left None");
+ KUNIT_EXPECT_NULL(test, kc);
+
+ kc = snd_soc_card_get_kcontrol(card, "Left");
+ KUNIT_EXPECT_NULL(test, kc);
+
+ kc = snd_soc_card_get_kcontrol(card, NULL);
+ KUNIT_EXPECT_NULL(test, kc);
+}
+
+static int soc_card_test_case_init(struct kunit *test)
+{
+ struct soc_card_test_priv *priv;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ test->priv = priv;
+
+ priv->card = kunit_kzalloc(test, sizeof(*priv->card), GFP_KERNEL);
+ if (!priv->card)
+ return -ENOMEM;
+
+ priv->card_dev = kunit_device_register(test, "sound-soc-card-test");
+ priv->card_dev = get_device(priv->card_dev);
+ if (!priv->card_dev)
+ return -ENODEV;
+
+ priv->card->name = "soc-card-test";
+ priv->card->dev = priv->card_dev;
+ priv->card->owner = THIS_MODULE;
+
+ ret = snd_soc_register_card(priv->card);
+ if (ret) {
+ put_device(priv->card_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void soc_card_test_case_exit(struct kunit *test)
+{
+ struct soc_card_test_priv *priv = test->priv;
+
+ if (priv->card)
+ snd_soc_unregister_card(priv->card);
+
+ if (priv->card_dev)
+ put_device(priv->card_dev);
+}
+
+static struct kunit_case soc_card_test_cases[] = {
+ KUNIT_CASE(test_snd_soc_card_get_kcontrol),
+ {}
+};
+
+static struct kunit_suite soc_card_test_suite = {
+ .name = "soc-card",
+ .test_cases = soc_card_test_cases,
+ .init = soc_card_test_case_init,
+ .exit = soc_card_test_case_exit,
+};
+
+kunit_test_suites(&soc_card_test_suite);
+
+MODULE_DESCRIPTION("ASoC soc-card KUnit test");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c
index 285ab4c9c716..235427d69061 100644
--- a/sound/soc/soc-card.c
+++ b/sound/soc/soc-card.c
@@ -5,6 +5,9 @@
// Copyright (C) 2019 Renesas Electronics Corp.
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
//
+
+#include <linux/lockdep.h>
+#include <linux/rwsem.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -12,33 +15,17 @@
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,
const char *name)
{
- struct snd_card *card = soc_card->snd_card;
- struct snd_kcontrol *kctl;
-
if (unlikely(!name))
return NULL;
- list_for_each_entry(kctl, &card->controls, list)
- if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
- return kctl;
- return NULL;
+ return snd_ctl_find_id_mixer(soc_card->snd_card, name);
}
EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
@@ -222,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);
@@ -234,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 4356cc320fea..c815fd1b3fd1 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,
@@ -58,7 +46,7 @@ static inline int soc_component_field_shift(struct snd_soc_component *component,
* In such case, we can update these macros.
*/
#define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream)
-#define soc_component_mark_pop(component, substream, tgt) ((component)->mark_##tgt = NULL)
+#define soc_component_mark_pop(component, tgt) ((component)->mark_##tgt = NULL)
#define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream)
void snd_soc_component_set_aux(struct snd_soc_component *component,
@@ -236,18 +224,33 @@ int snd_soc_component_force_enable_pin_unlocked(
}
EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked);
+static void soc_get_kcontrol_name(struct snd_soc_component *component,
+ char *buf, int size, const char * const ctl)
+{
+ /* When updating, change also snd_soc_dapm_widget_name_cmp() */
+ if (component->name_prefix)
+ snprintf(buf, size, "%s %s", component->name_prefix, ctl);
+ else
+ snprintf(buf, size, "%s", ctl);
+}
+
+struct snd_kcontrol *snd_soc_component_get_kcontrol(struct snd_soc_component *component,
+ const char * const ctl)
+{
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+ soc_get_kcontrol_name(component, name, ARRAY_SIZE(name), ctl);
+
+ return snd_soc_card_get_kcontrol(component->card, name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_get_kcontrol);
+
int snd_soc_component_notify_control(struct snd_soc_component *component,
const char * const ctl)
{
- char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
struct snd_kcontrol *kctl;
- if (component->name_prefix)
- snprintf(name, ARRAY_SIZE(name), "%s %s", component->name_prefix, ctl);
- else
- snprintf(name, ARRAY_SIZE(name), "%s", ctl);
-
- kctl = snd_soc_card_get_kcontrol(component->card, name);
+ kctl = snd_soc_component_get_kcontrol(component, ctl);
if (!kctl)
return soc_component_ret(component, -EINVAL);
@@ -324,7 +327,7 @@ void snd_soc_component_module_put(struct snd_soc_component *component,
module_put(component->dev->driver->owner);
/* remove the mark from module */
- soc_component_mark_pop(component, mark, module);
+ soc_component_mark_pop(component, module);
}
int snd_soc_component_open(struct snd_soc_component *component,
@@ -355,7 +358,7 @@ int snd_soc_component_close(struct snd_soc_component *component,
ret = component->driver->close(component, substream);
/* remove marked substream */
- soc_component_mark_pop(component, substream, open);
+ soc_component_mark_pop(component, open);
return soc_component_ret(component, ret);
}
@@ -500,7 +503,7 @@ void snd_soc_component_compr_free(struct snd_soc_component *component,
component->driver->compress_ops->free(component, cstream);
/* remove marked substream */
- soc_component_mark_pop(component, cstream, compr_open);
+ soc_component_mark_pop(component, compr_open);
}
EXPORT_SYMBOL_GPL(snd_soc_component_compr_free);
@@ -634,7 +637,7 @@ int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack);
int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *component;
@@ -962,7 +965,7 @@ EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
@@ -992,7 +995,7 @@ void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
snd_pcm_sframes_t *cpu_delay,
snd_pcm_sframes_t *codec_delay)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
snd_pcm_sframes_t delay;
int i;
@@ -1019,7 +1022,7 @@ void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
@@ -1036,7 +1039,7 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream,
int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -1052,22 +1055,20 @@ int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream)
return 0;
}
-int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream,
- int channel, unsigned long pos,
- void __user *buf, unsigned long bytes)
+int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream,
+ int channel, unsigned long pos,
+ struct iov_iter *iter, unsigned long bytes)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
/* FIXME. it returns 1st copy now */
for_each_rtd_components(rtd, i, component)
- if (component->driver->copy_user)
- return soc_component_ret(
- component,
- component->driver->copy_user(
- component, substream, channel,
- pos, buf, bytes));
+ if (component->driver->copy)
+ return soc_component_ret(component,
+ component->driver->copy(component, substream,
+ channel, pos, iter, bytes));
return -EINVAL;
}
@@ -1075,7 +1076,7 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream,
struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
struct page *page;
int i;
@@ -1096,7 +1097,7 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream,
int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
@@ -1143,7 +1144,7 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd)
int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -1161,7 +1162,7 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -1182,7 +1183,7 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
@@ -1197,7 +1198,7 @@ void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
}
/* remove marked substream */
- soc_component_mark_pop(component, substream, hw_params);
+ soc_component_mark_pop(component, hw_params);
}
}
@@ -1216,7 +1217,7 @@ static int soc_component_trigger(struct snd_soc_component *component,
int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
int cmd, int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, r, ret = 0;
@@ -1241,7 +1242,7 @@ int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
r = soc_component_trigger(component, substream, cmd);
if (r < 0)
ret = r; /* use last ret */
- soc_component_mark_pop(component, substream, trigger);
+ soc_component_mark_pop(component, trigger);
}
}
@@ -1277,17 +1278,16 @@ void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
if (rollback && !soc_component_mark_match(component, stream, pm))
continue;
- pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
/* remove marked stream */
- soc_component_mark_pop(component, stream, pm);
+ soc_component_mark_pop(component, pm);
}
}
int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i;
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 02fdb683f75f..7b81dffc6a93 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -57,8 +57,8 @@ static void snd_soc_compr_components_free(struct snd_compr_stream *cstream,
static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ 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);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
snd_soc_dpcm_mutex_lock(rtd);
@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback)
snd_soc_dai_digital_mute(codec_dai, 1, stream);
if (!snd_soc_dai_active(cpu_dai))
- cpu_dai->rate = 0;
+ cpu_dai->symmetric_rate = 0;
if (!snd_soc_dai_active(codec_dai))
- codec_dai->rate = 0;
+ codec_dai->symmetric_rate = 0;
snd_soc_link_compr_shutdown(cstream, rollback);
@@ -98,7 +98,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
int ret;
@@ -133,7 +133,7 @@ err_no_lock:
static int soc_compr_open_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
@@ -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;
@@ -193,6 +193,7 @@ open_err:
snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1);
out:
dpcm_path_put(&list);
+ snd_soc_dpcm_mutex_unlock(fe);
be_err:
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
snd_soc_card_mutex_unlock(fe->card);
@@ -202,7 +203,7 @@ be_err:
static int soc_compr_free_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
struct snd_soc_dpcm *dpcm;
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
@@ -243,8 +244,8 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
int ret;
@@ -275,7 +276,7 @@ out:
static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
int ret;
@@ -322,7 +323,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
int ret;
@@ -368,7 +369,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_pcm_substream *fe_substream =
fe->pcm->streams[cstream->direction].substream;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */
int ret;
@@ -384,11 +385,15 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+ snd_soc_dpcm_mutex_lock(fe);
ret = dpcm_be_dai_hw_params(fe, stream);
+ snd_soc_dpcm_mutex_unlock(fe);
if (ret < 0)
goto out;
+ snd_soc_dpcm_mutex_lock(fe);
ret = dpcm_be_dai_prepare(fe, stream);
+ snd_soc_dpcm_mutex_unlock(fe);
if (ret < 0)
goto out;
@@ -418,7 +423,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
struct snd_codec *params)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret = 0;
snd_soc_dpcm_mutex_lock(rtd);
@@ -436,7 +441,7 @@ err:
static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
snd_soc_dpcm_mutex_lock(rtd);
@@ -452,11 +457,11 @@ err:
}
static int soc_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
int ret;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
snd_soc_dpcm_mutex_lock(rtd);
@@ -474,7 +479,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata);
@@ -488,7 +493,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata);
@@ -532,15 +537,14 @@ static struct snd_compr_ops soc_compr_dyn_ops = {
* snd_soc_new_compress - create a new compress.
*
* @rtd: The runtime for which we will create compress
- * @num: the device index number (zero based - shared with normal PCMs)
*
* Return: 0 for success, else error.
*/
-int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
+int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *component;
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_compr *compr;
struct snd_pcm *be_pcm;
char new_name[64];
@@ -601,12 +605,19 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
return -ENOMEM;
if (rtd->dai_link->dynamic) {
+ int playback = 1;
+ int capture = 1;
+
+ if (rtd->dai_link->capture_only)
+ playback = 0;
+ if (rtd->dai_link->playback_only)
+ capture = 0;
+
snprintf(new_name, sizeof(new_name), "(%s)",
rtd->dai_link->stream_name);
- ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
- rtd->dai_link->dpcm_playback,
- rtd->dai_link->dpcm_capture, &be_pcm);
+ ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id,
+ playback, capture, &be_pcm);
if (ret < 0) {
dev_err(rtd->card->dev,
"Compress ASoC: can't create compressed for %s: %d\n",
@@ -619,14 +630,14 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
rtd->pcm = be_pcm;
rtd->fe_compr = 1;
- if (rtd->dai_link->dpcm_playback)
+ if (playback)
be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
- if (rtd->dai_link->dpcm_capture)
+ if (capture)
be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
} else {
snprintf(new_name, sizeof(new_name), "%s %s-%d",
- rtd->dai_link->stream_name, codec_dai->name, num);
+ rtd->dai_link->stream_name, codec_dai->name, rtd->id);
memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
}
@@ -640,10 +651,10 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
break;
}
- ret = snd_compress_new(rtd->card->snd_card, num, direction,
+ ret = snd_compress_new(rtd->card->snd_card, rtd->id, direction,
new_name, compr);
if (ret < 0) {
- component = asoc_rtd_to_codec(rtd, 0)->component;
+ component = snd_soc_rtd_to_codec(rtd, 0)->component;
dev_err(component->dev,
"Compress ASoC: can't create compress for codec %s: %d\n",
component->name, ret);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e8308926bd98..e4b21bf39e59 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>
@@ -111,7 +112,7 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
}
static const struct attribute_group soc_dapm_dev_group = {
- .attrs = soc_dapm_dev_attrs,
+ .attrs = snd_soc_dapm_dev_attrs,
.is_visible = soc_dev_attr_is_visible,
};
@@ -150,7 +151,7 @@ static void soc_init_component_debugfs(struct snd_soc_component *component)
component->card->debugfs_card_root);
}
- snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
+ snd_soc_dapm_debugfs_init(snd_soc_component_to_dapm(component),
component->debugfs_root);
}
@@ -202,7 +203,7 @@ static void soc_init_card_debugfs(struct snd_soc_card *card)
debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root,
&card->pop_time);
- snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
+ snd_soc_dapm_debugfs_init(snd_soc_card_to_dapm(card), card->debugfs_card_root);
}
static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
@@ -238,6 +239,81 @@ static inline void snd_soc_debugfs_exit(void) { }
#endif
+static int snd_soc_is_match_dai_args(const struct of_phandle_args *args1,
+ const struct of_phandle_args *args2)
+{
+ if (!args1 || !args2)
+ return 0;
+
+ if (args1->np != args2->np)
+ return 0;
+
+ for (int i = 0; i < args1->args_count; i++)
+ if (args1->args[i] != args2->args[i])
+ return 0;
+
+ return 1;
+}
+
+static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+ return !(dlc->dai_args || dlc->name || dlc->of_node);
+}
+
+static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc)
+{
+ return (dlc->name && dlc->of_node);
+}
+
+static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+ return !(dlc->dai_args || dlc->dai_name);
+}
+
+static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
+ struct snd_soc_dai *dai)
+{
+ if (!dlc)
+ return 0;
+
+ if (dlc->dai_args)
+ return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args);
+
+ if (!dlc->dai_name)
+ return 1;
+
+ /* see snd_soc_dai_name_get() */
+
+ if (dai->driver->name &&
+ strcmp(dlc->dai_name, dai->driver->name) == 0)
+ return 1;
+
+ if (strcmp(dlc->dai_name, dai->name) == 0)
+ return 1;
+
+ if (dai->component->name &&
+ strcmp(dlc->dai_name, dai->component->name) == 0)
+ return 1;
+
+ return 0;
+}
+
+const char *snd_soc_dai_name_get(const struct snd_soc_dai *dai)
+{
+ /* see snd_soc_is_matching_dai() */
+ if (dai->driver->name)
+ return dai->driver->name;
+
+ if (dai->name)
+ return dai->name;
+
+ if (dai->component->name)
+ return dai->component->name;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_name_get);
+
static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_component *component)
{
@@ -251,8 +327,8 @@ static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
}
/* see for_each_rtd_components */
- rtd->components[rtd->num_components] = component;
- rtd->num_components++;
+ rtd->num_components++; // increment flex array count at first
+ rtd->components[rtd->num_components - 1] = component;
return 0;
}
@@ -293,20 +369,25 @@ struct snd_soc_component
*snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name)
{
struct snd_soc_component *component;
- struct snd_soc_component *found_component;
- found_component = NULL;
for_each_component(component) {
- if ((dev == component->dev) &&
- (!driver_name ||
- (driver_name == component->driver->name) ||
- (strcmp(component->driver->name, driver_name) == 0))) {
- found_component = component;
- break;
- }
+ if (dev != component->dev)
+ continue;
+
+ if (!driver_name)
+ return component;
+
+ if (!component->driver->name)
+ continue;
+
+ if (component->driver->name == driver_name)
+ return component;
+
+ if (strcmp(component->driver->name, driver_name) == 0)
+ return component;
}
- return found_component;
+ return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_lookup_component_nolocked);
@@ -345,7 +426,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
*/
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
int playback = SNDRV_PCM_STREAM_PLAYBACK;
snd_soc_dpcm_mutex_lock(rtd);
@@ -355,7 +436,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) {
@@ -419,7 +500,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_component *component;
struct device *dev;
int ret;
int stream;
@@ -446,10 +526,10 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
* for rtd
*/
rtd = devm_kzalloc(dev,
- sizeof(*rtd) +
- sizeof(component) * (dai_link->num_cpus +
- dai_link->num_codecs +
- dai_link->num_platforms),
+ struct_size(rtd, components,
+ dai_link->num_cpus +
+ dai_link->num_codecs +
+ dai_link->num_platforms),
GFP_KERNEL);
if (!rtd) {
device_unregister(dev);
@@ -465,6 +545,11 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
dev_set_drvdata(dev, rtd);
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+ if ((dai_link->num_cpus + dai_link->num_codecs) == 0) {
+ dev_err(dev, "ASoC: it has no CPU or codec DAIs\n");
+ goto free_rtd;
+ }
+
/*
* for rtd->dais
*/
@@ -479,12 +564,12 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
* ^cpu_dais ^codec_dais
* |--- num_cpus ---|--- num_codecs --|
* see
- * asoc_rtd_to_cpu()
- * asoc_rtd_to_codec()
+ * snd_soc_rtd_to_cpu()
+ * snd_soc_rtd_to_codec()
*/
rtd->card = card;
rtd->dai_link = dai_link;
- rtd->num = card->num_rtd++;
+ rtd->id = card->num_rtd++;
rtd->pmdown_time = pmdown_time; /* default power off timeout */
/* see for_each_card_rtds */
@@ -501,6 +586,28 @@ free_rtd:
return NULL;
}
+static void snd_soc_fill_dummy_dai(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *dai_link;
+ int i;
+
+ /*
+ * COMP_DUMMY() creates size 0 array on dai_link.
+ * Fill it as dummy DAI in case of CPU/Codec here.
+ * Do nothing for Platform.
+ */
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->num_cpus == 0 && dai_link->cpus) {
+ dai_link->num_cpus = 1;
+ dai_link->cpus = &snd_soc_dummy_dlc;
+ }
+ if (dai_link->num_codecs == 0 && dai_link->codecs) {
+ dai_link->num_codecs = 1;
+ dai_link->codecs = &snd_soc_dummy_dlc;
+ }
+ }
+}
+
static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
@@ -584,8 +691,8 @@ int snd_soc_suspend(struct device *dev)
soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_SUSPEND);
/* Recheck all endpoints too, their state is affected by suspend */
- dapm_mark_endpoints_dirty(card);
- snd_soc_dapm_sync(&card->dapm);
+ snd_soc_dapm_mark_endpoints_dirty(card);
+ snd_soc_dapm_sync(snd_soc_card_to_dapm(card));
/* suspend all COMPONENTs */
for_each_card_rtds(card, rtd) {
@@ -594,8 +701,7 @@ int snd_soc_suspend(struct device *dev)
continue;
for_each_rtd_components(rtd, i, component) {
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
/*
* ignore if component was already suspended
@@ -615,7 +721,7 @@ int snd_soc_suspend(struct device *dev)
* means it's doing something,
* otherwise fall through.
*/
- if (dapm->idle_bias_off) {
+ if (!snd_soc_dapm_get_idle_bias(dapm)) {
dev_dbg(component->dev,
"ASoC: idle_bias_off CODEC on over suspend\n");
break;
@@ -681,8 +787,8 @@ static void soc_resume_deferred(struct work_struct *work)
dev_dbg(card->dev, "ASoC: resume work completed\n");
/* Recheck all endpoints too, their state is affected by suspend */
- dapm_mark_endpoints_dirty(card);
- snd_soc_dapm_sync(&card->dapm);
+ snd_soc_dapm_mark_endpoints_dirty(card);
+ snd_soc_dapm_sync(snd_soc_card_to_dapm(card));
/* userspace can access us now we are back as we were before */
snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
@@ -734,6 +840,20 @@ static struct device_node
return of_node;
}
+struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL);
+
+ if (!ret)
+ return NULL;
+
+ *ret = *args;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_copy_dai_args);
+
static int snd_soc_is_matching_component(
const struct snd_soc_dai_link_component *dlc,
struct snd_soc_component *component)
@@ -743,6 +863,15 @@ static int snd_soc_is_matching_component(
if (!dlc)
return 0;
+ if (dlc->dai_args) {
+ struct snd_soc_dai *dai;
+
+ for_each_component_dais(component, dai)
+ if (snd_soc_is_matching_dai(dlc, dai))
+ return 1;
+ return 0;
+ }
+
component_of_node = soc_component_to_node(component);
if (dlc->of_node && component_of_node != dlc->of_node)
@@ -795,18 +924,11 @@ struct snd_soc_dai *snd_soc_find_dai(
lockdep_assert_held(&client_mutex);
/* Find CPU DAI from registered DAIs */
- for_each_component(component) {
- if (!snd_soc_is_matching_component(dlc, component))
- continue;
- for_each_component_dais(component, dai) {
- if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
- && (!dai->driver->name
- || strcmp(dai->driver->name, dlc->dai_name)))
- continue;
-
- return dai;
- }
- }
+ for_each_component(component)
+ if (snd_soc_is_matching_component(dlc, component))
+ for_each_component_dais(component, dai)
+ if (snd_soc_is_matching_dai(dlc, dai))
+ return dai;
return NULL;
}
@@ -829,99 +951,188 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
struct snd_soc_dai_link *link)
{
int i;
- struct snd_soc_dai_link_component *cpu, *codec, *platform;
+ struct snd_soc_dai_link_component *dlc;
- for_each_link_codecs(link, i, codec) {
+ /* Codec check */
+ for_each_link_codecs(link, i, dlc) {
/*
* Codec must be specified by 1 of name or OF node,
* not both or neither.
*/
- if (!!codec->name == !!codec->of_node) {
- dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
+
+ if (snd_soc_dlc_component_is_empty(dlc))
+ goto component_empty;
/* Codec DAI name must be specified */
- if (!codec->dai_name) {
- dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_dai_is_empty(dlc))
+ goto dai_empty;
/*
* Defer card registration if codec component is not added to
* component list.
*/
- if (!soc_find_component(codec)) {
- dev_dbg(card->dev,
- "ASoC: codec component %s not found for link %s\n",
- codec->name, link->name);
- return -EPROBE_DEFER;
- }
+ if (!soc_find_component(dlc))
+ goto component_not_found;
}
- for_each_link_platforms(link, i, platform) {
+ /* Platform check */
+ for_each_link_platforms(link, i, dlc) {
/*
* Platform may be specified by either name or OF node, but it
* can be left unspecified, then no components will be inserted
* in the rtdcom list
*/
- if (!!platform->name == !!platform->of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both platform name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
+
+ if (snd_soc_dlc_component_is_empty(dlc))
+ goto component_empty;
/*
* Defer card registration if platform component is not added to
* component list.
*/
- if (!soc_find_component(platform)) {
- dev_dbg(card->dev,
- "ASoC: platform component %s not found for link %s\n",
- platform->name, link->name);
- return -EPROBE_DEFER;
- }
+ if (!soc_find_component(dlc))
+ goto component_not_found;
}
- for_each_link_cpus(link, i, cpu) {
+ /* CPU check */
+ for_each_link_cpus(link, i, dlc) {
/*
* CPU device may be specified by either name or OF node, but
* can be left unspecified, and will be matched based on DAI
* name alone..
*/
- if (cpu->name && cpu->of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both cpu name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
- /*
- * Defer card registration if cpu dai component is not added to
- * component list.
- */
- if ((cpu->of_node || cpu->name) &&
- !soc_find_component(cpu)) {
- dev_dbg(card->dev,
- "ASoC: cpu component %s not found for link %s\n",
- cpu->name, link->name);
- return -EPROBE_DEFER;
+
+ if (snd_soc_dlc_component_is_empty(dlc)) {
+ /*
+ * At least one of CPU DAI name or CPU device name/node must be specified
+ */
+ if (snd_soc_dlc_dai_is_empty(dlc))
+ goto component_dai_empty;
+ } else {
+ /*
+ * Defer card registration if Component is not added
+ */
+ if (!soc_find_component(dlc))
+ goto component_not_found;
}
+ }
- /*
- * At least one of CPU DAI name or CPU device name/node must be
- * specified
- */
- if (!cpu->dai_name &&
- !(cpu->name || cpu->of_node)) {
+ return 0;
+
+component_invalid:
+ dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+
+component_empty:
+ dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+
+component_not_found:
+ dev_dbg(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
+ return -EPROBE_DEFER;
+
+dai_empty:
+ dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name);
+ return -EINVAL;
+
+component_dai_empty:
+ dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+}
+
+#define MAX_DEFAULT_CH_MAP_SIZE 8
+static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] = {
+ { .cpu = 0, .codec = 0 },
+ { .cpu = 1, .codec = 1 },
+ { .cpu = 2, .codec = 2 },
+ { .cpu = 3, .codec = 3 },
+ { .cpu = 4, .codec = 4 },
+ { .cpu = 5, .codec = 5 },
+ { .cpu = 6, .codec = 6 },
+ { .cpu = 7, .codec = 7 },
+};
+static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] = {
+ { .cpu = 0, .codec = 0 },
+ { .cpu = 0, .codec = 1 },
+ { .cpu = 0, .codec = 2 },
+ { .cpu = 0, .codec = 3 },
+ { .cpu = 0, .codec = 4 },
+ { .cpu = 0, .codec = 5 },
+ { .cpu = 0, .codec = 6 },
+ { .cpu = 0, .codec = 7 },
+};
+static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] = {
+ { .cpu = 0, .codec = 0 },
+ { .cpu = 1, .codec = 0 },
+ { .cpu = 2, .codec = 0 },
+ { .cpu = 3, .codec = 0 },
+ { .cpu = 4, .codec = 0 },
+ { .cpu = 5, .codec = 0 },
+ { .cpu = 6, .codec = 0 },
+ { .cpu = 7, .codec = 0 },
+};
+static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct snd_soc_dai_link_ch_map *ch_maps;
+ int i;
+
+ /*
+ * dai_link->ch_maps indicates how CPU/Codec are connected.
+ * It will be a map seen from a larger number of DAI.
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
+ */
+
+ /* it should have ch_maps if connection was N:M */
+ if (dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
+ dai_link->num_cpus != dai_link->num_codecs && !dai_link->ch_maps) {
+ dev_err(card->dev, "need to have ch_maps when N:M connection (%s)",
+ dai_link->name);
+ return -EINVAL;
+ }
+
+ /* do nothing if it has own maps */
+ if (dai_link->ch_maps)
+ goto sanity_check;
+
+ /* check default map size */
+ if (dai_link->num_cpus > MAX_DEFAULT_CH_MAP_SIZE ||
+ dai_link->num_codecs > MAX_DEFAULT_CH_MAP_SIZE) {
+ dev_err(card->dev, "soc-core.c needs update default_connection_maps");
+ return -EINVAL;
+ }
+
+ /* Compensate missing map for ... */
+ if (dai_link->num_cpus == dai_link->num_codecs)
+ dai_link->ch_maps = default_ch_map_sync; /* for 1:1 or N:N */
+ else if (dai_link->num_cpus < dai_link->num_codecs)
+ dai_link->ch_maps = default_ch_map_1cpu; /* for 1:N */
+ else
+ dai_link->ch_maps = default_ch_map_1codec; /* for N:1 */
+
+sanity_check:
+ dev_dbg(card->dev, "dai_link %s\n", dai_link->stream_name);
+ for_each_link_ch_maps(dai_link, i, ch_maps) {
+ if ((ch_maps->cpu >= dai_link->num_cpus) ||
+ (ch_maps->codec >= dai_link->num_codecs)) {
dev_err(card->dev,
- "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
- link->name);
+ "unexpected dai_link->ch_maps[%d] index (cpu(%d/%d) codec(%d/%d))",
+ i,
+ ch_maps->cpu, dai_link->num_cpus,
+ ch_maps->codec, dai_link->num_codecs);
return -EINVAL;
}
+
+ dev_dbg(card->dev, " [%d] cpu%d <-> codec%d\n",
+ i, ch_maps->cpu, ch_maps->codec);
}
return 0;
@@ -937,6 +1148,9 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd)
{
+ if (!rtd)
+ return;
+
lockdep_assert_held(&client_mutex);
/*
@@ -965,7 +1179,7 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai_link_component *codec, *platform, *cpu;
struct snd_soc_component *component;
- int i, ret;
+ int i, id, ret;
lockdep_assert_held(&client_mutex);
@@ -990,25 +1204,25 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
return -ENOMEM;
for_each_link_cpus(dai_link, i, cpu) {
- asoc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu);
- if (!asoc_rtd_to_cpu(rtd, i)) {
+ snd_soc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu);
+ if (!snd_soc_rtd_to_cpu(rtd, i)) {
dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
cpu->dai_name);
goto _err_defer;
}
- snd_soc_rtd_add_component(rtd, asoc_rtd_to_cpu(rtd, i)->component);
+ snd_soc_rtd_add_component(rtd, snd_soc_rtd_to_cpu(rtd, i)->component);
}
/* Find CODEC from registered CODECs */
for_each_link_codecs(dai_link, i, codec) {
- asoc_rtd_to_codec(rtd, i) = snd_soc_find_dai(codec);
- if (!asoc_rtd_to_codec(rtd, i)) {
+ snd_soc_rtd_to_codec(rtd, i) = snd_soc_find_dai(codec);
+ if (!snd_soc_rtd_to_codec(rtd, i)) {
dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
codec->dai_name);
goto _err_defer;
}
- snd_soc_rtd_add_component(rtd, asoc_rtd_to_codec(rtd, i)->component);
+ snd_soc_rtd_add_component(rtd, snd_soc_rtd_to_codec(rtd, i)->component);
}
/* Find PLATFORM from registered PLATFORMs */
@@ -1017,10 +1231,35 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
if (!snd_soc_is_matching_component(platform, component))
continue;
+ if (snd_soc_component_is_dummy(component) && component->num_dai)
+ continue;
+
snd_soc_rtd_add_component(rtd, component);
}
}
+ /*
+ * Most drivers will register their PCMs using DAI link ordering but
+ * topology based drivers can use the DAI link id field to set PCM
+ * device number and then use rtd + a base offset of the BEs.
+ *
+ * FIXME
+ *
+ * This should be implemented by using "dai_link" feature instead of
+ * "component" feature.
+ */
+ id = rtd->id;
+ for_each_rtd_components(rtd, i, component) {
+ if (!component->driver->use_dai_pcm_id)
+ continue;
+
+ if (rtd->dai_link->no_pcm)
+ id += component->driver->be_pcm_base;
+ else
+ id = rtd->dai_link->id;
+ }
+ rtd->id = id;
+
return 0;
_err_defer:
@@ -1033,8 +1272,13 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
int num_dai_link)
{
for (int i = 0; i < num_dai_link; i++) {
- int ret = snd_soc_add_pcm_runtime(card, dai_link + i);
+ int ret;
+ ret = snd_soc_compensate_channel_connection_map(card, dai_link + i);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_add_pcm_runtime(card, dai_link + i);
if (ret < 0)
return ret;
}
@@ -1118,7 +1362,7 @@ found:
*
* To avoid such issue, loop from 63 to 0 here.
* Small number of SND_SOC_POSSIBLE_xxx will be Hi priority.
- * Basic/Default settings of each part and aboves are defined
+ * Basic/Default settings of each part and above are defined
* as Hi priority (= small number) of SND_SOC_POSSIBLE_xxx.
*/
for (i = 63; i >= 0; i--) {
@@ -1218,23 +1462,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;
}
@@ -1247,9 +1514,8 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_component *component;
- int ret, num, i;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ int ret;
/* do machine specific initialization */
ret = snd_soc_link_init(rtd);
@@ -1259,42 +1525,34 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
snd_soc_runtime_get_dai_fmt(rtd);
ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
if (ret)
- return ret;
+ goto err;
/* add DPCM sysfs entries */
soc_dpcm_debugfs_add(rtd);
- num = rtd->num;
-
- /*
- * most drivers will register their PCMs using DAI link ordering but
- * topology based drivers can use the DAI link id field to set PCM
- * device number and then use rtd + a base offset of the BEs.
- */
- for_each_rtd_components(rtd, i, component) {
- if (!component->driver->use_dai_pcm_id)
- continue;
-
- if (rtd->dai_link->no_pcm)
- num += component->driver->be_pcm_base;
- else
- num = rtd->dai_link->id;
- }
-
/* create compress_device if possible */
- ret = snd_soc_dai_compress_new(cpu_dai, rtd, num);
+ ret = snd_soc_dai_compress_new(cpu_dai, rtd);
if (ret != -ENOTSUPP)
- return ret;
+ goto err;
/* create the pcm */
- ret = soc_new_pcm(rtd, num);
+ ret = soc_new_pcm(rtd);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
dai_link->stream_name, ret);
- return ret;
+ goto err;
}
- return snd_soc_pcm_dai_new(rtd);
+ ret = snd_soc_pcm_dai_new(rtd);
+ if (ret < 0)
+ goto err;
+
+ rtd->initialized = true;
+
+ return 0;
+err:
+ snd_soc_link_exit(rtd);
+ return ret;
}
static void soc_set_name_prefix(struct snd_soc_card *card,
@@ -1336,7 +1594,7 @@ static void soc_remove_component(struct snd_soc_component *component,
snd_soc_component_remove(component);
list_del_init(&component->card_list);
- snd_soc_dapm_free(snd_soc_component_get_dapm(component));
+ snd_soc_dapm_free(snd_soc_component_to_dapm(component));
soc_cleanup_component_debugfs(component);
component->card = NULL;
snd_soc_component_module_put_when_remove(component);
@@ -1345,8 +1603,7 @@ static void soc_remove_component(struct snd_soc_component *component,
static int soc_probe_component(struct snd_soc_card *card,
struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct snd_soc_dai *dai;
int probed = 0;
int ret;
@@ -1357,8 +1614,8 @@ static int soc_probe_component(struct snd_soc_card *card,
if (component->card) {
if (component->card != card) {
dev_err(component->dev,
- "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
- card->name, component->card->name);
+ "Trying to bind component \"%s\" to card \"%s\" but is already bound to card \"%s\"\n",
+ component->name, card->name, component->card->name);
return -ENODEV;
}
return 0;
@@ -1398,8 +1655,8 @@ static int soc_probe_component(struct snd_soc_card *card,
if (ret < 0)
goto err_probe;
- WARN(dapm->idle_bias_off &&
- dapm->bias_level != SND_SOC_BIAS_OFF,
+ WARN(!snd_soc_dapm_get_idle_bias(dapm) &&
+ snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_OFF,
"codec %s can not start from non-off bias with idle_bias_off==1\n",
component->name);
probed = 1;
@@ -1422,18 +1679,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);
@@ -1652,10 +1899,9 @@ 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 ususally
+ * difficult for userspace to differentiate, since machine drivers usually
* use their own name as the card short name and leave the card long name
* blank. To differentiate such devices and fix bugs due to lack of
* device-specific configurations, this function allows DMI info to be used
@@ -1676,11 +1922,11 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str)
* We only keep number and alphabet characters and a few separator characters
* in the card long name since UCM in the user space uses the card long names
* as card configuration directory names and AudoConf cannot support special
- * charactors like SPACE.
+ * characters like SPACE.
*
* 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;
@@ -1724,16 +1970,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)
@@ -1781,25 +2027,7 @@ match:
dai_link->platforms->name = component->name;
/* convert non BE into BE */
- if (!dai_link->no_pcm) {
- dai_link->no_pcm = 1;
-
- if (dai_link->dpcm_playback)
- dev_warn(card->dev,
- "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_playback=1\n",
- dai_link->name);
- if (dai_link->dpcm_capture)
- dev_warn(card->dev,
- "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_capture=1\n",
- dai_link->name);
-
- /* convert normal link into DPCM one */
- if (!(dai_link->dpcm_playback ||
- dai_link->dpcm_capture)) {
- dai_link->dpcm_playback = !dai_link->capture_only;
- dai_link->dpcm_capture = !dai_link->playback_only;
- }
- }
+ dai_link->no_pcm = 1;
/*
* override any BE fixups
@@ -1892,7 +2120,8 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
/* release machine specific resources */
for_each_card_rtds(card, rtd)
- snd_soc_link_exit(rtd);
+ if (rtd->initialized)
+ snd_soc_link_exit(rtd);
/* remove and free each DAI */
soc_remove_link_dais(card);
soc_remove_link_components(card);
@@ -1904,7 +2133,7 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
soc_remove_aux_devices(card);
soc_unbind_aux_dev(card);
- snd_soc_dapm_free(&card->dapm);
+ snd_soc_dapm_free(snd_soc_card_to_dapm(card));
soc_cleanup_card_debugfs(card);
/* remove the card */
@@ -1916,18 +2145,13 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
}
}
-static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
+static void snd_soc_unbind_card(struct snd_soc_card *card)
{
if (snd_soc_card_is_instantiated(card)) {
card->instantiated = false;
snd_soc_flush_all_delayed_work(card);
soc_cleanup_card_resources(card);
- if (!unregister)
- list_add(&card->list, &unbind_card_list);
- } else {
- if (unregister)
- list_del(&card->list);
}
}
@@ -1935,12 +2159,13 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *component;
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
int ret;
- mutex_lock(&client_mutex);
snd_soc_card_mutex_lock_root(card);
+ snd_soc_fill_dummy_dai(card);
- snd_soc_dapm_init(&card->dapm, card, NULL);
+ snd_soc_dapm_init(dapm, card, NULL);
/* check whether any platform is ignore machine FE and using topology */
soc_check_tplg_fes(card);
@@ -1970,12 +2195,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
soc_resume_init(card);
- ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, card->dapm_widgets,
card->num_dapm_widgets);
if (ret < 0)
goto probe_end;
- ret = snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
+ ret = snd_soc_dapm_new_controls(dapm, card->of_dapm_widgets,
card->num_of_dapm_widgets);
if (ret < 0)
goto probe_end;
@@ -1988,8 +2213,10 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
/* probe all components used by DAI links on this card */
ret = soc_probe_link_components(card);
if (ret < 0) {
- dev_err(card->dev,
- "ASoC: failed to instantiate card %d\n", ret);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(card->dev,
+ "ASoC: failed to instantiate card %d\n", ret);
+ }
goto probe_end;
}
@@ -2023,28 +2250,18 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
if (ret < 0)
goto probe_end;
- ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
+ ret = snd_soc_dapm_add_routes(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,
+ ret = snd_soc_dapm_add_routes(dapm, card->of_dapm_routes,
card->num_of_dapm_routes);
if (ret < 0)
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);
@@ -2081,8 +2298,8 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
}
card->instantiated = 1;
- dapm_mark_endpoints_dirty(card);
- snd_soc_dapm_sync(&card->dapm);
+ snd_soc_dapm_mark_endpoints_dirty(card);
+ snd_soc_dapm_sync(dapm);
/* deactivate pins to sleep state */
for_each_card_components(card, component)
@@ -2092,9 +2309,49 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
probe_end:
if (ret < 0)
soc_cleanup_card_resources(card);
-
snd_soc_card_mutex_unlock(card);
- mutex_unlock(&client_mutex);
+
+ return ret;
+}
+
+static void devm_card_bind_release(struct device *dev, void *res)
+{
+ snd_soc_unregister_card(*(struct snd_soc_card **)res);
+}
+
+static int devm_snd_soc_bind_card(struct device *dev, struct snd_soc_card *card)
+{
+ struct snd_soc_card **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_card_bind_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = snd_soc_bind_card(card);
+ if (ret == 0 || ret == -EPROBE_DEFER) {
+ *ptr = card;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return ret;
+}
+
+static int snd_soc_rebind_card(struct snd_soc_card *card)
+{
+ int ret;
+
+ if (card->devres_dev) {
+ devres_destroy(card->devres_dev, devm_card_bind_release, NULL, NULL);
+ ret = devm_snd_soc_bind_card(card->devres_dev, card);
+ } else {
+ ret = snd_soc_bind_card(card);
+ }
+
+ if (ret != -EPROBE_DEFER)
+ list_del_init(&card->list);
return ret;
}
@@ -2268,7 +2525,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
/**
* snd_soc_add_dai_controls - add an array of controls to a DAI.
- * Convienience function to add a list of controls.
+ * Convenience function to add a list of controls.
*
* @dai: DAI to add controls to
* @controls: array of controls to add
@@ -2294,6 +2551,8 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
*/
int snd_soc_register_card(struct snd_soc_card *card)
{
+ int ret;
+
if (!card->name || !card->dev)
return -EINVAL;
@@ -2314,7 +2573,21 @@ int snd_soc_register_card(struct snd_soc_card *card)
mutex_init(&card->dapm_mutex);
mutex_init(&card->pcm_mutex);
- return snd_soc_bind_card(card);
+ mutex_lock(&client_mutex);
+
+ if (card->devres_dev) {
+ ret = devm_snd_soc_bind_card(card->devres_dev, card);
+ if (ret == -EPROBE_DEFER) {
+ list_add(&card->list, &unbind_card_list);
+ ret = 0;
+ }
+ } else {
+ ret = snd_soc_bind_card(card);
+ }
+
+ mutex_unlock(&client_mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_card);
@@ -2327,7 +2600,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
void snd_soc_unregister_card(struct snd_soc_card *card)
{
mutex_lock(&client_mutex);
- snd_soc_unbind_card(card, true);
+ snd_soc_unbind_card(card);
+ list_del(&card->list);
mutex_unlock(&client_mutex);
dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
}
@@ -2342,6 +2616,7 @@ static char *fmt_single_name(struct device *dev, int *id)
const char *devname = dev_name(dev);
char *found, *name;
unsigned int id1, id2;
+ int __id;
if (devname == NULL)
return NULL;
@@ -2354,10 +2629,10 @@ static char *fmt_single_name(struct device *dev, int *id)
found = strstr(name, dev->driver->name);
if (found) {
/* get ID */
- if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
+ if (sscanf(&found[strlen(dev->driver->name)], ".%d", &__id) == 1) {
/* discard ID from name if ID == -1 */
- if (*id == -1)
+ if (__id == -1)
found[strlen(dev->driver->name)] = '\0';
}
@@ -2365,16 +2640,19 @@ static char *fmt_single_name(struct device *dev, int *id)
} else if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
/* create unique ID number from I2C addr and bus */
- *id = ((id1 & 0xffff) << 16) + id2;
+ __id = ((id1 & 0xffff) << 16) + id2;
devm_kfree(dev, name);
/* sanitize component name for DAI link creation */
name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", dev->driver->name, devname);
} else {
- *id = 0;
+ __id = 0;
}
+ if (id)
+ *id = __id;
+
return name;
}
@@ -2541,23 +2819,19 @@ static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
stream->formats |= endianness_format_map[i];
}
-static void snd_soc_try_rebind_card(void)
-{
- struct snd_soc_card *card, *c;
-
- list_for_each_entry_safe(card, c, &unbind_card_list, list)
- if (!snd_soc_bind_card(card))
- list_del(&card->list);
-}
-
static void snd_soc_del_component_unlocked(struct snd_soc_component *component)
{
struct snd_soc_card *card = component->card;
+ bool instantiated;
snd_soc_unregister_dais(component);
- if (card)
- snd_soc_unbind_card(card, false);
+ if (card) {
+ instantiated = card->instantiated;
+ snd_soc_unbind_card(card);
+ if (instantiated)
+ list_add(&card->list, &unbind_card_list);
+ }
list_del(&component->list);
}
@@ -2572,10 +2846,12 @@ int snd_soc_component_initialize(struct snd_soc_component *component,
INIT_LIST_HEAD(&component->list);
mutex_init(&component->io_mutex);
- component->name = fmt_single_name(dev, &component->id);
if (!component->name) {
- dev_err(dev, "ASoC: Failed to allocate name\n");
- return -ENOMEM;
+ component->name = fmt_single_name(dev, NULL);
+ if (!component->name) {
+ dev_err(dev, "ASoC: Failed to allocate name\n");
+ return -ENOMEM;
+ }
}
component->dev = dev;
@@ -2594,6 +2870,7 @@ int snd_soc_add_component(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
+ struct snd_soc_card *card, *c;
int ret;
int i;
@@ -2624,15 +2901,14 @@ int snd_soc_add_component(struct snd_soc_component *component,
/* see for_each_component */
list_add(&component->list, &component_list);
+ list_for_each_entry_safe(card, c, &unbind_card_list, list)
+ snd_soc_rebind_card(card);
+
err_cleanup:
if (ret < 0)
snd_soc_del_component_unlocked(component);
mutex_unlock(&client_mutex);
-
- if (ret == 0)
- snd_soc_try_rebind_card();
-
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_add_component);
@@ -2667,34 +2943,14 @@ EXPORT_SYMBOL_GPL(snd_soc_register_component);
void snd_soc_unregister_component_by_driver(struct device *dev,
const struct snd_soc_component_driver *component_driver)
{
- struct snd_soc_component *component;
-
- if (!component_driver)
- return;
+ const char *driver_name = NULL;
- mutex_lock(&client_mutex);
- component = snd_soc_lookup_component_nolocked(dev, component_driver->name);
- if (!component)
- goto out;
+ if (component_driver)
+ driver_name = component_driver->name;
- snd_soc_del_component_unlocked(component);
-
-out:
- mutex_unlock(&client_mutex);
-}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_component_by_driver);
-
-/**
- * snd_soc_unregister_component - Unregister all related component
- * from the ASoC core
- *
- * @dev: The device to unregister
- */
-void snd_soc_unregister_component(struct device *dev)
-{
mutex_lock(&client_mutex);
while (1) {
- struct snd_soc_component *component = snd_soc_lookup_component_nolocked(dev, NULL);
+ struct snd_soc_component *component = snd_soc_lookup_component_nolocked(dev, driver_name);
if (!component)
break;
@@ -2703,7 +2959,7 @@ void snd_soc_unregister_component(struct device *dev)
}
mutex_unlock(&client_mutex);
}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component_by_driver);
/* Retrieve a card's name from device tree */
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
@@ -2832,7 +3088,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,
@@ -2906,28 +3162,30 @@ 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;
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
+void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
+ struct snd_soc_dai_link_component *cpus)
+{
+ platforms->of_node = cpus->of_node;
+ platforms->dai_args = cpus->dai_args;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform);
+
void snd_soc_of_parse_node_prefix(struct device_node *np,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
@@ -3138,10 +3396,10 @@ unsigned int snd_soc_daifmt_parse_format(struct device_node *np,
* SND_SOC_DAIFMT_INV_MASK area
*/
snprintf(prop, sizeof(prop), "%sbitclock-inversion", prefix);
- bit = !!of_get_property(np, prop, NULL);
+ bit = of_property_read_bool(np, prop);
snprintf(prop, sizeof(prop), "%sframe-inversion", prefix);
- frame = !!of_get_property(np, prop, NULL);
+ frame = of_property_read_bool(np, prop);
switch ((bit << 4) + frame) {
case 0x11:
@@ -3170,6 +3428,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 = "";
@@ -3178,12 +3439,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_get_property(np, prop, NULL);
+ 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_get_property(np, prop, NULL);
+ frame = of_property_present(np, prop);
if (frame && framemaster)
*framemaster = of_parse_phandle(np, prop, 0);
@@ -3196,7 +3457,7 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_daifmt_parse_clock_provider_raw);
-int snd_soc_get_stream_cpu(struct snd_soc_dai_link *dai_link, int stream)
+int snd_soc_get_stream_cpu(const struct snd_soc_dai_link *dai_link, int stream)
{
/*
* [Normal]
@@ -3233,11 +3494,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu);
int snd_soc_get_dai_id(struct device_node *ep)
{
struct snd_soc_component *component;
- struct snd_soc_dai_link_component dlc;
+ struct snd_soc_dai_link_component dlc = {
+ .of_node = of_graph_get_port_parent(ep),
+ };
int ret;
- dlc.of_node = of_graph_get_port_parent(ep);
- dlc.name = NULL;
+
/*
* For example HDMI case, HDMI has video/sound port,
* but ALSA SoC needs sound port number only.
@@ -3257,8 +3519,7 @@ int snd_soc_get_dai_id(struct device_node *ep)
}
EXPORT_SYMBOL_GPL(snd_soc_get_dai_id);
-int snd_soc_get_dai_name(const struct of_phandle_args *args,
- const char **dai_name)
+int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_component *dlc)
{
struct snd_soc_component *pos;
int ret = -EPROBE_DEFER;
@@ -3270,7 +3531,7 @@ int snd_soc_get_dai_name(const struct of_phandle_args *args,
if (component_of_node != args->np || !pos->num_dai)
continue;
- ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name);
+ ret = snd_soc_component_of_xlate_dai_name(pos, args, &dlc->dai_name);
if (ret == -ENOTSUPP) {
struct snd_soc_dai *dai;
int id = -1;
@@ -3301,9 +3562,7 @@ int snd_soc_get_dai_name(const struct of_phandle_args *args,
id--;
}
- *dai_name = dai->driver->name;
- if (!*dai_name)
- *dai_name = pos->name;
+ dlc->dai_name = snd_soc_dai_name_get(dai);
} else if (ret) {
/*
* if another error than ENOTSUPP is returned go on and
@@ -3316,30 +3575,79 @@ int snd_soc_get_dai_name(const struct of_phandle_args *args,
break;
}
+
+ if (ret == 0)
+ dlc->of_node = args->np;
+
mutex_unlock(&client_mutex);
return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
+EXPORT_SYMBOL_GPL(snd_soc_get_dlc);
-int snd_soc_of_get_dai_name(struct device_node *of_node,
- const char **dai_name)
+int snd_soc_of_get_dlc(struct device_node *of_node,
+ struct of_phandle_args *args,
+ struct snd_soc_dai_link_component *dlc,
+ int index)
{
- struct of_phandle_args args;
+ struct of_phandle_args __args;
int ret;
+ if (!args)
+ args = &__args;
+
ret = of_parse_phandle_with_args(of_node, "sound-dai",
- "#sound-dai-cells", 0, &args);
+ "#sound-dai-cells", index, args);
if (ret)
return ret;
- ret = snd_soc_get_dai_name(&args, dai_name);
+ return snd_soc_get_dlc(args, dlc);
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_get_dlc);
+
+int snd_soc_get_dai_name(const struct of_phandle_args *args,
+ const char **dai_name)
+{
+ struct snd_soc_dai_link_component dlc;
+ int ret = snd_soc_get_dlc(args, &dlc);
- of_node_put(args.np);
+ if (ret == 0)
+ *dai_name = dlc.dai_name;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
+
+int snd_soc_of_get_dai_name(struct device_node *of_node,
+ const char **dai_name, int index)
+{
+ struct snd_soc_dai_link_component dlc;
+ int ret = snd_soc_of_get_dlc(of_node, NULL, &dlc, index);
+
+ if (ret == 0)
+ *dai_name = dlc.dai_name;
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
+struct snd_soc_dai *snd_soc_get_dai_via_args(const struct of_phandle_args *dai_args)
+{
+ struct snd_soc_dai *dai;
+ struct snd_soc_component *component;
+
+ mutex_lock(&client_mutex);
+ for_each_component(component) {
+ for_each_component_dais(component, dai)
+ if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args))
+ goto found;
+ }
+ dai = NULL;
+found:
+ mutex_unlock(&client_mutex);
+ return dai;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args);
+
static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
{
if (component->of_node) {
@@ -3375,26 +3683,6 @@ static int __snd_soc_of_get_dai_link_component_alloc(
return 0;
}
-static int __snd_soc_of_get_dai_link_component_parse(
- struct device_node *of_node,
- struct snd_soc_dai_link_component *component, int index)
-{
- struct of_phandle_args args;
- int ret;
-
- ret = of_parse_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells",
- index, &args);
- if (ret)
- return ret;
-
- ret = snd_soc_get_dai_name(&args, &component->dai_name);
- if (ret < 0)
- return ret;
-
- component->of_node = args.np;
- return 0;
-}
-
/*
* snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
* @dai_link: DAI link
@@ -3439,7 +3727,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
/* Parse the list */
for_each_link_codecs(dai_link, index, component) {
- ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index);
+ ret = snd_soc_of_get_dlc(of_node, NULL, component, index);
if (ret)
goto err;
}
@@ -3494,7 +3782,7 @@ int snd_soc_of_get_dai_link_cpus(struct device *dev,
/* Parse the list */
for_each_link_cpus(dai_link, index, component) {
- ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index);
+ ret = snd_soc_of_get_dlc(of_node, NULL, component, index);
if (ret)
goto err;
}
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 02dd64dea179..a1e05307067d 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -11,25 +11,11 @@
#include <sound/soc-link.h>
#define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
-static inline int _soc_dai_ret(struct snd_soc_dai *dai,
+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);
}
/*
@@ -37,7 +23,7 @@ static inline int _soc_dai_ret(struct snd_soc_dai *dai,
* In such case, we can update these macros.
*/
#define soc_dai_mark_push(dai, substream, tgt) ((dai)->mark_##tgt = substream)
-#define soc_dai_mark_pop(dai, substream, tgt) ((dai)->mark_##tgt = NULL)
+#define soc_dai_mark_pop(dai, tgt) ((dai)->mark_##tgt = NULL)
#define soc_dai_mark_match(dai, substream, tgt) ((dai)->mark_##tgt == substream)
/**
@@ -45,7 +31,7 @@ static inline int _soc_dai_ret(struct snd_soc_dai *dai,
* @dai: DAI
* @clk_id: DAI specific clock ID
* @freq: new clock frequency in Hz
- * @dir: new clock direction - input/output.
+ * @dir: new clock direction (SND_SOC_CLOCK_IN or SND_SOC_CLOCK_OUT)
*
* Configures the DAI master (MCLK) or system (SYSCLK) clocking.
*/
@@ -134,7 +120,7 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
-int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
+int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *dai;
int i, max = 0;
@@ -166,7 +152,7 @@ int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
* modes. This will mean that sometimes fewer formats
* are reported here than are supported by set_fmt().
*/
-u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
+u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority)
{
const struct snd_soc_dai_ops *ops = dai->driver->ops;
u64 fmt = 0;
@@ -191,8 +177,9 @@ u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
if (max < until)
until = max;
- for (i = 0; i < until; i++)
- fmt |= ops->auto_selectable_formats[i];
+ if (ops && ops->auto_selectable_formats)
+ for (i = 0; i < until; i++)
+ fmt |= ops->auto_selectable_formats[i];
return fmt;
}
@@ -273,12 +260,15 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
&rx_mask,
};
- if (dai->driver->ops &&
- dai->driver->ops->xlate_tdm_slot_mask)
- dai->driver->ops->xlate_tdm_slot_mask(slots,
- &tx_mask, &rx_mask);
- else
- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ if (slots) {
+ if (dai->driver->ops &&
+ dai->driver->ops->xlate_tdm_slot_mask)
+ ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ else
+ 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 +277,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);
@@ -304,8 +295,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
* configure the relationship between channel number and TDM slot number.
*/
int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
- unsigned int tx_num, unsigned int *tx_slot,
- unsigned int rx_num, unsigned int *rx_slot)
+ unsigned int tx_num, const unsigned int *tx_slot,
+ unsigned int rx_num, const unsigned int *rx_slot)
{
int ret = -ENOTSUPP;
@@ -327,7 +318,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
* @rx_slot: pointer to an array which imply the RX slot number channel
* 0~num-1 uses
*/
-int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+int snd_soc_dai_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)
{
@@ -360,6 +351,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
@@ -416,7 +431,7 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
dai->driver->ops->hw_free(substream, dai);
/* remove marked substream */
- soc_dai_mark_pop(dai, substream, hw_params);
+ soc_dai_mark_pop(dai, hw_params);
}
int snd_soc_dai_startup(struct snd_soc_dai *dai,
@@ -424,6 +439,9 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
{
int ret = 0;
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return 0;
+
if (dai->driver->ops &&
dai->driver->ops->startup)
ret = dai->driver->ops->startup(substream, dai);
@@ -439,6 +457,9 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream,
int rollback)
{
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return;
+
if (rollback && !soc_dai_mark_match(dai, substream, startup))
return;
@@ -447,15 +468,16 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
dai->driver->ops->shutdown(substream, dai);
/* remove marked substream */
- soc_dai_mark_pop(dai, substream, startup);
+ soc_dai_mark_pop(dai, startup);
}
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
- struct snd_soc_pcm_runtime *rtd, int num)
+ struct snd_soc_pcm_runtime *rtd)
{
int ret = -ENOTSUPP;
- if (dai->driver->compress_new)
- ret = dai->driver->compress_new(rtd, num);
+ if (dai->driver->ops &&
+ dai->driver->ops->compress_new)
+ ret = dai->driver->ops->compress_new(rtd);
return soc_dai_ret(dai, ret);
}
@@ -464,52 +486,14 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
*
* Returns true if the DAI supports the indicated stream type.
*/
-bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
+bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir)
{
- struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
+ const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
/* If the codec specifies any channels at all, it supports the stream */
return stream->channels_min;
}
-/*
- * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
- */
-void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
-{
- bool supported[SNDRV_PCM_STREAM_LAST + 1];
- int direction;
-
- for_each_pcm_streams(direction) {
- struct snd_soc_dai_link_component *cpu;
- struct snd_soc_dai_link_component *codec;
- struct snd_soc_dai *dai;
- bool supported_cpu = false;
- bool supported_codec = false;
- int i;
-
- for_each_link_cpus(dai_link, i, cpu) {
- dai = snd_soc_find_dai_with_mutex(cpu);
- if (dai && snd_soc_dai_stream_valid(dai, direction)) {
- supported_cpu = true;
- break;
- }
- }
- for_each_link_codecs(dai_link, i, codec) {
- dai = snd_soc_find_dai_with_mutex(codec);
- if (dai && snd_soc_dai_stream_valid(dai, direction)) {
- supported_codec = true;
- break;
- }
- }
- supported[direction] = supported_cpu && supported_codec;
- }
-
- dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
- dai_link->dpcm_capture = supported[SNDRV_PCM_STREAM_CAPTURE];
-}
-EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
-
void snd_soc_dai_action(struct snd_soc_dai *dai,
int stream, int action)
{
@@ -521,7 +505,7 @@ void snd_soc_dai_action(struct snd_soc_dai *dai,
}
EXPORT_SYMBOL_GPL(snd_soc_dai_action);
-int snd_soc_dai_active(struct snd_soc_dai *dai)
+int snd_soc_dai_active(const struct snd_soc_dai *dai)
{
int stream, active;
@@ -539,19 +523,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
int i;
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->probe_order != order)
- continue;
-
if (dai->probed)
continue;
- if (dai->driver->probe) {
- int ret = dai->driver->probe(dai);
+ if (dai->driver->ops) {
+ if (dai->driver->ops->probe_order != order)
+ continue;
- if (ret < 0)
- return soc_dai_ret(dai, ret);
- }
+ if (dai->driver->ops->probe) {
+ int ret = dai->driver->ops->probe(dai);
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+ }
dai->probed = 1;
}
@@ -564,16 +549,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
int i, r, ret = 0;
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->remove_order != order)
+ if (!dai->probed)
continue;
- if (dai->probed &&
- dai->driver->remove) {
- r = dai->driver->remove(dai);
- if (r < 0)
- ret = r; /* use last error */
- }
+ if (dai->driver->ops) {
+ if (dai->driver->ops->remove_order != order)
+ continue;
+ if (dai->driver->ops->remove) {
+ r = dai->driver->ops->remove(dai);
+ if (r < 0)
+ ret = r; /* use last error */
+ }
+ }
dai->probed = 0;
}
@@ -586,8 +574,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
int i;
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->pcm_new) {
- int ret = dai->driver->pcm_new(rtd, dai);
+ if (dai->driver->ops &&
+ dai->driver->ops->pcm_new) {
+ int ret = dai->driver->ops->pcm_new(rtd, dai);
if (ret < 0)
return soc_dai_ret(dai, ret);
}
@@ -598,17 +587,14 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *dai;
int i, ret;
for_each_rtd_dais(rtd, i, dai) {
- 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;
@@ -619,6 +605,9 @@ static int soc_dai_trigger(struct snd_soc_dai *dai,
{
int ret = 0;
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return 0;
+
if (dai->driver->ops &&
dai->driver->ops->trigger)
ret = dai->driver->ops->trigger(substream, cmd, dai);
@@ -629,7 +618,7 @@ static int soc_dai_trigger(struct snd_soc_dai *dai,
int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
int cmd, int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *dai;
int i, r, ret = 0;
@@ -641,6 +630,10 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
ret = soc_dai_trigger(dai, substream, cmd);
if (ret < 0)
break;
+
+ 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);
}
break;
@@ -651,41 +644,24 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
if (rollback && !soc_dai_mark_match(dai, substream, trigger))
continue;
+ 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);
if (r < 0)
ret = r; /* use last ret */
- soc_dai_mark_pop(dai, substream, trigger);
+ soc_dai_mark_pop(dai, trigger);
}
}
return ret;
}
-int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
- int cmd)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *dai;
- int i, ret;
-
- for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->ops &&
- dai->driver->ops->bespoke_trigger) {
- ret = dai->driver->ops->bespoke_trigger(substream,
- cmd, dai);
- if (ret < 0)
- return soc_dai_ret(dai, ret);
- }
- }
-
- return 0;
-}
-
void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
snd_pcm_sframes_t *cpu_delay,
snd_pcm_sframes_t *codec_delay)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *dai;
int i;
@@ -738,7 +714,7 @@ void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
dai->driver->cops->shutdown(cstream, dai);
/* remove marked cstream */
- soc_dai_mark_pop(dai, cstream, compr_startup);
+ soc_dai_mark_pop(dai, compr_startup);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
@@ -799,7 +775,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
int ret = 0;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 3091e8160bad..4d920a59da3c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/async.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/bitops.h>
@@ -48,22 +49,6 @@
for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
(dir)++)
-static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
- const char *control,
- int (*connected)(struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink));
-
-struct snd_soc_dapm_widget *
-snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_widget *widget);
-
-struct snd_soc_dapm_widget *
-snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_widget *widget);
-
-static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg);
-
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 1,
@@ -180,6 +165,27 @@ static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
kfree(buf);
}
+struct device *snd_soc_dapm_to_dev(struct snd_soc_dapm_context *dapm)
+{
+ if (dapm->component)
+ return dapm->component->dev;
+
+ return dapm->card->dev;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_to_dev);
+
+struct snd_soc_card *snd_soc_dapm_to_card(struct snd_soc_dapm_context *dapm)
+{
+ return dapm->card;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_to_card);
+
+struct snd_soc_component *snd_soc_dapm_to_component(struct snd_soc_dapm_context *dapm)
+{
+ return dapm->component;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_to_component);
+
static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
{
return !list_empty(&w->dirty);
@@ -187,10 +193,12 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
{
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+
dapm_assert_locked(w->dapm);
if (!dapm_dirty_widget(w)) {
- dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
+ dev_vdbg(dev, "Marking %s dirty due to %s\n",
w->name, reason);
list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
}
@@ -221,7 +229,7 @@ static __always_inline void dapm_widget_invalidate_paths(
list_for_each_entry(w, &list, work_list) {
snd_soc_dapm_widget_for_each_path(w, dir, p) {
- if (p->is_supply || p->weak || !p->connect)
+ if (p->is_supply || !p->connect)
continue;
node = p->node[rdir];
if (node->endpoints[dir] != -1) {
@@ -283,7 +291,7 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
* Weak paths or supply paths do not influence the number of input or
* output paths of their neighbors.
*/
- if (p->weak || p->is_supply)
+ if (p->is_supply)
return;
/*
@@ -298,7 +306,7 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
dapm_widget_invalidate_output_paths(p->source);
}
-void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
+void snd_soc_dapm_mark_endpoints_dirty(struct snd_soc_card *card)
{
struct snd_soc_dapm_widget *w;
@@ -316,30 +324,34 @@ 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(
- const struct snd_soc_dapm_widget *_widget)
+ const struct snd_soc_dapm_widget *_widget,
+ const char *prefix)
{
- struct snd_soc_dapm_widget *w;
-
- w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
+ struct snd_soc_dapm_widget *w __free(kfree) = kmemdup(_widget,
+ sizeof(*_widget),
+ GFP_KERNEL);
if (!w)
return NULL;
- /*
- * w->name is duplicated in caller, but w->sname isn't.
- * Duplicate it here if defined
- */
+ if (prefix)
+ w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, _widget->name);
+ else
+ w->name = kstrdup_const(_widget->name, GFP_KERNEL);
+ if (!w->name)
+ return NULL;
+
if (_widget->sname) {
w->sname = kstrdup_const(_widget->sname, GFP_KERNEL);
if (!w->sname) {
- kfree(w);
+ kfree_const(w->name);
return NULL;
}
}
- return w;
+
+ return_ptr(w);
}
struct dapm_kcontrol_data {
@@ -349,9 +361,326 @@ struct dapm_kcontrol_data {
struct snd_soc_dapm_widget_list *wlist;
};
+static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg)
+{
+ if (!dapm->component)
+ return -EIO;
+ return snd_soc_component_read(dapm->component, reg);
+}
+
+/* set up initial codec paths */
+static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
+ int nth_path)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)
+ p->sink->kcontrol_news[i].private_value;
+ unsigned int reg = mc->reg;
+ unsigned int invert = mc->invert;
+
+ if (reg != SND_SOC_NOPM) {
+ unsigned int shift = mc->shift;
+ unsigned int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int val = soc_dapm_read(p->sink->dapm, reg);
+
+ /*
+ * The nth_path argument allows this function to know
+ * which path of a kcontrol it is setting the initial
+ * status for. Ideally this would support any number
+ * of paths and channels. But since kcontrols only come
+ * in mono and stereo variants, we are limited to 2
+ * channels.
+ *
+ * The following code assumes for stereo controls the
+ * first path is the left channel, and all remaining
+ * paths are the right channel.
+ */
+ if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
+ if (reg != mc->rreg)
+ val = soc_dapm_read(p->sink->dapm, mc->rreg);
+ val = (val >> mc->rshift) & mask;
+ } else {
+ val = (val >> shift) & mask;
+ }
+ if (invert)
+ val = max - val;
+ p->connect = !!val;
+ } else {
+ /* since a virtual mixer has no backing registers to
+ * decide which path to connect, it will try to match
+ * with initial state. This is to ensure
+ * that the default mixer choice will be
+ * correctly powered up during initialization.
+ */
+ p->connect = invert;
+ }
+}
+
+/* connect mux widget to its interconnecting audio paths */
+static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_path *path, const char *control_name,
+ struct snd_soc_dapm_widget *w)
+{
+ const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int item;
+ int i;
+
+ if (e->reg != SND_SOC_NOPM) {
+ unsigned int val;
+
+ val = soc_dapm_read(dapm, e->reg);
+ val = (val >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ } else {
+ /* since a virtual mux has no backing registers to
+ * decide which path to connect, it will try to match
+ * with the first enumeration. This is to ensure
+ * that the default mux choice (the first) will be
+ * correctly powered up during initialization.
+ */
+ item = 0;
+ }
+
+ i = match_string(e->texts, e->items, control_name);
+ if (i < 0)
+ return -ENODEV;
+
+ path->name = e->texts[i];
+ path->connect = (i == item);
+ return 0;
+
+}
+
+/* connect mixer widget to its interconnecting audio paths */
+static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_path *path, const char *control_name)
+{
+ int i, nth_path = 0;
+
+ /* search for mixer kcontrol */
+ for (i = 0; i < path->sink->num_kcontrols; i++) {
+ if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
+ path->name = path->sink->kcontrol_news[i].name;
+ dapm_set_mixer_path_status(path, i, nth_path++);
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+/*
+ * dapm_update_widget_flags() - Re-compute widget sink and source flags
+ * @w: The widget for which to update the flags
+ *
+ * Some widgets have a dynamic category which depends on which neighbors they
+ * are connected to. This function update the category for these widgets.
+ *
+ * This function must be called whenever a path is added or removed to a widget.
+ */
+static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
+{
+ enum snd_soc_dapm_direction dir;
+ struct snd_soc_dapm_path *p;
+ unsigned int ep;
+
+ switch (w->id) {
+ case snd_soc_dapm_input:
+ /* On a fully routed card an input is never a source */
+ if (w->dapm->card->fully_routed)
+ return;
+ ep = SND_SOC_DAPM_EP_SOURCE;
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
+ if (p->source->id == snd_soc_dapm_micbias ||
+ p->source->id == snd_soc_dapm_mic ||
+ p->source->id == snd_soc_dapm_line ||
+ p->source->id == snd_soc_dapm_output) {
+ ep = 0;
+ break;
+ }
+ }
+ break;
+ case snd_soc_dapm_output:
+ /* On a fully routed card a output is never a sink */
+ if (w->dapm->card->fully_routed)
+ return;
+ ep = SND_SOC_DAPM_EP_SINK;
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (p->sink->id == snd_soc_dapm_spk ||
+ p->sink->id == snd_soc_dapm_hp ||
+ p->sink->id == snd_soc_dapm_line ||
+ p->sink->id == snd_soc_dapm_input) {
+ ep = 0;
+ break;
+ }
+ }
+ break;
+ case snd_soc_dapm_line:
+ ep = 0;
+ snd_soc_dapm_for_each_direction(dir) {
+ if (!list_empty(&w->edges[dir]))
+ ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
+ }
+ break;
+ default:
+ return;
+ }
+
+ w->is_ep = ep;
+}
+
+static int snd_soc_dapm_check_dynamic_path(
+ struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
+ const char *control)
+{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+ bool dynamic_source = false;
+ bool dynamic_sink = false;
+
+ if (!control)
+ return 0;
+
+ switch (source->id) {
+ case snd_soc_dapm_demux:
+ dynamic_source = true;
+ break;
+ default:
+ break;
+ }
+
+ switch (sink->id) {
+ case snd_soc_dapm_mux:
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
+ dynamic_sink = true;
+ break;
+ default:
+ break;
+ }
+
+ if (dynamic_source && dynamic_sink) {
+ dev_err(dev,
+ "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
+ source->name, control, sink->name);
+ return -EINVAL;
+ } else if (!dynamic_source && !dynamic_sink) {
+ dev_err(dev,
+ "Control not supported for path %s -> [%s] -> %s\n",
+ source->name, control, sink->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int snd_soc_dapm_add_path(
+ struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
+ const char *control,
+ int (*connected)(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink))
+{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+ enum snd_soc_dapm_direction dir;
+ struct snd_soc_dapm_path *path;
+ int ret;
+
+ if (wsink->is_supply && !wsource->is_supply) {
+ dev_err(dev,
+ "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
+ wsource->name, wsink->name);
+ return -EINVAL;
+ }
+
+ if (connected && !wsource->is_supply) {
+ dev_err(dev,
+ "connected() callback only supported for supply widgets (%s -> %s)\n",
+ wsource->name, wsink->name);
+ return -EINVAL;
+ }
+
+ if (wsource->is_supply && control) {
+ dev_err(dev,
+ "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
+ wsource->name, control, wsink->name);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
+ if (ret)
+ return ret;
+
+ path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+
+ path->node[SND_SOC_DAPM_DIR_IN] = wsource;
+ path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
+
+ path->connected = connected;
+ INIT_LIST_HEAD(&path->list);
+ INIT_LIST_HEAD(&path->list_kcontrol);
+
+ if (wsource->is_supply || wsink->is_supply)
+ path->is_supply = 1;
+
+ /* connect static paths */
+ if (control == NULL) {
+ path->connect = 1;
+ } else {
+ switch (wsource->id) {
+ case snd_soc_dapm_demux:
+ ret = dapm_connect_mux(dapm, path, control, wsource);
+ if (ret)
+ goto err;
+ break;
+ default:
+ break;
+ }
+
+ switch (wsink->id) {
+ case snd_soc_dapm_mux:
+ ret = dapm_connect_mux(dapm, path, control, wsink);
+ if (ret != 0)
+ goto err;
+ break;
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
+ ret = dapm_connect_mixer(dapm, path, control);
+ if (ret != 0)
+ goto err;
+ break;
+ default:
+ break;
+ }
+ }
+
+ list_add(&path->list, &dapm->card->paths);
+
+ snd_soc_dapm_for_each_direction(dir)
+ list_add(&path->list_node[dir], &path->node[dir]->edges[dir]);
+
+ snd_soc_dapm_for_each_direction(dir) {
+ dapm_update_widget_flags(path->node[dir]);
+ dapm_mark_dirty(path->node[dir], "Route added");
+ }
+
+ if (snd_soc_card_is_instantiated(dapm->card) && path->connect)
+ dapm_path_invalidate(path);
+
+ return 0;
+err:
+ kfree(path);
+ return ret;
+}
+
static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, const char *ctrl_name)
{
+ struct device *dev = snd_soc_dapm_to_dev(widget->dapm);
struct dapm_kcontrol_data *data;
struct soc_mixer_control *mc;
struct soc_enum *e;
@@ -374,7 +703,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
struct snd_soc_dapm_widget template;
if (snd_soc_volsw_is_stereo(mc))
- dev_warn(widget->dapm->dev,
+ dev_warn(dev,
"ASoC: Unsupported stereo autodisable control '%s'\n",
ctrl_name);
@@ -497,8 +826,8 @@ static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
if (!new_wlist)
return -ENOMEM;
- new_wlist->widgets[n - 1] = widget;
new_wlist->num_widgets = n;
+ new_wlist->widgets[n - 1] = widget;
data->wlist = new_wlist;
@@ -535,13 +864,13 @@ static struct list_head *dapm_kcontrol_get_path_list(
list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
list_kcontrol)
-unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+unsigned int snd_soc_dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
return data->value;
}
-EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_get_value);
static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
unsigned int value)
@@ -574,31 +903,42 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
}
/**
- * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
+ * snd_soc_dapm_kcontrol_to_widget() - Returns the widget associated to a
* kcontrol
* @kcontrol: The kcontrol
*/
-struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
- struct snd_kcontrol *kcontrol)
+struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_to_widget(struct snd_kcontrol *kcontrol)
{
return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_widget);
/**
- * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
- * kcontrol
+ * snd_soc_dapm_kcontrol_to_dapm() - Returns the dapm context associated to a kcontrol
* @kcontrol: The kcontrol
*
* Note: This function must only be used on kcontrols that are known to have
* been registered for a CODEC. Otherwise the behaviour is undefined.
*/
-struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
- struct snd_kcontrol *kcontrol)
+struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_to_dapm(struct snd_kcontrol *kcontrol)
{
return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_dapm);
+
+/**
+ * snd_soc_dapm_kcontrol_to_component() - Returns the component associated to a
+ * kcontrol
+ * @kcontrol: The kcontrol
+ *
+ * This function must only be used on DAPM contexts that are known to be part of
+ * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined
+ */
+struct snd_soc_component *snd_soc_dapm_kcontrol_to_component(struct snd_kcontrol *kcontrol)
+{
+ return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_to_dapm(kcontrol));
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_to_component);
static void dapm_reset(struct snd_soc_card *card)
{
@@ -621,13 +961,6 @@ static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
return dapm->component->name_prefix;
}
-static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg)
-{
- if (!dapm->component)
- return -EIO;
- return snd_soc_component_read(dapm->component, reg);
-}
-
static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
int reg, unsigned int mask, unsigned int value)
{
@@ -704,6 +1037,25 @@ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
/**
+ * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
+ * @dapm: The DAPM context to initialize
+ * @level: The DAPM level to initialize to
+ *
+ * This function only sets the driver internal state of the DAPM level and will
+ * not modify the state of the device. Hence it should not be used during normal
+ * operation, but only to synchronize the internal state to the device state.
+ * E.g. during driver probe to set the DAPM level to the one corresponding with
+ * the power-on reset state of the device.
+ *
+ * To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
+ */
+void snd_soc_dapm_init_bias_level(struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+{
+ dapm->bias_level = level;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_init_bias_level);
+
+/**
* snd_soc_dapm_set_bias_level - set the bias level for the system
* @dapm: DAPM context
* @level: level to configure
@@ -718,13 +1070,13 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
struct snd_soc_card *card = dapm->card;
int ret = 0;
- trace_snd_soc_bias_level_start(card, level);
+ trace_snd_soc_bias_level_start(dapm, level);
ret = snd_soc_card_set_bias_level(card, dapm, level);
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)
@@ -732,110 +1084,26 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
ret = snd_soc_card_set_bias_level_post(card, dapm, level);
out:
- trace_snd_soc_bias_level_done(card, level);
+ trace_snd_soc_bias_level_done(dapm, level);
- return ret;
-}
-
-/* connect mux widget to its interconnecting audio paths */
-static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_path *path, const char *control_name,
- struct snd_soc_dapm_widget *w)
-{
- const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int item;
- int i;
-
- if (e->reg != SND_SOC_NOPM) {
- unsigned int val;
- val = soc_dapm_read(dapm, e->reg);
- val = (val >> e->shift_l) & e->mask;
- item = snd_soc_enum_val_to_item(e, val);
- } else {
- /* since a virtual mux has no backing registers to
- * decide which path to connect, it will try to match
- * with the first enumeration. This is to ensure
- * that the default mux choice (the first) will be
- * correctly powered up during initialization.
- */
- item = 0;
- }
-
- i = match_string(e->texts, e->items, control_name);
- if (i < 0)
- return -ENODEV;
-
- path->name = e->texts[i];
- path->connect = (i == item);
- return 0;
-
-}
-
-/* set up initial codec paths */
-static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
- int nth_path)
-{
- struct soc_mixer_control *mc = (struct soc_mixer_control *)
- p->sink->kcontrol_news[i].private_value;
- unsigned int reg = mc->reg;
- unsigned int invert = mc->invert;
-
- if (reg != SND_SOC_NOPM) {
- unsigned int shift = mc->shift;
- unsigned int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int val = soc_dapm_read(p->sink->dapm, reg);
+ /* success */
+ if (ret == 0)
+ snd_soc_dapm_init_bias_level(dapm, level);
- /*
- * The nth_path argument allows this function to know
- * which path of a kcontrol it is setting the initial
- * status for. Ideally this would support any number
- * of paths and channels. But since kcontrols only come
- * in mono and stereo variants, we are limited to 2
- * channels.
- *
- * The following code assumes for stereo controls the
- * first path is the left channel, and all remaining
- * paths are the right channel.
- */
- if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
- if (reg != mc->rreg)
- val = soc_dapm_read(p->sink->dapm, mc->rreg);
- val = (val >> mc->rshift) & mask;
- } else {
- val = (val >> shift) & mask;
- }
- if (invert)
- val = max - val;
- p->connect = !!val;
- } else {
- /* since a virtual mixer has no backing registers to
- * decide which path to connect, it will try to match
- * with initial state. This is to ensure
- * that the default mixer choice will be
- * correctly powered up during initialization.
- */
- p->connect = invert;
- }
+ return ret;
}
-/* connect mixer widget to its interconnecting audio paths */
-static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_path *path, const char *control_name)
+/**
+ * snd_soc_dapm_get_bias_level() - Get current DAPM bias level
+ * @dapm: The context for which to get the bias level
+ *
+ * Returns: The current bias level of the passed DAPM context.
+ */
+enum snd_soc_bias_level snd_soc_dapm_get_bias_level(struct snd_soc_dapm_context *dapm)
{
- int i, nth_path = 0;
-
- /* search for mixer kcontrol */
- for (i = 0; i < path->sink->num_kcontrols; i++) {
- if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
- path->name = path->sink->kcontrol_news[i].name;
- dapm_set_mixer_path_status(path, i, nth_path++);
- return 0;
- }
- }
- return -ENODEV;
+ return dapm->bias_level;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_bias_level);
static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *kcontrolw,
@@ -870,6 +1138,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
int kci)
{
struct snd_soc_dapm_context *dapm = w->dapm;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct snd_card *card = dapm->card->snd_card;
const char *prefix;
size_t prefix_len;
@@ -916,6 +1185,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
return -EINVAL;
}
}
+ if (w->no_wname_in_kcontrol_name)
+ wname_in_long_name = false;
if (wname_in_long_name && kcname_in_long_name) {
/*
@@ -956,7 +1227,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
ret = snd_ctl_add(card, kcontrol);
if (ret < 0) {
- dev_err(dapm->dev,
+ dev_err(dev,
"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
w->name, name, ret);
goto exit_free;
@@ -1012,6 +1283,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
static int dapm_new_mux(struct snd_soc_dapm_widget *w)
{
struct snd_soc_dapm_context *dapm = w->dapm;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_path *path;
const char *type;
@@ -1031,14 +1303,14 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
}
if (w->num_kcontrols != 1) {
- dev_err(dapm->dev,
+ dev_err(dev,
"ASoC: %s %s has incorrect number of controls\n", type,
w->name);
return -EINVAL;
}
if (list_empty(&w->edges[dir])) {
- dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
+ dev_err(dev, "ASoC: %s %s has no paths\n", type, w->name);
return -EINVAL;
}
@@ -1081,13 +1353,14 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
/* add kcontrol */
for (i = 0; i < w->num_kcontrols; i++) {
struct snd_soc_dapm_context *dapm = w->dapm;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct snd_card *card = dapm->card->snd_card;
struct snd_kcontrol *kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
w, w->name, NULL);
int ret = snd_ctl_add(card, kcontrol);
if (ret < 0) {
- dev_err(dapm->dev,
+ dev_err(dev,
"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
w->name, w->kcontrol_news[i].name, ret);
return ret;
@@ -1105,13 +1378,14 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
*/
static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
{
+ struct device *dev = snd_soc_dapm_to_dev(widget->dapm);
int level = snd_power_get_state(widget->dapm->card->snd_card);
switch (level) {
case SNDRV_CTL_POWER_D3hot:
case SNDRV_CTL_POWER_D3cold:
if (widget->ignore_suspend)
- dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
+ dev_dbg(dev, "ASoC: %s ignoring suspend\n",
widget->name);
return widget->ignore_suspend;
default:
@@ -1139,6 +1413,8 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
if (*list == NULL)
return -ENOMEM;
+ (*list)->num_widgets = size;
+
list_for_each_entry(w, widgets, work_list)
(*list)->widgets[i++] = w;
@@ -1161,7 +1437,7 @@ static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget,
widget->endpoints[dir] = -1;
snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
- if (path->weak || path->is_supply)
+ if (path->is_supply)
continue;
if (path->walking)
@@ -1216,7 +1492,7 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
DAPM_UPDATE_STAT(widget, neighbour_checks);
- if (path->weak || path->is_supply)
+ if (path->is_supply)
continue;
if (path->walking)
@@ -1337,9 +1613,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_dai_free_widgets);
/*
* Handler for regulator supply widget.
*/
-int dapm_regulator_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+int snd_soc_dapm_regulator_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
int ret;
soc_dapm_async_complete(w->dapm);
@@ -1348,7 +1625,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, false);
if (ret != 0)
- dev_warn(w->dapm->dev,
+ dev_warn(dev,
"ASoC: Failed to unbypass %s: %d\n",
w->name, ret);
}
@@ -1358,7 +1635,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
- dev_warn(w->dapm->dev,
+ dev_warn(dev,
"ASoC: Failed to bypass %s: %d\n",
w->name, ret);
}
@@ -1366,13 +1643,13 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
return regulator_disable_deferred(w->regulator, w->shift);
}
}
-EXPORT_SYMBOL_GPL(dapm_regulator_event);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_regulator_event);
/*
* Handler for pinctrl widget.
*/
-int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+int snd_soc_dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_dapm_pinctrl_priv *priv = w->priv;
struct pinctrl *p = w->pinctrl;
@@ -1391,13 +1668,13 @@ int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
return pinctrl_select_state(p, s);
}
-EXPORT_SYMBOL_GPL(dapm_pinctrl_event);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_pinctrl_event);
/*
* Handler for clock supply widget.
*/
-int dapm_clock_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+int snd_soc_dapm_clock_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
if (!w->clk)
return -EIO;
@@ -1413,7 +1690,7 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w,
return 0;
}
-EXPORT_SYMBOL_GPL(dapm_clock_event);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_clock_event);
static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
{
@@ -1453,9 +1730,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
snd_soc_dapm_widget_for_each_sink_path(w, path) {
DAPM_UPDATE_STAT(w, neighbour_checks);
- if (path->weak)
- continue;
-
if (path->connected &&
!path->connected(path->source, path->sink))
continue;
@@ -1524,6 +1798,7 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
static void dapm_seq_check_event(struct snd_soc_card *card,
struct snd_soc_dapm_widget *w, int event)
{
+ struct device *dev = card->dev;
const char *ev_name;
int power;
@@ -1563,14 +1838,14 @@ static void dapm_seq_check_event(struct snd_soc_card *card,
if (w->event && (w->event_flags & event)) {
int ret;
- pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
+ pop_dbg(dev, card->pop_time, "pop test : %s %s\n",
w->name, ev_name);
soc_dapm_async_complete(w->dapm);
trace_snd_soc_dapm_widget_event_start(w, event);
ret = w->event(w, NULL, event);
trace_snd_soc_dapm_widget_event_done(w, event);
if (ret < 0)
- dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
+ dev_err(dev, "ASoC: %s: %s event failed: %d\n",
ev_name, w->name, ret);
}
}
@@ -1579,6 +1854,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card,
static void dapm_seq_run_coalesced(struct snd_soc_card *card,
struct list_head *pending)
{
+ struct device *dev = card->dev;
struct snd_soc_dapm_context *dapm;
struct snd_soc_dapm_widget *w;
int reg;
@@ -1599,7 +1875,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
else
value |= w->off_val << w->shift;
- pop_dbg(dapm->dev, card->pop_time,
+ pop_dbg(dev, card->pop_time,
"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
w->name, reg, value, mask);
@@ -1613,7 +1889,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
* same register.
*/
- pop_dbg(dapm->dev, card->pop_time,
+ pop_dbg(dev, card->pop_time,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, card->pop_time);
pop_wait(card->pop_time);
@@ -1637,6 +1913,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
static void dapm_seq_run(struct snd_soc_card *card,
struct list_head *list, int event, bool power_up)
{
+ struct device *dev = card->dev;
struct snd_soc_dapm_widget *w, *n;
struct snd_soc_dapm_context *d;
LIST_HEAD(pending);
@@ -1715,7 +1992,7 @@ static void dapm_seq_run(struct snd_soc_card *card,
}
if (ret < 0)
- dev_err(w->dapm->dev,
+ dev_err(dev,
"ASoC: Failed to apply widget power: %d\n", ret);
}
@@ -1734,9 +2011,9 @@ 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 device *dev = card->dev;
struct snd_soc_dapm_widget_list *wlist;
struct snd_soc_dapm_widget *w = NULL;
unsigned int wi;
@@ -1751,7 +2028,7 @@ static void dapm_widget_update(struct snd_soc_card *card)
if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
if (ret != 0)
- dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
+ dev_err(dev, "ASoC: %s DAPM pre-event failed: %d\n",
w->name, ret);
}
}
@@ -1762,14 +2039,14 @@ static void dapm_widget_update(struct snd_soc_card *card)
ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
update->val);
if (ret < 0)
- dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
+ dev_err(dev, "ASoC: %s DAPM update failed: %d\n",
w->name, ret);
if (update->has_second_set) {
ret = soc_dapm_update_bits(w->dapm, update->reg2,
update->mask2, update->val2);
if (ret < 0)
- dev_err(w->dapm->dev,
+ dev_err(dev,
"ASoC: %s DAPM update failed: %d\n",
w->name, ret);
}
@@ -1778,7 +2055,7 @@ static void dapm_widget_update(struct snd_soc_card *card)
if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
if (ret != 0)
- dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
+ dev_err(dev, "ASoC: %s DAPM post-event failed: %d\n",
w->name, ret);
}
}
@@ -1789,29 +2066,30 @@ static void dapm_widget_update(struct snd_soc_card *card)
*/
static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
{
- struct snd_soc_dapm_context *d = data;
+ struct snd_soc_dapm_context *dapm = data;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
int ret;
/* If we're off and we're not supposed to go into STANDBY */
- if (d->bias_level == SND_SOC_BIAS_OFF &&
- d->target_bias_level != SND_SOC_BIAS_OFF) {
- if (d->dev && cookie)
- pm_runtime_get_sync(d->dev);
+ if (dapm->bias_level == SND_SOC_BIAS_OFF &&
+ dapm->target_bias_level != SND_SOC_BIAS_OFF) {
+ if (dev && cookie)
+ pm_runtime_get_sync(dev);
- ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
+ ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
if (ret != 0)
- dev_err(d->dev,
+ dev_err(dev,
"ASoC: Failed to turn on bias: %d\n", ret);
}
/* Prepare for a transition to ON or away from ON */
- if ((d->target_bias_level == SND_SOC_BIAS_ON &&
- d->bias_level != SND_SOC_BIAS_ON) ||
- (d->target_bias_level != SND_SOC_BIAS_ON &&
- d->bias_level == SND_SOC_BIAS_ON)) {
- ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
+ if ((dapm->target_bias_level == SND_SOC_BIAS_ON &&
+ dapm->bias_level != SND_SOC_BIAS_ON) ||
+ (dapm->target_bias_level != SND_SOC_BIAS_ON &&
+ dapm->bias_level == SND_SOC_BIAS_ON)) {
+ ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
if (ret != 0)
- dev_err(d->dev,
+ dev_err(dev,
"ASoC: Failed to prepare bias: %d\n", ret);
}
}
@@ -1821,38 +2099,36 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
*/
static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
{
- struct snd_soc_dapm_context *d = data;
+ struct snd_soc_dapm_context *dapm = data;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
int ret;
/* If we just powered the last thing off drop to standby bias */
- if (d->bias_level == SND_SOC_BIAS_PREPARE &&
- (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
- d->target_bias_level == SND_SOC_BIAS_OFF)) {
- ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
+ if (dapm->bias_level == SND_SOC_BIAS_PREPARE &&
+ (dapm->target_bias_level == SND_SOC_BIAS_STANDBY ||
+ dapm->target_bias_level == SND_SOC_BIAS_OFF)) {
+ ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
if (ret != 0)
- dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
- ret);
+ dev_err(dev, "ASoC: Failed to apply standby bias: %d\n", ret);
}
/* If we're in standby and can support bias off then do that */
- if (d->bias_level == SND_SOC_BIAS_STANDBY &&
- d->target_bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
+ if (dapm->bias_level == SND_SOC_BIAS_STANDBY &&
+ dapm->target_bias_level == SND_SOC_BIAS_OFF) {
+ ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_OFF);
if (ret != 0)
- dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
- ret);
+ dev_err(dev, "ASoC: Failed to turn off bias: %d\n", ret);
- if (d->dev && cookie)
- pm_runtime_put(d->dev);
+ if (dev && cookie)
+ pm_runtime_put(dev);
}
/* If we just powered up then move to active bias */
- if (d->bias_level == SND_SOC_BIAS_PREPARE &&
- d->target_bias_level == SND_SOC_BIAS_ON) {
- ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
+ if (dapm->bias_level == SND_SOC_BIAS_PREPARE &&
+ dapm->target_bias_level == SND_SOC_BIAS_ON) {
+ ret = snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_ON);
if (ret != 0)
- dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
- ret);
+ dev_err(dev, "ASoC: Failed to apply active bias: %d\n", ret);
}
}
@@ -1917,21 +2193,26 @@ end:
dapm_seq_insert(w, down_list, false);
}
-static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
+bool snd_soc_dapm_get_idle_bias(struct snd_soc_dapm_context *dapm)
{
- if (dapm->idle_bias_off)
- return true;
+ if (dapm->idle_bias) {
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ unsigned int state = snd_power_get_state(dapm->card->snd_card);
- switch (snd_power_get_state(dapm->card->snd_card)) {
- case SNDRV_CTL_POWER_D3hot:
- case SNDRV_CTL_POWER_D3cold:
- return dapm->suspend_bias_off;
- default:
- break;
+ if ((state == SNDRV_CTL_POWER_D3hot || (state == SNDRV_CTL_POWER_D3cold)) &&
+ component)
+ return !component->driver->suspend_bias_off;
}
- return false;
+ return dapm->idle_bias;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_idle_bias);
+
+void snd_soc_dapm_set_idle_bias(struct snd_soc_dapm_context *dapm, bool on)
+{
+ dapm->idle_bias = on;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_set_idle_bias);
/*
* Scan each dapm widget for complete audio path.
@@ -1942,8 +2223,10 @@ 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_context *dapm = snd_soc_card_to_dapm(card);
struct snd_soc_dapm_widget *w;
struct snd_soc_dapm_context *d;
LIST_HEAD(up_list);
@@ -1954,13 +2237,13 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
snd_soc_dapm_mutex_assert_held(card);
- trace_snd_soc_dapm_start(card);
+ trace_snd_soc_dapm_start(card, event);
for_each_card_dapms(card, d) {
- if (dapm_idle_bias_off(d))
- d->target_bias_level = SND_SOC_BIAS_OFF;
- else
+ if (snd_soc_dapm_get_idle_bias(d))
d->target_bias_level = SND_SOC_BIAS_STANDBY;
+ else
+ d->target_bias_level = SND_SOC_BIAS_OFF;
}
dapm_reset(card);
@@ -2024,16 +2307,16 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
if (d->target_bias_level > bias)
bias = d->target_bias_level;
for_each_card_dapms(card, d)
- if (!dapm_idle_bias_off(d))
+ if (snd_soc_dapm_get_idle_bias(d))
d->target_bias_level = bias;
trace_snd_soc_dapm_walk_done(card);
/* Run card bias changes at first */
- dapm_pre_sequence_async(&card->dapm, 0);
+ dapm_pre_sequence_async(dapm, 0);
/* Run other bias changes in parallel */
for_each_card_dapms(card, d) {
- if (d != &card->dapm && d->bias_level != d->target_bias_level)
+ if (d != dapm && d->bias_level != d->target_bias_level)
async_schedule_domain(dapm_pre_sequence_async, d,
&async_domain);
}
@@ -2050,20 +2333,20 @@ 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);
/* Run all the bias changes in parallel */
for_each_card_dapms(card, d) {
- if (d != &card->dapm && d->bias_level != d->target_bias_level)
+ if (d != dapm && d->bias_level != d->target_bias_level)
async_schedule_domain(dapm_post_sequence_async, d,
&async_domain);
}
async_synchronize_full_domain(&async_domain);
/* Run card bias changes at last */
- dapm_post_sequence_async(&card->dapm, 0);
+ dapm_post_sequence_async(dapm, 0);
/* do we need to notify any clients that DAPM event is complete */
for_each_card_dapms(card, d) {
@@ -2079,12 +2362,54 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
"DAPM sequencing finished, waiting %dms\n", card->pop_time);
pop_wait(card->pop_time);
- trace_snd_soc_dapm_done(card);
+ trace_snd_soc_dapm_done(card, event);
return 0;
}
#ifdef CONFIG_DEBUG_FS
+
+static const char * const snd_soc_dapm_type_name[] = {
+ [snd_soc_dapm_input] = "input",
+ [snd_soc_dapm_output] = "output",
+ [snd_soc_dapm_mux] = "mux",
+ [snd_soc_dapm_demux] = "demux",
+ [snd_soc_dapm_mixer] = "mixer",
+ [snd_soc_dapm_mixer_named_ctl] = "mixer_named_ctl",
+ [snd_soc_dapm_pga] = "pga",
+ [snd_soc_dapm_out_drv] = "out_drv",
+ [snd_soc_dapm_adc] = "adc",
+ [snd_soc_dapm_dac] = "dac",
+ [snd_soc_dapm_micbias] = "micbias",
+ [snd_soc_dapm_mic] = "mic",
+ [snd_soc_dapm_hp] = "hp",
+ [snd_soc_dapm_spk] = "spk",
+ [snd_soc_dapm_line] = "line",
+ [snd_soc_dapm_switch] = "switch",
+ [snd_soc_dapm_vmid] = "vmid",
+ [snd_soc_dapm_pre] = "pre",
+ [snd_soc_dapm_post] = "post",
+ [snd_soc_dapm_supply] = "supply",
+ [snd_soc_dapm_pinctrl] = "pinctrl",
+ [snd_soc_dapm_regulator_supply] = "regulator_supply",
+ [snd_soc_dapm_clock_supply] = "clock_supply",
+ [snd_soc_dapm_aif_in] = "aif_in",
+ [snd_soc_dapm_aif_out] = "aif_out",
+ [snd_soc_dapm_siggen] = "siggen",
+ [snd_soc_dapm_sink] = "sink",
+ [snd_soc_dapm_dai_in] = "dai_in",
+ [snd_soc_dapm_dai_out] = "dai_out",
+ [snd_soc_dapm_dai_link] = "dai_link",
+ [snd_soc_dapm_kcontrol] = "kcontrol",
+ [snd_soc_dapm_buffer] = "buffer",
+ [snd_soc_dapm_scheduler] = "scheduler",
+ [snd_soc_dapm_effect] = "effect",
+ [snd_soc_dapm_src] = "src",
+ [snd_soc_dapm_asrc] = "asrc",
+ [snd_soc_dapm_encoder] = "encoder",
+ [snd_soc_dapm_decoder] = "decoder",
+};
+
static ssize_t dapm_widget_power_read_file(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -2095,6 +2420,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
int in, out;
ssize_t ret;
struct snd_soc_dapm_path *p = NULL;
+ const char *c_name;
+
+ BUILD_BUG_ON(ARRAY_SIZE(snd_soc_dapm_type_name) != SND_SOC_DAPM_TYPE_COUNT);
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
@@ -2127,6 +2455,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
w->sname,
w->active ? "active" : "inactive");
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, " widget-type %s\n",
+ snd_soc_dapm_type_name[w->id]);
+
snd_soc_dapm_for_each_direction(dir) {
rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
snd_soc_dapm_widget_for_each_path(w, dir, p) {
@@ -2136,11 +2467,13 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (!p->connect)
continue;
+ c_name = p->node[rdir]->dapm->component ?
+ p->node[rdir]->dapm->component->name : NULL;
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- " %s \"%s\" \"%s\"\n",
+ " %s \"%s\" \"%s\" \"%s\"\n",
(rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
p->name ? p->name : "static",
- p->node[rdir]->name);
+ p->node[rdir]->name, c_name);
}
}
@@ -2196,7 +2529,7 @@ static const struct file_operations dapm_bias_fops = {
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
struct dentry *parent)
{
- if (!parent || IS_ERR(parent))
+ if (IS_ERR_OR_NULL(parent))
return;
dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
@@ -2273,7 +2606,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;
@@ -2294,7 +2629,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;
}
@@ -2307,9 +2642,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);
@@ -2320,6 +2653,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;
@@ -2359,7 +2693,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;
}
@@ -2372,9 +2706,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);
@@ -2382,10 +2714,10 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
-static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
+static ssize_t dapm_widget_show_component(struct snd_soc_component *component,
char *buf, int count)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct snd_soc_dapm_widget *w;
char *state = "not set";
@@ -2393,10 +2725,10 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
* we're checking for that case specifically here but in future
* we will ensure that the dummy component looks like others.
*/
- if (!cmpnt->card)
+ if (!component->card)
return 0;
- for_each_card_widgets(cmpnt->card, w) {
+ for_each_card_widgets(component->card, w) {
if (w->dapm != dapm)
continue;
@@ -2457,9 +2789,9 @@ static ssize_t dapm_widget_show(struct device *dev,
snd_soc_dapm_mutex_lock_root(rtd->card);
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- struct snd_soc_component *cmpnt = codec_dai->component;
+ struct snd_soc_component *component = codec_dai->component;
- count = dapm_widget_show_component(cmpnt, buf, count);
+ count = dapm_widget_show_component(component, buf, count);
}
snd_soc_dapm_mutex_unlock(rtd->card);
@@ -2469,7 +2801,7 @@ static ssize_t dapm_widget_show(struct device *dev,
static DEVICE_ATTR_RO(dapm_widget);
-struct attribute *soc_dapm_dev_attrs[] = {
+struct attribute *snd_soc_dapm_dev_attrs[] = {
&dev_attr_dapm_widget.attr,
NULL
};
@@ -2575,12 +2907,13 @@ static int __snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
const char *pin, int status)
{
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
int ret = 0;
dapm_assert_locked(dapm);
if (!w) {
- dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
+ dev_err(dev, "ASoC: DAPM unknown pin %s\n", pin);
return -EINVAL;
}
@@ -2630,7 +2963,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);
@@ -2658,6 +2991,8 @@ static int dapm_update_dai_chan(struct snd_soc_dapm_path *p,
struct snd_soc_dapm_widget *w,
int channels)
{
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
+
switch (w->id) {
case snd_soc_dapm_aif_out:
case snd_soc_dapm_aif_in:
@@ -2666,7 +3001,7 @@ static int dapm_update_dai_chan(struct snd_soc_dapm_path *p,
return 0;
}
- dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n",
+ dev_dbg(dev, "%s DAI route %s -> %s\n",
w->channel < channels ? "Connecting" : "Disconnecting",
p->source->name, p->sink->name);
@@ -2693,8 +3028,7 @@ static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream,
if (!w)
return 0;
- dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name,
- dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
+ dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, snd_pcm_direction_name(dir));
snd_soc_dapm_widget_for_each_sink_path(w, p) {
ret = dapm_update_dai_chan(p, p->sink, channels);
@@ -2715,7 +3049,7 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret;
snd_soc_dapm_mutex_lock(rtd->card);
@@ -2724,217 +3058,25 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
-
-/*
- * dapm_update_widget_flags() - Re-compute widget sink and source flags
- * @w: The widget for which to update the flags
- *
- * Some widgets have a dynamic category which depends on which neighbors they
- * are connected to. This function update the category for these widgets.
- *
- * This function must be called whenever a path is added or removed to a widget.
- */
-static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
-{
- enum snd_soc_dapm_direction dir;
- struct snd_soc_dapm_path *p;
- unsigned int ep;
-
- switch (w->id) {
- case snd_soc_dapm_input:
- /* On a fully routed card an input is never a source */
- if (w->dapm->card->fully_routed)
- return;
- ep = SND_SOC_DAPM_EP_SOURCE;
- snd_soc_dapm_widget_for_each_source_path(w, p) {
- if (p->source->id == snd_soc_dapm_micbias ||
- p->source->id == snd_soc_dapm_mic ||
- p->source->id == snd_soc_dapm_line ||
- p->source->id == snd_soc_dapm_output) {
- ep = 0;
- break;
- }
- }
- break;
- case snd_soc_dapm_output:
- /* On a fully routed card a output is never a sink */
- if (w->dapm->card->fully_routed)
- return;
- ep = SND_SOC_DAPM_EP_SINK;
- snd_soc_dapm_widget_for_each_sink_path(w, p) {
- if (p->sink->id == snd_soc_dapm_spk ||
- p->sink->id == snd_soc_dapm_hp ||
- p->sink->id == snd_soc_dapm_line ||
- p->sink->id == snd_soc_dapm_input) {
- ep = 0;
- break;
- }
- }
- break;
- case snd_soc_dapm_line:
- ep = 0;
- snd_soc_dapm_for_each_direction(dir) {
- if (!list_empty(&w->edges[dir]))
- ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
- }
- break;
- default:
- return;
- }
-
- w->is_ep = ep;
-}
-static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
- const char *control)
+int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s)
{
- bool dynamic_source = false;
- bool dynamic_sink = false;
-
- if (!control)
- return 0;
-
- switch (source->id) {
- case snd_soc_dapm_demux:
- dynamic_source = true;
- break;
- default:
- break;
- }
-
- switch (sink->id) {
- case snd_soc_dapm_mux:
- case snd_soc_dapm_switch:
- case snd_soc_dapm_mixer:
- case snd_soc_dapm_mixer_named_ctl:
- dynamic_sink = true;
- break;
- default:
- break;
- }
+ struct snd_soc_component *component = widget->dapm->component;
+ const char *wname = widget->name;
- if (dynamic_source && dynamic_sink) {
- dev_err(dapm->dev,
- "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
- source->name, control, sink->name);
- return -EINVAL;
- } else if (!dynamic_source && !dynamic_sink) {
- dev_err(dapm->dev,
- "Control not supported for path %s -> [%s] -> %s\n",
- source->name, control, sink->name);
- return -EINVAL;
- }
+ if (component && component->name_prefix)
+ wname += strlen(component->name_prefix) + 1; /* plus space */
- return 0;
-}
-
-static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
- const char *control,
- int (*connected)(struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink))
-{
- enum snd_soc_dapm_direction dir;
- struct snd_soc_dapm_path *path;
- int ret;
-
- if (wsink->is_supply && !wsource->is_supply) {
- dev_err(dapm->dev,
- "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
- wsource->name, wsink->name);
- return -EINVAL;
- }
-
- if (connected && !wsource->is_supply) {
- dev_err(dapm->dev,
- "connected() callback only supported for supply widgets (%s -> %s)\n",
- wsource->name, wsink->name);
- return -EINVAL;
- }
-
- if (wsource->is_supply && control) {
- dev_err(dapm->dev,
- "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
- wsource->name, control, wsink->name);
- return -EINVAL;
- }
-
- ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
- if (ret)
- return ret;
-
- path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
- if (!path)
- return -ENOMEM;
-
- path->node[SND_SOC_DAPM_DIR_IN] = wsource;
- path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
-
- path->connected = connected;
- INIT_LIST_HEAD(&path->list);
- INIT_LIST_HEAD(&path->list_kcontrol);
-
- if (wsource->is_supply || wsink->is_supply)
- path->is_supply = 1;
-
- /* connect static paths */
- if (control == NULL) {
- path->connect = 1;
- } else {
- switch (wsource->id) {
- case snd_soc_dapm_demux:
- ret = dapm_connect_mux(dapm, path, control, wsource);
- if (ret)
- goto err;
- break;
- default:
- break;
- }
-
- switch (wsink->id) {
- case snd_soc_dapm_mux:
- ret = dapm_connect_mux(dapm, path, control, wsink);
- if (ret != 0)
- goto err;
- break;
- case snd_soc_dapm_switch:
- case snd_soc_dapm_mixer:
- case snd_soc_dapm_mixer_named_ctl:
- ret = dapm_connect_mixer(dapm, path, control);
- if (ret != 0)
- goto err;
- break;
- default:
- break;
- }
- }
-
- list_add(&path->list, &dapm->card->paths);
-
- snd_soc_dapm_for_each_direction(dir)
- list_add(&path->list_node[dir], &path->node[dir]->edges[dir]);
-
- snd_soc_dapm_for_each_direction(dir) {
- dapm_update_widget_flags(path->node[dir]);
- dapm_mark_dirty(path->node[dir], "Route added");
- }
-
- if (snd_soc_card_is_instantiated(dapm->card) && path->connect)
- dapm_path_invalidate(path);
-
- return 0;
-err:
- kfree(path);
- return ret;
+ return strcmp(wname, s);
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_widget_name_cmp);
static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route)
{
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
const char *sink;
const char *source;
char prefixed_sink[80];
@@ -2977,7 +3119,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
}
sink_ref++;
if (sink_ref > 1)
- dev_warn(dapm->dev,
+ dev_warn(dev,
"ASoC: sink widget %s overwritten\n",
w->name);
continue;
@@ -2991,7 +3133,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
}
source_ref++;
if (source_ref > 1)
- dev_warn(dapm->dev,
+ dev_warn(dev,
"ASoC: source widget %s overwritten\n",
w->name);
}
@@ -3017,7 +3159,7 @@ skip_search:
route->connected);
err:
if (ret)
- dev_err(dapm->dev, "ASoC: Failed to add route %s%s -%s%s%s> %s%s\n",
+ dev_err(dev, "ASoC: Failed to add route %s%s -%s%s%s> %s%s\n",
source, !wsource ? "(*)" : "",
!route->control ? "" : "> [",
!route->control ? "" : route->control,
@@ -3029,6 +3171,7 @@ err:
static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route)
{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct snd_soc_dapm_path *path, *p;
const char *sink;
const char *source;
@@ -3037,7 +3180,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
const char *prefix;
if (route->control) {
- dev_err(dapm->dev,
+ dev_err(dev,
"ASoC: Removal of routes with controls not supported\n");
return -EINVAL;
}
@@ -3080,7 +3223,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
dapm_update_widget_flags(wsource);
dapm_update_widget_flags(wsink);
} else {
- dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
+ dev_warn(dev, "ASoC: Route %s->%s does not exist\n",
source, sink);
}
@@ -3142,86 +3285,6 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
-static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_route *route)
-{
- struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
- route->source,
- true);
- struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
- route->sink,
- true);
- struct snd_soc_dapm_path *path;
- int count = 0;
-
- if (!source) {
- dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
- route->source);
- return -ENODEV;
- }
-
- if (!sink) {
- dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
- route->sink);
- return -ENODEV;
- }
-
- if (route->control || route->connected)
- dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
- route->source, route->sink);
-
- snd_soc_dapm_widget_for_each_sink_path(source, path) {
- if (path->sink == sink) {
- path->weak = 1;
- count++;
- }
- }
-
- if (count == 0)
- dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
- route->source, route->sink);
- if (count > 1)
- dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
- count, route->source, route->sink);
-
- return 0;
-}
-
-/**
- * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
- * @dapm: DAPM context
- * @route: audio routes
- * @num: number of routes
- *
- * Mark existing routes matching those specified in the passed array
- * as being weak, meaning that they are ignored for the purpose of
- * power decisions. The main intended use case is for sidetone paths
- * which couple audio between other independent paths if they are both
- * active in order to make the combination work better at the user
- * level but which aren't intended to be "used".
- *
- * Note that CODEC drivers should not use this as sidetone type paths
- * can frequently also be used as bypass paths.
- */
-int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_route *route, int num)
-{
- int i;
- int ret = 0;
-
- snd_soc_dapm_mutex_lock_root(dapm);
- for (i = 0; i < num; i++) {
- int err = snd_soc_dapm_weak_route(dapm, route);
- if (err)
- ret = err;
- route++;
- }
- snd_soc_dapm_mutex_unlock(dapm);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
-
/**
* snd_soc_dapm_new_widgets - add new dapm widgets
* @card: card to be checked for new dapm widgets
@@ -3289,7 +3352,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;
}
@@ -3307,7 +3370,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int reg = mc->reg;
@@ -3329,7 +3392,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
if (snd_soc_volsw_is_stereo(mc))
rval = (reg_val >> mc->rshift) & mask;
} else {
- reg_val = dapm_kcontrol_get_value(kcontrol);
+ reg_val = snd_soc_dapm_kcontrol_get_value(kcontrol);
val = reg_val & mask;
if (snd_soc_volsw_is_stereo(mc))
@@ -3365,7 +3428,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct snd_soc_card *card = dapm->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -3378,6 +3442,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);
@@ -3397,7 +3462,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
/* This assumes field width < (bits in unsigned int / 2) */
if (width > sizeof(unsigned int) * 8 / 2)
- dev_warn(dapm->dev,
+ dev_warn(dev,
"ASoC: control %s field width limit exceeded\n",
kcontrol->id.name);
change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
@@ -3426,13 +3491,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);
@@ -3456,7 +3517,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg_val, val;
@@ -3464,7 +3525,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
reg_val = soc_dapm_read(dapm, e->reg);
} else {
- reg_val = dapm_kcontrol_get_value(kcontrol);
+ reg_val = snd_soc_dapm_kcontrol_get_value(kcontrol);
}
snd_soc_dapm_mutex_unlock(dapm);
@@ -3492,13 +3553,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
struct snd_soc_card *card = dapm->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
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)
@@ -3526,12 +3588,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);
@@ -3563,75 +3622,128 @@ int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
+static int __snd_soc_dapm_get_pin_switch(struct snd_soc_dapm_context *dapm,
+ const char *pin,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ snd_soc_dapm_mutex_lock(dapm);
+ ucontrol->value.integer.value[0] = snd_soc_dapm_get_pin_status(dapm, pin);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return 0;
+}
+
/**
* snd_soc_dapm_get_pin_switch - Get information for a pin switch
*
* @kcontrol: mixer control
* @ucontrol: Value
+ *
+ * Callback to provide information for a pin switch added at the card
+ * level.
*/
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
const char *pin = (const char *)kcontrol->private_value;
- snd_soc_dapm_mutex_lock(card);
+ return __snd_soc_dapm_get_pin_switch(dapm, pin, ucontrol);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
+
+/**
+ * snd_soc_dapm_get_component_pin_switch - Get information for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @ucontrol: Value
+ *
+ * Callback to provide information for a pin switch added at the component
+ * level.
+ */
+int snd_soc_dapm_get_component_pin_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ const char *pin = (const char *)kcontrol->private_value;
- ucontrol->value.integer.value[0] =
- snd_soc_dapm_get_pin_status(&card->dapm, pin);
+ return __snd_soc_dapm_get_pin_switch(dapm, pin, ucontrol);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_component_pin_switch);
- snd_soc_dapm_mutex_unlock(card);
+static int __snd_soc_dapm_put_pin_switch(struct snd_soc_dapm_context *dapm,
+ const char *pin,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
- return 0;
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = __snd_soc_dapm_set_pin(dapm, pin, !!ucontrol->value.integer.value[0]);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ snd_soc_dapm_sync(dapm);
+
+ return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
/**
* snd_soc_dapm_put_pin_switch - Set information for a pin switch
*
* @kcontrol: mixer control
* @ucontrol: Value
+ *
+ * Callback to provide information for a pin switch added at the card
+ * level.
*/
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
const char *pin = (const char *)kcontrol->private_value;
- int ret;
- snd_soc_dapm_mutex_lock(card);
- ret = __snd_soc_dapm_set_pin(&card->dapm, pin,
- !!ucontrol->value.integer.value[0]);
- snd_soc_dapm_mutex_unlock(card);
-
- snd_soc_dapm_sync(&card->dapm);
- return ret;
+ return __snd_soc_dapm_put_pin_switch(dapm, pin, ucontrol);
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
+/**
+ * snd_soc_dapm_put_component_pin_switch - Set information for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @ucontrol: Value
+ *
+ * Callback to provide information for a pin switch added at the component
+ * level.
+ */
+int snd_soc_dapm_put_component_pin_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
+ const char *pin = (const char *)kcontrol->private_value;
+
+ return __snd_soc_dapm_put_pin_switch(dapm, pin, ucontrol);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_component_pin_switch);
+
struct snd_soc_dapm_widget *
snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget)
{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
enum snd_soc_dapm_direction dir;
struct snd_soc_dapm_widget *w;
- const char *prefix;
int ret = -ENOMEM;
- if ((w = dapm_cnew_widget(widget)) == NULL)
+ w = dapm_cnew_widget(widget, soc_dapm_prefix(dapm));
+ if (!w)
goto cnew_failed;
- prefix = soc_dapm_prefix(dapm);
- if (prefix)
- w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
- else
- w->name = kstrdup_const(widget->name, GFP_KERNEL);
- if (!w->name)
- goto name_failed;
-
switch (w->id) {
case snd_soc_dapm_regulator_supply:
- w->regulator = devm_regulator_get(dapm->dev, widget->name);
+ w->regulator = devm_regulator_get(dev, widget->name);
if (IS_ERR(w->regulator)) {
ret = PTR_ERR(w->regulator);
goto request_failed;
@@ -3640,23 +3752,23 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
- dev_warn(dapm->dev,
+ dev_warn(dev,
"ASoC: Failed to bypass %s: %d\n",
w->name, ret);
}
break;
case snd_soc_dapm_pinctrl:
- w->pinctrl = devm_pinctrl_get(dapm->dev);
+ w->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(w->pinctrl)) {
ret = PTR_ERR(w->pinctrl);
goto request_failed;
}
/* set to sleep_state when initializing */
- dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD);
+ snd_soc_dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD);
break;
case snd_soc_dapm_clock_supply:
- w->clk = devm_clk_get(dapm->dev, w->name);
+ w->clk = devm_clk_get(dev, widget->name);
if (IS_ERR(w->clk)) {
ret = PTR_ERR(w->clk);
goto request_failed;
@@ -3750,10 +3862,9 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
return w;
request_failed:
- dev_err_probe(dapm->dev, ret, "ASoC: Failed to request %s\n",
+ dev_err_probe(dev, ret, "ASoC: Failed to request %s\n",
w->name);
kfree_const(w->name);
-name_failed:
kfree_const(w->sname);
kfree(w);
cnew_failed:
@@ -3795,7 +3906,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
*/
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget,
- int num)
+ unsigned int num)
{
int i;
int ret = 0;
@@ -3818,14 +3929,14 @@ static int
snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
struct snd_pcm_substream *substream)
{
+ struct device *dev = snd_soc_dapm_to_dev(w->dapm);
struct snd_soc_dapm_path *path;
struct snd_soc_dai *source, *sink;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_pcm_hw_params *params = NULL;
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
const struct snd_soc_pcm_stream *config = NULL;
struct snd_pcm_runtime *runtime = NULL;
unsigned int fmt;
- int ret = 0;
+ int ret;
/*
* NOTE
@@ -3836,15 +3947,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
* stuff that increases stack usage.
* So, we use kzalloc()/kfree() for params in this function.
*/
- params = kzalloc(sizeof(*params), GFP_KERNEL);
+ struct snd_pcm_hw_params *params __free(kfree) = kzalloc(sizeof(*params),
+ GFP_KERNEL);
if (!params)
return -ENOMEM;
runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
- if (!runtime) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!runtime)
+ return -ENOMEM;
substream->runtime = runtime;
@@ -3854,7 +3964,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
ret = snd_soc_dai_startup(source, substream);
if (ret < 0)
- goto out;
+ return ret;
snd_soc_dai_activate(source, substream->stream);
}
@@ -3865,7 +3975,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
ret = snd_soc_dai_startup(sink, substream);
if (ret < 0)
- goto out;
+ return ret;
snd_soc_dai_activate(sink, substream->stream);
}
@@ -3879,17 +3989,15 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
*/
config = rtd->dai_link->c2c_params + rtd->c2c_params_select;
if (!config) {
- dev_err(w->dapm->dev, "ASoC: link config missing\n");
- ret = -EINVAL;
- goto out;
+ dev_err(dev, "ASoC: link config missing\n");
+ return -EINVAL;
}
/* Be a little careful as we don't want to overflow the mask array */
if (!config->formats) {
- dev_warn(w->dapm->dev, "ASoC: Invalid format was specified\n");
+ dev_warn(dev, "ASoC: Invalid format was specified\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
fmt = ffs(config->formats) - 1;
@@ -3910,7 +4018,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
ret = snd_soc_dai_hw_params(source, substream, params);
if (ret < 0)
- goto out;
+ return ret;
dapm_update_dai_unlocked(substream, params, source);
}
@@ -3921,7 +4029,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
ret = snd_soc_dai_hw_params(sink, substream, params);
if (ret < 0)
- goto out;
+ return ret;
dapm_update_dai_unlocked(substream, params, sink);
}
@@ -3931,11 +4039,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
runtime->channels = params_channels(params);
runtime->rate = params_rate(params);
-out:
- /* see above NOTE */
- kfree(params);
-
- return ret;
+ return 0;
}
static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
@@ -3959,6 +4063,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;
@@ -4004,6 +4120,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMD:
kfree(substream->runtime);
+ substream->runtime = NULL;
break;
default:
@@ -4088,7 +4205,7 @@ snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
for (count = 0 ; count < num_c2c_params; count++) {
if (!config->stream_name) {
- dev_warn(card->dapm.dev,
+ dev_warn(card->dev,
"ASoC: anonymous config %d for dai link %s\n",
count, link_name);
w_param_text[count] =
@@ -4140,7 +4257,8 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
struct snd_pcm_substream *substream,
char *id)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
const struct snd_kcontrol_new *kcontrol_news;
@@ -4187,7 +4305,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card,
dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
- w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
+ w = snd_soc_dapm_new_control_unlocked(dapm, &template);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
goto outfree_kcontrol_news;
@@ -4219,10 +4337,11 @@ name_fail:
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
struct snd_soc_dai *dai)
{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
- WARN_ON(dapm->dev != dai->dev);
+ WARN_ON(dev != dai->dev);
memset(&template, 0, sizeof(template));
template.reg = SND_SOC_NOPM;
@@ -4326,7 +4445,9 @@ static void dapm_connect_dai_routes(struct snd_soc_dapm_context *dapm,
struct snd_soc_dai *sink_dai,
struct snd_soc_dapm_widget *sink)
{
- dev_dbg(dapm->dev, "connected DAI link %s:%s -> %s:%s\n",
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
+
+ dev_dbg(dev, "connected DAI link %s:%s -> %s:%s\n",
src_dai->component->name, src->name,
sink_dai->component->name, sink->name);
@@ -4343,6 +4464,7 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai,
struct snd_soc_dai *cpu_dai)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dapm_widget *codec, *cpu;
struct snd_soc_dai *src_dai[] = { cpu_dai, codec_dai };
@@ -4377,7 +4499,7 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card,
rtd->c2c_widget[stream] = dai;
}
- dapm_connect_dai_routes(&card->dapm, src_dai[stream], *src[stream],
+ dapm_connect_dai_routes(dapm, src_dai[stream], *src[stream],
rtd->c2c_widget[stream],
sink_dai[stream], *sink[stream]);
}
@@ -4424,11 +4546,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
- int i;
/* for each BE DAI link... */
for_each_card_rtds(card, rtd) {
+ struct snd_soc_dai_link_ch_map *ch_maps;
+ int i;
+
/*
* dynamic FE links have no fixed DAI mapping.
* CODEC<->CODEC links have no direct connection.
@@ -4436,39 +4561,15 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
if (rtd->dai_link->dynamic)
continue;
- if (rtd->dai_link->num_cpus == 1) {
- for_each_rtd_codec_dais(rtd, i, codec_dai)
- dapm_connect_dai_pair(card, rtd, codec_dai,
- asoc_rtd_to_cpu(rtd, 0));
- } else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) {
- for_each_rtd_codec_dais(rtd, i, codec_dai)
- dapm_connect_dai_pair(card, rtd, codec_dai,
- asoc_rtd_to_cpu(rtd, i));
- } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
- int cpu_id;
-
- if (!rtd->dai_link->codec_ch_maps) {
- dev_err(card->dev, "%s: no codec channel mapping table provided\n",
- __func__);
- continue;
- }
+ /*
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
+ */
+ for_each_rtd_ch_maps(rtd, i, ch_maps) {
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu);
+ codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec);
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
- if (cpu_id >= rtd->dai_link->num_cpus) {
- dev_err(card->dev,
- "%s: dai_link %s cpu_id %d too large, num_cpus is %d\n",
- __func__, rtd->dai_link->name, cpu_id,
- rtd->dai_link->num_cpus);
- continue;
- }
- dapm_connect_dai_pair(card, rtd, codec_dai,
- asoc_rtd_to_cpu(rtd, cpu_id));
- }
- } else {
- dev_err(card->dev,
- "%s: codec number %d < cpu number %d is not supported\n",
- __func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus);
+ dapm_connect_dai_pair(card, rtd, codec_dai, cpu_dai);
}
}
}
@@ -4482,7 +4583,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);
}
/**
@@ -4591,14 +4692,19 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
const char *pin)
{
+ struct device *dev;
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
if (!w) {
- dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
+ dev = snd_soc_dapm_to_dev(dapm);
+
+ dev_err(dev, "ASoC: unknown pin %s\n", pin);
return -EINVAL;
}
- dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
+ dev = snd_soc_dapm_to_dev(w->dapm);
+
+ dev_dbg(dev, "ASoC: force enable pin %s\n", pin);
if (!w->connected) {
/*
* w->force does not affect the number of input or output paths,
@@ -4687,57 +4793,6 @@ int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
/**
- * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
- * @dapm: DAPM context
- * @pin: pin name
- *
- * Marks the specified pin as being not connected, disabling it along
- * any parent or child widgets. At present this is identical to
- * snd_soc_dapm_disable_pin() but in future it will be extended to do
- * additional things such as disabling controls which only affect
- * paths through the pin.
- *
- * Requires external locking.
- *
- * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
- * do any widget power switching.
- */
-int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
- const char *pin)
-{
- return snd_soc_dapm_set_pin(dapm, pin, 0);
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
-
-/**
- * snd_soc_dapm_nc_pin - permanently disable pin.
- * @dapm: DAPM context
- * @pin: pin name
- *
- * Marks the specified pin as being not connected, disabling it along
- * any parent or child widgets. At present this is identical to
- * snd_soc_dapm_disable_pin() but in future it will be extended to do
- * additional things such as disabling controls which only affect
- * paths through the pin.
- *
- * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
- * do any widget power switching.
- */
-int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
-{
- int ret;
-
- snd_soc_dapm_mutex_lock(dapm);
-
- ret = snd_soc_dapm_set_pin(dapm, pin, 0);
-
- snd_soc_dapm_mutex_unlock(dapm);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
-
-/**
* snd_soc_dapm_get_pin_status - get audio pin status
* @dapm: DAPM context
* @pin: audio signal pin endpoint (or start point)
@@ -4772,10 +4827,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
const char *pin)
{
+ struct device *dev = snd_soc_dapm_to_dev(dapm);
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
if (!w) {
- dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
+ dev_err(dev, "ASoC: unknown pin %s\n", pin);
return -EINVAL;
}
@@ -4797,7 +4853,6 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
dapm_free_widgets(dapm);
list_del(&dapm->list);
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
struct snd_soc_card *card,
@@ -4809,8 +4864,7 @@ void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
if (component) {
dapm->dev = component->dev;
- dapm->idle_bias_off = !component->driver->idle_bias_on;
- dapm->suspend_bias_off = component->driver->suspend_bias_off;
+ dapm->idle_bias = component->driver->idle_bias_on;
} else {
dapm->dev = card->dev;
}
@@ -4819,7 +4873,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)
{
@@ -4861,21 +4914,20 @@ static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
*/
void snd_soc_dapm_shutdown(struct snd_soc_card *card)
{
+ struct snd_soc_dapm_context *card_dapm = snd_soc_card_to_dapm(card);
struct snd_soc_dapm_context *dapm;
for_each_card_dapms(card, dapm) {
- if (dapm != &card->dapm) {
+ if (dapm != card_dapm) {
soc_dapm_shutdown_dapm(dapm);
if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
- snd_soc_dapm_set_bias_level(dapm,
- SND_SOC_BIAS_OFF);
+ snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_OFF);
}
}
- soc_dapm_shutdown_dapm(&card->dapm);
- if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
- snd_soc_dapm_set_bias_level(&card->dapm,
- SND_SOC_BIAS_OFF);
+ soc_dapm_shutdown_dapm(card_dapm);
+ if (card_dapm->bias_level == SND_SOC_BIAS_STANDBY)
+ snd_soc_dapm_set_bias_level(card_dapm, SND_SOC_BIAS_OFF);
}
/* Module information */
diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c
index 4534a1c03e8e..d33f83ec24f2 100644
--- a/sound/soc/soc-devres.c
+++ b/sound/soc/soc-devres.c
@@ -9,43 +9,6 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-static void devm_dai_release(struct device *dev, void *res)
-{
- snd_soc_unregister_dai(*(struct snd_soc_dai **)res);
-}
-
-/**
- * devm_snd_soc_register_dai - resource-managed dai registration
- * @dev: Device used to manage component
- * @component: The component the DAIs are registered for
- * @dai_drv: DAI driver to use for the DAI
- * @legacy_dai_naming: if %true, use legacy single-name format;
- * if %false, use multiple-name format;
- */
-struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev,
- struct snd_soc_component *component,
- struct snd_soc_dai_driver *dai_drv,
- bool legacy_dai_naming)
-{
- struct snd_soc_dai **ptr;
- struct snd_soc_dai *dai;
-
- ptr = devres_alloc(devm_dai_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- dai = snd_soc_register_dai(component, dai_drv, legacy_dai_naming);
- if (dai) {
- *ptr = dai;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
-
- return dai;
-}
-EXPORT_SYMBOL_GPL(devm_snd_soc_register_dai);
-
static void devm_component_release(struct device *dev, void *res)
{
const struct snd_soc_component_driver **cmpnt_drv = res;
@@ -120,6 +83,13 @@ int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card)
}
EXPORT_SYMBOL_GPL(devm_snd_soc_register_card);
+int devm_snd_soc_register_deferrable_card(struct device *dev, struct snd_soc_card *card)
+{
+ card->devres_dev = dev;
+ return snd_soc_register_card(card);
+}
+EXPORT_SYMBOL_GPL(devm_snd_soc_register_deferrable_card);
+
#ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM
static void devm_dmaengine_pcm_release(struct device *dev, void *res)
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 3b99f619e37e..a63e942fdc0b 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -44,13 +44,13 @@ static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
* platforms which make use of the snd_dmaengine_dai_dma_data struct for their
* DAI DMA data. Internally the function will first call
* snd_hwparams_to_dma_slave_config to fill in the slave config based on the
- * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
- * remaining fields based on the DAI DMA data.
+ * hw_params, followed by snd_dmaengine_pcm_set_config_from_dai_data to fill in
+ * the remaining fields based on the DAI DMA data.
*/
int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_dmaengine_dai_dma_data *dma_data;
int ret;
@@ -60,7 +60,7 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
return -EINVAL;
}
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
if (ret)
@@ -98,7 +98,7 @@ static int
dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
struct device *dma_dev = dmaengine_dma_dev(pcm, substream);
struct dma_chan *chan = pcm->chan[substream->stream];
@@ -115,7 +115,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component,
return snd_soc_set_runtime_hwparams(substream,
pcm->config->pcm_hardware);
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
memset(&hw, 0, sizeof(hw));
hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
@@ -185,7 +185,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
return NULL;
}
- dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
+ dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0])
return pcm->chan[0];
@@ -287,37 +287,43 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
return snd_dmaengine_pcm_pointer(substream);
}
-static int dmaengine_copy_user(struct snd_soc_component *component,
- struct snd_pcm_substream *substream,
- int channel, unsigned long hwoff,
- void __user *buf, unsigned long bytes)
+static int dmaengine_copy(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ int channel, unsigned long hwoff,
+ struct iov_iter *iter, unsigned long bytes)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
int (*process)(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
- void *buf, unsigned long bytes) = pcm->config->process;
+ unsigned long bytes) = pcm->config->process;
bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
void *dma_ptr = runtime->dma_area + hwoff +
channel * (runtime->dma_bytes / runtime->channels);
if (is_playback)
- if (copy_from_user(dma_ptr, buf, bytes))
+ if (copy_from_iter(dma_ptr, bytes, iter) != bytes)
return -EFAULT;
if (process) {
- int ret = process(substream, channel, hwoff, (__force void *)buf, bytes);
+ int ret = process(substream, channel, hwoff, bytes);
if (ret < 0)
return ret;
}
if (!is_playback)
- if (copy_to_user(buf, dma_ptr, bytes))
+ if (copy_to_iter(dma_ptr, bytes, iter) != bytes)
return -EFAULT;
return 0;
}
+static int dmaengine_pcm_sync_stop(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ return snd_dmaengine_pcm_sync_stop(substream);
+}
+
static const struct snd_soc_component_driver dmaengine_pcm_component = {
.name = SND_DMAENGINE_PCM_DRV_NAME,
.probe_order = SND_SOC_COMP_ORDER_LATE,
@@ -327,6 +333,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component = {
.trigger = dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
.pcm_construct = dmaengine_pcm_new,
+ .sync_stop = dmaengine_pcm_sync_stop,
};
static const struct snd_soc_component_driver dmaengine_pcm_component_process = {
@@ -337,8 +344,9 @@ static const struct snd_soc_component_driver dmaengine_pcm_component_process = {
.hw_params = dmaengine_pcm_hw_params,
.trigger = dmaengine_pcm_trigger,
.pointer = dmaengine_pcm_pointer,
- .copy_user = dmaengine_copy_user,
+ .copy = dmaengine_copy,
.pcm_construct = dmaengine_pcm_new,
+ .sync_stop = dmaengine_pcm_sync_stop,
};
static const char * const dmaengine_pcm_dma_channel_names[] = {
@@ -441,6 +449,9 @@ int snd_dmaengine_pcm_register(struct device *dev,
pcm->config = config;
pcm->flags = flags;
+ if (config->name)
+ pcm->component.name = config->name;
+
ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
if (ret)
goto err_free_dma;
@@ -491,4 +502,5 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
+MODULE_DESCRIPTION("ASoC helpers for generic PCM dmaengine API");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index f951acb2ce36..05985ccec571 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -8,7 +8,6 @@
#include <sound/jack.h>
#include <sound/soc.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
@@ -37,11 +36,11 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
struct snd_soc_jack_pin *pin;
unsigned int sync = 0;
- if (!jack)
+ if (!jack || !jack->jack)
return;
trace_snd_soc_jack_report(jack, mask, status);
- dapm = &jack->card->dapm;
+ dapm = snd_soc_card_to_dapm(jack->card);
mutex_lock(&jack->mutex);
@@ -345,21 +344,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
goto undo;
}
} else {
- /* legacy GPIO number */
- if (!gpio_is_valid(gpios[i].gpio)) {
- dev_err(jack->card->dev,
- "ASoC: Invalid gpio %d\n",
- gpios[i].gpio);
- ret = -EINVAL;
- goto undo;
- }
-
- ret = gpio_request_one(gpios[i].gpio, GPIOF_IN,
- gpios[i].name);
- if (ret)
- goto undo;
-
- gpios[i].desc = gpio_to_desc(gpios[i].gpio);
+ dev_err(jack->card->dev, "ASoC: Invalid gpio at index %d\n", i);
+ ret = -EINVAL;
+ goto undo;
}
got_gpio:
INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
@@ -373,7 +360,7 @@ got_gpio:
gpios[i].name,
&gpios[i]);
if (ret < 0)
- goto err;
+ goto undo;
if (gpios[i].wake) {
ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1);
@@ -401,8 +388,6 @@ got_gpio:
devres_add(jack->card->dev, tbl);
return 0;
-err:
- gpio_free(gpios[i].gpio);
undo:
jack_free_gpios(jack, i, gpios);
devres_free(tbl);
diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c
index 619664cc9ab9..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);
}
/*
@@ -35,7 +21,7 @@ static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd,
* In such case, we can update these macros.
*/
#define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream)
-#define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL)
+#define soc_link_mark_pop(rtd, tgt) ((rtd)->mark_##tgt = NULL)
#define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream)
int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd)
@@ -67,7 +53,7 @@ int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
int snd_soc_link_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
@@ -84,7 +70,7 @@ int snd_soc_link_startup(struct snd_pcm_substream *substream)
void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rollback && !soc_link_mark_match(rtd, substream, startup))
return;
@@ -94,12 +80,12 @@ void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
rtd->dai_link->ops->shutdown(substream);
/* remove marked substream */
- soc_link_mark_pop(rtd, substream, startup);
+ soc_link_mark_pop(rtd, startup);
}
int snd_soc_link_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
@@ -112,7 +98,7 @@ int snd_soc_link_prepare(struct snd_pcm_substream *substream)
int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
@@ -128,7 +114,7 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
return;
@@ -138,12 +124,12 @@ void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
rtd->dai_link->ops->hw_free(substream);
/* remove marked substream */
- soc_link_mark_pop(rtd, substream, hw_params);
+ soc_link_mark_pop(rtd, hw_params);
}
static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
@@ -156,7 +142,7 @@ static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
switch (cmd) {
@@ -175,7 +161,7 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
break;
ret = soc_link_trigger(substream, cmd);
- soc_link_mark_pop(rtd, substream, startup);
+ soc_link_mark_pop(rtd, startup);
}
return ret;
@@ -209,7 +195,7 @@ void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
rtd->dai_link->compr_ops->shutdown)
rtd->dai_link->compr_ops->shutdown(cstream);
- soc_link_mark_pop(rtd, cstream, compr_startup);
+ soc_link_mark_pop(rtd, compr_startup);
}
EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown);
diff --git a/sound/soc/soc-ops-test.c b/sound/soc/soc-ops-test.c
new file mode 100644
index 000000000000..1bafa5626d48
--- /dev/null
+++ b/sound/soc/soc-ops-test.c
@@ -0,0 +1,548 @@
+// 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,
+ };
+ unsigned int val;
+ int ret;
+ /* it is too large struct. use kzalloc() */
+ struct snd_ctl_elem_value *result;
+
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
+ if (!result)
+ return;
+
+ 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)
+ goto end;
+
+ 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);
+end:
+ kfree(result);
+}
+
+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 55b009d3c681..ce86978c158d 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -11,6 +11,7 @@
// with code, comments and ideas from :-
// Richard Purdie <richard@openedhand.com>
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -23,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>
/**
@@ -37,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;
@@ -56,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;
@@ -87,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;
@@ -110,95 +110,224 @@ 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 sdca_soc_q78_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
+ unsigned int mask, unsigned int shift, int max)
+{
+ int val = reg_val;
+
+ if (WARN_ON(!mc->shift))
+ return -EINVAL;
+
+ val = sign_extend32(val, mc->sign_bit);
+ val = (((val * 100) >> 8) / (int)mc->shift);
+ val -= mc->min;
+
+ return val & mask;
+}
+
+static unsigned int sdca_soc_q78_ctl_to_reg(struct soc_mixer_control *mc, int val,
+ unsigned int mask, unsigned int shift, int max)
+{
+ unsigned int ret_val;
+ int reg_val;
+
+ if (WARN_ON(!mc->shift))
+ return -EINVAL;
+
+ reg_val = val + mc->min;
+ ret_val = (int)((reg_val * mc->shift) << 8) / 100;
+
+ return ret_val & mask;
+}
+
+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 = clamp(val, mc->min, mc->max);
+ 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)
+{
+ unsigned int (*ctl_to_reg)(struct soc_mixer_control *, int, unsigned int, unsigned int, int);
+ 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;
+ if (mc->sdca_q78) {
+ ctl_to_reg = sdca_soc_q78_ctl_to_reg;
+ val_mask = mask;
+ } else {
+ ctl_to_reg = soc_mixer_ctl_to_reg;
+ val_mask = mask << mc->shift;
+ }
- if (!sign_bit) {
- *signed_val = val;
- return 0;
+ ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max);
+ if (ret)
+ return ret;
+
+ val1 = ctl_to_reg(mc, ucontrol->value.integer.value[0],
+ mask, mc->shift, max);
+
+ 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 |= ctl_to_reg(mc, ucontrol->value.integer.value[1], mask, mc->rshift, max);
+ val_mask |= mask << mc->rshift;
+ } else {
+ val2 = 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)
+{
+ int (*reg_to_ctl)(struct soc_mixer_control *, unsigned int, unsigned int, unsigned int, int);
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int reg_val;
+ int val;
+
+ if (mc->sdca_q78)
+ reg_to_ctl = sdca_soc_q78_reg_to_ctl;
+ else
+ reg_to_ctl = soc_mixer_reg_to_ctl;
+
+ reg_val = snd_soc_component_read(component, mc->reg);
+ val = reg_to_ctl(mc, reg_val, mask, mc->shift, max);
- *signed_val = ret;
+ ucontrol->value.integer.value[0] = val;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (mc->reg == mc->rreg) {
+ val = reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
+ } else {
+ reg_val = snd_soc_component_read(component, mc->rreg);
+ val = 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);
@@ -220,165 +349,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 = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- int val;
- int ret;
+ unsigned int mask = soc_mixer_mask(mc);
- 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];
-
- 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;
+ unsigned int mask = soc_mixer_mask(mc);
- 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;
- }
- }
-
- return ret;
+ return soc_put_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
@@ -393,30 +407,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);
@@ -432,212 +429,44 @@ 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;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
+ uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
+ if (!uctl)
+ return -ENOMEM;
-/**
- * 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;
+ ret = kctl->get(kctl, uctl);
+ if (ret < 0)
+ goto out;
- 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;
+ if (uctl->value.integer.value[0] > mc->platform_max)
+ uctl->value.integer.value[0] = mc->platform_max;
- 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) &&
+ uctl->value.integer.value[1] > mc->platform_max)
+ uctl->value.integer.value[1] = 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 (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;
- }
- }
+ ret = kctl->put(kctl, uctl);
+out:
+ kfree(uctl);
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;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
/**
* snd_soc_limit_volume - Set new limit to an existing volume control.
@@ -648,8 +477,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;
@@ -660,12 +488,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;
- if (max <= mc->max) {
+ 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);
@@ -725,16 +556,16 @@ 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;
- void *data;
+ int ret, len;
if (!component->regmap || !params->num_regs)
return -EINVAL;
len = params->num_regs * component->val_bytes;
- data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
+ void *data __free(kfree) = kmemdup(ucontrol->value.bytes.data, len,
+ GFP_KERNEL | GFP_DMA);
if (!data)
return -ENOMEM;
@@ -746,7 +577,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
if (params->mask) {
ret = regmap_read(component->regmap, params->base, &val);
if (ret != 0)
- goto out;
+ return ret;
val &= params->mask;
@@ -757,54 +588,43 @@ 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)
- goto out;
+ 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)
- goto out;
+ return ret;
((u16 *)data)[0] |= val;
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)
- goto out;
+ 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)
- goto out;
+ return ret;
((u32 *)data)[0] |= val;
break;
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
}
- ret = regmap_raw_write(component->regmap, params->base,
- data, len);
-
-out:
- kfree(data);
-
- return ret;
+ return regmap_raw_write(component->regmap, params->base, data, len);
}
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;
@@ -816,7 +636,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;
@@ -832,6 +652,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);
@@ -841,17 +662,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;
@@ -866,16 +689,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 =
@@ -883,23 +707,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;
@@ -911,16 +733,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 =
@@ -928,24 +751,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)
@@ -966,22 +790,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;
@@ -999,24 +822,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 6fc90bc25317..6b134962c71c 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -30,54 +30,120 @@
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;
+ return snd_soc_ret(rtd->dev, ret,
+ "at %s() on %s\n", func, rtd->dai_link->name);
+}
- /* 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);
+/* is the current PCM operation for this FE ? */
+#if 0
+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;
+ return 0;
+}
+#endif
+
+/* is the current PCM operation for this BE ? */
+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) ||
+ ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
+ be->dpcm[stream].runtime_update))
+ return 1;
+ return 0;
+}
+
+static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be,
+ int stream,
+ const enum snd_soc_dpcm_state *states,
+ int num_states)
+{
+ struct snd_soc_dpcm *dpcm;
+ int state;
+ int ret = 1;
+ int i;
+
+ for_each_dpcm_fe(be, stream, dpcm) {
+
+ if (dpcm->fe == fe)
+ continue;
+
+ state = dpcm->fe->dpcm[stream].state;
+ for (i = 0; i < num_states; i++) {
+ if (state == states[i]) {
+ ret = 0;
+ break;
+ }
+ }
}
+ /* it's safe to do this BE DAI */
return ret;
}
-static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd,
- int stream)
+/*
+ * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
+ * are not running, paused or suspended for the specified stream direction.
+ */
+static int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
{
- snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream));
-}
+ const enum snd_soc_dpcm_state state[] = {
+ SND_SOC_DPCM_STATE_START,
+ SND_SOC_DPCM_STATE_PAUSED,
+ SND_SOC_DPCM_STATE_SUSPEND,
+ };
-#define snd_soc_dpcm_stream_lock_irqsave_nested(rtd, stream, flags) \
- snd_pcm_stream_lock_irqsave_nested(snd_soc_dpcm_get_substream(rtd, stream), flags)
+ return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
+}
-static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd,
- int stream)
+/*
+ * We can only change hw params a BE DAI if any of it's FE are not prepared,
+ * running, paused or suspended for the specified stream direction.
+ */
+static int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
{
- snd_pcm_stream_unlock_irq(snd_soc_dpcm_get_substream(rtd, stream));
+ const enum snd_soc_dpcm_state state[] = {
+ SND_SOC_DPCM_STATE_START,
+ SND_SOC_DPCM_STATE_PAUSED,
+ SND_SOC_DPCM_STATE_SUSPEND,
+ SND_SOC_DPCM_STATE_PREPARE,
+ };
+
+ return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
}
-#define snd_soc_dpcm_stream_unlock_irqrestore(rtd, stream, flags) \
- snd_pcm_stream_unlock_irqrestore(snd_soc_dpcm_get_substream(rtd, stream), flags)
+/*
+ * We can only prepare a BE DAI if any of it's FE are not prepared,
+ * running or paused for the specified stream direction.
+ */
+static int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
+{
+ const enum snd_soc_dpcm_state state[] = {
+ SND_SOC_DPCM_STATE_START,
+ SND_SOC_DPCM_STATE_PAUSED,
+ SND_SOC_DPCM_STATE_PREPARE,
+ };
+
+ return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
+}
#define DPCM_MAX_BE_USERS 8
static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd)
{
- return (rtd)->dai_link->num_cpus == 1 ? asoc_rtd_to_cpu(rtd, 0)->name : "multicpu";
+ return (rtd)->dai_link->num_cpus == 1 ? snd_soc_rtd_to_cpu(rtd, 0)->name : "multicpu";
}
static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd)
{
- return (rtd)->dai_link->num_codecs == 1 ? asoc_rtd_to_codec(rtd, 0)->name : "multicodec";
+ 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) {
@@ -106,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)
{
@@ -171,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)
@@ -183,7 +248,7 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
snd_soc_dpcm_mutex_lock(fe);
for_each_pcm_streams(stream)
- if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
+ if (snd_soc_dai_stream_valid(snd_soc_rtd_to_cpu(fe, 0), stream))
offset += dpcm_show_state(fe, stream,
buf + offset,
out_count - offset);
@@ -221,7 +286,7 @@ static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
char *name;
name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
- stream ? "capture" : "playback");
+ snd_pcm_direction_name(stream));
if (name) {
dpcm->debugfs_state = debugfs_create_dir(
name, dpcm->fe->debugfs_dpcm_root);
@@ -259,14 +324,14 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
struct snd_pcm_substream *substream =
snd_soc_dpcm_get_substream(fe, stream);
- snd_soc_dpcm_stream_lock_irq(fe, stream);
+ snd_pcm_stream_lock_irq(substream);
if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
dpcm_fe_dai_do_trigger(substream,
fe->dpcm[stream].trigger_pending - 1);
fe->dpcm[stream].trigger_pending = 0;
}
fe->dpcm[stream].runtime_update = state;
- snd_soc_dpcm_stream_unlock_irq(fe, stream);
+ snd_pcm_stream_unlock_irq(substream);
}
static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
@@ -291,6 +356,7 @@ static void dpcm_set_be_update_state(struct snd_soc_pcm_runtime *be,
void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
int stream, int action)
{
+ struct snd_soc_component *component;
struct snd_soc_dai *dai;
int i;
@@ -298,6 +364,13 @@ void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
for_each_rtd_dais(rtd, i, dai)
snd_soc_dai_action(dai, stream, action);
+
+ /* Increments/Decrements the active count for components without DAIs */
+ for_each_rtd_components(rtd, i, component) {
+ if (component->num_dai)
+ continue;
+ component->active += action;
+ }
}
EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
@@ -306,44 +379,28 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
* @rtd: The ASoC PCM runtime that should be checked.
*
* This function checks whether the power down delay should be ignored for a
- * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
+ * specific PCM runtime. Returns true if the delay is 0, if the DAI link has
* been configured to ignore the delay, or if none of the components benefits
* from having the delay.
*/
bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *component;
- bool ignore = true;
int i;
if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
return true;
for_each_rtd_components(rtd, i, component)
- ignore &= !component->driver->use_pmdown_time;
+ if (component->driver->use_pmdown_time)
+ /* No need to go through all components */
+ return false;
- return ignore;
+ return true;
}
-/**
- * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
- * @substream: the pcm substream
- * @hw: the hardware parameters
- *
- * Sets the substream runtime hardware parameters.
- */
-int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
- const struct snd_pcm_hardware *hw)
-{
- substream->runtime->hw = *hw;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
-
/* 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;
@@ -364,48 +421,43 @@ 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,
struct snd_pcm_hw_params *params)
{
if (params) {
- dai->rate = params_rate(params);
- dai->channels = params_channels(params);
- dai->sample_bits = snd_pcm_format_physical_width(params_format(params));
+ dai->symmetric_rate = params_rate(params);
+ dai->symmetric_channels = params_channels(params);
+ dai->symmetric_sample_bits = snd_pcm_format_physical_width(params_format(params));
} else {
- dai->rate = 0;
- dai->channels = 0;
- dai->sample_bits = 0;
+ dai->symmetric_rate = 0;
+ dai->symmetric_channels = 0;
+ dai->symmetric_sample_bits = 0;
}
}
static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
struct snd_soc_dai *soc_dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret;
if (!snd_soc_dai_active(soc_dai))
return 0;
#define __soc_pcm_apply_symmetry(name, NAME) \
- if (soc_dai->name && (soc_dai->driver->symmetric_##name || \
- rtd->dai_link->symmetric_##name)) { \
+ if (soc_dai->symmetric_##name && \
+ (soc_dai->driver->symmetric_##name || rtd->dai_link->symmetric_##name)) { \
dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\
- #name, soc_dai->name); \
+ #name, soc_dai->symmetric_##name); \
\
ret = snd_pcm_hw_constraint_single(substream->runtime, \
SNDRV_PCM_HW_PARAM_##NAME,\
- soc_dai->name); \
- if (ret < 0) { \
- dev_err(soc_dai->dev, \
- "ASoC: Unable to apply %s constraint: %d\n",\
- #name, ret); \
- return ret; \
- } \
+ soc_dai->symmetric_##name); \
+ if (ret < 0) \
+ return snd_soc_ret(soc_dai->dev, ret, \
+ "Unable to apply %s constraint\n", #name); \
}
__soc_pcm_apply_symmetry(rate, RATE);
@@ -418,7 +470,7 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai d;
struct snd_soc_dai *dai;
struct snd_soc_dai *cpu_dai;
@@ -435,11 +487,12 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
if (symmetry) \
for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
if (!snd_soc_dai_is_dummy(cpu_dai) && \
- cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \
- dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \
- #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \
- return -EINVAL; \
- }
+ cpu_dai->symmetric_##xxx && \
+ 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);
@@ -451,7 +504,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
static void soc_pcm_update_symmetry(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai_link *link = rtd->dai_link;
struct snd_soc_dai *dai;
unsigned int symmetry, i;
@@ -472,7 +525,7 @@ static void soc_pcm_update_symmetry(struct snd_pcm_substream *substream)
static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret;
if (!bits)
@@ -486,7 +539,7 @@ static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
int stream = substream->stream;
@@ -494,7 +547,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
unsigned int bits = 0, cpu_bits = 0;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
+ const struct snd_soc_pcm_stream *pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
if (pcm_codec->sig_bits == 0) {
bits = 0;
@@ -504,7 +557,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
}
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
+ const struct snd_soc_pcm_stream *pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
if (pcm_cpu->sig_bits == 0) {
cpu_bits = 0;
@@ -517,18 +570,30 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
soc_pcm_set_msb(substream, cpu_bits);
}
-static void soc_pcm_hw_init(struct snd_pcm_hardware *hw)
+static void soc_pcm_hw_init(struct snd_pcm_hardware *hw, bool force)
{
- hw->rates = UINT_MAX;
- hw->rate_min = 0;
- hw->rate_max = UINT_MAX;
- hw->channels_min = 0;
- hw->channels_max = UINT_MAX;
- hw->formats = ULLONG_MAX;
+ if (force) {
+ hw->rates = UINT_MAX;
+ hw->rate_min = 0;
+ hw->rate_max = UINT_MAX;
+ hw->channels_min = 0;
+ hw->channels_max = UINT_MAX;
+ hw->formats = ULLONG_MAX;
+ } else {
+ /* Preserve initialized parameters */
+ if (!hw->rates)
+ hw->rates = UINT_MAX;
+ if (!hw->rate_max)
+ hw->rate_max = UINT_MAX;
+ if (!hw->channels_max)
+ hw->channels_max = UINT_MAX;
+ if (!hw->formats)
+ hw->formats = ULLONG_MAX;
+ }
}
static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
- struct snd_soc_pcm_stream *p)
+ const struct snd_soc_pcm_stream *p)
{
hw->rates = snd_pcm_rate_mask_intersect(hw->rates, p->rates);
@@ -541,16 +606,17 @@ static void soc_pcm_hw_update_rate(struct snd_pcm_hardware *hw,
}
static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
- struct snd_soc_pcm_stream *p)
+ const struct snd_soc_pcm_stream *p)
{
hw->channels_min = max(hw->channels_min, p->channels_min);
hw->channels_max = min(hw->channels_max, p->channels_max);
}
static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
- struct snd_soc_pcm_stream *p)
+ const struct snd_soc_pcm_stream *p)
{
- hw->formats &= p->formats;
+ hw->formats &= p->formats;
+ hw->subformats &= p->subformats;
}
/**
@@ -567,12 +633,12 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
- struct snd_soc_pcm_stream *codec_stream;
- struct snd_soc_pcm_stream *cpu_stream;
+ const struct snd_soc_pcm_stream *codec_stream;
+ const struct snd_soc_pcm_stream *cpu_stream;
unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
int i;
- soc_pcm_hw_init(hw);
+ soc_pcm_hw_init(hw, true);
/* first calculate min/max only for CPUs in the DAI link */
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
@@ -635,7 +701,7 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
{
struct snd_pcm_hardware *hw = &substream->runtime->hw;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
u64 formats = hw->formats;
/*
@@ -651,7 +717,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
static int soc_pcm_components_open(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret = 0;
@@ -671,7 +737,7 @@ static int soc_pcm_components_open(struct snd_pcm_substream *substream)
static int soc_pcm_components_close(struct snd_pcm_substream *substream,
int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret = 0;
@@ -697,17 +763,15 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
if (!rollback) {
snd_soc_runtime_deactivate(rtd, substream->stream);
- /* clear the corresponding DAIs parameters when going to be inactive */
+
+ /* Make sure DAI parameters cleared if the DAI becomes inactive */
for_each_rtd_dais(rtd, i, dai) {
if (snd_soc_dai_active(dai) == 0)
soc_pcm_set_dai_params(dai, NULL);
-
- if (snd_soc_dai_stream_active(dai, substream->stream) == 0)
- snd_soc_dai_digital_mute(dai, 1, substream->stream);
}
}
- for_each_rtd_dais(rtd, i, dai)
+ for_each_rtd_dais_reverse(rtd, i, dai)
snd_soc_dai_shutdown(dai, substream, rollback);
snd_soc_link_shutdown(substream, rollback);
@@ -737,7 +801,7 @@ static int __soc_pcm_close(struct snd_soc_pcm_runtime *rtd,
/* PCM close ops for non-DPCM streams */
static int soc_pcm_close(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
snd_soc_dpcm_mutex_lock(rtd);
__soc_pcm_close(rtd, substream);
@@ -747,7 +811,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
static int soc_hw_sanity_check(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_hardware *hw = &substream->runtime->hw;
const char *name_cpu = soc_cpu_dai_name(rtd);
const char *name_codec = soc_codec_dai_name(rtd);
@@ -778,9 +842,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);
}
/*
@@ -853,7 +916,7 @@ err:
/* PCM open ops for non-DPCM streams */
static int soc_pcm_open(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret;
snd_soc_dpcm_mutex_lock(rtd);
@@ -897,22 +960,37 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd,
snd_soc_dapm_stream_event(rtd, substream->stream,
SND_SOC_DAPM_STREAM_START);
- for_each_rtd_dais(rtd, i, dai)
- snd_soc_dai_digital_mute(dai, 0, substream->stream);
+ for_each_rtd_dais(rtd, i, dai) {
+ 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 */
static int soc_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret;
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;
}
@@ -935,6 +1013,17 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
snd_soc_dpcm_mutex_assert_held(rtd);
+ /* clear the corresponding DAIs parameters when going to be inactive */
+ for_each_rtd_dais(rtd, i, dai) {
+ if (snd_soc_dai_active(dai) == 1)
+ soc_pcm_set_dai_params(dai, NULL);
+
+ if (snd_soc_dai_stream_active(dai, substream->stream) == 1) {
+ if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai))
+ snd_soc_dai_digital_mute(dai, 1, substream->stream);
+ }
+ }
+
/* run the stream event */
snd_soc_dapm_stream_stop(rtd, substream->stream);
@@ -964,7 +1053,7 @@ static int __soc_pcm_hw_free(struct snd_soc_pcm_runtime *rtd,
/* hw_free PCM ops for non-DPCM streams */
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret;
snd_soc_dpcm_mutex_lock(rtd);
@@ -978,12 +1067,13 @@ 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;
int i, ret = 0;
snd_soc_dpcm_mutex_assert_held(rtd);
@@ -997,7 +1087,6 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
goto out;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- struct snd_pcm_hw_params codec_params;
unsigned int tdm_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream);
/*
@@ -1018,23 +1107,23 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
continue;
/* copy params for each codec */
- codec_params = *params;
+ tmp_params = *params;
/* fixup params based on TDM slot masks */
if (tdm_mask)
- soc_pcm_codec_params_fixup(&codec_params, tdm_mask);
+ soc_pcm_codec_params_fixup(&tmp_params, tdm_mask);
ret = snd_soc_dai_hw_params(codec_dai, substream,
- &codec_params);
+ &tmp_params);
if(ret < 0)
goto out;
- soc_pcm_set_dai_params(codec_dai, &codec_params);
- snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
+ soc_pcm_set_dai_params(codec_dai, &tmp_params);
+ snd_soc_dapm_update_dai(substream, &tmp_params, codec_dai);
}
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- struct snd_pcm_hw_params cpu_params;
+ struct snd_soc_dai_link_ch_map *ch_maps;
unsigned int ch_mask = 0;
int j;
@@ -1046,31 +1135,29 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
continue;
/* copy params for each cpu */
- cpu_params = *params;
+ tmp_params = *params;
- if (!rtd->dai_link->codec_ch_maps)
- goto hw_params;
/*
* construct cpu channel mask by combining ch_mask of each
* codec which maps to the cpu.
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
*/
- for_each_rtd_codec_dais(rtd, j, codec_dai) {
- if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id == i)
- ch_mask |= rtd->dai_link->codec_ch_maps[j].ch_mask;
- }
+ for_each_rtd_ch_maps(rtd, j, ch_maps)
+ if (ch_maps->cpu == i)
+ ch_mask |= ch_maps->ch_mask;
/* fixup cpu channel number */
if (ch_mask)
- soc_pcm_codec_params_fixup(&cpu_params, ch_mask);
+ soc_pcm_codec_params_fixup(&tmp_params, ch_mask);
-hw_params:
- ret = snd_soc_dai_hw_params(cpu_dai, substream, &cpu_params);
+ ret = snd_soc_dai_hw_params(cpu_dai, substream, &tmp_params);
if (ret < 0)
goto out;
/* store the parameters for each DAI */
- soc_pcm_set_dai_params(cpu_dai, &cpu_params);
- snd_soc_dapm_update_dai(substream, &cpu_params, cpu_dai);
+ soc_pcm_set_dai_params(cpu_dai, &tmp_params);
+ snd_soc_dapm_update_dai(substream, &tmp_params, cpu_dai);
}
ret = snd_soc_pcm_component_hw_params(substream, params);
@@ -1085,11 +1172,11 @@ out:
static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(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;
}
@@ -1110,7 +1197,7 @@ static int (* const trigger[][TRIGGER_MAX])(struct snd_pcm_substream *substream,
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component;
int ret = 0, r = 0, i;
int rollback = 0;
@@ -1219,19 +1306,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;
@@ -1244,13 +1330,13 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
dpcm->be = be;
dpcm->fe = fe;
dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
- snd_soc_dpcm_stream_lock_irq(fe, stream);
+ snd_pcm_stream_lock_irq(fe_substream);
list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
- snd_soc_dpcm_stream_unlock_irq(fe, stream);
+ snd_pcm_stream_unlock_irq(fe_substream);
dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
- stream ? "capture" : "playback", fe->dai_link->name,
+ snd_pcm_direction_name(stream), fe->dai_link->name,
stream ? "<-" : "->", be->dai_link->name);
dpcm_create_debugfs_state(dpcm, stream);
@@ -1278,7 +1364,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
continue;
dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
- stream ? "capture" : "playback",
+ snd_pcm_direction_name(stream),
dpcm->fe->dai_link->name,
stream ? "<-" : "->", dpcm->be->dai_link->name);
@@ -1292,21 +1378,22 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm, *d;
+ struct snd_pcm_substream *substream = snd_soc_dpcm_get_substream(fe, stream);
LIST_HEAD(deleted_dpcms);
snd_soc_dpcm_mutex_assert_held(fe);
- snd_soc_dpcm_stream_lock_irq(fe, stream);
+ snd_pcm_stream_lock_irq(substream);
for_each_dpcm_be_safe(fe, stream, dpcm, d) {
dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n",
- stream ? "capture" : "playback",
+ snd_pcm_direction_name(stream),
dpcm->be->dai_link->name);
if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
continue;
dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
- stream ? "capture" : "playback", fe->dai_link->name,
+ snd_pcm_direction_name(stream), fe->dai_link->name,
stream ? "<-" : "->", dpcm->be->dai_link->name);
/* BEs still alive need new FE */
@@ -1315,7 +1402,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
list_del(&dpcm->list_be);
list_move(&dpcm->list_fe, &deleted_dpcms);
}
- snd_soc_dpcm_stream_unlock_irq(fe, stream);
+ snd_pcm_stream_unlock_irq(substream);
while (!list_empty(&deleted_dpcms)) {
dpcm = list_first_entry(&deleted_dpcms, struct snd_soc_dpcm,
@@ -1376,7 +1463,7 @@ EXPORT_SYMBOL_GPL(widget_in_list);
bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir)
{
- struct snd_soc_card *card = widget->dapm->card;
+ struct snd_soc_card *card = snd_soc_dapm_to_card(widget->dapm);
struct snd_soc_pcm_runtime *rtd;
int stream;
@@ -1397,14 +1484,12 @@ EXPORT_SYMBOL_GPL(dpcm_end_walk_at_be);
int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list)
{
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
+ 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,
@@ -1413,10 +1498,10 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
if (paths > 0)
dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
- stream ? "capture" : "playback");
+ snd_pcm_direction_name(stream));
else if (paths == 0)
dev_dbg(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name,
- stream ? "capture" : "playback");
+ snd_pcm_direction_name(stream));
return paths;
}
@@ -1459,7 +1544,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
continue;
dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
- stream ? "capture" : "playback",
+ snd_pcm_direction_name(stream),
dpcm->be->dai_link->name, fe->dai_link->name);
dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
dpcm_set_be_update_state(dpcm->be, stream, SND_SOC_DPCM_UPDATE_BE);
@@ -1470,8 +1555,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_;
@@ -1511,10 +1596,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
/*
* Filter for systems with 'component_chaining' enabled.
* This helps to avoid unnecessary re-configuration of an
- * already active BE on such systems.
+ * already active BE on such systems and ensures the BE DAI
+ * widget is powered ON after hw_params() BE DAI callback.
*/
if (fe->card->component_chaining &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
continue;
@@ -1536,19 +1624,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;
@@ -1572,13 +1647,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",
- stream ? "capture" : "playback",
- be->dpcm[stream].state);
+ dev_err(be->dev, "ASoC: no users %s at close - state %s\n",
+ snd_pcm_direction_name(stream),
+ dpcm_state_string(be->dpcm[stream].state));
continue;
}
@@ -1617,19 +1692,19 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
if (!be_substream) {
dev_err(be->dev, "ASoC: no backend %s stream\n",
- stream ? "capture" : "playback");
+ snd_pcm_direction_name(stream));
continue;
}
/* 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",
- stream ? "capture" : "playback",
- be->dpcm[stream].state);
+ dev_err(be->dev, "ASoC: too many users %s at open %s\n",
+ snd_pcm_direction_name(stream),
+ dpcm_state_string(be->dpcm[stream].state));
continue;
}
@@ -1641,16 +1716,16 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
continue;
dev_dbg(be->dev, "ASoC: open %s BE %s\n",
- stream ? "capture" : "playback", be->dai_link->name);
+ snd_pcm_direction_name(stream), be->dai_link->name);
be_substream->runtime = fe_substream->runtime;
err = __soc_pcm_open(be, be_substream);
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",
- stream ? "capture" : "playback",
- be->dpcm[stream].state);
+ dev_err(be->dev, "ASoC: no users %s at unwind %s\n",
+ snd_pcm_direction_name(stream),
+ dpcm_state_string(be->dpcm[stream].state));
be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
goto unwind;
@@ -1670,21 +1745,17 @@ unwind:
static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw;
struct snd_soc_dai *dai;
int stream = substream->stream;
- u64 formats = hw->formats;
int i;
- soc_pcm_hw_init(hw);
-
- if (formats)
- hw->formats &= formats;
+ soc_pcm_hw_init(hw, false);
for_each_rtd_cpu_dais(fe, i, dai) {
- struct snd_soc_pcm_stream *cpu_stream;
+ const struct snd_soc_pcm_stream *cpu_stream;
/*
* Skip CPUs which don't support the current stream
@@ -1704,7 +1775,7 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw;
struct snd_soc_dpcm *dpcm;
@@ -1721,7 +1792,7 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
for_each_dpcm_be(fe, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
- struct snd_soc_pcm_stream *codec_stream;
+ const struct snd_soc_pcm_stream *codec_stream;
int i;
for_each_rtd_codec_dais(be, i, dai) {
@@ -1741,7 +1812,7 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw;
struct snd_soc_dpcm *dpcm;
@@ -1757,7 +1828,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
for_each_dpcm_be(fe, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
- struct snd_soc_pcm_stream *cpu_stream;
+ const struct snd_soc_pcm_stream *cpu_stream;
struct snd_soc_dai *dai;
int i;
@@ -1779,8 +1850,8 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
* DAIs connected to a single CPU DAI, use CPU DAI's directly
*/
if (be->dai_link->num_codecs == 1) {
- struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream(
- asoc_rtd_to_codec(be, 0), stream);
+ const struct snd_soc_pcm_stream *codec_stream = snd_soc_dai_get_pcm_stream(
+ snd_soc_rtd_to_codec(be, 0), stream);
soc_pcm_hw_update_chan(hw, codec_stream);
}
@@ -1789,7 +1860,7 @@ static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream)
static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw;
struct snd_soc_dpcm *dpcm;
@@ -1805,7 +1876,7 @@ static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream)
for_each_dpcm_be(fe, stream, dpcm) {
struct snd_soc_pcm_runtime *be = dpcm->be;
- struct snd_soc_pcm_stream *pcm;
+ const struct snd_soc_pcm_stream *pcm;
struct snd_soc_dai *dai;
int i;
@@ -1828,7 +1899,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
int stream)
{
struct snd_soc_dpcm *dpcm;
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(fe_substream);
struct snd_soc_dai *fe_cpu_dai;
int err = 0;
int i;
@@ -1855,7 +1926,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
if (!be_substream)
continue;
- rtd = asoc_substream_to_rtd(be_substream);
+ rtd = snd_soc_substream_to_rtd(be_substream);
if (rtd->dai_link->be_hw_params_fixup)
continue;
@@ -1874,7 +1945,7 @@ error:
static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(fe_substream);
int stream = fe_substream->stream, ret = 0;
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
@@ -1911,7 +1982,7 @@ be_err:
static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int stream = substream->stream;
snd_soc_dpcm_mutex_assert_held(fe);
@@ -1947,7 +2018,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 */
@@ -1977,7 +2048,7 @@ void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int stream = substream->stream;
snd_soc_dpcm_mutex_lock(fe);
@@ -2013,7 +2084,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 */
@@ -2041,7 +2112,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;
@@ -2058,7 +2129,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 */
@@ -2080,7 +2151,7 @@ unwind:
static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int ret, stream = substream->stream;
snd_soc_dpcm_mutex_lock(fe);
@@ -2097,7 +2168,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
@@ -2125,10 +2196,10 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
be = dpcm->be;
be_substream = snd_soc_dpcm_get_substream(be, stream);
- snd_soc_dpcm_stream_lock_irqsave_nested(be, stream, flags);
+ 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",
@@ -2272,7 +2343,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
break;
}
next:
- snd_soc_dpcm_stream_unlock_irqrestore(be, stream, flags);
+ snd_pcm_stream_unlock_irqrestore(be_substream, flags);
if (ret)
break;
}
@@ -2283,7 +2354,7 @@ EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
int cmd, bool fe_first)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int ret;
/* call trigger on the frontend before the backend. */
@@ -2293,78 +2364,41 @@ 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)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ 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;
- }
- break;
- case SND_SOC_DPCM_TRIGGER_BESPOKE:
- /* bespoke trigger() - handles both FE and BEs */
-
- dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d\n",
- fe->dai_link->name, cmd);
-
- ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
+ fe_first = false;
break;
default:
dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
@@ -2373,12 +2407,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:
@@ -2401,7 +2449,7 @@ out:
static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int stream = substream->stream;
/* if FE's runtime_update is already set, we're in race;
@@ -2428,7 +2476,10 @@ 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))
continue;
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
@@ -2447,12 +2498,18 @@ 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)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int stream = substream->stream, ret = 0;
snd_soc_dpcm_mutex_lock(fe);
@@ -2461,14 +2518,6 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
- /* there is no point preparing this FE if there are no BEs */
- if (list_empty(&fe->dpcm[stream].be_clients)) {
- dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
- fe->dai_link->name);
- ret = -EINVAL;
- goto out;
- }
-
ret = dpcm_be_dai_prepare(fe, stream);
if (ret < 0)
goto out;
@@ -2484,31 +2533,23 @@ 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)
{
- struct snd_pcm_substream *substream =
- snd_soc_dpcm_get_substream(fe, stream);
- enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
int err;
dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
- stream ? "capture" : "playback", fe->dai_link->name);
+ snd_pcm_direction_name(stream), fe->dai_link->name);
- if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
- /* call bespoke trigger - FE takes care of all BE triggers */
- dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop\n",
- fe->dai_link->name);
-
- err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
- } else {
- dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n",
- fe->dai_link->name);
-
- err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
- }
+ err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
dpcm_be_dai_hw_free(fe, stream);
@@ -2522,20 +2563,17 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
{
- struct snd_pcm_substream *substream =
- snd_soc_dpcm_get_substream(fe, stream);
struct snd_soc_dpcm *dpcm;
- enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
int ret = 0;
dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n",
- stream ? "capture" : "playback", fe->dai_link->name);
+ snd_pcm_direction_name(stream), fe->dai_link->name);
/* 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;
}
@@ -2569,23 +2607,9 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
return 0;
- if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
- /* call trigger on the frontend - FE takes care of all BE triggers */
- dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start\n",
- fe->dai_link->name);
-
- ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
- if (ret < 0)
- goto hw_free;
- } else {
- dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n",
- fe->dai_link->name);
-
- ret = dpcm_be_dai_trigger(fe, stream,
- SNDRV_PCM_TRIGGER_START);
- if (ret < 0)
- goto hw_free;
- }
+ ret = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_START);
+ if (ret < 0)
+ goto hw_free;
return 0;
@@ -2599,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 ||
@@ -2619,14 +2643,12 @@ 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(asoc_rtd_to_cpu(fe, 0)))
+ if (!snd_soc_dai_active(snd_soc_rtd_to_cpu(fe, 0)))
return 0;
/* DAPM sync will call this to update DSP paths */
@@ -2636,13 +2658,13 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
for_each_pcm_streams(stream) {
/* skip if FE doesn't have playback/capture capability */
- if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream) ||
- !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
+ if (!snd_soc_dai_stream_valid(snd_soc_rtd_to_cpu(fe, 0), stream) ||
+ !snd_soc_dai_stream_valid(snd_soc_rtd_to_codec(fe, 0), stream))
continue;
/* skip if FE isn't currently playing/capturing */
- if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
- !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
+ if (!snd_soc_dai_stream_active(snd_soc_rtd_to_cpu(fe, 0), stream) ||
+ !snd_soc_dai_stream_active(snd_soc_rtd_to_codec(fe, 0), stream))
continue;
paths = dpcm_path_get(fe, stream, &list);
@@ -2650,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)
@@ -2694,13 +2723,14 @@ 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);
static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(fe_substream);
struct snd_soc_dpcm *dpcm;
int stream = fe_substream->stream;
@@ -2715,7 +2745,7 @@ static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(fe_substream);
int ret;
snd_soc_dpcm_mutex_lock(fe);
@@ -2729,7 +2759,7 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(fe_substream);
struct snd_soc_dapm_widget_list *list;
int ret;
int stream = fe_substream->stream;
@@ -2741,13 +2771,25 @@ 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);
+
+ /* There is no point starting up this FE if there are no BEs. */
+ if (list_empty(&fe->dpcm[stream].be_clients)) {
+ /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles. */
+ dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n",
+ fe->dai_link->name);
+ dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n", fe->dai_link->name);
+
+ ret = -EINVAL;
+ goto put_path;
+ }
ret = dpcm_fe_dai_startup(fe_substream);
if (ret < 0)
dpcm_fe_dai_cleanup(fe_substream);
dpcm_clear_pending_state(fe, stream);
+put_path:
dpcm_path_put(&list);
open_end:
snd_soc_dpcm_mutex_unlock(fe);
@@ -2759,89 +2801,51 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *cpu_dai;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai_link_ch_map *ch_maps;
+ struct snd_soc_dai *dummy_dai = snd_soc_find_dai(&snd_soc_dummy_dlc);
+ int cpu_capture;
+ int cpu_playback;
int has_playback = 0;
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");
- if (dai_link->dynamic || dai_link->no_pcm) {
- int stream;
+ /* Adapt stream for codec2codec links */
+ cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE);
+ cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK);
- if (dai_link->dpcm_playback) {
- stream = SNDRV_PCM_STREAM_PLAYBACK;
-
- for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
- has_playback = 1;
- break;
- }
- }
- if (!has_playback) {
- dev_err(rtd->card->dev,
- "No CPU DAIs support playback for stream %s\n",
- dai_link->stream_name);
- return -EINVAL;
- }
- }
- if (dai_link->dpcm_capture) {
- stream = SNDRV_PCM_STREAM_CAPTURE;
-
- for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
- has_capture = 1;
- break;
- }
- }
-
- if (!has_capture) {
- dev_err(rtd->card->dev,
- "No CPU DAIs support capture for stream %s\n",
- dai_link->stream_name);
- return -EINVAL;
- }
- }
- } else {
- struct snd_soc_dai *codec_dai;
-
- /* Adapt stream for codec2codec links */
- int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE);
- int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK);
-
- for_each_rtd_codec_dais(rtd, i, codec_dai) {
- if (dai_link->num_cpus == 1) {
- cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- } else if (dai_link->num_cpus == dai_link->num_codecs) {
- cpu_dai = asoc_rtd_to_cpu(rtd, i);
- } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) {
- int cpu_id;
-
- if (!rtd->dai_link->codec_ch_maps) {
- dev_err(rtd->card->dev, "%s: no codec channel mapping table provided\n",
- __func__);
- return -EINVAL;
- }
+ /*
+ * see
+ * soc.h :: [dai_link->ch_maps Image sample]
+ */
+ for_each_rtd_ch_maps(rtd, i, ch_maps) {
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu);
+ codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec);
- cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id;
- cpu_dai = asoc_rtd_to_cpu(rtd, cpu_id);
- } else {
- dev_err(rtd->card->dev,
- "%s codec number %d < cpu number %d is not supported\n",
- __func__, rtd->dai_link->num_codecs,
- rtd->dai_link->num_cpus);
- return -EINVAL;
- }
+ /*
+ * FIXME
+ *
+ * DPCM Codec has been no checked before.
+ * It should be checked, but it breaks compatibility.
+ *
+ * For example there is a case that CPU have loopback capabilities which is used
+ * for tests on boards where the Codec has no capture capabilities. In this case,
+ * Codec capture validation check will be fail, but system should allow capture
+ * capabilities. We have no solution for it today.
+ */
+ if (dai_link->dynamic || dai_link->no_pcm)
+ codec_dai = dummy_dai;
- if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
- snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
- has_playback = 1;
- if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
- snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
- has_capture = 1;
- }
+ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
+ snd_soc_dai_stream_valid(cpu_dai, cpu_playback))
+ has_playback = 1;
+ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
+ snd_soc_dai_stream_valid(cpu_dai, cpu_capture))
+ has_capture = 1;
}
if (dai_link->playback_only)
@@ -2850,12 +2854,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;
@@ -2865,7 +2866,7 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
static int soc_create_pcm(struct snd_pcm **pcm,
struct snd_soc_pcm_runtime *rtd,
- int playback, int capture, int num)
+ int playback, int capture)
{
char new_name[64];
int ret;
@@ -2875,13 +2876,13 @@ static int soc_create_pcm(struct snd_pcm **pcm,
snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
rtd->dai_link->stream_name);
- ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+ ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id,
playback, capture, pcm);
} else if (rtd->dai_link->no_pcm) {
snprintf(new_name, sizeof(new_name), "(%s)",
rtd->dai_link->stream_name);
- ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+ ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id,
playback, capture, pcm);
} else {
if (rtd->dai_link->dynamic)
@@ -2890,23 +2891,22 @@ static int soc_create_pcm(struct snd_pcm **pcm,
else
snprintf(new_name, sizeof(new_name), "%s %s-%d",
rtd->dai_link->stream_name,
- soc_codec_dai_name(rtd), num);
+ soc_codec_dai_name(rtd), rtd->id);
- ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
+ 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;
- }
- dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
+ 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;
}
/* create a new pcm */
-int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *component;
struct snd_pcm *pcm;
@@ -2917,7 +2917,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
if (ret < 0)
return ret;
- ret = soc_create_pcm(&pcm, rtd, playback, capture, num);
+ ret = soc_create_pcm(&pcm, rtd, playback, capture);
if (ret < 0)
return ret;
@@ -2970,8 +2970,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
rtd->ops.ioctl = snd_soc_pcm_component_ioctl;
if (drv->sync_stop)
rtd->ops.sync_stop = snd_soc_pcm_component_sync_stop;
- if (drv->copy_user)
- rtd->ops.copy_user = snd_soc_pcm_component_copy_user;
+ if (drv->copy)
+ rtd->ops.copy = snd_soc_pcm_component_copy;
if (drv->page)
rtd->ops.page = snd_soc_pcm_component_page;
if (drv->mmap)
@@ -2995,27 +2995,6 @@ out:
return ret;
}
-/* is the current PCM operation for this FE ? */
-int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
-{
- if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
- return 1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
-
-/* is the current PCM operation for this BE ? */
-int snd_soc_dpcm_be_can_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) ||
- ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
- be->dpcm[stream].runtime_update))
- return 1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
-
/* get the substream for this BE */
struct snd_pcm_substream *
snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
@@ -3023,67 +3002,3 @@ struct snd_pcm_substream *
return be->pcm->streams[stream].substream;
}
EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
-
-static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
- struct snd_soc_pcm_runtime *be,
- int stream,
- const enum snd_soc_dpcm_state *states,
- int num_states)
-{
- struct snd_soc_dpcm *dpcm;
- int state;
- int ret = 1;
- int i;
-
- for_each_dpcm_fe(be, stream, dpcm) {
-
- if (dpcm->fe == fe)
- continue;
-
- state = dpcm->fe->dpcm[stream].state;
- for (i = 0; i < num_states; i++) {
- if (state == states[i]) {
- ret = 0;
- break;
- }
- }
- }
-
- /* it's safe to do this BE DAI */
- return ret;
-}
-
-/*
- * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
- * are not running, paused or suspended for the specified stream direction.
- */
-int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
- struct snd_soc_pcm_runtime *be, int stream)
-{
- const enum snd_soc_dpcm_state state[] = {
- SND_SOC_DPCM_STATE_START,
- SND_SOC_DPCM_STATE_PAUSED,
- SND_SOC_DPCM_STATE_SUSPEND,
- };
-
- return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
-}
-EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
-
-/*
- * We can only change hw params a BE DAI if any of it's FE are not prepared,
- * running, paused or suspended for the specified stream direction.
- */
-int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
- struct snd_soc_pcm_runtime *be, int stream)
-{
- const enum snd_soc_dpcm_state state[] = {
- SND_SOC_DPCM_STATE_START,
- SND_SOC_DPCM_STATE_PAUSED,
- SND_SOC_DPCM_STATE_SUSPEND,
- SND_SOC_DPCM_STATE_PREPARE,
- };
-
- return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
-}
-EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c
index 2cd3540cec04..c8f2ec29e970 100644
--- a/sound/soc/soc-topology-test.c
+++ b/sound/soc/soc-topology-test.c
@@ -2,13 +2,14 @@
/*
* soc-topology-test.c -- ALSA SoC Topology Kernel Unit Tests
*
- * Copyright(c) 2021 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021 Intel Corporation.
*/
#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-topology.h>
+#include <kunit/device.h>
#include <kunit/test.h>
/* ===== HELPER FUNCTIONS =================================================== */
@@ -21,26 +22,19 @@
*/
static struct device *test_dev;
-static struct device_driver test_drv = {
- .name = "sound-soc-topology-test-driver",
-};
-
static int snd_soc_tplg_test_init(struct kunit *test)
{
- test_dev = root_device_register("sound-soc-topology-test");
+ test_dev = kunit_device_register(test, "sound-soc-topology-test");
test_dev = get_device(test_dev);
if (!test_dev)
return -ENODEV;
- test_dev->driver = &test_drv;
-
return 0;
}
static void snd_soc_tplg_test_exit(struct kunit *test)
{
put_device(test_dev);
- root_device_unregister(test_dev);
}
/*
@@ -94,8 +88,6 @@ static struct snd_soc_dai_link kunit_dai_links[] = {
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_playback = 1,
- .dpcm_capture = 1,
SND_SOC_DAILINK_REG(dummy, dummy, platform),
},
};
@@ -250,12 +242,12 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
kunit_comp->kunit = test;
kunit_comp->expect = -EINVAL; /* expect failure */
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -292,12 +284,12 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
kunit_comp->kunit = test;
kunit_comp->expect = 0; /* expect success */
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -354,12 +346,12 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
kunit_comp->kunit = test;
kunit_comp->expect = -EINVAL; /* expect failure */
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -402,12 +394,12 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
kunit_comp->fw.data = (u8 *)data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -457,12 +449,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
kunit_comp->fw.data = (u8 *)data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -512,12 +504,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
kunit_comp->fw.data = (u8 *)data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -567,12 +559,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
kunit_comp->fw.data = (u8 *)data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -623,12 +615,12 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes
kunit_comp->fw.data = (u8 *)data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -671,12 +663,12 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
kunit_comp->fw.data = data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -721,12 +713,12 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
kunit_comp->fw.data = data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
@@ -773,12 +765,12 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test)
kunit_comp->fw.data = data;
kunit_comp->fw.size = size;
- kunit_comp->card.dev = test_dev,
- kunit_comp->card.name = "kunit-card",
- kunit_comp->card.owner = THIS_MODULE,
- kunit_comp->card.dai_link = kunit_dai_links,
- kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
- kunit_comp->card.fully_routed = true,
+ kunit_comp->card.dev = test_dev;
+ kunit_comp->card.name = "kunit-card";
+ kunit_comp->card.owner = THIS_MODULE;
+ kunit_comp->card.dai_link = kunit_dai_links;
+ kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
+ kunit_comp->card.fully_routed = true;
/* run test */
ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
@@ -825,4 +817,5 @@ static struct kunit_suite snd_soc_tplg_test_suite = {
kunit_test_suites(&snd_soc_tplg_test_suite);
+MODULE_DESCRIPTION("ASoC Topology Kernel Unit Tests");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 8add361e87c6..064b8d76b955 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -73,7 +73,7 @@ struct soc_tplg {
int bytes_ext_ops_count;
/* optional fw loading callbacks to component drivers */
- struct snd_soc_tplg_ops *ops;
+ const struct snd_soc_tplg_ops *ops;
};
/* check we dont overflow the data for this control chunk */
@@ -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)
{
@@ -394,13 +385,9 @@ static void soc_tplg_remove_widget(struct snd_soc_component *comp,
if (dobj->unload)
dobj->unload(comp, dobj);
- if (!w->kcontrols)
- goto free_news;
-
- for (i = 0; w->kcontrols && i < w->num_kcontrols; i++)
- snd_ctl_remove(card, w->kcontrols[i]);
-
-free_news:
+ if (w->kcontrols)
+ for (i = 0; i < w->num_kcontrols; i++)
+ snd_ctl_remove(card, w->kcontrols[i]);
list_del(&dobj->list);
@@ -442,8 +429,11 @@ static void soc_tplg_remove_link(struct snd_soc_component *comp,
dobj->unload(comp, dobj);
list_del(&dobj->list);
- snd_soc_remove_pcm_runtime(comp->card,
- snd_soc_get_pcm_runtime(comp->card, link));
+
+ /* Ignored links do not need to be removed, they are not added */
+ if (!link->ignore)
+ snd_soc_remove_pcm_runtime(comp->card,
+ snd_soc_get_pcm_runtime(comp->card, link));
}
/* unload dai link */
@@ -644,105 +634,33 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
return 0;
}
-static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size)
-{
- struct snd_soc_tplg_bytes_control *be;
- struct soc_bytes_ext *sbe;
- struct snd_kcontrol_new kc;
- int ret = 0;
-
- if (soc_tplg_check_elem_count(tplg,
- sizeof(struct snd_soc_tplg_bytes_control),
- 1, size, "mixer bytes"))
- return -EINVAL;
-
- be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
-
- /* validate kcontrol */
- if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
- return -EINVAL;
-
- sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
- if (sbe == NULL)
- return -ENOMEM;
-
- tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
- le32_to_cpu(be->priv.size));
-
- dev_dbg(tplg->dev,
- "ASoC: adding bytes kcontrol %s with access 0x%x\n",
- be->hdr.name, be->hdr.access);
-
- memset(&kc, 0, sizeof(kc));
- kc.name = be->hdr.name;
- kc.private_value = (long)sbe;
- kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc.access = le32_to_cpu(be->hdr.access);
-
- sbe->max = le32_to_cpu(be->max);
- sbe->dobj.type = SND_SOC_DOBJ_BYTES;
- if (tplg->ops)
- sbe->dobj.unload = tplg->ops->control_unload;
- INIT_LIST_HEAD(&sbe->dobj.list);
-
- /* map io handlers */
- ret = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
- if (ret) {
- soc_control_err(tplg, &be->hdr, be->hdr.name);
- goto err;
- }
-
- /* pass control to driver for optional further init */
- ret = soc_tplg_control_load(tplg, &kc, &be->hdr);
- if (ret < 0)
- goto err;
-
- /* register control here */
- ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol);
- if (ret < 0)
- goto err;
-
- list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
-
-err:
- return ret;
-}
-
-static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
+static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
{
struct snd_soc_tplg_mixer_control *mc;
struct soc_mixer_control *sm;
- struct snd_kcontrol_new kc;
- int ret = 0;
-
- if (soc_tplg_check_elem_count(tplg,
- sizeof(struct snd_soc_tplg_mixer_control),
- 1, size, "mixers"))
- return -EINVAL;
+ int err;
mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
/* validate kcontrol */
- if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+ if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
return -EINVAL;
sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
- if (sm == NULL)
+ if (!sm)
return -ENOMEM;
- tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
- le32_to_cpu(mc->priv.size));
- dev_dbg(tplg->dev,
- "ASoC: adding mixer kcontrol %s with access 0x%x\n",
+ tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) + le32_to_cpu(mc->priv.size);
+
+ dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n",
mc->hdr.name, mc->hdr.access);
- memset(&kc, 0, sizeof(kc));
- kc.name = mc->hdr.name;
- kc.private_value = (long)sm;
- kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc.access = le32_to_cpu(mc->hdr.access);
+ kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
+ if (!kc->name)
+ return -ENOMEM;
+ kc->private_value = (long)sm;
+ kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kc->access = le32_to_cpu(mc->hdr.access);
/* we only support FL/FR channel mapping atm */
sm->reg = tplg_chan_get_reg(tplg, mc->channel, SNDRV_CHMAP_FL);
@@ -754,40 +672,24 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
sm->min = le32_to_cpu(mc->min);
sm->invert = le32_to_cpu(mc->invert);
sm->platform_max = le32_to_cpu(mc->platform_max);
- sm->dobj.index = tplg->index;
- sm->dobj.type = SND_SOC_DOBJ_MIXER;
- if (tplg->ops)
- sm->dobj.unload = tplg->ops->control_unload;
- INIT_LIST_HEAD(&sm->dobj.list);
+ sm->num_channels = le32_to_cpu(mc->num_channels);
/* map io handlers */
- ret = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
- if (ret) {
+ err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg);
+ if (err) {
soc_control_err(tplg, &mc->hdr, mc->hdr.name);
- goto err;
+ return err;
}
/* create any TLV data */
- ret = soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
- if (ret < 0) {
+ err = soc_tplg_create_tlv(tplg, kc, &mc->hdr);
+ if (err < 0) {
dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name);
- goto err;
+ return err;
}
/* pass control to driver for optional further init */
- ret = soc_tplg_control_load(tplg, &kc, &mc->hdr);
- if (ret < 0)
- goto err;
-
- /* register control here */
- ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol);
- if (ret < 0)
- goto err;
-
- list_add(&sm->dobj.list, &tplg->comp->dobj_list);
-
-err:
- return ret;
+ return soc_tplg_control_load(tplg, kc, &mc->hdr);
}
static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se,
@@ -851,107 +753,220 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *
se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]);
}
+ se->items = le32_to_cpu(ec->items);
+ se->values = (const unsigned int *)se->dobj.control.dvalues;
return 0;
}
-static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size)
+static int soc_tplg_control_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
{
struct snd_soc_tplg_enum_control *ec;
struct soc_enum *se;
- struct snd_kcontrol_new kc;
- int ret = 0;
-
- if (soc_tplg_check_elem_count(tplg,
- sizeof(struct snd_soc_tplg_enum_control),
- 1, size, "enums"))
- return -EINVAL;
+ int err;
ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
/* validate kcontrol */
- if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+ if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
return -EINVAL;
- se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL);
- if (se == NULL)
+ se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL);
+ if (!se)
return -ENOMEM;
- tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
- le32_to_cpu(ec->priv.size));
+ tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + le32_to_cpu(ec->priv.size));
- dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
- ec->hdr.name, ec->items);
+ dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items);
- memset(&kc, 0, sizeof(kc));
- kc.name = ec->hdr.name;
- kc.private_value = (long)se;
- kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc.access = le32_to_cpu(ec->hdr.access);
+ kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
+ if (!kc->name)
+ return -ENOMEM;
+ kc->private_value = (long)se;
+ kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kc->access = le32_to_cpu(ec->hdr.access);
+ /* we only support FL/FR channel mapping atm */
se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
- se->shift_l = tplg_chan_get_shift(tplg, ec->channel,
- SNDRV_CHMAP_FL);
- se->shift_r = tplg_chan_get_shift(tplg, ec->channel,
- SNDRV_CHMAP_FL);
+ se->shift_l = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL);
+ se->shift_r = tplg_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR);
se->mask = le32_to_cpu(ec->mask);
- se->dobj.index = tplg->index;
- se->dobj.type = SND_SOC_DOBJ_ENUM;
- if (tplg->ops)
- se->dobj.unload = tplg->ops->control_unload;
- INIT_LIST_HEAD(&se->dobj.list);
switch (le32_to_cpu(ec->hdr.ops.info)) {
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
case SND_SOC_TPLG_CTL_ENUM_VALUE:
- ret = soc_tplg_denum_create_values(tplg, se, ec);
- if (ret < 0) {
- dev_err(tplg->dev,
- "ASoC: could not create values for %s\n",
- ec->hdr.name);
- goto err;
+ case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+ err = soc_tplg_denum_create_values(tplg, se, ec);
+ if (err < 0) {
+ dev_err(tplg->dev, "ASoC: could not create values for %s\n", ec->hdr.name);
+ return err;
}
fallthrough;
case SND_SOC_TPLG_CTL_ENUM:
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
- ret = soc_tplg_denum_create_texts(tplg, se, ec);
- if (ret < 0) {
- dev_err(tplg->dev,
- "ASoC: could not create texts for %s\n",
- ec->hdr.name);
- goto err;
+ err = soc_tplg_denum_create_texts(tplg, se, ec);
+ if (err < 0) {
+ dev_err(tplg->dev, "ASoC: could not create texts for %s\n", ec->hdr.name);
+ return err;
}
break;
default:
- ret = -EINVAL;
- dev_err(tplg->dev,
- "ASoC: invalid enum control type %d for %s\n",
+ dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
ec->hdr.ops.info, ec->hdr.name);
- goto err;
+ return -EINVAL;
}
/* map io handlers */
- ret = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg);
- if (ret) {
+ err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
+ if (err) {
soc_control_err(tplg, &ec->hdr, ec->hdr.name);
- goto err;
+ return err;
}
/* pass control to driver for optional further init */
- ret = soc_tplg_control_load(tplg, &kc, &ec->hdr);
+ return soc_tplg_control_load(tplg, kc, &ec->hdr);
+}
+
+static int soc_tplg_control_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
+{
+ struct snd_soc_tplg_bytes_control *be;
+ struct soc_bytes_ext *sbe;
+ int err;
+
+ be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
+
+ /* validate kcontrol */
+ if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+ return -EINVAL;
+
+ sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
+ if (!sbe)
+ return -ENOMEM;
+
+ tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + le32_to_cpu(be->priv.size));
+
+ dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n",
+ be->hdr.name, be->hdr.access);
+
+ kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
+ if (!kc->name)
+ return -ENOMEM;
+ kc->private_value = (long)sbe;
+ kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kc->access = le32_to_cpu(be->hdr.access);
+
+ sbe->max = le32_to_cpu(be->max);
+
+ /* map standard io handlers and check for external handlers */
+ err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg);
+ if (err) {
+ soc_control_err(tplg, &be->hdr, be->hdr.name);
+ return err;
+ }
+
+ /* pass control to driver for optional further init */
+ return soc_tplg_control_load(tplg, kc, &be->hdr);
+}
+
+static int soc_tplg_dbytes_create(struct soc_tplg *tplg, size_t size)
+{
+ struct snd_kcontrol_new kc = {0};
+ struct soc_bytes_ext *sbe;
+ int ret;
+
+ if (soc_tplg_check_elem_count(tplg,
+ sizeof(struct snd_soc_tplg_bytes_control),
+ 1, size, "mixer bytes"))
+ return -EINVAL;
+
+ ret = soc_tplg_control_dbytes_create(tplg, &kc);
+ if (ret)
+ return ret;
+
+ /* register dynamic object */
+ sbe = (struct soc_bytes_ext *)kc.private_value;
+
+ INIT_LIST_HEAD(&sbe->dobj.list);
+ sbe->dobj.type = SND_SOC_DOBJ_BYTES;
+ sbe->dobj.index = tplg->index;
+ if (tplg->ops)
+ sbe->dobj.unload = tplg->ops->control_unload;
+
+ /* create control directly */
+ ret = soc_tplg_add_kcontrol(tplg, &kc, &sbe->dobj.control.kcontrol);
if (ret < 0)
- goto err;
+ return ret;
+
+ list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
+
+ return ret;
+}
+
+static int soc_tplg_dmixer_create(struct soc_tplg *tplg, size_t size)
+{
+ struct snd_kcontrol_new kc = {0};
+ struct soc_mixer_control *sm;
+ int ret;
+
+ if (soc_tplg_check_elem_count(tplg,
+ sizeof(struct snd_soc_tplg_mixer_control),
+ 1, size, "mixers"))
+ return -EINVAL;
+
+ ret = soc_tplg_control_dmixer_create(tplg, &kc);
+ if (ret)
+ return ret;
+
+ /* register dynamic object */
+ sm = (struct soc_mixer_control *)kc.private_value;
+
+ INIT_LIST_HEAD(&sm->dobj.list);
+ sm->dobj.type = SND_SOC_DOBJ_MIXER;
+ sm->dobj.index = tplg->index;
+ if (tplg->ops)
+ sm->dobj.unload = tplg->ops->control_unload;
- /* register control here */
+ /* create control directly */
+ ret = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol);
+ if (ret < 0)
+ return ret;
+
+ list_add(&sm->dobj.list, &tplg->comp->dobj_list);
+
+ return ret;
+}
+
+static int soc_tplg_denum_create(struct soc_tplg *tplg, size_t size)
+{
+ struct snd_kcontrol_new kc = {0};
+ struct soc_enum *se;
+ int ret;
+
+ if (soc_tplg_check_elem_count(tplg,
+ sizeof(struct snd_soc_tplg_enum_control),
+ 1, size, "enums"))
+ return -EINVAL;
+
+ ret = soc_tplg_control_denum_create(tplg, &kc);
+ if (ret)
+ return ret;
+
+ /* register dynamic object */
+ se = (struct soc_enum *)kc.private_value;
+
+ INIT_LIST_HEAD(&se->dobj.list);
+ se->dobj.type = SND_SOC_DOBJ_ENUM;
+ se->dobj.index = tplg->index;
+ if (tplg->ops)
+ se->dobj.unload = tplg->ops->control_unload;
+
+ /* create control directly */
ret = soc_tplg_add_kcontrol(tplg, &kc, &se->dobj.control.kcontrol);
if (ret < 0)
- goto err;
+ return ret;
list_add(&se->dobj.list, &tplg->comp->dobj_list);
-err:
return ret;
}
@@ -972,35 +987,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;
@@ -1020,7 +1026,8 @@ static int soc_tplg_add_route(struct soc_tplg *tplg,
static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
- struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(tplg->comp);
+ const size_t maxlen = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
struct snd_soc_tplg_dapm_graph_elem *elem;
struct snd_soc_dapm_route *route;
int count, i;
@@ -1044,31 +1051,27 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem);
/* validate routes */
- if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
+ if ((strnlen(elem->source, maxlen) == maxlen) ||
+ (strnlen(elem->sink, maxlen) == maxlen) ||
+ (strnlen(elem->control, maxlen) == maxlen)) {
ret = -EINVAL;
break;
}
- if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
- ret = -EINVAL;
- break;
- }
- if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
- ret = -EINVAL;
+
+ route->source = devm_kstrdup(tplg->dev, elem->source, GFP_KERNEL);
+ route->sink = devm_kstrdup(tplg->dev, elem->sink, GFP_KERNEL);
+ if (!route->source || !route->sink) {
+ ret = -ENOMEM;
break;
}
- route->source = elem->source;
- route->sink = elem->sink;
-
- /* set to NULL atm for tplg users */
- route->connected = NULL;
- if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0)
- route->control = NULL;
- else
- route->control = elem->control;
+ if (strnlen(elem->control, maxlen) != 0) {
+ route->control = devm_kstrdup(tplg->dev, elem->control, GFP_KERNEL);
+ if (!route->control) {
+ ret = -ENOMEM;
+ break;
+ }
+ }
/* add route dobj to dobj_list */
route->dobj.type = SND_SOC_DOBJ_GRAPH;
@@ -1083,217 +1086,18 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
break;
}
- /* add route, but keep going if some fail */
- snd_soc_dapm_add_routes(dapm, route, 1);
+ ret = snd_soc_dapm_add_routes(dapm, route, 1);
+ if (ret)
+ break;
}
return ret;
}
-static int soc_tplg_dapm_widget_dmixer_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
-{
- struct soc_mixer_control *sm;
- struct snd_soc_tplg_mixer_control *mc;
- int err;
-
- mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
-
- /* validate kcontrol */
- if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
- return -EINVAL;
-
- sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL);
- if (!sm)
- return -ENOMEM;
-
- tplg->pos += sizeof(struct snd_soc_tplg_mixer_control) +
- le32_to_cpu(mc->priv.size);
-
- dev_dbg(tplg->dev, " adding DAPM widget mixer control %s\n",
- mc->hdr.name);
-
- kc->private_value = (long)sm;
- kc->name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL);
- if (!kc->name)
- return -ENOMEM;
- kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc->access = le32_to_cpu(mc->hdr.access);
-
- /* we only support FL/FR channel mapping atm */
- sm->reg = tplg_chan_get_reg(tplg, mc->channel,
- SNDRV_CHMAP_FL);
- sm->rreg = tplg_chan_get_reg(tplg, mc->channel,
- SNDRV_CHMAP_FR);
- sm->shift = tplg_chan_get_shift(tplg, mc->channel,
- SNDRV_CHMAP_FL);
- sm->rshift = tplg_chan_get_shift(tplg, mc->channel,
- SNDRV_CHMAP_FR);
-
- sm->max = le32_to_cpu(mc->max);
- sm->min = le32_to_cpu(mc->min);
- sm->invert = le32_to_cpu(mc->invert);
- sm->platform_max = le32_to_cpu(mc->platform_max);
- sm->dobj.index = tplg->index;
- INIT_LIST_HEAD(&sm->dobj.list);
-
- /* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg);
- if (err) {
- soc_control_err(tplg, &mc->hdr, mc->hdr.name);
- return err;
- }
-
- /* create any TLV data */
- err = soc_tplg_create_tlv(tplg, kc, &mc->hdr);
- if (err < 0) {
- dev_err(tplg->dev, "ASoC: failed to create TLV %s\n",
- mc->hdr.name);
- return err;
- }
-
- /* pass control to driver for optional further init */
- err = soc_tplg_control_load(tplg, kc, &mc->hdr);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int soc_tplg_dapm_widget_denum_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
-{
- struct snd_soc_tplg_enum_control *ec;
- struct soc_enum *se;
- int err;
-
- ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
- /* validate kcontrol */
- if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
- return -EINVAL;
-
- se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL);
- if (!se)
- return -ENOMEM;
-
- tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
- le32_to_cpu(ec->priv.size));
-
- dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
- ec->hdr.name);
-
- kc->private_value = (long)se;
- kc->name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL);
- if (!kc->name)
- return -ENOMEM;
- kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc->access = le32_to_cpu(ec->hdr.access);
-
- /* we only support FL/FR channel mapping atm */
- se->reg = tplg_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
- se->shift_l = tplg_chan_get_shift(tplg, ec->channel,
- SNDRV_CHMAP_FL);
- se->shift_r = tplg_chan_get_shift(tplg, ec->channel,
- SNDRV_CHMAP_FR);
-
- se->items = le32_to_cpu(ec->items);
- se->mask = le32_to_cpu(ec->mask);
- se->dobj.index = tplg->index;
-
- switch (le32_to_cpu(ec->hdr.ops.info)) {
- case SND_SOC_TPLG_CTL_ENUM_VALUE:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
- err = soc_tplg_denum_create_values(tplg, se, ec);
- if (err < 0) {
- dev_err(tplg->dev, "ASoC: could not create values for %s\n",
- ec->hdr.name);
- return err;
- }
- fallthrough;
- case SND_SOC_TPLG_CTL_ENUM:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
- err = soc_tplg_denum_create_texts(tplg, se, ec);
- if (err < 0) {
- dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
- ec->hdr.name);
- return err;
- }
- break;
- default:
- dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
- ec->hdr.ops.info, ec->hdr.name);
- return -EINVAL;
- }
-
- /* map io handlers */
- err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
- if (err) {
- soc_control_err(tplg, &ec->hdr, ec->hdr.name);
- return err;
- }
-
- /* pass control to driver for optional further init */
- err = soc_tplg_control_load(tplg, kc, &ec->hdr);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int soc_tplg_dapm_widget_dbytes_create(struct soc_tplg *tplg, struct snd_kcontrol_new *kc)
-{
- struct snd_soc_tplg_bytes_control *be;
- struct soc_bytes_ext *sbe;
- int err;
-
- be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
-
- /* validate kcontrol */
- if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
- SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
- return -EINVAL;
-
- sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL);
- if (!sbe)
- return -ENOMEM;
-
- tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
- le32_to_cpu(be->priv.size));
-
- dev_dbg(tplg->dev,
- "ASoC: adding bytes kcontrol %s with access 0x%x\n",
- be->hdr.name, be->hdr.access);
-
- kc->private_value = (long)sbe;
- kc->name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL);
- if (!kc->name)
- return -ENOMEM;
- kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- kc->access = le32_to_cpu(be->hdr.access);
-
- sbe->max = le32_to_cpu(be->max);
- INIT_LIST_HEAD(&sbe->dobj.list);
-
- /* map standard io handlers and check for external handlers */
- err = soc_tplg_kcontrol_bind_io(&be->hdr, kc, tplg);
- if (err) {
- soc_control_err(tplg, &be->hdr, be->hdr.name);
- return err;
- }
-
- /* pass control to driver for optional further init */
- err = soc_tplg_control_load(tplg, kc, &be->hdr);
- if (err < 0)
- return err;
-
- return 0;
-}
-
static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
struct snd_soc_tplg_dapm_widget *w)
{
- struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(tplg->comp);
struct snd_soc_dapm_widget template, *widget;
struct snd_soc_tplg_ctl_hdr *control_hdr;
struct snd_soc_card *card = tplg->comp->card;
@@ -1366,40 +1170,32 @@ 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;
mixer_count++;
- ret = soc_tplg_dapm_widget_dmixer_create(tplg, &kc[i]);
+ ret = soc_tplg_control_dmixer_create(tplg, &kc[i]);
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;
enum_count++;
- ret = soc_tplg_dapm_widget_denum_create(tplg, &kc[i]);
+ ret = soc_tplg_control_denum_create(tplg, &kc[i]);
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;
bytes_count++;
- ret = soc_tplg_dapm_widget_dbytes_create(tplg, &kc[i]);
+ ret = soc_tplg_control_dbytes_create(tplg, &kc[i]);
if (ret < 0)
goto hdr_err;
break;
@@ -1449,7 +1245,8 @@ widget:
return 0;
ready_err:
- soc_tplg_remove_widget(widget->dapm->component, &widget->dobj, SOC_TPLG_PASS_WIDGET);
+ soc_tplg_remove_widget(snd_soc_dapm_to_component(widget->dapm),
+ &widget->dobj, SOC_TPLG_PASS_WIDGET);
snd_soc_dapm_free_widget(widget);
hdr_err:
kfree(template.sname);
@@ -1560,6 +1357,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
1 : 0;
}
+static const struct snd_soc_dai_ops tplg_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static int soc_tplg_dai_create(struct soc_tplg *tplg,
struct snd_soc_tplg_pcm *pcm)
{
@@ -1567,8 +1368,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
struct snd_soc_pcm_stream *stream;
struct snd_soc_tplg_stream_caps *caps;
struct snd_soc_dai *dai;
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(tplg->comp);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(tplg->comp);
int ret;
dai_drv = devm_kzalloc(tplg->dev, sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
@@ -1601,7 +1401,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
}
if (pcm->compress)
- dai_drv->compress_new = snd_soc_new_compress;
+ dai_drv->ops = &tplg_dai_ops;
/* pass control to component driver for optional further init */
ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
@@ -1702,22 +1502,22 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
/*
* Many topology are assuming link has Codec / Platform, and
* these might be overwritten at soc_tplg_dai_link_load().
- * Don't use &asoc_dummy_dlc here.
+ * Don't use &snd_soc_dummy_dlc here.
*/
- link->codecs = &dlc[1]; /* Don't use &asoc_dummy_dlc here */
+ link->codecs = &dlc[1]; /* Don't use &snd_soc_dummy_dlc here */
link->codecs->name = "snd-soc-dummy";
link->codecs->dai_name = "snd-soc-dummy-dai";
link->num_codecs = 1;
- link->platforms = &dlc[2]; /* Don't use &asoc_dummy_dlc here */
+ link->platforms = &dlc[2]; /* Don't use &snd_soc_dummy_dlc here */
link->platforms->name = "snd-soc-dummy";
link->num_platforms = 1;
/* enable DPCM */
link->dynamic = 1;
link->ignore_pmdown_time = 1;
- link->dpcm_playback = le32_to_cpu(pcm->playback);
- link->dpcm_capture = le32_to_cpu(pcm->capture);
+ link->playback_only = le32_to_cpu(pcm->playback) && !le32_to_cpu(pcm->capture);
+ link->capture_only = !le32_to_cpu(pcm->playback) && le32_to_cpu(pcm->capture);
if (pcm->flag_mask)
set_link_flags(link,
le32_to_cpu(pcm->flag_mask),
@@ -1732,7 +1532,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
ret = snd_soc_add_pcm_runtimes(tplg->comp->card, link, 1);
if (ret < 0) {
- dev_err(tplg->dev, "ASoC: adding FE link failed\n");
+ if (ret != -EPROBE_DEFER)
+ dev_err(tplg->dev, "ASoC: adding FE link failed\n");
goto err;
}
@@ -1756,83 +1557,13 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg,
return soc_tplg_fe_link_create(tplg, pcm);
}
-/* copy stream caps from the old version 4 of source */
-static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest,
- struct snd_soc_tplg_stream_caps_v4 *src)
-{
- dest->size = cpu_to_le32(sizeof(*dest));
- memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
- dest->formats = src->formats;
- dest->rates = src->rates;
- dest->rate_min = src->rate_min;
- dest->rate_max = src->rate_max;
- dest->channels_min = src->channels_min;
- dest->channels_max = src->channels_max;
- dest->periods_min = src->periods_min;
- dest->periods_max = src->periods_max;
- dest->period_size_min = src->period_size_min;
- dest->period_size_max = src->period_size_max;
- dest->buffer_size_min = src->buffer_size_min;
- dest->buffer_size_max = src->buffer_size_max;
-}
-
-/**
- * pcm_new_ver - Create the new version of PCM from the old version.
- * @tplg: topology context
- * @src: older version of pcm as a source
- * @pcm: latest version of pcm created from the source
- *
- * Support from version 4. User should free the returned pcm manually.
- */
-static int pcm_new_ver(struct soc_tplg *tplg,
- struct snd_soc_tplg_pcm *src,
- struct snd_soc_tplg_pcm **pcm)
-{
- struct snd_soc_tplg_pcm *dest;
- struct snd_soc_tplg_pcm_v4 *src_v4;
- int i;
-
- *pcm = NULL;
-
- if (le32_to_cpu(src->size) != sizeof(*src_v4)) {
- dev_err(tplg->dev, "ASoC: invalid PCM size\n");
- return -EINVAL;
- }
-
- dev_warn(tplg->dev, "ASoC: old version of PCM\n");
- src_v4 = (struct snd_soc_tplg_pcm_v4 *)src;
- dest = kzalloc(sizeof(*dest), GFP_KERNEL);
- if (!dest)
- return -ENOMEM;
-
- dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */
- memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
- memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
- dest->pcm_id = src_v4->pcm_id;
- dest->dai_id = src_v4->dai_id;
- dest->playback = src_v4->playback;
- dest->capture = src_v4->capture;
- dest->compress = src_v4->compress;
- dest->num_streams = src_v4->num_streams;
- for (i = 0; i < le32_to_cpu(dest->num_streams); i++)
- memcpy(&dest->stream[i], &src_v4->stream[i],
- sizeof(struct snd_soc_tplg_stream));
-
- for (i = 0; i < 2; i++)
- stream_caps_new_ver(&dest->caps[i], &src_v4->caps[i]);
-
- *pcm = dest;
- return 0;
-}
-
static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
- struct snd_soc_tplg_pcm *pcm, *_pcm;
+ struct snd_soc_tplg_pcm *pcm;
int count;
int size;
int i;
- bool abi_match;
int ret;
count = le32_to_cpu(hdr->count);
@@ -1840,8 +1571,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
/* check the element size and count */
pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
size = le32_to_cpu(pcm->size);
- if (size > sizeof(struct snd_soc_tplg_pcm)
- || size < sizeof(struct snd_soc_tplg_pcm_v4)) {
+ if (size > sizeof(struct snd_soc_tplg_pcm)) {
dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n",
size);
return -EINVAL;
@@ -1860,31 +1590,18 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
/* check ABI version by size, create a new version of pcm
* if abi not match.
*/
- if (size == sizeof(*pcm)) {
- abi_match = true;
- _pcm = pcm;
- } else {
- abi_match = false;
- ret = pcm_new_ver(tplg, pcm, &_pcm);
- if (ret < 0)
- return ret;
- }
+ if (size != sizeof(*pcm))
+ return -EINVAL;
/* create the FE DAIs and DAI links */
- ret = soc_tplg_pcm_create(tplg, _pcm);
- if (ret < 0) {
- if (!abi_match)
- kfree(_pcm);
+ ret = soc_tplg_pcm_create(tplg, pcm);
+ if (ret < 0)
return ret;
- }
/* offset by version-specific struct size and
* real priv data size
*/
- tplg->pos += size + le32_to_cpu(_pcm->priv.size);
-
- if (!abi_match)
- kfree(_pcm); /* free the duplicated one */
+ tplg->pos += size + le32_to_cpu(pcm->priv.size);
}
dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
@@ -1961,49 +1678,6 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
}
/**
- * link_new_ver - Create a new physical link config from the old
- * version of source.
- * @tplg: topology context
- * @src: old version of phyical link config as a source
- * @link: latest version of physical link config created from the source
- *
- * Support from version 4. User need free the returned link config manually.
- */
-static int link_new_ver(struct soc_tplg *tplg,
- struct snd_soc_tplg_link_config *src,
- struct snd_soc_tplg_link_config **link)
-{
- struct snd_soc_tplg_link_config *dest;
- struct snd_soc_tplg_link_config_v4 *src_v4;
- int i;
-
- *link = NULL;
-
- if (le32_to_cpu(src->size) !=
- sizeof(struct snd_soc_tplg_link_config_v4)) {
- dev_err(tplg->dev, "ASoC: invalid physical link config size\n");
- return -EINVAL;
- }
-
- dev_warn(tplg->dev, "ASoC: old version of physical link config\n");
-
- src_v4 = (struct snd_soc_tplg_link_config_v4 *)src;
- dest = kzalloc(sizeof(*dest), GFP_KERNEL);
- if (!dest)
- return -ENOMEM;
-
- dest->size = cpu_to_le32(sizeof(*dest));
- dest->id = src_v4->id;
- dest->num_streams = src_v4->num_streams;
- for (i = 0; i < le32_to_cpu(dest->num_streams); i++)
- memcpy(&dest->stream[i], &src_v4->stream[i],
- sizeof(struct snd_soc_tplg_stream));
-
- *link = dest;
- return 0;
-}
-
-/**
* snd_soc_find_dai_link - Find a DAI link
*
* @card: soc card
@@ -2108,19 +1782,17 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,
static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
- struct snd_soc_tplg_link_config *link, *_link;
+ struct snd_soc_tplg_link_config *link;
int count;
int size;
int i, ret;
- bool abi_match;
count = le32_to_cpu(hdr->count);
/* check the element size and count */
link = (struct snd_soc_tplg_link_config *)tplg->pos;
size = le32_to_cpu(link->size);
- if (size > sizeof(struct snd_soc_tplg_link_config)
- || size < sizeof(struct snd_soc_tplg_link_config_v4)) {
+ if (size > sizeof(struct snd_soc_tplg_link_config)) {
dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n",
size);
return -EINVAL;
@@ -2135,30 +1807,17 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
for (i = 0; i < count; i++) {
link = (struct snd_soc_tplg_link_config *)tplg->pos;
size = le32_to_cpu(link->size);
- if (size == sizeof(*link)) {
- abi_match = true;
- _link = link;
- } else {
- abi_match = false;
- ret = link_new_ver(tplg, link, &_link);
- if (ret < 0)
- return ret;
- }
+ if (size != sizeof(*link))
+ return -EINVAL;
- ret = soc_tplg_link_config(tplg, _link);
- if (ret < 0) {
- if (!abi_match)
- kfree(_link);
+ ret = soc_tplg_link_config(tplg, link);
+ if (ret < 0)
return ret;
- }
/* offset by version-specific struct size and
* real priv data size
*/
- tplg->pos += size + le32_to_cpu(_link->priv.size);
-
- if (!abi_match)
- kfree(_link); /* free the duplicated one */
+ tplg->pos += size + le32_to_cpu(link->priv.size);
}
return 0;
@@ -2207,7 +1866,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
ret = set_stream_info(tplg, stream, caps);
if (ret < 0)
- goto err;
+ return ret;
}
if (d->capture) {
@@ -2215,7 +1874,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];
ret = set_stream_info(tplg, stream, caps);
if (ret < 0)
- goto err;
+ return ret;
}
if (d->flag_mask)
@@ -2227,13 +1886,10 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
if (ret < 0) {
dev_err(tplg->dev, "ASoC: DAI loading failed\n");
- goto err;
+ return ret;
}
return 0;
-
-err:
- return ret;
}
/* load physical DAI elements */
@@ -2268,84 +1924,21 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg,
return 0;
}
-/**
- * manifest_new_ver - Create a new version of manifest from the old version
- * of source.
- * @tplg: topology context
- * @src: old version of manifest as a source
- * @manifest: latest version of manifest created from the source
- *
- * Support from version 4. Users need free the returned manifest manually.
- */
-static int manifest_new_ver(struct soc_tplg *tplg,
- struct snd_soc_tplg_manifest *src,
- struct snd_soc_tplg_manifest **manifest)
-{
- struct snd_soc_tplg_manifest *dest;
- struct snd_soc_tplg_manifest_v4 *src_v4;
- int size;
-
- *manifest = NULL;
-
- size = le32_to_cpu(src->size);
- if (size != sizeof(*src_v4)) {
- dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n",
- size);
- if (size)
- return -EINVAL;
- src->size = cpu_to_le32(sizeof(*src_v4));
- }
-
- dev_warn(tplg->dev, "ASoC: old version of manifest\n");
-
- src_v4 = (struct snd_soc_tplg_manifest_v4 *)src;
- dest = kzalloc(sizeof(*dest) + le32_to_cpu(src_v4->priv.size),
- GFP_KERNEL);
- if (!dest)
- return -ENOMEM;
-
- dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */
- dest->control_elems = src_v4->control_elems;
- dest->widget_elems = src_v4->widget_elems;
- dest->graph_elems = src_v4->graph_elems;
- dest->pcm_elems = src_v4->pcm_elems;
- dest->dai_link_elems = src_v4->dai_link_elems;
- dest->priv.size = src_v4->priv.size;
- if (dest->priv.size)
- memcpy(dest->priv.data, src_v4->priv.data,
- le32_to_cpu(src_v4->priv.size));
-
- *manifest = dest;
- return 0;
-}
-
static int soc_tplg_manifest_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
- struct snd_soc_tplg_manifest *manifest, *_manifest;
- bool abi_match;
+ struct snd_soc_tplg_manifest *manifest;
int ret = 0;
manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
/* check ABI version by size, create a new manifest if abi not match */
- if (le32_to_cpu(manifest->size) == sizeof(*manifest)) {
- abi_match = true;
- _manifest = manifest;
- } else {
- abi_match = false;
-
- ret = manifest_new_ver(tplg, manifest, &_manifest);
- if (ret < 0)
- return ret;
- }
+ if (le32_to_cpu(manifest->size) != sizeof(*manifest))
+ return -EINVAL;
/* pass control to component driver for optional further init */
if (tplg->ops && tplg->ops->manifest)
- ret = tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
-
- if (!abi_match) /* free the duplicated one */
- kfree(_manifest);
+ ret = tplg->ops->manifest(tplg->comp, tplg->index, manifest);
return ret;
}
@@ -2492,8 +2085,11 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg)
/* load the header object */
ret = soc_tplg_load_header(tplg, hdr);
if (ret < 0) {
- dev_err(tplg->dev,
- "ASoC: topology: could not load header: %d\n", ret);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(tplg->dev,
+ "ASoC: topology: could not load header: %d\n",
+ ret);
+ }
return ret;
}
@@ -2524,7 +2120,7 @@ static int soc_tplg_load(struct soc_tplg *tplg)
/* load audio component topology from "firmware" file */
int snd_soc_tplg_component_load(struct snd_soc_component *comp,
- struct snd_soc_tplg_ops *ops, const struct firmware *fw)
+ const struct snd_soc_tplg_ops *ops, const struct firmware *fw)
{
struct soc_tplg tplg;
int ret;
@@ -2564,7 +2160,6 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
/* remove dynamic controls from the component driver */
int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
{
- struct snd_card *card = comp->card->snd_card;
struct snd_soc_dobj *dobj, *next_dobj;
int pass;
@@ -2572,7 +2167,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
for (pass = SOC_TPLG_PASS_END; pass >= SOC_TPLG_PASS_START; pass--) {
/* remove mixer controls */
- down_write(&card->controls_rwsem);
list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
list) {
@@ -2607,7 +2201,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
break;
}
}
- up_write(&card->controls_rwsem);
}
/* let caller know if FW can be freed when no objects are left */
diff --git a/sound/soc/soc-usb.c b/sound/soc/soc-usb.c
new file mode 100644
index 000000000000..26baa66d29a8
--- /dev/null
+++ b/sound/soc/soc-usb.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <linux/of.h>
+#include <linux/usb.h>
+
+#include <sound/jack.h>
+#include <sound/soc-usb.h>
+
+#include "../usb/card.h"
+
+static DEFINE_MUTEX(ctx_mutex);
+static LIST_HEAD(usb_ctx_list);
+
+static struct device_node *snd_soc_find_phandle(struct device *dev)
+{
+ struct device_node *node;
+
+ node = of_parse_phandle(dev->of_node, "usb-soc-be", 0);
+ if (!node)
+ return ERR_PTR(-ENODEV);
+
+ return node;
+}
+
+static struct snd_soc_usb *snd_soc_usb_ctx_lookup(struct device_node *node)
+{
+ struct snd_soc_usb *ctx;
+
+ if (!node)
+ return NULL;
+
+ list_for_each_entry(ctx, &usb_ctx_list, list) {
+ if (ctx->component->dev->of_node == node)
+ return ctx;
+ }
+
+ return NULL;
+}
+
+static struct snd_soc_usb *snd_soc_find_usb_ctx(struct device *dev)
+{
+ struct snd_soc_usb *ctx;
+ struct device_node *node;
+
+ node = snd_soc_find_phandle(dev);
+ if (!IS_ERR(node)) {
+ ctx = snd_soc_usb_ctx_lookup(node);
+ of_node_put(node);
+ } else {
+ ctx = snd_soc_usb_ctx_lookup(dev->of_node);
+ }
+
+ return ctx ? ctx : NULL;
+}
+
+/* SOC USB sound kcontrols */
+/**
+ * snd_soc_usb_setup_offload_jack() - Create USB offloading jack
+ * @component: USB DPCM backend DAI component
+ * @jack: jack structure to create
+ *
+ * Creates a jack device for notifying userspace of the availability
+ * of an offload capable device.
+ *
+ * Returns 0 on success, negative on error.
+ *
+ */
+int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack)
+{
+ int ret;
+
+ ret = snd_soc_card_jack_new(component->card, "USB Offload Jack",
+ SND_JACK_USB, jack);
+ if (ret < 0) {
+ dev_err(component->card->dev, "Unable to add USB offload jack: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+ if (ret) {
+ dev_err(component->card->dev, "Failed to set jack: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_setup_offload_jack);
+
+/**
+ * snd_soc_usb_update_offload_route - Find active USB offload path
+ * @dev: USB device to get offload status
+ * @card: USB card index
+ * @pcm: USB PCM device index
+ * @direction: playback or capture direction
+ * @path: pcm or card index
+ * @route: pointer to route output array
+ *
+ * Fetch the current status for the USB SND card and PCM device indexes
+ * specified. The "route" argument should be an array of integers being
+ * used for a kcontrol output. The first element should have the selected
+ * card index, and the second element should have the selected pcm device
+ * index.
+ */
+int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm,
+ int direction, enum snd_soc_usb_kctl path,
+ long *route)
+{
+ struct snd_soc_usb *ctx;
+ int ret = -ENODEV;
+
+ mutex_lock(&ctx_mutex);
+ ctx = snd_soc_find_usb_ctx(dev);
+ if (!ctx)
+ goto exit;
+
+ if (ctx->update_offload_route_info)
+ ret = ctx->update_offload_route_info(ctx->component, card, pcm,
+ direction, path, route);
+exit:
+ mutex_unlock(&ctx_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_update_offload_route);
+
+/**
+ * snd_soc_usb_find_priv_data() - Retrieve private data stored
+ * @usbdev: device reference
+ *
+ * Fetch the private data stored in the USB SND SoC structure.
+ *
+ */
+void *snd_soc_usb_find_priv_data(struct device *usbdev)
+{
+ struct snd_soc_usb *ctx;
+
+ mutex_lock(&ctx_mutex);
+ ctx = snd_soc_find_usb_ctx(usbdev);
+ mutex_unlock(&ctx_mutex);
+
+ return ctx ? ctx->priv_data : NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_find_priv_data);
+
+/**
+ * snd_soc_usb_find_supported_format() - Check if audio format is supported
+ * @card_idx: USB sound chip array index
+ * @params: PCM parameters
+ * @direction: capture or playback
+ *
+ * Ensure that a requested audio profile from the ASoC side is able to be
+ * supported by the USB device.
+ *
+ * Return 0 on success, negative on error.
+ *
+ */
+int snd_soc_usb_find_supported_format(int card_idx,
+ struct snd_pcm_hw_params *params,
+ int direction)
+{
+ struct snd_usb_stream *as;
+
+ as = snd_usb_find_suppported_substream(card_idx, params, direction);
+ if (!as)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_find_supported_format);
+
+/**
+ * snd_soc_usb_allocate_port() - allocate a SoC USB port for offloading support
+ * @component: USB DPCM backend DAI component
+ * @data: private data
+ *
+ * Allocate and initialize a SoC USB port. The SoC USB port is used to communicate
+ * different USB audio devices attached, in order to start audio offloading handled
+ * by an ASoC entity. USB device plug in/out events are signaled with a
+ * notification, but don't directly impact the memory allocated for the SoC USB
+ * port.
+ *
+ */
+struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component,
+ void *data)
+{
+ struct snd_soc_usb *usb;
+
+ usb = kzalloc(sizeof(*usb), GFP_KERNEL);
+ if (!usb)
+ return ERR_PTR(-ENOMEM);
+
+ usb->component = component;
+ usb->priv_data = data;
+
+ return usb;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_allocate_port);
+
+/**
+ * snd_soc_usb_free_port() - free a SoC USB port used for offloading support
+ * @usb: allocated SoC USB port
+ *
+ * Free and remove the SoC USB port from the available list of ports. This will
+ * ensure that the communication between USB SND and ASoC is halted.
+ *
+ */
+void snd_soc_usb_free_port(struct snd_soc_usb *usb)
+{
+ snd_soc_usb_remove_port(usb);
+ kfree(usb);
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_free_port);
+
+/**
+ * snd_soc_usb_add_port() - Add a USB backend port
+ * @usb: soc usb port to add
+ *
+ * Register a USB backend DAI link to the USB SoC framework. Memory is allocated
+ * as part of the USB backend DAI link.
+ *
+ */
+void snd_soc_usb_add_port(struct snd_soc_usb *usb)
+{
+ mutex_lock(&ctx_mutex);
+ list_add_tail(&usb->list, &usb_ctx_list);
+ mutex_unlock(&ctx_mutex);
+
+ snd_usb_rediscover_devices();
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_add_port);
+
+/**
+ * snd_soc_usb_remove_port() - Remove a USB backend port
+ * @usb: soc usb port to remove
+ *
+ * Remove a USB backend DAI link from USB SoC. Memory is freed when USB backend
+ * DAI is removed, or when snd_soc_usb_free_port() is called.
+ *
+ */
+void snd_soc_usb_remove_port(struct snd_soc_usb *usb)
+{
+ struct snd_soc_usb *ctx, *tmp;
+
+ mutex_lock(&ctx_mutex);
+ list_for_each_entry_safe(ctx, tmp, &usb_ctx_list, list) {
+ if (ctx == usb) {
+ list_del(&ctx->list);
+ break;
+ }
+ }
+ mutex_unlock(&ctx_mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_remove_port);
+
+/**
+ * snd_soc_usb_connect() - Notification of USB device connection
+ * @usbdev: USB bus device
+ * @sdev: USB SND device to add
+ *
+ * Notify of a new USB SND device connection. The sdev->card_idx can be used to
+ * handle how the DPCM backend selects, which device to enable USB offloading
+ * on.
+ *
+ */
+int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev)
+{
+ struct snd_soc_usb *ctx;
+
+ if (!usbdev)
+ return -ENODEV;
+
+ mutex_lock(&ctx_mutex);
+ ctx = snd_soc_find_usb_ctx(usbdev);
+ if (!ctx)
+ goto exit;
+
+ if (ctx->connection_status_cb)
+ ctx->connection_status_cb(ctx, sdev, true);
+
+exit:
+ mutex_unlock(&ctx_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_connect);
+
+/**
+ * snd_soc_usb_disconnect() - Notification of USB device disconnection
+ * @usbdev: USB bus device
+ * @sdev: USB SND device to remove
+ *
+ * Notify of a new USB SND device disconnection to the USB backend.
+ *
+ */
+int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev)
+{
+ struct snd_soc_usb *ctx;
+
+ if (!usbdev)
+ return -ENODEV;
+
+ mutex_lock(&ctx_mutex);
+ ctx = snd_soc_find_usb_ctx(usbdev);
+ if (!ctx)
+ goto exit;
+
+ if (ctx->connection_status_cb)
+ ctx->connection_status_cb(ctx, sdev, false);
+
+exit:
+ mutex_unlock(&ctx_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_usb_disconnect);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SoC USB driver for offloading");
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 11607c5f5d5a..c8adfff826bd 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,13 +15,40 @@
#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;
}
EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size);
-int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
+int snd_soc_params_to_frame_size(const struct snd_pcm_hw_params *params)
{
int sample_size;
@@ -40,7 +67,7 @@ int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots)
}
EXPORT_SYMBOL_GPL(snd_soc_calc_bclk);
-int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
+int snd_soc_params_to_bclk(const struct snd_pcm_hw_params *params)
{
int ret;
@@ -79,7 +106,7 @@ EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
* Return: bclk frequency in Hz, else a negative error code if params format
* is invalid.
*/
-int snd_soc_tdm_params_to_bclk(struct snd_pcm_hw_params *params,
+int snd_soc_tdm_params_to_bclk(const struct snd_pcm_hw_params *params,
int tdm_width, int tdm_slots, int slot_multiple)
{
if (!tdm_slots)
@@ -103,8 +130,8 @@ static const struct snd_pcm_hardware dummy_dma_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER,
.buffer_bytes_max = 128*1024,
- .period_bytes_min = PAGE_SIZE,
- .period_bytes_max = PAGE_SIZE*2,
+ .period_bytes_min = 4096,
+ .period_bytes_max = 4096*2,
.periods_min = 2,
.periods_max = 128,
};
@@ -115,7 +142,7 @@ static const struct snd_soc_component_driver dummy_platform;
static int dummy_dma_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int i;
/*
@@ -144,7 +171,6 @@ static const struct snd_soc_component_driver dummy_codec = {
.endianness = 1,
};
-#define STUB_RATES SNDRV_PCM_RATE_8000_384000
#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
@@ -163,7 +189,7 @@ static const struct snd_soc_component_driver dummy_codec = {
* SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
* SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
*/
-static u64 dummy_dai_formats =
+static const u64 dummy_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
@@ -198,25 +224,30 @@ static struct snd_soc_dai_driver dummy_dai = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 384,
- .rates = STUB_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 768000,
.formats = STUB_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 384,
- .rates = STUB_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 768000,
.formats = STUB_FORMATS,
},
.ops = &dummy_dai_ops,
};
-int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
+int snd_soc_dai_is_dummy(const struct snd_soc_dai *dai)
{
if (dai->driver == &dummy_dai)
return 1;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_dai_is_dummy);
int snd_soc_component_is_dummy(struct snd_soc_component *component)
{
@@ -224,55 +255,58 @@ int snd_soc_component_is_dummy(struct snd_soc_component *component)
(component->driver == &dummy_codec));
}
-struct snd_soc_dai_link_component asoc_dummy_dlc = {
+struct snd_soc_dai_link_component snd_soc_dummy_dlc = {
.of_node = NULL,
.dai_name = "snd-soc-dummy-dai",
.name = "snd-soc-dummy",
};
-EXPORT_SYMBOL_GPL(asoc_dummy_dlc);
+EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc);
+
+int snd_soc_dlc_is_dummy(struct snd_soc_dai_link_component *dlc)
+{
+ if (dlc == &snd_soc_dummy_dlc)
+ return true;
+
+ if ((dlc->name && strcmp(dlc->name, snd_soc_dummy_dlc.name) == 0) ||
+ (dlc->dai_name && strcmp(dlc->dai_name, snd_soc_dummy_dlc.dai_name) == 0))
+ return true;
-static int snd_soc_dummy_probe(struct platform_device *pdev)
+ return false;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dlc_is_dummy);
+
+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);
-
- ret = platform_driver_register(&soc_dummy_driver);
- if (ret != 0)
- platform_device_unregister(soc_dummy_dev);
+ soc_dummy_dev = faux_device_create("snd-soc-dummy", NULL,
+ &soc_dummy_ops);
+ if (!soc_dummy_dev)
+ return -ENODEV;
- 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/Kconfig b/sound/soc/sof/Kconfig
index 80361139a49a..a487ab0b51c7 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SND_SOC_SOF_TOPLEVEL
- bool "Sound Open Firmware Support"
+ bool "Sound Open Firmware (SOF) platforms"
help
This adds support for Sound Open Firmware (SOF). SOF is free and
generic open source audio DSP firmware for multiple devices.
@@ -126,6 +126,17 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS
If you are not involved in SOF releases and CI development,
select "N".
+config SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION
+ bool "SOF allow fallback to newer IPC version"
+ help
+ This option will allow the kernel to try to 'fallback' to a newer IPC
+ version if there are missing firmware files to satisfy the default IPC
+ version.
+ IPC version fallback to older versions is not affected by this option,
+ it is always available.
+ Say Y if you are involved in SOF development and need this option.
+ If not, select N.
+
config SND_SOC_SOF_DEBUG
bool "SOF debugging features"
help
@@ -283,7 +294,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE
config SND_SOC_SOF_IPC3
bool
-config SND_SOC_SOF_INTEL_IPC4
+config SND_SOC_SOF_IPC4
bool
source "sound/soc/sof/amd/Kconfig"
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index 744d40bd8c8b..b0b22e6ebc03 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -1,43 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
- control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
+snd-sof-y := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
+ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
+ fw-file-profile.o
# IPC implementations
ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
-snd-sof-objs += ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\
+snd-sof-y += ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\
ipc3-dtrace.o
endif
-ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),)
-snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\
- ipc4-mtrace.o
+ifneq ($(CONFIG_SND_SOC_SOF_IPC4),)
+snd-sof-y += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\
+ ipc4-mtrace.o ipc4-telemetry.o
endif
# SOF client support
ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
-snd-sof-objs += sof-client.o
+snd-sof-y += sof-client.o
endif
snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o
-snd-sof-pci-objs := sof-pci-dev.o
-snd-sof-acpi-objs := sof-acpi-dev.o
-snd-sof-of-objs := sof-of-dev.o
+snd-sof-pci-y := sof-pci-dev.o
+snd-sof-acpi-y := sof-acpi-dev.o
+snd-sof-of-y := sof-of-dev.o
-snd-sof-ipc-flood-test-objs := sof-client-ipc-flood-test.o
-snd-sof-ipc-msg-injector-objs := sof-client-ipc-msg-injector.o
-snd-sof-ipc-kernel-injector-objs := sof-client-ipc-kernel-injector.o
-snd-sof-probes-objs := sof-client-probes.o
+snd-sof-ipc-flood-test-y := sof-client-ipc-flood-test.o
+snd-sof-ipc-msg-injector-y := sof-client-ipc-msg-injector.o
+snd-sof-ipc-kernel-injector-y := sof-client-ipc-kernel-injector.o
+snd-sof-probes-y := sof-client-probes.o
ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
-snd-sof-probes-objs += sof-client-probes-ipc3.o
+snd-sof-probes-y += sof-client-probes-ipc3.o
endif
-ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),)
-snd-sof-probes-objs += sof-client-probes-ipc4.o
+ifneq ($(CONFIG_SND_SOC_SOF_IPC4),)
+snd-sof-probes-y += sof-client-probes-ipc4.o
endif
-snd-sof-nocodec-objs := nocodec.o
+snd-sof-nocodec-y := nocodec.o
-snd-sof-utils-objs := sof-utils.o
+snd-sof-utils-y := sof-utils.o
obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o
obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 1cb92d6030e3..05faf1c6d6fc 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -2,10 +2,11 @@
# 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) 2021 Advanced Micro Devices, Inc. All rights reserved.
+# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
config SND_SOC_SOF_AMD_TOPLEVEL
tristate "SOF support for AMD audio DSPs"
+ depends on SOUNDWIRE_AMD || !SOUNDWIRE_AMD
depends on X86 || COMPILE_TEST
help
This adds support for Sound Open Firmware for AMD platforms.
@@ -21,6 +22,8 @@ config SND_SOC_SOF_AMD_COMMON
select SND_SOC_SOF_PCI_DEV
select SND_AMD_ACP_CONFIG
select SND_SOC_SOF_XTENSA
+ select SND_SOC_SOF_ACP_PROBES
+ select SND_SOC_ACPI_AMD_MATCH
select SND_SOC_ACPI if ACPI
help
This option is not user-selectable but automatically handled by
@@ -29,17 +32,76 @@ 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
+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
+ on AMD Vangogh platform.
+ Say Y if you want to enable SOF on Vangogh.
+ If unsure select "N".
+
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
Say Y if you want to enable SOF on Rembrandt.
If unsure select "N".
+config SND_SOC_SOF_ACP_PROBES
+ tristate
+ select SND_SOC_SOF_DEBUG_PROBES
+ help
+ This option is not user-selectable but automatically handled by
+ 'select' statements at a higher level
+
+config SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
+ tristate
+ select SND_AMD_SOUNDWIRE_ACPI if ACPI
+
+config SND_SOC_SOF_AMD_SOUNDWIRE
+ tristate "SOF support for SoundWire based AMD platforms"
+ default SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
+ depends on SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
+ depends on ACPI
+ depends on SOUNDWIRE_AMD
+ help
+ This adds support for SoundWire with Sound Open Firmware
+ for AMD platforms.
+ Say Y if you want to enable SoundWire links with SOF.
+ If unsure select "N".
+
+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
+ Select this option for SOF support on
+ AMD ACP6.3 version based platforms.
+ Say Y if you want to enable SOF on ACP6.3 based platform.
+ If unsure select "N".
+
+config SND_SOC_SOF_AMD_ACP70
+ tristate "SOF support for ACP7.0/ACP7.1 platforms"
+ 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
+ Select this option for SOF support on
+ AMD ACP7.0/ACP7.1 version based platforms.
+ Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms.
+
endif
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile
index 5626d13b3e69..6ae39fd5a836 100644
--- a/sound/soc/sof/amd/Makefile
+++ b/sound/soc/sof/amd/Makefile
@@ -2,12 +2,19 @@
# 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) 2021 Advanced Micro Devices, Inc. All rights reserved.
+# Copyright(c) 2021, 2023, 2024 Advanced Micro Devices, Inc. All rights reserved.
-snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o
-snd-sof-amd-renoir-objs := pci-rn.o renoir.o
-snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o
+snd-sof-amd-acp-y := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o
+snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) += acp-probes.o
+snd-sof-amd-renoir-y := pci-rn.o renoir.o
+snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o
+snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o
+snd-sof-amd-acp63-y := pci-acp63.o acp63.o
+snd-sof-amd-acp70-y := pci-acp70.o acp70.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
-obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o
-obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) += snd-sof-amd-renoir.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index df36b411a12e..0c3a92f5f942 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -13,7 +13,6 @@
#include "../sof-priv.h"
#include "../sof-audio.h"
#include "../ops.h"
-#include "../sof-audio.h"
#include "acp.h"
#include "acp-dsp-offset.h"
#include <sound/sof/xtensa.h>
@@ -119,18 +118,76 @@ void amd_sof_dump(struct snd_sof_dev *sdev, u32 flags)
&panic_info, stack, AMD_STACK_DUMP_SIZE);
}
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE)
+static int amd_sof_sdw_get_slave_info(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
+
+ return sdw_amd_get_slave_info(acp_data->sdw);
+}
+
+static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_soc_acpi_mach *mach;
+ const struct snd_soc_acpi_link_adr *link;
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
+ int ret, i;
+
+ if (acp_data->info.count) {
+ ret = amd_sof_sdw_get_slave_info(sdev);
+ if (ret) {
+ dev_info(sdev->dev, "failed to read slave information\n");
+ return NULL;
+ }
+ for (mach = sdev->pdata->desc->alt_machines; mach; mach++) {
+ if (!mach->links)
+ break;
+ link = mach->links;
+ for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
+ if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
+ acp_data->sdw->peripherals))
+ break;
+ }
+ if (i == acp_data->info.count || !link->num_adr)
+ break;
+ }
+ if (mach && mach->link_mask) {
+ mach->mach_params.subsystem_rev = acp_data->pci_rev;
+ mach->mach_params.links = mach->links;
+ mach->mach_params.link_mask = mach->link_mask;
+ mach->mach_params.platform = dev_name(sdev->dev);
+ return mach;
+ }
+ }
+ dev_info(sdev->dev, "No SoundWire machine driver found\n");
+ return NULL;
+}
+
+#else
+static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *sdev)
+{
+ return NULL;
+}
+#endif
+
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
const struct sof_dev_desc *desc = sof_pdata->desc;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = NULL;
- mach = snd_soc_acpi_find_machine(desc->machines);
+ if (desc->machines)
+ mach = snd_soc_acpi_find_machine(desc->machines);
if (!mach) {
- dev_warn(sdev->dev, "No matching ASoC machine driver found\n");
- return NULL;
+ mach = amd_sof_sdw_machine_select(sdev);
+ if (!mach) {
+ dev_warn(sdev->dev, "No matching ASoC machine driver found\n");
+ return NULL;
+ }
}
+ mach->mach_params.subsystem_rev = acp_data->pci_rev;
sof_pdata->tplg_filename = mach->sof_tplg_filename;
sof_pdata->fw_filename = mach->fw_filename;
@@ -138,7 +195,7 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
}
/* AMD Common DSP ops */
-struct snd_sof_dsp_ops sof_acp_common_ops = {
+const struct snd_sof_dsp_ops sof_acp_common_ops = {
/* probe and remove */
.probe = amd_sof_acp_probe,
.remove = amd_sof_acp_remove,
@@ -196,10 +253,15 @@ struct snd_sof_dsp_ops sof_acp_common_ops = {
.dbg_dump = amd_sof_dump,
.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
.dsp_arch_ops = &sof_xtensa_arch_ops,
+
+ /* probe client device registation */
+ .register_ipc_clients = acp_probes_register,
+ .unregister_ipc_clients = acp_probes_unregister,
};
-EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(sof_acp_common_ops, "SND_SOC_SOF_AMD_COMMON");
-MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_DESCRIPTION("ACP SOF COMMON Driver");
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("ACP SOF COMMON Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
+MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index 920155dee819..08583a91afbc 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -3,7 +3,7 @@
* 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) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright(c) 2021, 2023, 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
*/
@@ -23,6 +23,17 @@
#define ACP_DMA_CH_STS 0xE8
#define ACP_DMA_CH_GROUP 0xEC
#define ACP_DMA_CH_RST_STS 0xF0
+#define ACP70_DMA_CNTL_0 0x00
+#define ACP70_DMA_DSCR_STRT_IDX_0 0x28
+#define ACP70_DMA_DSCR_CNT_0 0x50
+#define ACP70_DMA_PRIO_0 0x78
+#define ACP70_DMA_CUR_DSCR_0 0xA0
+#define ACP70_DMA_ERR_STS_0 0xF0
+#define ACP70_DMA_DESC_BASE_ADDR 0x118
+#define ACP70_DMA_DESC_MAX_NUM_DSCR 0x11C
+#define ACP70_DMA_CH_STS 0x120
+#define ACP70_DMA_CH_GROUP 0x124
+#define ACP70_DMA_CH_RST_STS 0x128
/* Registers from ACP_DSP_0 block */
#define ACP_DSP0_RUNSTALL 0x414
@@ -49,28 +60,53 @@
#define ACP_CONTROL 0x1004
#define ACP3X_I2S_PIN_CONFIG 0x1400
+#define ACP5X_I2S_PIN_CONFIG 0x1400
#define ACP6X_I2S_PIN_CONFIG 0x1440
/* Registers offsets from ACP_PGFSM block */
#define ACP3X_PGFSM_BASE 0x141C
+#define ACP5X_PGFSM_BASE 0x1424
#define ACP6X_PGFSM_BASE 0x1024
+#define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE
#define PGFSM_CONTROL_OFFSET 0x0
#define PGFSM_STATUS_OFFSET 0x4
#define ACP3X_CLKMUX_SEL 0x1424
+#define ACP5X_CLKMUX_SEL 0x142C
#define ACP6X_CLKMUX_SEL 0x102C
+#define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL
/* Registers from ACP_INTR block */
#define ACP3X_EXT_INTR_STAT 0x1808
+#define ACP5X_EXT_INTR_STAT 0x1808
+#define ACP6X_EXTERNAL_INTR_ENB 0x1A00
+#define ACP6X_EXTERNAL_INTR_CNTL 0x1A04
#define ACP6X_EXT_INTR_STAT 0x1A0C
+#define ACP6X_EXT_INTR_STAT1 0x1A10
+#define ACP70_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB
+#define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL
+#define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT
+#define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1
#define ACP3X_DSP_SW_INTR_BASE 0x1814
+#define ACP5X_DSP_SW_INTR_BASE 0x1814
#define ACP6X_DSP_SW_INTR_BASE 0x1808
+#define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE
#define DSP_SW_INTR_CNTL_OFFSET 0x0
#define DSP_SW_INTR_STAT_OFFSET 0x4
#define DSP_SW_INTR_TRIG_OFFSET 0x8
-#define ACP_ERROR_STATUS 0x18C4
+#define ACP3X_ERROR_STATUS 0x18C4
+#define ACP6X_ERROR_STATUS 0x1A4C
+#define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS
#define ACP3X_AXI2DAGB_SEM_0 0x1880
+#define ACP5X_AXI2DAGB_SEM_0 0x1884
#define ACP6X_AXI2DAGB_SEM_0 0x1874
+#define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0
+
+/* ACP common registers to report errors related to I2S & SoundWire interfaces */
+#define ACP3X_SW_I2S_ERROR_REASON 0x18C8
+#define ACP6X_SW0_I2S_ERROR_REASON 0x18B4
+#define ACP7X_SW0_I2S_ERROR_REASON ACP6X_SW0_I2S_ERROR_REASON
+#define ACP_SW1_I2S_ERROR_REASON 0x1A50
/* Registers from ACP_SHA block */
#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70
@@ -81,12 +117,27 @@
#define ACP_SHA_DMA_CMD_STS 0x1CC0
#define ACP_SHA_DMA_ERR_STATUS 0x1CC4
#define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8
+#define ACP_SHA_DMA_INCLUDE_HDR 0x1CCC
#define ACP_SHA_PSP_ACK 0x1C74
#define ACP_SCRATCH_REG_0 0x10000
#define ACP6X_DSP_FUSION_RUNSTALL 0x0644
+#define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL
/* Cache window registers */
#define ACP_DSP0_CACHE_OFFSET0 0x0420
#define ACP_DSP0_CACHE_SIZE0 0x0424
+
+#define ACP_SW0_EN 0x3000
+#define ACP_SW1_EN 0x3C00
+#define ACP70_PME_EN 0x1400
+#define ACP70_EXTERNAL_INTR_CNTL1 0x1A08
+#define ACP70_SW0_WAKE_EN 0x1458
+#define ACP70_SW1_WAKE_EN 0x1460
+#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)
+
#endif
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index 8a0fc635a997..22d4b807e1bb 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Balakishore Pati <Balakishore.pati@amd.com>
// Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
@@ -19,13 +19,13 @@ void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size
{
memcpy_to_scratch(sdev, offset, message, bytes);
}
-EXPORT_SYMBOL_NS(acp_mailbox_write, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_mailbox_write, "SND_SOC_SOF_AMD_COMMON");
void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes)
{
memcpy_from_scratch(sdev, offset, message, bytes);
}
-EXPORT_SYMBOL_NS(acp_mailbox_read, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_mailbox_read, "SND_SOC_SOF_AMD_COMMON");
static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata)
{
@@ -91,7 +91,7 @@ int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, "SND_SOC_SOF_AMD_COMMON");
static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
{
@@ -155,6 +155,8 @@ out:
irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
unsigned int dsp_msg_write = sdev->debug_box.offset +
offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
unsigned int dsp_ack_write = sdev->debug_box.offset +
@@ -163,11 +165,14 @@ 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);
+ status = 0;
+ acp_mailbox_write(sdev, sdev->dsp_box.offset, &status, sizeof(status));
return IRQ_HANDLED;
}
snd_sof_ipc_msgs_rx(sdev);
@@ -184,28 +189,62 @@ 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;
}
acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32));
if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, sdev->dsp_oops_offset, true);
+ status = 0;
+ acp_mailbox_write(sdev, sdev->debug_box.offset, &status, sizeof(status));
return IRQ_HANDLED;
}
+ if (desc->probe_reg_offset) {
+ u32 val;
+ u32 posn;
+
+ /* Probe register consists of two parts
+ * (0-30) bit has cumulative position value
+ * 31 bit is a synchronization flag between DSP and CPU
+ * for the position update
+ */
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->probe_reg_offset);
+ if (val & PROBE_STATUS_BIT) {
+ posn = val & ~PROBE_STATUS_BIT;
+ if (adata->probe_stream) {
+ /* Probe related posn value is of 31 bits limited to 2GB
+ * once wrapped DSP won't send posn interrupt.
+ */
+ adata->probe_stream->cstream_posn = posn;
+ snd_compr_fragment_elapsed(adata->probe_stream->cstream);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->probe_reg_offset, posn);
+ ipc_irq = true;
+ }
+ }
+ }
+
if (!ipc_irq)
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, "SND_SOC_SOF_AMD_COMMON");
int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps,
void *p, size_t sz)
@@ -231,7 +270,7 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sp
return 0;
}
-EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, "SND_SOC_SOF_AMD_COMMON");
int acp_set_stream_data_offset(struct snd_sof_dev *sdev,
struct snd_sof_pcm_stream *sps,
@@ -252,7 +291,7 @@ int acp_set_stream_data_offset(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(acp_set_stream_data_offset, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_set_stream_data_offset, "SND_SOC_SOF_AMD_COMMON");
int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
@@ -260,12 +299,12 @@ int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
return desc->sram_pte_offset;
}
-EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, "SND_SOC_SOF_AMD_COMMON");
int acp_sof_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return 0;
}
-EXPORT_SYMBOL_NS(acp_sof_ipc_get_window_offset, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_ipc_get_window_offset, "SND_SOC_SOF_AMD_COMMON");
MODULE_DESCRIPTION("AMD ACP sof-ipc driver");
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index a4bce5a3ae48..98324bbade15 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
@@ -19,8 +19,9 @@
#include "acp-dsp-offset.h"
#include "acp.h"
-#define FW_BIN 0
-#define FW_DATA_BIN 1
+#define FW_BIN 0
+#define FW_DATA_BIN 1
+#define FW_SRAM_DATA_BIN 2
#define FW_BIN_PTE_OFFSET 0x00
#define FW_DATA_BIN_PTE_OFFSET 0x08
@@ -43,13 +44,12 @@ int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_ty
return 0;
}
-EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_dsp_block_read, "SND_SOC_SOF_AMD_COMMON");
int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
u32 offset, void *src, size_t size)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
- const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
struct acp_dev_data *adata;
void *dest;
u32 dma_size, page_count;
@@ -65,7 +65,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
dma_size = page_count * ACP_PAGE_SIZE;
adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size,
&adata->sha_dma_addr,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!adata->bin_buf)
return -ENOMEM;
}
@@ -77,17 +77,27 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
adata->data_buf = dma_alloc_coherent(&pci->dev,
ACP_DEFAULT_DRAM_LENGTH,
&adata->dma_addr,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!adata->data_buf)
return -ENOMEM;
}
dest = adata->data_buf + offset;
adata->fw_data_bin_size = size + offset;
+ adata->is_dram_in_use = true;
break;
case SOF_FW_BLK_TYPE_SRAM:
- offset = offset - desc->sram_pte_offset;
- memcpy_to_scratch(sdev, offset, src, size);
- return 0;
+ if (!adata->sram_data_buf) {
+ adata->sram_data_buf = dma_alloc_coherent(&pci->dev,
+ ACP_DEFAULT_SRAM_LENGTH,
+ &adata->sram_dma_addr,
+ GFP_KERNEL);
+ if (!adata->sram_data_buf)
+ return -ENOMEM;
+ }
+ adata->fw_sram_data_bin_size = size + offset;
+ dest = adata->sram_data_buf + offset;
+ adata->is_sram_in_use = true;
+ break;
default:
dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type);
return -EINVAL;
@@ -96,13 +106,13 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
memcpy(dest, src, size);
return 0;
}
-EXPORT_SYMBOL_NS(acp_dsp_block_write, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_dsp_block_write, "SND_SOC_SOF_AMD_COMMON");
int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
{
return type;
}
-EXPORT_SYMBOL_NS(acp_get_bar_index, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_get_bar_index, "SND_SOC_SOF_AMD_COMMON");
static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata)
{
@@ -122,6 +132,10 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev
offset = adata->fw_bin_page_count * 8;
addr = adata->dma_addr;
break;
+ case FW_SRAM_DATA_BIN:
+ offset = (adata->fw_bin_page_count + ACP_DRAM_PAGE_COUNT) * 8;
+ addr = adata->sram_dma_addr;
+ break;
default:
dev_err(sdev->dev, "Invalid data type %x\n", type);
return;
@@ -153,12 +167,16 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
struct pci_dev *pci = to_pci_dev(sdev->dev);
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
struct acp_dev_data *adata;
- unsigned int src_addr, size_fw;
+ unsigned int src_addr, size_fw, dest_addr;
u32 page_count, dma_size;
int ret;
adata = sdev->pdata->hw_pdata;
- size_fw = adata->fw_bin_size;
+
+ if (adata->quirks && adata->quirks->signed_fw_image)
+ size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
+ else
+ size_fw = adata->fw_bin_size;
page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
adata->fw_bin_page_count = page_count;
@@ -170,21 +188,41 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "SHA DMA transfer failed status: %d\n", ret);
return ret;
}
- configure_pte_for_fw_loading(FW_DATA_BIN, ACP_DRAM_PAGE_COUNT, adata);
+ if (adata->is_dram_in_use) {
+ configure_pte_for_fw_loading(FW_DATA_BIN, ACP_DRAM_PAGE_COUNT, adata);
+ src_addr = ACP_SYSTEM_MEMORY_WINDOW + (page_count * ACP_PAGE_SIZE);
+ dest_addr = ACP_DRAM_BASE_ADDRESS;
- src_addr = ACP_SYSTEM_MEMORY_WINDOW + page_count * ACP_PAGE_SIZE;
- ret = configure_and_run_dma(adata, src_addr, ACP_DATA_RAM_BASE_ADDRESS,
- adata->fw_data_bin_size);
- if (ret < 0) {
- dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret);
- return ret;
+ ret = configure_and_run_dma(adata, src_addr, dest_addr, adata->fw_data_bin_size);
+ if (ret < 0) {
+ dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret);
+ return ret;
+ }
+ ret = acp_dma_status(adata, 0);
+ if (ret < 0)
+ dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
}
+ if (adata->is_sram_in_use) {
+ configure_pte_for_fw_loading(FW_SRAM_DATA_BIN, ACP_SRAM_PAGE_COUNT, adata);
+ src_addr = ACP_SYSTEM_MEMORY_WINDOW + ACP_DEFAULT_SRAM_LENGTH +
+ (page_count * ACP_PAGE_SIZE);
+ if (adata->pci_rev > ACP63_PCI_ID)
+ dest_addr = ACP7X_SRAM_BASE_ADDRESS;
+ else
+ dest_addr = ACP_SRAM_BASE_ADDRESS;
- ret = acp_dma_status(adata, 0);
- if (ret < 0)
- dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
+ ret = configure_and_run_dma(adata, src_addr, dest_addr,
+ adata->fw_sram_data_bin_size);
+ if (ret < 0) {
+ dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret);
+ return ret;
+ }
+ ret = acp_dma_status(adata, 0);
+ if (ret < 0)
+ dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
+ }
- if (desc->rev > 3) {
+ if (adata->pci_rev > ACP_RN_PCI_ID) {
/* Cache Window enable */
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_OFFSET0, desc->sram_pte_offset);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_SIZE0, SRAM1_SIZE | BIT(31));
@@ -193,16 +231,24 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
/* Free memory once DMA is complete */
dma_size = (PAGE_ALIGN(sdev->basefw.fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr);
- dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf, adata->dma_addr);
adata->bin_buf = NULL;
- adata->data_buf = NULL;
-
+ if (adata->is_dram_in_use) {
+ dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf,
+ adata->dma_addr);
+ adata->data_buf = NULL;
+ }
+ if (adata->is_sram_in_use) {
+ dma_free_coherent(&pci->dev, ACP_DEFAULT_SRAM_LENGTH, adata->sram_data_buf,
+ adata->sram_dma_addr);
+ adata->sram_data_buf = NULL;
+ }
return ret;
}
-EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, "SND_SOC_SOF_AMD_COMMON");
int acp_sof_dsp_run(struct snd_sof_dev *sdev)
{
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
int val;
@@ -211,11 +257,64 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val);
/* Some platforms won't support fusion DSP,keep offset zero for no support */
- if (desc->fusion_dsp_offset) {
+ if (desc->fusion_dsp_offset && adata->enable_fw_debug) {
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN);
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset);
dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val);
}
return 0;
}
-EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_dsp_run, "SND_SOC_SOF_AMD_COMMON");
+
+int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct acp_dev_data *adata = plat_data->hw_pdata;
+ const char *fw_filename;
+ int ret;
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
+ plat_data->fw_filename_prefix,
+ adata->fw_code_bin);
+ if (!fw_filename)
+ return -ENOMEM;
+
+ ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
+ if (ret < 0) {
+ kfree(fw_filename);
+ dev_err(sdev->dev, "sof signed firmware code bin is missing\n");
+ return ret;
+ } else {
+ dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
+ }
+ kfree(fw_filename);
+
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
+ (void *)sdev->basefw.fw->data,
+ sdev->basefw.fw->size);
+ if (ret < 0)
+ return ret;
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
+ plat_data->fw_filename_prefix,
+ adata->fw_data_bin);
+ if (!fw_filename)
+ return -ENOMEM;
+
+ ret = request_firmware(&adata->fw_dbin, fw_filename, sdev->dev);
+ if (ret < 0) {
+ kfree(fw_filename);
+ dev_err(sdev->dev, "sof signed firmware data bin is missing\n");
+ return ret;
+
+ } else {
+ dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
+ }
+ kfree(fw_filename);
+
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
+ (void *)adata->fw_dbin->data,
+ adata->fw_dbin->size);
+ return ret;
+}
+EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON");
diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c
index 0828245bbb99..2802684f26de 100644
--- a/sound/soc/sof/amd/acp-pcm.c
+++ b/sound/soc/sof/amd/acp-pcm.c
@@ -52,7 +52,7 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr
return 0;
}
-EXPORT_SYMBOL_NS(acp_pcm_hw_params, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_pcm_hw_params, "SND_SOC_SOF_AMD_COMMON");
int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
@@ -67,7 +67,7 @@ int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
return 0;
}
-EXPORT_SYMBOL_NS(acp_pcm_open, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_pcm_open, "SND_SOC_SOF_AMD_COMMON");
int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
@@ -84,12 +84,12 @@ int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
return acp_dsp_stream_put(sdev, stream);
}
-EXPORT_SYMBOL_NS(acp_pcm_close, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_pcm_close, "SND_SOC_SOF_AMD_COMMON");
snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(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;
@@ -117,4 +117,4 @@ snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev,
return pos;
}
-EXPORT_SYMBOL_NS(acp_pcm_pointer, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_pcm_pointer, "SND_SOC_SOF_AMD_COMMON");
diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c
new file mode 100644
index 000000000000..ce51ed108a47
--- /dev/null
+++ b/sound/soc/sof/amd/acp-probes.c
@@ -0,0 +1,147 @@
+// 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) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: V Sujith Kumar Reddy <Vsujithkumar.Reddy@amd.com>
+
+/*
+ * Probe interface for generic AMD audio ACP DSP block
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include "../sof-priv.h"
+#include "../sof-client-probes.h"
+#include "../sof-client.h"
+#include "../ops.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+static int acp_probes_compr_startup(struct sof_client_dev *cdev,
+ struct snd_compr_stream *cstream,
+ struct snd_soc_dai *dai, u32 *stream_id)
+{
+ struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+ struct acp_dsp_stream *stream;
+ struct acp_dev_data *adata;
+
+ adata = sdev->pdata->hw_pdata;
+ stream = acp_dsp_stream_get(sdev, 0);
+ if (!stream)
+ return -ENODEV;
+
+ stream->cstream = cstream;
+ cstream->runtime->private_data = stream;
+
+ adata->probe_stream = stream;
+ *stream_id = stream->stream_tag;
+
+ return 0;
+}
+
+static int acp_probes_compr_shutdown(struct sof_client_dev *cdev,
+ struct snd_compr_stream *cstream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+ struct acp_dsp_stream *stream = cstream->runtime->private_data;
+ struct acp_dev_data *adata;
+ int ret;
+
+ ret = acp_dsp_stream_put(sdev, stream);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Failed to release probe compress stream\n");
+ return ret;
+ }
+
+ adata = sdev->pdata->hw_pdata;
+ stream->cstream = NULL;
+ cstream->runtime->private_data = NULL;
+ adata->probe_stream = NULL;
+
+ return 0;
+}
+
+static int acp_probes_compr_set_params(struct sof_client_dev *cdev,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+ struct acp_dsp_stream *stream = cstream->runtime->private_data;
+ unsigned int buf_offset, index;
+ u32 size;
+ int ret;
+
+ stream->dmab = cstream->runtime->dma_buffer_p;
+ stream->num_pages = PFN_UP(cstream->runtime->dma_bytes);
+ size = cstream->runtime->buffer_size;
+
+ ret = acp_dsp_stream_config(sdev, stream);
+ if (ret < 0) {
+ acp_dsp_stream_put(sdev, stream);
+ return ret;
+ }
+
+ /* write buffer size of stream in scratch memory */
+
+ buf_offset = sdev->debug_box.offset +
+ offsetof(struct scratch_reg_conf, buf_size);
+ index = stream->stream_tag - 1;
+ buf_offset = buf_offset + index * 4;
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size);
+
+ return 0;
+}
+
+static int acp_probes_compr_trigger(struct sof_client_dev *cdev,
+ struct snd_compr_stream *cstream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ /* Nothing to do here, as it is a mandatory callback just defined */
+ return 0;
+}
+
+static int acp_probes_compr_pointer(struct sof_client_dev *cdev,
+ struct snd_compr_stream *cstream,
+ struct snd_compr_tstamp64 *tstamp,
+ struct snd_soc_dai *dai)
+{
+ struct acp_dsp_stream *stream = cstream->runtime->private_data;
+ struct snd_soc_pcm_stream *pstream;
+
+ pstream = &dai->driver->capture;
+ tstamp->copied_total = stream->cstream_posn;
+ tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
+
+ return 0;
+}
+
+/* SOF client implementation */
+static const struct sof_probes_host_ops acp_probes_ops = {
+ .startup = acp_probes_compr_startup,
+ .shutdown = acp_probes_compr_shutdown,
+ .set_params = acp_probes_compr_set_params,
+ .trigger = acp_probes_compr_trigger,
+ .pointer = acp_probes_compr_pointer,
+};
+
+int acp_probes_register(struct snd_sof_dev *sdev)
+{
+ return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops,
+ sizeof(acp_probes_ops));
+}
+EXPORT_SYMBOL_NS(acp_probes_register, "SND_SOC_SOF_AMD_COMMON");
+
+void acp_probes_unregister(struct snd_sof_dev *sdev)
+{
+ sof_client_dev_unregister(sdev, "acp-probes", 0);
+}
+EXPORT_SYMBOL_NS(acp_probes_unregister, "SND_SOC_SOF_AMD_COMMON");
+
+MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT");
+
diff --git a/sound/soc/sof/amd/acp-stream.c b/sound/soc/sof/amd/acp-stream.c
index 6f40ef7ba85e..9212a3137cfd 100644
--- a/sound/soc/sof/amd/acp-stream.c
+++ b/sound/soc/sof/amd/acp-stream.c
@@ -150,7 +150,7 @@ struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag)
dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag);
return NULL;
}
-EXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_dsp_stream_get, "SND_SOC_SOF_AMD_COMMON");
int acp_dsp_stream_put(struct snd_sof_dev *sdev,
struct acp_dsp_stream *acp_stream)
@@ -170,7 +170,7 @@ int acp_dsp_stream_put(struct snd_sof_dev *sdev,
dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag);
return -EINVAL;
}
-EXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_dsp_stream_put, "SND_SOC_SOF_AMD_COMMON");
int acp_dsp_stream_init(struct snd_sof_dev *sdev)
{
@@ -184,4 +184,4 @@ int acp_dsp_stream_init(struct snd_sof_dev *sdev)
}
return 0;
}
-EXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_dsp_stream_init, "SND_SOC_SOF_AMD_COMMON");
diff --git a/sound/soc/sof/amd/acp-trace.c b/sound/soc/sof/amd/acp-trace.c
index c9482b27cbe3..0bd1f5990e8c 100644
--- a/sound/soc/sof/amd/acp-trace.c
+++ b/sound/soc/sof/amd/acp-trace.c
@@ -32,7 +32,7 @@ int acp_sof_trace_release(struct snd_sof_dev *sdev)
adata->dtrace_stream = NULL;
return 0;
}
-EXPORT_SYMBOL_NS(acp_sof_trace_release, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_trace_release, "SND_SOC_SOF_AMD_COMMON");
int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct sof_ipc_dma_trace_params_ext *dtrace_params)
@@ -61,4 +61,4 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
return 0;
}
-EXPORT_SYMBOL_NS(acp_sof_trace_init, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(acp_sof_trace_init, "SND_SOC_SOF_AMD_COMMON");
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 2ae76bcd3590..71a18f156de2 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc. All rights reserved.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
// Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
@@ -16,37 +16,59 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <asm/amd/node.h>
+
#include "../ops.h"
#include "acp.h"
#include "acp-dsp-offset.h"
-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 bool enable_fw_debug;
+module_param(enable_fw_debug, bool, 0444);
+MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
-static 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);
+static struct acp_quirk_entry quirk_valve_galileo = {
+ .signed_fw_image = true,
+ .skip_iram_dram_size_mod = true,
+ .post_fw_run_delay = true,
+};
- return 0;
-}
+const struct dmi_system_id acp_sof_quirk_table[] = {
+ {
+ /* Steam Deck OLED device */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ },
+ .driver_data = &quirk_valve_galileo,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(acp_sof_quirk_table);
static void init_dma_descriptor(struct acp_dev_data *adata)
{
struct snd_sof_dev *sdev = adata->dev;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
unsigned int addr;
+ unsigned int acp_dma_desc_base_addr, acp_dma_desc_max_num_dscr;
addr = desc->sram_pte_offset + sdev->debug_box.offset +
offsetof(struct scratch_reg_conf, dma_desc);
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_BASE_ADDR, addr);
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_MAX_NUM_DSCR, ACP_MAX_DESC_CNT);
+ switch (acp_data->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR;
+ acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR;
+ break;
+ default:
+ acp_dma_desc_base_addr = ACP_DMA_DESC_BASE_ADDR;
+ acp_dma_desc_max_num_dscr = ACP_DMA_DESC_MAX_NUM_DSCR;
+ }
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_desc_base_addr, addr);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_desc_max_num_dscr, ACP_MAX_DESC_CNT);
}
static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short idx,
@@ -68,28 +90,53 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch,
unsigned int idx, unsigned int dscr_count)
{
struct snd_sof_dev *sdev = adata->dev;
+ struct acp_dev_data *acp_data = sdev->pdata->hw_pdata;
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
unsigned int val, status;
+ unsigned int acp_dma_cntl_0, acp_dma_ch_rst_sts, acp_dma_dscr_err_sts_0;
+ unsigned int acp_dma_dscr_cnt_0, acp_dma_prio_0, acp_dma_dscr_strt_idx_0;
int ret;
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32),
+ switch (acp_data->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ acp_dma_cntl_0 = ACP70_DMA_CNTL_0;
+ acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS;
+ acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0;
+ acp_dma_dscr_cnt_0 = ACP70_DMA_DSCR_CNT_0;
+ acp_dma_prio_0 = ACP70_DMA_PRIO_0;
+ acp_dma_dscr_strt_idx_0 = ACP70_DMA_DSCR_STRT_IDX_0;
+ break;
+ default:
+ acp_dma_cntl_0 = ACP_DMA_CNTL_0;
+ acp_dma_ch_rst_sts = ACP_DMA_CH_RST_STS;
+ acp_dma_dscr_err_sts_0 = ACP_DMA_ERR_STS_0;
+ acp_dma_dscr_cnt_0 = ACP_DMA_DSCR_CNT_0;
+ acp_dma_prio_0 = ACP_DMA_PRIO_0;
+ acp_dma_dscr_strt_idx_0 = ACP_DMA_DSCR_STRT_IDX_0;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_cntl_0 + ch * sizeof(u32),
ACP_DMA_CH_RST | ACP_DMA_CH_GRACEFUL_RST_EN);
- ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_RST_STS, val,
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, acp_dma_ch_rst_sts, val,
val & (1 << ch), ACP_REG_POLL_INTERVAL,
ACP_REG_POLL_TIMEOUT_US);
if (ret < 0) {
- status = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_ERROR_STATUS);
- val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_ERR_STS_0 + ch * sizeof(u32));
+ status = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->acp_error_stat);
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, acp_dma_dscr_err_sts_0 +
+ ch * sizeof(u32));
dev_err(sdev->dev, "ACP_DMA_ERR_STS :0x%x ACP_ERROR_STATUS :0x%x\n", val, status);
return ret;
}
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, (ACP_DMA_CNTL_0 + ch * sizeof(u32)), 0);
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_CNT_0 + ch * sizeof(u32), dscr_count);
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DSCR_STRT_IDX_0 + ch * sizeof(u32), idx);
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_PRIO_0 + ch * sizeof(u32), 0);
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32), ACP_DMA_CH_RUN);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, (acp_dma_cntl_0 + ch * sizeof(u32)), 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_dscr_cnt_0 + ch * sizeof(u32), dscr_count);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_dscr_strt_idx_0 + ch * sizeof(u32), idx);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_prio_0 + ch * sizeof(u32), 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, acp_dma_cntl_0 + ch * sizeof(u32), ACP_DMA_CH_RUN);
return ret;
}
@@ -150,15 +197,13 @@ 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 timeout;
- u32 data;
+ int ret, data;
- for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
- msleep(20);
- smn_read(adata->smn_dev, MP0_C2PMSG_114_REG, &data);
- if (data & MBOX_READY_MASK)
- return 0;
- }
+ 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);
+
+ if (!ret)
+ return 0;
dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK);
@@ -177,23 +222,19 @@ static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
{
struct snd_sof_dev *sdev = adata->dev;
- int ret, timeout;
+ int ret;
u32 data;
if (!cmd)
return -EINVAL;
/* Get a non-zero Doorbell value from PSP */
- for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
- msleep(MBOX_DELAY);
- smn_read(adata->smn_dev, MP0_C2PMSG_73_REG, &data);
- if (data)
- break;
- }
+ ret = read_poll_timeout(smn_read_register, data, data > 0, MBOX_DELAY_US,
+ ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_73_REG);
- if (!timeout) {
+ if (ret) {
dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG);
- return -EINVAL;
+ return ret;
}
/* Check if PSP is ready for new command */
@@ -201,10 +242,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);
@@ -238,9 +283,24 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
}
}
+ if (adata->quirks && adata->quirks->signed_fw_image)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER);
+
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length);
+
+ /* psp_send_cmd only required for vangogh platform */
+ if (adata->pci_rev == ACP_VANGOGH_PCI_ID &&
+ !(adata->quirks && adata->quirks->skip_iram_dram_size_mod)) {
+ /* Modify IRAM and DRAM size */
+ ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | IRAM_DRAM_FENCE_2);
+ if (ret)
+ return ret;
+ ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | MBOX_ISREADY_FLAG);
+ if (ret)
+ return ret;
+ }
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_CMD, ACP_SHA_RUN);
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_TRANSFER_BYTE_CNT,
@@ -251,15 +311,20 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
return ret;
}
- ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND);
- if (ret)
- return ret;
+ /* psp_send_cmd only required for renoir platform*/
+ if (adata->pci_rev == ACP_RN_PCI_ID) {
+ ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND);
+ if (ret)
+ return ret;
+ }
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER,
fw_qualifier, fw_qualifier & DSP_FW_RUN_ENABLE,
ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US);
if (ret < 0) {
- dev_err(sdev->dev, "PSP validation failed\n");
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_PSP_ACK);
+ dev_err(sdev->dev, "PSP validation failed: fw_qualifier = %#x, ACP_SHA_PSP_ACK = %#x\n",
+ fw_qualifier, val);
return ret;
}
@@ -270,11 +335,21 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch)
{
struct snd_sof_dev *sdev = adata->dev;
unsigned int val;
+ unsigned int acp_dma_ch_sts;
int ret = 0;
+ switch (adata->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ acp_dma_ch_sts = ACP70_DMA_CH_STS;
+ break;
+ default:
+ acp_dma_ch_sts = ACP_DMA_CH_STS;
+ }
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32));
if (val & ACP_DMA_CH_RUN) {
- ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_STS, val, !val,
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, acp_dma_ch_sts, val, !val,
ACP_REG_POLL_INTERVAL,
ACP_DMA_COMPLETE_TIMEOUT_US);
if (ret < 0)
@@ -314,26 +389,84 @@ static int acp_memory_init(struct snd_sof_dev *sdev)
return 0;
}
+static void amd_sof_handle_acp70_sdw_wake_event(struct acp_dev_data *adata)
+{
+ struct amd_sdw_manager *amd_manager;
+
+ 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;
+ }
+
+ 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 amd_sof_check_and_handle_acp70_sdw_wake_irq(struct snd_sof_dev *sdev)
+{
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
+ u32 ext_intr_stat1;
+ int irq_flag = 0;
+ bool sdw_wake_irq = false;
+
+ ext_intr_stat1 = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
+ if (ext_intr_stat1 & ACP70_SDW0_HOST_WAKE_STAT) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
+ ACP70_SDW0_HOST_WAKE_STAT);
+ adata->acp70_sdw0_wake_event = true;
+ sdw_wake_irq = true;
+ }
+
+ if (ext_intr_stat1 & ACP70_SDW1_HOST_WAKE_STAT) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
+ ACP70_SDW1_HOST_WAKE_STAT);
+ adata->acp70_sdw1_wake_event = true;
+ sdw_wake_irq = true;
+ }
+
+ if (ext_intr_stat1 & ACP70_SDW0_PME_STAT) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_SW0_WAKE_EN, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, ACP70_SDW0_PME_STAT);
+ adata->acp70_sdw0_wake_event = true;
+ sdw_wake_irq = true;
+ }
+
+ if (ext_intr_stat1 & ACP70_SDW1_PME_STAT) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_SW1_WAKE_EN, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, ACP70_SDW1_PME_STAT);
+ adata->acp70_sdw1_wake_event = true;
+ sdw_wake_irq = true;
+ }
+
+ if (sdw_wake_irq) {
+ amd_sof_handle_acp70_sdw_wake_event(adata);
+ irq_flag = 1;
+ }
+ return irq_flag;
+}
+
static irqreturn_t acp_irq_thread(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
- unsigned int val, count = ACP_HW_SEM_RETRY_COUNT;
+ unsigned int count = ACP_HW_SEM_RETRY_COUNT;
- val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
- if (val & ACP_SHA_STAT) {
- /* Clear SHA interrupt raised by PSP */
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val);
- return IRQ_HANDLED;
- }
+ spin_lock_irq(&sdev->ipc_lock);
+ /* Wait until acquired HW Semaphore lock or timeout */
+ while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset) && --count)
+ ;
+ spin_unlock_irq(&sdev->ipc_lock);
- while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
- /* Wait until acquired HW Semaphore lock or timeout */
- count--;
- if (!count) {
- dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
- return IRQ_NONE;
- }
+ if (!count) {
+ dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
+ return IRQ_NONE;
}
sof_ops(sdev)->irq_thread(irq, sdev);
@@ -345,26 +478,71 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
static irqreturn_t acp_irq_handler(int irq, void *dev_id)
{
+ struct amd_sdw_manager *amd_manager;
struct snd_sof_dev *sdev = dev_id;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
unsigned int base = desc->dsp_intr_base;
unsigned int val;
+ int irq_flag = 0, wake_irq_flag = 0;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
- if (val) {
- val |= ACP_DSP_TO_HOST_IRQ;
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val);
+ if (val & ACP_DSP_TO_HOST_IRQ) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
+ ACP_DSP_TO_HOST_IRQ);
return IRQ_WAKE_THREAD;
}
- return IRQ_NONE;
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
+ if (val & ACP_SDW0_IRQ_MASK) {
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_SDW0_IRQ_MASK);
+ if (amd_manager)
+ schedule_work(&amd_manager->amd_sdw_irq_thread);
+ irq_flag = 1;
+ }
+
+ if (val & ACP_ERROR_IRQ_MASK) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0);
+ /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */
+ if (adata->pci_rev >= ACP_RMB_PCI_ID)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
+ irq_flag = 1;
+ }
+
+ if (desc->ext_intr_stat1) {
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
+ if (val & ACP_SDW1_IRQ_MASK) {
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
+ ACP_SDW1_IRQ_MASK);
+ if (amd_manager)
+ schedule_work(&amd_manager->amd_sdw_irq_thread);
+ irq_flag = 1;
+ }
+ switch (adata->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ wake_irq_flag = amd_sof_check_and_handle_acp70_sdw_wake_irq(sdev);
+ break;
+ }
+ }
+ if (irq_flag || wake_irq_flag)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
static int acp_power_on(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
unsigned int base = desc->pgfsm_base;
unsigned int val;
+ unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask;
int ret;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET);
@@ -372,9 +550,30 @@ static int acp_power_on(struct snd_sof_dev *sdev)
if (val == ACP_POWERED_ON)
return 0;
- if (val & ACP_PGFSM_STATUS_MASK)
+ switch (adata->pci_rev) {
+ case ACP_RN_PCI_ID:
+ case ACP_VANGOGH_PCI_ID:
+ acp_pgfsm_status_mask = ACP3X_PGFSM_STATUS_MASK;
+ acp_pgfsm_cntl_mask = ACP3X_PGFSM_CNTL_POWER_ON_MASK;
+ break;
+ case ACP_RMB_PCI_ID:
+ case ACP63_PCI_ID:
+ acp_pgfsm_status_mask = ACP6X_PGFSM_STATUS_MASK;
+ acp_pgfsm_cntl_mask = ACP6X_PGFSM_CNTL_POWER_ON_MASK;
+ break;
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK;
+ acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val & acp_pgfsm_status_mask)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET,
- ACP_PGFSM_CNTL_POWER_ON_MASK);
+ acp_pgfsm_cntl_mask);
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val,
!val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
@@ -386,7 +585,6 @@ static int acp_power_on(struct snd_sof_dev *sdev)
static int acp_reset(struct snd_sof_dev *sdev)
{
- const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
unsigned int val;
int ret;
@@ -407,15 +605,43 @@ static int acp_reset(struct snd_sof_dev *sdev)
if (ret < 0)
dev_err(sdev->dev, "timeout in releasing reset\n");
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
+ return ret;
+}
+
+static int acp_dsp_reset(struct snd_sof_dev *sdev)
+{
+ unsigned int val;
+ int ret;
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_DSP_ASSERT_RESET);
+
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val,
+ val & ACP_DSP_SOFT_RESET_DONE_MASK,
+ ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
+ if (ret < 0) {
+ dev_err(sdev->dev, "timeout asserting reset\n");
+ return ret;
+ }
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, ACP_DSP_RELEASE_RESET);
+
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SOFT_RESET, val, !val,
+ ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
+ if (ret < 0)
+ dev_err(sdev->dev, "timeout in releasing reset\n");
+
return ret;
}
static int acp_init(struct snd_sof_dev *sdev)
{
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ struct acp_dev_data *acp_data;
+ unsigned int sdw0_wake_en, sdw1_wake_en;
int ret;
/* power on */
+ acp_data = sdev->pdata->hw_pdata;
ret = acp_power_on(sdev);
if (ret) {
dev_err(sdev->dev, "ACP power on failed\n");
@@ -424,49 +650,192 @@ static int acp_init(struct snd_sof_dev *sdev)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01);
/* Reset */
- return acp_reset(sdev);
+ ret = acp_reset(sdev);
+ if (ret)
+ return ret;
+
+ if (desc->acp_clkmux_sel)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
+
+ if (desc->ext_intr_enb)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01);
+
+ if (desc->ext_intr_cntl)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_cntl, ACP_ERROR_IRQ_MASK);
+
+ switch (acp_data->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ sdw0_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP70_SW0_WAKE_EN);
+ sdw1_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP70_SW1_WAKE_EN);
+ if (sdw0_wake_en || sdw1_wake_en)
+ snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP70_EXTERNAL_INTR_CNTL1,
+ ACP70_SDW_HOST_WAKE_MASK, ACP70_SDW_HOST_WAKE_MASK);
+
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1);
+ break;
+ }
+ return 0;
+}
+
+static bool check_acp_sdw_enable_status(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+ u32 sdw0_en, sdw1_en;
+
+ acp_data = sdev->pdata->hw_pdata;
+ if (!acp_data->sdw)
+ return false;
+
+ sdw0_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW0_EN);
+ sdw1_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW1_EN);
+ acp_data->sdw_en_stat = sdw0_en || sdw1_en;
+ return acp_data->sdw_en_stat;
}
int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
+ struct acp_dev_data *acp_data;
int ret;
+ bool enable = false;
+
+ acp_data = sdev->pdata->hw_pdata;
+ /* When acp_reset() function is invoked, it will apply ACP SOFT reset and
+ * DSP reset. ACP Soft reset sequence will cause all ACP IP registers will
+ * be reset to default values which will break the ClockStop Mode functionality.
+ * Add a condition check to apply DSP reset when SoundWire ClockStop mode
+ * is selected. For the rest of the scenarios, apply acp reset sequence.
+ */
+ if (check_acp_sdw_enable_status(sdev))
+ return acp_dsp_reset(sdev);
ret = acp_reset(sdev);
if (ret) {
dev_err(sdev->dev, "ACP Reset failed\n");
return ret;
}
-
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00);
+ switch (acp_data->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ enable = true;
+ break;
+ }
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);
return 0;
}
-EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(amd_sof_acp_suspend, "SND_SOC_SOF_AMD_COMMON");
int amd_sof_acp_resume(struct snd_sof_dev *sdev)
{
- const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
int ret;
+ struct acp_dev_data *acp_data;
- ret = acp_init(sdev);
- if (ret) {
- dev_err(sdev->dev, "ACP Init failed\n");
- return ret;
+ acp_data = sdev->pdata->hw_pdata;
+ if (!acp_data->sdw_en_stat) {
+ ret = acp_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Init failed\n");
+ return ret;
+ }
+ return acp_memory_init(sdev);
+ }
+ switch (acp_data->pci_rev) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1);
+ break;
}
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
+ return acp_dsp_reset(sdev);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp_resume, "SND_SOC_SOF_AMD_COMMON");
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE)
+static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr)
+{
+ struct acpi_device *sdw_dev;
+ struct acp_dev_data *acp_data;
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+
+ if (!addr)
+ return -ENODEV;
+
+ acp_data = sdev->pdata->hw_pdata;
+ sdw_dev = acpi_find_child_device(ACPI_COMPANION(sdev->dev), addr, 0);
+ if (!sdw_dev)
+ return -ENODEV;
- ret = acp_memory_init(sdev);
+ acp_data->info.handle = sdw_dev->handle;
+ acp_data->info.count = desc->sdw_max_link_count;
+ return amd_sdw_scan_controller(&acp_data->info);
+}
+
+static int amd_sof_sdw_probe(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+ struct sdw_amd_res sdw_res;
+ int ret;
+
+ acp_data = sdev->pdata->hw_pdata;
+
+ memset(&sdw_res, 0, sizeof(sdw_res));
+ sdw_res.addr = acp_data->addr;
+ sdw_res.reg_range = acp_data->reg_range;
+ sdw_res.handle = acp_data->info.handle;
+ sdw_res.parent = sdev->dev;
+ sdw_res.dev = sdev->dev;
+ sdw_res.acp_lock = &acp_data->acp_lock;
+ sdw_res.count = acp_data->info.count;
+ sdw_res.link_mask = acp_data->info.link_mask;
+ sdw_res.mmio_base = sdev->bar[ACP_DSP_BAR];
+ sdw_res.acp_rev = acp_data->pci_rev;
+
+ ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
+ if (ret)
+ dev_err(sdev->dev, "SoundWire probe failed\n");
return ret;
}
-EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
+
+static int amd_sof_sdw_exit(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+
+ acp_data = sdev->pdata->hw_pdata;
+ if (acp_data->sdw)
+ sdw_amd_exit(acp_data->sdw);
+ acp_data->sdw = NULL;
+
+ return 0;
+}
+
+#else
+static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr)
+{
+ return 0;
+}
+
+static int amd_sof_sdw_probe(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+
+static int amd_sof_sdw_exit(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+#endif
int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct acp_dev_data *adata;
const struct sof_amd_acp_desc *chip;
+ const struct dmi_system_id *dmi_id;
unsigned int addr;
int ret;
@@ -496,14 +865,15 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
}
pci_set_master(pci);
-
+ adata->addr = addr;
+ adata->reg_range = chip->reg_end_addr - chip->reg_start_addr;
+ adata->pci_rev = pci->revision;
+ mutex_init(&adata->acp_lock);
sdev->pdata->hw_pdata = adata;
- 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;
+
+ ret = acp_init(sdev);
+ if (ret < 0)
goto unregister_dev;
- }
sdev->ipc_irq = pci->irq;
ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread,
@@ -511,13 +881,23 @@ 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;
}
- ret = acp_init(sdev);
- if (ret < 0)
- goto free_ipc_irq;
+ /* scan SoundWire capabilities exposed by DSDT */
+ ret = acp_sof_scan_sdw_devices(sdev, chip->sdw_acpi_dev_addr);
+ if (ret < 0) {
+ dev_dbg(sdev->dev, "skipping SoundWire, not detected with ACPI scan\n");
+ goto skip_soundwire;
+ }
+ ret = amd_sof_sdw_probe(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: SoundWire probe error\n");
+ free_irq(sdev->ipc_irq, sdev);
+ return ret;
+ }
+skip_soundwire:
sdev->dsp_box.offset = 0;
sdev->dsp_box.size = BOX_SIZE_512;
@@ -527,6 +907,30 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
sdev->debug_box.size = BOX_SIZE_1024;
+ dmi_id = dmi_first_match(acp_sof_quirk_table);
+ if (dmi_id) {
+ adata->quirks = dmi_id->driver_data;
+
+ if (adata->quirks->signed_fw_image) {
+ adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-code.bin",
+ chip->name);
+ if (!adata->fw_code_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+
+ adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-data.bin",
+ chip->name);
+ if (!adata->fw_data_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+ }
+ }
+
+ adata->enable_fw_debug = enable_fw_debug;
acp_memory_init(sdev);
acp_dsp_stream_init(sdev);
@@ -535,20 +939,18 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
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;
}
-EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(amd_sof_acp_probe, "SND_SOC_SOF_AMD_COMMON");
-int amd_sof_acp_remove(struct snd_sof_dev *sdev)
+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);
if (sdev->ipc_irq)
free_irq(sdev->ipc_irq, sdev);
@@ -556,9 +958,11 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev)
if (adata->dmic_dev)
platform_device_unregister(adata->dmic_dev);
- return acp_reset(sdev);
+ acp_reset(sdev);
}
-EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON");
-MODULE_DESCRIPTION("AMD ACP sof driver");
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("AMD ACP sof driver");
+MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
+MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI");
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index dc624f727aa3..2b7ea8c64106 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -3,7 +3,7 @@
* 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) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
*
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
*/
@@ -11,6 +11,8 @@
#ifndef __SOF_AMD_ACP_H
#define __SOF_AMD_ACP_H
+#include <linux/dmi.h>
+#include <linux/soundwire/sdw_amd.h>
#include "../sof-priv.h"
#include "../sof-audio.h"
@@ -23,16 +25,26 @@
#define ACP_REG_POLL_TIMEOUT_US 2000
#define ACP_DMA_COMPLETE_TIMEOUT_US 5000
-#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01
-#define ACP_PGFSM_STATUS_MASK 0x03
+#define ACP3X_PGFSM_CNTL_POWER_ON_MASK 0x01
+#define ACP3X_PGFSM_STATUS_MASK 0x03
+#define ACP6X_PGFSM_CNTL_POWER_ON_MASK 0x07
+#define ACP6X_PGFSM_STATUS_MASK 0x0F
+#define ACP70_PGFSM_CNTL_POWER_ON_MASK 0x1F
+#define ACP70_PGFSM_STATUS_MASK 0xFF
+
#define ACP_POWERED_ON 0x00
#define ACP_ASSERT_RESET 0x01
#define ACP_RELEASE_RESET 0x00
#define ACP_SOFT_RESET_DONE_MASK 0x00010001
+#define ACP_DSP_ASSERT_RESET 0x04
+#define ACP_DSP_RELEASE_RESET 0x00
+#define ACP_DSP_SOFT_RESET_DONE_MASK 0x00050004
#define ACP_DSP_INTR_EN_MASK 0x00000001
#define ACP3X_SRAM_PTE_OFFSET 0x02050000
+#define ACP5X_SRAM_PTE_OFFSET 0x02050000
#define ACP6X_SRAM_PTE_OFFSET 0x03800000
+#define ACP70_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET
#define PAGE_SIZE_4K_ENABLE 0x2
#define ACP_PAGE_SIZE 0x1000
#define ACP_DMA_CH_RUN 0x02
@@ -40,6 +52,7 @@
#define DSP_FW_RUN_ENABLE 0x01
#define ACP_SHA_RUN 0x01
#define ACP_SHA_RESET 0x02
+#define ACP_SHA_HEADER 0x01
#define ACP_DMA_CH_RST 0x01
#define ACP_DMA_CH_GRACEFUL_RST_EN 0x10
#define ACP_ATU_CACHE_INVALID 0x01
@@ -50,25 +63,39 @@
#define ACP3X_SCRATCH_MEMORY_ADDRESS 0x02050000
#define ACP_SYSTEM_MEMORY_WINDOW 0x4000000
#define ACP_IRAM_BASE_ADDRESS 0x000000
-#define ACP_DATA_RAM_BASE_ADDRESS 0x01000000
+#define ACP_DRAM_BASE_ADDRESS 0x01000000
#define ACP_DRAM_PAGE_COUNT 128
-
+#define ACP_SRAM_BASE_ADDRESS 0x3806000
+#define ACP7X_SRAM_BASE_ADDRESS 0x380C000
#define ACP_DSP_TO_HOST_IRQ 0x04
#define ACP_RN_PCI_ID 0x01
+#define ACP_VANGOGH_PCI_ID 0x50
#define ACP_RMB_PCI_ID 0x6F
+#define ACP63_PCI_ID 0x63
+#define ACP70_PCI_ID 0x70
+#define ACP71_PCI_ID 0x71
+#define ACP72_PCI_ID 0x72
#define HOST_BRIDGE_CZN 0x1630
+#define HOST_BRIDGE_VGH 0x1645
#define HOST_BRIDGE_RMB 0x14B5
+#define HOST_BRIDGE_ACP63 0x14E8
+#define HOST_BRIDGE_ACP70 0x1507
#define ACP_SHA_STAT 0x8000
-#define ACP_PSP_TIMEOUT_COUNTER 5
+#define ACP_PSP_TIMEOUT_US 1000000
#define ACP_EXT_INTR_ERROR_STAT 0x20000000
#define MP0_C2PMSG_114_REG 0x3810AC8
#define MP0_C2PMSG_73_REG 0x3810A24
#define MBOX_ACP_SHA_DMA_COMMAND 0x70000
-#define MBOX_DELAY 1000
+#define MBOX_ACP_IRAM_DRAM_FENCE_COMMAND 0x80000
+#define MBOX_DELAY_US 1000
#define MBOX_READY_MASK 0x80000000
#define MBOX_STATUS_MASK 0xFFFF
+#define MBOX_ISREADY_FLAG 0x40000000
+#define IRAM_DRAM_FENCE_0 0X0
+#define IRAM_DRAM_FENCE_1 0X01
+#define IRAM_DRAM_FENCE_2 0X02
#define BOX_SIZE_512 0x200
#define BOX_SIZE_1024 0x400
@@ -76,7 +103,19 @@
#define EXCEPT_MAX_HDR_SIZE 0x400
#define AMD_STACK_DUMP_SIZE 32
-#define SRAM1_SIZE 0x13A000
+#define SRAM1_SIZE 0x280000
+#define PROBE_STATUS_BIT BIT(31)
+
+#define ACP_FIRMWARE_SIGNATURE 0x100
+#define ACP_ERROR_IRQ_MASK BIT(29)
+#define ACP_SDW0_IRQ_MASK BIT(21)
+#define ACP_SDW1_IRQ_MASK BIT(2)
+#define SDW_ACPI_ADDR_ACP63 5
+#define SDW_ACPI_ADDR_ACP70 SDW_ACPI_ADDR_ACP63
+#define ACP_DEFAULT_SRAM_LENGTH 0x00080000
+#define ACP_SRAM_PAGE_COUNT 128
+#define ACP6X_SDW_MAX_MANAGER_COUNT 2
+#define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT
enum clock_source {
ACP_CLOCK_96M = 0,
@@ -156,36 +195,80 @@ struct acp_dsp_stream {
int active;
unsigned int reg_offset;
size_t posn_offset;
+ struct snd_compr_stream *cstream;
+ u64 cstream_posn;
};
struct sof_amd_acp_desc {
- unsigned int rev;
- unsigned int host_bridge_id;
+ const char *name;
u32 pgfsm_base;
+ u32 ext_intr_enb;
+ u32 ext_intr_cntl;
u32 ext_intr_stat;
+ u32 ext_intr_stat1;
u32 dsp_intr_base;
u32 sram_pte_offset;
u32 hw_semaphore_offset;
u32 acp_clkmux_sel;
u32 fusion_dsp_offset;
+ u32 probe_reg_offset;
+ u32 reg_start_addr;
+ u32 reg_end_addr;
+ u32 acp_error_stat;
+ u32 acp_sw0_i2s_err_reason;
+ u32 sdw_max_link_count;
+ u64 sdw_acpi_dev_addr;
+};
+
+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 */
struct acp_dev_data {
struct snd_sof_dev *dev;
+ const struct firmware *fw_dbin;
/* DMIC device */
struct platform_device *dmic_dev;
+ /* mutex lock to protect ACP common registers access */
+ struct mutex acp_lock;
+ /* ACPI information stored between scan and probe steps */
+ struct sdw_amd_acpi_info info;
+ /* sdw context allocated by SoundWire driver */
+ struct sdw_amd_ctx *sdw;
unsigned int fw_bin_size;
unsigned int fw_data_bin_size;
+ unsigned int fw_sram_data_bin_size;
+ const char *fw_code_bin;
+ const char *fw_data_bin;
+ const char *fw_sram_data_bin;
u32 fw_bin_page_count;
+ u32 fw_data_bin_page_count;
+ u32 addr;
+ u32 reg_range;
+ u32 blk_type;
dma_addr_t sha_dma_addr;
u8 *bin_buf;
dma_addr_t dma_addr;
u8 *data_buf;
+ dma_addr_t sram_dma_addr;
+ u8 *sram_data_buf;
+ struct acp_quirk_entry *quirks;
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;
+ bool is_sram_in_use;
+ bool sdw_en_stat;
+ /* acp70_sdw0_wake_event flag set to true when wake irq asserted for SW0 instance */
+ bool acp70_sdw0_wake_event;
+ /* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */
+ bool acp70_sdw1_wake_event;
+ unsigned int pci_rev;
};
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -200,11 +283,12 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
/* ACP device probe/remove */
int amd_sof_acp_probe(struct snd_sof_dev *sdev);
-int amd_sof_acp_remove(struct snd_sof_dev *sdev);
+void amd_sof_acp_remove(struct snd_sof_dev *sdev);
/* DSP Loader callbacks */
int acp_sof_dsp_run(struct snd_sof_dev *sdev);
int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev);
+int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev);
int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type);
/* Block IO callbacks */
@@ -244,12 +328,19 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr
snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream);
-extern struct snd_sof_dsp_ops sof_acp_common_ops;
+extern const struct snd_sof_dsp_ops sof_acp_common_ops;
extern struct snd_sof_dsp_ops sof_renoir_ops;
int sof_renoir_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_vangogh_ops;
+int sof_vangogh_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_rembrandt_ops;
int sof_rembrandt_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_acp63_ops;
+int sof_acp63_ops_init(struct snd_sof_dev *sdev);
+
+extern struct snd_sof_dsp_ops sof_acp70_ops;
+int sof_acp70_ops_init(struct snd_sof_dev *sdev);
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev);
/* Machine configuration */
@@ -273,4 +364,10 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata
return desc->chip_info;
}
+
+int acp_probes_register(struct snd_sof_dev *sdev);
+void acp_probes_unregister(struct snd_sof_dev *sdev);
+
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[];
+extern const struct dmi_system_id acp_sof_quirk_table[];
#endif
diff --git a/sound/soc/sof/amd/acp63.c b/sound/soc/sof/amd/acp63.c
new file mode 100644
index 000000000000..a686620b1358
--- /dev/null
+++ b/sound/soc/sof/amd/acp63.c
@@ -0,0 +1,142 @@
+// 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) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on ACP6.3 version based platform
+ */
+
+#include <linux/platform_device.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
+#define I2S_SP_INSTANCE 2
+#define PDM_DMIC_INSTANCE 3
+#define I2S_HS_VIRTUAL_INSTANCE 4
+
+static struct snd_soc_dai_driver acp63_sof_dai[] = {
+ [I2S_HS_INSTANCE] = {
+ .id = I2S_HS_INSTANCE,
+ .name = "acp-sof-hs",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_BT_INSTANCE] = {
+ .id = I2S_BT_INSTANCE,
+ .name = "acp-sof-bt",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S BT controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_SP_INSTANCE] = {
+ .id = I2S_SP_INSTANCE,
+ .name = "acp-sof-sp",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S SP controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM_DMIC_INSTANCE] = {
+ .id = PDM_DMIC_INSTANCE,
+ .name = "acp-sof-dmic",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_HS_VIRTUAL_INSTANCE] = {
+ .id = I2S_HS_VIRTUAL_INSTANCE,
+ .name = "acp-sof-hs-virtual",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ },
+};
+
+/* Phoenix ops */
+struct snd_sof_dsp_ops sof_acp63_ops;
+EXPORT_SYMBOL_NS(sof_acp63_ops, "SND_SOC_SOF_AMD_COMMON");
+
+int sof_acp63_ops_init(struct snd_sof_dev *sdev)
+{
+ /* common defaults */
+ memcpy(&sof_acp63_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ sof_acp63_ops.drv = acp63_sof_dai;
+ sof_acp63_ops.num_drv = ARRAY_SIZE(acp63_sof_dai);
+
+ return 0;
+}
diff --git a/sound/soc/sof/amd/acp70.c b/sound/soc/sof/amd/acp70.c
new file mode 100644
index 000000000000..8314ac4008da
--- /dev/null
+++ b/sound/soc/sof/amd/acp70.c
@@ -0,0 +1,142 @@
+// 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) 2024 Advanced Micro Devices, Inc.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on ACP7.0 version based platform
+ */
+
+#include <linux/platform_device.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
+#define I2S_SP_INSTANCE 2
+#define PDM_DMIC_INSTANCE 3
+#define I2S_HS_VIRTUAL_INSTANCE 4
+
+static struct snd_soc_dai_driver acp70_sof_dai[] = {
+ [I2S_HS_INSTANCE] = {
+ .id = I2S_HS_INSTANCE,
+ .name = "acp-sof-hs",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_BT_INSTANCE] = {
+ .id = I2S_BT_INSTANCE,
+ .name = "acp-sof-bt",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S BT controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_SP_INSTANCE] = {
+ .id = I2S_SP_INSTANCE,
+ .name = "acp-sof-sp",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S SP controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM_DMIC_INSTANCE] = {
+ .id = PDM_DMIC_INSTANCE,
+ .name = "acp-sof-dmic",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_HS_VIRTUAL_INSTANCE] = {
+ .id = I2S_HS_VIRTUAL_INSTANCE,
+ .name = "acp-sof-hs-virtual",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ },
+};
+
+/* Phoenix ops */
+struct snd_sof_dsp_ops sof_acp70_ops;
+EXPORT_SYMBOL_NS(sof_acp70_ops, "SND_SOC_SOF_AMD_COMMON");
+
+int sof_acp70_ops_init(struct snd_sof_dev *sdev)
+{
+ /* common defaults */
+ memcpy(&sof_acp70_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ sof_acp70_ops.drv = acp70_sof_dai;
+ sof_acp70_ops.num_drv = ARRAY_SIZE(acp70_sof_dai);
+
+ return 0;
+}
diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c
new file mode 100644
index 000000000000..21ffdfdcf03d
--- /dev/null
+++ b/sound/soc/sof/amd/pci-acp63.c
@@ -0,0 +1,115 @@
+// 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) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*.
+ * PCI interface for ACP6.3 device
+ */
+
+#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"
+#include "acp-dsp-offset.h"
+
+#define ACP6X_FUTURE_REG_ACLK_0 0x1854
+#define ACP6x_REG_START 0x1240000
+#define ACP6x_REG_END 0x125C000
+
+static const struct sof_amd_acp_desc acp63_chip_info = {
+ .pgfsm_base = ACP6X_PGFSM_BASE,
+ .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB,
+ .ext_intr_cntl = ACP6X_EXTERNAL_INTR_CNTL,
+ .ext_intr_stat = ACP6X_EXT_INTR_STAT,
+ .ext_intr_stat1 = ACP6X_EXT_INTR_STAT1,
+ .acp_error_stat = ACP6X_ERROR_STATUS,
+ .acp_sw0_i2s_err_reason = ACP6X_SW0_I2S_ERROR_REASON,
+ .dsp_intr_base = ACP6X_DSP_SW_INTR_BASE,
+ .sram_pte_offset = ACP6X_SRAM_PTE_OFFSET,
+ .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
+ .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
+ .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0,
+ .sdw_max_link_count = ACP6X_SDW_MAX_MANAGER_COUNT,
+ .sdw_acpi_dev_addr = SDW_ACPI_ADDR_ACP63,
+ .reg_start_addr = ACP6x_REG_START,
+ .reg_end_addr = ACP6x_REG_END,
+};
+
+static const struct sof_dev_desc acp63_desc = {
+ .machines = snd_soc_acpi_amd_acp63_sof_machines,
+ .alt_machines = snd_soc_acpi_amd_acp63_sof_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &acp63_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_3] = "sof-acp_6_3.ri",
+ },
+ .nocodec_tplg_filename = "sof-acp.tplg",
+ .ops = &sof_acp63_ops,
+ .ops_init = sof_acp63_ops_init,
+};
+
+static int acp63_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ unsigned int flag;
+
+ if (pci->revision != ACP63_PCI_ID)
+ return -ENODEV;
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+ return -ENODEV;
+
+ return sof_pci_probe(pci, pci_id);
+};
+
+static void acp63_pci_remove(struct pci_dev *pci)
+{
+ sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id acp63_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+ .driver_data = (unsigned long)&acp63_desc},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, acp63_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_acp63_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = acp63_pci_ids,
+ .probe = acp63_pci_probe,
+ .remove = acp63_pci_remove,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_amd_acp63_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("ACP63 SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c
new file mode 100644
index 000000000000..3523c9a92a94
--- /dev/null
+++ b/sound/soc/sof/amd/pci-acp70.c
@@ -0,0 +1,121 @@
+// 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) 2024 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*.
+ * PCI interface for ACP7.0 device
+ */
+
+#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"
+#include "acp-dsp-offset.h"
+
+#define ACP70_FUTURE_REG_ACLK_0 0x1854
+#define ACP70_REG_START 0x1240000
+#define ACP70_REG_END 0x125C000
+
+static const struct sof_amd_acp_desc acp70_chip_info = {
+ .pgfsm_base = ACP70_PGFSM_BASE,
+ .ext_intr_enb = ACP70_EXTERNAL_INTR_ENB,
+ .ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL,
+ .ext_intr_stat = ACP70_EXT_INTR_STAT,
+ .ext_intr_stat1 = ACP70_EXT_INTR_STAT1,
+ .acp_error_stat = ACP70_ERROR_STATUS,
+ .dsp_intr_base = ACP70_DSP_SW_INTR_BASE,
+ .acp_sw0_i2s_err_reason = ACP7X_SW0_I2S_ERROR_REASON,
+ .sram_pte_offset = ACP70_SRAM_PTE_OFFSET,
+ .hw_semaphore_offset = ACP70_AXI2DAGB_SEM_0,
+ .fusion_dsp_offset = ACP70_DSP_FUSION_RUNSTALL,
+ .probe_reg_offset = ACP70_FUTURE_REG_ACLK_0,
+ .sdw_max_link_count = ACP70_SDW_MAX_MANAGER_COUNT,
+ .sdw_acpi_dev_addr = SDW_ACPI_ADDR_ACP70,
+ .reg_start_addr = ACP70_REG_START,
+ .reg_end_addr = ACP70_REG_END,
+};
+
+static const struct sof_dev_desc acp70_desc = {
+ .machines = snd_soc_acpi_amd_acp70_sof_machines,
+ .alt_machines = snd_soc_acpi_amd_acp70_sof_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &acp70_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_3] = "sof-acp_7_0.ri",
+ },
+ .nocodec_tplg_filename = "sof-acp.tplg",
+ .ops = &sof_acp70_ops,
+ .ops_init = sof_acp70_ops_init,
+};
+
+static int acp70_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ unsigned int flag;
+
+ switch (pci->revision) {
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+ return -ENODEV;
+
+ return sof_pci_probe(pci, pci_id);
+};
+
+static void acp70_pci_remove(struct pci_dev *pci)
+{
+ sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id acp70_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+ .driver_data = (unsigned long)&acp70_desc},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, acp70_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_acp70_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = acp70_pci_ids,
+ .probe = acp70_pci_probe,
+ .remove = acp70_pci_remove,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_amd_acp70_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("ACP70 SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c
index 58b3092425f1..0233b6ba2d2e 100644
--- a/sound/soc/sof/amd/pci-rmb.c
+++ b/sound/soc/sof/amd/pci-rmb.c
@@ -25,17 +25,18 @@
#define ACP6x_REG_START 0x1240000
#define ACP6x_REG_END 0x125C000
+#define ACP6X_FUTURE_REG_ACLK_0 0x1854
static const struct sof_amd_acp_desc rembrandt_chip_info = {
- .rev = 6,
- .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,
+ .acp_error_stat = ACP6X_ERROR_STATUS,
+ .acp_sw0_i2s_err_reason = ACP6X_SW0_I2S_ERROR_REASON,
.sram_pte_offset = ACP6X_SRAM_PTE_OFFSET,
.hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
- .acp_clkmux_sel = ACP6X_CLKMUX_SEL,
.fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
+ .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0,
};
static const struct sof_dev_desc rembrandt_desc = {
@@ -45,16 +46,16 @@ static const struct sof_dev_desc rembrandt_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &rembrandt_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "amd/sof",
+ [SOF_IPC_TYPE_3] = "amd/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "amd/sof-tplg",
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-rmb.ri",
+ [SOF_IPC_TYPE_3] = "sof-rmb.ri",
},
.nocodec_tplg_filename = "sof-acp.tplg",
.ops = &sof_rembrandt_ops,
@@ -98,5 +99,6 @@ static struct pci_driver snd_sof_pci_amd_rmb_driver = {
module_pci_driver(snd_sof_pci_amd_rmb_driver);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("REMBRANDT SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c
index 7409e21ce5aa..2b7fbcf11b55 100644
--- a/sound/soc/sof/amd/pci-rn.c
+++ b/sound/soc/sof/amd/pci-rn.c
@@ -25,16 +25,18 @@
#define ACP3x_REG_START 0x1240000
#define ACP3x_REG_END 0x125C000
+#define ACP3X_FUTURE_REG_ACLK_0 0x1860
static const struct sof_amd_acp_desc renoir_chip_info = {
- .rev = 3,
- .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,
+ .acp_error_stat = ACP3X_ERROR_STATUS,
+ .acp_sw0_i2s_err_reason = ACP3X_SW_I2S_ERROR_REASON,
.sram_pte_offset = ACP3X_SRAM_PTE_OFFSET,
.hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0,
.acp_clkmux_sel = ACP3X_CLKMUX_SEL,
+ .probe_reg_offset = ACP3X_FUTURE_REG_ACLK_0,
};
static const struct sof_dev_desc renoir_desc = {
@@ -45,16 +47,16 @@ static const struct sof_dev_desc renoir_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &renoir_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "amd/sof",
+ [SOF_IPC_TYPE_3] = "amd/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "amd/sof-tplg",
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-rn.ri",
+ [SOF_IPC_TYPE_3] = "sof-rn.ri",
},
.nocodec_tplg_filename = "sof-acp.tplg",
.ops = &sof_renoir_ops,
@@ -95,11 +97,12 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("RENOIR SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c
new file mode 100644
index 000000000000..6ef692becfb9
--- /dev/null
+++ b/sound/soc/sof/amd/pci-vangogh.c
@@ -0,0 +1,101 @@
+// 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) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com>
+
+/*.
+ * PCI interface for Vangogh ACP device
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/sof.h>
+#include <sound/soc-acpi.h>
+
+#include "../sof-pci-dev.h"
+#include "../../amd/mach-config.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define ACP5X_FUTURE_REG_ACLK_0 0x1864
+
+static const struct sof_amd_acp_desc vangogh_chip_info = {
+ .name = "vangogh",
+ .pgfsm_base = ACP5X_PGFSM_BASE,
+ .ext_intr_stat = ACP5X_EXT_INTR_STAT,
+ .dsp_intr_base = ACP5X_DSP_SW_INTR_BASE,
+ .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET,
+ .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0,
+ .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0,
+};
+
+static const struct sof_dev_desc vangogh_desc = {
+ .machines = snd_soc_acpi_amd_vangogh_sof_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &vangogh_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_3] = "sof-vangogh.ri",
+ },
+ .nocodec_tplg_filename = "sof-acp.tplg",
+ .ops = &sof_vangogh_ops,
+ .ops_init = sof_vangogh_ops_init,
+};
+
+static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ unsigned int flag;
+
+ if (pci->revision != ACP_VANGOGH_PCI_ID)
+ return -ENODEV;
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+ return -ENODEV;
+
+ return sof_pci_probe(pci, pci_id);
+};
+
+static void acp_pci_vgh_remove(struct pci_dev *pci)
+{
+ sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id vgh_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+ .driver_data = (unsigned long)&vangogh_desc},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, vgh_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_vgh_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = vgh_pci_ids,
+ .probe = acp_pci_vgh_probe,
+ .remove = acp_pci_vgh_remove,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_amd_vgh_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("VANGOGH SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c
index f1d1ba57ab3a..86ef59743fc8 100644
--- a/sound/soc/sof/amd/rembrandt.c
+++ b/sound/soc/sof/amd/rembrandt.c
@@ -128,7 +128,7 @@ static struct snd_soc_dai_driver rembrandt_sof_dai[] = {
/* Rembrandt ops */
struct snd_sof_dsp_ops sof_rembrandt_ops;
-EXPORT_SYMBOL_NS(sof_rembrandt_ops, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(sof_rembrandt_ops, "SND_SOC_SOF_AMD_COMMON");
int sof_rembrandt_ops_init(struct snd_sof_dev *sdev)
{
@@ -140,7 +140,3 @@ int sof_rembrandt_ops_init(struct snd_sof_dev *sdev)
return 0;
}
-
-MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
-MODULE_DESCRIPTION("REMBRANDT SOF Driver");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c
index 47b863f6258c..b3b4639abf50 100644
--- a/sound/soc/sof/amd/renoir.c
+++ b/sound/soc/sof/amd/renoir.c
@@ -103,7 +103,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = {
/* Renoir ops */
struct snd_sof_dsp_ops sof_renoir_ops;
-EXPORT_SYMBOL_NS(sof_renoir_ops, SND_SOC_SOF_AMD_COMMON);
+EXPORT_SYMBOL_NS(sof_renoir_ops, "SND_SOC_SOF_AMD_COMMON");
int sof_renoir_ops_init(struct snd_sof_dev *sdev)
{
@@ -115,7 +115,3 @@ int sof_renoir_ops_init(struct snd_sof_dev *sdev)
return 0;
}
-
-MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
-MODULE_DESCRIPTION("RENOIR SOF Driver");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c
new file mode 100644
index 000000000000..6ed5f9aaa414
--- /dev/null
+++ b/sound/soc/sof/amd/vangogh.c
@@ -0,0 +1,177 @@
+// 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) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on Vangogh platform
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include "acp.h"
+
+#define I2S_HS_INSTANCE 0
+#define I2S_BT_INSTANCE 1
+#define I2S_SP_INSTANCE 2
+#define PDM_DMIC_INSTANCE 3
+#define I2S_HS_VIRTUAL_INSTANCE 4
+
+static struct snd_soc_dai_driver vangogh_sof_dai[] = {
+ [I2S_HS_INSTANCE] = {
+ .id = I2S_HS_INSTANCE,
+ .name = "acp-sof-hs",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_BT_INSTANCE] = {
+ .id = I2S_BT_INSTANCE,
+ .name = "acp-sof-bt",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S BT controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_SP_INSTANCE] = {
+ .id = I2S_SP_INSTANCE,
+ .name = "acp-sof-sp",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S SP controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM_DMIC_INSTANCE] = {
+ .id = PDM_DMIC_INSTANCE,
+ .name = "acp-sof-dmic",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_HS_VIRTUAL_INSTANCE] = {
+ .id = I2S_HS_VIRTUAL_INSTANCE,
+ .name = "acp-sof-hs-virtual",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS-Virtual controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+};
+
+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");
+
+int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
+{
+ const struct dmi_system_id *dmi_id;
+ struct acp_quirk_entry *quirks;
+
+ /* common defaults */
+ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ sof_vangogh_ops.drv = vangogh_sof_dai;
+ sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai);
+
+ dmi_id = dmi_first_match(acp_sof_quirk_table);
+ if (dmi_id) {
+ quirks = dmi_id->driver_data;
+
+ 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/compress.c b/sound/soc/sof/compress.c
index d7b044f33d79..90b932ae3bab 100644
--- a/sound/soc/sof/compress.c
+++ b/sound/soc/sof/compress.c
@@ -361,7 +361,7 @@ static int sof_compr_copy(struct snd_soc_component *component,
static int sof_compr_pointer(struct snd_soc_component *component,
struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp)
+ struct snd_compr_tstamp64 *tstamp)
{
struct snd_sof_pcm *spcm;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index 75e13f4fd1eb..a3fd1d523c09 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -196,7 +196,6 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get)
ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
- pm_runtime_mark_last_busy(scomp->dev);
err = pm_runtime_put_autosuspend(scomp->dev);
if (err < 0)
dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err);
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 9a9d82220fd0..b11f408f1366 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -13,16 +13,53 @@
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
+#include "sof-of-dev.h"
#include "ops.h"
#define CREATE_TRACE_POINTS
#include <trace/events/sof.h>
+/* Module parameters for firmware, topology and IPC type override */
+static char *override_fw_path;
+module_param_named(fw_path, override_fw_path, charp, 0444);
+MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
+
+static char *override_fw_filename;
+module_param_named(fw_filename, override_fw_filename, charp, 0444);
+MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware.");
+
+static char *override_lib_path;
+module_param_named(lib_path, override_lib_path, charp, 0444);
+MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries.");
+
+static char *override_tplg_path;
+module_param_named(tplg_path, override_tplg_path, charp, 0444);
+MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
+
+static char *override_tplg_filename;
+module_param_named(tplg_filename, override_tplg_filename, charp, 0444);
+MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology.");
+
+static int override_ipc_type = -1;
+module_param_named(ipc_type, override_ipc_type, int, 0444);
+MODULE_PARM_DESC(ipc_type, "Force SOF IPC type. 0 - IPC3, 1 - IPC4");
+
/* see SOF_DBG_ flags */
static int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE);
module_param_named(sof_debug, sof_core_debug, int, 0444);
MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)");
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
+static unsigned int sof_ipc_timeout_ms;
+static unsigned int sof_boot_timeout_ms;
+module_param_named(ipc_timeout, sof_ipc_timeout_ms, uint, 0444);
+MODULE_PARM_DESC(ipc_timeout,
+ "Set the IPC timeout value in ms (0 to use the platform default)");
+module_param_named(boot_timeout, sof_boot_timeout_ms, uint, 0444);
+MODULE_PARM_DESC(boot_timeout,
+ "Set the DSP boot timeout value in ms (0 to use the platform default)");
+#endif
+
/* SOF defaults if not provided by the platform in ms */
#define TIMEOUT_DEFAULT_IPC_MS 500
#define TIMEOUT_DEFAULT_BOOT_MS 2000
@@ -143,6 +180,237 @@ void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state)
}
EXPORT_SYMBOL(sof_set_fw_state);
+static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_sof_of_mach *mach = desc->of_machines;
+
+ if (!mach)
+ return NULL;
+
+ for (; mach->compatible; mach++) {
+ if (of_machine_is_compatible(mach->compatible)) {
+ sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ if (mach->fw_filename)
+ sof_pdata->fw_filename = mach->fw_filename;
+
+ return mach;
+ }
+ }
+
+ return NULL;
+}
+
+/* SOF Driver enumeration */
+static int sof_machine_check(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_soc_acpi_mach *mach;
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
+ const struct snd_sof_of_mach *of_mach;
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ goto nocodec;
+
+ /* find machine */
+ mach = snd_sof_machine_select(sdev);
+ if (mach) {
+ sof_pdata->machine = mach;
+
+ if (sof_pdata->subsystem_id_set) {
+ mach->mach_params.subsystem_vendor = sof_pdata->subsystem_vendor;
+ mach->mach_params.subsystem_device = sof_pdata->subsystem_device;
+ mach->mach_params.subsystem_id_set = true;
+ }
+
+ snd_sof_set_mach_params(mach, sdev);
+ return 0;
+ }
+
+ of_mach = sof_of_machine_select(sdev);
+ if (of_mach) {
+ sof_pdata->of_machine = of_mach;
+ return 0;
+ }
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
+ dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
+ return -ENODEV;
+ }
+ } else {
+ dev_warn(sdev->dev, "Force to use nocodec mode\n");
+ }
+
+nocodec:
+ /* select nocodec mode */
+ dev_warn(sdev->dev, "Using nocodec machine driver\n");
+ mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
+ if (!mach)
+ return -ENOMEM;
+
+ mach->drv_name = "sof-nocodec";
+ if (!sof_pdata->tplg_filename)
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+
+ sof_pdata->machine = mach;
+ snd_sof_set_mach_params(mach, sdev);
+
+ return 0;
+}
+
+static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
+ struct sof_loadable_file_profile out_profile;
+ struct device *dev = sdev->dev;
+ int ret;
+
+ if (base_profile->ipc_type != plat_data->desc->ipc_default)
+ dev_info(dev,
+ "Module parameter used, overriding default IPC %d to %d\n",
+ plat_data->desc->ipc_default, base_profile->ipc_type);
+
+ if (base_profile->fw_path)
+ dev_dbg(dev, "Module parameter used, changed fw path to %s\n",
+ base_profile->fw_path);
+ else if (base_profile->fw_path_postfix)
+ dev_dbg(dev, "Path postfix appended to default fw path: %s\n",
+ base_profile->fw_path_postfix);
+
+ if (base_profile->fw_lib_path)
+ dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
+ base_profile->fw_lib_path);
+ else if (base_profile->fw_lib_path_postfix)
+ dev_dbg(dev, "Path postfix appended to default fw_lib path: %s\n",
+ base_profile->fw_lib_path_postfix);
+
+ if (base_profile->fw_name)
+ dev_dbg(dev, "Module parameter used, changed fw filename to %s\n",
+ base_profile->fw_name);
+
+ if (base_profile->tplg_path)
+ dev_dbg(dev, "Module parameter used, changed tplg path to %s\n",
+ base_profile->tplg_path);
+
+ if (base_profile->tplg_name)
+ dev_dbg(dev, "Module parameter used, changed tplg name to %s\n",
+ base_profile->tplg_name);
+
+ ret = sof_create_ipc_file_profile(sdev, base_profile, &out_profile);
+ if (ret)
+ return ret;
+
+ plat_data->ipc_type = out_profile.ipc_type;
+ plat_data->fw_filename = out_profile.fw_name;
+ plat_data->fw_filename_prefix = out_profile.fw_path;
+ plat_data->fw_lib_prefix = out_profile.fw_lib_path;
+ plat_data->tplg_filename_prefix = out_profile.tplg_path;
+
+ return 0;
+}
+
+static int validate_sof_ops(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ /* init ops, if necessary */
+ ret = sof_ops_init(sdev);
+ if (ret < 0)
+ return ret;
+
+ /* check all mandatory ops */
+ if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
+ dev_err(sdev->dev, "missing mandatory ops\n");
+ sof_ops_free(sdev);
+ return -EINVAL;
+ }
+
+ if (!sdev->dspless_mode_selected &&
+ (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read ||
+ !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg ||
+ !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) {
+ dev_err(sdev->dev, "missing mandatory DSP ops\n");
+ sof_ops_free(sdev);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sof_init_sof_ops(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
+
+ /* check IPC support */
+ if (!(BIT(base_profile->ipc_type) & plat_data->desc->ipc_supported_mask)) {
+ dev_err(sdev->dev,
+ "ipc_type %d is not supported on this platform, mask is %#x\n",
+ base_profile->ipc_type, plat_data->desc->ipc_supported_mask);
+ return -EINVAL;
+ }
+
+ /*
+ * Save the selected IPC type and a topology name override before
+ * selecting ops since platform code might need this information
+ */
+ plat_data->ipc_type = base_profile->ipc_type;
+ plat_data->tplg_filename = base_profile->tplg_name;
+
+ return validate_sof_ops(sdev);
+}
+
+static int sof_init_environment(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
+ int ret;
+
+ /* probe the DSP hardware */
+ ret = snd_sof_probe(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to probe DSP %d\n", ret);
+ goto err_sof_probe;
+ }
+
+ /* check machine info */
+ ret = sof_machine_check(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to get machine info %d\n", ret);
+ goto err_machine_check;
+ }
+
+ ret = sof_select_ipc_and_paths(sdev);
+ if (ret) {
+ goto err_machine_check;
+ } else if (plat_data->ipc_type != base_profile->ipc_type) {
+ /* IPC type changed, re-initialize the ops */
+ sof_ops_free(sdev);
+
+ ret = validate_sof_ops(sdev);
+ if (ret < 0) {
+ snd_sof_remove(sdev);
+ snd_sof_remove_late(sdev);
+ return ret;
+ }
+ }
+
+ return 0;
+
+err_machine_check:
+ snd_sof_remove(sdev);
+err_sof_probe:
+ snd_sof_remove_late(sdev);
+ sof_ops_free(sdev);
+
+ return ret;
+}
+
/*
* FW Boot State Transition Diagram
*
@@ -188,23 +456,13 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
struct snd_sof_pdata *plat_data = sdev->pdata;
int ret;
- /* probe the DSP hardware */
- ret = snd_sof_probe(sdev);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
- goto probe_err;
- }
+ /* Initialize loadable file paths and check the environment validity */
+ ret = sof_init_environment(sdev);
+ if (ret)
+ return ret;
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
- /* check machine info */
- ret = sof_machine_check(sdev);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to get machine info %d\n",
- ret);
- goto dsp_err;
- }
-
/* set up platform component driver */
snd_sof_new_platform_drv(sdev);
@@ -324,9 +582,8 @@ fw_load_err:
ipc_err:
dbg_err:
snd_sof_free_debug(sdev);
-dsp_err:
snd_sof_remove(sdev);
-probe_err:
+ snd_sof_remove_late(sdev);
sof_ops_free(sdev);
/* all resources freed, update state to match */
@@ -349,6 +606,27 @@ static void sof_probe_work(struct work_struct *work)
}
}
+static void
+sof_apply_profile_override(struct sof_loadable_file_profile *path_override,
+ struct snd_sof_pdata *plat_data)
+{
+ if (override_ipc_type >= 0 && override_ipc_type < SOF_IPC_TYPE_COUNT)
+ path_override->ipc_type = override_ipc_type;
+ if (override_fw_path)
+ path_override->fw_path = override_fw_path;
+ if (override_fw_filename)
+ path_override->fw_name = override_fw_filename;
+ if (override_lib_path)
+ path_override->fw_lib_path = override_lib_path;
+ if (override_tplg_path)
+ path_override->tplg_path = override_tplg_path;
+ if (override_tplg_filename) {
+ path_override->tplg_name = override_tplg_filename;
+ /* User requested a specific topology file and expect it to be loaded */
+ plat_data->disable_function_topology = true;
+ }
+}
+
int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
{
struct snd_sof_dev *sdev;
@@ -380,34 +658,13 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
}
}
- /* check IPC support */
- if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) {
- dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n",
- plat_data->ipc_type, plat_data->desc->ipc_supported_mask);
- return -EINVAL;
- }
+ sof_apply_profile_override(&plat_data->ipc_file_profile_base, plat_data);
- /* init ops, if necessary */
- ret = sof_ops_init(sdev);
- if (ret < 0)
+ /* Initialize sof_ops based on the initial selected IPC version */
+ ret = sof_init_sof_ops(sdev);
+ if (ret)
return ret;
- /* check all mandatory ops */
- if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
- sof_ops_free(sdev);
- dev_err(dev, "missing mandatory ops\n");
- return -EINVAL;
- }
-
- if (!sdev->dspless_mode_selected &&
- (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read ||
- !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg ||
- !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) {
- sof_ops_free(sdev);
- dev_err(dev, "missing mandatory DSP ops\n");
- return -EINVAL;
- }
-
INIT_LIST_HEAD(&sdev->pcm_list);
INIT_LIST_HEAD(&sdev->kcontrol_list);
INIT_LIST_HEAD(&sdev->widget_list);
@@ -434,8 +691,25 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
else
sdev->boot_timeout = plat_data->desc->boot_timeout;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
+ /* Override the timeout values with module parameter, if set */
+ if (sof_ipc_timeout_ms)
+ sdev->ipc_timeout = sof_ipc_timeout_ms;
+
+ if (sof_boot_timeout_ms)
+ sdev->boot_timeout = sof_boot_timeout_ms;
+#endif
+
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
+ /*
+ * first pass of probe which isn't allowed to run in a work-queue,
+ * typically to rely on -EPROBE_DEFER dependencies
+ */
+ ret = snd_sof_probe_early(sdev);
+ if (ret < 0)
+ return ret;
+
if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
INIT_WORK(&sdev->probe_work, sof_probe_work);
schedule_work(&sdev->probe_work);
@@ -459,9 +733,10 @@ int snd_sof_device_remove(struct device *dev)
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_pdata *pdata = sdev->pdata;
int ret;
+ bool aborted = false;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
- cancel_work_sync(&sdev->probe_work);
+ aborted = cancel_work_sync(&sdev->probe_work);
/*
* Unregister any registered client device first before IPC and debugfs
@@ -476,6 +751,16 @@ int snd_sof_device_remove(struct device *dev)
*/
snd_sof_machine_unregister(sdev, pdata);
+ /*
+ * Balance the runtime pm usage count in case we are faced with an
+ * exception and we forcably prevented D3 power state to preserve
+ * context
+ */
+ if (sdev->d3_prevented) {
+ sdev->d3_prevented = false;
+ pm_runtime_put_noidle(sdev->dev);
+ }
+
if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
sof_fw_trace_free(sdev);
ret = snd_sof_dsp_power_down_notify(sdev);
@@ -486,10 +771,14 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_ipc_free(sdev);
snd_sof_free_debug(sdev);
snd_sof_remove(sdev);
+ snd_sof_remove_late(sdev);
+ sof_ops_free(sdev);
+ } else if (aborted) {
+ /* probe_work never ran */
+ snd_sof_remove_late(sdev);
+ sof_ops_free(sdev);
}
- sof_ops_free(sdev);
-
/* release firmware */
snd_sof_fw_unload(sdev);
@@ -504,15 +793,51 @@ int snd_sof_device_shutdown(struct device *dev)
if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
cancel_work_sync(&sdev->probe_work);
- if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
+ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
+ sof_fw_trace_free(sdev);
return snd_sof_shutdown(sdev);
+ }
return 0;
}
EXPORT_SYMBOL(snd_sof_device_shutdown);
+/* Machine driver registering and unregistering */
+int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = pdata;
+ const char *drv_name;
+ const void *mach;
+ int size;
+
+ drv_name = plat_data->machine->drv_name;
+ mach = plat_data->machine;
+ size = sizeof(*plat_data->machine);
+
+ /* register machine driver, pass machine info as pdata */
+ plat_data->pdev_mach =
+ platform_device_register_data(sdev->dev, drv_name,
+ PLATFORM_DEVID_NONE, mach, size);
+ if (IS_ERR(plat_data->pdev_mach))
+ return PTR_ERR(plat_data->pdev_mach);
+
+ dev_dbg(sdev->dev, "created machine %s\n",
+ dev_name(&plat_data->pdev_mach->dev));
+
+ return 0;
+}
+EXPORT_SYMBOL(sof_machine_register);
+
+void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = pdata;
+
+ platform_device_unregister(plat_data->pdev_mach);
+}
+EXPORT_SYMBOL(sof_machine_unregister);
+
MODULE_AUTHOR("Liam Girdwood");
-MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
MODULE_ALIAS("platform:sof-audio");
-MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
+MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT");
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index d547318e0d32..b24943a65c89 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -19,24 +19,6 @@
#include "sof-priv.h"
#include "ops.h"
-static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- size_t size;
- char *string;
- int ret;
-
- string = kzalloc(count+1, GFP_KERNEL);
- if (!string)
- return -ENOMEM;
-
- size = simple_write_to_buffer(string, count, ppos, buffer, count);
- ret = size;
-
- kfree(string);
- return ret;
-}
-
static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
@@ -126,7 +108,6 @@ static const struct file_operations sof_dfs_fops = {
.open = simple_open,
.read = sof_dfsentry_read,
.llseek = default_llseek,
- .write = sof_dfsentry_write,
};
/* create FS entry for debug files that can expose DSP memories, registers */
@@ -236,7 +217,6 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
}
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
- pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
if (ret < 0 || reply->rhdr.error < 0) {
ret = min(ret, reply->rhdr.error);
@@ -330,14 +310,51 @@ EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
int snd_sof_dbg_init(struct snd_sof_dev *sdev)
{
- struct snd_sof_dsp_ops *ops = sof_ops(sdev);
+ const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
+ struct snd_sof_pdata *plat_data = sdev->pdata;
const struct snd_sof_debugfs_map *map;
+ struct dentry *fw_profile;
int i;
int err;
/* use "sof" as top level debugFS dir */
sdev->debugfs_root = debugfs_create_dir("sof", NULL);
+ /* expose firmware/topology prefix/names for test purposes */
+ fw_profile = debugfs_create_dir("fw_profile", sdev->debugfs_root);
+
+ debugfs_create_str("fw_path", 0444, fw_profile,
+ (char **)&plat_data->fw_filename_prefix);
+ /* library path is not valid for IPC3 */
+ if (plat_data->ipc_type != SOF_IPC_TYPE_3) {
+ /*
+ * fw_lib_prefix can be NULL if the vendor/platform does not
+ * support loadable libraries
+ */
+ if (plat_data->fw_lib_prefix) {
+ debugfs_create_str("fw_lib_path", 0444, fw_profile,
+ (char **)&plat_data->fw_lib_prefix);
+ } else {
+ static char *fw_lib_path;
+
+ fw_lib_path = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "Not supported");
+ if (!fw_lib_path)
+ return -ENOMEM;
+
+ debugfs_create_str("fw_lib_path", 0444, fw_profile,
+ (char **)&fw_lib_path);
+ }
+ }
+ debugfs_create_str("tplg_path", 0444, fw_profile,
+ (char **)&plat_data->tplg_filename_prefix);
+ debugfs_create_str("fw_name", 0444, fw_profile,
+ (char **)&plat_data->fw_filename);
+ debugfs_create_str("tplg_name", 0444, fw_profile,
+ (char **)&plat_data->tplg_filename);
+ debugfs_create_u32("ipc_type", 0444, fw_profile,
+ (u32 *)&plat_data->ipc_type);
+
/* init dfsentry list */
INIT_LIST_HEAD(&sdev->dfsentry_list);
@@ -433,13 +450,15 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg)
{
- if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
- sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) {
+ if ((IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
+ sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) && !sdev->d3_prevented) {
/* should we prevent DSP entering D3 ? */
if (!sdev->ipc_dump_printed)
dev_info(sdev->dev,
"Attempting to prevent DSP from entering D3 state to preserve context\n");
- pm_runtime_get_if_in_use(sdev->dev);
+
+ if (pm_runtime_get_if_in_use(sdev->dev) == 1)
+ sdev->d3_prevented = true;
}
/* dump vital information to the logs */
diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c
new file mode 100644
index 000000000000..76bde2e0be1d
--- /dev/null
+++ b/sound/soc/sof/fw-file-profile.c
@@ -0,0 +1,345 @@
+// 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) 2023 Intel Corporation
+//
+
+#include <linux/firmware.h>
+#include <sound/sof.h>
+#include <sound/sof/ext_manifest4.h>
+#include "sof-priv.h"
+
+static int sof_test_firmware_file(struct device *dev,
+ struct sof_loadable_file_profile *profile,
+ enum sof_ipc_type *ipc_type_to_adjust)
+{
+ enum sof_ipc_type fw_ipc_type;
+ const struct firmware *fw;
+ const char *fw_filename;
+ const u32 *magic;
+ int ret;
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path,
+ profile->fw_name);
+ if (!fw_filename)
+ return -ENOMEM;
+
+ ret = firmware_request_nowarn(&fw, fw_filename, dev);
+ if (ret < 0) {
+ dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename);
+ kfree(fw_filename);
+ return ret;
+ }
+
+ /* firmware file exists, check the magic number */
+ magic = (const u32 *)fw->data;
+ switch (*magic) {
+ case SOF_EXT_MAN_MAGIC_NUMBER:
+ fw_ipc_type = SOF_IPC_TYPE_3;
+ break;
+ case SOF_EXT_MAN4_MAGIC_NUMBER:
+ fw_ipc_type = SOF_IPC_TYPE_4;
+ break;
+ default:
+ dev_err(dev, "Invalid firmware magic: %#x\n", *magic);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ipc_type_to_adjust) {
+ *ipc_type_to_adjust = fw_ipc_type;
+ } else if (fw_ipc_type != profile->ipc_type) {
+ dev_err(dev,
+ "ipc type mismatch between %s and expected: %d vs %d\n",
+ fw_filename, fw_ipc_type, profile->ipc_type);
+ ret = -EINVAL;
+ }
+out:
+ release_firmware(fw);
+ kfree(fw_filename);
+
+ return ret;
+}
+
+static int sof_test_topology_file(struct device *dev,
+ struct sof_loadable_file_profile *profile)
+{
+ const struct firmware *fw;
+ const char *tplg_filename;
+ int ret;
+
+ if (!profile->tplg_path || !profile->tplg_name)
+ return 0;
+
+ /* Dummy topology does not exist and should not be used */
+ if (strstr(profile->tplg_name, "dummy"))
+ return 0;
+
+ tplg_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->tplg_path,
+ profile->tplg_name);
+ if (!tplg_filename)
+ return -ENOMEM;
+
+ ret = firmware_request_nowarn(&fw, tplg_filename, dev);
+ if (!ret)
+ release_firmware(fw);
+ else
+ dev_dbg(dev, "Failed to open topology file: %s\n", tplg_filename);
+
+ kfree(tplg_filename);
+
+ return ret;
+}
+
+static bool sof_platform_uses_generic_loader(struct snd_sof_dev *sdev)
+{
+ return (sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_raw ||
+ sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_memcpy);
+}
+
+static int
+sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev,
+ enum sof_ipc_type ipc_type,
+ const struct sof_dev_desc *desc,
+ struct sof_loadable_file_profile *base_profile,
+ struct sof_loadable_file_profile *out_profile)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ bool fw_lib_path_allocated = false;
+ struct device *dev = sdev->dev;
+ bool fw_path_allocated = false;
+ int ret = 0;
+
+ /* firmware path */
+ if (base_profile->fw_path) {
+ out_profile->fw_path = base_profile->fw_path;
+ } else if (base_profile->fw_path_postfix) {
+ out_profile->fw_path = devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
+ desc->default_fw_path[ipc_type],
+ base_profile->fw_path_postfix);
+ if (!out_profile->fw_path)
+ return -ENOMEM;
+
+ fw_path_allocated = true;
+ } else {
+ out_profile->fw_path = desc->default_fw_path[ipc_type];
+ }
+
+ /* firmware filename */
+ if (base_profile->fw_name)
+ out_profile->fw_name = base_profile->fw_name;
+ else
+ out_profile->fw_name = desc->default_fw_filename[ipc_type];
+
+ /*
+ * Check the custom firmware path/filename and adjust the ipc_type to
+ * match with the existing file for the remaining path configuration.
+ *
+ * For default path and firmware name do a verification before
+ * continuing further.
+ */
+ if ((base_profile->fw_path || base_profile->fw_name) &&
+ sof_platform_uses_generic_loader(sdev)) {
+ ret = sof_test_firmware_file(dev, out_profile, &ipc_type);
+ if (ret)
+ return ret;
+
+ if (!(desc->ipc_supported_mask & BIT(ipc_type))) {
+ dev_err(dev, "Unsupported IPC type %d needed by %s/%s\n",
+ ipc_type, out_profile->fw_path,
+ out_profile->fw_name);
+ return -EINVAL;
+ }
+ }
+
+ /* firmware library path */
+ if (base_profile->fw_lib_path) {
+ out_profile->fw_lib_path = base_profile->fw_lib_path;
+ } else if (desc->default_lib_path[ipc_type]) {
+ if (base_profile->fw_lib_path_postfix) {
+ out_profile->fw_lib_path = devm_kasprintf(dev,
+ GFP_KERNEL, "%s/%s",
+ desc->default_lib_path[ipc_type],
+ base_profile->fw_lib_path_postfix);
+ if (!out_profile->fw_lib_path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ fw_lib_path_allocated = true;
+ } else {
+ out_profile->fw_lib_path = desc->default_lib_path[ipc_type];
+ }
+ }
+
+ if (base_profile->fw_path_postfix)
+ out_profile->fw_path_postfix = base_profile->fw_path_postfix;
+
+ if (base_profile->fw_lib_path_postfix)
+ out_profile->fw_lib_path_postfix = base_profile->fw_lib_path_postfix;
+
+ /* topology path */
+ if (base_profile->tplg_path)
+ out_profile->tplg_path = base_profile->tplg_path;
+ else
+ out_profile->tplg_path = desc->default_tplg_path[ipc_type];
+
+ /* topology name */
+ out_profile->tplg_name = plat_data->tplg_filename;
+
+ out_profile->ipc_type = ipc_type;
+
+ /* Test only default firmware file */
+ if ((!base_profile->fw_path && !base_profile->fw_name) &&
+ sof_platform_uses_generic_loader(sdev))
+ ret = sof_test_firmware_file(dev, out_profile, NULL);
+
+ if (!ret)
+ ret = sof_test_topology_file(dev, out_profile);
+
+out:
+ if (ret) {
+ /* Free up path strings created with devm_kasprintf */
+ if (fw_path_allocated)
+ devm_kfree(dev, out_profile->fw_path);
+ if (fw_lib_path_allocated)
+ devm_kfree(dev, out_profile->fw_lib_path);
+
+ memset(out_profile, 0, sizeof(*out_profile));
+ }
+
+ return ret;
+}
+
+static void
+sof_print_missing_firmware_info(struct snd_sof_dev *sdev,
+ enum sof_ipc_type ipc_type,
+ struct sof_loadable_file_profile *base_profile)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ const struct sof_dev_desc *desc = plat_data->desc;
+ struct device *dev = sdev->dev;
+ int ipc_type_count, i;
+ char *marker;
+
+ dev_err(dev, "SOF firmware and/or topology file not found.\n");
+ dev_info(dev, "Supported default profiles\n");
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION))
+ ipc_type_count = SOF_IPC_TYPE_COUNT - 1;
+ else
+ ipc_type_count = base_profile->ipc_type;
+
+ for (i = 0; i <= ipc_type_count; i++) {
+ if (!(desc->ipc_supported_mask & BIT(i)))
+ continue;
+
+ if (i == ipc_type)
+ marker = "Requested";
+ else
+ marker = "Fallback";
+
+ dev_info(dev, "- ipc type %d (%s):\n", i, marker);
+ if (base_profile->fw_path_postfix)
+ dev_info(dev, " Firmware file: %s/%s/%s\n",
+ desc->default_fw_path[i],
+ base_profile->fw_path_postfix,
+ desc->default_fw_filename[i]);
+ else
+ dev_info(dev, " Firmware file: %s/%s\n",
+ desc->default_fw_path[i],
+ desc->default_fw_filename[i]);
+
+ dev_info(dev, " Topology file: %s/%s\n",
+ desc->default_tplg_path[i],
+ plat_data->tplg_filename);
+ }
+
+ if (base_profile->fw_path || base_profile->fw_name ||
+ base_profile->tplg_path || base_profile->tplg_name)
+ dev_info(dev, "Verify the path/name override module parameters.\n");
+
+ dev_info(dev, "Check if you have 'sof-firmware' package installed.\n");
+ dev_info(dev, "Optionally it can be manually downloaded from:\n");
+ dev_info(dev, " https://github.com/thesofproject/sof-bin/\n");
+}
+
+static void sof_print_profile_info(struct snd_sof_dev *sdev,
+ enum sof_ipc_type ipc_type,
+ struct sof_loadable_file_profile *profile)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct device *dev = sdev->dev;
+
+ if (ipc_type != profile->ipc_type)
+ dev_info(dev,
+ "Using fallback IPC type %d (requested type was %d)\n",
+ profile->ipc_type, ipc_type);
+
+ dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type);
+
+ /* The firmware path is only valid when generic loader is used */
+ if (sof_platform_uses_generic_loader(sdev))
+ dev_info(dev, " Firmware file: %s/%s\n",
+ profile->fw_path, profile->fw_name);
+
+ if (profile->fw_lib_path)
+ dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path);
+
+ if (plat_data->machine && plat_data->machine->get_function_tplg_files &&
+ !plat_data->disable_function_topology)
+ dev_info(dev, " Topology file: function topologies\n");
+ else
+ dev_info(dev, " Topology file: %s/%s\n",
+ profile->tplg_path, profile->tplg_name);
+}
+
+int sof_create_ipc_file_profile(struct snd_sof_dev *sdev,
+ struct sof_loadable_file_profile *base_profile,
+ struct sof_loadable_file_profile *out_profile)
+{
+ const struct sof_dev_desc *desc = sdev->pdata->desc;
+ int ipc_fallback_start, ret, i;
+
+ memset(out_profile, 0, sizeof(*out_profile));
+
+ ret = sof_file_profile_for_ipc_type(sdev, base_profile->ipc_type, desc,
+ base_profile, out_profile);
+ if (!ret)
+ goto out;
+
+ /*
+ * No firmware file was found for the requested IPC type, as fallback
+ * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is selected, check
+ * all IPC versions in a backwards direction (from newer to older)
+ * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is not selected,
+ * check only older IPC versions than the selected/default version
+ */
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION))
+ ipc_fallback_start = SOF_IPC_TYPE_COUNT - 1;
+ else
+ ipc_fallback_start = (int)base_profile->ipc_type - 1;
+
+ for (i = ipc_fallback_start; i >= 0 ; i--) {
+ if (i == base_profile->ipc_type ||
+ !(desc->ipc_supported_mask & BIT(i)))
+ continue;
+
+ ret = sof_file_profile_for_ipc_type(sdev, i, desc, base_profile,
+ out_profile);
+ if (!ret)
+ break;
+ }
+
+out:
+ if (ret)
+ sof_print_missing_firmware_info(sdev, base_profile->ipc_type,
+ base_profile);
+ else
+ sof_print_profile_info(sdev, base_profile->ipc_type, out_profile);
+
+ return ret;
+}
+EXPORT_SYMBOL(sof_create_ipc_file_profile);
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index 4751b04d5e6f..09d88ce5b9e6 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -32,22 +32,14 @@ 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
+ depends on IMX_SCMI_LMM_DRV
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 798b43a415bf..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-objs := imx8.o
-snd-sof-imx8m-objs := imx8m.o
-snd-sof-imx8ulp-objs := imx8ulp.o
+snd-sof-imx8-y := imx8.o
+snd-sof-imx9-y := imx9.o
-snd-sof-imx-common-objs := imx-common.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 36e3d414a18f..e787d3932fbb 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,28 +79,406 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
}
EXPORT_SYMBOL(imx8_dump);
-int imx8_parse_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks)
+static void imx_handle_reply(struct imx_dsp_ipc *ipc)
{
- int ret;
+ 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;
+}
- ret = devm_clk_bulk_get(sdev->dev, clks->num_dsp_clks, clks->dsp_clks);
+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 request DSP clocks\n");
+ 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 ret;
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
}
-EXPORT_SYMBOL(imx8_parse_clocks);
-int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks)
+static int imx_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
{
- return clk_bulk_prepare_enable(clks->num_dsp_clks, clks->dsp_clks);
+ 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);
}
-EXPORT_SYMBOL(imx8_enable_clocks);
-void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks)
+static int imx_region_name_to_blk_type(const char *region_name)
{
- clk_bulk_disable_unprepare(clks->num_dsp_clks, clks->dsp_clks);
+ 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 platform_device *pdev;
+ struct resource *res, _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);
+
+ } else {
+ ret = of_reserved_mem_region_to_resource_byname(pdev->dev.of_node,
+ chip_info->memory[i].name,
+ &_res);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "no valid entry for %s\n",
+ chip_info->memory[i].name);
+ res = &_res;
+ }
+
+ sdev->bar[blk_type] = devm_ioremap_resource(sdev->dev, res);
+ if (IS_ERR(sdev->bar[blk_type]))
+ return dev_err_probe(sdev->dev,
+ PTR_ERR(sdev->bar[blk_type]),
+ "failed to ioremap %s region\n",
+ chip_info->memory[i].name);
+ }
+
+ return 0;
}
-EXPORT_SYMBOL(imx8_disable_clocks);
+
+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 -ENOMEM;
+
+ 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 ret;
+
+ 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 ec4b3a5c7496..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,13 +164,6 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
void imx8_dump(struct snd_sof_dev *sdev, u32 flags);
-struct imx_clocks {
- struct clk_bulk_data *dsp_clks;
- int num_dsp_clks;
-};
-
-int imx8_parse_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks);
-int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks);
-void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks);
+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 2844d9a8040a..7e9eab2e3034 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -1,119 +1,54 @@
// 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>
+#include <linux/reset.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
-
-/* DSP clocks */
-static struct clk_bulk_data imx8_dsp_clks[] = {
- { .id = "ipg" },
- { .id = "ocram" },
- { .id = "core" },
+/* 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)
+
+/* 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;
+ struct reset_control *run_stall;
};
-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 imx_clocks *clks;
-};
-
-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)
+static int imx8_shutdown(struct snd_sof_dev *sdev)
{
- 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,
-};
-
-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);
+ /*
+ * Force the DSP to stall. After the firmware image is loaded,
+ * the stall will be removed during run() by a matching
+ * imx_sc_pm_cpu_start() call.
+ */
+ imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, false,
+ RESET_VECTOR_VADDR);
return 0;
}
@@ -123,24 +58,23 @@ static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
*/
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",
@@ -148,14 +82,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;
@@ -163,17 +97,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;
@@ -181,468 +114,344 @@ 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;
-
- priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL);
- if (!priv->clks)
- 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;
- }
-
- 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;
- }
+ struct imx_sc_ipc *sc_ipc_handle;
+ struct imx_common_data *common;
+ int ret;
- 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;
- }
+ common = sdev->pdata->hw_pdata;
- 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;
- }
+ 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");
- 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;
+ common->chip_pdata = sc_ipc_handle;
- 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;
- }
+ return 0;
+}
- 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;
- }
+static int imx8m_reset(struct snd_sof_dev *sdev)
+{
+ struct imx8m_chip_data *chip;
+ u32 pwrctl;
- 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;
+ chip = get_chip_pdata(sdev);
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
+ /* put DSP into reset and stall */
+ pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL);
+ pwrctl |= IMX8M_PWRCTL_CORERESET;
+ writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL);
- /* init clocks info */
- priv->clks->dsp_clks = imx8_dsp_clks;
- priv->clks->num_dsp_clks = ARRAY_SIZE(imx8_dsp_clks);
+ /* keep reset asserted for 10 cycles */
+ usleep_range(1, 2);
- ret = imx8_parse_clocks(sdev, priv->clks);
- if (ret < 0)
- goto exit_pdev_unregister;
+ reset_control_assert(chip->run_stall);
- ret = imx8_enable_clocks(sdev, priv->clks);
- if (ret < 0)
- 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 int 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;
-
- imx8_disable_clocks(sdev, 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);
- }
+ struct imx8m_chip_data *chip = get_chip_pdata(sdev);
- return 0;
+ return reset_control_deassert(chip->run_stall);
}
-/* 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)
+static int imx8m_probe(struct snd_sof_dev *sdev)
{
- /* 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;
- }
-}
+ struct imx_common_data *common;
+ struct imx8m_chip_data *chip;
-static void imx8_suspend(struct snd_sof_dev *sdev)
-{
- int i;
- struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
+ common = sdev->pdata->hw_pdata;
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
+ chip = devm_kzalloc(sdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
- imx8_disable_clocks(sdev, priv->clks);
-}
+ 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");
-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->run_stall = devm_reset_control_get_exclusive(sdev->dev, "runstall");
+ if (IS_ERR(chip->run_stall))
+ return dev_err_probe(sdev->dev, PTR_ERR(chip->run_stall),
+ "failed to get dsp runstall reset control\n");
- ret = imx8_enable_clocks(sdev, priv->clks);
- if (ret < 0)
- return ret;
-
- 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,
- };
-
- ret = imx8_resume(sdev);
- if (ret < 0)
- return ret;
+ struct regmap *regmap = get_chip_pdata(sdev);
- 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 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,
+ .core_shutdown = imx8_shutdown,
};
-/* i.MX8X ops */
-static 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,
+ .core_shutdown = imx8_shutdown,
+};
- .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_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 sof_dev_desc sof_of_imx8qxp_desc = {
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
- .default_fw_path = {
- [SOF_IPC] = "imx/sof",
+static struct snd_sof_of_mach sof_imx8_machs[] = {
+ {
+ .compatible = "fsl,imx8qxp-mek",
+ .sof_tplg_filename = "sof-imx8-wm8960.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_tplg_path = {
- [SOF_IPC] = "imx/sof-tplg",
+ {
+ .compatible = "fsl,imx8qxp-mek-wcpu",
+ .sof_tplg_filename = "sof-imx8-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_fw_filename = {
- [SOF_IPC] = "sof-imx8x.ri",
+ {
+ .compatible = "fsl,imx8qm-mek",
+ .sof_tplg_filename = "sof-imx8-wm8960.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 = {
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
- .default_fw_path = {
- [SOF_IPC] = "imx/sof",
+ {
+ .compatible = "fsl,imx8qm-mek-revd",
+ .sof_tplg_filename = "sof-imx8-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
+ },
+ {
+ .compatible = "fsl,imx8qxp-mek-bb",
+ .sof_tplg_filename = "sof-imx8-cs42888.tplg",
+ .drv_name = "asoc-audio-graph-card2",
+ },
+ {
+ .compatible = "fsl,imx8qm-mek-bb",
+ .sof_tplg_filename = "sof-imx8-cs42888.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_tplg_path = {
- [SOF_IPC] = "imx/sof-tplg",
+ {
+ .compatible = "fsl,imx8mp-evk",
+ .sof_tplg_filename = "sof-imx8mp-wm8960.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_fw_filename = {
- [SOF_IPC] = "sof-imx8.ri",
+ {
+ .compatible = "fsl,imx8mp-evk-revb4",
+ .sof_tplg_filename = "sof-imx8mp-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8_ops,
+ {
+ .compatible = "fsl,imx8ulp-evk",
+ .sof_tplg_filename = "sof-imx8ulp-btsco.tplg",
+ .drv_name = "asoc-audio-graph-card2",
+ },
+ {}
};
+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);
@@ -653,11 +462,12 @@ 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,
},
};
module_platform_driver(snd_sof_of_imx8_driver);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF support for IMX8 platforms");
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c
deleted file mode 100644
index 1243f8a6141e..000000000000
--- a/sound/soc/sof/imx/imx8m.c
+++ /dev/null
@@ -1,508 +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
-
-static struct clk_bulk_data imx8m_dsp_clks[] = {
- { .id = "ipg" },
- { .id = "ocram" },
- { .id = "core" },
-};
-
-/* 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 imx_clocks *clks;
-
- 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;
-
- priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL);
- if (!priv->clks)
- 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_compatible("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;
- }
-
- /* init clocks info */
- priv->clks->dsp_clks = imx8m_dsp_clks;
- priv->clks->num_dsp_clks = ARRAY_SIZE(imx8m_dsp_clks);
-
- ret = imx8_parse_clocks(sdev, priv->clks);
- if (ret < 0)
- goto exit_pdev_unregister;
-
- ret = imx8_enable_clocks(sdev, priv->clks);
- if (ret < 0)
- goto exit_pdev_unregister;
-
- return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
- return ret;
-}
-
-static int imx8m_remove(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = sdev->pdata->hw_pdata;
-
- imx8_disable_clocks(sdev, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-
- return 0;
-}
-
-/* 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,
- },
-},
-};
-
-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 = imx8_enable_clocks(sdev, priv->clks);
- if (ret < 0)
- 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);
-
- imx8_disable_clocks(sdev, 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 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_NO_PERIOD_WAKEUP,
-};
-
-static struct sof_dev_desc sof_of_imx8mp_desc = {
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
- .default_fw_path = {
- [SOF_IPC] = "imx/sof",
- },
- .default_tplg_path = {
- [SOF_IPC] = "imx/sof-tplg",
- },
- .default_fw_filename = {
- [SOF_IPC] = "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_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c
deleted file mode 100644
index 4a562c9856e9..000000000000
--- a/sound/soc/sof/imx/imx8ulp.c
+++ /dev/null
@@ -1,515 +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
-
-static struct clk_bulk_data imx8ulp_dsp_clks[] = {
- { .id = "core" },
- { .id = "ipg" },
- { .id = "ocram" },
- { .id = "mu" },
-};
-
-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 imx_clocks *clks;
-};
-
-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;
-
- priv->clks = devm_kzalloc(&pdev->dev, sizeof(*priv->clks), GFP_KERNEL);
- if (!priv->clks)
- 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;
- }
-
- priv->clks->dsp_clks = imx8ulp_dsp_clks;
- priv->clks->num_dsp_clks = ARRAY_SIZE(imx8ulp_dsp_clks);
-
- ret = imx8_parse_clocks(sdev, priv->clks);
- if (ret < 0)
- goto exit_pdev_unregister;
-
- ret = imx8_enable_clocks(sdev, priv->clks);
- if (ret < 0)
- goto exit_pdev_unregister;
-
- return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
-
- return ret;
-}
-
-static int imx8ulp_remove(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- imx8_disable_clocks(sdev, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-
- return 0;
-}
-
-/* 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);
-
- imx8_disable_clocks(sdev, 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;
-
- imx8_enable_clocks(sdev, priv->clks);
-
- 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 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_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 sof_dev_desc sof_of_imx8ulp_desc = {
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
- .default_fw_path = {
- [SOF_IPC] = "imx/sof",
- },
- .default_tplg_path = {
- [SOF_IPC] = "imx/sof-tplg",
- },
- .default_fw_filename = {
- [SOF_IPC] = "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_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/imx/imx9.c b/sound/soc/sof/imx/imx9.c
new file mode 100644
index 000000000000..e56e8a1c8022
--- /dev/null
+++ b/sound/soc/sof/imx/imx9.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/firmware/imx/sm.h>
+
+#include "imx-common.h"
+
+#define IMX95_M7_CPU_ID 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 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");
+
+ return scmi_imx_lmm_reset_vector_set(IMX95_M7_LM_ID, IMX95_M7_CPU_ID,
+ 0, res->start);
+}
+
+static int imx95_core_kick(struct snd_sof_dev *sdev)
+{
+ return scmi_imx_lmm_operation(IMX95_M7_LM_ID, SCMI_IMX_LMM_BOOT, 0);
+}
+
+static int imx95_core_shutdown(struct snd_sof_dev *sdev)
+{
+ return scmi_imx_lmm_operation(IMX95_M7_LM_ID,
+ SCMI_IMX_LMM_SHUTDOWN,
+ SCMI_IMX_LMM_OP_FORCEFUL);
+}
+
+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/Kconfig b/sound/soc/sof/intel/Kconfig
index 69c1a370d3b6..54cd3807f8c6 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -97,8 +97,8 @@ config SND_SOC_SOF_MERRIFIELD
config SND_SOC_SOF_INTEL_SKL
tristate
- select SND_SOC_SOF_HDA_COMMON
- select SND_SOC_SOF_INTEL_IPC4
+ select SND_SOC_SOF_HDA_GENERIC
+ select SND_SOC_SOF_IPC4
config SND_SOC_SOF_SKYLAKE
tristate "SOF support for SkyLake"
@@ -122,9 +122,9 @@ config SND_SOC_SOF_KABYLAKE
config SND_SOC_SOF_INTEL_APL
tristate
- select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_HDA_GENERIC
select SND_SOC_SOF_IPC3
- select SND_SOC_SOF_INTEL_IPC4
+ select SND_SOC_SOF_IPC4
config SND_SOC_SOF_APOLLOLAKE
tristate "SOF support for Apollolake"
@@ -148,10 +148,10 @@ config SND_SOC_SOF_GEMINILAKE
config SND_SOC_SOF_INTEL_CNL
tristate
- select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_HDA_GENERIC
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
- select SND_SOC_SOF_INTEL_IPC4
+ select SND_SOC_SOF_IPC4
config SND_SOC_SOF_CANNONLAKE
tristate "SOF support for Cannonlake"
@@ -184,10 +184,11 @@ config SND_SOC_SOF_COMETLAKE
config SND_SOC_SOF_INTEL_ICL
tristate
- select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_HDA_GENERIC
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
- select SND_SOC_SOF_INTEL_IPC4
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_CNL
config SND_SOC_SOF_ICELAKE
tristate "SOF support for Icelake"
@@ -211,10 +212,11 @@ config SND_SOC_SOF_JASPERLAKE
config SND_SOC_SOF_INTEL_TGL
tristate
- select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_HDA_GENERIC
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
- select SND_SOC_SOF_INTEL_IPC4
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_CNL
config SND_SOC_SOF_TIGERLAKE
tristate "SOF support for Tigerlake"
@@ -248,9 +250,9 @@ config SND_SOC_SOF_ALDERLAKE
config SND_SOC_SOF_INTEL_MTL
tristate
- select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_HDA_GENERIC
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
- select SND_SOC_SOF_INTEL_IPC4
+ select SND_SOC_SOF_IPC4
config SND_SOC_SOF_METEORLAKE
tristate "SOF support for Meteorlake"
@@ -262,13 +264,71 @@ config SND_SOC_SOF_METEORLAKE
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_SOF_INTEL_LNL
+ tristate
+ select SOUNDWIRE_INTEL if SND_SOC_SOF_INTEL_SOUNDWIRE != n
+ select SND_SOC_SOF_HDA_GENERIC
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOF_SOF_HDA_SDW_BPT if SND_SOC_SOF_INTEL_SOUNDWIRE != n
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_MTL
+
+config SND_SOC_SOF_LUNARLAKE
+ tristate "SOF support for Lunarlake"
+ default SND_SOC_SOF_PCI
+ select SND_SOC_SOF_INTEL_LNL
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Lunarlake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_INTEL_PTL
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_LNL
+
+config SND_SOC_SOF_PANTHERLAKE
+ tristate "SOF support for Pantherlake"
+ default SND_SOC_SOF_PCI
+ select SND_SOC_SOF_INTEL_PTL
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Pantherlake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_INTEL_NVL
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_PTL
+
+config SND_SOC_SOF_NOVALAKE
+ tristate "SOF support for Novalake"
+ default SND_SOC_SOF_PCI
+ select SND_SOC_SOF_INTEL_NVL
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Novalake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
config SND_SOC_SOF_HDA_COMMON
tristate
+
+config SND_SOC_SOF_HDA_GENERIC
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_PCI_DEV
select SND_INTEL_DSP_CONFIG
select SND_SOC_SOF_HDA_LINK_BASELINE
select SND_SOC_SOF_HDA_PROBES
+ select SND_SOC_SDW_UTILS if SND_SOC_SOF_INTEL_SOUNDWIRE
select SND_SOC_SOF_HDA_MLINK if SND_SOC_SOF_HDA_LINK
help
This option is not user-selectable but automagically handled by
@@ -280,7 +340,7 @@ config SND_SOC_SOF_HDA_MLINK
This option is not user-selectable but automagically handled by
'select' statements at a higher level.
-if SND_SOC_SOF_HDA_COMMON
+if SND_SOC_SOF_HDA_GENERIC
config SND_SOC_SOF_HDA_LINK
bool "SOF support for HDA Links(HDA/HDMI)"
@@ -300,7 +360,14 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
Say Y if you want to enable HDAudio codecs with SOF.
If unsure select "N".
-endif ## SND_SOC_SOF_HDA_COMMON
+endif ## SND_SOC_SOF_HDA_GENERIC
+
+config SND_SOF_SOF_HDA_SDW_BPT
+ tristate
+ select SND_HDA_EXT_CORE
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level.
config SND_SOC_SOF_HDA_LINK_BASELINE
tristate
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index fdb463c12e91..cc9783e933f8 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -1,36 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-snd-sof-acpi-intel-byt-objs := byt.o
-snd-sof-acpi-intel-bdw-objs := bdw.o
+snd-sof-acpi-intel-byt-y := byt.o
+snd-sof-acpi-intel-bdw-y := bdw.o
-snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
+snd-sof-intel-hda-common-y := hda-loader.o hda-stream.o hda-trace.o \
hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
hda-dai.o hda-dai-ops.o hda-bus.o \
- skl.o hda-loader-skl.o \
- apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
+ telemetry.o tracepoints.o
-snd-sof-intel-hda-mlink-objs := hda-mlink.o
+snd-sof-intel-hda-generic-y := hda.o hda-common-ops.o
+
+snd-sof-intel-hda-mlink-y := hda-mlink.o
+
+snd-sof-intel-hda-sdw-bpt-objs := hda-sdw-bpt.o
snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o
-snd-sof-intel-hda-objs := hda-codec.o
+snd-sof-intel-hda-y := hda-codec.o
-snd-sof-intel-atom-objs := atom.o
+snd-sof-intel-atom-y := atom.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-atom.o
obj-$(CONFIG_SND_SOC_SOF_BAYTRAIL) += snd-sof-acpi-intel-byt.o
obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-acpi-intel-bdw.o
obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o
+obj-$(CONFIG_SND_SOC_SOF_HDA_GENERIC) += snd-sof-intel-hda-generic.o
obj-$(CONFIG_SND_SOC_SOF_HDA_MLINK) += snd-sof-intel-hda-mlink.o
obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o
-snd-sof-pci-intel-tng-objs := pci-tng.o
-snd-sof-pci-intel-skl-objs := pci-skl.o
-snd-sof-pci-intel-apl-objs := pci-apl.o
-snd-sof-pci-intel-cnl-objs := pci-cnl.o
-snd-sof-pci-intel-icl-objs := pci-icl.o
-snd-sof-pci-intel-tgl-objs := pci-tgl.o
-snd-sof-pci-intel-mtl-objs := pci-mtl.o
+obj-$(CONFIG_SND_SOF_SOF_HDA_SDW_BPT) += snd-sof-intel-hda-sdw-bpt.o
+
+snd-sof-pci-intel-tng-y := pci-tng.o
+snd-sof-pci-intel-skl-y := pci-skl.o skl.o hda-loader-skl.o
+snd-sof-pci-intel-apl-y := pci-apl.o apl.o
+snd-sof-pci-intel-cnl-y := pci-cnl.o cnl.o
+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 ptl.o
+snd-sof-pci-intel-nvl-y := pci-nvl.o nvl.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
@@ -39,3 +48,6 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_PTL) += snd-sof-pci-intel-ptl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_NVL) += snd-sof-pci-intel-nvl.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index e1f25a8f0c32..0c68ae41a8a8 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -29,7 +29,6 @@ static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = {
/* apollolake ops */
struct snd_sof_dsp_ops sof_apl_ops;
-EXPORT_SYMBOL_NS(sof_apl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_apl_ops_init(struct snd_sof_dev *sdev)
{
@@ -39,7 +38,7 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
/* probe/remove/shutdown */
sof_apl_ops.shutdown = hda_dsp_shutdown;
- if (sdev->pdata->ipc_type == SOF_IPC) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
/* doorbell */
sof_apl_ops.irq_thread = hda_dsp_ipc_irq_thread;
@@ -52,10 +51,10 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
sof_apl_ops.set_power_state = hda_dsp_set_power_state_ipc3;
}
- if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -97,7 +96,6 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_apl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc apl_chip_info = {
/* Apollolake */
@@ -120,5 +118,5 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS,
+ .platform = "apl",
};
-EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c
index bd9789b483b1..0d364bcdcfa9 100644
--- a/sound/soc/sof/intel/atom.c
+++ b/sound/soc/sof/intel/atom.c
@@ -3,7 +3,7 @@
// 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) 2018-2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2021 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -78,23 +78,23 @@ 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);
+EXPORT_SYMBOL_NS(atom_dump, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
/*
* IPC Doorbell IRQ handler and thread.
@@ -131,7 +131,7 @@ irqreturn_t atom_irq_handler(int irq, void *context)
return ret;
}
-EXPORT_SYMBOL_NS(atom_irq_handler, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_irq_handler, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
irqreturn_t atom_irq_thread(int irq, void *context)
{
@@ -176,7 +176,7 @@ irqreturn_t atom_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(atom_irq_thread, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_irq_thread, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
@@ -191,19 +191,19 @@ int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_send_msg, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MBOX_OFFSET;
}
-EXPORT_SYMBOL_NS(atom_get_mailbox_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_get_mailbox_offset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MBOX_OFFSET;
}
-EXPORT_SYMBOL_NS(atom_get_window_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_get_window_offset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
static void atom_host_done(struct snd_sof_dev *sdev)
{
@@ -248,7 +248,7 @@ int atom_run(struct snd_sof_dev *sdev)
/* return init core mask */
return 1;
}
-EXPORT_SYMBOL_NS(atom_run, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_run, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_reset(struct snd_sof_dev *sdev)
{
@@ -267,7 +267,7 @@ int atom_reset(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(atom_reset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_reset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *sof_tplg_filename,
@@ -330,7 +330,7 @@ struct snd_soc_acpi_mach *atom_machine_select(struct snd_sof_dev *sdev)
return mach;
}
-EXPORT_SYMBOL_NS(atom_machine_select, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_machine_select, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
/* Atom DAIs */
struct snd_soc_dai_driver atom_dai[] = {
@@ -401,7 +401,7 @@ struct snd_soc_dai_driver atom_dai[] = {
},
},
};
-EXPORT_SYMBOL_NS(atom_dai, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_dai, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
void atom_set_mach_params(struct snd_soc_acpi_mach *mach,
struct snd_sof_dev *sdev)
@@ -415,6 +415,7 @@ void atom_set_mach_params(struct snd_soc_acpi_mach *mach,
mach_params->num_dai_drivers = desc->ops->num_drv;
mach_params->dai_drivers = desc->ops->drv;
}
-EXPORT_SYMBOL_NS(atom_set_mach_params, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_set_mach_params, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF support for Atom platforms");
diff --git a/sound/soc/sof/intel/atom.h b/sound/soc/sof/intel/atom.h
index b965e5e080a6..20fb19102cb0 100644
--- a/sound/soc/sof/intel/atom.h
+++ b/sound/soc/sof/intel/atom.h
@@ -3,7 +3,7 @@
* 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) 2017-2021 Intel Corporation. All rights reserved.
+ * Copyright(c) 2017-2021 Intel Corporation
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index 812a49b1d3f4..f1287d509835 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -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;
@@ -567,7 +566,7 @@ static struct snd_soc_dai_driver bdw_dai[] = {
};
/* broadwell ops */
-static struct snd_sof_dsp_ops sof_bdw_ops = {
+static const struct snd_sof_dsp_ops sof_bdw_ops = {
/*Device init */
.probe = bdw_probe,
@@ -639,16 +638,16 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = 0,
.chip_info = &bdw_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
+ [SOF_IPC_TYPE_3] = "intel/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-bdw.ri",
+ [SOF_IPC_TYPE_3] = "sof-bdw.ri",
},
.nocodec_tplg_filename = "sof-bdw-nocodec.tplg",
.ops = &sof_bdw_ops,
@@ -687,13 +686,13 @@ 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,
},
};
module_platform_driver(snd_sof_acpi_intel_bdw_driver);
MODULE_LICENSE("Dual BSD/GPL");
-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_DESCRIPTION("SOF support for Broadwell platforms");
+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 faf223b38360..18208f77b84d 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -100,19 +100,16 @@ static int byt_resume(struct snd_sof_dev *sdev)
return 0;
}
-static int byt_remove(struct snd_sof_dev *sdev)
+static void byt_remove(struct snd_sof_dev *sdev)
{
byt_reset_dsp_disable_int(sdev);
-
- return 0;
}
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;
@@ -216,7 +213,7 @@ irq:
}
/* baytrail ops */
-static struct snd_sof_dsp_ops sof_byt_ops = {
+static const struct snd_sof_dsp_ops sof_byt_ops = {
/* device init */
.probe = byt_acpi_probe,
.remove = byt_remove,
@@ -291,7 +288,7 @@ static const struct sof_intel_dsp_desc byt_chip_info = {
};
/* cherrytrail and braswell ops */
-static struct snd_sof_dsp_ops sof_cht_ops = {
+static const struct snd_sof_dsp_ops sof_cht_ops = {
/* device init */
.probe = byt_acpi_probe,
.remove = byt_remove,
@@ -374,16 +371,16 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = {
.resindex_imr_base = 2,
.irqindex_host_ipc = 0,
.chip_info = &byt_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
+ [SOF_IPC_TYPE_3] = "intel/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-byt.ri",
+ [SOF_IPC_TYPE_3] = "sof-byt.ri",
},
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
@@ -396,16 +393,16 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = {
.resindex_imr_base = 2,
.irqindex_host_ipc = 5,
.chip_info = &byt_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
+ [SOF_IPC_TYPE_3] = "intel/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-byt.ri",
+ [SOF_IPC_TYPE_3] = "sof-byt.ri",
},
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
@@ -418,16 +415,16 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
.resindex_imr_base = 2,
.irqindex_host_ipc = 5,
.chip_info = &cht_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
+ [SOF_IPC_TYPE_3] = "intel/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-cht.ri",
+ [SOF_IPC_TYPE_3] = "sof-cht.ri",
},
.nocodec_tplg_filename = "sof-cht-nocodec.tplg",
.ops = &sof_cht_ops,
@@ -470,14 +467,14 @@ 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,
},
};
module_platform_driver(snd_sof_acpi_intel_byt_driver);
MODULE_LICENSE("Dual BSD/GPL");
-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);
+MODULE_DESCRIPTION("SOF support for Baytrail/Cherrytrail");
+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/cnl.c b/sound/soc/sof/intel/cnl.c
index a95222e53ecf..0cc5725515e7 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -110,6 +110,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS(cnl_ipc4_irq_thread, "SND_SOC_SOF_INTEL_CNL");
irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
{
@@ -202,6 +203,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS(cnl_ipc_irq_thread, "SND_SOC_SOF_INTEL_CNL");
static void cnl_ipc_host_done(struct snd_sof_dev *sdev)
{
@@ -284,6 +286,7 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
+EXPORT_SYMBOL_NS(cnl_ipc4_send_msg, "SND_SOC_SOF_INTEL_CNL");
int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
@@ -326,11 +329,12 @@ int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
* CTX_SAVE IPC, which is sent before the DSP enters D3.
*/
if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE))
- mod_delayed_work(system_wq, &hdev->d0i3_work,
+ mod_delayed_work(system_dfl_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
return 0;
}
+EXPORT_SYMBOL_NS(cnl_ipc_send_msg, "SND_SOC_SOF_INTEL_CNL");
void cnl_ipc_dump(struct snd_sof_dev *sdev)
{
@@ -351,6 +355,7 @@ void cnl_ipc_dump(struct snd_sof_dev *sdev)
"error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
hipcida, hipctdr, hipcctl);
}
+EXPORT_SYMBOL_NS(cnl_ipc_dump, "SND_SOC_SOF_INTEL_CNL");
void cnl_ipc4_dump(struct snd_sof_dev *sdev)
{
@@ -372,10 +377,11 @@ void cnl_ipc4_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(cnl_ipc4_dump, "SND_SOC_SOF_INTEL_CNL");
/* cannonlake ops */
struct snd_sof_dsp_ops sof_cnl_ops;
-EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_cnl_ops, "SND_SOC_SOF_INTEL_CNL");
int sof_cnl_ops_init(struct snd_sof_dev *sdev)
{
@@ -386,7 +392,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
sof_cnl_ops.shutdown = hda_dsp_shutdown;
/* ipc */
- if (sdev->pdata->ipc_type == SOF_IPC) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
/* doorbell */
sof_cnl_ops.irq_thread = cnl_ipc_irq_thread;
@@ -399,10 +405,10 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
sof_cnl_ops.set_power_state = hda_dsp_set_power_state_ipc3;
}
- if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -444,7 +450,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_cnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_cnl_ops_init, "SND_SOC_SOF_INTEL_CNL");
const struct sof_intel_dsp_desc cnl_chip_info = {
/* Cannonlake */
@@ -466,13 +472,15 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_8,
+ .platform = "cnl",
};
-EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
/*
* JasperLake is technically derived from IceLake, and should be in
@@ -501,10 +509,13 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
+ .platform = "jsl",
};
-EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(jsl_chip_info, "SND_SOC_SOF_INTEL_CNL");
diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h
index 2dfae9285d3c..1ca19c691852 100644
--- a/sound/soc/sof/intel/ext_manifest.h
+++ b/sound/soc/sof/intel/ext_manifest.h
@@ -3,7 +3,7 @@
* 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) 2020 Intel Corporation. All rights reserved.
+ * Copyright(c) 2020 Intel Corporation
*/
/*
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index fc63085d2d74..6492e1cefbfb 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Keyon Jie <yang.jie@linux.intel.com>
@@ -72,7 +72,12 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+ const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
+
snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
+
+ if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0)
+ bus->use_pio_for_commands = true;
#else
snd_hdac_ext_bus_init(bus, dev, NULL, NULL);
#endif
@@ -94,6 +99,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
spin_lock_init(&bus->reg_lock);
#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
}
+EXPORT_SYMBOL_NS(sof_hda_bus_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
void sof_hda_bus_exit(struct snd_sof_dev *sdev)
{
@@ -103,3 +109,4 @@ void sof_hda_bus_exit(struct snd_sof_dev *sdev)
snd_hdac_ext_bus_exit(bus);
#endif
}
+EXPORT_SYMBOL_NS(sof_hda_bus_exit, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index 8a5e99a898ec..37674ea452d6 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Keyon Jie <yang.jie@linux.intel.com>
//
@@ -54,8 +54,16 @@ static int request_codec_module(struct hda_codec *codec)
static int hda_codec_load_module(struct hda_codec *codec)
{
- int ret = request_codec_module(codec);
+ int ret;
+
+ ret = snd_hdac_device_register(&codec->core);
+ if (ret) {
+ dev_err(&codec->core.dev, "failed to register hdac device\n");
+ put_device(&codec->core.dev);
+ return ret;
+ }
+ ret = request_codec_module(codec);
if (ret <= 0) {
codec->probe_id = HDA_CODEC_ID_GENERIC;
ret = request_codec_module(codec);
@@ -71,20 +79,29 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
struct hdac_bus *bus = sof_to_bus(sdev);
struct hda_codec *codec;
unsigned int mask = 0;
+ unsigned int val = 0;
if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
if (enable) {
- list_for_each_codec(codec, hbus)
+ list_for_each_codec(codec, hbus) {
+ /* only set WAKEEN when needed for HDaudio codecs */
+ mask |= BIT(codec->core.addr);
if (codec->jacktbl.used)
- mask |= BIT(codec->core.addr);
+ val |= BIT(codec->core.addr);
+ }
+ } else {
+ list_for_each_codec(codec, hbus) {
+ /* reset WAKEEN only HDaudio codecs */
+ mask |= BIT(codec->core.addr);
+ }
}
- snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
+ snd_hdac_chip_updatew(bus, WAKEEN, mask & STATESTS_INT_MASK, val);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, "SND_SOC_SOF_HDA_AUDIO_CODEC");
/* check jack status after resuming from suspend mode */
void hda_codec_jack_check(struct snd_sof_dev *sdev)
@@ -104,7 +121,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
if (codec->jacktbl.used)
pm_request_resume(&codec->core.dev);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, "SND_SOC_SOF_HDA_AUDIO_CODEC");
#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
#define is_generic_config(bus) \
@@ -116,7 +133,6 @@ EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, int type)
{
struct hda_codec *codec;
- int ret;
codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr);
if (IS_ERR(codec)) {
@@ -126,13 +142,6 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i
codec->core.type = type;
- ret = snd_hdac_device_register(&codec->core);
- if (ret) {
- dev_err(bus->dev, "failed to register hdac device\n");
- put_device(&codec->core.dev);
- return ERR_PTR(ret);
- }
-
return codec;
}
@@ -169,6 +178,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
return ret;
hda_priv->codec = codec;
+ hda_priv->dev_index = address;
dev_set_drvdata(&codec->core.dev, hda_priv);
if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) {
@@ -227,7 +237,7 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev)
}
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_check_for_state_change(struct snd_sof_dev *sdev)
{
@@ -240,7 +250,7 @@ void hda_codec_check_for_state_change(struct snd_sof_dev *sdev)
snd_hdac_chip_writew(bus, STATESTS, codec_mask);
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_detect_mask(struct snd_sof_dev *sdev)
{
@@ -250,9 +260,6 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev)
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
- /* Accept unsolicited responses */
- snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
-
/* detect codecs */
if (!bus->codec_mask) {
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
@@ -265,7 +272,7 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev)
bus->codec_mask);
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
{
@@ -278,7 +285,7 @@ void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
/* initialize the codec command I/O */
snd_hdac_bus_init_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
{
@@ -292,7 +299,7 @@ void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
if (bus->cmd_dma_state)
snd_hdac_bus_init_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
{
@@ -305,7 +312,7 @@ void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
/* initialize the codec command I/O */
snd_hdac_bus_stop_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
{
@@ -320,7 +327,7 @@ void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
snd_hdac_bus_stop_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
{
@@ -333,7 +340,7 @@ void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
/* clear rirb status */
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
{
@@ -344,7 +351,7 @@ void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
snd_hdac_set_codec_wakeup(bus, status);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, "SND_SOC_SOF_HDA_AUDIO_CODEC");
bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
{
@@ -371,7 +378,7 @@ bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
}
return active;
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_device_remove(struct snd_sof_dev *sdev)
{
@@ -384,7 +391,7 @@ void hda_codec_device_remove(struct snd_sof_dev *sdev)
/* codec removal, invoke bus_device_remove */
snd_hdac_ext_bus_device_remove(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, "SND_SOC_SOF_HDA_AUDIO_CODEC");
#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
@@ -403,7 +410,7 @@ void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable)
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
int hda_codec_i915_init(struct snd_sof_dev *sdev)
{
@@ -424,7 +431,7 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
int hda_codec_i915_exit(struct snd_sof_dev *sdev)
{
@@ -442,8 +449,10 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
return snd_hdac_i915_exit(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+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");
+MODULE_DESCRIPTION("SOF support for HDaudio codecs");
diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c
index 8e1cd0babd32..746b426b1329 100644
--- a/sound/soc/sof/intel/hda-common-ops.c
+++ b/sound/soc/sof/intel/hda-common-ops.c
@@ -3,7 +3,7 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
/*
@@ -14,10 +14,12 @@
#include "hda.h"
#include "../sof-audio.h"
-struct snd_sof_dsp_ops sof_hda_common_ops = {
+const struct snd_sof_dsp_ops sof_hda_common_ops = {
/* probe/remove/shutdown */
+ .probe_early = hda_dsp_probe_early,
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
+ .remove_late = hda_dsp_remove_late,
/* Register IO uses direct mmio */
@@ -55,6 +57,9 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,
+ .get_dai_frame_counter = hda_dsp_get_stream_llp,
+ .get_host_byte_counter = hda_dsp_get_stream_ldp,
+
/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,
@@ -81,6 +86,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
+ .is_chain_dma_supported = hda_is_chain_dma_supported,
/* PM */
.suspend = hda_dsp_suspend,
@@ -99,3 +105,4 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
.dsp_arch_ops = &sof_xtensa_arch_ops,
};
+EXPORT_SYMBOL_NS(sof_hda_common_ops, "SND_SOC_SOF_INTEL_HDA_GENERIC");
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index 84bf01bd360a..8332d4bda558 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -128,6 +128,7 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_get_caps, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
{
@@ -136,6 +137,7 @@ void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_GPROCEN, val);
}
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
{
@@ -144,6 +146,7 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_PIE, val);
}
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
{
@@ -178,12 +181,14 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON");
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
{
struct hdac_bus *bus = sof_to_bus(sdev);
struct hdac_stream *stream;
int sd_offset, ret = 0;
+ u32 gctl;
if (bus->chip_init)
return 0;
@@ -192,6 +197,12 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
hda_dsp_ctrl_misc_clock_gating(sdev, false);
+ /* clear WAKE_STS if not in reset */
+ gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
+ if (gctl & SOF_HDA_GCTL_RESET)
+ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
+ SOF_HDA_WAKESTS, SOF_HDA_WAKESTS_INT_MASK);
+
/* reset HDA controller */
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
@@ -209,7 +220,11 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
}
usleep_range(1000, 1200);
- hda_codec_detect_mask(sdev);
+ /* Accept unsolicited responses */
+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+
+ if (detect_codec)
+ hda_codec_detect_mask(sdev);
/* clear stream status */
list_for_each_entry(stream, &bus->stream_list, list) {
@@ -221,7 +236,7 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
/* clear WAKESTS */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
- SOF_HDA_WAKESTS_INT_MASK);
+ bus->codec_mask);
hda_codec_rirb_status_clear(sdev);
@@ -255,6 +270,7 @@ err:
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_init_chip, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
{
@@ -314,3 +330,9 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
bus->chip_init = false;
}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF helpers for HDaudio platforms");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index f3513796c189..92681ca7f24d 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -3,10 +3,12 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
+#include <sound/hda_register.h>
+#include <sound/hda-mlink.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
#include "../ipc4-priv.h"
@@ -42,7 +44,7 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
static struct hdac_ext_stream *
hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_intel_hda_stream *hda_stream;
const struct sof_intel_dsp_desc *chip;
struct snd_sof_dev *sdev;
@@ -179,8 +181,8 @@ static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
struct hdac_stream *hstream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
/* set the hdac_stream in the codec dai */
snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);
@@ -190,18 +192,20 @@ static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
unsigned int link_bps;
unsigned int format_val;
+ unsigned int bits;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
link_bps = codec_dai->driver->playback.sig_bits;
else
link_bps = codec_dai->driver->capture.sig_bits;
- format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
- params_format(params), link_bps, 0);
+ bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
+ link_bps);
+ format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
params_rate(params), params_channels(params), params_format(params));
@@ -212,13 +216,83 @@ static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,
static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct hdac_bus *bus = sof_to_bus(sdev);
return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
}
+static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int format_val;
+ unsigned int bits;
+
+ bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,
+ params_physical_width(params));
+ format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));
+
+ dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+ params_rate(params), params_channels(params), params_format(params));
+
+ return format_val;
+}
+
+static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int format_val;
+ snd_pcm_format_t format;
+ unsigned int channels;
+ unsigned int width;
+ unsigned int bits;
+
+ channels = params_channels(params);
+ format = params_format(params);
+ width = params_physical_width(params);
+
+ if (format == SNDRV_PCM_FORMAT_S16_LE) {
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ channels /= 2;
+ width = 32;
+ }
+
+ bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width);
+ format_val = snd_hdac_stream_format(channels, bits, params_rate(params));
+
+ dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+ params_rate(params), channels, format);
+
+ return format_val;
+}
+
+static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_ssp_get_hlink(bus);
+}
+
+static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_dmic_get_hlink(bus);
+}
+
+static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_sdw_get_hlink(bus);
+}
+
static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
@@ -234,6 +308,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
+ if (pipe_widget->instance_id < 0)
+ return 0;
+
mutex_lock(&ipc4_data->pipeline_state_mutex);
switch (cmd) {
@@ -269,9 +346,20 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_hdac_ext_stream_start(hext_stream);
break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /*
+ * Save the LLP registers since in case of PAUSE the LLP
+ * register are not reset to 0, the delay calculation will use
+ * the saved offsets for compensating the delay calculation.
+ */
+ hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
+ hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
+ snd_hdac_ext_stream_clear(hext_stream);
+ break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ hext_stream->pplcllpl = 0;
+ hext_stream->pplcllpu = 0;
snd_hdac_ext_stream_clear(hext_stream);
break;
default:
@@ -297,6 +385,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
+ if (pipe_widget->instance_id < 0)
+ return 0;
+
mutex_lock(&ipc4_data->pipeline_state_mutex);
switch (cmd) {
@@ -357,6 +448,45 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.get_hlink = hda_get_hlink,
};
+static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
+ .get_hext_stream = hda_ipc4_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .pre_trigger = hda_ipc4_pre_trigger,
+ .trigger = hda_trigger,
+ .post_trigger = hda_ipc4_post_trigger,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = ssp_get_hlink,
+};
+
+static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
+ .get_hext_stream = hda_ipc4_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .pre_trigger = hda_ipc4_pre_trigger,
+ .trigger = hda_trigger,
+ .post_trigger = hda_ipc4_post_trigger,
+ .calc_stream_format = dmic_calc_stream_format,
+ .get_hlink = dmic_get_hlink,
+};
+
+static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
+ .get_hext_stream = hda_ipc4_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .pre_trigger = hda_ipc4_pre_trigger,
+ .trigger = hda_trigger,
+ .post_trigger = hda_ipc4_post_trigger,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = sdw_get_hlink,
+};
+
static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.get_hext_stream = hda_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
@@ -369,6 +499,17 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.get_hlink = hda_get_hlink,
};
+static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
+ .get_hext_stream = hda_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .trigger = hda_trigger,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = sdw_get_hlink,
+};
+
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
@@ -379,9 +520,14 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
case SNDRV_PCM_TRIGGER_STOP:
{
struct snd_sof_dai_config_data data = { 0 };
+ int ret;
data.dai_data = DMA_CHAN_INVALID;
- return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+ ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+ if (ret < 0)
+ return ret;
+
+ break;
}
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
@@ -434,6 +580,13 @@ static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
.get_hlink = hda_get_hlink,
};
+static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
+ .get_hext_stream = hda_dspless_get_hext_stream,
+ .setup_hext_stream = hda_dspless_setup_hext_stream,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = sdw_get_hlink,
+};
+
#endif
const struct hda_dai_widget_dma_ops *
@@ -441,14 +594,26 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
struct snd_sof_dai *sdai;
+ const struct sof_intel_dsp_desc *chip;
- if (sdev->dspless_mode_selected)
- return &hda_dspless_dma_ops;
-
+ chip = get_chip_info(sdev->pdata);
sdai = swidget->private;
+ if (sdev->dspless_mode_selected) {
+ switch (sdai->type) {
+ case SOF_DAI_INTEL_HDA:
+ return &hda_dspless_dma_ops;
+ case SOF_DAI_INTEL_ALH:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &sdw_dspless_dma_ops;
+ default:
+ return NULL;
+ }
+ }
+
switch (sdev->pdata->ipc_type) {
- case SOF_IPC:
+ case SOF_IPC_TYPE_3:
{
struct sof_dai_private_data *private = sdai->private;
@@ -456,18 +621,34 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
return &hda_ipc3_dma_ops;
break;
}
- case SOF_INTEL_IPC4:
+ case SOF_IPC_TYPE_4:
{
- struct sof_ipc4_copier *ipc4_copier = sdai->private;
-
- if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ switch (sdai->type) {
+ case SOF_DAI_INTEL_HDA:
if (pipeline->use_chain_dma)
return &hda_ipc4_chain_dma_ops;
return &hda_ipc4_dma_ops;
+ case SOF_DAI_INTEL_SSP:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &ssp_ipc4_dma_ops;
+ case SOF_DAI_INTEL_DMIC:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &dmic_ipc4_dma_ops;
+ case SOF_DAI_INTEL_ALH:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ if (pipeline->use_chain_dma)
+ return &sdw_ipc4_chain_dma_ops;
+ return &sdw_ipc4_dma_ops;
+
+ default:
+ break;
}
break;
}
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 3297dea493aa..883d0d3bae9e 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -3,13 +3,15 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Keyon Jie <yang.jie@linux.intel.com>
//
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
+#include <sound/hda_register.h>
#include <sound/intel-nhlt.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
@@ -27,14 +29,6 @@ static bool hda_use_tplg_nhlt;
module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
-static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
-{
- struct snd_sof_widget *swidget = w->dobj.private;
- struct snd_soc_component *component = swidget->scomp;
-
- return snd_soc_component_get_drvdata(component);
-}
-
int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
struct snd_sof_dai_config_data *data)
{
@@ -60,6 +54,7 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
return 0;
}
+EXPORT_SYMBOL_NS(hda_dai_config, "SND_SOC_SOF_INTEL_HDA_COMMON");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
@@ -81,12 +76,13 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
sdev = widget_to_sdev(w);
- /*
- * The swidget parameter of hda_select_dai_widget_ops() is ignored in
- * case of DSPless mode
- */
+ if (!swidget) {
+ dev_err(sdev->dev, "%s: swidget is NULL\n", __func__);
+ return NULL;
+ }
+
if (sdev->dspless_mode_selected)
- return hda_select_dai_widget_ops(sdev, NULL);
+ return hda_select_dai_widget_ops(sdev, swidget);
sdai = swidget->private;
@@ -107,9 +103,10 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
return sdai->platform_private;
}
-static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
- struct hdac_ext_stream *hext_stream,
- struct snd_soc_dai *cpu_dai)
+static int
+hda_link_dma_cleanup(struct snd_pcm_substream *substream,
+ struct hdac_ext_stream *hext_stream,
+ struct snd_soc_dai *cpu_dai, bool release)
{
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
struct sof_intel_hda_stream *hda_stream;
@@ -133,6 +130,17 @@ static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
}
+ if (!release) {
+ /*
+ * Force stream reconfiguration without releasing the channel on
+ * subsequent stream restart (without free), including LinkDMA
+ * reset.
+ * The stream is released via hda_dai_hw_free()
+ */
+ hext_stream->link_prepared = 0;
+ return 0;
+ }
+
if (ops->release_hext_stream)
ops->release_hext_stream(sdev, cpu_dai, substream);
@@ -216,18 +224,18 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
if (!hext_stream)
return 0;
- return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
+ return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, true);
}
-static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int __maybe_unused hda_dai_hw_params_data(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai,
+ struct snd_sof_dai_config_data *data,
+ unsigned int flags)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
struct hdac_ext_stream *hext_stream;
- struct snd_sof_dai_config_data data = { 0 };
- unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
struct snd_sof_dev *sdev = widget_to_sdev(w);
int ret;
@@ -247,9 +255,19 @@ static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
hext_stream = ops->get_hext_stream(sdev, dai, substream);
flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
- data.dai_data = hdac_stream(hext_stream)->stream_tag - 1;
+ data->dai_data = hdac_stream(hext_stream)->stream_tag - 1;
+
+ return hda_dai_config(w, flags, data);
+}
+
+static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_sof_dai_config_data data = { 0 };
+ unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
- return hda_dai_config(w, flags, &data);
+ return hda_dai_hw_params_data(substream, params, dai, &data, flags);
}
/*
@@ -297,8 +315,10 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
}
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- ret = hda_link_dma_cleanup(substream, hext_stream, dai);
+ ret = hda_link_dma_cleanup(substream, hext_stream, dai,
+ cmd != SNDRV_PCM_TRIGGER_STOP);
if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
return ret;
@@ -315,7 +335,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int stream = substream->stream;
return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai);
@@ -330,6 +350,294 @@ static const struct snd_soc_dai_ops hda_dai_ops = {
#endif
+static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
+{
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_sof_dai *sdai = swidget->private;
+ struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
+
+ return ipc4_copier;
+}
+
+static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai,
+ struct snd_sof_dai_config_data *data,
+ unsigned int flags)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_ipc4_dma_config_tlv *dma_config_tlv;
+ const struct hda_dai_widget_dma_ops *ops;
+ struct sof_ipc4_dma_config *dma_config;
+ struct sof_ipc4_copier *ipc4_copier;
+ struct hdac_ext_stream *hext_stream;
+ struct hdac_stream *hstream;
+ struct snd_sof_dev *sdev;
+ struct snd_soc_dai *dai;
+ int cpu_dai_id;
+ int stream_id;
+ int ret;
+
+ ops = hda_dai_get_ops(substream, cpu_dai);
+ if (!ops) {
+ dev_err(cpu_dai->dev, "DAI widget ops not set\n");
+ return -EINVAL;
+ }
+
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ /* nothing more to do if the link is already prepared */
+ if (hext_stream && hext_stream->link_prepared)
+ return 0;
+
+ /* use HDaudio stream handling */
+ ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hda_dai_hw_params_data failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (sdev->dspless_mode_selected)
+ return 0;
+
+ /* get stream_id */
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ if (!hext_stream) {
+ dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
+ return -ENODEV;
+ }
+
+ hstream = &hext_stream->hstream;
+ stream_id = hstream->stream_tag;
+
+ if (!stream_id) {
+ dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
+ return -ENODEV;
+ }
+
+ /* configure TLV */
+ ipc4_copier = widget_to_copier(w);
+
+ for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
+ if (dai == cpu_dai)
+ break;
+ }
+
+ dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
+ dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
+ /* dma_config_priv_size is zero */
+ dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
+
+ dma_config = &dma_config_tlv->dma_config;
+
+ dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
+ dma_config->pre_allocated_by_host = 1;
+ dma_config->dma_channel_id = stream_id - 1;
+ dma_config->stream_id = stream_id;
+ /*
+ * Currently we use a DMA for each device in ALH blob. The device will
+ * be copied in sof_ipc4_prepare_copier_module.
+ */
+ dma_config->dma_stream_channel_map.device_count = 1;
+ dma_config->dma_priv_config_size = 0;
+
+ return 0;
+}
+
+static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_sof_dai_config_data data = { 0 };
+ unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
+
+ return non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
+}
+
+static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ int stream = substream->stream;
+
+ return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
+}
+
+static const struct snd_soc_dai_ops ssp_dai_ops = {
+ .hw_params = non_hda_dai_hw_params,
+ .hw_free = hda_dai_hw_free,
+ .trigger = hda_dai_trigger,
+ .prepare = non_hda_dai_prepare,
+};
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+ .hw_params = non_hda_dai_hw_params,
+ .hw_free = hda_dai_hw_free,
+ .trigger = hda_dai_trigger,
+ .prepare = non_hda_dai_prepare,
+};
+
+int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai,
+ int link_id,
+ int intel_alh_id)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_ipc4_dma_config_tlv *dma_config_tlv;
+ struct snd_sof_dai_config_data data = { 0 };
+ unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS;
+ const struct hda_dai_widget_dma_ops *ops;
+ struct sof_ipc4_dma_config *dma_config;
+ struct sof_ipc4_copier *ipc4_copier;
+ struct hdac_ext_stream *hext_stream;
+ struct snd_soc_dai *dai;
+ struct snd_sof_dev *sdev;
+ bool cpu_dai_found = false;
+ int cpu_dai_id;
+ int ch_mask;
+ 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");
+ return -EINVAL;
+ }
+
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ /* nothing more to do if the link is already prepared */
+ if (hext_stream && hext_stream->link_prepared)
+ return 0;
+
+ /*
+ * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
+ * due to xruns or after a call to snd_pcm_drain/drop()
+ */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ 0, 0, substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ data.dai_index = (link_id << 8) | cpu_dai->id;
+ data.dai_node_id = intel_alh_id;
+ ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+ if (!hext_stream)
+ return -ENODEV;
+
+ /*
+ * in the case of SoundWire we need to program the PCMSyCM registers. In case
+ * of aggregated devices, we need to define the channel mask for each sublink
+ * by reconstructing the split done in soc-pcm.c
+ */
+ for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
+ if (dai == cpu_dai) {
+ cpu_dai_found = true;
+ break;
+ }
+ }
+
+ if (!cpu_dai_found)
+ return -ENODEV;
+
+ ch_mask = GENMASK(params_channels(params) - 1, 0);
+
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ ch_mask,
+ hdac_stream(hext_stream)->stream_tag,
+ substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (sdev->dspless_mode_selected)
+ return 0;
+
+ ipc4_copier = widget_to_copier(w);
+ dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id];
+ dma_config = &dma_config_tlv->dma_config;
+ dma_config->dma_stream_channel_map.mapping[0].device = data.dai_index;
+ dma_config->dma_stream_channel_map.mapping[0].channel_mask = ch_mask;
+
+ /*
+ * copy the dma_config_tlv to all ipc4_copier in the same link. Because only one copier
+ * will be handled in sof_ipc4_prepare_copier_module.
+ */
+ 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));
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai,
+ int link_id)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_sof_dev *sdev;
+ int ret;
+
+ ret = hda_dai_hw_free(substream, cpu_dai);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ sdev = widget_to_sdev(w);
+
+ /* in the case of SoundWire we need to reset the PCMSyCM registers */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ 0, 0, substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ return hda_dai_trigger(substream, cmd, cpu_dai);
+}
+EXPORT_SYMBOL_NS(sdw_hda_dai_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
static int hda_dai_suspend(struct hdac_bus *bus)
{
struct snd_soc_pcm_runtime *rtd;
@@ -356,19 +664,17 @@ static int hda_dai_suspend(struct hdac_bus *bus)
struct snd_sof_dev *sdev;
struct snd_sof_dai *sdai;
- rtd = asoc_substream_to_rtd(hext_stream->link_substream);
- cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ rtd = snd_soc_substream_to_rtd(hext_stream->link_substream);
+ cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
swidget = w->dobj.private;
sdev = widget_to_sdev(w);
sdai = swidget->private;
ops = sdai->platform_private;
- ret = hda_link_dma_cleanup(hext_stream->link_substream,
- hext_stream,
- cpu_dai);
- if (ret < 0)
- return ret;
+ if (rtd->dpcm[hext_stream->link_substream->stream].state !=
+ SND_SOC_DPCM_STATE_PAUSED)
+ continue;
/* for consistency with TRIGGER_SUSPEND */
if (ops->post_trigger) {
@@ -378,13 +684,53 @@ static int hda_dai_suspend(struct hdac_bus *bus)
if (ret < 0)
return ret;
}
+
+ ret = hda_link_dma_cleanup(hext_stream->link_substream,
+ hext_stream, cpu_dai, true);
+ if (ret < 0)
+ return ret;
}
}
return 0;
}
-#endif
+static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+ const struct sof_intel_dsp_desc *chip;
+ int i;
+
+ chip = get_chip_info(sdev->pdata);
+
+ if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+ for (i = 0; i < ops->num_drv; i++) {
+ if (strstr(ops->drv[i].name, "SSP"))
+ ops->drv[i].ops = &ssp_dai_ops;
+ }
+ }
+}
+
+static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+ const struct sof_intel_dsp_desc *chip;
+ int i;
+
+ chip = get_chip_info(sdev->pdata);
+
+ if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+ for (i = 0; i < ops->num_drv; i++) {
+ if (strstr(ops->drv[i].name, "DMIC"))
+ ops->drv[i].ops = &dmic_dai_ops;
+ }
+ }
+}
+
+#else
+
+static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
@@ -399,23 +745,30 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
#endif
}
- if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
+ ssp_set_dai_drv_ops(sdev, ops);
+ dmic_set_dai_drv_ops(sdev, ops);
+
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4 && !hda_use_tplg_nhlt) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
}
}
+EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_ops_free(struct snd_sof_dev *sdev)
{
- if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
if (!hda_use_tplg_nhlt)
intel_nhlt_free(ipc4_data->nhlt);
+
+ kfree(sdev->private);
+ sdev->private = NULL;
}
}
-EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ops_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* common dai driver for skl+ platforms.
@@ -567,6 +920,7 @@ struct snd_soc_dai_driver skl_dai[] = {
},
#endif
};
+EXPORT_SYMBOL_NS(skl_dai, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
{
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 44f39a520bb3..e9f092f082a1 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -20,11 +20,21 @@
#include <sound/hda_register.h>
#include <sound/hda-mlink.h>
#include <trace/events/sof_intel.h>
+#include <sound/sof/xtensa.h>
#include "../sof-audio.h"
#include "../ops.h"
#include "hda.h"
+#include "mtl.h"
#include "hda-ipc.h"
+#define EXCEPT_MAX_HDR_SIZE 0x400
+#define HDA_EXT_ROM_STATUS_SIZE 8
+
+struct hda_dsp_msg_code {
+ u32 code;
+ const char *text;
+};
+
static bool hda_enable_trace_D0I3_S0;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
module_param_named(enable_trace_D0I3_S0, hda_enable_trace_D0I3_S0, bool, 0444);
@@ -32,6 +42,87 @@ MODULE_PARM_DESC(enable_trace_D0I3_S0,
"SOF HDA enable trace when the DSP is in D0I3 in S0");
#endif
+static void hda_get_interfaces(struct snd_sof_dev *sdev, u32 *interface_mask)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ switch (chip->hw_ip_version) {
+ case SOF_INTEL_TANGIER:
+ case SOF_INTEL_BAYTRAIL:
+ case SOF_INTEL_BROADWELL:
+ interface_mask[SOF_DAI_DSP_ACCESS] = BIT(SOF_DAI_INTEL_SSP);
+ break;
+ case SOF_INTEL_CAVS_1_5:
+ case SOF_INTEL_CAVS_1_5_PLUS:
+ interface_mask[SOF_DAI_DSP_ACCESS] =
+ BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | BIT(SOF_DAI_INTEL_HDA);
+ interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
+ break;
+ case SOF_INTEL_CAVS_1_8:
+ case SOF_INTEL_CAVS_2_0:
+ case SOF_INTEL_CAVS_2_5:
+ case SOF_INTEL_ACE_1_0:
+ interface_mask[SOF_DAI_DSP_ACCESS] =
+ BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
+ BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
+ interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
+ break;
+ case SOF_INTEL_ACE_2_0:
+ case SOF_INTEL_ACE_3_0:
+ case SOF_INTEL_ACE_4_0:
+ interface_mask[SOF_DAI_DSP_ACCESS] =
+ BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
+ BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
+ /* all interfaces accessible without DSP */
+ interface_mask[SOF_DAI_HOST_ACCESS] =
+ interface_mask[SOF_DAI_DSP_ACCESS];
+ break;
+ default:
+ break;
+ }
+}
+
+u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
+{
+ u32 interface_mask[SOF_DAI_ACCESS_NUM] = { 0 };
+
+ hda_get_interfaces(sdev, interface_mask);
+
+ return interface_mask[sdev->dspless_mode_selected];
+}
+EXPORT_SYMBOL_NS(hda_get_interface_mask, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type)
+{
+ u32 interface_mask[SOF_DAI_ACCESS_NUM] = { 0 };
+ const struct sof_intel_dsp_desc *chip;
+
+ if (sdev->dspless_mode_selected)
+ return false;
+
+ hda_get_interfaces(sdev, interface_mask);
+
+ if (!(interface_mask[SOF_DAI_DSP_ACCESS] & BIT(dai_type)))
+ return false;
+
+ if (dai_type == SOF_DAI_INTEL_HDA)
+ return true;
+
+ switch (dai_type) {
+ case SOF_DAI_INTEL_SSP:
+ case SOF_DAI_INTEL_DMIC:
+ case SOF_DAI_INTEL_ALH:
+ chip = get_chip_info(sdev->pdata);
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return false;
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS(hda_is_chain_dma_supported, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
/*
* DSP Core control.
*/
@@ -126,6 +217,7 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask)
/* set reset state */
return hda_dsp_core_reset_enter(sdev, core_mask);
}
+EXPORT_SYMBOL_NS(hda_dsp_core_stall_reset, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask)
{
@@ -151,6 +243,7 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask)
return is_enable;
}
+EXPORT_SYMBOL_NS(hda_dsp_core_is_enabled, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
{
@@ -178,6 +271,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_core_run, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* Power Management.
@@ -229,6 +323,7 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_core_power_up, "SND_SOC_SOF_INTEL_HDA_COMMON");
static int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask)
{
@@ -276,6 +371,7 @@ int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask)
return hda_dsp_core_run(sdev, core_mask);
}
+EXPORT_SYMBOL_NS(hda_dsp_enable_core, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
unsigned int core_mask)
@@ -316,6 +412,7 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_core_reset_power_down, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
{
@@ -334,6 +431,7 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
{
@@ -351,6 +449,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0);
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_int_disable, "SND_SOC_SOF_INTEL_HDA_COMMON");
static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev)
{
@@ -634,6 +733,7 @@ int hda_dsp_set_power_state_ipc3(struct snd_sof_dev *sdev,
return hda_dsp_set_power_state(sdev, target_state);
}
+EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc3, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev,
const struct sof_dsp_power_state *target_state)
@@ -645,6 +745,7 @@ int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev,
return hda_dsp_set_power_state(sdev, target_state);
}
+EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc4, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* Audio DSP states may transform as below:-
@@ -681,17 +782,27 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
struct hdac_bus *bus = sof_to_bus(sdev);
+ bool imr_lost = false;
int ret, j;
/*
- * The memory used for IMR boot loses its content in deeper than S3 state
- * We must not try IMR boot on next power up (as it will fail).
- *
+ * The memory used for IMR boot loses its content in deeper than S3
+ * state on CAVS platforms.
+ * On ACE platforms due to the system architecture the IMR content is
+ * lost at S3 state already, they are tailored for s2idle use.
+ * We must not try IMR boot on next power up in these cases as it will
+ * fail.
+ */
+ if (sdev->system_suspend_target > SOF_SUSPEND_S3 ||
+ (chip->hw_ip_version >= SOF_INTEL_ACE_1_0 &&
+ sdev->system_suspend_target == SOF_SUSPEND_S3))
+ imr_lost = true;
+
+ /*
* In case of firmware crash or boot failure set the skip_imr_boot to true
* as well in order to try to re-load the firmware to do a 'cold' boot.
*/
- if (sdev->system_suspend_target > SOF_SUSPEND_S3 ||
- sdev->fw_state == SOF_FW_CRASHED ||
+ if (imr_lost || sdev->fw_state == SOF_FW_CRASHED ||
sdev->fw_state == SOF_FW_BOOT_FAILED)
hda->skip_imr_boot = true;
@@ -699,6 +810,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
if (ret < 0)
return ret;
+ /* make sure that no irq handler is pending before shutdown */
+ synchronize_irq(sdev->ipc_irq);
+
hda_codec_jack_wake_enable(sdev, runtime_suspend);
/* power down all hda links */
@@ -757,7 +871,7 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
/* reset and start hda controller */
- ret = hda_dsp_ctrl_init_chip(sdev);
+ ret = hda_dsp_ctrl_init_chip(sdev, false);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to start controller after resume\n");
@@ -835,6 +949,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
return snd_sof_dsp_set_power_state(sdev, &target_state);
}
+EXPORT_SYMBOL_NS(hda_dsp_resume, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
{
@@ -850,6 +965,7 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
return snd_sof_dsp_set_power_state(sdev, &target_state);
}
+EXPORT_SYMBOL_NS(hda_dsp_runtime_resume, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
{
@@ -863,6 +979,7 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_runtime_idle, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
{
@@ -875,6 +992,10 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
if (!sdev->dspless_mode_selected) {
/* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work);
+
+ /* Cancel the microphone privacy work if mic privacy is active */
+ if (hda->mic_privacy.active)
+ cancel_work_sync(&hda->mic_privacy.work);
}
/* stop hda controller and power dsp off */
@@ -884,6 +1005,7 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
return snd_sof_dsp_set_power_state(sdev, &target_state);
}
+EXPORT_SYMBOL_NS(hda_dsp_runtime_suspend, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
@@ -900,6 +1022,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
if (!sdev->dspless_mode_selected) {
/* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work);
+
+ /* Cancel the microphone privacy work if mic privacy is active */
+ if (hda->mic_privacy.active)
+ cancel_work_sync(&hda->mic_privacy.work);
}
if (target_state == SOF_DSP_PM_D0) {
@@ -944,6 +1070,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
}
+EXPORT_SYMBOL_NS(hda_dsp_suspend, "SND_SOC_SOF_INTEL_HDA_COMMON");
static unsigned int hda_dsp_check_for_dma_streams(struct snd_sof_dev *sdev)
{
@@ -1016,12 +1143,14 @@ int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_shutdown_dma_flush, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_shutdown(struct snd_sof_dev *sdev)
{
sdev->system_suspend_target = SOF_SUSPEND_S3;
return snd_sof_suspend(sdev->dev);
}
+EXPORT_SYMBOL_NS(hda_dsp_shutdown, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
@@ -1034,6 +1163,7 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_set_hw_params_upon_resume, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_d0i3_work(struct work_struct *work)
{
@@ -1060,6 +1190,7 @@ void hda_dsp_d0i3_work(struct work_struct *work)
"error: failed to set DSP state %d substate %d\n",
target_state.state, target_state.substate);
}
+EXPORT_SYMBOL_NS(hda_dsp_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
@@ -1100,6 +1231,115 @@ power_down:
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_core_get, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+ struct sof_intel_hda_dev *hdev;
+
+ hdev = sdev->pdata->hw_pdata;
+
+ if (!hdev->sdw)
+ return;
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2,
+ HDA_DSP_REG_ADSPIC2_SNDW,
+ enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
+}
+EXPORT_SYMBOL_NS(hda_common_enable_sdw_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
+{
+ u32 interface_mask = hda_get_interface_mask(sdev);
+ const struct sof_intel_dsp_desc *chip;
+
+ if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
+ return;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->enable_sdw_irq)
+ chip->enable_sdw_irq(sdev, enable);
+}
+EXPORT_SYMBOL_NS(hda_sdw_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hdev;
+ struct sdw_intel_ctx *ctx;
+ u32 caps;
+
+ hdev = sdev->pdata->hw_pdata;
+ ctx = hdev->sdw;
+
+ caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP);
+ caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
+
+ /* Check HW supported vs property value */
+ if (caps < ctx->count) {
+ dev_err(sdev->dev,
+ "%s: BIOS master count %d is larger than hardware capabilities %d\n",
+ __func__, ctx->count, caps);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(hda_sdw_check_lcount_common, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hdev;
+ struct sdw_intel_ctx *ctx;
+ struct hdac_bus *bus;
+ u32 slcount;
+
+ bus = sof_to_bus(sdev);
+
+ hdev = sdev->pdata->hw_pdata;
+ ctx = hdev->sdw;
+
+ slcount = hdac_bus_eml_get_count(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
+
+ /* Check HW supported vs property value */
+ if (slcount < ctx->count) {
+ dev_err(sdev->dev,
+ "%s: BIOS master count %d is larger than hardware capabilities %d\n",
+ __func__, ctx->count, slcount);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(hda_sdw_check_lcount_ext, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->read_sdw_lcount)
+ return chip->read_sdw_lcount(sdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(hda_sdw_check_lcount, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
+{
+ u32 interface_mask = hda_get_interface_mask(sdev);
+ const struct sof_intel_dsp_desc *chip;
+
+ if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
+ return;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->sdw_process_wakeen)
+ chip->sdw_process_wakeen(sdev);
+}
+EXPORT_SYMBOL_NS(hda_sdw_process_wakeen, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+#endif
int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
@@ -1108,3 +1348,288 @@ int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_disable_interrupts, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
+ {HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
+ {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
+ {HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"},
+ {HDA_DSP_ROM_BASE_FW_NOT_FOUND, "error: base fw not found"},
+ {HDA_DSP_ROM_CSE_VALIDATION_FAILED, "error: signature verification failed"},
+ {HDA_DSP_ROM_IPC_FATAL_ERROR, "error: ipc fatal error"},
+ {HDA_DSP_ROM_L2_CACHE_ERROR, "error: L2 cache error"},
+ {HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL, "error: load offset too small"},
+ {HDA_DSP_ROM_API_PTR_INVALID, "error: API ptr invalid"},
+ {HDA_DSP_ROM_BASEFW_INCOMPAT, "error: base fw incompatible"},
+ {HDA_DSP_ROM_UNHANDLED_INTERRUPT, "error: unhandled interrupt"},
+ {HDA_DSP_ROM_MEMORY_HOLE_ECC, "error: ECC memory hole"},
+ {HDA_DSP_ROM_KERNEL_EXCEPTION, "error: kernel exception"},
+ {HDA_DSP_ROM_USER_EXCEPTION, "error: user exception"},
+ {HDA_DSP_ROM_UNEXPECTED_RESET, "error: unexpected reset"},
+ {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"},
+};
+
+#define FSR_ROM_STATE_ENTRY(state) {FSR_STATE_ROM_##state, #state}
+static const struct hda_dsp_msg_code cavs_fsr_rom_state_names[] = {
+ FSR_ROM_STATE_ENTRY(INIT),
+ FSR_ROM_STATE_ENTRY(INIT_DONE),
+ FSR_ROM_STATE_ENTRY(CSE_MANIFEST_LOADED),
+ FSR_ROM_STATE_ENTRY(FW_MANIFEST_LOADED),
+ FSR_ROM_STATE_ENTRY(FW_FW_LOADED),
+ FSR_ROM_STATE_ENTRY(FW_ENTERED),
+ FSR_ROM_STATE_ENTRY(VERIFY_FEATURE_MASK),
+ FSR_ROM_STATE_ENTRY(GET_LOAD_OFFSET),
+ FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT),
+ FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT_DONE),
+ /* CSE states */
+ FSR_ROM_STATE_ENTRY(CSE_IMR_REQUEST),
+ FSR_ROM_STATE_ENTRY(CSE_IMR_GRANTED),
+ FSR_ROM_STATE_ENTRY(CSE_VALIDATE_IMAGE_REQUEST),
+ FSR_ROM_STATE_ENTRY(CSE_IMAGE_VALIDATED),
+ FSR_ROM_STATE_ENTRY(CSE_IPC_IFACE_INIT),
+ FSR_ROM_STATE_ENTRY(CSE_IPC_RESET_PHASE_1),
+ FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL_ENTRY),
+ FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL),
+ FSR_ROM_STATE_ENTRY(CSE_IPC_DOWN),
+};
+
+static const struct hda_dsp_msg_code ace_fsr_rom_state_names[] = {
+ FSR_ROM_STATE_ENTRY(INIT),
+ FSR_ROM_STATE_ENTRY(INIT_DONE),
+ FSR_ROM_STATE_ENTRY(CSE_MANIFEST_LOADED),
+ FSR_ROM_STATE_ENTRY(FW_MANIFEST_LOADED),
+ FSR_ROM_STATE_ENTRY(FW_FW_LOADED),
+ FSR_ROM_STATE_ENTRY(FW_ENTERED),
+ FSR_ROM_STATE_ENTRY(VERIFY_FEATURE_MASK),
+ FSR_ROM_STATE_ENTRY(GET_LOAD_OFFSET),
+ FSR_ROM_STATE_ENTRY(RESET_VECTOR_DONE),
+ FSR_ROM_STATE_ENTRY(PURGE_BOOT),
+ FSR_ROM_STATE_ENTRY(RESTORE_BOOT),
+ FSR_ROM_STATE_ENTRY(FW_ENTRY_POINT),
+ FSR_ROM_STATE_ENTRY(VALIDATE_PUB_KEY),
+ FSR_ROM_STATE_ENTRY(POWER_DOWN_HPSRAM),
+ FSR_ROM_STATE_ENTRY(POWER_DOWN_ULPSRAM),
+ FSR_ROM_STATE_ENTRY(POWER_UP_ULPSRAM_STACK),
+ FSR_ROM_STATE_ENTRY(POWER_UP_HPSRAM_DMA),
+ FSR_ROM_STATE_ENTRY(BEFORE_EP_POINTER_READ),
+ FSR_ROM_STATE_ENTRY(VALIDATE_MANIFEST),
+ FSR_ROM_STATE_ENTRY(VALIDATE_FW_MODULE),
+ FSR_ROM_STATE_ENTRY(PROTECT_IMR_REGION),
+ FSR_ROM_STATE_ENTRY(PUSH_MODEL_ROUTINE),
+ FSR_ROM_STATE_ENTRY(PULL_MODEL_ROUTINE),
+ FSR_ROM_STATE_ENTRY(VALIDATE_PKG_DIR),
+ FSR_ROM_STATE_ENTRY(VALIDATE_CPD),
+ FSR_ROM_STATE_ENTRY(VALIDATE_CSS_MAN_HEADER),
+ FSR_ROM_STATE_ENTRY(VALIDATE_BLOB_SVN),
+ FSR_ROM_STATE_ENTRY(VERIFY_IFWI_PARTITION),
+ FSR_ROM_STATE_ENTRY(REMOVE_ACCESS_CONTROL),
+ FSR_ROM_STATE_ENTRY(AUTH_BYPASS),
+ FSR_ROM_STATE_ENTRY(AUTH_ENABLED),
+ FSR_ROM_STATE_ENTRY(INIT_DMA),
+ FSR_ROM_STATE_ENTRY(PURGE_FW_ENTRY),
+ FSR_ROM_STATE_ENTRY(PURGE_FW_END),
+ FSR_ROM_STATE_ENTRY(CLEAN_UP_BSS_DONE),
+ FSR_ROM_STATE_ENTRY(IMR_RESTORE_ENTRY),
+ FSR_ROM_STATE_ENTRY(IMR_RESTORE_END),
+ FSR_ROM_STATE_ENTRY(FW_MANIFEST_IN_DMA_BUFF),
+ FSR_ROM_STATE_ENTRY(LOAD_CSE_MAN_TO_IMR),
+ FSR_ROM_STATE_ENTRY(LOAD_FW_MAN_TO_IMR),
+ FSR_ROM_STATE_ENTRY(LOAD_FW_CODE_TO_IMR),
+ FSR_ROM_STATE_ENTRY(FW_LOADING_DONE),
+ FSR_ROM_STATE_ENTRY(FW_CODE_LOADED),
+ FSR_ROM_STATE_ENTRY(VERIFY_IMAGE_TYPE),
+ FSR_ROM_STATE_ENTRY(AUTH_API_INIT),
+ FSR_ROM_STATE_ENTRY(AUTH_API_PROC),
+ FSR_ROM_STATE_ENTRY(AUTH_API_FIRST_BUSY),
+ FSR_ROM_STATE_ENTRY(AUTH_API_FIRST_RESULT),
+ FSR_ROM_STATE_ENTRY(AUTH_API_CLEANUP),
+};
+
+#define FSR_BRINGUP_STATE_ENTRY(state) {FSR_STATE_BRINGUP_##state, #state}
+static const struct hda_dsp_msg_code fsr_bringup_state_names[] = {
+ FSR_BRINGUP_STATE_ENTRY(INIT),
+ FSR_BRINGUP_STATE_ENTRY(INIT_DONE),
+ FSR_BRINGUP_STATE_ENTRY(HPSRAM_LOAD),
+ FSR_BRINGUP_STATE_ENTRY(UNPACK_START),
+ FSR_BRINGUP_STATE_ENTRY(IMR_RESTORE),
+ FSR_BRINGUP_STATE_ENTRY(FW_ENTERED),
+};
+
+#define FSR_WAIT_STATE_ENTRY(state) {FSR_WAIT_FOR_##state, #state}
+static const struct hda_dsp_msg_code fsr_wait_state_names[] = {
+ FSR_WAIT_STATE_ENTRY(IPC_BUSY),
+ FSR_WAIT_STATE_ENTRY(IPC_DONE),
+ FSR_WAIT_STATE_ENTRY(CACHE_INVALIDATION),
+ FSR_WAIT_STATE_ENTRY(LP_SRAM_OFF),
+ FSR_WAIT_STATE_ENTRY(DMA_BUFFER_FULL),
+ FSR_WAIT_STATE_ENTRY(CSE_CSR),
+};
+
+#define FSR_MODULE_NAME_ENTRY(mod) [FSR_MOD_##mod] = #mod
+static const char * const fsr_module_names[] = {
+ FSR_MODULE_NAME_ENTRY(ROM),
+ FSR_MODULE_NAME_ENTRY(ROM_BYP),
+ FSR_MODULE_NAME_ENTRY(BASE_FW),
+ FSR_MODULE_NAME_ENTRY(LP_BOOT),
+ FSR_MODULE_NAME_ENTRY(BRNGUP),
+ FSR_MODULE_NAME_ENTRY(ROM_EXT),
+};
+
+static const char *
+hda_dsp_get_state_text(u32 code, const struct hda_dsp_msg_code *msg_code,
+ size_t array_size)
+{
+ int i;
+
+ for (i = 0; i < array_size; i++) {
+ if (code == msg_code[i].code)
+ return msg_code[i].text;
+ }
+
+ return NULL;
+}
+
+void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level)
+{
+ const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
+ const char *state_text, *error_text, *module_text;
+ u32 fsr, state, wait_state, module, error_code;
+
+ fsr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg);
+ state = FSR_TO_STATE_CODE(fsr);
+ wait_state = FSR_TO_WAIT_STATE_CODE(fsr);
+ module = FSR_TO_MODULE_CODE(fsr);
+
+ if (module > FSR_MOD_ROM_EXT)
+ module_text = "unknown";
+ else
+ module_text = fsr_module_names[module];
+
+ if (module == FSR_MOD_BRNGUP) {
+ state_text = hda_dsp_get_state_text(state, fsr_bringup_state_names,
+ ARRAY_SIZE(fsr_bringup_state_names));
+ } else {
+ if (chip->hw_ip_version < SOF_INTEL_ACE_1_0)
+ state_text = hda_dsp_get_state_text(state,
+ cavs_fsr_rom_state_names,
+ ARRAY_SIZE(cavs_fsr_rom_state_names));
+ else
+ state_text = hda_dsp_get_state_text(state,
+ ace_fsr_rom_state_names,
+ ARRAY_SIZE(ace_fsr_rom_state_names));
+ }
+
+ /* not for us, must be generic sof message */
+ if (!state_text) {
+ dev_printk(level, sdev->dev, "%#010x: unknown ROM status value\n", fsr);
+ return;
+ }
+
+ if (wait_state) {
+ const char *wait_state_text;
+
+ wait_state_text = hda_dsp_get_state_text(wait_state, fsr_wait_state_names,
+ ARRAY_SIZE(fsr_wait_state_names));
+ if (!wait_state_text)
+ wait_state_text = "unknown";
+
+ dev_printk(level, sdev->dev,
+ "%#010x: module: %s, state: %s, waiting for: %s, %s\n",
+ fsr, module_text, state_text, wait_state_text,
+ fsr & FSR_HALTED ? "not running" : "running");
+ } else {
+ dev_printk(level, sdev->dev, "%#010x: module: %s, state: %s, %s\n",
+ fsr, module_text, state_text,
+ fsr & FSR_HALTED ? "not running" : "running");
+ }
+
+ error_code = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + 4);
+ if (!error_code)
+ return;
+
+ error_text = hda_dsp_get_state_text(error_code, hda_dsp_rom_fw_error_texts,
+ ARRAY_SIZE(hda_dsp_rom_fw_error_texts));
+ if (!error_text)
+ error_text = "unknown";
+
+ if (state == FSR_STATE_FW_ENTERED)
+ dev_printk(level, sdev->dev, "status code: %#x (%s)\n", error_code,
+ error_text);
+ else
+ dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code,
+ error_text);
+}
+EXPORT_SYMBOL_NS(hda_dsp_get_state, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
+ struct sof_ipc_dsp_oops_xtensa *xoops,
+ struct sof_ipc_panic_info *panic_info,
+ u32 *stack, size_t stack_words)
+{
+ u32 offset = sdev->dsp_oops_offset;
+
+ /* first read registers */
+ sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
+
+ /* note: variable AR register array is not read */
+
+ /* then get panic info */
+ if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
+ dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
+ xoops->arch_hdr.totalsize);
+ return;
+ }
+ offset += xoops->arch_hdr.totalsize;
+ sof_block_read(sdev, sdev->mmio_bar, offset,
+ panic_info, sizeof(*panic_info));
+
+ /* then get the stack */
+ offset += sizeof(*panic_info);
+ sof_block_read(sdev, sdev->mmio_bar, offset, stack,
+ stack_words * sizeof(u32));
+}
+
+/* dump the first 8 dwords representing the extended ROM status */
+void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level,
+ u32 flags)
+{
+ const struct sof_intel_dsp_desc *chip;
+ char msg[128];
+ int len = 0;
+ u32 value;
+ int i;
+
+ chip = get_chip_info(sdev->pdata);
+ for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) {
+ value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + i * 0x4);
+ len += scnprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
+ }
+
+ dev_printk(level, sdev->dev, "extended rom status: %s", msg);
+
+}
+
+void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+{
+ char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
+ struct sof_ipc_dsp_oops_xtensa xoops;
+ struct sof_ipc_panic_info panic_info;
+ u32 stack[HDA_DSP_STACK_DUMP_SIZE];
+
+ /* print ROM/FW status */
+ hda_dsp_get_state(sdev, level);
+
+ /* The firmware register dump only available with IPC3 */
+ if (flags & SOF_DBG_DUMP_REGS && sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
+ u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS);
+ u32 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP);
+
+ hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
+ HDA_DSP_STACK_DUMP_SIZE);
+ sof_print_oops_and_stack(sdev, level, status, panic, &xoops,
+ &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE);
+ } else {
+ hda_dsp_dump_ext_rom_status(sdev, level, flags);
+ }
+}
+EXPORT_SYMBOL_NS(hda_dsp_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index a838dddb1d32..94425c510861 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -15,10 +15,16 @@
* Hardware interface for generic Intel audio DSP HDA IP
*/
+#include <sound/hda_register.h>
#include <sound/sof/ipc4/header.h>
#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "hda.h"
+#include "telemetry.h"
+
+EXPORT_TRACEPOINT_SYMBOL(sof_intel_ipc_firmware_initiated);
+EXPORT_TRACEPOINT_SYMBOL(sof_intel_ipc_firmware_response);
+EXPORT_TRACEPOINT_SYMBOL(sof_intel_hda_irq_ipc_check);
static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev)
{
@@ -66,6 +72,7 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON");
static inline bool hda_dsp_ipc4_pm_msg(u32 primary)
{
@@ -89,9 +96,10 @@ void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev,
if (hda_dsp_ipc4_pm_msg(msg_data->primary))
return;
- mod_delayed_work(system_wq, &hdev->d0i3_work,
+ mod_delayed_work(system_dfl_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_schedule_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
@@ -118,6 +126,7 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
{
@@ -153,6 +162,7 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
snd_sof_ipc_get_reply(sdev);
}
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_get_reply, "SND_SOC_SOF_INTEL_HDA_COMMON");
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
{
@@ -235,6 +245,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON");
/* IPC handler thread */
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
@@ -347,6 +358,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON");
/* Check if an IPC IRQ occurred */
bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
@@ -380,16 +392,19 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
out:
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_check_ipc_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return HDA_DSP_MBOX_UPLINK_OFFSET;
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_get_mailbox_offset, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return SRAM_WINDOW_OFFSET(id);
}
+EXPORT_SYMBOL_NS(hda_dsp_ipc_get_window_offset, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_ipc_msg_data(struct snd_sof_dev *sdev,
struct snd_sof_pcm_stream *sps,
@@ -415,6 +430,7 @@ int hda_ipc_msg_data(struct snd_sof_dev *sdev,
return 0;
}
+EXPORT_SYMBOL_NS(hda_ipc_msg_data, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_set_stream_data_offset(struct snd_sof_dev *sdev,
struct snd_sof_pcm_stream *sps,
@@ -439,3 +455,102 @@ int hda_set_stream_data_offset(struct snd_sof_dev *sdev,
return 0;
}
+EXPORT_SYMBOL_NS(hda_set_stream_data_offset, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+void hda_ipc4_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+{
+ char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
+
+ /* print ROM/FW status */
+ hda_dsp_get_state(sdev, level);
+
+ if (flags & SOF_DBG_DUMP_REGS)
+ sof_ipc4_intel_dump_telemetry_state(sdev, flags);
+ else
+ hda_dsp_dump_ext_rom_status(sdev, level, flags);
+}
+EXPORT_SYMBOL_NS(hda_ipc4_dsp_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->check_ipc_irq)
+ return chip->check_ipc_irq(sdev);
+
+ return false;
+}
+EXPORT_SYMBOL_NS(hda_check_ipc_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
+{
+ u32 adspis;
+ u32 intsts;
+ u32 intctl;
+ u32 ppsts;
+ u8 rirbsts;
+
+ /* read key IRQ stats and config registers */
+ adspis = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
+ intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
+ intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL);
+ ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS);
+ rirbsts = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, AZX_REG_RIRBSTS);
+
+ dev_err(sdev->dev, "hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n",
+ intsts, intctl, rirbsts);
+ dev_err(sdev->dev, "dsp irq ppsts 0x%8.8x adspis 0x%8.8x\n", ppsts, adspis);
+}
+EXPORT_SYMBOL_NS(hda_ipc_irq_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+void hda_ipc_dump(struct snd_sof_dev *sdev)
+{
+ u32 hipcie;
+ u32 hipct;
+ u32 hipcctl;
+
+ hda_ipc_irq_dump(sdev);
+
+ /* read IPC status */
+ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
+ hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
+ hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
+
+ /* dump the IPC regs */
+ /* TODO: parse the raw msg */
+ dev_err(sdev->dev, "host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
+ hipcie, hipct, hipcctl);
+}
+EXPORT_SYMBOL_NS(hda_ipc_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+void hda_ipc4_dump(struct snd_sof_dev *sdev)
+{
+ u32 hipci, hipcie, hipct, hipcte, hipcctl;
+
+ hda_ipc_irq_dump(sdev);
+
+ hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
+ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
+ hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
+ hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE);
+ hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
+
+ /* dump the IPC regs */
+ /* TODO: parse the raw msg */
+ dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n",
+ hipci, hipcie, hipct, hipcte, hipcctl);
+}
+EXPORT_SYMBOL_NS(hda_ipc4_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+ u32 val;
+
+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req);
+
+ return !!(val & chip->ipc_req_mask);
+}
+EXPORT_SYMBOL_NS(hda_ipc4_tx_is_busy, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h
index 8ec5e9f6f8d7..ad9478b8c390 100644
--- a/sound/soc/sof/intel/hda-ipc.h
+++ b/sound/soc/sof/intel/hda-ipc.h
@@ -3,7 +3,7 @@
* 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) 2019 Intel Corporation. All rights reserved.
+ * Copyright(c) 2019 Intel Corporation
*
* Author: Keyon Jie <yang.jie@linux.intel.com>
*/
diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c
index 1e77ca936f80..f38178c904de 100644
--- a/sound/soc/sof/intel/hda-loader-skl.c
+++ b/sound/soc/sof/intel/hda-loader-skl.c
@@ -3,7 +3,7 @@
// 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) 2018-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2022 Intel Corporation
//
#include <linux/delay.h>
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 50ce6b190002..2cc11d8b0f70 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -26,6 +26,11 @@
#include "../sof-priv.h"
#include "hda.h"
+static bool persistent_cl_buffer = true;
+module_param(persistent_cl_buffer, bool, 0444);
+MODULE_PARM_DESC(persistent_cl_buffer, "Persistent Code Loader DMA buffer "
+ "(default = Y, use N to force buffer re-allocation)");
+
static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
@@ -43,13 +48,14 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
}
}
-struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
- unsigned int size, struct snd_dma_buffer *dmab,
- int direction)
+struct hdac_ext_stream*
+hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size,
+ struct snd_dma_buffer *dmab, bool persistent_buffer, int direction,
+ bool is_iccmax)
{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream;
- struct pci_dev *pci = to_pci_dev(sdev->dev);
int ret;
hext_stream = hda_dsp_stream_get(sdev, direction, 0);
@@ -61,18 +67,26 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned
hstream = &hext_stream->hstream;
hstream->substream = NULL;
- /* allocate DMA buffer */
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
- if (ret < 0) {
- dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
- goto out_put;
+ /*
+ * Allocate DMA buffer if it is temporary or if the buffer is intended
+ * to be persistent but not yet allocated.
+ * We cannot rely solely on !dmab->area as caller might use a struct on
+ * stack (when it is temporary) without clearing it to 0.
+ */
+ if (!persistent_buffer || !dmab->area) {
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: memory alloc failed: %d\n",
+ __func__, ret);
+ goto out_put;
+ }
}
hstream->period_bytes = 0;/* initialize period_bytes */
hstream->format_val = format;
hstream->bufsize = size;
- if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+ if (is_iccmax) {
ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL);
if (ret < 0) {
dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
@@ -91,10 +105,15 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned
out_free:
snd_dma_free_pages(dmab);
+ dmab->area = NULL;
+ dmab->bytes = 0;
+ hstream->bufsize = 0;
+ hstream->format_val = 0;
out_put:
hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_NS(hda_cl_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* first boot sequence has some extra steps.
@@ -218,16 +237,22 @@ err:
kfree(dump_msg);
return ret;
}
+EXPORT_SYMBOL_NS(cl_dsp_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
-static int cl_trigger(struct snd_sof_dev *sdev,
- struct hdac_ext_stream *hext_stream, int cmd)
+int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd)
{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
+ struct sof_intel_hda_stream *hda_stream;
/* code loader is special case that reuses stream ops */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
+ hext_stream);
+ reinit_completion(&hda_stream->ioc);
+
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
1 << hstream->index,
1 << hstream->index);
@@ -245,10 +270,12 @@ static int cl_trigger(struct snd_sof_dev *sdev,
return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
}
+EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
-int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
- struct hdac_ext_stream *hext_stream)
+int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream)
{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret = 0;
@@ -270,13 +297,20 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
- snd_dma_free_pages(dmab);
- dmab->area = NULL;
- hstream->bufsize = 0;
- hstream->format_val = 0;
+
+ if (!persistent_buffer) {
+ snd_dma_free_pages(dmab);
+ dmab->area = NULL;
+ dmab->bytes = 0;
+ hstream->bufsize = 0;
+ hstream->format_val = 0;
+ }
return ret;
}
+EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+#define HDA_CL_DMA_IOC_TIMEOUT_MS 500
int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
{
@@ -285,12 +319,16 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
unsigned int reg;
int ret, status;
- ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
+ dev_dbg(sdev->dev, "Code loader DMA starting\n");
+
+ ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(sdev->dev, "error: DMA trigger start failed\n");
return ret;
}
+ dev_dbg(sdev->dev, "waiting for FW_ENTERED status\n");
+
status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
chip->rom_status_reg, reg,
(FSR_TO_STATE_CODE(reg) == FSR_STATE_FW_ENTERED),
@@ -306,13 +344,17 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
dev_err(sdev->dev,
"%s: timeout with rom_status_reg (%#x) read\n",
__func__, chip->rom_status_reg);
+ } else {
+ dev_dbg(sdev->dev, "Code loader FW_ENTERED status\n");
}
- ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
+ ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
if (ret < 0) {
dev_err(sdev->dev, "error: DMA trigger stop failed\n");
if (!status)
status = ret;
+ } else {
+ dev_dbg(sdev->dev, "Code loader DMA stopped\n");
}
return status;
@@ -320,8 +362,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct hdac_ext_stream *iccmax_stream;
- struct snd_dma_buffer dmab_bdl;
int ret, ret1;
u8 original_gb;
@@ -333,8 +375,9 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Prepare capture stream for ICCMAX. We do not need to store
* the data, so use a buffer of PAGE_SIZE for receiving.
*/
- iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
- &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
+ iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
+ &hda->iccmax_dmab, persistent_cl_buffer,
+ SNDRV_PCM_STREAM_CAPTURE, true);
if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
return PTR_ERR(iccmax_stream);
@@ -346,7 +389,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Perform iccmax stream cleanup. This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
- ret1 = hda_cl_cleanup(sdev, &dmab_bdl, iccmax_stream);
+ ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab,
+ persistent_cl_buffer, iccmax_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@@ -361,6 +405,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, "SND_SOC_SOF_INTEL_CNL");
static int hda_dsp_boot_imr(struct snd_sof_dev *sdev)
{
@@ -387,7 +432,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
const struct sof_intel_dsp_desc *chip_info;
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
- struct snd_dma_buffer dmab;
int ret, ret1, i;
if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) {
@@ -411,23 +455,31 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
return -EINVAL;
}
- stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
- stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
-
/* init for booting wait */
init_waitqueue_head(&sdev->boot_wait);
/* prepare DMA for code loader stream */
- hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
- stripped_firmware.size,
- &dmab, SNDRV_PCM_STREAM_PLAYBACK);
+ stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
+ hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
+ stripped_firmware.size,
+ &hda->cl_dmab, persistent_cl_buffer,
+ SNDRV_PCM_STREAM_PLAYBACK, false);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
return PTR_ERR(hext_stream);
}
- memcpy(dmab.area, stripped_firmware.data,
- stripped_firmware.size);
+ /*
+ * Copy the payload to the DMA buffer if it is temporary or if the
+ * buffer is persistent but it does not have the basefw payload either
+ * because this is the first boot and the buffer needs to be initialized,
+ * or a library got loaded and it replaced the basefw.
+ */
+ if (!persistent_cl_buffer || !hda->cl_dmab_contains_basefw) {
+ stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
+ memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size);
+ hda->cl_dmab_contains_basefw = true;
+ }
/* try ROM init a few times before giving up */
for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) {
@@ -493,7 +545,8 @@ cleanup:
* This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
- ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
+ ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab,
+ persistent_cl_buffer, hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@@ -510,56 +563,109 @@ cleanup:
return chip_info->init_core_mask;
/* disable DSP */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
- SOF_HDA_REG_PP_PPCTL,
- SOF_HDA_PPCTL_GPROCEN, 0);
+ hda_dsp_ctrl_ppcap_enable(sdev, false);
+
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
struct sof_ipc4_msg msg = {};
- struct snd_dma_buffer dmab;
int ret, ret1;
- /* IMR booting will restore the libraries as well, skip the loading */
- if (reload && hda->booted_from_imr)
+ /*
+ * if IMR booting is enabled and libraries have been restored during fw
+ * boot, skip the loading
+ */
+ if (reload && hda->booted_from_imr && ipc4_data->libraries_restored)
return 0;
/* the fw_lib has been verified during loading, we can trust the validity here */
stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset;
stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;
+ /*
+ * force re-allocation of the cl_dmab if the preserved DMA buffer is
+ * smaller than what is needed for the library
+ */
+ if (persistent_cl_buffer && stripped_firmware.size > hda->cl_dmab.bytes) {
+ snd_dma_free_pages(&hda->cl_dmab);
+ hda->cl_dmab.area = NULL;
+ hda->cl_dmab.bytes = 0;
+ }
+
/* prepare DMA for code loader stream */
- hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
- stripped_firmware.size,
- &dmab, SNDRV_PCM_STREAM_PLAYBACK);
+ hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
+ stripped_firmware.size,
+ &hda->cl_dmab, persistent_cl_buffer,
+ SNDRV_PCM_STREAM_PLAYBACK, false);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
return PTR_ERR(hext_stream);
}
- memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size);
+ memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size);
+ hda->cl_dmab_contains_basefw = false;
+ /*
+ * 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE
+ * Message includes the dma_id to be prepared for the library loading.
+ * If the firmware does not have support for the message, we will
+ * receive -EOPNOTSUPP. In this case we will use single step library
+ * loading and proceed to send the LOAD_LIBRARY message.
+ */
msg.primary = hext_stream->hstream.stream_tag - 1;
- msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY);
+ msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE);
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
- msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id);
+ ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
+ if (!ret) {
+ int sd_offset = SOF_STREAM_SD_OFFSET(&hext_stream->hstream);
+ unsigned int status;
+
+ /*
+ * Make sure that the FIFOS value is not 0 in SDxFIFOS register
+ * which indicates that the firmware set the GEN bit and we can
+ * continue to start the DMA
+ */
+ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR,
+ sd_offset + SOF_HDA_ADSP_REG_SD_FIFOSIZE,
+ status,
+ status & SOF_HDA_SD_FIFOSIZE_FIFOS_MASK,
+ HDA_DSP_REG_POLL_INTERVAL_US,
+ HDA_DSP_BASEFW_TIMEOUT_US);
+
+ if (ret < 0)
+ dev_warn(sdev->dev,
+ "%s: timeout waiting for FIFOS\n", __func__);
+ } else if (ret != -EOPNOTSUPP) {
+ goto cleanup;
+ }
- ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START);
+ ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);
goto cleanup;
}
+ /*
+ * 2nd stage: LOAD_LIBRARY
+ * Message includes the dma_id and the lib_id, the dma_id must be
+ * identical to the one sent via LOAD_LIBRARY_PREPARE
+ */
+ msg.primary &= ~SOF_IPC4_MSG_TYPE_MASK;
+ msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY);
+ msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id);
ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
- ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
+ /* Stop the DMA channel */
+ ret1 = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);
if (!ret)
@@ -568,7 +674,8 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
cleanup:
/* clean up even in case of error and return the first error */
- ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
+ ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer,
+ hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
@@ -579,41 +686,7 @@ cleanup:
return ret;
}
-
-/* pre fw run operations */
-int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
-{
- /* disable clock gating and power gating */
- return hda_dsp_ctrl_clock_power_gating(sdev, false);
-}
-
-/* post fw run operations */
-int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
-{
- int ret;
-
- if (sdev->first_boot) {
- struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
-
- ret = hda_sdw_startup(sdev);
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: could not startup SoundWire links\n");
- return ret;
- }
-
- /* Check if IMR boot is usable */
- if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) &&
- (sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT ||
- sdev->pdata->ipc_type == SOF_INTEL_IPC4))
- hdev->imrboot_supported = true;
- }
-
- hda_sdw_int_enable(sdev, true);
-
- /* re-enable clock gating and power gating */
- return hda_dsp_ctrl_clock_power_gating(sdev, true);
-}
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
@@ -652,3 +725,4 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index b7cbf66badf5..ce561fe52bd5 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -3,7 +3,7 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
/*
@@ -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
@@ -331,14 +342,19 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask)
return !!(val & cmdsync_mask);
}
-static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num)
+static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid)
{
- u32 val;
+ return readw(lsdiid);
+}
+
+static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num)
+{
+ u16 val;
- val = readl(lsdiid);
+ val = readw(lsdiid);
val |= BIT(dev_num);
- writel(val, lsdiid);
+ writew(val, lsdiid);
}
static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan,
@@ -429,7 +445,7 @@ int hda_bus_ml_init(struct hdac_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_NS(hda_bus_ml_init, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_init, "SND_SOC_SOF_HDA_MLINK");
void hda_bus_ml_free(struct hdac_bus *bus)
{
@@ -447,7 +463,7 @@ void hda_bus_ml_free(struct hdac_bus *bus)
kfree(h2link);
}
}
-EXPORT_SYMBOL_NS(hda_bus_ml_free, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_free, "SND_SOC_SOF_HDA_MLINK");
static struct hdac_ext2_link *
find_ext2_link(struct hdac_bus *bus, bool alt, int elid)
@@ -474,7 +490,25 @@ int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid)
return h2link->slcount;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, "SND_SOC_SOF_HDA_MLINK");
+
+void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable)
+{
+ struct hdac_ext2_link *h2link;
+ struct hdac_ext_link *hlink;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return;
+
+ if (!h2link->intc)
+ return;
+
+ hlink = &h2link->hext_link;
+
+ hdaml_link_enable_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL, enable);
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt_unlocked, "SND_SOC_SOF_HDA_MLINK");
void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable)
{
@@ -496,7 +530,7 @@ void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, boo
mutex_unlock(&h2link->eml_lock);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, "SND_SOC_SOF_HDA_MLINK");
bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid)
{
@@ -514,7 +548,7 @@ bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid)
return hdaml_link_check_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid, u32 syncprd)
{
@@ -534,13 +568,13 @@ int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid,
return 0;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_set_syncprd_unlocked(struct hdac_bus *bus, u32 syncprd)
{
return hdac_bus_eml_set_syncprd_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, syncprd);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid)
{
@@ -558,13 +592,13 @@ int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid)
return hdaml_link_wait_syncpu(hlink->ml_addr + AZX_REG_ML_LSYNC);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_wait_syncpu_unlocked(struct hdac_bus *bus)
{
return hdac_bus_eml_wait_syncpu_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, "SND_SOC_SOF_HDA_MLINK");
void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
@@ -582,13 +616,13 @@ void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, in
hdaml_link_sync_arm(hlink->ml_addr + AZX_REG_ML_LSYNC, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, "SND_SOC_SOF_HDA_MLINK");
void hdac_bus_eml_sdw_sync_arm_unlocked(struct hdac_bus *bus, int sublink)
{
hdac_bus_eml_sync_arm_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid)
{
@@ -608,13 +642,13 @@ int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid)
return 0;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_sync_go_unlocked(struct hdac_bus *bus)
{
return hdac_bus_eml_sync_go_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, "SND_SOC_SOF_HDA_MLINK");
bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int elid)
{
@@ -637,13 +671,13 @@ bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int eli
return hdaml_link_check_cmdsync(hlink->ml_addr + AZX_REG_ML_LSYNC,
cmdsync_mask);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, "SND_SOC_SOF_HDA_MLINK");
bool hdac_bus_eml_sdw_check_cmdsync_unlocked(struct hdac_bus *bus)
{
return hdac_bus_eml_check_cmdsync_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, "SND_SOC_SOF_HDA_MLINK");
static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid, int sublink,
bool eml_lock)
@@ -673,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)
@@ -685,13 +733,13 @@ int hdac_bus_eml_power_up(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, true);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_power_up_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, false);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, "SND_SOC_SOF_HDA_MLINK");
static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid, int sublink,
bool eml_lock)
@@ -719,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:
@@ -732,25 +790,41 @@ int hdac_bus_eml_power_down(struct hdac_bus *bus, bool alt, int elid, int sublin
{
return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, true);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, false);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink)
{
return hdac_bus_eml_power_up_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink)
{
return hdac_bus_eml_power_down_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, "SND_SOC_SOF_HDA_MLINK");
+
+int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid)
+{
+ struct hdac_ext2_link *h2link;
+ struct hdac_ext_link *hlink;
+
+ h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
+ if (!h2link)
+ return -ENODEV;
+
+ hlink = &h2link->hext_link;
+
+ *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink));
+
+ return 0;
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
{
@@ -770,7 +844,7 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
mutex_unlock(&h2link->eml_lock);
return 0;
-} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, SND_SOC_SOF_HDA_MLINK);
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, "SND_SOC_SOF_HDA_MLINK");
/*
* the 'y' parameter comes from the PCMSyCM hardware register naming. 'y' refers to the
@@ -781,6 +855,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
{
struct hdac_ext2_link *h2link;
u16 __iomem *pcmsycm;
+ int hchan;
+ int lchan;
u16 val;
h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
@@ -791,20 +867,28 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
h2link->instance_offset * sublink +
AZX_REG_SDW_SHIM_PCMSyCM(y);
+ if (channel_mask) {
+ hchan = __fls(channel_mask);
+ lchan = __ffs(channel_mask);
+ } else {
+ hchan = 0;
+ lchan = 0;
+ }
+
mutex_lock(&h2link->eml_lock);
- hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask),
+ hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan,
stream_id, dir);
mutex_unlock(&h2link->eml_lock);
val = readw(pcmsycm);
- dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
- channel_mask, stream_id, dir, val);
+ dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
+ sublink, channel_mask, stream_id, dir, val);
return 0;
-} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK");
void hda_bus_ml_put_all(struct hdac_bus *bus)
{
@@ -817,7 +901,7 @@ void hda_bus_ml_put_all(struct hdac_bus *bus)
snd_hdac_ext_bus_link_put(bus, hlink);
}
}
-EXPORT_SYMBOL_NS(hda_bus_ml_put_all, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK");
void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
{
@@ -827,7 +911,7 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
list_for_each_entry(hlink, &bus->hlink_list, list)
writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
}
-EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK");
int hda_bus_ml_resume(struct hdac_bus *bus)
{
@@ -846,7 +930,7 @@ int hda_bus_ml_resume(struct hdac_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_NS(hda_bus_ml_resume, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_resume, "SND_SOC_SOF_HDA_MLINK");
int hda_bus_ml_suspend(struct hdac_bus *bus)
{
@@ -864,7 +948,7 @@ int hda_bus_ml_suspend(struct hdac_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_NS(hda_bus_ml_suspend, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_suspend, "SND_SOC_SOF_HDA_MLINK");
struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid)
{
@@ -876,7 +960,7 @@ struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid)
return &h2link->eml_lock;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, "SND_SOC_SOF_HDA_MLINK");
struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus)
{
@@ -888,7 +972,7 @@ struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus)
return &h2link->hext_link;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, "SND_SOC_SOF_HDA_MLINK");
struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus)
{
@@ -900,7 +984,7 @@ struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus)
return &h2link->hext_link;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, "SND_SOC_SOF_HDA_MLINK");
struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus)
{
@@ -912,7 +996,7 @@ struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus)
return &h2link->hext_link;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable)
{
@@ -936,8 +1020,101 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e
return 0;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, SND_SOC_SOF_HDA_MLINK);
+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");
+MODULE_DESCRIPTION("SOF support for HDaudio multi-link");
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index f23c72cdff48..da6c1e7263cd 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -29,6 +29,8 @@
#define SDnFMT_BITS(x) ((x) << 4)
#define SDnFMT_CHAN(x) ((x) << 0)
+#define HDA_MAX_PERIOD_TIME_HEADROOM 10
+
static bool hda_always_enable_dmi_l1;
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
@@ -37,6 +39,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) {
@@ -142,6 +149,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");
/* update SPIB register with appl position */
int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
@@ -164,6 +172,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_pcm_ack, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream, int cmd)
@@ -173,11 +182,12 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
+EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *scomp = sdev->component;
struct hdac_stream *hstream = substream->runtime->private_data;
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
@@ -204,11 +214,12 @@ found:
trace_sof_intel_hda_dsp_pcm(sdev, hstream, substream, pos);
return pos;
}
+EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_component *scomp = sdev->component;
struct hdac_ext_stream *dsp_stream;
@@ -236,6 +247,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)
@@ -254,15 +275,62 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
+ /* Limit the maximum number of periods to not exceed the BDL entries count */
+ if (runtime->hw.periods_max > HDA_DSP_MAX_BDL_ENTRIES)
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
+ runtime->hw.periods_min,
+ HDA_DSP_MAX_BDL_ENTRIES);
+
/* Only S16 and S32 supported by HDA hardware when used without DSP */
if (sdev->dspless_mode_selected)
snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32);
+ /*
+ * The dsp_max_burst_size_in_ms is the length of the maximum burst size
+ * of the host DMA in the ALSA buffer.
+ *
+ * On playback start the DMA will transfer dsp_max_burst_size_in_ms
+ * amount of data in one initial burst to fill up the host DMA buffer.
+ * Consequent DMA burst sizes are shorter and their length can vary.
+ * To avoid immediate xrun by the initial burst we need to place
+ * constraint on the period size (via PERIOD_TIME) to cover the size of
+ * the host buffer.
+ * We need to add headroom of max 10ms as the firmware needs time to
+ * settle to the 1ms pacing and initially it can run faster for few
+ * internal periods.
+ *
+ * On capture the DMA will transfer 1ms chunks.
+ */
+ if (spcm->stream[direction].dsp_max_burst_size_in_ms) {
+ unsigned int period_time = spcm->stream[direction].dsp_max_burst_size_in_ms;
+
+ /*
+ * add headroom over the maximum burst size to cover the time
+ * needed for the DMA pace to settle.
+ * Limit the headroom time to HDA_MAX_PERIOD_TIME_HEADROOM
+ */
+ period_time += min(period_time, HDA_MAX_PERIOD_TIME_HEADROOM);
+
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ period_time * USEC_PER_MSEC,
+ UINT_MAX);
+ }
+
/* binding pcm substream to hda stream */
substream->runtime->private_data = &dsp_stream->hstream;
+
+ /*
+ * Reset the llp cache values (they are used for LLP compensation in
+ * case the counter is not reset)
+ */
+ dsp_stream->pplcllpl = 0;
+ dsp_stream->pplcllpu = 0;
+
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_pcm_open, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
@@ -282,3 +350,4 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
substream->runtime->private_data = NULL;
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_pcm_close, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c
index 56a533c63cb0..b06933cebc45 100644
--- a/sound/soc/sof/intel/hda-probes.c
+++ b/sound/soc/sof/intel/hda-probes.c
@@ -3,7 +3,7 @@
// 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) 2019-2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2019-2021 Intel Corporation
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
// Converted to SOF client:
@@ -112,7 +112,7 @@ static int hda_probes_compr_trigger(struct sof_client_dev *cdev,
static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp,
+ struct snd_compr_tstamp64 *tstamp,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
@@ -139,10 +139,12 @@ int hda_probes_register(struct snd_sof_dev *sdev)
return sof_client_dev_register(sdev, "hda-probes", 0, &hda_probes_ops,
sizeof(hda_probes_ops));
}
+EXPORT_SYMBOL_NS(hda_probes_register, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_probes_unregister(struct snd_sof_dev *sdev)
{
sof_client_dev_unregister(sdev, "hda-probes", 0);
}
+EXPORT_SYMBOL_NS(hda_probes_unregister, "SND_SOC_SOF_INTEL_HDA_COMMON");
-MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
+MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT");
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
new file mode 100644
index 000000000000..ff5abccf0d88
--- /dev/null
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -0,0 +1,445 @@
+// 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.
+//
+
+/*
+ * Hardware interface for SoundWire BPT support with HDA DMA
+ */
+
+#include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
+#include <sound/hda-sdw-bpt.h>
+#include <sound/sof.h>
+#include <sound/sof/ipc4/header.h>
+#include "../ops.h"
+#include "../sof-priv.h"
+#include "../ipc4-priv.h"
+#include "hda.h"
+
+#define BPT_FREQUENCY 192000 /* The max rate defined in rate_bits[] hdac_device.c */
+#define BPT_MULTIPLIER ((BPT_FREQUENCY / 48000) - 1)
+#define BPT_CHAIN_DMA_FIFO_MS 10
+/*
+ * This routine is directly inspired by sof_ipc4_chain_dma_trigger(),
+ * with major simplifications since there are no pipelines defined
+ * and no dependency on ALSA hw_params
+ */
+static int chain_dma_trigger(struct snd_sof_dev *sdev, unsigned int stream_tag,
+ int direction, int state)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ bool allocate, enable, set_fifo_size;
+ struct sof_ipc4_msg msg = {{ 0 }};
+ int dma_id;
+
+ if (sdev->pdata->ipc_type != SOF_IPC_TYPE_4)
+ return -EOPNOTSUPP;
+
+ switch (state) {
+ case SOF_IPC4_PIPE_RUNNING: /* Allocate and start the chain */
+ allocate = true;
+ enable = true;
+ set_fifo_size = true;
+ break;
+ case SOF_IPC4_PIPE_PAUSED: /* Stop the chain */
+ allocate = true;
+ enable = false;
+ set_fifo_size = false;
+ break;
+ case SOF_IPC4_PIPE_RESET: /* Deallocate chain resources and remove the chain */
+ allocate = false;
+ enable = false;
+ set_fifo_size = false;
+ break;
+ default:
+ dev_err(sdev->dev, "Unexpected state %d", state);
+ return -EINVAL;
+ }
+
+ msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+ /* for BPT/BRA we can use the same stream tag for host and link */
+ dma_id = stream_tag - 1;
+ if (direction == SNDRV_PCM_STREAM_CAPTURE)
+ dma_id += ipc4_data->num_playback_streams;
+
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(dma_id);
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(dma_id);
+
+ /* For BPT/BRA we use 32 bits so SCS is not set */
+
+ /* CHAIN DMA needs at least 2ms */
+ if (set_fifo_size)
+ msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(BPT_FREQUENCY / 1000 *
+ BPT_CHAIN_DMA_FIFO_MS *
+ sizeof(u32));
+
+ if (allocate)
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK;
+
+ if (enable)
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK;
+
+ return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
+}
+
+static int hda_sdw_bpt_dma_prepare(struct device *dev, struct hdac_ext_stream **sdw_bpt_stream,
+ struct snd_dma_buffer *dmab_bdl, u32 bpt_num_bytes,
+ unsigned int num_channels, int direction)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct hdac_ext_stream *bpt_stream;
+ unsigned int format = HDA_CL_STREAM_FORMAT;
+
+ /*
+ * the baseline format needs to be adjusted to
+ * bandwidth requirements
+ */
+ format |= (num_channels - 1);
+ format |= BPT_MULTIPLIER << AC_FMT_MULT_SHIFT;
+
+ dev_dbg(dev, "direction %d format_val %#x\n", direction, format);
+
+ bpt_stream = hda_cl_prepare(dev, format, bpt_num_bytes, dmab_bdl, false, direction, false);
+ if (IS_ERR(bpt_stream)) {
+ dev_err(sdev->dev, "%s: SDW BPT DMA prepare failed: dir %d\n",
+ __func__, direction);
+ return PTR_ERR(bpt_stream);
+ }
+ *sdw_bpt_stream = bpt_stream;
+
+ if (!sdev->dspless_mode_selected) {
+ struct hdac_stream *hstream;
+ u32 mask;
+
+ /* decouple host and link DMA if the DSP is used */
+ hstream = &bpt_stream->hstream;
+ mask = BIT(hstream->index);
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, mask);
+
+ snd_hdac_ext_stream_reset(bpt_stream);
+
+ snd_hdac_ext_stream_setup(bpt_stream, format);
+ }
+
+ if (hdac_stream(bpt_stream)->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct hdac_ext_link *hlink;
+ int stream_tag;
+
+ stream_tag = hdac_stream(bpt_stream)->stream_tag;
+ hlink = hdac_bus_eml_sdw_get_hlink(bus);
+
+ snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
+ }
+ return 0;
+}
+
+static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream *sdw_bpt_stream,
+ struct snd_dma_buffer *dmab_bdl)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct hdac_stream *hstream;
+ u32 mask;
+ int ret;
+
+ ret = hda_cl_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n",
+ __func__);
+ return ret;
+ }
+
+ if (hdac_stream(sdw_bpt_stream)->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct hdac_ext_link *hlink;
+ int stream_tag;
+
+ stream_tag = hdac_stream(sdw_bpt_stream)->stream_tag;
+ hlink = hdac_bus_eml_sdw_get_hlink(bus);
+
+ snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
+ }
+
+ if (!sdev->dspless_mode_selected) {
+ /* Release CHAIN_DMA resources */
+ ret = chain_dma_trigger(sdev, hdac_stream(sdw_bpt_stream)->stream_tag,
+ hdac_stream(sdw_bpt_stream)->direction,
+ SOF_IPC4_PIPE_RESET);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: chain_dma_trigger PIPE_RESET failed: %d\n",
+ __func__, ret);
+
+ /* couple host and link DMA */
+ hstream = &sdw_bpt_stream->hstream;
+ mask = BIT(hstream->index);
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, 0);
+ }
+
+ return 0;
+}
+
+static int hda_sdw_bpt_dma_enable(struct device *dev, struct hdac_ext_stream *sdw_bpt_stream)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = hda_cl_trigger(sdev->dev, sdw_bpt_stream, SNDRV_PCM_TRIGGER_START);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: SDW BPT DMA trigger start failed\n", __func__);
+
+ if (!sdev->dspless_mode_selected) {
+ /* the chain DMA needs to be programmed before the DMAs */
+ ret = chain_dma_trigger(sdev, hdac_stream(sdw_bpt_stream)->stream_tag,
+ hdac_stream(sdw_bpt_stream)->direction,
+ SOF_IPC4_PIPE_RUNNING);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: chain_dma_trigger failed: %d\n",
+ __func__, ret);
+ hda_cl_trigger(sdev->dev, sdw_bpt_stream, SNDRV_PCM_TRIGGER_STOP);
+ return ret;
+ }
+ snd_hdac_ext_stream_start(sdw_bpt_stream);
+ }
+
+ return ret;
+}
+
+static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *sdw_bpt_stream)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ int ret;
+
+ if (!sdev->dspless_mode_selected) {
+ snd_hdac_ext_stream_clear(sdw_bpt_stream);
+
+ ret = chain_dma_trigger(sdev, hdac_stream(sdw_bpt_stream)->stream_tag,
+ hdac_stream(sdw_bpt_stream)->direction,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: chain_dma_trigger PIPE_PAUSED failed: %d\n",
+ __func__, ret);
+ }
+
+ ret = hda_cl_trigger(sdev->dev, sdw_bpt_stream, SNDRV_PCM_TRIGGER_STOP);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: SDW BPT DMA trigger stop failed\n", __func__);
+
+ return ret;
+}
+
+int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **bpt_tx_stream,
+ struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes,
+ u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream,
+ struct snd_dma_buffer *dmab_rx_bdl, u32 bpt_rx_num_bytes,
+ u32 rx_dma_bandwidth)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ unsigned int num_channels_tx;
+ unsigned int num_channels_rx;
+ int ret1;
+ int ret;
+
+ num_channels_tx = DIV_ROUND_UP(tx_dma_bandwidth, BPT_FREQUENCY * 32);
+
+ ret = hda_sdw_bpt_dma_prepare(dev, bpt_tx_stream, dmab_tx_bdl, bpt_tx_num_bytes,
+ num_channels_tx, SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_prepare failed for TX: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ num_channels_rx = DIV_ROUND_UP(rx_dma_bandwidth, BPT_FREQUENCY * 32);
+
+ ret = hda_sdw_bpt_dma_prepare(dev, bpt_rx_stream, dmab_rx_bdl, bpt_rx_num_bytes,
+ num_channels_rx, SNDRV_PCM_STREAM_CAPTURE);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_prepare failed for RX: %d\n",
+ __func__, ret);
+
+ ret1 = hda_sdw_bpt_dma_deprepare(dev, *bpt_tx_stream, dmab_tx_bdl);
+ if (ret1 < 0)
+ dev_err(dev, "%s: hda_sdw_bpt_dma_deprepare failed for TX: %d\n",
+ __func__, ret1);
+ return ret;
+ }
+
+ /* we need to map the channels in PCMSyCM registers */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id,
+ 0, /* cpu_dai->id -> PDI0 */
+ GENMASK(num_channels_tx - 1, 0),
+ hdac_stream(*bpt_tx_stream)->stream_tag,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret < 0) {
+ dev_err(dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed for TX: %d\n",
+ __func__, ret);
+ goto close;
+ }
+
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id,
+ 1, /* cpu_dai->id -> PDI1 */
+ GENMASK(num_channels_rx - 1, 0),
+ hdac_stream(*bpt_rx_stream)->stream_tag,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (!ret)
+ return 0;
+
+ dev_err(dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed for RX: %d\n",
+ __func__, ret);
+
+close:
+ ret1 = hda_sdw_bpt_close(dev, *bpt_tx_stream, dmab_tx_bdl, *bpt_rx_stream, dmab_rx_bdl);
+ if (ret1 < 0)
+ dev_err(dev, "%s: hda_sdw_bpt_close failed: %d\n",
+ __func__, ret1);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_open, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+int hda_sdw_bpt_send_async(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
+ struct hdac_ext_stream *bpt_rx_stream)
+{
+ int ret1;
+ int ret;
+
+ ret = hda_sdw_bpt_dma_enable(dev, bpt_tx_stream);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_enable failed for TX: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = hda_sdw_bpt_dma_enable(dev, bpt_rx_stream);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_enable failed for RX: %d\n",
+ __func__, ret);
+
+ ret1 = hda_sdw_bpt_dma_disable(dev, bpt_tx_stream);
+ if (ret1 < 0)
+ dev_err(dev, "%s: hda_sdw_bpt_dma_disable failed for TX: %d\n",
+ __func__, ret1);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_send_async, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+/*
+ * 3s is several orders of magnitude larger than what is needed for a
+ * typical firmware download.
+ */
+#define HDA_BPT_IOC_TIMEOUT_MS 3000
+
+int hda_sdw_bpt_wait(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
+ struct hdac_ext_stream *bpt_rx_stream)
+{
+ struct sof_intel_hda_stream *hda_tx_stream;
+ struct sof_intel_hda_stream *hda_rx_stream;
+ snd_pcm_uframes_t tx_position;
+ snd_pcm_uframes_t rx_position;
+ unsigned long time_tx_left;
+ unsigned long time_rx_left;
+ int ret = 0;
+ int ret1;
+ int i;
+
+ hda_tx_stream = container_of(bpt_tx_stream, struct sof_intel_hda_stream, hext_stream);
+ hda_rx_stream = container_of(bpt_rx_stream, struct sof_intel_hda_stream, hext_stream);
+
+ time_tx_left = wait_for_completion_timeout(&hda_tx_stream->ioc,
+ msecs_to_jiffies(HDA_BPT_IOC_TIMEOUT_MS));
+ if (!time_tx_left) {
+ tx_position = hda_dsp_stream_get_position(hdac_stream(bpt_tx_stream),
+ SNDRV_PCM_STREAM_PLAYBACK, false);
+ dev_err(dev, "%s: SDW BPT TX DMA did not complete: %ld\n",
+ __func__, tx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+ /* Make sure the DMA is flushed */
+ i = 0;
+ do {
+ tx_position = hda_dsp_stream_get_position(hdac_stream(bpt_tx_stream),
+ SNDRV_PCM_STREAM_PLAYBACK, false);
+ usleep_range(1000, 1010);
+ i++;
+ } while (tx_position && i < HDA_BPT_IOC_TIMEOUT_MS);
+ if (tx_position) {
+ dev_err(dev, "%s: SDW BPT TX DMA position %ld was not cleared\n",
+ __func__, tx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+ /* the wait should be minimal here */
+ time_rx_left = wait_for_completion_timeout(&hda_rx_stream->ioc,
+ msecs_to_jiffies(HDA_BPT_IOC_TIMEOUT_MS));
+ if (!time_rx_left) {
+ rx_position = hda_dsp_stream_get_position(hdac_stream(bpt_rx_stream),
+ SNDRV_PCM_STREAM_CAPTURE, false);
+ dev_err(dev, "%s: SDW BPT RX DMA did not complete: %ld\n",
+ __func__, rx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+ /* Make sure the DMA is flushed */
+ i = 0;
+ do {
+ rx_position = hda_dsp_stream_get_position(hdac_stream(bpt_rx_stream),
+ SNDRV_PCM_STREAM_CAPTURE, false);
+ usleep_range(1000, 1010);
+ i++;
+ } while (rx_position && i < HDA_BPT_IOC_TIMEOUT_MS);
+ if (rx_position) {
+ dev_err(dev, "%s: SDW BPT RX DMA position %ld was not cleared\n",
+ __func__, rx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+dma_disable:
+ ret1 = hda_sdw_bpt_dma_disable(dev, bpt_rx_stream);
+ if (!ret)
+ ret = ret1;
+
+ ret1 = hda_sdw_bpt_dma_disable(dev, bpt_tx_stream);
+ if (!ret)
+ ret = ret1;
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_wait, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
+ struct snd_dma_buffer *dmab_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
+ struct snd_dma_buffer *dmab_rx_bdl)
+{
+ int ret;
+ int ret1;
+
+ ret = hda_sdw_bpt_dma_deprepare(dev, bpt_rx_stream, dmab_rx_bdl);
+
+ ret1 = hda_sdw_bpt_dma_deprepare(dev, bpt_tx_stream, dmab_tx_bdl);
+ if (!ret)
+ ret = ret1;
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_close, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF helpers for HDaudio SoundWire BPT");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index b13acb959653..9c3b3a9aaf83 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -21,8 +21,14 @@
#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "../sof-audio.h"
+#include "../ipc4-priv.h"
#include "hda.h"
+int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS;
+module_param_named(position_quirk, sof_hda_position_quirk, int, 0444);
+MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk");
+EXPORT_SYMBOL_NS(sof_hda_position_quirk, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
#define HDA_LTRP_GB_VALUE_US 95
static inline const char *hda_hstream_direction_str(struct hdac_stream *hstream)
@@ -38,7 +44,7 @@ static char *hda_hstream_dbg_get_stream_info_str(struct hdac_stream *hstream)
struct snd_soc_pcm_runtime *rtd;
if (hstream->substream)
- rtd = asoc_substream_to_rtd(hstream->substream);
+ rtd = snd_soc_substream_to_rtd(hstream->substream);
else if (hstream->cstream)
rtd = hstream->cstream->private_data;
else
@@ -113,13 +119,39 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
int remain, ioc;
period_bytes = hstream->period_bytes;
- dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes);
- if (!period_bytes)
+ dev_dbg(sdev->dev, "period_bytes: %#x, bufsize: %#x\n", period_bytes,
+ hstream->bufsize);
+
+ if (!period_bytes) {
+ unsigned int chunk_size;
+
+ chunk_size = snd_sgbuf_get_chunk_size(dmab, 0, hstream->bufsize);
+
period_bytes = hstream->bufsize;
+ /*
+ * HDA spec demands that the LVI value must be at least one
+ * before the DMA operation can begin. This means that there
+ * must be at least two BDLE present for the transfer.
+ *
+ * If the buffer is not a single continuous area then the
+ * hda_setup_bdle() will create multiple BDLEs for each segment.
+ * If the memory is a single continuous area, force it to be
+ * split into two 'periods', otherwise the transfer will be
+ * split to multiple BDLE for each chunk in hda_setup_bdle()
+ *
+ * Note: period_bytes == 0 can only happen for firmware or
+ * library loading. The data size is 4K aligned, which ensures
+ * that the second chunk's start address will be 128-byte
+ * aligned.
+ */
+ if (chunk_size == hstream->bufsize)
+ period_bytes /= 2;
+ }
+
periods = hstream->bufsize / period_bytes;
- dev_dbg(sdev->dev, "periods:%d\n", periods);
+ dev_dbg(sdev->dev, "periods: %d\n", periods);
remain = hstream->bufsize % period_bytes;
if (remain)
@@ -210,9 +242,7 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags)
/* stream found ? */
if (!hext_stream) {
- dev_err(sdev->dev, "error: no free %s streams\n",
- direction == SNDRV_PCM_STREAM_PLAYBACK ?
- "playback" : "capture");
+ dev_err(sdev->dev, "error: no free %s streams\n", snd_pcm_direction_name(direction));
return hext_stream;
}
@@ -668,7 +698,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
sd_offset +
SOF_HDA_ADSP_REG_SD_FIFOSIZE);
- hstream->fifo_size &= 0xffff;
+ hstream->fifo_size &= SOF_HDA_SD_FIFOSIZE_FIFOS_MASK;
hstream->fifo_size += 1;
} else {
hstream->fifo_size = 0;
@@ -708,6 +738,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
{
@@ -730,6 +761,7 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
static void
hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
@@ -764,12 +796,27 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS);
active = true;
- if ((!s->substream && !s->cstream) ||
- !s->running ||
- (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
+ if (!s->running)
+ continue;
+ if ((sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
+ continue;
+ if (!s->substream && !s->cstream) {
+ /*
+ * when no substream is found, the DMA may used for code loading
+ * or data transfers which can rely on wait_for_completion()
+ */
+ struct sof_intel_hda_stream *hda_stream;
+ struct hdac_ext_stream *hext_stream;
+
+ hext_stream = stream_to_hdac_ext_stream(s);
+ hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
+ hext_stream);
+
+ complete(&hda_stream->ioc);
continue;
+ }
- /* Inform ALSA only in case not do that with IPC */
+ /* Inform ALSA only if the IPC position is not used */
if (s->substream && sof_hda->no_ipc_position) {
snd_sof_pcm_period_elapsed(s->substream);
} else if (s->cstream) {
@@ -811,6 +858,7 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_stream_init(struct snd_sof_dev *sdev)
{
@@ -842,7 +890,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
if (num_capture >= SOF_HDA_CAPTURE_STREAMS) {
dev_err(sdev->dev, "error: too many capture streams %d\n",
- num_playback);
+ num_capture);
return -EINVAL;
}
@@ -869,8 +917,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return -ENOMEM;
}
- /* create capture streams */
- for (i = 0; i < num_capture; i++) {
+ /* create capture and playback streams */
+ for (i = 0; i < num_total; i++) {
struct sof_intel_hda_stream *hda_stream;
hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
@@ -879,6 +927,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return -ENOMEM;
hda_stream->sdev = sdev;
+ init_completion(&hda_stream->ioc);
hext_stream = &hda_stream->hext_stream;
@@ -909,69 +958,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
hstream->index = i;
sd_offset = SOF_STREAM_SD_OFFSET(hstream);
hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
- hstream->stream_tag = i + 1;
hstream->opened = false;
hstream->running = false;
- hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
-
- /* memory alloc for stream BDL */
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
- HDA_DSP_BDL_SIZE, &hstream->bdl);
- if (ret < 0) {
- dev_err(sdev->dev, "error: stream bdl dma alloc failed\n");
- return -ENOMEM;
- }
- hstream->posbuf = (__le32 *)(bus->posbuf.area +
- (hstream->index) * 8);
-
- list_add_tail(&hstream->list, &bus->stream_list);
- }
-
- /* create playback streams */
- for (i = num_capture; i < num_total; i++) {
- struct sof_intel_hda_stream *hda_stream;
-
- hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
- GFP_KERNEL);
- if (!hda_stream)
- return -ENOMEM;
-
- hda_stream->sdev = sdev;
-
- hext_stream = &hda_stream->hext_stream;
-
- if (sdev->bar[HDA_DSP_PP_BAR]) {
- hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
- SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
-
- hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
- SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
- SOF_HDA_PPLC_INTERVAL * i;
- }
-
- hstream = &hext_stream->hstream;
-
- /* do we support SPIB */
- if (sdev->bar[HDA_DSP_SPIB_BAR]) {
- hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
- SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
- SOF_HDA_SPIB_SPIB;
- hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
- SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
- SOF_HDA_SPIB_MAXFIFO;
+ if (i < num_capture) {
+ hstream->stream_tag = i + 1;
+ hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
+ } else {
+ hstream->stream_tag = i - num_capture + 1;
+ hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
}
- hstream->bus = bus;
- hstream->sd_int_sta_mask = 1 << i;
- hstream->index = i;
- sd_offset = SOF_STREAM_SD_OFFSET(hstream);
- hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
- hstream->stream_tag = i - num_capture + 1;
- hstream->opened = false;
- hstream->running = false;
- hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
-
/* mem alloc for stream BDL */
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
HDA_DSP_BDL_SIZE, &hstream->bdl);
@@ -989,8 +986,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
/* store total stream count (playback + capture) from GCAP */
sof_hda->stream_max = num_total;
+ /* store stream count from GCAP required for CHAIN_DMA */
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ ipc4_data->num_playback_streams = num_playback;
+ ipc4_data->num_capture_streams = num_capture;
+ }
+
return 0;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_stream_free(struct snd_sof_dev *sdev)
{
@@ -1020,6 +1026,7 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
devm_kfree(sdev->dev, hda_stream);
}
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
int direction, bool can_sleep)
@@ -1106,3 +1113,101 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
return pos;
}
+EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+#define merge_u64(u32_u, u32_l) (((u64)(u32_u) << 32) | (u32_l))
+
+/**
+ * hda_dsp_get_stream_llp - Retrieve the LLP (Linear Link Position) of the stream
+ * @sdev: SOF device
+ * @component: ASoC component
+ * @substream: PCM substream
+ *
+ * Returns the raw Linear Link Position value
+ */
+u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *be_rtd = NULL;
+ struct hdac_ext_stream *hext_stream;
+ struct snd_soc_dai *cpu_dai;
+ struct snd_soc_dpcm *dpcm;
+ u32 llp_l, llp_u;
+
+ /*
+ * The LLP needs to be read from the Link DMA used for this FE as it is
+ * allowed to use any combination of Link and Host channels
+ */
+ for_each_dpcm_be(rtd, substream->stream, dpcm) {
+ if (dpcm->fe != rtd)
+ continue;
+
+ be_rtd = dpcm->be;
+ }
+
+ if (!be_rtd)
+ return 0;
+
+ cpu_dai = snd_soc_rtd_to_cpu(be_rtd, 0);
+ if (!cpu_dai)
+ return 0;
+
+ hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ if (!hext_stream)
+ return 0;
+
+ /*
+ * The pplc_addr have been calculated during probe in
+ * hda_dsp_stream_init():
+ * pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
+ * SOF_HDA_PPLC_BASE +
+ * SOF_HDA_PPLC_MULTI * total_stream +
+ * SOF_HDA_PPLC_INTERVAL * stream_index
+ *
+ * Use this pre-calculated address to avoid repeated re-calculation.
+ */
+ llp_l = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
+ llp_u = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
+
+ /* Compensate the LLP counter with the saved offset */
+ if (hext_stream->pplcllpl || hext_stream->pplcllpu)
+ return merge_u64(llp_u, llp_l) -
+ merge_u64(hext_stream->pplcllpu, hext_stream->pplcllpl);
+
+ return merge_u64(llp_u, llp_l);
+}
+EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON");
+
+/**
+ * hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream
+ * @sdev: SOF device
+ * @component: ASoC component
+ * @substream: PCM substream
+ *
+ * Returns the raw Linear Link Position value
+ */
+u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_stream *hstream = substream->runtime->private_data;
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+ u32 ldp_l, ldp_u;
+
+ /*
+ * The pphc_addr have been calculated during probe in
+ * hda_dsp_stream_init():
+ * pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
+ * SOF_HDA_PPHC_BASE +
+ * SOF_HDA_PPHC_INTERVAL * stream_index
+ *
+ * Use this pre-calculated address to avoid repeated re-calculation.
+ */
+ ldp_l = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPL);
+ ldp_u = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPU);
+
+ return ((u64)ldp_u << 32) | ldp_l;
+}
+EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c
index cbb9bd7770e6..5da8188ffcfe 100644
--- a/sound/soc/sof/intel/hda-trace.c
+++ b/sound/soc/sof/intel/hda-trace.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -68,6 +68,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_trace_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_trace_release(struct snd_sof_dev *sdev)
{
@@ -86,6 +87,7 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "DMA trace stream is not opened!\n");
return -ENODEV;
}
+EXPORT_SYMBOL_NS(hda_dsp_trace_release, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd)
{
@@ -93,3 +95,4 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd)
return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd);
}
+EXPORT_SYMBOL_NS(hda_dsp_trace_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index ec31a5762ddf..c1518dbee1b7 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
@@ -19,20 +19,24 @@
#include <sound/hda_register.h>
#include <linux/acpi.h>
+#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_intel.h>
#include <sound/intel-dsp-config.h>
#include <sound/intel-nhlt.h>
+#include <sound/soc-acpi-intel-ssp-common.h>
+#include <sound/soc_sdw_utils.h>
#include <sound/sof.h>
#include <sound/sof/xtensa.h>
#include <sound/hda-mlink.h>
#include "../sof-audio.h"
#include "../sof-pci-dev.h"
#include "../ops.h"
+#include "../ipc4-topology.h"
+#include "../../intel/common/sof-function-topology-lib.h"
#include "hda.h"
-#define CREATE_TRACE_POINTS
#include <trace/events/sof_intel.h>
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
@@ -42,42 +46,6 @@
/* platform specific devices */
#include "shim.h"
-#define EXCEPT_MAX_HDR_SIZE 0x400
-#define HDA_EXT_ROM_STATUS_SIZE 8
-
-static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
-{
- const struct sof_intel_dsp_desc *chip;
- u32 interface_mask[2] = { 0 };
-
- chip = get_chip_info(sdev->pdata);
- switch (chip->hw_ip_version) {
- case SOF_INTEL_TANGIER:
- case SOF_INTEL_BAYTRAIL:
- case SOF_INTEL_BROADWELL:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP);
- break;
- case SOF_INTEL_CAVS_1_5:
- case SOF_INTEL_CAVS_1_5_PLUS:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
- BIT(SOF_DAI_INTEL_HDA);
- interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
- break;
- case SOF_INTEL_CAVS_1_8:
- case SOF_INTEL_CAVS_2_0:
- case SOF_INTEL_CAVS_2_5:
- case SOF_INTEL_ACE_1_0:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
- BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
- interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
- break;
- default:
- break;
- }
-
- return interface_mask[sdev->dspless_mode_selected];
-}
-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
/*
@@ -94,46 +62,78 @@ static int sdw_params_stream(struct device *dev,
struct sdw_intel_stream_params_data *params_data)
{
struct snd_soc_dai *d = params_data->dai;
- struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, params_data->stream);
+ 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;
return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_PARAMS, &data);
}
+static int sdw_params_free(struct device *dev, struct sdw_intel_stream_free_data *free_data)
+{
+ struct snd_soc_dai *d = free_data->dai;
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, free_data->substream->stream);
+ struct snd_sof_dev *sdev = widget_to_sdev(w);
+
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_copier_data *copier_data;
+ struct sof_ipc4_copier *ipc4_copier;
+
+ ipc4_copier = dai->private;
+ ipc4_copier->dai_index = 0;
+ copier_data = &ipc4_copier->data;
+
+ /* clear the node ID */
+ copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+ }
+
+ return 0;
+}
+
struct sdw_intel_ops sdw_callback = {
.params_stream = sdw_params_stream,
+ .free_stream = sdw_params_free,
};
-void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+static int sdw_ace2x_params_stream(struct device *dev,
+ struct sdw_intel_stream_params_data *params_data)
{
- struct sof_intel_hda_dev *hdev;
-
- hdev = sdev->pdata->hw_pdata;
-
- if (!hdev->sdw)
- return;
-
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2,
- HDA_DSP_REG_ADSPIC2_SNDW,
- enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
+ return sdw_hda_dai_hw_params(params_data->substream,
+ params_data->hw_params,
+ params_data->dai,
+ params_data->link_id,
+ params_data->alh_stream_id);
}
-void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
+static int sdw_ace2x_free_stream(struct device *dev,
+ struct sdw_intel_stream_free_data *free_data)
{
- u32 interface_mask = hda_get_interface_mask(sdev);
- const struct sof_intel_dsp_desc *chip;
-
- if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
- return;
+ return sdw_hda_dai_hw_free(free_data->substream,
+ free_data->dai,
+ free_data->link_id);
+}
- chip = get_chip_info(sdev->pdata);
- if (chip && chip->enable_sdw_irq)
- chip->enable_sdw_irq(sdev, enable);
+static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+ return sdw_hda_dai_trigger(substream, cmd, dai);
}
+static struct sdw_intel_ops sdw_ace2x_callback = {
+ .params_stream = sdw_ace2x_params_stream,
+ .free_stream = sdw_ace2x_free_stream,
+ .trigger = sdw_ace2x_trigger,
+};
+
static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
@@ -158,6 +158,7 @@ static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
static int hda_sdw_probe(struct snd_sof_dev *sdev)
{
+ const struct sof_intel_dsp_desc *chip;
struct sof_intel_hda_dev *hdev;
struct sdw_intel_res res;
void *sdw;
@@ -166,16 +167,44 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
memset(&res, 0, sizeof(res));
- res.hw_ops = &sdw_intel_cnl_hw_ops;
- res.mmio_base = sdev->bar[HDA_DSP_BAR];
- res.shim_base = hdev->desc->sdw_shim_base;
- res.alh_base = hdev->desc->sdw_alh_base;
+ chip = get_chip_info(sdev->pdata);
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) {
+ res.mmio_base = sdev->bar[HDA_DSP_BAR];
+ res.hw_ops = &sdw_intel_cnl_hw_ops;
+ res.shim_base = hdev->desc->sdw_shim_base;
+ res.alh_base = hdev->desc->sdw_alh_base;
+ res.ext = false;
+ res.ops = &sdw_callback;
+ } else {
+ /*
+ * retrieve eml_lock needed to protect shared registers
+ * in the HDaudio multi-link areas
+ */
+ res.eml_lock = hdac_bus_eml_get_mutex(sof_to_bus(sdev), true,
+ AZX_REG_ML_LEPTR_ID_SDW);
+ if (!res.eml_lock)
+ return -ENODEV;
+
+ res.mmio_base = sdev->bar[HDA_DSP_HDA_BAR];
+ /*
+ * the SHIM and SoundWire register offsets are link-specific
+ * and will be determined when adding auxiliary devices
+ */
+ res.hw_ops = &sdw_intel_lnl_hw_ops;
+ res.ext = true;
+ res.ops = &sdw_ace2x_callback;
+
+ /* ACE3+ supports microphone privacy */
+ if (chip->hw_ip_version >= SOF_INTEL_ACE_3_0)
+ res.mic_privacy = true;
+ }
res.irq = sdev->ipc_irq;
res.handle = hdev->info.handle;
res.parent = sdev->dev;
- res.ops = &sdw_callback;
+
res.dev = sdev->dev;
res.clock_stop_quirks = sdw_clock_stop_quirks;
+ res.hbus = sof_to_bus(sdev);
/*
* ops and arg fields are not populated for now,
@@ -199,65 +228,6 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
return 0;
}
-int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
-{
- struct sof_intel_hda_dev *hdev;
- struct sdw_intel_ctx *ctx;
- u32 caps;
-
- hdev = sdev->pdata->hw_pdata;
- ctx = hdev->sdw;
-
- caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP);
- caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
-
- /* Check HW supported vs property value */
- if (caps < ctx->count) {
- dev_err(sdev->dev,
- "%s: BIOS master count %d is larger than hardware capabilities %d\n",
- __func__, ctx->count, caps);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
-{
- struct sof_intel_hda_dev *hdev;
- struct sdw_intel_ctx *ctx;
- struct hdac_bus *bus;
- u32 slcount;
-
- bus = sof_to_bus(sdev);
-
- hdev = sdev->pdata->hw_pdata;
- ctx = hdev->sdw;
-
- slcount = hdac_bus_eml_get_count(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
-
- /* Check HW supported vs property value */
- if (slcount < ctx->count) {
- dev_err(sdev->dev,
- "%s: BIOS master count %d is larger than hardware capabilities %d\n",
- __func__, ctx->count, slcount);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
-{
- const struct sof_intel_dsp_desc *chip;
-
- chip = get_chip_info(sdev->pdata);
- if (chip && chip->read_sdw_lcount)
- return chip->read_sdw_lcount(sdev);
-
- return 0;
-}
-
int hda_sdw_startup(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev;
@@ -278,6 +248,7 @@ int hda_sdw_startup(struct snd_sof_dev *sdev)
return sdw_intel_startup(hdev->sdw);
}
+EXPORT_SYMBOL_NS(hda_sdw_startup, "SND_SOC_SOF_INTEL_HDA_GENERIC");
static int hda_sdw_exit(struct snd_sof_dev *sdev)
{
@@ -285,12 +256,12 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev)
hdev = sdev->pdata->hw_pdata;
- hda_sdw_int_enable(sdev, false);
-
if (hdev->sdw)
sdw_intel_exit(hdev->sdw);
hdev->sdw = NULL;
+ hda_sdw_int_enable(sdev, false);
+
return 0;
}
@@ -319,6 +290,7 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
out:
return ret;
}
+EXPORT_SYMBOL_NS(hda_common_check_sdw_irq, "SND_SOC_SOF_INTEL_HDA_GENERIC");
static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
{
@@ -340,14 +312,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
return sdw_intel_thread(irq, context);
}
-static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
{
- u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev;
- if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
- return false;
-
hdev = sdev->pdata->hw_pdata;
if (hdev->sdw &&
snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -356,8 +324,24 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
return false;
}
+EXPORT_SYMBOL_NS(hda_sdw_check_wakeen_irq_common, "SND_SOC_SOF_INTEL_HDA_GENERIC");
+
+static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+{
+ u32 interface_mask = hda_get_interface_mask(sdev);
+ const struct sof_intel_dsp_desc *chip;
+
+ if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
+ return false;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->check_sdw_wakeen_irq)
+ return chip->check_sdw_wakeen_irq(sdev);
+
+ return false;
+}
-void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
+void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev;
@@ -371,6 +355,28 @@ void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
sdw_intel_process_wakeen_event(hdev->sdw);
}
+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)
@@ -403,17 +409,59 @@ 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 */
+int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
+{
+ /* disable clock gating and power gating */
+ return hda_dsp_ctrl_clock_power_gating(sdev, false);
+}
+
+/* post fw run operations */
+int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ if (sdev->first_boot) {
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ ret = hda_sdw_startup(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "error: could not startup SoundWire links\n");
+ return ret;
+ }
+
+ /* Check if IMR boot is usable */
+ if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) &&
+ (sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT ||
+ sdev->pdata->ipc_type == SOF_IPC_TYPE_4)) {
+ hdev->imrboot_supported = true;
+ debugfs_create_bool("skip_imr_boot",
+ 0644, sdev->debugfs_root,
+ &hdev->skip_imr_boot);
+ }
+ }
+
+ hda_sdw_int_enable(sdev, true);
+
+ /* re-enable clock gating and power gating */
+ return hda_dsp_ctrl_clock_power_gating(sdev, true);
+}
+EXPORT_SYMBOL_NS(hda_dsp_post_fw_run, "SND_SOC_SOF_INTEL_HDA_GENERIC");
+
/*
* Debug
*/
-struct hda_dsp_msg_code {
- u32 code;
- const char *text;
-};
-
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
static bool hda_use_msi = true;
module_param_named(use_msi, hda_use_msi, bool, 0444);
@@ -422,10 +470,6 @@ MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode");
#define hda_use_msi (1)
#endif
-int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS;
-module_param_named(position_quirk, sof_hda_position_quirk, int, 0444);
-MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk");
-
static char *hda_model;
module_param(hda_model, charp, 0444);
MODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
@@ -438,307 +482,9 @@ static int mclk_id_override = -1;
module_param_named(mclk_id, mclk_id_override, int, 0444);
MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id");
-static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
- {HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
- {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
- {HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"},
- {HDA_DSP_ROM_BASE_FW_NOT_FOUND, "error: base fw not found"},
- {HDA_DSP_ROM_CSE_VALIDATION_FAILED, "error: signature verification failed"},
- {HDA_DSP_ROM_IPC_FATAL_ERROR, "error: ipc fatal error"},
- {HDA_DSP_ROM_L2_CACHE_ERROR, "error: L2 cache error"},
- {HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL, "error: load offset too small"},
- {HDA_DSP_ROM_API_PTR_INVALID, "error: API ptr invalid"},
- {HDA_DSP_ROM_BASEFW_INCOMPAT, "error: base fw incompatible"},
- {HDA_DSP_ROM_UNHANDLED_INTERRUPT, "error: unhandled interrupt"},
- {HDA_DSP_ROM_MEMORY_HOLE_ECC, "error: ECC memory hole"},
- {HDA_DSP_ROM_KERNEL_EXCEPTION, "error: kernel exception"},
- {HDA_DSP_ROM_USER_EXCEPTION, "error: user exception"},
- {HDA_DSP_ROM_UNEXPECTED_RESET, "error: unexpected reset"},
- {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"},
-};
-
-#define FSR_ROM_STATE_ENTRY(state) {FSR_STATE_ROM_##state, #state}
-static const struct hda_dsp_msg_code fsr_rom_state_names[] = {
- FSR_ROM_STATE_ENTRY(INIT),
- FSR_ROM_STATE_ENTRY(INIT_DONE),
- FSR_ROM_STATE_ENTRY(CSE_MANIFEST_LOADED),
- FSR_ROM_STATE_ENTRY(FW_MANIFEST_LOADED),
- FSR_ROM_STATE_ENTRY(FW_FW_LOADED),
- FSR_ROM_STATE_ENTRY(FW_ENTERED),
- FSR_ROM_STATE_ENTRY(VERIFY_FEATURE_MASK),
- FSR_ROM_STATE_ENTRY(GET_LOAD_OFFSET),
- FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT),
- FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT_DONE),
- /* CSE states */
- FSR_ROM_STATE_ENTRY(CSE_IMR_REQUEST),
- FSR_ROM_STATE_ENTRY(CSE_IMR_GRANTED),
- FSR_ROM_STATE_ENTRY(CSE_VALIDATE_IMAGE_REQUEST),
- FSR_ROM_STATE_ENTRY(CSE_IMAGE_VALIDATED),
- FSR_ROM_STATE_ENTRY(CSE_IPC_IFACE_INIT),
- FSR_ROM_STATE_ENTRY(CSE_IPC_RESET_PHASE_1),
- FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL_ENTRY),
- FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL),
- FSR_ROM_STATE_ENTRY(CSE_IPC_DOWN),
-};
-
-#define FSR_BRINGUP_STATE_ENTRY(state) {FSR_STATE_BRINGUP_##state, #state}
-static const struct hda_dsp_msg_code fsr_bringup_state_names[] = {
- FSR_BRINGUP_STATE_ENTRY(INIT),
- FSR_BRINGUP_STATE_ENTRY(INIT_DONE),
- FSR_BRINGUP_STATE_ENTRY(HPSRAM_LOAD),
- FSR_BRINGUP_STATE_ENTRY(UNPACK_START),
- FSR_BRINGUP_STATE_ENTRY(IMR_RESTORE),
- FSR_BRINGUP_STATE_ENTRY(FW_ENTERED),
-};
-
-#define FSR_WAIT_STATE_ENTRY(state) {FSR_WAIT_FOR_##state, #state}
-static const struct hda_dsp_msg_code fsr_wait_state_names[] = {
- FSR_WAIT_STATE_ENTRY(IPC_BUSY),
- FSR_WAIT_STATE_ENTRY(IPC_DONE),
- FSR_WAIT_STATE_ENTRY(CACHE_INVALIDATION),
- FSR_WAIT_STATE_ENTRY(LP_SRAM_OFF),
- FSR_WAIT_STATE_ENTRY(DMA_BUFFER_FULL),
- FSR_WAIT_STATE_ENTRY(CSE_CSR),
-};
-
-#define FSR_MODULE_NAME_ENTRY(mod) [FSR_MOD_##mod] = #mod
-static const char * const fsr_module_names[] = {
- FSR_MODULE_NAME_ENTRY(ROM),
- FSR_MODULE_NAME_ENTRY(ROM_BYP),
- FSR_MODULE_NAME_ENTRY(BASE_FW),
- FSR_MODULE_NAME_ENTRY(LP_BOOT),
- FSR_MODULE_NAME_ENTRY(BRNGUP),
- FSR_MODULE_NAME_ENTRY(ROM_EXT),
-};
-
-static const char *
-hda_dsp_get_state_text(u32 code, const struct hda_dsp_msg_code *msg_code,
- size_t array_size)
-{
- int i;
-
- for (i = 0; i < array_size; i++) {
- if (code == msg_code[i].code)
- return msg_code[i].text;
- }
-
- return NULL;
-}
-
-static void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level)
-{
- const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
- const char *state_text, *error_text, *module_text;
- u32 fsr, state, wait_state, module, error_code;
-
- fsr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg);
- state = FSR_TO_STATE_CODE(fsr);
- wait_state = FSR_TO_WAIT_STATE_CODE(fsr);
- module = FSR_TO_MODULE_CODE(fsr);
-
- if (module > FSR_MOD_ROM_EXT)
- module_text = "unknown";
- else
- module_text = fsr_module_names[module];
-
- if (module == FSR_MOD_BRNGUP)
- state_text = hda_dsp_get_state_text(state, fsr_bringup_state_names,
- ARRAY_SIZE(fsr_bringup_state_names));
- else
- state_text = hda_dsp_get_state_text(state, fsr_rom_state_names,
- ARRAY_SIZE(fsr_rom_state_names));
-
- /* not for us, must be generic sof message */
- if (!state_text) {
- dev_printk(level, sdev->dev, "%#010x: unknown ROM status value\n", fsr);
- return;
- }
-
- if (wait_state) {
- const char *wait_state_text;
-
- wait_state_text = hda_dsp_get_state_text(wait_state, fsr_wait_state_names,
- ARRAY_SIZE(fsr_wait_state_names));
- if (!wait_state_text)
- wait_state_text = "unknown";
-
- dev_printk(level, sdev->dev,
- "%#010x: module: %s, state: %s, waiting for: %s, %s\n",
- fsr, module_text, state_text, wait_state_text,
- fsr & FSR_HALTED ? "not running" : "running");
- } else {
- dev_printk(level, sdev->dev, "%#010x: module: %s, state: %s, %s\n",
- fsr, module_text, state_text,
- fsr & FSR_HALTED ? "not running" : "running");
- }
-
- error_code = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + 4);
- if (!error_code)
- return;
-
- error_text = hda_dsp_get_state_text(error_code, hda_dsp_rom_fw_error_texts,
- ARRAY_SIZE(hda_dsp_rom_fw_error_texts));
- if (!error_text)
- error_text = "unknown";
-
- if (state == FSR_STATE_FW_ENTERED)
- dev_printk(level, sdev->dev, "status code: %#x (%s)\n", error_code,
- error_text);
- else
- dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code,
- error_text);
-}
-
-static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
- struct sof_ipc_dsp_oops_xtensa *xoops,
- struct sof_ipc_panic_info *panic_info,
- u32 *stack, size_t stack_words)
-{
- u32 offset = sdev->dsp_oops_offset;
-
- /* first read registers */
- sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
-
- /* note: variable AR register array is not read */
-
- /* then get panic info */
- if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
- dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
- xoops->arch_hdr.totalsize);
- return;
- }
- offset += xoops->arch_hdr.totalsize;
- sof_block_read(sdev, sdev->mmio_bar, offset,
- panic_info, sizeof(*panic_info));
-
- /* then get the stack */
- offset += sizeof(*panic_info);
- sof_block_read(sdev, sdev->mmio_bar, offset, stack,
- stack_words * sizeof(u32));
-}
-
-/* dump the first 8 dwords representing the extended ROM status */
-static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level,
- u32 flags)
-{
- const struct sof_intel_dsp_desc *chip;
- char msg[128];
- int len = 0;
- u32 value;
- int i;
-
- chip = get_chip_info(sdev->pdata);
- for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) {
- value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + i * 0x4);
- len += scnprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
- }
-
- dev_printk(level, sdev->dev, "extended rom status: %s", msg);
-
-}
-
-void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
-{
- char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
- struct sof_ipc_dsp_oops_xtensa xoops;
- struct sof_ipc_panic_info panic_info;
- u32 stack[HDA_DSP_STACK_DUMP_SIZE];
-
- /* print ROM/FW status */
- hda_dsp_get_state(sdev, level);
-
- /* The firmware register dump only available with IPC3 */
- if (flags & SOF_DBG_DUMP_REGS && sdev->pdata->ipc_type == SOF_IPC) {
- u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS);
- u32 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP);
-
- hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
- HDA_DSP_STACK_DUMP_SIZE);
- sof_print_oops_and_stack(sdev, level, status, panic, &xoops,
- &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE);
- } else {
- hda_dsp_dump_ext_rom_status(sdev, level, flags);
- }
-}
-
-static bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
-{
- const struct sof_intel_dsp_desc *chip;
-
- chip = get_chip_info(sdev->pdata);
- if (chip && chip->check_ipc_irq)
- return chip->check_ipc_irq(sdev);
-
- return false;
-}
-
-void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
-{
- u32 adspis;
- u32 intsts;
- u32 intctl;
- u32 ppsts;
- u8 rirbsts;
-
- /* read key IRQ stats and config registers */
- adspis = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
- intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
- intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL);
- ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS);
- rirbsts = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, AZX_REG_RIRBSTS);
-
- dev_err(sdev->dev, "hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n",
- intsts, intctl, rirbsts);
- dev_err(sdev->dev, "dsp irq ppsts 0x%8.8x adspis 0x%8.8x\n", ppsts, adspis);
-}
-
-void hda_ipc_dump(struct snd_sof_dev *sdev)
-{
- u32 hipcie;
- u32 hipct;
- u32 hipcctl;
-
- hda_ipc_irq_dump(sdev);
-
- /* read IPC status */
- hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
- hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
- hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
-
- /* dump the IPC regs */
- /* TODO: parse the raw msg */
- dev_err(sdev->dev, "host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
- hipcie, hipct, hipcctl);
-}
-
-void hda_ipc4_dump(struct snd_sof_dev *sdev)
-{
- u32 hipci, hipcie, hipct, hipcte, hipcctl;
-
- hda_ipc_irq_dump(sdev);
-
- hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
- hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
- hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
- hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE);
- hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
-
- /* dump the IPC regs */
- /* TODO: parse the raw msg */
- dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n",
- hipci, hipcie, hipct, hipcte, hipcctl);
-}
-
-bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
-{
- struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
- const struct sof_intel_dsp_desc *chip = hda->desc;
- u32 val;
-
- val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req);
-
- return !!(val & chip->ipc_req_mask);
-}
+static int bt_link_mask_override;
+module_param_named(bt_link_mask, bt_link_mask_override, int, 0444);
+MODULE_PARM_DESC(bt_link_mask, "SOF BT offload link mask");
static int hda_init(struct snd_sof_dev *sdev)
{
@@ -778,13 +524,21 @@ static int hda_init(struct snd_sof_dev *sdev)
/* init i915 and HDMI codecs */
ret = hda_codec_i915_init(sdev);
- if (ret < 0)
- dev_warn(sdev->dev, "init of i915 and HDMI codec failed\n");
+ if (ret < 0 && ret != -ENODEV) {
+ dev_err_probe(sdev->dev, ret, "init of i915 and HDMI codec failed\n");
+ goto out;
+ }
/* get controller capabilities */
ret = hda_dsp_ctrl_get_caps(sdev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(sdev->dev, "error: get caps error\n");
+ hda_codec_i915_exit(sdev);
+ }
+
+out:
+ if (ret < 0)
+ iounmap(sof_to_bus(sdev)->remap_addr);
return ret;
}
@@ -799,6 +553,8 @@ static int check_dmic_num(struct snd_sof_dev *sdev)
if (nhlt)
dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
+ dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
+
/* allow for module parameter override */
if (dmic_num_override != -1) {
dev_dbg(sdev->dev,
@@ -815,7 +571,7 @@ static int check_dmic_num(struct snd_sof_dev *sdev)
return dmic_num;
}
-static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
+static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev, u8 device_type)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct nhlt_acpi_table *nhlt;
@@ -826,9 +582,11 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
return ssp_mask;
if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP)) {
- ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S);
+ ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, device_type);
if (ssp_mask)
- dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask);
+ dev_info(sdev->dev, "NHLT device %s(%d) detected, ssp_mask %#x\n",
+ device_type == NHLT_DEVICE_BT ? "BT" : "I2S",
+ device_type, ssp_mask);
}
return ssp_mask;
@@ -846,82 +604,6 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
-
-static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
- const char *sof_tplg_filename,
- const char *idisp_str,
- const char *dmic_str)
-{
- const char *tplg_filename = NULL;
- char *filename, *tmp;
- const char *split_ext;
-
- filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
- if (!filename)
- return NULL;
-
- /* this assumes a .tplg extension */
- tmp = filename;
- split_ext = strsep(&tmp, ".");
- if (split_ext)
- tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
- "%s%s%s.tplg",
- split_ext, idisp_str, dmic_str);
- kfree(filename);
-
- return tplg_filename;
-}
-
-static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
- const char **tplg_filename,
- const char *idisp_str,
- int *dmic_found,
- bool tplg_fixup)
-{
- const char *dmic_str;
- int dmic_num;
-
- /* first check for DMICs (using NHLT or module parameter) */
- dmic_num = check_dmic_num(sdev);
-
- switch (dmic_num) {
- case 1:
- dmic_str = "-1ch";
- break;
- case 2:
- dmic_str = "-2ch";
- break;
- case 3:
- dmic_str = "-3ch";
- break;
- case 4:
- dmic_str = "-4ch";
- break;
- default:
- dmic_num = 0;
- dmic_str = "";
- break;
- }
-
- if (tplg_fixup) {
- const char *default_tplg_filename = *tplg_filename;
- const char *fixed_tplg_filename;
-
- fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
- idisp_str, dmic_str);
- if (!fixed_tplg_filename)
- return -ENOMEM;
- *tplg_filename = fixed_tplg_filename;
- }
-
- dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
- *dmic_found = dmic_num;
-
- return 0;
-}
-#endif
-
static int hda_init_caps(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
@@ -936,7 +618,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
/* Init HDA controller after i915 init */
- ret = hda_dsp_ctrl_init_chip(sdev);
+ ret = hda_dsp_ctrl_init_chip(sdev, true);
if (ret < 0) {
dev_err(bus->dev, "error: init chip failed with ret: %d\n",
ret);
@@ -949,6 +631,11 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
+ /* Skip SoundWire in nocodec mode */
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ goto skip_soundwire;
+
/* scan SoundWire capabilities exposed by DSDT */
ret = hda_sdw_acpi_scan(sdev);
if (ret < 0) {
@@ -1029,7 +716,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)) {
@@ -1048,11 +741,10 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
return IRQ_HANDLED;
}
-int hda_dsp_probe(struct snd_sof_dev *sdev)
+int hda_dsp_probe_early(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct sof_intel_hda_dev *hdev;
- struct hdac_bus *bus;
const struct sof_intel_dsp_desc *chip;
int ret = 0;
@@ -1072,8 +764,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
pci->class);
return -ENODEV;
}
- dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
- pci->class);
+ dev_info_once(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
+ pci->class);
}
chip = get_chip_info(sdev->pdata);
@@ -1091,6 +783,19 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
return -ENOMEM;
sdev->pdata->hw_pdata = hdev;
hdev->desc = chip;
+ ret = hda_init(sdev);
+
+err:
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_dsp_probe_early, "SND_SOC_SOF_INTEL_HDA_GENERIC");
+
+int hda_dsp_probe(struct snd_sof_dev *sdev)
+{
+ struct pci_dev *pci = to_pci_dev(sdev->dev);
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip;
+ int ret = 0;
hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
PLATFORM_DEVID_NONE,
@@ -1113,12 +818,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
if (sdev->dspless_mode_selected)
hdev->no_ipc_position = 1;
- /* set up HDA base */
- bus = sof_to_bus(sdev);
- ret = hda_init(sdev);
- if (ret < 0)
- goto hdac_bus_unmap;
-
if (sdev->dspless_mode_selected)
goto skip_dsp_setup;
@@ -1209,12 +908,26 @@ skip_dsp_setup:
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
}
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+ ret = hda_sdw_startup(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "could not startup SoundWire links\n");
+ goto disable_pp_cap;
+ }
+ }
+
init_waitqueue_head(&hdev->waitq);
hdev->nhlt = intel_nhlt_init(sdev->dev);
return 0;
+disable_pp_cap:
+ if (!sdev->dspless_mode_selected) {
+ hda_dsp_ctrl_ppcap_int_enable(sdev, false);
+ hda_dsp_ctrl_ppcap_enable(sdev, false);
+ }
free_ipc_irq:
free_irq(sdev->ipc_irq, sdev);
free_irq_vector:
@@ -1227,17 +940,15 @@ free_streams:
iounmap(sdev->bar[HDA_DSP_BAR]);
hdac_bus_unmap:
platform_device_unregister(hdev->dmic_dev);
- iounmap(bus->remap_addr);
- hda_codec_i915_exit(sdev);
-err:
+
return ret;
}
+EXPORT_SYMBOL_NS(hda_dsp_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC");
-int hda_dsp_remove(struct snd_sof_dev *sdev)
+void hda_dsp_remove(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
- struct hdac_bus *bus = sof_to_bus(sdev);
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct nhlt_acpi_table *nhlt = hda->nhlt;
@@ -1257,8 +968,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
if (!sdev->dspless_mode_selected) {
/* disable DSP IRQ */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
- SOF_HDA_PPCTL_PIE, 0);
+ hda_dsp_ctrl_ppcap_int_enable(sdev, false);
}
/* disable CIE and GIE interrupts */
@@ -1268,13 +978,22 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
if (sdev->dspless_mode_selected)
goto skip_disable_dsp;
+ /* Cancel the microphone privacy work if mic privacy is active */
+ if (hda->mic_privacy.active)
+ cancel_work_sync(&hda->mic_privacy.work);
+
/* no need to check for error as the DSP will be disabled anyway */
if (chip && chip->power_down_dsp)
chip->power_down_dsp(sdev);
/* disable DSP */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
- SOF_HDA_PPCTL_GPROCEN, 0);
+ hda_dsp_ctrl_ppcap_enable(sdev, false);
+
+ /* Free the persistent DMA buffers used for base firmware download */
+ if (hda->cl_dmab.area)
+ snd_dma_free_pages(&hda->cl_dmab);
+ if (hda->iccmax_dmab.area)
+ snd_dma_free_pages(&hda->iccmax_dmab);
skip_disable_dsp:
free_irq(sdev->ipc_irq, sdev);
@@ -1287,14 +1006,14 @@ skip_disable_dsp:
if (!sdev->dspless_mode_selected)
iounmap(sdev->bar[HDA_DSP_BAR]);
+}
+EXPORT_SYMBOL_NS(hda_dsp_remove, "SND_SOC_SOF_INTEL_HDA_GENERIC");
- iounmap(bus->remap_addr);
-
+void hda_dsp_remove_late(struct snd_sof_dev *sdev)
+{
+ iounmap(sof_to_bus(sdev)->remap_addr);
sof_hda_bus_exit(sdev);
-
hda_codec_i915_exit(sdev);
-
- return 0;
}
int hda_power_down_dsp(struct snd_sof_dev *sdev)
@@ -1304,6 +1023,7 @@ int hda_power_down_dsp(struct snd_sof_dev *sdev)
return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
}
+EXPORT_SYMBOL_NS(hda_power_down_dsp, "SND_SOC_SOF_INTEL_HDA_GENERIC");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
static void hda_generic_machine_select(struct snd_sof_dev *sdev,
@@ -1314,10 +1034,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
struct snd_soc_acpi_mach *hda_mach;
struct snd_sof_pdata *pdata = sdev->pdata;
const char *tplg_filename;
- const char *idisp_str;
- int dmic_num = 0;
int codec_num = 0;
- int ret;
int i;
/* codec detection */
@@ -1340,33 +1057,44 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
* - one external HDAudio codec
*/
if (!*mach && codec_num <= 2) {
- bool tplg_fixup;
+ bool tplg_fixup = false;
- hda_mach = snd_soc_acpi_intel_hda_machines;
+ /*
+ * make a local copy of the match array since we might
+ * be modifying it
+ */
+ hda_mach = devm_kmemdup_array(sdev->dev,
+ snd_soc_acpi_intel_hda_machines,
+ 2, /* we have one entry + sentinel in the array */
+ sizeof(snd_soc_acpi_intel_hda_machines[0]),
+ GFP_KERNEL);
+ if (!hda_mach) {
+ dev_err(bus->dev,
+ "%s: failed to duplicate the HDA match table\n",
+ __func__);
+ return;
+ }
dev_info(bus->dev, "using HDA machine driver %s now\n",
hda_mach->drv_name);
- if (codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask))
- idisp_str = "-idisp";
- else
- idisp_str = "";
-
- /* topology: use the info from hda_machines */
- if (pdata->tplg_filename) {
- tplg_fixup = false;
- tplg_filename = pdata->tplg_filename;
- } else {
+ /*
+ * topology: use the info from hda_machines since tplg file name
+ * is not overwritten
+ */
+ if (!pdata->tplg_filename)
tplg_fixup = true;
- tplg_filename = hda_mach->sof_tplg_filename;
- }
- ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
- tplg_fixup);
- if (ret < 0)
- return;
- hda_mach->mach_params.dmic_num = dmic_num;
- pdata->tplg_filename = tplg_filename;
+ if (tplg_fixup &&
+ codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask)) {
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-idisp",
+ hda_mach->sof_tplg_filename);
+ if (!tplg_filename)
+ return;
+
+ hda_mach->sof_tplg_filename = tplg_filename;
+ }
if (codec_num == 2 ||
(codec_num == 1 && !HDA_IDISP_CODEC(bus->codec_mask))) {
@@ -1394,7 +1122,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
if (*mach) {
mach_params = &(*mach)->mach_params;
mach_params->codec_mask = bus->codec_mask;
- mach_params->common_hdmi_codec_drv = true;
}
}
#else
@@ -1406,180 +1133,297 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
-#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
- SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
+static bool is_endpoint_present(struct sdw_slave *sdw_device,
+ struct asoc_sdw_codec_info *dai_info, int dai_type)
+{
+ int i;
+
+ for (i = 0; i < sdw_device->sdca_data.num_functions; i++) {
+ if (dai_type == dai_info->dais[i].dai_type)
+ return true;
+ }
+ dev_dbg(&sdw_device->dev, "Endpoint DAI type %d not found\n", dai_type);
+ return false;
+}
-/* Check if all Slaves defined on the link can be found */
-static bool link_slaves_found(struct snd_sof_dev *sdev,
- const struct snd_soc_acpi_link_adr *link,
- struct sdw_intel_ctx *sdw)
+static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
+ struct sdw_slave *sdw_device,
+ struct snd_soc_acpi_link_adr *link,
+ int *amp_index)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
- struct sdw_intel_slave_id *ids = sdw->ids;
- int num_slaves = sdw->num_slaves;
- unsigned int part_id, link_id, unique_id, mfg_id, version;
- int i, j, k;
-
- for (i = 0; i < link->num_adr; i++) {
- u64 adr = link->adr_d[i].adr;
- int reported_part_count = 0;
-
- mfg_id = SDW_MFG_ID(adr);
- part_id = SDW_PART_ID(adr);
- link_id = SDW_DISCO_LINK_ID(adr);
- version = SDW_VERSION(adr);
-
- for (j = 0; j < num_slaves; j++) {
- /* find out how many identical parts were reported on that link */
- if (ids[j].link_id == link_id &&
- ids[j].id.part_id == part_id &&
- ids[j].id.mfg_id == mfg_id &&
- ids[j].id.sdw_version == version)
- reported_part_count++;
- }
+ struct snd_soc_acpi_adr_device *adr_dev;
+ const char *name_prefix = "";
+ int index = link->num_adr;
+ bool is_amp = true; /* Set it to false if the codec wiah any NON-AMP DAI type */
+ int ep_index = 0;
+ int i, j;
+
+ link->mask = BIT(sdw_device->bus->link_id);
+ /* index is 0 based, we need allocate index + 1 for the array size */
+ if (!index)
+ adr_dev = devm_kzalloc(dev, sizeof(*adr_dev), GFP_KERNEL);
+ else
+ adr_dev = devm_krealloc(dev, (struct snd_soc_acpi_adr_device *)link->adr_d,
+ (index + 1) * sizeof(*adr_dev), GFP_KERNEL);
- for (j = 0; j < num_slaves; j++) {
- int expected_part_count = 0;
+ if (!adr_dev)
+ return NULL;
- if (ids[j].link_id != link_id ||
- ids[j].id.part_id != part_id ||
- ids[j].id.mfg_id != mfg_id ||
- ids[j].id.sdw_version != version)
- continue;
+ for (i = 0; i < asoc_sdw_get_codec_info_list_count(); i++) {
+ struct snd_soc_acpi_endpoint *endpoints;
+ int amp_group_id = 1;
- /* find out how many identical parts are expected */
- for (k = 0; k < link->num_adr; k++) {
- u64 adr2 = link->adr_d[k].adr;
+ if (sdw_device->id.part_id != codec_info_list[i].part_id)
+ continue;
- if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
- expected_part_count++;
- }
+ endpoints = devm_kcalloc(dev, codec_info_list[i].dai_num,
+ sizeof(struct snd_soc_acpi_endpoint), GFP_KERNEL);
+ if (!endpoints)
+ return NULL;
- if (reported_part_count == expected_part_count) {
- /*
- * we have to check unique id
- * if there is more than one
- * Slave on the link
- */
- unique_id = SDW_UNIQUE_ID(adr);
- if (reported_part_count == 1 ||
- ids[j].id.unique_id == unique_id) {
- dev_dbg(bus->dev, "found %x at link %d\n",
- part_id, link_id);
- break;
- }
+ name_prefix = codec_info_list[i].name_prefix;
+ /*
+ * This should not happen, but add a paranoid check to avoid NULL pointer
+ * dereference
+ */
+ if (!name_prefix) {
+ dev_err(dev, "codec_info_list name_prefix of part id %#x is missing\n",
+ codec_info_list[i].part_id);
+ return NULL;
+ }
+ for (j = 0; j < codec_info_list[i].dai_num; j++) {
+ /* Check if the endpoint is present by the SDCA DisCo table */
+ if (!is_endpoint_present(sdw_device, &codec_info_list[i],
+ codec_info_list[i].dais[j].dai_type))
+ continue;
+
+ endpoints[ep_index].num = ep_index;
+ if (codec_info_list[i].dais[j].dai_type == SOC_SDW_DAI_TYPE_AMP) {
+ /* Assume all amp are aggregated */
+ endpoints[ep_index].aggregated = 1;
+ endpoints[ep_index].group_id = amp_group_id;
+ endpoints[ep_index].group_position = *amp_index;
+ /* Set group id = 2 for feedback capture endpoint */
+ amp_group_id++;
} else {
- dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n",
- part_id, reported_part_count, expected_part_count, link_id);
+ endpoints[ep_index].aggregated = 0;
+ endpoints[ep_index].group_id = 0;
+ endpoints[ep_index].group_position = 0;
+ is_amp = false;
}
+ ep_index++;
}
- if (j == num_slaves) {
- dev_dbg(bus->dev,
- "Slave %x not found\n",
- part_id);
- return false;
+ adr_dev[index].endpoints = endpoints;
+ adr_dev[index].num_endpoints = ep_index;
+ break;
+ }
+
+ if (i == asoc_sdw_get_codec_info_list_count()) {
+ dev_err(dev, "part id %#x is not supported\n", sdw_device->id.part_id);
+ return NULL;
+ }
+
+ adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) |
+ ((u64)sdw_device->id.part_id & 0xFFFF) << 8 |
+ ((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 |
+ ((u64)(sdw_device->id.unique_id & 0xF) << 40) |
+ ((u64)(sdw_device->id.sdw_version & 0xF) << 44) |
+ ((u64)(sdw_device->bus->link_id & 0xF) << 48);
+
+ if (!is_amp) {
+ /* For non-amp codecs, get name_prefix from codec_info_list[] */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s", name_prefix);
+ goto done_name_prefix;
+ }
+
+ /*
+ * The name_prefix comes from codec_info_list which has a name_prefix per codec.
+ * And we need to give a unique name_prefix for each amp and should be backwards
+ * compatible to the existing acpi match tables to not break existing UCMs.
+ * For the common name_prefix, we append the amp index to it. However, for the
+ * "Left" name_prefix, we convert the second amp name_prefix to "Right" and
+ * for the third and further amps, we set the name_prefix to "AMP<amp_index>".
+ */
+ if (!strcmp(name_prefix, "Left")) {
+ switch (*amp_index) {
+ case 1:
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", "Left");
+ break;
+ case 2:
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", "Right");
+ break;
+ default:
+ /* Set the name_fix to AMP<amp_index> if there are more than 2 amps */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+ "AMP", *amp_index);
+ break;
}
+ } else if (!strcmp(name_prefix, "AMP")) {
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+ name_prefix,
+ *amp_index);
+ } else {
+ /*
+ * The name_prefix will be the amp name if it is not "Left" or "AMP", set it to
+ * <name_prefix>-<amp_index> format. Like rt1320-1
+ */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s-%d",
+ name_prefix,
+ *amp_index);
}
- return true;
+ (*amp_index)++;
+
+done_name_prefix:
+ if (!adr_dev[index].name_prefix) {
+ dev_err(dev, "failed to allocate memory for name_prefix\n");
+ return NULL;
+ }
+
+ dev_dbg(dev, "adr[%d] 0x%llx link id %d name_prefix \"%s\" is found\n",
+ index, adr_dev[index].adr, sdw_device->bus->link_id, adr_dev[index].name_prefix);
+
+ link->num_adr++;
+
+ return adr_dev;
}
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct snd_soc_acpi_link_adr *link;
+ const struct sof_intel_dsp_desc *chip;
+ struct snd_soc_acpi_link_adr *links;
+ struct sdw_peripherals *peripherals;
struct snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
- u32 link_mask;
+ int link_index, link_num;
+ int amp_index = 1;
+ u32 link_mask = 0;
int i;
hdev = pdata->hw_pdata;
link_mask = hdev->info.link_mask;
+ if (!link_mask) {
+ dev_info(sdev->dev, "SoundWire links not enabled\n");
+ return NULL;
+ }
+
+ if (!hdev->sdw) {
+ dev_dbg(sdev->dev, "SoundWire context not allocated\n");
+ return NULL;
+ }
+
+ if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) {
+ dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n");
+ return NULL;
+ }
+
/*
* Select SoundWire machine driver if needed using the
* alternate tables. This case deals with SoundWire-only
* machines, for mixed cases with I2C/I2S the detection relies
* on the HID list.
*/
- if (link_mask) {
- for (mach = pdata->desc->alt_machines;
- mach && mach->link_mask; mach++) {
- /*
- * On some platforms such as Up Extreme all links
- * are enabled but only one link can be used by
- * external codec. Instead of exact match of two masks,
- * first check whether link_mask of mach is subset of
- * link_mask supported by hw and then go on searching
- * link_adr
- */
- if (~link_mask & mach->link_mask)
- continue;
+ for (mach = pdata->desc->alt_machines;
+ mach && mach->link_mask; mach++) {
+ /*
+ * On some platforms such as Up Extreme all links
+ * are enabled but only one link can be used by
+ * external codec. Instead of exact match of two masks,
+ * first check whether link_mask of mach is subset of
+ * link_mask supported by hw and then go on searching
+ * link_adr
+ */
+ if (~link_mask & mach->link_mask)
+ continue;
- /* No need to match adr if there is no links defined */
- if (!mach->links)
- break;
+ /* No need to match adr if there is no links defined */
+ if (!mach->links)
+ break;
- link = mach->links;
- for (i = 0; i < hdev->info.count && link->num_adr;
- i++, link++) {
- /*
- * Try next machine if any expected Slaves
- * are not found on this link.
- */
- if (!link_slaves_found(sdev, link, hdev->sdw))
- break;
- }
- /* Found if all Slaves are checked */
- if (i == hdev->info.count || !link->num_adr)
+ link = mach->links;
+ for (i = 0; i < hdev->info.count && link->num_adr;
+ i++, link++) {
+ /*
+ * Try next machine if any expected Slaves
+ * are not found on this link.
+ */
+ if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
+ hdev->sdw->peripherals))
break;
}
- if (mach && mach->link_mask) {
- int dmic_num = 0;
- bool tplg_fixup;
- const char *tplg_filename;
+ /* Found if all Slaves are checked */
+ if (i == hdev->info.count || !link->num_adr)
+ if (!mach->machine_check || mach->machine_check(hdev->sdw))
+ break;
+ }
+ if (mach && mach->link_mask) {
+ mach->mach_params.links = mach->links;
+ mach->mach_params.link_mask = mach->link_mask;
+ mach->mach_params.platform = dev_name(sdev->dev);
- mach->mach_params.links = mach->links;
- mach->mach_params.link_mask = mach->link_mask;
- mach->mach_params.platform = dev_name(sdev->dev);
+ return mach;
+ }
- if (pdata->tplg_filename) {
- tplg_fixup = false;
- } else {
- tplg_fixup = true;
- tplg_filename = mach->sof_tplg_filename;
- }
+ dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n");
+ peripherals = hdev->sdw->peripherals;
+ for (i = 0; i < peripherals->num_peripherals; i++)
+ dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n",
+ peripherals->array[i]->bus->link_id,
+ peripherals->array[i]->id.mfg_id,
+ peripherals->array[i]->id.part_id,
+ peripherals->array[i]->id.sdw_version);
- /*
- * 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) {
- int ret;
+ chip = get_chip_info(sdev->pdata);
- ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
- &dmic_num, tplg_fixup);
- if (ret < 0)
- return NULL;
- }
- if (tplg_fixup)
- pdata->tplg_filename = tplg_filename;
- mach->mach_params.dmic_num = dmic_num;
+ /* SDCA was not well supported in the BIOS before ACE2.0 */
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
- dev_dbg(sdev->dev,
- "SoundWire machine driver %s topology %s\n",
- mach->drv_name,
- pdata->tplg_filename);
+ if (!peripherals->num_peripherals)
+ return NULL;
- return mach;
- }
+ /* Create default SDW mach */
+ mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
+ if (!mach)
+ return NULL;
+
+ /* Get link mask and link number */
+ for (i = 0; i < peripherals->num_peripherals; i++)
+ link_mask |= BIT(peripherals->array[i]->bus->link_id);
+
+ link_num = hweight32(link_mask);
+ links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
+ if (!links)
+ return NULL;
- dev_info(sdev->dev, "No SoundWire machine driver found\n");
+ /* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */
+ for (i = 0; i < peripherals->num_peripherals; i++) {
+ /* link_index = the number of used links below the current link */
+ link_index = hweight32(link_mask & (BIT(peripherals->array[i]->bus->link_id) - 1));
+ links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i],
+ &links[link_index], &amp_index);
+ if (!links[link_index].adr_d)
+ return NULL;
}
- return NULL;
+ mach->drv_name = "sof_sdw";
+ mach->mach_params.links = links;
+ mach->mach_params.link_mask = link_mask;
+ mach->mach_params.platform = dev_name(sdev->dev);
+ mach->get_function_tplg_files = sof_sdw_get_tplg_files;
+ /*
+ * Set mach->sof_tplg_filename as a dummy topology to avoid tplg file checking
+ * and being used.
+ */
+ mach->sof_tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-dummy.tplg", chip->platform);
+
+ dev_info(sdev->dev, "Use SoundWire default machine driver with function topologies\n");
+ return mach;
}
#else
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
@@ -1605,48 +1449,153 @@ void hda_set_mach_params(struct snd_soc_acpi_mach *mach,
mach_params->dai_drivers = desc->ops->drv;
}
+static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach)
+{
+ u32 dmic_ssp_quirk;
+ u32 codec_amp_name_quirk;
+
+ /*
+ * In current implementation dmic and ssp quirks are designed for es8336
+ * machine driver and could not be mixed with codec name and amp name
+ * quirks.
+ */
+ dmic_ssp_quirk = mach->tplg_quirk_mask &
+ (SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER | SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER);
+ codec_amp_name_quirk = mach->tplg_quirk_mask &
+ (SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME);
+
+ if (dmic_ssp_quirk && codec_amp_name_quirk)
+ return -EINVAL;
+
+ return 0;
+}
+
+static char *remove_file_ext(struct device *dev, const char *tplg_filename)
+{
+ char *filename, *tmp;
+
+ filename = devm_kstrdup(dev, tplg_filename, GFP_KERNEL);
+ if (!filename)
+ return NULL;
+
+ /* remove file extension if exist */
+ tmp = filename;
+ return strsep(&tmp, ".");
+}
+
struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
struct snd_sof_pdata *sof_pdata = sdev->pdata;
const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_soc_acpi_mach *mach = NULL;
+ enum snd_soc_acpi_intel_codec codec_type, amp_type;
const char *tplg_filename;
+ const char *tplg_suffix;
+ bool amp_name_valid;
+ bool i2s_mach_found = false;
+ bool sdw_mach_found = false;
/* Try I2S or DMIC if it is supported */
- if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC)))
+ if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) {
mach = snd_soc_acpi_find_machine(desc->machines);
+ if (mach)
+ i2s_mach_found = true;
+ }
+
+ /*
+ * If I2S fails and no external HDaudio codec is detected,
+ * try SoundWire if it is supported
+ */
+ if (!mach && !HDA_EXT_CODEC(bus->codec_mask) &&
+ (interface_mask & BIT(SOF_DAI_INTEL_ALH))) {
+ mach = hda_sdw_machine_select(sdev);
+ if (mach)
+ sdw_mach_found = true;
+ }
+ /*
+ * Choose HDA generic machine driver if mach is NULL.
+ * Otherwise, set certain mach params.
+ */
+ hda_generic_machine_select(sdev, &mach);
+ if (!mach) {
+ dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
+ return NULL;
+ }
+
+ /* report BT offload link mask to machine driver */
+ mach->mach_params.bt_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_BT);
+
+ dev_info(sdev->dev, "BT link detected in NHLT tables: %#x\n",
+ mach->mach_params.bt_link_mask);
+
+ /* allow for module parameter override */
+ if (bt_link_mask_override) {
+ dev_dbg(sdev->dev, "overriding BT link detected in NHLT tables %#x by kernel param %#x\n",
+ mach->mach_params.bt_link_mask, bt_link_mask_override);
+ mach->mach_params.bt_link_mask = bt_link_mask_override;
+ }
+
+ if (hweight_long(mach->mach_params.bt_link_mask) > 1) {
+ dev_warn(sdev->dev, "invalid BT link mask %#x found, reset the mask\n",
+ mach->mach_params.bt_link_mask);
+ mach->mach_params.bt_link_mask = 0;
+ }
+
+ /*
+ * Fixup tplg file name by appending dmic num, ssp num, codec/amplifier
+ * name string if quirk flag is set.
+ */
if (mach) {
- bool add_extension = false;
bool tplg_fixup = false;
+ bool dmic_fixup = false;
/*
* If tplg file name is overridden, use it instead of
* the one set in mach table
*/
if (!sof_pdata->tplg_filename) {
- sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ /* remove file extension if it exists */
+ tplg_filename = remove_file_ext(sdev->dev, mach->sof_tplg_filename);
+ if (!tplg_filename)
+ return NULL;
+
+ sof_pdata->tplg_filename = tplg_filename;
tplg_fixup = true;
}
+ /*
+ * Checking quirk mask integrity; some quirk flags could not be
+ * set concurrently.
+ */
+ if (tplg_fixup &&
+ check_tplg_quirk_mask(mach)) {
+ dev_err(sdev->dev, "Invalid tplg quirk mask 0x%x\n",
+ mach->tplg_quirk_mask);
+ return NULL;
+ }
+
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
+ if (sdw_mach_found || mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER)
+ dmic_fixup = true;
+
if (tplg_fixup &&
- mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
+ dmic_fixup &&
mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s",
sof_pdata->tplg_filename,
- "-dmic",
+ i2s_mach_found ? "-dmic" : "-",
mach->mach_params.dmic_num,
"ch");
if (!tplg_filename)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
- add_extension = true;
}
if (mach->link_mask) {
@@ -1655,7 +1604,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
/* report SSP link mask to machine driver */
- mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
+ mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_I2S);
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
@@ -1686,7 +1635,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
- add_extension = true;
mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num);
@@ -1704,7 +1652,51 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
}
- if (tplg_fixup && add_extension) {
+ amp_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev);
+ codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev);
+ amp_name_valid = amp_type != CODEC_NONE && amp_type != codec_type;
+
+ if (tplg_fixup && amp_name_valid &&
+ mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME) {
+ tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(amp_type);
+ if (!tplg_suffix) {
+ dev_err(sdev->dev, "no tplg suffix found, amp %d\n",
+ amp_type);
+ return NULL;
+ }
+
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-%s",
+ sof_pdata->tplg_filename,
+ tplg_suffix);
+ if (!tplg_filename)
+ return NULL;
+
+ sof_pdata->tplg_filename = tplg_filename;
+ }
+
+
+ if (tplg_fixup &&
+ mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME &&
+ codec_type != CODEC_NONE) {
+ tplg_suffix = snd_soc_acpi_intel_get_codec_tplg_suffix(codec_type);
+ if (!tplg_suffix) {
+ dev_err(sdev->dev, "no tplg suffix found, codec %d\n",
+ codec_type);
+ return NULL;
+ }
+
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-%s",
+ sof_pdata->tplg_filename,
+ tplg_suffix);
+ if (!tplg_filename)
+ return NULL;
+
+ sof_pdata->tplg_filename = tplg_filename;
+ }
+
+ if (tplg_fixup) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s",
sof_pdata->tplg_filename,
@@ -1723,18 +1715,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
}
- /* If I2S fails, try SoundWire if it is supported */
- if (!mach && (interface_mask & BIT(SOF_DAI_INTEL_ALH)))
- mach = hda_sdw_machine_select(sdev);
-
- /*
- * Choose HDA generic machine driver if mach is NULL.
- * Otherwise, set certain mach params.
- */
- hda_generic_machine_select(sdev, &mach);
- if (!mach)
- dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
-
return mach;
}
@@ -1750,7 +1730,7 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return sof_pci_probe(pci, pci_id);
}
-EXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_pci_intel_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC");
int hda_register_clients(struct snd_sof_dev *sdev)
{
@@ -1763,11 +1743,15 @@ void hda_unregister_clients(struct snd_sof_dev *sdev)
}
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
-MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);
-MODULE_IMPORT_NS(SOUNDWIRE_INTEL);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
+MODULE_DESCRIPTION("SOF support for HDaudio platforms");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
+MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI");
+MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT");
+MODULE_IMPORT_NS("SOUNDWIRE_INTEL");
+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 3f7c6fb05e5d..562fe8be79c1 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -3,7 +3,7 @@
* 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) 2017 Intel Corporation. All rights reserved.
+ * Copyright(c) 2017 Intel Corporation
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
@@ -11,6 +11,7 @@
#ifndef __SOF_INTEL_HDA_H
#define __SOF_INTEL_HDA_H
+#include <linux/completion.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_intel.h>
#include <sound/compress_driver.h>
@@ -135,6 +136,9 @@
#define SOF_HDA_ADSP_REG_SD_BDLPU 0x1C
#define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20
+/* SDxFIFOS FIFOS */
+#define SOF_HDA_SD_FIFOSIZE_FIFOS_MASK GENMASK(15, 0)
+
/* CL: Software Position Based FIFO Capability Registers */
#define SOF_DSP_REG_CL_SPBFIFO \
(SOF_HDA_ADSP_LOADER_BASE + 0x20)
@@ -450,6 +454,8 @@
#define SSP_SET_SFRM_CONSUMER BIT(24)
#define SSP_SET_CBP_CFP (SSP_SET_SCLK_CONSUMER | SSP_SET_SFRM_CONSUMER)
+#define HDA_EXT_ADDR 0
+#define HDA_EXT_CODEC(x) ((x) & BIT(HDA_EXT_ADDR))
#define HDA_IDISP_ADDR 2
#define HDA_IDISP_CODEC(x) ((x) & BIT(HDA_IDISP_ADDR))
@@ -481,6 +487,11 @@ enum sof_hda_D0_substate {
SOF_HDA_DSP_PM_D0I3, /* low power D0 substate */
};
+struct sof_ace3_mic_privacy {
+ bool active;
+ struct work_struct work;
+};
+
/* represents DSP HDA controller frontend - i.e. host facing control */
struct sof_intel_hda_dev {
bool imrboot_supported;
@@ -489,6 +500,15 @@ struct sof_intel_hda_dev {
int boot_iteration;
+ /*
+ * DMA buffers for base firmware download. By default the buffers are
+ * allocated once and kept through the lifetime of the driver.
+ * See module parameter: persistent_cl_buffer
+ */
+ struct snd_dma_buffer cl_dmab;
+ bool cl_dmab_contains_basefw;
+ struct snd_dma_buffer iccmax_dmab;
+
struct hda_bus hbus;
/* hw config */
@@ -527,6 +547,9 @@ struct sof_intel_hda_dev {
/* Intel NHLT information */
struct nhlt_acpi_table *nhlt;
+ /* work queue for mic privacy state change notification sending */
+ struct sof_ace3_mic_privacy mic_privacy;
+
/*
* Pointing to the IPC message if immediate sending was not possible
* because the downlink communication channel was BUSY at the time.
@@ -556,6 +579,7 @@ struct sof_intel_hda_stream {
struct sof_intel_stream sof_intel_stream;
int host_reserved; /* reserve host DMA channel */
u32 flags;
+ struct completion ioc;
};
#define hstream_to_sof_hda_stream(hstream) \
@@ -571,10 +595,17 @@ struct sof_intel_hda_stream {
#define SOF_STREAM_SD_OFFSET_CRST 0x1
/*
+ * DAI support
+ */
+bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type);
+
+/*
* DSP Core services.
*/
+int hda_dsp_probe_early(struct snd_sof_dev *sdev);
int hda_dsp_probe(struct snd_sof_dev *sdev);
-int hda_dsp_remove(struct snd_sof_dev *sdev);
+void hda_dsp_remove(struct snd_sof_dev *sdev);
+void hda_dsp_remove_late(struct snd_sof_dev *sdev);
int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
@@ -600,10 +631,13 @@ int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev);
int hda_dsp_shutdown(struct snd_sof_dev *sdev);
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
+void hda_ipc4_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
void hda_ipc_dump(struct snd_sof_dev *sdev);
void hda_ipc_irq_dump(struct snd_sof_dev *sdev);
void hda_dsp_d0i3_work(struct work_struct *work);
int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev);
+bool hda_check_ipc_irq(struct snd_sof_dev *sdev);
+u32 hda_get_interface_mask(struct snd_sof_dev *sdev);
/*
* DSP PCM Operations.
@@ -651,6 +685,12 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
int direction, bool can_sleep);
+u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream);
+u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream);
struct hdac_ext_stream *
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
@@ -678,17 +718,25 @@ int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context);
int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
+void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level);
+void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level,
+ u32 flags);
+
/*
* DSP Code loader.
*/
int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev);
int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream);
-struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
- unsigned int size, struct snd_dma_buffer *dmab,
- int direction);
-int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
- struct hdac_ext_stream *hext_stream);
+
+struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
+ unsigned int size, struct snd_dma_buffer *dmab,
+ bool persistent_buffer, int direction,
+ bool is_iccmax);
+int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd);
+
+int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
@@ -709,7 +757,7 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev);
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec);
void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev);
/*
* HDA bus operations.
@@ -782,9 +830,12 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev);
int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev);
+int hda_sdw_check_lcount(struct snd_sof_dev *sdev);
int hda_sdw_startup(struct snd_sof_dev *sdev);
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
+bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev);
+void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev);
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
@@ -800,6 +851,11 @@ static inline int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
return 0;
}
+static inline int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
+{
+ return 0;
+}
+
static inline int hda_sdw_startup(struct snd_sof_dev *sdev)
{
return 0;
@@ -813,6 +869,15 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
}
+static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
+{
+ return false;
+}
+
+static inline void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev)
+{
+}
+
static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{
}
@@ -824,6 +889,19 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
#endif
+int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai,
+ int link_id,
+ int intel_alh_id);
+
+int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai,
+ int link_id);
+
+int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai);
+
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
@@ -831,7 +909,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
/*
* Platform Specific HW abstraction Ops.
*/
-extern struct snd_sof_dsp_ops sof_hda_common_ops;
+extern const struct snd_sof_dsp_ops sof_hda_common_ops;
extern struct snd_sof_dsp_ops sof_skl_ops;
int sof_skl_ops_init(struct snd_sof_dev *sdev);
@@ -843,8 +921,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 const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc apl_chip_info;
@@ -856,6 +932,11 @@ extern const struct sof_intel_dsp_desc ehl_chip_info;
extern const struct sof_intel_dsp_desc jsl_chip_info;
extern const struct sof_intel_dsp_desc adls_chip_info;
extern const struct sof_intel_dsp_desc mtl_chip_info;
+extern const struct sof_intel_dsp_desc arl_s_chip_info;
+extern const struct sof_intel_dsp_desc lnl_chip_info;
+extern const struct sof_intel_dsp_desc ptl_chip_info;
+extern const struct sof_intel_dsp_desc wcl_chip_info;
+extern const struct sof_intel_dsp_desc nvl_s_chip_info;
/* Probes support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
@@ -964,4 +1045,12 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
struct snd_sof_dai_config_data *data);
+static inline struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
+{
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_soc_component *component = swidget->scomp;
+
+ return snd_soc_component_get_drvdata(component);
+}
+
#endif
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index 0f249efc6a5a..dbc5ad62258b 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Author: Fred Oh <fred.oh@linux.intel.com>
//
@@ -97,7 +97,6 @@ static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev)
/* Icelake ops */
struct snd_sof_dsp_ops sof_icl_ops;
-EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_icl_ops_init(struct snd_sof_dev *sdev)
{
@@ -107,7 +106,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
/* probe/remove/shutdown */
sof_icl_ops.shutdown = hda_dsp_shutdown;
- if (sdev->pdata->ipc_type == SOF_IPC) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
/* doorbell */
sof_icl_ops.irq_thread = cnl_ipc_irq_thread;
@@ -120,10 +119,10 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
sof_icl_ops.set_power_state = hda_dsp_set_power_state_ipc3;
}
- if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -166,7 +165,6 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_icl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc icl_chip_info = {
/* Icelake */
@@ -188,10 +186,12 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
+ .platform = "icl",
};
-EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
new file mode 100644
index 000000000000..c01ea7e731aa
--- /dev/null
+++ b/sound/soc/sof/intel/lnl.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2023 Intel Corporation
+
+/*
+ * Hardware interface for audio DSP on LunarLake.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/firmware.h>
+#include <sound/hda_register.h>
+#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof_intel.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 <sound/hda-mlink.h>
+
+/* this helps allows the DSP to setup DMIC/SSP */
+static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus, bool enable)
+{
+ int ret;
+
+ ret = hdac_bus_eml_enable_offload(bus, true,
+ AZX_REG_ML_LEPTR_ID_INTEL_SSP, enable);
+ if (ret < 0)
+ return ret;
+
+ ret = hdac_bus_eml_enable_offload(bus, true,
+ AZX_REG_ML_LEPTR_ID_INTEL_DMIC, enable);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hda_dsp_probe(sdev);
+ if (ret < 0)
+ return ret;
+
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);
+}
+
+static void lnl_hda_dsp_remove(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), false);
+ if (ret < 0)
+ dev_warn(sdev->dev,
+ "Failed to disable offload for DMIC/SSP: %d\n", ret);
+
+ hda_dsp_remove(sdev);
+}
+
+static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hda_dsp_resume(sdev);
+ if (ret < 0)
+ return ret;
+
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);
+}
+
+static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hda_dsp_runtime_resume(sdev);
+ if (ret < 0)
+ return ret;
+
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);
+}
+
+static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+{
+ if (sdev->first_boot) {
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+
+ /* Check if IMR boot is usable */
+ if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) {
+ hda->imrboot_supported = true;
+ debugfs_create_bool("skip_imr_boot",
+ 0644, sdev->debugfs_root,
+ &hda->skip_imr_boot);
+ }
+ }
+
+ return 0;
+}
+
+int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
+{
+ int ret;
+
+ ret = sof_mtl_set_ops(sdev, dsp_ops);
+ if (ret)
+ return ret;
+
+ /* probe/remove */
+ if (!sdev->dspless_mode_selected) {
+ dsp_ops->probe = lnl_hda_dsp_probe;
+ dsp_ops->remove = lnl_hda_dsp_remove;
+ }
+
+ /* post fw run */
+ dsp_ops->post_fw_run = lnl_dsp_post_fw_run;
+
+ /* PM */
+ if (!sdev->dspless_mode_selected) {
+ dsp_ops->resume = lnl_hda_dsp_resume;
+ dsp_ops->runtime_resume = lnl_hda_dsp_runtime_resume;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sof_lnl_set_ops, "SND_SOC_SOF_INTEL_LNL");
+
+/* Check if an SDW IRQ occurred */
+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");
+
+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");
+
+bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ u16 wake_sts;
+
+ /*
+ * we need to use the global HDaudio WAKEEN/STS to be able to
+ * detect wakes in low-power modes. The link-specific information
+ * is handled in the process_wakeen() helper, this helper only
+ * detects a SoundWire wake without identifying the link.
+ */
+ wake_sts = snd_hdac_chip_readw(bus, STATESTS);
+
+ /* 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,
+ .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,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .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_2_0,
+ .platform = "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
new file mode 100644
index 000000000000..2837f818ac51
--- /dev/null
+++ b/sound/soc/sof/intel/lnl.h
@@ -0,0 +1,21 @@
+/* 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) 2024 Intel Corporation
+ */
+
+#ifndef __SOF_INTEL_LNL_H
+#define __SOF_INTEL_LNL_H
+
+#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 8ae331faca4e..095dcf1a18e4 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
//
@@ -9,7 +9,9 @@
* Hardware interface for audio DSP on Meteorlake.
*/
+#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"
@@ -18,11 +20,13 @@
#include "hda-ipc.h"
#include "../sof-audio.h"
#include "mtl.h"
+#include "telemetry.h"
static const struct snd_sof_debugfs_map mtl_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},
};
static void mtl_ipc_host_done(struct snd_sof_dev *sdev)
@@ -74,6 +78,7 @@ bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
return false;
}
+EXPORT_SYMBOL_NS(mtl_dsp_check_ipc_irq, "SND_SOC_SOF_INTEL_MTL");
/* Check if an SDW IRQ occurred */
static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
@@ -144,6 +149,7 @@ void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);
}
+EXPORT_SYMBOL_NS(mtl_disable_ipc_interrupts, "SND_SOC_SOF_INTEL_MTL");
static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
@@ -170,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)
@@ -203,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;
}
@@ -222,12 +228,13 @@ 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;
}
return ret;
}
+EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL");
/* pre fw run operations */
static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
@@ -238,6 +245,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
u32 cpa;
u32 pgs;
int ret;
+ u32 dsppwrctl;
+ u32 dsppwrsts;
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) {
+ dsppwrctl = PTL_HFPWRCTL2;
+ dsppwrsts = PTL_HFPWRSTS2;
+ } else {
+ dsppwrctl = MTL_HFPWRCTL;
+ dsppwrsts = MTL_HFPWRSTS;
+ }
/* Set the DSP subsystem power on */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
@@ -257,14 +276,14 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
}
/* Power up gated-DSP-0 domain in order to access the DSP shim register block. */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, dsppwrctl,
MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG);
usleep_range(1000, 1010);
/* poll with timeout to check if operation successful */
pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK;
- ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts,
+ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, dsppwrsts, dsphfpwrsts,
(dsphfpwrsts & pgs) == pgs,
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
@@ -293,8 +312,12 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
}
/* Check if IMR boot is usable */
- if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT))
+ if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) {
hdev->imrboot_supported = true;
+ debugfs_create_bool("skip_imr_boot",
+ 0644, sdev->debugfs_root,
+ &hdev->skip_imr_boot);
+ }
}
hda_sdw_int_enable(sdev, true);
@@ -304,22 +327,18 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
- u32 romdbgsts;
- u32 romdbgerr;
u32 fwsts;
u32 fwlec;
+ hda_dsp_get_state(sdev, level);
fwsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_STS);
fwlec = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_ERROR);
- romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY);
- romdbgerr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY_ERROR);
-
- dev_err(sdev->dev, "ROM status: %#x, ROM error: %#x\n", fwsts, fwlec);
- dev_err(sdev->dev, "ROM debug status: %#x, ROM debug error: %#x\n", romdbgsts,
- romdbgerr);
- romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY + 0x8 * 3);
- dev_printk(level, sdev->dev, "ROM feature bit%s enabled\n",
- romdbgsts & BIT(24) ? "" : " not");
+
+ if (fwsts != 0xffffffff)
+ dev_err(sdev->dev, "Firmware state: %#x, status/error code: %#x\n",
+ fwsts, fwlec);
+
+ sof_ipc4_intel_dump_telemetry_state(sdev, flags);
}
static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)
@@ -361,11 +380,17 @@ static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
(dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
- if (ret < 0)
+ if (ret < 0) {
dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
__func__);
+ return ret;
+ }
- return ret;
+ /* set primary core mask and refcount to 1 */
+ sdev->enabled_cores_mask = BIT(SOF_DSP_PRIMARY_CORE);
+ sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 1;
+
+ return 0;
}
static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
@@ -388,10 +413,15 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
!(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);
- if (ret < 0)
+ if (ret < 0) {
dev_err(sdev->dev, "failed to power down primary core\n");
+ return ret;
+ }
- return ret;
+ sdev->enabled_cores_mask = 0;
+ sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 0;
+
+ return 0;
}
int mtl_power_down_dsp(struct snd_sof_dev *sdev)
@@ -420,13 +450,15 @@ int mtl_power_down_dsp(struct snd_sof_dev *sdev)
(dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
}
+EXPORT_SYMBOL_NS(mtl_power_down_dsp, "SND_SOC_SOF_INTEL_MTL");
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
- unsigned int status;
- u32 ipc_hdr;
+ unsigned int status, target_status;
+ u32 ipc_hdr, flags;
+ char *dump_msg;
int ret;
/* step 1: purge FW request */
@@ -449,7 +481,7 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
/* step 3: wait for IPC DONE bit from ROM */
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status,
((status & chip->ipc_ack_mask) == chip->ipc_ack_mask),
- HDA_DSP_REG_POLL_INTERVAL_US, MTL_DSP_PURGE_TIMEOUT_US);
+ HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_INIT_TIMEOUT_US);
if (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "timeout waiting for purge IPC done\n");
@@ -470,19 +502,58 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
mtl_enable_ipc_interrupts(sdev);
+ if (chip->rom_status_reg == MTL_DSP_ROM_STS) {
+ /*
+ * Workaround: when the ROM status register is pointing to
+ * the SRAM window (MTL_DSP_ROM_STS) the platform cannot catch
+ * ROM_INIT_DONE because of a very short timing window.
+ * Follow the recommendations and skip target state waiting.
+ */
+ return 0;
+ }
+
/*
- * ACE workaround: don't wait for ROM INIT.
- * The platform cannot catch ROM_INIT_DONE because of a very short
- * timing window. Follow the recommendations and skip this part.
+ * step 7:
+ * - Cold/Full boot: wait for ROM init to proceed to download the firmware
+ * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR)
*/
+ if (imr_boot)
+ target_status = FSR_STATE_FW_ENTERED;
+ else
+ target_status = FSR_STATE_INIT_DONE;
- return 0;
+ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
+ chip->rom_status_reg, status,
+ (FSR_TO_STATE_CODE(status) == target_status),
+ HDA_DSP_REG_POLL_INTERVAL_US,
+ chip->rom_init_timeout *
+ USEC_PER_MSEC);
+
+ if (!ret)
+ return 0;
+
+ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+ dev_err(sdev->dev,
+ "%s: timeout with rom_status_reg (%#x) read\n",
+ __func__, chip->rom_status_reg);
err:
- snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0);
+ flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
+
+ /* after max boot attempts make sure that the dump is printed */
+ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+ flags &= ~SOF_DBG_DUMP_OPTIONAL;
+
+ dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",
+ hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);
+ snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);
+ mtl_enable_interrupts(sdev, false);
mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
+
+ kfree(dump_msg);
return ret;
}
+EXPORT_SYMBOL_NS(mtl_dsp_cl_init, "SND_SOC_SOF_INTEL_MTL");
static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
@@ -601,18 +672,6 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return mtl_enable_interrupts(sdev, false);
}
-static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
- struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
-{
- struct hdac_stream *hstream = substream->runtime->private_data;
- u32 llp_l, llp_u;
-
- llp_l = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPL(hstream->index));
- llp_u = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPU(hstream->index));
- return ((u64)llp_u << 32) | llp_l;
-}
-
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;
@@ -643,48 +702,42 @@ static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
return 0;
}
-/* Meteorlake ops */
-struct snd_sof_dsp_ops sof_mtl_ops;
-EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
-
-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;
-
- sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
+ dsp_ops->core_get = mtl_dsp_core_get;
+ dsp_ops->core_put = mtl_dsp_core_put;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -693,17 +746,19 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
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_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_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+}
+EXPORT_SYMBOL_NS(sof_mtl_set_ops, "SND_SOC_SOF_INTEL_MTL");
const struct sof_intel_dsp_desc mtl_chip_info = {
.cores_num = 3,
@@ -714,7 +769,36 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.ipc_ack = MTL_DSP_REG_HFIPCXIDA,
.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
- .rom_status_reg = MTL_DSP_ROM_STS,
+ .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,
+ .rom_init_timeout = 300,
+ .ssp_count = MTL_SSP_COUNT,
+ .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+ .sdw_shim_base = SDW_SHIM_BASE_ACE,
+ .sdw_alh_base = SDW_ALH_BASE_ACE,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_common,
+ .enable_sdw_irq = mtl_enable_sdw_irq,
+ .check_sdw_irq = mtl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .check_ipc_irq = mtl_dsp_check_ipc_irq,
+ .cl_init = mtl_dsp_cl_init,
+ .power_down_dsp = mtl_power_down_dsp,
+ .disable_interrupts = mtl_dsp_disable_interrupts,
+ .hw_ip_version = SOF_INTEL_ACE_1_0,
+ .platform = "mtl",
+};
+
+const struct sof_intel_dsp_desc arl_s_chip_info = {
+ .cores_num = 2,
+ .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 = MTL_DSP_REG_HFFLGPXQWY,
.rom_init_timeout = 300,
.ssp_count = MTL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
@@ -724,10 +808,12 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = mtl_enable_sdw_irq,
.check_sdw_irq = mtl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = mtl_dsp_check_ipc_irq,
.cl_init = mtl_dsp_cl_init,
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = mtl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_1_0,
+ .platform = "arl",
};
-EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index 2794fe6e8139..e01a1536709e 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -3,24 +3,20 @@
* 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) 2020-2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2020-2022 Intel Corporation
*/
-/* HDA Registers */
-#define MTL_PPLCLLPL_BASE 0x948
-#define MTL_PPLCLLPU_STRIDE 0x10
-#define MTL_PPLCLLPL(x) (MTL_PPLCLLPL_BASE + (x) * MTL_PPLCLLPU_STRIDE)
-#define MTL_PPLCLLPU(x) (MTL_PPLCLLPL_BASE + 0x4 + (x) * MTL_PPLCLLPU_STRIDE)
-
/* DSP Registers */
#define MTL_HFDSSCS 0x1000
#define MTL_HFDSSCS_SPA_MASK BIT(16)
#define MTL_HFDSSCS_CPA_MASK BIT(24)
#define MTL_HFSNDWIE 0x114C
#define MTL_HFPWRCTL 0x1D18
+#define PTL_HFPWRCTL2 0x1D20
#define MTL_HfPWRCTL_WPIOXPG(x) BIT((x) + 8)
#define MTL_HFPWRCTL_WPDSPHPXPG BIT(0)
#define MTL_HFPWRSTS 0x1D1C
+#define PTL_HFPWRSTS2 0x1D24
#define MTL_HFPWRSTS_DSPHPXPGS_MASK BIT(0)
#define MTL_HFINTIPPTR 0x1108
#define MTL_IRQ_INTEN_L_HOST_IPC_MASK BIT(0)
@@ -62,7 +58,6 @@
#define MTL_DSP_IRQSTS_IPC BIT(0)
#define MTL_DSP_IRQSTS_SDW BIT(6)
-#define MTL_DSP_PURGE_TIMEOUT_US 20000000 /* 20s */
#define MTL_DSP_REG_POLL_INTERVAL_US 10 /* 10 us */
/* Memory windows */
@@ -77,15 +72,63 @@
#define MTL_DSP_ROM_STS MTL_SRAM_WINDOW_OFFSET(0) /* ROM status */
#define MTL_DSP_ROM_ERROR (MTL_SRAM_WINDOW_OFFSET(0) + 0x4) /* ROM error code */
-#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* ROM debug status */
-#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* ROM debug error code */
+#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* DSP core0 status */
+#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* DSP core0 error */
+
+/* FSR status codes */
+#define FSR_STATE_ROM_RESET_VECTOR_DONE 0x8
+#define FSR_STATE_ROM_PURGE_BOOT 0x9
+#define FSR_STATE_ROM_RESTORE_BOOT 0xA
+#define FSR_STATE_ROM_FW_ENTRY_POINT 0xB
+#define FSR_STATE_ROM_VALIDATE_PUB_KEY 0xC
+#define FSR_STATE_ROM_POWER_DOWN_HPSRAM 0xD
+#define FSR_STATE_ROM_POWER_DOWN_ULPSRAM 0xE
+#define FSR_STATE_ROM_POWER_UP_ULPSRAM_STACK 0xF
+#define FSR_STATE_ROM_POWER_UP_HPSRAM_DMA 0x10
+#define FSR_STATE_ROM_BEFORE_EP_POINTER_READ 0x11
+#define FSR_STATE_ROM_VALIDATE_MANIFEST 0x12
+#define FSR_STATE_ROM_VALIDATE_FW_MODULE 0x13
+#define FSR_STATE_ROM_PROTECT_IMR_REGION 0x14
+#define FSR_STATE_ROM_PUSH_MODEL_ROUTINE 0x15
+#define FSR_STATE_ROM_PULL_MODEL_ROUTINE 0x16
+#define FSR_STATE_ROM_VALIDATE_PKG_DIR 0x17
+#define FSR_STATE_ROM_VALIDATE_CPD 0x18
+#define FSR_STATE_ROM_VALIDATE_CSS_MAN_HEADER 0x19
+#define FSR_STATE_ROM_VALIDATE_BLOB_SVN 0x1A
+#define FSR_STATE_ROM_VERIFY_IFWI_PARTITION 0x1B
+#define FSR_STATE_ROM_REMOVE_ACCESS_CONTROL 0x1C
+#define FSR_STATE_ROM_AUTH_BYPASS 0x1D
+#define FSR_STATE_ROM_AUTH_ENABLED 0x1E
+#define FSR_STATE_ROM_INIT_DMA 0x1F
+#define FSR_STATE_ROM_PURGE_FW_ENTRY 0x20
+#define FSR_STATE_ROM_PURGE_FW_END 0x21
+#define FSR_STATE_ROM_CLEAN_UP_BSS_DONE 0x22
+#define FSR_STATE_ROM_IMR_RESTORE_ENTRY 0x23
+#define FSR_STATE_ROM_IMR_RESTORE_END 0x24
+#define FSR_STATE_ROM_FW_MANIFEST_IN_DMA_BUFF 0x25
+#define FSR_STATE_ROM_LOAD_CSE_MAN_TO_IMR 0x26
+#define FSR_STATE_ROM_LOAD_FW_MAN_TO_IMR 0x27
+#define FSR_STATE_ROM_LOAD_FW_CODE_TO_IMR 0x28
+#define FSR_STATE_ROM_FW_LOADING_DONE 0x29
+#define FSR_STATE_ROM_FW_CODE_LOADED 0x2A
+#define FSR_STATE_ROM_VERIFY_IMAGE_TYPE 0x2B
+#define FSR_STATE_ROM_AUTH_API_INIT 0x2C
+#define FSR_STATE_ROM_AUTH_API_PROC 0x2D
+#define FSR_STATE_ROM_AUTH_API_FIRST_BUSY 0x2E
+#define FSR_STATE_ROM_AUTH_API_FIRST_RESULT 0x2F
+#define FSR_STATE_ROM_AUTH_API_CLEANUP 0x30
+
#define MTL_DSP_REG_HfIMRIS1 0x162088
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)
+bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
+
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
-bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
-int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
+
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);
+
+int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
diff --git a/sound/soc/sof/intel/nvl.c b/sound/soc/sof/intel/nvl.c
new file mode 100644
index 000000000000..ff215151af2a
--- /dev/null
+++ b/sound/soc/sof/intel/nvl.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2025 Intel Corporation
+
+/*
+ * Hardware interface for audio DSP on NovaLake.
+ */
+
+#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"
+#include "nvl.h"
+
+int sof_nvl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
+{
+ /* Use PTL ops for NVL */
+ return sof_ptl_set_ops(sdev, dsp_ops);
+};
+EXPORT_SYMBOL_NS(sof_nvl_set_ops, "SND_SOC_SOF_INTEL_NVL");
+
+const struct sof_intel_dsp_desc nvl_s_chip_info = {
+ .cores_num = 2,
+ .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,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .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_4_0,
+};
+
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_PTL");
diff --git a/sound/soc/sof/intel/nvl.h b/sound/soc/sof/intel/nvl.h
new file mode 100644
index 000000000000..0be3fdfbbd48
--- /dev/null
+++ b/sound/soc/sof/intel/nvl.h
@@ -0,0 +1,14 @@
+/* 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_NVL_H
+#define __SOF_INTEL_NVL_H
+
+int sof_nvl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
+
+#endif /* __SOF_INTEL_NVL_H */
diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index 69cad5a6bc72..0bf7ee753bc3 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -3,7 +3,7 @@
// 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) 2018-2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2021 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -27,23 +27,23 @@ static const struct sof_dev_desc bxt_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &apl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/apl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/apl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/apl",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/apl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-apl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-apl.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
.ops = &sof_apl_ops,
@@ -59,23 +59,23 @@ static const struct sof_dev_desc glk_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &apl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/glk",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/glk",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/glk",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/glk",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-glk.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-glk.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-glk-nocodec.tplg",
.ops = &sof_apl_ops,
@@ -85,12 +85,8 @@ static const struct sof_dev_desc glk_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- { PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */
- .driver_data = (unsigned long)&bxt_desc},
- { PCI_DEVICE(0x8086, 0x1a98),/* BXT-T */
- .driver_data = (unsigned long)&bxt_desc},
- { PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */
- .driver_data = (unsigned long)&glk_desc},
+ { PCI_DEVICE_DATA(INTEL, HDA_APL, &bxt_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_GML, &glk_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -103,11 +99,13 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("SOF support for ApolloLake 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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index 8895508a0be6..de48640024e4 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -28,23 +28,23 @@ static const struct sof_dev_desc cnl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &cnl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/cnl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/cnl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/cnl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-cnl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-cnl.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -61,23 +61,23 @@ static const struct sof_dev_desc cfl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &cnl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/cnl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/cnl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/cnl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-cfl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-cfl.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -94,23 +94,23 @@ static const struct sof_dev_desc cml_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &cnl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/cnl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/cnl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/cnl",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/cnl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-cml.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-cml.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -120,16 +120,11 @@ static const struct sof_dev_desc cml_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- { PCI_DEVICE(0x8086, 0x9dc8), /* CNL-LP */
- .driver_data = (unsigned long)&cnl_desc},
- { PCI_DEVICE(0x8086, 0xa348), /* CNL-H */
- .driver_data = (unsigned long)&cfl_desc},
- { PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */
- .driver_data = (unsigned long)&cml_desc},
- { PCI_DEVICE(0x8086, 0x06c8), /* CML-H */
- .driver_data = (unsigned long)&cml_desc},
- { PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */
- .driver_data = (unsigned long)&cml_desc},
+ { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cfl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cml_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cml_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &cml_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -142,11 +137,13 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("SOF support for CannonLake 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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 5fb5a820693e..fd219e654844 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -3,7 +3,7 @@
// 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) 2018-2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2021 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -28,23 +28,23 @@ static const struct sof_dev_desc icl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &icl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/icl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/icl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/icl",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/icl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-icl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-icl.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
.ops = &sof_icl_ops,
@@ -60,23 +60,23 @@ static const struct sof_dev_desc jsl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &jsl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/jsl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/avs/jsl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/jsl",
+ [SOF_IPC_TYPE_4] = "intel/avs-lib/jsl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-jsl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-jsl.ri",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-jsl-nocodec.tplg",
.ops = &sof_cnl_ops,
@@ -86,14 +86,10 @@ static const struct sof_dev_desc jsl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- { PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */
- .driver_data = (unsigned long)&icl_desc},
- { PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */
- .driver_data = (unsigned long)&icl_desc},
- { PCI_DEVICE(0x8086, 0x38c8), /* ICL-N */
- .driver_data = (unsigned long)&jsl_desc},
- { PCI_DEVICE(0x8086, 0x4dc8), /* JSL-N */
- .driver_data = (unsigned long)&jsl_desc},
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &jsl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -106,11 +102,14 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("SOF support for IceLake 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_CNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c
new file mode 100644
index 000000000000..ae379c23f008
--- /dev/null
+++ b/sound/soc/sof/intel/pci-lnl.c
@@ -0,0 +1,84 @@
+// 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) 2023 Intel Corporation
+//
+// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.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,
+ .machines = snd_soc_acpi_intel_lnl_machines,
+ .alt_machines = snd_soc_acpi_intel_lnl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &lnl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/lnl",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-lnl.ri",
+ },
+ .nocodec_tplg_filename = "sof-lnl-nocodec.tplg",
+ .ops = &sof_lnl_ops,
+ .ops_init = sof_lnl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_lnl_driver = {
+ .name = "sof-audio-pci-intel-lnl",
+ .id_table = sof_pci_ids,
+ .probe = hda_pci_intel_probe,
+ .remove = sof_pci_remove,
+ .shutdown = sof_pci_shutdown,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_intel_lnl_driver);
+
+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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c
index e276e1e37fed..7b2533999195 100644
--- a/sound/soc/sof/intel/pci-mtl.c
+++ b/sound/soc/sof/intel/pci-mtl.c
@@ -3,7 +3,7 @@
// 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) 2018-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2022 Intel Corporation
//
// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
//
@@ -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,
@@ -29,20 +37,20 @@ static const struct sof_dev_desc mtl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &mtl_chip_info,
- .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_INTEL_IPC4,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/mtl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/sof-ipc4-lib/mtl",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/mtl",
},
.default_tplg_path = {
- [SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg",
},
.default_fw_filename = {
- [SOF_INTEL_IPC4] = "sof-mtl.ri",
+ [SOF_IPC_TYPE_4] = "sof-mtl.ri",
},
.nocodec_tplg_filename = "sof-mtl-nocodec.tplg",
.ops = &sof_mtl_ops,
@@ -50,10 +58,71 @@ static const struct sof_dev_desc mtl_desc = {
.ops_free = hda_ops_free,
};
+static const struct sof_dev_desc arl_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_arl_machines,
+ .alt_machines = snd_soc_acpi_intel_arl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &mtl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true, /* Only supported for HDaudio */
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/arl",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-arl.ri",
+ },
+ .nocodec_tplg_filename = "sof-arl-nocodec.tplg",
+ .ops = &sof_mtl_ops,
+ .ops_init = sof_mtl_ops_init,
+ .ops_free = hda_ops_free,
+};
+
+static const struct sof_dev_desc arl_s_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_arl_machines,
+ .alt_machines = snd_soc_acpi_intel_arl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &arl_s_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true, /* Only supported for HDaudio */
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/arl-s",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/arl-s",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ace-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-arl-s.ri",
+ },
+ .nocodec_tplg_filename = "sof-arl-nocodec.tplg",
+ .ops = &sof_mtl_ops,
+ .ops_init = sof_mtl_ops_init,
+ .ops_free = hda_ops_free,
+};
+
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- { PCI_DEVICE(0x8086, 0x7E28), /* MTL */
- .driver_data = (unsigned long)&mtl_desc},
+ { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, &arl_s_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ARL, &arl_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -66,11 +135,13 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("SOF support for MeteorLake 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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-nvl.c b/sound/soc/sof/intel/pci-nvl.c
new file mode 100644
index 000000000000..c499c14b93d5
--- /dev/null
+++ b/sound/soc/sof/intel/pci-nvl.c
@@ -0,0 +1,82 @@
+// 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.
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.h"
+#include "nvl.h"
+
+/* PantherLake ops */
+static struct snd_sof_dsp_ops sof_nvl_ops;
+
+static int sof_nvl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_nvl_set_ops(sdev, &sof_nvl_ops);
+}
+
+static const struct sof_dev_desc nvl_s_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_nvl_machines,
+ .alt_machines = snd_soc_acpi_intel_nvl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &nvl_s_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/nvl-s",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/nvl-s",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-nvl-s.ri",
+ },
+ .nocodec_tplg_filename = "sof-nvl-nocodec.tplg",
+ .ops = &sof_nvl_ops,
+ .ops_init = sof_nvl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, HDA_NVL_S, &nvl_s_desc) }, /* NVL-S */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_nvl_driver = {
+ .name = "sof-audio-pci-intel-nvl",
+ .id_table = sof_pci_ids,
+ .probe = hda_pci_intel_probe,
+ .remove = sof_pci_remove,
+ .shutdown = sof_pci_shutdown,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_intel_nvl_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF support for NovaLake 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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c
new file mode 100644
index 000000000000..68f6a9841633
--- /dev/null
+++ b/sound/soc/sof/intel/pci-ptl.c
@@ -0,0 +1,113 @@
+// 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) 2024 Intel Corporation.
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.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,
+ .machines = snd_soc_acpi_intel_ptl_machines,
+ .alt_machines = snd_soc_acpi_intel_ptl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &ptl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/ptl",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ptl",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-ptl.ri",
+ },
+ .nocodec_tplg_filename = "sof-ptl-nocodec.tplg",
+ .ops = &sof_ptl_ops,
+ .ops_init = sof_ptl_ops_init,
+};
+
+static const struct sof_dev_desc wcl_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_ptl_machines,
+ .alt_machines = snd_soc_acpi_intel_ptl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &wcl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/wcl",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/wcl",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-wcl.ri",
+ },
+ .nocodec_tplg_filename = "sof-ptl-nocodec.tplg",
+ .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 */
+ { PCI_DEVICE_DATA(INTEL, HDA_WCL, &wcl_desc) }, /* WCL */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_ptl_driver = {
+ .name = "sof-audio-pci-intel-ptl",
+ .id_table = sof_pci_ids,
+ .probe = hda_pci_intel_probe,
+ .remove = sof_pci_remove,
+ .shutdown = sof_pci_shutdown,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_intel_ptl_driver);
+
+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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c
index 5e69af6eed34..a16945dc35f7 100644
--- a/sound/soc/sof/intel/pci-skl.c
+++ b/sound/soc/sof/intel/pci-skl.c
@@ -3,7 +3,7 @@
// 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) 2018-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2022 Intel Corporation
//
#include <linux/module.h>
@@ -24,17 +24,17 @@ static struct sof_dev_desc skl_desc = {
.resindex_imr_base = -1,
.chip_info = &skl_chip_info,
.irqindex_host_ipc = -1,
- .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_INTEL_IPC4,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_INTEL_IPC4] = "intel/avs/skl",
+ [SOF_IPC_TYPE_4] = "intel/avs/skl",
},
.default_tplg_path = {
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-skl-nocodec.tplg",
.ops = &sof_skl_ops,
@@ -49,17 +49,17 @@ static struct sof_dev_desc kbl_desc = {
.resindex_imr_base = -1,
.chip_info = &skl_chip_info,
.irqindex_host_ipc = -1,
- .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_INTEL_IPC4,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_INTEL_IPC4] = "intel/avs/kbl",
+ [SOF_IPC_TYPE_4] = "intel/avs/kbl",
},
.default_tplg_path = {
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_4] = "intel/avs-tplg",
},
.default_fw_filename = {
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-kbl-nocodec.tplg",
.ops = &sof_skl_ops,
@@ -69,10 +69,8 @@ static struct sof_dev_desc kbl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- /* Sunrise Point-LP */
- { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&skl_desc},
- /* KBL */
- { PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc},
+ { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &kbl_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -85,11 +83,13 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("SOF support for SkyLake 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_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index ca37ff1bbd2a..437c43819825 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -3,7 +3,7 @@
// 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) 2018-2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2021 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -28,23 +28,23 @@ static const struct sof_dev_desc tgl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/tgl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/tgl",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-tgl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-tgl.ri",
+ [SOF_IPC_TYPE_4] = "sof-tgl.ri",
},
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -61,23 +61,23 @@ static const struct sof_dev_desc tglh_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tglh_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/tgl-h",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/tgl-h",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/tgl-h",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/tgl-h",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-tgl-h.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-tgl-h.ri",
+ [SOF_IPC_TYPE_4] = "sof-tgl-h.ri",
},
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -93,23 +93,23 @@ static const struct sof_dev_desc ehl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &ehl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/ehl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/ehl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/ehl",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ehl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-ehl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-ehl.ri",
+ [SOF_IPC_TYPE_4] = "sof-ehl.ri",
},
.nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -126,23 +126,23 @@ static const struct sof_dev_desc adls_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &adls_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/adl-s",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-s",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/adl-s",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-s",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-adl-s.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-adl-s.ri",
+ [SOF_IPC_TYPE_4] = "sof-adl-s.ri",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -159,23 +159,23 @@ static const struct sof_dev_desc adl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/adl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/adl",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-adl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-adl.ri",
+ [SOF_IPC_TYPE_4] = "sof-adl.ri",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -183,7 +183,7 @@ static const struct sof_dev_desc adl_desc = {
.ops_free = hda_ops_free,
};
-static const struct sof_dev_desc adl_n_desc = {
+static const struct sof_dev_desc adln_desc = {
.machines = snd_soc_acpi_intel_adl_machines,
.alt_machines = snd_soc_acpi_intel_adl_sdw_machines,
.use_acpi_target_states = true,
@@ -192,23 +192,23 @@ static const struct sof_dev_desc adl_n_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/adl-n",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/adl-n",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/adl-n",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/adl-n",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-adl-n.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-adl-n.ri",
+ [SOF_IPC_TYPE_4] = "sof-adl-n.ri",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -225,23 +225,23 @@ static const struct sof_dev_desc rpls_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &adls_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/rpl-s",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl-s",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/rpl-s",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl-s",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-rpl-s.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-rpl-s.ri",
+ [SOF_IPC_TYPE_4] = "sof-rpl-s.ri",
},
.nocodec_tplg_filename = "sof-rpl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -258,23 +258,23 @@ static const struct sof_dev_desc rpl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3) | BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_3,
.dspless_mode_supported = true, /* Only supported for HDaudio */
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
- [SOF_INTEL_IPC4] = "intel/avs/rpl",
+ [SOF_IPC_TYPE_3] = "intel/sof",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/rpl",
},
.default_lib_path = {
- [SOF_INTEL_IPC4] = "intel/avs-lib/rpl",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/rpl",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
- [SOF_INTEL_IPC4] = "intel/avs-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-rpl.ri",
- [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+ [SOF_IPC_TYPE_3] = "sof-rpl.ri",
+ [SOF_IPC_TYPE_4] = "sof-rpl.ri",
},
.nocodec_tplg_filename = "sof-rpl-nocodec.tplg",
.ops = &sof_tgl_ops,
@@ -284,36 +284,21 @@ static const struct sof_dev_desc rpl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */
- .driver_data = (unsigned long)&tgl_desc},
- { PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */
- .driver_data = (unsigned long)&tglh_desc},
- { PCI_DEVICE(0x8086, 0x4b55), /* EHL */
- .driver_data = (unsigned long)&ehl_desc},
- { PCI_DEVICE(0x8086, 0x4b58), /* EHL */
- .driver_data = (unsigned long)&ehl_desc},
- { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */
- .driver_data = (unsigned long)&adls_desc},
- { PCI_DEVICE(0x8086, 0x7a50), /* RPL-S */
- .driver_data = (unsigned long)&rpls_desc},
- { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */
- .driver_data = (unsigned long)&adl_desc},
- { PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */
- .driver_data = (unsigned long)&adl_desc},
- { PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */
- .driver_data = (unsigned long)&rpl_desc},
- { PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */
- .driver_data = (unsigned long)&rpl_desc},
- { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
- .driver_data = (unsigned long)&adl_desc},
- { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
- .driver_data = (unsigned long)&adl_desc},
- { PCI_DEVICE(0x8086, 0x51ce), /* RPL-M */
- .driver_data = (unsigned long)&rpl_desc},
- { PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */
- .driver_data = (unsigned long)&rpl_desc},
- { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
- .driver_data = (unsigned long)&adl_n_desc},
+ { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tglh_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adls_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &rpls_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &rpl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &rpl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adln_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -326,11 +311,14 @@ 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);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_DESCRIPTION("SOF support for TigerLake 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_CNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c
index 8c22a00266c0..0c11cc1fd820 100644
--- a/sound/soc/sof/intel/pci-tng.c
+++ b/sound/soc/sof/intel/pci-tng.c
@@ -3,7 +3,7 @@
// 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) 2018-2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2021 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -132,7 +132,7 @@ irq:
return ret;
}
-struct snd_sof_dsp_ops sof_tng_ops = {
+const struct snd_sof_dsp_ops sof_tng_ops = {
/* device init */
.probe = tangier_pci_probe,
@@ -208,16 +208,16 @@ static const struct sof_dev_desc tng_desc = {
.resindex_imr_base = 0,
.irqindex_host_ipc = -1,
.chip_info = &tng_chip_info,
- .ipc_supported_mask = BIT(SOF_IPC),
- .ipc_default = SOF_IPC,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
.default_fw_path = {
- [SOF_IPC] = "intel/sof",
+ [SOF_IPC_TYPE_3] = "intel/sof",
},
.default_tplg_path = {
- [SOF_IPC] = "intel/sof-tplg",
+ [SOF_IPC_TYPE_3] = "intel/sof-tplg",
},
.default_fw_filename = {
- [SOF_IPC] = "sof-byt.ri",
+ [SOF_IPC_TYPE_3] = "sof-byt.ri",
},
.nocodec_tplg_filename = "sof-byt.tplg",
.ops = &sof_tng_ops,
@@ -225,8 +225,7 @@ static const struct sof_dev_desc tng_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
- { PCI_DEVICE(0x8086, 0x119a),
- .driver_data = (unsigned long)&tng_desc},
+ { PCI_DEVICE_DATA(INTEL, SST_TNG, &tng_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -239,13 +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_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);
+MODULE_DESCRIPTION("SOF support for Tangier platforms");
+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..c1db735237f8
--- /dev/null
+++ b/sound/soc/sof/intel/ptl.c
@@ -0,0 +1,158 @@
+// 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_mic_privacy_work(struct work_struct *work)
+{
+ struct sof_intel_hda_dev *hdev = container_of(work,
+ struct sof_intel_hda_dev,
+ mic_privacy.work);
+ struct hdac_bus *bus = &hdev->hbus.core;
+ struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev);
+ bool state;
+
+ /*
+ * The microphone privacy state is only available via Soundwire shim
+ * in PTL
+ * The work is only scheduled on change.
+ */
+ state = hdac_bus_eml_get_mic_privacy_state(bus, 1,
+ AZX_REG_ML_LEPTR_ID_SDW);
+ sof_ipc4_mic_privacy_state_change(sdev, state);
+}
+
+static void sof_ptl_process_mic_privacy(struct snd_sof_dev *sdev, bool alt,
+ int elid)
+{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW)
+ return;
+
+ /*
+ * Schedule the work to read the microphone privacy state and send IPC
+ * message about the new state to the firmware
+ */
+ schedule_work(&hdev->mic_privacy.work);
+}
+
+static void sof_ptl_set_mic_privacy(struct snd_sof_dev *sdev,
+ struct sof_ipc4_intel_mic_privacy_cap *caps)
+{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+ 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));
+
+ INIT_WORK(&hdev->mic_privacy.work, sof_ptl_mic_privacy_work);
+ hdev->mic_privacy.active = true;
+}
+
+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,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .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,
+ .platform = "ptl",
+};
+
+const struct sof_intel_dsp_desc wcl_chip_info = {
+ .cores_num = 3,
+ .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,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .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,
+ .platform = "wcl",
+};
+
+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 48428ccbcfe0..33d27cb5f1d7 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -3,7 +3,7 @@
* 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) 2017 Intel Corporation. All rights reserved.
+ * Copyright(c) 2017 Intel Corporation
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
@@ -21,6 +21,9 @@ enum sof_intel_hw_ip_version {
SOF_INTEL_CAVS_2_0, /* IceLake, JasperLake */
SOF_INTEL_CAVS_2_5, /* TigerLake, AlderLake */
SOF_INTEL_ACE_1_0, /* MeteorLake */
+ SOF_INTEL_ACE_2_0, /* LunarLake */
+ SOF_INTEL_ACE_3_0, /* PantherLake */
+ SOF_INTEL_ACE_4_0, /* NovaLake */
};
/*
@@ -184,17 +187,22 @@ struct sof_intel_dsp_desc {
u32 sdw_alh_base;
u32 d0i3_offset;
u32 quirks;
+ const char *platform;
enum sof_intel_hw_ip_version hw_ip_version;
int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
+ 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);
};
-extern struct snd_sof_dsp_ops sof_tng_ops;
+extern const struct snd_sof_dsp_ops sof_tng_ops;
extern const struct sof_intel_dsp_desc tng_chip_info;
diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c
index d24e64e71b58..90a3c2e2334c 100644
--- a/sound/soc/sof/intel/skl.c
+++ b/sound/soc/sof/intel/skl.c
@@ -3,7 +3,7 @@
// 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) 2018-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2022 Intel Corporation
//
/*
@@ -50,7 +50,7 @@ static int skl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
/* skylake ops */
struct snd_sof_dsp_ops sof_skl_ops;
-EXPORT_SYMBOL_NS(sof_skl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_skl_ops, "SND_SOC_SOF_INTEL_HDA_COMMON");
int sof_skl_ops_init(struct snd_sof_dev *sdev)
{
@@ -62,7 +62,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev)
/* probe/remove/shutdown */
sof_skl_ops.shutdown = hda_dsp_shutdown;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -96,7 +96,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_skl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_skl_ops_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
const struct sof_intel_dsp_desc skl_chip_info = {
.cores_num = 2,
@@ -113,5 +113,6 @@ const struct sof_intel_dsp_desc skl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_5,
+ .platform = "skl",
};
-EXPORT_SYMBOL_NS(skl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(skl_chip_info, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/telemetry.c b/sound/soc/sof/intel/telemetry.c
new file mode 100644
index 000000000000..dcaaf03599db
--- /dev/null
+++ b/sound/soc/sof/intel/telemetry.c
@@ -0,0 +1,96 @@
+// 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) 2023 Intel Corporation
+
+/* telemetry data queried from debug window */
+
+#include <sound/sof/ipc4/header.h>
+#include <sound/sof/xtensa.h>
+#include "../ipc4-priv.h"
+#include "../sof-priv.h"
+#include "hda.h"
+#include "telemetry.h"
+
+void sof_ipc4_intel_dump_telemetry_state(struct snd_sof_dev *sdev, u32 flags)
+{
+ static const char invalid_slot_msg[] = "Core dump is not available due to";
+ struct sof_ipc4_telemetry_slot_data *telemetry_data;
+ struct sof_ipc_dsp_oops_xtensa *xoops;
+ struct xtensa_arch_block *block;
+ u32 slot_offset;
+ char *level;
+
+ level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
+
+ slot_offset = sof_ipc4_find_debug_slot_offset_by_type(sdev, SOF_IPC4_DEBUG_SLOT_TELEMETRY);
+ if (!slot_offset)
+ return;
+
+ telemetry_data = kmalloc(sizeof(*telemetry_data), GFP_KERNEL);
+ if (!telemetry_data)
+ return;
+ sof_mailbox_read(sdev, slot_offset, telemetry_data, sizeof(*telemetry_data));
+ if (telemetry_data->separator != XTENSA_CORE_DUMP_SEPARATOR) {
+ dev_err(sdev->dev, "%s invalid separator %#x\n", invalid_slot_msg,
+ telemetry_data->separator);
+ goto free_telemetry_data;
+ }
+
+ block = kmalloc(sizeof(*block), GFP_KERNEL);
+ if (!block)
+ goto free_telemetry_data;
+
+ sof_mailbox_read(sdev, slot_offset + sizeof(*telemetry_data), block, sizeof(*block));
+ if (block->soc != XTENSA_SOC_INTEL_ADSP) {
+ dev_err(sdev->dev, "%s invalid SOC %d\n", invalid_slot_msg, block->soc);
+ goto free_block;
+ }
+
+ if (telemetry_data->hdr.id[0] != COREDUMP_HDR_ID0 ||
+ telemetry_data->hdr.id[1] != COREDUMP_HDR_ID1 ||
+ telemetry_data->arch_hdr.id != COREDUMP_ARCH_HDR_ID) {
+ dev_err(sdev->dev, "%s invalid coredump header %c%c, arch hdr %c\n",
+ invalid_slot_msg, telemetry_data->hdr.id[0],
+ telemetry_data->hdr.id[1],
+ telemetry_data->arch_hdr.id);
+ goto free_block;
+ }
+
+ switch (block->toolchain) {
+ case XTENSA_TOOL_CHAIN_ZEPHYR:
+ dev_printk(level, sdev->dev, "FW is built with Zephyr toolchain\n");
+ break;
+ case XTENSA_TOOL_CHAIN_XCC:
+ dev_printk(level, sdev->dev, "FW is built with XCC toolchain\n");
+ break;
+ default:
+ dev_printk(level, sdev->dev, "Unknown toolchain is used\n");
+ break;
+ }
+
+ xoops = kzalloc(struct_size(xoops, ar, XTENSA_CORE_AR_REGS_COUNT), GFP_KERNEL);
+ if (!xoops)
+ goto free_block;
+
+ xoops->exccause = block->exccause;
+ xoops->excvaddr = block->excvaddr;
+ xoops->epc1 = block->pc;
+ xoops->ps = block->ps;
+ xoops->sar = block->sar;
+
+ xoops->plat_hdr.numaregs = XTENSA_CORE_AR_REGS_COUNT;
+ memcpy((void *)xoops->ar, block->ar, XTENSA_CORE_AR_REGS_COUNT * sizeof(u32));
+
+ sof_oops(sdev, level, xoops);
+ sof_stack(sdev, level, xoops, NULL, 0);
+
+ kfree(xoops);
+free_block:
+ kfree(block);
+free_telemetry_data:
+ kfree(telemetry_data);
+}
+EXPORT_SYMBOL_NS(sof_ipc4_intel_dump_telemetry_state, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/telemetry.h b/sound/soc/sof/intel/telemetry.h
new file mode 100644
index 000000000000..e4e91943a41a
--- /dev/null
+++ b/sound/soc/sof/intel/telemetry.h
@@ -0,0 +1,35 @@
+/* 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) 2023 Intel Corporation
+ *
+ * telemetry data in debug windows
+ */
+
+#ifndef _SOF_INTEL_TELEMETRY_H
+#define _SOF_INTEL_TELEMETRY_H
+
+#include "../ipc4-telemetry.h"
+
+struct xtensa_arch_block {
+ u8 soc; /* should be equal to XTENSA_SOC_INTEL_ADSP */
+ u16 version;
+ u8 toolchain; /* ZEPHYR or XCC */
+
+ u32 pc;
+ u32 exccause;
+ u32 excvaddr;
+ u32 sar;
+ u32 ps;
+ u32 scompare1;
+ u32 ar[XTENSA_CORE_AR_REGS_COUNT];
+ u32 lbeg;
+ u32 lend;
+ u32 lcount;
+} __packed;
+
+void sof_ipc4_intel_dump_telemetry_state(struct snd_sof_dev *sdev, u32 flags);
+
+#endif /* _SOF_INTEL_TELEMETRY_H */
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 8e2b07e1612b..e68bbe685ba3 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright(c) 2020 Intel Corporation. All rights reserved.
+// Copyright(c) 2020 Intel Corporation
//
// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
//
@@ -22,6 +22,13 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
{"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
};
+static const struct snd_sof_debugfs_map tgl_ipc4_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, SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY},
+};
+
static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
@@ -56,7 +63,6 @@ static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
/* Tigerlake ops */
struct snd_sof_dsp_ops sof_tgl_ops;
-EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_tgl_ops_init(struct snd_sof_dev *sdev)
{
@@ -66,7 +72,7 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
/* probe/remove/shutdown */
sof_tgl_ops.shutdown = hda_dsp_shutdown_dma_flush;
- if (sdev->pdata->ipc_type == SOF_IPC) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
/* doorbell */
sof_tgl_ops.irq_thread = cnl_ipc_irq_thread;
@@ -75,14 +81,16 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
/* debug */
sof_tgl_ops.ipc_dump = cnl_ipc_dump;
+ sof_tgl_ops.debug_map = tgl_dsp_debugfs;
+ sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs);
sof_tgl_ops.set_power_state = hda_dsp_set_power_state_ipc3;
}
- if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -91,6 +99,8 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
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;
@@ -102,6 +112,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
/* debug */
sof_tgl_ops.ipc_dump = cnl_ipc4_dump;
+ sof_tgl_ops.dbg_dump = hda_ipc4_dsp_dump;
+ sof_tgl_ops.debug_map = tgl_ipc4_dsp_debugfs;
+ sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_ipc4_dsp_debugfs);
sof_tgl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
}
@@ -109,10 +122,6 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_tgl_ops);
- /* debug */
- sof_tgl_ops.debug_map = tgl_dsp_debugfs;
- sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs);
-
/* pre/post fw run */
sof_tgl_ops.post_fw_run = hda_dsp_post_fw_run;
@@ -125,7 +134,6 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_tgl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc tgl_chip_info = {
/* Tigerlake , Alderlake */
@@ -147,13 +155,15 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "tgl",
};
-EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc tglh_chip_info = {
/* Tigerlake-H */
@@ -175,13 +185,15 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "tgl",
};
-EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc ehl_chip_info = {
/* Elkhartlake */
@@ -203,13 +215,15 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "ehl",
};
-EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc adls_chip_info = {
/* Alderlake-S */
@@ -231,10 +245,12 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "adl",
};
-EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/tracepoints.c b/sound/soc/sof/intel/tracepoints.c
new file mode 100644
index 000000000000..9e3260a062c2
--- /dev/null
+++ b/sound/soc/sof/intel/tracepoints.c
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+#define CREATE_TRACE_POINTS
+#include <trace/events/sof_intel.h>
+
+EXPORT_TRACEPOINT_SYMBOL(sof_intel_hda_irq);
diff --git a/sound/soc/sof/iomem-utils.c b/sound/soc/sof/iomem-utils.c
index 3f57f6cf6542..f6cb79082672 100644
--- a/sound/soc/sof/iomem-utils.c
+++ b/sound/soc/sof/iomem-utils.c
@@ -3,14 +3,14 @@
// 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) 2018-2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2018-2022 Intel Corporation
//
// Author: Keyon Jie <yang.jie@linux.intel.com>
//
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/platform_device.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
index b53abc923026..3fb8d3e9dc6a 100644
--- a/sound/soc/sof/ipc.c
+++ b/sound/soc/sof/ipc.c
@@ -3,7 +3,7 @@
// 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) 2018 Intel Corporation. All rights reserved.
+// Copyright(c) 2018 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
@@ -165,12 +165,12 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
switch (sdev->pdata->ipc_type) {
#if defined(CONFIG_SND_SOC_SOF_IPC3)
- case SOF_IPC:
+ case SOF_IPC_TYPE_3:
ops = &ipc3_ops;
break;
#endif
-#if defined(CONFIG_SND_SOC_SOF_INTEL_IPC4)
- case SOF_INTEL_IPC4:
+#if defined(CONFIG_SND_SOC_SOF_IPC4)
+ case SOF_IPC_TYPE_4:
ops = &ipc4_ops;
break;
#endif
diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c
index a8deec7dc021..2b1befad6d5c 100644
--- a/sound/soc/sof/ipc3-control.c
+++ b/sound/soc/sof/ipc3-control.c
@@ -3,7 +3,7 @@
// 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) 2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2021 Intel Corporation
//
//
diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c
index 1d3bca2d28dd..6ec391fd39a9 100644
--- a/sound/soc/sof/ipc3-dtrace.c
+++ b/sound/soc/sof/ipc3-dtrace.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
@@ -126,7 +126,7 @@ static int trace_filter_parse(struct snd_sof_dev *sdev, char *string,
capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY;
entry = strchr(entry + 1, entry_delimiter[0]);
}
- *out = kmalloc(capacity * sizeof(**out), GFP_KERNEL);
+ *out = kmalloc_array(capacity, sizeof(**out), GFP_KERNEL);
if (!*out)
return -ENOMEM;
@@ -172,7 +172,6 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
goto error;
}
ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
- pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
error:
@@ -186,7 +185,6 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user
struct snd_sof_dfsentry *dfse = file->private_data;
struct sof_ipc_trace_filter_elem *elems = NULL;
struct snd_sof_dev *sdev = dfse->sdev;
- loff_t pos = 0;
int num_elems;
char *string;
int ret;
@@ -197,15 +195,9 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user
return -EINVAL;
}
- string = kmalloc(count + 1, GFP_KERNEL);
- if (!string)
- return -ENOMEM;
-
- /* assert null termination */
- string[count] = 0;
- ret = simple_write_to_buffer(string, count, &pos, from, count);
- if (ret < 0)
- goto error;
+ string = memdup_user_nul(from, count);
+ if (IS_ERR(string))
+ return PTR_ERR(string);
ret = trace_filter_parse(sdev, string, &num_elems, &elems);
if (ret < 0)
@@ -501,7 +493,7 @@ static int ipc3_dtrace_init(struct snd_sof_dev *sdev)
int ret;
/* dtrace is only supported with SOF_IPC */
- if (sdev->pdata->ipc_type != SOF_IPC)
+ if (sdev->pdata->ipc_type != SOF_IPC_TYPE_3)
return -EOPNOTSUPP;
if (sdev->fw_trace_data) {
diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c
index 28218766d211..7e9c76d5b2c9 100644
--- a/sound/soc/sof/ipc3-loader.c
+++ b/sound/soc/sof/ipc3-loader.c
@@ -3,7 +3,7 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
#include <linux/firmware.h>
#include "sof-priv.h"
@@ -148,6 +148,8 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
head = (struct sof_ext_man_header *)fw->data;
remaining = head->full_size - head->header_size;
+ if (remaining < 0 || remaining > sdev->basefw.fw->size)
+ return -EINVAL;
ext_man_size = ipc3_fw_ext_man_size(sdev, fw);
/* Assert firmware starts with extended manifest */
@@ -191,6 +193,9 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
case SOF_EXT_MAN_ELEM_CC_VERSION:
ret = ipc3_fw_ext_man_get_cc_info(sdev, elem_hdr);
break;
+ case SOF_EXT_MAN_ELEM_PROBE_INFO:
+ dev_dbg(sdev->dev, "Probe info (not parsed)\n");
+ break;
case SOF_EXT_MAN_ELEM_DBG_ABI:
ret = ipc3_fw_ext_man_get_dbg_abi_info(sdev, elem_hdr);
break;
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 304faf6425ab..90ef5d99f626 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -3,7 +3,7 @@
// 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) 2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2021 Intel Corporation
//
//
@@ -17,7 +17,7 @@ static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_ipc_stream stream;
struct snd_sof_pcm *spcm;
@@ -42,7 +42,7 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
struct snd_sof_platform_stream_params *platform_params)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_pcm_runtime *runtime = substream->runtime;
struct sof_ipc_pcm_params_reply ipc_params_reply;
@@ -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;
}
@@ -142,7 +143,7 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_ipc_stream stream;
struct snd_sof_pcm *spcm;
@@ -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;
}
@@ -309,6 +310,23 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = private->dai_config->afe.channels;
channels->max = private->dai_config->afe.channels;
+ snd_mask_none(fmt);
+
+ switch (private->dai_config->afe.format) {
+ case SOF_IPC_FRAME_S16_LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ break;
+ case SOF_IPC_FRAME_S24_4LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ break;
+ case SOF_IPC_FRAME_S32_LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+ break;
+ default:
+ dev_err(component->dev, "Not available format!\n");
+ return -EINVAL;
+ }
+
dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
channels->min, channels->max);
@@ -367,6 +385,42 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n",
channels->min, channels->max);
break;
+ case SOF_DAI_IMX_MICFIL:
+ rate->min = private->dai_config->micfil.pdm_rate;
+ rate->max = private->dai_config->micfil.pdm_rate;
+ channels->min = private->dai_config->micfil.pdm_ch;
+ channels->max = private->dai_config->micfil.pdm_ch;
+
+ dev_dbg(component->dev,
+ "MICFIL PDM rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "MICFIL PDM channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
+ case SOF_DAI_AMD_SDW:
+ /* change the default trigger sequence as per HW implementation */
+ for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) {
+ struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+ fe->dai_link->trigger[SNDRV_PCM_STREAM_PLAYBACK] =
+ SND_SOC_DPCM_TRIGGER_POST;
+ }
+
+ for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
+ struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+ fe->dai_link->trigger[SNDRV_PCM_STREAM_CAPTURE] =
+ SND_SOC_DPCM_TRIGGER_POST;
+ }
+ rate->min = private->dai_config->acp_sdw.rate;
+ rate->max = private->dai_config->acp_sdw.rate;
+ channels->min = private->dai_config->acp_sdw.channels;
+ channels->max = private->dai_config->acp_sdw.channels;
+
+ dev_dbg(component->dev,
+ "AMD_SDW rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
default:
dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
break;
@@ -381,4 +435,5 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
.trigger = sof_ipc3_pcm_trigger,
.dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
.reset_hw_params_during_stop = true,
+ .d0i3_supported_in_s0ix = true,
};
diff --git a/sound/soc/sof/ipc3-priv.h b/sound/soc/sof/ipc3-priv.h
index 0bbca418e67e..866c5f67b91a 100644
--- a/sound/soc/sof/ipc3-priv.h
+++ b/sound/soc/sof/ipc3-priv.h
@@ -3,7 +3,7 @@
* 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) 2021 Intel Corporation. All rights reserved.
+ * Copyright(c) 2021 Intel Corporation
*/
#ifndef __SOUND_SOC_SOF_IPC3_PRIV_H
@@ -36,7 +36,7 @@ static inline int sof_dtrace_host_init(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmatb,
struct sof_ipc_dma_trace_params_ext *dtrace_params)
{
- struct snd_sof_dsp_ops *dsp_ops = sdev->pdata->desc->ops;
+ const struct snd_sof_dsp_ops *dsp_ops = sdev->pdata->desc->ops;
if (dsp_ops->trace_init)
return dsp_ops->trace_init(sdev, dmatb, dtrace_params);
@@ -46,7 +46,7 @@ static inline int sof_dtrace_host_init(struct snd_sof_dev *sdev,
static inline int sof_dtrace_host_release(struct snd_sof_dev *sdev)
{
- struct snd_sof_dsp_ops *dsp_ops = sdev->pdata->desc->ops;
+ const struct snd_sof_dsp_ops *dsp_ops = sdev->pdata->desc->ops;
if (dsp_ops->trace_release)
return dsp_ops->trace_release(sdev);
@@ -56,7 +56,7 @@ static inline int sof_dtrace_host_release(struct snd_sof_dev *sdev)
static inline int sof_dtrace_host_trigger(struct snd_sof_dev *sdev, int cmd)
{
- struct snd_sof_dsp_ops *dsp_ops = sdev->pdata->desc->ops;
+ const struct snd_sof_dsp_ops *dsp_ops = sdev->pdata->desc->ops;
if (dsp_ops->trace_trigger)
return dsp_ops->trace_trigger(sdev, cmd);
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index ba4ef290b634..f449362a2905 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -3,7 +3,7 @@
// 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) 2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2021 Intel Corporation
//
//
@@ -20,6 +20,9 @@
/* size of tplg ABI in bytes */
#define SOF_IPC3_TPLG_ABI_SIZE 3
+/* Base of SOF_DAI_INTEL_ALH, this should be aligned with SOC_SDW_INTEL_BIDIR_PDI_BASE */
+#define INTEL_ALH_DAI_INDEX_BASE 2
+
struct sof_widget_data {
int ctrl_type;
int ipc_cmd;
@@ -72,6 +75,8 @@ static const struct sof_topology_token buffer_tokens[] = {
offsetof(struct sof_ipc_buffer, size)},
{SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_buffer, caps)},
+ {SOF_TKN_BUF_FLAGS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_buffer, flags)},
};
/* DAI */
@@ -286,6 +291,24 @@ static const struct sof_topology_token acpi2s_tokens[] = {
offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
};
+/* MICFIL PDM */
+static const struct sof_topology_token micfil_pdm_tokens[] = {
+ {SOF_TKN_IMX_MICFIL_RATE,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_micfil_params, pdm_rate)},
+ {SOF_TKN_IMX_MICFIL_CH,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_micfil_params, pdm_ch)},
+};
+
+/* ACP_SDW */
+static const struct sof_topology_token acp_sdw_tokens[] = {
+ {SOF_TKN_AMD_ACP_SDW_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_sdw_params, rate)},
+ {SOF_TKN_AMD_ACP_SDW_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_sdw_params, channels)},
+};
+
/* Core tokens */
static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -322,6 +345,9 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
[SOF_ACPI2S_TOKENS] = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)},
+ [SOF_MICFIL_TOKENS] = {"MICFIL PDM tokens",
+ micfil_pdm_tokens, ARRAY_SIZE(micfil_pdm_tokens)},
+ [SOF_ACP_SDW_TOKENS] = {"ACP_SDW tokens", acp_sdw_tokens, ARRAY_SIZE(acp_sdw_tokens)},
};
/**
@@ -493,6 +519,7 @@ static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc_pipe_new *pipeline;
struct snd_sof_widget *comp_swidget;
int ret;
@@ -545,6 +572,7 @@ static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
swidget->dynamic_pipeline_widget);
swidget->core = pipeline->core;
+ spipe->core_mask |= BIT(pipeline->core);
return 0;
@@ -1136,6 +1164,37 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_da
return 0;
}
+static int sof_link_micfil_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
+ struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
+{
+ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
+ struct sof_dai_private_data *private = dai->private;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ config->hdr.size = size;
+
+ /* parse the required set of MICFIL PDM tokens based on num_hw_cfgs */
+ ret = sof_update_ipc_object(scomp, &config->micfil, SOF_MICFIL_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
+
+ dev_info(scomp->dev, "MICFIL PDM config dai_index %d channel %d rate %d\n",
+ config->dai_index, config->micfil.pdm_ch, config->micfil.pdm_rate);
+
+ dai->number_configs = 1;
+ dai->current_config = 0;
+ private->dai_config = kmemdup(config, size, GFP_KERNEL);
+ if (!private->dai_config)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
{
@@ -1174,6 +1233,7 @@ static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
+ int ret;
/* handle master/slave and inverted clocks */
sof_dai_set_format(hw_config, config);
@@ -1182,12 +1242,14 @@ static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_
memset(&config->acpbt, 0, sizeof(config->acpbt));
config->hdr.size = size;
- config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
- config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ ret = sof_update_ipc_object(scomp, &config->acpbt, SOF_ACPI2S_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
- dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n",
+ dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d tdm_mode %d\n",
config->dai_index, config->acpbt.tdm_slots,
- config->acpbt.fsync_rate);
+ config->acpbt.fsync_rate, config->acpbt.tdm_mode);
dai->number_configs = 1;
dai->current_config = 0;
@@ -1265,6 +1327,34 @@ static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_
return 0;
}
+static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
+ struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
+{
+ struct sof_dai_private_data *private = dai->private;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* parse the required set of ACP_SDW tokens based on num_hw_cfgs */
+ ret = sof_update_ipc_object(scomp, &config->acp_sdw, SOF_ACP_SDW_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
+
+ /* init IPC */
+ config->hdr.size = size;
+ dev_dbg(scomp->dev, "ACP SDW config rate %d channels %d\n",
+ config->acp_sdw.rate, config->acp_sdw.channels);
+
+ /* set config for all DAI's with name matching the link name */
+ dai->number_configs = 1;
+ dai->current_config = 0;
+ private->dai_config = kmemdup(config, size, GFP_KERNEL);
+ if (!private->dai_config)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
{
@@ -1498,14 +1588,26 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*comp_dai), 1);
if (ret < 0)
- goto free;
+ goto free_comp;
/* update comp_tokens */
ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS,
swidget->tuples, swidget->num_tuples,
sizeof(comp_dai->config), 1);
if (ret < 0)
- goto free;
+ goto free_comp;
+
+ /* Subtract the base to match the FW dai index. */
+ if (comp_dai->type == SOF_DAI_INTEL_ALH) {
+ if (comp_dai->dai_index < INTEL_ALH_DAI_INDEX_BASE) {
+ dev_err(sdev->dev,
+ "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n",
+ comp_dai->dai_index, INTEL_ALH_DAI_INDEX_BASE);
+ ret = -EINVAL;
+ goto free_comp;
+ }
+ comp_dai->dai_index -= INTEL_ALH_DAI_INDEX_BASE;
+ }
dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
swidget->widget->name, comp_dai->type, comp_dai->dai_index);
@@ -1559,6 +1661,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
case SOF_DAI_IMX_ESAI:
ret = sof_link_esai_load(scomp, slink, config, dai);
break;
+ case SOF_DAI_IMX_MICFIL:
+ ret = sof_link_micfil_load(scomp, slink, config, dai);
+ break;
case SOF_DAI_AMD_BT:
ret = sof_link_acp_bt_load(scomp, slink, config, dai);
break;
@@ -1576,6 +1681,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
case SOF_DAI_MEDIATEK_AFE:
ret = sof_link_afe_load(scomp, slink, config, dai);
break;
+ case SOF_DAI_AMD_SDW:
+ ret = sof_link_acp_sdw_load(scomp, slink, config, dai);
+ break;
default:
break;
}
@@ -2074,8 +2182,16 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
case SOF_DAI_INTEL_ALH:
if (data) {
/* save the dai_index during hw_params and reuse it for hw_free */
- if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS)
- config->dai_index = data->dai_index;
+ if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
+ /* Subtract the base to match the FW dai index. */
+ if (data->dai_index < INTEL_ALH_DAI_INDEX_BASE) {
+ dev_err(sdev->dev,
+ "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n",
+ config->dai_index, INTEL_ALH_DAI_INDEX_BASE);
+ return -EINVAL;
+ }
+ config->dai_index = data->dai_index - INTEL_ALH_DAI_INDEX_BASE;
+ }
config->alh.stream_id = data->dai_data;
}
break;
@@ -2270,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
@@ -2307,27 +2411,16 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
return 0;
}
-/*
- * For older firmware, this function doesn't free widgets for static pipelines during suspend.
- * It only resets use_count for all widgets.
- */
-static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
+static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler,
+ bool *dyn_widgets, bool verify)
{
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_sof_widget *swidget;
- struct snd_sof_route *sroute;
- bool dyn_widgets = false;
int ret;
- /*
- * This function is called during suspend and for one-time topology verification during
- * first boot. In both cases, there is no need to protect swidget->use_count and
- * sroute->setup because during suspend all running streams are suspended and during
- * topology loading the sound card unavailable to open PCMs.
- */
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->dynamic_pipeline_widget) {
- dyn_widgets = true;
+ *dyn_widgets = true;
continue;
}
@@ -2342,11 +2435,44 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
continue;
}
+ if (include_scheduler && swidget->id != snd_soc_dapm_scheduler)
+ continue;
+
+ if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler)
+ continue;
+
ret = sof_widget_free(sdev, swidget);
if (ret < 0)
return ret;
}
+ return 0;
+}
+
+/*
+ * For older firmware, this function doesn't free widgets for static pipelines during suspend.
+ * It only resets use_count for all widgets.
+ */
+static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
+{
+ struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
+ struct snd_sof_widget *swidget;
+ struct snd_sof_route *sroute;
+ bool dyn_widgets = false;
+ int ret;
+
+ /*
+ * This function is called during suspend and for one-time topology verification during
+ * first boot. In both cases, there is no need to protect swidget->use_count and
+ * sroute->setup because during suspend all running streams are suspended and during
+ * topology loading the sound card unavailable to open PCMs. Do not free the scheduler
+ * widgets yet so that the secondary cores do not get powered down before all the widgets
+ * associated with the scheduler are freed.
+ */
+ ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
+ if (ret < 0)
+ return ret;
+
/*
* Tear down all pipelines associated with PCMs that did not get suspended
* and unset the prepare flag so that they can be set up again during resume.
@@ -2362,6 +2488,11 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
}
}
+ /* free all the scheduler widgets now. This will also power down the secondary cores */
+ ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
+ if (ret < 0)
+ return ret;
+
list_for_each_entry(sroute, &sdev->route_list, list)
sroute->setup = false;
@@ -2380,7 +2511,7 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
return 0;
}
-static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
+static int sof_ipc3_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type)
{
struct sof_dai_private_data *private = dai->private;
@@ -2389,15 +2520,17 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
switch (private->dai_config->type) {
case SOF_DAI_INTEL_SSP:
- switch (clk_type) {
- case SOF_DAI_CLK_INTEL_SSP_MCLK:
+ switch (param_type) {
+ case SOF_DAI_PARAM_INTEL_SSP_MCLK:
return private->dai_config->ssp.mclk_rate;
- case SOF_DAI_CLK_INTEL_SSP_BCLK:
+ case SOF_DAI_PARAM_INTEL_SSP_BCLK:
return private->dai_config->ssp.bclk_rate;
+ case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS:
+ return private->dai_config->ssp.tdm_slots;
default:
+ dev_err(sdev->dev, "invalid SSP param %d\n", param_type);
break;
}
- dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type);
break;
default:
/* not yet implemented for platforms other than the above */
@@ -2572,7 +2705,7 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.widget_free = sof_ipc3_widget_free,
.widget_setup = sof_ipc3_widget_setup,
.dai_config = sof_ipc3_dai_config,
- .dai_get_clk = sof_ipc3_dai_get_clk,
+ .dai_get_param = sof_ipc3_dai_get_param,
.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
.parse_manifest = sof_ipc3_parse_manifest,
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index ec1ac0fb2d9f..4a194a705ace 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -3,7 +3,7 @@
// 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) 2021 Intel Corporation. All rights reserved.
+// Copyright(c) 2021 Intel Corporation
//
//
@@ -223,6 +223,14 @@ static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
}
#endif
+static void sof_ipc3_dump_payload(struct snd_sof_dev *sdev,
+ void *ipc_data, size_t size)
+{
+ dev_dbg(sdev->dev, "Size of payload following the header: %zu\n", size);
+ print_hex_dump_debug("Message payload: ", DUMP_PREFIX_OFFSET,
+ 16, 4, ipc_data, size, false);
+}
+
static int sof_ipc3_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
@@ -304,7 +312,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
} else {
if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
- if (msg->reply_size)
+ if (reply_data && msg->reply_size)
/* copy the data returned from DSP */
memcpy(reply_data, msg->reply_data,
msg->reply_size);
@@ -374,6 +382,29 @@ static int sof_ipc3_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_
ret = ipc3_tx_msg_unlocked(ipc, msg_data, msg_bytes, reply_data, reply_bytes);
+ if (sof_debug_check_flag(SOF_DBG_DUMP_IPC_MESSAGE_PAYLOAD)) {
+ size_t payload_bytes, header_bytes;
+ char *payload = NULL;
+
+ /* payload is indicated by non zero msg/reply_bytes */
+ if (msg_bytes > sizeof(struct sof_ipc_cmd_hdr)) {
+ payload = msg_data;
+
+ header_bytes = sizeof(struct sof_ipc_cmd_hdr);
+ payload_bytes = msg_bytes - header_bytes;
+ } else if (reply_bytes > sizeof(struct sof_ipc_reply)) {
+ payload = reply_data;
+
+ header_bytes = sizeof(struct sof_ipc_reply);
+ payload_bytes = reply_bytes - header_bytes;
+ }
+
+ if (payload) {
+ payload += header_bytes;
+ sof_ipc3_dump_payload(sdev, payload, payload_bytes);
+ }
+ }
+
mutex_unlock(&ipc->tx_mutex);
return ret;
@@ -472,6 +503,14 @@ static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t da
offset += payload_size;
}
+ if (sof_debug_check_flag(SOF_DBG_DUMP_IPC_MESSAGE_PAYLOAD)) {
+ size_t header_bytes = sizeof(struct sof_ipc_reply);
+ char *payload = (char *)cdata;
+
+ payload += header_bytes;
+ sof_ipc3_dump_payload(sdev, payload, data_bytes - header_bytes);
+ }
+
mutex_unlock(&sdev->ipc->tx_mutex);
kfree(cdata_chunk);
@@ -528,13 +567,10 @@ int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
/* create read-only cc_version debugfs to store compiler version info */
/* use local copy of the cc_version to prevent data corruption */
if (sdev->first_boot) {
- sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
- GFP_KERNEL);
-
+ sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL);
if (!sdev->cc_version)
return -ENOMEM;
- memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
cc->ext_hdr.hdr.size,
"cc_version", 0444);
@@ -765,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));
@@ -962,7 +994,7 @@ void sof_ipc3_do_rx_work(struct snd_sof_dev *sdev, struct sof_ipc_cmd_hdr *hdr,
ipc3_log_header(sdev->dev, "ipc rx", hdr->cmd);
- if (hdr->size < sizeof(hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
+ if (hdr->size < sizeof(*hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
dev_err(sdev->dev, "The received message size is invalid: %u\n",
hdr->size);
return;
@@ -1031,7 +1063,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
return;
}
- if (hdr.size < sizeof(hdr)) {
+ if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) {
dev_err(sdev->dev, "The received message size is invalid\n");
return;
}
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
index c6d404d44097..976a4794d610 100644
--- a/sound/soc/sof/ipc4-control.c
+++ b/sound/soc/sof/ipc4-control.c
@@ -3,7 +3,7 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
//
@@ -89,7 +89,7 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
struct sof_ipc4_gain *gain = swidget->private;
struct sof_ipc4_msg *msg = &cdata->msg;
- struct sof_ipc4_gain_data data;
+ struct sof_ipc4_gain_params params;
bool all_channels_equal = true;
u32 value;
int ret, i;
@@ -109,20 +109,20 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
*/
for (i = 0; i < scontrol->num_channels; i++) {
if (all_channels_equal) {
- data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
- data.init_val = cdata->chanv[0].value;
+ params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+ params.init_val = cdata->chanv[0].value;
} else {
- data.channels = cdata->chanv[i].channel;
- data.init_val = cdata->chanv[i].value;
+ params.channels = cdata->chanv[i].channel;
+ params.init_val = cdata->chanv[i].value;
}
/* set curve type and duration from topology */
- data.curve_duration_l = gain->data.curve_duration_l;
- data.curve_duration_h = gain->data.curve_duration_h;
- data.curve_type = gain->data.curve_type;
+ params.curve_duration_l = gain->data.params.curve_duration_l;
+ params.curve_duration_h = gain->data.params.curve_duration_h;
+ params.curve_type = gain->data.params.curve_type;
- msg->data_ptr = &data;
- msg->data_size = sizeof(data);
+ msg->data_ptr = &params;
+ msg->data_size = sizeof(params);
ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
msg->data_ptr = NULL;
@@ -201,6 +201,207 @@ static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
return 0;
}
+static int
+sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct snd_sof_control *scontrol, bool lock)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct sof_ipc4_control_msg_payload *data;
+ struct sof_ipc4_msg *msg = &cdata->msg;
+ size_t data_size;
+ unsigned int i;
+ int ret;
+
+ data_size = struct_size(data, chanv, scontrol->num_channels);
+ data = kzalloc(data_size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->id = cdata->index;
+ data->num_elems = scontrol->num_channels;
+ for (i = 0; i < scontrol->num_channels; i++) {
+ data->chanv[i].channel = cdata->chanv[i].channel;
+ data->chanv[i].value = cdata->chanv[i].value;
+ }
+
+ msg->data_ptr = data;
+ msg->data_size = data_size;
+
+ ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
+ msg->data_ptr = NULL;
+ msg->data_size = 0;
+ if (ret < 0)
+ dev_err(sdev->dev, "Failed to set control update for %s\n",
+ scontrol->name);
+
+ kfree(data);
+
+ return ret;
+}
+
+static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct snd_soc_component *scomp = scontrol->scomp;
+ struct sof_ipc4_control_msg_payload *data;
+ struct sof_ipc4_msg *msg = &cdata->msg;
+ size_t data_size;
+ unsigned int i;
+ int ret;
+
+ if (!scontrol->comp_data_dirty)
+ return;
+
+ if (!pm_runtime_active(scomp->dev))
+ return;
+
+ data_size = struct_size(data, chanv, scontrol->num_channels);
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (!data)
+ return;
+
+ data->id = cdata->index;
+ data->num_elems = scontrol->num_channels;
+ msg->data_ptr = data;
+ msg->data_size = data_size;
+
+ scontrol->comp_data_dirty = false;
+ ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, true);
+ msg->data_ptr = NULL;
+ msg->data_size = 0;
+ if (!ret) {
+ for (i = 0; i < scontrol->num_channels; i++) {
+ cdata->chanv[i].channel = data->chanv[i].channel;
+ cdata->chanv[i].value = data->chanv[i].value;
+ }
+ } else {
+ dev_err(scomp->dev, "Failed to read control data for %s\n",
+ scontrol->name);
+ scontrol->comp_data_dirty = true;
+ }
+
+ kfree(data);
+}
+
+static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct snd_soc_component *scomp = scontrol->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_widget *swidget;
+ bool widget_found = false;
+ bool change = false;
+ unsigned int i;
+ u32 value;
+ int ret;
+
+ /* update each channel */
+ for (i = 0; i < scontrol->num_channels; i++) {
+ value = ucontrol->value.integer.value[i];
+ change = change || (value != cdata->chanv[i].value);
+ cdata->chanv[i].channel = i;
+ cdata->chanv[i].value = value;
+ }
+
+ if (!pm_runtime_active(scomp->dev))
+ return change;
+
+ /* find widget associated with the control */
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (swidget->comp_id == scontrol->comp_id) {
+ widget_found = true;
+ break;
+ }
+ }
+
+ if (!widget_found) {
+ dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+ return false;
+ }
+
+ ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true);
+ if (ret < 0)
+ return false;
+
+ return change;
+}
+
+static int sof_ipc4_switch_get(struct snd_sof_control *scontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ unsigned int i;
+
+ sof_ipc4_refresh_generic_control(scontrol);
+
+ /* read back each channel */
+ for (i = 0; i < scontrol->num_channels; i++)
+ ucontrol->value.integer.value[i] = cdata->chanv[i].value;
+
+ return 0;
+}
+
+static bool sof_ipc4_enum_put(struct snd_sof_control *scontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct snd_soc_component *scomp = scontrol->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct snd_sof_widget *swidget;
+ bool widget_found = false;
+ bool change = false;
+ unsigned int i;
+ u32 value;
+ int ret;
+
+ /* update each channel */
+ for (i = 0; i < scontrol->num_channels; i++) {
+ value = ucontrol->value.enumerated.item[i];
+ change = change || (value != cdata->chanv[i].value);
+ cdata->chanv[i].channel = i;
+ cdata->chanv[i].value = value;
+ }
+
+ if (!pm_runtime_active(scomp->dev))
+ return change;
+
+ /* find widget associated with the control */
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ if (swidget->comp_id == scontrol->comp_id) {
+ widget_found = true;
+ break;
+ }
+ }
+
+ if (!widget_found) {
+ dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+ return false;
+ }
+
+ ret = sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, true);
+ if (ret < 0)
+ return false;
+
+ return change;
+}
+
+static int sof_ipc4_enum_get(struct snd_sof_control *scontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ unsigned int i;
+
+ sof_ipc4_refresh_generic_control(scontrol);
+
+ /* read back each channel */
+ for (i = 0; i < scontrol->num_channels; i++)
+ ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
+
+ return 0;
+}
+
static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
struct snd_sof_control *scontrol,
bool set, bool lock)
@@ -330,6 +531,14 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol,
return -EINVAL;
}
+ /* Check header id */
+ if (header.numid != SOF_CTRL_CMD_BINARY) {
+ dev_err_ratelimited(scomp->dev,
+ "Incorrect numid for bytes put %d\n",
+ header.numid);
+ return -EINVAL;
+ }
+
/* Verify the ABI header first */
if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr)))
return -EFAULT;
@@ -412,7 +621,8 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
if (data_size > size)
return -ENOSPC;
- header.numid = scontrol->comp_id;
+ /* Set header id and length */
+ header.numid = SOF_CTRL_CMD_BINARY;
header.length = data_size;
if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
@@ -438,6 +648,146 @@ static int sof_ipc4_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, true);
}
+static int
+sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+ struct snd_sof_control *scontrol)
+{
+ if (scontrol->max == 1)
+ return sof_ipc4_set_generic_control_data(sdev, swidget, scontrol, false);
+
+ return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false);
+}
+
+#define PARAM_ID_FROM_EXTENSION(_ext) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \
+ >> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT)
+
+static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
+{
+ struct sof_ipc4_msg *ipc4_msg = ipc_message;
+ struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr;
+ struct sof_ipc4_control_msg_payload *msg_data;
+ struct sof_ipc4_control_data *cdata;
+ struct snd_soc_dapm_widget *widget;
+ struct snd_sof_control *scontrol;
+ struct snd_sof_widget *swidget;
+ struct snd_kcontrol *kc = NULL;
+ bool scontrol_found = false;
+ u32 event_param_id;
+ int i, type;
+
+ if (ndata->event_data_size < sizeof(*msg_data)) {
+ dev_err(sdev->dev,
+ "%s: Invalid event data size for module %u.%u: %u\n",
+ __func__, ndata->module_id, ndata->instance_id,
+ ndata->event_data_size);
+ return;
+ }
+
+ event_param_id = ndata->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK;
+ switch (event_param_id) {
+ case SOF_IPC4_SWITCH_CONTROL_PARAM_ID:
+ type = SND_SOC_TPLG_TYPE_MIXER;
+ break;
+ case SOF_IPC4_ENUM_CONTROL_PARAM_ID:
+ type = SND_SOC_TPLG_TYPE_ENUM;
+ break;
+ default:
+ dev_err(sdev->dev,
+ "%s: Invalid control type for module %u.%u: %u\n",
+ __func__, ndata->module_id, ndata->instance_id,
+ event_param_id);
+ return;
+ }
+
+ /* Find the swidget based on ndata->module_id and ndata->instance_id */
+ swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id,
+ ndata->instance_id);
+ if (!swidget) {
+ dev_err(sdev->dev, "%s: Failed to find widget for module %u.%u\n",
+ __func__, ndata->module_id, ndata->instance_id);
+ return;
+ }
+
+ /* Find the scontrol which is the source of the notification */
+ msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data;
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
+ if (scontrol->comp_id == swidget->comp_id) {
+ u32 local_param_id;
+
+ cdata = scontrol->ipc_control_data;
+ /*
+ * The scontrol's param_id is stored in the IPC message
+ * template's extension
+ */
+ local_param_id = PARAM_ID_FROM_EXTENSION(cdata->msg.extension);
+ if (local_param_id == event_param_id &&
+ msg_data->id == cdata->index) {
+ scontrol_found = true;
+ break;
+ }
+ }
+ }
+
+ if (!scontrol_found) {
+ dev_err(sdev->dev,
+ "%s: Failed to find control on widget %s: %u:%u\n",
+ __func__, swidget->widget->name, ndata->event_id & 0xffff,
+ msg_data->id);
+ return;
+ }
+
+ if (msg_data->num_elems) {
+ /*
+ * The message includes the updated value/data, update the
+ * control's local cache using the received notification
+ */
+ for (i = 0; i < msg_data->num_elems; i++) {
+ u32 channel = msg_data->chanv[i].channel;
+
+ if (channel >= scontrol->num_channels) {
+ dev_warn(sdev->dev,
+ "Invalid channel index for %s: %u\n",
+ scontrol->name, i);
+
+ /*
+ * Mark the scontrol as dirty to force a refresh
+ * on next read
+ */
+ scontrol->comp_data_dirty = true;
+ break;
+ }
+
+ cdata->chanv[channel].value = msg_data->chanv[i].value;
+ }
+ } else {
+ /*
+ * Mark the scontrol as dirty because the value/data is changed
+ * in firmware, forcing a refresh on next read access
+ */
+ scontrol->comp_data_dirty = true;
+ }
+
+ /*
+ * Look up the ALSA kcontrol of the scontrol to be able to send a
+ * notification to user space
+ */
+ widget = swidget->widget;
+ for (i = 0; i < widget->num_kcontrols; i++) {
+ /* skip non matching types or non matching indexes within type */
+ if (widget->dobj.widget.kcontrol_type[i] == type &&
+ widget->kcontrol_news[i].index == cdata->index) {
+ kc = widget->kcontrols[i];
+ break;
+ }
+ }
+
+ if (!kc)
+ return;
+
+ snd_ctl_notify_one(swidget->scomp->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
+}
+
/* set up all controls for the widget */
static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
@@ -450,13 +800,17 @@ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_s
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_VOLSW_SX:
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
- ret = sof_ipc4_set_volume_data(sdev, swidget,
- scontrol, false);
+ ret = sof_ipc4_volsw_setup(sdev, swidget, scontrol);
break;
case SND_SOC_TPLG_CTL_BYTES:
ret = sof_ipc4_set_get_bytes_data(sdev, scontrol,
true, false);
break;
+ case SND_SOC_TPLG_CTL_ENUM:
+ case SND_SOC_TPLG_CTL_ENUM_VALUE:
+ ret = sof_ipc4_set_generic_control_data(sdev, swidget,
+ scontrol, false);
+ break;
default:
break;
}
@@ -498,11 +852,16 @@ sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_I
const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
.volume_put = sof_ipc4_volume_put,
.volume_get = sof_ipc4_volume_get,
+ .switch_put = sof_ipc4_switch_put,
+ .switch_get = sof_ipc4_switch_get,
+ .enum_put = sof_ipc4_enum_put,
+ .enum_get = sof_ipc4_enum_get,
.bytes_put = sof_ipc4_bytes_put,
.bytes_get = sof_ipc4_bytes_get,
.bytes_ext_put = sof_ipc4_bytes_ext_put,
.bytes_ext_get = sof_ipc4_bytes_ext_get,
.bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get,
+ .update = sof_ipc4_control_update,
.widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
.set_up_volume_table = sof_ipc4_set_up_volume_table,
};
diff --git a/sound/soc/sof/ipc4-fw-reg.h b/sound/soc/sof/ipc4-fw-reg.h
index 7226161e57e1..7b85a364a6a6 100644
--- a/sound/soc/sof/ipc4-fw-reg.h
+++ b/sound/soc/sof/ipc4-fw-reg.h
@@ -3,7 +3,7 @@
* 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) 2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2022 Intel Corporation
*/
#ifndef __IPC4_FW_REG_H__
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index eaa04762eb11..b0d293f62d1c 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -3,7 +3,7 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
#include <linux/firmware.h>
#include <sound/sof/ext_manifest4.h>
@@ -80,6 +80,14 @@ static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
dev_dbg(sdev->dev, "Header length: %u, module count: %u\n",
fw_header->len, fw_header->num_module_entries);
+ /* copy the fw_version of basefw into debugfs at first boot */
+ if (fw == sdev->basefw.fw) {
+ sdev->fw_version.major = fw_header->major_version;
+ sdev->fw_version.minor = fw_header->minor_version;
+ sdev->fw_version.micro = fw_header->hotfix_version;
+ sdev->fw_version.build = fw_header->build_version;
+ }
+
fw_lib->modules = devm_kmalloc_array(sdev->dev, fw_header->num_module_entries,
sizeof(*fw_module), GFP_KERNEL);
if (!fw_lib->modules)
@@ -161,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;
@@ -185,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)
@@ -230,7 +236,6 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
ret = ipc4_data->load_library(sdev, fw_lib, false);
- pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
@@ -243,22 +248,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)
{
@@ -391,6 +491,48 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
goto out;
}
break;
+ case SOF_IPC4_FW_CONTEXT_SAVE:
+ ipc4_data->fw_context_save = *tuple->value;
+ /*
+ * Set the default libraries_restored value - if full
+ * context save is supported then it means that
+ * libraries are restored
+ */
+ ipc4_data->libraries_restored = ipc4_data->fw_context_save;
+ break;
+ default:
+ break;
+ }
+
+ 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;
}
@@ -479,13 +621,10 @@ void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
msg = "No CPC match in the firmware file's manifest";
no_cpc:
- dev_warn(sdev->dev, "%s (UUID: %pUL): %s (ibs/obs: %u/%u)\n",
- fw_module->man4_module_entry.name,
- &fw_module->man4_module_entry.uuid, msg, basecfg->ibs,
- basecfg->obs);
- dev_warn_once(sdev->dev, "Please try to update the firmware.\n");
- dev_warn_once(sdev->dev, "If the issue persists, file a bug at\n");
- dev_warn_once(sdev->dev, "https://github.com/thesofproject/sof/issues/\n");
+ dev_dbg(sdev->dev, "%s (UUID: %pUL): %s (ibs/obs: %u/%u)\n",
+ fw_module->man4_module_entry.name,
+ &fw_module->man4_module_entry.uuid, msg, basecfg->ibs,
+ basecfg->obs);
}
const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
diff --git a/sound/soc/sof/ipc4-mtrace.c b/sound/soc/sof/ipc4-mtrace.c
index 2b4659a1768e..aa5b78604db6 100644
--- a/sound/soc/sof/ipc4-mtrace.c
+++ b/sound/soc/sof/ipc4-mtrace.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
#include <linux/debugfs.h>
#include <linux/sched/signal.h>
+#include <linux/sched/clock.h>
#include <sound/sof/ipc4/header.h>
#include "sof-priv.h"
#include "ipc4-priv.h"
@@ -41,24 +42,12 @@
* The two pointers are offsets within the buffer.
*/
-#define SOF_MTRACE_DESCRIPTOR_SIZE 12 /* 3 x u32 */
-
#define FW_EPOCH_DELTA 11644473600LL
-#define INVALID_SLOT_OFFSET 0xffffffff
#define MAX_ALLOWED_LIBRARIES 16
-#define MAX_MTRACE_SLOTS 15
-
-#define SOF_MTRACE_PAGE_SIZE 0x1000
-#define SOF_MTRACE_SLOT_SIZE SOF_MTRACE_PAGE_SIZE
-
-/* debug log slot types */
-#define SOF_MTRACE_SLOT_UNUSED 0x00000000
-#define SOF_MTRACE_SLOT_CRITICAL_LOG 0x54524300 /* byte 0: core ID */
-#define SOF_MTRACE_SLOT_DEBUG_LOG 0x474f4c00 /* byte 0: core ID */
-#define SOF_MTRACE_SLOT_GDB_STUB 0x42444700
-#define SOF_MTRACE_SLOT_TELEMETRY 0x4c455400
-#define SOF_MTRACE_SLOT_BROKEN 0x44414544
+
+#define SOF_IPC4_INVALID_SLOT_OFFSET 0xffffffff
+
/* for debug and critical types */
#define SOF_MTRACE_SLOT_CORE_MASK GENMASK(7, 0)
#define SOF_MTRACE_SLOT_TYPE_MASK GENMASK(31, 8)
@@ -140,7 +129,7 @@ static int sof_ipc4_mtrace_dfs_open(struct inode *inode, struct file *file)
if (unlikely(ret))
goto out;
- core_data->log_buffer = kmalloc(SOF_MTRACE_SLOT_SIZE, GFP_KERNEL);
+ core_data->log_buffer = kmalloc(SOF_IPC4_DEBUG_SLOT_SIZE, GFP_KERNEL);
if (!core_data->log_buffer) {
debugfs_file_put(file->f_path.dentry);
ret = -ENOMEM;
@@ -212,13 +201,13 @@ static ssize_t sof_ipc4_mtrace_dfs_read(struct file *file, char __user *buffer,
return 0;
}
- if (core_data->slot_offset == INVALID_SLOT_OFFSET)
+ if (core_data->slot_offset == SOF_IPC4_INVALID_SLOT_OFFSET)
return 0;
/* The log data buffer starts after the two pointer in the slot */
log_buffer_offset = core_data->slot_offset + (sizeof(u32) * 2);
/* The log data size excludes the pointers */
- log_buffer_size = SOF_MTRACE_SLOT_SIZE - (sizeof(u32) * 2);
+ log_buffer_size = SOF_IPC4_DEBUG_SLOT_SIZE - (sizeof(u32) * 2);
read_ptr = core_data->host_read_ptr;
write_ptr = core_data->dsp_write_ptr;
@@ -424,7 +413,6 @@ static int ipc4_mtrace_enable(struct snd_sof_dev *sdev)
const struct sof_ipc_ops *iops = sdev->ipc->ops;
struct sof_ipc4_msg msg;
u64 system_time;
- ktime_t kt;
int ret;
if (priv->mtrace_state != SOF_MTRACE_DISABLED)
@@ -436,9 +424,12 @@ static int ipc4_mtrace_enable(struct snd_sof_dev *sdev)
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_SYSTEM_TIME);
- /* The system time is in usec, UTC, epoch is 1601-01-01 00:00:00 */
- kt = ktime_add_us(ktime_get_real(), FW_EPOCH_DELTA * USEC_PER_SEC);
- system_time = ktime_to_us(kt);
+ /*
+ * local_clock() is used to align with dmesg, so both kernel and firmware logs have
+ * the same base and a minor delta due to the IPC. system time is in us format but
+ * local_clock() returns the time in ns, so convert to ns.
+ */
+ system_time = div64_u64(local_clock(), NSEC_PER_USEC);
msg.data_size = sizeof(system_time);
msg.data_ptr = &system_time;
ret = iops->set_get_data(sdev, &msg, msg.data_size, true);
@@ -510,13 +501,13 @@ static void sof_mtrace_find_core_slots(struct snd_sof_dev *sdev)
u32 slot_desc_type_offset, type, core;
int i;
- for (i = 0; i < MAX_MTRACE_SLOTS; i++) {
+ for (i = 0; i < SOF_IPC4_MAX_DEBUG_SLOTS; i++) {
/* The type is the second u32 in the slot descriptor */
slot_desc_type_offset = sdev->debug_box.offset;
- slot_desc_type_offset += SOF_MTRACE_DESCRIPTOR_SIZE * i + sizeof(u32);
+ slot_desc_type_offset += SOF_IPC4_DEBUG_DESCRIPTOR_SIZE * i + sizeof(u32);
sof_mailbox_read(sdev, slot_desc_type_offset, &type, sizeof(type));
- if ((type & SOF_MTRACE_SLOT_TYPE_MASK) == SOF_MTRACE_SLOT_DEBUG_LOG) {
+ if ((type & SOF_MTRACE_SLOT_TYPE_MASK) == SOF_IPC4_DEBUG_SLOT_DEBUG_LOG) {
core = type & SOF_MTRACE_SLOT_CORE_MASK;
if (core >= sdev->num_cores) {
@@ -533,7 +524,7 @@ static void sof_mtrace_find_core_slots(struct snd_sof_dev *sdev)
* debug_box + SOF_MTRACE_SLOT_SIZE offset
*/
core_data->slot_offset = sdev->debug_box.offset;
- core_data->slot_offset += SOF_MTRACE_SLOT_SIZE * (i + 1);
+ core_data->slot_offset += SOF_IPC4_DEBUG_SLOT_SIZE * (i + 1);
dev_dbg(sdev->dev, "slot%d is used for core%u\n", i, core);
if (core_data->delayed_pos_update) {
sof_ipc4_mtrace_update_pos(sdev, core);
@@ -633,7 +624,7 @@ int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core)
core_data = &priv->cores[core];
- if (core_data->slot_offset == INVALID_SLOT_OFFSET) {
+ if (core_data->slot_offset == SOF_IPC4_INVALID_SLOT_OFFSET) {
core_data->delayed_pos_update = true;
return 0;
}
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 0c905bd0fab4..6d81969e181c 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -3,7 +3,7 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
#include <sound/pcm_params.h>
@@ -15,15 +15,94 @@
#include "ipc4-topology.h"
#include "ipc4-fw-reg.h"
+/**
+ * struct sof_ipc4_timestamp_info - IPC4 timestamp info
+ * @host_copier: the host copier of the pcm stream
+ * @dai_copier: the dai copier of the pcm stream
+ * @stream_start_offset: reported by fw in memory window (converted to
+ * frames at host_copier sampling rate)
+ * @stream_end_offset: reported by fw in memory window (converted to
+ * frames at host_copier sampling rate)
+ * @llp_offset: llp offset in memory window
+ * @delay: Calculated and stored in pointer callback. The stored value is
+ * returned in the delay callback. Expressed in frames at host copier
+ * sampling rate.
+ */
+struct sof_ipc4_timestamp_info {
+ struct sof_ipc4_copier *host_copier;
+ struct sof_ipc4_copier *dai_copier;
+ u64 stream_start_offset;
+ u64 stream_end_offset;
+ u32 llp_offset;
+
+ snd_pcm_sframes_t delay;
+};
+
+/**
+ * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data
+ * @time_info: pointer to time info struct if it is supported, otherwise NULL
+ * @chain_dma_allocated: indicates the ChainDMA allocation state
+ */
+struct sof_ipc4_pcm_stream_priv {
+ struct sof_ipc4_timestamp_info *time_info;
+
+ bool chain_dma_allocated;
+};
+
+/*
+ * Modulus to use to compare host and link position counters. The sampling
+ * rates may be different, so the raw hardware counters will wrap
+ * around at different times. To calculate differences, use
+ * DELAY_BOUNDARY as a common modulus. This value must be smaller than
+ * the wrap-around point of any hardware counter, and larger than any
+ * valid delay measurement.
+ */
+#define DELAY_BOUNDARY U32_MAX
+
+#define DELAY_MAX (DELAY_BOUNDARY >> 1)
+
+static inline struct sof_ipc4_timestamp_info *
+sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
+{
+ struct sof_ipc4_pcm_stream_priv *stream_priv = sps->private;
+
+ return stream_priv->time_info;
+}
+
+static
+char *sof_ipc4_set_multi_pipeline_state_debug(struct snd_sof_dev *sdev, char *buf, size_t size,
+ struct ipc4_pipeline_set_state_data *trigger_list)
+{
+ int i, offset = 0;
+
+ for (i = 0; i < trigger_list->count; i++) {
+ offset += snprintf(buf + offset, size - offset, " %d",
+ trigger_list->pipeline_instance_ids[i]);
+
+ if (offset >= size - 1) {
+ buf[size - 1] = '\0';
+ break;
+ }
+ }
+ return buf;
+}
+
static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state,
struct ipc4_pipeline_set_state_data *trigger_list)
{
struct sof_ipc4_msg msg = {{ 0 }};
u32 primary, ipc_size;
+ char debug_buf[32];
/* trigger a single pipeline */
if (trigger_list->count == 1)
- return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state);
+ return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
+ state);
+
+ dev_dbg(sdev->dev, "Set pipelines %s to state %d%s",
+ sof_ipc4_set_multi_pipeline_state_debug(sdev, debug_buf, sizeof(debug_buf),
+ trigger_list),
+ state, sof_ipc4_pipeline_state_str(state));
primary = state;
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
@@ -42,15 +121,16 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size);
}
-int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state)
{
struct sof_ipc4_msg msg = {{ 0 }};
u32 primary;
- dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
+ dev_dbg(sdev->dev, "Set pipeline %d to state %d%s", instance_id, state,
+ sof_ipc4_pipeline_state_str(state));
primary = state;
- primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
+ primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id);
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -61,10 +141,37 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
}
EXPORT_SYMBOL(sof_ipc4_set_pipeline_state);
+static void sof_ipc4_add_pipeline_by_priority(struct ipc4_pipeline_set_state_data *trigger_list,
+ struct snd_sof_widget *pipe_widget,
+ s8 *pipe_priority, bool ascend)
+{
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ int i, j;
+
+ for (i = 0; i < trigger_list->count; i++) {
+ /* add pipeline from low priority to high */
+ if (ascend && pipeline->priority < pipe_priority[i])
+ break;
+ /* add pipeline from high priority to low */
+ else if (!ascend && pipeline->priority > pipe_priority[i])
+ break;
+ }
+
+ for (j = trigger_list->count - 1; j >= i; j--) {
+ trigger_list->pipeline_instance_ids[j + 1] = trigger_list->pipeline_instance_ids[j];
+ pipe_priority[j + 1] = pipe_priority[j];
+ }
+
+ trigger_list->pipeline_instance_ids[i] = pipe_widget->instance_id;
+ trigger_list->count++;
+ pipe_priority[i] = pipeline->priority;
+}
+
static void
sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
struct snd_sof_pipeline *spipe,
- struct ipc4_pipeline_set_state_data *trigger_list)
+ struct ipc4_pipeline_set_state_data *trigger_list,
+ s8 *pipe_priority)
{
struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
@@ -79,20 +186,20 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
* for the first time
*/
if (spipe->started_count == spipe->paused_count)
- trigger_list->pipeline_ids[trigger_list->count++] =
- pipe_widget->instance_id;
+ sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority,
+ false);
break;
case SOF_IPC4_PIPE_RESET:
/* RESET if the pipeline is neither running nor paused */
if (!spipe->started_count && !spipe->paused_count)
- trigger_list->pipeline_ids[trigger_list->count++] =
- pipe_widget->instance_id;
+ sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority,
+ true);
break;
case SOF_IPC4_PIPE_PAUSED:
/* Pause the pipeline only when its started_count is 1 more than paused_count */
if (spipe->paused_count == (spipe->started_count - 1))
- trigger_list->pipeline_ids[trigger_list->count++] =
- pipe_widget->instance_id;
+ sof_ipc4_add_pipeline_by_priority(trigger_list, pipe_widget, pipe_priority,
+ true);
break;
default:
break;
@@ -113,7 +220,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
/* set state for pipeline if it was just triggered */
for (i = 0; i < trigger_list->count; i++) {
- if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) {
+ if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) {
pipeline->state = state;
break;
}
@@ -203,12 +310,17 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
*/
static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
+ struct snd_sof_pcm *spcm, int direction,
struct snd_sof_pcm_stream_pipeline_list *pipeline_list,
int state, int cmd)
{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_pcm_stream_priv *stream_priv;
bool allocate, enable, set_fifo_size;
struct sof_ipc4_msg msg = {{ 0 }};
- int i;
+ int ret, i;
+
+ stream_priv = spcm->stream[direction].private;
switch (state) {
case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */
@@ -229,12 +341,17 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
set_fifo_size = false;
break;
case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */
+
+ /* ChainDMA can only be reset if it has been allocated */
+ if (!stream_priv->chain_dma_allocated)
+ return 0;
+
allocate = false;
enable = false;
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;
}
@@ -254,8 +371,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;
}
@@ -266,20 +383,39 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
msg.extension |= pipeline->msg.extension;
}
+ if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+ /*
+ * For ChainDMA the DMA ids are unique with the following mapping:
+ * playback: 0 - (num_playback_streams - 1)
+ * capture: num_playback_streams - (num_playback_streams +
+ * num_capture_streams - 1)
+ *
+ * Add the num_playback_streams offset to the DMA ids stored in
+ * msg.primary in case capture
+ */
+ msg.primary += SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(ipc4_data->num_playback_streams);
+ msg.primary += SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(ipc4_data->num_playback_streams);
+ }
+
if (allocate)
msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK;
if (enable)
msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK;
- return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
+ ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
+ /* Update the ChainDMA allocation state */
+ if (!ret)
+ stream_priv->chain_dma_allocated = allocate;
+
+ return ret;
}
static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int state, int cmd)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct ipc4_pipeline_set_state_data *trigger_list;
@@ -287,15 +423,16 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
struct sof_ipc4_pipeline *pipeline;
struct snd_sof_pipeline *spipe;
struct snd_sof_pcm *spcm;
+ u8 *pipe_priority;
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 */
@@ -310,15 +447,46 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
* If use_chain_dma attribute is set we proceed to chained DMA
* trigger function that handles the rest for the substream.
*/
- if (pipeline->use_chain_dma)
- return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
+ if (pipeline->use_chain_dma) {
+ struct sof_ipc4_timestamp_info *time_info;
+
+ time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
+
+ ret = sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
+ pipeline_list, state, cmd);
+ if (ret || !time_info)
+ return ret;
+
+ if (state == SOF_IPC4_PIPE_PAUSED) {
+ /*
+ * Record the DAI position for delay reporting
+ * To handle multiple pause/resume/xrun we need to add
+ * the positions to simulate how the firmware behaves
+ */
+ u64 pos = snd_sof_pcm_get_dai_frame_counter(sdev, component,
+ substream);
+
+ time_info->stream_end_offset += pos;
+ } else if (state == SOF_IPC4_PIPE_RESET) {
+ /* Reset the end offset as the stream is stopped */
+ time_info->stream_end_offset = 0;
+ }
+
+ return 0;
+ }
/* allocate memory for the pipeline data */
- trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
- GFP_KERNEL);
+ trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
+ pipeline_list->count), GFP_KERNEL);
if (!trigger_list)
return -ENOMEM;
+ pipe_priority = kzalloc(pipeline_list->count, GFP_KERNEL);
+ if (!pipe_priority) {
+ kfree(trigger_list);
+ return -ENOMEM;
+ }
+
mutex_lock(&ipc4_data->pipeline_state_mutex);
/*
@@ -333,12 +501,14 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
if (state == SOF_IPC4_PIPE_RUNNING || state == SOF_IPC4_PIPE_RESET)
for (i = pipeline_list->count - 1; i >= 0; i--) {
spipe = pipeline_list->pipelines[i];
- sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list);
+ sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list,
+ pipe_priority);
}
else
for (i = 0; i < pipeline_list->count; i++) {
spipe = pipeline_list->pipelines[i];
- sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list);
+ sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list,
+ pipe_priority);
}
/* return if all pipelines are in the requested state already */
@@ -357,7 +527,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;
}
@@ -369,14 +539,38 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
}
/* return if this is the final state */
- if (state == SOF_IPC4_PIPE_PAUSED)
+ if (state == SOF_IPC4_PIPE_PAUSED) {
+ struct sof_ipc4_timestamp_info *time_info;
+
+ /*
+ * Invalidate the stream_start_offset to make sure that it is
+ * going to be updated if the stream resumes
+ */
+ time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
+ if (time_info)
+ time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION;
+
goto free;
+ }
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);
- goto free;
+ 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
+ * reset it to 0.
+ * Since the firmware is crashed we will not send IPC messages
+ * and we are going to see errors printed, but the state of the
+ * widgets will be correct for the next boot.
+ */
+ if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET)
+ goto free;
+
+ ret = 0;
}
/* update RUNNING/RESET state for all pipelines that were just triggered */
@@ -388,6 +582,7 @@ skip_pause_transition:
free:
mutex_unlock(&ipc4_data->pipeline_state_mutex);
kfree(trigger_list);
+ kfree(pipe_priority);
return ret;
}
@@ -398,14 +593,12 @@ static int sof_ipc4_pcm_trigger(struct snd_soc_component *component,
/* determine the pipeline state */
switch (cmd) {
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- state = SOF_IPC4_PIPE_PAUSED;
- break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
state = SOF_IPC4_PIPE_RUNNING;
break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
state = SOF_IPC4_PIPE_PAUSED;
@@ -426,12 +619,15 @@ static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0);
}
-static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
- struct snd_pcm_hw_params *params)
+static int ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev,
+ const char *link_name,
+ struct snd_pcm_hw_params *params)
{
struct snd_sof_dai_link *slink;
struct snd_sof_dai *dai;
bool dai_link_found = false;
+ int current_config = -1;
+ bool partial_match;
int i;
list_for_each_entry(slink, &sdev->dai_link_list, list) {
@@ -442,19 +638,50 @@ static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const
}
if (!dai_link_found)
- return;
+ return 0;
+ /*
+ * Find the first best matching hardware config:
+ * rate + format + channels are matching
+ * rate + channel are matching
+ *
+ * The copier cannot do rate and/or channel conversion.
+ */
for (i = 0; i < slink->num_hw_configs; i++) {
struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i];
- if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) {
- /* set current config for all DAI's with matching name */
- list_for_each_entry(dai, &sdev->dai_list, list)
- if (!strcmp(slink->link->name, dai->name))
- dai->current_config = le32_to_cpu(hw_config->id);
+ if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate) &&
+ params_width(params) == le32_to_cpu(hw_config->tdm_slot_width) &&
+ params_channels(params) <= le32_to_cpu(hw_config->tdm_slots)) {
+ current_config = le32_to_cpu(hw_config->id);
+ partial_match = false;
+ /* best match found */
break;
+ } else if (current_config < 0 &&
+ params_rate(params) == le32_to_cpu(hw_config->fsync_rate) &&
+ params_channels(params) <= le32_to_cpu(hw_config->tdm_slots)) {
+ current_config = le32_to_cpu(hw_config->id);
+ partial_match = true;
+ /* keep looking for better match */
}
}
+
+ if (current_config < 0) {
+ dev_err(sdev->dev,
+ "%s: No suitable hw_config found for %s (num_hw_configs: %d)\n",
+ __func__, slink->link->name, slink->num_hw_configs);
+ return -EINVAL;
+ }
+
+ dev_dbg(sdev->dev,
+ "hw_config for %s: %d (num_hw_configs: %d) with %s match\n",
+ slink->link->name, current_config, slink->num_hw_configs,
+ partial_match ? "partial" : "full");
+ list_for_each_entry(dai, &sdev->dai_list, list)
+ if (!strcmp(slink->link->name, dai->name))
+ dai->current_config = current_config;
+
+ return 0;
}
/*
@@ -474,16 +701,18 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev,
unsigned int be_rate;
int i;
+ if (WARN_ON_ONCE(!num_input_formats))
+ return -EINVAL;
+
/*
* 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) {
@@ -511,16 +740,71 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev,
return 0;
}
+static int sof_ipc4_pcm_dai_link_fixup_channels(struct snd_sof_dev *sdev,
+ struct snd_pcm_hw_params *params,
+ struct sof_ipc4_copier *ipc4_copier)
+{
+ struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts;
+ struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ int num_input_formats = ipc4_copier->available_fmt.num_input_formats;
+ unsigned int fe_channels = params_channels(params);
+ bool fe_be_match = false;
+ bool single_be_channels = true;
+ unsigned int be_channels, val;
+ int i;
+
+ if (WARN_ON_ONCE(!num_input_formats))
+ return -EINVAL;
+
+ /*
+ * Copier does not change channels, so we
+ * need to only consider the input pin information.
+ */
+ be_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(pin_fmts[0].audio_fmt.fmt_cfg);
+ for (i = 0; i < num_input_formats; i++) {
+ val = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(pin_fmts[i].audio_fmt.fmt_cfg);
+
+ if (val != be_channels)
+ single_be_channels = false;
+
+ if (val == fe_channels) {
+ fe_be_match = true;
+ break;
+ }
+ }
+
+ /*
+ * If channels is different than FE channels, topology must contain a
+ * module which can change the number of channels. But we do require
+ * topology to define a single channels in the DAI copier config in
+ * this case (FE channels may be variable).
+ */
+ if (!fe_be_match) {
+ if (!single_be_channels) {
+ dev_err(sdev->dev, "Unable to select channels for DAI link\n");
+ return -EINVAL;
+ }
+
+ channels->min = be_channels;
+ channels->max = be_channels;
+ }
+
+ return 0;
+}
+
static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct sof_ipc4_audio_format *ipc4_fmt;
struct sof_ipc4_copier *ipc4_copier;
- bool use_chain_dma = false;
- int dir;
+ bool single_bitdepth = false;
+ u32 valid_bits = 0;
+ int dir, ret;
if (!dai) {
dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
@@ -539,43 +823,84 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, dir);
if (w) {
+ struct sof_ipc4_available_audio_format *available_fmt =
+ &ipc4_copier->available_fmt;
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ /* Chain DMA does not use copiers, so no fixup needed */
if (pipeline->use_chain_dma)
- use_chain_dma = true;
+ return 0;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (sof_ipc4_copier_is_single_bitdepth(sdev,
+ available_fmt->output_pin_fmts,
+ available_fmt->num_output_formats)) {
+ ipc4_fmt = &available_fmt->output_pin_fmts->audio_fmt;
+ single_bitdepth = true;
+ }
+ } else {
+ if (sof_ipc4_copier_is_single_bitdepth(sdev,
+ available_fmt->input_pin_fmts,
+ available_fmt->num_input_formats)) {
+ ipc4_fmt = &available_fmt->input_pin_fmts->audio_fmt;
+ single_bitdepth = true;
+ }
+ }
}
}
- /* Chain DMA does not use copiers, so no fixup needed */
- if (!use_chain_dma) {
- int ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier);
+ ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier);
+ if (ret)
+ return ret;
- if (ret)
- return ret;
+ ret = sof_ipc4_pcm_dai_link_fixup_channels(sdev, params, ipc4_copier);
+ if (ret)
+ return ret;
+
+ if (single_bitdepth) {
+ snd_mask_none(fmt);
+ valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(ipc4_fmt->fmt_cfg);
+ dev_dbg(component->dev, "Set %s to %d bit format\n", dai->name, valid_bits);
}
- switch (ipc4_copier->dai_type) {
- case SOF_DAI_INTEL_SSP:
- ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
+ /* Set format if it is specified */
+ switch (valid_bits) {
+ case 16:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ break;
+ case 24:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ break;
+ case 32:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
break;
default:
break;
}
+ if (ipc4_copier->dai_type == SOF_DAI_INTEL_SSP)
+ return ipc4_ssp_dai_config_pcm_params_match(sdev,
+ (char *)rtd->dai_link->name,
+ params);
+
return 0;
}
static void sof_ipc4_pcm_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm)
{
struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
+ struct sof_ipc4_pcm_stream_priv *stream_priv;
int stream;
for_each_pcm_streams(stream) {
pipeline_list = &spcm->stream[stream].pipeline_list;
kfree(pipeline_list->pipelines);
pipeline_list->pipelines = NULL;
+
+ stream_priv = spcm->stream[stream].private;
+ kfree(stream_priv->time_info);
kfree(spcm->stream[stream].private);
spcm->stream[stream].private = NULL;
}
@@ -585,7 +910,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
{
struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct sof_ipc4_timestamp_info *stream_info;
+ struct sof_ipc4_pcm_stream_priv *stream_priv;
+ struct sof_ipc4_timestamp_info *time_info;
bool support_info = true;
u32 abi_version;
u32 abi_offset;
@@ -598,44 +924,58 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
if (abi_version < SOF_IPC4_FW_REGS_ABI_VER)
support_info = false;
+ /* For delay reporting the get_host_byte_counter callback is needed */
+ if (!sof_ops(sdev) || !sof_ops(sdev)->get_host_byte_counter)
+ support_info = false;
+
for_each_pcm_streams(stream) {
pipeline_list = &spcm->stream[stream].pipeline_list;
/* allocate memory for max number of pipeline IDs */
pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines,
- sizeof(struct snd_sof_widget *), GFP_KERNEL);
+ sizeof(*pipeline_list->pipelines),
+ GFP_KERNEL);
if (!pipeline_list->pipelines) {
sof_ipc4_pcm_free(sdev, spcm);
return -ENOMEM;
}
- if (!support_info)
+ stream_priv = kzalloc(sizeof(*stream_priv), GFP_KERNEL);
+ if (!stream_priv) {
+ sof_ipc4_pcm_free(sdev, spcm);
+ return -ENOMEM;
+ }
+
+ spcm->stream[stream].private = stream_priv;
+
+ /* Delay reporting is only supported on playback */
+ if (!support_info || stream == SNDRV_PCM_STREAM_CAPTURE)
continue;
- stream_info = kzalloc(sizeof(*stream_info), GFP_KERNEL);
- if (!stream_info) {
+ time_info = kzalloc(sizeof(*time_info), GFP_KERNEL);
+ if (!time_info) {
sof_ipc4_pcm_free(sdev, spcm);
return -ENOMEM;
}
- spcm->stream[stream].private = stream_info;
+ stream_priv->time_info = time_info;
}
return 0;
}
-static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *spcm)
+static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps)
{
struct sof_ipc4_copier *host_copier = NULL;
struct sof_ipc4_copier *dai_copier = NULL;
struct sof_ipc4_llp_reading_slot llp_slot;
- struct sof_ipc4_timestamp_info *info;
+ struct sof_ipc4_timestamp_info *time_info;
struct snd_soc_dapm_widget *widget;
struct snd_sof_dai *dai;
int i;
/* find host & dai to locate info in memory window */
- for_each_dapm_widgets(spcm->list, i, widget) {
+ for_each_dapm_widgets(sps->list, i, widget) {
struct snd_sof_widget *swidget = widget->dobj.private;
if (!swidget)
@@ -655,46 +995,44 @@ static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pc
return;
}
- info = spcm->private;
- info->host_copier = host_copier;
- info->dai_copier = dai_copier;
- info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_gpdma_reading_slots) +
- sdev->fw_info_box.offset;
+ time_info = sof_ipc4_sps_to_time_info(sps);
+ time_info->host_copier = host_copier;
+ time_info->dai_copier = dai_copier;
+ time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers,
+ llp_gpdma_reading_slots) + sdev->fw_info_box.offset;
/* find llp slot used by current dai */
for (i = 0; i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS; i++) {
- sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot));
+ sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot));
if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id)
break;
- info->llp_offset += sizeof(llp_slot);
+ time_info->llp_offset += sizeof(llp_slot);
}
if (i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS)
return;
/* if no llp gpdma slot is used, check aggregated sdw slot */
- info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_sndw_reading_slots) +
- sdev->fw_info_box.offset;
+ time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers,
+ llp_sndw_reading_slots) + sdev->fw_info_box.offset;
for (i = 0; i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS; i++) {
- sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot));
+ sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot));
if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id)
break;
- info->llp_offset += sizeof(llp_slot);
+ time_info->llp_offset += sizeof(llp_slot);
}
if (i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS)
return;
/* check EVAD slot */
- info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_evad_reading_slot) +
- sdev->fw_info_box.offset;
- sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot));
- if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id) {
- dev_info(sdev->dev, "no llp found, fall back to default HDA path");
- info->llp_offset = 0;
- }
+ time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers,
+ llp_evad_reading_slot) + sdev->fw_info_box.offset;
+ sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot));
+ if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id)
+ time_info->llp_offset = 0;
}
static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
@@ -703,12 +1041,15 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
struct snd_sof_platform_stream_params *platform_params)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_ipc4_timestamp_info *time_info;
struct snd_sof_pcm *spcm;
spcm = snd_sof_find_spcm_dai(component, rtd);
- time_info = spcm->stream[substream->stream].private;
+ if (!spcm)
+ return -EINVAL;
+
+ time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
/* delay calculation is not supported by current fw_reg ABI */
if (!time_info)
return 0;
@@ -721,15 +1062,43 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
+static u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value)
+{
+ u64 dai_rate, host_rate;
+
+ if (!time_info->dai_copier || !time_info->host_copier)
+ return value;
+
+ /*
+ * copiers do not change sampling rate, so we can use the
+ * out_format independently of stream direction
+ */
+ dai_rate = time_info->dai_copier->data.out_format.sampling_frequency;
+ host_rate = time_info->host_copier->data.out_format.sampling_frequency;
+
+ if (!dai_rate || !host_rate || dai_rate == host_rate)
+ return value;
+
+ /* take care not to overflow u64, rates can be up to 768000 */
+ if (value > U32_MAX) {
+ value = div64_u64(value, dai_rate);
+ value *= host_rate;
+ } else {
+ value *= host_rate;
+ value = div64_u64(value, dai_rate);
+ }
+
+ return value;
+}
+
static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
- struct snd_sof_pcm_stream *stream,
+ struct snd_sof_pcm_stream *sps,
struct sof_ipc4_timestamp_info *time_info)
{
struct sof_ipc4_copier *host_copier = time_info->host_copier;
struct sof_ipc4_copier *dai_copier = time_info->dai_copier;
struct sof_ipc4_pipeline_registers ppl_reg;
- u64 stream_start_position;
u32 dai_sample_size;
u32 ch, node_index;
u32 offset;
@@ -737,8 +1106,30 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
if (!host_copier || !dai_copier)
return -EINVAL;
- if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID)
+ if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) {
return -EINVAL;
+ } else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
+ /*
+ * While the firmware does not support time_info reporting for
+ * streams using ChainDMA, it is granted that ChainDMA can only
+ * be used on Host+Link pairs where the link position is
+ * accessible from the host side.
+ *
+ * Enable delay calculation in case of ChainDMA via host
+ * accessible registers.
+ *
+ * The ChainDMA prefills the link DMA with a preamble
+ * of zero samples. Set the stream start offset based
+ * on size of the preamble (driver provided fifo size
+ * multiplied by 2.5). We add 1ms of margin as the FW
+ * will align the buffer size to DMA hardware
+ * alignment that is not known to host.
+ */
+ int pre_ms = SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * 5 / 2 + 1;
+
+ time_info->stream_start_offset = pre_ms * substream->runtime->rate / MSEC_PER_SEC;
+ goto out;
+ }
node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id);
offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg);
@@ -746,38 +1137,51 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
if (ppl_reg.stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION)
return -EINVAL;
- stream_start_position = ppl_reg.stream_start_offset;
ch = dai_copier->data.out_format.fmt_cfg;
ch = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(ch);
dai_sample_size = (dai_copier->data.out_format.bit_depth >> 3) * ch;
- /* convert offset to sample count */
- do_div(stream_start_position, dai_sample_size);
- time_info->stream_start_offset = stream_start_position;
+
+ /* convert offsets to frame count */
+ time_info->stream_start_offset = ppl_reg.stream_start_offset;
+ do_div(time_info->stream_start_offset, dai_sample_size);
+ time_info->stream_end_offset = ppl_reg.stream_end_offset;
+ do_div(time_info->stream_end_offset, dai_sample_size);
+
+ /* convert to host frame time */
+ time_info->stream_start_offset =
+ sof_ipc4_frames_dai_to_host(time_info, time_info->stream_start_offset);
+ time_info->stream_end_offset =
+ sof_ipc4_frames_dai_to_host(time_info, time_info->stream_end_offset);
+
+out:
+ /* Initialize the delay value to 0 (no delay) */
+ time_info->delay = 0;
return 0;
}
-static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
+static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t *pointer)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sof_ipc4_timestamp_info *time_info;
struct sof_ipc4_llp_reading_slot llp;
- snd_pcm_uframes_t head_ptr, tail_ptr;
- struct snd_sof_pcm_stream *stream;
+ snd_pcm_uframes_t head_cnt, tail_cnt;
+ struct snd_sof_pcm_stream *sps;
+ u64 dai_cnt, host_cnt, host_ptr;
struct snd_sof_pcm *spcm;
- u64 tmp_ptr;
int ret;
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
- return 0;
+ return -EOPNOTSUPP;
- stream = &spcm->stream[substream->stream];
- time_info = stream->private;
+ sps = &spcm->stream[substream->stream];
+ time_info = sof_ipc4_sps_to_time_info(sps);
if (!time_info)
- return 0;
+ return -EOPNOTSUPP;
/*
* stream_start_offset is updated to memory window by FW based on
@@ -785,47 +1189,125 @@ static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component,
* the statistics is complete. And it will not change after the first initiailization.
*/
if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) {
- ret = sof_ipc4_get_stream_start_offset(sdev, substream, stream, time_info);
+ ret = sof_ipc4_get_stream_start_offset(sdev, substream, sps, time_info);
if (ret < 0)
- return 0;
+ return -EOPNOTSUPP;
}
+ /* For delay calculation we need the host counter */
+ host_cnt = snd_sof_pcm_get_host_byte_counter(sdev, component, substream);
+
+ /* Store the original value to host_ptr */
+ host_ptr = host_cnt;
+
+ /* convert the host_cnt to frames */
+ host_cnt = div64_u64(host_cnt, frames_to_bytes(substream->runtime, 1));
+
/*
- * HDaudio links don't support the LLP counter reported by firmware
- * the link position is read directly from hardware registers.
+ * If the LLP counter is not reported by firmware in the SRAM window
+ * then read the dai (link) counter via host accessible means if
+ * available.
*/
if (!time_info->llp_offset) {
- tmp_ptr = snd_sof_pcm_get_stream_position(sdev, component, substream);
- if (!tmp_ptr)
- return 0;
+ dai_cnt = snd_sof_pcm_get_dai_frame_counter(sdev, component, substream);
+ if (!dai_cnt)
+ return -EOPNOTSUPP;
} else {
sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp));
- tmp_ptr = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l;
+ dai_cnt = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l;
}
- /* In two cases dai dma position is not accurate
+ dai_cnt = sof_ipc4_frames_dai_to_host(time_info, dai_cnt);
+ dai_cnt += time_info->stream_end_offset;
+
+ /* In two cases dai dma counter is not accurate
* (1) dai pipeline is started before host pipeline
- * (2) multiple streams mixed into one. Each stream has the same dai dma position
+ * (2) multiple streams mixed into one. Each stream has the same dai dma
+ * counter
*
- * Firmware calculates correct stream_start_offset for all cases including above two.
- * Driver subtracts stream_start_offset from dai dma position to get accurate one
+ * Firmware calculates correct stream_start_offset for all cases
+ * including above two.
+ * Driver subtracts stream_start_offset from dai dma counter to get
+ * accurate one
*/
- tmp_ptr -= time_info->stream_start_offset;
- /* Calculate the delay taking into account that both pointer can wrap */
- div64_u64_rem(tmp_ptr, substream->runtime->boundary, &tmp_ptr);
+ /*
+ * On stream start the dai counter might not yet have reached the
+ * stream_start_offset value which means that no frames have left the
+ * DSP yet from the audio stream (on playback, capture streams have
+ * offset of 0 as we start capturing right away).
+ * In this case we need to adjust the distance between the counters by
+ * increasing the host counter by (offset - dai_counter).
+ * Otherwise the dai_counter needs to be adjusted to reflect the number
+ * of valid frames passed on the DAI side.
+ *
+ * The delay is the difference between the counters on the two
+ * sides of the DSP.
+ */
+ if (dai_cnt < time_info->stream_start_offset) {
+ host_cnt += time_info->stream_start_offset - dai_cnt;
+ dai_cnt = 0;
+ } else {
+ dai_cnt -= time_info->stream_start_offset;
+ }
+
+ /* Convert to a common base before comparisons */
+ dai_cnt &= DELAY_BOUNDARY;
+ host_cnt &= DELAY_BOUNDARY;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- head_ptr = substream->runtime->status->hw_ptr;
- tail_ptr = tmp_ptr;
+ head_cnt = host_cnt;
+ tail_cnt = dai_cnt;
} else {
- head_ptr = tmp_ptr;
- tail_ptr = substream->runtime->status->hw_ptr;
+ head_cnt = dai_cnt;
+ tail_cnt = host_cnt;
}
- if (head_ptr < tail_ptr)
- return substream->runtime->boundary - tail_ptr + head_ptr;
+ if (unlikely(head_cnt < tail_cnt))
+ time_info->delay = DELAY_BOUNDARY - tail_cnt + head_cnt;
+ else
+ time_info->delay = head_cnt - tail_cnt;
+
+ if (time_info->delay > DELAY_MAX) {
+ spcm_dbg_ratelimited(spcm, substream->stream,
+ "inaccurate delay, host %llu dai_cnt %llu",
+ host_cnt, dai_cnt);
+ time_info->delay = 0;
+ }
+
+ /*
+ * Convert the host byte counter to PCM pointer which wraps in buffer
+ * and it is in frames
+ */
+ div64_u64_rem(host_ptr, snd_pcm_lib_buffer_bytes(substream), &host_ptr);
+ *pointer = bytes_to_frames(substream->runtime, host_ptr);
+
+ return 0;
+}
+
+static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_ipc4_timestamp_info *time_info;
+ struct snd_sof_pcm *spcm;
+
+ spcm = snd_sof_find_spcm_dai(component, rtd);
+ if (!spcm)
+ return 0;
+
+ time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
+ /*
+ * Report the stored delay value calculated in the pointer callback.
+ * In the unlikely event that the calculation was skipped/aborted, the
+ * default 0 delay returned.
+ */
+ if (time_info)
+ return time_info->delay;
+
+ /* No delay information available, report 0 as delay */
+ return 0;
- return head_ptr - tail_ptr;
}
const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
@@ -835,6 +1317,7 @@ const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
.dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
.pcm_setup = sof_ipc4_pcm_setup,
.pcm_free = sof_ipc4_pcm_free,
+ .pointer = sof_ipc4_pcm_pointer,
.delay = sof_ipc4_pcm_delay,
.ipc_first_on_start = true,
.platform_stop_during_hw_free = true,
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index a5d0b2eae464..a8cdf9bc750b 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -3,7 +3,7 @@
* 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) 2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2022 Intel Corporation
*/
#ifndef __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 */
@@ -66,9 +67,13 @@ struct sof_ipc4_fw_library {
* @nhlt: NHLT table either from the BIOS or the topology manifest
* @mtrace_type: mtrace type supported on the booted platform
* @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply
+ * @num_playback_streams: max number of playback DMAs, needed for CHAIN_DMA offset
+ * @num_capture_streams: max number of capture DMAs
* @max_num_pipelines: max number of pipelines
* @max_libs_count: Maximum number of libraries support by the FW including the
* base firmware
+ * @fw_context_save: Firmware supports full context save and restore
+ * @libraries_restored: The libraries have been retained during firmware boot
*
* @load_library: Callback function for platform dependent library loading
* @pipeline_state_mutex: Mutex to protect pipeline triggers, ref counts, states and deletion
@@ -79,45 +84,49 @@ struct sof_ipc4_fw_data {
void *nhlt;
enum sof_ipc4_mtrace_type mtrace_type;
u32 mtrace_log_bytes;
+ int num_playback_streams;
+ int num_capture_streams;
int max_num_pipelines;
u32 max_libs_count;
+ bool fw_context_save;
+ bool libraries_restored;
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 */
};
-/**
- * struct sof_ipc4_timestamp_info - IPC4 timestamp info
- * @host_copier: the host copier of the pcm stream
- * @dai_copier: the dai copier of the pcm stream
- * @stream_start_offset: reported by fw in memory window
- * @llp_offset: llp offset in memory window
- */
-struct sof_ipc4_timestamp_info {
- struct sof_ipc4_copier *host_copier;
- struct sof_ipc4_copier *dai_copier;
- u64 stream_start_offset;
- u32 llp_offset;
-};
-
extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
extern const struct sof_ipc_tplg_ops ipc4_tplg_ops;
extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops;
extern const struct sof_ipc_pcm_ops ipc4_pcm_ops;
extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
-int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
+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,
const guid_t *uuid);
+struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
+ u32 module_id, int instance_id);
+
struct sof_ipc4_base_module_cfg;
void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_module *fw_module,
struct sof_ipc4_base_module_cfg *basecfg);
+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);
+
+enum sof_ipc4_pipeline_state;
+const char *sof_ipc4_pipeline_state_str(enum sof_ipc4_pipeline_state state);
+
#endif
diff --git a/sound/soc/sof/ipc4-telemetry.c b/sound/soc/sof/ipc4-telemetry.c
new file mode 100644
index 000000000000..ddc3bc494ffe
--- /dev/null
+++ b/sound/soc/sof/ipc4-telemetry.c
@@ -0,0 +1,95 @@
+// 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) 2018-2023 Intel Corporation
+//
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <sound/sof/debug.h>
+#include <sound/sof/ipc4/header.h>
+#include "sof-priv.h"
+#include "ops.h"
+#include "ipc4-telemetry.h"
+#include "ipc4-priv.h"
+
+static void __iomem *sof_ipc4_query_exception_address(struct snd_sof_dev *sdev)
+{
+ u32 type = SOF_IPC4_DEBUG_SLOT_TELEMETRY;
+ size_t telemetry_slot_offset;
+ u32 offset;
+
+ telemetry_slot_offset = sof_ipc4_find_debug_slot_offset_by_type(sdev, type);
+ if (!telemetry_slot_offset)
+ return NULL;
+
+ /* skip the first separator magic number */
+ offset = telemetry_slot_offset + sizeof(u32);
+
+ return sdev->bar[sdev->mailbox_bar] + offset;
+}
+
+static ssize_t sof_telemetry_entry_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct snd_sof_dfsentry *dfse = file->private_data;
+ struct snd_sof_dev *sdev = dfse->sdev;
+ void __iomem *io_addr;
+ loff_t pos = *ppos;
+ size_t size_ret;
+ u8 *buf;
+
+ if (pos < 0)
+ return -EINVAL;
+ /* skip the first separator magic number */
+ if (pos >= SOF_IPC4_DEBUG_SLOT_SIZE - 4 || !count)
+ return 0;
+ if (count > SOF_IPC4_DEBUG_SLOT_SIZE - 4 - pos)
+ count = SOF_IPC4_DEBUG_SLOT_SIZE - 4 - pos;
+
+ io_addr = sof_ipc4_query_exception_address(sdev);
+ if (!io_addr)
+ return -EFAULT;
+
+ buf = kzalloc(SOF_IPC4_DEBUG_SLOT_SIZE - 4, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy_fromio(buf, io_addr, SOF_IPC4_DEBUG_SLOT_SIZE - 4);
+ size_ret = copy_to_user(buffer, buf + pos, count);
+ if (size_ret) {
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ *ppos = pos + count;
+ kfree(buf);
+
+ return count;
+}
+
+static const struct file_operations sof_telemetry_fops = {
+ .open = simple_open,
+ .read = sof_telemetry_entry_read,
+};
+
+void sof_ipc4_create_exception_debugfs_node(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_dfsentry *dfse;
+
+ dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
+ if (!dfse)
+ return;
+
+ dfse->type = SOF_DFSENTRY_TYPE_IOMEM;
+ dfse->size = SOF_IPC4_DEBUG_SLOT_SIZE - 4;
+ dfse->access_type = SOF_DEBUGFS_ACCESS_ALWAYS;
+ dfse->sdev = sdev;
+
+ list_add(&dfse->list, &sdev->dfsentry_list);
+
+ debugfs_create_file("exception", 0444, sdev->debugfs_root, dfse, &sof_telemetry_fops);
+}
diff --git a/sound/soc/sof/ipc4-telemetry.h b/sound/soc/sof/ipc4-telemetry.h
new file mode 100644
index 000000000000..9298f8acc648
--- /dev/null
+++ b/sound/soc/sof/ipc4-telemetry.h
@@ -0,0 +1,73 @@
+/* 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) 2023 Intel Corporation
+ */
+
+#ifndef __SOUND_SOC_SOF_IPC4_TELEMETRY_H
+#define __SOUND_SOC_SOF_IPC4_TELEMETRY_H
+
+/* Target code */
+enum sof_ipc4_coredump_tgt_code {
+ COREDUMP_TGT_UNKNOWN = 0,
+ COREDUMP_TGT_X86,
+ COREDUMP_TGT_X86_64,
+ COREDUMP_TGT_ARM_CORTEX_M,
+ COREDUMP_TGT_RISC_V,
+ COREDUMP_TGT_XTENSA,
+};
+
+#define COREDUMP_ARCH_HDR_ID 'A'
+#define COREDUMP_HDR_ID0 'Z'
+#define COREDUMP_HDR_ID1 'E'
+
+#define XTENSA_BLOCK_HDR_VER 2
+#define XTENSA_CORE_DUMP_SEPARATOR 0x0DEC0DEB
+#define XTENSA_CORE_AR_REGS_COUNT 16
+#define XTENSA_SOC_INTEL_ADSP 3
+#define XTENSA_TOOL_CHAIN_ZEPHYR 1
+#define XTENSA_TOOL_CHAIN_XCC 2
+
+/* Coredump header */
+struct sof_ipc4_coredump_hdr {
+ /* 'Z', 'E' as identifier of file */
+ char id[2];
+
+ /* Identify the version of the header */
+ u16 hdr_version;
+
+ /* Indicate which target (e.g. architecture or SoC) */
+ u16 tgt_code;
+
+ /* Size of uintptr_t in power of 2. (e.g. 5 for 32-bit, 6 for 64-bit) */
+ u8 ptr_size_bits;
+
+ u8 flag;
+
+ /* Reason for the fatal error */
+ u32 reason;
+} __packed;
+
+/* Architecture-specific block header */
+struct sof_ipc4_coredump_arch_hdr {
+ /* COREDUMP_ARCH_HDR_ID to indicate this is a architecture-specific block */
+ char id;
+
+ /* Identify the version of this block */
+ u16 hdr_version;
+
+ /* Number of bytes following the header */
+ u16 num_bytes;
+} __packed;
+
+struct sof_ipc4_telemetry_slot_data {
+ u32 separator;
+ struct sof_ipc4_coredump_hdr hdr;
+ struct sof_ipc4_coredump_arch_hdr arch_hdr;
+ u32 arch_data[];
+} __packed;
+
+void sof_ipc4_create_exception_debugfs_node(struct snd_sof_dev *sdev);
+#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index a4e1a70b607d..221e9d4052b8 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -3,10 +3,11 @@
// 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) 2022 Intel Corporation. All rights reserved.
+// Copyright(c) 2022 Intel Corporation
//
//
#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>
@@ -17,13 +18,55 @@
#include "ipc4-topology.h"
#include "ops.h"
+/*
+ * The ignore_cpc flag can be used to ignore the CPC value for all modules by
+ * using 0 instead.
+ * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE
+ * message and it is used for clock scaling.
+ * 0 as CPC value will instruct the firmware to use maximum frequency, thus
+ * deactivating the clock scaling.
+ */
+static bool ignore_cpc;
+module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444);
+MODULE_PARM_DESC(ipc4_ignore_cpc,
+ "Ignore CPC values. This option will disable clock scaling in firmware.");
+
#define SOF_IPC4_GAIN_PARAM_ID 0
#define SOF_IPC4_TPLG_ABI_SIZE 6
-#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
static DEFINE_IDA(alh_group_ida);
static DEFINE_IDA(pipeline_ida);
+struct sof_comp_domains {
+ const char *name;
+ enum sof_comp_domain domain;
+};
+
+static const struct sof_comp_domains sof_domains[] = {
+ { "LL", SOF_COMP_DOMAIN_LL, },
+ { "DP", SOF_COMP_DOMAIN_DP, }
+};
+
+static enum sof_comp_domain find_domain(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sof_domains); i++) {
+ if (strcmp(name, sof_domains[i].name) == 0)
+ return sof_domains[i].domain;
+ }
+ /* No valid value found, fall back to manifest value */
+ return SOF_COMP_DOMAIN_UNSET;
+}
+
+static int get_token_comp_domain(void *elem, void *object, u32 offset)
+{
+ u32 *val = (u32 *)((u8 *)object + offset);
+
+ *val = find_domain((const char *)elem);
+ return 0;
+}
+
static const struct sof_topology_token ipc4_sched_tokens[] = {
{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_pipeline, lp_mode)},
@@ -31,6 +74,8 @@ static const struct sof_topology_token ipc4_sched_tokens[] = {
offsetof(struct sof_ipc4_pipeline, use_chain_dma)},
{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_pipeline, core_id)},
+ {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_pipeline, priority)},
};
static const struct sof_topology_token pipeline_tokens[] = {
@@ -111,22 +156,32 @@ static const struct sof_topology_token comp_ext_tokens[] = {
offsetof(struct snd_sof_widget, uuid)},
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct snd_sof_widget, core)},
+ {SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain,
+ offsetof(struct snd_sof_widget, comp_domain)},
};
static const struct sof_topology_token gain_tokens[] = {
{SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
- get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
+ get_token_u32, offsetof(struct sof_ipc4_gain_params, curve_type)},
{SOF_TKN_GAIN_RAMP_DURATION,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_gain_data, curve_duration_l)},
+ offsetof(struct sof_ipc4_gain_params, curve_duration_l)},
{SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
- get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
+ get_token_u32, offsetof(struct sof_ipc4_gain_params, init_val)},
};
/* SRC */
static const struct sof_topology_token src_tokens[] = {
{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_src, sink_rate)},
+ offsetof(struct sof_ipc4_src_data, sink_rate)},
+};
+
+/* ASRC */
+static const struct sof_topology_token asrc_tokens[] = {
+ {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_asrc_data, out_freq)},
+ {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc4_asrc_data, asrc_mode)},
};
static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
@@ -150,8 +205,29 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
+ [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
};
+struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
+ u32 module_id, int instance_id)
+{
+ struct snd_sof_widget *swidget;
+
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+
+ /* Only active module instances have valid instance_id */
+ if (!swidget->use_count)
+ continue;
+
+ if (fw_module && fw_module->man4_module_entry.id == module_id &&
+ swidget->instance_id == instance_id)
+ return swidget;
+ }
+
+ return NULL;
+}
+
static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
int num_formats)
{
@@ -160,13 +236,109 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_fo
for (i = 0; i < num_formats; i++) {
struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
dev_dbg(dev,
- "Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
- pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
- fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
+ "Pin #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
+ pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth,
+ SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg),
+ fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
pin_fmt[i].buffer_size);
}
}
+static void
+sof_ipc4_dbg_module_audio_format(struct device *dev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_available_audio_format *available_fmt,
+ int in_fmt_index, int out_fmt_index)
+{
+ struct sof_ipc4_audio_format *in_fmt, *out_fmt;
+ u32 out_rate, out_channels, out_valid_bits;
+ u32 in_rate, in_channels, in_valid_bits;
+ struct sof_ipc4_pin_format *pin_fmt;
+
+ if (!available_fmt->num_input_formats &&
+ !available_fmt->num_output_formats)
+ return;
+
+ /* Only input or output is supported by the module */
+ if (!available_fmt->num_input_formats) {
+ if (available_fmt->num_output_formats == 1)
+ dev_dbg(dev, "Output audio format for %s:\n",
+ swidget->widget->name);
+ else
+ dev_dbg(dev,
+ "Output audio format (format index: %d) for %s:\n",
+ out_fmt_index, swidget->widget->name);
+
+ pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index];
+ sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
+
+ return;
+ } else if (!available_fmt->num_output_formats) {
+ if (available_fmt->num_input_formats == 1)
+ dev_dbg(dev, "Input audio format for %s:\n",
+ swidget->widget->name);
+ else
+ dev_dbg(dev,
+ "Input audio format (format index: %d) for %s:\n",
+ out_fmt_index, swidget->widget->name);
+
+ pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
+ sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
+
+ return;
+ }
+
+ in_fmt = &available_fmt->input_pin_fmts[in_fmt_index].audio_fmt;
+ out_fmt = &available_fmt->output_pin_fmts[out_fmt_index].audio_fmt;
+
+ in_rate = in_fmt->sampling_frequency;
+ in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+ out_rate = out_fmt->sampling_frequency;
+ out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg);
+ out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
+
+ if (!(in_valid_bits != out_valid_bits || in_rate != out_rate ||
+ in_channels != out_channels)) {
+ /* There is no change in format */
+ if (available_fmt->num_input_formats == 1 &&
+ available_fmt->num_output_formats == 1)
+ dev_dbg(dev, "Audio format for %s:\n",
+ swidget->widget->name);
+ else
+ dev_dbg(dev,
+ "Audio format (in/out format index: %d/%d) for %s:\n",
+ in_fmt_index, out_fmt_index, swidget->widget->name);
+
+ pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
+ sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
+
+ return;
+ }
+
+ /* The format is changed by the module */
+ if (available_fmt->num_input_formats == 1)
+ dev_dbg(dev, "Input audio format for %s:\n",
+ swidget->widget->name);
+ else
+ dev_dbg(dev, "Input audio format (format index: %d) for %s:\n",
+ in_fmt_index, swidget->widget->name);
+
+ pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
+ sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
+
+ if (available_fmt->num_output_formats == 1)
+ dev_dbg(dev, "Output audio format for %s:\n",
+ swidget->widget->name);
+ else
+ dev_dbg(dev, "Output audio format (format index: %d) for %s:\n",
+ out_fmt_index, swidget->widget->name);
+
+ pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index];
+ sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
+}
+
static const struct sof_ipc4_audio_format *
sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
{
@@ -182,6 +354,14 @@ sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
}
process = swidget->private;
+
+ /*
+ * For process modules without base config extension, base module config
+ * format is used for all input pins
+ */
+ if (process->init_config != SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT)
+ return &process->base_config.audio_fmt;
+
base_cfg_ext = process->base_config_ext;
/*
@@ -218,7 +398,7 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
ret = sof_update_ipc_object(scomp, available_fmt,
SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(available_fmt), 1);
+ swidget->num_tuples, sizeof(*available_fmt), 1);
if (ret) {
dev_err(scomp->dev, "Failed to parse audio format token count\n");
return ret;
@@ -348,7 +528,17 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_
msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
- type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
+ switch (swidget->comp_domain) {
+ case SOF_COMP_DOMAIN_LL:
+ type = 0;
+ break;
+ case SOF_COMP_DOMAIN_DP:
+ type = 1;
+ break;
+ default:
+ type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
+ break;
+ }
msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
return 0;
@@ -372,13 +562,60 @@ static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swi
}
}
+static int
+sof_ipc4_update_card_components_string(struct snd_sof_widget *swidget,
+ struct snd_sof_pcm *spcm, int dir)
+{
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ struct snd_soc_component *scomp = spcm->scomp;
+ struct snd_soc_card *card = scomp->card;
+ const char *pt_marker = "iec61937-pcm";
+
+ /*
+ * Update the card's components list with iec61937-pcm and a list of PCM
+ * ids where ChainDMA is enabled.
+ * These PCMs can be used for bytestream passthrough.
+ */
+ if (!pipeline->use_chain_dma)
+ return 0;
+
+ if (card->components) {
+ const char *tmp = card->components;
+
+ if (strstr(card->components, pt_marker))
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s,%d",
+ card->components,
+ spcm->pcm.pcm_id);
+ else
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s %s:%d",
+ card->components,
+ pt_marker,
+ spcm->pcm.pcm_id);
+
+ devm_kfree(card->dev, tmp);
+ } else {
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s:%d", pt_marker,
+ spcm->pcm.pcm_id);
+ }
+
+ if (!card->components)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
{
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_copier *ipc4_copier;
+ struct snd_sof_pcm *spcm;
int node_type = 0;
- int ret;
+ int ret, dir;
ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
if (!ipc4_copier)
@@ -412,6 +649,34 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
}
dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
+ spcm = snd_sof_find_spcm_comp(scomp, swidget->comp_id, &dir);
+ if (!spcm)
+ goto skip_gtw_cfg;
+
+ ret = sof_ipc4_update_card_components_string(swidget, spcm, dir);
+ if (ret)
+ goto free_available_fmt;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct snd_sof_pcm_stream *sps = &spcm->stream[dir];
+
+ sof_update_ipc_object(scomp, &sps->dsp_max_burst_size_in_ms,
+ SOF_COPIER_DEEP_BUFFER_TOKENS,
+ swidget->tuples,
+ swidget->num_tuples, sizeof(u32), 1);
+ /* Set default DMA buffer size if it is not specified in topology */
+ if (!sps->dsp_max_burst_size_in_ms) {
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+ sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
+ SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
+ }
+ } else {
+ /* Capture data is copied from DSP to host in 1ms bursts */
+ spcm->stream[dir].dsp_max_burst_size_in_ms = 1;
+ }
+
skip_gtw_cfg:
ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
if (!ipc4_copier->gtw_attr) {
@@ -474,6 +739,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
{
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_copier *ipc4_copier;
struct snd_sof_widget *pipe_widget;
@@ -513,14 +779,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
+ dai->type = ipc4_copier->dai_type;
ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
- if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) {
- dev_err(scomp->dev,
- "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n",
- ipc4_copier->dai_type, SOF_DAI_INTEL_HDA);
+
+ if (pipeline->use_chain_dma &&
+ !snd_sof_is_chain_dma_supported(sdev, ipc4_copier->dai_type)) {
+ dev_err(scomp->dev, "Bad DAI type '%d', Chain DMA is not supported\n",
+ ipc4_copier->dai_type);
ret = -ENODEV;
goto free_available_fmt;
}
@@ -528,7 +796,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
switch (ipc4_copier->dai_type) {
case SOF_DAI_INTEL_ALH:
{
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_alh_configuration_blob *blob;
struct snd_soc_dapm_path *p;
struct snd_sof_widget *w;
@@ -544,7 +811,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
* It is fine to call kfree(ipc4_copier->copier_config) since
* ipc4_copier->copier_config is null.
*/
- ret = 0;
break;
}
@@ -555,15 +821,25 @@ 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++;
}
ipc4_copier->copier_config = (uint32_t *)blob;
- ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
+ /* set data.gtw_cfg.config_length based on device_count */
+ ipc4_copier->data.gtw_cfg.config_length = (sizeof(blob->gw_attr) +
+ sizeof(blob->alh_cfg.device_count) +
+ sizeof(*blob->alh_cfg.mapping) *
+ blob->alh_cfg.device_count) >> 2;
break;
}
case SOF_DAI_INTEL_SSP:
@@ -641,6 +917,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_pipeline *pipeline;
+ struct snd_sof_pipeline *spipe = swidget->spipe;
int ret;
pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
@@ -655,6 +932,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
}
swidget->core = pipeline->core_id;
+ spipe->core_mask |= BIT(pipeline->core_id);
if (pipeline->use_chain_dma) {
dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
@@ -670,9 +948,6 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
goto err;
}
- /* TODO: Get priority from topology */
- pipeline->priority = 0;
-
dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d\n",
swidget->widget->name, swidget->pipeline_id,
pipeline->priority, pipeline->core_id, pipeline->lp_mode);
@@ -706,15 +981,15 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
swidget->private = gain;
- gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
- gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
+ gain->data.params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+ gain->data.params.init_val = SOF_IPC4_VOL_ZERO_DB;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->base_config);
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->data.base_config);
if (ret)
goto err;
- ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(gain->data), 1);
+ ret = sof_update_ipc_object(scomp, &gain->data.params, SOF_GAIN_TOKENS,
+ swidget->tuples, swidget->num_tuples, sizeof(gain->data), 1);
if (ret) {
dev_err(scomp->dev, "Parsing gain tokens failed\n");
goto err;
@@ -722,8 +997,8 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
dev_dbg(scomp->dev,
"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
- swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
- gain->data.init_val);
+ swidget->widget->name, gain->data.params.curve_type,
+ gain->data.params.curve_duration_l, gain->data.params.init_val);
ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
if (ret)
@@ -785,6 +1060,7 @@ err:
static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc4_src *src;
int ret;
@@ -796,18 +1072,21 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
swidget->private = src;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, &src->base_config);
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt,
+ &src->data.base_config);
if (ret)
goto err;
- ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
+ ret = sof_update_ipc_object(scomp, &src->data, SOF_SRC_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*src), 1);
if (ret) {
dev_err(scomp->dev, "Parsing SRC tokens failed\n");
goto err;
}
- dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
+ spipe->core_mask |= BIT(swidget->core);
+
+ dev_dbg(scomp->dev, "SRC sink rate %d\n", src->data.sink_rate);
ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
if (ret)
@@ -821,6 +1100,50 @@ err:
return ret;
}
+static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_pipeline *spipe = swidget->spipe;
+ struct sof_ipc4_asrc *asrc;
+ int ret;
+
+ dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+ asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
+ if (!asrc)
+ return -ENOMEM;
+
+ swidget->private = asrc;
+
+ ret = sof_ipc4_get_audio_fmt(scomp, swidget, &asrc->available_fmt,
+ &asrc->data.base_config);
+ if (ret)
+ goto err;
+
+ ret = sof_update_ipc_object(scomp, &asrc->data, SOF_ASRC_TOKENS, swidget->tuples,
+ swidget->num_tuples, sizeof(*asrc), 1);
+ if (ret) {
+ dev_err(scomp->dev, "Parsing ASRC tokens failed\n");
+ goto err;
+ }
+
+ spipe->core_mask |= BIT(swidget->core);
+
+ dev_dbg(scomp->dev, "ASRC sink rate %d, mode 0x%08x\n",
+ asrc->data.out_freq, asrc->data.asrc_mode);
+
+ ret = sof_ipc4_widget_setup_msg(swidget, &asrc->msg);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ sof_ipc4_free_audio_fmt(&asrc->available_fmt);
+ kfree(asrc);
+ swidget->private = NULL;
+ return ret;
+}
+
static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
{
struct sof_ipc4_src *src = swidget->private;
@@ -833,6 +1156,18 @@ static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
swidget->private = NULL;
}
+static void sof_ipc4_widget_free_comp_asrc(struct snd_sof_widget *swidget)
+{
+ struct sof_ipc4_asrc *asrc = swidget->private;
+
+ if (!asrc)
+ return;
+
+ sof_ipc4_free_audio_fmt(&asrc->available_fmt);
+ kfree(swidget->private);
+ swidget->private = NULL;
+}
+
static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
{
struct sof_ipc4_mixer *mixer = swidget->private;
@@ -852,6 +1187,7 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_fw_module *fw_module;
+ struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc4_process *process;
void *cfg;
int ret;
@@ -882,7 +1218,8 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
u32 ext_size = struct_size(base_cfg_ext, pin_formats,
- swidget->num_input_pins + swidget->num_output_pins);
+ size_add(swidget->num_input_pins,
+ swidget->num_output_pins));
base_cfg_ext = kzalloc(ext_size, GFP_KERNEL);
if (!base_cfg_ext) {
@@ -907,6 +1244,9 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
sof_ipc4_widget_update_kcontrol_module_id(swidget);
+ /* set pipeline core mask to keep track of the core the module is scheduled to run on */
+ spipe->core_mask |= BIT(swidget->core);
+
return 0;
free_base_cfg_ext:
kfree(process->base_config_ext);
@@ -970,9 +1310,16 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *
/* Update base_config->cpc from the module manifest */
sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
- dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
- swidget->widget->name, base_config->ibs, base_config->obs,
- base_config->cpc);
+ if (ignore_cpc) {
+ dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n",
+ swidget->widget->name, base_config->ibs, base_config->obs,
+ base_config->cpc);
+ base_config->cpc = 0;
+ } else {
+ dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
+ swidget->widget->name, base_config->ibs, base_config->obs,
+ base_config->cpc);
+ }
}
static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
@@ -991,44 +1338,96 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
return 0;
}
+static u32 sof_ipc4_fmt_cfg_to_type(u32 fmt_cfg)
+{
+ /* Fetch the sample type from the fmt for 8 and 32 bit formats */
+ u32 __bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt_cfg);
+
+ if (__bits == 8 || __bits == 32)
+ return SOF_IPC4_AUDIO_FORMAT_CFG_SAMPLE_TYPE(fmt_cfg);
+
+ /*
+ * Return LSB integer type for 20 and 24 formats as the firmware is
+ * handling the LSB/MSB alignment internally, for the kernel this
+ * should not be taken into account, we treat them as LSB to match with
+ * the format we support on the PCM side.
+ */
+ return SOF_IPC4_TYPE_LSB_INTEGER;
+}
+
/* update hw_params based on the audio stream format */
static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params,
- struct sof_ipc4_audio_format *fmt)
+ struct sof_ipc4_audio_format *fmt, u32 param_to_update)
{
- snd_pcm_format_t snd_fmt;
struct snd_interval *i;
- struct snd_mask *m;
- int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- unsigned int channels, rate;
- switch (valid_bits) {
- case 16:
- snd_fmt = SNDRV_PCM_FORMAT_S16_LE;
- break;
- case 24:
- snd_fmt = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 32:
- snd_fmt = SNDRV_PCM_FORMAT_S32_LE;
- break;
- default:
- dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits);
- return -EINVAL;
+ if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
+ int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+ int type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
+ snd_pcm_format_t snd_fmt;
+ struct snd_mask *m;
+
+ switch (valid_bits) {
+ case 8:
+ switch (type) {
+ case SOF_IPC4_TYPE_A_LAW:
+ snd_fmt = SNDRV_PCM_FORMAT_A_LAW;
+ break;
+ case SOF_IPC4_TYPE_MU_LAW:
+ snd_fmt = SNDRV_PCM_FORMAT_MU_LAW;
+ break;
+ case SOF_IPC4_TYPE_UNSIGNED_INTEGER:
+ snd_fmt = SNDRV_PCM_FORMAT_U8;
+ break;
+ default:
+ dev_err(sdev->dev, "Unsupported PCM 8-bit IPC4 type %d\n", type);
+ return -EINVAL;
+ }
+ break;
+ case 16:
+ snd_fmt = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 24:
+ snd_fmt = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 32:
+ switch (type) {
+ case SOF_IPC4_TYPE_LSB_INTEGER:
+ snd_fmt = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ case SOF_IPC4_TYPE_FLOAT:
+ snd_fmt = SNDRV_PCM_FORMAT_FLOAT_LE;
+ break;
+ default:
+ dev_err(sdev->dev, "Unsupported PCM 32-bit IPC4 type %d\n", type);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits);
+ return -EINVAL;
+ }
+
+ m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ snd_mask_none(m);
+ snd_mask_set_format(m, snd_fmt);
}
- m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- snd_mask_none(m);
- snd_mask_set_format(m, snd_fmt);
+ if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
+ unsigned int rate = fmt->sampling_frequency;
- rate = fmt->sampling_frequency;
- i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- i->min = rate;
- i->max = rate;
+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ i->min = rate;
+ i->max = rate;
+ }
- channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- i->min = channels;
- i->max = channels;
+ if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
+ unsigned int channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+
+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ i->min = channels;
+ i->max = channels;
+ }
return 0;
}
@@ -1062,64 +1461,104 @@ static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev,
}
static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
struct sof_ipc4_base_module_cfg *base_config,
struct sof_ipc4_available_audio_format *available_fmt,
u32 out_ref_rate, u32 out_ref_channels,
- u32 out_ref_valid_bits)
+ u32 out_ref_valid_bits, u32 out_ref_type)
{
- struct sof_ipc4_audio_format *out_fmt;
+ struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts;
+ u32 pin_fmts_size = available_fmt->num_output_formats;
bool single_format;
- int i;
+ int i = 0;
- if (!available_fmt->num_output_formats)
+ if (!pin_fmts_size) {
+ dev_err(sdev->dev, "no output formats for %s\n",
+ swidget->widget->name);
return -EINVAL;
+ }
- single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts,
- available_fmt->num_output_formats);
+ single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size);
/* pick the first format if there's only one available or if all formats are the same */
- if (single_format) {
- base_config->obs = available_fmt->output_pin_fmts[0].buffer_size;
- return 0;
- }
+ if (single_format)
+ goto out_fmt;
/*
* if there are multiple output formats, then choose the output format that matches
* the reference params
*/
- for (i = 0; i < available_fmt->num_output_formats; i++) {
- u32 _out_rate, _out_channels, _out_valid_bits;
+ for (i = 0; i < pin_fmts_size; i++) {
+ struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
+
+ u32 _out_rate, _out_channels, _out_valid_bits, _out_type;
- out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt;
- _out_rate = out_fmt->sampling_frequency;
- _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg);
- _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
+ _out_rate = fmt->sampling_frequency;
+ _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+ _out_type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
if (_out_rate == out_ref_rate && _out_channels == out_ref_channels &&
- _out_valid_bits == out_ref_valid_bits) {
- base_config->obs = available_fmt->output_pin_fmts[i].buffer_size;
- return i;
- }
+ _out_valid_bits == out_ref_valid_bits && _out_type == out_ref_type)
+ goto out_fmt;
}
+ dev_err(sdev->dev,
+ "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n",
+ __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels,
+ out_ref_type);
+
return -EINVAL;
+
+out_fmt:
+ base_config->obs = pin_fmts[i].buffer_size;
+
+ return i;
}
static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
{
switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
+ case SNDRV_PCM_FORMAT_MU_LAW:
+ case SNDRV_PCM_FORMAT_A_LAW:
+ return 8;
case SNDRV_PCM_FORMAT_S16_LE:
return 16;
case SNDRV_PCM_FORMAT_S24_LE:
return 24;
case SNDRV_PCM_FORMAT_S32_LE:
return 32;
+ case SNDRV_PCM_FORMAT_FLOAT_LE:
+ return 32;
default:
dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
return -EINVAL;
}
}
+static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
+{
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_A_LAW:
+ return SOF_IPC4_TYPE_A_LAW;
+ case SNDRV_PCM_FORMAT_MU_LAW:
+ return SOF_IPC4_TYPE_MU_LAW;
+ case SNDRV_PCM_FORMAT_U8:
+ return SOF_IPC4_TYPE_UNSIGNED_INTEGER;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ return SOF_IPC4_TYPE_LSB_INTEGER;
+ case SNDRV_PCM_FORMAT_FLOAT_LE:
+ return SOF_IPC4_TYPE_FLOAT;
+ default:
+ dev_err(sdev->dev, "invalid pcm sample type %d\n", params_format(params));
+ return -EINVAL;
+ }
+}
+
static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget,
struct sof_ipc4_base_module_cfg *base_config,
@@ -1131,17 +1570,18 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
u32 valid_bits;
u32 channels;
u32 rate;
+ u32 type;
bool single_format;
int sample_valid_bits;
+ int sample_type;
int i = 0;
- if (!available_fmt->num_input_formats) {
+ if (!pin_fmts_size) {
dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name);
return -EINVAL;
}
- single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts,
- available_fmt->num_input_formats);
+ single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size);
if (single_format)
goto in_fmt;
@@ -1149,6 +1589,10 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
if (sample_valid_bits < 0)
return sample_valid_bits;
+ sample_type = sof_ipc4_get_sample_type(sdev, params);
+ if (sample_type < 0)
+ return sample_type;
+
/*
* Search supported input audio formats with pin index 0 to match rate, channels and
* sample_valid_bits from reference params
@@ -1162,32 +1606,27 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
rate = fmt->sampling_frequency;
channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+ type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
if (params_rate(params) == rate && params_channels(params) == channels &&
- sample_valid_bits == valid_bits) {
- dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n",
- rate, valid_bits, channels, i);
+ sample_valid_bits == valid_bits && sample_type == type)
break;
- }
}
if (i == pin_fmts_size) {
- dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
- __func__, params_rate(params), sample_valid_bits, params_channels(params));
+ dev_err(sdev->dev,
+ "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n",
+ __func__, params_rate(params), sample_valid_bits,
+ params_channels(params), sample_type);
return -EINVAL;
}
in_fmt:
/* copy input format */
- if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) {
- memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt,
- sizeof(struct sof_ipc4_audio_format));
-
- /* set base_cfg ibs/obs */
- base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size;
+ memcpy(&base_config->audio_fmt, &pin_fmts[i].audio_fmt,
+ sizeof(struct sof_ipc4_audio_format));
- dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
- sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1);
- }
+ /* set base_cfg ibs/obs */
+ base_config->ibs = pin_fmts[i].buffer_size;
return i;
}
@@ -1215,12 +1654,17 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
ipc4_copier = dai->private;
if (pipeline->use_chain_dma) {
- pipeline->msg.primary = 0;
+ /*
+ * Preserve the DMA Link ID and clear other bits since
+ * the DMA Link ID is only configured once during
+ * dai_config, other fields are expected to be 0 for
+ * re-configuration
+ */
+ pipeline->msg.primary &= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
pipeline->msg.extension = 0;
}
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
- struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
struct sof_ipc4_alh_configuration_blob *blob;
unsigned int group_id;
@@ -1230,9 +1674,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
ALH_MULTI_GTW_BASE;
ida_free(&alh_group_ida, group_id);
}
-
- /* clear the node ID */
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
}
}
@@ -1290,23 +1731,36 @@ static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof
return 0;
}
-static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
- struct snd_pcm_hw_params *params, u32 dai_index,
- u32 linktype, u8 dir, u32 **dst, u32 *len)
+static int
+snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+ bool single_bitdepth,
+ struct snd_pcm_hw_params *params, u32 dai_index,
+ u32 linktype, u8 dir, u32 **dst, u32 *len)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct nhlt_specific_cfg *cfg;
int sample_rate, channel_count;
+ bool format_change = false;
int bit_depth, ret;
u32 nhlt_type;
+ int dev_type = 0;
/* convert to NHLT type */
switch (linktype) {
case SOF_DAI_INTEL_DMIC:
nhlt_type = NHLT_LINK_DMIC;
- bit_depth = params_width(params);
channel_count = params_channels(params);
sample_rate = params_rate(params);
+ bit_depth = params_width(params);
+ /*
+ * Look for 32-bit blob first instead of 16-bit if copier
+ * supports multiple formats
+ */
+ if (bit_depth == 16 && !single_bitdepth) {
+ dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n");
+ format_change = true;
+ bit_depth = 32;
+ }
break;
case SOF_DAI_INTEL_SSP:
nhlt_type = NHLT_LINK_SSP;
@@ -1314,61 +1768,231 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
&bit_depth);
if (ret < 0)
return ret;
+
+ /*
+ * We need to know the type of the external device attached to a SSP
+ * port to retrieve the blob from NHLT. However, device type is not
+ * specified in topology.
+ * Query the type for the port and then pass that information back
+ * to the blob lookup function.
+ */
+ dev_type = intel_nhlt_ssp_device_type(sdev->dev, ipc4_data->nhlt,
+ dai_index);
+ if (dev_type < 0)
+ return dev_type;
break;
default:
return 0;
}
- dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
- dai_index, nhlt_type, dir);
+ dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d dev type %d\n",
+ dai_index, nhlt_type, dir, dev_type);
/* find NHLT blob with matching params */
cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
bit_depth, bit_depth, channel_count, sample_rate,
- dir, 0);
+ dir, dev_type);
if (!cfg) {
+ bool get_new_blob = false;
+
+ if (format_change) {
+ /*
+ * The 32-bit blob was not found in NHLT table, try to
+ * look for one based on the params
+ */
+ bit_depth = params_width(params);
+ format_change = false;
+ get_new_blob = true;
+ } else if (linktype == SOF_DAI_INTEL_DMIC && !single_bitdepth) {
+ /*
+ * The requested 32-bit blob (no format change for the
+ * blob request) was not found in NHLT table, try to
+ * look for 16-bit blob if the copier supports multiple
+ * formats
+ */
+ bit_depth = 16;
+ format_change = true;
+ get_new_blob = true;
+ }
+
+ if (get_new_blob) {
+ cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt,
+ dai_index, nhlt_type,
+ bit_depth, bit_depth,
+ channel_count, sample_rate,
+ dir, dev_type);
+ if (cfg)
+ goto out;
+ }
+
dev_err(sdev->dev,
"no matching blob for sample rate: %d sample width: %d channels: %d\n",
sample_rate, bit_depth, channel_count);
return -EINVAL;
}
+out:
/* config length should be in dwords */
*len = cfg->size >> 2;
*dst = (u32 *)cfg->caps;
+ if (format_change) {
+ /*
+ * Update the params to reflect that different blob was loaded
+ * instead of the requested bit depth (16 -> 32 or 32 -> 16).
+ * This information is going to be used by the caller to find
+ * matching copier format on the dai side.
+ */
+ struct snd_mask *m;
+
+ m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ snd_mask_none(m);
+ if (bit_depth == 16)
+ snd_mask_set_format(m, SNDRV_PCM_FORMAT_S16_LE);
+ else
+ snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE);
+
+ }
+
return 0;
}
#else
-static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
- struct snd_pcm_hw_params *params, u32 dai_index,
- u32 linktype, u8 dir, u32 **dst, u32 *len)
+static int
+snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+ bool single_bitdepth,
+ struct snd_pcm_hw_params *params, u32 dai_index,
+ u32 linktype, u8 dir, u32 **dst, u32 *len)
{
return 0;
}
#endif
-static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth)
+bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev,
+ struct sof_ipc4_pin_format *pin_fmts,
+ u32 pin_fmts_size)
{
- switch (bit_depth) {
- case 16:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
- break;
- case 24:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- break;
- case 32:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
- break;
- default:
- return -EINVAL;
+ struct sof_ipc4_audio_format *fmt;
+ u32 valid_bits;
+ int i;
+
+ fmt = &pin_fmts[0].audio_fmt;
+ valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ /* check if all formats in topology are the same */
+ for (i = 1; i < pin_fmts_size; i++) {
+ u32 _valid_bits;
+
+ fmt = &pin_fmts[i].audio_fmt;
+ _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ if (_valid_bits != valid_bits)
+ return false;
}
+ return true;
+}
+
+static int
+sof_ipc4_adjust_params_to_dai_format(struct snd_sof_dev *sdev,
+ struct snd_pcm_hw_params *params,
+ struct sof_ipc4_pin_format *pin_fmts,
+ u32 pin_fmts_size)
+{
+ u32 params_mask = BIT(SNDRV_PCM_HW_PARAM_RATE) |
+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
+ BIT(SNDRV_PCM_HW_PARAM_FORMAT);
+ struct sof_ipc4_audio_format *fmt;
+ u32 rate, channels, valid_bits;
+ int i;
+
+ fmt = &pin_fmts[0].audio_fmt;
+ rate = fmt->sampling_frequency;
+ channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ /* check if parameters in topology defined formats are the same */
+ for (i = 1; i < pin_fmts_size; i++) {
+ u32 val;
+
+ fmt = &pin_fmts[i].audio_fmt;
+
+ if (params_mask & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
+ val = fmt->sampling_frequency;
+ if (val != rate)
+ params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_RATE);
+ }
+ if (params_mask & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
+ val = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ if (val != channels)
+ params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_CHANNELS);
+ }
+ if (params_mask & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
+ val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+ if (val != valid_bits)
+ params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_FORMAT);
+ }
+ }
+
+ if (params_mask)
+ return sof_ipc4_update_hw_params(sdev, params,
+ &pin_fmts[0].audio_fmt,
+ params_mask);
+
return 0;
}
static int
+sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+ struct snd_pcm_hw_params *params, int dir)
+{
+ struct sof_ipc4_available_audio_format *available_fmt;
+ struct snd_pcm_hw_params dai_params = *params;
+ struct sof_ipc4_copier_data *copier_data;
+ struct sof_ipc4_pin_format *pin_fmts;
+ struct sof_ipc4_copier *ipc4_copier;
+ bool single_bitdepth;
+ u32 num_pin_fmts;
+ int ret;
+
+ ipc4_copier = dai->private;
+ copier_data = &ipc4_copier->data;
+ available_fmt = &ipc4_copier->available_fmt;
+
+ /*
+ * Fixup the params based on the format parameters of the DAI. If any
+ * of the RATE, CHANNELS, bit depth is static among the formats then
+ * narrow the params to only allow that specific parameter value.
+ */
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ pin_fmts = available_fmt->output_pin_fmts;
+ num_pin_fmts = available_fmt->num_output_formats;
+ } else {
+ pin_fmts = available_fmt->input_pin_fmts;
+ num_pin_fmts = available_fmt->num_input_formats;
+ }
+
+ ret = sof_ipc4_adjust_params_to_dai_format(sdev, &dai_params, pin_fmts,
+ num_pin_fmts);
+ if (ret)
+ return ret;
+
+ single_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev, pin_fmts,
+ num_pin_fmts);
+ ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_bitdepth,
+ &dai_params,
+ ipc4_copier->dai_index,
+ ipc4_copier->dai_type, dir,
+ &ipc4_copier->copier_config,
+ &copier_data->gtw_cfg.config_length);
+ /* Update the params to reflect the changes made in this function */
+ if (!ret)
+ *params = dai_params;
+
+ return ret;
+}
+
+static int
sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_pcm_hw_params *fe_params,
struct snd_sof_platform_stream_params *platform_params,
@@ -1378,30 +2002,34 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_copier_data *copier_data;
- struct snd_pcm_hw_params *ref_params;
+ int input_fmt_index, output_fmt_index;
struct sof_ipc4_copier *ipc4_copier;
+ struct snd_pcm_hw_params *ref_params __free(kfree) = NULL;
struct snd_sof_dai *dai;
- struct snd_mask *fmt;
- int out_sample_valid_bits;
u32 gtw_cfg_config_length;
u32 dma_config_tlv_size = 0;
void **ipc_config_data;
int *ipc_config_size;
u32 **data;
int ipc_size, ret, out_ref_valid_bits;
- u32 out_ref_rate, out_ref_channels;
+ u32 out_ref_rate, out_ref_channels, out_ref_type;
u32 deep_buffer_dma_ms = 0;
- int output_fmt_index;
-
- dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
+ bool single_output_bitdepth;
+ int i;
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,
@@ -1418,9 +2046,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;
@@ -1428,10 +2053,13 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
host_dma_id = platform_params->stream_tag - 1;
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
- /* Set SCS bit for S16_LE format only */
if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE)
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
+ /* Set SCS bit for 8 and 16 bit formats */
+ if (params_physical_width(fe_params) <= 16)
+ pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
+
/*
* Despite its name the bitfield 'fifo_size' is used to define DMA buffer
* size. The expression calculates 2ms buffer size.
@@ -1443,10 +2071,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
/*
- * Chain DMA does not support stream timestamping, set node_id to invalid
- * to skip the code in sof_ipc4_get_stream_start_offset().
+ * Chain DMA does not support stream timestamping, but it
+ * can use the host side registers for delay calculation.
*/
- copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
+ copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID;
return 0;
}
@@ -1456,9 +2084,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 |=
@@ -1474,6 +2104,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;
@@ -1484,31 +2118,42 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
available_fmt = &ipc4_copier->available_fmt;
/*
- * When there is format conversion within a pipeline, the number of supported
- * output formats is typically limited to just 1 for the DAI copiers. But when there
- * is no format conversion, the DAI copiers input format must match that of the
- * FE hw_params for capture and the pipeline params for playback.
+ * Use the fe_params as a base for the copier configuration.
+ * The ref_params might get updated to reflect what format is
+ * supported by the copier on the DAI side.
+ *
+ * In case of capture the ref_params returned will be used to
+ * find the input configuration of the copier.
*/
- if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- ref_params = pipeline_params;
- else
- ref_params = fe_params;
+ ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
+ if (!ref_params)
+ return -ENOMEM;
- ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
- ipc4_copier->dai_type, dir,
- &ipc4_copier->copier_config,
- &copier_data->gtw_cfg.config_length);
+ ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir);
if (ret < 0)
return ret;
+ /*
+ * For playback the pipeline_params needs to be used to find the
+ * input configuration of the copier.
+ */
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ 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;
}
@@ -1519,12 +2164,16 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
}
/* set input and output audio formats */
- ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params,
- available_fmt);
- if (ret < 0)
- return ret;
+ input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
+ &copier_data->base_config,
+ ref_params, available_fmt);
+ if (input_fmt_index < 0)
+ return input_fmt_index;
/* set the reference params for output format selection */
+ single_output_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev,
+ available_fmt->output_pin_fmts,
+ available_fmt->num_output_formats);
switch (swidget->id) {
case snd_soc_dapm_aif_in:
case snd_soc_dapm_dai_out:
@@ -1532,20 +2181,30 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
{
struct sof_ipc4_audio_format *in_fmt;
- in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
out_ref_rate = in_fmt->sampling_frequency;
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
+
+ if (!single_output_bitdepth)
+ out_ref_valid_bits =
+ SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
break;
}
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai_in:
- out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
- if (out_ref_valid_bits < 0)
- return out_ref_valid_bits;
-
out_ref_rate = params_rate(fe_params);
out_ref_channels = params_channels(fe_params);
+ ret = sof_ipc4_get_sample_type(sdev, fe_params);
+ if (ret < 0)
+ return ret;
+ out_ref_type = (u32)ret;
+
+ if (!single_output_bitdepth) {
+ out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
+ if (out_ref_valid_bits < 0)
+ return out_ref_valid_bits;
+ }
break;
default:
/*
@@ -1555,14 +2214,26 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
return -EINVAL;
}
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config,
+ /*
+ * if the output format is the same across all available output formats, choose
+ * that as the reference.
+ */
+ if (single_output_bitdepth) {
+ struct sof_ipc4_audio_format *out_fmt;
+
+ out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
+ out_ref_valid_bits =
+ SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
+ out_ref_type = sof_ipc4_fmt_cfg_to_type(out_fmt->fmt_cfg);
+ }
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
+ &copier_data->base_config,
available_fmt, out_ref_rate,
- out_ref_channels, out_ref_valid_bits);
- if (output_fmt_index < 0) {
- dev_err(sdev->dev, "Failed to initialize output format for %s",
- swidget->widget->name);
+ out_ref_channels, out_ref_valid_bits,
+ out_ref_type);
+ if (output_fmt_index < 0)
return output_fmt_index;
- }
/*
* Set the output format. Current topology defines pin 0 input and output formats in pairs.
@@ -1574,8 +2245,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
memcpy(&copier_data->out_format,
&available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
sizeof(struct sof_ipc4_audio_format));
- dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name);
- sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1);
switch (swidget->id) {
case snd_soc_dapm_dai_in:
@@ -1587,6 +2256,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*/
if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
struct sof_ipc4_alh_configuration_blob *blob;
+ struct sof_ipc4_dma_config *dma_config;
struct sof_ipc4_copier_data *alh_data;
struct sof_ipc4_copier *alh_copier;
struct snd_sof_widget *w;
@@ -1595,7 +2265,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
u32 ch_map;
u32 step;
u32 mask;
- int i;
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
@@ -1619,14 +2288,33 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*/
i = 0;
list_for_each_entry(w, &sdev->widget_list, list) {
- if (w->widget->sname &&
+ u32 node_type;
+
+ 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;
- blob->alh_cfg.mapping[i].device = alh_data->gtw_cfg.node_id;
+ node_type = SOF_IPC4_GET_NODE_TYPE(alh_data->gtw_cfg.node_id);
+ blob->alh_cfg.mapping[i].device = SOF_IPC4_NODE_TYPE(node_type);
+ blob->alh_cfg.mapping[i].device |=
+ SOF_IPC4_NODE_INDEX(alh_copier->dai_index);
+
+ /*
+ * The mapping[i] device in ALH blob should be the same as the
+ * dma_config_tlv[i] mapping device if a dma_config_tlv is present.
+ * The device id will be used for DMA tlv mapping purposes.
+ */
+ if (ipc4_copier->dma_config_tlv[i].length) {
+ dma_config = &ipc4_copier->dma_config_tlv[i].dma_config;
+ blob->alh_cfg.mapping[i].device =
+ dma_config->dma_stream_channel_map.mapping[0].device;
+ }
+
/*
* Set the same channel mask for playback as the audio data is
* duplicated for all speakers. For capture, split the channels
@@ -1664,11 +2352,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
}
/* modify the input params for the next widget */
- fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
- out_sample_valid_bits =
- SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
- snd_mask_none(fmt);
- ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits);
+ ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
+ &copier_data->out_format,
+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
+ BIT(SNDRV_PCM_HW_PARAM_RATE));
if (ret)
return ret;
@@ -1683,9 +2371,14 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
break;
case snd_soc_dapm_aif_in:
- copier_data->gtw_cfg.dma_buffer_size =
- max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
- copier_data->base_config.ibs;
+ copier_data->gtw_cfg.dma_buffer_size =
+ max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
+ copier_data->base_config.ibs;
+ dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)",
+ swidget->widget->name,
+ deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
+ max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms),
+ copier_data->gtw_cfg.dma_buffer_size);
break;
case snd_soc_dapm_dai_out:
case snd_soc_dapm_aif_out:
@@ -1704,19 +2397,18 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
ipc_size = sizeof(*copier_data) + gtw_cfg_config_length;
- if (ipc4_copier->dma_config_tlv.type == SOF_IPC4_GTW_DMA_CONFIG_ID &&
- ipc4_copier->dma_config_tlv.length) {
- dma_config_tlv_size = sizeof(ipc4_copier->dma_config_tlv) +
- ipc4_copier->dma_config_tlv.dma_config.dma_priv_config_size;
-
- /* paranoia check on TLV size/length */
- if (dma_config_tlv_size != ipc4_copier->dma_config_tlv.length +
- sizeof(uint32_t) * 2) {
- dev_err(sdev->dev, "Invalid configuration, TLV size %d length %d\n",
- dma_config_tlv_size, ipc4_copier->dma_config_tlv.length);
- return -EINVAL;
- }
+ dma_config_tlv_size = 0;
+ for (i = 0; i < SOF_IPC4_DMA_DEVICE_MAX_COUNT; i++) {
+ if (ipc4_copier->dma_config_tlv[i].type != SOF_IPC4_GTW_DMA_CONFIG_ID)
+ continue;
+ dma_config_tlv_size += ipc4_copier->dma_config_tlv[i].length;
+ dma_config_tlv_size +=
+ ipc4_copier->dma_config_tlv[i].dma_config.dma_priv_config_size;
+ dma_config_tlv_size += (sizeof(ipc4_copier->dma_config_tlv[i]) -
+ sizeof(ipc4_copier->dma_config_tlv[i].dma_config));
+ }
+ if (dma_config_tlv_size) {
ipc_size += dma_config_tlv_size;
/* we also need to increase the size at the gtw level */
@@ -1731,6 +2423,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*ipc_config_size = ipc_size;
+ sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
+ input_fmt_index, output_fmt_index);
+
+ /* update pipeline memory usage */
+ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
+
/* copy IPC data */
memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
if (gtw_cfg_config_length)
@@ -1743,8 +2441,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
gtw_cfg_config_length,
&ipc4_copier->dma_config_tlv, dma_config_tlv_size);
- /* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
+ /*
+ * Restore gateway config length now that IPC payload is prepared. This avoids
+ * counting the DMA CONFIG TLV multiple times
+ */
+ copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
return 0;
}
@@ -1759,29 +2460,37 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
struct sof_ipc4_gain *gain = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
struct sof_ipc4_audio_format *in_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
- int ret;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
+ int input_fmt_index, output_fmt_index;
- ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->base_config,
- pipeline_params, available_fmt);
- if (ret < 0)
- return ret;
+ input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
+ &gain->data.base_config,
+ pipeline_params,
+ available_fmt);
+ if (input_fmt_index < 0)
+ return input_fmt_index;
- in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
out_ref_rate = in_fmt->sampling_frequency;
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
+ &gain->data.base_config,
+ available_fmt,
+ out_ref_rate,
+ out_ref_channels,
+ out_ref_valid_bits,
+ out_ref_type);
+ if (output_fmt_index < 0)
+ return output_fmt_index;
- ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->base_config, available_fmt,
- out_ref_rate, out_ref_channels, out_ref_valid_bits);
- if (ret < 0) {
- dev_err(sdev->dev, "Failed to initialize output format for %s",
- swidget->widget->name);
- return ret;
- }
+ sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
+ input_fmt_index, output_fmt_index);
/* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &gain->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config);
return 0;
}
@@ -1796,26 +2505,34 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
struct sof_ipc4_mixer *mixer = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
struct sof_ipc4_audio_format *in_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
- int ret;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
+ int input_fmt_index, output_fmt_index;
- ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config,
- pipeline_params, available_fmt);
- if (ret < 0)
- return ret;
+ input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
+ &mixer->base_config,
+ pipeline_params,
+ available_fmt);
+ if (input_fmt_index < 0)
+ return input_fmt_index;
- in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
+ in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
out_ref_rate = in_fmt->sampling_frequency;
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
+ &mixer->base_config,
+ available_fmt,
+ out_ref_rate,
+ out_ref_channels,
+ out_ref_valid_bits,
+ out_ref_type);
+ if (output_fmt_index < 0)
+ return output_fmt_index;
- ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt,
- out_ref_rate, out_ref_channels, out_ref_valid_bits);
- if (ret < 0) {
- dev_err(sdev->dev, "Failed to initialize output format for %s",
- swidget->widget->name);
- return ret;
- }
+ sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
+ input_fmt_index, output_fmt_index);
/* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config);
@@ -1832,37 +2549,68 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_src *src = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
- struct sof_ipc4_audio_format *in_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
- struct snd_interval *rate;
- int ret;
+ struct sof_ipc4_audio_format *out_audio_fmt;
+ struct sof_ipc4_audio_format *in_audio_fmt;
+ u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
+ int output_fmt_index, input_fmt_index;
+
+ input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
+ &src->data.base_config,
+ pipeline_params,
+ available_fmt);
+ if (input_fmt_index < 0)
+ return input_fmt_index;
- ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
- pipeline_params, available_fmt);
- if (ret < 0)
- return ret;
+ /*
+ * For playback, the SRC sink rate will be configured based on the requested output
+ * format, which is restricted to only deal with DAI's with a single format for now.
+ */
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) {
+ dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n",
+ available_fmt->num_output_formats, swidget->widget->name);
+ return -EINVAL;
+ }
- in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ /*
+ * SRC does not perform format conversion, so the output channels and valid bit depth must
+ * be the same as that of the input.
+ */
+ in_audio_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg);
+ out_ref_type = sof_ipc4_fmt_cfg_to_type(in_audio_fmt->fmt_cfg);
- ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt,
- out_ref_rate, out_ref_channels, out_ref_valid_bits);
- if (ret < 0) {
- dev_err(sdev->dev, "Failed to initialize output format for %s",
- swidget->widget->name);
- }
+ /*
+ * For capture, the SRC module should convert the rate to match the rate requested by the
+ * PCM hw_params. Set the reference params based on the fe_params unconditionally as it
+ * will be ignored for playback anyway.
+ */
+ out_ref_rate = params_rate(fe_params);
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
+ &src->data.base_config,
+ available_fmt,
+ out_ref_rate,
+ out_ref_channels,
+ out_ref_valid_bits,
+ out_ref_type);
+ if (output_fmt_index < 0)
+ return output_fmt_index;
+
+ sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
+ input_fmt_index, output_fmt_index);
/* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config);
+ sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config);
- /* update pipeline_params for sink widgets */
- rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
- rate->min = src->sink_rate;
- rate->max = rate->min;
+ out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt;
+ src->data.sink_rate = out_audio_fmt->sampling_frequency;
- return 0;
+ /* update pipeline_params for sink widgets */
+ return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt,
+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
+ BIT(SNDRV_PCM_HW_PARAM_RATE));
}
static int
@@ -1952,45 +2700,63 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_process *process = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
- struct sof_ipc4_audio_format *in_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
void *cfg = process->ipc_config_data;
- int output_fmt_index;
+ int output_fmt_index = 0;
+ int input_fmt_index = 0;
int ret;
- ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config,
- pipeline_params, available_fmt);
- if (ret < 0)
- return ret;
-
- in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
+ &process->base_config,
+ pipeline_params,
+ available_fmt);
+ if (input_fmt_index < 0)
+ return input_fmt_index;
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config,
- available_fmt, out_ref_rate,
- out_ref_channels, out_ref_valid_bits);
- if (output_fmt_index < 0 && available_fmt->num_output_formats) {
- dev_err(sdev->dev, "Failed to initialize output format for %s",
- swidget->widget->name);
- return output_fmt_index;
- }
+ /* Configure output audio format only if the module supports output */
+ if (available_fmt->num_output_formats) {
+ struct sof_ipc4_audio_format *in_fmt;
+ struct sof_ipc4_pin_format *pin_fmt;
+ u32 out_ref_rate, out_ref_channels;
+ int out_ref_valid_bits, out_ref_type;
- /* copy Pin 0 output format */
- if (available_fmt->num_output_formats &&
- output_fmt_index < available_fmt->num_output_formats &&
- !available_fmt->output_pin_fmts[output_fmt_index].pin_index) {
- memcpy(&process->output_format,
- &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
- sizeof(struct sof_ipc4_audio_format));
+ in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- /* modify the pipeline params with the pin 0 output format */
- ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format);
- if (ret)
- return ret;
+ out_ref_rate = in_fmt->sampling_frequency;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
+
+ output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
+ &process->base_config,
+ available_fmt,
+ out_ref_rate,
+ out_ref_channels,
+ out_ref_valid_bits,
+ out_ref_type);
+ if (output_fmt_index < 0)
+ return output_fmt_index;
+
+ pin_fmt = &available_fmt->output_pin_fmts[output_fmt_index];
+
+ /* copy Pin output format for Pin 0 only */
+ if (pin_fmt->pin_index == 0) {
+ memcpy(&process->output_format, &pin_fmt->audio_fmt,
+ sizeof(struct sof_ipc4_audio_format));
+
+ /* modify the pipeline params with the output format */
+ ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
+ &process->output_format,
+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
+ BIT(SNDRV_PCM_HW_PARAM_RATE));
+ if (ret)
+ return ret;
+ }
}
+ sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
+ input_fmt_index, output_fmt_index);
+
/* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config);
@@ -2032,17 +2798,57 @@ static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof
msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
+ /* volume controls with range 0-1 (off/on) are switch controls */
+ if (scontrol->max == 1)
+ msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID);
+ else
+ msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
- /* set default volume values to 0dB in control */
for (i = 0; i < scontrol->num_channels; i++) {
control_data->chanv[i].channel = i;
- control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
+ /*
+ * Default, initial values:
+ * - 0dB for volume controls
+ * - off (0) for switch controls - value already zero after
+ * memory allocation
+ */
+ if (scontrol->max > 1)
+ control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
}
return 0;
}
+static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+ struct sof_ipc4_control_data *control_data;
+ struct sof_ipc4_msg *msg;
+ int i;
+
+ scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
+
+ /* scontrol->ipc_control_data will be freed in sof_control_unload */
+ scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
+ if (!scontrol->ipc_control_data)
+ return -ENOMEM;
+
+ control_data = scontrol->ipc_control_data;
+ control_data->index = scontrol->index;
+
+ msg = &control_data->msg;
+ msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
+ msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+ msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID);
+
+ /* Default, initial value for enums: first enum entry is selected (0) */
+ for (i = 0; i < scontrol->num_channels; i++)
+ control_data->chanv[i].channel = i;
+
+ return 0;
+}
+
static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
struct sof_ipc4_control_data *control_data;
@@ -2117,6 +2923,9 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
return sof_ipc4_control_load_volume(sdev, scontrol);
case SND_SOC_TPLG_CTL_BYTES:
return sof_ipc4_control_load_bytes(sdev, scontrol);
+ case SND_SOC_TPLG_CTL_ENUM:
+ case SND_SOC_TPLG_CTL_ENUM_VALUE:
+ return sof_ipc4_control_load_enum(sdev, scontrol);
default:
break;
}
@@ -2196,9 +3005,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
{
struct sof_ipc4_gain *gain = swidget->private;
- ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
- sizeof(struct sof_ipc4_gain_data);
- ipc_data = gain;
+ ipc_size = sizeof(gain->data);
+ ipc_data = &gain->data;
msg = &gain->msg;
break;
@@ -2217,12 +3025,22 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
{
struct sof_ipc4_src *src = swidget->private;
- ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
- ipc_data = src;
+ ipc_size = sizeof(src->data);
+ ipc_data = &src->data;
msg = &src->msg;
break;
}
+ case snd_soc_dapm_asrc:
+ {
+ struct sof_ipc4_asrc *asrc = swidget->private;
+
+ ipc_size = sizeof(asrc->data);
+ ipc_data = &asrc->data;
+
+ msg = &asrc->msg;
+ break;
+ }
case snd_soc_dapm_effect:
{
struct sof_ipc4_process *process = swidget->private;
@@ -2245,6 +3063,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
}
if (swidget->id != snd_soc_dapm_scheduler) {
+ int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK;
+
ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
if (ret < 0) {
dev_err(sdev->dev, "failed to assign instance id for %s\n",
@@ -2256,13 +3076,19 @@ 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);
+
+ dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n",
+ swidget->widget->name, swidget->pipeline_id, module_id,
+ swidget->instance_id, swidget->core);
+ } else {
+ dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
+ swidget->widget->name, swidget->pipeline_id,
+ swidget->instance_id, swidget->core);
}
- dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
- swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
msg->data_size = ipc_size;
msg->data_ptr = ipc_data;
@@ -2319,6 +3145,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
pipeline->mem_usage = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
ida_free(&pipeline_ida, swidget->instance_id);
+ swidget->instance_id = -EINVAL;
} else {
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
@@ -2417,7 +3244,7 @@ static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
struct snd_sof_widget *src_widget,
struct snd_sof_widget *sink_widget,
- int sink_id)
+ struct snd_sof_route *sroute)
{
struct sof_ipc4_copier_config_set_sink_format format;
const struct sof_ipc_ops *iops = sdev->ipc->ops;
@@ -2426,9 +3253,6 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_module *fw_module;
struct sof_ipc4_msg msg = {{ 0 }};
- dev_dbg(sdev->dev, "%s set copier sink %d format\n",
- src_widget->widget->name, sink_id);
-
if (WIDGET_IS_DAI(src_widget->id)) {
struct snd_sof_dai *dai = src_widget->private;
@@ -2439,13 +3263,15 @@ static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
fw_module = src_widget->module_info;
- format.sink_id = sink_id;
+ format.sink_id = sroute->src_queue_id;
memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
- pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id);
+ pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sroute->dst_queue_id);
if (!pin_fmt) {
- dev_err(sdev->dev, "Unable to get pin %d format for %s",
- sink_id, sink_widget->widget->name);
+ dev_err(sdev->dev,
+ "Failed to get input audio format of %s:%d for output of %s:%d\n",
+ sink_widget->widget->name, sroute->dst_queue_id,
+ src_widget->widget->name, sroute->src_queue_id);
return -EINVAL;
}
@@ -2503,7 +3329,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
SOF_PIN_TYPE_OUTPUT);
if (sroute->src_queue_id < 0) {
- dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n",
+ dev_err(sdev->dev,
+ "failed to get src_queue_id ID from source widget %s\n",
src_widget->widget->name);
return sroute->src_queue_id;
}
@@ -2511,7 +3338,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
SOF_PIN_TYPE_INPUT);
if (sroute->dst_queue_id < 0) {
- dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n",
+ dev_err(sdev->dev,